From 5fa3ea047aba6e3a3574905b907a29d18b29ea64 Mon Sep 17 00:00:00 2001 From: AuxXxilium Date: Fri, 5 Jul 2024 18:00:04 +0200 Subject: [PATCH] init: add dsm gpl source Signed-off-by: AuxXxilium --- .clang-format | 238 +- Documentation/ABI/testing/debugfs-aufs | 55 + Documentation/ABI/testing/sysfs-aufs | 31 + Documentation/ABI/testing/sysfs-firmware-acpi | 43 + Documentation/admin-guide/sysctl/vm.rst | 24 + .../devicetree/bindings/arm/realtek.yaml | 14 + .../bindings/clock/realtek,clocks.txt | 76 + .../bindings/iio/adc/realtek,rtk-lsadc.txt | 57 + .../interrupt-controller/realtek,intc.txt | 18 + .../devicetree/bindings/mfd/apw888x.txt | 54 + .../bindings/net/ethernet-controller.yaml | 4 + .../bindings/net/realtek,r8169soc.txt | 56 + .../devicetree/bindings/nvmem/rtk-efuse.txt | 12 + .../bindings/power/reset/regmap-poweroff.txt | 29 + .../bindings/power/reset/rtk,reboot-mode.txt | 15 + .../bindings/power/reset/rtk,reboot.txt | 20 + .../bindings/pwm/realtek,rtk-pwm.txt | 19 + .../reserved-memory/realtek,shared-memory.txt | 4 + .../devicetree/bindings/reset/rtk-reset.txt | 14 + .../devicetree/bindings/rtc/rtc-rtk.txt | 24 + .../devicetree/bindings/rtc/rtc-sw.txt | 8 + .../bindings/soc/realtek/bsv_ctrl.txt | 58 + .../devicetree/bindings/soc/realtek/crt.txt | 24 + .../bindings/soc/realtek/dbus_pmu.txt | 42 + .../bindings/soc/realtek/ddrc_pmu.txt | 36 + .../devicetree/bindings/soc/realtek/info.txt | 16 + .../bindings/soc/realtek/power-domain.txt | 14 + .../bindings/soc/realtek/rbus_pmu.txt | 16 + .../bindings/soc/realtek/wdt_st.txt | 16 + .../bindings/sound/snd-realtek-notify.txt | 27 + .../devicetree/bindings/sound/snd-realtek.txt | 27 + .../devicetree/bindings/spi/spi-dw-rtk.txt | 38 + .../bindings/thermal/realtek-thermal.txt | 41 + .../devicetree/bindings/watchdog/rtk-wdt.txt | 30 + Documentation/filesystems/aufs/README | 401 + .../filesystems/aufs/design/01intro.txt | 171 + .../filesystems/aufs/design/02struct.txt | 258 + .../filesystems/aufs/design/03atomic_open.txt | 85 + .../filesystems/aufs/design/03lookup.txt | 113 + .../filesystems/aufs/design/04branch.txt | 74 + .../filesystems/aufs/design/05wbr_policy.txt | 64 + .../filesystems/aufs/design/06dirren.dot | 31 + .../filesystems/aufs/design/06dirren.txt | 102 + .../filesystems/aufs/design/06fhsm.txt | 120 + .../filesystems/aufs/design/06mmap.txt | 72 + .../filesystems/aufs/design/06xattr.txt | 96 + .../filesystems/aufs/design/07export.txt | 58 + .../filesystems/aufs/design/08shwh.txt | 52 + .../filesystems/aufs/design/10dynop.txt | 47 + Documentation/networking/ip-sysctl.rst | 4 + MAINTAINERS | 13 + Makefile | 3 + SynoBuildConf/_env | 71 + SynoBuildConf/_kconfig | 255 + SynoBuildConf/_modules | 770 ++ SynoBuildConf/_platform | 72 + SynoBuildConf/build | 123 + SynoBuildConf/build-virtual-headers | 16 + SynoBuildConf/build-virtual-qctool | 28 + SynoBuildConf/conflict | 1 + SynoBuildConf/conflict-virtual-headers | 1 + SynoBuildConf/depends | 2 + SynoBuildConf/depends-virtual-qctool | 3 + SynoBuildConf/error | 3 + SynoBuildConf/gitlab-ci | 201 + SynoBuildConf/install | 386 + SynoBuildConf/install-dev | 89 + SynoBuildConf/install-dev-virtual-headers | 12 + SynoBuildConf/install-virinst-Satatool | 27 + SynoBuildConf/install-virinst-T1tool | 11 + SynoBuildConf/install-virtual-qctool | 11 + SynoBuildConf/shellcheck | 1 + SynoBuildConf/version | 4 + arch/arm/net/bpf_jit_32.c | 3 + arch/arm64/Makefile | 4 + arch/arm64/boot/dts/realtek/Makefile | 18 + .../dts/realtek/rtd-1619b-synology-ds124.dts | 155 + .../dts/realtek/rtd-1619b-synology-ds223.dts | 165 + .../dts/realtek/rtd-1619b-synology-ds223j.dts | 165 + .../dts/realtek/rtd-1619b-synology-ds423.dts | 163 + .../dts/realtek/rtd-1619b-synology-mango.dts | 178 + .../dts/realtek/rtd1319-pymparticles-2gb.dts | 50 + .../dts/realtek/rtd1319-pymparticles.dtsi | 502 + .../arm64/boot/dts/realtek/rtd1319-rescue.dts | 23 + .../arm64/boot/dts/realtek/rtd13xx-efuse.dtsi | 52 + arch/arm64/boot/dts/realtek/rtd13xx-pcie.dtsi | 177 + .../boot/dts/realtek/rtd13xx-pinctrl.dtsi | 503 + .../boot/dts/realtek/rtd13xx-rescue.dtsi | 107 + arch/arm64/boot/dts/realtek/rtd13xx-usb.dtsi | 344 + arch/arm64/boot/dts/realtek/rtd13xx.dtsi | 1251 ++ .../realtek/rtd1619b-bleedingedge-1gb-nas.dts | 133 + .../dts/realtek/rtd1619b-bleedingedge-1gb.dts | 113 + .../realtek/rtd1619b-bleedingedge-2gb-spi.dts | 133 + .../dts/realtek/rtd1619b-bleedingedge-2gb.dts | 52 + .../dts/realtek/rtd1619b-bleedingedge-4gb.dts | 26 + .../dts/realtek/rtd1619b-bleedingedge.dtsi | 533 + .../boot/dts/realtek/rtd1619b-rescue-nas.dts | 94 + .../boot/dts/realtek/rtd1619b-rescue.dts | 18 + .../boot/dts/realtek/rtd16xxb-efuse.dtsi | 53 + .../dts/realtek/rtd16xxb-etn-wol-pattern.dtsi | 46 + .../arm64/boot/dts/realtek/rtd16xxb-pcie.dtsi | 115 + .../boot/dts/realtek/rtd16xxb-pinctrl.dtsi | 463 + .../boot/dts/realtek/rtd16xxb-rescue.dtsi | 126 + arch/arm64/boot/dts/realtek/rtd16xxb-usb.dtsi | 308 + arch/arm64/boot/dts/realtek/rtd16xxb.dtsi | 1257 ++ .../arm64/configs/rtd161xxb_nas_spi_defconfig | 460 + arch/arm64/net/bpf_jit_comp.c | 13 + arch/microblaze/include/asm/elf.h | 8 - arch/microblaze/include/asm/page.h | 3 - arch/mips/net/ebpf_jit.c | 3 + arch/powerpc/net/bpf_jit_comp64.c | 6 + arch/riscv/net/bpf_jit_comp32.c | 4 + arch/riscv/net/bpf_jit_comp64.c | 4 + arch/s390/net/bpf_jit_comp.c | 5 + arch/sparc/include/uapi/asm/traps.h | 2 - arch/sparc/net/bpf_jit_comp_64.c | 3 + arch/x86/boot/boot.h | 36 +- arch/x86/boot/compressed/head_64.S | 29 + arch/x86/boot/main.c | 2 +- arch/x86/entry/syscalls/syscall_32.tbl | 34 + arch/x86/entry/syscalls/syscall_64.tbl | 34 + arch/x86/entry/syscalls/syscallhdr.sh | 46 + arch/x86/include/asm/mce.h | 12 + arch/x86/include/uapi/asm/stat.h | 27 + arch/x86/kernel/cpu/bugs.c | 39 + arch/x86/kernel/cpu/mce/amd.c | 57 + arch/x86/kernel/cpu/mce/core.c | 22 + arch/x86/kernel/dumpstack.c | 8 + arch/x86/kernel/early_printk.c | 233 + arch/x86/kernel/setup.c | 10 + arch/x86/kernel/smpboot.c | 17 + arch/x86/kvm/x86.c | 7 + arch/x86/mm/fault.c | 7 + arch/x86/mm/pti.c | 22 + arch/x86/net/bpf_jit_comp.c | 7 + arch/x86/net/bpf_jit_comp32.c | 6 + arch/xtensa/include/uapi/asm/types.h | 3 - block/bio.c | 25 +- block/blk-core.c | 121 +- block/blk-flush.c | 13 + block/blk-lib.c | 86 + block/blk-map.c | 2 +- block/blk-merge.c | 35 + block/blk-mq.c | 39 +- block/blk-sysfs.c | 20 + block/blk.h | 6 +- block/bounce.c | 6 + block/elevator.c | 7 + block/genhd.c | 499 + block/ioctl.c | 46 + block/partitions/core.c | 35 + block/scsi_ioctl.c | 7 + crypto/Makefile | 1 + crypto/asymmetric_keys/x509_cert_parser.c | 6 + crypto/hydrogen/Makefile | 1 + drivers/Kconfig | 2 + drivers/Makefile | 11 +- drivers/acpi/Makefile | 1 + drivers/acpi/acpi_fpdt.c | 265 + drivers/acpi/acpica/hwsleep.c | 18 + drivers/acpi/thermal.c | 2 - drivers/android/binder.c | 21 +- drivers/ata/Kconfig | 11 + drivers/ata/Makefile | 4 + drivers/ata/ahci.c | 1917 +++ drivers/ata/ahci.h | 25 + drivers/ata/ahci_rtk.c | 309 + drivers/ata/ata_syno_i2c.c | 526 + drivers/ata/libahci.c | 729 +- drivers/ata/libahci_platform.c | 44 + drivers/ata/libata-core.c | 850 +- drivers/ata/libata-eh.c | 1714 ++- drivers/ata/libata-pmp.c | 2136 +++ drivers/ata/libata-sata.c | 232 + drivers/ata/libata-scsi.c | 3401 +++++ drivers/ata/libata-sff.c | 77 +- drivers/ata/libata-transport.c | 16 + drivers/ata/libata.h | 90 + drivers/base/bus.c | 37 + drivers/base/core.c | 154 + drivers/base/soc.c | 6 + drivers/bluetooth/Kconfig | 8 + drivers/bluetooth/Makefile | 3 + drivers/bluetooth/rtk_rfkill.c | 242 + drivers/char/hw_random/Kconfig | 9 + drivers/char/hw_random/Makefile | 3 + drivers/char/hw_random/rtd1319-rng.c | 156 + drivers/char/random.c | 28 + drivers/clk/Kconfig | 3 + drivers/clk/Makefile | 3 + drivers/clk/realtek/Kconfig | 93 + drivers/clk/realtek/Makefile | 27 + drivers/clk/realtek/clk-det.c | 191 + drivers/clk/realtek/clk-det.h | 33 + drivers/clk/realtek/clk-pll-dif.c | 81 + drivers/clk/realtek/clk-pll-psaud.c | 123 + drivers/clk/realtek/clk-pll.c | 485 + drivers/clk/realtek/clk-pll.h | 192 + drivers/clk/realtek/clk-regmap-gate.c | 98 + drivers/clk/realtek/clk-regmap-gate.h | 31 + drivers/clk/realtek/clk-regmap-mux.c | 66 + drivers/clk/realtek/clk-regmap-mux.h | 32 + drivers/clk/realtek/clk-rtd1195-cc.c | 375 + drivers/clk/realtek/clk-rtd1195-ic.c | 102 + drivers/clk/realtek/clk-rtd1295-cc.c | 478 + drivers/clk/realtek/clk-rtd1295-ic.c | 101 + drivers/clk/realtek/clk-rtd1319-cc.c | 777 ++ drivers/clk/realtek/clk-rtd1319-ic.c | 113 + drivers/clk/realtek/clk-rtd1395-cc.c | 528 + drivers/clk/realtek/clk-rtd1395-ic.c | 105 + drivers/clk/realtek/clk-rtd1619-cc.c | 610 + drivers/clk/realtek/clk-rtd1619-ic.c | 102 + drivers/clk/realtek/clk-rtd1619b-cc.c | 684 + drivers/clk/realtek/clk-rtd1619b-ic.c | 114 + drivers/clk/realtek/clk-tee.c | 231 + drivers/clk/realtek/common.c | 336 + drivers/clk/realtek/common.h | 219 + drivers/clk/realtek/debugfs.c | 25 + drivers/clk/realtek/of-conf.c | 15 + drivers/clk/realtek/of-conf.h | 9 + drivers/clk/realtek/reset.c | 170 + drivers/clk/realtek/reset.h | 63 + drivers/cpufreq/acpi-cpufreq.c | 12 + drivers/dma-buf/dma-buf.c | 44 + drivers/dma-buf/sw_sync.c | 29 + drivers/firmware/efi/cper.c | 30 + drivers/firmware/efi/efi-pstore.c | 57 + drivers/firmware/efi/efivars.c | 7 + drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 4 + drivers/gpio/gpio-rtd.c | 747 ++ drivers/gpio/gpiolib.c | 14 + drivers/gpio/syno_gpio.c | 431 + .../include/asic_reg/umc/umc_8_7_0_sh_mask.h | 158 +- .../gpu/drm/i915/gem/i915_gem_object_types.h | 1 + drivers/gpu/drm/i915/gem/i915_gem_pages.c | 10 + drivers/gpu/drm/i915/gt/intel_gt.c | 102 + drivers/gpu/drm/i915/gt/intel_gt.h | 2 + drivers/gpu/drm/i915/gt/intel_gt_types.h | 2 + drivers/gpu/drm/i915/i915_reg.h | 11 + drivers/gpu/drm/i915/i915_vma.c | 3 + drivers/gpu/drm/i915/intel_uncore.c | 26 +- drivers/gpu/drm/i915/intel_uncore.h | 2 + drivers/hwmon/Makefile | 2 + drivers/hwmon/adt7475.c | 941 ++ drivers/hwmon/coretemp.c | 147 + drivers/hwmon/k10temp.c | 41 + drivers/hwmon/syno_hddmon.c | 333 + drivers/hwmon/syno_smbus_hddmon.c | 140 + drivers/i2c/busses/Kconfig | 12 + drivers/i2c/busses/Makefile | 3 + drivers/i2c/busses/i2c-amd-mp2-pci.c | 6 + drivers/i2c/busses/i2c-amd-mp2-plat.c | 7 + drivers/i2c/busses/i2c-designware-master.c | 25 + drivers/i2c/busses/i2c-designware-platdrv.c | 26 + drivers/i2c/busses/i2c-i801.c | 404 + drivers/i2c/busses/i2c-rtk.c | 1049 ++ drivers/i2c/busses/i2c-rtk.h | 156 + drivers/i2c/i2c-core-base.c | 30 + drivers/i2c/i2c-core-of.c | 51 + drivers/i2c/i2c-core.h | 6 + drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 3 + drivers/iio/adc/rtk_lsadc0.c | 1058 ++ drivers/iio/adc/rtk_lsadc0.h | 98 + drivers/infiniband/ulp/iser/iscsi_iser.c | 1 + drivers/iommu/amd/iommu.c | 14 + drivers/iommu/iommu.c | 23 + drivers/irqchip/Makefile | 3 + drivers/irqchip/irq-gic-v3.c | 97 + drivers/irqchip/irq-realtek-mux.c | 538 + drivers/irqchip/irq-realtek-mux.h | 126 + drivers/leds/Kconfig | 9 + drivers/leds/Makefile | 3 + drivers/leds/led-class.c | 35 + drivers/leds/leds-atmega1608-seg7.c | 688 + drivers/leds/leds-atmega1608.c | 470 + drivers/leds/leds-lp3943.c | 749 ++ drivers/leds/trigger/Makefile | 2 + drivers/leds/trigger/ledtrig-disk-syno.c | 161 + drivers/leds/trigger/syno_ledtrig.c | 173 + drivers/md/Makefile | 5 +- drivers/md/dm-core.h | 10 + drivers/md/dm-crypt.c | 33 + drivers/md/dm-io.c | 149 + drivers/md/dm-linear.c | 17 + drivers/md/dm-sysfs.c | 31 + drivers/md/dm-table.c | 39 + drivers/md/dm.c | 369 + drivers/md/dm.h | 14 + drivers/md/libmd-report.c | 110 + drivers/md/md-linear.c | 288 + drivers/md/md.c | 2025 ++- drivers/md/md.h | 245 + drivers/md/raid0.c | 294 + drivers/md/raid1.c | 912 ++ drivers/md/raid1.h | 21 + drivers/md/raid10.c | 896 ++ drivers/md/raid10.h | 22 + drivers/md/raid5.c | 3738 ++++++ drivers/md/raid5.h | 224 + drivers/md/syno-md-fast-wakeup.h | 56 + drivers/md/syno-md-hint.c | 107 + drivers/md/syno-md-hint.h | 45 + drivers/mfd/Kconfig | 18 + drivers/mfd/Makefile | 5 + drivers/mfd/apw8886-i2c.c | 167 + drivers/mfd/apw8889-i2c.c | 140 + drivers/mfd/apw888x-core.c | 44 + drivers/misc/enclosure.c | 92 + drivers/mmc/core/block.c | 150 +- drivers/mmc/core/core.c | 75 + drivers/mmc/core/sd.c | 33 + drivers/mmc/core/sdio.c | 20 + drivers/mmc/host/Kconfig | 48 + drivers/mmc/host/Makefile | 10 + drivers/mmc/host/cqhci.c | 10 + drivers/mmc/host/cqhci.h | 7 + drivers/mmc/host/mmc_debug.h | 110 + drivers/mmc/host/reg_iso.h | 12 + drivers/mmc/host/reg_mmc.h | 315 + drivers/mmc/host/reg_mmc_rtd13xx.h | 383 + drivers/mmc/host/reg_sys.h | 78 + drivers/mmc/host/rtk-sdmmc-export.c | 18 + drivers/mmc/host/rtk-sdmmc-reg.h | 212 + drivers/mmc/host/rtk-sdmmc.c | 3542 +++++ drivers/mmc/host/rtk-sdmmc.h | 228 + drivers/mmc/host/rtkemmc_rtd13xx.c | 4753 +++++++ drivers/mmc/host/rtkemmc_rtd13xx.h | 301 + drivers/mmc/host/sdhci-rtk.c | 921 ++ drivers/mmc/host/sdhci-rtk.h | 17 + drivers/mmc/host/sdhci.c | 7 + drivers/mtd/mtdchar.c | 201 + drivers/mtd/mtdcore.c | 20 + drivers/mtd/mtdpart.c | 425 + drivers/mtd/mtdpstore.c | 38 +- drivers/mtd/nand/raw/Kconfig | 20 + drivers/mtd/nand/raw/Makefile | 4 + drivers/mtd/nand/raw/rtk_bbm.c | 499 + drivers/mtd/nand/raw/rtk_nand.c | 1209 ++ drivers/mtd/nand/raw/rtk_nand.h | 244 + drivers/mtd/parsers/redboot.c | 89 + drivers/mtd/spi-nor/controllers/Kconfig | 10 + drivers/mtd/spi-nor/controllers/Makefile | 3 + drivers/mtd/spi-nor/controllers/rtk-sfc.c | 686 + drivers/mtd/spi-nor/core.c | 44 + drivers/net/bonding/bond_3ad.c | 6 + drivers/net/bonding/bond_alb.c | 115 + drivers/net/bonding/bond_main.c | 87 + drivers/net/bonding/bond_procfs.c | 7 + drivers/net/ethernet/amd/xgbe/xgbe-common.h | 44 + drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 33 + drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 88 +- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 46 + drivers/net/ethernet/amd/xgbe/xgbe-main.c | 7 + drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 108 +- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 29 + drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 526 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 27 +- drivers/net/ethernet/emulex/benet/be_main.c | 49 + drivers/net/ethernet/realtek/Kconfig | 24 +- drivers/net/ethernet/realtek/Makefile | 3 + drivers/net/ethernet/realtek/r8169soc.c | 11033 ++++++++++++++++ drivers/net/mii.c | 25 + drivers/net/phy/marvell10g.c | 221 +- .../net/wireless/intersil/hostap/hostap_ap.c | 2 - drivers/ntb/ntb_transport.c | 260 +- drivers/nvme/host/core.c | 431 + drivers/nvme/host/fabrics.c | 60 - drivers/nvme/host/fabrics.h | 13 - drivers/nvme/host/fc.c | 4 +- drivers/nvme/host/nvme.h | 42 + drivers/nvme/host/pci.c | 371 + drivers/nvme/host/rdma.c | 4 +- drivers/nvme/host/tcp.c | 4 +- drivers/nvme/target/loop.c | 4 +- drivers/nvmem/Kconfig | 12 + drivers/nvmem/Makefile | 4 + drivers/nvmem/rtk-efuse.c | 364 + drivers/of/fdt.c | 168 + drivers/pci/controller/Kconfig | 21 + drivers/pci/controller/Makefile | 4 + drivers/pci/controller/pcie-rtd-trans.c | 293 + drivers/pci/controller/pcie-rtd.c | 1757 +++ drivers/pci/controller/pcie-rtd.h | 315 + drivers/pci/probe.c | 61 + drivers/pci/quirks.c | 180 + drivers/phy/Kconfig | 3 + drivers/phy/Makefile | 3 + drivers/phy/realtek/Kconfig | 17 + drivers/phy/realtek/Makefile | 6 + drivers/phy/realtek/phy-rtk-pcie.c | 403 + drivers/phy/realtek/phy-rtk-sata.c | 809 ++ drivers/pinctrl/Kconfig | 3 + drivers/pinctrl/Makefile | 3 + drivers/pinctrl/intel/Kconfig | 9 + drivers/pinctrl/intel/Makefile | 1 + drivers/pinctrl/intel/pinctrl-intel.c | 11 + drivers/pinctrl/intel/pinctrl-intel.h | 8 + .../pinctrl/intel/syno-pinctrl-lewisburg.c | 472 + drivers/pinctrl/realtek/Kconfig | 12 + drivers/pinctrl/realtek/Makefile | 2 + drivers/pinctrl/realtek/pinctrl-rtd.c | 749 ++ drivers/pinctrl/realtek/pinctrl-rtd1319.h | 1390 ++ drivers/pinctrl/realtek/pinctrl-rtd1619b.h | 1566 +++ drivers/power/reset/Kconfig | 24 + drivers/power/reset/Makefile | 10 + drivers/power/reset/regmap-poweroff.c | 86 + drivers/power/reset/rtk-reboot-mode.c | 103 + drivers/power/reset/rtk-reboot.c | 166 + drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 3 + drivers/pwm/pwm-rtk.c | 934 ++ drivers/regulator/Kconfig | 31 + drivers/regulator/Makefile | 8 + drivers/regulator/apw8886-regulator.c | 216 + drivers/regulator/apw8889-regulator.c | 213 + drivers/regulator/apw888x-regulator-core.c | 399 + drivers/regulator/apw888x-regulator.h | 84 + drivers/regulator/virtual-helper.c | 142 + drivers/reset/Kconfig | 9 + drivers/reset/Makefile | 3 + drivers/reset/reset-rtk-m2tmx.c | 128 + drivers/rtc/Kconfig | 9 + drivers/rtc/Makefile | 3 + drivers/rtc/rtc-cmos.c | 19 + drivers/rtc/rtc-ds1307.c | 9 + drivers/rtc/rtc-rtk.c | 484 + drivers/rtc/rtc-s35390a.c | 40 + drivers/scsi/Makefile | 1 + drivers/scsi/be2iscsi/be_iscsi.c | 19 +- drivers/scsi/bnx2i/bnx2i_iscsi.c | 23 +- drivers/scsi/cxgbi/libcxgbi.c | 12 +- drivers/scsi/hosts.c | 28 + drivers/scsi/libiscsi.c | 22 + drivers/scsi/libsyno_report.c | 71 + drivers/scsi/libsyno_report.h | 24 + drivers/scsi/qedi/qedi_iscsi.c | 25 +- drivers/scsi/qla4xxx/ql4_os.c | 1 + drivers/scsi/scsi_devinfo.c | 7 + drivers/scsi/scsi_error.c | 49 + drivers/scsi/scsi_ioctl.c | 19 + drivers/scsi/scsi_lib.c | 576 + drivers/scsi/scsi_logging.c | 10 + drivers/scsi/scsi_proc.c | 7 + drivers/scsi/scsi_scan.c | 444 + drivers/scsi/scsi_sysfs.c | 316 + drivers/scsi/scsi_transport_iscsi.c | 485 +- drivers/scsi/sd.c | 1011 ++ drivers/scsi/sd.h | 37 + drivers/scsi/ses.c | 65 +- drivers/scsi/sg.c | 7 + drivers/scsi/virtio_scsi.c | 34 + drivers/soc/Kconfig | 3 + drivers/soc/Makefile | 3 + drivers/soc/realtek/Kconfig | 59 + drivers/soc/realtek/Makefile | 5 + drivers/soc/realtek/common/Kconfig | 105 + drivers/soc/realtek/common/Makefile | 52 + drivers/soc/realtek/common/buflock/Kconfig | 6 + drivers/soc/realtek/common/buflock/Makefile | 10 + .../soc/realtek/common/buflock/src/buflock.c | 1092 ++ .../soc/realtek/common/buflock/uapi/buflock.h | 53 + drivers/soc/realtek/common/chip.c | 503 + drivers/soc/realtek/common/dvfs/Kconfig | 4 + drivers/soc/realtek/common/dvfs/Makefile | 1 + .../soc/realtek/common/dvfs/cpu-volt-sel.c | 212 + drivers/soc/realtek/common/hse/Kconfig | 6 + drivers/soc/realtek/common/hse/Makefile | 7 + drivers/soc/realtek/common/hse/cq.c | 90 + drivers/soc/realtek/common/hse/device.c | 124 + drivers/soc/realtek/common/hse/engine.c | 170 + drivers/soc/realtek/common/hse/hse.h | 117 + .../soc/realtek/common/hse/include/hse-sw.h | 26 + .../soc/realtek/common/hse/include/hsectl.h | 26 + drivers/soc/realtek/common/hse/platform.c | 221 + drivers/soc/realtek/common/info/Kconfig | 5 + drivers/soc/realtek/common/info/Makefile | 3 + drivers/soc/realtek/common/info/rtk_info.c | 17 + drivers/soc/realtek/common/info/rtk_info.h | 13 + .../soc/realtek/common/info/rtk_info_pll.c | 298 + .../soc/realtek/common/mem_allocator/Kconfig | 46 + .../soc/realtek/common/mem_allocator/Makefile | 8 + .../realtek/common/mem_allocator/ion-ioctl.c | 109 + .../soc/realtek/common/mem_allocator/ion.c | 817 ++ .../soc/realtek/common/mem_allocator/ion.h | 364 + .../common/mem_allocator/ion_carveout_heap.c | 147 + .../common/mem_allocator/ion_chunk_heap.c | 162 + .../common/mem_allocator/ion_cma_heap.c | 173 + .../realtek/common/mem_allocator/ion_heap.c | 316 + .../common/mem_allocator/ion_page_pool.c | 201 + .../common/mem_allocator/ion_system_heap.c | 455 + .../realtek/common/mem_allocator/rtk/Kconfig | 12 + .../realtek/common/mem_allocator/rtk/Makefile | 16 + .../mem_allocator/rtk/inc/ion_rtk_alloc.h | 11 + .../rtk/inc/ion_rtk_protected_notifier.h | 85 + .../mem_allocator/rtk/src/carveout_heap.c | 1052 ++ .../mem_allocator/rtk/src/carveout_heap.h | 69 + .../common/mem_allocator/rtk/src/debugfs.c | 73 + .../common/mem_allocator/rtk/src/debugfs.h | 14 + .../common/mem_allocator/rtk/src/dev.c | 744 ++ .../common/mem_allocator/rtk/src/dev_legacy.c | 494 + .../common/mem_allocator/rtk/src/dev_legacy.h | 213 + .../common/mem_allocator/rtk/src/flags.h | 297 + .../common/mem_allocator/rtk/src/ioctl.c | 369 + .../common/mem_allocator/rtk/src/ioctl.h | 8 + .../common/mem_allocator/rtk/src/pool.h | 75 + .../common/mem_allocator/rtk/src/pool_cma.c | 1067 ++ .../mem_allocator/rtk/src/pool_common.c | 205 + .../common/mem_allocator/rtk/src/pool_gen.c | 819 ++ .../common/mem_allocator/rtk/src/protected.c | 172 + .../common/mem_allocator/rtk/src/protected.h | 50 + .../common/mem_allocator/rtk/src/sys_heap.c | 403 + .../common/mem_allocator/rtk/test/Makefile | 4 + .../mem_allocator/rtk/test/notifier/Makefile | 3 + .../test/notifier/test-protecteds-_notifier.c | 80 + .../rtk/test/protected-alloc/Makefile | 4 + .../test-alloc-ion-protected.c | 189 + drivers/soc/realtek/common/rpc/Kconfig | 12 + drivers/soc/realtek/common/rpc/Makefile | 8 + .../soc/realtek/common/rpc/compat_rpc_mem.c | 95 + .../soc/realtek/common/rpc/compat_rpc_mem.h | 13 + drivers/soc/realtek/common/rpc/rpc_mem.c | 180 + drivers/soc/realtek/common/rpc/rpc_mem.h | 17 + drivers/soc/realtek/common/rpc/rpc_mem_uapi.h | 17 + drivers/soc/realtek/common/rpc/rtk_rpc.c | 886 ++ drivers/soc/realtek/common/rpc/rtk_rpc.h | 899 ++ drivers/soc/realtek/common/rpc/rtk_rpc_intr.c | 2383 ++++ drivers/soc/realtek/common/rpc/rtk_rpc_kern.c | 734 + drivers/soc/realtek/common/rpc/rtk_rpc_poll.c | 892 ++ drivers/soc/realtek/common/rtk_bootstatus.c | 263 + drivers/soc/realtek/common/rtk_bsv_ctrl.c | 377 + drivers/soc/realtek/common/rtk_cpu_vclk.c | 216 + drivers/soc/realtek/common/rtk_cpuhp.c | 85 + drivers/soc/realtek/common/rtk_cpuhp_ctrl.c | 201 + drivers/soc/realtek/common/rtk_crt.c | 264 + drivers/soc/realtek/common/rtk_fan.c | 454 + drivers/soc/realtek/common/rtk_fss_scan.c | 605 + drivers/soc/realtek/common/rtk_fw_pm.c | 256 + drivers/soc/realtek/common/rtk_gpio_default.c | 94 + drivers/soc/realtek/common/rtk_iso_wa.c | 148 + drivers/soc/realtek/common/rtk_mcp.c | 1088 ++ drivers/soc/realtek/common/rtk_mcp.h | 178 + drivers/soc/realtek/common/rtk_memory_remap.c | 129 + drivers/soc/realtek/common/rtk_pd/Kconfig | 38 + drivers/soc/realtek/common/rtk_pd/Makefile | 10 + drivers/soc/realtek/common/rtk_pd/rtk_gpc.c | 306 + drivers/soc/realtek/common/rtk_pd/rtk_iso.c | 59 + drivers/soc/realtek/common/rtk_pd/rtk_iso.h | 29 + drivers/soc/realtek/common/rtk_pd/rtk_pd-pm.c | 96 + .../realtek/common/rtk_pd/rtk_pd-rtd1295.c | 111 + .../realtek/common/rtk_pd/rtk_pd-rtd1395.c | 98 + .../realtek/common/rtk_pd/rtk_pd-rtd1619.c | 113 + .../realtek/common/rtk_pd/rtk_pd-rtd1619b.c | 135 + drivers/soc/realtek/common/rtk_pd/rtk_pd.c | 251 + drivers/soc/realtek/common/rtk_pd/rtk_pd.h | 150 + .../realtek/common/rtk_pd/rtk_pd_internal.h | 123 + drivers/soc/realtek/common/rtk_pd/rtk_sram.c | 129 + drivers/soc/realtek/common/rtk_pd/rtk_sram.h | 51 + drivers/soc/realtek/common/rtk_pm.c | 368 + drivers/soc/realtek/common/rtk_pm_common.c | 80 + drivers/soc/realtek/common/rtk_pm_sysfs.c | 277 + drivers/soc/realtek/common/rtk_refclk.c | 269 + drivers/soc/realtek/common/rtk_sb2.c | 145 + drivers/soc/realtek/common/rtk_sb2.h | 67 + drivers/soc/realtek/common/rtk_sb2_dbg.c | 323 + drivers/soc/realtek/common/rtk_sb2_inv.c | 190 + drivers/soc/realtek/common/rtk_sb2_sem.c | 148 + drivers/soc/realtek/common/rtk_sc_wrap.c | 142 + drivers/soc/realtek/common/rtk_sha1.c | 381 + drivers/soc/realtek/common/rtk_usb.h | 145 + drivers/soc/realtek/common/rtk_usb_manager.c | 2760 ++++ drivers/soc/realtek/common/rtk_usb_rtd119x.c | 85 + drivers/soc/realtek/common/rtk_usb_rtd129x.c | 626 + drivers/soc/realtek/common/rtk_usb_rtd1312c.c | 250 + drivers/soc/realtek/common/rtk_usb_rtd139x.c | 253 + drivers/soc/realtek/common/rtk_usb_rtd13xx.c | 261 + drivers/soc/realtek/common/rtk_usb_rtd16xx.c | 422 + drivers/soc/realtek/common/rtk_usb_rtd16xxb.c | 280 + drivers/soc/realtek/common/rtk_vcpu.c | 141 + drivers/soc/realtek/common/rtk_ve3_uart.c | 170 + drivers/soc/realtek/common/rtk_vsfc_ctrl.c | 466 + .../soc/realtek/common/rtk_watchdog_status.c | 136 + drivers/soc/realtek/rtd13xx/Makefile | 1 + drivers/soc/realtek/rtd13xx/rtk_ve/Makefile | 8 + .../soc/realtek/rtd13xx/rtk_ve/jdi/Makefile | 6 + .../realtek/rtd13xx/rtk_ve/jdi/compat_jpu.c | 324 + .../realtek/rtd13xx/rtk_ve/jdi/compat_jpu.h | 31 + drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jmm.h | 647 + drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.c | 1056 ++ drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.h | 47 + drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.c | 554 + drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.h | 44 + .../soc/realtek/rtd13xx/rtk_ve/ve1/Makefile | 7 + .../realtek/rtd13xx/rtk_ve/ve1/compat_ve1.c | 666 + .../realtek/rtd13xx/rtk_ve/ve1/compat_ve1.h | 42 + drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.c | 1896 +++ drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.h | 106 + .../soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.c | 129 + .../soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.h | 33 + .../realtek/rtd13xx/rtk_ve/ve1/ve1config.h | 110 + drivers/soc/realtek/rtd13xx/rtk_ve/ve1/vmm.h | 634 + drivers/soc/realtek/rtd16xxb/Makefile | 2 + drivers/soc/realtek/rtd16xxb/rtk_ve/Makefile | 8 + .../soc/realtek/rtd16xxb/rtk_ve/jdi/Makefile | 6 + .../realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.c | 324 + .../realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.h | 31 + drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jmm.h | 647 + drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.c | 1056 ++ drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.h | 47 + drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.c | 554 + drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.h | 44 + .../soc/realtek/rtd16xxb/rtk_ve/ve1/Makefile | 6 + .../realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.c | 666 + .../realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.h | 42 + drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.c | 1682 +++ drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.h | 106 + .../soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.c | 234 + .../soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.h | 36 + .../realtek/rtd16xxb/rtk_ve/ve1/ve1config.h | 110 + drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/vmm.h | 634 + drivers/soc/realtek/trace/Makefile | 1 + drivers/soc/realtek/trace/rtk_pm.c | 2 + drivers/spi/Kconfig | 10 + drivers/spi/Makefile | 3 + drivers/spi/spi-dw-rtk.c | 255 + drivers/staging/rtl8723bs/include/drv_types.h | 2 - drivers/syno/Kconfig | 13 + drivers/syno/Makefile | 5 + .../syno-flashcache-control-driver/Makefile | 1 + .../syno_flashcache_control.c | 38 + drivers/syno/syno-mem-saving-driver/Makefile | 2 + drivers/syno/syno-mem-saving-driver/dkms.conf | 7 + .../syno/syno-mem-saving-driver/flashcache.h | 2162 +++ .../syno-mem-saving-driver/flashcache.hook | 24 + .../syno-mem-saving-driver/flashcache_conf.c | 4995 +++++++ .../syno-mem-saving-driver/flashcache_ioctl.c | 1009 ++ .../syno-mem-saving-driver/flashcache_ioctl.h | 96 + .../syno-mem-saving-driver/flashcache_main.c | 5710 ++++++++ .../flashcache_pin_file.h | 31 + .../flashcache_procfs.c | 3269 +++++ .../syno-mem-saving-driver/flashcache_subr.c | 1581 +++ .../syno/syno-mem-saving-driver/ocf/Makefile | 15 + .../syno-mem-saving-driver/ocf/flashcache | 265 + .../syno_common_4k_driver.h | 79 + .../syno-mem-saving-driver/syno_common_tool.h | 237 + .../syno_feature_defines.h | 102 + .../syno-mem-saving-driver/syno_functions.c | 623 + .../syno-mem-saving-driver/syno_functions.h | 120 + .../syno_kernel_functions.c | 97 + .../syno_kernel_functions.h | 129 + .../syno-mem-saving-driver/syno_md_update.c | 2259 ++++ .../syno-mem-saving-driver/syno_md_update.h | 27 + .../syno-mem-saving-driver/syno_quickflush.c | 1497 +++ .../syno-mem-saving-driver/syno_quickflush.h | 61 + .../syno-mem-saving-driver/syno_unit_test.c | 197 + .../syno-mem-saving-driver/syno_unit_test.h | 9 + drivers/syno/synobios/Makefile | 3 + drivers/syno/synobios/Makefile.inc | 133 + drivers/syno/synobios/Makefile_vdsm.inc | 9 + drivers/syno/synobios/SynoBuildConf/build | 22 + .../SynoBuildConf/build-virtual-headers | 2 + .../SynoBuildConf/conflict-virtual-headers | 1 + drivers/syno/synobios/SynoBuildConf/depends | 3 + .../SynoBuildConf/depends-virtual-headers | 3 + .../syno/synobios/SynoBuildConf/install-dev | 230 + .../SynoBuildConf/install-dev-virtual-headers | 5 + drivers/syno/synobios/alpine/Makefile | 35 + drivers/syno/synobios/alpine/alpine_common.c | 312 + drivers/syno/synobios/alpine/alpine_common.h | 32 + drivers/syno/synobios/alpine/ds1515.c | 154 + drivers/syno/synobios/alpine/ds1517.c | 154 + drivers/syno/synobios/alpine/ds1817.c | 161 + drivers/syno/synobios/alpine/ds2015xs.c | 164 + drivers/syno/synobios/alpine/ds215+.c | 157 + drivers/syno/synobios/alpine/ds416.c | 204 + drivers/syno/synobios/alpine/ds715.c | 157 + drivers/syno/synobios/alpine/fan-pwm.c | 47 + drivers/syno/synobios/alpine/rs1219.c | 176 + drivers/syno/synobios/apollolake/Makefile | 29 + .../synobios/apollolake/apollolake_common.c | 774 ++ .../synobios/apollolake/apollolake_common.h | 126 + drivers/syno/synobios/apollolake/ds1019p.c | 158 + drivers/syno/synobios/apollolake/ds218p.c | 156 + drivers/syno/synobios/apollolake/ds418play.c | 165 + drivers/syno/synobios/apollolake/ds419p.c | 156 + drivers/syno/synobios/apollolake/ds620slim.c | 159 + drivers/syno/synobios/apollolake/ds718p.c | 156 + drivers/syno/synobios/apollolake/ds719p.c | 152 + drivers/syno/synobios/apollolake/ds918p.c | 156 + drivers/syno/synobios/apollolake/rs419p.c | 170 + drivers/syno/synobios/armada/Makefile | 54 + drivers/syno/synobios/armada/armada_common.c | 491 + drivers/syno/synobios/armada/armada_common.h | 99 + drivers/syno/synobios/armada/ds114.c | 67 + drivers/syno/synobios/armada/ds115.c | 67 + drivers/syno/synobios/armada/ds115j.c | 70 + drivers/syno/synobios/armada/ds213j.c | 66 + drivers/syno/synobios/armada/ds214.c | 151 + drivers/syno/synobios/armada/ds214p.c | 77 + drivers/syno/synobios/armada/ds214se.c | 66 + drivers/syno/synobios/armada/ds215j.c | 66 + drivers/syno/synobios/armada/ds216se.c | 66 + drivers/syno/synobios/armada/ds414.c | 85 + drivers/syno/synobios/armada/ds414slim.c | 81 + drivers/syno/synobios/armada/fan-pwm.c | 44 + drivers/syno/synobios/armada/fan-resister.c | 106 + .../syno/synobios/armada/mv_level_button.c | 134 + drivers/syno/synobios/armada/rs214.c | 66 + drivers/syno/synobios/armada/rs814.c | 125 + drivers/syno/synobios/armada/rs815.c | 125 + drivers/syno/synobios/armada/thermal_ctrl.c | 389 + drivers/syno/synobios/armada/us3.c | 354 + drivers/syno/synobios/armada37xx/Makefile | 31 + .../synobios/armada37xx/armada37xx_common.c | 393 + .../synobios/armada37xx/armada37xx_common.h | 53 + drivers/syno/synobios/armada37xx/ds119j.c | 203 + drivers/syno/synobios/armada37xx/ds120j.c | 203 + drivers/syno/synobios/armada37xx/ds219j.c | 166 + drivers/syno/synobios/armada37xx/ds219se.c | 168 + drivers/syno/synobios/armada37xx/fan-pwm.c | 44 + .../syno/synobios/armada37xx/fan-resistor.c | 28 + drivers/syno/synobios/armada38x/Makefile | 35 + .../synobios/armada38x/armada38x_common.c | 364 + .../synobios/armada38x/armada38x_common.h | 50 + drivers/syno/synobios/armada38x/ds116.c | 314 + drivers/syno/synobios/armada38x/ds216.c | 278 + drivers/syno/synobios/armada38x/ds216j.c | 321 + drivers/syno/synobios/armada38x/ds218j.c | 327 + drivers/syno/synobios/armada38x/ds416j.c | 198 + drivers/syno/synobios/armada38x/ds416slim.c | 193 + drivers/syno/synobios/armada38x/ds419slim.c | 193 + drivers/syno/synobios/armada38x/fan-pwm.c | 44 + .../syno/synobios/armada38x/fan-resistor.c | 28 + drivers/syno/synobios/armada38x/rs217.c | 187 + drivers/syno/synobios/armada38x/rs816.c | 230 + drivers/syno/synobios/avoton/Makefile | 27 + drivers/syno/synobios/avoton/avoton_common.c | 1018 ++ drivers/syno/synobios/avoton/avoton_common.h | 109 + drivers/syno/synobios/avoton/ds1515+.c | 53 + drivers/syno/synobios/avoton/ds1517+.c | 53 + drivers/syno/synobios/avoton/ds1616+.c | 56 + drivers/syno/synobios/avoton/ds1815+.c | 53 + drivers/syno/synobios/avoton/ds1817+.c | 53 + drivers/syno/synobios/avoton/ds2415+.c | 53 + drivers/syno/synobios/avoton/ds415+.c | 75 + drivers/syno/synobios/avoton/rs1219+.c | 57 + drivers/syno/synobios/avoton/rs2416+.c | 57 + drivers/syno/synobios/avoton/rs2416rp+.c | 57 + drivers/syno/synobios/avoton/rs815+.c | 57 + drivers/syno/synobios/avoton/rs815rp+.c | 57 + drivers/syno/synobios/avoton/rs818+.c | 57 + drivers/syno/synobios/avoton/rs818rp+.c | 57 + drivers/syno/synobios/braswell/Makefile | 20 + .../syno/synobios/braswell/braswell_common.c | 687 + .../syno/synobios/braswell/braswell_common.h | 114 + drivers/syno/synobios/braswell/ds216+.c | 73 + drivers/syno/synobios/braswell/ds216+II.c | 73 + drivers/syno/synobios/braswell/ds416play.c | 73 + drivers/syno/synobios/braswell/ds716+.c | 73 + drivers/syno/synobios/braswell/ds716+II.c | 73 + drivers/syno/synobios/braswell/ds916p.c | 72 + drivers/syno/synobios/broadwell/Makefile | 25 + .../synobios/broadwell/broadwell_common.c | 1199 ++ .../synobios/broadwell/broadwell_common.h | 129 + drivers/syno/synobios/broadwell/ds3017xs.c | 34 + drivers/syno/synobios/broadwell/ds3617xs.c | 95 + drivers/syno/synobios/broadwell/ds3617xsII.c | 95 + drivers/syno/synobios/broadwell/ds3622xs+.c | 106 + drivers/syno/synobios/broadwell/fs2017.c | 102 + drivers/syno/synobios/broadwell/fs3400.c | 102 + drivers/syno/synobios/broadwell/rs18017xs+.c | 102 + drivers/syno/synobios/broadwell/rs3617rpxs.c | 102 + drivers/syno/synobios/broadwell/rs3617xs+.c | 103 + drivers/syno/synobios/broadwell/rs3618xs.c | 120 + drivers/syno/synobios/broadwell/rs4017xs+.c | 171 + drivers/syno/synobios/broadwell/rsd18016xs+.c | 45 + drivers/syno/synobios/broadwellnk/Makefile | 32 + .../synobios/broadwellnk/broadwellnk_common.c | 1472 +++ .../synobios/broadwellnk/broadwellnk_common.h | 151 + drivers/syno/synobios/broadwellnk/ds1621xs+.c | 98 + drivers/syno/synobios/broadwellnk/ds3018xs.c | 34 + drivers/syno/synobios/broadwellnk/ds3622xs+.c | 99 + drivers/syno/synobios/broadwellnk/fs1018.c | 34 + drivers/syno/synobios/broadwellnk/fs3600.c | 103 + drivers/syno/synobios/broadwellnk/hd3400.c | 43 + drivers/syno/synobios/broadwellnk/rs1619xs+.c | 111 + .../syno/synobios/broadwellnk/rs3621rpxs.c | 120 + drivers/syno/synobios/broadwellnk/rs3621xs+.c | 121 + drivers/syno/synobios/broadwellnk/rs4021xs+.c | 185 + drivers/syno/synobios/broadwellnk/sa3400.c | 103 + drivers/syno/synobios/broadwellnk/sa3600.c | 103 + drivers/syno/synobios/broadwellnkv2/Makefile | 20 + .../broadwellnkv2/broadwellnkv2_common.c | 742 ++ .../broadwellnkv2/broadwellnkv2_common.h | 91 + drivers/syno/synobios/broadwellnkv2/fs3410.c | 236 + .../syno/synobios/broadwellnkv2/rs4022xs+.c | 73 + drivers/syno/synobios/broadwellnkv2/sa3410.c | 214 + drivers/syno/synobios/broadwellnkv2/sa3610.c | 214 + drivers/syno/synobios/broadwellntb/Makefile | 14 + .../broadwellntb/broadwellntb_common.c | 531 + .../broadwellntb/broadwellntb_common.h | 60 + drivers/syno/synobios/broadwellntb/taipei.c | 40 + drivers/syno/synobios/broadwellntbap/Makefile | 15 + .../broadwellntbap/broadwellntbap_common.c | 671 + .../broadwellntbap/broadwellntbap_common.h | 83 + .../syno/synobios/broadwellntbap/sa3200d.c | 40 + .../syno/synobios/broadwellntbap/sa3400d.c | 117 + drivers/syno/synobios/bromolow/Makefile | 29 + .../syno/synobios/bromolow/bromolow_common.c | 1226 ++ .../syno/synobios/bromolow/bromolow_common.h | 103 + drivers/syno/synobios/bromolow/ds2414xs.c | 34 + drivers/syno/synobios/bromolow/ds3611xs.c | 32 + drivers/syno/synobios/bromolow/ds3612xs.c | 32 + drivers/syno/synobios/bromolow/ds3615xs.c | 85 + drivers/syno/synobios/bromolow/es3614xs+.c | 34 + drivers/syno/synobios/bromolow/rc18015xs+.c | 114 + drivers/syno/synobios/bromolow/rs10613xs+.c | 43 + drivers/syno/synobios/bromolow/rs18016xs+.c | 102 + drivers/syno/synobios/bromolow/rs3411rpxs.c | 41 + drivers/syno/synobios/bromolow/rs3411xs.c | 41 + drivers/syno/synobios/bromolow/rs3412rpxs.c | 41 + drivers/syno/synobios/bromolow/rs3412xs.c | 41 + drivers/syno/synobios/bromolow/rs3413xs+.c | 43 + drivers/syno/synobios/bromolow/rs3415xs+.c | 34 + drivers/syno/synobios/bromolow/rs3614rpxs.c | 93 + drivers/syno/synobios/bromolow/rs3614xs+.c | 93 + drivers/syno/synobios/bromolow/rs3614xs.c | 93 + drivers/syno/synobios/bromolow/rs3617xs.c | 93 + drivers/syno/synobios/cedarview/Makefile | 28 + .../synobios/cedarview/cedarview_common.c | 1340 ++ .../synobios/cedarview/cedarview_common.h | 104 + drivers/syno/synobios/cedarview/ds1512+.c | 57 + drivers/syno/synobios/cedarview/ds1513+.c | 57 + drivers/syno/synobios/cedarview/ds1812+.c | 85 + drivers/syno/synobios/cedarview/ds1813+.c | 85 + drivers/syno/synobios/cedarview/ds2413+.c | 85 + drivers/syno/synobios/cedarview/ds412+.c | 85 + drivers/syno/synobios/cedarview/ds713+.c | 107 + drivers/syno/synobios/cedarview/rs2212+.c | 111 + drivers/syno/synobios/cedarview/rs2212rp+.c | 113 + drivers/syno/synobios/cedarview/rs2414+.c | 111 + drivers/syno/synobios/cedarview/rs2414rp+.c | 113 + drivers/syno/synobios/cedarview/rs812+.c | 129 + drivers/syno/synobios/cedarview/rs812rp+.c | 113 + drivers/syno/synobios/cedarview/rs814+.c | 112 + drivers/syno/synobios/cedarview/rs814rp+.c | 113 + drivers/syno/synobios/coffeelake/Makefile | 15 + .../synobios/coffeelake/coffeelake_common.c | 459 + .../synobios/coffeelake/coffeelake_common.h | 53 + drivers/syno/synobios/coffeelake/ds3619xs.c | 30 + drivers/syno/synobios/comcerto2k/Makefile | 23 + .../synobios/comcerto2k/comcerto2k_common.c | 328 + .../synobios/comcerto2k/comcerto2k_common.h | 67 + drivers/syno/synobios/comcerto2k/ds414j.c | 148 + drivers/syno/synobios/comcerto2k/ds415j.c | 205 + drivers/syno/synobios/comcerto2k/fan-pwm.c | 44 + .../syno/synobios/comcerto2k/fan-resister.c | 60 + drivers/syno/synobios/common/common.c | 376 + drivers/syno/synobios/common/common.h | 35 + drivers/syno/synobios/denverton/Makefile | 33 + .../synobios/denverton/denverton_common.c | 1007 ++ .../synobios/denverton/denverton_common.h | 123 + drivers/syno/synobios/denverton/ds1618+.c | 61 + drivers/syno/synobios/denverton/ds1819+.c | 61 + drivers/syno/synobios/denverton/ds2419+.c | 63 + drivers/syno/synobios/denverton/ds2419+II.c | 63 + drivers/syno/synobios/denverton/dva3219.c | 95 + drivers/syno/synobios/denverton/dva3221.c | 95 + drivers/syno/synobios/denverton/rs1220+.c | 56 + drivers/syno/synobios/denverton/rs1220rp+.c | 59 + drivers/syno/synobios/denverton/rs2418+.c | 64 + drivers/syno/synobios/denverton/rs2418rp+.c | 67 + drivers/syno/synobios/denverton/rs2818rp+.c | 67 + drivers/syno/synobios/denverton/rs820+.c | 118 + drivers/syno/synobios/denverton/rs820rp+.c | 120 + drivers/syno/synobios/epyc7002/Makefile | 21 + .../syno/synobios/epyc7002/epyc7002_common.c | 642 + .../syno/synobios/epyc7002/epyc7002_common.h | 79 + drivers/syno/synobios/epyc7002/fs6400n.c | 191 + drivers/syno/synobios/epyc7002/fs6410.c | 202 + drivers/syno/synobios/epyc7002/sa6200.c | 202 + drivers/syno/synobios/epyc7002/sa6400.c | 202 + drivers/syno/synobios/epyc7002/sc6200.c | 202 + drivers/syno/synobios/epyc7002sofs/Makefile | 22 + .../epyc7002sofs/epyc7002sofs_common.c | 642 + .../epyc7002sofs/epyc7002sofs_common.h | 79 + drivers/syno/synobios/epyc7002sofs/fs6400n.c | 191 + drivers/syno/synobios/epyc7002sofs/fs6410.c | 202 + drivers/syno/synobios/epyc7002sofs/sa6200.c | 202 + drivers/syno/synobios/epyc7002sofs/sa6400.c | 202 + drivers/syno/synobios/epyc7002sofs/sc6200.c | 202 + drivers/syno/synobios/epyc7003ntb/Makefile | 18 + .../synobios/epyc7003ntb/epyc7003ntb_common.c | 445 + .../synobios/epyc7003ntb/epyc7003ntb_common.h | 71 + drivers/syno/synobios/epyc7003ntb/fs6600dn.c | 202 + drivers/syno/synobios/evansport/Makefile | 16 + drivers/syno/synobios/evansport/ds114+.c | 79 + drivers/syno/synobios/evansport/ds214play.c | 79 + drivers/syno/synobios/evansport/ds415play.c | 54 + .../synobios/evansport/evansport_common.c | 541 + .../synobios/evansport/evansport_common.h | 53 + drivers/syno/synobios/geminilake/Makefile | 24 + drivers/syno/synobios/geminilake/ds1520p.c | 114 + drivers/syno/synobios/geminilake/ds220p.c | 138 + drivers/syno/synobios/geminilake/ds224p.c | 138 + drivers/syno/synobios/geminilake/ds420p.c | 115 + drivers/syno/synobios/geminilake/ds423p.c | 115 + drivers/syno/synobios/geminilake/ds720p.c | 127 + drivers/syno/synobios/geminilake/ds920p.c | 115 + drivers/syno/synobios/geminilake/dva1622.c | 115 + .../synobios/geminilake/geminilake_common.c | 709 + .../synobios/geminilake/geminilake_common.h | 82 + drivers/syno/synobios/geminilakevs/Makefile | 17 + .../geminilakevs/geminilakevs_common.c | 468 + .../geminilakevs/geminilakevs_common.h | 66 + drivers/syno/synobios/geminilakevs/vs750hd.c | 122 + drivers/syno/synobios/grantley/Makefile | 14 + drivers/syno/synobios/grantley/fs3017.c | 34 + .../syno/synobios/grantley/grantley_common.c | 362 + .../syno/synobios/grantley/grantley_common.h | 41 + drivers/syno/synobios/grantley/rs18016dxs+.c | 34 + drivers/syno/synobios/i2c/i2c-linux.c | 169 + drivers/syno/synobios/i2c/i2c-linux.h | 4 + drivers/syno/synobios/i2c/i2c-mv.c | 191 + drivers/syno/synobios/i2c/i2c-mv.h | 2 + drivers/syno/synobios/i2c/i2c-plx.c | 111 + drivers/syno/synobios/i2c/i2c-plx.h | 2 + drivers/syno/synobios/i2c/i2c-ppc.c | 263 + drivers/syno/synobios/i2c/i2c-ppc.h | 3 + drivers/syno/synobios/icelaked/Makefile | 17 + .../syno/synobios/icelaked/icelaked_common.c | 566 + .../syno/synobios/icelaked/icelaked_common.h | 81 + drivers/syno/synobios/icelaked/rs4023xs+.c | 211 + .../synobios/include/syno_shutdown_hook.h | 16 + drivers/syno/synobios/include/syno_ttyS.h | 100 + drivers/syno/synobios/include/synobios.h | 1608 +++ drivers/syno/synobios/kvmcloud/Makefile | 8 + drivers/syno/synobios/kvmcloud/alidsm.c | 32 + .../syno/synobios/kvmcloud/kvmcloud_common.c | 286 + .../syno/synobios/kvmcloud/kvmcloud_common.h | 40 + drivers/syno/synobios/kvmx64/Makefile | 9 + drivers/syno/synobios/kvmx64/c2dsm.c | 32 + drivers/syno/synobios/kvmx64/kvmx64_common.c | 289 + drivers/syno/synobios/kvmx64/kvmx64_common.h | 41 + drivers/syno/synobios/kvmx64/virtualdsm.c | 32 + drivers/syno/synobios/kvmx64sofs/Makefile | 8 + .../synobios/kvmx64sofs/kvmx64sofs_common.c | 283 + .../synobios/kvmx64sofs/kvmx64sofs_common.h | 40 + drivers/syno/synobios/kvmx64sofs/virtualdsm.c | 32 + drivers/syno/synobios/kvmx64v2/Makefile | 8 + .../syno/synobios/kvmx64v2/kvmx64v2_common.c | 283 + .../syno/synobios/kvmx64v2/kvmx64v2_common.h | 40 + drivers/syno/synobios/kvmx64v2/virtualdsm.c | 32 + drivers/syno/synobios/led/led_1475.c | 35 + drivers/syno/synobios/led/led_1475.h | 10 + drivers/syno/synobios/led/led_9170.c | 35 + drivers/syno/synobios/led/led_9170.h | 11 + drivers/syno/synobios/led/led_9235.c | 213 + drivers/syno/synobios/led/led_9235.h | 19 + drivers/syno/synobios/led/led_asm116x.c | 45 + drivers/syno/synobios/led/led_asm116x.h | 9 + drivers/syno/synobios/led/led_common.h | 8 + drivers/syno/synobios/led/led_gpio.c | 48 + drivers/syno/synobios/led/led_gpio.h | 10 + drivers/syno/synobios/led/led_jmb585.c | 46 + drivers/syno/synobios/led/led_jmb585.h | 10 + drivers/syno/synobios/led/led_trigger.c | 192 + drivers/syno/synobios/led/led_trigger.h | 22 + drivers/syno/synobios/led/led_trigger_disk.c | 93 + drivers/syno/synobios/led/led_trigger_disk.h | 11 + drivers/syno/synobios/mapping.c | 411 + drivers/syno/synobios/mapping.h | 542 + drivers/syno/synobios/mesh/mesh.c | 277 + drivers/syno/synobios/mesh/mesh.h | 21 + drivers/syno/synobios/monaco/Makefile | 22 + drivers/syno/synobios/monaco/ds216play.c | 102 + drivers/syno/synobios/monaco/fan-pwm.c | 44 + drivers/syno/synobios/monaco/fan-resistor.c | 36 + drivers/syno/synobios/monaco/monaco_common.c | 334 + drivers/syno/synobios/monaco/monaco_common.h | 71 + drivers/syno/synobios/nextkvmx64/Makefile | 8 + .../synobios/nextkvmx64/nextkvmx64_common.c | 286 + .../synobios/nextkvmx64/nextkvmx64_common.h | 43 + .../syno/synobios/nextkvmx64/nextvirtualdsm.c | 32 + drivers/syno/synobios/pmbus/pmbus.c | 181 + drivers/syno/synobios/pmbus/pmbus.h | 6 + drivers/syno/synobios/purley/Makefile | 23 + drivers/syno/synobios/purley/fs6400.c | 122 + drivers/syno/synobios/purley/fs6500.c | 123 + drivers/syno/synobios/purley/fs6600n.c | 177 + drivers/syno/synobios/purley/hd6500.c | 195 + drivers/syno/synobios/purley/purley_common.c | 651 + drivers/syno/synobios/purley/purley_common.h | 82 + drivers/syno/synobios/purley/sa6500.c | 391 + drivers/syno/synobios/r1000/Makefile | 20 + drivers/syno/synobios/r1000/ds1522p.c | 107 + drivers/syno/synobios/r1000/ds723p.c | 101 + drivers/syno/synobios/r1000/ds923p.c | 107 + drivers/syno/synobios/r1000/r1000_common.c | 529 + drivers/syno/synobios/r1000/r1000_common.h | 65 + drivers/syno/synobios/r1000/rs422p.c | 129 + drivers/syno/synobios/rtc/alarmtime.c | 159 + drivers/syno/synobios/rtc/localtime.c | 133 + drivers/syno/synobios/rtc/localtime.h | 29 + drivers/syno/synobios/rtc/rtc-linux-pericom.c | 366 + drivers/syno/synobios/rtc/rtc-linux-ricoh.c | 164 + drivers/syno/synobios/rtc/rtc-linux-seiko.c | 194 + drivers/syno/synobios/rtc/rtc-mv-builtin.c | 195 + drivers/syno/synobios/rtc/rtc-mv-ricoh.c | 165 + drivers/syno/synobios/rtc/rtc-mv-seiko.c | 194 + drivers/syno/synobios/rtc/rtc-mvebu-builtin.c | 214 + drivers/syno/synobios/rtc/rtc-mvebu-builtin.h | 7 + drivers/syno/synobios/rtc/rtc-pericom-lib.c | 89 + drivers/syno/synobios/rtc/rtc-plx-ricoh.c | 164 + drivers/syno/synobios/rtc/rtc-plx-seiko.c | 193 + drivers/syno/synobios/rtc/rtc-ppc-ricoh.c | 158 + drivers/syno/synobios/rtc/rtc-ricoh-lib.c | 93 + drivers/syno/synobios/rtc/rtc-rtk-builtin.c | 214 + drivers/syno/synobios/rtc/rtc-rtk-builtin.h | 7 + drivers/syno/synobios/rtc/rtc-seiko-lib.c | 102 + drivers/syno/synobios/rtc/rtc-x86.c | 330 + drivers/syno/synobios/rtc/rtc.h | 76 + drivers/syno/synobios/rtd1296/Makefile | 35 + drivers/syno/synobios/rtd1296/ds118.c | 200 + drivers/syno/synobios/rtd1296/ds218.c | 247 + drivers/syno/synobios/rtd1296/ds218play.c | 211 + drivers/syno/synobios/rtd1296/ds220j.c | 226 + drivers/syno/synobios/rtd1296/ds418.c | 259 + drivers/syno/synobios/rtd1296/ds418j.c | 269 + drivers/syno/synobios/rtd1296/ds420j.c | 269 + drivers/syno/synobios/rtd1296/eds19.c | 230 + drivers/syno/synobios/rtd1296/fan-pwm.c | 44 + drivers/syno/synobios/rtd1296/fan-resistor.c | 28 + drivers/syno/synobios/rtd1296/rs819.c | 248 + .../syno/synobios/rtd1296/rtd1296_common.c | 480 + .../syno/synobios/rtd1296/rtd1296_common.h | 58 + drivers/syno/synobios/rtd1619/Makefile | 22 + drivers/syno/synobios/rtd1619/ds220.c | 262 + drivers/syno/synobios/rtd1619/ds220play.c | 245 + drivers/syno/synobios/rtd1619/fan-pwm.c | 44 + drivers/syno/synobios/rtd1619/fan-resistor.c | 28 + .../syno/synobios/rtd1619/rtd1619_common.c | 364 + .../syno/synobios/rtd1619/rtd1619_common.h | 58 + drivers/syno/synobios/rtd1619b/Makefile | 21 + drivers/syno/synobios/rtd1619b/ds124.c | 209 + drivers/syno/synobios/rtd1619b/ds223.c | 227 + drivers/syno/synobios/rtd1619b/ds223j.c | 210 + drivers/syno/synobios/rtd1619b/ds423.c | 219 + drivers/syno/synobios/rtd1619b/fan-pwm.c | 44 + drivers/syno/synobios/rtd1619b/fan-resistor.c | 28 + .../syno/synobios/rtd1619b/rtd1619b_common.c | 372 + .../syno/synobios/rtd1619b/rtd1619b_common.h | 45 + drivers/syno/synobios/ryzen5k/Makefile | 17 + drivers/syno/synobios/ryzen5k/rs4024xs+.c | 211 + .../syno/synobios/ryzen5k/ryzen5k_common.c | 566 + .../syno/synobios/ryzen5k/ryzen5k_common.h | 81 + drivers/syno/synobios/skylaked/Makefile | 15 + drivers/syno/synobios/skylaked/rs4021xsp.c | 84 + .../syno/synobios/skylaked/skylaked_common.c | 441 + .../syno/synobios/skylaked/skylaked_common.h | 46 + drivers/syno/synobios/switchtec/switchtec.c | 183 + drivers/syno/synobios/switchtec/switchtec.h | 6 + .../syno_power_outage/syno_power_outage.c | 147 + .../syno_power_outage/syno_power_outage.h | 8 + drivers/syno/synobios/syno_ttyS/syno_ttyS.c | 592 + .../syno/synobios/syno_ttyS/syno_ttyS_srm.c | 65 + drivers/syno/synobios/synobios.c | 3231 +++++ drivers/syno/synobios/v1000/Makefile | 39 + drivers/syno/synobios/v1000/ds1621p.c | 147 + drivers/syno/synobios/v1000/ds1623p.c | 147 + drivers/syno/synobios/v1000/ds1821p.c | 147 + drivers/syno/synobios/v1000/ds1823p.c | 147 + drivers/syno/synobios/v1000/ds1823xsp.c | 148 + drivers/syno/synobios/v1000/ds2422p.c | 147 + drivers/syno/synobios/v1000/fs2500.c | 179 + drivers/syno/synobios/v1000/fs2500t.c | 147 + drivers/syno/synobios/v1000/rs1221p.c | 161 + drivers/syno/synobios/v1000/rs1221rp+.c | 174 + drivers/syno/synobios/v1000/rs1623xsp.c | 165 + drivers/syno/synobios/v1000/rs2421p.c | 164 + drivers/syno/synobios/v1000/rs2421rpp.c | 206 + drivers/syno/synobios/v1000/rs2423p.c | 156 + drivers/syno/synobios/v1000/rs2423rpp.c | 198 + drivers/syno/synobios/v1000/rs2821rpp.c | 224 + drivers/syno/synobios/v1000/rs822p.c | 156 + drivers/syno/synobios/v1000/rs822rpp.c | 183 + drivers/syno/synobios/v1000/sc2500.c | 198 + drivers/syno/synobios/v1000/v1000_common.c | 1216 ++ drivers/syno/synobios/v1000/v1000_common.h | 112 + drivers/syno/synobios/v1000sofs/Makefile | 22 + drivers/syno/synobios/v1000sofs/ds1621p.c | 147 + drivers/syno/synobios/v1000sofs/ds1821p.c | 147 + .../synobios/v1000sofs/v1000sofs_common.c | 468 + .../synobios/v1000sofs/v1000sofs_common.h | 76 + drivers/tee/Makefile | 10 + drivers/tee/optee/core.c | 12 + drivers/tee/tee_client_api.h | 530 + drivers/tee/tee_core.c | 53 + drivers/tee/tee_mem_api.c | 708 + drivers/tee/tee_shm.c | 121 + drivers/thermal/Kconfig | 4 + drivers/thermal/Makefile | 3 + drivers/thermal/realtek/Kconfig | 18 + drivers/thermal/realtek/Makefile | 8 + drivers/thermal/realtek/cpu_core_cooling.c | 106 + drivers/thermal/realtek/sensor-rtd119x.c | 122 + drivers/thermal/realtek/sensor-rtd129x.c | 83 + drivers/thermal/realtek/sensor-rtd161x.c | 130 + drivers/thermal/realtek/sensor.c | 320 + drivers/thermal/realtek/sensor.h | 94 + drivers/tty/n_tty.c | 21 + drivers/tty/serial/8250/8250_core.c | 497 +- drivers/tty/serial/8250/8250_pci.c | 19 +- drivers/tty/serial/8250/8250_port.c | 172 + drivers/tty/serial/8250/Makefile | 19 + drivers/tty/serial/serial_core.c | 117 + drivers/tty/sysrq.c | 24 + drivers/tty/tty_io.c | 95 + drivers/tty/vt/vt.c | 17 + drivers/tty/vt/vt_ioctl.c | 10 +- drivers/usb/Kconfig | 6 + drivers/usb/class/cdc-acm.h | 9 + drivers/usb/core/Kconfig | 9 + drivers/usb/core/devices.c | 74 + drivers/usb/core/driver.c | 61 + drivers/usb/core/hcd-pci.c | 13 + drivers/usb/core/hub.c | 848 ++ drivers/usb/core/hub.h | 33 + drivers/usb/core/port.c | 210 + drivers/usb/core/quirks.c | 77 + drivers/usb/core/sysfs.c | 264 + drivers/usb/core/usb.c | 26 + drivers/usb/dwc3/Kconfig | 34 + drivers/usb/dwc3/Makefile | 26 + drivers/usb/dwc3/core.c | 221 + drivers/usb/dwc3/core.h | 44 + drivers/usb/dwc3/dwc3-rtk-debugfs.c | 523 + drivers/usb/dwc3/dwc3-rtk-drd.c | 200 + drivers/usb/dwc3/dwc3-rtk-drd.h | 26 + drivers/usb/dwc3/dwc3-rtk-type_c.c | 2801 ++++ drivers/usb/dwc3/dwc3-rtk.c | 829 ++ drivers/usb/dwc3/dwc3-rtk.h | 61 + drivers/usb/dwc3/gadget.c | 24 + drivers/usb/dwc3/host.c | 11 + drivers/usb/dwc3/io.h | 37 + drivers/usb/dwc3/rtk-rts5400.c | 729 + drivers/usb/dwc3/trace-rtk.c | 3 + drivers/usb/dwc3/trace.h | 7 + drivers/usb/gadget/Kconfig | 22 + drivers/usb/gadget/composite.c | 13 + drivers/usb/gadget/function/Makefile | 6 + drivers/usb/gadget/function/f_fs.c | 10 + drivers/usb/gadget/function/f_mtp.c | 1714 +++ drivers/usb/gadget/function/f_mtp.h | 10 + drivers/usb/gadget/function/f_ptp.c | 30 + drivers/usb/gadget/function/f_sourcesink.c | 75 + drivers/usb/gadget/function/g_zero.h | 8 + drivers/usb/gadget/udc/Kconfig | 15 + drivers/usb/gadget/udc/rtk-hsotg.c | 4077 ++++++ drivers/usb/gadget/udc/rtk-hsotg.h | 379 + drivers/usb/host/Kconfig | 24 + drivers/usb/host/Makefile | 3 + drivers/usb/host/ehci-dbg.c | 27 + drivers/usb/host/ehci-orion.c | 34 + drivers/usb/host/ehci-pci.c | 7 + drivers/usb/host/ehci-q.c | 76 + drivers/usb/host/ehci-rtk.c | 409 + drivers/usb/host/ehci-sched.c | 20 + drivers/usb/host/ehci.h | 9 + drivers/usb/host/ohci-hub.c | 49 + drivers/usb/host/ohci-rtk.c | 455 + drivers/usb/host/ohci.h | 48 + drivers/usb/host/xhci-hub.c | 61 + drivers/usb/host/xhci-mem.c | 73 + drivers/usb/host/xhci-pci.c | 11 + drivers/usb/host/xhci-plat.c | 106 + drivers/usb/host/xhci-ring.c | 239 + drivers/usb/host/xhci.c | 21 + drivers/usb/host/xhci.h | 25 + drivers/usb/phy/Kconfig | 20 + drivers/usb/phy/Makefile | 5 + drivers/usb/phy/phy-rtk-rle0599.c | 740 ++ drivers/usb/phy/phy-rtk-usb.h | 53 + drivers/usb/phy/phy-rtk-usb2.c | 1586 +++ drivers/usb/phy/phy-rtk-usb3.c | 912 ++ drivers/usb/storage/scsiglue.c | 39 + drivers/usb/storage/transport.c | 60 +- drivers/usb/storage/uas.c | 9 + drivers/usb/storage/usb.c | 27 + drivers/vhost/net.c | 2 - drivers/virtio/virtio_pci_common.c | 2 +- drivers/watchdog/Kconfig | 18 + drivers/watchdog/Makefile | 6 + drivers/watchdog/pretimeout_dump.c | 54 + drivers/watchdog/rtk_wdt.c | 372 + fs/Kconfig | 1 + fs/Makefile | 2 + fs/aio.c | 184 +- fs/attr.c | 25 + fs/aufs/Kconfig | 199 + fs/aufs/Makefile | 46 + fs/aufs/aufs.h | 62 + fs/aufs/branch.c | 1427 ++ fs/aufs/branch.h | 364 + fs/aufs/conf.mk | 40 + fs/aufs/cpup.c | 1445 ++ fs/aufs/cpup.h | 100 + fs/aufs/dbgaufs.c | 526 + fs/aufs/dbgaufs.h | 53 + fs/aufs/dcsub.c | 225 + fs/aufs/dcsub.h | 137 + fs/aufs/debug.c | 441 + fs/aufs/debug.h | 226 + fs/aufs/dentry.c | 1154 ++ fs/aufs/dentry.h | 268 + fs/aufs/dinfo.c | 554 + fs/aufs/dir.c | 763 ++ fs/aufs/dir.h | 134 + fs/aufs/dirren.c | 1316 ++ fs/aufs/dirren.h | 140 + fs/aufs/dynop.c | 368 + fs/aufs/dynop.h | 77 + fs/aufs/export.c | 837 ++ fs/aufs/f_op.c | 771 ++ fs/aufs/fhsm.c | 427 + fs/aufs/file.c | 863 ++ fs/aufs/file.h | 342 + fs/aufs/finfo.c | 149 + fs/aufs/fstype.h | 401 + fs/aufs/hbl.h | 65 + fs/aufs/hfsnotify.c | 288 + fs/aufs/hfsplus.c | 60 + fs/aufs/hnotify.c | 715 + fs/aufs/i_op.c | 1502 +++ fs/aufs/i_op_add.c | 936 ++ fs/aufs/i_op_del.c | 513 + fs/aufs/i_op_ren.c | 1250 ++ fs/aufs/iinfo.c | 286 + fs/aufs/inode.c | 529 + fs/aufs/inode.h | 698 + fs/aufs/ioctl.c | 220 + fs/aufs/lcnt.h | 186 + fs/aufs/loop.c | 148 + fs/aufs/loop.h | 55 + fs/aufs/magic.mk | 31 + fs/aufs/module.c | 273 + fs/aufs/module.h | 166 + fs/aufs/mvdown.c | 706 + fs/aufs/opts.c | 1880 +++ fs/aufs/opts.h | 225 + fs/aufs/plink.c | 516 + fs/aufs/poll.c | 51 + fs/aufs/posix_acl.c | 105 + fs/aufs/procfs.c | 170 + fs/aufs/rdu.c | 384 + fs/aufs/rwsem.h | 77 + fs/aufs/sbinfo.c | 314 + fs/aufs/super.c | 1047 ++ fs/aufs/super.h | 587 + fs/aufs/sysaufs.c | 93 + fs/aufs/sysaufs.h | 102 + fs/aufs/sysfs.c | 381 + fs/aufs/sysrq.c | 149 + fs/aufs/vdir.c | 896 ++ fs/aufs/vfsub.c | 885 ++ fs/aufs/vfsub.h | 354 + fs/aufs/wbr_policy.c | 830 ++ fs/aufs/whout.c | 1062 ++ fs/aufs/whout.h | 86 + fs/aufs/wkq.c | 372 + fs/aufs/wkq.h | 89 + fs/aufs/xattr.c | 356 + fs/aufs/xino.c | 1925 +++ fs/btrfs/Makefile | 10 + fs/btrfs/async-thread.c | 22 + fs/btrfs/async-thread.h | 12 + fs/btrfs/backref.c | 904 +- fs/btrfs/backref.h | 40 +- fs/btrfs/block-group.c | 1004 +- fs/btrfs/block-group.h | 45 +- fs/btrfs/block-rsv.c | 112 +- fs/btrfs/btrfs_inode.h | 150 +- fs/btrfs/compression.c | 24 +- fs/btrfs/compression.h | 6 + fs/btrfs/ctree.c | 103 +- fs/btrfs/ctree.h | 1444 +- fs/btrfs/delalloc-space.c | 35 + fs/btrfs/delalloc-space.h | 7 + fs/btrfs/delayed-inode.c | 72 +- fs/btrfs/delayed-inode.h | 8 + fs/btrfs/delayed-ref.c | 261 +- fs/btrfs/delayed-ref.h | 88 +- fs/btrfs/dir-item.c | 190 +- fs/btrfs/disk-io.c | 1945 ++- fs/btrfs/disk-io.h | 60 +- fs/btrfs/extent-io-tree.h | 35 +- fs/btrfs/extent-tree.c | 2130 ++- fs/btrfs/extent_io.c | 1068 +- fs/btrfs/extent_io.h | 88 +- fs/btrfs/extent_map.c | 120 + fs/btrfs/extent_map.h | 21 + fs/btrfs/file-item.c | 258 + fs/btrfs/file.c | 1406 +- fs/btrfs/free-space-analyze.c | 342 + fs/btrfs/free-space-cache.c | 1053 +- fs/btrfs/free-space-cache.h | 38 +- fs/btrfs/free-space-tree.c | 75 +- fs/btrfs/free-space-tree.h | 7 +- fs/btrfs/inode.c | 2799 +++- fs/btrfs/ioctl.c | 3057 ++++- fs/btrfs/locking.c | 25 +- fs/btrfs/locking.h | 5 +- fs/btrfs/ordered-data.c | 41 + fs/btrfs/ordered-data.h | 14 + fs/btrfs/print-tree.c | 15 + fs/btrfs/props.c | 30 +- fs/btrfs/props.h | 3 +- fs/btrfs/qgroup.c | 2528 +++- fs/btrfs/qgroup.h | 151 + fs/btrfs/reada.c | 12 +- fs/btrfs/reflink.c | 1708 ++- fs/btrfs/reflink.h | 13 + fs/btrfs/relocation.c | 35 +- fs/btrfs/root-tree.c | 14 + fs/btrfs/scrub.c | 291 +- fs/btrfs/send.c | 1710 ++- fs/btrfs/send.h | 24 + fs/btrfs/snapshot-size-query.c | 660 + fs/btrfs/space-info.c | 378 +- fs/btrfs/space-info.h | 33 + fs/btrfs/super.c | 747 +- fs/btrfs/syno-extent-usage.c | 3018 +++++ fs/btrfs/syno-feat-tree.c | 367 + fs/btrfs/syno-feat-tree.h | 38 + fs/btrfs/syno-locker.c | 1948 +++ fs/btrfs/syno-rbd-meta.c | 1018 ++ fs/btrfs/syno-rbd-meta.h | 21 + fs/btrfs/syno_acl.c | 149 + fs/btrfs/syno_acl.h | 14 + fs/btrfs/sysfs.c | 1077 ++ fs/btrfs/sysfs.h | 10 + fs/btrfs/tests/btrfs-tests.c | 28 +- fs/btrfs/tests/btrfs-tests.h | 6 + fs/btrfs/tests/inode-tests.c | 6 + fs/btrfs/tests/qgroup-tests.c | 6 + fs/btrfs/transaction.c | 713 +- fs/btrfs/transaction.h | 57 +- fs/btrfs/tree-checker.c | 12 + fs/btrfs/tree-log.c | 223 +- fs/btrfs/ulist.c | 136 + fs/btrfs/ulist.h | 21 + fs/btrfs/usrquota.c | 2877 ++++ fs/btrfs/volumes.c | 405 +- fs/btrfs/volumes.h | 63 +- fs/btrfs/xattr.c | 149 +- fs/btrfs/xattr.h | 15 + fs/buffer.c | 10 + fs/ceph/Makefile | 1 + fs/ceph/addr.c | 141 +- fs/ceph/cache.c | 125 - fs/ceph/cache.h | 97 +- fs/ceph/caps.c | 615 +- fs/ceph/debugfs.c | 69 +- fs/ceph/dir.c | 211 +- fs/ceph/export.c | 10 +- fs/ceph/file.c | 226 +- fs/ceph/inode.c | 436 +- fs/ceph/io.c | 35 +- fs/ceph/io.h | 4 + fs/ceph/locks.c | 8 +- fs/ceph/mds_client.c | 596 +- fs/ceph/mds_client.h | 29 +- fs/ceph/mdsmap.c | 16 +- fs/ceph/metric.c | 215 +- fs/ceph/metric.h | 109 +- fs/ceph/quota.c | 67 +- fs/ceph/snap.c | 153 +- fs/ceph/strings.c | 1 + fs/ceph/super.c | 98 +- fs/ceph/super.h | 104 +- fs/ceph/syno_acl.c | 155 + fs/ceph/syno_acl.h | 16 + fs/ceph/xattr.c | 133 +- fs/cifs/Makefile | 2 + fs/cifs/cifsfs.c | 41 + fs/cifs/cifsfs.h | 7 + fs/cifs/cifsglob.h | 19 + fs/cifs/cifsproto.h | 12 + fs/cifs/cifssmb.c | 47 + fs/cifs/connect.c | 72 + fs/cifs/file.c | 10 + fs/cifs/fs_context.c | 15 + fs/cifs/fs_context.h | 6 + fs/cifs/inode.c | 33 + fs/cifs/readdir.c | 9 + fs/cifs/sess.c | 18 + fs/cifs/smb2misc.c | 9 + fs/cifs/smb2ops.c | 130 +- fs/cifs/smb2pdu.c | 57 + fs/cifs/smb2proto.h | 13 + fs/cifs/synoops.c | 855 ++ fs/cifs/transport.c | 196 + fs/configfs/file.c | 7 + fs/dcache.c | 218 +- fs/debugfs/inode.c | 18 +- fs/ecryptfs/Makefile | 2 + fs/ecryptfs/crypto.c | 211 +- fs/ecryptfs/ecryptfs_kernel.h | 29 + fs/ecryptfs/export.c | 449 + fs/ecryptfs/file.c | 101 +- fs/ecryptfs/inode.c | 334 +- fs/ecryptfs/kthread.c | 6 + fs/ecryptfs/main.c | 98 + fs/ecryptfs/mmap.c | 202 +- fs/ecryptfs/read_write.c | 16 + fs/ecryptfs/super.c | 30 + fs/exec.c | 10 +- fs/exfat/Kconfig | 20 +- fs/exfat/LICENSE | 359 + fs/exfat/Makefile | 2 +- fs/exfat/README.md | 184 + fs/exfat/SynoBuildConf/build | 18 + fs/exfat/SynoBuildConf/depends | 2 + fs/exfat/SynoBuildConf/install | 10 + fs/exfat/SynoBuildConf/shellcheck | 1 + fs/exfat/SynoBuildConf/version | 3 + fs/exfat/balloc.c | 35 +- fs/exfat/cache.c | 12 +- fs/exfat/compat.h | 71 + fs/exfat/config.h | 19 + fs/exfat/dir.c | 96 +- fs/exfat/exfat_fs.h | 125 +- fs/exfat/exfat_raw.h | 4 - fs/exfat/fatent.c | 1 - fs/exfat/file.c | 373 +- fs/exfat/inode.c | 117 +- fs/exfat/misc.c | 48 +- fs/exfat/namei.c | 414 +- fs/exfat/nls.c | 22 +- fs/exfat/super.c | 422 +- fs/exfat/version.h | 5 + fs/exfat/xattr.c | 80 + fs/exportfs/expfs.c | 60 + fs/ext4/Makefile | 1 + fs/ext4/dir.c | 21 + fs/ext4/ext4.h | 329 +- fs/ext4/ext4_jbd2.h | 8 + fs/ext4/extents.c | 44 + fs/ext4/file.c | 33 + fs/ext4/hash.c | 95 +- fs/ext4/ialloc.c | 41 + fs/ext4/inline.c | 27 +- fs/ext4/inode.c | 436 +- fs/ext4/ioctl.c | 186 +- fs/ext4/mballoc.c | 78 +- fs/ext4/namei.c | 249 +- fs/ext4/resize.c | 22 + fs/ext4/super.c | 399 +- fs/ext4/symlink.c | 50 + fs/ext4/syno_acl.c | 363 + fs/ext4/syno_acl.h | 45 + fs/ext4/sysfs.c | 124 + fs/ext4/xattr.c | 87 + fs/ext4/xattr.h | 18 + fs/fat/fat.h | 12 + fs/fat/file.c | 42 + fs/fat/inode.c | 33 + fs/fat/namei_msdos.c | 8 + fs/fat/namei_vfat.c | 8 + fs/fcntl.c | 264 + fs/file_table.c | 143 + fs/fs-writeback.c | 42 +- fs/fs_context.c | 93 +- fs/fuse/dev.c | 12 +- fs/fuse/dir.c | 377 + fs/fuse/file.c | 86 + fs/fuse/fuse_i.h | 32 + fs/fuse/inode.c | 65 + fs/hfsplus/attributes.c | 7 + fs/hfsplus/bnode.c | 11 + fs/hfsplus/catalog.c | 83 + fs/hfsplus/dir.c | 50 + fs/hfsplus/hfsplus_fs.h | 35 +- fs/hfsplus/hfsplus_raw.h | 38 + fs/hfsplus/inode.c | 49 + fs/hfsplus/options.c | 20 + fs/hfsplus/super.c | 7 + fs/hfsplus/unicode.c | 86 +- fs/hfsplus/xattr.c | 7 + fs/inode.c | 48 + fs/internal.h | 9 + fs/io_uring.c | 17 +- fs/ioctl.c | 352 + fs/iomap/fiemap.c | 129 +- fs/isofs/inode.c | 9 +- fs/lockd/svc.c | 21 + fs/mount.h | 7 + fs/namei.c | 949 +- fs/namespace.c | 144 +- fs/nfs/Kconfig | 2 +- fs/nfs/callback_xdr.c | 15 + fs/nfsd/Makefile | 1 + fs/nfsd/auth.c | 39 + fs/nfsd/netns.h | 11 + fs/nfsd/nfs2acl.c | 9 + fs/nfsd/nfs3acl.c | 9 + fs/nfsd/nfs3proc.c | 62 + fs/nfsd/nfs4proc.c | 76 + fs/nfsd/nfs4state.c | 31 + fs/nfsd/nfs4xdr.c | 43 + fs/nfsd/nfsctl.c | 602 +- fs/nfsd/nfsd.h | 29 + fs/nfsd/nfsfh.c | 24 + fs/nfsd/nfsproc.c | 332 + fs/nfsd/nfssvc.c | 10 + fs/nfsd/state.h | 6 + fs/nfsd/stats.c | 110 + fs/nfsd/stats.h | 10 + fs/nfsd/syno_io_stat.c | 1334 ++ fs/nfsd/syno_io_stat.h | 73 + fs/nfsd/trace.h | 52 + fs/nfsd/vfs.c | 526 +- fs/nfsd/vfs.h | 47 + fs/nfsd/xdr4.h | 15 + fs/notify/Makefile | 1 + fs/notify/fanotify/fanotify_user.c | 12 + fs/notify/fsnotify.c | 147 + fs/notify/fsnotify.h | 14 + fs/notify/group.c | 6 + fs/notify/inotify/inotify_user.c | 12 + fs/notify/mark.c | 12 + fs/notify/notification.c | 25 + fs/notify/synotify/Makefile | 2 + fs/notify/synotify/synotify.c | 339 + fs/notify/synotify/synotify.h | 47 + fs/notify/synotify/synotify_user.c | 642 + fs/open.c | 302 + fs/overlayfs/dir.c | 10 +- fs/overlayfs/util.c | 8 + fs/proc/base.c | 7 + fs/proc/loadavg.c | 25 + fs/proc/nommu.c | 10 + fs/proc/task_mmu.c | 14 + fs/proc/task_nommu.c | 10 + fs/proc_namespace.c | 7 + fs/pstore/Kconfig | 2 +- fs/pstore/platform.c | 20 + fs/pstore/zone.c | 64 + fs/quota/dquot.c | 6 + fs/quota/quota_tree.c | 15 + fs/read_write.c | 218 + fs/remap_range.c | 20 +- fs/signalfd.c | 12 +- fs/splice.c | 33 + fs/stack.c | 7 + fs/stat.c | 333 + fs/super.c | 38 + fs/sync.c | 10 + fs/syno_acl.c | 626 + fs/syno_acl.h | 40 + fs/syno_acl_api.c | 270 + fs/udf/inode.c | 9 +- fs/udf/namei.c | 23 + fs/udf/super.c | 90 +- fs/udf/udf_sb.h | 6 + fs/udf/udfdecl.h | 7 + fs/utimes.c | 108 + fs/xattr.c | 96 + include/asm-generic/signal.h | 2 - include/dt-bindings/clock/rtd1195-clk.h | 62 + include/dt-bindings/clock/rtd1295-clk.h | 80 + include/dt-bindings/clock/rtd1319-clk.h | 95 + include/dt-bindings/clock/rtd1395-clk.h | 79 + include/dt-bindings/clock/rtd1619-clk.h | 94 + include/dt-bindings/clock/rtd1619b-clk.h | 109 + include/dt-bindings/power/rtd1295-power.h | 12 + include/dt-bindings/power/rtd1395-power.h | 10 + include/dt-bindings/power/rtd1619-power.h | 12 + include/dt-bindings/power/rtd1619b-power.h | 16 + include/dt-bindings/regulator/anpec,apw888x.h | 12 + include/dt-bindings/reset/rtd1195-reset.h | 65 + include/dt-bindings/reset/rtd1295-reset.h | 108 + include/dt-bindings/reset/rtd1319-reset.h | 143 + include/dt-bindings/reset/rtd1395-reset.h | 82 + include/dt-bindings/reset/rtd1619-reset.h | 112 + include/dt-bindings/reset/rtd1619b-reset.h | 141 + include/dt-bindings/soc/realtek,mem-flag.h | 13 + include/dt-bindings/soc/realtek,pm.h | 42 + include/linux/ata.h | 49 + include/linux/bio.h | 12 + include/linux/blk-mq.h | 12 + include/linux/blk_types.h | 60 + include/linux/blkdev.h | 31 + include/linux/bpf_verifier.h | 2 +- include/linux/ceph/ceph_fs.h | 46 +- include/linux/ceph/ceph_hash.h | 7 + include/linux/ceph/libceph.h | 4 + include/linux/ceph/osdmap.h | 10 + include/linux/compiler.h | 2 + include/linux/console.h | 8 + include/linux/cpu.h | 6 + include/linux/cred.h | 2 - include/linux/crush/crush.h | 12 + include/linux/crush/mapper.h | 6 +- include/linux/dcache.h | 39 +- include/linux/device-mapper.h | 28 + include/linux/dm-io.h | 7 + include/linux/dma-buf.h | 36 + include/linux/etherdevice.h | 5 +- include/linux/falloc.h | 10 + include/linux/fiemap.h | 11 + include/linux/filter.h | 15 + include/linux/fs.h | 288 + include/linux/fs_context.h | 11 + include/linux/fsnotify.h | 182 +- include/linux/fsnotify_backend.h | 34 + include/linux/genhd.h | 48 + include/linux/iomap.h | 10 + include/linux/kernel.h | 15 + include/linux/leds-atmega1608-seg7.h | 46 + include/linux/leds-atmega1608.h | 62 + include/linux/leds-lp3943.h | 74 + include/linux/leds.h | 13 + include/linux/libata.h | 529 + include/linux/lockdep.h | 10 + include/linux/mfd/apw8886.h | 158 + include/linux/mfd/apw8889.h | 182 + include/linux/mfd/apw888x.h | 28 + include/linux/mm.h | 34 + include/linux/mm_types.h | 9 + include/linux/mmc/host.h | 6 + include/linux/mmzone.h | 23 + include/linux/mtd/mtd.h | 11 + include/linux/namei.h | 13 + include/linux/netdevice.h | 7 + include/linux/nvme.h | 17 + include/linux/parser.h | 1 + include/linux/pci.h | 10 + include/linux/raid/libmd-report.h | 27 + include/linux/rbtree.h | 190 + include/linux/relay.h | 7 + include/linux/rmap.h | 7 +- include/linux/sched.h | 11 + include/linux/sched/loadavg.h | 6 + include/linux/sched/sysctl.h | 7 + include/linux/sched/user.h | 6 + include/linux/serial.h | 9 + include/linux/serial_8250.h | 7 + include/linux/shmem_fs.h | 6 + include/linux/skbuff.h | 25 + include/linux/soc/realtek/rtk_pd.h | 14 + include/linux/splice.h | 11 + include/linux/stat.h | 17 + include/linux/sunrpc/stats.h | 11 + include/linux/sunrpc/svc.h | 43 + include/linux/sunrpc/svc_xprt.h | 6 + include/linux/syno_acl.h | 132 + include/linux/syno_acl_xattr.h | 21 + include/linux/syno_fdt.h | 21 + include/linux/syno_fs.h | 337 + include/linux/syno_gpio.h | 161 + include/linux/synobios.h | 10 + include/linux/synolib.h | 276 + include/linux/synosata.h | 548 + include/linux/synotify.h | 17 + include/linux/sys_soc.h | 11 + include/linux/syscalls.h | 32 + include/linux/sysctl.h | 11 + include/linux/task_io_accounting_ops.h | 16 + include/linux/tee_drv.h | 15 + include/linux/tty.h | 9 + include/linux/usb.h | 13 + include/linux/usb/f_mtp.h | 15 + include/linux/usb/hcd.h | 10 + include/linux/usb/syno_quirks.h | 26 + include/linux/usb/uas.h | 23 + include/linux/user_namespace.h | 4 - include/linux/wait.h | 26 + include/linux/workqueue.h | 13 + include/linux/xattr.h | 11 + include/net/bond_alb.h | 29 + include/net/esp.h | 2 + include/net/ipv6.h | 10 + include/net/sock.h | 3 + include/scsi/scsi.h | 16 + include/scsi/scsi_device.h | 72 + include/scsi/scsi_host.h | 44 + include/scsi/scsi_ioctl.h | 1 + include/scsi/scsi_transport.h | 10 + include/scsi/scsi_transport_iscsi.h | 11 +- include/soc/realtek/avcpu.h | 279 + include/soc/realtek/kernel-rpc.h | 57 + include/soc/realtek/memory.h | 126 + include/soc/realtek/rtk-usb-manager.h | 30 + include/soc/realtek/rtk_cec.h | 19 + include/soc/realtek/rtk_chip.h | 182 + include/soc/realtek/rtk_cpuhp.h | 25 + include/soc/realtek/rtk_i2c.h | 23 + include/soc/realtek/rtk_ipc_shm.h | 107 + include/soc/realtek/rtk_ir.h | 32 + include/soc/realtek/rtk_iso.h | 58 + include/soc/realtek/rtk_misc.h | 28 + include/soc/realtek/rtk_pcie.h | 18 + include/soc/realtek/rtk_pm.h | 107 + include/soc/realtek/rtk_refclk.h | 25 + include/soc/realtek/rtk_rstctl.h | 29 + include/soc/realtek/rtk_sb2_dbg.h | 61 + include/soc/realtek/rtk_sb2_sem.h | 39 + include/soc/realtek/rtk_sha1.h | 40 + include/soc/realtek/uapi/ashmem.h | 48 + include/soc/realtek/uapi/ion.h | 136 + include/soc/realtek/uapi/ion_rtk.h | 164 + include/soc/realtek/uapi/vsoc_shm.h | 303 + include/trace/events/btrfs.h | 83 + include/trace/events/ext4.h | 29 + include/trace/events/mmc.h | 59 + include/trace/events/rtk_pm.h | 76 + include/trace/events/rtk_rpc.h | 70 + include/trace/events/sunrpc.h | 1 - include/trace/events/syno.h | 136 + include/uapi/asm-generic/poll.h | 2 +- include/uapi/asm-generic/stat.h | 27 + include/uapi/asm-generic/unistd.h | 91 + include/uapi/linux/aufs_type.h | 452 + include/uapi/linux/btrfs.h | 837 ++ include/uapi/linux/btrfs_tree.h | 390 + include/uapi/linux/falloc.h | 13 + include/uapi/linux/fs.h | 98 + include/uapi/linux/mmc/ioctl.h | 20 + include/uapi/linux/mount.h | 6 + include/uapi/linux/nfs2.h | 19 + include/uapi/linux/raid/md_p.h | 10 + include/uapi/linux/raid/md_u.h | 13 + include/uapi/linux/stat.h | 63 + include/uapi/linux/syno.h | 114 + include/uapi/linux/syno_acl.h | 154 + include/uapi/linux/syno_acl_xattr_ds.h | 12 + include/uapi/linux/synobios.h | 585 + include/uapi/linux/synotify.h | 75 + include/uapi/linux/sysctl.h | 14 + include/uapi/linux/tee.h | 34 + include/uapi/linux/usb/f_mtp.h | 53 + include/uapi/linux/xattr.h | 42 + include/uapi/mtd/mtd-abi.h | 27 + init/Kconfig | 4 +- init/do_mounts.c | 7 + init/initramfs.c | 35 + kernel/Makefile | 3 + kernel/bpf/core.c | 19 +- kernel/bpf/disasm.c | 16 +- kernel/bpf/verifier.c | 97 +- kernel/cpu.c | 17 + kernel/cred.c | 41 - kernel/events/core.c | 14 + kernel/fork.c | 24 +- kernel/hung_task.c | 23 + kernel/kthread.c | 33 +- kernel/locking/lockdep.c | 11 + kernel/module.c | 39 + kernel/pid.c | 8 + kernel/printk/printk.c | 46 + kernel/reboot.c | 26 + kernel/relay.c | 25 + kernel/sched/core.c | 26 + kernel/sched/cputime.c | 15 + kernel/sched/fair.c | 50 +- kernel/sched/loadavg.c | 152 + kernel/sched/sched.h | 15 + kernel/sched/wait.c | 7 + kernel/softirq.c | 7 + kernel/stacktrace.c | 6 + kernel/syno-module-internal.h | 7 + kernel/syno_bootargs.c | 375 + kernel/sys.c | 12 - kernel/sysctl.c | 892 +- kernel/task_work.c | 6 + kernel/time/ntp.c | 7 + kernel/time/time.c | 7 + kernel/trace/blktrace.c | 30 + kernel/ucount.c | 40 +- kernel/user_namespace.c | 3 - kernel/watchdog.c | 37 + kernel/watchdog_hld.c | 19 + kernel/workqueue.c | 54 + kernel/workqueue_internal.h | 28 + kernel/workstat.c | 405 + lib/Kconfig | 7 +- lib/Kconfig.kcsan | 11 - lib/Kconfig.ubsan | 12 - lib/Makefile | 2 + lib/decompress_unlzma.c | 9 + lib/iov_iter.c | 2 + lib/parser.c | 44 +- lib/synolib/Makefile | 18 + lib/synolib/asm116xfwdl/116xfwdl.c | 1108 ++ lib/synolib/asm116xfwdl/Makefile | 6 + lib/synolib/asm116xfwdl/asm116.h | 52 + lib/synolib/asm116xfwdl/crc.c | 99 + lib/synolib/asm116xfwdl/crc.h | 29 + lib/synolib/asm116xfwdl/precomp.h | 74 + lib/synolib/asm116xfwdl/spictrl.c | 432 + lib/synolib/asm116xfwdl/spictrl.h | 168 + lib/synolib/asm116xfwdl/spifile.h | 193 + lib/synolib/asm116xfwdl/spiflash.c | 1954 +++ lib/synolib/asm116xfwdl/spiflash.h | 194 + lib/synolib/syno_ahci_reg_read_test.c | 143 + lib/synolib/syno_check_on_opt_pci.c | 43 + lib/synolib/syno_disk_pwr_ctrl.c | 296 + lib/synolib/syno_disk_ready_check.c | 39 + lib/synolib/syno_disk_wait_for_spindown.c | 67 + lib/synolib/syno_draw_auto_remap_buffer.c | 31 + lib/synolib/syno_fdt.c | 242 + lib/synolib/syno_hddpwrctl_test.c | 158 + lib/synolib/syno_jmb585_update_spi.c | 318 + lib/synolib/syno_kexec_test.c | 213 + lib/synolib/syno_pciepath_dts_pattern.c | 98 + lib/synolib/syno_plugin.c | 211 + lib/synolib/syno_sata_signal_check.c | 301 + lib/synolib/syno_sata_signal_test.c | 1044 ++ lib/synolib/syno_uart2spi_logout.c | 198 + mm/Kconfig | 2 +- mm/Makefile | 1 + mm/cma.c | 11 + mm/compaction.c | 23 + mm/filemap.c | 204 + mm/mmap.c | 60 + mm/mremap.c | 8 + mm/nommu.c | 25 + mm/oom_kill.c | 32 + mm/page-writeback.c | 15 + mm/page_alloc.c | 22 +- mm/prfile.c | 86 + mm/rmap.c | 35 +- mm/shmem.c | 92 + mm/swapfile.c | 27 + mm/util.c | 6 + mm/vmscan.c | 138 + net/Kconfig | 9 +- net/ceph/ceph_hash.c | 11 + net/ceph/crush/mapper.c | 725 +- net/ceph/debugfs.c | 83 + net/ceph/messenger.c | 24 + net/ceph/mon_client.c | 4 + net/ceph/osdmap.c | 47 +- net/core/dev.c | 171 + net/core/net-sysfs.c | 62 + net/core/sock.c | 39 +- net/ethernet/eth.c | 14 + net/ipv4/af_inet.c | 23 +- net/ipv4/esp4.c | 5 + net/ipv4/igmp.c | 2 + net/ipv4/ip_gre.c | 2 + net/ipv4/route.c | 56 +- net/ipv4/tcp.c | 10 +- net/ipv4/tcp_ipv4.c | 8 + net/ipv6/addrconf.c | 11 + net/ipv6/af_inet6.c | 21 + net/ipv6/datagram.c | 17 + net/ipv6/esp6.c | 5 + net/ipv6/ipv6_sockglue.c | 10 +- net/ipv6/raw.c | 16 + net/ipv6/route.c | 25 +- net/ipv6/tcp_ipv6.c | 23 +- net/key/af_key.c | 5 +- net/netfilter/nf_nat_core.c | 66 +- net/netfilter/nf_tables_api.c | 36 +- net/netfilter/nf_tables_core.c | 2 +- net/netfilter/nfnetlink_queue.c | 7 +- net/openvswitch/datapath.c | 375 + net/openvswitch/datapath.h | 36 + net/openvswitch/dp_notify.c | 40 + net/openvswitch/flow_netlink.c | 2 +- net/openvswitch/vport-internal_dev.c | 30 + net/openvswitch/vport-netdev.c | 27 + net/packet/af_packet.c | 16 +- net/sched/cls_api.c | 11 +- net/sched/cls_u32.c | 16 +- net/sunrpc/clnt.c | 55 +- net/sunrpc/sched.c | 1 + net/sunrpc/stats.c | 12 + net/sunrpc/svc.c | 7 + net/sunrpc/svc_xprt.c | 53 +- net/sunrpc/xprt.c | 7 +- net/sunrpc/xprtsock.c | 16 +- net/unix/af_unix.c | 34 +- net/xfrm/xfrm_policy.c | 5 +- scripts/Makefile | 4 + scripts/Makefile.extrawarn | 1 + scripts/headers_install.sh | 4 + scripts/kallsyms.c | 32 + scripts/kconfig/confdata.c | 34 + scripts/link-vmlinux.sh | 2 +- scripts/lld-version.sh | 35 +- scripts/mod/modpost.c | 1 + scripts/pahole-flags.sh | 21 + security/apparmor/apparmorfs.c | 1 + security/apparmor/include/apparmor.h | 2 +- security/apparmor/include/net.h | 11 + security/apparmor/include/policy.h | 2 + security/apparmor/net.c | 31 +- security/apparmor/policy.c | 22 + security/apparmor/policy_unpack.c | 54 +- security/security.c | 27 + security/selinux/hooks.c | 7 + synology/certs/.gitignore | 0 synology/synoconfigs-spec/CONFIG_CRYPTO.rb | 28 + .../synoconfigs-spec/CONFIG_DEBUG_OPTIONS.rb | 36 + .../CONFIG_GENERAL_SETUP_#.rb | 62 + .../synoconfigs-spec/CONFIG_KERNEL_LZMA.rb | 16 + synology/synoconfigs-spec/CONFIG_NUMA.rb | 19 + synology/synoconfigs-spec/CONFIG_PCIEASPM.rb | 28 + synology/synoconfigs-spec/CONFIG_QUOTA_#.rb | 36 + synology/synoconfigs-spec/CONFIG_SWIOTLB.rb | 17 + .../synoconfigs-spec/CONFIG_SYNO_AUFS_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_BASIC_#.rb | 25 + .../synoconfigs-spec/CONFIG_SYNO_BTRFS_#.rb | 59 + .../synoconfigs-spec/CONFIG_SYNO_CIFS_#.rb | 18 + .../CONFIG_SYNO_CONFIGFS_#.rb | 18 + .../CONFIG_SYNO_ECRYPTFS_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_EXT4_#.rb | 61 + .../synoconfigs-spec/CONFIG_SYNO_FAT_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_FEATURES.rb | 13 + synology/synoconfigs-spec/CONFIG_SYNO_FS_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_FUSE_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_HFSPLUS_#.rb | 18 + .../CONFIG_SYNO_IOMMU_PASSTHROUGH.rb | 16 + synology/synoconfigs-spec/CONFIG_SYNO_MD_#.rb | 65 + .../synoconfigs-spec/CONFIG_SYNO_MODULE_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_NFS_#.rb | 98 + .../CONFIG_SYNO_OVERLAYFS_#.rb | 18 + .../CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT.rb | 22 + .../synoconfigs-spec/CONFIG_SYNO_TMPFS_#.rb | 18 + .../CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS.rb | 16 + .../synoconfigs-spec/CONFIG_SYNO_UDF_#.rb | 18 + .../synoconfigs-spec/CONFIG_SYNO_USB_#.rb | 38 + synology/synoconfigs-spec/Rakefile | 21 + synology/synoconfigs-spec/lib/ansi/chart.rb | 100 + synology/synoconfigs-spec/lib/ansi/code.rb | 349 + .../synoconfigs-spec/lib/ansi/constants.rb | 25 + synology/synoconfigs-spec/lib/inifile.rb | 632 + .../minitest/extensible_backtrace_filter.rb | 67 + .../synoconfigs-spec/lib/minitest/hooks.rb | 7 + .../lib/minitest/hooks/default.rb | 3 + .../lib/minitest/hooks/test.rb | 132 + .../lib/minitest/minitest_reporter_plugin.rb | 73 + .../lib/minitest/relative_position.rb | 26 + .../lib/minitest/reporters.rb | 85 + .../lib/minitest/reporters/ansi.rb | 35 + .../lib/minitest/reporters/base_reporter.rb | 101 + .../minitest/reporters/default_reporter.rb | 216 + .../lib/minitest/reporters/spec_reporter.rb | 71 + .../lib/minitest/reporters/version.rb | 5 + synology/synoconfigs-spec/lib/platform.rb | 59 + .../synoconfigs-spec/lib/platform_helper.rb | 20 + synology/synoconfigs-spec/lib/syno_kconfig.rb | 125 + synology/synoconfigs/Kconfig | 13 + synology/synoconfigs/Kconfig.basic | 206 + synology/synoconfigs/Kconfig.devices | 1367 ++ synology/synoconfigs/Kconfig.fs | 1212 ++ synology/synoconfigs/Kconfig.misc | 163 + synology/synoconfigs/Kconfig.network | 57 + synology/synoconfigs/Kconfig.platform | 90 + synology/synoconfigs/back-porting-records | 7 + synology/synoconfigs/epyc7002 | 5992 +++++++++ synology/synoconfigs/epyc7002sofs | 5803 ++++++++ synology/synoconfigs/epyc7003ntb | 5819 ++++++++ synology/synoconfigs/fst-ci-config | 4721 +++++++ synology/synoconfigs/fst-locker-config | 3239 +++++ synology/synoconfigs/geminilakelk5 | 5925 +++++++++ synology/synoconfigs/icelaked | 5787 ++++++++ synology/synoconfigs/kvmx64lk5 | 5493 ++++++++ synology/synoconfigs/kvmx64sofs | 5516 ++++++++ synology/synoconfigs/kvmx64v2 | 5517 ++++++++ synology/synoconfigs/purleylk5 | 5810 ++++++++ synology/synoconfigs/rtd1619b | 6002 +++++++++ synology/synoconfigs/rtd1619bmango | 6001 +++++++++ synology/synoconfigs/ryzen5k | 5815 ++++++++ synology/synoconfigs/soit-ci-config | 1 + synology/synoconfigs/v1000lk5 | 5746 ++++++++ synology/synoconfigs/v1000sofs | 5757 ++++++++ .../systemd/syno-fan-modules-load.service | 14 + synology/systemd/syno-fan-modules-load.sh | 130 + .../systemd/syno-kernel-modules-load.service | 14 + synology/systemd/syno-kernel-modules-load.sh | 138 + tools/include/linux/rbtree.h | 192 +- tools/include/uapi/linux/fs.h | 11 + tools/lib/subcmd/subcmd-util.h | 11 +- tools/objtool/elf.c | 73 +- tools/perf/bench/inject-buildid.c | 52 +- tools/perf/builtin-sched.c | 2 +- tools/testing/selftests/vm/userfaultfd.c | 2 +- tools/virtio/linux/device.h | 2 - 1993 files changed, 475779 insertions(+), 4517 deletions(-) create mode 100644 Documentation/ABI/testing/debugfs-aufs create mode 100644 Documentation/ABI/testing/sysfs-aufs create mode 100644 Documentation/devicetree/bindings/clock/realtek,clocks.txt create mode 100644 Documentation/devicetree/bindings/iio/adc/realtek,rtk-lsadc.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/realtek,intc.txt create mode 100644 Documentation/devicetree/bindings/mfd/apw888x.txt create mode 100644 Documentation/devicetree/bindings/net/realtek,r8169soc.txt create mode 100644 Documentation/devicetree/bindings/nvmem/rtk-efuse.txt create mode 100644 Documentation/devicetree/bindings/power/reset/regmap-poweroff.txt create mode 100644 Documentation/devicetree/bindings/power/reset/rtk,reboot-mode.txt create mode 100644 Documentation/devicetree/bindings/power/reset/rtk,reboot.txt create mode 100644 Documentation/devicetree/bindings/pwm/realtek,rtk-pwm.txt create mode 100644 Documentation/devicetree/bindings/reserved-memory/realtek,shared-memory.txt create mode 100644 Documentation/devicetree/bindings/reset/rtk-reset.txt create mode 100644 Documentation/devicetree/bindings/rtc/rtc-rtk.txt create mode 100644 Documentation/devicetree/bindings/rtc/rtc-sw.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/bsv_ctrl.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/crt.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/dbus_pmu.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/ddrc_pmu.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/info.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/power-domain.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/rbus_pmu.txt create mode 100644 Documentation/devicetree/bindings/soc/realtek/wdt_st.txt create mode 100644 Documentation/devicetree/bindings/sound/snd-realtek-notify.txt create mode 100644 Documentation/devicetree/bindings/sound/snd-realtek.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-dw-rtk.txt create mode 100644 Documentation/devicetree/bindings/thermal/realtek-thermal.txt create mode 100644 Documentation/devicetree/bindings/watchdog/rtk-wdt.txt create mode 100644 Documentation/filesystems/aufs/README create mode 100644 Documentation/filesystems/aufs/design/01intro.txt create mode 100644 Documentation/filesystems/aufs/design/02struct.txt create mode 100644 Documentation/filesystems/aufs/design/03atomic_open.txt create mode 100644 Documentation/filesystems/aufs/design/03lookup.txt create mode 100644 Documentation/filesystems/aufs/design/04branch.txt create mode 100644 Documentation/filesystems/aufs/design/05wbr_policy.txt create mode 100644 Documentation/filesystems/aufs/design/06dirren.dot create mode 100644 Documentation/filesystems/aufs/design/06dirren.txt create mode 100644 Documentation/filesystems/aufs/design/06fhsm.txt create mode 100644 Documentation/filesystems/aufs/design/06mmap.txt create mode 100644 Documentation/filesystems/aufs/design/06xattr.txt create mode 100644 Documentation/filesystems/aufs/design/07export.txt create mode 100644 Documentation/filesystems/aufs/design/08shwh.txt create mode 100644 Documentation/filesystems/aufs/design/10dynop.txt create mode 100644 SynoBuildConf/_env create mode 100644 SynoBuildConf/_kconfig create mode 100644 SynoBuildConf/_modules create mode 100644 SynoBuildConf/_platform create mode 100644 SynoBuildConf/build create mode 100644 SynoBuildConf/build-virtual-headers create mode 100644 SynoBuildConf/build-virtual-qctool create mode 100644 SynoBuildConf/conflict create mode 100644 SynoBuildConf/conflict-virtual-headers create mode 100644 SynoBuildConf/depends create mode 100644 SynoBuildConf/depends-virtual-qctool create mode 100644 SynoBuildConf/error create mode 100644 SynoBuildConf/gitlab-ci create mode 100644 SynoBuildConf/install create mode 100644 SynoBuildConf/install-dev create mode 100644 SynoBuildConf/install-dev-virtual-headers create mode 100644 SynoBuildConf/install-virinst-Satatool create mode 100644 SynoBuildConf/install-virinst-T1tool create mode 100644 SynoBuildConf/install-virtual-qctool create mode 100644 SynoBuildConf/shellcheck create mode 100644 SynoBuildConf/version create mode 100644 arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds124.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223j.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds423.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd-1619b-synology-mango.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1319-pymparticles-2gb.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1319-pymparticles.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd1319-rescue.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd13xx-efuse.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd13xx-pcie.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd13xx-pinctrl.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd13xx-rescue.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd13xx-usb.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd13xx.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb-nas.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb-spi.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-4gb.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-rescue-nas.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd1619b-rescue.dts create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb-efuse.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb-etn-wol-pattern.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb-pcie.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb-pinctrl.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb-rescue.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb-usb.dtsi create mode 100644 arch/arm64/boot/dts/realtek/rtd16xxb.dtsi create mode 100644 arch/arm64/configs/rtd161xxb_nas_spi_defconfig create mode 100644 crypto/hydrogen/Makefile create mode 100644 drivers/acpi/acpi_fpdt.c create mode 100644 drivers/ata/ahci_rtk.c create mode 100644 drivers/ata/ata_syno_i2c.c create mode 100644 drivers/bluetooth/rtk_rfkill.c create mode 100644 drivers/char/hw_random/rtd1319-rng.c create mode 100644 drivers/clk/realtek/Kconfig create mode 100644 drivers/clk/realtek/Makefile create mode 100644 drivers/clk/realtek/clk-det.c create mode 100644 drivers/clk/realtek/clk-det.h create mode 100644 drivers/clk/realtek/clk-pll-dif.c create mode 100644 drivers/clk/realtek/clk-pll-psaud.c create mode 100644 drivers/clk/realtek/clk-pll.c create mode 100644 drivers/clk/realtek/clk-pll.h create mode 100644 drivers/clk/realtek/clk-regmap-gate.c create mode 100644 drivers/clk/realtek/clk-regmap-gate.h create mode 100644 drivers/clk/realtek/clk-regmap-mux.c create mode 100644 drivers/clk/realtek/clk-regmap-mux.h create mode 100644 drivers/clk/realtek/clk-rtd1195-cc.c create mode 100644 drivers/clk/realtek/clk-rtd1195-ic.c create mode 100644 drivers/clk/realtek/clk-rtd1295-cc.c create mode 100644 drivers/clk/realtek/clk-rtd1295-ic.c create mode 100644 drivers/clk/realtek/clk-rtd1319-cc.c create mode 100644 drivers/clk/realtek/clk-rtd1319-ic.c create mode 100644 drivers/clk/realtek/clk-rtd1395-cc.c create mode 100644 drivers/clk/realtek/clk-rtd1395-ic.c create mode 100644 drivers/clk/realtek/clk-rtd1619-cc.c create mode 100644 drivers/clk/realtek/clk-rtd1619-ic.c create mode 100644 drivers/clk/realtek/clk-rtd1619b-cc.c create mode 100644 drivers/clk/realtek/clk-rtd1619b-ic.c create mode 100644 drivers/clk/realtek/clk-tee.c create mode 100644 drivers/clk/realtek/common.c create mode 100644 drivers/clk/realtek/common.h create mode 100644 drivers/clk/realtek/debugfs.c create mode 100644 drivers/clk/realtek/of-conf.c create mode 100644 drivers/clk/realtek/of-conf.h create mode 100644 drivers/clk/realtek/reset.c create mode 100644 drivers/clk/realtek/reset.h create mode 100644 drivers/gpio/gpio-rtd.c create mode 100644 drivers/gpio/syno_gpio.c create mode 100644 drivers/hwmon/syno_hddmon.c create mode 100644 drivers/hwmon/syno_smbus_hddmon.c create mode 100644 drivers/i2c/busses/i2c-rtk.c create mode 100644 drivers/i2c/busses/i2c-rtk.h create mode 100644 drivers/iio/adc/rtk_lsadc0.c create mode 100644 drivers/iio/adc/rtk_lsadc0.h create mode 100644 drivers/irqchip/irq-realtek-mux.c create mode 100644 drivers/irqchip/irq-realtek-mux.h create mode 100644 drivers/leds/leds-atmega1608-seg7.c create mode 100644 drivers/leds/leds-atmega1608.c create mode 100644 drivers/leds/leds-lp3943.c create mode 100644 drivers/leds/trigger/ledtrig-disk-syno.c create mode 100644 drivers/leds/trigger/syno_ledtrig.c create mode 100644 drivers/md/libmd-report.c create mode 100644 drivers/md/syno-md-fast-wakeup.h create mode 100644 drivers/md/syno-md-hint.c create mode 100644 drivers/md/syno-md-hint.h create mode 100644 drivers/mfd/apw8886-i2c.c create mode 100644 drivers/mfd/apw8889-i2c.c create mode 100644 drivers/mfd/apw888x-core.c create mode 100644 drivers/mmc/host/mmc_debug.h create mode 100644 drivers/mmc/host/reg_iso.h create mode 100644 drivers/mmc/host/reg_mmc.h create mode 100644 drivers/mmc/host/reg_mmc_rtd13xx.h create mode 100644 drivers/mmc/host/reg_sys.h create mode 100644 drivers/mmc/host/rtk-sdmmc-export.c create mode 100644 drivers/mmc/host/rtk-sdmmc-reg.h create mode 100644 drivers/mmc/host/rtk-sdmmc.c create mode 100644 drivers/mmc/host/rtk-sdmmc.h create mode 100644 drivers/mmc/host/rtkemmc_rtd13xx.c create mode 100644 drivers/mmc/host/rtkemmc_rtd13xx.h create mode 100644 drivers/mmc/host/sdhci-rtk.c create mode 100644 drivers/mmc/host/sdhci-rtk.h create mode 100644 drivers/mtd/nand/raw/rtk_bbm.c create mode 100644 drivers/mtd/nand/raw/rtk_nand.c create mode 100644 drivers/mtd/nand/raw/rtk_nand.h create mode 100644 drivers/mtd/spi-nor/controllers/rtk-sfc.c create mode 100644 drivers/net/ethernet/realtek/r8169soc.c create mode 100644 drivers/nvmem/rtk-efuse.c create mode 100644 drivers/pci/controller/pcie-rtd-trans.c create mode 100644 drivers/pci/controller/pcie-rtd.c create mode 100644 drivers/pci/controller/pcie-rtd.h create mode 100644 drivers/phy/realtek/Kconfig create mode 100644 drivers/phy/realtek/Makefile create mode 100644 drivers/phy/realtek/phy-rtk-pcie.c create mode 100644 drivers/phy/realtek/phy-rtk-sata.c create mode 100644 drivers/pinctrl/intel/syno-pinctrl-lewisburg.c create mode 100644 drivers/pinctrl/realtek/Kconfig create mode 100644 drivers/pinctrl/realtek/Makefile create mode 100644 drivers/pinctrl/realtek/pinctrl-rtd.c create mode 100644 drivers/pinctrl/realtek/pinctrl-rtd1319.h create mode 100644 drivers/pinctrl/realtek/pinctrl-rtd1619b.h create mode 100644 drivers/power/reset/regmap-poweroff.c create mode 100644 drivers/power/reset/rtk-reboot-mode.c create mode 100644 drivers/power/reset/rtk-reboot.c create mode 100644 drivers/pwm/pwm-rtk.c create mode 100644 drivers/regulator/apw8886-regulator.c create mode 100644 drivers/regulator/apw8889-regulator.c create mode 100644 drivers/regulator/apw888x-regulator-core.c create mode 100644 drivers/regulator/apw888x-regulator.h create mode 100644 drivers/regulator/virtual-helper.c create mode 100644 drivers/reset/reset-rtk-m2tmx.c create mode 100644 drivers/rtc/rtc-rtk.c create mode 100644 drivers/scsi/libsyno_report.c create mode 100644 drivers/scsi/libsyno_report.h create mode 100644 drivers/soc/realtek/Kconfig create mode 100644 drivers/soc/realtek/Makefile create mode 100644 drivers/soc/realtek/common/Kconfig create mode 100644 drivers/soc/realtek/common/Makefile create mode 100644 drivers/soc/realtek/common/buflock/Kconfig create mode 100644 drivers/soc/realtek/common/buflock/Makefile create mode 100644 drivers/soc/realtek/common/buflock/src/buflock.c create mode 100644 drivers/soc/realtek/common/buflock/uapi/buflock.h create mode 100644 drivers/soc/realtek/common/chip.c create mode 100644 drivers/soc/realtek/common/dvfs/Kconfig create mode 100644 drivers/soc/realtek/common/dvfs/Makefile create mode 100644 drivers/soc/realtek/common/dvfs/cpu-volt-sel.c create mode 100644 drivers/soc/realtek/common/hse/Kconfig create mode 100644 drivers/soc/realtek/common/hse/Makefile create mode 100644 drivers/soc/realtek/common/hse/cq.c create mode 100644 drivers/soc/realtek/common/hse/device.c create mode 100644 drivers/soc/realtek/common/hse/engine.c create mode 100644 drivers/soc/realtek/common/hse/hse.h create mode 100644 drivers/soc/realtek/common/hse/include/hse-sw.h create mode 100644 drivers/soc/realtek/common/hse/include/hsectl.h create mode 100644 drivers/soc/realtek/common/hse/platform.c create mode 100644 drivers/soc/realtek/common/info/Kconfig create mode 100644 drivers/soc/realtek/common/info/Makefile create mode 100644 drivers/soc/realtek/common/info/rtk_info.c create mode 100644 drivers/soc/realtek/common/info/rtk_info.h create mode 100644 drivers/soc/realtek/common/info/rtk_info_pll.c create mode 100644 drivers/soc/realtek/common/mem_allocator/Kconfig create mode 100644 drivers/soc/realtek/common/mem_allocator/Makefile create mode 100644 drivers/soc/realtek/common/mem_allocator/ion-ioctl.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion.h create mode 100644 drivers/soc/realtek/common/mem_allocator/ion_carveout_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion_chunk_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion_cma_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion_page_pool.c create mode 100644 drivers/soc/realtek/common/mem_allocator/ion_system_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/Kconfig create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/Makefile create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_alloc.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_protected_notifier.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/dev.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/flags.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/pool.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/pool_cma.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/pool_common.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/pool_gen.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/protected.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/protected.h create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/src/sys_heap.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/test/Makefile create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/Makefile create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/test-protecteds-_notifier.c create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/Makefile create mode 100644 drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/test-alloc-ion-protected.c create mode 100644 drivers/soc/realtek/common/rpc/Kconfig create mode 100644 drivers/soc/realtek/common/rpc/Makefile create mode 100644 drivers/soc/realtek/common/rpc/compat_rpc_mem.c create mode 100644 drivers/soc/realtek/common/rpc/compat_rpc_mem.h create mode 100644 drivers/soc/realtek/common/rpc/rpc_mem.c create mode 100644 drivers/soc/realtek/common/rpc/rpc_mem.h create mode 100644 drivers/soc/realtek/common/rpc/rpc_mem_uapi.h create mode 100644 drivers/soc/realtek/common/rpc/rtk_rpc.c create mode 100644 drivers/soc/realtek/common/rpc/rtk_rpc.h create mode 100644 drivers/soc/realtek/common/rpc/rtk_rpc_intr.c create mode 100644 drivers/soc/realtek/common/rpc/rtk_rpc_kern.c create mode 100644 drivers/soc/realtek/common/rpc/rtk_rpc_poll.c create mode 100644 drivers/soc/realtek/common/rtk_bootstatus.c create mode 100644 drivers/soc/realtek/common/rtk_bsv_ctrl.c create mode 100644 drivers/soc/realtek/common/rtk_cpu_vclk.c create mode 100644 drivers/soc/realtek/common/rtk_cpuhp.c create mode 100644 drivers/soc/realtek/common/rtk_cpuhp_ctrl.c create mode 100644 drivers/soc/realtek/common/rtk_crt.c create mode 100644 drivers/soc/realtek/common/rtk_fan.c create mode 100644 drivers/soc/realtek/common/rtk_fss_scan.c create mode 100644 drivers/soc/realtek/common/rtk_fw_pm.c create mode 100644 drivers/soc/realtek/common/rtk_gpio_default.c create mode 100644 drivers/soc/realtek/common/rtk_iso_wa.c create mode 100644 drivers/soc/realtek/common/rtk_mcp.c create mode 100644 drivers/soc/realtek/common/rtk_mcp.h create mode 100644 drivers/soc/realtek/common/rtk_memory_remap.c create mode 100644 drivers/soc/realtek/common/rtk_pd/Kconfig create mode 100644 drivers/soc/realtek/common/rtk_pd/Makefile create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_gpc.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_iso.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_iso.h create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd-pm.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1295.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1395.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619b.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd.h create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_pd_internal.h create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_sram.c create mode 100644 drivers/soc/realtek/common/rtk_pd/rtk_sram.h create mode 100644 drivers/soc/realtek/common/rtk_pm.c create mode 100644 drivers/soc/realtek/common/rtk_pm_common.c create mode 100644 drivers/soc/realtek/common/rtk_pm_sysfs.c create mode 100644 drivers/soc/realtek/common/rtk_refclk.c create mode 100644 drivers/soc/realtek/common/rtk_sb2.c create mode 100644 drivers/soc/realtek/common/rtk_sb2.h create mode 100644 drivers/soc/realtek/common/rtk_sb2_dbg.c create mode 100644 drivers/soc/realtek/common/rtk_sb2_inv.c create mode 100644 drivers/soc/realtek/common/rtk_sb2_sem.c create mode 100644 drivers/soc/realtek/common/rtk_sc_wrap.c create mode 100644 drivers/soc/realtek/common/rtk_sha1.c create mode 100644 drivers/soc/realtek/common/rtk_usb.h create mode 100644 drivers/soc/realtek/common/rtk_usb_manager.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd119x.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd129x.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd1312c.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd139x.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd13xx.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd16xx.c create mode 100644 drivers/soc/realtek/common/rtk_usb_rtd16xxb.c create mode 100644 drivers/soc/realtek/common/rtk_vcpu.c create mode 100644 drivers/soc/realtek/common/rtk_ve3_uart.c create mode 100644 drivers/soc/realtek/common/rtk_vsfc_ctrl.c create mode 100644 drivers/soc/realtek/common/rtk_watchdog_status.c create mode 100644 drivers/soc/realtek/rtd13xx/Makefile create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/Makefile create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/jdi/Makefile create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.c create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jmm.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.c create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.c create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/Makefile create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.c create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.c create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.c create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1config.h create mode 100644 drivers/soc/realtek/rtd13xx/rtk_ve/ve1/vmm.h create mode 100644 drivers/soc/realtek/rtd16xxb/Makefile create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/Makefile create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/Makefile create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.c create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jmm.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.c create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.c create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/Makefile create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.c create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.c create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.c create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1config.h create mode 100644 drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/vmm.h create mode 100644 drivers/soc/realtek/trace/Makefile create mode 100644 drivers/soc/realtek/trace/rtk_pm.c create mode 100644 drivers/spi/spi-dw-rtk.c create mode 100644 drivers/syno/Kconfig create mode 100644 drivers/syno/Makefile create mode 100644 drivers/syno/syno-flashcache-control-driver/Makefile create mode 100644 drivers/syno/syno-flashcache-control-driver/syno_flashcache_control.c create mode 100644 drivers/syno/syno-mem-saving-driver/Makefile create mode 100644 drivers/syno/syno-mem-saving-driver/dkms.conf create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache.h create mode 100755 drivers/syno/syno-mem-saving-driver/flashcache.hook create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_conf.c create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_ioctl.c create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_ioctl.h create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_main.c create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_pin_file.h create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_procfs.c create mode 100644 drivers/syno/syno-mem-saving-driver/flashcache_subr.c create mode 100644 drivers/syno/syno-mem-saving-driver/ocf/Makefile create mode 100755 drivers/syno/syno-mem-saving-driver/ocf/flashcache create mode 100644 drivers/syno/syno-mem-saving-driver/syno_common_4k_driver.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_common_tool.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_feature_defines.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_functions.c create mode 100644 drivers/syno/syno-mem-saving-driver/syno_functions.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_kernel_functions.c create mode 100644 drivers/syno/syno-mem-saving-driver/syno_kernel_functions.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_md_update.c create mode 100644 drivers/syno/syno-mem-saving-driver/syno_md_update.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_quickflush.c create mode 100644 drivers/syno/syno-mem-saving-driver/syno_quickflush.h create mode 100644 drivers/syno/syno-mem-saving-driver/syno_unit_test.c create mode 100644 drivers/syno/syno-mem-saving-driver/syno_unit_test.h create mode 100644 drivers/syno/synobios/Makefile create mode 100644 drivers/syno/synobios/Makefile.inc create mode 100644 drivers/syno/synobios/Makefile_vdsm.inc create mode 100644 drivers/syno/synobios/SynoBuildConf/build create mode 100644 drivers/syno/synobios/SynoBuildConf/build-virtual-headers create mode 100644 drivers/syno/synobios/SynoBuildConf/conflict-virtual-headers create mode 100644 drivers/syno/synobios/SynoBuildConf/depends create mode 100644 drivers/syno/synobios/SynoBuildConf/depends-virtual-headers create mode 100644 drivers/syno/synobios/SynoBuildConf/install-dev create mode 100644 drivers/syno/synobios/SynoBuildConf/install-dev-virtual-headers create mode 100644 drivers/syno/synobios/alpine/Makefile create mode 100644 drivers/syno/synobios/alpine/alpine_common.c create mode 100644 drivers/syno/synobios/alpine/alpine_common.h create mode 100644 drivers/syno/synobios/alpine/ds1515.c create mode 100644 drivers/syno/synobios/alpine/ds1517.c create mode 100644 drivers/syno/synobios/alpine/ds1817.c create mode 100644 drivers/syno/synobios/alpine/ds2015xs.c create mode 100644 drivers/syno/synobios/alpine/ds215+.c create mode 100755 drivers/syno/synobios/alpine/ds416.c create mode 100644 drivers/syno/synobios/alpine/ds715.c create mode 100755 drivers/syno/synobios/alpine/fan-pwm.c create mode 100644 drivers/syno/synobios/alpine/rs1219.c create mode 100644 drivers/syno/synobios/apollolake/Makefile create mode 100755 drivers/syno/synobios/apollolake/apollolake_common.c create mode 100755 drivers/syno/synobios/apollolake/apollolake_common.h create mode 100644 drivers/syno/synobios/apollolake/ds1019p.c create mode 100644 drivers/syno/synobios/apollolake/ds218p.c create mode 100644 drivers/syno/synobios/apollolake/ds418play.c create mode 100644 drivers/syno/synobios/apollolake/ds419p.c create mode 100644 drivers/syno/synobios/apollolake/ds620slim.c create mode 100644 drivers/syno/synobios/apollolake/ds718p.c create mode 100644 drivers/syno/synobios/apollolake/ds719p.c create mode 100644 drivers/syno/synobios/apollolake/ds918p.c create mode 100644 drivers/syno/synobios/apollolake/rs419p.c create mode 100644 drivers/syno/synobios/armada/Makefile create mode 100755 drivers/syno/synobios/armada/armada_common.c create mode 100755 drivers/syno/synobios/armada/armada_common.h create mode 100755 drivers/syno/synobios/armada/ds114.c create mode 100755 drivers/syno/synobios/armada/ds115.c create mode 100755 drivers/syno/synobios/armada/ds115j.c create mode 100755 drivers/syno/synobios/armada/ds213j.c create mode 100755 drivers/syno/synobios/armada/ds214.c create mode 100755 drivers/syno/synobios/armada/ds214p.c create mode 100755 drivers/syno/synobios/armada/ds214se.c create mode 100755 drivers/syno/synobios/armada/ds215j.c create mode 100755 drivers/syno/synobios/armada/ds216se.c create mode 100755 drivers/syno/synobios/armada/ds414.c create mode 100644 drivers/syno/synobios/armada/ds414slim.c create mode 100755 drivers/syno/synobios/armada/fan-pwm.c create mode 100644 drivers/syno/synobios/armada/fan-resister.c create mode 100644 drivers/syno/synobios/armada/mv_level_button.c create mode 100755 drivers/syno/synobios/armada/rs214.c create mode 100755 drivers/syno/synobios/armada/rs814.c create mode 100755 drivers/syno/synobios/armada/rs815.c create mode 100644 drivers/syno/synobios/armada/thermal_ctrl.c create mode 100644 drivers/syno/synobios/armada/us3.c create mode 100644 drivers/syno/synobios/armada37xx/Makefile create mode 100755 drivers/syno/synobios/armada37xx/armada37xx_common.c create mode 100755 drivers/syno/synobios/armada37xx/armada37xx_common.h create mode 100755 drivers/syno/synobios/armada37xx/ds119j.c create mode 100755 drivers/syno/synobios/armada37xx/ds120j.c create mode 100755 drivers/syno/synobios/armada37xx/ds219j.c create mode 100755 drivers/syno/synobios/armada37xx/ds219se.c create mode 100755 drivers/syno/synobios/armada37xx/fan-pwm.c create mode 100644 drivers/syno/synobios/armada37xx/fan-resistor.c create mode 100644 drivers/syno/synobios/armada38x/Makefile create mode 100755 drivers/syno/synobios/armada38x/armada38x_common.c create mode 100755 drivers/syno/synobios/armada38x/armada38x_common.h create mode 100755 drivers/syno/synobios/armada38x/ds116.c create mode 100755 drivers/syno/synobios/armada38x/ds216.c create mode 100755 drivers/syno/synobios/armada38x/ds216j.c create mode 100755 drivers/syno/synobios/armada38x/ds218j.c create mode 100755 drivers/syno/synobios/armada38x/ds416j.c create mode 100755 drivers/syno/synobios/armada38x/ds416slim.c create mode 100755 drivers/syno/synobios/armada38x/ds419slim.c create mode 100755 drivers/syno/synobios/armada38x/fan-pwm.c create mode 100644 drivers/syno/synobios/armada38x/fan-resistor.c create mode 100755 drivers/syno/synobios/armada38x/rs217.c create mode 100755 drivers/syno/synobios/armada38x/rs816.c create mode 100644 drivers/syno/synobios/avoton/Makefile create mode 100755 drivers/syno/synobios/avoton/avoton_common.c create mode 100755 drivers/syno/synobios/avoton/avoton_common.h create mode 100644 drivers/syno/synobios/avoton/ds1515+.c create mode 100644 drivers/syno/synobios/avoton/ds1517+.c create mode 100644 drivers/syno/synobios/avoton/ds1616+.c create mode 100644 drivers/syno/synobios/avoton/ds1815+.c create mode 100644 drivers/syno/synobios/avoton/ds1817+.c create mode 100644 drivers/syno/synobios/avoton/ds2415+.c create mode 100644 drivers/syno/synobios/avoton/ds415+.c create mode 100644 drivers/syno/synobios/avoton/rs1219+.c create mode 100644 drivers/syno/synobios/avoton/rs2416+.c create mode 100644 drivers/syno/synobios/avoton/rs2416rp+.c create mode 100644 drivers/syno/synobios/avoton/rs815+.c create mode 100644 drivers/syno/synobios/avoton/rs815rp+.c create mode 100644 drivers/syno/synobios/avoton/rs818+.c create mode 100644 drivers/syno/synobios/avoton/rs818rp+.c create mode 100644 drivers/syno/synobios/braswell/Makefile create mode 100644 drivers/syno/synobios/braswell/braswell_common.c create mode 100644 drivers/syno/synobios/braswell/braswell_common.h create mode 100644 drivers/syno/synobios/braswell/ds216+.c create mode 100644 drivers/syno/synobios/braswell/ds216+II.c create mode 100644 drivers/syno/synobios/braswell/ds416play.c create mode 100644 drivers/syno/synobios/braswell/ds716+.c create mode 100644 drivers/syno/synobios/braswell/ds716+II.c create mode 100644 drivers/syno/synobios/braswell/ds916p.c create mode 100755 drivers/syno/synobios/broadwell/Makefile create mode 100755 drivers/syno/synobios/broadwell/broadwell_common.c create mode 100755 drivers/syno/synobios/broadwell/broadwell_common.h create mode 100644 drivers/syno/synobios/broadwell/ds3017xs.c create mode 100644 drivers/syno/synobios/broadwell/ds3617xs.c create mode 100644 drivers/syno/synobios/broadwell/ds3617xsII.c create mode 100755 drivers/syno/synobios/broadwell/ds3622xs+.c create mode 100644 drivers/syno/synobios/broadwell/fs2017.c create mode 100644 drivers/syno/synobios/broadwell/fs3400.c create mode 100644 drivers/syno/synobios/broadwell/rs18017xs+.c create mode 100644 drivers/syno/synobios/broadwell/rs3617rpxs.c create mode 100644 drivers/syno/synobios/broadwell/rs3617xs+.c create mode 100644 drivers/syno/synobios/broadwell/rs3618xs.c create mode 100644 drivers/syno/synobios/broadwell/rs4017xs+.c create mode 100644 drivers/syno/synobios/broadwell/rsd18016xs+.c create mode 100644 drivers/syno/synobios/broadwellnk/Makefile create mode 100755 drivers/syno/synobios/broadwellnk/broadwellnk_common.c create mode 100755 drivers/syno/synobios/broadwellnk/broadwellnk_common.h create mode 100644 drivers/syno/synobios/broadwellnk/ds1621xs+.c create mode 100644 drivers/syno/synobios/broadwellnk/ds3018xs.c create mode 100755 drivers/syno/synobios/broadwellnk/ds3622xs+.c create mode 100644 drivers/syno/synobios/broadwellnk/fs1018.c create mode 100644 drivers/syno/synobios/broadwellnk/fs3600.c create mode 100644 drivers/syno/synobios/broadwellnk/hd3400.c create mode 100644 drivers/syno/synobios/broadwellnk/rs1619xs+.c create mode 100644 drivers/syno/synobios/broadwellnk/rs3621rpxs.c create mode 100644 drivers/syno/synobios/broadwellnk/rs3621xs+.c create mode 100755 drivers/syno/synobios/broadwellnk/rs4021xs+.c create mode 100644 drivers/syno/synobios/broadwellnk/sa3400.c create mode 100644 drivers/syno/synobios/broadwellnk/sa3600.c create mode 100644 drivers/syno/synobios/broadwellnkv2/Makefile create mode 100755 drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.c create mode 100755 drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.h create mode 100644 drivers/syno/synobios/broadwellnkv2/fs3410.c create mode 100644 drivers/syno/synobios/broadwellnkv2/rs4022xs+.c create mode 100644 drivers/syno/synobios/broadwellnkv2/sa3410.c create mode 100644 drivers/syno/synobios/broadwellnkv2/sa3610.c create mode 100644 drivers/syno/synobios/broadwellntb/Makefile create mode 100644 drivers/syno/synobios/broadwellntb/broadwellntb_common.c create mode 100644 drivers/syno/synobios/broadwellntb/broadwellntb_common.h create mode 100644 drivers/syno/synobios/broadwellntb/taipei.c create mode 100644 drivers/syno/synobios/broadwellntbap/Makefile create mode 100644 drivers/syno/synobios/broadwellntbap/broadwellntbap_common.c create mode 100644 drivers/syno/synobios/broadwellntbap/broadwellntbap_common.h create mode 100644 drivers/syno/synobios/broadwellntbap/sa3200d.c create mode 100755 drivers/syno/synobios/broadwellntbap/sa3400d.c create mode 100644 drivers/syno/synobios/bromolow/Makefile create mode 100755 drivers/syno/synobios/bromolow/bromolow_common.c create mode 100755 drivers/syno/synobios/bromolow/bromolow_common.h create mode 100644 drivers/syno/synobios/bromolow/ds2414xs.c create mode 100644 drivers/syno/synobios/bromolow/ds3611xs.c create mode 100644 drivers/syno/synobios/bromolow/ds3612xs.c create mode 100644 drivers/syno/synobios/bromolow/ds3615xs.c create mode 100644 drivers/syno/synobios/bromolow/es3614xs+.c create mode 100644 drivers/syno/synobios/bromolow/rc18015xs+.c create mode 100644 drivers/syno/synobios/bromolow/rs10613xs+.c create mode 100644 drivers/syno/synobios/bromolow/rs18016xs+.c create mode 100644 drivers/syno/synobios/bromolow/rs3411rpxs.c create mode 100644 drivers/syno/synobios/bromolow/rs3411xs.c create mode 100644 drivers/syno/synobios/bromolow/rs3412rpxs.c create mode 100644 drivers/syno/synobios/bromolow/rs3412xs.c create mode 100644 drivers/syno/synobios/bromolow/rs3413xs+.c create mode 100644 drivers/syno/synobios/bromolow/rs3415xs+.c create mode 100644 drivers/syno/synobios/bromolow/rs3614rpxs.c create mode 100644 drivers/syno/synobios/bromolow/rs3614xs+.c create mode 100644 drivers/syno/synobios/bromolow/rs3614xs.c create mode 100644 drivers/syno/synobios/bromolow/rs3617xs.c create mode 100644 drivers/syno/synobios/cedarview/Makefile create mode 100755 drivers/syno/synobios/cedarview/cedarview_common.c create mode 100755 drivers/syno/synobios/cedarview/cedarview_common.h create mode 100644 drivers/syno/synobios/cedarview/ds1512+.c create mode 100644 drivers/syno/synobios/cedarview/ds1513+.c create mode 100644 drivers/syno/synobios/cedarview/ds1812+.c create mode 100644 drivers/syno/synobios/cedarview/ds1813+.c create mode 100644 drivers/syno/synobios/cedarview/ds2413+.c create mode 100644 drivers/syno/synobios/cedarview/ds412+.c create mode 100644 drivers/syno/synobios/cedarview/ds713+.c create mode 100644 drivers/syno/synobios/cedarview/rs2212+.c create mode 100644 drivers/syno/synobios/cedarview/rs2212rp+.c create mode 100644 drivers/syno/synobios/cedarview/rs2414+.c create mode 100644 drivers/syno/synobios/cedarview/rs2414rp+.c create mode 100644 drivers/syno/synobios/cedarview/rs812+.c create mode 100644 drivers/syno/synobios/cedarview/rs812rp+.c create mode 100644 drivers/syno/synobios/cedarview/rs814+.c create mode 100644 drivers/syno/synobios/cedarview/rs814rp+.c create mode 100644 drivers/syno/synobios/coffeelake/Makefile create mode 100644 drivers/syno/synobios/coffeelake/coffeelake_common.c create mode 100644 drivers/syno/synobios/coffeelake/coffeelake_common.h create mode 100644 drivers/syno/synobios/coffeelake/ds3619xs.c create mode 100644 drivers/syno/synobios/comcerto2k/Makefile create mode 100755 drivers/syno/synobios/comcerto2k/comcerto2k_common.c create mode 100755 drivers/syno/synobios/comcerto2k/comcerto2k_common.h create mode 100755 drivers/syno/synobios/comcerto2k/ds414j.c create mode 100755 drivers/syno/synobios/comcerto2k/ds415j.c create mode 100755 drivers/syno/synobios/comcerto2k/fan-pwm.c create mode 100644 drivers/syno/synobios/comcerto2k/fan-resister.c create mode 100644 drivers/syno/synobios/common/common.c create mode 100644 drivers/syno/synobios/common/common.h create mode 100644 drivers/syno/synobios/denverton/Makefile create mode 100755 drivers/syno/synobios/denverton/denverton_common.c create mode 100755 drivers/syno/synobios/denverton/denverton_common.h create mode 100644 drivers/syno/synobios/denverton/ds1618+.c create mode 100644 drivers/syno/synobios/denverton/ds1819+.c create mode 100644 drivers/syno/synobios/denverton/ds2419+.c create mode 100644 drivers/syno/synobios/denverton/ds2419+II.c create mode 100644 drivers/syno/synobios/denverton/dva3219.c create mode 100644 drivers/syno/synobios/denverton/dva3221.c create mode 100644 drivers/syno/synobios/denverton/rs1220+.c create mode 100644 drivers/syno/synobios/denverton/rs1220rp+.c create mode 100644 drivers/syno/synobios/denverton/rs2418+.c create mode 100644 drivers/syno/synobios/denverton/rs2418rp+.c create mode 100644 drivers/syno/synobios/denverton/rs2818rp+.c create mode 100644 drivers/syno/synobios/denverton/rs820+.c create mode 100644 drivers/syno/synobios/denverton/rs820rp+.c create mode 100644 drivers/syno/synobios/epyc7002/Makefile create mode 100755 drivers/syno/synobios/epyc7002/epyc7002_common.c create mode 100755 drivers/syno/synobios/epyc7002/epyc7002_common.h create mode 100644 drivers/syno/synobios/epyc7002/fs6400n.c create mode 100644 drivers/syno/synobios/epyc7002/fs6410.c create mode 100644 drivers/syno/synobios/epyc7002/sa6200.c create mode 100644 drivers/syno/synobios/epyc7002/sa6400.c create mode 100644 drivers/syno/synobios/epyc7002/sc6200.c create mode 100644 drivers/syno/synobios/epyc7002sofs/Makefile create mode 100755 drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.c create mode 100755 drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.h create mode 100644 drivers/syno/synobios/epyc7002sofs/fs6400n.c create mode 100644 drivers/syno/synobios/epyc7002sofs/fs6410.c create mode 100644 drivers/syno/synobios/epyc7002sofs/sa6200.c create mode 100644 drivers/syno/synobios/epyc7002sofs/sa6400.c create mode 100644 drivers/syno/synobios/epyc7002sofs/sc6200.c create mode 100644 drivers/syno/synobios/epyc7003ntb/Makefile create mode 100755 drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.c create mode 100755 drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.h create mode 100644 drivers/syno/synobios/epyc7003ntb/fs6600dn.c create mode 100644 drivers/syno/synobios/evansport/Makefile create mode 100644 drivers/syno/synobios/evansport/ds114+.c create mode 100644 drivers/syno/synobios/evansport/ds214play.c create mode 100644 drivers/syno/synobios/evansport/ds415play.c create mode 100755 drivers/syno/synobios/evansport/evansport_common.c create mode 100755 drivers/syno/synobios/evansport/evansport_common.h create mode 100644 drivers/syno/synobios/geminilake/Makefile create mode 100644 drivers/syno/synobios/geminilake/ds1520p.c create mode 100644 drivers/syno/synobios/geminilake/ds220p.c create mode 100644 drivers/syno/synobios/geminilake/ds224p.c create mode 100644 drivers/syno/synobios/geminilake/ds420p.c create mode 100644 drivers/syno/synobios/geminilake/ds423p.c create mode 100644 drivers/syno/synobios/geminilake/ds720p.c create mode 100644 drivers/syno/synobios/geminilake/ds920p.c create mode 100644 drivers/syno/synobios/geminilake/dva1622.c create mode 100755 drivers/syno/synobios/geminilake/geminilake_common.c create mode 100755 drivers/syno/synobios/geminilake/geminilake_common.h create mode 100644 drivers/syno/synobios/geminilakevs/Makefile create mode 100755 drivers/syno/synobios/geminilakevs/geminilakevs_common.c create mode 100755 drivers/syno/synobios/geminilakevs/geminilakevs_common.h create mode 100644 drivers/syno/synobios/geminilakevs/vs750hd.c create mode 100644 drivers/syno/synobios/grantley/Makefile create mode 100644 drivers/syno/synobios/grantley/fs3017.c create mode 100755 drivers/syno/synobios/grantley/grantley_common.c create mode 100755 drivers/syno/synobios/grantley/grantley_common.h create mode 100644 drivers/syno/synobios/grantley/rs18016dxs+.c create mode 100644 drivers/syno/synobios/i2c/i2c-linux.c create mode 100644 drivers/syno/synobios/i2c/i2c-linux.h create mode 100644 drivers/syno/synobios/i2c/i2c-mv.c create mode 100644 drivers/syno/synobios/i2c/i2c-mv.h create mode 100644 drivers/syno/synobios/i2c/i2c-plx.c create mode 100644 drivers/syno/synobios/i2c/i2c-plx.h create mode 100644 drivers/syno/synobios/i2c/i2c-ppc.c create mode 100644 drivers/syno/synobios/i2c/i2c-ppc.h create mode 100644 drivers/syno/synobios/icelaked/Makefile create mode 100755 drivers/syno/synobios/icelaked/icelaked_common.c create mode 100755 drivers/syno/synobios/icelaked/icelaked_common.h create mode 100755 drivers/syno/synobios/icelaked/rs4023xs+.c create mode 100644 drivers/syno/synobios/include/syno_shutdown_hook.h create mode 100755 drivers/syno/synobios/include/syno_ttyS.h create mode 100755 drivers/syno/synobios/include/synobios.h create mode 100644 drivers/syno/synobios/kvmcloud/Makefile create mode 100644 drivers/syno/synobios/kvmcloud/alidsm.c create mode 100755 drivers/syno/synobios/kvmcloud/kvmcloud_common.c create mode 100755 drivers/syno/synobios/kvmcloud/kvmcloud_common.h create mode 100644 drivers/syno/synobios/kvmx64/Makefile create mode 100644 drivers/syno/synobios/kvmx64/c2dsm.c create mode 100755 drivers/syno/synobios/kvmx64/kvmx64_common.c create mode 100755 drivers/syno/synobios/kvmx64/kvmx64_common.h create mode 100644 drivers/syno/synobios/kvmx64/virtualdsm.c create mode 100644 drivers/syno/synobios/kvmx64sofs/Makefile create mode 100755 drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.c create mode 100755 drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.h create mode 100644 drivers/syno/synobios/kvmx64sofs/virtualdsm.c create mode 100644 drivers/syno/synobios/kvmx64v2/Makefile create mode 100755 drivers/syno/synobios/kvmx64v2/kvmx64v2_common.c create mode 100755 drivers/syno/synobios/kvmx64v2/kvmx64v2_common.h create mode 100644 drivers/syno/synobios/kvmx64v2/virtualdsm.c create mode 100755 drivers/syno/synobios/led/led_1475.c create mode 100644 drivers/syno/synobios/led/led_1475.h create mode 100755 drivers/syno/synobios/led/led_9170.c create mode 100644 drivers/syno/synobios/led/led_9170.h create mode 100755 drivers/syno/synobios/led/led_9235.c create mode 100644 drivers/syno/synobios/led/led_9235.h create mode 100644 drivers/syno/synobios/led/led_asm116x.c create mode 100644 drivers/syno/synobios/led/led_asm116x.h create mode 100644 drivers/syno/synobios/led/led_common.h create mode 100644 drivers/syno/synobios/led/led_gpio.c create mode 100644 drivers/syno/synobios/led/led_gpio.h create mode 100644 drivers/syno/synobios/led/led_jmb585.c create mode 100644 drivers/syno/synobios/led/led_jmb585.h create mode 100755 drivers/syno/synobios/led/led_trigger.c create mode 100644 drivers/syno/synobios/led/led_trigger.h create mode 100755 drivers/syno/synobios/led/led_trigger_disk.c create mode 100644 drivers/syno/synobios/led/led_trigger_disk.h create mode 100755 drivers/syno/synobios/mapping.c create mode 100755 drivers/syno/synobios/mapping.h create mode 100644 drivers/syno/synobios/mesh/mesh.c create mode 100644 drivers/syno/synobios/mesh/mesh.h create mode 100644 drivers/syno/synobios/monaco/Makefile create mode 100755 drivers/syno/synobios/monaco/ds216play.c create mode 100755 drivers/syno/synobios/monaco/fan-pwm.c create mode 100644 drivers/syno/synobios/monaco/fan-resistor.c create mode 100755 drivers/syno/synobios/monaco/monaco_common.c create mode 100755 drivers/syno/synobios/monaco/monaco_common.h create mode 100644 drivers/syno/synobios/nextkvmx64/Makefile create mode 100755 drivers/syno/synobios/nextkvmx64/nextkvmx64_common.c create mode 100755 drivers/syno/synobios/nextkvmx64/nextkvmx64_common.h create mode 100644 drivers/syno/synobios/nextkvmx64/nextvirtualdsm.c create mode 100644 drivers/syno/synobios/pmbus/pmbus.c create mode 100644 drivers/syno/synobios/pmbus/pmbus.h create mode 100644 drivers/syno/synobios/purley/Makefile create mode 100644 drivers/syno/synobios/purley/fs6400.c create mode 100755 drivers/syno/synobios/purley/fs6500.c create mode 100644 drivers/syno/synobios/purley/fs6600n.c create mode 100755 drivers/syno/synobios/purley/hd6500.c create mode 100755 drivers/syno/synobios/purley/purley_common.c create mode 100644 drivers/syno/synobios/purley/purley_common.h create mode 100644 drivers/syno/synobios/purley/sa6500.c create mode 100644 drivers/syno/synobios/r1000/Makefile create mode 100644 drivers/syno/synobios/r1000/ds1522p.c create mode 100644 drivers/syno/synobios/r1000/ds723p.c create mode 100644 drivers/syno/synobios/r1000/ds923p.c create mode 100755 drivers/syno/synobios/r1000/r1000_common.c create mode 100755 drivers/syno/synobios/r1000/r1000_common.h create mode 100644 drivers/syno/synobios/r1000/rs422p.c create mode 100644 drivers/syno/synobios/rtc/alarmtime.c create mode 100644 drivers/syno/synobios/rtc/localtime.c create mode 100644 drivers/syno/synobios/rtc/localtime.h create mode 100644 drivers/syno/synobios/rtc/rtc-linux-pericom.c create mode 100644 drivers/syno/synobios/rtc/rtc-linux-ricoh.c create mode 100644 drivers/syno/synobios/rtc/rtc-linux-seiko.c create mode 100755 drivers/syno/synobios/rtc/rtc-mv-builtin.c create mode 100644 drivers/syno/synobios/rtc/rtc-mv-ricoh.c create mode 100644 drivers/syno/synobios/rtc/rtc-mv-seiko.c create mode 100755 drivers/syno/synobios/rtc/rtc-mvebu-builtin.c create mode 100644 drivers/syno/synobios/rtc/rtc-mvebu-builtin.h create mode 100644 drivers/syno/synobios/rtc/rtc-pericom-lib.c create mode 100644 drivers/syno/synobios/rtc/rtc-plx-ricoh.c create mode 100644 drivers/syno/synobios/rtc/rtc-plx-seiko.c create mode 100644 drivers/syno/synobios/rtc/rtc-ppc-ricoh.c create mode 100644 drivers/syno/synobios/rtc/rtc-ricoh-lib.c create mode 100755 drivers/syno/synobios/rtc/rtc-rtk-builtin.c create mode 100644 drivers/syno/synobios/rtc/rtc-rtk-builtin.h create mode 100644 drivers/syno/synobios/rtc/rtc-seiko-lib.c create mode 100755 drivers/syno/synobios/rtc/rtc-x86.c create mode 100644 drivers/syno/synobios/rtc/rtc.h create mode 100644 drivers/syno/synobios/rtd1296/Makefile create mode 100755 drivers/syno/synobios/rtd1296/ds118.c create mode 100755 drivers/syno/synobios/rtd1296/ds218.c create mode 100755 drivers/syno/synobios/rtd1296/ds218play.c create mode 100644 drivers/syno/synobios/rtd1296/ds220j.c create mode 100755 drivers/syno/synobios/rtd1296/ds418.c create mode 100755 drivers/syno/synobios/rtd1296/ds418j.c create mode 100644 drivers/syno/synobios/rtd1296/ds420j.c create mode 100755 drivers/syno/synobios/rtd1296/eds19.c create mode 100755 drivers/syno/synobios/rtd1296/fan-pwm.c create mode 100644 drivers/syno/synobios/rtd1296/fan-resistor.c create mode 100755 drivers/syno/synobios/rtd1296/rs819.c create mode 100644 drivers/syno/synobios/rtd1296/rtd1296_common.c create mode 100755 drivers/syno/synobios/rtd1296/rtd1296_common.h create mode 100644 drivers/syno/synobios/rtd1619/Makefile create mode 100644 drivers/syno/synobios/rtd1619/ds220.c create mode 100644 drivers/syno/synobios/rtd1619/ds220play.c create mode 100644 drivers/syno/synobios/rtd1619/fan-pwm.c create mode 100644 drivers/syno/synobios/rtd1619/fan-resistor.c create mode 100644 drivers/syno/synobios/rtd1619/rtd1619_common.c create mode 100755 drivers/syno/synobios/rtd1619/rtd1619_common.h create mode 100644 drivers/syno/synobios/rtd1619b/Makefile create mode 100644 drivers/syno/synobios/rtd1619b/ds124.c create mode 100644 drivers/syno/synobios/rtd1619b/ds223.c create mode 100644 drivers/syno/synobios/rtd1619b/ds223j.c create mode 100644 drivers/syno/synobios/rtd1619b/ds423.c create mode 100644 drivers/syno/synobios/rtd1619b/fan-pwm.c create mode 100644 drivers/syno/synobios/rtd1619b/fan-resistor.c create mode 100644 drivers/syno/synobios/rtd1619b/rtd1619b_common.c create mode 100755 drivers/syno/synobios/rtd1619b/rtd1619b_common.h create mode 100644 drivers/syno/synobios/ryzen5k/Makefile create mode 100755 drivers/syno/synobios/ryzen5k/rs4024xs+.c create mode 100755 drivers/syno/synobios/ryzen5k/ryzen5k_common.c create mode 100755 drivers/syno/synobios/ryzen5k/ryzen5k_common.h create mode 100644 drivers/syno/synobios/skylaked/Makefile create mode 100644 drivers/syno/synobios/skylaked/rs4021xsp.c create mode 100755 drivers/syno/synobios/skylaked/skylaked_common.c create mode 100755 drivers/syno/synobios/skylaked/skylaked_common.h create mode 100644 drivers/syno/synobios/switchtec/switchtec.c create mode 100644 drivers/syno/synobios/switchtec/switchtec.h create mode 100644 drivers/syno/synobios/syno_power_outage/syno_power_outage.c create mode 100644 drivers/syno/synobios/syno_power_outage/syno_power_outage.h create mode 100755 drivers/syno/synobios/syno_ttyS/syno_ttyS.c create mode 100755 drivers/syno/synobios/syno_ttyS/syno_ttyS_srm.c create mode 100755 drivers/syno/synobios/synobios.c create mode 100644 drivers/syno/synobios/v1000/Makefile create mode 100644 drivers/syno/synobios/v1000/ds1621p.c create mode 100644 drivers/syno/synobios/v1000/ds1623p.c create mode 100644 drivers/syno/synobios/v1000/ds1821p.c create mode 100644 drivers/syno/synobios/v1000/ds1823p.c create mode 100644 drivers/syno/synobios/v1000/ds1823xsp.c create mode 100644 drivers/syno/synobios/v1000/ds2422p.c create mode 100644 drivers/syno/synobios/v1000/fs2500.c create mode 100644 drivers/syno/synobios/v1000/fs2500t.c create mode 100644 drivers/syno/synobios/v1000/rs1221p.c create mode 100644 drivers/syno/synobios/v1000/rs1221rp+.c create mode 100644 drivers/syno/synobios/v1000/rs1623xsp.c create mode 100644 drivers/syno/synobios/v1000/rs2421p.c create mode 100644 drivers/syno/synobios/v1000/rs2421rpp.c create mode 100644 drivers/syno/synobios/v1000/rs2423p.c create mode 100644 drivers/syno/synobios/v1000/rs2423rpp.c create mode 100644 drivers/syno/synobios/v1000/rs2821rpp.c create mode 100644 drivers/syno/synobios/v1000/rs822p.c create mode 100644 drivers/syno/synobios/v1000/rs822rpp.c create mode 100644 drivers/syno/synobios/v1000/sc2500.c create mode 100755 drivers/syno/synobios/v1000/v1000_common.c create mode 100755 drivers/syno/synobios/v1000/v1000_common.h create mode 100644 drivers/syno/synobios/v1000sofs/Makefile create mode 100644 drivers/syno/synobios/v1000sofs/ds1621p.c create mode 100644 drivers/syno/synobios/v1000sofs/ds1821p.c create mode 100755 drivers/syno/synobios/v1000sofs/v1000sofs_common.c create mode 100755 drivers/syno/synobios/v1000sofs/v1000sofs_common.h create mode 100644 drivers/tee/tee_client_api.h create mode 100644 drivers/tee/tee_mem_api.c create mode 100644 drivers/thermal/realtek/Kconfig create mode 100644 drivers/thermal/realtek/Makefile create mode 100644 drivers/thermal/realtek/cpu_core_cooling.c create mode 100644 drivers/thermal/realtek/sensor-rtd119x.c create mode 100644 drivers/thermal/realtek/sensor-rtd129x.c create mode 100644 drivers/thermal/realtek/sensor-rtd161x.c create mode 100644 drivers/thermal/realtek/sensor.c create mode 100644 drivers/thermal/realtek/sensor.h create mode 100644 drivers/usb/dwc3/dwc3-rtk-debugfs.c create mode 100644 drivers/usb/dwc3/dwc3-rtk-drd.c create mode 100644 drivers/usb/dwc3/dwc3-rtk-drd.h create mode 100644 drivers/usb/dwc3/dwc3-rtk-type_c.c create mode 100644 drivers/usb/dwc3/dwc3-rtk.c create mode 100644 drivers/usb/dwc3/dwc3-rtk.h create mode 100644 drivers/usb/dwc3/rtk-rts5400.c create mode 100644 drivers/usb/dwc3/trace-rtk.c create mode 100644 drivers/usb/gadget/function/f_mtp.c create mode 100644 drivers/usb/gadget/function/f_mtp.h create mode 100644 drivers/usb/gadget/function/f_ptp.c create mode 100644 drivers/usb/gadget/udc/rtk-hsotg.c create mode 100644 drivers/usb/gadget/udc/rtk-hsotg.h create mode 100644 drivers/usb/host/ehci-rtk.c create mode 100644 drivers/usb/host/ohci-rtk.c create mode 100644 drivers/usb/phy/phy-rtk-rle0599.c create mode 100644 drivers/usb/phy/phy-rtk-usb.h create mode 100644 drivers/usb/phy/phy-rtk-usb2.c create mode 100644 drivers/usb/phy/phy-rtk-usb3.c create mode 100644 drivers/watchdog/pretimeout_dump.c create mode 100644 drivers/watchdog/rtk_wdt.c create mode 100644 fs/aufs/Kconfig create mode 100644 fs/aufs/Makefile create mode 100644 fs/aufs/aufs.h create mode 100644 fs/aufs/branch.c create mode 100644 fs/aufs/branch.h create mode 100644 fs/aufs/conf.mk create mode 100644 fs/aufs/cpup.c create mode 100644 fs/aufs/cpup.h create mode 100644 fs/aufs/dbgaufs.c create mode 100644 fs/aufs/dbgaufs.h create mode 100644 fs/aufs/dcsub.c create mode 100644 fs/aufs/dcsub.h create mode 100644 fs/aufs/debug.c create mode 100644 fs/aufs/debug.h create mode 100644 fs/aufs/dentry.c create mode 100644 fs/aufs/dentry.h create mode 100644 fs/aufs/dinfo.c create mode 100644 fs/aufs/dir.c create mode 100644 fs/aufs/dir.h create mode 100644 fs/aufs/dirren.c create mode 100644 fs/aufs/dirren.h create mode 100644 fs/aufs/dynop.c create mode 100644 fs/aufs/dynop.h create mode 100644 fs/aufs/export.c create mode 100644 fs/aufs/f_op.c create mode 100644 fs/aufs/fhsm.c create mode 100644 fs/aufs/file.c create mode 100644 fs/aufs/file.h create mode 100644 fs/aufs/finfo.c create mode 100644 fs/aufs/fstype.h create mode 100644 fs/aufs/hbl.h create mode 100644 fs/aufs/hfsnotify.c create mode 100644 fs/aufs/hfsplus.c create mode 100644 fs/aufs/hnotify.c create mode 100644 fs/aufs/i_op.c create mode 100644 fs/aufs/i_op_add.c create mode 100644 fs/aufs/i_op_del.c create mode 100644 fs/aufs/i_op_ren.c create mode 100644 fs/aufs/iinfo.c create mode 100644 fs/aufs/inode.c create mode 100644 fs/aufs/inode.h create mode 100644 fs/aufs/ioctl.c create mode 100644 fs/aufs/lcnt.h create mode 100644 fs/aufs/loop.c create mode 100644 fs/aufs/loop.h create mode 100644 fs/aufs/magic.mk create mode 100644 fs/aufs/module.c create mode 100644 fs/aufs/module.h create mode 100644 fs/aufs/mvdown.c create mode 100644 fs/aufs/opts.c create mode 100644 fs/aufs/opts.h create mode 100644 fs/aufs/plink.c create mode 100644 fs/aufs/poll.c create mode 100644 fs/aufs/posix_acl.c create mode 100644 fs/aufs/procfs.c create mode 100644 fs/aufs/rdu.c create mode 100644 fs/aufs/rwsem.h create mode 100644 fs/aufs/sbinfo.c create mode 100644 fs/aufs/super.c create mode 100644 fs/aufs/super.h create mode 100644 fs/aufs/sysaufs.c create mode 100644 fs/aufs/sysaufs.h create mode 100644 fs/aufs/sysfs.c create mode 100644 fs/aufs/sysrq.c create mode 100644 fs/aufs/vdir.c create mode 100644 fs/aufs/vfsub.c create mode 100644 fs/aufs/vfsub.h create mode 100644 fs/aufs/wbr_policy.c create mode 100644 fs/aufs/whout.c create mode 100644 fs/aufs/whout.h create mode 100644 fs/aufs/wkq.c create mode 100644 fs/aufs/wkq.h create mode 100644 fs/aufs/xattr.c create mode 100644 fs/aufs/xino.c create mode 100644 fs/btrfs/free-space-analyze.c create mode 100644 fs/btrfs/snapshot-size-query.c create mode 100644 fs/btrfs/syno-extent-usage.c create mode 100644 fs/btrfs/syno-feat-tree.c create mode 100644 fs/btrfs/syno-feat-tree.h create mode 100644 fs/btrfs/syno-locker.c create mode 100644 fs/btrfs/syno-rbd-meta.c create mode 100644 fs/btrfs/syno-rbd-meta.h create mode 100644 fs/btrfs/syno_acl.c create mode 100644 fs/btrfs/syno_acl.h create mode 100644 fs/btrfs/usrquota.c create mode 100644 fs/ceph/syno_acl.c create mode 100644 fs/ceph/syno_acl.h create mode 100644 fs/cifs/synoops.c create mode 100644 fs/ecryptfs/export.c create mode 100644 fs/exfat/LICENSE create mode 100644 fs/exfat/README.md create mode 100644 fs/exfat/SynoBuildConf/build create mode 100644 fs/exfat/SynoBuildConf/depends create mode 100644 fs/exfat/SynoBuildConf/install create mode 100644 fs/exfat/SynoBuildConf/shellcheck create mode 100644 fs/exfat/SynoBuildConf/version create mode 100644 fs/exfat/compat.h create mode 100644 fs/exfat/config.h create mode 100644 fs/exfat/version.h create mode 100644 fs/exfat/xattr.c create mode 100644 fs/ext4/syno_acl.c create mode 100644 fs/ext4/syno_acl.h create mode 100644 fs/nfsd/syno_io_stat.c create mode 100644 fs/nfsd/syno_io_stat.h create mode 100644 fs/notify/synotify/Makefile create mode 100644 fs/notify/synotify/synotify.c create mode 100644 fs/notify/synotify/synotify.h create mode 100644 fs/notify/synotify/synotify_user.c create mode 100644 fs/syno_acl.c create mode 100644 fs/syno_acl.h create mode 100644 fs/syno_acl_api.c create mode 100644 include/dt-bindings/clock/rtd1195-clk.h create mode 100644 include/dt-bindings/clock/rtd1295-clk.h create mode 100644 include/dt-bindings/clock/rtd1319-clk.h create mode 100644 include/dt-bindings/clock/rtd1395-clk.h create mode 100644 include/dt-bindings/clock/rtd1619-clk.h create mode 100644 include/dt-bindings/clock/rtd1619b-clk.h create mode 100644 include/dt-bindings/power/rtd1295-power.h create mode 100644 include/dt-bindings/power/rtd1395-power.h create mode 100644 include/dt-bindings/power/rtd1619-power.h create mode 100644 include/dt-bindings/power/rtd1619b-power.h create mode 100644 include/dt-bindings/regulator/anpec,apw888x.h create mode 100644 include/dt-bindings/reset/rtd1195-reset.h create mode 100644 include/dt-bindings/reset/rtd1295-reset.h create mode 100644 include/dt-bindings/reset/rtd1319-reset.h create mode 100644 include/dt-bindings/reset/rtd1395-reset.h create mode 100644 include/dt-bindings/reset/rtd1619-reset.h create mode 100644 include/dt-bindings/reset/rtd1619b-reset.h create mode 100644 include/dt-bindings/soc/realtek,mem-flag.h create mode 100644 include/dt-bindings/soc/realtek,pm.h create mode 100644 include/linux/leds-atmega1608-seg7.h create mode 100644 include/linux/leds-atmega1608.h create mode 100644 include/linux/leds-lp3943.h create mode 100644 include/linux/mfd/apw8886.h create mode 100644 include/linux/mfd/apw8889.h create mode 100644 include/linux/mfd/apw888x.h create mode 100644 include/linux/raid/libmd-report.h create mode 100644 include/linux/soc/realtek/rtk_pd.h create mode 100644 include/linux/syno_acl.h create mode 100644 include/linux/syno_acl_xattr.h create mode 100644 include/linux/syno_fdt.h create mode 100644 include/linux/syno_fs.h create mode 100644 include/linux/syno_gpio.h create mode 100644 include/linux/synobios.h create mode 100644 include/linux/synolib.h create mode 100644 include/linux/synosata.h create mode 100644 include/linux/synotify.h create mode 100644 include/linux/usb/f_mtp.h create mode 100644 include/linux/usb/syno_quirks.h create mode 100644 include/soc/realtek/avcpu.h create mode 100644 include/soc/realtek/kernel-rpc.h create mode 100644 include/soc/realtek/memory.h create mode 100644 include/soc/realtek/rtk-usb-manager.h create mode 100644 include/soc/realtek/rtk_cec.h create mode 100644 include/soc/realtek/rtk_chip.h create mode 100644 include/soc/realtek/rtk_cpuhp.h create mode 100644 include/soc/realtek/rtk_i2c.h create mode 100644 include/soc/realtek/rtk_ipc_shm.h create mode 100644 include/soc/realtek/rtk_ir.h create mode 100644 include/soc/realtek/rtk_iso.h create mode 100644 include/soc/realtek/rtk_misc.h create mode 100644 include/soc/realtek/rtk_pcie.h create mode 100644 include/soc/realtek/rtk_pm.h create mode 100644 include/soc/realtek/rtk_refclk.h create mode 100644 include/soc/realtek/rtk_rstctl.h create mode 100644 include/soc/realtek/rtk_sb2_dbg.h create mode 100644 include/soc/realtek/rtk_sb2_sem.h create mode 100644 include/soc/realtek/rtk_sha1.h create mode 100644 include/soc/realtek/uapi/ashmem.h create mode 100644 include/soc/realtek/uapi/ion.h create mode 100644 include/soc/realtek/uapi/ion_rtk.h create mode 100644 include/soc/realtek/uapi/vsoc_shm.h create mode 100644 include/trace/events/rtk_pm.h create mode 100644 include/trace/events/rtk_rpc.h create mode 100644 include/trace/events/syno.h create mode 100644 include/uapi/linux/aufs_type.h create mode 100644 include/uapi/linux/syno.h create mode 100644 include/uapi/linux/syno_acl.h create mode 100644 include/uapi/linux/syno_acl_xattr_ds.h create mode 100644 include/uapi/linux/synobios.h create mode 100644 include/uapi/linux/synotify.h create mode 100644 include/uapi/linux/usb/f_mtp.h create mode 100644 kernel/syno-module-internal.h create mode 100644 kernel/syno_bootargs.c create mode 100644 kernel/workstat.c create mode 100644 lib/synolib/Makefile create mode 100644 lib/synolib/asm116xfwdl/116xfwdl.c create mode 100644 lib/synolib/asm116xfwdl/Makefile create mode 100644 lib/synolib/asm116xfwdl/asm116.h create mode 100644 lib/synolib/asm116xfwdl/crc.c create mode 100644 lib/synolib/asm116xfwdl/crc.h create mode 100644 lib/synolib/asm116xfwdl/precomp.h create mode 100644 lib/synolib/asm116xfwdl/spictrl.c create mode 100644 lib/synolib/asm116xfwdl/spictrl.h create mode 100644 lib/synolib/asm116xfwdl/spifile.h create mode 100644 lib/synolib/asm116xfwdl/spiflash.c create mode 100644 lib/synolib/asm116xfwdl/spiflash.h create mode 100644 lib/synolib/syno_ahci_reg_read_test.c create mode 100644 lib/synolib/syno_check_on_opt_pci.c create mode 100644 lib/synolib/syno_disk_pwr_ctrl.c create mode 100644 lib/synolib/syno_disk_ready_check.c create mode 100644 lib/synolib/syno_disk_wait_for_spindown.c create mode 100644 lib/synolib/syno_draw_auto_remap_buffer.c create mode 100644 lib/synolib/syno_fdt.c create mode 100644 lib/synolib/syno_hddpwrctl_test.c create mode 100644 lib/synolib/syno_jmb585_update_spi.c create mode 100644 lib/synolib/syno_kexec_test.c create mode 100644 lib/synolib/syno_pciepath_dts_pattern.c create mode 100644 lib/synolib/syno_plugin.c create mode 100644 lib/synolib/syno_sata_signal_check.c create mode 100644 lib/synolib/syno_sata_signal_test.c create mode 100644 lib/synolib/syno_uart2spi_logout.c create mode 100644 mm/prfile.c create mode 100755 scripts/pahole-flags.sh create mode 100644 synology/certs/.gitignore create mode 100644 synology/synoconfigs-spec/CONFIG_CRYPTO.rb create mode 100644 synology/synoconfigs-spec/CONFIG_DEBUG_OPTIONS.rb create mode 100644 synology/synoconfigs-spec/CONFIG_GENERAL_SETUP_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_KERNEL_LZMA.rb create mode 100644 synology/synoconfigs-spec/CONFIG_NUMA.rb create mode 100644 synology/synoconfigs-spec/CONFIG_PCIEASPM.rb create mode 100644 synology/synoconfigs-spec/CONFIG_QUOTA_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SWIOTLB.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_AUFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_BASIC_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_BTRFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_CIFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_CONFIGFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_ECRYPTFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_EXT4_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_FAT_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_FEATURES.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_FS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_FUSE_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_HFSPLUS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_IOMMU_PASSTHROUGH.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_MD_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_MODULE_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_NFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_OVERLAYFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_TMPFS_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_UDF_#.rb create mode 100644 synology/synoconfigs-spec/CONFIG_SYNO_USB_#.rb create mode 100644 synology/synoconfigs-spec/Rakefile create mode 100644 synology/synoconfigs-spec/lib/ansi/chart.rb create mode 100644 synology/synoconfigs-spec/lib/ansi/code.rb create mode 100644 synology/synoconfigs-spec/lib/ansi/constants.rb create mode 100644 synology/synoconfigs-spec/lib/inifile.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/extensible_backtrace_filter.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/hooks.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/hooks/default.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/hooks/test.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/minitest_reporter_plugin.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/relative_position.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/reporters.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/reporters/ansi.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/reporters/base_reporter.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/reporters/default_reporter.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/reporters/spec_reporter.rb create mode 100644 synology/synoconfigs-spec/lib/minitest/reporters/version.rb create mode 100644 synology/synoconfigs-spec/lib/platform.rb create mode 100644 synology/synoconfigs-spec/lib/platform_helper.rb create mode 100644 synology/synoconfigs-spec/lib/syno_kconfig.rb create mode 100644 synology/synoconfigs/Kconfig create mode 100644 synology/synoconfigs/Kconfig.basic create mode 100644 synology/synoconfigs/Kconfig.devices create mode 100644 synology/synoconfigs/Kconfig.fs create mode 100644 synology/synoconfigs/Kconfig.misc create mode 100644 synology/synoconfigs/Kconfig.network create mode 100644 synology/synoconfigs/Kconfig.platform create mode 100644 synology/synoconfigs/back-porting-records create mode 100644 synology/synoconfigs/epyc7002 create mode 100644 synology/synoconfigs/epyc7002sofs create mode 100644 synology/synoconfigs/epyc7003ntb create mode 100644 synology/synoconfigs/fst-ci-config create mode 100644 synology/synoconfigs/fst-locker-config create mode 100644 synology/synoconfigs/geminilakelk5 create mode 100644 synology/synoconfigs/icelaked create mode 100644 synology/synoconfigs/kvmx64lk5 create mode 100644 synology/synoconfigs/kvmx64sofs create mode 100644 synology/synoconfigs/kvmx64v2 create mode 100644 synology/synoconfigs/purleylk5 create mode 100644 synology/synoconfigs/rtd1619b create mode 100644 synology/synoconfigs/rtd1619bmango create mode 100644 synology/synoconfigs/ryzen5k create mode 120000 synology/synoconfigs/soit-ci-config create mode 100644 synology/synoconfigs/v1000lk5 create mode 100644 synology/synoconfigs/v1000sofs create mode 100644 synology/systemd/syno-fan-modules-load.service create mode 100644 synology/systemd/syno-fan-modules-load.sh create mode 100644 synology/systemd/syno-kernel-modules-load.service create mode 100644 synology/systemd/syno-kernel-modules-load.sh diff --git a/.clang-format b/.clang-format index 10dc5a9a61b3..9b87ea1fc16e 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # -# clang-format configuration file. Intended for clang-format >= 4. +# clang-format configuration file. Intended for clang-format >= 11. # # For more information, see: # @@ -13,7 +13,7 @@ AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false -#AlignEscapedNewlines: Left # Unknown to clang-format-4.0 +AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false @@ -37,24 +37,24 @@ BraceWrapping: AfterObjCDeclaration: false AfterStruct: false AfterUnion: false - #AfterExternBlock: false # Unknown to clang-format-5.0 + AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false - #SplitEmptyFunction: true # Unknown to clang-format-4.0 - #SplitEmptyRecord: true # Unknown to clang-format-4.0 - #SplitEmptyNamespace: true # Unknown to clang-format-4.0 + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom -#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 +BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false -#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 +BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' -#CompactNamespaces: false # Unknown to clang-format-4.0 +CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 @@ -62,39 +62,56 @@ Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false -#FixNamespaceComments: false # Unknown to clang-format-4.0 +FixNamespaceComments: false # Taken from: -# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ +# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ tools/ \ # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ -# | sort | uniq +# | LC_ALL=C sort -u ForEachMacros: + - '__ata_qc_for_each' + - '__bio_for_each_bvec' + - '__bio_for_each_segment' + - '__evlist__for_each_entry' + - '__evlist__for_each_entry_continue' + - '__evlist__for_each_entry_from' + - '__evlist__for_each_entry_reverse' + - '__evlist__for_each_entry_safe' + - '__for_each_mem_range' + - '__for_each_mem_range_rev' + - '__for_each_thread' + - '__hlist_for_each_rcu' + - '__map__for_each_symbol_by_name' + - '__perf_evlist__for_each_entry' + - '__perf_evlist__for_each_entry_reverse' + - '__perf_evlist__for_each_entry_safe' + - '__rq_for_each_bio' + - '__shost_for_each_device' - 'apei_estatus_for_each_section' - 'ata_for_each_dev' - 'ata_for_each_link' - - '__ata_qc_for_each' - 'ata_qc_for_each' - 'ata_qc_for_each_raw' - 'ata_qc_for_each_with_internal' - 'ax25_for_each' - 'ax25_uid_for_each' - - '__bio_for_each_bvec' - 'bio_for_each_bvec' - 'bio_for_each_bvec_all' + - 'bio_for_each_folio_all' - 'bio_for_each_integrity_vec' - - '__bio_for_each_segment' - 'bio_for_each_segment' - 'bio_for_each_segment_all' - 'bio_list_for_each' - 'bip_for_each_vec' - - 'bitmap_for_each_clear_region' - - 'bitmap_for_each_set_region' - - 'blkg_for_each_descendant_post' - - 'blkg_for_each_descendant_pre' - - 'blk_queue_for_each_rl' - 'bond_for_each_slave' - 'bond_for_each_slave_rcu' + - 'bpf__perf_for_each_map' + - 'bpf__perf_for_each_map_named' - 'bpf_for_each_spilled_reg' + - 'bpf_object__for_each_map' + - 'bpf_object__for_each_program' + - 'bpf_object__for_each_safe' + - 'bpf_perf_object__for_each' - 'btree_for_each_safe128' - 'btree_for_each_safe32' - 'btree_for_each_safe64' @@ -102,6 +119,7 @@ ForEachMacros: - 'card_for_each_dev' - 'cgroup_taskset_for_each' - 'cgroup_taskset_for_each_leader' + - 'cpufreq_for_each_efficient_entry_idx' - 'cpufreq_for_each_entry' - 'cpufreq_for_each_entry_idx' - 'cpufreq_for_each_valid_entry' @@ -109,8 +127,22 @@ ForEachMacros: - 'css_for_each_child' - 'css_for_each_descendant_post' - 'css_for_each_descendant_pre' + - 'damon_for_each_region' + - 'damon_for_each_region_safe' + - 'damon_for_each_scheme' + - 'damon_for_each_scheme_safe' + - 'damon_for_each_target' + - 'damon_for_each_target_safe' + - 'data__for_each_file' + - 'data__for_each_file_new' + - 'data__for_each_file_start' - 'device_for_each_child_node' + - 'displayid_iter_for_each' + - 'dma_fence_array_for_each' - 'dma_fence_chain_for_each' + - 'dma_fence_unwrap_for_each' + - 'dma_resv_for_each_fence' + - 'dma_resv_for_each_fence_unlocked' - 'do_for_each_ftrace_op' - 'drm_atomic_crtc_for_each_plane' - 'drm_atomic_crtc_state_for_each_plane' @@ -122,6 +154,7 @@ ForEachMacros: - 'drm_for_each_bridge_in_chain' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' + - 'drm_for_each_crtc_reverse' - 'drm_for_each_encoder' - 'drm_for_each_encoder_mask' - 'drm_for_each_fb' @@ -133,14 +166,37 @@ ForEachMacros: - 'drm_mm_for_each_node' - 'drm_mm_for_each_node_in_range' - 'drm_mm_for_each_node_safe' + - 'dsa_switch_for_each_available_port' + - 'dsa_switch_for_each_cpu_port' + - 'dsa_switch_for_each_port' + - 'dsa_switch_for_each_port_continue_reverse' + - 'dsa_switch_for_each_port_safe' + - 'dsa_switch_for_each_user_port' + - 'dsa_tree_for_each_user_port' + - 'dso__for_each_symbol' + - 'dsos__for_each_with_build_id' + - 'elf_hash_for_each_possible' + - 'elf_section__for_each_rel' + - 'elf_section__for_each_rela' + - 'elf_symtab__for_each_symbol' + - 'evlist__for_each_cpu' + - 'evlist__for_each_entry' + - 'evlist__for_each_entry_continue' + - 'evlist__for_each_entry_from' + - 'evlist__for_each_entry_reverse' + - 'evlist__for_each_entry_safe' - 'flow_action_for_each' + - 'for_each_acpi_dev_match' - 'for_each_active_dev_scope' - 'for_each_active_drhd_unit' - 'for_each_active_iommu' - 'for_each_aggr_pgid' - 'for_each_available_child_of_node' + - 'for_each_bench' - 'for_each_bio' - 'for_each_board_func_rsrc' + - 'for_each_btf_ext_rec' + - 'for_each_btf_ext_sec' - 'for_each_bvec' - 'for_each_card_auxs' - 'for_each_card_auxs_safe' @@ -156,20 +212,24 @@ ForEachMacros: - 'for_each_child_of_node' - 'for_each_clear_bit' - 'for_each_clear_bit_from' + - 'for_each_clear_bitrange' + - 'for_each_clear_bitrange_from' + - 'for_each_cmd' - 'for_each_cmsghdr' + - 'for_each_collection' + - 'for_each_comp_order' - 'for_each_compatible_node' - 'for_each_component_dais' - 'for_each_component_dais_safe' - - 'for_each_comp_order' - 'for_each_console' - 'for_each_cpu' - 'for_each_cpu_and' - 'for_each_cpu_not' - 'for_each_cpu_wrap' - 'for_each_dapm_widgets' + - 'for_each_dedup_cand' - 'for_each_dev_addr' - 'for_each_dev_scope' - - 'for_each_displayid_db' - 'for_each_dma_cap_mask' - 'for_each_dpcm_be' - 'for_each_dpcm_be_rollback' @@ -183,6 +243,8 @@ ForEachMacros: - 'for_each_element_extid' - 'for_each_element_id' - 'for_each_endpoint_of_node' + - 'for_each_event' + - 'for_each_event_tps' - 'for_each_evictable_lru' - 'for_each_fib6_node_rt_rcu' - 'for_each_fib6_walker_rt' @@ -191,31 +253,35 @@ ForEachMacros: - 'for_each_free_mem_range' - 'for_each_free_mem_range_reverse' - 'for_each_func_rsrc' + - 'for_each_group_evsel' + - 'for_each_group_member' - 'for_each_hstate' - 'for_each_if' + - 'for_each_inject_fn' + - 'for_each_insn' + - 'for_each_insn_prefix' + - 'for_each_intid' - 'for_each_iommu' - 'for_each_ip_tunnel_rcu' - 'for_each_irq_nr' + - 'for_each_lang' - 'for_each_link_codecs' - 'for_each_link_cpus' - 'for_each_link_platforms' - 'for_each_lru' - 'for_each_matching_node' - 'for_each_matching_node_and_match' - - 'for_each_member' - - 'for_each_mem_region' - - 'for_each_memblock_type' - - 'for_each_memcg_cache_index' - 'for_each_mem_pfn_range' - - '__for_each_mem_range' - 'for_each_mem_range' - - '__for_each_mem_range_rev' - 'for_each_mem_range_rev' + - 'for_each_mem_region' + - 'for_each_member' + - 'for_each_memory' - 'for_each_migratetype_order' - - 'for_each_msi_entry' - - 'for_each_msi_entry_safe' + - 'for_each_missing_reg' - 'for_each_net' - 'for_each_net_continue_reverse' + - 'for_each_net_rcu' - 'for_each_netdev' - 'for_each_netdev_continue' - 'for_each_netdev_continue_rcu' @@ -225,12 +291,13 @@ ForEachMacros: - 'for_each_netdev_rcu' - 'for_each_netdev_reverse' - 'for_each_netdev_safe' - - 'for_each_net_rcu' - 'for_each_new_connector_in_state' - 'for_each_new_crtc_in_state' - 'for_each_new_mst_mgr_in_state' - 'for_each_new_plane_in_state' + - 'for_each_new_plane_in_state_reverse' - 'for_each_new_private_obj_in_state' + - 'for_each_new_reg' - 'for_each_node' - 'for_each_node_by_name' - 'for_each_node_by_type' @@ -246,20 +313,20 @@ ForEachMacros: - 'for_each_old_connector_in_state' - 'for_each_old_crtc_in_state' - 'for_each_old_mst_mgr_in_state' + - 'for_each_old_plane_in_state' + - 'for_each_old_private_obj_in_state' - 'for_each_oldnew_connector_in_state' - 'for_each_oldnew_crtc_in_state' - 'for_each_oldnew_mst_mgr_in_state' - 'for_each_oldnew_plane_in_state' - 'for_each_oldnew_plane_in_state_reverse' - 'for_each_oldnew_private_obj_in_state' - - 'for_each_old_plane_in_state' - - 'for_each_old_private_obj_in_state' - 'for_each_online_cpu' - 'for_each_online_node' - 'for_each_online_pgdat' + - 'for_each_path' - 'for_each_pci_bridge' - 'for_each_pci_dev' - - 'for_each_pci_msi_entry' - 'for_each_pcm_streams' - 'for_each_physmem_range' - 'for_each_populated_zone' @@ -267,22 +334,33 @@ ForEachMacros: - 'for_each_present_cpu' - 'for_each_prime_number' - 'for_each_prime_number_from' + - 'for_each_probe_cache_entry' - 'for_each_process' - 'for_each_process_thread' + - 'for_each_prop_codec_conf' + - 'for_each_prop_dai_codec' + - 'for_each_prop_dai_cpu' + - 'for_each_prop_dlc_codecs' + - 'for_each_prop_dlc_cpus' + - 'for_each_prop_dlc_platforms' - 'for_each_property_of_node' + - 'for_each_reg' + - 'for_each_reg_filtered' - 'for_each_registered_fb' - 'for_each_requested_gpio' - 'for_each_requested_gpio_in_range' - 'for_each_reserved_mem_range' - 'for_each_reserved_mem_region' - 'for_each_rtd_codec_dais' - - 'for_each_rtd_codec_dais_rollback' - 'for_each_rtd_components' - 'for_each_rtd_cpu_dais' - - 'for_each_rtd_cpu_dais_rollback' - 'for_each_rtd_dais' + - 'for_each_script' + - 'for_each_sec' - 'for_each_set_bit' - 'for_each_set_bit_from' + - 'for_each_set_bitrange' + - 'for_each_set_bitrange_from' - 'for_each_set_clump8' - 'for_each_sg' - 'for_each_sg_dma_page' @@ -291,17 +369,25 @@ ForEachMacros: - 'for_each_sgtable_dma_sg' - 'for_each_sgtable_page' - 'for_each_sgtable_sg' + - 'for_each_shell_test' - 'for_each_sibling_event' - 'for_each_subelement' - 'for_each_subelement_extid' - 'for_each_subelement_id' - - '__for_each_thread' + - 'for_each_sublist' + - 'for_each_subsystem' + - 'for_each_supported_activate_fn' + - 'for_each_supported_inject_fn' + - 'for_each_test' - 'for_each_thread' + - 'for_each_token' - 'for_each_unicast_dest_pgid' + - 'for_each_vsi' - 'for_each_wakeup_source' - 'for_each_zone' - 'for_each_zone_zonelist' - 'for_each_zone_zonelist_nodemask' + - 'func_for_each_insn' - 'fwnode_for_each_available_child_node' - 'fwnode_for_each_child_node' - 'fwnode_graph_for_each_endpoint' @@ -315,7 +401,13 @@ ForEachMacros: - 'hash_for_each_possible_safe' - 'hash_for_each_rcu' - 'hash_for_each_safe' + - 'hashmap__for_each_entry' + - 'hashmap__for_each_entry_safe' + - 'hashmap__for_each_key_entry' + - 'hashmap__for_each_key_entry_safe' - 'hctx_for_each_ctx' + - 'hists__for_each_format' + - 'hists__for_each_sort_list' - 'hlist_bl_for_each_entry' - 'hlist_bl_for_each_entry_rcu' - 'hlist_bl_for_each_entry_safe' @@ -330,7 +422,7 @@ ForEachMacros: - 'hlist_for_each_entry_rcu_bh' - 'hlist_for_each_entry_rcu_notrace' - 'hlist_for_each_entry_safe' - - '__hlist_for_each_rcu' + - 'hlist_for_each_entry_srcu' - 'hlist_for_each_safe' - 'hlist_nulls_for_each_entry' - 'hlist_nulls_for_each_entry_from' @@ -338,9 +430,6 @@ ForEachMacros: - 'hlist_nulls_for_each_entry_safe' - 'i3c_bus_for_each_i2cdev' - 'i3c_bus_for_each_i3cdev' - - 'ide_host_for_each_port' - - 'ide_port_for_each_dev' - - 'ide_port_for_each_present_dev' - 'idr_for_each_entry' - 'idr_for_each_entry_continue' - 'idr_for_each_entry_continue_ul' @@ -348,7 +437,12 @@ ForEachMacros: - 'in_dev_for_each_ifa_rcu' - 'in_dev_for_each_ifa_rtnl' - 'inet_bind_bucket_for_each' + - 'inet_lhash2_for_each_icsk' + - 'inet_lhash2_for_each_icsk_continue' - 'inet_lhash2_for_each_icsk_rcu' + - 'intlist__for_each_entry' + - 'intlist__for_each_entry_safe' + - 'kcore_copy__for_each_phdr' - 'key_for_each' - 'key_for_each_safe' - 'klp_for_each_func' @@ -359,7 +453,9 @@ ForEachMacros: - 'klp_for_each_object_static' - 'kunit_suite_for_each_test_case' - 'kvm_for_each_memslot' + - 'kvm_for_each_memslot_in_gfn_range' - 'kvm_for_each_vcpu' + - 'libbpf_nla_for_each_attr' - 'list_for_each' - 'list_for_each_codec' - 'list_for_each_codec_safe' @@ -378,6 +474,8 @@ ForEachMacros: - 'list_for_each_entry_safe_continue' - 'list_for_each_entry_safe_from' - 'list_for_each_entry_safe_reverse' + - 'list_for_each_entry_srcu' + - 'list_for_each_from' - 'list_for_each_prev' - 'list_for_each_prev_safe' - 'list_for_each_safe' @@ -385,11 +483,18 @@ ForEachMacros: - 'llist_for_each_entry' - 'llist_for_each_entry_safe' - 'llist_for_each_safe' + - 'map__for_each_symbol' + - 'map__for_each_symbol_by_name' + - 'map_for_each_event' + - 'map_for_each_metric' + - 'maps__for_each_entry' + - 'maps__for_each_entry_safe' - 'mci_for_each_dimm' - 'media_device_for_each_entity' - 'media_device_for_each_intf' - 'media_device_for_each_link' - 'media_device_for_each_pad' + - 'msi_for_each_desc' - 'nanddev_io_for_each_page' - 'netdev_for_each_lower_dev' - 'netdev_for_each_lower_private' @@ -411,7 +516,23 @@ ForEachMacros: - 'of_property_for_each_string' - 'of_property_for_each_u32' - 'pci_bus_for_each_resource' + - 'pcl_for_each_chunk' + - 'pcl_for_each_segment' - 'pcm_for_each_format' + - 'perf_config_items__for_each_entry' + - 'perf_config_sections__for_each_entry' + - 'perf_config_set__for_each_entry' + - 'perf_cpu_map__for_each_cpu' + - 'perf_evlist__for_each_entry' + - 'perf_evlist__for_each_entry_reverse' + - 'perf_evlist__for_each_entry_safe' + - 'perf_evlist__for_each_evsel' + - 'perf_evlist__for_each_mmap' + - 'perf_hpp_list__for_each_format' + - 'perf_hpp_list__for_each_format_safe' + - 'perf_hpp_list__for_each_sort_list' + - 'perf_hpp_list__for_each_sort_list_safe' + - 'perf_pmu__for_each_hybrid_pmu' - 'ping_portaddr_for_each_entry' - 'plist_for_each' - 'plist_for_each_continue' @@ -426,10 +547,12 @@ ForEachMacros: - 'queue_for_each_hw_ctx' - 'radix_tree_for_each_slot' - 'radix_tree_for_each_tagged' + - 'rb_for_each' - 'rbtree_postorder_for_each_entry_safe' - 'rdma_for_each_block' - 'rdma_for_each_port' - 'rdma_umem_for_each_dma_block' + - 'resort_rb__for_each_entry' - 'resource_list_for_each_entry' - 'resource_list_for_each_entry_safe' - 'rhl_for_each_entry_rcu' @@ -443,15 +566,18 @@ ForEachMacros: - 'rht_for_each_from' - 'rht_for_each_rcu' - 'rht_for_each_rcu_from' - - '__rq_for_each_bio' - 'rq_for_each_bvec' - 'rq_for_each_segment' + - 'rq_list_for_each' + - 'rq_list_for_each_safe' - 'scsi_for_each_prot_sg' - 'scsi_for_each_sg' - 'sctp_for_each_hentry' - 'sctp_skb_for_each' + - 'sec_for_each_insn' + - 'sec_for_each_insn_continue' + - 'sec_for_each_insn_from' - 'shdma_for_each_chan' - - '__shost_for_each_device' - 'shost_for_each_device' - 'sk_for_each' - 'sk_for_each_bound' @@ -468,7 +594,13 @@ ForEachMacros: - 'snd_soc_dapm_widget_for_each_path_safe' - 'snd_soc_dapm_widget_for_each_sink_path' - 'snd_soc_dapm_widget_for_each_source_path' + - 'strlist__for_each_entry' + - 'strlist__for_each_entry_safe' + - 'sym_for_each_insn' + - 'sym_for_each_insn_continue_reverse' + - 'symbols__for_each_entry' - 'tb_property_for_each' + - 'tcf_act_for_each_action' - 'tcf_exts_for_each_action' - 'udp_portaddr_for_each_entry' - 'udp_portaddr_for_each_entry_rcu' @@ -492,15 +624,17 @@ ForEachMacros: - 'xbc_node_for_each_array_value' - 'xbc_node_for_each_child' - 'xbc_node_for_each_key_value' + - 'xbc_node_for_each_subkey' - 'zorro_for_each_dev' -#IncludeBlocks: Preserve # Unknown to clang-format-5.0 +IncludeBlocks: Preserve IncludeCategories: - Regex: '.*' Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false -#IndentPPDirectives: None # Unknown to clang-format-5.0 +IndentGotoLabels: false +IndentPPDirectives: None IndentWidth: 8 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave @@ -510,13 +644,13 @@ MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None -#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 +ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true # Taken from git's rules -#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 +PenaltyBreakAssignment: 10 PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 0 @@ -527,14 +661,14 @@ PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: false SortIncludes: false -#SortUsingDeclarations: false # Unknown to clang-format-4.0 +SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true -#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 -#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 -SpaceBeforeParens: ControlStatements -#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatementsExceptForEachMacros +SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs new file mode 100644 index 000000000000..45b739879d76 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-aufs @@ -0,0 +1,55 @@ +What: /debug/aufs/si_/ +Date: March 2009 +Contact: J. R. Okajima +Description: + Under /debug/aufs, a directory named si_ is created + per aufs mount, where is a unique id generated + internally. + +What: /debug/aufs/si_/plink +Date: Apr 2013 +Contact: J. R. Okajima +Description: + It has three lines and shows the information about the + pseudo-link. The first line is a single number + representing a number of buckets. The second line is a + number of pseudo-links per buckets (separated by a + blank). The last line is a single number representing a + total number of psedo-links. + When the aufs mount option 'noplink' is specified, it + will show "1\n0\n0\n". + +What: /debug/aufs/si_/xib +Date: March 2009 +Contact: J. R. Okajima +Description: + It shows the consumed blocks by xib (External Inode Number + Bitmap), its block size and file size. + When the aufs mount option 'noxino' is specified, it + will be empty. About XINO files, see the aufs manual. + +What: /debug/aufs/si_/xi +Date: March 2009 +Contact: J. R. Okajima +Description: + It shows the consumed blocks by xino (External Inode Number + Translation Table), its link count, block size and file + size. + Due to the file size limit, there may exist multiple + xino files per branch. In this case, "-N" is added to + the filename and it corresponds to the index of the + internal xino array. "-0" is omitted. + When the aufs mount option 'noxino' is specified, Those + entries won't exist. About XINO files, see the aufs + manual. + +What: /debug/aufs/si_/xigen +Date: March 2009 +Contact: J. R. Okajima +Description: + It shows the consumed blocks by xigen (External Inode + Generation Table), its block size and file size. + If CONFIG_AUFS_EXPORT is disabled, this entry will not + be created. + When the aufs mount option 'noxino' is specified, it + will be empty. About XINO files, see the aufs manual. diff --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs new file mode 100644 index 000000000000..48500c0569e6 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-aufs @@ -0,0 +1,31 @@ +What: /sys/fs/aufs/si_/ +Date: March 2009 +Contact: J. R. Okajima +Description: + Under /sys/fs/aufs, a directory named si_ is created + per aufs mount, where is a unique id generated + internally. + +What: /sys/fs/aufs/si_/br +Date: March 2009 +Contact: J. R. Okajima +Description: + It shows the abolute path of a member directory (which + is called branch) in aufs, and its permission. + +What: /sys/fs/aufs/si_/brid +Date: July 2013 +Contact: J. R. Okajima +Description: + It shows the id of a member directory (which is called + branch) in aufs. + +What: /sys/fs/aufs/si_/xi_path +Date: March 2009 +Contact: J. R. Okajima +Description: + It shows the abolute path of XINO (External Inode Number + Bitmap, Translation Table and Generation Table) file + even if it is the default path. + When the aufs mount option 'noxino' is specified, it + will be empty. About XINO files, see the aufs manual. diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi index b16d30a71709..b9d9a9908ceb 100644 --- a/Documentation/ABI/testing/sysfs-firmware-acpi +++ b/Documentation/ABI/testing/sysfs-firmware-acpi @@ -1,3 +1,46 @@ +What: /sys/firmware/acpi/firmware_performance_data/ +Date: Aug 2019 +Contact: Zhang Rui +Description: + ACPI Firmware Performance Data Table (FPDT) provides + information for firmware performance data for system boot, + S3 suspend and S3 resume. This sysfs entry contains the + performance data retrieved from the FPDT. + + boot_performance: + firmware_start_ns: Timer value logged at the beginning + of firmware image execution. In nanoseconds. + bootloader_load_ns: Timer value logged just prior to + loading the OS boot loader into memory. + In nanoseconds. + bootloader_launch_ns: Timer value logged just prior to + launching the currently loaded OS boot loader + image. In nanoseconds. + exitbootservice_start_ns: Timer value logged at the + point when the OS loader calls the + ExitBootServices function for UEFI compatible + firmware. In nanoseconds. + exitbootservice_end_ns: Timer value logged at the point + just prior to the OS loader gaining control + back from the ExitBootServices function for + UEFI compatible firmware. In nanoseconds. + suspend_performance: + suspend_start_ns: Timer value recorded at the previous + OS write to SLP_TYP upon entry to S3. In + nanoseconds. + suspend_end_ns: Timer value recorded at the previous + firmware write to SLP_TYP used to trigger + hardware entry to S3. In nanoseconds. + resume_performance: + resume_count: A count of the number of S3 resume cycles + since the last full boot sequence. + resume_avg_ns: Average timer value of all resume cycles + logged since the last full boot sequence, + including the most recent resume. In nanoseconds. + resume_prev_ns: Timer recorded at the end of the previous + platform runtime firmware S3 resume, just prior to + handoff to the OS waking vector. In nanoseconds. + What: /sys/firmware/acpi/bgrt/ Date: January 2012 Contact: Matthew Garrett diff --git a/Documentation/admin-guide/sysctl/vm.rst b/Documentation/admin-guide/sysctl/vm.rst index 06027c6a233a..763fc021ca7b 100644 --- a/Documentation/admin-guide/sysctl/vm.rst +++ b/Documentation/admin-guide/sysctl/vm.rst @@ -40,6 +40,7 @@ Currently, these files are in /proc/sys/vm: - extfrag_threshold - highmem_is_dirtyable - hugetlb_shm_group +- kswapd_threads - laptop_mode - legacy_va_layout - lowmem_reserve_ratio @@ -314,6 +315,29 @@ hugetlb_shm_group contains group id that is allowed to create SysV shared memory segment using hugetlb page. +kswapd_threads +============== + +Available only when CONFIG_SYNO_MULTI_KSWAPD is set. +kswapd_threads allows you to control the number of kswapd threads per node +running on the system. This provides the ability to devote additional CPU +resources toward proactive page replacement with the goal of reducing +direct reclaims. When direct reclaims are prevented, the CPU consumed +by them is prevented as well. Depending on the workload, the result can +cause aggregate CPU usage on the system to go up, down or stay the same. + +More aggressive page replacement can reduce direct reclaims which cause +latency for tasks and decrease throughput when doing filesystem IO through +the pagecache. Direct reclaims are recorded using the allocstall counter +in /proc/vmstat. + +The default value is 1 and the range of acceptible values are 1-16. +Always start with lower values in the 2-6 range. Higher values should +be justified with testing. If direct reclaims occur in spite of high +values, the cost of direct reclaims (in latency) that occur can be +higher due to increased lock contention. + + laptop_mode =========== diff --git a/Documentation/devicetree/bindings/arm/realtek.yaml b/Documentation/devicetree/bindings/arm/realtek.yaml index 9fb0297fe1ce..a7e9757b7701 100644 --- a/Documentation/devicetree/bindings/arm/realtek.yaml +++ b/Documentation/devicetree/bindings/arm/realtek.yaml @@ -55,6 +55,20 @@ properties: - realtek,mjolnir # Realtek Mjolnir EVB - const: realtek,rtd1619 +#if defined(CONFIG_SYNO_LSP_RTD1619B) + # RTD1319 SoC based boards + - items: + - enum: + - realtek,pym-particles # Realtek Pym Particles EVB + - const: realtek,rtd1319 + + # RTD1619B SoC based boards + - items: + - enum: + - realtek,bleeding-edge # Realtek Bleeding Edge EVB + - const: realtek,rtd1619b + +#endif /* CONFIG_SYNO_LSP_RTD1619B */ additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/clock/realtek,clocks.txt b/Documentation/devicetree/bindings/clock/realtek,clocks.txt new file mode 100644 index 000000000000..6958de9b1cd9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/realtek,clocks.txt @@ -0,0 +1,76 @@ +Realtek Clock/Reset Controller +============================== + +Clock/Reset controllers for Realtek Platform + +Platform Controllers +-------------------- + +These device tree node should be placed in a syscon. + +Required properties : + +- compatible : + should contain only one of the following: + + "realtek,rtd1195-crt-clk" for RTD1195 CRT clock controller, + "realtek,rtd1195-iso-clk" for RTD1195 ISO clock controller, + "realtek,rtd1295-crt-clk" for RTD1295 CRT clock controller, + "realtek,rtd1295-iso-clk" for RTD1295 ISO clock controller, + "realtek,rtd1395-crt-clk" for RTD1395 CRT clock controller, + "realtek,rtd1395-iso-clk" for RTD1395 ISO clock controller, + "realtek,rtd1619-crt-clk" for RTD1619 CRT clock controller, + "realtek,rtd1611-crt-clk" for RTD1611 CRT clock controller, + "realtek,rtd1619-iso-clk" for RTD1619 ISO clock controller, + "realtek,rtd1319-crt-clk" for RTD1319 CRT clock controller, + "realtek,rtd1319-crt-clk-n" for RTD1319 CRT clock controller of non-protected clocks, + "realtek,rtd1311-crt-clk" for RTD1311 CRT clock controller, + "realtek,rtd1319-iso-clk" for RTD1319 ISO clock controller, + "realtek,rtd1619b-crt-clk" for RTD1319 CRT clock controller, + "realtek,rtd1619b-crt-clk-n" for RTD1319 CRT clock controller of non-protected clocks, + "realtek,rtd1619b-iso-clk" for RTD1319 ISO clock controller. + + +- #clock-cells : should be 1. + +- #reset-cells : should be 1. + +Example: + + syscon@98000000 { + ... + + cc: clock-controller { + compatible = "realtek,rtd1295-cc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + }; + + consumer { + clocks = <&cc CC_CKE_GSPI>; + }; + + +TEE Clock Controller +-------------------- + +Required properties : + +- compatible : + should contain only one of the following: + + "realtek,tee-clock-controller" for TEE Clock Controller + + +- #clock-cells : should be 0. + +Example: + + tcc: tee-clocks { + compatible = "realtek,tee-clock-controller"; + #clock-cells = <0>; + }; + + +See "clock-bindings.txt" diff --git a/Documentation/devicetree/bindings/iio/adc/realtek,rtk-lsadc.txt b/Documentation/devicetree/bindings/iio/adc/realtek,rtk-lsadc.txt new file mode 100644 index 000000000000..fecc9789748d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/realtek,rtk-lsadc.txt @@ -0,0 +1,57 @@ +Realtek Low-speed Analog to Digital Converter + +This LSADC has 2 pads with 6-bits resolution for 0 ~ 3.3V. + +Required properties: +- compatible: should be one of + "realtek,rtk-lsadc0" + "realtek,rtk-lsadc" +- interrupt-parent: phandle to the parent interrupt controller + see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +- interrupts: IRQ line for the LSADC +- reg: Offset and length of the LSADC block register set. +- clk_gating_en: clock gating for LSADC is used for power saving. + 0: disable + 1: enable +- clocks: Clock used for this block. +- resets: phandle to reset this block. + +Sub-nodes: +Each LSADC pad is configured as a subnode. + +Required properties for subnodes: +- activate: 0:in-activate, 1:activate +- ctrl_mode: 0:voltage mode, 1:current mode +- sw_idx: 0:External input pin 0, 1:External input pin 1 +- voltage_threshold: voltage threshold to trigger interrupt +- adc_val_baseline: absolute baseline to reset adc_val + + +Example node: + + lsadc@7900 { + compatible = "realtek,rtk-lsadc0"; + interrupt-parent = <&iso_irq_mux>; + interrupts = <3>; + reg = <0x7900 0x200>, + <0x34c 0x4>; + clk_gating_en = <1>; + clocks = <&ic IC_CKE_LSADC_ECOA2>; + resets = <&ic IC_RSTN_LSADC_ECOA2>; + lsadc0-pad0 { + activate = <1>; + ctrl_mode = <0>; + sw_idx = <0>; + voltage_threshold = <32>; + adc_val_baseline = <63>; + }; + + lsadc0-pad1 { + activate = <0>; + ctrl_mode = <0>; + sw_idx = <1>; + voltage_threshold = <63>; + adc_val_baseline = <63>; + }; + }; + diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek,intc.txt b/Documentation/devicetree/bindings/interrupt-controller/realtek,intc.txt new file mode 100644 index 000000000000..3a9aed48ad91 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,intc.txt @@ -0,0 +1,18 @@ +Realrek Interrupt Controller + +Required properties: + +- compatible : "realtek,rtd13xx-iso-irq-mux" for rtd1319 SoCs + "realtek,rtd13xx-misc-irq-mux" for rtd1319 SoCs + "realtek,rtd16xxb-iso-irq-mux" for rtd1619b SoCs + "realtek,rtd16xxb-misc-irq-mux" for rtd1619b SoCs + +Example: + +iso_irq_mux: iso_irq_mux { + compatible = "realtek,rtd13xx-iso-irq-mux"; + syscon = <&iso>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; +}; diff --git a/Documentation/devicetree/bindings/mfd/apw888x.txt b/Documentation/devicetree/bindings/mfd/apw888x.txt new file mode 100644 index 000000000000..eb977abb28f7 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/apw888x.txt @@ -0,0 +1,54 @@ +Anpec APW888X series PMIC DT-bindings + +Required properties: + +* compatible: shall contains one of the following + "anpec,apw8889", + "anpec,apw8886", or + "anpec,apw7899". + + +===================================== + +Anpec APW888X serise PMIC contains the following sub devices: + g22xx-powerkey, + apw8889-regulator for Anpec APW8889, + apw8886-regulator for Anper APW8886. + +Sub nodes: + +regulators +---------- + +Required properties: + +* compatible: shall contains one of the following + "anpec,apw8889-regulator", + "anpec,apw8886-regulator". + +See also Documentation/devicetree/bindings/regulator/regulator.txt. + +Properties for sub nodes + +Optional properties: + +* apw888x-discharge-disable: disable discharge when suspend state is configured + to regulator-off-in-suspend in the sub nodes + regulator-state-mem/regulator-state-coldboot. + +Example: + + &i2c_0 { + status = "okay"; + + apw8889: apw8889@12 { + compatible = "anpec,apw8889"; + reg = <0x12>; + status = "okay"; + + regulators: regulators { + compatible = "anpec,apw8889-regulator"; + status = "okay"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml b/Documentation/devicetree/bindings/net/ethernet-controller.yaml index 9e41dad9ef4d..b73d3f77ca99 100644 --- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml @@ -49,7 +49,11 @@ properties: description: Reference to an nvmem node for the MAC address +#if defined(CONFIG_SYNO_LSP_RTD1619B) + nvmem-cells-names: +#else /* CONFIG_SYNO_LSP_RTD1619B */ nvmem-cell-names: +#endif /* CONFIG_SYNO_LSP_RTD1619B */ const: mac-address phy-connection-type: diff --git a/Documentation/devicetree/bindings/net/realtek,r8169soc.txt b/Documentation/devicetree/bindings/net/realtek,r8169soc.txt new file mode 100644 index 000000000000..596535aaa8ce --- /dev/null +++ b/Documentation/devicetree/bindings/net/realtek,r8169soc.txt @@ -0,0 +1,56 @@ +Realtek r8169soc Ethernet driver + +Required properties: +- compatible: should be one of below strings + "realtek,rtd119x-r8169soc" for Phoenix (RTD1195) SoC + "realtek,rtd129x-r8169soc" for Kylin (RTD1293, RTD1295, RTD1296) SoC + "realtek,rtd139x-r8169soc" for Hercules (RTD1395) SoC + "realtek,rtd16xx-r8169soc" for Thor (RTD1619) SoC + "realtek,rtd13xx-r8169soc" for Hank (RTD1319) SoC + "realtek,rtd16xxb-r8169soc" for Stark (RTD1619B) SoC +- reg: Address and length of the register set for the device +- interrupts: Should contain the MAC interrupts +- pinctrl-names: names of pinmux set of corresponding output mode +- pinctrl-0: the default pinmux set +- local-mac-address: See ethernet-controller.yaml in the same directory. + This property is overwrited by bootloader. +- output-mode: 0:embedded PHY (default), + 1:RGMII to MAC (valid for RTD1295, and RTD1319), + 2:RGMII to PHY (valid for RTD1319), + 3:SGMII to MAC (valid for RTD1395, and RTD1619), + 4:SGMII to PHY (valid for RTD1395, and RTD1619), + 5:RMII (valid for RTD1319), + 6:forced link (valid for RTD1319) +- acp: support ACP (Accelerator Coherence Port) or not +- eee: support EEE (Energy-Efficient Ethernet) or not +- clocks: Must contain a handle for each entry in clock-names. +- clock-names: The name of the clock listed in the clocks property. +- resets: Must contain a handle for each entry in reset-names. +- reset-names: The name of the reset listed in the resets property. + +Optional properties: +- bypass: valid for RTD1395 + 1: ETN MAC bypasses efuse update flow. SW needs to take this sequence. + 0: ETN MAC sets efuse update and efuse_rdy setting +- wol-enable: enable WoL or not + BIT 0: WoL enable + BIT 1: CRC match (up to 16 match patterns) + BIT 2: WPD (Wake Packet Detection) +- led-cfg: customized LED setting +- pinctrl-1: the extra pinmux set of of corresponding output mode +- ext-phy-id: 0 ~ 31, only valid when output-mode = "SGMII to PHY" +- sgmii-swing: 0:640mV, 1:380mV, 2:250mV, 3:190mV, + only valid when output-mode = "SGMII to MAC" or "SGMII to PHY" +- voltage: 1:1.8V, 2:2.5V, 3: 3.3V; + only valid when output-mode = "RGMII to MAC", "RGMII to PHY", or "RMII" +- tx-delay: 0:0ns, 1:2ns; + only valid when output-mode = "RGMII to MAC", "RGMII to PHY", or "RMII" +- rx-delay: 0:0ns, 1:2ns; + only valid when output-mode = "RGMII to MAC", "RGMII to PHY", or "RMII" +- force-Gb-off: disable gigabit feature if defined +- wake-mask[0-15]: pattern mask of a packet (for WoL via CRC match) +- wake-crc[0-15]: CRC value of a masked packet (for WoL via CRC match) +- wake-mask[0-31]: pattern mask of a packet (for WoL via exactly pattern match) +- wake-crc[0-31]: CRC value of a masked packet (for WoL via exactly pattern match) +- wake-pattern[0-31]: pattern content for corresponding masked bytes (for WoL via exactly pattern match) +- wake-offset[0-31]: start offset of pattern (for WoL via exactly pattern match) diff --git a/Documentation/devicetree/bindings/nvmem/rtk-efuse.txt b/Documentation/devicetree/bindings/nvmem/rtk-efuse.txt new file mode 100644 index 000000000000..0a9d6c65e276 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/rtk-efuse.txt @@ -0,0 +1,12 @@ +Realtek eFuse DT-bindings +========================= + +See also 'Documentation/devicetree/bindings/nvmem/nvmem.txt' + +Requried properties : +- compatible : shall contain one of the followings : + "realtek,efuse", + "realtek,rtd1619-otp" + +Optional properties: +- realtek,sb2-lock : a hw lock for synchronization diff --git a/Documentation/devicetree/bindings/power/reset/regmap-poweroff.txt b/Documentation/devicetree/bindings/power/reset/regmap-poweroff.txt new file mode 100644 index 000000000000..45abe48de10a --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/regmap-poweroff.txt @@ -0,0 +1,29 @@ +Simple Regmap Poweroff +====================== + +This is a simple regmap poweroff driver, which gets regmap from the parent +device and sets a register with value. + +Required properties: +- compatible: should contain "regmap-poweroff" +- poweroff,offset: offset in the register map for the poweroff register +- poweroff,mask: the mask written to the poweroff register +- poweroff,value the value written to the poweroff register + +Optional properties: +- system-power-controller: to indicate pm_power_off is set by this device. + See also ../power-controller.txt + +Examples: + + parent { + + poweroff { + compatible = "regmap-poweroff"; + poweroff,offset = <0x04>; + poweroff,mask = <0x80>; + poweroff,value = <0x80> + system-power-controller; + }; + }; + diff --git a/Documentation/devicetree/bindings/power/reset/rtk,reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/rtk,reboot-mode.txt new file mode 100644 index 000000000000..4c8ab25291bd --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/rtk,reboot-mode.txt @@ -0,0 +1,15 @@ +Realtek reboot mode driver + +Required propertise: + +- compatible: should contain "realtek,reboot-mode". + +- reg: register to fill reboot command + +Exmaple: + + reboot-mode { + compatible = "realtek,reboot-mode"; + reg = <0x0 0x98007640 0x0 0x4>; + status = "okay"; + }; diff --git a/Documentation/devicetree/bindings/power/reset/rtk,reboot.txt b/Documentation/devicetree/bindings/power/reset/rtk,reboot.txt new file mode 100644 index 000000000000..cabef3336005 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/rtk,reboot.txt @@ -0,0 +1,20 @@ +Realtek reboot driver + +Required properties: + +- compatible: should be "realtek,reboot" + +Optional properties: + +- rst-oe: an unsigned int for value of oe to be configured + +- rst-oe-for-init: an unsigned int for init value of oe + +Example: + reboot { + compatible = "realtek,reboot"; + rst-oe = <0>; + rst-oe-for-init = <1>; + status = "okay"; + }; + diff --git a/Documentation/devicetree/bindings/pwm/realtek,rtk-pwm.txt b/Documentation/devicetree/bindings/pwm/realtek,rtk-pwm.txt new file mode 100644 index 000000000000..be581f3639fd --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/realtek,rtk-pwm.txt @@ -0,0 +1,19 @@ +Realtek PWM controller + +This PWM controller provides 4 PWM outputs as sub-nodes and each one can be +enabled individually. +Required properties: +- compatible: should be one of below strings + "realtek,rtk-pwm" for PWM V1 mode (rtd129x, rtd139x, rtd16xx, rtd13xx, rtd16xxb) + "realtek,rtk-pwm-v2" for PWM V2 mode (rtd1312c) +- #pwm-cells: should be 2. See pwm.yaml in this directory for a description + of the cells format +- reg: physical base address and length for this controller + +Required properties of each sub-node: +- enable: turn on/off this PWM output +- clkout_div: PWM output clock divisor. +- clksrc_div: PWM clock source divisor. +- duty_rate: crest-to-trough ratio of this PWM output + + diff --git a/Documentation/devicetree/bindings/reserved-memory/realtek,shared-memory.txt b/Documentation/devicetree/bindings/reserved-memory/realtek,shared-memory.txt new file mode 100644 index 000000000000..f45327e60a9a --- /dev/null +++ b/Documentation/devicetree/bindings/reserved-memory/realtek,shared-memory.txt @@ -0,0 +1,4 @@ +* Realtek DHC platforms reserved-memory binding + +- compatible: + compatible = "ringbuf", "audio_heap", "media_heap"; diff --git a/Documentation/devicetree/bindings/reset/rtk-reset.txt b/Documentation/devicetree/bindings/reset/rtk-reset.txt new file mode 100644 index 000000000000..1dc872302c67 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/rtk-reset.txt @@ -0,0 +1,14 @@ +Realtek Reset Controller DT-bindings +------------------------------------ + +1. M2TMX reset controller + +Required properties + +- compatible: shall contain + "realtek,rtd1319-m2tmx-reset". + +- #reset-cells: shall be 1. + +- realtek,m2tmx: shall contain a phandle to m2tmx syscon + diff --git a/Documentation/devicetree/bindings/rtc/rtc-rtk.txt b/Documentation/devicetree/bindings/rtc/rtc-rtk.txt new file mode 100644 index 000000000000..9db0b450b73c --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-rtk.txt @@ -0,0 +1,24 @@ +Realtek real time clock driver dt-bindings +========================================== + +Required properties: +- compatible: must contains one of the following + "realtek,rtd1195-rtc", + "realtek,rtd1295-rtc", + "realtek,rtd1619-rtc", + "realtek,rtd1319-rtc". + +- reg: contain the base of rtc register + +- realtek,iso: a phandle to iso syscon + +Optional properties: + +- clocks: only required by rtd1195-rtc and rtd1295-rtc + +- resets: only required by rtd1195-rtc + +- rtc-base-year: should contain a integer for base year + +- rtc-bias: should contain a integer for bias + diff --git a/Documentation/devicetree/bindings/rtc/rtc-sw.txt b/Documentation/devicetree/bindings/rtc/rtc-sw.txt new file mode 100644 index 000000000000..60811aa75bfa --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-sw.txt @@ -0,0 +1,8 @@ +Realtek Software-emulated Real-time Clock Driver DT-bindings +============================================================ + +Required properties: + +* compatible: shoull be "realtek,emulated-rtc". + + diff --git a/Documentation/devicetree/bindings/soc/realtek/bsv_ctrl.txt b/Documentation/devicetree/bindings/soc/realtek/bsv_ctrl.txt new file mode 100644 index 000000000000..db0216b5dc23 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/bsv_ctrl.txt @@ -0,0 +1,58 @@ +Realtek BSV Controller for CPU DVFS dt-bindings +=============================================== + +Required properties: + +- compatible: should be "realtek,bsv-controller". + +- #clock-cells: should be 0. + +- clocks: cpu clock + +- cpu-supply: cpu supply + +- nvmem-cells: bsv data in otp + +- nvmem-cell-names: should be "bsv" + + +See regulator/regulator.yaml for regulator bindings. + +Example: + +/ { + bsvc: bsv-ctrl { + compatible = "realtek,bsv-controller"; + #clock-cells = <0>; + regulator-name = "bsv_cpudvs"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + clocks = <&cc RTD1619B_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + nvmem-cells = <&otp_bsv>; + nvmem-cell-names = "bsv"; + }; +}; + +&cpu0 { + clocks = <&bsvc>; + cpu-supply = <&bsvc>; +}; + +&cpu1 { + clocks = <&bsvc>; + cpu-supply = <&bsvc>; +}; + +&cpu2 { + clocks = <&bsvc>; + cpu-supply = <&bsvc>; +}; + +&cpu3 { + clocks = <&bsvc>; + cpu-supply = <&bsvc>; +}; + diff --git a/Documentation/devicetree/bindings/soc/realtek/crt.txt b/Documentation/devicetree/bindings/soc/realtek/crt.txt new file mode 100644 index 000000000000..b13af1314f23 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/crt.txt @@ -0,0 +1,24 @@ +Realtek CRT Driver DT-binding document +====================================== + +Required properties: + +- compatible: should contain "syscon", "simple-mfd" and one of the following, + "realtek,rtd1295-crt", + "realtek,rtd1395-crt", + "realtek,rtd1619-crt", + "realtek,rtd1319-crt". + +- reg: address of CRT. + +Example: + + crt: crt@98000000 { + reg = <0x0 0x98000000 0x0 0x1000>; + compatible = "realtek,rtd1319-crt", "syscon", "simple-mfd"; + ranges = <0x0 0x0 0x0 0x98000000 0x0 0x1000>; + #address-cells = <2>; + #size-cells = <2>; + }; + + diff --git a/Documentation/devicetree/bindings/soc/realtek/dbus_pmu.txt b/Documentation/devicetree/bindings/soc/realtek/dbus_pmu.txt new file mode 100644 index 000000000000..4a7f1b2a0db2 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/dbus_pmu.txt @@ -0,0 +1,42 @@ +Realtek Dbus (DC-SYS) PMU dt-bindings +===================================== + +Required properties: +- compatible: + "realtek,rtd-16xxb-dbus-pmu" for rtd16xxb family +- reg: address range of Dbus PMU + +Performance Counters Subnode +---------------------------- +Each subnode of Dbus PMU represents a set of PMC groups which has its own +counter groups and controlling mechanism, but will be enabled and disabled +together with Dbus PMU. + +Required properties: +- compatible: + "dbus-sysh" + "dbus-sys" + "dbus-ch" + +Optional properties: +- nr_defects: the number of counters which may work incorrectly +- defects: array of the index of problematic counters + +Example: + + dbus-pmu: rtk-dbus-pmu@8000 { + compatible = "realtek,rtk-16xxb-dbus-pmu"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x8000 0x0 0x0d00>; + + dbus-sysh: dbus-sysh { + nr_defects = <2>; + defects = <1 3>; + }; + + dbus-sys: dbus-sys { + nr_defects = <1>; + defects = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/realtek/ddrc_pmu.txt b/Documentation/devicetree/bindings/soc/realtek/ddrc_pmu.txt new file mode 100644 index 000000000000..712a1270018b --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/ddrc_pmu.txt @@ -0,0 +1,36 @@ +Realtek DDRC PMU dt-bindings +============================ + +Required properties: +- compatible: + "realtek,rtd-16xxb-ddrc-pmu" for rtd16xxb family +- reg: address range of DDRC PMU + +Performance Counters Subnode +---------------------------- +Each subnode of Dbus PMU represents a set of PMC groups which has its own +counter groups and controlling mechanism, but will be enabled and disabled +together with Dbus PMU. + +Required properties: +- compatible: + "ddrc-" + "ddrc-total" + +Optional properties: +- nr_defects: the number of counters which may work incorrectly +- defects: array of the index of problematic counters + +Example: + + ddrc-pmu: rtk-ddrc-pmu@94000 { + compatible = "realtek,rtk-16xxb-ddrc-pmu"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x94000 0x0 0x0800>; + + ddrc: ddrc { + nr_defects = <2>; + defects = <1 3>; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/realtek/info.txt b/Documentation/devicetree/bindings/soc/realtek/info.txt new file mode 100644 index 000000000000..06223ad6dce9 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/info.txt @@ -0,0 +1,16 @@ +Realtek Information provider DT-bindings +======================================== + +1. pll + +required properties: + +* compatible: should be one of the followings: + "realtek,rtd139x-pll-info", or + "realtek,rtd161x-pll-info", or + "realtek,rtd161xb-pll-info". + +* realtek,crt: a phandle to crt syscon. + +* realtek,scpu-wrapper: a phandle to scpu wrapper syscon. + diff --git a/Documentation/devicetree/bindings/soc/realtek/power-domain.txt b/Documentation/devicetree/bindings/soc/realtek/power-domain.txt new file mode 100644 index 000000000000..f660b5a086d0 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/power-domain.txt @@ -0,0 +1,14 @@ +Realtek Power Domain DT-bindings +================================ + +required propertise: + +- compatible : shall contain the one of followings : + "realtek,rtd1295-power", + "realtek,rtd1395-power", + "realtek,rtd1619-power", + "realtek,rtd1319-power", + "realtek,rtd1619b-power". + +- #power-domain-cells : shall contain unsigned int 1 + diff --git a/Documentation/devicetree/bindings/soc/realtek/rbus_pmu.txt b/Documentation/devicetree/bindings/soc/realtek/rbus_pmu.txt new file mode 100644 index 000000000000..bf2088a0bf35 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/rbus_pmu.txt @@ -0,0 +1,16 @@ +Realtek Rbus PMU dt-bindings +============================ + +Required properties: +- compatible: + "realtek,rtd-16xxb-rbus-pmu" for rtd16xxb family +- reg: Address range of Rbus PMU + +Example: + + rbus-pmu: rtk-rbus-pmu@1af00 { + compatible = "realtek,rtk-16xxb-rbus-pmu"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x1af00 0x0 0x0080>; + }; diff --git a/Documentation/devicetree/bindings/soc/realtek/wdt_st.txt b/Documentation/devicetree/bindings/soc/realtek/wdt_st.txt new file mode 100644 index 000000000000..e28473c35201 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/realtek/wdt_st.txt @@ -0,0 +1,16 @@ +Realtek Watchdog Status Driver DT-bindings +========================================== + +Required properties: + +- reg: address and size of the device. + +- compatible: shall be "realtek,rtd1619b-watchdog-status". + + +Example: + watchdog5: watchdog-st@aa0 { + reg = <0xaa0 0x20>; + compatible = "realtek,rtd1619b-watchdog-status"; + }; + diff --git a/Documentation/devicetree/bindings/sound/snd-realtek-notify.txt b/Documentation/devicetree/bindings/sound/snd-realtek-notify.txt new file mode 100644 index 000000000000..abc26a88beca --- /dev/null +++ b/Documentation/devicetree/bindings/sound/snd-realtek-notify.txt @@ -0,0 +1,27 @@ +Realtek Sound Pinmux Driver. + +Required properties: +- compatible : "adc" + "analog-in" + "adc-amic" + "earc-combo" + "realtek,audio-in" + "realtek,audio-out" + "realtek,audio" +- reg : The register base for the controller. +- interrupts : One interrupt, used by the controller. +- #address-cells : <1>, as required by generic sound device binding. +- #size-cells : <0>, also as required by generic sound device binding. +- pinctrl-names : Names of pinmux set of corresponding output mode. +- pinctrl-0 : The default pinmux set. +- num-chipselect : The number of chipselects. It should be 1. +- bus-num : The bus number of this sound device controller. +- clock-frequency : The max. frequency of this sound device controller. +- clocks : phandles for the clocks +- resets : phandles for the resets + +Child nodes as per the generic sound device binding. + +Example: + + diff --git a/Documentation/devicetree/bindings/sound/snd-realtek.txt b/Documentation/devicetree/bindings/sound/snd-realtek.txt new file mode 100644 index 000000000000..15a57c966f02 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/snd-realtek.txt @@ -0,0 +1,27 @@ +Realtek ALSA Driver. + +Required properties: +- compatible : "realtek,rtk-alsa-pcm" +- reg : The register base for the clock enable. +- interrupts : One interrupt, used by the controller. +- #address-cells : <1>, as required by generic alsa binding. +- #size-cells : <0>, also as required by generic alsa binding. +- pinctrl-names : Names of pinmux set of corresponding output mode. +- pinctrl-0 : The default pinmux set. +- num-chipselect : The number of chipselects. It should be 1. +- bus-num : The bus number of this alsa controller. +- clock-frequency : The max. frequency of this alsa controller. +- clocks : phandles for the clocks +- resets : phandles for the resets + +Child nodes as per the generic alsa binding. + +Example: + + sound: sound@10 { + compatible = "realtek,rtk-alsa-pcm"; + reg = <0x10 0x1000>; /* CLK_EN2 */ + realtek,refclk = <&refclk>; + status = "okay"; + }; + diff --git a/Documentation/devicetree/bindings/spi/spi-dw-rtk.txt b/Documentation/devicetree/bindings/spi/spi-dw-rtk.txt new file mode 100644 index 000000000000..2c1d964a8620 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-dw-rtk.txt @@ -0,0 +1,38 @@ +Realtek Synchronous Serial Interface based on DesignWare SPI core. + +Required properties: +- compatible : "realtek,rtk-dw-apb-ssi" +- reg : The register base for the controller. + The 1st one is for DW SPI core, and the 2nd one is for wrapper. +- interrupts : One interrupt, used by the controller. +- #address-cells : <1>, as required by generic SPI binding. +- #size-cells : <0>, also as required by generic SPI binding. +- pinctrl-names : Names of pinmux set of corresponding output mode. +- pinctrl-0 : The default pinmux set. +- num-chipselect : The number of chipselects. It should be 1. +- bus-num : The bus number of this SPI controller. +- clock-frequency : The max. frequency of this SPI controller. +- clocks : phandles for the clocks +- resets : phandles for the resets + +Child nodes as per the generic SPI binding. + +Example: + + spi_0: spi@1BD00 { + compatible = "realtek,rtk-dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <27>; /* SPI_INT */ + reg = <0x1BD00 0x100>, /* DW SPI */ + <0x1B300 0x18>; /* SPI wrapper */ + pinctrl-names = "default"; + pinctrl-0 = <&gspi_pins_0>; + num-chipselect = <1>; + bus-num = <0>; + clocks = <&cc CC_CKE_GSPI>; + clock-frequency = <256000000>; + resets = <&cc CC_RSTN_GSPI>; + }; + diff --git a/Documentation/devicetree/bindings/thermal/realtek-thermal.txt b/Documentation/devicetree/bindings/thermal/realtek-thermal.txt new file mode 100644 index 000000000000..9a6620637f1f --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/realtek-thermal.txt @@ -0,0 +1,41 @@ +Realtek Thermal Driver DT-bindings +================================== + +* Sensor node +------------- +Required properties : +- compatible : shall contain one of the following : + "realtek,rtd119x-thermal-sensor", + "realtek,rtd129x-thermal-sensor", + "realtek,rtd139x-thermal-sensor", + "realtek,rtd161x-thermal-sensor", + "realtek,rtd131x-thermal-sensor", + "realtek,rtd1619b-thermal-sensor", + "realtek,rtd1312c-thermal-sensor". + +- #thermal-sensor-cells : shall contain 0. + +Optional properties: +- eoh-restore-ms: shall contain a interger, lock-freq time in ms for eoh, + only vaild if eoh configured. + +See also 'Documentation/devicetree/bindings/thermal/thermal.txt' + +Exmaple : + cpu-tsensor { + tible = "realtek,rtd129x-thermal-sensor"; + reg = <0x9801D150 0x1C>; + #thermal-sensor-cells = <0>; + + status = "okay"; + }; + + +* CPU Core cooling +------------------ + +Required properties : +- compatible : should be "realtek,cpu-core-cooling" + +- #cooling-cells : should be 2 + diff --git a/Documentation/devicetree/bindings/watchdog/rtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/rtk-wdt.txt new file mode 100644 index 000000000000..0c2af49774cd --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/rtk-wdt.txt @@ -0,0 +1,30 @@ +Realtek watchdog DT-bindings +============================ + +Required properties: + +- compatible : should be "realtek,watchdog". + +- reg : should contains 1 or 2 base physical address and size of registers + + the first address/size is for watchdog registers, + the second address/size is optional and for watchdog ov-rstb registers. + + +Optional properties: + +- timeout-sec: contains the watchdog timeout in seconds + +- restart_priority: contains a value for restart_priority + +- ov-rstb-oe-init: initial value of ov-rstb-oe + +- ov-rstb-oe: value of ov-rstb-oe to be set during reboot + +Example: + + watchdog@10000000 { + compatible = "realtek,watchdog"; + reg = <0x10000000 0x100>; + timeout-sec = <20>; + }; diff --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README new file mode 100644 index 000000000000..3e655d357134 --- /dev/null +++ b/Documentation/filesystems/aufs/README @@ -0,0 +1,401 @@ + +Aufs5 -- advanced multi layered unification filesystem version 5.x +http://aufs.sf.net +Junjiro R. Okajima + + +0. Introduction +---------------------------------------- +In the early days, aufs was entirely re-designed and re-implemented +Unionfs Version 1.x series. Adding many original ideas, approaches, +improvements and implementations, it became totally different from +Unionfs while keeping the basic features. +Later, Unionfs Version 2.x series began taking some of the same +approaches to aufs1's. +Unionfs was being developed by Professor Erez Zadok at Stony Brook +University and his team. + +Aufs5 supports linux-v5.0 and later, If you want older kernel version +support, +- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git +- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git +- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git + or aufs1 from CVS on SourceForge. + +Note: it becomes clear that "Aufs was rejected. Let's give it up." + According to Christoph Hellwig, linux rejects all union-type + filesystems but UnionMount. + + +PS. Al Viro seems have a plan to merge aufs as well as overlayfs and + UnionMount, and he pointed out an issue around a directory mutex + lock and aufs addressed it. But it is still unsure whether aufs will + be merged (or any other union solution). + + + +1. Features +---------------------------------------- +- unite several directories into a single virtual filesystem. The member + directory is called as a branch. +- you can specify the permission flags to the branch, which are 'readonly', + 'readwrite' and 'whiteout-able.' +- by upper writable branch, internal copyup and whiteout, files/dirs on + readonly branch are modifiable logically. +- dynamic branch manipulation, add, del. +- etc... + +Also there are many enhancements in aufs, such as: +- test only the highest one for the directory permission (dirperm1) +- copyup on open (coo=) +- 'move' policy for copy-up between two writable branches, after + checking free space. +- xattr, acl +- readdir(3) in userspace. +- keep inode number by external inode number table +- keep the timestamps of file/dir in internal copyup operation +- seekable directory, supporting NFS readdir. +- whiteout is hardlinked in order to reduce the consumption of inodes + on branch +- do not copyup, nor create a whiteout when it is unnecessary +- revert a single systemcall when an error occurs in aufs +- remount interface instead of ioctl +- maintain /etc/mtab by an external command, /sbin/mount.aufs. +- loopback mounted filesystem as a branch +- kernel thread for removing the dir who has a plenty of whiteouts +- support copyup sparse file (a file which has a 'hole' in it) +- default permission flags for branches +- selectable permission flags for ro branch, whether whiteout can + exist or not +- export via NFS. +- support /fs/aufs and /aufs. +- support multiple writable branches, some policies to select one + among multiple writable branches. +- a new semantics for link(2) and rename(2) to support multiple + writable branches. +- no glibc changes are required. +- pseudo hardlink (hardlink over branches) +- allow a direct access manually to a file on branch, e.g. bypassing aufs. + including NFS or remote filesystem branch. +- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. +- and more... + +Currently these features are dropped temporary from aufs5. +See design/08plan.txt in detail. +- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs + (robr) +- statistics of aufs thread (/sys/fs/aufs/stat) + +Features or just an idea in the future (see also design/*.txt), +- reorder the branch index without del/re-add. +- permanent xino files for NFSD +- an option for refreshing the opened files after add/del branches +- light version, without branch manipulation. (unnecessary?) +- copyup in userspace +- inotify in userspace +- readv/writev + + +2. Download +---------------------------------------- +There are three GIT trees for aufs5, aufs5-linux.git, +aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in +"aufs-util.git." +While the aufs-util is always necessary, you need either of aufs5-linux +or aufs5-standalone. + +The aufs5-linux tree includes the whole linux mainline GIT tree, +git://git.kernel.org/.../torvalds/linux.git. +And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot +build aufs5 as an external kernel module. +Several extra patches are not included in this tree. Only +aufs5-standalone tree contains them. They are described in the later +section "Configuration and Compilation." + +On the other hand, the aufs5-standalone tree has only aufs source files +and necessary patches, and you can select CONFIG_AUFS_FS=m. +But you need to apply all aufs patches manually. + +You will find GIT branches whose name is in form of "aufs5.x" where "x" +represents the linux kernel version, "linux-5.x". For instance, +"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use +"aufs5.x-rcN" branch. + +o aufs5-linux tree +$ git clone --reference /your/linux/git/tree \ + git://github.com/sfjro/aufs5-linux.git aufs5-linux.git +- if you don't have linux GIT tree, then remove "--reference ..." +$ cd aufs5-linux.git +$ git checkout origin/aufs5.0 + +Or You may want to directly git-pull aufs into your linux GIT tree, and +leave the patch-work to GIT. +$ cd /your/linux/git/tree +$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git +$ git fetch aufs5 +$ git checkout -b my5.0 v5.0 +$ (add your local change...) +$ git pull aufs5 aufs5.0 +- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. +- you may need to solve some conflicts between your_changes and + aufs5.0. in this case, git-rerere is recommended so that you can + solve the similar conflicts automatically when you upgrade to 5.1 or + later in the future. + +o aufs5-standalone tree +$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git +$ cd aufs5-standalone.git +$ git checkout origin/aufs5.0 + +o aufs-util tree +$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git +- note that the public aufs-util.git is on SourceForge instead of + GitHUB. +$ cd aufs-util.git +$ git checkout origin/aufs5.0 + +Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. +The minor version number, 'x' in '5.x', of aufs may not always +follow the minor version number of the kernel. +Because changes in the kernel that cause the use of a new +minor version number do not always require changes to aufs-util. + +Since aufs-util has its own minor version number, you may not be +able to find a GIT branch in aufs-util for your kernel's +exact minor version number. +In this case, you should git-checkout the branch for the +nearest lower number. + +For (an unreleased) example: +If you are using "linux-5.10" and the "aufs5.10" branch +does not exist in aufs-util repository, then "aufs5.9", "aufs5.8" +or something numerically smaller is the branch for your kernel. + +Also you can view all branches by + $ git branch -a + + +3. Configuration and Compilation +---------------------------------------- +Make sure you have git-checkout'ed the correct branch. + +For aufs5-linux tree, +- enable CONFIG_AUFS_FS. +- set other aufs configurations if necessary. + +For aufs5-standalone tree, +There are several ways to build. + +1. +- apply ./aufs5-kbuild.patch to your kernel source files. +- apply ./aufs5-base.patch too. +- apply ./aufs5-mmap.patch too. +- apply ./aufs5-standalone.patch too, if you have a plan to set + CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-standalone.patch. +- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your + kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. +- enable CONFIG_AUFS_FS, you can select either + =m or =y. +- and build your kernel as usual. +- install the built kernel. +- install the header files too by "make headers_install" to the + directory where you specify. By default, it is $PWD/usr. + "make help" shows a brief note for headers_install. +- and reboot your system. + +2. +- module only (CONFIG_AUFS_FS=m). +- apply ./aufs5-base.patch to your kernel source files. +- apply ./aufs5-mmap.patch too. +- apply ./aufs5-standalone.patch too. +- build your kernel, don't forget "make headers_install", and reboot. +- edit ./config.mk and set other aufs configurations if necessary. + Note: You should read $PWD/fs/aufs/Kconfig carefully which describes + every aufs configurations. +- build the module by simple "make". +- you can specify ${KDIR} make variable which points to your kernel + source tree. +- install the files + + run "make install" to install the aufs module, or copy the built + $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). + + run "make install_headers" (instead of headers_install) to install + the modified aufs header file (you can specify DESTDIR which is + available in aufs standalone version's Makefile only), or copy + $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever + you like manually. By default, the target directory is $PWD/usr. +- no need to apply aufs5-kbuild.patch, nor copying source files to your + kernel source tree. + +Note: The header file aufs_type.h is necessary to build aufs-util + as well as "make headers_install" in the kernel source tree. + headers_install is subject to be forgotten, but it is essentially + necessary, not only for building aufs-util. + You may not meet problems without headers_install in some older + version though. + +And then, +- read README in aufs-util, build and install it +- note that your distribution may contain an obsoleted version of + aufs_type.h in /usr/include/linux or something. When you build aufs + utilities, make sure that your compiler refers the correct aufs header + file which is built by "make headers_install." +- if you want to use readdir(3) in userspace or pathconf(3) wrapper, + then run "make install_ulib" too. And refer to the aufs manual in + detail. + +There several other patches in aufs5-standalone.git. They are all +optional. When you meet some problems, they will help you. +- aufs5-loopback.patch + Supports a nested loopback mount in a branch-fs. This patch is + unnecessary until aufs produces a message like "you may want to try + another patch for loopback file". +- proc_mounts.patch + When there are many mountpoints and many mount(2)/umount(2) are + running, then /proc/mounts may not show the all mountpoints. This + patch makes /proc/mounts always show the full mountpoints list. + If you don't want to apply this patch and meet such problem, then you + need to increase the value of 'ProcMounts_Times' make-variable in + aufs-util.git as a second best solution. +- vfs-ino.patch + Modifies a system global kernel internal function get_next_ino() in + order to stop assigning 0 for an inode-number. Not directly related to + aufs, but recommended generally. +- tmpfs-idr.patch + Keeps the tmpfs inode number as the lowest value. Effective to reduce + the size of aufs XINO files for tmpfs branch. Also it prevents the + duplication of inode number, which is important for backup tools and + other utilities. When you find aufs XINO files for tmpfs branch + growing too much, try this patch. +- lockdep-debug.patch + Because aufs is not only an ordinary filesystem (callee of VFS), but + also a caller of VFS functions for branch filesystems, subclassing of + the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging + feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will + need to apply this debug patch to expand several constant values. + If you don't know what LOCKDEP is, then you don't have apply this + patch. + + +4. Usage +---------------------------------------- +At first, make sure aufs-util are installed, and please read the aufs +manual, aufs.5 in aufs-util.git tree. +$ man -l aufs.5 + +And then, +$ mkdir /tmp/rw /tmp/aufs +# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs + +Here is another example. The result is equivalent. +# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs + Or +# mount -t aufs -o br:/tmp/rw none /tmp/aufs +# mount -o remount,append:${HOME} /tmp/aufs + +Then, you can see whole tree of your home dir through /tmp/aufs. If +you modify a file under /tmp/aufs, the one on your home directory is +not affected, instead the same named file will be newly created under +/tmp/rw. And all of your modification to a file will be applied to +the one under /tmp/rw. This is called the file based Copy on Write +(COW) method. +Aufs mount options are described in aufs.5. +If you run chroot or something and make your aufs as a root directory, +then you need to customize the shutdown script. See the aufs manual in +detail. + +Additionally, there are some sample usages of aufs which are a +diskless system with network booting, and LiveCD over NFS. +See sample dir in CVS tree on SourceForge. + + +5. Contact +---------------------------------------- +When you have any problems or strange behaviour in aufs, please let me +know with: +- /proc/mounts (instead of the output of mount(8)) +- /sys/module/aufs/* +- /sys/fs/aufs/* (if you have them) +- /debug/aufs/* (if you have them) +- linux kernel version + if your kernel is not plain, for example modified by distributor, + the url where i can download its source is necessary too. +- aufs version which was printed at loading the module or booting the + system, instead of the date you downloaded. +- configuration (define/undefine CONFIG_AUFS_xxx) +- kernel configuration or /proc/config.gz (if you have it) +- LSM (linux security module, if you are using) +- behaviour which you think to be incorrect +- actual operation, reproducible one is better +- mailto: aufs-users at lists.sourceforge.net + +Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, +and Feature Requests) on SourceForge. Please join and write to +aufs-users ML. + + +6. Acknowledgements +---------------------------------------- +Thanks to everyone who have tried and are using aufs, whoever +have reported a bug or any feedback. + +Especially donators: +Tomas Matejicek(slax.org) made a donation (much more than once). + Since Apr 2010, Tomas M (the author of Slax and Linux Live + scripts) is making "doubling" donations. + Unfortunately I cannot list all of the donators, but I really + appreciate. + It ends Aug 2010, but the ordinary donation URL is still available. + +Dai Itasaka made a donation (2007/8). +Chuck Smith made a donation (2008/4, 10 and 12). +Henk Schoneveld made a donation (2008/9). +Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). +Francois Dupoux made a donation (2008/11). +Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public + aufs2 GIT tree (2009/2). +William Grant made a donation (2009/3). +Patrick Lane made a donation (2009/4). +The Mail Archive (mail-archive.com) made donations (2009/5). +Nippy Networks (Ed Wildgoose) made a donation (2009/7). +New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). +Pavel Pronskiy made a donation (2011/2). +Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy + Networks (Ed Wildgoose) made a donation for hardware (2011/3). +Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and +11). +Sam Liddicott made a donation (2011/9). +Era Scarecrow made a donation (2013/4). +Bor Ratajc made a donation (2013/4). +Alessandro Gorreta made a donation (2013/4). +POIRETTE Marc made a donation (2013/4). +Alessandro Gorreta made a donation (2013/4). +lauri kasvandik made a donation (2013/5). +"pemasu from Finland" made a donation (2013/7). +The Parted Magic Project made a donation (2013/9 and 11). +Pavel Barta made a donation (2013/10). +Nikolay Pertsev made a donation (2014/5). +James B made a donation (2014/7 and 2015/7). +Stefano Di Biase made a donation (2014/8). +Daniel Epellei made a donation (2015/1). +OmegaPhil made a donation (2016/1, 2018/4). +Tomasz Szewczyk made a donation (2016/4). +James Burry made a donation (2016/12). +Carsten Rose made a donation (2018/9). +Porteus Kiosk made a donation (2018/10). + +Thank you very much. +Donations are always, including future donations, very important and +helpful for me to keep on developing aufs. + + +7. +---------------------------------------- +If you are an experienced user, no explanation is needed. Aufs is +just a linux filesystem. + + +Enjoy! + +# Local variables: ; +# mode: text; +# End: ; diff --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt new file mode 100644 index 000000000000..609bf0e9b93a --- /dev/null +++ b/Documentation/filesystems/aufs/design/01intro.txt @@ -0,0 +1,171 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Introduction +---------------------------------------- + +aufs [ei ju: ef es] | /ey-yoo-ef-es/ | [a u f s] +1. abbrev. for "advanced multi-layered unification filesystem". +2. abbrev. for "another unionfs". +3. abbrev. for "auf das" in German which means "on the" in English. + Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). + But "Filesystem aufs Filesystem" is hard to understand. +4. abbrev. for "African Urban Fashion Show". + +AUFS is a filesystem with features: +- multi layered stackable unification filesystem, the member directory + is called as a branch. +- branch permission and attribute, 'readonly', 'real-readonly', + 'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their + combination. +- internal "file copy-on-write". +- logical deletion, whiteout. +- dynamic branch manipulation, adding, deleting and changing permission. +- allow bypassing aufs, user's direct branch access. +- external inode number translation table and bitmap which maintains the + persistent aufs inode number. +- seekable directory, including NFS readdir. +- file mapping, mmap and sharing pages. +- pseudo-link, hardlink over branches. +- loopback mounted filesystem as a branch. +- several policies to select one among multiple writable branches. +- revert a single systemcall when an error occurs in aufs. +- and more... + + +Multi Layered Stackable Unification Filesystem +---------------------------------------------------------------------- +Most people already knows what it is. +It is a filesystem which unifies several directories and provides a +merged single directory. When users access a file, the access will be +passed/re-directed/converted (sorry, I am not sure which English word is +correct) to the real file on the member filesystem. The member +filesystem is called 'lower filesystem' or 'branch' and has a mode +'readonly' and 'readwrite.' And the deletion for a file on the lower +readonly branch is handled by creating 'whiteout' on the upper writable +branch. + +On LKML, there have been discussions about UnionMount (Jan Blunck, +Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took +different approaches to implement the merged-view. +The former tries putting it into VFS, and the latter implements as a +separate filesystem. +(If I misunderstand about these implementations, please let me know and +I shall correct it. Because it is a long time ago when I read their +source files last time). + +UnionMount's approach will be able to small, but may be hard to share +branches between several UnionMount since the whiteout in it is +implemented in the inode on branch filesystem and always +shared. According to Bharata's post, readdir does not seems to be +finished yet. +There are several missing features known in this implementations such as +- for users, the inode number may change silently. eg. copy-up. +- link(2) may break by copy-up. +- read(2) may get an obsoleted filedata (fstat(2) too). +- fcntl(F_SETLK) may be broken by copy-up. +- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after + open(O_RDWR). + +In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was +merged into mainline. This is another implementation of UnionMount as a +separated filesystem. All the limitations and known problems which +UnionMount are equally inherited to "overlay" filesystem. + +Unionfs has a longer history. When I started implementing a stackable +filesystem (Aug 2005), it already existed. It has virtual super_block, +inode, dentry and file objects and they have an array pointing lower +same kind objects. After contributing many patches for Unionfs, I +re-started my project AUFS (Jun 2006). + +In AUFS, the structure of filesystem resembles to Unionfs, but I +implemented my own ideas, approaches and enhancements and it became +totally different one. + +Comparing DM snapshot and fs based implementation +- the number of bytes to be copied between devices is much smaller. +- the type of filesystem must be one and only. +- the fs must be writable, no readonly fs, even for the lower original + device. so the compression fs will not be usable. but if we use + loopback mount, we may address this issue. + for instance, + mount /cdrom/squashfs.img /sq + losetup /sq/ext2.img + losetup /somewhere/cow + dmsetup "snapshot /dev/loop0 /dev/loop1 ..." +- it will be difficult (or needs more operations) to extract the + difference between the original device and COW. +- DM snapshot-merge may help a lot when users try merging. in the + fs-layer union, users will use rsync(1). + +You may want to read my old paper "Filesystems in LiveCD" +(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). + + +Several characters/aspects/persona of aufs +---------------------------------------------------------------------- + +Aufs has several characters, aspects or persona. +1. a filesystem, callee of VFS helper +2. sub-VFS, caller of VFS helper for branches +3. a virtual filesystem which maintains persistent inode number +4. reader/writer of files on branches such like an application + +1. Callee of VFS Helper +As an ordinary linux filesystem, aufs is a callee of VFS. For instance, +unlink(2) from an application reaches sys_unlink() kernel function and +then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it +calls filesystem specific unlink operation. Actually aufs implements the +unlink operation but it behaves like a redirector. + +2. Caller of VFS Helper for Branches +aufs_unlink() passes the unlink request to the branch filesystem as if +it were called from VFS. So the called unlink operation of the branch +filesystem acts as usual. As a caller of VFS helper, aufs should handle +every necessary pre/post operation for the branch filesystem. +- acquire the lock for the parent dir on a branch +- lookup in a branch +- revalidate dentry on a branch +- mnt_want_write() for a branch +- vfs_unlink() for a branch +- mnt_drop_write() for a branch +- release the lock on a branch + +3. Persistent Inode Number +One of the most important issue for a filesystem is to maintain inode +numbers. This is particularly important to support exporting a +filesystem via NFS. Aufs is a virtual filesystem which doesn't have a +backend block device for its own. But some storage is necessary to +keep and maintain the inode numbers. It may be a large space and may not +suit to keep in memory. Aufs rents some space from its first writable +branch filesystem (by default) and creates file(s) on it. These files +are created by aufs internally and removed soon (currently) keeping +opened. +Note: Because these files are removed, they are totally gone after + unmounting aufs. It means the inode numbers are not persistent + across unmount or reboot. I have a plan to make them really + persistent which will be important for aufs on NFS server. + +4. Read/Write Files Internally (copy-on-write) +Because a branch can be readonly, when you write a file on it, aufs will +"copy-up" it to the upper writable branch internally. And then write the +originally requested thing to the file. Generally kernel doesn't +open/read/write file actively. In aufs, even a single write may cause a +internal "file copy". This behaviour is very similar to cp(1) command. + +Some people may think it is better to pass such work to user space +helper, instead of doing in kernel space. Actually I am still thinking +about it. But currently I have implemented it in kernel space. diff --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt new file mode 100644 index 000000000000..2467788c7f10 --- /dev/null +++ b/Documentation/filesystems/aufs/design/02struct.txt @@ -0,0 +1,258 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Basic Aufs Internal Structure + +Superblock/Inode/Dentry/File Objects +---------------------------------------------------------------------- +As like an ordinary filesystem, aufs has its own +superblock/inode/dentry/file objects. All these objects have a +dynamically allocated array and store the same kind of pointers to the +lower filesystem, branch. +For example, when you build a union with one readwrite branch and one +readonly, mounted /au, /rw and /ro respectively. +- /au = /rw + /ro +- /ro/fileA exists but /rw/fileA + +Aufs lookup operation finds /ro/fileA and gets dentry for that. These +pointers are stored in a aufs dentry. The array in aufs dentry will be, +- [0] = NULL (because /rw/fileA doesn't exist) +- [1] = /ro/fileA + +This style of an array is essentially same to the aufs +superblock/inode/dentry/file objects. + +Because aufs supports manipulating branches, ie. add/delete/change +branches dynamically, these objects has its own generation. When +branches are changed, the generation in aufs superblock is +incremented. And a generation in other object are compared when it is +accessed. When a generation in other objects are obsoleted, aufs +refreshes the internal array. + + +Superblock +---------------------------------------------------------------------- +Additionally aufs superblock has some data for policies to select one +among multiple writable branches, XIB files, pseudo-links and kobject. +See below in detail. +About the policies which supports copy-down a directory, see +wbr_policy.txt too. + + +Branch and XINO(External Inode Number Translation Table) +---------------------------------------------------------------------- +Every branch has its own xino (external inode number translation table) +file. The xino file is created and unlinked by aufs internally. When two +members of a union exist on the same filesystem, they share the single +xino file. +The struct of a xino file is simple, just a sequence of aufs inode +numbers which is indexed by the lower inode number. +In the above sample, assume the inode number of /ro/fileA is i111 and +aufs assigns the inode number i999 for fileA. Then aufs writes 999 as +4(8) bytes at 111 * 4(8) bytes offset in the xino file. + +When the inode numbers are not contiguous, the xino file will be sparse +which has a hole in it and doesn't consume as much disk space as it +might appear. If your branch filesystem consumes disk space for such +holes, then you should specify 'xino=' option at mounting aufs. + +Aufs has a mount option to free the disk blocks for such holes in XINO +files on tmpfs or ramdisk. But it is not so effective actually. If you +meet a problem of disk shortage due to XINO files, then you should try +"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. +The patch localizes the assignment inumbers per tmpfs-mount and avoid +the holes in XINO files. + +Also a writable branch has three kinds of "whiteout bases". All these +are existed when the branch is joined to aufs, and their names are +whiteout-ed doubly, so that users will never see their names in aufs +hierarchy. +1. a regular file which will be hardlinked to all whiteouts. +2. a directory to store a pseudo-link. +3. a directory to store an "orphan"-ed file temporary. + +1. Whiteout Base + When you remove a file on a readonly branch, aufs handles it as a + logical deletion and creates a whiteout on the upper writable branch + as a hardlink of this file in order not to consume inode on the + writable branch. +2. Pseudo-link Dir + See below, Pseudo-link. +3. Step-Parent Dir + When "fileC" exists on the lower readonly branch only and it is + opened and removed with its parent dir, and then user writes + something into it, then aufs copies-up fileC to this + directory. Because there is no other dir to store fileC. After + creating a file under this dir, the file is unlinked. + +Because aufs supports manipulating branches, ie. add/delete/change +dynamically, a branch has its own id. When the branch order changes, +aufs finds the new index by searching the branch id. + + +Pseudo-link +---------------------------------------------------------------------- +Assume "fileA" exists on the lower readonly branch only and it is +hardlinked to "fileB" on the branch. When you write something to fileA, +aufs copies-up it to the upper writable branch. Additionally aufs +creates a hardlink under the Pseudo-link Directory of the writable +branch. The inode of a pseudo-link is kept in aufs super_block as a +simple list. If fileB is read after unlinking fileA, aufs returns +filedata from the pseudo-link instead of the lower readonly +branch. Because the pseudo-link is based upon the inode, to keep the +inode number by xino (see above) is essentially necessary. + +All the hardlinks under the Pseudo-link Directory of the writable branch +should be restored in a proper location later. Aufs provides a utility +to do this. The userspace helpers executed at remounting and unmounting +aufs by default. +During this utility is running, it puts aufs into the pseudo-link +maintenance mode. In this mode, only the process which began the +maintenance mode (and its child processes) is allowed to operate in +aufs. Some other processes which are not related to the pseudo-link will +be allowed to run too, but the rest have to return an error or wait +until the maintenance mode ends. If a process already acquires an inode +mutex (in VFS), it has to return an error. + + +XIB(external inode number bitmap) +---------------------------------------------------------------------- +Addition to the xino file per a branch, aufs has an external inode number +bitmap in a superblock object. It is also an internal file such like a +xino file. +It is a simple bitmap to mark whether the aufs inode number is in-use or +not. +To reduce the file I/O, aufs prepares a single memory page to cache xib. + +As well as XINO files, aufs has a feature to truncate/refresh XIB to +reduce the number of consumed disk blocks for these files. + + +Virtual or Vertical Dir, and Readdir in Userspace +---------------------------------------------------------------------- +In order to support multiple layers (branches), aufs readdir operation +constructs a virtual dir block on memory. For readdir, aufs calls +vfs_readdir() internally for each dir on branches, merges their entries +with eliminating the whiteout-ed ones, and sets it to file (dir) +object. So the file object has its entry list until it is closed. The +entry list will be updated when the file position is zero and becomes +obsoleted. This decision is made in aufs automatically. + +The dynamically allocated memory block for the name of entries has a +unit of 512 bytes (by default) and stores the names contiguously (no +padding). Another block for each entry is handled by kmem_cache too. +During building dir blocks, aufs creates hash list and judging whether +the entry is whiteouted by its upper branch or already listed. +The merged result is cached in the corresponding inode object and +maintained by a customizable life-time option. + +Some people may call it can be a security hole or invite DoS attack +since the opened and once readdir-ed dir (file object) holds its entry +list and becomes a pressure for system memory. But I'd say it is similar +to files under /proc or /sys. The virtual files in them also holds a +memory page (generally) while they are opened. When an idea to reduce +memory for them is introduced, it will be applied to aufs too. +For those who really hate this situation, I've developed readdir(3) +library which operates this merging in userspace. You just need to set +LD_PRELOAD environment variable, and aufs will not consume no memory in +kernel space for readdir(3). + + +Workqueue +---------------------------------------------------------------------- +Aufs sometimes requires privilege access to a branch. For instance, +in copy-up/down operation. When a user process is going to make changes +to a file which exists in the lower readonly branch only, and the mode +of one of ancestor directories may not be writable by a user +process. Here aufs copy-up the file with its ancestors and they may +require privilege to set its owner/group/mode/etc. +This is a typical case of a application character of aufs (see +Introduction). + +Aufs uses workqueue synchronously for this case. It creates its own +workqueue. The workqueue is a kernel thread and has privilege. Aufs +passes the request to call mkdir or write (for example), and wait for +its completion. This approach solves a problem of a signal handler +simply. +If aufs didn't adopt the workqueue and changed the privilege of the +process, then the process may receive the unexpected SIGXFSZ or other +signals. + +Also aufs uses the system global workqueue ("events" kernel thread) too +for asynchronous tasks, such like handling inotify/fsnotify, re-creating a +whiteout base and etc. This is unrelated to a privilege. +Most of aufs operation tries acquiring a rw_semaphore for aufs +superblock at the beginning, at the same time waits for the completion +of all queued asynchronous tasks. + + +Whiteout +---------------------------------------------------------------------- +The whiteout in aufs is very similar to Unionfs's. That is represented +by its filename. UnionMount takes an approach of a file mode, but I am +afraid several utilities (find(1) or something) will have to support it. + +Basically the whiteout represents "logical deletion" which stops aufs to +lookup further, but also it represents "dir is opaque" which also stop +further lookup. + +In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. +In order to make several functions in a single systemcall to be +revertible, aufs adopts an approach to rename a directory to a temporary +unique whiteouted name. +For example, in rename(2) dir where the target dir already existed, aufs +renames the target dir to a temporary unique whiteouted name before the +actual rename on a branch, and then handles other actions (make it opaque, +update the attributes, etc). If an error happens in these actions, aufs +simply renames the whiteouted name back and returns an error. If all are +succeeded, aufs registers a function to remove the whiteouted unique +temporary name completely and asynchronously to the system global +workqueue. + + +Copy-up +---------------------------------------------------------------------- +It is a well-known feature or concept. +When user modifies a file on a readonly branch, aufs operate "copy-up" +internally and makes change to the new file on the upper writable branch. +When the trigger systemcall does not update the timestamps of the parent +dir, aufs reverts it after copy-up. + + +Move-down (aufs3.9 and later) +---------------------------------------------------------------------- +"Copy-up" is one of the essential feature in aufs. It copies a file from +the lower readonly branch to the upper writable branch when a user +changes something about the file. +"Move-down" is an opposite action of copy-up. Basically this action is +ran manually instead of automatically and internally. +For desgin and implementation, aufs has to consider these issues. +- whiteout for the file may exist on the lower branch. +- ancestor directories may not exist on the lower branch. +- diropq for the ancestor directories may exist on the upper branch. +- free space on the lower branch will reduce. +- another access to the file may happen during moving-down, including + UDBA (see "Revalidate Dentry and UDBA"). +- the file should not be hard-linked nor pseudo-linked. they should be + handled by auplink utility later. + +Sometimes users want to move-down a file from the upper writable branch +to the lower readonly or writable branch. For instance, +- the free space of the upper writable branch is going to run out. +- create a new intermediate branch between the upper and lower branch. +- etc. + +For this purpose, use "aumvdown" command in aufs-util.git. diff --git a/Documentation/filesystems/aufs/design/03atomic_open.txt b/Documentation/filesystems/aufs/design/03atomic_open.txt new file mode 100644 index 000000000000..9f16ac1e0173 --- /dev/null +++ b/Documentation/filesystems/aufs/design/03atomic_open.txt @@ -0,0 +1,85 @@ + +# Copyright (C) 2015-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Support for a branch who has its ->atomic_open() +---------------------------------------------------------------------- +The filesystems who implement its ->atomic_open() are not majority. For +example NFSv4 does, and aufs should call NFSv4 ->atomic_open, +particularly for open(O_CREAT|O_EXCL, 0400) case. Other than +->atomic_open(), NFSv4 returns an error for this open(2). While I am not +sure whether all filesystems who have ->atomic_open() behave like this, +but NFSv4 surely returns the error. + +In order to support ->atomic_open() for aufs, there are a few +approaches. + +A. Introduce aufs_atomic_open() + - calls one of VFS:do_last(), lookup_open() or atomic_open() for + branch fs. +B. Introduce aufs_atomic_open() calling create, open and chmod. this is + an aufs user Pip Cet's approach + - calls aufs_create(), VFS finish_open() and notify_change(). + - pass fake-mode to finish_open(), and then correct the mode by + notify_change(). +C. Extend aufs_open() to call branch fs's ->atomic_open() + - no aufs_atomic_open(). + - aufs_lookup() registers the TID to an aufs internal object. + - aufs_create() does nothing when the matching TID is registered, but + registers the mode. + - aufs_open() calls branch fs's ->atomic_open() when the matching + TID is registered. +D. Extend aufs_open() to re-try branch fs's ->open() with superuser's + credential + - no aufs_atomic_open(). + - aufs_create() registers the TID to an internal object. this info + represents "this process created this file just now." + - when aufs gets EACCES from branch fs's ->open(), then confirm the + registered TID and re-try open() with superuser's credential. + +Pros and cons for each approach. + +A. + - straightforward but highly depends upon VFS internal. + - the atomic behavaiour is kept. + - some of parameters such as nameidata are hard to reproduce for + branch fs. + - large overhead. +B. + - easy to implement. + - the atomic behavaiour is lost. +C. + - the atomic behavaiour is kept. + - dirty and tricky. + - VFS checks whether the file is created correctly after calling + ->create(), which means this approach doesn't work. +D. + - easy to implement. + - the atomic behavaiour is lost. + - to open a file with superuser's credential and give it to a user + process is a bad idea, since the file object keeps the credential + in it. It may affect LSM or something. This approach doesn't work + either. + +The approach A is ideal, but it hard to implement. So here is a +variation of A, which is to be implemented. + +A-1. Introduce aufs_atomic_open() + - calls branch fs ->atomic_open() if exists. otherwise calls + vfs_create() and finish_open(). + - the demerit is that the several checks after branch fs + ->atomic_open() are lost. in the ordinary case, the checks are + done by VFS:do_last(), lookup_open() and atomic_open(). some can + be implemented in aufs, but not all I am afraid. diff --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt new file mode 100644 index 000000000000..08b443d94dfa --- /dev/null +++ b/Documentation/filesystems/aufs/design/03lookup.txt @@ -0,0 +1,113 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Lookup in a Branch +---------------------------------------------------------------------- +Since aufs has a character of sub-VFS (see Introduction), it operates +lookup for branches as VFS does. It may be a heavy work. But almost all +lookup operation in aufs is the simplest case, ie. lookup only an entry +directly connected to its parent. Digging down the directory hierarchy +is unnecessary. VFS has a function lookup_one_len() for that use, and +aufs calls it. + +When a branch is a remote filesystem, aufs basically relies upon its +->d_revalidate(), also aufs forces the hardest revalidate tests for +them. +For d_revalidate, aufs implements three levels of revalidate tests. See +"Revalidate Dentry and UDBA" in detail. + + +Test Only the Highest One for the Directory Permission (dirperm1 option) +---------------------------------------------------------------------- +Let's try case study. +- aufs has two branches, upper readwrite and lower readonly. + /au = /rw + /ro +- "dirA" exists under /ro, but /rw. and its mode is 0700. +- user invoked "chmod a+rx /au/dirA" +- the internal copy-up is activated and "/rw/dirA" is created and its + permission bits are set to world readable. +- then "/au/dirA" becomes world readable? + +In this case, /ro/dirA is still 0700 since it exists in readonly branch, +or it may be a natively readonly filesystem. If aufs respects the lower +branch, it should not respond readdir request from other users. But user +allowed it by chmod. Should really aufs rejects showing the entries +under /ro/dirA? + +To be honest, I don't have a good solution for this case. So aufs +implements 'dirperm1' and 'nodirperm1' mount options, and leave it to +users. +When dirperm1 is specified, aufs checks only the highest one for the +directory permission, and shows the entries. Otherwise, as usual, checks +every dir existing on all branches and rejects the request. + +As a side effect, dirperm1 option improves the performance of aufs +because the number of permission check is reduced when the number of +branch is many. + + +Revalidate Dentry and UDBA (User's Direct Branch Access) +---------------------------------------------------------------------- +Generally VFS helpers re-validate a dentry as a part of lookup. +0. digging down the directory hierarchy. +1. lock the parent dir by its i_mutex. +2. lookup the final (child) entry. +3. revalidate it. +4. call the actual operation (create, unlink, etc.) +5. unlock the parent dir + +If the filesystem implements its ->d_revalidate() (step 3), then it is +called. Actually aufs implements it and checks the dentry on a branch is +still valid. +But it is not enough. Because aufs has to release the lock for the +parent dir on a branch at the end of ->lookup() (step 2) and +->d_revalidate() (step 3) while the i_mutex of the aufs dir is still +held by VFS. +If the file on a branch is changed directly, eg. bypassing aufs, after +aufs released the lock, then the subsequent operation may cause +something unpleasant result. + +This situation is a result of VFS architecture, ->lookup() and +->d_revalidate() is separated. But I never say it is wrong. It is a good +design from VFS's point of view. It is just not suitable for sub-VFS +character in aufs. + +Aufs supports such case by three level of revalidation which is +selectable by user. +1. Simple Revalidate + Addition to the native flow in VFS's, confirm the child-parent + relationship on the branch just after locking the parent dir on the + branch in the "actual operation" (step 4). When this validation + fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still + checks the validation of the dentry on branches. +2. Monitor Changes Internally by Inotify/Fsnotify + Addition to above, in the "actual operation" (step 4) aufs re-lookup + the dentry on the branch, and returns EBUSY if it finds different + dentry. + Additionally, aufs sets the inotify/fsnotify watch for every dir on branches + during it is in cache. When the event is notified, aufs registers a + function to kernel 'events' thread by schedule_work(). And the + function sets some special status to the cached aufs dentry and inode + private data. If they are not cached, then aufs has nothing to + do. When the same file is accessed through aufs (step 0-3) later, + aufs will detect the status and refresh all necessary data. + In this mode, aufs has to ignore the event which is fired by aufs + itself. +3. No Extra Validation + This is the simplest test and doesn't add any additional revalidation + test, and skip the revalidation in step 4. It is useful and improves + aufs performance when system surely hide the aufs branches from user, + by over-mounting something (or another method). diff --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt new file mode 100644 index 000000000000..3ab3682a42b4 --- /dev/null +++ b/Documentation/filesystems/aufs/design/04branch.txt @@ -0,0 +1,74 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Branch Manipulation + +Since aufs supports dynamic branch manipulation, ie. add/remove a branch +and changing its permission/attribute, there are a lot of works to do. + + +Add a Branch +---------------------------------------------------------------------- +o Confirm the adding dir exists outside of aufs, including loopback + mount, and its various attributes. +o Initialize the xino file and whiteout bases if necessary. + See struct.txt. + +o Check the owner/group/mode of the directory + When the owner/group/mode of the adding directory differs from the + existing branch, aufs issues a warning because it may impose a + security risk. + For example, when a upper writable branch has a world writable empty + top directory, a malicious user can create any files on the writable + branch directly, like copy-up and modify manually. If something like + /etc/{passwd,shadow} exists on the lower readonly branch but the upper + writable branch, and the writable branch is world-writable, then a + malicious guy may create /etc/passwd on the writable branch directly + and the infected file will be valid in aufs. + I am afraid it can be a security issue, but aufs can do nothing except + producing a warning. + + +Delete a Branch +---------------------------------------------------------------------- +o Confirm the deleting branch is not busy + To be general, there is one merit to adopt "remount" interface to + manipulate branches. It is to discard caches. At deleting a branch, + aufs checks the still cached (and connected) dentries and inodes. If + there are any, then they are all in-use. An inode without its + corresponding dentry can be alive alone (for example, inotify/fsnotify case). + + For the cached one, aufs checks whether the same named entry exists on + other branches. + If the cached one is a directory, because aufs provides a merged view + to users, as long as one dir is left on any branch aufs can show the + dir to users. In this case, the branch can be removed from aufs. + Otherwise aufs rejects deleting the branch. + + If any file on the deleting branch is opened by aufs, then aufs + rejects deleting. + + +Modify the Permission of a Branch +---------------------------------------------------------------------- +o Re-initialize or remove the xino file and whiteout bases if necessary. + See struct.txt. + +o rw --> ro: Confirm the modifying branch is not busy + Aufs rejects the request if any of these conditions are true. + - a file on the branch is mmap-ed. + - a regular file on the branch is opened for write and there is no + same named entry on the upper branch. diff --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt new file mode 100644 index 000000000000..1f9b86bc6a3e --- /dev/null +++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt @@ -0,0 +1,64 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Policies to Select One among Multiple Writable Branches +---------------------------------------------------------------------- +When the number of writable branch is more than one, aufs has to decide +the target branch for file creation or copy-up. By default, the highest +writable branch which has the parent (or ancestor) dir of the target +file is chosen (top-down-parent policy). +By user's request, aufs implements some other policies to select the +writable branch, for file creation several policies, round-robin, +most-free-space, and other policies. For copy-up, top-down-parent, +bottom-up-parent, bottom-up and others. + +As expected, the round-robin policy selects the branch in circular. When +you have two writable branches and creates 10 new files, 5 files will be +created for each branch. mkdir(2) systemcall is an exception. When you +create 10 new directories, all will be created on the same branch. +And the most-free-space policy selects the one which has most free +space among the writable branches. The amount of free space will be +checked by aufs internally, and users can specify its time interval. + +The policies for copy-up is more simple, +top-down-parent is equivalent to the same named on in create policy, +bottom-up-parent selects the writable branch where the parent dir +exists and the nearest upper one from the copyup-source, +bottom-up selects the nearest upper writable branch from the +copyup-source, regardless the existence of the parent dir. + +There are some rules or exceptions to apply these policies. +- If there is a readonly branch above the policy-selected branch and + the parent dir is marked as opaque (a variation of whiteout), or the + target (creating) file is whiteout-ed on the upper readonly branch, + then the result of the policy is ignored and the target file will be + created on the nearest upper writable branch than the readonly branch. +- If there is a writable branch above the policy-selected branch and + the parent dir is marked as opaque or the target file is whiteouted + on the branch, then the result of the policy is ignored and the target + file will be created on the highest one among the upper writable + branches who has diropq or whiteout. In case of whiteout, aufs removes + it as usual. +- link(2) and rename(2) systemcalls are exceptions in every policy. + They try selecting the branch where the source exists as possible + since copyup a large file will take long time. If it can't be, + ie. the branch where the source exists is readonly, then they will + follow the copyup policy. +- There is an exception for rename(2) when the target exists. + If the rename target exists, aufs compares the index of the branches + where the source and the target exists and selects the higher + one. If the selected branch is readonly, then aufs follows the + copyup policy. diff --git a/Documentation/filesystems/aufs/design/06dirren.dot b/Documentation/filesystems/aufs/design/06dirren.dot new file mode 100644 index 000000000000..2d62bb6dd55f --- /dev/null +++ b/Documentation/filesystems/aufs/design/06dirren.dot @@ -0,0 +1,31 @@ + +// to view this graph, run dot(1) command in GRAPHVIZ. + +digraph G { +node [shape=box]; +whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"]; + +node [shape=oval]; + +aufs_rename -> whinfo [label="store/remove"]; + +node [shape=oval]; +inode_list [label="h_inum list in branch\ncache"]; + +node [shape=box]; +whinode [label="h_inum list file"]; + +node [shape=oval]; +brmgmt [label="br_add/del/mod/umount"]; + +brmgmt -> inode_list [label="create/remove"]; +brmgmt -> whinode [label="load/store"]; + +inode_list -> whinode [style=dashed,dir=both]; + +aufs_rename -> inode_list [label="add/del"]; + +aufs_lookup -> inode_list [label="search"]; + +aufs_lookup -> whinfo [label="load/remove"]; +} diff --git a/Documentation/filesystems/aufs/design/06dirren.txt b/Documentation/filesystems/aufs/design/06dirren.txt new file mode 100644 index 000000000000..3b80f8659b3e --- /dev/null +++ b/Documentation/filesystems/aufs/design/06dirren.txt @@ -0,0 +1,102 @@ + +# Copyright (C) 2017-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Special handling for renaming a directory (DIRREN) +---------------------------------------------------------------------- +First, let's assume we have a simple usecase. + +- /u = /rw + /ro +- /rw/dirA exists +- /ro/dirA and /ro/dirA/file exist too +- there is no dirB on both branches +- a user issues rename("dirA", "dirB") + +Now, what should aufs behave against this rename(2)? +There are a few possible cases. + +A. returns EROFS. + since dirA exists on a readonly branch which cannot be renamed. +B. returns EXDEV. + it is possible to copy-up dirA (only the dir itself), but the child + entries ("file" in this case) should not be. it must be a bad + approach to copy-up recursively. +C. returns a success. + even the branch /ro is readonly, aufs tries renaming it. Obviously it + is a violation of aufs' policy. +D. construct an extra information which indicates that /ro/dirA should + be handled as the name of dirB. + overlayfs has a similar feature called REDIRECT. + +Until now, aufs implements the case B only which returns EXDEV, and +expects the userspace application behaves like mv(1) which tries +issueing rename(2) recursively. + +A new aufs feature called DIRREN is introduced which implements the case +D. There are several "extra information" added. + +1. detailed info per renamed directory + path: /rw/dirB/$AUFS_WH_DR_INFO_PFX. +2. the inode-number list of directories on a branch + path: /rw/dirB/$AUFS_WH_DR_BRHINO + +The filename of "detailed info per directory" represents the lower +branch, and its format is +- a type of the branch id + one of these. + + uuid (not implemented yet) + + fsid + + dev +- the inode-number of the branch root dir + +And it contains these info in a single regular file. +- magic number +- branch's inode-number of the logically renamed dir +- the name of the before-renamed dir + +The "detailed info per directory" file is created in aufs rename(2), and +loaded in any lookup. +The info is considered in lookup for the matching case only. Here +"matching" means that the root of branch (in the info filename) is same +to the current looking-up branch. After looking-up the before-renamed +name, the inode-number is compared. And the matched dentry is used. + +The "inode-number list of directories" is a regular file which contains +simply the inode-numbers on the branch. The file is created or updated +in removing the branch, and loaded in adding the branch. Its lifetime is +equal to the branch. +The list is refered in lookup, and when the current target inode is +found in the list, the aufs tries loading the "detailed info per +directory" and get the changed and valid name of the dir. + +Theoretically these "extra informaiton" may be able to be put into XATTR +in the dir inode. But aufs doesn't choose this way because +1. XATTR may not be supported by the branch (or its configuration) +2. XATTR may have its size limit. +3. XATTR may be less easy to convert than a regular file, when the + format of the info is changed in the future. +At the same time, I agree that the regular file approach is much slower +than XATTR approach. So, in the future, aufs may take the XATTR or other +better approach. + +This DIRREN feature is enabled by aufs configuration, and is activated +by a new mount option. + +For the more complicated case, there is a work with UDBA option, which +is to dected the direct access to the branches (by-passing aufs) and to +maintain the cashes in aufs. Since a single cached aufs dentry may +contains two names, before- and after-rename, the name comparision in +UDBA handler may not work correctly. In this case, the behaviour will be +equivalen to udba=reval case. diff --git a/Documentation/filesystems/aufs/design/06fhsm.txt b/Documentation/filesystems/aufs/design/06fhsm.txt new file mode 100644 index 000000000000..8b498d0af812 --- /dev/null +++ b/Documentation/filesystems/aufs/design/06fhsm.txt @@ -0,0 +1,120 @@ + +# Copyright (C) 2011-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +File-based Hierarchical Storage Management (FHSM) +---------------------------------------------------------------------- +Hierarchical Storage Management (or HSM) is a well-known feature in the +storage world. Aufs provides this feature as file-based with multiple +writable branches, based upon the principle of "Colder, the Lower". +Here the word "colder" means that the less used files, and "lower" means +that the position in the order of the stacked branches vertically. +These multiple writable branches are prioritized, ie. the topmost one +should be the fastest drive and be used heavily. + +o Characters in aufs FHSM story +- aufs itself and a new branch attribute. +- a new ioctl interface to move-down and to establish a connection with + the daemon ("move-down" is a converse of "copy-up"). +- userspace tool and daemon. + +The userspace daemon establishes a connection with aufs and waits for +the notification. The notified information is very similar to struct +statfs containing the number of consumed blocks and inodes. +When the consumed blocks/inodes of a branch exceeds the user-specified +upper watermark, the daemon activates its move-down process until the +consumed blocks/inodes reaches the user-specified lower watermark. + +The actual move-down is done by aufs based upon the request from +user-space since we need to maintain the inode number and the internal +pointer arrays in aufs. + +Currently aufs FHSM handles the regular files only. Additionally they +must not be hard-linked nor pseudo-linked. + + +o Cowork of aufs and the user-space daemon + During the userspace daemon established the connection, aufs sends a + small notification to it whenever aufs writes something into the + writable branch. But it may cost high since aufs issues statfs(2) + internally. So user can specify a new option to cache the + info. Actually the notification is controlled by these factors. + + the specified cache time. + + classified as "force" by aufs internally. + Until the specified time expires, aufs doesn't send the info + except the forced cases. When aufs decide forcing, the info is always + notified to userspace. + For example, the number of free inodes is generally large enough and + the shortage of it happens rarely. So aufs doesn't force the + notification when creating a new file, directory and others. This is + the typical case which aufs doesn't force. + When aufs writes the actual filedata and the files consumes any of new + blocks, the aufs forces notifying. + + +o Interfaces in aufs +- New branch attribute. + + fhsm + Specifies that the branch is managed by FHSM feature. In other word, + participant in the FHSM. + When nofhsm is set to the branch, it will not be the source/target + branch of the move-down operation. This attribute is set + independently from coo and moo attributes, and if you want full + FHSM, you should specify them as well. +- New mount option. + + fhsm_sec + Specifies a second to suppress many less important info to be + notified. +- New ioctl. + + AUFS_CTL_FHSM_FD + create a new file descriptor which userspace can read the notification + (a subset of struct statfs) from aufs. +- Module parameter 'brs' + It has to be set to 1. Otherwise the new mount option 'fhsm' will not + be set. +- mount helpers /sbin/mount.aufs and /sbin/umount.aufs + When there are two or more branches with fhsm attributes, + /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs + terminates it. As a result of remounting and branch-manipulation, the + number of branches with fhsm attribute can be one. In this case, + /sbin/mount.aufs will terminate the user-space daemon. + + +Finally the operation is done as these steps in kernel-space. +- make sure that, + + no one else is using the file. + + the file is not hard-linked. + + the file is not pseudo-linked. + + the file is a regular file. + + the parent dir is not opaqued. +- find the target writable branch. +- make sure the file is not whiteout-ed by the upper (than the target) + branch. +- make the parent dir on the target branch. +- mutex lock the inode on the branch. +- unlink the whiteout on the target branch (if exists). +- lookup and create the whiteout-ed temporary name on the target branch. +- copy the file as the whiteout-ed temporary name on the target branch. +- rename the whiteout-ed temporary name to the original name. +- unlink the file on the source branch. +- maintain the internal pointer array and the external inode number + table (XINO). +- maintain the timestamps and other attributes of the parent dir and the + file. + +And of course, in every step, an error may happen. So the operation +should restore the original file state after an error happens. diff --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt new file mode 100644 index 000000000000..cdd84ea777fc --- /dev/null +++ b/Documentation/filesystems/aufs/design/06mmap.txt @@ -0,0 +1,72 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +mmap(2) -- File Memory Mapping +---------------------------------------------------------------------- +In aufs, the file-mapped pages are handled by a branch fs directly, no +interaction with aufs. It means aufs_mmap() calls the branch fs's +->mmap(). +This approach is simple and good, but there is one problem. +Under /proc, several entries show the mmapped files by its path (with +device and inode number), and the printed path will be the path on the +branch fs's instead of virtual aufs's. +This is not a problem in most cases, but some utilities lsof(1) (and its +user) may expect the path on aufs. + +To address this issue, aufs adds a new member called vm_prfile in struct +vm_area_struct (and struct vm_region). The original vm_file points to +the file on the branch fs in order to handle everything correctly as +usual. The new vm_prfile points to a virtual file in aufs, and the +show-functions in procfs refers to vm_prfile if it is set. +Also we need to maintain several other places where touching vm_file +such like +- fork()/clone() copies vma and the reference count of vm_file is + incremented. +- merging vma maintains the ref count too. + +This is not a good approach. It just fakes the printed path. But it +leaves all behaviour around f_mapping unchanged. This is surely an +advantage. +Actually aufs had adopted another complicated approach which calls +generic_file_mmap() and handles struct vm_operations_struct. In this +approach, aufs met a hard problem and I could not solve it without +switching the approach. + +There may be one more another approach which is +- bind-mount the branch-root onto the aufs-root internally +- grab the new vfsmount (ie. struct mount) +- lazy-umount the branch-root internally +- in open(2) the aufs-file, open the branch-file with the hidden + vfsmount (instead of the original branch's vfsmount) +- ideally this "bind-mount and lazy-umount" should be done atomically, + but it may be possible from userspace by the mount helper. + +Adding the internal hidden vfsmount and using it in opening a file, the +file path under /proc will be printed correctly. This approach looks +smarter, but is not possible I am afraid. +- aufs-root may be bind-mount later. when it happens, another hidden + vfsmount will be required. +- it is hard to get the chance to bind-mount and lazy-umount + + in kernel-space, FS can have vfsmount in open(2) via + file->f_path, and aufs can know its vfsmount. But several locks are + already acquired, and if aufs tries to bind-mount and lazy-umount + here, then it may cause a deadlock. + + in user-space, bind-mount doesn't invoke the mount helper. +- since /proc shows dev and ino, aufs has to give vma these info. it + means a new member vm_prinode will be necessary. this is essentially + equivalent to vm_prfile described above. + +I have to give up this "looks-smater" approach. diff --git a/Documentation/filesystems/aufs/design/06xattr.txt b/Documentation/filesystems/aufs/design/06xattr.txt new file mode 100644 index 000000000000..edd7553f3289 --- /dev/null +++ b/Documentation/filesystems/aufs/design/06xattr.txt @@ -0,0 +1,96 @@ + +# Copyright (C) 2014-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Listing XATTR/EA and getting the value +---------------------------------------------------------------------- +For the inode standard attributes (owner, group, timestamps, etc.), aufs +shows the values from the topmost existing file. This behaviour is good +for the non-dir entries since the bahaviour exactly matches the shown +information. But for the directories, aufs considers all the same named +entries on the lower branches. Which means, if one of the lower entry +rejects readdir call, then aufs returns an error even if the topmost +entry allows it. This behaviour is necessary to respect the branch fs's +security, but can make users confused since the user-visible standard +attributes don't match the behaviour. +To address this issue, aufs has a mount option called dirperm1 which +checks the permission for the topmost entry only, and ignores the lower +entry's permission. + +A similar issue can happen around XATTR. +getxattr(2) and listxattr(2) families behave as if dirperm1 option is +always set. Otherwise these very unpleasant situation would happen. +- listxattr(2) may return the duplicated entries. +- users may not be able to remove or reset the XATTR forever, + + +XATTR/EA support in the internal (copy,move)-(up,down) +---------------------------------------------------------------------- +Generally the extended attributes of inode are categorized as these. +- "security" for LSM and capability. +- "system" for posix ACL, 'acl' mount option is required for the branch + fs generally. +- "trusted" for userspace, CAP_SYS_ADMIN is required. +- "user" for userspace, 'user_xattr' mount option is required for the + branch fs generally. + +Moreover there are some other categories. Aufs handles these rather +unpopular categories as the ordinary ones, ie. there is no special +condition nor exception. + +In copy-up, the support for XATTR on the dst branch may differ from the +src branch. In this case, the copy-up operation will get an error and +the original user operation which triggered the copy-up will fail. It +can happen that even all copy-up will fail. +When both of src and dst branches support XATTR and if an error occurs +during copying XATTR, then the copy-up should fail obviously. That is a +good reason and aufs should return an error to userspace. But when only +the src branch support that XATTR, aufs should not return an error. +For example, the src branch supports ACL but the dst branch doesn't +because the dst branch may natively un-support it or temporary +un-support it due to "noacl" mount option. Of course, the dst branch fs +may NOT return an error even if the XATTR is not supported. It is +totally up to the branch fs. + +Anyway when the aufs internal copy-up gets an error from the dst branch +fs, then aufs tries removing the just copied entry and returns the error +to the userspace. The worst case of this situation will be all copy-up +will fail. + +For the copy-up operation, there two basic approaches. +- copy the specified XATTR only (by category above), and return the + error unconditionally if it happens. +- copy all XATTR, and ignore the error on the specified category only. + +In order to support XATTR and to implement the correct behaviour, aufs +chooses the latter approach and introduces some new branch attributes, +"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". +They correspond to the XATTR namespaces (see above). Additionally, to be +convenient, "icex" is also provided which means all "icex*" attributes +are set (here the word "icex" stands for "ignore copy-error on XATTR"). + +The meaning of these attributes is to ignore the error from setting +XATTR on that branch. +Note that aufs tries copying all XATTR unconditionally, and ignores the +error from the dst branch according to the specified attributes. + +Some XATTR may have its default value. The default value may come from +the parent dir or the environment. If the default value is set at the +file creating-time, it will be overwritten by copy-up. +Some contradiction may happen I am afraid. +Do we need another attribute to stop copying XATTR? I am unsure. For +now, aufs implements the branch attributes to ignore the error. diff --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt new file mode 100644 index 000000000000..9b983f3dd78a --- /dev/null +++ b/Documentation/filesystems/aufs/design/07export.txt @@ -0,0 +1,58 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Export Aufs via NFS +---------------------------------------------------------------------- +Here is an approach. +- like xino/xib, add a new file 'xigen' which stores aufs inode + generation. +- iget_locked(): initialize aufs inode generation for a new inode, and + store it in xigen file. +- destroy_inode(): increment aufs inode generation and store it in xigen + file. it is necessary even if it is not unlinked, because any data of + inode may be changed by UDBA. +- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise + build file handle by + + branch id (4 bytes) + + superblock generation (4 bytes) + + inode number (4 or 8 bytes) + + parent dir inode number (4 or 8 bytes) + + inode generation (4 bytes)) + + return value of exportfs_encode_fh() for the parent on a branch (4 + bytes) + + file handle for a branch (by exportfs_encode_fh()) +- fh_to_dentry(): + + find the index of a branch from its id in handle, and check it is + still exist in aufs. + + 1st level: get the inode number from handle and search it in cache. + + 2nd level: if not found in cache, get the parent inode number from + the handle and search it in cache. and then open the found parent + dir, find the matching inode number by vfs_readdir() and get its + name, and call lookup_one_len() for the target dentry. + + 3rd level: if the parent dir is not cached, call + exportfs_decode_fh() for a branch and get the parent on a branch, + build a pathname of it, convert it a pathname in aufs, call + path_lookup(). now aufs gets a parent dir dentry, then handle it as + the 2nd level. + + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount + for every branch, but not itself. to get this, (currently) aufs + searches in current->nsproxy->mnt_ns list. it may not be a good + idea, but I didn't get other approach. + + test the generation of the gotten inode. +- every inode operation: they may get EBUSY due to UDBA. in this case, + convert it into ESTALE for NFSD. +- readdir(): call lockdep_on/off() because filldir in NFSD calls + lookup_one_len(), vfs_getattr(), encode_fh() and others. diff --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt new file mode 100644 index 000000000000..647a86a65db7 --- /dev/null +++ b/Documentation/filesystems/aufs/design/08shwh.txt @@ -0,0 +1,52 @@ + +# Copyright (C) 2005-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Show Whiteout Mode (shwh) +---------------------------------------------------------------------- +Generally aufs hides the name of whiteouts. But in some cases, to show +them is very useful for users. For instance, creating a new middle layer +(branch) by merging existing layers. + +(borrowing aufs1 HOW-TO from a user, Michael Towers) +When you have three branches, +- Bottom: 'system', squashfs (underlying base system), read-only +- Middle: 'mods', squashfs, read-only +- Top: 'overlay', ram (tmpfs), read-write + +The top layer is loaded at boot time and saved at shutdown, to preserve +the changes made to the system during the session. +When larger changes have been made, or smaller changes have accumulated, +the size of the saved top layer data grows. At this point, it would be +nice to be able to merge the two overlay branches ('mods' and 'overlay') +and rewrite the 'mods' squashfs, clearing the top layer and thus +restoring save and load speed. + +This merging is simplified by the use of another aufs mount, of just the +two overlay branches using the 'shwh' option. +# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ + aufs /livesys/merge_union + +A merged view of these two branches is then available at +/livesys/merge_union, and the new feature is that the whiteouts are +visible! +Note that in 'shwh' mode the aufs mount must be 'ro', which will disable +writing to all branches. Also the default mode for all branches is 'ro'. +It is now possible to save the combined contents of the two overlay +branches to a new squashfs, e.g.: +# mksquashfs /livesys/merge_union /path/to/newmods.squash + +This new squashfs archive can be stored on the boot device and the +initramfs will use it to replace the old one at the next boot. diff --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt new file mode 100644 index 000000000000..13e8583f2b91 --- /dev/null +++ b/Documentation/filesystems/aufs/design/10dynop.txt @@ -0,0 +1,47 @@ + +# Copyright (C) 2010-2019 Junjiro R. Okajima +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +Dynamically customizable FS operations +---------------------------------------------------------------------- +Generally FS operations (struct inode_operations, struct +address_space_operations, struct file_operations, etc.) are defined as +"static const", but it never means that FS have only one set of +operation. Some FS have multiple sets of them. For instance, ext2 has +three sets, one for XIP, for NOBH, and for normal. +Since aufs overrides and redirects these operations, sometimes aufs has +to change its behaviour according to the branch FS type. More importantly +VFS acts differently if a function (member in the struct) is set or +not. It means aufs should have several sets of operations and select one +among them according to the branch FS definition. + +In order to solve this problem and not to affect the behaviour of VFS, +aufs defines these operations dynamically. For instance, aufs defines +dummy direct_IO function for struct address_space_operations, but it may +not be set to the address_space_operations actually. When the branch FS +doesn't have it, aufs doesn't set it to its address_space_operations +while the function definition itself is still alive. So the behaviour +itself will not change, and it will return an error when direct_IO is +not set. + +The lifetime of these dynamically generated operation object is +maintained by aufs branch object. When the branch is removed from aufs, +the reference counter of the object is decremented. When it reaches +zero, the dynamically generated operation object will be freed. + +This approach is designed to support AIO (io_submit), Direct I/O and +XIP (DAX) mainly. +Currently this approach is applied to address_space_operations for +regular files only. diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 4822a058a81d..36cc5f070336 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -907,7 +907,11 @@ tcp_limit_output_bytes - INTEGER limits the number of bytes on qdisc or device to reduce artificial RTT/cwnd and reduce bufferbloat. +#if defined(CONFIG_SYNO_LSP_RTD1619B) + Default: 262144 +#else /* CONFIG_SYNO_LSP_RTD1619B */ Default: 1048576 (16 * 65536) +#endif /* CONFIG_SYNO_LSP_RTD1619B */ tcp_challenge_ack_limit - INTEGER Limits number of Challenge ACK sent per second, as recommended diff --git a/MAINTAINERS b/MAINTAINERS index 4fef10dd2975..d6a305e9a607 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3009,6 +3009,19 @@ F: include/linux/audit.h F: include/uapi/linux/audit.h F: kernel/audit* +AUFS (advanced multi layered unification filesystem) FILESYSTEM +M: "J. R. Okajima" +L: aufs-users@lists.sourceforge.net (members only) +L: linux-unionfs@vger.kernel.org +S: Supported +W: http://aufs.sourceforge.net +T: git://github.com/sfjro/aufs5-linux.git +F: Documentation/ABI/testing/debugfs-aufs +F: Documentation/ABI/testing/sysfs-aufs +F: Documentation/filesystems/aufs/ +F: fs/aufs/ +F: include/uapi/linux/aufs_type.h + AUXILIARY DISPLAY DRIVERS M: Miguel Ojeda Sandonis S: Maintained diff --git a/Makefile b/Makefile index 7fb6405f3b60..e4d1b7e44933 100644 --- a/Makefile +++ b/Makefile @@ -465,6 +465,8 @@ LZ4 = lz4c XZ = xz ZSTD = zstd +PAHOLE_FLAGS = $(shell PAHOLE=$(PAHOLE) $(srctree)/scripts/pahole-flags.sh) + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) NOSTDINC_FLAGS := @@ -518,6 +520,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL +export PAHOLE_FLAGS # Files to ignore in find ... statements diff --git a/SynoBuildConf/_env b/SynoBuildConf/_env new file mode 100644 index 000000000000..72aec5651e9b --- /dev/null +++ b/SynoBuildConf/_env @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +[ -z "$__INCLUDE_ENV__" ] || return +readonly __INCLUDE_ENV__=defined + + +export ARCH="${ARCH:=x86_64}" +export CROSS_COMPILE="${ToolChainPrefix:=}" +export KCFLAGS="-fdiagnostics-color=always -Werror" + +_init() +{ + C_INFO="\e[1;32m" + C_WARN="\e[1;33m" + C_ERROR="\e[1;31m" + C_CLEAR="\e[m" + + # simple alternatives of utilities from lnxscripts + local _func + for _func in INFO ERROR WARNING; do + if ! type -p "$_func"; then + eval "$_func() { echo \"[$_func] \$*\"; }" + fi + done +} + +INFO() +{ + echo -e "[${C_INFO:-}INFO${C_CLEAR:-}] $*" +} + +WARNING() +{ + echo -e "[${C_WARN:-}WARNING${C_CLEAR:-}] $*" +} + +ERROR() +{ + echo -e "[${C_ERROR:-}Error${C_CLEAR:-}] $*" +} + +env_check_command() # $1: command +{ + if ! command -v "$1" &>/dev/null; then + ERROR "'$1' is not found" + return 1 + fi +} + +env_detect_clang() +{ + env_check_command "clang" +} + +env_detect_llvm() +{ + env_check_command "lld" # FIXME +} + +env_enable_clang() +{ + export CC="clang" +} + +env_enable_llvm() +{ + export LLVM=1 +} + +_init diff --git a/SynoBuildConf/_kconfig b/SynoBuildConf/_kconfig new file mode 100644 index 000000000000..a6b45f51444f --- /dev/null +++ b/SynoBuildConf/_kconfig @@ -0,0 +1,255 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +[ -z "$__INCLUDE_KCONFIG__" ] || return +readonly __INCLUDE_KCONFIG__=defined + + +# shellcheck source=/dev/null +source "SynoBuildConf/_platform" + +kconfig_check_diff() +{ + local _plat_config="synology/synoconfigs/$PLATFORM_ABBR" + + [ -f ".debug" ] && return + + if ! diff -bu "$_plat_config" .config; then + ERROR "There's difference between $_plat_config & .config" + ERROR "Please reconfirm your modifications before committing." + return 1 + fi +} + +kconfig_check_syno_macro() +{ + local _m + declare -A syno_kconfig=() + + # collect syno macros from all kconfigs + for _m in $(find . -name "Kconfig*" -exec grep "config SYNO" {} + | cut -d' ' -f2); do + syno_kconfig[$_m]= + done + + # all syno macros should be defined in kconfig. + # toolkit: ds.epyc7002-7.2.env + # toolchain: epyc7002-gcc1220_glibc236_x86_64-GPL (Not used) + find . \( -path './.git' -o -path './SynoBuildConf' -o -path './ds.*' -o -path './drivers/syno' \) -prune -o -type f -exec \ + grep -rohE --exclude="*.patch" "[/]*((#ifdef)|(#defined))[[:space:]]*\(?CONFIG_SYNO([[:alnum:]]|_)*" {} + \ + | grep -v "^//" \ + | awk -F 'CONFIG_' '{ print $2 }' \ + | while IFS= read -r _m + do + if [[ ! -v syno_kconfig[$_m] ]]; then + ERROR "'$_m' isn't defined in kconfig" + return 1 + fi + done + + # '#ifndef CONFIG_SYNO*' isn't allowed. + # toolkit: ds.epyc7002-7.2.env + # toolchain: epyc7002-gcc1220_glibc236_x86_64-GPL (Not used) + if find . \( -path './.git' -o -path './SynoBuildConf' -o -path './ds.*' -o -path './drivers/syno' \) -prune -o -type f -exec \ + grep -roE "ifndef[[:space:]]*CONFIG_SYNO" {} +; then + ERROR "'#ifndef' isn't allowed with syno macros" + return 1 + fi + + # all syno macros should start with prefix SYNO_ + # toolkit: ds.epyc7002-7.2.env + # toolchain: epyc7002-gcc1220_glibc236_x86_64-GPL (Not used) + if find . \( -path './.git' -o -path './SynoBuildConf' -o -path './ds.*' -o -path './drivers/syno' \) -prune -o -type f -exec \ + grep -roE "((ifdef)|(defined))[[:space:]]*\(?SYNO([[:alnum:]]|_)*" {} + \ + | grep -v -e SYNO_EXPORT_CONFIG -e SYNO_FS_SYNO_ACL; then + ERROR "all syno macros should start with prefix SYNO_" + return 1 + fi +} + +kconfig_debug_mode() +{ + local _cfg= + local _enabled=" + # + # printk and dmesg options + # + CONFIG_DYNAMIC_DEBUG + + # + # Memory Debugging + # + CONFIG_DEBUG_PAGEALLOC + CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT + CONFIG_PAGE_OWNER + CONFIG_PAGE_POISONING + + #CONFIG_DEBUG_OBJECTS + #CONFIG_DEBUG_OBJECTS_FREE + #CONFIG_DEBUG_OBJECTS_TIMERS + #CONFIG_DEBUG_OBJECTS_WORK + #CONFIG_DEBUG_OBJECTS_RCU_HEAD + #CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER + CONFIG_SLUB_DEBUG_ON + CONFIG_SLUB_STATS + #CONFIG_DEBUG_KMEMLEAK + CONFIG_DEBUG_STACK_USAGE + + #CONFIG_DEBUG_VM + #CONFIG_DEBUG_VM_VMACACHE + #CONFIG_DEBUG_VM_RB + #CONFIG_DEBUG_VIRTUAL + #CONFIG_DEBUG_NOMMU_REGIONS + #CONFIG_DEBUG_MEMORY_INIT + #CONFIG_MEMORY_NOTIFIER_ERROR_INJECT + #CONFIG_DEBUG_PER_CPU_MAPS + #CONFIG_DEBUG_HIGHMEM + #CONFIG_DEBUG_STACKOVERFLOW + + # + # Kernel address sanitizer (Kasan) + # + CONFIG_KASAN + CONFIG_KASAN_OUTLINE + CONFIG_KASAN_VMALLOC + #CONFIG_KASAN_INLINE + + # + # Debug Lockups and Hangs + # + #CONFIG_SCHED_STACK_END_CHECK + #CONFIG_DEBUG_TIMEKEEPING + #CONFIG_TIMER_STATS + + # + # Lock Debugging + # + CONFIG_DEBUG_SPINLOCK + CONFIG_DEBUG_MUTEXES + CONFIG_DEBUG_LOCK_ALLOC + CONFIG_PROVE_LOCKING + CONFIG_LOCK_STAT + CONFIG_DEBUG_ATOMIC_SLEEP + CONFIG_LOCKDEP + + #CONFIG_TRACE_IRQFLAGS + #CONFIG_DEBUG_KOBJECT + #CONFIG_DEBUG_KOBJECT_RELEASE + #CONFIG_DEBUG_LIST + #CONFIG_DEBUG_PI_LIST + #CONFIG_DEBUG_SG + #CONFIG_DEBUG_NOTIFIERS + #CONFIG_DEBUG_CREDENTIALS + + # + # RCU Debugging + # + #CONFIG_PROVE_RCU + #CONFIG_PROVE_RCU_REPEATEDLY + #CONFIG_RCU_TRACE + + # + # Fault-injection framework + # + CONFIG_FAULT_INJECTION + CONFIG_FAILSLAB + CONFIG_FAIL_PAGE_ALLOC + CONFIG_FAIL_MAKE_REQUEST + CONFIG_FAIL_IO_TIMEOUT + #CONFIG_FAIL_MMC_REQUEST + #CONFIG_FAIL_FUTEX + CONFIG_FAULT_INJECTION_DEBUG_FS + CONFIG_FAIL_FUNCTION + #CONFIG_FAULT_INJECTION_STACKTRACE_FILTER + + #CONFIG_LATENCYTOP + #CONFIG_DEBUG_STRICT_USER_COPY_CHECKS + + # + # Trace + # + #CONFIG_FUNCTION_TRACER + #CONFIG_FUNCTION_GRAPH_TRACER + #CONFIG_IRQSOFF_TRACER + #CONFIG_PREEMPT_TRACER + #CONFIG_ENABLE_DEFAULT_TRACERS + #CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP + #CONFIG_BRANCH_PROFILE_NONE + #CONFIG_PROFILE_ANNOTATED_BRANCHES + #CONFIG_PROFILE_ALL_BRANCHES + #CONFIG_STACK_TRACER + #CONFIG_DYNAMIC_FTRACE + #CONFIG_FUNCTION_PROFILER + #CONFIG_MMIOTRACE + + # + # Btrfs + # + CONFIG_BTRFS_FS_RUN_SANITY_TESTS + #CONFIG_BTRFS_DEBUG + CONFIG_BTRFS_ASSERT + #CONFIG_BTRFS_FS_REF_VERIFY + " + local _disabled=" + " + + ./scripts/config --set-val CONFIG_CONSOLE_LOGLEVEL_DEFAULT 7 + ./scripts/config --set-val CONFIG_MESSAGE_LOGLEVEL_DEFAULT 7 + + while read -r _cfg; do + if [ -z "$_cfg" ] || [[ "$_cfg" =~ .*"#".* ]]; then + continue + fi + + INFO "Enable $_cfg" + ./scripts/config --enable "$_cfg" + done <<< "$_enabled" + + while read -r _cfg; do + if [ -z "$_cfg" ] || [[ "$_cfg" =~ .*"#".* ]]; then + continue + fi + + INFO "Disable $_cfg" + ./scripts/config --disable "$_cfg" + done <<< "$_disabled" + + # disable KASAN for non-x64 platform due to MTD size + if [ "$PLATFORM_FAMILY" != "SYNOPLAT_F_X86_64" ]; then + ./scripts/config --disable CONFIG_KASAN + ./scripts/config --disable CONFIG_DEBUG_SPINLOCK + ./scripts/config --disable CONFIG_DEBUG_MUTEXES + ./scripts/config --disable CONFIG_DEBUG_LOCK_ALLOC + ./scripts/config --disable CONFIG_PROVE_LOCKING + ./scripts/config --disable CONFIG_LOCK_STAT + ./scripts/config --disable CONFIG_DEBUG_ATOMIC_SLEEP + ./scripts/config --disable CONFIG_LOCKDEP + fi +} + +kconfig_generate() +{ + if [ -z "$PLATFORM_ABBR" ]; then + ERROR "environment variable 'PLATFORM_ABBR' isn't assigned" + return 1 + fi + + cp -f "synology/synoconfigs/$PLATFORM_ABBR" .config + + if [ -f ".debug" ]; then + INFO "File '.debug' is detected. Configured as debug mode." + kconfig_debug_mode + make olddefconfig + else + make oldconfig + fi +} + +kconfig_check_rule() +{ + if ! (cd synology/synoconfigs-spec/ || return 1; rake test) > /dev/null; then + ERROR "kernel configs don't match the rules." + ERROR "please check them with 'rake test' in synology/synoconfigs-spec" + return 1 + fi +} + diff --git a/SynoBuildConf/_modules b/SynoBuildConf/_modules new file mode 100644 index 000000000000..af49c4f1a844 --- /dev/null +++ b/SynoBuildConf/_modules @@ -0,0 +1,770 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +# shellcheck disable=SC2034 + +[ -z "$__INCLUDE_MODULE__" ] || return +readonly __INCLUDE_MODULE__=defined + +mod_crypto=" + crypto/ansi_cprng.ko + crypto/cbc.ko + crypto/des_generic.ko + crypto/ecb.ko + crypto/cmac.ko + crypto/hmac.ko + crypto/md4.ko + crypto/md5.ko + crypto/sha256_generic.ko + crypto/cts.ko + crypto/seqiv.ko + crypto/gcm.ko + crypto/ccm.ko + crypto/ghash-generic.ko + crypto/ctr.ko + crypto/cryptd.ko + crypto/gf128mul.ko + crypto/lrw.ko + crypto/echainiv.ko + crypto/xxhash_generic.ko + lib/crypto/libdes.ko + lib/crypto/libsha256.ko + lib/crypto/libarc4.ko + crypto/zstd.ko + crypto/lzo-rle.ko + crypto/lzo.ko +" + +mod_fs_misc=" + fs/fat/fat.ko + fs/fat/vfat.ko + fs/hfsplus/hfsplus.ko + drivers/md/dm-flakey.ko +" + +mod_fs_enc=" + fs/ecryptfs/ecryptfs.ko +" + +mod_fs_fuse=" + fs/fuse/fuse.ko +" + +mod_fs_iso=" + drivers/block/loop.ko + fs/isofs/isofs.ko + fs/udf/udf.ko + lib/crc-itu-t.ko +" + +mod_net_bonding=" + drivers/net/bonding/bonding.ko +" + +mod_appletalk=" + net/802/psnap.ko + net/802/p8022.ko + net/appletalk/appletalk.ko + net/llc/llc.ko +" + +mod_net_firewall=" + net/ipv4/netfilter/ip_tables.ko + net/netfilter/xt_REDIRECT.ko + net/ipv4/netfilter/iptable_filter.ko + net/ipv4/netfilter/iptable_nat.ko + net/ipv4/netfilter/nf_defrag_ipv4.ko + net/netfilter/nf_nat.ko + net/netfilter/nf_conntrack.ko + net/netfilter/x_tables.ko + net/netfilter/xt_multiport.ko + net/netfilter/xt_state.ko + net/netfilter/xt_tcpudp.ko + net/netfilter/xt_LOG.ko + net/netfilter/xt_limit.ko + net/netfilter/xt_iprange.ko + net/netfilter/xt_recent.ko + net/netfilter/nfnetlink.ko + net/netfilter/nfnetlink_queue.ko + net/netfilter/ipset/ip_set.ko + net/netfilter/ipset/ip_set_hash_ip.ko + net/netfilter/xt_set.ko + net/netfilter/xt_nat.ko + net/netfilter/xt_TCPMSS.ko + net/netfilter/xt_MASQUERADE.ko + net/netfilter/xt_mac.ko + net/netfilter/xt_policy.ko +" + +mod_ipv6_firewall=" + net/ipv6/netfilter/ip6_tables.ko + net/ipv6/netfilter/ip6table_filter.ko + net/ipv6/netfilter/nf_defrag_ipv6.ko + net/netfilter/xt_LOG.ko +" + +mod_ipv6=" + net/ipv6/ipv6.ko +" + +mod_net_ppp=" + drivers/net/ppp/ppp_async.ko + drivers/net/ppp/ppp_generic.ko + drivers/net/ppp/ppp_synctty.ko + drivers/net/ppp/pppox.ko + drivers/net/ppp/pppoe.ko + drivers/net/ppp/bsd_comp.ko + drivers/net/ppp/ppp_deflate.ko + drivers/net/ppp/ppp_mppe.ko + drivers/net/ppp/pptp.ko + net/l2tp/l2tp_core.ko + net/l2tp/l2tp_ppp.ko + net/ipv4/gre.ko + drivers/net/slip/slhc.ko + drivers/tty/n_hdlc.ko + lib/crc-ccitt.ko +" + +mod_net_tunnel=" + drivers/net/tun.ko +" + +mod_iscsi=" + drivers/scsi/libiscsi.ko + drivers/scsi/libiscsi_tcp.ko + drivers/scsi/iscsi_tcp.ko +" + +mod_fs_nfsd=" + fs/nfsd/nfsd.ko + fs/nfs_common/grace.ko + fs/lockd/lockd.ko + net/sunrpc/sunrpc.ko + net/sunrpc/auth_gss/auth_rpcgss.ko + net/sunrpc/auth_gss/rpcsec_gss_krb5.ko +" + +mod_fs_nfs=" + fs/nfs/nfs.ko + fs/nfs/nfsv2.ko + fs/nfs/nfsv3.ko + fs/nfs/nfsv4.ko + fs/nfs_common/nfs_ssc.ko +" + +mod_fs_cifs=" + fs/cifs/cifs.ko +" + +mod_scsi=" + drivers/scsi/sg.ko +" + +mod_dm_snapshot=" + drivers/md/dm-bufio.ko + drivers/md/dm-snapshot.ko +" + +mod_sound=" + sound/soundcore.ko +" + +mod_usb_printer=" + drivers/usb/class/usblp.ko +" + +mod_usb=" + drivers/hid/hid.ko + drivers/hid/hid-generic.ko + drivers/hid/usbhid/usbhid.ko + drivers/usb/host/uhci-hcd.ko + drivers/usb/host/xhci-hcd.ko + drivers/usb/host/xhci-pci.ko + drivers/usb/common/usb-common.ko + drivers/usb/core/usbcore.ko + drivers/usb/storage/usb-storage.ko + drivers/usb/storage/uas.ko + drivers/usb/class/cdc-acm.ko +" + +mod_usb_ehci=" + drivers/usb/host/ehci-hcd.ko + drivers/usb/host/ehci-pci.ko +" + +mod_usb_ip=" + drivers/usb/usbip/usbip-host.ko + drivers/usb/usbip/usbip-core.ko +" + +mod_usb_wimax=" + drivers/net/usb/usbnet.ko + drivers/net/usb/cdc_ether.ko +" + +mod_usb_alsa=" + sound/usb/snd-usbmidi-lib.ko + sound/usb/snd-usb-audio.ko + sound/core/snd-hwdep.ko + sound/core/snd-rawmidi.ko + sound/usb/hiface/snd-usb-hiface.ko +" + +mod_usb_rtk=" + drivers/usb/phy/phy-rtk-usb3.ko + drivers/usb/phy/phy-rtk-usb2.ko + drivers/usb/dwc3/dwc3_rtk.ko + drivers/usb/dwc3/dwc3.ko + drivers/usb/host/xhci-plat-hcd.ko + drivers/soc/realtek/common/rtk-usb-manager.ko +" + +mod_sound_alsa=" + sound/core/snd-pcm.ko + sound/core/snd-seq-device.ko + sound/core/snd.ko + sound/core/oss/snd-pcm-oss.ko + sound/core/oss/snd-mixer-oss.ko + sound/core/snd-timer.ko +" + +mod_docker=" + drivers/net/macvlan.ko + drivers/net/veth.ko + drivers/net/vxlan.ko + net/bridge/br_netfilter.ko + net/ipv4/udp_tunnel.ko + net/ipv6/ip6_udp_tunnel.ko + net/netfilter/xt_addrtype.ko + net/netfilter/xt_conntrack.ko + fs/aufs/aufs.ko + fs/overlayfs/overlay.ko +" + +mod_raid=" + drivers/md/dm-mod.ko + drivers/md/dm-raid.ko + drivers/md/linear.ko + drivers/md/raid0.ko + drivers/md/raid10.ko + drivers/md/raid456.ko + lib/raid6/raid6_pq.ko + crypto/async_tx/async_tx.ko + crypto/async_tx/async_memcpy.ko + crypto/async_tx/async_xor.ko + crypto/async_tx/async_pq.ko + crypto/async_tx/async_raid6_recov.ko + crypto/xor.ko +" + +mod_ipv6_tunnel=" + net/ipv4/ip_tunnel.ko + net/ipv4/tunnel4.ko + net/ipv6/sit.ko +" + +mod_net_filter=" + net/netfilter/nfnetlink.ko + net/netfilter/nfnetlink_queue.ko + net/netfilter/xt_NFQUEUE.ko +" + +mod_cpufreq=" + drivers/cpufreq/acpi-cpufreq.ko + drivers/cpufreq/cpufreq_performance.ko + drivers/cpufreq/cpufreq_powersave.ko +" + +mod_net_bridge=" + net/bridge/bridge.ko + net/802/stp.ko +" + +mod_net_tc=" + net/sched/sch_htb.ko + net/sched/sch_sfq.ko + net/sched/cls_fw.ko + net/sched/sch_netem.ko + net/netfilter/xt_mark.ko + net/ipv4/netfilter/iptable_mangle.ko + net/ipv6/netfilter/ip6table_mangle.ko + net/sched/cls_u32.ko +" + +mod_net_fw_security=" + net/netfilter/nf_conntrack_pptp.ko + net/ipv4/netfilter/nf_nat_pptp.ko +" + +mod_net_vlan=" + net/8021q/8021q.ko +" + +mod_net_ipsec=" + crypto/authenc.ko + crypto/authencesn.ko + net/ipv4/ah4.ko + net/ipv4/esp4.ko + net/ipv4/ipcomp.ko + net/ipv4/xfrm4_tunnel.ko + net/ipv4/tunnel4.ko + net/ipv4/udp_tunnel.ko + net/ipv4/xfrm4_tunnel.ko + net/xfrm/xfrm_algo.ko + net/xfrm/xfrm_user.ko + net/xfrm/xfrm_ipcomp.ko + net/ipv6/ah6.ko + net/ipv6/esp6.ko + net/ipv6/ipcomp6.ko + net/ipv6/xfrm6_tunnel.ko + net/ipv6/tunnel6.ko + net/ipv6/ip6_udp_tunnel.ko + net/ipv6/xfrm6_tunnel.ko + net/key/af_key.ko +" + +mod_zram=" + drivers/block/zram/zram.ko +" +mod_vaapi=" + drivers/gpu/drm/drm.ko + arch/x86/video/fbdev.ko + drivers/video/fbdev/core/fb.ko + drivers/video/fbdev/core/fb_sys_fops.ko + drivers/video/fbdev/core/sysimgblt.ko + drivers/video/fbdev/core/sysfillrect.ko + drivers/video/fbdev/core/syscopyarea.ko + drivers/gpu/drm/drm_kms_helper.ko + drivers/video/fbdev/core/cfbcopyarea.ko + drivers/video/fbdev/core/cfbimgblt.ko + drivers/video/fbdev/core/cfbfillrect.ko + drivers/acpi/button.ko + drivers/video/backlight/backlight.ko + drivers/acpi/video.ko + drivers/gpu/drm/i915/i915.ko + arch/x86/platform/intel/iosf_mbi.ko + drivers/gpu/drm/drm_panel_orientation_quirks.ko +" + +mod_kvm=" + virt/lib/irqbypass.ko + arch/x86/kvm/kvm.ko + arch/x86/kvm/kvm-intel.ko + drivers/pci/pci-stub.ko +" + +mod_vfio=" + drivers/vfio/vfio.ko + drivers/vfio/vfio_iommu_type1.ko + drivers/vfio/pci/vfio-pci.ko + drivers/vfio/vfio_virqfd.ko +" + +mod_net_openvswitch=" + net/openvswitch/openvswitch.ko + net/mpls/mpls_gso.ko + net/nsh/nsh.ko +" + +mod_usb_serial=" + drivers/usb/serial/usbserial.ko + drivers/usb/serial/ftdi_sio.ko +" + +mod_led_lp3943=" + drivers/leds/leds-lp3943.ko +" + +mod_led_atmega1608=" + drivers/leds/leds-atmega1608.ko +" + +mod_led_atmega1608_seg7=" + drivers/leds/leds-atmega1608-seg7.ko +" + +mod_i2c=" + drivers/i2c/algos/i2c-algo-bit.ko +" + +mod_fs_btrfs_cp=" + fs/syno_cache_protection/syno_cache_protection.ko +" + +mod_fs_btrfs=" + fs/btrfs/btrfs.ko + lib/zstd/zstd_compress.ko +" + +mod_crypto_intel=" + crypto/crypto_simd.ko + arch/x86/crypto/glue_helper.ko + arch/x86/crypto/aesni-intel.ko +" + +mod_hwmon_disk_pwctl=" + drivers/hwmon/syno_hddmon.ko +" + +mod_virtio=" + drivers/block/virtio_blk.ko + drivers/char/virtio_console.ko + drivers/char/hw_random/virtio-rng.ko + drivers/net/virtio_net.ko + drivers/net/net_failover.ko + drivers/scsi/virtio_scsi.ko + drivers/virtio/virtio.ko + drivers/virtio/virtio_balloon.ko + drivers/virtio/virtio_mmio.ko + drivers/virtio/virtio_pci.ko + drivers/virtio/virtio_ring.ko + net/9p/9pnet_virtio.ko + net/core/failover.ko +" + +mod_dca=" + drivers/dca/dca.ko +" + +mod_hwmon_adt=" + drivers/hwmon/adt7475.ko +" + +mod_net_console=" + drivers/net/netconsole.ko +" + +mod_ntb=" + drivers/ntb/ntb.ko + drivers/ntb/hw/intel/ntb_hw_intel.ko + drivers/ntb/ntb_transport.ko + drivers/net/ntb_netdev.ko +" + +mod_ntb_brd=" + drivers/block/ntb_brd.ko +" + +mod_docker_ingress=" + net/netfilter/ipvs/ip_vs.ko + net/netfilter/ipvs/ip_vs_rr.ko + net/netfilter/xt_ipvs.ko +" + +mod_scsi_fc="\ + drivers/scsi/scsi_transport_fc.ko + drivers/scsi/libfc/libfc.ko +" + +mod_acpi="\ + drivers/acpi/button.ko +" + +mod_dm_multipath="\ + drivers/md/dm-multipath.ko + drivers/md/dm-round-robin.ko + drivers/md/dm-queue-length.ko + drivers/md/dm-service-time.ko +" + +mod_fc="\ + drivers/scsi/scsi_transport_fc.ko + drivers/scsi/libfc/libfc.ko +" + +mod_bnx2x="\ + drivers/net/ethernet/emulex/benet/be2net.ko +" + +mod_cpufreq_rtk=" + drivers/cpufreq/cpufreq_performance.ko + drivers/cpufreq/cpufreq_powersave.ko +" + +mod_dm_crypt="\ + drivers/md/dm-crypt.ko + crypto/essiv.ko +" + +mod_ceph="\ + drivers/block/rbd.ko \ + net/ceph/libceph.ko \ + fs/ceph/ceph.ko \ +" + +declare -A _mapping_idx=( + [KVMX64]=2 + [GEMINILAKE]=3 + [V1000]=4 + [BROADWELL]=5 + [BROADWELLNK]=6 + [BROADWELLNTB]=7 + [BROADWELLNTBAP]=8 + [DENVERTON]=9 + [APOLLOLAKE]=10 + [REALTEK_RTD1296]=11 + [PURLEY]=12 + [MARVELL_ARMADA37XX]=13 + [COFFEELAKE]=14 + [NEXTKVMX64]=15 + [REALTEK_RTD1619]=16 + [SKYLAKED]=17 + [KVMCLOUD]=18 + [REALTEK_RTD1619B]=19 + [ICELAKED]=20 + [EPYC7002]=21 + [EPYC7002SOFS]=22 + [V1000SOFS]=23 + [KVMX64SOFS]=24 + [RYZEN5K]=25 + [EPYC7003NTB]=26 + [KVMX64V2]=27 +) + +_mapping=" +# Please add modules-platform mappings in this array map +# Platform aliases: +# KVM: KVMX64 +# GML: GEMINILAKE +# V1K: V1000 +# BRW: BROADWELL +# BRN: BROADWELLNK +# BNT: BROADWELLNTB +# BAP: BROADWELLNTBAP +# DNV: DENVERTON +# APL: APOLLOLAKE +# R96: REALTEK_RTD1296 +# PUR: PURLEY +# A37: MARVELL_ARMADA37XX +# CFL: COFFEELAKE +# NXT: NEXTKVMX64 +# R19: REALTEK_RTD1619 +# SKL: SKYLAKED +# KCL: KVMCLOUD +# ICXD: ICELAKED +# EPC2: EPYC7002 +# EPSO: EPYC7002SOFS +# VSO: V1000SOFS +# KVSO: KVMX64SOFS +# R5K: RYZEN5K +# EPC3N: EPYC7003NTB +# KV2: KVMX64V2 + +# Modules KVM GML V1K BRW BRN BNT BAP DNV APL R96 PUR A37 CFL NXT R19 SKL KCL R19B ICXD EPC2 EPSO VSO KVSO R5K EPC3N KV2 +mod_crypto o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_crypto_intel o o o o o o o o o x o x o o x o o x o o o o o o o o +mod_fs_misc o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_enc o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_fuse o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_iso o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_nfsd o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_nfs o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_cifs o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_fs_btrfs o o o o o o o o o o o x o o o o o o o o o o o o o o +mod_fs_btrfs_cp x x x x x x o x x x x x x x x x x x x x x x x x x x +mod_appletalk o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_bonding o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_firewall o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_ppp o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_tunnel o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_filter o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_bridge o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_tc o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_fw_security o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_vlan o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_ipsec o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_net_openvswitch o o o o o o o o o x o o o o x o o x o o o o o o o o +mod_net_console x o o o o x x o o x o o o x x o x x o o o o x o o x # XXX: need review ?? +mod_ipv6 o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_ipv6_firewall o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_ipv6_tunnel o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_iscsi o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_scsi o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_scsi_fc x x x o o o x x x x o x x x x x x x o o o x x o o x +mod_sound o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_sound_alsa o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_raid o o o o o o o o o o o o o o o o o o o o o o o o o o +mod_cpufreq o o o o o o o o o x o x o o x o o x o o o o o o o o +mod_zram o o o o o o o o o o o o o o x o o x o o o o o o o o # XXX: why not installed in REALTEK_RTD1619 ?? +mod_vaapi x o x x x x x x o x x x x x x x x x x x x o x x x x +mod_kvm x o x o o o o o o x o x o o x o x x x x x o x x x x +mod_virtio o x x x x x x x x x x x x o x x o x x x x x o x x o + +# Modules KVM GML V1K BRW BRN BNT BAP DNV APL R96 PUR A37 CFL NXT R19 SKL KCL R19B ICXD EPC2 EPSO VSO KVSO R5k EPC3N KV2 +mod_usb o o o o o o o o o o o o o o o o x o o o o o o o o o +mod_usb_printer o o o o o o o o o o o o o o o o x o o o o o o o o o +mod_usb_ehci o o o x x o o o o o o o o o o o x o o o o o o o o o # XXX: not consistent in broadwell/kvm series ?? +mod_usb_ip o o o o o o o o o o o o o o o o x o o o o o o o o o +mod_usb_wimax o o o o o o o o o o o o o o o o x o o o o o o o o o # deprecated +mod_usb_serial o o o o o o o o o o o o o o o o x o o o o o o o o o +mod_usb_alsa o o o o o o o o o o o o o o o o x o o o o o o o o o +mod_led_lp3943 x o o o o o o o o x o x o x x x x x x x x o x x x x # XXX: need review ?? +mod_led_atmega1608 x x o x x x x x x x o x x x x x x x o o o o x o o x +mod_led_atmega1608_seg7 x x o x x x x x x x o x x x x x x x o o o o x o x x +mod_vfio x o o o o o x o o x o x o o x o x x o o o o o o o x # XXX: need review ?? +mod_i2c o o x o o o o o o x o x o o x o x x o o o x o o o o +mod_hwmon_adt x x o o o o o x x x x x o x x x x x o o o o x o o x +mod_hwmon_disk_pwctl x o o o o o o o o o x o o x o x x o x x x o x x x x # XXX: need review ?? +mod_dca x x x o o o o x x x x x o x x x x x o x x x x x x x +mod_ntb x x x x x o o x x x x x x x x x x x x x x x x x x x +mod_ntb_brd x x x x x x o x x x x x x x x x x x x x x x x x x x +mod_docker o o o o o o o o o o o o o o o o o o o o o o o o o o # deprecated +mod_docker_ingress o o o o o o o o o x o x o o x o o o o o o o o o o o +mod_acpi x x x x x x x x x x x x x x x x o x x x x x x x x x +mod_dm_multipath x x x x x x x x x x o x x x x x x x x x x x x x x x +mod_dm_snapshot o o o o o o o o o o o o o o o o o o o o o o o o o o # deprecated +mod_fc x x x o o o o x x x o x x x x x x x o o o x x o o x +mod_usb_rtk x x x x x x x x x x x x x x x x x o x x x x x x x x +mod_bnx2x o x x o x x x x x x o x x x x x x x o o o x o o o o +mod_cpufreq_rtk x x x x x x x x x x x x x x x x x o x x x x x x x x +mod_dm_crypt o o o o o o o o o x o x o o x o o x o o o o o o o o +mod_ceph x x x x x x x x x x x x x x x x x x x x o o o x x x +" + +modules_customized() +{ + local _modules + + case "$BUILD_TARGET" in + KVMX64) + _modules=" + drivers/i2c/busses/i2c-i801.ko + drivers/dma/ioat/ioatdma.ko + drivers/hwmon/adt7475.ko + drivers/dca/dca.ko + drivers/net/mdio.ko + lib/zlib_deflate/zlib_deflate.ko + drivers/net/ethernet/intel/igbvf/igbvf.ko + " + ;; + KVMX64SOFS) + _modules=" + drivers/i2c/busses/i2c-i801.ko + drivers/dma/ioat/ioatdma.ko + drivers/hwmon/adt7475.ko + drivers/dca/dca.ko + drivers/net/mdio.ko + lib/zlib_deflate/zlib_deflate.ko + drivers/net/ethernet/intel/igbvf/igbvf.ko + " + ;; + KVMX64V2) + _modules=" + drivers/i2c/busses/i2c-i801.ko + drivers/dma/ioat/ioatdma.ko + drivers/hwmon/adt7475.ko + drivers/dca/dca.ko + drivers/net/mdio.ko + lib/zlib_deflate/zlib_deflate.ko + drivers/net/ethernet/intel/igbvf/igbvf.ko + " + ;; + BROADWELL) + _modules=" + drivers/net/mdio.ko + " + ;; + PURLEY) + _modules=" + drivers/dma/ioat/ioatdma.ko + drivers/hwmon/adt7475.ko + drivers/dca/dca.ko + drivers/scsi/mpt3sas/mpt3sas.ko + " + ;; + GEMINILAKE) + ;; + V1000) + _modules=" + drivers/hwmon/hwmon-vid.ko + virt/lib/irqbypass.ko + arch/x86/kvm/kvm.ko + arch/x86/kvm/kvm-amd.ko + drivers/pci/pci-stub.ko + drivers/hwmon/syno_smbus_hddmon.ko + drivers/net/phy/marvell10g.ko + drivers/net/ethernet/amd/xgbe/amd-xgbe.ko + lib/synolib/syno_uart2spi_logout.ko + " + ;; + V1000SOFS) + _modules=" + drivers/hwmon/hwmon-vid.ko + virt/lib/irqbypass.ko + arch/x86/kvm/kvm.ko + arch/x86/kvm/kvm-amd.ko + drivers/pci/pci-stub.ko + drivers/hwmon/syno_smbus_hddmon.ko + drivers/net/phy/marvell10g.ko + drivers/net/ethernet/amd/xgbe/amd-xgbe.ko + lib/synolib/syno_uart2spi_logout.ko + " + ;; + REALTEK_RTD1619B) + _modules=" + arch/arm64/lib/xor-neon.ko + " + ;; + ICELAKED) + ;; + EPYC7002) + _modules=" + drivers/hwmon/hwmon-vid.ko + virt/lib/irqbypass.ko + arch/x86/kvm/kvm.ko + arch/x86/kvm/kvm-amd.ko + drivers/pci/pci-stub.ko + " + ;; + EPYC7002SOFS) + _modules=" + drivers/hwmon/hwmon-vid.ko + virt/lib/irqbypass.ko + arch/x86/kvm/kvm.ko + arch/x86/kvm/kvm-amd.ko + drivers/pci/pci-stub.ko + " + ;; + RYZEN5K) + _modules=" + drivers/hwmon/hwmon-vid.ko + " + ;; + EPYC7003NTB) + _modules=" + drivers/hwmon/hwmon-vid.ko + virt/lib/irqbypass.ko + arch/x86/kvm/kvm.ko + arch/x86/kvm/kvm-amd.ko + drivers/pci/pci-stub.ko + drivers/ntb/ntb.ko + drivers/ntb/hw/amd/ntb_hw_amd.ko + drivers/ntb/ntb_transport.ko + drivers/net/ntb_netdev.ko + " + ;; + esac + + printf "%s" "$_modules" +} + +module_list() +{ + local _line _modules _install _idx + + while read -r _line; do + [[ "$_line" =~ ^[[:blank:]]*(#.*)?$ ]] && continue + + _idx="${_mapping_idx[${BUILD_TARGET:?undefined}]}" + _modules="$(echo "$_line" | awk "{ print \$1 }")" + _install="$(echo "$_line" | awk "{ print \$$_idx }")" + + # shellcheck disable=SC2086 + [ "$_install" = "o" ] && printf "%s " ${!_modules} + done <<< "$_mapping" + + while read -r _line; do + printf "%s " "$_line" + done <<< "$(modules_customized)" +} + diff --git a/SynoBuildConf/_platform b/SynoBuildConf/_platform new file mode 100644 index 000000000000..50cbd30b9586 --- /dev/null +++ b/SynoBuildConf/_platform @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +[ -z "$__INCLUDE_PLATFORM__" ] || return +readonly __INCLUDE_PLATFORM__=defined + + +# shellcheck source=/dev/null +source "SynoBuildConf/_env" + +platform_target() +{ + case $PLATFORM_FAMILY in + SYNOPLAT_F_X86_64) + echo "bzImage" + ;; + SYNOPLAT_F_ARMV8) + echo "Image.lzma" + ;; + esac +} + +# displayed image name should be matched with the result of +# platform_customize_image() +platform_image_name() +{ + [ -f ".config" ] || return + + if [ "$PLATFORM_FAMILY" = "SYNOPLAT_F_X86_64" ]; then + make -s image_name + elif [ "$PLATFORM_FAMILY" = "SYNOPLAT_F_ARMV8" ]; then + make -s image_name + else + echo "ENOENT" + fi +} + +# shellcheck disable=SC2154 +platform_customize_rtd1619b_mango_image() +{ + # shellcheck disable=SC2043 + for model in mango; do + DTBIMG="${KernelDir}/arch/arm64/boot/dts/realtek/rtd-1619b-synology-${model}.dtb" + mkdir -p "${DebDevBuild}/image/files/sds-sii/dtbs/synology_rtd1619bmango_${model}/" + cp -vf "${DTBIMG}" "${DebDevBuild}/image/files/sds-sii/dtbs/synology_rtd1619bmango_${model}/model-vendor.dtb" + done +} + +# shellcheck disable=SC2154 +platform_customize_rtd1619b_image() +{ + # shellcheck disable=SC2043 + for model in ds223j ds423 ds223 ds124; do + DTBIMG="${KernelDir}/arch/arm64/boot/dts/realtek/rtd-1619b-synology-${model}.dtb" + mkdir -p "${DebDevBuild}/image/files/sds-sii/dtbs/synology_rtd1619b_${model}/" + cp -vf "${DTBIMG}" "${DebDevBuild}/image/files/sds-sii/dtbs/synology_rtd1619b_${model}/model-vendor.dtb" + done +} + +# some platforms such as REALTEK_RTD1296, may need customized kernel image. +# please leave your customization here. +platform_customize_image() +{ + if [ "$PLATFORM_FAMILY" = "SYNOPLAT_F_X86_64" ]; then + : # do nothing + elif [ "$BUILD_TARGET" = "REALTEK_RTD1619B" ]; then + platform_customize_rtd1619b_image + else + : # customized by platform later + fi +} + diff --git a/SynoBuildConf/build b/SynoBuildConf/build new file mode 100644 index 000000000000..507323c23de0 --- /dev/null +++ b/SynoBuildConf/build @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +# shellcheck source=/dev/null +source "SynoBuildConf/_env" +source "SynoBuildConf/_kconfig" + + +case ${MakeClean:-} in + [Yy][Ee][Ss]) + make distclean + ;; +esac + +case ${CleanOnly:-} in + [Yy][Ee][Ss]) + return + ;; +esac + +build_public_key() +{ + # shellcheck disable=SC2154 + # lnxscripts/include/applyEnv: SysRootInclude="${ToolChainSysRoot}/usr/include" + # lnxscripts/include/platforms: KernelDir="/source/${SYNO_KERNEL_SOURCE_DIR}" + if [ "$PLATFORM_FAMILY" = "SYNOPLAT_F_X86_64" ]; then + ln -fsv "$SysRootInclude/hydrogen/hydrogen.h" "$KernelDir/include/crypto/hydrogen.h" + ln -fsv "$SysRootInclude/hydrogen/hydrogen.c" "$KernelDir/crypto/hydrogen/hydrogen.c" + ln -fsv "$SysRootInclude/hydrogen/impl" "$KernelDir/crypto/hydrogen/impl" + sed -i "s/__RAMDISK_SIGN_PUBLIC_KEY__/$(cat < "$ScriptsDir/config/rd_sign.pub" | xxd -i -c 32)/" \ + "$KernelDir/init/initramfs.c" + fi +} + +build_certification() +{ + ln -fsv "$ScriptsDir/config/signing_key.pem" "$KernelDir/synology/certs/signing_key.pem" + ln -fsv "$ScriptsDir/config/trusted_certificates.pem" "$KernelDir/synology/certs/trusted_certificates.pem" +} + +build_seed() +{ + # shellcheck disable=SC2154 + # lnxscripts/include/platforms: KernelDir="/source/${SYNO_KERNEL_SOURCE_DIR}" + if [ "$PLATFORM_FAMILY" = "SYNOPLAT_F_X86_64" ]; then + DECOMPRESSION_TYPE=$(shuf -i 1001-2147483647 -n 1) + sed -i "s/__DECOMPRESSION_TYPE__/${DECOMPRESSION_TYPE}/" \ + "${KernelDir}/arch/x86/boot/compressed/head_64.S" + sed -i "s/__DECOMPRESSION_TYPE__/${DECOMPRESSION_TYPE}/" \ + "${KernelDir}/lib/synolib/syno_kexec_test.c" + fi +} + +build_version() +{ + local _protect_ver _dsm_ver + + if [ -f "${VERSION_FILE:-/source/synoversion/VERSION}" ]; then + # originally ".version" is updated by scripts/link-vmlinux.sh + # we forcely overwrite it with DSM build number at every build. + echo $(($(GetDSMBuildNumber) - 1)) > ".version" + fi + + [ -f ".debug" ] || return + + _protect_ver="$(dpkg -l | grep "synoprotection-$PLATFORM_ABBR-" | awk '{print $3}' | cut -d'-' -f2 | head -n1)" + _dsm_ver="$(GetDSMBuildNumber)" + if [ -z "$_protect_ver" ]; then + ERROR "Unable to detect dpkg 'synoprotection'" + exit 1 + fi + if [ "$_dsm_ver" != "$_protect_ver" ]; then + ERROR "buildnumber in synoversion/VERSION doesn't match dpkg 'synoprotection'" + exit 1 + fi + +} + +# shellcheck disable=SC2086 +build_kernel() +{ + [ -f ".config" ] || return 1 + + make prepare $MAKE_FLAGS + make vmlinux $MAKE_FLAGS + make modules $MAKE_FLAGS + make "$(platform_target)" $MAKE_FLAGS + +} + +# shellcheck disable=SC2086 +build_device_tree() +{ + # Usually only arm platform needs this action + if [ "$BUILD_TARGET" = "REALTEK_RTD1619B" ]; then + make $MAKE_FLAGS dtbs + fi +} + + +INFO "Generate .config for architecture $ARCH platform $PLATFORM_ABBR" +kconfig_generate + +# INFO "Copying signing_key and certification from build system" +# build_certification + +# build_public_key +# build_seed +build_version + +INFO "Build Synology linux kernel $(make -s kernelversion)" +build_kernel + +INFO "Build device tree" +build_device_tree + +INFO "Compare kernel config with re-generated one" +kconfig_check_diff + +INFO "Check Synology kernel configs" +kconfig_check_syno_macro +kconfig_check_rule + diff --git a/SynoBuildConf/build-virtual-headers b/SynoBuildConf/build-virtual-headers new file mode 100644 index 000000000000..1812008d0871 --- /dev/null +++ b/SynoBuildConf/build-virtual-headers @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +# shellcheck source=/dev/null +source "SynoBuildConf/_env" +source "SynoBuildConf/_kconfig" + +kconfig_generate + +make prepare +make headers_install + +# `make headers_install` will deploy all headers (*.h) in "include/uapi" and +# "arch/$ARCH/include/uapi'. Please *DO NOT* copy the files one by one. Just +# place your headers at the right location. + diff --git a/SynoBuildConf/build-virtual-qctool b/SynoBuildConf/build-virtual-qctool new file mode 100644 index 000000000000..01e93e45bb01 --- /dev/null +++ b/SynoBuildConf/build-virtual-qctool @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +# shellcheck disable=SC2154 + +build_turbostat() +{ + # shellcheck disable=SC2086 + if [ "$PLATFORM_FAMILY" = "SYNOPLAT_F_X86_64" ]; then + case "$MakeClean" in + [Yy][Ee][Ss]) + make turbostat_clean -C tools + ;; + esac + make $MAKE_FLAGS turbostat -C tools + fi +} + +case "$CleanOnly" in + [Yy][Ee][Ss]) + return + ;; +esac + +env CC="$CC" CXX="$CXX" LD="$LD" AR="$AR" RANLIB="$RANLIB" NM="$NM" STRIP="$STRIP" \ + CROSS_COMPILE="$ToolChainPrefix" LDFLAGS="$LDFLAGS" \ + +build_turbostat diff --git a/SynoBuildConf/conflict b/SynoBuildConf/conflict new file mode 100644 index 000000000000..8d50740768c6 --- /dev/null +++ b/SynoBuildConf/conflict @@ -0,0 +1 @@ +linux-5.10.x="linux-4.4.x" diff --git a/SynoBuildConf/conflict-virtual-headers b/SynoBuildConf/conflict-virtual-headers new file mode 100644 index 000000000000..d8b1c5fdf67a --- /dev/null +++ b/SynoBuildConf/conflict-virtual-headers @@ -0,0 +1 @@ +linux-5.10.x-virtual-headers="linux-4.4.x-virtual-headers" diff --git a/SynoBuildConf/depends b/SynoBuildConf/depends new file mode 100644 index 000000000000..5ec80b7cfaeb --- /dev/null +++ b/SynoBuildConf/depends @@ -0,0 +1,2 @@ +[BuildDependent] +libhydrogen diff --git a/SynoBuildConf/depends-virtual-qctool b/SynoBuildConf/depends-virtual-qctool new file mode 100644 index 000000000000..067537d597b1 --- /dev/null +++ b/SynoBuildConf/depends-virtual-qctool @@ -0,0 +1,3 @@ +[BuildDependent-Tag] +${KernelHeaders} +libcap-2.x diff --git a/SynoBuildConf/error b/SynoBuildConf/error new file mode 100644 index 000000000000..41f04e977ba5 --- /dev/null +++ b/SynoBuildConf/error @@ -0,0 +1,3 @@ +{ + "warning:" : [" locale ", "dpkg: warning:"] +} diff --git a/SynoBuildConf/gitlab-ci b/SynoBuildConf/gitlab-ci new file mode 100644 index 000000000000..9fd773911869 --- /dev/null +++ b/SynoBuildConf/gitlab-ci @@ -0,0 +1,201 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +# shellcheck source=/dev/null +source "SynoBuildConf/_env" +source "SynoBuildConf/_kconfig" + +unset ARCH CROSS_COMPILE + +ci_help() +{ + cat <<-EOF +Usage: + $(basename "$0") + +Commands: + config + prepare + check-patch + check-sparse + check-smatch + check-syno-macro + check-syno-script + check-clang-format-diff + build-tools + build-ci-image + build-btf-image +EOF +} + +ci_config() +{ + cp -f "synology/synoconfigs/fst-ci-config" .config + make olddefconfig +} + +ci_prepare() +{ + [ -f ".config" ] || return 1 + + make prepare +} + +ci_check_sparse() +{ + env_check_command "sparse" || return + + make C=2 CHECK="$(command -v 'sparse')" -j "$(nproc)" +} + +ci_check_patch() +{ + if git remote show origin &>/dev/null; then + ./scripts/checkpatch.pl -g origin/HEAD..HEAD + else + ./scripts/checkpatch.pl -g HEAD~1..HEAD + fi +} + +ci_check_smatch() +{ + env_check_command "smatch" || return + + make C=2 CHECK="$(command -v 'smatch') -p=kernel" -j "$(nproc)" +} + +ci_check_coccinelle() +{ + env_check_command "spatch" || return + + make coccicheck MODE=report +} + +ci_check_syno_script() +{ + local _f + + env_check_command "shellcheck" || return + + while IFS= read -r _f; do + if ! shellcheck "$_f"; then + ERROR "'$_f' doesn't honor shellcheck" + return 1 + fi + done < <(find SynoBuildConf/ -regex '.*/\(gitlab-ci\|build.*\|install.*\|_.*\)'; + find synology/systemd/ -regex '.*/.*\.sh';) +} + +ci_check_syno_macro() +{ + kconfig_check_syno_macro +} + +ci_check_clang_format_diff() +{ + env_check_command "clang-format-diff" || return + + local _diff + + if git remote show origin &>/dev/null; then + _diff="$(git diff -U0 --no-color origin/HEAD..HEAD | clang-format-diff -p1)" + else + _diff="$(git diff -U0 --no-color HEAD~1..HEAD | clang-format-diff -p1)" + fi + + + if [ -n "$_diff" ]; then + echo "$_diff" + return 1 + fi +} + +ci_build_tools() +{ + local _tools _tool _failed + + # you need to install lots of dependency ... + _tools=" + acpi + bpf + cgroup + cpupower + debugging + firewire + firmware + freefall + gpio + hv + iio + intel-speed-select + leds + #liblockdep + objtool + pci + perf + #selftests + spi + tmon + turbostat + usb + #virtio + libapi + vm + wmi + x86_energy_perf_policy + " + + if env_detect_clang && env_detect_llvm; then + env_enable_clang + env_enable_llvm + INFO "Build with LLVM/Clang" + fi + + # FIXME: workaround for tools/bpf/runqslower bad detection + export VMLINUX_BTF="../../../vmlinux" + + while read -r _tool; do + [[ "$_tool" =~ ^[[:blank:]]*(#.*)?$ ]] && continue + + INFO "Build tools/$_tool" + if ! make "tools/$_tool"; then + _failed="$_failed $_tool" + fi + done <<< "$_tools" + + if [ -n "$_failed" ]; then + ERROR "failed to build tools: $_failed" + return 1 + fi +} + +ci_build_ci_image() +{ + make olddefconfig + make vmlinux modules -j "$(nproc)" +} + +ci_build_btf_image() +{ + if env_detect_clang && env_detect_llvm; then + env_enable_clang + env_enable_llvm + INFO "Build with LLVM/Clang" + fi + + # vmlinux with BTF is required for tools/bpf + ./scripts/config --enable CONFIG_DEBUG_INFO_BTF + + make olddefconfig + make vmlinux modules -j "$(nproc)" +} + +if [ -z "$1" ]; then + ci_help +elif type -p "ci_${1//-/_}"; then + cmd="${1//-/_}"; shift + ci_"$cmd" "$@" +else + ERROR "Command $1 not found" +fi + diff --git a/SynoBuildConf/install b/SynoBuildConf/install new file mode 100644 index 000000000000..73745d81b8f8 --- /dev/null +++ b/SynoBuildConf/install @@ -0,0 +1,386 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +# shellcheck source=/dev/null +source "SynoBuildConf/_env" + +TmpInstDir="${TmpInstDir:-/tmp/_install}" + +# Auto generate bootup insert module list config into /lib/modules-load.d/ +SYNOAutoGenerateModulesConfig () { + local _install_list=${1} + local _insert_list=${2} + local _config_name=${3} + local _mod="" + local _mod_path="" + + if [ -f ".synotmp-${_config_name}" ];then + rm -f ".synotmp-${_config_name}" + fi + + for _mod in ${_insert_list}; + do + _mod_path="/${_mod}.ko" + # Check the insert modules is really in install list + if [[ ${_install_list} == *${_mod_path}* ]]; then + echo "${_mod}" >> ".synotmp-${_config_name}" + else + echo "Error: insert module [${_mod}] not in install list" + fi + done + + if [ -f ".synotmp-${_config_name}" ];then + install -Dm644 ".synotmp-${_config_name}" "${KERNEL_MODULES_CONFIG_PATH}/${_config_name}" + fi +} + +install_systemd_units() +{ + KERNEL_MODULES_CONFIG_PATH=${TmpInstDir}/lib/modules-load.d + IPV6_COMMON_LIST="ipv6 ip_tunnel tunnel4 sit" + CRYPTO_MODULES_X86_64_COMMON_LIST="cbc md5 cts ansi_cprng des_generic authenc ecb sha256_generic cryptd libarc4 aesni-intel lzo lzo-rle zstd" + CPUFREQ_MODULES_X86_64_COMMON_LIST="acpi-cpufreq cpufreq_performance cpufreq_powersave" + MISC_MODULES_X86_64_COMMON_LIST="hmac md4 hfsplus llc p8022 psnap crc-ccitt crc-itu-t dm-bufio dm-snapshot sg loop essiv dm-crypt" + MISC_MODULES_ARM_64_COMMON_LIST="hmac md4 hfsplus llc p8022 psnap crc-ccitt crc-itu-t dm-bufio dm-snapshot sg loop" + USB_MODULES_COMMON_LIST="usb-common usbcore xhci-hcd" + + # shellcheck disable=SC2154 + if [ ! -f "$ConfDir/_modules" ]; then + echo "Error: Cannot find ${KERNEL_MODULES_TABLE} for generate insert modules list." + return + fi + # get platform $ModuleList + source "$ConfDir/_modules" + ModuleList=$(module_list) + [ -d "${KERNEL_MODULES_CONFIG_PATH}" ] || install -d "${KERNEL_MODULES_CONFIG_PATH}" + + # Set the white list on each platform, please not use global white list + case ${BUILD_TARGET} in + KVMX64) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net igbvf" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + KVMX64SOFS) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net igbvf" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + KVMX64V2) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net igbvf" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + BROADWELL) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + PURLEY) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST="${MISC_MODULES_X86_64_COMMON_LIST}" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + GEMINILAKE) + # Auto generate video driver conf into /lib/modules-load.d/video.conf + VIDEO_DRIVER_LIST="i2c-algo-bit button backlight video fbdev fb iosf_mbi drm_panel_orientation_quirks drm cfbimgblt cfbcopyarea cfbfillrect fb_sys_fops sysimgblt sysfillrect syscopyarea drm_kms_helper i915" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VIDEO_DRIVER_LIST}" "70-video-kernel.conf" + + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + ;; + V1000) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NET_DRIVER_MODULES_LIST="marvell10g amd-xgbe" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NET_DRIVER_MODULES_LIST}" "70-net-kernel.conf" + ;; + V1000SOFS) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NET_DRIVER_MODULES_LIST="marvell10g amd-xgbe" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NET_DRIVER_MODULES_LIST}" "70-net-kernel.conf" + ;; + REALTEK_RTD1619B) + + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST="lrw md4 ansi_cprng hmac des_generic cts md5 ghash-generic cbc ecb sha256_generic echainiv cmac ccm seqiv ctr libarc4" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST="cpufreq_performance cpufreq_powersave" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST=${MISC_MODULES_ARM_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} dwc3 xhci-pci xhci-plat-hcd phy-rtk-usb2 phy-rtk-usb3 dwc3_rtk rtk-usb-manager cdc-acm" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + ;; + ICELAKED) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST="${MISC_MODULES_X86_64_COMMON_LIST}" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + EPYC7002) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST="${MISC_MODULES_X86_64_COMMON_LIST}" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + EPYC7002SOFS) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST="${MISC_MODULES_X86_64_COMMON_LIST}" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + RYZEN5K) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST="${MISC_MODULES_COMMON_LIST}" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + + EPYC7003NTB) + IPV6_LIST=${IPV6_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${IPV6_LIST}" "70-ipv6-kernel.conf" + + CRYPTO_MODULES_LIST=${CRYPTO_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CRYPTO_MODULES_LIST}" "70-crypto-kernel.conf" + + CPUFREQ_MODULES_LIST=${CPUFREQ_MODULES_X86_64_COMMON_LIST} + SYNOAutoGenerateModulesConfig "${ModuleList}" "${CPUFREQ_MODULES_LIST}" "70-cpufreq-kernel.conf" + + MISC_MODULES_LIST="${MISC_MODULES_X86_64_COMMON_LIST}" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${MISC_MODULES_LIST}" "70-misc-kernel.conf" + + USB_MODULES_LIST="${USB_MODULES_COMMON_LIST} ehci-hcd ehci-pci uhci-hcd" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${USB_MODULES_LIST}" "70-usb-kernel.conf" + + VXLAN_MODULES="ip_tunnel udp_tunnel ip6_udp_tunnel vxlan" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${VXLAN_MODULES}" "69-docker-vxlan.conf" + + NETWORK_MODULES="be2net" + SYNOAutoGenerateModulesConfig "${ModuleList}" "${NETWORK_MODULES}" "70-network-kernel.conf" + ;; + *) + ;; + esac +} + +# module configs in /lib/modules-load.d +install_module_configs() +{ + SYSTEMD_UNIT_DIR="${TmpInstDir}/lib/systemd/system" + SYSTEMD_UNIT_SCRIPT_DIR="${TmpInstDir}/usr/syno/lib/systemd/scripts" + # install services unit of kernel module to systemd + [ -d "${SYSTEMD_UNIT_DIR}" ] || install -d "${SYSTEMD_UNIT_DIR}" + [ -d "${SYSTEMD_UNIT_DIR}"/sysinit.target.wants ] || install -d "${SYSTEMD_UNIT_DIR}"/sysinit.target.wants + [ -d "${SYSTEMD_UNIT_SCRIPT_DIR}" ] || install -d "${SYSTEMD_UNIT_SCRIPT_DIR}" + install -m644 synology/systemd/syno-kernel-modules-load.service "${SYSTEMD_UNIT_DIR}" + install -m755 synology/systemd/syno-kernel-modules-load.sh "${SYSTEMD_UNIT_SCRIPT_DIR}" + ln -s ../syno-kernel-modules-load.service "${SYSTEMD_UNIT_DIR}"/sysinit.target.wants/syno-kernel-modules-load.service + + install -m644 synology/systemd/syno-fan-modules-load.service "${SYSTEMD_UNIT_DIR}" + install -m755 synology/systemd/syno-fan-modules-load.sh "${SYSTEMD_UNIT_SCRIPT_DIR}" + ln -s ../syno-fan-modules-load.service "${SYSTEMD_UNIT_DIR}"/sysinit.target.wants/syno-fan-modules-load.service +} + +INFO "Install systemd units" +install_systemd_units + +INFO "Install kernel module configs" +install_module_configs + diff --git a/SynoBuildConf/install-dev b/SynoBuildConf/install-dev new file mode 100644 index 000000000000..e76849b5ce16 --- /dev/null +++ b/SynoBuildConf/install-dev @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +# shellcheck source=/dev/null +source "SynoBuildConf/_env" +source "SynoBuildConf/_modules" +source "SynoBuildConf/_platform" + +DebDevBuild="${DebDevBuild:-/deb/build}" + +install_dev_image() +{ + local _image + + # FIXME: moved to build ? + platform_customize_image + + _image="$(platform_image_name)" + if [ -z "$_image" ]; then + ERROR "image '$_image' not found" + return 1 + fi + + install -Dm644 "$_image" "$DebDevBuild/image/zImage" + install -Dm644 "vmlinux" "$DebDevBuild/image/synodebug/vmlinux" + install -Dm644 "System.map" "$DebDevBuild/image/synodebug/System.map" + install -Dm644 "Module.symvers" "$DebDevBuild/image/synodebug/Module.symvers" +} + +install_dev_modules() +{ + if [ ! -f "modules.order" ]; then + ERROR "'modules.order' not found" + return 1 + fi + + local _mod _mod_name + declare -A _built_modules + + while read -r _mod; do + _built_modules["$_mod"]= + done < "modules.order" + + for _mod in $(module_list); do + if [ ! -f "$_mod" ]; then + WARNING "Not found: $_mod" + continue + fi + + unset "_built_modules[$_mod]" + _mod_name="$(basename "$_mod")" + + install -Dm644 "$_mod" "$DebDevBuild/image/modules/$_mod_name" + install -Dm644 "$_mod" "$DebDevBuild/image/modulesdebug/$_mod_name" + $STRIP -d "$DebDevBuild/image/modules/$_mod_name" + done + + for _mod in "${!_built_modules[@]}"; do + WARNING "Not installed: $_mod" + done +} + +install_dev_kernel_devel() +{ + # shellcheck source=/dev/null + source "${ScriptsDir:-}/include/kernel-devel" + + # FIXME: get rid of "${ScriptsDir:-}/include/kernel-devel" + + # for kmsynoacl + install -Dm644 "fs/syno_acl.h" "$WRKDIR/fs/synoacl_int.h" + + install -Dm644 "include/linux/syno_fs.h" "$WRKDIR/include/linux/syno_fs.h" + + install -Dm644 "include/linux/syno_gpio.h" "$WRKDIR/include/linux/syno_gpio.h" + install -Dm644 "include/linux/syno_fdt.h" "$WRKDIR/include/linux/syno_fdt.h" + install -Dm755 "scripts/sign-file" "${DebDevBuild}/usr/syno/bin/sign-file" +} + + +INFO "Install kernel image for packing and debugging" +install_dev_image + +INFO "Install kernel modules for packing and debugging" +install_dev_modules + +INFO "Install stuff for kernel module development" +install_dev_kernel_devel + diff --git a/SynoBuildConf/install-dev-virtual-headers b/SynoBuildConf/install-dev-virtual-headers new file mode 100644 index 000000000000..523387b601bc --- /dev/null +++ b/SynoBuildConf/install-dev-virtual-headers @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +mkdir -p "${DebDevBuild:?undefined}/DEBIAN/" + +for _inc in ${ToolChainInclude32:=} ${ToolChainInclude64:=} ${StaticInclude32:=} ${StaticInclude64:=}; do + for _kinc in $(find "usr/include/"* -maxdepth 0 -type d -print | cut -d'/' -f3); do + mkdir -p "$DebDevBuild/$_inc/$_kinc" + cp -a "usr/include/$_kinc/"* "$DebDevBuild/$_inc/$_kinc" + done +done + diff --git a/SynoBuildConf/install-virinst-Satatool b/SynoBuildConf/install-virinst-Satatool new file mode 100644 index 000000000000..0d647b626f4d --- /dev/null +++ b/SynoBuildConf/install-virinst-Satatool @@ -0,0 +1,27 @@ +#!/bin/bash + +# shellcheck disable=SC2154 +if [ -e "${KernelDir}/lib/synolib/syno_sata_signal_check.ko" ]; then +install -Dm644 "${KernelDir}"/lib/synolib/syno_sata_signal_check.ko "${TmpInstDir}"/lib/modules/syno_sata_signal_check.ko +fi +if [ -e "${KernelDir}/lib/synolib/syno_sata_signal_test.ko" ]; then +install -Dm644 "${KernelDir}"/lib/synolib/syno_sata_signal_test.ko "${TmpInstDir}"/lib/modules/syno_sata_signal_test.ko +fi + +if [ -e "${KernelDir}/lib/synolib/syno_jmb585_update_spi.ko" ]; then + install -Dm644 "${KernelDir}"/lib/synolib/syno_jmb585_update_spi.ko "${TmpInstDir}"/lib/modules/syno_jmb585_update_spi.ko +fi + +if [ -e "${KernelDir}/lib/synolib/asm116xfwdl/asm116xfwdl.ko" ]; then + install -Dm644 "${KernelDir}"/lib/synolib/asm116xfwdl/asm116xfwdl.ko "${TmpInstDir}"/lib/modules/asm116xfwdl.ko +fi + +if [ -e "${KernelDir}/lib/synolib/syno_hddpwrctl_test.ko" ]; then + install -Dm644 "${KernelDir}"/lib/synolib/syno_hddpwrctl_test.ko "${TmpInstDir}"/lib/modules/syno_hddpwrctl_test.ko +fi + +if [ -e "${KernelDir}/lib/synolib/syno_ahci_reg_read_test.ko" ]; then + install -Dm644 "${KernelDir}"/lib/synolib/syno_ahci_reg_read_test.ko "${TmpInstDir}"/lib/modules/syno_ahci_reg_read_test.ko +fi + +exit 0 diff --git a/SynoBuildConf/install-virinst-T1tool b/SynoBuildConf/install-virinst-T1tool new file mode 100644 index 000000000000..e3e92bfc2b88 --- /dev/null +++ b/SynoBuildConf/install-virinst-T1tool @@ -0,0 +1,11 @@ +#!/bin/bash + +cpufreq_modules="freq_table cpufreq_stats cpufreq thermal_sys processor mperf acpi-cpufreq cpufreq_ondemand cpufreq_performance cpufreq_powersave cpufreq_conservative" + +# shellcheck disable=SC2154 +for module_name in $cpufreq_modules; do + module=$(find . -name "${module_name}".ko) + [ -e "${module}" ] && install -Dm644 "${module}" "${TmpInstDir}/lib/modules/${module_name}.ko" +done + +exit 0 diff --git a/SynoBuildConf/install-virtual-qctool b/SynoBuildConf/install-virtual-qctool new file mode 100644 index 000000000000..b15d160d8b46 --- /dev/null +++ b/SynoBuildConf/install-virtual-qctool @@ -0,0 +1,11 @@ +#!/bin/bash + +# shellcheck disable=SC2154 +if [ "$PLATFORM_FAMILY" != "SYNOPLAT_F_X86_64" ]; then + SkipThisProject + return +fi + +if [ -e "tools/power/x86/turbostat/turbostat" ]; then + install -Dm755 tools/power/x86/turbostat/turbostat "${TmpInstDir}"/turbostat +fi diff --git a/SynoBuildConf/shellcheck b/SynoBuildConf/shellcheck new file mode 100644 index 000000000000..bf0509ea76f2 --- /dev/null +++ b/SynoBuildConf/shellcheck @@ -0,0 +1 @@ +dsm: diff --git a/SynoBuildConf/version b/SynoBuildConf/version new file mode 100644 index 000000000000..e2293bff87a8 --- /dev/null +++ b/SynoBuildConf/version @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +make -s kernelversion diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 0207b6ea6e8a..ce8b04326352 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -1602,6 +1602,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code)); break; + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + break; /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 485b7dbd4f9e..55d185e346dd 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -150,7 +150,11 @@ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a # Default target when executing plain make boot := arch/arm64/boot +ifeq ($(CONFIG_SYNO_RTD1619B), y) +KBUILD_IMAGE := $(boot)/Image.lzma +else # CONFIG_SYNO_RTD1619B KBUILD_IMAGE := $(boot)/Image.gz +endif # CONFIG_SYNO_RTD1619B all: Image.gz diff --git a/arch/arm64/boot/dts/realtek/Makefile b/arch/arm64/boot/dts/realtek/Makefile index ef8d8fcbaa05..f6646124013d 100644 --- a/arch/arm64/boot/dts/realtek/Makefile +++ b/arch/arm64/boot/dts/realtek/Makefile @@ -13,3 +13,21 @@ dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-bpi-m4.dtb dtb-$(CONFIG_ARCH_REALTEK) += rtd1395-lionskin.dtb dtb-$(CONFIG_ARCH_REALTEK) += rtd1619-mjolnir.dtb +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) + +dtb-$(CONFIG_ARCH_REALTEK) += rtd1319-pymparticles-2gb.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd1319-rescue.dtb + +dtb-$(CONFIG_ARCH_REALTEK) += rtd1619b-bleedingedge-1gb-nas.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd1619b-bleedingedge-2gb-spi.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd1619b-bleedingedge-2gb.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd1619b-bleedingedge-4gb.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd1619b-rescue.dtb +endif # CONFIG_SYNO_LSP_RTD1619B +ifeq ($(CONFIG_SYNO_RTD1619B), y) +dtb-$(CONFIG_ARCH_REALTEK) += rtd-1619b-synology-ds223j.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd-1619b-synology-ds423.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd-1619b-synology-ds223.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd-1619b-synology-ds124.dtb +dtb-$(CONFIG_ARCH_REALTEK) += rtd-1619b-synology-mango.dtb +endif # CONFIG_SYNO_RTD1619B diff --git a/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds124.dts b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds124.dts new file mode 100644 index 000000000000..54991a527cf8 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds124.dts @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (1GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&pcie2 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + tx-drv = <0x40ab2001>, <0x40ab6001>, <0x40aba001>, + <0x12601a01>, <0x12605a01>, <0x126b9a01>; + status = "okay"; +}; + +&ahci_sata { + hostinit-mode = <1>; + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&rtk_pm { + wakeup-flags = <(LAN | GPIO | RTC | TIMER | CEC)>; + wakeup-gpio-list = <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_HIGH>; + wakeup-timer = <0>; + status = "okay"; +}; + +&i2c_1 { + rtc@68 { + compatible = "pericom,pt7c4337"; + reg = <0x68>; + wakeup-source; + }; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&nic { + led-cfg = <0x17000F00>; + eee = <0>; /* 0: disable, 1: enable */ +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223.dts b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223.dts new file mode 100644 index 000000000000..c76a5d99c74a --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223.dts @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (1GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x7ffc0000>; /* 1 GB */ + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&pcie2 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + tx-drv = <0x40ab2001>, <0x40ab6001>, <0x40aba001>, + <0x12601a01>, <0x12605a01>, <0x126b9a01>; + status = "okay"; +}; + +&sata_phy1 { + tx-drv = <0x40ab2001>, <0x40ab6001>, <0x40ada001>, + <0x12601a01>, <0x12605a01>, <0x126a9a01>; + status = "okay"; +}; + +&ahci_sata { + hostinit-mode = <1>; + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&sata_port1 { + status = "okay"; +}; + +&rtk_pm { + wakeup-flags = <(LAN | GPIO | RTC | TIMER | CEC)>; + wakeup-gpio-list = <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_HIGH>; + wakeup-timer = <0>; + status = "okay"; +}; + +&i2c_1 { + rtc@68 { + compatible = "pericom,pt7c4337"; + reg = <0x68>; + wakeup-source; + }; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&nic { + led-cfg = <0x17000F00>; + eee = <0>; /* 0: disable, 1: enable */ +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223j.dts b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223j.dts new file mode 100644 index 000000000000..369a3d3420ac --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds223j.dts @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (1GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&pcie2 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + tx-drv = <0x40ab2001>, <0x40ab6001>, <0x40aba001>, + <0x12601a01>, <0x12605a01>, <0x12659a01>; + status = "okay"; +}; + +&sata_phy1 { + tx-drv = <0x40ab2001>, <0x40ab6001>, <0x40aba001>, + <0x12601a01>, <0x12605a01>, <0x12609a01>; + status = "okay"; +}; + +&ahci_sata { + hostinit-mode = <1>; + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&sata_port1 { + status = "okay"; +}; + +&rtk_pm { + wakeup-flags = <(LAN | GPIO | RTC | TIMER | CEC)>; + wakeup-gpio-list = <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_HIGH>; + wakeup-timer = <0>; + status = "okay"; +}; + +&i2c_1 { + rtc@68 { + compatible = "pericom,pt7c4337"; + reg = <0x68>; + wakeup-source; + }; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&nic { + led-cfg = <0x17000F00>; + eee = <0>; /* 0: disable, 1: enable */ +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds423.dts b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds423.dts new file mode 100644 index 000000000000..92aa2ed22461 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-ds423.dts @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (2GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x7ffc0000>; /* 1 GB */ + }; +}; + +&pcie1 { + perst-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pcie2 { + perst-gpios = <&gpio 19 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&sata_phy { + status = "disabled"; +}; + +&sata_phy0 { + status = "disabled"; +}; + +&sata_phy1 { + status = "disabled"; +}; + +&ahci_sata { + status = "disabled"; +}; + +&sata_port0 { + status = "disabled"; +}; + +&sata_port1 { + status = "disabled"; +}; + +&rtk_pm { + wakeup-flags = <(LAN | GPIO | RTC | TIMER | CEC)>; + wakeup-gpio-list = <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_HIGH>; + wakeup-timer = <0>; + status = "okay"; +}; + +&i2c_1 { + rtc@68 { + compatible = "pericom,pt7c4337"; + reg = <0x68>; + wakeup-source; + }; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&nic { + led-cfg = <0x17000F00>; + eee = <0>; /* 0: disable, 1: enable */ + wol-enable = <1>; +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd-1619b-synology-mango.dts b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-mango.dts new file mode 100644 index 000000000000..891c12f0425c --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd-1619b-synology-mango.dts @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (1GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&pcie2 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + tx-drv = <0x40ab2001>, <0x40ab6001>, <0x40aba001>, + <0x12601a01>, <0x12605a01>, <0x126b9a01>; + status = "okay"; +}; + +&ahci_sata { + hostinit-mode = <1>; + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&rtk_pm { + wakeup-flags = <(LAN | GPIO | RTC | TIMER | CEC)>; + wakeup-gpio-list = <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_HIGH>; + wakeup-timer = <0>; + status = "okay"; +}; + +&i2c_1 { + s35390a: s35390a@30 { + status = "ok"; + compatible = "sii,s35390a"; + reg = <0x30>; + }; + +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&nic { + led-cfg = <0x1700042F>; + eee = <0>; /* 0: disable, 1: enable */ +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; +&iso { + pwm: pwm@d0 { + pwm_1 { + enable = <1>; + clkout_div = <0xff>; + clksrc_div = <0xf>; + duty_rate = <50>; /* HW active low */ + }; + pwm_2 { + enable = <1>; + clkout_div = <0xff>; + clksrc_div = <0xf>; + duty_rate = <100>; /* HW active low */ + }; + }; +}; +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm1_0_pins>, + <&pwm2_0_pins>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1319-pymparticles-2gb.dts b/arch/arm64/boot/dts/realtek/rtd1319-pymparticles-2gb.dts new file mode 100644 index 000000000000..80c382663be0 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1319-pymparticles-2gb.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1319-pymparticles.dtsi" + +/ { + compatible = "realtek,pym-particles", "realtek,rtd1319"; + model = "Realtek Pym Particles EVB (2GB, TEE)"; + + memory@40000 { + device_type = "memory"; + reg = <0x00004000 0x7fffc000>; /* 2 GiB */ + }; + + chosen { + linux,initrd-start = <0x03100000>; + linux,initrd-end = <0x03500000>; + bootargs = "earlycon=uart8250,mmio32,0x98007800 console=ttyS0,460800 init=/init loop.max_part=7 androidboot.storage=emmc androidboot.hardware=hank"; + }; +}; + +&pcie { + status = "disabled"; +}; + +&pcie1 { + status = "disabled"; +}; + +&pcie2 { + workaround = <1>; + status = "okay"; +}; + +&pcie_trans { + status = "okay"; +}; + +&rfkill { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + diff --git a/arch/arm64/boot/dts/realtek/rtd1319-pymparticles.dtsi b/arch/arm64/boot/dts/realtek/rtd1319-pymparticles.dtsi new file mode 100644 index 000000000000..098de1048a00 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1319-pymparticles.dtsi @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include +#include +#include +#include + +#include "rtd13xx.dtsi" + +/ { + compatible = "realtek,pym-particles", "realtek,rtd1319"; + model = "Realtek Pym Particles EVB"; + + memory@40000 { + device_type = "memory"; + reg = <0x00040000 0x7ffc0000>; /* boot ROM to 1 GiB or 2 GiB */ + }; + + chosen { + stdout-path = "serial0:460800n8"; + }; +}; + +/* debug console (J1) */ +&uart0 { + status = "okay"; +}; + +/* M.2 slot (CON8) */ +&uart1 { + status = "disabled"; +}; + +/* GPIO connector (T1) */ +&uart2 { + status = "disabled"; +}; + +/* PMIC */ +&i2c_0 { + clock-frequency = <3400000>; + pinctrl-0 = <&i2c_pins_0_HS>; + status = "okay"; + + apw8886: apw8886@12 { + compatible = "anpec,apw8886"; + reg = <0x12>; + + regulators: regulators { + compatible = "anpec,apw8886-regulator"; + }; + + }; +}; + +&i2c_1 { + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c_3 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&reboot_mode { + status = "okay"; +}; + +&reboot { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&nic { + status = "okay"; +}; + +&spi_0 { + status = "okay"; +}; + +&pwm { + status = "okay"; +}; + + +&i2c_3 { + status = "okay"; +}; + +&emmc { + status = "okay"; +}; + +&sd { + status = "okay"; +}; + +&sdio { + bus-width = <4>; + non-removable; + cap-sd-highspeed; + cap-mmc-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + keep-power-in-suspend; + enable-sdio-wakeup; + no-sd; + no-mmc; + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + status = "okay"; +}; + +&sata_phy1 { + status = "disabled"; +}; + +&ahci_sata { + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&sata_port1 { + status = "disabled"; +}; + +&rng { + status = "okay"; +}; + +&hse { + status = "okay"; +}; + +&cp { + status = "okay"; +}; + +&ve1 { + status = "okay"; +}; + +&jpeg { + status = "okay"; +}; + +&apw8886 { + regulators { + vd33_supp: dc1 { + regulator-name = "vd33"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <3777500>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + core_supp: dc2 { + regulator-name = "core"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1337500>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + cpu_supp: dc3 { + regulator-name = "cpudvs"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1337500>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-ramp-delay = <625>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vd18_supp: dc4 { + regulator-name = "vd18"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2060000>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + ddr_supp: dc5 { + regulator-name = "ddr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + }; + regulator-state-shutdown { + regulator-off-in-suspend; + }; + }; + + vd25_supp: ldo1 { + regulator-name = "vd25"; + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <3020000>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vfb5 { + regulator-name = "vfb5"; + regulator-min-microvolt = <512500>; + regulator-max-microvolt = <700000>; + + regulator-boot-on; + regulator-always-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + }; +}; + +&usb_manager { + status = "okay"; + + rtk_usb { + pcie_usb3phy_sel = <0x9800705c>; /* Only for RTD1319 */ + type_c { + /* For 1319, u3drd */ + realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + + }; +}; + +&dwc3_u2drd { + status = "okay"; + + dwc3_u2drd@98020000 { + dr_mode = "host"; /*host, peripheral*/ + status = "okay"; + }; + /delete-node/rtk_dwc3_type_c; +}; + +&dwc3_u2host { + status = "okay"; +}; + +&dwc3_u3drd { + status = "okay"; + + dwc3_u3drd@981f0000 { + dr_mode = "peripheral"; /*host, peripheral*/ + status = "okay"; + }; + + rtk_dwc3_type_c@98007220 { + status = "okay"; + }; +}; + +&cpu0 { + clocks = <&cc RTD1319_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu1 { + clocks = <&cc RTD1319_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu2 { + clocks = <&cc RTD1319_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu3 { + clocks = <&cc RTD1319_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu_dvfs { + fss,opp-updated = <0>; + fss,volt-correct = <12500 12500 12500>; + fss,volt-step = <25000>; + fss,volt-min = <850000>; + fss,volt-max = <1100000>; + + cpu_opps: cpu-opp-table { + compatible = "operating-points-v2"; + opp-shared; + opp600: opp-600mhz { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <862500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp700: opp-700mhz { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <887500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp800: opp-800mhz { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <912500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp900: opp-900mhz { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <937500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp1000: opp-1000mhz { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <962500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp1100: opp-1100mhz { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <987500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + opp-suspend; + status = "okay"; + }; + opp1200: opp-1200mhz { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1012500>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp1300: opp-1300mhz { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + opp1400: opp-1400mhz { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <1100000>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + }; +}; + +&usb_manager { + status = "okay"; + + rtk_usb { + pcie_usb3phy_sel = <0x9800705c>; /* Only for RTD1319 */ + type_c { + /* For 1319, u3drd */ + realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + + }; +}; + +&dwc3_u2drd { + status = "okay"; + + dwc3_u2drd@98020000 { + dr_mode = "host"; /*host, peripheral*/ + status = "okay"; + }; +}; + +&dwc3_u2host { + status = "okay"; +}; + +&dwc3_u3drd { + status = "okay"; + + dwc3_u3drd@981f0000 { + dr_mode = "peripheral"; /*host, peripheral*/ + status = "okay"; + }; + +}; + +&rtk_type_c { + status = "okay"; + + dwc3_rtk = <&dwc3_u3drd>; +}; + +&cpu_thermal { + trips { + cpu_alert0: cpu-alert0 { + temperature = <90000>; + hysteresis = <0>; + type = "passive"; + }; + cpu_alert1: cpu-alert1 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + cpu-map0 { + trip = <&cpu_alert0>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT 3>; + contribution = <70>; + }; + cpu-map1 { + trip = <&cpu_alert1>; + cooling-device = <&cpu0 4 THERMAL_NO_LIMIT>; + contribution = <70>; + }; + }; +}; + +&vcpu { + status = "okay"; +}; + +&rtk_fw_pm { + status = "okay"; +}; + +&rtk_pm { + wakeup-flags = ; + wakeup-gpio-list = <11 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>; + wakeup-timer = <0>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1319-rescue.dts b/arch/arm64/boot/dts/realtek/rtd1319-rescue.dts new file mode 100644 index 000000000000..060254f1291c --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1319-rescue.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd13xx-rescue.dtsi" + +/ { + model = "Realtek RTD1319 Rescue"; + + memory@40000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; + + chosen { + stdout-path = "serial0:460800n8"; + bootargs = "earlycon=uart8250,mmio32,0x98007800 console=ttyS0,460800 init=/init androidboot.storage=emmc androidboot.hardware=hank"; + }; +}; + diff --git a/arch/arm64/boot/dts/realtek/rtd13xx-efuse.dtsi b/arch/arm64/boot/dts/realtek/rtd13xx-efuse.dtsi new file mode 100644 index 000000000000..2e30b10a2f5c --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd13xx-efuse.dtsi @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019-2020 Realtek Semiconductor Corporation + */ +&efuse { + otp_chip_id: chip-id@3cc { + reg = <0x3cc 0x10>; + }; + otp_secure_chip_en: secure-chip-en@3fd { + reg = <0x3fd 0x1>; + bits = <2 3>; + }; + otp_bist_rst_ctrl: bist-rst-ctrl@406 { + reg = <0x406 0x1>; + bits = <5 2>; + }; + otp_uuid: uuid@478 { + reg = <0x478 0xc>; + }; + otp_bond_id: bond-id@4f4 { + reg = <0x4f4 0x4>; + }; + otp_iddq: iddq@4f8 { + reg = <0x4f8 0x2>; + }; + otp_etn_para: etn-para@4fc { + reg = <0x4fc 0x1>; + bits = <0 5>; + }; + otp_etn_idac: etn-idac@500 { + reg = <0x500 0x1>; + }; + otp_cpu_dss: cpu-dss@514 { + reg = <0x514 0x13>; + bits = <0 148>; + }; + otp_usb_cal: usb-cal@528 { + reg = <0x528 0xa>; + bits = <0 77>; + }; + otp_usb_port0_dc_cal: usb-port0-dc-cal@534 { + reg = <0x534 0x1>; + bits = <0 4>; + }; + otp_usb_port1_dc_cal: usb-port1-dc-cal@534 { + reg = <0x534 0x1>; + bits = <4 4>; + }; + otp_usb_port2_dc_cal: usb-port2-dc-cal@535 { + reg = <0x535 0x1>; + bits = <0 4>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd13xx-pcie.dtsi b/arch/arm64/boot/dts/realtek/rtd13xx-pcie.dtsi new file mode 100644 index 000000000000..e277eabf506a --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd13xx-pcie.dtsi @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek RTD13xx SoC family + * + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +&rbus { + pcie: pcie@60000 { + compatible = "realtek,rtd13xx-pcie-slot1", "syscon"; + reg = <0x60000 0x00001000>; + syscon = <&iso>; + interrupt-names = "rtk-pcie0-intr"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 61 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clk_pins_0>; + bus-range = <0x00 0xff>; + linux,pci-domain = <0>; + device_type = "pci"; + perst-gpios = <&gpio 19 GPIO_ACTIVE_HIGH>; + #size-cells = <2>; + #address-cells = <3>; + num-lanes = <1>; + phys = <&pcie0_phy>; + speed-mode = <1>; // 0:GEN1, 1:GEN2 + debug-mode = <0>; + ranges = <0x02000000 0x0 0x98062000 0x00062000 0x0 0x0001E000 + 0x01000000 0x0 0x00030000 0x10030000 0x0 0x00010000>; + resets = <&cc RTD1319_CRT_RSTN_PCIE0>, + <&cc RTD1319_CRT_RSTN_PCIE0_CORE>, + <&cc RTD1319_CRT_RSTN_PCIE0_POWER>, + <&cc RTD1319_CRT_RSTN_PCIE0_NONSTITCH>, + <&cc RTD1319_CRT_RSTN_PCIE0_STITCH>, + <&cc RTD1319_CRT_RSTN_PCIE0_SGMII_MDIO>; + + reset-names = "rstn", + "core", + "power", + "nonstitch", + "stitch", + "sgmii_mdio"; + clocks = <&cc RTD1319_CRT_CLK_EN_PCIE0>; + status = "disabled"; + }; + + pcie1: pcie@a0000 { + compatible = "realtek,rtd13xx-pcie-slot1", "syscon"; + reg = <0xA0000 0x00001000>; + syscon = <&m2tmx>; + interrupt-names = "rtk-pcie1-intr"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 62 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clk_pins_1>; + bus-range = <0x00 0xff>; + linux,pci-domain = <1>; + device_type = "pci"; + perst-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>; + #size-cells = <2>; + #address-cells = <3>; + num-lanes = <1>; + phys = <&pcie1_phy>; + speed-mode = <1>; // 0:GEN1, 1:GEN2 + debug-mode = <0>; + ranges = <0x03000000 0x0 0x980A2000 0x000A2000 0x0 0x0001E000 + 0x01000000 0x0 0x00040000 0x10040000 0x0 0x00010000>; + workaround = <0>; + workaround-ranges = <0x03000000 0x0 0xC0000000 0xC0000000 0x0 0x00100000 + 0x01000000 0x0 0x00040000 0x10040000 0x0 0x00010000>; + resets = <&cc RTD1319_CRT_RSTN_PCIE1>, + <&cc RTD1319_CRT_RSTN_PCIE1_CORE>, + <&cc RTD1319_CRT_RSTN_PCIE1_POWER>, + <&cc RTD1319_CRT_RSTN_PCIE1_NONSTITCH>, + <&cc RTD1319_CRT_RSTN_PCIE1_STITCH>; + + reset-names = "rstn", + "core", + "power", + "nonstitch", + "stitch"; + clocks = <&cc RTD1319_CRT_CLK_EN_PCIE1>; + status = "okay"; + }; + + pcie2: pcie@c0000 { + compatible = "realtek,rtd13xx-pcie-slot2", "syscon"; + reg = <0xC0000 0x00001000>; + syscon = <&m2tmx>; + interrupt-names = "rtk-pcie2-intr"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 62 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clk_pins_2>; + bus-range = <0x00 0xff>; + linux,pci-domain = <2>; + device_type = "pci"; + perst-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>; + #size-cells = <2>; + #address-cells = <3>; + num-lanes = <1>; + phys = <&pcie2_phy>; + speed-mode = <1>; // 0:GEN1, 1:GEN2 + debug-mode = <0>; + ranges = <0x02000000 0x0 0x980C2000 0x000C2000 0x0 0x0001E000 + 0x01000000 0x0 0x00050000 0x10050000 0x0 0x00010000>; + workaround = <0>; + workaround-ranges = <0x02000000 0x0 0xC1000000 0xC1000000 0x0 0x00100000 + 0x01000000 0x0 0x00050000 0x10050000 0x0 0x00010000>; + resets = <&cc RTD1319_CRT_RSTN_PCIE2>, + <&cc RTD1319_CRT_RSTN_PCIE2_CORE>, + <&cc RTD1319_CRT_RSTN_PCIE2_POWER>, + <&cc RTD1319_CRT_RSTN_PCIE2_NONSTITCH>, + <&cc RTD1319_CRT_RSTN_PCIE2_STITCH>; + + reset-names = "rstn", + "core", + "power", + "nonstitch", + "stitch"; + clocks = <&cc RTD1319_CRT_CLK_EN_PCIE2>; + status = "okay"; + }; + + pcie_trans: pcie_trans@70000 { + compatible = "realtek,rtd13xx-pcie-trans"; + reg = <0x70000 0x10000>, + <0xb0000 0x10000>, + <0xd0000 0x10000>; + syscon = <&pcie>, + <&pcie1>, + <&pcie2>; + status = "disabled"; + }; +}; + +/ { + pcie0_phy: pcie0_phy { + compatible = "realtek,rtd13xx-pcie-slot0-phy"; + syscon = <&pcie>; + resets = <&cc RTD1319_CRT_RSTN_PCIE0_PHY>, + <&cc RTD1319_CRT_RSTN_PCIE0_PHY_MDIO>; + reset-names = "phy", + "phy_mdio"; + #phy-cells = <0>; + status = "okay"; + }; + + pcie1_phy: pcie1_phy { + compatible = "realtek,rtd13xx-pcie-slot1-phy"; + syscon = <&pcie1>; + resets = <&cc RTD1319_CRT_RSTN_PCIE1_PHY>, + <&cc RTD1319_CRT_RSTN_PCIE1_PHY_MDIO>; + reset-names = "phy", + "phy_mdio"; + #phy-cells = <0>; + status = "okay"; + }; + + pcie2_phy: pcie2_phy { + compatible = "realtek,rtd13xx-pcie-slot2-phy"; + syscon = <&pcie2>; + resets = <&cc RTD1319_CRT_RSTN_PCIE2_PHY>, + <&cc RTD1319_CRT_RSTN_PCIE2_PHY_MDIO>; + reset-names = "phy", + "phy_mdio"; + #phy-cells = <0>; + status = "okay"; + }; + +}; diff --git a/arch/arm64/boot/dts/realtek/rtd13xx-pinctrl.dtsi b/arch/arm64/boot/dts/realtek/rtd13xx-pinctrl.dtsi new file mode 100644 index 000000000000..73205d908e97 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd13xx-pinctrl.dtsi @@ -0,0 +1,503 @@ +&pinctrl { + sdcard_pins_low: sdcard_low { + pins= "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function="sd"; + bias-pull-down; + }; + + sdcard_pins_high: sdcard_high { + pins="gpio_35", "gpio_34"; + function="mmc"; + bias-pull-up; + }; + + sdio_pins_0: sdio_pins_0 { + pins= "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk", + "sdio_loc"; + function = "sdio_loc0"; + }; + + sdio_pins_1: sdio_pins_1 { + pins = "gpio_40", + "gpio_41", + "gpio_42", + "gpio_43", + "gpio_44", + "gpio_45", + "sdio_loc"; + function = "sdio_loc1"; + }; + + rgmii_mdio_pins: rgmii_mdio_pins { + pins = "gpio_14", + "gpio_15"; + function = "rgmii"; + }; + + rgmii_txrx_pins: rgmii_txrx_pins { + pins = "gpio_65", + "gpio_66", + "gpio_67", + "gpio_68", + "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72", + "gpio_73", + "gpio_74", + "gpio_75", + "gpio_76"; + function = "rgmii"; + }; + + uart0_pins: uart0_pins { + pins = "ur0_rx", + "ur0_tx"; + function = "uart0"; + }; + + uart1_pins: uart1_pins { + pins = "gpio_8", + "gpio_9"; + function = "uart1"; + }; + + uart2_pins_0: uart2_pins_0 { + pins = "ur2_loc", + "gpio_18", + "gpio_19"; + function = "uart2_loc0"; + }; + + uart2_pins_1: uart2_pins_1 { + pins ="ur2_loc", + "gpio_26", + "gpio_27"; + function = "uart2_loc1"; + }; + + i2c_pins_0: i2c_pins_0 { + pins = "gpio_12", + "gpio_13"; + function = "i2c0"; + drive-strength = <4>; + }; + + i2c_pins_0_HS: i2c_pins_0_HS { + pins = "gpio_12", + "gpio_13"; + function = "i2c0"; + drive-strength = <8>; + }; + + i2c_pins_1: i2c_pins_1 { + pins = "gpio_16", + "gpio_17"; + function = "i2c1"; + }; + + + i2c_pins_3: i2c_pins_3 { + pins = "gpio_63", + "gpio_64"; + function = "i2c3"; + }; + + + i2c_pins_5: i2c_pins_5 { + pins = "gpio_29", + "gpio_46"; + function = "i2c5"; + }; + + spi_pins_enable: spi-pins-enable { + pins = "sf_en"; + function = "sf_enable"; + }; + + spi_pins_loc_spi: spi_pins_loc_spi { + pins = "spi_ce_n", + "spi_sck", + "spi_so", + "spi_si"; + function = "spi"; + }; + + gspi_pins_0: gspi_pins_0 { + pins = "gspi_loc", + "gpio_18", + "gpio_19", + "gpio_20", + "gpio_31"; + function = "gspi_loc0"; + }; + + gspi_pins_1: gspi_pins_1 { + pins = "gspi_loc", + "gpio_8", + "gpio_9", + "gpio_10", + "gpio_11"; + function = "gspi_loc1"; + }; + + iso_gspi_pins_0: iso_gspi_pins_0 { + pins = "iso_gspi_loc", + "gpio_18", + "gpio_19", + "gpio_20", + "gpio_31"; + function = "iso_gspi_loc0"; + }; + + iso_gspi_pins_1: iso_gspi_pins_1 { + pins = "iso_gspi_loc", + "gpio_8", + "gpio_9", + "gpio_10", + "gpio_11"; + function = "iso_gspi_loc1"; + }; + + smartcard_pins_0:smartcard_pins_0{ + pins = "gpio_18", + "gpio_19", + "gpio_20", + "gpio_31"; + function = "sc0"; + }; + + smartcard_pins_1:smartcard_pins_1{ + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5"; + function = "sc1"; + }; + + tp_common_pins: tp-common-pins { + pins = "gpio_66", + "gpio_67", + "gpio_68", + "gpio_73", + "gpio_74", + "gpio_75", + "gpio_76"; + function = "tp0"; + }; + + tp0_parallel_pins: tp0-parallel-pins { + pins = "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72"; + function = "tp0"; + }; + + tp1_serial_pins: tp1-serial-pins { + pins = "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72"; + function = "tp1"; + }; + + ao_pins: ao_pins { + pins = "gpio_66", + "gpio_67", + "gpio_68", + "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72"; + function = "ao"; + }; + + ao_pins_1: ao_pins_1 { + pins = "gpio_66", + "gpio_67", + "gpio_68", + "gpio_69"; + function = "ao"; + }; + + ir_rx_pins: ir_rx_pins { + pins = "ir_rx"; + function = "ir_rx"; + }; + + spdif_pins: spdif_pins { + pins = "gpio_50"; + function = "spdif"; + }; + + /*spdif_optical_pins: spdif_optical_pins { + pins = "gpio_21", "gpio_68", "gpio_85"; + function = "spdif"; + pull_en = <0>; + };*/ + + ai_loc0_pins: ai_loc0_pins { + pins = "gpio_57", + "gpio_58", + "gpio_59", + "gpio_60", + "gpio_61", + "gpio_62", + "gpio_63"; + function = "ai_loc0"; + }; + + ai_loc1_pins: ai_loc1_pins { + pins = "gpio_32", + "gpio_33", + "gpio_34", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function = "ai_loc1"; + }; + + dmic_loc0_pins: dmic_loc0_pins { + pins = "dmic_loc", + "gpio_57", + "gpio_58", + "gpio_59", + "gpio_60", + "gpio_61", + "gpio_62", + "gpio_63", + "gpio_64"; + function = "dmic_loc0"; + }; + + dmic_loc1_pins: dmic_loc1_pins { + pins = "dmic_loc", + "gpio_32", + "gpio_33", + "gpio_34", + "gpio_35", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function = "dmic_loc1"; + }; + + tdm_loc0_pins: tdm_loc0_pins { + pins = + "gpio_57", + "gpio_58", + "gpio_59", + "gpio_60"; + function = "tdm_ai_loc0"; + }; + + + tdm_loc1_pins: tdm_loc1_pins { + pins = + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function = "tdm_ai_loc1"; + }; + + + /*i2s_out_4pins: i2s_out_4pins { + pins ="tp_data_1", + "tp_data_2", + "tp_data_3", + "tp_data_4"; + function = "ao"; + };*/ + + /*i2s_in_pins: i2s_in_pins { + pins = "gpio_6"; + function = "ai"; + };*/ + + etn_led_pins: etn_led_pins { + pins = "gpio_14", + "gpio_15"; + function = "etn_led"; + }; + + + pcie_clk_pins_0: pcie_clk_pins_0 { + pins = "gpio_46"; + function = "pcie0"; + }; + + pcie_clk_pins_1: pcie_clk_pins_1 { + pins = "gpio_25"; + function = "pcie1"; + }; + + pcie_clk_pins_2: pcie_clk_pins_2 { + pins = "gpio_52"; + function = "pcie2"; + }; + + scpu_ejtag_pins_loc_0: scpu_ejtag_pins_loc_0 { + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5", + "gpio_6", + "ejtag_scpu_loc"; + function = "scpu_ejtag_loc0"; + }; + + scpu_ejtag_pins_loc_1: scpu_ejtag_pins_loc_1 { + pins = "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_clk", + "ejtag_scpu_loc"; + function = "scpu_ejtag_loc1"; + }; + + scpu_ejtag_pins_disable: scpu_ejtag_pins_disable { + pins = "ejtag_scpu_loc"; + function = "scpu_ejtag_disable"; + }; + + acpu_ejtag_pins_loc_0: acpu_ejtag_pins_loc_0 { + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5", + "gpio_6", + "ejtag_acpu_loc"; + function = "acpu_ejtag_loc0"; + }; + + acpu_ejtag_pins_loc_1: acpu_ejtag_pins_loc_1 { + pins = "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_clk", + "ejtag_acpu_loc"; + function = "acpu_ejtag_loc1"; + }; + + acpu_ejtag_pins_disable:acpu_ejtag_pins_disable{ + pins = "ejtag_acpu_loc"; + function = "acpu_ejtag_disable"; + }; + + vcpu_ejtag_pins_loc_0: avpu_ejtag_pins_loc_0 { + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5", + "gpio_6", + "ejtag_vcpu_loc"; + function = "vcpu_ejtag_loc0"; + }; + + vcpu_ejtag_pins_loc_1: vcpu_ejtag_pins_loc_1 { + pins = "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_clk", + "ejtag_vcpu_loc"; + function = "vcpu_ejtag_loc1"; + }; + + vcpu_ejtag_pins_disable:vcpu_ejtag_pins_disable{ + pins = "ejtag_vcpu_loc"; + function = "vcpu_ejtag_disable"; + }; + + dc_fan_sensor_pins: dc_fan_sensor_pins { + pins = "gpio_47"; + function = "dc_fan"; + }; + + pwm0_0_pins: pwm0_0_pins { + pins = "gpio_12"; + function = "pwm0"; + }; + + pwm0_1_pins: pwm0_1_pins { + pins = "gpio_20"; + function = "pwm0"; + }; + + pwm1_0_pins: pwm1_0_pins { + pins = "gpio_13"; + function = "pwm1"; + }; + + pwm1_1_pins: pwm1_1_pins { + pins = "gpio_21"; + function = "pwm1"; + }; + + pwm2_0_pins: pwm2_0_pins { + pins = "gpio_14"; + function = "pwm2"; + }; + + pwm2_1_pins: pwm2_1_pins { + pins = "gpio_22"; + function = "pwm2"; + }; + + pwm3_0_pins: pwm3_0_pins { + pins = "gpio_15"; + function = "pwm3"; + }; + + pwm3_1_pins: pwm3_1_pins { + pins = "gpio_23"; + function = "pwm3"; + }; + + usb_cc1_pins: usb_cc1_pins { + pins = "usb_cc1"; + function = "usb_cc1"; + }; + + usb_cc2_pins: usb_cc2_pins { + pins = "usb_cc2"; + function = "usb_cc2"; + }; + + demod_pins: demod-pins { + pins = "gpio_21"; + function = "qam_agc_if"; + }; + + /*rtc_pins: rtc_pins { + pins = "gpio_25"; + function = "rtc"; + };*/ + + /*prob0_pins: prob0_pins{ + pins = "prob_0"; + function = "gpio"; + }; + + prob1_pins: prob1_pins{ + pins = "prob_1"; + function = "gpio"; + };*/ +}; + diff --git a/arch/arm64/boot/dts/realtek/rtd13xx-rescue.dtsi b/arch/arm64/boot/dts/realtek/rtd13xx-rescue.dtsi new file mode 100644 index 000000000000..233e81c5c0bc --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd13xx-rescue.dtsi @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd13xx.dtsi" +#include + +/ { + model = "Realtek Rescue"; + + memory@40000 { + device_type = "memory"; + reg = <0x00004000 0x7fffc000>; /* boot ROM to 1 GiB or 2 GiB */ + }; + + chosen { + linux,initrd-start = <0x03100000>; + linux,initrd-end = <0x03d00000>; + }; +}; + +/* debug console (J1) */ +&uart0 { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&nic { + status = "okay"; +}; + +&emmc { + hs400_force_tuning = <0x1>; + status = "okay"; +}; + +&cp { + status = "okay"; +}; + +&usb_manager { + status = "okay"; + + rtk_usb { + pcie_usb3phy_sel = <0x9800705c>; /* Only for RTD1319 */ + type_c { + /* For 1319, u3drd */ + realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + + }; +}; + +&dwc3_u2drd { + status = "okay"; + + dwc3_u2drd@98020000 { + dr_mode = "host"; /*host, peripheral*/ + status = "okay"; + }; +}; + +&dwc3_u2host { + status = "okay"; +}; + +&dwc3_u3drd { + status = "okay"; + + dwc3_u3drd@981f0000 { + dr_mode = "peripheral"; /*host, peripheral*/ + status = "okay"; + }; +}; + +&rtk_type_c { + status = "okay"; + + dwc3_rtk = <&dwc3_u3drd>; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&psci { + status = "disabled"; +}; + +&rtk_pm { + wakeup-flags = ; + wakeup-gpio-list = <2 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <4 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>; + wakeup-timer = <0>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd13xx-usb.dtsi b/arch/arm64/boot/dts/realtek/rtd13xx-usb.dtsi new file mode 100644 index 000000000000..d75ac1d4363e --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd13xx-usb.dtsi @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek RTD13xx SoC USB + * + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/ { + usb_manager: rtk_usb_manager { + compatible = "realtek,usb-manager"; + + //usb_iso_mode; /* ISO mode is only port suspend (Default disable) */ + //en_usb_storage_reprobe; /* To enable usb storage re-probe*/ + //rescue_usb; /* For rescue dtb use */ + + status = "disabled"; + + gpio0: gpio0 { + realtek,power-gpio = <&gpio 48 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + gpio1: gpio1 { + realtek,power-gpio = <&gpio 49 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + port0 { + usb = <&dwc3_u2drd>; + usb_gpio = <&gpio0>; + }; + + port1 { + usb = <&dwc3_u2host>; + usb_gpio = <&gpio0>; + }; + + port2 { + usb = <&dwc3_u3drd>; + usb_gpio = <&gpio1>; + }; + + rtk_usb { + //pcie_usb3phy_sel = <0x9800705c>; /* Only for RTD1319 */ + + power_ctrl_reg { + /* l4_icg */ + p0_l4_icg = <0x98013364>; + p1_l4_icg = <0x98013d60>; + p2_l4_icg = <0x98013f60>; + + usb_power_cut; /* Non ISO mode and power cut (Default disable power cut) */ + /* Note if enable ISO mode, then power_cut will not effective*/ + }; + + type_c { + /* For 1315, 1317, u2drd */ + //realtek,connector_switch-gpio = <&gpio 25 GPIO_ACTIVE_HIGH>; + /* For 1319, u3drd */ + //realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + }; + }; + + dwc3_u2drd_usb2phy: dwc3_u2drd_usb2phy@98013214 { + compatible = "realtek,usb2phy"; + reg = <0x98013214 0x4>, <0x98028280 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "okay"; + nvmem-cells = <&otp_usb_port0_dc_cal>; + nvmem-cell-names = "usb-dc-cal"; + port_index = <0>; /* index in u2 port */ + phyN = <1>; + phy0 { + phy_data_page0_size = <16>; + phy_data_page0_addr = /bits/ 8 + <0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xF0 0xF1 + 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7>; + phy_data_page0_A00 = /bits/ 8 + <0xE0 0x30 0x79 0x8D 0x6A 0x65 0x01 0x71 0xFC 0x8C + 0x00 0x11 0x9B 0x00 0x00 0x0A>; + phy_data_page0_B00 = /bits/ 8 + <0x18 0x30 0x79 0x8D 0x6A 0x65 0x01 0x71 0xFC 0x8C + 0x00 0x11 0x9B 0x00 0x00 0x32>; + phy_data_page1_size = <8>; + phy_data_page1_addr = /bits/ 8 + <0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7>; + phy_data_page1_A00 = /bits/ 8 + <0x25 0xEF 0x60 0x44 0x00 0x0F 0x18 0xE3>; + phy_data_page2_size = <1>; + phy_data_page2_addr = /bits/ 8 + <0xE0>; + phy_data_page2_A00 = /bits/ 8 + <0x01>; + do_toggle; + check_efuse; + //use_default_parameter; + is_double_sensitivity_mode; + ldo_page0_e4_compensate = <(-2)>; + }; + }; + + dwc3_u2drd: rtk_dwc3_u2drd@98013200 { + compatible = "realtek,dwc3"; + reg = <0x98013200 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + delay_probe_work; //To delay probe work + ordered_probe; // ordered probe in delay work + drd_mode; + status = "disabled"; + + dwc3_u2drd@98020000 { + compatible = "synopsys,dwc3"; + reg = <0x98020000 0x9000>; + interrupts = <0 95 4>; + snps,fixed_dwc3_globals_regs_start = <0x8100>; + usb-phy = <&dwc3_u2drd_usb2phy>; + dr_mode = "host"; /*otg, host, peripheral*/ + snps,dis_u2_susphy_quirk; // Disable u2phy suspend for drd + snps,dis-u2-freeclk-exists-quirk; // Fixed u2drd host die issue + + status = "disabled"; + }; + }; + + dwc3_u2host_usb2phy: dwc3_u2host_usb2phy@98013C14 { + compatible = "realtek,usb2phy"; + reg = <0x98013C14 0x4>, <0x98031280 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "okay"; + nvmem-cells = <&otp_usb_port1_dc_cal>; + nvmem-cell-names = "usb-dc-cal"; + port_index = <1>; /* index in u2 port */ + phyN = <1>; + phy0 { + phy_data_page0_size = <16>; + phy_data_page0_addr = /bits/ 8 + <0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xF0 0xF1 + 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7>; + phy_data_page0_A00 = /bits/ 8 + <0xE0 0x30 0x79 0x8D 0x6A 0x65 0x01 0x71 0xFC 0x8C + 0x00 0x11 0x9B 0x00 0x00 0x0A>; + phy_data_page0_B00 = /bits/ 8 + <0x18 0x30 0x79 0x8D 0x6A 0x65 0x01 0x71 0xFC 0x8C + 0x00 0x11 0x9B 0x00 0x00 0x32>; + phy_data_page1_size = <8>; + phy_data_page1_addr = /bits/ 8 + <0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7>; + phy_data_page1_A00 = /bits/ 8 + <0x25 0xEF 0x60 0x44 0x00 0x0F 0x18 0xE3>; + phy_data_page2_size = <1>; + phy_data_page2_addr = /bits/ 8 + <0xE0>; + phy_data_page2_A00 = /bits/ 8 + <0x01>; + do_toggle; + check_efuse; + //use_default_parameter; + is_double_sensitivity_mode; + ldo_page0_e4_compensate = <(-2)>; + }; + }; + + dwc3_u2host: rtk_dwc3_u2host@98013C00 { + compatible = "realtek,dwc3"; + reg = <0x98013C00 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + delay_probe_work; //To delay probe work + ordered_probe; // ordered probe in delay work + status = "disabled"; + + dwc3_u2host@98029000 { + compatible = "synopsys,dwc3"; + reg = <0x98029000 0x9000>; + interrupts = <0 21 4>; + snps,fixed_dwc3_globals_regs_start = <0x8100>; + usb-phy = <&dwc3_u2host_usb2phy>; + dr_mode = "host"; /*only host*/ + }; + }; + + dwc3_u3drd_usb3phy: dwc3_u3drd_usb3phy@98013E10 { + compatible = "realtek,usb3phy"; + reg = <0x98013E10 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "okay"; + port_index = <0>; /* index in u3 port */ + phyN = <1>; + phy0 { + phy_data_size = <0x30>; + phy_data_addr = /bits/ 8 + <0x00 0x01 0x02 0x03 0x04 0x05 0x06 + 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D + 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 + 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B + 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 + 0x23 0x24 0x25 0x26 0x27 0x28 0x29 + 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F>; + phy_data_A00 = /bits/ 16 + <0x400C 0xAC86 0x6042 0x2771 0x72F5 0x2AD3 0x0003 + 0x2E00 0x3591 0x925C 0xA608 0xA905 0xC000 0xEF1E + 0x2010 0x8D50 0x000C 0x4C10 0xFC00 0x0C81 0xDE01 + 0x0000 0x0000 0x0000 0x0000 0x6000 0x0085 0x2014 + 0xC900 0xA03F 0xC2E0 0x7E00 0x705A 0xF645 0x0013 + 0xCB66 0x4770 0x126C 0x840A 0x01D6 0xF802 0xff00 + 0x3040 0x8028 0xFFFF 0xFFFF 0x0000 0x8600>; + phy_data_B00 = /bits/ 16 + <0x400C 0xAC86 0x6042 0x2771 0x72F5 0x2AD3 0x0003 + 0x2E00 0x3591 0x924C 0xA608 0xB905 0xC000 0xEF1E + 0x2010 0x8D50 0x000C 0x4C10 0xFC00 0x0C81 0xDE01 + 0x0000 0x0000 0x0000 0x0000 0x6000 0x0085 0x2014 + 0xC900 0xA03F 0xC2E0 0x7E00 0x705A 0xF645 0x0013 + 0xCB66 0x4770 0x126C 0x840A 0x01D6 0xF802 0xff00 + 0x3040 0x8028 0xFFFF 0xFFFF 0x0000 0x8600>; + do_toggle; + //use_default_parameter; + }; + }; + + dwc3_u3drd_usb2phy: dwc3_u3drd_usb2phy@98013E14 { + compatible = "realtek,usb2phy"; + reg = <0x98013E14 0x4>, <0x98058280 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "okay"; + nvmem-cells = <&otp_usb_port2_dc_cal>; + nvmem-cell-names = "usb-dc-cal"; + port_index = <2>; /* index in u2 port */ + phyN = <1>; + phy0 { + phy_data_page0_size = <16>; + phy_data_page0_addr = /bits/ 8 + <0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7 0xF0 0xF1 + 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7>; + phy_data_page0_A00 = /bits/ 8 + <0xE0 0x30 0x79 0x8D 0x6A 0x65 0x01 0x71 0xFC 0x8C + 0x00 0x11 0x9B 0x00 0x00 0x0A>; + phy_data_page0_B00 = /bits/ 8 + <0x18 0x30 0x79 0x8D 0x6A 0x65 0x01 0x71 0xFC 0x8C + 0x00 0x11 0x9B 0x00 0x00 0x32>; + phy_data_page1_size = <8>; + phy_data_page1_addr = /bits/ 8 + <0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7>; + phy_data_page1_A00 = /bits/ 8 + <0x25 0xEF 0x60 0x44 0x00 0x0F 0x18 0xE3>; + phy_data_page2_size = <1>; + phy_data_page2_addr = /bits/ 8 + <0xE0>; + phy_data_page2_A00 = /bits/ 8 + <0x01>; + do_toggle; + check_efuse; + //use_default_parameter; + is_double_sensitivity_mode; + ldo_page0_e4_compensate = <(-2)>; + }; + }; + + dwc3_u3drd: rtk_dwc3_u3drd@98013E00 { + compatible = "realtek,dwc3"; + reg = <0x98013E00 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + delay_probe_work; //To delay probe work + ordered_probe; // ordered probe in delay work + drd_mode; + status = "disabled"; + + dwc3_u3drd@981f0000 { + compatible = "synopsys,dwc3"; + reg = <0x98050000 0x9000>; + interrupts = <0 94 4>; + snps,fixed_dwc3_globals_regs_start = <0x8100>; + usb-phy = <&dwc3_u3drd_usb2phy &dwc3_u3drd_usb3phy>; + dr_mode = "peripheral"; /*only host*/ + snps,dis_u2_susphy_quirk; // Disable u2phy suspend for drd + snps,parkmode-disable-ss-quirk; // disable usb3.0 park mode + + status = "disabled"; + }; + }; + + rtk_type_c: rtk_type_c@98007220 { + compatible = "realtek,dwc3-type_c"; + reg = <0x98007220 0x20>; + interrupts = <0 60 4>; + //debug; /*to enable debug log*/ + delay_probe_work; /*To delay probe work*/ + ordered_probe; /*ordered probe in delay work*/ + + dwc3_rtk = <&dwc3_u3drd>; + + boot_check_time = <(-1)>; /*ms (At boot Device switch Host time)*/ + pinctrl-names = "default"; + pinctrl-0 = <&usb_cc1_pins>, <&usb_cc2_pins>; + + nvmem-cells = <&otp_usb_cal>; + nvmem-cell-names = "usb-cal"; + + status = "disabled"; + + default_revision = <0xA00>; + A00 { + cc_dfp_mode = "dfp_3_0"; /*dfp_3_0, dfp_1_5, dfp_usb*/ + cc1_rp_4p7k_code = <0x9>; + cc1_rp_36k_code = <0xE>; + cc1_rp_12k_code = <0x9>; + cc1_rd_code = <0x9>; + cc1_vref_ufp = /bits/ 8 + <0x7 0x6 0x3>; /*<1p23v,0p66v,0p2v>*/ + cc1_vref_dfp_usb = /bits/ 8 + <0x7 0x3 0x0>; /*<0_1p6v,0p2v,unused>*/ + cc1_vref_dfp_1_5 = /bits/ 8 + <0x4 0x2 0x3>; /*<1_1p6v,0p4v,0p2v>*/ + cc1_vref_dfp_3_0 = /bits/ 8 + <0x3 0x7 0x3>; /*<2p6v,0p8v,0p2v>*/ + cc2_rp_4p7k_code = <0x8>; + cc2_rp_36k_code = <0xE>; + cc2_rp_12k_code = <0x9>; + cc2_rd_code = <0x9>; + cc2_vref_ufp = /bits/ 8 + <0x7 0x6 0x3>; /*<1p23v,0p66v,0p2v>*/ + cc2_vref_dfp_usb = /bits/ 8 + <0x7 0x3 0x0>; /*<0_1p6v,0p2v,unused>*/ + cc2_vref_dfp_1_5 = /bits/ 8 + <0x6 0x3 0x3>; /*<1_1p6v,0p4v,0p2v>*/ + cc2_vref_dfp_3_0 = /bits/ 8 + <0x3 0x7 0x3>; /*<2p6v,0p8v,0p2v>*/ + }; + }; + +}; diff --git a/arch/arm64/boot/dts/realtek/rtd13xx.dtsi b/arch/arm64/boot/dts/realtek/rtd13xx.dtsi new file mode 100644 index 000000000000..67c51390626a --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd13xx.dtsi @@ -0,0 +1,1251 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek RTD13xx SoC family + * + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include + +#include "rtd13xx-usb.dtsi" + +/ { + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + i2c0 = &i2c_0; + i2c1 = &i2c_1; + i2c3 = &i2c_3; + i2c5 = &i2c_5; + }; + + reserved_memory: reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + protected_mem: protected_mem@4000 { + reg = <0x00004000 0x1000000>; + no-map; + }; + + rpc_comm: comm@4080000 { + compatible = "comm"; + reg = <0x04080000 0x1000>; + }; + + rpc_ringbuf: ringbuf@40ff000 { + compatible = "ringbuf"; + reg = <0x040ff000 0x4000>; + }; + + audio_heap: audio_heap@4200000 { + compatible = "audio_heap"; + reg = <0x04200000 0xc00000>; + }; + + media_heap: media_heap@4e00000 { + compatible = "media_heap"; + reg = <0x04e00000 0x06000000>; + }; + + audio_fw_mem: audio_fw_mem@10000000 { + reg = <0x10000000 0x14000>; + no-map; + }; + + tee: tee@10100000 { + reg = <0x11000000 0x03200000>; + no-map; + }; + + cma_resrved_0:linux,default_cma { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alignment = <0x01000000>; + linux,cma-default; + linux,contiguous-region; + reusable; + }; + + cma_resrved_1:linux,cma_1 { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alloc-ranges=<0x14200000 0x0be00000>; + linux,contiguous-region; + reusable; + status = "disabled"; + }; + + cma_resrved_2:linux,cma_2 { + compatible = "shared-dma-pool"; + size = <0x08000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_3:linux,cma_3 { + compatible = "shared-dma-pool"; + size = <0x10000000>; + alignment = <0x01000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_4:linux,cma_4 { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alignment = <0x01000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_5:linux,cma_5 { + compatible = "shared-dma-pool"; + size = <0x01000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_6:linux,cma_6 { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_7:linux,cma_7 { + compatible = "shared-dma-pool"; + size = <0x01000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_8:linux,cma_8 { + compatible = "shared-dma-pool"; + size = <0x06000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_9:linux,cma_9 { + compatible = "shared-dma-pool"; + reusable; + size = <0x04000000>; + alignment = <0x01000000>; + linux,contiguous-region; + alloc-ranges=<0x00000000 0x60000000>; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x100>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x200>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x300>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + l2: l2-cache { + compatible = "cache"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + , + ; + }; + + arm_pmu: pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + osc27m: osc { + compatible = "fixed-clock"; + clock-frequency = <27000000>; + clock-output-names = "osc27m"; + #clock-cells = <0>; + }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; + + buadclk: buadclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <432000000>; + clock-output-names = "buadclk"; + }; + + rtk_fw_pm: rtk_fw_pm { + compatible = "realtek,fw_pm"; + status = "disabled"; + }; + + vcpu: vcpu { + compatible = "realtek,rtd1319-vcpu"; + power-domains = <&pwr_ve2>; + status = "disabled"; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00000000 0x00000000 0x0002e000>, /* boot ROM */ + <0x00030000 0x00030000 0x00030000>, /* PCIE IO*/ + <0xff100000 0xff100000 0x00200000>, /* GIC */ + <0xC0000000 0xC0000000 0x00100000>, /* PCIe Trans */ + <0xC1000000 0xC1000000 0x00100000>, /* PCIe Trans */ + <0x98000000 0x98000000 0x00200000>; /* rbus */ + + rbus: rbus@98000000 { + compatible = "simple-bus"; + reg = <0x98000000 0x200000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00000000 0x98000000 0x200000>, + <0xC0000000 0xC0000000 0x00100000>, /* PCIe Trans */ + <0xC1000000 0xC1000000 0x00100000>, /* PCIe Trans */ + <0x10030000 0x00030000 0x00030000>; /* PCIE IO*/ + + crt: syscon@0 { + compatible = "realtek,rtd1319-crt", "syscon", "simple-mfd"; + reg = <0x0 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x1000>; + }; + + pinctrl: pinctrl@4e000 { + compatible = "realtek,rtd13xx-pinctrl", "syscon"; + reg = <0x4e000 0x130>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + #gpio-range-cells = <3>; + ranges = <0x0 0x4e000 0x130>; + }; + + iso: syscon@7000 { + compatible = "syscon", "simple-mfd"; + reg = <0x7000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x7000 0x1000>; + }; + + efuse: efuse@17000 { + compatible = "realtek,rtd1619-otp", "syscon"; + reg = <0x17000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + }; + + sb2: syscon@1a000 { + compatible = "syscon", "simple-mfd"; + reg = <0x1a000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1a000 0x1000>; + }; + + misc: syscon@1b000 { + compatible = "syscon", "simple-mfd"; + reg = <0x1b000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1b000 0x1000>; + }; + + sbx: syscon@1c000 { + compatible = "syscon", "simple-mfd"; + reg = <0x1c000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1c000 0x1000>; + }; + + scpu_wrapper: syscon@1d000 { + compatible = "syscon", "simple-mfd", "realtek,rtd1319-scpu-wrapper"; + reg = <0x1d000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1d000 0x1000>; + }; + + cbus_wrapper: syscon@37500 { + compatible = "syscon", "simple-mfd"; + reg = <0x37500 0x10>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x37500 0x10>; + }; + + nic: r8169soc@16000 { + compatible = "realtek,rtd13xx-r8169soc"; + reg = <0x16000 0x1000>; /* ETN */ + realtek,iso = <&iso>; + realtek,sbx = <&sbx>; + realtek,scpu_wrapper = <&scpu_wrapper>; + realtek,pinctrl = <&pinctrl>; + interrupts = <0 22 4>; + pinctrl-names = "default", + "rgmii"; + pinctrl-0 = <&etn_led_pins>; + pinctrl-1 = <&rgmii_mdio_pins>, + <&rgmii_txrx_pins>; + local-mac-address = [00 10 20 30 40 50]; + wol-enable = <0>; + wake-mask0 = [3f 30 80 c0 3f 10 80 ff ff 1f 00 00 00 00 00 00]; + wake-crc0 = <0x8d25>; + wake-mask1 = [3f 30 80 c0 3f 10 00 00 c0 ff ff 0f 00 00 00 00]; + wake-crc1 = <0x8d25>; + wake-mask2 = [3f 30 80 c0 3f 10 00 00 00 00 00 00 80 ff ff 1f]; + wake-crc2 = <0x8d25>; + wake-mask3 = [3f 30 10 00 c0 ff ff 03 01 f8 ff ff 01 00 00 00]; + wake-crc3 = <0x11da>; + wake-mask4 = [3f 30 10 00 c0 ff ff 03 01 00 00 fc ff ff 00 00]; + wake-crc4 = <0x11da>; + wake-mask5 = [3f 30 10 00 c0 ff ff 03 01 00 00 00 00 00 00 f8]; + wake-crc5 = <0x15f8>; + output-mode = <0>; /* 0:embedded PHY, 1:RGMII to MAC, 2:RGMII to PHY, 5:RMII */ + voltage = <1>; /* 1:1.8V, 2: 2.5V, 3:3.3V */ + tx-delay = <0>; /* 0: 0ns, 1: 2ns */ + rx-delay = <0>; /* 0 ~ 7 x 0.5ns */ + ext-phy-id = <1>; /* 0 ~ 31, only valid when output-mode = 2 or 4 */ + acp = <0>; /* 0: disable, 1: enable */ + eee = <1>; /* 0: disable, 1: enable */ + clocks = <&ic RTD1319_ISO_CLK_EN_ETN_250M>, + <&ic RTD1319_ISO_CLK_EN_ETN_SYS>; + clock-names = "etn_250m", + "etn_sys"; + resets = <&ic RTD1319_ISO_RSTN_GMAC>, + <&ic RTD1319_ISO_RSTN_GPHY>; + reset-names = "gmac", + "gphy"; + nvmem-cells = <&otp_etn_para>, <&otp_etn_idac>; + nvmem-cell-names = "para", "idac"; + status = "disabled"; + + phy_0 { + interrupt-parent = <&iso_irq_mux>; + interrupts = <28>, <29>, <30>; + irq-mask = <0x70000000>; + por-xv-mask = <0x00000111>; + }; + }; + + spi_0: spi@1bd00 { + compatible = "realtek,rtk-dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <27>; /* SPI_INT */ + reg = <0x1bd00 0x100>, /* DW SPI */ + <0x1b300 0x18>; /* SPI wrapper */ + pinctrl-names = "default"; + pinctrl-0 = <&gspi_pins_0>; + num-chipselect = <1>; + bus-num = <0>; + clocks = <&cc RTD1319_CRT_CLK_EN_GSPI>; + clock-frequency = <256000000>; + resets = <&cc RTD1319_CRT_RSTN_GSPI>; + status = "disabled"; + }; + + spi_1: spi@7500 { + compatible = "realtek,rtk-dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <6>; /* SPI1_INT */ + reg = <0x7500 0x100>, /* DW SPI */ + <0x72e4 0x1c>; /* SPI wrapper */ + pinctrl-names = "default"; + pinctrl-0 = <&iso_gspi_pins_0>; + num-chipselect = <1>; + bus-num = <0>; + clock-frequency = <256000000>; + clocks = <&ic RTD1319_ISO_CLK_EN_ISO_GSPI>; + resets = <&ic RTD1319_ISO_RSTN_ISO_GSPI>; + status = "disabled"; + }; + + emmc: emmc@12000 { + compatible = "realtek,rtd13xx-emmc"; + emmc-pon-gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; + emmc-pon-toggle-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + reg = <0x00012000 0x00a00>, /* eMMC */ + <0x00000000 0x00600>, /* CRT */ + <0x0001a000 0x00080>, /* SB2 */ + <0x0004e000 0x00100>, /* ISO */ + <0x00007e00 0x00020>, + <0x0004f000 0x00100>, /* m2tmx */ + <0x00012180 0x00060>, + <0x0000765c 0x00004>; + reg-names = "emmc","crt","sb2","mux","iso","m2tmx","cqhci","norst"; + interrupts = <0 42 4>; + speed-step = <3>; /* 0: sdr50, 1: ddr50, 2: hs200, 3: hs400 */ + clocks = <&cc RTD1319_CRT_CLK_EN_EMMC>, + <&cc RTD1319_CRT_CLK_EN_EMMC_IP>; + clock-names = "emmc", "emmc_ip"; + resets = <&cc RTD1319_CRT_RSTN_EMMC>; + nvmem-cells = <&otp_uuid>; + nvmem-cell-names = "uuid"; + reset-names = "emmc"; + pddrive_nf_s0 = <1 0x0 0x0 0x0 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for sdr50 */ + pddrive_nf_s1 = <1 0x0 0x0 0x0 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for ddr50 */ + pddrive_nf_s2 = <1 0x2 0x2 0x2 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for hs200 */ + pddrive_nf_s3 = <1 0x4 0x4 0x4 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for hs400 */ + phase_tuning = <1 1>; /* arg0: tx tuning switch, arg1: rx tuning switch, if we want to set user defined tx or rx, we should set 0 for tx or rx*/ + reference_phase = <0 0x0 0 0x0>; /* arg0: switch user defined tx, arg1: tx reference phase value, arg2: switch user defined rx, arg3: rx reference phase value*/ + dqs_tuning = <1>; + dqs_dly_tape = <0x0>; + mbr_tuning_addr = <0xa31000>; + hs400_force_tuning = <0x0>; + cmdq = <0x1>; + frequency = <0xa6>; + status = "disabled"; + }; + + sd: sdmmc@10400 { + compatible = "realtek,rtd13xx-sdmmc"; + reg = <0x10400 0x200>, /* SDMMC */ + <0x00000 0x400>, /* CRT */ + <0x1A000 0x400>, /* BS2 */ + <0x4E000 0x60>, /* ISO */ + <0x10A00 0x40>, /* SDIO */ + <0x07000 0x200>; + interrupts = ; + sd-power-gpios = <&gpio 30 GPIO_ACTIVE_HIGH>; /*sd power , output, default high (poweroff) */ + sd-wp-gpios = <&gpio 34 GPIO_PULL_UP>; + sd-cd-gpios = <&gpio 35 GPIO_PULL_UP>; + sdmmc-bounce = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdcard_pins_low>, + <&scpu_ejtag_pins_disable>; + clocks = <&cc RTD1319_CRT_CLK_EN_SD>, + <&cc RTD1319_CRT_CLK_EN_SD_IP>; + clock-names = "sd", "sd_ip"; + resets = <&cc RTD1319_CRT_RSTN_SD>; + status = "disabled"; + }; + + sfc: sfc@1a800 { + compatible = "realtek,rtd13xx-sfc"; + reg = <0x1a800 0x00050>; + status = "okay"; + }; + + sdio: sdio@10c00 { + compatible = "realtek,rtd1319-sdio"; + reg = <0x10c00 0x200>, + <0x00000 0x200000>; + interrupts = ; + sdio-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins_1>; + clocks = <&cc RTD1319_CRT_CLK_EN_SDIO>, + <&cc RTD1319_CRT_CLK_EN_SDIO_IP>; + clock-names = "sdio", "sdio_ip"; + resets = <&cc RTD1319_CRT_RSTN_SDIO>; + status = "disabled"; + }; + + nand: nand@10000 { + compatible = "realtek,rtd13xx-nf"; + reg = <0x10000 0x400>, /* NWC */ + <0x001F0 0x20>, /* PLL */ + <0x4E000 0x20>; /* PAD */ + clocks = <&cc RTD1319_CRT_CLK_EN_NF>; + clock-names = "nand"; + status = "disabled"; + }; + + sata_phy: sata_phy@3ff00 { + compatible = "realtek,rtk-sata-phy", "syscon"; + reg = <0x3ff00 0x100>; + clocks = <&cc RTD1319_CRT_CLK_EN_SATA_WRAP_SYS>, + <&cc RTD1319_CRT_CLK_EN_SATA_WRAP_SYSH>; + clock-names = "wrap_sys", "wrap_sysh"; + resets = <&cc RTD1319_CRT_RSTN_SATA_WRAP>; + realtek,phyctl = <&m2tmx>; + #address-cells = <1>; + #size-cells = <0>; + #phy-cells = <1>; + status = "disabled"; + }; + + ahci_sata: sata@3f000 { + compatible = "realtek,ahci-sata"; + reg = <0x3f000 0xf00>; + interrupts = ; + clocks = <&cc RTD1319_CRT_CLK_EN_SATA_MAC_SYSH>; + resets = <&cc RTD1319_CRT_RSTN_SATA_MAC_COM>; + realtek,satawrap = <&sata_phy>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + rng: rng@1000 { + compatible = "realtek,rt1319-rng"; + reg = <0x1000 0x70>; + status = "disabled"; + }; + + hse: hse@5000 { + reg = <0x5000 0x1000>; + compatible = "realtek,highspeed-streaming-engine"; + interrupts = ; + clocks = <&cc RTD1319_CRT_CLK_EN_HSE>; + resets = <&cc RTD1319_CRT_RSTN_HSE_BIST>; + reset-names = "bist"; + engine-1-enabled; + engine-0-disabled; + status = "disabled"; + }; + + cp: mcp@15000 { + compatible = "realtek,rtk-mcp", "syscon"; + reg = <0x15000 0x1000>, + <0x14000 0x1000>; + status = "disabled"; + }; + + m2tmx: m2tmx@4f000 { + compatible = "syscon", "simple-mfd"; + reg = <0x4f000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4f000 0x1000>; + }; + + ve1: ve1@40000 { + compatible = "realtek,rtk13xx-ve1"; + reg = <0x40000 0xc000>, + <0x08000 0x1000>, + <0x07000 0x30>, + <0x0e000 0x1000>; + interrupts = , + ; + power-domains = <&pwr_ve1>, <&pwr_ve3>; + resets = <&pwr_ve1>, <&pwr_ve3>; + reset-names = "ve1", "ve3"; + status = "disabled"; + }; + + jpeg: jpeg@3e000 { + compatible = "realtek,rtd13xx-jpeg"; + reg = <0x3e000 0x1000>, + <0x07000 0x30>; + interrupts = ; + clocks = <&cc RTD1319_CRT_CLK_EN_JPEG>; + clock-names = "jpeg"; + resets = <&cc RTD1319_CRT_RSTN_JPEG>; + status = "disabled"; + }; + }; + + gic: interrupt-controller@ff100000 { + compatible = "arm,gic-v3"; + #address-cells = <1>; + reg = <0xff100000 0x10000>, + <0xff140000 0x80000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + }; + + }; + + cpu_dvfs: cpu-dvfs { + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&cpu_tm>; + trips { + cpu_crit: cpu-crit { + temperature = <120000>; + hysteresis = <0>; + type = "critical"; + }; + }; + cooling-maps { + }; + }; + }; + + rtk_ion: rtk,ion { + compatible = "realtek,rtk-ion"; + #address-cells = <1>; + #size-cells = <0>; + + rtk,ion-heap@7 { /* Media */ + compatible = "realtek,rtk-ion-media"; + reg = <7>; + memory-region = <&media_heap>; + rtk,use-cma-pools; + rtk,cma-pools-skip-dma-default-array; + rtk,cma-pool-flags = ; + rtk,cma-pool-extFlags-info = ; + rtk,memory-reserve = <0x04e00000 0x06000000 RTK_FLAG_ION_HEAP + 0x00C40000 0x003C4000 RTK_FLAG_PROTECTED_DYNAMIC_METADATA>; + + cma_pool_2 { + memory-region = <&cma_resrved_2>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_3 { + memory-region = <&cma_resrved_3>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_4 { + memory-region = <&cma_resrved_4>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_5 { + memory-region = <&cma_resrved_5>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_6 { + memory-region = <&cma_resrved_6>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_7 { + memory-region = <&cma_resrved_7>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_8 { + memory-region = <&cma_resrved_8>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_9 { + memory-region = <&cma_resrved_9>; + rtk,cma-pool-extFlags = ; + }; + }; + + rtk,ion-heap@8 { /* Audio */ + compatible = "realtek,rtk-ion-audio"; + reg = <8>; + memory-region = <&audio_heap>; + rtk,memory-reserve = <0x04200000 + 0x00c00000 + RTK_FLAG_ION_HEAP>; + }; + + rtk,ion-heap@9 { /* Secure */ + compatible = "realtek,rtk-ion-secure"; + reg = <9>; + rtk,memory-reserve = <>; + status = "disabled"; + }; + }; + + info-pll { + compatible = "realtek,rtd161x-pll-info"; + realtek,crt = <&crt>; + realtek,scpu-wrapper = <&scpu_wrapper>; + }; + + rfkill: rfkilligpio { + compatible = "realtek,rfkill"; + rfkill-gpios = <&gpio 28 GPIO_ACTIVE_HIGH>; /*bt power, output, default low(poweroff) */ + status = "disabled"; + }; +}; + +&crt { + cc: clock-controller { + compatible = "realtek,rtd1319-crt-clk"; + #clock-cells = <1>; + #reset-cells = <1>; + realtek,sb2-lock = <&sb2_lock0>; + }; +}; + +&iso { + ic: clock-controller { + compatible = "realtek,rtd1319-iso-clk"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pwr_gpu: power-gpu { + compatible = "realtek,gpu-power"; + #power-domain-cells = <0>; + }; + + pwr_ve1: power-ve1 { + compatible = "realtek,rtd1319-ve1-power"; + #power-domain-cells = <0>; + #reset-cells = <0>; + clocks = <&cc RTD1319_CRT_CLK_VE1>; + resets = <&m2tmx_reset RTD1319_M2TMX_RSTN_VE1>, + <&cc RTD1319_CRT_RSTN_VE1_BIST>; + reset-names = "reset", "bist"; + + assigned-clocks = <&cc RTD1319_CRT_CLK_VE1>; + assigned-clock-rates = <500000000>; + assigned-clock-parents = <&cc RTD1319_CRT_PLL_VE1>; + }; + + pwr_ve2: power-ve2 { + compatible = "realtek,rtd1319-ve2-power"; + #power-domain-cells = <0>; + #reset-cells = <0>; + clocks = <&cc RTD1319_CRT_CLK_VE2>; + resets = <&cc RTD1319_CRT_RSTN_VE2>, + <&cc RTD1319_CRT_RSTN_VE2_BIST>; + reset-names = "reset", "bist"; + }; + + pwr_ve3: power-ve3 { + compatible = "realtek,rtd1319-ve3-power"; + #power-domain-cells = <0>; + #reset-cells = <0>; + clocks = <&cc RTD1319_CRT_CLK_VE3>; + resets = <&m2tmx_reset RTD1319_M2TMX_RSTN_VE3>, + <&cc RTD1319_CRT_RSTN_VE3_BIST>; + reset-names = "reset", "bist"; + + assigned-clocks = <&cc RTD1319_CRT_CLK_VE3>; + assigned-clock-parents = <&cc RTD1319_CRT_PLL_VE1>; + }; + + iso_irq_mux: iso_irq_mux { + compatible = "realtek,rtd13xx-iso-irq-mux"; + syscon = <&iso>; + interrupts-extended = <&gic GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + uart0: serial0@800 { + compatible = "snps,dw-apb-uart"; + reg = <0x800 0x400>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = ; + clock-frequency = <432000000>; + clock-names = "buadclk", "apb_pclk"; + clocks = <&buadclk>, <&ic RTD1319_ISO_CLK_EN_UR0>; + resets = <&ic RTD1319_ISO_RSTN_UR0>; + status = "disabled"; + }; + + gpio: gpio@100 { + compatible = "realtek,gpio"; + reg = <0x100 0x100>, + <0x0 0xB0>; + syscon = <&iso>; + realtek,gpio_base = <0>; + realtek,gpio_numbers = <82>; + interrupt-parent = <&iso_irq_mux>; + #interrupt-cells = <1>; + interrupt-controller; + #address-cells = <0>; + interrupts = <19>, <20>; + gpio-ranges = <&pinctrl 0 0 82>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + /* + * Set gpio default value need to add gpios & gpio-default + * ex: + * gpios = <&gpio 0 GPIO_ACTIVE_HIGH>, + * <&gpio 1 GPIO_ACTIVE_HIGH>, + * <&gpio 2 GPIO_PULL_UP>; + * + * gpio-default = <0>, //output low + * <1>, //output high + * <2>; //input + */ + gpio_default: gpio_default { + compatible = "realtek,gpio-set-default"; + status = "disabled"; + }; + + i2c_0: i2c_0@d00 { + compatible = "realtek,highspeed-i2c"; + reg = <0xd00 0x100>, + <0x000 0x100>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ic RTD1319_ISO_CLK_EN_I2C0>; + resets = <&ic RTD1319_ISO_RSTN_I2C_0>; + status = "disabled"; + }; + + i2c_1: i2c_1@c00 { + compatible = "realtek,i2c"; + reg = <0xc00 0x100>, + <0x000 0x100>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <11>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_1>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ic RTD1319_ISO_CLK_EN_I2C1>; + resets = <&ic RTD1319_ISO_RSTN_I2C_1>; + status = "disabled"; + }; + + reboot_mode: reboot-mode@640 { + compatible = "realtek,reboot-mode"; + reg = <0x640 0x4>; + status = "disabled"; + }; + + reboot: reboot@680 { + compatible = "realtek,reboot"; + reg = <0x680 0x48>; + rst-oe = <0>; + rst-oe-for-init = <1>; + status = "disabled"; + }; + + rtk_pm: rtk_pm { + compatible = "realtek,rtd13xx_pm"; + system-power-controller; + syscon = <&iso>; + pm-dbg = <0>; + status = "disabled"; + }; + + pwm: pwm@d0 { + compatible = "realtek,rtk-pwm"; + #pwm-cells = <2>; + reg = <0xd0 0xc>; + status = "disabled"; + + pwm_0 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <5>; /* default duty_rate 0 ~ 100 */ + }; + + pwm_1 { + enable = <1>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + + pwm_2 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + + pwm_3 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + }; +}; + +&misc { + misc_irq_mux: misc_irq_mux { + compatible = "realtek,rtd13xx-misc-irq-mux"; + syscon = <&misc>; + interrupts-extended = + <&gic GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + refclk: refclk@538 { + compatible = "realtek,refclk"; + reg = <0x538 0x10>; + }; + + uart1: serial1@200 { + compatible = "snps,dw-apb-uart"; + reg = <0x200 0x400>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts-extended = <&misc_irq_mux 3>; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + clock-frequency = <432000000>; + clock-names = "buadclk", "apb_pclk"; + clocks = <&buadclk>, <&cc RTD1319_CRT_CLK_EN_UR1>; + resets = <&cc RTD1319_CRT_RSTN_UR1>; + status = "disabled"; + }; + + uart2: serial2@400 { + compatible = "snps,dw-apb-uart"; + reg = <0x400 0x400>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts-extended = <&misc_irq_mux 7>; + clock-frequency = <432000000>; + clock-names = "buadclk", "apb_pclk"; + clocks = <&buadclk>, <&cc RTD1319_CRT_CLK_EN_UR2>; + resets = <&cc RTD1319_CRT_RSTN_UR2>; + status = "disabled"; + }; + + i2c_3: i2c_3@900 { + compatible = "realtek,i2c"; + reg = <0x900 0x100>, + <0x000 0x100>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <23>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_3>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cc RTD1319_CRT_CLK_EN_MISC_I2C_3>; + resets = <&cc RTD1319_CRT_RSTN_I2C_3>; + status = "disabled"; + }; + + i2c_5: i2c_5@b00 { + compatible = "realtek,i2c"; + reg = <0xb00 0x100>, + <0x000 0x100>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <14>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_5>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cc RTD1319_CRT_CLK_EN_MISC_I2C_5>; + resets = <&cc RTD1319_CRT_RSTN_I2C_5>; + status = "disabled"; + }; + + watchdog: watchdog@5b0 { + compatible = "realtek,watchdog"; + reg = <0x5b0 0x20>; + interrupts-extended = <&misc_irq_mux 2>; + timeout-sec = <20>; + status = "disabled"; + }; + + rtc: rtc@600 { + compatible = "realtek,rtd1319-rtc"; + reg = <0x600 0x34>; + realtek,iso = <&iso>; + rtc-base-year = <2020>; + interrupts-extended = <&iso_irq_mux 13>; + status = "disabled"; + }; + + rtk_fan: rtk_fan@c00 { + compatible = "realtek,rtk-fan"; + reg = <0xc00 0x14>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <29>; + status = "disable"; + + timer_target = <0x100000>; + fan_debounce = <0x0>;// 0x0~0x7 + fan_factor = <2>; /* count per revolution for fan */ + clocks = <&cc RTD1319_CRT_CLK_EN_FAN>; + resets = <&cc RTD1319_CRT_RSTN_FAN>; + pinctrl-names = "default"; + pinctrl-0 = <&dc_fan_sensor_pins>; + + /* For speed control */ + pwms = <&pwm 1 37878>; // (1) pwm node (2) pwm id (3) out period_ns (1/26400 ns) + }; +}; + +&sb2{ + chip: chip-info@200 { + compatible = "realtek,soc-chip"; + reg = <0x200 0x8>; + nvmem-cells = <&otp_bond_id>; + nvmem-cell-names = "bond_id"; + }; + + rpc: rpc@a80 { + compatible = "realtek,rpc"; + reg = <0xa80 0xc>; /* interrupt enable */ + interrupts = <0 33 4>, + <0 92 4>; + realtek,refclk = <&refclk>; + }; + + sb2_lock0: sb2-lock@0 { + compatible = "realtek,sb2-sem"; + reg = <0x0 0x4>; + }; + + sb2_lock1: sb2-lock@620 { + compatible = "realtek,sb2-sem"; + reg = <0x620 0x4>; + }; + + sb2_lock2: sb2-lock@624 { + compatible = "realtek,sb2-sem"; + reg = <0x624 0x4>; + }; + + sb2_lock3: sb2-lock@628 { + compatible = "realtek,sb2-sem"; + reg = <0x628 0x4>; + }; + + sb2_lock4: sb2-lock@62c { + compatible = "realtek,sb2-sem"; + reg = <0x62c 0x4>; + }; + + sb2_lock5: sb2-lock@630 { + compatible = "realtek,sb2-sem"; + reg = <0x630 0x4>; + }; + + sb2_lock6: sb2-lock@634 { + compatible = "realtek,sb2-sem"; + reg = <0x634 0x4>; + }; + + sb2_lock7: sb2-lock@638 { + compatible = "realtek,sb2-sem"; + reg = <0x638 0x4>; + }; + + sb2_lock8: sb2-lock@63c { + compatible = "realtek,sb2-sem"; + reg = <0x63c 0x4>; + }; +}; + +&usb_manager { + clocks = <&ic RTD1319_ISO_CLK_EN_USB>, /* clk_en_usb */ + <&ic RTD1319_ISO_CLK_EN_USB_DRD>, /* clk_en_usb_drd (port0 phy to u2drd clock) */ + <&ic RTD1319_ISO_CLK_EN_USB_HOST>, /* clk_en_usb_host0 (port1 phy to u2host clock) */ + <&ic RTD1319_ISO_CLK_EN_USB_U3_HOST>; /* clk_en_usb_host1 (port2 phy to u3drd clock) */ + clock-names = "clk_en_usb", /*clk_en_usb*/ + "clk_en_phy0_to_host", /* clk_en_usb_drd (port0 phy to u2drd clock) */ + "clk_en_phy1_to_host", /* clk_en_usb_u2host (port1 phy to u2host clock) */ + "clk_en_phy2_to_host"; /* clk_en_usb_u3host (port2 phy to u3drd clock) */ + + resets = <&ic RTD1319_ISO_RSTN_USB_DRD>, /* rstn_usb_u2drd (port0) */ + <&ic RTD1319_ISO_RSTN_USB_HOST>, /* rstn_usb_u2host(port1) */ + <&ic RTD1319_ISO_RSTN_USB_PHY_0>, /* rstn_usb_phy0 (port0 u2phy) */ + <&ic RTD1319_ISO_RSTN_USB_PHY_1>, /* rstn_usb_phy1 (port1 u2phy) */ + <&ic RTD1319_ISO_RSTN_USB_PHY_2>, /* rstn_usb_phy2 (port2 u2phy) */ + <&ic RTD1319_ISO_RSTN_USB>, /* rstn_usb */ + <&ic RTD1319_ISO_RSTN_TYPE_C>, /* rstn_type_c */ + <&ic RTD1319_ISO_RSTN_USB_U3_HOST>, /* rstn_usb_u3drd (port2) */ + <&ic RTD1319_ISO_RSTN_USB3_PHY0_POW>, /* rstn_usb3_phy0 (port0 u3phy) no used */ + <&ic RTD1319_ISO_RSTN_USB3_P0_MDIO>, /* rstn_usb3_phy0_mdio (port0 u3phy) no used */ + <&ic RTD1319_ISO_RSTN_USB3_PHY1_POW>, /* rstn_usb3_phy1 (port2 u3phy) */ + <&ic RTD1319_ISO_RSTN_USB3_P1_MDIO>; /* rstn_usb3_phy1_mdio (port2 u3phy) */ + + reset-names = "usb_host0", /* rstn_usb_u2drd (port0) */ + "usb_host1", /* rstn_usb_u2host (port1) */ + "u2phy0", /* rstn_usb_phy0 (port0 u2phy) */ + "u2phy1", /* rstn_usb_phy1 (port1 u2phy) */ + "u2phy2", /* rstn_usb_phy2 (port2 u2phy) */ + "usb", /* rstn_usb */ + "type_c", /* rstn_type_c */ + "usb_host2", /* rstn_usb_u3drd (port2) */ + "u3phy0", /* rstn_usb3_phy0 (port0 u3phy) no used*/ + "u3mdio0", /* rstn_usb3_phy0_mdio (port0 u3phy) no used */ + "u3phy2", /* rstn_usb3_phy1 (port2 u3phy) */ + "u3mdio2"; /* rstn_usb3_phy1_mdio (port2 u3phy) */ +}; + +&sata_phy{ + sata_phy0: sata-phy@0 { + reg = <0>; + resets = <&cc RTD1319_CRT_RSTN_SATA_MDIO0>, + <&cc RTD1319_CRT_RSTN_SATA_PHY_POW0>; + spread-spectrum = <0>; + phy-param = <0x70000211>, <0x70004211>, <0x70008211>, + <0x336a0511>, <0x336a4511>, <0x336a8511>, + <0xa9040b11>, <0xa9044b11>, <0xa9048b11>, + <0x500b1411>, <0x500b5411>, <0x500b9411>, + <0x77771511>, <0x77775511>, <0x77779511>, + <0x00231711>, <0x00235711>, <0x00239711>, + <0x00632211>, <0x00636211>, <0x0063a211>, + <0xab762311>, <0xab766311>, <0xab76a311>, + /* user can define tx driving here */ + <0x40aa2011>, <0x40aa6011>, <0x40a8a011>, + <0x88aa2111>, <0x88aa6111>, <0x88aaa111>; + status = "disabled"; + }; + + sata_phy1: sata-phy@1 { + reg = <1>; + resets = <&cc RTD1319_CRT_RSTN_SATA_MDIO1>, + <&cc RTD1319_CRT_RSTN_SATA_PHY_POW1>; + spread-spectrum = <0>; + phy-param = <0x70000211>, <0x70004211>, <0x70008211>, + <0x336a0511>, <0x336a4511>, <0x336a8511>, + <0xa9040b11>, <0xa9044b11>, <0xa9048b11>, + <0x500b1411>, <0x500b5411>, <0x500b9411>, + <0x77771511>, <0x77775511>, <0x77779511>, + <0x00231711>, <0x00235711>, <0x00239711>, + <0x00632211>, <0x00636211>, <0x0063a211>, + <0xab762311>, <0xab766311>, <0xab76a311>, + /* user can define tx driving here */ + <0x40aa2011>, <0x40aa6011>, <0x40a8a011>, + <0x88aa2111>, <0x88aa6111>, <0x88aaa111>; + status = "disabled"; + }; +}; + +&ahci_sata{ + sata_port0: sata-port@0 { + reg = <0>; + phys = <&sata_phy 0>; + resets = <&cc RTD1319_CRT_RSTN_SATA_MAC_P0>; + sata-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + sata_port1: sata-port@1 { + reg = <1>; + phys = <&sata_phy 1>; + resets = <&cc RTD1319_CRT_RSTN_SATA_MAC_P1>; + sata-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&scpu_wrapper { + clk-det { + compatible = "realtek,clk-det"; + clk-det,offset = <0x700>; + clk-det,type = <1>; + clock-output-names = "ref_pll_scpu"; + }; + + cpu_tm: thermal-sensor@b00 { + compatible = "realtek,rtd131x-thermal-sensor"; + reg = <0xb00 0x48>; + realtek,scpu-wrapper = <&scpu_wrapper>; + #thermal-sensor-cells = <0>; + }; + + fss: fss@b70 { + compatible = "realtek,scpu-wrapper-fss"; + reg = <0xb70 0x24>; + status = "disabled"; + }; +}; + +&m2tmx { + m2tmx_reset: reset { + realtek,m2tmx = <&m2tmx>; + compatible = "realtek,rtd1319-m2tmx-reset"; + #reset-cells = <1>; + clocks = <&cc RTD1319_CRT_CLK_VE1>, <&cc RTD1319_CRT_CLK_VE3>; + clock-names = "ve1", "ve3"; + }; +}; + +#include "rtd13xx-pinctrl.dtsi" +#include "rtd13xx-efuse.dtsi" +#include "rtd13xx-pcie.dtsi" diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb-nas.dts b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb-nas.dts new file mode 100644 index 000000000000..0ad2514e2d81 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb-nas.dts @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (1GB spi)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; + + chosen { + bootargs = "earlycon=uart8250,mmio32,0x98007800 console=ttyS0,460800 uio_pdrv_genirq.of_id=generic-uio init=/etc/init root=/dev/mtdblock3 rootwait loglevel=8 mtdparts=RtkSFC:256k(u-boot-env),1280k(u-boot)ro,4736k(firmware),9600k(rootfs)"; + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + status = "okay"; +}; + +&ahci_sata { + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; + +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb.dts b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb.dts new file mode 100644 index 000000000000..e42e12b29eb5 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-1gb.dts @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (2GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00004000 0x3fffc000>; /* 1 GiB */ + }; + +}; + +&pcie1 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + status = "okay"; +}; + +&ahci_sata { + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&audio_heap { + compatible = "audio_heap"; + reg = <0x04400000 0xc0000>; +}; + +&media_heap { + compatible = "media_heap"; + reg = <0x04e00000 0x02000000>; +}; + +&cma_resrved_0 { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + size = <0x400000>; + status = "disabled"; +}; + +&cma_resrved_3 { + size = <0xa000000>; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + size = <0x800000>; +}; + +&cma_resrved_6 { + size = <0x1c00000>; +}; + +&cma_resrved_7 { + size = <0x400000>; +}; + +&cma_resrved_8 { + size = <0x6000000>; + status = "disabled"; +}; + +&cma_resrved_9 { + size = <0x4000000>; + status = "disabled"; +}; + +&rtk_ion { + rtk,ion-heap@7 { + rtk,memory-reserve = <0x04e00000 0x02000000 0x0000008e + 0x00C40000 0x003C4000 0x000004ec>; + }; + + rtk,ion-heap@8 { + rtk,memory-reserve = <0x04400000 0x000c0000 0x0000008e>; + }; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb-spi.dts b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb-spi.dts new file mode 100644 index 000000000000..dfc74b6dc1ce --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb-spi.dts @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (2GB spi)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00040000 0x7ffc0000>; /* 2 GiB */ + }; + + chosen { + bootargs = "earlycon=uart8250,mmio32,0x98007800 console=ttyS0,460800 uio_pdrv_genirq.of_id=generic-uio init=/etc/init root=/dev/mtdblock3 rootwait loglevel=8 mtdparts=RtkSFC:256k(u-boot-env),1280k(u-boot)ro,10752k(firmware),3072k(rootfs)"; + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + status = "okay"; +}; + +&ahci_sata { + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; + +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb.dts b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb.dts new file mode 100644 index 000000000000..d6e22e8c01bb --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-2gb.dts @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (2GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00004000 0x7fffc000>; /* 2 GB */ + }; + + chosen { + bootargs = "earlycon=uart8250,mmio32,0x98007800 console=ttyS0,460800 init=/init loop.max_part=7 androidboot.storage=emmc androidboot.hardware=stark"; + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata_phy0 { + status = "okay"; +}; + +&ahci_sata { + status = "okay"; +}; + +&sata_port0 { + status = "okay"; +}; + +&reserved_memory { + ramoops@22000000 { + compatible = "ramoops"; + reg = <0x22000000 0x00200000>; + console-size = <0x00100000>; + record-size = <0x00004000>; + ftrace-size = <0x00004000>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-4gb.dts b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-4gb.dts new file mode 100644 index 000000000000..7ec1b567a40f --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge-4gb.dts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd1619b-bleedingedge.dtsi" + +/ { + compatible = "realtek,bleeding-edge", "realtek,rtd1619b"; + model = "Realtek Bleeding Edge EVB (4GB)"; + + memory@4000 { + device_type = "memory"; + reg = <0x00004000 0x7fffc000>, + <0x80020000 0x080e0000>, + <0x8a100000 0x0defc000>, + <0x98200000 0x00df0000>, + <0x99000000 0x66000000>; + }; +}; + +&cma_resrved_4 { + alloc-ranges=<0x00000000 0x60000000>; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge.dtsi b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge.dtsi new file mode 100644 index 000000000000..44f1fc2b473e --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-bleedingedge.dtsi @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include +#include +#include +#include "rtd16xxb.dtsi" + +/ { + chosen { + stdout-path = "serial0:460800n8"; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + rtc0 = &sw_rtc; + }; + + sw_rtc: sw-rtc { + compatible = "realtek,emulated-rtc"; + }; +}; + +&cp { + status = "okay"; +}; + +&cpu0 { + clocks = <&cc RTD1619B_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu1 { + clocks = <&cc RTD1619B_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu2 { + clocks = <&cc RTD1619B_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu3 { + clocks = <&cc RTD1619B_CRT_PLL_SCPU>; + cpu-supply = <&cpu_supp>; + operating-points-v2 = <&cpu_opps>; + #cooling-cells = <2>; +}; + +&cpu_dvfs { + fss,opp-updated = <0>; + fss,volt-correct = <25000>; + fss,volt-step = <25000>; + fss,volt-min = <775000>; + fss,volt-max = <1050000>; + + bsv,opp-updated = <0>; + bsv,volt-correct = <150000 175000>; + bsv,volt-step = <25000>; + bsv,volt-min = <800000>; + bsv,volt-max = <1050000>; + + cpu_opps: cpu-opp-table { + compatible = "operating-points-v2"; + opp-shared; + opp1000: opp-1000mhz { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <800000>; + opp-microvolt-bsv = <0>; + opp-microvolt-fss = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1100: opp-1100mhz { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1200: opp-1200mhz { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1300: opp-1300mhz { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1400: opp-1400mhz { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1500: opp-1500mhz { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1600: opp-1600mhz { + opp-hz = /bits/ 64 <1600000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + status = "okay"; + }; + + opp1700: opp-1700mhz { + opp-hz = /bits/ 64 <1700000000>; + opp-microvolt = <1050000>; + opp-microvolt-fss = <0>; + opp-microvolt-bsv = <0>; + clock-latency-ns = <150000>; + opp-suspend; + status = "okay"; + }; + }; +}; + +&cpu_thermal { + trips { + cpu_alert0: cpu-alert0 { + temperature = <90000>; + hysteresis = <0>; + type = "passive"; + }; + + cpu_alert1: cpu-alert1 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + cpu-map0 { + trip = <&cpu_alert0>; + cooling-device = <&cpu0 2 3>; + contribution = <70>; + }; + + cpu-map1 { + trip = <&cpu_alert1>; + cooling-device = <&cpu0 4 THERMAL_NO_LIMIT>; + contribution = <70>; + }; + }; +}; + +&cpu_tm { + status = "okay"; +}; + +&emmc { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&hse { + status = "okay"; +}; + +&i2c_0 { + clock-frequency = <3400000>; + pinctrl-0 = <&i2c_pins_0_HS>; + status = "okay"; + + apw7899: apw7899@12 { + compatible = "anpec,apw7899"; + reg = <0x12>; + + regulators { + compatible = "anpec,apw8886-regulator"; + + vd33_supp: dc1 { + regulator-name = "vd33"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <3777500>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + core_supp: dc2 { + regulator-name = "core"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1337500>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <800000>; + }; + }; + + cpu_supp: dc3 { + regulator-name = "cpudvs"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1337500>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-ramp-delay = <625>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vd18_supp: dc4 { + regulator-name = "vd18"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2060000>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + ddr_supp: dc5 { + regulator-name = "ddr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + }; + + regulator-state-shutdown { + regulator-off-in-suspend; + }; + }; + + vd25_supp: ldo1 { + regulator-name = "vd25"; + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <3020000>; + + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = ; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vfb5 { + regulator-name = "vfb5"; + regulator-min-microvolt = <512500>; + regulator-max-microvolt = <700000>; + + regulator-boot-on; + regulator-always-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + }; + }; +}; + +&i2c_1 { + status = "okay"; +}; + +&i2c_3 { + status = "okay"; +}; + +&i2c_4 { + status = "okay"; +}; + +&i2c_5 { + status = "okay"; +}; + +&iso { + rtc-reload@64c { + compatible = "realtek,rtc-reload"; + reg = <0x64c 0x4>; + status = "okay"; + }; +}; + +&jpeg { + status = "okay"; +}; + +&nic { + status = "okay"; +}; + +&rfkill { + rfkill-gpios = <&gpio 6 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie1_phy { + status = "okay"; +}; + +&pcie2 { + status = "okay"; +}; + +&pcie2_phy { + status = "okay"; +}; + +&pwm { + status = "disabled"; +}; + +&reboot_mode { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&lsadc { + status = "okay"; +}; + +&rtk_fw_pm { + status = "okay"; +}; + +&rtk_pm { + wakeup-flags = ; + wakeup-gpio-list = <2 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <4 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>; + wakeup-timer = <0>; + status = "okay"; +}; + +&sb2_inv { + status = "okay"; +}; + +&sd { + status = "okay"; +}; + +&sdio { + bus-width = <4>; + non-removable; + cap-sd-highspeed; + cap-mmc-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + keep-power-in-suspend; + enable-sdio-wakeup; + no-sd; + no-mmc; + status = "okay"; +}; + +&u2drd_usb2phy { + status = "okay"; +}; + +&u2drd { + status = "okay"; +}; + +&u2host_usb2phy { + status = "okay"; +}; + +&u2host { + status = "okay"; +}; + +&u3drd_usb2phy { + status = "okay"; +}; + +&u3drd_usb3phy { + status = "okay"; +}; + +&u3drd { + status = "okay"; +}; + +&rtk_type_c { + status = "okay"; + + dwc3_rtk = <&u3drd>; +}; + +/* debug console (J1) */ +&uart0 { + status = "okay"; +}; + +/* M.2 slot (CON2) */ +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb_manager { + status = "okay"; + + gpio0 { + realtek,power-gpio = <&gpio 48 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + gpio1 { + realtek,power-gpio = <&gpio 49 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + rtk_usb { + /* + type_c { + realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + */ + }; +}; + +&vcpu { + status = "okay"; +}; + +&vcpu_ve3 { + status = "disabled"; +}; + +&ve1 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&watchdog5 { + status = "okay"; +}; + +&sata_phy { + status = "disabled"; +}; + +&sata_phy0 { + tx-swing = <(-2)>, <(1)>, <(0)>; /* tx swing adjust sample : , , */ + /delete-property/ tx-swing; + tx-emphasis = <3>, <(-2)>, <(-3)>; /* tx emphasis adjust sample : , , */ + /delete-property/ tx-emphasis; + status = "disabled"; +}; + +&sata_phy1 { + status = "disabled"; +}; + +&ahci_sata { + status = "disabled"; +}; + +&sata_port0 { + status = "disabled"; +}; + +&sata_port1 { + status = "disabled"; +}; + diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-rescue-nas.dts b/arch/arm64/boot/dts/realtek/rtd1619b-rescue-nas.dts new file mode 100644 index 000000000000..a7af636ff4f0 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-rescue-nas.dts @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019-2021 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd16xxb-rescue.dtsi" + +/ { + model = "Realtek RTD1619B Rescue for Pure NAS"; + + memory@40000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; +}; + +&protected_mem { + status = "disabled"; +}; + +&rpc_comm { + status = "disabled"; +}; + +&rpc_ringbuf { + status = "disabled"; +}; + +&video_fw_ve3 { + status = "disabled"; +}; + +&audio_heap { + status = "disabled"; +}; + +&media_heap { + status = "disabled"; +}; + +&cma_resrved_1 { + status = "disabled"; +}; + +&cma_resrved_2 { + status = "disabled"; +}; + +&cma_resrved_4 { + status = "disabled"; +}; + +&cma_resrved_5 { + status = "disabled"; +}; + +&cma_resrved_6 { + status = "disabled"; +}; + +&cma_resrved_7 { + status = "disabled"; +}; + +&cma_resrved_8 { + status = "disabled"; +}; + +&cma_resrved_9 { + status = "disabled"; +}; + +&rtk_ion { + status = "disabled"; + +}; + +&tee { + status = "disabled"; +}; + +&hifi { + status = "disabled"; +}; + +&rpc { + status = "disabled"; +}; + +&rtk_fw_pm { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd1619b-rescue.dts b/arch/arm64/boot/dts/realtek/rtd1619b-rescue.dts new file mode 100644 index 000000000000..25709446b659 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd1619b-rescue.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019-2021 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd16xxb-rescue.dtsi" + +/ { + model = "Realtek RTD1619B Rescue"; + + memory@40000 { + device_type = "memory"; + reg = <0x00040000 0x3ffc0000>; /* 1 GiB */ + }; +}; + diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb-efuse.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb-efuse.dtsi new file mode 100644 index 000000000000..9cfa5c0c1f76 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb-efuse.dtsi @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020 Realtek Semiconductor Corporation + */ +&efuse { + otp_chip_id: chip-id@3cc { + reg = <0x3cc 0x10>; + }; + otp_secure_chip_en: secure-chip-en@3fd { + reg = <0x3fd 0x1>; + bits = <2 3>; + }; + otp_bist_rst_ctrl: bist-rst-ctrl@406 { + reg = <0x406 0x1>; + bits = <5 2>; + }; + otp_uuid: uuid@478 { + reg = <0x478 0xc>; + }; + otp_iddq: iddq@4f8 { + reg = <0x4f8 0x2>; + }; + otp_etn_rc_r_amp_cal: etn_rc_r_amp_cal@504 { + reg = <0x504 0x8>; + }; + otp_usb_cal: usb-cal@528 { + reg = <0x528 0xa>; + bits = <0 77>; + }; + otp_usb_port0_dc_cal: usb-port0-dc-cal@534 { + reg = <0x534 0x1>; + bits = <0 4>; + }; + otp_usb_port1_dc_cal: usb-port1-dc-cal@534 { + reg = <0x534 0x1>; + bits = <4 4>; + }; + otp_usb_port2_dc_cal: usb-port2-dc-cal@535 { + reg = <0x535 0x1>; + bits = <0 4>; + }; + + otp_sata_cal: sata-cal@a14 { + reg = <0xa14 0x4>; + }; + + otp_bsv: bsv@adc { + reg = <0xadc 0x4>; + }; + otp_usb_u3_tx_lfps_swing_trim: usb_u3_tx_lfps_swing_trim@A18 { + reg = <0xA18 0x1>; + bits = <0 4>; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb-etn-wol-pattern.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb-etn-wol-pattern.dtsi new file mode 100644 index 000000000000..a5632e7b74c1 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb-etn-wol-pattern.dtsi @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Realtek RTD16xxb SoC family + * + * Copyright (c) 2019-2021 Realtek Semiconductor Corp. + */ +&nic { + wake-mask0 = [3f 30 80 c0 3f 10 80 ff ff 1f 00 00 00 00 00 00]; + wake-crc0 = <0x8d25>; + wake-pattern0 = [01 00 5e 00 00 fb 08 00 11 e0 00 00 fb 14 e9 14 + e9 00 5f 67 6f 6f 67 6c 65 63 61 73 74 04 5f 74 + 63 70 05 6c 6f 63 61 6c]; + wake-offset0 = <0x0>; + wake-mask1 = [3f 30 80 c0 3f 10 00 00 c0 ff ff 0f 00 00 00 00]; + wake-crc1 = <0x8d25>; + wake-pattern1 = [01 00 5e 00 00 fb 08 00 11 e0 00 00 fb 14 e9 14 + e9 00 5f 67 6f 6f 67 6c 65 63 61 73 74 04 5f 74 + 63 70 05 6c 6f 63 61 6c]; + wake-offset1 = <0x0>; + wake-mask2 = [3f 30 80 c0 3f 10 00 00 00 00 00 00 80 ff ff 1f]; + wake-crc2 = <0x8d25>; + wake-pattern2 = [01 00 5e 00 00 fb 08 00 11 e0 00 00 fb 14 e9 14 + e9 00 5f 67 6f 6f 67 6c 65 63 61 73 74 04 5f 74 + 63 70 05 6c 6f 63 61 6c]; + wake-offset2 = <0x0>; + wake-mask3 = [3f 30 10 00 c0 ff ff 03 01 f8 ff ff 01 00 00 00]; + wake-crc3 = <0x11da>; + wake-pattern3 = [33 33 00 00 00 fb 86 dd 11 ff 02 00 00 00 00 00 + 00 00 00 00 00 00 00 00 fb 14 e9 14 e9 00 5f 67 + 6f 6f 67 6c 65 63 61 73 74 04 5f 74 63 70 05 6c + 6f 63 61 6c]; + wake-offset3 = <0x0>; + wake-mask4 = [3f 30 10 00 c0 ff ff 03 01 00 00 fc ff ff 00 00]; + wake-crc4 = <0x11da>; + wake-pattern4 = [33 33 00 00 00 fb 86 dd 11 ff 02 00 00 00 00 00 + 00 00 00 00 00 00 00 00 fb 14 e9 14 e9 00 5f 67 + 6f 6f 67 6c 65 63 61 73 74 04 5f 74 63 70 05 6c + 6f 63 61 6c]; + wake-offset4 = <0x0>; + wake-mask5 = [3f 30 10 00 c0 ff ff 03 01 00 00 00 00 00 00 f8]; + wake-crc5 = <0x15f8>; + wake-pattern5 = [33 33 00 00 00 fb 86 dd 11 ff 02 00 00 00 00 00 + 00 00 00 00 00 00 00 00 fb 14 e9 14 e9 00 5f 67 + 6f 6f 67]; + wake-offset5 = <0x0>; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb-pcie.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb-pcie.dtsi new file mode 100644 index 000000000000..72e4602caa2f --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb-pcie.dtsi @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek RTD16xxb SoC family + * + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +&rbus { + + pcie1: pcie@a0000 { + compatible = "realtek,rtd16xxb-pcie-slot1", "syscon"; + reg = <0xA0000 0x00001000 + 0xA1000 0x00001000>; + syscon = <&m2tmx>; + syscon-scpu-wrapper = <&scpu_wrapper>; + interrupt-names = "rtk-pcie1-intr"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 62 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clk_pins_1>; + bus-range = <0x00 0xff>; + linux,pci-domain = <1>; + device_type = "pci"; + perst-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>; + #size-cells = <2>; + #address-cells = <3>; + num-lanes = <1>; + phys = <&pcie1_phy>; + speed-mode = <1>; // 0:GEN1, 1:GEN2 + debug-mode = <0>; + //ranges = <0x03000000 0x0 0x980A2000 0x980A2000 0x0 0x0001E000 + ranges = <0x02000000 0x0 0xA0000000 0xA0000000 0x0 0x00100000 + 0x01000000 0x0 0x00040000 0x10040000 0x0 0x00010000>; + resets = <&cc RTD1619B_CRT_RSTN_PCIE1>, + <&cc RTD1619B_CRT_RSTN_PCIE1_CORE>, + <&cc RTD1619B_CRT_RSTN_PCIE1_POWER>, + <&cc RTD1619B_CRT_RSTN_PCIE1_NONSTICH>, + <&cc RTD1619B_CRT_RSTN_PCIE1_STITCH>; + + reset-names = "rstn", + "core", + "power", + "nonstitch", + "stitch"; + clocks = <&cc RTD1619B_CRT_CLK_EN_PCIE1>; + status = "okay"; + }; + + pcie2: pcie@c0000 { + compatible = "realtek,rtd16xxb-pcie-slot2", "syscon"; + reg = <0xC0000 0x00001000 + 0xC1000 0x00001000>; + syscon = <&m2tmx>; + syscon-scpu-wrapper = <&scpu_wrapper>; + interrupt-names = "rtk-pcie2-intr"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <0 107 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clk_pins_2>; + bus-range = <0x00 0xff>; + linux,pci-domain = <2>; + device_type = "pci"; + perst-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>; + #size-cells = <2>; + #address-cells = <3>; + num-lanes = <1>; + phys = <&pcie2_phy>; + speed-mode = <1>; // 0:GEN1, 1:GEN2 + debug-mode = <0>; + //ranges = <0x02000000 0x0 0x980C2000 0x980C2000 0x0 0x0001E000 + ranges = <0x02000000 0x0 0xA0100000 0xA0100000 0x0 0x00100000 + 0x01000000 0x0 0x00050000 0x10050000 0x0 0x00010000>; + resets = <&cc RTD1619B_CRT_RSTN_PCIE2>, + <&cc RTD1619B_CRT_RSTN_PCIE2_CORE>, + <&cc RTD1619B_CRT_RSTN_PCIE2_POWER>, + <&cc RTD1619B_CRT_RSTN_PCIE2_NONSTITCH>, + <&cc RTD1619B_CRT_RSTN_PCIE2_STITCH>; + reset-names = "rstn", + "core", + "power", + "nonstitch", + "stitch"; + clocks = <&cc RTD1619B_CRT_CLK_EN_PCIE2>; + status = "okay"; + }; + +}; + +/ { + pcie1_phy: pcie1_phy { + compatible = "realtek,rtd16xxb-pcie-slot1-phy"; + syscon = <&pcie1>; + resets = <&cc RTD1619B_CRT_RSTN_PCIE1_PHY>, + <&cc RTD1619B_CRT_RSTN_PCIE1_PHY_MDIO>; + reset-names = "phy", + "phy_mdio"; + #phy-cells = <0>; + status = "okay"; + }; + + pcie2_phy: pcie2_phy { + compatible = "realtek,rtd16xxb-pcie-slot2-phy"; + syscon = <&pcie2>; + resets = <&cc RTD1619B_CRT_RSTN_PCIE2_PHY>, + <&cc RTD1619B_CRT_RSTN_PCIE2_PHY_MDIO>; + reset-names = "phy", + "phy_mdio"; + #phy-cells = <0>; + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb-pinctrl.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb-pinctrl.dtsi new file mode 100644 index 000000000000..6171d040f00a --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb-pinctrl.dtsi @@ -0,0 +1,463 @@ +&pinctrl { + sdcard_pins_low: sdcard_low { + pins= "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function="sd"; + bias-pull-down; + }; + + sdcard_pins_high: sdcard_high { + pins="gpio_35", "gpio_34"; + function="mmc"; + bias-pull-up; + }; + + sdio_pins_0: sdio_pins_0 { + pins= "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk", + "sdio_loc"; + function = "sdio_loc0"; + }; + + sdio_pins_1: sdio_pins_1 { + pins = "gpio_40", + "gpio_41", + "gpio_42", + "gpio_43", + "gpio_44", + "gpio_45", + "sdio_loc"; + function = "sdio_loc1"; + }; + + uart0_pins: uart0_pins { + pins = "ur0_rx", + "ur0_tx"; + function = "uart0"; + }; + + uart1_pins: uart1_pins { + pins = "gpio_8", + "gpio_9"; + function = "uart1"; + }; + + uart2_pins_0: uart2_pins_0 { + pins = "ur2_loc", + "gpio_18", + "gpio_19"; + function = "uart2_loc0"; + }; + + uart2_pins_1: uart2_pins_1 { + pins ="ur2_loc", + "gpio_26", + "gpio_27"; + function = "uart2_loc1"; + }; + + i2c_pins_0: i2c_pins_0 { + pins = "gpio_12", + "gpio_13"; + function = "i2c0"; + drive-strength = <4>; + }; + + i2c_pins_0_HS: i2c_pins_0_HS { + pins = "gpio_12", + "gpio_13"; + function = "i2c0"; + drive-strength = <8>; + }; + + i2c_pins_1: i2c_pins_1 { + pins = "gpio_16", + "gpio_17"; + function = "i2c1"; + }; + + + i2c_pins_3: i2c_pins_3 { + pins = "gpio_63", + "gpio_64"; + function = "i2c3"; + }; + + i2c_pins_4: i2c_pins_4 { + pins = "gpio_34", + "gpio_35"; + function = "i2c4"; + }; + + i2c_pins_5: i2c_pins_5 { + pins = "gpio_29", + "gpio_46"; + function = "i2c5"; + }; + + spi_pins_enable: spi-pins-enable { + pins = "sf_en"; + function = "sf_enable"; + }; + + spi_pins_loc_spi: spi_pins_loc_spi { + pins = "spi_ce_n", + "spi_sck", + "spi_so", + "spi_si"; + function = "spi"; + }; + + gspi_pins_0: gspi_pins_0 { + pins = "gspi_loc", + "gpio_18", + "gpio_19", + "gpio_20", + "gpio_31"; + function = "gspi_loc0"; + }; + + gspi_pins_1: gspi_pins_1 { + pins = "gspi_loc", + "gpio_8", + "gpio_9", + "gpio_10", + "gpio_11"; + function = "gspi_loc1"; + }; + + iso_gspi_pins_0: iso_gspi_pins_0 { + pins = "iso_gspi_loc", + "gpio_18", + "gpio_19", + "gpio_20", + "gpio_31"; + function = "iso_gspi_loc0"; + }; + + iso_gspi_pins_1: iso_gspi_pins_1 { + pins = "iso_gspi_loc", + "gpio_8", + "gpio_9", + "gpio_10", + "gpio_11"; + function = "iso_gspi_loc1"; + }; + + smartcard_pins_0:smartcard_pins_0{ + pins = "gpio_18", + "gpio_19", + "gpio_20", + "gpio_31"; + function = "sc0"; + }; + + smartcard_pins_1:smartcard_pins_1{ + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5"; + function = "sc1"; + }; + + tp_common_pins: tp-common-pins { + pins = "gpio_66", + "gpio_67", + "gpio_68", + "gpio_73", + "gpio_74", + "gpio_75", + "gpio_76"; + function = "tp0"; + }; + + tp0_parallel_pins: tp0-parallel-pins { + pins = "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72"; + function = "tp0"; + }; + + tp1_serial_pins: tp1-serial-pins { + pins = "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72"; + function = "tp1"; + }; + + ao_pins: ao_pins { + pins = "gpio_66", + "gpio_67", + "gpio_68", + "gpio_69", + "gpio_70", + "gpio_71", + "gpio_72"; + function = "ao"; + }; + + ao_pins_1: ao_pins_1 { + pins = "gpio_66", + "gpio_67", + "gpio_68", + "gpio_69"; + function = "ao"; + }; + + ir_rx_pins: ir_rx_pins { + pins = "ir_rx"; + function = "ir_rx"; + }; + + spdif_pins: spdif_pins { + pins = "gpio_50"; + function = "spdif"; + }; + + ai_loc0_pins: ai_loc0_pins { + pins = "gpio_57", + "gpio_58", + "gpio_59", + "gpio_60", + "gpio_61", + "gpio_62", + "gpio_63"; + function = "ai_loc0"; + }; + + ai_loc1_pins: ai_loc1_pins { + pins = "gpio_32", + "gpio_33", + "gpio_34", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function = "ai_loc1"; + }; + + dmic_loc0_pins: dmic_loc0_pins { + pins = "dmic_loc", + "gpio_57", + "gpio_58", + "gpio_59", + "gpio_60", + "gpio_61", + "gpio_62", + "gpio_63", + "gpio_64"; + function = "dmic_loc0"; + }; + + dmic_loc1_pins: dmic_loc1_pins { + pins = "dmic_loc", + "gpio_32", + "gpio_33", + "gpio_34", + "gpio_35", + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function = "dmic_loc1"; + }; + + tdm_loc0_pins: tdm_loc0_pins { + pins = + "gpio_57", + "gpio_58", + "gpio_59", + "gpio_60"; + function = "tdm_ai_loc0"; + }; + + + tdm_loc1_pins: tdm_loc1_pins { + pins = + "hif_data", + "hif_en", + "hif_rdy", + "hif_clk"; + function = "tdm_ai_loc1"; + }; + + etn_led_pins: etn_led_pins { + pins = "gpio_14", + "gpio_15", + "gpio_23"; + function = "etn_led"; + }; + + + + pcie_clk_pins_1: pcie_clk_pins_1 { + pins = "gpio_25"; + function = "pcie1"; + }; + + pcie_clk_pins_2: pcie_clk_pins_2 { + pins = "gpio_52"; + function = "pcie2"; + }; + + scpu_ejtag_pins_loc_0: scpu_ejtag_pins_loc_0 { + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5", + "gpio_6", + "ejtag_scpu_loc"; + function = "scpu_ejtag_loc0"; + }; + + scpu_ejtag_pins_loc_1: scpu_ejtag_pins_loc_1 { + pins = "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_clk", + "ejtag_scpu_loc"; + function = "scpu_ejtag_loc1"; + }; + + scpu_ejtag_pins_disable: scpu_ejtag_pins_disable { + pins = "ejtag_scpu_loc"; + function = "scpu_ejtag_disable"; + }; + + acpu_ejtag_pins_loc_0: acpu_ejtag_pins_loc_0 { + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5", + "gpio_6", + "ejtag_acpu_loc"; + function = "acpu_ejtag_loc0"; + }; + + acpu_ejtag_pins_loc_1: acpu_ejtag_pins_loc_1 { + pins = "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_clk", + "ejtag_acpu_loc"; + function = "acpu_ejtag_loc1"; + }; + + acpu_ejtag_pins_disable:acpu_ejtag_pins_disable{ + pins = "ejtag_acpu_loc"; + function = "acpu_ejtag_disable"; + }; + + vcpu_ejtag_pins_loc_0: avpu_ejtag_pins_loc_0 { + pins = "gpio_2", + "gpio_3", + "gpio_4", + "gpio_5", + "gpio_6", + "ejtag_vcpu_loc"; + function = "vcpu_ejtag_loc0"; + }; + + vcpu_ejtag_pins_loc_1: vcpu_ejtag_pins_loc_1 { + pins = "gpio_32", + "gpio_33", + "hif_data", + "hif_en", + "hif_clk", + "ejtag_vcpu_loc"; + function = "vcpu_ejtag_loc1"; + }; + + vcpu_ejtag_pins_disable:vcpu_ejtag_pins_disable{ + pins = "ejtag_vcpu_loc"; + function = "vcpu_ejtag_disable"; + }; + + dc_fan_sensor_pins: dc_fan_sensor_pins { + pins = "gpio_47"; + function = "dc_fan"; + }; + + pwm0_1_pins: pwm0_1_pins { + pins = "gpio_20"; + function = "pwm0"; + }; + + pwm0_0_pins: pwm0_0_pins { + pins = "gpio_26"; + function = "pwm0"; + }; + + pwm1_1_pins: pwm1_1_pins { + pins = "gpio_21"; + function = "pwm1"; + }; + + pwm1_0_pins: pwm1_0_pins { + pins = "gpio_27"; + function = "pwm1"; + }; + + pwm2_1_pins: pwm2_1_pins { + pins = "gpio_22"; + function = "pwm2"; + }; + + pwm2_0_pins: pwm2_0_pins { + pins = "gpio_28"; + function = "pwm2"; + }; + + pwm3_1_pins: pwm3_1_pins { + pins = "gpio_23"; + function = "pwm3"; + }; + + pwm3_0_pins: pwm3_0_pins { + pins = "gpio_47"; + function = "pwm3"; + }; + + usb_cc1_pins: usb_cc1_pins { + pins = "usb_cc1"; + function = "usb_cc1"; + }; + + usb_cc2_pins: usb_cc2_pins { + pins = "usb_cc2"; + function = "usb_cc2"; + }; + + nf_pins: nf_pins { + pins = "emmc_rst_n", + "emmc_clk", + "emmc_cmd", + "emmc_data_0", + "emmc_data_1", + "emmc_data_2", + "emmc_data_3", + "emmc_data_4", + "emmc_data_5", + "emmc_data_6", + "emmc_data_7", + "spi_ce_n", + "spi_sck", + "spi_so", + "spi_si"; + function = "nf"; + }; + +}; + diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb-rescue.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb-rescue.dtsi new file mode 100644 index 000000000000..618bc296c03a --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb-rescue.dtsi @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +/dts-v1/; + +#include "rtd16xxb.dtsi" +#include + +/ { + model = "Realtek Rescue"; + + memory@40000 { + device_type = "memory"; + reg = <0x00004000 0x3fffc000>; /* boot ROM to 1 GiB or 2 GiB */ + }; + + chosen { + stdout-path = "serial0:460800n8"; + bootargs = "earlycon=uart8250,mmio32,0x98007800 init=/init"; + linux,initrd-start = <0x03100000>; + linux,initrd-end = <0x03d00000>; + }; +}; + +/* debug console (J1) */ +&uart0 { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb_manager { + status = "okay"; + + gpio0 { + realtek,power-gpio = <&gpio 48 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + gpio1 { + realtek,power-gpio = <&gpio 49 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + rtk_usb { + type_c { + realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&u2drd_usb2phy { + status = "okay"; +}; + +&u2drd { + status = "okay"; +}; + +&u2host_usb2phy { + status = "okay"; +}; + +&u2host { + status = "okay"; +}; + +&u3drd_usb2phy { + status = "okay"; +}; + +&u3drd_usb3phy { + status = "okay"; +}; + +&u3drd { + status = "okay"; +}; + +&rtk_type_c { + status = "okay"; + + dwc3_rtk = <&u3drd>; +}; + +&emmc { + hs400_force_tuning = <0x1>; + status = "okay"; +}; + +&cp { + status = "okay"; +}; + +&psci { + status = "disabled"; +}; + +&watchdog { + status = "okay"; +}; + +&reboot_mode { + status = "okay"; +}; + +&cma_resrved_3 { + status = "disabled"; +}; + +&rtk_pm { + wakeup-flags = ; + wakeup-gpio-list = <2 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <4 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>, + <26 GPIO_WAKEUP_ENABLE GPIO_WAKEUP_ACTIVE_LOW>; + wakeup-timer = <0>; + status = "okay"; +}; + +&nic { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb-usb.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb-usb.dtsi new file mode 100644 index 000000000000..e741e1a9f94d --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb-usb.dtsi @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek RTD16xxb SoC USB + * + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +&usb_manager { + //usb_iso_mode; /* ISO mode is only port suspend (Default disable) */ + //en_usb_storage_reprobe; /* To enable usb storage re-probe*/ + //rescue_usb; /* For rescue dtb use */ + + status = "disabled"; + + gpio0: gpio0 { + //realtek,power-gpio = <&gpio 48 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + gpio1: gpio1 { + //realtek,power-gpio = <&gpio 49 GPIO_ACTIVE_HIGH>; + power_low_active; + }; + + port0 { + usb = <&u2drd>; + usb_gpio = <&gpio0>; + }; + + port1 { + usb = <&u2host>; + usb_gpio = <&gpio0>; + }; + + port2 { + usb = <&u3drd>; + usb_gpio = <&gpio1>; + }; + + rtk_usb { + //pcie_usb3phy_sel = <0x9800705c>; /* Only for RTD1319 */ + + TP1CK_MEM_TEST1_register = <0x9804ef14>; + + power_ctrl_reg { + /* l4_icg */ + p0_l4_icg = <0x98013364>; + p1_l4_icg = <0x98013d60>; + p2_l4_icg = <0x98013f60>; + + usb_power_cut; /* Non ISO mode and power cut (Default disable power cut) */ + /* Note if enable ISO mode, then power_cut will not effective*/ + }; + + type_c { + /* For 1315C, u3drd */ + //realtek,connector_switch-gpio = <&gpio 49 GPIO_ACTIVE_HIGH>; + /* For 1619B, u3drd */ + //realtek,plug_side_switch-gpio = <&gpio 53 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&usb_manager { + clocks = <&ic RTD1619B_ISO_CLK_EN_USB>, /* clk_en_usb */ + <&ic RTD1619B_ISO_CLK_EN_USB_DRD>, /* clk_en_usb_drd (port0 phy to u2drd clock) */ + <&ic RTD1619B_ISO_CLK_EN_USB_HOST>, /* clk_en_usb_host0 (port1 phy to u2host clock) */ + <&ic RTD1619B_ISO_CLK_EN_USB_U3_HOST>; /* clk_en_usb_host1 (port2 phy to u3drd clock) */ + clock-names = "clk_en_usb", /*clk_en_usb*/ + "clk_en_phy0_to_host", /* clk_en_usb_drd (port0 phy to u2drd clock) */ + "clk_en_phy1_to_host", /* clk_en_usb_u2host (port1 phy to u2host clock) */ + "clk_en_phy2_to_host"; /* clk_en_usb_u3host (port2 phy to u3drd clock) */ + + resets = <&ic RTD1619B_ISO_RSTN_USB_DRD>, /* rstn_usb_u2drd (port0) */ + <&ic RTD1619B_ISO_RSTN_USB_HOST>, /* rstn_usb_u2host(port1) */ + <&ic RTD1619B_ISO_RSTN_USB_PHY_0>, /* rstn_usb_phy0 (port0 u2phy) */ + <&ic RTD1619B_ISO_RSTN_USB_PHY_1>, /* rstn_usb_phy1 (port1 u2phy) */ + <&ic RTD1619B_ISO_RSTN_USB_PHY_2>, /* rstn_usb_phy2 (port2 u2phy) */ + <&ic RTD1619B_ISO_RSTN_USB>, /* rstn_usb */ + <&ic RTD1619B_ISO_RSTN_TYPE_C>, /* rstn_type_c */ + <&ic RTD1619B_ISO_RSTN_USB_U3_HOST>, /* rstn_usb_u3drd (port2) */ + <&ic RTD1619B_ISO_RSTN_USB3_PHY0_POW>, /* rstn_usb3_phy0 (port0 u3phy) no used */ + <&ic RTD1619B_ISO_RSTN_USB3_P0_MDIO>, /* rstn_usb3_phy0_mdio (port0 u3phy) no used */ + <&ic RTD1619B_ISO_RSTN_USB3_PHY1_POW>, /* rstn_usb3_phy1 (port2 u3phy) */ + <&ic RTD1619B_ISO_RSTN_USB3_P1_MDIO>; /* rstn_usb3_phy1_mdio (port2 u3phy) */ + + reset-names = "usb_host0", /* rstn_usb_u2drd (port0) */ + "usb_host1", /* rstn_usb_u2host (port1) */ + "u2phy0", /* rstn_usb_phy0 (port0 u2phy) */ + "u2phy1", /* rstn_usb_phy1 (port1 u2phy) */ + "u2phy2", /* rstn_usb_phy2 (port2 u2phy) */ + "usb", /* rstn_usb */ + "type_c", /* rstn_type_c */ + "usb_host2", /* rstn_usb_u3drd (port2) */ + "u3phy0", /* rstn_usb3_phy0 (port0 u3phy) no used*/ + "u3mdio0", /* rstn_usb3_phy0_mdio (port0 u3phy) no used */ + "u3phy2", /* rstn_usb3_phy1 (port2 u3phy) */ + "u3mdio2"; /* rstn_usb3_phy1_mdio (port2 u3phy) */ +}; + +&u2drd { + delay_probe_work; //To delay probe work + ordered_probe; // ordered probe in delay work + drd_mode; + status = "disabled"; + + dwc3_u2drd@20000 { + compatible = "synopsys,dwc3"; + reg = <0x20000 0x9000>; + interrupts = <0 95 4>; + snps,fixed_dwc3_globals_regs_start = <0x8100>; + usb-phy = <&u2drd_usb2phy>; + dr_mode = "host"; /*otg, host, peripheral*/ + snps,dis_u2_susphy_quirk; // Disable u2phy suspend for drd + snps,dis-u2-freeclk-exists-quirk; // Fixed u2drd host die issue + + status = "okay"; + }; +}; + +&u2host { + delay_probe_work; //To delay probe work + ordered_probe; // ordered probe in delay work + status = "disabled"; + + dwc3_u2host@29000 { + compatible = "synopsys,dwc3"; + reg = <0x29000 0x9000>; + interrupts = <0 21 4>; + snps,fixed_dwc3_globals_regs_start = <0x8100>; + usb-phy = <&u2host_usb2phy>; + dr_mode = "host"; /*only host*/ + status = "okay"; + }; +}; + +&u3drd { + delay_probe_work; //To delay probe work + ordered_probe; // ordered probe in delay work + drd_mode; + status = "disabled"; + + dwc3_u3drd@50000 { + compatible = "synopsys,dwc3"; + reg = <0x50000 0x9000>; + interrupts = <0 94 4>; + snps,fixed_dwc3_globals_regs_start = <0x8100>; + usb-phy = <&u3drd_usb2phy &u3drd_usb3phy>; + dr_mode = "host"; /*only host*/ + snps,dis_u2_susphy_quirk; // Disable u2phy suspend for drd + snps,parkmode-disable-ss-quirk; // disable usb3.0 park mode + + status = "okay"; + }; +}; + +&u2drd_usb2phy { + nvmem-cells = <&otp_usb_port0_dc_cal>; + nvmem-cell-names = "usb-dc-cal"; + port_index = <0>; /* index in u2 port */ + phyN = <1>; + phy0_data { + page0_size = <16>; + page0_data_A00 = /* < addr data > */ + <0xE0 0xA3>, <0xE4 0xB2>, <0xE5 0x4F>, <0xE6 0x42>; + //page0_data_B00 = + // <0xE6 0x41>; + page1_size = <8>; + page1_data_A00 = <0xE3 0x64>; + page2_size = <8>; + page2_data_A00 = <0xE7 0x45>; + do_toggle; + check_efuse; + //use_default_parameter; + is_double_sensitivity_mode; + ldo_force_enable; + }; +}; + +&u2host_usb2phy { + nvmem-cells = <&otp_usb_port1_dc_cal>; + nvmem-cell-names = "usb-dc-cal"; + port_index = <1>; /* index in u2 port */ + phyN = <1>; + phy0_data { + page0_size = <16>; + page0_data_A00 = /* < addr data > */ + <0xE4 0xB1>, <0xE6 0x02>; + //page0_data_B00 = + // <0xE6 0x41>; + page1_size = <8>; + //page1_data_A00 = /* use default */ + // <0xE0 0x25>, <0xE1 0xEF>, <0xE2 0x60>, + // <0xE3 0x44>, <0xE4 0x00>, <0xE5 0x0F>, + // <0xE6 0x18>, <0xE7 0xE3>; + page2_size = <8>; + page2_data_A00 = <0xE7 0x45>; + do_toggle; + check_efuse; + //use_default_parameter; + is_double_sensitivity_mode; + ldo_force_enable; + }; +}; + +&u3drd_usb2phy { + nvmem-cells = <&otp_usb_port2_dc_cal>; + nvmem-cell-names = "usb-dc-cal"; + port_index = <2>; /* index in u2 port */ + phyN = <1>; + phy0_data { + page0_size = <16>; + page0_data_A00 = /* < addr data > */ + <0xE4 0xB1>, <0xE6 0x02>; + //page0_data_B00 = + // <0xE6 0x41>; + page1_size = <8>; + page1_data_A00 = <0xE2 0x08>; + //page1_data_A00 = /* use default */ + // <0xE0 0x25>, <0xE1 0xEF>, <0xE2 0x60>, + // <0xE3 0x44>, <0xE4 0x00>, <0xE5 0x0F>, + // <0xE6 0x18>, <0xE7 0xE3>; + page2_size = <8>; + page2_data_A00 = <0xE7 0x45>; + do_toggle; + check_efuse; + //use_default_parameter; + is_double_sensitivity_mode; + ldo_force_enable; + }; +}; + +&u3drd_usb3phy { + nvmem-cells = <&otp_usb_u3_tx_lfps_swing_trim>; + nvmem-cell-names = "usb_u3_tx_lfps_swing_trim"; + port_index = <0>; /* index in u3 port */ + phyN = <1>; + phy0_data { + phy_data_size = <0x30>; + phy_data_A00 = /* */ + <0x01 0xAC8C>, + <0x06 0x0017>, + <0x09 0x724C>, + <0x0B 0xB90D>, + <0x0A 0xB610>, + <0x0D 0xEF6A>, + <0x0F 0x9050>, + <0x10 0x03C4>, + <0x20 0x70FF>, + <0x21 0xCFAA>, + <0x22 0x0013>, + <0x23 0xDB66>, + <0x26 0x8609>, + <0x29 0xFF13>, + <0x2A 0x3070>; + + do_toggle_once; + check_efuse; + //use_default_parameter; + }; +}; + +&rtk_type_c { + interrupts = <0 60 4>; + //debug; /*to enable debug log*/ + delay_probe_work; /*To delay probe work*/ + ordered_probe; /*ordered probe in delay work*/ + + dwc3_rtk = <&u3drd>; /* default dwc3_rtk is u3drd*/ + + boot_check_time = <(-1)>; /*ms (At boot Device switch Host time)*/ + pinctrl-names = "default"; + pinctrl-0 = <&usb_cc1_pins>, <&usb_cc2_pins>; + + nvmem-cells = <&otp_usb_cal>; + nvmem-cell-names = "usb-cal"; + + status = "okay"; + + default_revision = <0xA00>; + A00 { + cc_dfp_mode = "dfp_3_0"; /*dfp_3_0, dfp_1_5, dfp_usb*/ + cc1_rp_4p7k_code = <0xF>; + cc1_rp_36k_code = <0xF>; + cc1_rp_12k_code = <0xF>; + cc1_rd_code = <0xF>; + cc1_vref_ufp = /bits/ 8 + <0x7 0x7 0x7>; /*<1p23v,0p66v,0p2v>*/ + cc1_vref_dfp_usb = /bits/ 8 + <0x7 0x7 0x0>; /*<0_1p6v,0p2v,unused>*/ + cc1_vref_dfp_1_5 = /bits/ 8 + <0x7 0x7 0x7>; /*<1_1p6v,0p4v,0p2v>*/ + cc1_vref_dfp_3_0 = /bits/ 8 + <0x7 0x7 0x7>; /*<2p6v,0p8v,0p2v>*/ + cc2_rp_4p7k_code = <0xF>; + cc2_rp_36k_code = <0xF>; + cc2_rp_12k_code = <0xF>; + cc2_rd_code = <0xF>; + cc2_vref_ufp = /bits/ 8 + <0x7 0x7 0x7>; /*<1p23v,0p66v,0p2v>*/ + cc2_vref_dfp_usb = /bits/ 8 + <0x7 0x7 0x0>; /*<0_1p6v,0p2v,unused>*/ + cc2_vref_dfp_1_5 = /bits/ 8 + <0x7 0x7 0x7>; /*<1_1p6v,0p4v,0p2v>*/ + cc2_vref_dfp_3_0 = /bits/ 8 + <0x7 0x7 0x7>; /*<2p6v,0p8v,0p2v>*/ + }; +}; diff --git a/arch/arm64/boot/dts/realtek/rtd16xxb.dtsi b/arch/arm64/boot/dts/realtek/rtd16xxb.dtsi new file mode 100644 index 000000000000..dfdeefdcce56 --- /dev/null +++ b/arch/arm64/boot/dts/realtek/rtd16xxb.dtsi @@ -0,0 +1,1257 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek RTD1619b SoC family + * + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + i2c0 = &i2c_0; + i2c1 = &i2c_1; + i2c3 = &i2c_3; + i2c4 = &i2c_4; + i2c5 = &i2c_5; + watchdog0 = &watchdog; + }; + + reserved_memory: reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + protected_mem: protected_mem@4000 { + reg = <0x00004000 0x1000000>; + no-map; + }; + + rpc_comm: comm@4080000 { + compatible = "comm"; + reg = <0x04080000 0x1000>; + }; + + rpc_ringbuf: ringbuf@40ff000 { + compatible = "ringbuf"; + reg = <0x040ff000 0x4000>; + }; + + video_fw_ve3: video_fw_ve3@4200000 { + reg = <0x04200000 0x200000>; + no-map; + }; + + audio_heap: audio_heap@4400000 { + compatible = "audio_heap"; + reg = <0x04400000 0xa00000>; + }; + + media_heap: media_heap@4e00000 { + compatible = "media_heap"; + reg = <0x04e00000 0x3800000>; + }; + + hifi: hifi@fe00000 { + reg = <0x0fe00000 0x200000>; + no-map; + }; + + tee: tee@10100000 { + reg = <0x11000000 0x03200000>; + no-map; + }; + + cma_resrved_0:linux,default_cma { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alignment = <0x01000000>; + linux,cma-default; + linux,contiguous-region; + reusable; + }; + + cma_resrved_1:linux,cma_1 { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alloc-ranges=<0x14200000 0x0be00000>; + linux,contiguous-region; + reusable; + status = "disabled"; + }; + + cma_resrved_2:linux,cma_2 { + compatible = "shared-dma-pool"; + size = <0x08000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_3:linux,cma_3 { + compatible = "shared-dma-pool"; + size = <0x10000000>; + alignment = <0x01000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_4:linux,cma_4 { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alignment = <0x01000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_5:linux,cma_5 { + compatible = "shared-dma-pool"; + size = <0x01000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_6:linux,cma_6 { + compatible = "shared-dma-pool"; + size = <0x02000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_7:linux,cma_7 { + compatible = "shared-dma-pool"; + size = <0x01000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_8:linux,cma_8 { + compatible = "shared-dma-pool"; + size = <0x06000000>; + alignment = <0x01000000>; + alloc-ranges=<0x00000000 0x60000000>; + linux,contiguous-region; + reusable; + }; + + cma_resrved_9:linux,cma_9 { + compatible = "shared-dma-pool"; + reusable; + size = <0x04000000>; + alignment = <0x01000000>; + linux,contiguous-region; + alloc-ranges=<0x00000000 0x60000000>; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x100>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x200>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x300>; + enable-method = "psci"; + next-level-cache = <&l2>; + }; + + l2: l2-cache { + compatible = "cache"; + next-level-cache = <&l3>; + + }; + + l3: l3-cache { + compatible = "cache"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + , + ; + }; + + arm_pmu: pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + osc27m: osc { + compatible = "fixed-clock"; + clock-frequency = <27000000>; + clock-output-names = "osc27m"; + #clock-cells = <0>; + }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; + + buadclk: buadclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <432000000>; + clock-output-names = "buadclk"; + }; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00000000 0x00000000 0x00040000>, /* boot code */ + <0xff100000 0xff100000 0x00200000>, /* GIC */ + <0x00040000 0x00040000 0x00020000>, /* PCIE IO*/ + <0xA0000000 0xA0000000 0x00200000>, /* PCIE*/ + <0x98000000 0x98000000 0x00200000>; /* rbus */ + + rbus: rbus@98000000 { + compatible = "simple-bus"; + reg = <0x98000000 0x200000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x98000000 0x200000>, + <0x10040000 0x00040000 0x00020000>, /* PCIE IO*/ + <0xA0000000 0xA0000000 0x00200000>; /* PCIE*/ + + crt: syscon@0 { + compatible = "realtek,rtd1619b-crt", "syscon", "simple-mfd"; + reg = <0x0 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x1000>; + }; + + pinctrl: pinctrl@4e000 { + compatible = "realtek,rtd16xxb-pinctrl", "syscon"; + reg = <0x4e000 0x130>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + #gpio-range-cells = <3>; + ranges = <0x0 0x4e000 0x130>; + }; + + hse: hse@5000 { + reg = <0x5000 0x1000>; + compatible = "realtek,rtd1619b-highspeed-streaming-engine"; + interrupts = ; + clocks = <&cc RTD1619B_CRT_CLK_EN_HSE>; + engine-1-enabled; + engine-0-disabled; + status = "disabled"; + }; + + iso: syscon@7000 { + compatible = "syscon", "simple-mfd"; + reg = <0x7000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x7000 0x1000>; + }; + + u2drd_usb2phy: u2drd_usb2phy@13214 { + compatible = "realtek,usb2phy"; + reg = <0x13214 0x4>, <0x28280 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + ve3: syscon@48c00 { + compatible = "syscon", "simple-mfd"; + reg = <0x48c00 0x100>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x48c00 0x100>; + }; + + u2drd: usb_port0_u2drd@13200 { + compatible = "realtek,dwc3"; + reg = <0x13200 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + u2host_usb2phy: u2host_usb2phy@13c14 { + compatible = "realtek,usb2phy"; + reg = <0x13c14 0x4>, <0x31280 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + u2host: usb_port1_u2host@13c00 { + compatible = "realtek,dwc3"; + reg = <0x13c00 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + u3drd_usb2phy: u3drd_usb2phy@13e14 { + compatible = "realtek,usb2phy"; + reg = <0x13e14 0x4>, <0x58280 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + u3drd_usb3phy: u3drd_usb3phy@13e10 { + compatible = "realtek,usb3phy"; + reg = <0x13e10 0x4>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + u3drd: usb_port2_u3drd@13e00 { + compatible = "realtek,dwc3"; + reg = <0x13e00 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + rtk_type_c: rtk_type_c@7220 { + compatible = "realtek,dwc3-type_c"; + reg = <0x7220 0x20>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + }; + + efuse: efuse@32000 { + compatible = "realtek,rtd1619b-otp"; + reg = <0x32000 0x1000>, <0x17800 0x400>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + }; + + sb2: syscon@1a000 { + compatible = "syscon", "simple-mfd"; + reg = <0x1a000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1a000 0x1000>; + }; + + misc: syscon@1b000 { + compatible = "syscon", "simple-mfd"; + reg = <0x1b000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1b000 0x1000>; + }; + + sbx: syscon@1c000 { + compatible = "syscon", "simple-mfd"; + reg = <0x1c000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1c000 0x1000>; + }; + + scpu_wrapper: syscon@1d000 { + compatible = "syscon", "simple-mfd", "realtek,rtd1619b-scpu-wrapper"; + reg = <0x1d000 0x1000>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1d000 0x1000>; + }; + + cbus_wrapper: syscon@37500 { + compatible = "syscon", "simple-mfd"; + reg = <0x37500 0x10>; + reg-io-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x37500 0x10>; + }; + + m2tmx: syscon@4f000 { + compatible = "syscon", "simple-mfd"; + reg = <0x4f000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x4f000 0x1000>; + }; + + emmc: emmc@12000 { + compatible = "realtek,rtd13xx-emmc"; + emmc-pon-gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; + emmc-pon-toggle-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + reg = <0x00012000 0x00a00>, /* eMMC */ + <0x00000000 0x00600>, /* CRT */ + <0x0001a000 0x00080>, /* SB2 */ + <0x0004e000 0x00100>, /* ISO */ + <0x00007e00 0x00020>, + <0x0004f000 0x00100>, /* m2tmx */ + <0x00012180 0x00060>, + <0x0000765c 0x00004>; + reg-names = "emmc","crt","sb2","mux","iso","m2tmx","cqhci","norst"; + interrupts = <0 42 4>; + speed-step = <3>; /* 0: sdr50, 1: ddr50, 2: hs200, 3: hs400 */ + clocks = <&cc RTD1619B_CRT_CLK_EN_EMMC>, + <&cc RTD1619B_CRT_CLK_EN_EMMC_IP>; + clock-names = "emmc", "emmc_ip"; + resets = <&cc RTD1619B_CRT_RSTN_EMMC>; + nvmem-cells = <&otp_uuid>; + nvmem-cell-names = "uuid"; + reset-names = "emmc"; + pddrive_nf_s0 = <1 0x0 0x0 0x0 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for sdr50 */ + pddrive_nf_s1 = <1 0x0 0x0 0x0 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for ddr50 */ + pddrive_nf_s2 = <1 0x2 0x2 0x2 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for hs200 */ + pddrive_nf_s3 = <1 0x4 0x4 0x4 0x0>; /* pddrive_nf0, pddrive_nf1, pddrive_nf2, pddrive_nf3, pddrive_nf4 ; for hs400 */ + phase_tuning = <1 1>; /* arg0: tx tuning switch, arg1: rx tuning switch, if we want to set user defined tx or rx, we should set 0 for tx or rx*/ + reference_phase = <0 0x0 0 0x0>; /* arg0: switch user defined tx, arg1: tx reference phase value, arg2: switch user defined rx, arg3: rx reference phase value*/ + dqs_tuning = <1>; + dqs_dly_tape = <0x0>; + mbr_tuning_addr = <0xa31000>; + hs400_force_tuning = <0x0>; + cmdq = <0x1>; + frequency = <0xa6>; + status = "disabled"; + }; + + sfc: sfc@1a800 { + compatible = "realtek,rtd16xxb-sfc"; + reg = <0x1a800 0x00050>; + status = "okay"; + }; + + sdio: sdio@10c00 { + compatible = "realtek,rtd1619b-sdio"; + reg = <0x10c00 0x200>, + <0x00000 0x200000>; + interrupts = ; + sdio-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins_1>; + clocks = <&cc RTD1619B_CRT_CLK_EN_SDIO>, + <&cc RTD1619B_CRT_CLK_EN_SDIO_IP>; + clock-names = "sdio", "sdio_ip"; + resets = <&cc RTD1619B_CRT_RSTN_SDIO>; + status = "disabled"; + }; + + sd: sdmmc@10400 { + compatible = "realtek,rtd1619b-sdmmc"; + reg = <0x10400 0x200>, /* SDMMC */ + <0x00000 0x400>, /* CRT */ + <0x1A000 0x400>, /* BS2 */ + <0x4E000 0x60>, /* ISO */ + <0x10A00 0x40>, /* SDIO */ + <0x07000 0x200>; + interrupts = ; + sd-power-gpios = <&gpio 30 GPIO_ACTIVE_HIGH>; /*sd power , output, default high (poweroff) */ + sd-wp-gpios = <&gpio 34 GPIO_PULL_UP>; + sd-cd-gpios = <&gpio 35 GPIO_PULL_UP>; + sdmmc-bounce = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdcard_pins_low>, + <&scpu_ejtag_pins_disable>; + clocks = <&cc RTD1619B_CRT_CLK_EN_SD>, + <&cc RTD1619B_CRT_CLK_EN_SD_IP>; + clock-names = "sd", "sd_ip"; + resets = <&cc RTD1619B_CRT_RSTN_SD>; + status = "disabled"; + }; + + cp: mcp@15000 { + compatible = "realtek,rtk-mcp", "syscon"; + reg = <0x15000 0x1000>, + <0x14000 0x1000>; + status = "disabled"; + }; + + sata_phy: sata_phy@3ff00 { + compatible = "realtek,rtk-sata-phy", "syscon"; + reg = <0x3ff00 0x100>; + clocks = <&cc RTD1619B_CRT_CLK_EN_SATA_WRAP_SYS>, + <&cc RTD1619B_CRT_CLK_EN_SATA_WRAP_SYSH>; + clock-names = "wrap_sys", "wrap_sysh"; + resets = <&cc RTD1619B_CRT_RSTN_SATA_WRAP>; + realtek,crt = <&crt>; + realtek,phyctl = <&m2tmx>; + nvmem-cells = <&otp_sata_cal>; + nvmem-cell-names = "sata-cal"; + #address-cells = <1>; + #size-cells = <0>; + #phy-cells = <1>; + status = "disabled"; + }; + + ahci_sata: sata@3f000 { + compatible = "realtek,ahci-sata"; + reg = <0x3f000 0xf00>; + interrupts = ; + clocks = <&cc RTD1619B_CRT_CLK_EN_SATA_MAC_SYSH>; + resets = <&cc RTD1619B_CRT_RSTN_SATA_MAC_COM>; + realtek,satawrap = <&sata_phy>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + rtk_ve3_uart@4b000 { + compatible = "realtek,rtk-ve3-uart"; + reg = <0x4b000 0x20>; + clocks = <&cc RTD1619B_CRT_CLK_VE3>; + clock-names = "ve3"; + log_enable = <0>; + status = "disabled"; + }; + + ve1: ve1@40000 { + compatible = "realtek,rtk13xx-ve1"; + reg = <0x40000 0xc000>, + <0x08000 0x1000>, + <0x07000 0x30>, + <0x0e000 0x1000>; + interrupts = , + ; + power-domains = <&pd RTD1619B_PD_VE1>; + clocks = <&cc RTD1619B_CRT_CLK_VE1>; + resets = <&cc RTD1619B_CRT_RSTN_VE1>, + <&cc RTD1619B_CRT_RSTN_VE1_BIST>; + reset-names = "reset","bist"; + assigned-clocks = <&cc RTD1619B_CRT_CLK_VE1>; + assigned-clock-parents = <&cc RTD1619B_CRT_PLL_VE1>; + status = "disabled"; + }; + + jpeg: jpeg@3e000 { + compatible = "realtek,rtd13xx-jpeg"; + reg = <0x3e000 0x1000>, + <0x07000 0x30>; + interrupts = ; + clocks = <&cc RTD1619B_CRT_CLK_EN_JPEG>; + clock-names = "jpeg"; + resets = <&cc RTD1619B_CRT_RSTN_JPEG>; + status = "disabled"; + }; + + rng: rng@1000 { + compatible = "realtek,rt16xxb-rng"; + reg = <0x1000 0x2000>; + status = "disabled"; + }; + + nic: r8169soc@16000 { + compatible = "realtek,rtd16xxb-r8169soc"; + reg = <0x16000 0x1000>; /* ETN */ + realtek,iso = <&iso>; + realtek,pinctrl = <&pinctrl>; + interrupts = <0 22 4>; + pinctrl-names = "default"; + pinctrl-0 = <&etn_led_pins>; + local-mac-address = [00 10 20 30 40 50]; + wol-enable = <0>; + output-mode = <0>; /* 0:embedded PHY */ + acp = <0>; /* 0: disable */ + eee = <1>; /* 0: disable, 1: enable */ + clocks = <&ic RTD1619B_ISO_CLK_EN_ETN_250M>, + <&ic RTD1619B_ISO_CLK_EN_ETN_SYS>; + clock-names = "etn_250m", + "etn_sys"; + resets = <&ic RTD1619B_ISO_RSTN_GMAC>, + <&ic RTD1619B_ISO_RSTN_GPHY>; + reset-names = "gmac", + "gphy"; + nvmem-cells = <&otp_etn_rc_r_amp_cal>; + nvmem-cell-names = "rc_r_amp_cal"; + status = "disabled"; + + phy_0 { + interrupt-parent = <&iso_irq_mux>; + interrupts = <28>, <29>, <30>; + irq-mask = <0x70000000>; + por-xv-mask = <0x00000111>; + }; + }; + + spi_0: spi@1bd00 { + compatible = "realtek,rtk-dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <27>; /* SPI_INT */ + reg = <0x1bd00 0x100>, /* DW SPI */ + <0x1b300 0x18>; /* SPI wrapper */ + pinctrl-names = "default"; + pinctrl-0 = <&gspi_pins_0>; + num-chipselect = <1>; + bus-num = <0>; + clocks = <&cc RTD1619B_CRT_CLK_EN_GSPI>; + clock-frequency = <256000000>; + resets = <&cc RTD1619B_CRT_RSTN_GSPI>; + status = "disabled"; + }; + + spi_1: spi@7500 { + compatible = "realtek,rtk-dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <6>; /* SPI1_INT */ + reg = <0x7500 0x100>, /* DW SPI */ + <0x72e4 0x1c>; /* SPI wrapper */ + pinctrl-names = "default"; + pinctrl-0 = <&iso_gspi_pins_0>; + num-chipselect = <1>; + bus-num = <0>; + clock-frequency = <256000000>; + clocks = <&ic RTD1619B_ISO_CLK_EN_ISO_GSPI>; + resets = <&ic RTD1619B_ISO_RSTN_ISO_GSPI>; + status = "disabled"; + }; + + lsadc: lsadc@7900 { + compatible = "realtek,rtk-lsadc0"; + interrupt-parent = <&iso_irq_mux>; + interrupts = <3>; /* LSADC0_INT */ + reg = <0x7900 0x200>, /* LSADC */ + <0x34c 0x4>; /* LSADC_PG */ + clk_gating_en = <1>; /* LSADC0 0:disable; 1:enable */ + debounce0_cnt = <8>; /* debounce cnt : 0 ~ 15 */ + clocks = <&ic RTD1619B_ISO_CLK_EN_LSADC>; + resets = <&ic RTD1619B_ISO_RSTN_LSADC>; + status = "disabled"; + + lsadc0-pad0 { + activate = <1>; /* 0:in-activate; 1:activate */ + ctrl_mode = <0>; /* 0:Voltage mode; 1:Current mode*/ + sw_idx = <0>; /* 0:External input pin 0; 1:External input pin 1 */ + voltage_threshold = <4>; /* 8 bits : 0 ~ 255 */ + adc_val_baseline = <255>; /* 8 bits : 0 ~ 255 */ + }; + + lsadc0-pad1 { + activate = <1>; /* 0:in-activate; 1:activate */ + ctrl_mode = <0>; /* 0:Voltage mode; 1:Current mode*/ + sw_idx = <1>; /* 0:External input pin 0; 1:External input pin 1 */ + voltage_threshold = <255>; /* 8 bits : 0 ~ 255 */ + adc_val_baseline = <255>; /* 8 bits : 0 ~ 255 */ + }; + }; + }; + + gic: interrupt-controller@ff100000 { + compatible = "arm,gic-v3"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xff100000 0x10000>, + <0xff140000 0x80000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + }; + }; + + rtk_ion:rtk,ion { + compatible = "realtek,rtk-ion"; + #address-cells = <1>; + #size-cells = <0>; + + rtk,ion-heap@7 { /* Media */ + compatible = "realtek,rtk-ion-media"; + reg = <7>; + memory-region = <&media_heap>; + rtk,use-cma-pools; + /* rtk,cma-pools-skip-dma-default-array; */ + rtk,cma-pool-flags = ; + rtk,cma-pool-extFlags-info = ; + rtk,memory-reserve = <0x04e00000 0x3800000 RTK_FLAG_ION_HEAP + 0x00C40000 0x003C4000 RTK_FLAG_PROTECTED_DYNAMIC_METADATA>; + + rtk,flag-replace-table = <(RTK_FLAG_PROTECTED_V2_FW_STACK) (RTK_FLAG_PROTECTED_V2_AUDIO_POOL | RTK_FLAG_PROTECTED_EXT_BITS(1)) + (RTK_FLAG_PROTECTED_V2_VIDEO_POOL) (RTK_FLAG_PROTECTED_V2_VIDEO_POOL | RTK_FLAG_PROTECTED_EXT_BITS(1))>; + + rtk,pre-alloc = <(RTK_FLAG_PROTECTED_V2_AUDIO_POOL | RTK_FLAG_PROTECTED_EXT_BITS(1) | RTK_FLAG_ACPUACC) (0x00a00000)>; + + cma_pool_2 { + memory-region = <&cma_resrved_2>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_3 { + memory-region = <&cma_resrved_3>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_4 { + memory-region = <&cma_resrved_4>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_5 { + memory-region = <&cma_resrved_5>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_6 { + memory-region = <&cma_resrved_6>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_7 { + memory-region = <&cma_resrved_7>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_8 { + memory-region = <&cma_resrved_8>; + rtk,cma-pool-extFlags = ; + }; + + cma_pool_9 { + memory-region = <&cma_resrved_9>; + rtk,cma-pool-extFlags = ; + }; + }; + + rtk,ion-heap@8 { /* Audio */ + compatible = "realtek,rtk-ion-audio"; + reg = <8>; + memory-region = <&audio_heap>; + rtk,memory-reserve = <0x04400000 + 0x00a00000 + RTK_FLAG_ION_HEAP>; + }; + + rtk,ion-heap@9 { /* Secure */ + compatible = "realtek,rtk-ion-secure"; + reg = <9>; + rtk,memory-reserve = <>; + status = "disabled"; + }; + }; + + info-pll { + compatible = "realtek,rtd161xb-pll-info"; + realtek,crt = <&crt>; + realtek,scpu-wrapper = <&scpu_wrapper>; + }; + + usb_manager: rtk_usb_manager { + compatible = "realtek,usb-manager"; + }; + + cpu_dvfs: cpu-dvfs { + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&cpu_tm>; + trips { + cpu_crit: cpu-crit { + temperature = <120000>; + hysteresis = <0>; + type = "critical"; + }; + }; + cooling-maps { + }; + }; + }; + + leds: leds { + compatible = "gpio-leds"; + status = "disabled"; + led0 { + gpios = <&gpio 7 GPIO_PULL_DOWN>; + linux,default-trigger = "disk-activity"; + function = LED_FUNCTION_DISK; + }; + }; + + vcpu: vcpu0 { + compatible = "realtek,rtd1619b-vcpu"; + power-domains = <&pd RTD1619B_PD_VE2>; + clocks = <&cc RTD1619B_CRT_CLK_VE2>; + resets = <&cc RTD1619B_CRT_RSTN_VE2>, <&cc RTD1619B_CRT_RSTN_VE2_BIST>; + reset-names = "reset","bist"; + status = "disabled"; + }; + + vcpu_ve3: vcpu1 { + compatible = "realtek,rtd1619b-vcpu"; + power-domains = <&pd RTD1619B_PD_VE3>; + clocks = <&cc RTD1619B_CRT_CLK_VE3>; + status = "disabled"; + }; + rbus-uio { + reg = <0x98000000 0x200000>; + compatible = "generic-uio"; + }; +}; + +&crt { + cc: clock-controller { + compatible = "realtek,rtd1619b-crt-clk"; + #clock-cells = <1>; + #reset-cells = <1>; + realtek,sb2-lock = <&sb2_lock0>; + + assigned-clocks = <&cc RTD1619B_CRT_PLL_SCPU>; + assigned-clock-rates = <1600000000>; + }; +}; + +&iso { + ic: clock-controller { + compatible = "realtek,rtd1619b-iso-clk"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pd: power-domain { + compatible = "realtek,rtd1619b-power"; + #power-domain-cells = <1>; + }; + + iso_irq_mux: iso_irq_mux { + compatible = "realtek,rtd16xxb-iso-irq-mux"; + syscon = <&iso>; + interrupts-extended = <&gic GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + uart0: serial0@800 { + compatible = "snps,dw-apb-uart"; + reg = <0x800 0x400>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts = ; + clock-frequency = <432000000>; + clock-names = "buadclk", "apb_pclk"; + clocks = <&buadclk>, <&ic RTD1619B_ISO_CLK_EN_MISC_UR0>; + resets = <&ic RTD1619B_ISO_RSTN_UR0>; + status = "disabled"; + }; + + gpio: gpio@100 { + compatible = "realtek,gpio"; + reg = <0x100 0x100>, + <0x0 0xB0>; + syscon = <&iso>; + realtek,gpio_base = <0>; + realtek,gpio_numbers = <82>; + interrupt-parent = <&iso_irq_mux>; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + interrupts = <19>, <20>; + gpio-ranges = <&pinctrl 0 0 82>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + /* + * Set gpio default value need to add gpios & gpio-default + * ex: + * gpios = <&gpio 0 GPIO_ACTIVE_HIGH>, + * <&gpio 1 GPIO_ACTIVE_HIGH>, + * <&gpio 2 GPIO_PULL_UP>; + * + * gpio-default = <0>, //output low + * <1>, //output high + * <2>; //input + */ + gpio_default: gpio_default { + compatible = "realtek,gpio-set-default"; + status = "disabled"; + }; + + i2c_0: i2c_0@d00 { + compatible = "realtek,highspeed-i2c"; + reg = <0xd00 0x100>, + <0x000 0x100>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_0>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ic RTD1619B_ISO_CLK_EN_I2C0>; + resets = <&ic RTD1619B_ISO_RSTN_I2C_0>; + status = "disabled"; + }; + + i2c_1: i2c_1@c00 { + compatible = "realtek,i2c"; + reg = <0xc00 0x100>, + <0x000 0x100>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <11>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_1>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&ic RTD1619B_ISO_CLK_EN_I2C1>; + resets = <&ic RTD1619B_ISO_RSTN_I2C_1>; + status = "disabled"; + }; + + watchdog: watchdog@a20 { + compatible = "realtek,watchdog"; + reg = <0xa20 0x10>, <0xa30 0x8>; + interrupts-extended = <&iso_irq_mux 4>; + timeout-sec = <20>; + ov-rstb-oe-init = <1>; + ov-rstb-oe = <0>; + status = "disabled"; + }; + + watchdog5: watchdog-st@aa0 { + reg = <0xaa0 0x20>; + compatible = "realtek,rtd1619b-watchdog-status"; + status = "disabled"; + }; + + reboot_mode: reboot-mode@640 { + compatible = "realtek,reboot-mode"; + reg = <0x640 0x4>; + status = "disabled"; + }; + + rtk_fw_pm: rtk_fw_pm { + compatible = "realtek,fw_pm"; + status = "disabled"; + }; + + rtk_pm: rtk_pm { + compatible = "realtek,rtd16xxb_pm"; + system-power-controller; + syscon = <&iso>; + pm-dbg = <0>; + status = "disabled"; + }; + + rfkill: rfkilligpio { + compatible = "Realtek,rfkill"; + realtek,iso = <&iso>; + realtek,pinctrl = <&pinctrl>; + rfkill-gpios = <&gpio 6 GPIO_ACTIVE_HIGH>; /*bt power, output, default low(poweroff) */ + status = "disabled"; + }; + + pwm: pwm@d0 { + compatible = "realtek,rtk-pwm"; + #pwm-cells = <2>; + reg = <0xd0 0xc>; + realtek,iso = <&iso>; + status = "disabled"; + + pwm_0 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + + pwm_1 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + + pwm_2 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + + pwm_3 { + enable = <0>; + clkout_div = <0xff>; /* default OCD: from 0x0 to 0xff */ + clksrc_div = <0x1>; /* default OSD: from 0x0 to 0xf */ + duty_rate = <50>; /* default duty_rate 0 ~ 100 */ + }; + }; +}; + +&sb2 { + chip: chip-info@200 { + compatible = "realtek,soc-chip"; + reg = <0x200 0x8>; + }; + + rpc: rpc@a80 { + compatible = "realtek,rpc"; + reg = <0xa80 0xc>; /* interrupt enable */ + syscon = <&ve3>; + interrupts = <0 33 4>, + <0 92 4>, + <0 55 4>; + realtek,refclk = <&refclk>; + }; + + rtk_fb: rtk-fb { + compatible = "realtek,framebuffer"; + interrupt-parent = <&gic>; + interrupts = <0 33 4>; + syscon = <&sb2>; + buffer-cnt = <3>; + resolution = <1920 1080>; + fps = <60>; + osd-init = <1>; + skip-front = <2>; + }; + + sb2_lock0: sb2-lock@0 { + compatible = "realtek,sb2-sem"; + reg = <0x0 0x4>; + }; + + sb2_inv: inv@4 { + compatible = "realtek,sysbrg2-inv"; + reg = <0x4 0x10>; + interrupts = <0 36 4>; + nvmem-cells = <&otp_secure_chip_en>; + nvmem-cell-names = "secure_en"; + status = "disabled"; + }; +}; + +&misc { + misc_irq_mux: misc_irq_mux { + compatible = "realtek,rtd16xxb-misc-irq-mux"; + syscon = <&misc>; + interrupts-extended = <&gic GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, + <&gic GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + refclk: refclk@538 { + compatible = "realtek,refclk"; + reg = <0x538 0x10>; + }; + + uart1: serial1@200 { + compatible = "snps,dw-apb-uart"; + reg = <0x200 0x400>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts-extended = <&misc_irq_mux 3>; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + clock-frequency = <432000000>; + clock-names = "buadclk", "apb_pclk"; + clocks = <&buadclk>, <&cc RTD1619B_CRT_CLK_EN_UR1>; + resets = <&cc RTD1619B_CRT_RSTN_UR1>; + status = "disabled"; + }; + + uart2: serial2@400 { + compatible = "snps,dw-apb-uart"; + reg = <0x400 0x400>; + reg-shift = <2>; + reg-io-width = <4>; + interrupts-extended = <&misc_irq_mux 7>; + clock-frequency = <432000000>; + clock-names = "buadclk", "apb_pclk"; + clocks = <&buadclk>, <&cc RTD1619B_CRT_CLK_EN_UR2>; + resets = <&cc RTD1619B_CRT_RSTN_UR2>; + status = "disabled"; + }; + + i2c_3: i2c_3@900 { + compatible = "realtek,i2c"; + reg = <0x900 0x100>, + <0x000 0x100>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <23>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_3>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cc RTD1619B_CRT_CLK_EN_MISC_I2C_3>; + resets = <&cc RTD1619B_CRT_RSTN_I2C_3>; + status = "disabled"; + }; + + i2c_4: i2c_4@a00 { + compatible = "realtek,i2c"; + reg = <0xa00 0x100>, + <0x000 0x100>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <15>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_4>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cc RTD1619B_CRT_CLK_EN_MISC_I2C_4>; + resets = <&cc RTD1619B_CRT_RSTN_I2C_4>; + status = "disabled"; + }; + + i2c_5: i2c_5@b00 { + compatible = "realtek,i2c"; + reg = <0xb00 0x100>, + <0x000 0x100>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <14>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins_5>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cc RTD1619B_CRT_CLK_EN_MISC_I2C_5>; + resets = <&cc RTD1619B_CRT_RSTN_I2C_5>; + status = "disabled"; + }; + + rtk_fan: rtk_fan@c00 { + compatible = "realtek,rtk-fan"; + reg = <0xc00 0x14>; + interrupt-parent = <&misc_irq_mux>; + interrupts = <29>; + status = "disable"; + + timer_target = <0x100000>; + fan_debounce = <0x0>;// 0x0~0x7 + fan_factor = <2>; /* count per revolution for fan */ + clocks = <&cc RTD1619B_CRT_CLK_EN_FAN>; + resets = <&cc RTD1619B_CRT_RSTN_FAN>; + pinctrl-names = "default"; + pinctrl-0 = <&dc_fan_sensor_pins>; + + /* For speed control */ + pwms = <&pwm 1 37878>; // (1) pwm node (2) pwm id (3) out period_ns (1/26400 ns) + }; +}; + +&sata_phy { + sata_phy0: sata-phy@0 { + reg = <0>; + resets = <&cc RTD1619B_CRT_RSTN_SATA_MDIO0>, + <&cc RTD1619B_CRT_RSTN_SATA_PHY_POW0>; + status = "disabled"; + }; + + sata_phy1: sata-phy@1 { + reg = <1>; + resets = <&cc RTD1619B_CRT_RSTN_SATA_MDIO1>, + <&cc RTD1619B_CRT_RSTN_SATA_PHY_POW1>; + status = "disabled"; + }; +}; + +&ahci_sata { + sata_port0: sata-port@0 { + reg = <0>; + phys = <&sata_phy 0>; + resets = <&cc RTD1619B_CRT_RSTN_SATA_MAC_P0>; + sata-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + sata_port1: sata-port@1 { + reg = <1>; + phys = <&sata_phy 1>; + resets = <&cc RTD1619B_CRT_RSTN_SATA_MAC_P1>; + sata-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&scpu_wrapper { + clk-det { + compatible = "realtek,clk-det"; + clk-det,offset = <0x700>; + clk-det,type = <1>; + clock-output-names = "ref_pll_scpu"; + }; + + cpu_tm: thermal-sensor@b00 { + compatible = "realtek,rtd1619b-thermal-sensor"; + reg = <0xb00 0x48>; + realtek,scpu-wrapper = <&scpu_wrapper>; + #thermal-sensor-cells = <0>; + status = "disabled"; + }; +}; + +#include "rtd16xxb-efuse.dtsi" +#include "rtd16xxb-pinctrl.dtsi" +#include "rtd16xxb-usb.dtsi" +#include "rtd16xxb-pcie.dtsi" diff --git a/arch/arm64/configs/rtd161xxb_nas_spi_defconfig b/arch/arm64/configs/rtd161xxb_nas_spi_defconfig new file mode 100644 index 000000000000..a7aba720ec94 --- /dev/null +++ b/arch/arm64/configs/rtd161xxb_nas_spi_defconfig @@ -0,0 +1,460 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_DEFAULT_HOSTNAME="OpenWRT-Stark" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=m +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_NAMESPACES=y +# CONFIG_TIME_NS is not set +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SYSFS_DEPRECATED=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_ZSTD is not set +CONFIG_KALLSYMS_UNCOMPRESSED=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_EMBEDDED=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_ARCH_REALTEK=y +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_1418040 is not set +# CONFIG_ARM64_ERRATUM_1165522 is not set +# CONFIG_ARM64_ERRATUM_1319367 is not set +# CONFIG_ARM64_ERRATUM_1530923 is not set +# CONFIG_ARM64_ERRATUM_1286807 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_1542419 is not set +# CONFIG_ARM64_ERRATUM_1508412 is not set +# CONFIG_CAVIUM_ERRATUM_22375 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_TX2_ERRATUM_219 is not set +# CONFIG_FUJITSU_ERRATUM_010001 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=4 +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_COMPAT=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM64_AMU_EXTN is not set +# CONFIG_ARM64_BTI is not set +# CONFIG_ARM64_E0PD is not set +# CONFIG_ARCH_RANDOM is not set +CONFIG_ARM64_MODULE_PLTS=y +# CONFIG_RELOCATABLE is not set +# CONFIG_EFI is not set +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_DEBUG=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPUFREQ_DT=y +# CONFIG_ARM_SMCCC_SOC_ID is not set +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_BS=y +CONFIG_KPROBES=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_STRIPPED=y +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_BOUNCE is not set +CONFIG_CMA=y +CONFIG_CMA_DEBUG=y +CONFIG_CMA_AREAS=32 +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_ESP=y +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +CONFIG_TCP_CONG_HTCP=y +CONFIG_DEFAULT_HTCP=y +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_XTABLES is not set +CONFIG_IP_VS=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=y +CONFIG_IP_VS_MH_TAB_INDEX=10 +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_IP_NF_IPTABLES is not set +CONFIG_BRIDGE=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=y +CONFIG_NET_CLS_CGROUP=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BPF_JIT=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_PCI=y +# CONFIG_PCIEASPM is not set +CONFIG_PCIE_RTD=y +CONFIG_RTD16XXB_PCIE1_ACP=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_MTD=y +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_SPI_RTK_SFC=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +# CONFIG_ATA_FORCE is not set +CONFIG_SATA_AHCI=m +CONFIG_AHCI_RTK=y +# CONFIG_ATA_SFF is not set +CONFIG_MD=y +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_MIRROR=m +CONFIG_NETDEVICES=y +CONFIG_MACVLAN=y +CONFIG_IPVLAN=y +CONFIG_VXLAN=y +CONFIG_VETH=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_R8169SOC=y +CONFIG_R8168=m +CONFIG_R8125=m +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_USB_RTL8152=m +# 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_MICROCHIP 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_WLAN_VENDOR_QUANTENNA is not set +CONFIG_ISDN=y +CONFIG_INPUT=m +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_MISC=y +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=3 +CONFIG_SERIAL_8250_RUNTIME_UARTS=3 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_HW_RANDOM is not set +# CONFIG_DEVMEM is not set +CONFIG_I2C=y +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_REALTEK=y +CONFIG_SPI=y +CONFIG_PINCTRL=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +# CONFIG_GPIO_CDEV is not set +CONFIG_POWER_RESET_REGMAP_POWEROFF=y +CONFIG_RTK_REBOOT_MODE=y +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +CONFIG_RTK_THERMAL_CPU_CORE_COOLING=y +CONFIG_WATCHDOG=y +CONFIG_RTK_WATCHDOG=y +# CONFIG_RTD119X_WATCHDOG is not set +CONFIG_MFD_APW8886_I2C=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_APW8886=y +# CONFIG_VGA_ARB is not set +# CONFIG_HID is not set +# CONFIG_USB_HID is not set +CONFIG_USB=y +# CONFIG_USB_PCI is not set +CONFIG_USB_OTG=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=y +CONFIG_USB_DWC3=y +# CONFIG_USB_DWC3_OF_SIMPLE is not set +CONFIG_USB_GADGET=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_RTK=y +CONFIG_MMC_RTK_SDMMC=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_DRV_RTK=y +# CONFIG_RTC_DRV_RTD119X is not set +CONFIG_DMADEVICES=y +CONFIG_UIO=y +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_VIRTIO_MENU is not set +CONFIG_STAGING=y +# CONFIG_COMMON_CLK_RTD1195 is not set +# CONFIG_COMMON_CLK_RTD1295 is not set +# CONFIG_COMMON_CLK_RTD1319 is not set +# CONFIG_COMMON_CLK_RTD1395 is not set +# CONFIG_COMMON_CLK_RTD1619 is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_SENDFILE_PATCH=y +CONFIG_RTK_MCP=y +CONFIG_RTK_FAN=y +# CONFIG_RTK_VE3_UART is not set +CONFIG_ION_REALTEK=y +CONFIG_ION_SYSTEM_HEAP_REALTEK=y +CONFIG_ION_CARVEOUT_HEAP_REALTEK=y +CONFIG_ION_CHUNK_HEAP_REALTEK=y +CONFIG_ION_RTK_DHC_HEAP=y +# CONFIG_PD_RTD1295 is not set +# CONFIG_PD_RTD1395 is not set +# CONFIG_PD_RTD1619 is not set +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_PWM=y +CONFIG_PWM_RTK=y +CONFIG_RESET_RTK_M2TMX=y +CONFIG_RTK_EFUSE=y +CONFIG_EXT3_FS=y +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_DNOTIFY is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW is not set +CONFIG_FSCACHE=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=y +CONFIG_NTFS_RW=y +CONFIG_TMPFS=y +CONFIG_TMPFS_XATTR=y +CONFIG_CONFIGFS_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +# CONFIG_JFFS2_ZLIB is not set +CONFIG_JFFS2_LZMA=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_ZLIB is not set +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_EMBEDDED=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V2 is not set +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_UNICODE=y +CONFIG_KEYS=y +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +CONFIG_FORTIFY_SOURCE=y +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_PCRYPT=y +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=m +# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set +CONFIG_CRYPTO_LIB_ARC4=y +# CONFIG_CRYPTO_HW is not set +CONFIG_CRC32_SARWATE=y +CONFIG_LIBCRC32C=m +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_TEXTSEARCH=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_CMA_ALIGNMENT=4 +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_STRIP_ASM_SYMS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_MISC is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_RCU_TRACE is not set +CONFIG_FUNCTION_TRACER=y +# CONFIG_UPROBE_EVENTS is not set diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index ef9f1d5e989d..345066b8e9fc 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -829,6 +829,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, return ret; break; + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + /* + * Nothing required here. + * + * In case of arm64, we rely on the firmware mitigation of + * Speculative Store Bypass as controlled via the ssbd kernel + * parameter. Whenever the mitigation is enabled, it works + * for all of the kernel code with no need to provide any + * additional instructions. + */ + break; + /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h index 5331a8473a46..94de7e913e00 100644 --- a/arch/microblaze/include/asm/elf.h +++ b/arch/microblaze/include/asm/elf.h @@ -10,14 +10,6 @@ #include #ifndef __uClinux__ -#ifndef ELF_GREG_T -#endif -#ifndef ELF_NGREG -#endif -#ifndef ELF_GREGSET_T -#endif -#ifndef ELF_FPREGSET_T -#endif #ifdef __MICROBLAZEEL__ #else #endif diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h index b13463d39b38..f1b6c9a54a90 100644 --- a/arch/microblaze/include/asm/page.h +++ b/arch/microblaze/include/asm/page.h @@ -192,9 +192,6 @@ extern int page_is_ram(unsigned long pfn); #define TOPHYS(addr) __virt_to_phys(addr) -#ifdef CONFIG_MMU - -#endif /* CONFIG_MMU */ #endif /* __KERNEL__ */ diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c index 561154cbcc40..b31b91e57c34 100644 --- a/arch/mips/net/ebpf_jit.c +++ b/arch/mips/net/ebpf_jit.c @@ -1355,6 +1355,9 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, } break; + case BPF_ST | BPF_NOSPEC: /* speculation barrier */ + break; + case BPF_ST | BPF_B | BPF_MEM: case BPF_ST | BPF_H | BPF_MEM: case BPF_ST | BPF_W | BPF_MEM: diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 022103c6a201..658ca2bab13c 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -646,6 +646,12 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, } break; + /* + * BPF_ST NOSPEC (speculation barrier) + */ + case BPF_ST | BPF_NOSPEC: + break; + /* * BPF_ST(X) */ diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c index 579575f9cdae..f300f93ba645 100644 --- a/arch/riscv/net/bpf_jit_comp32.c +++ b/arch/riscv/net/bpf_jit_comp32.c @@ -1251,6 +1251,10 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, return -1; break; + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + break; + case BPF_ST | BPF_MEM | BPF_B: case BPF_ST | BPF_MEM | BPF_H: case BPF_ST | BPF_MEM | BPF_W: diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 8a56b5293117..c113ae818b14 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -939,6 +939,10 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, emit_ld(rd, 0, RV_REG_T1, ctx); break; + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + break; + /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_B: emit_imm(RV_REG_T1, imm, ctx); diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index fc44dce59536..dee01d3b23a4 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -1153,6 +1153,11 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, break; } break; + /* + * BPF_NOSPEC (speculation barrier) + */ + case BPF_ST | BPF_NOSPEC: + break; /* * BPF_ST(X) */ diff --git a/arch/sparc/include/uapi/asm/traps.h b/arch/sparc/include/uapi/asm/traps.h index 930db746f8bd..93d6c95bf5d0 100644 --- a/arch/sparc/include/uapi/asm/traps.h +++ b/arch/sparc/include/uapi/asm/traps.h @@ -10,8 +10,6 @@ #define NUM_SPARC_TRAPS 255 -#ifndef __ASSEMBLY__ -#endif /* !(__ASSEMBLY__) */ /* For patching the trap table at boot time, we need to know how to * form various common Sparc instructions. Thus these macros... diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c index 3364e2a00989..fef734473c0f 100644 --- a/arch/sparc/net/bpf_jit_comp_64.c +++ b/arch/sparc/net/bpf_jit_comp_64.c @@ -1287,6 +1287,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) return 1; break; } + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + break; /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index ca866f1cca2e..4d79391bb787 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -110,66 +110,78 @@ typedef unsigned int addr_t; static inline u8 rdfs8(addr_t addr) { + u8 *ptr = (u8 *)absolute_pointer(addr); u8 v; - asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr)); + asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*ptr)); return v; } static inline u16 rdfs16(addr_t addr) { + u16 *ptr = (u16 *)absolute_pointer(addr); u16 v; - asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr)); + asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*ptr)); return v; } static inline u32 rdfs32(addr_t addr) { + u32 *ptr = (u32 *)absolute_pointer(addr); u32 v; - asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr)); + asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*ptr)); return v; } static inline void wrfs8(u8 v, addr_t addr) { - asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "qi" (v)); + u8 *ptr = (u8 *)absolute_pointer(addr); + asm volatile("movb %1,%%fs:%0" : "+m" (*ptr) : "qi" (v)); } static inline void wrfs16(u16 v, addr_t addr) { - asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "ri" (v)); + u16 *ptr = (u16 *)absolute_pointer(addr); + asm volatile("movw %1,%%fs:%0" : "+m" (*ptr) : "ri" (v)); } static inline void wrfs32(u32 v, addr_t addr) { - asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "ri" (v)); + u32 *ptr = (u32 *)absolute_pointer(addr); + asm volatile("movl %1,%%fs:%0" : "+m" (*ptr) : "ri" (v)); } static inline u8 rdgs8(addr_t addr) { + u8 *ptr = (u8 *)absolute_pointer(addr); u8 v; - asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr)); + asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*ptr)); return v; } static inline u16 rdgs16(addr_t addr) { + u16 *ptr = (u16 *)absolute_pointer(addr); u16 v; - asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr)); + asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*ptr)); return v; } static inline u32 rdgs32(addr_t addr) { + u32 *ptr = (u32 *)absolute_pointer(addr); u32 v; - asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr)); + asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*ptr)); return v; } static inline void wrgs8(u8 v, addr_t addr) { - asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "qi" (v)); + u8 *ptr = (u8 *)absolute_pointer(addr); + asm volatile("movb %1,%%gs:%0" : "+m" (*ptr) : "qi" (v)); } static inline void wrgs16(u16 v, addr_t addr) { - asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "ri" (v)); + u16 *ptr = (u16 *)absolute_pointer(addr); + asm volatile("movw %1,%%gs:%0" : "+m" (*ptr) : "ri" (v)); } static inline void wrgs32(u32 v, addr_t addr) { - asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "ri" (v)); + u32 *ptr = (u32 *)absolute_pointer(addr); + asm volatile("movl %1,%%gs:%0" : "+m" (*ptr) : "ri" (v)); } /* Note: these only return true/false, not a signed return value! */ diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 72f655c238cf..8bcbf06b2e4d 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/boot/head.S @@ -545,6 +548,20 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated) shrq $3, %rcx rep stosq +#ifdef CONFIG_SYNO_KEXEC_TEST +/* + * Insert setup_data for testing whether decompression is skipped + */ + leaq decompression_setup_data(%rip), %r8 + movw 0x206(%rsi), %r9w + cmpw $0x0209, %r9w + jl 3f + movq 0x250(%rsi), %r9 + movq %r9, 0x0(%r8) + movq %r8, 0x250(%rsi) +3: +#endif /* CONFIG_SYNO_KEXEC_TEST */ + /* * If running as an SEV guest, the encryption mask is required in the * page-table setup code below. When the guest also has SEV-ES enabled @@ -799,6 +816,18 @@ SYM_DATA_START_LOCAL(loaded_image_proto) SYM_DATA_END(loaded_image_proto) #endif +#ifdef CONFIG_SYNO_KEXEC_TEST +/* + * setup_data for testing whether decompression is skipped + */ + .data + .balign 4 +decompression_setup_data: + .quad 0x0000000000000000 /* next */ + .long __DECOMPRESSION_TYPE__ /* type */ + .long 0x00000000 /* len, no data */ +#endif /* CONFIG_SYNO_KEXEC_TEST */ + /* * Check for the correct C-bit position when the startup_32 boot-path is used. * diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index e3add857c2c9..c421af5a3cdc 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c @@ -33,7 +33,7 @@ static void copy_boot_params(void) u16 cl_offset; }; const struct old_cmdline * const oldcmd = - (const struct old_cmdline *)OLD_CL_ADDRESS; + absolute_pointer(OLD_CL_ADDRESS); BUILD_BUG_ON(sizeof(boot_params) != 4096); memcpy(&boot_params.hdr, &hdr, sizeof(hdr)); diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 0d0667a9fbd7..acd731c1ce6a 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -445,3 +445,37 @@ 438 i386 pidfd_getfd sys_pidfd_getfd 439 i386 faccessat2 sys_faccessat2 440 i386 process_madvise sys_process_madvise + +# +# start - CONFIG_SYNO_SYSTEM_CALL +# Synology defined system calls are listed here. +# +802 i386 syno_utime sys_syno_utime32 +803 i386 syno_archive_bit sys_syno_archive_bit +804 i386 syno_recv_file sys_syno_recv_file +#805 not used +#806 syno_caseless_stat: removed from linux-5.10.x +#807 syno_caseless_lstat: removed from linux-5.10.x +#808 not used +#809 not used +810 i386 syno_ecrypt_name sys_syno_ecrypt_name +811 i386 syno_decrypt_name sys_syno_decrypt_name +812 i386 syno_acl_check_perm sys_syno_acl_check_perm +813 i386 syno_acl_is_support sys_syno_acl_is_support +814 i386 syno_acl_get_perm sys_syno_acl_get_perm +815 i386 syno_flush_aggregate sys_syno_flush_aggregate +#816 not used +#817 not used +#818 not used +#819 syno_stat: removed from linux-5.10.x +#820 syno_fstat: removed from linux-5.10.x +#821 syno_lstat: removed from linux-5.10.x +822 i386 syno_notify_init sys_syno_notify_init +823 i386 syno_notify_add_watch sys_syno_notify_add_watch +#825 not used +#826 not used +824 i386 syno_notify_remove_watch sys_syno_notify_remove_watch +827 i386 syno_archive_overwrite sys_syno_archive_overwrite +# +# end - CONFIG_SYNO_SYSTEM_CALL +# diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 379819244b91..35666bacd07a 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -407,3 +407,37 @@ 547 x32 pwritev2 compat_sys_pwritev64v2 # This is the end of the legacy x32 range. Numbers 548 and above are # not special and are not to be used for x32-specific syscalls. + +# +# start - CONFIG_SYNO_SYSTEM_CALL +# Synology defined system calls are listed here. +# +802 common syno_utime sys_syno_utime +803 common syno_archive_bit sys_syno_archive_bit +804 common syno_recv_file sys_syno_recv_file +#805 common syno_mtd_alloc sys_syno_mtd_alloc +806 common syno_caseless_stat sys_syno_caseless_stat +807 common syno_caseless_lstat sys_syno_caseless_lstat +#808 not used +#809 not used +810 common syno_ecrypt_name sys_syno_ecrypt_name +811 common syno_decrypt_name sys_syno_decrypt_name +812 common syno_acl_check_perm sys_syno_acl_check_perm +813 common syno_acl_is_support sys_syno_acl_is_support +814 common syno_acl_get_perm sys_syno_acl_get_perm +815 common syno_flush_aggregate sys_syno_flush_aggregate +#816 not used +#817 not used +#818 not used +819 common syno_stat sys_syno_stat +820 common syno_fstat sys_syno_fstat +821 common syno_lstat sys_syno_lstat +822 common syno_notify_init sys_syno_notify_init +823 64 syno_notify_add_watch sys_syno_notify_add_watch +824 64 syno_notify_remove_watch sys_syno_notify_remove_watch +#825 not used +#826 not used +827 common syno_archive_overwrite sys_syno_archive_overwrite +# +# end - CONFIG_SYNO_SYSTEM_CALL +# diff --git a/arch/x86/entry/syscalls/syscallhdr.sh b/arch/x86/entry/syscalls/syscallhdr.sh index cc1e63857427..e110d7072bd3 100644 --- a/arch/x86/entry/syscalls/syscallhdr.sh +++ b/arch/x86/entry/syscalls/syscallhdr.sh @@ -7,6 +7,50 @@ my_abis=`echo "($3)" | tr ',' '|'` prefix="$4" offset="$5" +syno_syscalls() +{ +cat << SYNO_SYSTEM_CALLS + +#ifndef __KERNEL__ +#include + +#define syno_utime(arg1, arg2) syscall(__NR_syno_utime, arg1, arg2) + +#define syno_archive_bit(arg1, arg2) syscall(__NR_syno_archive_bit, arg1, arg2) + +#define syno_recv_file(arg1, arg2, arg3, arg4, arg5) syscall(__NR_syno_recv_file, arg1, arg2, arg3, arg4, arg5) + +#define syno_mtd_alloc(arg1) syscall(__NR_syno_mtd_alloc, arg1) + +#define syno_ecrypt_name(arg1, arg2) syscall(__NR_syno_ecrypt_name, arg1, arg2) +#define syno_decrypt_name(arg1, arg2, arg3) syscall(__NR_syno_decrypt_name, arg1, arg2, arg3) + +#define syno_acl_check_perm(arg1, arg2) syscall(__NR_syno_acl_check_perm, arg1, arg2) +#define syno_acl_is_support(arg1, arg2, arg3) syscall(__NR_syno_acl_is_support, arg1, arg2, arg3) +#define syno_acl_get_perm(arg1, arg2) syscall(__NR_syno_acl_get_perm, arg1, arg2) + +#define syno_flush_aggregate(arg1) syscall(__NR_syno_flush_aggregate, arg1) + +#if __WORDSIZE == 64 +#define syno_stat(arg1, arg2, arg3) syscall(__NR_syno_stat, arg1, arg2, arg3) +#define syno_fstat(arg1, arg2, arg3) syscall(__NR_syno_fstat, arg1, arg2, arg3) +#define syno_lstat(arg1, arg2, arg3) syscall(__NR_syno_lstat, arg1, arg2, arg3) +#define syno_caseless_stat(arg1, arg2) syscall(__NR_syno_caseless_stat, arg1, arg2) +#define syno_caseless_lstat(arg1, arg2) syscall(__NR_syno_caseless_lstat, arg1, arg2) +#endif /* __WORDSIZE == 64 */ + +#define syno_notify_init(arg1) syscall(__NR_syno_notify_init, arg1) +#define syno_notify_add_watch(arg1, arg2, arg3) syscall(__NR_syno_notify_add_watch, arg1, arg2, arg3) +#define syno_notify_remove_watch(arg1, arg2, arg3) syscall(__NR_syno_notify_remove_watch, arg1, arg2, arg3) +#define syno_notify_add_watch32(arg1, arg2, arg3) syscall(__NR_syno_notify_add_watch32, arg1, arg2, arg3) +#define syno_notify_remove_watch32(arg1, arg2, arg3) syscall(__NR_syno_notify_remove_watch32, arg1, arg2, arg3) + +#define syno_archive_overwrite(arg1, arg2) syscall(__NR_syno_archive_overwrite, arg1, arg2) +#endif + +SYNO_SYSTEM_CALLS +} + fileguard=_ASM_X86_`basename "$out" | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` @@ -26,6 +70,8 @@ grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( max=$nr done + syno_syscalls + echo "" echo "#ifdef __KERNEL__" echo "#define __NR_${prefix}syscall_max $max" diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index fc25c88c7ff2..9a199511177a 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ASM_X86_MCE_H #define _ASM_X86_MCE_H @@ -42,6 +45,15 @@ #define MCI_STATUS_CEC_SHIFT 38 /* Corrected Error Count */ #define MCI_STATUS_CEC_MASK GENMASK_ULL(52,38) #define MCI_STATUS_CEC(c) (((c) & MCI_STATUS_CEC_MASK) >> MCI_STATUS_CEC_SHIFT) +#ifdef MY_ABC_HERE /* reference: intel 253668-037US chapter15 & 253669-037US appendix E */ +#define SYNO_MCI_STATUS_UECC_SHIFT 45 +#define SYNO_MCI_STATUS_CECC_SHIFT 46 +#define SYNO_MCI_STATUS_ECC_SYNDROME_SHIFT 47 +#define SYNO_MCI_STATUS_UECC (1ULL << SYNO_MCI_STATUS_UECC_SHIFT) /* uncorrected ECC error */ +#define SYNO_MCI_STATUS_CECC (1ULL << SYNO_MCI_STATUS_CECC_SHIFT) /* correctable ECC error */ +#define SYNO_MCI_STATUS_ECC (SYNO_MCI_STATUS_UECC | SYNO_MCI_STATUS_CECC) +#define SYNO_MCI_STATUS_ECC_SYNDROME (0xffULL << SYNO_MCI_STATUS_ECC_SYNDROME_SHIFT) /* ECC syndrome */ +#endif /* MY_ABC_HERE */ /* AMD-specific bits */ #define MCI_STATUS_TCC BIT_ULL(55) /* Task context corrupt */ diff --git a/arch/x86/include/uapi/asm/stat.h b/arch/x86/include/uapi/asm/stat.h index 9e3982d95d0f..321249dfa4e1 100644 --- a/arch/x86/include/uapi/asm/stat.h +++ b/arch/x86/include/uapi/asm/stat.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _ASM_X86_STAT_H #define _ASM_X86_STAT_H @@ -135,4 +138,28 @@ struct __old_kernel_stat { #endif }; +#ifdef MY_ABC_HERE +#ifdef __KERNEL__ +#include +#endif + +struct SYNOSTAT_EXTRA { +#ifdef __KERNEL__ + struct __kernel_old_timespec create_time; +#else + struct timespec create_time; +#endif + unsigned int archive_version; + unsigned int archive_bit; + unsigned int compressed; + unsigned int flags; + unsigned int reserved[7]; +}; + +struct SYNOSTAT { + struct stat st; + struct SYNOSTAT_EXTRA ext; +}; +#endif /* MY_ABC_HERE */ + #endif /* _ASM_X86_STAT_H */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index d41b70fe4918..c933e052319e 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1994 Linus Torvalds @@ -78,6 +81,16 @@ EXPORT_SYMBOL_GPL(mds_idle_clear); void __init check_bugs(void) { +#ifdef MY_ABC_HERE + if (cmdline_find_option_bool(boot_command_line, "SpectreAll_on") || + cmdline_find_option_bool(boot_command_line, "SpectreV2_on") || + cmdline_find_option_bool(boot_command_line, "SSBD_on") || + cmdline_find_option_bool(boot_command_line, "MDS_on") || + cmdline_find_option_bool(boot_command_line, "KPTI_on")) { + cpu_mitigations_auto_set(); + } +#endif /* MY_ABC_HERE */ + identify_boot_cpu(); /* @@ -244,6 +257,14 @@ static void __init mds_select_mitigation(void) mds_mitigation = MDS_MITIGATION_OFF; return; } +#ifdef MY_ABC_HERE + if(cmdline_find_option_bool(boot_command_line, "SpectreAll_on") || + cmdline_find_option_bool(boot_command_line, "MDS_on")) { + mds_mitigation = MDS_MITIGATION_FULL; + } else { + mds_mitigation = MDS_MITIGATION_OFF; + } +#endif /* MY_ABC_HERE */ if (mds_mitigation == MDS_MITIGATION_FULL) { if (!boot_cpu_has(X86_FEATURE_MD_CLEAR)) @@ -822,8 +843,19 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) return SPECTRE_V2_CMD_NONE; ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); +#ifdef MY_ABC_HERE + if (ret < 0) { + if (cmdline_find_option_bool(boot_command_line, "SpectreAll_on") || + cmdline_find_option_bool(boot_command_line, "SpectreV2_on")) { + return SPECTRE_V2_CMD_AUTO; + } else { + return SPECTRE_V2_CMD_NONE; + } + } +#else /* MY_ABC_HERE */ if (ret < 0) return SPECTRE_V2_CMD_AUTO; +#endif /* MY_ABC_HERE */ for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) { if (!match_option(arg, ret, mitigation_options[i].option)) @@ -923,6 +955,13 @@ static void __init spectre_v2_select_mitigation(void) spectre_v2_enabled = mode; pr_info("%s\n", spectre_v2_strings[mode]); +#ifdef MY_ABC_HERE + if (0 == cmdline_find_option_bool(boot_command_line, "SpectreAll_on") && + 0 == cmdline_find_option_bool(boot_command_line, "SpectreV2_on")) { + return; + } +#endif /* MY_ABC_HERE */ + /* * If spectre v2 protection has been enabled, unconditionally fill * RSB during a context switch; this protects against two independent diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 0c6b02dd744c..7663f8e20d58 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * (c) 2005-2016 Advanced Micro Devices, Inc. @@ -55,6 +58,10 @@ /* Threshold LVT offset is at MSR0xC0000410[15:12] */ #define SMCA_THR_LVT_OFF 0xF000 +#ifdef MY_ABC_HERE +extern int (*funcSYNOECCNotification)(unsigned int type, unsigned int syndrome, u64 memAddr); +#endif /* MY_ABC_HERE */ + static bool thresholding_irq_en; static const char * const th_names[] = { @@ -428,6 +435,16 @@ static void threshold_restart_bank(void *_tr) hi |= MASK_COUNT_EN_HI; wrmsr(tr->b->address, lo, hi); + +#ifdef MY_ABC_HERE + rdmsr(tr->b->address, lo, hi); + if ((hi & MASK_OVERFLOW_HI) && 1 == tr->reset) { + hi = (hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) | + (THRESHOLD_MAX - tr->b->threshold_limit); + wrmsr_safe(tr->b->address, lo, hi); + } + tr->reset = 0; +#endif /* MY_ABC_HERE */ } static void mce_threshold_block_init(struct threshold_block *b, int offset) @@ -439,6 +456,9 @@ static void mce_threshold_block_init(struct threshold_block *b, int offset) }; b->threshold_limit = THRESHOLD_MAX; +#ifdef MY_ABC_HERE + tr.reset = 1; +#endif /* MY_ABC_HERE */ threshold_restart_bank(&tr); }; @@ -889,6 +909,9 @@ bool amd_mce_is_memory_error(struct mce *m) static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc) { struct mce m; +#ifdef MY_ABC_HERE + u64 eccsyndrome,eccstatus; +#endif /* MY_ABC_HERE */ mce_setup(&m); @@ -918,6 +941,15 @@ static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc) rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m.synd); } +#ifdef MY_ABC_HERE + eccstatus = ((m.status & SYNO_MCI_STATUS_ECC) >> SYNO_MCI_STATUS_UECC_SHIFT); + eccsyndrome = ((m.status & SYNO_MCI_STATUS_ECC_SYNDROME) >> SYNO_MCI_STATUS_ECC_SYNDROME_SHIFT); + if (funcSYNOECCNotification && (m.status & SYNO_MCI_STATUS_ECC)) { + funcSYNOECCNotification(((unsigned int *)(void *)&eccstatus)[0], + ((unsigned int *)(void *)&eccsyndrome)[0], m.addr); + } +#endif /* MY_ABC_HERE */ + mce_log(&m); } @@ -1497,6 +1529,10 @@ int mce_threshold_create_device(unsigned int cpu) unsigned int numbanks, bank; struct threshold_bank **bp; int err; +#ifdef MY_ABC_HERE + struct threshold_block *first_block = NULL, *block = NULL, *tmp = NULL; + u32 hi, lo; +#endif /* MY_ABC_HERE */ if (!mce_flags.amd_threshold) return 0; @@ -1519,6 +1555,27 @@ int mce_threshold_create_device(unsigned int cpu) } this_cpu_write(threshold_banks, bp); +#ifdef MY_ABC_HERE + for (bank = 0; bank < numbanks; ++bank) { + if (!(per_cpu(bank_map, cpu) & (1 << bank))) + continue; + + first_block = bp[bank]->blocks; + if (!first_block) + continue; + + rdmsr_safe(first_block->address, &lo, &hi); + hi = (hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) | (THRESHOLD_MAX - first_block->threshold_limit); + err = wrmsr_safe(first_block->address, lo, hi); + + list_for_each_entry_safe(block, tmp, &first_block->miscj, miscj) { + rdmsr_safe(block->address, &lo, &hi); + hi = (hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) | (THRESHOLD_MAX - block->threshold_limit); + err = wrmsr_safe(block->address, lo, hi); + } + } +#endif /* MY_ABC_HERE */ + if (thresholding_irq_en) mce_threshold_vector = amd_threshold_interrupt; return 0; diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index b7a27589dfa0..23caeced8cf9 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Machine check handler. @@ -101,6 +104,11 @@ static DEFINE_PER_CPU(struct mce, mces_seen); static unsigned long mce_need_notify; static int cpu_missing; +#ifdef MY_ABC_HERE +int (*funcSYNOECCNotification)(unsigned int type, unsigned int syndrome, u64 memAddr) = NULL; +EXPORT_SYMBOL(funcSYNOECCNotification); +#endif /* MY_ABC_HERE */ + /* * MCA banks polled by the period polling timer for corrected events. * With Intel CMCI, this only has MCA banks which do not support CMCI (if any). @@ -741,6 +749,9 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b) bool error_seen = false; struct mce m; int i; +#ifdef MY_ABC_HERE + u64 mstatus, eccsyndrome; +#endif /* MY_ABC_HERE */ this_cpu_inc(mce_poll_count); @@ -808,6 +819,17 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b) goto clear_it; mce_read_aux(&m, i); + +#ifdef MY_ABC_HERE + mstatus = ((m.status & SYNO_MCI_STATUS_ECC) >> SYNO_MCI_STATUS_UECC_SHIFT); + eccsyndrome = ((m.status & SYNO_MCI_STATUS_ECC_SYNDROME) >> SYNO_MCI_STATUS_ECC_SYNDROME_SHIFT); + if (funcSYNOECCNotification && + ((m.status & SYNO_MCI_STATUS_ECC))) { + funcSYNOECCNotification(((unsigned int *)(void *)&mstatus)[0], + ((unsigned int *)(void *)&eccsyndrome)[0], m.addr); + } +#endif /* MY_ABC_HERE */ + m.severity = mce_severity(&m, NULL, mca_cfg.tolerant, NULL, false); /* * Don't get the IP here because it's unlikely to diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 97aa900386cb..da0331591878 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs @@ -69,7 +72,12 @@ static void printk_stack_address(unsigned long address, int reliable, const char *log_lvl) { touch_nmi_watchdog(); +#ifdef MY_ABC_HERE + printk("%s [<%px>] %s%pB\n", log_lvl, (void *)address, reliable ? "" : "? ", + (void *)address); +#else /* MY_ABC_HERE */ printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address); +#endif /* MY_ABC_HERE */ } static int copy_code(struct pt_regs *regs, u8 *buf, unsigned long src, diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index d3c531d3b244..6970b2d56c0e 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -79,6 +82,11 @@ static struct console early_vga_console = { static unsigned long early_serial_base = 0x3f8; /* ttyS0 */ #define XMTRDY 0x20 +#ifdef MY_ABC_HERE +#define TEMT 0x40 +#define THRE XMTRDY +#define BOTH_EMPTY (TEMT | THRE) +#endif /* MY_ABC_HERE */ #define DLAB 0x80 @@ -206,6 +214,196 @@ static unsigned int mem32_serial_in(unsigned long addr, int offset) return readl(vaddr + offset); } +#ifdef MY_ABC_HERE +static void early_serial_hw_deinit(void) +{ + unsigned long timeout_jiffies = jiffies + msecs_to_jiffies(2000); + while ((serial_in(early_serial_base, LSR) & BOTH_EMPTY) != BOTH_EMPTY) { + if (time_after(jiffies, timeout_jiffies)) { + break; + } + } + serial_out(early_serial_base, IER, 0); /* no interrupt */ + serial_out(early_serial_base, FCR, 0); /* no fifo */ +} + +static struct console early_serial_console = { + .name = "earlyser", + .write = early_serial_write, + .flags = CON_PRINTBUFFER, + .index = -1, + /* Synology add */ + .pcimapaddress = 0, + .pcimapsize = 0, + .deinit = early_serial_hw_deinit, +}; + +static __init void early_mmio_serial_init(char *s) +{ + unsigned divisor; + unsigned long addr; + unsigned long baud = 115200; /* Default baud 115200 */ + unsigned long base_clock = 1843200; /* Default clock 1.84M */ + char *e; + + if (*s == ',') + ++s; + + if (!strncmp(s, "0x", 2)) { + addr = simple_strtoul(s, &e, 16); + } + + s = e; + + if (*s == ',') + ++s; + + baud = simple_strtoul(s, &e, 10); + + s = e; + + if (*s == ',') + ++s; + + base_clock = simple_strtoul(s, &e, 10); + + + early_serial_base = (unsigned long)early_ioremap(addr, 0x10); + + + serial_in = mem32_serial_in; + serial_out = mem32_serial_out; + + early_serial_console.pcimapaddress = (void __iomem *)early_serial_base; + early_serial_console.pcimapsize = 0x10; + + divisor = (base_clock / 16) / baud; + + early_serial_hw_init(divisor); +} + +/* + * early_pcifull_serial_init() + * + */ +static __init void early_pcifull_serial_init(char *s) +{ + unsigned divisor; + unsigned long baud = DEFAULT_BAUD; + u8 bus, slot, func; + u8 htype, secondbus; + u32 classcode, bar0; + u16 cmdreg; + char *e; + + /* + * First, part the param to get the BDF values + */ + if (*s == ',') + ++s; + + if (*s == 0) + return; + + bus = (u8)simple_strtoul(s, &e, 16); + s = e; + if (*s != ':') + return; + ++s; + slot = (u8)simple_strtoul(s, &e, 16); + s = e; + if (*s != '.') + return; + ++s; + func = (u8)simple_strtoul(s, &e, 16); + s = e; + + htype = read_pci_config_byte(bus, slot, func, PCI_HEADER_TYPE); + while((htype & 0x7F) == PCI_HEADER_TYPE_BRIDGE || + (htype & 0x7F) == PCI_HEADER_TYPE_CARDBUS ){ + + secondbus = read_pci_config_byte(bus, slot, func, PCI_SECONDARY_BUS); + if(secondbus == 0xFF) + return; + bus = secondbus; + + if (*s != ',') + return; + ++s; + + slot = (u8)simple_strtoul(s, &e, 16); + s = e; + if (*s != '.') + return; + ++s; + + func = (u8)simple_strtoul(s, &e, 16); + s = e; + + htype = read_pci_config_byte(bus, slot, func, PCI_HEADER_TYPE); + } + + if ((htype & 0x7F) != PCI_HEADER_TYPE_NORMAL) + return ; + + /* A baud might be following */ + if (*s == ',') + s++; + + /* + * Second, find the device from the BDF + */ + cmdreg = read_pci_config(bus, slot, func, PCI_COMMAND); + classcode = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); + bar0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); + + /* + * Determine if it is IO or memory mapped + */ + if (bar0 & 0x01) { + /* it is IO mapped */ + serial_in = io_serial_in; + serial_out = io_serial_out; + early_serial_base = bar0&0xfffffffc; + write_pci_config(bus, slot, func, PCI_COMMAND, + cmdreg|PCI_COMMAND_IO); + } else { + /* It is memory mapped - assume 32-bit alignment */ + serial_in = mem32_serial_in; + serial_out = mem32_serial_out; + /* WARNING! assuming the address is always in the first 4G */ + early_serial_base = + (unsigned long)early_ioremap(bar0 & 0xfffffff0, 0x10); + early_serial_console.pcimapaddress = (void __iomem *)early_serial_base; + /* base on pci spec with serial console */ + early_serial_console.pcimapsize = 0x10; + write_pci_config(bus, slot, func, PCI_COMMAND, + cmdreg|PCI_COMMAND_MEMORY); + } + + /* + * Lastly, initalize the hardware + */ + if (*s) { + if (strcmp(s, "nocfg") == 0) + /* Sometimes, we want to leave the UART alone + * and assume the BIOS has set it up correctly. + * "nocfg" tells us this is the case, and we + * should do no more setup. + */ + return; + if (kstrtoul(s, 0, &baud) < 0 || baud == 0) + baud = DEFAULT_BAUD; + } + + /* Convert from baud to divisor value */ + divisor = 115200 / baud; + + /* Set up the HW */ + early_serial_hw_init(divisor); +} +#endif /* MY_ABC_HERE */ + /* * early_pci_serial_init() * @@ -266,6 +464,10 @@ static __init void early_pci_serial_init(char *s) /* * Verify it is a UART type device */ +#ifdef MY_ABC_HERE + force = 1; +#endif /* MY_ABC_HERE */ + if (((classcode >> 16 != PCI_CLASS_COMMUNICATION_MODEM) && (classcode >> 16 != PCI_CLASS_COMMUNICATION_SERIAL)) || (((classcode >> 8) & 0xff) != 0x02)) /* 16550 I/F at BAR0 */ { @@ -290,10 +492,16 @@ static __init void early_pci_serial_init(char *s) /* WARNING! assuming the address is always in the first 4G */ early_serial_base = (unsigned long)early_ioremap(bar0 & 0xfffffff0, 0x10); +#ifdef MY_ABC_HERE + early_serial_console.pcimapaddress = (void __iomem *)early_serial_base; + /* base on pci spec with serial console */ + early_serial_console.pcimapsize = 0x10; +#endif /* MY_ABC_HERE */ write_pci_config(bus, slot, func, PCI_COMMAND, cmdreg|PCI_COMMAND_MEMORY); } + /* * Initialize the hardware */ @@ -317,12 +525,16 @@ static __init void early_pci_serial_init(char *s) } #endif +#ifdef MY_ABC_HERE + /* Move to upper */ +#else /* MY_ABC_HERE */ static struct console early_serial_console = { .name = "earlyser", .write = early_serial_write, .flags = CON_PRINTBUFFER, .index = -1, }; +#endif /* MY_ABC_HERE */ static void early_console_register(struct console *con, int keep_early) { @@ -339,7 +551,11 @@ static void early_console_register(struct console *con, int keep_early) register_console(early_console); } +#ifdef MY_ABC_HERE +int __init setup_early_printk(char *buf) +#else /* MY_ABC_HERE */ static int __init setup_early_printk(char *buf) +#endif /* MY_ABC_HERE */ { int keep; @@ -369,7 +585,21 @@ static int __init setup_early_printk(char *buf) early_console_register(&early_serial_console, keep); buf += 9; /* Keep from match the above "serial" */ } +#ifdef MY_ABC_HERE + if (!strncmp(buf, "pcifull", 7)) { + early_pcifull_serial_init(buf + 7); + early_console_register(&early_serial_console, keep); + buf += 7; /* Keep from match the above "serial" */ + } +#endif /* MY_ABC_HERE */ #endif +#ifdef MY_ABC_HERE + if (!strncmp(buf, "mmio", 4)) { + early_mmio_serial_init(buf + 4); + early_console_register(&early_serial_console, keep); + buf += 4; /* Keep from match the above "serial" */ + } +#endif /* MY_ABC_HERE */ if (!strncmp(buf, "vga", 3) && boot_params.screen_info.orig_video_isVGA == 1) { max_xpos = boot_params.screen_info.orig_video_cols; @@ -395,4 +625,7 @@ static int __init setup_early_printk(char *buf) return 0; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(setup_early_printk); +#endif /* MY_ABC_HERE */ early_param("earlyprintk", setup_early_printk); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 28c89fce0dab..b8c29d353b6c 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 1995 Linus Torvalds @@ -48,6 +51,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ /* * max_low_pfn_mapped: highest directly mapped pfn < 4 GB @@ -944,6 +950,10 @@ void __init setup_arch(char **cmdline_p) x86_report_nx(); +#ifdef CONFIG_SYNO_KEXEC_TEST + syno_kexec_test_init(); +#endif /* CONFIG_SYNO_KEXEC_TEST */ + /* after early param, so could get panic from serial */ memblock_x86_reserve_range_setup_data(); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 8baff500914e..73733cf1655f 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * x86 SMP booting functions @@ -1314,6 +1317,10 @@ static void __init smp_get_logical_apicid(void) void __init native_smp_prepare_cpus(unsigned int max_cpus) { unsigned int i; +#ifdef MY_DEF_HERE + unsigned long flags; + unsigned char SynoMemoryTrainFailReason = 0; +#endif /* MY_DEF_HERE */ smp_cpu_index_default(); @@ -1367,6 +1374,16 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) pr_info("CPU0: "); print_cpu_info(&cpu_data(0)); +#ifdef MY_DEF_HERE + spin_lock_irqsave(&rtc_lock, flags); + SynoMemoryTrainFailReason = CMOS_READ(CONFIG_SYNO_BIOS_MRC_POSTCODE_CMOS_ADDR); + CMOS_WRITE(0xff, CONFIG_SYNO_BIOS_MRC_POSTCODE_CMOS_ADDR); + spin_unlock_irqrestore(&rtc_lock, flags); + if (0xff != SynoMemoryTrainFailReason) { + pr_err("%s: this boot have memory training fail, last reason is 0x%02x\n", __func__, SynoMemoryTrainFailReason); + } +#endif /* MY_DEF_HERE */ + uv_system_init(); set_mtrr_aps_delayed_init(); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3ad6f77ea1c4..04115daa9b8c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Kernel-based Virtual Machine driver for Linux @@ -117,7 +120,11 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops); static bool __read_mostly ignore_msrs = 0; module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR); +#ifdef MY_ABC_HERE +static bool __read_mostly report_ignored_msrs = false; +#else /* MY_ABC_HERE */ static bool __read_mostly report_ignored_msrs = true; +#endif /* MY_ABC_HERE */ module_param(report_ignored_msrs, bool, S_IRUGO | S_IWUSR); unsigned int min_timer_period_us = 200; diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9c1545c376e9..9e6d3cb72787 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1995 Linus Torvalds @@ -762,7 +765,11 @@ static inline void show_signal_msg(struct pt_regs *regs, unsigned long error_code, unsigned long address, struct task_struct *tsk) { +#ifdef MY_ABC_HERE + const char *loglvl = task_pid_nr(tsk) > 1 ? KERN_WARNING : KERN_EMERG; +#else const char *loglvl = task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG; +#endif /* MY_ABC_HERE */ if (!unhandled_signal(tsk, SIGSEGV)) return; diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 1aab92930569..aa2d8f93bd15 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2017 Intel Corporation. All rights reserved. @@ -79,9 +82,24 @@ void __init pti_check_boottime_disable(void) { char arg[5]; int ret; +#ifdef MY_ABC_HERE + /* Assume mode is off unless overridden. */ + pti_mode = PTI_FORCE_OFF; + if (cmdline_find_option_bool(boot_command_line, "SpectreAll_on") || + cmdline_find_option_bool(boot_command_line, "KPTI_on")) { + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { + pti_print_if_insecure("disabled on command line."); + return; + } else { + pti_mode = PTI_FORCE_ON; + goto enable; + } + } +#else /* MY_ABC_HERE */ /* Assume mode is auto unless overridden. */ pti_mode = PTI_AUTO; +#endif /* MY_ABC_HERE */ if (hypervisor_is_type(X86_HYPER_XEN_PV)) { pti_mode = PTI_FORCE_OFF; @@ -107,12 +125,16 @@ void __init pti_check_boottime_disable(void) } } +#ifdef MY_ABC_HERE + return; +#else /* MY_ABC_HERE */ if (cmdline_find_option_bool(boot_command_line, "nopti") || cpu_mitigations_off()) { pti_mode = PTI_FORCE_OFF; pti_print_if_insecure("disabled on command line."); return; } +#endif /* MY_ABC_HERE */ autosel: if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index d5fa77256058..0a962cd6bac1 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1141,6 +1141,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, } break; + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + if (boot_cpu_has(X86_FEATURE_XMM2)) + /* Emit 'lfence' */ + EMIT3(0x0F, 0xAE, 0xE8); + break; + /* ST: *(u8*)(dst_reg + off) = imm */ case BPF_ST | BPF_MEM | BPF_B: if (is_ereg(dst_reg)) diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c index 2cf4d217840d..4bd0f98df700 100644 --- a/arch/x86/net/bpf_jit_comp32.c +++ b/arch/x86/net/bpf_jit_comp32.c @@ -1705,6 +1705,12 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, i++; break; } + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + if (boot_cpu_has(X86_FEATURE_XMM2)) + /* Emit 'lfence' */ + EMIT3(0x0F, 0xAE, 0xE8); + break; /* ST: *(u8*)(dst_reg + off) = imm */ case BPF_ST | BPF_MEM | BPF_H: case BPF_ST | BPF_MEM | BPF_B: diff --git a/arch/xtensa/include/uapi/asm/types.h b/arch/xtensa/include/uapi/asm/types.h index 12db8ac38750..0e6e6dbaa1ac 100644 --- a/arch/xtensa/include/uapi/asm/types.h +++ b/arch/xtensa/include/uapi/asm/types.h @@ -23,8 +23,5 @@ # define __XTENSA_UL_CONST(x) ___XTENSA_UL_CONST(x) #endif -#ifndef __ASSEMBLY__ - -#endif #endif /* _UAPI_XTENSA_TYPES_H */ diff --git a/block/bio.c b/block/bio.c index 9c931df2d986..5a32ea8c2a2d 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2001 Jens Axboe @@ -689,6 +692,16 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_write_hint = bio_src->bi_write_hint; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bio_src, BIO_CORRECTION_RETRY))) + bio_set_flag(bio, BIO_CORRECTION_RETRY); + if (unlikely(bio_flagged(bio_src, BIO_CORRECTION_ABORT))) + bio_set_flag(bio, BIO_CORRECTION_ABORT); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bio_src, BIO_SYNO_FULL_STRIPE_MERGE))) + bio_set_flag(bio, BIO_SYNO_FULL_STRIPE_MERGE); +#endif /* MY_ABC_HERE */ bio_clone_blkg_association(bio, bio_src); blkcg_bio_issue_init(bio); @@ -1425,6 +1438,14 @@ void bio_endio(struct bio *bio) if (bio->bi_disk) rq_qos_done_bio(bio->bi_disk->queue, bio); +#ifdef MY_ABC_HERE + if (bio->bi_disk && bio_flagged(bio, BIO_TRACE_COMPLETION)) { + trace_block_bio_complete(bio->bi_disk->queue, bio); + bio_clear_flag(bio, BIO_TRACE_COMPLETION); + } +#else +#endif /* MY_ABC_HERE */ + /* * Need to have a real endio function for chained bios, otherwise * various corner cases will break (like stacking block devices that @@ -1437,11 +1458,13 @@ void bio_endio(struct bio *bio) bio = __bio_chain_endio(bio); goto again; } - +#ifdef MY_ABC_HERE +#else if (bio->bi_disk && bio_flagged(bio, BIO_TRACE_COMPLETION)) { trace_block_bio_complete(bio->bi_disk->queue, bio); bio_clear_flag(bio, BIO_TRACE_COMPLETION); } +#endif /* MY_ABC_HERE */ blk_throtl_bio_endio(bio); /* release cgroup info */ diff --git a/block/blk-core.c b/block/blk-core.c index 2d53e2ff48ff..7d202f840500 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991, 1992 Linus Torvalds @@ -42,6 +45,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #define CREATE_TRACE_POINTS #include @@ -121,8 +127,10 @@ void blk_rq_init(struct request_queue *q, struct request *rq) rq->internal_tag = BLK_MQ_NO_TAG; rq->start_time_ns = ktime_get_ns(); rq->part = NULL; - refcount_set(&rq->ref, 1); blk_crypto_rq_set_defaults(rq); +#ifdef MY_ABC_HERE + rq->syno_seq = 0; +#endif /* MY_ABC_HERE */ } EXPORT_SYMBOL(blk_rq_init); @@ -145,6 +153,9 @@ static const char *const blk_op_name[] = { REQ_OP_NAME(SCSI_OUT), REQ_OP_NAME(DRV_IN), REQ_OP_NAME(DRV_OUT), +#ifdef MY_ABC_HERE + REQ_OP_NAME(UNUSED_HINT), +#endif /* MY_ABC_HERE */ }; #undef REQ_OP_NAME @@ -706,7 +717,11 @@ static inline bool bio_check_ro(struct bio *bio, struct hd_struct *part) "Trying to write to read-only block-device %s (partno %d)\n", bio_devname(bio, b), part->partno); /* Older lvm-tools actually trigger this */ +#ifdef MY_ABC_HERE + return true; +#else return false; +#endif /* MY_ABC_HERE */ } return false; @@ -861,6 +876,12 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio) if (!blk_queue_secure_erase(q)) goto not_supported; break; +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: + if (!blk_queue_unused_hint(q)) + goto not_supported; + break; +#endif /* MY_ABC_HERE */ case REQ_OP_WRITE_SAME: if (!q->limits.max_write_same_sectors) goto not_supported; @@ -960,9 +981,15 @@ static blk_qc_t __submit_bio_noacct(struct bio *bio) { struct bio_list bio_list_on_stack[2]; blk_qc_t ret = BLK_QC_T_NONE; +#ifdef MY_ABC_HERE + unsigned int noio_flag; +#endif /* MY_ABC_HERE */ BUG_ON(bio->bi_next); +#ifdef MY_ABC_HERE + noio_flag = memalloc_noio_save(); +#endif /* MY_ABC_HERE */ bio_list_init(&bio_list_on_stack[0]); current->bio_list = bio_list_on_stack; @@ -1002,6 +1029,10 @@ static blk_qc_t __submit_bio_noacct(struct bio *bio) } while ((bio = bio_list_pop(&bio_list_on_stack[0]))); current->bio_list = NULL; +#ifdef MY_ABC_HERE + memalloc_noio_restore(noio_flag); +#endif /* MY_ABC_HERE */ + return ret; } @@ -1052,7 +1083,19 @@ blk_qc_t submit_bio_noacct(struct bio *bio) * it is active, and then process them after it returned. */ if (current->bio_list) { +#ifdef MY_ABC_HERE + if (bio_flagged(bio, BIO_SYNO_DELAYED)) { + bio_clear_flag(bio, BIO_SYNO_DELAYED); + /* mq device never use bio_list[1] */ + if (!bio->bi_disk->fops->submit_bio) + bio_list_add(¤t->bio_list[0], bio); + else + bio_list_add_head(¤t->bio_list[1], bio); + } else + bio_list_add(¤t->bio_list[0], bio); +#else /* MY_ABC_HERE */ bio_list_add(¤t->bio_list[0], bio); +#endif /* MY_ABC_HERE */ return BLK_QC_T_NONE; } @@ -1101,8 +1144,14 @@ blk_qc_t submit_bio(struct bio *bio) if (unlikely(block_dump)) { char b[BDEVNAME_SIZE]; +#ifdef MY_ABC_HERE + printk(KERN_DEBUG "ppid:%d(%s), pid:%d(%s), %s block %Lu on %s (%u sectors)\n", + task_pid_nr(current->real_parent), current->real_parent->comm, + task_pid_nr(current), current->comm, +#else /* MY_ABC_HERE */ printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", current->comm, task_pid_nr(current), +#endif /* MY_ABC_HERE */ op_is_write(bio_op(bio)) ? "WRITE" : "READ", (unsigned long long)bio->bi_iter.bi_sector, bio_devname(bio, b), count); @@ -1289,6 +1338,58 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) } } +#ifdef MY_ABC_HERE +static inline unsigned int syno_block_latency_bucket_offset_get(const u64 u64Latency) +{ + unsigned int uOffset = 0; + + /* latency >= 1024 us */ + if ( 0x1F < u64Latency) { + uOffset += 1; + } + + /* latency >= 32ms */ + if (unlikely( 0x3FF < u64Latency)) { + uOffset += 1; + } + + /* latency >= 1024ms */ + if (unlikely( 0x7FFF < u64Latency)) { + uOffset += 1; + } + + return uOffset; +} + +static void syno_block_latency_cal(struct request *req) +{ + int iDirection = rq_data_dir(req); + unsigned int uBucketOffset = 0; + u64 u64StepOffset = 0; + u64 u64CmdRespTime = 0; + + if (!req->rq_disk) { + return; + } + u64CmdRespTime = cpu_clock(0) - req->u64IssueTime; + + req->rq_disk->u64CplCmdCnt[iDirection] += 1; + + // calculate the response time buckets + // shift to 32us + u64StepOffset = (u64CmdRespTime >> 15); + // calculate the offset of buckets with the response time + uBucketOffset = syno_block_latency_bucket_offset_get(u64StepOffset); + u64StepOffset >>= (5 * uBucketOffset); + if (unlikely(31 < u64StepOffset)) { + uBucketOffset = (SYNO_BLOCK_RESPONSE_BUCKETS_END - 1); + u64StepOffset = 31; + } + req->rq_disk->u64RespTimeSum[iDirection] += u64CmdRespTime; + req->rq_disk->u64RespTimeBuckets[iDirection][uBucketOffset][u64StepOffset] += 1; +} +#endif /* MY_ABC_HERE */ + void blk_account_io_done(struct request *req, u64 now) { /* @@ -1310,6 +1411,21 @@ void blk_account_io_done(struct request *req, u64 now) part_stat_unlock(); hd_struct_put(part); +#ifdef MY_ABC_HERE + if (likely(req->start_time_ns < req->io_start_time_ns)) { + req->rq_disk->u64WaitTime[rq_data_dir(req)] += + req->io_start_time_ns - req->start_time_ns; + } + syno_block_latency_cal(req); +#ifdef MY_ABC_HERE + if (0 != req->syno_seq) { + req->rq_disk->seq_ios[SYNO_DISK_SEQ_STAT_NEAR_SEQ]++; + req->rq_disk->seq_ios[SYNO_DISK_SEQ_STAT_SEQ] += + !!(req->syno_seq & (1 << SYNO_DISK_SEQ_STAT_SEQ)); + } +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + } } @@ -1760,6 +1876,9 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) if (!list_empty(&plug->mq_list)) blk_mq_flush_plug_list(plug, from_schedule); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(blk_flush_plug_list); +#endif /* MY_ABC_HERE */ /** * blk_finish_plug - mark the end of a batch of submitted I/O diff --git a/block/blk-flush.c b/block/blk-flush.c index 7ee7e5e8905d..70f1d02135ed 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -263,6 +263,11 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error) spin_unlock_irqrestore(&fq->mq_flush_lock, flags); } +bool is_flush_rq(struct request *rq) +{ + return rq->end_io == flush_end_io; +} + /** * blk_kick_flush - consider issuing flush request * @q: request_queue being kicked @@ -330,6 +335,14 @@ static void blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq, flush_rq->rq_flags |= RQF_FLUSH_SEQ; flush_rq->rq_disk = first_rq->rq_disk; flush_rq->end_io = flush_end_io; + /* + * Order WRITE ->end_io and WRITE rq->ref, and its pair is the one + * implied in refcount_inc_not_zero() called from + * blk_mq_find_and_get_req(), which orders WRITE/READ flush_rq->ref + * and READ flush_rq->end_io + */ + smp_wmb(); + refcount_set(&flush_rq->ref, 1); blk_flush_queue_rq(flush_rq, false); } diff --git a/block/blk-lib.c b/block/blk-lib.c index e90614fd8d6a..7fb9102b606b 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Functions related to generic helpers functions @@ -150,6 +153,89 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, } EXPORT_SYMBOL(blkdev_issue_discard); +#ifdef MY_ABC_HERE +static int __blkdev_hint_unused(struct block_device *bdev, + sector_t sector, sector_t nr_sects, gfp_t gfp_mask, + struct bio **biop) +{ + struct bio *bio = *biop; + unsigned int max_unused_hint_sectors; + struct request_queue *q = bdev_get_queue(bdev); + sector_t bs_mask = 0; + sector_t aligned_sector = 0; + + if (!q) + return -ENXIO; + + if (!blk_queue_unused_hint(q)) + return -EOPNOTSUPP; + + bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1; + + aligned_sector = (sector + bs_mask) & ~bs_mask; + if (sector != aligned_sector) { + if (nr_sects > aligned_sector - sector) + nr_sects -= aligned_sector - sector; + else + nr_sects = 0; + sector = aligned_sector; + } + /* Ensure that max_unused_hint_sectors doesn't overflow bi_size */ + max_unused_hint_sectors = bio_allowed_max_sectors(q) & ~bs_mask; + + while (nr_sects) { + bio = blk_next_bio(bio, 0, gfp_mask); + bio->bi_iter.bi_sector = sector; + bio_set_dev(bio, bdev); + bio_set_op_attrs(bio, REQ_OP_UNUSED_HINT, 0); + + if (nr_sects > max_unused_hint_sectors) { + bio->bi_iter.bi_size = max_unused_hint_sectors << 9; + nr_sects -= max_unused_hint_sectors; + sector += max_unused_hint_sectors; + } else { + bio->bi_iter.bi_size = nr_sects << 9; + nr_sects = 0; + } + cond_resched(); + } + + *biop = bio; + return 0; +} + +/** + * blkdev_hint_unused - queue a unused hint + * @bdev: blockdev to issue unused hint for + * @sector: start sector + * @nr_sects: number of sectors to hint unused + * @gfp_mask: memory allocation flags (for bio_alloc) + * + * Description: + * Issue a unused hint for the sectors in question. + */ +int blkdev_hint_unused(struct block_device *bdev, sector_t sector, + sector_t nr_sects, gfp_t gfp_mask) +{ + struct bio *bio = NULL; + struct blk_plug plug; + int ret; + + blk_start_plug(&plug); + ret = __blkdev_hint_unused(bdev, sector, nr_sects, gfp_mask, &bio); + if (!ret && bio) { + ret = submit_bio_wait(bio); + if (ret == -EOPNOTSUPP) + ret = 0; + bio_put(bio); + } + blk_finish_plug(&plug); + + return ret; +} +EXPORT_SYMBOL(blkdev_hint_unused); +#endif /* MY_ABC_HERE */ + /** * __blkdev_issue_write_same - generate number of bios with same page * @bdev: target blockdev diff --git a/block/blk-map.c b/block/blk-map.c index 21630dccac62..ede73f4f7014 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -488,7 +488,7 @@ static struct bio *bio_copy_kern(struct request_queue *q, void *data, if (bytes > len) bytes = len; - page = alloc_page(q->bounce_gfp | gfp_mask); + page = alloc_page(q->bounce_gfp | __GFP_ZERO | gfp_mask); if (!page) goto cleanup; diff --git a/block/blk-merge.c b/block/blk-merge.c index 349cd7d3af81..68d2e330335c 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Functions related to segment and merge handling @@ -103,6 +106,26 @@ static struct bio *blk_bio_discard_split(struct request_queue *q, return bio_split(bio, split_sectors, GFP_NOIO, bs); } +#ifdef MY_ABC_HERE +static struct bio *blk_bio_unused_hint_split(struct request_queue *q, + struct bio *bio, + struct bio_set *bs, + unsigned *nsegs) +{ + unsigned int max_unused_hint_sectors; + sector_t bs_mask = (queue_logical_block_size(q) >> 9) - 1; + + *nsegs = 1; + + max_unused_hint_sectors = bio_allowed_max_sectors(q) & ~bs_mask; + + if (bio_sectors(bio) <= max_unused_hint_sectors) + return NULL; + + return bio_split(bio, max_unused_hint_sectors, GFP_NOIO, bs); +} +#endif /* MY_ABC_HERE */ + static struct bio *blk_bio_write_zeroes_split(struct request_queue *q, struct bio *bio, struct bio_set *bs, unsigned *nsegs) { @@ -305,6 +328,12 @@ void __blk_queue_split(struct bio **bio, unsigned int *nr_segs) case REQ_OP_SECURE_ERASE: split = blk_bio_discard_split(q, *bio, &q->bio_split, nr_segs); break; +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: + split = blk_bio_unused_hint_split(q, *bio, &q->bio_split, + nr_segs); + break; +#endif /* MY_ABC_HERE */ case REQ_OP_WRITE_ZEROES: split = blk_bio_write_zeroes_split(q, *bio, &q->bio_split, nr_segs); @@ -339,6 +368,9 @@ void __blk_queue_split(struct bio **bio, unsigned int *nr_segs) bio_chain(split, *bio); trace_block_split(q, split, (*bio)->bi_iter.bi_sector); +#ifdef MY_ABC_HERE + bio_set_flag(*bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(*bio); *bio = split; } @@ -375,6 +407,9 @@ unsigned int blk_recalc_rq_segments(struct request *rq) switch (bio_op(rq->bio)) { case REQ_OP_DISCARD: case REQ_OP_SECURE_ERASE: +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: +#endif /* MY_ABC_HERE */ if (queue_max_discard_segments(rq->q) > 1) { struct bio *bio = rq->bio; diff --git a/block/blk-mq.c b/block/blk-mq.c index a368eb6dc647..31d36527116b 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Block multiqueue core code @@ -301,6 +304,10 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, RB_CLEAR_NODE(&rq->rb_node); rq->rq_disk = NULL; rq->part = NULL; +#ifdef MY_ABC_HERE + rq->syno_seq = 0; +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_BLK_RQ_ALLOC_TIME rq->alloc_time_ns = alloc_time_ns; #endif @@ -730,8 +737,17 @@ static void hctx_lock(struct blk_mq_hw_ctx *hctx, int *srcu_idx) void blk_mq_start_request(struct request *rq) { struct request_queue *q = rq->q; +#ifdef MY_ABC_HERE + sector_t rq_pos = 0; + sector_t end_sector = 0; +#endif /* MY_ABC_HERE */ trace_block_rq_issue(q, rq); +#ifdef MY_ABC_HERE + if (rq->rq_disk) { + rq->u64IssueTime = cpu_clock(0); + } +#endif /* MY_ABC_HERE */ if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) { rq->io_start_time_ns = ktime_get_ns(); @@ -749,6 +765,23 @@ void blk_mq_start_request(struct request *rq) if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE) q->integrity.profile->prepare_fn(rq); #endif + +#ifdef MY_ABC_HERE + if (blk_do_io_stat(rq)) { + rq_pos = blk_rq_pos(rq); + end_sector = rq->rq_disk->end_sector; + + if (end_sector == rq_pos) { + rq->syno_seq |= (1 << SYNO_DISK_SEQ_STAT_NEAR_SEQ); + rq->syno_seq |= (1 << SYNO_DISK_SEQ_STAT_SEQ); + } else if (end_sector < rq_pos + && end_sector + 256 >= rq_pos) { + rq->syno_seq |= (1 << SYNO_DISK_SEQ_STAT_NEAR_SEQ); + } + rq->rq_disk->end_sector = rq_end_sector(rq); + } +#endif /* MY_ABC_HERE */ + } EXPORT_SYMBOL(blk_mq_start_request); @@ -929,7 +962,7 @@ static bool blk_mq_req_expired(struct request *rq, unsigned long *next) void blk_mq_put_rq_ref(struct request *rq) { - if (is_flush_rq(rq, rq->mq_hctx)) + if (is_flush_rq(rq)) rq->end_io(rq, 0); else if (refcount_dec_and_test(&rq->ref)) __blk_mq_free_request(rq); @@ -3246,7 +3279,11 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, goto err_hctxs; INIT_WORK(&q->timeout_work, blk_mq_timeout_work); +#ifdef CONFIG_SYNO_KVMX64_MQ_TIMEOUT + blk_queue_rq_timeout(q, set->timeout ? set->timeout : CONFIG_SYNO_KVMX64_MQ_TIMEOUT * HZ); +#else blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ); +#endif /* CONFIG_SYNO_KVMX64_MQ_TIMEOUT */ q->tag_set = set; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index b513f1683af0..161a826b87a2 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Functions related to sysfs handling @@ -204,7 +207,11 @@ static ssize_t queue_discard_max_store(struct request_queue *q, static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page) { +#ifdef MY_ABC_HERE + return queue_var_show(1, page); +#else return queue_var_show(0, page); +#endif } static ssize_t queue_write_same_max_show(struct request_queue *q, char *page) @@ -548,6 +555,13 @@ static ssize_t queue_dax_show(struct request_queue *q, char *page) return queue_var_show(blk_queue_dax(q), page); } +#ifdef MY_ABC_HERE +static ssize_t queue_unused_hint_show(struct request_queue *q, char *page) +{ + return sprintf(page, "%u\n", test_bit(QUEUE_FLAG_UNUSED_HINT, &q->queue_flags)); +} +#endif /* MY_ABC_HERE */ + #define QUEUE_RO_ENTRY(_prefix, _name) \ static struct queue_sysfs_entry _prefix##_entry = { \ .attr = { .name = _name, .mode = 0444 }, \ @@ -604,6 +618,9 @@ QUEUE_RW_ENTRY(queue_wb_lat, "wbt_lat_usec"); #ifdef CONFIG_BLK_DEV_THROTTLING_LOW QUEUE_RW_ENTRY(blk_throtl_sample_time, "throttle_sample_time"); #endif +#ifdef MY_ABC_HERE +QUEUE_RO_ENTRY(queue_unused_hint, "syno_unused_hint"); +#endif /* MY_ABC_HERE */ /* legacy alias for logical_block_size: */ static struct queue_sysfs_entry queue_hw_sector_size_entry = { @@ -659,6 +676,9 @@ static struct attribute *queue_attrs[] = { #ifdef CONFIG_BLK_DEV_THROTTLING_LOW &blk_throtl_sample_time_entry.attr, #endif +#ifdef MY_ABC_HERE + &queue_unused_hint_entry.attr, +#endif /* MY_ABC_HERE */ NULL, }; diff --git a/block/blk.h b/block/blk.h index dfab98465db9..ecfd523c68d0 100644 --- a/block/blk.h +++ b/block/blk.h @@ -44,11 +44,7 @@ static inline void __blk_get_queue(struct request_queue *q) kobject_get(&q->kobj); } -static inline bool -is_flush_rq(struct request *req, struct blk_mq_hw_ctx *hctx) -{ - return hctx->fq->flush_rq == req; -} +bool is_flush_rq(struct request *req); struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size, gfp_t flags); diff --git a/block/bounce.c b/block/bounce.c index 162a6eee8999..8f95e44f87c3 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* bounce buffer handling for block devices * @@ -256,6 +259,9 @@ static struct bio *bounce_clone_bio(struct bio *bio_src, gfp_t gfp_mask, switch (bio_op(bio)) { case REQ_OP_DISCARD: case REQ_OP_SECURE_ERASE: +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: +#endif /* MY_ABC_HERE */ case REQ_OP_WRITE_ZEROES: break; case REQ_OP_WRITE_SAME: diff --git a/block/elevator.c b/block/elevator.c index 293c5c81397a..31137c907dca 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Block device elevator/IO-scheduler. @@ -624,7 +627,11 @@ static struct elevator_type *elevator_get_default(struct request_queue *q) if (q->nr_hw_queues != 1) return NULL; +#ifdef MY_ABC_HERE + return elevator_get(q, "bfq", false); +#else /* MY_ABC_HERE */ return elevator_get(q, "mq-deadline", false); +#endif /* MY_ABC_HERE */ } /* diff --git a/block/genhd.c b/block/genhd.c index 796baf761202..f5e19e2d3570 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * gendisk handling @@ -152,6 +155,25 @@ struct hd_struct *__disk_get_part(struct gendisk *disk, int partno) return rcu_dereference(ptbl->part[partno]); } +#ifdef MY_DEF_HERE +extern int g_is_sas_model; +static inline char *make_class_name(const char *name, struct kobject *kobj) +{ + char *class_name = NULL; + int size = 0; + + size = strlen(name) + strlen(kobject_name(kobj)) + 2; + + class_name = kmalloc(size, GFP_KERNEL); + if (!class_name) + return NULL; + + snprintf(class_name, size, "%s:%s", name, kobject_name(kobj)); + + return class_name; +} +#endif /* MY_DEF_HERE */ + /** * disk_get_part - get partition * @disk: disk to look partition from @@ -699,6 +721,9 @@ static void register_disk(struct device *parent, struct gendisk *disk, struct disk_part_iter piter; struct hd_struct *part; int err; +#ifdef MY_DEF_HERE + int error = 0; +#endif /* MY_DEF_HERE */ ddev->parent = parent; @@ -713,10 +738,33 @@ static void register_disk(struct device *parent, struct gendisk *disk, } if (device_add(ddev)) return; +#ifdef MY_DEF_HERE + if (1 == g_is_sas_model && ddev->parent) { + char *class_name = NULL; + class_name = make_class_name(ddev->class->name, + &ddev->kobj); + if (class_name) { + error = sysfs_create_link(&ddev->parent->kobj, + &ddev->kobj, class_name); + kfree(class_name); + } + } +#endif /* MY_DEF_HERE */ if (!sysfs_deprecated) { err = sysfs_create_link(block_depr, &ddev->kobj, kobject_name(&ddev->kobj)); if (err) { +#ifdef MY_DEF_HERE + if (1 == g_is_sas_model && ddev->parent && !error) { + char *class_name = NULL; + class_name = make_class_name(ddev->class->name, + &ddev->kobj); + if (class_name) { + sysfs_remove_link(&ddev->parent->kobj, class_name); + kfree(class_name); + } + } +#endif /* MY_DEF_HERE */ device_del(ddev); return; } @@ -894,6 +942,10 @@ void del_gendisk(struct gendisk *disk) struct disk_part_iter piter; struct hd_struct *part; +#ifdef MY_DEF_HERE + struct device *ddev = disk_to_dev(disk); +#endif /* MY_DEF_HERE */ + might_sleep(); blk_integrity_del(disk); @@ -949,6 +1001,17 @@ void del_gendisk(struct gendisk *disk) disk->part0.stamp = 0; if (!sysfs_deprecated) sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); +#ifdef MY_DEF_HERE + if (1 == g_is_sas_model && ddev && ddev->parent) { + char *class_name = NULL; + class_name = make_class_name(ddev->class->name, + &ddev->kobj); + if (class_name) { + sysfs_remove_link(&ddev->parent->kobj, class_name); + kfree(class_name); + } + } +#endif /* MY_DEF_HERE */ pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); device_del(disk_to_dev(disk)); } @@ -1370,11 +1433,130 @@ static ssize_t disk_discard_alignment_show(struct device *dev, return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue)); } +#ifdef MY_ABC_HERE +static ssize_t disk_ro_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gendisk *disk = dev_to_disk(dev); + int ro = 0; + + if (!count || !sscanf(buf, "%d", &ro)) + return -EINVAL; + + set_disk_ro(disk, ro ? 1 : 0); + pr_err("%s: set read-only mode to %d\n", + disk->disk_name, ro ? 1 : 0); + return count; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t block_resp_stat_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + ssize_t len = 0; + char szTmp[512] = {'\0'}; + + if (!disk) { + goto END; + } + // Disk uuid + snprintf(szTmp, sizeof(szTmp), "%pU\n", + disk->block_latency_uuid); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + + // Latency info + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu %llu\n", + disk->u64CplCmdCnt[0], + disk->u64RespTimeSum[0], + disk->u64CplCmdCnt[1], + disk->u64RespTimeSum[1]); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + // Extend info +#ifdef MY_ABC_HERE + snprintf(szTmp, sizeof(szTmp), "%lu %lu %llu %llu\n", + disk->seq_ios[SYNO_DISK_SEQ_STAT_NEAR_SEQ], + disk->seq_ios[SYNO_DISK_SEQ_STAT_SEQ], + disk->u64WaitTime[0], + disk->u64WaitTime[1] + ); +#else /* MY_ABC_HERE */ + snprintf(szTmp, sizeof(szTmp), "%u %u %llu %llu\n", + 0, 0, + disk->u64WaitTime[0], + disk->u64WaitTime[1] + ); +#endif /* MY_ABC_HERE */ + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + + +END: + return len; +} + +static void block_latency_hist_get(u64 u64TimeBuckets[SYNO_BLOCK_RESPONSE_BUCKETS_END][32], + char *szBuf, int cbBuf) +{ + ssize_t len = 0; + unsigned int j = 0; + unsigned int i = 0; + char szTmp[32] = {'\0'}; + for (j = 0; j < SYNO_BLOCK_RESPONSE_BUCKETS_END; j++) { + for (i = 0; i < 32; i++) { + snprintf(szTmp, sizeof(szTmp), "%llu ", u64TimeBuckets[j][i]); + len += strlen(szTmp); + strncat(szBuf, szTmp, cbBuf - len - 1); + } + szBuf[len - 1] = '\n'; + } +} + +static ssize_t block_resp_read_hist_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + + if (!disk) { + goto END; + } + block_latency_hist_get(disk->u64RespTimeBuckets[0], buf, PAGE_SIZE); + +END: + return strlen(buf); +} + +static ssize_t block_resp_write_hist_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + + if (!disk) { + goto END; + } + + block_latency_hist_get(disk->u64RespTimeBuckets[1], buf, PAGE_SIZE); + +END: + return strlen(buf); +} +#endif /* MY_ABC_HERE */ + static DEVICE_ATTR(range, 0444, disk_range_show, NULL); static DEVICE_ATTR(ext_range, 0444, disk_ext_range_show, NULL); static DEVICE_ATTR(removable, 0444, disk_removable_show, NULL); static DEVICE_ATTR(hidden, 0444, disk_hidden_show, NULL); +#ifdef MY_ABC_HERE +static DEVICE_ATTR(ro, 0664, disk_ro_show, disk_ro_store); +#else /* MY_ABC_HERE */ static DEVICE_ATTR(ro, 0444, disk_ro_show, NULL); +#endif /* MY_ABC_HERE */ static DEVICE_ATTR(size, 0444, part_size_show, NULL); static DEVICE_ATTR(alignment_offset, 0444, disk_alignment_offset_show, NULL); static DEVICE_ATTR(discard_alignment, 0444, disk_discard_alignment_show, NULL); @@ -1414,6 +1596,41 @@ static struct device_attribute dev_attr_fail_timeout = __ATTR(io-timeout-fail, 0644, part_timeout_show, part_timeout_store); #endif +#ifdef MY_ABC_HERE +static DEVICE_ATTR(block_resp_stat, S_IRUGO, block_resp_stat_show, NULL); +static DEVICE_ATTR(block_resp_read_hist, S_IRUGO, block_resp_read_hist_show, NULL); +static DEVICE_ATTR(block_resp_write_hist, S_IRUGO, block_resp_write_hist_show, NULL); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void syno_disk_remap_mode_set(struct gendisk *disk, unsigned char auto_remap); + +static ssize_t +syno_disk_auto_remap_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%u\n", disk->syno_auto_remap); +} + +static ssize_t +syno_disk_auto_remap_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gendisk *disk = dev_to_disk(dev); + int val = 0; + + if (!count) + return -EINVAL; + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + + syno_disk_remap_mode_set(disk, val ? 1 : 0); + return count; +} +static DEVICE_ATTR(auto_remap, 0644, syno_disk_auto_remap_show, syno_disk_auto_remap_store); +#endif /* MY_ABC_HERE */ + static struct attribute *disk_attrs[] = { &dev_attr_range.attr, &dev_attr_ext_range.attr, @@ -1433,6 +1650,14 @@ static struct attribute *disk_attrs[] = { #ifdef CONFIG_FAIL_IO_TIMEOUT &dev_attr_fail_timeout.attr, #endif +#ifdef MY_ABC_HERE + &dev_attr_block_resp_stat.attr, + &dev_attr_block_resp_read_hist.attr, + &dev_attr_block_resp_write_hist.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_auto_remap.attr, +#endif /* MY_ABC_HERE */ NULL }; @@ -1760,6 +1985,17 @@ struct gendisk *__alloc_disk_node(int minors, int node_id) disk_to_dev(disk)->class = &block_class; disk_to_dev(disk)->type = &disk_type; device_initialize(disk_to_dev(disk)); +#ifdef MY_ABC_HERE + generate_random_uuid(disk->block_latency_uuid); + memset(&(disk->u64CplCmdCnt), 0, sizeof(disk->u64CplCmdCnt[0]) * 2); + memset(&(disk->u64RespTimeSum), 0, sizeof(disk->u64RespTimeSum[0]) * 2); + memset(&(disk->u64WaitTime), 0, sizeof(disk->u64WaitTime[0]) * 2); + memset(&(disk->u64RespTimeBuckets), 0, sizeof(disk->u64RespTimeBuckets[0][0][0]) * 2 * SYNO_BLOCK_RESPONSE_BUCKETS_END * 32); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + disk->syno_auto_remap = 0; +#endif /* MY_ABC_HERE */ return disk; out_free_part0: @@ -2365,3 +2601,266 @@ static void disk_release_events(struct gendisk *disk) WARN_ON_ONCE(disk->ev && disk->ev->block != 1); kfree(disk->ev); } + +#ifdef MY_ABC_HERE +/** + * Set the partition to specify remap mode + * + * @param gd [IN] general disk. Should not be NULL + * @param phd [IN] partition. Should not be NULL + * @param auto_remap + * [IN] remap mode + */ +void syno_partition_remap_mode_set(struct gendisk *gd, struct hd_struct *phd, + unsigned char auto_remap) +{ + if (!gd || !phd) + return; + + phd->syno_auto_remap = auto_remap; + + if (!auto_remap) + gd->syno_auto_remap = 0; +} +EXPORT_SYMBOL(syno_partition_remap_mode_set); + +/** + * Set the gendisk to specify remap mode. + * + * And also set the relative partition to that mode. + * + * @param sdev [IN] gendisk of the target disk. Should not be NULL. + * @param auto_remap + * [IN] auto remap mode. + */ +void syno_disk_remap_mode_set(struct gendisk *disk, unsigned char auto_remap) +{ + struct hd_struct *phd = NULL; + struct disk_part_tbl *ptbl; + int i = 0; + + if (!disk) + return; + + disk->syno_auto_remap = auto_remap; + + rcu_read_lock(); + ptbl = rcu_dereference(disk->part_tbl); + /* disk part */ + for (i = 0; i < ptbl->len; i++) { + phd = disk_get_part(disk, i+1); + if (!phd) + continue; + if (!phd->nr_sects) { + disk_put_part(phd); + continue; + } + + phd->syno_auto_remap = auto_remap; + disk_put_part(phd); + } + rcu_read_unlock(); +} +EXPORT_SYMBOL(syno_disk_remap_mode_set); + +void syno_disk_and_part_remap_mode_set(struct gendisk *disk, struct hd_struct *bd_part, + unsigned char auto_remap) +{ + /* + * TOFIX: There is bd_part in a bdev, even if it is a whole disk. + * Therefore the whole disk condition in the "else part" is + * unreachable. You should use different branching criterion. + */ + if (bd_part) { + /* is a partition of some disks */ + bd_part->syno_auto_remap = auto_remap; + } else { + /* is whole disk */ + syno_disk_remap_mode_set(disk, auto_remap); + } +} +EXPORT_SYMBOL(syno_disk_and_part_remap_mode_set); + +/** + * Set the block device to specify remap mode + * + * @param bdev [IN] block device. Should not be NULL. + * @param auto_remap + * [IN] remap mode + */ +void syno_bdev_remap_mode_set(struct block_device *bdev, unsigned char auto_remap) +{ + struct gendisk *disk = NULL; + + if (!bdev) { + WARN_ON(1); + return; + } + + disk = bdev->bd_disk; + if (!disk) { + WARN_ON(1); + return; + } + + syno_disk_and_part_remap_mode_set(disk, bdev->bd_part, auto_remap); +} +EXPORT_SYMBOL(syno_bdev_remap_mode_set); + +unsigned char syno_is_sector_need_auto_remap(struct gendisk *disk, sector_t lba) +{ + struct hd_struct *phd; + struct disk_part_tbl *ptbl; + char szName[BDEVNAME_SIZE]; + sector_t start, end; + u8 ret = 0; + int i = 0; + + if (!disk) { + WARN_ON(1); + goto end; + } + + /* global disk auto remap */ + if (disk->syno_auto_remap) { + ret = 1; + pr_info("%s auto remap is on\n", disk->disk_name); + goto end; + } + + rcu_read_lock(); + ptbl = rcu_dereference(disk->part_tbl); + /* disk part */ + for (i = 0; i < ptbl->len; i++) { + phd = disk_get_part(disk, i+1); + if (!phd) + continue; + if (!phd->nr_sects) { + disk_put_part(phd); + continue; + } + + start = phd->start_sect; + end = phd->nr_sects + start - 1; + + if (lba >= start && lba <= end) { + ret = phd->syno_auto_remap; + pr_info("lba %llu start %llu end %llu, %s auto_remap %u\n", + (unsigned long long)lba, (unsigned long long)start, + (unsigned long long)end, disk_name(disk, i+1, szName), + phd->syno_auto_remap); + disk_put_part(phd); + break; + } + disk_put_part(phd); + } + rcu_read_unlock(); +end: + return ret; +} +EXPORT_SYMBOL(syno_is_sector_need_auto_remap); + +#ifdef MY_ABC_HERE +void syno_req_set_bio_auto_remap_flag(struct request *req, sector_t lba) +{ + struct bio *b = NULL; + unsigned int len = 0; + int i = 0; + + for (b = req->bio; b; b = b->bi_next) { + len = 0; + for (i = 0; i < b->bi_vcnt; i++) + len += b->bi_io_vec[i].bv_len; + if (b->bi_iter.bi_sector <= lba && lba < b->bi_iter.bi_sector + (len >> 9)) { + bio_set_flag(b, BIO_SYNO_AUTO_REMAP); + pr_info("%s:%s(%d) set bio BIO_AUTO_REMAP bit on\n", + __FILE__, __func__, __LINE__); + break; + } + } +} +EXPORT_SYMBOL(syno_req_set_bio_auto_remap_flag); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +bool syno_is_device_disappear(struct block_device *bdev) +{ + struct gendisk *disk = NULL; + bool ret = false; + + if (!bdev) { + WARN_ON(1); + goto err; + } + + disk = bdev->bd_disk; + if (!disk) { + WARN_ON(1); + goto err; + } + + if (disk->syno_ops && disk->syno_ops->is_device_disappear) { + ret = disk->syno_ops->is_device_disappear(disk); + } else { + WARN_ONCE(true, "The is_device_disappear of disk %s not implemented\n", + disk->disk_name); + } +err: + return ret; +} +EXPORT_SYMBOL(syno_is_device_disappear); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int syno_disk_get_device_index(struct block_device *bdev) +{ + struct gendisk *disk = NULL; + int ret = -1; + + if (!bdev) { + WARN_ON(1); + goto err; + } + + disk = bdev->bd_disk; + if (!disk) { + WARN_ON(1); + goto err; + } + + if (disk->syno_ops && disk->syno_ops->get_device_index) + ret = disk->syno_ops->get_device_index(disk); + else + WARN_ONCE(true, "the get_device_index of disk %s not implemented\n", + disk->disk_name); +err: + return ret; +} +EXPORT_SYMBOL(syno_disk_get_device_index); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +bool IsSynoRbdDeviceEnabled(struct block_device *bdev) +{ +#ifdef MY_ABC_HERE + bool ret = false; + struct gendisk *disk = NULL; + + if (!bdev) { + WARN_ON(1); + goto out; + } + + disk = bdev->bd_disk; + if (disk && disk->syno_ops && disk->syno_ops->check_device_status) + ret = (1 == disk->syno_ops->check_device_status(disk, + SYNO_DEVICE_STATUS_IS_RBD_ENABLED)); +out: + return ret; +#else /* MY_ABC_HERE */ + return false; +#endif /* MY_ABC_HERE */ +} +EXPORT_SYMBOL(IsSynoRbdDeviceEnabled); +#endif /* MY_ABC_HERE */ diff --git a/block/ioctl.c b/block/ioctl.c index ed240e170e14..7e74c83ce146 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -151,6 +154,45 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, GFP_KERNEL, flags); } +#ifdef MY_ABC_HERE +static int blk_ioctl_hint_unused(struct block_device *bdev, fmode_t mode, + unsigned long arg) +{ + uint64_t range[2]; + uint64_t start, len; + struct request_queue *q = bdev_get_queue(bdev); + + if (!blk_queue_unused_hint(q)) + return -EOPNOTSUPP; + + if (copy_from_user(range, (void __user *)arg, sizeof(range))) + return -EFAULT; + + start = range[0]; + len = range[1]; + + /** + * Shrink the range to fit it for the device so that userspace + * can give casual range, such as [0, ULLONG_MAX]. + */ + if (start & 511) { + start += 512; + if (len < 512 || start < 512) + return -EINVAL; + len -= 512; + } + + if (start > (uint64_t)i_size_read(bdev->bd_inode)) + return -EINVAL; + + if (start + len > (uint64_t)i_size_read(bdev->bd_inode)) + len = (uint64_t)i_size_read(bdev->bd_inode) - start; + + return blkdev_hint_unused(bdev, start >> 9, len >> 9, + GFP_KERNEL); +} +#endif /* MY_ABC_HERE */ + static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode, unsigned long arg) { @@ -518,6 +560,10 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode, case BLKSECDISCARD: return blk_ioctl_discard(bdev, mode, arg, BLKDEV_DISCARD_SECURE); +#ifdef MY_ABC_HERE + case BLKHINTUNUSED: + return blk_ioctl_hint_unused(bdev, mode, arg); +#endif /* MY_ABC_HERE */ case BLKZEROOUT: return blk_ioctl_zeroout(bdev, mode, arg); case BLKREPORTZONE: diff --git a/block/partitions/core.c b/block/partitions/core.c index a02e22411594..39c589bd28ab 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991-1998 Linus Torvalds @@ -215,6 +218,29 @@ static ssize_t part_discard_alignment_show(struct device *dev, p->start_sect)); } +#ifdef MY_ABC_HERE +extern void syno_partition_remap_mode_set(struct gendisk *gd, struct hd_struct *phd, + unsigned char auto_remap); +ssize_t part_syno_auto_remap_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", dev_to_part(dev)->syno_auto_remap); +} + +ssize_t part_syno_auto_remap_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = 0; + struct hd_struct *p = dev_to_part(dev); + struct gendisk *disk = part_to_disk(p); + + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + + syno_partition_remap_mode_set(disk, p, val ? 1 : 0); + return count; +} +#endif /* MY_ABC_HERE */ + static DEVICE_ATTR(partition, 0444, part_partition_show, NULL); static DEVICE_ATTR(start, 0444, part_start_show, NULL); static DEVICE_ATTR(size, 0444, part_size_show, NULL); @@ -227,6 +253,9 @@ static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL); static struct device_attribute dev_attr_fail = __ATTR(make-it-fail, 0644, part_fail_show, part_fail_store); #endif +#ifdef MY_ABC_HERE +static DEVICE_ATTR(auto_remap, 0644, part_syno_auto_remap_show, part_syno_auto_remap_store); +#endif /* MY_ABC_HERE */ static struct attribute *part_attrs[] = { &dev_attr_partition.attr, @@ -240,6 +269,9 @@ static struct attribute *part_attrs[] = { #ifdef CONFIG_FAIL_MAKE_REQUEST &dev_attr_fail.attr, #endif +#ifdef MY_ABC_HERE + &dev_attr_auto_remap.attr, +#endif /* MY_ABC_HERE */ NULL }; @@ -475,6 +507,9 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno, /* suppress uevent if the disk suppresses it */ if (!dev_get_uevent_suppress(ddev)) kobject_uevent(&pdev->kobj, KOBJ_ADD); +#ifdef MY_ABC_HERE + syno_partition_remap_mode_set(disk, p, 0); +#endif /* MY_ABC_HERE */ return p; out_free_info: diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index c9f009cc0446..824d9574dbca 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2001 Jens Axboe @@ -822,7 +825,11 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod * old junk scsi send command ioctl */ case SCSI_IOCTL_SEND_COMMAND: +#ifdef MY_ABC_HERE + /* Just hide the warning message */ +#else /* MY_ABC_HERE */ printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); +#endif /* MY_ABC_HERE */ err = -EINVAL; if (!arg) break; diff --git a/crypto/Makefile b/crypto/Makefile index b279483fba50..7a1291f3b1ed 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -194,6 +194,7 @@ obj-$(CONFIG_CRYPTO_ECRDSA) += ecrdsa_generic.o obj-$(CONFIG_XOR_BLOCKS) += xor.o obj-$(CONFIG_ASYNC_CORE) += async_tx/ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ +obj-$(CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK) += hydrogen/ obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o crypto_simd-y := simd.o obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 52c9b455fc7d..17469b79735d 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* X.509 certificate parser * @@ -573,8 +576,11 @@ int x509_decode_time(time64_t *_t, size_t hdrlen, if (vlen != 15) goto unsupported_time; year = DD2bin(p) * 100 + DD2bin(p); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ if (year >= 1950 && year <= 2049) goto invalid_time; +#endif /* MY_ABC_HERE */ } else { goto unsupported_time; } diff --git a/crypto/hydrogen/Makefile b/crypto/hydrogen/Makefile new file mode 100644 index 000000000000..9389619ec464 --- /dev/null +++ b/crypto/hydrogen/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK) += hydrogen.o diff --git a/drivers/Kconfig b/drivers/Kconfig index dcecc9f6e33f..a17e07cab044 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -235,4 +235,6 @@ source "drivers/interconnect/Kconfig" source "drivers/counter/Kconfig" source "drivers/most/Kconfig" + +source "drivers/syno/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 576228037718..ae336ad2268a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -79,6 +79,9 @@ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ obj-y += scsi/ obj-y += nvme/ +ifeq ($(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS), y) +obj-y += i2c/ +endif obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_TARGET_CORE) += target/ obj-$(CONFIG_MTD) += mtd/ @@ -111,7 +114,11 @@ obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_RTC_LIB) += rtc/ -obj-y += i2c/ i3c/ media/ +ifeq ($(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS), y) +obj-y += i3c/ media/ +else #CONFIG_SYNO_SATA_PWR_CTRL_SMBUS +obj-y += i2c/ i3c/ media/ +endif #CONFIG_SYNO_SATA_PWR_CTRL_SMBUS obj-$(CONFIG_PPS) += pps/ obj-y += ptp/ obj-$(CONFIG_W1) += w1/ @@ -189,3 +196,5 @@ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_INTERCONNECT) += interconnect/ obj-$(CONFIG_COUNTER) += counter/ obj-$(CONFIG_MOST) += most/ + +obj-y += syno/ diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 4466156474ee..82d823cddf7c 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o obj-y += pmic/ +obj-$(CONFIG_SYNO_BIOS_ACPI_FPDT) += acpi_fpdt.o video-objs += acpi_video.o video_detect.o obj-y += dptf/ diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c new file mode 100644 index 000000000000..ec8faf977118 --- /dev/null +++ b/drivers/acpi/acpi_fpdt.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * FPDT support for exporting boot and suspend/resume performance data + * + * Copyright (C) 2019 Intel Corporation. All rights reserved. + */ + +#define pr_fmt(fmt) "ACPI FPDT: " fmt + +#include + +/* + * FPDT contains ACPI table header and a number of fpdt_subtable_entries. + * Each fpdt_subtable_entry points to a subtable: FBPT or S3PT. + * Each FPDT subtable (FBPT/S3PT) is composed of a fpdt_subtable_header + * and a number of fpdt performance records. + * Each FPDT performance record is composed of a fpdt_record_header and + * performance data fields, for boot or suspend or resume phase. + */ +enum fpdt_subtable_type { + SUBTABLE_FBPT, + SUBTABLE_S3PT, +}; + +struct fpdt_subtable_entry { + u16 type; /* refer to enum fpdt_subtable_type */ + u8 length; + u8 revision; + u32 reserved; + u64 address; /* physical address of the S3PT/FBPT table */ +}; + +struct fpdt_subtable_header { + u32 signature; + u32 length; +}; + +enum fpdt_record_type { + RECORD_S3_RESUME, + RECORD_S3_SUSPEND, + RECORD_BOOT, +}; + +struct fpdt_record_header { + u16 type; /* refer to enum fpdt_record_type */ + u8 length; + u8 revision; +}; + +struct resume_performance_record { + struct fpdt_record_header header; + u32 resume_count; + u64 resume_prev; + u64 resume_avg; +} __attribute__((packed)); + +struct boot_performance_record { + struct fpdt_record_header header; + u32 reserved; + u64 firmware_start; + u64 bootloader_load; + u64 bootloader_launch; + u64 exitbootservice_start; + u64 exitbootservice_end; +} __attribute__((packed)); + +struct suspend_performance_record { + struct fpdt_record_header header; + u64 suspend_start; + u64 suspend_end; +} __attribute__((packed)); + + +static struct resume_performance_record *record_resume; +static struct suspend_performance_record *record_suspend; +static struct boot_performance_record *record_boot; + +#define FPDT_ATTR(phase, name) \ +static ssize_t name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%llu\n", record_##phase->name); \ +} \ +static struct kobj_attribute name##_attr = \ +__ATTR(name##_ns, 0444, name##_show, NULL) + +FPDT_ATTR(resume, resume_prev); +FPDT_ATTR(resume, resume_avg); +FPDT_ATTR(suspend, suspend_start); +FPDT_ATTR(suspend, suspend_end); +FPDT_ATTR(boot, firmware_start); +FPDT_ATTR(boot, bootloader_load); +FPDT_ATTR(boot, bootloader_launch); +FPDT_ATTR(boot, exitbootservice_start); +FPDT_ATTR(boot, exitbootservice_end); + +static ssize_t resume_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", record_resume->resume_count); +} + +static struct kobj_attribute resume_count_attr = +__ATTR_RO(resume_count); + +static struct attribute *resume_attrs[] = { + &resume_count_attr.attr, + &resume_prev_attr.attr, + &resume_avg_attr.attr, + NULL +}; + +static const struct attribute_group resume_attr_group = { + .attrs = resume_attrs, + .name = "resume", +}; + +static struct attribute *suspend_attrs[] = { + &suspend_start_attr.attr, + &suspend_end_attr.attr, + NULL +}; + +static const struct attribute_group suspend_attr_group = { + .attrs = suspend_attrs, + .name = "suspend", +}; + +static struct attribute *boot_attrs[] = { + &firmware_start_attr.attr, + &bootloader_load_attr.attr, + &bootloader_launch_attr.attr, + &exitbootservice_start_attr.attr, + &exitbootservice_end_attr.attr, + NULL +}; + +static const struct attribute_group boot_attr_group = { + .attrs = boot_attrs, + .name = "boot", +}; + +static struct kobject *fpdt_kobj; + +static int fpdt_process_subtable(u64 address, u32 subtable_type) +{ + struct fpdt_subtable_header *subtable_header; + struct fpdt_record_header *record_header; + char *signature = (subtable_type == SUBTABLE_FBPT ? "FBPT" : "S3PT"); + u32 length, offset; + int result; + + subtable_header = acpi_os_map_memory(address, sizeof(*subtable_header)); + if (!subtable_header) + return -ENOMEM; + + if (strncmp((char *)&subtable_header->signature, signature, 4)) { + pr_info(FW_BUG "subtable signature and type mismatch!\n"); + return -EINVAL; + } + + length = subtable_header->length; + acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header)); + + subtable_header = acpi_os_map_memory(address, length); + if (!subtable_header) + return -ENOMEM; + + offset = sizeof(*subtable_header); + while (offset < length) { + record_header = (void *)subtable_header + offset; + offset += record_header->length; + + switch (record_header->type) { + case RECORD_S3_RESUME: + if (subtable_type != SUBTABLE_S3PT) { + pr_err(FW_BUG "Invalid record %d for subtable %s\n", + record_header->type, signature); + return -EINVAL; + } + if (record_resume) { + pr_err("Duplicate resume performance record found.\n"); + continue; + } + record_resume = (struct resume_performance_record *)record_header; + result = sysfs_create_group(fpdt_kobj, &resume_attr_group); + if (result) + return result; + break; + case RECORD_S3_SUSPEND: + if (subtable_type != SUBTABLE_S3PT) { + pr_err(FW_BUG "Invalid %d for subtable %s\n", + record_header->type, signature); + continue; + } + if (record_suspend) { + pr_err("Duplicate suspend performance record found.\n"); + continue; + } + record_suspend = (struct suspend_performance_record *)record_header; + result = sysfs_create_group(fpdt_kobj, &suspend_attr_group); + if (result) + return result; + break; + case RECORD_BOOT: + if (subtable_type != SUBTABLE_FBPT) { + pr_err(FW_BUG "Invalid %d for subtable %s\n", + record_header->type, signature); + return -EINVAL; + } + if (record_boot) { + pr_err("Duplicate boot performance record found.\n"); + continue; + } + record_boot = (struct boot_performance_record *)record_header; + result = sysfs_create_group(fpdt_kobj, &boot_attr_group); + if (result) + return result; + break; + + default: + pr_err(FW_BUG "Invalid record %d found.\n", record_header->type); + return -EINVAL; + } + } + return 0; +} + +static int __init acpi_init_fpdt(void) +{ + acpi_status status; + struct acpi_table_header *header; + struct fpdt_subtable_entry *subtable; + u32 offset = sizeof(*header); + + status = acpi_get_table(ACPI_SIG_FPDT, 0, &header); + + if (ACPI_FAILURE(status)) + return 0; + + fpdt_kobj = kobject_create_and_add("fpdt", acpi_kobj); + if (!fpdt_kobj) + return 0; + + while (offset < header->length) { + subtable = (void *)header + offset; + switch (subtable->type) { + case SUBTABLE_FBPT: + case SUBTABLE_S3PT: + fpdt_process_subtable(subtable->address, + subtable->type); + break; + default: + pr_info(FW_BUG "Invalid subtable type %d found.\n", + subtable->type); + return 0; + } + offset += sizeof(*subtable); + } + + return 0; +} + +fs_initcall(acpi_init_fpdt); diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 317ae870336b..3f45ee5234e8 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /****************************************************************************** * @@ -11,6 +14,10 @@ #include #include "accommon.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwsleep") @@ -99,6 +106,10 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) /* Write #1: write the SLP_TYP data to the PM1 Control registers */ status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); +#ifdef MY_ABC_HERE + printk("Confirm SLP_TYP poweroff status %x pm1a %x pm1b %x\n", status, pm1a_control, pm1b_control); + mdelay(10); +#endif /* MY_ABC_HERE */ if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -113,6 +124,10 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) ACPI_FLUSH_CPU_CACHE(); status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control); +#ifdef MY_ABC_HERE + printk("Confirm OS poweroff status %x pm1a %x pm1b %x\n", status, pm1a_control, pm1b_control); + mdelay(10); +#endif /* MY_ABC_HERE */ if (status == AE_CTRL_TERMINATE) { return_ACPI_STATUS(AE_OK); } @@ -123,6 +138,9 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) /* Write #2: Write both SLP_TYP + SLP_EN */ status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); +#ifdef MY_ABC_HERE + printk("Confirm SLP_EN poweroff status %x pm1a %x pm1b %x\n", status, pm1a_control, pm1b_control); +#endif /* MY_ABC_HERE */ if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 859b1de31ddc..d62bf6df78f8 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1120,8 +1120,6 @@ static int acpi_thermal_resume(struct device *dev) return -EINVAL; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!(&tz->trips.active[i])) - break; if (!tz->trips.active[i].flags.valid) break; tz->trips.active[i].flags.enabled = 1; diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 2a3952925855..497805f4fd1e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4768,23 +4768,20 @@ static int binder_thread_release(struct binder_proc *proc, __release(&t->lock); /* - * If this thread used poll, make sure we remove the waitqueue - * from any epoll data structures holding it with POLLFREE. - * waitqueue_active() is safe to use here because we're holding - * the inner lock. + * If this thread used poll, make sure we remove the waitqueue from any + * poll data structures holding it. */ - if ((thread->looper & BINDER_LOOPER_STATE_POLL) && - waitqueue_active(&thread->wait)) { - wake_up_poll(&thread->wait, EPOLLHUP | POLLFREE); - } + if (thread->looper & BINDER_LOOPER_STATE_POLL) + wake_up_pollfree(&thread->wait); binder_inner_proc_unlock(thread->proc); /* - * This is needed to avoid races between wake_up_poll() above and - * and ep_remove_waitqueue() called for other reasons (eg the epoll file - * descriptor being closed); ep_remove_waitqueue() holds an RCU read - * lock, so we can be sure it's done after calling synchronize_rcu(). + * This is needed to avoid races between wake_up_pollfree() above and + * someone else removing the last entry from the queue for other reasons + * (e.g. ep_remove_wait_queue() being called due to an epoll file + * descriptor being closed). Such other users hold an RCU read lock, so + * we can be sure they're done after we call synchronize_rcu(). */ if (thread->looper & BINDER_LOOPER_STATE_POLL) synchronize_rcu(); diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 030cb32da980..61e8696c818a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -271,6 +271,17 @@ config AHCI_QORIQ If unsure, say N. +if SYNO_LSP_RTD1619B +config AHCI_RTK + tristate "Realtek AHCI SATA support" + select PHY_RTK_SATA + help + This option enables support for Realtek AHCI Serial ATA + controllers. + + If unsure, say N. + +endif # SYNO_LSP_RTD1619B config SATA_FSL tristate "Freescale 3.0Gbps SATA support" depends on FSL_SOC diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index b8aebfb14e82..4d3315a75765 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -26,6 +26,9 @@ obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_QORIQ) += ahci_qoriq.o libahci.o libahci_platform.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_AHCI_RTK) += ahci_rtk.o libahci.o libahci_platform.o +endif # CONFIG_SYNO_LSP_RTD1619B # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o @@ -33,6 +36,7 @@ obj-$(CONFIG_PATA_ARASAN_CF) += pata_arasan_cf.o obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o obj-$(CONFIG_SATA_SX4) += sata_sx4.o +obj-$(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS)+= ata_syno_i2c.o # SFF SATA w/ BMDMA obj-$(CONFIG_ATA_PIIX) += ata_piix.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 33192a8f687d..a2258363743b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * ahci.c - AHCI SATA support @@ -34,6 +37,27 @@ #include #include "ahci.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#include +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +extern struct ata_port *syno_ata_port_get_by_port(const unsigned short diskPort); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern char g_ahci_switch; +#endif /* MY_ABC_HERE */ + #define DRV_NAME "ahci" #define DRV_VERSION "3.0" @@ -59,6 +83,9 @@ enum board_ids { /* board IDs for specific chipsets in alphabetical order */ board_ahci_al, board_ahci_avn, +#ifdef MY_ABC_HERE + board_ahci_jmb585, +#endif /* MY_ABC_HERE */ board_ahci_mcp65, board_ahci_mcp77, board_ahci_mcp89, @@ -80,6 +107,11 @@ enum board_ids { board_ahci_mcp79 = board_ahci_mcp77, }; +#ifdef MY_ABC_HERE +static int syno_ahci_hardreset_jmb(struct ata_link *link, unsigned int *class, unsigned long deadline); +static int syno_ahci_softreset_jmb(struct ata_link *link, unsigned int *class, unsigned long deadline); +#endif /* MY_ABC_HERE */ + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void ahci_remove_one(struct pci_dev *dev); static void ahci_shutdown_one(struct pci_dev *dev); @@ -119,6 +151,15 @@ static struct ata_port_operations ahci_avn_ops = { .hardreset = ahci_avn_hardreset, }; +#ifdef MY_ABC_HERE +static struct ata_port_operations ahci_jmb585_ops = { + .inherits = &ahci_ops, + .hardreset = syno_ahci_hardreset_jmb, + .softreset = syno_ahci_softreset_jmb, + .pmp_softreset = syno_ahci_softreset_jmb, +}; +#endif /* MY_ABC_HERE */ + static const struct ata_port_info ahci_port_info[] = { /* by features */ [board_ahci] = { @@ -242,6 +283,14 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, +#ifdef MY_ABC_HERE + [board_ahci_jmb585] = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_jmb585_ops, + }, +#endif /* MY_ABC_HERE */ }; static const struct pci_device_id ahci_pci_tbl[] = { @@ -416,6 +465,11 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x34d3), board_ahci_mobile }, /* Ice Lake LP AHCI */ { PCI_VDEVICE(INTEL, 0x02d3), board_ahci_mobile }, /* Comet Lake PCH-U AHCI */ { PCI_VDEVICE(INTEL, 0x02d7), board_ahci_mobile }, /* Comet Lake PCH RAID */ +#ifdef MY_ABC_HERE + // restore JMB585 IFS error handler + { PCI_VDEVICE(JMICRON, 0x0585), board_ahci_jmb585 }, + { PCI_VDEVICE(JMICRON, 0x0582), board_ahci_jmb585 }, +#endif /* MY_ABC_HERE */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -576,6 +630,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */ .driver_data = board_ahci_yes_fbs }, +#ifdef MY_ABC_HERE + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235), + .driver_data = board_ahci_yes_fbs }, /* 88se9235 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9215), + .driver_data = board_ahci_yes_fbs }, /* 88se9215 */ +#endif /* MY_ABC_HERE */ /* Promise */ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ @@ -609,6 +669,138 @@ static const struct pci_device_id ahci_pci_tbl[] = { { } /* terminate list */ }; +#ifdef MY_ABC_HERE +#define SYNO_SATA_MAX_PORTS_CNT 32 + +static struct { + const char *model_name; + + /* switch information on the adapter card */ + u8 switch_layer; + u16 switch_vid; + u16 switch_pid; + + /* for extracting model ID: + * mid_off: the offset of GPIO in config space of switch + * mid_mask: the mask of model ID in GPIO pins + * mid_shift: the shift of model ID in GPIO pins + * (for more details, please refer product PRD and switch manual) + */ + u16 mid_off; + u16 mid_mask; + u16 mid_shift; + + /* model ID of the adapter card */ + u16 mid; + + /* maximum ports of the sata controller (e.g. MV9235: 4 ports) */ + u8 max_ports; + + /* amplifying parameters - if some ports do not + * need to adjust amplifying parameters, you + * can leave it blank or manually set it to zero + */ + u32 amp_param_g2[SYNO_SATA_MAX_PORTS_CNT]; + u32 amp_param_g3[SYNO_SATA_MAX_PORTS_CNT]; +} syno_m2d_models[] = { + { /* M2D17 */ + .model_name = "M2D17", + .switch_layer = 2, + .switch_vid = 0x111D, + .switch_pid = 0x806E, + .mid_off = 0x420, + .mid_mask = 0x780, + .mid_shift = 7, + .mid = 0x0, + .max_ports = 4, + }, + { /* M2D18 */ + .model_name = "M2D18", + .switch_layer = 2, + .switch_vid = 0x111D, + .switch_pid = 0x806E, + .mid_off = 0x420, + .mid_mask = 0x780, + .mid_shift = 7, + .mid = 0x1, + .max_ports = 4, + .amp_param_g3 = { + 0xFF5, + }, + }, + { /* terminated with NULL model_name */ + .model_name = NULL, + }, +}; + +static int m2d_switch_match(struct pci_dev *pdev, int idx) +{ + int ret = -1; + u16 val = 0; + struct pci_dev *pdev_cur = NULL; + int layer_cnt = 0; + + layer_cnt = syno_m2d_models[idx].switch_layer; + pdev_cur = pdev; + + while (NULL != pdev_cur && 0 < layer_cnt) { + pdev_cur = pdev_cur->bus->self; + layer_cnt -= 1; + } + + if (NULL == pdev_cur) { + goto END; + } + + if (pdev_cur->vendor != syno_m2d_models[idx].switch_vid || + pdev_cur->device != syno_m2d_models[idx].switch_pid) { + goto END; + } + + if (0 > pci_read_config_word(pdev_cur, syno_m2d_models[idx].mid_off, &val)) { + goto END; + } + + val = (val & syno_m2d_models[idx].mid_mask) + >> syno_m2d_models[idx].mid_shift; + + if (val != syno_m2d_models[idx].mid) { + goto END; + } + + ret = 0; +END: + return ret; +} + +static int syno_m2d_model_get(struct pci_dev *pdev) +{ + int ret = -1; + int idx = 0; + + if (NULL == pdev) { + printk(KERN_WARNING "Bad parameter!\n"); + goto END; + } + + if (1 != syno_check_on_option_pci_slot(pdev)) { + goto END; + } + + for (idx = 0; syno_m2d_models[idx].model_name; idx++) { + if (0 != m2d_switch_match(pdev, idx)) { + continue; + } + + ret = idx; + goto END; + } + +END: + return ret; +} +#endif /* SYNO_PCI_M2DXX_SIGNAL_SETTING */ + static const struct dev_pm_ops ahci_pci_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ahci_pci_device_suspend, ahci_pci_device_resume) SET_RUNTIME_PM_OPS(ahci_pci_device_runtime_suspend, @@ -638,6 +830,1403 @@ static int mobile_lpm_policy = -1; module_param(mobile_lpm_policy, int, 0644); MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); +#ifdef MY_DEF_HERE +/* + * 9170 gpio mmio address, to control 9170 GPIO, please read register manual(AN-ML-10-051513_GPIO) + */ +enum { + MV_9170_GPIO_DATA_OUT = 0x220, + MV_9170_GPIO_DATA_OUT_ENABLE = 0x224, + MV_9170_GPIO_ACTIVE = 0x258, + MV_9170_VENDOR_SPEC1_ADDR_OFFSET = 0xA8, /* To manipulate GPIO via Vendor specific register */ + MV_9170_VENDOR_SPEC1_DATA_OFFSET = 0xAC, +}; + +/* + * Read value from 9170 gpio register + */ +u32 syno_mv_9170_gpio_reg_read(struct ata_host *host, const unsigned int gpioaddr) +{ + void __iomem *host_mmio = NULL; + u32 value = 0; + + host_mmio = ahci_host_base(host); + if (NULL == host_mmio) { + goto END; + } + + /* write to 9170 gpio active register address to VENDER_SPEC_ADDR1 */ + writel(gpioaddr, host_mmio + MV_9170_VENDOR_SPEC1_ADDR_OFFSET); + /* read original value from vendor specific data1 */ + value = readl(host_mmio + MV_9170_VENDOR_SPEC1_DATA_OFFSET); +END: + return value; +} + +/* + * 9170 GPIO register set + */ +void syno_mv_9170_gpio_reg_set(struct ata_host *host, const unsigned int gpioaddr, u32 value) +{ + void __iomem *host_mmio = NULL; + u32 reg_val; + + host_mmio = ahci_host_base(host); + if (NULL == host_mmio) { + goto END; + } + + /* write to 9170 gpio active register address to VENDER_SPEC_ADDR1 */ + writel(gpioaddr, host_mmio + MV_9170_VENDOR_SPEC1_ADDR_OFFSET); + /* read original value from vendor specific data1 */ + reg_val = readl(host_mmio + MV_9170_VENDOR_SPEC1_DATA_OFFSET); + /* then write value to it */ + writel(value, host_mmio + MV_9170_VENDOR_SPEC1_DATA_OFFSET); +END: + return; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +/* + * 9235 gpio mmio address, to control 9235/9215 GPIO, please read register manual section 1.6 + */ +enum { + /* MV_9235_GPIO_DATA_OUT the actual address is 0x71020, the 0x07000000 is MBUS_ID for vendor specific register 1 */ + MV_9235_GPIO_DATA_OUT = 0x07071020, + MV_9235_GPIO_DATA_OUT_ENABLE = 0x07071024, + MV_9235_GPIO_ACTIVE = 0x07071058, + MV_9235_VENDOR_SPEC1_ADDR_OFFSET = 0xA8, /* To manipulate GPIO via Vendor specific register */ + MV_9235_VENDOR_SPEC1_DATA_OFFSET = 0xAC, +}; + +/* + * Read value from 9235 gpio register + */ +u32 syno_mv_9235_gpio_reg_read(struct ata_host *host, const unsigned int gpioaddr) +{ + void __iomem *host_mmio = NULL; + u32 value = 0; + + if(NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // write to 9235 gpio active register address to VENDER_SPEC_ADDR1 + writel(gpioaddr, host_mmio + MV_9235_VENDOR_SPEC1_ADDR_OFFSET); + // read original value from vendor specific data1 + value = readl(host_mmio + MV_9235_VENDOR_SPEC1_DATA_OFFSET); +END: + return value; +} + +/* + * 9235 GPIO register set + */ +void syno_mv_9235_gpio_reg_set(struct ata_host *host, const unsigned int gpioaddr, u32 value) +{ + void __iomem *host_mmio = NULL; + u32 reg_val; + + if(NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // write to 9235 gpio active register address to VENDER_SPEC_ADDR1 + writel(gpioaddr, host_mmio + MV_9235_VENDOR_SPEC1_ADDR_OFFSET); + // read original value from vendor specific data1 + reg_val = readl(host_mmio + MV_9235_VENDOR_SPEC1_DATA_OFFSET); + // then write value to it + writel(value, host_mmio + MV_9235_VENDOR_SPEC1_DATA_OFFSET); +END: + return; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +/* + * Check vender and device for Marvell 88se9235, 88se9215, 88se9170 + */ +static int syno_mv_9xxx_check(struct pci_dev* pdev) +{ + if (pdev->vendor == 0x1b4b && (pdev->device == 0x9235 || pdev->device == 0x9215 || pdev->device == 0x9170)) { + return 1; + } + + return 0; +} + +/* + * Get value from 9xxx vendor spec register2 + */ +static u32 syno_mv_9xxx_reg_get(struct ata_host *host, const unsigned int reg_addr, unsigned int addr_offset, unsigned int data_offset) +{ + void __iomem *host_mmio = NULL; + u32 value = 0; + + if(NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // write to 9xxx from register + writel(reg_addr, host_mmio + addr_offset); + // read original value from register + value = readl(host_mmio + data_offset); +END: + return value; +} + +/* + * Set value to 9xxx vendor spec register2 + */ +static void syno_mv_9xxx_reg_set(struct ata_host *host, const unsigned int reg_addr, u32 value, const unsigned int addr_offset, const unsigned int data_offset) +{ + void __iomem *host_mmio = NULL; + + if(NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // set 9xxx register for writting + writel(reg_addr, host_mmio + addr_offset); + // then write value to it + writel(value, host_mmio + data_offset); +END: + return; +} + +/* + * Signal adjustment per model + */ +#define MV_GEN 3 +#define MV_PORT 4 +/* The register addrs are provided by Marvell and no description on spec */ +const unsigned int mv_sata_gen[MV_GEN] = {0x8D, 0x8F, 0x91}; +const unsigned mv_port_addr[MV_PORT] = {0x178, 0x1f8, 0x278, 0x2f8}; +const unsigned mv_port_data[MV_PORT] = {0x17c, 0x1fc, 0x27c, 0x2fc}; + +void syno_mv_9xxx_amp_adjust_by_port(struct ata_host *host, u32 val, unsigned int addr_offset, const unsigned int data_offset, const unsigned int reg_addr) +{ + u32 reg_val = 0; + + reg_val = syno_mv_9xxx_reg_get(host, 0x0E, addr_offset, data_offset); + syno_mv_9xxx_reg_set(host, 0xE, reg_val & ~0x100, addr_offset, data_offset); + reg_val = syno_mv_9xxx_reg_get(host, reg_addr, addr_offset, data_offset); + // Make sure we only modify the necessary bits + val &= 0xFBE; + reg_val &= ~0xFBE; + reg_val |= val; + syno_mv_9xxx_reg_set(host, reg_addr, reg_val, addr_offset, data_offset); +} + +void syno_mv_9xxx_amp_adjust(struct ata_host *host, struct pci_dev *pdev) +{ + int port = 0; +#ifdef MY_ABC_HERE + int idx = 0; + + if (0 <= (idx = syno_m2d_model_get(pdev))) { + for (port = 0; port < syno_m2d_models[idx].max_ports; port++) { + if (syno_m2d_models[idx].amp_param_g2[port]) { + syno_mv_9xxx_amp_adjust_by_port(host, + syno_m2d_models[idx].amp_param_g2[port], + mv_port_addr[port], mv_port_data[port], mv_sata_gen[1]); + } + + if (syno_m2d_models[idx].amp_param_g3[port]) { + syno_mv_9xxx_amp_adjust_by_port(host, + syno_m2d_models[idx].amp_param_g3[port], + mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + } + } + } else { +#endif /* MY_ABC_HERE */ + if (syno_is_hw_version(HW_DS720p)) { + // ESATA port + /* MV9170 */ + if (syno_is_hw_revision(HW_R1)) { + port = 0; + syno_mv_9xxx_amp_adjust_by_port(host, 0xE75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + port = 1; + syno_mv_9xxx_amp_adjust_by_port(host, 0xE75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + } else { + port = 0; + syno_mv_9xxx_amp_adjust_by_port(host, 0xA75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + } + } else if (syno_is_hw_version(HW_DS1520p)) { + if (0x9170 == pdev->device) { + port = 0; + syno_mv_9xxx_amp_adjust_by_port(host, 0xD75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + port = 1; + syno_mv_9xxx_amp_adjust_by_port(host, 0xD75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + } + } else if (syno_is_hw_version(HW_DS920p)) { + if (0x9170 == pdev->device) { + port = 0; + syno_mv_9xxx_amp_adjust_by_port(host, 0xD75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + port = 1; + syno_mv_9xxx_amp_adjust_by_port(host, 0xE75, mv_port_addr[port], mv_port_data[port], mv_sata_gen[2]); + } + } +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +#define SYNO_JMB585_PORT_NUM 5 +#define SYNO_JMB582_PORT_NUM 2 +#define SYNO_JMB58X_GEN 3 +#define SYNO_JMB58X_SATA_REG 1 +#define SYNO_JMB58X_PCIE_REG 0 + +const unsigned jmb_port_addr[SYNO_JMB58X_GEN][SYNO_JMB585_PORT_NUM] = {{0x74, 0x76, 0x78, 0x7A, 0x7C}, + {0x73, 0x75, 0x77, 0x79, 0x7B}, + {0x04, 0x11, 0x1e, 0x2b, 0x38}}; +const unsigned jmb_port_ctle_reg[SYNO_JMB585_PORT_NUM] = {0x0B, 0x18, 0x25, 0x32, 0x3F}; +const unsigned jmb_ssc_addr = 0x2; + +static u32 syno_jmb58x_reg_get(struct ata_host *host, const unsigned int addr, unsigned long reg_type) +{ + void __iomem *host_mmio = NULL; + u32 reg_data = 0; + + if (NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers + // 1: SATA PHY registers. + // Offset C0 [IDXP] is index port register + writel((addr & 0x01FFFUL) + (reg_type << 18UL), host_mmio + 0xC0); + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + reg_data = readl(host_mmio + 0xC8); + +END: + return reg_data; +} + +static void syno_jmb58x_reg_set(struct ata_host *host, const unsigned int addr, unsigned int data, unsigned long reg_type) +{ + void __iomem *host_mmio = NULL; + + if (NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers + // 1: SATA PHY registers. + // Offset C0 [IDXP] is index port register + writel((addr & 0x01FFFUL) + (reg_type << 18UL), host_mmio + 0xC0); + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + writel(data, host_mmio + 0xC8); + +END: + return; +} + +void syno_jmb58x_amp_adjust(struct ata_host *host, struct pci_dev* pdev, const unsigned addr[][SYNO_JMB585_PORT_NUM], unsigned int *data, int len, unsigned int gen) +{ + int port = 0; + if ( NULL == pdev || NULL == data || SYNO_JMB585_PORT_NUM < len || SYNO_JMB58X_GEN < gen || 0 == gen) { + dev_warn(&pdev->dev, "Invalid parameter\n"); + return; + } + for (port = 0; port < len; port++) { + syno_jmb58x_reg_set(host, addr[gen - 1][port], data[port], SYNO_JMB58X_SATA_REG); + mdelay(100); + dev_info(&pdev->dev, "JMB58%d port=%d, reg_addr=0x%x, reg_data=0x%x\n", len, port, addr[gen - 1][port], syno_jmb58x_reg_get(host, addr[gen - 1][port], SYNO_JMB58X_SATA_REG)); + } +} + +static void syno_jmb58x_ssc_set(struct ata_host *host, struct pci_dev* pdev, const unsigned addr, unsigned ssc_enable) +{ + u32 value = 0; + + if (ssc_enable) { + value = 0x00003803; // 0x3803 for SSC enable + } else { + value = 0x00003813; // 0x3813 for SSC disable + } + syno_jmb58x_reg_set(host, addr, value, SYNO_JMB58X_SATA_REG); + + value = syno_jmb58x_reg_get(host, addr, SYNO_JMB58X_SATA_REG); + dev_info(&pdev->dev, "JMB58%d SSC register: 0x%x, SSC %s\n", pdev->device, value, (value & 0x00000010)?"off":"on"); + return; +} + +static void syno_jmb58x_spi_read(struct ata_host *host, u8 *buffer, u32 buffer_size, u32 offset) +{ + u32 i = 0; + u32 dwData = 0; + void __iomem *host_mmio = NULL; + + if (NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // setting register for spi_read + // offset B4 is SPI configuration register, 0xFF for set configuration + // offset B5 is SPI write protect bit, 0x80 for disable write protect + // offset B6 is SPI control register + // offset B7 is SPI command register, spi flash's instruction code. + // combine and set + writel(0xFF | (0x80 << 8) | (0xE9 << 16) | (0x03 << 24), host_mmio + 0xB4); + + for (i = offset; i < (offset + buffer_size); i += 4) { + // write to index port(offset 0xC0) first + // the unit of index port is byte but must DW aligned + // Offset C0 [IDXP] is index port register. + writel(i, host_mmio + 0xC0); + + // Offset CC [EROM] is data port for external SPI flash access. + // read data port(offset 0xCC) from the desired target address + dwData = readl(host_mmio + 0xCC); + buffer[i - offset] = (u8) dwData; + buffer[i - offset + 1] = (u8)(dwData >> 8); + buffer[i - offset + 2] = (u8)(dwData >> 16); + buffer[i - offset + 3] = (u8)(dwData >> 24); + } + +END: + return; +} + +static bool syno_jmb58x_read_header_ver(struct ata_host *host, struct pci_dev *pdev, char *szHeaderVer, int cbHeaderVer) +{ + u32 offset = 0; + u32 rdbuffer_offset = 0; + static u8 rbuffer[1024] = {0};//Modified data type to static to prevent the compiling warning that the frame size is larger than 1024 bytes + u32 cmp_offset = 0; + bool blFoundOffset = false; + + for (offset = 0; offset < 1048576; offset += 1024) { + //Default flash size 1MB, can adjust this value according to flash's actual size + // read 1024 bytes from flash + syno_jmb58x_spi_read(host, rbuffer, 1024, offset); + + for (rdbuffer_offset = 0; rdbuffer_offset < 1024; rdbuffer_offset += 8) { + if((0x08 == (rbuffer[rdbuffer_offset + 3] & 0x08)) && !(offset == 0 && rdbuffer_offset == 0)) { + blFoundOffset = true; //Offset command location found + rdbuffer_offset += 8; + break; + } + } + + if (blFoundOffset) { + if (0 == rdbuffer_offset % 512) { + cmp_offset = rbuffer[rdbuffer_offset - 4] | rbuffer[rdbuffer_offset - 3] << 8 | rbuffer[rdbuffer_offset - 2] << 16 | rbuffer[rdbuffer_offset - 1] << 24; + if ((offset + rdbuffer_offset) == cmp_offset) { + //If the Option ROM offset equals the found offset value while the found offset location is adjacent to Option ROM offset, + //it means the header version doesn't exist + dev_err(&pdev->dev, "JMB%x header error: No Version in Header\n", pdev->device); + blFoundOffset = false; + goto END; + } + } + + //If the location of the found offset is at the end of 1024 bytes, it means the header version is located at the beginning of + //the next 1024 bytes. So read 4 more bytes to acquire the header version + if (1024 == rdbuffer_offset) { + memset(rbuffer, 0, 1024); + syno_jmb58x_spi_read(host, rbuffer, 4, offset); + rdbuffer_offset = 0; + } + + if (0 == rbuffer[rdbuffer_offset] && 0 == rbuffer[rdbuffer_offset + 1] && 0 == rbuffer[rdbuffer_offset + 2] && 0 == rbuffer[rdbuffer_offset + 3]) { + //The version value equals 0.0.0.0, which means the header version doesn't exist + dev_err(&pdev->dev, "JMB%x header error: Version value is 0.0.0.0\n", pdev->device); + blFoundOffset = false; + goto END; + } + + snprintf(szHeaderVer, cbHeaderVer, "%02d.%02d.%02d.%02d", rbuffer[rdbuffer_offset], rbuffer[rdbuffer_offset+1], rbuffer[rdbuffer_offset+2], rbuffer[rdbuffer_offset+3]); + goto END; + } + } + +END: + return blFoundOffset; +} + +static int syno_jmb58x_get_chip_version(struct ata_host *host, char *szChipVer, int cbChipVer) +{ + int iRet = -1; + struct pci_dev *pdev = NULL; + void __iomem *host_mmio = NULL; + u32 reg_data = 0; + + if (!host || !szChipVer || 0 > cbChipVer) { + goto END; + } + + if (NULL == (host_mmio = ahci_host_base(host)) || + NULL == (pdev = to_pci_dev(host->dev))) { + goto END; + } + + reg_data = readl(host_mmio + 0x44); + if (reg_data & 0xFF) { + snprintf(szChipVer, cbChipVer, "B0"); + } else { + //read chip and header version + reg_data = syno_jmb58x_reg_get(host, 0x564, SYNO_JMB58X_PCIE_REG); + snprintf(szChipVer, cbChipVer, (reg_data & 0x00000100)?"A1":"A0"); + } + + iRet = 0; +END: + return iRet; +} + +static void syno_jmb58x_version_show(struct ata_host *host) +{ + struct pci_dev *pdev = NULL; + char szHeaderVer[32] = {0}; + char szChipVer[16] = {0}; + + if (!host || NULL == (pdev = to_pci_dev(host->dev))) { + goto END; + } + + //read chip and header version + + if (0 == syno_jmb58x_get_chip_version(host, szChipVer, sizeof(szChipVer))) { + dev_info(&pdev->dev, "JMB%x Chip Version: %s\n", pdev->device, szChipVer); + } else { + dev_err(&pdev->dev, "JMB%x Chip Version: CANNOT GET VERSION!!\n", pdev->device); + } + + if (syno_jmb58x_read_header_ver(host, pdev, szHeaderVer, 32)) { + dev_info(&pdev->dev, "JMB%x Header Version: %s\n", pdev->device, szHeaderVer); + } else { + dev_err(&pdev->dev, "JMB%x Header Version: CANNOT GET HEADER VERSION!!\n", pdev->device); + } + +END: + return; +} + +void syno_jmb58x_init(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + unsigned int jmb585_data[SYNO_JMB585_PORT_NUM] = {0}; + unsigned int link_speed = 0; + + u32 value = 0; + + syno_jmb58x_version_show(host); + + if (syno_is_hw_version(HW_RS1220p)) { + if (0x11 == PCI_SLOT(pdev->bus->self->devfn)) { + /* 197b:0585 pci address is 00:11.0 in RS1220+ */ + //set gen 3 SATA Signal + link_speed = 3; + jmb585_data[0] = 0x7fe9; + jmb585_data[1] = 0xffe9; + jmb585_data[2] = 0x7fe9; + jmb585_data[3] = 0x1ffe9; + jmb585_data[4] = 0x1fe7; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_DS1520p)) { + if (0x13 == PCI_SLOT(pdev->bus->self->devfn)) { + /* 197b:0585 pci address is 00:13.0 in DS1520+ */ + //set gen 2 SATA Signal + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_DS1621p)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x05 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe9; + jmb585_data[1] = 0x1fe9; + jmb585_data[2] = 0x1fe9; + jmb585_data[3] = 0x1fe9; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x06 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x3fe9; + jmb585_data[1] = 0xffe9; + jmb585_data[2] = 0x3fe9; + jmb585_data[3] = 0x1ffe9; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e5; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_RS1221p)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x06 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1fe5; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x7e5; + jmb585_data[4] = 0xfef; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x07 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x3e5; + jmb585_data[1] = 0x1e5; + jmb585_data[2] = 0x1fe5; + jmb585_data[3] = 0x1fe5; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_RS1221rpp)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x06 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1e5; + jmb585_data[2] = 0x1fe5; + jmb585_data[3] = 0x1fe5; + jmb585_data[4] = 0x7fff; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x07 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1fe5; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x7e5; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_DS1821p)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x05 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0xae8; + jmb585_data[1] = 0xae5; + jmb585_data[2] = 0xae5; + jmb585_data[3] = 0xae5; + jmb585_data[4] = 0xae5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x06 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0xae8; + jmb585_data[1] = 0xae5; + jmb585_data[2] = 0xae5; + jmb585_data[3] = 0x7e5; + jmb585_data[4] = 0x7e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_DS2422p)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x02 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1fe9; + jmb585_data[2] = 0x1fe5; + jmb585_data[3] = 0x1fe9; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x03 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1fe9; + jmb585_data[2] = 0x1fe5; + jmb585_data[3] = 0x1fe9; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x04 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1fed; + jmb585_data[2] = 0x1fe5; + jmb585_data[3] = 0x1fed; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x05 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe7; + jmb585_data[1] = 0x1fe9; + jmb585_data[2] = 0x1fe9; + jmb585_data[3] = 0x1fe9; + jmb585_data[4] = 0x1fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_RS2421p) || syno_is_hw_version(HW_RS2421rpp)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x05 == PCI_FUNC(pdev->bus->self->devfn)) { + value = syno_jmb58x_reg_get(host, jmb_port_ctle_reg[3], SYNO_JMB58X_SATA_REG); + value &= ~0xFF0; + value |= 0x020; + syno_jmb58x_reg_set(host, jmb_port_ctle_reg[3], value, SYNO_JMB58X_SATA_REG); + } + } else if (syno_is_hw_version(HW_RS2821rpp)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x02 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x1fe5; + jmb585_data[1] = 0x1fe5; + jmb585_data[2] = 0x1fe5; + jmb585_data[3] = 0x1fe5; + jmb585_data[4] = 0x3fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x03 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x7fe5; + jmb585_data[1] = 0x7fe5; + jmb585_data[2] = 0xfe5; + jmb585_data[3] = 0xfe5; + jmb585_data[4] = 0x3fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x04 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x3fe5; + jmb585_data[1] = 0x3fe5; + jmb585_data[2] = 0x7fe5; + jmb585_data[3] = 0x3fe5; + jmb585_data[4] = 0x3fe5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x05 == PCI_FUNC(pdev->bus->self->devfn)) { + link_speed = 3; + jmb585_data[0] = 0x7fe5; + jmb585_data[1] = 0x1fe6; + jmb585_data[2] = 0x1fe6; + jmb585_data[3] = 0x1fe6; + jmb585_data[4] = 0x1fe6; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + link_speed = 2; + jmb585_data[0] = 0x1e4; + jmb585_data[1] = 0x1e4; + jmb585_data[2] = 0x1e5; + jmb585_data[3] = 0x1e4; + jmb585_data[4] = 0x1e5; + syno_jmb58x_amp_adjust(host, pdev, jmb_port_addr, jmb585_data, SYNO_JMB585_PORT_NUM, link_speed); + } + } else if (syno_is_hw_version(HW_RS2423p) || syno_is_hw_version(HW_RS2423rpp)) { + //set SSC off + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x06 == PCI_FUNC(pdev->bus->self->devfn)) { + value = syno_jmb58x_reg_get(host, jmb_port_ctle_reg[3], SYNO_JMB58X_SATA_REG); + value &= ~0xFF0; + value |= 0x020; + syno_jmb58x_reg_set(host, jmb_port_ctle_reg[3], value, SYNO_JMB58X_SATA_REG); + } + } +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +//Access Offset 0xAC to set GPIO[15:11] for pull up[15:11] and output enable [15:11], pull up is used to control resister status, set 0 in this case +//Register description: +// Memory Write (BAR5 + 0xAC ) = { pull_up[15:11] , 3'h0 , 8'h00, output_enable [15:11] , 3'h0, 8'h00 } +// (MSB) (LSB) +//Access Offset 0xA8 DWORD[31:27] to output value to GPIO 15~11 or read value from it. +//Ex: +// Memory Write (BAR5 + 0xA8 ) = { DATA[31:27], 3'h00, 8'h00, 16h'00 } +// Memory Read (BAR5 + 0xA8 ) = { 16'h00, DATA[15:11], 3'h00, 8'h00 } +// (MSB) (LSB) +// +//Need to wait 25 sec after boot up to controll the GPIOs +#define JMB585_GPIO_ENABLE_PIN 0xF800 +#define JMB585_GPIO_PIN_OFFSET 11 +#define JMB585_LED_BOOT_TIME 25 + +static u32 syno_jmb585_led_gpio_get(struct ata_host *host) +{ + void __iomem *host_mmio = NULL; + u32 uData; + + if (NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + //clear output enable for GPIO[15:11] + writel(0x0, host_mmio + 0xAC); + uData = readl(host_mmio + 0xA8); + writel(JMB585_GPIO_ENABLE_PIN, host_mmio + 0xAC); + +END: + return ((uData & JMB585_GPIO_ENABLE_PIN) >> 27); +} + +static void syno_jmb585_led_gpio_set(struct ata_host *host, const unsigned int uiGpioCtrl) +{ + void __iomem *host_mmio = NULL; + + if (NULL == (host_mmio = ahci_host_base(host))) { + goto END; + } + + // set output enable for GPIO[15:11] + writel(JMB585_GPIO_ENABLE_PIN, host_mmio + 0xAC); + // pull high for GPIO[15:11] + // Memory Write (BAR5 + 0xA8 ) = { DATA[31:27], 3'h00, 8'h00, 16h'00 } + writel((uiGpioCtrl & 0x1F) << 27, host_mmio + 0xA8); + +END: + return; +} + +int syno_jmb585_disk_led_get(const int iDiskPort) +{ + unsigned int uiLedIdx = 0; + unsigned int uiLedPolarity = 0; + int iRet = -EINVAL; + struct ata_port *ap = syno_ata_port_get_by_port(iDiskPort); + if (NULL == ap) { + goto END; + } + + // Access GPIO[15:11] for Led[4:0] + uiLedIdx = HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort) - JMB585_GPIO_PIN_OFFSET; + uiLedPolarity = HDD_FAIL_LED_POLARITY_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort); + + //Access Offset 0xAC to set GPIO[15:11] for pull up[15:11] + iRet = syno_jmb585_led_gpio_get(ap->host) & (1 << uiLedIdx); + iRet = iRet >> uiLedIdx; +END: + return (iRet == uiLedPolarity)? 1 : 0; +} +EXPORT_SYMBOL(syno_jmb585_disk_led_get); + +int syno_jmb585_disk_led_set(const int iDiskPort, const int iValue) +{ + unsigned int uiLedIdx = 0; + unsigned int uiLedPolarity = 0; + int iRet = -EINVAL; + struct ata_port *ap = syno_ata_port_get_by_port(iDiskPort); + if (NULL == ap || iValue > 1 || iValue < 0) { + goto END; + } + + // Access GPIO[15:11] for Led[4:0] + uiLedIdx = HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort) - JMB585_GPIO_PIN_OFFSET; + uiLedPolarity = HDD_FAIL_LED_POLARITY_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort); + + if (iValue == uiLedPolarity) { + ap->host->uJMB585LedStat |= (1 << uiLedIdx); + } else { + ap->host->uJMB585LedStat &= ~(1 << uiLedIdx); + } + syno_jmb585_led_gpio_set(ap->host, ap->host->uJMB585LedStat); + iRet = 0; +END: + return iRet; +} +EXPORT_SYMBOL(syno_jmb585_disk_led_set); + +void syno_jmb585_led_wait(void) +{ + struct timespec64 tp; + ktime_get_boottime_ts64(&tp); + if (tp.tv_sec < JMB585_LED_BOOT_TIME) { + msleep((JMB585_LED_BOOT_TIME - tp.tv_sec) * 1000); + } +} +EXPORT_SYMBOL(syno_jmb585_led_wait); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#define SYNO_ASM1061_MAX_PORT_NUM 2 +#define SYNO_ASM1061_GEN 3 +/* + * Check vender and device for asmedia 1061 + */ +static int syno_asmedia_1061_check(struct pci_dev* pdev) +{ + return (pdev->vendor == 0x1b21 && pdev->device == 0x0612) ? 0 : -1; +} + +/* + * Get value from asmedia vendor spec register + */ +static u8 syno_asmedia_1061_reg_get(struct pci_dev *pdev, unsigned int devfn, unsigned int reg_addr) +{ + int check = -1; + u8 reg_data = 0; + + if (0 != syno_asmedia_1061_check(pdev)) { + dev_warn(&pdev->dev, "Invalid PCI device !!\n"); + goto END; + } + + check = pci_bus_read_config_byte(pdev->bus, devfn, reg_addr, ®_data); + if (0 != check) { + dev_warn(&pdev->dev, "pci_bus_read_config_byte error, return = %d\n", check); + goto END; + } +END: + return reg_data; +} + +/* + * Set value to asmedia vendor spec register + */ +static void syno_asmedia_1061_reg_set(struct pci_dev *pdev, unsigned int devfn, unsigned int reg_addr, u8 reg_data) +{ + int check = -1; + + if (0 != syno_asmedia_1061_check(pdev)) { + dev_warn(&pdev->dev, "Invalid PCI device !!\n"); + goto END; + } + + check = pci_bus_write_config_byte(pdev->bus, devfn, reg_addr, reg_data); + if (0 != check) { + dev_warn(&pdev->dev, "pci_bus_write_config_byte error, return = %d\n", check); + goto END; + } +END: + return; +} + +void syno_asmedia_1061_gpio2_led_mode(struct pci_dev *pdev, unsigned int devfn) +{ + unsigned int led_mode_addr = 0xA02; + u8 reg_data = 0; + + reg_data = syno_asmedia_1061_reg_get(pdev, devfn, led_mode_addr); + reg_data |= (1 << 3); + syno_asmedia_1061_reg_set(pdev, devfn, led_mode_addr, reg_data); +} + +void syno_asmedia_1061_amp_adjust(struct pci_dev *pdev, unsigned int devfn, unsigned int *addr, unsigned int *data, int len, unsigned int gen_offset) +{ + int port = 0; + + if (NULL == pdev || NULL == data || SYNO_ASM1061_MAX_PORT_NUM < len) { + printk("syno_asmedia_1061_amp_adjust: Invalid parameter\n"); + goto END; + } + + for (port = 0; port < len; ++port) { + syno_asmedia_1061_reg_set(pdev, devfn, addr[port] | gen_offset, data[port]); + dev_info(&pdev->dev, "Asmedia 1061 port=%d, reg_addr=0x%x, reg_data=0x%x\n", port, addr[port] | gen_offset, syno_asmedia_1061_reg_get(pdev, devfn, addr[port] | gen_offset)); + } + +END: + return; +} + +unsigned int asmedia_addr[SYNO_ASM1061_MAX_PORT_NUM] = {0xCA0, 0xDA0}; +unsigned int asmedia_gen[SYNO_ASM1061_GEN] = {0x4, 0x5, 0x6}; + +void syno_asmedia_1061_init(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + unsigned int devfn = 0; + unsigned int asmedia_DS420p_data_gen1[SYNO_ASM1061_MAX_PORT_NUM] = {0xab, 0xab}; + unsigned int asmedia_DS420p_data_gen2[SYNO_ASM1061_MAX_PORT_NUM] = {0x26, 0x26}; + unsigned int asmedia_DS420p_data_gen3[SYNO_ASM1061_MAX_PORT_NUM] = {0x38, 0x28}; + unsigned int asmedia_DS920p_data_gen1[SYNO_ASM1061_MAX_PORT_NUM] = {0xab, 0xab}; + unsigned int asmedia_DS920p_data_gen2[SYNO_ASM1061_MAX_PORT_NUM] = {0x26, 0x26}; + unsigned int asmedia_DS920p_data_gen3[SYNO_ASM1061_MAX_PORT_NUM] = {0x25, 0xd8}; + + if (syno_is_hw_version(HW_DS420p)) { + devfn = PCI_DEVFN(0x00, 0x0); + syno_asmedia_1061_amp_adjust(pdev, devfn, asmedia_addr, asmedia_DS420p_data_gen1, SYNO_ASM1061_MAX_PORT_NUM, asmedia_gen[0]); + syno_asmedia_1061_amp_adjust(pdev, devfn, asmedia_addr, asmedia_DS420p_data_gen2, SYNO_ASM1061_MAX_PORT_NUM, asmedia_gen[1]); + syno_asmedia_1061_amp_adjust(pdev, devfn, asmedia_addr, asmedia_DS420p_data_gen3, SYNO_ASM1061_MAX_PORT_NUM, asmedia_gen[2]); + mdelay(100); + syno_asmedia_1061_reg_set(pdev, devfn, 0xCAE, 0x92); + mdelay(100); + syno_asmedia_1061_reg_set(pdev, devfn, 0xDAE, 0x92); + } else if (syno_is_hw_version(HW_DS920p)) { + devfn = PCI_DEVFN(0x00, 0x0); + syno_asmedia_1061_amp_adjust(pdev, devfn, asmedia_addr, asmedia_DS920p_data_gen1, SYNO_ASM1061_MAX_PORT_NUM, asmedia_gen[0]); + syno_asmedia_1061_amp_adjust(pdev, devfn, asmedia_addr, asmedia_DS920p_data_gen2, SYNO_ASM1061_MAX_PORT_NUM, asmedia_gen[1]); + syno_asmedia_1061_amp_adjust(pdev, devfn, asmedia_addr, asmedia_DS920p_data_gen3, SYNO_ASM1061_MAX_PORT_NUM, asmedia_gen[2]); + mdelay(100); + syno_asmedia_1061_reg_set(pdev, devfn, 0xCAE, 0x92); + mdelay(100); + syno_asmedia_1061_reg_set(pdev, devfn, 0xDAE, 0x92); + } +} +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SATA_ASM116X_CONTROL +#define SYNO_ASM116X_MAX_PORT_NUM 6 +#define SYNO_ASM116X_GEN 3 + +static int syno_asmedia_116x_check(struct pci_dev* pdev) +{ + return (pdev->vendor == 0x1b21 && (pdev->device == 0x1164 || pdev->device == 0x1165)) ? 0 : -1; +} + +u8 syno_asmedia_116x_reg_get_byte(struct pci_dev *pdev, const unsigned int reg_addr) +{ + u8 reg_data = 0; + void __iomem *bar0 = NULL; + + if (NULL == (bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)))) { + dev_warn(&pdev->dev, "Can't map asmedia registers\n"); + goto END; + } + + reg_data = readb(bar0 + reg_addr); + +END: + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + return reg_data; +} + +void syno_asmedia_116x_reg_set_byte(struct pci_dev *pdev, unsigned int reg_addr, u8 reg_data) +{ + void __iomem *bar0 = NULL; + + if (NULL == (bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)))) { + dev_warn(&pdev->dev, "Can't map asmedia registers\n"); + goto END; + } + + writeb(reg_data, bar0 + reg_addr); + +END: + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + return; +} + +u16 syno_asmedia_116x_reg_get_word(struct pci_dev *pdev, const unsigned int reg_addr) +{ + u16 reg_data = 0; + void __iomem *bar0 = NULL; + + if (NULL == (bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)))) { + dev_warn(&pdev->dev, "Can't map asmedia registers\n"); + goto END; + } + + reg_data = readw(bar0 + reg_addr); + +END: + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + return reg_data; +} + +void syno_asmedia_116x_reg_set_word(struct pci_dev *pdev, unsigned int reg_addr, u16 reg_data) +{ + void __iomem *bar0 = NULL; + + if (NULL == (bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)))) { + dev_warn(&pdev->dev, "Can't map asmedia registers\n"); + goto END; + } + + writew(reg_data, bar0 + reg_addr); + +END: + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + return; +} + +#ifdef MY_DEF_HERE +static void syno_asmedia_116x_amp_adjust(struct pci_dev *pdev, const unsigned addr[][SYNO_ASM116X_MAX_PORT_NUM], unsigned int *data, unsigned int len, unsigned int gen) +{ + void __iomem *bar0 = NULL; + unsigned int port = 0; + + if (NULL == pdev || NULL == data || SYNO_ASM116X_MAX_PORT_NUM < len || SYNO_ASM116X_GEN < gen || 0 == gen) { + printk("syno_asmedia_116x_amp_adjust: Invalid parameter\n"); + goto END; + } + + bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!bar0) { + dev_warn(&pdev->dev, "Can't map asmedia sata registers\n"); + goto END; + } + + for (port = 0; port < len; port++) { + syno_asmedia_116x_reg_set_byte(pdev, addr[gen - 1][port], data[port]); + dev_info(&pdev->dev, "ASM%x port=%d, reg_addr=0x%x, reg_data=0x%x\n",pdev->device, port, addr[gen - 1][port], syno_asmedia_116x_reg_get_byte(pdev, addr[gen - 1][port])); + } + +END: + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + return; +} + +static void syno_asmedia_116x_ssc_set(struct pci_dev* pdev, unsigned ssc_enable) +{ + const unsigned asm116x_ssc_addr = 0x198C; + u8 value = 0; + + if (NULL == pdev || 1 < ssc_enable) { + printk("syno_asmedia_116x_ssc_set: Invalid parameter\n"); + goto END; + } + + value = syno_asmedia_116x_reg_get_byte(pdev, asm116x_ssc_addr); + if (ssc_enable) { + value |= 0x01; + } else { + value &= ~0x01; + } + syno_asmedia_116x_reg_set_byte(pdev, asm116x_ssc_addr, value); + value = syno_asmedia_116x_reg_get_byte(pdev, asm116x_ssc_addr); + dev_info(&pdev->dev, "ASM%x SSC register: 0x%x, SSC %s\n", pdev->device, value, (value & 0x01)?"on":"off"); + +END: + return; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +#define SYNO_ASM116X_LED_UNIT_REG 0x1D20 +#define SYNO_ASM116X_GPIO_MODE_REG 0x1D6E +#define SYNO_ASM116X_GPIO_CTL_REG 0x1D6A +#define SYNO_ASM116X_GPIO_OUTPUT_REG 0x1D6C +#define SYNO_ASM116X_ALED_DURATION 100 + +enum { + ASM116X_LED_UNIT_100US, + ASM116X_LED_UNIT_1MS, + ASM116X_LED_UNIT_10MS, + ASM116X_LED_UNIT_100MS, +}; + +const unsigned asm116x_aled_off_addr[SYNO_ASM116X_MAX_PORT_NUM] = {0x1D10, 0x1D11, 0x1D12, 0x1D13, 0x1D14, 0x1D15}; +const unsigned asm116x_aled_on_addr[SYNO_ASM116X_MAX_PORT_NUM] = {0x1D18, 0x1D19, 0x1D1A, 0x1D1B, 0x1D1C, 0x1D1D}; + +extern int lookup_internal_slot(const struct ata_port *ap); +extern struct ata_port *syno_ata_port_get_by_port(const unsigned short diskPort); + +int syno_asmedia_116x_disk_led_get(const int iDiskPort) +{ + unsigned int uiLedGpioIdx = 0; + unsigned int uiLedPolarity = 0; + int iRet = -EINVAL; + struct ata_port *ap = syno_ata_port_get_by_port(iDiskPort); + + if (NULL == ap) { + printk("syno_asmedia_116x_disk_led_get: Invalid parameter\n"); + goto END; + } + + uiLedGpioIdx = HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort); + uiLedPolarity = HDD_FAIL_LED_POLARITY_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort); + + iRet = syno_asmedia_116x_reg_get_word(to_pci_dev(ap->dev), SYNO_ASM116X_GPIO_OUTPUT_REG) & (1 << uiLedGpioIdx); + iRet = iRet >> uiLedGpioIdx; +END: + return (uiLedPolarity == iRet)? 1 : 0; +} +EXPORT_SYMBOL(syno_asmedia_116x_disk_led_get); + +int syno_asmedia_116x_disk_led_set(const int iDiskPort, const int iValue) +{ + unsigned int uiLedGpioIdx = 0; + unsigned int uiLedPolarity = 0; + int iRet = -EINVAL; + u16 reg_data = 0; + struct ata_port *ap = syno_ata_port_get_by_port(iDiskPort); + + if (NULL == ap || iValue > 1 || iValue < 0) { + printk("syno_asmedia_116x_disk_led_set: Invalid parameter\n"); + goto END; + } + + uiLedGpioIdx = HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort); + uiLedPolarity = HDD_FAIL_LED_POLARITY_BY_SLOT(DT_INTERNAL_SLOT, iDiskPort); + reg_data = syno_asmedia_116x_reg_get_word(to_pci_dev(ap->dev), SYNO_ASM116X_GPIO_OUTPUT_REG); + + if (uiLedPolarity == iValue) { + reg_data |= (1 << uiLedGpioIdx); + } else { + reg_data &= ~(1 << uiLedGpioIdx); + } + syno_asmedia_116x_reg_set_word(to_pci_dev(ap->dev), SYNO_ASM116X_GPIO_OUTPUT_REG, reg_data); + iRet = 0; +END: + return iRet; +} +EXPORT_SYMBOL(syno_asmedia_116x_disk_led_set); + +static void syno_asmedia_116x_disk_led_gpio_init(struct ata_host *host, unsigned int uiMaxPort) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + u8 gpio_mode = 0; + u16 gpio_ctl = 0, gpio_output = 0, led_unit = 0; + unsigned int uiHddFailLedGpioIdx = 0; + unsigned int uiHddFailLedPolarity = 0; + unsigned int i = 0; + unsigned int uiDiskIdx = 0; + + if (NULL == pdev || SYNO_ASM116X_MAX_PORT_NUM < uiMaxPort) { + printk("syno_asmedia_116x_disk_led_gpio_init: Invalid parameter\n"); + goto END; + } + + // GPIO_MODE[0:5] represent GPIO 8 ~ 13 mode, 1 for GPIO, 0 for DEVSLP + gpio_mode = syno_asmedia_116x_reg_get_byte(pdev, SYNO_ASM116X_GPIO_MODE_REG); + // GPIO_OUTPUT[0:5] represent GPIO 0 ~ 5 and GPIO_OUTPUT[8:13] represent GPIO 8 ~ 13 + gpio_output = syno_asmedia_116x_reg_get_word(pdev, SYNO_ASM116X_GPIO_OUTPUT_REG); + // GPIO_CTL[0:5] represent GPIO 0 ~ 5 and GPIO_CTL[8:13] represent GPIO 8 ~ 13, 1 for enable + gpio_ctl = syno_asmedia_116x_reg_get_word(pdev, SYNO_ASM116X_GPIO_CTL_REG); + // LED_UNIT[0:11] represent Port 0 ~ 5 Led time unit, bit[2n:2n+1] for led n, 0h : 100us, 1h:1ms, 2h:10ms, 3h:100ms + led_unit = syno_asmedia_116x_reg_get_word(pdev, SYNO_ASM116X_LED_UNIT_REG); + + for (i = 0; i < uiMaxPort; i++) { + if (0 > (uiDiskIdx = lookup_internal_slot(host->ports[i]))) { + goto END; + } else if ( 0 == uiDiskIdx) { + continue; + } + uiHddFailLedGpioIdx = HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, uiDiskIdx); + uiHddFailLedPolarity = HDD_FAIL_LED_POLARITY_BY_SLOT(DT_INTERNAL_SLOT, uiDiskIdx); + // clean led time unit first + led_unit &= ~(3 << (2 * i)); + // set Led time unit to 1 ms for led i + led_unit |= (ASM116X_LED_UNIT_1MS << (2 * i)); + // set LED_ON_PX Duration + syno_asmedia_116x_reg_set_byte(pdev, asm116x_aled_on_addr[i], SYNO_ASM116X_ALED_DURATION); + // set LED_OFF_PX Duration + syno_asmedia_116x_reg_set_byte(pdev, asm116x_aled_off_addr[i], SYNO_ASM116X_ALED_DURATION); + // set to GPIO mode + if (8 <= uiHddFailLedGpioIdx) { + gpio_mode |= (1 << (uiHddFailLedGpioIdx - 8)); + } + // initialize Led to off + if (0 == uiHddFailLedPolarity) { + gpio_output |= (1 << uiHddFailLedGpioIdx); + } else { + gpio_output &= ~(1 << uiHddFailLedGpioIdx); + } + // enable GPIO + gpio_ctl |= (1 << uiHddFailLedGpioIdx); + } + + syno_asmedia_116x_reg_set_word(pdev, SYNO_ASM116X_LED_UNIT_REG, led_unit); + syno_asmedia_116x_reg_set_byte(pdev, SYNO_ASM116X_GPIO_MODE_REG, gpio_mode); + syno_asmedia_116x_reg_set_word(pdev, SYNO_ASM116X_GPIO_OUTPUT_REG, gpio_output); + syno_asmedia_116x_reg_set_word(pdev, SYNO_ASM116X_GPIO_CTL_REG, gpio_ctl); + +END: + return; +} +#endif /* MY_DEF_HERE */ + +static u32 syno_asmedia_116x_fw_version_get(struct pci_dev *pdev, unsigned int devfn, unsigned int reg_addr) +{ + int iRet = -1; + u32 reg_data = 0; + + if (0 != syno_asmedia_116x_check(pdev)) { + dev_warn(&pdev->dev, "Invalid PCI device !!\n"); + goto END; + } + + // FW Version: 0xF0~0xF5 from PCIe MMIO + iRet = pci_bus_read_config_dword(pdev->bus, devfn, reg_addr, ®_data); + if (0 != iRet) { + dev_warn(&pdev->dev, "pci_bus_read_config_byte error, return = %d\n", iRet); + goto END; + } +END: + return reg_data; +} + +static void syno_asmedia_116x_fw_version_show(struct ata_host *host) +{ + + struct pci_dev *pdev = NULL; + unsigned int uiFwVer_1 = 0, uiFwVer_2 = 0; + + if (NULL == host || NULL == (pdev = to_pci_dev(host->dev))) { + goto END; + } + + // FW Version: 0xF0~0xF5 from PCIe MMIO + uiFwVer_1 = syno_asmedia_116x_fw_version_get(pdev, PCI_DEVFN(0x00, 0x0), 0xF0); + uiFwVer_2 = syno_asmedia_116x_fw_version_get(pdev, PCI_DEVFN(0x00, 0x0), 0xF4); + dev_info(&pdev->dev, "ASM%x FW Version: %x%x\n", pdev->device, uiFwVer_1, uiFwVer_2); + +END: + return; +} + +#ifdef MY_DEF_HERE +const unsigned asm116x_port_addr[SYNO_ASM116X_GEN][SYNO_ASM116X_MAX_PORT_NUM] = {{0x122, 0x322, 0x522, 0x722, 0x922, 0xB22}, + {0x123, 0x323, 0x523, 0x723, 0x923, 0xB23}, + {0x124, 0x324, 0x524, 0x724, 0x924, 0xB24}}; +#endif /* MY_DEF_HERE */ + +void syno_asmedia_116x_init(struct ata_host *host) +{ +#ifdef MY_DEF_HERE + struct pci_dev *pdev = to_pci_dev(host->dev); + unsigned int uiLinkSpeed = 0; + unsigned int asm116x_data[SYNO_ASM116X_MAX_PORT_NUM] = {0}; +#endif /* MY_DEF_HERE */ + + syno_asmedia_116x_fw_version_show(host); + +#ifdef MY_DEF_HERE + // Initialize GPIO Mode for led control + syno_asmedia_116x_disk_led_gpio_init(host, host->n_ports); +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE + if (syno_is_hw_version(HW_RS2421p) || syno_is_hw_version(HW_RS2421rpp)) { + // Set SSC off + syno_asmedia_116x_ssc_set(pdev, 0); + + if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x02 == PCI_FUNC(pdev->bus->self->devfn)) { + uiLinkSpeed = 3; + asm116x_data[0] = 0x38; + asm116x_data[1] = 0x38; + asm116x_data[2] = 0x38; + asm116x_data[3] = 0x38; + syno_asmedia_116x_amp_adjust(pdev, asm116x_port_addr, asm116x_data, host->n_ports, uiLinkSpeed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x03 == PCI_FUNC(pdev->bus->self->devfn)) { + uiLinkSpeed = 3; + asm116x_data[0] = 0x38; + asm116x_data[1] = 0x38; + asm116x_data[2] = 0x38; + asm116x_data[3] = 0x38; + syno_asmedia_116x_amp_adjust(pdev, asm116x_port_addr, asm116x_data, host->n_ports, uiLinkSpeed); + } else if (0x01 == PCI_SLOT(pdev->bus->self->devfn) && 0x04 == PCI_FUNC(pdev->bus->self->devfn)) { + uiLinkSpeed = 3; + asm116x_data[0] = 0x38; + asm116x_data[1] = 0x38; + asm116x_data[2] = 0x38; + asm116x_data[3] = 0x38; + syno_asmedia_116x_amp_adjust(pdev, asm116x_port_addr, asm116x_data, host->n_ports, uiLinkSpeed); + } + } +#endif /* MY_DEF_HERE */ +} +#endif /* CONFIG_SYNO_SATA_ASM116X_CONTROL */ + static void ahci_pci_save_initial_config(struct pci_dev *pdev, struct ahci_host_priv *hpriv) { @@ -831,6 +2420,61 @@ static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, return rc; } +#ifdef MY_ABC_HERE +static int syno_ahci_hardreset_jmb(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; + int rc; + void __iomem *port_mmio = ahci_port_base(link->ap); + u32 uIRQStatus = 0; + + DPRINTK("ENTER\n"); + hpriv->stop_engine(ap); + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = ATA_BUSY; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + + uIRQStatus = readl(port_mmio + PORT_IRQ_MASK); + writel(uIRQStatus & ~PORT_IRQ_BAD_PMP, port_mmio + PORT_IRQ_MASK); + rc = sata_link_hardreset(link, timing, deadline, &online, + ahci_check_ready); + writel(uIRQStatus, port_mmio + PORT_IRQ_MASK); + + hpriv->start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); + return rc; +} + +static int syno_ahci_softreset_jmb(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + int iRet = 0; + void __iomem *port_mmio = ahci_port_base(link->ap); + u32 uIRQStatus = 0; + DPRINTK("ENTER\n"); + + uIRQStatus = readl(port_mmio + PORT_IRQ_MASK); + writel(uIRQStatus & ~PORT_IRQ_BAD_PMP, port_mmio + PORT_IRQ_MASK); + iRet = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); + writel(uIRQStatus, port_mmio + PORT_IRQ_MASK); + return iRet; +} +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_PM static void ahci_pci_disable_interrupts(struct ata_host *host) @@ -1660,6 +3304,224 @@ static ssize_t remapped_nvme_show(struct device *dev, static DEVICE_ATTR_RO(remapped_nvme); +#ifdef MY_ABC_HERE + +#define SYNO_SATA_MAX_GEN 3 +#define SYNO_SATA_MAX_PORTS 32 + +extern int syno_compare_dts_ata_port(const struct ata_port *pAtaPort, const struct device_node *pDeviceNode); +extern int syno_compare_dts_pciepath(const struct pci_dev *pdev, const struct device_node *pDeviceNode); +/** + * syno_ahci_compare_ata_devicetree_info - check the ata_port matches the device_node + * @ap [IN]: query ata_port + * @node [IN]: comparing device_node + * + * return true: success + false: fail + */ +bool syno_ahci_compare_ata_devicetree_info(const struct ata_port *ap, const struct device_node *pNode) +{ + int ret = false; + struct device_node *pAhciNode = NULL; + if (NULL == ap || NULL == pNode) { + goto END; + } + + pAhciNode = of_get_child_by_name(pNode, DT_AHCI); + if (0 != syno_compare_dts_ata_port(ap, pAhciNode)) { + goto END; + } + + if (0 != syno_compare_dts_pciepath(to_pci_dev(ap->dev), pAhciNode)) { + goto END; + } + ret = true; +END: + if (pAhciNode) { + of_node_put(pAhciNode); + } + return ret; +} +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE +static void syno_set_signal(struct ata_host *host, unsigned int sigData[SYNO_SATA_MAX_GEN][SYNO_SATA_MAX_PORTS], unsigned int sscOffTable[SYNO_SATA_MAX_PORTS]) +{ + int port, gen; + struct pci_dev *pdev = NULL; + int max_port = 0; + + if (NULL == host || NULL == sigData) { + goto END; + } + + pdev = to_pci_dev(host->dev); + +#ifdef MY_ABC_HERE + if (syno_mv_9xxx_check(pdev)) { + printk("mv9xxx\n"); + for (gen = 0; gen < MV_GEN; gen++) { + for (port = 0; port < MV_PORT; ++port) { + if (sigData[gen][port]) { + syno_mv_9xxx_amp_adjust_by_port(host, sigData[gen][port], mv_port_addr[port], mv_port_data[port], mv_sata_gen[gen]); + } + } + } + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (0 == syno_jmb58x_check(pdev->vendor, pdev->device)) { + if (0x0585 == pdev->device) { + max_port = SYNO_JMB585_PORT_NUM; + } else if (0x0582 == pdev->device) { + max_port = SYNO_JMB582_PORT_NUM; + } + + for (gen = 0; gen < SYNO_JMB58X_GEN; gen++) { + for(port = 0; port < max_port; port++) { + if (sigData[gen][port]) { + syno_jmb58x_reg_set(host, jmb_port_addr[gen][port], sigData[gen][port], SYNO_JMB58X_SATA_REG); + mdelay(100); + dev_info(&pdev->dev, "JMB58%d port=%d, reg_addr=0x%x, reg_data=0x%x\n", max_port, port, jmb_port_addr[gen][port], syno_jmb58x_reg_get(host, jmb_port_addr[gen][port], SYNO_JMB58X_SATA_REG)); + } + } + } + + for (port = 0; port < max_port; port++) { + if (sscOffTable[port]) { + syno_jmb58x_ssc_set(host, pdev, jmb_ssc_addr, 0); + break; + } + } + } +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + if (0 == syno_asmedia_1061_check(pdev)) { + for (gen = 0; gen < SYNO_ASM1061_GEN; gen++) { + for (port = 0; port < SYNO_ASM1061_MAX_PORT_NUM; ++port) { + if (sigData[gen][port]) { + syno_asmedia_1061_reg_set(pdev, pdev->devfn, asmedia_addr[port] | asmedia_gen[gen], sigData[gen][port]); + dev_info(&pdev->dev, "Asmedia 1061 port=%d, reg_addr=0x%x, reg_data=0x%x\n", port, asmedia_addr[port] | asmedia_gen[gen], syno_asmedia_1061_reg_get(pdev, pdev->devfn, asmedia_addr[port] | asmedia_gen[gen])); + } + } + } + } +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + if (0 == syno_asmedia_116x_check(pdev)) { + for (gen = 0; gen < SYNO_ASM116X_GEN; ++gen) { + for (port = 0; port < SYNO_ASM116X_MAX_PORT_NUM; ++port) { + if (0 != sigData[gen][port]) { + syno_asmedia_116x_reg_set_byte(pdev, asm116x_port_addr[gen][port], sigData[gen][port]); + dev_info(&pdev->dev, "ASM%x port=%d, reg_addr=0x%x, reg_data=0x%x\n",pdev->device, port, asm116x_port_addr[gen][port], syno_asmedia_116x_reg_get_byte(pdev, asm116x_port_addr[gen][port])); + } + } + } + for (port = 0; port < SYNO_ASM116X_GEN; port++) { + if (sscOffTable[port]) { + syno_asmedia_116x_ssc_set(pdev, 0); + break; + } + } + } +#endif /* MY_DEF_HERE */ + +END: + return; +} + +static void syno_init_and_signal_adjust_by_dts(struct ata_host *host) +{ + struct pci_dev *pdev = NULL; + struct device_node *pSlotNode = NULL; + struct device_node *pAhciNode = NULL; + + unsigned int sigData[SYNO_SATA_MAX_GEN][SYNO_SATA_MAX_PORTS] = {{0}}; + unsigned int sscOffTable[SYNO_SATA_MAX_PORTS] = {0}; + + u32 ata_port_no = U32_MAX; + + char buf[MAX_NODENAME_LEN] = {0}; + int i = 0; + + if (NULL == of_root || NULL == (pdev = to_pci_dev(host->dev))) { + goto END; + } + +/* Show contorller fw version */ +#ifdef MY_ABC_HERE + if (0 == syno_jmb58x_check(pdev->vendor, pdev->device)) { + syno_jmb58x_version_show(host); + } +#endif /* MY_ABC_HERE */ +#ifdef CONFIG_SYNO_SATA_ASM116X_CONTROL + if (0 == syno_asmedia_116x_check(pdev)) { + syno_asmedia_116x_fw_version_show(host); + } +#endif /* CONFIG_SYNO_SATA_ASM116X_CONTROL */ + + /* Enum slot */ + for_each_child_of_node(of_root, pSlotNode) { + + /* Skip non-disk slot */ + if ((0 != strncmp(pSlotNode->full_name, DT_INTERNAL_SLOT, strlen(DT_INTERNAL_SLOT))) && + (0 != strncmp(pSlotNode->full_name, DT_ESATA_SLOT, strlen(DT_ESATA_SLOT))) && + (0 != strncmp(pSlotNode->full_name, DT_CX4_SLOT, strlen(DT_CX4_SLOT))) && + (0 != strncmp(pSlotNode->full_name, DT_SYSTEM_SLOT, strlen(DT_SYSTEM_SLOT)))) { + continue; + } + + /* Get AHCI node */ + if (NULL == (pAhciNode = of_get_child_by_name(pSlotNode, DT_AHCI))) { + printk("Can not get ahci node: %s\n", pSlotNode->full_name); + continue; + } + + /* Match PCIe path */ + if (0 != syno_compare_dts_pciepath(pdev, pAhciNode)) { + continue; + } + + /* Get ATA port index */ + if (0 != of_property_read_u32_index(pAhciNode, DT_ATA_PORT, 0, &ata_port_no)) { + continue; + } + + /* Check ATA port index is vaild */ + if (SYNO_SATA_MAX_PORTS <= ata_port_no) { + continue; + } + + /* Get Singal data & store data */ + for (i = 0; i < SYNO_SATA_MAX_GEN; i++) { + snprintf(buf, MAX_NODENAME_LEN, "signal_data_gen%d", i+1); + of_property_read_u32_index(pAhciNode, buf, 0, &sigData[i][ata_port_no]); + } + + /* Read SSC OFF */ + if(of_property_read_bool(pAhciNode, DT_SET_SSC_OFF)) { + sscOffTable[ata_port_no] = 1; + } + } + + syno_set_signal(host, sigData, sscOffTable); + +/* General adjust */ +#ifdef MY_DEF_HERE + if (0 == syno_asmedia_1061_check(pdev)) { + syno_asmedia_1061_reg_set(pdev, pdev->devfn, 0xCAE, 0x92); + mdelay(100); + syno_asmedia_1061_reg_set(pdev, pdev->devfn, 0xDAE, 0x92); + } +#endif /* MY_DEF_HERE */ + +END: + return; + +} +#endif /* MY_ABC_HERE */ + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int board_id = ent->driver_data; @@ -1673,6 +3535,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) VPRINTK("ENTER\n"); +#ifdef MY_ABC_HERE + if ('0' == g_ahci_switch) { + printk("AHCI is disabled.\n"); + return 0; + } +#endif /* MY_ABC_HERE */ + WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS); ata_print_version_once(&pdev->dev, DRV_VERSION); @@ -1886,6 +3755,24 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) ap->ops = &ata_dummy_port_ops; + +#ifdef MY_ABC_HERE + ap->ops->syno_compare_node_info = syno_ahci_compare_ata_devicetree_info; + /* Fill internal slot index. 0 base, < 0 means error or not internal slot */ + ap->syno_internal_slot_index = lookup_internal_slot(ap) - 1; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* Have default syno_recover method, set max tries */ + ap->syno_recover_max_tries = 1; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* Support deep sleep, change recover method to deep retry */ + if (iIsSynoDeepSleepSupport(ap)) { + ap->ops->syno_recover = syno_sata_deep_retry; + } +#endif /* MY_ABC_HERE */ } /* apply workaround for ASUS P5W DH Deluxe mainboard */ @@ -1908,6 +3795,36 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); +#ifdef CONFIG_SYNO_SATA_SIGNAL_ADJUST +#ifdef MY_ABC_HERE + if (syno_mv_9xxx_check(pdev)) { + syno_mv_9xxx_amp_adjust(host, pdev); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (0 == syno_jmb58x_check(pdev->vendor, pdev->device)) { + syno_jmb58x_init(host); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + if (0 == syno_asmedia_1061_check(pdev)) { + syno_asmedia_1061_init(host); + } +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SATA_ASM116X_CONTROL + if (0 == syno_asmedia_116x_check(pdev)) { + syno_asmedia_116x_init(host); + } +#endif /* CONFIG_SYNO_SATA_ASM116X_CONTROL */ +#endif /* CONFIG_SYNO_SATA_SIGNAL_ADJUST */ + +#ifdef MY_ABC_HERE + syno_init_and_signal_adjust_by_dts(host); +#endif /* MY_ABC_HERE */ + rc = ahci_host_activate(host, &ahci_sht); if (rc) return rc; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index d1f284f0c83d..cd78cb84be6d 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * ahci.h - Common AHCI SATA definitions and declarations @@ -320,6 +323,10 @@ struct ahci_port_priv { /* enclosure management info per PM slot */ struct ahci_em_priv em_priv[EM_MAX_SLOTS]; char *irq_desc; /* desc in /proc/interrupts */ + +#ifdef MY_ABC_HERE + int (*syno_set_blink)(struct ata_port* ap, u32 state); +#endif /* MY_ABC_HERE */ }; struct ahci_host_priv { @@ -444,4 +451,22 @@ static inline int ahci_nr_ports(u32 cap) return (cap & 0x1f) + 1; } +#ifdef MY_ABC_HERE +static inline void __iomem *ahci_host_base(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + return hpriv->mmio; +} +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +/* + * Check PCI vender and device for JMB585, JMB582 + */ +static inline int syno_jmb58x_check(unsigned short vendor, unsigned short device) +{ + return (PCI_VENDOR_ID_JMICRON == vendor && ( 0x0585 == device || 0x0582 == device)) ? 0 : -1; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE|| MY_ABC_HERE */ + #endif /* _AHCI_H */ diff --git a/drivers/ata/ahci_rtk.c b/drivers/ata/ahci_rtk.c new file mode 100644 index 000000000000..48a90596e262 --- /dev/null +++ b/drivers/ata/ahci_rtk.c @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek ahci driver + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ahci.h" + +#define DRV_NAME "rtk_ahci" +#define RTK_SATA_MAX_PORT 2 + +#define REG_CLKEN 0x18 +#define MAC_CLKEN BIT(6) +#define MAC_PORT0_EN BIT(0) | BIT(1) | BIT(2) +#define MAC_PORT1_EN BIT(3) | BIT(4) | BIT(5) + +#define REG_SRAM_CTL3 0xf0 +#define SRAM_SHARE BIT(0) +#define CLEAR_ERR BIT(2) + +enum host_state { + INITIAL = 0, + SUSPEND, + RESUME, + RUNNING +}; + +struct rtk_ahci_port { + struct reset_control *rst; +}; + +struct rtk_ahci_priv { + struct device *dev; + struct ahci_host_priv *hpriv; + struct regmap *wrapper; + struct rtk_ahci_port **ports; + struct delayed_work work; + + enum host_state state; + unsigned int hostinit; +}; + +static const struct ata_port_info ahci_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + +static void rtk_sata_init(struct ahci_host_priv *hpriv, unsigned int port) +{ + struct rtk_ahci_priv *priv = hpriv->plat_data; + + regmap_update_bits(priv->wrapper, REG_CLKEN, MAC_CLKEN, MAC_CLKEN); + + regmap_update_bits(priv->wrapper, REG_SRAM_CTL3, + SRAM_SHARE | CLEAR_ERR, SRAM_SHARE | CLEAR_ERR); + + if (port == 0) + regmap_update_bits(priv->wrapper, REG_CLKEN, + MAC_PORT0_EN , MAC_PORT0_EN); + else + regmap_update_bits(priv->wrapper, REG_CLKEN, + MAC_PORT1_EN , MAC_PORT1_EN); +} + +static int rtk_sata_host_resume(struct rtk_ahci_priv *priv) +{ + struct ata_host *host = dev_get_drvdata(priv->dev); + struct ahci_host_priv *hpriv = host->private_data; + struct ata_port *ap; + int cnt = 0, i; + + for (i = 0; i < hpriv->nports; i++) { + ap = host->ports[i]; + if (ap->link.sata_spd && ap->scsi_host->shost_state == SHOST_RUNNING) + cnt++; + else if (!ap->link.sata_spd) + cnt++; + } + if (cnt < hpriv->nports) + return -1; + + return 0; +} + +static void rtk_sata_host_ctrl(struct work_struct *work) +{ + struct rtk_ahci_priv *priv = container_of(work, struct rtk_ahci_priv, work.work); + struct device *dev = priv->dev; + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + + switch (priv->state) { + case INITIAL: + ahci_platform_init_host(pdev, priv->hpriv, &ahci_port_info, + &ahci_platform_sht); + priv->state = RUNNING; + break; + case RUNNING: + pr_err("host is running\n"); + break; + case RESUME: + if (rtk_sata_host_resume(priv)) + priv->state = RUNNING; + else + schedule_delayed_work(&priv->work, 2*HZ); + break; + case SUSPEND: + default: + dev_err(priv->dev, "state error, do nothing\n"); + break; + } +} + +static int rtk_ahci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *child; + struct ahci_host_priv *hpriv; + struct rtk_ahci_priv *priv; + struct rtk_ahci_port *port; + unsigned int index = 0; + unsigned int portid; + struct gpio_desc *powerio; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + priv->wrapper = syscon_regmap_lookup_by_phandle(node, "realtek,satawrap"); + if (IS_ERR(priv->wrapper)) { + dev_err(dev, "failed to remap sata wrapper reg\n"); + return PTR_ERR(priv->wrapper); + } + + hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + if (hpriv->nports > RTK_SATA_MAX_PORT || hpriv->nports == 0) { + dev_err(dev, "port number can't not support\n"); + return -ENODEV; + } + hpriv->plat_data = priv; + priv->hpriv = hpriv; + + priv->ports = devm_kcalloc(dev, hpriv->nports, sizeof(*priv->ports), GFP_KERNEL); + if (!priv->ports) + return -ENOMEM; + + for_each_available_child_of_node(node, child) { + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + if (of_property_read_u32(child, "reg", &portid)) + if (portid >= RTK_SATA_MAX_PORT) + continue; + + powerio = gpiod_get_from_of_node(child, "sata-gpios", 0, GPIOD_OUT_HIGH, child->name); + if (!IS_ERR(powerio)) { + //gpiod_put(powerio); + } + port->rst = of_reset_control_get_by_index(child, 0); + if (IS_ERR(port->rst)) + return PTR_ERR(port->rst); + reset_control_deassert(port->rst); + + priv->ports[index++] = port; + + rtk_sata_init(hpriv, portid); + } + + ahci_platform_enable_resources(hpriv); + + hpriv->flags |= AHCI_HFLAG_YES_FBS; + writel((readl(hpriv->mmio + HOST_PORTS_IMPL) | 3), + hpriv->mmio + HOST_PORTS_IMPL); + + INIT_DELAYED_WORK(&priv->work, rtk_sata_host_ctrl); + + priv->state = INITIAL; + of_property_read_u32(dev->of_node, "hostinit-mode", &priv->hostinit); + if (priv->hostinit) { + ahci_platform_init_host(pdev, hpriv, &ahci_port_info, + &ahci_platform_sht); + priv->state = RUNNING; + } + + schedule_delayed_work(&priv->work, 1*HZ); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int rtk_ahci_suspend(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + struct rtk_ahci_priv *priv = hpriv->plat_data; + struct device_node *child; + int rc; + struct gpio_desc *powerio; + + cancel_delayed_work(&priv->work); + priv->state = SUSPEND; + + rc = ahci_platform_suspend(dev); + if (rc) + return rc; + + for_each_available_child_of_node(dev->of_node, child) { + powerio = gpiod_get_from_of_node(child, "sata-gpios", 0, GPIOD_OUT_LOW, child->name); + if (!IS_ERR(powerio)) { + gpiod_put(powerio); + } + } + + return 0; +} + +static int rtk_ahci_resume(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + struct rtk_ahci_priv *priv = hpriv->plat_data; + struct device_node *child; + int rc, i; + struct gpio_desc *powerio; + + for (i=0; inports; i++) { + if (priv->ports[i]->rst != NULL) { + reset_control_deassert(priv->ports[i]->rst); + } + rtk_sata_init(hpriv, i); + } + + ahci_platform_enable_resources(hpriv); + + writel((readl(hpriv->mmio + HOST_PORTS_IMPL) | 3), + hpriv->mmio + HOST_PORTS_IMPL); + + rc = ahci_platform_resume_host(dev); + if (rc) + return rc; + + /* We resumed so update PM runtime state */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + for_each_available_child_of_node(dev->of_node, child) { + powerio = gpiod_get_from_of_node(child, "sata-gpios", 0, GPIOD_OUT_HIGH, child->name); + if (!IS_ERR(powerio)) { + gpiod_put(powerio); + } + } + + priv->state = RESUME; + schedule_delayed_work(&priv->work, 3*HZ); + + return 0; +} + +static const struct dev_pm_ops rtk_ahci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rtk_ahci_suspend, rtk_ahci_resume) +}; + +#define DEV_PM_OPS (&rtk_ahci_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +static const struct of_device_id rtk_ahci_of_match[] = { + { .compatible = "realtek,ahci-sata", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtk_ahci_of_match); + +static struct platform_driver rtk_ahci_driver = { + .probe = rtk_ahci_probe, + .driver = { + .name = DRV_NAME, + .of_match_table = rtk_ahci_of_match, + .pm = DEV_PM_OPS, + }, +}; +module_platform_driver(rtk_ahci_driver); + +MODULE_DESCRIPTION("RTK AHCI SATA platform driver"); +MODULE_AUTHOR("Simon Hsu "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ahci"); diff --git a/drivers/ata/ata_syno_i2c.c b/drivers/ata/ata_syno_i2c.c new file mode 100644 index 000000000000..ee359ecf9d20 --- /dev/null +++ b/drivers/ata/ata_syno_i2c.c @@ -0,0 +1,526 @@ +#include +#include +#include +#include +#include +#include +#include + +#define HDDBP_TCA9555_PORT0_PRESENT 0x0 +#define HDDBP_TCA9555_PORT1_PRESENT 0x1 +#define HDDBP_TCA9555_PORT0_ENABLE 0x2 +#define HDDBP_TCA9555_PORT1_ENABLE 0x3 +#define HDDBP_TCA9555_PORT0_CONFIG 0x6 +#define HDDBP_TCA9555_PORT1_CONFIG 0x7 + +#define HDDBP_CPLD_ENABLE 0x10 +#define HDDBP_CPLD_PRESENT 0x20 + +#define HDDBP_MICROP_PORT0_PRESENT 0x0D +#define HDDBP_MICROP_PORT1_PRESENT 0x0E +#define HDDBP_MICROP_PORT2_PRESENT 0x0F +#define HDDBP_MICROP_PORT0_ENABLE 0x1D +#define HDDBP_MICROP_PORT1_ENABLE 0x1E +#define HDDBP_MICROP_PORT2_ENABLE 0x1F + +static struct mutex smbus_hdd_powerctl_mutex_spin; +static DEFINE_MUTEX(smbus_hdd_powerctl_mutex_spin); +extern char gSynoSmbusHddType[16]; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +extern int gSynoSmbusSwitchCount; +extern int gSynoSmbusSwitchAdapters[SMBUS_SWITCH_MAX_COUNT+1]; +extern int gSynoSmbusSwitchAddrs[SMBUS_SWITCH_MAX_COUNT+1]; +extern int gSynoSmbusSwitchVals[SMBUS_SWITCH_MAX_COUNT+1]; + +bool gblIsTca9555Init = false; +bool gbIsTca9555Enabled = false; +static int syno_tca9555_init(int adapter, int address) { + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + + mutex_lock(&smbus_hdd_powerctl_mutex_spin); + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + data.byte = 0xaa; + /*0xaa => clear port0 bit0, 2, 4, 6 as output, bit 1, 3, 5, 7 as input*/ + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_WRITE, HDDBP_TCA9555_PORT0_CONFIG, + I2C_SMBUS_BYTE_DATA, &data); + if (iRet < 0) { + printk(KERN_ERR "i2c_smbus_xfer error: failed to write i2c reg:0x%x\n", HDDBP_TCA9555_PORT0_CONFIG); + goto END; + } + /*0xaa => clear port1 bit0, 2, 4, 6 as output, bit 1, 3, 5, 7 as input*/ + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_WRITE, HDDBP_TCA9555_PORT1_CONFIG, + I2C_SMBUS_BYTE_DATA, &data); + if (iRet < 0) { + printk(KERN_ERR "i2c_smbus_xfer error: failed to write i2c reg:0x%x\n", HDDBP_TCA9555_PORT1_CONFIG); + goto END; + } + + if (iRet >= 0) { + gblIsTca9555Init = true; + } +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + mutex_unlock(&smbus_hdd_powerctl_mutex_spin); + return iRet; +} +/* syno_smbus_hdd_present_read + * Query HDD present check by SMBus. + * output: 1 - present, 0 - not present. + */ +int syno_tca9555_hdd_present_read(int adapter, int address, int index) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + unsigned int iI2c_REG = 0; + unsigned int iBitToAccess = 0; + + if(!gblIsTca9555Init) { + syno_tca9555_init(adapter, address); + } + + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + if (index <= 4) { + iI2c_REG = HDDBP_TCA9555_PORT0_PRESENT; + //disk 0~3 is on port0 + //index is start from 1, so we need -1 + //present is bit 1, 3, 5, 7. so need *2 and + 1 + iBitToAccess = (((index - 1) * 2) + 1); + } else { + iI2c_REG = HDDBP_TCA9555_PORT1_PRESENT; + iBitToAccess = ((((index - 4) - 1) * 2) + 1); + } + + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (iRet < 0) { + printk(KERN_ERR "i2c_smbus_xfer error: failed to read i2c reg:0x%x\n", iI2c_REG); + goto END; + } + + //0 means on + iRet = (data.byte >> iBitToAccess) & 1; +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + /* + * By default present pin is low active, which means 0 is present. + * Also return not present when error occur. + */ + return !iRet; +} + +int syno_tca9555_hdd_enable_read(int adapter, int address, int index) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + unsigned int iI2c_REG = 0; + unsigned int iBitToAccess = 0; + + if(!gblIsTca9555Init) { + syno_tca9555_init(adapter, address); + } + + mutex_lock(&smbus_hdd_powerctl_mutex_spin); + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + if (4 >= index) { + iI2c_REG = HDDBP_TCA9555_PORT0_ENABLE; + //disk 0~3 is on port0 + //index is start from 1, so we need -1 + //enable is bit 0, 2, 4, 6. so need *2 + iBitToAccess = (index - 1) * 2; + } else { + //index 5 is the bit 1 of port0, so we have to minus 4 + iI2c_REG = HDDBP_TCA9555_PORT1_ENABLE; + iBitToAccess = ((index - 4) - 1) * 2; + } + + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk(KERN_ERR "I2C read fail\n"); + goto END; + } + + //bit set = disable, clear = enable + iRet = (data.byte >> iBitToAccess) & 1; + +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + mutex_unlock(&smbus_hdd_powerctl_mutex_spin); + + return !iRet; +} + +int syno_tca9555_hdd_enable_write(int adapter, int address, int index, int val) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + unsigned int iI2c_REG = 0; + unsigned int iBitToAccess = 0; + + if(!gblIsTca9555Init) { + syno_tca9555_init(adapter, address); + } + + mutex_lock(&smbus_hdd_powerctl_mutex_spin); + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + if (index <= 4) { + iI2c_REG = HDDBP_TCA9555_PORT0_ENABLE; + //disk 0~3 is on port0 + //index is start from 1, so we need -1 + //enable is bit 0, 2, 4, 6. so need *2 + iBitToAccess = (index - 1) * 2; + } else { + //index 5 is the bit 1 of port0, so we have to minus 4 + iI2c_REG = HDDBP_TCA9555_PORT1_ENABLE; + iBitToAccess = ((index - 4) - 1) * 2; + } + + //read current enable data from i2c + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk(KERN_ERR "I2C read fail\n"); + goto END; + } + + + //bit set = disable, clear = enable + if (1 == val && ((data.byte >> iBitToAccess) & 1)) { + //if the bit is set, we need to cleart it to enable + data.byte &= ~(1 << iBitToAccess); + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_WRITE, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + } else if (0 == val && !(((data.byte >> iBitToAccess) & 1))){ + data.byte |= 1 << iBitToAccess; + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_WRITE, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + } + if (0 > iRet) { + printk(KERN_ERR "I2C write fail\n"); + } + +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + + mutex_unlock(&smbus_hdd_powerctl_mutex_spin); + return iRet; +} + +int syno_tca9555_hdd_enable_write_all_once(int adapter, int address) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + + if(!gblIsTca9555Init) { + syno_tca9555_init(adapter, address); + } + + mutex_lock(&smbus_hdd_powerctl_mutex_spin); + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + if (!gbIsTca9555Enabled) { + data.byte = 0x00; + + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_WRITE, HDDBP_TCA9555_PORT0_ENABLE, + I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk(KERN_ERR "TCA9555 I2C write port0 fail\n"); + goto END; + } + + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_WRITE, HDDBP_TCA9555_PORT1_ENABLE, + I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk(KERN_ERR "TCA9555 I2C write port1 fail\n"); + goto END; + } + + gbIsTca9555Enabled = true; + } + +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + + mutex_unlock(&smbus_hdd_powerctl_mutex_spin); + return iRet; +} + +/* syno_smbus_hdd_present_read + * Query HDD present check by SMBus. + * output: 1 - present, 0 - not present. + */ +int syno_cpld_hdd_present_read(int adapter, int address, int index) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, HDDBP_CPLD_PRESENT, + I2C_SMBUS_BYTE_DATA, &data); + if (iRet < 0) { + printk(KERN_ERR "i2c_smbus_xfer error: failed to read i2c reg:0x%x\n", HDDBP_CPLD_PRESENT); + goto END; + } + + iRet = (data.byte >> (index -1)) & 1; +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + /* + * By default present pin is low active, which means 0 is present. + * Also return not present when error occur. + */ + return !iRet; +} + +int syno_cpld_hdd_enable_read(int adapter, int address, int index) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + + mutex_lock(&smbus_hdd_powerctl_mutex_spin); + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + //read current enable data from i2c + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, HDDBP_CPLD_ENABLE, + I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + goto END; + } + iRet = (data.byte >> (index -1)) & 1; + +END: + + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + mutex_unlock(&smbus_hdd_powerctl_mutex_spin); + + return iRet; +} + +int syno_microp_hdd_present_read(int adapter, int address, int index) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + unsigned int iI2c_REG = 0; + unsigned int iBitToAccess = 0; + + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + //disk 1 ~ 8 is on port0 + // 9 ~ 16 is on port1 + // 17 ~ 24 is on port2 + if (8 >= index) { + iI2c_REG = HDDBP_MICROP_PORT0_PRESENT; + iBitToAccess = index - 1; + } else if (16 >= index) { + iI2c_REG = HDDBP_MICROP_PORT1_PRESENT; + iBitToAccess = index - 9; + } else { + iI2c_REG = HDDBP_MICROP_PORT2_PRESENT; + iBitToAccess = index - 17; + } + + // read present data from i2c + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (iRet < 0) { + printk(KERN_ERR "i2c_smbus_xfer error: failed to read i2c reg:0x%x\n", iI2c_REG); + goto END; + } + + iRet = (data.byte >> iBitToAccess) & 1; +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + /* + * By default present pin is low active, which means 0 is present. + * Also return not present when error occur. + */ + return !iRet; +} + +int syno_microp_hdd_enable_read(int adapter, int address, int index) +{ + int iRet = -1; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + unsigned int iI2c_REG = 0; + unsigned int iBitToAccess = 0; + + pAdapter = i2c_get_adapter(adapter); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter\n"); + goto END; + } + + //disk 1 ~ 8 is on port0 + // 9 ~ 16 is on port1 + // 17 ~ 24 is on port2 + if (8 >= index) { + iI2c_REG = HDDBP_MICROP_PORT0_ENABLE; + iBitToAccess = index - 1; + } else if (16 >= index) { + iI2c_REG = HDDBP_MICROP_PORT1_ENABLE; + iBitToAccess = index - 9; + } else { + iI2c_REG = HDDBP_MICROP_PORT2_ENABLE; + iBitToAccess = index - 17; + } + + //read current enable data from i2c + iRet = i2c_smbus_xfer(pAdapter, address, 0, + I2C_SMBUS_READ, iI2c_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + goto END; + } + iRet = (data.byte >> iBitToAccess) & 1; + +END: + + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + + return iRet; +} + +void syno_smbus_switch_config(void) +{ + int iRet = -1; + int i; + union i2c_smbus_data data; + struct i2c_adapter *pAdapter = NULL; + + mutex_lock(&smbus_hdd_powerctl_mutex_spin); + if(0 == gSynoSmbusSwitchCount) { + // some model need not to config + goto END; + } + for (i = 0;i < gSynoSmbusSwitchCount;i++){ + if(0 == gSynoSmbusSwitchAddrs[i]) { + // some model need not to config + printk(KERN_ERR "gSynoSmbusSwitchAddrs[%d] is 0. End the switch process\n", i); + goto END; + } + + pAdapter = i2c_get_adapter(gSynoSmbusSwitchAdapters[i]); + if (NULL == pAdapter) { + printk(KERN_ERR "I2C initial error: failed to get i2c adapter from gSynoSmbusSwitchAdapters[%d], %d\n", + i, gSynoSmbusSwitchAdapters[i] + ); + goto END; + } + + memset(&data, 0, sizeof(data)); + iRet = i2c_smbus_xfer(pAdapter, gSynoSmbusSwitchAddrs[i], 0, + I2C_SMBUS_WRITE, gSynoSmbusSwitchVals[i], + I2C_SMBUS_BYTE, &data); + if (0 > iRet) { + printk(KERN_ERR "I2C write 0x%2x to 0x%2x fail\n", gSynoSmbusSwitchVals[i], gSynoSmbusSwitchAddrs[i]); + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + goto END; + } + // release the pAdapter + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + } +END: + mutex_unlock(&smbus_hdd_powerctl_mutex_spin); +} + +void syno_smbus_hdd_powerctl_init(void){ + syno_smbus_switch_config(); + if(0 == strncmp(gSynoSmbusHddType, "tca9555", strlen("tca9555"))){ + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write=syno_tca9555_hdd_enable_write; + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read=syno_tca9555_hdd_enable_read; + SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read=syno_tca9555_hdd_present_read; + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write_all_once=syno_tca9555_hdd_enable_write_all_once; + } else if (0 == strncmp(gSynoSmbusHddType, "cpld", strlen("cpld"))){ + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write=NULL; + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read=syno_cpld_hdd_enable_read; + SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read=syno_cpld_hdd_present_read; + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write_all_once=NULL; + } else if (0 == strncmp(gSynoSmbusHddType, "microp", strlen("microp"))){ + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write=NULL; + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read=syno_microp_hdd_enable_read; + SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read=syno_microp_hdd_present_read; + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write_all_once=NULL; + } + SynoSmbusHddPowerCtl.bl_init = 1; +} +EXPORT_SYMBOL(syno_smbus_hdd_powerctl_init); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index fec2e9754aed..f45ba11510b0 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * libahci.c - Common AHCI SATA low-level routines @@ -31,6 +34,22 @@ #include #include "ahci.h" #include "libata.h" +#if defined(MY_ABC_HERE) || defined(MY_DEF_HERE) +#include +#endif /* MY_ABC_HERE || MY_DEF_HERE */ +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +#define SYNO_LED_BLINK_OFF 0 +#define SYNO_LED_BLINK_ON 1 +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void syno_ledtrig_active_set(int iLedNum); +extern int *gpGreenLedMap; +#endif /* SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER */ static int ahci_skip_host_reset; int ahci_ignore_sss; @@ -100,6 +119,23 @@ static ssize_t ahci_show_em_supported(struct device *dev, struct device_attribute *attr, char *buf); static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance); +#ifdef MY_ABC_HERE +static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance); +static irqreturn_t syno_ahci_multi_irqs_intr_hard_jmb(int irq, void *dev_instance); +static irqreturn_t (*syno_ahci_multi_irqs_intr)(int, void *); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void syno_internal_ahci_handle_port_interrupt(struct ata_port *ap, + void __iomem *port_mmio, u32 status); +static void ahci_handle_port_interrupt(struct ata_port *ap, + void __iomem *port_mmio, u32 status); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void syno_ahci_force_intr(struct ata_port *ap); +#endif /* MY_ABC_HERE */ + static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); @@ -118,6 +154,22 @@ struct device_attribute *ahci_shost_attrs[] = { &dev_attr_ahci_port_cmd, &dev_attr_em_buffer, &dev_attr_em_message_supported, +#ifdef MY_ABC_HERE + &dev_attr_syno_sata_disk_led_ctrl, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_manutil_power_disable, + &dev_attr_syno_pm_gpio, + &dev_attr_syno_pm_info, + &dev_attr_syno_pm_i2c, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_power_ctrl, + &dev_attr_syno_pm_control_support, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_port_thaw, +#endif /* MY_ABC_HERE */ NULL }; EXPORT_SYMBOL_GPL(ahci_shost_attrs); @@ -125,7 +177,29 @@ EXPORT_SYMBOL_GPL(ahci_shost_attrs); struct device_attribute *ahci_sdev_attrs[] = { &dev_attr_sw_activity, &dev_attr_unload_heads, +#ifdef MY_ABC_HERE + &dev_attr_syno_wcache, +#endif /* MY_ABC_HERE */ &dev_attr_ncq_prio_enable, +#ifdef MY_ABC_HERE + &dev_attr_syno_deep_sleep_support, + &dev_attr_syno_deep_sleep_ctrl, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_disk_latency_read_hist, + &dev_attr_syno_disk_latency_write_hist, + &dev_attr_syno_disk_latency_other_hist, + &dev_attr_syno_disk_latency_stat, +#ifdef MY_ABC_HERE + &dev_attr_syno_disk_seq_stat, +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_pwr_reset_count, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_sata_error_event_debug, +#endif /* MY_ABC_HERE */ NULL }; EXPORT_SYMBOL_GPL(ahci_sdev_attrs); @@ -165,6 +239,9 @@ struct ata_port_operations ahci_ops = { #endif .port_start = ahci_port_start, .port_stop = ahci_port_stop, +#ifdef MY_ABC_HERE + .syno_recover = syno_ahci_force_intr, +#endif /* MY_ABC_HERE */ }; EXPORT_SYMBOL_GPL(ahci_ops); @@ -841,6 +918,114 @@ static void ahci_power_down(struct ata_port *ap) } #endif +#ifdef MY_ABC_HERE +/** + * syno_need_ahci_software_activity - Get Extended AHCI attributes + named sw_activity + * @ap: target ata port + * + * The implementation reads extended AHCI attributes + * This function aims to replace hard-coded model check of + * syno_need_ahci_software_activity but not limited to it. + * + * RETURNS: + * 0 if not found or failed, else returns sw_activity value. + */ +static int syno_need_ahci_software_activity(struct ata_port* ap) +{ + struct device_node *pSlotNode = NULL; + struct device_node *pAhciNode = NULL; + int sw_activity = 0; /* Do NOT set software activity by default */ + + if (!ap) { + goto Err; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (ap->ops->syno_compare_node_info(ap, pSlotNode)) { + break; + } + } + + if (!pSlotNode) { + printk(KERN_ERR "Cannot find slot node of this ata_port.\n"); + goto Err; + } + + pAhciNode = of_get_child_by_name(pSlotNode, DT_AHCI); + of_node_put(pSlotNode); + if (!pAhciNode) { + printk(KERN_WARNING "No AHCI child node.\n"); + goto Err; + } + + if (of_property_read_u32(pAhciNode, DT_PROPERTY_SW_ACTIVITY, &sw_activity)) { + sw_activity = 0; /* Do NOT set software activity if NOT found */ + } + of_node_put(pAhciNode); + +Err: + return sw_activity; +} + +int __syno_ahci_disk_led_enable(struct ata_port *ap, const int iValue) +{ + int ret = -EINVAL; + struct ahci_port_priv *pp = NULL; + struct ahci_em_priv *emp = NULL; + struct ata_link *link = NULL; + unsigned long flags; + + if (NULL == ap) { + goto ERROR; + } + + // del old timer + pp = ap->private_data; + spin_lock_irqsave(ap->lock, flags); + ata_for_each_link(link, ap, EDGE) { + emp = &pp->em_priv[link->pmp]; + emp->saved_activity = emp->activity = 0; + del_timer(&emp->timer); + } + + if (iValue) { + ap->flags |= ATA_FLAG_SW_ACTIVITY; + ata_for_each_link(link, ap, EDGE) { + ahci_init_sw_activity(link); + } + } else { + ap->flags &= ~ATA_FLAG_SW_ACTIVITY; + ata_for_each_link(link, ap, EDGE) { + link->flags &= ~ATA_LFLAG_SW_ACTIVITY; + } + } + spin_unlock_irqrestore(ap->lock, flags); + ret = 0; + +ERROR: + return ret; +} + +extern struct ata_port *syno_ata_port_get_by_port(const unsigned short diskPort); +/** + * This function is used for AHCI software activity led by disk port. + * Disk port would be remapped to scsi host number. + * + * @param diskPort [IN] is disk port index + * @param iValue [IN] is the value going to set. + */ +int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue) +{ + struct ata_port *ap = NULL; + + ap = syno_ata_port_get_by_port(diskPort); + + return __syno_ahci_disk_led_enable(ap, iValue); +} +EXPORT_SYMBOL(syno_ahci_disk_led_enable_by_port); +#endif /* MY_ABC_HERE */ + static void ahci_start_port(struct ata_port *ap) { struct ahci_host_priv *hpriv = ap->host->private_data; @@ -883,6 +1068,12 @@ static void ahci_start_port(struct ata_port *ap) } } +#ifdef MY_ABC_HERE + if (syno_need_ahci_software_activity(ap)) { + ap->flags |= ATA_FLAG_SW_ACTIVITY; + } +#endif /* MY_ABC_HERE */ + if (ap->flags & ATA_FLAG_SW_ACTIVITY) ata_for_each_link(link, ap, EDGE) ahci_init_sw_activity(link); @@ -927,6 +1118,9 @@ int ahci_reset_controller(struct ata_host *host) tmp = readl(mmio + HOST_CTL); if ((tmp & HOST_RESET) == 0) { writel(tmp | HOST_RESET, mmio + HOST_CTL); +#ifdef MY_DEF_HERE + udelay(1); +#endif /* MY_DEF_HERE */ readl(mmio + HOST_CTL); /* flush */ } @@ -974,6 +1168,218 @@ static void ahci_sw_activity(struct ata_link *link) mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10)); } +#ifdef MY_ABC_HERE +static int syno_sw_activity(struct ata_port* ap, u32 state) +{ + /* Doesn't initialized */ + if (NULL == gpGreenLedMap) { + return 0; + } + + /* Do nothing when SYNO_LED_BLINK_OFF */ + if (SYNO_LED_BLINK_OFF == state) { + return 0; + } + + syno_ledtrig_active_set(gpGreenLedMap[ap->syno_internal_slot_index]); + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +static int sw_activity_by_ledtrig_disk_syno(struct ata_port* ap, u32 state) +{ + int ret = -EINVAL; + struct device_node *pSlotNode = NULL; + struct device_node *pLedNode = NULL; + struct led_classdev *led_cdev = NULL; + + if (!ap) { + goto Err; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (ap->ops->syno_compare_node_info(ap, pSlotNode)) { + break; + } + } + if (!pSlotNode) { + goto Err; + } + + pLedNode = of_parse_phandle(pSlotNode, DT_HDD_GREEN_LED, 0); + of_node_put(pSlotNode); + if (!pLedNode) { + goto Err; + } + + led_cdev = of_leddev_get(pLedNode); + of_node_put(pLedNode); + if (IS_ERR(led_cdev)) { + goto Err; + } + + if (SYNO_LED_BLINK_ON == state) { + ledtrig_syno_disk_activity_on(led_cdev); + } + + ret = 0; + +Err: + return ret; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +/** + * syno_set_blink_gpio - Set led-blinking state of given ata port + * @ap: target ata port + * @state: 0 for SYNO_LED_BLINK_OFF; 1 for SYNO_LED_BLINK_ON + * + * The implementation reads information of pin from device tree, and + * set it by input state. + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int syno_set_blink_gpio(struct ata_port* ap, u32 state) +{ + int ret = -EINVAL; + struct device_node *pSlotNode = NULL; + struct device_node *pLedNode = NULL; + u32 pinInfo[SYNO_GPIO_INDEX_MAX] = {0}; + + if (!ap) { + goto Err; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (ap->ops->syno_compare_node_info(ap, pSlotNode)) { + break; + } + } + if (!pSlotNode) { + printk(KERN_ERR "Cannot find slot node of this ata_port.\n"); + goto Err; + } + + pLedNode = of_get_child_by_name(pSlotNode, DT_HDD_ACT_LED); + of_node_put(pSlotNode); + if (!pLedNode) { + printk(KERN_WARNING "No ACT LED pin.\n"); + goto Err; + } + + if (of_property_read_u32_array(pLedNode, DT_SYNO_GPIO, pinInfo, SYNO_GPIO_INDEX_MAX)) { + printk(KERN_ERR "Cannot find pin information.\n"); + goto Err; + } + of_node_put(pLedNode); + + if (pinInfo[SYNO_POLARITY_PIN] == state) { + SYNO_GPIO_WRITE(pinInfo[SYNO_GPIO_PIN], 1); + } else { + SYNO_GPIO_WRITE(pinInfo[SYNO_GPIO_PIN], 0); + } + ret = 0; + +Err: + return ret; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static void syno_setup_blink_method(struct ata_port* ap) +{ + struct ahci_port_priv *pp = ap->private_data; + struct device_node *slot_node = NULL; + const char *led_type = NULL; + + /* Default not implement */ + pp->syno_set_blink = NULL; + + for_each_child_of_node(of_root, slot_node) { + if (ap->ops->syno_compare_node_info(ap, slot_node)) { + break; + } + } + if (!slot_node) { + goto END; + } + + of_property_read_string(slot_node, DT_HDD_LED_TYPE, &led_type); + of_node_put(slot_node); + +#ifdef MY_ABC_HERE + if ((0 == strcmp(led_type, DT_HDD_LED_TYPE_LP3943)) || (0 == strcmp(led_type, DT_HDD_LED_TYPE_ATMEGA1608))) { + pp->syno_set_blink = &syno_sw_activity; + goto END; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + if (0 == strcmp(led_type, DT_HDD_LED_TYPE_GPIO)) { + pp->syno_set_blink = &syno_set_blink_gpio; + goto END; + } +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE + if (0 == strcmp(led_type, DT_HDD_LED_TYPE_TRIG_DISK_SYNO)) { + pp->syno_set_blink = &sw_activity_by_ledtrig_disk_syno; + goto END; + } +#endif /* MY_DEF_HERE */ + +END: + return; +} + +static void syno_ahci_sw_activity_blink(struct timer_list *t) +{ + struct ahci_em_priv *emp = from_timer(emp, t, timer); + struct ata_port *ap = emp->link->ap; + struct ahci_port_priv *pp = ap->private_data; + unsigned long flags; + struct Scsi_Host *shost; + struct scsi_device *sdev; + + shost = scsi_host_get(ap->scsi_host); + + if (NULL == shost) { + goto DO_NOTHING; + } + list_for_each_entry(sdev, &shost->__devices, siblings) { + goto DO_BLINK; + } + goto DO_NOTHING; + +DO_BLINK: + /* check to see if we've had activity. If so, + * toggle state of LED and reset timer. If not, + * turn LED to desired idle state. + */ + if (!pp->syno_set_blink) { + goto DO_NOTHING; + } + + spin_lock_irqsave(ap->lock, flags); + if (emp->saved_activity != emp->activity) { + emp->saved_activity = emp->activity; + + /* toggle state */ + pp->syno_set_blink(ap, SYNO_LED_BLINK_ON); + mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100)); + } else { + pp->syno_set_blink(ap, SYNO_LED_BLINK_OFF); + } + spin_unlock_irqrestore(ap->lock, flags); + +DO_NOTHING: + return; +} +#else /* !MY_ABC_HERE */ static void ahci_sw_activity_blink(struct timer_list *t) { struct ahci_em_priv *emp = from_timer(emp, t, timer); @@ -1017,6 +1423,7 @@ static void ahci_sw_activity_blink(struct timer_list *t) spin_unlock_irqrestore(ap->lock, flags); ap->ops->transmit_led_message(ap, led_message, 4); } +#endif /* MY_ABC_HERE */ static void ahci_init_sw_activity(struct ata_link *link) { @@ -1027,11 +1434,19 @@ static void ahci_init_sw_activity(struct ata_link *link) /* init activity stats, setup timer */ emp->saved_activity = emp->activity = 0; emp->link = link; + +#ifdef MY_ABC_HERE + syno_setup_blink_method(ap); + + timer_setup(&emp->timer, syno_ahci_sw_activity_blink, 0); + link->flags |= ATA_LFLAG_SW_ACTIVITY; +#else /* MY_ABC_HERE */ timer_setup(&emp->timer, ahci_sw_activity_blink, 0); /* check our blink policy and set flag for link if it's enabled */ if (emp->blink_policy) link->flags |= ATA_LFLAG_SW_ACTIVITY; +#endif /* MY_ABC_HERE */ } int ahci_reset_em(struct ata_host *host) @@ -1239,6 +1654,9 @@ void ahci_init_controller(struct ata_host *host) int i; void __iomem *port_mmio; u32 tmp; +#ifdef MY_ABC_HERE + struct pci_dev *pdev = NULL; +#endif /* MY_ABC_HERE */ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; @@ -1249,6 +1667,14 @@ void ahci_init_controller(struct ata_host *host) ahci_port_init(host->dev, ap, i, mmio, port_mmio); } +#ifdef MY_ABC_HERE + pdev = to_pci_dev(host->dev); + if (0 == syno_jmb58x_check(pdev->vendor, pdev->device)) { + syno_ahci_multi_irqs_intr = &syno_ahci_multi_irqs_intr_hard_jmb; + } else { + syno_ahci_multi_irqs_intr = &ahci_multi_irqs_intr_hard; + } +#endif /* MY_ABC_HERE */ tmp = readl(mmio + HOST_CTL); VPRINTK("HOST_CTL 0x%x\n", tmp); @@ -1462,6 +1888,18 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, fail: ata_link_err(link, "softreset failed (%s)\n", reason); +#ifdef MY_ABC_HERE + if (-EBUSY == rc) { + ata_link_printk(link, KERN_ERR, "SRST fail, set srst fail flag\n"); + link->uiSflags |= ATA_SYNO_FLAG_SRST_FAIL; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* re-enable FBS if disabled before */ + if (fbs_disabled) + ahci_enable_fbs(ap); +#endif /* MY_ABC_HERE */ return rc; } @@ -1693,6 +2131,40 @@ static void ahci_fbs_dec_intr(struct ata_port *ap) dev_err(ap->host->dev, "failed to clear device error\n"); } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +static int irqoff_error_case (struct ata_port *ap, u32 irq_stat) +{ +#ifdef MY_ABC_HERE + /* Only support deep sleep port, we can on ATA_PFLAG_SYNO_IRQ_OFF. + * So if this case happened, we should BUG */ + if (0 == iIsSynoDeepSleepSupport(ap) && !(ap->pflags & ATA_PFLAG_SYNO_DS_PWROFF)) { + printk("BUG!!! This port %d didn't support deep sleep\n", ap->print_id); + ap->pflags &= ~ATA_PFLAG_SYNO_IRQ_OFF; + return 1; + } +#endif /* MY_ABC_HERE */ + + /* unknown & suprise interrupt */ + if (!(irq_stat & (PORT_IRQ_PHYRDY | PORT_IRQ_CONNECT))) { + printk("WARNING: disk %d irq off but received un-wanted interrupts, reset now. irq_stat 0x%x\n", + ap->print_id, irq_stat); + + return 1; + } + + /* NOTE the caller must make sure, can on irq_off, so we just WARN_ON here. And still + * let this interrupt ignore */ + if (ap->nr_active_links && !(ap->pflags & ATA_PFLAG_SYNO_DS_PWROFF)) { + printk("WARNING: disk %d irq off but still have cmd. Reset now. irq_stat 0x%x\n", + ap->print_id, irq_stat); + + return 1; + } + + return 0; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { struct ahci_host_priv *hpriv = ap->host->private_data; @@ -1727,14 +2199,40 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) active_ehi = &link->eh_info; /* record irq stat */ + +#ifdef MY_ABC_HERE + // ('\0' != host_ehi->desc[0]) is true when there is unhandle message is desc + // JMB585 raises BAD_PMP following a IFS sometimes and the IFS msg will be overwritten by BAD_PMP + if (unlikely((0 == syno_jmb58x_check(ap->host->vendor, ap->host->device)) + && (irq_stat & PORT_IRQ_BAD_PMP) && ('\0' != host_ehi->desc[0]))) { + irq_stat &= ~PORT_IRQ_BAD_PMP; + } else { + ata_ehi_clear_desc(host_ehi); + ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); + } +#else /* MY_ABC_HERE */ ata_ehi_clear_desc(host_ehi); ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); +#endif /* MY_ABC_HERE */ /* AHCI needs SError cleared; otherwise, it might lock up */ ahci_scr_read(&ap->link, SCR_ERROR, &serror); ahci_scr_write(&ap->link, SCR_ERROR, serror); host_ehi->serror |= serror; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + /* irq_off case */ + if (ap->pflags & ATA_PFLAG_SYNO_IRQ_OFF) { + /* Skip interrupt handler if no suprise */ + if (irqoff_error_case(ap, irq_stat)) { + WARN_ON(1); + host_ehi->action |= ATA_EH_RESET; + } else { + return; + } + } +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + /* some controllers set IRQ_IF_ERR on device errors, ignore it */ if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) irq_stat &= ~PORT_IRQ_IF_ERR; @@ -1782,11 +2280,32 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) host_ehi->err_mask |= AC_ERR_ATA_BUS; host_ehi->action |= ATA_EH_RESET; } - +#ifdef MY_ABC_HERE + // if IFS and Proto error exist, we use workaround to check for the real error. + // The workaround only works for the first attempt. + if (unlikely(0 == syno_jmb58x_check(ap->host->vendor, ap->host->device) && // only JMB585 workaround + (PORT_IRQ_IF_ERR & irq_stat) && (SERR_PROTOCOL & host_ehi->serror) && ATA_EH_MAX_TRIES == ap->eh_tries)) { + if (fbs_need_dec) { + irq_stat &= ~PORT_IRQ_IF_ERR; + active_ehi->uiJM585DubiosIFSProtoFlag |= ATA_SYNO_FLAG_JM585_READ_LOG; + } else { + host_ehi->uiJM585DubiosIFSProtoFlag |= ATA_SYNO_FLAG_JM585_READ_LOG; + } + } +#endif /* MY_ABC_HERE */ ata_ehi_push_desc(host_ehi, "interface fatal error"); } if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { +#ifdef MY_ABC_HERE + if (irq_stat & PORT_IRQ_CONNECT) { + ap->pflags |= ATA_PFLAG_SYNO_BOOT_PROBE; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_ata_detection_info_print(ap); +#endif /* MY_ABC_HERE */ + ata_ehi_hotplugged(host_ehi); ata_ehi_push_desc(host_ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? @@ -1829,6 +2348,25 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, } if (status & PORT_IRQ_SDB_FIS) { +#ifdef MY_ABC_HERE + if (ap->pflags & ATA_PFLAG_SYNO_IRQ_OFF) { + /* irq_off case */ + u32 sntf = 0; + sntf = readl(port_mmio + PORT_SCR_NTF); + if (sntf & (1<< SATA_PMP_CTRL_PORT)) { + if (status & (PORT_IRQ_PHYRDY | PORT_IRQ_CONNECT)) { + /* NOTE the caller must make sure, can on irq_off, so we just WARN_ON here. + * The following action is call sata_async_notification() + * and it will call EH. + */ + printk("WARNING: pmp disk %d irq off but still have cmd. Reset now. irq_stat 0x%x\n", + ap->print_id, status); + ap->pflags &= ~ATA_PFLAG_SYNO_IRQ_OFF; + } + } + } +#endif /* MY_ABC_HERE */ + /* If SNotification is available, leave notification * handling to sata_async_notification(). If not, * emulate it by snooping SDB FIS RX area. @@ -1888,6 +2426,59 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, } } +#ifdef MY_ABC_HERE +static void syno_internal_ahci_handle_port_interrupt(struct ata_port *ap, + void __iomem *port_mmio, u32 status) +{ + struct ata_eh_info *ehi = &ap->link.eh_info; + struct ahci_port_priv *pp = ap->private_data; + int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); + u32 qc_active = 0; + int rc; + + /* ignore BAD_PMP while resetting */ + if (unlikely(resetting)) + status &= ~PORT_IRQ_BAD_PMP; + + if (sata_lpm_ignore_phy_events(&ap->link)) { + status &= ~PORT_IRQ_PHYRDY; + ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); + } + + if (unlikely(status & PORT_IRQ_ERROR)) { + ahci_error_intr(ap, status); + return; + } + + /* pp->active_link is not reliable once FBS is enabled, both + * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because + * NCQ and non-NCQ commands may be in flight at the same time. + */ + if (pp->fbs_enabled) { + if (ap->qc_active) { + qc_active = readl(port_mmio + PORT_SCR_ACT); + qc_active |= readl(port_mmio + PORT_CMD_ISSUE); + } + } else { + /* pp->active_link is valid iff any command is in flight */ + if (ap->qc_active && pp->active_link->sactive) + qc_active = readl(port_mmio + PORT_SCR_ACT); + else + qc_active = readl(port_mmio + PORT_CMD_ISSUE); + } + + + rc = ata_qc_complete_multiple(ap, qc_active); + + /* while resetting, invalid completions are expected */ + if (unlikely(rc < 0 && !resetting)) { + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_RESET; + ata_port_freeze(ap); + } +} +#endif /* MY_ABC_HERE */ + static void ahci_port_intr(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); @@ -1896,9 +2487,63 @@ static void ahci_port_intr(struct ata_port *ap) status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); - ahci_handle_port_interrupt(ap, port_mmio, status); +#ifdef MY_ABC_HERE + if (likely(ap->syno_ahci_handle_port_interrupt)) { + ap->syno_ahci_handle_port_interrupt(ap, port_mmio, status); + } +#else /* MY_ABC_HERE */ + ahci_handle_port_interrupt(ap, port_mmio, status); +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +static void syno_ahci_force_intr(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + u32 status; + + ata_port_err(ap, "do detect tries %d\n", ap->syno_recover_tries); + + status = readl(port_mmio + PORT_IRQ_STAT); + writel(status, port_mmio + PORT_IRQ_STAT); + + if (sata_lpm_ignore_phy_events(&ap->link)) { + status &= ~PORT_IRQ_PHYRDY; + ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); + } + + ahci_error_intr(ap, status); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static irqreturn_t syno_ahci_multi_irqs_intr_hard_jmb(int irq, void *dev_instance) +{ + struct ata_port *ap = dev_instance; + void __iomem *port_mmio = ahci_port_base(ap); + u32 status; + + VPRINTK("ENTER\n"); + + status = readl(port_mmio + PORT_IRQ_STAT); + writel(status & ~(PORT_IRQ_PHYRDY | PORT_IRQ_CONNECT), port_mmio + PORT_IRQ_STAT); + + spin_lock(ap->lock); +#ifdef MY_ABC_HERE + if (likely(ap->syno_ahci_handle_port_interrupt)) { + ap->syno_ahci_handle_port_interrupt(ap, port_mmio, status); + } +#else /* MY_ABC_HERE */ + ahci_handle_port_interrupt(ap, port_mmio, status); +#endif /* MY_ABC_HERE */ + spin_unlock(ap->lock); + + VPRINTK("EXIT\n"); + + return IRQ_HANDLED; +} +#endif /* MY_ABC_HERE */ + static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance) { struct ata_port *ap = dev_instance; @@ -1911,7 +2556,13 @@ static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance) writel(status, port_mmio + PORT_IRQ_STAT); spin_lock(ap->lock); +#ifdef MY_ABC_HERE + if (likely(ap->syno_ahci_handle_port_interrupt)) { + ap->syno_ahci_handle_port_interrupt(ap, port_mmio, status); + } +#else /* MY_ABC_HERE */ ahci_handle_port_interrupt(ap, port_mmio, status); +#endif /* MY_ABC_HERE */ spin_unlock(ap->lock); VPRINTK("EXIT\n"); @@ -2073,7 +2724,13 @@ void ahci_error_handler(struct ata_port *ap) { struct ahci_host_priv *hpriv = ap->host->private_data; +#ifdef MY_ABC_HERE + struct ata_eh_context *host_ehc = &ap->link.eh_context; + // the work around need to thaw the ata port for reading ncq log + if (!(ap->pflags & ATA_PFLAG_FROZEN) || host_ehc->i.uiJM585DubiosIFSProtoFlag) { +#else /* MY_ABC_HERE */ if (!(ap->pflags & ATA_PFLAG_FROZEN)) { +#endif /* MY_ABC_HERE */ /* restart engine */ hpriv->stop_engine(ap); hpriv->start_engine(ap); @@ -2559,7 +3216,12 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, continue; } - rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard, + rc = devm_request_irq(host->dev, irq, +#ifdef MY_ABC_HERE + syno_ahci_multi_irqs_intr, +#else /* MY_ABC_HERE */ + ahci_multi_irqs_intr_hard, +#endif /* MY_ABC_HERE */ 0, pp->irq_desc, host->ports[i]); if (rc) @@ -2570,6 +3232,53 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, return ata_host_register(host, sht); } +#ifdef MY_ABC_HERE +static bool syno_internal_slot_check(struct ata_port* ap) +{ + struct device_node *pSlotNode = NULL; + struct device_node *pAhciNode = NULL; + bool blRet = false; + int index = 0; + + if (!ap) { + goto END; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (ap->ops->syno_compare_node_info(ap, pSlotNode)) { + break; + } + } + + if (!pSlotNode) { + goto END; + } + + if (pSlotNode->full_name && 1 == sscanf(pSlotNode->full_name, DT_INTERNAL_SLOT"@%d", &index)) { + /* + * At first, we only apply internal slot mode on those models which have "internal_mode" attr in dts + * If we want to apply to all ahci models one day, just remove the comparison as below + */ + if (NULL == (pAhciNode = of_get_child_by_name(pSlotNode, DT_AHCI))) { + goto END; + } + if (of_property_read_bool(pAhciNode, DT_AHCI_INTERNAL_MODE)) { + blRet = true; + goto END; + } + } + +END: + if (pAhciNode) { + of_node_put(pAhciNode); + } + if (pSlotNode) { + of_node_put(pSlotNode); + } + return blRet; +} +#endif /* MY_ABC_HERE */ + /** * ahci_host_activate - start AHCI host, request IRQs and register it * @host: target ATA host @@ -2586,6 +3295,10 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) struct ahci_host_priv *hpriv = host->private_data; int irq = hpriv->irq; int rc; +#ifdef MY_ABC_HERE + int i = 0; + struct ata_port *ap = NULL; +#endif /* MY_ABC_HERE */ if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) { if (hpriv->irq_handler && @@ -2604,6 +3317,16 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) IRQF_SHARED, sht); } +#ifdef MY_ABC_HERE + for (i = 0; i < host->n_ports; i++) { + ap = host->ports[i]; + if (syno_internal_slot_check(ap)) { + ap->syno_ahci_handle_port_interrupt = &syno_internal_ahci_handle_port_interrupt; + } else { + ap->syno_ahci_handle_port_interrupt = &ahci_handle_port_interrupt; + } + } +#endif /* MY_ABC_HERE */ return rc; } diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index b2f552088291..8284af3647d6 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * AHCI SATA platform library @@ -556,6 +559,41 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(ahci_platform_get_resources); +#ifdef MY_ABC_HERE + +extern int lookup_internal_slot(const struct ata_port *ap); +extern int syno_compare_dts_ata_port(const struct ata_port *pAtaPort, const struct device_node *pDeviceNode); +/** + * syno_ahci_compare_ata_devicetree_info - check the ata_port matches the device_node + * @ap [IN]: query ata_port + * @node [IN]: comparing device_node + * + * return true: success + false: fail + */ +bool syno_ahci_rtk_compare_ata_devicetree_info(const struct ata_port *ap, const struct device_node *pNode) +{ + int ret = false; + struct device_node *pAhciNode = NULL; + if (NULL == ap || NULL == pNode) { + goto END; + } + + pAhciNode = of_get_child_by_name(pNode, DT_RTK_AHCI); + if (0 != syno_compare_dts_ata_port(ap, pAhciNode)) { + goto END; + } + + ret = true; +END: + if (pAhciNode) { + of_node_put(pAhciNode); + } + + return ret; +} +#endif /* MY_ABC_HERE */ + /** * ahci_platform_init_host - Bring up an ahci-platform host * @pdev: platform device pointer for the host @@ -640,6 +678,12 @@ int ahci_platform_init_host(struct platform_device *pdev, /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) ap->ops = &ata_dummy_port_ops; +#ifdef MY_ABC_HERE + /* FIXME: add check if using ahci_rtk before assigning syno_ahci_rtk_compare_ata_devicetree_info */ + ap->ops->syno_compare_node_info = syno_ahci_rtk_compare_ata_devicetree_info; + /* Fill internal slot index. 0 base, < 0 means error or not internal slot */ + ap->syno_internal_slot_index = lookup_internal_slot(ap) - 1; +#endif /* MY_ABC_HERE */ } if (hpriv->cap & HOST_CAP_64) { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 61c762961ca8..5fc0d0682258 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * libata-core.c - helper library for ATA @@ -58,6 +61,27 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +/* Power control via GPIO */ +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE*/ + +#if defined(MY_DEF_HERE) || defined(MY_ABC_HERE) +#include +#endif /* MY_DEF_HERE) || defined(MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #define CREATE_TRACE_POINTS #include @@ -70,6 +94,9 @@ const struct ata_port_operations ata_base_port_ops = { .error_handler = ata_std_error_handler, .sched_eh = ata_std_sched_eh, .end_eh = ata_std_end_eh, +#ifdef MY_ABC_HERE + .syno_recover = NULL, +#endif /* MY_ABC_HERE */ }; const struct ata_port_operations sata_port_ops = { @@ -80,6 +107,11 @@ const struct ata_port_operations sata_port_ops = { }; EXPORT_SYMBOL_GPL(sata_port_ops); +#ifdef MY_ABC_HERE +struct klist syno_ata_port_head; +EXPORT_SYMBOL(syno_ata_port_head); +#endif /* MY_ABC_HERE */ + static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -88,6 +120,11 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev); atomic_t ata_print_id = ATOMIC_INIT(0); +#ifdef MY_ABC_HERE +extern unsigned int SynoDiskSeqValidBytesThreshold; +extern unsigned int SynoDiskSeqValidSkipBytes; +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_ATA_FORCE struct ata_force_param { const char *name; @@ -126,7 +163,12 @@ int atapi_passthru16 = 1; module_param(atapi_passthru16, int, 0444); MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])"); +#ifdef MY_ABC_HERE +int libata_fua = 1; +#else /* MY_ABC_HERE */ int libata_fua = 0; +#endif /* MY_ABC_HERE */ + module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)"); @@ -279,6 +321,27 @@ struct ata_device *ata_dev_next(struct ata_device *dev, struct ata_link *link, } EXPORT_SYMBOL_GPL(ata_dev_next); +#ifdef MY_ABC_HERE +unsigned int uiCheckPortLinksFlags(struct ata_port *pAp) { + struct ata_link *pLink = NULL; + unsigned int uiFlags = 0x0; + + if (!pAp) { + goto END; + } + + ata_for_each_link(pLink, pAp, EDGE) { + if (pLink->uiSflags) { + ata_link_printk(pLink, KERN_ERR, "get error flags 0x%x\n", pLink->uiSflags); + uiFlags |= pLink->uiSflags; + } + } + +END: + return uiFlags; +} +#endif /* MY_ABC_HERE */ + /** * ata_dev_phys_link - find physical link for a device * @dev: ATA device to look up physical link for @@ -1573,12 +1636,24 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, } } +#ifdef MY_ABC_HERE + /* ATA_PFLAG_PMP_PMCTL means we are injecting ata cmd during eh, don't release the oringal one's. */ + /* JMB575 control commnads do not need to deal with eh lock */ + if (ap->ops->error_handler && !(ap->pflags & ATA_PFLAG_PMP_PMCTL)) +#else /* MY_ABC_HERE */ if (ap->ops->error_handler) +#endif /* MY_ABC_HERE */ ata_eh_release(ap); rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); +#ifdef MY_ABC_HERE + /* ATA_PFLAG_PMP_PMCTL means we are injecting ata cmd during eh, don't acquire a new one. */ + /* JMB575 control commnads do not need to deal with eh lock */ + if (ap->ops->error_handler && !(ap->pflags & ATA_PFLAG_PMP_PMCTL)) +#else /* MY_ABC_HERE */ if (ap->ops->error_handler) +#endif /* MY_ABC_HERE */ ata_eh_acquire(ap); ata_sff_flush_pio_task(ap); @@ -1833,7 +1908,11 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { +#ifdef MY_ABC_HERE + ata_dev_warn(dev, "NODEV after polling detection\n"); +#else /* MY_ABC_HERE */ ata_dev_dbg(dev, "NODEV after polling detection\n"); +#endif /* MY_ABC_HERE */ return -ENOENT; } @@ -1865,8 +1944,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, * both flavors of IDENTIFYs which happens * sometimes with phantom devices. */ +#ifdef MY_ABC_HERE + ata_dev_warn(dev, + "both IDENTIFYs aborted, assuming NODEV\n"); +#else /* MY_ABC_HERE */ ata_dev_dbg(dev, "both IDENTIFYs aborted, assuming NODEV\n"); +#endif /* MY_ABC_HERE */ return -ENOENT; } @@ -1899,8 +1983,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, goto err_out; if (ap->host->flags & ATA_HOST_IGNORE_ATA && ata_id_is_ata(id)) { +#ifdef MY_ABC_HERE + ata_dev_warn(dev, + "host indicates ignore ATA devices, ignored\n"); +#else /* MY_ABC_HERE */ ata_dev_dbg(dev, "host indicates ignore ATA devices, ignored\n"); +#endif /* MY_ABC_HERE */ return -ENOENT; } } else { @@ -1960,6 +2049,12 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, *p_class = class; +#ifdef MY_ABC_HERE + if (syno_ata_id_is_ssd(id)) { + dev->is_ssd = 1; + } +#endif /* MY_ABC_HERE */ + return 0; err_out: @@ -2003,6 +2098,11 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, return AC_ERR_DEV; retry: + +#ifdef MY_ABC_HERE + dev->horkage |= ATA_HORKAGE_NO_DMA_LOG; +#endif /* MY_ABC_HERE */ + ata_tf_init(dev, &tf); if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) && !(dev->horkage & ATA_HORKAGE_NO_DMA_LOG)) { @@ -2021,7 +2121,11 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, +#ifdef MY_ABC_HERE + buf, sectors * ATA_SECT_SIZE, 15 * 1000); +#else /* MY_ABC_HERE */ buf, sectors * ATA_SECT_SIZE, 0); +#endif /* MY_ABC_HERE */ if (err_mask && dma) { dev->horkage |= ATA_HORKAGE_NO_DMA_LOG; @@ -2136,8 +2240,12 @@ static void ata_dev_config_ncq_send_recv(struct ata_device *dev) dev->flags |= ATA_DFLAG_NCQ_SEND_RECV; memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE); - +#ifdef MY_ABC_HERE + if (1) { + // All SSDs that enter here will disable NCQ trim +#else if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) { +#endif /* MY_DEF_HERE */ ata_dev_dbg(dev, "disabling queued TRIM support\n"); cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &= ~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM; @@ -2363,6 +2471,23 @@ static void ata_dev_config_trusted(struct ata_device *dev) dev->flags |= ATA_DFLAG_TRUSTED; } +#ifdef MY_ABC_HERE +static void syno_pmp_horkage(struct ata_port *ap, struct ata_device **dev) { + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + + if (!ap || !dev || !*dev) { + goto END; + } + + ata_id_c_string((*dev)->id, model_num, ATA_ID_PROD, sizeof(model_num)); + if (syno_pm_is_synology_9705(ap) && glob_match("WDC WD?0EFRX-*", model_num)) { + (*dev)->horkage |= ATA_HORKAGE_1_5_GBPS; + } +END: + return; +} +#endif /* MY_ABC_HERE */ + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -2387,6 +2512,12 @@ int ata_dev_configure(struct ata_device *dev) char revbuf[7]; /* XYZ-99\0 */ char fwrevbuf[ATA_ID_FW_REV_LEN+1]; char modelbuf[ATA_ID_PROD_LEN+1]; +#ifdef MY_ABC_HERE + char snbuf[ATA_ID_SERNO_LEN+1]; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct pci_dev *pdev = NULL; +#endif /* MY_ABC_HERE */ int rc; if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { @@ -2397,8 +2528,23 @@ int ata_dev_configure(struct ata_device *dev) if (ata_msg_probe(ap)) ata_dev_dbg(dev, "%s: ENTER\n", __func__); +#ifdef MY_ABC_HERE + // Reset the statistics of disk latecny. + memset(&(dev->link->ata_latency), 0, sizeof(struct syno_ata_latency)); + memset(&(dev->link->latency_stat), 0, sizeof(struct syno_latency_stat)); +#ifdef MY_ABC_HERE + memset(&(dev->link->seq_stat), 0, sizeof(dev->link->seq_stat)); +#endif /* MY_ABC_HERE */ + generate_random_uuid(dev->link->latency_stat.uuid); +#endif /* MY_ABC_HERE */ + /* set horkage */ dev->horkage |= ata_dev_blacklisted(dev); +#ifdef MY_ABC_HERE + if (ap->nr_pmp_links) { + syno_pmp_horkage(ap, &dev); + } +#endif /* MY_ABC_HERE */ ata_force_horkage(dev); if (dev->horkage & ATA_HORKAGE_DISABLE) { @@ -2478,6 +2624,23 @@ int ata_dev_configure(struct ata_device *dev) ata_id_c_string(dev->id, modelbuf, ATA_ID_PROD, sizeof(modelbuf)); +#ifdef MY_ABC_HERE + ata_id_c_string(dev->id, snbuf, ATA_ID_SERNO, + sizeof(snbuf)); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* We disable ncq cmd of WD7500BPKX and WD5000BPKX on 92XX ports to avoid ata error*/ + if (ap->host->dev->bus && !strcmp("pci", ap->host->dev->bus->name)) { + pdev = to_pci_dev(ap->host->dev); + if (NULL != pdev && (0x9215 == pdev->device || 0x9235 == pdev->device)) { + if (glob_match("WDC WD7500BPKX-*", modelbuf) || + glob_match("WDC WD5000BPKX-*", modelbuf)) { + dev->horkage |= ATA_HORKAGE_NONCQ; + } + } + } +#endif /* MY_ABC_HERE */ /* ATA-specific feature tests */ if (dev->class == ATA_DEV_ATA || dev->class == ATA_DEV_ZAC) { @@ -2536,6 +2699,11 @@ int ata_dev_configure(struct ata_device *dev) "%llu sectors, multi %u: %s %s\n", (unsigned long long)dev->n_sectors, dev->multi_count, lba_desc, ncq_desc); +#ifdef MY_ABC_HERE + ata_dev_info(dev, + "SN:%s\n", + snbuf); +#endif /* MY_ABC_HERE */ } } else { /* CHS */ @@ -2562,6 +2730,11 @@ int ata_dev_configure(struct ata_device *dev) (unsigned long long)dev->n_sectors, dev->multi_count, dev->cylinders, dev->heads, dev->sectors); +#ifdef MY_ABC_HERE + ata_dev_info(dev, + "SN:%s\n", + snbuf); +#endif /* MY_ABC_HERE */ } } @@ -2592,6 +2765,21 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_config_zac(dev); ata_dev_config_trusted(dev); dev->cdb_len = 32; +#ifdef MY_ABC_HERE + if ((dev->horkage & ATA_HORKAGE_NOWCACHE) && + !(dev->flags & ATA_DFLAG_NO_WCACHE)) { + unsigned int err_mask; + + ata_dev_printk(dev, KERN_ERR, "Disable disk write cache"); + dev->flags |= ATA_DFLAG_NO_WCACHE; + + err_mask = ata_dev_set_feature(dev, SETFEATURES_WC_OFF, 0); + if (err_mask) + ata_dev_printk(dev, KERN_ERR, + "failed to dsiable write cache " + "(err_mask=0x%x)\n", err_mask); + } +#endif /* MY_ABC_HERE */ } /* ATAPI-specific feature tests */ @@ -2711,6 +2899,19 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_warn(dev, " contact the vendor or visit http://ata.wiki.kernel.org\n"); } +#ifdef MY_ABC_HERE + if (0 > (dev->u8LbaZoneShiftBit = + (u8)(fls64(dev->n_sectors) - 4))) { + dev->u8LbaZoneShiftBit = 0; + } + if (ata_id_rahead_enabled(id) && ata_id_has_rahead(id)) { + dev->u64SeqValidSkipBytes = SynoDiskSeqValidSkipBytes; + } else { + dev->u64SeqValidSkipBytes = 0; + } + +#endif /* MY_ABC_HERE */ + return 0; err_out_nosup: @@ -2924,6 +3125,38 @@ int ata_bus_probe(struct ata_port *ap) goto retry; } +#ifdef MY_ABC_HERE +extern int SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(int index); +extern int SYNO_CHECK_HDD_DETECT(int index); +extern void SYNO_HDD_POWER_ON(int index); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void syno_ata_present_print(struct ata_port *ap, const char *eventlog) +{ + bool blPresent = false; + + /* XXX: Assume all eunit don't have present pin info */ + if (0 > ap->syno_internal_slot_index) { + return ; + } + + if (SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(ap->syno_internal_slot_index+1)) { + if (SYNO_CHECK_HDD_DETECT(ap->syno_internal_slot_index + 1)) { + ata_port_printk(ap, KERN_ERR, "Disk is present for %s event\n", eventlog); + blPresent = true; + } else { + ata_port_printk(ap, KERN_ERR, "Disk is not present for %s event\n", eventlog); + } + } else { + ata_port_printk(ap, KERN_ERR, "No present pin info for %s event\n", eventlog); + } + + ap->iPresentAfterError = (blPresent) ? 1 : 0; +} +EXPORT_SYMBOL(syno_ata_present_print); +#endif /* MY_ABC_HERE */ + /** * sata_print_link_status - Print SATA link status * @link: SATA link to printk link status about @@ -2943,11 +3176,30 @@ static void sata_print_link_status(struct ata_link *link) if (ata_phys_link_online(link)) { tmp = (sstatus >> 4) & 0xf; +#ifdef MY_ABC_HERE + ata_link_warn(link, "SATA link up %s (SStatus %X SControl %X)\n", + sata_spd_string(tmp), sstatus, scontrol); +#else /* MY_ABC_HERE */ ata_link_info(link, "SATA link up %s (SStatus %X SControl %X)\n", sata_spd_string(tmp), sstatus, scontrol); +#endif /* MY_ABC_HERE */ } else { +#ifdef MY_ABC_HERE + ata_link_warn(link, "SATA link down (SStatus %X SControl %X)\n", + sstatus, scontrol); +#else /* MY_ABC_HERE */ ata_link_info(link, "SATA link down (SStatus %X SControl %X)\n", sstatus, scontrol); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (link->ap) { + syno_ata_present_print(link->ap, "SATA link down"); + if (link->ap->iPresentAfterError) { + schedule_work(&(link->ap->SendLinkDownEventTask)); + } + } +#endif /* MY_ABC_HERE */ } } @@ -3267,6 +3519,13 @@ static int ata_dev_set_mode(struct ata_device *dev) ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)), dev_err_whine); +#ifdef MY_ABC_HERE + if (ap->uiSflags & ATA_SYNO_FLAG_REVALID_FAIL) { + DBGMESG("port %d set mode sucessfully , clear revalid fail flag\n", ap->print_id); + ap->uiSflags &= ~ATA_SYNO_FLAG_REVALID_FAIL; + } +#endif /* MY_ABC_HERE */ + return 0; fail: @@ -3762,9 +4021,18 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, dev->n_sectors = n_sectors; fail: ata_dev_err(dev, "revalidation failed (errno=%d)\n", rc); +#ifdef MY_ABC_HERE + if (-EIO == rc) { + DBGMESG("port %d revalidation failed, set revalid fail flag\n", dev->link->ap->print_id); + dev->link->ap->uiSflags |= ATA_SYNO_FLAG_REVALID_FAIL; + } +#endif /* MY_ABC_HERE */ return rc; } +#ifdef MY_ABC_HERE +struct ata_blacklist_entry ata_device_blacklist [] = { +#else /* MY_ABC_HERE */ struct ata_blacklist_entry { const char *model_num; const char *model_rev; @@ -3772,6 +4040,7 @@ struct ata_blacklist_entry { }; static const struct ata_blacklist_entry ata_device_blacklist [] = { +#endif /* MY_ABC_HERE */ /* Devices with DMA related problems under Linux */ { "WDC AC11000H", NULL, ATA_HORKAGE_NODMA }, { "WDC AC22100H", NULL, ATA_HORKAGE_NODMA }, @@ -4000,6 +4269,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD3000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, { "WDC WD3200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, +#ifdef MY_ABC_HERE + /* + * Now we implemented blacklist of disabling write-cache in usersapce instead + * of kernel. If there is particular reason you need to add models of hard + * disk into blacklist in kernel for disabling write-cache, please refer to + * the following example. + */ + //{ "SAMSUNG HD204UI", "1AQ10001", ATA_HORKAGE_NOWCACHE}, +#endif /* MY_ABC_HERE */ + /* End Marker */ { } }; @@ -4361,6 +4640,12 @@ int ata_std_qc_defer(struct ata_queued_cmd *qc) { struct ata_link *link = qc->dev->link; +#ifdef MY_ABC_HERE + if (link->ap->pflags & (ATA_PFLAG_EH_IN_PROGRESS | ATA_PFLAG_EH_PENDING)) { + return ATA_DEFER_LINK; + } +#endif /* MY_ABC_HERE */ + if (ata_is_ncq(qc->tf.protocol)) { if (!ata_tag_valid(link->active_tag)) return 0; @@ -4552,6 +4837,62 @@ void ata_qc_free(struct ata_queued_cmd *qc) } } +#ifdef MY_ABC_HERE +static void syno_ata_cmd_latency_preprocess(struct ata_queued_cmd *qc, + struct ata_link *link, + u64 u64AtaIntrTime) +{ + u8 u8QcType = 0; + unsigned int uBucketOffset = 0; + u64 u64StepOffset = 0; + u64 u64CmdRespTime = 0; + + /* read: 1, write: 2, others: 0. */ + u8QcType = qc->qc_stat.u8QcType; + if (unlikely(2 < u8QcType)) { + u8QcType = 0; + } + + u64CmdRespTime = (u64AtaIntrTime - qc->qc_stat.u64IssueTime); + + link->ata_latency.u16TotalCplCmdCnt += 1; + link->ata_latency.u16CplCmdCnt[u8QcType] += 1; + +#ifdef MY_ABC_HERE + link->ata_latency.u8CplCmdSeqState |= (SYNO_ANY_NONE_SEQ & + (qc->qc_stat.u8SeqTag != link->ata_latency.u8SeqTag)); + link->ata_latency.u8CplCmdSeqState |= (1 << qc->qc_stat.u8SeqState); + link->ata_latency.u8CplCmdSeqLbaZone = qc->qc_stat.u8LbaZone; + link->ata_latency.u32CplCmdBytes[u8QcType] += qc->nbytes; + link->ata_latency.u32CplCmdSkipBytes[u8QcType] += qc->qc_stat.u32SkipBytes; + + link->ata_latency.u8NonSeqActiveIo -= + 1 & (SYNO_NON_READ_SEQ_STAT == qc->qc_stat.u8SeqState); +#endif /* MY_ABC_HERE */ + + link->latency_stat.u64TotalCount[u8QcType] += 1; + link->latency_stat.u64TotalBytes[u8QcType] += qc->nbytes; + link->latency_stat.u64TotalRespTime[u8QcType] += u64CmdRespTime; + if ((0 == link->ata_latency.u64FirstCmdStartTime) + || (qc->qc_stat.u64IssueTime < link->ata_latency.u64FirstCmdStartTime)) { + link->ata_latency.u64FirstCmdStartTime = qc->qc_stat.u64IssueTime; + } + + // calculate the response time buckets + // shift to 32us + u64StepOffset = (u64CmdRespTime >> 15); + // calculate the offset of buckets with the response time + uBucketOffset = syno_ata_latency_bucket_offset_get(u64StepOffset); + u64StepOffset >>= (5 * uBucketOffset); + if (unlikely(31 < u64StepOffset)) { + uBucketOffset = (SYNO_LATENCY_BUCKETS_END - 1); + u64StepOffset = 31; + } + link->ata_latency.u64RespTimeBuckets[u8QcType][uBucketOffset][u64StepOffset] += 1; + return; +} +#endif /* MY_ABC_HERE */ + void __ata_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap; @@ -4580,6 +4921,10 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) ap->excl_link == link)) ap->excl_link = NULL; +#ifdef MY_ABC_HERE + syno_ata_cmd_latency_preprocess(qc, link, ap->u64AtaIntrTime); +#endif /* MY_ABC_HERE */ + /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler * is called. (when rc != 0 and atapi request sense is needed) @@ -4671,6 +5016,15 @@ void ata_qc_complete(struct ata_queued_cmd *qc) */ if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { fill_result_tf(qc); + +#ifdef MY_ABC_HERE + /* Complete Synology command without eh */ + if (syno_qc_filter(qc)) { + __ata_qc_complete(qc); + return; + } +#endif /* MY_ABC_HERE */ + trace_ata_qc_complete_failed(qc); ata_qc_schedule_eh(qc); return; @@ -4723,6 +5077,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) } EXPORT_SYMBOL_GPL(ata_qc_complete); + /** * ata_qc_get_active - get bitmask of active qcs * @ap: port in question @@ -4747,6 +5102,62 @@ u64 ata_qc_get_active(struct ata_port *ap) } EXPORT_SYMBOL_GPL(ata_qc_get_active); +#ifdef MY_ABC_HERE +#define SYNO_SAMPLE_SEQ_FLYOUT_CNT 8 + +static void syno_ata_latency_start(struct ata_queued_cmd *qc, u8 blIsBatchHead) +{ + struct ata_link *link = qc->dev->link; +#ifdef MY_ABC_HERE + u8 u8FlyoutCnts = hweight32(link->sactive); + u64 u64SeqSkipBytes = 0; +#endif /* MY_ABC_HERE */ + + qc->qc_stat.u64IssueTime = cpu_clock(0); + + if (1 == blIsBatchHead) { + /* + * record the issue time of first qc within batch, + * then we could caclulate the comsumption time of the whole batch + */ + link->ata_latency.u64BatchIssue = qc->qc_stat.u64IssueTime; +#ifdef MY_ABC_HERE + link->ata_latency.u8NonSeqActiveIo = 0; +#endif /* MY_ABC_HERE */ + } + +#ifdef MY_ABC_HERE + u64SeqSkipBytes = qc->qc_stat.u64StartLbaByte - + link->ata_latency.u64SeqLastLbaByte; + + if (1 != qc->qc_stat.u8QcType + || qc->qc_stat.u64StartLbaByte < link->ata_latency.u64SeqLastLbaByte + || qc->dev->u64SeqValidSkipBytes < u64SeqSkipBytes) { + + link->ata_latency.u64SeqBytes = 0; + link->ata_latency.u8SeqTag++; + link->ata_latency.u8SeqTag &= 0x1F; + link->ata_latency.u8NonSeqActiveIo++; + qc->qc_stat.u8SeqState = SYNO_NON_READ_SEQ_STAT; + } else { + if (SynoDiskSeqValidBytesThreshold < link->ata_latency.u64SeqBytes + && 0 == link->ata_latency.u8NonSeqActiveIo + && SYNO_SAMPLE_SEQ_FLYOUT_CNT < u8FlyoutCnts) { + qc->qc_stat.u8SeqState = SYNO_READ_SEQ_STAT; + qc->qc_stat.u32SkipBytes = u64SeqSkipBytes; + qc->qc_stat.u8SeqTag = link->ata_latency.u8SeqTag; + } + link->ata_latency.u64SeqBytes += qc->nbytes; + } + + link->ata_latency.u64SeqLastLbaByte = qc->qc_stat.u64StartLbaByte + + qc->nbytes; +#endif /* MY_ABC_HERE */ + + return; +} +#endif /* MY_ABC_HERE */ + /** * ata_qc_issue - issue taskfile to device * @qc: command to issue to device @@ -4764,6 +5175,9 @@ void ata_qc_issue(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct ata_link *link = qc->dev->link; u8 prot = qc->tf.protocol; +#ifdef MY_ABC_HERE + u8 blIsBatchHead = 1; +#endif /* MY_ABC_HERE */ /* Make sure only one non-NCQ command is outstanding. The * check is skipped for old EH because it reuses active qc to @@ -4784,6 +5198,12 @@ void ata_qc_issue(struct ata_queued_cmd *qc) link->active_tag = qc->tag; } +#ifdef MY_ABC_HERE + if (ata_is_ncq(prot) && link->sactive) { + blIsBatchHead = 0; + } +#endif /* MY_ABC_HERE */ + qc->flags |= ATA_QCFLAG_ACTIVE; ap->qc_active |= 1ULL << qc->tag; @@ -4811,6 +5231,11 @@ void ata_qc_issue(struct ata_queued_cmd *qc) if (unlikely(qc->err_mask)) goto err; trace_ata_qc_issue(qc); + +#ifdef MY_ABC_HERE + syno_ata_latency_start(qc, blIsBatchHead); +#endif /* MY_ABC_HERE */ + qc->err_mask |= ap->ops->qc_issue(qc); if (unlikely(qc->err_mask)) goto err; @@ -5189,6 +5614,16 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) link->pmp = pmp; link->active_tag = ATA_TAG_POISON; link->hw_sata_spd_limit = UINT_MAX; +#ifdef MY_ABC_HERE + link->uiSflags = 0x0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + INIT_WORK(&link->SendSataErrEventTask, SendSataErrEvent); + INIT_WORK(&link->SendDiskTimeoutEventTask, SendDiskTimeoutEvent); + INIT_WORK(&link->SendDiskSoftResetFailEventTask, SendDiskSoftResetFailEvent); + INIT_WORK(&link->SendDiskHardResetFailEventTask, SendDiskHardResetFailEvent); +#endif /* MY_ABC_HERE */ /* can't use iterator, ap isn't initialized yet */ for (i = 0; i < ATA_MAX_DEVICES; i++) { @@ -5199,6 +5634,12 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) #ifdef CONFIG_ATA_ACPI dev->gtf_filter = ata_acpi_gtf_filter; #endif +#ifdef MY_DEF_HERE + dev->ulSpinupState = 0; + dev->ulLastCmd = 0; + dev->iCheckPwr = 0; +#endif /* MY_DEF_HERE */ + ata_dev_init(dev); } } @@ -5276,6 +5717,12 @@ struct ata_port *ata_port_alloc(struct ata_host *host) mutex_init(&ap->scsi_scan_mutex); INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); +#ifdef MY_ABC_HERE + INIT_DELAYED_WORK(&ap->syno_pmp_task, ata_syno_pmp_hotplug); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + INIT_WORK(&ap->SendDsleepWakeEventTask, SendDsleepWakeEvent); +#endif /* MY_ABC_HERE */ INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); @@ -5293,6 +5740,40 @@ struct ata_port *ata_port_alloc(struct ata_host *host) #endif ata_sff_port_init(ap); +#ifdef MY_ABC_HERE + ap->syno_internal_slot_index = -1; + klist_add_tail(&ap->ata_port_list, &syno_ata_port_head); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ap->error_handling = 0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ap->uiSflags = 0x0; + ap->syno_recover_tries = 0; + ap->syno_recover_max_tries = 0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ap->iPresentAfterError = 0; + INIT_WORK(&ap->SendPortRetryFailedEventTask, SendPortRetryFailedEvent); + INIT_WORK(&ap->SendLinkDownEventTask, SendLinkDownEvent); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ap->ulSynoPortEnabledBitmap = 0; + ap->blSynoDiskHotplugEvent = false; + ap->uSynoPMPErrorPort = 0; + INIT_WORK(&ap->SendDiskPowerShortBreakEventTask, SendDiskPowerShortBreakEvent); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + INIT_WORK(&ap->SendPwrResetEventTask, SendPwrResetEvent); + INIT_WORK(&ap->SendPortDisEventTask, SendPortDisEvent); + INIT_WORK(&ap->SendDiskRetryEventTask, SendDiskRetryEvent); +#endif /* MY_ABC_HERE */ + return ap; } @@ -5369,6 +5850,9 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) size_t sz; int i; void *dr; +#ifdef MY_ABC_HERE + struct pci_dev *pdev = NULL; +#endif /* MY_ABC_HERE */ DPRINTK("ENTER\n"); @@ -5407,6 +5891,18 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) } devres_remove_group(dev, NULL); + +#ifdef MY_ABC_HERE + pdev = to_pci_dev(dev); + if (dev->bus && !strcmp("pci", dev->bus->name) && pdev) { + host->vendor = pdev->vendor; + host->device = pdev->device; + } else { + host->vendor = 0; + host->device = 0; + } +#endif /* MY_ABC_HERE */ + return host; err_out: @@ -5634,6 +6130,80 @@ void ata_host_init(struct ata_host *host, struct device *dev, } EXPORT_SYMBOL_GPL(ata_host_init); +#ifdef MY_DEF_HERE +/* + * delay for HW ready, if this port already wait for latency, + * we delay 5s, otherwise we dleay 7s. And the first, last + * disks, we shouldn't delay them. + * + **/ +static void delay_use_strategy(void) +{ + int iDelay = 0; + + if (0 >= (iDelay = SpinupDelayEval())) { + goto skip_wait_or_wait_done; + } + + /* the first shouldn't wait */ + if (syno_boot_hd_count && + (gSynoHddPowerupSeq && (syno_boot_hd_count < gSynoInternalHddNumber))) { + + if (0 < iDelay) { + printk("Delay %d seconds according to spin up strategy.\n", iDelay); + msleep(iDelay * 1000); + goto skip_wait_or_wait_done; + } else { + /* XXX: left some debug log for the model without spinup group? */ + } + } + +skip_wait_or_wait_done: + syno_boot_hd_count++; +} + +/* + * May do poweron for this port and sleep for hw ready + * + * @param ap [IN] the ata port + * + **/ +static void DelayForHWCtl(struct ata_port *ap) +{ + int iSynoDiskIdx = -1; + + if (!ap) { + goto END; + } + + /* No spin up strategy */ + if (!gSynoHddPowerupSeq) { + goto END; + } + + iSynoDiskIdx = lookup_internal_slot(ap); + // TODO: currently there is no esata node in kernel dts, so syno_libata_index_get now return iSynoDiskInx = 0 + if (0 == iSynoDiskIdx) { + // for disk that is not internal disk, there is no need to do delay for poweron. + goto END; + } + +#ifdef MY_DEF_HERE + if(SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(iSynoDiskIdx)) { + /* disk doesn't present, no need to delay */ + if (0 == SYNO_CHECK_HDD_DETECT(iSynoDiskIdx)) { + goto END; + } + } +#endif /* MY_DEF_HERE */ + + delay_use_strategy(); + +END: + return; +} +#endif /* MY_DEF_HERE */ + void __ata_port_probe(struct ata_port *ap) { struct ata_eh_info *ehi = &ap->link.eh_info; @@ -5656,10 +6226,44 @@ void __ata_port_probe(struct ata_port *ap) int ata_port_probe(struct ata_port *ap) { int rc = 0; +#ifdef MY_ABC_HERE + int index = -1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned long flags; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + /* delay Xs to avoid probe disks in the same time(consume too much power) + * If this async_port_probe(..) function is run asynchronously this code is not work, + * so we must disable async_enabled before call async_port_probe(..) */ + DelayForHWCtl(ap); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE + /* If the machine supports disk power control, switch to power on */ + if (0 < (index = lookup_internal_slot(ap)) && SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(index)) { + SYNO_HDD_POWER_ON(index); + + /* Default delay for HDD ready */ + mdelay(3000); + } +#endif /* MY_ABC_HERE */ if (ap->ops->error_handler) { __ata_port_probe(ap); ata_port_wait_eh(ap); + +#ifdef MY_ABC_HERE + spin_lock_irqsave(ap->lock, flags); + if (ap->pflags & ATA_PFLAG_PMP_DISCONNECT || + ap->pflags & ATA_PFLAG_PMP_CONNECT) { + /* Clear unused PMP event during boot probe */ + ap->pflags &= ~ATA_PFLAG_PMP_DISCONNECT; + ap->pflags &= ~ATA_PFLAG_PMP_CONNECT; + } + spin_unlock_irqrestore(ap->lock, flags); +#endif /* MY_ABC_HERE */ } else { DPRINTK("ata%u: bus probe begin\n", ap->print_id); rc = ata_bus_probe(ap); @@ -5673,6 +6277,14 @@ static void async_port_probe(void *data, async_cookie_t cookie) { struct ata_port *ap = data; +#ifdef MY_ABC_HERE + /* + * Skip ATA_HOST_PARALLEL_SCAN check to speed up the disk power on. + * The original design is avoid scanning ata ports in parallel if + * the controller support Staggered Spin-up (SSS). + * We control the HDD power on by ourselves. + */ +#else /* MY_ABC_HERE */ /* * If we're not allowed to scan this host in parallel, * we need to wait until all previous scans have completed @@ -5682,6 +6294,7 @@ static void async_port_probe(void *data, async_cookie_t cookie) */ if (!(ap->host->flags & ATA_HOST_PARALLEL_SCAN) && ap->port_no != 0) async_synchronize_cookie(cookie); +#endif /* MY_ABC_HERE */ (void)ata_port_probe(ap); @@ -5950,6 +6563,9 @@ void ata_pci_remove_one(struct pci_dev *pdev) } EXPORT_SYMBOL_GPL(ata_pci_remove_one); +#ifdef MY_ABC_HERE +extern int syno_eunit_poweroff(struct ata_port *ap); +#endif /* MY_ABC_HERE */ void ata_pci_shutdown_one(struct pci_dev *pdev) { struct ata_host *host = pci_get_drvdata(pdev); @@ -5958,6 +6574,11 @@ void ata_pci_shutdown_one(struct pci_dev *pdev) for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; +#ifdef MY_ABC_HERE + /* Send sata commands to power off EUnit before port freeze */ + syno_eunit_poweroff(ap); +#endif /* MY_ABC_HERE */ + ap->pflags |= ATA_PFLAG_FROZEN; /* Disable port interrupts */ @@ -6295,6 +6916,10 @@ static int __init ata_init(void) goto err_out; } +#ifdef MY_ABC_HERE + klist_init(&syno_ata_port_head, NULL, NULL); +#endif /* MY_ABC_HERE */ + printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n"); return 0; @@ -6428,6 +7053,43 @@ const struct ata_port_info ata_dummy_port_info = { }; EXPORT_SYMBOL_GPL(ata_dummy_port_info); +#ifdef MY_ABC_HERE +void syno_ata_detection_info_print(struct ata_port *ap) +{ + u32 sstatus; + + if(NULL == ap->ops || NULL == ap->ops->scr_read) { + return; + } + + ap->ops->scr_read(&ap->link, SCR_STATUS, &sstatus); + /** + * 0000 No device detected and PHY communication not + * established + * 0001 Device presence detected but PHY communication not + * established + * 0011 Device presence detected and PHY communication + * established + * 0100 PHY in offline mode as a result of the + * interface being disabled or running in a BIST loopback + * mode + * + * PMP port hotplug would not detect by this + */ + if(0x0 == (0xf & sstatus)) { + printk("ata%u: device unplugged sstatus 0x%x\n", ap->print_id, sstatus); + } else if (0x1 == (0xf & sstatus) || 0x3 == (0xf & sstatus)) { + printk("ata%u: device plugged sstatus 0x%x\n", ap->print_id, sstatus); + } else if (0x4 == (0xf & sstatus)){ + printk("ata%u: PHY in offline mode 0x%x\n", ap->print_id, sstatus); + } else { + printk("ata%u: UnKnown ATA SStatus\n", ap->print_id); + } +} + +EXPORT_SYMBOL(syno_ata_detection_info_print); +#endif /* MY_ABC_HERE */ + /* * Utility print functions */ @@ -6442,7 +7104,15 @@ void ata_port_printk(const struct ata_port *ap, const char *level, vaf.fmt = fmt; vaf.va = &args; +#ifdef MY_ABC_HERE + if (0 <= ap->syno_internal_slot_index) { + printk("%sata%u (slot %d): %pV", level, ap->print_id, ap->syno_internal_slot_index + 1 , &vaf); + } else { + printk("%sata%u : %pV", level, ap->print_id, &vaf); + } +#else /* MY_ABC_HERE */ printk("%sata%u: %pV", level, ap->print_id, &vaf); +#endif /* MY_ABC_HERE */ va_end(args); } @@ -6494,3 +7164,181 @@ void ata_print_version(const struct device *dev, const char *version) dev_printk(KERN_DEBUG, dev, "version %s\n", version); } EXPORT_SYMBOL(ata_print_version); + +#ifdef MY_ABC_HERE +/** + * syno_ata_port_get_by_port - get the ata_port of the internal slot + * @diskPort [IN]: slot number + * + * return !NULL: ata_port + NULL: fail + */ +struct ata_port *syno_ata_port_get_by_port(const unsigned short diskPort) +{ + int index = -1; + struct ata_port *ap = NULL; + struct device_node *pSlotNode = NULL; + struct klist_iter klist_iter; + struct klist_node *ata_node = NULL; + + if (NULL == of_root) { + goto END; + } + for_each_child_of_node(of_root, pSlotNode) { + // get index number of internal_slot, e.g. internal_slot@4 --> 4 + if (!pSlotNode->full_name || 1 != sscanf(pSlotNode->full_name, DT_INTERNAL_SLOT"@%d", &index)) { + continue; + } + if (diskPort == index) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + + klist_iter_init(&syno_ata_port_head, &klist_iter); + for (ata_node = klist_next(&klist_iter); NULL != ata_node; ata_node = klist_next(&klist_iter)) { + ap = container_of(ata_node, struct ata_port, ata_port_list); + if (true == ap->ops->syno_compare_node_info(ap, pSlotNode)) { + break; + } + ap = NULL; + } + klist_iter_exit(&klist_iter); + + of_node_put(pSlotNode); +END: + return ap; +} +EXPORT_SYMBOL(syno_ata_port_get_by_port); + +/** + * lookup_internal_slot - lookup device tree to find corresponding internal slot of the ata_port + * @ap [IN]: query ata_port + * + * return >0: slot + * 0: slot not found + * -1: error return + */ +int lookup_internal_slot(const struct ata_port *ap) +{ + int index = -1; + int isInternalSlotFound = 0; + struct device_node *pDeviceNode = NULL; + + if (NULL == ap || NULL == of_root || NULL == ap->ops->syno_compare_node_info) { + goto END; + } + + for_each_child_of_node(of_root, pDeviceNode) { + if (pDeviceNode->full_name + && 0 == (strncmp(pDeviceNode->full_name, DT_INTERNAL_SLOT, strlen(DT_INTERNAL_SLOT)))) { + if (true == ap->ops->syno_compare_node_info(ap, pDeviceNode)) { + // get index number of internal_slot, e.g. internal_slot@4 --> 4 + sscanf(pDeviceNode->full_name, DT_INTERNAL_SLOT"@%d", &index); + isInternalSlotFound = 1; + of_node_put(pDeviceNode); + break; + } + } + } + if (!isInternalSlotFound) { + index = 0; + } +END: + return index; +} +EXPORT_SYMBOL(lookup_internal_slot); + +/** + * get_disk_port_type_and_index_by_ata_port - Find ata_port in DTS, return DISK_PORT_TYPE and port index + * @ap [IN] : ata_port + * @portType [OUT]: DISK_PORT_TYPE + * @portIndex [OUT]: port index + * + * return 0: Program ended normally + * -1: Error return + * + * For example, ata_port matches below DTS member, portType = SYSTEM_DEVICE, portIndex = 1 + * system_slot@1 { + * ahci { + * pcie_root = "00:17.0"; + * ata_port = <0>; + * sw_activity = <1>; + * }; + * } + * + * For example, ata_port matches below DTS member, portType = INTERNAL_DEVICE, portIndex = 2 + * internal_slot@2 { + * ahci { + * pcie_root = "00:17.0"; + * ata_port = <0>; + * sw_activity = <1>; + * }; + * } + */ +int get_disk_port_type_and_index_by_ata_port(const struct ata_port *ap, DISK_PORT_TYPE *portType, int *portIndex) +{ + int iRet = -1; + struct device_node *pDeviceNode = NULL; + if (NULL == ap || NULL == of_root || NULL == portType || NULL == portIndex) { + printk("Invalid parameter\n"); + goto END; + } + + *portType = UNKNOWN_DEVICE; + + for_each_child_of_node(of_root, pDeviceNode) { + if (NULL == pDeviceNode->full_name) { + continue; + } + + if (false == ap->ops->syno_compare_node_info(ap, pDeviceNode)) { + continue; + } + + if (1 == sscanf(pDeviceNode->full_name, DT_INTERNAL_SLOT"@%d", portIndex)) { + *portType = INTERNAL_DEVICE; + } else if (1 == sscanf(pDeviceNode->full_name, DT_SYSTEM_SLOT"@%d", portIndex)) { + *portType = SYSTEM_DEVICE; + } else if (1 == sscanf(pDeviceNode->full_name, DT_ESATA_SLOT"@%d", portIndex)) { + *portType = EXTERNAL_SATA_DEVICE; + } else if (1 == sscanf(pDeviceNode->full_name, DT_CX4_SLOT"@%d", portIndex)) { + *portType = EUNIT_DEVICE; + } else { + printk("Error, unknown disk port type\n"); + } + + // Everytime for_each_child_of_node will put "previous" pDeviceNode, but we break here, threfore need a put. + of_node_put(pDeviceNode); + break; + } + + iRet = 0; +END: + return iRet; +} +EXPORT_SYMBOL(get_disk_port_type_and_index_by_ata_port); + +int syno_compare_dts_ata_port(const struct ata_port *pAtaPort, const struct device_node *pDeviceNode) +{ + int ret = -1; + u32 ata_port_no = U32_MAX; + if (NULL == pDeviceNode || NULL == pAtaPort) { + goto END; + } + if (0 != of_property_read_u32_index(pDeviceNode, DT_ATA_PORT, 0, &ata_port_no)) { + printk(KERN_ERR "%s: read ata_port error\n", __func__); + goto END; + } + + if (pAtaPort->port_no == ata_port_no) { + ret = 0; + } +END: + return ret; +} +EXPORT_SYMBOL(syno_compare_dts_ata_port); +#endif /* MY_ABC_HERE */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index b6f92050e60c..91bfe5e90c39 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * libata-eh.c - libata error handling @@ -28,6 +31,20 @@ #include #include "libata.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct list_head gSynoBiosEventHead; +extern spinlock_t syno_sata_error_lock; +#define SYNO_DISK_RESET_FAIL_REPORT_COUNT 3 +#endif /* MY_ABC_HERE */ + enum { /* speed down verdicts */ ATA_EH_SPDN_NCQ_OFF = (1 << 0), @@ -53,8 +70,12 @@ enum { ATA_EH_CMD_DFL_TIMEOUT = 5000, +#ifdef MY_ABC_HERE + ATA_EH_RESET_COOL_DOWN = 2000, +#else /* MY_ABC_HERE */ /* always put at least this amount of time between resets */ ATA_EH_RESET_COOL_DOWN = 5000, +#endif /* MY_ABC_HERE */ /* Waiting in ->prereset can never be reliable. It's * sometimes nice to wait there but it can't be depended upon; @@ -71,6 +92,10 @@ enum { ATA_EH_PROBE_TRIALS = 2, }; +#ifdef MY_DEF_HERE +extern unsigned int guiWakeupDisksNum; +#endif /* MY_DEF_HERE */ + /* The following table determines how we sequence resets. Each entry * represents timeout for that try. The first try can be soft or * hardreset. All others are hardreset if available. In most cases @@ -87,8 +112,13 @@ static const unsigned long ata_eh_reset_timeouts[] = { }; static const unsigned long ata_eh_identify_timeouts[] = { +#ifdef MY_ABC_HERE + 10000, + 30000, +#else /* MY_ABC_HERE */ 5000, /* covers > 99% of successes and not too boring on failures */ 10000, /* combined time till here is enough even for media access */ +#endif /* MY_ABC_HERE */ 30000, /* for true idiots */ ULONG_MAX, }; @@ -101,8 +131,13 @@ static const unsigned long ata_eh_flush_timeouts[] = { }; static const unsigned long ata_eh_other_timeouts[] = { +#ifdef MY_ABC_HERE + 30000, + 30000, +#else /* MY_ABC_HERE */ 5000, /* same rationale as identify timeout */ 10000, /* ditto */ +#endif /* MY_ABC_HERE */ /* but no merciful 30sec for other commands, it just isn't worth it */ ULONG_MAX, }; @@ -527,6 +562,9 @@ void ata_scsi_error(struct Scsi_Host *host) DPRINTK("ENTER\n"); +#ifdef MY_ABC_HERE + ap->error_handling = 1; +#endif /* MY_ABC_HERE */ spin_lock_irqsave(host->host_lock, flags); list_splice_init(&host->eh_cmd_q, &eh_work_q); spin_unlock_irqrestore(host->host_lock, flags); @@ -540,9 +578,140 @@ void ata_scsi_error(struct Scsi_Host *host) /* finish or retry handled scmd's and clean up */ WARN_ON(!list_empty(&eh_work_q)); +#ifdef MY_ABC_HERE + /* this makes sure that the scsi cmd dispatch to it's corresponding ata port won't do eunit deepsleep check.*/ + host->is_eunit_deepsleep = 0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ap->error_handling = 0; +#endif /* MY_ABC_HERE */ DPRINTK("EXIT\n"); } +#ifdef MY_ABC_HERE +/** + * ata_scsi_is_eunit_deepsleep - before ata_scsi_error called + * @host: SCSI host on which error occurred + * + * check if eunit is in deep sleep. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + * + * RETURNS: + * master pmp's Scsi Host if eunit is in deep sleep, need to poweron first. + * the host itself if master is doing poweron. it should never happen. + * NULL otherwise. + */ +struct Scsi_Host * ata_scsi_is_eunit_deepsleep(struct Scsi_Host *host) +{ + struct ata_port *ap = ata_shost_to_port(host); + struct ata_port *pAp_master = NULL; + unsigned long flags; + int iRet = -1; + + if (!ap->nr_pmp_links) { + goto END; + } else if (!syno_is_synology_pm(ap)) { + goto END; + } + + pAp_master = SynoEunitFindMaster(ap); + + if (NULL == pAp_master) { + printk("WARNING: disk %d can't find master!\n", ap->print_id); + goto END; + } + + if(0 == iIsSynoDeepSleepSupport(pAp_master)) { + goto END; + } + + spin_lock_irqsave(pAp_master->lock, flags); + /* if master is doing EH, means we are waking. */ + if ((pAp_master->pflags & ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH) || + (pAp_master->pflags & ATA_PFLAG_SYNO_DS_WAKING)) { + spin_unlock_irqrestore(pAp_master->lock, flags); + ata_port_printk(ap, KERN_NOTICE, "Waiting for master waking up\n"); + iRet = 0; + goto END; + } + /* if not power off and irq off, we must power on it first */ + if (!(pAp_master->pflags & ATA_PFLAG_SYNO_DS_PWROFF) && + ((pAp_master->pflags & ATA_PFLAG_SYNO_IRQ_OFF) || + (pAp_master->pflags & ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE))) { + iRet = 1; + } + spin_unlock_irqrestore(pAp_master->lock, flags); + +END: + if (-1 == iRet) { + return NULL; + } else if (0 == iRet && ap) { + return ap->scsi_host; + } + return pAp_master->scsi_host; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void syno_pmp_ncq_cmd_error_handler(struct ata_port *ap) +{ + struct ata_link *link = NULL; + struct ata_eh_info *ehi = NULL; + struct ata_eh_context *ehc = NULL; + bool eh_acquired = false; + u32 qc_timeout_map = 0; + struct ata_queued_cmd *qc = NULL; + int i; + + /* Undo timeout flag */ + for (i = 0; i < ATA_MAX_QUEUE; i++) { + qc = __ata_qc_from_tag(ap, i); + + if ((qc->err_mask & AC_ERR_TIMEOUT) && (qc->flags & ATA_QCFLAG_FAILED)) { + qc->err_mask &= ~AC_ERR_TIMEOUT; + qc->flags &= ~ATA_QCFLAG_FAILED; + qc_timeout_map |= (1 << i); + } + } + + /* Analyze NCQ error */ + ata_for_each_link(link, ap, EDGE) { + ehi = &link->eh_info; + eh_acquired = false; + + if (ehi->err_mask & AC_ERR_DEV) { + ehc = &link->eh_context; + ehc->i.err_mask |= AC_ERR_DEV; + + if (ap->host->eh_owner == NULL) { + ata_eh_acquire(ap); + eh_acquired = true; + } + + ata_eh_analyze_ncq_error(link); + + if (eh_acquired) { + ata_eh_release(ap); + } + } + } + + /* Add timeout flag back */ + for (i = 0; i < ATA_MAX_QUEUE; i++) { + if (qc_timeout_map & (1 << i)) { + qc = __ata_qc_from_tag(ap, i); + + qc->err_mask |= AC_ERR_TIMEOUT; + qc->flags |= ATA_QCFLAG_FAILED; + qc_timeout_map &= ~(1 << i); + } + } +} +#endif /* MY_ABC_HERE */ + /** * ata_scsi_cmd_error_handler - error callback for a list of commands * @host: scsi host containing the port @@ -620,6 +789,14 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, } } +#ifdef MY_ABC_HERE + if (nr_timedout && ap->nr_pmp_links) { + spin_unlock_irqrestore(ap->lock, flags); + syno_pmp_ncq_cmd_error_handler(ap); + spin_lock_irqsave(ap->lock, flags); + } +#endif /* MY_ABC_HERE */ + /* If we have timed out qcs. They belong to EH from * this point but the state of the controller is * unknown. Freeze the port to make sure the IRQ @@ -638,6 +815,887 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, } EXPORT_SYMBOL(ata_scsi_cmd_error_handler); +#ifdef MY_ABC_HERE + +/* Global value for spin up group */ +#ifdef MY_DEF_HERE +extern int gSynoHddPowerupSeq; +static unsigned long int gJiffiesLastPmOn = 0; +DEFINE_SPINLOCK(PmPendingLock); +#endif /* MY_DEF_HERE */ + +static int wake_up_deepsleep_internal(struct ata_port *ap) +{ + int ret = 0; + unsigned long flags = 0; + int iDeepCtlRet = -1; + int iRetry = 0; + + /* if not power off and irq off, we must power on it first */ + spin_lock_irqsave(ap->lock, flags); + if (!(ap->pflags & (ATA_PFLAG_SYNO_IRQ_OFF | ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE))) { + /* not irq off, bye */ + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } else { + if (ap->pflags & ATA_PFLAG_SYNO_DS_PWROFF) { + /* power off case, bye */ + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } + } + spin_unlock_irqrestore(ap->lock, flags); + + /* check if master locked, if locked we must wait here */ + spin_lock_irqsave(ap->lock, flags); + if (ap->pflags & ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH) { + DBGMESG("port %d eh locked, wait here\n", ap->print_id); + while(ap->pflags & ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ); + spin_lock_irqsave(ap->lock, flags); + } + } + /* lock master to prevent others do eh */ + ap->pflags |= ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH; + spin_unlock_irqrestore(ap->lock, flags); + +#ifdef MY_DEF_HERE + /* Spin up group control for disk deepsleep */ + if (gSynoHddPowerupSeq) { + spin_lock(&PmPendingLock); + if (SynoWakeInterval() > (jiffies - gJiffiesLastPmOn)) { + DBGMESG("disk %d will busy loop wait for other disk doing Power On Control\n", + ap->print_id); + + /* it is too close from last disk power on. */ + while (SynoWakeInterval() > (jiffies - gJiffiesLastPmOn)) { + spin_unlock(&PmPendingLock); + schedule_timeout_uninterruptible(HZ); + spin_lock(&PmPendingLock); + } + } + if (SynoDSleepNeedUpdateLastPmOn()) { + gJiffiesLastPmOn = jiffies; + } + spin_unlock(&PmPendingLock); + } +#endif /* MY_DEF_HERE */ + + ata_port_printk(ap, KERN_ERR, "wake up from deepsleep, reset link now\n"); + iDeepCtlRet = -1; + /* if it still in irq off state, we must power on it first */ + for (iRetry = 0; iDeepCtlRet && iRetry < ATA_PROBE_MAX_TRIES; ++iRetry) { + iDeepCtlRet = syno_libata_set_deep_sleep(ap, 0); + if (iDeepCtlRet) { + printk("port %d unset deepsleep fail, retry it\n", ap->print_id); + schedule_timeout_uninterruptible(7UL*HZ); + } + } + + /* TODO: ATA_PFLAG_SYNO_DS_WAKING means we are waking up from deepsleep + * Sometimes we need power on it again for workaround, so we need on this flag */ + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_SYNO_DS_WAKING; + spin_unlock_irqrestore(ap->lock, flags); + + /* after pm control and slaves flag set, clear master lock flags */ + if (0 != iDeepCtlRet) { + printk("port %d unset deepsleep after %d tries fail\n", + ap->print_id, ATA_PROBE_MAX_TRIES); + } else { + DBGMESG("port %d POWER ON clear\n", ap->print_id); + } + + // no matter unset deepsleep success or not, clear flag here + SynoFlagSet(ap, ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE, 0); + SynoFlagSet(ap, ATA_PFLAG_SYNO_IRQ_OFF, 0); + + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~(ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH); + spin_unlock_irqrestore(ap->lock, flags); + + ret = 1; + +END: + return ret; +} + +#ifdef MY_ABC_HERE +static int schedule_eunit_eh(struct ata_port *pAp_target) +{ + int iRet = -1; + struct ata_port *pAp = NULL; + + if (NULL == pAp_target || !syno_is_synology_pm(pAp_target)) { + goto END; + } + + if (!IS_SYNOLOGY_RX1223RP(pAp_target->PMSynoUnique)) { + iRet = 0; + goto END; + } + + while (NULL != (pAp = SynoEunitEnumPort(pAp_target, pAp? &pAp->ata_port_list: NULL))) { + // pAp_target already entered eh, do not trigger eh again + if (pAp_target != pAp) { + DBGMESG("Schedule EH for ata_port %d\n", pAp->print_id); + ata_port_schedule_eh(pAp); + } + } + + iRet = 0; +END: + return iRet; +} + +static int wake_up_deepsleep_eunit(struct ata_port *ap) +{ + int ret = 0; + unsigned long flags = 0; + struct ata_port *pAp_master = NULL; + int iDeepCtlRet = -1; + int iRetry = 0; + + /* find master first */ + pAp_master = SynoEunitFindMaster(ap); + + spin_lock_irqsave(ap->lock, flags); + if (NULL == pAp_master) { + ap->uiStsFlags |= SYNO_STATUS_EUNIT_MASTER_REFIND; + spin_unlock_irqrestore(ap->lock, flags); + printk("WARNING: port %d can't find master\n", ap->print_id); + goto END; + } + ap->uiStsFlags &= ~SYNO_STATUS_EUNIT_MASTER_REFIND; + spin_unlock_irqrestore(ap->lock, flags); + + /* check if master locked, if locked we must wait here */ + spin_lock_irqsave(pAp_master->lock, flags); + if (pAp_master->pflags & ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH) { + DBGMESG("port %d master %d eh locked, wait here\n", ap->print_id, pAp_master->print_id); + while(pAp_master->pflags & ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH) { + spin_unlock_irqrestore(pAp_master->lock, flags); + schedule_timeout_uninterruptible(HZ); + spin_lock_irqsave(pAp_master->lock, flags); + } + } + + /* if not power off and irq off, we must power on it first */ + /* we must check IRQ_OFF state after getting IRQOFF_LOCK_FOR_EH */ + /* because we have to assure that only one ata port triggers eunit poweron */ + if (!(pAp_master->pflags & (ATA_PFLAG_SYNO_IRQ_OFF | ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE))) { + /* not irq off, bye */ + spin_unlock_irqrestore(pAp_master->lock, flags); + goto SKIP; + } else { + if (pAp_master->pflags & ATA_PFLAG_SYNO_DS_PWROFF) { + /* power off case, bye */ + spin_unlock_irqrestore(pAp_master->lock, flags); + goto SKIP; + } + } + + /* lock master to prevent others do eh */ + pAp_master->pflags |= ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH; + spin_unlock_irqrestore(pAp_master->lock, flags); + + ata_port_printk(ap, KERN_ERR, "wake up from deepsleep, reset link now\n"); + iDeepCtlRet = -1; + /* if it still in irq off state, we must power on it first */ + for (iRetry = 0; iDeepCtlRet && iRetry < ATA_EH_PMP_TRIES; ++iRetry) { + iDeepCtlRet = syno_libata_set_deep_sleep(ap, 0); + if (iDeepCtlRet) { + printk("port %d unset deepsleep fail, retry it\n", ap->print_id); + schedule_timeout_uninterruptible(7UL*HZ); + } + } + + /* TODO: ATA_PFLAG_SYNO_DS_WAKING means we are waking up from deepsleep + * Sometimes we need power on it again for workaround, so we need on this flag */ + + if (!(pAp_master->uiStsFlags & SYNO_STATUS_DEEP_SLEEP_FAILED)) { + /* If wake up from deep sleep, raise flag for all slaves which any disk on it. DSM #105789 */ + SynoEunitFlagSet(pAp_master, 1, ATA_PFLAG_SYNO_DS_WAKING, 1); + } + + /* after pm control and slaves flag set, clear master lock flags */ + if (0 != iDeepCtlRet) { + printk("port %d unset deepsleep after %d tries fail [master %d]\n", + ap->print_id, ATA_EH_PMP_TRIES, pAp_master->print_id); + } else { + DBGMESG("port %d POWER ON clear master %d\n", ap->print_id, pAp_master->print_id); + } + // no matter unset deepsleep success or not, clear flag here + SynoEunitFlagSet(pAp_master, 0, ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE, 0); + SynoEunitFlagSet(pAp_master, 0, ATA_PFLAG_SYNO_IRQ_OFF, 0); + + // For some eunit, we have to trigger EH for other pmp manually. + schedule_eunit_eh(ap); + + spin_lock_irqsave(pAp_master->lock, flags); + pAp_master->pflags &= ~(ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH); + spin_unlock_irqrestore(pAp_master->lock, flags); + +SKIP: + ret = 1; + +END: + return ret; +} +#else /* MY_ABC_HERE */ +static inline int wake_up_deepsleep_eunit(struct ata_port *ap) +{ + return 0; +} +#endif /* MY_ABC_HERE */ + + +/** + * Wake up if ata_port is in deepsleep + * + * @param ap [IN] ata port + * + * @return 0: not in deepsleep + * 1: in deepsleep, and ata_port is waking now. + */ +static int wake_up_if_deepsleep(struct ata_port *ap) +{ + if (ap->nr_pmp_links) { + return wake_up_deepsleep_eunit(ap); + } else { + return wake_up_deepsleep_internal(ap); + } +} + +/** + * Clean up deepsleep related flags + * + * @param ap [IN] ata port + * + */ +static void clean_up_deepsleep_flag(struct ata_port *ap) +{ + unsigned long flags; + struct ata_port *pAp_master = NULL; + + pAp_master = ap; + +#ifdef MY_ABC_HERE + if (ap->nr_pmp_links) { + pAp_master = SynoEunitFindMaster(ap); + if (NULL == pAp_master) { + printk("WARNING: port %d can't find master\n", ap->print_id); + return; + } + } +#endif /* MY_ABC_HERE */ + + spin_lock_irqsave(ap->lock, flags); + if (ap->pflags & ATA_PFLAG_SYNO_DS_WAKING) { + ap->pflags &= ~ATA_PFLAG_SYNO_DS_WAKING; + if (0 == ap->nr_pmp_links) { + /* master only */ + struct ata_link *link = NULL; + ata_for_each_link(link, ap, HOST_FIRST) { + link->eh_context.i.flags &= ~ATA_EHI_QUIET; + } + ata_port_printk(ap, KERN_ERR, "wake up successful, the reset fail can be ignored\n"); + schedule_work(&(ap->SendDsleepWakeEventTask)); + } + } + spin_unlock_irqrestore(ap->lock, flags); + + spin_lock_irqsave(pAp_master->lock, flags); + if (pAp_master->pflags & ATA_PFLAG_SYNO_DS_PWROFF) { + pAp_master->pflags &= ~ATA_PFLAG_SYNO_DS_PWROFF; + } + pAp_master->uiStsFlags &= ~SYNO_STATUS_DEEP_SLEEP_FAILED; + spin_unlock_irqrestore(pAp_master->lock, flags); +} + +#ifdef MY_ABC_HERE +/* + * Event for user space + * + */ +void SendDsleepWakeEvent(struct work_struct *work) +{ + struct ata_port *ap = container_of(work, struct ata_port, SendDsleepWakeEventTask); + int iSynoDiskNameNumber = syno_libata_numeric_diskname_number_get(&(ap->link)); + + if (func_synobios_event_handler && (0 < iSynoDiskNameNumber)) { + func_synobios_event_handler(SYNO_EVENT_WAKE_FROM_DEEP_SLEEP, 2, iSynoDiskNameNumber, 0); + } + + return; +} +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void SendPortDisEvent(struct work_struct *work) +{ + DISK_PORT_TYPE diskType = UNKNOWN_DEVICE; + int slotNumber = 0; + struct ata_port *ap = NULL; +#ifdef MY_ABC_HERE + SYNO_DISK_PORT_LOST_TYPE type = PORT_LOST_UNKNOWN; +#endif /* MY_ABC_HERE */ + + ap = container_of(work, struct ata_port, SendPortDisEventTask); + if (NULL == func_synobios_event_handler || NULL == ap) { + goto END; + } + slotNumber = ap->syno_internal_slot_index + 1; + // FIXME: add support for m.2 sata cache + if (0 < slotNumber) { + diskType = INTERNAL_DEVICE; + } +#ifdef MY_ABC_HERE + else if (syno_is_synology_pm(ap)) { + diskType = EUNIT_DEVICE; + slotNumber = syno_external_libata_index_get(ap); + } +#endif /* MY_ABC_HERE */ + else { + diskType = EXTERNAL_SATA_DEVICE; + slotNumber = syno_external_libata_index_get(ap); + } + // FIXME: We only send disabled event from internal device and esata. + if (INTERNAL_DEVICE != diskType && EXTERNAL_SATA_DEVICE != diskType) { + goto END; + } + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_DISABLED, 3, diskType, slotNumber, ap->scsi_host->unique_id); + +#ifdef MY_ABC_HERE + if (INTERNAL_DEVICE != diskType) { + goto END; + } + + type = (ap->iPresentAfterError) ? + PORT_LOST_DISABLED_PRESENT : PORT_LOST_DISABLED; + + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, slotNumber, type); +#endif /* MY_ABC_HERE */ + +END: + return; +} + +void SendPwrResetEvent(struct work_struct *work) +{ + if (func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_DISK_PWR_RESET, 2, 0, 0); + } + + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* Only internal port would trigger this event */ +void SendPortRetryFailedEvent(struct work_struct *work) +{ + int slotNumber = 0; + struct ata_port *ap = NULL; + SYNO_DISK_PORT_LOST_TYPE type = PORT_LOST_UNKNOWN; + ap = container_of(work, struct ata_port, + SendPortRetryFailedEventTask); + if (NULL == func_synobios_event_handler || NULL == ap) { + goto END; + } + slotNumber = ap->syno_internal_slot_index + 1; + // Note: m.2 sata cache and esata would be treat as internal device. + if (0 >= slotNumber) { + goto END; + } + + type = (ap->iPresentAfterError) ? + PORT_LOST_RETRY_FAILED_PRESENT : PORT_LOST_RETRY_FAILED; + + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, slotNumber, type); +END: + return; +} + +/* Only internal port would trigger this event */ +void SendLinkDownEvent(struct work_struct *work) +{ + int slotNumber = 0; + struct ata_port *ap = NULL; + ap = container_of(work, struct ata_port, + SendLinkDownEventTask); + if (NULL == func_synobios_event_handler || NULL == ap) { + goto END; + } + slotNumber = ap->syno_internal_slot_index + 1; + // Note: m.2 sata cache and esata would be treat as internal device. + if (0 >= slotNumber) { + goto END; + } + + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, slotNumber, PORT_LOST_LINK_DOWN_PRESENT); +END: + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void SendSataErrEvent(struct work_struct *work) +{ + struct ata_link *link = container_of(work, struct ata_link, SendSataErrEventTask); + SYNOBIOS_EVENT_PARM parms = link->diskSataErrEventParm; + unsigned long syno_sata_error_lock_flags; + + if (func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_SATA_ERROR_REPORT, 6, parms.data[0], parms.data[1], parms.data[2], parms.data[3], parms.data[4], parms.data[5]); + } else { + SYNOBIOS_EVENT_ACTION_LIST *synobios_action = NULL; + synobios_action = (SYNOBIOS_EVENT_ACTION_LIST*)kzalloc(sizeof(SYNOBIOS_EVENT_ACTION_LIST), GFP_KERNEL); + memcpy(&synobios_action->parms, &parms, sizeof(parms)); + synobios_action->synobios_event_type = SYNO_EVENT_SATA_ERROR_REPORT; + spin_lock_irqsave(&syno_sata_error_lock, syno_sata_error_lock_flags); + list_add_tail(&synobios_action->list, &gSynoBiosEventHead); + spin_unlock_irqrestore(&syno_sata_error_lock, syno_sata_error_lock_flags); + } + + return; +} + +void SendDiskRetryEvent(struct work_struct *work) +{ + struct ata_port *ap = container_of(work, struct ata_port, SendDiskRetryEventTask); + + if (func_synobios_event_handler) { + // eunit is not support + // syno_libata_numeric_diskname_number_get return -1 when the sata device is in eunit + func_synobios_event_handler(SYNO_EVENT_DISK_RETRY_REPORT, 2, syno_libata_numeric_diskname_number_get(&ap->link), ap->nr_pmp_links); + } + + return; +} + +void SendDiskTimeoutEvent(struct work_struct *work) +{ + struct ata_link *link = container_of(work, struct ata_link, SendDiskTimeoutEventTask); + SYNOBIOS_EVENT_PARM parms = link->diskTimeoutEventParm; + unsigned long syno_sata_error_lock_flags; + + if (func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_DISK_TIMEOUT_REPORT, 6, parms.data[0], parms.data[1], parms.data[2], parms.data[3], parms.data[4], parms.data[5]); + } else { + SYNOBIOS_EVENT_ACTION_LIST *synobios_action = NULL; + synobios_action = (SYNOBIOS_EVENT_ACTION_LIST*)kzalloc(sizeof(SYNOBIOS_EVENT_ACTION_LIST), GFP_KERNEL); + memcpy(&synobios_action->parms, &parms, sizeof(parms)); + synobios_action->synobios_event_type = SYNO_EVENT_DISK_TIMEOUT_REPORT; + spin_lock_irqsave(&syno_sata_error_lock, syno_sata_error_lock_flags); + list_add_tail(&synobios_action->list, &gSynoBiosEventHead); + spin_unlock_irqrestore(&syno_sata_error_lock, syno_sata_error_lock_flags); + } + + return; +} + +void SendDiskSoftResetFailEvent(struct work_struct *work) +{ + struct ata_link *link = container_of(work, struct ata_link, SendDiskSoftResetFailEventTask); + SYNOBIOS_EVENT_PARM parms = link->diskSoftResetFailEventParm; + unsigned long syno_sata_error_lock_flags; + + if (func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_DISK_RESET_FAIL_REPORT, 6, parms.data[0], parms.data[1], parms.data[2], parms.data[3], parms.data[4], parms.data[5]); + } else { + SYNOBIOS_EVENT_ACTION_LIST *synobios_action = NULL; + synobios_action = (SYNOBIOS_EVENT_ACTION_LIST*)kzalloc(sizeof(SYNOBIOS_EVENT_ACTION_LIST), GFP_KERNEL); + memcpy(&synobios_action->parms, &parms, sizeof(parms)); + synobios_action->synobios_event_type = SYNO_EVENT_DISK_RESET_FAIL_REPORT; + spin_lock_irqsave(&syno_sata_error_lock, syno_sata_error_lock_flags); + list_add_tail(&synobios_action->list, &gSynoBiosEventHead); + spin_unlock_irqrestore(&syno_sata_error_lock, syno_sata_error_lock_flags); + } + + return; +} + +void SendDiskHardResetFailEvent(struct work_struct *work) +{ + struct ata_link *link = container_of(work, struct ata_link, SendDiskHardResetFailEventTask); + SYNOBIOS_EVENT_PARM parms = link->diskHardResetFailEventParm; + unsigned long syno_sata_error_lock_flags; + + if (func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_DISK_RESET_FAIL_REPORT, 6, parms.data[0], parms.data[1], parms.data[2], parms.data[3], parms.data[4], parms.data[5]); + } else { + SYNOBIOS_EVENT_ACTION_LIST *synobios_action = NULL; + synobios_action = (SYNOBIOS_EVENT_ACTION_LIST*)kzalloc(sizeof(SYNOBIOS_EVENT_ACTION_LIST), GFP_KERNEL); + memcpy(&synobios_action->parms, &parms, sizeof(parms)); + synobios_action->synobios_event_type = SYNO_EVENT_DISK_RESET_FAIL_REPORT; + spin_lock_irqsave(&syno_sata_error_lock, syno_sata_error_lock_flags); + list_add_tail(&synobios_action->list, &gSynoBiosEventHead); + spin_unlock_irqrestore(&syno_sata_error_lock, syno_sata_error_lock_flags); + } + + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void SendDiskPowerShortBreakEvent(struct work_struct *work) +{ + struct ata_port *ap = container_of(work, struct ata_port, SendDiskPowerShortBreakEventTask); + + DISK_PORT_TYPE diskType = UNKNOWN_DEVICE; + int slotNumber = 0, iPMSynoEMID = 0; + if (NULL == func_synobios_event_handler || NULL == ap) { + goto END; + } + get_disk_port_type_and_index_by_ata_port(ap, &diskType, &slotNumber); +#ifdef MY_ABC_HERE + if (syno_is_synology_pm(ap)) { + iPMSynoEMID = ap->PMSynoEMID; + } +#endif /* MY_ABC_HERE */ + + func_synobios_event_handler(SYNO_EVENT_DSIK_POWER_SHORT_BREAK, 4, diskType, slotNumber, iPMSynoEMID, ap->uSynoPMPErrorPort); +END: + + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +bool wcache_is_enable (struct ata_port *ap) +{ + struct ata_link *link = NULL; + struct ata_device *dev = NULL; + + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, link, ALL) { + if (ata_dev_enabled(dev) && ATA_DEV_ATA == dev->class) { + if (!(dev->flags & ATA_DFLAG_NO_WCACHE)) { + return true; + } + continue; + } + } + } + + /* all disk write cache disable */ + return false; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int iSynoCountPwrReset(struct ata_device *dev, int iSet) +{ + int iRet = -1; + + if (!dev) { + goto END; + } + + if (iSet) { + dev->iResetPwrCount += iSet; + } else { + dev->iResetPwrCount = 0; + } + +END: + return iRet; +} + +static void power_reset_record(struct ata_port *ap, bool need_notify) +{ + struct ata_link *link = NULL; + struct ata_device *dev = NULL; + + if (!iIsSynoDeepSleepSupport(ap)) { + goto END; + } + + /* count the number of disk reset power */ + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, link, ALL) { + iSynoCountPwrReset(dev, 1); + } + } + +#ifdef MY_ABC_HERE + /* send event */ + if (need_notify) { + schedule_work(&(ap->SendPwrResetEventTask)); + } +#endif /* MY_ABC_HERE */ + +END: + return; +} + +void syno_sata_deep_retry (struct ata_port *ap) +{ + int iDeepCtlRet = -1; + bool need_notify = false; + + /* if the port doesn't support deep sleep, give up */ + if (!iIsSynoDeepSleepSupport(ap)) { + ap->syno_recover_tries = 0; + goto END; + } + + ata_port_printk(ap, KERN_ERR, "do deep tries %d\n", ap->syno_recover_tries); + +#ifdef MY_ABC_HERE + /* + * if we reset disk power and the write cache is on, + * we must record the count and send the event + * for scemd to check if the volume need to do fsck or not + */ + need_notify = true; + +#ifdef MY_ABC_HERE + /* FIXME: + * I don't know how to refine these code. + * + * SYNO_SATA_WCACHE_DISABLE should be not depended on + * MY_DEF_HERE and vice versa. + * + * So I set default "on" and then overriding the value if + * the disk write cache is "off". + **/ + need_notify = wcache_is_enable(ap); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + + /* power off */ + iDeepCtlRet = syno_libata_set_deep_sleep(ap, 1); + if (iDeepCtlRet) { + /* if power off fail, give up */ + ata_port_printk(ap, KERN_ERR, "set deepsleep fail, can't recover, give up\n"); + ap->syno_recover_tries = 0; + goto END; + } + + /* wait for a while */ + /* FIXME: hard code delay 11s, old kernel use 7s*/ + schedule_timeout_uninterruptible(11UL*HZ); + + /* power on */ + wake_up_if_deepsleep(ap); + + /* clean up flags at here, don't mixup with normal deep sleep waking */ + clean_up_deepsleep_flag(ap); + + /* record event */ + power_reset_record(ap, need_notify); + +END: + return; +} +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE +static void syno_sata_recover_mechanism (struct ata_port *ap) +{ + unsigned long flags; + + /* XXX: + * ap->uiSflags != 0 means libata error handling had some fail. + * syno_recover_max_tries > 0 means we have special recover method. + * + **/ + spin_lock_irqsave(ap->lock, flags); + if (ap->uiSflags && (ap->syno_recover_max_tries > 0)) { + ap->eh_tries = 1; /* FIXME: set eh_tries to 1 to prevent it retry recursively */ + } else { + ap->syno_recover_tries = 0; + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } + spin_unlock_irqrestore(ap->lock, flags); + +#ifdef MY_ABC_HERE + /* + * --- Record retry events --- + */ + if(ap->syno_recover_tries == ap->syno_recover_max_tries) { + /* first time the port enter our retry mechanism */ + schedule_work(&(ap->SendDiskRetryEventTask)); + } +#endif /* MY_ABC_HERE */ + + /* already fail, let it go */ + if (ap->syno_recover_tries == 0) { + ata_port_printk(ap, KERN_ERR, "==== port retry failed ====\n"); + +#ifdef MY_ABC_HERE + /* check disk present */ + syno_ata_present_print(ap, "port retry failed"); + /* send event */ + schedule_work(&(ap->SendPortRetryFailedEventTask)); +#endif /* MY_ABC_HERE */ + + goto END; + } + + /* + * --- try to recover --- + */ + ap->uiSflags = 0; + if (ap->ops->syno_recover) { + ap->ops->syno_recover(ap); + } + +END: + return; +} + +static void syno_sata_recover_mechanism_cleanup (struct ata_port *ap) +{ + unsigned long flags; + struct ata_link *link = NULL; + struct ata_device *dev = NULL; + + /* + * --- force detach --- + */ + if (ap->uiSflags) { + /* clear port error flags */ + DBGMESG("ata%u: detect error flags 0x%x\n", ap->print_id, ap->uiSflags); + ap->uiSflags = 0; + + /* if had on our action flag, we must take action now. Some action may cause deadlock (ex.detach), + * so we must unlock now. */ + ata_for_each_link(link, ap, EDGE) { + link->uiSflags = 0; + ata_for_each_dev(dev, link, ALL) { + if (dev->ulSflags & ATA_SYNO_DFLAG_PMP_DETACH) { + ata_dev_printk(dev, KERN_WARNING, + "force pmp detach\n"); + sata_pmp_detach(dev); + } + if (dev->ulSflags & ATA_SYNO_DFLAG_DETACH) { + ata_dev_printk(dev, KERN_WARNING, + "force dev detach\n"); + ata_eh_detach_dev(dev); + } + if (dev->ulSflags & ATA_SYNO_DFLAG_DISABLE) { + ata_dev_printk(dev, KERN_WARNING, + "force dev disable\n"); + ata_dev_disable(dev); + } + dev->ulSflags = 0; + } + } + } + + /* + * --- clean up flags --- + */ + /* FIXME: I can't find another properly place to clear them. + * So I clear them here when EH complete and no error flags */ + spin_lock_irqsave(ap->lock, flags); + ap->uiSflags = 0; + ata_for_each_link(link, ap, EDGE) { + link->uiSflags = 0; + ata_for_each_dev(dev, link, ALL) { + dev->ulSflags = 0; + } + } + spin_unlock_irqrestore(ap->lock, flags); + + /* + * --- port disabled Handle --- + */ + if (ap->pflags & ATA_PFLAG_FROZEN && 0 == ap->scsi_host->host_eh_scheduled) { + ata_port_printk(ap, KERN_ERR, "port disabled\n"); + + /* FIXME: + * syno_ata_present_print need to be executed first to provide information + * to SendPortDisEventTask, but these two configs have no dependency. + */ +#ifdef MY_ABC_HERE + /* check disk present */ + syno_ata_present_print(ap, "port disabled"); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* send event */ + schedule_work(&(ap->SendPortDisEventTask)); +#endif /* MY_ABC_HERE */ + } +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +unsigned int syno_get_ata_enabled_dev_bitmap(struct ata_port *ap) +{ + struct ata_link *link = NULL; + struct ata_device *dev = NULL; + int i = 0; + unsigned int uiRet = 0; + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, link, ALL) { + +#ifdef MY_ABC_HERE + /* skip the disks which we marked error */ + if(dev->ulSflags) { + ++i; + continue; + } +#endif /* MY_ABC_HERE */ + + uiRet |= (ata_dev_enabled(dev)) << i; + ++i; + } + } + + return uiRet; +} + +static void check_power_short_break(struct ata_port *ap) +{ + bool iIsWriteCacheOn = false; + + if (!ap->blSynoDiskHotplugEvent) { + goto END; + } + +#ifdef MY_ABC_HERE + /* deep sleep event, skip it */ + if (ap->pflags & ATA_PFLAG_SYNO_DS_WAKING) { + goto END; + } +#endif /* MY_ABC_HERE */ + + iIsWriteCacheOn = true; +#ifdef MY_ABC_HERE + /* FIXME: + * I don't know how to refine these code. + * + * SYNO_SATA_WCACHE_DISABLE should be not depended on + * MY_DEF_HERE and vice versa. + * + * So I set default "on" and then overriding the value if + * the disk write cache is "off". + **/ + iIsWriteCacheOn = wcache_is_enable(ap); +#endif /* MY_ABC_HERE */ + + /* skip if disk write cache off */ + if (!iIsWriteCacheOn) { + goto END; + } + + if (ap->ulSynoPortEnabledBitmap == syno_get_ata_enabled_dev_bitmap(ap)) { + schedule_work(&(ap->SendDiskPowerShortBreakEventTask)); + } +END: + return; +} +#endif /* MY_ABC_HERE */ + /** * ata_scsi_port_error_handler - recover the port after the commands * @host: SCSI host containing the port @@ -650,6 +1708,49 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) { unsigned long flags; +#ifdef MY_ABC_HERE + struct ata_link *reset_link = NULL; + int iDiskPortType = 0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + DISK_PORT_TYPE diskPortType = UNKNOWN_DEVICE; + int iDiskPortIndex = -1; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + int is_waking = 0; + + /* + * Check and wake up from deep sleep + */ + is_waking = wake_up_if_deepsleep(ap); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* SYNO PMP command working, don't invoke error handler */ + spin_lock_irqsave(ap->lock, flags); + while (ap->pflags & ATA_PFLAG_PMP_PMCTL) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ); + spin_lock_irqsave(ap->lock, flags); + } + spin_unlock_irqrestore(ap->lock, flags); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* + * --- port freeze handle --- + */ + // XXX: see old kernel code + + + /* init retry times at eh start */ + ap->syno_recover_tries = ap->syno_recover_max_tries; + +syno_recover_repeat: +#endif /* MY_ABC_HERE */ + /* invoke error handler */ if (ap->ops->error_handler) { struct ata_link *link; @@ -674,6 +1775,12 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) link->eh_context.i = link->eh_info; memset(&link->eh_info, 0, sizeof(link->eh_info)); +#ifdef MY_ABC_HERE + if (is_waking) { + link->eh_context.i.flags |= ATA_EHI_QUIET; + } +#endif /* MY_ABC_HERE */ + ata_for_each_dev(dev, link, ENABLED) { int devno = dev->devno; @@ -740,7 +1847,25 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) scsi_eh_flush_done_q(&ap->eh_done_q); +#ifdef MY_ABC_HERE + syno_sata_recover_mechanism(ap); + if (ap->syno_recover_tries > 0) { + --ap->syno_recover_tries; + /* repeat normal reset flow */ + goto syno_recover_repeat; + } + syno_sata_recover_mechanism_cleanup(ap); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + check_power_short_break(ap); +#endif /* MY_ABC_HERE */ + /* clean up */ +#ifdef MY_ABC_HERE + /* note: already spinlock in clean_up_deepsleep_flag */ + clean_up_deepsleep_flag(ap); +#endif /* MY_ABC_HERE */ spin_lock_irqsave(ap->lock, flags); if (ap->pflags & ATA_PFLAG_LOADING) @@ -748,12 +1873,73 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) && !(ap->flags & ATA_FLAG_SAS_HOST)) schedule_delayed_work(&ap->hotplug_task, 0); +#ifdef MY_ABC_HERE + else if (ap->pflags & ATA_PFLAG_PMP_DISCONNECT || + ap->pflags & ATA_PFLAG_PMP_CONNECT) { + /* Clear unused PMP event when no ATA_PFLAG_SCSI_HOTPLUG */ + schedule_delayed_work(&ap->hotplug_task, 0); + } +#endif /* MY_ABC_HERE */ if (ap->pflags & ATA_PFLAG_RECOVERED) ata_port_info(ap, "EH complete\n"); ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED); +#ifdef MY_ABC_HERE + ap->ulSynoPortEnabledBitmap = syno_get_ata_enabled_dev_bitmap(ap); + ap->blSynoDiskHotplugEvent = false; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (ap->pflags & ATA_PFLAG_SYNO_BOOT_PROBE) { + ap->pflags &= ~ATA_PFLAG_SYNO_BOOT_PROBE; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + get_disk_port_type_and_index_by_ata_port(ap, &diskPortType, &iDiskPortIndex); + iDiskPortType = (int) diskPortType; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ata_for_each_link(reset_link, ap, EDGE) { + if (SYNO_DISK_RESET_FAIL_REPORT_COUNT <= reset_link->uiSoftResetFailCount) { + memset(&reset_link->diskSoftResetFailEventParm, 0, sizeof(reset_link->diskSoftResetFailEventParm)); + reset_link->diskSoftResetFailEventParm.data[0] = syno_libata_numeric_diskname_number_get(reset_link); + reset_link->diskSoftResetFailEventParm.data[1] = ap->nr_pmp_links; + reset_link->diskSoftResetFailEventParm.data[2] = reset_link->pmp; + reset_link->diskSoftResetFailEventParm.data[3] = 0; + reset_link->diskSoftResetFailEventParm.data[4] = reset_link->uiSoftResetFailCount; + reset_link->diskSoftResetFailEventParm.data[5] = iDiskPortType; + schedule_work(&(reset_link->SendDiskSoftResetFailEventTask)); + } + if (SYNO_DISK_RESET_FAIL_REPORT_COUNT <= reset_link->uiHardResetFailCount) { + memset(&reset_link->diskHardResetFailEventParm, 0, sizeof(reset_link->diskHardResetFailEventParm)); + reset_link->diskHardResetFailEventParm.data[0] = syno_libata_numeric_diskname_number_get(reset_link);; + reset_link->diskHardResetFailEventParm.data[1] = ap->nr_pmp_links; + reset_link->diskHardResetFailEventParm.data[2] = reset_link->pmp; + reset_link->diskHardResetFailEventParm.data[3] = 1; + reset_link->diskHardResetFailEventParm.data[4] = reset_link->uiHardResetFailCount; + reset_link->diskHardResetFailEventParm.data[5] = iDiskPortType; + schedule_work(&(reset_link->SendDiskHardResetFailEventTask)); + } + reset_link->uiSoftResetFailCount = 0; + reset_link->uiHardResetFailCount = 0; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if(syno_is_synology_pm(ap) && IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique) && 0 == ap->PMSynoEMID) { + if (ap->scsi_host && func_synobios_event_handler) { + DBGMESG("PMP eh trigger synobios event, host_no = %d\n", ap->scsi_host->host_no); + func_synobios_event_handler(SYNO_EVENT_EBOX_RESET, 1, ap->scsi_host->host_no); + } else { + DBGMESG("PMP eh trigger synobios event, scsi host is NULL\n"); + } + } +#endif /* MY_ABC_HERE */ + /* tell wait_eh that we're done */ ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS; wake_up_all(&ap->eh_wait_q); @@ -806,6 +1992,10 @@ static int ata_eh_nr_in_flight(struct ata_port *ap) /* count only non-internal commands */ ata_qc_for_each(ap, qc, tag) { if (qc) +#ifdef MY_ABC_HERE + /* Don't count Synology special command */ + if (!syno_qc_filter(qc)) +#endif /* MY_ABC_HERE */ nr++; } @@ -1209,6 +2399,16 @@ void ata_dev_disable(struct ata_device *dev) if (!ata_dev_enabled(dev)) return; +#ifdef MY_ABC_HERE + if (dev->link->uiSflags && ata_dev_enabled(dev)) { + ata_dev_printk(dev, KERN_WARNING, + "still have recovery flags link 0x%x ap 0x%x, don't disabled it\n", dev->link->uiSflags, dev->link->ap->uiSflags); + dev->ulSflags |= ATA_SYNO_DFLAG_DISABLE; + return; + } + dev->ulSflags &= ~ATA_SYNO_DFLAG_DISABLE; +#endif /* MY_ABC_HERE */ + if (ata_msg_drv(dev->link->ap)) ata_dev_warn(dev, "disabled\n"); ata_acpi_on_disable(dev); @@ -1238,6 +2438,16 @@ void ata_eh_detach_dev(struct ata_device *dev) struct ata_eh_context *ehc = &link->eh_context; unsigned long flags; +#ifdef MY_ABC_HERE + if (dev->link->uiSflags && ata_dev_enabled(dev)) { + ata_dev_printk(dev, KERN_WARNING, + "still have recovery flags link 0x%x ap 0x%x, don't detach it\n", dev->link->uiSflags, dev->link->ap->uiSflags); + dev->ulSflags |= ATA_SYNO_DFLAG_DETACH; + return; + } + dev->ulSflags &= ~ATA_SYNO_DFLAG_DETACH; +#endif /* MY_ABC_HERE */ + ata_dev_disable(dev); spin_lock_irqsave(ap->lock, flags); @@ -1501,6 +2711,9 @@ static void ata_eh_analyze_serror(struct ata_link *link) u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; u32 hotplug_mask; +#ifdef MY_ABC_HERE + struct ata_port *ap = link->ap; +#endif /* MY_ABC_HERE */ if (serror & (SERR_PERSISTENT | SERR_DATA)) { err_mask |= AC_ERR_ATA_BUS; @@ -1528,10 +2741,40 @@ static void ata_eh_analyze_serror(struct ata_link *link) hotplug_mask = SERR_PHYRDY_CHG; if (serror & hotplug_mask) +#ifdef MY_ABC_HERE + { + ap->blSynoDiskHotplugEvent = true; + ap->uSynoPMPErrorPort = link->pmp; ata_ehi_hotplugged(&ehc->i); + } +#else /* MY_ABC_HERE */ + ata_ehi_hotplugged(&ehc->i); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + // if uiJM585DubiosIFSProtoFlag has any flags, we might need to remove proto and check ncq log for determining the error + // for host link (internal slot and pmp link 15), we check for only hsm error and reset action. + // This represents that only proto error is set in previos analysis. + // for pmp link, there should be no error, so no action should be set. + if (ata_is_host_link(link) && + ((ATA_SYNO_FLAG_JM585_READ_LOG | ATA_SYNO_FLAG_JM585_UNC) & ehc->i.uiJM585DubiosIFSProtoFlag) && + (AC_ERR_HSM == err_mask && ATA_EH_RESET == action && !(serror & hotplug_mask))) { + // remove proto and ata_bus_error from IFS + ehc->i.serror &= ~SERR_PROTOCOL; + ehc->i.err_mask &= ~AC_ERR_ATA_BUS; + ehc->i.action &= ~ATA_EH_RESET; + if (ATA_SYNO_FLAG_JM585_UNC & ehc->i.uiJM585DubiosIFSProtoFlag) { + ehc->i.uiJM585DubiosIFSProtoFlag = 0; + } + } else { + // if there is other error, then go with original error handler. + ehc->i.err_mask |= err_mask; + ehc->i.action |= action; + } +#else /* MY_ABC_HERE */ ehc->i.err_mask |= err_mask; ehc->i.action |= action; +#endif /* MY_ABC_HERE */ } /** @@ -1920,12 +3163,25 @@ static void ata_eh_link_autopsy(struct ata_link *link) int tag, nr_failed = 0, nr_quiet = 0; u32 serror; int rc; +#ifdef MY_ABC_HERE + struct ata_eh_context *host_ehc = &ap->link.eh_context; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int ncq_err_tag = ATA_MAX_QUEUE; +#endif /* MY_ABC_HERE */ DPRINTK("ENTER\n"); if (ehc->i.flags & ATA_EHI_NO_AUTOPSY) return; +#ifdef MY_ABC_HERE + // We restore IFS error on JMB585, this makes ata port be frozen and cause the read ncq log failed. + if ((ap->pflags & ATA_PFLAG_FROZEN) && host_ehc->i.uiJM585DubiosIFSProtoFlag) { + ata_eh_thaw_port(ap); + } +#endif /* MY_ABC_HERE */ + /* obtain and analyze SError */ rc = sata_scr_read(link, SCR_ERROR, &serror); if (rc == 0) { @@ -1947,6 +3203,19 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |= ehc->i.err_mask; +#ifdef MY_ABC_HERE + /* Find actually NCQ error tag */ + ata_qc_for_each_raw(ap, qc, tag) { + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + + if (qc->err_mask & (AC_ERR_DEV | AC_ERR_NCQ)) { + ncq_err_tag = tag; + break; + } + } +#endif /* MY_ABC_HERE */ + ata_qc_for_each_raw(ap, qc, tag) { if (!(qc->flags & ATA_QCFLAG_FAILED) || ata_dev_phys_link(qc->dev) != link) @@ -1958,11 +3227,38 @@ static void ata_eh_link_autopsy(struct ata_link *link) /* analyze TF */ ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf); +#ifdef MY_ABC_HERE + if (qc->err_mask && + (ATA_SYNO_FLAG_JM585_READ_LOG & ehc->i.uiJM585DubiosIFSProtoFlag)) { + // Only MEDIA error is handle by the workaround. If there is other error, we return to use original error handler. + if ((AC_ERR_MEDIA | AC_ERR_NCQ | AC_ERR_DEV) == qc->err_mask) { + host_ehc->i.uiJM585DubiosIFSProtoFlag |= ATA_SYNO_FLAG_JM585_UNC; + } else { + ehc->i.uiJM585DubiosIFSProtoFlag &= ~ATA_SYNO_FLAG_JM585_READ_LOG; + host_ehc->i.uiJM585DubiosIFSProtoFlag |= ATA_SYNO_FLAG_JM585_OTHER_ERR; + qc->err_mask |= AC_ERR_ATA_BUS | AC_ERR_HSM; + ehc->i.action |= ATA_EH_RESET; + } + } +#endif /* MY_ABC_HERE */ + /* DEV errors are probably spurious in case of ATA_BUS error */ if (qc->err_mask & AC_ERR_ATA_BUS) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA | AC_ERR_INVALID); +#ifdef MY_ABC_HERE + /* Replace involved error */ + if (ncq_err_tag != ATA_MAX_QUEUE){ + if (qc->err_mask & AC_ERR_MEDIA && tag != ncq_err_tag) { + qc->err_mask &= ~AC_ERR_MEDIA; + qc->err_mask |= AC_ERR_TIMEOUT; + + ata_link_err(link, "Replace tag %d involved Media Error to Timeout\n", tag); + } + } +#endif /* MY_ABC_HERE */ + /* any real error trumps unknown error */ if (qc->err_mask & ~AC_ERR_OTHER) qc->err_mask &= ~AC_ERR_OTHER; @@ -1993,9 +3289,37 @@ static void ata_eh_link_autopsy(struct ata_link *link) } /* If all failed commands requested silence, then be quiet */ - if (nr_quiet == nr_failed) + if (nr_quiet == nr_failed +#ifdef MY_ABC_HERE + && nr_failed != 0 +#endif /* MY_ABC_HERE */ + ) ehc->i.flags |= ATA_EHI_QUIET; +#ifdef MY_ABC_HERE + if ((ATA_SYNO_FLAG_JM585_OTHER_ERR & host_ehc->i.uiJM585DubiosIFSProtoFlag)) { + host_ehc->i.uiJM585DubiosIFSProtoFlag &= ~ATA_SYNO_FLAG_JM585_UNC; + } else if ((ATA_SYNO_FLAG_JM585_READ_LOG & host_ehc->i.uiJM585DubiosIFSProtoFlag) && + !(ATA_SYNO_FLAG_JM585_UNC & host_ehc->i.uiJM585DubiosIFSProtoFlag)) { + // it is a error, if we cannot determine the error is UNC or other errors. + host_ehc->i.uiJM585DubiosIFSProtoFlag |= ATA_SYNO_FLAG_JM585_OTHER_ERR; + } + // if ATA_SYNO_FLAG_JM585_HOST_UNC is not set, this means that we did not get media error in ncq log. + // Therefore, we return to original error handler and freeze the ata port + if (ata_is_host_link(link) && + (ATA_SYNO_FLAG_JM585_OTHER_ERR & host_ehc->i.uiJM585DubiosIFSProtoFlag)) { + ehc->i.err_mask |= AC_ERR_ATA_BUS | AC_ERR_HSM; + ehc->i.serror |= SERR_PROTOCOL; + ehc->i.action |= ATA_EH_RESET; + __ata_port_freeze(ap); + } + + // Removed workaround flags for next error + if (ehc->i.uiJM585DubiosIFSProtoFlag) { + ehc->i.uiJM585DubiosIFSProtoFlag = 0; + } +#endif /* MY_ABC_HERE */ + /* enforce default EH actions */ if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) @@ -2029,6 +3353,18 @@ static void ata_eh_link_autopsy(struct ata_link *link) ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask); } + +#ifdef MY_ABC_HERE + /* Skip PMP Hardreset on JMB575 */ + if (!syno_pm_is_jmb575(sata_pmp_gscr_vendor(link->ap->link.device->gscr), sata_pmp_gscr_devid(link->ap->link.device->gscr))){ + if (ap->nr_pmp_links && + ehc->i.serror & SERR_PHYRDY_CHG && + ehc->i.serror & SERR_COMM_WAKE) { + ap->link.eh_context.i.action |= ATA_EH_HARDRESET; + } + } +#endif /* MY_ABC_HERE */ + DPRINTK("EXIT\n"); } @@ -2217,6 +3553,15 @@ static void ata_eh_link_report(struct ata_link *link) const char *frozen, *desc; char tries_buf[6] = ""; int tag, nr_failed = 0; +#ifdef MY_ABC_HERE + bool blTimeout = false; + bool blRWCmd = true; + int iDiskPortType = 0; +#ifdef MY_ABC_HERE + DISK_PORT_TYPE diskPortType = UNKNOWN_DEVICE; + int iDiskPortIndex = -1; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ if (ehc->i.flags & ATA_EHI_QUIET) return; @@ -2287,6 +3632,10 @@ static void ata_eh_link_report(struct ata_link *link) ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : ""); #endif +#ifdef MY_ABC_HERE + link->uiSError = ehc->i.serror; +#endif /* MY_ABC_HERE */ + ata_qc_for_each_raw(ap, qc, tag) { struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; char data_buf[20] = ""; @@ -2354,6 +3703,15 @@ static void ata_eh_link_report(struct ata_link *link) descr); } +#ifdef MY_ABC_HERE + if (qc->err_mask & AC_ERR_TIMEOUT) { + blTimeout = true; + if (false == is_ata_read_write_cmd(cmd->command)) { + blRWCmd = false; + } + } +#endif /* MY_ABC_HERE */ + ata_dev_err(qc->dev, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "tag %d%s\n %s" @@ -2395,7 +3753,45 @@ static void ata_eh_link_report(struct ata_link *link) res->feature & ATA_IDNF ? "IDNF " : "", res->feature & ATA_ABORTED ? "ABRT " : ""); #endif + +#ifdef MY_ABC_HERE + if (cmd->command != ATA_CMD_PACKET && + (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | ATA_ABORTED))) { + link->uiError = res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | ATA_ABORTED); + } else { + link->uiError = 0; + } +#endif /* MY_ABC_HERE */ } + +#ifdef MY_ABC_HERE + +#ifdef MY_ABC_HERE + get_disk_port_type_and_index_by_ata_port(ap, &diskPortType, &iDiskPortIndex); + iDiskPortType = (int) diskPortType; +#endif /* MY_ABC_HERE */ + + /* Send error event */ + memset(&link->diskSataErrEventParm, 0, sizeof(link->diskSataErrEventParm)); + link->diskSataErrEventParm.data[0] = syno_libata_numeric_diskname_number_get(link); + link->diskSataErrEventParm.data[1] = ap->nr_pmp_links; + link->diskSataErrEventParm.data[2] = link->pmp; + link->diskSataErrEventParm.data[3] = link->uiSError; + link->diskSataErrEventParm.data[4] = link->uiError; + link->diskSataErrEventParm.data[5] = iDiskPortType; + schedule_work(&(link->SendSataErrEventTask)); + + if (true == blTimeout) { + memset(&link->diskTimeoutEventParm, 0, sizeof(link->diskTimeoutEventParm)); + link->diskTimeoutEventParm.data[0] = syno_libata_numeric_diskname_number_get(link); + link->diskTimeoutEventParm.data[1] = ap->nr_pmp_links; + link->diskTimeoutEventParm.data[2] = link->pmp; + link->diskTimeoutEventParm.data[3] = blRWCmd; + link->diskTimeoutEventParm.data[4] = 0x0; + link->diskTimeoutEventParm.data[5] = iDiskPortType; + schedule_work(&(link->SendDiskTimeoutEventTask)); + } +#endif /* MY_ABC_HERE */ } /** @@ -2584,8 +3980,13 @@ int ata_eh_reset(struct ata_link *link, int classify, if (reset) { if (verbose) +#ifdef MY_ABC_HERE + ata_link_warn(link, "%s resetting link\n", + reset == softreset ? "soft" : "hard"); +#else /* MY_ABC_HERE */ ata_link_info(link, "%s resetting link\n", reset == softreset ? "soft" : "hard"); +#endif /* MY_ABC_HERE */ /* mark that this EH session started with reset */ ehc->last_reset = jiffies; @@ -2605,7 +4006,11 @@ int ata_eh_reset(struct ata_link *link, int classify, int tmp; if (verbose) +#ifdef MY_ABC_HERE + ata_link_warn(slave, "hard resetting link\n"); +#else /* MY_ABC_HERE */ ata_link_info(slave, "hard resetting link\n"); +#endif /* MY_ABC_HERE */ ata_eh_about_to_do(slave, NULL, ATA_EH_RESET); tmp = ata_do_reset(slave, reset, classes, deadline, @@ -2711,6 +4116,15 @@ int ata_eh_reset(struct ata_link *link, int classify, if (ap->pflags & ATA_PFLAG_FROZEN) ata_eh_thaw_port(ap); +#ifdef MY_ABC_HERE + if (ap->nr_pmp_links > 0 && sata_scr_read(link, SCR_STATUS, &sstatus) == 0) { + if (((sstatus >> 4) & 0xf) != link->sata_spd) { + printk("Rescan sata_spd\n"); + link->sata_spd = (sstatus >> 4) & 0xf; + } + } +#endif /* MY_ABC_HERE */ + /* * Make sure onlineness and classification result correspond. * Hotplug could have happened during reset and some @@ -2773,9 +4187,34 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->pflags &= ~ATA_PFLAG_RESETTING; spin_unlock_irqrestore(ap->lock, flags); +#ifdef MY_ABC_HERE + spin_lock_irqsave(ap->lock, flags); + if (!rc && link->uiSflags) { + /* + * reset done, clear all the link flags including: + * ATA_SYNO_FLAG_SRST_FAIL, ATA_SYNO_FLAG_COMRESET_FAIL, + * and ATA_SYNO_FLAG_GSCR_FAIL + */ + ata_link_printk(link, KERN_ERR, "link reset sucessfully clear error flags\n"); + link->uiSflags = 0; + } + spin_unlock_irqrestore(ap->lock, flags); +#endif /* MY_ABC_HERE */ + return rc; fail: +#ifdef MY_ABC_HERE + /* record reset fail */ + if (failed_link) { + if (reset == softreset) { + failed_link->uiSoftResetFailCount++; + } else { + failed_link->uiHardResetFailCount++; + } + } +#endif /* MY_ABC_HERE */ + /* if SCR isn't accessible on a fan-out port, PMP needs to be reset */ if (!ata_is_host_link(link) && sata_scr_read(link, SCR_STATUS, &sstatus)) @@ -2982,6 +4421,10 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, * thaw and ignore the device. */ ata_eh_thaw_port(ap); +#ifdef MY_ABC_HERE + ata_link_err(link, "Issued IDENTIFY to non-existent device ?!\n"); + goto err; +#endif /* MY_ABC_HERE */ break; default: goto err; @@ -3024,6 +4467,13 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, ehc->i.flags |= ATA_EHI_SETMODE; } +#ifdef MY_ABC_HERE + if (ap->uiSflags & ATA_SYNO_FLAG_REVALID_FAIL) { + DBGMESG("port %d revalid sucessfully , clear revalid fail flag\n", ap->print_id); + ap->uiSflags &= ~ATA_SYNO_FLAG_REVALID_FAIL; + } +#endif /* MY_ABC_HERE */ + return 0; err: @@ -3168,7 +4618,11 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev) return 0; /* if the device failed it, it should be reported to upper layers */ - if (qc->err_mask & AC_ERR_DEV) +#ifdef MY_ABC_HERE + if ((qc->err_mask & AC_ERR_DEV) && ATA_DEV_UNKNOWN == dev->class) +#else /* MY_ABC_HERE */ + if (qc->err_mask & AC_ERR_DEV) +#endif /* MY_ABC_HERE */ return 0; /* flush failed for some other reason, give it another shot */ @@ -3463,11 +4917,37 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { struct ata_eh_context *ehc = &dev->link->eh_context; +#ifdef MY_ABC_HERE + /* To solve some disk drop speed after last chance reset in ICH sata port, + * We clean the speed limit and do one more reset to apply this modification + */ + if (1 == ehc->tries[dev->devno] && -EIO == err && + dev->link->ap->scsi_host->hostt->proc_name && + 0 == strcmp("ahci", dev->link->ap->scsi_host->hostt->proc_name)) { + u32 scontrol = 0; + dev->link->sata_spd_limit = 0; + sata_scr_read(dev->link, SCR_CONTROL, &scontrol); + scontrol = (scontrol & ~0x0f0); + sata_scr_write(dev->link, SCR_CONTROL, scontrol); + ehc->i.action |= ATA_EH_RESET; + ehc->tries[dev->devno] = 0; + return 0; + } + /* We set ehc->tries to 0, but preset another ATA_EH_RESET. + * ata_eh_handle_dev_fail will be called again with ehc->tries = 0. + * If we decrease ehc->tries without checking, the result of + * echo->tries will overflow. + */ + if (err != -EAGAIN && ehc->tries[dev->devno]) { + ehc->tries[dev->devno]--; + } +#else /* MY_ABC_HERE */ /* -EAGAIN from EH routine indicates retry without prejudice. * The requester is responsible for ensuring forward progress. */ if (err != -EAGAIN) ehc->tries[dev->devno]--; +#endif /* MY_ABC_HERE */ switch (err) { case -ENODEV: @@ -3480,6 +4960,14 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) fallthrough; case -EIO: if (ehc->tries[dev->devno] == 1) { + +#ifdef MY_ABC_HERE + if (dev->link->ap->pflags & ATA_PFLAG_SYNO_DS_WAKING) { + ata_link_warn(dev->link, "Waking up from deep sleep, don't downgrade link speed"); + break; + } +#endif /* MY_ABC_HERE */ + /* This is the last chance, better to slow * down than lose it. */ @@ -3496,6 +4984,12 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) /* detach if offline */ if (ata_phys_link_offline(ata_dev_phys_link(dev))) ata_eh_detach_dev(dev); +#ifdef MY_ABC_HERE + else if(-EIO == err) { + ata_dev_printk(dev, KERN_WARNING,"handle -EIO dev fail, detach this dev\n"); + ata_eh_detach_dev(dev); + } +#endif /* MY_ABC_HERE */ /* schedule probe if necessary */ if (ata_eh_schedule_probe(dev)) { @@ -3542,6 +5036,9 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_device *dev; int rc, nr_fails; unsigned long flags, deadline; +#ifdef MY_ABC_HERE + bool blCleanFlags = 0; +#endif /* MY_ABC_HERE */ DPRINTK("ENTER\n"); @@ -3598,6 +5095,20 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; } +#ifdef MY_ABC_HERE + if (ap->nr_pmp_links && + ap->pflags & ATA_PFLAG_SYNO_BOOT_PROBE) { + ata_port_printk(ap, KERN_INFO, "Apply Synology fast PMP boot\n"); + ap->pflags |= ATA_PFLAG_RESETTING; + ata_for_each_link(link, ap, EDGE) { + int class = 0; + if (ap->ops->pmp_hardreset) + ap->ops->pmp_hardreset(link, &class, 0); + } + ap->pflags &= ~ATA_PFLAG_RESETTING; + } +#endif /* MY_ABC_HERE */ + /* reset */ ata_for_each_link(link, ap, EDGE) { struct ata_eh_context *ehc = &link->eh_context; @@ -3605,10 +5116,34 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (!(ehc->i.action & ATA_EH_RESET)) continue; +#ifdef MY_ABC_HERE + /* We add 2 secs delay for pmp first link to avoid HDD drop */ + if (ap->nr_pmp_links && 0 == link->pmp) { + mdelay(2000); + } +#endif /* MY_ABC_HERE */ + rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, softreset, hardreset, postreset); if (rc) { ata_link_err(link, "reset failed, giving up\n"); + +#ifdef MY_ABC_HERE + if (link->uiSflags) { + ata_for_each_dev(dev, link, ALL) { + if (ATA_DEV_ATA == dev->class) { + dev->ulSflags |= ATA_SYNO_DFLAG_DETACH; + ata_dev_printk(dev, KERN_ERR, "detect reset link fail, set detach flag\n"); + } + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (sata_pmp_attached(ap)){ + blCleanFlags = 1; + } +#endif /* MY_ABC_HERE */ goto out; } } @@ -3681,7 +5216,23 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* if PMP got attached, return, pmp EH will take care of it */ if (link->device->class == ATA_DEV_PMP) { +#ifdef MY_ABC_HERE + /* Some disks would not stagger spin up when we power only + * the ebox. If we do not reset pmp link first, those disk + * would not spin up after next time we reset pmp link. + * + * This problem only happen in power on ebox. If the ebox + * has poweron already, It would not happen. + */ + if (ehc->i.action & ATA_EH_SYNO_PWON) { + ehc->i.action = 0; + ehc->i.action |= ATA_EH_HARDRESET; + } else { + ehc->i.action = 0; + } +#else /* MY_ABC_HERE */ ehc->i.action = 0; +#endif /* MY_ABC_HERE */ return 0; } @@ -3726,6 +5277,23 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, goto rest_fail; } +#ifdef MY_ABC_HERE + if (ehc->i.action & ATA_EH_WCACHE_DISABLE) { + ata_for_each_dev(dev, link, ALL) { + unsigned int err_mask = 0; + if (dev->class != ATA_DEV_ATA || !(dev->flags & ATA_DFLAG_NO_WCACHE)) + continue; + + ata_dev_printk(dev, KERN_ERR, "Disable disk write cache in EH"); + err_mask = ata_dev_set_feature(dev, SETFEATURES_WC_OFF, 0); + if (err_mask) + ata_dev_printk(dev, KERN_ERR, + "failed to dsiable write cache " + "(err_mask=0x%x)\n", err_mask); + } + } +#endif /* MY_ABC_HERE */ + /* this link is okay now */ ehc->i.flags = 0; continue; @@ -3739,8 +5307,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* PMP reset requires working host port. * Can't retry if it's frozen. */ +#ifdef MY_ABC_HERE + if (sata_pmp_attached(ap)){ + blCleanFlags = 1; + goto out; + } +#else if (sata_pmp_attached(ap)) goto out; +#endif /* MY_ABC_HERE */ break; } } @@ -3752,10 +5327,128 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc && r_failed_link) *r_failed_link = link; +#ifdef MY_ABC_HERE + if (blCleanFlags){ + ata_for_each_link(link, ap, PMP_FIRST){ + struct ata_eh_context *ehc = &link->eh_context; + ehc->i.flags = 0; + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* if not pmp, set link flags to ata port flags for ata port error handling. + * pmp handler will handle pmp case by itself */ + if (!ap->nr_pmp_links) { + ap->uiSflags = uiCheckPortLinksFlags(ap); + } +#endif /* MY_ABC_HERE */ + DPRINTK("EXIT, rc=%d\n", rc); return rc; } +#ifdef MY_ABC_HERE +void syno_print_active_command(struct ata_port *ap) +{ + int tag = 0; + if (NULL == ap) { + printk(KERN_DEBUG "debug: ap is null\n"); + goto END; + } + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; + char data_buf[20] = ""; + char cdb_buf[70] = ""; + + if (!(ap->qc_active & (1 << qc->tag))) { + continue; + } + + if (qc->dma_dir != DMA_NONE) { + static const char *dma_str[] = { + [DMA_BIDIRECTIONAL] = "bidi", + [DMA_TO_DEVICE] = "out", + [DMA_FROM_DEVICE] = "in", + }; + static const char *prot_str[] = { + [ATA_PROT_PIO] = "pio", + [ATA_PROT_DMA] = "dma", + [ATA_PROT_NCQ] = "ncq", + [ATAPI_PROT_PIO] = "pio", + [ATAPI_PROT_DMA] = "dma", + }; + + snprintf(data_buf, sizeof(data_buf), " %s %u %s", + prot_str[qc->tf.protocol], qc->nbytes, + dma_str[qc->dma_dir]); + } + + if (ata_is_atapi(qc->tf.protocol)) { + const u8 *cdb = qc->cdb; + size_t cdb_len = qc->dev->cdb_len; + + if (qc->scsicmd) { + cdb = qc->scsicmd->cmnd; + cdb_len = qc->scsicmd->cmd_len; + } + __scsi_format_command(cdb_buf, sizeof(cdb_buf), + cdb, cdb_len); + } else { + const char *descr = ata_get_cmd_descript(cmd->command); + if (descr) + ata_dev_err(qc->dev, "active command: %s\n", + descr); + } + + ata_dev_err(qc->dev, + "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " + "tag %d%s\n %s" + "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " + "Emask 0x%x (%s)%s\n", + cmd->command, cmd->feature, cmd->nsect, + cmd->lbal, cmd->lbam, cmd->lbah, + cmd->hob_feature, cmd->hob_nsect, + cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, + cmd->device, qc->tag, data_buf, cdb_buf, + res->command, res->feature, res->nsect, + res->lbal, res->lbam, res->lbah, + res->hob_feature, res->hob_nsect, + res->hob_lbal, res->hob_lbam, res->hob_lbah, + res->device, qc->err_mask, ata_err_string(qc->err_mask), + qc->err_mask & AC_ERR_NCQ ? " " : ""); + +#ifdef CONFIG_ATA_VERBOSE_ERROR + if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | + ATA_ERR)) { + if (res->command & ATA_BUSY) + ata_dev_err(qc->dev, "status: { Busy }\n"); + else + ata_dev_err(qc->dev, "status: { %s%s%s%s}\n", + res->command & ATA_DRDY ? "DRDY " : "", + res->command & ATA_DF ? "DF " : "", + res->command & ATA_DRQ ? "DRQ " : "", + res->command & ATA_ERR ? "ERR " : ""); + } + + if (cmd->command != ATA_CMD_PACKET && + (res->feature & (ATA_ICRC | ATA_UNC | ATA_AMNF | + ATA_IDNF | ATA_ABORTED))) + ata_dev_err(qc->dev, "error: { %s%s%s%s%s}\n", + res->feature & ATA_ICRC ? "ICRC " : "", + res->feature & ATA_UNC ? "UNC " : "", + res->feature & ATA_AMNF ? "AMNF " : "", + res->feature & ATA_IDNF ? "IDNF " : "", + res->feature & ATA_ABORTED ? "ABRT " : ""); +#endif + } +END: + return; +} +#endif /* MY_ABC_HERE */ + /** * ata_eh_finish - finish up EH * @ap: host port to finish EH for @@ -3773,6 +5466,17 @@ void ata_eh_finish(struct ata_port *ap) /* retry or finish qcs */ ata_qc_for_each_raw(ap, qc, tag) { + +#ifdef MY_DEF_HERE + if (0 < guiWakeupDisksNum && 1 == ap->nr_active_links && + (qc->flags & ATA_QCFLAG_ACTIVE) && IS_SYNO_SPINUP_CMD(qc)) { + DBGMESG("ata%u eh finish, set failed to spinup cmd 0x%x\n", ap->print_id, qc->tf.command); + qc->flags |= ATA_QCFLAG_FAILED; + __ata_qc_complete(qc); + continue; + } +#endif /* MY_DEF_HERE */ + if (!(qc->flags & ATA_QCFLAG_FAILED)) continue; @@ -3796,6 +5500,12 @@ void ata_eh_finish(struct ata_port *ap) } } +#ifdef MY_ABC_HERE + if (ap->nr_active_links) { + syno_print_active_command(ap); + } +#endif /* MY_ABC_HERE */ + /* make sure nr_active_links is zero after EH */ WARN_ON(ap->nr_active_links); ap->nr_active_links = 0; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 79f2aeeb482a..701a7bdddfb0 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * libata-pmp.c - libata port multiplier support @@ -21,6 +24,117 @@ const struct ata_port_operations sata_pmp_port_ops = { .error_handler = sata_pmp_error_handler, }; +#ifdef MY_ABC_HERE +static u8 syno_i2c_pkg_data_2_tf_offset_mapping[] = { + /* data[0] ~ data[3] */ + offsetof(struct ata_taskfile, lbal), + offsetof(struct ata_taskfile, lbam), + offsetof(struct ata_taskfile, lbah), + offsetof(struct ata_taskfile, hob_lbal), + /* data[4] ~ data[7] */ + offsetof(struct ata_taskfile, hob_lbam), + offsetof(struct ata_taskfile, hob_lbah), + offsetof(struct ata_taskfile, nsect), + offsetof(struct ata_taskfile, hob_nsect), +}; + +static void init_tf_data_from_pkg(struct ata_taskfile *tf, int idx, u8 data) +{ + u8 *ptr = NULL; + + if (!tf || SYNO_PMP_I2C_MAX_DATA_LEN <= idx || 0 > idx) { + goto END; + } + + ptr = ((u8*)tf) + syno_i2c_pkg_data_2_tf_offset_mapping[idx]; + *ptr = data; + +END: + return; +} + +#define SYNO_JMB575_I2C_NACK 0x51 +static unsigned int sata_pmp_i2c_read_core(struct ata_link *link, SYNO_PM_I2C_PKG *pkg) +{ + unsigned int err_mask = 0; + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + struct ata_taskfile tf; + int i = 0; + + /* Init tf */ + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_SYNO_I2C; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; + tf.feature = pkg->addr << 1 | 0x01; /* Read */ + tf.device = pkg->len; + tf.hob_feature = 0x01; /* Randon Read */ + + /* data[0]: i2c device offset */ + init_tf_data_from_pkg(&tf, 0, pkg->offset); + + /* Internal Command */ + err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, SATA_PMP_RW_TIMEOUT); + + if (err_mask) { + ata_link_err(link, "failed to read PMP I2C(Addr=0x%x, Offset=0x%x ,Emask=0x%x)\n", pkg->addr, pkg->offset, err_mask); + pkg->blIsErr = true; + goto END; + } + + if (SYNO_JMB575_I2C_NACK == tf.hob_nsect) { + pkg->blIsErr = true; + goto END; + } + + for (i = 0; i < pkg->len; i++) { + pkg->resultData[i] = *(((u8*)&tf) + syno_i2c_pkg_data_2_tf_offset_mapping[i]) ; + } + +END: + return err_mask; +} + +static unsigned int sata_pmp_i2c_write_core(struct ata_link *link, SYNO_PM_I2C_PKG *pkg) +{ + unsigned int err_mask = 0; + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + struct ata_taskfile tf; + int i = 0; + + /* Init tf */ + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_SYNO_I2C; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; + tf.feature = pkg->addr << 1; + tf.device = pkg->len + 1; + + /* data[0]: i2c device offset */ + init_tf_data_from_pkg(&tf, 0, pkg->offset); + + /* data[1]~data[len]: data to be written */ + for (i = 1; i <= pkg->len; i++) { + init_tf_data_from_pkg(&tf, i, pkg->inputData[i-1]); + } + + /* Internal Command */ + err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, SATA_PMP_RW_TIMEOUT); + + if (err_mask) { + ata_link_err(link, "failed to write PMP I2C(Addr=0x%x, Offset=0x%x ,Emask=0x%x)\n", pkg->addr, pkg->offset, err_mask); + pkg->blIsErr = true; + } + + if (SYNO_JMB575_I2C_NACK == tf.hob_nsect){ + pkg->blIsErr = true; + } + return err_mask; +} +#endif /* MY_ABC_HERE */ + /** * sata_pmp_read - read PMP register * @link: link to read PMP register for @@ -46,7 +160,12 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) tf.command = ATA_CMD_PMP_READ; tf.protocol = ATA_PROT_NODATA; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; +#ifdef MY_ABC_HERE + tf.feature = reg & 0xff; + tf.hob_feature = (reg >> 8) & 0xff; +#else /* MY_ABC_HERE */ tf.feature = reg; +#endif /* MY_ABC_HERE */ tf.device = link->pmp; err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, @@ -82,7 +201,12 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val) tf.command = ATA_CMD_PMP_WRITE; tf.protocol = ATA_PROT_NODATA; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; +#ifdef MY_ABC_HERE + tf.feature = reg & 0xff; + tf.hob_feature = (reg >> 8) & 0xff; +#else /* MY_ABC_HERE */ tf.feature = reg; +#endif /* MY_ABC_HERE */ tf.device = link->pmp; tf.nsect = val & 0xff; tf.lbal = (val >> 8) & 0xff; @@ -93,6 +217,1890 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val) SATA_PMP_RW_TIMEOUT); } +#ifdef MY_ABC_HERE + +unsigned int syno_sata_pmp_read_i2c_acmd(struct ata_link* link, SYNO_PM_I2C_PKG *pPM_pkg) +{ + unsigned int uiRet = 1; + unsigned long flags = 0; + int iRetries = 0; + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(link->ap->lock, flags); + while ((link->uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES > iRetries)) { + spin_unlock_irqrestore(link->ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(link->ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_sata_pmp_read_i2c_acmd get gpio lock timeout\n"); + spin_unlock_irqrestore(link->ap->lock, flags); + goto END; + } + + /* lock to prevent others to do pmp gpio control */ + link->uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + uiRet = sata_pmp_i2c_read_core(link, pPM_pkg); + +END: + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(link->ap->lock, flags); + link->uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + return uiRet; +} + + +unsigned int +syno_sata_pmp_write_i2c_acmd(struct ata_link *link, SYNO_PM_I2C_PKG *pPM_pkg) +{ + unsigned int uiRet = 1; + unsigned long flags = 0; + int iRetries = 0; + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(link->ap->lock, flags); + while ((link->uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES > iRetries)) { + spin_unlock_irqrestore(link->ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(link->ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_sata_pmp_write_i2c_acmd get gpio lock timeout\n"); + spin_unlock_irqrestore(link->ap->lock, flags); + goto END; + } + + /* lock to prevent others to do pmp gpio control */ + link->uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + uiRet = sata_pmp_i2c_write_core(link, pPM_pkg); + +END: + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(link->ap->lock, flags); + link->uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + return uiRet; +} + +unsigned int syno_sata_pmp_read_i2c(struct ata_port *ap, SYNO_PM_I2C_PKG *pPM_pkg) +{ + if ((ap->pflags & (ATA_PFLAG_RECOVERED)) || (!ap->link.device->sdev) || (ap->pflags & ATA_PFLAG_PMP_PMCTL)) + return syno_sata_pmp_read_i2c_acmd(&(ap->link), pPM_pkg); + else + return syno_i2c_with_scmd(ap, ap->link.device->sdev, pPM_pkg, READ); +} + +unsigned int syno_sata_pmp_write_i2c(struct ata_port *ap, SYNO_PM_I2C_PKG *pPM_pkg) +{ + if ((ap->pflags & (ATA_PFLAG_RECOVERED)) || (!ap->link.device->sdev) || (ap->pflags & ATA_PFLAG_PMP_PMCTL)) + return syno_sata_pmp_write_i2c_acmd(&(ap->link), pPM_pkg); + else + return syno_i2c_with_scmd(ap, ap->link.device->sdev, pPM_pkg, WRITE); +} + +/** + * Some PM chips need to config GPIO related + * registers before starting using them. + * + * @param ap ata port + */ +static inline void +syno_pm_gpio_config(struct ata_port *ap) +{ + if (syno_pm_is_9705(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + /* GPIO data_out enable */ + sata_pmp_write(&(ap->link), SATA_PMP_GSCR_9705_GPO_EN, 0xFFFFF); + + /* GPIO data_in polarity */ + sata_pmp_write(&(ap->link), SATA_PMP_GSCR_9705_GPI_POLARITY, 0xFFFFF); + + /* 9705 SATA Blink rate*/ + sata_pmp_write(&(ap->link), SATA_PMP_GSCR_9705_SATA_0_TO_3_BLINK_RATE, 0x2082082); + sata_pmp_write(&(ap->link), SATA_PMP_GSCR_9705_SATA_4_BLINK_RATE, 0x00000082); + + /* 9705 enable FIFO, the values are from Marvell application note */ + sata_pmp_write(&(ap->link), 0x090, 0x00001F1F); + sata_pmp_write(&(ap->link), 0x091, 0xFFF0003A); + + /* 9705 host port OOB upper bond, the values are from Marvell application note */ + sata_pmp_write(&(ap->link), 0x248, 0x62D8); + } +} + +static inline int +syno_pm_device_config_set(struct ata_port *ap, int pmp, int reg, u32 val) +{ + struct ata_link *pmp_link = NULL; + int iRet = -1; + + if (!ap) { + goto END; + } + pmp_link = &(ap->pmp_link[pmp]); + if (!pmp_link) { + goto END; + } + iRet = sata_pmp_write(pmp_link, reg, val); + +END: + return iRet; +} + +static inline void +syno_pm_device_config(struct ata_port *ap) +{ + /* 9705 device port OOB upper bond, the values are from Marvell application note */ + if (syno_pm_is_9705(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + syno_pm_device_config_set(ap, 0, 0x48, 0x62D8); + syno_pm_device_config_set(ap, 1, 0x48, 0x62D8); + syno_pm_device_config_set(ap, 2, 0x48, 0x62D8); + syno_pm_device_config_set(ap, 3, 0x48, 0x62D8); + syno_pm_device_config_set(ap, 4, 0x48, 0x62D8); + } + +#ifdef MY_ABC_HERE + /* Set MV9705 register for Denlow DS3615xs */ + if (IS_SYNOLOGY_DX1215(ap->PMSynoUnique)) { // this modification applied to DX1215 with all models + syno_pm_device_config_set(ap, 0, 0x91, 0xE7F); + syno_pm_device_config_set(ap, 1, 0x91, 0xE7F); + syno_pm_device_config_set(ap, 2, 0x91, 0xE7F); + syno_pm_device_config_set(ap, 3, 0x91, 0xE7F); + syno_pm_device_config_set(ap, 4, 0x91, 0xE7F); + } + if (IS_SYNOLOGY_RX1217(ap->PMSynoUnique)) { + if (0 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xEFF); + } else if (1 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xEFF); + syno_pm_device_config_set(ap, 1, 0x91, 0xE7F); + } else if (2 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 1, 0x91, 0xE79); + syno_pm_device_config_set(ap, 2, 0x91, 0xF7F); + } else if (3 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xEFF); + syno_pm_device_config_set(ap, 2, 0x91, 0xF7F); + } + + /* uplink adjustment */ + if (syno_is_hw_version(HW_RS2421p) || + syno_is_hw_version(HW_RS2421rpp) || + syno_is_hw_version(HW_RS2423p) || + syno_is_hw_version(HW_RS2423rpp)) { + if (0 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0xD7D); + } else if (1 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0x9F5); + } else if (2 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0xA7D); + } else if (3 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0xAFD); + } + } else { + if (0 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0x8f5); + } else if (1 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0x9f5); + } else if (2 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0xA75); + } else if (3 == ap->PMSynoEMID) { + sata_pmp_write(&(ap->link), 0x291, 0xE75); + } + } + } + if (IS_SYNOLOGY_DX517(ap->PMSynoUnique)) { + syno_pm_device_config_set(ap, 4, 0x91, 0xE7F); + + /* uplink adjustment */ + sata_pmp_write(&(ap->link), 0x291, 0xA75); + } + if (IS_SYNOLOGY_RX418(ap->PMSynoUnique)) { + syno_pm_device_config_set(ap, 0, 0x91, 0xD75); + syno_pm_device_config_set(ap, 1, 0x91, 0xD75); + syno_pm_device_config_set(ap, 2, 0x91, 0xE75); + syno_pm_device_config_set(ap, 3, 0x91, 0xEF5); + + /* uplink adjustment */ + sata_pmp_write(&(ap->link), 0x291, 0xB75); + + } + + if (IS_SYNOLOGY_DX1222(ap->PMSynoUnique)) { + if (0 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 1, 0x91, 0xE75); + syno_pm_device_config_set(ap, 2, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 3, 0x91, 0xE75); + } else if (1 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 1, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 2, 0x91, 0xE75); + syno_pm_device_config_set(ap, 3, 0x91, 0xFF5); + } else if (2 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 1, 0x91, 0xE75); + syno_pm_device_config_set(ap, 2, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 3, 0x91, 0xE75); + } else if (3 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 1, 0x91, 0xFFF); + syno_pm_device_config_set(ap, 2, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 3, 0x91, 0xFFF); + } + + /* uplink adjustment */ + sata_pmp_write(&(ap->link), 0x291, 0xFF5); + } + + /* Set MV9705 register for DX1215II */ + if (IS_SYNOLOGY_DX1215II(ap->PMSynoUnique)) { + if (0 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xE75); + syno_pm_device_config_set(ap, 1, 0x91, 0xEF5); + syno_pm_device_config_set(ap, 2, 0x91, 0xE75); + } else if (1 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 1, 0x91, 0xDF5); + syno_pm_device_config_set(ap, 2, 0x91, 0xFFF); + } else if (2 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 1, 0x91, 0xFFF); + syno_pm_device_config_set(ap, 2, 0x91, 0xF75); + } else if (3 == ap->PMSynoEMID) { + syno_pm_device_config_set(ap, 0, 0x91, 0xFFF); + syno_pm_device_config_set(ap, 1, 0x91, 0xFF5); + syno_pm_device_config_set(ap, 2, 0x91, 0xFFF); + } + } +#endif /* MY_ABC_HERE */ +} + +void +syno_pm_device_info_set(struct ata_port *ap, u8 rw, SYNO_PM_PKG *pm_pkg) +{ + if (syno_pm_is_9705(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + pm_pkg->decode = SIMG9705_gpio_decode; + pm_pkg->encode = SIMG9705_gpio_encode; + pm_pkg->gpio_addr = READ == rw ? SATA_PMP_GSCR_9705_GPI : SATA_PMP_GSCR_9705_GPO; + return; + } +} + +/* On 9705, GPI and GPO are the same pin, so each pin can + * only be treated as input or output at one time, + * Before reading, we need to set "output_enable" to LOW + * so that we can read the values CPLD writes on these pins. + * + * After reading, remember to call syno_pm_gpio_output_enable(). + */ +unsigned int +syno_pm_gpio_output_disable(struct ata_link *link) +{ + unsigned int uiRet = 0; + + if (syno_pm_is_9705(sata_pmp_gscr_vendor(link->device->gscr), + sata_pmp_gscr_devid(link->device->gscr))) { + /* Only GPI1~GPI8(GPIO 0~4,11~13) need to set LOW. */ + uiRet = sata_pmp_write(link, SATA_PMP_GSCR_9705_GPO_EN, 0xFC7C0); + } + + return uiRet; +} + +/* On 9705, GPI and GPO are the same pin, so each pin can + * only be treated as input or output at one time, + * After reading, we need to set "output_enable" to HIGH + * so that we can write values on these pins later, + */ +unsigned int +syno_pm_gpio_output_enable(struct ata_link *link) +{ + unsigned int uiRet = 0; + + if (syno_pm_is_9705(sata_pmp_gscr_vendor(link->device->gscr), + sata_pmp_gscr_devid(link->device->gscr))) { + /* Only GPI1~GPI8(GPIO 0~4,11~13) need to set LOW. */ + uiRet = sata_pmp_write(link, SATA_PMP_GSCR_9705_GPO_EN, 0xFFFFF); + } + + return uiRet; +} + +/* sata_pmp_read_gpio by scsi command */ +unsigned int +syno_sata_pmp_read_gpio_scmd(struct ata_port *ap, SYNO_PM_PKG *pPkg) +{ + unsigned int uiRet = 1; + struct scsi_device *sdev = ap->link.device->sdev; + + if ( syno_pm_is_9705(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + /* The read machanism of 9705 is totally different from 3xxx. + * Read is issued by controlling the Read bit, which is active low. + * Refer to HW Spec for further details. + */ + unsigned int uiVar = pPkg->var; + unsigned int uiVarActive = pPkg->var & ~(1 << 9); /* pull down the read bit */ + unsigned int uiResult = 0; + + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, WRITE); + if ( 0 != uiRet ) { + goto END; + } + pPkg->var = uiVarActive; + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, WRITE); + if ( 0 != uiRet ) { + goto END; + } + pPkg->var = uiVarActive; + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, READ); + if ( 0 != uiRet ) { + goto END; + } + uiResult = pPkg->var; + pPkg->var = uiVar; + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, WRITE); + if ( 0 != uiRet ) { + goto END; + } + pPkg->var = uiResult; + } + uiRet = 0; +END: + return uiRet; + +} + +/* sata_pmp_write_gpio by scsi command */ +unsigned int +syno_sata_pmp_write_gpio_scmd(struct ata_port *ap, SYNO_PM_PKG *pPkg) +{ + unsigned int uiRet = 1; + struct scsi_device *sdev = ap->link.device->sdev; + + if (syno_pm_is_9705(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + /* The write machanism of 9705 is totally different from 3xxx. + * Write is issued by controlling the Write bit, which is active low. + * Refer to HW Spec for further details. + */ + unsigned int uiVar = pPkg->var; + unsigned int uiVarActive = pPkg->var & ~(1 << 8); /* pull down the write bit */ + + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, WRITE); + if ( 0 != uiRet ) { + goto END; + } + pPkg->var = uiVarActive; + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, WRITE); + if ( 0 != uiRet ) { + goto END; + } + pPkg->var = uiVar; + uiRet = syno_gpio_with_scmd(ap, sdev, pPkg, WRITE); + if ( 0 != uiRet ) { + goto END; + } + } +END: + return uiRet; +} + +/* sata_pmp_read_gpio by ata command */ +unsigned int +syno_sata_pmp_read_gpio_acmd(struct ata_link* link, SYNO_PM_PKG *pPM_pkg) +{ + unsigned int uiRet = 1; + + if (syno_pm_is_9705(sata_pmp_gscr_vendor(link->device->gscr), + sata_pmp_gscr_devid(link->device->gscr))) { + /* The read machanism of 9705 is totally different from 3xxx. + * Read is issued by controlling the Read bit, which is active low. + * Refer to HW Spec for further details. + */ + unsigned int uiVar = pPM_pkg->var; + unsigned int uiVarActive = pPM_pkg->var & ~(1 << 9); /* pull down the read bit */ + unsigned int uiResult = 0; + + uiRet = syno_sata_pmp_write_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + pPM_pkg->var = uiVarActive; + uiRet = syno_sata_pmp_write_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + pPM_pkg->var = uiVarActive; + uiRet = syno_sata_pmp_read_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + uiResult = pPM_pkg->var; + pPM_pkg->var = uiVar; + uiRet = syno_sata_pmp_write_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + pPM_pkg->var = uiResult; + } + uiRet = 0; +END: + return uiRet; +} + +/* sata_pmp_write_gpio by ata command */ +unsigned int +syno_sata_pmp_write_gpio_acmd(struct ata_link *link, SYNO_PM_PKG *pPM_pkg) +{ + unsigned int uiRet = 1; + + if (syno_pm_is_9705(sata_pmp_gscr_vendor(link->device->gscr), + sata_pmp_gscr_devid(link->device->gscr))) { + /* The write machanism of 9705 is totally different from 3xxx. + * Write is issued by controlling the Write bit, which is active low. + * Refer to HW Spec for further details. + */ + unsigned int uiVar = pPM_pkg->var; + unsigned int uiVarActive = pPM_pkg->var & ~(1 << 8); /* pull down the write bit */ + uiRet = syno_sata_pmp_write_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + pPM_pkg->var = uiVarActive; + uiRet = syno_sata_pmp_write_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + pPM_pkg->var = uiVar; + uiRet = syno_sata_pmp_write_gpio_core(link, pPM_pkg); + if (0 != uiRet) { + goto END; + } + } +END: + return uiRet; +} + +unsigned int +syno_sata_pmp_read_gpio_core(struct ata_link *link, SYNO_PM_PKG *pPM_pkg) +{ + unsigned int uiRet = 1; + unsigned long flags = 0; + int iRetries = 0; + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(link->ap->lock, flags); + while ((link->uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES > iRetries)) { + spin_unlock_irqrestore(link->ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(link->ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_sata_pmp_read_gpio_core get gpio lock timeout\n"); + spin_unlock_irqrestore(link->ap->lock, flags); + goto END; + } + + /* lock to prevent others to do pmp gpio control */ + link->uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + syno_pm_device_info_set(link->ap, READ, pPM_pkg); + + uiRet = syno_pm_gpio_output_disable(link); + if (0 != uiRet) { + goto END; + } + + uiRet = sata_pmp_read(link, pPM_pkg->gpio_addr, &(pPM_pkg->var)); + if (0 != uiRet) { + goto END; + } + + if (pPM_pkg->decode) { + pPM_pkg->decode(pPM_pkg, READ); + } + +END: + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(link->ap->lock, flags); + link->uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + return uiRet; +} + +unsigned int +syno_sata_pmp_write_gpio_core(struct ata_link *link, SYNO_PM_PKG *pPM_pkg) +{ + unsigned int uiRet = 1; + unsigned long flags = 0; + int iRetries = 0; + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(link->ap->lock, flags); + while ((link->uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES > iRetries)) { + spin_unlock_irqrestore(link->ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(link->ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_sata_pmp_write_gpio_core get gpio lock timeout\n"); + spin_unlock_irqrestore(link->ap->lock, flags); + goto END; + } + + /* lock to prevent others to do pmp gpio control */ + link->uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + syno_pm_device_info_set(link->ap, WRITE, pPM_pkg); + + uiRet = syno_pm_gpio_output_enable(link); + if (0 != uiRet) { + goto END; + } + + if (pPM_pkg->encode) { + pPM_pkg->encode(pPM_pkg, WRITE); + } + + uiRet = sata_pmp_write(link, pPM_pkg->gpio_addr, pPM_pkg->var); + if (0 != uiRet) { + goto END; + } + + /* HW suggestions: delay 5ms, wait for CPLD ready */ + mdelay(5); +END: + + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(link->ap->lock, flags); + link->uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(link->ap->lock, flags); + + return uiRet; +} + +unsigned int syno_sata_pmp_read_gpio(struct ata_port *ap, SYNO_PM_PKG *pPM_pkg) +{ + if ((ap->pflags & (ATA_PFLAG_RECOVERED)) || (!ap->link.device->sdev) || (ap->pflags & ATA_PFLAG_PMP_PMCTL)) + return syno_sata_pmp_read_gpio_acmd(&(ap->link), pPM_pkg); + else + return syno_sata_pmp_read_gpio_scmd(ap, pPM_pkg); +} + +unsigned int syno_sata_pmp_write_gpio(struct ata_port *ap, SYNO_PM_PKG *pPM_pkg) +{ + if ((ap->pflags & ATA_PFLAG_RECOVERED) || (!ap->link.device->sdev) || (ap->pflags & ATA_PFLAG_PMP_PMCTL)) + return syno_sata_pmp_write_gpio_acmd(&(ap->link), pPM_pkg); + else + return syno_sata_pmp_write_gpio_scmd(ap, pPM_pkg); +} + +u8 syno_pm_is_synology_9705(const struct ata_port *ap) +{ + u8 ret = 0; + + if (!syno_pm_is_9705(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + goto END; + } + + if (!IS_SYNOLOGY_RX413(ap->PMSynoUnique) && + !IS_SYNOLOGY_RX1214(ap->PMSynoUnique) && + !IS_SYNOLOGY_RX1217(ap->PMSynoUnique) && + !IS_SYNOLOGY_DX1215(ap->PMSynoUnique) && + !IS_SYNOLOGY_DX517(ap->PMSynoUnique) && + !IS_SYNOLOGY_RX418(ap->PMSynoUnique) && + !IS_SYNOLOGY_DX1222(ap->PMSynoUnique) && + !IS_SYNOLOGY_DX1215II(ap->PMSynoUnique)) { + goto END; + } + + ret = 1; +END: + return ret; +} + +u8 syno_pm_is_synology_jmb575(const struct ata_port *ap) +{ + u8 ret = 0; + + if (!syno_pm_is_jmb575(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr))) { + goto END; + } + + if (!IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique)) { + goto END; + } + + ret = 1; + +END: + return ret; + +} + +static int syno_jmb575_get_i2c_info(struct ata_port *ap, struct device_node *pNode, SYNO_JMB575_I2C_DEV_INFO *pI2cInfo) +{ + int iRet = -1; + SYNO_JMB575_I2C_DEV_INFO i2cInfoTmp; + + if (NULL == ap || NULL == pNode || NULL == pI2cInfo) { + goto END; + } + + if(of_property_read_u32_index(pNode, SZ_DTS_EBOX_I2C_OFFSET, 0, &i2cInfoTmp.offset)) { + printk("Get node %s fail\n", SZ_DTS_EBOX_I2C_OFFSET); + goto END; + } + + if(of_property_read_u32_index(pNode, SZ_DTS_EBOX_I2C_MASK, 0, &i2cInfoTmp.mask)) { + printk("Get node %s fail\n", SZ_DTS_EBOX_I2C_MASK); + goto END; + } + + if (syno_pmp_i2c_addr_get(pNode, &i2cInfoTmp.addr)) { + printk("Get Power control i2c addr fail\n"); + goto END; + } + + memcpy(pI2cInfo, &i2cInfoTmp, sizeof(SYNO_JMB575_I2C_DEV_INFO)); + + iRet = 0; +END: + return iRet; + + +} + +static int syno_sata_jmb575_pwrbtn(struct ata_port *ap, u8 blDisable) +{ + int iRet = -1; + struct device_node *pEBoxNode = NULL; + struct device_node *pPwrBtnNode = NULL; + SYNO_JMB575_I2C_DEV_INFO i2cInfo; + SYNO_PM_I2C_PKG i2cPkg; + const int dataLen = 1; + + if (NULL == ap) { + goto END; + } + + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Get EBox node fail"); + goto END; + } + + if (NULL == (pPwrBtnNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_I2C_PWR_BTN))) { + printk("Get node %s fail", SZ_DTS_EBOX_I2C_PWR_BTN); + goto END; + } + + if (syno_jmb575_get_i2c_info(ap, pPwrBtnNode, &i2cInfo)) { + printk("Get i2c device info fail"); + goto END; + } + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_READ, i2cInfo.addr, i2cInfo.offset, dataLen); + + if (syno_sata_pmp_read_i2c(ap, &i2cPkg)) { + goto END; + } + + i2cPkg.inputData[0] = blDisable? (i2cPkg.resultData[0] | i2cInfo.mask) : (i2cPkg.resultData[0] & (~i2cInfo.mask)); + + if (syno_sata_pmp_write_i2c(ap, &i2cPkg)) { + goto END; + } + +END: + return iRet; +} + +/** + * syno_sata_jmb575_is_rp + * + * @return -1: error + * 0: not rp + * 1: is rp + */ +static int syno_sata_jmb575_is_rp(struct ata_port *ap) +{ + int iRet = 0; + struct device_node *pEBoxNode = NULL; + struct device_node *pRpNode = NULL; + struct device_node *pSubRpNode = NULL; + SYNO_JMB575_I2C_DEV_INFO i2cInfo; + SYNO_PM_I2C_PKG i2cPkg; + const int dataLen = 1; + + if (NULL == ap) { + iRet = -1; + goto END; + } + + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Get EBox node fail"); + goto END; + } + + if (NULL == (pRpNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_RP))) { + printk("Get node %s fail", SZ_DTS_EBOX_RP); + goto END; + } + + /* For each RP */ + for_each_child_of_node(pRpNode, pSubRpNode) { + if (!pSubRpNode->full_name || strncmp(pSubRpNode->full_name, SZ_DTS_EBOX_RP_INFO, strlen(SZ_DTS_EBOX_RP_INFO))) { + continue; + } + + memset(&i2cInfo, 0, sizeof(SYNO_JMB575_I2C_DEV_INFO)); + + if (syno_jmb575_get_i2c_info(ap, pSubRpNode, &i2cInfo)) { + printk("Get i2c device info fail"); + goto END; + } + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_READ, i2cInfo.addr, i2cInfo.offset, dataLen); + + if (syno_sata_pmp_read_i2c(ap, &i2cPkg)) { + goto END; + } + + if (i2cPkg.inputData[0] & i2cInfo.mask) { + iRet = 1; /* Is RP */ + goto END; + } + } + +END: + return iRet; +} + +unsigned int +syno_sata_pmp_is_rp(struct ata_port *ap) +{ +#define GPI_9705_PSU1_STAT(GPIO) ((1<<6)&GPIO)>>6 +#define GPI_9705_PSU2_STAT(GPIO) ((1<<7)&GPIO)>>7 + int res = 0; + SYNO_PM_PKG pm_pkg; + + if (NULL == ap) { + goto END; + } + + if (0 != ap->PMSynoEMID) { + goto END; + } + + if (syno_pm_is_synology_9705(ap)) { + syno_pm_fanstatus_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &pm_pkg); + + res = syno_sata_pmp_read_gpio(ap, &pm_pkg); + if (0 != res) { + goto END; + } + + if (GPI_9705_PSU1_STAT(pm_pkg.var) || GPI_9705_PSU2_STAT(pm_pkg.var)) { + res = 1; + } + } else if (syno_pm_is_synology_jmb575(ap)) { + + if (1 == syno_sata_jmb575_is_rp(ap)) { + res = 1; + } + } + +END: + return res; +} + +static unsigned int +syno_sata_pmp_read_cpld_ver(struct ata_port *ap) +{ +#define GPI_9705_CPLDVER_BIT0(GPIO) ((1<<1)&GPIO)>>1 +#define GPI_9705_CPLDVER_BIT1(GPIO) ((1<<2)&GPIO)>>1 + int iRes = 0; + SYNO_PM_PKG stPmPkg; + + if (NULL == ap) { + goto END; + } + + if (syno_pm_is_synology_9705(ap)) { + syno_pm_systemstate_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &stPmPkg); + + iRes = syno_sata_pmp_read_gpio(ap, &stPmPkg); + if (0 != iRes) { + goto END; + } + ap->PMSynoCpldVer = GPI_9705_CPLDVER_BIT1(stPmPkg.var) | + GPI_9705_CPLDVER_BIT0(stPmPkg.var); + } +END: + return iRes; +} + +static int syno_sata_jmb575_disk_led_get(struct ata_link *link, u8 *pLedMask) +{ + int iRet = -1; + struct ata_taskfile tf; + struct ata_port *ap = NULL; + + if (NULL == link || NULL == pLedMask) { + goto END; + } + + ap = link->ap; + + if ((ap->pflags & (ATA_PFLAG_RECOVERED)) || (!link->device->sdev)) { + ata_tf_init(link->device, &tf); + tf.command = ATA_CMD_PMP_SYNO_LED_GPIO; + tf.protocol = ATA_PROT_NODATA; + tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; + tf.lbal = 0x40; /* Read GPIO */ + + if (0 != (iRet = ata_exec_internal(link->device, &tf, NULL, DMA_NONE, NULL, 0, SATA_PMP_RW_TIMEOUT))) { + ata_link_err(link, "Failed to read disk led(Emask=0x%x)\n", iRet); + goto END; + } + + *pLedMask = tf.lbal & 0xFF; + } else { + iRet = syno_jmb_575_led_ctl_with_scmd(ap, ap->link.device->sdev, pLedMask, READ); + } +END: + return iRet; +} + + +#define SYNO_JMB575_MAX_LED_LINK 6 +const int jmb575_mask_shift[SYNO_JMB575_MAX_LED_LINK] = {3, 5, 0, 2, 4, 1}; +int syno_sata_jmb575_disk_led_set_with_scmnd(struct ata_link *link, u8 ledIdx, u8 blLightOn) +{ + u8 ledMask = 0; + int iRet = -1; + struct ata_port *ap = NULL; + + if (NULL == link || SYNO_JMB575_MAX_LED_LINK <= ledIdx) { + goto END; + } + + if (!link->device->sdev) { + DBGMESG("ata%d: Skip JMB575 disk led set\n", ap->print_id); + goto END; + } + + ap = link->ap; + + /* Read current setting */ + if (syno_jmb_575_led_ctl_with_scmd(ap, link->device->sdev, &ledMask, READ)) { + DBGMESG("ata%d: JMB575 Read disk led with scmnd failed\n", ap->print_id); + goto END; + } + + ledMask = (blLightOn? ledMask | (1 << jmb575_mask_shift[ledIdx]): ledMask & (~(1 << jmb575_mask_shift[ledIdx]))) & 0x3F; + + if (syno_jmb_575_led_ctl_with_scmd(ap, ap->link.device->sdev, &ledMask, WRITE)) { + DBGMESG("ata%d: JMB575 Write disk led with scmnd failed\n", ap->print_id); + goto END; + } + + iRet = 0; + +END: + return iRet; +} + + +int syno_sata_jmb575_disk_led_set(struct ata_link *link, u8 ledIdx, u8 blLightOn) +{ + u8 ledMask = 0; + int iRet = -1; + struct ata_taskfile tf; + struct ata_port *ap = NULL; + + if (NULL == link || SYNO_JMB575_MAX_LED_LINK <= ledIdx) { + goto END; + } + + /* Read current setting */ + if (syno_sata_jmb575_disk_led_get(link, &ledMask)) { + printk("Read fail\n"); + goto END; + } + + ap = link->ap; + ledMask = (blLightOn? ledMask | (1 << jmb575_mask_shift[ledIdx]): ledMask & (~(1 << jmb575_mask_shift[ledIdx]))) & 0x3F; + + if ((ap->pflags & (ATA_PFLAG_RECOVERED)) || (!link->device->sdev)) { + /* Init task file */ + ata_tf_init(link->device, &tf); + tf.command = ATA_CMD_PMP_SYNO_LED_GPIO; + tf.protocol = ATA_PROT_NODATA; + tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; + tf.lbal = ledMask; + + if (0 != (iRet = ata_exec_internal(link->device, &tf, NULL, DMA_NONE, NULL, 0, SATA_PMP_RW_TIMEOUT))) { + ata_link_err(link, "Failed to set disk led(Emask=0x%x)\n", iRet); + goto END; + } + } else { + iRet = syno_jmb_575_led_ctl_with_scmd(ap, ap->link.device->sdev, &ledMask, WRITE); + } +END: + return iRet; +} + +static unsigned int syno_sata_jmb575_info_get(struct ata_link *link, unsigned int *fw, u8 *emid) +{ + struct ata_device *pmp_dev = link->device; + struct ata_taskfile tf; + unsigned int err_mask = 0; + + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_GET_BOARD_INFO_JMB575; + tf.protocol = ATA_PROT_NODATA; + tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48; + tf.feature = SYNO_JMB575_GET_INFO_FEATURE; + + if(0 != (err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, SATA_PMP_RW_TIMEOUT))) { + ata_link_err(link, "Failed to get jmb575 board info(Emask=0x%x)\n", err_mask); + return err_mask; + } + + *fw = (tf.hob_lbah & 0xff) << 24 | + (tf.hob_lbam & 0xff) << 16 | + (tf.hob_lbal & 0xff) << 8 | + (tf.hob_nsect & 0xff); + + *emid = tf.lbam; + + return err_mask; +} + +static int syno_sata_pmp_lock(struct ata_port *ap) +{ + int iRet = -1; + unsigned long flags = 0; + struct ata_link *link = NULL; + int iRetries = 0; + + if (NULL == ap) { + goto END; + } + + link = &(ap->link); + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(ap->lock, flags); + while ((link->uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES > iRetries)) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(ap->lock, flags); + ++iRetries; + } + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("gpio lock timeout\n"); + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } + + /* lock to prevent others to do pmp gpio control */ + link->uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + + iRet = 0; +END: + return iRet; +} + +static void syno_sata_pmp_unlock(struct ata_port *ap) +{ + unsigned long flags = 0; + struct ata_link *link = NULL; + + if (NULL == ap) { + goto END; + } + + link = &(ap->link); + + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(ap->lock, flags); + link->uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + +END: + return; +} + +int syno_sata_jmb575_custom_cmd(struct ata_port *ap, SYNO_JMB575_VENDOR_COMMAND cmd, int *var) +{ + int iRet = -1; + + unsigned int fw; + u8 emid; + + if (!ap || SYNO_JMB575_COMMAND_UNKNOWN == cmd || !var) { + goto END; + } + + if (syno_sata_pmp_lock(ap)) { + goto END; + } + + switch (cmd) { + case SYNO_JMB575_GET_UNIQUE_ID: + if(syno_sata_jmb575_info_get(&(ap->link), &fw, &emid)) { + goto END; + } + *var = (fw >> 16) & 0xFF; + break; + case SYNO_JMB575_GET_EMID: + if(syno_sata_jmb575_info_get(&(ap->link), &fw, &emid)) { + goto END; + } + *var = emid; + break; + case SYNO_JMB575_GET_FW_INFO: + if(syno_sata_jmb575_info_get(&(ap->link), &fw, &emid)) { + goto END; + } + *var = fw; + break; + case SYNO_JMB575_DISK_LED_MASK: + iRet = syno_sata_jmb575_disk_led_set(&(ap->link), (*var >> 8) & 0xFF, *var & 0xFF); + default: + break; + } + + iRet = 0; + +END: + syno_sata_pmp_unlock(ap); + return iRet; +} + +unsigned int +syno_sata_pmp_read_emid(struct ata_port *ap) +{ +#define GPI_9705_EMID_BIT1(GPIO) ((1<<5)&GPIO)>>5 +#define GPI_9705_EMID_BIT2(GPIO) ((1<<6)&GPIO)>>5 +#define GPI_9705_EMID_BIT3(GPIO) ((1<<7)&GPIO)>>5 + int res = 0; + SYNO_PM_PKG pm_pkg; + int emid = 0; + + if (NULL == ap) { + goto END; + } + + if (syno_pm_is_synology_9705(ap)) { + syno_pm_unique_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &pm_pkg); + + res = syno_sata_pmp_read_gpio(ap, &pm_pkg); + if (0 != res) { + goto END; + } + + ap->PMSynoEMID = GPI_9705_EMID_BIT1(pm_pkg.var)| + GPI_9705_EMID_BIT2(pm_pkg.var)| + GPI_9705_EMID_BIT3(pm_pkg.var); + } else if (syno_pm_is_synology_jmb575(ap)) { + if(syno_sata_jmb575_custom_cmd(ap, SYNO_JMB575_GET_EMID, &emid)) { + ata_dev_printk(ap->link.device, KERN_WARNING, "JMB575: Get EMID faild\n"); + goto END; + } else { + ap->PMSynoEMID = emid & 0xFF; + ata_dev_printk(ap->link.device, KERN_WARNING, "JMB575: Get EMID %d\n", ap->PMSynoEMID); + } + } + +END: + return res; +} + +unsigned int syno_sata_pmp_show_fw_info(struct ata_port *ap) +{ + int res = 0; + int fw_info = 0; + + if (NULL == ap) { + goto END; + } + + if (syno_pm_is_synology_jmb575(ap)) { + if(syno_sata_jmb575_custom_cmd(ap, SYNO_JMB575_GET_FW_INFO, &fw_info)) { + ata_dev_printk(ap->link.device, KERN_WARNING, "JMB575: get fw info fail\n"); + goto END; + } + ata_dev_printk(ap->link.device, KERN_WARNING, "JMB575: FW ver %02x.%02x.%02x.%02x\n", + (fw_info >> 24) & 0xff, + (fw_info >> 16) & 0xff, + (fw_info >> 8) & 0xff, + fw_info& 0xff); + } + +END: + return res; +} + +/* + * Query backplane switch mode + * + * @param ap ata_port + * + * @return 0: success + * overwise fail + */ +static unsigned int +syno_sata_pmp_read_switch_mode(struct ata_port *ap) +{ +#define GPI_9705_SWITCHMODE_BIT(GPIO) (1&GPIO) + int iRes = 0; + SYNO_PM_PKG stPmPkg; + + if (NULL == ap) { + goto END; + } + + if (syno_pm_is_synology_9705(ap)) { + syno_pm_systemstate_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &stPmPkg); + + iRes = syno_sata_pmp_read_gpio(ap, &stPmPkg); + if (0 != iRes) { + goto END; + } + + if (0 == GPI_9705_SWITCHMODE_BIT(stPmPkg.var)){ + ap->PMSynoSwitchMode = PMP_SWITCH_MODE_MANUAL; + } else { + ap->PMSynoSwitchMode = PMP_SWITCH_MODE_AUTO; + } + } +END: + return iRes; +} + +/* + * Check power button whether disable or not + * + * @param ap ata_port + * + * @return 0: success + * overwise fail + */ +static unsigned int +syno_sata_pmp_check_powerbtn(struct ata_port *ap) +{ +#define GPI_9705_POWERDISABLE_BIT(GPIO) ((1<<5)&GPIO)>>5 + int iRes = 0; + SYNO_PM_PKG stPmPkg; + unsigned short vendor; + unsigned short devid; + const u8 blDisable = 0; + + if (NULL == ap) { + goto END; + } + + vendor = sata_pmp_gscr_vendor(ap->link.device->gscr); + devid = sata_pmp_gscr_devid(ap->link.device->gscr); + + if (syno_pm_is_9705(vendor, devid)) { + syno_pm_raidledstate_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &stPmPkg); + + iRes = syno_sata_pmp_read_gpio(ap, &stPmPkg); + + if (0 != iRes) { + goto END; + } + + if ((syno_pm_is_synology_9705(ap) && 1 == GPI_9705_POWERDISABLE_BIT(stPmPkg.var))) { + goto END; + } + + syno_pm_enable_powerbtn_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &stPmPkg); + + syno_sata_pmp_write_gpio(ap, &stPmPkg); + } else if (syno_pm_is_synology_jmb575(ap)) { + if (syno_sata_jmb575_pwrbtn(ap, blDisable)) { + goto END; + } + } + +END: + return iRes; +} + +u8 syno_pm_with_synology_magic(const struct ata_port *ap) +{ + u8 ret = 0; + + if (sata_pmp_gscr_syno(ap->link.device->gscr) != SYNO_HEX || + sata_pmp_gscr_logy(ap->link.device->gscr) != LOGY_HEX) { + goto END; + } + + ret = 1; + +END: + return ret; +} + +u8 +syno_is_synology_pm(const struct ata_port *ap) +{ + u8 ret = 0; + + /* can't using ap->nr_pmp_links here, because the execution order + * is not right, libata do a bad thing in sata_pmp_attach when + * init ap->nr_pmp_links. It should be placed just after + * sata_pmp_read_gscr(dev, dev->gscr); + */ + if (!sata_pmp_gscr_ports(ap->link.device->gscr)) { + goto END; + } + + if (0 >= ap->PMSynoUnique) { + goto END; + } + + if (syno_pm_is_synology_9705(ap) || + syno_pm_is_synology_jmb575(ap)) { + ret = 1; + goto END; + } + + /* add other port multiplier here */ +END: + return ret; +} + +u32 +syno_pmp_ports_num(struct ata_port *ap) +{ + u32 ret = 1; + + if (syno_is_synology_pm(ap)) { + ret = sata_pmp_gscr_ports(ap->link.device->gscr); + + if (syno_pm_is_synology_9705(ap)) { + /* it would read 6 ports from GSCR, + * but this is not what we want + * So we modify here. + */ + ret = 5; + } + /* add other quirk of port multiplier here */ + } + return ret; +} + +static unsigned char +syno_pm_is_poweron(struct ata_port *ap) +{ +#define GPI_9705_PSU_OFF(GPIO) !(0x20&GPIO) + int iRes = 0; + SYNO_PM_PKG stPmPkg; + unsigned short vendor, devid; + SYNO_JMB575_I2C_DEV_INFO i2cInfo; + SYNO_PM_I2C_PKG i2cPkg; + struct device_node *pPwrNode = NULL; + struct device_node *pEBoxNode = NULL; + const int dataLen = 1; + + if (NULL == ap) { + goto END; + } + + vendor = sata_pmp_gscr_vendor(ap->link.device->gscr); + devid = sata_pmp_gscr_devid(ap->link.device->gscr); + + if(syno_pm_is_9705(vendor, devid)) { + syno_pm_fanstatus_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &stPmPkg); + + iRes = syno_sata_pmp_read_gpio(ap, &stPmPkg); + + if (0 != iRes) { + goto END; + } + + if (syno_pm_is_synology_9705(ap) && GPI_9705_PSU_OFF(stPmPkg.var)) { + goto END; + } + }else if (syno_pm_is_jmb575(vendor, devid)) { + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Get EBox node fail"); + goto END; + } + if (NULL == (pPwrNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_I2C_PWR_CTL))) { + printk("Get node %s fail", SZ_DTS_EBOX_I2C_PWR_CTL); + goto END; + } + + if (syno_jmb575_get_i2c_info(ap, pPwrNode, &i2cInfo)) { + printk("Get i2c device info fail"); + goto END; + } + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_READ, i2cInfo.addr, i2cInfo.offset, dataLen); + + if (syno_sata_pmp_read_i2c(ap, &i2cPkg)) { + iRes = 1; + goto END; + } + + if (!(i2cPkg.resultData[0] & i2cInfo.mask)) { + goto END; + } + } + + iRes = 1; +END: + return iRes; +} + +static inline void +syno_prepare_custom_info(struct ata_port *ap) +{ + syno_libata_pm_power_ctl(ap, 1, 1); +} + +void +syno_9705_workaround(struct ata_port *ap) +{ + struct ata_port *pAp_master = NULL; + int i = 0; + + for (i = 0; i < ap->host->n_ports; i++) { + pAp_master = ap->host->ports[i]; + if (NULL == pAp_master) { + continue; + } + + if (ap->PMSynoUnique != pAp_master->PMSynoUnique) { + if (syno_pm_is_synology_9705(pAp_master)) { + ata_port_printk(ap, KERN_ERR, + "replace unique %x with master unique %x\n", + ap->PMSynoUnique, pAp_master->PMSynoUnique); + ap->PMSynoUnique = pAp_master->PMSynoUnique; + } else { + ata_port_printk(ap, KERN_ERR, + "WARNING : master unique is not syno 9705, don't replace\n"); + } + break; + } + } +} + +int syno_libata_pmp_deepsleep_indicator_set(struct ata_port *ap, const int blCLR) +{ +#define CLEAR_DEEPSLEEP_BIT(BITMAP) (BITMAP & (~0x80)) + SYNO_PM_PKG pm_pkg; + int iRet = -1; + unsigned int uiVar = 0; + unsigned short vendor; + unsigned short devid; + + struct device_node *pEBoxNode; + struct device_node *pPwrNode; + SYNO_JMB575_I2C_DEV_INFO i2cInfo; + SYNO_PM_I2C_PKG i2cPkg; + + if (!ap) { + goto END; + } + + vendor = sata_pmp_gscr_vendor(ap->link.device->gscr); + devid = sata_pmp_gscr_devid(ap->link.device->gscr); + + if (syno_pm_is_9705(vendor, devid)) { + syno_pm_hddled_status_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), &pm_pkg); + + iRet = syno_sata_pmp_read_gpio(ap, &pm_pkg); + if(0 != iRet) { + goto END; + } + uiVar = CLEAR_DEEPSLEEP_BIT(pm_pkg.var); + + if (syno_pm_deepsleep_indicator_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), &pm_pkg, blCLR)) { + pm_pkg.var |= uiVar; + if (syno_sata_pmp_write_gpio(ap, &pm_pkg)) { + printk("ata%d pm deepsleep indicator write 0 fail\n", ap->print_id); + ata_port_printk(ap, KERN_INFO, "Set PMP deepsleep indicator %d failed\n", blCLR); + goto END; + } + } + } else if (syno_pm_is_jmb575(vendor, devid)) { + + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Get EBox node fail"); + goto END; + } + + if (NULL == (pPwrNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_I2C_DEEPSELLP_INDICATOR))) { + printk("Get node %s fail\n", SZ_DTS_EBOX_I2C_DEEPSELLP_INDICATOR); + goto END; + } + + if (syno_jmb575_get_i2c_info(ap, pPwrNode, &i2cInfo)) { + printk("Get i2c device info fail"); + goto END; + } + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_READ, i2cInfo.addr, i2cInfo.offset, 1); + + if (syno_sata_pmp_read_i2c(ap, &i2cPkg)) { + goto END; + } + + if (blCLR) { + i2cPkg.inputData[0]= i2cPkg.resultData[0] & (~i2cInfo.mask); + } else { + i2cPkg.inputData[0]= i2cPkg.resultData[0] | i2cInfo.mask; + } + + if (syno_sata_pmp_write_i2c(ap, &i2cPkg)) { + goto END; + } + } + + iRet = 0; +END: + return iRet; +} + +static int syno_sata_pmp_read_unique(struct ata_port *ap) +{ + int iRet = -1; + unsigned short vendor = 0; + unsigned short devid = 0; + SYNO_PM_PKG pm_pkg; + unsigned int var = 0; + + if (!ap) { + goto END; + } + + vendor = sata_pmp_gscr_vendor(ap->link.device->gscr); + devid = sata_pmp_gscr_devid(ap->link.device->gscr); + + if (syno_pm_is_9705(vendor, devid)) { + syno_pm_unique_pkg_init(vendor, devid, &pm_pkg); + + if (syno_sata_pmp_read_gpio(ap, &pm_pkg)) { + printk("ata%d pm unique read fail\n", ap->print_id); + goto END; + } + + ap->PMSynoUnique = pm_pkg.var & 0x1f; + if (!syno_pm_is_synology_9705(ap)) { + syno_9705_workaround(ap); + } + } else if (syno_pm_is_jmb575(vendor, devid)) { + if(syno_sata_jmb575_custom_cmd(ap, SYNO_JMB575_GET_UNIQUE_ID, &var)) { + printk("ata%d jmb575 pm unique read fail\n", ap->print_id); + goto END; + } + ap->PMSynoUnique = var & 0xFF; + } else { + printk("Get unique fail, unknown pmp\n"); + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static int syno_libata_pm_power_ctl_core(struct ata_port *ap, u8 pwrOp) +{ + int iRet = -1; + int iRetry = 0; + + unsigned short vendor = 0; + unsigned short devid = 0; + SYNO_PM_PKG pm_pkg; + struct device_node *pEBoxNode; + struct device_node *pPwrNode; + SYNO_JMB575_I2C_DEV_INFO i2cInfo; + SYNO_PM_I2C_PKG i2cPkg; + u8 blPowerOn = (pwrOp & (SYNO_PWR_OP_POWER_ON | SYNO_PWR_OP_WAKE))? 1 : 0; + int i = 0; + int regManual = 0; + + if (NULL == ap) { + goto END; + } + + vendor = sata_pmp_gscr_vendor(ap->link.device->gscr); + devid = sata_pmp_gscr_devid(ap->link.device->gscr); + + for (iRetry = 0; blPowerOn ^ syno_pm_is_poweron(ap) + && iRetry < SYNO_PMP_PWR_TRIES; ++iRetry) { + + if (!blPowerOn) { + if (syno_sata_pmp_check_powerbtn(ap)) { + printk("check Eunit port %d power button fail\n", ap->print_id); + } + + /* if DS poweroff disable deepsleep indicator + * else, enable it + */ + if (SYSTEM_POWER_OFF == system_state) { + syno_libata_pmp_deepsleep_indicator_set(ap, 1); + } else { + syno_libata_pmp_deepsleep_indicator_set(ap, 0); + } + } + else { + /* If eunit poweron, disable the eunit deepsleep indicator*/ + syno_libata_pmp_deepsleep_indicator_set(ap, 1); + } + +#ifdef MY_ABC_HERE + if (blPowerOn && 0 == ap->PMSynoEMID) { + ap->pflags |= ATA_PFLAG_SYNO_BOOT_PROBE; + } +#endif /* MY_ABC_HERE */ + + if (syno_pm_is_9705(vendor, devid)) { + syno_pm_poweron_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &pm_pkg, 0); + if (syno_sata_pmp_write_gpio(ap, &pm_pkg)) { + printk("ata%d pm poweron write 0 fail\n", ap->print_id); + goto END; + } + + if (blPowerOn) { + mdelay(5); /* don't do it too fast. Otherwise CPLD might not response */ + } else { + mdelay(7000); /* hardware spec */ + } + + syno_pm_poweron_pkg_init(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + &pm_pkg, 1); + if (syno_sata_pmp_write_gpio(ap, &pm_pkg)) { + if (system_state != SYSTEM_POWER_OFF) { + printk("ata%d pm poweron write 1 fail\n", ap->print_id); + } + goto END; + } + + if (blPowerOn) { + DBGMESG("port %d delay 3000ms wait for HW ready\n", ap->print_id); + mdelay(3000); + + ata_port_printk(ap, KERN_INFO, "PMP Power control set ATA_EH_SYNO_PWON\n"); + ap->link.eh_context.i.action |= ATA_EH_SYNO_PWON; + } + + mdelay(1000); + + /* test if this power control success */ + if (syno_sata_pmp_read_unique(ap)) { + printk("ata%d re-check pm unique read fail\n", ap->print_id); + goto END; + } + } else if (syno_pm_is_jmb575(vendor, devid)) { + + if (SYNO_PWR_OP_POWER_ON != pwrOp && SYNO_PWR_OP_POWER_OFF != pwrOp) { + break; + } + + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Get EBox node fail"); + goto END; + } + + if (NULL == (pPwrNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_I2C_PWR_CTL))) { + printk("Get node %s fail", SZ_DTS_EBOX_I2C_PWR_CTL); + goto END; + } + + if (syno_jmb575_get_i2c_info(ap, pPwrNode, &i2cInfo)) { + printk("Get i2c device info fail"); + goto END; + } + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_READ, i2cInfo.addr, i2cInfo.offset, 1); + + if (syno_sata_pmp_read_i2c(ap, &i2cPkg)) { + goto END; + } + + i2cPkg.inputData[0]= blPowerOn ? (i2cPkg.resultData[0] | i2cInfo.mask) : (i2cPkg.resultData[0] &= (~i2cInfo.mask)); + + if (syno_sata_pmp_write_i2c(ap, &i2cPkg)) { + goto END; + } + } + + if (blPowerOn ^ syno_pm_is_poweron(ap)) { + if (iRetry == (SYNO_PMP_PWR_TRIES - 1)) { + printk("port %d do pmp power ctl %d after %d tries fail\n", + ap->print_id, blPowerOn, SYNO_PMP_PWR_TRIES); + } else { + printk("port %d do pmp power ctl %d fail, retry it\n", ap->print_id, blPowerOn); + } + } else { + break; + } + } + + if (syno_pm_is_jmb575(vendor, devid) && (SYNO_PWR_OP_DEEPSLEEP == pwrOp || SYNO_PWR_OP_WAKE == pwrOp || SYNO_PWR_OP_POWER_ON == pwrOp)) { + + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Get EBox node fail"); + goto END; + } + + if (NULL == (pPwrNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_I2C_DEEPSELLP_CTL))) { + printk("Get node %s fail\n", SZ_DTS_EBOX_I2C_DEEPSELLP_CTL); + goto END; + } + + if (syno_jmb575_get_i2c_info(ap, pPwrNode, &i2cInfo)) { + printk("Get i2c device info fail"); + goto END; + } + + if (SYNO_PWR_OP_DEEPSLEEP == pwrOp) { + for (i = 0; 0 == of_property_read_u32_index(pPwrNode, SZ_DTS_EBOX_I2C_REG_MANUAL_ENABLE, i, ®Manual); i++) { + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_WRITE, i2cInfo.addr, regManual, 1); + i2cPkg.inputData[0] = 0x00; + if (syno_sata_pmp_write_i2c(ap, &i2cPkg)) { + printk("PM BP manual reg %d set fail\n", i); + goto END; + } + } + } + + syno_libata_pmp_deepsleep_indicator_set(ap, blPowerOn); + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_WRITE, i2cInfo.addr, i2cInfo.offset, 1); + if (SYNO_PWR_OP_DEEPSLEEP == pwrOp) { + i2cPkg.inputData[0] = 0x01; + } else if (SYNO_PWR_OP_WAKE == pwrOp || SYNO_PWR_OP_POWER_ON == pwrOp) { + i2cPkg.inputData[0] = 0x00; + } + + if (syno_sata_pmp_write_i2c(ap, &i2cPkg)) { + printk("pm BP %s fail", blPowerOn? "wake":"deepsleep"); + goto END; + } + + } + + iRet = 0; +END: + return iRet; +} + +int syno_pm_show_sn(struct ata_device *dev) +{ + struct ata_port *ap = dev->link->ap; + int iRet = -1; + int i = 0; + struct device_node *pEBoxNode = NULL; + struct device_node *pSnNode = NULL; + SYNO_JMB575_I2C_DEV_INFO snInfo; + SYNO_PM_I2C_PKG i2cPkg; +#ifdef MY_ABC_HERE + int slotIdx = -1; +#endif /* MY_ABC_HERE*/ + + char szSn[MAX_EBOX_SN_LEN + 1] = {'\0'}; + + if (NULL == ap) { + goto END; + } + + if (!IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique)) { + goto END; + } + + if (0 != ap->PMSynoEMID) { + goto END; + } + + if (syno_pmp_get_ebox_node_by_unique_id(ap->PMSynoUnique, ap->PMSynoIsRP, &pEBoxNode)) { + printk("Failed to get EBox node\n"); + goto END; + } + + if (NULL == (pSnNode = of_get_child_by_name(pEBoxNode, SZ_DTS_EBOX_I2C_SN_READ))) { + printk("Failed to get node %s\n", SZ_DTS_EBOX_I2C_SN_READ); + goto END; + } + + if (of_property_read_u32_index(pSnNode, SZ_DTS_EBOX_I2C_OFFSET, 0, &snInfo.offset)) { + printk("Failed to get %s\n", SZ_DTS_EBOX_I2C_OFFSET); + goto END; + } + + if (syno_pmp_i2c_addr_get(pSnNode, &snInfo.addr)) { + printk("Failed to get i2c addr\n"); + goto END; + } + + if (!dev->sdev) { + printk("Failed to read EBox SN"); + goto END; + } + + for (i = 0; i < MAX_EBOX_SN_LEN; ++i) { + + syno_init_i2c_pkg(&i2cPkg, PM_I2C_OP_READ, snInfo.addr, snInfo.offset + i, 1); + + if (syno_i2c_with_scmd(ap, dev->sdev, &i2cPkg, READ)) { + printk("Failed to read EBox SN\n"); + goto END; + } + + szSn[i] = i2cPkg.resultData[0]; + } + +#ifdef MY_ABC_HERE + slotIdx = syno_external_libata_index_get(ap); + if (-1 != slotIdx) { + ata_dev_info(dev, "External Slot %d Eunit SN: %s\n", syno_external_libata_index_get(ap), szSn); + } else { + ata_dev_info(dev, "Eunit SN: %s\n", szSn); + } +#else + ata_dev_info(dev, "Eunit SN: %s\n", szSn); +#endif + +END: + return iRet; +} + +int +syno_libata_pm_power_ctl(struct ata_port *ap, u8 pwrOp, u8 blCustomInfo) +{ + int iRet = -1; + unsigned long flags = 0; + u8 blPowerOn = pwrOp & 0x01; + + if (NULL == ap) { + goto END; + } + + spin_lock_irqsave(ap->lock, flags); + while (ap->pflags & ATA_PFLAG_PMP_PMCTL) { + DBGMESG("port %d can't do pmp power ctl %d, must waiting for others\n", ap->print_id, blPowerOn); + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ); + spin_lock_irqsave(ap->lock, flags); + } + /* lock to prevent others to do pmp power control */ + ap->pflags |= ATA_PFLAG_PMP_PMCTL; + /* we should make sure this port isn't frozen */ + if (ap->pflags & ATA_PFLAG_FROZEN) { + printk("ata%u: is FROZEN, thaw it now\n", ap->print_id); + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_thaw_port(ap); + spin_lock_irqsave(ap->lock, flags); + } + DBGMESG("port %d do pmp power ctl %d, and thaw it\n", ap->print_id, blPowerOn); + spin_unlock_irqrestore(ap->lock, flags); + + if (syno_sata_pmp_read_unique(ap)) { + printk("ata%d pm unique read fail\n", ap->print_id); + goto END; + } + + if (blCustomInfo && blPowerOn) { + syno_sata_pmp_read_cpld_ver(ap); + + syno_sata_pmp_read_emid(ap); + + syno_sata_pmp_show_fw_info(ap); + + mdelay(1000); + + if(syno_sata_pmp_is_rp(ap)) { + ap->PMSynoIsRP = 1; + }else{ + ap->PMSynoIsRP = 0; + } + } + + if(IS_SYNOLOGY_DXC(ap->PMSynoUnique) || + IS_SYNOLOGY_RXC(ap->PMSynoUnique) || + IS_SYNOLOGY_RX1214(ap->PMSynoUnique) || + IS_SYNOLOGY_RX1217(ap->PMSynoUnique) || + IS_SYNOLOGY_DX1215(ap->PMSynoUnique) || + IS_SYNOLOGY_DX1222(ap->PMSynoUnique) || + IS_SYNOLOGY_DX1215II(ap->PMSynoUnique) || + IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique)) { + if(0 != ap->PMSynoEMID) { + goto END; + } + } + + if (1 == ap->PMSynoPowerDisable) { + goto SKIP_POWER_ON; + } + + if (syno_libata_pm_power_ctl_core(ap, pwrOp)) { + printk("ata%d power control fail\n", ap->print_id); + } + +SKIP_POWER_ON: + syno_sata_pmp_read_switch_mode(ap); + + iRet = 0; + +END: + /* unlock to let others can do pmp power control */ + DBGMESG("port %d do pmp power ctl %d done iRet %d\n", ap->print_id, blPowerOn, iRet); + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~ATA_PFLAG_PMP_PMCTL; + spin_unlock_irqrestore(ap->lock, flags); + return iRet; +} +#endif /* MY_ABC_HERE */ + /** * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP * @qc: ATA command in question @@ -222,7 +2230,11 @@ int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, */ static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) { +#ifdef MY_ABC_HERE + static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 , SATA_PMP_GSCR_SYNO, SATA_PMP_GSCR_LOGY}; +#else /* MY_ABC_HERE */ static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 }; +#endif /* MY_ABC_HERE */ int i; for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) { @@ -233,6 +2245,11 @@ static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) if (err_mask) { ata_dev_err(dev, "failed to read PMP GSCR[%d] (Emask=0x%x)\n", reg, err_mask); +#ifdef MY_ABC_HERE + if (SATA_PMP_GSCR_SYNO == reg || SATA_PMP_GSCR_LOGY == reg) { + continue; + } +#endif /* MY_ABC_HERE */ return -EIO; } } @@ -265,7 +2282,11 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) const char *reason; int nr_ports, rc; +#ifdef MY_ABC_HERE + nr_ports = syno_pmp_ports_num(ap); +#else /* MY_ABC_HERE */ nr_ports = sata_pmp_gscr_ports(gscr); +#endif /* MY_ABC_HERE */ if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) { rc = -EINVAL; @@ -514,12 +2535,27 @@ int sata_pmp_attach(struct ata_device *dev) if (rc) goto fail; +#ifdef MY_ABC_HERE + /* Get information for all PM we supported */ + syno_pm_gpio_config(ap); + syno_prepare_custom_info(ap); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (0 == ap->PMSynoEMID && !(ap->pflags & ATA_PFLAG_SYNO_DS_WAKING)) { + ap->pflags |= ATA_PFLAG_SYNO_BOOT_PROBE; + } +#endif /* MY_ABC_HERE */ + /* config PMP */ rc = sata_pmp_configure(dev, 1); if (rc) goto fail; +#ifdef MY_ABC_HERE + rc = sata_pmp_init_links(ap, syno_pmp_ports_num(ap)); +#else /* MY_ABC_HERE */ rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr)); +#endif /* MY_ABC_HERE */ if (rc) { ata_dev_info(dev, "failed to initialize PMP links\n"); goto fail; @@ -528,17 +2564,29 @@ int sata_pmp_attach(struct ata_device *dev) /* attach it */ spin_lock_irqsave(ap->lock, flags); WARN_ON(ap->nr_pmp_links); +#ifdef MY_ABC_HERE + ap->nr_pmp_links = syno_pmp_ports_num(ap); +#else /* MY_ABC_HERE */ ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr); +#endif /* MY_ABC_HERE */ spin_unlock_irqrestore(ap->lock, flags); sata_pmp_quirks(ap); +#ifdef MY_ABC_HERE + syno_pm_device_config(ap); +#endif /* MY_ABC_HERE */ + if (ap->ops->pmp_attach) ap->ops->pmp_attach(ap); ata_for_each_link(tlink, ap, EDGE) sata_link_init_spd(tlink); +#ifdef MY_ABC_HERE + ap->pflags |= ATA_PFLAG_PMP_CONNECT; +#endif /* MY_ABC_HERE */ + return 0; fail: @@ -556,7 +2604,11 @@ int sata_pmp_attach(struct ata_device *dev) * LOCKING: * Kernel thread context (may sleep). */ +#ifdef MY_ABC_HERE +void sata_pmp_detach(struct ata_device *dev) +#else /* MY_ABC_HERE */ static void sata_pmp_detach(struct ata_device *dev) +#endif /* MY_ABC_HERE */ { struct ata_link *link = dev->link; struct ata_port *ap = link->ap; @@ -568,6 +2620,36 @@ static void sata_pmp_detach(struct ata_device *dev) WARN_ON(!ata_is_host_link(link) || dev->devno || link->pmp != SATA_PMP_CTRL_PORT); +#ifdef MY_ABC_HERE + if ((dev->link->uiSflags || dev->link->ap->uiSflags) && ata_dev_enabled(dev)) { + ata_dev_printk(dev, KERN_WARNING, + "still have recovery flags link 0x%x ap 0x%x, don't detach this pmp dev\n", dev->link->uiSflags, dev->link->ap->uiSflags); + dev->ulSflags |= ATA_SYNO_DFLAG_PMP_DETACH; + /*FIXME: set detach flag, copy form ata_eh_detach_dev */ + ata_for_each_link(tlink, ap, EDGE) { + tlink->device->ulSflags |= ATA_SYNO_DFLAG_DETACH; + } + return; + } + dev->ulSflags &= ~ATA_SYNO_DFLAG_PMP_DETACH; + ata_for_each_link(tlink, ap, EDGE) { + DBGMESG("ata%u: do pmp detach, clear all link uiSflags\n", dev->link->ap->print_id); + tlink->uiSflags = 0; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ata_for_each_link(tlink, ap, EDGE) { + unsigned int *classes = tlink->eh_context.classes; + struct ata_device *tdev = tlink->device; + classes[tdev->devno] = ATA_DEV_UNKNOWN; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ap->PMSynoUnique = 0; +#endif /* MY_ABC_HERE */ + if (ap->ops->pmp_detach) ap->ops->pmp_detach(ap); @@ -578,6 +2660,11 @@ static void sata_pmp_detach(struct ata_device *dev) ap->nr_pmp_links = 0; link->pmp = 0; spin_unlock_irqrestore(ap->lock, flags); + +#ifdef MY_ABC_HERE + ap->pflags |= ATA_PFLAG_PMP_DISCONNECT; + ata_dev_printk(dev, KERN_WARNING, "flag ATA_PFLAG_PMP_DISCONNECT on (pflags=0x%x)\n", dev->link->ap->pflags); +#endif /* MY_ABC_HERE */ } /** @@ -599,13 +2686,21 @@ static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr) const u32 *old_gscr = dev->gscr; u16 old_vendor, new_vendor, old_devid, new_devid; int old_nr_ports, new_nr_ports; +#ifdef MY_ABC_HERE + struct ata_port *ap = dev->link->ap; + u32 old_syno_unique = ap->PMSynoUnique; +#endif /* MY_ABC_HERE */ old_vendor = sata_pmp_gscr_vendor(old_gscr); new_vendor = sata_pmp_gscr_vendor(new_gscr); old_devid = sata_pmp_gscr_devid(old_gscr); new_devid = sata_pmp_gscr_devid(new_gscr); +#ifdef MY_ABC_HERE + new_nr_ports = old_nr_ports = syno_pmp_ports_num(ap); +#else /* MY_ABC_HERE */ old_nr_ports = sata_pmp_gscr_ports(old_gscr); new_nr_ports = sata_pmp_gscr_ports(new_gscr); +#endif /* MY_ABC_HERE */ if (old_vendor != new_vendor) { ata_dev_info(dev, @@ -628,6 +2723,18 @@ static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr) return 0; } +#ifdef MY_ABC_HERE + /* power on and re-custom */ + syno_pm_gpio_config(ap); + syno_prepare_custom_info(ap); + if (SYNO_UNIQUE(old_syno_unique) != SYNO_UNIQUE(ap->PMSynoUnique)) { + ata_dev_printk(dev, KERN_ERR, + "Got different EBox Model old [0x%x], new [0x%x]\n", SYNO_UNIQUE(old_syno_unique), SYNO_UNIQUE(ap->PMSynoUnique)); + return 0; + } + syno_pm_device_config(ap); +#endif /* MY_ABC_HERE */ + return 1; } @@ -758,12 +2865,18 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, int tries = ATA_EH_PMP_TRIES; int detach = 0, rc = 0; int reval_failed = 0; +#ifdef MY_ABC_HERE + unsigned int uiSflags = 0x0; +#endif /* MY_ABC_HERE */ DPRINTK("ENTER\n"); if (dev->flags & ATA_DFLAG_DETACH) { detach = 1; rc = -ENODEV; +#ifdef MY_ABC_HERE + ata_dev_printk(dev, KERN_WARNING, "ATA_DFLAG_DETACH (flags=0x%lx)\n", dev->flags); +#endif /* MY_ABC_HERE */ goto fail; } @@ -832,6 +2945,14 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap, return 0; fail: + +#ifdef MY_ABC_HERE + /* set link error flags to ata port for ata port error handling. */ + if ((uiSflags = uiCheckPortLinksFlags(ap))) { + ap->uiSflags = uiSflags; + } +#endif /* MY_ABC_HERE */ + sata_pmp_detach(dev); if (detach) ata_eh_detach_dev(dev); @@ -933,6 +3054,9 @@ static int sata_pmp_eh_recover(struct ata_port *ap) unsigned int err_mask; u32 gscr_error, sntf; int cnt, rc; +#ifdef MY_ABC_HERE + unsigned int uiSflags = 0x0; +#endif /* MY_ABC_HERE */ pmp_tries = ATA_EH_PMP_TRIES; ata_for_each_link(link, ap, EDGE) @@ -1058,6 +3182,12 @@ static int sata_pmp_eh_recover(struct ata_port *ap) goto retry; } +#ifdef MY_ABC_HERE + /* set link error flags to ata port for ata port error handling. */ + uiSflags = uiCheckPortLinksFlags(ap); + ap->uiSflags = uiSflags; +#endif /* MY_ABC_HERE */ + return 0; link_fail: @@ -1084,6 +3214,12 @@ static int sata_pmp_eh_recover(struct ata_port *ap) ata_port_err(ap, "failed to recover PMP after %d tries, giving up\n", ATA_EH_PMP_TRIES); +#ifdef MY_ABC_HERE + /* set link error flags to ata port for ata port error handling. */ + if ((uiSflags = uiCheckPortLinksFlags(ap))) { + ap->uiSflags = uiSflags; + } +#endif /* MY_ABC_HERE */ sata_pmp_detach(pmp_dev); ata_dev_disable(pmp_dev); diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index c16423e44525..97964f4c0e55 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * SATA specific part of ATA helper library @@ -17,9 +20,17 @@ #include "libata-transport.h" /* debounce timing parameters in msecs { interval, duration, timeout } */ +#ifdef MY_ABC_HERE +const unsigned long sata_deb_timing_normal[] = { 5, 100, 6000 }; +#else /* MY_ABC_HERE */ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; +#endif /* MY_ABC_HERE */ EXPORT_SYMBOL_GPL(sata_deb_timing_normal); +#ifdef MY_ABC_HERE +const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 6000 }; +#else /* MY_ABC_HERE */ const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; +#endif /* MY_ABC_HERE */ EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; EXPORT_SYMBOL_GPL(sata_deb_timing_long); @@ -592,7 +603,12 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, pmp_deadline = ata_deadline(jiffies, ATA_TMOUT_PMP_SRST_WAIT); +#ifdef MY_ABC_HERE + /* SSD Intel S4500 3.84TB Hotplug 100% failed on SATA controller Marvell 88SE9235. */ + if (time_before(pmp_deadline, deadline)) +#else if (time_after(pmp_deadline, deadline)) +#endif /* MY_ABC_HERE */ pmp_deadline = deadline; ata_wait_ready(link, pmp_deadline, check_ready); } @@ -609,12 +625,161 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, if (online) *online = false; ata_link_err(link, "COMRESET failed (errno=%d)\n", rc); +#ifdef MY_ABC_HERE + if (-EBUSY == rc || -EIO == rc) { + ata_link_printk(link, KERN_ERR, "COMRESET fail, set COMRESET fail flag\n"); + link->uiSflags |= ATA_SYNO_FLAG_COMRESET_FAIL; + } +#endif /* MY_ABC_HERE */ } DPRINTK("EXIT, rc=%d\n", rc); return rc; } EXPORT_SYMBOL_GPL(sata_link_hardreset); +#ifdef MY_ABC_HERE +/* Calculate the complete commands latency and record into latency statisics. + * + * Disk drive could queue multiple waiting commands (NCQ) + * and one interrupt may carry multiple complete commands, + * So the wating time that command in the disk queue + * makes the latency time become inaccurate. + * + * To solve above problem, we try to estimate the processing time of one command. + * + * We use the some assumptions to estimate the latency. + * 1. When disk drive complete one command, + * it would immediately process the next command in the queue. + * 2. In the short interval, all the command processing time may equally. + * + * + * The following example show how we get approximate latency. + * + * Si : the ith command send to the disk drive from host. + * Ci : the ith command is completed and report to host. + * I : host generate interrupt and let software to check complete commands. + * + * Ex . + * S1 S2 S3 S4 C1 C2 C3 C4 + * ---|---|---|---|---|---|---|---|---|---|---|---|---| + * 1s 4s 8s I 12s I + * + * The first interrupt carry completed commands 1'st and 2'nd. + * The time that drive process this 2 commands sould be + * the time of disk drive complete the last command [1.] minus + * the time of disk drive start to process the first command in this interval [2.] + * And according the assumption 2., the approximate latency of this commands is + * the total process time divide the number of commands in this interrupt. + * So the latency of this 2 commands should be (9s - 1s) / 2 = 4s. + * + * [1.] we use the time of interrupt generate to approach completed time. + * [2.] we use the issue time of first command to approach the start time. + * + * The second interrupt carry completed commands 3'th and 4'th, + * we could use same way to get approximate latency of this commands. + * But according the assumption 1., + * we do not use the issue time of first command to approach the start time, + * Actually, we should use the time of last interrupt to approach the start time. + * So the latency of this 2 commands should be (13s - 9s) / 2 = 2s. + * + */ +static void syno_ata_latency_calculate(struct ata_link *link, u64 u64AtaIntrTime) +{ + int iType = 0; + unsigned int uBucketOffset = 0; + u64 u64CmdStartTime = 0; + u64 u64CmdLatencyTime = 0; + u64 u64StepOffset = 0; + +#ifdef MY_ABC_HERE + u8 u8LbaZone = link->ata_latency.u8CplCmdSeqLbaZone & + SYNO_SEQ_SAMPLE_LBA_ZONE_MASK; +#endif /* MY_ABC_HERE */ + + if (0 == link->ata_latency.u16TotalCplCmdCnt) { + goto END; + } + + /* get the qc complete time */ + u64CmdStartTime = (link->ata_latency.u64FirstCmdStartTime + > link->ata_latency.u64LastIntrTime) + ? link->ata_latency.u64FirstCmdStartTime + : link->ata_latency.u64LastIntrTime; + u64CmdLatencyTime = div_u64((u64AtaIntrTime - u64CmdStartTime), + link->ata_latency.u16TotalCplCmdCnt); + +#ifdef MY_ABC_HERE + if (SYNO_ALL_SEQ_READ == link->ata_latency.u8CplCmdSeqState) { + link->seq_stat.u64TotalSampleTime[u8LbaZone] += u64CmdLatencyTime * + link->ata_latency.u16CplCmdCnt[1]; + link->seq_stat.u64TotalSampleBytes[u8LbaZone] += link->ata_latency.u32CplCmdBytes[1]; + link->seq_stat.u64TotalSampleSkipBytes[u8LbaZone] += link->ata_latency.u32CplCmdSkipBytes[1]; + } +#endif /* MY_ABC_HERE */ + + /* calculate the latency buckets + * + * bucket[ 0 ~ 31 ] : step is 32 us + * bucket[ 32 ~ 63 ] : step is 1 ms + * bucket[ 64 ~ 95 ] : step is 32 ms + * + * so the limit of latency is 1024 ms which is 20 bits or 0x100000 + * + * 1 1 1 1 1 | 1 1 1 1 1 | 1 1 1 1 1 | 1 1 1 1 1 + * 0 ~ 31 us 32 ~ 1024 us 1 ~ 31 ms 32 ~ 1023 ms + * + */ + /* shift to 32us */ + u64StepOffset = (u64CmdLatencyTime >> 15); + /* calculate the offset of buckets with the latency time */ + uBucketOffset = syno_ata_latency_bucket_offset_get(u64StepOffset); + u64StepOffset >>= (5 * uBucketOffset); + if (unlikely(31 < u64StepOffset)) { + uBucketOffset = (SYNO_LATENCY_BUCKETS_END - 1); + u64StepOffset = 31; + } + + for (iType = 0 ; iType < SYNO_LATENCY_TYPE_COUNT; iType++) { + link->latency_stat.u64TotalTime[iType] + += (u64CmdLatencyTime * link->ata_latency.u16CplCmdCnt[iType]); + + link->ata_latency.u64TimeBuckets[iType][uBucketOffset][u64StepOffset] + += link->ata_latency.u16CplCmdCnt[iType]; + } + + if (!link->sactive) { + /* + * when the link is inactive, it means the whole batch is complete, + * so we record the last qc complete time, + * and use it to calculate the pending time between two batch. + */ + link->ata_latency.u64BatchComplete = u64AtaIntrTime; + link->latency_stat.u64TotalBatchCount += 1; + link->latency_stat.u64TotalBatchTime += + (u64AtaIntrTime - link->ata_latency.u64BatchIssue); + } + + /* update last intr time if there is any cmd been process */ + link->ata_latency.u64LastIntrTime = u64AtaIntrTime; +END: + /* reset the link ata latency state */ + link->ata_latency.u64FirstCmdStartTime = 0; + link->ata_latency.u16TotalCplCmdCnt = 0; +#ifdef MY_ABC_HERE + link->ata_latency.u8CplCmdSeqState = 0; + link->ata_latency.u8CplCmdSeqLbaZone = 0; +#endif /* MY_ABC_HERE */ + for (iType = 0 ; iType < SYNO_LATENCY_TYPE_COUNT; iType++) { + link->ata_latency.u16CplCmdCnt[iType] = 0; +#ifdef MY_ABC_HERE + link->ata_latency.u32CplCmdBytes[iType] = 0; + link->ata_latency.u32CplCmdSkipBytes[iType] = 0; +#endif /* MY_ABC_HERE */ + } + return; +} +#endif /* MY_ABC_HERE */ + /** * ata_qc_complete_multiple - Complete multiple qcs successfully * @ap: port in question @@ -639,6 +804,11 @@ int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active) { u64 done_mask, ap_qc_active = ap->qc_active; int nr_done = 0; +#ifdef MY_ABC_HERE + struct ata_link *link = NULL; + + ap->u64AtaIntrTime = cpu_clock(0); +#endif /* MY_ABC_HERE */ /* * If the internal tag is set on ap->qc_active, then we care about @@ -669,6 +839,11 @@ int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active) } done_mask &= ~(1ULL << tag); } +#ifdef MY_ABC_HERE + ata_for_each_link(link, ap, HOST_FIRST) { + syno_ata_latency_calculate(link, ap->u64AtaIntrTime); + } +#endif /* MY_ABC_HERE */ return nr_done; } @@ -1302,6 +1477,39 @@ int sata_async_notification(struct ata_port *ap) if (rc == 0) sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); +#ifdef MY_ABC_HERE + /* If PMP is reporting that PHY status of some downstream ports has changed, + * sata_async_notification will call schedule EH. + * So in IRQ_OFF we ignore the PMP interrupt + */ + if (ap->pflags & ATA_PFLAG_SYNO_IRQ_OFF) { + + if (rc) { + DBGMESG("pmp disk %d irq off and read SCR fail, ignore this interrupt, rc %d\n", ap->print_id, rc); + return 0; + } + +#ifdef MY_ABC_HERE + if (sntf & (1<< SATA_PMP_CTRL_PORT)) { + /* Only support deep sleep port, we on ATA_PFLAG_SYNO_IRQ_OFF. + * So if this case happened, we should BUG + * The following action is call sata_async_notification() + * and it will call EH. + * */ + if (0 == iIsSynoDeepSleepSupport(ap) && !(ap->pflags & ATA_PFLAG_SYNO_DS_PWROFF)) { + printk("BUG!!! This port %d didn't support deep sleep\n", ap->print_id); + WARN_ON(1); + ap->pflags &= ~ATA_PFLAG_SYNO_IRQ_OFF; + } else { + // if the eunit enter to deep sleep, we ignore the chip 1's interrupt + DBGMESG("pmp disk %d irq off, ignore this interrupt\n", ap->print_id); + return 0; + } + } +#endif /* MY_ABC_HERE */ + } +#endif /* MY_ABC_HERE */ + if (!sata_pmp_attached(ap) || rc) { /* PMP is not attached or SNTF is not available */ if (!sata_pmp_attached(ap)) { @@ -1373,6 +1581,9 @@ static int ata_eh_read_log_10h(struct ata_device *dev, unsigned int err_mask; u8 csum; int i; +#ifdef MY_ABC_HERE + struct scsi_device *sdev = dev->sdev; +#endif /* MY_ABC_HERE */ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1); if (err_mask) @@ -1404,6 +1615,13 @@ static int ata_eh_read_log_10h(struct ata_device *dev, if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id)) tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16]; +#ifdef MY_ABC_HERE + if (sdev && (0 == strncmp(sdev->vendor, "WDC", strlen("WDC")))) { + if (0x4 == buf[256] && 0x49 == buf[257]) { + tf->blTler = true; + } + } +#endif /* MY_ABC_HERE */ return 0; } @@ -1433,7 +1651,13 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) return; /* is it NCQ device error? */ +#ifdef MY_ABC_HERE + // we need to check error by reading ncq log, but the driver may not set AC_ERR_DEV correctly due to JMB585 mishandling UNC. + // when uiJM585DubiosIFSProtoFlag is set, we skip the return and let analysis keep going. + if (!link->sactive || (!(ehc->i.err_mask & AC_ERR_DEV) && !(ATA_SYNO_FLAG_JM585_READ_LOG & ehc->i.uiJM585DubiosIFSProtoFlag))) +#else /* MY_ABC_HERE */ if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) +#endif /* MY_ABC_HERE */ return; /* has LLDD analyzed already? */ @@ -1479,5 +1703,13 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) } ehc->i.err_mask &= ~AC_ERR_DEV; + +#ifdef MY_ABC_HERE + // TLER error + if (true == tf.blTler) { + ata_link_err(link, "Error caused by TLER, retry command\n"); + qc->flags |= ATA_QCFLAG_RETRY; + } +#endif /* MY_ABC_HERE */ } EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 48b8934970f3..54034cc89cda 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * libata-scsi.c - helper library for ATA @@ -37,6 +40,62 @@ #include "libata.h" #include "libata-transport.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#include +#include +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#include +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size); +extern struct klist syno_ata_port_head; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +extern DISK_PWRCTRL_TYPE SYNO_GET_DISK_PWR_TYPE(int index); +extern int SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(int index); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int SYNO_CTRL_HDD_POWERON(int index, int value); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#include +#include +#include + +extern unsigned int guiWakeupDisksNum; +static int giGroupDisks = 0; +static int giWakingDisks = 0; +static unsigned long gulLastWake = 0; +DEFINE_SPINLOCK(SYNOLastWakeLock); +extern int giSynoSpinupGroup[SYNO_SPINUP_GROUP_MAX]; +extern int giSynoSpinupGroupNum; +extern int giSynoSpinupGroupDelay; +static int gCurrentSpinupGroupNum = 0; +static int giNeedWakeAll = 0; +#endif /* MY_DEF_HERE */ + #define ATA_SCSI_RBUF_SIZE 576 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); @@ -188,6 +247,36 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR, ata_scsi_park_show, ata_scsi_park_store); EXPORT_SYMBOL_GPL(dev_attr_unload_heads); +#ifdef MY_ABC_HERE +int (*funcSYNOSATADiskLedCtrl) (int iHostNum, SYNO_DISK_LED diskLed) = NULL; +EXPORT_SYMBOL(funcSYNOSATADiskLedCtrl); + +/* control the color of disk led */ +static ssize_t +syno_sata_disk_led_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct Scsi_Host *shost = class_to_shost(device); + long led; + int rc; + + if (NULL == funcSYNOSATADiskLedCtrl) { + return -EINVAL; + } + rc = kstrtol(buf, 10, &led); + if (rc) { + return -EINVAL; + } + + rc = funcSYNOSATADiskLedCtrl(shost->host_no, led); + return len; +} +DEVICE_ATTR(syno_sata_disk_led_ctrl, S_IWUSR, + NULL, syno_sata_disk_led_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_sata_disk_led_ctrl); +#endif /* MY_ABC_HERE */ + void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) { @@ -236,8 +325,2408 @@ static void ata_scsi_set_invalid_parameter(struct ata_device *dev, field, 0xff, 0); } + +#if defined(MY_ABC_HERE) || defined (MY_ABC_HERE) +/** + * Query this ap support pm control capacity + * + * @param ap [IN] ata port + * + * @return 0: not support + * 1: support + */ +int iIsSynoPmCtlSupport(const struct ata_port *ap) +{ + int ret = 0; + + if (NULL == ap) { + DBGMESG("ap is NULL, can't check pm control support\n"); + goto END; + } + +#ifdef MY_ABC_HERE + if (-1 != ap->syno_internal_slot_index) { + /* Internal disks case */ + if (SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(ap->syno_internal_slot_index + 1)) { + ret = 1; + goto END; + } + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (ap->nr_pmp_links && syno_is_synology_pm(ap)) { + ret = 1; + goto END; + } +#endif /* MY_ABC_HERE */ + +END: + return ret; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined (MY_ABC_HERE) +/** + * Check if this port irqoff on + * + * @param [IN] ata port + * + * @return + * 1: irqoff on + * 0: not on + * + * */ +int +iIsSynoIRQOff(const struct ata_port *ap) +{ + unsigned long flags = 0; + int iRet = 0; + + if (NULL == ap) { + goto END; + } + + /* if no commands and pflags only on ATA_PFLAG_SYNO_IRQ_OFF and ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE, + * it means irq off */ + spin_lock_irqsave(ap->lock, flags); + if (0 == ap->nr_active_links && + (ap->pflags == (ATA_PFLAG_SYNO_IRQ_OFF | ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE) || + ap->pflags == (ATA_PFLAG_SYNO_IRQ_OFF | ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE | ATA_PFLAG_SYNO_DS_PWROFF) || + ap->pflags == (ATA_PFLAG_SYNO_IRQ_OFF | ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE | ATA_PFLAG_EXTERNAL) || + ap->pflags == (ATA_PFLAG_SYNO_IRQ_OFF | ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE | ATA_PFLAG_SYNO_DS_PWROFF | ATA_PFLAG_EXTERNAL))) { + iRet = 1; + } + spin_unlock_irqrestore(ap->lock, flags); + +END: + return iRet; +} +EXPORT_SYMBOL(iIsSynoIRQOff); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * Eliminate CPU usage in scemd. while there is no disks in the + * PM. Libata may need this because the bug in sil24 that need + * qc_defer. + */ +typedef struct _tag_SYNO_GPIO_TASK { + /* delay work */ + struct delayed_work work; + + /* target ata port */ + struct ata_port *ap; + + /* gpio pkg */ + SYNO_PM_PKG pm_pkg; + + /* complete interface */ + struct completion wait; + + /* indicate result */ + unsigned char blIsErr; + + /* indicate read or write */ + unsigned char blIsRead; + + /* indicate retry or not */ + unsigned char blRetry; + +} SYNO_GPIO_TASK; + +static u8 inline +defer_gpio_cmd(struct ata_port *ap, u32 input, u8 rw) +{ + u8 ret = 0; + + /* we don't want to insert any gpio while the port is in error_handling */ + if (ap->pflags & (~ATA_PFLAG_EXTERNAL)) { + ret = 1; + goto END; + } + +END: + return ret; +} + +/** + * using scsi command to enable/disable 9705 GPO + * + * @param blEnable [IN] enable or disable + * @param link [IN] Should not be NULL + * @param sdev [IN] Should not be NULL + * + * @return 0: success + * Otherwise: fail + * + * Note: On 9705, GPI and GPO are the same pin, so each pin can + * only be treated as input or output at one time, + * Before reading, need to set "output_enable" to LOW (disable). + * Before writing, need to set "output_enable" to HIGH (enable). + */ + +int +syno_pm_gpio_output_enable_with_sdev(bool blEnable, + struct ata_link *link, + struct scsi_device *sdev) +{ + int ret = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u16 feature = SATA_PMP_GSCR_9705_GPO_EN; + u8 sense[SCSI_SENSE_BUFFERSIZE]; + struct scsi_sense_hdr sshdr; + + /* Only GPI1~GPI8(GPIO 0~4,11~13) need to set LOW. */ + u32 var = (blEnable ? 0xFFFFF : 0xFC7C0); + + if (!syno_pm_is_9705(sata_pmp_gscr_vendor(link->device->gscr), + sata_pmp_gscr_devid(link->device->gscr))) { + goto END; + } + + if (NULL == link || NULL == sdev) { + ret = 1; + goto END; + } + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + memset(sense, 0, sizeof(sense)); + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1) | 1; + scsi_cmd[3] = (feature >> 8) & 0xff; + scsi_cmd[4] = feature & 0xff; + scsi_cmd[13] = link->pmp; + + scsi_cmd[6] = var & 0xff; + scsi_cmd[8] = (var >> 8) & 0xff; + scsi_cmd[10] = (var >> 16) & 0xff; + scsi_cmd[12] = (var >> 24) & 0xff; + scsi_cmd[14] = ATA_CMD_PMP_WRITE; + + ret = scsi_execute(sdev, scsi_cmd, DMA_NONE, NULL, 0, sense, &sshdr, (10*HZ), 5, 0, 0, NULL); + +END: + + return ret; +} + +/** + * Using scsi command to issue jmb575 led command + * + * @param ap [IN] Should not be NULL + * @param sde [IN] Should not be NULL + * @param pPkg [IN] Should not be NULL + * @param rw [IN] read or write + * + * @return 0: success + * Otherwise: fail + */ +int syno_jmb_575_led_ctl_with_scmd(struct ata_port *ap, + struct scsi_device *sdev, + u8 *pLedMask, + u8 rw) +{ + struct scsi_sense_hdr sshdr; + unsigned long flags = 0; + int cmd_result; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 sense[SCSI_SENSE_BUFFERSIZE]; + int ret = -EIO; + int iRetries = 0; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + memset(sense, 0, sizeof(sense)); + + if (NULL == ap || NULL == sdev || NULL == pLedMask) { + goto END; + } + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(ap->lock, flags); + while ((ap->link.uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES < iRetries)) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_gpio_with_scmd get gpio lock timeout\n"); + spin_unlock_irqrestore(ap->lock, flags); + goto RELEASE_LOCK; + } + /* lock to prevent others to do pmp gpio control */ + ap->link.uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1) | 1; + + /* Command */ + scsi_cmd[14] = ATA_CMD_PMP_SYNO_LED_GPIO; + + if (READ == rw) { + scsi_cmd[2] = 0x20; + /* LBA(0:7) */ + scsi_cmd[8] = 0x40; /* Read GPIO */ + } else { + /* LBA(0:7) */ + scsi_cmd[8] = *pLedMask; + } + + cmd_result = scsi_execute(sdev, scsi_cmd, DMA_NONE, NULL, 0, + sense, &sshdr, (10*HZ), 5, 0, 0, NULL); + + if (driver_byte(cmd_result) == DRIVER_SENSE) { + u8 *desc = sense + 8; + + if (WRITE == rw) { + ret = 0; + goto RELEASE_LOCK; + } + + cmd_result &= ~(0xFF<<24); + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, + &sshdr); + if (sshdr.sense_key == RECOVERED_ERROR && + sshdr.asc == 0 && sshdr.ascq == 0x1d) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + + *pLedMask = desc[7]; + } + + if (cmd_result) { + goto RELEASE_LOCK; + } + + ret = 0; + +RELEASE_LOCK: + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(ap->lock, flags); + ap->link.uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); +END: + return ret; +} + +static int syno_pm_jmb575_poll(struct ata_port *ap, + struct scsi_device *sdev, + char *buf, + int sectors) +{ + /* Scsi command */ + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 sense[SCSI_SENSE_BUFFERSIZE]; + struct scsi_sense_hdr sshdr; + u8 *argbuf = NULL; + int argsize = 0; + + /* Lock */ + int iRetries = 0; + unsigned long flags = 0; + + int cmd_result; + int ret = -EIO; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + memset(sense, 0, sizeof(sense)); + + if (NULL == ap || NULL == sdev || NULL == buf || 0 >= sectors) { + printk("%s: Parameters check failed\n", __func__); + goto END; + } + + if(!IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique)) { + goto END; + } + + /* Get Lock in 2s */ + spin_lock_irqsave(ap->lock, flags); + while ((ap->link.uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES < iRetries)) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(ap->lock, flags); + ++iRetries; + } + + /* Get Lock Timeout */ + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + printk("%s: Failed to get lock\n", __func__); + spin_unlock_irqrestore(ap->lock, flags); + goto RELEASE_LOCK; + } + /* lock to prevent others to do pmp gpio control */ + ap->link.uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + + /* Init CDB */ + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (0x04 << 1) | 0x01; + scsi_cmd[2] = 0x28; + scsi_cmd[4] = 0xE9; + scsi_cmd[6] = 0x01; + scsi_cmd[14] = 0xF0; + + argsize = sectors * ATA_SECT_SIZE; + argbuf = kmalloc(argsize, GFP_KERNEL); + + /* Scsi execute */ + + cmd_result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, buf, argsize, + sense, &sshdr, (10*HZ), 5, 0, 0, NULL); + + if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */ + cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ + + /* If we set cc then ATA pass-through will cause a + * check condition even if no error. Filter that. */ + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + if (sshdr.sense_key == RECOVERED_ERROR && + sshdr.asc == 0 && sshdr.ascq == 0x1d) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + } + + if (cmd_result) { + ret = -EIO; + goto END; + } + + ret = 0; + +RELEASE_LOCK: + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(ap->lock, flags); + ap->link.uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + +END: + kfree(argbuf); + return ret; +} + +/** + * Using scsi command to issue ebox i2c command + * + * @param ap [IN] Should not be NULL + * @param sde [IN] Should not be NULL + * @param pPkg [IN] Should not be NULL + * @param rw [IN] read or write + * + * @return 0: success + * Otherwise: fail + */ +int syno_i2c_with_scmd(struct ata_port *ap, + struct scsi_device *sdev, + SYNO_PM_I2C_PKG *pPkg, + u8 rw) +{ + struct scsi_sense_hdr sshdr; + unsigned long flags = 0; + int cmd_result; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 sense[SCSI_SENSE_BUFFERSIZE]; + int ret = -EIO; + int iRetries = 0; + int i = 0; + + /* i2c pkg to scmd mapping */ + const int i2c_pkg_to_scmd[7] = {10, 12, 7, 9, 11, 6, 5}; + const int desc_to_i2c_pkg[7] = {7, 9, 11, 6, 8, 10, 5}; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + memset(sense, 0, sizeof(sense)); + + if (NULL == ap || NULL == sdev || NULL == pPkg) { + goto END; + } + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(ap->lock, flags); + while ((ap->link.uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES < iRetries)) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_gpio_with_scmd get gpio lock timeout\n"); + spin_unlock_irqrestore(ap->lock, flags); + goto RELEASE_LOCK; + } + /* lock to prevent others to do pmp gpio control */ + ap->link.uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1) | 1; + + /* LBA(0:7) */ + scsi_cmd[8] = pPkg->offset; + /* Command */ + scsi_cmd[14] = ATA_CMD_PMP_SYNO_I2C; + + if (READ == rw) { + scsi_cmd[2] = 0x20; + /* Feature(15:8) */ + scsi_cmd[3] = 1; + /* Feature(0:7) */ + scsi_cmd[4] = pPkg->addr << 1 | 0x01; /* Read */ + /* Device */ + scsi_cmd[13] = pPkg->len; + } else { + /* Feature(0:7) */ + scsi_cmd[4] = pPkg->addr << 1; + /* Device */ + scsi_cmd[13] = pPkg->len + 1; /* Add 1 for i2c dev offset */ + /* Write Data */ + for (i = 0; i < pPkg->len; i++) { + if (ARRAY_SIZE(i2c_pkg_to_scmd) > i) { + scsi_cmd[i2c_pkg_to_scmd[i]] = pPkg->inputData[i]; + } + } + } + + cmd_result = scsi_execute(sdev, scsi_cmd, DMA_NONE, NULL, 0, + sense, &sshdr, (10*HZ), 5, 0, 0, NULL); + + if (driver_byte(cmd_result) == DRIVER_SENSE) { + u8 *desc = sense + 8; + + if (WRITE == rw) { + ret = 0; + goto END; + } + + cmd_result &= ~(0xFF<<24); + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, + &sshdr); + if (sshdr.sense_key == RECOVERED_ERROR && + sshdr.asc == 0 && sshdr.ascq == 0x1d) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + + for (i = 0; i < pPkg->len; i++) { + if (ARRAY_SIZE(desc_to_i2c_pkg) > i) { + pPkg->resultData[i] = desc[desc_to_i2c_pkg[i]]; + } + } + } + + if (cmd_result) { + goto END; + } + + ret = 0; + +RELEASE_LOCK: + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(ap->lock, flags); + ap->link.uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); +END: + return ret; +} + +/** + * using scsi command to issue gpio command + * + * @param ap [IN] Should not be NULL + * @param sdev [IN] Should not be NULL + * @param pPkg [IN] Should not be NULL + * @param rw [IN] read or write + * + * @return 0: success + * Otherwise: fail + */ +int syno_gpio_with_scmd(struct ata_port *ap, + struct scsi_device *sdev, + SYNO_PM_PKG *pPkg, + u8 rw) +{ + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 sense[SCSI_SENSE_BUFFERSIZE]; + int ret = -EIO; + int cmd_result; + struct scsi_sense_hdr sshdr; + unsigned long flags = 0; + int iRetries = 0; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + memset(sense, 0, sizeof(sense)); + + if (NULL == ap) { + goto END; + } + + /* Get gpio ctrl lock in 2s */ + spin_lock_irqsave(ap->lock, flags); + while ((ap->link.uiStsFlags & SYNO_STATUS_GPIO_CTRL) && (SYNO_PMP_GPIO_TRIES < iRetries)) { + spin_unlock_irqrestore(ap->lock, flags); + schedule_timeout_uninterruptible(HZ/2); + spin_lock_irqsave(ap->lock, flags); + ++iRetries; + } + + if (SYNO_PMP_GPIO_TRIES <= iRetries) { + DBGMESG("syno_gpio_with_scmd get gpio lock timeout\n"); + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } + /* lock to prevent others to do pmp gpio control */ + ap->link.uiStsFlags |= SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + + syno_pm_device_info_set(ap, rw, pPkg); + + if (READ == rw) { + if (syno_pm_gpio_output_enable_with_sdev(false, &ap->link, sdev)) { + goto END; + } + } else if (WRITE == rw) { + if (syno_pm_gpio_output_enable_with_sdev(true, &ap->link, sdev)) { + goto END; + } + } + + if (READ == rw) { + scsi_cmd[2] = 0x20; + scsi_cmd[14] = ATA_CMD_PMP_READ; + } else { + if (pPkg->encode) { + pPkg->encode(pPkg, WRITE); + } + scsi_cmd[6] = pPkg->var & 0xff; + scsi_cmd[8] = (pPkg->var >> 8) & 0xff; + scsi_cmd[10] = (pPkg->var >> 16) & 0xff; + scsi_cmd[12] = (pPkg->var >> 24) & 0xff; + scsi_cmd[14] = ATA_CMD_PMP_WRITE; + } + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1) | 1; + scsi_cmd[3] = (pPkg->gpio_addr >> 8) & 0xff; + scsi_cmd[4] = pPkg->gpio_addr & 0xff; + scsi_cmd[13] = ap->link.pmp; + + cmd_result = scsi_execute(sdev, scsi_cmd, DMA_NONE, NULL, 0, + sense, &sshdr, (10*HZ), 5, 0, 0, NULL); + + if (driver_byte(cmd_result) == DRIVER_SENSE) { + u8 *desc = sense + 8; + + if (WRITE == rw) { + goto END; + } + + cmd_result &= ~(0xFF<<24); + if (cmd_result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, + &sshdr); + if (sshdr.sense_key == RECOVERED_ERROR && + sshdr.asc == 0 && sshdr.ascq == 0x1d) + cmd_result &= ~SAM_STAT_CHECK_CONDITION; + } + + pPkg->var = desc[5] | desc[7] << 8 | desc[9] << 16 | desc[11] << 24; + pPkg->decode(pPkg, READ); + } + + if (cmd_result) { + goto END; + } + + /* + * A strange situation appears on DX1211/RX1211 that the write command is sent but the device does not act. + * Delaying for several microseconds can solve such an issue, however, the actual root cause is not confirmed. + * This might be just a walkaround. + */ + if (WRITE == rw) { + msleep(50); + } + + ret = 0; +END: + + /* unlock to let others can do pmp gpio control */ + spin_lock_irqsave(ap->lock, flags); + ap->link.uiStsFlags &= ~SYNO_STATUS_GPIO_CTRL; + spin_unlock_irqrestore(ap->lock, flags); + + return ret; +} + +static void +syno_gpio_task(struct work_struct *pWork) +{ + SYNO_GPIO_TASK *pTask = container_of(pWork, SYNO_GPIO_TASK, work.work); + unsigned int (*gpio_func)(struct ata_link *, SYNO_PM_PKG *); + unsigned int ret = 0; + + if (pTask->blIsRead) { + gpio_func = syno_sata_pmp_read_gpio_core; + } else { + gpio_func = syno_sata_pmp_write_gpio_core; + } + + pTask->blRetry = pTask->blIsErr = 0; + + ret = gpio_func(&(pTask->ap->link), &(pTask->pm_pkg)); + + if (AC_ERR_OTHER == ret) { + pTask->blRetry = 1; + } + + if (0 != ret) { + pTask->blIsErr = 1; + } + + complete(&pTask->wait); +} + +static void inline +syno_gpio_task_init(SYNO_GPIO_TASK *pTask, + u8 rw, + struct ata_port *ap) +{ + memset(pTask, 0, sizeof(*pTask)); + INIT_DELAYED_WORK(&(pTask->work), syno_gpio_task); + init_completion(&(pTask->wait)); + pTask->blIsRead = (WRITE == rw)? 0 : 1; + pTask->ap = ap; +} + +static ssize_t +syno_gpio_read_with_sdev(struct ata_port *ap, char *buf, struct scsi_device *sdev) +{ + SYNO_PM_PKG pm_pkg; + ssize_t len = -EIO; + + if (syno_gpio_with_scmd(ap, sdev, &pm_pkg, READ)) { + sprintf(buf, "%s=\"\"%s", EBOX_GPIO_KEY, "\n"); + } else { + len = sprintf(buf, "%s=\"0x%x\"%s", EBOX_GPIO_KEY, pm_pkg.var, "\n"); + } + + return len; +} + + +/** + * issue ata command with scsi command, we append it at first + * pm drive. + * + * @param ap [IN] ata port. Should not be NULL + * @param sdev [IN] scsi device. Should not be NULL + * @param input [IN] the value we want to write into gpio + * + * @return 0: success + * otherwise: fail + */ +static u8 +syno_gpio_write_with_sdev(struct ata_port *ap, struct scsi_device *sdev, u32 input) +{ + SYNO_PM_PKG pm_pkg; + + pm_pkg.var = input; + return syno_gpio_with_scmd(ap, sdev, &pm_pkg, WRITE); +} + +struct ata_port* SynoEunitEnumPort(struct ata_port *pAp_master, struct klist_node *pAtaNode) +{ + struct ata_port *pAp = NULL; + struct klist_node *ata_node = NULL; + int slotNumber = -1; + struct klist_iter klist_iter; + memset(&klist_iter, 0, sizeof(klist_iter)); + + if (NULL == pAp_master) { + goto END; + } + + if (-1 == (slotNumber = syno_external_libata_index_get(pAp_master))) { + printk(KERN_DEBUG "Failed to get slotNumber for ata_port %d\n", pAp_master->print_id); + goto END; + } + + klist_iter_init_node(&syno_ata_port_head, &klist_iter, pAtaNode); + for (ata_node = klist_next(&klist_iter); NULL != ata_node; ata_node = klist_next(&klist_iter)) { + pAp = container_of(ata_node, struct ata_port, ata_port_list); + + if (syno_is_synology_pm(pAp) && slotNumber == syno_external_libata_index_get(pAp)) { + break; + } + + pAp = NULL; + } + klist_iter_exit(&klist_iter); + +END: + return pAp; + +} + +/* find eunit master */ +struct ata_port *SynoEunitFindMaster(struct ata_port *pAp) +{ + struct ata_port *pAp_master = NULL; + struct klist_iter klist_iter; + int slotNumber = -1; + struct klist_node *ata_node = NULL; + + memset(&klist_iter, 0, sizeof(klist_iter)); + + if (NULL == pAp) { + goto END; + } + + /* if this port is master, we return itself immediately */ + if (0 == pAp->PMSynoEMID) { + pAp_master = pAp; + goto END; + } + + slotNumber = syno_external_libata_index_get(pAp); + if (-1 == slotNumber) { + printk(KERN_DEBUG "Failed to get slotNumber for ata_port %d\n", pAp->print_id); + goto END; + } + + klist_iter_init(&syno_ata_port_head, &klist_iter); + for (ata_node = klist_next(&klist_iter); NULL != ata_node; ata_node = klist_next(&klist_iter)) { + pAp_master = container_of(ata_node, struct ata_port, ata_port_list); + if (0 == pAp_master->PMSynoEMID && slotNumber == syno_external_libata_index_get(pAp_master)) { + break; + } + pAp_master = NULL; + } + klist_iter_exit(&klist_iter); + +END: + return pAp_master; +} + +#ifdef MY_ABC_HERE +static void SynoEunitBindLock(struct ata_port *pAp_master, bool blset) +{ + struct klist_iter klist_iter; + struct ata_port *ap = NULL; + + memset(&klist_iter, 0, sizeof(klist_iter)); + + if (NULL == pAp_master) { + goto END; + } + + if (!syno_is_synology_pm(pAp_master)) { + goto END; + } + + while (NULL != (ap = SynoEunitEnumPort(pAp_master, ap? &ap->ata_port_list: NULL))) { + /* This special lock is used to power on eunit in deep sleep state. */ + if (!ap->scsi_host->eunit_lock_configured) { + ap->scsi_host->peunit_poweron_lock = &(pAp_master->scsi_host->eunit_poweron_lock); + ap->scsi_host->puiata_eh_flag = &(pAp_master->scsi_host->uiata_eh_flag); + ap->scsi_host->eunit_lock_configured = 1; + } + if (blset) { + ap->scsi_host->is_eunit_deepsleep = 1; + } + } + +END: + return ; +} + +/* check if any port in this EUnit still have errors or activeties + * + * @param host [IN] EUnit master port + * + * @return 0: not have errors or activeties + * 1: have errors or activeties + * -1: failed + */ +static int SynoIsEunitPortActing(const struct ata_port *pAp_master) +{ + int iRet = -1; + unsigned long flags = 0; + struct klist_iter klist_iter; + struct klist_node *ata_node = NULL; + struct ata_port *ap = NULL; + int slotNumber = -1; + + memset(&klist_iter, 0, sizeof(klist_iter)); + + if (NULL == pAp_master) { + goto END; + } + + if (!syno_is_synology_pm(pAp_master)) { + goto END; + } + + slotNumber = syno_external_libata_index_get(pAp_master); + if (-1 == slotNumber) { + printk(KERN_DEBUG "Failed to get slotNumber for ata_port %d\n", pAp_master->print_id); + goto END; + } + + klist_iter_init(&syno_ata_port_head, &klist_iter); + for (ata_node = klist_next(&klist_iter); NULL != ata_node; ata_node = klist_next(&klist_iter)) { + ap = container_of(ata_node, struct ata_port, ata_port_list); + if (slotNumber != syno_external_libata_index_get(ap)) { + goto CONTINUE_FOR; + } + + spin_lock_irqsave(ap->lock, flags); + /* still have activities */ + if (ap->nr_active_links) { + DBGMESG("%s EUnit %d have activities\n", + (ap->PMSynoEMID == 0 ? "Master" : "Slave"), + ap->print_id); + iRet = 1; + } + /* have errors */ + if (ap->pflags & (~ATA_PFLAG_EXTERNAL)) { + DBGMESG("%s EUnit %d have errors pflags 0x%x\n", + (ap->PMSynoEMID == 0 ? "Master" : "Slave"), + ap->print_id, + ap->pflags); + iRet = 1; + } + spin_unlock_irqrestore(ap->lock, flags); + + if (1 == iRet) { + goto END; + } + +CONTINUE_FOR: + ap = NULL; + } + klist_iter_exit(&klist_iter); + +END: + return iRet; +} +#endif /* MY_ABC_HERE */ + +/* + * blWithLink is false: No matter any disk on ap, just raise/pull flag + * blWithLink is true: If any disk(link) on ata port, then raise/pull the flag + */ +void SynoEunitFlagSet(struct ata_port *pAp_master, bool blset, unsigned int flag, bool blWithLink) +{ + struct klist_iter klist_iter; + struct klist_node *ata_node = NULL; + struct ata_port *ap = NULL; + struct ata_link *link = NULL; + unsigned long flags_ap; + bool blAnyLink = false; + int slotNumber = -1; + + memset(&klist_iter, 0, sizeof(klist_iter)); + + if (NULL == pAp_master) { + goto END; + } + + if (!syno_is_synology_pm(pAp_master)) { + goto END; + } + + slotNumber = syno_external_libata_index_get(pAp_master); + if (-1 == slotNumber) { + printk(KERN_DEBUG "Failed to get slotNumber for ata_port %d\n", pAp_master->print_id); + goto END; + } + + klist_iter_init(&syno_ata_port_head, &klist_iter); + for (ata_node = klist_next(&klist_iter); NULL != ata_node; ata_node = klist_next(&klist_iter)) { + ap = container_of(ata_node, struct ata_port, ata_port_list); + if (slotNumber != syno_external_libata_index_get(ap)) { + goto CONTINUE_FOR; + } + + if (blWithLink) { + /* Check any link on ap */ + ata_for_each_link(link, ap, EDGE) { + if (0 != link->sata_spd) { + blAnyLink = true; + break; + } + } + /* If no link on ap, do not raise/pull flag. */ + if (!blAnyLink) { + goto CONTINUE_FOR; + } + } + + spin_lock_irqsave(ap->lock, flags_ap); + if (blset) { + ap->pflags |= flag; + } else { + ap->pflags &= ~flag; + } + spin_unlock_irqrestore(ap->lock, flags_ap); + +CONTINUE_FOR: + ap = NULL; + } + klist_iter_exit(&klist_iter); + +END: + return ; +} + +int syno_eunit_poweroff(struct ata_port *ap) +{ + struct ata_port *pAp_master = NULL; + int iRet = -1; + + if (SYSTEM_POWER_OFF != system_state) { + iRet = 0; + goto END; + } + + /* Only handle EUnit */ + if(!ap->nr_pmp_links) { + DBGMESG("port %d is internal disk skip it\n", ap->print_id); + iRet = 0; + goto END; + } + + /* this host already irqoff by other hosts, we needn't poweroff it again */ + if (iIsSynoIRQOff(ap)) { + DBGMESG("port %d already irqoff, skip this poweroff control\n", ap->print_id); + iRet = 0; + goto END; + } + + /* Because SynoEunitFlagSet, syno_libata_pm_power_ctl need find master too, + * so we use master here, that can save more time */ + pAp_master = SynoEunitFindMaster(ap); + if (NULL == pAp_master) { + printk("Can't find syno Eunit master to do power control\n"); + goto END; + } + + DBGMESG("disk %d do poweroff task\n", ap->print_id); + + /* set ATA_PFLAG_SYNO_IRQ_OFF and ATA_PFLAG_SYNO_DS_PWROFF flag */ + SynoEunitFlagSet(pAp_master, 1, ATA_PFLAG_SYNO_IRQ_OFF, 0); + SynoEunitFlagSet(pAp_master, 1, ATA_PFLAG_SYNO_DS_PWROFF, 0); + + /* poweroff */ + if (0 != syno_libata_pm_power_ctl(pAp_master, 0, 0)) { + /* Not support PM port or GPIO cmd timeout (ex. DX510), it will go to this case. + * So this may not be an error, just by HW design */ + DBGMESG("disk %d poweroff task fail, it may still power on after DS poweroff\n", ap->print_id); + } + + /* set ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE flag */ + SynoEunitFlagSet(pAp_master, 1, ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE, 0); + iRet = 0; + +END: + return iRet; +} +EXPORT_SYMBOL(syno_eunit_poweroff); + +/* + * + * change interface from syno_pm_gpio_show(struct device *dev, char *buf) + * to syno_pm_gpio_show(struct device *dev, struct device_attribute *attr, char *buf) + * to fit the DEVICE_ATTR macro defined in 2.6.32 +*/ +static ssize_t +syno_pm_gpio_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct scsi_device *sdev = NULL; + struct ata_device *pAtaDev = (struct ata_device *)ap->link.device; + ssize_t len = -EIO; + + if (ap->nr_pmp_links && + syno_is_synology_pm(ap)) { + if (defer_gpio_cmd(ap, 0, READ)) { + sprintf(buf, "%s%s%s", EBOX_GPIO_KEY, "=\"\"", "\n"); + return len; + } else if (NULL != (sdev = pAtaDev->sdev)) { + return syno_gpio_read_with_sdev(ap, buf, sdev); + } else { + printk("can't find pm scsi device for gpio show\n"); + } + } else { + len = sprintf(buf, "%s%s%s", EBOX_GPIO_KEY, "=\"\"", "\n"); + } + + return len; +} + +static ssize_t +syno_pm_gpio_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ata_device *pAtaDev = (struct ata_device *)ap->link.device; + struct scsi_device *sdev = NULL; + /* please man 2 write */ + ssize_t ret = -EIO; + u32 input; + + sscanf(buf, "%x", &input); + + if (ap->nr_pmp_links && + syno_is_synology_pm(ap) && + !defer_gpio_cmd(ap, input, WRITE)) { + u8 result = 0; + + if (NULL != (sdev = pAtaDev->sdev)) { + result = syno_gpio_write_with_sdev(ap, sdev, input); + } else { + printk("can't find pm scsi device for store\n"); + } + + ret = !result ? count : -EIO; + } + return ret; +} +DEVICE_ATTR(syno_pm_gpio, S_IRUGO | S_IWUSR, syno_pm_gpio_show, syno_pm_gpio_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_pm_gpio); + +/* + * show if power disabled while new expansion unit plugged in + */ +static ssize_t +syno_pm_gpio_power_disable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t len = -EIO; + + len = sprintf(buf, "%d\n", ap->PMSynoPowerDisable); + + return len; +} + +/* + * store power disable flag while new expansion unit plugged in + */ +static ssize_t +syno_pm_gpio_power_disable_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + //please man 2 write + ssize_t ret = -EIO; + u32 input; + + sscanf(buf, "%d", &input); + + if (1 == input) { + ap->PMSynoPowerDisable = 1; + } else { + ap->PMSynoPowerDisable = 0; + } + + return ret; +} +DEVICE_ATTR(syno_manutil_power_disable, S_IRUGO | S_IWUSR, syno_pm_gpio_power_disable_show, syno_pm_gpio_power_disable_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_manutil_power_disable); + +static ssize_t +syno_pm_info_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t len = 0; + int index = 0; + int NumOfPMPorts = 0; + char szPciePath[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (ap->nr_pmp_links && + (syno_is_synology_pm(ap) || + syno_pm_with_synology_magic(ap))) { + char szTmp[BDEVNAME_SIZE]; + char *szTmp1 = NULL; + struct scsi_device *sdev = NULL; + + szTmp1 = (char*) kcalloc(PAGE_SIZE, sizeof(char), GFP_KERNEL); + if (NULL == szTmp1) { + printk(KERN_WARNING "%s kmalloc failed\n", __FUNCTION__); + len = 0; + goto END; + } + + NumOfPMPorts = syno_support_disk_num(sata_pmp_gscr_vendor(ap->link.device->gscr), + sata_pmp_gscr_devid(ap->link.device->gscr), + ap->PMSynoUnique); + + memset(szTmp, 0, sizeof(szTmp)); + + /* syno_device_list */ + shost_for_each_device(sdev, shost) { + + /* Skip virtual pmp device */ + if (SYNO_PM_VIRTUAL_SCSI_CHANNEL == sdev->channel) { + continue; + } + + if (0 == index) { + snprintf(szTmp, BDEVNAME_SIZE, "/dev/%s", sdev->syno_disk_name); + } else { + snprintf(szTmp, BDEVNAME_SIZE, ",/dev/%s", sdev->syno_disk_name); + } + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + index++; + } + snprintf(buf, PAGE_SIZE, "%s%s%s%s", EBOX_INFO_DEV_LIST_KEY, "=\"", szTmp1, "\"\n"); + + /* vendor id and device id */ + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=%s0x%x%s", EBOX_INFO_VENDOR_KEY, "\"", + sata_pmp_gscr_vendor(ap->link.device->gscr), + "\"\n"); + snprintf(szTmp1, PAGE_SIZE, "%s", szTmp); + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=%s%x%s", EBOX_INFO_DEVICE_KEY, "\"", + sata_pmp_gscr_devid(ap->link.device->gscr), + "\"\n"); + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + + /* error handle processing */ + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=%s%s%s", EBOX_INFO_ERROR_HANDLE, "\"", + (ap->pflags & (~ATA_PFLAG_EXTERNAL)) ? "yes" : "no", + "\"\n"); + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=%sv%d%s", EBOX_INFO_CPLDVER_KEY, "\"", + ap->PMSynoCpldVer, + "\"\n"); + + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + +#ifdef MY_ABC_HERE + /* deepsleep support */ + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=%s%s%s", EBOX_INFO_DEEP_SLEEP, "\"", + iIsSynoDeepSleepSupport(ap) ? "yes" : "no", + "\"\n"); + strncat(szTmp1, szTmp, BDEVNAME_SIZE); +#endif /* MY_ABC_HERE */ + + /* irq off state */ + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=%s%s%s", EBOX_INFO_IRQ_OFF, "\"", + iIsSynoIRQOff(ap) ? "yes" : "no", + "\"\n"); + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + + /* unique model name and EMID*/ + if (IS_SYNOLOGY_RX413(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX413, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if (IS_SYNOLOGY_RX1214(ap->PMSynoUnique)) { + if (ap->PMSynoIsRP) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX1214RP, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX1214, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } + } else if(IS_SYNOLOGY_RX1217(ap->PMSynoUnique)) { + if(ap->PMSynoIsRP) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX1217RP, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX1217, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } + } else if(IS_SYNOLOGY_RX415(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX415, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if (IS_SYNOLOGY_DX1215(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_DX1215, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if(IS_SYNOLOGY_DX517(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_DX517, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if (IS_SYNOLOGY_RX418(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX418, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if (IS_SYNOLOGY_DX1222(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_DX1222, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if (IS_SYNOLOGY_DX1215II(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_DX1215II, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else if (IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique)) { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n%s=\"%d\"\n", + EBOX_INFO_UNIQUE_KEY, + EBOX_INFO_UNIQUE_RX1223RP, + EBOX_INFO_EMID_KEY, + ap->PMSynoEMID); + } else { + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"Unknown\"\n%s=\"%d\"\n", EBOX_INFO_UNIQUE_KEY, EBOX_INFO_EMID_KEY, ap->PMSynoEMID); + } + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + + /* Host Unique ID */ + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%lx\"\n", + EBOX_INFO_SATAHOST_KEY, + (unsigned long)ap->host); + + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + + /* ATA Port Number */ + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%u\"\n", + EBOX_INFO_PORTNO_KEY, + ap->port_no); + + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + + /* Pcie Path */ + if (ap->dev->bus && !strcmp("pci", ap->dev->bus->name)) { + syno_pciepath_dts_pattern_get(to_pci_dev(ap->dev), szPciePath, sizeof(szPciePath)); + snprintf(szTmp, + BDEVNAME_SIZE, + "%s=\"%s\"\n", + EBOX_INFO_PCIEPATH_KEY, + szPciePath); + strncat(szTmp1, szTmp, BDEVNAME_SIZE); + } + + /* put it together */ + len = snprintf(buf, PAGE_SIZE, "%s%s", buf, szTmp1); + kfree(szTmp1); + } else { + len = snprintf(buf, PAGE_SIZE, "%s%s%s", EBOX_INFO_DEV_LIST_KEY, "=\"\"", "\n"); + } + +END: + return len; +} + +DEVICE_ATTR(syno_pm_info, S_IRUGO, syno_pm_info_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_pm_info); + +typedef struct { + unsigned char fanTach[4][2]; +} SYNO_JMB575_POLL_DATA; + +static ssize_t +syno_pm_i2c_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + int written = 0, i = 0; + int fanIdx = 0; + + if (SYNO_PM_I2C_SYSFS_I2C_READ == ap->i2cOp && !ap->i2cPkg.blIsErr) { + written += sprintf(buf, "%s=\"", EBOX_I2C_KEY); + + for(i = 0; i < ap->i2cPkg.len; i++) { + written += snprintf(buf+written, 20, "0x%02x%s", + ap->i2cPkg.resultData[i], + ((ap->i2cPkg.len -1) == i) ? "\"\n" : " "); + } + } else if (SYNO_PM_I2C_SYSFS_POLLING == ap->i2cOp) { + if (NULL != ap->link.device->sdev && 0 == syno_pm_jmb575_poll(ap, ap->link.device->sdev, ap->sector_buf, 1)) { + written += snprintf(buf+written, 25, "[%s]\n", EBOX_I2C_KEY); + for (fanIdx = 0; fanIdx < ARRAY_SIZE(((SYNO_JMB575_POLL_DATA*)(ap->sector_buf))->fanTach); fanIdx++) { + + written += snprintf(buf+written, 25, "%s%d=\"0x%02x 0x%02x\"\n", + EBOX_I2C_POLLING_FAN, + fanIdx + 1, + ((SYNO_JMB575_POLL_DATA*)(ap->sector_buf))->fanTach[fanIdx][0], + ((SYNO_JMB575_POLL_DATA*)(ap->sector_buf))->fanTach[fanIdx][1]); + } + + } + } + return written; +} + +static ssize_t +syno_pm_i2c_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t ret = -EIO; + + int i = 0; + int offset = 0; + int total_offset = 0; + + int ledIdx = 0; + int setLedMask = 0; + struct scsi_device *sdev = NULL; + + if (defer_gpio_cmd(ap, 0, READ) || NULL == (sdev = ap->link.device->sdev)) { + ap->i2cPkg.blIsErr = true; + DBGMESG("ata%d: skip ebox i2c control\n", ap->print_id); + goto END; + } + + if (0 == strncmp(buf, EBOX_I2C_SYSFS_OP_WRITE, strlen(EBOX_I2C_SYSFS_OP_WRITE))) { + total_offset = strlen(EBOX_I2C_SYSFS_OP_WRITE); + ap->i2cOp = SYNO_PM_I2C_SYSFS_I2C_WRITE; + + if (3 > sscanf(buf + total_offset, "%hx %hx %hu%n", &ap->i2cPkg.addr, &ap->i2cPkg.offset, &ap->i2cPkg.len, &offset)) { + printk("I2C store parameter error\n"); + goto END; + } + + total_offset += offset; + ap->i2cPkg.len = ap->i2cPkg.len <= SYNO_PMP_I2C_MAX_DATA_LEN? ap->i2cPkg.len : SYNO_PMP_I2C_MAX_DATA_LEN; + + for (i = 0; i < ap->i2cPkg.len; i++) { + if(0 >= sscanf(buf + total_offset, "%4hhx%n", &ap->i2cPkg.inputData[i], &offset)) { + printk("I2C store parameter error\n"); + goto END; + } + total_offset += offset; + } + + syno_i2c_with_scmd(ap, sdev, &ap->i2cPkg, WRITE); + } else if (0 == strncmp(buf, EBOX_I2C_SYSFS_OP_READ, strlen(EBOX_I2C_SYSFS_OP_READ))) { + total_offset = strlen(EBOX_I2C_SYSFS_OP_READ); + ap->i2cOp = SYNO_PM_I2C_SYSFS_I2C_READ; + + if (3 > sscanf(buf + total_offset, "%hx %hx %hu%n", &ap->i2cPkg.addr, &ap->i2cPkg.offset, &ap->i2cPkg.len, &offset)) { + printk("I2C store parameter error\n"); + goto END; + } + + total_offset += offset; + ap->i2cPkg.len = ap->i2cPkg.len <= SYNO_PMP_I2C_MAX_DATA_LEN? ap->i2cPkg.len : SYNO_PMP_I2C_MAX_DATA_LEN; + + ap->i2cPkg.blIsErr = false; + syno_i2c_with_scmd(ap, sdev, &ap->i2cPkg, READ); + + } else if (0 == strncmp(buf, EBOX_I2C_SYSFS_OP_JMB575_LED_CTL, strlen(EBOX_I2C_SYSFS_OP_JMB575_LED_CTL))) { + total_offset = strlen(EBOX_I2C_SYSFS_OP_JMB575_LED_CTL); + + if (2 > sscanf(buf + total_offset, "%d %d", &ledIdx, &setLedMask)) { + ret = count; + goto END; + } + + if (syno_sata_jmb575_disk_led_set_with_scmnd(&ap->link, ledIdx, setLedMask)) { + printk("JMB575 Led Ctrl Fail\n"); + } + } else if (0 == strncmp(buf, EBOX_I2C_SYSFS_OP_POLL, strlen(EBOX_I2C_SYSFS_OP_POLL))) { + ap->i2cOp = SYNO_PM_I2C_SYSFS_POLLING; + } + + ret = count; +END: + + return ret; +} +DEVICE_ATTR(syno_pm_i2c, S_IRUGO | S_IWUSR, syno_pm_i2c_show, syno_pm_i2c_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_pm_i2c); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +/** + * Query this ap deep sleep capacity + * + * @param ap [IN] ata port + * + * @return 0: not support + * 1: support + */ +int iIsSynoDeepSleepSupport(struct ata_port *ap) +{ + int iRet = 0; + + if (NULL == ap) { + DBGMESG("ap is NULL, can't check deep sleep support\n"); + goto END; + } + + if (-1 != ap->syno_internal_slot_index) { + /* Internal case */ + if (PWRCTRL_TYPE_GPIO != SYNO_GET_DISK_PWR_TYPE(ap->syno_internal_slot_index+1)) { + goto END; + } + } + + /* this ap can't support power control, so it must can't support deep sleep */ + iRet = iIsSynoPmCtlSupport(ap); + +END: + return iRet; +} + +/* this function will set the ata power + * TODO: You can't do spin_lock(ap) before you call this function + * @param host [IN] the scsi host + * blPowerOn 1: set poweron 0: set poweroff + * + * @return 0: success + * -1: failed + */ +static int syno_libata_port_power_ctl(struct ata_port *ap, u8 pwrOp) +{ + unsigned long flags = 0; + int iIsDSPowerOff = 0; + int iRet = -1; + + u8 blPowerOn = 0; + if(NULL == ap) { + goto END; + } + + if(0 == iIsSynoPmCtlSupport(ap)) { + DBGMESG("disk %d doesn't support pm control\n", ap->print_id); + goto END; + } + + blPowerOn = (pwrOp & (SYNO_PWR_OP_POWER_ON | SYNO_PWR_OP_WAKE))? 1 : 0; + + // Check if still have command + spin_lock_irqsave(ap->lock, flags); + iIsDSPowerOff = ap->pflags & ATA_PFLAG_SYNO_DS_PWROFF; + spin_unlock_irqrestore(ap->lock, flags); + if(!blPowerOn && ap->nr_active_links && !iIsDSPowerOff) { + printk("WARNING: disk %d still have command, poweroff it may cause data inconsistency\n", + ap->print_id); + WARN_ON(1); + } + DBGMESG("disk %d do pm control pwrOp %d\n", ap->print_id, pwrOp); + +#if defined(MY_ABC_HERE) + if(-1 != ap->syno_internal_slot_index && SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(ap->syno_internal_slot_index + 1)) { + /* Internal disks case: only support deep sleep ap, we can do pm control */ + SYNO_CTRL_HDD_POWERON(ap->syno_internal_slot_index + 1, blPowerOn); + + if(blPowerOn) { + mdelay(3000); + } + + iRet = 0; + goto END; + } +#endif /* MY_ABC_HERE && MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_is_synology_pm(ap)) { + /* this port is a master , we no need to get master */ + struct ata_port *pAp_master = NULL; + + pAp_master = SynoEunitFindMaster(ap); + if (NULL == pAp_master) { + printk("Can't find syno Eunit master to do power control\n"); + } + + if (0 != syno_libata_pm_power_ctl(pAp_master, pwrOp, 0)) { + goto END; + } + + iRet = 0; + goto END; + } +#endif /* MY_ABC_HERE */ + + iRet = 0; +END: + return iRet; +} + +/** + * set/clear ata port pflags + * + * @parami ap [IN/OUT]: the ata port + * ulFlag [IN]: the pflag which need to be set/clear + * blSet [IN]: set or clear + * + * @retrun + * 0: success others: fail + */ +int SynoFlagSet(struct ata_port *ap, const unsigned int ulFlag, const u8 blSet) +{ + int iRet = -1; + unsigned long flags; +#ifdef MY_ABC_HERE + struct ata_port *pAp_slave = NULL; + struct ata_port *pAp_master = NULL; + int iIsActing = 0; +#endif /* MY_ABC_HERE */ + + if (NULL == ap) { + goto END; + } + + /* Internal port flag set */ + if (!ap->nr_pmp_links) { + spin_lock_irqsave(ap->lock, flags); + if(blSet) { + ap->pflags |= ulFlag; + } else { + ap->pflags &= ~(ulFlag); + } + spin_unlock_irqrestore(ap->lock, flags); + } +#ifdef MY_ABC_HERE + else { /* Eunit flag set */ + if(0 == ap->PMSynoEMID) { + pAp_master = ap; + } else { + pAp_master = SynoEunitFindMaster(ap); + if (NULL == pAp_master) { + printk("Can't find syno Eunit master to set flag\n"); + goto END; + } + } + /* set master flag */ + spin_lock_irqsave(pAp_master->lock, flags); + if(ATA_PFLAG_SYNO_IRQ_OFF == ulFlag && blSet && pAp_master->nr_active_links) { + DBGMESG("WARNING:Master disk %d still have command\n", + pAp_master->print_id); + iIsActing = 1; + } + if(blSet) { + pAp_master->pflags |= ulFlag; + } else { + pAp_master->pflags &= ~(ulFlag); + } + spin_unlock_irqrestore(pAp_master->lock, flags); + + /* find slave disks */ + while (NULL != (pAp_slave = SynoEunitEnumPort(pAp_master, pAp_slave? &pAp_slave->ata_port_list: NULL))) { + spin_lock_irqsave(pAp_slave->lock, flags); + if(ATA_PFLAG_SYNO_IRQ_OFF == ulFlag && blSet && pAp_slave->nr_active_links) { + DBGMESG("Slave disk %d still have command\n", + pAp_slave->print_id); + iIsActing = 1; + } + if(blSet) { + pAp_slave->pflags |= ulFlag; + DBGMESG("Set pflags 0x%x for ata_port %d\n", ulFlag, pAp_slave->print_id); + } else { + pAp_slave->pflags &= ~(ulFlag); + DBGMESG("Unset pflags 0x%x for ata_port %d\n", ulFlag, pAp_slave->print_id); + } + spin_unlock_irqrestore(pAp_slave->lock, flags); + } + if (iIsActing) { + goto END; + } + } +#endif /* MY_ABC_HERE */ + + iRet = 0; + +END: + return iRet; +} + +static struct scsi_device * +look_up_scsi_dev_from_ap(struct ata_port *ap) +{ + struct scsi_device *sdev = NULL; + struct ata_link *link = NULL; + struct ata_device *dev = NULL; + + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, link, ALL) { + if (dev->sdev && SDEV_RUNNING == dev->sdev->sdev_state) { + sdev = dev->sdev; + return sdev; + } + } + } + return NULL; +} + +/** + * NOTE: shouldn't call spin_lock(ap) before you call this function + * deep sleep control + * + * @param host [IN] scsi host + * @param blSet [IN] 0: unset this host deep sleep + * set this host to deep sleep + * + * @return 0: success + * others: fail + */ +int +syno_libata_set_deep_sleep(struct ata_port *ap, const u8 blSet) +{ + struct ata_port *pAp_master = NULL; + int iRet = -1; + unsigned long flags; + u8 blPowerOn = !blSet; + + if (NULL == look_up_scsi_dev_from_ap(ap)&& blSet) { + /* Only skip when entering deep sleep, chips may trigger error with no disks in deepsleep, need to wakeup. */ + DBGMESG("port %d have no disks, ignore it\n", ap->print_id); + iRet = 0; + goto END; + } + if(0 == iIsSynoDeepSleepSupport(ap)) { + DBGMESG("disk %d doesn't support deep sleep\n", ap->print_id); + iRet = 0; + goto END; + } + if (blSet && 1 == iIsSynoIRQOff(ap)) { + DBGMESG("disk %d already irqoff, skip this irq off control\n", ap->print_id); + iRet = 0; + goto END; + } + + /* set/unset ATA_PFLAG_SYNO_IRQ_OFF */ + if (blSet) { + if(ap->nr_active_links) { + DBGMESG("disk %d still have command, can't set deep sleep\n",ap->print_id); + goto END; + } + } + + pAp_master = ap; + +#ifdef MY_ABC_HERE + if(ap->nr_pmp_links) { + pAp_master = SynoEunitFindMaster(ap); + if (NULL == pAp_master) { + printk("Can't find syno Eunit master to do power control\n"); + goto END; + } + if (blSet && 1 == SynoIsEunitPortActing(pAp_master)) { + DBGMESG("EUnit %d is still acting, can't set deepsleep\n", pAp_master->print_id); + goto END; + } + } +#endif /* MY_ABC_HERE */ + + /* check if master locked, if locked we must wait here */ + spin_lock_irqsave(pAp_master->lock, flags); + if (pAp_master->iIsDeepCtlLock) { + DBGMESG("disk %d master %d deep locked, wait here\n", ap->print_id, pAp_master->print_id); + while(pAp_master->iIsDeepCtlLock) { + spin_unlock_irqrestore(pAp_master->lock, flags); + schedule_timeout_uninterruptible(HZ); + spin_lock_irqsave(pAp_master->lock, flags); + } + } + pAp_master->iIsDeepCtlLock = 1; + spin_unlock_irqrestore(pAp_master->lock, flags); + + DBGMESG("disk %d do deep sleep control blSet %d\n", ap->print_id, blSet); + /* set/unset ATA_PFLAG_SYNO_IRQ_OFF flag */ + if (SynoFlagSet(pAp_master, ATA_PFLAG_SYNO_IRQ_OFF, blSet)) { + printk("Enit %d set ATA_PFLAG_SYNO_IRQ_OFF fail, reset now\n", pAp_master->print_id); + spin_lock_irqsave(ap->lock, flags); + ata_port_schedule_eh(ap); + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } + +#ifdef MY_ABC_HERE + if (!blSet) { + struct ata_link *link; + struct ata_device *dev; + ata_for_each_link(link, pAp_master, EDGE) { + ata_for_each_dev(dev, link, ALL) { + if (dev->flags & ATA_DFLAG_NO_WCACHE) { + DBGMESG("port %d set wcache disable action\n", pAp_master->print_id); + dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_WCACHE_DISABLE; + } + } + } + } +#endif /* MY_ABC_HERE */ + + /* set pwr */ + if (0 != syno_libata_port_power_ctl(pAp_master, blPowerOn? SYNO_PWR_OP_WAKE : SYNO_PWR_OP_DEEPSLEEP)) { + printk("ata port %d set deep sleep pwr fail blPowerOn %d\n", ap->print_id, blPowerOn); + goto END; + } + + /* if pm control success, set/unset ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE flag */ + if (SynoFlagSet(pAp_master, ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE, blSet)) { + printk("Enit %d set ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE fail, reset now\n", pAp_master->print_id); + spin_lock_irqsave(ap->lock, flags); + ata_port_schedule_eh(ap); + spin_unlock_irqrestore(ap->lock, flags); + goto END; + } + +#ifdef MY_ABC_HERE + /* Bind deepsleep lock and flags to master host on same eunit, for future wake up use. */ + if (ap->nr_pmp_links) { + SynoEunitBindLock(pAp_master, blSet); + } +#endif /* MY_ABC_HERE */ + + iRet = 0; + +END: + if (pAp_master) { + spin_lock_irqsave(pAp_master->lock, flags); + if (pAp_master->iIsDeepCtlLock) { + pAp_master->iIsDeepCtlLock = 0; + } + spin_unlock_irqrestore(pAp_master->lock, flags); + } + /* Set SYNO_STATUS_DEEP_SLEEP_FAILED pAp_master flag to prevent waking flag is set inproperly when wake up next time. */ + if (NULL != pAp_master && 0 != iRet && blSet) { + spin_lock_irqsave(pAp_master->lock, flags); + pAp_master->uiStsFlags |= SYNO_STATUS_DEEP_SLEEP_FAILED; + spin_unlock_irqrestore(pAp_master->lock, flags); + } + + return iRet; +} + +static ssize_t +syno_power_ctrl_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t ret = -EIO; + int iPwrOn = 0; + + sscanf(buf, "%d", &iPwrOn); + syno_libata_port_power_ctl(ap, iPwrOn); + + ret = count; + + return ret; +} +DEVICE_ATTR(syno_power_ctrl, S_IWUSR, NULL, syno_power_ctrl_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_power_ctrl); + +static ssize_t +syno_deep_sleep_ctrl_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ata_port *ap = ata_shost_to_port(sdev->host); + ssize_t ret = -EIO; + int iBlSet = 0; + + if(0 == iIsSynoDeepSleepSupport(ap)) { + goto END; + } + + sscanf(buf, "%d", &iBlSet); + if(syno_libata_set_deep_sleep(ap, iBlSet)) { + goto END; + } + + ret = count; + +END: + return ret; +} +DEVICE_ATTR(syno_deep_sleep_ctrl, S_IWUSR, NULL, syno_deep_sleep_ctrl_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_deep_sleep_ctrl); + +/* query this device support deep sleep or not */ +static ssize_t +syno_deep_sleep_support_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + /* copy from ata_scsi_park_show to get ata_device */ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = NULL; + ssize_t len = 0; + int iSupport = 0; + + ap = ata_shost_to_port(sdev->host); + iSupport = iIsSynoDeepSleepSupport(ap); + /* +2, '0' and '\n' */ + len = snprintf(buf, 1 + 2, "%d%s", iSupport, "\n"); + + return len; +} +DEVICE_ATTR(syno_deep_sleep_support, S_IRUGO, syno_deep_sleep_support_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_deep_sleep_support); + +/* query this scsi host support pm control or not */ +static ssize_t +syno_pm_control_support_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t len = 0; + int iSupport = 0; + + iSupport = iIsSynoPmCtlSupport(ap); + /* +2, '0' and '\n' */ + len = snprintf(buf, 1 + 2, "%d%s", iSupport, "\n"); + + return len; +} +DEVICE_ATTR(syno_pm_control_support, S_IRUGO, syno_pm_control_support_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_pm_control_support); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +static ssize_t +syno_seq_stat_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + struct ata_link *link; + ssize_t len = 0; + char szTmp[512] = {'\0'}; + int i = 0; + + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) { + goto END; + } + link = dev->link; + + // Disk uuid + snprintf(szTmp, sizeof(szTmp), "%pU\n", + link->latency_stat.uuid); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + // total IO cmd count. + for (i = 0; i < SYNO_SEQ_SAMPLE_LBA_ZONE; i++) { + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu\n", + link->seq_stat.u64TotalSampleBytes[i], + link->seq_stat.u64TotalSampleTime[i], + link->seq_stat.u64TotalSampleSkipBytes[i]); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + } +END: + return len; +} +DEVICE_ATTR(syno_disk_seq_stat, S_IRUGO, syno_seq_stat_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_disk_seq_stat); +#endif /* MY_ABC_HERE */ + +static void disk_latency_hist_get(u64 u64TimeBuckets[SYNO_LATENCY_BUCKETS_END][32], + char *szBuf, int cbBuf) +{ + ssize_t len = 0; + unsigned int j = 0; + unsigned int i = 0; + char szTmp[32] = {'\0'}; + for (j = 0; j < SYNO_LATENCY_BUCKETS_END; j++) { + for (i = 0; i < 32; i++) { + snprintf(szTmp, sizeof(szTmp), "%llu ", u64TimeBuckets[j][i]); + len += strlen(szTmp); + strncat(szBuf, szTmp, cbBuf - len - 1); + } + szBuf[len - 1] = '\n'; + } + return; +} + +static ssize_t +syno_latency_read_hist_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + struct ata_link *link; + ssize_t len = 0; + + // We not lock it to sacrifice some accuracy but decrease overhead. + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) { + goto END; + } + link = dev->link; + + disk_latency_hist_get(link->ata_latency.u64TimeBuckets[1], buf, PAGE_SIZE); + len = strlen(buf); + disk_latency_hist_get(link->ata_latency.u64RespTimeBuckets[1], buf + len, PAGE_SIZE - len - 1); + len = strlen(buf); + +END: + return len; +} +DEVICE_ATTR(syno_disk_latency_read_hist, S_IRUGO, syno_latency_read_hist_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_disk_latency_read_hist); + +static ssize_t +syno_latency_write_hist_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + struct ata_link *link; + ssize_t len = 0; + + // We not lock it to sacrifice some accuracy but decrease overhead. + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) { + goto END; + } + link = dev->link; + + disk_latency_hist_get(link->ata_latency.u64TimeBuckets[2], buf, PAGE_SIZE); + len = strlen(buf); + disk_latency_hist_get(link->ata_latency.u64RespTimeBuckets[2], buf + len, PAGE_SIZE - len - 1); + len = strlen(buf); + +END: + return len; +} +DEVICE_ATTR(syno_disk_latency_write_hist, S_IRUGO, syno_latency_write_hist_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_disk_latency_write_hist); + +static ssize_t +syno_latency_other_hist_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + struct ata_link *link; + ssize_t len = 0; + + // We not lock it to sacrifice some accuracy but decrease overhead. + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) { + goto END; + } + link = dev->link; + + disk_latency_hist_get(link->ata_latency.u64TimeBuckets[0], buf, PAGE_SIZE); + len = strlen(buf); + disk_latency_hist_get(link->ata_latency.u64RespTimeBuckets[0], buf + len, PAGE_SIZE - len - 1); + len = strlen(buf); + +END: + return len; +} +DEVICE_ATTR(syno_disk_latency_other_hist, S_IRUGO, syno_latency_other_hist_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_disk_latency_other_hist); + +static ssize_t +syno_latency_stat_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + struct ata_link *link; + ssize_t len = 0; + unsigned long ulFlags = 0; + char szTmp[512] = {'\0'}; + u64 u64CurrentTime = 0; + + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) { + goto END; + } + link = dev->link; + + // Disk uuid + snprintf(szTmp, sizeof(szTmp), "%pU\n", + link->latency_stat.uuid); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + // total IO cmd count. + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu\n", + link->latency_stat.u64TotalCount[0], + link->latency_stat.u64TotalCount[1], + link->latency_stat.u64TotalCount[2]); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + + // total IO cmd process time. + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu\n", + link->latency_stat.u64TotalTime[0], + link->latency_stat.u64TotalTime[1], + link->latency_stat.u64TotalTime[2]); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + + // total IO cmd reponse time. + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu\n", + link->latency_stat.u64TotalRespTime[0], + link->latency_stat.u64TotalRespTime[1], + link->latency_stat.u64TotalRespTime[2]); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + + // total IO bytes. + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu\n", + link->latency_stat.u64TotalBytes[0], + link->latency_stat.u64TotalBytes[1], + link->latency_stat.u64TotalBytes[2]); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + + spin_lock_irqsave(ap->lock, ulFlags); + u64CurrentTime = cpu_clock(0); + // Batch status. + snprintf(szTmp, sizeof(szTmp), "%llu %llu %llu %llu %llu\n", + link->latency_stat.u64TotalBatchCount, + link->latency_stat.u64TotalBatchTime, + link->ata_latency.u64BatchIssue, + link->ata_latency.u64BatchComplete, + u64CurrentTime); + spin_unlock_irqrestore(ap->lock, ulFlags); + len += strlen(szTmp); + strncat(buf, szTmp, PAGE_SIZE - len - 1); + +END: + return len; +} +DEVICE_ATTR(syno_disk_latency_stat, S_IRUGO, syno_latency_stat_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_syno_disk_latency_stat); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +syno_port_thaw_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t ret = -EIO; + int iThaw = 1; + + if(!ap) { + goto END; + } + + sscanf(buf, "%d", &iThaw); + if (iThaw) { + ata_port_schedule_eh(ap); + } else { + ata_port_printk(ap, KERN_ERR, "port freeze from sysfs control\n"); + ata_eh_freeze_port(ap); + +#ifdef MY_ABC_HERE + schedule_work(&(ap->SendPortDisEventTask)); +#endif /* MY_ABC_HERE */ + } + + ret = count; + +END: + return ret; +} + +static ssize_t +syno_port_thaw_show(struct device *dev, struct device_attribute *attr, char * buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + ssize_t len = -EIO; + + if(!ap) { + goto END; + } + + + if (ap->pflags & ATA_PFLAG_FROZEN) { + len = sprintf(buf, "%d%s", 0, "\n"); + } else { + len = sprintf(buf, "%d%s", 1, "\n"); + } + +END: + return len; +} +DEVICE_ATTR(syno_port_thaw, S_IRUGO | S_IWUSR, syno_port_thaw_show, syno_port_thaw_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_port_thaw); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * show this dev power reset count + **/ +static ssize_t +syno_pwr_reset_count_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *ata_dev = ata_scsi_find_dev(ap, sdev); + + ssize_t len = -EIO; + + if (!ap || !ata_dev) { + goto END; + } + + len = sprintf(buf, "%d%s", ata_dev->iResetPwrCount, "\n"); + +END: + return len; +} + +/** + * set this dev power reset count + **/ +static ssize_t +syno_pwr_reset_count_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *ata_dev = ata_scsi_find_dev(ap, sdev); + + int iSet = 0; + ssize_t ret = -EIO; + + if (!ap || !ata_dev) { + goto END; + } + + sscanf(buf, "%d", &iSet); + ata_dev->iResetPwrCount = iSet; + + ret = count; + +END: + return ret; +} +DEVICE_ATTR(syno_pwr_reset_count, S_IRUGO | S_IWUSR, syno_pwr_reset_count_show, syno_pwr_reset_count_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_pwr_reset_count); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * send an error event to user space + **/ +static ssize_t +syno_sata_error_event_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *ata_dev = ata_scsi_find_dev(ap, sdev); + ssize_t ret = -EIO; + int iStartIdx = 0; + int iErrorCount = 0; + int iDiskPortType = 0; +#ifdef MY_ABC_HERE + DISK_PORT_TYPE diskPortType = UNKNOWN_DEVICE; + int iDiskPortIndex = -1; +#endif /* MY_ABC_HERE */ + + if (!ap || !ata_dev) { + goto END; + } + sscanf(buf, "%d", &iErrorCount); + + iStartIdx = syno_libata_numeric_diskname_number_get(ata_dev->link); + +#ifdef MY_ABC_HERE + get_disk_port_type_and_index_by_ata_port(ap, &diskPortType, &iDiskPortIndex); + iDiskPortType = (int) diskPortType; +#endif /* MY_ABC_HERE */ + + if (func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_SATA_ERROR_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + SERR_10B_8B_ERR, + ATA_ICRC, + iDiskPortType); + printk(KERN_ERR "----------------------- sent event: {SError: 10B8B} {Error: ICRC} --------------------\n"); + + func_synobios_event_handler(SYNO_EVENT_SATA_ERROR_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + SERR_HANDSHAKE | SERR_DISPARITY, + ATA_UNC, + iDiskPortType); + printk(KERN_ERR "----------------------- sent event: {SError: Dispar Handshk} {Error: UNC} --------------------\n"); + + func_synobios_event_handler(SYNO_EVENT_SATA_ERROR_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + 0, + ATA_IDNF | ATA_ABORTED | ATA_UNC, + iDiskPortType); + printk(KERN_ERR "----------------------- send event: {Error: UNC IDNF ABORTED} --------------------\n"); + + func_synobios_event_handler(SYNO_EVENT_DISK_TIMEOUT_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + 0, + 0, + iDiskPortType); + + printk(KERN_ERR "----------------------- sent event: {Timeout Others} --------------------\n"); + func_synobios_event_handler(SYNO_EVENT_DISK_TIMEOUT_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + 1, + 0, + iDiskPortType); + printk(KERN_ERR "----------------------- sent event: {Timeout R/W} --------------------\n"); + + func_synobios_event_handler(SYNO_EVENT_DISK_RESET_FAIL_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + 0, + iErrorCount, + iDiskPortType); + printk(KERN_ERR "----------------------- sent event: {Soft reset failed count %d} --------------------\n", iErrorCount); + + func_synobios_event_handler(SYNO_EVENT_DISK_RESET_FAIL_REPORT, + 6, + iStartIdx, + ap->nr_pmp_links, + ata_dev->link->pmp, + 1, + iErrorCount, + iDiskPortType); + printk(KERN_ERR "----------------------- sent event: {Hard reset failed count %d} --------------------\n", iErrorCount); + +#ifdef MY_ABC_HERE + /* slot index of PORT_LOST_XXX event should be 1 based. */ + iStartIdx = ap->syno_internal_slot_index; + printk(KERN_ERR "----------------------- sent event: {Retry Failed} --------------------\n"); + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, iStartIdx + 1, PORT_LOST_RETRY_FAILED); + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, iStartIdx + 1, PORT_LOST_RETRY_FAILED_PRESENT); + printk(KERN_ERR "----------------------- sent event: {Port Disabled} --------------------\n"); + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, iStartIdx + 1, PORT_LOST_DISABLED); + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, iStartIdx + 1, PORT_LOST_DISABLED_PRESENT); + printk(KERN_ERR "----------------------- sent event: {link down} --------------------\n"); + func_synobios_event_handler(SYNO_EVENT_DISK_PORT_LOST, 2, iStartIdx + 1, PORT_LOST_LINK_DOWN_PRESENT); +#endif /* MY_ABC_HERE */ + + } + + schedule_work(&(ap->SendDiskRetryEventTask)); + + ret = count; + +END: + return ret; +} +DEVICE_ATTR(syno_sata_error_event_debug, S_IWUSR, NULL, syno_sata_error_event_debug_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_sata_error_event_debug); +#endif /* MY_ABC_HERE */ + struct device_attribute *ata_common_sdev_attrs[] = { &dev_attr_unload_heads, +#ifdef MY_ABC_HERE + &dev_attr_syno_wcache, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_deep_sleep_support, + &dev_attr_syno_deep_sleep_ctrl, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_disk_latency_read_hist, + &dev_attr_syno_disk_latency_write_hist, + &dev_attr_syno_disk_latency_other_hist, + &dev_attr_syno_disk_latency_stat, +#ifdef MY_ABC_HERE + &dev_attr_syno_disk_seq_stat, +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_pwr_reset_count, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_sata_error_event_debug, +#endif /* MY_ABC_HERE */ NULL }; EXPORT_SYMBOL_GPL(ata_common_sdev_attrs); @@ -526,6 +3015,48 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) return rc; } +#ifdef MY_ABC_HERE +/** + * This function is used to get SATA disk power status. + * + * @param scsidev The SCSI device structure of the disk + * @param DiskStatus We will put disk status in DiskStatus. If DiskStatus == 0, + * means the disk is sleeping. If DiskStatus == 255, means + * the disk is active. + * + * @return <0: Failed + * 0: Success + */ +int SynoDiskPowerCheck(struct scsi_device *scsidev, int *DiskStatus) +{ + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 sensebuf[SCSI_SENSE_BUFFERSIZE]; + int result = -EFAULT; + struct scsi_sense_hdr sshdr; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1); /* Non-data */ + + /* So the ata_scsi_qc_complete() will call ata_gen_ata_desc_sense() to fill taskfile registers. */ + scsi_cmd[2] = 0x20; + scsi_cmd[14] = ATA_CMD_CHK_POWER; + + memset(sensebuf, 0, sizeof(sensebuf)); + + result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0, + sensebuf, &sshdr, (10*HZ), 5, 0, 0, NULL); + + if (result == ((DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION)) { + *DiskStatus = sensebuf[13]; + result = 0; + } + + return result; +} +#endif /* MY_ABC_HERE */ + static int ata_ioc32(struct ata_port *ap) { if (ap->flags & ATA_FLAG_PIO_DMA) @@ -545,6 +3076,9 @@ int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, unsigned long val; int rc = -EINVAL; unsigned long flags; +#ifdef MY_ABC_HERE + struct ata_device *dev; +#endif /* MY_ABC_HERE */ switch (cmd) { case HDIO_GET_32BIT: @@ -586,6 +3120,33 @@ int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, return -EACCES; return ata_task_ioctl(scsidev, arg); +#ifdef MY_ABC_HERE + case HDIO_GET_DMA: + { + dev = ata_scsi_find_dev(ap, scsidev); + + if(!dev) + return -ENODEV; + + if (dev->xfer_mode <= XFER_PIO_4) { + val = 0; + } else { + val = 1; + } + if (copy_to_user(arg, &val, sizeof(int))) + return -EFAULT; + return 0; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + case ATA_CMD_CHK_POWER: + { + int *DiskStatus = (int *)arg; + return SynoDiskPowerCheck(scsidev, DiskStatus); + } +#endif /* MY_ABC_HERE */ + default: rc = -ENOTTY; break; @@ -1000,6 +3561,9 @@ void ata_scsi_sdev_config(struct scsi_device *sdev) * requests. */ sdev->max_device_blocked = 1; +#ifdef MY_ABC_HERE + sdev->default_disable_fua = 1; +#endif /* MY_ABC_HERE */ } /** @@ -1052,6 +3616,12 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) } else { sdev->sector_size = ata_id_logical_sector_size(dev->id); sdev->manage_start_stop = 1; + +#ifdef MY_ABC_HERE + if (iIsSynoPmCtlSupport(dev->link->ap)) { + sdev->power_loss_during_reboot = 1; + } +#endif /* MY_ABC_HERE */ } /* @@ -1541,8 +4111,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) int rc; u16 fp = 0; +#ifdef MY_ABC_HERE + if (cdb[0] == WRITE_10 || cdb[0] == WRITE_6 || cdb[0] == WRITE_16) { + tf_flags |= ATA_TFLAG_WRITE; + qc->qc_stat.u8QcType = 2; + } else if (cdb[0] == READ_10 || cdb[0] == READ_6 || cdb[0] == READ_16) { + qc->qc_stat.u8QcType = 1; + } +#else /* MY_ABC_HERE */ if (cdb[0] == WRITE_10 || cdb[0] == WRITE_6 || cdb[0] == WRITE_16) tf_flags |= ATA_TFLAG_WRITE; +#endif /* MY_ABC_HERE */ /* Calculate the SCSI LBA, transfer length and FUA. */ switch (cdb[0]) { @@ -1605,6 +4184,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) qc->flags |= ATA_QCFLAG_IO; qc->nbytes = n_block * scmd->device->sector_size; +#ifdef MY_ABC_HERE + qc->qc_stat.u64StartLbaByte = block * scmd->device->sector_size; + qc->qc_stat.u8LbaZone = (block >> qc->dev->u8LbaZoneShiftBit) & + SYNO_SEQ_SAMPLE_LBA_ZONE_MASK; +#endif /* MY_ABC_HERE */ rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, qc->hw_tag, class); @@ -1643,6 +4227,9 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; +#ifdef MY_ABC_HERE + u8 *desc = NULL; +#endif /* MY_ABC_HERE */ int need_sense = (qc->err_mask != 0); /* For ATA pass thru (SAT) commands, generate a sense block if @@ -1659,14 +4246,51 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_gen_passthru_sense(qc); else if (qc->flags & ATA_QCFLAG_SENSE_VALID) cmd->result = SAM_STAT_CHECK_CONDITION; +#ifdef MY_ABC_HERE + else if (need_sense) { + ata_gen_ata_sense(qc); + /* Only UNC errors need remaping, and we also make sure that + * the result is reported by log page 10h for NCQ commands. + * This prevents remapping with untrusted LBAs. + */ + if ((qc->result_tf.feature & ATA_UNC) && + ata_is_ncq(qc->tf.protocol) && + !(qc->err_mask & AC_ERR_NCQ)) { + desc = qc->scsicmd->sense_buffer + 8; + desc[SYNO_DESCRIPTOR_RESERVED_INDEX] |= SYNO_NCQ_FAKE_UNC; + } + } +#else /* MY_ABC_HERE */ else if (need_sense) ata_gen_ata_sense(qc); +#endif /* MY_ABC_HERE */ else cmd->result = SAM_STAT_GOOD; if (need_sense && !ap->ops->error_handler) ata_dump_status(ap->print_id, &qc->result_tf); +#ifdef MY_DEF_HERE + if (!(cdb[0] == ATA_16 && cdb[14] == ATA_CMD_CHK_POWER)) { + /* update time of last command */ + qc->dev->ulLastCmd = jiffies; + } + + if ((cdb[0] == ATA_16) && + (ATA_CMD_IDLEIMMEDIATE == qc->tf.command || + ATA_CMD_STANDBY == qc->tf.command || + ATA_CMD_STANDBYNOW1 == qc->tf.command)) { + DBGMESG("disk %d set iCheckPwr\n", ap->print_id); + qc->dev->iCheckPwr = 1; + if (0 < giSynoSpinupGroupNum) { + gCurrentSpinupGroupNum = 0; + guiWakeupDisksNum = giSynoSpinupGroup[0]; + /* reset giNeedWakeAll when no HDD waking*/ + giNeedWakeAll = 0; + } + } +#endif /* MY_DEF_HERE */ + ata_qc_done(qc); } @@ -1761,6 +4385,242 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, return SCSI_MLQUEUE_HOST_BUSY; } +#ifdef MY_DEF_HERE +void ata_qc_complete_read(struct ata_queued_cmd *qc) +{ + if (qc->err_mask) { + DBGMESG("read cmd qc->err_mask != 0 print_id %u pmp %u\n", qc->ap->print_id, qc->dev->link->pmp); + } + if (qc->flags & ATA_QCFLAG_FAILED) { + DBGMESG("This read qc is failed 0 print_id %u pmp %u\n", qc->ap->print_id, qc->dev->link->pmp); + } + + DBGMESG("port %d clear CHKPOWER_FIRST_WAIT\n", qc->ap->print_id); + clear_bit(CHKPOWER_FIRST_WAIT, &(qc->dev->ulSpinupState)); + + if(NULL == qc->cursg) { + printk(KERN_ERR "MEMORY LEAK!! qc->cursg is NULL, the psg we allocated becomes orphan \n"); + WARN_ON(1); + goto OUT; + } + kfree(qc->cursg); + +OUT: + ata_qc_free(qc); +} + +static int SynoIssueWakeUpCmd(struct ata_device *dev, struct scsi_cmnd *cmd) +{ + struct ata_queued_cmd *qc; + struct ata_port *ap = dev->link->ap; + struct scatterlist *psg = NULL; + int rc; + u16 *buf = (void *)dev->link->ap->sector_buf; + + if (test_and_set_bit(CHKPOWER_FIRST_WAIT, &(dev->ulSpinupState))) { + printk("%s: there is already read cmd processing print_id %d link->pmp %d\n", + __FUNCTION__, ap->print_id, dev->link->pmp); + WARN_ON(1); + goto ERR_MEM; + } + + /* issue a chk_power ata command to check disk power status */ + qc = ata_qc_new_init(dev, cmd->request->tag); + if (NULL == qc) { + DBGMESG("%s: read cmd fail NULL == qc print_id %d link->pmp %d\n", + __FUNCTION__, ap->print_id, dev->link->pmp); + clear_bit(CHKPOWER_FIRST_WAIT, &(dev->ulSpinupState)); + goto ERR_MEM; + } + + /* copy from ata_scsi_rw_xlat(..) and ata_exec_internal(..) */ + psg = kmalloc(ATA_SECT_SIZE, GFP_ATOMIC);//will free in complete function + sg_init_one(psg, buf, ATA_SECT_SIZE); + ata_sg_init(qc, psg, 1); + /* + * for ASMEDIA 1061, SynoRead command always fail, + * so we change this to idle immediate command + * this command apply to ASMEDIA & RTDSoC HDD both. + * no need for init qc->nbytes & dma_dir & flags + * the init procedure is in ata_qc_new_init + */ + qc->tf.command = ATA_CMD_IDLEIMMEDIATE; + qc->tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + qc->tf.protocol = ATA_PROT_NODATA; + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = DMA_NONE; + qc->complete_fn = ata_qc_complete_read; + + if (ap->ops->qc_defer) { + if ((rc = ap->ops->qc_defer(qc))){ + /* if this port need defer, we should set CHKPOWER_FIRST_CMD and clear CHKPOWER_FIRST_WAIT + * to let this port re-insert read later */ + set_bit(CHKPOWER_FIRST_CMD, &(dev->ulSpinupState)); + clear_bit(CHKPOWER_FIRST_WAIT, &(dev->ulSpinupState)); + DBGMESG("%s read cmd qc_defer, print_id %d pmp %d tag %d\n", __FUNCTION__, ap->print_id, dev->link->pmp, qc->tag); + goto DEFER; + } + } + + /* issue read and update gulLastWake */ + spin_lock(&SYNOLastWakeLock); + gulLastWake = jiffies; + /* count waking disks */ + ++giWakingDisks; + /* if all disks in group were waking, reset group */ + if (giWakingDisks == guiWakeupDisksNum) { + giWakingDisks = giGroupDisks = 0; + if(0 < giSynoSpinupGroupNum){ + DBG_SpinupGroup("Disk Group %d is full, going to delay for spinup.\n",gCurrentSpinupGroupNum); + gCurrentSpinupGroupNum++; + if (gCurrentSpinupGroupNum >= giSynoSpinupGroupNum) { + /* if syno_spinup_group not use all disks, left hdd poweron 1 by 1 */ + guiWakeupDisksNum = 1; + } else { + guiWakeupDisksNum = giSynoSpinupGroup[gCurrentSpinupGroupNum]; + } + } + } + spin_unlock(&SYNOLastWakeLock); + DBGMESG("port %d update gulLastWake %lu and issue read\n", ap->print_id, gulLastWake); + dev->ulLastCmd = jiffies; + ata_qc_issue(qc); + + return SCSI_MLQUEUE_HOST_BUSY; + +ERR_MEM: + dev->ulLastCmd = jiffies; + return SCSI_MLQUEUE_HOST_BUSY; +DEFER: + ata_qc_free(qc); + if (rc == ATA_DEFER_LINK) + return SCSI_MLQUEUE_DEVICE_BUSY; + else + return SCSI_MLQUEUE_HOST_BUSY; +} + +static int syno_ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, + ata_xlat_func_t xlat_func) +{ + struct ata_port *ap = dev->link->ap; + u8 *scsicmd = cmd->cmnd; + int iNeedWait = 0; + + /* no insert comamnd while the device is derived from PM */ + if (ap->nr_pmp_links) { + goto PASS; + } + + /* no insert command while frozen */ + if (ap->pflags & ATA_PFLAG_FROZEN) { + if (printk_ratelimit()) { + DBGMESG("port %d ATA_PFLAG_FROZEN or ATA_FLAG_DISABLED, clear all bits\n", ap->print_id); + } + ata_port_schedule_eh(ap); + clear_bit(CHKPOWER_FIRST_CMD, &(dev->ulSpinupState)); + clear_bit(CHKPOWER_FIRST_WAIT, &(dev->ulSpinupState)); + goto PASS; + } + +#ifdef MY_ABC_HERE + if (dev->is_ssd) { + goto PASS; + } +#endif /* MY_ABC_HERE */ + + /* The inserted command timeout! reset the port and notify upper layer to re-send command */ + if (test_bit(CHKPOWER_FIRST_WAIT, &(dev->ulSpinupState))) { + if (time_after(jiffies, dev->ulLastCmd + ISSUEREADTIMEOUT)) { + ata_link_printk(dev->link, KERN_ERR, "checking issue READ timeout\n"); + WARN_ON(1 != dev->link->ap->nr_active_links); + dev->link->eh_info.action |= ATA_EH_RESET; + ata_port_schedule_eh(dev->link->ap); + } + goto WAIT; + } + + /* if already have ata command executing, don't insert ATA_CMD_CHK_POWER */ + if(0 != ap->nr_active_links) { + goto PASS; + } + + /* The ATA_CMD_CHK_POWER command won't wake up disk. So we don't check whether + * DS is sleeping now. + */ + if (scsicmd[0] == ATA_16 && scsicmd[14] == ATA_CMD_CHK_POWER) { + goto PASS_ONCE; + } else { + /* we need insert read as the first cmd to wakeup disk */ + if (dev->iCheckPwr || test_bit(CHKPOWER_FIRST_CMD, &(dev->ulSpinupState))) { + /* check if this port need wait other disks wakeup */ + spin_lock(&SYNOLastWakeLock); + /* last hdd of group cannot reset group unless giSynoSpinupGroupNum = 0 */ + if(gulLastWake && time_after(jiffies, gulLastWake + SynoWakeInterval())) { + if(0 < giSynoSpinupGroupNum && (giGroupDisks && giGroupDisks < guiWakeupDisksNum)) { + giWakingDisks = giGroupDisks = 0; + } + else if(0 == giSynoSpinupGroupNum) { + /* not set syno_spinup_group so go the original way*/ + giWakingDisks = giGroupDisks = 0; + } + } + + /* The following case, we can add this disk to group to wakup + * 1. No body waking + * 2. The group is empty and jiffies is already after last wakeup jiffies + * 3. The group not full + * 4. Dynamic HDD power on mechanism when two RP is connected. + **/ + if (!gulLastWake || + (!giGroupDisks && + time_after(jiffies, gulLastWake + SynoWakeInterval())) || + giNeedWakeAll || + (giGroupDisks && giGroupDisks < guiWakeupDisksNum)) { + if (0 < giSynoSpinupGroupNum) { + DBGMESG("hiberation debug: port %d detected\n", ap->print_id); + if (SynoHaveRPDetectPin() && SynoAllRedundantPowerDetected()) { + /* set giNeedWakeAll when this model have RP detect pin and two RP is power good*/ + giNeedWakeAll = 1; + } + } + ++giGroupDisks; + } else { + /* the group is full, must wait */ + iNeedWait = 1; + } + spin_unlock(&SYNOLastWakeLock); + + if (!iNeedWait) { + goto ISSUE_READ; + } else { + /* These msg will appear very much, so we mark it. + * But it is useful for debug, I leave it here */ +#ifdef MY_ABC_HERE + if (0 < gSynoAtaDebug && printk_ratelimit()) { + printk("port %d too close to last wakeup, wait again (%lu) (%lu) (%lu)\n", + ap->print_id, jiffies, gulLastWake, SynoWakeInterval()); +#endif /* MY_ABC_HERE */ + } + goto WAIT; + } + } + } + +PASS: + dev->iCheckPwr = 0; +PASS_ONCE: + /* update time-bookkeeping of last command */ + dev->ulLastCmd = jiffies; + return ata_scsi_translate(dev, cmd, xlat_func); +ISSUE_READ: + dev->iCheckPwr = 0; + dev->ulSpinupState = 0; + return SynoIssueWakeUpCmd(dev, cmd); +WAIT: + return SCSI_MLQUEUE_HOST_BUSY; +} +#endif /* MY_DEF_HERE */ + struct ata_scsi_args { struct ata_device *dev; u16 *id; @@ -1893,6 +4753,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) 2 }; +#ifdef MY_ABC_HERE + unsigned char szIdBuf[ATA_ID_PROD_LEN + 1] = {0x00}; + int idxStr, idxModelStr; + char bHasSpace = 0; +#endif /* MY_ABC_HERE */ VPRINTK("ENTER\n"); /* set scsi removable (RMB) bit per ata bit, or if the @@ -1908,8 +4773,45 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) } memcpy(rbuf, hdr, sizeof(hdr)); +#ifdef MY_ABC_HERE + ata_id_c_string(args->id, szIdBuf, ATA_ID_PROD, ATA_ID_PROD_LEN+1); + + for (idxStr = 0; idxStr < ATA_ID_PROD_LEN; idxStr++) { + if (' ' == szIdBuf[idxStr]) { + bHasSpace = 1; + break; + } + + if (0x00 == szIdBuf[idxStr]) { + break; + } + } + + if (0 == bHasSpace) { + memcpy(&rbuf[8], "ATA ", 8); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + } else { + for (idxStr = 0; idxStr < 8; idxStr++) { + if (' ' == szIdBuf[idxStr]) { + break; + } + rbuf[8 + idxStr] = szIdBuf[idxStr]; + } + while (' ' == szIdBuf[idxStr]) { + idxStr++; + } + for (idxModelStr = 0; idxModelStr < 16; idxModelStr++) { + if (' ' == szIdBuf[idxStr]) { + break; + } + rbuf[16 + idxModelStr] = szIdBuf[idxStr]; + idxStr++; + } + } +#else /* MY_ABC_HERE */ memcpy(&rbuf[8], "ATA ", 8); ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); +#endif /* MY_ABC_HERE */ /* From SAT, use last 2 words from fw rev unless they are spaces */ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); @@ -2468,7 +5370,11 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[14] |= 0x80; /* LBPME */ if (ata_id_has_zero_after_trim(args->id) && +#ifdef MY_ABC_HERE + 1 ) { +#else /* MY_ABC_HERE */ dev->horkage & ATA_HORKAGE_ZERO_AFTER_TRIM) { +#endif /* MY_ABC_HERE */ ata_dev_info(dev, "Enabling discard_zeroes_data\n"); rbuf[14] |= 0x40; /* LBPRZ */ } @@ -2752,6 +5658,11 @@ static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) if (likely(devno >= 0 && devno < ap->nr_pmp_links)) return &ap->pmp_link[devno].device[0]; +#ifdef MY_ABC_HERE + else if (devno == SYNO_PM_VIRTUAL_SCSI_CHANNEL && syno_is_synology_pm(ap)) { + return &ap->link.device[0]; + } +#endif /* MY_ABC_HERE */ } return NULL; @@ -3066,6 +5977,23 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) goto invalid_fld; } +#ifdef MY_ABC_HERE + if (ATA_CMD_SET_FEATURES == tf->command && + SETFEATURES_WC_ON == tf->feature && + (dev->flags & ATA_DFLAG_NO_WCACHE) && + (dev->horkage & ATA_HORKAGE_NOWCACHE)) { + goto skip_cmd; + } + + if (ATA_CMD_SET_FEATURES == tf->command) { + if (SETFEATURES_WC_OFF == tf->feature) { + dev->flags |= ATA_DFLAG_NO_WCACHE; + } else if (SETFEATURES_WC_ON == tf->feature) { + dev->flags &= ~ATA_DFLAG_NO_WCACHE; + } + } +#endif /* MY_ABC_HERE */ + /* * Filter TPM commands by default. These provide an * essentially uncontrolled encrypted "back door" between @@ -3091,6 +6019,15 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) invalid_fld: ata_scsi_set_invalid_field(dev, scmd, fp, 0xff); return 1; + +#ifdef MY_ABC_HERE + skip_cmd: + ata_dev_printk(dev, KERN_ERR, "skip command 0x%x feature 0x%x", tf->command, tf->feature); + if (cdb[2] & 0x20) { + ata_gen_passthru_sense(qc); + } + return 1; +#endif /* MY_ABC_HERE */ } /** @@ -4017,6 +6954,101 @@ void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd) #endif } +#ifdef MY_ABC_HERE +/* Action after prehook */ +typedef enum _tag_ATACMD_HOOK_ACTION { + ACT_BYPASS = 0, + ACT_SKIP, + ACT_REISSUE, +} ATACMD_HOOK_ACTION; + +/* Check before cmd xlat */ +static ATACMD_HOOK_ACTION syno_ata_scsi_xlat_prehook(struct ata_device *dev, struct scsi_cmnd *scmd) +{ + ATACMD_HOOK_ACTION ret = ACT_BYPASS; + + +#ifdef MY_ABC_HERE + /* + * EUnit GPIO control commands can be directly issued + */ + if (ata_is_host_link(dev->link) && (dev->link->ap->link.uiStsFlags & SYNO_STATUS_GPIO_CTRL)) { + return ACT_BYPASS; + } + + /* if irq off, we must Schedule Wake Up immediately to let + * ResubmitCommand(..) -> ata_port_schedule_eh(..) -> ata_scsi_error(..) + * power on disk */ + if ((dev->link->ap->pflags & ATA_PFLAG_SYNO_IRQ_OFF) || + (dev->link->ap->pflags & ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE)) { + + if (!(dev->link->ap->pflags & ATA_PFLAG_SYNO_DS_PWROFF)) { + ata_port_schedule_eh(dev->link->ap); + return ACT_REISSUE; + } else { + return ACT_SKIP; + } + } + + if(IS_SYNOLOGY_RX1223RP(dev->link->ap->PMSynoUnique)) { + if ((dev->link->ap->pflags & ATA_PFLAG_SYNO_DS_WAKING)) { + ata_port_schedule_eh(dev->link->ap); + return ACT_REISSUE; + } + } + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (dev->link->ap->nr_pmp_links && dev->link->ap->pflags & ATA_PFLAG_SYNO_BOOT_PROBE) { + /* I don't know why some EUnit master may not clear ATA_PFLAG_SYNO_BOOT_PROBE, + * so we must clear it again by schedule_eh*/ + ata_port_schedule_eh(dev->link->ap); + return ACT_REISSUE; + } +#endif /* MY_ABC_HERE */ + + return ret; +} + +/* Something after cmd xlat */ +static void syno_ata_scsi_xlat_posthook(struct ata_device *dev, struct scsi_cmnd *scmd, int rc) +{ +#ifdef MY_ABC_HERE + static unsigned long iStuckTimeout; + static int icPMRWDefer = 0; + struct ata_queued_cmd *active_qc; + u8 active_command; + + /* This was the original work around for the problem that PMP GPIO command stucked in the low level driver and cause in system hang. + * Though the issue has been fixed, we leave it here to make sure the system will not hang when running into a similar situation. + * When multiple commands are deferred in a row longer than normal ATA command timeout(10 sec), + * and the command occupying the lower level queue is an PMP R/W command, we force it to abort. + * Also, we assumed that there won't be more than 64 commands(twice of the default ATA queue depth) + * be deffered in common cases. */ + active_qc = __ata_qc_from_tag(dev->link->ap, 0); + active_command = active_qc->tf.command; + /* we abort the PMP R/W command if it stuck in ata queue too long and caused too many defer */ + if (SCSI_MLQUEUE_DEVICE_BUSY != rc && SCSI_MLQUEUE_HOST_BUSY != rc){ + icPMRWDefer = 0; + iStuckTimeout = jiffies + 10 * HZ; + } else if (64 <= icPMRWDefer && + time_after_eq(jiffies, iStuckTimeout) && + active_qc->flags & ATA_QCFLAG_ACTIVE && + (ATA_CMD_PMP_READ == active_command || ATA_CMD_PMP_WRITE == active_command)) { + icPMRWDefer = 0; + iStuckTimeout = jiffies + 10 * HZ; + ata_dev_printk(dev, KERN_INFO,"Abort stucked PMP R/W command\n"); + ata_port_abort(dev->link->ap); + } else { + icPMRWDefer++; + } +#endif /* MY_ABC_HERE */ + + return ; +} +#endif /* MY_ABC_HERE */ + int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) { u8 scsi_op = scmd->cmnd[0]; @@ -4051,11 +7083,41 @@ int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) } } +#ifdef MY_ABC_HERE + if (xlat_func) { + ATACMD_HOOK_ACTION hook = syno_ata_scsi_xlat_prehook(dev, scmd); + + if (ACT_REISSUE == hook) { + return SCSI_MLQUEUE_HOST_BUSY; + } else if (ACT_SKIP == hook) { + goto SKIP; + } + /* else should be ACT_BYPASS, just bypass */ + } +#endif /* MY_ABC_HERE */ + if (xlat_func) +#ifdef MY_DEF_HERE + { + if (0 == gSynoHddPowerupSeq && 1 == guiWakeupDisksNum) { + /* no spin up delay, use original function */ + rc = ata_scsi_translate(dev, scmd, xlat_func); + } else { + /* command translate with spin up delay */ + rc = syno_ata_scsi_translate(dev, scmd, xlat_func); + } + } +#else /* MY_DEF_HERE */ rc = ata_scsi_translate(dev, scmd, xlat_func); +#endif /* MY_DEF_HERE */ else ata_scsi_simulate(dev, scmd); +#ifdef MY_ABC_HERE +SKIP: + syno_ata_scsi_xlat_posthook(dev, scmd, rc); +#endif /* MY_ABC_HERE */ + return rc; bad_cdb_len: @@ -4318,6 +7380,29 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) struct ata_device *last_failed_dev = NULL; struct ata_link *link; struct ata_device *dev; +#ifdef MY_ABC_HERE + char modelbuf[ATA_ID_PROD_LEN+1]; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct scsi_device *pPmSdev; + int iPmId = 0; + + if (syno_is_synology_pm(ap)) { + dev = (struct ata_device *)ap->link.device; + iPmId = dev->devno; + pPmSdev = __scsi_add_device(ap->scsi_host, SYNO_PM_VIRTUAL_SCSI_CHANNEL, iPmId, 0, + NULL); + + if (!IS_ERR(pPmSdev)) { + dev->sdev = pPmSdev; + scsi_device_put(pPmSdev); + syno_pm_show_sn(dev); + } else { + dev->sdev = NULL; + } + } +#endif /* MY_ABC_HERE */ repeat: ata_for_each_link(link, ap, EDGE) { @@ -4333,6 +7418,13 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) else channel = link->pmp; +#ifdef MY_ABC_HERE + if (dev->is_ssd) { + ata_id_c_string(dev->id, modelbuf, ATA_ID_PROD, sizeof(modelbuf)); + ata_dev_printk(dev, KERN_WARNING, "Find SSD disks. [%s]\n", modelbuf); + } +#endif /* MY_ABC_HERE */ + sdev = __scsi_add_device(ap->scsi_host, channel, id, 0, NULL); if (!IS_ERR(sdev)) { @@ -4525,6 +7617,9 @@ void ata_scsi_hotplug(struct work_struct *work) struct ata_port *ap = container_of(work, struct ata_port, hotplug_task.work); int i; +#ifdef MY_ABC_HERE + char *envp[2]; +#endif /* MY_ABC_HERE */ if (ap->pflags & ATA_PFLAG_UNLOADING) { DPRINTK("ENTER/EXIT - unloading\n"); @@ -4546,10 +7641,47 @@ void ata_scsi_hotplug(struct work_struct *work) /* scan for new ones */ ata_scsi_scan_host(ap, 0); +#ifdef MY_ABC_HERE + if (ap->pflags & ATA_PFLAG_PMP_DISCONNECT) { + envp[0] = SZK_PMP_UEVENT"="SZV_PMP_DISCONNECT; + ap->pflags &= ~ATA_PFLAG_PMP_DISCONNECT; + } else if (ap->pflags & ATA_PFLAG_PMP_CONNECT) { + envp[0] = SZK_PMP_UEVENT"="SZV_PMP_CONNECT; + ap->pflags &= ~ATA_PFLAG_PMP_CONNECT; + } else { + envp[0] = NULL; + } + + envp[1] = NULL; + kobject_uevent_env(&ap->scsi_host->shost_dev.kobj, KOBJ_CHANGE, envp); +#endif /* MY_ABC_HERE */ + mutex_unlock(&ap->scsi_scan_mutex); DPRINTK("EXIT\n"); } +#ifdef MY_ABC_HERE +void ata_syno_pmp_hotplug(struct work_struct *work) +{ + struct ata_port *ap = + container_of(work, struct ata_port, hotplug_task.work); + char *envp[2]; + + if (ap->pflags & ATA_PFLAG_PMP_DISCONNECT) { + envp[0] = SZK_PMP_UEVENT"="SZV_PMP_DISCONNECT; + ap->pflags &= ~ATA_PFLAG_PMP_DISCONNECT; + } else if (ap->pflags & ATA_PFLAG_PMP_CONNECT) { + envp[0] = SZK_PMP_UEVENT"="SZV_PMP_CONNECT; + ap->pflags &= ~ATA_PFLAG_PMP_CONNECT; + } else { + envp[0] = NULL; + } + + envp[1] = NULL; + kobject_uevent_env(&ap->scsi_host->shost_dev.kobj, KOBJ_CHANGE, envp); +} +#endif /* MY_ABC_HERE */ + /** * ata_scsi_user_scan - indication for user-initiated bus scan * @shost: SCSI host to scan @@ -4660,3 +7792,272 @@ void ata_scsi_dev_rescan(struct work_struct *work) spin_unlock_irqrestore(ap->lock, flags); mutex_unlock(&ap->scsi_scan_mutex); } + +#ifdef MY_ABC_HERE +static struct scsi_device * syno_look_up_scsi_dev_from_ata_link(struct ata_link *pAtaLink) +{ + struct scsi_device *pScsiDevice = NULL; + struct ata_device *pAtaDevicedev = NULL; + + if (NULL == pAtaLink) { + goto END; + } + + ata_for_each_dev(pAtaDevicedev, pAtaLink, ALL) { + if (pAtaDevicedev->sdev && SDEV_RUNNING == pAtaDevicedev->sdev->sdev_state) { + pScsiDevice = pAtaDevicedev->sdev; + break; + } + } +END: + return pScsiDevice; +} + +int syno_libata_numeric_diskname_number_get(struct ata_link *pAtaLink) +{ + struct scsi_device *pScsiDevice = syno_look_up_scsi_dev_from_ata_link(pAtaLink); + int iSynoDiskNameNumber = 0, iRet = -1; + char *pSynoDiskNameNumber = NULL; + + if (NULL == pAtaLink || NULL == pScsiDevice) { + goto END; + } + + pSynoDiskNameNumber = strstr(pScsiDevice->syno_disk_name, CONFIG_SYNO_SATA_DEVICE_PREFIX); + if (NULL == pSynoDiskNameNumber) { + printk(KERN_INFO "Disk name [%s] is not a %s disk name.\n", pScsiDevice->syno_disk_name, CONFIG_SYNO_SATA_DEVICE_PREFIX); + goto END; + } + + if (0 != kstrtoint(pSynoDiskNameNumber + strlen(CONFIG_SYNO_SATA_DEVICE_PREFIX), 10, &iSynoDiskNameNumber)) { + printk(KERN_INFO "Disk name [%s] cannot convert its disk number.\n", pScsiDevice->syno_disk_name); + goto END; + } + iRet = iSynoDiskNameNumber; +END: + return iRet; +} +EXPORT_SYMBOL(syno_libata_numeric_diskname_number_get); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int syno_external_libata_index_get(const struct ata_port *ap) +{ + int index = -1; + struct device_node *pDeviceNode = NULL; + if (NULL == ap || NULL == of_root) { + goto END; + } + + for_each_child_of_node(of_root, pDeviceNode) { + if (pDeviceNode->full_name + && 0 == (strncmp(pDeviceNode->full_name, DT_ESATA_SLOT, strlen(DT_ESATA_SLOT)))) { + if (true == ap->ops->syno_compare_node_info(ap, pDeviceNode)) { + // get index number of esata_slot, e.g. /esata_slot@4 --> 4 + sscanf(pDeviceNode->full_name, DT_ESATA_SLOT"@%d", &index); + of_node_put(pDeviceNode); + break; + } + } else if (pDeviceNode->full_name + && 0 == (strncmp(pDeviceNode->full_name, DT_CX4_SLOT, strlen(DT_CX4_SLOT)))) { + if (true == ap->ops->syno_compare_node_info(ap, pDeviceNode)) { + // get index number of cx4_slot, e.g. /cx4_slot@4, 1 --> 4 + sscanf(pDeviceNode->full_name, DT_CX4_SLOT"@%d", &index); + of_node_put(pDeviceNode); + break; + } + } + } +END: + return index; +} +EXPORT_SYMBOL(syno_external_libata_index_get); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size); +static void syno_pciepath_enum(struct device *dev, char *buf) { + struct pci_dev *pdev = NULL; + char sztemp[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (NULL == buf || NULL == dev) { + return; + } + pdev = to_pci_dev(dev); + + if (-1 == syno_pciepath_dts_pattern_get(pdev, sztemp, sizeof(sztemp))) { + return; + } + + snprintf(buf, BLOCK_INFO_SIZE, "%spciepath=%s\n", buf, sztemp); +} + +static void syno_ata_info_enum(struct ata_port *ap, struct scsi_device *sdev) { +#ifdef MY_ABC_HERE + struct ata_device *dev = NULL; +#endif /* MY_ABC_HERE */ + + if (NULL == ap || NULL == sdev || NULL == ap->host) { + return; + } + + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sata_port_no=%u\n", sdev->syno_block_info, ap->port_no); + +#ifdef MY_ABC_HERE + dev = ata_scsi_find_dev(ap, sdev); + if (syno_is_synology_pm(ap) && NULL != dev && NULL != dev->link) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sis_syno_pmp=1\n", sdev->syno_block_info); + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%spmp_link=%u\n", sdev->syno_block_info, dev->link->pmp); + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sEMID=%u\n", sdev->syno_block_info, ap->PMSynoEMID); + + if (IS_SYNOLOGY_DX517(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_DX517); + } else if (IS_SYNOLOGY_RX418(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_RX418); + } else if (IS_SYNOLOGY_RX1217(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_RX1217); + } else if (IS_SYNOLOGY_DX1215(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_DX1215); + } else if (IS_SYNOLOGY_DX1222(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_DX1222); + } else if (IS_SYNOLOGY_DX1215II(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_DX1215II); + } else if (IS_SYNOLOGY_RX1223RP(ap->PMSynoUnique)) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sunique=%s\n", sdev->syno_block_info, EBOX_INFO_UNIQUE_RX1223RP); + } + } +#endif /* MY_ABC_HERE */ +} + +void syno_libata_info_enum(struct scsi_device *sdev) { + struct ata_port *ap = NULL; + + ap = ata_shost_to_port(sdev->host); + + if (NULL != ap) { + if (ap->dev->bus && !strcmp("pci", ap->dev->bus->name)) { + syno_pciepath_enum(ap->dev, sdev->syno_block_info); + } + syno_ata_info_enum(ap, sdev); + if (ap->scsi_host->hostt && ap->scsi_host->hostt->name) { + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sdriver=%s\n", sdev->syno_block_info, ap->scsi_host->hostt->name); + } + } +} +EXPORT_SYMBOL(syno_libata_info_enum); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t syno_wcache_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap; + struct ata_device *dev; + unsigned long flags; + int rc = 0; + + ap = ata_shost_to_port(sdev->host); + + spin_lock_irqsave(ap->lock, flags); + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) { + rc = -ENODEV; + goto unlock; + } + + if (dev->class != ATA_DEV_ATA) { + rc = -EOPNOTSUPP; + goto unlock; + } + + if (dev->flags & ATA_DFLAG_NO_WCACHE) { + rc = snprintf(buf, 20, "%s\n", "wcache_disable"); + } else { + rc = snprintf(buf, 20, "%s\n", "wcache_enable"); + } + +unlock: + spin_unlock_irq(ap->lock); + + return rc; +} + +static ssize_t syno_wcache_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t len) +{ + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + unsigned char model_rev[ATA_ID_FW_REV_LEN + 1]; + struct ata_blacklist_entry *ad = ata_device_blacklist; + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap; + struct ata_device *dev; + long int input; + unsigned long flags; + int rc; + + rc = kstrtol_from_user(buf, len, 10, &input); + if (rc) + return -EINVAL; + + ap = ata_shost_to_port(sdev->host); + + spin_lock_irqsave(ap->lock, flags); + dev = ata_scsi_find_dev(ap, sdev); + if (unlikely(!dev)) { + rc = -ENODEV; + goto unlock; + } + if (dev->class != ATA_DEV_ATA) { + rc = -EOPNOTSUPP; + goto unlock; + } + + /* FIXME: Because we can't poweroff EUnit disks separately. + * So we can't let EUnit control wcache flag now */ + if (ap->nr_pmp_links) { + DBGMESG("ata%u: we can't let EUnit control wcache through this path now\n", ap->print_id); + goto unlock; + } + + // update ata_device_blacklist + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); + while (ad->model_num) { + if (glob_match(ad->model_num, model_num)) { + if (ad->model_rev == NULL || glob_match(ad->model_rev, model_rev)) { + if (input) { + ad->horkage &= ~ATA_HORKAGE_NOWCACHE; + } else { + ad->horkage |= ATA_HORKAGE_NOWCACHE; + } + } + } + ad++; + } + + if (!input) { + if (dev->flags & ATA_DFLAG_NO_WCACHE) { + rc = 0; + goto unlock; + } + + dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_WCACHE_DISABLE; + dev->flags |= ATA_DFLAG_NO_WCACHE; + dev->horkage |= ATA_HORKAGE_NOWCACHE; + ata_port_schedule_eh(ap); + } else { + dev->flags &= ~ATA_DFLAG_NO_WCACHE; + dev->horkage &= ~ATA_HORKAGE_NOWCACHE; + } + +unlock: + spin_unlock_irqrestore(ap->lock, flags); + + return rc ? rc : len; +} +DEVICE_ATTR(syno_wcache, S_IRUGO | S_IWUSR, + syno_wcache_show, syno_wcache_store); +EXPORT_SYMBOL_GPL(dev_attr_syno_wcache); +#endif /* MY_ABC_HERE */ diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index ae7189d1a568..36bfd855d4af 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * libata-sff.c - helper library for PCI IDE BMDMA @@ -928,6 +931,26 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) struct ata_port *ap = qc->ap; if (ap->ops->error_handler) { +#ifdef MY_DEF_HERE + if (IS_SYNO_SPINUP_CMD(qc)) { + if (in_wq) { + ata_sff_irq_on(ap); + } + + /* read result TF if requested, copy from ata_qc_complete() and fill_result_tf() */ + if (qc->err_mask || + qc->flags & ATA_QCFLAG_RESULT_TF || + qc->flags & ATA_QCFLAG_FAILED) { + qc->result_tf.flags = qc->tf.flags; + ap->ops->qc_fill_rtf(qc); + } + + __ata_qc_complete(qc); + + return; + } +#endif /* MY_DEF_HERE */ + if (in_wq) { /* EH might have kicked in while host lock is * released. @@ -937,12 +960,28 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) if (likely(!(qc->err_mask & AC_ERR_HSM))) { ata_sff_irq_on(ap); ata_qc_complete(qc); - } else + } +#ifdef MY_ABC_HERE + else if (NULL == qc->scsicmd && !ata_tag_internal(qc->tag)) { + DBGMESG("disk %d:its our insert cmd,don't freeze. cmd 0x%x tag %d feature 0x%x\n", + qc->ap->print_id, qc->tf.command, qc->tag, qc->tf.feature); + __ata_qc_complete(qc); + } +#endif /* MY_ABC_HERE */ + else ata_port_freeze(ap); + } } else { if (likely(!(qc->err_mask & AC_ERR_HSM))) ata_qc_complete(qc); +#ifdef MY_ABC_HERE + else if (NULL == qc->scsicmd && !ata_tag_internal(qc->tag)) { + DBGMESG("disk %d:its our insert cmd,don't freeze. cmd 0x%x tag %d feature 0x%x\n", + qc->ap->print_id, qc->tf.command, qc->tag, qc->tf.feature); + __ata_qc_complete(qc); + } +#endif /* MY_ABC_HERE */ else ata_port_freeze(ap); } @@ -974,6 +1013,15 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, lockdep_assert_held(ap->lock); +#ifdef MY_ABC_HERE + /* if Synology special command timeout, + * it will be flushed (ATA_QCFLAG_ACTIVE = 0). + * But it still in workqueue, so we should be ignore it when called by ata_pio_task + */ + if (syno_qc_filter(qc)) { + goto fsm_start; + } +#endif /* MY_ABC_HERE */ WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); /* Make sure ata_sff_qc_issue() does not throw things @@ -1247,6 +1295,20 @@ void ata_sff_flush_pio_task(struct ata_port *ap) cancel_delayed_work_sync(&ap->sff_pio_task); +#ifdef MY_ABC_HERE + /* + * FIXME: + * The following kernel upstream fix doesn't apply to our kernel + * + * commit ce7514526742c0898b837d4395f515b79dfb5a12 upstream. + * libata: prevent HSM state change race between ISR and PIO + * + * ata_sff_flush_pio_task() is used when sending internal commands. We add + * another path to use internal commands, the commands may come from user + * space and will be preempted by EH, EH also use internal commands. This + * spin_lock_irq may cause deadlock, so we remove it. + */ +#else /* MY_ABC_HERE */ /* * We wanna reset the HSM state to IDLE. If we do so without * grabbing the port lock, critical sections protected by it which @@ -1256,8 +1318,15 @@ void ata_sff_flush_pio_task(struct ata_port *ap) * ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG(). */ spin_lock_irq(ap->lock); +#endif /* MY_ABC_HERE */ + ap->hsm_task_state = HSM_ST_IDLE; + +#ifdef MY_ABC_HERE + /* Please see above FIXME */ +#else /* MY_ABC_HERE */ spin_unlock_irq(ap->lock); +#endif /* MY_ABC_HERE */ ap->sff_pio_task_link = NULL; @@ -1993,6 +2062,12 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes, /* if link is occupied, -ENODEV too is an error */ if (rc && (rc != -ENODEV || sata_scr_valid(link))) { ata_link_err(link, "SRST failed (errno=%d)\n", rc); +#ifdef MY_ABC_HERE + if (-EBUSY == rc) { + ata_link_printk(link, KERN_ERR, "SRST fail, set srst fail flag\n"); + link->uiSflags |= ATA_SYNO_FLAG_SRST_FAIL; + } +#endif /* MY_ABC_HERE */ return rc; } diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index 6a40e3c6cf49..f82e7688773a 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 ioogle, Inc. All rights reserved. @@ -37,7 +40,11 @@ #include "libata.h" #include "libata-transport.h" +#ifdef MY_ABC_HERE +#define ATA_PORT_ATTRS 4 +#else /* MY_ABC_HERE */ #define ATA_PORT_ATTRS 3 +#endif /* MY_ABC_HERE */ #define ATA_LINK_ATTRS 3 #define ATA_DEV_ATTRS 9 @@ -218,6 +225,9 @@ static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL) ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int); ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long); ata_port_simple_attr(local_port_no, port_no, "%u\n", unsigned int); +#ifdef MY_ABC_HERE +ata_port_simple_attr(error_handling, error_handling, "%u\n", unsigned int); +#endif /* MY_ABC_HERE */ static DECLARE_TRANSPORT_CLASS(ata_port_class, "ata_port", NULL, NULL, NULL); @@ -718,6 +728,9 @@ struct scsi_transport_template *ata_attach_transport(void) i->t.eh_strategy_handler = ata_scsi_error; i->t.user_scan = ata_scsi_user_scan; +#ifdef MY_ABC_HERE + i->t.is_eunit_deepsleep = ata_scsi_is_eunit_deepsleep; +#endif /* MY_ABC_HERE */ i->t.host_attrs.ac.attrs = &i->port_attrs[0]; i->t.host_attrs.ac.class = &ata_port_class.class; @@ -738,6 +751,9 @@ struct scsi_transport_template *ata_attach_transport(void) SETUP_PORT_ATTRIBUTE(nr_pmp_links); SETUP_PORT_ATTRIBUTE(idle_irq); SETUP_PORT_ATTRIBUTE(port_no); +#ifdef MY_ABC_HERE + SETUP_PORT_ATTRIBUTE(error_handling); +#endif /* MY_ABC_HERE */ BUG_ON(count > ATA_PORT_ATTRS); i->port_attrs[count] = NULL; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 68cdd81d747c..a126cf861523 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * libata.h - helper library for ATA @@ -15,6 +18,16 @@ #define DRV_NAME "libata" #define DRV_VERSION "3.00" /* must be exactly four chars */ +#ifdef MY_ABC_HERE +struct ata_blacklist_entry { + const char *model_num; + const char *model_rev; + unsigned long horkage; +}; + +extern struct ata_blacklist_entry ata_device_blacklist []; +#endif /* MY_ABC_HERE */ + /* libata-core.c */ enum { /* flags for ata_dev_read_id() */ @@ -141,6 +154,9 @@ extern void ata_scsi_set_sense_information(struct ata_device *dev, const struct ata_taskfile *tf); extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); +#ifdef MY_ABC_HERE +extern void ata_syno_pmp_hotplug(struct work_struct *work); +#endif /* MY_ABC_HERE */ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); @@ -183,6 +199,9 @@ extern int ata_ering_map(struct ata_ering *ering, extern unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key); extern unsigned int atapi_eh_request_sense(struct ata_device *dev, u8 *sense_buf, u8 dfl_sense_key); +#ifdef MY_ABC_HERE +extern void sata_pmp_detach(struct ata_device *dev); +#endif /* MY_ABC_HERE */ /* libata-pmp.c */ #ifdef CONFIG_SATA_PMP @@ -255,4 +274,75 @@ static inline void zpodd_disable_run_wake(struct ata_device *dev) {} static inline void zpodd_post_poweron(struct ata_device *dev) {} #endif /* CONFIG_SATA_ZPODD */ +#ifdef MY_ABC_HERE +int syno_gpio_with_scmd(struct ata_port *ap, struct scsi_device *sdev, SYNO_PM_PKG *pPkg, u8 rw); +int syno_i2c_with_scmd(struct ata_port *ap, struct scsi_device *sdev, SYNO_PM_I2C_PKG *pPkg, u8 rw); +int syno_jmb_575_led_ctl_with_scmd(struct ata_port *ap, struct scsi_device *sdev, u8 *pLedMask, u8 rw); +unsigned int syno_sata_pmp_read_i2c(struct ata_port *ap, SYNO_PM_I2C_PKG *pPM_pkg); +unsigned int syno_sata_pmp_write_i2c(struct ata_port *ap, SYNO_PM_I2C_PKG *pPM_pkg); +unsigned int syno_jmb575_polling_data(struct ata_port *ap, char *buf, unsigned int sectors); +#define SYNO_JMB575_GET_INFO_FEATURE 0xE5 +int syno_pmp_get_ebox_node_by_unique_id(u8 synoUniqueID, u8 isRP, struct device_node **pEBoxNode); +int syno_pmp_i2c_addr_get(struct device_node *pNode, unsigned int *addr); +typedef struct _tag_SYNO_JMB575_I2C_DEV_INFO { + unsigned int addr; + unsigned int offset; + unsigned int mask; +} SYNO_JMB575_I2C_DEV_INFO; +typedef enum __tag_SYNO_JMB575_VENDOR_COMMAND { + SYNO_JMB575_COMMAND_UNKNOWN = 0x00, + SYNO_JMB575_GET_UNIQUE_ID = 0x01, + SYNO_JMB575_GET_EMID = 0x02, + SYNO_JMB575_DISK_LED_MASK = 0x03, + SYNO_JMB575_GET_FW_INFO = 0x04, +} SYNO_JMB575_VENDOR_COMMAND; +int syno_sata_jmb575_custom_cmd(struct ata_port *ap, SYNO_JMB575_VENDOR_COMMAND cmd, int *var); +int syno_sata_jmb575_disk_led_set_with_scmnd(struct ata_link *link, u8 ledIdx, u8 blLightOn); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void syno_smbus_hdd_powerctl_init(void); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +/* + * Event for user space + * + * FIXME: SYNO_SATA_DEEPSLEEP need to depended on SYNO_PORT_MAPPING_V2 + * for just one function "SendDsleepWakeEvent", so add a ugly + * nested config to fix the kconfig dependency. + */ +extern void SendDsleepWakeEvent(struct work_struct *work); +#else /* MY_ABC_HERE */ +static inline void SendDsleepWakeEvent(struct work_struct *work) +{ + return; +} +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct Scsi_Host* ata_scsi_is_eunit_deepsleep(struct Scsi_Host *host); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void SendSataErrEvent(struct work_struct *work); +extern void SendDiskRetryEvent(struct work_struct *work); +extern void SendDiskTimeoutEvent(struct work_struct *work); +extern void SendDiskSoftResetFailEvent(struct work_struct *work); +extern void SendDiskHardResetFailEvent(struct work_struct *work); +extern void SendPortDisEvent(struct work_struct *work); +extern void SendPwrResetEvent(struct work_struct *work); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void SendPortRetryFailedEvent(struct work_struct *work); +extern void SendLinkDownEvent(struct work_struct *work); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void SendDiskPowerShortBreakEvent(struct work_struct *work); +#endif /* MY_ABC_HERE */ + #endif /* __LIBATA_H__ */ diff --git a/drivers/base/bus.c b/drivers/base/bus.c index a9c23ecebc7c..c2cb8936f7e6 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * bus.c - bus driver management @@ -587,6 +590,27 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf, } static DRIVER_ATTR_WO(uevent); +#ifdef MY_ABC_HERE +int syno_all_usb_uas_enabled = 0; +EXPORT_SYMBOL(syno_all_usb_uas_enabled); + +static ssize_t syno_all_usb_uas_enabled_show(struct bus_type *bus, char *buf) +{ + return sprintf(buf, "%d\n", syno_all_usb_uas_enabled); +} + +static ssize_t syno_all_usb_uas_enabled_store(struct bus_type *bus, + const char *buf, size_t count) +{ + if (buf[0] == '0') + syno_all_usb_uas_enabled = 0; + else + syno_all_usb_uas_enabled = 1; + return count; +} +static BUS_ATTR_RW(syno_all_usb_uas_enabled); +#endif /* MY_ABC_HERE */ + /** * bus_add_driver - Add a driver to the bus. * @drv: driver. @@ -857,9 +881,22 @@ int bus_register(struct bus_type *bus) if (retval) goto bus_groups_fail; +#ifdef MY_ABC_HERE + if (!strncmp(bus->name, "usb", 3)) { + retval = bus_create_file(bus, &bus_attr_syno_all_usb_uas_enabled); + if (retval) + goto bus_syno_all_usb_uas_enabled_fail; + } +#endif /* MY_ABC_HERE */ + pr_debug("bus: '%s': registered\n", bus->name); return 0; +#ifdef MY_ABC_HERE +bus_syno_all_usb_uas_enabled_fail: + if (!strncmp(bus->name, "usb", 3)) + bus_remove_file(bus, &bus_attr_syno_all_usb_uas_enabled); +#endif /* MY_ABC_HERE */ bus_groups_fail: remove_probe_files(bus); bus_probe_files_fail: diff --git a/drivers/base/core.c b/drivers/base/core.c index 1157f9aea9c0..e9f2461043b3 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * drivers/base/core.c - core driver model code (device registration, etc) @@ -32,6 +35,12 @@ #include "base.h" #include "power/power.h" +#ifdef MY_ABC_HERE +#include +#include +#include +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_SYSFS_DEPRECATED #ifdef CONFIG_SYSFS_DEPRECATED_V2 long sysfs_deprecated = 1; @@ -1919,6 +1928,14 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, kfree(tmp); } } +#ifdef MY_ABC_HERE + /* host with dev->devt 0, if we want to get hotplug of CABLE_CONNECT/CABLE_DISCONNECT + * we must add DEVNAME in env to pass it to hotplug. + **/ + else { + add_uevent_var(env, "DEVNAME=%s", dev_name(dev)); + } +#endif /* MY_ABC_HERE */ if (dev->type && dev->type->name) add_uevent_var(env, "DEVTYPE=%s", dev->type->name); @@ -1926,6 +1943,37 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->driver) add_uevent_var(env, "DRIVER=%s", dev->driver->name); +#if defined(CONFIG_SYSFS_DEPRECATED) || defined(MY_ABC_HERE) + if (dev->class) { + struct device *parent = dev->parent; + + /* find first bus device in parent chain */ + while (parent && !parent->bus) + parent = parent->parent; + if (parent && parent->bus) { + const char *path; + + path = kobject_get_path(&parent->kobj, GFP_KERNEL); + if (path) { + add_uevent_var(env, "PHYSDEVPATH=%s", path); + kfree(path); + } + + add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); + + if (parent->driver) + add_uevent_var(env, "PHYSDEVDRIVER=%s", + parent->driver->name); + } + } else if (dev->bus) { + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); + + if (dev->driver) + add_uevent_var(env, "PHYSDEVDRIVER=%s", + dev->driver->name); + } +#endif /* CONFIG_SYSFS_DEPRECATED || MY_ABC_HERE */ + /* Add common DT information about the device */ of_device_uevent(dev, env); @@ -4026,6 +4074,108 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) } EXPORT_SYMBOL_GPL(device_change_owner); +#ifdef MY_ABC_HERE +static void syno_turnoff_usb_vbus_gpio(const unsigned vbus_gpio_pin, const unsigned vbus_gpio_polarity) +{ + int gpio_off_value = 0; + + if (UINT_MAX == vbus_gpio_pin || UINT_MAX == vbus_gpio_polarity) { + return; + } + + SYNO_GPIO_WRITE(vbus_gpio_pin, !(gpio_off_value ^ vbus_gpio_polarity)); + msleep(500); + + printk(KERN_INFO "Turned off USB vbus gpio %u (%s)\n", vbus_gpio_pin, + vbus_gpio_polarity ? "ACTIVE_HIGH" : "ACTIVE_LOW"); + + return; +} + +static void syno_turnoff_all_usb_vbus_gpio(void) +{ + int index; + struct device_node *pUSBNode = NULL, *pVbusNode = NULL; + u32 vbusGpioPin = U32_MAX, vbusGpioPolarity = U32_MAX; + + for_each_child_of_node(of_root, pUSBNode) { + // TODO: corrently the index of usb is not well defined, so the index is read but not used. + // get index number of usb_slot, e.g. usb_slot@4 --> 4 + if (pUSBNode->full_name && 1 != sscanf(pUSBNode->full_name, DT_USB_SLOT"@%d", &index)) { + pVbusNode = of_get_child_by_name(pUSBNode, DT_VBUS); + if (NULL == pVbusNode) { + goto USB_PUT_NODE; + } + + if (0 != of_property_read_u32_index(pVbusNode, DT_SYNO_GPIO, SYNO_GPIO_PIN, &vbusGpioPin)) { + printk(KERN_ERR "%s reading vbus vbusGpioPin failed.\n", __func__); + goto USB_PUT_NODE; + } + if (0 != of_property_read_u32_index(pVbusNode, DT_SYNO_GPIO, SYNO_POLARITY_PIN, &vbusGpioPolarity)) { + printk(KERN_ERR "%s reading vbus vbusGpioPolarity failed.\n", __func__); + goto USB_PUT_NODE; + } + + syno_turnoff_usb_vbus_gpio(vbusGpioPin, vbusGpioPolarity); +USB_PUT_NODE: + if (pVbusNode) { + of_node_put(pVbusNode); + } + } + } + + for_each_child_of_node(of_root, pUSBNode) { + // TODO: corrently the index of usb is not well defined, so the index is read but not used. + // get index number of usb_slot, e.g. usb_slot@4 --> 4 + if (pUSBNode->full_name && 1 != sscanf(pUSBNode->full_name, DT_HUB_SLOT"@%d", &index)) { + pVbusNode = of_get_child_by_name(pUSBNode, DT_VBUS); + if (NULL == pVbusNode) { + goto HUB_PUT_NODE; + } + + if (0 != of_property_read_u32_index(pVbusNode, DT_SYNO_GPIO, SYNO_GPIO_PIN, &vbusGpioPin)) { + printk(KERN_ERR "%s reading vbus vbusGpioPin failed.\n", __func__); + goto HUB_PUT_NODE; + } + if (0 != of_property_read_u32_index(pVbusNode, DT_SYNO_GPIO, SYNO_POLARITY_PIN, &vbusGpioPolarity)) { + printk(KERN_ERR "%s reading vbus vbusGpioPolarity failed.\n", __func__); + goto HUB_PUT_NODE; + } + + syno_turnoff_usb_vbus_gpio(vbusGpioPin, vbusGpioPolarity); +HUB_PUT_NODE: + if (pVbusNode) { + of_node_put(pVbusNode); + } + } + } + +#ifdef CONFIG_SYNO_USB_POWER_OFF_TIME + mdelay(CONFIG_SYNO_USB_POWER_OFF_TIME); +#endif /* CONFIG_SYNO_USB_POWER_OFF_TIME */ +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int (*funcSYNOShutdownHook) (void) = NULL; +EXPORT_SYMBOL(funcSYNOShutdownHook); +static void syno_custom_shutdown_prepare(void) +{ + +#ifdef MY_ABC_HERE + if (SYSTEM_POWER_OFF == system_state || SYSTEM_RESTART == system_state) { + syno_turnoff_all_usb_vbus_gpio(); + } +#endif /* MY_ABC_HERE */ + + if(NULL != funcSYNOShutdownHook) { + funcSYNOShutdownHook(); + } + + return; +} +#endif /* MY_ABC_HERE */ + /** * device_shutdown - call ->shutdown() on each device to shutdown. */ @@ -4096,6 +4246,10 @@ void device_shutdown(void) spin_lock(&devices_kset->list_lock); } spin_unlock(&devices_kset->list_lock); + +#ifdef MY_ABC_HERE + syno_custom_shutdown_prepare(); +#endif /* MY_ABC_HERE */ } /* diff --git a/drivers/base/soc.c b/drivers/base/soc.c index d34609bb7386..36455fe9150b 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) ST-Ericsson SA 2011 @@ -21,12 +24,15 @@ static DEFINE_IDA(soc_ida); static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr, char *buf); +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ struct soc_device { struct device dev; struct soc_device_attribute *attr; int soc_dev_num; }; +#endif /* MY_DEF_HERE */ static struct bus_type soc_bus_type = { .name = "soc", }; diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 4e73a531b377..b795646536d4 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -41,6 +41,14 @@ config BT_HCIBTUSB_AUTOSUSPEND This can be overridden by passing btusb.enable_autosuspend=[y|n] on the kernel commandline. +if SYNO_LSP_RTD1619B +config BT_RTKBTRFKILL + tristate "Realtek Bluetooth RFKILL driver" + default n + help + Realtek Bluetooth rfkill driver + +endif # SYNO_LSP_RTD1619B config BT_HCIBTUSB_BCM bool "Broadcom protocol support" depends on BT_HCIBTUSB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 1a58a3ae142c..979e7bb836fb 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -13,6 +13,9 @@ obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_BT_RTKBTRFKILL) += rtk_rfkill.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o obj-$(CONFIG_BT_INTEL) += btintel.o diff --git a/drivers/bluetooth/rtk_rfkill.c b/drivers/bluetooth/rtk_rfkill.c new file mode 100644 index 000000000000..b25b3e48bc7c --- /dev/null +++ b/drivers/bluetooth/rtk_rfkill.c @@ -0,0 +1,242 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#if defined(MY_DEF_HERE) +#include +#else /* MY_DEF_HERE */ +#include +#endif /* MY_DEF_HERE */ +#include +#include +#include +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ +#include +#endif /* MY_DEF_HERE */ +#include +#if defined(MY_DEF_HERE) +#include +#include +#include +#include + +#define LSADC0_PAD0 0x900 +#define ISO_PFUNC21 0x74 +#endif /* MY_DEF_HERE */ + +static struct rfkill *bt_rfk; +static const char bt_name[] = "bluetooth"; +#if defined(MY_DEF_HERE) +static struct gpio_desc *bt_reset; + +static const struct soc_device_attribute rtk_soc_stark[] = { + { + .family = "Realtek Stark", + }, + { + /* empty */ + } +}; +#else /* MY_DEF_HERE */ +static int bt_reset; +#endif /* MY_DEF_HERE */ + +static int bluetooth_set_power(void *data, bool blocked) +{ + pr_info("%s: block=%d\n", __func__, blocked); + +#if defined(MY_DEF_HERE) + if (!blocked) + gpiod_direction_output(bt_reset, 1); + else + gpiod_direction_output(bt_reset, 0); +#else /* MY_DEF_HERE */ + if (!blocked) + gpio_direction_output(bt_reset, 1); + else + gpio_direction_output(bt_reset, 0); +#endif /* MY_DEF_HERE */ + + return 0; +} + +static struct rfkill_ops rfkill_bluetooth_ops = { + .set_block = bluetooth_set_power, +}; + +#if defined(MY_DEF_HERE) +static void rfkill_gpio_init(struct device *dev) +#else /* MY_DEF_HERE */ +static void rfkill_gpio_init(struct device_node *rtk119x_bt_node) +#endif /* MY_DEF_HERE */ +{ + /*initial gpios*/ + /* get gpio number from device tree*/ +#if defined(MY_DEF_HERE) + bt_reset = devm_gpiod_get(dev, "rfkill", + GPIOD_OUT_LOW); + if (IS_ERR(bt_reset)) { + pr_err("[%s ] could not request gpio, %d\n", + __func__, desc_to_gpio(bt_reset)); + } +#else /* MY_DEF_HERE */ + bt_reset = of_get_gpio_flags(rtk119x_bt_node, 0, NULL); + + if (bt_reset < 0) + pr_err("[%s ] could not get gpio from of\n", __func__); + + if (!gpio_is_valid(bt_reset)) /*check whether gpio number is valid*/ + pr_err("[%s ] gpio %d is not valid\n", __func__, bt_reset); + + if (gpio_request(bt_reset, rtk119x_bt_node->name)) /*request gpio*/ + pr_err("[%s ] could not request gpio, %d\n", + __func__, bt_reset); +#endif /* MY_DEF_HERE */ +} + +static void rfkill_gpio_deinit(void) +{ +#if defined(MY_DEF_HERE) + gpiod_put(bt_reset); +#else /* MY_DEF_HERE */ + gpio_free(bt_reset); +#endif /* MY_DEF_HERE */ +} + +static int rfkill_bluetooth_probe(struct platform_device *pdev) +{ + + int rc = 0; + bool default_state = true; +#if defined(MY_DEF_HERE) + struct device *rtk119x_bt_dev; + + rtk119x_bt_dev = &pdev->dev; +#else /* MY_DEF_HERE */ + struct device_node *rtk119x_bt_node; + rtk119x_bt_node = pdev->dev.of_node; +#endif /* MY_DEF_HERE */ + + pr_info("-->%s\n", __func__); + +#if defined(MY_DEF_HERE) + if(soc_device_match(rtk_soc_stark)) { + struct regmap *iso_base; + struct regmap *pad_base; + struct device_node *rtk119x_bt_node = NULL; + u32 iso_tmp=0, pad_tmp=0; + + rtk119x_bt_node = pdev->dev.of_node; + iso_base = syscon_regmap_lookup_by_phandle(rtk119x_bt_node, "realtek,iso"); + pad_base = syscon_regmap_lookup_by_phandle(rtk119x_bt_node, "realtek,pinctrl"); + + if (IS_ERR_OR_NULL(iso_base) || IS_ERR_OR_NULL(pad_base)) { + printk(KERN_ERR "iso_base = NULL or pad_base = NULL !!!\n"); + return -ENOMEM; + } + + regmap_read(iso_base, LSADC0_PAD0, &iso_tmp); + + if((iso_tmp&0xff)>=0x94) { + pad_tmp = BIT(11)|BIT(16)|BIT(21)|BIT(26); + regmap_update_bits_base(pad_base, ISO_PFUNC21, + pad_tmp, pad_tmp, NULL, false, true); + } + else { + pad_tmp = BIT(11)|BIT(16)|BIT(21)|BIT(26); + regmap_update_bits_base(pad_base, ISO_PFUNC21, + pad_tmp, 0, NULL, false, true); + } + } + +#endif /* MY_DEF_HERE */ + bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH, + &rfkill_bluetooth_ops, NULL); + if (!bt_rfk) { + rc = -ENOMEM; + goto err_rfkill_alloc; + } +#if defined(MY_DEF_HERE) + rfkill_gpio_init(rtk119x_bt_dev); +#else /* MY_DEF_HERE */ + rfkill_gpio_init(rtk119x_bt_node); +#endif /* MY_DEF_HERE */ + /* userspace cannot take exclusive control */ + rfkill_init_sw_state(bt_rfk, false); + rc = rfkill_register(bt_rfk); + if (rc) + goto err_rfkill_reg; + + rfkill_set_sw_state(bt_rfk, true); + bluetooth_set_power(NULL, default_state); + + pr_info("<--%s\n", __func__); + return 0; + +err_rfkill_reg: + rfkill_destroy(bt_rfk); +err_rfkill_alloc: + return rc; +} + +static int rfkill_bluetooth_remove(struct platform_device *dev) +{ + pr_info("-->%s\n", __func__); + rfkill_gpio_deinit(); + rfkill_unregister(bt_rfk); + rfkill_destroy(bt_rfk); + pr_info("<--%s\n", __func__); + return 0; +} +static const struct of_device_id rtk119x_bt_ids[] = { + { .compatible = "realtek,rfkill" }, + { /* Sentinel */ }, +}; +static struct platform_driver rfkill_bluetooth_driver = { + .probe = rfkill_bluetooth_probe, + .remove = rfkill_bluetooth_remove, + .driver = { + .name = "rfkill", + .owner = THIS_MODULE, + .of_match_table = rtk119x_bt_ids, + }, +}; + +static int __init rfkill_bluetooth_init(void) +{ + pr_info("-->%s\n", __func__); + return platform_driver_register(&rfkill_bluetooth_driver); +} + +static void __exit rfkill_bluetooth_exit(void) +{ + pr_info("-->%s\n", __func__); + platform_driver_unregister(&rfkill_bluetooth_driver); +} + +late_initcall(rfkill_bluetooth_init); +module_exit(rfkill_bluetooth_exit); +MODULE_DESCRIPTION("bluetooth rfkill"); +MODULE_AUTHOR("rs "); +MODULE_LICENSE("GPL"); + diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 5952210526aa..2425fe9b4614 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -493,6 +493,15 @@ config HW_RANDOM_OPTEE If unsure, say Y. +if SYNO_LSP_RTD1619B +config HW_RANDOM_REALTEK_RTD1319 + tristate "Realtek RTD1319 Random Number Generator support" + depends on ARCH_REALTEK + default y + help + Say Y, if you want to enable random number generator on Realtek platform. + +endif # SYNO_LSP_RTD1619B config HW_RANDOM_NPCM tristate "NPCM Random Number Generator support" depends on ARCH_NPCM || COMPILE_TEST diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 5da344509a4d..7200412cf0cb 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -43,6 +43,9 @@ obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_HW_RANDOM_REALTEK_RTD1319) += rtd1319-rng.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_HW_RANDOM_NPCM) += npcm-rng.o obj-$(CONFIG_HW_RANDOM_CCTRNG) += cctrng.o obj-$(CONFIG_HW_RANDOM_XIPHERA) += xiphera-trng.o diff --git a/drivers/char/hw_random/rtd1319-rng.c b/drivers/char/hw_random/rtd1319-rng.c new file mode 100644 index 000000000000..4aff58e3f76b --- /dev/null +++ b/drivers/char/hw_random/rtd1319-rng.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Realtek RTD1319 RNG driver + * + * Copyright (c) 2015-2020 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_1MS_TO_CNT 1000 + +#define TRNG_REG_BASE 0 + +#define RNG_ANALOG (TRNG_REG_BASE + 0x004) +#define RNG_CALI_CHK (TRNG_REG_BASE + 0x008) +#define RNG_CALI_CTRL (TRNG_REG_BASE + 0x00c) +#define RNG_CALI_RETURN0 (TRNG_REG_BASE + 0x010) +#define RNG_CTRL (TRNG_REG_BASE + 0x000) +#define RNG_DUMMY (TRNG_REG_BASE + 0x034) +#define RNG_LOCK_CHK (TRNG_REG_BASE + 0x014) +#define RNG_RESULTR (TRNG_REG_BASE + 0xc0c) +#define RNG_RETURN6 (TRNG_REG_BASE + 0xc00) +#define RNG_RETURN7 (TRNG_REG_BASE + 0xc04) +#define RNG_RETURN8 (TRNG_REG_BASE + 0xc08) +#define RNG_ST (TRNG_REG_BASE + 0x03c) + +#define RNG_OUT_READY RNG_RETURN6 +#define RNG_RETURN3 RNG_RETURN0 + +static int rtd_rng_read(struct hwrng *rng, void *buf, size_t max, + bool wait) +{ + void __iomem *rng_base = (void __iomem *)rng->priv; + unsigned int tocnt=0; + + while (!(__raw_readl(rng_base + RNG_OUT_READY) & 0x1)) { + if (!wait || tocnt++ > MAX_1MS_TO_CNT){ + pr_err("**************************%s timeout******************** \n", __func__); + return 0; + } + udelay(30); + } + *(u32 *)buf = __raw_readl(rng_base + RNG_RESULTR); + return sizeof(u32); +} + +static int rtd_rng_init(struct hwrng *rng) +{ + void __iomem *rng_base = (void __iomem *)rng->priv; + pr_info("%s %d\n", __func__, __LINE__); + + __raw_writel(0x00008000, rng_base + RNG_CTRL); + __raw_writel(0x010c1041, rng_base + RNG_CALI_CTRL); + __raw_writel(0x24a524a4, rng_base + RNG_CALI_CHK); + __raw_writel(0x300021c0, rng_base + RNG_LOCK_CHK); + __raw_writel(0x00008a91, rng_base + RNG_ANALOG); + + msleep(2); + return 0; +} + +static struct hwrng rtd_rng_ops = { + .name = "rtd", + .init = rtd_rng_init, + .read = rtd_rng_read, + .quality = 1000, +}; + +static int rtd_rng_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + void __iomem *rng_base; + int err; + + /* map peripheral */ + rng_base = of_iomap(np, 0); + if (!rng_base) { + dev_err(dev, "failed to remap rng regs"); + return -ENODEV; + } + rtd_rng_ops.priv = (unsigned long)rng_base; + + /* register driver */ + err = hwrng_register(&rtd_rng_ops); + if (err) { + dev_err(dev, "hwrng registration failed\n"); + iounmap(rng_base); + rtd_rng_ops.priv = (unsigned long)0; + } else + dev_info(dev, "hwrng registered\n"); + + return err; +} + +static int rtd_rng_remove(struct platform_device *pdev) +{ + void __iomem *rng_base = (void __iomem *)rtd_rng_ops.priv; + + /* unregister driver */ + hwrng_unregister(&rtd_rng_ops); + iounmap(rng_base); + + return 0; +} + +#ifdef CONFIG_PM +static int rtd_rng_suspend(struct device *dev) +{ + return 0; +} + +static int rtd_rng_resume(struct device *dev) +{ + if (rtd_rng_ops.priv) + rtd_rng_init(&rtd_rng_ops); + return 0; +} + +static const struct dev_pm_ops rtd_rng_pm_ops = { + .suspend = rtd_rng_suspend, + .resume = rtd_rng_resume, +}; +#endif /* CONFIG_PM */ + +static const struct of_device_id rtd_rng_of_match[] = { + { .compatible = "realtek,rt1319-rng", }, + { .compatible = "realtek,rt16xxb-rng", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtd_rng_of_match); + +static struct platform_driver rtd_rng_driver = { + .driver = { + .name = "rtd1319-rng", + .of_match_table = rtd_rng_of_match, +#ifdef CONFIG_PM + .pm = &rtd_rng_pm_ops, +#endif /* CONFIG_PM */ + }, + .probe = rtd_rng_probe, + .remove = rtd_rng_remove, +}; +module_platform_driver(rtd_rng_driver); + +MODULE_AUTHOR("Cy Huang"); +MODULE_DESCRIPTION("13xx Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/random.c b/drivers/char/random.c index 340ad21491e2..8dccd7a88268 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * random.c -- A strong random number generator * @@ -2100,6 +2103,22 @@ static int proc_do_entropy(struct ctl_table *table, int write, return proc_dointvec(&fake_table, write, buffer, lenp, ppos); } +#ifdef MY_ABC_HERE +int syno_gen_entropy = 0; +static int proc_syno_gen_entropy(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + + if (write && !crng_ready()) { + try_to_generate_entropy(); + } + fake_table.data = &syno_gen_entropy; + fake_table.maxlen = sizeof(syno_gen_entropy); + return proc_dostring(&fake_table, write, buffer, lenp, ppos); +} +#endif /* MY_ABC_HERE */ + static int sysctl_poolsize = INPUT_POOL_WORDS * 32; extern struct ctl_table random_table[]; struct ctl_table random_table[] = { @@ -2162,6 +2181,15 @@ struct ctl_table random_table[] = { .proc_handler = proc_doulongvec_minmax, }, #endif +#ifdef MY_ABC_HERE + { + .procname = "syno_gen_entropy", + .data = &syno_gen_entropy, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_syno_gen_entropy, + }, +#endif /* MY_ABC_HERE */ { } }; #endif /* CONFIG_SYSCTL */ diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c715d4681a0b..db35ee5e7aa1 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -372,6 +372,9 @@ source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" +if SYNO_LSP_RTD1619B +source "drivers/clk/realtek/Kconfig" +endif # SYNO_LSP_RTD1619B source "drivers/clk/renesas/Kconfig" source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf147eb1..2b5fa25e9954 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -100,6 +100,9 @@ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_COMMON_CLK_REALTEK) += realtek/ +endif # CONFIG_SYNO_LSP_RTD1619B obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig new file mode 100644 index 000000000000..99a34fbdc181 --- /dev/null +++ b/drivers/clk/realtek/Kconfig @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: GPL-2.0-only +menuconfig COMMON_CLK_REALTEK + tristate "Clock driver for Realtek" + depends on ARCH_REALTEK || COMPILE_TEST + select RESET_CONTROLLER + select MFD_SYSCON + default y + +if COMMON_CLK_REALTEK + +config CLK_PLL_PSAUD + bool + +config CLK_PLL_DIF + bool + +config COMMON_CLK_RTD1195 + tristate "RTD1195 Clock Controller" + depends on COMMON_CLK_REALTEK + default y + help + Support for the clock controller on RTD1195 + +config COMMON_CLK_RTD1295 + tristate "RTD1295 Clock Controller" + depends on COMMON_CLK_REALTEK + default y + help + Support for the clock controller on RTD1295 + +config COMMON_CLK_RTD1319 + tristate "RTD1319 Clock Controller" + depends on COMMON_CLK_REALTEK + select CLK_PLL_PSAUD + select CLK_PLL_DIF + default y + help + Support for the clock controller on RTD1319 + +config COMMON_CLK_RTD1395 + tristate "RTD1395 Clock Controller" + depends on COMMON_CLK_REALTEK + select CLK_DET + default y + help + Support for the clock controller on RTD1395 + +config COMMON_CLK_RTD1619 + tristate "RTD1619 Clock Controller" + depends on COMMON_CLK_REALTEK + select CLK_PLL_PSAUD + select CLK_PLL_DIF + select CLK_DET + default y + help + Support for the clock controller on RTD1619 + +config COMMON_CLK_RTD1319 + tristate "RTD1319 Clock Controller" + depends on COMMON_CLK_REALTEK + select CLK_PLL_PSAUD + select CLK_PLL_DIF + select CLK_DET + default y + help + Support for the clock controller on RTD1619B + +config COMMON_CLK_RTD1619B + tristate "RTD1619B Clock Controller" + depends on COMMON_CLK_REALTEK + select CLK_PLL_PSAUD + select CLK_PLL_DIF + select CLK_DET + default y + help + Support for the clock controller on RTD1319 + +config COMMON_CLK_REALTEK_TEE + tristate "Clock Driver to Control PLL SCPU over TEE" + depends on TEE + depends on COMMON_CLK_REALTEK + default y + help + PLL BUS/DCSB would be fixed when enable this. + +config CLK_DET + tristate "Clock Detection Support" + depends on COMMON_CLK_REALTEK + default y + help + This enables clock detection support. + +endif diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile new file mode 100644 index 000000000000..354c20e7f02b --- /dev/null +++ b/drivers/clk/realtek/Makefile @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_COMMON_CLK_REALTEK) += clk-rtk.o + +clk-rtk-y += common.o +clk-rtk-y += debugfs.o +clk-rtk-y += of-conf.o +clk-rtk-y += clk-regmap-mux.o +clk-rtk-y += clk-regmap-gate.o +clk-rtk-y += clk-pll.o +clk-rtk-$(CONFIG_CLK_PLL_PSAUD) += clk-pll-psaud.o +clk-rtk-$(CONFIG_CLK_PLL_DIF) += clk-pll-dif.o +clk-rtk-y += reset.o + +obj-$(CONFIG_COMMON_CLK_RTD1195) += clk-rtd1195-cc.o +obj-$(CONFIG_COMMON_CLK_RTD1195) += clk-rtd1195-ic.o +obj-$(CONFIG_COMMON_CLK_RTD1295) += clk-rtd1295-cc.o +obj-$(CONFIG_COMMON_CLK_RTD1295) += clk-rtd1295-ic.o +obj-$(CONFIG_COMMON_CLK_RTD1319) += clk-rtd1319-cc.o +obj-$(CONFIG_COMMON_CLK_RTD1319) += clk-rtd1319-ic.o +obj-$(CONFIG_COMMON_CLK_RTD1395) += clk-rtd1395-cc.o +obj-$(CONFIG_COMMON_CLK_RTD1395) += clk-rtd1395-ic.o +obj-$(CONFIG_COMMON_CLK_RTD1619) += clk-rtd1619-cc.o +obj-$(CONFIG_COMMON_CLK_RTD1619) += clk-rtd1619-ic.o +obj-$(CONFIG_COMMON_CLK_RTD1619B) += clk-rtd1619b-cc.o +obj-$(CONFIG_COMMON_CLK_RTD1619B) += clk-rtd1619b-ic.o +obj-$(CONFIG_COMMON_CLK_REALTEK_TEE) += clk-tee.o +obj-$(CONFIG_CLK_DET) += clk-det.o diff --git a/drivers/clk/realtek/clk-det.c b/drivers/clk/realtek/clk-det.c new file mode 100644 index 000000000000..0838f38aa49b --- /dev/null +++ b/drivers/clk/realtek/clk-det.c @@ -0,0 +1,191 @@ + +#include +#include +#include +#include +#include +#include +#include +#include "clk-det.h" + +struct clk_det_desc { + uint32_t ctrl_rstn_bit; + uint32_t ctrl_cnten_bit; + uint32_t stat_ofs; + uint32_t stat_done_bit; + uint32_t cnt_mask; + uint32_t cnt_shift; +}; + +static const struct clk_det_desc clk_det_descs[2] = { + [CLK_DET_TYPE_CRT] = { + 0, 1, 0, 30, 0x3FFFC000, 13 + }, + [CLK_DET_TYPE_SC_WRAP] = { + 17, 16, 8, 0, 0x0001FFFE, 1 + }, +}; + +static DEFINE_MUTEX(clk_det_lock); + +static unsigned long clk_det_get_freq(struct clk_det *clkd) +{ + struct clk_regmap *clkr = &clkd->clkr; + const struct clk_det_desc *desc = &clk_det_descs[clkd->type]; + uint32_t ctrl_mask; + uint32_t val; + unsigned long freq = 0; + int ret; + + mutex_lock(&clk_det_lock); + + ctrl_mask = BIT(desc->ctrl_rstn_bit) | BIT(desc->ctrl_cnten_bit); + clk_regmap_update(clkr, clkd->ofs, ctrl_mask, 0); + clk_regmap_update(clkr, clkd->ofs, ctrl_mask, BIT(desc->ctrl_rstn_bit)); + clk_regmap_update(clkr, clkd->ofs, ctrl_mask, ctrl_mask); + + ret = regmap_read_poll_timeout(clkr->regmap, clkd->ofs + desc->stat_ofs, val, + val & BIT(desc->stat_done_bit), 0, 100); + if (!ret) { + val = clk_regmap_read(clkr, clkd->ofs + desc->stat_ofs); + freq = ((val & desc->cnt_mask) >> desc->cnt_shift) * 100000; + } + + clk_regmap_update(clkr, clkd->ofs, ctrl_mask, 0); + + mutex_unlock(&clk_det_lock); + + return freq; +} + +static unsigned long clk_det_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clk_det *clkd = to_clk_det(hw); + + if (clkd->ref && !__clk_is_enabled(clkd->ref)) + return 0; + + return clk_det_get_freq(clkd); +} + +const struct clk_ops clk_det_ops = { + .recalc_rate = clk_det_recalc_rate, +}; + +struct clk_det_initdata { + const char *name; + uint32_t ofs; + uint32_t type; + struct clk *ref; +}; + +static int of_clk_det_initdata_parse(struct device_node *np, struct clk_det_initdata *data) +{ + int ret; + + ret = of_property_read_string_index(np, "clock-output-names", 0, &data->name); + if (ret) + return ret; + + ret = of_property_read_u32(np, "clk-det,offset", &data->ofs); + if (ret) + return ret; + + if (of_property_read_u32(np, "clk-det,type", &data->type)) + data->type = 0; + return 0; +} + +static int clk_det_plat_init(struct device *dev, struct rtk_clk_data *ctlr_data, struct clk_det_initdata *data) +{ + struct clk_det *clkd; + struct clk_init_data initdata = { .name = data->name, .ops = &clk_det_ops, .flags = CLK_GET_RATE_NOCACHE}; + struct clk_hw *hws[1]; + + clkd = devm_kzalloc(dev, sizeof(*clkd), GFP_KERNEL); + if (!clkd) + return -ENOMEM; + + clkd->clkr.hw.init = &initdata; + clkd->ofs = data->ofs; + clkd->type = data->type; + clkd->ref = data->ref; + hws[0] = &clkd->clkr.hw; + + return rtk_clk_add_hws(dev, ctlr_data, hws, 1); +} + +static struct regmap *of_clk_det_syscon_get(struct device_node *np) +{ + struct device_node *parent; + struct regmap *regmap; + + if (of_find_property(np, "syscon", NULL)) + return syscon_regmap_lookup_by_phandle(np, "syscon"); + + parent = of_get_parent(np); + regmap = syscon_node_to_regmap(parent); + of_node_put(parent); + + return regmap; +} + +static int clk_det_plat_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *ctlr_data; + struct clk_det_initdata clk_det_initdata; + int ret; + + ctlr_data = rtk_clk_alloc_data(1); + if (!ctlr_data) + return -ENOMEM; + + ctlr_data->regmap = of_clk_det_syscon_get(np); + if (IS_ERR(ctlr_data->regmap)) { + ret = PTR_ERR(ctlr_data->regmap); + dev_err(dev, "failed to get regmap: %d\n", ret); + goto free_data; + } + + clk_det_initdata.ref = clk_get(dev, 0); + if (IS_ERR(clk_det_initdata.ref)) + clk_det_initdata.ref = NULL; + + ret = of_clk_det_initdata_parse(np, &clk_det_initdata); + if (ret){ + dev_err(dev, "failed to parse initdata: %d\n", ret); + goto free_data; + } + + ret = clk_det_plat_init(dev, ctlr_data, &clk_det_initdata); + if (ret) { + dev_err(dev, "failed to create clk_det: %d\n", ret); + goto free_data; + } + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ctlr_data->clk_data); + if (ret) + dev_warn(dev, "failed to add clk provider: %d\n", ret); + return 0; + +free_data: + rtk_clk_free_data(ctlr_data); + return ret; +} + +static const struct of_device_id clk_det_match[] = { + { .compatible = "realtek,clk-det", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, clk_det_match); + +static struct platform_driver clk_det_driver = { + .probe = clk_det_plat_probe, + .driver = { + .name = "rtk-clk-det", + .of_match_table = of_match_ptr(clk_det_match), + }, +}; +module_platform_driver(clk_det_driver); diff --git a/drivers/clk/realtek/clk-det.h b/drivers/clk/realtek/clk-det.h new file mode 100644 index 000000000000..975fd5906552 --- /dev/null +++ b/drivers/clk/realtek/clk-det.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __CLK_REALTEK_CLK_DET_H +#define __CLK_REALTEK_CLK_DET_H + +#include +#include "common.h" + +struct clk_det { + struct clk_regmap clkr; + int ofs; + int type; + struct clk *ref; +}; + +#define to_clk_det(_hw) container_of(to_clk_regmap(_hw), struct clk_det, clkr) +#define __clk_det_hw(_ptr) __clk_regmap_hw(&(_ptr)->clkr) + +#define CLK_DET_TYPE_CRT 0 +#define CLK_DET_TYPE_SC_WRAP 1 + +extern const struct clk_ops clk_det_ops; + +static inline int is_clk_det_ops(const struct clk_ops *ops) +{ + return ops == &clk_det_ops; +} + +#endif diff --git a/drivers/clk/realtek/clk-pll-dif.c b/drivers/clk/realtek/clk-pll-dif.c new file mode 100644 index 000000000000..ce438a0b6a58 --- /dev/null +++ b/drivers/clk/realtek/clk-pll-dif.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" + +static int clk_pll_dif_enable(struct clk_hw *hw) +{ + struct clk_pll_dif *pll = to_clk_pll_dif(hw); + + pr_debug("%pC: %s\n", hw->clk, __func__); + + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x0C, pll->adtv_conf[0]); + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x08, pll->adtv_conf[1]); + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x04, pll->adtv_conf[2]); + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x00, pll->adtv_conf[3]); + udelay(100); + + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x08, pll->adtv_conf[4]); + udelay(50); + + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x08, pll->adtv_conf[5]); + udelay(200); + + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x0C, pll->adtv_conf[6]); + udelay(100); + + clk_regmap_write(&pll->clkr, pll->pll_ofs + 0x04, pll->adtv_conf[7]); + + /* ssc control */ + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x00, 0x00000004); + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x04, 0x00006800); + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x0C, 0x00000000); + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x10, 0x00000000); + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x08, 0x001e1f98); + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x00, 0x00000005); + pll->status = 1; + + return 0; +} + +static void clk_pll_dif_disable(struct clk_hw *hw) +{ + struct clk_pll_dif *pll = to_clk_pll_dif(hw); + + pr_debug("%pC: %s\n", hw->clk, __func__); + clk_regmap_update(&pll->clkr, pll->pll_ofs + 0x04, 0x00080000, 0x0); + clk_regmap_update(&pll->clkr, pll->pll_ofs + 0x08, 0x00400C03, 0x0); + clk_regmap_update(&pll->clkr, pll->pll_ofs + 0x0C, 0x00000038, 0x0); + + clk_regmap_write(&pll->clkr, pll->ssc_ofs + 0x00, 0x00000004); + pll->status = 0; +} + +static int clk_pll_dif_is_enabled(struct clk_hw *hw) +{ + struct clk_pll_dif *pll = to_clk_pll_dif(hw); + + return pll->status; +} + +static void clk_pll_dif_disable_unused(struct clk_hw *hw) +{ + pr_info("%pC: %s\n", hw->clk, __func__); + clk_pll_dif_disable(hw); +} + +const struct clk_ops clk_pll_dif_ops = { + .enable = clk_pll_dif_enable, + .disable = clk_pll_dif_disable, + .disable_unused = clk_pll_dif_disable_unused, + .is_enabled = clk_pll_dif_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_pll_dif_ops); diff --git a/drivers/clk/realtek/clk-pll-psaud.c b/drivers/clk/realtek/clk-pll-psaud.c new file mode 100644 index 000000000000..d962c62a9d91 --- /dev/null +++ b/drivers/clk/realtek/clk-pll-psaud.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * clk-pll-psaud.c - PLL_PSAUDXA + * + * Copyright (c) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include "common.h" +#include "clk-pll.h" + +static int clk_pll_psaud_enable(struct clk_hw *hw) +{ + struct clk_pll_psaud *pll = to_clk_pll_psaud(hw); + u32 mask = 0, val = 0; + + if (pll->id == CLK_PLL_PSAUD1A) { + mask = 0x3; + val = 0x1; + } else { + mask = 0xc; + val = 0x4; + } + clk_regmap_update(&pll->clkr, pll->reg + 4, mask, val); + return 0; +} + +static void clk_pll_psaud_disable(struct clk_hw *hw) +{ + struct clk_pll_psaud *pll = to_clk_pll_psaud(hw); + u32 mask = 0, val = 0; + + if (pll->id == CLK_PLL_PSAUD1A) { + mask = 0x3; + val = 0x3; + } else { + mask = 0xc; + val = 0xc; + } + clk_regmap_update(&pll->clkr, pll->reg + 4, mask, val); +} + +static void clk_pll_psaud_disable_unused(struct clk_hw *hw) +{ + pr_info("%pC: %s\n", hw->clk, __func__); + clk_pll_psaud_disable(hw); +} + +static int clk_pll_psaud_is_enabled(struct clk_hw *hw) +{ + struct clk_pll_psaud *pll = to_clk_pll_psaud(hw); + u32 val; + + val = clk_regmap_read(&pll->clkr, pll->reg + 4); + if (pll->id == CLK_PLL_PSAUD1A) + val &= 0x3; + else + val >>= 2; + return val == 0x1; +} + +static long clk_pll_psaud_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + if (45158400 == rate) + return rate; + return 49192000; +} + +static int clk_pll_psaud_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pll_psaud *pll = to_clk_pll_psaud(hw); + u32 rsel = 0; + u32 mask = 0, val = 0; + + if (WARN_ON_ONCE(rate != 45158400 && rate != 49192000)) + return -EINVAL; + + if (rate == 45158400) + rsel = 1; + if (pll->id == CLK_PLL_PSAUD1A) { + val = 0x6a0 | (rsel << 8); + mask = 0x7e0; + } else { + val = 0x19 | (rsel << 2); + mask = 0x1f; + } + clk_regmap_update(&pll->clkr, pll->reg, mask, val); + return 0; +} + +static unsigned long clk_pll_psaud_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll_psaud *pll = to_clk_pll_psaud(hw); + u32 val; + u32 rsel = 0; + + val = clk_regmap_read(&pll->clkr, pll->reg); + + if (pll->id == CLK_PLL_PSAUD1A) + rsel = !!(val & BIT(8)); + else + rsel = !!(val & BIT(2)); + + return rsel ? 45158400 : 49192000; +} + +const struct clk_ops clk_pll_psaud_ops = { + .debug_init = set_clk_rate_debugfs_init, + .enable = clk_pll_psaud_enable, + .disable = clk_pll_psaud_disable, + .disable_unused = clk_pll_psaud_disable_unused, + .is_enabled = clk_pll_psaud_is_enabled, + .set_rate = clk_pll_psaud_set_rate, + .round_rate = clk_pll_psaud_round_rate, + .recalc_rate = clk_pll_psaud_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_pll_psaud_ops); diff --git a/drivers/clk/realtek/clk-pll.c b/drivers/clk/realtek/clk-pll.c new file mode 100644 index 000000000000..7929f79728c7 --- /dev/null +++ b/drivers/clk/realtek/clk-pll.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017-2018 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" + +static const struct freq_table *ftbl_find_by_rate(const struct freq_table *ftbl, + unsigned long rate) +{ + unsigned long best_rate = 0; + const struct freq_table *best = NULL; + + for ( ; !IS_FREQ_TABLE_END(ftbl); ftbl++) { + if (ftbl->rate == rate) + return ftbl; + + if (ftbl->rate > rate) + continue; + + if ((rate - best_rate) > (rate - ftbl->rate)) { + best_rate = ftbl->rate; + best = ftbl; + } + } + + return best; +} + +static const struct freq_table *ftbl_find_by_val_with_mask(const struct freq_table *ftbl, + uint32_t mask, uint32_t value) +{ + while (!IS_FREQ_TABLE_END(ftbl)) { + if ((ftbl->val & mask) == (value & mask)) + return ftbl; + ftbl++; + } + return NULL; +}; + +static const struct div_table *dtbl_find_by_rate(const struct div_table *dtbl, + unsigned long rate) +{ + while (!IS_DIV_TABLE_END(dtbl)) { + if (rate >= dtbl->rate) + return dtbl; + dtbl++; + } + return NULL; +} + +static const struct div_table *dtbl_find_by_val(const struct div_table *dtbl, + uint32_t val) +{ + while (!IS_DIV_TABLE_END(dtbl)) { + if (val == dtbl->val) + return dtbl; + dtbl++; + } + return NULL; +} + +static inline int __clk_pll_set_oc_en(struct clk_pll *clkp) +{ + uint32_t val; + uint32_t pollval; + + val = clk_regmap_read(&clkp->clkr, clkp->ssc_ofs + 0x0); + if (val == 0x5) + return 0; + clk_regmap_update(&clkp->clkr, clkp->ssc_ofs + 0x0, 0x7, 0x5); + + return regmap_read_poll_timeout(clkp->clkr.regmap, clkp->ssc_ofs + 0x1c, + pollval, pollval & BIT(20), 0, 2000); +} + +static inline int __clk_pll_set_pow_on_common(struct clk_pll *clkp) +{ + struct clk_regmap *clkr = &clkp->clkr; + uint32_t pow = clk_pll_get_pow_offset(clkp); + + if (clkp->pow_set_rs) + clk_regmap_update(clkr, clkp->pll_ofs, clkp->rs_mask, clkp->rs_val); + + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x5); + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x7); + udelay(200); + + if (clkp->pow_set_pi_bps) + clk_regmap_update(clkr, clkp->pll_ofs, 0x10, 0); + + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x3); + + return clkp->pll_type == CLK_PLL_TYPE_NF_SSC ? __clk_pll_set_oc_en(clkp) : 0; +} + +static inline int __clk_pll_set_pow_on_mno_v2(struct clk_pll *clkp) +{ + struct clk_regmap *clkr = &clkp->clkr; + uint32_t pow = clk_pll_get_pow_offset(clkp); + uint32_t val = 0, mask = 0; + + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x5); + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x7); + + if (clkp->pow_set_rs) { + val |= clkp->rs_val; + mask |= clkp->rs_mask; + } + + if (clkp->freq_val) { + val |= clkp->freq_val; + mask |= clk_pll_get_freq_mask(clkp); + } + + if (mask) + clk_regmap_update(clkr, clkp->pll_ofs, mask, val); + udelay(200); + + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x3); + + return 0; +} + +static inline int __clk_pll_set_pow_on(struct clk_pll *clkp) +{ + if (clkp->pll_type == CLK_PLL_TYPE_MNO_V2) + return __clk_pll_set_pow_on_mno_v2(clkp); + + return __clk_pll_set_pow_on_common(clkp); +} + +static inline int __clk_pll_set_pow_off(struct clk_pll *clkp) +{ + struct clk_regmap *clkr = &clkp->clkr; + uint32_t pow = clk_pll_get_pow_offset(clkp); + + clk_regmap_update(clkr, clkp->pll_ofs + pow, 0x7, 0x4); + if (clkp->pll_type != CLK_PLL_TYPE_NF_SSC) + return 0; + + if (clkp->pow_set_pi_bps) + clk_regmap_update(clkr, clkp->pll_ofs, 0x10, 0x10); + return 0; +} + +static inline int __clk_pll_get_pow(struct clk_pll *clkp) +{ + uint32_t pow = clk_pll_get_pow_offset(clkp); + uint32_t val; + + if (!clk_pll_has_pow(clkp)) + return -EINVAL; + + pow = clk_pll_get_pow_offset(clkp); + val = clk_regmap_read(&clkp->clkr, clkp->pll_ofs + pow); + return !!(val & 0x1); +} + +static uint32_t __clk_pll_freq_raw_get(struct clk_pll *clkp) +{ + uint32_t val = 0; + + switch (clkp->pll_type) { + case CLK_PLL_TYPE_MNO_V2: + if (clkp->freq_val) { + val = clkp->freq_val; + break; + } + fallthrough; + case CLK_PLL_TYPE_MNO: + val = clk_regmap_read(&clkp->clkr, clkp->pll_ofs + 0x0); + break; + + case CLK_PLL_TYPE_NF: + val = clk_regmap_read(&clkp->clkr, clkp->pll_ofs + 0x4); + break; + + case CLK_PLL_TYPE_NF_SSC: + val = clk_regmap_read(&clkp->clkr, clkp->ssc_ofs + 0x4); + break; + + default: + break; + } + return val; +} + +static inline int __clk_pll_freq_set(struct clk_pll *clkp, uint32_t val) +{ + int ret = 0; + uint32_t mask = clk_pll_get_freq_mask(clkp); + + switch (clkp->pll_type) { + case CLK_PLL_TYPE_MNO: + clk_regmap_update(&clkp->clkr, clkp->pll_ofs, mask, val); + break; + + case CLK_PLL_TYPE_MNO_V2: + clkp->freq_val = val; + break; + + case CLK_PLL_TYPE_NF: + clk_regmap_update(&clkp->clkr, clkp->pll_ofs + 0x4, mask, val); + if (__clk_pll_get_pow(clkp) > 0) { + __clk_pll_set_pow_off(clkp); + __clk_pll_set_pow_on(clkp); + } + break; + + case CLK_PLL_TYPE_NF_SSC: + clk_regmap_update(&clkp->clkr, clkp->ssc_ofs + 0x0, 0x7, 0x4); + clk_regmap_update(&clkp->clkr, clkp->ssc_ofs + 0x4, mask, val); + + if (__clk_pll_get_pow(clkp) == 0) + break; + + ret = __clk_pll_set_oc_en(clkp); + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +static inline int __clk_pll_get_plldiv(struct clk_pll *clkp) +{ + uint32_t val; + + if (clkp->pll_type != CLK_PLL_TYPE_NF_SSC) + return 1; + + if (!CLK_OFS_IS_VALID(clkp->pll_ofs)) + return 1; + + val = (clk_regmap_read(&clkp->clkr, clkp->pll_ofs) >> 22) & 0x7; + return val + 1; +} + +static int clk_pll_enable(struct clk_hw *hw) +{ + struct clk_pll *clkp = to_clk_pll(hw); + int ret = 0; + + if (clk_pll_has_pow(clkp)) + ret = __clk_pll_set_pow_on(clkp); + if (ret) + pr_warn("%pC: error in %s: %d\n", hw->clk, __func__, ret); + return 0; +} + +static void clk_pll_disable(struct clk_hw *hw) +{ + struct clk_pll *clkp = to_clk_pll(hw); + int ret = 0; + + if (clk_pll_has_pow(clkp)) + ret = __clk_pll_set_pow_off(clkp); + if (ret) + pr_warn("%pC: error in %s: %d\n", hw->clk, __func__, ret); +} + +static void clk_pll_disable_unused(struct clk_hw *hw) +{ + pr_info("%pC: %s\n", hw->clk, __func__); + clk_pll_disable(hw); +} + +static int clk_pll_is_enabled(struct clk_hw *hw) +{ + struct clk_pll *clkp = to_clk_pll(hw); + + return __clk_pll_get_pow(clkp); +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_pll *clkp = to_clk_pll(hw); + const struct freq_table *ftblv = NULL; + int plldiv = __clk_pll_get_plldiv(clkp); + + ftblv = ftbl_find_by_rate(clkp->freq_tbl, rate * plldiv); + return ftblv ? ftblv->rate / plldiv: 0; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll *clkp = to_clk_pll(hw); + unsigned long flags = 0; + const struct freq_table *fv; + uint32_t raw; + int plldiv = __clk_pll_get_plldiv(clkp); + + flags = clk_pll_lock(clkp); + raw = __clk_pll_freq_raw_get(clkp); + clk_pll_unlock(clkp, flags); + + fv = ftbl_find_by_val_with_mask(clkp->freq_tbl, clkp->freq_mask, raw); + return fv ? fv->rate / plldiv : 0; +} + +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pll *clkp = to_clk_pll(hw); + unsigned long flags = 0; + const struct freq_table *fv; + int ret = 0; + int plldiv = __clk_pll_get_plldiv(clkp); + + fv = ftbl_find_by_rate(clkp->freq_tbl, rate * plldiv); + if (!fv) + return -EINVAL; + + pr_debug("%pC: %s: tbl_rate=%ld, reg_val=0x%08x, plldiv=%d, target_rate=%ld\n", hw->clk, __func__, + fv->rate, fv->val, plldiv, rate); + + flags = clk_pll_lock(clkp); + ret = __clk_pll_freq_set(clkp, fv->val); + clk_pll_unlock(clkp, flags); + if (ret) + pr_warn("%pC %s: failed to set freq: %d\n", hw->clk, __func__, ret); + return 0; +} + +static void __clk_pll_div_set(struct clk_pll_div *clkpd, uint32_t val) +{ + uint32_t m = (BIT(clkpd->div_width) - 1) << clkpd->div_shift; + uint32_t s = clkpd->div_shift; + + clk_regmap_update(&clkpd->clkp.clkr, clkpd->div_ofs, m, val << s); +} + +static uint32_t __clk_pll_div_get(struct clk_pll_div *clkpd) +{ + uint32_t m = (BIT(clkpd->div_width) - 1) << clkpd->div_shift; + uint32_t s = clkpd->div_shift; + + return (clk_regmap_read(&clkpd->clkp.clkr, clkpd->div_ofs) & m) >> s; +} + +static long clk_pll_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_pll_div *clkpd = to_clk_pll_div(hw); + const struct div_table *dv; + + /* lookup div in dtbl */ + dv = dtbl_find_by_rate(clkpd->div_tbl, rate); + if (!dv) + return 0; + + rate *= dv->div; + rate = clk_pll_round_rate(hw, rate, parent_rate); + return rate / dv->div; +} + +static unsigned long clk_pll_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll_div *clkpd = to_clk_pll_div(hw); + unsigned long rate; + const struct div_table *dv; + uint32_t val; + + rate = clk_pll_recalc_rate(hw, parent_rate); + + val = __clk_pll_div_get(clkpd); + dv = dtbl_find_by_val(clkpd->div_tbl, val); + if (!dv) + return 0; + + rate /= dv->div; + pr_debug("%pC: %s: current rate=%lu, div=%d, reg_val=0x%x\n", + hw->clk, __func__, rate, dv->div, val); + + return rate; +} + +static int clk_pll_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk *clk = hw->clk; + struct clk_pll_div *clkpd = to_clk_pll_div(hw); + unsigned long flags; + const struct div_table *ndv, *cdv; + unsigned long target; + uint32_t cur_d; + int ret; + + /* find next in the dtbl */ + ndv = dtbl_find_by_rate(clkpd->div_tbl, rate); + if (!ndv) + return -EINVAL; + + target = rate * ndv->div; + + /* find current in the dtbl */ + cur_d = __clk_pll_div_get(clkpd); + cdv = dtbl_find_by_val(clkpd->div_tbl, cur_d); + if (!cdv) + return -EINVAL; + + pr_debug("%pC: rate=%lu, cdv={%d,0x%x}, ndv={%d,0x%x}\n", + clk, rate, cdv->div, cdv->val, ndv->div, ndv->val); + + flags = clk_pll_div_lock(clkpd); + + /* workaround to prevent glitch */ +#ifdef CONFIG_COMMON_CLK_RTD129X + if ((&clkpd->clkp.flags & CLK_PLL_DIV_WORKAROUND) && + ndv->val != cdv->val && (ndv->val == 1 || cdv->val == 1)) { + + pr_debug("%pC: apply rate=%u\n", clk, 1000000000); + clk_pll_set_rate(hw, 1000000000, parent_rate); + + pr_debug("%pC: apply dv={%d, 0x%x}\n", clk, ndv->div, ndv->val); + __clk_pll_div_set(clkpd, ndv->val); + cdv = ndv; + } +#endif + + if (ndv->div > cdv->div) + __clk_pll_div_set(clkpd, ndv->val); + ret = clk_pll_set_rate(hw, target, parent_rate); + if (ndv->div < cdv->div) + __clk_pll_div_set(clkpd, ndv->val); + + clk_pll_div_unlock(clkpd, flags); + + return ret; +} + +static int clk_pll_raw_freq_u64_get(void *data, u64 *val) +{ + struct clk_pll *clkp = to_clk_pll(data); + + *val = __clk_pll_freq_raw_get(clkp); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clk_pll_raw_freq_ops, clk_pll_raw_freq_u64_get, NULL, "%08llx\n"); + +static void clk_pll_debugfs_init(struct clk_hw *hw, struct dentry *d) +{ + set_clk_rate_debugfs_init(hw, d); + debugfs_create_file("freq_raw", 0444, d, hw, &clk_pll_raw_freq_ops); +} + +const struct clk_ops clk_pll_ops = { + .debug_init = clk_pll_debugfs_init, + .round_rate = clk_pll_round_rate, + .recalc_rate = clk_pll_recalc_rate, + .set_rate = clk_pll_set_rate, + .enable = clk_pll_enable, + .disable = clk_pll_disable, + .disable_unused = clk_pll_disable_unused, + .is_enabled = clk_pll_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_pll_ops); + +const struct clk_ops clk_pll_div_ops = { + .debug_init = clk_pll_debugfs_init, + .round_rate = clk_pll_div_round_rate, + .recalc_rate = clk_pll_div_recalc_rate, + .set_rate = clk_pll_div_set_rate, + .enable = clk_pll_enable, + .disable = clk_pll_disable, + .disable_unused = clk_pll_disable_unused, + .is_enabled = clk_pll_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_pll_div_ops); diff --git a/drivers/clk/realtek/clk-pll.h b/drivers/clk/realtek/clk-pll.h new file mode 100644 index 000000000000..99196566b4b2 --- /dev/null +++ b/drivers/clk/realtek/clk-pll.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __CLK_REALTEK_CLK_PLL_H +#define __CLK_REALTEK_CLK_PLL_H + +#include "common.h" + +struct freq_table { + uint32_t val; + unsigned long rate; +}; + +#define FREQ_TABLE_END { .rate = 0 } +#define IS_FREQ_TABLE_END(_f) ((_f)->rate == 0) + +struct div_table { + unsigned long rate; + uint32_t div; + uint32_t val; +}; + +#define DIV_TABLE_END { .rate = 0 } +#define IS_DIV_TABLE_END(_d) ((_d)->rate == 0) + +struct clk_pll { + struct clk_regmap clkr; + uint32_t pll_type; +#define CLK_PLL_TYPE_MNO 1 +#define CLK_PLL_TYPE_NF 2 +#define CLK_PLL_TYPE_NF_SSC 3 +#define CLK_PLL_TYPE_MNO_V2 4 + + int pll_ofs; + int ssc_ofs; + + const struct freq_table *freq_tbl; + uint32_t freq_mask; + uint32_t freq_mask_set; + uint32_t freq_val; + + uint32_t pow_loc; +#define CLK_PLL_CONF_NO_POW 0 +#define CLK_PLL_CONF_POW_LOC_CTL2 1 +#define CLK_PLL_CONF_POW_LOC_CTL3 2 + uint32_t pow_set_rs; + uint32_t pow_set_pi_bps; + uint32_t rs_mask; + uint32_t rs_val; + + spinlock_t *lock; + + uint32_t flags; +}; + +#define CLK_PLL_CONF_RS(_m, _v) \ + .pow_set_rs = 1, \ + .rs_mask = (_m), \ + .rs_val = (_v) + +#define CLK_PLL_CONF_PI_BPS() \ + .pow_set_pi_bps = 1 + +#define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr) +#define __clk_pll_hw(_ptr) __clk_regmap_hw(&(_ptr)->clkr) + +/* clk_pll flags */ +#define CLK_PLL_DIV_WORKAROUND BIT(2) + +static inline uint32_t clk_pll_get_pow_offset(struct clk_pll *clkp) +{ + return (clkp->pow_loc == CLK_PLL_CONF_POW_LOC_CTL3) ? 0x8 : 0x4; +} + +static inline uint32_t clk_pll_get_freq_mask(struct clk_pll *clkp) +{ + return clkp->freq_mask_set ?: clkp->freq_mask; +} + +static inline bool clk_pll_has_pow(struct clk_pll *pll) +{ + if (pll->pow_loc != CLK_PLL_CONF_NO_POW) + return true; + return false; +} + +static inline unsigned long clk_pll_lock(struct clk_pll *pll) +{ + unsigned long flags = 0; + + if (pll->lock) + spin_lock_irqsave(pll->lock, flags); + return flags; +} + +static inline void clk_pll_unlock(struct clk_pll *pll, unsigned long flags) +{ + if (pll->lock) + spin_unlock_irqrestore(pll->lock, flags); +} + +struct clk_pll_div { + struct clk_pll clkp; + int div_ofs; + int div_shift; + int div_width; + const struct div_table *div_tbl; + spinlock_t *lock; +}; + +#define to_clk_pll_div(_hw) \ + container_of(to_clk_pll(_hw), struct clk_pll_div, clkp) +#define __clk_pll_div_hw(_ptr) __clk_pll_hw(&(_ptr)->clkp) + +/* clk_pll_div helper functions */ +static inline unsigned long clk_pll_div_lock(struct clk_pll_div *plld) +{ + unsigned long flags = 0; + + if (plld->lock) + spin_lock_irqsave(plld->lock, flags); + return flags; +} + +static inline void clk_pll_div_unlock(struct clk_pll_div *plld, + unsigned long flags) +{ + if (plld->lock) + spin_unlock_irqrestore(plld->lock, flags); +} + +extern const struct clk_ops clk_pll_ops; +extern const struct clk_ops clk_pll_div_ops; + +#ifdef CONFIG_CLK_PLL_PSAUD + +struct clk_pll_psaud { + struct clk_regmap clkr; + int id; + int reg; + spinlock_t *lock; +}; + +#define to_clk_pll_psaud(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_pll_psaud, clkr) +#define __clk_pll_psaud_hw(_ptr) __clk_regmap_hw(&(_ptr)->clkr) +extern const struct clk_ops clk_pll_psaud_ops; + +#define CLK_PLL_PSAUD1A (0x1) +#define CLK_PLL_PSAUD2A (0x2) + +#endif /* CONFIG_CLK_PLL_PSAUD */ + +#ifdef CONFIG_CLK_PLL_DIF + +struct clk_pll_dif { + struct clk_regmap clkr; + int pll_ofs; + int ssc_ofs; + uint32_t status; + spinlock_t *lock; + uint32_t adtv_conf[8]; +}; +#define to_clk_pll_dif(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_pll_dif, clkr) +#define __clk_pll_dif_hw(_ptr) __clk_regmap_hw(&(_ptr)->clkr) + +extern const struct clk_ops clk_pll_dif_ops; +#endif /* CONFIG_CLK_PLL_DIF */ + +static inline int is_clk_pll_ops(const struct clk_ops *ops) +{ + if (ops == &clk_pll_ops || ops == &clk_pll_div_ops) + return 1; + +#ifdef CONFIG_CLK_PLL_PSAUD + if (ops == &clk_pll_psaud_ops) + return 1; +#endif + +#ifdef CONFIG_CLK_PLL_DIF + if (ops == &clk_pll_dif_ops) + return 1; +#endif + + return 0; +} + +#endif /* __CLK_REALTEK_CLK_PLL_H */ diff --git a/drivers/clk/realtek/clk-regmap-gate.c b/drivers/clk/realtek/clk-regmap-gate.c new file mode 100644 index 000000000000..cbdc85795d35 --- /dev/null +++ b/drivers/clk/realtek/clk-regmap-gate.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include "clk-regmap-gate.h" + +static int clk_regmap_gate_enable(struct clk_hw *hw) +{ + struct clk_regmap_gate *clkg = to_clk_regmap_gate(hw); + unsigned long flags = 0; + unsigned int mask; + unsigned int val; + + pr_debug("%pC: clk enable\n", hw->clk); + + if (clkg->lock) + spin_lock_irqsave(clkg->lock, flags); + + mask = BIT(clkg->bit_idx); + val = BIT(clkg->bit_idx); + + if (clkg->write_en) { + mask |= BIT(clkg->bit_idx + 1); + val |= BIT(clkg->bit_idx + 1); + } + + trace_rtk_pm_reg_update_bits("clk_en", clkg->gate_ofs, mask, val); + + clk_regmap_update(&clkg->clkr, clkg->gate_ofs, mask, val); + + if (clkg->lock) + spin_unlock_irqrestore(clkg->lock, flags); + + return 0; +} + +static void clk_regmap_gate_disable(struct clk_hw *hw) +{ + struct clk_regmap_gate *clkg = to_clk_regmap_gate(hw); + unsigned long flags = 0; + unsigned int mask; + unsigned int val; + + pr_debug("%pC: clk disable\n", hw->clk); + + if (clkg->lock) + spin_lock_irqsave(clkg->lock, flags); + + mask = BIT(clkg->bit_idx); + val = 0; + + if (clkg->write_en) { + mask |= BIT(clkg->bit_idx + 1); + val |= BIT(clkg->bit_idx + 1); + } + + trace_rtk_pm_reg_update_bits("clk_en", clkg->gate_ofs, mask, val); + + clk_regmap_update(&clkg->clkr, clkg->gate_ofs, mask, val); + + if (clkg->lock) + spin_unlock_irqrestore(clkg->lock, flags); +} + +static void clk_regmap_gate_disable_unused(struct clk_hw *hw) +{ + pr_info("%pC: %s\n", hw->clk, __func__); + clk_regmap_gate_disable(hw); +} + +static int clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap_gate *clkg = to_clk_regmap_gate(hw); + int ret; + unsigned long flags = 0; + + if (clkg->lock) + spin_lock_irqsave(clkg->lock, flags); + + ret = clk_regmap_read(&clkg->clkr, clkg->gate_ofs) & BIT(clkg->bit_idx); + + if (clkg->lock) + spin_unlock_irqrestore(clkg->lock, flags); + + return !!ret; +} + +const struct clk_ops clk_regmap_gate_ops = { + .enable = clk_regmap_gate_enable, + .disable = clk_regmap_gate_disable, + .disable_unused = clk_regmap_gate_disable_unused, + .is_enabled = clk_regmap_gate_is_enabled, +}; diff --git a/drivers/clk/realtek/clk-regmap-gate.h b/drivers/clk/realtek/clk-regmap-gate.h new file mode 100644 index 000000000000..e60fbbe28811 --- /dev/null +++ b/drivers/clk/realtek/clk-regmap-gate.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __CLK_REALTEK_CLK_MMIO_GATE_H +#define __CLK_REALTEK_CLK_MMIO_GATE_H + +#include "common.h" + +struct clk_regmap_gate { + struct clk_regmap clkr; + int gate_ofs; + uint8_t bit_idx; + spinlock_t *lock; + int write_en:1; +}; + +#define to_clk_regmap_gate(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_gate, clkr) +#define __clk_regmap_gate_hw(_p) __clk_regmap_hw(&(_p)->clkr) + +extern const struct clk_ops clk_regmap_gate_ops; + +static inline int is_clk_regmap_gate_ops(const struct clk_ops *ops) +{ + return ops == &clk_regmap_gate_ops; +} + +#endif diff --git a/drivers/clk/realtek/clk-regmap-mux.c b/drivers/clk/realtek/clk-regmap-mux.c new file mode 100644 index 000000000000..29b2f8ea43c5 --- /dev/null +++ b/drivers/clk/realtek/clk-regmap-mux.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "clk-regmap-mux.h" + +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) +{ + struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 val; + unsigned long flags = 0; + + if (clkm->lock) + spin_lock_irqsave(clkm->lock, flags); + + val = clk_regmap_read(&clkm->clkr, clkm->mux_ofs) >> clkm->shift; + if (clkm->lock) + spin_unlock_irqrestore(clkm->lock, flags); + + val &= clkm->mask; + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw); + unsigned long flags = 0; + + pr_debug("%pC: clk set parent, idx=%d\n", hw->clk, index); + + if (clkm->lock) + spin_lock_irqsave(clkm->lock, flags); + + clk_regmap_update(&clkm->clkr, clkm->mux_ofs, clkm->mask << clkm->shift, + index << clkm->shift); + + if (clkm->lock) + spin_unlock_irqrestore(clkm->lock, flags); + return 0; +} + +const struct clk_ops clk_regmap_mux_ops = { + .get_parent = clk_regmap_mux_get_parent, + .set_parent = clk_regmap_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ops); + +const struct clk_ops clk_regmap_mux_ro_ops = { + .get_parent = clk_regmap_mux_get_parent, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops); + diff --git a/drivers/clk/realtek/clk-regmap-mux.h b/drivers/clk/realtek/clk-regmap-mux.h new file mode 100644 index 000000000000..9cacbfd89d2b --- /dev/null +++ b/drivers/clk/realtek/clk-regmap-mux.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __CLK_REALTEK_CLK_MMIO_MUX_H +#define __CLK_REALTEK_CLK_MMIO_MUX_H + +#include "common.h" + +struct clk_regmap_mux { + struct clk_regmap clkr; + int mux_ofs; + unsigned int mask; + unsigned int shift; + spinlock_t *lock; +}; + +#define to_clk_regmap_mux(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_mux, clkr) +#define __clk_regmap_mux_hw(_p) __clk_regmap_hw(&(_p)->clkr) + +extern const struct clk_ops clk_regmap_mux_ops; + + +static inline int is_clk_regmap_mux_ops(const struct clk_ops *ops) +{ + return ops == &clk_regmap_mux_ops; +} + +#endif diff --git a/drivers/clk/realtek/clk-rtd1195-cc.c b/drivers/clk/realtek/clk-rtd1195-cc.c new file mode 100644 index 000000000000..c28198a873ca --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1195-cc.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define DIV_DV(_r, _div, _val) { .rate = _r, .div = _div, .val = _val, } +#define FREQ_NF_MASK 0x1FFFFC00 +#define FREQ_NF(_r, _n, _f) { .rate = _r, .val = ((_n) << 21) | ((_f) << 10), } +#define FREQ_MNO_MASK 0x030FF800 +#define FREQ_MNO(_r, _m, _n, _o) \ + { .rate = _r, .val = ((_m) << 11) | ((_n) << 18) | ((_o) << 24), } +#define FREQ_MN_MASK 0x07FC0000 +#define FREQ_MN(_r, _m, _n) { .rate = _r, .val = ((_m) << 18) | ((_n) << 25), } + +static const char * const default_parent[] = { "osc27m" }; + +static const struct div_table scpu_div_tbl[] = { + DIV_DV(700000000, 1, 0), + DIV_DV(350000000, 2, 2), + DIV_DV(290000000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table scpu_tbl[] = { + FREQ_NF(720000000, 25, 1364), + FREQ_NF(780000000, 27, 1820), + FREQ_NF(800000000, 28, 1290), + FREQ_NF(1000000000, 36, 75), + FREQ_NF(1160000000, 41, 1159), + FREQ_NF(1200000000, 43, 910), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_scpu = { + .div_ofs = 0x030, + .div_shift = 7, + .div_width = 2, + .div_tbl = scpu_div_tbl, + .clkp = { + .pll_type = CLK_PLL_TYPE_NF, + .freq_mask = FREQ_NF_MASK, + .freq_tbl = scpu_tbl, + .pll_ofs = 0x100, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + }, +}; + +static const struct div_table bus_div_tbl[] = { + DIV_DV(250000000, 2, 0), + DIV_DV(1, 4, 1), + DIV_TABLE_END +}; + +static const struct freq_table bus_tbl[] = { + FREQ_MN(459000000, 15, 0), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_bus = { + .div_ofs = 0x030, + .div_shift = 0, + .div_width = 1, + .div_tbl = bus_div_tbl, + .clkp = { + .pll_type = CLK_PLL_TYPE_MNO, + .freq_mask = FREQ_MN_MASK, + .freq_tbl = bus_tbl, + .pll_ofs = 0x164, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + }, +}; + +static struct clk_fixed_factor clk_sys = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + .flags = 0, + }, +}; + +static const struct freq_table dcsb_tbl[] = { + FREQ_MN(351000000, 11, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_dcsb = { + .pll_type = CLK_PLL_TYPE_MNO, + .freq_mask = FREQ_MN_MASK, + .freq_tbl = dcsb_tbl, + .pll_ofs = 0x1B4, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_fixed_factor clk_sysh = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sysh", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_dscb" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_table gpu_tbl[] = { + FREQ_MNO(378000000, 12, 0, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_gpu = { + .pll_type = CLK_PLL_TYPE_MNO, + .freq_mask = FREQ_MNO_MASK, + .freq_tbl = gpu_tbl, + .pll_ofs = 0x1C0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_gpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table vcpu_tbl[] = { + FREQ_MNO(243000000, 7, 0, 0), + FREQ_MNO(324000000, 10, 0, 0), + FREQ_MNO(405000000, 13, 0, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_vcpu = { + .pll_type = CLK_PLL_TYPE_MNO, + .freq_mask = FREQ_MNO_MASK, + .freq_tbl = vcpu_tbl, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_vcpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_hw *cc_hws[] = { + [RTD1195_CRT_PLL_SCPU] = &__clk_pll_div_hw(&pll_scpu), + [RTD1195_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1195_CRT_PLL_DCSB] = &__clk_pll_hw(&pll_dcsb), + [RTD1195_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1195_CRT_PLL_VCPU] = &__clk_pll_hw(&pll_vcpu), + [RTD1195_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1195_CRT_CLK_SYSH] = &clk_sysh.hw, +}; + +static struct clk_composite_data cc_composites[] = { + { + .id = RTD1195_CRT_CLK_GPU, + .gate_ofs = 0x00C, + .gate_shift = 11, + .mux_ofs = CLK_OFS_INVALID, + .parent_names = (const char *[]){ "pll_gpu", }, + .num_parents = 1, + .name = "clk_gpu", + .flags = CLK_SET_RATE_PARENT, + }, + { + .id = RTD1195_CRT_CLK_VE, + .mux_ofs = CLK_OFS_INVALID, + .gate_ofs = 0x010, + .gate_shift = 5, + .parent_names = (const char *[]){ "pll_vcpu", }, + .num_parents = 1, + .name = "clk_ve", + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1195_CRT_CLK_VE1, + .mux_ofs = 0x04C, + .mux_width = 2, + .mux_shift = 0, + .gate_ofs = 0x00C, + .gate_shift = 12, + .parent_names = (const char *[]){ + "clk_sys", + "clk_sysh", + "clk_ve", + }, + .num_parents = 3, + .name = "clk_ve1", + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1195_CRT_CLK_VE2, + .mux_ofs = 0x04C, + .mux_width = 2, + .mux_shift = 2, + .gate_ofs = 0x00C, + .gate_shift = 29, + .parent_names = (const char *[]){ + "clk_sys", + "clk_sysh", + "clk_ve", + }, + .num_parents = 3, + .name = "clk_ve2", + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1195_CRT_CLK_VE2_BPU, + .mux_ofs = 0x04C, + .mux_width = 2, + .mux_shift = 6, + .gate_ofs = CLK_OFS_INVALID, + .parent_names = (const char *[]){ + "clk_sys", + "clk_sysh", + "clk_gpu", + }, + .num_parents = 3, + .name = "clk_ve2_bpu", + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, +}; + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE_CRITICAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IS_CRITICAL, _ofs, _shift) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) +#define GATE_IGNORE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IGNORE_UNUSED, _ofs, _shift) + +static struct clk_gate_data cc_gates[] = { + GATE_CRITICAL(RTD1195_CRT_CLK_EN_MISC, "misc", NULL, 0x0C, 0), + GATE(RTD1195_CRT_CLK_EN_HDMIRX, "hdmirx", NULL, 0x0C, 1), + GATE(RTD1195_CRT_CLK_EN_GSPI, "gspi", "misc", 0x0C, 3), + GATE(RTD1195_CRT_CLK_EN_USB, "usb", NULL, 0x0C, 4), + GATE(RTD1195_CRT_CLK_EN_HDMI, "hdmi", NULL, 0x0C, 8), + GATE(RTD1195_CRT_CLK_EN_ETN, "etn", NULL, 0x0C, 9), + GATE(RTD1195_CRT_CLK_EN_VE_JPEG, "jpeg", NULL, 0x0C, 13), + GATE(RTD1195_CRT_CLK_EN_SE, "se", NULL, 0x0C, 17), + GATE(RTD1195_CRT_CLK_EN_CP, "cp", NULL, 0x0C, 19), + GATE(RTD1195_CRT_CLK_EN_MD, "md", NULL, 0x0C, 20), + GATE(RTD1195_CRT_CLK_EN_TP, "tp", NULL, 0x0C, 21), + GATE(RTD1195_CRT_CLK_EN_NF, "nf", NULL, 0x0C, 23), + GATE(RTD1195_CRT_CLK_EN_EMMC, "emmc", NULL, 0x0C, 24), + GATE(RTD1195_CRT_CLK_EN_CR, "cr", NULL, 0x0C, 25), + GATE(RTD1195_CRT_CLK_EN_SDIO_IP, "sdio_ip", NULL, 0x0C, 26), + GATE(RTD1195_CRT_CLK_EN_MIPI, "mipi", NULL, 0x0C, 27), + GATE(RTD1195_CRT_CLK_EN_EMMC_IP, "emmc_ip", NULL, 0x0C, 28), + GATE(RTD1195_CRT_CLK_EN_SDIO, "sdio", NULL, 0x0C, 30), + GATE(RTD1195_CRT_CLK_EN_SD_IP, "sd_ip", NULL, 0x0C, 31), + GATE(RTD1195_CRT_CLK_EN_MISC_I2C_5, "i2c5", "misc", 0x10, 2), + GATE(RTD1195_CRT_CLK_EN_MISC_RTC, "rtc", "misc", 0x10, 9), + GATE(RTD1195_CRT_CLK_EN_MISC_I2C_4, "i2c4", "misc", 0x10, 13), + GATE(RTD1195_CRT_CLK_EN_MISC_I2C_3, "i2c3", "misc", 0x10, 14), + GATE(RTD1195_CRT_CLK_EN_MISC_I2C_2, "i2c2", "misc", 0x10, 15), + GATE(RTD1195_CRT_CLK_EN_MISC_I2C_1, "i2c1", "misc", 0x10, 16), + GATE(RTD1195_CRT_CLK_EN_UR1, "ur1", "misc", 0x10, 28), +}; + +static struct rtk_reset_bank cc_reset_banks[] = { + { .ofs = 0x00, }, + { .ofs = 0x04, }, +}; + +static struct rtk_reset_initdata cc_reset_initdata = { + .banks = cc_reset_banks, + .num_banks = ARRAY_SIZE(cc_reset_banks), +}; + +static int rtd1195_cc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1195_CRT_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + rtk_clk_add_hws(dev, data, cc_hws, ARRAY_SIZE(cc_hws)); + rtk_clk_add_composites(dev, data, cc_composites, + ARRAY_SIZE(cc_composites)); + rtk_clk_add_gates(dev, data, cc_gates, ARRAY_SIZE(cc_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + cc_reset_initdata.lock = data->lock; + cc_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &cc_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1195_cc_match[] = { + { .compatible = "realtek,rtd1195-crt-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1195_cc_match); + +static struct platform_driver rtd1195_cc_driver = { + .probe = rtd1195_cc_probe, + .driver = { + .name = "rtk-rtd1195-crt-clk", + .of_match_table = of_match_ptr(rtd1195_cc_match), + }, +}; + +static int __init rtd1195_cc_init(void) +{ + return platform_driver_register(&rtd1195_cc_driver); +} +core_initcall(rtd1195_cc_init); +MODULE_DESCRIPTION("Reatek RTD1195 CRT Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1195-ic.c b/drivers/clk/realtek/clk-rtd1195-ic.c new file mode 100644 index 000000000000..e2f650b517f2 --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1195-ic.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +static struct clk_gate_data ic_gates[] = { + GATE(RTD1195_ISO_CLK_EN_VFD, "vfd", NULL, 0x8C, 1), + GATE(RTD1195_ISO_CLK_EN_CEC0, "cec0", NULL, 0x8C, 2), + GATE(RTD1195_ISO_CLK_EN_CBUSRX_SYS, "cbusrx_sys", NULL, 0x8C, 3), + GATE(RTD1195_ISO_CLK_EN_CBUSTX_SYS, "cbustx_sys", NULL, 0x8C, 4), + GATE(RTD1195_ISO_CLK_EN_CBUS_SYS, "cbus_sys", NULL, 0x8C, 5), + GATE(RTD1195_ISO_CLK_EN_CBUS_OSC, "cbus_osc", NULL, 0x8C, 6), + GATE(RTD1195_ISO_CLK_EN_IR, "ir", NULL, 0x8C, 7), + GATE(RTD1195_ISO_CLK_EN_UR0, "ur0", NULL, 0x8C, 8), + GATE(RTD1195_ISO_CLK_EN_I2C0, "i2c0", NULL, 0x8C, 9), + GATE(RTD1195_ISO_CLK_EN_I2C6, "i2c6", NULL, 0x8C, 10), + GATE(RTD1195_ISO_CLK_EN_ETN_250M, "etn_250m", NULL, 0x8C, 11), + GATE(RTD1195_ISO_CLK_EN_ETN_SYS, "etn_sys", NULL, 0x8C, 12), +}; + +static struct rtk_reset_bank ic_reset_banks[] = { + { .ofs = 0x88, }, +}; + +static struct rtk_reset_initdata ic_reset_initdata = { + .banks = ic_reset_banks, + .num_banks = ARRAY_SIZE(ic_reset_banks), +}; + +static int rtd1195_ic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1195_ISO_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + + rtk_clk_add_gates(dev, data, ic_gates, ARRAY_SIZE(ic_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + ic_reset_initdata.lock = data->lock; + ic_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &ic_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1195_ic_match[] = { + { .compatible = "realtek,rtd1195-iso-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1195_ic_match); + +static struct platform_driver rtd1195_ic_driver = { + .probe = rtd1195_ic_probe, + .driver = { + .name = "rtk-rtd1195-iso-clk", + .of_match_table = of_match_ptr(rtd1195_ic_match), + }, +}; + +static int __init rtd1195_ic_init(void) +{ + return platform_driver_register(&rtd1195_ic_driver); +} +core_initcall(rtd1195_ic_init); +MODULE_DESCRIPTION("Reatek RTD1195 ISO Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1295-cc.c b/drivers/clk/realtek/clk-rtd1295-cc.c new file mode 100644 index 000000000000..9ecc947adf6b --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1295-cc.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017,2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define DIV_DV(_r, _d, _v) { .rate = _r, .div = _d, .val = _v, } +#define FREQ_NF_MASK (0x7FFFF) +#define FREQ_NF(_r, _n, _f) { .rate = _r, .val = ((_n) << 11) | (_f), } +#define FREQ_MNO_MASK (0x63FF0) +#define FREQ_MNO(_r, _m, _n, _o) \ + { .rate = _r, .val = ((_m) << 4) | ((_n) << 12) | ((_o) << 17), } + +static const char * const default_parent[] = { "osc27m" }; + +static const struct div_table scpu_div_tbl[] = { + DIV_DV(1000000000, 1, 0), + DIV_DV(500000000, 2, 2), + DIV_DV(250000000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table scpu_tbl[] = { + FREQ_NF(1000000000, 34, 75), + FREQ_NF(1100000000, 37, 1517), + FREQ_NF(1200000000, 41, 910), + FREQ_NF(1300000000, 45, 303), + FREQ_NF(1400000000, 48, 1745), + FREQ_NF(1500000000, 52, 1137), + FREQ_NF(1600000000, 56, 531), + FREQ_NF(1800000000, 63, 1365), + FREQ_NF(1200000000, 41, 1024), + FREQ_NF(1300000000, 45, 1024), + FREQ_NF(1503000000, 48, 1744), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_scpu = { + .div_ofs = 0x030, + .div_shift = 7, + .div_width = 2, + .div_tbl = scpu_div_tbl, + .clkp = { + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .flags = CLK_PLL_DIV_WORKAROUND, + .ssc_ofs = 0x500, + .pll_ofs = CLK_OFS_INVALID, + .freq_tbl = scpu_tbl, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct freq_table bus_tbl[] = { + FREQ_NF(200000000, 4, 835), + FREQ_NF(243000000, 6, 0), + FREQ_NF(256000000, 6, 1024), + FREQ_NF(256000000, 6, 986), + FREQ_NF(257000000, 6, 1061), + FREQ_NF(459000000, 14, 0), + FREQ_NF(486000000, 15, 0), + FREQ_NF(482000000, 14, 1744), + FREQ_NF(513000000, 16, 0), + FREQ_NF(540000000, 17, 0), + FREQ_TABLE_END +}; + +static const struct div_table bus_div_tbl[] = { + DIV_DV(256000000, 1, 0), + DIV_DV(1, 2, 1), + DIV_TABLE_END +}; + +static struct clk_pll_div pll_bus = { + .div_ofs = 0x030, + .div_shift = 0, + .div_width = 1, + .div_tbl = bus_div_tbl, + .clkp = { + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .freq_tbl = bus_tbl, + .pll_ofs = CLK_OFS_INVALID, + .ssc_ofs = 0x520, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static struct clk_fixed_factor clk_sys = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_pll pll_dcsb = { + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .freq_tbl = bus_tbl, + .pll_ofs = CLK_OFS_INVALID, + .ssc_ofs = 0x540, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_fixed_factor clk_sysh = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sysh", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_dcsb" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_table ddsx_tbl[] = { + FREQ_NF(432000000, 13, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ddsa = { + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .freq_tbl = ddsx_tbl, + .pll_ofs = 0x120, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .ssc_ofs = 0x560, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsa", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_pll pll_ddsb = { + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .freq_tbl = ddsx_tbl, + .pll_ofs = 0x174, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .ssc_ofs = 0x580, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsb", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table gpu_tbl[] = { + FREQ_NF(300000000, 8, 227), + FREQ_NF(320000000, 8, 1744), + FREQ_NF(340000000, 9, 1213), + FREQ_NF(360000000, 10, 682), + FREQ_NF(380000000, 11, 151), + FREQ_NF(400000000, 11, 1668), + FREQ_NF(420000000, 12, 1137), + FREQ_NF(440000000, 13, 606), + FREQ_NF(460000000, 14, 75), + FREQ_NF(480000000, 14, 1592), + FREQ_NF(500000000, 15, 1061), + FREQ_NF(520000000, 16, 530), + FREQ_NF(540000000, 17, 0), + FREQ_NF(560000000, 17, 1517), + FREQ_NF(580000000, 18, 986), + FREQ_NF(600000000, 19, 455), + FREQ_NF(620000000, 19, 1972), + FREQ_NF(640000000, 20, 1441), + FREQ_NF(660000000, 21, 910), + FREQ_NF(680000000, 22, 379), + FREQ_NF(460000000, 13, 1365), + FREQ_TABLE_END +}; + +static struct clk_pll pll_gpu = { + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .freq_tbl = gpu_tbl, + .pll_ofs = 0x1C0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .ssc_ofs = 0x5A0, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_gpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table ve_tbl[] = { + FREQ_MNO(189000000, 5, 0, 0), + FREQ_MNO(270000000, 8, 0, 0), + FREQ_MNO(405000000, 13, 0, 0), + FREQ_MNO(432000000, 14, 0, 0), + FREQ_MNO(459000000, 15, 0, 0), + FREQ_MNO(486000000, 16, 0, 0), + FREQ_MNO(513000000, 17, 0, 0), + FREQ_MNO(540000000, 18, 0, 0), + FREQ_MNO(567000000, 19, 0, 0), + FREQ_MNO(594000000, 20, 0, 0), + FREQ_MNO(648000000, 22, 0, 0), + FREQ_MNO(675000000, 23, 0, 0), + FREQ_MNO(702000000, 24, 0, 0), + FREQ_MNO(715000000, 51, 1, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ve1 = { + .pll_type = CLK_PLL_TYPE_MNO, + .freq_mask = FREQ_MNO_MASK, + .freq_tbl = ve_tbl, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .ssc_ofs = CLK_OFS_INVALID, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve1", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_pll pll_ve2 = { + .pll_type = CLK_PLL_TYPE_MNO, + .freq_mask = FREQ_MNO_MASK, + .freq_tbl = ve_tbl, + .pll_ofs = 0x1D0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .ssc_ofs = CLK_OFS_INVALID, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve2", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_hw *cc_hws[] = { + [RTD1295_CRT_PLL_SCPU] = &__clk_pll_div_hw(&pll_scpu), + [RTD1295_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1295_CRT_PLL_DCSB] = &__clk_pll_hw(&pll_dcsb), + [RTD1295_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1295_CRT_PLL_DDSB] = &__clk_pll_hw(&pll_ddsb), + [RTD1295_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1295_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1), + [RTD1295_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2), + [RTD1295_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1295_CRT_CLK_SYSH] = &clk_sysh.hw, +}; + +static const char * const ve_parents[] = { + "clk_sysh", + "pll_ve1", + "pll_ve2", + "pll_ve2", +}; + +static struct clk_composite_data cc_composites[] = { + { + .id = RTD1295_CRT_CLK_GPU, + .flags = CLK_SET_RATE_PARENT, + .gate_ofs = 0x00C, + .gate_shift = 11, + .mux_ofs = CLK_OFS_INVALID, + .name = "clk_gpu", + .num_parents = 1, + .parent_names = (const char *[]){ "pll_gpu" }, + .shared = 1, + }, + { + .id = RTD1295_CRT_CLK_VE1, + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .gate_ofs = 0x00C, + .gate_shift = 12, + .mux_ofs = 0x04C, + .mux_shift = 0, + .mux_width = 2, + .name = "clk_ve1", + .num_parents = ARRAY_SIZE(ve_parents), + .parent_names = ve_parents, + .shared = 1 + }, + { + .id = RTD1295_CRT_CLK_VE2, + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .gate_ofs = 0x00C, + .gate_shift = 13, + .mux_ofs = 0x04C, + .mux_shift = 2, + .mux_width = 2, + .name = "clk_ve2", + .num_parents = ARRAY_SIZE(ve_parents), + .parent_names = ve_parents, + .shared = 1 + }, + { + .id = RTD1295_CRT_CLK_VE3, + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .gate_ofs = 0x00C, + .gate_shift = 29, + .mux_ofs = 0x04C, + .mux_shift = 4, + .mux_width = 2, + .name = "clk_ve3", + .num_parents = ARRAY_SIZE(ve_parents), + .parent_names = ve_parents, + .shared = 1 + }, +}; + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 1) +#define GATE_CRITICAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IS_CRITICAL, _ofs, _shift) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) +#define GATE_IGNORE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IGNORE_UNUSED, _ofs, _shift) + +static struct clk_gate_data cc_gates[] = { + GATE_CRITICAL(RTD1295_CRT_CLK_EN_MISC, "misc", NULL, 0x0C, 0), + GATE(RTD1295_CRT_CLK_EN_PCIE0, "pcie0", NULL, 0x0C, 1), + GATE(RTD1295_CRT_CLK_EN_SATA_0, "sata_0", NULL, 0x0C, 2), + GATE(RTD1295_CRT_CLK_EN_GSPI, "gspi", NULL, 0x0C, 3), + GATE(RTD1295_CRT_CLK_EN_USB, "usb", NULL, 0x0C, 4), + GATE(RTD1295_CRT_CLK_EN_SATA_ALIVE_0, "sata_alive_0", NULL, 0x0C, 7), + GATE_IGNORE(RTD1295_CRT_CLK_EN_HDMI, "hdmi", NULL, 0x0C, 8), + GATE(RTD1295_CRT_CLK_EN_ETN, "etn", NULL, 0x0C, 9), + GATE(RTD1295_CRT_CLK_EN_SE, "se", NULL, 0x0C, 17), + GATE_IGNORE(RTD1295_CRT_CLK_EN_CP, "cp", NULL, 0x0C, 19), + GATE_IGNORE(RTD1295_CRT_CLK_EN_MD, "md", NULL, 0x0C, 20), + GATE_IGNORE(RTD1295_CRT_CLK_EN_TP, "tp", NULL, 0x0C, 21), + GATE(RTD1295_CRT_CLK_EN_NF, "nf", NULL, 0x0C, 23), + GATE(RTD1295_CRT_CLK_EN_EMMC, "emmc", NULL, 0x0C, 24), + GATE(RTD1295_CRT_CLK_EN_CR, "cr", NULL, 0x0C, 25), + GATE(RTD1295_CRT_CLK_EN_SDIO_IP, "sdio_ip", NULL, 0x0C, 26), + GATE(RTD1295_CRT_CLK_EN_MIPI, "mipi", NULL, 0x0C, 27), + GATE(RTD1295_CRT_CLK_EN_EMMC_IP, "emmc_ip", NULL, 0x0C, 28), + GATE(RTD1295_CRT_CLK_EN_SDIO, "sdio", NULL, 0x0C, 30), + GATE(RTD1295_CRT_CLK_EN_SD_IP, "sd_ip", NULL, 0x0C, 31), + GATE(RTD1295_CRT_CLK_EN_NAT, "nat", NULL, 0x10, 0), + GATE(RTD1295_CRT_CLK_EN_MISC_I2C_5, "i2c5", NULL, 0x10, 1), + GATE(RTD1295_CRT_CLK_EN_JPEG, "jpeg", NULL, 0x10, 3), + GATE(RTD1295_CRT_CLK_EN_PCIE1, "pcie1", NULL, 0x10, 5), + GATE(RTD1295_CRT_CLK_EN_MISC_SC, "sc", "misc", 0x10, 6), + GATE(RTD1295_CRT_CLK_EN_CBUS_TX, "cbus_tx", NULL, 0x10, 7), + GATE(RTD1295_CRT_CLK_EN_MISC_RTC, "rtc", NULL, 0x10, 10), + GATE(RTD1295_CRT_CLK_EN_MISC_I2C_4, "i2c4", "misc", 0x10, 13), + GATE(RTD1295_CRT_CLK_EN_MISC_I2C_3, "i2c3", "misc", 0x10, 14), + GATE(RTD1295_CRT_CLK_EN_MISC_I2C_2, "i2c2", "misc", 0x10, 15), + GATE(RTD1295_CRT_CLK_EN_HDMIRX, "hdmirx", NULL, 0x10, 24), + GATE(RTD1295_CRT_CLK_EN_SATA_1, "sata_1", NULL, 0x10, 25), + GATE(RTD1295_CRT_CLK_EN_SATA_ALIVE_1, "sata_alive_1", NULL, 0x10, 26), + GATE(RTD1295_CRT_CLK_EN_UR2, "ur2", "misc", 0x10, 27), + GATE(RTD1295_CRT_CLK_EN_UR1, "ur1", "misc", 0x10, 28), + GATE(RTD1295_CRT_CLK_EN_FAN, "fan", "misc", 0x10, 29), + GATE(RTD1295_CRT_CLK_EN_LSADC, "lsadc", NULL, 0x450, 2), + GATE_IGNORE(RTD1295_CRT_CLK_EN_TVE, "tve", NULL, 0x0C, 14), + GATE_IGNORE(RTD1295_CRT_CLK_EN_VO, "vo", NULL, 0x0C, 15), + GATE_IGNORE(RTD1295_CRT_CLK_EN_LVDS, "lvds", NULL, 0x0C, 16), +}; + +static struct rtk_reset_bank cc_reset_banks[] = { + { .ofs = 0x00, }, + { .ofs = 0x04, }, + { .ofs = 0x50, }, +}; + +static struct rtk_reset_initdata cc_reset_initdata = { + .banks = cc_reset_banks, + .num_banks = ARRAY_SIZE(cc_reset_banks), + .shared = 1, +}; + +static int rtd1295_cc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1295_CRT_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_hws(dev, data, cc_hws, ARRAY_SIZE(cc_hws)); + rtk_clk_add_composites(dev, data, cc_composites, + ARRAY_SIZE(cc_composites)); + rtk_clk_add_gates(dev, data, cc_gates, ARRAY_SIZE(cc_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + cc_reset_initdata.lock = data->lock; + cc_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &cc_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1295_cc_match[] = { + { .compatible = "realtek,rtd1295-crt-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1295_cc_match); + +static struct platform_driver rtd1295_cc_driver = { + .probe = rtd1295_cc_probe, + .driver = { + .name = "rtk-rtd1295-crt-clk", + .of_match_table = of_match_ptr(rtd1295_cc_match), + }, +}; + +static int __init rtd1295_cc_init(void) +{ + return platform_driver_register(&rtd1295_cc_driver); +} +core_initcall(rtd1295_cc_init); +MODULE_DESCRIPTION("Reatek RTD1295 CRT Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1295-ic.c b/drivers/clk/realtek/clk-rtd1295-ic.c new file mode 100644 index 000000000000..3397fc8b8121 --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1295-ic.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +static struct clk_gate_data ic_gates[] = { + GATE(RTD1295_ISO_CLK_EN_CEC0, "cec0", NULL, 0x8C, 2), + GATE(RTD1295_ISO_CLK_EN_CBUSRX_SYS, "cbusrx_sys", NULL, 0x8C, 3), + GATE(RTD1295_ISO_CLK_EN_CBUSTX_SYS, "cbustx_sys", NULL, 0x8C, 4), + GATE(RTD1295_ISO_CLK_EN_CBUS_SYS, "cbus_sys", NULL, 0x8C, 5), + GATE(RTD1295_ISO_CLK_EN_CBUS_OSC, "cbus_osc", NULL, 0x8C, 6), + GATE(RTD1295_ISO_CLK_EN_IR, "ir", NULL, 0x8C, 7), + GATE(RTD1295_ISO_CLK_EN_UR0, "ur0", NULL, 0x8C, 8), + GATE(RTD1295_ISO_CLK_EN_I2C0, "i2c0", NULL, 0x8C, 9), + GATE(RTD1295_ISO_CLK_EN_I2C1, "i2c1", NULL, 0x8C, 10), + GATE(RTD1295_ISO_CLK_EN_ETN_250M, "etn_250m", NULL, 0x8C, 11), + GATE(RTD1295_ISO_CLK_EN_ETN_SYS, "etn_sys", NULL, 0x8C, 12), +}; + +static struct rtk_reset_bank ic_reset_banks[] = { + { .ofs = 0x88, }, +}; + +static struct rtk_reset_initdata ic_reset_initdata = { + .banks = ic_reset_banks, + .num_banks = ARRAY_SIZE(ic_reset_banks), +}; + +static int rtd1295_ic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1295_ISO_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_gates(dev, data, ic_gates, ARRAY_SIZE(ic_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + ic_reset_initdata.lock = data->lock; + ic_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &ic_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1295_ic_match[] = { + { .compatible = "realtek,rtd1295-iso-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1295_ic_match); + +static struct platform_driver rtd1295_ic_driver = { + .probe = rtd1295_ic_probe, + .driver = { + .name = "rtk-rtd1295-iso-clk", + .of_match_table = of_match_ptr(rtd1295_ic_match), + }, +}; + +static int __init rtd1295_ic_init(void) +{ + return platform_driver_register(&rtd1295_ic_driver); +} +core_initcall(rtd1295_ic_init); +MODULE_DESCRIPTION("Reatek RTD1295 ISO Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1319-cc.c b/drivers/clk/realtek/clk-rtd1319-cc.c new file mode 100644 index 000000000000..564e8e9da9d1 --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1319-cc.c @@ -0,0 +1,777 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "clk-det.h" +#include "reset.h" +#include +#include + +#define DIV_DV(_r, _d, _v) { .rate = _r, .div = _d, .val = _v, } +#define FREQ_NF_MASK (0x7FFFF) +#define FREQ_NF(_r, _n, _f) { .rate = _r, .val = ((_n) << 11) | (_f), } +#define FREQ_MNO_MASK (0x63FF0) +#define FREQ_MNO_MASK_SET (0x7FFFE) +#define FREQ_MNO(_r, _m, _n, _o) \ + { .rate = _r, .val = ((_m) << 4) | ((_n) << 12) | ((_o) << 17) | ((_m) <= 0x18 ? 0x0000c002 : 0x0001c000), } + +static const char * const default_parent[] = { "osc27m" }; + +static const struct div_table scpu_div_tbl[] = { + DIV_DV(1000000000, 1, 0x00), + DIV_DV(500000000, 2, 0x88), + DIV_DV(250000000, 4, 0x90), + DIV_DV(200000000, 8, 0xA0), + DIV_DV(100000000, 10, 0xA8), + DIV_TABLE_END +}; + +static const struct freq_table scpu_tbl[] = { + FREQ_NF(918000000, 31, 0), + FREQ_NF(1000000000, 34, 75), + FREQ_NF(1100000000, 37, 1517), + FREQ_NF(1200000000, 41, 910), + FREQ_NF(1300000000, 45, 303), + FREQ_NF(1350000000, 47, 0), + FREQ_NF(1400000000, 48, 1745), + FREQ_NF(1500000000, 52, 1137), + FREQ_NF(1600000000, 56, 530), + FREQ_NF(1700000000, 59, 1972), + FREQ_NF(1800000000, 63, 1365), + FREQ_NF(1900000000, 67, 758), + FREQ_NF(2000000000, 71, 151), + FREQ_NF(1000000000, 35, 0), + FREQ_NF(1200000000, 41, 0), + FREQ_NF(1800000000, 65, 0), + FREQ_NF(1800000000, 64, 0), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_scpu = { + .div_ofs = 0x030, + .div_shift = 6, + .div_width = 8, + .div_tbl = scpu_div_tbl, + .clkp = { + .ssc_ofs = 0x500, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = scpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct div_table bus_div_tbl[] = { + DIV_DV(257000000, 1, 0), + DIV_DV(129000000, 2, 2), + DIV_DV(65000000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table bus_tbl[] = { + FREQ_NF(400000000, 26, 1289), + FREQ_NF(459000000, 31, 0), + FREQ_NF(500000000, 34, 0), + FREQ_NF(513000000, 35, 0), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_bus = { + .div_ofs = 0x030, + .div_shift = 0, + .div_width = 2, + .div_tbl = bus_div_tbl, + .clkp = { + .ssc_ofs = 0x520, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = bus_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct div_table dcsb_div_tbl[] = { + DIV_DV(400000000, 1, 0), + DIV_DV(275000000, 2, 2), + DIV_DV(1, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table dcsb_tbl[] = { + FREQ_NF(459000000, 31, 0), + FREQ_NF(472000000, 32, 0), + FREQ_NF(550000000, 38, 0), + FREQ_NF(550000000, 37, 1517), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_dcsb = { + .div_ofs = 0x030, + .div_shift = 2, + .div_width = 2, + .div_tbl = dcsb_div_tbl, + .clkp = { + .ssc_ofs = 0x540, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = dcsb_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static struct clk_fixed_factor clk_sys = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor clk_sysh = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sysh", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_dcsb" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_table ddsx_tbl[] = { + FREQ_NF(432000000, 13, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ddsa = { + .ssc_ofs = 0x560, + .pll_ofs = 0x120, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = ddsx_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsa", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table gpu_tbl[] = { + FREQ_NF(300000000, 19, 455), + FREQ_NF(400000000, 26, 1289), + FREQ_NF(500000000, 34, 75), + FREQ_NF(550000000, 37, 1517), + FREQ_NF(585000000, 40, 682), + FREQ_NF(600000000, 41, 910), + FREQ_NF(650000000, 45, 303), + FREQ_NF(700000000, 48, 1745), + FREQ_NF(720000000, 50, 682), + FREQ_NF(750000000, 52, 1137), + FREQ_TABLE_END +}; + +static struct clk_pll pll_gpu = { + .ssc_ofs = 0x5A0, + .pll_ofs = 0x1C0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = gpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_gpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table ve_tbl[] = { + FREQ_MNO(189000000, 12, 0, 1), + FREQ_MNO(270000000, 18, 0, 1), + FREQ_MNO(405000000, 13, 0, 0), + FREQ_MNO(432000000, 14, 0, 0), + FREQ_MNO(459000000, 15, 0, 0), + FREQ_MNO(486000000, 16, 0, 0), + FREQ_MNO(500000000, 35, 1, 0), + FREQ_MNO(513000000, 17, 0, 0), + FREQ_MNO(540000000, 18, 0, 0), + FREQ_MNO(550000000, 59, 2, 0), + FREQ_MNO(567000000, 19, 0, 0), + FREQ_MNO(594000000, 20, 0, 0), + FREQ_MNO(621000000, 21, 0, 0), + FREQ_MNO(648000000, 22, 0, 0), + FREQ_MNO(675000000, 23, 0, 0), + FREQ_MNO(702000000, 24, 0, 0), + FREQ_MNO(715000000, 51, 1, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ve1 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .freq_mask_set = FREQ_MNO_MASK_SET, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve1", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_pll pll_ve2 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x1D0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .freq_mask_set = FREQ_MNO_MASK_SET, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve2", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_pll_dif pll_dif = { + .ssc_ofs = 0x634, + .pll_ofs = 0x624, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dif", + .ops = &clk_pll_dif_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, + .adtv_conf = { + 0x02000949, 0x00030c00, 0x204004ca, 0x400C6004, + 0x00431c00, 0x00431c03, 0x02000979, 0x004884ca, + }, +}; + +static struct clk_pll_psaud pll_psaud1a = { + .reg = 0x130, + .id = CLK_PLL_PSAUD1A, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_psaud1a", + .ops = &clk_pll_psaud_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_UNGATE, + }, +}; + +static struct clk_pll_psaud pll_psaud2a = { + .reg = 0x130, + .id = CLK_PLL_PSAUD2A, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_psaud2a", + .ops = &clk_pll_psaud_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_UNGATE, + }, +}; + +static struct clk_det clk_det_pll_bus = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_bus", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x424, +}; + +static struct clk_det clk_det_pll_dcsb = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_dcsb", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x428, +}; + +static struct clk_det clk_det_pll_acpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_acpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x42c, +}; + +static struct clk_det clk_det_pll_ddsa = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ddsa", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x430, +}; + +static struct clk_det clk_det_pll_gpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_gpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x438, +}; + +static struct clk_det clk_det_pll_ve1 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve1", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x43c, +}; + +static struct clk_det clk_det_pll_ve2 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve2", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x440, +}; + +static struct clk_hw *cc_hws[] = { + [RTD1319_CRT_PLL_SCPU] = &__clk_pll_div_hw(&pll_scpu), + [RTD1319_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1319_CRT_PLL_DCSB] = &__clk_pll_div_hw(&pll_dcsb), + [RTD1319_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1319_CRT_CLK_SYSH] = &clk_sysh.hw, + [RTD1319_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1319_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1319_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1), + [RTD1319_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2), + [RTD1319_CRT_PLL_DIF] = &__clk_pll_dif_hw(&pll_dif), + [RTD1319_CRT_PLL_PSAUD1A] = &__clk_pll_psaud_hw(&pll_psaud1a), + [RTD1319_CRT_PLL_PSAUD2A] = &__clk_pll_psaud_hw(&pll_psaud2a), + + [RTD1319_CRT_CLK_DET_PLL_BUS] = &__clk_det_hw(&clk_det_pll_bus), + [RTD1319_CRT_CLK_DET_PLL_DCSB] = &__clk_det_hw(&clk_det_pll_dcsb), + [RTD1319_CRT_CLK_DET_PLL_ACPU] = &__clk_det_hw(&clk_det_pll_acpu), + [RTD1319_CRT_CLK_DET_PLL_DDSA] = &__clk_det_hw(&clk_det_pll_ddsa), + [RTD1319_CRT_CLK_DET_PLL_GPU] = &__clk_det_hw(&clk_det_pll_gpu), + [RTD1319_CRT_CLK_DET_PLL_VE1] = &__clk_det_hw(&clk_det_pll_ve1), + [RTD1319_CRT_CLK_DET_PLL_VE2] = &__clk_det_hw(&clk_det_pll_ve2), +}; + +static const char * const ve_parents[] = { + "pll_gpu", + "clk_sysh", + "pll_ve1", + "pll_ve2", +}; + +static struct clk_composite_data cc_composites[] = { + { + .id = RTD1319_CRT_CLK_GPU, + .mux_ofs = CLK_OFS_INVALID, + .gate_ofs = 0x050, + .gate_shift = 18, + .gate_write_en = 1, + .parent_names = (const char *[]){ "pll_gpu" }, + .num_parents = 1, + .name = "clk_gpu", + .flags = CLK_SET_RATE_PARENT, + }, + { + .id = RTD1319_CRT_CLK_VE1, + .gate_ofs = 0x050, + .gate_shift = 20, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 0, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve1", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1319_CRT_CLK_VE2, + .gate_ofs = 0x050, + .gate_shift = 22, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 3, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve2", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1319_CRT_CLK_VE3, + .gate_ofs = 0x05C, + .gate_shift = 26, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 6, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve3", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1319_CRT_CLK_VE3_BPU, + .gate_ofs = CLK_OFS_INVALID, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 9, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve3_bpu", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 1, 0) +#define GATE_CRITICAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IS_CRITICAL, _ofs, _shift) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) +#define GATE_IGNORE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IGNORE_UNUSED, _ofs, _shift) + +static struct clk_gate_data cc_gates[] = { + GATE_CRITICAL(RTD1319_CRT_CLK_EN_MISC, "misc", NULL, 0x50, 0), + GATE(RTD1319_CRT_CLK_EN_PCIE0, "pcie0", NULL, 0x50, 2), + GATE(RTD1319_CRT_CLK_EN_GSPI, "gspi", "misc", 0x50, 6), + GATE(RTD1319_CRT_CLK_EN_SDS, "sds", NULL, 0x50, 12), + GATE_IGNORE(RTD1319_CRT_CLK_EN_HDMI, "hdmi", NULL, 0x50, 14), + GATE(RTD1319_CRT_CLK_EN_LSADC, "lsadc", NULL, 0x50, 28), + GATE_IGNORE(RTD1319_CRT_CLK_EN_CP, "cp", NULL, 0x54, 2), + GATE_IGNORE(RTD1319_CRT_CLK_EN_TP, "tp", NULL, 0x54, 6), + GATE(RTD1319_CRT_CLK_EN_RSA, "rsa", NULL, 0x54, 8), + GATE(RTD1319_CRT_CLK_EN_NF, "nf", NULL, 0x54, 10), + GATE(RTD1319_CRT_CLK_EN_EMMC, "emmc", NULL, 0x54, 12), + GATE(RTD1319_CRT_CLK_EN_SD, "sd", NULL, 0x54, 14), + GATE(RTD1319_CRT_CLK_EN_SDIO_IP, "sdio_ip", NULL, 0x54, 16), + GATE(RTD1319_CRT_CLK_EN_MIPI, "mipi", NULL, 0x54, 18), + GATE(RTD1319_CRT_CLK_EN_EMMC_IP, "emmc_ip", NULL, 0x54, 20), + GATE(RTD1319_CRT_CLK_EN_SDIO, "sdio", NULL, 0x54, 22), + GATE(RTD1319_CRT_CLK_EN_SD_IP, "sd_ip", NULL, 0x54, 24), + GATE(RTD1319_CRT_CLK_EN_CABLERX, "cablerx", NULL, 0x54, 26), + GATE(RTD1319_CRT_CLK_EN_TPB, "tpb", NULL, 0x54, 28), + GATE(RTD1319_CRT_CLK_EN_MISC_SC1, "sc1", "misc", 0x54, 30), + GATE(RTD1319_CRT_CLK_EN_MISC_I2C_3, "i2c3", "misc", 0x58, 0), + GATE(RTD1319_CRT_CLK_EN_JPEG, "jpeg", NULL, 0x58, 4), + GATE(RTD1319_CRT_CLK_EN_MISC_SC0, "sc0", "misc", 0x58, 10), + GATE(RTD1319_CRT_CLK_EN_HDMIRX, "hdmirx", NULL, 0x58, 26), + GATE(RTD1319_CRT_CLK_EN_HSE, "hse", NULL, 0x58, 28), + GATE(RTD1319_CRT_CLK_EN_UR2, "ur2", "misc", 0x58, 30), + GATE(RTD1319_CRT_CLK_EN_UR1, "ur1", "misc", 0x5C, 0), + GATE(RTD1319_CRT_CLK_EN_FAN, "fan", NULL, 0x5C, 2), + GATE(RTD1319_CRT_CLK_EN_SATA_WRAP_SYS, "sata_wrap_sys", NULL, 0x5C, 8), + GATE(RTD1319_CRT_CLK_EN_SATA_WRAP_SYSH, "sata_wrap_sysh", NULL, 0x5C, 10), + GATE(RTD1319_CRT_CLK_EN_SATA_MAC_SYSH, "sata_mac_sysh", NULL, 0x5C, 12), + GATE(RTD1319_CRT_CLK_EN_R2RDSC, "r2rdsc", NULL, 0x5C, 14), + GATE(RTD1319_CRT_CLK_EN_TPC, "tpc", NULL, 0x5C, 16), + GATE(RTD1319_CRT_CLK_EN_PCIE1, "pcie1", NULL, 0x5C, 18), + GATE(RTD1319_CRT_CLK_EN_MISC_I2C_4, "i2c4", "misc", 0x5C, 20), + GATE(RTD1319_CRT_CLK_EN_MISC_I2C_5, "i2c5", "misc", 0x5C, 22), + GATE(RTD1319_CRT_CLK_EN_EDP, "edp", NULL, 0x5C, 28), + GATE(RTD1319_CRT_CLK_EN_PCIE2, "pcie2", NULL, 0x8C, 0), +}; + +static struct rtk_reset_bank cc_reset_banks[] = { + { .ofs = 0x000, .write_en = 1, }, + { .ofs = 0x004, .write_en = 1, }, + { .ofs = 0x008, .write_en = 1, }, + { .ofs = 0x00C, .write_en = 1, }, + { .ofs = 0x068, .write_en = 1, }, + { .ofs = 0x090, .write_en = 1, }, + { .ofs = 0x454, }, + { .ofs = 0x458, }, + { .ofs = 0x464, }, +}; + +static struct rtk_reset_initdata cc_reset_initdata = { + .banks = cc_reset_banks, + .num_banks = ARRAY_SIZE(cc_reset_banks), +}; + +static struct clk_hw_map rtd1319_sys_map = { + .group = &(struct clk_hw_group) { + .hws = cc_hws, + .num_hws = ARRAY_SIZE(cc_hws), + }, + .start_index = 0, +}; + +static struct clk_pll rtd1311_pll_bus = { + .ssc_ofs = 0x520, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = bus_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_fixed_factor rtd1311_clk_sys = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + }, +}; + +static struct clk_pll rtd1311_pll_dcsb = { + .ssc_ofs = 0x540, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = dcsb_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_hw *rtd1311_cc_hws[] = { + [RTD1319_CRT_PLL_BUS] = &__clk_pll_hw(&rtd1311_pll_bus), + [RTD1319_CRT_PLL_DCSB] = &__clk_pll_hw(&rtd1311_pll_dcsb), + [RTD1319_CRT_CLK_SYS] = &rtd1311_clk_sys.hw, + [RTD1319_CRT_CLK_SYSH] = &clk_sysh.hw, + [RTD1319_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1319_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1319_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1), + [RTD1319_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2), + [RTD1319_CRT_PLL_DIF] = &__clk_pll_dif_hw(&pll_dif), + [RTD1319_CRT_PLL_PSAUD1A] = &__clk_pll_psaud_hw(&pll_psaud1a), + [RTD1319_CRT_PLL_PSAUD2A] = &__clk_pll_psaud_hw(&pll_psaud2a), + + [RTD1319_CRT_CLK_DET_PLL_BUS] = &__clk_det_hw(&clk_det_pll_bus), + [RTD1319_CRT_CLK_DET_PLL_DCSB] = &__clk_det_hw(&clk_det_pll_dcsb), + [RTD1319_CRT_CLK_DET_PLL_ACPU] = &__clk_det_hw(&clk_det_pll_acpu), + [RTD1319_CRT_CLK_DET_PLL_DDSA] = &__clk_det_hw(&clk_det_pll_ddsa), + [RTD1319_CRT_CLK_DET_PLL_GPU] = &__clk_det_hw(&clk_det_pll_gpu), + [RTD1319_CRT_CLK_DET_PLL_VE1] = &__clk_det_hw(&clk_det_pll_ve1), + [RTD1319_CRT_CLK_DET_PLL_VE2] = &__clk_det_hw(&clk_det_pll_ve2), +}; + +static struct clk_hw_map rtd1311_sys_map = { + .group = &(struct clk_hw_group) { + .hws = rtd1311_cc_hws, + .num_hws = ARRAY_SIZE(rtd1311_cc_hws), + }, + .start_index = 0, +}; + +static const struct freq_table rtd1312c_scpu_tbl[] = { + FREQ_NF(700000000, 22, 1896), + FREQ_NF(800000000, 26, 1289), + FREQ_NF(900000000, 30, 681), + FREQ_NF(918000000, 31, 0), + FREQ_NF(1000000000, 34, 75), + FREQ_NF(1100000000, 37, 1517), + FREQ_NF(1200000000, 41, 910), + FREQ_TABLE_END +}; + +static struct clk_pll rtd1312c_pll_scpu = { + .ssc_ofs = 0x500, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = rtd1312c_scpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table rtd1312c_ve_tbl[] = { + FREQ_NF(351000000, 23, 0), + FREQ_TABLE_END +}; + +static struct clk_pll rtd1312c_pll_ve1 = { + .ssc_ofs = 0x5E0, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = rtd1312c_ve_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve1", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_pll rtd1312c_pll_ve2 = { + .ssc_ofs = 0x600, + .pll_ofs = 0x1D0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = rtd1312c_ve_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve2", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_hw *rtd1312c_cc_hws[] = { + [RTD1319_CRT_PLL_SCPU] = &__clk_pll_hw(&rtd1312c_pll_scpu), + [RTD1319_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1319_CRT_PLL_DCSB] = &__clk_pll_div_hw(&pll_dcsb), + [RTD1319_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1319_CRT_CLK_SYSH] = &clk_sysh.hw, + [RTD1319_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1319_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1319_CRT_PLL_VE1] = &__clk_pll_hw(&rtd1312c_pll_ve1), + [RTD1319_CRT_PLL_VE2] = &__clk_pll_hw(&rtd1312c_pll_ve2), + [RTD1319_CRT_PLL_DIF] = &__clk_pll_dif_hw(&pll_dif), + [RTD1319_CRT_PLL_PSAUD1A] = &__clk_pll_psaud_hw(&pll_psaud1a), + [RTD1319_CRT_PLL_PSAUD2A] = &__clk_pll_psaud_hw(&pll_psaud2a), + + [RTD1319_CRT_CLK_DET_PLL_BUS] = &__clk_det_hw(&clk_det_pll_bus), + [RTD1319_CRT_CLK_DET_PLL_DCSB] = &__clk_det_hw(&clk_det_pll_dcsb), + [RTD1319_CRT_CLK_DET_PLL_ACPU] = &__clk_det_hw(&clk_det_pll_acpu), + [RTD1319_CRT_CLK_DET_PLL_DDSA] = &__clk_det_hw(&clk_det_pll_ddsa), + [RTD1319_CRT_CLK_DET_PLL_GPU] = &__clk_det_hw(&clk_det_pll_gpu), + [RTD1319_CRT_CLK_DET_PLL_VE1] = &__clk_det_hw(&clk_det_pll_ve1), + [RTD1319_CRT_CLK_DET_PLL_VE2] = &__clk_det_hw(&clk_det_pll_ve2), +}; + +static struct clk_hw_map rtd1312c_sys_map = { + .group = &(struct clk_hw_group) { + .hws = rtd1312c_cc_hws, + .num_hws = ARRAY_SIZE(rtd1312c_cc_hws), + }, + .start_index = 0, +}; + +static int rtd1319_cc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + const struct clk_hw_map *map; + + map = of_device_get_match_data(dev); + if (!map) + return -EINVAL; + + data = rtk_clk_alloc_data(RTD1319_CRT_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_hw_map(dev, data, map); + + rtk_clk_add_composites(dev, data, cc_composites, + ARRAY_SIZE(cc_composites)); + rtk_clk_add_gates(dev, data, cc_gates, ARRAY_SIZE(cc_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + cc_reset_initdata.lock = data->lock; + cc_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &cc_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1319_cc_match[] = { + { .compatible = "realtek,rtd1319-crt-clk", .data = &rtd1319_sys_map, }, + { .compatible = "realtek,rtd1311-crt-clk", .data = &rtd1311_sys_map, }, + { .compatible = "realtek,rtd1319-crt-clk-n", .data = &rtd1311_sys_map, }, + { .compatible = "realtek,rtd1312c-crt-clk", .data = &rtd1312c_sys_map, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1319_cc_match); + +static struct platform_driver rtd1319_cc_driver = { + .probe = rtd1319_cc_probe, + .driver = { + .name = "rtk-rtd1319-crt-clk", + .of_match_table = of_match_ptr(rtd1319_cc_match), + }, +}; + +static int __init rtd1319_cc_init(void) +{ + return platform_driver_register(&rtd1319_cc_driver); +} +core_initcall(rtd1319_cc_init); +MODULE_DESCRIPTION("Reatek RTD1319 CRT Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1319-ic.c b/drivers/clk/realtek/clk-rtd1319-ic.c new file mode 100644 index 000000000000..3c82af65ad0d --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1319-ic.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +static struct clk_gate_data ic_gates[] = { + GATE(RTD1319_ISO_CLK_EN_LSADC_ECOA2, "lsadc_ecoa2", NULL, 0x8C, 0), + GATE(RTD1319_ISO_CLK_EN_CEC0, "cec0", NULL, 0x8C, 2), + GATE(RTD1319_ISO_CLK_EN_CBUSRX_SYS, "cbusrx_sys", NULL, 0x8C, 3), + GATE(RTD1319_ISO_CLK_EN_CBUSTX_SYS, "cbustx_sys", NULL, 0x8C, 4), + GATE(RTD1319_ISO_CLK_EN_CBUS_SYS, "cbus_sys", NULL, 0x8C, 5), + GATE(RTD1319_ISO_CLK_EN_CBUS_OSC, "cbus_osc", NULL, 0x8C, 6), + GATE(RTD1319_ISO_CLK_EN_IR, "ir", NULL, 0x8C, 7), + GATE(RTD1319_ISO_CLK_EN_UR0, "ur0", NULL, 0x8C, 8), + GATE(RTD1319_ISO_CLK_EN_I2C0, "i2c0", NULL, 0x8C, 9), + GATE(RTD1319_ISO_CLK_EN_I2C1, "i2c1", NULL, 0x8C, 10), + GATE(RTD1319_ISO_CLK_EN_ETN_250M, "etn_250m", NULL, 0x8C, 11), + GATE(RTD1319_ISO_CLK_EN_ETN_SYS, "etn_sys", NULL, 0x8C, 12), + GATE(RTD1319_ISO_CLK_EN_USB_DRD, "usb_drd", NULL, 0x8C, 13), + GATE(RTD1319_ISO_CLK_EN_USB_HOST, "usb_host", NULL, 0x8C, 14), + GATE(RTD1319_ISO_CLK_EN_USB_U3_HOST, "usb_u3_host", NULL, 0x8C, 15), + GATE(RTD1319_ISO_CLK_EN_USB, "usb", NULL, 0x8C, 16), + GATE(RTD1319_ISO_CLK_EN_ISO_GSPI, "iso_gspi", NULL, 0x64, 9), +}; + +static struct rtk_reset_bank ic_reset_banks[] = { + { .ofs = 0x88, }, +}; + +static struct rtk_reset_initdata ic_reset_initdata = { + .banks = ic_reset_banks, + .num_banks = ARRAY_SIZE(ic_reset_banks), +}; + +static int rtd1319_ic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1319_ISO_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_gates(dev, data, ic_gates, ARRAY_SIZE(ic_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + ic_reset_initdata.lock = data->lock; + ic_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &ic_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1319_ic_match[] = { + { .compatible = "realtek,rtd1319-iso-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1319_ic_match); + +static struct platform_driver rtd1319_ic_driver = { + .probe = rtd1319_ic_probe, + .driver = { + .name = "rtk-rtd1319-iso-clk", + .of_match_table = of_match_ptr(rtd1319_ic_match), + }, +}; + +static int __init rtd1319_ic_init(void) +{ + return platform_driver_register(&rtd1319_ic_driver); +} +core_initcall(rtd1319_ic_init); +MODULE_DESCRIPTION("Reatek RTD1319 ISO Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1395-cc.c b/drivers/clk/realtek/clk-rtd1395-cc.c new file mode 100644 index 000000000000..2e06dc42b6de --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1395-cc.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "clk-det.h" +#include "reset.h" +#include + +#define DIV_DV(_r, _d, _v) { .rate = _r, .div = _d, .val = _v, } +#define FREQ_NF_MASK (0x7FFFF) +#define FREQ_NF(_r, _n, _f) { .rate = _r, .val = ((_n) << 11) | (_f), } +#define FREQ_MNO_MASK (0x63FF0) +#define FREQ_MNO(_r, _m, _n, _o) \ + { .rate = _r, .val = ((_m) << 4) | ((_n) << 12) | ((_o) << 17), } + +static const char * const default_parent[] = { "osc27m" }; + +static const struct div_table scpu_div_tbl[] = { + DIV_DV(1000000000, 1, 0x00), + DIV_DV(500000000, 2, 0x02), + DIV_DV(250000000, 4, 0x03), + DIV_DV(200000000, 8, 0xA0), + DIV_DV(100000000, 10, 0xC0), + DIV_TABLE_END +}; + +static const struct freq_table scpu_tbl[] = { + FREQ_NF(1000000000, 34, 75), + FREQ_NF(1100000000, 37, 1517), + FREQ_NF(1200000000, 41, 910), + FREQ_NF(1300000000, 45, 303), + FREQ_NF(1400000000, 48, 1745), + FREQ_NF(1500000000, 52, 1137), + FREQ_NF(1600000000, 56, 530), + FREQ_NF(1800000000, 63, 1365), + FREQ_NF(1000000000, 35, 0), + FREQ_NF(1800000000, 65, 0), + FREQ_NF(1800000000, 64, 0), + FREQ_NF(1400000001, 45, 301), + FREQ_NF(1500000001, 45, 302), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_scpu = { + .div_ofs = 0x030, + .div_shift = 6, + .div_width = 8, + .div_tbl = scpu_div_tbl, + .clkp = { + .ssc_ofs = 0x500, + .pll_ofs = CLK_OFS_INVALID, + .freq_tbl = scpu_tbl, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct div_table bus_div_tbl[] = { + DIV_DV(257000000, 1, 0), + DIV_DV(129000000, 2, 2), + DIV_DV(65000000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table bus_tbl[] = { + FREQ_NF(513000000, 35, 0), + FREQ_NF(423000000, 29, 0), + FREQ_NF(400000000, 26, 1289), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_bus = { + .div_ofs = 0x030, + .div_shift = 0, + .div_width = 2, + .div_tbl = bus_div_tbl, + .clkp = { + .ssc_ofs = 0x520, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = bus_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static struct clk_fixed_factor clk_sys = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct div_table dcsb_div_tbl[] = { + DIV_DV(250000000, 1, 0), + DIV_DV(125000000, 2, 2), + DIV_DV(62500000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table dcsb_tbl[] = { + FREQ_NF(500000000, 34, 0), + FREQ_NF(450000000, 30, 682), + FREQ_NF(351000000, 23, 0), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_dcsb = { + .div_ofs = 0x030, + .div_shift = 2, + .div_width = 2, + .div_tbl = dcsb_div_tbl, + .clkp = { + .ssc_ofs = 0x540, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = dcsb_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static struct clk_fixed_factor clk_sysh = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sysh", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_dcsb" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_table ddsx_tbl[] = { + FREQ_NF(432000000, 13, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ddsa = { + .ssc_ofs = 0x560, + .pll_ofs = 0x120, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = ddsx_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsa", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_pll pll_ddsb = { + .ssc_ofs = 0x580, + .pll_ofs = 0x174, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = ddsx_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsb", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table gpu_tbl[] = { + FREQ_NF(300000000, 19, 455), + FREQ_NF(400000000, 26, 1289), + FREQ_NF(500000000, 34, 75), + FREQ_NF(600000000, 41, 910), + FREQ_NF(700000000, 48, 1745), + FREQ_NF(750000000, 52, 1137), + FREQ_NF(800000000, 56, 530), + FREQ_NF(850000000, 59, 1971), + FREQ_TABLE_END +}; + +static struct clk_pll pll_gpu = { + .ssc_ofs = 0x5A0, + .pll_ofs = 0x1C0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = gpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_gpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table ve_tbl[] = { + FREQ_MNO(189000000, 12, 0, 1), + FREQ_MNO(270000000, 18, 0, 1), + FREQ_MNO(405000000, 13, 0, 0), + FREQ_MNO(432000000, 14, 0, 0), + FREQ_MNO(459000000, 15, 0, 0), + FREQ_MNO(486000000, 16, 0, 0), + FREQ_MNO(513000000, 17, 0, 0), + FREQ_MNO(540000000, 18, 0, 0), + FREQ_MNO(550000000, 59, 2, 0), + FREQ_MNO(567000000, 19, 0, 0), + FREQ_MNO(594000000, 20, 0, 0), + FREQ_MNO(648000000, 22, 0, 0), + FREQ_MNO(675000000, 23, 0, 0), + FREQ_MNO(702000000, 24, 0, 0), + FREQ_MNO(715000000, 51, 1, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ve1 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve1", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_pll pll_ve2 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x1D0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve2", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_det clk_det_pll_bus = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_bus", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x424, +}; + +static struct clk_det clk_det_pll_dcsb = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_dcsb", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x428, +}; + +static struct clk_det clk_det_pll_acpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_acpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x42c, +}; + +static struct clk_det clk_det_pll_ddsa = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ddsa", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x430, +}; + +static struct clk_det clk_det_pll_ddsb = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ddsb", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x434, +}; + +static struct clk_det clk_det_pll_gpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_gpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x438, +}; + +static struct clk_det clk_det_pll_ve1 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve1", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x43c, +}; + +static struct clk_det clk_det_pll_ve2 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve2", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x440, +}; + +static struct clk_hw *cc_hws[] = { + [RTD1395_CRT_PLL_SCPU] = &__clk_pll_div_hw(&pll_scpu), + [RTD1395_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1395_CRT_PLL_DCSB] = &__clk_pll_div_hw(&pll_dcsb), + [RTD1395_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1395_CRT_PLL_DDSB] = &__clk_pll_hw(&pll_ddsb), + [RTD1395_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1395_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1), + [RTD1395_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2), + [RTD1395_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1395_CRT_CLK_SYSH] = &clk_sysh.hw, + + [RTD1395_CRT_CLK_DET_PLL_BUS] = &__clk_det_hw(&clk_det_pll_bus), + [RTD1395_CRT_CLK_DET_PLL_DCSB] = &__clk_det_hw(&clk_det_pll_dcsb), + [RTD1395_CRT_CLK_DET_PLL_ACPU] = &__clk_det_hw(&clk_det_pll_acpu), + [RTD1395_CRT_CLK_DET_PLL_DDSA] = &__clk_det_hw(&clk_det_pll_ddsa), + [RTD1395_CRT_CLK_DET_PLL_DDSB] = &__clk_det_hw(&clk_det_pll_ddsb), + [RTD1395_CRT_CLK_DET_PLL_GPU] = &__clk_det_hw(&clk_det_pll_gpu), + [RTD1395_CRT_CLK_DET_PLL_VE1] = &__clk_det_hw(&clk_det_pll_ve1), + [RTD1395_CRT_CLK_DET_PLL_VE2] = &__clk_det_hw(&clk_det_pll_ve2), +}; + +static const char * const ve_parents[] = { + "pll_ve1", + "pll_ve2", + "clk_sysh", + "clk_sysh", + "pll_ddsa", +}; + +static struct clk_composite_data cc_composites[] = { + { + .id = RTD1395_CRT_CLK_GPU, + .gate_ofs = 0x00C, + .gate_shift = 11, + .parent_names = (const char *[]){ "pll_gpu" }, + .mux_ofs = CLK_OFS_INVALID, + .num_parents = 1, + .name = "clk_gpu", + .flags = CLK_SET_RATE_PARENT, + .shared = 1, + }, + { + .id = RTD1395_CRT_CLK_VE1, + .gate_ofs = 0x00C, + .gate_shift = 12, + .parent_names = ve_parents, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 0, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve1", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .shared = 1, + }, + { + .id = RTD1395_CRT_CLK_VE2, + .gate_ofs = 0x00C, + .gate_shift = 13, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 3, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve2", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .shared = 1, + }, + { + .id = RTD1395_CRT_CLK_VE2_BPU, + .gate_ofs = CLK_OFS_INVALID, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 9, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve2_bpu", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 1) +#define GATE_CRITICAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IS_CRITICAL, _ofs, _shift) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) +#define GATE_IGNORE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IGNORE_UNUSED, _ofs, _shift) + +static struct clk_gate_data cc_gates[] = { + GATE_CRITICAL(RTD1395_CRT_CLK_EN_MISC, "misc", NULL, 0x0C, 0), + GATE(RTD1395_CRT_CLK_EN_PCIE0, "pcie0", NULL, 0x0C, 1), + GATE(RTD1395_CRT_CLK_EN_GSPI, "gspi", "misc", 0x0C, 3), + GATE(RTD1395_CRT_CLK_EN_SDS, "sds", NULL, 0x0C, 7), + GATE_IGNORE(RTD1395_CRT_CLK_EN_HDMI, "hdmi", NULL, 0x0C, 8), + GATE(RTD1395_CRT_CLK_EN_LSADC, "lsadc", NULL, 0x0C, 16), + GATE(RTD1395_CRT_CLK_EN_SE, "se", NULL, 0x0C, 17), + GATE_IGNORE(RTD1395_CRT_CLK_EN_CP, "cp", NULL, 0x0C, 19), + GATE_IGNORE(RTD1395_CRT_CLK_EN_MD, "md", NULL, 0x0C, 20), + GATE_IGNORE(RTD1395_CRT_CLK_EN_TP, "tp", NULL, 0x0C, 21), + GATE(RTD1395_CRT_CLK_EN_RSA, "rsa", NULL, 0x0C, 22), + GATE(RTD1395_CRT_CLK_EN_NF, "nf", NULL, 0x0C, 23), + GATE(RTD1395_CRT_CLK_EN_EMMC, "emmc", NULL, 0x0C, 24), + GATE(RTD1395_CRT_CLK_EN_CR, "cr", NULL, 0x0C, 25), + GATE(RTD1395_CRT_CLK_EN_SDIO_IP, "sdio_ip", NULL, 0x0C, 26), + GATE(RTD1395_CRT_CLK_EN_MIPI, "mipi", NULL, 0x0C, 27), + GATE(RTD1395_CRT_CLK_EN_EMMC_IP, "emmc_ip", NULL, 0x0C, 28), + GATE(RTD1395_CRT_CLK_EN_SDIO, "sdio", NULL, 0x0C, 30), + GATE(RTD1395_CRT_CLK_EN_SD_IP, "sd_ip", NULL, 0x0C, 31), + GATE(RTD1395_CRT_CLK_EN_MISC_I2C_5, "i2c5", "misc", 0x10, 1), + GATE(RTD1395_CRT_CLK_EN_JPEG, "jpeg", NULL, 0x10, 3), + GATE(RTD1395_CRT_CLK_EN_MISC_SC, "sc", "misc", 0x10, 6), + GATE(RTD1395_CRT_CLK_EN_HSE, "hse", NULL, 0x10, 25), + GATE(RTD1395_CRT_CLK_EN_UR2, "ur2", "misc", 0x10, 27), + GATE(RTD1395_CRT_CLK_EN_UR1, "ur1", "misc", 0x10, 28), + GATE(RTD1395_CRT_CLK_EN_FAN, "fan", "misc", 0x10, 29), +}; + +static struct rtk_reset_bank cc_reset_banks[] = { + { .ofs = 0x00, }, + { .ofs = 0x04, }, + { .ofs = 0x50, }, +}; + +static struct rtk_reset_initdata cc_reset_initdata = { + .banks = cc_reset_banks, + .num_banks = ARRAY_SIZE(cc_reset_banks), + .shared = 1, +}; + +static int rtd1395_cc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1395_CRT_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_hws(dev, data, cc_hws, ARRAY_SIZE(cc_hws)); + rtk_clk_add_composites(dev, data, cc_composites, + ARRAY_SIZE(cc_composites)); + rtk_clk_add_gates(dev, data, cc_gates, ARRAY_SIZE(cc_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + cc_reset_initdata.lock = data->lock; + cc_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &cc_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1395_cc_match[] = { + { .compatible = "realtek,rtd1395-crt-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1395_cc_match); + +static struct platform_driver rtd1395_cc_driver = { + .probe = rtd1395_cc_probe, + .driver = { + .name = "rtk-rtd1395-crt-clk", + .of_match_table = of_match_ptr(rtd1395_cc_match), + }, +}; + +static int __init rtd1395_cc_init(void) +{ + return platform_driver_register(&rtd1395_cc_driver); +} +core_initcall(rtd1395_cc_init); +MODULE_DESCRIPTION("Reatek RTD1395 CRT Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1395-ic.c b/drivers/clk/realtek/clk-rtd1395-ic.c new file mode 100644 index 000000000000..7a5da4eb58ab --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1395-ic.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +static struct clk_gate_data ic_gates[] = { + GATE(RTD1395_ISO_CLK_EN_CEC0, "cec0", NULL, 0x8C, 2), + GATE(RTD1395_ISO_CLK_EN_CBUSRX_SYS, "cbusrx_sys", NULL, 0x8C, 3), + GATE(RTD1395_ISO_CLK_EN_CBUSTX_SYS, "cbustx_sys", NULL, 0x8C, 4), + GATE(RTD1395_ISO_CLK_EN_CBUS_SYS, "cbus_sys", NULL, 0x8C, 5), + GATE(RTD1395_ISO_CLK_EN_CBUS_OSC, "cbus_osc", NULL, 0x8C, 6), + GATE(RTD1395_ISO_CLK_EN_IR, "misc_ir", NULL, 0x8C, 7), + GATE(RTD1395_ISO_CLK_EN_UR0, "ur0", NULL, 0x8C, 8), + GATE(RTD1395_ISO_CLK_EN_I2C0, "i2c0", NULL, 0x8C, 9), + GATE(RTD1395_ISO_CLK_EN_I2C1, "i2c1", NULL, 0x8C, 10), + GATE(RTD1395_ISO_CLK_EN_ETN_250M, "etn_250m", NULL, 0x8C, 11), + GATE(RTD1395_ISO_CLK_EN_ETN_SYS, "etn_sys", NULL, 0x8C, 12), + GATE(RTD1395_ISO_CLK_EN_USB_DRD, "usb_drd", NULL, 0x8C, 13), + GATE(RTD1395_ISO_CLK_EN_USB_HOST_0, "usb_host_0", NULL, 0x8C, 14), + GATE(RTD1395_ISO_CLK_EN_USB_HOST_1, "usb_host_1", NULL, 0x8C, 15), + GATE(RTD1395_ISO_CLK_EN_USB, "usb", NULL, 0x8C, 16), +}; + +static struct rtk_reset_bank ic_reset_banks[] = { + { .ofs = 0x88, }, +}; + +static struct rtk_reset_initdata ic_reset_initdata = { + .banks = ic_reset_banks, + .num_banks = ARRAY_SIZE(ic_reset_banks), +}; + +static int rtd1395_ic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1395_ISO_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_gates(dev, data, ic_gates, ARRAY_SIZE(ic_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + ic_reset_initdata.lock = data->lock; + ic_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &ic_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1395_ic_match[] = { + { .compatible = "realtek,rtd1395-iso-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1395_ic_match); + +static struct platform_driver rtd1395_ic_driver = { + .probe = rtd1395_ic_probe, + .driver = { + .name = "rtk-rtd1395-iso-clk", + .of_match_table = of_match_ptr(rtd1395_ic_match), + }, +}; + +static int __init rtd1395_ic_init(void) +{ + return platform_driver_register(&rtd1395_ic_driver); +} +core_initcall(rtd1395_ic_init); +MODULE_DESCRIPTION("Reatek RTD1395 ISO Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1619-cc.c b/drivers/clk/realtek/clk-rtd1619-cc.c new file mode 100644 index 000000000000..b48d7b140138 --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1619-cc.c @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "clk-det.h" +#include "reset.h" +#include +#include + +#define DIV_DV(_r, _d, _v) { .rate = _r, .div = _d, .val = _v, } +#define FREQ_NF_MASK (0x7FFFF) +#define FREQ_NF(_r, _n, _f) { .rate = _r, .val = ((_n) << 11) | (_f), } +#define FREQ_MNO_MASK (0x63FF0) +#define FREQ_MNO(_r, _m, _n, _o) \ + { .rate = _r, .val = ((_m) << 4) | ((_n) << 12) | ((_o) << 17), } + +static const char * const default_parent[] = { "osc27m" }; + +static const struct div_table scpu_div_tbl[] = { + DIV_DV(1000000000, 1, 0), + DIV_DV(500000000, 2, 0x88), + DIV_DV(350000000, 3, 0x8C), + DIV_DV(250000000, 4, 0x90), + DIV_DV(200000000, 8, 0xA0), + DIV_DV(100000000, 10, 0xA8), + DIV_TABLE_END +}; + +static const struct freq_table scpu_tbl[] = { + FREQ_NF(1000000000, 34, 75), + FREQ_NF(1100000000, 37, 1517), + FREQ_NF(1200000000, 41, 910), + FREQ_NF(1300000000, 45, 303), + FREQ_NF(1400000000, 48, 1745), + FREQ_NF(1500000000, 52, 1137), + FREQ_NF(1600000000, 56, 530), + FREQ_NF(1700000000, 59, 1972), + FREQ_NF(1800000000, 63, 1365), + FREQ_NF(1900000000, 67, 758), + FREQ_NF(2000000000, 71, 151), + /* init-value mapping */ + FREQ_NF(1000000000, 35, 0), + FREQ_NF(1200000000, 41, 0), + FREQ_NF(1800000000, 65, 0), + FREQ_NF(1800000000, 64, 0), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_scpu = { + .div_ofs = 0x030, + .div_shift = 6, + .div_width = 8, + .div_tbl = scpu_div_tbl, + .clkp = { + .ssc_ofs = 0x500, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = scpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct div_table bus_div_tbl[] = { + DIV_DV(257000000, 1, 0), + DIV_DV(129000000, 2, 2), + DIV_DV(65000000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table bus_tbl[] = { + FREQ_NF(513000000, 35, 0), + FREQ_NF(400000000, 26, 1289), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_bus = { + .div_ofs = 0x030, + .div_shift = 0, + .div_width = 2, + .div_tbl = bus_div_tbl, + .clkp = { + .ssc_ofs = 0x520, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = bus_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct div_table dcsb_div_tbl[] = { + DIV_DV(500000000, 1, 0), + DIV_DV(250000000, 2, 2), + DIV_DV(1, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table dcsb_tbl[] = { + FREQ_NF(526500000, 36, 0), + FREQ_NF(553500000, 38, 0), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_dcsb = { + .div_ofs = 0x030, + .div_shift = 2, + .div_width = 2, + .div_tbl = dcsb_div_tbl, + .clkp = { + .ssc_ofs = 0x540, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = dcsb_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static struct clk_fixed_factor clk_sys = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor clk_sysh = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sysh", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_dcsb" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_table ddsx_tbl[] = { + FREQ_NF(432000000, 13, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ddsa = { + .ssc_ofs = 0x560, + .pll_ofs = 0x120, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = ddsx_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsa", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table gpu_tbl[] = { + FREQ_NF(300000000, 19, 455), + FREQ_NF(400000000, 26, 1289), + FREQ_NF(500000000, 34, 75), + FREQ_NF(600000000, 41, 910), + FREQ_NF(650000000, 45, 303), + FREQ_NF(700000000, 48, 1745), + FREQ_NF(750000000, 52, 1137), + FREQ_NF(800000000, 56, 530), + FREQ_NF(850000000, 59, 1971), + FREQ_TABLE_END +}; + +static struct clk_pll pll_gpu = { + .ssc_ofs = 0x5A0, + .pll_ofs = 0x1C0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = gpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_gpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table ve_tbl[] = { + FREQ_MNO(189000000, 12, 0, 1), + FREQ_MNO(270000000, 18, 0, 1), + FREQ_MNO(405000000, 13, 0, 0), + FREQ_MNO(432000000, 14, 0, 0), + FREQ_MNO(459000000, 15, 0, 0), + FREQ_MNO(486000000, 16, 0, 0), + FREQ_MNO(513000000, 17, 0, 0), + FREQ_MNO(540000000, 18, 0, 0), + FREQ_MNO(550000000, 59, 2, 0), + FREQ_MNO(567000000, 19, 0, 0), + FREQ_MNO(594000000, 20, 0, 0), + FREQ_MNO(648000000, 22, 0, 0), + FREQ_MNO(675000000, 23, 0, 0), + FREQ_MNO(702000000, 24, 0, 0), + FREQ_MNO(715000000, 51, 1, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ve1 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve1", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_pll pll_ve2 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x1D0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve2", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, +}; + +static struct clk_pll_dif pll_dif = { + .ssc_ofs = 0x634, + .pll_ofs = 0x624, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dif", + .ops = &clk_pll_dif_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, + .adtv_conf = { + 0x00000048, 0x00020c00, 0x204004ca, 0x8000a000, + 0x00420c00, 0x00420c03, 0x00000078, 0x204084ca, + }, +}; + +static struct clk_pll_psaud pll_psaud1a = { + .reg = 0x130, + .id = CLK_PLL_PSAUD1A, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_psaud1a", + .ops = &clk_pll_psaud_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_UNGATE, + }, +}; + +static struct clk_pll_psaud pll_psaud2a = { + .reg = 0x130, + .id = CLK_PLL_PSAUD2A, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_psaud2a", + .ops = &clk_pll_psaud_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_UNGATE, + }, +}; + +static struct clk_det clk_det_pll_bus = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_bus", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x424, +}; + +static struct clk_det clk_det_pll_dcsb = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_dcsb", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x428, +}; + +static struct clk_det clk_det_pll_acpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_acpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x42c, +}; + +static struct clk_det clk_det_pll_ddsa = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ddsa", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x430, +}; + +static struct clk_det clk_det_pll_gpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_gpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x438, +}; + +static struct clk_det clk_det_pll_ve1 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve1", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x43c, +}; + +static struct clk_det clk_det_pll_ve2 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve2", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x440, +}; + +static struct clk_hw *cc_hws[] = { + [RTD1619_CRT_PLL_SCPU] = &__clk_pll_div_hw(&pll_scpu), + [RTD1619_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1619_CRT_PLL_DCSB] = &__clk_pll_div_hw(&pll_dcsb), + [RTD1619_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1619_CRT_CLK_SYSH] = &clk_sysh.hw, + [RTD1619_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1619_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1619_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1), + [RTD1619_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2), + [RTD1619_CRT_PLL_DIF] = &__clk_pll_dif_hw(&pll_dif), + [RTD1619_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1619_CRT_CLK_SYSH] = &clk_sysh.hw, + [RTD1619_CRT_PLL_PSAUD1A] = &__clk_pll_psaud_hw(&pll_psaud1a), + [RTD1619_CRT_PLL_PSAUD2A] = &__clk_pll_psaud_hw(&pll_psaud2a), + + [RTD1619_CRT_CLK_DET_PLL_BUS] = &__clk_det_hw(&clk_det_pll_bus), + [RTD1619_CRT_CLK_DET_PLL_DCSB] = &__clk_det_hw(&clk_det_pll_dcsb), + [RTD1619_CRT_CLK_DET_PLL_ACPU] = &__clk_det_hw(&clk_det_pll_acpu), + [RTD1619_CRT_CLK_DET_PLL_DDSA] = &__clk_det_hw(&clk_det_pll_ddsa), + [RTD1619_CRT_CLK_DET_PLL_GPU] = &__clk_det_hw(&clk_det_pll_gpu), + [RTD1619_CRT_CLK_DET_PLL_VE1] = &__clk_det_hw(&clk_det_pll_ve1), + [RTD1619_CRT_CLK_DET_PLL_VE2] = &__clk_det_hw(&clk_det_pll_ve2), +}; + +static const char * const ve_parents[] = { + "clk_sys", + "clk_sysh", + "pll_ve1", + "pll_ve2", +}; + +static struct clk_composite_data cc_composites[] = { + { + .id = RTD1619_CRT_CLK_GPU, + .mux_ofs = CLK_OFS_INVALID, + .gate_ofs = 0x050, + .gate_shift = 18, + .gate_write_en = 1, + .parent_names = (const char *[]){ "pll_gpu" }, + .num_parents = 1, + .name = "clk_gpu", + .flags = CLK_SET_RATE_PARENT, + }, + { + .id = RTD1619_CRT_CLK_VE1, + .gate_ofs = 0x050, + .gate_shift = 20, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 0, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve1", + .flags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1619_CRT_CLK_VE2, + .gate_ofs = 0x050, + .gate_shift = 22, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 3, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve2", + .flags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1619_CRT_CLK_VE3, + .gate_ofs = 0x05C, + .gate_shift = 26, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 6, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve3", + .flags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1619_CRT_CLK_VE2_BPU, + .gate_ofs = CLK_OFS_INVALID, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 9, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve2_bpu", + .flags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT, + }, +}; + + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 1, 0) +#define GATE_CRITICAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IS_CRITICAL, _ofs, _shift) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) +#define GATE_IGNORE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IGNORE_UNUSED, _ofs, _shift) + +static struct clk_gate_data cc_gates[] = { + GATE_CRITICAL(RTD1619_CRT_CLK_EN_MISC, "misc", NULL, 0x50, 0), + GATE(RTD1619_CRT_CLK_EN_PCIE0, "pcie0", NULL, 0x50, 2), + GATE(RTD1619_CRT_CLK_EN_GSPI, "gspi", "misc", 0x50, 6), + GATE(RTD1619_CRT_CLK_EN_SDS, "sds", NULL, 0x50, 12), + GATE_IGNORE(RTD1619_CRT_CLK_EN_HDMI, "hdmi", NULL, 0x50, 14), + GATE_IGNORE(RTD1619_CRT_CLK_EN_TVE, "tve", NULL, 0x50, 24), + GATE_IGNORE(RTD1619_CRT_CLK_EN_VO, "vo", NULL, 0x50, 26), + GATE_IGNORE(RTD1619_CRT_CLK_EN_LSADC, "lsadc", NULL, 0x50, 28), + GATE(RTD1619_CRT_CLK_EN_SE, "se", NULL, 0x50, 30), + GATE_IGNORE(RTD1619_CRT_CLK_EN_CP, "cp", NULL, 0x54, 2), + GATE_IGNORE(RTD1619_CRT_CLK_EN_MD, "md", NULL, 0x54, 4), + GATE_IGNORE(RTD1619_CRT_CLK_EN_TP, "tp", NULL, 0x54, 6), + GATE(RTD1619_CRT_CLK_EN_RSA, "rsa", NULL, 0x54, 8), + GATE(RTD1619_CRT_CLK_EN_NF, "nf", NULL, 0x54, 10), + GATE(RTD1619_CRT_CLK_EN_EMMC, "emmc", NULL, 0x54, 12), + GATE(RTD1619_CRT_CLK_EN_SD, "sd", NULL, 0x54, 14), + GATE(RTD1619_CRT_CLK_EN_SDIO_IP, "sdio_ip", NULL, 0x54, 16), + GATE(RTD1619_CRT_CLK_EN_MIPI, "mipi", NULL, 0x54, 18), + GATE(RTD1619_CRT_CLK_EN_EMMC_IP, "emmc_ip", NULL, 0x54, 20), + GATE(RTD1619_CRT_CLK_EN_SDIO, "sdio", NULL, 0x54, 22), + GATE(RTD1619_CRT_CLK_EN_SD_IP, "sd_ip", NULL, 0x54, 24), + GATE(RTD1619_CRT_CLK_EN_CABLERX, "cablerx", NULL, 0x54, 26), + GATE(RTD1619_CRT_CLK_EN_TPB, "tpb", NULL, 0x54, 28), + GATE(RTD1619_CRT_CLK_EN_MISC_SC1, "sc1", "misc", 0x54, 30), + GATE(RTD1619_CRT_CLK_EN_MISC_I2C_3, "i2c3", "misc", 0x58, 0), + GATE(RTD1619_CRT_CLK_EN_JPEG, "jpeg", NULL, 0x58, 4), + GATE(RTD1619_CRT_CLK_EN_MISC_SC0, "sc0", "misc", 0x58, 10), + GATE(RTD1619_CRT_CLK_EN_HDMIRX, "hdmirx", NULL, 0x58, 26), + GATE(RTD1619_CRT_CLK_EN_HSE, "hse", NULL, 0x58, 28), + GATE(RTD1619_CRT_CLK_EN_UR2, "ur2", "misc", 0x58, 30), + GATE(RTD1619_CRT_CLK_EN_UR1, "ur1", "misc", 0x5C, 0), + GATE(RTD1619_CRT_CLK_EN_FAN, "fan", "misc", 0x5C, 2), + GATE(RTD1619_CRT_CLK_EN_SATA_WRAP_SYS, "sata_wrap_sys", NULL, 0x5C, 8), + GATE(RTD1619_CRT_CLK_EN_SATA_WRAP_SYSH, "sata_wrap_sysh", NULL, 0x5C, 10), + GATE(RTD1619_CRT_CLK_EN_SATA_MAC_SYSH, "sata_mac_sysh", NULL, 0x5C, 12), + GATE(RTD1619_CRT_CLK_EN_R2RDSC, "r2rdsc", NULL, 0x5C, 14), + GATE(RTD1619_CRT_CLK_EN_PCIE1, "pcie1", NULL, 0x5C, 18), + GATE(RTD1619_CRT_CLK_EN_MISC_I2C_4, "i2c4", "misc", 0x5C, 20), + GATE(RTD1619_CRT_CLK_EN_MISC_I2C_5, "i2c5", "misc", 0x5C, 22), + GATE(RTD1619_CRT_CLK_EN_EDP, "edp", NULL, 0x5C, 28), + GATE_IGNORE(RTD1619_CRT_CLK_EN_TSIO_TRX, "tsio_trx", NULL, 0x5C, 30), +}; + +static struct rtk_reset_bank cc_reset_banks[] = { + { .ofs = 0x00, .write_en = 1, }, + { .ofs = 0x04, .write_en = 1, }, + { .ofs = 0x08, .write_en = 1, }, + { .ofs = 0x0c, .write_en = 1, }, + { .ofs = 0x68, .write_en = 1, }, +}; + +static struct rtk_reset_initdata cc_reset_initdata = { + .banks = cc_reset_banks, + .num_banks = ARRAY_SIZE(cc_reset_banks), +}; + +static struct clk_hw_map rtd1619_sys_map = { + .group = &(struct clk_hw_group){ + .hws = cc_hws, + .num_hws = ARRAY_SIZE(cc_hws), + }, + .start_index = 0, +}; + +static struct clk_hw_map rtd1611_sys_map = { + .group = &(struct clk_hw_group){ + .hws = cc_hws + RTD1619_CRT_CLK_SYS, + .num_hws = ARRAY_SIZE(cc_hws) - RTD1619_CRT_CLK_SYS, + }, + .start_index = RTD1619_CRT_CLK_SYS, +}; + +static int rtd1619_cc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + const struct clk_hw_map *map; + + map = of_device_get_match_data(dev); + if (!map) + return -EINVAL; + + data = rtk_clk_alloc_data(RTD1619_CRT_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + dev_err(dev, "failed to get init data from dt: %d\n", ret); + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_hw_map(dev, data, map); + rtk_clk_add_composites(dev, data, cc_composites, + ARRAY_SIZE(cc_composites)); + rtk_clk_add_gates(dev, data, cc_gates, ARRAY_SIZE(cc_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + cc_reset_initdata.lock = data->lock; + cc_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &cc_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1619_cc_match[] = { + { .compatible = "realtek,rtd1619-crt-clk", .data = &rtd1619_sys_map, }, + { .compatible = "realtek,rtd1611-crt-clk", .data = &rtd1611_sys_map, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1619_cc_match); + +static struct platform_driver rtd1619_cc_driver = { + .probe = rtd1619_cc_probe, + .driver = { + .name = "rtk-rtd1619-crt-clk", + .of_match_table = of_match_ptr(rtd1619_cc_match), + }, +}; + +static int __init rtd1619_cc_init(void) +{ + return platform_driver_register(&rtd1619_cc_driver); +} +core_initcall(rtd1619_cc_init); +MODULE_DESCRIPTION("Reatek RTD1619 CRT Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1619-ic.c b/drivers/clk/realtek/clk-rtd1619-ic.c new file mode 100644 index 000000000000..f17acc21d245 --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1619-ic.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "reset.h" +#include + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +static struct clk_gate_data ic_gates[] = { + GATE(RTD1619_ISO_CLK_EN_CEC0, "cec0", NULL, 0x8c, 2), + GATE(RTD1619_ISO_CLK_EN_CBUSRX_SYS, "cbusrx_sys", NULL, 0x8c, 3), + GATE(RTD1619_ISO_CLK_EN_CBUSTX_SYS, "cbustx_sys", NULL, 0x8c, 4), + GATE(RTD1619_ISO_CLK_EN_CBUS_SYS, "cbus_sys", NULL, 0x8c, 5), + GATE(RTD1619_ISO_CLK_EN_CBUS_OSC, "cbus_osc", NULL, 0x8c, 6), + GATE(RTD1619_ISO_CLK_EN_IR, "ir", NULL, 0x8c, 7), + GATE(RTD1619_ISO_CLK_EN_UR0, "ur0", NULL, 0x8c, 8), + GATE(RTD1619_ISO_CLK_EN_I2C0, "i2c0", NULL, 0x8c, 9), + GATE(RTD1619_ISO_CLK_EN_I2C1, "i2c1", NULL, 0x8c, 10), + GATE(RTD1619_ISO_CLK_EN_ETN_250M, "etn_250m", NULL, 0x8c, 11), + GATE(RTD1619_ISO_CLK_EN_ETN_SYS, "etn_sys", NULL, 0x8c, 12), + GATE(RTD1619_ISO_CLK_EN_USB_DRD, "usb_drd", NULL, 0x8c, 13), + GATE(RTD1619_ISO_CLK_EN_USB_HOST, "usb_host", NULL, 0x8c, 14), + GATE(RTD1619_ISO_CLK_EN_USB_U3_HOST, "usb_u3_host", NULL, 0x8c, 15), + GATE(RTD1619_ISO_CLK_EN_USB, "usb", NULL, 0x8c, 16), +}; + +static struct rtk_reset_bank ic_reset_banks[] = { + { .ofs = 0x88, }, +}; + +static struct rtk_reset_initdata ic_reset_initdata = { + .banks = ic_reset_banks, + .num_banks = ARRAY_SIZE(ic_reset_banks), +}; + +static int rtd1619_ic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1619_ISO_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_gates(dev, data, ic_gates, ARRAY_SIZE(ic_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + ic_reset_initdata.lock = data->lock; + ic_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &ic_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1619_ic_match[] = { + { .compatible = "realtek,rtd1619-iso-clk", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtd1619_ic_match); + +static struct platform_driver rtd1619_ic_driver = { + .probe = rtd1619_ic_probe, + .driver = { + .name = "rtk-rtd1619-iso-clk", + .of_match_table = of_match_ptr(rtd1619_ic_match), + }, +}; + +static int __init rtd1619_ic_init(void) +{ + return platform_driver_register(&rtd1619_ic_driver); +} +core_initcall(rtd1619_ic_init); +MODULE_DESCRIPTION("Reatek RTD1619 ISO Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1619b-cc.c b/drivers/clk/realtek/clk-rtd1619b-cc.c new file mode 100644 index 000000000000..09654b20d8ec --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1619b-cc.c @@ -0,0 +1,684 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "clk-det.h" +#include "reset.h" +#include +#include +#include "of-conf.h" + +#define DIV_DV(_r, _d, _v) { .rate = _r, .div = _d, .val = _v, } +#define FREQ_NF_MASK (0x7FFFF) +#define FREQ_NF(_r, _n, _f) { .rate = _r, .val = ((_n) << 11) | (_f), } +#define FREQ_MNO_MASK (0xe3FF0) +#define FREQ_MNO(_r, _m, _n, _o) \ + { .rate = _r, .val = ((_m) << 4) | ((_n) << 12) | ((_o) << 17), } + +static const char * const default_parent[] = { "osc27m" }; + +static const struct div_table scpu_div_tbl[] = { + DIV_DV(1000000000, 1, 0x00), + DIV_DV(500000000, 2, 0x88), + DIV_DV(250000000, 4, 0x90), + DIV_DV(200000000, 8, 0xA0), + DIV_DV(100000000, 10, 0xA8), + DIV_TABLE_END +}; + +static const struct freq_table scpu_tbl[] = { + FREQ_NF(1000000000, 34, 75), + FREQ_NF(1100000000, 37, 1517), + FREQ_NF(1200000000, 41, 910), + FREQ_NF(1200000000, 41, 0), + FREQ_NF(1300000000, 45, 303), + FREQ_NF(1400000000, 48, 1745), + FREQ_NF(1500000000, 52, 1137), + FREQ_NF(1600000000, 56, 530), + FREQ_NF(1700000000, 60, 0), + FREQ_NF(1800000000, 63, 1365), + FREQ_NF(1900000000, 67, 758), + FREQ_NF(2000000000, 71, 151), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_scpu = { + .div_ofs = 0x108, + .div_shift = 8, + .div_width = 8, + .div_tbl = scpu_div_tbl, + .clkp = { + .ssc_ofs = 0x500, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = scpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + }, +}; + +static const struct div_table bus_div_tbl[] = { + DIV_DV(257000000, 1, 0), + DIV_DV(129000000, 2, 2), + DIV_DV(65000000, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table bus_tbl[] = { + FREQ_NF(459000000, 0x1f, 0x000), + FREQ_NF(486000000, 0x21, 0x000), + FREQ_NF(499500000, 0x22, 0x000), + FREQ_NF(594000000, 0x23, 0x000), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_bus = { + .div_ofs = 0x030, + .div_shift = 0, + .div_width = 2, + .div_tbl = bus_div_tbl, + .clkp = { + .ssc_ofs = 0x520, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = bus_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_bus", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static const struct div_table dcsb_div_tbl[] = { + DIV_DV(300000000, 1, 0), + DIV_DV(1, 2, 2), + DIV_DV(1, 4, 3), + DIV_TABLE_END +}; + +static const struct freq_table dcsb_tbl[] = { + FREQ_NF(351000000, 0x1a, 0x000), + FREQ_NF(405000000, 0x1b, 0x000), + FREQ_NF(459000000, 0x1f, 0x000), + FREQ_NF(472000000, 0x1f, 0x7b4), + FREQ_NF(499500000, 0x22, 0x000), + FREQ_NF(567000000, 0x27, 0x000), + FREQ_NF(594000000, 0x29, 0x000), + FREQ_TABLE_END +}; + +static struct clk_pll_div pll_dcsb = { + .div_ofs = 0x030, + .div_shift = 2, + .div_width = 2, + .div_tbl = dcsb_div_tbl, + .clkp = { + .ssc_ofs = 0x540, + .pll_ofs = CLK_OFS_INVALID, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = dcsb_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dcsb", + .ops = &clk_pll_div_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | + CLK_GET_RATE_NOCACHE, + }, + .clkr.shared = 1, + }, +}; + +static struct clk_fixed_factor clk_sys = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sys", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_bus" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor clk_sysh = { + .div = 1, + .mult = 1, + .hw.init = &(struct clk_init_data) { + .name = "clk_sysh", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "pll_dcsb" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_table ddsx_tbl[] = { + FREQ_NF(432000000, 29, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ddsa = { + .ssc_ofs = 0x560, + .pll_ofs = 0x120, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL3, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = ddsx_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ddsa", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct freq_table gpu_tbl[] = { + FREQ_NF(400000000, 0x1a, 0x509), + FREQ_NF(450000000, 0x1e, 0x2aa), + FREQ_NF(500000000, 0x22, 0x04b), + FREQ_NF(550000000, 0x25, 0x5ed), + FREQ_NF(650000000, 0x2d, 0x12f), + FREQ_NF(702000000, 0x31, 0x000), + FREQ_NF(729000000, 0x33, 0x000), + FREQ_NF(769000000, 0x36, 0x000), + FREQ_NF(810000000, 0x39, 0x000), + FREQ_NF(837000000, 0x3b, 0x000), + FREQ_NF(850500000, 0x3c, 0x000), + FREQ_TABLE_END +}; + +static struct clk_pll pll_gpu = { + .ssc_ofs = 0x5A0, + .pll_ofs = 0x1C0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = gpu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_gpu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, + CLK_PLL_CONF_RS(0x0003c000, 0x00020000), + CLK_PLL_CONF_PI_BPS(), +}; + +static const struct freq_table ve_tbl[] = { + FREQ_MNO(432000000, 0x0d, 0, 0), + FREQ_MNO(540000000, 0x11, 0, 0), + FREQ_MNO(553000000, 0x26, 1, 0), + FREQ_MNO(621000000, 0x14, 0, 0), + FREQ_MNO(621000000, 0x2b, 1, 0), + FREQ_MNO(648000000, 0x2d, 1, 0), + FREQ_MNO(675000000, 0x2f, 1, 0), + FREQ_TABLE_END +}; + +static struct clk_pll pll_ve1 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x114, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO_V2, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve1", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE, + }, + CLK_PLL_CONF_RS(0x0081c000, 0x00800000), +}; + +static struct clk_pll pll_ve2 = { + .ssc_ofs = CLK_OFS_INVALID, + .pll_ofs = 0x1D0, + .pow_loc = CLK_PLL_CONF_POW_LOC_CTL2, + .pll_type = CLK_PLL_TYPE_MNO_V2, + .freq_tbl = ve_tbl, + .freq_mask = FREQ_MNO_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_ve2", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + }, + CLK_PLL_CONF_RS(0x0081c000, 0x00800000), +}; + +static struct clk_pll_dif pll_dif = { + .ssc_ofs = 0x634, + .pll_ofs = 0x624, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_dif", + .ops = &clk_pll_dif_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, + .adtv_conf = { + 0x02000949, 0x00030c00, 0x204004ca, 0x400C6004, + 0x00431c00, 0x00431c03, 0x02000979, 0x004884ca, + }, +}; + +static struct clk_pll_psaud pll_psaud1a = { + .reg = 0x130, + .id = CLK_PLL_PSAUD1A, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_psaud1a", + .ops = &clk_pll_psaud_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_UNGATE, + }, +}; + +static struct clk_pll_psaud pll_psaud2a = { + .reg = 0x130, + .id = CLK_PLL_PSAUD2A, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_psaud2a", + .ops = &clk_pll_psaud_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_IGNORE_UNUSED | CLK_SET_RATE_UNGATE, + }, +}; + +static const struct freq_table npu_tbl[] = { + FREQ_NF(600000000, 0x29, 0x38e), + FREQ_NF(700000000, 0x30, 0x6d0), + FREQ_NF(729000000, 0x33, 0x000), + FREQ_NF(756000000, 0x35, 0x000), + FREQ_NF(850500000, 0x3c, 0x000), + FREQ_TABLE_END +}; + +static struct clk_pll pll_npu = { + .ssc_ofs = 0x6b0, + .pll_ofs = 0x1c8, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = npu_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_npu", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, + CLK_PLL_CONF_RS(0x0003c000, 0x00020000), + CLK_PLL_CONF_PI_BPS(), +}; + +static const struct freq_table hifi_tbl[] = { + FREQ_NF(405000000, 0x1b, 0x000), + FREQ_NF(486000000, 0x21, 0x000), + FREQ_NF(499500000, 0x22, 0x000), + FREQ_NF(702000000, 0x31, 0x000), + FREQ_NF(796500000, 0x38, 0x000), + FREQ_NF(810000000, 0x39, 0x000), + FREQ_TABLE_END +}; + +static struct clk_pll pll_hifi = { + .ssc_ofs = 0x6e0, + .pll_ofs = 0x1d8, + .pll_type = CLK_PLL_TYPE_NF_SSC, + .freq_tbl = hifi_tbl, + .freq_mask = FREQ_NF_MASK, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pll_hifi", + .ops = &clk_pll_ops, + .parent_names = default_parent, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, + CLK_PLL_CONF_RS(0x0003c000, 0x00020000), + CLK_PLL_CONF_PI_BPS(), +}; + +static struct clk_det clk_det_pll_bus = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_bus", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x424, +}; + +static struct clk_det clk_det_pll_dcsb = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_dcsb", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x428, +}; + +static struct clk_det clk_det_pll_acpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_acpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x42c, +}; + +static struct clk_det clk_det_pll_ddsa = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ddsa", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x430, +}; + +static struct clk_det clk_det_pll_gpu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_gpu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x438, +}; + +static struct clk_det clk_det_pll_ve1 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve1", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x43c, +}; + +static struct clk_det clk_det_pll_ve2 = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_ve2", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x440, +}; + +static struct clk_det clk_det_pll_npu = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_npu", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x444, +}; + +static struct clk_det clk_det_pll_hifi = { + .clkr.hw.init = CLK_HW_INIT_NO_PARENT("ref_pll_hifi", &clk_det_ops, CLK_GET_RATE_NOCACHE), + .type = CLK_DET_TYPE_CRT, + .ofs = 0x448, +}; + +static struct clk_hw *cc_hws[] = { + [RTD1619B_CRT_PLL_SCPU] = &__clk_pll_div_hw(&pll_scpu), + [RTD1619B_CRT_PLL_BUS] = &__clk_pll_div_hw(&pll_bus), + [RTD1619B_CRT_PLL_DCSB] = &__clk_pll_div_hw(&pll_dcsb), + [RTD1619B_CRT_CLK_SYS] = &clk_sys.hw, + [RTD1619B_CRT_CLK_SYSH] = &clk_sysh.hw, + [RTD1619B_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa), + [RTD1619B_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu), + [RTD1619B_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1), + [RTD1619B_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2), + [RTD1619B_CRT_PLL_DIF] = &__clk_pll_dif_hw(&pll_dif), + [RTD1619B_CRT_PLL_PSAUD1A] = &__clk_pll_psaud_hw(&pll_psaud1a), + [RTD1619B_CRT_PLL_PSAUD2A] = &__clk_pll_psaud_hw(&pll_psaud2a), + [RTD1619B_CRT_PLL_NPU] = &__clk_pll_hw(&pll_npu), + [RTD1619B_CRT_PLL_HIFI] = &__clk_pll_hw(&pll_hifi), + + [RTD1619B_CRT_CLK_DET_PLL_BUS] = &__clk_det_hw(&clk_det_pll_bus), + [RTD1619B_CRT_CLK_DET_PLL_DCSB] = &__clk_det_hw(&clk_det_pll_dcsb), + [RTD1619B_CRT_CLK_DET_PLL_ACPU] = &__clk_det_hw(&clk_det_pll_acpu), + [RTD1619B_CRT_CLK_DET_PLL_DDSA] = &__clk_det_hw(&clk_det_pll_ddsa), + [RTD1619B_CRT_CLK_DET_PLL_GPU] = &__clk_det_hw(&clk_det_pll_gpu), + [RTD1619B_CRT_CLK_DET_PLL_VE1] = &__clk_det_hw(&clk_det_pll_ve1), + [RTD1619B_CRT_CLK_DET_PLL_VE2] = &__clk_det_hw(&clk_det_pll_ve2), + [RTD1619B_CRT_CLK_DET_PLL_NPU] = &__clk_det_hw(&clk_det_pll_npu), + [RTD1619B_CRT_CLK_DET_PLL_HIFI] = &__clk_det_hw(&clk_det_pll_hifi), +}; + +static const char * const ve_parents[] = { + "", + "clk_sysh", + "pll_ve1", + "pll_ve2", +}; + +static struct clk_composite_data cc_composites[] = { + { + .id = RTD1619B_CRT_CLK_GPU, + .mux_ofs = CLK_OFS_INVALID, + .gate_ofs = 0x050, + .gate_shift = 18, + .gate_write_en = 1, + .parent_names = (const char *[]){ "pll_gpu" }, + .num_parents = 1, + .name = "clk_gpu", + .flags = CLK_SET_RATE_PARENT, + }, + { + .id = RTD1619B_CRT_CLK_VE1, + .gate_ofs = 0x050, + .gate_shift = 20, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 0, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve1", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1619B_CRT_CLK_VE2, + .gate_ofs = 0x050, + .gate_shift = 22, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 3, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve2", + .flags = CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED, + }, + { + .id = RTD1619B_CRT_CLK_VE3, + .gate_ofs = 0x05C, + .gate_shift = 26, + .gate_write_en = 1, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 6, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve3", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, + { + .id = RTD1619B_CRT_CLK_VE3_BPU, + .gate_ofs = CLK_OFS_INVALID, + .mux_ofs = 0x04C, + .mux_width = 3, + .mux_shift = 9, + .parent_names = ve_parents, + .num_parents = ARRAY_SIZE(ve_parents), + .name = "clk_ve3_bpu", + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 1, 0) + +#define GATE_NORMAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +#define GATE_IGNORED(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IGNORE_UNUSED, _ofs, _shift) + +#define GATE_CRITICAL(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, CLK_IS_CRITICAL, _ofs, _shift) + +static struct clk_gate_data cc_gates[] = { + GATE_CRITICAL(RTD1619B_CRT_CLK_EN_MISC, "misc", NULL, 0x50, 0), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_PCIE0, "pcie0", NULL, 0x50, 2), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_GSPI, "gspi", "misc", 0x50, 6), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SDS, "sds", NULL, 0x50, 12), + GATE_IGNORED(RTD1619B_CRT_CLK_EN_HDMI, "hdmi", NULL, 0x50, 14), + GATE_IGNORED(RTD1619B_CRT_CLK_EN_CP, "cp", NULL, 0x54, 2), + GATE_IGNORED(RTD1619B_CRT_CLK_EN_TP, "tp", NULL, 0x54, 6), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_NF, "nf", NULL, 0x54, 10), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_EMMC, "emmc", NULL, 0x54, 12), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SD, "sd", NULL, 0x54, 14), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SDIO_IP, "sdio_ip", NULL, 0x54, 16), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MIPI, "mipi", NULL, 0x54, 18), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_EMMC_IP, "emmc_ip", NULL, 0x54, 20), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SDIO, "sdio", NULL, 0x54, 22), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SD_IP, "sd_ip", NULL, 0x54, 24), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_CABLERX, "cablerx", NULL, 0x54, 26), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_TPB, "tpb", NULL, 0x54, 28), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MISC_SC1, "misc_sc1", "misc", 0x54, 30), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MISC_I2C_3, "misc_i2c_3", "misc", 0x58, 0), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_JPEG, "jpeg", NULL, 0x58, 4), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MISC_SC0, "misc_sc0", "misc", 0x58, 10), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_HDMIRX, "hdmirx", NULL, 0x58, 26), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_HSE, "hse", NULL, 0x58, 28), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_UR2, "ur2", "misc", 0x58, 30), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_UR1, "ur1", "misc", 0x5c, 0), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_FAN, "fan", "misc", 0x5c, 2), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SATA_WRAP_SYS, "sata_wrap_sys", NULL, 0x5c, 8), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SATA_WRAP_SYSH, "sata_wrap_sysh", NULL, 0x5c, 10), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_SATA_MAC_SYSH, "sata_mac_sysh", NULL, 0x5c, 12), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_R2RDSC, "r2rdsc", NULL, 0x5c, 14), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_TPC, "tpc", NULL, 0x5c, 16), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_PCIE1, "pcie1", NULL, 0x5c, 18), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MISC_I2C_4, "misc_i2c_4", "misc", 0x5c, 20), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MISC_I2C_5, "misc_i2c_5", "misc", 0x5c, 22), + GATE_IGNORED(RTD1619B_CRT_CLK_EN_TSIO, "tsio", NULL, 0x5c, 24), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_EDP, "edp", NULL, 0x5c, 28), + GATE_IGNORED(RTD1619B_CRT_CLK_EN_TSIO_TRX, "tsio_trx", NULL, 0x5c, 30), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_PCIE2, "pcie2", NULL, 0x8c, 0), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_LITE, "lite", NULL, 0x8c, 6), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_MIPI_DSI, "mipi_dsi", NULL, 0x8c, 8), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_NPUPP, "npupp", NULL, 0x8c, 10), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_NPU, "npu", NULL, 0x8c, 12), + GATE_NORMAL(RTD1619B_CRT_CLK_EN_HDMITOP, "hdmitop", NULL, 0x8c, 20), +}; + +static struct rtk_reset_bank cc_reset_banks[] = { + { .ofs = 0x000, .write_en = 1, }, + { .ofs = 0x004, .write_en = 1, }, + { .ofs = 0x008, .write_en = 1, }, + { .ofs = 0x00C, .write_en = 1, }, + { .ofs = 0x068, .write_en = 1, }, + { .ofs = 0x090, .write_en = 1, }, + { .ofs = 0x454, }, + { .ofs = 0x458, }, + { .ofs = 0x464, }, +}; + +static struct rtk_reset_initdata cc_reset_initdata = { + .banks = cc_reset_banks, + .num_banks = ARRAY_SIZE(cc_reset_banks), +}; + +static struct clk_hw_map rtd1619b_sys_map = { + .group = &(struct clk_hw_group) { + .hws = cc_hws, + .num_hws = ARRAY_SIZE(cc_hws), + }, + .start_index = 0, +}; + +static struct clk_hw_map rtd1619b_sys_n_map = { + .group = &(struct clk_hw_group) { + .hws = cc_hws + RTD1619B_CRT_PLL_BUS, + .num_hws = ARRAY_SIZE(cc_hws) - RTD1619B_CRT_PLL_BUS, + }, + .start_index = RTD1619B_CRT_PLL_BUS, +}; + +static int rtd1619b_cc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + const struct clk_hw_map *map; + + map = of_device_get_match_data(dev); + if (!map) + return -EINVAL; + + data = rtk_clk_alloc_data(RTD1619B_CRT_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + of_rtk_clk_setup_crt(np, data->regmap); + + platform_set_drvdata(pdev, data); + + rtk_clk_add_hw_map(dev, data, map); + + rtk_clk_add_composites(dev, data, cc_composites, + ARRAY_SIZE(cc_composites)); + rtk_clk_add_gates(dev, data, cc_gates, ARRAY_SIZE(cc_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + cc_reset_initdata.lock = data->lock; + cc_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &cc_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1619b_cc_match[] = { + { .compatible = "realtek,rtd1619b-crt-clk", .data = &rtd1619b_sys_map, }, + { .compatible = "realtek,rtd1619b-crt-clk-n", .data = &rtd1619b_sys_n_map, }, + { /* sentinel */ } +}; + +static struct platform_driver rtd1619b_cc_driver = { + .probe = rtd1619b_cc_probe, + .driver = { + .name = "rtk-rtd1619b-crt-clk", + .of_match_table = rtd1619b_cc_match, + }, +}; + +static int __init rtd1619b_cc_init(void) +{ + return platform_driver_register(&rtd1619b_cc_driver); +} +core_initcall(rtd1619b_cc_init); +MODULE_DESCRIPTION("Reatek RTD1619B CRT Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-rtd1619b-ic.c b/drivers/clk/realtek/clk-rtd1619b-ic.c new file mode 100644 index 000000000000..1c0afcc77117 --- /dev/null +++ b/drivers/clk/realtek/clk-rtd1619b-ic.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "reset.h" +#include + +#define GATE_COMMON(_id, _name, _parent, _flags, _ofs, _shift) \ + CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, 0, 0) +#define GATE(_id, _name, _parent, _ofs, _shift) \ + GATE_COMMON(_id, _name, _parent, 0, _ofs, _shift) + +static struct clk_gate_data ic_gates[] = { + GATE(RTD1619B_ISO_CLK_EN_LSADC, "lsadc", NULL, 0x8c, 0), + GATE(RTD1619B_ISO_CLK_EN_ISO_GSPI, "iso_gspi", NULL, 0x8c, 1), + GATE(RTD1619B_ISO_CLK_EN_MISC_CEC0, "misc_cec0", NULL, 0x8c, 2), + GATE(RTD1619B_ISO_CLK_EN_CBUSRX_SYS, "cbusrx_sys", NULL, 0x8c, 3), + GATE(RTD1619B_ISO_CLK_EN_CBUSTX_SYS, "cbustx_sys", NULL, 0x8c, 4), + GATE(RTD1619B_ISO_CLK_EN_CBUS_SYS, "cbus_sys", NULL, 0x8c, 5), + GATE(RTD1619B_ISO_CLK_EN_CBUS_OSC, "cbus_osc", NULL, 0x8c, 6), + GATE(RTD1619B_ISO_CLK_EN_MISC_IR, "misc_ir", NULL, 0x8c, 7), + GATE(RTD1619B_ISO_CLK_EN_MISC_UR0, "misc_ur0", NULL, 0x8c, 8), + GATE(RTD1619B_ISO_CLK_EN_I2C0, "i2c0", NULL, 0x8c, 9), + GATE(RTD1619B_ISO_CLK_EN_I2C1, "i2c1", NULL, 0x8c, 10), + GATE(RTD1619B_ISO_CLK_EN_ETN_250M, "etn_250m", NULL, 0x8c, 11), + GATE(RTD1619B_ISO_CLK_EN_ETN_SYS, "etn_sys", NULL, 0x8c, 12), + GATE(RTD1619B_ISO_CLK_EN_USB_DRD, "usb_drd", NULL, 0x8c, 13), + GATE(RTD1619B_ISO_CLK_EN_USB_HOST, "usb_host", NULL, 0x8c, 14), + GATE(RTD1619B_ISO_CLK_EN_USB_U3_HOST, "usb_u3_host", NULL, 0x8c, 15), + GATE(RTD1619B_ISO_CLK_EN_USB, "usb", NULL, 0x8c, 16), + GATE(RTD1619B_ISO_CLK_EN_VTC, "vtc", NULL, 0x8c, 17), + GATE(RTD1619B_ISO_CLK_EN_MISC_VFD, "misc_vfd", NULL, 0x8c, 18), +}; + +static struct rtk_reset_bank ic_reset_banks[] = { + { .ofs = 0x88, }, +}; + +static struct rtk_reset_initdata ic_reset_initdata = { + .banks = ic_reset_banks, + .num_banks = ARRAY_SIZE(ic_reset_banks), +}; + +static int rtd1619b_ic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_clk_data *data; + int ret; + + data = rtk_clk_alloc_data(RTD1619B_ISO_CLK_MAX); + if (!data) + return -ENOMEM; + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + ret = rtk_clk_of_init_data(np, data); + if (ret) { + rtk_clk_free_data(data); + return ret; + } + + platform_set_drvdata(pdev, data); + + rtk_clk_add_gates(dev, data, ic_gates, ARRAY_SIZE(ic_gates)); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &data->clk_data); + if (ret) + dev_err(dev, "failed to add clk provider: %d\n", ret); + + ic_reset_initdata.lock = data->lock; + ic_reset_initdata.regmap = data->regmap; + rtk_reset_controller_add(dev, &ic_reset_initdata); + + return 0; +} + +static const struct of_device_id rtd1619b_ic_match[] = { + { .compatible = "realtek,rtd1619b-iso-clk", }, + { /* sentinel */ } +}; + +static struct platform_driver rtd1619b_ic_driver = { + .probe = rtd1619b_ic_probe, + .driver = { + .name = "rtk-rtd1619b-iso-clk", + .of_match_table = rtd1619b_ic_match, + }, +}; + +static int __init rtd1619b_ic_init(void) +{ + return platform_driver_register(&rtd1619b_ic_driver); +} +core_initcall(rtd1619b_ic_init); +MODULE_DESCRIPTION("Reatek RTD1619B ISO Controller Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/realtek/clk-tee.c b/drivers/clk/realtek/clk-tee.c new file mode 100644 index 000000000000..772e5e6eedd3 --- /dev/null +++ b/drivers/clk/realtek/clk-tee.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cc-tee.c - TEE clock controller + * + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +#define HZ_PER_MHZ 1000000 +#define TA_CMD_SCPU_PLL 5 + +struct ta_clk_data { + struct clk_hw hw; + struct device *dev; + unsigned long freq_mhz; + struct tee_context *ctx; + u32 session_id; +}; + +static const uuid_t uuid = UUID_INIT(0x650b79a1, 0xa79a, 0x43ea, + 0x91, 0x85, 0xf6, 0x67, 0x55, 0x65, 0x64, 0xa7); + +static int ta_clk_optee_match(struct tee_ioctl_version_data *vers, + const void *data) +{ + if (vers->impl_id == TEE_IMPL_ID_OPTEE) + return 1; + return 0; +} + +static int ta_clk_init(struct ta_clk_data *tcd) +{ + struct tee_ioctl_version_data vers = { + .impl_id = TEE_IMPL_ID_OPTEE, + .impl_caps = TEE_OPTEE_CAP_TZ, + .gen_caps = TEE_GEN_CAP_GP, + }; + struct tee_ioctl_open_session_arg arg = { 0 }; + int ret; + + tcd->ctx = tee_client_open_context(NULL, ta_clk_optee_match, NULL, + &vers); + if (IS_ERR(tcd->ctx)) { + ret = PTR_ERR(tcd->ctx); + dev_err(tcd->dev, "failed to open context: %d\n", ret); + return ret; + } + + memcpy(arg.uuid, uuid.b, TEE_IOCTL_UUID_LEN); + arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; + arg.num_params = 0; + + ret = tee_client_open_session(tcd->ctx, &arg, NULL); + if (ret) { + dev_err(tcd->dev, "failed to open session: %d\n", ret); + return ret; + } + + tcd->session_id = arg.session; + return 0; +} + +static void ta_clk_fini(struct ta_clk_data *tcd) +{ + tee_client_close_session(tcd->ctx, tcd->session_id); + tee_client_close_context(tcd->ctx); +} + +static int ta_clk_set_pll_scpu_freq(struct ta_clk_data *tcd, unsigned int freq) +{ + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + int ret; + int retry = 0; + +again: + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + inv_arg.func = TA_CMD_SCPU_PLL; + inv_arg.session = tcd->session_id; + inv_arg.num_params = 4; + + param[0].u.value.a = freq; + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; + param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + ret = tee_client_invoke_func(tcd->ctx, &inv_arg, param); + if (inv_arg.ret != 0 && retry == 0) { + dev_warn(tcd->dev, "failed to invoke, retry\n"); + ta_clk_init(tcd); + retry++; + goto again; + } + + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(tcd->dev, "failed to invoke func: %d, %x\n", ret, + inv_arg.ret); + return -EINVAL; + } + + if (param[0].u.value.b) { + dev_err(tcd->dev, "failed to set freq: %lld\n", + param[0].u.value.b); + return -EINVAL; + } + + return 0; +} + + +static long ta_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + rate /= HZ_PER_MHZ; + rate = rate > 1400 ? 1400 : rate; + rate = rate < 300 ? 300 : rate; + return rate * HZ_PER_MHZ; +} + +static unsigned long ta_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ta_clk_data *tcd = container_of(hw, struct ta_clk_data, hw); + + dev_dbg(tcd->dev, "freq = %ld\n", tcd->freq_mhz * HZ_PER_MHZ); + return tcd->freq_mhz * HZ_PER_MHZ; +} + +static int ta_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ta_clk_data *tcd = container_of(hw, struct ta_clk_data, hw); + unsigned long freq_mhz = rate / HZ_PER_MHZ; + int ret; + ktime_t start; + s64 delta_us; + + dev_dbg(tcd->dev, "enter %s (freq=%lu)\n", __func__, freq_mhz); + + start = ktime_get(); + ret = ta_clk_set_pll_scpu_freq(tcd, freq_mhz); + if (ret) + goto done; + tcd->freq_mhz = freq_mhz; +done: + delta_us = ktime_to_us(ktime_sub(ktime_get(), start)); + dev_dbg(tcd->dev, "exit %s (freq=%lu, time=%lld, ret=%d)\n", __func__, + freq_mhz, delta_us, ret); + return ret; +} + +static const struct clk_ops ta_clk_ops = { + .debug_init = set_clk_rate_debugfs_init, + .round_rate = ta_clk_round_rate, + .recalc_rate = ta_clk_recalc_rate, + .set_rate = ta_clk_set_rate, +}; + +static struct ta_clk_data pll_scpu = { + .freq_mhz = 1100, + .hw.init = &(struct clk_init_data) { + .name = "pll_scpu", + .ops = &ta_clk_ops, + }, +}; + +static int rtk_tee_cc_probe(struct platform_device *pdev) +{ + int ret; + struct device *dev = &pdev->dev; + struct clk *clk; + struct ta_clk_data *tcd = &pll_scpu; + + tcd->dev = dev; + + ret = ta_clk_init(tcd); + if (ret) + return -EPROBE_DEFER; + + ret = ta_clk_set_pll_scpu_freq(tcd, tcd->freq_mhz); + if (ret) + goto error; + + clk = clk_register(NULL, &pll_scpu.hw); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "failed to register clk: %d\n", ret); + goto error; + } + platform_set_drvdata(pdev, clk); + + of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, __clk_get_name(clk), NULL); + + dev_info(dev, "ready\n"); + return 0; + +error: + ta_clk_fini(tcd); + return ret; +} + +static const struct of_device_id rtk_tee_cc_match[] = { + { .compatible = "realtek,tee-clock-controller", }, + {} +}; + +static struct platform_driver rtk_tee_cc_driver = { + .probe = rtk_tee_cc_probe, + .driver = { + .name = "rtk-tee-cc", + .of_match_table = of_match_ptr(rtk_tee_cc_match), + }, +}; + +static int __init rtk_tee_cc_init(void) +{ + return platform_driver_register(&rtk_tee_cc_driver); +} +late_initcall(rtk_tee_cc_init); diff --git a/drivers/clk/realtek/common.c b/drivers/clk/realtek/common.c new file mode 100644 index 000000000000..914fdbcfb3e9 --- /dev/null +++ b/drivers/clk/realtek/common.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "clk-pll.h" +#include "clk-regmap-gate.h" +#include "clk-regmap-mux.h" +#include "clk-det.h" +#include +#include + +MODULE_LICENSE("GPL v2"); + +struct rtk_clk_data *rtk_clk_alloc_data(int clk_num) +{ + struct rtk_clk_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return NULL; + + data->clk_num = clk_num; + data->clk_data.clk_num = clk_num; + data->clk_data.clks = kcalloc(clk_num, sizeof(*data->clk_data.clks), + GFP_KERNEL); + if (!data->clk_data.clks) + goto free_data; + return data; + +free_data: + kfree(data->clk_data.clks); + kfree(data); + return NULL; +} +EXPORT_SYMBOL_GPL(rtk_clk_alloc_data); + +void rtk_clk_free_data(struct rtk_clk_data *data) +{ + kfree(data->clk_data.clks); + kfree(data); +} +EXPORT_SYMBOL_GPL(rtk_clk_free_data); + +int rtk_clk_of_init_data(struct device_node *np, struct rtk_clk_data *data) +{ + struct regmap *regmap; + struct sb2_sem *lock; + int ret; + struct device_node *parent = of_get_parent(np); + + regmap = syscon_node_to_regmap(parent); + of_node_put(parent); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + pr_err("%s: failed to get regmap form %s: %d\n", __func__, + np->name, ret); + return ret; + } + data->regmap = regmap; + + lock = of_sb2_sem_get(np, 0); + if (!IS_ERR(lock)) { + data->lock = lock; + pr_info("%s: %s: lock used\n", __func__, np->name); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtk_clk_of_init_data); + +static inline +int __cell_clk_add(struct clk_onecell_data *clk_data, int i, struct clk *clk) +{ + if (clk_data->clks[i]) { + pr_err("%s: failed to add %pC, cell%d is used by %pC\n", + __func__, clk, i, clk_data->clks[i]); + return -EINVAL; + } + clk_data->clks[i] = clk; + return 0; +} + +struct clk_regmap_init_data { + struct regmap *regmap; + struct sb2_sem *lock; + int shared; +}; + +static void clk_regmap_init(struct clk_regmap *clkr, struct clk_regmap_init_data *initdata) +{ + clkr->regmap = initdata->regmap; + clkr->shared = initdata->shared; + if (!initdata->shared) + return; + clkr->lock = initdata->lock; + WARN_ON_ONCE(!clkr->lock); +} + + + +static inline int is_clk_regmap_ops(const struct clk_ops *ops ) +{ + if (is_clk_pll_ops(ops)) + return 1; + + if (is_clk_regmap_mux_ops(ops)) + return 1; + + if (is_clk_regmap_gate_ops(ops)) + return 1; + + if (is_clk_det_ops(ops)) + return 1; + + return 0; +} + +static inline int is_clk_regmap(struct clk_hw *hw) +{ + if (!hw->init || !hw->init->ops) + return 0; + + return is_clk_regmap_ops(hw->init->ops); +} + +static +struct clk *rtk_clk_register_hw(struct device *dev, struct rtk_clk_data *data, + struct clk_hw *hw) +{ + if (is_clk_regmap(hw)) { + struct clk_regmap *clkr = to_clk_regmap(hw); + struct clk_regmap_init_data initdata = { + .regmap = data->regmap, + .lock = data->lock, + .shared = clkr->shared, + }; + + clk_regmap_init(clkr, &initdata); + } + + return clk_register(dev, hw); +} + +int rtk_clk_add_hws_from(struct device *dev, struct rtk_clk_data *data, + struct clk_hw **hws, int size, int start_index) +{ + struct clk_onecell_data *clk_data = &data->clk_data; + int i, j; + + for (i = 0, j = start_index; i < size; i++, j++) { + struct clk_hw *hw = hws[i]; + const char *name; + struct clk *clk; + + if (IS_ERR_OR_NULL(hw)) + continue; + + name = hw->init->name; + dev_dbg(dev, "%s: registering clk_hw '%s' (idx=%d) at slot%d\n", + __func__, name, i, j); + + clk = rtk_clk_register_hw(dev, data, hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clk_hw '%s' (idx=%d): %ld\n", + __func__, name, i, PTR_ERR(clk)); + continue; + } + + clk_register_clkdev(clk, name, NULL); + __cell_clk_add(clk_data, j, clk); + } + return 0; +} +EXPORT_SYMBOL_GPL(rtk_clk_add_hws_from); + +static +struct clk *rtk_clk_register_composite(struct device *dev, + struct rtk_clk_data *data, + struct clk_composite_data *comp) +{ + struct clk_regmap_mux *clkm = NULL; + const struct clk_ops *mux_op = NULL; + struct clk_hw *mux_hw = NULL; + struct clk_regmap_gate *clkg = NULL; + const struct clk_ops *gate_op = NULL; + struct clk_hw *gate_hw = NULL; + struct clk *clk; + struct clk_regmap_init_data initdata = { + .regmap = data->regmap, + .lock = data->lock, + .shared = comp->shared, + }; + + if (comp->mux_ofs != CLK_OFS_INVALID) { + clkm = kzalloc(sizeof(*clkm), GFP_KERNEL); + if (!clkm) { + clk = ERR_PTR(-ENOMEM); + goto check_err; + } + + clkm->mux_ofs = comp->mux_ofs; + clkm->mask = BIT(comp->mux_width) - 1; + clkm->shift = comp->mux_shift; + + clk_regmap_init(&clkm->clkr, &initdata); + + mux_op = &clk_regmap_mux_ops; + mux_hw = &__clk_regmap_mux_hw(clkm); + } + + if (comp->gate_ofs != CLK_OFS_INVALID) { + clkg = kzalloc(sizeof(*clkg), GFP_KERNEL); + if (!clkg) { + clk = ERR_PTR(-ENOMEM); + goto check_err; + } + + clkg->gate_ofs = comp->gate_ofs; + clkg->bit_idx = comp->gate_shift; + clkg->write_en = comp->gate_write_en; + + clk_regmap_init(&clkg->clkr, &initdata); + + gate_op = &clk_regmap_gate_ops; + gate_hw = &__clk_regmap_gate_hw(clkg); + } + + clk = clk_register_composite(NULL, comp->name, comp->parent_names, + comp->num_parents, mux_hw, mux_op, + NULL, NULL, gate_hw, gate_op, comp->flags); +check_err: + if (IS_ERR(clk)) { + kfree(clkm); + kfree(clkg); + } + return clk; +} + +int rtk_clk_add_composites(struct device *dev, struct rtk_clk_data *data, + struct clk_composite_data *comps, int num) +{ + struct clk_onecell_data *clk_data = &data->clk_data; + int i; + + for (i = 0; i < num; i++) { + struct clk_composite_data *comp = &comps[i]; + const char *name = comp->name; + struct clk *clk; + + clk = rtk_clk_register_composite(dev, data, comp); + if (IS_ERR(clk)) { + pr_err("%s: failed to add composite%d(%s): %ld\n", + __func__, i, name, PTR_ERR(clk)); + continue; + } + + clk_register_clkdev(clk, name, NULL); + __cell_clk_add(clk_data, comp->id, clk); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtk_clk_add_composites); + +static +struct clk *rtk_clk_register_gate(struct device *dev, struct rtk_clk_data *data, + struct clk_gate_data *gate) +{ + struct clk_regmap_gate *clkg; + struct clk_init_data init = { 0 }; + struct clk_hw *hw; + struct clk_regmap_init_data initdata = { + .regmap = data->regmap, + .lock = data->lock, + .shared = gate->shared, + }; + + clkg = kzalloc(sizeof(*clkg), GFP_KERNEL); + if (!clkg) + return ERR_PTR(-ENOMEM); + + clkg->gate_ofs = gate->gate_ofs; + clkg->bit_idx = gate->gate_shift; + clkg->write_en = gate->gate_write_en; + + clk_regmap_init(&clkg->clkr, &initdata); + + init.name = gate->name; + init.ops = &clk_regmap_gate_ops; + init.flags = gate->flags; + if (gate->parent) { + init.parent_names = &gate->parent; + init.num_parents = 1; + } + + hw = &__clk_regmap_gate_hw(clkg); + hw->init = &init; + return clk_register(dev, hw); +} + +int rtk_clk_add_gates(struct device *dev, struct rtk_clk_data *data, + struct clk_gate_data *gates, int num) +{ + struct clk_onecell_data *clk_data = &data->clk_data; + int i; + + for (i = 0; i < num; i++) { + struct clk_gate_data *gate = &gates[i]; + const char *name = gate->name; + struct clk *clk; + + clk = rtk_clk_register_gate(dev, data, gate); + if (IS_ERR(clk)) { + pr_err("%s: failed to add gate%d(%s): %ld\n", __func__, + i, name, PTR_ERR(clk)); + continue; + } + + clk_register_clkdev(clk, name, NULL); + __cell_clk_add(clk_data, gate->id, clk); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtk_clk_add_gates); diff --git a/drivers/clk/realtek/common.h b/drivers/clk/realtek/common.h new file mode 100644 index 000000000000..96827acbbbb2 --- /dev/null +++ b/drivers/clk/realtek/common.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2016-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __CLK_REALTEK_COMMON_H +#define __CLK_REALTEK_COMMON_H + +#include +#include +#include +#include +#include +#include +#include + +struct device; +struct platform_device; + +struct clk_regmap { + struct clk_hw hw; + struct regmap *regmap; + struct sb2_sem *lock; + int shared; +}; + +#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw) +#define __clk_regmap_hw(_p) ((_p)->hw) + +static inline +void clk_regmap_write(struct clk_regmap *clkr, uint32_t ofs, uint32_t val) +{ + pr_debug("%s: ofs=%03x, val=%08x\n", __func__, ofs, val); + + if (clkr->shared && clkr->lock) + sb2_sem_lock(clkr->lock, SB2_SEM_NO_WARNING); + + regmap_write(clkr->regmap, ofs, val); + + if (clkr->shared && clkr->lock) + sb2_sem_unlock(clkr->lock); +} + +static inline +uint32_t clk_regmap_read(struct clk_regmap *clkr, uint32_t ofs) +{ + uint32_t val = 0; + + if (clkr->shared && clkr->lock) + sb2_sem_lock(clkr->lock, SB2_SEM_NO_WARNING); + + regmap_read(clkr->regmap, ofs, &val); + + if (clkr->shared && clkr->lock) + sb2_sem_unlock(clkr->lock); + + pr_debug("%s: ofs=%03x, val=%08x\n", __func__, ofs, val); + return val; +} + +static inline void clk_regmap_update(struct clk_regmap *clkr, uint32_t ofs, + uint32_t mask, uint32_t val) +{ + + pr_debug("%s: ofs=%03x, mask=%08x, val=%08x\n", __func__, ofs, + mask, val); + + if (clkr->shared && clkr->lock) + sb2_sem_lock(clkr->lock, SB2_SEM_NO_WARNING); + + regmap_update_bits(clkr->regmap, ofs, mask, val); + + if (clkr->shared && clkr->lock) + sb2_sem_unlock(clkr->lock); +} + +/* ofs check */ +#define CLK_OFS_INVALID (-1) +#define CLK_OFS_IS_VALID(_ofs) ((_ofs) != CLK_OFS_INVALID) + +struct clk_composite_data { + int id; + const char *name; + unsigned long flags; + struct clk *clk; + + int gate_ofs; + int gate_shift; + int gate_write_en; + + int mux_ofs; + int mux_width; + int mux_shift; + const char * const *parent_names; + int num_parents; + + int shared; +}; + +struct clk_gate_data { + int id; + const char *name; + const char *parent; + unsigned long flags; + struct clk *clk; + + int gate_ofs; + int gate_shift; + int gate_write_en; + + int shared; +}; + +#define CLK_GATE_DATA(_id, _name, _parent, _flags, _ofs, _shift, _write_en, \ + _shared) \ +{ \ + .id = _id, \ + .name = _name, \ + .parent = _parent, \ + .flags = _flags, \ + .gate_ofs = _ofs, \ + .gate_shift = _shift, \ + .gate_write_en = _write_en, \ + .shared = _shared, \ +} + +struct rtk_clk_data { + int clk_num; + struct regmap *regmap; + struct sb2_sem *lock; + struct clk_onecell_data clk_data; +}; + +struct rtk_clk_data *rtk_clk_alloc_data(int clk_num); +void rtk_clk_free_data(struct rtk_clk_data *data); +int rtk_clk_of_init_data(struct device_node *np, struct rtk_clk_data *data); +int rtk_clk_add_composites(struct device *dev, struct rtk_clk_data *data, + struct clk_composite_data *comps, int num); +int rtk_clk_add_gates(struct device *dev, struct rtk_clk_data *data, + struct clk_gate_data *gates, int num); + +/** + * rtk_clk_add_hws_from() - register clocks form a clk_hw array to clock + * controller with a start index of the provider + * @dev: the controller device + * @data: the controller data + * @hws: a array of clk_hw to be added, + * @size: size of the array + * @start_index: the start index to be added, + * + * Return 0 if success + */ +int rtk_clk_add_hws_from(struct device *dev, struct rtk_clk_data *data, + struct clk_hw **hws, int size, int start_index); + +static inline int rtk_clk_add_hws(struct device *dev, struct rtk_clk_data *data, + struct clk_hw **hws, int num) +{ + return rtk_clk_add_hws_from(dev, data, hws, num, 0); +} + +/** + * struct clk_hw_group - a group of clk_hw + * @hws: clk_hw array + * @num_hws: number of clk_hw in array + */ +struct clk_hw_group { + struct clk_hw **hws; + int num_hws; +}; + +/** + * struct clk_hw_map - map of a clk_hw_group + * @group: a clk_hw group + * @start_index: first id of the group + */ +struct clk_hw_map { + struct clk_hw_group *group; + int start_index; +}; + +static inline +int rtk_clk_add_hw_group_from(struct device *dev, struct rtk_clk_data *data, + struct clk_hw_group *grp, int start_index) +{ + return rtk_clk_add_hws_from(dev, data, grp->hws, grp->num_hws, + start_index); +} + +static inline +int rtk_clk_add_hw_map(struct device *dev, struct rtk_clk_data *data, + const struct clk_hw_map *map) +{ + return rtk_clk_add_hw_group_from(dev, data, map->group, + map->start_index); +} + +static inline +int rtk_clk_add_hw_maps(struct device *dev, struct rtk_clk_data *data, + struct clk_hw_map * const *maps) +{ + int ret; + int i; + + for (i = 0; maps[i]; i++) { + ret = rtk_clk_add_hw_map(dev, data, maps[i]); + if (ret) + return ret; + } + return 0; +} + +/* debugfs init */ +struct dentry; +void set_clk_rate_debugfs_init(struct clk_hw *hw, struct dentry *d); + +#endif /* __CLK_REALTEK_COMMON_H */ + diff --git a/drivers/clk/realtek/debugfs.c b/drivers/clk/realtek/debugfs.c new file mode 100644 index 000000000000..7e8657a7ab57 --- /dev/null +++ b/drivers/clk/realtek/debugfs.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include "common.h" + +static int set_clk_rate_u64_set(void *data, u64 val) +{ + struct clk_hw *hw = data; + + return clk_set_rate(hw->clk, (unsigned long)(val)); +} + +DEFINE_SIMPLE_ATTRIBUTE(set_clk_rate_ops, NULL, + set_clk_rate_u64_set, "%llu\n"); + +void set_clk_rate_debugfs_init(struct clk_hw *hw, struct dentry *d) +{ + debugfs_create_file("set_clk_rate", 0644, d, hw, &set_clk_rate_ops); +} diff --git a/drivers/clk/realtek/of-conf.c b/drivers/clk/realtek/of-conf.c new file mode 100644 index 000000000000..3c15633411ca --- /dev/null +++ b/drivers/clk/realtek/of-conf.c @@ -0,0 +1,15 @@ +#define pr_fmt(fmt) "rtk-clk-of: " fmt +#include +#include + +static void pll_gpu_use_low_freq_mode(struct regmap *regmap) +{ + pr_info("%s\n", __func__); + regmap_update_bits(regmap, 0x1c0, 0x01C00000, 0x00400000); +} + +void of_rtk_clk_setup_crt(struct device_node *np, struct regmap *regmap) +{ + if (of_find_property(np, "pll-gpu,use-low-freq-mode", NULL)) + pll_gpu_use_low_freq_mode(regmap); +} diff --git a/drivers/clk/realtek/of-conf.h b/drivers/clk/realtek/of-conf.h new file mode 100644 index 000000000000..0bf455904d18 --- /dev/null +++ b/drivers/clk/realtek/of-conf.h @@ -0,0 +1,9 @@ +#ifndef __REALTEK_CLK_OF_CONF_H +#define __REALTEK_CLK_OF_CONF_H + +struct device_node; +struct regmap; + +void of_rtk_clk_setup_crt(struct device_node *np, struct regmap *regmap); + +#endif diff --git a/drivers/clk/realtek/reset.c b/drivers/clk/realtek/reset.c new file mode 100644 index 000000000000..ecf690220e67 --- /dev/null +++ b/drivers/clk/realtek/reset.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + */ + +#include +#include +#include +#include +#include +#include +#include "reset.h" + +#define RTK_RESET_MAGIC (0x20) + +static int rtk_reset_should_locked(struct rtk_reset_data *data) +{ + return data->shared && data->lock; +} + +static void rtk_reset_reg_lock(struct rtk_reset_data *data) +{ + if (rtk_reset_should_locked(data)) + sb2_sem_lock(data->lock, SB2_SEM_NO_WARNING); +} + +static void rtk_reset_reg_unlock(struct rtk_reset_data *data) +{ + if (rtk_reset_should_locked(data)) + sb2_sem_unlock(data->lock); +} + + +static int rtk_reset_update_bits(struct rtk_reset_data *data, + uint32_t offset, uint32_t mask, uint32_t val) +{ + int ret; + + rtk_reset_reg_lock(data); + + trace_rtk_pm_reg_update_bits("rstn", offset, mask, val); + + ret = regmap_update_bits(data->regmap, offset, mask, val); + + rtk_reset_reg_unlock(data); + + return ret; +} + +static int rtk_reset_read(struct rtk_reset_data *data, + uint32_t offset, uint32_t *val) +{ + int ret; + + rtk_reset_reg_lock(data); + + ret = regmap_read(data->regmap, offset, val); + + rtk_reset_reg_unlock(data); + + return ret; +} + +static int rtk_reset_assert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + struct rtk_reset_bank *bank = rtk_reset_get_bank(data, idx); + uint32_t id = rtk_reset_get_id(data, idx); + uint32_t mask = bank->write_en ? (0x3 << id) : BIT(id); + uint32_t val = bank->write_en ? (0x2 << id) : 0; + + dev_dbg(data->dev, "%s: idx=%lx\n", __func__, idx); + + return rtk_reset_update_bits(data, bank->ofs, mask, val); +} + +static int rtk_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + struct rtk_reset_bank *bank = rtk_reset_get_bank(data, idx); + uint32_t id = rtk_reset_get_id(data, idx); + uint32_t mask = bank->write_en ? (0x3 << id) : BIT(id); + uint32_t val = mask; + + dev_dbg(data->dev, "%s: idx=%lx\n", __func__, idx); + + return rtk_reset_update_bits(data, bank->ofs, mask, val); +} + +static int rtk_reset_reset(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + int ret; + + dev_dbg(data->dev, "%s: idx=%lx\n", __func__, idx); + + ret = rtk_reset_assert(rcdev, idx); + if (ret) + return ret; + + return rtk_reset_deassert(rcdev, idx); +} + +static int rtk_reset_status(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + struct rtk_reset_bank *bank = &data->banks[idx >> 8]; + uint32_t id = idx & 0xff; + uint32_t val; + + rtk_reset_read(data, bank->ofs, &val); + return !((val >> id) & 1); +} + +static struct reset_control_ops rtk_reset_ops = { + .assert = rtk_reset_assert, + .deassert = rtk_reset_deassert, + .reset = rtk_reset_reset, + .status = rtk_reset_status, +}; + +static int rtk_of_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + int val; + + val = reset_spec->args[0]; + if (val >= rcdev->nr_resets) + return -EINVAL; + + return val; +} + +int rtk_reset_controller_add(struct device *dev, + struct rtk_reset_initdata *initdata) +{ + struct rtk_reset_data *data; + struct device_node *np = dev->of_node; + int ret; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + data->num_banks = initdata->num_banks; + data->banks = initdata->banks; + data->regmap = initdata->regmap; + data->lock = initdata->lock; + data->shared = initdata->shared; + + WARN_ON_ONCE(data->shared && !data->lock); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.ops = &rtk_reset_ops; + data->rcdev.of_node = np; + data->rcdev.nr_resets = initdata->num_banks * 0x100; + data->rcdev.of_xlate = rtk_of_reset_xlate; + data->rcdev.of_reset_n_cells = 1; + + ret = reset_controller_register(&data->rcdev); + if (ret) + kfree(data); + return ret; +} +EXPORT_SYMBOL_GPL(rtk_reset_controller_add); diff --git a/drivers/clk/realtek/reset.h b/drivers/clk/realtek/reset.h new file mode 100644 index 000000000000..a8df4c944d59 --- /dev/null +++ b/drivers/clk/realtek/reset.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __CLK_REALTEK_RESET_H +#define __CLK_REALTEK_RESET_H + +#include +#include + +struct rtk_reset_bank { + uint32_t ofs; + uint32_t write_en; +}; + +struct device; + +struct rtk_reset_data { + struct device *dev; + struct reset_controller_dev rcdev; + struct rtk_reset_bank *banks; + uint32_t num_banks; + struct regmap *regmap; + struct sb2_sem *lock; + int shared; +}; + +#define to_rtk_reset_controller(r) \ + container_of(r, struct rtk_reset_data, rcdev) + +#define RTK_RESET_BANK_SHIFT 8 +#define RTK_RESET_ID_MASK 0xff + +static inline +struct rtk_reset_bank *rtk_reset_get_bank(struct rtk_reset_data *data, + unsigned long idx) +{ + int bank_id = idx >> RTK_RESET_BANK_SHIFT; + + return &data->banks[bank_id]; +} + +static inline +int rtk_reset_get_id(struct rtk_reset_data *data, unsigned long idx) +{ + return idx & RTK_RESET_ID_MASK; +} + +struct rtk_reset_initdata { + struct rtk_reset_bank *banks; + uint32_t num_banks; + unsigned long (*id_xlate)(unsigned long id); + struct regmap *regmap; + struct sb2_sem *lock; + int shared; +}; + +int rtk_reset_controller_add(struct device *dev, + struct rtk_reset_initdata *initdata); + +#endif /* __CLK_REALTEK_RESET_H */ diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index d1bbc16fba4b..e6361cca3c3c 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * acpi-cpufreq.c - ACPI Processor P-States Driver @@ -223,7 +226,16 @@ static unsigned extract_msr(struct cpufreq_policy *policy, u32 msr) perf = to_perf_data(data); cpufreq_for_each_entry(pos, policy->freq_table) +#ifdef MY_DEF_HERE + /* + * The value of MSR_IA32_PERF_CTL (199h) may not match any state of P-State + * table. The different part is "Voltage Target", this field is no use in + * some Intel BIOS, so just compare "P-State Target". + */ + if ((msr & 0xff00) == (perf->states[pos->driver_data].status & 0xff00)) +#else /* MY_DEF_HERE */ if (msr == perf->states[pos->driver_data].status) +#endif /* MY_DEF_HERE */ return pos->frequency; return policy->freq_table[0].frequency; } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 922416b3aace..872bc5ac0653 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Framework for buffer objects that can be shared across devices/subsystems. @@ -1140,6 +1143,47 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf, } EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access); +#if defined(MY_DEF_HERE) +/** + * dma_buf_kmap - Map a page of the buffer object into kernel address space. The + * same restrictions as for kmap and friends apply. + * @dmabuf: [in] buffer to map page from. + * @page_num: [in] page in PAGE_SIZE units to map. + * + * This call must always succeed, any necessary preparations that might fail + * need to be done in begin_cpu_access. + */ +void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num) +{ + WARN_ON(!dmabuf); + + if (!dmabuf->ops->map) + return NULL; + return dmabuf->ops->map(dmabuf, page_num); +} +EXPORT_SYMBOL_GPL(dma_buf_kmap); + +/** + * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap. + * @dmabuf: [in] buffer to unmap page from. + * @page_num: [in] page in PAGE_SIZE units to unmap. + * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap. + * + * This call must always succeed. + */ +void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num, + void *vaddr) +{ + WARN_ON(!dmabuf); + + if (dmabuf->ops->unmap) + dmabuf->ops->unmap(dmabuf, page_num, vaddr); +} +EXPORT_SYMBOL_GPL(dma_buf_kunmap); + + + +#endif /* MY_DEF_HERE */ /** * dma_buf_mmap - Setup up a userspace mmap with the given vma diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 348b3a9170fa..9f04d0f23c55 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Sync File validation framework @@ -10,6 +13,11 @@ #include #include #include +#if defined(MY_DEF_HERE) +#include +#include +#include +#endif /* MY_DEF_HERE */ #include "sync_debug.h" @@ -410,3 +418,24 @@ const struct file_operations sw_sync_debugfs_fops = { .unlocked_ioctl = sw_sync_ioctl, .compat_ioctl = compat_ptr_ioctl, }; + +#if defined(MY_DEF_HERE) +static struct miscdevice sw_sync_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sw_sync", + .fops = &sw_sync_debugfs_fops, +}; + +static int __init sw_sync_device_init(void) +{ + return misc_register(&sw_sync_dev); +} + +static void __exit sw_sync_device_remove(void) +{ + misc_deregister(&sw_sync_dev); +} + +module_init(sw_sync_device_init); +module_exit(sw_sync_device_remove); +#endif /* MY_DEF_HERE */ diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index ea7ca74fc173..65099704c40f 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * UEFI Common Platform Error Record (CPER) support @@ -403,6 +406,32 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); +#ifdef MY_DEF_HERE + // Print AER register + if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { + struct aer_capability_regs *aer; + aer = (struct aer_capability_regs *)pcie->aer_info; + + if (aer->uncor_status) { + printk("%saer_uncor_status: 0x%08x\n", pfx, aer->uncor_status); + printk("%saer_uncor_mask: 0x%08x\n", pfx, aer->uncor_mask); + printk("%saer_uncor_severity: 0x%08x\n", pfx, aer->uncor_severity); + printk("%saer_uncor_err_source: 0x%08x\n", pfx, aer->uncor_err_source); + } else { + printk("%saer_cor_status: 0x%08x\n", pfx, aer->cor_status); + printk("%saer_cor_mask: 0x%08x\n", pfx, aer->cor_mask); + printk("%saer_cor_err_source: 0x%08x\n", pfx, aer->cor_err_source); + } + + printk("%saer_cap_control: 0x%08x\n", pfx, aer->cap_control); + printk("%sheader: 0x%08x\n", pfx, aer->header); + printk("%sroot_command: 0x%08x\n", pfx, aer->root_command); + printk("%sroot_status: 0x%08x\n", pfx, aer->root_status); + printk("%sTLP Header: %08x %08x %08x %08x\n", pfx, + aer->header_log.dw0, aer->header_log.dw1, + aer->header_log.dw2, aer->header_log.dw3); + } +#else // MY_DEF_HERE /* Fatal errors call __ghes_panic() before AER handler prints this */ if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && (gdata->error_severity & CPER_SEV_FATAL)) { @@ -417,6 +446,7 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, aer->header_log.dw0, aer->header_log.dw1, aer->header_log.dw2, aer->header_log.dw3); } +#endif // MY_DEF_HERE } static const char * const fw_err_rec_type_strs[] = { diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 0ef086e43090..3f029f93c830 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ #include @@ -20,6 +23,11 @@ module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); EFI_VARIABLE_BOOTSERVICE_ACCESS | \ EFI_VARIABLE_RUNTIME_ACCESS) +#ifdef MY_ABC_HERE +#define EFI_DUMMY_GUID \ + EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9) +#endif /* MY_ABC_HERE */ + static LIST_HEAD(efi_pstore_list); static DECLARE_WORK(efivar_work, NULL); @@ -250,6 +258,11 @@ static int efi_pstore_write(struct pstore_record *record) efi_char16_t efi_name[DUMP_NAME_LEN]; efi_guid_t vendor = LINUX_EFI_CRASH_GUID; int i, ret = 0; +#ifdef MY_ABC_HERE + unsigned long dummy_size = 0; + void *dummy = NULL; + u64 storage_size, remaining_size, max_size; +#endif /* MY_ABC_HERE */ record->id = generic_id(record->time.tv_sec, record->part, record->count); @@ -268,6 +281,46 @@ static int efi_pstore_write(struct pstore_record *record) ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, preemptible(), record->size, record->psi->buf); +#ifdef MY_ABC_HERE + /* If no space for pstore, set dummy variable to force BIOS doing garbage collection */ + if (-ENOSPC == ret) { + ret = efi.query_variable_info_nonblocking(PSTORE_EFI_ATTRIBUTES, &storage_size, + &remaining_size, + &max_size); + + if (ret != EFI_SUCCESS) { + return -ENOSPC; + } + + dummy_size = remaining_size + 1024; + dummy = kzalloc(dummy_size, GFP_KERNEL); + if (!dummy) { + return -ENOSPC; + } + + ret = efi.set_variable_nonblocking(L"DUMMY", + &EFI_DUMMY_GUID, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + dummy_size, dummy); + + if (ret == EFI_SUCCESS) { + efi.set_variable_nonblocking(L"DUMMY", + &EFI_DUMMY_GUID, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); + } + + kfree(dummy); + + /* After BIOS garbage collection, set pstore variable again */ + ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, + preemptible(), record->size, record->psi->buf); + } +#endif /* MY_ABC_HERE */ + if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE)) if (!schedule_work(&efivar_work)) module_put(THIS_MODULE); @@ -459,7 +512,11 @@ static __exit void efivars_pstore_exit(void) efi_pstore_info.bufsize = 0; } +#ifdef MY_ABC_HERE +subsys_initcall(efivars_pstore_init); +#else /* MY_ABC_HERE */ module_init(efivars_pstore_init); +#endif /* MY_ABC_HERE */ module_exit(efivars_pstore_exit); MODULE_DESCRIPTION("EFI variable backend for pstore"); diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index e6b16b3a17a8..89369e332378 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Originally from efivars.c, @@ -666,5 +669,9 @@ static int efivars_sysfs_init(void) return 0; } +#ifdef MY_ABC_HERE +subsys_initcall(efivars_sysfs_init); +#else /* MY_ABC_HERE */ module_init(efivars_sysfs_init); +#endif /* MY_ABC_HERE */ module_exit(efivars_sysfs_exit); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d1300fc003ed..5934b4a420a6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -178,6 +178,16 @@ config GPIO_RASPBERRYPI_EXP Turn on GPIO support for the expander on Raspberry Pi 3 boards, using the firmware mailbox to communicate with VideoCore on BCM283x chips. +if SYNO_LSP_RTD1619B +config GPIO_RTD + bool "Realtek DHC GPIO support" + depends on ARCH_REALTEK + default y + select GPIOLIB_IRQCHIP + help + Realtek RTD GPIO support. + +endif # SYNO_LSP_RTD1619B config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 09dada80ac34..c9bd87f1b855 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -125,6 +125,9 @@ obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o obj-$(CONFIG_GPIO_RDA) += gpio-rda.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_REG) += gpio-reg.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_GPIO_RTD) += gpio-rtd.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o @@ -180,3 +183,4 @@ obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZX) += gpio-zx.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o +obj-$(CONFIG_SYNO_GPIO) += syno_gpio.o diff --git a/drivers/gpio/gpio-rtd.c b/drivers/gpio/gpio-rtd.c new file mode 100644 index 000000000000..8efe38e7ce6e --- /dev/null +++ b/drivers/gpio/gpio-rtd.c @@ -0,0 +1,747 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Realtek DHC gpio driver + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * Copyright (c) 2017 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rtd_gpio_info { + const char *name; + unsigned int gpio_base; + unsigned int num_gpios; + unsigned int (*dir_offset)(unsigned int offset); + unsigned int (*dato_offset)(unsigned int offset); + unsigned int (*dati_offset)(unsigned int offset); + unsigned int (*ie_offset)(unsigned int offset); + unsigned int (*dp_offset)(unsigned int offset); + unsigned int (*gpa_offset)(unsigned int offset); + unsigned int (*gpda_offset)(unsigned int offset); + unsigned int (*deb_offset)(unsigned int offset); +}; + +struct rtd_gpio { + struct platform_device *pdev; + const struct rtd_gpio_info *info; + void __iomem *base; + void __iomem *irq_base; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; + int assert_irq; + int deassert_irq; + struct irq_domain *domain; + spinlock_t lock; +}; + +#define to_rtd_gpio_chip(chip) container_of(chip, struct rtd_gpio, gpio_chip) + +static int rtd_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned int debounce) +{ + struct rtd_gpio *data = to_rtd_gpio_chip(chip); + unsigned long flags; + unsigned int reg_offset; + unsigned int shift = (offset % 8) * 4; + unsigned int write_en = BIT(shift + 3); + u32 val; + u32 deb_val; + + switch(debounce) { + case 1: + deb_val = 0; + break; + case 10: + deb_val = 1; + break; + case 100: + deb_val = 2; + break; + case 1000: + deb_val = 3; + break; + case 10000: + deb_val = 4; + break; + case 20000: + deb_val = 5; + break; + case 30000: + deb_val = 6; + break; + default: + return -ENOTSUPP; + } + + val = (deb_val << shift) | write_en; + reg_offset = data->info->deb_offset(offset); + + spin_lock_irqsave(&data->lock, flags); + writel_relaxed(val, data->base + reg_offset); + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + + +static int rtd_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + int debounce; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + return pinctrl_gpio_set_config(chip->base + offset, config); + case PIN_CONFIG_INPUT_DEBOUNCE: + debounce = pinconf_to_config_argument(config); + return rtd_gpio_set_debounce(chip, offset, debounce); + default: + return -ENOTSUPP; + } +} + + +static int rtd_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_gpio_request(chip->base + offset); +} + +static void rtd_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + pinctrl_gpio_free(chip->base + offset); +} + +static int rtd_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct rtd_gpio *data = to_rtd_gpio_chip(chip); + unsigned long flags; + unsigned int reg_offset; + u32 val; + + reg_offset = data->info->dir_offset(offset); + + spin_lock_irqsave(&data->lock, flags); + + val = readl_relaxed(data->base + reg_offset); + val &= BIT(offset % 32); + + spin_unlock_irqrestore(&data->lock, flags); + + return (val) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + +static int rtd_gpio_set_direction(struct gpio_chip *chip, unsigned int offset, bool out) +{ + struct rtd_gpio *data = to_rtd_gpio_chip(chip); + unsigned long flags; + unsigned int reg_offset; + u32 mask = BIT(offset % 32); + u32 val; + + reg_offset = data->info->dir_offset(offset); + + spin_lock_irqsave(&data->lock, flags); + + val = readl_relaxed(data->base + reg_offset); + if (out) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, data->base + reg_offset); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int rtd_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return rtd_gpio_set_direction(chip, offset, false); +} + +static int rtd_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) +{ + chip->set(chip, offset, value); + return rtd_gpio_set_direction(chip, offset, true); +} + +static void rtd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct rtd_gpio *data = to_rtd_gpio_chip(chip); + unsigned long flags; + unsigned int dato_reg_offset; + u32 mask = BIT(offset % 32); + u32 val; + + dato_reg_offset = data->info->dato_offset(offset); + + spin_lock_irqsave(&data->lock, flags); + + val = readl_relaxed(data->base + dato_reg_offset); + if (value) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, data->base + dato_reg_offset); + + spin_unlock_irqrestore(&data->lock, flags); +} + +static int rtd_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct rtd_gpio *data = to_rtd_gpio_chip(chip); + unsigned long flags; + unsigned int dir_reg_offset, dat_reg_offset; + u32 val; + + dir_reg_offset = data->info->dir_offset(offset); + + spin_lock_irqsave(&data->lock, flags); + + val = readl_relaxed(data->base + dir_reg_offset); + val &= BIT(offset % 32); + dat_reg_offset = (val) ? data->info->dato_offset(offset) : data->info->dati_offset(offset); + + val = readl_relaxed(data->base + dat_reg_offset); + val >>= offset % 32; + val &= 0x1; + + spin_unlock_irqrestore(&data->lock, flags); + + return val; +} + + +static int rtd_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct rtd_gpio *data = to_rtd_gpio_chip(chip); + u32 irq = 0; + + irq = irq_find_mapping(data->domain, offset); + if (!irq) { + dev_err(&data->pdev->dev, "%s: can not find irq number for hwirq= %d\n", __func__, offset); + return -EINVAL; + } + return irq; +} + + +static unsigned int rtd_iso_gpio_dir_offset(unsigned int offset) +{ + int reg_off = 0; + int group = offset / 32; + + switch(group){ + case 0: + reg_off = 0x0; + break; + case 1: + reg_off = 0x18; + break; + case 2: + reg_off = 0x2c; + break; + default: + reg_off = -EINVAL; + break; + } + return reg_off; +} + +static unsigned int rtd_iso_gpio_dato_offset(unsigned int offset) +{ + int reg_off = 0; + int group = offset / 32; + + switch(group){ + case 0: + reg_off = 0x4; + break; + case 1: + reg_off = 0x1c; + break; + case 2: + reg_off = 0x30; + break; + default: + reg_off = -EINVAL; + break; + } + return reg_off; +} + +static unsigned int rtd_iso_gpio_dati_offset(unsigned int offset) +{ + int reg_off = 0; + int group = offset / 32; + + switch(group){ + case 0: + reg_off = 0x8; + break; + case 1: + reg_off = 0x20; + break; + case 2: + reg_off = 0x34; + break; + default: + reg_off = -EINVAL; + break; + } + return reg_off; +} + +static unsigned int rtd_iso_gpio_ie_offset(unsigned int offset) +{ + int reg_off = 0; + int group = offset / 32; + + switch(group){ + case 0: + reg_off = 0xc; + break; + case 1: + reg_off = 0x24; + break; + case 2: + reg_off = 0x38; + break; + default: + reg_off = -EINVAL; + break; + } + return reg_off; +} + +static unsigned int rtd_iso_gpio_dp_offset(unsigned int offset) +{ + int reg_off = 0; + int group = offset / 32; + + switch(group){ + case 0: + reg_off = 0x10; + break; + case 1: + reg_off = 0x28; + break; + case 2: + reg_off = 0x3c; + break; + default: + reg_off = -EINVAL; + break; + } + return reg_off; +} + +static unsigned int rtd_iso_gpio_gpa_offset(unsigned int offset) +{ + unsigned int group = offset / 31; + unsigned int ret = 0; + + switch (group) { + case 0: + ret = 0x08; + break; + case 1: + ret = 0xE0; + break; + case 2: + ret = 0x90; + break; + default: + pr_err("GPIO iso gpa offset(%d) over range\n", offset); + break; + } + return ret; +} + +static unsigned int rtd_iso_gpio_gpda_offset(unsigned int offset) +{ + unsigned int group = offset / 31; + unsigned int ret = 0; + + switch (group) { + case 0: + ret = 0x0C; + break; + case 1: + ret = 0xE4; + break; + case 2: + ret = 0x94; + break; + default: + pr_err("GPIO iso gpda offset(%d) over range\n", offset); + break; + } + return ret; +} + +static unsigned int rtd_iso_gpio_deb_offset(unsigned int offset) +{ + unsigned int group = offset / 8; + unsigned int ret = 0; + + switch (group) { + case 0: + ret = 0x44; + break; + case 1: + ret = 0x48; + break; + case 2: + ret = 0x4C; + break; + case 3: + ret = 0x50; + break; + case 4: + ret = 0x54; + break; + case 5: + ret = 0x58; + break; + case 6: + ret = 0x5C; + break; + case 7: + ret = 0x60; + break; + case 8: + ret = 0x64; + break; + case 9: + ret = 0x68; + break; + case 10: + ret = 0x6C; + break; + default: + pr_err("GPIO iso deb offset(%d) over range\n", offset); + break; + } + return ret; +} + + +static const struct rtd_gpio_info rtd_iso_gpio_info = { + .name = "rtk_iso_gpio", + .gpio_base = 0, + .num_gpios = 82, + .dir_offset = rtd_iso_gpio_dir_offset, + .dato_offset = rtd_iso_gpio_dato_offset, + .dati_offset = rtd_iso_gpio_dati_offset, + .ie_offset = rtd_iso_gpio_ie_offset, + .dp_offset = rtd_iso_gpio_dp_offset, + .gpa_offset = rtd_iso_gpio_gpa_offset, + .gpda_offset = rtd_iso_gpio_gpda_offset, + .deb_offset = rtd_iso_gpio_deb_offset, +}; + +static bool rtd_gpio_check_ie(struct rtd_gpio *data, int irq) +{ + unsigned int ie_reg_offset; + u32 enable; + int mask = BIT(irq % 32); + + ie_reg_offset = data->info->ie_offset(irq); + enable = readl_relaxed(data->base + ie_reg_offset); + + return enable & mask; +} + +static void rtd_gpio_assert_irq_handle(struct irq_desc *desc) +{ + struct rtd_gpio *data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int gpa_reg_offset; + u32 status; + int hwirq; + int i; + int j; + + chained_irq_enter(chip, desc); + + for (i = 0; i < data->info->num_gpios; i = i + 31) { + gpa_reg_offset = data->info->gpa_offset(i); + status = readl_relaxed(data->irq_base + gpa_reg_offset) >> 1; + writel_relaxed(status << 1, data->irq_base + gpa_reg_offset); + + while (status) { + j = __ffs(status); + status &= ~BIT(j); + hwirq = i + j; + if (rtd_gpio_check_ie(data, hwirq)) { + int irq = irq_find_mapping(data->domain, hwirq); + + generic_handle_irq(irq); + } + } + } + + chained_irq_exit(chip, desc); +} + +static void rtd_gpio_deassert_irq_handle(struct irq_desc *desc) +{ + struct rtd_gpio *data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int gpda_reg_offset; + u32 status; + int hwirq; + int i; + int j; + + chained_irq_enter(chip, desc); + + for (i = 0; i < data->info->num_gpios; i = i + 31) { + gpda_reg_offset = data->info->gpda_offset(i); + status = readl_relaxed(data->irq_base + gpda_reg_offset) >> 1; + writel_relaxed(status << 1, data->irq_base + gpda_reg_offset); + + while (status) { + j = __ffs(status); + status &= ~BIT(j); + hwirq = i + j; + if (rtd_gpio_check_ie(data, hwirq)) { + int irq = irq_find_mapping(data->domain, hwirq); + u32 irq_type = irq_get_trigger_type(irq); + + if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) + generic_handle_irq(irq); + } + } + } + + chained_irq_exit(chip, desc); +} + +static void rtd_gpio_enable_irq(struct irq_data *d) +{ + struct rtd_gpio *data = irq_data_get_irq_chip_data(d); + unsigned long flags; + unsigned int ie_reg_offset; + unsigned int gpa_reg_offset; + unsigned int gpda_reg_offset; + u32 ie_mask = BIT(d->hwirq % 32); + u32 clr_mask = BIT(d->hwirq % 31) << 1; + u32 val; + + ie_reg_offset = data->info->ie_offset(d->hwirq); + gpa_reg_offset = data->info->gpa_offset(d->hwirq); + gpda_reg_offset = data->info->gpda_offset(d->hwirq); + + spin_lock_irqsave(&data->lock, flags); + + writel_relaxed(clr_mask, data->irq_base + gpa_reg_offset); + writel_relaxed(clr_mask, data->irq_base + gpda_reg_offset); + + val = readl_relaxed(data->base + ie_reg_offset); + val |= ie_mask; + writel_relaxed(val, data->base + ie_reg_offset); + + spin_unlock_irqrestore(&data->lock, flags); + +} + +static void rtd_gpio_disable_irq(struct irq_data *d) +{ + struct rtd_gpio *data = irq_data_get_irq_chip_data(d); + unsigned long flags; + unsigned int ie_reg_offset; + u32 ie_mask = BIT(d->hwirq % 32); + u32 val; + + ie_reg_offset = data->info->ie_offset(d->hwirq); + + spin_lock_irqsave(&data->lock, flags); + + val = readl_relaxed(data->base + ie_reg_offset); + val &= ~ie_mask; + writel_relaxed(val, data->base + ie_reg_offset); + + spin_unlock_irqrestore(&data->lock, flags); +} + + +static int rtd_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct rtd_gpio *data = irq_data_get_irq_chip_data(d); + unsigned long flags; + unsigned int dp_reg_offset; + u32 mask = BIT(d->hwirq % 32); + u32 val; + bool polarity; + + dp_reg_offset = data->info->dp_offset(d->hwirq); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + polarity = 1; + break; + + case IRQ_TYPE_EDGE_FALLING: + polarity = 0; + break; + + case IRQ_TYPE_EDGE_BOTH: + polarity = 1; + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&data->lock, flags); + + val = readl_relaxed(data->base + dp_reg_offset); + if (polarity) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, data->base + dp_reg_offset); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + + +static const struct irq_chip rtd_gpio_irq_chip = { + .irq_enable = rtd_gpio_enable_irq, + .irq_disable = rtd_gpio_disable_irq, + .irq_set_type = rtd_gpio_irq_set_type, +}; + +static const struct of_device_id rtd_gpio_of_matches[] = { + { .compatible = "realtek,gpio", .data = &rtd_iso_gpio_info } +}; + +static int rtd_gpio_probe(struct platform_device *pdev) +{ + struct rtd_gpio *data; + const struct of_device_id *match; + struct resource *res; + struct device_node *node; + int ret; + int i; + + node = pdev->dev.of_node; + match = of_match_node(rtd_gpio_of_matches, pdev->dev.of_node); + if (!match) + return -EINVAL; + if (!match->data) + return -EINVAL; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->info = match->data; + spin_lock_init(&data->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + data->irq_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->irq_base)) { + return PTR_ERR(data->irq_base); + } + data->gpio_chip.parent = &pdev->dev; + data->gpio_chip.label = dev_name(&pdev->dev); + data->gpio_chip.of_node = pdev->dev.of_node; + data->gpio_chip.of_gpio_n_cells = 2; + data->gpio_chip.base = data->info->gpio_base; + data->gpio_chip.ngpio = data->info->num_gpios; + data->gpio_chip.request = rtd_gpio_request; + data->gpio_chip.free = rtd_gpio_free; + data->gpio_chip.get_direction = rtd_gpio_get_direction; + data->gpio_chip.direction_input = rtd_gpio_direction_input; + data->gpio_chip.direction_output = rtd_gpio_direction_output; + data->gpio_chip.set = rtd_gpio_set; + data->gpio_chip.get = rtd_gpio_get; + data->gpio_chip.set_config = rtd_gpio_set_config; + data->gpio_chip.to_irq = rtd_gpio_to_irq; + data->irq_chip = rtd_gpio_irq_chip; + data->irq_chip.name = data->info->name; + + data->assert_irq = irq_of_parse_and_map(node, 0); + if (data->assert_irq <= 0) { + kfree(data); + return -EINVAL; + } + + data->deassert_irq = irq_of_parse_and_map(node, 1); + if (data->deassert_irq <= 0) { + kfree(data); + return -EINVAL; + } + + ret = gpiochip_add(&data->gpio_chip); + if (ret) { + dev_err(&pdev->dev, "Adding GPIO chip failed (%d)\n", ret); + return ret; + } + + data->domain = irq_domain_add_linear(node, data->gpio_chip.ngpio, + &irq_domain_simple_ops, data); + if (!data->domain) { + kfree(data); + return -ENOMEM; + } + + for (i = 0; i < data->gpio_chip.ngpio; i++) { + int irq = irq_create_mapping(data->domain, i); + + irq_set_chip_data(irq, data); + irq_set_chip_and_handler(irq, &data->irq_chip, handle_simple_irq); + } + + irq_set_chained_handler_and_data(data->assert_irq, rtd_gpio_assert_irq_handle, data); + irq_set_chained_handler_and_data(data->deassert_irq, rtd_gpio_deassert_irq_handle, data); + platform_set_drvdata(pdev, data); + + dev_info(&pdev->dev, "probed\n"); + + return 0; +} + +static struct platform_driver rtd_gpio_platform_driver = { + .driver = { + .name = "gpio-rtd", + .of_match_table = rtd_gpio_of_matches, + }, + .probe = rtd_gpio_probe, +}; + + +static int rtd_gpio_init(void) +{ + return platform_driver_register(&rtd_gpio_platform_driver); +} + +postcore_initcall(rtd_gpio_init); + diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index af5bb8fedfea..090d85090d05 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -105,15 +108,26 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) { struct gpio_device *gdev; unsigned long flags; +#ifdef MY_ABC_HERE + unsigned int gpio_base = 0; +#endif /* MY_ABC_HERE */ spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(gdev, &gpio_devices, list) { +#ifdef MY_ABC_HERE + gpio_base = ARCH_NR_GPIOS - (gdev->base+gdev->ngpio); + if (gpio_base <= gpio && gpio_base + gdev->ngpio > gpio) { + spin_unlock_irqrestore(&gpio_lock, flags); + return &gdev->descs[gpio - gpio_base]; + } +#else /* MY_ABC_HERE */ if (gdev->base <= gpio && gdev->base + gdev->ngpio > gpio) { spin_unlock_irqrestore(&gpio_lock, flags); return &gdev->descs[gpio - gdev->base]; } +#endif /* MY_ABC_HERE */ } spin_unlock_irqrestore(&gpio_lock, flags); diff --git a/drivers/gpio/syno_gpio.c b/drivers/gpio/syno_gpio.c new file mode 100644 index 000000000000..d9a04de821d9 --- /dev/null +++ b/drivers/gpio/syno_gpio.c @@ -0,0 +1,431 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Synology NAS Board GPIO Setup + * + * Maintained by: Comsumer Platform Team + * + * Copyright 2009-2015 Synology, Inc. 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 as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +#include +#include + +#ifdef MY_ABC_HERE +#include +#include +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ + +SYNO_GPIO syno_gpio = { + .fan_ctrl =NULL, + .fan_fail =NULL, + .hdd_fail_led =NULL, + .hdd_present_led =NULL, + .hdd_act_led =NULL, + .hdd_detect =NULL, + .hdd_enable =NULL, + .model_id =NULL, + .alarm_led =NULL, + .power_led =NULL, + .disk_led_ctrl =NULL, + .phy_led_ctrl =NULL, + .copy_button_detect =NULL, + .redundant_power_detect =NULL, +}; +EXPORT_SYMBOL(syno_gpio); + +void syno_gpio_direction_output(int pin, int pValue) +{ + int iErr = 0; + iErr = gpio_request(pin, NULL); + if (iErr) { + printk("%s:%s(%d) gpio_request pin %d fail!\n", __FILE__, __FUNCTION__, __LINE__, pin); + goto END; + } + iErr = gpio_direction_output(pin, pValue); + if (iErr) { + printk("%s:%s(%d) set gpio pin %d value %d fail!\n", __FILE__, __FUNCTION__, __LINE__, pin, pValue); + goto UNLOCK; + } +UNLOCK: + gpio_free(pin); +END: + return; +} +EXPORT_SYMBOL(syno_gpio_direction_output); + +void syno_gpio_direction_input(int pin) +{ + int iErr = 0; + iErr = gpio_request(pin, NULL); + if (iErr) { + printk("%s:%s(%d) gpio_request pin %d fail!\n", __FILE__, __FUNCTION__, __LINE__, pin); + goto END; + } + iErr = gpio_direction_input(pin); + if (iErr) { + printk("%s:%s(%d) set gpio pin %d input fail!\n", __FILE__, __FUNCTION__, __LINE__, pin); + goto UNLOCK; + } +UNLOCK: + gpio_free(pin); +END: + return; +} +EXPORT_SYMBOL(syno_gpio_direction_input); + +int syno_gpio_to_irq(int pin) +{ + return gpio_to_irq(pin); +} +EXPORT_SYMBOL(syno_gpio_to_irq); + +int SYNO_GPIO_READ(int pin) +{ + return gpio_get_value(pin); +} +EXPORT_SYMBOL(SYNO_GPIO_READ); + +void SYNO_GPIO_WRITE(int pin, int pValue) +{ + gpio_set_value(pin, pValue); +} +EXPORT_SYMBOL(SYNO_GPIO_WRITE); + +int SynoHaveRPDetectPin(void) +{ + if (syno_gpio.redundant_power_detect && + HAVE_RP_DETECT(1) && + HAVE_RP_DETECT(2)) { + return 1; + } + return 0; +} +int SynoAllRedundantPowerDetected(void) +{ + if (syno_gpio.redundant_power_detect && 2 == syno_gpio.redundant_power_detect->nr_gpio && + !(SYNO_GPIO_READ(RP_DETECT_PIN(1)) ^ SYNO_GPIO_READ(RP_DETECT_PIN(2)))) { + return 1; + } + return 0; +} + +#ifdef MY_DEF_HERE +extern int giSynoSpinupGroupDebug; +void DBG_SpinupGroupListGpio(void) +{ + int i = 0; + if (giSynoSpinupGroupDebug && NULL != syno_gpio.hdd_detect) { + for (i = 0; i < syno_gpio.hdd_detect->nr_gpio; i++) { + printk("gpio debug: hdd detect pin %d, value= %d\n", HDD_DETECT_PIN(i + 1), SYNO_GPIO_READ(HDD_DETECT_PIN(i + 1))); + } + for (i = 0; i < syno_gpio.hdd_enable->nr_gpio; i++) { + printk("gpio debug: hdd enable pin %d, value= %d\n", HDD_ENABLE_PIN(i + 1), SYNO_GPIO_READ(HDD_ENABLE_PIN(i + 1))); + } + if (syno_gpio.redundant_power_detect && 2 == syno_gpio.redundant_power_detect->nr_gpio) { + printk("gpio debug: redundant power detect pin %d, value= %d\n", RP_DETECT_PIN(1), SYNO_GPIO_READ(RP_DETECT_PIN(1))); + printk("gpio debug: redundant power detect pin %d, value= %d\n", RP_DETECT_PIN(2), SYNO_GPIO_READ(RP_DETECT_PIN(2))); + } + } +} +EXPORT_SYMBOL(DBG_SpinupGroupListGpio); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +/** + * syno_disk_gpio_pin_get - get the property content of internal slot + * @diskPort [IN]: internel slot number + * @szPropertyName [IN]: + * @propertyIndex [IN]: index of number need be read in szPropertyName + * + * return >=0: property number in device tree of internal slot + * -1: fail + */ +u32 syno_disk_gpio_pin_get(const int diskPort, const char *szPropertyName, const int propertyIndex) +{ + int index= 0; + u32 synoGpioPin = U32_MAX; + struct device_node *pSlotNode = NULL; + + if (NULL == szPropertyName || 1 > diskPort || 0 >propertyIndex) { + goto END; + } + + for_each_child_of_node(of_root, pSlotNode) { + // get index number of internal_slot, e.g. internal_slot@4 --> 4 + if (!pSlotNode->full_name || 1 != sscanf(pSlotNode->full_name, DT_INTERNAL_SLOT"@%d", &index)) { + continue; + } + + if (diskPort == index) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + of_property_read_u32_index(pSlotNode, szPropertyName, propertyIndex, &synoGpioPin); + of_node_put(pSlotNode); + +END: + return synoGpioPin; +} +EXPORT_SYMBOL(syno_disk_gpio_pin_get); + +/** + * syno_disk_gpio_pin_have - determine the szPropertyName of the internal slot is defined in device tree + * @diskPort [IN]: internel slot number + * @szPropertyName [IN]: + * + * return 1: property exist + * 0: property not exist + */ +int syno_disk_gpio_pin_have(const int diskPort, const char *szPropertyName) +{ + u32 synoGpioPin = U32_MAX; + int ret = -1; + + synoGpioPin = syno_disk_gpio_pin_get(diskPort, szPropertyName, SYNO_GPIO_PIN); + + if (U32_MAX != synoGpioPin) { + ret = 1; + } else { + ret = 0; + } + return ret; +} +EXPORT_SYMBOL(syno_disk_gpio_pin_have); +/** + * syno_led_pin_get - get the szLedName pin of target slot + * @szSlotName [IN]: slot name + * @diskPort [IN]: slot number + * @szLedName [IN]: LED node name in device node + * @propertyIndex [IN]: index of number need be read in DT_SYNO_GPIO + * + * return >=0: property number in device tree of target slot + * -1: fail + */ +u32 syno_led_pin_get(const char* szSlotName, const int diskPort, const char *szLedName, const int propertyIndex) +{ + u32 synoGpioPin = U32_MAX; + struct device_node *pSlotNode = NULL, *pLedNode = NULL; + char szFullName[MAX_NODENAME_LEN] = {0}; + + if (NULL == szSlotName || NULL == szLedName || 1 > diskPort || 0 > propertyIndex) { + goto END; + } + if (0 > snprintf(szFullName, MAX_NODENAME_LEN - 1, "%s@%d", szSlotName, diskPort)) { + goto END; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (pSlotNode->full_name && 0 == strcmp(pSlotNode->full_name, szFullName)) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + pLedNode = of_get_child_by_name(pSlotNode, szLedName); + of_node_put(pSlotNode); + if (NULL == pLedNode) { + goto END; + } + of_property_read_u32_index(pLedNode, DT_SYNO_GPIO, propertyIndex, &synoGpioPin); + of_node_put(pLedNode); + +END: + return synoGpioPin; +} +EXPORT_SYMBOL(syno_led_pin_get); + +/** + * syno_led_pin_have - determine the szLedName of the target slot is defined in device tree + * @szSlotName [IN]: slot name + * @diskPort [IN]: slot number + * @szLedName [IN]: LED node name in device node + * + * return 1: szLedName exist + * 0: szLedName not exist + */ +int syno_led_pin_have(const char* szSlotName, const int diskPort, const char *szLedName) +{ + u32 synoGpioPin = U32_MAX; + int ret = -1; + + if (szSlotName && szLedName) { + synoGpioPin = syno_led_pin_get(szSlotName, diskPort, szLedName, SYNO_GPIO_PIN); + } + + if (U32_MAX != synoGpioPin) { + ret = 1; + } else { + ret = 0; + } + return ret; +} +EXPORT_SYMBOL(syno_led_pin_have); + +/** + * syno_led_name_get - get the szLedName led_name of target slot + * @szSlotName [IN]: slot name + * @diskPort [IN]: slot number + * @szLedType [IN]: LED node name in device node + * + */ +int syno_led_name_get(const char* szSlotName, const int diskPort, const char *szLedType, char *szSynoLedName, unsigned int cbSynoLedName) +{ + int iRet = -1; + struct device_node *pSlotNode = NULL, *pLedNode = NULL; + char szFullName[MAX_NODENAME_LEN] = {0}; + const char *szLedName = NULL; + + if (NULL == szSlotName || NULL == szLedType || 1 > diskPort || NULL == szSynoLedName) { + goto END; + } + if (0 > snprintf(szFullName, MAX_NODENAME_LEN - 1, "%s@%d", szSlotName, diskPort)) { + goto END; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (pSlotNode->full_name && 0 == strcmp(pSlotNode->full_name, szFullName)) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + pLedNode = of_get_child_by_name(pSlotNode, szLedType); + of_node_put(pSlotNode); + if (NULL == pLedNode) { + goto END; + } + of_property_read_string(pLedNode, DT_HDD_LED_NAME, &szLedName); + of_node_put(pLedNode); + if (0 > snprintf(szSynoLedName, cbSynoLedName, "%s", szLedName)) { + goto END; + } + iRet = 0; +END: + return iRet; +} +EXPORT_SYMBOL(syno_led_name_get); + +/** + * syno_led_type_get - get the szLedType led_type of target slot + * @szSlotName [IN]: slot name + * @diskPort [IN]: slot number + * + */ +int syno_led_type_get(const char* szSlotName, const int diskPort, char *szSynoLedType, unsigned int cbSynoLedType) +{ + int iRet = -1; + struct device_node *pSlotNode = NULL; + char szFullName[MAX_NODENAME_LEN] = {0}; + const char *szLedType = NULL; + + if (NULL == szSlotName || 1 > diskPort || NULL == szSynoLedType) { + goto END; + } + if (0 > snprintf(szFullName, MAX_NODENAME_LEN - 1, "%s@%d", szSlotName, diskPort)) { + goto END; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (pSlotNode->full_name && 0 == strcmp(pSlotNode->full_name, szFullName)) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + + of_property_read_string(pSlotNode, DT_HDD_LED_TYPE, &szLedType); + of_node_put(pSlotNode); + if (0 > snprintf(szSynoLedType, cbSynoLedType, "%s", szLedType)) { + goto END; + } + iRet = 0; +END: + return iRet; +} +EXPORT_SYMBOL(syno_led_type_get); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +/** + * syno_led_dev_get - get the szLedType led_type of target slot + * @szSlotName [IN]: slot name + * @diskPort [IN]: slot number + * + */ +struct led_classdev* syno_led_dev_get(const char* szSlotName, const int diskPort, const char* szledName) +{ + struct led_classdev* led_cdev = NULL; + struct device_node *pSlotNode = NULL; + struct device_node *pLedNode = NULL; + char szFullName[MAX_NODENAME_LEN] = {0}; + + if (NULL == szSlotName || 1 > diskPort || NULL == szledName) { + goto END; + } + + if (0 > snprintf(szFullName, MAX_NODENAME_LEN - 1, "%s@%d", szSlotName, diskPort)) { + goto END; + } + + for_each_child_of_node(of_root, pSlotNode) { + if (pSlotNode->full_name && 0 == strcmp(pSlotNode->full_name, szFullName)) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + + pLedNode = of_parse_phandle(pSlotNode, szledName, 0); + of_node_put(pSlotNode); + if (!pLedNode) { + printk(KERN_WARNING "No LED %s.\n", szledName); + goto END; + } + + led_cdev = of_leddev_get(pLedNode); + of_node_put(pLedNode); + if (IS_ERR(led_cdev)) { + led_cdev = NULL; + printk(KERN_ERR "can't get class\n"); + goto END; + } + +END: + return led_cdev; +} +EXPORT_SYMBOL(syno_led_dev_get); +#endif /* MY_DEF_HERE */ diff --git a/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h index 4c5097fa0c09..d5ef91d3c391 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/umc/umc_8_7_0_sh_mask.h @@ -1,79 +1,79 @@ -#ifndef _umc_8_7_0_SH_MASK_HEADER -#define _umc_8_7_0_SH_MASK_HEADER - -//UMCCH0_0_GeccErrCntSel -#define UMCCH0_0_GeccErrCntSel__GeccErrCntCsSel__SHIFT 0x0 -#define UMCCH0_0_GeccErrCntSel__GeccErrInt__SHIFT 0xc -#define UMCCH0_0_GeccErrCntSel__GeccErrCntEn__SHIFT 0xf -#define UMCCH0_0_GeccErrCntSel__PoisonCntEn__SHIFT 0x10 -#define UMCCH0_0_GeccErrCntSel__GeccErrCntCsSel_MASK 0x0000000FL -#define UMCCH0_0_GeccErrCntSel__GeccErrInt_MASK 0x00003000L -#define UMCCH0_0_GeccErrCntSel__GeccErrCntEn_MASK 0x00008000L -#define UMCCH0_0_GeccErrCntSel__PoisonCntEn_MASK 0x00030000L -//UMCCH0_0_GeccErrCnt -#define UMCCH0_0_GeccErrCnt__GeccErrCnt__SHIFT 0x0 -#define UMCCH0_0_GeccErrCnt__GeccUnCorrErrCnt__SHIFT 0x10 -#define UMCCH0_0_GeccErrCnt__GeccErrCnt_MASK 0x0000FFFFL -#define UMCCH0_0_GeccErrCnt__GeccUnCorrErrCnt_MASK 0xFFFF0000L -//MCA_UMC_UMC0_MCUMC_STATUST0 -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCode__SHIFT 0x0 -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCodeExt__SHIFT 0x10 -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV22__SHIFT 0x16 -#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrLsb__SHIFT 0x18 -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV30__SHIFT 0x1e -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreId__SHIFT 0x20 -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV38__SHIFT 0x26 -#define MCA_UMC_UMC0_MCUMC_STATUST0__Scrub__SHIFT 0x28 -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV41__SHIFT 0x29 -#define MCA_UMC_UMC0_MCUMC_STATUST0__Poison__SHIFT 0x2b -#define MCA_UMC_UMC0_MCUMC_STATUST0__Deferred__SHIFT 0x2c -#define MCA_UMC_UMC0_MCUMC_STATUST0__UECC__SHIFT 0x2d -#define MCA_UMC_UMC0_MCUMC_STATUST0__CECC__SHIFT 0x2e -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV47__SHIFT 0x2f -#define MCA_UMC_UMC0_MCUMC_STATUST0__Transparent__SHIFT 0x34 -#define MCA_UMC_UMC0_MCUMC_STATUST0__SyndV__SHIFT 0x35 -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV54__SHIFT 0x36 -#define MCA_UMC_UMC0_MCUMC_STATUST0__TCC__SHIFT 0x37 -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreIdVal__SHIFT 0x38 -#define MCA_UMC_UMC0_MCUMC_STATUST0__PCC__SHIFT 0x39 -#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrV__SHIFT 0x3a -#define MCA_UMC_UMC0_MCUMC_STATUST0__MiscV__SHIFT 0x3b -#define MCA_UMC_UMC0_MCUMC_STATUST0__En__SHIFT 0x3c -#define MCA_UMC_UMC0_MCUMC_STATUST0__UC__SHIFT 0x3d -#define MCA_UMC_UMC0_MCUMC_STATUST0__Overflow__SHIFT 0x3e -#define MCA_UMC_UMC0_MCUMC_STATUST0__Val__SHIFT 0x3f -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCode_MASK 0x000000000000FFFFL -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCodeExt_MASK 0x00000000003F0000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV22_MASK 0x0000000000C00000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrLsb_MASK 0x000000003F000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV30_MASK 0x00000000C0000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreId_MASK 0x0000003F00000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV38_MASK 0x000000C000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__Scrub_MASK 0x0000010000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV41_MASK 0x0000060000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__Poison_MASK 0x0000080000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__Deferred_MASK 0x0000100000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__UECC_MASK 0x0000200000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__CECC_MASK 0x0000400000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV47_MASK 0x000F800000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__Transparent_MASK 0x0010000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__SyndV_MASK 0x0020000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV54_MASK 0x0040000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__TCC_MASK 0x0080000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreIdVal_MASK 0x0100000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__PCC_MASK 0x0200000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrV_MASK 0x0400000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__MiscV_MASK 0x0800000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__En_MASK 0x1000000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__UC_MASK 0x2000000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__Overflow_MASK 0x4000000000000000L -#define MCA_UMC_UMC0_MCUMC_STATUST0__Val_MASK 0x8000000000000000L -//MCA_UMC_UMC0_MCUMC_ADDRT0 -#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr__SHIFT 0x0 -#define MCA_UMC_UMC0_MCUMC_ADDRT0__LSB__SHIFT 0x38 -#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved__SHIFT 0x3e -#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr_MASK 0x00FFFFFFFFFFFFFFL -#define MCA_UMC_UMC0_MCUMC_ADDRT0__LSB_MASK 0x3F00000000000000L -#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved_MASK 0xC000000000000000L - -#endif +#ifndef _umc_8_7_0_SH_MASK_HEADER +#define _umc_8_7_0_SH_MASK_HEADER + +//UMCCH0_0_GeccErrCntSel +#define UMCCH0_0_GeccErrCntSel__GeccErrCntCsSel__SHIFT 0x0 +#define UMCCH0_0_GeccErrCntSel__GeccErrInt__SHIFT 0xc +#define UMCCH0_0_GeccErrCntSel__GeccErrCntEn__SHIFT 0xf +#define UMCCH0_0_GeccErrCntSel__PoisonCntEn__SHIFT 0x10 +#define UMCCH0_0_GeccErrCntSel__GeccErrCntCsSel_MASK 0x0000000FL +#define UMCCH0_0_GeccErrCntSel__GeccErrInt_MASK 0x00003000L +#define UMCCH0_0_GeccErrCntSel__GeccErrCntEn_MASK 0x00008000L +#define UMCCH0_0_GeccErrCntSel__PoisonCntEn_MASK 0x00030000L +//UMCCH0_0_GeccErrCnt +#define UMCCH0_0_GeccErrCnt__GeccErrCnt__SHIFT 0x0 +#define UMCCH0_0_GeccErrCnt__GeccUnCorrErrCnt__SHIFT 0x10 +#define UMCCH0_0_GeccErrCnt__GeccErrCnt_MASK 0x0000FFFFL +#define UMCCH0_0_GeccErrCnt__GeccUnCorrErrCnt_MASK 0xFFFF0000L +//MCA_UMC_UMC0_MCUMC_STATUST0 +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCode__SHIFT 0x0 +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCodeExt__SHIFT 0x10 +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV22__SHIFT 0x16 +#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrLsb__SHIFT 0x18 +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV30__SHIFT 0x1e +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreId__SHIFT 0x20 +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV38__SHIFT 0x26 +#define MCA_UMC_UMC0_MCUMC_STATUST0__Scrub__SHIFT 0x28 +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV41__SHIFT 0x29 +#define MCA_UMC_UMC0_MCUMC_STATUST0__Poison__SHIFT 0x2b +#define MCA_UMC_UMC0_MCUMC_STATUST0__Deferred__SHIFT 0x2c +#define MCA_UMC_UMC0_MCUMC_STATUST0__UECC__SHIFT 0x2d +#define MCA_UMC_UMC0_MCUMC_STATUST0__CECC__SHIFT 0x2e +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV47__SHIFT 0x2f +#define MCA_UMC_UMC0_MCUMC_STATUST0__Transparent__SHIFT 0x34 +#define MCA_UMC_UMC0_MCUMC_STATUST0__SyndV__SHIFT 0x35 +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV54__SHIFT 0x36 +#define MCA_UMC_UMC0_MCUMC_STATUST0__TCC__SHIFT 0x37 +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreIdVal__SHIFT 0x38 +#define MCA_UMC_UMC0_MCUMC_STATUST0__PCC__SHIFT 0x39 +#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrV__SHIFT 0x3a +#define MCA_UMC_UMC0_MCUMC_STATUST0__MiscV__SHIFT 0x3b +#define MCA_UMC_UMC0_MCUMC_STATUST0__En__SHIFT 0x3c +#define MCA_UMC_UMC0_MCUMC_STATUST0__UC__SHIFT 0x3d +#define MCA_UMC_UMC0_MCUMC_STATUST0__Overflow__SHIFT 0x3e +#define MCA_UMC_UMC0_MCUMC_STATUST0__Val__SHIFT 0x3f +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCode_MASK 0x000000000000FFFFL +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrorCodeExt_MASK 0x00000000003F0000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV22_MASK 0x0000000000C00000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrLsb_MASK 0x000000003F000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV30_MASK 0x00000000C0000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreId_MASK 0x0000003F00000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV38_MASK 0x000000C000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__Scrub_MASK 0x0000010000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV41_MASK 0x0000060000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__Poison_MASK 0x0000080000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__Deferred_MASK 0x0000100000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__UECC_MASK 0x0000200000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__CECC_MASK 0x0000400000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV47_MASK 0x000F800000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__Transparent_MASK 0x0010000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__SyndV_MASK 0x0020000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__RESERV54_MASK 0x0040000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__TCC_MASK 0x0080000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__ErrCoreIdVal_MASK 0x0100000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__PCC_MASK 0x0200000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__AddrV_MASK 0x0400000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__MiscV_MASK 0x0800000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__En_MASK 0x1000000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__UC_MASK 0x2000000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__Overflow_MASK 0x4000000000000000L +#define MCA_UMC_UMC0_MCUMC_STATUST0__Val_MASK 0x8000000000000000L +//MCA_UMC_UMC0_MCUMC_ADDRT0 +#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr__SHIFT 0x0 +#define MCA_UMC_UMC0_MCUMC_ADDRT0__LSB__SHIFT 0x38 +#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved__SHIFT 0x3e +#define MCA_UMC_UMC0_MCUMC_ADDRT0__ErrorAddr_MASK 0x00FFFFFFFFFFFFFFL +#define MCA_UMC_UMC0_MCUMC_ADDRT0__LSB_MASK 0x3F00000000000000L +#define MCA_UMC_UMC0_MCUMC_ADDRT0__Reserved_MASK 0xC000000000000000L + +#endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index d6711caa7f39..dbc88fc7136b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -159,6 +159,7 @@ struct drm_i915_gem_object { #define I915_BO_ALLOC_VOLATILE BIT(1) #define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | I915_BO_ALLOC_VOLATILE) #define I915_BO_READONLY BIT(2) +#define I915_BO_WAS_BOUND_BIT 3 /* * Is the object to be mapped as read-only to the GPU diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index f60ca6dc911f..27d24cb38c0d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -10,6 +10,8 @@ #include "i915_gem_lmem.h" #include "i915_gem_mman.h" +#include "gt/intel_gt.h" + void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, struct sg_table *pages, unsigned int sg_page_sizes) @@ -186,6 +188,14 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj) __i915_gem_object_reset_page_iter(obj); obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0; + if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) { + struct drm_i915_private *i915 = to_i915(obj->base.dev); + intel_wakeref_t wakeref; + + with_intel_runtime_pm_if_active(&i915->runtime_pm, wakeref) + intel_gt_invalidate_tlbs(&i915->gt); + } + return pages; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 39b428c5049c..6615eb5147e2 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -26,6 +26,8 @@ void intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915) spin_lock_init(>->irq_lock); + mutex_init(>->tlb_invalidate_lock); + INIT_LIST_HEAD(>->closed_vma); spin_lock_init(>->closed_lock); @@ -661,3 +663,103 @@ void intel_gt_info_print(const struct intel_gt_info *info, intel_sseu_dump(&info->sseu, p); } + +struct reg_and_bit { + i915_reg_t reg; + u32 bit; +}; + +static struct reg_and_bit +get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8, + const i915_reg_t *regs, const unsigned int num) +{ + const unsigned int class = engine->class; + struct reg_and_bit rb = { }; + + if (drm_WARN_ON_ONCE(&engine->i915->drm, + class >= num || !regs[class].reg)) + return rb; + + rb.reg = regs[class]; + if (gen8 && class == VIDEO_DECODE_CLASS) + rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */ + else + rb.bit = engine->instance; + + rb.bit = BIT(rb.bit); + + return rb; +} + +void intel_gt_invalidate_tlbs(struct intel_gt *gt) +{ + static const i915_reg_t gen8_regs[] = { + [RENDER_CLASS] = GEN8_RTCR, + [VIDEO_DECODE_CLASS] = GEN8_M1TCR, /* , GEN8_M2TCR */ + [VIDEO_ENHANCEMENT_CLASS] = GEN8_VTCR, + [COPY_ENGINE_CLASS] = GEN8_BTCR, + }; + static const i915_reg_t gen12_regs[] = { + [RENDER_CLASS] = GEN12_GFX_TLB_INV_CR, + [VIDEO_DECODE_CLASS] = GEN12_VD_TLB_INV_CR, + [VIDEO_ENHANCEMENT_CLASS] = GEN12_VE_TLB_INV_CR, + [COPY_ENGINE_CLASS] = GEN12_BLT_TLB_INV_CR, + }; + struct drm_i915_private *i915 = gt->i915; + struct intel_uncore *uncore = gt->uncore; + struct intel_engine_cs *engine; + enum intel_engine_id id; + const i915_reg_t *regs; + unsigned int num = 0; + + if (I915_SELFTEST_ONLY(gt->awake == -ENODEV)) + return; + + if (INTEL_GEN(i915) == 12) { + regs = gen12_regs; + num = ARRAY_SIZE(gen12_regs); + } else if (INTEL_GEN(i915) >= 8 && INTEL_GEN(i915) <= 11) { + regs = gen8_regs; + num = ARRAY_SIZE(gen8_regs); + } else if (INTEL_GEN(i915) < 8) { + return; + } + + if (drm_WARN_ONCE(&i915->drm, !num, + "Platform does not implement TLB invalidation!")) + return; + + GEM_TRACE("\n"); + + assert_rpm_wakelock_held(&i915->runtime_pm); + + mutex_lock(>->tlb_invalidate_lock); + intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); + + for_each_engine(engine, gt, id) { + /* + * HW architecture suggest typical invalidation time at 40us, + * with pessimistic cases up to 100us and a recommendation to + * cap at 1ms. We go a bit higher just in case. + */ + const unsigned int timeout_us = 100; + const unsigned int timeout_ms = 4; + struct reg_and_bit rb; + + rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); + if (!i915_mmio_reg_offset(rb.reg)) + continue; + + intel_uncore_write_fw(uncore, rb.reg, rb.bit); + if (__intel_wait_for_register_fw(uncore, + rb.reg, rb.bit, 0, + timeout_us, timeout_ms, + NULL)) + drm_err_ratelimited(>->i915->drm, + "%s TLB invalidation did not complete in %ums!\n", + engine->name, timeout_ms); + } + + intel_uncore_forcewake_put_delayed(uncore, FORCEWAKE_ALL); + mutex_unlock(>->tlb_invalidate_lock); +} diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 9157c7411f60..d9a1168172ae 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -77,4 +77,6 @@ static inline bool intel_gt_is_wedged(const struct intel_gt *gt) void intel_gt_info_print(const struct intel_gt_info *info, struct drm_printer *p); +void intel_gt_invalidate_tlbs(struct intel_gt *gt); + #endif /* __INTEL_GT_H__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 6d39a4a11bf3..78c061614d8b 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -36,6 +36,8 @@ struct intel_gt { struct intel_uc uc; + struct mutex tlb_invalidate_lock; + struct intel_gt_timelines { spinlock_t lock; /* protects active_list */ struct list_head active_list; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5cd83eac940c..0f6251030a7f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2639,6 +2639,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1 << 28) #define GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT (1 << 24) +#define GEN8_RTCR _MMIO(0x4260) +#define GEN8_M1TCR _MMIO(0x4264) +#define GEN8_M2TCR _MMIO(0x4268) +#define GEN8_BTCR _MMIO(0x426c) +#define GEN8_VTCR _MMIO(0x4270) + #if 0 #define PRB0_TAIL _MMIO(0x2030) #define PRB0_HEAD _MMIO(0x2034) @@ -2728,6 +2734,11 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define FAULT_VA_HIGH_BITS (0xf << 0) #define FAULT_GTT_SEL (1 << 4) +#define GEN12_GFX_TLB_INV_CR _MMIO(0xced8) +#define GEN12_VD_TLB_INV_CR _MMIO(0xcedc) +#define GEN12_VE_TLB_INV_CR _MMIO(0xcee0) +#define GEN12_BLT_TLB_INV_CR _MMIO(0xcee4) + #define GEN12_AUX_ERR_DBG _MMIO(0x43f4) #define FPGA_DBG _MMIO(0x42300) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index caa9b041616b..50a86fd89d00 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -439,6 +439,9 @@ int i915_vma_bind(struct i915_vma *vma, vma->ops->bind_vma(vma->vm, NULL, vma, cache_level, bind_flags); } + if (vma->obj) + set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags); + atomic_or(bind_flags, &vma->flags); return 0; } diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 97ded2a59cf4..01849840ac56 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -694,7 +694,8 @@ void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore, } static void __intel_uncore_forcewake_put(struct intel_uncore *uncore, - enum forcewake_domains fw_domains) + enum forcewake_domains fw_domains, + bool delayed) { struct intel_uncore_forcewake_domain *domain; unsigned int tmp; @@ -709,7 +710,11 @@ static void __intel_uncore_forcewake_put(struct intel_uncore *uncore, continue; } - uncore->funcs.force_wake_put(uncore, domain->mask); + if (delayed && + !(domain->uncore->fw_domains_timer & domain->mask)) + fw_domain_arm_timer(domain); + else + uncore->funcs.force_wake_put(uncore, domain->mask); } } @@ -730,7 +735,20 @@ void intel_uncore_forcewake_put(struct intel_uncore *uncore, return; spin_lock_irqsave(&uncore->lock, irqflags); - __intel_uncore_forcewake_put(uncore, fw_domains); + __intel_uncore_forcewake_put(uncore, fw_domains, false); + spin_unlock_irqrestore(&uncore->lock, irqflags); +} + +void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore, + enum forcewake_domains fw_domains) +{ + unsigned long irqflags; + + if (!uncore->funcs.force_wake_put) + return; + + spin_lock_irqsave(&uncore->lock, irqflags); + __intel_uncore_forcewake_put(uncore, fw_domains, true); spin_unlock_irqrestore(&uncore->lock, irqflags); } @@ -772,7 +790,7 @@ void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore, if (!uncore->funcs.force_wake_put) return; - __intel_uncore_forcewake_put(uncore, fw_domains); + __intel_uncore_forcewake_put(uncore, fw_domains, false); } void assert_forcewakes_inactive(struct intel_uncore *uncore) diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index c4b22d9d0b45..034f04e0de8b 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -211,6 +211,8 @@ void intel_uncore_forcewake_get(struct intel_uncore *uncore, enum forcewake_domains domains); void intel_uncore_forcewake_put(struct intel_uncore *uncore, enum forcewake_domains domains); +void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore, + enum forcewake_domains domains); void intel_uncore_forcewake_flush(struct intel_uncore *uncore, enum forcewake_domains fw_domains); diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 9db2903b61e5..fd5786fdb291 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -193,6 +193,8 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o +obj-$(CONFIG_SYNO_HDDMON) += syno_hddmon.o +obj-$(CONFIG_SYNO_SMBUS_HDDMON)+= syno_smbus_hddmon.o obj-$(CONFIG_SENSORS_OCC) += occ/ obj-$(CONFIG_PMBUS) += pmbus/ diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 9d5b019651f2..22533b138fe7 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives @@ -21,6 +24,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ /* Indexes for the sysfs hooks */ @@ -90,6 +96,18 @@ #define REG_TEMP_OFFSET_BASE 0x70 +#ifdef MY_ABC_HERE +#define REG_CONFIG1 0x40 /* ADT7490 only */ +#define REG_PECI0 0x33 /* ADT7490 only */ +#define REG_PECI1_BASE 0x1A /* ADT7490 only */ +#define REG_PECI_CONFIG 0x88 /* ADT7490 only */ +#define REG_PECI_MIN 0x3B /* ADT7490 only */ +#define REG_PECI_RANGE 0x3C /* ADT7490 only */ +#define REG_PECI_OFFSET_BASE 0x94 /* ADT7490 only */ +#define REG_PECI_LOW_LIMIT 0x34 /* ADT7490 only */ +#define REG_PECI_HIGH_LIMIT 0x35 /* ADT7490 only */ +#endif /* MY_ABC_HERE */ + #define REG_CONFIG2 0x73 #define REG_EXTEND1 0x76 @@ -127,6 +145,11 @@ #define ADT7475_TACH_COUNT 4 #define ADT7475_PWM_COUNT 3 +#ifdef MY_ABC_HERE +#define ADT7490_PECI_COUNT 4 /*ADT7490 only*/ +#define SYNO_IS_ADT7490(client) !strcmp(client->name, "adt7490") +#endif /* MY_ABC_HERE */ + /* Macro to read the registers */ #define adt7475_read(reg) i2c_smbus_read_byte_data(client, (reg)) @@ -145,6 +168,11 @@ #define VOLTAGE_MIN_REG(idx) (REG_VOLTAGE_MIN_BASE + ((idx) * 2)) #define VOLTAGE_MAX_REG(idx) (REG_VOLTAGE_MAX_BASE + ((idx) * 2)) +#ifdef MY_ABC_HERE +#define PECI_REG(idx) (idx == 0 ? REG_PECI0:REG_PECI1_BASE + (idx-1)) /* ADT7490 only */ +#define PECI_OFFSET_REG(idx) (REG_PECI_OFFSET_BASE + (idx)) +#endif /* MY_ABC_HERE */ + #define TEMP_REG(idx) (REG_TEMP_BASE + (idx)) #define TEMP_MIN_REG(idx) (REG_TEMP_MIN_BASE + ((idx) * 2)) #define TEMP_MAX_REG(idx) (REG_TEMP_MAX_BASE + ((idx) * 2)) @@ -215,6 +243,12 @@ struct adt7475_data { u8 vid; u8 vrm; const struct attribute_group *groups[9]; + +#ifdef MY_ABC_HERE + u8 pwmsynoctl[4]; + u16 peci[7][4]; /* ADT7490 only */ + u8 peci_range[4]; +#endif /* MY_ABC_HERE */ }; static struct i2c_driver adt7475_driver; @@ -485,6 +519,15 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr, val = clamp_val(val, temp - 15000, temp); val = (temp - val) / 1000; +#ifdef MY_ABC_HERE + if (sattr->index != 1) { + data->temp[HYSTERSIS][sattr->index] &= 0x0F; + data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4; + } else { + data->temp[HYSTERSIS][sattr->index] &= 0xF0; + data->temp[HYSTERSIS][sattr->index] |= (val & 0xF); + } +#else /* MY_ABC_HERE */ if (sattr->index != 1) { data->temp[HYSTERSIS][sattr->index] &= 0xF0; data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4; @@ -492,6 +535,7 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr, data->temp[HYSTERSIS][sattr->index] &= 0x0F; data->temp[HYSTERSIS][sattr->index] |= (val & 0xF); } +#endif /* MY_ABC_HERE */ out = data->temp[HYSTERSIS][sattr->index]; break; @@ -1046,6 +1090,505 @@ static ssize_t pwm_use_point2_pwm_at_crit_store(struct device *dev, return count; } + +#ifdef MY_ABC_HERE + +/* set peci */ +static ssize_t set_peci(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + unsigned char reg = 0; + u8 out = 0; + long val = 0; + long temp = 0; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + mutex_lock(&data->lock); + /* We need the config register in all cases for temp <-> reg conv. */ + data->config5 = adt7475_read(REG_CONFIG5); + + switch (sattr->nr) { + case OFFSET: + val = clamp_val(val, -127000, 127000); + out = data->peci[OFFSET][sattr->index] = val / 1000; + break; + + case HYSTERSIS: + /* The value will be given as an absolute value, turn it + into an offset based on THERM */ + /* Read fresh THERM and HYSTERSIS values from the chip */ + /* in ADT7490 register 0x3D is for PECI Tcontrol*/ + data->peci[THERM][sattr->index] = adt7475_read(REG_DEVID) << 2; + adt7475_read_hystersis(client); + temp = reg2temp(data, data->peci[THERM][sattr->index]); + val = clamp_val(val, temp - 15000, temp); + val = (temp - val) / 1000; + + data->peci[HYSTERSIS][sattr->index] &= 0xF0; + data->peci[HYSTERSIS][sattr->index] |= (val & 0xF); + + out = data->peci[HYSTERSIS][sattr->index]; + break; + + default: + data->peci[sattr->nr][sattr->index] = temp2reg(data, val); + /* We maintain an extra 2 digits of precision for simplicity + * - shift those back off before writing the value */ + out = (u8) (data->peci[sattr->nr][sattr->index] >> 2); + } + + switch (sattr->nr) { + case MIN: + reg = REG_PECI_LOW_LIMIT; + break; + case MAX: + reg = REG_PECI_HIGH_LIMIT; + break; + case OFFSET: + reg = PECI_OFFSET_REG(sattr->index); + break; + case AUTOMIN: + reg = REG_PECI_MIN; + break; + case THERM: + reg = REG_DEVID; + break; + case HYSTERSIS: + reg = REG_REMOTE2_HYSTERSIS; + break; + } + + i2c_smbus_write_byte_data(client, reg, out); + + mutex_unlock(&data->lock); + return count; +} +/* + * Show temperature from PECI interface + */ +static ssize_t show_peci(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // this function is adt7490 only + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int out = 0; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + switch (sattr->nr) { + case OFFSET: + mutex_lock(&data->lock); + out = (s8)data->peci[sattr->nr][sattr->index] * 1000; + mutex_unlock(&data->lock); + break; + + case HYSTERSIS: + mutex_lock(&data->lock); + out = data->peci[sattr->nr][sattr->index]; + out &= 0xF; + out = reg2temp(data, data->peci[THERM][sattr->index]) - out * 1000; + mutex_unlock(&data->lock); + break; + + default: + /* show peci temperature */ + mutex_lock(&data->lock); + out = reg2temp(data, data->peci[sattr->nr][sattr->index]); + mutex_unlock(&data->lock); + break; + } + + return sprintf(buf, "%d\n", out); +} + +static ssize_t show_adt_full_duty_cycle(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // this function is adt7490 only + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + u8 config1; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + config1 = adt7475_read(REG_CONFIG1); + + return sprintf(buf, "%d\n", (config1 & 0x8) > 0 ? 1 : 0); +} + +static ssize_t set_adt_full_duty_cycle(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + // this function is adt7490 only + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u8 config1; + long val; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + config1 = adt7475_read(REG_CONFIG1); + if (val) { + config1 |= 0x8; + } else { + config1 &= ~0x8; + } + + i2c_smbus_write_byte_data(client, REG_CONFIG1, config1); + + return count; +} + +static ssize_t show_peci_error(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // this function is adt7490 only + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + u8 config; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + config = adt7475_read(REG_VID); + return sprintf(buf, "%d\n", config); +} + +static ssize_t show_enh_acou_reg(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // this function is adt7490 only + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + u8 config; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + config = adt7475_read(REG_ENHANCE_ACOUSTICS1); + return sprintf(buf, "%d\n", config >> 5); +} + +static ssize_t set_enh_acou_reg(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + // this function is adt7490 only + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u8 config; + long val; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + config = adt7475_read(REG_ENHANCE_ACOUSTICS1); + config &= ~0xE0; + config |= (val & 0x7) << 5; + + i2c_smbus_write_byte_data(client, REG_ENHANCE_ACOUSTICS1, config); + return count; +} + +static ssize_t show_adtenable(struct device *dev, struct device_attribute *attr, + char *buf) +{ + // this function is adt7490 only + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + u8 config1; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + config1 = adt7475_read(REG_CONFIG1); + return sprintf(buf, "%d\n", config1 & 0x1); +} + +static ssize_t set_adtenable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + // this function is adt7490 only + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u8 config1; + long val; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + config1 = adt7475_read(REG_CONFIG1); + if (val) { + config1 |= 0x1; + } else { + config1 &= ~0x1; + } + i2c_smbus_write_byte_data(client, REG_CONFIG1, config1); + return count; +} + +/* + * Show high frequency configure of pwm + */ +static ssize_t show_pwmHighFreq(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + int out; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + mutex_lock(&data->lock); + out = (data->range[sattr->index] & 0x8) >> 3; + mutex_unlock(&data->lock); + + return sprintf(buf, "%d\n", out); +} + +/* + * Set pwm output as high frequency + */ +static ssize_t set_pwmHighFreq(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + mutex_lock(&data->lock); + data->range[sattr->index] = + adt7475_read(TEMP_TRANGE_REG(sattr->index)); + if (val) { + data->range[sattr->index] |= 0x8; + } else { + data->range[sattr->index] &= ~0x8; + } + + i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index), + data->range[sattr->index]); + mutex_unlock(&data->lock); + return count; +} + +static ssize_t show_peci_point2(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int out, val; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + mutex_lock(&data->lock); + out = (data->peci_range[sattr->index] >> 4) & 0x0F; + val = reg2temp(data, data->peci[AUTOMIN][sattr->index]); + mutex_unlock(&data->lock); + + return sprintf(buf, "%d\n", val + autorange_table[out]); +} + +static ssize_t set_peci_point2(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int temp; + long val; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + mutex_lock(&data->lock); + + /* Get a fresh copy of the needed registers */ + data->config5 = adt7475_read(REG_CONFIG5); + data->peci[AUTOMIN][sattr->index] = adt7475_read(REG_PECI_MIN) << 2; + data->peci_range[sattr->index] = adt7475_read(REG_PECI_RANGE); + + /* The user will write an absolute value, so subtract the start point + to figure the range */ + temp = reg2temp(data, data->peci[AUTOMIN][sattr->index]); + val = clamp_val(val, temp + autorange_table[0], + temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]); + val -= temp; + + /* Find the nearest table entry to what the user wrote */ + val = find_closest(val, autorange_table, ARRAY_SIZE(autorange_table)); + + data->peci_range[sattr->index] &= ~0xF0; + data->peci_range[sattr->index] |= val << 4; + + i2c_smbus_write_byte_data(client, REG_PECI_RANGE, + data->peci_range[sattr->index]); + + mutex_unlock(&data->lock); + return count; +} + +static ssize_t show_pwm_syno_control(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adt7475_data *data = adt7475_update_device(dev); + struct i2c_client *client = data->client; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + mutex_lock(&data->lock); + /* Read Modify Write PWM values */ + adt7475_read_pwm(client, sattr->index); + mutex_unlock(&data->lock); + + return sprintf(buf, "%d\n", data->pwmsynoctl[sattr->index]); +} + +/* + * This function is set the pwm control sensor, + * In ADT7490 spec, it could choose many way to control the pwm + * we implement all the valid control mapping in this fucntion + * + * We don't use pwm_enable and pwm_auto_channel to set pwm control source + */ +static ssize_t set_pwm_syno_control(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adt7475_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + long val = 0; + long inputVal = 0; + long valt = 0; + int index = sattr->index; + + if (!SYNO_IS_ADT7490(client)) { + return -EINVAL; + } + + if (kstrtol(buf, 10, &inputVal)) + return -EINVAL; + + mutex_lock(&data->lock); + /* Read Modify Write PWM values */ + data->pwm[CONTROL][index] = adt7475_read(PWM_CONFIG_REG(index)); + + switch (inputVal) { + case 1: + valt = 0; + val = 0x03; /* Run at maximun duty cycle (set by pwmMax) */ + break; + case 2: + valt = 0; + val = 0x07; /* Manual mode*/ + break; + case 3: + valt = 1; + val = 0x07; /* Source from all peci and all sensor */ + break; + case 4: + valt = 1; + val = 0x05; /* Source from all peci */ + break; + case 5: + valt = 1; + val = 0x00; /* Source from peci0 */ + break; + case 6: + valt = 1; + val = 0x01; /* Source from peci1 */ + break; + case 7: + valt = 1; + val = 0x02; /* Source from peci2 */ + break; + case 8: + valt = 1; + val = 0x03; /* Source from peci3 */ + break; + case 9: + valt = 0; + val = 0x06; /* Source from all sensors */ + break; + case 10: + valt = 0; + val = 0x05; /* Source from local and remote2 */ + break; + case 11: + valt = 0; + val = 0x00; /* Source from remote1 */ + break; + case 12: + valt = 0; + val = 0x01; /* Source from local */ + break; + case 13: + valt = 0; + val = 0x02; /* Source from remote2 */ + break; + default: + valt = 0; + val = 0x03; /* Run at maximun duty cycle (set by pwmMax) */ + break; + } + + data->pwm[CONTROL][index] &= ~0xE8; + data->pwm[CONTROL][index] |= (valt & 1) << 3; + data->pwm[CONTROL][index] |= (val & 7) << 5; + + i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index), + data->pwm[CONTROL][index]); + mutex_unlock(&data->lock); + + return count; +} +#endif /* MY_ABC_HERE */ + static ssize_t vrm_show(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -1168,6 +1711,87 @@ static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_channels_temp, pwmchan, INPUT, 2); static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, pwm, MIN, 2); static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, pwm, MAX, 2); static SENSOR_DEVICE_ATTR_2_RW(pwm3_stall_disable, stall_disable, 0, 2); +#ifdef MY_ABC_HERE +static SENSOR_DEVICE_ATTR_2(peci0_input, S_IRUGO, show_peci, NULL, INPUT, 0); +static SENSOR_DEVICE_ATTR_2(peci0_auto_point1_temp, S_IRUGO | S_IWUSR, + show_peci, set_peci, AUTOMIN, 0); +static SENSOR_DEVICE_ATTR_2(peci0_auto_point2_temp, S_IRUGO | S_IWUSR, + show_peci_point2, set_peci_point2, 0, 0); +static SENSOR_DEVICE_ATTR_2(peci0_crit, S_IRUGO | S_IWUSR, show_peci, set_peci, + THERM, 0); +static SENSOR_DEVICE_ATTR_2(peci0_crit_hyst, S_IRUGO | S_IWUSR, show_peci, + set_peci, HYSTERSIS, 0); +static SENSOR_DEVICE_ATTR_2(peci0_offset, S_IRUGO | S_IWUSR, show_peci, + set_peci, OFFSET, 0); +static SENSOR_DEVICE_ATTR_2(peci0_min, S_IRUGO | S_IWUSR, show_peci, set_peci, + MIN, 0); +static SENSOR_DEVICE_ATTR_2(peci0_max, S_IRUGO | S_IWUSR, show_peci, set_peci, + MAX, 0); +static SENSOR_DEVICE_ATTR_2(peci1_input, S_IRUGO, show_peci, NULL, INPUT, 1); +static SENSOR_DEVICE_ATTR_2(peci1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_peci, set_peci, AUTOMIN, 1); +static SENSOR_DEVICE_ATTR_2(peci1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_peci_point2, set_peci_point2, 0, 1); +static SENSOR_DEVICE_ATTR_2(peci1_crit, S_IRUGO | S_IWUSR, show_peci, set_peci, + THERM, 1); +static SENSOR_DEVICE_ATTR_2(peci1_crit_hyst, S_IRUGO | S_IWUSR, show_peci, + set_peci, HYSTERSIS, 1); +static SENSOR_DEVICE_ATTR_2(peci1_offset, S_IRUGO | S_IWUSR, show_peci, + set_peci, OFFSET, 1); +static SENSOR_DEVICE_ATTR_2(peci1_min, S_IRUGO | S_IWUSR, show_peci, set_peci, + MIN, 1); +static SENSOR_DEVICE_ATTR_2(peci1_max, S_IRUGO | S_IWUSR, show_peci, set_peci, + MAX, 1); +static SENSOR_DEVICE_ATTR_2(peci2_input, S_IRUGO, show_peci, NULL, INPUT, 2); +static SENSOR_DEVICE_ATTR_2(peci2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_peci, set_peci, AUTOMIN, 2); +static SENSOR_DEVICE_ATTR_2(peci2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_peci_point2, set_peci_point2, 0, 2); +static SENSOR_DEVICE_ATTR_2(peci2_crit, S_IRUGO | S_IWUSR, show_peci, set_peci, + THERM, 2); +static SENSOR_DEVICE_ATTR_2(peci2_crit_hyst, S_IRUGO | S_IWUSR, show_peci, + set_peci, HYSTERSIS, 2); +static SENSOR_DEVICE_ATTR_2(peci2_offset, S_IRUGO | S_IWUSR, show_peci, + set_peci, OFFSET, 2); +static SENSOR_DEVICE_ATTR_2(peci2_min, S_IRUGO | S_IWUSR, show_peci, set_peci, + MIN, 2); +static SENSOR_DEVICE_ATTR_2(peci2_max, S_IRUGO | S_IWUSR, show_peci, set_peci, + MAX, 2); +static SENSOR_DEVICE_ATTR_2(peci3_input, S_IRUGO, show_peci, NULL, INPUT, 3); +static SENSOR_DEVICE_ATTR_2(peci3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_peci, set_peci, AUTOMIN, 3); +static SENSOR_DEVICE_ATTR_2(peci3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_peci_point2, set_peci_point2, 0, 3); +static SENSOR_DEVICE_ATTR_2(peci3_crit, S_IRUGO | S_IWUSR, show_peci, set_peci, + THERM, 3); +static SENSOR_DEVICE_ATTR_2(peci3_crit_hyst, S_IRUGO | S_IWUSR, show_peci, + set_peci, HYSTERSIS, 3); +static SENSOR_DEVICE_ATTR_2(peci3_offset, S_IRUGO | S_IWUSR, show_peci, + set_peci, OFFSET, 3); +static SENSOR_DEVICE_ATTR_2(peci3_min, S_IRUGO | S_IWUSR, show_peci, set_peci, + MIN, 3); +static SENSOR_DEVICE_ATTR_2(peci3_max, S_IRUGO | S_IWUSR, show_peci, set_peci, + MAX, 3); +static SENSOR_DEVICE_ATTR_2(enable, S_IRUGO | S_IWUSR, show_adtenable, + set_adtenable, INPUT, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_high_freq, S_IWUSR | S_IRUGO, show_pwmHighFreq, + set_pwmHighFreq, INPUT, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_high_freq, S_IWUSR | S_IRUGO, show_pwmHighFreq, + set_pwmHighFreq, INPUT, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_high_freq, S_IWUSR | S_IRUGO, show_pwmHighFreq, + set_pwmHighFreq, INPUT, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_syno_control, S_IRUGO | S_IWUSR, show_pwm_syno_control, + set_pwm_syno_control, INPUT, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_syno_control, S_IRUGO | S_IWUSR, show_pwm_syno_control, + set_pwm_syno_control, INPUT, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_syno_control, S_IRUGO | S_IWUSR, show_pwm_syno_control, + set_pwm_syno_control, INPUT, 2); +static SENSOR_DEVICE_ATTR_2(full_duty_cycle, S_IRUGO | S_IWUSR, show_adt_full_duty_cycle, + set_adt_full_duty_cycle, INPUT, 0); +static SENSOR_DEVICE_ATTR_2(peci_error, S_IRUGO, show_peci_error, NULL, INPUT, 0); +static SENSOR_DEVICE_ATTR_2(enhanced_acoustic_register, S_IWUSR | S_IRUGO, show_enh_acou_reg, + set_enh_acou_reg, INPUT, 0); +#endif /* MY_ABC_HERE */ /* Non-standard name, might need revisiting */ static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit); @@ -1239,6 +1863,54 @@ static struct attribute *adt7475_attrs[] = { &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm3_stall_disable.dev_attr.attr, +#ifdef MY_ABC_HERE + &sensor_dev_attr_peci0_input.dev_attr.attr, + &sensor_dev_attr_peci0_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_peci0_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_peci0_crit.dev_attr.attr, + &sensor_dev_attr_peci0_crit_hyst.dev_attr.attr, + &sensor_dev_attr_peci0_offset.dev_attr.attr, + &sensor_dev_attr_peci0_min.dev_attr.attr, + &sensor_dev_attr_peci0_max.dev_attr.attr, + + &sensor_dev_attr_peci1_input.dev_attr.attr, + &sensor_dev_attr_peci1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_peci1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_peci1_crit.dev_attr.attr, + &sensor_dev_attr_peci1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_peci1_offset.dev_attr.attr, + &sensor_dev_attr_peci1_min.dev_attr.attr, + &sensor_dev_attr_peci1_max.dev_attr.attr, + + &sensor_dev_attr_peci2_input.dev_attr.attr, + &sensor_dev_attr_peci2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_peci2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_peci2_crit.dev_attr.attr, + &sensor_dev_attr_peci2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_peci2_offset.dev_attr.attr, + &sensor_dev_attr_peci2_min.dev_attr.attr, + &sensor_dev_attr_peci2_max.dev_attr.attr, + + &sensor_dev_attr_peci3_input.dev_attr.attr, + &sensor_dev_attr_peci3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_peci3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_peci3_crit.dev_attr.attr, + &sensor_dev_attr_peci3_crit_hyst.dev_attr.attr, + &sensor_dev_attr_peci3_offset.dev_attr.attr, + &sensor_dev_attr_peci3_min.dev_attr.attr, + &sensor_dev_attr_peci3_max.dev_attr.attr, + + &sensor_dev_attr_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_high_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_high_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_high_freq.dev_attr.attr, + &sensor_dev_attr_pwm1_syno_control.dev_attr.attr, + &sensor_dev_attr_pwm2_syno_control.dev_attr.attr, + &sensor_dev_attr_pwm3_syno_control.dev_attr.attr, + &sensor_dev_attr_full_duty_cycle.dev_attr.attr, + &sensor_dev_attr_peci_error.dev_attr.attr, + &sensor_dev_attr_enhanced_acoustic_register.dev_attr.attr, +#endif /* MY_ABC_HERE */ &dev_attr_pwm_use_point2_pwm_at_crit.attr, NULL, }; @@ -1539,6 +2211,145 @@ static int adt7475_set_pwm_polarity(struct i2c_client *client) return 0; } +#ifdef MY_ABC_HERE +extern int (*funcSYNOReadAdtFanSpeedRpm)(struct _SYNO_HWMON_SENSOR_TYPE *); +extern int (*funcSYNOReadAdtVoltageSensor)(struct _SYNO_HWMON_SENSOR_TYPE *); +extern int (*funcSYNOReadAdtThermalSensor)(struct _SYNO_HWMON_SENSOR_TYPE *); +extern int (*funcSYNOReadAdtPeci)(struct _SynoCpuTemp *); +extern int (*funcSYNOReadAdtFanSpeedRpmByOrder)(struct _SYNO_HWMON_SENSOR_TYPE *, struct _SYNO_HWMON_FAN_ORDER *); +static struct i2c_client *syno_find_adt7490_client(void) +{ + struct i2c_client *client, *_n, *ret = NULL; + + list_for_each_entry_safe(client, _n, &adt7475_driver.clients, detected) { + if (SYNO_IS_ADT7490(client)) { + ret = client; + break; + } + } + + return ret; +} + +static int syno_parse_adt_peci_input(struct _SynoCpuTemp *pCpuTemp) +{ + int i, ret = -1; + int cpu_count = 1; + struct i2c_client *client; + struct adt7475_data *data; + + if (NULL == pCpuTemp) { + printk("adt7475: parameter error.\n"); + goto RET; + } + + client = syno_find_adt7490_client(); + if (NULL == client) { + printk("adt7475: client not found.\n"); + goto RET; + } + + data = i2c_get_clientdata(client); + +#ifdef MY_DEF_HERE + cpu_count = 2; +#endif /* MY_DEF_HERE */ + + for (i = 0; i < cpu_count; ++i) { + pCpuTemp->cpu_temp[i] = reg2temp(data, data->peci[INPUT][i]); + } + pCpuTemp->cpu_num = cpu_count; + + ret = 0; +RET: + return ret; +} + +static int syno_parse_adt_voltage_sensor(struct _SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + struct i2c_client *client; + struct adt7475_data *data; + int i = 0; + + client = syno_find_adt7490_client(); + if (NULL == client || NULL == SysVoltage) { + return -ENODEV; + } + + data = i2c_get_clientdata(client); + + for (i = 0 ; i < SysVoltage->sensor_num ; i++) { + snprintf(SysVoltage->sensor[i].value, sizeof(SysVoltage->sensor[i].value), "%d", reg2volt(i, data->voltage[INPUT][i], data->bypass_attn)); + } + + return 0; +} + +static int syno_parse_adt_thermal_sensor(struct _SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + struct i2c_client *client; + struct adt7475_data *data; + int i = 0; + + client = syno_find_adt7490_client(); + if (NULL == client || NULL == SysThermal) { + return -ENODEV; + } + + data = i2c_get_clientdata(client); + + for (i = 0 ; i < SysThermal->sensor_num ; i++) { + snprintf(SysThermal->sensor[i].value, sizeof(SysThermal->sensor[i].value), "%d", reg2temp(data, data->temp[INPUT][i]) / 1000); + } + + return 0; +} + +static int syno_parse_adt_fan_speed_rpm(struct _SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + struct i2c_client *client; + struct adt7475_data *data; + int i = 0; + + client = syno_find_adt7490_client(); + if (NULL == client || NULL == FanSpeedRpm) { + return -ENODEV; + } + + data = i2c_get_clientdata(client); + + for (i = 0 ; i < FanSpeedRpm->sensor_num ; i++) { + snprintf(FanSpeedRpm->sensor[i].value, sizeof(FanSpeedRpm->sensor[i].value), "%d", tach2rpm(data->tach[INPUT][i])); + } + + return 0; +} + +static int syno_parse_adt_fan_speed_rpm_by_order(struct _SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm, struct _SYNO_HWMON_FAN_ORDER *FanOrder) +{ + struct i2c_client *client; + struct adt7475_data *data; + int i = 0; + + client = syno_find_adt7490_client(); + if (NULL == client || NULL == FanSpeedRpm || NULL == FanOrder) { + return -ENODEV; + } + + data = i2c_get_clientdata(client); + + for (i = 0 ; i < FanSpeedRpm->sensor_num ; i++) { + snprintf(FanSpeedRpm->sensor[i].value, sizeof(FanSpeedRpm->sensor[i].value), "%d", tach2rpm(data->tach[INPUT][FanOrder->fan_order_list[i]])); + } + + return 0; +} + +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +extern u8 syno_cpu_tjmax(int, int*); +#endif /* MY_DEF_HERE */ static int adt7475_probe(struct i2c_client *client) { enum chips chip; @@ -1548,12 +2359,18 @@ static int adt7475_probe(struct i2c_client *client) [adt7476] = "ADT7476", [adt7490] = "ADT7490", }; +#ifdef MY_ABC_HERE + u8 config1, configPECI; +#endif /* MY_ABC_HERE */ struct adt7475_data *data; struct device *hwmon_dev; int i, ret = 0, revision, group_num = 0; u8 config3; const struct i2c_device_id *id = i2c_match_id(adt7475_id, client); +#ifdef MY_DEF_HERE + int tjmax; +#endif /* MY_DEF_HERE */ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (data == NULL) @@ -1585,6 +2402,43 @@ static int adt7475_probe(struct i2c_client *client) revision = adt7475_read(REG_DEVID2) & 0x07; } +#ifdef MY_ABC_HERE + if (SYNO_IS_ADT7490(client)) { + config1 = adt7475_read(REG_CONFIG1); + // which means adt7490 is not been told to start + if (!(config1 & 0x1)) { + // which means adt7490 is ready to go... + if (config1 & 0x4) { + config1 |= 0x11; + i2c_smbus_write_byte_data(client, REG_CONFIG1, config1); + } + } + configPECI = adt7475_read(REG_PECI_CONFIG); +#ifdef MY_DEF_HERE + // 40h = 01000000b + // Bits [7:6], 01: 2 CPUs (PECI0, PECI1) + configPECI = 0x40; +#else /* MY_DEF_HERE */ + configPECI = 0x00; +#endif /* MY_DEF_HERE */ + i2c_smbus_write_byte_data(client, REG_PECI_CONFIG, configPECI); + + funcSYNOReadAdtPeci = syno_parse_adt_peci_input; + funcSYNOReadAdtFanSpeedRpm = syno_parse_adt_fan_speed_rpm; + funcSYNOReadAdtVoltageSensor = syno_parse_adt_voltage_sensor; + funcSYNOReadAdtThermalSensor = syno_parse_adt_thermal_sensor; + funcSYNOReadAdtFanSpeedRpmByOrder = syno_parse_adt_fan_speed_rpm_by_order; +#ifdef MY_DEF_HERE + for (i = 0; i < ADT7490_PECI_COUNT; ++i) { + if (syno_cpu_tjmax(i, &tjmax) < 0) { + continue; + } + i2c_smbus_write_byte_data(client, PECI_OFFSET_REG(i), (u8)tjmax); + } +#endif /* MY_DEF_HERE */ + } +#endif /* MY_ABC_HERE */ + config3 = adt7475_read(REG_CONFIG3); /* Pin PWM2 may alternatively be used for ALERT output */ if (!(config3 & CONFIG3_SMBALERT)) @@ -1741,8 +2595,77 @@ static void adt7475_read_hystersis(struct i2c_client *client) data->temp[HYSTERSIS][0] = (u16) adt7475_read(REG_REMOTE1_HYSTERSIS); data->temp[HYSTERSIS][1] = data->temp[HYSTERSIS][0]; data->temp[HYSTERSIS][2] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS); +#ifdef MY_ABC_HERE + data->peci[HYSTERSIS][0] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS); + data->peci[HYSTERSIS][1] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS); + data->peci[HYSTERSIS][2] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS); + data->peci[HYSTERSIS][3] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS); +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +static unsigned int adt7490_pwmctl_read(const unsigned int pwmReg) +{ + unsigned int valt = pwmReg & 0x8; + unsigned int pwmSource = (pwmReg >> 5) & 7; + unsigned int ret = 1; + + if (valt) { + switch (pwmSource) { + case 0x0: + ret = 5; + break; + case 0x1: + ret = 6; + break; + case 0x2: + ret = 7; + break; + case 0x3: + ret = 8; + break; + case 0x5: + ret = 4; + break; + case 0x7: + ret = 3; + break; + default: + ret = 0; + break; + } + } else { + switch (pwmSource) { + case 0x0: + ret = 11; + break; + case 0x1: + ret = 12; + break; + case 0x2: + ret = 13; + break; + case 0x3: + ret = 1; + break; + case 0x5: + ret = 10; + break; + case 0x6: + ret = 9; + break; + case 0x7: + ret = 2; + break; + default: + ret = 0; + break; + } + } + return ret; +} +#endif /* MY_ABC_HERE */ + static void adt7475_read_pwm(struct i2c_client *client, int index) { struct adt7475_data *data = i2c_get_clientdata(client); @@ -1755,6 +2678,9 @@ static void adt7475_read_pwm(struct i2c_client *client, int index) * based on the current settings */ v = (data->pwm[CONTROL][index] >> 5) & 7; +#ifdef MY_ABC_HERE + data->pwmsynoctl[index] = adt7490_pwmctl_read(data->pwm[CONTROL][index]); +#endif /* MY_ABC_HERE */ if (v == 3) data->pwmctl[index] = 0; @@ -1868,6 +2794,21 @@ static int adt7475_update_measure(struct device *dev) ((ext >> 4) & 3); } +#ifdef MY_ABC_HERE + if (SYNO_IS_ADT7490(client)) { + for (i = 0; i < ADT7490_PECI_COUNT; i++) { + /* Adjust values so they match the input precision */ + data->peci[MIN][i] = adt7475_read(REG_PECI_LOW_LIMIT) << 2; + data->peci[MAX][i] = adt7475_read(REG_PECI_HIGH_LIMIT) << 2; + data->peci[AUTOMIN][i] = adt7475_read(REG_PECI_MIN) << 2; + data->peci[THERM][i] = adt7475_read(REG_DEVID) << 2; + data->peci[INPUT][i] = adt7475_read(PECI_REG(i)) << 2; + data->peci[OFFSET][i] = adt7475_read(PECI_OFFSET_REG(i)); + data->peci_range[i] = adt7475_read(REG_PECI_RANGE); + } + } +#endif /* MY_ABC_HERE */ + for (i = 0; i < ADT7475_TACH_COUNT; i++) { if (i == 3 && !data->has_fan4) continue; diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index bb9211215a68..40674c2e70dc 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * coretemp.c - Linux kernel module for hardware monitoring @@ -101,6 +104,10 @@ static int max_zones __read_mostly; /* Array of zone pointers. Serialized by cpu hotplug lock */ static struct platform_device **zone_devices; +#ifdef MY_DEF_HERE +static DEFINE_MUTEX(pdev_list_mutex); +#endif /* MY_DEF_HERE */ + static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -442,6 +449,13 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) tdata->is_pkg_data = pkg_flag; tdata->cpu = cpu; tdata->cpu_core_id = TO_CORE_ID(cpu); +#ifdef MY_DEF_HERE + /* + * if the cpu temp can't read, syno_cpu_temperature() still return this value, + * so we must set a valid value(default 20 degree C) when init + */ + tdata->temp = 20 * 1000; +#endif /* MY_DEF_HERE */ tdata->attr_size = MAX_CORE_ATTRS; mutex_init(&tdata->update_lock); return tdata; @@ -761,6 +775,139 @@ static void __exit coretemp_exit(void) } module_exit(coretemp_exit) +#ifdef MY_DEF_HERE +#include +/* update core temp + * p.s. copy from "show_temp(..)" + * + * @param tdata [IN/OUT]: the temperature data, should not be NULL + **/ +static void syno_update_temp(struct temp_data *tdata) +{ + u32 eax, edx; + + mutex_lock(&tdata->update_lock); + /* Check whether the time interval has elapsed */ + if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) { + rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); + tdata->valid = 0; + /* Check whether the data is valid */ + if (eax & 0x80000000) { + tdata->temp = tdata->tjmax - + ((eax >> 16) & 0x7f) * 1000; + tdata->valid = 1; + } + tdata->last_updated = jiffies; + } + mutex_unlock(&tdata->update_lock); +} + +/* Get the core number and highest temp of cores + * + * @param + * pCpuTemp [OUT]: the result + * + * @return + * 0: success + * others: fail + **/ +int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp) +{ + struct platform_data *pdata = NULL; + struct temp_data *tdata = NULL; + int iCpuCount = 0; + int iIndex = 0; + int i = 0; + + if (NULL == pCpuTemp) { + printk("coretemp: parameter error.\n"); + return -1; + } + + mutex_lock(&pdev_list_mutex); + for (i = 0; i < max_zones; i++) { + if (!zone_devices[i]) { + continue; + } + + pdata = dev_get_drvdata(&(zone_devices[i]->dev)); + if (!pdata) { + continue; + } + + iIndex = TO_ATTR_NO(pdata->pkg_id); + tdata = pdata->core_data[iIndex]; + if (!tdata) { + printk("Can't get Core %d temperature data\n", pdata->pkg_id); + continue; + } + if (MAX_CPU <= iCpuCount) { + printk("CPU count larger than MAX_CPU %d: %d\n", MAX_CPU, iCpuCount); + } else { + /* no need to check tdata->valid, so even !tdata->valid we also return tdata->temp which + * is the last valid temperature. */ + syno_update_temp(tdata); + pCpuTemp->cpu_temp[iCpuCount] = tdata->temp / 1000; + ++iCpuCount; + } + } + mutex_unlock(&pdev_list_mutex); + pCpuTemp->cpu_num = iCpuCount; + + return 0; +} +EXPORT_SYMBOL(syno_cpu_temperature); + +/* Get the tjmax + * + * @return + * others: success + * -1: fail + **/ +int syno_cpu_tjmax(int cpu_no, int *tjmax) +{ + struct platform_data *pdata = NULL; + struct temp_data *tdata = NULL; + int iIndex = 0; + int ret = -1; + int i = 0; + + if (tjmax == NULL) { + goto RET; + } + + mutex_lock(&pdev_list_mutex); + for (i = 0; i < max_zones; i++) { + if (!zone_devices[i]) { + continue; + } + + pdata = dev_get_drvdata(&(zone_devices[i]->dev)); + if (!pdata) { + continue; + } + + if (cpu_no != pdata->pkg_id) { + continue; + } + + iIndex = TO_ATTR_NO(pdata->pkg_id); + tdata = pdata->core_data[iIndex]; + if (!tdata) { + printk("Can't get Core %d temperature data\n", pdata->pkg_id); + continue; + } + *tjmax = tdata->tjmax / 1000; + ret = 0; + break; + } + mutex_unlock(&pdev_list_mutex); +RET: + return ret; +} +EXPORT_SYMBOL(syno_cpu_tjmax); +#endif /* MY_DEF_HERE */ + MODULE_AUTHOR("Rudolf Marek "); MODULE_DESCRIPTION("Intel Core temperature monitor"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 3bc2551577a3..e548850b5594 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h/17h @@ -393,6 +396,44 @@ static void k10temp_get_ccd_support(struct pci_dev *pdev, } } +#ifdef MY_ABC_HERE +#include +int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp) +{ + struct pci_dev *pdev = NULL; + u32 regval; + int temp; + + if (NULL == pCpuTemp) { + printk("coretemp: parameter error.\n"); + return -1; + } + +#if defined(MY_DEF_HERE) || defined(MY_DEF_HERE) + pdev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3, NULL); +#elif defined(MY_ABC_HERE) || defined(MY_DEF_HERE) + pdev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3, NULL); +#elif defined(MY_DEF_HERE) + pdev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3, NULL); +#endif /* MY_DEF_HERE || MY_DEF_HERE || MY_ABC_HERE || MY_DEF_HERE */ + + if (!pdev) + return -ENODEV; + + read_tempreg_nb_zen(pdev, ®val); + + temp = (regval >> 21) * 125; + if (regval & 0x80000) + temp -= 49000; + + pCpuTemp->cpu_temp[0] = temp / 1000; + pCpuTemp->cpu_num = 1; + + return 0; +} +EXPORT_SYMBOL(syno_k10cpu_temperature); +#endif /* MY_ABC_HERE */ + static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int unreliable = has_erratum_319(pdev); diff --git a/drivers/hwmon/syno_hddmon.c b/drivers/hwmon/syno_hddmon.c new file mode 100644 index 000000000000..43118b97f56a --- /dev/null +++ b/drivers/hwmon/syno_hddmon.c @@ -0,0 +1,333 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("Proprietary"); + +#define SYNO_HDDMON_POLL_SEC 1 +#define SYNO_HDDMON_EN_WAIT_SEC 7 +#define SYNO_HDDMON_STR "Syno_HDDMon" +#define SYNO_HDDMON_UPLG_STR "Syno_HDDMon_UPLGM" + +extern int SYNO_CTRL_HDD_POWERON(int index, int value); +extern int SYNO_CHECK_HDD_DETECT(int index); +extern DISK_PWRCTRL_TYPE SYNO_GET_DISK_PWR_TYPE(int index); + +extern struct ata_port *syno_ata_port_get_by_port(const unsigned short diskPort); + +typedef struct __SynoHddMonData { + int iProcessingIdx; + int blHddHotPlugSupport; + int iMaxHddNum; + int* blHddEnStat; + int iHddEnWait; +} SynoHddMonData_t; + +static struct task_struct *pHddPrzPolling; +static SynoHddMonData_t synoHddMonData; + +static int syno_hddmon_data_init(SynoHddMonData_t *pData) +{ + int iRet = -1; + int idx = 0; + + if (NULL == pData) { + goto END; + } + + memset(pData, 0, sizeof(SynoHddMonData_t)); + + /* HDD monitor only service internal slots */ + if (0 == gSynoInternalHddNumber) { + goto END; + } + + /* HDD monitor can't work without present pins */ + for (idx = 1; idx <= gSynoInternalHddNumber; idx++) { + if (PWRCTRL_TYPE_GPIO == SYNO_GET_DISK_PWR_TYPE(idx)) { + pData->blHddHotPlugSupport = 1; + if (!HAVE_HDD_DETECT(idx)) { + pData->blHddHotPlugSupport = 0; + goto END; + } + } + } + if (0 == pData->blHddHotPlugSupport) { + goto END; + } + + pData->blHddHotPlugSupport = 1; + pData->iMaxHddNum = gSynoInternalHddNumber; + pData->blHddEnStat = kmalloc(sizeof(int) * pData->iMaxHddNum, GFP_KERNEL); + memset(pData->blHddEnStat, 0, sizeof(int) * pData->iMaxHddNum); + /* default wait time 7s */ + pData->iHddEnWait = SYNO_HDDMON_EN_WAIT_SEC; + +#ifdef MY_DEF_HERE + /* override wait time if setup spinup group */ + if (0 < giSynoSpinupGroupDelay) { + pData->iHddEnWait = giSynoSpinupGroupDelay; + } +#endif /* MY_DEF_HERE */ + + iRet = 0; +END: + return iRet; +} + +static int syno_hddmon_unplug_monitor(void *args) +{ + int iRet = -1; + int iIdx; + int iPrzPinVal; + SynoHddMonData_t *pData = NULL; + unsigned int uiTimeout; + + if (NULL == args) { + goto END; + } + + pData = (SynoHddMonData_t *) args; + + while (1) { + if (kthread_should_stop()) { + break; + } + + for (iIdx = 1; iIdx <= pData->iMaxHddNum; iIdx++) { + if (pData->iProcessingIdx == iIdx) { + continue; + } + + if (PWRCTRL_TYPE_GPIO != SYNO_GET_DISK_PWR_TYPE(iIdx)) { + continue; + } + + iPrzPinVal = SYNO_CHECK_HDD_DETECT(iIdx); + + if (iPrzPinVal) { + continue; + } + + mdelay(200); + SYNO_CTRL_HDD_POWERON(iIdx, iPrzPinVal); + pData->blHddEnStat[iIdx-1] = iPrzPinVal; + } + + uiTimeout = SYNO_HDDMON_POLL_SEC * HZ; + do { + set_current_state(TASK_INTERRUPTIBLE); + uiTimeout = schedule_timeout(uiTimeout); + } while (uiTimeout); + } + + iRet = 0; +END: + return iRet; +} + +#ifdef MY_ABC_HERE +extern int iIsSynoIRQOff(const struct ata_port *ap); + +static int syno_hddmon_is_disk_deepsleep(int iDiskIdx, SynoHddMonData_t *pData) +{ + struct ata_port *pAtaPrt = NULL; + int iErr = -1; + + if (NULL == pData) { + goto END; + } + + if (1 > iDiskIdx || pData->iMaxHddNum < iDiskIdx) { + iErr = -EINVAL; + goto END; + } + + if (NULL == (pAtaPrt = syno_ata_port_get_by_port(iDiskIdx))) { + iErr = -ENODEV; + goto END; + } + + iErr = iIsSynoIRQOff(pAtaPrt); +END: + return iErr; +} +#endif /* MY_ABC_HERE */ + +static void syno_hddmon_task(SynoHddMonData_t *pData) +{ + int iIdx; + int iPrzPinVal; + static struct task_struct *pUnplugMonitor; + unsigned int uiTimeout; + + if (NULL == pData) { + goto END; + } + + for (iIdx = 1; iIdx <= pData->iMaxHddNum; iIdx++) { + pUnplugMonitor = NULL; + pData->iProcessingIdx = iIdx; + + if (PWRCTRL_TYPE_GPIO != SYNO_GET_DISK_PWR_TYPE(iIdx)) { + continue; + } + iPrzPinVal = SYNO_CHECK_HDD_DETECT(iIdx); + + if (pData->blHddEnStat[iIdx-1] != iPrzPinVal) { +#ifdef MY_ABC_HERE + /*if the disk is plugged in while deep-sleep, do nothing*/ + if (iPrzPinVal && syno_hddmon_is_disk_deepsleep(iIdx, pData)) { + continue; + } +#endif /* MY_ABC_HERE */ + + if (iPrzPinVal) { + //while starting a port, monitoring other ports for the disks unplugged + pUnplugMonitor = kthread_run(syno_hddmon_unplug_monitor, pData, SYNO_HDDMON_UPLG_STR); + } + + mdelay(200); + + SYNO_CTRL_HDD_POWERON(iIdx, iPrzPinVal); + pData->blHddEnStat[iIdx-1] = iPrzPinVal; + + if (iPrzPinVal) { + uiTimeout = pData->iHddEnWait * HZ; + do { + set_current_state(TASK_INTERRUPTIBLE); + uiTimeout = schedule_timeout(uiTimeout); + } while (uiTimeout); + } + + if (NULL != pUnplugMonitor) { + kthread_stop(pUnplugMonitor); + } + } + } + +END: + return; +} + +static void syno_hddmon_sync(SynoHddMonData_t *pData) +{ + int iIdx; + int iPrzPinVal; + + if (NULL == pData) { + goto END; + } + + for (iIdx = 1; iIdx <= pData->iMaxHddNum; iIdx++) { + pData->iProcessingIdx = iIdx; + + if (PWRCTRL_TYPE_GPIO != SYNO_GET_DISK_PWR_TYPE(iIdx)) { + continue; + } + iPrzPinVal = SYNO_CHECK_HDD_DETECT(iIdx); + + /* HDD Enable pins must be high just after boot-up, + * so turns the pins to low if the hdds do not present. + */ + if (!iPrzPinVal) { + mdelay(200); + SYNO_CTRL_HDD_POWERON(iIdx, iPrzPinVal); + pData->blHddEnStat[iIdx-1] = iPrzPinVal; + } + + /*sync the states*/ + pData->blHddEnStat[iIdx-1] = iPrzPinVal; + + } + +END: + return; +} + +static int syno_hddmon_routine(void *args) +{ + int iRet = -1; + SynoHddMonData_t *pData = NULL; + unsigned int uiTimeout; + + if (NULL == args) { + goto END; + } + + pData = (SynoHddMonData_t *) args; + + while (1) { + if (kthread_should_stop()) { + break; + } + + syno_hddmon_task(pData); + + uiTimeout = SYNO_HDDMON_POLL_SEC * HZ; + do { + set_current_state(TASK_INTERRUPTIBLE); + uiTimeout = schedule_timeout(uiTimeout); + } while (uiTimeout); + } + + iRet = 0; +END: + return iRet; +} + +static int __init syno_hddmon_init(void) +{ + int iRet = -1; + + iRet = syno_hddmon_data_init(&synoHddMonData); + if (0 > iRet) { + goto END; + } + + syno_hddmon_sync(&synoHddMonData); + + /* processing */ + pHddPrzPolling = kthread_create(syno_hddmon_routine, &synoHddMonData, SYNO_HDDMON_STR); + + if (IS_ERR(pHddPrzPolling)) { + iRet = PTR_ERR(pHddPrzPolling); + pHddPrzPolling = NULL; + goto END; + } + + wake_up_process(pHddPrzPolling); + + printk("Syno_HddMon: Initialization completed.\n"); + + iRet = 0; +END: + return iRet; +} + +static void __exit syno_hddman_exit(void) +{ + if (pHddPrzPolling) { + printk("###\n"); + WARN_ON(1); + kthread_stop(pHddPrzPolling); + } + + if (synoHddMonData.blHddEnStat) { + kfree(synoHddMonData.blHddEnStat); + } + synoHddMonData.blHddEnStat = NULL; +} + +MODULE_AUTHOR("Yikai Peng"); +MODULE_DESCRIPTION("Syno_HddMon\n"); +MODULE_LICENSE("Synology Inc."); + +module_init(syno_hddmon_init); +module_exit(syno_hddman_exit); diff --git a/drivers/hwmon/syno_smbus_hddmon.c b/drivers/hwmon/syno_smbus_hddmon.c new file mode 100644 index 000000000000..893ef45ecb2a --- /dev/null +++ b/drivers/hwmon/syno_smbus_hddmon.c @@ -0,0 +1,140 @@ +/* Copyright (c) 2000-2019 Synology Inc. All rights reserved. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define BPCPLD_ADAPTER 0 +#define BPCPLD_TYPE "gowin" +#define BPCPLD_LOCATION 0x42 +#define BPCPLD_HDD_PRESENT 0x20 +#define BPCPLD_HDD_ENABLE 0x10 + +typedef struct SynoSMBusHddMonData { + int HddPresentStat; + int HddEnableStat; + //if need spinup group, add spinup group & delay variable here +} SynoSMBusHddMonData_t; + +static struct i2c_client *gpClient; +static SynoSMBusHddMonData_t synoSMBusHddMonData; + +struct i2c_board_info __initdata CPLDI2CBoardInfo[] = { + { + I2C_BOARD_INFO(BPCPLD_TYPE, BPCPLD_LOCATION), + }, +}; + +static int syno_smbus_hddmon_data_init(SynoSMBusHddMonData_t *pData) +{ + int iRet = -1; + + if (NULL == pData) { + goto END; + } + + memset(pData, 0, sizeof(SynoSMBusHddMonData_t)); + +//if need spinup group, get spinup group & delay info here + + iRet = 0; +END: + return iRet; +} + +static int syno_smbus_set_hdd_enable_data(int val) +{ + return i2c_smbus_write_byte_data(gpClient, BPCPLD_HDD_ENABLE, val); +} + +static int syno_i2c_client_init(void) +{ + int iRet = -1; + struct i2c_adapter *pAdapter = NULL; + + /* instantiate the devices explicitly */ + pAdapter = i2c_get_adapter(BPCPLD_ADAPTER); + if (NULL == pAdapter) { + printk(KERN_ERR "BP CPLD initial error: failed to get i2c adapter\n"); + goto END; + } + + /*regist board info*/ + gpClient = i2c_new_client_device(pAdapter, &CPLDI2CBoardInfo[0]); + if (NULL == gpClient) { + printk(KERN_ERR "BP CPLD initial error: failed to initial device\n"); + goto END; + } + + iRet = 0; + +END: + if (pAdapter) { + i2c_put_adapter(pAdapter); + } + + return iRet; +} + +static int syno_smbus_hdd_enable_spinup(SynoSMBusHddMonData_t *pData) +{ + int iRet = -1; + int iEnableVal; + + /* for RS1220+, directly set enable data byte to 0xff. + * if need spinup group, add code here. + */ + iEnableVal = 0xff; + iRet = syno_smbus_set_hdd_enable_data(iEnableVal); + if (0 > iRet) { + goto END; + } + +END: + return iRet; +} + +static int __init syno_smbus_hddmon_init(void) +{ + int iRet = -1; + + iRet = syno_smbus_hddmon_data_init(&synoSMBusHddMonData); + if (0 > iRet) { + goto END; + } + + iRet = syno_i2c_client_init(); + if (0 > iRet) { + goto END; + } + + iRet = syno_smbus_hdd_enable_spinup(&synoSMBusHddMonData); + if (0 > iRet) { + goto END; + } + + printk("Syno_SMBus_HddMon: Initialization completed.\n"); + + iRet = 0; +END: + return iRet; +} + + + +static void __exit syno_smbus_hddmon_exit(void) +{ + i2c_unregister_device(gpClient); + printk("Syno_SMBus_HddMon: Exit.\n"); +} + +MODULE_AUTHOR("Chih-Chien Chien"); +MODULE_DESCRIPTION("Syno_SMBus_HddMon\n"); +MODULE_LICENSE("GPL"); + +module_init(syno_smbus_hddmon_init); +module_exit(syno_smbus_hddmon_exit); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7e693dcbdd19..cb92e580b50e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -934,6 +934,18 @@ config I2C_QUP This driver can also be built as a module. If so, the module will be called i2c-qup. +if SYNO_LSP_RTD1619B +config I2C_REALTEK + tristate "Realtek I2C" + depends on I2C + help + This driver supports I2C Controller on Realtek SoC + +config I2C_RTK_SECURE_ACCESS + bool + depends on HAVE_ARM_SMCCC + +endif # SYNO_LSP_RTD1619B config I2C_RIIC tristate "Renesas RIIC adapter" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 683c49faca05..c54fe6e98133 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -95,6 +95,9 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_I2C_REALTEK) += i2c-rtk.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index cd3fd5ee5f65..72d9c2aaae14 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -213,7 +213,9 @@ static irqreturn_t amd_mp2_irq_isr(int irq, void *dev) unsigned int bus_id; void __iomem *reg; enum irqreturn ret = IRQ_NONE; + u32 retried = 0; +retry: for (bus_id = 0; bus_id < 2; bus_id++) { i2c_common = privdata->busses[bus_id]; if (!i2c_common) @@ -235,6 +237,10 @@ static irqreturn_t amd_mp2_irq_isr(int irq, void *dev) if (ret != IRQ_HANDLED) { val = readl(privdata->mmio + AMD_P2C_MSG_INTEN); if (val != 0) { + if (0 == retried) { + retried = 1; + goto retry; + } writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); dev_warn(ndev_dev(privdata), "received irq without message\n"); diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 506433bc0ff2..cc80fcb50259 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * AMD MP2 platform driver @@ -310,6 +313,10 @@ static int i2c_amd_probe(struct platform_device *pdev) i2c_dev->adap.dev.parent = &pdev->dev; i2c_dev->adap.algo_data = i2c_dev; i2c_dev->adap.timeout = AMD_I2C_TIMEOUT; +#if defined(MY_DEF_HERE) || defined(MY_DEF_HERE) || defined(MY_DEF_HERE) + i2c_dev->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD, +#endif /* MY_DEF_HERE || MY_DEF_HERE || MY_DEF_HERE */ + ACPI_COMPANION_SET(&i2c_dev->adap.dev, ACPI_COMPANION(&pdev->dev)); i2c_dev->adap.dev.of_node = pdev->dev.of_node; snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name), diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 2871cf2ee8b4..11ca29f93c7a 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Synopsys DesignWare I2C adapter driver (master only). @@ -20,6 +23,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "i2c-designware-core.h" @@ -69,6 +75,25 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) 4700, /* tLOW = 4.7 us */ scl_falling_time, 0); /* No offset */ + +#ifdef MY_ABC_HERE + /* FIXME: Don't use these model customize code + * They should be customized in dts or acpi + */ + if (!syno_is_hw_version(HW_DS1621p) && !syno_is_hw_version(HW_DS1821p)) { + dev->ss_hcnt = + i2c_dw_scl_hcnt(ic_clk, + 5000, /* tHD;STA = tHIGH = 5.0 us */ + sda_falling_time, + 0, /* 0: DW default, 1: Ideal */ + 0); /* No offset */ + dev->ss_lcnt = + i2c_dw_scl_lcnt(ic_clk, + 5000, /* tLOW = 5.0 us */ + scl_falling_time, + 0); /* No offset */ + } +#endif /* MY_ABC_HERE */ } dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n", dev->ss_hcnt, dev->ss_lcnt); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0dfeb2d11603..e507be0183ca 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Synopsys DesignWare I2C adapter driver. @@ -32,6 +35,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "i2c-designware-core.h" @@ -241,7 +247,23 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) else i2c_parse_fw_timings(&pdev->dev, t, false); +#ifdef MY_ABC_HERE + /* FIXME: Don't use these model customize code + * They should be customized in dts or acpi + */ + if (syno_is_hw_version(HW_DS1621p) || syno_is_hw_version(HW_DS1821p)) { + t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; + } else { + t->bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; + } + + if (syno_is_hw_version(HW_RS822p) || syno_is_hw_version(HW_RS822rpp) + || syno_is_hw_version(HW_SA6400) || syno_is_hw_version(HW_SA6200) || syno_is_hw_version(HW_FS6410) || syno_is_hw_version(HW_SC6200)) { + t->sda_hold_ns = 100; + } +#else /* MY_ABC_HERE */ i2c_dw_adjust_bus_speed(dev); +#endif /* MY_ABC_HERE */ if (pdev->dev.of_node) dw_i2c_of_configure(pdev); @@ -282,6 +304,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) adap->owner = THIS_MODULE; adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ? I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; +#ifdef MY_ABC_HERE + /* override class to use this driver directly */ + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; +#endif /* MY_ABC_HERE */ ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; adap->nr = -1; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index eab6fd6b890e..a96c3382b622 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (c) 1998 - 2002 Frodo Looijaard , @@ -107,6 +110,11 @@ #include #include +#ifdef MY_DEF_HERE +#include +#include +#endif /* MY_DEF_HERE */ + #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI #include #include @@ -123,6 +131,10 @@ #define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ #define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ #define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ +#ifdef MY_DEF_HERE +// SMBUS_PIN_CTL Register (SMBC)—Offset Fh +#define SMBPINCTL(p) (15 + (p)->smba) +#endif /* MY_DEF_HERE */ #define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ #define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ #define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ @@ -149,6 +161,9 @@ #define SMBHSTCFG_HST_EN BIT(0) #define SMBHSTCFG_SMB_SMI_EN BIT(1) #define SMBHSTCFG_I2C_EN BIT(2) +#ifdef MY_DEF_HERE +#define SMBHSTCFG_SSRESET BIT(3) +#endif /* MY_DEF_HERE */ #define SMBHSTCFG_SPD_WD BIT(4) /* TCO configuration bits for TCOCTL */ @@ -192,6 +207,13 @@ #define SMBHSTSTS_INTR BIT(1) #define SMBHSTSTS_HOST_BUSY BIT(0) +#ifdef MY_DEF_HERE +/* I801 Pin Control register bits*/ +#define SMBPINCTL_SCL_CTL BIT(2) +#define SMBPINCTL_SDATA_STS BIT(1) +#define SMBPINCTL_SCL_STS BIT(0) +#endif /* MY_DEF_HERE */ + /* Host Notify Status register bits */ #define SMBSLVSTS_HST_NTFY_STS BIT(0) @@ -320,6 +342,330 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" "\t\t 0x10 don't use interrupts\n" "\t\t 0x20 disable SMBus Host Notify "); +#ifdef MY_DEF_HERE +static int i801_i2c_get_sda(struct i2c_adapter *adap) +{ + struct i801_priv *priv = NULL; + int result = 0; + if (adap) { + priv = i2c_get_adapdata(adap); + } else { + printk("adap should not be null\n"); + goto out; + } + + if (priv) { + result = inb_p(SMBPINCTL(priv)) & SMBPINCTL_SDATA_STS; + } else { + printk("priv should not be null\n"); + goto out; + } + +out: + return result; +} + +static int i801_i2c_get_scl(struct i2c_adapter *adap) +{ + struct i801_priv *priv = NULL; + int result = 0; + if (adap) { + priv = i2c_get_adapdata(adap); + } else { + printk("adap should not be null\n"); + goto out; + } + + if (priv) { + result = inb_p(SMBPINCTL(priv)) & SMBPINCTL_SCL_STS; + } else { + printk("priv should not be null\n"); + goto out; + } + +out: + return result; +} + +static void i801_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct i801_priv *priv = NULL; + + if (adap) { + priv = i2c_get_adapdata(adap); + } else { + printk("adap should not be null\n"); + goto out; + } + + if (priv) { + if (val) { + outb_p(SMBPINCTL_SCL_CTL, SMBPINCTL(priv)); + } else { + outb_p(0, SMBPINCTL(priv)); + } + } else { + printk("priv should not be null\n"); + goto out; + } + +out: + return; +} + +#define SMB_CLK_DELAY_TIME_MS 42 + +static int i801_delay_recovery(struct i2c_adapter *adap) +{ + int ret = -1; + + if (NULL == adap) { + printk("adap should not be null\n"); + goto out; + } + + i801_i2c_set_scl(adap, 0); + mdelay(SMB_CLK_DELAY_TIME_MS); + i801_i2c_set_scl(adap, 1); + + if (i801_i2c_get_sda(adap)) + ret = 0; + +out: + return ret; +} + +static unsigned long delay_try_cnt = 0; +static unsigned long delay_suc_cnt = 0; +static unsigned long pulse_try_cnt = 0; +static unsigned long pulse_suc_cnt = 0; +static unsigned long i801_reset_count = 0; +static int i801_smbusbusy = 0; + +static int i801_recovery_proc_show(struct seq_file *m, void *v) +{ + struct i801_priv *priv = (struct i801_priv *)m->private; + + pulse_try_cnt++; + if (0 == i2c_recover_bus(&priv->adapter)) { + pulse_suc_cnt++; + printk("i2c recover work\n"); + goto out; + } + + delay_try_cnt++; + if (0 == i801_delay_recovery(&priv->adapter)) { + delay_suc_cnt++; + printk("smbus recover work\n"); + goto out; + } + +out: + + seq_printf(m, "Force i2c recoery\n"); + + return 0; +} + +static int i801_recovery_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, i801_recovery_proc_show, PDE_DATA(inode)); +} + +static const struct proc_ops i801_recovery_proc_fops = { + .proc_open = i801_recovery_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int i801_recovery_cnt_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "42ms delay try cnt : %lu\n", delay_try_cnt); + seq_printf(m, "42ms delay suc cnt : %lu\n", delay_suc_cnt); + seq_printf(m, "more pulse try cnt : %lu\n", pulse_try_cnt); + seq_printf(m, "more pulse suc cnt : %lu\n", pulse_suc_cnt); + + return 0; +} + +static int i801_recovery_cnt_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, i801_recovery_cnt_proc_show, PDE_DATA(inode)); +} + +static const struct proc_ops i801_recovery_cnt_proc_fops = { + .proc_open = i801_recovery_cnt_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int proc_i801_recovery_cnt_init(struct i801_priv *priv) +{ + int iResult = 0; + struct proc_dir_entry *p; + p = proc_create_data("i801_recovery_cnt", 0, NULL, &i801_recovery_cnt_proc_fops, priv); + if (NULL == p) { + printk("Fail to cat i801_recovery_cnt proc\n"); + iResult = -1; + } + + return iResult; +} + +static int proc_i801_recovery_init(struct i801_priv *priv) +{ + int iResult = 0; + struct proc_dir_entry *p; + p = proc_create_data("i801_recovery", 0, NULL, &i801_recovery_proc_fops, priv); + if (NULL == p) { + printk("Fail to create i801_recovery proc\n"); + iResult = -1; + } + + return iResult; +} +static struct i2c_bus_recovery_info i801_i2c_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .get_scl = i801_i2c_get_scl, + .set_scl = i801_i2c_set_scl, + .get_sda = i801_i2c_get_sda, +}; + +#define BUS_BUSY_COUT_TO_RESET 3 +#define BUS_BUSY_TIMEWINDOW_TO_RESET 1 * HZ +static void syno_i801_softreset(struct i801_priv *priv) +{ + static int smbus_busy_count = 1; + static unsigned long gulSmbus_busy_first_timestamp = 0; + unsigned char hostc; + + if (time_before(jiffies, gulSmbus_busy_first_timestamp + BUS_BUSY_TIMEWINDOW_TO_RESET)) { + if (smbus_busy_count >= BUS_BUSY_COUT_TO_RESET) { + // Soft reset SMBus controller due to multiple BUSBUSY in a preiod of time + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, + hostc | SMBHSTCFG_SSRESET); + + printk("i801 softreset\n"); + smbus_busy_count = 0; + i801_reset_count++; + } else { + smbus_busy_count++; + } + } else { + gulSmbus_busy_first_timestamp = jiffies; + smbus_busy_count = 1; + } +} + +// +// sysfs to i801 soft reset +// +static int i801_softreset_proc_show(struct seq_file *m, void *v) +{ + struct i801_priv *priv = (struct i801_priv *)m->private; + unsigned char hostc; + + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, + hostc | SMBHSTCFG_SSRESET); + + i801_reset_count++; + seq_printf(m, "i801 soft reset\n"); + + return 0; +} +static int i801_softreset_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, i801_softreset_proc_show, PDE_DATA(inode)); +} +static const struct proc_ops i801_softreset_proc_fops = { + .proc_open = i801_softreset_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +static int proc_i801_softreset_init(struct i801_priv *priv) +{ + int iResult = 0; + struct proc_dir_entry *p; + p = proc_create_data("i801_softreset", 0, NULL, &i801_softreset_proc_fops, priv); + if (NULL == p) { + printk("Fail to create i801_softreset proc\n"); + iResult = -1; + } + + return iResult; +} + +// +// sysfs to print i801 soft reset count +// +static int i801_softreset_cnt_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "i801 soft reset count: %lu\n", i801_reset_count); + + return 0; +} +static int i801_softreset_cnt_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, i801_softreset_cnt_proc_show, PDE_DATA(inode)); +} +static const struct proc_ops i801_softreset_cnt_proc_fops = { + .proc_open = i801_softreset_cnt_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +static int proc_i801_softreset_cnt_init(struct i801_priv *priv) +{ + int iResult = 0; + struct proc_dir_entry *p; + p = proc_create_data("i801_softreset_cnt", 0, NULL, &i801_softreset_cnt_proc_fops, priv); + if (NULL == p) { + printk("Fail to create i801_softreset_cnt proc\n"); + iResult = -1; + } + + return iResult; +} + +// +// sysfs to force smbus busy only once +// +static int i801_smbusbusy_proc_show(struct seq_file *m, void *v) +{ + i801_smbusbusy = 1; + seq_printf(m, "force i801 smbusbusy\n"); + + return 0; +} +static int i801_smbusbusy_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, i801_smbusbusy_proc_show, PDE_DATA(inode)); +} +static const struct proc_ops i801_smbusbusy_proc_fops = { + .proc_open = i801_smbusbusy_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +static int proc_i801_smbusbusy_init(struct i801_priv *priv) +{ + int iResult = 0; + struct proc_dir_entry *p; + p = proc_create_data("i801_smbusbusy", 0, NULL, &i801_smbusbusy_proc_fops, priv); + if (NULL == p) { + printk("Fail to create i801_smbusbusy proc\n"); + iResult = -1; + } + + return iResult; +} +#endif /* MY_DEF_HERE */ + /* Make sure the SMBus host is ready to start transmitting. Return 0 if it is, -EBUSY if it is not. */ static int i801_check_pre(struct i801_priv *priv) @@ -327,7 +673,13 @@ static int i801_check_pre(struct i801_priv *priv) int status; status = inb_p(SMBHSTSTS(priv)); +#ifdef MY_DEF_HERE + if (i801_smbusbusy || (status & SMBHSTSTS_HOST_BUSY)) { + syno_i801_softreset(priv); + i801_smbusbusy = 0; +#else /* MY_DEF_HERE */ if (status & SMBHSTSTS_HOST_BUSY) { +#endif /* MY_DEF_HERE */ dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); return -EBUSY; } @@ -851,6 +1203,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, int block = 0; int ret = 0, xact = 0; struct i801_priv *priv = i2c_get_adapdata(adap); +#ifdef MY_DEF_HERE + int iRunTimes = 0; +#endif /* MY_DEF_HERE */ mutex_lock(&priv->acpi_lock); if (priv->acpi_reserved) { @@ -860,6 +1215,10 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, pm_runtime_get_sync(&priv->pci_dev->dev); +#ifdef MY_DEF_HERE +redo: +#endif /* MY_DEF_HERE */ + hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; @@ -979,6 +1338,31 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); + +#ifdef MY_DEF_HERE + //Only first run and SDA low we do recover, + //We run i2c recovery first, then SMBUS recover if needed + if ((-ENXIO == ret) && !(i801_i2c_get_sda(adap))) { + iRunTimes++; + delay_try_cnt++; + if ((10 >= iRunTimes) && (0 == i801_delay_recovery(adap))) { + delay_suc_cnt++; + goto redo; + } + pulse_try_cnt++; + if ((20 >= iRunTimes ) && (0 == i2c_recover_bus(adap))) { + pulse_suc_cnt++; + goto redo; + } + + if (20 < iRunTimes) { + printk("Fail to recover i801 \n"); + } else { + goto redo; + } + } +#endif /* MY_DEF_HERE */ + mutex_unlock(&priv->acpi_lock); return ret; } @@ -1816,6 +2200,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) } priv->features &= ~disable_features; +#ifdef MY_ABC_HERE + priv->features &= ~FEATURE_IRQ; +#endif /* MY_ABC_HERE */ + err = pcim_enable_device(dev); if (err) { dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", @@ -1929,6 +2317,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) pm_runtime_put_autosuspend(&dev->dev); pm_runtime_allow(&dev->dev); +#ifdef MY_DEF_HERE + proc_i801_recovery_init(priv); + priv->adapter.bus_recovery_info = &i801_i2c_recovery_info; + proc_i801_recovery_cnt_init(priv); + proc_i801_softreset_init(priv); + proc_i801_softreset_cnt_init(priv); + proc_i801_smbusbusy_init(priv); +#endif /* MY_DEF_HERE */ + return 0; } @@ -1947,6 +2344,13 @@ static void i801_remove(struct pci_dev *dev) platform_device_unregister(priv->tco_pdev); +#ifdef MY_DEF_HERE + remove_proc_entry("i801_recovery", NULL); + remove_proc_entry("i801_recovery_cnt", NULL); + remove_proc_entry("i801_smbusbusy", NULL); + remove_proc_entry("i801_softreset", NULL); + remove_proc_entry("i801_softreset_cnt", NULL); +#endif /* MY_DEF_HERE */ /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) diff --git a/drivers/i2c/busses/i2c-rtk.c b/drivers/i2c/busses/i2c-rtk.c new file mode 100644 index 000000000000..00dafaf31b14 --- /dev/null +++ b/drivers/i2c/busses/i2c-rtk.c @@ -0,0 +1,1049 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek I2C driver + * + * Copyright (c) 2017 - 2020 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* I2C Registers */ +#define I2C_CON 0x00 +#define I2C_TAR 0x04 +#define I2C_SAR 0x08 +#define I2C_DATA_CMD 0x10 +#define I2C_SS_SCL_HCNT 0x14 +#define I2C_SS_SCL_LCNT 0x18 +#define I2C_FS_SCL_HCNT 0x1c +#define I2C_FS_SCL_LCNT 0x20 +#define I2C_HS_SCL_HCNT 0x24 +#define I2C_HS_SCL_LCNT 0x28 +#define I2C_INTR_STAT 0x2C +#define I2C_INTR_MASK 0x30 +#define I2C_RAW_INTR_STAT 0x34 +#define I2C_RX_TL 0x38 +#define I2C_TX_TL 0x3C +#define I2C_CLR_INT 0x40 +#define I2C_CLR_RX_UNDER 0x44 +#define I2C_CLR_RX_OVER 0x48 +#define I2C_CLR_TX_OVER 0x4c +#define I2C_CLR_RD_REQ 0x50 +#define I2C_CLR_TX_ABRT 0x54 +#define I2C_CLR_RX_DONE 0x58 +#define I2C_CLR_ACTIVITY 0x5c +#define I2C_CLR_STOP_DET 0x60 +#define I2C_CLR_START_DET 0x64 +#define I2C_CLR_GEN_CALL 0x68 +#define I2C_ENABLE 0x6C +#define I2C_IC_STATUS 0x70 +#define I2C_TXFLR 0x74 +#define I2C_RXFLR 0x78 +#define I2C_SDA_HOLD 0x7c +#define I2C_TX_ABRT_SOURCE 0x80 +#define I2C_COMP_PARAM_1 0xF4 + +/* I2C_CONTROL Masks */ +#define MASTER_EN (1UL << 0) +#define TEN_BIT_SLAVE (1UL << 3) +#define TEN_BIT_MASTER (1UL << 4) +#define RESTART_EN (1UL << 5) +#define SLAVE_DISABLE (1UL << 6) +#define TX_EMPTY_CTL (1UL << 8) +#define SPEED_MSK 0x06 +#define SPEED_SS 0x02 +#define SPEED_FS 0x04 +#define SPEED_HS 0x06 + +/* I2C_TAR Masks */ +#define TAR_TEN_BITADDR (1UL << 12) + +#define STOP_CMD (1UL << 9) +#define RESTART_CMD (1UL << 10) + +/* INTR_MASK */ +#define RX_UNDER (1UL << 0) +#define RX_OVER (1UL << 1) +#define RX_FULL (1UL << 2) +#define TX_OVER (1UL << 3) +#define TX_EMPTY (1UL << 4) +#define RD_REQ (1UL << 5) +#define TX_ABRT (1UL << 6) +#define RX_DONE (1UL << 7) +#define ACTIVITY (1UL << 8) +#define STOP_DET (1UL << 9) +#define START_DET (1UL << 10) +#define GEN_CALL (1UL << 11) +#define INT_DEFAULT_MASK (RX_FULL | TX_EMPTY | TX_ABRT | STOP_DET) + +/* I2C_IC_STATUS */ +#define SLV_ACTIVITY (1UL << 6) + +#define STATUS_IDLE 0x0 +#define STATUS_W_IN_PROGRESS 0x1 +#define STATUS_R_IN_PROGRESS 0x2 +#define STATUS_W_TAR_CHANGE 0x4 + +/* + * hardware abort codes from the TX_ABRT_SOURCE register + * + * only expected abort codes are listed here + * refer to the datasheet for the full list + */ +#define ABRT_7B_ADDR_NOACK 0 +#define ABRT_10ADDR1_NOACK 1 +#define ABRT_10ADDR2_NOACK 2 +#define ABRT_TXDATA_NOACK 3 +#define ABRT_GCALL_NOACK 4 +#define ABRT_GCALL_READ 5 +#define ABRT_SBYTE_ACKDET 7 +#define ABRT_SBYTE_NORSTRT 9 +#define ABRT_10B_RD_NORSTRT 10 +#define ABRT_MASTER_DIS 11 +#define ABRT_LOST 12 + +#define TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK) +#define TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK) +#define TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK) +#define TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK) +#define TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK) +#define TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ) +#define TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET) +#define TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT) +#define TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT) +#define TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS) +#define TX_ABRT_LOST (1UL << ABRT_LOST) + +#define TX_ABRT_NOACK (TX_ABRT_7B_ADDR_NOACK | \ + TX_ABRT_10ADDR1_NOACK | \ + TX_ABRT_10ADDR2_NOACK | \ + TX_ABRT_TXDATA_NOACK | \ + TX_ABRT_GCALL_NOACK) + +#define SDA_DEL_EN + +static int ISR_CLR_BIT[] = { 8, 11, 26, 23, 15, 14, 10 }; +#ifdef SDA_DEL_EN +static int SDA_DEL_SHIFT[] = { 0x84, 0x80, 0x80, 0x90, 0x94, 0x98, 0xC0 }; +#define I2C_SDA_DEL_MASK (0x1FF) +#define I2C_SDA_DEL_EN (0x00000001<<8) +#define I2C_SDA_DEL_SEL(x) ((x & 0x1F)) /* Delay time: (unit 518ns)*/ +#define SDA_DEL_518NS 1 +#define I2C0_SDA_DEL_520NS 4 +#define SDA_DEL_1036NS 2 +#define SDA_DEL_1554NS 3 +#define SDA_DEL_2072NS 4 +#define SDA_DEL_2590NS 5 +#endif + +static char *abort_sources[] = { + [ABRT_7B_ADDR_NOACK] = + "slave address not acknowledged (7bit mode)", + [ABRT_10ADDR1_NOACK] = + "first address byte not acknowledged (10bit mode)", + [ABRT_10ADDR2_NOACK] = + "second address byte not acknowledged (10bit mode)", + [ABRT_TXDATA_NOACK] = + "data not acknowledged", + [ABRT_GCALL_NOACK] = + "no acknowledgement for a general call", + [ABRT_GCALL_READ] = + "read after general call", + [ABRT_SBYTE_ACKDET] = + "start byte acknowledged", + [ABRT_SBYTE_NORSTRT] = + "trying to send start byte when restart is disabled", + [ABRT_10B_RD_NORSTRT] = + "trying to read when restart is disabled (10bit mode)", + [ABRT_MASTER_DIS] = + "trying to use disabled adapter", + [ABRT_LOST] = + "lost arbitration", +}; + +struct rtk_i2c_quirks { + int high_speed; +}; + +struct rtk_i2c_dev { + struct device *dev; + struct i2c_adapter adap; + struct i2c_client *slave; + struct completion msg_done; + struct clk *clk; + struct i2c_msg *msgs; + struct i2c_bus_recovery_info bri; + + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_default; + struct pinctrl_state *pinctrl_gpio; + + unsigned int tx_buf_len; + unsigned char *tx_buf; + unsigned int rx_buf_len; + unsigned char *rx_buf; + int msgs_num; + int msg_w_idx; + int msg_r_idx; + int msg_err; + int rx_outstanding; + int abort_source; + int tx_fifo_depth; + int rx_fifo_depth; + + struct i2c_timings timings; + + void __iomem *base; + void __iomem *irqbase; + int irq; + int status; + + enum rtd_chip_id chip_id; + const struct rtk_i2c_quirks *quirks; +}; + +static void rtk_i2c_int_disable(struct rtk_i2c_dev *priv, unsigned int mask) +{ + unsigned int int_en; + + int_en = readl(priv->base + I2C_INTR_MASK); + writel(int_en & ~mask, priv->base + I2C_INTR_MASK); +} + +static void rtk_i2c_int_enable(struct rtk_i2c_dev *priv, unsigned int mask) +{ + unsigned int int_en; + + int_en = readl(priv->base + I2C_INTR_MASK); + writel(int_en | mask, priv->base + I2C_INTR_MASK); +} + +static inline int rtk_i2c_high_speed_supported(struct rtk_i2c_dev *priv) +{ + struct i2c_adapter *adap = &priv->adap; + + if (priv->quirks) + return priv->quirks->high_speed; + + return (adap->nr == 0) && (((priv->chip_id & 0xFFF0) == CHIP_ID_RTD161X) + || ((priv->chip_id & 0xFFF0) == CHIP_ID_RTD131X)); +} + +static int rtk_i2c_set_speed(struct rtk_i2c_dev *priv) +{ + struct i2c_adapter *adap = &priv->adap; + unsigned int KHz = priv->timings.bus_freq_hz / 1000; + unsigned int scl_time; + unsigned int div_h = 0; + unsigned int div_l = 0; + unsigned int fs_hcnt = 0; + unsigned int fs_lcnt = 0; + unsigned int clk_time; + unsigned int val; + int max_speed = rtk_i2c_high_speed_supported(priv) ? 3400 : 800; + + if (KHz < 10 || KHz > max_speed) { + dev_err(priv->dev, "speed %d out of range\n", KHz); + return -1; + } + + clk_time = 37; /*use 27MHZ crystal, one clock 37ns*/ + scl_time = (1000000 / KHz) / 2; /* the time ns need for SCL */ + if (scl_time % clk_time) { + if ((scl_time % clk_time) > clk_time / 2) + scl_time += (clk_time - (scl_time % clk_time)); + else + scl_time -= (scl_time % clk_time); + } + + if (rtk_i2c_high_speed_supported(priv)) { + if (KHz == 100) { + div_h = 524; + div_l = 532; + } else if (KHz == 400) { + div_h = 106; + div_l = 146; + } else if (KHz == 3400) { + fs_hcnt = 106; + fs_lcnt = 146; + div_h = 6; + div_l = 17; + } + } else { + if (KHz < 400) { + div_h = (scl_time / clk_time) - 8; + div_l = (scl_time / clk_time); + } else { + div_h = 21; + div_l = 35; + } + } + + writel(0, priv->base + I2C_ENABLE); + + val = readl(priv->base + I2C_CON); + if (KHz <= 100) { + writel((val & ~SPEED_MSK) | SPEED_SS, priv->base + I2C_CON); + writel(div_h, priv->base + I2C_SS_SCL_HCNT); + writel(div_l, priv->base + I2C_SS_SCL_LCNT); + } else if (KHz == 400) { + writel((val & ~SPEED_MSK) | SPEED_FS, priv->base + I2C_CON); + writel(div_h, priv->base + I2C_FS_SCL_HCNT); + writel(div_l, priv->base + I2C_FS_SCL_LCNT); + } else if (KHz == 3400) { + writel((val & ~SPEED_MSK) | SPEED_HS, priv->base + I2C_CON); + writel(fs_hcnt, priv->base + I2C_FS_SCL_HCNT); + writel(fs_lcnt, priv->base + I2C_FS_SCL_LCNT); + writel(div_h, priv->base + I2C_HS_SCL_HCNT); + writel(div_l, priv->base + I2C_HS_SCL_LCNT); + priv->timings.sda_hold_ns = 0x5; + } + + if (adap->nr != 0 && priv->timings.sda_hold_ns == 0 && ((1000000 / KHz) / 4) > 600 ) + priv->timings.sda_hold_ns = (((1000000 / KHz) / 4 - 600) * 27) / 1000; + + writel(priv->timings.sda_hold_ns, priv->base + I2C_SDA_HOLD); + + dev_info(priv->dev, "i2c sda hold time = 0x%x\n", priv->timings.sda_hold_ns); + +#ifdef SDA_DEL_EN + val = readl(priv->irqbase + SDA_DEL_SHIFT[adap->nr]); + val &= ~I2C_SDA_DEL_MASK; + + if (rtk_i2c_high_speed_supported(priv)) { + if (KHz == 3400) + val = 0x0; + else + val |= I2C_SDA_DEL_EN | I2C_SDA_DEL_SEL(I2C0_SDA_DEL_520NS); + + } else { + val |= I2C_SDA_DEL_EN | I2C_SDA_DEL_SEL(SDA_DEL_518NS); + } + writel(val, priv->irqbase + SDA_DEL_SHIFT[adap->nr]); +#endif + return 0; +} + +static void rtk_i2c_disable(struct rtk_i2c_dev *priv) +{ + writel(0, priv->base + I2C_ENABLE); + writel(0, priv->base + I2C_INTR_MASK); + readl(priv->base + I2C_CLR_INT); +} + +static int rtk_i2c_init(struct rtk_i2c_dev *priv) +{ + writel(0, priv->base + I2C_ENABLE); + writel(0, priv->base + I2C_INTR_MASK); + + priv->tx_fifo_depth = + (((readl(priv->base + I2C_COMP_PARAM_1) >> 16) & 0xFF) + 1); + priv->rx_fifo_depth = + (((readl(priv->base + I2C_COMP_PARAM_1) >> 8) & 0xFF) + 1); + + writel(0, priv->base + I2C_TX_TL); + writel(0, priv->base + I2C_RX_TL); + + return rtk_i2c_set_speed(priv); +} + +#if IS_ENABLED(CONFIG_I2C_SLAVE) +static unsigned int rtk_i2c_clear_intrbits_slave(struct rtk_i2c_dev *priv) +{ + unsigned int status; + + status = readl(priv->base + I2C_INTR_STAT); + + if (status & TX_ABRT) + readl(priv->base + I2C_CLR_TX_ABRT); + if (status & RX_UNDER) + readl(priv->base + I2C_CLR_RX_UNDER); + if (status & RX_OVER) + readl(priv->base + I2C_CLR_RX_OVER); + if (status & TX_OVER) + readl(priv->base + I2C_CLR_TX_OVER); + if (status & RX_DONE) + readl(priv->base + I2C_CLR_RX_DONE); + if (status & ACTIVITY) + readl(priv->base + I2C_CLR_ACTIVITY); + if (status & STOP_DET) + readl(priv->base + I2C_CLR_STOP_DET); + if (status & START_DET) + readl(priv->base + I2C_CLR_START_DET); + if (status & GEN_CALL) + readl(priv->base + I2C_CLR_GEN_CALL); + + return status; +} +#endif + +static unsigned int rtk_i2c_clear_intrbits(struct rtk_i2c_dev *priv) +{ + unsigned int status; + + status = readl(priv->base + I2C_INTR_STAT); + + if (status & RX_UNDER) + readl(priv->base + I2C_CLR_RX_UNDER); + if (status & RX_OVER) + readl(priv->base + I2C_CLR_RX_OVER); + if (status & TX_OVER) + readl(priv->base + I2C_CLR_TX_OVER); + if (status & RD_REQ) + readl(priv->base + I2C_CLR_RD_REQ); + if (status & TX_ABRT) { + priv->abort_source = readl(priv->base + I2C_TX_ABRT_SOURCE); + readl(priv->base + I2C_CLR_TX_ABRT); + } + if (status & RX_DONE) + readl(priv->base + I2C_CLR_RX_DONE); + if (status & ACTIVITY) + readl(priv->base + I2C_CLR_ACTIVITY); + if (status & STOP_DET) + readl(priv->base + I2C_CLR_STOP_DET); + if (status & START_DET) + readl(priv->base + I2C_CLR_START_DET); + if (status & GEN_CALL) + readl(priv->base + I2C_CLR_GEN_CALL); + + return status; +} + +static void rtk_i2c_handle_tx_abort(struct rtk_i2c_dev *priv) +{ + unsigned long abort_source = priv->abort_source; + int i; + + if (abort_source & TX_ABRT_NOACK) { + for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) +#ifdef MY_DEF_HERE + dev_dbg(priv->dev, + "%s: %s\n", __func__, abort_sources[i]); +#else /* MY_DEF_HERE */ + dev_err(priv->dev, + "%s: %s\n", __func__, abort_sources[i]); +#endif /* MY_DEF_HERE */ + return; + } + + for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) + dev_err(priv->dev, "%s: %s\n", __func__, abort_sources[i]); +} + +static void rtk_i2c_xfer_read(struct rtk_i2c_dev *priv) +{ + struct i2c_msg *msgs = priv->msgs; + int rx_valid; + + for (; priv->msg_r_idx < priv->msgs_num; priv->msg_r_idx++) { + unsigned int len; + unsigned char *buf; + + if (!(msgs[priv->msg_r_idx].flags & I2C_M_RD)) + continue; + + if (!(priv->status & STATUS_R_IN_PROGRESS)) { + len = msgs[priv->msg_r_idx].len; + buf = msgs[priv->msg_r_idx].buf; + } else { + len = priv->rx_buf_len; + buf = priv->rx_buf; + } + + rx_valid = readl(priv->base + I2C_RXFLR); + + for (; len > 0 && rx_valid > 0; len--, rx_valid--) { + *buf++ = readl(priv->base + I2C_DATA_CMD); + priv->rx_outstanding--; + } + + if (len > 0) { + priv->status |= STATUS_R_IN_PROGRESS; + priv->rx_buf_len = len; + priv->rx_buf = buf; + return; + } + priv->status &= ~STATUS_R_IN_PROGRESS; + } +} + +static void rtk_i2c_xfer_msg(struct rtk_i2c_dev *priv) +{ + struct i2c_msg *msgs = priv->msgs; + unsigned int addr = msgs[priv->msg_w_idx].addr; + unsigned int buf_len = priv->tx_buf_len; + unsigned char *buf = priv->tx_buf; + int tx_limit, rx_limit; + bool restart = false; + unsigned int intr_mask = 0; + + for (; priv->msg_w_idx < priv->msgs_num; priv->msg_w_idx++) { + if (msgs[priv->msg_w_idx].addr != addr) { + priv->status |= STATUS_W_TAR_CHANGE; + break; + } + if (msgs[priv->msg_w_idx].len == 0) { + dev_err(priv->dev, + "%s: invalid message length\n", __func__); + priv->msg_err = -EINVAL; + break; + } + if (priv->status & STATUS_W_TAR_CHANGE) { + writel(0, priv->base + I2C_ENABLE); + if (msgs[priv->msg_w_idx].flags & I2C_M_TEN) + writel((msgs[priv->msg_w_idx].addr & 0x3FF) | + TAR_TEN_BITADDR, priv->base + I2C_TAR); + else + writel(msgs[priv->msg_w_idx].addr & 0x7F, + priv->base + I2C_TAR); + writel(1, priv->base + I2C_ENABLE); + restart = true; + priv->status &= ~STATUS_W_TAR_CHANGE; + } + if (!(priv->status & STATUS_W_IN_PROGRESS)) { + buf = msgs[priv->msg_w_idx].buf; + buf_len = msgs[priv->msg_w_idx].len; + if (priv->msg_w_idx > 0) + restart = true; + } + tx_limit = priv->tx_fifo_depth - readl(priv->base + I2C_TXFLR); + rx_limit = priv->rx_fifo_depth - readl(priv->base + I2C_RXFLR); + + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + unsigned int cmd = 0; + + if ((priv->msg_w_idx == priv->msgs_num - 1) && + buf_len == 1) + cmd |= STOP_CMD; + if (restart) { + cmd |= RESTART_CMD; + restart = false; + } + + if (msgs[priv->msg_w_idx].flags & I2C_M_RD) { + if (priv->rx_outstanding >= priv->rx_fifo_depth) + break; + writel(cmd | 0x100, priv->base + I2C_DATA_CMD); + rx_limit--; + priv->rx_outstanding++; + } else + writel(cmd | *buf++, priv->base + I2C_DATA_CMD); + tx_limit--; buf_len--; + } + priv->tx_buf = buf; + priv->tx_buf_len = buf_len; + + if (buf_len > 0) { + /* more bytes to be written */ + priv->status |= STATUS_W_IN_PROGRESS; + break; + } + priv->status &= ~STATUS_W_IN_PROGRESS; + } + + if (priv->msg_w_idx == priv->msgs_num) + intr_mask = TX_EMPTY; + + if (priv->msg_err) + intr_mask = ~0; + + if (intr_mask) + rtk_i2c_int_disable(priv, intr_mask); +} + +static int rtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct rtk_i2c_dev *priv = i2c_get_adapdata(adap); + unsigned int val; + unsigned int addr = 0; + + if (priv->slave != NULL) { + priv->msg_err = -EPROTOTYPE; + goto fail; + } + + reinit_completion(&priv->msg_done); + priv->msgs = msgs; + priv->msgs_num = num; + priv->msg_err = 0; + priv->msg_w_idx = 0; + priv->msg_r_idx = 0; + priv->status = STATUS_IDLE; + priv->rx_outstanding = 0; + priv->abort_source = 0; + + writel(0, priv->base + I2C_ENABLE); + + if (msgs[priv->msg_w_idx].flags & I2C_M_TEN) { + addr = msgs[priv->msg_w_idx].addr & 0x3FF; + writel(addr | TAR_TEN_BITADDR, priv->base + I2C_TAR); + val = readl(priv->base + I2C_CON) | TEN_BIT_MASTER; + val = val | SLAVE_DISABLE | MASTER_EN | TX_EMPTY_CTL; + writel(val, priv->base + I2C_CON); + } else { + addr = msgs[priv->msg_w_idx].addr & 0x7F; + writel(addr, priv->base + I2C_TAR); + val = readl(priv->base + I2C_CON) & ~TEN_BIT_MASTER; + val = val | SLAVE_DISABLE | MASTER_EN | TX_EMPTY_CTL; + writel(val, priv->base + I2C_CON); + } + + rtk_i2c_int_disable(priv, ~0); + + writel(1, priv->base + I2C_ENABLE); + + readl(priv->base + I2C_CLR_INT); + rtk_i2c_int_enable(priv, INT_DEFAULT_MASK); + + if (!wait_for_completion_timeout(&priv->msg_done, adap->timeout)) { + priv->msg_err = -ETIMEDOUT; + rtk_i2c_init(priv); + goto fail; + } + + if (priv->msg_w_idx != priv->msgs_num) { + priv->msg_err = -EPROTO; + rtk_i2c_init(priv); + goto fail; + } + + writel(0, priv->base + I2C_ENABLE); + + if (priv->msg_err) + goto fail; + + return num; +fail: + if (priv->msg_err == -EPROTO) + rtk_i2c_handle_tx_abort(priv); + + if (priv->adap.bus_recovery_info) + i2c_recover_bus(&priv->adap); + +#ifdef MY_DEF_HERE + if (priv->abort_source & TX_ABRT_NOACK) + dev_dbg(priv->dev, "transmit error %d 0x%x 0x%x 0x%x with %x\n", + priv->msg_err, addr, priv->msg_w_idx, num, priv->abort_source); + else +#endif /* MY_DEF_HERE */ + dev_err(priv->dev, "transmit error %d 0x%x 0x%x 0x%x\n", + priv->msg_err, addr, priv->msg_w_idx, num); + + return priv->msg_err; +} + +static unsigned int rtk_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_SLAVE; +} + +#if IS_ENABLED(CONFIG_I2C_SLAVE) +static void rtk_i2c_slave_irq(struct rtk_i2c_dev *priv) +{ + unsigned int status; + unsigned int raw_status; + unsigned char val, activity; + + status = readl(priv->base + I2C_INTR_STAT); + raw_status = readl(priv->base + I2C_RAW_INTR_STAT); + activity = (readl(priv->base + I2C_IC_STATUS) & SLV_ACTIVITY) >> 6; + + if ((status & RX_FULL) && (status & STOP_DET)) + i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &val); + + if ((status & RD_REQ) && activity) { + if (status & RX_FULL) { + val = readl(priv->base + I2C_DATA_CMD); + if (!i2c_slave_event(priv->slave, + I2C_SLAVE_WRITE_RECEIVED, &val)) + dev_dbg(priv->dev, "Byte %x acked!\n", val); + readl(priv->base + I2C_CLR_RD_REQ); + status = rtk_i2c_clear_intrbits_slave(priv); + } else { + readl(priv->base + I2C_CLR_RD_REQ); + readl(priv->base + I2C_CLR_RX_UNDER); + status = rtk_i2c_clear_intrbits_slave(priv); + } + if (!i2c_slave_event(priv->slave, + I2C_SLAVE_READ_REQUESTED, &val)) + writel(val, priv->base + I2C_DATA_CMD); + } + + if (status & RX_DONE) { + if (!i2c_slave_event(priv->slave, + I2C_SLAVE_READ_PROCESSED, &val)) + readl(priv->base + I2C_CLR_RD_REQ); + + i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &val); + status = rtk_i2c_clear_intrbits_slave(priv); + return; + } + + if (status & RX_FULL) { + val = readl(priv->base + I2C_DATA_CMD); + if (!i2c_slave_event(priv->slave, + I2C_SLAVE_WRITE_RECEIVED, &val)) + dev_dbg(priv->dev, "Byte 0x%x acked!\n", val); + } else { + i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &val); + status = rtk_i2c_clear_intrbits_slave(priv); + } +} + +static int rtk_i2c_slave_init(struct rtk_i2c_dev *priv) +{ + struct i2c_client *slave = priv->slave; + unsigned int val = 0; + + writel(0, priv->base + I2C_ENABLE); + rtk_i2c_int_disable(priv, ~0); + + if (slave->flags & I2C_CLIENT_TEN) { + val = slave->addr & 0x3FF; + writel(val, priv->base + I2C_SAR); + val = readl(priv->base + I2C_CON) | + (TEN_BIT_SLAVE & ~(SLAVE_DISABLE | MASTER_EN)); + writel(val, priv->base + I2C_CON); + } else { + val = slave->addr & 0x7F; + writel(val, priv->base + I2C_SAR); + val = readl(priv->base + I2C_CON) & + ~(SLAVE_DISABLE | MASTER_EN | + TEN_BIT_SLAVE | TEN_BIT_MASTER); + writel(val, priv->base + I2C_CON); + } + val = STOP_DET | RD_REQ | RX_FULL | RX_DONE; + + writel(0, priv->base + I2C_TX_TL); + writel(0, priv->base + I2C_RX_TL); + + rtk_i2c_int_enable(priv, val); + + writel(1, priv->base + I2C_ENABLE); + return 0; +} + +static int rtk_i2c_reg_slave(struct i2c_client *slave) +{ + struct rtk_i2c_dev *priv = i2c_get_adapdata(slave->adapter); + + if (priv->slave) + return -EBUSY; + + priv->slave = slave; + rtk_i2c_slave_init(priv); + + return 0; +} + +static int rtk_i2c_unreg_slave(struct i2c_client *slave) +{ + struct rtk_i2c_dev *priv = i2c_get_adapdata(slave->adapter); + + rtk_i2c_init(priv); + priv->slave = NULL; + + return 0; +} + +#endif + +static const struct i2c_algorithm rtk_i2c_algo = { + .master_xfer = rtk_i2c_xfer, + .functionality = rtk_i2c_func, +#if IS_ENABLED(CONFIG_I2C_SLAVE) + .reg_slave = rtk_i2c_reg_slave, + .unreg_slave = rtk_i2c_unreg_slave, +#endif +}; + +static irqreturn_t rtk_i2c_irq(int this_irq, void *dev_id) +{ + struct rtk_i2c_dev *priv = dev_id; + struct i2c_adapter *adap = &priv->adap; + unsigned int status, enabled; + + enabled = readl(priv->base + I2C_ENABLE); + status = readl(priv->base + I2C_INTR_STAT); + + if (!enabled || !(status & ~ACTIVITY)) { + dev_err(priv->dev, "IRQ_NONE: 0x%x, 0x%x\n", enabled, status); + return IRQ_NONE; + } + +#if IS_ENABLED(CONFIG_I2C_SLAVE) + if (!(readl(priv->base + I2C_CON) & SLAVE_DISABLE)) { + rtk_i2c_slave_irq(priv); + goto clear; + } +#endif + status = rtk_i2c_clear_intrbits(priv); + + if (status & TX_ABRT) { + priv->msg_err = -EPROTO; + priv->status = STATUS_IDLE; + rtk_i2c_int_disable(priv, ~0); + goto out; + } + if (status & RX_FULL) + rtk_i2c_xfer_read(priv); + + if (status & TX_EMPTY) + rtk_i2c_xfer_msg(priv); + +out: + if ((status & (TX_ABRT | STOP_DET)) || priv->msg_err) + complete(&priv->msg_done); +#if IS_ENABLED(CONFIG_I2C_SLAVE) +clear: +#endif + writel((1 << ISR_CLR_BIT[adap->nr]), priv->irqbase); + + return IRQ_HANDLED; +} + +static void rtk_i2c_prepare_recovery(struct i2c_adapter *adap) +{ + struct rtk_i2c_dev *priv = container_of(adap, struct rtk_i2c_dev, adap); + + dev_info(priv->dev, "%s\n", __func__); + pinctrl_select_state(priv->pinctrl, priv->pinctrl_gpio); +} + +static void rtk_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ + struct rtk_i2c_dev *priv = container_of(adap, struct rtk_i2c_dev, adap); + + dev_info(priv->dev, "%s\n", __func__); + pinctrl_select_state(priv->pinctrl, priv->pinctrl_default); +} + +static int rtk_i2c_init_recovery_info(struct rtk_i2c_dev *priv) +{ + struct device *dev = priv->dev; + struct i2c_bus_recovery_info *bri = &priv->bri; + + priv->pinctrl = devm_pinctrl_get(dev); + if (!priv->pinctrl || IS_ERR(priv->pinctrl)) { + dev_err(dev, "can't get pinctrl, bus recovery not support\n"); + return PTR_ERR(priv->pinctrl); + } + + priv->pinctrl_default = pinctrl_lookup_state(priv->pinctrl, "default"); + priv->pinctrl_gpio = pinctrl_lookup_state(priv->pinctrl, "gpio_mode"); + if (IS_ERR(priv->pinctrl_default) || IS_ERR(priv->pinctrl_gpio)) { + dev_err(dev, "can't get pin state, bus recovery not support\n"); + return -1; + } + + bri->scl_gpiod = devm_gpiod_get_optional(dev, "scl", GPIOD_OUT_HIGH); + if (IS_ERR_OR_NULL(bri->scl_gpiod)) + return PTR_ERR_OR_ZERO(bri->scl_gpiod); + + bri->sda_gpiod = devm_gpiod_get_optional(dev, "sda", GPIOD_OUT_HIGH); + if (IS_ERR_OR_NULL(bri->scl_gpiod)) + return PTR_ERR_OR_ZERO(bri->sda_gpiod); + + bri->prepare_recovery = rtk_i2c_prepare_recovery; + bri->unprepare_recovery = rtk_i2c_unprepare_recovery; + bri->recover_bus = i2c_generic_scl_recovery; + priv->adap.bus_recovery_info = bri; + + return 0; +} + +static int rtk_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_i2c_dev *priv = NULL; + struct resource *res; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + priv->chip_id = get_rtd_chip_id(); + priv->quirks = of_device_get_match_data(dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->irqbase = of_iomap(np, 1); + if (!priv->irqbase) + return PTR_ERR(priv->irqbase); + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(dev, "missing interrupt resource\n"); + return priv->irq; + } + + priv->clk = of_clk_get(np, 0); + if (IS_ERR(priv->clk)) { + dev_err(dev, "missing clock\n"); + return PTR_ERR(priv->clk); + } + clk_prepare_enable(priv->clk); + + ret = device_reset(&pdev->dev); + if (ret) + dev_warn(dev, "fail to reset device\n"); + + i2c_parse_fw_timings(dev, &priv->timings, 1); + + priv->adap.timeout = msecs_to_jiffies(250); + priv->adap.retries = 5; + priv->adap.dev.parent = dev; + priv->adap.algo = &rtk_i2c_algo; + priv->adap.owner = THIS_MODULE; + priv->adap.dev.of_node = np; + priv->adap.nr = of_alias_get_id(np, "i2c"); + strlcpy(priv->adap.name, "realtek i2c adapter", sizeof(priv->adap.name)); + + rtk_i2c_init_recovery_info(priv); + + platform_set_drvdata(pdev, priv); + i2c_set_adapdata(&priv->adap, priv); + + init_completion(&priv->msg_done); + + /* rtk i2c initial */ + ret = rtk_i2c_init(priv); + if (ret) + goto probe_fail; + + ret = devm_request_irq(dev, priv->irq, rtk_i2c_irq, IRQF_SHARED, + dev_name(dev), priv); + if (ret) + goto probe_fail; + + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret) + goto probe_fail; + + return 0; + +probe_fail: + clk_disable_unprepare(priv->clk); + return ret; +} + +static int rtk_i2c_remove(struct platform_device *pdev) +{ + struct rtk_i2c_dev *priv = platform_get_drvdata(pdev); + + i2c_del_adapter(&priv->adap); + rtk_i2c_disable(priv); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int rtk_i2c_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_i2c_dev *priv = platform_get_drvdata(pdev); + + dev_info(dev, "Enter %s\n", __func__); + + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + rtk_i2c_disable(priv); + clk_disable_unprepare(priv->clk); + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_i2c_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_i2c_dev *priv = platform_get_drvdata(pdev); + + dev_info(dev, "Enter %s\n", __func__); + + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + clk_prepare_enable(priv->clk); + rtk_i2c_init(priv); +#if IS_ENABLED(CONFIG_I2C_SLAVE) + if (priv->slave) + rtk_i2c_slave_init(priv); +#endif + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops rtk_i2c_pm_ops = { + .suspend_noirq = rtk_i2c_suspend, + .resume_noirq = rtk_i2c_resume, +}; + +#define RTK_I2C_PM_OPS (&rtk_i2c_pm_ops) +#else +#define RTK_I2C_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static const struct rtk_i2c_quirks rtk_i2c_hs_quirks = { + .high_speed = 1, +}; + +/* Match table for of_platform binding */ +static const struct of_device_id rtk_i2c_of_match[] = { + { .compatible = "realtek,i2c", }, + { .compatible = "realtek,highspeed-i2c", .data = &rtk_i2c_hs_quirks, }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtk_i2c_of_match); + +static struct platform_driver rtk_i2c_driver = { + .probe = rtk_i2c_probe, + .remove = rtk_i2c_remove, + .driver = { + .name = "realtek-i2c", + .owner = THIS_MODULE, + .pm = RTK_I2C_PM_OPS, + .of_match_table = rtk_i2c_of_match, + }, +}; + +/* I2C may be needed to bring up other drivers */ +static int __init rtk_i2c_init_driver(void) +{ + return platform_driver_register(&rtk_i2c_driver); +} +rootfs_initcall(rtk_i2c_init_driver); + +static void __exit rtk_i2c_exit_driver(void) +{ + platform_driver_unregister(&rtk_i2c_driver); +} +module_exit(rtk_i2c_exit_driver); + +MODULE_AUTHOR("Simon Hsu "); +MODULE_DESCRIPTION("Realtek I2C bus driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-rtk.h b/drivers/i2c/busses/i2c-rtk.h new file mode 100644 index 000000000000..04e908481c6a --- /dev/null +++ b/drivers/i2c/busses/i2c-rtk.h @@ -0,0 +1,156 @@ +/* + * Realtek I2C driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + */ + +#ifndef __I2C_RTK_H__ +#define __I2C_RTK_H__ + +#include "platform.h" +#include "../algos/i2c-algo-phoenix.h" + +#define MODLE_NAME "rtk_i2c" +#define I2C_PHY_CNT 7 +#define VERSION "2.2" + + +#define SET_I2C_CFG(phy_id, port_id) ((0x80000000) | ((phy_id)<<8) \ + | (port_id)) +#define SET_G2C_CFG(sda, scl) ((0xC0000000) | ((sda)<<8) \ + | (scl)) +#define IS_I2C_CFG(cfg) ((cfg & 0xFFFF0000) == 0x80000000) +#define IS_G2C_CFG(cfg) ((cfg & 0xFFFF0000) == 0xC0000000) +#define IS_VALID_CFG(cfg) (IS_G2C_MODE(cfg) || \ + IS_I2C_MODE(cfg)) +#define GET_I2C_PHY(cfg) ((cfg>>8) & 0xFF) +#define GET_I2C_PORT(cfg) (cfg & 0xFF) +#define GET_G2C_SDA(cfg) ((cfg>>8) & 0xFF) +#define GET_G2C_SCL(cfg) (cfg & 0xFF) + + +#define I2C_CON 0x0000 +#define I2C_TAR 0x0004 +#define I2C_SAR 0x0008 +#define I2C_HS_MADDR 0x000c +#define I2C_DATA_CMD 0x0010 +#define I2C_SS_SCL_HCNT 0x0014 +#define I2C_SS_SCL_LCNT 0x0018 +#define I2C_FS_SCL_HCNT 0x001c +#define I2C_FS_SCL_LCNT 0x0020 +#define I2C_HS_SCL_HCNT 0x0024 +#define I2C_HS_SCL_LCNT 0x0028 +#define I2C_INTR_STAT 0x002c +#define I2C_INTR_MASK 0x0030 +#define I2C_RAW_INTR_STAT 0x0034 +#define I2C_RX_TL 0x0038 +#define I2C_TX_TL 0x003c +#define I2C_CLR_INTR 0x0040 +#define I2C_CLR_RX_UNDER 0x0044 +#define I2C_CLR_RX_OVER 0x0048 +#define I2C_CLR_TX_OVER 0x004c +#define I2C_CLR_RD_REQ 0x0050 +#define I2C_CLR_TX_ABRT 0x0054 +#define I2C_CLR_RX_DONE 0x0058 +#define I2C_CLR_ACTIVITY 0x005c +#define I2C_CLR_STOP_DET 0x0060 +#define I2C_CLR_START_DET 0x0064 +#define I2C_CLR_GEN_CALL 0x0068 +#define I2C_ENABLE 0x006c +#define I2C_STATUS 0x0070 +#define I2C_TXFLR 0x0074 +#define I2C_RXFLR 0x0078 +#define I2C_SDA_HOLD 0x007c +#define I2C_TX_ABRT_SOURCE 0x0080 +#define I2C_SLV_DATA_NACK_ONLY 0x0084 +#define I2C_DMA_CR 0x0088 +#define I2C_DMA_TDLR 0x008c +#define I2C_DMA_RDLR 0x0090 +#define I2C_SDA_SETUP 0x0094 +#define I2C_ACK_GENERAL_CALL 0x0098 +#define I2C_ENABLE_STATUS 0x009c +#define I2C_COMP_PARAM_1 0x00f4 +#define I2C_COMP_VERSION 0x00f8 +#define I2C_COMP_TYPE 0x00fc + + +#ifdef CONFIG_ARCH_RTD119X +#define MISC_ISR_I2C1 (0x00000001 << 4) +#define MISC_I2C1_SDA_DEL 0x0088 +#else +#define ISO_ISR_I2C1 (0x00000001 << 11) +#define ISO_I2C1_SDA_DEL 0x0080 +#endif + +#define ISO_ISR_I2C0 (0x00000001 << 8) +#define ISO_ISR_I2C6 (0x00000001 << 10) + +#define MIS_ISR_I2C2 (0x00000001 << 26) +#define MIS_ISR_I2C3 (0x00000001 << 23) +#define MIS_ISR_I2C4 (0x00000001 << 15) +#define MIS_ISR_I2C5 (0x00000001 << 14) + +#define MIS_I2C2_SDA_DEL 0x008C +#define MIS_I2C3_SDA_DEL 0x0090 +#define MIS_I2C4_SDA_DEL 0x0094 +#define MIS_I2C5_SDA_DEL 0x0098 + +#define ISO_I2C0_SDA_DEL 0x0084 +#define ISO_I2C6_SDA_DEL 0x00c0 + + + +/*IC_CON*/ +#define IC_SLAVE_DISABLE 0x0040 +#define IC_RESTART_EN 0x0020 +#define IC_10BITADDR_MASTER 0x0010 +#define IC_10BITADDR_SLAVE 0x0008 +#define IC_MASTER_MODE 0x0001 + +#define IC_SPEED 0x0006 +#define SPEED_SS 0x0002 +#define SPEED_FS 0x0004 +#define SPEED_HS 0x0006 + +/*ID_DATA*/ +#define READ_CMD 0x0100 + +/*INT*/ +#define GEN_CALL_BIT 0x800 +#define START_DET_BIT 0x400 +#define STOP_DET_BIT 0x200 +#define ACTIVITY_BIT 0x100 +#define RX_DONE_BIT 0x080 +#define TX_ABRT_BIT 0x040 +#define RD_REQ_BIT 0x020 +#define TX_EMPTY_BIT 0x010 +#define TX_OVER_BIT 0x008 +#define RX_FULL_BIT 0x004 +#define RX_OVER_BIT 0x002 +#define RX_UNDER_BIT 0x001 + +/*STATUS*/ +#define ST_RFF_BIT 0x10 +#define ST_RFNE_BIT 0x08 +#define ST_TFE_BIT 0x04 +#define ST_TFNF_BIT 0x02 +#define ST_ACTIVITY_BIT 0x01 + +/*DELAY*/ +#define I2C_SDA_DEL_MASK (0x1FF) +#define I2C_SDA_DEL_EN (0x00000001<<8) +#define I2C_SDA_DEL_SEL(x) ((x & 0x1F)) /* Delay time: (unit 518ns)*/ +#define SDA_DEL_518NS 1 +#define SDA_DEL_1036NS 2 +#define SDA_DEL_1554NS 3 +#define SDA_DEL_2072NS 4 +#define SDA_DEL_2590NS 5 +#define I2C0_SDA_DEL_520NS 4 + + +#endif /*__I2C_RTK_H__*/ diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index bdce6d3e5327..f6bb619c925f 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Linux I2C core @@ -40,6 +43,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "i2c-core.h" @@ -106,6 +112,12 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (acpi_driver_match_device(dev, drv)) return 1; +#ifdef MY_ABC_HERE + if (of_root && syno_of_i2c_driver_match_device(dev, drv)) { + return 1; + } +#endif /* MY_ABC_HERE */ + driver = to_i2c_driver(drv); /* Finally an I2C match */ @@ -1468,6 +1480,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap) /* create pre-declared device nodes */ of_i2c_register_devices(adap); +#ifdef MY_ABC_HERE + syno_of_i2c_register_devices(adap); +#endif /* MY_ABC_HERE */ i2c_acpi_install_space_handler(adap); i2c_acpi_register_devices(adap); @@ -1531,6 +1546,11 @@ int i2c_add_adapter(struct i2c_adapter *adapter) struct device *dev = &adapter->dev; int id; +#ifdef MY_ABC_HERE + struct device_node *pI2CNode = NULL; + int index = 0; +#endif /* MY_ABC_HERE */ + if (dev->of_node) { id = of_alias_get_id(dev->of_node, "i2c"); if (id >= 0) { @@ -1539,6 +1559,16 @@ int i2c_add_adapter(struct i2c_adapter *adapter) } } +#ifdef MY_ABC_HERE + if (adapter->nr == -1) { + /* -1 means dynamically assign bus id */ + if (NULL != (pI2CNode = syno_of_i2c_bus_match(dev, &index))) { + adapter->nr = index; + return __i2c_add_numbered_adapter(adapter); + } + } +#endif /* MY_ABC_HERE */ + mutex_lock(&core_lock); id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 3ed74aa4b44b..55c9b87a7c7f 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Linux I2C core OF support code @@ -16,6 +19,11 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#include +#include +#endif /* MY_ABC_HERE */ #include "i2c-core.h" @@ -62,6 +70,49 @@ int of_i2c_get_board_info(struct device *dev, struct device_node *node, } EXPORT_SYMBOL_GPL(of_i2c_get_board_info); +#ifdef MY_ABC_HERE +void syno_of_i2c_register_device(struct i2c_adapter *adap, struct device_node *node) +{ + struct i2c_board_info info = {}; + const char *i2c_address = NULL; + const char *i2c_driver_name = NULL; + unsigned short val = 0; + + + if ( 0 == of_property_read_string(node, DT_I2C_DEVICE_NAME, &i2c_driver_name) && + 0 == of_property_read_string(node, DT_I2C_ADDRESS, &i2c_address)) { + if(0 == kstrtoul(i2c_address, 16, (unsigned long*) &val)) { + info.addr = val; + info.of_node = node; + strlcpy(info.type,i2c_driver_name,sizeof(info.type)); + + if (!i2c_new_client_device(adap, &info)) { + pr_err("fail to add I2C device %s at 0x%d", info.type, info.addr); + return; + } + } + } +} + +void syno_of_i2c_register_devices(struct i2c_adapter *adap) +{ + struct device_node *pI2CNode = NULL; + struct device_node *pI2CDevNode = NULL; + + if (NULL == of_root || NULL == adap){ + return; + } + + pI2CNode = syno_of_i2c_adapter_match(adap); + + if (NULL != pI2CNode) { + for_each_child_of_node(pI2CNode, pI2CDevNode) { + syno_of_i2c_register_device(adap, pI2CDevNode); + } + } +} +#endif /* MY_ABC_HERE */ + static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, struct device_node *node) { diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 8ce261167a2d..290ca048f5d4 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * i2c-core.h - interfaces internal to the I2C framework @@ -82,6 +85,9 @@ static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { #ifdef CONFIG_OF void of_i2c_register_devices(struct i2c_adapter *adap); +#ifdef MY_ABC_HERE +void syno_of_i2c_register_devices(struct i2c_adapter *adap); +#endif /* MY_ABC_HERE */ #else static inline void of_i2c_register_devices(struct i2c_adapter *adap) { } #endif diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index e39b679126a2..75556a66a4c5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -876,6 +876,16 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +if SYNO_LSP_RTD1619B +config RTK_LSADC0 + tristate "Realtek LSADC driver" + depends on ARCH_REALTEK + default n + help + Say Y, if you want to enable LSADC feature on Realtek RTD129x, + RTD139x, RTD16xx, RTD13xx, or RTD16xxb platform. +endif # SYNO_LSP_RTD1619B + config SC27XX_ADC tristate "Spreadtrum SC27xx series PMICs ADC" depends on MFD_SC27XX_PMIC || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 90f94ada7b30..1b5f67591437 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -81,6 +81,9 @@ obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTK_LSADC0) += rtk_lsadc0.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o obj-$(CONFIG_STX104) += stx104.o diff --git a/drivers/iio/adc/rtk_lsadc0.c b/drivers/iio/adc/rtk_lsadc0.c new file mode 100644 index 000000000000..a8fa4e80a19a --- /dev/null +++ b/drivers/iio/adc/rtk_lsadc0.c @@ -0,0 +1,1058 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Realtek Low Speed ADC driver + * + * Copyright (C) 2020 Realtek Semiconductor Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "rtk_lsadc0.h" + +#define SA_SHIRQ IRQF_SHARED +#define LSADC_READL(reg) readl((void __iomem *)(reg + (uintptr_t)(st->lsadc_addr))) +#define LSADC_WRITEL(val, reg) writel(val, (void __iomem *)(reg + (uintptr_t)(st->lsadc_addr))) + +struct rtk_lsadc_pad_info { + uint activate; + uint ctrl_mode; + uint pad_sw; + uint threshold; + uint vref_sel; + uint adc_val0; + uint adc_val_baseline; + uint range_evt_cfg; +}; + +struct rtk_lsadc_info { + struct rtk_lsadc_pad_info pad[2]; + uint debounce_cnt; + uint irq; + uint clk_gating_en; +}; + +struct rtk_lsadc_state { + struct device *dev; + struct rtk_lsadc_info lsadc[1]; + uint crt_lsadc_pg_val; + void __iomem *crt_lsadc_pg_addr; + void __iomem *lsadc_addr; + struct clk *clk; + uint rising_evt_cfg; + uint falling_evt_cfg; + struct mutex lock; +}; + +static const struct iio_event_spec rtk_lsadc_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const int rtk_mod_map[] = { + [IIO_MOD_X] = 0, + [IIO_MOD_Y] = 1, + [IIO_MOD_Z] = 2, + [IIO_MOD_LIGHT_RED] = 3, + [IIO_MOD_LIGHT_GREEN] = 4, + [IIO_MOD_LIGHT_BLUE] = 5, +}; + +static const int rtk_level_map[] = { + IIO_MOD_X, IIO_MOD_Y, IIO_MOD_Z, + IIO_MOD_LIGHT_RED, IIO_MOD_LIGHT_GREEN, IIO_MOD_LIGHT_BLUE +}; + +static irqreturn_t lsadc0_interrupt_pad(int irq, void *data) +{ + struct iio_dev *idev = data; + struct rtk_lsadc_state *st = iio_priv(idev); + uint status_reg; + uint pad0_reg, pad1_reg; + uint pad0_int, pad1_int; + uint new_adc_val = 0; + uint reg; + uint addr; + int i, j; + + for (i = 0; i < 2; i++) { + addr = (i ? LSADC0_PAD1_LEVEL_SET0_ADDR : LSADC0_PAD0_LEVEL_SET0_ADDR); + for (j = 0; j < LSADC0_PAD_LEVEL_SET_NUMBER; j++) { + if (!(st->lsadc[0].pad[i].range_evt_cfg & BIT(j))) + continue; + reg = LSADC_READL(addr + 4 * j); + dev_info(st->dev, "[LSADC] pad%d level set%d reg = 0x%0x\n", i, j, reg); + if ((reg & LSADC0_LEVEL_BLK_EN_MASK) && + (reg & LSADC0_LEVEL_INT_EN_MASK) && + (reg & LSADC0_LEVEL_INT_PEND_MASK)) { + st->lsadc[0].pad[i].range_evt_cfg &= ~BIT(j); + dev_info(st->dev, "[LSADC] pad%d level set%d INT!\n", i, j); + iio_push_event(idev, + IIO_MOD_EVENT_CODE(IIO_VOLTAGE, + i, + rtk_level_map[j], + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(idev)); + } + } + } + status_reg = LSADC_READL(LSADC0_STATUS_ADDR); + + pad0_int = LSADC0_STATUS_PAD0_STATUS_MASK & status_reg; + pad1_int = LSADC0_STATUS_PAD1_STATUS_MASK & status_reg; + + pad0_reg = LSADC_READL(LSADC0_PAD0_ADDR); + pad1_reg = LSADC_READL(LSADC0_PAD1_ADDR); + dev_info(st->dev, "[LSADC] %s: pad0_adc=0x%0x, pad1_adc=0x%0x\n", + __func__, st->lsadc[0].pad[0].adc_val0, st->lsadc[0].pad[1].adc_val0); + + if (pad0_int) { + new_adc_val = pad0_reg & LSADC0_PAD_ADC_VAL_MASK; + dev_info(st->dev, "[LSADC] pad0 interrupt! status_reg=0x%x , adc_val=> from [%d] to [%d]\n", + status_reg, st->lsadc[0].pad[0].adc_val0, new_adc_val); + if (st->lsadc[0].pad[0].adc_val0 > new_adc_val) { + dev_info(st->dev, "[LSADC] pad0 adc became smaller!\n\n"); + if (st->falling_evt_cfg & BIT(0)) + iio_push_event(idev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(idev)); + } else { + dev_info(st->dev, "[LSADC] pad0 adc became bigger!\n\n"); + + /* set adc_val0 to base line */ + pad0_reg = (pad0_reg & ~LSADC0_PAD_ADC_VAL_MASK) | + st->lsadc[0].pad[0].adc_val_baseline; + LSADC_WRITEL(pad0_reg, LSADC0_PAD0_ADDR); + + if (st->rising_evt_cfg & BIT(0)) + iio_push_event(idev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(idev)); + } + st->lsadc[0].pad[0].adc_val0 = new_adc_val; + } + + if (pad1_int) { + new_adc_val = pad1_reg & LSADC0_PAD_ADC_VAL_MASK; + dev_info(st->dev, "[LSADC] pad1 interrupt! status_reg=0x%x , adc_val=> from [%d] to [%d]\n", + status_reg, st->lsadc[0].pad[1].adc_val0, new_adc_val); + if (st->lsadc[0].pad[1].adc_val0 > new_adc_val) { + dev_info(st->dev, "[LSADC] pad1 adc became smaller!\n\n"); + + if (st->falling_evt_cfg & BIT(1)) + iio_push_event(idev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(idev)); + } else { + dev_info(st->dev, "[LSADC] pad1 adc became bigger!\n\n"); + + /* set adc_val0 to base line */ + pad1_reg = (pad1_reg & ~LSADC0_PAD_ADC_VAL_MASK) | + st->lsadc[0].pad[1].adc_val_baseline; + LSADC_WRITEL(pad1_reg, LSADC0_PAD1_ADDR); + + if (st->rising_evt_cfg & BIT(1)) + iio_push_event(idev, + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, + 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(idev)); + } + st->lsadc[0].pad[1].adc_val0 = new_adc_val; + } + + /* reset INT flag */ + status_reg |= LSADC0_STATUS_PAD0_STATUS_MASK | LSADC0_STATUS_PAD1_STATUS_MASK; + LSADC_WRITEL(status_reg, LSADC0_STATUS_ADDR); + + return IRQ_HANDLED; +} + +static ssize_t in_info_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iio_dev *idev = platform_get_drvdata(pdev); + struct rtk_lsadc_state *st = iio_priv(idev); + uint ctrl_reg; + uint analog_ctrl_reg; + uint pad0_reg; + uint pad1_reg; + uint lsadc_status_reg; + uint pad0_set[LSADC0_PAD_LEVEL_SET_NUMBER]; + uint pad1_set[LSADC0_PAD_LEVEL_SET_NUMBER]; + int i = 0; + int len = 0; + + mutex_lock(&st->lock); + ctrl_reg = LSADC_READL(LSADC0_CTRL_ADDR); + lsadc_status_reg = LSADC_READL(LSADC0_STATUS_ADDR); + analog_ctrl_reg = LSADC_READL(LSADC0_ANALOG_CTRL_ADDR); + + if ((ctrl_reg & LSADC0_CTRL_ENABLE_MASK) == 0) { + ctrl_reg = ctrl_reg | LSADC0_CTRL_ENABLE_MASK; + LSADC_WRITEL(ctrl_reg, LSADC0_CTRL_ADDR); + dev_info(dev, "[LSADC] write ctrl_enable, ctrl_reg=0x%x\n", + ctrl_reg); + } + + pad0_reg = LSADC_READL(LSADC0_PAD0_ADDR); + pad1_reg = LSADC_READL(LSADC0_PAD1_ADDR); + + st->lsadc[0].pad[0].adc_val0 = pad0_reg & LSADC0_PAD_ADC_VAL_MASK; + st->lsadc[0].pad[1].adc_val0 = pad1_reg & LSADC0_PAD_ADC_VAL_MASK; + + len += scnprintf(buf + len, PAGE_SIZE - len, "%s --\n", __func__); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t ctrl_reg=0x%x\n", + ctrl_reg); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t lsadc_status_reg=0x%x\n", + lsadc_status_reg); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t analog_ctrl_reg=0x%x\n", + analog_ctrl_reg); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t pad0_reg=0x%x\n", + pad0_reg); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t pad1_reg=0x%x\n", + pad1_reg); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t pad0_adc=0x%x\n", + st->lsadc[0].pad[0].adc_val0); + len += scnprintf(buf + len, PAGE_SIZE - len, "\t pad1_adc=0x%x\n", + st->lsadc[0].pad[1].adc_val0); + + len += scnprintf(buf + len, PAGE_SIZE - len, "info:\n"); + for (i = 0; i < LSADC0_PAD_LEVEL_SET_NUMBER; i++) { + pad0_set[i] = LSADC_READL(LSADC0_PAD0_LEVEL_SET0_ADDR + (i * 4)); + pad1_set[i] = LSADC_READL(LSADC0_PAD1_LEVEL_SET0_ADDR + (i * 4)); + len += scnprintf(buf + len, PAGE_SIZE - len, "set_idx[%d]: pad0_set=0x%0x, pad1_set=0x%0x\n", + i, pad0_set[i], pad1_set[i]); + } + mutex_unlock(&st->lock); + + return len; +} + +static IIO_DEVICE_ATTR_RO(in_info, 0); + +static struct attribute *rtk_attr_base[] = { + &iio_dev_attr_in_info.dev_attr.attr, + NULL +}; + +static const struct attribute_group rtk_group_base = { + .attrs = rtk_attr_base, +}; + +#define RTK_LSADC_CHAN(_idx, _data_reg_addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_idx), \ + .address = (_data_reg_addr), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_DEBOUNCE_COUNT), \ + .scan_index = (_idx), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 8, \ + .shift = 0, \ + }, \ + .event_spec = rtk_lsadc_event, \ + .num_event_specs = ARRAY_SIZE(rtk_lsadc_event), \ +} + +#define RTK_LSADC_CHAN2(_idx, _idx2, _data_reg_addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_idx), \ + .modified = 1, \ + .channel2 = (_idx2), \ + .address = (_data_reg_addr), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ + .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_DEBOUNCE_COUNT), \ + .scan_index = (_idx), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 8, \ + .shift = 0, \ + }, \ + .event_spec = rtk_lsadc_event, \ + .num_event_specs = ARRAY_SIZE(rtk_lsadc_event), \ +} + +static const struct iio_chan_spec rtk_lsadc_iio_channels[] = { + RTK_LSADC_CHAN(0, LSADC0_PAD0_ADDR), + RTK_LSADC_CHAN(1, LSADC0_PAD1_ADDR), + RTK_LSADC_CHAN2(0, IIO_MOD_X, LSADC0_PAD0_LEVEL_SET0_ADDR), + RTK_LSADC_CHAN2(0, IIO_MOD_Y, LSADC0_PAD0_LEVEL_SET1_ADDR), + RTK_LSADC_CHAN2(0, IIO_MOD_Z, LSADC0_PAD0_LEVEL_SET2_ADDR), + RTK_LSADC_CHAN2(0, IIO_MOD_LIGHT_RED, LSADC0_PAD0_LEVEL_SET3_ADDR), + RTK_LSADC_CHAN2(0, IIO_MOD_LIGHT_GREEN, LSADC0_PAD0_LEVEL_SET4_ADDR), + RTK_LSADC_CHAN2(0, IIO_MOD_LIGHT_BLUE, LSADC0_PAD0_LEVEL_SET5_ADDR), + RTK_LSADC_CHAN2(1, IIO_MOD_X, LSADC0_PAD1_LEVEL_SET0_ADDR), + RTK_LSADC_CHAN2(1, IIO_MOD_Y, LSADC0_PAD1_LEVEL_SET1_ADDR), + RTK_LSADC_CHAN2(1, IIO_MOD_Z, LSADC0_PAD1_LEVEL_SET2_ADDR), + RTK_LSADC_CHAN2(1, IIO_MOD_LIGHT_RED, LSADC0_PAD1_LEVEL_SET3_ADDR), + RTK_LSADC_CHAN2(1, IIO_MOD_LIGHT_GREEN, LSADC0_PAD1_LEVEL_SET4_ADDR), + RTK_LSADC_CHAN2(1, IIO_MOD_LIGHT_BLUE, LSADC0_PAD1_LEVEL_SET5_ADDR), +}; + +static int rtk_lsadc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + int ret = -EINVAL; + + mutex_lock(&st->lock); + switch (mask) { + case IIO_CHAN_INFO_RAW: + *val = st->lsadc[0].pad[chan->channel].adc_val0; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = MICROVOLT_HIGH; + *val2 = chan->scan_type.realbits; + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + case IIO_CHAN_INFO_ENABLE: + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + goto err_exit; + + *val = !!(LSADC_READL(chan->address) & LSADC0_LEVEL_BLK_EN_MASK); + ret = IIO_VAL_INT; + } else { + *val = st->lsadc[0].pad[chan->channel].activate; + ret = IIO_VAL_INT; + } + break; + case IIO_CHAN_INFO_DEBOUNCE_COUNT: + *val = st->lsadc[0].debounce_cnt; + ret = IIO_VAL_INT; + break; + default: + break; + } +err_exit: + mutex_unlock(&st->lock); + return ret; +} + +static int rtk_lsadc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + uint reg; + int activate = 0; + int addr = 0; + + switch (mask) { + case IIO_CHAN_INFO_ENABLE: + if (val) + activate = 1; + else + activate = 0; + + addr = chan->address; + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + return -EINVAL; + + mutex_lock(&st->lock); + reg = LSADC_READL(addr); + if ((reg & LSADC0_LEVEL_BLK_EN_MASK) != (activate << LSADC0_LEVEL_BLK_EN_SHIFT)) { + if (activate) + reg |= LSADC0_LEVEL_BLK_EN_MASK; + else + reg &= ~LSADC0_LEVEL_BLK_EN_MASK; + reg &= ~LSADC0_LEVEL_INT_PEND_MASK; + LSADC_WRITEL(reg, addr); + } + mutex_unlock(&st->lock); + } else { + if (st->lsadc[0].pad[chan->channel].activate == activate) + return 0; /* ignore the same setting */ + + st->lsadc[0].pad[chan->channel].activate = activate; + + mutex_lock(&st->lock); + reg = LSADC_READL(addr); + if (activate) + reg |= LSADC0_PAD_ACTIVE_MASK; + else + reg &= ~LSADC0_PAD_ACTIVE_MASK; + LSADC_WRITEL(reg, addr); + mutex_unlock(&st->lock); + } + return 0; + case IIO_CHAN_INFO_DEBOUNCE_COUNT: + if (val > 15) + val = 15; + if (val < 0) + val = 0; + + if (st->lsadc[0].debounce_cnt == val) + return 0; /* ignore the same setting */ + + st->lsadc[0].debounce_cnt = val; + addr = LSADC0_CTRL_ADDR; + + mutex_lock(&st->lock); + reg = LSADC_READL(addr); + reg &= ~LSADC0_CTRL_DEBOUNCE_MASK; + reg |= val << LSADC0_CTRL_DEBOUNCE_SHIFT; + LSADC_WRITEL(reg, addr); + mutex_unlock(&st->lock); + return 0; + case IIO_CHAN_INFO_SCALE: + case IIO_CHAN_INFO_RAW: + return -EPERM; + default: + return -EINVAL; + } +} + +int rtk_lsadc_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + uint reg; + + switch (dir) { + case IIO_EV_DIR_RISING: + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + return -EINVAL; + + mutex_lock(&st->lock); + reg = LSADC_READL(chan->address); + mutex_unlock(&st->lock); + return !!(reg & LSADC0_LEVEL_INT_EN_MASK); + } else { + return !!(st->rising_evt_cfg & BIT(chan->channel)); + } + case IIO_EV_DIR_FALLING: + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + return -EINVAL; + + mutex_lock(&st->lock); + reg = LSADC_READL(chan->address); + mutex_unlock(&st->lock); + return !!(reg & LSADC0_LEVEL_INT_PEND_MASK); + } else { + return !!(st->falling_evt_cfg & BIT(chan->channel)); + } + default: + return -EINVAL; + } + + return 0; +} + +int rtk_lsadc_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + uint reg; + uint blk_en; + int ret = -EINVAL; + + mutex_lock(&st->lock); + switch (dir) { + case IIO_EV_DIR_RISING: + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + goto err_exit; + + reg = LSADC_READL(chan->address); + if (state) { + reg |= LSADC0_LEVEL_INT_EN_MASK; + st->lsadc[0].pad[chan->channel].range_evt_cfg |= BIT(rtk_mod_map[chan->channel2]); + } else { + reg &= ~LSADC0_LEVEL_INT_EN_MASK; + } + reg &= ~LSADC0_LEVEL_INT_PEND_MASK; + LSADC_WRITEL(reg, chan->address); + } else { + if (state) + st->rising_evt_cfg |= BIT(chan->channel); + else + st->rising_evt_cfg &= ~BIT(chan->channel); + } + ret = 0; + break; + case IIO_EV_DIR_FALLING: + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + goto err_exit; + + /* disable blk_en */ + reg = LSADC_READL(chan->address); + blk_en = reg & LSADC0_LEVEL_BLK_EN_MASK; + reg &= ~LSADC0_LEVEL_BLK_EN_MASK; + + if (state) { + reg |= LSADC0_LEVEL_INT_PEND_MASK; + st->lsadc[0].pad[chan->channel].range_evt_cfg |= BIT(rtk_mod_map[chan->channel2]); + } else { + reg &= ~LSADC0_LEVEL_INT_PEND_MASK; + } + LSADC_WRITEL(reg, chan->address); + + /* restore blk_en */ + if (blk_en) { + reg |= blk_en; + reg &= ~LSADC0_LEVEL_INT_PEND_MASK; + LSADC_WRITEL(reg, chan->address); + } + /* reset pad INT status */ + reg = LSADC_READL(LSADC0_STATUS_ADDR); + reg |= LSADC0_STATUS_PAD0_STATUS_MASK | LSADC0_STATUS_PAD1_STATUS_MASK; + LSADC_WRITEL(reg, LSADC0_STATUS_ADDR); + } else { + if (state) + st->falling_evt_cfg |= BIT(chan->channel); + else + st->falling_evt_cfg &= ~BIT(chan->channel); + } + ret = 0; + break; + default: + dev_err(st->dev, "unsupported dir %d\n", dir); + } + +err_exit: + mutex_unlock(&st->lock); + + return ret; +} + +int rtk_lsadc_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + uint reg; + + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + return -EINVAL; + + mutex_lock(&st->lock); + reg = LSADC_READL(chan->address); + mutex_unlock(&st->lock); + + switch (dir) { + case IIO_EV_DIR_RISING: + *val = (reg & LSADC0_LEVEL_TOP_BOUND_MASK) >> LSADC0_LEVEL_TOP_BOUND_SHIFT; + break; + case IIO_EV_DIR_FALLING: + *val = (reg & LSADC0_LEVEL_LOW_BOUND_MASK) >> LSADC0_LEVEL_LOW_BOUND_SHIFT; + break; + default: + return -EINVAL; + } + } else { + if (chan->channel > 1) + return -EINVAL; + + mutex_lock(&st->lock); + reg = LSADC_READL(chan->address); + mutex_unlock(&st->lock); + *val = (reg & LSADC0_PAD_THRED_MASK) >> LSADC0_PAD_THRED_SHIFT; + } + + return IIO_VAL_INT; +} + +int rtk_lsadc_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + uint reg = 0; + uint old_thresh = 0; + uint max_thresh; + + max_thresh = GENMASK(chan->scan_type.realbits - 1, 0); + if (val < 0 || val > max_thresh) { + dev_info(st->dev, "channel %d: val (%d) out of range (0~%u)\n", + chan->channel, val, max_thresh); + return -EINVAL; + } + + + if (chan->modified) { + if (chan->channel > 1 || rtk_mod_map[chan->channel2] >= LSADC0_PAD_LEVEL_SET_NUMBER) + return -EINVAL; + + mutex_lock(&st->lock); + reg = LSADC_READL(chan->address); + + switch (dir) { + case IIO_EV_DIR_RISING: + old_thresh = (reg & LSADC0_LEVEL_TOP_BOUND_MASK) >> LSADC0_LEVEL_TOP_BOUND_SHIFT; + reg = (reg & ~LSADC0_LEVEL_TOP_BOUND_MASK) | (val << LSADC0_LEVEL_TOP_BOUND_SHIFT); + break; + case IIO_EV_DIR_FALLING: + old_thresh = (reg & LSADC0_LEVEL_LOW_BOUND_MASK) >> LSADC0_LEVEL_LOW_BOUND_SHIFT; + reg = (reg & ~LSADC0_LEVEL_LOW_BOUND_MASK) | (val << LSADC0_LEVEL_LOW_BOUND_SHIFT); + break; + default: + dev_err(st->dev, "dir %d is not supported\n", dir); + } + reg &= ~LSADC0_LEVEL_INT_PEND_MASK; + LSADC_WRITEL(reg, chan->address); + mutex_unlock(&st->lock); + dev_info(st->dev, "channel %d, mapped channel2 %d: write pad_reg = 0x%x, new threshold = %d, old threshold = %d\n", + chan->channel, rtk_mod_map[chan->channel2], reg, val, old_thresh); + } else { + if (chan->channel > 1) + return -EINVAL; + + mutex_lock(&st->lock); + st->lsadc[0].pad[chan->channel].threshold = val; + reg = LSADC_READL(chan->address); + old_thresh = (reg & LSADC0_PAD_THRED_MASK) >> LSADC0_PAD_THRED_SHIFT; + reg = (reg & ~LSADC0_PAD_THRED_MASK) | (val << LSADC0_PAD_THRED_SHIFT); + LSADC_WRITEL(reg, chan->address); + mutex_unlock(&st->lock); + dev_info(st->dev, "channel %d: write pad_reg = 0x%x, new threshold = %d, old threshold = %d\n", + chan->channel, reg, val, old_thresh); + } + + return 0; +} + + +static int rtk_lsadc_reg_access(struct iio_dev *indio_dev, + unsigned int addr, unsigned int writeval, + unsigned int *readval) +{ + struct rtk_lsadc_state *st = iio_priv(indio_dev); + struct device *dev = st->dev; + + if (addr % 4 || addr > LSADC0_POWER_ADDR) + return -EINVAL; + + mutex_lock(&st->lock); + if (readval) { + *readval = LSADC_READL(addr); + dev_info(dev, "read reg 0x%X = 0x%X\n", addr, *readval); + } else { + LSADC_WRITEL(writeval, addr); + dev_info(dev, "write reg 0x%X = 0x%X\n", addr, writeval); + } + mutex_unlock(&st->lock); + + return 0; +} + +static const struct iio_info rtk_lsadc_iio_info = { + .read_raw = rtk_lsadc_read_raw, + .write_raw = rtk_lsadc_write_raw, + .read_event_config = &rtk_lsadc_read_event_config, + .write_event_config = &rtk_lsadc_write_event_config, + .read_event_value = &rtk_lsadc_read_event_value, + .write_event_value = &rtk_lsadc_write_event_value, + .attrs = &rtk_group_base, + .debugfs_reg_access = rtk_lsadc_reg_access, +}; + + +static int rtk_lsadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *idev; + struct rtk_lsadc_state *st; + struct device_node *lsadc0_pad0_node; + struct device_node *lsadc0_pad1_node; + int ret = -EINVAL; + uint val; + uint ctrl_reg; + uint analog_ctrl_reg; + uint pad0_reg; + uint pad1_reg; + uint lsadc_status_reg; + uint irq_num; + uint lsadc_power_reg; + struct clk *clk; + struct reset_control *rstc; + + dev_info(dev, "[LSADC] %s : init\n", __func__); + + idev = devm_iio_device_alloc(dev, sizeof(struct rtk_lsadc_state)); + if (!idev) { + dev_err(dev, "[LSADC] failed to allocate memory\n"); + return -ENOMEM; + } + + st = iio_priv(idev); + mutex_init(&st->lock); + + lsadc0_pad0_node = of_get_child_by_name(pdev->dev.of_node, "lsadc0-pad0"); + if (!lsadc0_pad0_node) { + dev_err(dev, "[LSADC] could not find [lsadc0-pad0] sub-node\n"); + return -EINVAL; + } + lsadc0_pad1_node = of_get_child_by_name(pdev->dev.of_node, "lsadc0-pad1"); + if (!lsadc0_pad1_node) { + dev_err(dev, "[LSADC] could not find [lsadc0-pad1] sub-node\n"); + return -EINVAL; + } + + /* Request IRQ */ + irq_num = irq_of_parse_and_map(pdev->dev.of_node, 0); + + st->dev = dev; + st->lsadc[0].irq = irq_num; + st->lsadc_addr = of_iomap(pdev->dev.of_node, 0); + st->crt_lsadc_pg_addr = of_iomap(pdev->dev.of_node, 1); + + platform_set_drvdata(pdev, idev); + + if (!of_property_read_u32(pdev->dev.of_node, "clk_gating_en", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].clk_gating_en = val; + } + + if (!of_property_read_u32(pdev->dev.of_node, "debounce0_cnt", &val)) { + if (val > 15) + val = 15; + st->lsadc[0].debounce_cnt = val; + } + + st->crt_lsadc_pg_val = CRT_LSADC_PG_VALUE; + + + /* set LSADC0 pad0 from device tree : lsadc0-pad0 */ + if (!of_property_read_u32(lsadc0_pad0_node, "activate", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].pad[0].activate = val; + } + + if (!of_property_read_u32(lsadc0_pad0_node, "ctrl_mode", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].pad[0].ctrl_mode = val; + } + + if (!of_property_read_u32(lsadc0_pad0_node, "sw_idx", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].pad[0].pad_sw = val; + } + + if (!of_property_read_u32(lsadc0_pad0_node, "voltage_threshold", &val)) + st->lsadc[0].pad[0].threshold = val; + + if (!of_property_read_u32(lsadc0_pad0_node, "adc_val_baseline", &val)) + st->lsadc[0].pad[0].adc_val_baseline = val; + else + st->lsadc[0].pad[0].adc_val_baseline = LSADC0_PAD_ADC_VAL_MASK; + + /* set LSADC0 pad1 from device tree : lsadc0-pad1 */ + if (!of_property_read_u32(lsadc0_pad1_node, "activate", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].pad[1].activate = val; + } + + if (!of_property_read_u32(lsadc0_pad1_node, "ctrl_mode", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].pad[1].ctrl_mode = val; + } + + if (!of_property_read_u32(lsadc0_pad1_node, "sw_idx", &val)) { + if (val > 1) + val = 1; + st->lsadc[0].pad[1].pad_sw = val; + } + + if (!of_property_read_u32(lsadc0_pad1_node, "voltage_threshold", &val)) + st->lsadc[0].pad[1].threshold = val; + + if (!of_property_read_u32(lsadc0_pad1_node, "adc_val_baseline", &val)) + st->lsadc[0].pad[1].adc_val_baseline = val & LSADC0_PAD_ADC_VAL_MASK; + else + st->lsadc[0].pad[1].adc_val_baseline = LSADC0_PAD_ADC_VAL_MASK; + + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) { + clk = NULL; + dev_err(dev, "[LSADC] can't get LSADC clock\n"); + goto err_get_clk; + } else { + clk_prepare_enable(clk); + } + st->clk = clk; + + + rstc = reset_control_get_exclusive(dev, NULL); + if (IS_ERR(rstc)) { + dev_err(dev, "[LSADC] can't get LSADC reset\n"); + goto err_get_rstc; + } else { + reset_control_deassert(rstc); + reset_control_put(rstc); + } + + lsadc_power_reg = LSADC_READL(LSADC0_POWER_ADDR) & ~(LSADC0_CLK_GATING_EN); + if (st->lsadc[0].clk_gating_en == 1) + lsadc_power_reg |= LSADC0_CLK_GATING_EN; + + LSADC_WRITEL(lsadc_power_reg, LSADC0_POWER_ADDR); + dev_info(dev, "[LSADC] write lsadc0_power_reg=0x%x\n", lsadc_power_reg); + + /* Enable JD_power in ananlog ctrl register */ + analog_ctrl_reg = LSADC_READL(LSADC0_ANALOG_CTRL_ADDR); + analog_ctrl_reg |= LSADC0_ANALOG_CTRL_VALUE; + LSADC_WRITEL(analog_ctrl_reg, LSADC0_ANALOG_CTRL_ADDR); + mdelay(100); + + /* LSADC0 */ + ctrl_reg = LSADC_READL(LSADC0_CTRL_ADDR); + analog_ctrl_reg = LSADC_READL(LSADC0_ANALOG_CTRL_ADDR); + lsadc_status_reg = LSADC_READL(LSADC0_STATUS_ADDR); + pad0_reg = LSADC_READL(LSADC0_PAD0_ADDR); + pad1_reg = LSADC_READL(LSADC0_PAD1_ADDR); + + dev_info(dev, "[LSADC] from device tree: pad0=[activate=%d, ctrl_mode=%d, pad_sw=%d, threshold=%d]\n", + st->lsadc[0].pad[0].activate, + st->lsadc[0].pad[0].ctrl_mode, + st->lsadc[0].pad[0].pad_sw, + st->lsadc[0].pad[0].threshold); + dev_info(dev, "[LSADC] from device tree: pad1=[activate=%d, ctrl_mode=%d, pad_sw=%d, threshold=%d]\n", + st->lsadc[0].pad[1].activate, + st->lsadc[0].pad[1].ctrl_mode, + st->lsadc[0].pad[1].pad_sw, + st->lsadc[0].pad[1].threshold); + + dev_info(dev, "[LSADC] current value: ctrl_reg=0x%x, lsadc_status_reg=0x%x, pad0_reg=0x%x, pad1_reg=0x%x\n", + ctrl_reg, lsadc_status_reg, pad0_reg, pad1_reg); + + if (st->lsadc[0].pad[0].activate == 1) { + pad0_reg = pad0_reg | LSADC0_PAD_ACTIVE_MASK; + if (st->lsadc[0].pad[0].ctrl_mode == 1) + pad0_reg |= LSADC0_PAD_CTRL_MASK; + else + pad0_reg &= ~LSADC0_PAD_CTRL_MASK; + + if (st->lsadc[0].pad[0].pad_sw == 1) + pad0_reg |= LSADC0_PAD_SW_MASK; + else + pad0_reg &= ~LSADC0_PAD_SW_MASK; + + if (st->lsadc[0].pad[0].threshold <= 0xFF && + st->lsadc[0].pad[0].threshold >= 0) { + pad0_reg |= LSADC0_PAD_THRED_MASK & + (st->lsadc[0].pad[0].threshold << LSADC0_PAD_THRED_SHIFT); + } + + /* set adc_val0 to base line */ + st->lsadc[0].pad[0].adc_val0 = st->lsadc[0].pad[0].adc_val_baseline; + pad0_reg = (pad0_reg & ~LSADC0_PAD_ADC_VAL_MASK) | st->lsadc[0].pad[0].adc_val0; + + /* enable IIO events */ + st->rising_evt_cfg |= BIT(0); + st->falling_evt_cfg |= BIT(0); + } else { + pad0_reg &= ~LSADC0_PAD_ACTIVE_MASK; + + /* disable IIO events */ + st->rising_evt_cfg &= ~BIT(0); + st->falling_evt_cfg &= ~BIT(0); + } + LSADC_WRITEL(pad0_reg, LSADC0_PAD0_ADDR); + dev_info(dev, "[LSADC] write pad0_reg=0x%x\n", pad0_reg); + + if (st->lsadc[0].pad[1].activate == 1) { + pad1_reg |= LSADC0_PAD_ACTIVE_MASK; + if (st->lsadc[0].pad[1].ctrl_mode == 1) + pad1_reg |= LSADC0_PAD_CTRL_MASK; + else + pad1_reg &= ~LSADC0_PAD_CTRL_MASK; + + if (st->lsadc[0].pad[1].pad_sw == 1) + pad1_reg |= LSADC0_PAD_SW_MASK; + else + pad1_reg &= ~LSADC0_PAD_SW_MASK; + + if (st->lsadc[0].pad[1].threshold <= 0xFF && + st->lsadc[0].pad[1].threshold >= 0) { + pad1_reg |= LSADC0_PAD_THRED_MASK & + (st->lsadc[0].pad[1].threshold << LSADC0_PAD_THRED_SHIFT); + } + + /* set adc_val0 to base line */ + st->lsadc[0].pad[1].adc_val0 = st->lsadc[0].pad[1].adc_val_baseline; + pad1_reg = (pad1_reg & ~LSADC0_PAD_ADC_VAL_MASK) | st->lsadc[0].pad[1].adc_val0; + + /* enable IIO events */ + st->rising_evt_cfg |= BIT(1); + st->falling_evt_cfg |= BIT(1); + } else { + pad1_reg &= ~LSADC0_PAD_ACTIVE_MASK; + + /* disable IIO events */ + st->rising_evt_cfg &= ~BIT(1); + st->falling_evt_cfg &= ~BIT(1); + } + LSADC_WRITEL(pad1_reg, LSADC0_PAD1_ADDR); + dev_info(dev, "[LSADC] write pad1_reg=0x%x\n", pad1_reg); + + ctrl_reg &= ~LSADC0_CTRL_DEBOUNCE_MASK; + ctrl_reg |= LSADC0_CTRL_ENABLE_MASK | LSADC0_CTRL_SEL_WAIT_DEFAULT; + ctrl_reg |= st->lsadc[0].debounce_cnt << LSADC0_CTRL_DEBOUNCE_SHIFT; + LSADC_WRITEL(ctrl_reg, LSADC0_CTRL_ADDR); + dev_info(dev, "[LSADC] ctrl_reg=0x%x, irq_num=%d\n", + ctrl_reg, irq_num); + + if ((lsadc_status_reg & LSADC0_STATUS_IRQ_EN_MASK) != LSADC0_STATUS_IRQ_EN_MASK) { + lsadc_status_reg = lsadc_status_reg | LSADC0_STATUS_IRQ_EN_MASK; + LSADC_WRITEL(lsadc_status_reg, LSADC0_STATUS_ADDR); + dev_info(dev, "[LSADC] write lsadc_status_reg=0x%x\n", + lsadc_status_reg); + } + + if (request_irq(st->lsadc[0].irq, lsadc0_interrupt_pad, IRQF_SHARED, "lsadc0", idev) < 0) { + dev_err(dev, "[LSADC] unable to request LSADC0 irq#%d\n", + st->lsadc[0].irq); + goto err_req_irq; + } + /* Enable IRQ for pad0/pad1, set LSADC0_STATUS to 0x0300000 */ + LSADC_WRITEL(LSADC0_STATUS_ENABLE_IRQ, LSADC0_STATUS_ADDR); + + ctrl_reg = LSADC_READL(LSADC0_CTRL_ADDR); + lsadc_status_reg = LSADC_READL(LSADC0_STATUS_ADDR); + analog_ctrl_reg = LSADC_READL(LSADC0_ANALOG_CTRL_ADDR); + pad0_reg = LSADC_READL(LSADC0_PAD0_ADDR); + pad1_reg = LSADC_READL(LSADC0_PAD1_ADDR); + + st->lsadc[0].pad[0].adc_val0 = pad0_reg & LSADC0_PAD_ADC_VAL_MASK; + st->lsadc[0].pad[1].adc_val0 = pad1_reg & LSADC0_PAD_ADC_VAL_MASK; + + dev_info(dev, "[LSADC] set ctrl_reg=0x%x, lsadc_status_reg=0x%x, pad0_reg=0x%x, pad1_reg=0x%x\n", + ctrl_reg, lsadc_status_reg, pad0_reg, pad1_reg); + + /* Init CRT LSADC PG */ + writel(st->crt_lsadc_pg_val, st->crt_lsadc_pg_addr); + dev_info(dev, "[LSADC] write crt_lsadc_pg_val=0x%x\n", + st->crt_lsadc_pg_val); + + idev->dev.parent = dev; + idev->dev.of_node = dev->of_node; + idev->name = dev_name(dev); + idev->info = &rtk_lsadc_iio_info; + idev->modes = INDIO_DIRECT_MODE; + idev->channels = rtk_lsadc_iio_channels; + idev->num_channels = ARRAY_SIZE(rtk_lsadc_iio_channels); + ret = iio_device_register(idev); + if (ret) + goto err_iio_reg; + + return 0; + +err_iio_reg: + free_irq(st->lsadc[0].irq, idev); +err_req_irq: +err_get_rstc: + clk_disable_unprepare(st->clk); +err_get_clk: + return ret; +} + +static int rtk_lsadc_remove(struct platform_device *pdev) +{ + struct iio_dev *idev = platform_get_drvdata(pdev); + struct rtk_lsadc_state *st = iio_priv(idev); + + iio_device_unregister(idev); + clk_disable_unprepare(st->clk); + free_irq(st->lsadc[0].irq, idev); + iio_device_free(idev); + return 0; +} + +static const struct of_device_id rtk_lsadc_of_match[] = { + {.compatible = "realtek,rtk-lsadc0"}, + { } +}; +MODULE_DEVICE_TABLE(of, rtk_lsadc_of_match); + + +static struct platform_driver rtk_lsadc_platform_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "rtk-lsadc0", + .of_match_table = rtk_lsadc_of_match, + }, + .probe = rtk_lsadc_probe, + .remove = rtk_lsadc_remove, +}; +module_platform_driver(rtk_lsadc_platform_driver); + +MODULE_DESCRIPTION("RTK LSADC0 driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-lsadc0"); + + diff --git a/drivers/iio/adc/rtk_lsadc0.h b/drivers/iio/adc/rtk_lsadc0.h new file mode 100644 index 000000000000..6fa80d07aeb5 --- /dev/null +++ b/drivers/iio/adc/rtk_lsadc0.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * + * Realtek Low Speed ADC driver + * + * Copyright (C) 2020 Realtek Semiconductor Corporation. + */ + +#ifndef __RTK_LSADC0_H_ +#define __RTK_LSADC0_H_ + +/* LSADC0 registers */ +#define LSADC0_PAD0_ADDR (0x00) +#define LSADC0_PAD1_ADDR (0x04) + +#define LSADC0_CTRL_ADDR (0x20) +#define LSADC0_STATUS_ADDR (0x24) +#define LSADC0_ANALOG_CTRL_ADDR (0x28) + +#define LSADC0_PAD_LEVEL_SET_NUMBER (6) +#define LSADC0_PAD0_LEVEL_SET0_ADDR (0x30) +#define LSADC0_PAD0_LEVEL_SET1_ADDR (0x34) +#define LSADC0_PAD0_LEVEL_SET2_ADDR (0x38) +#define LSADC0_PAD0_LEVEL_SET3_ADDR (0x3c) +#define LSADC0_PAD0_LEVEL_SET4_ADDR (0x40) +#define LSADC0_PAD0_LEVEL_SET5_ADDR (0x44) + +#define LSADC0_PAD1_LEVEL_SET0_ADDR (0x48) +#define LSADC0_PAD1_LEVEL_SET1_ADDR (0x4c) +#define LSADC0_PAD1_LEVEL_SET2_ADDR (0x50) +#define LSADC0_PAD1_LEVEL_SET3_ADDR (0x54) +#define LSADC0_PAD1_LEVEL_SET4_ADDR (0x58) +#define LSADC0_PAD1_LEVEL_SET5_ADDR (0x5c) + +#define LSADC0_POWER_ADDR (0x80) + +/* LSADC0_PAD0_ADDR - bit fields */ +/* LSADC0_PAD1_ADDR - bit fields */ +#define LSADC0_PAD_ACTIVE_MASK BIT(31) +#define LSADC0_PAD_THRED_SHIFT (16) +#define LSADC0_PAD_THRED_MASK GENMASK(23, 16) +#define LSADC0_PAD_SW_MASK BIT(12) +#define LSADC0_PAD_CTRL_MASK BIT(8) +#define LSADC0_PAD_ADC_VAL_MASK GENMASK(7, 0) + +/* LSADC0_CTRL_ADDR - bit fields */ +#define LSADC0_CTRL_SEL_WAIT_MASK GENMASK(31, 28) +#define LSADC0_CTRL_SEL_WAIT_DEFAULT BIT(31) +#define LSADC0_CTRL_DEBOUNCE_SHIFT (20) +#define LSADC0_CTRL_DEBOUNCE_MASK GENMASK(23, 20) +#define LSADC0_CTRL_ENABLE_MASK BIT(0) + +/* LSADC0_STATUS_ADDR - bit fields */ +#define LSADC0_STATUS_IRQ_EN_MASK GENMASK(25, 24) +#define LSADC0_STATUS_PAD_CNT_MASK BIT(20) +#define LSADC0_STATUS_ADC_BUSY_MASK BIT(19) +#define LSADC0_STATUS_PAD_CTRL_MASK GENMASK(16, 12) +#define LSADC0_STATUS_PAD1_STATUS_MASK BIT(1) +#define LSADC0_STATUS_PAD0_STATUS_MASK BIT(0) +#define LSADC0_STATUS_ENABLE_IRQ LSADC0_STATUS_IRQ_EN_MASK + +/* LSADC0_ANALOG_CTRL_ADDR - bit fields */ +#define LSADC0_ANALOG_CTRL_JD_PWR_MASK BIT(0) +#define LSADC0_ANALOG_CTRL_VALUE LSADC0_ANALOG_CTRL_JD_PWR_MASK + +/* LSADC0_PAD1_LEVEL_SET0_ADDR - bit fields */ +#define LSADC0_LEVEL_TOP_BOUND_SHIFT (24) +#define LSADC0_LEVEL_TOP_BOUND_MASK GENMASK(31, 24) +#define LSADC0_LEVEL_LOW_BOUND_SHIFT (16) +#define LSADC0_LEVEL_LOW_BOUND_MASK GENMASK(23, 16) +#define LSADC0_LEVEL_BLK_EN_SHIFT (15) +#define LSADC0_LEVEL_BLK_EN_MASK BIT(15) +#define LSADC0_LEVEL_INT_EN_SHIFT (1) +#define LSADC0_LEVEL_INT_EN_MASK BIT(1) +#define LSADC0_LEVEL_INT_PEND_MASK BIT(0) +#define LSADC0_LEVEL_ENABLE_BLOCK LSADC0_LEVEL_BLK_EN_MASK +#define LSADC0_LEVEL_ENABLE_IRQ LSADC0_LEVEL_INT_EN_MASK +#define LSADC0_LEVEL_CLEAR_IRQ LSADC0_LEVEL_INT_PEND_MASK + +/* LSADC0_POWER_ADDR - bit fields */ +#define LSADC0_CLK_GATING_EN_MASK BIT(0) +#define LSADC0_CLK_GATING_EN LSADC0_CLK_GATING_EN_MASK + +/* CRT LSADC_PG_ADDR - bit fields */ +#define CRT_LSADC_VDDMUX_SEL_SHIFT (10) +#define CRT_LSADC_VDDMUX_SEL_MASK BIT(10) +#define CRT_LSADC_VDD_MUX1_SHIFT (6) +#define CRT_LSADC_VDD_MUX1_MASK GENMASK(9, 6) +#define CRT_LSADC_VDD_MUX2_SHIFT (2) +#define CRT_LSADC_VDD_MUX2_MASK GENMASK(5, 2) +#define CRT_LSADC_VDDMUX_EN_SHIFT (1) +#define CRT_LSADC_VDDMUX_EN_MASK BIT(1) +#define CRT_LSADC_PG_VALUE CRT_LSADC_VDDMUX_EN_MASK + +#define MICROVOLT_HIGH (3300000) + +#endif /*__RTK_LSADC0_H_ */ + diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 3690e28cc7ea..da3ee3cc2632 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -499,6 +499,7 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, iser_conn->iscsi_conn = conn; out: + iscsi_put_endpoint(ep); mutex_unlock(&iser_conn->state_mutex); return error; } diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 5f1195791cb1..6a353c6f59b8 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007-2010 Advanced Micro Devices, Inc. @@ -2738,6 +2741,17 @@ static int amd_iommu_def_domain_type(struct device *dev) { struct iommu_dev_data *dev_data; +#ifdef MY_ABC_HERE + if (dev_is_pci(dev)) { + struct pci_dev *pdev = to_pci_dev(dev); + + /* AMD Starship USB 3.0 Host Controller 0x148c */ + if (pdev && pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x148c) { + return IOMMU_DOMAIN_DMA; + } + } +#endif /* MY_ABC_HERE */ + dev_data = dev_iommu_priv_get(dev); if (!dev_data) return 0; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9b8664d388af..165d0ba3726e 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. @@ -28,9 +31,16 @@ static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); +#ifdef MY_ABC_HERE +#define IOMMU_CMD_LINE_DMA_API BIT(0) +static unsigned int iommu_def_domain_type __read_mostly = IOMMU_DOMAIN_IDENTITY; +static bool iommu_dma_strict __read_mostly = true; +static u32 iommu_cmd_line __read_mostly = IOMMU_CMD_LINE_DMA_API; +#else /* MY_ABC_HERE */ static unsigned int iommu_def_domain_type __read_mostly; static bool iommu_dma_strict __read_mostly = true; static u32 iommu_cmd_line __read_mostly; +#endif /* MY_ABC_HERE */ struct iommu_group { struct kobject kobj; @@ -68,7 +78,10 @@ static const char * const iommu_group_resv_type_string[] = { [IOMMU_RESV_SW_MSI] = "msi", }; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ #define IOMMU_CMD_LINE_DMA_API BIT(0) +#endif /* MY_ABC_HERE */ static void iommu_set_cmd_line_dma_api(void) { @@ -1467,6 +1480,12 @@ static int iommu_get_def_domain_type(struct device *dev) if (ops->def_domain_type) type = ops->def_domain_type(dev); +#ifdef MY_ABC_HERE + if (type) { + dev_info(dev, "Device specific iommu domain: %s\n", iommu_domain_type_str(type)); + } +#endif /* MY_ABC_HERE */ + return (type == 0) ? iommu_def_domain_type : type; } @@ -1661,6 +1680,10 @@ static int probe_get_default_domain_type(struct device *dev, void *data) dev_name(gtype->dev), iommu_domain_type_str(gtype->type)); gtype->type = 0; +#ifdef MY_ABC_HERE + } else { + dev_info(dev, "Device specific iommu domain: %s\n", iommu_domain_type_str(type)); +#endif /* MY_ABC_HERE */ } if (!gtype->dev) { diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 94c2885882ee..e949839b87e8 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -48,6 +48,9 @@ obj-$(CONFIG_IXP4XX_IRQ) += irq-ixp4xx.o obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_ARCH_REALTEK) += irq-realtek-mux.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 1005b182bab4..8d77cccd0ad1 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013-2017 ARM Limited, All Rights Reserved. @@ -31,6 +34,10 @@ #include "irq-gic-common.h" +#if defined(MY_DEF_HERE) +#define GICD_CTLR_E1NWF (1 << 7) + +#endif /* MY_DEF_HERE */ #define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80) #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) @@ -38,6 +45,14 @@ #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) +#if defined(MY_DEF_HERE) +static unsigned int GICR_ISENABLER0_REG; +static unsigned int GIC_ISENABLER0_REG; +static unsigned int GIC_ISENABLER1_REG; +static unsigned int GIC_ISENABLER2_REG; +static unsigned int GIC_ISENABLER3_REG; + +#endif /* MY_DEF_HERE */ struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; @@ -235,10 +250,27 @@ static void gic_enable_redist(bool enable) rbase = gic_data_rdist_rd_base(); val = readl_relaxed(rbase + GICR_WAKER); +#if defined(MY_DEF_HERE) + if (enable) { + +#if defined(MY_DEF_HERE) + if (readl_relaxed(rbase) & 0x02000000) + writel_relaxed(readl_relaxed(rbase) & 0xfdffffff, rbase); +#else /* MY_DEF_HERE */ + if (readl_relaxed(rbase) & 0x02000000) + writel_relaxed(readl_relaxed(rbase) & 0xfdffffff, rbase); +#endif /* MY_DEF_HERE */ + +#else /* MY_DEF_HERE */ if (enable) +#endif /* MY_DEF_HERE */ /* Wake up this CPU redistributor */ val &= ~GICR_WAKER_ProcessorSleep; +#if defined(MY_DEF_HERE) + } else +#else /* MY_DEF_HERE */ else +#endif /* MY_DEF_HERE */ val |= GICR_WAKER_ProcessorSleep; writel_relaxed(val, rbase + GICR_WAKER); @@ -784,7 +816,11 @@ static void __init gic_dist_init(void) /* Now do the common stuff, and wait for the distributor to drain */ gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp); +#if defined(MY_DEF_HERE) + val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1 | GICD_CTLR_E1NWF; +#else /* MY_DEF_HERE */ val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1; +#endif /* MY_DEF_HERE */ if (gic_data.rdists.gicd_typer2 & GICD_TYPER2_nASSGIcap) { pr_info("Enabling SGIs without active state\n"); val |= GICD_CTLR_nASSGIreq; @@ -798,6 +834,15 @@ static void __init gic_dist_init(void) * enabled. */ affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id())); +#if defined(MY_DEF_HERE) + + /* + * The GIC selects the appropriate core for a SPI. + * GICD_IROUTER.Interrupt_Routing_Mode = 1 + */ + affinity |= 0x80000000; + +#endif /* MY_DEF_HERE */ for (i = 32; i < GIC_LINE_NR; i++) gic_write_irouter(affinity, base + GICD_IROUTER + i * 8); @@ -1112,6 +1157,19 @@ static int gic_starting_cpu(unsigned int cpu) return 0; } +#if defined(MY_DEF_HERE) +static int gic_off_cpu(unsigned int cpu) +{ + + void __iomem *rbase; + + rbase = gic_data_rdist_rd_base(); + writel_relaxed(readl_relaxed(rbase) | 0x2000000, rbase); + + return 0; +} + +#endif /* MY_DEF_HERE */ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask, unsigned long cluster_id) { @@ -1193,7 +1251,11 @@ static void __init gic_smp_init(void) cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, "irqchip/arm/gicv3:starting", +#if defined(MY_DEF_HERE) + gic_starting_cpu, gic_off_cpu); +#else /* MY_DEF_HERE */ gic_starting_cpu, NULL); +#endif /* MY_DEF_HERE */ /* Register all 8 non-secure SGIs */ base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 8, @@ -1234,6 +1296,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, reg = gic_dist_base(d) + offset + (index * 8); val = gic_mpidr_to_affinity(cpu_logical_map(cpu)); +#if defined(MY_DEF_HERE) + if (cpumask_subset(cpu_online_mask, mask_val)) + val |= 0x80000000; + +#endif /* MY_DEF_HERE */ gic_write_irouter(val, reg); /* @@ -1264,6 +1331,36 @@ static int gic_retrigger(struct irq_data *data) static int gic_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v) { +#if defined(MY_DEF_HERE) + void __iomem *rbase; + + rbase = gic_data_rdist_sgi_base(); + if (cmd == CPU_PM_EXIT) { + pr_err("GICR_ISENABLER0 = %x\n", GICR_ISENABLER0_REG); + pr_err("GIC_ISENABLER0 = %x\n", GIC_ISENABLER0_REG); + pr_err("GIC_ISENABLER1 = %x\n", GIC_ISENABLER1_REG); + pr_err("GIC_ISENABLER2 = %x\n", GIC_ISENABLER2_REG); + pr_err("GIC_ISENABLER3 = %x\n", GIC_ISENABLER3_REG); + writel_relaxed(GICR_ISENABLER0_REG, rbase + GICR_ISENABLER0); + writel_relaxed(GIC_ISENABLER0_REG, gic_data.dist_base + 0x100); + writel_relaxed(GIC_ISENABLER1_REG, gic_data.dist_base + 0x104); + writel_relaxed(GIC_ISENABLER2_REG, gic_data.dist_base + 0x108); + writel_relaxed(GIC_ISENABLER3_REG, gic_data.dist_base + 0x10C); + + } else if (cmd == CPU_PM_ENTER) { + GICR_ISENABLER0_REG = readl_relaxed(rbase + GICR_ISENABLER0); + GIC_ISENABLER0_REG = readl_relaxed(gic_data.dist_base + 0x100); + GIC_ISENABLER1_REG = readl_relaxed(gic_data.dist_base + 0x104); + GIC_ISENABLER2_REG = readl_relaxed(gic_data.dist_base + 0x108); + GIC_ISENABLER3_REG = readl_relaxed(gic_data.dist_base + 0x10C); + pr_err("GICR_ISENABLER0 = %x\n", GICR_ISENABLER0_REG); + pr_err("GIC_ISENABLER0 = %x\n", GIC_ISENABLER0_REG); + pr_err("GIC_ISENABLER1 = %x\n", GIC_ISENABLER1_REG); + pr_err("GIC_ISENABLER2 = %x\n", GIC_ISENABLER2_REG); + pr_err("GIC_ISENABLER3 = %x\n", GIC_ISENABLER3_REG); + } + +#endif /* MY_DEF_HERE */ if (cmd == CPU_PM_EXIT) { if (gic_dist_security_disabled()) gic_enable_redist(true); diff --git a/drivers/irqchip/irq-realtek-mux.c b/drivers/irqchip/irq-realtek-mux.c new file mode 100644 index 000000000000..a06ca2b3caa9 --- /dev/null +++ b/drivers/irqchip/irq-realtek-mux.c @@ -0,0 +1,538 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek IRQ mux + * + * Copyright (c) 2017 - 2021 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTK_MUX_IRQ_ALWAYS_ENABLED (-1) + +struct realtek_irq_mux_data; + +/** + * struct realtek_irq_mux_subset_cfg + * + * @ints_mask: handler of a interrupt source only handles + * ints bits in the mask. + */ +struct realtek_irq_mux_subset_cfg { + unsigned int ints_mask; +}; + +struct realtek_irq_mux_info { + unsigned int isr_offset; + unsigned int umsk_isr_offset; + unsigned int scpu_int_en_offset; + unsigned int first_irq; + const u32 *isr_to_scpu_int_en_mask; + const struct realtek_irq_mux_subset_cfg *cfg; + int cfg_num; +}; + +/** + * struct realtek_irq_mux_subset_data + * + * @cfg: cfg of the subset + * @common: common data + * @parent_irq: interrupt source + */ +struct realtek_irq_mux_subset_data { + const struct realtek_irq_mux_subset_cfg *cfg; + struct realtek_irq_mux_data *common; + int parent_irq; +}; + +struct realtek_irq_mux_data { + struct regmap *base; + const struct realtek_irq_mux_info *info; + struct irq_domain *domain; + spinlock_t lock; + int subset_data_num; + struct realtek_irq_mux_subset_data subset_data[0]; +}; + +static unsigned int realtek_mux_irq_get_ints(struct realtek_irq_mux_data *data) +{ + unsigned int val; + + regmap_read(data->base, data->info->isr_offset, &val); + return val; +} + +static void realtek_mux_irq_clear_ints_bit(struct realtek_irq_mux_data *data, int bit) +{ + regmap_write(data->base, data->info->isr_offset, BIT(bit) & ~1); +} + +static unsigned int realtek_mux_irq_get_inte(struct realtek_irq_mux_data *data) +{ + unsigned int val; + unsigned long flags; + + spin_lock_irqsave(&data->lock, flags); + regmap_read(data->base, data->info->scpu_int_en_offset, &val); + spin_unlock_irqrestore(&data->lock, flags); + + return val; +} + +static void realtek_mux_irq_handle(struct irq_desc *desc) +{ + struct realtek_irq_mux_subset_data *subset_data = irq_desc_get_handler_data(desc); + struct realtek_irq_mux_data *data = subset_data->common; + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 ints, inte, mask; + int i; + + chained_irq_enter(chip, desc); + + ints = realtek_mux_irq_get_ints(data) & subset_data->cfg->ints_mask; + inte = realtek_mux_irq_get_inte(data); + + for (i = 0; i < 32; i++) { + if (!(ints & BIT(i))) + continue; + + mask = data->info->isr_to_scpu_int_en_mask[i]; + if (mask != RTK_MUX_IRQ_ALWAYS_ENABLED && !(inte & mask)) + continue; + + generic_handle_irq(irq_find_mapping(data->domain, i)); + realtek_mux_irq_clear_ints_bit(data, i); + } + + chained_irq_exit(chip, desc); +} + +static void realtek_mux_mask_irq(struct irq_data *data) +{ + struct realtek_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data); + + regmap_write(mux_data->base, mux_data->info->isr_offset, BIT(data->hwirq)); +} + +static void realtek_mux_unmask_irq(struct irq_data *data) +{ + struct realtek_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data); + + regmap_write(mux_data->base, mux_data->info->umsk_isr_offset, BIT(data->hwirq)); +} + +static void realtek_mux_enable_irq(struct irq_data *data) +{ + struct realtek_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data); + unsigned long flags; + u32 scpu_int_en, mask; + + mask = mux_data->info->isr_to_scpu_int_en_mask[data->hwirq]; + if (!mask) + return; + + spin_lock_irqsave(&mux_data->lock, flags); + + regmap_read(mux_data->base, mux_data->info->scpu_int_en_offset, &scpu_int_en); + scpu_int_en |= mask; + regmap_write(mux_data->base, mux_data->info->umsk_isr_offset, scpu_int_en); + + spin_unlock_irqrestore(&mux_data->lock, flags); +} + +static void realtek_mux_disable_irq(struct irq_data *data) +{ + struct realtek_irq_mux_data *mux_data = irq_data_get_irq_chip_data(data); + unsigned long flags; + u32 scpu_int_en, mask; + + mask = mux_data->info->isr_to_scpu_int_en_mask[data->hwirq]; + if (!mask) + return; + + spin_lock_irqsave(&mux_data->lock, flags); + + regmap_read(mux_data->base, mux_data->info->scpu_int_en_offset, &scpu_int_en); + scpu_int_en &= ~mask; + regmap_write(mux_data->base, mux_data->info->umsk_isr_offset, scpu_int_en); + + spin_unlock_irqrestore(&mux_data->lock, flags); +} + +static int lookup_parent_irq(struct realtek_irq_mux_data *mux_data, struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + int i; + + for (i = 0; i < mux_data->subset_data_num; i++) + if (mux_data->subset_data[i].cfg->ints_mask & mask) + return mux_data->subset_data[i].parent_irq; + + return -EINVAL; +} + +static int realtek_mux_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, bool force) +{ + struct realtek_irq_mux_data *mux_data = irq_data_get_irq_chip_data(d); + int irq; + struct irq_chip *chip; + struct irq_data *data; + + irq = lookup_parent_irq(mux_data, d); + if (irq < 0) + return irq; + + chip = irq_get_chip(irq); + data = irq_get_irq_data(irq); + + irq_data_update_effective_affinity(d, cpu_online_mask); + if (chip && chip->irq_set_affinity) + return chip->irq_set_affinity(data, mask_val, force); + else + return -EINVAL; +} + +static struct irq_chip realtek_mux_irq_chip = { + .name = "realtek-irq-mux", + .irq_mask = realtek_mux_mask_irq, + .irq_unmask = realtek_mux_unmask_irq, + .irq_enable = realtek_mux_enable_irq, + .irq_disable = realtek_mux_disable_irq, + .irq_set_affinity = realtek_mux_set_affinity, +}; + +static int realtek_mux_irq_domain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hw) +{ + struct realtek_irq_mux_data *data = d->host_data; + + irq_set_chip_and_handler(irq, &realtek_mux_irq_chip, handle_level_irq); + irq_set_chip_data(irq, data); + irq_set_probe(irq); + + return 0; +} + +static const struct irq_domain_ops realtek_mux_irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = realtek_mux_irq_domain_map, +}; + +enum rtd13xx_iso_isr_bits { + RTD13XX_ISO_ISR_TC3_SHIFT = 1, + RTD13XX_ISO_ISR_UR0_SHIFT = 2, + RTD13XX_ISO_ISR_LSADC0_SHIFT = 3, + RTD13XX_ISO_ISR_IRDA_SHIFT = 5, + RTD13XX_ISO_ISR_SPI1_SHIFT = 6, + RTD13XX_ISO_ISR_WDOG_NMI_SHIFT = 7, + RTD13XX_ISO_ISR_I2C0_SHIFT = 8, + RTD13XX_ISO_ISR_TC4_SHIFT = 9, + RTD13XX_ISO_ISR_TC7_SHIFT = 10, + RTD13XX_ISO_ISR_I2C1_SHIFT = 11, + RTD13XX_ISO_ISR_RTC_HSEC_SHIFT = 12, + RTD13XX_ISO_ISR_RTC_ALARM_SHIFT = 13, + RTD13XX_ISO_ISR_GPIOA_SHIFT = 19, + RTD13XX_ISO_ISR_GPIODA_SHIFT = 20, + RTD13XX_ISO_ISR_ISO_MISC_SHIFT = 21, + RTD13XX_ISO_ISR_CBUS_SHIFT = 22, + RTD13XX_ISO_ISR_ETN_SHIFT = 23, + RTD13XX_ISO_ISR_USB_HOST_SHIFT = 24, + RTD13XX_ISO_ISR_USB_U3_DRD_SHIFT = 25, + RTD13XX_ISO_ISR_USB_U2_DRD_SHIFT = 26, + RTD13XX_ISO_ISR_PORB_HV_SHIFT = 28, + RTD13XX_ISO_ISR_PORB_DV_SHIFT = 29, + RTD13XX_ISO_ISR_PORB_AV_SHIFT = 30, + RTD13XX_ISO_ISR_I2C1_REQ_SHIFT = 31, +}; + +static const u32 rtd13xx_iso_isr_to_scpu_int_en_mask[32] = { + [RTD13XX_ISO_ISR_SPI1_SHIFT] = BIT(1), + [RTD13XX_ISO_ISR_UR0_SHIFT] = BIT(2), + [RTD13XX_ISO_ISR_LSADC0_SHIFT] = BIT(3), + [RTD13XX_ISO_ISR_IRDA_SHIFT] = BIT(5), + [RTD13XX_ISO_ISR_I2C0_SHIFT] = BIT(8), + [RTD13XX_ISO_ISR_I2C1_SHIFT] = BIT(11), + [RTD13XX_ISO_ISR_RTC_HSEC_SHIFT] = BIT(12), + [RTD13XX_ISO_ISR_RTC_ALARM_SHIFT] = BIT(13), + [RTD13XX_ISO_ISR_GPIOA_SHIFT] = BIT(19), + [RTD13XX_ISO_ISR_GPIODA_SHIFT] = BIT(20), + [RTD13XX_ISO_ISR_PORB_HV_SHIFT] = BIT(28), + [RTD13XX_ISO_ISR_PORB_DV_SHIFT] = BIT(29), + [RTD13XX_ISO_ISR_PORB_AV_SHIFT] = BIT(30), + [RTD13XX_ISO_ISR_I2C1_REQ_SHIFT] = BIT(31), +}; + +enum rtd13xx_misc_isr_bits { + RTD13XX_ISR_WDOG_NMI_SHIFT = 2, + RTD13XX_ISR_UR1_SHIFT = 3, + RTD13XX_ISR_TC5_SHIFT = 4, + RTD13XX_ISR_UR1_TO_SHIFT = 5, + RTD13XX_ISR_TC0_SHIFT = 6, + RTD13XX_ISR_TC1_SHIFT = 7, + RTD13XX_ISR_UR2_SHIFT = 8, + RTD13XX_ISR_RTC_HSEC_SHIFT = 9, + RTD13XX_ISR_RTC_MIN_SHIFT = 10, + RTD13XX_ISR_RTC_HOUR_SHIFT = 11, + RTD13XX_ISR_RTC_DATE_SHIFT = 12, + RTD13XX_ISR_UR2_TO_SHIFT = 13, + RTD13XX_ISR_I2C5_SHIFT = 14, + RTD13XX_ISR_I2C3_SHIFT = 23, + RTD13XX_ISR_SC0_SHIFT = 24, + RTD13XX_ISR_SC1_SHIFT = 25, + RTD13XX_ISR_SPI_SHIFT = 27, + RTD13XX_ISR_FAN_SHIFT = 29, +}; + +static const u32 rtd13xx_misc_isr_to_scpu_int_en_mask[32] = { + [RTD13XX_ISR_UR1_SHIFT] = BIT(3), + [RTD13XX_ISR_UR1_TO_SHIFT] = BIT(5), + [RTD13XX_ISR_UR2_TO_SHIFT] = BIT(6), + [RTD13XX_ISR_UR2_SHIFT] = BIT(7), + [RTD13XX_ISR_RTC_MIN_SHIFT] = BIT(10), + [RTD13XX_ISR_RTC_HOUR_SHIFT] = BIT(11), + [RTD13XX_ISR_RTC_DATE_SHIFT] = BIT(12), + [RTD13XX_ISR_I2C5_SHIFT] = BIT(14), + [RTD13XX_ISR_SC0_SHIFT] = BIT(24), + [RTD13XX_ISR_SC1_SHIFT] = BIT(25), + [RTD13XX_ISR_SPI_SHIFT] = BIT(27), + [RTD13XX_ISR_I2C3_SHIFT] = BIT(28), + [RTD13XX_ISR_FAN_SHIFT] = BIT(29), + [RTD13XX_ISR_WDOG_NMI_SHIFT] = RTK_MUX_IRQ_ALWAYS_ENABLED, +}; + +enum rtd16xxb_iso_isr_bits { + RTD16XXB_ISO_ISR_TC3_SHIFT = 1, + RTD16XXB_ISO_ISR_UR0_SHIFT = 2, + RTD16XXB_ISO_ISR_LSADC0_SHIFT = 3, + RTD16XXB_ISO_ISR_WDOG1_NMI_SHIFT = 4, + RTD16XXB_ISO_ISR_IRDA_SHIFT = 5, + RTD16XXB_ISO_ISR_SPI1_SHIFT = 6, + RTD16XXB_ISO_ISR_WDOG2_NMI_SHIFT = 7, + RTD16XXB_ISO_ISR_I2C0_SHIFT = 8, + RTD16XXB_ISO_ISR_TC4_SHIFT = 9, + RTD16XXB_ISO_ISR_TC7_SHIFT = 10, + RTD16XXB_ISO_ISR_I2C1_SHIFT = 11, + RTD16XXB_ISO_ISR_HIFI_WAKEUP_SHIFT = 14, + RTD16XXB_ISO_ISR_WDOG4_NMI_SHIFT = 15, + RTD16XXB_ISO_ISR_TC8_SHIFT = 16, + RTD16XXB_ISO_ISR_VFD_SHIFT = 17, + RTD16XXB_ISO_ISR_VTC_SHIFT = 18, + RTD16XXB_ISO_ISR_GPIOA_SHIFT = 19, + RTD16XXB_ISO_ISR_GPIODA_SHIFT = 20, + RTD16XXB_ISO_ISR_ISO_MISC_SHIFT = 21, + RTD16XXB_ISO_ISR_CBUS_SHIFT = 22, + RTD16XXB_ISO_ISR_ETN_SHIFT = 23, + RTD16XXB_ISO_ISR_USB_HOST_SHIFT = 24, + RTD16XXB_ISO_ISR_USB_U3_DRD_SHIFT = 25, + RTD16XXB_ISO_ISR_USB_U2_DRD_SHIFT = 26, + RTD16XXB_ISO_ISR_WDOG3_NMI_SHIFT = 27, + RTD16XXB_ISO_ISR_PORB_HV_CEN_SHIFT = 28, + RTD16XXB_ISO_ISR_PORB_DV_CEN_SHIFT = 29, + RTD16XXB_ISO_ISR_PORB_AV_CEN_SHIFT = 30, + RTD16XXB_ISO_ISR_I2C1_REQ_SHIFT = 31, +}; +static const u32 rtd16xxb_iso_isr_to_scpu_int_en_mask[32] = { + [RTD16XXB_ISO_ISR_SPI1_SHIFT] = BIT(1), + [RTD16XXB_ISO_ISR_UR0_SHIFT] = BIT(2), + [RTD16XXB_ISO_ISR_LSADC0_SHIFT] = BIT(3), + [RTD16XXB_ISO_ISR_IRDA_SHIFT] = BIT(5), + [RTD16XXB_ISO_ISR_I2C0_SHIFT] = BIT(8), + [RTD16XXB_ISO_ISR_I2C1_SHIFT] = BIT(11), + [RTD16XXB_ISO_ISR_VFD_SHIFT] = BIT(17), + [RTD16XXB_ISO_ISR_GPIOA_SHIFT] = BIT(19), + [RTD16XXB_ISO_ISR_GPIODA_SHIFT] = BIT(20), + [RTD16XXB_ISO_ISR_PORB_HV_CEN_SHIFT] = BIT(28), + [RTD16XXB_ISO_ISR_PORB_DV_CEN_SHIFT] = BIT(29), + [RTD16XXB_ISO_ISR_PORB_AV_CEN_SHIFT] = BIT(30), + [RTD16XXB_ISO_ISR_I2C1_REQ_SHIFT] = BIT(31), + [RTD16XXB_ISO_ISR_WDOG1_NMI_SHIFT] = RTK_MUX_IRQ_ALWAYS_ENABLED, + [RTD16XXB_ISO_ISR_WDOG2_NMI_SHIFT] = RTK_MUX_IRQ_ALWAYS_ENABLED, + [RTD16XXB_ISO_ISR_WDOG3_NMI_SHIFT] = RTK_MUX_IRQ_ALWAYS_ENABLED, + [RTD16XXB_ISO_ISR_WDOG4_NMI_SHIFT] = RTK_MUX_IRQ_ALWAYS_ENABLED, +}; +enum rtd16xxb_misc_isr_bits { + RTD16XXB_ISR_UR1_SHIFT = 3, + RTD16XXB_ISR_TC5_SHIFT = 4, + RTD16XXB_ISR_UR1_TO_SHIFT = 5, + RTD16XXB_ISR_TC0_SHIFT = 6, + RTD16XXB_ISR_TC1_SHIFT = 7, + RTD16XXB_ISR_UR2_SHIFT = 8, + RTD16XXB_ISR_UR2_TO_SHIFT = 13, + RTD16XXB_ISR_I2C5_SHIFT = 14, + RTD16XXB_ISR_I2C4_SHIFT = 15, + RTD16XXB_ISR_I2C3_SHIFT = 23, + RTD16XXB_ISR_SC0_SHIFT = 24, + RTD16XXB_ISR_SC1_SHIFT = 25, + RTD16XXB_ISR_SPI_SHIFT = 27, + RTD16XXB_ISR_FAN_SHIFT = 29, +}; +static const u32 rtd16xxb_misc_isr_to_scpu_int_en_mask[32] = { + [RTD16XXB_ISR_UR1_SHIFT] = BIT(3), + [RTD16XXB_ISR_UR1_TO_SHIFT] = BIT(5), + [RTD16XXB_ISR_UR2_TO_SHIFT] = BIT(6), + [RTD16XXB_ISR_UR2_SHIFT] = BIT(7), + [RTD16XXB_ISR_I2C5_SHIFT] = BIT(14), + [RTD16XXB_ISR_I2C4_SHIFT] = BIT(15), + [RTD16XXB_ISR_SC0_SHIFT] = BIT(24), + [RTD16XXB_ISR_SC1_SHIFT] = BIT(25), + [RTD16XXB_ISR_SPI_SHIFT] = BIT(27), + [RTD16XXB_ISR_I2C3_SHIFT] = BIT(28), + [RTD16XXB_ISR_FAN_SHIFT] = BIT(29), +}; + +static struct realtek_irq_mux_subset_cfg rtd13xx_iso_irq_cfgs[] = { + { 0xffffcffe, }, + { 0x00003001, }, /* rtc */ +}; + +static const struct realtek_irq_mux_info rtd13xx_iso_irq_mux_info = { + .isr_offset = 0x0, + .umsk_isr_offset = 0x4, + .scpu_int_en_offset = 0x40, + .first_irq = 160, + .isr_to_scpu_int_en_mask = rtd13xx_iso_isr_to_scpu_int_en_mask, + .cfg = rtd13xx_iso_irq_cfgs, + .cfg_num = ARRAY_SIZE(rtd13xx_iso_irq_cfgs), +}; + +static struct realtek_irq_mux_subset_cfg rtd13xx_misc_irq_cfgs[] = { + { 0xffffc0d2, }, + { 0x00000004, }, /* wdt */ + { 0x00000028, }, /* ur1 */ + { 0x00002100, }, /* ur2 */ +}; + +static const struct realtek_irq_mux_info rtd13xx_misc_irq_mux_info = { + .umsk_isr_offset = 0x8, + .isr_offset = 0xc, + .scpu_int_en_offset = 0x80, + .first_irq = 192, + .isr_to_scpu_int_en_mask = rtd13xx_misc_isr_to_scpu_int_en_mask, + .cfg = rtd13xx_misc_irq_cfgs, + .cfg_num = ARRAY_SIZE(rtd13xx_misc_irq_cfgs), +}; + +static struct realtek_irq_mux_subset_cfg rtd16xxb_iso_irq_cfgs[] = { + { 0xf7ff7f6e, }, + { 0x08008090, }, /* wdt */ +}; + +static const struct realtek_irq_mux_info rtd16xxb_iso_irq_mux_info = { + .isr_offset = 0x0, + .umsk_isr_offset = 0x4, + .scpu_int_en_offset = 0x40, + .first_irq = 160, + .isr_to_scpu_int_en_mask = rtd16xxb_iso_isr_to_scpu_int_en_mask, + .cfg = rtd16xxb_iso_irq_cfgs, + .cfg_num = ARRAY_SIZE(rtd16xxb_iso_irq_cfgs), +}; + +static struct realtek_irq_mux_subset_cfg rtd16xxb_misc_irq_cfgs[] = { + { 0xffffded6, }, + { 0x00000028, }, /* ur1 */ + { 0x00002100, }, /* ur2 */ +}; + +static const struct realtek_irq_mux_info rtd16xxb_misc_irq_mux_info = { + .umsk_isr_offset = 0x8, + .isr_offset = 0xc, + .scpu_int_en_offset = 0x80, + .first_irq = 192, + .isr_to_scpu_int_en_mask = rtd16xxb_misc_isr_to_scpu_int_en_mask, + .cfg = rtd16xxb_misc_irq_cfgs, + .cfg_num = ARRAY_SIZE(rtd16xxb_misc_irq_cfgs), +}; + +static const struct of_device_id realtek_irq_mux_dt_matches[] = { + { + .compatible = "realtek,rtd13xx-iso-irq-mux", + .data = &rtd13xx_iso_irq_mux_info, + }, { + .compatible = "realtek,rtd13xx-misc-irq-mux", + .data = &rtd13xx_misc_irq_mux_info, + }, { + .compatible = "realtek,rtd16xxb-iso-irq-mux", + .data = &rtd16xxb_iso_irq_mux_info, + }, { + .compatible = "realtek,rtd16xxb-misc-irq-mux", + .data = &rtd16xxb_misc_irq_mux_info, + }, + { /* sentinel */ } +}; + +static int __init realtek_irq_mux_init_subset(struct device_node *node, + struct realtek_irq_mux_data *data, int index) +{ + int irq; + struct realtek_irq_mux_subset_data *subset_data = &data->subset_data[index]; + const struct realtek_irq_mux_subset_cfg *cfg = &data->info->cfg[index]; + + irq = irq_of_parse_and_map(node, index); + if (irq <= 0) + return irq; + + subset_data->common = data; + subset_data->cfg = cfg; + subset_data->parent_irq = irq; + irq_set_chained_handler_and_data(irq, realtek_mux_irq_handle, subset_data); + return 0; +} + +static int __init realtek_irq_mux_init(struct device_node *node, + struct device_node *parent) +{ + const struct of_device_id *match; + const struct realtek_irq_mux_info *info; + struct realtek_irq_mux_data *data; + int ret, i; + + match = of_match_node(realtek_irq_mux_dt_matches, node); + if (!match) + return -EINVAL; + + info = match->data; + if (!info) + return -EINVAL; + + data = kzalloc(struct_size(data, subset_data, info->cfg_num) , GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->base = syscon_regmap_lookup_by_phandle(node, "syscon"); + if (IS_ERR_OR_NULL(data->base)) { + return -EINVAL; + } + + data->info = info; + + spin_lock_init(&data->lock); + + data->domain = irq_domain_add_simple(node, 32, info->first_irq, &realtek_mux_irq_domain_ops, data); + if (!data->domain) { + kfree(data); + return -ENOMEM; + } + + data->subset_data_num = info->cfg_num; + for (i = 0; i < info->cfg_num; i++) { + ret = realtek_irq_mux_init_subset(node, data, i); + WARN(ret, "failed to init subset %d: %d", i, ret); + } + + return 0; +} +IRQCHIP_DECLARE(rtd13xx_iso_mux, "realtek,rtd13xx-iso-irq-mux", realtek_irq_mux_init); +IRQCHIP_DECLARE(rtd13xx_misc_mux, "realtek,rtd13xx-misc-irq-mux", realtek_irq_mux_init); +IRQCHIP_DECLARE(rtd16xxb_iso_mux, "realtek,rtd16xxb-iso-irq-mux", realtek_irq_mux_init); +IRQCHIP_DECLARE(rtd16xxb_misc_mux, "realtek,rtd16xxb-misc-irq-mux", realtek_irq_mux_init); diff --git a/drivers/irqchip/irq-realtek-mux.h b/drivers/irqchip/irq-realtek-mux.h new file mode 100644 index 000000000000..2f94ba5c01ed --- /dev/null +++ b/drivers/irqchip/irq-realtek-mux.h @@ -0,0 +1,126 @@ +/* + * irq-rtd13xx.h - RTK irq mux driver header file + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + * 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. + */ + +#ifndef IRQ_RTD13xx_H_ +#define IRQ_RTD13xx_H_ + +#define IRQ_INMUX 32 + +enum misc_int_en { + MISC_INT_FAIL = 0xFF, + MISC_INT_RVD = 0xFE, + MISC_INT_EN_FAN = 29, + MISC_INT_EN_I2C3 = 28, + MISC_INT_EN_SPI = 27, + MISC_INT_EN_SC1 = 25, + MISC_INT_EN_SC0 = 24, + MISC_INT_EN_I2C5 = 14, + MISC_INT_EN_RTC_DATE = 12, + MISC_INT_EN_RTC_HOUR = 11, + MISC_INT_EN_RTC_MIN = 10, + MISC_INT_EN_UR2 = 7, + MISC_INT_EN_UR2_TO = 6, + MISC_INT_EN_UR1_TO = 5, + MISC_INT_EN_UR1 = 3, + MISC_INT_EN_WDOG_NMI = 2, +}; + +enum iso_int_en { + ISO_INT_FAIL = 0xFF, + ISO_INT_RVD = 0xFE, + ISO_INT_EN_I2C1_REQ = 31, + ISO_INT_EN_GPHY_AV = 30, + ISO_INT_EN_GPHY_DV = 29, + ISO_INT_EN_GPHY_HV = 28, + ISO_INT_EN_GPIODA = 20, + ISO_INT_EN_GPIOA = 19, + ISO_INT_EN_RTC_ALARM = 13, + ISO_INT_EN_RTC_HSEC = 12, + ISO_INT_EN_I2C1 = 11, + ISO_INT_EN_I2C0 = 8, + ISO_INT_EN_IRDA = 5, + ISO_INT_EN_LSADC0 = 3, + ISO_INT_EN_UR0 = 2, + ISO_INT_EN_SPI1 = 1, +}; + +const unsigned char irq_map_tab[2][IRQ_INMUX] = { + { + MISC_INT_RVD, /* Bit0 */ + MISC_INT_RVD, /* Bit1 */ + MISC_INT_EN_WDOG_NMI, /* Bit2 */ + MISC_INT_EN_UR1, /* Bit3 */ + MISC_INT_RVD, /* Bit4 */ + MISC_INT_EN_UR1_TO, /* Bit5 */ + MISC_INT_EN_UR2_TO, /* Bit6 */ + MISC_INT_EN_UR2, /* Bit7 */ + MISC_INT_RVD, /* Bit8 */ + MISC_INT_RVD, /* Bit9 */ + MISC_INT_EN_RTC_MIN, /* Bit10 */ + MISC_INT_EN_RTC_HOUR, /* Bit11 */ + MISC_INT_EN_RTC_DATE, /* Bit12 */ + MISC_INT_RVD, /* Bit13 */ + MISC_INT_EN_I2C5, /* Bit14 */ + MISC_INT_RVD, /* Bit15 */ + MISC_INT_RVD, /* Bit16 */ + MISC_INT_RVD, /* Bit17 */ + MISC_INT_RVD, /* Bit18 */ + MISC_INT_RVD, /* Bit19 */ + MISC_INT_RVD, /* Bit20 */ + MISC_INT_RVD, /* Bit21 */ + MISC_INT_RVD, /* Bit22 */ + MISC_INT_EN_I2C3, /* Bit23 */ + MISC_INT_EN_SC0, /* Bit24 */ + MISC_INT_EN_SC1, /* Bit25 */ + MISC_INT_RVD, /* Bit26 */ + MISC_INT_EN_SPI, /* Bit27 */ + MISC_INT_RVD, /* Bit28 */ + MISC_INT_EN_FAN, /* Bit29 */ + MISC_INT_RVD, /* Bit30 */ + MISC_INT_RVD, /* Bit31 */ + }, + { + ISO_INT_RVD, /* Bit0 */ + ISO_INT_EN_SPI1, /* Bit1 */ + ISO_INT_EN_UR0, /* Bit2 */ + ISO_INT_EN_LSADC0, /* Bit3 */ + ISO_INT_RVD, /* Bit4 */ + ISO_INT_EN_IRDA, /* Bit5 */ + ISO_INT_RVD, /* Bit6 */ + ISO_INT_RVD, /* Bit7 */ + ISO_INT_EN_I2C0, /* Bit8 */ + ISO_INT_RVD, /* Bit9 */ + ISO_INT_RVD, /* Bit10 */ + ISO_INT_EN_I2C1, /* Bit11 */ + ISO_INT_EN_RTC_HSEC, /* Bit12 */ + ISO_INT_EN_RTC_ALARM, /* Bit13 */ + ISO_INT_RVD, /* Bit14 */ + ISO_INT_RVD, /* Bit15 */ + ISO_INT_RVD, /* Bit16 */ + ISO_INT_RVD, /* Bit17 */ + ISO_INT_RVD, /* Bit18 */ + ISO_INT_EN_GPIOA, /* Bit19 */ + ISO_INT_EN_GPIODA, /* Bit20 */ + ISO_INT_RVD, /* Bit21 */ + ISO_INT_RVD, /* Bit22 */ + ISO_INT_RVD, /* Bit23 */ + ISO_INT_RVD, /* Bit24 */ + ISO_INT_RVD, /* Bit25 */ + ISO_INT_RVD, /* Bit26 */ + ISO_INT_RVD, /* Bit27 */ + ISO_INT_EN_GPHY_HV, /* Bit28 */ + ISO_INT_EN_GPHY_DV, /* Bit29 */ + ISO_INT_EN_GPHY_AV, /* Bit30 */ + ISO_INT_EN_I2C1_REQ, /* Bit31 */ + } +}; + +#endif /* IRQ_RTD13xx_H_ */ diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 56e8198e13d1..048021b07ca3 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -371,6 +371,15 @@ config LEDS_GPIO defined as platform devices and/or OpenFirmware platform devices. The code to use these bindings can be selected below. +config LEDS_LP3943 + tristate "LED Support for N.S. LP3943 (Fun Light) I2C chip" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to the National + Semiconductor LP3943 Lighting Management Unit (LMU) also known as + Fun Light Chip. + config LEDS_LP3944 tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 73e603e1727e..1cb1f8e34815 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o +obj-$(CONFIG_LEDS_LP3943) += leds-lp3943.o obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o obj-$(CONFIG_LEDS_LP3952) += leds-lp3952.o obj-$(CONFIG_LEDS_LP50XX) += leds-lp50xx.o @@ -93,6 +94,8 @@ obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o +obj-$(CONFIG_SYNO_LED_ATMEGA1608) += leds-atmega1608.o +obj-$(CONFIG_SYNO_LED_ATMEGA1608_SEG7) += leds-atmega1608-seg7.o # LED SPI Drivers obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4365c1cc4505..3a886072a547 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * LED Class Core @@ -249,6 +252,38 @@ struct led_classdev *of_led_get(struct device_node *np, int index) } EXPORT_SYMBOL_GPL(of_led_get); +#ifdef MY_DEF_HERE +/** + * of_leddev_get() - request a LED device via the LED framework + * @np: device node to get the LED device from + * + * Returns the LED device parsed from the phandle + * property of a device tree node or a negative error-code on failure. + */ +struct led_classdev *of_leddev_get(struct device_node *led_node) +{ + struct device *led_dev; + struct led_classdev *led_cdev; + + if (!led_node) + return ERR_PTR(-ENOENT); + + led_dev = class_find_device_by_of_node(leds_class, led_node); + of_node_put(led_node); + + if (!led_dev) + return ERR_PTR(-EPROBE_DEFER); + + led_cdev = dev_get_drvdata(led_dev); + + if (!try_module_get(led_cdev->dev->parent->driver->owner)) + return ERR_PTR(-ENODEV); + + return led_cdev; +} +EXPORT_SYMBOL_GPL(of_leddev_get); +#endif /* MY_DEF_HERE */ + /** * led_put() - release a LED device * @led_cdev: LED device diff --git a/drivers/leds/leds-atmega1608-seg7.c b/drivers/leds/leds-atmega1608-seg7.c new file mode 100644 index 000000000000..74fe7f9daa6b --- /dev/null +++ b/drivers/leds/leds-atmega1608-seg7.c @@ -0,0 +1,688 @@ +/* + * Copyright (c) 2000-2021 Synology Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "atmega1608_seg7" + +#define MAX_NUM_LEDS 24 +#define MAX_NUM_SEG7 3 +#define NUM_LEDS_IN_SEG7 8 +#define LED_OFF 0 + +#define BRIGHTNESS_ON 255 +#define BRIGHTNESS_OFF 0 + +/* Registers */ +#define ATMEGA1608_INPUT1 0x00 +#define ATMEGA1608_INPUT2 0x01 +#define ATMEGA1608_PSC0 0x02 +#define ATMEGA1608_PWM0 0x03 +#define ATMEGA1608_PSC1 0x04 +#define ATMEGA1608_PWM1 0x05 +#define ATMEGA1608_LS0 0x06 +#define ATMEGA1608_LS1 0x07 +#define ATMEGA1608_LS2 0x08 +#define ATMEGA1608_LS3 0x09 +#define ATMEGA1608_LS4 0x0A +#define ATMEGA1608_LS5 0x0B + +/* Mask, shift */ +#define ATMEGA1608_MASK_M 0x01 +#define ATMEGA1608_SEL0_M 0x03 +#define ATMEGA1608_SEL1_M 0x0C +#define ATMEGA1608_SEL2_M 0x30 +#define ATMEGA1608_SEL3_M 0xC0 +#define ATMEGA1608_MASK_S 0 +#define ATMEGA1608_SEL0_S 0 +#define ATMEGA1608_SEL1_S 2 +#define ATMEGA1608_SEL2_S 4 +#define ATMEGA1608_SEL3_S 6 + +#define SIZE_END_CHAR 1 +#define SIZE_CHAR_ARRAY 64 + +#define SYNO_ATMEGA1608_MAX_RETRY 5 + +static DEFINE_MUTEX(ModeLock); + +static const u8 map_char[] = { + ' ', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', +}; + + // 7-segment map: + + // AAA + // F B + // F B + // GGG + // E C + // E C + // DDD H + +static const u8 map_digit[] = { + //HGFEDCBA char + 0b00000000, // ' ' + 0b00111111, // '0' + 0b00000110, // '1' + 0b01011011, // '2' + 0b01001111, // '3' + 0b01100110, // '4' + 0b01101101, // '5' + 0b01111101, // '6' + 0b00100111, // '7' + 0b01111111, // '8' + 0b01101111, // '9' +}; + +static const u8 mask_sel[] = { + ATMEGA1608_SEL0_M, + ATMEGA1608_SEL1_M, + ATMEGA1608_SEL2_M, + ATMEGA1608_SEL3_M, +}; + +static const u8 shift_sel[] = { + ATMEGA1608_SEL0_S, + ATMEGA1608_SEL1_S, + ATMEGA1608_SEL2_S, + ATMEGA1608_SEL3_S, +}; + +struct atmega1608_led_node { + int mode; + u8 prescale; + int channel; //read from dts seg_led_map +}; + +struct atmega1608_led { + int id; + struct atmega1608_led_node node; + struct work_struct brtwork; + u8 brightness; + int retry_count; +}; + +struct atmega1608_seg7 { + int id; + int num_leds; + struct atmega1608_led led[NUM_LEDS_IN_SEG7]; +}; + +struct atmega1608 { + char name[SIZE_CHAR_ARRAY]; + char display_number[SIZE_CHAR_ARRAY]; + int device_index; //read from dts device_index + struct i2c_client *client; + struct device *dev; + struct atmega1608_seg7 seg7[MAX_NUM_SEG7]; + int num_map_char; + int num_seg7; //read from dts seg7_num + int num_leds_in_seg7; + struct device_attribute dev_attr; + struct led_classdev cdev; +}; + +static int atmega1608_read_byte(struct atmega1608 *at, u8 reg, u8 *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(at->client, reg); + if (ret < 0) { + dev_err(at->dev, "failed to read 0x%.2x\n", reg); + return ret; + } + + *data = (u8)ret; + return 0; +} + +static int atmega1608_write_byte(struct atmega1608 *at, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(at->client, reg, data); +} + +static int atmega1608_update_bits(struct atmega1608 *at, u8 reg, u8 mask, u8 data) +{ + int ret; + u8 tmp; + + mutex_lock(&ModeLock); + ret = atmega1608_read_byte(at, reg, &tmp); + if (ret) { + goto End; + } + + tmp &= ~mask; + tmp |= data & mask; + + ret = atmega1608_write_byte(at, reg, tmp); + +End: + mutex_unlock(&ModeLock); + return ret; +} + +static int atmega1608_update_selector(struct atmega1608 *at, enum atmega1608_seg7_led_mode mode, + enum atmega1608_seg7_led_channel channel) +{ + u8 addr, mask, shift, idx; + + switch (channel) { + case ATMEGA1608_LED0 ... ATMEGA1608_LED3: + addr = ATMEGA1608_LS0; + break; + case ATMEGA1608_LED4 ... ATMEGA1608_LED7: + addr = ATMEGA1608_LS1; + break; + case ATMEGA1608_LED8 ... ATMEGA1608_LED11: + addr = ATMEGA1608_LS2; + break; + case ATMEGA1608_LED12 ... ATMEGA1608_LED15: + addr = ATMEGA1608_LS3; + break; + case ATMEGA1608_LED16 ... ATMEGA1608_LED19: + addr = ATMEGA1608_LS4; + break; + case ATMEGA1608_LED20 ... ATMEGA1608_LED23: + addr = ATMEGA1608_LS5; + break; + default: + return -EINVAL; + } + + idx = channel % 4; + mask = mask_sel[idx]; + shift = shift_sel[idx]; + + return atmega1608_update_bits(at, addr, mask, mode << shift); +} + +static int atmega1608_update_scale(struct atmega1608 *at, enum atmega1608_seg7_led_mode mode, + u8 prescale) +{ + u8 addr; + + switch (mode) { + case ATMEGA1608_LED_DIM0: + addr = ATMEGA1608_PSC0; + break; + case ATMEGA1608_LED_DIM1: + addr = ATMEGA1608_PSC1; + break; + default: + return 0; + } + + return atmega1608_write_byte(at, addr, prescale); +} + +static int atmega1608_update_pwm(struct atmega1608 *at, enum atmega1608_seg7_led_mode mode, + u8 pwm) +{ + u8 addr; + + switch (mode) { + case ATMEGA1608_LED_DIM0: + addr = ATMEGA1608_PWM0; + break; + case ATMEGA1608_LED_DIM1: + addr = ATMEGA1608_PWM1; + break; + default: + return 0; + } + + return atmega1608_write_byte(at, addr, pwm); +} + +static void atmega1608_syno_brightness_set(u8 brightness, enum atmega1608_seg7_led_mode *mode, enum atmega1608_seg7_led_mode nodeMode) +{ + if (!mode) { + goto End; + } + switch (brightness) { + case 0: + *mode = ATMEGA1608_LED_OFF; + break; + case 255: + *mode = ATMEGA1608_LED_ON; + break; + default: + *mode = nodeMode; + break; + } + +End: + return; +} + +static int atmega1608_update_brightness(struct atmega1608_led *led) +{ + struct atmega1608_seg7 *seg7 = container_of(led, struct atmega1608_seg7, led[led->id]); + struct atmega1608 *at = container_of(seg7, struct atmega1608, seg7[seg7->id]); + struct atmega1608_led_node *node = &led->node; + enum atmega1608_seg7_led_mode mode; + int ret; + + + atmega1608_syno_brightness_set(led->brightness, &mode, node->mode); + + ret = atmega1608_update_selector(at, mode, node->channel); + if (ret) { + return ret; + } + + if (mode == ATMEGA1608_LED_OFF || mode == ATMEGA1608_LED_ON) { + return 0; + } + + ret = atmega1608_update_scale(at, mode, node->prescale); + if (ret) { + return ret; + } + + ret = atmega1608_update_pwm(at, mode, led->brightness); + if (ret) { + return ret; + } + + return 0; +} + +static void atmega1608_brightness_force_off(struct atmega1608 *at) +{ + int i; + u8 addr[] = { ATMEGA1608_LS0, ATMEGA1608_LS1, ATMEGA1608_LS2, ATMEGA1608_LS3, ATMEGA1608_LS4, ATMEGA1608_LS5 }; + + for (i = 0 ; i < ARRAY_SIZE(addr) ; i++) + atmega1608_write_byte(at, addr[i], LED_OFF); +} + +static void atmega1608_brightness_work(struct work_struct *work) +{ + int ret = 0; + struct atmega1608_led *led; + + led = container_of(work, struct atmega1608_led, brtwork); + ret = atmega1608_update_brightness(led); + + if (ret) { + if (led->retry_count < SYNO_ATMEGA1608_MAX_RETRY) { + ++led->retry_count; + pr_err("%s: retry to recover led_%d for %d times\n", + __func__, led->id, led->retry_count); + schedule_work(&led->brtwork); + } else { + pr_err("%s: failed to recover led_%d\n", + __func__, led->id); + } + } else { + led->retry_count = 0; + } +} + +static int character_valid_check(u8 ch) { + int i; + for (i = 0 ; i < ARRAY_SIZE(map_char) ; i++) { + if (ch == map_char[i]) { + return 0; + } + } + return -EINVAL; +} + +static int character_index_find(u8 ch) { + int i; + for (i = 0 ; i < ARRAY_SIZE(map_char) ; i++) { + if (ch == map_char[i]) { + return i; + } + } + return -EINVAL; +} + +static void atmega1608_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i, j; + struct atmega1608 *at; + + at = container_of(led_cdev, struct atmega1608, cdev); + if(0 != brightness) { + return; + } + + for (i = 0 ; i < at->num_seg7 ; i++) { + for (j = 0 ; j < at->num_leds_in_seg7 ; j++) { + at->seg7[i].led[j].brightness = BRIGHTNESS_OFF; + schedule_work(&at->seg7[i].led[j].brtwork); + } + } +} + +static ssize_t atmega1608_seg7_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct atmega1608 *at; + + at = container_of(attr, struct atmega1608, dev_attr); + + memcpy(buf, at->display_number, at->num_seg7 + SIZE_END_CHAR); + return (at->num_seg7 + SIZE_END_CHAR); +} + +static ssize_t atmega1608_seg7_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int i, j, ret; + u8 map_index; + u8 digit; + struct atmega1608 *at; + size_t input_size = 0; + size_t noshow_size = 0; + + at = container_of(attr, struct atmega1608, dev_attr); + + if (count > (at->num_seg7 + SIZE_END_CHAR)) { + printk("ERROR: Invalid Input Size\n"); + goto End; + } + input_size = count - 1; + noshow_size = at->num_seg7 - input_size; + + for (i = 0 ; i < input_size ; i++) { + ret = character_valid_check(buf[i]); + if (ret) { + printk("ERROR: Invalid Input Character\n"); + goto End; + } + } + + for (i = 0 ; i < noshow_size ; i++) { + for (j = 0 ; j < at->num_leds_in_seg7 ; j++) { + at->seg7[i].led[j].brightness = BRIGHTNESS_OFF; + schedule_work(&at->seg7[i].led[j].brtwork); + } + } + for (i = noshow_size ; i < at->num_seg7 ; i++) { + map_index = character_index_find(buf[i - noshow_size]); + digit = map_digit[map_index]; + for (j = 0 ; j < at->num_leds_in_seg7 ; j++) { + if ((digit >> j) & 0x1) { + at->seg7[i].led[j].brightness = BRIGHTNESS_ON; + } else { + at->seg7[i].led[j].brightness = BRIGHTNESS_OFF; + } + schedule_work(&at->seg7[i].led[j].brtwork); + } + } + + snprintf(at->display_number, SIZE_CHAR_ARRAY, buf); + return count; +End: + return -EIO; +} + +static int atmega1608_seg7_initial(struct atmega1608 *at) +{ + int i, j; + + for (i = 0 ; i < at->num_seg7 ; i++) { + at->seg7[i].id = i; + at->seg7[i].num_leds = NUM_LEDS_IN_SEG7; + for (j = 0 ; j < at->num_leds_in_seg7 ; j++) { + at->seg7[i].led[j].id = j; + at->seg7[i].led[j].node.mode = ATMEGA1608_LED_DIM0; + at->seg7[i].led[j].node.prescale = 30; + at->seg7[i].led[j].retry_count = 0; + INIT_WORK(&at->seg7[i].led[j].brtwork, atmega1608_brightness_work); + } + } + + return 0; +} + +static int atmega1608_leds_mask(struct atmega1608* at, + enum atmega1608_seg7_led_mask led_mask) +{ + u8 addr, mask, shift; + + addr = ATMEGA1608_INPUT2; + mask = ATMEGA1608_MASK_M; + shift = ATMEGA1608_MASK_S; + + return atmega1608_update_bits(at, addr, mask, led_mask << shift); +} + +static int atmega1608_chip_detect(struct atmega1608 *at) +{ + u8 val; + return atmega1608_read_byte(at, ATMEGA1608_INPUT1, &val); +} + +static int atmega1608_device_tree_read(struct atmega1608 *at, struct i2c_client *cl) +{ + int i = 0, j = 0; + int ret = 0; + struct device_node *pI2CNode = NULL; + struct device_node *pI2CDevNode = NULL; + char *seg7_led_map_name = NULL; + + if (NULL == at || NULL == cl) { + printk("ERROR: at pointer or cl pointer is NULL"); + goto Err; + } + + if (!of_root) { + printk("ERROR: of_root is NULL"); + goto Err; + } + + pI2CNode = syno_of_i2c_adapter_match(cl->adapter); + if (!pI2CNode) { + dev_err(at->dev, "i2c device match err - i2c node\n"); + goto Err; + } + + pI2CDevNode = syno_of_i2c_device_match(cl, DRIVER_NAME, pI2CNode); + if (!pI2CDevNode) { + dev_err(at->dev, "i2c device match err - i2c device node\n"); + goto Err; + } + + ret = of_property_read_u32_index(pI2CDevNode, DT_DEVICE_INDEX, 0, &at->device_index); + if (ret) { + dev_err(at->dev, "not found device_index err - i2c device node\n"); + goto Err; + } + + ret = of_property_read_u32_index(pI2CDevNode, DT_SEG7_NUM, 0, &at->num_seg7); + if (ret) { + dev_err(at->dev, "not found seg7_num err\n"); + goto Err; + } + if (0 > at->num_seg7 || MAX_NUM_SEG7 < at->num_seg7) { + goto Err; + } + + for (i = 0 ; i < at->num_seg7 ; i++) { + + switch (i) { + case 0: + seg7_led_map_name = DT_SEG7_LED_MAP_0; + break; + case 1: + seg7_led_map_name = DT_SEG7_LED_MAP_1; + break; + case 2: + seg7_led_map_name = DT_SEG7_LED_MAP_2; + break; + default: + goto Err; + } + + for (j = 0 ; j < at->num_leds_in_seg7 ; j++) { + ret = of_property_read_u32_index(pI2CDevNode, seg7_led_map_name, j, &at->seg7[i].led[j].node.channel); + if (ret) { + dev_err(at->dev, "not found index %d in %s err\n", j, seg7_led_map_name); + goto Err; + } + if (0 > at->seg7[i].led[j].node.channel || MAX_NUM_LEDS < at->seg7[i].led[j].node.channel) { + goto Err; + } + } + } + + return 0; +Err: + return -EINVAL; +} + +static int atmega1608_probe(struct i2c_client *cl, + const struct i2c_device_id *id) +{ + struct atmega1608 *at = NULL; + int ret; + int i; + + if (NULL == cl || NULL == id) { + goto End; + } + + if (ARRAY_SIZE(map_char) != ARRAY_SIZE(map_digit)) { + goto End; + } + + at = devm_kzalloc(&cl->dev, sizeof(struct atmega1608), GFP_KERNEL); + if (!at) { + goto End; + } + + at->client = cl; + at->dev = &cl->dev; + at->num_map_char = ARRAY_SIZE(map_char); + at->num_leds_in_seg7 = NUM_LEDS_IN_SEG7; + + i2c_set_clientdata(cl, at); + + ret = atmega1608_device_tree_read(at, cl); + if (ret) { + dev_err(at->dev, "fail to get device tree\n"); + goto FreeEnd; + } + + ret = atmega1608_chip_detect(at); + if (ret) { + dev_err(at->dev, "chip detection err: %d\n", ret); + goto FreeEnd; + } + + ret = atmega1608_leds_mask(at, ATMEGA1608_LED_UNMASK); + if (ret) { + dev_err(at->dev, "let unmask err: %d\n", ret); + goto FreeEnd; + } + + ret = atmega1608_seg7_initial(at); + if (ret) { + dev_err(at->dev, "seg7 initial err: %d\n", ret); + goto FreeEnd; + } + + for (i = 0 ; i < at->num_seg7 ; i++) { + at->display_number[i] = ' '; + } + at->display_number[at->num_seg7] = '\0'; + snprintf(at->name, SIZE_CHAR_ARRAY, "syno_seg7_%d", at->device_index); + at->cdev.name = at->name; + at->cdev.max_brightness = 0; + at->cdev.brightness_set = atmega1608_brightness_set; + at->dev_attr.attr.name = "display"; + at->dev_attr.attr.mode = (S_IRUGO | S_IWUSR); + at->dev_attr.show = atmega1608_seg7_show; + at->dev_attr.store = atmega1608_seg7_store; + + ret = led_classdev_register(at->dev, &at->cdev); + if (ret) { + dev_err(at->dev, "led class device register err\n"); + goto FreeEnd; + } + + ret = device_create_file(at->cdev.dev, &at->dev_attr); + if (ret) { + printk("ERROR: class file can not be created!\n"); + goto FreeEnd; + } + + return 0; +FreeEnd: + devm_kfree(&cl->dev, at); +End: + return -EINVAL; +} + +static int atmega1608_remove(struct i2c_client *cl) +{ + int i, j; + struct atmega1608 *at = i2c_get_clientdata(cl); + + device_remove_file(at->cdev.dev, &at->dev_attr); + led_classdev_unregister(&at->cdev); + for (i = 0 ; i < at->num_seg7 ; i++) { + for (j = 0 ; j < at->num_leds_in_seg7 ; j++) { + cancel_work_sync(&at->seg7[i].led[j].brtwork); + } + } + atmega1608_brightness_force_off(at); + atmega1608_leds_mask(at, ATMEGA1608_LED_MASKED); + devm_kfree(&cl->dev, at); + + return 0; +} + +static const struct i2c_device_id atmega1608_id[] = { + {DRIVER_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, atmega1608_id); + +static struct i2c_driver atmega1608_driver = { + .probe = atmega1608_probe, + .remove = atmega1608_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .id_table = atmega1608_id, +}; + +module_i2c_driver(atmega1608_driver); + +MODULE_DESCRIPTION("ATMEGA1608 LED SEVEN SEGMENT Driver"); +MODULE_AUTHOR("Jack Zhang"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-atmega1608.c b/drivers/leds/leds-atmega1608.c new file mode 100644 index 000000000000..f97e6d63c59e --- /dev/null +++ b/drivers/leds/leds-atmega1608.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2000-2021 Synology Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NUM_LEDS 24 +#define MAX_BRIGHTNESS 255 +#define LED_OFF 0 + +/* Registers */ +#define ATMEGA1608_INPUT1 0x00 +#define ATMEGA1608_PSC0 0x02 +#define ATMEGA1608_PWM0 0x03 +#define ATMEGA1608_PSC1 0x04 +#define ATMEGA1608_PWM1 0x05 +#define ATMEGA1608_LS0 0x06 +#define ATMEGA1608_LS1 0x07 +#define ATMEGA1608_LS2 0x08 +#define ATMEGA1608_LS3 0x09 +#define ATMEGA1608_LS4 0x0A +#define ATMEGA1608_LS5 0x0B + +/* Mask, shift */ +#define ATMEGA1608_SEL0_M 0x03 +#define ATMEGA1608_SEL1_M 0x0C +#define ATMEGA1608_SEL2_M 0x30 +#define ATMEGA1608_SEL3_M 0xC0 +#define ATMEGA1608_SEL0_S 0 +#define ATMEGA1608_SEL1_S 2 +#define ATMEGA1608_SEL2_S 4 +#define ATMEGA1608_SEL3_S 6 + +extern char **syno_led_trigger_name; + +static const u8 mask_sel[] = { + ATMEGA1608_SEL0_M, + ATMEGA1608_SEL1_M, + ATMEGA1608_SEL2_M, + ATMEGA1608_SEL3_M, +}; + +static const u8 shift_sel[] = { + ATMEGA1608_SEL0_S, + ATMEGA1608_SEL1_S, + ATMEGA1608_SEL2_S, + ATMEGA1608_SEL3_S, +}; + +struct atmega1608_led { + int id; + struct led_classdev cdev; + struct atmega1608_led_node *node; + struct work_struct brtwork; + u8 brightness; + int retry_count; +}; + +struct atmega1608 { + struct i2c_client *client; + struct device *dev; + struct atmega1608_led led[MAX_NUM_LEDS]; + int num_leds; +}; + +static DEFINE_MUTEX(ModeLock); + +struct atmega1608_led_node syno_led_nodes[24] = {}; + +struct atmega1608_platform_data syno_atmega1608_pdata = { + .node = syno_led_nodes, + .num_nodes = ARRAY_SIZE(syno_led_nodes), +}; + +#define SYNO_ATMEGA1608_MAX_RETRY 5 + +static int atmega1608_read_byte(struct atmega1608 *at, u8 reg, u8 *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(at->client, reg); + if (ret < 0) { + dev_err(at->dev, "failed to read 0x%.2x\n", reg); + return ret; + } + + *data = (u8)ret; + return 0; +} + +static int atmega1608_write_byte(struct atmega1608 *at, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(at->client, reg, data); +} + +static int atmega1608_update_bits(struct atmega1608 *at, u8 reg, u8 mask, u8 data) +{ + int ret; + u8 tmp; + + mutex_lock(&ModeLock); + ret = atmega1608_read_byte(at, reg, &tmp); + if (ret) { + goto END; + } + + tmp &= ~mask; + tmp |= data & mask; + + ret = atmega1608_write_byte(at, reg, tmp); + +END: + mutex_unlock(&ModeLock); + return ret; +} + +static int atmega1608_update_selector(struct atmega1608 *at, enum atmega1608_led_mode mode, + enum atmega1608_led_channel channel) +{ + u8 addr, mask, shift, idx; + + switch (channel) { + case ATMEGA1608_LED0 ... ATMEGA1608_LED3: + addr = ATMEGA1608_LS0; + break; + case ATMEGA1608_LED4 ... ATMEGA1608_LED7: + addr = ATMEGA1608_LS1; + break; + case ATMEGA1608_LED8 ... ATMEGA1608_LED11: + addr = ATMEGA1608_LS2; + break; + case ATMEGA1608_LED12 ... ATMEGA1608_LED15: + addr = ATMEGA1608_LS3; + break; + case ATMEGA1608_LED16 ... ATMEGA1608_LED19: + addr = ATMEGA1608_LS4; + break; + case ATMEGA1608_LED20 ... ATMEGA1608_LED23: + addr = ATMEGA1608_LS5; + break; + default: + return -EINVAL; + } + + idx = channel % 4; + mask = mask_sel[idx]; + shift = shift_sel[idx]; + + return atmega1608_update_bits(at, addr, mask, mode << shift); +} + +static int atmega1608_update_scale(struct atmega1608 *at, enum atmega1608_led_mode mode, + u8 prescale) +{ + u8 addr; + + switch (mode) { + case ATMEGA1608_LED_DIM0: + addr = ATMEGA1608_PSC0; + break; + case ATMEGA1608_LED_DIM1: + addr = ATMEGA1608_PSC1; + break; + default: + return 0; + } + + return atmega1608_write_byte(at, addr, prescale); +} + +static int atmega1608_update_pwm(struct atmega1608 *at, enum atmega1608_led_mode mode, + u8 pwm) +{ + u8 addr; + + switch (mode) { + case ATMEGA1608_LED_DIM0: + addr = ATMEGA1608_PWM0; + break; + case ATMEGA1608_LED_DIM1: + addr = ATMEGA1608_PWM1; + break; + default: + return 0; + } + + return atmega1608_write_byte(at, addr, pwm); +} + +static void atmega1608_syno_brightness_set(u8 brightness, enum atmega1608_led_mode *mode, enum atmega1608_led_mode nodeMode) +{ + if (!mode) { + goto END; + } + switch (brightness) { + case 0: + *mode = ATMEGA1608_LED_OFF; + break; + case 255: + *mode = ATMEGA1608_LED_ON; + break; + default: + *mode = nodeMode; + break; + } + +END: + return; +} + +static int atmega1608_update_brightness(struct atmega1608_led *led) +{ + struct atmega1608 *at = container_of(led, struct atmega1608, led[led->id]); + struct atmega1608_led_node *node = led->node; + enum atmega1608_led_mode mode; + int ret; + + + atmega1608_syno_brightness_set(led->brightness, &mode, node->mode); + + ret = atmega1608_update_selector(at, mode, node->channel); + if (ret) { + return ret; + } + + if (mode == ATMEGA1608_LED_OFF || mode == ATMEGA1608_LED_ON) { + return 0; + } + + ret = atmega1608_update_scale(at, mode, node->prescale); + if (ret) { + return ret; + } + + ret = atmega1608_update_pwm(at, mode, led->brightness); + if (ret) { + return ret; + } + + return 0; +} + +static void atmega1608_brightness_force_off(struct atmega1608 *at) +{ + int i; + u8 addr[] = { ATMEGA1608_LS0, ATMEGA1608_LS1, ATMEGA1608_LS2, ATMEGA1608_LS3, ATMEGA1608_LS4, ATMEGA1608_LS5 }; + + for (i = 0 ; i < ARRAY_SIZE(addr) ; i++) + atmega1608_write_byte(at, addr[i], LED_OFF); +} + +static void atmega1608_brightness_work(struct work_struct *work) +{ + int ret = 0; + struct atmega1608_led *led; + + led = container_of(work, struct atmega1608_led, brtwork); + ret = atmega1608_update_brightness(led); + + if (ret) { + if (led->retry_count < SYNO_ATMEGA1608_MAX_RETRY) { + ++led->retry_count; + pr_err("%s: retry to recover %s for %d times\n", + __func__, led->node->name, led->retry_count); + schedule_work(&led->brtwork); + } else { + pr_err("%s: failed to recover %s\n", + __func__, led->node->name); + } + } else { + led->retry_count = 0; + } +} + +static void atmega1608_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct atmega1608_led *led; + + led = container_of(led_cdev, struct atmega1608_led, cdev); + if(brightness == led->brightness) { + return; + } + led->brightness = brightness; + schedule_work(&led->brtwork); +} + +static int atmega1608_leds_register(struct atmega1608 *at, + struct atmega1608_platform_data *pdata) +{ + struct atmega1608_led_node *node; + int i, ret; + + for (i = 0 ; i < at->num_leds ; i++) { + node = pdata->node + i; + + if (!node || !node->name) { + dev_err(at->dev, "invalid data on node%d\n", i); + ret = -EINVAL; + goto err_dev; + } + + INIT_WORK(&at->led[i].brtwork, atmega1608_brightness_work); + at->led[i].id = i; + at->led[i].node = node; + at->led[i].cdev.name = node->name; + at->led[i].cdev.max_brightness = MAX_BRIGHTNESS; + at->led[i].cdev.brightness_set = atmega1608_brightness_set; + at->led[i].cdev.default_trigger = node->default_trigger; + at->led[i].retry_count = 0; + + ret = led_classdev_register(at->dev, &at->led[i].cdev); + if (ret) { + dev_err(at->dev, "led(%d/%d) register err: %d\n", + i, at->num_leds, ret); + goto err_dev; + } + } + + return 0; + +err_dev: + while (--i >= 0) { + led_classdev_unregister(&at->led[i].cdev); + cancel_work_sync(&at->led[i].brtwork); + } + return ret; +} + +static void atmega1608_leds_unregister(struct atmega1608 *at) +{ + int i; + + for (i = 0 ; i < at->num_leds ; i++) { + led_classdev_unregister(&at->led[i].cdev); + cancel_work_sync(&at->led[i].brtwork); + } +} + +static int atmega1608_validate_platform_data(struct device *dev, + struct atmega1608_platform_data *pdata) +{ + if (!pdata || !pdata->node) { + dev_err(dev, "invalid platform data\n"); + goto err; + } + + if (pdata->num_nodes == 0 || pdata->num_nodes > MAX_NUM_LEDS) { + dev_err(dev, "invalid num_nodes: %d\n", pdata->num_nodes); + goto err; + } + + return 0; +err: + return -EINVAL; +} + +static int atmega1608_chip_detect(struct atmega1608 *at) +{ + u8 val; + return atmega1608_read_byte(at, ATMEGA1608_INPUT1, &val); +} + +static int atmega1608_probe(struct i2c_client *cl, + const struct i2c_device_id *id) +{ + struct atmega1608 *at = NULL; + struct atmega1608_platform_data *pdata = NULL; + int device_index = 0; + struct device_node *pI2CNode = NULL; + struct device_node *pI2CDevNode = NULL; + int ret; + char *drv_name = "atmega1608"; + int i = 0; + + if (NULL == cl || NULL == id) { + goto END; + } + + pdata = &syno_atmega1608_pdata; + + ret = atmega1608_validate_platform_data(&cl->dev, pdata); + if (ret) { + goto END; + } + + at = devm_kzalloc(&cl->dev, sizeof(struct atmega1608), GFP_KERNEL); + if (!at) { + goto END; + } + + + at->client = cl; + at->dev = &cl->dev; + at->num_leds = pdata->num_nodes; + i2c_set_clientdata(cl, at); + + if (of_root) { + pI2CNode = syno_of_i2c_adapter_match(cl->adapter); + pI2CDevNode = syno_of_i2c_device_match(cl, drv_name, pI2CNode); + of_property_read_u32_index(pI2CDevNode, DT_DEVICE_INDEX, 0, &device_index); + } else { + dev_err(at->dev, "fail to get device tree\n"); + goto END; + } + + for (i = 0 ; i < pdata->num_nodes ; i++) { + pdata->node[i].name = kzalloc(64 * sizeof(char), GFP_KERNEL); + snprintf( pdata->node[i].name, 64, "syno_led%d", ((24 * device_index) + i)); + + pdata->node[i].mode = ATMEGA1608_LED_DIM0; + pdata->node[i].prescale = 30; + pdata->node[i].channel = i; + pdata->node[i].default_trigger = syno_led_trigger_name[24 * device_index + i]; + } + + ret = atmega1608_chip_detect(at); + if (ret) { + dev_err(at->dev, "chip detection err: %d\n", ret); + goto END; + } + + return atmega1608_leds_register(at, pdata); +END: + return -EINVAL; +} + +static int atmega1608_remove(struct i2c_client *cl) +{ + struct atmega1608 *at = i2c_get_clientdata(cl); + + atmega1608_brightness_force_off(at); + atmega1608_leds_unregister(at); + return 0; +} + +static const struct i2c_device_id atmega1608_id[] = { + {"atmega1608", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, atmega1608_id); + +static struct i2c_driver atmega1608_driver = { + .probe = atmega1608_probe, + .remove = atmega1608_remove, + .driver = { + .name = "atmega1608", + .owner = THIS_MODULE, + }, + .id_table = atmega1608_id, +}; + +module_i2c_driver(atmega1608_driver); + +MODULE_DESCRIPTION("ATMEGA1608 LED Driver"); +MODULE_AUTHOR("Alex Lai"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-lp3943.c b/drivers/leds/leds-lp3943.c new file mode 100644 index 000000000000..6446de8b9f11 --- /dev/null +++ b/drivers/leds/leds-lp3943.c @@ -0,0 +1,749 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * 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 +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ +#ifdef CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI +#include +#endif /* CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI */ + +#define MAX_NUM_LEDS 16 +#define MAX_BRIGHTNESS 255 +#define LED_OFF 0 + +/* Registers */ +#define LP3943_INPUT1 0x00 +#define LP3943_PSC0 0x02 +#define LP3943_PWM0 0x03 +#define LP3943_PSC1 0x04 +#define LP3943_PWM1 0x05 +#define LP3943_LS0 0x06 +#define LP3943_LS1 0x07 +#define LP3943_LS2 0x08 +#define LP3943_LS3 0x09 + +/* Mask, shift */ +#define LP3943_SEL0_M 0x03 +#define LP3943_SEL1_M 0x0C +#define LP3943_SEL2_M 0x30 +#define LP3943_SEL3_M 0xC0 +#define LP3943_SEL0_S 0 +#define LP3943_SEL1_S 2 +#define LP3943_SEL2_S 4 +#define LP3943_SEL3_S 6 + +static const u8 mask_sel[] = { + LP3943_SEL0_M, + LP3943_SEL1_M, + LP3943_SEL2_M, + LP3943_SEL3_M, +}; + +static const u8 shift_sel[] = { + LP3943_SEL0_S, + LP3943_SEL1_S, + LP3943_SEL2_S, + LP3943_SEL3_S, +}; + +struct lp3943_led { + int id; + struct led_classdev cdev; + struct lp3943_led_node *node; + struct work_struct brtwork; + u8 brightness; +#ifdef MY_DEF_HERE + int retry_count; +#endif /* MY_DEF_HERE */ +}; + +struct lp3943 { + struct i2c_client *client; + struct device *dev; + struct lp3943_led led[MAX_NUM_LEDS]; + int num_leds; +}; + +#ifdef MY_DEF_HERE +static struct i2c_client *gpClient = NULL; +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +static DEFINE_MUTEX(ModeLock); + +enum lp3943_led_channel ch0[] = { + LP3943_LED0, +}; + +enum lp3943_led_channel ch1[] = { + LP3943_LED1, +}; + +enum lp3943_led_channel ch2[] = { + LP3943_LED2, +}; + +enum lp3943_led_channel ch3[] = { + LP3943_LED3, +}; + +enum lp3943_led_channel ch4[] = { + LP3943_LED4, +}; + +enum lp3943_led_channel ch5[] = { + LP3943_LED5, +}; + +enum lp3943_led_channel ch6[] = { + LP3943_LED6, +}; + +enum lp3943_led_channel ch7[] = { + LP3943_LED7, +}; + +enum lp3943_led_channel ch8[] = { + LP3943_LED8, +}; + +enum lp3943_led_channel ch9[] = { + LP3943_LED9, +}; + +enum lp3943_led_channel ch10[] = { + LP3943_LED10, +}; + +enum lp3943_led_channel ch11[] = { + LP3943_LED11, +}; + +enum lp3943_led_channel ch12[] = { + LP3943_LED12, +}; + +enum lp3943_led_channel ch13[] = { + LP3943_LED13, +}; + +enum lp3943_led_channel ch14[] = { + LP3943_LED14, +}; + +enum lp3943_led_channel ch15[] = { + LP3943_LED15, +}; + +struct lp3943_led_node syno_led_nodes[] = { + { + .name = "syno_led0", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch0, + .num_channels = ARRAY_SIZE(ch0), + .default_trigger = "syno_led0_ledtrig", + }, { + .name = "syno_led1", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch1, + .num_channels = ARRAY_SIZE(ch1), + .default_trigger = "syno_led1_ledtrig", + }, { + .name = "syno_led2", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch2, + .num_channels = ARRAY_SIZE(ch2), + .default_trigger = "syno_led2_ledtrig", + }, { + .name = "syno_led3", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch3, + .num_channels = ARRAY_SIZE(ch3), + .default_trigger = "syno_led3_ledtrig", + }, { + .name = "syno_led4", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch4, + .num_channels = ARRAY_SIZE(ch4), + .default_trigger = "syno_led4_ledtrig", + }, { + .name = "syno_led5", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch5, + .num_channels = ARRAY_SIZE(ch5), + .default_trigger = "syno_led5_ledtrig", + }, { + .name = "syno_led6", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch6, + .num_channels = ARRAY_SIZE(ch6), + .default_trigger = "syno_led6_ledtrig", + }, { + .name = "syno_led7", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch7, + .num_channels = ARRAY_SIZE(ch7), + .default_trigger = "syno_led7_ledtrig", + }, { + .name = "syno_led8", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch8, + .num_channels = ARRAY_SIZE(ch8), + .default_trigger = "syno_led8_ledtrig", + }, { + .name = "syno_led9", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch9, + .num_channels = ARRAY_SIZE(ch9), + .default_trigger = "syno_led9_ledtrig", + }, { + .name = "syno_led10", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch10, + .num_channels = ARRAY_SIZE(ch10), + .default_trigger = "syno_led10_ledtrig", + }, { + .name = "syno_led11", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch11, + .num_channels = ARRAY_SIZE(ch11), + .default_trigger = "syno_led11_ledtrig", + }, { + .name = "syno_led12", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch12, + .num_channels = ARRAY_SIZE(ch12), + .default_trigger = "syno_led12_ledtrig", + }, { + .name = "syno_led13", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch13, + .num_channels = ARRAY_SIZE(ch13), + .default_trigger = "syno_led13_ledtrig", + }, { + .name = "syno_led14", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch14, + .num_channels = ARRAY_SIZE(ch14), + .default_trigger = "syno_led14_ledtrig", + }, { + .name = "syno_led15", + .mode = LP3943_LED_DIM0, + .prescale = 30, + .channel = ch15, + .num_channels = ARRAY_SIZE(ch15), + .default_trigger = "syno_led15_ledtrig", + }, +}; + +struct lp3943_platform_data syno_lp3943_pdata = { + .node = syno_led_nodes, + .num_nodes = ARRAY_SIZE(syno_led_nodes), +}; + +struct i2c_board_info __initdata LedI2CBoardInfo[] = { + { + I2C_BOARD_INFO("lp3943", 0x60), + .platform_data = &syno_lp3943_pdata, + }, +}; +#define SYNO_LP3943_MAX_RETRY 5 +extern void (*funcSynoLP3943Mutex)(bool); +static struct mutex syno_lp3943_i2c_lock; +static void syno_lp3943_i2c_mutex (bool lock) +{ + if (lock) + { + mutex_lock(&syno_lp3943_i2c_lock); + } + else + { + mutex_unlock(&syno_lp3943_i2c_lock); + } +} +#endif /* MY_DEF_HERE */ + +static int lp3943_read_byte(struct lp3943 *lp, u8 reg, u8 *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(lp->client, reg); + if (ret < 0) { + dev_err(lp->dev, "failed to read 0x%.2x\n", reg); + return ret; + } + + *data = (u8)ret; + return 0; +} + +static int lp3943_write_byte(struct lp3943 *lp, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(lp->client, reg, data); +} + +static int lp3943_update_bits(struct lp3943 *lp, u8 reg, u8 mask, u8 data) +{ + int ret; + u8 tmp; + +#ifdef MY_DEF_HERE +/*LS registers are modified in this function only, so this is the only part that we have to protect as a critical section*/ + mutex_lock(&ModeLock); +#endif /* MY_DEF_HERE */ + + ret = lp3943_read_byte(lp, reg, &tmp); + if (ret) +#ifdef MY_DEF_HERE + goto END; +#else /* MY_DEF_HERE */ + return ret; +#endif /* MY_DEF_HERE */ + + tmp &= ~mask; + tmp |= data & mask; + +#ifdef MY_DEF_HERE + ret = lp3943_write_byte(lp, reg, tmp); + +END: + mutex_unlock(&ModeLock); + return ret; +#else /* MY_DEF_HERE */ + return lp3943_write_byte(lp, reg, tmp); +#endif /* MY_DEF_HERE */ +} + +static int lp3943_update_selector(struct lp3943 *lp, enum lp3943_led_mode mode, + enum lp3943_led_channel channel) +{ + u8 addr, mask, shift, idx; + + switch (channel) { + case LP3943_LED0 ... LP3943_LED3: + addr = LP3943_LS0; + break; + case LP3943_LED4 ... LP3943_LED7: + addr = LP3943_LS1; + break; + case LP3943_LED8 ... LP3943_LED11: + addr = LP3943_LS2; + break; + case LP3943_LED12 ... LP3943_LED15: + addr = LP3943_LS3; + break; + default: + return -EINVAL; + } + + idx = channel % 4; + mask = mask_sel[idx]; + shift = shift_sel[idx]; + + return lp3943_update_bits(lp, addr, mask, mode << shift); +} + +static int lp3943_update_scale(struct lp3943 *lp, enum lp3943_led_mode mode, + u8 prescale) +{ + u8 addr; + + switch (mode) { + case LP3943_LED_DIM0: + addr = LP3943_PSC0; + break; + case LP3943_LED_DIM1: + addr = LP3943_PSC1; + break; + default: + return 0; + } + + return lp3943_write_byte(lp, addr, prescale); +} + +static int lp3943_update_pwm(struct lp3943 *lp, enum lp3943_led_mode mode, + u8 pwm) +{ + u8 addr; + + switch (mode) { + case LP3943_LED_DIM0: + addr = LP3943_PWM0; + break; + case LP3943_LED_DIM1: + addr = LP3943_PWM1; + break; + default: + return 0; + } + + return lp3943_write_byte(lp, addr, pwm); +} + +#ifdef MY_DEF_HERE +static void lp3943_syno_brightness_set(u8 brightness, enum lp3943_led_mode *mode, enum lp3943_led_mode nodeMode) +{ + if (!mode) { + goto END; + } + switch (brightness) { + case 0: + *mode = LP3943_LED_OFF; + break; + case 255: + *mode = LP3943_LED_ON; + break; + default: + *mode = nodeMode; + break; + } + +END: + return; +} +#endif /* MY_DEF_HERE */ + +static int lp3943_update_brightness(struct lp3943_led *led) +{ + struct lp3943 *lp = container_of(led, struct lp3943, led[led->id]); + struct lp3943_led_node *node = led->node; + enum lp3943_led_channel *channel; + enum lp3943_led_mode mode; + int i, ret; + + for (i = 0 ; i < node->num_channels ; i++) { + channel = node->channel + i; + +#ifdef MY_DEF_HERE + lp3943_syno_brightness_set(led->brightness, &mode, node->mode); +#else /* MY_DEF_HERE */ + mode = led->brightness == 0 ? LP3943_LED_OFF : node->mode; +#endif /* MY_DEF_HERE */ + + ret = lp3943_update_selector(lp, mode, *channel); + if (ret) + return ret; + +#ifdef MY_DEF_HERE + if (mode == LP3943_LED_OFF || mode == LP3943_LED_ON) +#else /* MY_DEF_HERE */ + if (mode == LP3943_LED_OFF) +#endif /* MY_DEF_HERE */ + continue; + + ret = lp3943_update_scale(lp, mode, node->prescale); + if (ret) + return ret; + + ret = lp3943_update_pwm(lp, mode, led->brightness); + if (ret) + return ret; + } + + return 0; +} + +static void lp3943_brightness_force_off(struct lp3943 *lp) +{ + int i; + u8 addr[] = { LP3943_LS0, LP3943_LS1, LP3943_LS2, LP3943_LS3 }; + + for (i = 0 ; i < ARRAY_SIZE(addr) ; i++) + lp3943_write_byte(lp, addr[i], LED_OFF); +} + +static void lp3943_brightness_work(struct work_struct *work) +{ +#ifdef MY_DEF_HERE + int ret = 0; +#endif /* MY_DEF_HERE */ + struct lp3943_led *led; + + led = container_of(work, struct lp3943_led, brtwork); +#ifdef MY_DEF_HERE + syno_lp3943_i2c_mutex (true); + ret = lp3943_update_brightness(led); + syno_lp3943_i2c_mutex (false); + + if (ret) { + if (led->retry_count < SYNO_LP3943_MAX_RETRY) { + ++led->retry_count; + pr_err("%s: retry to recover %s for %d times\n", + __func__, led->node->name, led->retry_count); + schedule_work(&led->brtwork); + } else { + pr_err("%s: failed to recover %s\n", + __func__, led->node->name); + } + } else { + led->retry_count = 0; + } +#else /* MY_DEF_HERE */ + lp3943_update_brightness(led); +#endif /* MY_DEF_HERE */ +} + +static void lp3943_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct lp3943_led *led; + + led = container_of(led_cdev, struct lp3943_led, cdev); +#ifdef MY_DEF_HERE + if(brightness == led->brightness) { + return; + } +#endif /* MY_DEF_HERE */ + led->brightness = brightness; + schedule_work(&led->brtwork); +} + +static int lp3943_leds_register(struct lp3943 *lp, + struct lp3943_platform_data *pdata) +{ + struct lp3943_led_node *node; + int i, ret; + + for (i = 0 ; i < lp->num_leds ; i++) { + node = pdata->node + i; + + if (!node || !node->name) { + dev_err(lp->dev, "invalid data on node%d\n", i); + ret = -EINVAL; + goto err_dev; + } +#ifdef MY_DEF_HERE + INIT_WORK(&lp->led[i].brtwork, lp3943_brightness_work); +#endif /* MY_DEF_HERE */ + + lp->led[i].id = i; + lp->led[i].node = node; + lp->led[i].cdev.name = node->name; + lp->led[i].cdev.max_brightness = MAX_BRIGHTNESS; + lp->led[i].cdev.brightness_set = lp3943_brightness_set; +#ifdef MY_DEF_HERE + lp->led[i].cdev.default_trigger = node->default_trigger; + lp->led[i].retry_count = 0; +#endif /* MY_DEF_HERE */ + + ret = led_classdev_register(lp->dev, &lp->led[i].cdev); + if (ret) { + dev_err(lp->dev, "led(%d/%d) register err: %d\n", + i, lp->num_leds, ret); + goto err_dev; + } + +#ifdef MY_DEF_HERE + /* Move to above */ +#else /* MY_DEF_HERE */ + INIT_WORK(&lp->led[i].brtwork, lp3943_brightness_work); +#endif /* MY_DEF_HERE */ + } + + return 0; + +err_dev: + while (--i >= 0) { + led_classdev_unregister(&lp->led[i].cdev); + cancel_work_sync(&lp->led[i].brtwork); + } + return ret; +} + +static void lp3943_leds_unregister(struct lp3943 *lp) +{ + int i; + + for (i = 0 ; i < lp->num_leds ; i++) { + led_classdev_unregister(&lp->led[i].cdev); + cancel_work_sync(&lp->led[i].brtwork); + } +} + +static int lp3943_validate_platform_data(struct device *dev, + struct lp3943_platform_data *pdata) +{ + if (!pdata || !pdata->node) { + dev_err(dev, "invalid platform data\n"); + goto err; + } + + if (pdata->num_nodes == 0 || pdata->num_nodes > MAX_NUM_LEDS) { + dev_err(dev, "invalid num_nodes: %d\n", pdata->num_nodes); + goto err; + } + + return 0; +err: + return -EINVAL; +} + +static int lp3943_chip_detect(struct lp3943 *lp) +{ + u8 val; + return lp3943_read_byte(lp, LP3943_INPUT1, &val); +} + +#ifdef CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI +static const struct acpi_device_id lp3943_acpi_ids[] = { + { "LED3943", (kernel_ulong_t)&syno_lp3943_pdata }, + { } +}; +MODULE_DEVICE_TABLE(acpi, lp3943_acpi_ids); +#endif /* CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI */ + +static int lp3943_probe(struct i2c_client *cl, + const struct i2c_device_id *id) +{ + struct lp3943 *lp; + struct lp3943_platform_data *pdata = cl->dev.platform_data; + int ret; +#ifdef CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI + const struct acpi_device_id *aid; + + aid = acpi_match_device(lp3943_acpi_ids, &cl->dev); + if (aid) { + pdata = (struct lp3943_platform_data *) aid->driver_data; + } else { + return -ENODEV; + } +#endif /* CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI */ + + if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -EIO; + +#ifdef CONFIG_SYNO_LEDS_LP3943_PROBE_OF + pdata = &syno_lp3943_pdata; +#endif /* CONFIG_SYNO_LEDS_LP3943_PROBE_OF */ + + ret = lp3943_validate_platform_data(&cl->dev, pdata); + if (ret) + return ret; + + lp = devm_kzalloc(&cl->dev, sizeof(struct lp3943), GFP_KERNEL); + if (!lp) + return -ENOMEM; + + lp->client = cl; + lp->dev = &cl->dev; + lp->num_leds = pdata->num_nodes; + i2c_set_clientdata(cl, lp); + + ret = lp3943_chip_detect(lp); + if (ret) { + dev_err(lp->dev, "chip detection err: %d\n", ret); + return ret; + } + +#ifdef MY_DEF_HERE + mutex_init(&syno_lp3943_i2c_lock); + funcSynoLP3943Mutex = syno_lp3943_i2c_mutex; +#endif /* MY_DEF_HERE */ + return lp3943_leds_register(lp, pdata); +} + +static int lp3943_remove(struct i2c_client *cl) +{ + struct lp3943 *lp = i2c_get_clientdata(cl); + + lp3943_brightness_force_off(lp); + lp3943_leds_unregister(lp); + return 0; +} + +static const struct i2c_device_id lp3943_id[] = { + {"lp3943", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, lp3943_id); + +static struct i2c_driver lp3943_driver = { + .probe = lp3943_probe, + .remove = lp3943_remove, + .driver = { + .name = "lp3943", + .owner = THIS_MODULE, +#ifdef CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI + .acpi_match_table = ACPI_PTR(lp3943_acpi_ids), +#endif /* CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI */ + }, + .id_table = lp3943_id, +}; + +static int __init lp3943_init(void) +{ +#ifdef MY_DEF_HERE + int iErr = -1; + struct i2c_adapter *pAdapter = NULL; + /* instantiate the devices explicitly */ + pAdapter = i2c_get_adapter(0); + if (pAdapter == NULL) { + printk(KERN_ERR "led-lp3943 initial error: failed to get i2c adapter\n"); + goto END; + } + + i2c_put_adapter(pAdapter); + + /*regist board info*/ + gpClient = i2c_new_client_device(pAdapter, &LedI2CBoardInfo[0]); + if (gpClient == NULL) { + printk(KERN_ERR "led-lp3943 initial error: failed to initial device\n"); + goto END; + } + iErr = i2c_add_driver(&lp3943_driver); + +END: + return iErr; +#else /* MY_DEF_HERE */ + return i2c_add_driver(&lp3943_driver); +#endif /* MY_DEF_HERE */ +} +module_init(lp3943_init); + +static void __exit lp3943_exit(void) +{ +#ifdef MY_DEF_HERE + i2c_unregister_device(gpClient); +#endif /* MY_DEF_HERE */ + i2c_del_driver(&lp3943_driver); +} +module_exit(lp3943_exit); + +MODULE_DESCRIPTION("National Semiconductor/TI LP3943 LED Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 733a83e2a718..5f8d2027df61 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o +obj-$(CONFIG_SYNO_LEDS_TRIGGER) += syno_ledtrig.o +obj-$(CONFIG_SYNO_LEDS_TRIGGER_DISK) += ledtrig-disk-syno.o diff --git a/drivers/leds/trigger/ledtrig-disk-syno.c b/drivers/leds/trigger/ledtrig-disk-syno.c new file mode 100644 index 000000000000..4d5db7b981e5 --- /dev/null +++ b/drivers/leds/trigger/ledtrig-disk-syno.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LED Kernel Timer Trigger + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../leds.h" + +#define DEFAULT_BLINK_DELAY 150 + +static ssize_t led_delay_on_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + + return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); +} + +static ssize_t led_delay_on_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + unsigned long state; + ssize_t ret; + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + led_cdev->blink_delay_on = state; + + return size; +} + +static ssize_t led_delay_off_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + + return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); +} + +static ssize_t led_delay_off_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + unsigned long state; + ssize_t ret; + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + led_cdev->blink_delay_off = state; + + return size; +} + +static ssize_t led_activated_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + + return sprintf(buf, "%s\n", (led_cdev->activated ? "ON" : "OFF")); +} + +void ledtrig_syno_disk_led_on(struct led_classdev *led_cdev, bool active) +{ + led_cdev->activated = active; + + if (active) { + led_set_brightness_nosleep(led_cdev, led_cdev->max_brightness); + + //init blink rate + led_cdev->blink_delay_on = DEFAULT_BLINK_DELAY; + led_cdev->blink_delay_off = DEFAULT_BLINK_DELAY; + } else { + led_set_brightness(led_cdev, LED_OFF); + } +} +EXPORT_SYMBOL(ledtrig_syno_disk_led_on); + +static ssize_t led_activated_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = led_trigger_get_led(dev); + unsigned long state; + ssize_t ret; + + ret = kstrtoul(buf, 10, &state); + if (ret) + return ret; + + ledtrig_syno_disk_led_on(led_cdev, (state > 0 ? true : false)); + + return size; +} + +static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); +static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); +static DEVICE_ATTR(activated, 0644, led_activated_show, led_activated_store); + +static struct attribute *syno_disk_trig_attrs[] = { + &dev_attr_delay_on.attr, + &dev_attr_delay_off.attr, + &dev_attr_activated.attr, + NULL +}; +ATTRIBUTE_GROUPS(syno_disk_trig); + +void ledtrig_syno_disk_activity_on(struct led_classdev *led_cdev) +{ + if (!led_cdev->activated) { + return ; + } + + // the forth parameter of led_blink_set_oneshot is invert. + // This controlls the led behavior after the blink activity. + // For invert = 1, led is set to on after the blink which matched synology need. + // The led present is on after a disk is inserted on DSM. + // For invert = 0, led is set to off after the blink which matched normal pc behavior. + // The HDD led is usually off, and blinks when data transfer on most pc. + led_blink_set_oneshot(led_cdev, &led_cdev->blink_delay_on, &led_cdev->blink_delay_off, 1); +} +EXPORT_SYMBOL(ledtrig_syno_disk_activity_on); + +static int syno_disk_trig_activate(struct led_classdev *led_cdev) +{ + //init blink rate + led_cdev->blink_delay_on = DEFAULT_BLINK_DELAY; + led_cdev->blink_delay_off = DEFAULT_BLINK_DELAY; + + return 0; +} + +static void syno_disk_trig_deactivate(struct led_classdev *led_cdev) +{ + led_set_brightness(led_cdev, LED_OFF); + led_cdev->activated = false; +} + +static struct led_trigger syno_disk_led_trigger = { + .name = "disk_syno", + .activate = syno_disk_trig_activate, + .deactivate = syno_disk_trig_deactivate, + .groups = syno_disk_trig_groups, +}; +module_led_trigger(syno_disk_led_trigger); + +MODULE_DESCRIPTION("Synology Disk LED trigger"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/trigger/syno_ledtrig.c b/drivers/leds/trigger/syno_ledtrig.c new file mode 100644 index 000000000000..9effc56bfc07 --- /dev/null +++ b/drivers/leds/trigger/syno_ledtrig.c @@ -0,0 +1,173 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +typedef struct _tag_SYNO_LED_TRIGGER_TIMER { + struct timer_list Timer; + int DiskActivity; + int DiskLastActivity; + int DiskFaulty; + unsigned long LedNum; +} SYNO_LED_TRIGGER_TIMER; + +static SYNO_LED_TRIGGER_TIMER *syno_led_trigger_timer = NULL; +static struct led_trigger *syno_led_ledtrig = NULL; +char **syno_led_trigger_name; +EXPORT_SYMBOL(syno_led_trigger_name); + +static int num_of_led_trigger = 0; + +#ifdef MY_ABC_HERE +#define SYNO_MAX_LED 255 +#else /* MY_ABC_HERE */ +#define SYNO_MAX_LED 16 +#endif /* MY_ABC_HERE */ + +int *gpGreenLedMap, *gpOrangeLedMap = NULL; //mapping disk index to disk led; must be initialized before used +EXPORT_SYMBOL(gpGreenLedMap); +EXPORT_SYMBOL(gpOrangeLedMap); + +void syno_ledtrig_set(int iLedNum, enum led_brightness brightness) +{ + if(0 > iLedNum || num_of_led_trigger <= iLedNum || NULL == syno_led_ledtrig){ + return; + } + + led_trigger_event(&syno_led_ledtrig[iLedNum], brightness); +} +EXPORT_SYMBOL(syno_ledtrig_set); + +void syno_ledtrig_active_set(int iLedNum) +{ + SYNO_LED_TRIGGER_TIMER *pTriggerTimer = NULL; + + if(0 > iLedNum || num_of_led_trigger <= iLedNum || NULL == syno_led_ledtrig || NULL == syno_led_trigger_timer) { + goto END; + } + + pTriggerTimer = &syno_led_trigger_timer[iLedNum]; + if (1 == pTriggerTimer->DiskFaulty){ + goto END; + } + + pTriggerTimer->DiskActivity++; + if (!timer_pending(&pTriggerTimer->Timer)){ + mod_timer(&pTriggerTimer->Timer, jiffies + msecs_to_jiffies(100)); + } + +END: + return; + +} +EXPORT_SYMBOL(syno_ledtrig_active_set); + +void syno_ledtrig_faulty_set(int iLedNum, int iFaulty) +{ + SYNO_LED_TRIGGER_TIMER *pTriggerTimer = NULL; + + if(0 > iLedNum || num_of_led_trigger <= iLedNum || 0 > iFaulty || NULL == syno_led_trigger_timer) { + return; + } + + pTriggerTimer = &syno_led_trigger_timer[iLedNum]; + pTriggerTimer->DiskFaulty = iFaulty; +} +EXPORT_SYMBOL(syno_ledtrig_faulty_set); + +static void syno_active_ledtrig_timerfunc(struct timer_list *t) +{ + SYNO_LED_TRIGGER_TIMER *pTriggerTimer = from_timer(pTriggerTimer, t, Timer); + unsigned long iLedNum = pTriggerTimer->LedNum; + + if (pTriggerTimer->DiskLastActivity != pTriggerTimer->DiskActivity) { + pTriggerTimer->DiskLastActivity = pTriggerTimer->DiskActivity; + led_trigger_event(&syno_led_ledtrig[iLedNum], LED_HALF); + mod_timer(&pTriggerTimer->Timer, jiffies + msecs_to_jiffies(150)); + }else if( 1 == pTriggerTimer->DiskFaulty){ + led_trigger_event(&syno_led_ledtrig[iLedNum], LED_OFF); + }else{ + led_trigger_event(&syno_led_ledtrig[iLedNum], LED_FULL); + } +} + +static int __init syno_ledtrig_init(void) +{ + int iTriggerNum = 0; + int err = 0; + SYNO_LED_TRIGGER_TIMER *pTriggerTimer = NULL; + +#ifdef MY_ABC_HERE + if (of_root) { + if (of_find_property(of_root, "number_of_led_trigger", NULL)) { + of_property_read_u32_index(of_root, "number_of_led_trigger", 0, &num_of_led_trigger); + } + } +#endif /* MY_ABC_HERE */ + + if (0 == num_of_led_trigger) { + num_of_led_trigger = SYNO_MAX_LED; + } + + syno_led_trigger_name = (char **)kmalloc(num_of_led_trigger * sizeof (char* ), GFP_KERNEL); + syno_led_ledtrig = (struct led_trigger*)kmalloc(num_of_led_trigger * sizeof(struct led_trigger), GFP_KERNEL); + syno_led_trigger_timer = (SYNO_LED_TRIGGER_TIMER*)kmalloc(num_of_led_trigger * sizeof(SYNO_LED_TRIGGER_TIMER), GFP_KERNEL); + + if(NULL == syno_led_trigger_name || NULL == syno_led_ledtrig || NULL == syno_led_trigger_timer) { + printk("fail to allocate memory for led triggers \n"); + goto END; + } + memset(syno_led_trigger_name, 0, num_of_led_trigger * sizeof(char*)); + memset(syno_led_ledtrig, 0, num_of_led_trigger * sizeof(struct led_trigger)); + memset(syno_led_trigger_timer, 0, num_of_led_trigger * sizeof(SYNO_LED_TRIGGER_TIMER)); + + /*register all triggers used in DSM*/ + for(iTriggerNum = 0 ; iTriggerNum < num_of_led_trigger ; iTriggerNum++){ + syno_led_trigger_name[iTriggerNum] = (char*)kmalloc(64 * sizeof (char), GFP_KERNEL); + snprintf(syno_led_trigger_name[iTriggerNum], 64, "syno_led%d_ledtrig", iTriggerNum); + syno_led_ledtrig[iTriggerNum].name = syno_led_trigger_name[iTriggerNum]; + + err = led_trigger_register(&syno_led_ledtrig[iTriggerNum]); + if (0 != err ){ + printk("fail to regist tirgger Num %d \n", iTriggerNum); + break; + } + pTriggerTimer = &syno_led_trigger_timer[iTriggerNum]; + pTriggerTimer->DiskFaulty = 0; + pTriggerTimer->LedNum = iTriggerNum; + timer_setup(&pTriggerTimer->Timer, syno_active_ledtrig_timerfunc, 0); + } + +END: + return err; +} +module_init(syno_ledtrig_init); + +static void __exit syno_ledtrig_exit(void) +{ + int iTriggerNum = 0; + + /*unregister triggers*/ + for(iTriggerNum = 0 ; iTriggerNum < num_of_led_trigger ; iTriggerNum++){ + led_trigger_unregister_simple(&syno_led_ledtrig[iTriggerNum]); + } +} +module_exit(syno_ledtrig_exit); + +#endif // MY_ABC_HERE diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 6d3e234dc46a..c7df0ab1fc39 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -21,7 +21,7 @@ dm-ebs-y += dm-ebs-target.o dm-era-y += dm-era-target.o dm-clone-y += dm-clone-target.o dm-clone-metadata.o dm-verity-y += dm-verity-target.o -md-mod-y += md.o md-bitmap.o +md-mod-y += md.o md-bitmap.o libmd-report.o raid456-y += raid5.o raid5-cache.o raid5-ppl.o dm-zoned-y += dm-zoned-target.o dm-zoned-metadata.o dm-zoned-reclaim.o linear-y += md-linear.o @@ -46,6 +46,9 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o ifeq ($(CONFIG_BLK_DEV_MD),y) obj-y += md-autodetect.o endif +ifeq ($(CONFIG_SYNO_MD_FAST_REBUILD),y) +obj-y += syno-md-hint.o +endif obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o obj-$(CONFIG_DM_UNSTRIPED) += dm-unstripe.o diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 3db92d9a030b..4bff447e103a 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Internal header file _only_ for device mapper core * @@ -90,6 +93,10 @@ struct mapped_device { */ struct bio_set io_bs; struct bio_set bs; +#ifdef MY_ABC_HERE + /* used for noclone bio */ + mempool_t syno_noclone_pool; +#endif /* MY_ABC_HERE */ /* * Processing queue (flush) @@ -120,6 +127,9 @@ struct mapped_device { bool init_tio_pdu:1; struct srcu_struct io_barrier; +#ifdef MY_ABC_HERE + struct syno_md_fast_wakeup_info syno_fast_wakeup_info; +#endif /* MY_ABC_HERE */ }; void disable_discard(struct mapped_device *md); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 70ae6f3aede9..dfdbf895c89c 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2003 Jana Saout * Copyright (C) 2004 Clemens Fruhwirth @@ -216,6 +219,11 @@ struct crypt_config { struct bio_set bs; struct mutex bio_alloc_lock; +#ifdef MY_ABC_HERE + atomic_t syno_io_count; + wait_queue_head_t syno_wait_for_io_limit; +#endif /* MY_ABC_HERE */ + u8 *authenc_key; /* space for keys in authenc() format (if used) */ u8 key[]; }; @@ -224,6 +232,11 @@ struct crypt_config { #define MAX_TAG_SIZE 480 #define POOL_ENTRY_SIZE 512 +#ifdef MY_ABC_HERE +#define SYNO_IO_LIMIT_MAX 8192 +#define SYNO_IO_LIMIT_THRESHOLD 128 +#endif /* MY_ABC_HERE */ + static DEFINE_SPINLOCK(dm_crypt_clients_lock); static unsigned dm_crypt_clients_n = 0; static volatile unsigned long dm_crypt_pages_per_client; @@ -1758,6 +1771,10 @@ static void crypt_dec_pending(struct dm_crypt_io *io) kfree(io->integrity_metadata); base_bio->bi_status = error; +#ifdef MY_ABC_HERE + if (atomic_dec_return(&cc->syno_io_count) <= (SYNO_IO_LIMIT_MAX - SYNO_IO_LIMIT_THRESHOLD)) + wake_up(&cc->syno_wait_for_io_limit); +#endif /* MY_ABC_HERE */ /* * If we are running this function from our tasklet, @@ -3323,6 +3340,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } wake_up_process(cc->write_thread); +#ifdef MY_ABC_HERE + atomic_set(&cc->syno_io_count, 0); + init_waitqueue_head(&cc->syno_wait_for_io_limit); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ti->num_unused_hint_bios = 1; +#endif /* MY_ABC_HERE */ ti->num_flush_bios = 1; ti->limit_swap_bios = true; @@ -3344,6 +3369,9 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) * - for REQ_OP_DISCARD caller must use flush if IO ordering matters */ if (unlikely(bio->bi_opf & REQ_PREFLUSH || +#ifdef MY_ABC_HERE + bio_op(bio) == REQ_OP_UNUSED_HINT || +#endif /* MY_ABC_HERE */ bio_op(bio) == REQ_OP_DISCARD)) { bio_set_dev(bio, cc->dev->bdev); if (bio_sectors(bio)) @@ -3369,6 +3397,11 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) if (unlikely(bio->bi_iter.bi_size & (cc->sector_size - 1))) return DM_MAPIO_KILL; +#ifdef MY_ABC_HERE + wait_event(cc->syno_wait_for_io_limit, atomic_read(&cc->syno_io_count) <= SYNO_IO_LIMIT_MAX); + atomic_inc(&cc->syno_io_count); +#endif /* MY_ABC_HERE */ + io = dm_per_bio_data(bio, cc->per_bio_data_size); crypt_io_init(io, cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector)); diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 4312007d2d34..04fcf5e701bb 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2003 Sistina Software * Copyright (C) 2006 Red Hat GmbH @@ -26,6 +29,24 @@ struct dm_io_client { struct bio_set bios; }; +#ifdef MY_ABC_HERE +// Internal debug macro +// #define DM_CORRECTION_DEBUG +#ifdef DM_CORRECTION_DEBUG +#define dc_dbg(fmt, args...) do { \ + printk(KERN_INFO "%s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); \ +} while (0) + +#define dc_check_dbg(bi_flags, fmt, args...) \ + if ((bi_flags & (1 << BIO_CORRECTION_RETRY)) || (bi_flags & (1 << BIO_CORRECTION_ABORT))) {\ + printk(KERN_INFO "%s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); \ + } +#else +#define dc_dbg(fmt, args...) +#define dc_check_dbg(bi_flags, fmt, args...) +#endif /* DM_CORRECTION_DEBUG */ +#endif /* MY_ABC_HERE */ + /* * Aligning 'struct io' reduces the number of bits required to store * its address. Refer to store_io_and_region_in_bio() below. @@ -38,6 +59,9 @@ struct io { void *context; void *vma_invalidate_address; unsigned long vma_invalidate_size; +#ifdef MY_ABC_HERE + unsigned long bi_flags; +#endif /* MY_ABC_HERE */ } __attribute__((aligned(DM_IO_MAX_REGIONS))); static struct kmem_cache *_dm_io_cache; @@ -111,7 +135,11 @@ static void retrieve_io_and_region_from_bio(struct bio *bio, struct io **io, * We need an io object to keep track of the number of bios that * have been dispatched for a particular io. *---------------------------------------------------------------*/ +#ifdef MY_ABC_HERE +static void complete_io(struct io *io, int error, unsigned long bi_flags) +#else static void complete_io(struct io *io) +#endif { unsigned long error_bits = io->error_bits; io_notify_fn fn = io->callback; @@ -122,24 +150,79 @@ static void complete_io(struct io *io) io->vma_invalidate_size); mempool_free(io, &io->client->pool); +#ifdef MY_ABC_HERE + if (bi_flags & (1 << BIO_CORRECTION_ERR)) { + dc_dbg("detect BIO_CORRECTION_ERR start"); + + if (error_bits & (~SYNO_DM_IO_RESERVERD_IO_MASK)) { + printk(KERN_ERR "error bits is over the mask range"); + BUG_ON(1); + } + + if (SYNO_DM_IO_RESERVERD_IO_MASK & (1 << BIO_CORRECTION_ERR)) { + printk(KERN_ERR "BIO_CORRECTION_ERR (%d) should not in the mask (%x)", + BIO_CORRECTION_ERR, SYNO_DM_IO_RESERVERD_IO_MASK); + BUG_ON(1); + } else { + dc_dbg("add bio flag BIO_CORRECTION_ERR to error code"); + error_bits |= 1 << BIO_CORRECTION_ERR; + } + + dc_dbg("detect BIO_CORRECTION_ERR end"); + } +#endif /* MY_ABC_HERE */ fn(error_bits, context); } +#ifdef MY_ABC_HERE +static void dec_count_common(struct io *io, unsigned int region, blk_status_t error, + unsigned long bi_flags) +#else static void dec_count(struct io *io, unsigned int region, blk_status_t error) +#endif { if (error) set_bit(region, &io->error_bits); if (atomic_dec_and_test(&io->count)) +#ifdef MY_ABC_HERE + complete_io(io, error, bi_flags); +#else complete_io(io); +#endif } +#ifdef MY_ABC_HERE +static void dec_count_syno(struct io *io, unsigned int region, blk_status_t error, + unsigned long bi_flags) +{ + dec_count_common(io, region, error, bi_flags); +} +#endif + +#ifdef MY_ABC_HERE +static void dec_count(struct io *io, unsigned int region, blk_status_t error) +{ + dec_count_common(io, region, error, 0); +} +#endif + + static void endio(struct bio *bio) { struct io *io; unsigned region; blk_status_t error; +#ifdef MY_ABC_HERE + unsigned long bi_flags = 0; + if (!bio) { + dc_dbg("get a null bio"); + } else { + bi_flags = bio->bi_flags; + } +#endif /* MY_ABC_HERE */ + if (bio->bi_status && bio_data_dir(bio) == READ) zero_fill_bio(bio); @@ -151,7 +234,11 @@ static void endio(struct bio *bio) error = bio->bi_status; bio_put(bio); +#ifdef MY_ABC_HERE + dec_count_syno(io, region, error, bi_flags); +#else dec_count(io, region, error); +#endif /* MY_ABC_HERE */ } /*----------------------------------------------------------------- @@ -383,6 +470,10 @@ static void do_region(int op, int op_flags, unsigned region, } atomic_inc(&io->count); +#ifdef MY_ABC_HERE + bio->bi_flags |= io->bi_flags; + dc_check_dbg(io->bi_flags, "bio start=%llu size=%llu", (u64)bio->bi_iter.bi_sector, (u64)to_sector(bio->bi_iter.bi_size)); +#endif /* MY_ABC_HERE */ submit_bio(bio); } while (remaining); } @@ -429,9 +520,15 @@ static void sync_io_complete(unsigned long error, void *context) complete(&sio->wait); } +#ifdef MY_ABC_HERE +static int sync_io(struct dm_io_client *client, unsigned int num_regions, + struct dm_io_region *where, int op, int op_flags, + struct dpages *dp, unsigned long *error_bits, unsigned long bi_flags) +#else static int sync_io(struct dm_io_client *client, unsigned int num_regions, struct dm_io_region *where, int op, int op_flags, struct dpages *dp, unsigned long *error_bits) +#endif /* MY_ABC_HERE */ { struct io *io; struct sync_io sio; @@ -452,6 +549,10 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, io->vma_invalidate_address = dp->vma_invalidate_address; io->vma_invalidate_size = dp->vma_invalidate_size; +#ifdef MY_ABC_HERE + dc_check_dbg(bi_flags, "add io flags"); + io->bi_flags = bi_flags; +#endif /* MY_ABC_HERE */ dispatch_io(op, op_flags, num_regions, where, dp, io, 1); @@ -463,9 +564,15 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, return sio.error_bits ? -EIO : 0; } +#ifdef MY_ABC_HERE +static int async_io(struct dm_io_client *client, unsigned int num_regions, + struct dm_io_region *where, int op, int op_flags, + struct dpages *dp, io_notify_fn fn, void *context, unsigned long bi_flags) +#else static int async_io(struct dm_io_client *client, unsigned int num_regions, struct dm_io_region *where, int op, int op_flags, struct dpages *dp, io_notify_fn fn, void *context) +#endif /* MY_ABC_HERE */ { struct io *io; @@ -481,6 +588,10 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, io->client = client; io->callback = fn; io->context = context; +#ifdef MY_ABC_HERE + io->bi_flags = bi_flags; + dc_check_dbg(bi_flags, "set bi_flags=%lx", bi_flags); +#endif /* MY_ABC_HERE */ io->vma_invalidate_address = dp->vma_invalidate_address; io->vma_invalidate_size = dp->vma_invalidate_size; @@ -525,6 +636,33 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, return 0; } +#ifdef MY_ABC_HERE +/* + * Make dm_io() able to pass extra data correction bio flags to underlayers + */ +int syno_dm_io(struct dm_io_request *io_req, unsigned num_regions, + struct dm_io_region *where, unsigned long *sync_error_bits, unsigned long bi_flags) +{ + int r; + struct dpages dp; + + dc_check_dbg(bi_flags, "set extra bi_flags=%lx", bi_flags); + + r = dp_init(io_req, &dp, (unsigned long)where->count << SECTOR_SHIFT); + if (r) + return r; + + if (!io_req->notify.fn) + return sync_io(io_req->client, num_regions, where, + io_req->bi_op, io_req->bi_op_flags, &dp, + sync_error_bits, bi_flags); + + return async_io(io_req->client, num_regions, where, io_req->bi_op, + io_req->bi_op_flags, &dp, io_req->notify.fn, + io_req->notify.context, bi_flags); +} +EXPORT_SYMBOL(syno_dm_io); +#endif /* MY_ABC_HERE */ /* * New collapsed (a)synchronous interface. @@ -544,6 +682,16 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions, if (r) return r; +#ifdef MY_ABC_HERE + if (!io_req->notify.fn) + return sync_io(io_req->client, num_regions, where, + io_req->bi_op, io_req->bi_op_flags, &dp, + sync_error_bits, 0); + + return async_io(io_req->client, num_regions, where, io_req->bi_op, + io_req->bi_op_flags, &dp, io_req->notify.fn, + io_req->notify.context, 0); +#else if (!io_req->notify.fn) return sync_io(io_req->client, num_regions, where, io_req->bi_op, io_req->bi_op_flags, &dp, @@ -552,6 +700,7 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions, return async_io(io_req->client, num_regions, where, io_req->bi_op, io_req->bi_op_flags, &dp, io_req->notify.fn, io_req->notify.context); +#endif /* MY_ABC_HERE */ } EXPORT_SYMBOL(dm_io); diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 00774b5d7668..f0083f5e1f31 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2001-2003 Sistina Software (UK) Limited. * @@ -60,6 +63,9 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->num_flush_bios = 1; ti->num_discard_bios = 1; ti->num_secure_erase_bios = 1; +#ifdef MY_ABC_HERE + ti->num_unused_hint_bios = 1; +#endif /* MY_ABC_HERE */ ti->num_write_same_bios = 1; ti->num_write_zeroes_bios = 1; ti->private = lc; @@ -224,6 +230,13 @@ static int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff, #define linear_dax_zero_page_range NULL #endif +#ifdef MY_ABC_HERE +static int linear_support_noclone(struct dm_target *ti) +{ + return 1; +} +#endif /* MY_ABC_HERE */ + static struct target_type linear_target = { .name = "linear", .version = {1, 4, 0}, @@ -245,6 +258,10 @@ static struct target_type linear_target = { .dax_copy_from_iter = linear_dax_copy_from_iter, .dax_copy_to_iter = linear_dax_copy_to_iter, .dax_zero_page_range = linear_dax_zero_page_range, +#ifdef MY_ABC_HERE + .noclone_map = linear_map, + .support_noclone = linear_support_noclone, +#endif /* MY_ABC_HERE */ }; int __init dm_linear_init(void) diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index a05fcd50e1b9..905745d83fbe 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2008 Red Hat, Inc. All rights reserved. * @@ -97,12 +100,37 @@ static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf) return strlen(buf); } +#ifdef MY_ABC_HERE +static ssize_t dm_attr_syno_active_show(struct mapped_device *md, char *buf) +{ + sprintf(buf, "%d\n", dm_active_get(md)); + + return strlen(buf); +} + +static ssize_t dm_attr_syno_active_store( + struct mapped_device *md, const char *buf, size_t count) +{ + unsigned long value; + + if (kstrtoul(buf, 10, &value)) + return -EINVAL; + value = !!value; + + dm_active_set(md, value); + + return strlen(buf); +} +#endif /* MY_ABC_HERE */ static DM_ATTR_RO(name); static DM_ATTR_RO(uuid); static DM_ATTR_RO(suspended); static DM_ATTR_RO(use_blk_mq); static DM_ATTR_RW(rq_based_seq_io_merge_deadline); +#ifdef MY_ABC_HERE +static DM_ATTR_RW(syno_active); +#endif /* MY_ABC_HERE */ static struct attribute *dm_attrs[] = { &dm_attr_name.attr, @@ -110,6 +138,9 @@ static struct attribute *dm_attrs[] = { &dm_attr_suspended.attr, &dm_attr_use_blk_mq.attr, &dm_attr_rq_based_seq_io_merge_deadline.attr, +#ifdef MY_ABC_HERE + &dm_attr_syno_active.attr, +#endif /* MY_ABC_HERE */ NULL, }; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 5c590895c14c..c8cd166c877e 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2001 Sistina Software (UK) Limited. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. @@ -1783,6 +1786,35 @@ static bool dm_table_supports_secure_erase(struct dm_table *t) return true; } +#ifdef MY_ABC_HERE +static int device_not_unused_hint_capable(struct dm_target *ti, struct dm_dev *dev, + sector_t start, sector_t len, void *data) +{ + struct request_queue *q = bdev_get_queue(dev->bdev); + + return q && !blk_queue_unused_hint(q); +} + +static bool dm_table_supports_unused_hint(struct dm_table *t) +{ + struct dm_target *ti; + unsigned int i; + + for (i = 0; i < dm_table_get_num_targets(t); i++) { + ti = dm_table_get_target(t, i); + + if (!ti->num_unused_hint_bios) + return false; + + if (!ti->type->iterate_devices || + ti->type->iterate_devices(ti, device_not_unused_hint_capable, NULL)) + return false; + } + + return true; +} +#endif /* MY_ABC_HERE */ + static int device_requires_stable_pages(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) @@ -1822,6 +1854,13 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, if (dm_table_supports_secure_erase(t)) blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); +#ifdef MY_ABC_HERE + if (dm_table_supports_unused_hint(t)) + blk_queue_flag_set(QUEUE_FLAG_UNUSED_HINT, q); + else + blk_queue_flag_clear(QUEUE_FLAG_UNUSED_HINT, q); +#endif /* MY_ABC_HERE */ + if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) { wc = true; if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_FUA))) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 19a70f434029..417dec4c0aef 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. @@ -8,6 +11,12 @@ #include "dm-core.h" #include "dm-rq.h" #include "dm-uevent.h" +#ifdef MY_ABC_HERE +#include "syno-md-fast-wakeup.h" +#ifdef CONFIG_BLK_DEV_MD +#include "md.h" +#endif /* CONFIG_BLK_DEV_MD */ +#endif /* MY_ABC_HERE */ #include #include @@ -52,6 +61,15 @@ static void do_deferred_remove(struct work_struct *w); static DECLARE_WORK(deferred_remove_work, do_deferred_remove); static struct workqueue_struct *deferred_remove_workqueue; +#ifdef MY_ABC_HERE +static struct kmem_cache *_syno_noclone_cache; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static void syno_dm_fast_wakeup_md(struct mapped_device *md, struct dm_table *map); +#ifdef CONFIG_BLK_DEV_MD +extern void syno_md_fast_wakeup_devices(void *md); +#endif /* CONFIG_BLK_DEV_MD */ +#endif /* MY_ABC_HERE */ atomic_t dm_global_event_nr = ATOMIC_INIT(0); DECLARE_WAIT_QUEUE_HEAD(dm_global_eventq); @@ -105,6 +123,19 @@ struct dm_io { struct dm_target_io tio; }; +#ifdef MY_ABC_HERE +/* + * One of these is allocated per noclone bio. + */ +struct syno_dm_noclone { + struct mapped_device *md; + bio_end_io_t *orig_bi_end_io; + void *orig_bi_private; + unsigned long start_time; + struct bvec_iter orig_bi_iter; +}; +#endif /* MY_ABC_HERE */ + void *dm_per_bio_data(struct bio *bio, size_t data_size) { struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); @@ -164,6 +195,9 @@ static int get_swap_bios(void) struct dm_md_mempools { struct bio_set bs; struct bio_set io_bs; +#ifdef MY_ABC_HERE + unsigned int syno_pool_size; +#endif /* MY_ABC_HERE */ }; struct table_device { @@ -245,16 +279,32 @@ static int __init local_init(void) goto out_uevent_exit; } +#ifdef MY_ABC_HERE + _syno_noclone_cache = KMEM_CACHE(syno_dm_noclone, 0); + if (!_syno_noclone_cache) { + r = -ENOMEM; + goto out_free_workqueue; + } +#endif /* MY_ABC_HERE */ + _major = major; r = register_blkdev(_major, _name); if (r < 0) +#ifdef MY_ABC_HERE + goto out_free_noclone_cache; +#else goto out_free_workqueue; +#endif /* MY_ABC_HERE */ if (!_major) _major = r; return 0; +#ifdef MY_ABC_HERE +out_free_noclone_cache: + kmem_cache_destroy(_syno_noclone_cache); +#endif /* MY_ABC_HERE */ out_free_workqueue: destroy_workqueue(deferred_remove_workqueue); out_uevent_exit: @@ -267,6 +317,9 @@ static void local_exit(void) { flush_scheduled_work(); destroy_workqueue(deferred_remove_workqueue); +#ifdef MY_ABC_HERE + kmem_cache_destroy(_syno_noclone_cache); +#endif /* MY_ABC_HERE */ unregister_blkdev(_major, _name); dm_uevent_exit(); @@ -517,6 +570,69 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector, #define dm_blk_report_zones NULL #endif /* CONFIG_BLK_DEV_ZONED */ +#ifdef MY_ABC_HERE +/* + * Refer to dm_prepare_ioctl() behavior + * 1: Extra ioctl doesn't exist or cmd is not supported + * 0: Found extra ioctl and invoked successfully + * <0: Found extra ioctl but failed to invoke + */ + +static int syno_dm_do_extra_ioctl(struct mapped_device *md, int *srcu_idx, + unsigned int cmd, unsigned long arg) +{ + struct dm_target *tgt = NULL; + struct dm_table *map = NULL; + int r = -ENOTTY; + +retry: + r = -ENOTTY; + map = dm_get_live_table(md, srcu_idx); + if (!map || !dm_table_get_size(map)) { + goto out; + } + + /* We only support devices that have a single target */ + if (dm_table_get_num_targets(map) != 1) { + goto out; + } + + tgt = dm_table_get_target(map, 0); + if (!tgt->type->extra_ioctl) { + r = 1; + goto out; + } + + if (dm_suspended_md(md)) { + r = -EAGAIN; + goto out; + } + + /* + * 0: Success + * <0: Error + * 1: Command is not within extra ioctl + */ + r = tgt->type->extra_ioctl(tgt, cmd, arg); + if (r < 0) { + printk(KERN_ERR "%s: Invoke extra ioctl failed, cmd=%d", __FUNCTION__, cmd); + } + + if (r == -ENOTCONN && !fatal_signal_pending(current)) { + dm_put_live_table(md, *srcu_idx); + map = NULL; + msleep(10); + goto retry; + } +out: + if (map) { + dm_put_live_table(md, *srcu_idx); + } + + return r; +} +#endif /* MY_ABC_HERE */ + static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx, struct block_device **bdev) { @@ -562,6 +678,15 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, struct mapped_device *md = bdev->bd_disk->private_data; int r, srcu_idx; +#ifdef MY_ABC_HERE + r = syno_dm_do_extra_ioctl(md, &srcu_idx, cmd, arg); + if (0 >= r) { + // Get error or Perform extra IOCTL successfully + goto out_extra_ioctl; + } + // No supported extra ioctl +#endif /* MY_ABC_HERE */ + r = dm_prepare_ioctl(md, &srcu_idx, &bdev); if (r < 0) goto out; @@ -583,6 +708,9 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); out: dm_unprepare_ioctl(md, srcu_idx); +#ifdef MY_ABC_HERE +out_extra_ioctl: +#endif /* MY_ABC_HERE */ return r; } @@ -625,6 +753,18 @@ static void end_io_acct(struct dm_io *io) wake_up(&md->wait); } +#ifdef MY_ABC_HERE +// Modified from end_io_acct() +static void syno_noclone_end_io_acct(struct mapped_device *md, struct bio *bio, unsigned long start_time) +{ + bio_end_io_acct(bio, start_time); + + /* nudge anyone waiting on suspend queue */ + if (unlikely(wq_has_sleeper(&md->wait))) + wake_up(&md->wait); +} +#endif /* MY_ABC_HERE */ + static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio) { struct dm_io *io; @@ -976,6 +1116,13 @@ void disable_write_zeroes(struct mapped_device *md) limits->max_write_zeroes_sectors = 0; } +#ifdef MY_ABC_HERE +static void disable_unused_hint(struct mapped_device *md) +{ + blk_queue_flag_clear(QUEUE_FLAG_UNUSED_HINT, md->queue); +} +#endif /* MY_ABC_HERE */ + static bool swap_bios_limit(struct dm_target *ti, struct bio *bio) { return unlikely((bio->bi_opf & REQ_SWAP) != 0) && unlikely(ti->limit_swap_bios); @@ -1001,6 +1148,11 @@ static void clone_endio(struct bio *bio) !bio->bi_disk->queue->limits.max_write_zeroes_sectors) disable_write_zeroes(md); } +#ifdef MY_ABC_HERE + if (unlikely(error == BLK_STS_NOTSUPP) && + bio_op(bio) == REQ_OP_UNUSED_HINT) + disable_unused_hint(md); +#endif /* MY_ABC_HERE */ /* * For zone-append bios get offset in zone of the written @@ -1014,6 +1166,11 @@ static void clone_endio(struct bio *bio) orig_bio->bi_iter.bi_sector += written_sector & mask; } +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bio, BIO_CORRECTION_ERR))) + bio_set_flag(orig_bio, BIO_CORRECTION_ERR); +#endif /* MY_ABC_HERE */ + if (endio) { int r = endio(tio->ti, bio, &error); switch (r) { @@ -1040,6 +1197,37 @@ static void clone_endio(struct bio *bio) dec_pending(io, error); } +#ifdef MY_ABC_HERE +static void syno_noclone_endio(struct bio *bio) +{ + struct syno_dm_noclone *noclone = bio->bi_private; + struct mapped_device *md = noclone->md; + + bio->bi_end_io = noclone->orig_bi_end_io; + bio->bi_private = noclone->orig_bi_private; + /** + * Restore bd_disk for complete event + * Don't use bio_set_dev, since we don't want to + * associate a completed bio with blkg + */ + bio->bi_disk = md->bdev->bd_disk; + bio->bi_partno = md->bdev->bd_partno; + bio->bi_iter = noclone->orig_bi_iter; + + syno_noclone_end_io_acct(md, bio, noclone->start_time); + + mempool_free(noclone, &md->syno_noclone_pool); + +#ifdef MY_ABC_HERE + /* If bio is no clone io, restore completion flag + * when bio returns from the underlying block devices */ + bio_set_flag(bio, BIO_TRACE_COMPLETION); +#endif /* MY_ABC_HERE */ + + bio_endio(bio); +} +#endif /* MY_ABC_HERE */ + /* * Return maximum size of I/O possible at the supplied sector up to the current * target boundary. @@ -1547,6 +1735,9 @@ static bool is_abnormal_io(struct bio *bio) switch (bio_op(bio)) { case REQ_OP_DISCARD: case REQ_OP_SECURE_ERASE: +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: +#endif /* MY_ABC_HERE */ case REQ_OP_WRITE_SAME: case REQ_OP_WRITE_ZEROES: r = true; @@ -1569,6 +1760,11 @@ static bool __process_abnormal_io(struct clone_info *ci, struct dm_target *ti, case REQ_OP_SECURE_ERASE: num_bios = ti->num_secure_erase_bios; break; +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: + num_bios = ti->num_unused_hint_bios; + break; +#endif /* MY_ABC_HERE */ case REQ_OP_WRITE_SAME: num_bios = ti->num_write_same_bios; break; @@ -1684,12 +1880,33 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md, return ret; } +#ifdef MY_ABC_HERE +static bool syno_can_bio_use_noclone(struct bio *bio) +{ + if (is_abnormal_io(bio)) + return false; + if (bio_integrity(bio)) + return false; + if (bio->bi_opf & REQ_PREFLUSH) + return false; + if (op_is_zone_mgmt(bio_op(bio))) + return false; + + return true; +} +#endif /* MY_ABC_HERE */ + static blk_qc_t dm_submit_bio(struct bio *bio) { struct mapped_device *md = bio->bi_disk->private_data; blk_qc_t ret = BLK_QC_T_NONE; int srcu_idx; struct dm_table *map; +#ifdef MY_ABC_HERE + int r; + struct syno_dm_noclone *noclone; + struct dm_target *ti; +#endif /* MY_ABC_HERE */ map = dm_get_live_table(md, &srcu_idx); if (unlikely(!map)) { @@ -1710,6 +1927,10 @@ static blk_qc_t dm_submit_bio(struct bio *bio) goto out; } +#ifdef MY_ABC_HERE + if (syno_md_fast_wakeup_info_update(&md->syno_fast_wakeup_info)) + syno_dm_fast_wakeup_md(md, map); +#endif /* MY_ABC_HERE */ /* * Use blk_queue_split() for abnormal IO (e.g. discard, writesame, etc) * otherwise associated queue_limits won't be imposed. @@ -1717,6 +1938,59 @@ static blk_qc_t dm_submit_bio(struct bio *bio) if (is_abnormal_io(bio)) blk_queue_split(&bio); +#ifdef MY_ABC_HERE + if (!syno_can_bio_use_noclone(bio)) + goto no_fast_path; + + if (unlikely(dm_stats_used(&md->stats))) + goto no_fast_path; + + ti = dm_table_find_target(map, bio->bi_iter.bi_sector); + if (unlikely(!ti)) + goto no_fast_path; + + if (!ti->type->support_noclone || + !ti->type->support_noclone(ti) || + !ti->type->noclone_map) + goto no_fast_path; + + if (unlikely(bio_sectors(bio) > max_io_len(ti, bio->bi_iter.bi_sector))) + goto no_fast_path; + + noclone = mempool_alloc(&md->syno_noclone_pool, GFP_NOWAIT); + if (unlikely(!noclone)) + goto no_fast_path; + + noclone->md = md; + noclone->start_time = bio_start_io_acct(bio); + noclone->orig_bi_end_io = bio->bi_end_io; + noclone->orig_bi_private = bio->bi_private; + noclone->orig_bi_iter = bio->bi_iter; + bio->bi_end_io = syno_noclone_endio; + bio->bi_private = noclone; + r = ti->type->noclone_map(ti, bio); + switch (r) { + case DM_MAPIO_REMAPPED: + trace_block_bio_remap(bio->bi_disk->queue, bio, + disk_devt(dm_disk(md)), noclone->orig_bi_iter.bi_sector); +#ifdef MY_ABC_HERE + /* Clear the flag so the underlying block device gets queue events */ + bio_clear_flag(bio, BIO_TRACE_COMPLETION); +#endif /* MY_ABC_HERE */ + ret = submit_bio_noacct(bio); + break; + case DM_MAPIO_SUBMITTED: + WARN_ON(1); + break; + case DM_MAPIO_REQUEUE: + case DM_MAPIO_KILL: + default: + DMWARN("unimplemented target noclone map return value: %d", r); + BUG(); + } + goto out; +no_fast_path: +#endif /* MY_ABC_HERE */ ret = __split_and_process_bio(md, map, bio); out: dm_put_live_table(md, srcu_idx); @@ -1784,6 +2058,9 @@ static void cleanup_mapped_device(struct mapped_device *md) destroy_workqueue(md->wq); bioset_exit(&md->bs); bioset_exit(&md->io_bs); +#ifdef MY_ABC_HERE + mempool_exit(&md->syno_noclone_pool); +#endif /* MY_ABC_HERE */ if (md->dax_dev) { kill_dax(md->dax_dev); @@ -1917,6 +2194,9 @@ static struct mapped_device *alloc_dev(int minor) spin_unlock(&_minor_lock); BUG_ON(old_md != MINOR_ALLOCED); +#ifdef MY_ABC_HERE + syno_md_fast_wakeup_info_init(&md->syno_fast_wakeup_info); +#endif /* MY_ABC_HERE */ return md; @@ -1953,6 +2233,9 @@ static int __bind_mempools(struct mapped_device *md, struct dm_table *t) { struct dm_md_mempools *p = dm_table_get_md_mempools(t); int ret = 0; +#ifdef MY_ABC_HERE + bool noclone_pool_inited = false; +#endif /* MY_ABC_HERE */ if (dm_table_bio_based(t)) { /* @@ -1979,6 +2262,19 @@ static int __bind_mempools(struct mapped_device *md, struct dm_table *t) bioset_initialized(&md->bs) || bioset_initialized(&md->io_bs)); +#ifdef MY_ABC_HERE + if (mempool_initialized(&md->syno_noclone_pool)) + ret = mempool_resize(&md->syno_noclone_pool, + p->syno_pool_size); + else + ret = mempool_init_slab_pool(&md->syno_noclone_pool, + p->syno_pool_size, + _syno_noclone_cache); + if (ret) + goto out; + noclone_pool_inited = true; +#endif /* MY_ABC_HERE */ + ret = bioset_init_from_src(&md->bs, &p->bs); if (ret) goto out; @@ -1986,6 +2282,10 @@ static int __bind_mempools(struct mapped_device *md, struct dm_table *t) if (ret) bioset_exit(&md->bs); out: +#ifdef MY_ABC_HERE + if (ret && noclone_pool_inited) + mempool_exit(&md->syno_noclone_pool); +#endif /* MY_ABC_HERE */ /* mempool bind completed, no longer need any mempools in the table */ dm_table_free_md_mempools(t); return ret; @@ -2956,6 +3256,10 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_qu if (integrity && bioset_integrity_create(&pools->bs, pool_size)) goto out; +#ifdef MY_ABC_HERE + pools->syno_pool_size = pool_size; +#endif /* MY_ABC_HERE */ + return pools; out: @@ -3165,6 +3469,71 @@ static const struct dax_operations dm_dax_ops = { .zero_page_range = dm_dax_zero_page_range, }; +#ifdef MY_ABC_HERE +static void syno_dm_fast_wakeup_md(struct mapped_device *md, struct dm_table *map) +{ +#ifdef CONFIG_BLK_DEV_MD + char b[BDEVNAME_SIZE]; + struct mddev *mddev; + struct list_head *devices; + struct dm_dev_internal *dd; + struct syno_md_fast_wakeup_info *winfo; + + if (!map) + return; + + devices = dm_table_get_devices(map); + list_for_each_entry(dd, devices, list) { + if (dd && dd->dm_dev->bdev && + strstr(bdevname(dd->dm_dev->bdev, b), "md")) { + if (dd->dm_dev->bdev->bd_disk) { + mddev = dd->dm_dev->bdev->bd_disk->private_data; + if (!mddev) + continue; + + winfo = &mddev->syno_fast_wakeup_info; + spin_lock(&winfo->active_lock); + winfo->active = true; + spin_unlock(&winfo->active_lock); + syno_md_fast_wakeup_devices(mddev); + } + } + } +#else /* CONFIG_BLK_DEV_MD */ + return; +#endif /* CONFIG_BLK_DEV_MD */ +} + +int dm_active_get(struct mapped_device *md) +{ + return md->syno_fast_wakeup_info.active ? 1 : 0; +} + +void dm_active_set(struct mapped_device *md, unsigned long value) +{ + int srcu_idx; + struct dm_table *map; + bool need_wakeup = false; + struct syno_md_fast_wakeup_info *winfo; + + winfo = &md->syno_fast_wakeup_info; + spin_lock(&winfo->active_lock); + if (value) { + if (!winfo->active) + need_wakeup = true; + winfo->active = true; + } else { + winfo->active = false; + } + spin_unlock(&winfo->active_lock); + + if (need_wakeup) { + map = dm_get_live_table(md, &srcu_idx); + syno_dm_fast_wakeup_md(md, map); + dm_put_live_table(md, srcu_idx); + } +} +#endif /* MY_ABC_HERE */ /* * module hooks */ diff --git a/drivers/md/dm.h b/drivers/md/dm.h index b441ad772c18..72baf2636967 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Internal header file for device mapper * @@ -22,6 +25,12 @@ #include #include "dm-stats.h" +#ifdef MY_ABC_HERE +#include "syno-md-fast-wakeup.h" +#ifdef CONFIG_BLK_DEV_MD +#include "md.h" +#endif /* CONFIG_BLK_DEV_MD */ +#endif /* MY_ABC_HERE */ /* * Suspend feature flags @@ -83,6 +92,11 @@ enum dm_queue_mode dm_get_md_type(struct mapped_device *md); struct target_type *dm_get_immutable_target_type(struct mapped_device *md); int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t); +#ifdef MY_ABC_HERE +int dm_active_get(struct mapped_device *md); +void dm_active_set(struct mapped_device *md, unsigned long value); +void syno_dm_fast_wakeup_dev(struct mapped_device *md, struct dm_table *map); +#endif /* MY_ABC_HERE */ /* * To check whether the target type is bio-based or not (request-based). diff --git a/drivers/md/libmd-report.c b/drivers/md/libmd-report.c new file mode 100644 index 000000000000..2941729aafde --- /dev/null +++ b/drivers/md/libmd-report.c @@ -0,0 +1,110 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifdef MY_ABC_HERE +#include +#include +#include + +#include +#include "md.h" + +int (*funcSYNOSendRaidEvent)(unsigned int, unsigned int, unsigned int, unsigned long long) = NULL; + +void syno_report_faulty_device(int md_minor, struct block_device *bdev) +{ + int index = syno_disk_get_device_index(bdev); + char b[BDEVNAME_SIZE]; + + if (bdev) + bdevname(bdev, b); + + if (index < 0) { + pr_warn("disk index get error, disk = %s, index = %d\n", b, index); + return; + } + + if (funcSYNOSendRaidEvent) + funcSYNOSendRaidEvent(MD_FAULTY_DEVICE, md_minor, index, 0); +} +EXPORT_SYMBOL(syno_report_faulty_device); + +void syno_report_bad_sector(sector_t sector, unsigned long rw, + int md_minor, struct block_device *bdev, const char *func_name) +{ + int index = syno_disk_get_device_index(bdev); + char b[BDEVNAME_SIZE]; + + if (bdev) + bdevname(bdev, b); + + pr_warn("%s error, md%d, %s index [%d], sector %llu [%s]\n", + rw ? "write" : "read", md_minor, b, index, (unsigned long long)sector, func_name); + + if (index < 0) { + pr_warn("disk index get error, disk = %s, index = %d\n", b, index); + return; + } + + if (funcSYNOSendRaidEvent) + funcSYNOSendRaidEvent((rw == WRITE) ? MD_SECTOR_WRITE_ERROR : MD_SECTOR_READ_ERROR, + md_minor, index, sector); +} +EXPORT_SYMBOL(syno_report_bad_sector); + +void syno_report_correct_bad_sector(sector_t sector, int md_minor, + struct block_device *bdev, const char *func_name) +{ + int index = syno_disk_get_device_index(bdev); + char b[BDEVNAME_SIZE]; + + if (bdev) + bdevname(bdev, b); + + pr_warn("read error corrected, md%d, %s index [%d], sector %llu [%s]\n", + md_minor, b, index, (unsigned long long)sector, func_name); + + if (index < 0) { + pr_warn("disk index get error, disk = %s, index = %d\n", b, index); + return; + } + + if (funcSYNOSendRaidEvent) + funcSYNOSendRaidEvent(MD_SECTOR_REWRITE_OK, md_minor, index, sector); +} +EXPORT_SYMBOL(syno_report_correct_bad_sector); +EXPORT_SYMBOL(funcSYNOSendRaidEvent); + +#ifdef MY_ABC_HERE +int (*funcSYNOSendAutoRemapRaidEvent)(unsigned int, unsigned long long, unsigned int) = NULL; +EXPORT_SYMBOL(funcSYNOSendAutoRemapRaidEvent); + +void syno_auto_remap_report(struct mddev *mddev, sector_t sector, struct block_device *bdev) +{ + int index = syno_disk_get_device_index(bdev); + char b[BDEVNAME_SIZE]; + + if (bdev) + bdevname(bdev, b); + + if (index < 0) { + pr_warn("disk index get error, disk = %s, index = %d\n", b, index); + return; + } + + if (funcSYNOSendAutoRemapRaidEvent == NULL) { + pr_warn("can't reference to function 'SYNOSendAutoRemapRaidEvent'\n"); + } else { + pr_warn("report md[%d] auto-remapped sector:[%llu]\n", + mddev->md_minor, (unsigned long long)sector); + funcSYNOSendAutoRemapRaidEvent(mddev->md_minor, sector, (unsigned int)index); + } +} +EXPORT_SYMBOL(syno_auto_remap_report); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c index 5ab22069b5be..fefa0b072ab3 100644 --- a/drivers/md/md-linear.c +++ b/drivers/md/md-linear.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* linear.c : Multiple Devices driver for Linux @@ -21,14 +24,25 @@ /* * find which device holds a particular offset */ +#ifdef MY_ABC_HERE +static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector, bool take_rcu) +#else /* MY_ABC_HERE */ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector) +#endif /* MY_ABC_HERE */ { int lo, mid, hi; struct linear_conf *conf; lo = 0; hi = mddev->raid_disks - 1; +#ifdef MY_ABC_HERE + if (take_rcu) + conf = rcu_dereference(mddev->private); + else + conf = mddev->private; +#else /* MY_ABC_HERE */ conf = mddev->private; +#endif /* MY_ABC_HERE */ /* * Binary Search @@ -101,9 +115,24 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks) discard_supported = true; } if (cnt != raid_disks) { +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* + * for Linear status consistense to other raid type + * Let it can assemble. + */ + mddev->degraded = mddev->raid_disks - cnt; + pr_warn("md/linear:%s: not enough drives present.\n", + mdname(mddev)); + return conf; +#else /* MY_ABC_HERE */ pr_warn("md/linear:%s: not enough drives present. Aborting!\n", mdname(mddev)); goto out; +#endif /* MY_ABC_HERE */ } if (!discard_supported) @@ -148,6 +177,9 @@ static int linear_run (struct mddev *mddev) if (md_check_no_bitmap(mddev)) return -EINVAL; +#ifdef MY_ABC_HERE + mddev->degraded = 0; +#endif /* MY_ABC_HERE */ conf = linear_conf(mddev, mddev->raid_disks); if (!conf) @@ -214,18 +246,95 @@ static void linear_free(struct mddev *mddev, void *priv) kfree(conf); } +#ifdef MY_ABC_HERE +/** + * This is end_io callback function. + * We can use this for bad sector report and device error + * handing. Prevent umount panic from file system + * + * @author \$Author: khchen $ + * @version \$Revision: 1.1 + * + * @param bio Should not be NULL. Passing from block layer + * @param error error number + */ +static void +syno_linear_end_request(struct bio *bio) +{ + struct mddev *mddev = NULL; + struct md_rdev *rdev = NULL; + struct bio *orig_bio; + + orig_bio = bio->bi_private; + + rdev = (struct md_rdev *)orig_bio->bi_next; + mddev = rdev->mddev; + orig_bio->bi_next = bio->bi_next; + orig_bio->bi_status = bio->bi_status; + +#ifdef MY_ABC_HERE + if (bio->bi_status) { + struct dev_info *tmp_dev; + sector_t report_sector; + + rcu_read_lock(); + tmp_dev = which_dev(mddev, orig_bio->bi_iter.bi_sector, true); + report_sector = orig_bio->bi_iter.bi_sector - + (tmp_dev->end_sector - rdev->sectors) + + rdev->data_offset; + rcu_read_unlock(); + + md_error(mddev, rdev); + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(report_sector, bio_data_dir(bio), + mddev->md_minor, rdev->bdev, __func__); + } +#else /* MY_ABC_HERE */ + if (bio->bi_status) + md_error(mddev, rdev); +#endif /* MY_ABC_HERE */ + + atomic_dec(&rdev->nr_pending); + bio_put(bio); + /** + * Let mount could successful and bad sector could keep accessing, + * no matter it success or not + */ + bio_endio(orig_bio); +} +#endif /* MY_ABC_HERE */ + static bool linear_make_request(struct mddev *mddev, struct bio *bio) { char b[BDEVNAME_SIZE]; struct dev_info *tmp_dev; sector_t start_sector, end_sector, data_offset; sector_t bio_sector = bio->bi_iter.bi_sector; +#ifdef MY_ABC_HERE + struct bio *cloned_bio, *orig_bio; +#endif /* MY_ABC_HERE */ if (unlikely(bio->bi_opf & REQ_PREFLUSH) && md_flush_request(mddev, bio)) return true; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (mddev->degraded) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + tmp_dev = which_dev(mddev, bio_sector, false); +#else /* MY_ABC_HERE */ tmp_dev = which_dev(mddev, bio_sector); +#endif /* MY_ABC_HERE */ start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; end_sector = tmp_dev->end_sector; data_offset = tmp_dev->rdev->data_offset; @@ -244,10 +353,27 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) struct bio *split = bio_split(bio, end_sector - bio_sector, GFP_NOIO, &mddev->bio_set); bio_chain(split, bio); +#ifdef MY_ABC_HERE + bio_set_flag(bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(bio); bio = split; } +#ifdef MY_ABC_HERE + cloned_bio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); + + if (cloned_bio) { + atomic_inc(&tmp_dev->rdev->nr_pending); + cloned_bio->bi_end_io = syno_linear_end_request; + cloned_bio->bi_private = bio; + + orig_bio = bio; + orig_bio->bi_next = (void *)tmp_dev->rdev; + bio = cloned_bio; + } +#endif /* MY_ABC_HERE */ + bio_set_dev(bio, tmp_dev->rdev->bdev); bio->bi_iter.bi_sector = bio->bi_iter.bi_sector - start_sector + data_offset; @@ -255,6 +381,14 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) if (unlikely((bio_op(bio) == REQ_OP_DISCARD) && !blk_queue_discard(bio->bi_disk->queue))) { /* Just ignore it */ +#ifdef MY_ABC_HERE + if (cloned_bio) { + atomic_dec(&tmp_dev->rdev->nr_pending); + orig_bio->bi_next = bio->bi_next; + bio_put(bio); + bio = orig_bio; + } +#endif /* MY_ABC_HERE */ bio_endio(bio); } else { if (mddev->gendisk) @@ -278,15 +412,160 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) return true; } +#ifdef MY_ABC_HERE +static void +syno_linear_status(struct seq_file *seq, struct mddev *mddev) +{ + int i; + struct linear_conf *conf = mddev->private; + + seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2); + seq_printf(seq, " [%d/%d] [", mddev->raid_disks, mddev->raid_disks - mddev->degraded); + rcu_read_lock(); + for (i = 0; i < mddev->raid_disks; i++) + { + struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); +#ifdef MY_ABC_HERE + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) + ? (test_bit(SynoDiskError, &rdev->flags) ? "E" : "U") + : "_"); +#else /* MY_ABC_HERE */ + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); +#endif /* MY_ABC_HERE */ + } + rcu_read_unlock(); + seq_printf(seq, "]"); +} +#else /* MY_ABC_HERE */ static void linear_status (struct seq_file *seq, struct mddev *mddev) { seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2); } +#endif /* MY_ABC_HERE */ static void linear_quiesce(struct mddev *mddev, int state) { } +#ifdef MY_ABC_HERE +static int +syno_linear_remove_disk(struct mddev *mddev, struct md_rdev *rdev) +{ + int err = 0; + struct linear_conf *conf = mddev->private; + int number; + + if (!rdev) + goto END; + + number = rdev->raid_disk; + + /* + * use the same synchronize method as RAID5 + * see raid5.c:raid5_remove_disk + */ + conf->disks[number].rdev = NULL; + synchronize_rcu(); + if (atomic_read(&rdev->nr_pending)) { + /* lost the race, try later */ + err = -EBUSY; + conf->disks[number].rdev = rdev; + goto END; + } + +END: + return err; +} + +/** + * This is our implement for raid handler. + * It mainly for handling device hotplug. + * We let it look like other raid type. + * Set it faulty could let SDK know it's status + * + * @author \$Author: khchen $ + * @version \$Revision: 1.1 + * + * @param mddev Should not be NULL. passing from md.c + * @param rdev Should not be NULL. passing from md.c + */ +static void +syno_linear_error_for_hotplug(struct mddev *mddev, struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + + pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n", + mdname(mddev), bdevname(rdev->bdev, b)); + if (test_and_clear_bit(In_sync, &rdev->flags)) { + if (mddev->degraded < mddev->raid_disks) { + struct syno_update_sb_work *update_sb = NULL; + + mddev->degraded++; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ + set_bit(Faulty, &rdev->flags); +#ifdef MY_ABC_HERE + clear_bit(SynoDiskError, &rdev->flags); +#endif /* MY_ABC_HERE */ + + update_sb = kzalloc(sizeof(*update_sb), GFP_ATOMIC); + if (!update_sb) { + WARN_ON(!update_sb); + goto END; + } + + INIT_WORK(&update_sb->work, syno_update_sb_task); + update_sb->mddev = mddev; + schedule_work(&update_sb->work); + } + } +END: + return; +} + +/** + * This is our implement for raid handler. + * It mainly for mdadm set device faulty. We let it look like + * other raid type. Let it become read only (scemd would remount + * if it find SynoDiskError) + * + * You should not sync super block in the same thread, otherwise + * would panic. + * + * @author \$Author: khchen $ + * @version \$Revision: 1.1 * + * + * @param mddev Should not be NULL. passing from md.c + * @param rdev Should not be NULL. passing from md.c + */ +static void +syno_linear_error_for_internal(struct mddev *mddev, struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + + pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n", + mdname(mddev), bdevname(rdev->bdev, b)); +#ifdef MY_ABC_HERE + if (!test_bit(SynoDiskError, &rdev->flags)) { + struct syno_update_sb_work *update_sb = NULL; + + set_bit(SynoDiskError, &rdev->flags); + update_sb = kzalloc(sizeof(*update_sb), GFP_ATOMIC); + if (update_sb == NULL) { + WARN_ON(!update_sb); + return; + } + + INIT_WORK(&update_sb->work, syno_update_sb_task); + update_sb->mddev = mddev; + schedule_work(&update_sb->work); + } +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ + static struct md_personality linear_personality = { .name = "linear", @@ -295,8 +574,17 @@ static struct md_personality linear_personality = .make_request = linear_make_request, .run = linear_run, .free = linear_free, +#ifdef MY_ABC_HERE + .status = syno_linear_status, +#else /* MY_ABC_HERE */ .status = linear_status, +#endif /* MY_ABC_HERE */ .hot_add_disk = linear_add, +#ifdef MY_ABC_HERE + .hot_remove_disk = syno_linear_remove_disk, + .error_handler = syno_linear_error_for_internal, + .syno_error_handler = syno_linear_error_for_hotplug, +#endif /* MY_ABC_HERE */ .size = linear_size, .quiesce = linear_quiesce, }; diff --git a/drivers/md/md.c b/drivers/md/md.c index 288d26013de2..a3af60b6f682 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* md.c : Multiple Devices driver for Linux @@ -67,6 +70,42 @@ #include "md.h" #include "md-bitmap.h" #include "md-cluster.h" +#ifdef MY_ABC_HERE +#include "syno-md-hint.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +static struct crypto_shash *syno_md_heal_csum_hash; +static void syno_md_heal_del_all_record(struct mddev *mddev); +static void syno_md_heal_create_record_cache(struct mddev *mddev); +static void syno_md_heal_destroy_record_cache(struct mddev *mddev); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef CONFIG_PRINTK +/* + * syno md ratelimit for printk, only allow 5 messages in 10 mins. + */ +#define syno_md_printk_ratelimited(fmt, ...) \ +do { \ + static DEFINE_RATELIMIT_STATE(_rs, \ + 10 * 60 * HZ, \ + 5); \ + if (__ratelimit(&_rs)) \ + printk(fmt, ##__VA_ARGS__); \ +} while (0) +#else /* CONFIG_PRINTK */ +#define syno_md_printk_ratelimited(fmt, ...) \ + no_printk(fmt, ##__VA_ARGS__) +#endif /* CONFIG_PRINTK */ +#endif /* MY_ABC_HERE */ /* pers_list is a list of registered personalities protected * by pers_lock. @@ -90,6 +129,9 @@ static struct workqueue_struct *md_rdev_misc_wq; static int remove_and_add_spares(struct mddev *mddev, struct md_rdev *this); static void mddev_detach(struct mddev *mddev); +#ifdef MY_ABC_HERE +void syno_md_fast_wakeup_devices(void *md); +#endif /* MY_ABC_HERE */ /* * Default number of read corrections we'll attempt on an rdev @@ -196,6 +238,10 @@ static int rdevs_init_serial(struct mddev *mddev) */ static int rdev_need_serial(struct md_rdev *rdev) { +#ifdef MY_ABC_HERE + if (rdev && rdev->mddev->serialize_policy) + return true; +#endif /* MY_ABC_HERE */ return (rdev && rdev->mddev->bitmap_info.max_write_behind > 0 && rdev->bdev->bd_disk->queue->nr_hw_queues != 1 && test_bit(WriteMostly, &rdev->flags)); @@ -483,6 +529,45 @@ static void md_end_io(struct bio *bio) bio->bi_end_io(bio); } +#ifdef MY_ABC_HERE +static bool syno_is_rebuilding(struct mddev *mddev) +{ + bool ret = true; + struct md_rdev* rdev; + + if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || + test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) || + test_bit(MD_RECOVERY_SYNC, &mddev->recovery) || + !test_bit(MD_RECOVERY_RECOVER, &mddev->recovery)) + ret = false; + + /* Check for replacement */ + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + if (rdev->raid_disk >= 0 && + test_bit(WantReplacement, &rdev->flags)) { + ret = false; + break; + } + rcu_read_unlock(); + + return ret; +} + +#ifdef MY_ABC_HERE +static bool syno_is_requested_resyncing(struct mddev *mddev) +{ + return (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && + !test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && + test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && + !test_bit(MD_RECOVERY_CHECK, &mddev->recovery)); +} +#endif /* MY_ABC_HERE */ + +static int enable_fast_rebuild = 0; +#endif /* MY_ABC_HERE */ + static blk_qc_t md_submit_bio(struct bio *bio) { const int rw = bio_data_dir(bio); @@ -506,6 +591,44 @@ static blk_qc_t md_submit_bio(struct bio *bio) bio_endio(bio); return BLK_QC_T_NONE; } +#ifdef MY_ABC_HERE + if (syno_md_fast_wakeup_info_update(&mddev->syno_fast_wakeup_info)) + syno_md_fast_wakeup_devices(mddev); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (bio_op(bio) == REQ_OP_UNUSED_HINT) { + int ret; + sector_t start = bio->bi_iter.bi_sector; + sector_t len = bio_sectors(bio); + sector_t end = start + len; + sector_t dev_sector; + + if (!enable_fast_rebuild || len < SYNO_HINT_MIN_LEN) + goto endio_exit; + if (!syno_is_rebuilding(mddev)) + goto endio_exit; + if (!mddev->pers->align_chunk_addr_virt_to_dev) + goto endio_exit; + /* Check if we already recover it */ + mddev->pers->align_chunk_addr_virt_to_dev(mddev, end, 0, + &dev_sector, + NULL); + if (dev_sector < mddev->curr_resync) + goto endio_exit; + + mutex_lock(&mddev->syno_rh_mutex); + if (!mddev->syno_allow_fast_rebuild) + goto unlock; + ret = syno_hint_add(&mddev->syno_rh_tree, start, end, GFP_KERNEL); + if (ret) + pr_err("%s: failed to add hint.\n", mdname(mddev)); +unlock: + mutex_unlock(&mddev->syno_rh_mutex); +endio_exit: + bio_endio(bio); + return BLK_QC_T_NONE; + } +#endif /* MY_ABC_HERE */ if (bio->bi_end_io != md_end_io) { struct md_io *md_io; @@ -525,6 +648,22 @@ static blk_qc_t md_submit_bio(struct bio *bio) /* bio could be mergeable after passing to underlayer */ bio->bi_opf &= ~REQ_NOMERGE; +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bio, BIO_CORRECTION_RETRY))) { + struct bio_vec bv; + + bio_get_first_bvec(bio, &bv); + if (unlikely(bv.bv_len != bio->bi_iter.bi_size)) + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] receive a multi-segments correction bio at sector [%llu] with sector length [%d]\n", + mdname(mddev), + (u64)bio->bi_iter.bi_sector, bio_sectors(bio)); + } + + if (unlikely(bio_flagged(bio, BIO_CORRECTION_ABORT))) + syno_md_heal_find_and_del_record(mddev, bio); +#endif /* MY_ABC_HERE */ md_handle_request(mddev, bio); return BLK_QC_T_NONE; @@ -546,6 +685,9 @@ void mddev_suspend(struct mddev *mddev) wake_up(&mddev->sb_wait); set_bit(MD_ALLOW_SB_UPDATE, &mddev->flags); smp_mb__after_atomic(); +#ifdef MY_ABC_HERE + md_wakeup_thread(mddev->thread); +#endif /* MY_ABC_HERE */ wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0); mddev->pers->quiesce(mddev, 1); clear_bit_unlock(MD_ALLOW_SB_UPDATE, &mddev->flags); @@ -745,6 +887,19 @@ void mddev_init(struct mddev *mddev) mddev->resync_min = 0; mddev->resync_max = MaxSector; mddev->level = LEVEL_NONE; +#ifdef MY_ABC_HERE + mddev->syno_md_thread_fixed_node = -1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_hint_tree_init(&mddev->syno_rh_tree); + mutex_init(&mddev->syno_rh_mutex); +#ifdef MY_ABC_HERE + syno_hint_tree_init(&mddev->syno_sh_tree); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_sb_not_clean = 0; +#endif /* MY_ABC_HERE */ } EXPORT_SYMBOL_GPL(mddev_init); @@ -1075,6 +1230,112 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, } EXPORT_SYMBOL_GPL(sync_page_io); +#ifdef MY_ABC_HERE +void SYNOSwapSuperblock0(mdp_super_t *sb) +{ + int i; + __u32 t32; + char bTmp, *ptr = (char *)sb; + + for (i = 0; i < 4096; i += 4) { + bTmp = ptr[0]; + ptr[0] = ptr[3]; + ptr[3] = bTmp; + bTmp = ptr[1]; + ptr[1] = ptr[2]; + ptr[2] = bTmp; + ptr += 4; + } + + t32 = sb->events_hi; + sb->events_hi = sb->events_lo; + sb->events_lo = t32; + + t32 = sb->cp_events_hi; + sb->cp_events_hi = sb->cp_events_lo; + sb->cp_events_lo = t32; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void syno_raid_member_auto_remap_set(struct mddev *mddev) +{ + struct md_rdev *rdev; + char b[BDEVNAME_SIZE]; + + if (mddev->syno_auto_remap == SYNO_MD_AUTO_REMAP_MODE_ISMAXDEGRADE && + mddev->pers->syno_set_rdev_auto_remap) + mddev->pers->syno_set_rdev_auto_remap(mddev); + else { + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) { + bdevname(rdev->bdev, b); + syno_bdev_remap_mode_set(rdev->bdev, mddev->syno_auto_remap); + pr_warn("md: %s: set %s to syno_auto_remap [%d]\n", mdname(mddev), b, + mddev->syno_auto_remap); + } + rcu_read_unlock(); + } +} + +static int syno_raid_auto_remap_adjust(struct mddev *mddev, int specify_setting) +{ + int old_setting = -1; + + if (!mddev || !mddev->pers) + goto err; + + old_setting = mddev->syno_auto_remap; + + if (specify_setting == SYNO_MD_AUTO_REMAP_MODE_ISMAXDEGRADE) { + if (mddev->pers->syno_is_md_max_degrade && + mddev->pers->syno_is_md_max_degrade(mddev)) { + if (!mddev->pers->syno_set_rdev_auto_remap) + specify_setting = SYNO_MD_AUTO_REMAP_MODE_FORCE_ON; + } else + specify_setting = SYNO_MD_AUTO_REMAP_MODE_FORCE_OFF; + } + + mddev->syno_auto_remap = specify_setting; + + if (old_setting != mddev->syno_auto_remap || + mddev->syno_auto_remap == SYNO_MD_AUTO_REMAP_MODE_ISMAXDEGRADE) + syno_raid_member_auto_remap_set(mddev); + else /* md's auto_remap mode does not change (remain force on/off) */ + pr_warn("md: %s: current auto_remap = %d\n", mdname(mddev), + mddev->syno_auto_remap); + +err: + // return old setting, we need use it to restore auto remap setting when needed. + return old_setting; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int syno_sync_read_sb_page_io(struct md_rdev *rdev, int size) +{ + struct bio bio; + struct bio_vec bvec; + int ret; + + bio_init(&bio, &bvec, 1); + + bio_set_dev(&bio, rdev->bdev); + bio.bi_opf = REQ_OP_READ; + bio.bi_iter.bi_sector = rdev->sb_start; + bio_add_page(&bio, rdev->sb_page, size, 0); + submit_bio_wait(&bio); + + ret = !bio.bi_status; + if (ret && bio_flagged(&bio, BIO_SYNO_AUTO_REMAP)) { + bio_clear_flag(&bio, BIO_SYNO_AUTO_REMAP); + ret = 0; + } + + return ret; +} +#endif /* MY_ABC_HERE */ + static int read_disk_sb(struct md_rdev *rdev, int size) { char b[BDEVNAME_SIZE]; @@ -1082,8 +1343,13 @@ static int read_disk_sb(struct md_rdev *rdev, int size) if (rdev->sb_loaded) return 0; +#ifdef MY_ABC_HERE + if (!syno_sync_read_sb_page_io(rdev, size)) + goto fail; +#else /* MY_ABC_HERE */ if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, 0, true)) goto fail; +#endif /* MY_ABC_HERE */ rdev->sb_loaded = 1; return 0; @@ -1256,6 +1522,13 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor bdevname(rdev->bdev, b); sb = page_address(rdev->sb_page); +#ifdef MY_ABC_HERE + if (sb->major_version == 0) { + if (sb->md_magic != MD_SB_MAGIC) { + SYNOSwapSuperblock0(sb); + } + } +#endif /* MY_ABC_HERE */ if (sb->md_magic != MD_SB_MAGIC) { pr_warn("md: invalid raid superblock magic on %s\n", b); @@ -1399,8 +1672,15 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev) if (sb->events_hi == sb->cp_events_hi && sb->events_lo == sb->cp_events_lo) { mddev->recovery_cp = sb->recovery_cp; +#ifdef MY_ABC_HERE + } else { + mddev->recovery_cp = MaxSector; + mddev->syno_sb_not_clean = 1; + } +#else /* MY_ABC_HERE */ } else mddev->recovery_cp = 0; +#endif /* MY_ABC_HERE */ } memcpy(mddev->uuid+0, &sb->set_uuid0, 4); @@ -1450,6 +1730,10 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev) set_bit(In_sync, &rdev->flags); rdev->raid_disk = desc->raid_disk; rdev->saved_raid_disk = desc->raid_disk; +#ifdef MY_ABC_HERE + if (desc->state & (1 << MD_DISK_SYNO_ERROR)) + set_bit(SynoDiskError, &rdev->flags); +#endif /* MY_ABC_HERE */ } else if (desc->state & (1<state = (1<flags)) d->state |= (1<flags)) + d->state |= (1 << MD_DISK_SYNO_ERROR); +#endif /* MY_ABC_HERE */ active++; working++; } else { @@ -1610,6 +1898,11 @@ static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev) sb->this_disk = sb->disks[rdev->desc_nr]; sb->sb_csum = calc_sb_csum(sb); +#ifdef MY_ABC_HERE +#ifdef __LITTLE_ENDIAN + SYNOSwapSuperblock0(sb); +#endif /* __LITTLE_ENDIAN */ +#endif /* MY_ABC_HERE */ } /* @@ -1891,6 +2184,12 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->reshape_backwards = 0; mddev->recovery_cp = le64_to_cpu(sb->resync_offset); +#ifdef MY_ABC_HERE + if (mddev->recovery_cp == MaxSector - 1) { + mddev->recovery_cp = MaxSector; + mddev->syno_sb_not_clean = 1; + } +#endif /* MY_ABC_HERE */ memcpy(mddev->uuid, sb->set_uuid, 16); mddev->max_disks = (4096-256)/2; @@ -1937,6 +2236,12 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT)) mddev->layout = -1; +#ifdef MY_ABC_HERE + if (mddev->level == 0 && + (le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT)) + mddev->syno_has_r0layout_feature = true; +#endif /* MY_ABC_HERE */ + if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL) set_bit(MD_HAS_JOURNAL, &mddev->flags); @@ -2015,6 +2320,12 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) &mddev->recovery)) set_bit(In_sync, &rdev->flags); } +#ifdef MY_ABC_HERE + if (role & MD_DISK_ROLE_SYNO_ERROR_PREFIX) { + set_bit(SynoDiskError, &rdev->flags); + role &= ~MD_DISK_ROLE_SYNO_ERROR_PREFIX; + } +#endif /* MY_ABC_HERE */ rdev->raid_disk = role; break; } @@ -2050,6 +2361,10 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) sb->resync_offset = cpu_to_le64(mddev->recovery_cp); else if (test_bit(MD_JOURNAL_CLEAN, &mddev->flags)) sb->resync_offset = cpu_to_le64(MaxSector); +#ifdef MY_ABC_HERE + else if (mddev->recovery_cp == MaxSector) + sb->resync_offset = cpu_to_le64(MaxSector - 1); +#endif /* MY_ABC_HERE */ else sb->resync_offset = cpu_to_le64(0); @@ -2116,6 +2431,11 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) if (mddev_is_clustered(mddev)) sb->feature_map |= cpu_to_le32(MD_FEATURE_CLUSTERED); +#ifdef MY_ABC_HERE + if (mddev->level == 0 && mddev->syno_has_r0layout_feature) + sb->feature_map |= cpu_to_le32(MD_FEATURE_RAID0_LAYOUT); +#endif /* MY_ABC_HERE */ + if (rdev->badblocks.count == 0) /* Nothing to do for bad blocks*/ ; else if (sb->bblog_offset == 0) @@ -2186,7 +2506,21 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) if (test_bit(Faulty, &rdev2->flags)) sb->dev_roles[i] = cpu_to_le16(MD_DISK_ROLE_FAULTY); else if (test_bit(In_sync, &rdev2->flags)) +#ifdef MY_ABC_HERE + { + if (test_bit(SynoDiskError, &rdev2->flags)) { + /* + * steal the left most bit for our status use. + * hope the a raid don't contain more the 0x7fff members + */ + sb->dev_roles[i] = cpu_to_le16(MD_DISK_ROLE_SYNO_ERROR_PREFIX | + rdev2->raid_disk); + } else + sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); + } +#else /* MY_ABC_HERE */ sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); +#endif /* MY_ABC_HERE */ else if (test_bit(Journal, &rdev2->flags)) sb->dev_roles[i] = cpu_to_le16(MD_DISK_ROLE_JOURNAL); else if (rdev2->raid_disk >= 0) @@ -2604,6 +2938,9 @@ static void export_rdev(struct md_rdev *rdev) void md_kick_rdev_from_array(struct md_rdev *rdev) { +#ifdef MY_ABC_HERE + syno_bdev_remap_mode_set(rdev->bdev, 0); +#endif /* MY_ABC_HERE */ unbind_rdev_from_array(rdev); export_rdev(rdev); } @@ -2819,6 +3156,9 @@ void md_update_sb(struct mddev *mddev, int force_change) mddev->can_decrease_events = 0; } else { /* otherwise we have to go forward and ... */ +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) +#endif /* MY_ABC_HERE */ mddev->events ++; mddev->can_decrease_events = nospares; } @@ -2911,7 +3251,13 @@ static int add_bound_rdev(struct md_rdev *rdev) int err = 0; bool add_journal = test_bit(Journal, &rdev->flags); +#ifdef MY_ABC_HERE + if (mddev->level == LEVEL_LINEAR || + !mddev->pers->hot_remove_disk || add_journal) { + /* we extend hot_remove_disk for linear mode. */ +#else /* MY_ABC_HERE */ if (!mddev->pers->hot_remove_disk || add_journal) { +#endif /* MY_ABC_HERE */ /* If there is hot_add_disk but no hot_remove_disk * then added disks for geometry changes, * and should be added immediately. @@ -2976,6 +3322,10 @@ state_show(struct md_rdev *rdev, char *page) (!test_bit(ExternalBbl, &flags) && rdev->badblocks.unacked_exist)) len += sprintf(page+len, "faulty%s", sep); +#ifdef MY_ABC_HERE + if (test_bit(SynoDiskError, &flags)) + len += sprintf(page+len, "error%s", sep); +#endif /* MY_ABC_HERE */ if (test_bit(In_sync, &flags)) len += sprintf(page+len, "in_sync%s", sep); if (test_bit(Journal, &flags)) @@ -3031,6 +3381,11 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) err = 0; else err = -EBUSY; +#ifdef MY_ABC_HERE + } else if (cmd_match(buf, "-error")) { + clear_bit(SynoDiskError, &rdev->flags); + err = 0; +#endif /* MY_ABC_HERE */ } else if (cmd_match(buf, "remove")) { if (rdev->mddev->pers) { clear_bit(Blocked, &rdev->flags); @@ -3058,7 +3413,12 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) mddev_create_serial_pool(rdev->mddev, rdev, false); err = 0; } else if (cmd_match(buf, "-writemostly")) { +#ifdef MY_ABC_HERE + if (!rdev->mddev->serialize_policy) + mddev_destroy_serial_pool(rdev->mddev, rdev, false); +#else /* MY_ABC_HERE */ mddev_destroy_serial_pool(rdev->mddev, rdev, false); +#endif /* MY_ABC_HERE */ clear_bit(WriteMostly, &rdev->flags); err = 0; } else if (cmd_match(buf, "blocked")) { @@ -3108,6 +3468,15 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) * become want_replacement at any time, but we then need to * check if recovery is needed. */ +#ifdef MY_ABC_HERE + if (rdev->mddev->level == SYNO_RAID_LEVEL_F1 && + rdev->mddev->syno_resync_mode != SYNO_RESYNC_MODE_REPLACE) { + pr_warn("md: %s: cannot set %s to be want_replacement\n", + mdname(rdev->mddev), rdev->bdev->bd_disk->disk_name); + err = -EINVAL; + goto err; + } +#endif /* MY_ABC_HERE */ if (rdev->raid_disk >= 0 && !test_bit(Journal, &rdev->flags) && !test_bit(Replacement, &rdev->flags)) @@ -3166,6 +3535,9 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) clear_bit(ExternalBbl, &rdev->flags); err = 0; } +#ifdef MY_ABC_HERE +err: +#endif /* MY_ABC_HERE */ if (!err) sysfs_notify_dirent_safe(rdev->sysfs_state); return err ? err : len; @@ -3755,6 +4127,9 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe if (err) goto abort_free; +#ifdef MY_ABC_HERE + syno_bdev_remap_mode_set(rdev->bdev, 0); +#endif /* MY_ABC_HERE */ kobject_init(&rdev->kobj, &rdev_ktype); size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS; @@ -5468,7 +5843,11 @@ __ATTR(fail_last_dev, S_IRUGO | S_IWUSR, fail_last_dev_show, static ssize_t serialize_policy_show(struct mddev *mddev, char *page) { +#ifdef MY_ABC_HERE + if (mddev->pers == NULL || ((mddev->pers->level != 1) && (mddev->pers->level != 10))) +#else /* MY_ABC_HERE */ if (mddev->pers == NULL || (mddev->pers->level != 1)) +#endif /* MY_ABC_HERE */ return sprintf(page, "n/a\n"); else return sprintf(page, "%d\n", mddev->serialize_policy); @@ -5494,7 +5873,11 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len) err = mddev_lock(mddev); if (err) return err; +#ifdef MY_ABC_HERE + if (mddev->pers == NULL || ((mddev->pers->level != 1) && (mddev->pers->level != 10))) { +#else /* MY_ABC_HERE */ if (mddev->pers == NULL || (mddev->pers->level != 1)) { +#endif /* MY_ABC_HERE */ pr_err("md: serialize_policy is only effective for raid1\n"); err = -EINVAL; goto unlock; @@ -5516,6 +5899,494 @@ static struct md_sysfs_entry md_serialize_policy = __ATTR(serialize_policy, S_IRUGO | S_IWUSR, serialize_policy_show, serialize_policy_store); +#ifdef MY_ABC_HERE +static ssize_t syno_md_active_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_fast_wakeup_info.active ? 1 : 0); +} + +static ssize_t +syno_md_active_store(struct mddev *mddev, const char *buf, size_t len) +{ + int err; + unsigned long value; + bool need_wakeup = false; + struct syno_md_fast_wakeup_info *winfo; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(buf, 10, &value)) + return -EINVAL; + value = !!value; + + err = mddev_lock(mddev); + if (err) + return err; + + if (mddev->pers == NULL) { + err = -EINVAL; + goto unlock; + } + + winfo = &mddev->syno_fast_wakeup_info; + spin_lock(&winfo->active_lock); + if (value) { + if (!winfo->active) + need_wakeup = true; + winfo->active = true; + md_wakeup_thread(mddev->thread); + } else { + winfo->active = false; + } + spin_unlock(&winfo->active_lock); + +unlock: + mddev_unlock(mddev); + + if (need_wakeup) { + if (unlikely(block_dump)) + pr_warn("ppid:%d(%s), pid:%d(%s), try to wakeup %s\n", + task_pid_nr(current->real_parent), current->real_parent->comm, + task_pid_nr(current), current->comm, + mdname(mddev)); + syno_md_fast_wakeup_devices(mddev); + } + + return err ?: len; +} + +static struct md_sysfs_entry md_syno_active = +__ATTR(syno_active, 0644, syno_md_active_show, syno_md_active_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t syno_md_auto_remap_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_auto_remap); +} + +static ssize_t syno_md_auto_remap_store(struct mddev *mddev, const char *page, size_t len) +{ + int err; + int value; + int auto_remap_mode = -1; + +#ifdef MY_ABC_HERE + /* No response for faulty raid */ + if (mddev->syno_nodev_and_crashed) + return -EINVAL; +#endif /* MY_ABC_HERE */ + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(page, 10, &value)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + + if (!mddev->pers) { + err = -EINVAL; + goto end; + } + + // depends on syno_is_max_degrade + switch(value) { + case SYNO_MD_AUTO_REMAP_MODE_ISMAXDEGRADE: + case SYNO_MD_AUTO_REMAP_MODE_FORCE_ON: + case SYNO_MD_AUTO_REMAP_MODE_FORCE_OFF: + auto_remap_mode = value; + break; + default: + pr_err("md: %s: auto_remap, error input\n", mdname(mddev)); + err = -EINVAL; + goto end; + } + + syno_raid_auto_remap_adjust(mddev, auto_remap_mode); + +end: + mddev_unlock(mddev); + return err ?: len; +} + +static struct md_sysfs_entry md_syno_auto_remap = +__ATTR(auto_remap, 0644, syno_md_auto_remap_show, syno_md_auto_remap_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +syno_md_sync_debug_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_sync_debug); +} + +static ssize_t +syno_md_sync_debug_store(struct mddev *mddev, const char *buf, size_t len) +{ + int err; + unsigned long value; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(buf, 10, &value)) + return -EINVAL; + value = !!value; + + err = mddev_lock(mddev); + if (err) + return err; + + mddev->syno_sync_debug = value; + + mddev_unlock(mddev); + return err ?: len; +} +static struct md_sysfs_entry md_syno_sync_debug = +__ATTR(syno_sync_debug, 0644, + syno_md_sync_debug_show, syno_md_sync_debug_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t syno_flush_plug_threshold_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_flush_plug_threshold); +} + +static ssize_t +syno_flush_plug_threshold_store(struct mddev *mddev, const char *buf, size_t len) +{ + unsigned int new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(buf, 10, &new)) + return -EINVAL; + if (new <= 0 || new > 32768) + return -EINVAL; + + if (new == mddev->syno_flush_plug_threshold) + return len; + + err = mddev_lock(mddev); + if (err) + return err; + if (mddev->pers == NULL) { + err = -EINVAL; + goto unlock; + } + mddev->syno_flush_plug_threshold = new; + +unlock: + mddev_unlock(mddev); + return err ?: len; +} + +static struct md_sysfs_entry md_syno_flush_plug_threshold = +__ATTR(syno_flush_plug_threshold, 0644, syno_flush_plug_threshold_show, + syno_flush_plug_threshold_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +syno_md_threads_fixed_node_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_md_thread_fixed_node); +} + +static ssize_t +syno_md_threads_fixed_node_store(struct mddev *mddev, + const char *page, size_t len) +{ + int err; + int new; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(page, 10, &new)) + return -EINVAL; + if (-1 != new && !node_online(new)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + if (mddev->pers == NULL) { + err = -EINVAL; + goto unlock; + } + mddev->syno_md_thread_fixed_node = new; + if (mddev->pers->adjust_md_threads_node) + mddev->pers->adjust_md_threads_node(mddev); + +unlock: + mddev_unlock(mddev); + return err ?: len; +} + +static struct md_sysfs_entry md_syno_md_threads_fixed_node = +__ATTR(syno_md_threads_fixed_node, 0644, + syno_md_threads_fixed_node_show, + syno_md_threads_fixed_node_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +hints_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%lu\n", + syno_hint_count(&mddev->syno_rh_tree)); +} + +static struct md_sysfs_entry md_syno_hints = __ATTR_RO(hints); + +static ssize_t +hints_limit_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%lu\n", + syno_hint_max_count(&mddev->syno_rh_tree)); +} + +static struct md_sysfs_entry md_syno_hints_limit = __ATTR_RO(hints_limit); + +static ssize_t +skipped_sectors_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%llu\n", + (unsigned long long)mddev->syno_rh_skipped_sectors); +} + +static struct +md_sysfs_entry md_syno_skipped_sectors = __ATTR_RO(skipped_sectors); + +#ifdef MY_ABC_HERE +static ssize_t +syno_enable_requested_resync_hints_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_enable_requested_resync_hints); +} + +static ssize_t +syno_enable_requested_resync_hints_store(struct mddev *mddev, + const char *buf, + size_t len) +{ + int ret; + bool value; + struct md_rdev *rdev; + + ret = kstrtobool(buf, &value); + if (ret) + return ret; + + if (mddev->sync_thread || + test_bit(MD_RECOVERY_RUNNING,&mddev->recovery)) + return -EBUSY; + + if (!value) { + syno_hint_tree_clear(&mddev->syno_sh_tree); + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + clear_bit(SynoNonFullInsync, &rdev->flags); + rcu_read_unlock(); + } + + mddev->syno_enable_requested_resync_hints = value; + return len; +} + +static struct md_sysfs_entry md_syno_enable_requested_resync_hints = +__ATTR(enable_requested_resync_hints, 0644, + syno_enable_requested_resync_hints_show, + syno_enable_requested_resync_hints_store); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +syno_sb_not_clean_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_sb_not_clean); +} + +static ssize_t +syno_sb_not_clean_store(struct mddev *mddev, const char *page, size_t len) +{ + unsigned int new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(page, 10, &new)) + return -EINVAL; + + new = !!new; + + err = mddev_lock(mddev); + if (err) + return err; + + mddev->syno_sb_not_clean = new; + mddev_unlock(mddev); + return len; +} + +static struct md_sysfs_entry md_syno_sb_not_clean = +__ATTR(sb_not_clean, 0644, syno_sb_not_clean_show, syno_sb_not_clean_store); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static ssize_t syno_md_data_correction_log_flag_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_md_data_correction_log_flag); +} + +static ssize_t +syno_md_data_correction_log_flag_store(struct mddev *mddev, const char *buf, size_t len) +{ + int err; + int value; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(buf, 10, &value)) + return -EINVAL; + if (value != SYNO_MD_DATA_CORRECTION_LOG_OFF && + value != SYNO_MD_DATA_CORRECTION_LOG_ALL && + value != SYNO_MD_DATA_CORRECTION_LOG_ONLY_ERR && + value != SYNO_MD_DATA_CORRECTION_LOG_IN_INFO) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + + mddev->syno_md_data_correction_log_flag = value; + + mddev_unlock(mddev); + return err ?: len; +} + +static struct md_sysfs_entry md_data_correction_log_flag = +__ATTR(syno_md_data_correction_log_flag, 0644, + syno_md_data_correction_log_flag_show, + syno_md_data_correction_log_flag_store); + +static ssize_t syno_heal_record_cnt_max_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_md_heal_record_cnt_max); +} + +static ssize_t +syno_heal_record_cnt_max_store(struct mddev *mddev, const char *buf, size_t len) +{ + int err; + unsigned long value; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(buf, 10, &value)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + + mddev->syno_md_heal_record_cnt_max = value; + + mddev_unlock(mddev); + return err ?: len; +} + +static struct md_sysfs_entry md_heal_record_cnt_max = +__ATTR(syno_heal_record_cnt_max, 0644, + syno_heal_record_cnt_max_show, + syno_heal_record_cnt_max_store); + +static void syno_md_heal_record_show(struct mddev *mddev) +{ + int idx = 1; + int total; + struct syno_md_heal_record *heal_record = NULL; + + read_lock_irq(&mddev->record_list_lock); + + total = atomic_read(&mddev->syno_md_heal_record_cnt); + list_for_each_entry(heal_record, &mddev->syno_md_heal_record_list, record_list) + pr_info("%s: [Self Heal] record [%d/%d] at sector [%llu]\n", + mdname(mddev), idx++, total, (u64)heal_record->sector_start); + + read_unlock_irq(&mddev->record_list_lock); +} + +static ssize_t syno_heal_record_cnt_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", atomic_read(&mddev->syno_md_heal_record_cnt)); +} + +static ssize_t +syno_heal_record_cnt_store(struct mddev *mddev, const char *buf, size_t len) +{ + unsigned long value; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(buf, 10, &value)) + return -EINVAL; + + if (value != 0) + syno_md_heal_record_show(mddev); + else + syno_md_heal_del_all_record(mddev); + + return len; +} + +static struct md_sysfs_entry md_heal_record_cnt = +__ATTR(syno_heal_record_cnt, 0644, + syno_heal_record_cnt_show, + syno_heal_record_cnt_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t resync_mode_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%d\n", mddev->syno_resync_mode); +} + +static ssize_t resync_mode_store(struct mddev *mddev, const char *page, size_t len) +{ + int value; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(page, 10, &value)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + + switch(value) { + case SYNO_RESYNC_MODE_NORMAL: + case SYNO_RESYNC_MODE_REPAIR: + case SYNO_RESYNC_MODE_REPLACE: + mddev->syno_resync_mode = value; + break; + default: + pr_err("md: %s: resync_mode error input\n", mdname(mddev)); + err = -EINVAL; + } + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry md_resync_mode = +__ATTR(resync_mode, 0644, resync_mode_show, resync_mode_store); +#endif /* MY_ABC_HERE */ static struct attribute *md_default_attrs[] = { &md_level.attr, @@ -5536,6 +6407,23 @@ static struct attribute *md_default_attrs[] = { &md_consistency_policy.attr, &md_fail_last_dev.attr, &md_serialize_policy.attr, +#ifdef MY_ABC_HERE + &md_syno_active.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_syno_flush_plug_threshold.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_syno_md_threads_fixed_node.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_heal_record_cnt.attr, + &md_heal_record_cnt_max.attr, + &md_data_correction_log_flag.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_syno_auto_remap.attr, +#endif /* MY_ABC_HERE */ NULL, }; @@ -5554,6 +6442,23 @@ static struct attribute *md_redundancy_attrs[] = { &md_suspend_hi.attr, &md_bitmap.attr, &md_degraded.attr, +#ifdef MY_ABC_HERE + &md_syno_sync_debug.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_syno_hints.attr, + &md_syno_hints_limit.attr, + &md_syno_skipped_sectors.attr, +#ifdef MY_ABC_HERE + &md_syno_enable_requested_resync_hints.attr, +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_syno_sb_not_clean.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &md_resync_mode.attr, +#endif /* MY_ABC_HERE */ NULL, }; static struct attribute_group md_redundancy_group = { @@ -5836,7 +6741,11 @@ static void md_safemode_timeout(struct timer_list *t) md_wakeup_thread(mddev->thread); } +#ifdef MY_ABC_HERE +static int start_dirty_degraded = 1; +#else /* MY_ABC_HERE */ static int start_dirty_degraded; +#endif /* MY_ABC_HERE */ int md_run(struct mddev *mddev) { @@ -5989,6 +6898,38 @@ int md_run(struct mddev *mddev) if (start_readonly && mddev->ro == 0) mddev->ro = 2; /* read-only, but switch on first write */ +#ifdef MY_ABC_HERE + syno_md_fast_wakeup_info_init(&mddev->syno_fast_wakeup_info); + mddev->syno_fast_wakeup_page = alloc_page(GFP_KERNEL); + if (!mddev->syno_fast_wakeup_page) + pr_err("%s: failed to allocate page for fast wakeup\n", mdname(mddev)); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_sync_debug = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (0 == strcmp("md0", mdname(mddev)) || 0 == strcmp("md1", mdname(mddev))) + mddev->parallel_resync = 1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_nodev_and_crashed = MD_NOT_CRASHED; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_md_heal_create_record_cache(mddev); + rwlock_init(&mddev->record_list_lock); + INIT_LIST_HEAD(&mddev->syno_md_heal_record_list); + mddev->syno_md_data_correction_log_flag = SYNO_MD_DATA_CORRECTION_LOG_ALL; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (mddev->level == 1 || mddev->level == 10) { +#else /* MY_ABC_HERE */ + if (mddev->level == 1) { +#endif /* MY_ABC_HERE */ + mddev_create_serial_pool(mddev, NULL, true); + mddev->serialize_policy = 1; + } +#endif /* MY_ABC_HERE */ err = pers->run(mddev); if (err) @@ -6031,6 +6972,9 @@ int md_run(struct mddev *mddev) mempool_create_kmalloc_pool(NR_SERIAL_INFOS, sizeof(struct serial_info)); if (!mddev->serial_info_pool) { +#ifdef MY_ABC_HERE + rdevs_uninit_serial(mddev); +#endif /* MY_ABC_HERE */ err = -ENOMEM; goto bitmap_abort; } @@ -6088,8 +7032,16 @@ int md_run(struct mddev *mddev) set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) + mddev->syno_nodev_and_crashed = MD_CRASHED_ASSEMBLE; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + md_update_sb(mddev, 1); +#else /* MY_ABC_HERE */ if (mddev->sb_flags) md_update_sb(mddev, 0); +#endif /* MY_ABC_HERE */ md_new_event(mddev); return 0; @@ -6101,6 +7053,20 @@ int md_run(struct mddev *mddev) mddev->private = NULL; module_put(pers->owner); md_bitmap_destroy(mddev); +#ifdef MY_ABC_HERE + if (mddev->syno_fast_wakeup_page) + put_page(mddev->syno_fast_wakeup_page); + mddev->syno_fast_wakeup_page = NULL; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_md_heal_destroy_record_cache(mddev); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (mddev->serialize_policy) { + mddev_destroy_serial_pool(mddev, NULL, true); + mddev->serialize_policy = 0; + } +#endif /* MY_ABC_HERE */ abort: bioset_exit(&mddev->bio_set); bioset_exit(&mddev->sync_set); @@ -6304,6 +7270,9 @@ static void mddev_detach(struct mddev *mddev) static void __md_stop(struct mddev *mddev) { struct md_personality *pers = mddev->pers; +#ifdef MY_ABC_HERE + md_update_sb(mddev, 1); +#endif /* MY_ABC_HERE */ md_bitmap_destroy(mddev); mddev_detach(mddev); /* Ensure ->event_work is done */ @@ -6318,6 +7287,23 @@ static void __md_stop(struct mddev *mddev) mddev->to_remove = &md_redundancy_group; module_put(pers->owner); clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); +#ifdef MY_ABC_HERE + if (mddev->syno_fast_wakeup_page) + put_page(mddev->syno_fast_wakeup_page); + mddev->syno_fast_wakeup_page = NULL; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mutex_lock(&mddev->syno_rh_mutex); + syno_hint_tree_clear(&mddev->syno_rh_tree); + mutex_unlock(&mddev->syno_rh_mutex); +#ifdef MY_ABC_HERE + syno_hint_tree_clear(&mddev->syno_sh_tree); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_md_heal_del_all_record(mddev); + syno_md_heal_destroy_record_cache(mddev); +#endif /* MY_ABC_HERE */ } void md_stop(struct mddev *mddev) @@ -6454,6 +7440,11 @@ static int do_md_stop(struct mddev *mddev, int mode, if (mddev->ro) mddev->ro = 0; +#ifdef MY_ABC_HERE + mddev->syno_auto_remap = SYNO_MD_AUTO_REMAP_MODE_FORCE_OFF; + syno_raid_member_auto_remap_set(mddev); +#endif /* MY_ABC_HERE */ + } else mutex_unlock(&mddev->open_mutex); /* @@ -6721,6 +7712,10 @@ static int get_disk_info(struct mddev *mddev, void __user * arg) else if (test_bit(In_sync, &rdev->flags)) { info.state |= (1<flags)) + info.state |= (1 << MD_DISK_SYNO_ERROR); +#endif /* MY_ABC_HERE */ } if (test_bit(Journal, &rdev->flags)) info.state |= (1<bdev, b), mdname(mddev)); +#endif /* MY_ABC_HERE */ if (mddev_is_clustered(mddev)) { if (md_cluster_ops->remove_disk(mddev, rdev)) goto busy; @@ -6987,6 +7986,12 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev) busy: pr_debug("md: cannot remove active disk %s from %s ...\n", bdevname(rdev->bdev,b), mdname(mddev)); +#ifdef MY_ABC_HERE + syno_md_printk_ratelimited(KERN_WARNING + "%s (%d): cannot remove active disk %s from %s ... rdev->raid_disk %d pending %u\n", + __func__, __LINE__, bdevname(rdev->bdev, b), mdname(mddev), + rdev->raid_disk, atomic_read(&rdev->nr_pending)); +#endif /* MY_ABC_HERE */ return -EBUSY; } @@ -7520,6 +8525,10 @@ static inline bool md_ioctl_valid(unsigned int cmd) case STOP_ARRAY: case STOP_ARRAY_RO: case CLUSTERED_DISK_NACK: +#ifdef MY_ABC_HERE + case GET_ARRAY_STATUS: + case GET_SYNC_STATUS: +#endif /* MY_ABC_HERE */ return true; default: return false; @@ -7594,6 +8603,66 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, err = get_bitmap_file(mddev, argp); goto out; +#ifdef MY_ABC_HERE + /* 0: Raid status ok, 1: raid degrade, 2: raid crashed */ + case GET_ARRAY_STATUS: + { + int ret = 0; +#ifdef MY_ABC_HERE + struct md_rdev *rdev; +#endif /* MY_ABC_HERE */ + + if (mddev->degraded) + ret = 1; +#ifdef MY_ABC_HERE + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + if (rdev && test_bit(SynoDiskError, &rdev->flags)) { + ret = 3; + break; + } + rcu_read_unlock(); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) + ret = 2; +#endif /* MY_ABC_HERE */ + if (copy_to_user(argp, &ret, sizeof(ret))) { + err = -EFAULT; + } + goto out; + } + case GET_SYNC_STATUS: + { + MD_SYNC_STATUS status; + if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || + test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) { + status.inSync = 1; + } else { + status.inSync = 0; + } + if (0 == mddev->level || LEVEL_LINEAR == mddev->level) { + /* because we set inSync to 0 for linear and RAID0, + remove those non-necessary clear_bit(MD_RECOVERY_NEEDED) for RAID0 or linear */ + status.inSync = 0; + } + if (mddev->curr_resync > 2) { + status.finishSectors = (mddev->curr_resync - atomic_read(&mddev->recovery_active)); + } else { + status.finishSectors = 0; + } + + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) + status.totalSectors = mddev->resync_max_sectors; + else + status.totalSectors = mddev->dev_sectors; + + if (copy_to_user(argp, &status, sizeof(status))) { + err = -EFAULT; + } + goto out; + } +#endif /* MY_ABC_HERE */ } if (cmd == ADD_NEW_DISK || cmd == HOT_ADD_DISK) @@ -7918,6 +8987,9 @@ const struct block_device_operations md_fops = static int md_thread(void *arg) { struct md_thread *thread = arg; +#ifdef MY_ABC_HERE + int node = -1; +#endif /* MY_ABC_HERE */ /* * md_thread is a 'system-thread', it's priority should be very @@ -7948,6 +9020,18 @@ static int md_thread(void *arg) || kthread_should_stop() || kthread_should_park(), thread->timeout); +#ifdef MY_ABC_HERE + if (node != thread->mddev->syno_md_thread_fixed_node) { + node = thread->mddev->syno_md_thread_fixed_node; + if (-1 == node) + set_cpus_allowed_ptr(current, + cpu_online_mask); + else if (node_online(node)) + set_cpus_allowed_ptr(current, + cpumask_of_node(node)); + } +#endif /* MY_ABC_HERE */ + clear_bit(THREAD_WAKEUP, &thread->flags); if (kthread_should_park()) kthread_parkme(); @@ -8014,12 +9098,40 @@ EXPORT_SYMBOL(md_unregister_thread); void md_error(struct mddev *mddev, struct md_rdev *rdev) { +#ifdef MY_ABC_HERE + char b[BDEVNAME_SIZE]; +#endif /* MY_ABC_HERE */ if (!rdev || test_bit(Faulty, &rdev->flags)) return; if (!mddev->pers || !mddev->pers->error_handler) return; - mddev->pers->error_handler(mddev,rdev); +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (syno_is_device_disappear(rdev->bdev)) { + pr_warn("%s: no device, %s has been removed\n", + __func__, bdevname(rdev->bdev, b)); + if (mddev->pers->syno_error_handler) + mddev->pers->syno_error_handler(mddev, rdev); + else + mddev->pers->error_handler(mddev, rdev); + } else { +#if defined(MY_ABC_HERE) && defined(MY_ABC_HERE) + if (!test_bit(SynoDiskError, &rdev->flags)) + syno_report_faulty_device(mddev->md_minor, rdev->bdev); +#endif /* MY_ABC_HERE && MY_ABC_HERE */ + pr_warn("%s: %s is being to be set faulty\n", + __func__, bdevname(rdev->bdev, b)); + mddev->pers->error_handler(mddev, rdev); + } +#else /* MY_ABC_HERE */ + pr_warn("%s: %s is being to be set faulty\n", + __func__, bdevname(rdev->bdev, b)); + mddev->pers->error_handler(mddev, rdev); +#endif /* MY_ABC_HERE */ +#else /* MY_ABC_HERE */ + mddev->pers->error_handler(mddev, rdev); +#endif /* MY_ABC_HERE */ if (mddev->degraded) set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); sysfs_notify_dirent_safe(rdev->sysfs_state); @@ -8060,6 +9172,16 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev) sector_t rt, curr_mark_cnt, resync_mark_cnt; int scale, recovery_active; unsigned int per_milli; +#ifdef MY_ABC_HERE + char *sync_action; + + sync_action = (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) ? + "reshape" : + (test_bit(MD_RECOVERY_CHECK, &mddev->recovery) ? + "check" : + (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? + "resync" : "recovery"))); +#endif /* MY_ABC_HERE */ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) || test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) @@ -8069,9 +9191,18 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev) resync = mddev->curr_resync; if (resync <= 3) { +#ifdef MY_ABC_HERE + if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) { + /* Still cleaning up */ + resync = max_sectors; + seq_printf(seq, "\t%s=CLEANING UP", sync_action); + return 1; + } +#else /* MY_ABC_HERE */ if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) /* Still cleaning up */ resync = max_sectors; +#endif /* MY_ABC_HERE */ } else if (resync > max_sectors) resync = max_sectors; else @@ -8096,13 +9227,21 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev) return 1; } if (mddev->recovery_cp < MaxSector) { +#ifdef MY_ABC_HERE + seq_printf(seq, "\t%s=PENDING", sync_action); +#else /* MY_ABC_HERE */ seq_printf(seq, "\tresync=PENDING"); +#endif /* MY_ABC_HERE */ return 1; } return 0; } if (resync < 3) { +#ifdef MY_ABC_HERE + seq_printf(seq, "\t%s=DELAYED", sync_action); +#else /* MY_ABC_HERE */ seq_printf(seq, "\tresync=DELAYED"); +#endif /* MY_ABC_HERE */ return 1; } @@ -8132,12 +9271,16 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev) seq_printf(seq, "] "); } seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)", +#ifdef MY_ABC_HERE + sync_action, +#else /* MY_ABC_HERE */ (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)? "reshape" : (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)? "check" : (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? "resync" : "recovery"))), +#endif /* MY_ABC_HERE */ per_milli/10, per_milli % 10, (unsigned long long) resync/2, (unsigned long long) max_sectors/2); @@ -8296,6 +9439,12 @@ static int md_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "(F)"); continue; } +#ifdef MY_ABC_HERE + if (test_bit(SynoDiskError, &rdev->flags)) { + seq_printf(seq, "(E)"); + continue; + } +#endif /* MY_ABC_HERE */ if (rdev->raid_disk < 0) seq_printf(seq, "(S)"); /* spare */ if (test_bit(Replacement, &rdev->flags)) @@ -8667,6 +9816,15 @@ void md_do_sync(struct md_thread *thread) char *desc, *action = NULL; struct blk_plug plug; int ret; +#ifdef MY_ABC_HERE + bool is_rebuilding; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + sector_t tmp_curr_resync; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int old_auto_remap_setting = -1; +#endif /* MY_ABC_HERE */ /* just incase thread restarts... */ if (test_bit(MD_RECOVERY_DONE, &mddev->recovery) || @@ -8676,6 +9834,33 @@ void md_do_sync(struct md_thread *thread) set_bit(MD_RECOVERY_INTR, &mddev->recovery); return; } +#ifdef MY_ABC_HERE + is_rebuilding = syno_is_rebuilding(mddev); + if (is_rebuilding) { + mutex_lock(&mddev->syno_rh_mutex); + if (syno_hint_count(&mddev->syno_rh_tree)) + pr_err("%s: %lu hints are aborted, because it arrives before rebuild start\n", + mdname(mddev), syno_hint_count(&mddev->syno_rh_tree)); + syno_hint_tree_clear(&mddev->syno_rh_tree); + mddev->syno_rh_skipped_sectors = 0; + mutex_unlock(&mddev->syno_rh_mutex); +#ifdef MY_ABC_HERE + syno_hint_tree_clear(&mddev->syno_sh_tree); + } else if (!syno_is_requested_resyncing(mddev) && + !test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) { + syno_hint_tree_clear(&mddev->syno_sh_tree); + mddev->syno_enable_requested_resync_hints = false; + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + clear_bit(SynoNonFullInsync, &rdev->flags); + rcu_read_unlock(); +#endif /* MY_ABC_HERE */ + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + old_auto_remap_setting = syno_raid_auto_remap_adjust(mddev, + SYNO_MD_AUTO_REMAP_MODE_ISMAXDEGRADE); +#endif /* MY_ABC_HERE */ if (mddev_is_clustered(mddev)) { ret = md_cluster_ops->resync_start(mddev); @@ -8723,6 +9908,10 @@ void md_do_sync(struct md_thread *thread) * */ +#ifdef MY_ABC_HERE + set_bit(MD_SB_CHANGE_CLEAN, &mddev->sb_flags); + md_wakeup_thread(mddev->thread); +#endif /* MY_ABC_HERE */ do { int mddev2_minor = -1; mddev->curr_resync = 2; @@ -8822,12 +10011,20 @@ void md_do_sync(struct md_thread *thread) mddev->pers->quiesce(mddev, 0); } } - +#ifdef MY_ABC_HERE + syno_report_sync_status(desc, 0, 0, mddev->md_minor); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + pr_warn("md: %s of RAID array %s\n", desc, mdname(mddev)); + pr_warn("md: minimum _guaranteed_ speed: %d KB/sec/disk.\n", speed_min(mddev)); + pr_warn("md: using maximum available idle IO bandwidth (but not more than %d KB/sec) for %s.\n", + speed_max(mddev), desc); +#else /* MY_ABC_HERE */ pr_info("md: %s of RAID array %s\n", desc, mdname(mddev)); pr_debug("md: minimum _guaranteed_ speed: %d KB/sec/disk.\n", speed_min(mddev)); pr_debug("md: using maximum available idle IO bandwidth (but not more than %d KB/sec) for %s.\n", speed_max(mddev), desc); - +#endif /* MY_ABC_HERE */ is_mddev_idle(mddev, 1); /* this initializes IO event counters */ io_sectors = 0; @@ -8860,6 +10057,10 @@ void md_do_sync(struct md_thread *thread) md_new_event(mddev); update_time = jiffies; +#ifdef MY_ABC_HERE + if (is_rebuilding) + mddev->syno_last_rebuild_start = j; +#endif /* MY_ABC_HERE */ blk_start_plug(&plug); while (j < max_sectors) { sector_t sectors; @@ -8964,6 +10165,13 @@ void md_do_sync(struct md_thread *thread) /((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > speed_min(mddev)) { +#ifdef MY_ABC_HERE + if ((currspeed > speed_max(mddev)) || + !is_mddev_idle(mddev, 0)) { + msleep(500); + goto repeat; + } +#else /* MY_ABC_HERE */ if (currspeed > speed_max(mddev)) { msleep(500); goto repeat; @@ -8976,11 +10184,18 @@ void md_do_sync(struct md_thread *thread) wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active)); } +#endif /* MY_ABC_HERE */ } } +#ifdef MY_ABC_HERE + pr_warn("md: %s: %s %s.\n",mdname(mddev), desc, + test_bit(MD_RECOVERY_INTR, &mddev->recovery) + ? "interrupted" : "done"); +#else /* MY_ABC_HERE */ pr_info("md: %s: %s %s.\n",mdname(mddev), desc, test_bit(MD_RECOVERY_INTR, &mddev->recovery) ? "interrupted" : "done"); +#endif /* MY_ABC_HERE */ /* * this also signals 'finished resyncing' to md_stop */ @@ -8994,6 +10209,10 @@ void md_do_sync(struct md_thread *thread) sysfs_notify_dirent_safe(mddev->sysfs_completed); } mddev->pers->sync_request(mddev, max_sectors, &skipped); +#ifdef MY_ABC_HERE + syno_report_sync_status(desc, 1, (test_bit(MD_RECOVERY_INTR, &mddev->recovery) ? 1 : 0), + mddev->md_minor); +#endif /* MY_ABC_HERE */ if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && mddev->curr_resync > 3) { @@ -9061,11 +10280,42 @@ void md_do_sync(struct md_thread *thread) } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) mddev->resync_min = mddev->curr_resync_completed; set_bit(MD_RECOVERY_DONE, &mddev->recovery); +#ifdef MY_ABC_HERE + tmp_curr_resync = mddev->curr_resync; +#endif /* MY_ABC_HERE */ mddev->curr_resync = 0; spin_unlock(&mddev->lock); +#ifdef MY_ABC_HERE + if (is_rebuilding) { + mutex_lock(&mddev->syno_rh_mutex); + syno_hint_tree_clear(&mddev->syno_rh_tree); + mutex_unlock(&mddev->syno_rh_mutex); +#ifdef MY_ABC_HERE + if (mddev->syno_enable_requested_resync_hints && + tmp_curr_resync > mddev->syno_last_rebuild_start && + syno_hint_add(&mddev->syno_sh_tree, + mddev->syno_last_rebuild_start, + tmp_curr_resync, GFP_KERNEL)) + pr_err("%s: failed to add requested resync hint\n", + mdname(mddev)); + } else if (syno_is_requested_resyncing(mddev)) { + syno_hint_tree_clear(&mddev->syno_sh_tree); + mddev->syno_enable_requested_resync_hints = false; + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + clear_bit(SynoNonFullInsync, &rdev->flags); + rcu_read_unlock(); +#endif /* MY_ABC_HERE */ + } +#endif /* MY_ABC_HERE */ + wake_up(&resync_wait); md_wakeup_thread(mddev->thread); +#ifdef MY_ABC_HERE + // restore old setting + old_auto_remap_setting = syno_raid_auto_remap_adjust(mddev, old_auto_remap_setting); +#endif /* MY_ABC_HERE */ return; } EXPORT_SYMBOL_GPL(md_do_sync); @@ -9190,6 +10440,41 @@ static void md_start_sync(struct work_struct *ws) md_new_event(mddev); } +#ifdef MY_ABC_HERE +static int can_md_do_resync(struct mddev *mddev) +{ + int can_resync = (mddev->syno_resync_mode == SYNO_RESYNC_MODE_NORMAL ? 0 : 1); + sector_t min_recovery_offset = MaxSector; + struct md_rdev *rdev; + + if (mddev->level != SYNO_RAID_LEVEL_F1) + return 1; + + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + if (rdev->raid_disk >= 0 && + !test_bit(Faulty, &rdev->flags) && + !test_bit(In_sync, &rdev->flags) && + rdev->recovery_offset < min_recovery_offset) + min_recovery_offset = rdev->recovery_offset; + rcu_read_unlock(); + + if (min_recovery_offset > 0) + return 1; + + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) + return 1; + + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) + return 1; + + /* recovery */ + if (can_resync == 0) + pr_warn("md: %s: refuse to start recovery\n", mdname(mddev)); + return can_resync; +} +#endif /* MY_ABC_HERE */ + /* * This routine is regularly called by all per-raid-array threads to * deal with generic issues like resync and super-block update. @@ -9344,6 +10629,11 @@ void md_check_recovery(struct mddev *mddev) */ if (mddev->reshape_position != MaxSector) { +#ifdef MY_ABC_HERE + /* If it is possible. remove faulty disks */ + if (mddev->degraded) + remove_and_add_spares(mddev, NULL); +#endif /* MY_ABC_HERE */ if (mddev->pers->check_reshape == NULL || mddev->pers->check_reshape(mddev) != 0) /* Cannot proceed */ @@ -9362,6 +10652,14 @@ void md_check_recovery(struct mddev *mddev) /* nothing to be done ... */ goto not_running; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + pr_warn("%s: crashed, stop sync\n", mdname(mddev)); + clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); + clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery); + goto not_running; + } +#endif /* MY_ABC_HERE */ if (mddev->pers->sync_request) { if (spares) { /* We are adding a device or devices to an array @@ -9370,9 +10668,18 @@ void md_check_recovery(struct mddev *mddev) */ md_bitmap_write_all(mddev->bitmap); } +#ifdef MY_ABC_HERE + if (can_md_do_resync(mddev)) { + INIT_WORK(&mddev->del_work, md_start_sync); + queue_work(md_misc_wq, &mddev->del_work); + goto unlock; + } else + goto not_running; +#else /* MY_ABC_HERE */ INIT_WORK(&mddev->del_work, md_start_sync); queue_work(md_misc_wq, &mddev->del_work); goto unlock; +#endif /* MY_ABC_HERE */ } not_running: if (!mddev->sync_thread) { @@ -9397,7 +10704,18 @@ void md_reap_sync_thread(struct mddev *mddev) bool is_reshaped = false; /* resync has finished, collect result */ +#ifdef MY_ABC_HERE + set_bit(MD_ALLOW_SB_UPDATE, &mddev->flags); + smp_mb__after_atomic(); +#ifdef MY_ABC_HERE + md_wakeup_thread(mddev->thread); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ md_unregister_thread(&mddev->sync_thread); +#ifdef MY_ABC_HERE + clear_bit_unlock(MD_ALLOW_SB_UPDATE, &mddev->flags); + wait_event(mddev->sb_wait, !test_bit(MD_UPDATING_SB, &mddev->flags)); +#endif /* MY_ABC_HERE */ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && mddev->degraded != mddev->raid_disks) { @@ -9562,10 +10880,21 @@ static void md_geninit(void) proc_create("mdstat", S_IRUGO, NULL, &mdstat_proc_ops); } +#ifdef MY_ABC_HERE +int syno_raid_disk_unplug(char *szArgDiskName); +#endif /* MY_ABC_HERE */ + static int __init md_init(void) { int ret = -ENOMEM; +#ifdef MY_ABC_HERE + ret = syno_md_hint_init(); + if (ret) + goto err_syno_md_hint; + ret = -ENOMEM; +#endif /* MY_ABC_HERE */ + md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM, 0); if (!md_wq) goto err_wq; @@ -9594,6 +10923,21 @@ static int __init md_init(void) raid_table_header = register_sysctl_table(raid_root_table); md_geninit(); +#ifdef MY_ABC_HERE +#ifdef CONFIG_SCSI + syno_raid_scsi_unplug = syno_raid_disk_unplug; +#endif /* CONFIG_SCSI */ +#ifdef CONFIG_BLK_DEV_NVME + syno_raid_nvme_unplug = syno_raid_disk_unplug; +#endif /* CONFIG_BLK_DEV_NVME */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_md_heal_csum_hash = crypto_alloc_shash("crc32c", 0, 0); + if (IS_ERR(syno_md_heal_csum_hash)) { + pr_err("[Self Heal] failed to init csum hash for md\n"); + syno_md_heal_csum_hash = NULL; + } +#endif /* MY_ABC_HERE */ return 0; err_mdp: @@ -9605,6 +10949,10 @@ static int __init md_init(void) err_misc_wq: destroy_workqueue(md_wq); err_wq: +#ifdef MY_ABC_HERE + syno_md_hint_exit(); +err_syno_md_hint: +#endif /* MY_ABC_HERE */ return ret; } @@ -9859,6 +11207,10 @@ static __exit void md_exit(void) struct list_head *tmp; int delay = 1; +#ifdef MY_ABC_HERE + if (!IS_ERR_OR_NULL(syno_md_heal_csum_hash)) + crypto_free_shash(syno_md_heal_csum_hash); +#endif /* MY_ABC_HERE */ blk_unregister_region(MKDEV(MD_MAJOR,0), 512); blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS); @@ -9893,6 +11245,9 @@ static __exit void md_exit(void) destroy_workqueue(md_rdev_misc_wq); destroy_workqueue(md_misc_wq); destroy_workqueue(md_wq); +#ifdef MY_ABC_HERE + syno_md_hint_exit(); +#endif /* MY_ABC_HERE */ } subsys_initcall(md_init); @@ -9911,6 +11266,670 @@ module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR); module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR); module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR); module_param(create_on_open, bool, S_IRUSR|S_IWUSR); +#ifdef MY_ABC_HERE +module_param(enable_fast_rebuild, int, S_IRUSR|S_IWUSR); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * Modified from action_store + */ +static int syno_set_array_frozen(struct mddev *mddev, bool frozen) +{ + if (!mddev->pers || !mddev->pers->sync_request) + goto END; + + if (frozen) + set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); + else + clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); + if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && + mddev_lock(mddev) == 0) { + if (work_pending(&mddev->del_work)) + flush_workqueue(md_misc_wq); + if (mddev->sync_thread) { + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + md_reap_sync_thread(mddev); + } + mddev_unlock(mddev); + } + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + md_wakeup_thread(mddev->thread); + sysfs_notify_dirent_safe(mddev->sysfs_action); + +END: + return 0; +} + +static int syno_hot_remove_disk(struct mddev *mddev, dev_t dev) +{ + int err = -1; + + if (mddev_lock(mddev)) { + pr_warn("%s (%d): mddev_lock fail try again!\n", __func__, __LINE__); + return -EBUSY; + } + + err = hot_remove_disk(mddev, dev); + + mddev_unlock(mddev); + return err; +} + +struct syno_raid_unplug_work { + struct work_struct work; + char szDiskName[BDEVNAME_SIZE]; +}; + +struct syno_rdev_unplug_work { + struct work_struct work; + struct mddev *mddev; + dev_t dev; +}; + +static int syno_raid_unplug_single_rdev(struct mddev *mddev, dev_t dev) +{ + int err; + int res = 0; + bool frozen = test_bit(MD_RECOVERY_FROZEN, &mddev->recovery); + char b[BDEVNAME_SIZE]; + struct md_rdev *rdev; + + if (!frozen) + syno_set_array_frozen(mddev, true); + + rcu_read_lock(); + rdev = md_find_rdev_rcu(mddev, dev); + if (!rdev) { + res = 0; + goto END; + } else { + syno_md_printk_ratelimited(KERN_WARNING + "%s (%d): remove active disk %s from %s raid_disks %d mddev->degraded %d mddev->level %d\n", + __func__, __LINE__, + bdevname(rdev->bdev, b), mdname(mddev), + mddev->raid_disks, mddev->degraded, mddev->level); + } + rcu_read_unlock(); + + err = set_disk_faulty(mddev, dev); + if (err == -ENODEV) { + res = 0; + goto END; + } else if (err == -EBUSY) { + res = -1; + goto END; + } + + err = syno_hot_remove_disk(mddev, dev); + if (err == -EBUSY) { + res = -1; + goto END; + } + +END: + if (!frozen) + syno_set_array_frozen(mddev, false); + return res; +} + +void syno_raid_unplug_task(struct work_struct *work) +{ + struct mddev *mddev; + struct md_rdev *rdev; + struct list_head *mdev_tmp; + char *szDiskName; + struct syno_raid_unplug_work *raid_unplug_work; + + raid_unplug_work = container_of(work, struct syno_raid_unplug_work, work); + szDiskName = raid_unplug_work->szDiskName; + + /** + * Not disk name, it means this is not a disk device, may be SAS expander + * or other scsi devices so we don't need to kick any disk here from md + */ + if (NULL == szDiskName || 0 == szDiskName[0]) { + kfree(raid_unplug_work); + return; + } + + for_each_mddev(mddev, mdev_tmp) { + if (mddev_lock(mddev)) { + WARN_ON(1); + pr_warn("%s (%d): mddev_lock fail try again!\n", __func__, __LINE__); + continue; + } + + list_for_each_entry(rdev, &mddev->disks, same_set) { + /* make sure bdev is not release */ + if (!rdev || !rdev->mddev) + continue; + + if (!strcmp(rdev->bdev->bd_disk->disk_name, szDiskName)) + syno_raid_rdev_unplug(mddev, rdev->bdev->bd_dev); + } + mddev_unlock(mddev); + } + + kfree(raid_unplug_work); +} + +static void syno_rdev_unplug_task(struct work_struct *work) +{ + struct mddev *mddev; + dev_t dev; + struct syno_rdev_unplug_work *rdev_unplug_work; + + rdev_unplug_work = container_of(work, struct syno_rdev_unplug_work, work); + mddev = rdev_unplug_work->mddev; + dev = rdev_unplug_work->dev; + + if (syno_raid_unplug_single_rdev(mddev, dev)) { + // sleep for 1 sec before try again. + msleep(1000); + schedule_work(&rdev_unplug_work->work); + return; + } + + kfree(rdev_unplug_work); +} + +int syno_raid_disk_unplug(char *szArgDiskName) +{ + struct syno_raid_unplug_work *raid_unplug_work; + + raid_unplug_work = kmalloc(sizeof(*raid_unplug_work), GFP_ATOMIC); + if (raid_unplug_work) { + strlcpy(raid_unplug_work->szDiskName, szArgDiskName, BDEVNAME_SIZE); + + INIT_WORK(&raid_unplug_work->work, syno_raid_unplug_task); + schedule_work(&raid_unplug_work->work); + } + + return 0; +} + +void syno_raid_rdev_unplug(struct mddev *mddev, dev_t dev) +{ + struct syno_rdev_unplug_work *rdev_unplug_work; + + rdev_unplug_work = kmalloc(sizeof(*rdev_unplug_work), GFP_ATOMIC); + if (rdev_unplug_work) { + rdev_unplug_work->mddev = mddev; + rdev_unplug_work->dev = dev; + + INIT_WORK(&rdev_unplug_work->work, syno_rdev_unplug_task); + schedule_work(&rdev_unplug_work->work); + } +} +EXPORT_SYMBOL(syno_raid_rdev_unplug); + +void syno_update_sb_task(struct work_struct *work) +{ + struct syno_update_sb_work *update_sb; + + update_sb = container_of(work, struct syno_update_sb_work, work); + if (!update_sb->mddev) { + WARN_ON(!update_sb->mddev); + goto END; + } + + if (mddev_lock(update_sb->mddev)) { + pr_warn("%s (%d): mddev_lock fail try again!\n", __func__, __LINE__); + goto END; + } + + md_update_sb(update_sb->mddev, 1); + + mddev_unlock(update_sb->mddev); +END: + kfree(update_sb); +} +EXPORT_SYMBOL(syno_update_sb_task); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static void syno_md_fast_wakeup_end_request(struct bio *bio) +{ + struct md_rdev *rdev = bio->bi_private; + struct mddev *mddev = rdev->mddev; + + rdev_dec_pending(rdev, mddev); + bio_put(bio); +} + +static void syno_md_fast_wakeup_task(struct work_struct *work) +{ + struct syno_md_fast_wakeup_work *fast_wakeup_work; + struct md_rdev *rdev; + struct mddev *mddev; + + fast_wakeup_work = container_of(work, struct syno_md_fast_wakeup_work, work); + mddev = fast_wakeup_work->mddev; + + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) { + if (!rdev || !rdev->bdev) + continue; + if (rdev->raid_disk >= 0 && + !test_bit(Faulty, &rdev->flags)) { + struct bio *bio; + + atomic_inc(&rdev->nr_pending); + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + bio = bio_alloc_mddev(GFP_NOIO, 1, mddev); + bio_add_page(bio, mddev->syno_fast_wakeup_page, PAGE_SIZE, 0); + bio_set_dev(bio, rdev->bdev); + bio->bi_iter.bi_sector = rdev->sb_start; + bio->bi_private = rdev; + bio->bi_end_io = syno_md_fast_wakeup_end_request; + bio->bi_opf = REQ_OP_READ | REQ_SYNC; + submit_bio(bio); + rcu_read_lock(); + rdev_dec_pending(rdev, mddev); + } + } + rcu_read_unlock(); + + kfree(fast_wakeup_work); +} + +void syno_md_fast_wakeup_devices(void *md) +{ + struct mddev *mddev; + struct syno_md_fast_wakeup_work *fast_wakeup_work; + + if (!md) + return; + mddev = md; + + if (!mddev->syno_fast_wakeup_page) + return; + + fast_wakeup_work = kzalloc(sizeof(*fast_wakeup_work), GFP_ATOMIC); + if (!fast_wakeup_work) + return; + + fast_wakeup_work->mddev = mddev; + INIT_WORK(&fast_wakeup_work->work, syno_md_fast_wakeup_task); + schedule_work(&fast_wakeup_work->work); +} +EXPORT_SYMBOL(syno_md_fast_wakeup_devices); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +sector_t syno_md_speedup_rebuild(struct mddev *mddev, sector_t sector_nr) +{ + struct syno_hint *hint; + sector_t skipped_sectors = 0; + sector_t h_start = 0, h_end = 0, dev_start = 0, dev_end = 0; +#ifdef MY_ABC_HERE + sector_t last_start = mddev->syno_last_rebuild_start; +#endif /* MY_ABC_HERE */ + + if (!mddev->pers) { + WARN_ON(1); + return 0; + } + + if (!syno_is_rebuilding(mddev)) + return 0; + + if (!mddev->pers->align_chunk_addr_virt_to_dev) + return 0; + + if (!mutex_trylock(&mddev->syno_rh_mutex)) + return 0; + + hint = syno_hint_first(&mddev->syno_rh_tree); + while (hint) { + mddev->pers->align_chunk_addr_virt_to_dev(mddev, + hint->h_start, + 0, + &dev_start, + NULL); + if (sector_nr < dev_start) + break; + + h_start = hint->h_start; + /* Find the end of all continuous hints */ + do { + h_end = max(h_end, hint->h_end); + syno_hint_remove(&mddev->syno_rh_tree, hint); + syno_hint_free(hint); + hint = syno_hint_first(&mddev->syno_rh_tree); + } while (hint && hint->h_start <= h_end); + } + mutex_unlock(&mddev->syno_rh_mutex); + + mddev->pers->align_chunk_addr_virt_to_dev(mddev, + h_start, + h_end, + &dev_start, + &dev_end); + if (dev_start < dev_end && sector_nr < dev_end) { + skipped_sectors = dev_end - sector_nr; + mddev->syno_rh_skipped_sectors += skipped_sectors; +#ifdef MY_ABC_HERE + if (mddev->syno_enable_requested_resync_hints && + last_start < sector_nr) { + if (syno_hint_add(&mddev->syno_sh_tree, last_start, + sector_nr, + GFP_KERNEL)) + pr_err("%s: failed to add requested resync hint\n", + mdname(mddev)); + mddev->syno_last_rebuild_start = dev_end; + } +#endif /* MY_ABC_HERE */ + } + + return skipped_sectors; +} +EXPORT_SYMBOL(syno_md_speedup_rebuild); + +#ifdef MY_ABC_HERE +sector_t syno_md_speedup_requested_resync(struct mddev *mddev, + sector_t sector_nr) +{ + sector_t skipped_sectors = 0; + sector_t dev_end = 0; + struct syno_hint *hint; + + if (!mddev->pers) { + WARN_ON(1); + return 0; + } + + if (!syno_is_requested_resyncing(mddev)) + return 0; + + if (!mddev->syno_enable_requested_resync_hints) + return 0; + + if (mddev->resync_max_sectors != mddev->dev_sectors) + return 0; + + hint = syno_hint_first(&mddev->syno_sh_tree); + while (hint) { + if (sector_nr < hint->h_start) + break; + dev_end = hint->h_end; + syno_hint_remove(&mddev->syno_sh_tree, hint); + syno_hint_free(hint); + hint = syno_hint_first(&mddev->syno_sh_tree); + } + if (sector_nr < dev_end) + skipped_sectors = dev_end - sector_nr; + + return skipped_sectors; +} +EXPORT_SYMBOL(syno_md_speedup_requested_resync); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static void syno_md_heal_create_record_cache(struct mddev *mddev) +{ + struct kmem_cache *sc; + size_t namelen = sizeof(mddev->syno_md_heal_record_cache_name); + + snprintf(mddev->syno_md_heal_record_cache_name, namelen, + "%s-heal-cache", mdname(mddev)); + + sc = kmem_cache_create(mddev->syno_md_heal_record_cache_name, + sizeof(struct syno_md_heal_record), 0, 0, NULL); + if (!sc) + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to allocate heal record cache\n", + mdname(mddev)); + + atomic_set(&mddev->syno_md_heal_record_cnt, 0); + mddev->syno_md_heal_record_cnt_max = SYNO_MD_HEAL_RECORD_DEFAULT_CNT_MAX; + mddev->syno_md_heal_record_cache = sc; +} + +static void syno_md_heal_destroy_record_cache(struct mddev *mddev) +{ + kmem_cache_destroy(mddev->syno_md_heal_record_cache); + mddev->syno_md_heal_record_cache = NULL; + atomic_set(&mddev->syno_md_heal_record_cnt, 0); +} + +static void syno_md_heal_del_all_record(struct mddev *mddev) +{ + LIST_HEAD(free_list_head); + struct syno_md_heal_record *heal_record = NULL; + struct syno_md_heal_record *temp_record = NULL; + struct kmem_cache *sc = mddev->syno_md_heal_record_cache; + + write_lock_irq(&mddev->record_list_lock); + if (!list_empty(&mddev->syno_md_heal_record_list)) + list_replace_init(&mddev->syno_md_heal_record_list, &free_list_head); + write_unlock_irq(&mddev->record_list_lock); + + list_for_each_entry_safe(heal_record, temp_record, &free_list_head, record_list) { + WARN_ON(heal_record->bio); + list_del(&heal_record->record_list); + kmem_cache_free(sc, heal_record); + atomic_dec(&mddev->syno_md_heal_record_cnt); + } +} + +static bool syno_md_heal_is_bio_recorded(struct bio *bio, struct syno_md_heal_record *heal_record) +{ + if (heal_record->sector_start == bio->bi_iter.bi_sector) + return true; + return false; +} + +void syno_md_heal_put_record(struct mddev *mddev, struct syno_md_heal_record *heal_record) +{ + unsigned long flags; + + if (!heal_record) + return; + + spin_lock_irqsave(&heal_record->record_lock, flags); + heal_record->bio = NULL; + spin_unlock_irqrestore(&heal_record->record_lock, flags); +} +EXPORT_SYMBOL(syno_md_heal_put_record); + +static struct syno_md_heal_record* +syno_md_heal_init_record(struct mddev *mddev, struct bio *bio, int max_retry_cnt) +{ + int cnt_max = mddev->syno_md_heal_record_cnt_max; + struct kmem_cache *sc = mddev->syno_md_heal_record_cache; + struct syno_md_heal_record *heal_record; + + heal_record = kmem_cache_zalloc(sc, GFP_ATOMIC); + if (!heal_record) + return NULL; + + spin_lock_init(&heal_record->record_lock); + heal_record->mddev = mddev; + heal_record->retry_cnt = 1; + heal_record->max_retry_cnt = max_retry_cnt; + heal_record->is_hashed = false; + heal_record->request_cnt = 1; + heal_record->bio = bio; + heal_record->sector_start = bio->bi_iter.bi_sector; + + /* based on btrfs will not send the same sector inflight at the same time, + * we will not have TOCTOU race here. + */ + write_lock_irq(&mddev->record_list_lock); + if (cnt_max >= 0 && atomic_read(&mddev->syno_md_heal_record_cnt) >= cnt_max) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] reach max heal count [%d], abort sector [%llu]\n", + mdname(mddev), cnt_max, (u64)bio->bi_iter.bi_sector); + write_unlock_irq(&mddev->record_list_lock); + kmem_cache_free(sc, heal_record); + return NULL; + } + atomic_inc(&mddev->syno_md_heal_record_cnt); + list_add_tail(&heal_record->record_list, &mddev->syno_md_heal_record_list); + write_unlock_irq(&mddev->record_list_lock); + + return heal_record; +} + +struct syno_md_heal_record* +syno_md_heal_get_record(struct mddev *mddev, struct bio *bio, int max_retry_cnt) +{ + struct syno_md_heal_record *heal_record = NULL; + + read_lock_irq(&mddev->record_list_lock); + list_for_each_entry(heal_record, &mddev->syno_md_heal_record_list, record_list) { + if (syno_md_heal_is_bio_recorded(bio, heal_record)) { + read_unlock_irq(&mddev->record_list_lock); + + spin_lock_irq(&heal_record->record_lock); + if (heal_record->bio) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] sector [%llu] is already inflight\n", + mdname(mddev), (u64)bio->bi_iter.bi_sector); + heal_record = NULL; + } else { + heal_record->bio = bio; + ++(heal_record->request_cnt); + } + spin_unlock_irq(&heal_record->record_lock); + + return heal_record; + } + } + read_unlock_irq(&mddev->record_list_lock); + + return syno_md_heal_init_record(mddev, bio, max_retry_cnt); +} +EXPORT_SYMBOL(syno_md_heal_get_record); + +void syno_md_heal_find_and_del_record(struct mddev *mddev, struct bio *bio) +{ + struct kmem_cache *sc = mddev->syno_md_heal_record_cache; + struct syno_md_heal_record *heal_record = NULL; + struct syno_md_heal_record *temp_record = NULL; + unsigned long flags; + + write_lock_irqsave(&mddev->record_list_lock, flags); + list_for_each_entry_safe(heal_record, temp_record, + &mddev->syno_md_heal_record_list, record_list) { + if (syno_md_heal_is_bio_recorded(bio, heal_record)) { + WARN_ON(heal_record->bio); + list_del(&heal_record->record_list); + kmem_cache_free(sc, heal_record); + atomic_dec(&mddev->syno_md_heal_record_cnt); + break; + } + } + write_unlock_irqrestore(&mddev->record_list_lock, flags); +} +EXPORT_SYMBOL(syno_md_heal_find_and_del_record); + +struct syno_md_heal_record* +syno_md_heal_find_record(struct mddev *mddev, struct bio *bio) +{ + struct syno_md_heal_record *heal_record = NULL; + unsigned long flags; + + read_lock_irqsave(&mddev->record_list_lock, flags); + list_for_each_entry(heal_record, &mddev->syno_md_heal_record_list, record_list) { + if (syno_md_heal_is_bio_recorded(bio, heal_record)) { + read_unlock_irqrestore(&mddev->record_list_lock, flags); + return heal_record; + } + } + read_unlock_irqrestore(&mddev->record_list_lock, flags); + + return NULL; +} +EXPORT_SYMBOL(syno_md_heal_find_record); + +static void syno_md_heal_hash_bio_page(struct bio *bio, u8 *hash) +{ + SHASH_DESC_ON_STACK(shash, syno_md_heal_csum_hash); + struct bio_vec bvl; + struct bvec_iter iter; + char *kaddr; + + if (unlikely(!syno_md_heal_csum_hash)) + return; + + shash->tfm = syno_md_heal_csum_hash; + crypto_shash_init(shash); + + bio_for_each_segment(bvl, bio, iter) { + kaddr = kmap_atomic(bvl.bv_page); + crypto_shash_update(shash, kaddr, PAGE_SIZE); + kunmap_atomic(kaddr); + } + crypto_shash_final(shash, hash); +} + +int syno_md_heal_record_hash_value(struct syno_md_heal_record *heal_record, struct bio *bio) +{ + u8 hash[SYNO_MD_HEAL_HASH_SIZE] = {0}; + + syno_md_heal_hash_bio_page(bio, hash); + if (heal_record->is_hashed && + memcmp(hash, heal_record->u8_last_hash_arr, sizeof(hash)) == 0) { + ++(heal_record->retry_cnt); + return 1; + } + + memcpy(heal_record->u8_last_hash_arr, hash, sizeof(hash)); + heal_record->is_hashed = true; + + return 0; +} +EXPORT_SYMBOL(syno_md_heal_record_hash_value); + +int syno_md_heal_is_valid_md_stat(struct mddev *mddev) +{ + if (!(mddev->degraded == 0 && mddev->recovery_cp == MaxSector && + !test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))) + return 0; + return 1; +} +EXPORT_SYMBOL(syno_md_heal_is_valid_md_stat); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +bool syno_is_disk_error_set(struct mddev *mddev) +{ + bool ret = false; + struct md_rdev *rdev = NULL; + + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + if (rdev && test_bit(SynoDiskError, &rdev->flags)) { + ret = true; + break; + } + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(syno_is_disk_error_set); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int (*funcSYNOSendRaidSyncEvent)(const char *, int, int, int) = NULL; +EXPORT_SYMBOL(funcSYNOSendRaidSyncEvent); + +void syno_report_sync_status(const char *sync_type, int is_sync_finish, + int is_sync_interrupt, int md_minor) +{ + if (funcSYNOSendRaidSyncEvent) { + funcSYNOSendRaidSyncEvent(sync_type, is_sync_finish, is_sync_interrupt, md_minor); + } else { + pr_warn("md%d: failed to send sync event: (sync type: %s, finish: %d, interrupt: %d)\n", + md_minor, sync_type, is_sync_finish, is_sync_interrupt); + } +} +#endif /* MY_ABC_HERE */ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MD RAID framework"); diff --git a/drivers/md/md.h b/drivers/md/md.h index 2175a5ac4f7c..94ca0d856da9 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* md.h : kernel internal structure of the Linux MD driver @@ -19,6 +22,15 @@ #include #include #include "md-cluster.h" +#ifdef MY_ABC_HERE +#include "syno-md-fast-wakeup.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include "syno-md-hint.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #define MaxSector (~(sector_t)0) @@ -33,6 +45,51 @@ */ #define MD_FAILFAST (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT) +#ifdef MY_ABC_HERE +/* + * We now use crc32 to calculate data hash, it needs u32 buffer size. + * The data type of buffer is u8, so here we set size = 4. + */ +#define SYNO_MD_HEAL_HASH_SIZE 4 +#define SYNO_MD_HEAL_RECORD_DEFAULT_CNT_MAX 512 + +enum syno_md_data_correction_log_flags { + SYNO_MD_DATA_CORRECTION_LOG_OFF = 0, + SYNO_MD_DATA_CORRECTION_LOG_ALL = 1, + SYNO_MD_DATA_CORRECTION_LOG_ONLY_ERR = 2, + SYNO_MD_DATA_CORRECTION_LOG_IN_INFO = 3, +}; + +#ifdef MY_ABC_HERE +enum syno_md_resync_mode { + SYNO_RESYNC_MODE_NORMAL = 0, + SYNO_RESYNC_MODE_REPAIR = 1, + SYNO_RESYNC_MODE_REPLACE = 2, +}; +#endif /* MY_ABC_HERE */ + +#define syno_md_data_correction_print(flag, level, fmt, args...) \ +do { \ + switch (flag) { \ + case SYNO_MD_DATA_CORRECTION_LOG_ALL: \ + printk(level fmt, ##args); \ + break; \ + case SYNO_MD_DATA_CORRECTION_LOG_ONLY_ERR: \ + if (strcmp(level, KERN_ERR) != 0) \ + break; \ + printk(level fmt, ##args); \ + break; \ + case SYNO_MD_DATA_CORRECTION_LOG_IN_INFO: \ + pr_info(fmt, ##args); \ + break; \ + case SYNO_MD_DATA_CORRECTION_LOG_OFF: \ + break; \ + } \ +} while (0) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define SYNO_RAID_LEVEL_F1 45 +#endif /* MY_ABC_HERE */ /* * The struct embedded in rdev is used to serialize IO. */ @@ -139,6 +196,7 @@ struct md_rdev { sector_t sector; /* First sector of the PPL space */ } ppl; }; + enum flag_bits { Faulty, /* device is known to have a fault */ In_sync, /* device is in_sync with rest of array */ @@ -213,6 +271,14 @@ enum flag_bits { * check if there is collision between raid1 * serial bios. */ +#ifdef MY_ABC_HERE + SynoNonFullInsync, /* This device is rebuilding in fast rebuilding + * mode, so it's not fully in sync. + */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + SynoDiskError, /* device is know to have a fault in degraded state */ +#endif /* MY_ABC_HERE */ }; static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors, @@ -505,10 +571,87 @@ struct mddev { struct md_cluster_info *cluster_info; unsigned int good_device_nr; /* good device num within cluster raid */ unsigned int noio_flag; /* for memalloc scope API */ +#ifdef MY_ABC_HERE + struct page *syno_fast_wakeup_page; + struct syno_md_fast_wakeup_info syno_fast_wakeup_info; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define MD_NOT_CRASHED 0 +#define MD_CRASHED 1 +#define MD_CRASHED_ASSEMBLE 2 + unsigned char syno_nodev_and_crashed; // 1 ==> nodev && crashed. deny make_request +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define SYNO_MD_AUTO_REMAP_MODE_FORCE_OFF 0 +#define SYNO_MD_AUTO_REMAP_MODE_FORCE_ON 1 +#define SYNO_MD_AUTO_REMAP_MODE_ISMAXDEGRADE 2 + unsigned char syno_auto_remap; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned char syno_sync_debug; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned char syno_resync_mode; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_flush_plug_threshold; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_md_thread_fixed_node; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_sb_not_clean; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /** + * syno_rh_tree is used to record rebuild hints, + * hints in syno_rh_tree recorded the virtual address + * of array which could be skipped during rebuilding. + */ + struct syno_hint_tree syno_rh_tree; + /** + * syno_rh_mutex protects: + * syno_rh_tree, + * syno_allow_fast_rebuild - Avoid any hint being added + * after set it to false. + */ + struct mutex syno_rh_mutex; + sector_t syno_rh_skipped_sectors; +#ifdef MY_ABC_HERE + /** + * syno_sh_tree is used to record scrubbing hints, + * hints in syno_sh_tree record the dev sectors already + * rebuiled. + * + * syno_sh_tree is only used in sync_thread and md_stop, + * so we don't need any lock to protect it. + */ + struct syno_hint_tree syno_sh_tree; + sector_t syno_last_rebuild_start; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_md_data_correction_log_flag; + atomic_t syno_md_heal_record_cnt; + int syno_md_heal_record_cnt_max; + char syno_md_heal_record_cache_name[32]; + struct kmem_cache *syno_md_heal_record_cache; + struct list_head syno_md_heal_record_list; + rwlock_t record_list_lock; +#endif /* MY_ABC_HERE */ bool has_superblocks:1; bool fail_last_dev:1; bool serialize_policy:1; +#ifdef MY_ABC_HERE + bool syno_has_r0layout_feature:1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool syno_allow_fast_rebuild:1; +#ifdef MY_ABC_HERE + bool syno_enable_requested_resync_hints:1; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ }; enum recovery_flags { @@ -528,6 +671,9 @@ enum recovery_flags { MD_RECOVERY_ERROR, /* sync-action interrupted because io-error */ MD_RECOVERY_WAIT, /* waiting for pers->start() to finish */ MD_RESYNCING_REMOTE, /* remote node is running resync thread */ +#ifdef MY_ABC_HERE + MD_SYNO_RESHAPE_START, +#endif /* MY_ABC_HERE */ }; static inline int __must_check mddev_lock(struct mddev *mddev) @@ -575,6 +721,14 @@ struct md_personality int (*start)(struct mddev *mddev); void (*free)(struct mddev *mddev, void *priv); void (*status)(struct seq_file *seq, struct mddev *mddev); +#ifdef MY_ABC_HERE + /** + * for our special purpose, like raid1, there is not exist a + * easy way for distinguish between hotplug or read/write error + * on last one disk which is in sync + */ + void (*syno_error_handler)(struct mddev *mddev, struct md_rdev *rdev); +#endif /* MY_ABC_HERE */ /* error_handler must set ->faulty and clear ->in_sync * if appropriate, and should abort recovery if needed */ @@ -606,6 +760,36 @@ struct md_personality void *(*takeover) (struct mddev *mddev); /* Changes the consistency policy of an active array. */ int (*change_consistency_policy)(struct mddev *mddev, const char *buf); +#ifdef MY_ABC_HERE + void (*adjust_md_threads_node) (struct mddev *mddev); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* align_chunk_addr_virt_to_dev is used to transfer a range of + * virtual addresses of array to the range of addresses of devices. + * The addresses of devices need to be including in specified virtual + * addresses range, so we need to align the chunk sectors. + * + * e.g. 3drive raid5: + * + * dev_addr +---+---+---+ + * 0 | 0 | 1 | P | a. [0 ,4) in array -> [0, 2) in devices + * +---+---+---+ b. [1, 5) in array -> [1, 2) in devices + * 1 | 3 | P | 2 | c. [2, 3) in array -> [1, 1) in devices + * +---+---+---+ note that [1,1) is illegal interval. + * 2 | P | 4 | 5 | + * +---+---+---+ + * each chunk represent the range of [X, X+1) + */ + void (*align_chunk_addr_virt_to_dev)(struct mddev *mddev, + sector_t virt_start, + sector_t virt_end, + sector_t *dev_start, + sector_t *dev_end); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool (*syno_is_md_max_degrade)(struct mddev *mddev); + void (*syno_set_rdev_auto_remap)(struct mddev *mddev); +#endif /* MY_ABC_HERE */ }; struct md_sysfs_entry { @@ -691,6 +875,9 @@ static inline void safe_put_page(struct page *p) if (p) put_page(p); } +#ifdef MY_ABC_HERE +extern bool syno_is_device_disappear(struct block_device *bdev); +#endif /* MY_ABC_HERE */ extern int register_md_personality(struct md_personality *p); extern int unregister_md_personality(struct md_personality *p); extern int register_md_cluster_operations(struct md_cluster_operations *ops, @@ -814,5 +1001,63 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info); int do_md_run(struct mddev *mddev); extern const struct block_device_operations md_fops; +#ifdef MY_ABC_HERE +struct syno_update_sb_work { + struct work_struct work; + struct mddev *mddev; +}; +extern void syno_raid_rdev_unplug(struct mddev *mddev, dev_t dev); +extern void syno_update_sb_task(struct work_struct *work); +#ifdef CONFIG_SCSI +extern int (*syno_raid_scsi_unplug)(char *szDiskName); +#endif /* CONFIG_SCSI */ +#ifdef CONFIG_BLK_DEV_NVME +extern int (*syno_raid_nvme_unplug)(char *szDiskName); +#endif /* CONFIG_BLK_DEV_NVME */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +sector_t syno_md_speedup_rebuild(struct mddev *mddev, sector_t sector_nr); +#ifdef MY_ABC_HERE +sector_t syno_md_speedup_requested_resync(struct mddev *mddev, sector_t sector_nr); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +struct syno_md_heal_record { + struct list_head record_list; + struct bio *bio; + struct mddev *mddev; + u8 u8_last_hash_arr[SYNO_MD_HEAL_HASH_SIZE]; + int retry_cnt; + int max_retry_cnt; + int request_cnt; // the number of retry requests at this bio->bi_sector + bool is_hashed; // in case that hash value is equal to initial u8_last_hash_arr + sector_t sector_start; + spinlock_t record_lock; +}; + +int syno_md_heal_is_valid_md_stat(struct mddev *mddev); +int syno_md_heal_record_hash_value(struct syno_md_heal_record *heal_record, struct bio *bio); +void syno_md_heal_find_and_del_record(struct mddev *mddev, struct bio *bio); +void syno_md_heal_put_record(struct mddev *mddev, struct syno_md_heal_record *heal_record); +struct syno_md_heal_record *syno_md_heal_get_record( + struct mddev *mddev, struct bio *bio, int max_retry_cnt); +struct syno_md_heal_record *syno_md_heal_find_record(struct mddev *mddev, struct bio *bio); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern int (*funcSYNOSendRaidSyncEvent)(const char *sync_type, int is_sync_finish, + int is_sync_interrupt, int md_minor); +void syno_report_sync_status(const char *sync_type, int is_sync_finish, + int is_sync_interrupt, int md_minor); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +bool syno_is_disk_error_set(struct mddev *mddev); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +void syno_bdev_remap_mode_set(struct block_device *, unsigned char); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +void syno_auto_remap_report(struct mddev *mddev, sector_t sector, struct block_device *bdev); +#endif /* MY_ABC_HERE */ #endif /* _MD_MD_H */ diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 35843df15b5e..df5358aa7e6b 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* raid0.c : Multiple Devices driver for Linux @@ -217,7 +220,15 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) if (cnt != mddev->raid_disks) { pr_warn("md/raid0:%s: too few disks (%d of %d) - aborting!\n", mdname(mddev), cnt, mddev->raid_disks); +#ifdef MY_ABC_HERE + /* for raid0 status consistense to other raid type */ + mddev->degraded = mddev->raid_disks - cnt; + zone->nb_dev = mddev->raid_disks; + mddev->private = conf; + return -ENODEV; +#else /* MY_ABC_HERE */ goto abort; +#endif /* MY_ABC_HERE */ } zone->nb_dev = cnt; zone->zone_end = smallest->sectors * cnt; @@ -272,6 +283,12 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) mdname(mddev), (unsigned long long)smallest->sectors); } +#ifdef MY_ABC_HERE + if (conf->nr_strip_zones == 1) { + mddev->syno_has_r0layout_feature = false; + mddev->layout = -1; + } +#endif /* MY_ABC_HERE */ pr_debug("md/raid0:%s: done.\n", mdname(mddev)); *private_conf = conf; @@ -363,6 +380,9 @@ static int raid0_run(struct mddev *mddev) struct r0conf *conf; int ret; +#ifdef MY_ABC_HERE + mddev->degraded = 0; +#endif /* MY_ABC_HERE */ if (mddev->chunk_sectors == 0) { pr_warn("md/raid0:%s: chunk size must be set.\n", mdname(mddev)); return -EINVAL; @@ -373,6 +393,20 @@ static int raid0_run(struct mddev *mddev) /* if private is not null, we are here after takeover */ if (mddev->private == NULL) { ret = create_strip_zones(mddev, &conf); +#ifdef MY_ABC_HERE + if (ret < 0 && mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (ret == -ENODEV) { + /* The size must greater than zero, + * otherwise this partition would not present in /proc/partitions + */ + mddev->array_sectors = raid0_size(mddev, 0, 0); + /* pretend success for printing mdstatus otherwise it will not show raid0 status when it fail on boot */ + return 0; + } +#endif /* MY_ABC_HERE */ if (ret < 0) return ret; mddev->private = conf; @@ -426,6 +460,73 @@ static void raid0_free(struct mddev *mddev, void *priv) kfree(conf); } +#ifdef MY_ABC_HERE +/** + * This is end_io callback function. + * We can use this for bad sector report and device error + * handing. Prevent umount panic from file system + * + * @author \$Author: khchen $ + * @version \$Revision: 1.1 + * + * @param bio Should not be NULL. Passing from block layer + */ +static void syno_raid0_end_request(struct bio *bio) +{ + struct mddev *mddev = NULL; + struct md_rdev *rdev = NULL; + struct bio *orig_bio; + + orig_bio = bio->bi_private; + + rdev = (struct md_rdev *)orig_bio->bi_next; + mddev = rdev->mddev; + + orig_bio->bi_next = bio->bi_next; + orig_bio->bi_status = bio->bi_status; + + if (bio->bi_status) { + /* Let raid0 could keep read.(md_error would let it become read-only) */ + md_error(mddev, rdev); +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) { + sector_t mapped_sector, orig_sector, report_sector; + struct strip_zone *zone; + struct r0conf *conf = mddev->private; + struct md_rdev *tmp_dev = NULL; + + mapped_sector = orig_sector = orig_bio->bi_iter.bi_sector; + zone = find_zone(conf, &mapped_sector); + switch (conf->layout) { + case RAID0_ORIG_LAYOUT: + tmp_dev = map_sector(mddev, zone, orig_sector, &mapped_sector); + break; + case RAID0_ALT_MULTIZONE_LAYOUT: + tmp_dev = map_sector(mddev, zone, mapped_sector, &mapped_sector); + break; + default: + break; + } + + if (likely(tmp_dev)) + report_sector = mapped_sector + zone->dev_start + + tmp_dev->data_offset; + else + report_sector = bio->bi_iter.bi_sector; + + syno_report_bad_sector(report_sector, bio_data_dir(bio), + mddev->md_minor, rdev->bdev, __func__); + } +#endif /* MY_ABC_HERE */ + } + + atomic_dec(&rdev->nr_pending); + bio_put(bio); + /* Let mount could successful and bad sector could keep accessing */ + bio_endio(orig_bio); +} +#endif /* MY_ABC_HERE */ + static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) { struct r0conf *conf = mddev->private; @@ -447,6 +548,9 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) zone->zone_end - bio->bi_iter.bi_sector, GFP_NOIO, &mddev->bio_set); bio_chain(split, bio); +#ifdef MY_ABC_HERE + bio_set_flag(bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(bio); bio = split; end = zone->zone_end; @@ -526,11 +630,30 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) sector_t orig_sector; unsigned chunk_sects; unsigned sectors; +#ifdef MY_ABC_HERE + struct bio *cloned_bio, *orig_bio; +#endif /* MY_ABC_HERE */ if (unlikely(bio->bi_opf & REQ_PREFLUSH) && md_flush_request(mddev, bio)) return true; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /** + * if there has any device offline, we don't make any request to + * our raid0 md array + */ + if (mddev->degraded) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) { raid0_handle_discard(mddev, bio); return true; @@ -571,7 +694,28 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) return true; } +#ifdef MY_ABC_HERE + cloned_bio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); + if (cloned_bio) { + cloned_bio->bi_end_io = syno_raid0_end_request; + cloned_bio->bi_private = bio; + atomic_inc(&tmp_dev->nr_pending); + + orig_bio = bio; + orig_bio->bi_next = (void *)tmp_dev; + bio = cloned_bio; + } +#endif /* MY_ABC_HERE */ + if (unlikely(is_mddev_broken(tmp_dev, "raid0"))) { +#ifdef MY_ABC_HERE + if (cloned_bio) { + atomic_dec(&tmp_dev->nr_pending); + orig_bio->bi_next = bio->bi_next; + bio_put(bio); + bio = orig_bio; + } +#endif /* MY_ABC_HERE */ bio_io_error(bio); return true; } @@ -589,11 +733,152 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) return true; } +#ifdef MY_ABC_HERE +static void +syno_raid0_status(struct seq_file *seq, struct mddev *mddev) +{ + int i; + struct r0conf *conf = mddev->private; + + seq_printf(seq, " %dk chunks", mddev->chunk_sectors/2); + seq_printf(seq, " [%d/%d] [", mddev->raid_disks, mddev->raid_disks - mddev->degraded); + rcu_read_lock(); + for (i = 0; i < conf->strip_zone[0].nb_dev; i++) { + struct md_rdev *rdev = rcu_dereference(conf->devlist[i]); +#ifdef MY_ABC_HERE + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) + ? (test_bit(SynoDiskError, &rdev->flags) ? "E" : "U") + : "_"); +#else /* MY_ABC_HERE */ + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); +#endif /* MY_ABC_HERE */ + } + rcu_read_unlock(); + seq_printf(seq, "]"); +} +#else /* MY_ABC_HERE */ static void raid0_status(struct seq_file *seq, struct mddev *mddev) { seq_printf(seq, " %dk chunks", mddev->chunk_sectors / 2); return; } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int syno_raid0_remove_disk(struct mddev *mddev, struct md_rdev *rdev) +{ + int err = 0; + struct r0conf *conf = mddev->private; + int number; + + if (!rdev) + goto END; + + number = rdev->raid_disk; + + /* + * use the same synchronize method as RAID5 + * see raid5.c:raid5_remove_disk + */ + conf->devlist[number] = NULL; + synchronize_rcu(); + if (atomic_read(&rdev->nr_pending)) { + /* lost the race, try later */ + err = -EBUSY; + conf->devlist[number] = rdev; + goto END; + } + +END: + return err; +} + +/** + * This is our implement for raid handler. + * It mainly for handling device hotplug. + * We let it look like other raid type. + * Set it faulty could let SDK know it's status + * + * @author \$Author: khchen $ + * @version \$Revision: 1.1 * + * + * @param mddev Should not be NULL. passing from md.c + * @param rdev Should not be NULL. passing from md.c + */ +static void syno_raid0_error_for_hotplug(struct mddev *mddev, struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + + pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n", + mdname(mddev), bdevname(rdev->bdev, b)); + if (test_and_clear_bit(In_sync, &rdev->flags)) { + if (mddev->degraded < mddev->raid_disks) { + struct syno_update_sb_work *update_sb = NULL; + + mddev->degraded++; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ + set_bit(Faulty, &rdev->flags); +#ifdef MY_ABC_HERE + clear_bit(SynoDiskError, &rdev->flags); +#endif /* MY_ABC_HERE */ + set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags); + + update_sb = kzalloc(sizeof(*update_sb), GFP_ATOMIC); + if (!update_sb) { + WARN_ON(!update_sb); + goto END; + } + + INIT_WORK(&update_sb->work, syno_update_sb_task); + update_sb->mddev = mddev; + schedule_work(&update_sb->work); + } + } else { + set_bit(Faulty, &rdev->flags); + } +END: + return; +} + +/** + * This is our implement for raid handler. + * It mainly for mdadm set device faulty. We let it look like + * other raid type. Let it become read only (scemd would remount + * if it find SynoDiskError) + * + * @author \$Author: khchen $ + * @version \$Revision: 1.1 * + * + * @param mddev Should not be NULL. passing from md.c + * @param rdev Should not be NULL. passing from md.c + */ +static void syno_raid0_error_for_internal(struct mddev *mddev, struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + + pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n", + mdname(mddev), bdevname(rdev->bdev, b)); +#ifdef MY_ABC_HERE + if (!test_bit(SynoDiskError, &rdev->flags)) { + struct syno_update_sb_work *update_sb = NULL; + + set_bit(SynoDiskError, &rdev->flags); + update_sb = kzalloc(sizeof(*update_sb), GFP_ATOMIC); + if (update_sb == NULL) { + WARN_ON(!update_sb); + return; + } + + INIT_WORK(&update_sb->work, syno_update_sb_task); + update_sb->mddev = mddev; + schedule_work(&update_sb->work); + } +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ static void *raid0_takeover_raid45(struct mddev *mddev) { @@ -766,8 +1051,17 @@ static struct md_personality raid0_personality= .make_request = raid0_make_request, .run = raid0_run, .free = raid0_free, +#ifdef MY_ABC_HERE + .status = syno_raid0_status, +#else /* MY_ABC_HERE */ .status = raid0_status, +#endif /* MY_ABC_HERE */ .size = raid0_size, +#ifdef MY_ABC_HERE + .hot_remove_disk = syno_raid0_remove_disk, + .error_handler = syno_raid0_error_for_internal, + .syno_error_handler = syno_raid0_error_for_hotplug, +#endif /* MY_ABC_HERE */ .takeover = raid0_takeover, .quiesce = raid0_quiesce, }; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a6480568c7eb..d3e14f0eff58 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * raid1.c : Multiple Devices driver for Linux @@ -45,6 +48,23 @@ static void allow_barrier(struct r1conf *conf, sector_t sector_nr); static void lower_barrier(struct r1conf *conf, sector_t sector_nr); +#ifdef MY_ABC_HERE +static void syno_raid1_heal_read_request( + struct mddev *mddev, struct bio *bio, struct r1bio *r1_bio); +static void syno_raid1_heal_submit_bio( + struct r1conf *conf, struct r1bio *r1_bio, struct syno_md_heal_record *record_input); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline bool syno_raid1_is_max_degrade(struct mddev *mddev) +{ + struct r1conf *conf = mddev->private; + + if (mddev->degraded >= conf->raid_disks - 1) + return true; + return false; +} +#endif /* MY_ABC_HERE */ #define raid1_log(md, fmt, args...) \ do { if ((md)->queue) blk_add_trace_msg((md)->queue, "raid1 " fmt, ##args); } while (0) @@ -62,9 +82,17 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio, unsigned long flags; int ret = 0; sector_t lo = r1_bio->sector; +#ifdef MY_ABC_HERE + sector_t hi = lo + r1_bio->sectors - 1; +#else /* MY_ABC_HERE */ sector_t hi = lo + r1_bio->sectors; +#endif /* MY_ABC_HERE */ struct serial_in_rdev *serial = &rdev->serial[idx]; +#ifdef MY_ABC_HERE + if (hi < lo) + return ret; +#endif /* MY_ABC_HERE */ spin_lock_irqsave(&serial->serial_lock, flags); /* collision happened */ if (raid1_rb_iter_first(&serial->serial_rb, lo, hi)) @@ -102,6 +130,10 @@ static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi) int idx = sector_to_idx(lo); struct serial_in_rdev *serial = &rdev->serial[idx]; +#ifdef MY_ABC_HERE + if (hi < lo) + return; +#endif /* MY_ABC_HERE */ spin_lock_irqsave(&serial->serial_lock, flags); for (si = raid1_rb_iter_first(&serial->serial_rb, lo, hi); si; si = raid1_rb_iter_next(si, lo, hi)) { @@ -251,7 +283,14 @@ static void free_r1bio(struct r1bio *r1_bio) struct r1conf *conf = r1_bio->mddev->private; put_all_bios(conf, r1_bio); +#ifdef MY_ABC_HERE + if (likely(r1_bio->syno_generation == conf->syno_generation)) + mempool_free(r1_bio, conf->r1bio_pool); + else + kfree(r1_bio); +#else /* MY_ABC_HERE */ mempool_free(r1_bio, &conf->r1bio_pool); +#endif /* MY_ABC_HERE */ } static void put_buf(struct r1bio *r1_bio) @@ -368,6 +407,13 @@ static void raid1_end_read_request(struct bio *bio) */ update_head_pos(r1_bio->read_disk, r1_bio); +#ifdef MY_ABC_HERE + if (bio_flagged(bio, BIO_SYNO_AUTO_REMAP)) { + pr_warn("%s:%s(%d) BIO_SYNO_AUTO_REMAP detected\n", __FILE__, __func__, __LINE__); + syno_auto_remap_report(conf->mddev, r1_bio->sector, rdev->bdev); + } +#endif /* MY_ABC_HERE */ + if (uptodate) set_bit(R1BIO_Uptodate, &r1_bio->state); else if (test_bit(FailFast, &rdev->flags) && @@ -387,6 +433,26 @@ static void raid1_end_read_request(struct bio *bio) test_bit(In_sync, &rdev->flags))) uptodate = 1; spin_unlock_irqrestore(&conf->device_lock, flags); + +#ifdef MY_ABC_HERE + /* for that only one disk and got read error */ + if (uptodate) + md_error(r1_bio->mddev, rdev); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(r1_bio->sector + rdev->data_offset, + READ, conf->mddev->md_minor, rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* If we assign read target, we don't want to read data from other disks + * and we don't want to fail this disk, so we redefine "uptodate" here to + * mean "Not retry and not fail this disk". + */ + if (conf->syno_read_target >= 0) + uptodate = 1; +#endif /* MY_ABC_HERE */ } if (uptodate) { @@ -449,7 +515,11 @@ static void raid1_end_write_request(struct bio *bio) struct md_rdev *rdev = conf->mirrors[mirror].rdev; bool discard_error; sector_t lo = r1_bio->sector; +#ifdef MY_ABC_HERE + sector_t hi = r1_bio->sector + r1_bio->sectors - 1; +#else /* MY_ABC_HERE */ sector_t hi = r1_bio->sector + r1_bio->sectors; +#endif /* MY_ABC_HERE */ discard_error = bio->bi_status && bio_op(bio) == REQ_OP_DISCARD; @@ -457,6 +527,11 @@ static void raid1_end_write_request(struct bio *bio) * 'one mirror IO has finished' event handler: */ if (bio->bi_status && !discard_error) { +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(r1_bio->sector + rdev->data_offset, + WRITE, conf->mddev->md_minor, rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ set_bit(WriteErrorSeen, &rdev->flags); if (!test_and_set_bit(WantReplacement, &rdev->flags)) set_bit(MD_RECOVERY_NEEDED, & @@ -468,6 +543,10 @@ static void raid1_end_write_request(struct bio *bio) !test_bit(WriteMostly, &rdev->flags)) { md_error(r1_bio->mddev, rdev); } +#ifdef MY_ABC_HERE + if (rdev->badblocks.shift < 0) + md_error(conf->mddev, rdev); +#endif /* MY_ABC_HERE */ /* * When the device is faulty, it is not necessary to @@ -545,7 +624,12 @@ static void raid1_end_write_request(struct bio *bio) call_bio_endio(r1_bio); } } +#ifdef MY_ABC_HERE + } else if (rdev->mddev->serialize_policy && + test_bit(CollisionCheck, &rdev->flags)) +#else /* MY_ABC_HERE */ } else if (rdev->mddev->serialize_policy) +#endif /* MY_ABC_HERE */ remove_serial(rdev, lo, hi); if (r1_bio->bios[mirror] == NULL) rdev_dec_pending(rdev, conf->mddev); @@ -578,6 +662,46 @@ static sector_t align_to_barrier_unit_end(sector_t start_sector, return len; } +#ifdef MY_ABC_HERE +static int syno_read_assign_target(struct r1conf *conf, struct r1bio *r1_bio, int *max_sectors) +{ + const sector_t this_sector = r1_bio->sector; + int sectors = r1_bio->sectors; + int best_disk = -1; + struct md_rdev *rdev; + int read_target; + int block_sector_dummy; + sector_t first_block_dummy; + + rcu_read_lock(); + read_target = conf->syno_read_target; + + if (read_target >= 0 && read_target < conf->raid_disks * 2) { + rdev = rcu_dereference(conf->mirrors[read_target].rdev); + if (r1_bio->bios[read_target] == IO_BLOCKED + || rdev == NULL + || test_bit(Faulty, &rdev->flags)) + goto err; + if (!test_bit(In_sync, &rdev->flags) && + rdev->recovery_offset < this_sector + sectors) + goto err; + if (is_badblock(rdev, this_sector, sectors, + &first_block_dummy, &block_sector_dummy)) + goto err; + best_disk = read_target; + atomic_inc(&rdev->nr_pending); + + if (conf->mirrors[best_disk].next_seq_sect != this_sector) + conf->mirrors[best_disk].seq_start = this_sector; + + conf->mirrors[best_disk].next_seq_sect = this_sector + sectors; + } +err: + rcu_read_unlock(); + *max_sectors = sectors; + return best_disk; +} +#endif /* MY_ABC_HERE */ /* * This routine returns the disk from which the requested read should @@ -1167,6 +1291,10 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) spin_unlock_irq(&conf->device_lock); wake_up(&conf->wait_barrier); md_wakeup_thread(mddev->thread); +#ifdef MY_ABC_HERE + if (mddev->queue) + trace_block_unplug(mddev->queue, plug->pending_cnt, !from_schedule); +#endif /* MY_ABC_HERE */ kfree(plug); return; } @@ -1174,6 +1302,10 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) /* we aren't scheduling, so we can do the write-out directly. */ bio = bio_list_get(&plug->pending); flush_bio_list(conf, bio); +#ifdef MY_ABC_HERE + if (mddev->queue) + trace_block_unplug(mddev->queue, plug->pending_cnt, !from_schedule); +#endif /* MY_ABC_HERE */ kfree(plug); } @@ -1192,7 +1324,12 @@ alloc_r1bio(struct mddev *mddev, struct bio *bio) struct r1conf *conf = mddev->private; struct r1bio *r1_bio; +#ifdef MY_ABC_HERE + r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); + r1_bio->syno_generation = conf->syno_generation; +#else /* MY_ABC_HERE */ r1_bio = mempool_alloc(&conf->r1bio_pool, GFP_NOIO); +#endif /* MY_ABC_HERE */ /* Ensure no bio records IO_BLOCKED */ memset(r1_bio->bios, 0, conf->raid_disks * sizeof(r1_bio->bios[0])); init_r1bio(r1_bio, mddev, bio); @@ -1244,14 +1381,35 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, init_r1bio(r1_bio, mddev, bio); r1_bio->sectors = max_read_sectors; +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bio, BIO_CORRECTION_RETRY) && + syno_md_heal_is_valid_md_stat(mddev))) { + syno_raid1_heal_read_request(mddev, bio, r1_bio); + return; + } +#endif /* MY_ABC_HERE */ /* * make_request() can abort the operation when read-ahead is being * used and no empty request is available. */ +#ifdef MY_ABC_HERE + if (likely(conf->syno_read_target < 0)) + rdisk = read_balance(conf, r1_bio, &max_sectors); + else + rdisk = syno_read_assign_target(conf, r1_bio, &max_sectors); +#else /* MY_ABC_HERE */ rdisk = read_balance(conf, r1_bio, &max_sectors); +#endif /* MY_ABC_HERE */ if (rdisk < 0) { /* couldn't find anywhere to read from */ +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + /* Oringinal raid1 didn't think about this */ + pr_crit_ratelimited("md/raid1: no bdev: unrecoverable I/O read error for block %llu\n", + (unsigned long long)r1_bio->sector); + } else +#endif /* MY_ABC_HERE */ if (print_msg) { pr_crit_ratelimited("md/raid1:%s: %s: unrecoverable I/O read error for block %llu\n", mdname(mddev), @@ -1284,6 +1442,9 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, struct bio *split = bio_split(bio, max_sectors, gfp, &conf->bio_split); bio_chain(split, bio); +#ifdef MY_ABC_HERE + bio_set_flag(bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(bio); bio = split; r1_bio->master_bio = bio; @@ -1324,6 +1485,9 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; struct raid1_plug_cb *plug = NULL; +#ifdef MY_ABC_HERE + struct blk_plug *blk_plug = current->plug; +#endif /* MY_ABC_HERE */ int first_clone; int max_sectors; @@ -1455,6 +1619,9 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, struct bio *split = bio_split(bio, max_sectors, GFP_NOIO, &conf->bio_split); bio_chain(split, bio); +#ifdef MY_ABC_HERE + bio_set_flag(bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(bio); bio = split; r1_bio->master_bio = bio; @@ -1500,7 +1667,12 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, wait_for_serialization(rdev, r1_bio); if (test_bit(WriteMostly, &rdev->flags)) atomic_inc(&r1_bio->behind_remaining); +#ifdef MY_ABC_HERE + } else if (mddev->serialize_policy && + test_bit(CollisionCheck, &rdev->flags)) +#else /* MY_ABC_HERE */ } else if (mddev->serialize_policy) +#endif /* MY_ABC_HERE */ wait_for_serialization(rdev, r1_bio); r1_bio->bios[i] = mbio; @@ -1533,6 +1705,11 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, if (plug) { bio_list_add(&plug->pending, mbio); plug->pending_cnt++; +#ifdef MY_ABC_HERE + if (blk_plug && + plug->pending_cnt >= mddev->syno_flush_plug_threshold) + blk_flush_plug_list(blk_plug, false); +#endif /* MY_ABC_HERE */ } else { spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); @@ -1550,12 +1727,28 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, static bool raid1_make_request(struct mddev *mddev, struct bio *bio) { +#ifdef MY_ABC_HERE + struct r1conf *conf = mddev->private; +#endif /* MY_ABC_HERE */ sector_t sectors; if (unlikely(bio->bi_opf & REQ_PREFLUSH) && md_flush_request(mddev, bio)) return true; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (conf->raid_disks - mddev->degraded == 0) { + /* when there are no any disk, just pass it */ + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ /* * There is a limit to the maximum size, but * the read/write handler might find a lower limit @@ -1586,13 +1779,175 @@ static void raid1_status(struct seq_file *seq, struct mddev *mddev) rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); +#ifdef MY_ABC_HERE + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) + ? (test_bit(SynoDiskError, &rdev->flags) ? "E" : "U") + : "_"); +#else /* MY_ABC_HERE */ seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); +#endif /* MY_ABC_HERE */ } rcu_read_unlock(); seq_printf(seq, "]"); } +#ifdef MY_ABC_HERE +void syno_raid1_error_common(struct mddev *mddev, struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + struct r1conf *conf = mddev->private; + unsigned long flags; + + spin_lock_irqsave(&conf->device_lock, flags); + set_bit(Blocked, &rdev->flags); +#ifdef MY_ABC_HERE + if (test_and_clear_bit(In_sync, &rdev->flags)) { + mddev->degraded++; + if (mddev->degraded >= conf->raid_disks && + mddev->syno_nodev_and_crashed == MD_NOT_CRASHED) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#ifdef MY_ABC_HERE + clear_bit(SynoDiskError, &rdev->flags); +#endif /* MY_ABC_HERE */ + } +#else /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (test_and_clear_bit(In_sync, &rdev->flags)) { + mddev->degraded++; + clear_bit(SynoDiskError, &rdev->flags); + } +#else /* MY_ABC_HERE */ + if (test_and_clear_bit(In_sync, &rdev->flags)) + mddev->degraded++; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + set_bit(Faulty, &rdev->flags); + spin_unlock_irqrestore(&conf->device_lock, flags); + /* + * if recovery is running, make sure it aborts. + */ + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + set_mask_bits(&mddev->sb_flags, 0, + BIT(MD_SB_CHANGE_DEVS) | BIT(MD_SB_CHANGE_PENDING)); + pr_crit("md/raid1:%s: Disk failure on %s, disabling device.\n" + "md/raid1:%s: Operation continuing on %d devices.\n", + mdname(mddev), bdevname(rdev->bdev, b), + mdname(mddev), conf->raid_disks - mddev->degraded); +} + +/** + * This function is main for raid1 + * when the error_handler meet hotplug event. + * + * Internal raid1 error_handler must using + * syno_error_for_internal, because as there is only one disk + * active in raid1, we do not set it faulty, just let it become + * read only. + * + * External raid1 error_handler must using this function. + * because this type of error is hotplug event, we can't just + * let it be read-only, instead of this, we make it faulty + * + * If there left only one disk in raid1, and we want hotplug it. + * We need unplug all other disk which is building parity now. + * Otherwise the status will be error in sch disks("U" instead + * of "_" ) + * + * @param mddev passing from md.c + * @param rdev passing from md.c + */ +void syno_raid1_error_for_hotplug(struct mddev *mddev, struct md_rdev *rdev) +{ + char b1[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + struct r1conf *conf = mddev->private; + struct md_rdev *rdev_tmp; + + /* remove other disk which are buiding parity currently */ + if (test_bit(In_sync, &rdev->flags) && + (conf->raid_disks - mddev->degraded) == 1) { + list_for_each_entry(rdev_tmp, &mddev->disks, same_set) { + if (!test_bit(Faulty, &rdev_tmp->flags) && + !test_bit(In_sync, &rdev_tmp->flags) && + strcmp(bdevname(rdev_tmp->bdev, b1), bdevname(rdev->bdev, b2)) != 0) { + pr_warn("[%s] %d: %s is being to unplug, but %s is sync now, disable both\n", + __FILE__, __LINE__, + bdevname(rdev->bdev, b2), + bdevname(rdev_tmp->bdev, b1)); + syno_raid_rdev_unplug(mddev, rdev_tmp->bdev->bd_dev); + } + } + } + + syno_raid1_error_common(mddev, rdev); +} + +/** + * copy it from original error(...), and modify + * the case: when there is only one disk, + * and it encounter a read/write fail. + * + * @param mddev passing from md.c + * @param rdev passing from md.c + */ +static +void syno_raid1_error_for_internal(struct mddev *mddev, struct md_rdev *rdev) +{ + struct r1conf *conf = mddev->private; + unsigned char recovery_err = 0; + struct md_rdev *rdev_tmp; + char b1[BDEVNAME_SIZE]; + char b2[BDEVNAME_SIZE]; + unsigned long flags; + + /** + * Default raid1 not permit there has no device on it. So we + * must jump it, and let latet request done directly + **/ + spin_lock_irqsave(&conf->device_lock, flags); + if (test_bit(In_sync, &rdev->flags) && + (conf->raid_disks - mddev->degraded) == 1) { +#ifdef MY_ABC_HERE + /** + * set it to SynoDiskError, scemd would remount read only as soon as + * possible. File system would also remount read only when it + * encounter a write request. + */ + if (!test_and_set_bit(SynoDiskError, &rdev->flags)) + set_bit(MD_SB_CHANGE_DEVS, &mddev->flags); +#endif /* MY_ABC_HERE */ + /* + * find out the disk in sync now, set it to faulty + * let it fail to building parity + */ + list_for_each_entry(rdev_tmp, &mddev->disks, same_set) { + if (!test_bit(Faulty, &rdev_tmp->flags) && + !test_bit(In_sync, &rdev_tmp->flags)) { + pr_warn("[%s] %d: %s has read/write error, but there only has this device, so remove %s from raid\n", + __FILE__, __LINE__, + bdevname(rdev->bdev, b1), + bdevname(rdev_tmp->bdev, b2)); + syno_raid_rdev_unplug(mddev, rdev_tmp->bdev->bd_dev); + recovery_err = 1; + } + } + + if (recovery_err) + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + + conf->recovery_disabled = mddev->recovery_disabled; + spin_unlock_irqrestore(&conf->device_lock, flags); + /* + * Don't fail the drive, act as though we were just a + * normal single drive + */ + return; + } + + spin_unlock_irqrestore(&conf->device_lock, flags); + syno_raid1_error_common(mddev, rdev); +} +#else /* MY_ABC_HERE */ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev) { char b[BDEVNAME_SIZE]; @@ -1634,6 +1989,7 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev) mdname(mddev), bdevname(rdev->bdev, b), mdname(mddev), conf->raid_disks - mddev->degraded); } +#endif /* MY_ABC_HERE */ static void print_conf(struct r1conf *conf) { @@ -1679,6 +2035,11 @@ static int raid1_spare_active(struct mddev *mddev) int count = 0; unsigned long flags; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return 0; +#endif /* MY_ABC_HERE */ + /* * Find all failed disks within the RAID1 configuration * and mark them readable. @@ -1733,6 +2094,10 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) int first = 0; int last = conf->raid_disks - 1; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ if (mddev->recovery_disabled == conf->recovery_disabled) return -EBUSY; @@ -1861,9 +2226,20 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) static void end_sync_read(struct bio *bio) { struct r1bio *r1_bio = get_resync_r1bio(bio); +#ifdef MY_ABC_HERE + struct r1conf *conf = r1_bio->mddev->private; + int mirror = r1_bio->read_disk; +#endif /* MY_ABC_HERE */ update_head_pos(r1_bio->read_disk, r1_bio); +#ifdef MY_ABC_HERE + if (bio_flagged(bio, BIO_SYNO_AUTO_REMAP)) { + pr_warn("%s:%s(%d) BIO_SYNO_AUTO_REMAP detected\n", __FILE__, __func__, __LINE__); + syno_auto_remap_report(conf->mddev, r1_bio->sector, + conf->mirrors[mirror].rdev->bdev); + } +#endif /* MY_ABC_HERE */ /* * we have read a block, now it needs to be re-written, * or re-read if the read failed. @@ -1871,6 +2247,19 @@ static void end_sync_read(struct bio *bio) */ if (!bio->bi_status) set_bit(R1BIO_Uptodate, &r1_bio->state); +#ifdef MY_ABC_HERE + else { + /* + * No need prepare for end_sync_read retry, because it not going here + * Please refer sync_request_write + */ + if (!syno_is_device_disappear(conf->mirrors[mirror].rdev->bdev)) + syno_report_bad_sector(r1_bio->sector + + conf->mirrors[mirror].rdev->data_offset, + READ, conf->mddev->md_minor, + conf->mirrors[mirror].rdev->bdev, __func__); + } +#endif /* MY_ABC_HERE */ if (atomic_dec_and_test(&r1_bio->remaining)) reschedule_retry(r1_bio); @@ -1918,6 +2307,11 @@ static void end_sync_write(struct bio *bio) if (!uptodate) { abort_sync_write(mddev, r1_bio); +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(r1_bio->sector + rdev->data_offset, + WRITE, conf->mddev->md_minor, rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ set_bit(WriteErrorSeen, &rdev->flags); if (!test_and_set_bit(WantReplacement, &rdev->flags)) set_bit(MD_RECOVERY_NEEDED, & @@ -1954,6 +2348,45 @@ static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector, return 0; } +#ifdef MY_ABC_HERE +static void syno_raid1_resend_bio_to_disk_per_page(struct r1bio *r1_bio) +{ + struct mddev *mddev = r1_bio->mddev; + struct r1conf *conf = mddev->private; + int read_disk = r1_bio->read_disk; + int sectors = r1_bio->sectors; + sector_t sect = r1_bio->sector; + struct md_rdev *rdev = conf->mirrors[read_disk].rdev; + char b[BDEVNAME_SIZE]; + + if (r1_bio->bios[read_disk]->bi_end_io != end_sync_read || + !rdev || !test_bit(In_sync, &rdev->flags)) + return; + /* reach max-degraded, we count on only one disk. + * try to trigger auto remap of all UNC in this bio first, + * or we will fail in the following sync_page_io() if there are more than 2 UNC + */ + if (!(rdev->bdev) || + !(rdev->bdev->bd_part) || + rdev->bdev->bd_part->syno_auto_remap != SYNO_MD_AUTO_REMAP_MODE_FORCE_ON) + return; + + while (sectors) { + int s = sectors; + + if (s > (PAGE_SIZE >> 9)) + s = PAGE_SIZE >> 9; + + if (!sync_page_io(rdev, sect, s << 9, conf->tmppage, REQ_OP_READ, 0, false)) { + pr_err("%s: resend failed bio to [%s] at md sector [%llu]\n", + mdname(mddev), bdevname(rdev->bdev, b), (u64)sect); + } + sectors -= s; + sect += s; + } +} +#endif /* MY_ABC_HERE */ + static int fix_sync_read_error(struct r1bio *r1_bio) { /* Try some synchronous reads of other devices to get @@ -1988,6 +2421,9 @@ static int fix_sync_read_error(struct r1bio *r1_bio) bio->bi_end_io = end_sync_write; } +#ifdef MY_ABC_HERE + syno_raid1_resend_bio_to_disk_per_page(r1_bio); +#endif /* MY_ABC_HERE */ while(sectors) { int s = sectors; int d = r1_bio->read_disk; @@ -2030,8 +2466,29 @@ static int fix_sync_read_error(struct r1bio *r1_bio) rdev = conf->mirrors[d].rdev; if (!rdev || test_bit(Faulty, &rdev->flags)) continue; +#ifdef MY_ABC_HERE + if (!rdev_set_badblocks(rdev, sect, s, 0)) { +#ifdef MY_ABC_HERE + if (test_bit(In_sync, &rdev->flags) && + !test_bit(SynoDiskError, &rdev->flags)) { + pr_err("md/raid1:%s: mark disk error on %s due to unrecoverable sync read error\n", + mdname(mddev), bdevname(rdev->bdev, b)); + set_bit(SynoDiskError, &rdev->flags); + set_bit(MD_SB_CHANGE_DEVS, &mddev->flags); + } else +#endif /* MY_ABC_HERE */ + if (!test_bit(Faulty, &rdev->flags) && + !test_bit(In_sync, &rdev->flags)) { + pr_err("md/raid1:%s: remove %s from raid due to unrecoverable sync read error\n", + mdname(mddev), bdevname(rdev->bdev, b)); + syno_raid_rdev_unplug(mddev, rdev->bdev->bd_dev); + } + abort = 1; + } +#else /* MY_ABC_HERE */ if (!rdev_set_badblocks(rdev, sect, s, 0)) abort = 1; +#endif /* MY_ABC_HERE */ } if (abort) { conf->recovery_disabled = @@ -2160,7 +2617,16 @@ static void process_checks(struct r1bio *r1_bio) } else j = 0; if (j >= 0) +#ifdef MY_ABC_HERE + { + if (mddev->syno_sync_debug) + pr_err("%s: raid1 not sync in sector [%llu] size [%d]\n", + mdname(mddev), (u64)r1_bio->sector, r1_bio->sectors); atomic64_add(r1_bio->sectors, &mddev->resync_mismatches); + } +#else /* MY_ABC_HERE */ + atomic64_add(r1_bio->sectors, &mddev->resync_mismatches); +#endif /* MY_ABC_HERE */ if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && !status)) { /* No need to write to this device. */ @@ -2312,6 +2778,11 @@ static void fix_read_error(struct r1conf *conf, int read_disk, (unsigned long long)(sect + rdev->data_offset), bdevname(rdev->bdev, b)); +#ifdef MY_ABC_HERE + syno_report_correct_bad_sector(sect + rdev->data_offset, + mddev->md_minor, + rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ } rdev_dec_pending(rdev, mddev); } else @@ -2512,6 +2983,10 @@ static void raid1d(struct md_thread *thread) struct list_head *head = &conf->retry_list; struct blk_plug plug; int idx; +#ifdef MY_ABC_HERE + struct r1bio *r1_bio_temp; + struct list_head syno_heal_retry_list_head; +#endif /* MY_ABC_HERE */ md_check_recovery(mddev); @@ -2541,6 +3016,21 @@ static void raid1d(struct md_thread *thread) flush_pending_writes(conf); +#ifdef MY_ABC_HERE + spin_lock_irq(&conf->syno_heal_retry_list_lock); + if (list_empty(&conf->syno_heal_retry_list)) + INIT_LIST_HEAD(&syno_heal_retry_list_head); + else + list_replace_init(&conf->syno_heal_retry_list, &syno_heal_retry_list_head); + spin_unlock_irq(&conf->syno_heal_retry_list_lock); + + list_for_each_entry_safe(r1_bio, r1_bio_temp, + &syno_heal_retry_list_head, retry_list) { + list_del(&r1_bio->retry_list); + syno_raid1_heal_submit_bio(conf, r1_bio, NULL); + } +#endif /* MY_ABC_HERE */ + spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { spin_unlock_irqrestore(&conf->device_lock, flags); @@ -2630,13 +3120,42 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, int min_bad = 0; /* number of sectors that are bad in all devices */ int idx = sector_to_idx(sector_nr); int page_idx = 0; +#ifdef MY_ABC_HERE + sector_t skipped_sectors = 0; +#endif /* MY_ABC_HERE */ if (!mempool_initialized(&conf->r1buf_pool)) if (init_resync(conf)) return 0; +#ifdef MY_ABC_HERE + /** + * when last one disk has bad sector or r/w error. + * We just freeze any sync request. Because it is crashed now. + */ + if (mddev->degraded == mddev->raid_disks) { + *skipped = 1; + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + /* Stop infinity loop sync. */ + mddev->recovery_cp = MaxSector; + } +#ifdef MY_ABC_HERE + /** + * When Disk Error, we don't sync either. + */ + else if (syno_is_disk_error_set(mddev)) { + *skipped = 1; + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + } +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + max_sector = mddev->dev_sectors; +#ifdef MY_ABC_HERE + if (sector_nr >= max_sector || *skipped == 1) { +#else /* MY_ABC_HERE */ if (sector_nr >= max_sector) { +#endif /* MY_ABC_HERE */ /* If we aborted, we need to abort the * sync on the 'current' bitmap chunk (there will * only be one in raid1 resync. @@ -2674,6 +3193,13 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, *skipped = 1; return sync_blocks; } +#ifdef MY_ABC_HERE + skipped_sectors = syno_md_speedup_rebuild(mddev, sector_nr); + if (skipped_sectors) { + *skipped = 1; + return skipped_sectors; + } +#endif /* MY_ABC_HERE */ /* * If there is non-resync activity waiting for a turn, then let it @@ -2966,8 +3492,14 @@ static struct r1conf *setup_conf(struct mddev *mddev) if (!conf->poolinfo) goto abort; conf->poolinfo->raid_disks = mddev->raid_disks * 2; +#ifdef MY_ABC_HERE + conf->r1bio_pool = &conf->_r1bio_pool[0]; + err = mempool_init(conf->r1bio_pool, NR_RAID_BIOS, r1bio_pool_alloc, + rbio_pool_free, conf->poolinfo); +#else /* MY_ABC_HERE */ err = mempool_init(&conf->r1bio_pool, NR_RAID_BIOS, r1bio_pool_alloc, rbio_pool_free, conf->poolinfo); +#endif /* MY_ABC_HERE */ if (err) goto abort; @@ -3006,6 +3538,9 @@ static struct r1conf *setup_conf(struct mddev *mddev) bio_list_init(&conf->pending_bio_list); conf->pending_count = 0; conf->recovery_disabled = mddev->recovery_disabled - 1; +#ifdef MY_ABC_HERE + conf->syno_read_target = -1; +#endif /* MY_ABC_HERE */ err = -EIO; for (i = 0; i < conf->raid_disks * 2; i++) { @@ -3035,6 +3570,10 @@ static struct r1conf *setup_conf(struct mddev *mddev) conf->fullsync = 1; } } +#ifdef MY_ABC_HERE + spin_lock_init(&conf->syno_heal_retry_list_lock); + INIT_LIST_HEAD(&conf->syno_heal_retry_list); +#endif /* MY_ABC_HERE */ err = -ENOMEM; conf->thread = md_register_thread(raid1d, mddev, "raid1"); @@ -3045,7 +3584,11 @@ static struct r1conf *setup_conf(struct mddev *mddev) abort: if (conf) { +#ifdef MY_ABC_HERE + mempool_exit(&conf->_r1bio_pool[0]); +#else /* MY_ABC_HERE */ mempool_exit(&conf->r1bio_pool); +#endif /* MY_ABC_HERE */ kfree(conf->mirrors); safe_put_page(conf->tmppage); kfree(conf->poolinfo); @@ -3059,6 +3602,69 @@ static struct r1conf *setup_conf(struct mddev *mddev) return ERR_PTR(err); } +#ifdef MY_ABC_HERE +static ssize_t +raid1_show_syno_read_target(struct mddev *mddev, char *page) +{ + struct r1conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_read_target); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid1_store_syno_read_target(struct mddev *mddev, const char *page, size_t len) +{ + struct r1conf *conf; + int new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoint(page, 10, &new)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else { + if (new < conf->raid_disks * 2) + conf->syno_read_target = new; + else + err = -EINVAL; + } + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid1_syno_read_target = __ATTR(syno_read_target, 0644, + raid1_show_syno_read_target, raid1_store_syno_read_target); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static struct attribute *raid1_attrs[] = { +#ifdef MY_ABC_HERE + &raid1_syno_read_target.attr, +#endif /* MY_ABC_HERE */ + NULL, +}; + +static struct attribute_group raid1_attrs_group = { + .name = NULL, + .attrs = raid1_attrs, +}; +#endif /* MY_ABC_HERE */ + static void raid1_free(struct mddev *mddev, void *priv); static int raid1_run(struct mddev *mddev) { @@ -3117,6 +3723,9 @@ static int raid1_run(struct mddev *mddev) * RAID1 needs at least one disk in active */ if (conf->raid_disks - mddev->degraded < 1) { +#ifdef MY_ABC_HERE + md_unregister_thread(&conf->thread); +#endif /* MY_ABC_HERE */ ret = -EINVAL; goto abort; } @@ -3134,9 +3743,26 @@ static int raid1_run(struct mddev *mddev) /* * Ok, everything is just fine now */ +#ifdef MY_ABC_HERE + if (mddev->to_remove == &raid1_attrs_group) + mddev->to_remove = NULL; + else if (mddev->kobj.sd && + sysfs_create_group(&mddev->kobj, &raid1_attrs_group)) + pr_warn("raid1: failed to create sysfs attributes for %s\n", + mdname(mddev)); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_flush_plug_threshold = max_queued_requests; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_allow_fast_rebuild = true; +#endif /* MY_ABC_HERE */ mddev->thread = conf->thread; conf->thread = NULL; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ mddev->private = conf; +#endif /* MY_ABC_HERE */ set_bit(MD_FAILFAST_SUPPORTED, &mddev->flags); md_set_array_sectors(mddev, raid1_size(mddev, 0, 0)); @@ -3148,6 +3774,10 @@ static int raid1_run(struct mddev *mddev) else blk_queue_flag_clear(QUEUE_FLAG_DISCARD, mddev->queue); +#ifdef MY_ABC_HERE + blk_queue_flag_set(QUEUE_FLAG_UNUSED_HINT, + mddev->queue); +#endif /* MY_ABC_HERE */ } ret = md_integrity_register(mddev); @@ -3155,6 +3785,9 @@ static int raid1_run(struct mddev *mddev) md_unregister_thread(&mddev->thread); goto abort; } +#ifdef MY_ABC_HERE + mddev->private = conf; +#endif /* MY_ABC_HERE */ return 0; abort: @@ -3166,7 +3799,11 @@ static void raid1_free(struct mddev *mddev, void *priv) { struct r1conf *conf = priv; +#ifdef MY_ABC_HERE + mempool_exit(conf->r1bio_pool); +#else /* MY_ABC_HERE */ mempool_exit(&conf->r1bio_pool); +#endif /* MY_ABC_HERE */ kfree(conf->mirrors); safe_put_page(conf->tmppage); kfree(conf->poolinfo); @@ -3176,6 +3813,9 @@ static void raid1_free(struct mddev *mddev, void *priv) kfree(conf->barrier); bioset_exit(&conf->bio_split); kfree(conf); +#ifdef MY_ABC_HERE + mddev->to_remove = &raid1_attrs_group; +#endif /* MY_ABC_HERE */ } static int raid1_resize(struct mddev *mddev, sector_t sectors) @@ -3188,6 +3828,11 @@ static int raid1_resize(struct mddev *mddev, sector_t sectors) * worth it. */ sector_t newsize = raid1_size(mddev, sectors, 0); +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ + if (mddev->external_size && mddev->array_sectors > newsize) return -EINVAL; @@ -3220,7 +3865,11 @@ static int raid1_reshape(struct mddev *mddev) * At the same time, we "pack" the devices so that all the missing * devices have the higher raid_disk numbers. */ +#ifdef MY_ABC_HERE + mempool_t *newpool, *oldpool; +#else /* MY_ABC_HERE */ mempool_t newpool, oldpool; +#endif /* MY_ABC_HERE */ struct pool_info *newpoolinfo; struct raid1_info *newmirrors; struct r1conf *conf = mddev->private; @@ -3229,8 +3878,13 @@ static int raid1_reshape(struct mddev *mddev) int d, d2; int ret; +#ifdef MY_ABC_HERE + newpool = (conf->r1bio_pool == &conf->_r1bio_pool[0]) ? + &conf->_r1bio_pool[1] : &conf->_r1bio_pool[0]; +#else /* MY_ABC_HERE */ memset(&newpool, 0, sizeof(newpool)); memset(&oldpool, 0, sizeof(oldpool)); +#endif /* MY_ABC_HERE */ /* Cannot change chunk_size, layout, or level */ if (mddev->chunk_sectors != mddev->new_chunk_sectors || @@ -3242,6 +3896,11 @@ static int raid1_reshape(struct mddev *mddev) return -EINVAL; } +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ + if (!mddev_is_clustered(mddev)) md_allow_write(mddev); @@ -3262,8 +3921,14 @@ static int raid1_reshape(struct mddev *mddev) newpoolinfo->mddev = mddev; newpoolinfo->raid_disks = raid_disks * 2; +#ifdef MY_ABC_HERE + BUG_ON(mempool_initialized(newpool)); + ret = mempool_init(newpool, NR_RAID_BIOS, r1bio_pool_alloc, + rbio_pool_free, newpoolinfo); +#else /* MY_ABC_HERE */ ret = mempool_init(&newpool, NR_RAID_BIOS, r1bio_pool_alloc, rbio_pool_free, newpoolinfo); +#endif /* MY_ABC_HERE */ if (ret) { kfree(newpoolinfo); return ret; @@ -3273,7 +3938,11 @@ static int raid1_reshape(struct mddev *mddev) GFP_KERNEL); if (!newmirrors) { kfree(newpoolinfo); +#ifdef MY_ABC_HERE + mempool_exit(newpool); +#else /* MY_ABC_HERE */ mempool_exit(&newpool); +#endif /* MY_ABC_HERE */ return -ENOMEM; } @@ -3282,6 +3951,9 @@ static int raid1_reshape(struct mddev *mddev) /* ok, everything is stopped */ oldpool = conf->r1bio_pool; conf->r1bio_pool = newpool; +#ifdef MY_ABC_HERE + conf->syno_generation++; +#endif /* MY_ABC_HERE */ for (d = d2 = 0; d < conf->raid_disks; d++) { struct md_rdev *rdev = conf->mirrors[d].rdev; @@ -3313,7 +3985,11 @@ static int raid1_reshape(struct mddev *mddev) set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); +#ifdef MY_ABC_HERE + mempool_exit(oldpool); +#else /* MY_ABC_HERE */ mempool_exit(&oldpool); +#endif /* MY_ABC_HERE */ return 0; } @@ -3349,6 +4025,21 @@ static void *raid1_takeover(struct mddev *mddev) return ERR_PTR(-EINVAL); } +#ifdef MY_ABC_HERE +static void raid1_align_chunk_addr_virt_to_dev(struct mddev *mddev, + sector_t virt_start, sector_t virt_end, sector_t* dev_start, + sector_t* dev_end) +{ + if (!dev_start && !dev_end) + return; + + if (dev_start) + *dev_start = virt_start; + if (dev_end) + *dev_end = virt_end; +} +#endif /* MY_ABC_HERE */ + static struct md_personality raid1_personality = { .name = "raid1", @@ -3358,7 +4049,12 @@ static struct md_personality raid1_personality = .run = raid1_run, .free = raid1_free, .status = raid1_status, +#ifdef MY_ABC_HERE + .error_handler = syno_raid1_error_for_internal, + .syno_error_handler = syno_raid1_error_for_hotplug, +#else /* MY_ABC_HERE */ .error_handler = raid1_error, +#endif /* MY_ABC_HERE */ .hot_add_disk = raid1_add_disk, .hot_remove_disk= raid1_remove_disk, .spare_active = raid1_spare_active, @@ -3368,7 +4064,223 @@ static struct md_personality raid1_personality = .check_reshape = raid1_reshape, .quiesce = raid1_quiesce, .takeover = raid1_takeover, +#ifdef MY_ABC_HERE + .align_chunk_addr_virt_to_dev = raid1_align_chunk_addr_virt_to_dev, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_is_md_max_degrade = syno_raid1_is_max_degrade, +#endif /* MY_ABC_HERE */ + }; +#ifdef MY_ABC_HERE +static const char *syno_raid1_get_bdevname(struct md_rdev *rdev, char *buf) +{ + if (!rdev) + return "null"; + return bdevname(rdev->bdev, buf); +} + +static void syno_raid1_heal_return_master_bio( + struct r1bio *r1_bio, struct syno_md_heal_record *heal_record, bool success) +{ + struct mddev *mddev = r1_bio->mddev; + struct bio *master_bio = r1_bio->master_bio; + + syno_md_heal_put_record(mddev, heal_record); + + if (success) { + master_bio->bi_status = BLK_STS_OK; + set_bit(R1BIO_Uptodate, &r1_bio->state); + } else { + bio_set_flag(master_bio, BIO_CORRECTION_ERR); + syno_md_heal_find_and_del_record(mddev, master_bio); + clear_bit(R1BIO_Uptodate, &r1_bio->state); + } + raid_end_bio_io(r1_bio); +} + +static void syno_raid1_heal_end_request(struct bio *bio) +{ + int uptodate = !bio->bi_status; + struct r1bio *r1_bio = bio->bi_private; + struct bio *master_bio = r1_bio->master_bio; + struct mddev *mddev = r1_bio->mddev; + struct syno_md_heal_record *heal_record = NULL; + struct r1conf *conf = mddev->private; + int mirror = r1_bio->read_disk; + unsigned long flags; + struct md_rdev *rdev; + + bio_put(bio); + r1_bio->bios[mirror] = NULL; + update_head_pos(mirror, r1_bio); + + rdev = (void *)master_bio->bi_next; + master_bio->bi_next = NULL; + rdev_dec_pending(rdev, mddev); + + heal_record = syno_md_heal_find_record(mddev, master_bio); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to find record at sector [%llu]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector); + goto abort; + } + + if (!uptodate) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] read error: try next round\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt); + + ++(heal_record->retry_cnt); + + spin_lock_irqsave(&conf->syno_heal_retry_list_lock, flags); + list_add(&r1_bio->retry_list, &conf->syno_heal_retry_list); + spin_unlock_irqrestore(&conf->syno_heal_retry_list_lock, flags); + md_wakeup_thread(mddev->thread); + + return; + } + + if (syno_md_heal_record_hash_value(heal_record, master_bio) != 0) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] finished: get same result, retry next round\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt - 1, heal_record->max_retry_cnt); + spin_lock_irqsave(&conf->syno_heal_retry_list_lock, flags); + list_add(&r1_bio->retry_list, &conf->syno_heal_retry_list); + spin_unlock_irqrestore(&conf->syno_heal_retry_list_lock, flags); + md_wakeup_thread(mddev->thread); + } else { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] finished: return result to upper layer\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt); + syno_raid1_heal_return_master_bio(r1_bio, heal_record, true); + } + + return; +abort: + syno_raid1_heal_return_master_bio(r1_bio, heal_record, false); +} + +static void syno_raid1_heal_submit_bio( + struct r1conf *conf, struct r1bio *r1_bio, struct syno_md_heal_record *record_input) +{ + int disk = 0; + int max_retry_cnt = 0; + char d_buf[BDEVNAME_SIZE]; + struct mddev *mddev = conf->mddev; + struct bio *master_bio = r1_bio->master_bio; + struct bio *read_bio = NULL; + struct md_rdev *rdev = NULL; + struct syno_md_heal_record *heal_record = NULL; + /* + * gfp flag is referenced to raid1_read_request(), + * which says do not want to blocking raid1d + */ + gfp_t gfp = record_input ? GFP_NOIO : (GFP_NOIO | __GFP_HIGH); + + if (record_input) { + heal_record = record_input; + } else { + heal_record = syno_md_heal_find_record(mddev, master_bio); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to find record at sector [%llu]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector); + goto abort; + } + } + max_retry_cnt = heal_record->max_retry_cnt; + + read_bio = bio_clone_fast(master_bio, gfp, &mddev->bio_set); + if (!read_bio) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] error: failed to clone bio master bio\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, max_retry_cnt); + goto abort; + } + + rcu_read_lock(); + for (disk = heal_record->retry_cnt - 1; disk < max_retry_cnt; ++disk) { + rdev = rcu_dereference(conf->mirrors[disk].rdev); + if (r1_bio->bios[disk] == IO_BLOCKED || + rdev == NULL || + test_bit(Faulty, &rdev->flags) || + !test_bit(In_sync, &rdev->flags)) { + ++(heal_record->retry_cnt); + continue; + } + break; + } + + if (disk >= max_retry_cnt) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] error: cannot find a suitable device, request_cnt [%d]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, max_retry_cnt, heal_record->request_cnt); + rcu_read_unlock(); + goto abort; + } + + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] start: choose disk [%d:%s]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, max_retry_cnt, + disk, syno_raid1_get_bdevname(rdev, d_buf)); + + master_bio->bi_next = (void *)rdev; + r1_bio->read_disk = disk; + r1_bio->bios[disk] = read_bio; + bio_set_flag(read_bio, BIO_CORRECTION_RETRY); + bio_set_dev(read_bio, rdev->bdev); + read_bio->bi_iter.bi_sector = master_bio->bi_iter.bi_sector + rdev->data_offset; + read_bio->bi_end_io = syno_raid1_heal_end_request; + read_bio->bi_opf = REQ_OP_READ; + read_bio->bi_private = r1_bio; + + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + submit_bio_noacct(read_bio); + + return; +abort: + if (read_bio) + bio_put(read_bio); + syno_raid1_heal_return_master_bio(r1_bio, heal_record, false); +} + +static void syno_raid1_heal_read_request(struct mddev *mddev, struct bio *bio, struct r1bio *r1_bio) +{ + struct r1conf *conf = mddev->private; + struct syno_md_heal_record *heal_record; + + heal_record = syno_md_heal_get_record(mddev, bio, conf->raid_disks); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to get record at sector [%llu]\n", + mdname(mddev), (u64)bio->bi_iter.bi_sector); + goto abort; + } + syno_raid1_heal_submit_bio(conf, r1_bio, heal_record); + + return; +abort: + syno_raid1_heal_return_master_bio(r1_bio, heal_record, false); +} +#endif /* MY_ABC_HERE */ static int __init raid_init(void) { diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index b7eb09e8c025..532f4c545e90 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _RAID1_H #define _RAID1_H @@ -118,7 +121,14 @@ struct r1conf { * mempools - it changes when the array grows or shrinks */ struct pool_info *poolinfo; +#ifdef MY_ABC_HERE + short syno_generation; /* increments with every + * reshape */ + mempool_t *r1bio_pool; + mempool_t _r1bio_pool[2]; +#else /* MY_ABC_HERE */ mempool_t r1bio_pool; +#endif /* MY_ABC_HERE */ mempool_t r1buf_pool; struct bio_set bio_split; @@ -139,6 +149,13 @@ struct r1conf { sector_t cluster_sync_low; sector_t cluster_sync_high; +#ifdef MY_ABC_HERE + int syno_read_target; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + spinlock_t syno_heal_retry_list_lock; + struct list_head syno_heal_retry_list; +#endif /* MY_ABC_HERE */ }; /* @@ -156,6 +173,10 @@ struct r1bio { * in this BehindIO request */ sector_t sector; +#ifdef MY_ABC_HERE + short syno_generation; /* increments with every + * reshape */ +#endif /* MY_ABC_HERE */ int sectors; unsigned long state; struct mddev *mddev; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 9f9d8b67b5dd..29e71a113a1b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * raid10.c : Multiple Devices driver for Linux @@ -18,6 +21,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "md.h" #include "raid10.h" #include "raid0.h" @@ -73,12 +79,101 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio); static void end_reshape_write(struct bio *bio); static void end_reshape(struct r10conf *conf); +#ifdef MY_ABC_HERE +static sector_t choose_data_offset(struct r10bio *r10_bio, struct md_rdev *rdev); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static void syno_raid10_heal_read_request( + struct mddev *mddev, struct bio *bio, struct r10bio *r10_bio); +static void syno_raid10_heal_submit_bio( + struct r10conf *conf, struct r10bio *r10_bio, struct syno_md_heal_record *record_input); +#endif /* MY_ABC_HERE */ + #define raid10_log(md, fmt, args...) \ do { if ((md)->queue) blk_add_trace_msg((md)->queue, "raid10 " fmt, ##args); } while (0) #include "raid1-10.c" +#ifdef MY_ABC_HERE +/* modified from raid1.c */ +#define SYNO_RAID10_START(node) ((node)->start) +#define SYNO_RAID10_LAST(node) ((node)->last) +INTERVAL_TREE_DEFINE(struct serial_info, node, sector_t, _subtree_last, + SYNO_RAID10_START, SYNO_RAID10_LAST, static inline, syno_raid10_rb); + +static int syno_raid10_check_and_add_serial(struct md_rdev *rdev, + struct r10bio *r10_bio, + struct serial_info *si, int idx) +{ + unsigned long flags; + int ret = 0; + sector_t lo = r10_bio->sector; + sector_t hi = lo + r10_bio->sectors - 1; + struct serial_in_rdev *serial = &rdev->serial[idx]; + + if (hi < lo) + return ret; + + spin_lock_irqsave(&serial->serial_lock, flags); + /* collision happened */ + if (syno_raid10_rb_iter_first(&serial->serial_rb, lo, hi)) + ret = -EBUSY; + else { + si->start = lo; + si->last = hi; + syno_raid10_rb_insert(si, &serial->serial_rb); + } + spin_unlock_irqrestore(&serial->serial_lock, flags); + + return ret; +} + +static void syno_raid10_wait_for_serialization(struct md_rdev *rdev, + struct r10bio *r10_bio) +{ + struct mddev *mddev = rdev->mddev; + struct serial_info *si; + int idx = syno_raid10_sector_to_idx(r10_bio->sector); + struct serial_in_rdev *serial = &rdev->serial[idx]; + + if (WARN_ON(!mddev->serial_info_pool)) + return; + si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO); + wait_event(serial->serial_io_wait, + syno_raid10_check_and_add_serial(rdev, r10_bio, + si, idx) == 0); +} + +static void syno_raid10_remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi) +{ + struct serial_info *si; + unsigned long flags; + int found = 0; + struct mddev *mddev = rdev->mddev; + int idx = syno_raid10_sector_to_idx(lo); + struct serial_in_rdev *serial = &rdev->serial[idx]; + + if (hi < lo) + return; + + spin_lock_irqsave(&serial->serial_lock, flags); + for (si = syno_raid10_rb_iter_first(&serial->serial_rb, lo, hi); + si; si = syno_raid10_rb_iter_next(si, lo, hi)) { + if (si->start == lo && si->last == hi) { + syno_raid10_rb_remove(si, &serial->serial_rb); + mempool_free(si, mddev->serial_info_pool); + found = 1; + break; + } + } + if (!found) + WARN(1, "The write IO is not recorded for serialization\n"); + spin_unlock_irqrestore(&serial->serial_lock, flags); + wake_up(&serial->serial_io_wait); +} +#endif /* MY_ABC_HERE */ + /* * for resync bio, r10bio pointer can be retrieved from the per-bio * 'struct resync_pages'. @@ -361,6 +456,13 @@ static void raid10_end_read_request(struct bio *bio) */ update_head_pos(slot, r10_bio); +#ifdef MY_ABC_HERE + if (bio_flagged(bio, BIO_SYNO_AUTO_REMAP)) { + pr_warn("%s:%s(%d) BIO_SYNO_AUTO_REMAP detected\n", __FILE__, __func__, __LINE__); + syno_auto_remap_report(conf->mddev, r10_bio->sector, rdev->bdev); + } +#endif /* MY_ABC_HERE */ + if (uptodate) { /* * Set R10BIO_Uptodate in our master bio, so that @@ -381,6 +483,22 @@ static void raid10_end_read_request(struct bio *bio) if (!_enough(conf, test_bit(R10BIO_Previous, &r10_bio->state), rdev->raid_disk)) uptodate = 1; + +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(r10_bio->devs[slot].addr + + choose_data_offset(r10_bio, rdev), READ, conf->mddev->md_minor, + rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* + * If this rdev is the last drive. + * Then this raid10 is crashed because there is no any chance to retry. + */ + if (uptodate) + md_error(r10_bio->mddev, rdev); +#endif /* MY_ABC_HERE */ } if (uptodate) { raid_end_bio_io(r10_bio); @@ -434,6 +552,10 @@ static void raid10_end_write_request(struct bio *bio) struct md_rdev *rdev = NULL; struct bio *to_put = NULL; bool discard_error; +#ifdef MY_ABC_HERE + sector_t lo = r10_bio->sector; + sector_t hi = r10_bio->sector + r10_bio->sectors - 1; +#endif /* MY_ABC_HERE */ discard_error = bio->bi_status && bio_op(bio) == REQ_OP_DISCARD; @@ -456,6 +578,13 @@ static void raid10_end_write_request(struct bio *bio) */ md_error(rdev->mddev, rdev); else { +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(conf->mirrors[dev].rdev->bdev)) + syno_report_bad_sector(r10_bio->devs[slot].addr + + choose_data_offset(r10_bio, rdev), + WRITE, conf->mddev->md_minor, + rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ set_bit(WriteErrorSeen, &rdev->flags); if (!test_and_set_bit(WantReplacement, &rdev->flags)) set_bit(MD_RECOVERY_NEEDED, @@ -466,6 +595,10 @@ static void raid10_end_write_request(struct bio *bio) (bio->bi_opf & MD_FAILFAST)) { md_error(rdev->mddev, rdev); } +#ifdef MY_ABC_HERE + if (rdev->badblocks.shift < 0) + md_error(rdev->mddev, rdev); +#endif /* MY_ABC_HERE */ /* * When the device is faulty, it is not necessary to @@ -520,6 +653,15 @@ static void raid10_end_write_request(struct bio *bio) set_bit(R10BIO_MadeGood, &r10_bio->state); } } +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (rdev->mddev->serialize_policy && + test_bit(CollisionCheck, &rdev->flags)) +#else /* MY_ABC_HERE */ + if (rdev->mddev->serialize_policy) +#endif /* MY_ABC_HERE */ + syno_raid10_remove_serial(rdev, lo, hi); +#endif /* MY_ABC_HERE */ /* * @@ -1064,6 +1206,10 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) spin_unlock_irq(&conf->device_lock); wake_up(&conf->wait_barrier); md_wakeup_thread(mddev->thread); +#ifdef MY_ABC_HERE + if (mddev->queue) + trace_block_unplug(mddev->queue, plug->pending_cnt, !from_schedule); +#endif /* MY_ABC_HERE */ kfree(plug); return; } @@ -1088,6 +1234,10 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) submit_bio_noacct(bio); bio = next; } +#ifdef MY_ABC_HERE + if (mddev->queue) + trace_block_unplug(mddev->queue, plug->pending_cnt, !from_schedule); +#endif /* MY_ABC_HERE */ kfree(plug); } @@ -1157,8 +1307,21 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, } regular_request_wait(mddev, conf, bio, r10_bio->sectors); +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bio, BIO_CORRECTION_RETRY) && + syno_md_heal_is_valid_md_stat(mddev))) { + syno_raid10_heal_read_request(mddev, bio, r10_bio); + return; + } +#endif /* MY_ABC_HERE */ rdev = read_balance(conf, r10_bio, &max_sectors); if (!rdev) { +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + pr_crit_ratelimited("md/raid10: no bdev: unrecoverable I/O read error for block %llu\n", + (unsigned long long)r10_bio->sector); + } else +#endif /* MY_ABC_HERE */ if (err_rdev) { pr_crit_ratelimited("md/raid10:%s: %s: unrecoverable I/O read error for block %llu\n", mdname(mddev), b, @@ -1177,6 +1340,9 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, gfp, &conf->bio_split); bio_chain(split, bio); allow_barrier(conf); +#ifdef MY_ABC_HERE + bio_set_flag(bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(bio); wait_barrier(conf); bio = split; @@ -1234,6 +1400,15 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, rdev = conf->mirrors[devnum].rdev; mbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (mddev->serialize_policy && + test_bit(CollisionCheck, &rdev->flags)) +#else /* MY_ABC_HERE */ + if (mddev->serialize_policy) +#endif /* MY_ABC_HERE */ + syno_raid10_wait_for_serialization(rdev, r10_bio); +#endif /* MY_ABC_HERE */ if (replacement) r10_bio->devs[n_copy].repl_bio = mbio; else @@ -1267,6 +1442,11 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, if (plug) { bio_list_add(&plug->pending, mbio); plug->pending_cnt++; +#ifdef MY_ABC_HERE + if (current->plug && + plug->pending_cnt >= mddev->syno_flush_plug_threshold) + blk_flush_plug_list(current->plug, false); +#endif /* MY_ABC_HERE */ } else { spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); @@ -1462,6 +1642,9 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, GFP_NOIO, &conf->bio_split); bio_chain(split, bio); allow_barrier(conf); +#ifdef MY_ABC_HERE + bio_set_flag(bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(bio); wait_barrier(conf); bio = split; @@ -1513,6 +1696,18 @@ static bool raid10_make_request(struct mddev *mddev, struct bio *bio) && md_flush_request(mddev, bio)) return true; +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!enough(conf, -1)) { + bio_io_error(bio); + return true; + } +#endif /* MY_ABC_HERE */ if (!md_write_start(mddev, bio)) return false; @@ -1557,7 +1752,13 @@ static void raid10_status(struct seq_file *seq, struct mddev *mddev) rcu_read_lock(); for (i = 0; i < conf->geo.raid_disks; i++) { struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev); +#ifdef MY_ABC_HERE + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) + ? (test_bit(SynoDiskError, &conf->mirrors[i].rdev->flags) ? "E" : "U") + : "_"); +#else /* MY_ABC_HERE */ seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); +#endif /* MY_ABC_HERE */ } rcu_read_unlock(); seq_printf(seq, "]"); @@ -1614,7 +1815,226 @@ static int enough(struct r10conf *conf, int ignore) return _enough(conf, 0, ignore) && _enough(conf, 1, ignore); } +#ifdef MY_ABC_HERE +static inline void syno_set_rdev_auto_remap(struct mddev *mddev) +{ + struct r10conf *conf = mddev->private; + struct geom *geo = &conf->geo; + struct md_rdev *rdev; + char b[BDEVNAME_SIZE]; + int rdev_idx = 0; + if (geo->near_copies <= 1 || (geo->raid_disks % geo->near_copies)) { + pr_warn("md: %s: not a standard RAID 10, does not support auto remap mode", + mdname(mddev)); + return; + } + + /* reset all rdev to auto_remap = SYNO_MD_AUTO_REMAP_MODE_FORCE_OFF */ + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) + syno_bdev_remap_mode_set(rdev->bdev, SYNO_MD_AUTO_REMAP_MODE_FORCE_OFF); + + do { + int num_data_copies = conf->copies; + int survival_cnt = 0; + int last_survival_rdev = -1; + + /* check the group of rdevs that has same data chunck */ + while (num_data_copies--) { + rdev = rcu_dereference(conf->mirrors[rdev_idx].rdev); + if (rdev && !test_bit(Faulty, &rdev->flags) && + test_bit(In_sync, &rdev->flags)) { + survival_cnt++; + last_survival_rdev = rdev_idx; + } + rdev_idx = (rdev_idx + 1) % geo->raid_disks; + } + + /* need to set auto_remap = 1 of the last survival rdev in this group */ + if (survival_cnt == 1) { + rdev = rcu_dereference(conf->mirrors[last_survival_rdev].rdev); + syno_bdev_remap_mode_set(rdev->bdev, SYNO_MD_AUTO_REMAP_MODE_FORCE_ON); + } + } while (rdev_idx != 0); + + /* print rdev auto_remap mode info */ + rdev_for_each_rcu(rdev, mddev) { + if (rdev && rdev->bdev && rdev->bdev->bd_part) { + bdevname(rdev->bdev, b); + pr_warn("md: %s: set %s to auto_remap [%d]\n", mdname(mddev), b, + rdev->bdev->bd_part->syno_auto_remap); + } + } + rcu_read_unlock(); +} + +/* copy from _enough(), only change cnt <= 1*/ +static bool syno_raid10_is_max_degrade(struct mddev *mddev) +{ + int first = 0; + bool ret = false; + int disks, ncopies; + struct r10conf *conf = mddev->private; + + disks = conf->geo.raid_disks; + ncopies = conf->geo.near_copies; + + rcu_read_lock(); + do { + int n = conf->copies; + int cnt = 0; + int this = first; + while (n--) { + struct md_rdev *rdev = rcu_dereference(conf->mirrors[this].rdev); + + if (rdev && test_bit(In_sync, &rdev->flags)) + cnt++; + this = (this + 1) % disks; + } + if (cnt <= 1) { + ret = true; + goto out; + } + first = (first + ncopies) % disks; + } while (first != 0); +out: + rcu_read_unlock(); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void +syno_raid10_error_common(struct mddev *mddev, + struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + struct r10conf *conf = mddev->private; + unsigned long flags; + + spin_lock_irqsave(&conf->device_lock, flags); +#ifdef MY_ABC_HERE + if (test_and_clear_bit(In_sync, &rdev->flags)) { + mddev->degraded++; + if (!enough(conf, -1) && (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE)) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#ifdef MY_ABC_HERE + clear_bit(SynoDiskError, &rdev->flags); +#endif /* MY_ABC_HERE */ + } +#else /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (test_and_clear_bit(In_sync, &rdev->flags)) { + mddev->degraded++; + clear_bit(SynoDiskError, &rdev->flags); + } +#else /* MY_ABC_HERE */ + if (test_and_clear_bit(In_sync, &rdev->flags)) + mddev->degraded++; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + /* + * If recovery is running, make sure it aborts. + */ + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + set_bit(Blocked, &rdev->flags); + set_bit(Faulty, &rdev->flags); + set_mask_bits(&mddev->sb_flags, 0, + BIT(MD_SB_CHANGE_DEVS) | BIT(MD_SB_CHANGE_PENDING)); + spin_unlock_irqrestore(&conf->device_lock, flags); + pr_crit("md/raid10:%s: Disk failure on %s, disabling device.\n" + "md/raid10:%s: Operation continuing on %d devices.\n", + mdname(mddev), bdevname(rdev->bdev, b), + mdname(mddev), conf->geo.raid_disks - mddev->degraded); +} + +static void +syno_raid10_error_for_hotplug(struct mddev *mddev, + struct md_rdev *rdev) +{ + char b1[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + struct r10conf *conf = mddev->private; + struct md_rdev *rdev_tmp; + + /* remove other disk which are buiding parity currently, + * so the disk is released. And user space can do something on this member. + */ + if (test_bit(In_sync, &rdev->flags) && + enough(conf, -1) && + !enough(conf, rdev->raid_disk)) { + list_for_each_entry(rdev_tmp, &mddev->disks, same_set) { + if (!test_bit(Faulty, &rdev_tmp->flags) && + !test_bit(In_sync, &rdev_tmp->flags) && + strcmp(bdevname(rdev_tmp->bdev, b1), bdevname(rdev->bdev, b2)) != 0) { + pr_warn("[%s] %d: %s is being to unplug, but %s is sync now, disable both\n", + __FILE__, __LINE__, + bdevname(rdev->bdev, b2), + bdevname(rdev_tmp->bdev, b1)); + syno_raid_rdev_unplug(mddev, rdev_tmp->bdev->bd_dev); + } + } + } + + syno_raid10_error_common(mddev, rdev); +} + +/** + * copy it from original error(...), and modify + * the case: when there is only one disk, + * and it encounter a read/write fail. + * + * @param mddev passing from md.c + * @param rdev passing from md.c + */ +static +void syno_raid10_error_for_internal(struct mddev *mddev, + struct md_rdev *rdev) +{ + struct r10conf *conf = mddev->private; + struct md_rdev *rdev_tmp; + char b1[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + + if (test_bit(In_sync, &rdev->flags) && + enough(conf, -1) && + !enough(conf, rdev->raid_disk)) { +#ifdef MY_ABC_HERE + /** + * set it to SynoDiskError, scemd would remount read only as soon as + * possible. File system would also remount read only when it + * encounter a write request. + */ + if (!test_bit(SynoDiskError, &rdev->flags)) { + set_bit(SynoDiskError, &rdev->flags); + set_bit(MD_SB_CHANGE_DEVS, &mddev->flags); + } +#endif /* MY_ABC_HERE */ + /* remove other disk which are buiding parity currently, + * so the disk is released. And user space can do something on this member. + */ + list_for_each_entry(rdev_tmp, &mddev->disks, same_set) { + if (!test_bit(Faulty, &rdev_tmp->flags) && + !test_bit(In_sync, &rdev_tmp->flags) && + strcmp(bdevname(rdev_tmp->bdev, b1), bdevname(rdev->bdev, b2)) != 0) { + pr_warn("[%s] %d: %s is faulty, but %s is sync now, disable both\n", + __FILE__, __LINE__, + bdevname(rdev->bdev, b2), + bdevname(rdev_tmp->bdev, b1)); + syno_raid_rdev_unplug(mddev, rdev_tmp->bdev->bd_dev); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + } + } + + /* + * Don't fail the drive, act as though we were just a + * normal single drive + */ + return; + } + + syno_raid10_error_common(mddev, rdev); +} +#else /* MY_ABC_HERE */ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev) { char b[BDEVNAME_SIZE]; @@ -1652,6 +2072,7 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev) mdname(mddev), bdevname(rdev->bdev, b), mdname(mddev), conf->geo.raid_disks - mddev->degraded); } +#endif /* MY_ABC_HERE */ static void print_conf(struct r10conf *conf) { @@ -1695,6 +2116,11 @@ static int raid10_spare_active(struct mddev *mddev) int count = 0; unsigned long flags; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return 0; +#endif /* MY_ABC_HERE */ + /* * Find all non-in_sync disks within the RAID10 configuration * and mark them in_sync @@ -1743,6 +2169,14 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) int first = 0; int last = conf->geo.raid_disks - 1; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; + + if (!enough(conf, -1)) + return -EINVAL; +#endif /* MY_ABC_HERE */ + if (mddev->recovery_cp < MaxSector) /* only hot-add to in-sync arrays, as recovery is * very different from resync @@ -1864,18 +2298,48 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev) return err; } +#ifdef MY_ABC_HERE +static void __end_sync_read(struct r10bio *r10_bio, struct bio *bio, int d, int slot) +#else /* MY_ABC_HERE */ static void __end_sync_read(struct r10bio *r10_bio, struct bio *bio, int d) +#endif /* MY_ABC_HERE */ { struct r10conf *conf = r10_bio->mddev->private; +#ifdef MY_ABC_HERE + struct md_rdev *rdev = conf->mirrors[d].rdev; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (bio_flagged(bio, BIO_SYNO_AUTO_REMAP)) { + pr_warn("%s:%s(%d) BIO_SYNO_AUTO_REMAP detected\n", __FILE__, __func__, __LINE__); + syno_auto_remap_report(conf->mddev, r10_bio->sector, + conf->mirrors[d].rdev->bdev); + } +#endif /* MY_ABC_HERE */ if (!bio->bi_status) set_bit(R10BIO_Uptodate, &r10_bio->state); else +#ifdef MY_ABC_HERE + { + if (!syno_is_device_disappear(conf->mirrors[d].rdev->bdev)) { + sector_t report_sector = (slot >= 0 ? + r10_bio->devs[slot].addr + choose_data_offset(r10_bio, rdev) : + bio->bi_iter.bi_sector); + + syno_report_bad_sector(report_sector, READ, conf->mddev->md_minor, + conf->mirrors[d].rdev->bdev, __func__); + } + atomic_add(r10_bio->sectors, + &conf->mirrors[d].rdev->corrected_errors); + } +#else /* MY_ABC_HERE */ /* The write handler will notice the lack of * R10BIO_Uptodate and record any errors etc */ atomic_add(r10_bio->sectors, &conf->mirrors[d].rdev->corrected_errors); +#endif /* MY_ABC_HERE */ /* for reconstruct, we always reschedule after a read. * for resync, only after all reads @@ -1894,9 +2358,16 @@ static void end_sync_read(struct bio *bio) { struct r10bio *r10_bio = get_resync_r10bio(bio); struct r10conf *conf = r10_bio->mddev->private; +#ifdef MY_ABC_HERE + int slot = -1; + int d = find_bio_disk(conf, r10_bio, bio, &slot, NULL); + + __end_sync_read(r10_bio, bio, d, slot); +#else /* MY_ABC_HERE */ int d = find_bio_disk(conf, r10_bio, bio, NULL, NULL); __end_sync_read(r10_bio, bio, d); +#endif /* MY_ABC_HERE */ } static void end_reshape_read(struct bio *bio) @@ -1904,7 +2375,11 @@ static void end_reshape_read(struct bio *bio) /* reshape read bio isn't allocated from r10buf_pool */ struct r10bio *r10_bio = bio->bi_private; +#ifdef MY_ABC_HERE + __end_sync_read(r10_bio, bio, r10_bio->read_slot, -1); +#else /* MY_ABC_HERE */ __end_sync_read(r10_bio, bio, r10_bio->read_slot); +#endif /* MY_ABC_HERE */ } static void end_sync_request(struct r10bio *r10_bio) @@ -1956,6 +2431,13 @@ static void end_sync_write(struct bio *bio) if (repl) md_error(mddev, rdev); else { +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(r10_bio->devs[slot].addr + + choose_data_offset(r10_bio, rdev), + WRITE, conf->mddev->md_minor, + rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ set_bit(WriteErrorSeen, &rdev->flags); if (!test_and_set_bit(WantReplacement, &rdev->flags)) set_bit(MD_RECOVERY_NEEDED, @@ -2048,6 +2530,11 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) } if (j == vcnt) continue; +#ifdef MY_ABC_HERE + if (mddev->syno_sync_debug) + pr_err("%s: raid10 not sync in sector [%llu] size [%d]\n", + mdname(mddev), (u64)r10_bio->sector, r10_bio->sectors); +#endif /* MY_ABC_HERE */ atomic64_add(r10_bio->sectors, &mddev->resync_mismatches); if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) /* Don't fix anything. */ @@ -2112,6 +2599,48 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) } } +#ifdef MY_ABC_HERE +static void syno_raid10_resend_bio_to_disk_per_page(struct r10bio *r10_bio) +{ + struct mddev *mddev = r10_bio->mddev; + struct r10conf *conf = mddev->private; + int sectors = r10_bio->sectors; + int dr = r10_bio->devs[0].devnum; + struct md_rdev *rdev = conf->mirrors[dr].rdev; + sector_t sect = 0; + char b[BDEVNAME_SIZE]; + + if (!rdev || !test_bit(In_sync, &rdev->flags)) + return; + + /* reach max-degraded, we count on only one disk. + * try to trigger auto remap of all UNC in this bio first, + * or we will fail in the following sync_page_io() if there are more than 2 UNC + */ + if (!(rdev->bdev) || + !(rdev->bdev->bd_part) || + rdev->bdev->bd_part->syno_auto_remap != SYNO_MD_AUTO_REMAP_MODE_FORCE_ON) { + return; + } + + while (sectors) { + int s = sectors; + sector_t addr; + + if (s > (PAGE_SIZE >> 9)) + s = PAGE_SIZE >> 9; + + addr = r10_bio->devs[0].addr + sect; + if (!sync_page_io(rdev, addr, s << 9, conf->tmppage, REQ_OP_READ, 0, false)) { + pr_err("%s: resend failed bio to [%s] at dev sector [%llu]\n", + mdname(mddev), bdevname(rdev->bdev, b), (u64)addr); + } + sectors -= s; + sect += s; + } +} +#endif /* MY_ABC_HERE */ + /* * Now for the recovery code. * Recovery happens across physical sectors. @@ -2141,6 +2670,9 @@ static void fix_recovery_read_error(struct r10bio *r10_bio) int dw = r10_bio->devs[1].devnum; struct page **pages = get_resync_pages(bio)->pages; +#ifdef MY_ABC_HERE + syno_raid10_resend_bio_to_disk_per_page(r10_bio); +#endif /* MY_ABC_HERE */ while (sectors) { int s = sectors; struct md_rdev *rdev; @@ -2183,12 +2715,24 @@ static void fix_recovery_read_error(struct r10bio *r10_bio) if (rdev != conf->mirrors[dw].rdev) { /* need bad block on destination too */ struct md_rdev *rdev2 = conf->mirrors[dw].rdev; +#ifdef MY_ABC_HERE + char b1[BDEVNAME_SIZE]; + char b2[BDEVNAME_SIZE]; +#endif /* MY_ABC_HERE */ + addr = r10_bio->devs[1].addr + sect; ok = rdev_set_badblocks(rdev2, addr, s, 0); if (!ok) { /* just abort the recovery */ pr_notice("md/raid10:%s: recovery aborted due to read error\n", mdname(mddev)); +#ifdef MY_ABC_HERE + pr_warn("md/raid10:%s: Failed to sync from %s to %s\n", + mdname(mddev), + bdevname(rdev->bdev, b1), + bdevname(rdev2->bdev, b2)); + md_error(mddev, rdev); +#endif /* MY_ABC_HERE */ conf->mirrors[dw].recovery_disabled = mddev->recovery_disabled; @@ -2483,6 +3027,11 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 sect + choose_data_offset(r10_bio, rdev)), bdevname(rdev->bdev, b)); +#ifdef MY_ABC_HERE + syno_report_correct_bad_sector(r10_bio->devs[sl].addr + + sect + choose_data_offset(r10_bio, rdev), + mddev->md_minor, rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ atomic_add(s, &rdev->corrected_errors); } @@ -2700,6 +3249,10 @@ static void raid10d(struct md_thread *thread) struct r10conf *conf = mddev->private; struct list_head *head = &conf->retry_list; struct blk_plug plug; +#ifdef MY_ABC_HERE + struct r10bio *r10_bio_temp; + struct list_head syno_heal_retry_list_head; +#endif /* MY_ABC_HERE */ md_check_recovery(mddev); @@ -2733,6 +3286,21 @@ static void raid10d(struct md_thread *thread) flush_pending_writes(conf); +#ifdef MY_ABC_HERE + spin_lock_irq(&conf->syno_heal_retry_list_lock); + if (list_empty(&conf->syno_heal_retry_list)) + INIT_LIST_HEAD(&syno_heal_retry_list_head); + else + list_replace_init(&conf->syno_heal_retry_list, &syno_heal_retry_list_head); + spin_unlock_irq(&conf->syno_heal_retry_list_lock); + + list_for_each_entry_safe(r10_bio, r10_bio_temp, + &syno_heal_retry_list_head, retry_list) { + list_del(&r10_bio->retry_list); + syno_raid10_heal_submit_bio(conf, r10_bio, NULL); + } +#endif /* MY_ABC_HERE */ + spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { spin_unlock_irqrestore(&conf->device_lock, flags); @@ -2896,11 +3464,39 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, int chunks_skipped = 0; sector_t chunk_mask = conf->geo.chunk_mask; int page_idx = 0; +#ifdef MY_ABC_HERE + bool blStopSync = false; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + sector_t skipped_sectors = 0; +#endif /* MY_ABC_HERE */ if (!mempool_initialized(&conf->r10buf_pool)) if (init_resync(conf)) return 0; +#ifdef MY_ABC_HERE + if (!enough(conf, -1)) + blStopSync = true; +#ifdef MY_ABC_HERE + else if (syno_is_disk_error_set(mddev)) + blStopSync = true; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE + /** + * when last one disk has bad sector or r/w error. + * We just freeze any sync request. Because it is crashed now. + */ + if (blStopSync) { + *skipped = 1; + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + /* Stop infinity loop sync while creating. */ + mddev->recovery_cp = MaxSector; + } +#endif /* MY_ABC_HERE */ /* * Allow skipping a full rebuild for incremental assembly * of a clean array, like RAID1 does. @@ -2921,7 +3517,11 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) || test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) max_sector = mddev->resync_max_sectors; +#ifdef MY_ABC_HERE + if (sector_nr >= max_sector || *skipped == 1) { +#else /* MY_ABC_HERE */ if (sector_nr >= max_sector) { +#endif /* MY_ABC_HERE */ conf->cluster_sync_low = 0; conf->cluster_sync_high = 0; @@ -3024,6 +3624,13 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, int j; r10_bio = NULL; +#ifdef MY_ABC_HERE + skipped_sectors = syno_md_speedup_rebuild(mddev, sector_nr); + if (skipped_sectors) { + *skipped = 1; + return skipped_sectors; + } +#endif /* MY_ABC_HERE */ for (i = 0 ; i < conf->geo.raid_disks; i++) { int still_degraded; struct r10bio *rb2; @@ -3684,6 +4291,10 @@ static struct r10conf *setup_conf(struct mddev *mddev) spin_lock_init(&conf->resync_lock); init_waitqueue_head(&conf->wait_barrier); atomic_set(&conf->nr_pending, 0); +#ifdef MY_ABC_HERE + spin_lock_init(&conf->syno_heal_retry_list_lock); + INIT_LIST_HEAD(&conf->syno_heal_retry_list); +#endif /* MY_ABC_HERE */ err = -ENOMEM; conf->thread = md_register_thread(raid10d, mddev, "raid10"); @@ -3750,6 +4361,12 @@ static int raid10_run(struct mddev *mddev) } } +#ifdef MY_ABC_HERE + mddev->syno_flush_plug_threshold = max_queued_requests; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_allow_fast_rebuild = (conf->geo.far_copies == 1); +#endif /* MY_ABC_HERE */ mddev->thread = conf->thread; conf->thread = NULL; @@ -3808,12 +4425,24 @@ static int raid10_run(struct mddev *mddev) else blk_queue_flag_clear(QUEUE_FLAG_DISCARD, mddev->queue); +#ifdef MY_ABC_HERE + blk_queue_flag_set(QUEUE_FLAG_UNUSED_HINT, + mddev->queue); +#endif /* MY_ABC_HERE */ } /* need to check that every block has at least one working mirror */ if (!enough(conf, -1)) { +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ pr_err("md/raid10:%s: not enough operational mirrors.\n", mdname(mddev)); +#ifdef MY_ABC_HERE + // DS 2.2 #10254 +#else /* MY_ABC_HERE */ goto out_free_conf; +#endif /* MY_ABC_HERE */ } if (conf->reshape_progress != MaxSector) { @@ -4875,6 +5504,42 @@ static void raid10_finish_reshape(struct mddev *mddev) mddev->reshape_backwards = 0; } +#ifdef MY_ABC_HERE +static void raid10_align_chunk_addr_virt_to_dev(struct mddev *mddev, + sector_t virt_start, sector_t virt_end, sector_t* dev_start, + sector_t* dev_end) +{ + struct r10conf *conf = mddev->private; + sector_t chunk; + sector_t stripe; + int dev; + + if (!dev_start && !dev_end) + return; + + if (conf->geo.far_copies != 1) + return; + + if (dev_start) { + chunk = virt_start >> conf->geo.chunk_shift; + chunk *= conf->geo.near_copies; + stripe = chunk; + dev = sector_div(stripe, conf->geo.raid_disks); + if (dev || (virt_start & conf->geo.chunk_mask)) + stripe++; + *dev_start = stripe << conf->geo.chunk_shift; + } + + if (dev_end) { + chunk = virt_end >> conf->geo.chunk_shift; + chunk *= conf->geo.near_copies; + stripe = chunk; + sector_div(stripe, conf->geo.raid_disks); + *dev_end = stripe << conf->geo.chunk_shift; + } +} +#endif /* MY_ABC_HERE */ + static struct md_personality raid10_personality = { .name = "raid10", @@ -4884,7 +5549,12 @@ static struct md_personality raid10_personality = .run = raid10_run, .free = raid10_free, .status = raid10_status, +#ifdef MY_ABC_HERE + .error_handler = syno_raid10_error_for_internal, + .syno_error_handler = syno_raid10_error_for_hotplug, +#else /* MY_ABC_HERE */ .error_handler = raid10_error, +#endif /* MY_ABC_HERE */ .hot_add_disk = raid10_add_disk, .hot_remove_disk= raid10_remove_disk, .spare_active = raid10_spare_active, @@ -4897,7 +5567,233 @@ static struct md_personality raid10_personality = .start_reshape = raid10_start_reshape, .finish_reshape = raid10_finish_reshape, .update_reshape_pos = raid10_update_reshape_pos, +#ifdef MY_ABC_HERE + .align_chunk_addr_virt_to_dev = raid10_align_chunk_addr_virt_to_dev, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_rdev_auto_remap = syno_set_rdev_auto_remap, + .syno_is_md_max_degrade = syno_raid10_is_max_degrade, +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static const char *syno_raid10_get_bdevname(struct md_rdev *rdev, char *buf) +{ + if (!rdev) + return "null"; + return bdevname(rdev->bdev, buf); +} + +static void syno_raid10_heal_return_master_bio( + struct r10bio *r10_bio, struct syno_md_heal_record *heal_record, bool success) +{ + struct mddev *mddev = r10_bio->mddev; + struct bio *master_bio = r10_bio->master_bio; + + syno_md_heal_put_record(mddev, heal_record); + + if (success) { + master_bio->bi_status = BLK_STS_OK; + set_bit(R10BIO_Uptodate, &r10_bio->state); + } else { + bio_set_flag(master_bio, BIO_CORRECTION_ERR); + syno_md_heal_find_and_del_record(mddev, master_bio); + clear_bit(R10BIO_Uptodate, &r10_bio->state); + } + raid_end_bio_io(r10_bio); +} + +static void syno_raid10_heal_end_request(struct bio *bio) +{ + int uptodate = !bio->bi_status; + struct r10bio *r10_bio = bio->bi_private; + struct bio *master_bio = r10_bio->master_bio; + struct mddev *mddev = r10_bio->mddev; + struct r10conf *conf = mddev->private; + struct syno_md_heal_record *heal_record = NULL; + int slot = r10_bio->read_slot; + unsigned long flags; + struct md_rdev *rdev; + + bio_put(bio); + r10_bio->devs[slot].bio = NULL; + update_head_pos(slot, r10_bio); + + rdev = (void *)master_bio->bi_next; + master_bio->bi_next = NULL; + rdev_dec_pending(rdev, mddev); + + heal_record = syno_md_heal_find_record(mddev, master_bio); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to find record at sector [%llu]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector); + goto abort; + } + + if (!uptodate) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] read error: try next round\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt); + + ++(heal_record->retry_cnt); + + spin_lock_irqsave(&conf->syno_heal_retry_list_lock, flags); + list_add(&r10_bio->retry_list, &conf->syno_heal_retry_list); + spin_unlock_irqrestore(&conf->syno_heal_retry_list_lock, flags); + md_wakeup_thread(mddev->thread); + + return; + } + + if (syno_md_heal_record_hash_value(heal_record, master_bio) != 0) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] finished: get same result, retry next round\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt - 1, heal_record->max_retry_cnt); + spin_lock_irqsave(&conf->syno_heal_retry_list_lock, flags); + list_add(&r10_bio->retry_list, &conf->syno_heal_retry_list); + spin_unlock_irqrestore(&conf->syno_heal_retry_list_lock, flags); + md_wakeup_thread(mddev->thread); + } else { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] finished: return result to upper layer\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt); + syno_raid10_heal_return_master_bio(r10_bio, heal_record, true); + } + + return; +abort: + syno_raid10_heal_return_master_bio(r10_bio, heal_record, false); +} + +static void syno_raid10_heal_submit_bio( + struct r10conf *conf, struct r10bio *r10_bio, struct syno_md_heal_record *record_input) +{ + int disk = 0, slot = 0; + int max_retry_cnt = 0; + char d_buf[BDEVNAME_SIZE]; + struct mddev *mddev = conf->mddev; + struct bio *read_bio = NULL; + struct md_rdev *rdev = NULL; + struct bio *master_bio = r10_bio->master_bio; + struct syno_md_heal_record *heal_record = NULL; + /* + * gfp flag is referenced to raid10_read_request(), + * which says do not want to blocking raid10d + */ + gfp_t gfp = record_input ? GFP_NOIO : (GFP_NOIO | __GFP_HIGH); + + if (record_input) { + heal_record = record_input; + } else { + heal_record = syno_md_heal_find_record(mddev, master_bio); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to find record at sector [%llu]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector); + goto abort; + } + } + max_retry_cnt = heal_record->max_retry_cnt; + + read_bio = bio_clone_fast(master_bio, gfp, &mddev->bio_set); + if (!read_bio) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] error: failed to clone bio master bio\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt); + goto abort; + } + + raid10_find_phys(conf, r10_bio); + + rcu_read_lock(); + for (slot = heal_record->retry_cnt - 1; slot < max_retry_cnt; ++slot) { + if (r10_bio->devs[slot].bio == IO_BLOCKED) + continue; + + disk = r10_bio->devs[slot].devnum; + rdev = rcu_dereference(conf->mirrors[disk].rdev); + + if (rdev == NULL || + test_bit(Faulty, &rdev->flags) || + (!test_bit(In_sync, &rdev->flags) && + r10_bio->devs[slot].addr + r10_bio->sectors > rdev->recovery_offset)) { + ++(heal_record->retry_cnt); + continue; + } + break; + } + + if (slot >= max_retry_cnt) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] error: cannot find a suitable device, request_cnt [%d]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt, + heal_record->request_cnt); + rcu_read_unlock(); + goto abort; + } + + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] start: choose disk [%d:%s]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, heal_record->max_retry_cnt, + disk, syno_raid10_get_bdevname(rdev, d_buf)); + r10_bio->read_slot = slot; + + master_bio->bi_next = (void *)rdev; + r10_bio->devs[slot].bio = read_bio; + r10_bio->devs[slot].rdev = rdev; + bio_set_flag(read_bio, BIO_CORRECTION_RETRY); + bio_set_dev(read_bio, rdev->bdev); + read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + choose_data_offset(r10_bio, rdev); + read_bio->bi_end_io = syno_raid10_heal_end_request; + read_bio->bi_opf = REQ_OP_READ; + read_bio->bi_private = r10_bio; + + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + submit_bio_noacct(read_bio); + + return; +abort: + if (read_bio) + bio_put(read_bio); + syno_raid10_heal_return_master_bio(r10_bio, heal_record, false); +} + +static void syno_raid10_heal_read_request( + struct mddev *mddev, struct bio *bio, struct r10bio *r10_bio) +{ + struct r10conf *conf = mddev->private; + struct syno_md_heal_record *heal_record; + + heal_record = syno_md_heal_get_record(mddev, bio, conf->copies); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to get record at sector [%llu]\n", + mdname(mddev), (u64)bio->bi_iter.bi_sector); + goto abort; + } + syno_raid10_heal_submit_bio(conf, r10_bio, heal_record); + + return; +abort: + syno_raid10_heal_return_master_bio(r10_bio, heal_record, false); +} +#endif /* MY_ABC_HERE */ static int __init raid_init(void) { diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 79cd2b7d3128..8753ffce2bae 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _RAID10_H #define _RAID10_H @@ -108,6 +111,10 @@ struct r10conf { */ sector_t cluster_sync_low; sector_t cluster_sync_high; +#ifdef MY_ABC_HERE + spinlock_t syno_heal_retry_list_lock; + struct list_head syno_heal_retry_list; +#endif /* MY_ABC_HERE */ }; /* @@ -180,4 +187,19 @@ enum r10bio_state { /* failfast devices did receive failfast requests. */ R10BIO_FailFast, }; +#ifdef MY_ABC_HERE +/* modified from raid1.h */ +/* + * each barrier unit size is 64MB fow now + */ +#define SYNO_RAID10_BARRIER_UNIT_SECTOR_BITS 17 +#define SYNO_RAID10_BARRIER_UNIT_SECTOR_SIZE (1<<17) +#define SYNO_RAID10_BARRIER_BUCKETS_NR_BITS (PAGE_SHIFT - ilog2(sizeof(atomic_t))) +#define SYNO_RAID10_BARRIER_BUCKETS_NR (1<> SYNO_RAID10_BARRIER_UNIT_SECTOR_BITS, + SYNO_RAID10_BARRIER_BUCKETS_NR_BITS); +} +#endif /* MY_ABC_HERE */ #endif diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 39343479ac2a..09d127379172 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * raid5.c : Multiple Devices driver for Linux @@ -61,11 +64,43 @@ #define cpu_to_group(cpu) cpu_to_node(cpu) #define ANY_GROUP NUMA_NO_NODE +#ifdef MY_ABC_HERE +static bool devices_handle_discard_safely = true; +#else /* MY_ABC_HERE */ static bool devices_handle_discard_safely = false; +#endif /* MY_ABC_HERE */ module_param(devices_handle_discard_safely, bool, 0644); MODULE_PARM_DESC(devices_handle_discard_safely, "Set to Y if all devices in each array reliably return zeroes on reads from discarded regions"); static struct workqueue_struct *raid5_wq; +#ifdef MY_ABC_HERE +static void syno_raid5_heal_read_request(struct mddev *mddev, struct bio *bio); +static void syno_raid5_heal_handle_stripe(struct r5conf *conf); +static bool syno_raid5_heal_grow_stripes(struct r5conf *conf, int num); +static void syno_raid5_heal_shrink_stripes(struct r5conf *conf); +static void syno_raid5_heal_shrink_buffers(struct syno_heal_stripe_head *heal_sh); +static void syno_raid5_heal_free_stripe( + struct kmem_cache *sc, struct syno_heal_stripe_head *heal_sh); +static struct syno_heal_stripe_head *syno_raid5_heal_alloc_stripe( + struct kmem_cache *sc, gfp_t gfp, int disks, struct r5conf *conf); +static struct syno_heal_stripe_head *syno_raid5_heal_get_free_stripe( + struct r5conf *conf); +static void syno_raid5_heal_release_stripe(struct syno_heal_stripe_head *heal_sh); +static bool syno_raid5_heal_grow_one_stripe(struct r5conf *conf, gfp_t gfp); +static bool syno_raid5_heal_drop_one_stripe(struct r5conf *conf); + +static inline void syno_raid5_lock_device_heal_lock(struct r5conf *conf) +{ + spin_lock_irq(&conf->syno_heal_stripe_lock); + spin_lock(&conf->device_lock); +} + +static inline void syno_raid5_unlock_device_heal_lock(struct r5conf *conf) +{ + spin_unlock(&conf->device_lock); + spin_unlock_irq(&conf->syno_heal_stripe_lock); +} +#endif /* MY_ABC_HERE */ static inline struct hlist_head *stripe_hash(struct r5conf *conf, sector_t sect) { @@ -96,6 +131,9 @@ static inline void lock_all_device_hash_locks_irq(struct r5conf *conf) spin_lock_irq(conf->hash_locks); for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++) spin_lock_nest_lock(conf->hash_locks + i, conf->hash_locks); +#ifdef MY_ABC_HERE + spin_lock(&conf->syno_heal_stripe_lock); +#endif /* MY_ABC_HERE */ spin_lock(&conf->device_lock); } @@ -103,6 +141,9 @@ static inline void unlock_all_device_hash_locks_irq(struct r5conf *conf) { int i; spin_unlock(&conf->device_lock); +#ifdef MY_ABC_HERE + spin_unlock(&conf->syno_heal_stripe_lock); +#endif /* MY_ABC_HERE */ for (i = NR_STRIPE_HASH_LOCKS - 1; i; i--) spin_unlock(conf->hash_locks + i); spin_unlock_irq(conf->hash_locks); @@ -171,7 +212,21 @@ static void raid5_wakeup_stripe_thread(struct stripe_head *sh) int i, cpu = sh->cpu; if (!cpu_online(cpu)) { +#ifdef MY_ABC_HERE + int node = conf->mddev->syno_md_thread_fixed_node; + int selected_cpu = cpumask_any_and(cpumask_of_node(node), + cpu_online_mask); + + if (-1 != conf->syno_handle_stripes_cpu && + -1 != node && node_online(node) && + nr_cpu_ids > selected_cpu) { + cpu = selected_cpu; + conf->syno_handle_stripes_cpu = cpu; + } else + cpu = cpumask_any(cpu_online_mask); +#else /* MY_ABC_HERE */ cpu = cpumask_any(cpu_online_mask); +#endif /* MY_ABC_HERE */ sh->cpu = cpu; } @@ -209,6 +264,88 @@ static void raid5_wakeup_stripe_thread(struct stripe_head *sh) } } +#ifdef MY_ABC_HERE +static void syno_stat_init(struct stripe_head *sh) +{ + struct r5conf *conf = sh->raid_conf; + + sh->syno_stat_batched_len = 1; + sh->syno_stat_lat_handle_stripe = 0; + sh->syno_stat_lat_raid_run_ops = 0; + sh->syno_stat_lat_copy_data = 0; + sh->syno_stat_lat_enable = conf->syno_stat_lat_enable; + sh->syno_stat_is_rcw = true; + sh->syno_stat_is_full_write = false; +} + +static void syno_stat_lat_record_to_conf(struct r5conf *conf, + struct stripe_head *sh) +{ + u64 lat_xor = sh->syno_stat_lat_raid_run_ops - + sh->syno_stat_lat_copy_data; + + conf->syno_stat_lat_handle_stripe_max = + max(conf->syno_stat_lat_handle_stripe_max, + sh->syno_stat_lat_handle_stripe); + conf->syno_stat_lat_raid_run_ops_max = + max(conf->syno_stat_lat_raid_run_ops_max, + sh->syno_stat_lat_raid_run_ops); + conf->syno_stat_lat_copy_data_max = + max(conf->syno_stat_lat_copy_data_max, + sh->syno_stat_lat_copy_data); + conf->syno_stat_lat_xor_max = + max(conf->syno_stat_lat_xor_max, + lat_xor); + + conf->syno_stat_lat_handle_stripe += sh->syno_stat_lat_handle_stripe; + conf->syno_stat_lat_raid_run_ops += sh->syno_stat_lat_raid_run_ops; + conf->syno_stat_lat_copy_data += sh->syno_stat_lat_copy_data; + conf->syno_stat_lat_recorded_cnt++; +} + +static void syno_stat_wait_record_to_conf(struct r5conf *conf, + struct stripe_head *sh) +{ + int batched_len = sh->syno_stat_batched_len; + u64 syno_stat_wait_sh = jiffies - sh->syno_stat_wait_sh_start; + + conf->syno_stat_wait_sh_max = + max(conf->syno_stat_wait_sh_max, + syno_stat_wait_sh); + conf->syno_stat_wait_delay_max = + max(conf->syno_stat_wait_delay_max, + sh->syno_stat_wait_delay); + conf->syno_stat_wait_io_max = + max(conf->syno_stat_wait_io_max, + sh->syno_stat_wait_io); + + conf->syno_stat_wait_sh += syno_stat_wait_sh * batched_len; + conf->syno_stat_wait_delay += sh->syno_stat_wait_delay; + conf->syno_stat_wait_io += sh->syno_stat_wait_io * batched_len; +} + +static void syno_stat_record_to_conf(struct r5conf *conf, + struct stripe_head *sh) +{ + int batched_len = sh->syno_stat_batched_len; + + if (unlikely(sh->syno_stat_lat_enable)) + syno_stat_lat_record_to_conf(conf, sh); + + if (sh->syno_stat_is_rcw) + conf->syno_stat_rcw += batched_len; + if (sh->syno_stat_is_full_write) + conf->syno_stat_full_write += batched_len; + if (batched_len) + conf->syno_stat_head_stripe_cnt++; + conf->syno_stat_total_stripe++; + + syno_stat_wait_record_to_conf(conf, sh); + + syno_stat_init(sh); +} +#endif /* MY_ABC_HERE */ + static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh, struct list_head *temp_inactive_list) { @@ -240,13 +377,39 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh, if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state) && !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) +#ifdef MY_ABC_HERE + { + if (test_bit(STRIPE_SYNO_STABLE_STATE, &sh->state)) + list_add_tail(&sh->lru, &conf->syno_stable_list); + else +#ifdef MY_ABC_HERE + { + sh->syno_stat_wait_delay_start = jiffies; + list_add_tail(&sh->lru, &conf->delayed_list); + } +#else /* MY_ABC_HERE */ + list_add_tail(&sh->lru, &conf->delayed_list); +#endif /* MY_ABC_HERE */ + } +#else /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + sh->syno_stat_wait_delay_start = jiffies; list_add_tail(&sh->lru, &conf->delayed_list); + } +#else /* MY_ABC_HERE */ + list_add_tail(&sh->lru, &conf->delayed_list); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); else { clear_bit(STRIPE_DELAYED, &sh->state); clear_bit(STRIPE_BIT_DELAY, &sh->state); +#ifdef MY_ABC_HERE + clear_bit(STRIPE_SYNO_STABLE_STATE, &sh->state); +#endif /* MY_ABC_HERE */ if (conf->worker_cnt_per_group == 0) { if (stripe_is_lowprio(sh)) list_add_tail(&sh->lru, @@ -262,6 +425,9 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh, md_wakeup_thread(conf->mddev->thread); } else { BUG_ON(stripe_operations_active(sh)); +#ifdef MY_ABC_HERE + clear_bit(STRIPE_SYNO_STABLE_STATE, &sh->state); +#endif /* MY_ABC_HERE */ if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) if (atomic_dec_return(&conf->preread_active_stripes) < IO_THRESHOLD) @@ -290,6 +456,9 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh, */ list_add_tail(&sh->lru, &conf->r5c_partial_stripe_list); } +#ifdef MY_ABC_HERE + syno_stat_record_to_conf(conf, sh); +#endif /* MY_ABC_HERE */ } } } @@ -581,6 +750,12 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) sh->sector = sector; stripe_set_idx(sector, conf, previous, sh); sh->state = 0; +#ifdef MY_ABC_HERE + syno_stat_init(sh); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + sh->syno_full_stripe_merge_state = 0; +#endif /* MY_ABC_HERE */ for (i = sh->disks; i--; ) { struct r5dev *dev = &sh->dev[i]; @@ -601,6 +776,10 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) sh->overwrite_disks = 0; insert_hash(conf, sh); sh->cpu = smp_processor_id(); +#ifdef MY_ABC_HERE + if (-1 != conf->syno_handle_stripes_cpu) + sh->cpu = conf->syno_handle_stripes_cpu; +#endif /* MY_ABC_HERE */ set_bit(STRIPE_BATCH_READY, &sh->state); } @@ -706,6 +885,14 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector, struct stripe_head *sh; int hash = stripe_hash_locks_hash(conf, sector); int inc_empty_inactive_list_flag; +#ifdef MY_ABC_HERE + sector_t tmp_sector = sector; + int sectors_per_chunk = + previous ? conf->prev_chunk_sectors : conf->chunk_sectors; + int chunk_offset = sector_div(tmp_sector, sectors_per_chunk); + int reserved_stripe_cnt = + (sectors_per_chunk - chunk_offset) >> RAID5_STRIPE_SHIFT(conf); +#endif /* MY_ABC_HERE */ pr_debug("get_stripe, sector %llu\n", (unsigned long long)sector); @@ -718,7 +905,17 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector, sh = __find_stripe(conf, sector, conf->generation - previous); if (!sh) { if (!test_bit(R5_INACTIVE_BLOCKED, &conf->cache_state)) { +#ifdef MY_ABC_HERE + if ((conf->max_nr_stripes < 64) || + (conf->max_nr_stripes - atomic_read(&conf->active_stripes)) + >= reserved_stripe_cnt) + sh = get_free_stripe(conf, hash); +#else /* MY_ABC_HERE */ sh = get_free_stripe(conf, hash); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (unlikely(conf->syno_enable_stripe_grow)) +#endif /* MY_ABC_HERE */ if (!sh && !test_bit(R5_DID_ALLOC, &conf->cache_state)) set_bit(R5_ALLOC_MORE, @@ -729,6 +926,11 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector, r5c_check_stripe_cache_usage(conf); if (!sh) { +#ifdef MY_ABC_HERE + blk_add_trace_msg(conf->mddev->queue, + "syno raid5: start wait stripe: %llu", + (unsigned long long)sector); +#endif /* MY_ABC_HERE */ set_bit(R5_INACTIVE_BLOCKED, &conf->cache_state); r5l_wake_reclaim(conf->log, 0); @@ -737,14 +939,27 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector, !list_empty(conf->inactive_list + hash) && (atomic_read(&conf->active_stripes) < (conf->max_nr_stripes * 3 / 4) +#ifdef MY_ABC_HERE + || atomic_read(&conf->active_stripes) + < (conf->max_nr_stripes - + conf->syno_active_stripe_threshold) +#endif /* MY_ABC_HERE */ || !test_bit(R5_INACTIVE_BLOCKED, &conf->cache_state)), *(conf->hash_locks + hash)); clear_bit(R5_INACTIVE_BLOCKED, &conf->cache_state); +#ifdef MY_ABC_HERE + blk_add_trace_msg(conf->mddev->queue, + "syno raid5: finish wait stripe: %llu", + (unsigned long long)sector); +#endif /* MY_ABC_HERE */ } else { init_stripe(sh, sector, previous); atomic_inc(&sh->count); +#ifdef MY_ABC_HERE + sh->syno_stat_wait_sh_start = jiffies; +#endif /* MY_ABC_HERE */ } } else if (!atomic_inc_not_zero(&sh->count)) { spin_lock(&conf->device_lock); @@ -763,6 +978,10 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector, sh->group->stripes_cnt--; sh->group = NULL; } +#ifdef MY_ABC_HERE + if (!test_bit(STRIPE_HANDLE, &sh->state)) + sh->syno_stat_wait_sh_start = jiffies; +#endif /* MY_ABC_HERE */ } atomic_inc(&sh->count); spin_unlock(&conf->device_lock); @@ -807,6 +1026,10 @@ static bool stripe_can_batch(struct stripe_head *sh) if (raid5_has_log(conf) || raid5_has_ppl(conf)) return false; +#ifdef MY_ABC_HERE + if (test_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state)) + return false; +#endif /* MY_ABC_HERE */ return test_bit(STRIPE_BATCH_READY, &sh->state) && !test_bit(STRIPE_BITMAP_PENDING, &sh->state) && is_full_stripe_write(sh); @@ -894,12 +1117,20 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh * can still add the stripe to batch list */ list_add(&sh->batch_list, &head->batch_list); +#ifdef MY_ABC_HERE + sh->batch_head->syno_stat_batched_len++; + sh->syno_stat_batched_len = 0; +#endif /* MY_ABC_HERE */ spin_unlock(&head->batch_head->batch_lock); } else { head->batch_head = head; sh->batch_head = head->batch_head; spin_lock(&head->batch_lock); list_add_tail(&sh->batch_list, &head->batch_list); +#ifdef MY_ABC_HERE + sh->batch_head->syno_stat_batched_len++; + sh->syno_stat_batched_len = 0; +#endif /* MY_ABC_HERE */ spin_unlock(&head->batch_lock); } @@ -1048,6 +1279,205 @@ static void defer_issue_bios(struct r5conf *conf, sector_t sector, dispatch_bio_list(&tmp); } +#ifdef MY_ABC_HERE +static void syno_sort_deferred_bios(struct syno_r5defer *group, + struct bio_list *pending_bios) +{ + int ent_cnt = 0; + struct bio *bio; + struct r5pending_data *ent = NULL; + + while ((bio = bio_list_pop(pending_bios))) { + /** + * Same location or adjacent bio could add into one ent. + */ + if (!ent || (ent->sector != bio->bi_iter.bi_sector && + ent->sector != bio->bi_iter.bi_sector + - (bio->bi_iter.bi_size >> 9))) { + if (ent_cnt == SYNO_MAX_SORT_ENT_CNT) { + bio_list_add_head(pending_bios, bio); + break; + } + ent_cnt++; + + ent = list_first_entry(&group->free_list, + struct r5pending_data, sibling); + list_move_tail(&ent->sibling, &group->pending_list); + ent->sector = bio->bi_iter.bi_sector; + bio_list_init(&ent->bios); + ent->count = 0; + } + bio_list_add(&ent->bios, bio); + ent->count++; + } + + list_sort(NULL, &group->pending_list, cmp_stripe); +} + +static int syno_merge_sorted_deferred_bios(struct syno_r5defer *group, + struct bio_list *sorted_bios, + struct bio_list *pending_bios, + int target_cnt) +{ + int sorted_cnt = 0; + struct r5pending_data *ent = NULL; + + while (!list_empty(&group->pending_list)) { + ent = list_first_entry(&group->pending_list, + struct r5pending_data, sibling); + if (sorted_cnt < target_cnt) { + bio_list_merge(sorted_bios, &ent->bios); + sorted_cnt += ent->count; + } else { + bio_list_merge_head(pending_bios, &ent->bios); + } + list_move_tail(&ent->sibling, &group->free_list); + } + + return sorted_cnt; +} + +static int syno_group_sort_flush_deferred_bios(struct syno_r5defer *group, + struct bio_list *pending_bios, + int target_cnt) +{ + int flushed_cnt = 0; + struct bio_list sorted_bios; + + bio_list_init(&sorted_bios); + while (!bio_list_empty(pending_bios) && flushed_cnt < target_cnt) { + syno_sort_deferred_bios(group, pending_bios); + flushed_cnt += syno_merge_sorted_deferred_bios(group, + &sorted_bios, + pending_bios, + target_cnt + - flushed_cnt); + } + + dispatch_bio_list(&sorted_bios); + + return flushed_cnt; +} + +static int syno_group_handle_deferred_bios(struct syno_r5defer *group, + struct r5conf *conf) +{ + struct bio_list tmp; + int pending_cnt; + int flushed_cnt = 0; + int target_cnt = 0; + bool flush_all = false; + + bio_list_init(&tmp); + spin_lock(&group->pending_bios_lock); + flush_all = test_and_clear_bit(SYNO_DEFER_FLUSH_ALL, &group->state); + if (!flush_all && + group->pending_data_cnt < conf->syno_defer_flush_threshold) { + pending_cnt = group->pending_data_cnt; + spin_unlock(&group->pending_bios_lock); + goto out; + } + + target_cnt = flush_all ? + group->pending_data_cnt : + conf->syno_defer_flush_batch_size; + bio_list_merge(&tmp, &group->pending_bios); + bio_list_init(&group->pending_bios); + pending_cnt = group->pending_data_cnt; + group->pending_data_cnt = 0; + spin_unlock(&group->pending_bios_lock); + + /* we should be ok with the following function without taking lock */ + flushed_cnt = syno_group_sort_flush_deferred_bios(group, &tmp, + target_cnt); + + spin_lock(&group->pending_bios_lock); + if (!bio_list_empty(&tmp)) + bio_list_merge_head(&group->pending_bios, &tmp); + group->pending_data_cnt += (pending_cnt - flushed_cnt); + pending_cnt = group->pending_data_cnt; + spin_unlock(&group->pending_bios_lock); + +out: + return pending_cnt; +} + +//Without sorting +static int syno_group_flush_deferred_bios(struct syno_r5defer *group) +{ + struct bio_list tmp; + + bio_list_init(&tmp); + spin_lock(&group->pending_bios_lock); + bio_list_merge(&tmp, &group->pending_bios); + bio_list_init(&group->pending_bios); + group->pending_data_cnt = 0; + spin_unlock(&group->pending_bios_lock); + + dispatch_bio_list(&tmp); + + return group->pending_data_cnt; +} + +static void syno_flush_deferred_bios(struct md_thread *thread) +{ + struct blk_plug plug; + struct mddev *mddev = thread->mddev; + struct r5conf *conf = mddev->private; + struct syno_r5defer *group = thread->private; + int pending_cnt; + + /* avoid timeout wakeup, or defer_thread run before setting ready */ + if (!conf->syno_defer_mode || !group) + return; + + blk_start_plug(&plug); + do { + if (conf->syno_defer_skip_sort) + pending_cnt = syno_group_flush_deferred_bios(group); + else + pending_cnt = syno_group_handle_deferred_bios(group, conf); + cond_resched(); + } while (pending_cnt >= conf->syno_defer_flush_threshold); + blk_finish_plug(&plug); +} + +static void syno_defer_group_issue_bios(struct r5conf *conf, + struct syno_r5defer *group, struct bio_list *bios) +{ + struct bio *bio = NULL; + int pending_cnt; + + clear_bit(SYNO_DEFER_FLUSH_ALL, &group->state); + spin_lock(&group->pending_bios_lock); + while ((bio = bio_list_pop(bios)) != NULL) { + group->pending_data_cnt++; + bio_list_add(&group->pending_bios, bio); + } + pending_cnt = group->pending_data_cnt; + spin_unlock(&group->pending_bios_lock); + + if (conf->syno_defer_mode && + (pending_cnt >= conf->syno_defer_flush_threshold)) + md_wakeup_thread(group->defer_thread); +} + +static void syno_defer_issue_bios(struct r5conf *conf, + struct bio_list bios[SYNO_DEFER_GROUP_CNT_MAX]) +{ + int i; + int group_cnt = conf->syno_defer_group_cnt; + struct syno_r5defer *group; + + for (i = 0; i < group_cnt; ++i) { + if (!bio_list_empty(&bios[i])) { + group = &(conf->syno_defer_groups[i]); + syno_defer_group_issue_bios(conf, group, &bios[i]); + } + } +} +#endif /* MY_ABC_HERE */ + static void raid5_end_read_request(struct bio *bi); static void @@ -1060,9 +1490,18 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) struct stripe_head *head_sh = sh; struct bio_list pending_bios = BIO_EMPTY_LIST; bool should_defer; +#ifdef MY_ABC_HERE + struct bio_list syno_pending_bios[SYNO_DEFER_GROUP_CNT_MAX]; /* TODO: fix hard code here */ + int syno_defer_mode = conf->syno_defer_mode; +#endif /* MY_ABC_HERE */ might_sleep(); +#ifdef MY_ABC_HERE + for (i = 0; i < SYNO_DEFER_GROUP_CNT_MAX; ++i) + bio_list_init(&syno_pending_bios[i]); +#endif /* MY_ABC_HERE */ + if (log_stripe(sh, s) == 0) return; @@ -1073,6 +1512,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) int replace_only = 0; struct bio *bi, *rbi; struct md_rdev *rdev, *rrdev = NULL; +#ifdef MY_ABC_HERE + int group_id = i % conf->syno_defer_group_cnt; +#endif /* MY_ABC_HERE */ sh = head_sh; if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) { @@ -1225,7 +1667,18 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) trace_block_bio_remap(bi->bi_disk->queue, bi, disk_devt(conf->mddev->gendisk), sh->dev[i].sector); +#ifdef MY_ABC_HERE + if (!sh->syno_stat_wait_io_start) { + sh->syno_stat_wait_io_start = jiffies; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (syno_defer_mode) + bio_list_add(&syno_pending_bios[group_id], bi); + else if (should_defer && op_is_write(op)) +#else /* MY_ABC_HERE */ if (should_defer && op_is_write(op)) +#endif /* MY_ABC_HERE */ bio_list_add(&pending_bios, bi); else submit_bio_noacct(bi); @@ -1275,7 +1728,18 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) trace_block_bio_remap(rbi->bi_disk->queue, rbi, disk_devt(conf->mddev->gendisk), sh->dev[i].sector); +#ifdef MY_ABC_HERE + if (!sh->syno_stat_wait_io_start) { + sh->syno_stat_wait_io_start = jiffies; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (syno_defer_mode) + bio_list_add(&syno_pending_bios[group_id], rbi); + else if (should_defer && op_is_write(op)) +#else /* MY_ABC_HERE */ if (should_defer && op_is_write(op)) +#endif /* MY_ABC_HERE */ bio_list_add(&pending_bios, rbi); else submit_bio_noacct(rbi); @@ -1297,7 +1761,13 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) goto again; } +#ifdef MY_ABC_HERE + if (syno_defer_mode) + syno_defer_issue_bios(conf, syno_pending_bios); + else if (should_defer && !bio_list_empty(&pending_bios)) +#else /* MY_ABC_HERE */ if (should_defer && !bio_list_empty(&pending_bios)) +#endif /* MY_ABC_HERE */ defer_issue_bios(conf, head_sh->sector, &pending_bios); } @@ -1313,7 +1783,14 @@ async_copy_data(int frombio, struct bio *bio, struct page **page, struct async_submit_ctl submit; enum async_tx_flags flags = 0; struct r5conf *conf = sh->raid_conf; +#ifdef MY_ABC_HERE + u64 syno_stat_start_time; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (unlikely(sh->syno_stat_lat_enable)) + syno_stat_start_time = local_clock(); +#endif /* MY_ABC_HERE */ if (bio->bi_iter.bi_sector >= sector) page_offset = (signed)(bio->bi_iter.bi_sector - sector) * 512; else @@ -1363,6 +1840,12 @@ async_copy_data(int frombio, struct bio *bio, struct page **page, page_offset += len; } +#ifdef MY_ABC_HERE + if (unlikely(sh->syno_stat_lat_enable)) { + sh->syno_stat_lat_copy_data += local_clock() - + syno_stat_start_time; + } +#endif /* MY_ABC_HERE */ return tx; } @@ -1910,6 +2393,13 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) } if (head_sh->batch_head) { +#ifdef MY_ABC_HERE + /* Record all handle stripe latency in head stripe. */ + if (sh != head_sh) { + head_sh->syno_stat_lat_copy_data += sh->syno_stat_lat_copy_data; + sh->syno_stat_lat_copy_data = 0; + } +#endif /* MY_ABC_HERE */ sh = list_first_entry(&sh->batch_list, struct stripe_head, batch_list); @@ -2215,8 +2705,15 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) int level = conf->level; struct raid5_percpu *percpu; unsigned long cpu; +#ifdef MY_ABC_HERE + u64 syno_stat_start_time; +#endif /* MY_ABC_HERE */ cpu = get_cpu(); +#ifdef MY_ABC_HERE + if (unlikely(sh->syno_stat_lat_enable)) + syno_stat_start_time = local_clock(); +#endif /* MY_ABC_HERE */ percpu = per_cpu_ptr(conf->percpu, cpu); if (test_bit(STRIPE_OP_BIOFILL, &ops_request)) { ops_run_biofill(sh); @@ -2224,7 +2721,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) } if (test_bit(STRIPE_OP_COMPUTE_BLK, &ops_request)) { +#ifdef MY_ABC_HERE + if (level != 6) +#else /* MY_ABC_HERE */ if (level < 6) +#endif /* MY_ABC_HERE */ tx = ops_run_compute5(sh, percpu); else { if (sh->ops.target2 < 0 || sh->ops.target < 0) @@ -2238,7 +2739,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) } if (test_bit(STRIPE_OP_PREXOR, &ops_request)) { +#ifdef MY_ABC_HERE + if (level != 6) +#else /* MY_ABC_HERE */ if (level < 6) +#endif /* MY_ABC_HERE */ tx = ops_run_prexor5(sh, percpu, tx); else tx = ops_run_prexor6(sh, percpu, tx); @@ -2253,7 +2758,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) } if (test_bit(STRIPE_OP_RECONSTRUCT, &ops_request)) { +#ifdef MY_ABC_HERE + if (level != 6) +#else /* MY_ABC_HERE */ if (level < 6) +#endif /* MY_ABC_HERE */ ops_run_reconstruct5(sh, percpu, tx); else ops_run_reconstruct6(sh, percpu, tx); @@ -2276,6 +2785,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) if (test_and_clear_bit(R5_Overlap, &dev->flags)) wake_up(&sh->raid_conf->wait_for_overlap); } +#ifdef MY_ABC_HERE + if (unlikely(sh->syno_stat_lat_enable)) + sh->syno_stat_lat_raid_run_ops += local_clock() - + syno_stat_start_time; +#endif /* MY_ABC_HERE */ put_cpu(); } @@ -2457,6 +2971,112 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors) return err; } +#ifdef MY_ABC_HERE +static void syno_raid5_heal_resize_stripes(struct r5conf *conf, int newsize) +{ +#if PAGE_SIZE != DEFAULT_STRIPE_SIZE + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] page size [%ld] does not match default stripe size [%d], data correction disabled\n", + mdname(conf->mddev), PAGE_SIZE, DEFAULT_STRIPE_SIZE); +#else /* PAGE_SIZE != DEFAULT_STRIPE_SIZE */ + int err = 0; + int i; + LIST_HEAD(newstripes); + struct kmem_cache *sc; + struct syno_heal_stripe_head *osh, *nsh; + + sc = kmem_cache_create(conf->syno_heal_cache_name[1-conf->syno_heal_active_name], + sizeof(struct syno_heal_stripe_head)+(newsize-1)*sizeof(struct syno_heal_r5dev), + 0, 0, NULL); + if (!sc) { + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to allocate new memory cache\n", + mdname(conf->mddev)); + return; + } + + mutex_lock(&conf->syno_heal_cache_size_mutex); + + for (i = conf->syno_heal_max_nr_stripes; i; i--) { + nsh = syno_raid5_heal_alloc_stripe(sc, GFP_KERNEL, newsize, conf); + if (!nsh) + break; + list_add(&nsh->sh_list, &newstripes); + } + + if (i) { + /* didn't get enough, give up */ + while (!list_empty(&newstripes)) { + nsh = list_entry(newstripes.next, struct syno_heal_stripe_head, sh_list); + list_del(&nsh->sh_list); + syno_raid5_heal_free_stripe(sc, nsh); + } + kmem_cache_destroy(sc); + mutex_unlock(&conf->syno_heal_cache_size_mutex); + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to allocate new stripe\n", mdname(conf->mddev)); + return; + } + + list_for_each_entry(nsh, &newstripes, sh_list) { + int disks; + + spin_lock_irq(&conf->syno_heal_stripe_lock); + wait_event_lock_irq(conf->syno_heal_wait_for_stripe, + !list_empty(&conf->syno_heal_free_list), + conf->syno_heal_stripe_lock); + osh = syno_raid5_heal_get_free_stripe(conf); + spin_unlock_irq(&conf->syno_heal_stripe_lock); + + disks = osh->disks; + for (i = 0; i < disks; i++) + nsh->dev[i].page = osh->dev[i].page; + syno_raid5_heal_free_stripe(conf->syno_heal_slab_cache, osh); + } + kmem_cache_destroy(conf->syno_heal_slab_cache); + conf->syno_heal_slab_cache = sc; + conf->syno_heal_active_name = 1 - conf->syno_heal_active_name; + + while (!list_empty(&newstripes)) { + bool success = true; + + nsh = list_entry(newstripes.next, struct syno_heal_stripe_head, sh_list); + list_del_init(&nsh->sh_list); + + for (i = conf->raid_disks; i < newsize; i++) { + if (nsh->dev[i].page == NULL) { + struct page *p = alloc_page(GFP_NOIO); + + nsh->dev[i].page = p; + if (!p) { + success = false; + err = -ENOMEM; + break; + } + } + } + + if (success) { + syno_raid5_heal_release_stripe(nsh); + } else { + syno_raid5_heal_shrink_buffers(nsh); + syno_raid5_heal_free_stripe(conf->syno_heal_slab_cache, nsh); + conf->syno_heal_max_nr_stripes--; + atomic_dec(&conf->syno_heal_active_stripes); + } + } + mutex_unlock(&conf->syno_heal_cache_size_mutex); + + if (err) + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to allocate all pages\n", mdname(conf->mddev)); +#endif /* PAGE_SIZE != DEFAULT_STRIPE_SIZE */ +} +#endif /* MY_ABC_HERE */ static int resize_stripes(struct r5conf *conf, int newsize) { /* Make all the stripes able to hold 'newsize' devices. @@ -2625,7 +3245,14 @@ static int resize_stripes(struct r5conf *conf, int newsize) /* critical section pass, GFP_NOIO no longer needed */ if (!err) +#ifdef MY_ABC_HERE + { conf->pool_size = newsize; + syno_raid5_heal_resize_stripes(conf, newsize); + } +#else /* MY_ABC_HERE */ + conf->pool_size = newsize; +#endif /* MY_ABC_HERE */ mutex_unlock(&conf->cache_size_mutex); return err; @@ -2659,6 +3286,62 @@ static void shrink_stripes(struct r5conf *conf) conf->slab_cache = NULL; } +#ifdef MY_ABC_HERE +static int syno_raid5_data_corrupt_disk_get(const struct r5conf *conf, const int pd_idx, + const int qd_idx, int bad_disk, int *bad_disks, + int max_bad_disk) +{ + int d = 0; + int num_repair = 0; + int repair_disk[2] = {-1, -1}; + int num_bad_disk = 0; + + if (pd_idx != bad_disk && qd_idx != bad_disk) + bad_disks[num_bad_disk++] = bad_disk; + + for (d = 0; d < conf->raid_disks; d++) { + struct md_rdev *rdev; + rcu_read_lock(); + rdev = rcu_dereference(conf->disks[d].rdev); + if (!(rdev && test_bit(In_sync, &rdev->flags))) { + if (num_repair >= conf->max_degraded) { + WARN_ON(1); + rcu_read_unlock(); + return -1; + } + repair_disk[num_repair++] = d; + } + rcu_read_unlock(); + } + WARN_ON(conf->max_degraded != num_repair); + + for (d = 0; d < num_repair && num_bad_disk < max_bad_disk; d++) { + if (pd_idx != repair_disk[d] && qd_idx != repair_disk[d]) + bad_disks[num_bad_disk++] = repair_disk[d]; + } + + return num_bad_disk; +} + +static void syno_raid5_autoremap_report_sectors(const struct r5conf *conf, int bad_disk, + struct stripe_head *sh, struct md_rdev *rdev) +{ + sector_t raid_sector = 0; + int d = 0; + /* for now, maximum possible disk with data-corruption is max_degraded of RAID6 (2) + 1*/ + int bad_disks[3] = {0}; + int num_bad_disk = 0; + + num_bad_disk = syno_raid5_data_corrupt_disk_get(conf, sh->pd_idx, sh->qd_idx, bad_disk, + bad_disks, 3); + + for (d = 0; d < num_bad_disk; d++) { + raid_sector = raid5_compute_blocknr(sh, bad_disks[d], 0); + syno_auto_remap_report(conf->mddev, raid_sector, rdev->bdev); + } +} +#endif /* MY_ABC_HERE */ + static void raid5_end_read_request(struct bio * bi) { struct stripe_head *sh = bi->bi_private; @@ -2667,6 +3350,9 @@ static void raid5_end_read_request(struct bio * bi) char b[BDEVNAME_SIZE]; struct md_rdev *rdev = NULL; sector_t s; +#ifdef MY_ABC_HERE + bool retry_for_remap = false; +#endif /* MY_ABC_HERE */ for (i=0 ; idev[i].req) @@ -2694,9 +3380,25 @@ static void raid5_end_read_request(struct bio * bi) s = sh->sector + rdev->new_data_offset; else s = sh->sector + rdev->data_offset; + +#ifdef MY_ABC_HERE + if (bio_flagged(bi, BIO_SYNO_AUTO_REMAP)) { + bio_clear_flag(bi, BIO_SYNO_AUTO_REMAP); + pr_warn("%s:%s(%d) BIO_SYNO_AUTO_REMAP detected, sector:[%llu], sh count:[%d] disk count:[%d]\n", + __FILE__, __func__, __LINE__, (unsigned long long)sh->sector, + atomic_read(&sh->count), i); + syno_raid5_autoremap_report_sectors(conf, i, sh, rdev); + } +#endif /* MY_ABC_HERE */ + if (!bi->bi_status) { set_bit(R5_UPTODATE, &sh->dev[i].flags); if (test_bit(R5_ReadError, &sh->dev[i].flags)) { +#ifdef MY_ABC_HERE + syno_report_correct_bad_sector(s, + conf->mddev->md_minor, rdev->bdev, + __func__); +#endif /* MY_ABC_HERE */ /* Note that this cannot happen on a * replacement device. We just fail those on * any error @@ -2721,6 +3423,10 @@ static void raid5_end_read_request(struct bio * bi) if (atomic_read(&rdev->read_errors)) atomic_set(&rdev->read_errors, 0); +#ifdef MY_ABC_HERE + if (test_bit(R5_SynoAutoRemaped, &sh->dev[i].flags)) + clear_bit(R5_SynoAutoRemaped, &sh->dev[i].flags); +#endif /* MY_ABC_HERE */ } else { const char *bdn = bdevname(rdev->bdev, b); int retry = 0; @@ -2729,7 +3435,16 @@ static void raid5_end_read_request(struct bio * bi) clear_bit(R5_UPTODATE, &sh->dev[i].flags); if (!(bi->bi_status == BLK_STS_PROTECTION)) atomic_inc(&rdev->read_errors); + +#ifdef MY_ABC_HERE + if (conf->mddev->syno_auto_remap && + !test_bit(R5_SynoAutoRemaped, &sh->dev[i].flags)) { + retry = 1; + retry_for_remap = true; + } else if (test_bit(R5_ReadRepl, &sh->dev[i].flags)) +#else /* MY_ABC_HERE */ if (test_bit(R5_ReadRepl, &sh->dev[i].flags)) +#endif /* MY_ABC_HERE */ pr_warn_ratelimited( "md/raid:%s: read error on replacement device (sector %llu on %s).\n", mdname(conf->mddev), @@ -2737,6 +3452,9 @@ static void raid5_end_read_request(struct bio * bi) bdn); else if (conf->mddev->degraded >= conf->max_degraded) { set_bad = 1; +#ifdef MY_ABC_HERE + if (!test_bit(SynoDiskError, &rdev->flags)) +#endif /* MY_ABC_HERE */ pr_warn_ratelimited( "md/raid:%s: read error not correctable (sector %llu on %s).\n", mdname(conf->mddev), @@ -2752,7 +3470,12 @@ static void raid5_end_read_request(struct bio * bi) bdn); } else if (atomic_read(&rdev->read_errors) > conf->max_nr_stripes) { +#ifdef MY_ABC_HERE + if (!test_bit(Faulty, &rdev->flags) && + !test_bit(SynoDiskError, &rdev->flags)) { +#else /* MY_ABC_HERE */ if (!test_bit(Faulty, &rdev->flags)) { +#endif /* MY_ABC_HERE */ pr_warn("md/raid:%s: %d read_errors > %d stripes\n", mdname(conf->mddev), atomic_read(&rdev->read_errors), @@ -2765,12 +3488,34 @@ static void raid5_end_read_request(struct bio * bi) if (set_bad && test_bit(In_sync, &rdev->flags) && !test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) retry = 1; + +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(s, READ, conf->mddev->md_minor, + rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ if (retry) if (sh->qd_idx >= 0 && sh->pd_idx == i) +#ifdef MY_ABC_HERE + if (retry_for_remap) + set_bit(R5_SynoAutoRemaped, &sh->dev[i].flags); + else + set_bit(R5_ReadError, &sh->dev[i].flags); +#else /* MY_ABC_HERE */ set_bit(R5_ReadError, &sh->dev[i].flags); +#endif /* MY_ABC_HERE */ else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) { +#ifdef MY_ABC_HERE + if (retry_for_remap) + set_bit(R5_SynoAutoRemaped, &sh->dev[i].flags); + else { + set_bit(R5_ReadError, &sh->dev[i].flags); + clear_bit(R5_ReadNoMerge, &sh->dev[i].flags); + } +#else /* MY_ABC_HERE */ set_bit(R5_ReadError, &sh->dev[i].flags); clear_bit(R5_ReadNoMerge, &sh->dev[i].flags); +#endif /* MY_ABC_HERE */ } else set_bit(R5_ReadNoMerge, &sh->dev[i].flags); else { @@ -2780,7 +3525,16 @@ static void raid5_end_read_request(struct bio * bi) && test_bit(In_sync, &rdev->flags) && rdev_set_badblocks( rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), 0))) +#ifdef MY_ABC_HERE + { md_error(conf->mddev, rdev); + if (!syno_is_device_disappear(rdev->bdev) && + test_bit(SynoDiskError, &rdev->flags)) + set_bit(STRIPE_SYNO_NORETRY, &sh->state); + } +#else /* MY_ABC_HERE */ + md_error(conf->mddev, rdev); +#endif /* MY_ABC_HERE */ } } rdev_dec_pending(rdev, conf->mddev); @@ -2836,6 +3590,14 @@ static void raid5_end_write_request(struct bio *bi) set_bit(R5_MadeGoodRepl, &sh->dev[i].flags); } else { if (bi->bi_status) { +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) + syno_report_bad_sector(use_new_offset(conf, sh) ? + sh->sector + rdev->new_data_offset : + sh->sector + rdev->data_offset, + WRITE, conf->mddev->md_minor, + conf->disks[i].rdev->bdev, __func__); +#endif /* MY_ABC_HERE */ set_bit(STRIPE_DEGRADED, &sh->state); set_bit(WriteErrorSeen, &rdev->flags); set_bit(R5_WriteError, &sh->dev[i].flags); @@ -2863,12 +3625,162 @@ static void raid5_end_write_request(struct bio *bi) if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ raid5_release_stripe(sh); +#endif /* MY_ABC_HERE */ if (sh->batch_head && sh != sh->batch_head) raid5_release_stripe(sh->batch_head); +#ifdef MY_ABC_HERE + raid5_release_stripe(sh); +#endif /* MY_ABC_HERE */ } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +static inline bool syno_raid5_is_max_degrade(struct mddev *mddev) +{ + struct r5conf *conf = (struct r5conf *) mddev->private; + + return conf->max_degraded <= mddev->degraded; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * This function is copied from raid5_error. + * Difference is that we allow raid to fail disk even when max degraded. + */ +static void syno_raid5_error_common(struct mddev *mddev, struct md_rdev *rdev) +{ + char b[BDEVNAME_SIZE]; + struct r5conf *conf = mddev->private; + unsigned long flags; + + pr_debug("raid456: error called\n"); + + spin_lock_irqsave(&conf->device_lock, flags); + + set_bit(Faulty, &rdev->flags); + clear_bit(In_sync, &rdev->flags); + mddev->degraded = raid5_calc_degraded(conf); +#ifdef MY_ABC_HERE + if (mddev->degraded > conf->max_degraded && + mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ + spin_unlock_irqrestore(&conf->device_lock, flags); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + + set_bit(Blocked, &rdev->flags); + set_mask_bits(&mddev->sb_flags, 0, + BIT(MD_SB_CHANGE_DEVS) | BIT(MD_SB_CHANGE_PENDING)); + pr_crit("md/raid:%s: Disk failure on %s, disabling device.\n" + "md/raid:%s: Operation continuing on %d devices.\n", + mdname(mddev), + bdevname(rdev->bdev, b), + mdname(mddev), + conf->raid_disks - mddev->degraded); + r5c_update_on_rdev_error(mddev, rdev); +} + +/** + * copy it from original error(...), and modify + * the case: conf->max_degraded <= mddev->degraded + * + * In such case, we must let it can keep read from disk + * + * @param mddev passing from md.c + * @param rdev passing from md.c + * + * @see syno_error_for_hotplug + */ +static void syno_raid5_error_for_internal(struct mddev *mddev, struct md_rdev *rdev) +{ + char b1[BDEVNAME_SIZE]; +#ifdef MY_ABC_HERE + char b2[BDEVNAME_SIZE]; + struct md_rdev *rdev_tmp; +#endif /* MY_ABC_HERE */ + + if (test_bit(In_sync, &rdev->flags) && + syno_raid5_is_max_degrade(mddev)) { +#ifdef MY_ABC_HERE + if (!test_bit(Faulty, &rdev->flags) && !test_bit(SynoDiskError, &rdev->flags)) { + set_bit(MD_SB_CHANGE_DEVS, &mddev->flags); + /* + * find out the disk in sync now, remove it to let it fail to building + * parity. + */ + list_for_each_entry(rdev_tmp, &mddev->disks, same_set) { + if (!test_bit(Faulty, &rdev_tmp->flags) && + !test_bit(In_sync, &rdev_tmp->flags)) { + pr_warn("%s[%d]:%s: %s has read/write error, " + "but it gonna to crashed. " + "We remove %s from raid for stopping sync\n", + __FILE__, __LINE__, __func__, + bdevname(rdev->bdev, b1), + bdevname(rdev_tmp->bdev, b2)); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + syno_raid_rdev_unplug(mddev, rdev_tmp->bdev->bd_dev); + } + } + set_bit(SynoDiskError, &rdev->flags); + } +#endif /* MY_ABC_HERE */ + pr_warn("%s[%d]:%s: disk error on %s\n", + __FILE__, __LINE__, __func__, + bdevname(rdev->bdev, b1)); + } else { + syno_raid5_error_common(mddev, rdev); + } +} + +/** + * This function is main for raid5 + * when the error_handler meet hotplug event. + * + * Internal raid5 error_handler must using + * syno_error_for_internal. + * + * When md meet a r/w error at conf->max_degraded <= + * mddev->degraded, we do not set it faulty, because it + * would become crashed, so we just let it become read only in + * such situation. + * + * External raid5 error_handler must using this function. + * because this type of error is hotplug event, we can't just + * let it be read-only, instead of this, we make it faulty + * + * If there is going to be crashed in raid 4/5/6, and we want + * hotplug it. We need unplug all other disk which are building + * parity now. Otherwise the status will be error in such + * disks("U" instead of "_" ) + * + * @param mddev passing from md.c + * @param rdev passing from md.c + */ +static void syno_raid5_error_for_hotplug(struct mddev *mddev, struct md_rdev *rdev) +{ + char b1[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + struct md_rdev *rdev_tmp; + + if (test_bit(In_sync, &rdev->flags) && + syno_raid5_is_max_degrade(mddev)) { + list_for_each_entry(rdev_tmp, &mddev->disks, same_set) { + if (!test_bit(In_sync, &rdev_tmp->flags) && + !test_bit(Faulty, &rdev_tmp->flags)) { + pr_warn("[%s] %d: %s is being to unplug, but %s is building parity now, disable both\n", + __FILE__, __LINE__, + bdevname(rdev->bdev, b2), + bdevname(rdev_tmp->bdev, b1)); + syno_raid_rdev_unplug(mddev, rdev_tmp->bdev->bd_dev); + } + } + } + syno_raid5_error_common(mddev, rdev); +} +#else /* MY_ABC_HERE */ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev) { char b[BDEVNAME_SIZE]; @@ -2906,6 +3818,7 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev) conf->raid_disks - mddev->degraded); r5c_update_on_rdev_error(mddev, rdev); } +#endif /* MY_ABC_HERE */ /* * Input: a 'big' sector number, @@ -2928,6 +3841,9 @@ sector_t raid5_compute_sector(struct r5conf *conf, sector_t r_sector, int raid_disks = previous ? conf->previous_raid_disks : conf->raid_disks; int data_disks = raid_disks - conf->max_degraded; +#ifdef MY_ABC_HERE + int uneven_count = 0; +#endif /* MY_ABC_HERE */ /* First compute the information on this sector */ @@ -2951,6 +3867,14 @@ sector_t raid5_compute_sector(struct r5conf *conf, sector_t r_sector, case 4: pd_idx = data_disks; break; +#ifdef MY_ABC_HERE + case SYNO_RAID_LEVEL_F1: + uneven_count = md_raid_f1_uneven_count(conf->algorithm); + pd_idx = data_disks - sector_div(stripe2, raid_disks + uneven_count); + pd_idx = ((pd_idx < 0) ? 0 : pd_idx); + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; + break; +#endif /* MY_ABC_HERE */ case 5: switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: @@ -3137,6 +4061,13 @@ sector_t raid5_compute_blocknr(struct stripe_head *sh, int i, int previous) return 0; switch(conf->level) { case 4: break; +#ifdef MY_ABC_HERE + case SYNO_RAID_LEVEL_F1: + if (i < sh->pd_idx) + i += raid_disks; + i -= (sh->pd_idx + 1); + break; +#endif /* MY_ABC_HERE */ case 5: switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: @@ -3336,8 +4267,16 @@ schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s, set_bit(STRIPE_OP_RECONSTRUCT, &s->ops_request); if (s->locked + conf->max_degraded == disks) +#ifdef MY_ABC_HERE + if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) { + atomic_inc(&conf->pending_full_writes); + sh->syno_stat_is_full_write = true; + } + sh->syno_stat_is_rcw = true; +#else /* MY_ABC_HERE */ if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) atomic_inc(&conf->pending_full_writes); +#endif /* MY_ABC_HERE */ } else { BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) || test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags))); @@ -3369,6 +4308,9 @@ schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s, set_bit(STRIPE_OP_PREXOR, &s->ops_request); set_bit(STRIPE_OP_BIODRAIN, &s->ops_request); set_bit(STRIPE_OP_RECONSTRUCT, &s->ops_request); +#ifdef MY_ABC_HERE + sh->syno_stat_is_rcw = false; +#endif /* MY_ABC_HERE */ } /* keep the parity disk(s) locked while asynchronous operations @@ -3708,6 +4650,34 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh, md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf), !abort); } +#ifdef MY_ABC_HERE +static void +syno_handle_failed_expand(struct r5conf *conf, struct stripe_head *sh, + struct stripe_head_state *s) +{ + int disks = sh->disks; + int i; + + BUG_ON(sh->batch_head); + for (i = disks; i--; ) { + struct r5dev *dev = &sh->dev[i]; + /* Aborting all writes and unlocked it. + */ + if (test_and_clear_bit(R5_LOCKED, &dev->flags)) { + clear_bit(R5_Wantwrite, &dev->flags); + s->locked--; + } + } + clear_bit(STRIPE_EXPANDING, &sh->state); + clear_bit(STRIPE_EXPAND_READY, &sh->state); + s->expanded = 0; + atomic_dec(&conf->reshape_stripes); + conf->syno_reshape_failed = 1; + wake_up(&conf->wait_for_overlap); + md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf), 0); +} +#endif /* MY_ABC_HERE */ + static int want_replace(struct stripe_head *sh, int disk_idx) { struct md_rdev *rdev; @@ -3735,6 +4705,9 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); +#ifdef MY_ABC_HERE + force_rcw |= s->syno_force_stripe_rcw; +#endif /* MY_ABC_HERE */ if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) /* No point reading this as we already have it or have @@ -3754,6 +4727,11 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, */ return 1; +#ifdef MY_ABC_HERE + if (s->syno_full_stripe_merging && test_bit(R5_Insync, &dev->flags)) + return 1; +#endif /* MY_ABC_HERE */ + if ((s->failed >= 1 && fdev[0]->toread) || (s->failed >= 2 && fdev[1]->toread)) /* If we want to read from a failed device, then @@ -4090,6 +5068,9 @@ static int handle_stripe_dirtying(struct r5conf *conf, * generate correct data from the parity. */ if (conf->rmw_level == PARITY_DISABLE_RMW || +#ifdef MY_ABC_HERE + unlikely(s->syno_force_stripe_rcw) || +#endif /* MY_ABC_HERE */ (recovery_cp < MaxSector && sh->sector >= recovery_cp && s->failed == 0)) { /* Calculate the real rcw later - for now make it @@ -4300,15 +5281,33 @@ static void handle_parity_checks5(struct r5conf *conf, struct stripe_head *sh, */ set_bit(STRIPE_INSYNC, &sh->state); else { +#ifdef MY_ABC_HERE + struct mddev *mddev = conf->mddev; + + if (mddev->syno_sync_debug) + pr_err("%s: raid5 not sync in stripe sector [%llu] size [%llu]\n", + mdname(mddev), + (unsigned long long)sh->sector, + (unsigned long long)RAID5_STRIPE_SECTORS(conf)); +#endif /* MY_ABC_HERE */ atomic64_add(RAID5_STRIPE_SECTORS(conf), &conf->mddev->resync_mismatches); if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) { /* don't try to repair!! */ set_bit(STRIPE_INSYNC, &sh->state); +#ifdef MY_ABC_HERE + if (!mddev->syno_sync_debug) + pr_warn_ratelimited("%s: mismatch sector in range %llu-%llu\n", + mdname(conf->mddev), + (unsigned long long) sh->sector, + (unsigned long long) sh->sector + + RAID5_STRIPE_SECTORS(conf)); +#else /* MY_ABC_HERE */ pr_warn_ratelimited("%s: mismatch sector in range " "%llu-%llu\n", mdname(conf->mddev), (unsigned long long) sh->sector, (unsigned long long) sh->sector + RAID5_STRIPE_SECTORS(conf)); +#endif /* MY_ABC_HERE */ } else { sh->check_state = check_state_compute_run; set_bit(STRIPE_COMPUTE_RUN, &sh->state); @@ -4465,15 +5464,33 @@ static void handle_parity_checks6(struct r5conf *conf, struct stripe_head *sh, */ } } else { +#ifdef MY_ABC_HERE + struct mddev *mddev = conf->mddev; + + if (mddev->syno_sync_debug) + pr_err("%s: raid6 not sync in stripe sector [%llu] size [%llu]\n", + mdname(mddev), + (unsigned long long)sh->sector, + (unsigned long long)RAID5_STRIPE_SECTORS(conf)); +#endif /* MY_ABC_HERE */ atomic64_add(RAID5_STRIPE_SECTORS(conf), &conf->mddev->resync_mismatches); if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) { /* don't try to repair!! */ set_bit(STRIPE_INSYNC, &sh->state); +#ifdef MY_ABC_HERE + if (!mddev->syno_sync_debug) + pr_warn_ratelimited("%s: mismatch sector in range %llu-%llu\n", + mdname(conf->mddev), + (unsigned long long) sh->sector, + (unsigned long long) sh->sector + + RAID5_STRIPE_SECTORS(conf)); +#else /* MY_ABC_HERE */ pr_warn_ratelimited("%s: mismatch sector in range " "%llu-%llu\n", mdname(conf->mddev), (unsigned long long) sh->sector, (unsigned long long) sh->sector + RAID5_STRIPE_SECTORS(conf)); +#endif /* MY_ABC_HERE */ } else { int *target = &sh->ops.target; @@ -4588,10 +5605,26 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) int i; int do_recovery = 0; +#ifdef MY_ABC_HERE + unsigned char is_bad_sh = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int non_full_insync = 0; + int non_full_insync_num[2] = {-1, -1}; +#endif /* MY_ABC_HERE */ + memset(s, 0, sizeof(*s)); +#ifdef MY_ABC_HERE + if (test_and_clear_bit(STRIPE_SYNO_NORETRY, &sh->state)) + is_bad_sh = 1; +#endif /* MY_ABC_HERE */ + s->expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state) && !sh->batch_head; s->expanded = test_bit(STRIPE_EXPAND_READY, &sh->state) && !sh->batch_head; +#ifdef MY_ABC_HERE + s->syno_full_stripe_merging = test_bit(SYNO_FULL_STRIPE_MERGING, &sh->syno_full_stripe_merge_state); +#endif /* MY_ABC_HERE */ s->failed_num[0] = -1; s->failed_num[1] = -1; s->log_failed = r5l_log_disk_error(conf); @@ -4636,6 +5669,10 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) s->to_write++; if (!test_bit(R5_OVERWRITE, &dev->flags)) s->non_overwrite++; +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(dev->towrite, BIO_CORRECTION_ABORT))) + s->syno_force_stripe_rcw = true; +#endif /* MY_ABC_HERE */ } if (dev->written) s->written++; @@ -4685,7 +5722,16 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) set_bit(R5_ReadError, &dev->flags); } } else if (test_bit(In_sync, &rdev->flags)) +#ifdef MY_ABC_HERE + { + if (!is_bad_sh && + !(test_bit(SynoDiskError, &rdev->flags) && + test_bit(STRIPE_SYNCING, &sh->state))) + set_bit(R5_Insync, &dev->flags); + } +#else /* MY_ABC_HERE */ set_bit(R5_Insync, &dev->flags); +#endif /* MY_ABC_HERE */ else if (sh->sector + RAID5_STRIPE_SECTORS(conf) <= rdev->recovery_offset) /* in sync if before recovery_offset */ set_bit(R5_Insync, &dev->flags); @@ -4755,7 +5801,36 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) s->injournal++; if (test_bit(R5_InJournal, &dev->flags) && dev->written) s->just_cached++; +#ifdef MY_ABC_HERE + if (rdev && test_bit(SynoNonFullInsync, &rdev->flags)) { + if (non_full_insync < 2) + non_full_insync_num[non_full_insync] = i; + non_full_insync++; + } +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE + /* Only do fast scrubbing when there is no failed device. Otherwise, + * we might let in-flight IO on this sh return Error. + */ + if (test_bit(STRIPE_SYNCING, &sh->state) && + test_bit(MD_RECOVERY_REQUESTED, &(conf->mddev->recovery)) && + !s->failed && non_full_insync && + non_full_insync <= conf->max_degraded) { + for (i = 0; i < non_full_insync && i < 2; i++) { + int idx = non_full_insync_num[i]; + + if (idx == -1) + break; + clear_bit(R5_Insync, &sh->dev[idx].flags); + s->failed_num[s->failed] = idx; + s->failed++; + /* Since requested resync will set s->syncing = 1, + * we don't need to set do_recovery here + */ + } + } +#endif /* MY_ABC_HERE */ if (test_bit(STRIPE_SYNCING, &sh->state)) { /* If there is a failed device being replaced, * we must be recovering. @@ -4859,6 +5934,9 @@ static void break_stripe_batch_list(struct stripe_head *head_sh, if (handle_flags == 0 || sh->state & handle_flags) set_bit(STRIPE_HANDLE, &sh->state); +#ifdef MY_ABC_HERE + sh->syno_stat_wait_io_start = 0; +#endif /* MY_ABC_HERE */ raid5_release_stripe(sh); } spin_lock_irq(&head_sh->stripe_lock); @@ -4882,6 +5960,9 @@ static void handle_stripe(struct stripe_head *sh) int prexor; int disks = sh->disks; struct r5dev *pdev, *qdev; +#ifdef MY_ABC_HERE + u64 syno_stat_start_time; +#endif /* MY_ABC_HERE */ clear_bit(STRIPE_HANDLE, &sh->state); @@ -4901,6 +5982,11 @@ static void handle_stripe(struct stripe_head *sh) return; } +#ifdef MY_ABC_HERE + if (unlikely(sh->syno_stat_lat_enable)) + syno_stat_start_time = local_clock(); +#endif /* MY_ABC_HERE */ + if (test_and_clear_bit(STRIPE_BATCH_ERR, &sh->state)) break_stripe_batch_list(sh, 0); @@ -4920,6 +6006,15 @@ static void handle_stripe(struct stripe_head *sh) } spin_unlock(&sh->stripe_lock); } +#ifdef MY_ABC_HERE + if (test_bit(MD_RECOVERY_RUNNING, &conf->mddev->recovery)) { + clear_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state); + clear_bit(SYNO_FULL_STRIPE_MERGING, &sh->syno_full_stripe_merge_state); + clear_bit(SYNO_FULL_STRIPE_MERGE_DO_WRITE, &sh->syno_full_stripe_merge_state); + } else if (test_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state)) { + set_bit(SYNO_FULL_STRIPE_MERGING, &sh->syno_full_stripe_merge_state); + } +#endif /* MY_ABC_HERE */ clear_bit(STRIPE_DELAYED, &sh->state); pr_debug("handling stripe %llu, state=%#lx cnt=%d, " @@ -4927,6 +6022,16 @@ static void handle_stripe(struct stripe_head *sh) (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count), sh->pd_idx, sh->qd_idx, sh->check_state, sh->reconstruct_state); +#ifdef MY_ABC_HERE + if (sh->syno_stat_wait_delay_start) { + sh->syno_stat_wait_delay += jiffies - sh->syno_stat_wait_delay_start; + sh->syno_stat_wait_delay_start = 0; + } + if (sh->syno_stat_wait_io_start) { + sh->syno_stat_wait_io += jiffies - sh->syno_stat_wait_io_start; + sh->syno_stat_wait_io_start = 0; + } +#endif /* MY_ABC_HERE */ analyse_stripe(sh, &s); @@ -4968,13 +6073,27 @@ static void handle_stripe(struct stripe_head *sh) */ if (s.failed > conf->max_degraded || (s.log_failed && s.injournal == 0)) { +#ifdef MY_ABC_HERE + clear_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state); + clear_bit(SYNO_FULL_STRIPE_MERGING, &sh->syno_full_stripe_merge_state); + clear_bit(SYNO_FULL_STRIPE_MERGE_DO_WRITE, &sh->syno_full_stripe_merge_state); + s.syno_full_stripe_merging = 0; +#endif /* MY_ABC_HERE */ sh->check_state = 0; sh->reconstruct_state = 0; break_stripe_batch_list(sh, 0); if (s.to_read+s.to_write+s.written) handle_failed_stripe(conf, sh, &s, disks); if (s.syncing + s.replacing) +#ifdef MY_ABC_HERE handle_failed_sync(conf, sh, &s); +#else /* MY_ABC_HERE */ + handle_failed_sync(conf, sh, &s); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (s.expanded) + syno_handle_failed_expand(conf, sh, &s); +#endif /* MY_ABC_HERE */ } /* Now we check to see if any write operations have recently @@ -4995,6 +6114,22 @@ static void handle_stripe(struct stripe_head *sh) BUG_ON(sh->qd_idx >= 0 && !test_bit(R5_UPTODATE, &sh->dev[sh->qd_idx].flags) && !test_bit(R5_Discard, &sh->dev[sh->qd_idx].flags)); +#ifdef MY_ABC_HERE + set_bit(STRIPE_SYNO_STABLE_STATE, &sh->state); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (test_bit(MD_RECOVERY_RUNNING, &conf->mddev->recovery) && + test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery)) + for (i = 0; i < s.failed; i++) { + struct r5dev *dev = &sh->dev[s.failed_num[i]]; + if (test_bit(R5_UPTODATE, &dev->flags) && + !test_bit(R5_LOCKED, &dev->flags)) { + set_bit(R5_LOCKED, &dev->flags); + s.locked++; + set_bit(R5_Wantwrite, &dev->flags); + } + } +#endif /* MY_ABC_HERE */ for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; if (test_bit(R5_LOCKED, &dev->flags) && @@ -5017,6 +6152,23 @@ static void handle_stripe(struct stripe_head *sh) s.dec_preread_active = 1; } +#ifdef MY_ABC_HERE + if (s.syno_full_stripe_merging && test_and_clear_bit(SYNO_FULL_STRIPE_MERGE_DO_WRITE, &sh->syno_full_stripe_merge_state)) { + for (i = disks; i--; ) { + struct r5dev *dev = &sh->dev[i]; + if (!test_bit(R5_LOCKED, &dev->flags) + && test_bit(R5_UPTODATE, &dev->flags)) { + set_bit(R5_Wantwrite, &dev->flags); + set_bit(R5_LOCKED, &dev->flags); + s.locked++; + } + } + clear_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state); + clear_bit(SYNO_FULL_STRIPE_MERGING, &sh->syno_full_stripe_merge_state); + s.syno_full_stripe_merging = 0; + } +#endif /* MY_ABC_HERE */ + /* * might be able to return some write requests if the parity blocks * are safe, or on a failed drive @@ -5027,7 +6179,11 @@ static void handle_stripe(struct stripe_head *sh) qdev = &sh->dev[sh->qd_idx]; s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) +#ifdef MY_ABC_HERE + || conf->level != 6; +#else /* MY_ABC_HERE */ || conf->level < 6; +#endif /* MY_ABC_HERE */ if (s.written && (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) @@ -5052,9 +6208,19 @@ static void handle_stripe(struct stripe_head *sh) || (s.to_write && s.failed) || (s.syncing && (s.uptodate + s.compute < disks)) || s.replacing +#ifdef MY_ABC_HERE + || s.syno_full_stripe_merging +#endif /* MY_ABC_HERE */ || s.expanding) handle_stripe_fill(sh, &s, disks); +#ifdef MY_ABC_HERE + if (s.syno_full_stripe_merging && !s.locked && !sh->reconstruct_state && + !sh->check_state && s.uptodate + s.failed >= disks) { + set_bit(SYNO_FULL_STRIPE_MERGE_DO_WRITE, &sh->syno_full_stripe_merge_state); + set_bit(STRIPE_HANDLE, &sh->state); + } +#endif /* MY_ABC_HERE */ /* * When the stripe finishes full journal write cycle (write to journal * and raid disk), this is the clean up procedure so it is ready for @@ -5267,8 +6433,32 @@ static void handle_stripe(struct stripe_head *sh) } clear_bit_unlock(STRIPE_ACTIVE, &sh->state); +#ifdef MY_ABC_HERE + if (unlikely(sh->syno_stat_lat_enable)) { + sh->syno_stat_lat_handle_stripe += local_clock() - + syno_stat_start_time; + } +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +static void syno_raid5_activate_stable_delayed(struct r5conf *conf) +{ + while (!list_empty(&conf->syno_stable_list)) { + struct list_head *l = conf->syno_stable_list.next; + struct stripe_head *sh; + + sh = list_entry(l, struct stripe_head, lru); + list_del_init(l); + clear_bit(STRIPE_DELAYED, &sh->state); + clear_bit(STRIPE_SYNO_STABLE_STATE, &sh->state); + if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) + atomic_inc(&conf->preread_active_stripes); + list_add_tail(&sh->lru, &conf->hold_list); + raid5_wakeup_stripe_thread(sh); + } +} +#endif /* MY_ABC_HERE */ static void raid5_activate_delayed(struct r5conf *conf) { if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { @@ -5368,6 +6558,11 @@ static void raid5_align_endio(struct bio *bi) struct r5conf *conf; struct md_rdev *rdev; blk_status_t error = bi->bi_status; +#ifdef MY_ABC_HERE + bool auto_remap = bio_flagged(bi, BIO_SYNO_AUTO_REMAP); + + bio_clear_flag(bi, BIO_SYNO_AUTO_REMAP); +#endif /* MY_ABC_HERE */ bio_put(bi); @@ -5378,18 +6573,116 @@ static void raid5_align_endio(struct bio *bi) rdev_dec_pending(rdev, conf->mddev); +#ifdef MY_ABC_HERE + if (auto_remap) { + pr_warn("%s:%s(%d) BIO_SYNO_AUTO_REMAP detected\n", __FILE__, __func__, __LINE__); + syno_auto_remap_report(conf->mddev, raid_bi->bi_iter.bi_sector, rdev->bdev); + } +#endif /* MY_ABC_HERE */ + if (!error) { bio_endio(raid_bi); if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_quiescent); return; } +#ifdef MY_ABC_HERE + if (!syno_is_device_disappear(rdev->bdev)) { + int dd_idx; + sector_t report_sector = raid5_compute_sector(conf, + raid_bi->bi_iter.bi_sector, 0, &dd_idx, NULL) + + rdev->data_offset; + + syno_report_bad_sector(report_sector, READ, + conf->mddev->md_minor, rdev->bdev, __func__); + } +#endif /* MY_ABC_HERE */ pr_debug("raid5_align_endio : io error...handing IO for a retry\n"); add_bio_to_retry(raid_bi, conf); } +#ifdef MY_ABC_HERE +static void syno_dummy_read_endio(struct bio *bio) +{ + struct md_rdev *rdev = bio->bi_private; + + if (bio->bi_status) + pr_err("%s: dummy read sector [%llu] error %d\n", + mdname(rdev->mddev), (u64)bio->bi_iter.bi_sector, bio->bi_status); + + rdev_dec_pending(rdev, rdev->mddev); + bio_put(bio); +} + +static void syno_do_dummy_read(struct r5conf *conf, sector_t read_sector, sector_t leng, int idx) +{ + struct mddev *mddev = conf->mddev; + struct bio *bio = NULL; + struct md_rdev *rdev = NULL; + + if (idx < 0) { + pr_err("%s: bad idx [%d]\n", mdname(mddev), idx); + return; + } + + rcu_read_lock(); + rdev = rcu_dereference(conf->disks[idx].rdev); + if (!rdev) { + pr_err("%s: failed to get rdev of idx [%d]\n", mdname(mddev), idx); + goto err; + } + + if (unlikely((read_sector + leng) > mddev->dev_sectors)) + goto err; + + bio = bio_clone_fast(conf->syno_dummy_bio, GFP_NOWAIT, &mddev->bio_set); + if (!bio) { + pr_err("%s: failed to allocate dummy read bio\n", mdname(mddev)); + goto err; + } + + bio->bi_end_io = syno_dummy_read_endio; + bio->bi_private = rdev; + bio_set_dev(bio, rdev->bdev); + bio->bi_next = NULL; + bio->bi_opf = REQ_OP_READ; + bio->bi_iter.bi_sector = read_sector + rdev->data_offset; + bio->bi_iter.bi_size = leng << 9; + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + + submit_bio_noacct(bio); + return; + +err: + rcu_read_unlock(); + if (bio) + bio_put(bio); +} + +static void syno_dummy_read(struct r5conf *conf, sector_t raid5_logical_sector, + sector_t rdev_end_sector, int dd_idx) +{ + int dummy_dd_idx; + struct stripe_head sh; + + if (rdev_end_sector & (sector_t)(conf->chunk_sectors - 1)) + return; + + raid5_compute_sector(conf, raid5_logical_sector, 0, &dummy_dd_idx, &sh); + + if (dd_idx != sh.pd_idx) + return; + + if (conf->level == 5) + syno_do_dummy_read(conf, rdev_end_sector, conf->chunk_sectors, dd_idx); + else if (conf->level == 6) + syno_do_dummy_read(conf, rdev_end_sector, 2 * conf->chunk_sectors, dd_idx); +} +#endif /* MY_ABC_HERE */ + static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) { struct r5conf *conf = mddev->private; @@ -5397,6 +6690,10 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) struct bio* align_bi; struct md_rdev *rdev; sector_t end_sector; +#ifdef MY_ABC_HERE + sector_t raid5_next_stripe_sector = raid_bio->bi_iter.bi_sector + + (conf->raid_disks - conf->max_degraded) * conf->chunk_sectors; +#endif /* MY_ABC_HERE */ if (!in_chunk_boundary(mddev, raid_bio)) { pr_debug("%s: non aligned\n", __func__); @@ -5472,6 +6769,11 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) align_bi, disk_devt(mddev->gendisk), raid_bio->bi_iter.bi_sector); submit_bio_noacct(align_bi); +#ifdef MY_ABC_HERE + if (conf->syno_dummy_read) + syno_dummy_read(conf, raid5_next_stripe_sector, end_sector, + dd_idx); +#endif /* MY_ABC_HERE */ return 1; } else { rcu_read_unlock(); @@ -5491,6 +6793,9 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio) struct r5conf *conf = mddev->private; split = bio_split(raid_bio, sectors, GFP_NOIO, &conf->bio_split); bio_chain(split, raid_bio); +#ifdef MY_ABC_HERE + bio_set_flag(raid_bio, BIO_SYNO_DELAYED); +#endif /* MY_ABC_HERE */ submit_bio_noacct(raid_bio); raid_bio = split; } @@ -5607,8 +6912,50 @@ struct raid5_plug_cb { struct blk_plug_cb cb; struct list_head list; struct list_head temp_inactive_list[NR_STRIPE_HASH_LOCKS]; +#ifdef MY_ABC_HERE + int pending_cnt; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static bool syno_full_stripe_merge_check(struct stripe_head *sh, struct list_head *cb_list, sector_t *checked_sector) +{ + struct stripe_head *tmp = NULL; + struct r5conf *conf = sh->raid_conf; + int chunk_sectors = conf->chunk_sectors; + int stripe_cnt = 0; + int data_disks = (conf->raid_disks - conf->max_degraded) * (chunk_sectors / STRIPE_SECTORS); + int count = 0; + sector_t sector = sh->sector; + sector_t chunk_start, chunk_end; + + chunk_start = round_down(sector, chunk_sectors); + chunk_end = chunk_start + chunk_sectors; + + count = sh->overwrite_disks; + stripe_cnt++; + list_for_each_entry(tmp, cb_list, lru) { + if (tmp->sector >= chunk_end) + break; + count += tmp->overwrite_disks; + if (test_bit(SYNO_FULL_STRIPE_MERGE, &tmp->syno_full_stripe_merge_state)) + stripe_cnt++; + } + *checked_sector = chunk_end; + + if (stripe_cnt == chunk_sectors / STRIPE_SECTORS && + count >= data_disks / SYNO_FULL_STRIPE_MERGE_DENOMINATOR) + return true; + + list_for_each_entry(tmp, cb_list, lru) { + if (tmp->sector >= chunk_end) + break; + clear_bit(SYNO_FULL_STRIPE_MERGE, &tmp->syno_full_stripe_merge_state); + } + return false; +} +#endif /* MY_ABC_HERE */ + static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule) { struct raid5_plug_cb *cb = container_of( @@ -5620,10 +6967,19 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule) int hash; if (cb->list.next && !list_empty(&cb->list)) { +#ifdef MY_ABC_HERE + sector_t checked_sector = 0; +#endif /* MY_ABC_HERE */ spin_lock_irq(&conf->device_lock); while (!list_empty(&cb->list)) { sh = list_first_entry(&cb->list, struct stripe_head, lru); list_del_init(&sh->lru); +#ifdef MY_ABC_HERE + if (test_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state) && + sh->sector >= checked_sector && + !syno_full_stripe_merge_check(sh, &cb->list, &checked_sector)) + clear_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state); +#endif /* MY_ABC_HERE */ /* * avoid race release_stripe_plug() sees * STRIPE_ON_UNPLUG_LIST clear but the stripe @@ -5655,6 +7011,20 @@ static void release_stripe_plug(struct mddev *mddev, raid5_unplug, mddev, sizeof(struct raid5_plug_cb)); struct raid5_plug_cb *cb; +#ifdef MY_ABC_HERE + struct r5conf *conf = sh->raid_conf; + int flush_stripe_cnt = mddev->syno_flush_plug_threshold; + int sectors_per_chunk, stripes_per_chunk; + sector_t tmp_sector; + bool is_first_stripe; + + sectors_per_chunk = (sh->generation == conf->generation - 1) ? + conf->prev_chunk_sectors : conf->chunk_sectors; + stripes_per_chunk = sectors_per_chunk >> RAID5_STRIPE_SHIFT(conf); + tmp_sector = sh->sector; + is_first_stripe = !(sector_div(tmp_sector, sectors_per_chunk)); +init: +#endif /* MY_ABC_HERE */ if (!blk_cb) { raid5_release_stripe(sh); @@ -5670,10 +7040,30 @@ static void release_stripe_plug(struct mddev *mddev, INIT_LIST_HEAD(cb->temp_inactive_list + i); } +#ifdef MY_ABC_HERE + if (!test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state) && + current->plug && cb->pending_cnt >= flush_stripe_cnt) { + if (is_first_stripe || + cb->pending_cnt >= flush_stripe_cnt + stripes_per_chunk) { + blk_flush_plug_list(current->plug, false); + blk_cb = blk_check_plugged(raid5_unplug, mddev, + sizeof(struct raid5_plug_cb)); + goto init; + } + } + if (!test_and_set_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)) { + list_add_tail(&sh->lru, &cb->list); + /* blk_check_plugged will init pending_cnt to zero by kzalloc */ + ++cb->pending_cnt; + } else { + raid5_release_stripe(sh); + } +#else /* MY_ABC_HERE */ if (!test_and_set_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)) list_add_tail(&sh->lru, &cb->list); else raid5_release_stripe(sh); +#endif /* MY_ABC_HERE */ } static void make_discard_request(struct mddev *mddev, struct bio *bi) @@ -5763,6 +7153,35 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) bio_endio(bi); } +#ifdef MY_ABC_HERE +static void syno_do_full_stripe_merge(struct mddev *mddev, struct stripe_head *sh) +{ + struct r5conf *conf = mddev->private; + struct stripe_head *sh1; + sector_t stripe_addr = sh->sector; + int chunk_sectors = conf->chunk_sectors; + int i; + + if (test_bit(SYNO_FULL_STRIPE_MERGE, &sh->syno_full_stripe_merge_state)) + return; + stripe_addr = round_down(stripe_addr, chunk_sectors); + + for (i = 0; i < chunk_sectors; i += STRIPE_SECTORS) { + sh1 = raid5_get_active_stripe(conf, stripe_addr+i, 0, 1, 0); + if (!sh1) + break; + if (sh1->batch_head) { + release_stripe_plug(mddev,sh1); + break; + } + set_bit(SYNO_FULL_STRIPE_MERGE, &sh1->syno_full_stripe_merge_state); + set_bit(STRIPE_HANDLE, &sh1->state); + clear_bit(STRIPE_DELAYED, &sh1->state); + release_stripe_plug(mddev, sh1); + } +} +#endif /* MY_ABC_HERE */ + static bool raid5_make_request(struct mddev *mddev, struct bio * bi) { struct r5conf *conf = mddev->private; @@ -5792,6 +7211,30 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) do_flush = bi->bi_opf & REQ_PREFLUSH; } +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed) { + bio_io_error(bi); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (mddev->degraded > conf->max_degraded) { + /** + * if there has more than max_degraded disks lose, + * we would not permit keeping access on it + */ + bio_io_error(bi); + return true; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(bi, BIO_CORRECTION_RETRY)) && + syno_md_heal_is_valid_md_stat(mddev) && + conf->syno_heal_slab_cache) { + syno_raid5_heal_read_request(mddev, bi); + return true; + } +#endif /* MY_ABC_HERE */ if (!md_write_start(mddev, bi)) return false; /* @@ -5921,6 +7364,12 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) (bi->bi_opf & REQ_SYNC) && !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) atomic_inc(&conf->preread_active_stripes); +#ifdef MY_ABC_HERE + if (conf->syno_full_stripe_merge && rw == WRITE && !previous && + !test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) && + bio_flagged(bi, BIO_SYNO_FULL_STRIPE_MERGE)) + syno_do_full_stripe_merge(mddev, sh); +#endif /* MY_ABC_HERE */ release_stripe_plug(mddev, sh); } else { /* cannot get stripe for read-ahead, just give-up */ @@ -6072,6 +7521,10 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk || test_bit(MD_RECOVERY_INTR, &mddev->recovery)); if (atomic_read(&conf->reshape_stripes) != 0) return 0; +#ifdef MY_ABC_HERE + if (conf->syno_reshape_failed == 1) + return 0; +#endif /* MY_ABC_HERE */ mddev->reshape_position = conf->reshape_progress; mddev->curr_resync_completed = sector_nr; if (!mddev->reshape_backwards) @@ -6179,6 +7632,10 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk || test_bit(MD_RECOVERY_INTR, &mddev->recovery)); if (atomic_read(&conf->reshape_stripes) != 0) goto ret; +#ifdef MY_ABC_HERE + if (conf->syno_reshape_failed == 1) + goto ret; +#endif /* MY_ABC_HERE */ mddev->reshape_position = conf->reshape_progress; mddev->curr_resync_completed = sector_nr; if (!mddev->reshape_backwards) @@ -6216,6 +7673,13 @@ static inline sector_t raid5_sync_request(struct mddev *mddev, sector_t sector_n sector_t sync_blocks; int still_degraded = 0; int i; +#ifdef MY_ABC_HERE + sector_t skipped_sectors = 0; + bool do_fast_rebuild = true; +#ifdef MY_ABC_HERE + struct md_rdev *rdev; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ if (sector_nr >= max_sector) { /* just being told to finish up .. nothing much to do */ @@ -6257,6 +7721,14 @@ static inline sector_t raid5_sync_request(struct mddev *mddev, sector_t sector_n *skipped = 1; return rv; } +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) { + sector_t rv = mddev->dev_sectors - sector_nr; + *skipped = 1; + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + return rv; + } +#endif /* MY_ABC_HERE */ if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && !conf->fullsync && !md_bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && @@ -6269,6 +7741,34 @@ static inline sector_t raid5_sync_request(struct mddev *mddev, sector_t sector_n } md_bitmap_cond_end_sync(mddev->bitmap, sector_nr, false); +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + skipped_sectors = syno_md_speedup_requested_resync(mddev, sector_nr); + if (skipped_sectors) { + *skipped = 1; + return skipped_sectors; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (conf->level == SYNO_RAID_LEVEL_F1) { + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) { + if (rdev != NULL && test_bit(Replacement, &rdev->flags)) { + do_fast_rebuild = 0; + break; + } + } + rcu_read_unlock(); + } +#endif /* MY_ABC_HERE */ + if (do_fast_rebuild) { + skipped_sectors = syno_md_speedup_rebuild(mddev, sector_nr); + if (skipped_sectors) { + *skipped = 1; + return skipped_sectors; + } + } +#endif /* MY_ABC_HERE */ sh = raid5_get_active_stripe(conf, sector_nr, 0, 1, 0); if (sh == NULL) { @@ -6345,7 +7845,15 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { +#ifdef MY_ABC_HERE + int hash; + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); +#else /* MY_ABC_HERE */ raid5_release_stripe(sh); +#endif /* MY_ABC_HERE */ conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; @@ -6415,6 +7923,21 @@ static int handle_active_stripes(struct r5conf *conf, int group, return batch_size; } +#ifdef MY_ABC_HERE +static void syno_wakeup_defer_thread(struct r5conf *conf) +{ + int i; + int group_cnt = conf->syno_defer_group_cnt; + struct syno_r5defer *group; + + for (i = 0; i < group_cnt; ++i) { + group = &(conf->syno_defer_groups[i]); + set_bit(SYNO_DEFER_FLUSH_ALL, &group->state); + md_wakeup_thread(group->defer_thread); + } +} +#endif /* MY_ABC_HERE */ + static void raid5_do_work(struct work_struct *work) { struct r5worker *worker = container_of(work, struct r5worker, work); @@ -6427,6 +7950,10 @@ static void raid5_do_work(struct work_struct *work) pr_debug("+++ raid5worker active\n"); +#ifdef MY_ABC_HERE + atomic_inc(&conf->syno_active_stripe_workers); +#endif /* MY_ABC_HERE */ + blk_start_plug(&plug); handled = 0; spin_lock_irq(&conf->device_lock); @@ -6441,11 +7968,18 @@ static void raid5_do_work(struct work_struct *work) if (!batch_size && !released) break; handled += batch_size; +#ifdef MY_ABC_HERE + if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) + md_wakeup_thread(mddev->thread); +#endif /* MY_ABC_HERE */ wait_event_lock_irq(mddev->sb_wait, !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags), conf->device_lock); } pr_debug("%d stripes handled\n", handled); +#ifdef MY_ABC_HERE + conf->syno_stat_r5worker_handle_cnt += handled; +#endif /* MY_ABC_HERE */ spin_unlock_irq(&conf->device_lock); @@ -6456,6 +7990,12 @@ static void raid5_do_work(struct work_struct *work) async_tx_issue_pending_all(); blk_finish_plug(&plug); +#ifdef MY_ABC_HERE + if (atomic_dec_and_test(&conf->syno_active_stripe_workers) && + conf->syno_defer_mode) + syno_wakeup_defer_thread(conf); +#endif /* MY_ABC_HERE */ + pr_debug("--- raid5worker inactive\n"); } @@ -6477,6 +8017,10 @@ static void raid5d(struct md_thread *thread) md_check_recovery(mddev); +#ifdef MY_ABC_HERE + atomic_inc(&conf->syno_active_stripe_workers); +#endif /* MY_ABC_HERE */ + blk_start_plug(&plug); handled = 0; spin_lock_irq(&conf->device_lock); @@ -6485,6 +8029,11 @@ static void raid5d(struct md_thread *thread) int batch_size, released; unsigned int offset; +#ifdef MY_ABC_HERE + spin_unlock_irq(&conf->device_lock); + syno_raid5_heal_handle_stripe(conf); + spin_lock_irq(&conf->device_lock); +#endif /* MY_ABC_HERE*/ released = release_stripe_list(conf, conf->temp_inactive_list); if (released) clear_bit(R5_DID_ALLOC, &conf->cache_state); @@ -6500,6 +8049,9 @@ static void raid5d(struct md_thread *thread) activate_bit_delay(conf, conf->temp_inactive_list); } raid5_activate_delayed(conf); +#ifdef MY_ABC_HERE + syno_raid5_activate_stable_delayed(conf); +#endif /* MY_ABC_HERE */ while ((bio = remove_bio_from_retry(conf, &offset))) { int ok; @@ -6524,6 +8076,9 @@ static void raid5d(struct md_thread *thread) } } pr_debug("%d stripes handled\n", handled); +#ifdef MY_ABC_HERE + conf->syno_stat_raid5d_handle_cnt += handled; +#endif /* MY_ABC_HERE */ spin_unlock_irq(&conf->device_lock); if (test_and_clear_bit(R5_ALLOC_MORE, &conf->cache_state) && @@ -6543,6 +8098,12 @@ static void raid5d(struct md_thread *thread) async_tx_issue_pending_all(); blk_finish_plug(&plug); +#ifdef MY_ABC_HERE + if (atomic_dec_and_test(&conf->syno_active_stripe_workers) && + conf->syno_defer_mode) + syno_wakeup_defer_thread(conf); +#endif /* MY_ABC_HERE */ + pr_debug("--- raid5d inactive\n"); } @@ -6584,6 +8145,10 @@ raid5_set_cache_size(struct mddev *mddev, int size) result = -ENOMEM; break; } +#ifdef MY_ABC_HERE + if (!conf->syno_enable_stripe_grow) + conf->min_nr_stripes = conf->max_nr_stripes; +#endif /* MY_ABC_HERE */ mutex_unlock(&conf->cache_size_mutex); return result; @@ -6644,15 +8209,49 @@ raid5_store_rmw_level(struct mddev *mddev, const char *page, size_t len) if (kstrtoul(page, 10, &new)) return -EINVAL; +#ifdef MY_ABC_HERE + if (conf->level == 6 && new != PARITY_DISABLE_RMW && + !raid6_call.xor_syndrome) + return -EINVAL; +#else /* MY_ABC_HERE */ if (new != PARITY_DISABLE_RMW && !raid6_call.xor_syndrome) return -EINVAL; +#endif /* MY_ABC_HERE */ if (new != PARITY_DISABLE_RMW && new != PARITY_ENABLE_RMW && new != PARITY_PREFER_RMW) return -EINVAL; +#ifdef MY_ABC_HERE + if (new == conf->rmw_level) { + return len; + } else if (new != PARITY_DISABLE_RMW) { + mutex_lock(&mddev->syno_rh_mutex); +#ifdef MY_ABC_HERE + if (syno_hint_count(&mddev->syno_rh_tree) || + mddev->syno_enable_requested_resync_hints) { + mutex_unlock(&mddev->syno_rh_mutex); + return -EINVAL; + } +#else /* MY_ABC_HERE */ + if (syno_hint_count(&mddev->syno_rh_tree)) { + mutex_unlock(&mddev->syno_rh_mutex); + return -EINVAL; + } +#endif /* MY_ABC_HERE */ + mddev->syno_allow_fast_rebuild = false; + conf->rmw_level = new; + mutex_unlock(&mddev->syno_rh_mutex); + } else { + mutex_lock(&mddev->syno_rh_mutex); + conf->rmw_level = new; + mddev->syno_allow_fast_rebuild = true; + mutex_unlock(&mddev->syno_rh_mutex); + } +#else /* MY_ABC_HERE */ conf->rmw_level = new; +#endif /* MY_ABC_HERE */ return len; } @@ -6936,6 +8535,821 @@ raid5_group_thread_cnt = __ATTR(group_thread_cnt, S_IRUGO | S_IWUSR, raid5_show_group_thread_cnt, raid5_store_group_thread_cnt); +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_enable_stripe_grow(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_enable_stripe_grow); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_enable_stripe_grow(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + new = !!new; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + conf->syno_enable_stripe_grow = new; + mddev_unlock(mddev); + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_enable_stripe_grow = __ATTR(syno_enable_stripe_grow, S_IRUGO|S_IWUSR, + raid5_show_syno_enable_stripe_grow, raid5_store_syno_enable_stripe_grow); + +static ssize_t +syno_stripe_cache_max_show(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->max_nr_stripes); + spin_unlock(&mddev->lock); + return ret; +} + +static struct md_sysfs_entry +raid5_syno_stripe_cache_max = __ATTR_RO(syno_stripe_cache_max); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_defer_group_cnt(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_defer_group_cnt); + spin_unlock(&mddev->lock); + return ret; +} + +static int alloc_syno_raid5_defer_groups(struct mddev *mddev, + int *group_cnt, struct syno_r5defer **syno_defer_groups); + +static void free_syno_raid5_defer_groups(int group_cnt, + struct syno_r5defer *syno_defer_groups); + +static ssize_t +raid5_store_syno_defer_group_cnt(struct mddev *mddev, const char *page, + size_t len) +{ + struct r5conf *conf; + unsigned int new; + int err; + int old_group_cnt; + struct syno_r5defer *old_groups = NULL; + struct syno_r5defer *new_groups = NULL; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtouint(page, 10, &new)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new <= 0 || new > SYNO_DEFER_GROUP_CNT_MAX || + new > mddev->raid_disks) + err = -EINVAL; + else if (new != conf->syno_defer_group_cnt) { + mddev_suspend(mddev); + + old_groups = conf->syno_defer_groups; + old_group_cnt = conf->syno_defer_group_cnt; + + err = alloc_syno_raid5_defer_groups(mddev, &new, &new_groups); + if (err) { + pr_err("md: %s: failed to change defer groups\n", mdname(mddev)); + } else { + conf->syno_defer_groups = new_groups; + conf->syno_defer_group_cnt = new; + free_syno_raid5_defer_groups(old_group_cnt, old_groups); + + pr_warn("md: %s: change defer groups from %d to %d\n", + mdname(mddev), old_group_cnt, conf->syno_defer_group_cnt); + } + mddev_resume(mddev); + } + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_defer_group_cnt = __ATTR(syno_defer_group_cnt, 0644, + raid5_show_syno_defer_group_cnt, + raid5_store_syno_defer_group_cnt); + +static ssize_t +raid5_show_syno_defer_mode(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_defer_mode); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_defer_mode(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + new = !!new; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (!conf->syno_defer_groups) { + pr_err("md: %s: syno_defer_groups did not allocated, refuse to adjust syno_defer_mode\n", + mdname(mddev)); + err = -ENODEV; + } else if (new != conf->syno_defer_mode) { + mddev_suspend(mddev); + conf->syno_defer_mode = new; + pr_err("md: %s: change defer mode to %d\n", mdname(mddev), + conf->syno_defer_mode); + mddev_resume(mddev); + } + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_defer_mode = __ATTR(syno_defer_mode, 0644, + raid5_show_syno_defer_mode, + raid5_store_syno_defer_mode); + +static ssize_t +raid5_show_syno_defer_flush_threshold(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_defer_flush_threshold); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_defer_flush_threshold(struct mddev *mddev, const char *page, + size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + if (new <= 0 || new > 32768) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + conf->syno_defer_flush_threshold = new; + + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_defer_flush_threshold = __ATTR( + syno_defer_flush_threshold, 0644, + raid5_show_syno_defer_flush_threshold, + raid5_store_syno_defer_flush_threshold); + +static int adjust_syno_raid5_defer_groups(struct mddev *mddev); + +static ssize_t +raid5_show_syno_defer_group_disk_cnt_max(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_defer_group_disk_cnt_max); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_defer_group_disk_cnt_max(struct mddev *mddev, + const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + int old_disk_cnt_max; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + + if (new <= 0 || new > SYNO_DEFER_GROUP_DISK_CNT_MAX) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new != conf->syno_defer_group_disk_cnt_max) { + mddev_suspend(mddev); + old_disk_cnt_max = conf->syno_defer_group_disk_cnt_max; + conf->syno_defer_group_disk_cnt_max = new; + err = adjust_syno_raid5_defer_groups(mddev); + if (err) { + /* restore old value when failed */ + conf->syno_defer_group_disk_cnt_max = old_disk_cnt_max; + } else { + pr_err("md: %s: change defer group disk cnt max to %d\n", + mdname(mddev), conf->syno_defer_group_disk_cnt_max); + } + mddev_resume(mddev); + } + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_defer_group_disk_cnt_max = __ATTR( + syno_defer_group_disk_cnt_max, 0644, + raid5_show_syno_defer_group_disk_cnt_max, + raid5_store_syno_defer_group_disk_cnt_max); + +static ssize_t +raid5_show_syno_defer_flush_batch_size(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_defer_flush_batch_size); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_defer_flush_batch_size(struct mddev *mddev, const char *page, + size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + if (new <= 0 || new > 32768) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + conf->syno_defer_flush_batch_size = new; + + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_defer_flush_batch_size = __ATTR(syno_defer_flush_batch_size, 0644, + raid5_show_syno_defer_flush_batch_size, + raid5_store_syno_defer_flush_batch_size); + +static ssize_t +raid5_show_syno_defer_skip_sort(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_defer_skip_sort); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_defer_skip_sort(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + new = !!new; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + conf->syno_defer_skip_sort = new; + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_defer_skip_sort = __ATTR(syno_defer_skip_sort, 0644, + raid5_show_syno_defer_skip_sort, + raid5_store_syno_defer_skip_sort); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_active_stripe_threshold(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_active_stripe_threshold); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_active_stripe_threshold(struct mddev *mddev, + const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + if (new < 0 || new > 65536) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + conf->syno_active_stripe_threshold = new; + + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_active_stripe_threshold = + __ATTR(syno_active_stripe_threshold, 0644, + raid5_show_syno_active_stripe_threshold, + raid5_store_syno_active_stripe_threshold); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_stat(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) { + u64 syno_stat_wait_sh = conf->syno_stat_wait_sh * 1000; + u64 syno_stat_wait_delay = conf->syno_stat_wait_delay * 1000; + u64 syno_stat_wait_io = conf->syno_stat_wait_io * 1000; + u64 syno_stat_wait_sh_max = conf->syno_stat_wait_sh_max * 1000; + u64 syno_stat_wait_delay_max = conf->syno_stat_wait_delay_max * 1000; + u64 syno_stat_wait_io_max = conf->syno_stat_wait_io_max * 1000; + + do_div(syno_stat_wait_sh, HZ); + do_div(syno_stat_wait_delay, HZ); + do_div(syno_stat_wait_io, HZ); + do_div(syno_stat_wait_sh_max, HZ); + do_div(syno_stat_wait_delay_max, HZ); + do_div(syno_stat_wait_io_max, HZ); + + ret = sprintf(page, "%llu %llu %llu %llu %llu\n" + "%llu %llu %llu %llu\n" + "%llu %llu %llu\n" + "%llu %llu\n" + "%llu %llu %llu\n" + "%llu %llu %llu\n" + "%llu %llu %llu\n", + /* first line - sum latency of handle stripe */ + conf->syno_stat_lat_handle_stripe, + conf->syno_stat_lat_raid_run_ops, + conf->syno_stat_lat_copy_data, + conf->syno_stat_lat_raid_run_ops - + conf->syno_stat_lat_copy_data, + conf->syno_stat_lat_recorded_cnt, + /* second line - max latency of handle stripe */ + conf->syno_stat_lat_handle_stripe_max, + conf->syno_stat_lat_raid_run_ops_max, + conf->syno_stat_lat_copy_data_max, + conf->syno_stat_lat_xor_max, + /* third line - full write stripe */ + conf->syno_stat_total_stripe, + conf->syno_stat_head_stripe_cnt, + conf->syno_stat_full_write, + /* fourth line - rmw,rcw */ + conf->syno_stat_total_stripe - + conf->syno_stat_rcw, + conf->syno_stat_rcw, + /* fifth line - each threads */ + conf->syno_stat_raid5d_handle_cnt, + 0ULL, /* there is no proxy any more */ + conf->syno_stat_r5worker_handle_cnt, + /* sixth line - sum latency of stripe waiting */ + syno_stat_wait_sh, + syno_stat_wait_delay, + syno_stat_wait_io, + /* seventh line - max latency of stripe waiting */ + syno_stat_wait_sh_max, + syno_stat_wait_delay_max, + syno_stat_wait_io_max); + } + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_stat(struct mddev *mddev, + const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + if (new != 0) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else { + conf->syno_stat_rcw = 0; + conf->syno_stat_full_write = 0; + conf->syno_stat_total_stripe = 0; + conf->syno_stat_head_stripe_cnt = 0; + conf->syno_stat_lat_handle_stripe = 0; + conf->syno_stat_lat_raid_run_ops = 0; + conf->syno_stat_lat_copy_data = 0; + conf->syno_stat_lat_handle_stripe_max = 0; + conf->syno_stat_lat_raid_run_ops_max = 0; + conf->syno_stat_lat_copy_data_max = 0; + conf->syno_stat_lat_xor_max = 0; + conf->syno_stat_lat_recorded_cnt = 0; + conf->syno_stat_raid5d_handle_cnt = 0; + conf->syno_stat_r5worker_handle_cnt = 0; + conf->syno_stat_wait_sh = 0; + conf->syno_stat_wait_delay = 0; + conf->syno_stat_wait_io = 0; + conf->syno_stat_wait_sh_max = 0; + conf->syno_stat_wait_delay_max = 0; + conf->syno_stat_wait_io_max = 0; + } + + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_stat = __ATTR(syno_stat, 0644, + raid5_show_syno_stat, + raid5_store_syno_stat); + +static ssize_t +raid5_show_syno_stat_enable_record_time(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_stat_lat_enable); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_stat_enable_record_time(struct mddev *mddev, + const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + new = !!new; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new != conf->syno_stat_lat_enable) + conf->syno_stat_lat_enable = new; + + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_stat_enable_record_time = + __ATTR(syno_stat_enable_record_time, 0644, + raid5_show_syno_stat_enable_record_time, + raid5_store_syno_stat_enable_record_time); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_heal_stripe_cache_size(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_heal_max_nr_stripes); + spin_unlock(&mddev->lock); + + return ret; +} + +int +syno_raid5_heal_set_cache_size(struct mddev *mddev, int size) +{ + int result = 0; + struct r5conf *conf = mddev->private; + + if (size <= 16 || size > mddev->syno_md_heal_record_cnt_max) + return -EINVAL; + + mutex_lock(&conf->syno_heal_cache_size_mutex); + while (size < conf->syno_heal_max_nr_stripes && + syno_raid5_heal_drop_one_stripe(conf)) + ; + mutex_unlock(&conf->syno_heal_cache_size_mutex); + + mutex_lock(&conf->syno_heal_cache_size_mutex); + while (size > conf->syno_heal_max_nr_stripes) + if (!syno_raid5_heal_grow_one_stripe(conf, GFP_KERNEL)) { + result = -ENOMEM; + break; + } + mutex_unlock(&conf->syno_heal_cache_size_mutex); + + return result; +} + +static ssize_t +raid5_store_syno_heal_stripe_cache_size(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + +#if PAGE_SIZE != DEFAULT_STRIPE_SIZE + return -EINVAL; +#endif /* PAGE_SIZE != DEFAULT_STRIPE_SIZE */ + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + + err = mddev_lock(mddev); + if (err) + return err; + + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + err = syno_raid5_heal_set_cache_size(mddev, new); + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_heal_stripe_cache_size = __ATTR( + syno_heal_stripe_cache_size, 0644, + raid5_show_syno_heal_stripe_cache_size, + raid5_store_syno_heal_stripe_cache_size); + +static ssize_t +syno_heal_stripe_cache_active_show(struct mddev *mddev, char *page) +{ + struct r5conf *conf = mddev->private; + + if (conf) + return sprintf(page, "%d\n", atomic_read(&conf->syno_heal_active_stripes)); + else + return 0; +} + +static struct md_sysfs_entry +raid5_syno_heal_stripe_cache_active = __ATTR_RO(syno_heal_stripe_cache_active); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_dummy_read(struct mddev *mddev, char *page) +{ + struct r5conf *conf; + int ret = 0; + + spin_lock(&mddev->lock); + conf = mddev->private; + if (conf) + ret = sprintf(page, "%d\n", conf->syno_dummy_read); + spin_unlock(&mddev->lock); + return ret; +} + +static ssize_t +raid5_store_syno_dummy_read(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf; + unsigned long new; + int err; + + if (len >= PAGE_SIZE) + return -EINVAL; + if (kstrtoul(page, 10, &new)) + return -EINVAL; + new = !!new; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new && ((!conf->syno_dummy_page) || (!conf->syno_dummy_bio))) + err = -ENOMEM; + else + conf->syno_dummy_read = new; + mddev_unlock(mddev); + + return err ?: len; +} + +static struct md_sysfs_entry +raid5_syno_dummy_read = __ATTR(syno_dummy_read, 0644, + raid5_show_syno_dummy_read, + raid5_store_syno_dummy_read); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +syno_allow_rmw_show(struct mddev *mddev, char *page) +{ + struct r5conf *conf = mddev->private; + + if (conf) { + if (conf->level == 6 && !raid6_call.xor_syndrome) + return sprintf(page, "%d\n", 0); + else + return sprintf(page, "%d\n", 1); + } else + return 0; +} + +static struct md_sysfs_entry +raid5_syno_allow_rmw = __ATTR_RO(syno_allow_rmw); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +raid5_show_syno_full_stripe_merge(struct mddev *mddev, char *page) +{ + struct r5conf *conf = mddev->private; + if (conf) + return sprintf(page, "%d\n", conf->syno_full_stripe_merge); + else + return 0; +} + +static ssize_t +raid5_store_syno_full_stripe_merge(struct mddev *mddev, const char *page, size_t len) +{ + struct r5conf *conf = mddev->private; + unsigned long new; + + if (!conf) + return -ENODEV; + + if (len >= PAGE_SIZE) + return -EINVAL; + + if (kstrtoul(page, 10, &new)) + return -EINVAL; + + new = !!new; + + conf->syno_full_stripe_merge = new; + return len; +} + +static struct md_sysfs_entry +raid5_syno_full_stripe_merge = __ATTR(syno_full_stripe_merge, S_IRUGO | S_IWUSR, + raid5_show_syno_full_stripe_merge, + raid5_store_syno_full_stripe_merge); +#endif /* MY_ABC_HERE */ + static struct attribute *raid5_attrs[] = { &raid5_stripecache_size.attr, &raid5_stripecache_active.attr, @@ -6946,6 +9360,38 @@ static struct attribute *raid5_attrs[] = { &raid5_stripe_size.attr, &r5c_journal_mode.attr, &ppl_write_hint.attr, +#ifdef MY_ABC_HERE + &raid5_syno_enable_stripe_grow.attr, + &raid5_syno_stripe_cache_max.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_defer_group_cnt.attr, + &raid5_syno_defer_mode.attr, + &raid5_syno_defer_flush_threshold.attr, + &raid5_syno_defer_group_disk_cnt_max.attr, + &raid5_syno_defer_flush_batch_size.attr, + &raid5_syno_defer_skip_sort.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_active_stripe_threshold.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_stat.attr, + &raid5_syno_stat_enable_record_time.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_heal_stripe_cache_size.attr, + &raid5_syno_heal_stripe_cache_active.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_dummy_read.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_allow_rmw.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &raid5_syno_full_stripe_merge.attr, +#endif /* MY_ABC_HERE */ NULL, }; static struct attribute_group raid5_attrs_group = { @@ -6953,6 +9399,97 @@ static struct attribute_group raid5_attrs_group = { .attrs = raid5_attrs, }; +#ifdef MY_ABC_HERE +static void free_syno_raid5_defer_groups(int group_cnt, + struct syno_r5defer *syno_defer_groups) +{ + int i; + struct syno_r5defer *group; + + if (!syno_defer_groups) + return; + + for (i = 0; i < group_cnt; ++i) { + group = &(syno_defer_groups[i]); + + WARN_ON(group->pending_data_cnt != 0); + WARN_ON(!bio_list_empty(&group->pending_bios)); + WARN_ON(!list_empty(&group->pending_list)); + md_unregister_thread(&group->defer_thread); + kfree(group->pending_data); + group->pending_data = NULL; + } + + kfree(syno_defer_groups); +} + +static int alloc_syno_raid5_defer_groups(struct mddev *mddev, + int *group_cnt, struct syno_r5defer **syno_defer_groups) +{ + int i, j; + int err = 0; + char name[TASK_COMM_LEN]; + struct syno_r5defer *new_groups = NULL; + struct syno_r5defer *group; + + if (*group_cnt <= 0 || *group_cnt > mddev->raid_disks) { + pr_err("%s: bad defer group count: %d, abort\n", + mdname(mddev), *group_cnt); + err = -EINVAL; + goto abort; + } + + if (*group_cnt > SYNO_DEFER_GROUP_CNT_MAX) { + pr_err("%s: bad defer group count: %d, wrap count to %d\n", + mdname(mddev), *group_cnt, SYNO_DEFER_GROUP_CNT_MAX); + *group_cnt = SYNO_DEFER_GROUP_CNT_MAX; + } + + new_groups = kcalloc(*group_cnt, sizeof(struct syno_r5defer), + GFP_NOIO); + if (!new_groups) { + err = -ENOMEM; + goto abort; + } + + for (i = 0; i < *group_cnt; ++i) { + group = &new_groups[i]; + + INIT_LIST_HEAD(&group->free_list); + INIT_LIST_HEAD(&group->pending_list); + bio_list_init(&group->pending_bios); + spin_lock_init(&group->pending_bios_lock); + group->pending_data_cnt = 0; + + group->pending_data = kcalloc(SYNO_MAX_SORT_ENT_CNT, + sizeof(struct r5pending_data), GFP_NOIO); + if (!group->pending_data) { + err = -ENOMEM; + goto abort; + } + for (j = 0; j < SYNO_MAX_SORT_ENT_CNT; ++j) + list_add(&group->pending_data[j].sibling, &group->free_list); + + sprintf(name, "defer%d", i); + group->defer_thread = md_register_thread(syno_flush_deferred_bios, + mddev, name); + if (!group->defer_thread) { + pr_err("%s: failed to create defer_thread\n", mdname(mddev)); + err = -ENOMEM; + goto abort; + } + group->defer_thread->private = group; + } + + *syno_defer_groups = new_groups; + return err; + +abort: + free_syno_raid5_defer_groups(*group_cnt, new_groups); + return err; +} +#endif /* MY_ABC_HERE */ + static int alloc_thread_groups(struct r5conf *conf, int cnt, int *group_cnt, struct r5worker_group **worker_groups) { @@ -7077,6 +9614,9 @@ static void free_conf(struct r5conf *conf) unregister_shrinker(&conf->shrinker); free_thread_groups(conf); shrink_stripes(conf); +#ifdef MY_ABC_HERE + syno_raid5_heal_shrink_stripes(conf); +#endif /* MY_ABC_HERE */ raid5_free_percpu(conf); for (i = 0; i < conf->pool_size; i++) if (conf->disks[i].extra_page) @@ -7085,6 +9625,16 @@ static void free_conf(struct r5conf *conf) bioset_exit(&conf->bio_split); kfree(conf->stripe_hashtbl); kfree(conf->pending_data); +#ifdef MY_ABC_HERE + free_syno_raid5_defer_groups(conf->syno_defer_group_cnt, + conf->syno_defer_groups); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (conf->syno_dummy_page) + put_page(conf->syno_dummy_page); + if (conf->syno_dummy_bio) + bio_put(conf->syno_dummy_bio); +#endif /* MY_ABC_HERE */ kfree(conf); } @@ -7151,27 +9701,82 @@ static unsigned long raid5_cache_count(struct shrinker *shrink, return conf->max_nr_stripes - conf->min_nr_stripes; } +#ifdef MY_ABC_HERE +static void syno_setup_dummy_read(struct r5conf *conf) +{ + int i = 0; + int page_cnt = (conf->chunk_sectors / RAID5_STRIPE_SECTORS(conf)) * 2; + struct mddev *mddev = conf->mddev; + struct bio *bio = bio_alloc_mddev(GFP_NOIO, page_cnt, mddev); + struct page *page = alloc_page(GFP_KERNEL); + + conf->syno_dummy_read = 0; + + if (!page || !bio) { + pr_err("%s: failed to allocate memory for dummy read\n", mdname(mddev)); + goto err; + } + + bio->bi_iter.bi_size = 0; // bio_add_page() will add bi_size + for (i = 0; i < page_cnt; ++i) { + if (bio_add_page(bio, page, RAID5_STRIPE_SIZE(conf), 0) == 0) { + pr_err("%s: failed to add page to bio\n", mdname(mddev)); + goto err; + } + } + + conf->syno_dummy_bio = bio; + conf->syno_dummy_page = page; + return; + +err: + if (bio) + bio_put(bio); + if (page) + put_page(page); +} +#endif /* MY_ABC_HERE */ + static struct r5conf *setup_conf(struct mddev *mddev) { struct r5conf *conf; int raid_disk, memory, max_disks; struct md_rdev *rdev; struct disk_info *disk; +#ifdef MY_ABC_HERE + char pers_name[TASK_COMM_LEN]; +#else /* MY_ABC_HERE */ char pers_name[6]; +#endif /* MY_ABC_HERE */ int i; int group_cnt; struct r5worker_group *new_group; int ret; +#ifdef MY_ABC_HERE + struct syno_r5defer *syno_defer_groups = NULL; + int defer_group_cnt = (mddev->raid_disks - 1) / SYNO_DEFER_GROUP_DISK_CNT_MAX + 1; +#endif /* MY_ABC_HERE */ if (mddev->new_level != 5 && mddev->new_level != 4 +#ifdef MY_ABC_HERE + && mddev->new_level != SYNO_RAID_LEVEL_F1 +#endif /* MY_ABC_HERE */ && mddev->new_level != 6) { +#ifdef MY_ABC_HERE + pr_warn("md/raid:%s: raid level not set to 4/5/6/F1 (%d)\n", +#else /* MY_ABC_HERE */ pr_warn("md/raid:%s: raid level not set to 4/5/6 (%d)\n", +#endif /* MY_ABC_HERE */ mdname(mddev), mddev->new_level); return ERR_PTR(-EIO); } if ((mddev->new_level == 5 && !algorithm_valid_raid5(mddev->new_layout)) || +#ifdef MY_ABC_HERE + (mddev->new_level == SYNO_RAID_LEVEL_F1 + && !algorithm_valid_raid_f1(mddev->new_layout)) || +#endif /* MY_ABC_HERE */ (mddev->new_level == 6 && !algorithm_valid_raid6(mddev->new_layout))) { pr_warn("md/raid:%s: layout %d not supported\n", @@ -7217,6 +9822,30 @@ static struct r5conf *setup_conf(struct mddev *mddev) conf->worker_groups = new_group; } else goto abort; +#ifdef MY_ABC_HERE + conf->syno_defer_mode = 0; + conf->syno_defer_flush_threshold = SYNO_NONROT_FLUSH_THRESHOLD; + conf->syno_defer_flush_batch_size = SYNO_DEFAULT_FLUSH_BATCH; + conf->syno_defer_group_disk_cnt_max = SYNO_DEFER_GROUP_DISK_CNT_MAX; + conf->syno_defer_skip_sort = true; + atomic_set(&conf->syno_active_stripe_workers, 0); + rdev_for_each(rdev, mddev) + if (!blk_queue_nonrot(bdev_get_queue(rdev->bdev))) { + conf->syno_defer_flush_threshold = SYNO_DEFAULT_FLUSH_THRESHOLD; + conf->syno_defer_skip_sort = false; + break; + } + + if (!alloc_syno_raid5_defer_groups(mddev, &defer_group_cnt, + &syno_defer_groups)) { + conf->syno_defer_group_cnt = defer_group_cnt; + conf->syno_defer_groups = syno_defer_groups; + conf->syno_defer_mode = 1; + } else { + conf->syno_defer_groups = NULL; + pr_err("md: %s: syno_defer_groups did not allocated\n", mdname(mddev)); + } +#endif /* MY_ABC_HERE */ spin_lock_init(&conf->device_lock); seqcount_spinlock_init(&conf->gen_lock, &conf->device_lock); mutex_init(&conf->cache_size_mutex); @@ -7228,6 +9857,9 @@ static struct r5conf *setup_conf(struct mddev *mddev) INIT_LIST_HEAD(&conf->hold_list); INIT_LIST_HEAD(&conf->delayed_list); INIT_LIST_HEAD(&conf->bitmap_list); +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&conf->syno_stable_list); +#endif /* MY_ABC_HERE */ init_llist_head(&conf->released_stripes); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); @@ -7339,6 +9971,9 @@ static struct r5conf *setup_conf(struct mddev *mddev) conf->max_degraded = 1; conf->rmw_level = PARITY_ENABLE_RMW; } +#ifdef MY_ABC_HERE + conf->rmw_level = PARITY_DISABLE_RMW; +#endif /* MY_ABC_HERE */ conf->algorithm = mddev->new_layout; conf->reshape_progress = mddev->reshape_position; if (conf->reshape_progress != MaxSector) { @@ -7349,6 +9984,9 @@ static struct r5conf *setup_conf(struct mddev *mddev) conf->prev_algo = conf->algorithm; } +#ifdef MY_ABC_HERE + conf->syno_enable_stripe_grow = 0; +#endif /* MY_ABC_HERE */ conf->min_nr_stripes = NR_STRIPES; if (mddev->reshape_position != MaxSector) { int stripes = max_t(int, @@ -7368,6 +10006,23 @@ static struct r5conf *setup_conf(struct mddev *mddev) goto abort; } else pr_debug("md/raid:%s: allocated %dkB\n", mdname(mddev), memory); +#ifdef MY_ABC_HERE + atomic_set(&conf->syno_heal_active_stripes, 0); + conf->syno_heal_max_nr_stripes = 0; + spin_lock_init(&conf->syno_heal_stripe_lock); + INIT_LIST_HEAD(&conf->syno_heal_free_list); + INIT_LIST_HEAD(&conf->syno_heal_handle_list); + mutex_init(&conf->syno_heal_cache_size_mutex); + init_waitqueue_head(&conf->syno_heal_wait_for_stripe); + + if (!syno_raid5_heal_grow_stripes(conf, SYNO_RAID5_HEAL_STRIPE_DEFAULT_CNT)) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to allocate memory for data correction\n", + mdname(mddev)); + syno_raid5_heal_shrink_stripes(conf); + } +#endif /* MY_ABC_HERE */ /* * Losing a stripe head costs more than the time to refill it, * it reduces the queue depth and so can hurt throughput. @@ -7384,6 +10039,24 @@ static struct r5conf *setup_conf(struct mddev *mddev) goto abort; } +#ifdef MY_ABC_HERE + conf->syno_reshape_failed = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + conf->syno_active_stripe_threshold = SYNO_DEFAULT_ACTIVE_STRIPE_THRESHOLD; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + conf->syno_handle_stripes_cpu = -1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + conf->syno_stat_lat_enable = false; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_setup_dummy_read(conf); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + conf->syno_full_stripe_merge = false; +#endif /* MY_ABC_HERE */ sprintf(pers_name, "raid%d", mddev->new_level); conf->thread = md_register_thread(raid5d, mddev, pers_name); if (!conf->thread) { @@ -7552,8 +10225,14 @@ static int raid5_run(struct mddev *mddev) } else if (mddev->reshape_backwards ? (here_new * chunk_sectors + min_offset_diff <= here_old * chunk_sectors) +#ifdef MY_ABC_HERE + : ((here_new * chunk_sectors >= + here_old * chunk_sectors + (-min_offset_diff)) && + mddev->reshape_position != 0)) { +#else /* MY_ABC_HERE */ : (here_new * chunk_sectors >= here_old * chunk_sectors + (-min_offset_diff))) { +#endif /* MY_ABC_HERE */ /* Reading from the same stripe as writing to - bad */ pr_warn("md/raid:%s: reshape_position too early for auto-recovery - aborting.\n", mdname(mddev)); @@ -7595,6 +10274,12 @@ static int raid5_run(struct mddev *mddev) } conf->min_offset_diff = min_offset_diff; +#ifdef MY_ABC_HERE + mddev->syno_flush_plug_threshold = SYNO_DEFAULT_FLUSH_PLUG_STRIPE_CNT; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev->syno_allow_fast_rebuild = (conf->rmw_level == PARITY_DISABLE_RMW); +#endif /* MY_ABC_HERE */ mddev->thread = conf->thread; conf->thread = NULL; mddev->private = conf; @@ -7656,9 +10341,17 @@ static int raid5_run(struct mddev *mddev) mddev->degraded = raid5_calc_degraded(conf); if (has_failed(conf)) { +#ifdef MY_ABC_HERE + if (mddev->syno_nodev_and_crashed != MD_CRASHED_ASSEMBLE) + mddev->syno_nodev_and_crashed = MD_CRASHED; +#endif /* MY_ABC_HERE */ pr_crit("md/raid:%s: not enough operational devices (%d/%d failed)\n", mdname(mddev), mddev->degraded, conf->raid_disks); +#ifdef MY_ABC_HERE + // Let crashed raid5 array could assemble in boot time. +#else /* MY_ABC_HERE */ goto abort; +#endif /* MY_ABC_HERE */ } /* device size must be a multiple of chunk size */ @@ -7687,7 +10380,11 @@ static int raid5_run(struct mddev *mddev) print_raid5_conf(conf); +#ifdef MY_ABC_HERE + if (conf->reshape_progress != MaxSector && mddev->degraded <= conf->max_degraded) { +#else /* MY_ABC_HERE */ if (conf->reshape_progress != MaxSector) { +#endif /* MY_ABC_HERE */ conf->reshape_safe = conf->reshape_progress; atomic_set(&conf->reshape_stripes, 0); clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); @@ -7769,6 +10466,10 @@ static int raid5_run(struct mddev *mddev) blk_queue_flag_clear(QUEUE_FLAG_DISCARD, mddev->queue); +#ifdef MY_ABC_HERE + blk_queue_flag_set(QUEUE_FLAG_UNUSED_HINT, + mddev->queue); +#endif /* MY_ABC_HERE */ blk_queue_max_hw_sectors(mddev->queue, UINT_MAX); } @@ -7804,7 +10505,13 @@ static void raid5_status(struct seq_file *seq, struct mddev *mddev) rcu_read_lock(); for (i = 0; i < conf->raid_disks; i++) { struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); +#ifdef MY_ABC_HERE + seq_printf(seq, "%s", rdev && test_bit(In_sync, &rdev->flags) + ? (test_bit(SynoDiskError, &rdev->flags) ? "E" : "U") + : "_"); +#else /* MY_ABC_HERE */ seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); +#endif /* MY_ABC_HERE */ } rcu_read_unlock(); seq_printf (seq, "]"); @@ -7842,6 +10549,11 @@ static int raid5_spare_active(struct mddev *mddev) int count = 0; unsigned long flags; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return 0; +#endif /* MY_ABC_HERE */ + for (i = 0; i < conf->raid_disks; i++) { tmp = conf->disks + i; if (tmp->replacement @@ -7867,6 +10579,10 @@ static int raid5_spare_active(struct mddev *mddev) && !test_bit(Faulty, &tmp->rdev->flags) && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { count++; +#ifdef MY_ABC_HERE + if (mddev->syno_enable_requested_resync_hints) + set_bit(SynoNonFullInsync, &tmp->rdev->flags); +#endif /* MY_ABC_HERE */ sysfs_notify_dirent_safe(tmp->rdev->sysfs_state); } } @@ -7962,6 +10678,29 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev) return err; } +#ifdef MY_ABC_HERE +static int raid5_can_assign_disk(struct mddev *mddev, struct r5conf *conf) +{ + int resync_mode = mddev->syno_resync_mode; + + if (conf->level != SYNO_RAID_LEVEL_F1) + return 1; + + if (raid5_calc_degraded(conf) == 0) + return 1; + + if (test_bit(MD_SYNO_RESHAPE_START, &mddev->recovery)) + return 1; + + if (raid5_calc_degraded(conf) != 0 && resync_mode != SYNO_RESYNC_MODE_REPAIR) { + pr_warn("md: %s: refuse to assign disk because md is degraded and do not enable resync\n", + mdname(mddev)); + return 0; + } + + return (resync_mode == SYNO_RESYNC_MODE_REPAIR ? 1 : 0); +} +#endif /* MY_ABC_HERE */ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) { struct r5conf *conf = mddev->private; @@ -7997,6 +10736,11 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) /* no point adding a device */ return -EINVAL; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ + if (rdev->raid_disk >= 0) first = last = rdev->raid_disk; @@ -8012,6 +10756,13 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) for (disk = first; disk <= last; disk++) { p = conf->disks + disk; if (p->rdev == NULL) { +#ifdef MY_ABC_HERE + if (!raid5_can_assign_disk(mddev, conf)) { + pr_warn("md: %s: refuse to assign disk: %s\n", mdname(mddev), + rdev->bdev->bd_disk->disk_name); + continue; + } +#endif /* MY_ABC_HERE */ clear_bit(In_sync, &rdev->flags); rdev->raid_disk = disk; if (rdev->saved_raid_disk != disk) @@ -8025,6 +10776,10 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev) } for (disk = first; disk <= last; disk++) { p = conf->disks + disk; +#ifdef MY_ABC_HERE + if (p == NULL || p->rdev == NULL) + continue; +#endif /* MY_ABC_HERE */ if (test_bit(WantReplacement, &p->rdev->flags) && p->replacement == NULL) { clear_bit(In_sync, &rdev->flags); @@ -8055,6 +10810,10 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors) if (raid5_has_log(conf) || raid5_has_ppl(conf)) return -EINVAL; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ sectors &= ~((sector_t)conf->chunk_sectors - 1); newsize = raid5_size(mddev, sectors, mddev->raid_disks); if (mddev->external_size && @@ -8106,6 +10865,10 @@ static int check_reshape(struct mddev *mddev) if (raid5_has_log(conf) || raid5_has_ppl(conf)) return -EINVAL; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ if (mddev->delta_disks == 0 && mddev->new_layout == mddev->layout && mddev->new_chunk_sectors == mddev->chunk_sectors) @@ -8144,6 +10907,40 @@ static int check_reshape(struct mddev *mddev) + mddev->delta_disks)); } +#ifdef MY_ABC_HERE +static int adjust_syno_raid5_defer_groups(struct mddev *mddev) +{ + int err = 0; + int old_group_cnt, new_group_cnt, disk_cnt_max; + struct syno_r5defer *old_groups = NULL; + struct syno_r5defer *new_groups = NULL; + struct r5conf *conf = mddev->private; + + old_groups = conf->syno_defer_groups; + old_group_cnt = conf->syno_defer_group_cnt; + disk_cnt_max = conf->syno_defer_group_disk_cnt_max; + new_group_cnt = (mddev->raid_disks - 1) / disk_cnt_max + 1; + + if ((new_group_cnt == old_group_cnt) || + (new_group_cnt >= SYNO_DEFER_GROUP_CNT_MAX && + old_group_cnt >= SYNO_DEFER_GROUP_CNT_MAX)) + return 0; + + err = alloc_syno_raid5_defer_groups(mddev, &new_group_cnt, &new_groups); + if (err) { + pr_err("md: %s: failed to adjust defer groups from %d to %d\n", + mdname(mddev), old_group_cnt, new_group_cnt); + return err; + } + + conf->syno_defer_groups = new_groups; + conf->syno_defer_group_cnt = new_group_cnt; + free_syno_raid5_defer_groups(old_group_cnt, old_groups); + + return err; +} +#endif /* MY_ABC_HERE */ + static int raid5_start_reshape(struct mddev *mddev) { struct r5conf *conf = mddev->private; @@ -8172,6 +10969,10 @@ static int raid5_start_reshape(struct mddev *mddev) */ return -EINVAL; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ /* Refuse to reduce size of the array. Any reductions in * array size must be through explicit setting of array_size * attribute. @@ -8183,6 +10984,13 @@ static int raid5_start_reshape(struct mddev *mddev) return -EINVAL; } +#ifdef MY_ABC_HERE + set_bit(MD_SYNO_RESHAPE_START, &mddev->recovery); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mddev_suspend(mddev); +#endif /* MY_ABC_HERE */ + atomic_set(&conf->reshape_stripes, 0); spin_lock_irq(&conf->device_lock); write_seqcount_begin(&conf->gen_lock); @@ -8193,6 +11001,9 @@ static int raid5_start_reshape(struct mddev *mddev) conf->prev_algo = conf->algorithm; conf->algorithm = mddev->new_layout; conf->generation++; +#ifdef MY_ABC_HERE + conf->syno_reshape_failed = 0; +#endif /* MY_ABC_HERE */ /* Code that selects data_offset needs to see the generation update * if reshape_progress has been set - so a memory barrier needed. */ @@ -8205,12 +11016,18 @@ static int raid5_start_reshape(struct mddev *mddev) write_seqcount_end(&conf->gen_lock); spin_unlock_irq(&conf->device_lock); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ /* Now make sure any requests that proceeded on the assumption * the reshape wasn't running - like Discard or Read - have * completed. */ mddev_suspend(mddev); +#ifdef MY_ABC_HERE + adjust_syno_raid5_defer_groups(mddev); +#endif /* MY_ABC_HERE */ mddev_resume(mddev); +#endif /* MY_ABC_HERE */ /* Add some new drives, as many as will fit. * We know there are enough to make the newly sized array work. @@ -8254,8 +11071,17 @@ static int raid5_start_reshape(struct mddev *mddev) clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); clear_bit(MD_RECOVERY_DONE, &mddev->recovery); +#ifdef MY_ABC_HERE + clear_bit(MD_SYNO_RESHAPE_START, &mddev->recovery); +#endif /* MY_ABC_HERE */ set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + adjust_syno_raid5_defer_groups(mddev); +#endif /* MY_ABC_HERE */ + mddev_resume(mddev); +#endif /* MY_ABC_HERE */ mddev->sync_thread = md_register_thread(md_do_sync, mddev, "reshape"); if (!mddev->sync_thread) { @@ -8274,6 +11100,11 @@ static int raid5_start_reshape(struct mddev *mddev) mddev->reshape_position = MaxSector; write_seqcount_end(&conf->gen_lock); spin_unlock_irq(&conf->device_lock); +#ifdef MY_ABC_HERE + mddev_suspend(mddev); + adjust_syno_raid5_defer_groups(mddev); + mddev_resume(mddev); +#endif /* MY_ABC_HERE */ return -EAGAIN; } conf->reshape_checkpoint = jiffies; @@ -8356,6 +11187,9 @@ static void raid5_quiesce(struct mddev *mddev, int quiesce) r5c_flush_cache(conf, INT_MAX); conf->quiesce = 2; wait_event_cmd(conf->wait_for_quiescent, +#ifdef MY_ABC_HERE + atomic_read(&conf->syno_heal_active_stripes) == 0 && +#endif /* MY_ABC_HERE */ atomic_read(&conf->active_stripes) == 0 && atomic_read(&conf->active_aligned_reads) == 0, unlock_all_device_hash_locks_irq(conf), @@ -8401,6 +11235,53 @@ static void *raid45_takeover_raid0(struct mddev *mddev, int level) return setup_conf(mddev); } +#ifdef MY_ABC_HERE +static int raid_f1_check_reshape(struct mddev *mddev) +{ + /* For a 2-drive array, the layout and chunk size can be changed + * immediately as not restriping is needed. + * For larger arrays we record the new value - after validation + * to be used by a reshape pass. + */ + struct r5conf *conf = mddev->private; + int new_chunk = mddev->new_chunk_sectors; + +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ + + if (mddev->new_layout >= 0 && !algorithm_valid_raid_f1(mddev->new_layout)) + return -EINVAL; + if (new_chunk > 0) { + if (!is_power_of_2(new_chunk)) + return -EINVAL; + if (new_chunk < (PAGE_SIZE>>9)) + return -EINVAL; + if (mddev->array_sectors & (new_chunk-1)) + /* not factor of array size */ + return -EINVAL; + } + + /* They look valid */ + + if (mddev->raid_disks == 2) { + /* can make the change immediately */ + if (mddev->new_layout >= 0) { + conf->algorithm = mddev->new_layout; + mddev->layout = mddev->new_layout; + } + if (new_chunk > 0) { + conf->chunk_sectors = new_chunk; + mddev->chunk_sectors = new_chunk; + } + set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags); + md_wakeup_thread(mddev->thread); + } + return check_reshape(mddev); +} +#endif /* MY_ABC_HERE */ + static void *raid5_takeover_raid1(struct mddev *mddev) { int chunksect; @@ -8476,6 +11357,11 @@ static int raid5_check_reshape(struct mddev *mddev) struct r5conf *conf = mddev->private; int new_chunk = mddev->new_chunk_sectors; +#ifdef MY_ABC_HERE + if (syno_is_disk_error_set(mddev)) + return -EINVAL; +#endif /* MY_ABC_HERE */ + if (mddev->new_layout >= 0 && !algorithm_valid_raid5(mddev->new_layout)) return -EINVAL; if (new_chunk > 0) { @@ -8566,6 +11452,13 @@ static void *raid4_takeover(struct mddev *mddev) return ERR_PTR(-EINVAL); } +#ifdef MY_ABC_HERE +static void *raid_f1_takeover(struct mddev *mddev) +{ + return ERR_PTR(-EINVAL); +} +#endif /* MY_ABC_HERE */ + static struct md_personality raid5_personality; static void *raid6_takeover(struct mddev *mddev) @@ -8683,6 +11576,72 @@ static int raid5_start(struct mddev *mddev) return r5l_start(conf->log); } +#ifdef MY_ABC_HERE +static void raid5_adjust_md_threads_node(struct mddev *mddev) +{ + struct r5conf *conf = mddev->private; + int node = mddev->syno_md_thread_fixed_node; + int selected_cpu; + + if (!conf) + return; + + if (-1 == node) { + conf->syno_handle_stripes_cpu = -1; + } else { + selected_cpu = cpumask_any_and(cpumask_of_node(node), cpu_online_mask); + conf->syno_handle_stripes_cpu = selected_cpu < nr_cpu_ids ? selected_cpu : -1; + } +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void raid5_align_chunk_addr_virt_to_dev(struct mddev *mddev, + sector_t virt_start, sector_t virt_end, sector_t* dev_start, + sector_t* dev_end) +{ + struct r5conf *conf = mddev->private; + int stripe_chunks = conf->raid_disks - conf->max_degraded; + sector_t chunk_sectors = conf->chunk_sectors; + sector_t virt_sectors_per_chunk_stripe = chunk_sectors * stripe_chunks; + sector_t chunk_stripe_index, shift_inner_chunk_stripe; + + /** + * For starting address, + * we must check whether the current chunk stripe can be skipped or + * not. If the starting address starts from middle of chunk stripe, + * it cannot be skipped. So we will try to skip the next chunk stripe. + * To check whether the starting address starts from middle, we check + * the remainder is zero or not. + * + * For ending address, + * we need not to do anything more. The unwanted part in last chunk + * stripe will not appear because of integer division. + * + * Finally, we can multiply the chunk stripe index with only one chunk + * size, and we can get the address of the rebulding device. (Each + * device contribute exactly one chunk to a chunk stripe.) + */ + + if (!dev_start && !dev_end) + return; + + if (dev_start) { + chunk_stripe_index = virt_start; + shift_inner_chunk_stripe = sector_div(chunk_stripe_index, + virt_sectors_per_chunk_stripe); + chunk_stripe_index += !!shift_inner_chunk_stripe; + *dev_start = chunk_stripe_index * chunk_sectors; + } + + if (dev_end) { + chunk_stripe_index = virt_end; + sector_div(chunk_stripe_index, virt_sectors_per_chunk_stripe); + *dev_end = chunk_stripe_index * chunk_sectors; + } +} +#endif /* MY_ABC_HERE */ + static struct md_personality raid6_personality = { .name = "raid6", @@ -8693,7 +11652,12 @@ static struct md_personality raid6_personality = .start = raid5_start, .free = raid5_free, .status = raid5_status, +#ifdef MY_ABC_HERE + .syno_error_handler = syno_raid5_error_for_hotplug, + .error_handler = syno_raid5_error_for_internal, +#else /* MY_ABC_HERE */ .error_handler = raid5_error, +#endif /* MY_ABC_HERE */ .hot_add_disk = raid5_add_disk, .hot_remove_disk= raid5_remove_disk, .spare_active = raid5_spare_active, @@ -8706,6 +11670,15 @@ static struct md_personality raid6_personality = .quiesce = raid5_quiesce, .takeover = raid6_takeover, .change_consistency_policy = raid5_change_consistency_policy, +#ifdef MY_ABC_HERE + .adjust_md_threads_node = raid5_adjust_md_threads_node, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .align_chunk_addr_virt_to_dev = raid5_align_chunk_addr_virt_to_dev, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_is_md_max_degrade = syno_raid5_is_max_degrade, +#endif /* MY_ABC_HERE */ }; static struct md_personality raid5_personality = { @@ -8717,7 +11690,12 @@ static struct md_personality raid5_personality = .start = raid5_start, .free = raid5_free, .status = raid5_status, +#ifdef MY_ABC_HERE + .syno_error_handler = syno_raid5_error_for_hotplug, + .error_handler = syno_raid5_error_for_internal, +#else /* MY_ABC_HERE */ .error_handler = raid5_error, +#endif /* MY_ABC_HERE */ .hot_add_disk = raid5_add_disk, .hot_remove_disk= raid5_remove_disk, .spare_active = raid5_spare_active, @@ -8730,6 +11708,15 @@ static struct md_personality raid5_personality = .quiesce = raid5_quiesce, .takeover = raid5_takeover, .change_consistency_policy = raid5_change_consistency_policy, +#ifdef MY_ABC_HERE + .adjust_md_threads_node = raid5_adjust_md_threads_node, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .align_chunk_addr_virt_to_dev = raid5_align_chunk_addr_virt_to_dev, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_is_md_max_degrade = syno_raid5_is_max_degrade, +#endif /* MY_ABC_HERE */ }; static struct md_personality raid4_personality = @@ -8742,7 +11729,12 @@ static struct md_personality raid4_personality = .start = raid5_start, .free = raid5_free, .status = raid5_status, +#ifdef MY_ABC_HERE + .syno_error_handler = syno_raid5_error_for_hotplug, + .error_handler = syno_raid5_error_for_internal, +#else /* MY_ABC_HERE */ .error_handler = raid5_error, +#endif /* MY_ABC_HERE */ .hot_add_disk = raid5_add_disk, .hot_remove_disk= raid5_remove_disk, .spare_active = raid5_spare_active, @@ -8755,8 +11747,744 @@ static struct md_personality raid4_personality = .quiesce = raid5_quiesce, .takeover = raid4_takeover, .change_consistency_policy = raid5_change_consistency_policy, +#ifdef MY_ABC_HERE + .adjust_md_threads_node = raid5_adjust_md_threads_node, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .align_chunk_addr_virt_to_dev = raid5_align_chunk_addr_virt_to_dev, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_is_md_max_degrade = syno_raid5_is_max_degrade, +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static struct md_personality raid_f1_personality = { + .name = "raidF1", + .level = SYNO_RAID_LEVEL_F1, + .owner = THIS_MODULE, + .make_request = raid5_make_request, + .run = raid5_run, + .free = raid5_free, + .status = raid5_status, +#ifdef MY_ABC_HERE + .syno_error_handler = syno_raid5_error_for_hotplug, + .error_handler = syno_raid5_error_for_internal, +#else /* MY_ABC_HERE */ + .error_handler = raid5_error, +#endif /* MY_ABC_HERE */ + .hot_add_disk = raid5_add_disk, + .hot_remove_disk = raid5_remove_disk, + .spare_active = raid5_spare_active, + .sync_request = raid5_sync_request, + .resize = raid5_resize, + .size = raid5_size, + .check_reshape = raid_f1_check_reshape, + .start_reshape = raid5_start_reshape, + .finish_reshape = raid5_finish_reshape, + .quiesce = raid5_quiesce, + .takeover = raid_f1_takeover, + .change_consistency_policy = raid5_change_consistency_policy, +#ifdef MY_ABC_HERE + .adjust_md_threads_node = raid5_adjust_md_threads_node, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .align_chunk_addr_virt_to_dev = raid5_align_chunk_addr_virt_to_dev, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_is_md_max_degrade = syno_raid5_is_max_degrade, +#endif /* MY_ABC_HERE */ +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static const char *syno_raid5_get_bdevname(struct r5conf *conf, int disk_idx, char *buf) +{ + struct md_rdev *rdev = NULL; + + if (!conf || disk_idx < 0 || disk_idx >= conf->raid_disks) + return "null"; + + rdev = rcu_dereference(conf->disks[disk_idx].rdev); + return rdev ? bdevname(rdev->bdev, buf) : "null"; +} + +static void syno_raid5_heal_add_stripe_to_handle_list( + struct r5conf *conf, struct syno_heal_stripe_head *heal_sh) +{ + unsigned long flags; + + spin_lock_irqsave(&conf->syno_heal_stripe_lock, flags); + list_add_tail(&heal_sh->sh_list, &conf->syno_heal_handle_list); + spin_unlock_irqrestore(&conf->syno_heal_stripe_lock, flags); +} + +static void syno_raid5_heal_add_stripe_to_free_list( + struct r5conf *conf, struct syno_heal_stripe_head *heal_sh) +{ + spin_lock_irq(&conf->syno_heal_stripe_lock); + list_add_tail(&heal_sh->sh_list, &conf->syno_heal_free_list); + atomic_dec(&conf->syno_heal_active_stripes); + spin_unlock_irq(&conf->syno_heal_stripe_lock); + + wake_up(&conf->syno_heal_wait_for_stripe); + wake_up(&conf->wait_for_quiescent); +} + +static void syno_raid5_heal_release_stripe(struct syno_heal_stripe_head *heal_sh) +{ + if (atomic_dec_and_test(&heal_sh->count)) { + syno_raid5_heal_add_stripe_to_handle_list(heal_sh->raid_conf, heal_sh); + md_wakeup_thread(heal_sh->raid_conf->mddev->thread); + } +} + +static struct syno_heal_stripe_head *syno_raid5_heal_get_free_stripe( + struct r5conf *conf) +{ + struct list_head *first; + struct syno_heal_stripe_head *heal_sh; + + if (list_empty(&conf->syno_heal_free_list)) + return NULL; + + first = conf->syno_heal_free_list.next; + heal_sh = list_entry(first, struct syno_heal_stripe_head, sh_list); + list_del_init(first); + atomic_set(&heal_sh->count, 1); + atomic_inc(&conf->syno_heal_active_stripes); + + return heal_sh; +} + +static void syno_raid5_heal_free_stripe( + struct kmem_cache *sc, struct syno_heal_stripe_head *heal_sh) +{ + kmem_cache_free(sc, heal_sh); +} + +static void syno_raid5_heal_reset_stripe(struct syno_heal_stripe_head *heal_sh) +{ + int i; + int disks = heal_sh->disks; + + heal_sh->heal_record = NULL; + heal_sh->state = 0; + heal_sh->sh_sector = 0; + heal_sh->dd_idx = heal_sh->pd_idx = heal_sh->qd_idx = heal_sh->ddf_layout = 0; + atomic_set(&heal_sh->count, 0); + + for (i = 0; i < disks; i++) { + struct syno_heal_r5dev *dev = &heal_sh->dev[i]; + + dev->bio.bi_status = BLK_STS_IOERR; + dev->rdev = NULL; + } +} + +static void syno_raid5_heal_shrink_buffers(struct syno_heal_stripe_head *heal_sh) +{ + int i; + int disks = heal_sh->disks; + + for (i = 0; i < disks ; i++) { + struct page *p = heal_sh->dev[i].page; + + if (!p) + continue; + heal_sh->dev[i].page = NULL; + put_page(p); + } +} + +static bool syno_raid5_heal_drop_one_stripe(struct r5conf *conf) +{ + struct syno_heal_stripe_head *heal_sh; + + spin_lock_irq(&conf->syno_heal_stripe_lock); + heal_sh = syno_raid5_heal_get_free_stripe(conf); + spin_unlock_irq(&conf->syno_heal_stripe_lock); + if (!heal_sh) + return false; + + syno_raid5_heal_shrink_buffers(heal_sh); + syno_raid5_heal_free_stripe(conf->syno_heal_slab_cache, heal_sh); + conf->syno_heal_max_nr_stripes--; + atomic_dec(&conf->syno_heal_active_stripes); + return true; +} + +static void syno_raid5_heal_shrink_stripes(struct r5conf *conf) +{ + while (conf->syno_heal_max_nr_stripes && + syno_raid5_heal_drop_one_stripe(conf)) + ; + + kmem_cache_destroy(conf->syno_heal_slab_cache); + conf->syno_heal_slab_cache = NULL; +} + +static bool syno_raid5_heal_grow_buffers( + struct syno_heal_stripe_head *heal_sh, gfp_t gfp) +{ + int i; + int disks = heal_sh->disks; + + for (i = 0; i < disks; i++) { + struct page *page; + + page = alloc_page(gfp); + if (!page) + return false; + + heal_sh->dev[i].page = page; + } + return true; +} + +static struct syno_heal_stripe_head *syno_raid5_heal_alloc_stripe( + struct kmem_cache *sc, gfp_t gfp, int disks, struct r5conf *conf) +{ + int i; + struct syno_heal_stripe_head *heal_sh; + + heal_sh = kmem_cache_zalloc(sc, gfp); + if (heal_sh) { + INIT_LIST_HEAD(&heal_sh->sh_list); + heal_sh->raid_conf = conf; + heal_sh->disks = disks; + atomic_set(&heal_sh->count, 1); + for (i = 0; i < disks; i++) { + struct syno_heal_r5dev *dev = &heal_sh->dev[i]; + + bio_init(&dev->bio, &dev->vec, 1); + dev->rdev = NULL; + } + } + return heal_sh; +} + +static bool syno_raid5_heal_grow_one_stripe(struct r5conf *conf, gfp_t gfp) +{ + struct syno_heal_stripe_head *heal_sh; + + heal_sh = syno_raid5_heal_alloc_stripe( + conf->syno_heal_slab_cache, gfp, conf->pool_size, conf); + if (!heal_sh) + return false; + + if (!syno_raid5_heal_grow_buffers(heal_sh, gfp)) { + syno_raid5_heal_shrink_buffers(heal_sh); + syno_raid5_heal_free_stripe(conf->syno_heal_slab_cache, heal_sh); + return false; + } + + atomic_inc(&conf->syno_heal_active_stripes); + conf->syno_heal_max_nr_stripes++; + syno_raid5_heal_release_stripe(heal_sh); + return true; +} + +static bool syno_raid5_heal_grow_stripes(struct r5conf *conf, int num) +{ +#if PAGE_SIZE != DEFAULT_STRIPE_SIZE + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] page size [%ld] does not match default stripe size [%d], data correction disabled\n", + mdname(conf->mddev), PAGE_SIZE, DEFAULT_STRIPE_SIZE); + conf->syno_heal_slab_cache = NULL; + + return false; +#else /* PAGE_SIZE != DEFAULT_STRIPE_SIZE */ + struct mddev *mddev = conf->mddev; + struct kmem_cache *sc; + size_t namelen = sizeof(conf->syno_heal_cache_name[0]); + int devs = max(conf->raid_disks, conf->previous_raid_disks); + + if (mddev->gendisk) + snprintf(conf->syno_heal_cache_name[0], namelen, + "raid%d-%s-heal", conf->level, mdname(mddev)); + else + snprintf(conf->syno_heal_cache_name[0], namelen, + "raid%d-%p-heal", conf->level, mddev); + snprintf(conf->syno_heal_cache_name[1], namelen, + "%.27s-alt", conf->syno_heal_cache_name[0]); + + conf->syno_heal_active_name = 0; + sc = kmem_cache_create(conf->syno_heal_cache_name[conf->syno_heal_active_name], + sizeof(struct syno_heal_stripe_head)+(devs-1)*sizeof(struct syno_heal_r5dev), + 0, 0, NULL); + if (!sc) + return false; + + conf->syno_heal_slab_cache = sc; + while (num--) + if (!syno_raid5_heal_grow_one_stripe(conf, GFP_KERNEL)) + return false; + + return true; +#endif /* PAGE_SIZE != DEFAULT_STRIPE_SIZE */ +} + +static bool syno_raid5_heal_check_stripe_uptodate( + struct syno_heal_stripe_head *heal_sh) +{ + struct r5conf *conf = heal_sh->raid_conf; + int disks = heal_sh->disks; + int i; + + for (i = 0; i < disks; i++) { + if (heal_sh->dev[i].bio.bi_status) { + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] bio not uptodate at disk [%d] sector [%llu]\n", + mdname(conf->mddev), i, (u64)heal_sh->dev[i].bio.bi_iter.bi_sector); + return false; + } + } + return true; +} + +static addr_conv_t *syno_raid5_heal_to_addr_conv( + int disks, struct raid5_percpu *percpu, int i) +{ + return (void *) (to_addr_page(percpu, i) + disks + 2); +} + +static unsigned int *syno_raid5_heal_to_addr_offs( + int disks, struct raid5_percpu *percpu) +{ + return (unsigned int *)(syno_raid5_heal_to_addr_conv(disks, percpu, 0) + disks + 2); +} + +static bool syno_raid5_heal_can_return_data( + struct bio *master_bio, struct syno_md_heal_record *heal_record) +{ + bool ret = true; + char *msg; + int msg_cnt; + + if (syno_md_heal_record_hash_value(heal_record, master_bio) != 0) { + msg_cnt = heal_record->retry_cnt - 1; + if (heal_record->retry_cnt <= heal_record->max_retry_cnt) { + ret = false; + msg = "get same result, retry next round"; + } else { + msg = "get same result, give up"; + bio_set_flag(master_bio, BIO_CORRECTION_ERR); + } + } else { + msg_cnt = heal_record->retry_cnt; + msg = "return result to upper layer"; + /* in parity mode, we do not pass BIO_CORRECTION_RETRY to underlying device, + * if we add retry_cnt here, we can directly try next round correction if we receive + * BIO_CORRECTION_RETRY again + */ + if (heal_record->retry_cnt != 1) + ++(heal_record->retry_cnt); + } + + syno_md_data_correction_print(heal_record->mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] finished: %s\n", + mdname(heal_record->mddev), (u64)master_bio->bi_iter.bi_sector, + msg_cnt, heal_record->max_retry_cnt, msg); + return ret; +} + +static void syno_raid5_heal_return_master_bio( + struct mddev *mddev, struct bio *master_bio, + struct syno_md_heal_record *heal_record, bool success) +{ + syno_md_heal_put_record(mddev, heal_record); + + if (success) { + master_bio->bi_status = BLK_STS_OK; + } else { + master_bio->bi_status = BLK_STS_IOERR; + bio_set_flag(master_bio, BIO_CORRECTION_ERR); + syno_md_heal_find_and_del_record(mddev, master_bio); + } + bio_endio(master_bio); +} + +static void syno_raid5_heal_compute_data_complete(void *heal_sh_ref) +{ + struct syno_heal_stripe_head *heal_sh = heal_sh_ref; + struct syno_md_heal_record *heal_record = heal_sh->heal_record; + struct bio *master_bio = heal_record->bio; + unsigned int offset_src = master_bio->bi_iter.bi_sector + % RAID5_STRIPE_SECTORS(heal_sh->raid_conf); + unsigned int offset_dst = bio_offset(master_bio); + char *pa_src = page_address(heal_sh->dev[heal_sh->dd_idx].page); + char *pa_dst = kmap_atomic(bio_page(master_bio)); + + memcpy(pa_dst + offset_dst, + pa_src + offset_src, + bio_iter_len(master_bio, master_bio->bi_iter)); + + kunmap_atomic(pa_dst); + syno_raid5_heal_release_stripe(heal_sh); +} + +static void syno_raid5_heal_ops_compute( + struct syno_heal_stripe_head *heal_sh, struct raid5_percpu *percpu) +{ + struct r5conf *conf = heal_sh->raid_conf; + int i; + int count = 0; + int disks = heal_sh->disks; + int dd_idx = heal_sh->dd_idx; + int pd_idx = heal_sh->pd_idx; + int qd_idx = heal_sh->qd_idx; + int retry_cnt = heal_sh->heal_record->retry_cnt; + int max_retry_cnt = heal_sh->heal_record->max_retry_cnt; + struct page **src_page = to_addr_page(percpu, 0); + struct page *dst_page; + struct dma_async_tx_descriptor *tx; + struct async_submit_ctl submit; + + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] choose %s-disk\n", + mdname(conf->mddev), (u64)heal_sh->heal_record->bio->bi_iter.bi_sector, + retry_cnt, max_retry_cnt, + (retry_cnt == 2 ? "p" : (retry_cnt == 3 ? "q" : "d"))); + + if (retry_cnt == 2) { + init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_ZERO_DST, NULL, + syno_raid5_heal_compute_data_complete, + heal_sh, syno_raid5_heal_to_addr_conv(disks, percpu, 0)); + + dst_page = heal_sh->dev[dd_idx].page; + for (i = 0; i < disks; i++) { + if (i != dd_idx && i != qd_idx) + src_page[count++] = heal_sh->dev[i].page; + } + tx = async_xor(dst_page, src_page, 0, count, RAID5_STRIPE_SIZE(conf), &submit); + } else if (retry_cnt == 3) { + /* reference ops_run_compute6_2(): We're missing D+P */ + int d0_idx; + int faila = -1, failb = -1, count = 0; + int syndrome_disks = heal_sh->ddf_layout ? disks : disks-2; + struct stripe_head sh; + unsigned int *offs = syno_raid5_heal_to_addr_offs(disks, percpu); + + WARN_ON(conf->level == 5); + + sh.disks = disks; + sh.pd_idx = pd_idx; + sh.qd_idx = qd_idx; + sh.ddf_layout = heal_sh->ddf_layout; + d0_idx = raid6_d0(&sh); + + for (i = 0; i < disks ; i++) { + offs[i] = 0; + src_page[i] = NULL; + } + + i = d0_idx; + do { + int slot = raid6_idx_to_slot(i, &sh, &count, syndrome_disks); + + src_page[slot] = heal_sh->dev[i].page; + if (i == dd_idx) + faila = slot; + if (i == pd_idx) + failb = slot; + i = raid6_next_disk(i, disks); + } while (i != d0_idx); + + if (failb < faila) + swap(faila, failb); + + WARN_ON(failb != syndrome_disks); + + init_async_submit(&submit, ASYNC_TX_FENCE, NULL, + syno_raid5_heal_compute_data_complete, + heal_sh, syno_raid5_heal_to_addr_conv(disks, percpu, 0)); + tx = async_raid6_datap_recov(syndrome_disks+2, RAID5_STRIPE_SIZE(conf), + faila, src_page, offs, &submit); + } else { + syno_raid5_heal_compute_data_complete(heal_sh); + } +} + +static void syno_raid5_heal_compute_data(struct syno_heal_stripe_head *heal_sh) +{ + unsigned long cpu; + struct raid5_percpu *percpu; + struct r5conf *conf = heal_sh->raid_conf; + + set_bit(HEAL_STRIPE_COMPUTE_RUN, &heal_sh->state); + atomic_inc(&heal_sh->count); + + if (!syno_raid5_heal_check_stripe_uptodate(heal_sh)) + goto abort; + + cpu = get_cpu(); + percpu = per_cpu_ptr(conf->percpu, cpu); + syno_raid5_heal_ops_compute(heal_sh, percpu); + put_cpu(); + + return; +abort: + set_bit(HEAL_STRIPE_ERROR, &heal_sh->state); + syno_raid5_heal_release_stripe(heal_sh); +} + +static void syno_raid5_heal_check_master_data(struct syno_heal_stripe_head *heal_sh) +{ + struct r5conf *conf = heal_sh->raid_conf; + struct mddev *mddev = conf->mddev; + struct syno_md_heal_record *heal_record = heal_sh->heal_record; + struct bio *master_bio = heal_record->bio; + + if (syno_raid5_heal_can_return_data(master_bio, heal_record)) { + if (bio_flagged(master_bio, BIO_CORRECTION_ERR)) + syno_raid5_heal_return_master_bio(mddev, master_bio, heal_record, false); + else + syno_raid5_heal_return_master_bio(mddev, master_bio, heal_record, true); + syno_raid5_heal_reset_stripe(heal_sh); + syno_raid5_heal_add_stripe_to_free_list(conf, heal_sh); + } else { + set_bit(HEAL_STRIPE_IO_STARTED, &heal_sh->state); + syno_raid5_heal_add_stripe_to_handle_list(conf, heal_sh); + md_wakeup_thread(mddev->thread); + } +} + +static void syno_raid5_heal_handle_stripe(struct r5conf *conf) +{ + struct mddev *mddev = conf->mddev; + struct syno_heal_stripe_head *heal_sh; + struct syno_heal_stripe_head *tmp_sh; + LIST_HEAD(handle_list); + + spin_lock_irq(&conf->syno_heal_stripe_lock); + if (!list_empty(&conf->syno_heal_handle_list)) + list_replace_init(&conf->syno_heal_handle_list, &handle_list); + spin_unlock_irq(&conf->syno_heal_stripe_lock); + + list_for_each_entry_safe(heal_sh, tmp_sh, &handle_list, sh_list) { + list_del_init(&heal_sh->sh_list); + if (test_and_clear_bit(HEAL_STRIPE_ERROR, &heal_sh->state)) { + syno_raid5_heal_return_master_bio( + mddev, heal_sh->heal_record->bio, heal_sh->heal_record, false); + syno_raid5_heal_reset_stripe(heal_sh); + syno_raid5_heal_add_stripe_to_free_list(conf, heal_sh); + } else if (test_and_clear_bit(HEAL_STRIPE_IO_STARTED, &heal_sh->state)) { + syno_raid5_heal_compute_data(heal_sh); + } else if (test_and_clear_bit(HEAL_STRIPE_COMPUTE_RUN, &heal_sh->state)) { + syno_raid5_heal_check_master_data(heal_sh); + } else { + syno_raid5_heal_reset_stripe(heal_sh); + syno_raid5_heal_add_stripe_to_free_list(conf, heal_sh); + } + } +} + +static void syno_raid5_heal_end_request(struct bio *bio) +{ + struct md_rdev *rdev; + struct syno_heal_stripe_head *heal_sh = bio->bi_private; + struct r5conf *conf = heal_sh->raid_conf; + int disks = heal_sh->disks; + int i; + + for (i = 0; i < disks; i++) + if (bio == &heal_sh->dev[i].bio) + break; + + if (i == disks) { + syno_md_data_correction_print(conf->mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to find dev bio at sector [%llu] for master bio [%llu]\n", + mdname(conf->mddev), (u64)bio->bi_iter.bi_sector, + (u64)heal_sh->heal_record->bio->bi_iter.bi_sector); + set_bit(HEAL_STRIPE_ERROR, &heal_sh->state); + goto abort; + } + + /* it should be fine if we do not take rcu_read_lock() here, + * since we already added count before I/O. + */ + rdev = heal_sh->dev[i].rdev; + rdev_dec_pending(rdev, conf->mddev); + +abort: + syno_raid5_heal_release_stripe(heal_sh); +} + +static void syno_raid5_heal_submit_heal_sh( + struct r5conf *conf, struct syno_heal_stripe_head *heal_sh) +{ + int i; + int disks = heal_sh->disks; + + set_bit(HEAL_STRIPE_IO_STARTED, &heal_sh->state); + + for (i = disks; i--; ) { + struct bio *bio; + struct md_rdev *rdev; + + rcu_read_lock(); + rdev = rcu_dereference(conf->disks[i].rdev); + if (!rdev || test_bit(Faulty, &rdev->flags)) { + rcu_read_unlock(); + continue; + } + + bio = &heal_sh->dev[i].bio; + bio_reset(bio); + /* pass BIO_CORRECTION_RETRY to underlying device, + * since it might have the ability of data correction. + * but we do not pass BIO_CORRECTION_RETRY in parity mode. + */ + if (heal_sh->heal_record->retry_cnt == 1) + bio_set_flag(bio, BIO_CORRECTION_RETRY); + heal_sh->dev[i].vec.bv_page = heal_sh->dev[i].page; + heal_sh->dev[i].rdev = rdev; + bio_set_dev(bio, rdev->bdev); + bio->bi_iter.bi_sector = heal_sh->sh_sector + rdev->data_offset; + bio->bi_end_io = syno_raid5_heal_end_request; + bio->bi_opf = REQ_OP_READ; + bio->bi_private = heal_sh; + bio->bi_vcnt = 1; + bio->bi_io_vec[0].bv_len = RAID5_STRIPE_SIZE(conf); + bio->bi_io_vec[0].bv_offset = 0; + bio->bi_iter.bi_size = RAID5_STRIPE_SIZE(conf); + bio->bi_write_hint = heal_sh->heal_record->bio->bi_write_hint; + + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + atomic_inc(&heal_sh->count); + + submit_bio_noacct(bio); + } + + syno_raid5_heal_release_stripe(heal_sh); +} + +static void syno_raid5_heal_handle_bio(struct r5conf *conf, + struct bio *master_bio, struct syno_md_heal_record *heal_record) +{ + int dd_idx; + int max_retry_cnt; + char d_buf[BDEVNAME_SIZE]; + char p_buf[BDEVNAME_SIZE]; + char q_buf[BDEVNAME_SIZE]; + struct mddev *mddev = conf->mddev; + struct syno_heal_stripe_head *heal_sh; + struct stripe_head sh_role; + sector_t logical_sector, last_sector; + sector_t sh_sector; + DEFINE_WAIT(w); + signed long timeout = msecs_to_jiffies(180 * 1000); + + max_retry_cnt = heal_record->max_retry_cnt; + if (max_retry_cnt < heal_record->retry_cnt) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] reach max retry count: request_cnt [%d]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, max_retry_cnt, heal_record->request_cnt); + goto abort; + } + + logical_sector = master_bio->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1); + last_sector = bio_end_sector(master_bio); + sh_sector = raid5_compute_sector(conf, logical_sector, 0, &dd_idx, &sh_role); + + rcu_read_lock(); + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_WARNING, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] start: logical-sector [%llu], sh-sector [%llu], d-disk [%d:%s], p-disk [%d:%s], q-disk [%d:%s]\n", + mdname(mddev), (u64)master_bio->bi_iter.bi_sector, + heal_record->retry_cnt, max_retry_cnt, + (u64)logical_sector, (u64)sh_sector, + dd_idx, syno_raid5_get_bdevname(conf, dd_idx, d_buf), + sh_role.pd_idx, syno_raid5_get_bdevname(conf, sh_role.pd_idx, p_buf), + sh_role.qd_idx, syno_raid5_get_bdevname(conf, sh_role.qd_idx, q_buf)); + rcu_read_unlock(); + +retry: + syno_raid5_lock_device_heal_lock(conf); + wait_event_cmd(conf->wait_for_quiescent, + conf->quiesce == 0, + syno_raid5_unlock_device_heal_lock(conf), + syno_raid5_lock_device_heal_lock(conf)); + + heal_sh = syno_raid5_heal_get_free_stripe(conf); + if (!heal_sh) { + syno_raid5_unlock_device_heal_lock(conf); + + prepare_to_wait(&conf->syno_heal_wait_for_stripe, &w, TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + finish_wait(&conf->syno_heal_wait_for_stripe, &w); + + if (timeout == 0) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] round [%d/%d] failed to get stripe\n", + mdname(mddev), (u64)logical_sector, heal_record->retry_cnt, max_retry_cnt); + goto abort; + } + goto retry; + } + syno_raid5_unlock_device_heal_lock(conf); + + heal_sh->sh_sector = sh_sector; + heal_sh->dd_idx = dd_idx; + heal_sh->pd_idx = sh_role.pd_idx; + heal_sh->qd_idx = sh_role.qd_idx; + heal_sh->ddf_layout = sh_role.ddf_layout; + heal_sh->heal_record = heal_record; + syno_raid5_heal_submit_heal_sh(conf, heal_sh); + + return; +abort: + syno_raid5_heal_return_master_bio(mddev, master_bio, heal_record, false); +} + +static void syno_raid5_heal_read_request(struct mddev *mddev, struct bio *bio) +{ + struct r5conf *conf = mddev->private; + int max_retry_cnt = (conf->level == 6 ? 3 : 2); + struct syno_md_heal_record *heal_record; + sector_t logical_sector, last_sector; + + /* our system should only submit a 4k correction bio, + * and our system should be 4k-aligned, + * so we simply refuse unexpected correction bio. + */ + logical_sector = bio->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1); + last_sector = bio_end_sector(bio); + if (last_sector - logical_sector > RAID5_STRIPE_SECTORS(conf)) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] retry sector [%llu] not aligned: logical sector [%llu], last sector [%llu], stripe sector [%llu]\n", + mdname(mddev), (u64)bio->bi_iter.bi_sector, + (u64)logical_sector, (u64)last_sector, (u64)RAID5_STRIPE_SECTORS(conf)); + goto abort; + } + + heal_record = syno_md_heal_get_record(mddev, bio, max_retry_cnt); + if (!heal_record) { + syno_md_data_correction_print(mddev->syno_md_data_correction_log_flag, + KERN_ERR, + "%s: [Self Heal] failed to get record at sector [%llu]\n", + mdname(mddev), (u64)bio->bi_iter.bi_sector); + goto abort; + } + syno_raid5_heal_handle_bio(conf, bio, heal_record); + + return; +abort: + syno_raid5_heal_return_master_bio(mddev, bio, heal_record, false); +} +#endif /* MY_ABC_HERE */ + static int __init raid5_init(void) { int ret; @@ -8777,6 +12505,9 @@ static int __init raid5_init(void) register_md_personality(&raid6_personality); register_md_personality(&raid5_personality); register_md_personality(&raid4_personality); +#ifdef MY_ABC_HERE + register_md_personality(&raid_f1_personality); +#endif /* MY_ABC_HERE */ return 0; } @@ -8785,6 +12516,9 @@ static void raid5_exit(void) unregister_md_personality(&raid6_personality); unregister_md_personality(&raid5_personality); unregister_md_personality(&raid4_personality); +#ifdef MY_ABC_HERE + unregister_md_personality(&raid_f1_personality); +#endif /* MY_ABC_HERE */ cpuhp_remove_multi_state(CPUHP_MD_RAID5_PREPARE); destroy_workqueue(raid5_wq); } @@ -8801,6 +12535,10 @@ MODULE_ALIAS("md-level-4"); MODULE_ALIAS("md-personality-8"); /* RAID6 */ MODULE_ALIAS("md-raid6"); MODULE_ALIAS("md-level-6"); +#ifdef MY_ABC_HERE +MODULE_ALIAS("md-raidF1"); +MODULE_ALIAS("md-level-45"); +#endif /* MY_ABC_HERE */ /* This used to be two separate modules, they were: */ MODULE_ALIAS("raid5"); diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 5c05acf20e1f..7fcf8f3b422c 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _RAID5_H #define _RAID5_H @@ -254,6 +257,36 @@ struct stripe_head { int nr_pages; /* page array size */ int stripes_per_page; #endif +#ifdef MY_ABC_HERE + int syno_stat_batched_len; + /** + * we recored overhead of three function for raid5 cpu time analysis (ns) + * |------------------------ handle_stripe --------------------------------| + * |-------------------- raid_run_ops -------------|------- others --------| + * |--- async_copy_data (sync) ---|---- others ----| + * Since raid_run_ops mainly only do data copy and parity computation, the + * overhead of parity computation could be easily derived. + */ + u64 syno_stat_lat_handle_stripe; + u64 syno_stat_lat_raid_run_ops; + u64 syno_stat_lat_copy_data; + /** + * we recored two mainly waiting time for raid5 stripe latency analysis (ticks) + * |------------------------------ sh -------------------------------------| + * |------------ delay -----------------|------- io --------------------|..| + */ + u64 syno_stat_wait_sh_start; + u64 syno_stat_wait_delay_start; + u64 syno_stat_wait_io_start; + u64 syno_stat_wait_delay; + u64 syno_stat_wait_io; + bool syno_stat_lat_enable:1; + bool syno_stat_is_rcw:1; + bool syno_stat_is_full_write:1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned long syno_full_stripe_merge_state; +#endif /* MY_ABC_HERE */ struct r5dev { /* rreq and rvec are used for the replacement device when * writing data to both devices. @@ -293,6 +326,12 @@ struct stripe_head_state { int handle_bad_blocks; int log_failed; int waiting_extra_page; +#ifdef MY_ABC_HERE + int syno_full_stripe_merging; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool syno_force_stripe_rcw; +#endif /* MY_ABC_HERE */ }; /* Flags for struct r5dev.flags */ @@ -343,6 +382,9 @@ enum r5dev_flags { * set, orig_page contains latest data in the * raid disk. */ +#ifdef MY_ABC_HERE + R5_SynoAutoRemaped, +#endif /* MY_ABC_HERE */ }; /* @@ -398,6 +440,12 @@ enum { * in conf->r5c_full_stripe_list) */ STRIPE_R5C_PREFLUSH, /* need to flush journal device */ +#ifdef MY_ABC_HERE + STRIPE_SYNO_STABLE_STATE, /* finished xor and ready to write back */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + STRIPE_SYNO_NORETRY, +#endif /* MY_ABC_HERE */ }; #define STRIPE_EXPAND_SYNC_FLAGS \ @@ -502,6 +550,13 @@ struct disk_info { #define NR_STRIPE_HASH_LOCKS 8 #define STRIPE_HASH_LOCKS_MASK (NR_STRIPE_HASH_LOCKS - 1) +#ifdef MY_ABC_HERE +#define SYNO_DEFAULT_FLUSH_PLUG_STRIPE_CNT 128 +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define SYNO_DEFAULT_ACTIVE_STRIPE_THRESHOLD 1024 +#endif /* MY_ABC_HERE */ + struct r5worker { struct work_struct work; struct r5worker_group *group; @@ -557,8 +612,37 @@ struct r5pending_data { struct list_head sibling; sector_t sector; /* stripe sector */ struct bio_list bios; +#ifdef MY_ABC_HERE + int count; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +#define SYNO_MAX_SORT_ENT_CNT 512 +#define SYNO_DEFAULT_FLUSH_THRESHOLD 2048 +#define SYNO_NONROT_FLUSH_THRESHOLD 64 +#define SYNO_DEFAULT_FLUSH_BATCH 512 +#define SYNO_DEFER_GROUP_CNT_MAX 6 +#define SYNO_DEFER_GROUP_DISK_CNT_MAX 4 + +enum r5defer_flags { + SYNO_DEFER_FLUSH_ALL, /* flush all bio when all stripe have + * been handled + */ +}; + +struct syno_r5defer { + struct list_head free_list; + struct list_head pending_list; + spinlock_t pending_bios_lock; + unsigned long state; + int pending_data_cnt; + struct bio_list pending_bios; + struct r5pending_data *pending_data; + struct md_thread *defer_thread; +}; +#endif /* MY_ABC_HERE */ + struct r5conf { struct hlist_head *stripe_hashtbl; /* only protect corresponding hash list and inactive_list */ @@ -689,6 +773,81 @@ struct r5conf { struct list_head pending_list; int pending_data_cnt; struct r5pending_data *next_pending_data; + +#ifdef MY_ABC_HERE + unsigned char syno_enable_stripe_grow; /* Don't allow stripe grow automatic */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* I/O hits a stripe that finished compute parity and ready to write back to disks, + * thus this stripe cannot do preread and will be added into delayed_list. In this + * case, we add this stripe into our syno_stable_list instead, we mostly want to + * prevent direct I/O from high latency. + */ + struct list_head syno_stable_list; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_defer_flush_threshold; + int syno_defer_mode; + int syno_defer_group_cnt; + struct syno_r5defer *syno_defer_groups; + int syno_defer_group_disk_cnt_max; + int syno_defer_flush_batch_size; + atomic_t syno_active_stripe_workers; + bool syno_defer_skip_sort; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned char syno_reshape_failed; /* record when reshape failed */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_active_stripe_threshold; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_handle_stripes_cpu; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + atomic_t syno_heal_active_stripes; + int syno_heal_max_nr_stripes; + int syno_heal_active_name; + char syno_heal_cache_name[2][32]; + struct kmem_cache *syno_heal_slab_cache; + spinlock_t syno_heal_stripe_lock; + struct list_head syno_heal_free_list; + struct list_head syno_heal_handle_list; + struct mutex syno_heal_cache_size_mutex; /* Protect changes to cache size */ + wait_queue_head_t syno_heal_wait_for_stripe; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* histogram of batched length and io cnt */ + u64 syno_stat_rcw; + u64 syno_stat_full_write; + u64 syno_stat_total_stripe; + u64 syno_stat_head_stripe_cnt; + u64 syno_stat_lat_handle_stripe; + u64 syno_stat_lat_raid_run_ops; + u64 syno_stat_lat_copy_data; + u64 syno_stat_lat_handle_stripe_max; + u64 syno_stat_lat_raid_run_ops_max; + u64 syno_stat_lat_copy_data_max; + u64 syno_stat_lat_xor_max; + u64 syno_stat_wait_sh; + u64 syno_stat_wait_delay; + u64 syno_stat_wait_io; + u64 syno_stat_wait_sh_max; + u64 syno_stat_wait_delay_max; + u64 syno_stat_wait_io_max; + u64 syno_stat_lat_recorded_cnt; + u64 syno_stat_raid5d_handle_cnt; + u64 syno_stat_r5worker_handle_cnt; + bool syno_stat_lat_enable:1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int syno_dummy_read; + struct bio *syno_dummy_bio; + struct page *syno_dummy_page; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool syno_full_stripe_merge; +#endif /* MY_ABC_HERE */ }; #if PAGE_SIZE == DEFAULT_STRIPE_SIZE @@ -760,6 +919,24 @@ static inline struct bio *r5_next_bio(struct r5conf *conf, struct bio *bio, sect #define ALGORITHM_PARITY_0_6 20 #define ALGORITHM_PARITY_N_6 ALGORITHM_PARITY_N +#ifdef MY_ABC_HERE +/* For Synology RAID F1, define new layout as follow */ +#define ALGORITHM_RAID_F1_0 ALGORITHM_LEFT_SYMMETRIC +#define ALGORITHM_RAID_F1_1 32 +#define ALGORITHM_RAID_F1_2 33 +#define ALGORITHM_RAID_F1_3 34 +#define ALGORITHM_RAID_F1_4 35 + +#define ALGORITHM_RAID_F1 ALGORITHM_RAID_F1_1 + +static inline int algorithm_valid_raid_f1(int layout) +{ + return layout == ALGORITHM_RAID_F1_0 || + ((layout >= ALGORITHM_RAID_F1_1) && + (layout <= ALGORITHM_RAID_F1_4)); +} +#endif /* MY_ABC_HERE */ + static inline int algorithm_valid_raid5(int layout) { return (layout >= 0) && @@ -798,6 +975,36 @@ raid5_get_dev_page(struct stripe_head *sh, int disk_idx) } #endif +#ifdef MY_ABC_HERE +#define SYNO_RAID5_HEAL_STRIPE_DEFAULT_CNT 256 + +enum { + HEAL_STRIPE_NONE = 0, + HEAL_STRIPE_ERROR, + HEAL_STRIPE_IO_STARTED, + HEAL_STRIPE_COMPUTE_RUN, +}; + +struct syno_heal_stripe_head { + struct list_head sh_list; + unsigned long state; + sector_t sh_sector; + short dd_idx; + short pd_idx; + short qd_idx; + short ddf_layout; + atomic_t count; + int disks; + struct r5conf *raid_conf; + struct syno_md_heal_record *heal_record; + struct syno_heal_r5dev { + struct bio bio; + struct bio_vec vec; + struct page *page; + struct md_rdev *rdev; + } dev[1]; /* allocated with extra space depending of RAID geometry */ +}; +#endif /* MY_ABC_HERE */ extern void md_raid5_kick_device(struct r5conf *conf); extern int raid5_set_cache_size(struct mddev *mddev, int size); extern sector_t raid5_compute_blocknr(struct stripe_head *sh, int i, int previous); @@ -810,4 +1017,21 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector, int previous, int noblock, int noquiesce); extern int raid5_calc_degraded(struct r5conf *conf); extern int r5c_journal_mode_set(struct mddev *mddev, int journal_mode); +#ifdef MY_ABC_HERE +static inline int md_raid_f1_uneven_count(int algorithm) +{ + return (algorithm == ALGORITHM_RAID_F1_0 ? 0 : algorithm - ALGORITHM_RAID_F1_1 + 1); +} +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define SYNO_FULL_STRIPE_MERGE_DENOMINATOR 16 +/* + * Full stripe merge state + */ +enum { + SYNO_FULL_STRIPE_MERGE, + SYNO_FULL_STRIPE_MERGING, + SYNO_FULL_STRIPE_MERGE_DO_WRITE, +}; +#endif /* MY_ABC_HERE */ #endif diff --git a/drivers/md/syno-md-fast-wakeup.h b/drivers/md/syno-md-fast-wakeup.h new file mode 100644 index 000000000000..5df2e01c5f79 --- /dev/null +++ b/drivers/md/syno-md-fast-wakeup.h @@ -0,0 +1,56 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* SPDX-License-Identifier: GPL-2.0-or-later */ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. +#ifndef _SYNO_MD_FAST_WAKEUP_H +#define _SYNO_MD_FAST_WAKEUP_H + +#ifdef MY_ABC_HERE +#include +#include +#include + +#define SYNO_FAST_WAKEUP_CHECK_INTERVAL (7UL*HZ) + +struct syno_md_fast_wakeup_work { + void *mddev; + struct work_struct work; +}; + +struct syno_md_fast_wakeup_info { + bool active; + spinlock_t active_lock; + unsigned long last_req; +}; + +static inline void syno_md_fast_wakeup_info_init( + struct syno_md_fast_wakeup_info *winfo) +{ + spin_lock_init(&winfo->active_lock); + winfo->active = true; + winfo->last_req = jiffies; +} + +static inline bool syno_md_fast_wakeup_info_update( + struct syno_md_fast_wakeup_info *winfo) +{ + bool need_wakeup = false; + unsigned long req_jiffies = jiffies; + + if (time_after(req_jiffies, + winfo->last_req + SYNO_FAST_WAKEUP_CHECK_INTERVAL)) { + spin_lock(&winfo->active_lock); + if (!winfo->active) + need_wakeup = true; + winfo->active = true; + spin_unlock(&winfo->active_lock); + } + winfo->last_req = req_jiffies; + + return need_wakeup; +} + +#endif /* MY_ABC_HERE */ + +#endif /* _SYNO_MD_FAST_WAKEUP_H */ diff --git a/drivers/md/syno-md-hint.c b/drivers/md/syno-md-hint.c new file mode 100644 index 000000000000..344ff14d5ff6 --- /dev/null +++ b/drivers/md/syno-md-hint.c @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ + +#include +#include + +#include "syno-md-hint.h" + +static struct kmem_cache *syno_md_hint_cache; + +int syno_hint_add(struct syno_hint_tree *tree, sector_t h_start, + sector_t h_end, gfp_t gfp_mask) +{ + struct rb_root_cached *root = &tree->root; + struct rb_node **link = &root->rb_root.rb_node; + struct rb_node *parent = NULL; + struct syno_hint *new; + bool leftmost = true; + + while (*link) { + struct syno_hint *curr; + + parent = *link; + curr = rb_entry(parent, struct syno_hint, node); + + if (h_start < curr->h_start) { + link = &(*link)->rb_left; + } else if (h_start > curr->h_start) { + if (h_start <= curr->h_end) { + curr->h_end = max(curr->h_end, h_end); + return 0; + } + link = &(*link)->rb_right; + leftmost = false; + } else { + curr->h_end = max(curr->h_end, h_end); + return 0; + } + } + if (tree->count == tree->max_count) + return -ENOMEM; + new = kmem_cache_zalloc(syno_md_hint_cache, gfp_mask); + if (!new) + return -ENOMEM; + new->h_start = h_start; + new->h_end = h_end; + tree->count++; + + /* Add new node and rebalance tree. */ + rb_link_node(&new->node, parent, link); + rb_insert_color_cached(&new->node, root, leftmost); + + return 0; +} + +void syno_hint_remove(struct syno_hint_tree *tree, struct syno_hint *hint) +{ + rb_erase_cached(&hint->node, &tree->root); + tree->count--; +} + +void syno_hint_free(struct syno_hint *hint) +{ + kmem_cache_free(syno_md_hint_cache, hint); +} + +struct syno_hint *syno_hint_first(struct syno_hint_tree *tree) +{ + struct rb_node *first = rb_first_cached(&tree->root); + + return first ? rb_entry(first, struct syno_hint, node) : NULL; +} + +void syno_hint_tree_init(struct syno_hint_tree *tree) +{ + tree->root = RB_ROOT_CACHED; + tree->count = 0; + tree->max_count = SYNO_HINT_DEFAULT_MAX_COUNT; +} + +void syno_hint_tree_clear(struct syno_hint_tree *tree) +{ + struct rb_root *rbroot = &tree->root.rb_root; + struct syno_hint *hint, *next; + + rbtree_postorder_for_each_entry_safe(hint, next, rbroot, node) + syno_hint_free(hint); + tree->root = RB_ROOT_CACHED; + tree->count = 0; +} + +int __init syno_md_hint_init(void) +{ + syno_md_hint_cache = kmem_cache_create("syno_md_hint", + sizeof(struct syno_hint), + 0, 0, NULL); + if (!syno_md_hint_cache) + return -ENOMEM; + return 0; +} + +void syno_md_hint_exit(void) +{ + kmem_cache_destroy(syno_md_hint_cache); +} diff --git a/drivers/md/syno-md-hint.h b/drivers/md/syno-md-hint.h new file mode 100644 index 000000000000..0224ba3b0cf6 --- /dev/null +++ b/drivers/md/syno-md-hint.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ + +#ifndef _MD_HINT_H +#define _MD_HINT_H + +#include +#include + +#define SYNO_HINT_DEFAULT_MAX_COUNT 300000 +#define SYNO_HINT_MIN_LEN 2 * 1024 /* 1MB (unit: sector) */ + +struct syno_hint { + sector_t h_start; + sector_t h_end; + struct rb_node node; +}; + +struct syno_hint_tree { + struct rb_root_cached root; + unsigned long count; + unsigned long max_count; +}; + +int syno_hint_add(struct syno_hint_tree *tree, sector_t h_start, + sector_t h_end, gfp_t gfp_mask); +void syno_hint_remove(struct syno_hint_tree *tree, struct syno_hint *hint); +void syno_hint_free(struct syno_hint *hint); +struct syno_hint* syno_hint_first(struct syno_hint_tree *tree); +void syno_hint_tree_init(struct syno_hint_tree *tree); +void syno_hint_tree_clear(struct syno_hint_tree *tree); +static inline unsigned long syno_hint_count(struct syno_hint_tree *tree) +{ + return tree->count; +} +static inline unsigned long syno_hint_max_count(struct syno_hint_tree *tree) +{ + return tree->max_count; +} + +int syno_md_hint_init(void); +void syno_md_hint_exit(void); +#endif /* _MD_HINT_H */ diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b8847ae04d93..b34e2c5d200a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2168,5 +2168,23 @@ config MFD_INTEL_M10_BMC additional drivers must be enabled in order to use the functionality of the device. +if SYNO_LSP_RTD1619B +config MFD_APW888X + tristate + select MFD_CORE + +config MFD_APW8889_I2C + tristate "Support for Anpec-APW8889 PMIC" + depends on I2C + select MFD_APW888X + select REGMAP_I2C + +config MFD_APW8886_I2C + tristate "Support for Anpec-APW8886 PMIC" + depends on I2C + select MFD_APW888X + select REGMAP_I2C + +endif # SYNO_LSP_RTD1619B endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 1780019d2474..61a17541e9a1 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -253,6 +253,11 @@ obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_MFD_APW888X) += apw888x-core.o +obj-$(CONFIG_MFD_APW8889_I2C) += apw8889-i2c.o +obj-$(CONFIG_MFD_APW8886_I2C) += apw8886-i2c.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o diff --git a/drivers/mfd/apw8886-i2c.c b/drivers/mfd/apw8886-i2c.c new file mode 100644 index 000000000000..50d1e17eccef --- /dev/null +++ b/drivers/mfd/apw8886-i2c.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * apw8886-i2c.c - Anpec APW8886 PMIC I2C driver + * + * Copyright (C) 2018-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include + +static bool apw8886_regmap_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case APW8886_REG_INTR ... APW8886_REG_PWRKEY: + case APW8886_REG_SYS_CONTROL ... APW8886_REG_LDO1_SLPVOLT: + case APW8886_REG_CLAMP: + case APW8886_REG_VFB5_REF_VOLT_DAC: + case APW8886_REG_CHIP_ID: + case APW8886_REG_VERSION: + return true; + } + return false; +} + +static bool apw8886_regmap_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case APW8886_REG_INTR_MASK ... APW8886_REG_PWRKEY: + case APW8886_REG_SYS_CONTROL ... APW8886_REG_LDO1_SLPVOLT: + case APW8886_REG_VFB5_REF_VOLT_DAC: + case APW8886_REG_CLAMP: + return true; + } + return false; +} + +static bool apw8886_regmap_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case APW8886_REG_INTR_MASK ... APW8886_REG_PWRKEY: + case APW8886_REG_SYS_CONTROL: + case APW8886_REG_CLAMP: + case APW8886_REG_CHIP_ID: + case APW8886_REG_VERSION: + return true; + } + return false; +} + +static const struct regmap_config apw8886_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x1F, + .cache_type = REGCACHE_RBTREE, + .readable_reg = apw8886_regmap_readable_reg, + .writeable_reg = apw8886_regmap_writeable_reg, + .volatile_reg = apw8886_regmap_volatile_reg, +}; + +static inline unsigned long apw8886_i2c_get_driver_data(struct i2c_client *client, const struct i2c_device_id *id) +{ + if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) + return (unsigned long)of_device_get_match_data(&client->dev); + return id->driver_data; +} + +static int apw8886_chip_id_valid(u32 chip_id) +{ + return chip_id == 0x5a || chip_id == 0x9a || chip_id == 0xda; +} + +static int apw8886_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct apw888x_device *adev; + int ret; + u32 chip_id, rev; + unsigned long pmic_id = apw8886_i2c_get_driver_data(client, id); + + adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + adev->regmap = devm_regmap_init_i2c(client, &apw8886_regmap_config); + if (IS_ERR(adev->regmap)) + return PTR_ERR(adev->regmap); + + /* show chip info */ + ret = regmap_read(adev->regmap, APW8886_REG_CHIP_ID, &chip_id); + if (ret) { + dev_err(dev, "failed to read chip_id: %d\n", ret); + return ret; + } + if (!apw8886_chip_id_valid(chip_id)) { + dev_err(dev, "chip_id(%02x) not match\n", chip_id); + return -EINVAL; + } + + regmap_read(adev->regmap, APW8886_REG_VERSION, &rev); + dev_info(dev, "(%x) rev%d\n", chip_id, rev); + + adev->chip_id = pmic_id; + adev->chip_rev = rev; + adev->dev = dev; + i2c_set_clientdata(client, adev); + + ret = apw888x_device_init(adev); + if (ret) { + dev_err(dev, "failed to add sub-devices: %d\n", ret); + return ret; + } + return 0; +} + +static int apw8886_i2c_remove(struct i2c_client *client) +{ + struct apw888x_device *adev = i2c_get_clientdata(client); + + apw888x_device_exit(adev); + return 0; +} + +static void apw8886_i2c_shutdown(struct i2c_client *client) +{ + struct apw888x_device *adev = i2c_get_clientdata(client); + unsigned int val = adev->chip_id == APW888X_DEVICE_ID_APW8886 ? 0x24 : 0x28; + + dev_info(&client->dev, "reset dc3 nrmvolt\n"); + regmap_write(adev->regmap, APW8886_REG_DC3_NRMVOLT, val); +} + +static const struct of_device_id apw8886_of_match[] = { + { .compatible = "anpec,apw8886", .data = (void *)APW888X_DEVICE_ID_APW8886, }, + { .compatible = "anpec,apw7899", .data = (void *)APW888X_DEVICE_ID_APW7899, }, + {} +}; +MODULE_DEVICE_TABLE(of, apw8886_of_match); + +static const struct i2c_device_id apw8886_i2c_ids[] = { + {"apw8886", APW888X_DEVICE_ID_APW8886}, + {} +}; +MODULE_DEVICE_TABLE(i2c, apw8886_i2c_ids); + +static struct i2c_driver apw8886_i2c_driver = { + .driver = { + .name = "apw8886", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(apw8886_of_match), + }, + .id_table = apw8886_i2c_ids, + .probe = apw8886_i2c_probe, + .remove = apw8886_i2c_remove, + .shutdown = apw8886_i2c_shutdown, +}; +module_i2c_driver(apw8886_i2c_driver); + +MODULE_DESCRIPTION("Anpec APW8886 PMIC MFD Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/apw8889-i2c.c b/drivers/mfd/apw8889-i2c.c new file mode 100644 index 000000000000..ed343ddfa918 --- /dev/null +++ b/drivers/mfd/apw8889-i2c.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * apw8889-i2c.c - Anpec APW8889 PMIC I2C driver + * + * Copyright (C) 2018-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include + +static bool apw8889_regmap_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case APW8889_REG_INTR ... APW8889_REG_PWRKEY: + case APW8889_REG_SYS_CONTROL ... APW8889_REG_LDO1_SLPVOLT: + case APW8889_REG_CLAMP: + case APW8889_REG_CHIP_ID: + case APW8889_REG_VERSION: + return true; + } + return false; +} + +static bool apw8889_regmap_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case APW8889_REG_INTR_MASK ... APW8889_REG_PWRKEY: + case APW8889_REG_SYS_CONTROL ... APW8889_REG_LDO1_SLPVOLT: + case APW8889_REG_CLAMP: + return true; + } + return false; +} + +static bool apw8889_regmap_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case APW8889_REG_INTR_MASK ... APW8889_REG_PWRKEY: + case APW8889_REG_SYS_CONTROL: + case APW8889_REG_CLAMP: + case APW8889_REG_CHIP_ID: + case APW8889_REG_VERSION: + case APW8889_REG_DC1DC2_MODE ... APW8889_REG_DC5DC6_MODE: + return true; + } + return false; +} + +static const struct regmap_config apw8889_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x1F, + .cache_type = REGCACHE_RBTREE, + .readable_reg = apw8889_regmap_readable_reg, + .writeable_reg = apw8889_regmap_writeable_reg, + .volatile_reg = apw8889_regmap_volatile_reg, +}; + +static int apw8889_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct apw888x_device *adev; + int ret; + u32 chip_id, rev; + + adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + adev->regmap = devm_regmap_init_i2c(client, &apw8889_regmap_config); + if (IS_ERR(adev->regmap)) + return PTR_ERR(adev->regmap); + + /* show chip info */ + ret = regmap_read(adev->regmap, APW8889_REG_CHIP_ID, &chip_id); + if (ret) { + dev_err(dev, "failed to read chip_id: %d\n", ret); + return ret; + } + if (chip_id != 0x5a) { + dev_err(dev, "chip_id(%02x) not match\n", chip_id); + return -EINVAL; + } + regmap_read(adev->regmap, APW8889_REG_VERSION, &rev); + dev_info(dev, "apw8889(%02x) rev%d\n", chip_id, rev); + + + adev->chip_id = APW888X_DEVICE_ID_APW8889; + adev->chip_rev = rev; + adev->dev = dev; + i2c_set_clientdata(client, adev); + + ret = apw888x_device_init(adev); + if (ret) { + dev_err(dev, "failed to add sub-devices: %d\n", ret); + return ret; + } + return 0; +} + +static int apw8889_i2c_remove(struct i2c_client *client) +{ + struct apw888x_device *adev = i2c_get_clientdata(client); + + apw888x_device_exit(adev); + return 0; +} + +static const struct of_device_id apw8889_of_match[] = { + { .compatible = "anpec,apw8889", }, + {} +}; +MODULE_DEVICE_TABLE(of, apw8889_of_match); + +static const struct i2c_device_id apw8889_i2c_ids[] = { + {"apw8889", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, apw8889_i2c_ids); + +static struct i2c_driver apw8889_i2c_driver = { + .driver = { + .name = "apw8889", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(apw8889_of_match), + }, + .id_table = apw8889_i2c_ids, + .probe = apw8889_i2c_probe, + .remove = apw8889_i2c_remove, +}; +module_i2c_driver(apw8889_i2c_driver); + +MODULE_DESCRIPTION("Anpec APW8889 PMIC MFD Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/apw888x-core.c b/drivers/mfd/apw888x-core.c new file mode 100644 index 000000000000..c489c29536ed --- /dev/null +++ b/drivers/mfd/apw888x-core.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GMT-APW888X series PMIC MFD core + * + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include + +static struct mfd_cell apw8889_devs[] = { + { + .name = "apw8889-regulator", + .of_compatible = "anpec,apw8889-regulator", + }, +}; + +static struct mfd_cell apw8886_devs[] = { + { + .name = "apw8886-regulator", + .of_compatible = "anpec,apw8886-regulator", + }, +}; + +int apw888x_device_init(struct apw888x_device *adev) +{ + switch (adev->chip_id) { + case APW888X_DEVICE_ID_APW8889: + return devm_mfd_add_devices(adev->dev, PLATFORM_DEVID_NONE, + apw8889_devs, ARRAY_SIZE(apw8889_devs), 0, 0, 0); + case APW888X_DEVICE_ID_APW8886: + case APW888X_DEVICE_ID_APW7899: + return devm_mfd_add_devices(adev->dev, PLATFORM_DEVID_NONE, + apw8886_devs, ARRAY_SIZE(apw8886_devs), 0, 0, 0); + default: + return -EINVAL; + } + return 0; +} + +void apw888x_device_exit(struct apw888x_device *adev) +{} diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index f950d0155876..c14b467bb109 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Enclosure Services @@ -17,11 +20,19 @@ #include #include #include +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ static LIST_HEAD(container_list); static DEFINE_MUTEX(container_list_lock); static struct class enclosure_class; +#ifdef MY_DEF_HERE +// Add prototype here to avoid build fail +static void enclosure_remove_links(struct enclosure_component *cdev); +#endif /* MY_DEF_HERE */ + /** * enclosure_find - find an enclosure given a parent device * @dev: the parent to match against @@ -163,14 +174,52 @@ static struct enclosure_component_callbacks enclosure_null_callbacks; void enclosure_unregister(struct enclosure_device *edev) { int i; +#ifdef MY_DEF_HERE + struct enclosure_component *cdev = NULL; +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + struct scsi_device *scsi_dev = NULL; + struct scsi_device *scsi_enc = NULL; +#endif /* MY_DEF_HERE */ mutex_lock(&container_list_lock); list_del(&edev->node); mutex_unlock(&container_list_lock); +#ifdef MY_DEF_HERE + for (i = 0; i < edev->components; i++) { + if (edev->component[i].number != -1) { + //======================================= Following part is copy from enclosure_remove_device =================== + cdev = &edev->component[i]; + if (cdev->dev != NULL) { +#ifdef MY_DEF_HERE + if (ENCLOSURE_COMPONENT_ARRAY_DEVICE == cdev->type) { + scsi_dev = to_scsi_device(cdev->dev); + scsi_enc = to_scsi_device(edev->edev.parent); +#ifdef MY_ABC_HERE + printk(KERN_INFO "SCSI device (%s) with disk name (%s) removed from SLOT%02d of enclosure(%s), %.8s-%."SYNO_DISK_MODEL_LEN"s", + dev_name(cdev->dev), scsi_dev->syno_disk_name, cdev->number + 1, dev_name(&(edev->edev)), + scsi_enc->vendor, scsi_enc->model); +#else /* MY_ABC_HERE */ + printk(KERN_INFO "SCSI device (%s) with disk name (%s) removed from SLOT%02d of enclosure(%s), %.8s-%.16s", + dev_name(cdev->dev), scsi_dev->syno_disk_name, cdev->number + 1, dev_name(&(edev->edev)), + scsi_enc->vendor, scsi_enc->model); +#endif /* MY_ABC_HERE */ + } +#endif /* MY_DEF_HERE */ + enclosure_remove_links(cdev); + put_device(cdev->dev); + cdev->dev = NULL; + } + //======================================= Above part is copy from enclosure_remove_device =================== + device_unregister(&edev->component[i].cdev); + } + } +#else /* MY_DEF_HERE */ for (i = 0; i < edev->components; i++) if (edev->component[i].number != -1) device_unregister(&edev->component[i].cdev); +#endif /* MY_DEF_HERE */ /* prevent any callbacks into service user */ edev->cb = &enclosure_null_callbacks; @@ -231,12 +280,17 @@ static void enclosure_release(struct device *cdev) static void enclosure_component_release(struct device *dev) { +#ifdef MY_DEF_HERE + // the reason of #40515 happen is because of the following code, + // unregister will remove sysfs structure, and remove links in release stage will trigger warn on +#else /* MY_DEF_HERE */ struct enclosure_component *cdev = to_enclosure_component(dev); if (cdev->dev) { enclosure_remove_links(cdev); put_device(cdev->dev); } +#endif /* MY_DEF_HERE */ put_device(dev->parent); } @@ -365,6 +419,9 @@ int enclosure_add_device(struct enclosure_device *edev, int component, { struct enclosure_component *cdev; int err; +#ifdef MY_DEF_HERE + struct scsi_device *scsi_enc = NULL; +#endif /* MY_DEF_HERE */ if (!edev || component >= edev->components) return -EINVAL; @@ -379,6 +436,22 @@ int enclosure_add_device(struct enclosure_device *edev, int component, put_device(cdev->dev); } cdev->dev = get_device(dev); + +#ifdef MY_DEF_HERE + if (ENCLOSURE_COMPONENT_ARRAY_DEVICE == cdev->type) { + scsi_enc = to_scsi_device(edev->edev.parent); +#ifdef MY_ABC_HERE + printk(KERN_INFO "SCSI device (%s) plugged in SLOT%02d of enclosure(%s), %.8s-%."SYNO_DISK_MODEL_LEN"s", + dev_name(dev), cdev->number + 1, dev_name(&(edev->edev)), + scsi_enc->vendor, scsi_enc->model); +#else /* MY_ABC_HERE */ + printk(KERN_INFO "SCSI device (%s) plugged in SLOT%02d of enclosure(%s), %.8s-%.16s", + dev_name(dev), cdev->number + 1, dev_name(&(edev->edev)), + scsi_enc->vendor, scsi_enc->model); +#endif /* MY_ABC_HERE */ + } +#endif /* MY_DEF_HERE */ + err = enclosure_add_links(cdev); if (err) { put_device(cdev->dev); @@ -399,6 +472,10 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) { struct enclosure_component *cdev; +#ifdef MY_DEF_HERE + struct scsi_device *scsi_dev = NULL; + struct scsi_device *scsi_enc = NULL; +#endif /* MY_DEF_HERE */ int i; if (!edev || !dev) @@ -407,6 +484,21 @@ int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) for (i = 0; i < edev->components; i++) { cdev = &edev->component[i]; if (cdev->dev == dev) { +#ifdef MY_DEF_HERE + if (ENCLOSURE_COMPONENT_ARRAY_DEVICE == cdev->type) { + scsi_dev = to_scsi_device(dev); + scsi_enc = to_scsi_device(edev->edev.parent); +#ifdef MY_ABC_HERE + printk(KERN_INFO "SCSI device (%s) with disk name (%s) removed from SLOT%02d of enclosure(%s), %.8s-%."SYNO_DISK_MODEL_LEN"s", + dev_name(dev), scsi_dev->syno_disk_name, cdev->number + 1, dev_name(&(edev->edev)), + scsi_enc->vendor, scsi_enc->model); +#else /* MY_ABC_HERE */ + printk(KERN_INFO "SCSI device (%s) with disk name (%s) removed from SLOT%02d of enclosure(%s), %.8s-%.16s", + dev_name(dev), scsi_dev->syno_disk_name, cdev->number + 1, dev_name(&(edev->edev)), + scsi_enc->vendor, scsi_enc->model); +#endif /* MY_ABC_HERE */ + } +#endif /* MY_DEF_HERE */ enclosure_remove_links(cdev); put_device(dev); cdev->dev = NULL; diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 87bac9920702..3953ee536da4 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Block driver for media (i.e., flash cards) * @@ -57,6 +60,12 @@ #include "quirks.h" #include "sd_ops.h" +#if defined(MY_DEF_HERE) +#ifdef CONFIG_ARCH_REALTEK +#include "../../base/base.h" +#endif /* CONFIG_ARCH_REALTEK */ + +#endif /* MY_DEF_HERE */ MODULE_ALIAS("mmc:block"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX @@ -740,10 +749,64 @@ static int mmc_blk_check_blkdev(struct block_device *bdev) return 0; } +#if defined(MY_DEF_HERE) +#if defined(CONFIG_MMC_REALTEK_RTD13XX) +static int check_eod(struct block_device *bdev, unsigned int from, unsigned int nr) +{ + unsigned int maxsector; + + if (!nr) + return 0; + + maxsector = bdev->bd_inode->i_size >> 9; + if (maxsector && (maxsector < nr || maxsector - nr < from)) + return 1; + + return 0; +} + +static int mmc_blk_erase(struct mmc_blk_data *md, unsigned int from, unsigned int nr) +{ + struct mmc_card *card = md->queue.card; + unsigned int n; + int err; + + + + mmc_claim_host(card->host); + + n = card->pref_erase - (from % card->pref_erase); + do { + if (n > nr) + n = nr; + err = mmc_erase(card, from, n, MMC_TRIM_ARG); + if (err) + break; + from += n; + nr -= n; + n = card->pref_erase; + } while (nr); + + mmc_release_host(card->host); + + + + return err; +} + +void euda_gpp_setting(unsigned long size[], char type[], int gpp_num, unsigned long euda_start_addr, unsigned long euda_size); +#endif +#endif /* MY_DEF_HERE */ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct mmc_blk_data *md; +#if defined(MY_DEF_HERE) +#if defined(CONFIG_MMC_REALTEK_RTD13XX) + struct mmc_blk_erase_args args; + struct mmc_euda_gpp_args paras; +#endif +#endif /* MY_DEF_HERE */ int ret; switch (cmd) { @@ -771,6 +834,42 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, NULL); mmc_blk_put(md); return ret; +#if defined(MY_DEF_HERE) +#if defined(CONFIG_MMC_REALTEK_RTD13XX) + case MMCERASE: + ret = mmc_blk_check_blkdev(bdev); + if (ret) + return ret; + md = mmc_blk_get(bdev->bd_disk); + if (!md) + return -EINVAL; + if (!(mode & FMODE_WRITE)) + return -EBADF; + if (copy_from_user(&args, (void __user *)arg, sizeof(struct mmc_blk_erase_args))) + return -EFAULT; + if (check_eod(bdev, args.from, args.nr)) + return -EINVAL; + if (bdev != bdev->bd_contains) + args.from += bdev->bd_part->start_sect; + ret = mmc_blk_erase(md, args.from, args.nr); + mmc_blk_put(md); + return ret; + case GPP_EUDA_SETTING: + ret = mmc_blk_check_blkdev(bdev); + if (ret) + return ret; + md = mmc_blk_get(bdev->bd_disk); + if (!md) + return -EINVAL; + + if (copy_from_user(¶s, (void __user *)arg, sizeof(struct mmc_euda_gpp_args))) + return -EFAULT; + + euda_gpp_setting(paras.size, paras.type, paras.gpp_num, paras.euda_start_addr, paras.euda_size); + mmc_blk_put(md); + return ret; +#endif /* CONFIG_MMC_REALTEK_RTD13XX */ +#endif /* MY_DEF_HERE */ default: return -EINVAL; } @@ -806,7 +905,9 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card, if (ret) return ret; } +#if defined(MY_DEF_HERE) mmc_retune_pause(card->host); +#endif /* MY_DEF_HERE */ } return ret; @@ -818,7 +919,9 @@ static int mmc_blk_part_switch_post(struct mmc_card *card, int ret = 0; if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) { +#if defined(MY_DEF_HERE) mmc_retune_unpause(card->host); +#endif /* MY_DEF_HERE */ if (card->reenable_cmdq && !card->ext_csd.cmdq_en) ret = mmc_cmdq_enable(card); } @@ -1643,32 +1746,32 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req) struct mmc_card *card = mq->card; struct mmc_host *host = card->host; blk_status_t error = BLK_STS_OK; - int retries = 0; do { u32 status; int err; + int retries = 0; - mmc_blk_rw_rq_prep(mqrq, card, 1, mq); + while (retries++ <= MMC_READ_SINGLE_RETRIES) { + mmc_blk_rw_rq_prep(mqrq, card, 1, mq); - mmc_wait_for_req(host, mrq); + mmc_wait_for_req(host, mrq); - err = mmc_send_status(card, &status); - if (err) - goto error_exit; - - if (!mmc_host_is_spi(host) && - !mmc_ready_for_data(status)) { - err = mmc_blk_fix_state(card, req); + err = mmc_send_status(card, &status); if (err) goto error_exit; + + if (!mmc_host_is_spi(host) && + !mmc_ready_for_data(status)) { + err = mmc_blk_fix_state(card, req); + if (err) + goto error_exit; + } + + if (!mrq->cmd->error) + break; } - if (mrq->cmd->error && retries++ < MMC_READ_SINGLE_RETRIES) - continue; - - retries = 0; - if (mrq->cmd->error || mrq->data->error || (!mmc_host_is_spi(host) && @@ -2273,6 +2376,23 @@ static inline int mmc_blk_readonly(struct mmc_card *card) !(card->csd.cmdclass & CCC_BLOCK_WRITE); } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_ARCH_REALTEK +void mmc_blk_set_ro(struct mmc_card *card) +{ + struct mmc_blk_data *md=NULL, *part_md=NULL; + md = card->dev.driver_data; + if(md!=NULL) { + md->read_only = mmc_blk_readonly(card); + set_disk_ro(md->disk, md->read_only); + list_for_each_entry(part_md, &md->part, part) + set_disk_ro(part_md->disk, md->read_only); + } +} +EXPORT_SYMBOL(mmc_blk_set_ro); +#endif /* CONFIG_ARCH_REALTEK */ + +#endif /* MY_DEF_HERE */ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct device *parent, sector_t size, diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b5f3f160c842..c579cf2fa820 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/core.c @@ -46,6 +49,15 @@ #include "sd_ops.h" #include "sdio_ops.h" +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_SDHCI_OF_RTK +#include "../host/sdhci-rtk.h" +#endif /* CONFIG_MMC_SDHCI_OF_RTK */ + +/* If the device is not responding */ +#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ + +#endif /* MY_DEF_HERE */ /* The max erase timeout, used when host->max_busy_timeout isn't specified */ #define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */ #define SD_DISCARD_TIMEOUT_MS (250) @@ -60,6 +72,19 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_SDHCI_OF_RTK +bool SDIO_flag = false; +bool SDIO_fini = false; +extern bool SDIO_card; +#endif /* CONFIG_MMC_SDHCI_OF_RTK */ + +#ifdef CONFIG_MMC_RTK_SDMMC +void rtk_sdmmc_close_clk(struct mmc_host *host); +int rtk_sdmmc_clk_cls_chk(struct mmc_host *host); +#endif /* CONFIG_MMC_RTK_SDMMC */ + +#endif /* MY_DEF_HERE */ static int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { @@ -2126,6 +2151,12 @@ EXPORT_SYMBOL(mmc_sw_reset); static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_SDHCI_OF_RTK + int ret = 0; +#endif /* CONFIG_MMC_SDHCI_OF_RTK */ + +#endif /* MY_DEF_HERE */ host->f_init = freq; pr_debug("%s: %s: trying to init card at %u Hz\n", @@ -2154,9 +2185,26 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) mmc_send_if_cond(host, host->ocr_avail); /* Order's important: probe SDIO, then SD, then MMC */ +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_SDHCI_OF_RTK + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) { + if (!(ret = mmc_attach_sdio(host))) { + SDIO_flag = true; + return 0; + } + if(ret == -110) + SDIO_fini = true; + } +#else if (!(host->caps2 & MMC_CAP2_NO_SDIO)) if (!mmc_attach_sdio(host)) return 0; +#endif /* CONFIG_MMC_SDHCI_OF_RTK */ +#else /* MY_DEF_HERE */ + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) + if (!mmc_attach_sdio(host)) + return 0; +#endif /* MY_DEF_HERE */ if (!(host->caps2 & MMC_CAP2_NO_SD)) if (!mmc_attach_sd(host)) @@ -2261,8 +2309,21 @@ void mmc_rescan(struct work_struct *work) mmc_bus_get(host); /* Verify a registered card to be functional, else remove it. */ +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_RTK_SDMMC + if (host->bus_ops && !host->bus_dead) { + host->bus_ops->detect(host); + if(!(host->caps2 & MMC_CAP2_NO_SD)) + rtk_sdmmc_close_clk(host); + } +#else if (host->bus_ops && !host->bus_dead) host->bus_ops->detect(host); +#endif /* CONFIG_MMC_RTK_SDMMC */ +#else /* MY_DEF_HERE */ + if (host->bus_ops && !host->bus_dead) + host->bus_ops->detect(host); +#endif /* MY_DEF_HERE */ host->detect_change = 0; @@ -2310,6 +2371,20 @@ void mmc_rescan(struct work_struct *work) out: if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_SDHCI_OF_RTK + if(SDIO_fini==true && SDIO_flag == false && SDIO_card==false) { + SDIO_fini= false; + host->caps2 |= MMC_CAP2_NO_SDIO; + rtk_sdhci_close_clk(); + } +#endif /* CONFIG_MMC_SDHCI_OF_RTK */ + +#ifdef CONFIG_MMC_RTK_SDMMC + if(!(host->caps2 & MMC_CAP2_NO_SD) && rtk_sdmmc_clk_cls_chk(host)) + rtk_sdmmc_close_clk(host); +#endif /* CONFIG_MMC_RTK_SDMMC */ +#endif /* MY_DEF_HERE */ } void mmc_start_host(struct mmc_host *host) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index bac343a8d569..0ef23d8e10f0 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/sd.c @@ -26,6 +29,25 @@ #include "sd.h" #include "sd_ops.h" +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MMC_RTK_SDMMC + +int mmc_runtime_resume_flag=0; + +int get_mmc_runtime_resume_flag(void) +{ + return mmc_runtime_resume_flag; +} +EXPORT_SYMBOL(get_mmc_runtime_resume_flag); + +void set_mmc_runtime_resume_flag(int flag) +{ + mmc_runtime_resume_flag = flag; +} +EXPORT_SYMBOL(set_mmc_runtime_resume_flag); +#endif /* CONFIG_MMC_RTK_SDMMC */ + +#endif /* MY_DEF_HERE */ static const unsigned int tran_exp[] = { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 @@ -1310,9 +1332,20 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) int err; err = _mmc_sd_resume(host); +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_MMC_RTK_SDMMC + if (err && err != -ENOMEDIUM) { + mmc_runtime_resume_flag = 1; + pr_err("%s: error %d doing runtime resume\n", + mmc_hostname(host), err); + } +#else +#endif /* MY_DEF_HERE */ if (err && err != -ENOMEDIUM) pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); +#endif /* MY_DEF_HERE */ return 0; } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 1b0853a82189..23e6aa8b80fd 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * linux/drivers/mmc/sdio.c @@ -27,6 +30,8 @@ #include "sdio_ops.h" #include "sdio_cis.h" +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor); MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device); MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev); @@ -69,6 +74,7 @@ static struct device_type sdio_type = { .groups = sdio_std_groups, }; +#endif /* MY_DEF_HERE */ static int sdio_read_fbr(struct sdio_func *func) { int ret; @@ -680,7 +686,11 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* * Allocate card structure. */ +#if defined(MY_DEF_HERE) + card = mmc_alloc_card(host, NULL); +#else /* MY_DEF_HERE */ card = mmc_alloc_card(host, &sdio_type); +#endif /* MY_DEF_HERE */ if (IS_ERR(card)) return PTR_ERR(card); @@ -720,7 +730,17 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * to make sure which speed mode should work. */ if (rocr & ocr & R4_18V_PRESENT) { +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_MMC_SDHCI_OF_RTK + host->ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180; + ocr |= R4_18V_PRESENT; +#else err = mmc_set_uhs_voltage(host, ocr_card); +#endif /* CONFIG_MMC_SDHCI_OF_RTK */ +#else /* MY_DEF_HERE */ + err = mmc_set_uhs_voltage(host, ocr_card); +#endif /* MY_DEF_HERE */ if (err == -EAGAIN) { mmc_sdio_pre_init(host, ocr_card, card); retries--; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 31481c9fcc2e..793490387992 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -202,6 +202,21 @@ config MMC_SDHCI_OF_HLWD If unsure, say N. +if SYNO_LSP_RTD1619B +config MMC_SDHCI_OF_RTK + tristate "SDHCI OF support for the Realtek SoC SDHCI controller" + depends on MMC_SDHCI_PLTFM + depends on OF + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Secure Digital Host Controller Interface in + Realtek SoCs. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + +endif # SYNO_LSP_RTD1619B config MMC_SDHCI_OF_DWCMSHC tristate "SDHCI OF support for the Synopsys DWC MSHC" depends on MMC_SDHCI_PLTFM @@ -951,6 +966,39 @@ config MMC_WMT To compile this driver as a module, choose M here: the module will be called wmt-sdmmc. +if SYNO_LSP_RTD1619B +menuconfig MMC_RTK_EMMC + tristate "Realtek EMMC host controller support" + help + Realtek EMMC host controller support. + +config MMC_REALTEK_RTD13XX + bool "RTD1319 EMMC host controller support" + depends on MMC_RTK_EMMC + default n + help + RTD1319 SoC family EMMC host controller support. + +config MMC_RTK_EMMC_PON + bool "Realtek EMMC host driver with GPON feature" + depends on MMC_RTK_EMMC && MMC_REALTEK_RTD13XX + default n + help + Support RealTek EMMC for RTD1319 GPON feature. + +config MMC_RTK_EMMC_HW_SEMAPHORE + bool "Enable Realtek EMMC host driver hardware semaphore." + depends on MMC_RTK_EMMC + default n + help + Enable Realtek EMMC host driver hardware semaphore. + +config MMC_RTK_SDMMC + tristate "Realtek SD/MMC host controller support" + help + Realtek SD/MMC host controller support. + +endif # SYNO_LSP_RTD1619B config MMC_USDHI6ROL0 tristate "Renesas USDHI6ROL0 SD/SDIO Host Controller support" depends on HAS_DMA diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 451c25fc2c69..2d82126ed0da 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -72,6 +72,10 @@ meson-mx-sdhc-objs := meson-mx-sdhc-clkc.o meson-mx-sdhc-mmc.o obj-$(CONFIG_MMC_MESON_MX_SDHC) += meson-mx-sdhc.o obj-$(CONFIG_MMC_MESON_MX_SDIO) += meson-mx-sdio.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_MMC_REALTEK_RTD13XX) += cqhci.o +obj-$(CONFIG_MMC_REALTEK_RTD13XX) += rtkemmc_rtd13xx.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o @@ -80,6 +84,9 @@ obj-$(CONFIG_MMC_OWL) += owl-mmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_MMC_RTK_SDMMC) += rtk-sdmmc.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o @@ -94,6 +101,9 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_MMC_SDHCI_OF_RTK) += sdhci-rtk.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index 697fe40756bf..f90d3b9710cc 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015, The Linux Foundation. All rights reserved. */ @@ -491,6 +494,13 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq, desc = get_trans_desc(cq_host, tag); +#if defined(MY_DEF_HERE) + if (cq_host->ops->setup_tran_desc) { + cq_host->ops->setup_tran_desc(data, cq_host, desc, sg_count); + return 0; + } + +#endif /* MY_DEF_HERE */ for_each_sg(data->sg, sg, sg_count, i) { addr = sg_dma_address(sg); len = sg_dma_len(sg); diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 89bf6adbce8c..866b65ad6e40 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2015, The Linux Foundation. All rights reserved. */ @@ -208,6 +211,10 @@ struct cqhci_host_ops { u64 *data); void (*pre_enable)(struct mmc_host *mmc); void (*post_disable)(struct mmc_host *mmc); +#if defined(MY_DEF_HERE) + void (*setup_tran_desc)(struct mmc_data *data, + struct cqhci_host *cq_host, u8 *desc, int sg_count); +#endif /* MY_DEF_HERE */ }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) diff --git a/drivers/mmc/host/mmc_debug.h b/drivers/mmc/host/mmc_debug.h new file mode 100644 index 000000000000..ba1205db5931 --- /dev/null +++ b/drivers/mmc/host/mmc_debug.h @@ -0,0 +1,110 @@ +#ifndef _MMC_RTK_DEBUG_H +#define _MMC_RTK_DEBUG_H + +//#define MMC_DEBUG////////////////////// +#ifdef MMC_DEBUG + #define mmcinfo(fmt, args...) \ + printk(KERN_INFO "mmc:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcinfo(fmt, args...) +#endif + +//#define MMC_CORE////////////////////// +#ifdef MMC_CORE + #define mmcore(fmt, args...) \ + printk(KERN_INFO "mmcore:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcore(fmt, args...) +#endif + +//#define MMC_CARD////////////////////// +#ifdef MMC_CARD + #define mmcard(fmt, args...) \ + printk(KERN_INFO "mmcard:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcard(fmt, args...) +#endif + +//#define MMC_RTK////////////////////// +#ifdef MMC_RTK + #define mmcrtk(fmt, args...) \ + printk(KERN_INFO "mmcrtk:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcrtk(fmt, args...) +#endif + +//#define MMC_SPEC////////////////////// +#ifdef MMC_SPEC + #define mmcspec(fmt, args...) \ + printk(KERN_INFO "mmcspec:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcspec(fmt, args...) +#endif + +//#define MMC_MSG1////////////////////// +#ifdef MMC_MSG1 + #define mmcmsg1(fmt, args...) \ + printk(KERN_INFO "mmcmsg1:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcmsg1(fmt, args...) +#endif + +//#define MMC_MSG2////////////////////// +#ifdef MMC_MSG2 + #define mmcmsg2(fmt, args...) \ + printk(KERN_INFO "mmcmsg2:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcmsg2(fmt, args...) +#endif + +//#define MMC_MSG3////////////////////// +#ifdef MMC_MSG3 + #define mmcmsg3(fmt, args...) \ + printk(KERN_INFO "" fmt, ## args) + //printk(KERN_INFO "mmcmsg3:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define mmcmsg3(fmt, args...) +#endif + +//#define MMC_TRH////////////////////// +#ifdef MMC_TRH + #define trhmsg(fmt, args...) \ + printk(KERN_INFO "" fmt,## args) + //printk(KERN_INFO "trhmsg:%s(%d):" fmt, __func__ ,__LINE__,## args) +#else + #define trhmsg(fmt, args...) +#endif + +//#define SHOW_CSD +//#define SHOW_EXT_CSD +//#define SHOW_SWITCH_DATA +//#define SHOW_CID +//#define SHOW_SCR + +//#define SHOW_MS_PRD +//#define SHOW_MMC_PRD +//#define SHOW_INT_STATUS + +//#define GPIO_CTL +//#define TEST_POWER_RESCYCLE + +//#define OPEN_TEST_PORT + +//#define WR_WORK_AROUND_EN +//#define WR_WORK_AROUND_EN_TEST +//#define HW_ISSUE_RESET +//#define MONI_MEM_TRASH +//#define END_DELAY_EN +//#define FPGA_TEST_CASE + +#endif + + + + + + + + + + diff --git a/drivers/mmc/host/reg_iso.h b/drivers/mmc/host/reg_iso.h new file mode 100644 index 000000000000..b12457b5c367 --- /dev/null +++ b/drivers/mmc/host/reg_iso.h @@ -0,0 +1,12 @@ +#ifndef _REG_ISO_H_INCLUDED_ +#define _REG_ISO_H_INCLUDED_ + +#define ISO_OFFSET 0x00007000 + +#define UR0RBR_THR_DLL 0x00000800 + +#define RBUS_ISO_PHYS(pa) (RBUS_BASE_PHYS + ISO_OFFSET + pa) + +#define ISO_IO_ADDR(pa) (IOMEM(RBUS_BASE_VIRT) + ISO_OFFSET + pa) + +#endif // _REG_ISO_H_INCLUDED_ diff --git a/drivers/mmc/host/reg_mmc.h b/drivers/mmc/host/reg_mmc.h new file mode 100644 index 000000000000..deff0bc3e54c --- /dev/null +++ b/drivers/mmc/host/reg_mmc.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2013 Realtek Semiconductors, 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 as + * published by the Free Software Foundation. + */ + +#ifndef __REG_MMC_H +#define __REG_MMC_H + +/* eMMC control register definition */ +#define CR_BASE_ADDR 0x00000000 //map to 0x98012000 + +//1295 emmc ip register +#define EMMC_CTRL ( CR_BASE_ADDR) +#define EMMC_PWREN ( CR_BASE_ADDR + 0x004) +#define EMMC_CLKDIV ( CR_BASE_ADDR + 0x008) +#define EMMC_CLKSRC ( CR_BASE_ADDR + 0x00C) +#define EMMC_CLKENA ( CR_BASE_ADDR + 0x010) +#define EMMC_TMOUT ( CR_BASE_ADDR + 0x014) +#define EMMC_CTYPE ( CR_BASE_ADDR + 0x018) +#define EMMC_BLKSIZE ( CR_BASE_ADDR + 0x01C) +#define EMMC_BYTCNT ( CR_BASE_ADDR + 0x020) +#define EMMC_INTMASK ( CR_BASE_ADDR + 0x024) +#define EMMC_CMDARG ( CR_BASE_ADDR + 0x028) +#define EMMC_CMD ( CR_BASE_ADDR + 0x02C) +#define EMMC_RESP0 ( CR_BASE_ADDR + 0x030) +#define EMMC_RESP1 ( CR_BASE_ADDR + 0x034) +#define EMMC_RESP2 ( CR_BASE_ADDR + 0x038) +#define EMMC_RESP3 ( CR_BASE_ADDR + 0x03C) +#define EMMC_MINTSTS ( CR_BASE_ADDR + 0x040) +#define EMMC_RINTSTS ( CR_BASE_ADDR + 0x044) +#define EMMC_STATUS ( CR_BASE_ADDR + 0x048) +#define EMMC_FIFOTH ( CR_BASE_ADDR + 0x04C) +#define EMMC_TBBCNT ( CR_BASE_ADDR + 0x060) +#define EMMC_UHSREG ( CR_BASE_ADDR + 0x074) +#define EMMC_BMOD ( CR_BASE_ADDR + 0x080) +#define EMMC_DBADDR ( CR_BASE_ADDR + 0x088) +#define EMMC_IDINTEN ( CR_BASE_ADDR + 0x090) +#define EMMC_IDSTS ( CR_BASE_ADDR + 0x08C) +#define EMMC_CARD_THR_CTL ( CR_BASE_ADDR + 0x100) +#define EMMC_DDR_REG ( CR_BASE_ADDR + 0x10c) + + +//1295 emmc wrapper register +#define EMMC_DESC_CTL0 ( 0x400 ) +#define EMMC_DESC_CTL1 ( 0x404 ) +#define EMMC_DESC_CTL2 ( 0x408 ) +#define EMMC_DESC_CTL3 ( 0x40C ) +#define EMMC_DESC_STS ( 0x410 ) +#define EMMC_DESC_THD ( 0x414 ) +#define EMMC_SYS_LOW_PWR ( 0x418 ) +#define EMMC_CP ( 0x41c ) +#define EMMC_OTHER1 ( 0x420 ) +#define EMMC_ISR ( 0x424 ) +#define EMMC_DBG (0x444) +#define EMMC_PAD_CTL ( 0x474 ) +#define EMMC_IP_DESC0 ( 0x4a0) +#define EMMC_IP_DESC1 ( 0x4a4) +#define EMMC_IP_DESC2 ( 0x4a8) +#define EMMC_IP_DESC3 ( 0x4ac) +#define EMMC_MAIN2_DBG ( 0x4b0) + +#if defined(CONFIG_ARCH_RTD129x) +#define EMMC_muxpad0 (0x600) //mux for nand and emmc +#define EMMC_muxpad1 (0x604) //mux for sdio and sd card +#define EMMC_PFUNC_NF1 (0x60c) +#define EMMC_PFUNC_CR (0x610) +#define EMMC_muxpad2 (0x61c) +#define EMMC_PDRIVE_NF0 ( 0x620 ) +#define EMMC_PDRIVE_NF1 ( 0x624 ) +#define EMMC_PDRIVE_NF2 ( 0x628 ) +#define EMMC_PDRIVE_NF3 ( 0x62c ) +#define EMMC_PDRIVE_NF4 ( 0x630 ) + +#define EMMC_PDRIVE_CR0 ( 0x634 ) +#define EMMC_PDRIVE_CR1 ( 0x638 ) +#define EMMC_PDRIVE_SDIO ( 0x63c ) +#define EMMC_PDRIVE_SDIO1 ( 0x640 ) + +#elif defined(CONFIG_ARCH_RTD139x) //139x +#define ISO_MUXPAD ( 0x00000000 ) +#define ISO_muxpad4 ( ISO_MUXPAD + 0x10 ) +#define pfunc_emmc0 ( ISO_MUXPAD + 0x50 ) +#define pfunc_emmc1 ( ISO_MUXPAD + 0x54 ) +#define pfunc_emmc2 ( ISO_MUXPAD + 0x58 ) +#define pfunc_emmc3 ( ISO_MUXPAD + 0x5c ) +#define pfunc_emmc4 ( ISO_MUXPAD + 0x60 ) +#define pfunc_emmc5 ( ISO_MUXPAD + 0x64 ) + +#elif defined(CONFIG_ARCH_RTD16xx) //16xx +#define M2TMX ( 0x00000000 ) +#define m2tmx_muxpad0 ( M2TMX ) +#define m2tmx_pfunc4 ( M2TMX + 0x1c ) +#define m2tmx_pfunc5 ( M2TMX + 0x20 ) +#define m2tmx_pfunc6 ( M2TMX + 0x24 ) +#define m2tmx_pfunc7 ( M2TMX + 0x28 ) +#define m2tmx_pfunc8 ( M2TMX + 0x2c ) +#endif + +//MISC +#define MISC_GP2DIR (0x108) +#define MISC_GP3DIR (0x10c) + +#define MISC_GP2DATO (0x118) +#define MISC_GP3DATO (0x11c) + +#define MISC_DUMMY1 (0x0e4) +#define MISC_DUMMY2 (0x0e8) + + + +#define ISR_WRITE_DATA 1 //set bit +#define ISR_DMA_DONE_INT (1<<1) +#define ISR_DMA_INT_MASK (1<<2) +#define ISR_DESC_INT_MASK (1<<3) +#define ISR_IP_INT_MASK (1<<4) +#define EMMC_ISREN ( 0x428 ) +#define EMMC_DUMMY_SYS ( 0x42c ) +#define EMMC_AHB ( 0x430 ) +#define EMMC_IP_CTL ( 0x470 ) +#define EMMC_CKGEN_CTL ( 0x478 ) +#define EMMC_CARD_DRV1 ( 0x490 ) +#define EMMC_CARD_DRV2 ( 0x494 ) +#define EMMC_DQS_CTRL1 ( 0x498 ) +#define EMMC_SWC_SEL ( 0x4d4 ) + +#if defined(CONFIG_ARCH_RTD139x) || defined(CONFIG_ARCH_RTD16xx) +#define EMMC_SWC_SEL1 ( 0x4d8 ) +#define EMMC_SWC_SEL2 ( 0x4dc ) +#define EMMC_SWC_SEL3 ( 0x4e0 ) +#endif + +#define RESP_LEN64 (0x1) +#define RESP_LEN17 (0x2) +#define DMA_XFER (0x00000001) +#define DDR_WR (0x00000001<<1) +#define RSP17_SEL (0x00000001<<4) +#define RSP64_SEL (0x00000001<<5) +#define DAT64_SEL (0x00000001<<5) + +/*CARD_EXIST 0x1801051f */ +#if 0 +#define SD_WRITE_PROTECT (0x00000001<<5) +#define XD_EXISTENCE (0x00000001<<4) +#define MS_EXISTENCE (0x00000001<<3) +#define SD_EXISTENCE (0x00000001<<2) +#define SM_EXISTENCE (0x00000001<<1) +#endif + +/* SD_CONFIGURE1 0x18012180 */ +#define SDCLK_DIV (0x00000001<<7) +#define SDCLK_NO_DIV (0x00000000) +#define SDCLK_DIV_128 (0x00000000) +#define SDCLK_DIV_256 (0x00000001<<6) +#define NO_RST_RDWR_FIFO (0x00000000) +#define RST_RDWR_FIFO (0x00000001<<4) + +#define MASK_CLOCK_MODE (0x00000003<<2) +#define MASK_CLOCK_DIV (0x00000003<<6) +#define CLOCK_DIV_NON (0x00000002) +#define CLOCK_DIV_256 (0x00000001<<6) +#define CLOCK_DIV_128 (0x00000000) +#define EMMC_CLOCK_DIV_NON (0x00000000) +#define EMMC_CLOCK_DIV_2 (0x00000001) +#define EMMC_CLOCK_DIV_8 (0x00000004) +#define EMMC_CLOCK_DIV_128 (0x00000001<<6) +#define EMMC_CLOCK_DIV_256 (0x00000001<<7) + + +#define SPEED_MOD_HIGH (0x00000001<<4) +#define SPEED_MOD_NORM (0x00000000) +#define DELAY_PHA_MASK (0x00000003<<2) +#define DELAY_PHA_NORM (0x00000001<<3) +#define DELAY_PHA_HIGH (0x00000001<<2) +#define SD30_ASYNC_FIFO_RST (0x00000001<<4) +#define ACCESS_MODE_SDR (0x00000000) +#define ACCESS_MODE_DDR (0x00000001) +#define ACCESS_MODE_HS200 (0x00000002) +#define ACCESS_MODE_HS400 (0x00000003) +#define MODE_SEL_MASK (0x00000003<<2) +#define MODE_SEL_SD20 (ACCESS_MODE_SD20<<2) +#define MODE_SEL_DDR (ACCESS_MODE_DDR<<2) +#define MODE_SEL_SD30 (ACCESS_MODE_SD30<<2) + +#define MASK_MODE_SELECT (0x0c) +#define MODE_SDR (0x00) //sdr20/50 +#define MODE_DDR (0x01<<2) //ddr50 +#define MODE_HS200 (0x02<<2) //hs-200 +#define MODE_HS400 (0x03<<2) //hs-400 + +#define MASK_BUS_WIDTH (0x00010001) +#define BUS_WIDTH_1 (0x00000000) +#define BUS_WIDTH_4 (0x00000001) +#define BUS_WIDTH_8 (0x00010000) + +/* CPU_ACC_CTL 0x18012080 */ +#define CPU_MODE_EN (0x00000001) +#define BUF_FULL (0x00000001<<2) + +/* SD_CONFIGURE2 0x18012181 */ +#define CRC7_CAL_DIS (0x00000001<<7) +#define CRC16_CAL_DIS (0x00000001<<6) +#define IGN_WR_CRC_ERR_EN (0x00000001<<4) +#define WAIT_BUSY_EN (0x00000001<<3) +#define CRC7_CHK_DIS (0x00000001<<2) + +#define MASK_RESP_TYPE (0x00000003) +#define RESP_TYPE_NON (0x00000000) +#define RESP_TYPE_6B (0x00000001) +#define RESP_TYPE_17B (0x00000002) + +/* SD_CONFIGURE3 0x18012182 */ +#define DATA_TRANS_OVER_EN (0x00000001<<3) +#define RESP_CHK_EN (0x00000001<<2) +#define ADDR_BYTE_MODE (0x00000001<<1) +#define SD_CMD_RSP_TO (0x00000001<<0) + +/* SD_TRANSFER 0x18012193 */ +//98012044 : Raw Interrupt Status Register +#define INT_STS_EBE (1<<15) +#define INT_STS_ACD (1<<14) +#define INT_STS_SBE_BCI (1<<13) +#define INT_STS_HLE (1<<12) +#define INT_STS_FRUN (1<<11) +#define INT_STS_HTO (1<<10) +#define INT_STS_DRTO_BDS (1<<9) +#define INT_STS_RTO_BAR (1<<8) +#define INT_STS_DCRC (1<<7) +#define INT_STS_RCRC (1<<6) +#define INT_STS_RXDR (1<<5) +#define INT_STS_TXDR (1<<4) +#define INT_STS_DTO (1<<3) +#define INT_STS_CD (1<<2) +#define INT_STS_RE (1<<1) +#define INT_STS_CRD (1<<0) +#define INT_STS_ERRORS (INT_STS_RE|INT_STS_RCRC|INT_STS_DCRC|INT_STS_RTO_BAR|INT_STS_DRTO_BDS|INT_STS_HTO|INT_STS_FRUN|INT_STS_HLE|INT_STS_SBE_BCI|INT_STS_EBE) +#define INT_STS_ERRORS2 (INT_STS_RE|INT_STS_RCRC|INT_STS_DCRC|INT_STS_DRTO_BDS|INT_STS_HTO|INT_STS_FRUN|INT_STS_HLE|INT_STS_SBE_BCI|INT_STS_EBE) + + +#define INT_EN (INT_STS_ACD|INT_STS_DTO|INT_STS_CD) + +//98012048 : Status Register +#define STS_RSP_IDX_MASK (0x3f<<11) +#define STS_RSP_IDX (11) + +#define STS_DATA_BUSY (1<<9) +#define STS_DATA_3_STATUS (1<<8) + +//9801202c : command register +#define CMD_IDX_MASK(x) (x & 0x3f) +#define CMD_IDX (0x3f) +#define CMD_RSP_EXP (1<<6) +#define CMD_RSP_LEN (1<<7) +#define CMD_CHK_RESP_CRC (1<<8) +#define CMD_DATA_EXP (1<<9) +#define CMD_RD_WR (1<<10) +#define CMD_TRANS_MODE (1<<11) +#define CMD_SEND_AUTO_STOP (1<<12) +#define CMD_WAIT_PRV_DATA_COMPLETE (1<<13) +#define CMD_USE_HOLD_REG (1<<29) +#define CMD_START_CMD (1<<31) + + +#define MASK_CMD_CODE (0x0F) +#define SD_NORMALWRITE (0x00) +#define SD_AUTOWRITE3 (0x01) +#define SD_AUTOWRITE4 (0x02) +#define SD_AUTOREAD3 (0x05) +#define SD_AUTOREAD4 (0x06) +#define SD_SENDCMDGETRSP (0x08) +#define SD_AUTOWRITE1 (0x09) +#define SD_AUTOWRITE2 (0x0A) +#define SD_NORMALREAD (0x0C) +#define SD_AUTOREAD1 (0x0D) +#define SD_AUTOREAD2 (0x0E) +#define SD_CMD_UNKNOW (0x0F) + +#define EMMC_MASK_CMD_CODE (0xFF) +#define EMMC_NORMALWRITE (0x00) +#define EMMC_AUTOWRITE3 (0x01) +#define EMMC_AUTOWRITE4 (0x02) +#define EMMC_AUTOREAD3 (0x05) +#define EMMC_AUTOREAD4 (0x06) +#define EMMC_SENDCMDGETRSP (0x08) +#define EMMC_AUTOWRITE1 (0x09) +#define EMMC_AUTOWRITE2 (0x0A) +#define EMMC_NORMALREAD (0x0C) +#define EMMC_AUTOREAD1 (0x0D) +#define EMMC_AUTOREAD2 (0x0E) +#define EMMC_TUNING (0x0F) +#define EMMC_CMD_UNKNOW (0x10) + +/* SD_CONFIGURE2 0x18012181 */ +#define CRC7_STATUS (0x00000001<<7) +#define CRC16_STATUS (0x00000001<<6) +#define WRT_ERR_BIT (0x00000001<<5) +#define CRC_TIMEOUT_ERR (0x00000001<<1) +#define PATTERN_CMP_ERR (0x00000001<<0) +#define WRITE_CRC_ERR_STAT(x) ((x & (0x7<<2))>>2) +/* SD_STATUS2 0x18012184 */ +#define SD_CMD_RESP_INVALID (0x00000001<<1) +#define SD_CMD_RESP_TIMEOUT (0x00000001) +/* SD_BUS_STATUS 0x18012185 */ +#define SD_CLK_TOG_EN (0x00000001<<7) +#define SD_CLK_TOG_STOP (0x00000001<<6) +#define SD_DAT3_0_LEVEL (0x0000000F<<1) +#define SD_CMD_LEVEL (0x00000001<<0) + + +#define WRITE_DATA (0x1) +#define CLR_WRITE_DATA (0x0) +#define SD_EMMC_INT_EN (0x00000001<<2) +#endif diff --git a/drivers/mmc/host/reg_mmc_rtd13xx.h b/drivers/mmc/host/reg_mmc_rtd13xx.h new file mode 100644 index 000000000000..73cd459873ae --- /dev/null +++ b/drivers/mmc/host/reg_mmc_rtd13xx.h @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2013 Realtek Semiconductors, 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 as + * published by the Free Software Foundation. + */ + +#ifndef __REG_MMC_H +#define __REG_MMC_H + +/* eMMC control register definition */ +#define CR_BASE_ADDR (0x00000000) //map to 0x98012000 + +//hank emmc ip register + +#define EMMC_SDMASA_R (CR_BASE_ADDR) +#define EMMC_BLOCKSIZE_R (CR_BASE_ADDR + 0x004) +#define EMMC_BLOCKCOUNT_R (CR_BASE_ADDR + 0x006) +#define EMMC_ARGUMENT_R (CR_BASE_ADDR + 0x008) +#define EMMC_XFER_MODE_R (CR_BASE_ADDR + 0x00c) +#define EMMC_CMD_R (CR_BASE_ADDR + 0x00e) +#define EMMC_RESP01_R (CR_BASE_ADDR + 0x010) +#define EMMC_RESP23_R (CR_BASE_ADDR + 0x014) +#define EMMC_RESP45_R (CR_BASE_ADDR + 0x018) +#define EMMC_RESP67_R (CR_BASE_ADDR + 0x01c) +#define EMMC_BUF_DATA_R (CR_BASE_ADDR + 0x020) +#define EMMC_PSTATE_REG (CR_BASE_ADDR + 0x024) +#define EMMC_HOST_CTRL1_R (CR_BASE_ADDR + 0x028) +#define EMMC_PWR_CTRL_R (CR_BASE_ADDR + 0x029) +#define EMMC_BGAP_CTRL_R (CR_BASE_ADDR + 0x02a) +#define EMMC_CLK_CTRL_R (CR_BASE_ADDR + 0x02c) +#define EMMC_TOUT_CTRL_R (CR_BASE_ADDR + 0x02e) +#define EMMC_SW_RST_R (CR_BASE_ADDR + 0x02f) +#define EMMC_NORMAL_INT_STAT_R (CR_BASE_ADDR + 0x030) +#define EMMC_ERROR_INT_STAT_R (CR_BASE_ADDR + 0x032) +#define EMMC_NORMAL_INT_STAT_EN_R (CR_BASE_ADDR + 0x034) +#define EMMC_ERROR_INT_STAT_EN_R (CR_BASE_ADDR + 0x036) +#define EMMC_NORMAL_INT_SIGNAL_EN_R (CR_BASE_ADDR + 0x038) +#define EMMC_ERROR_INT_SIGNAL_EN_R (CR_BASE_ADDR + 0x03a) +#define EMMC_AUTO_CMD_STAT_R (CR_BASE_ADDR + 0x03c) +#define EMMC_HOST_CTRL2_R (CR_BASE_ADDR + 0x03e) +#define EMMC_ADMA_ERR_STAT_R (CR_BASE_ADDR + 0x054) +#define EMMC_ADMA_SA_LOW_R (CR_BASE_ADDR + 0x058) +#define EMMC_AT_CTRL_R (CR_BASE_ADDR + 0x240) + +#define EMMC_MSHC_CTRL_R (CR_BASE_ADDR + 0x208) +#define EMMC_CMD_CONFLICT_CHECK BIT(0) + +#define EMMC_CTRL_R (CR_BASE_ADDR + 0x22c) +//hank emmc wrapper register +#define EMMC_CP (CR_BASE_ADDR + 0x41c) +#define EMMC_OTHER1 (CR_BASE_ADDR + 0x420) +#define EMMC_ISR (CR_BASE_ADDR + 0x424) //unused in hank +#define EMMC_ISREN (CR_BASE_ADDR + 0x428) //unused in hank +#define EMMC_DUMMY_SYS (CR_BASE_ADDR + 0x42c) +#define EMMC_AHB (CR_BASE_ADDR + 0x430) +#define EMMC_DBG (CR_BASE_ADDR + 0x444) +#define EMMC_PP_BIST_CTL (CR_BASE_ADDR + 0x460) +#define EMMC_IP_BIST_CTL (CR_BASE_ADDR + 0x464) +#define EMMC_PP_BIST_STS (CR_BASE_ADDR + 0x468) +#define EMMC_IP_BIST_STS (CR_BASE_ADDR + 0x46c) +#define EMMC_CKGEN_CTL (CR_BASE_ADDR + 0x478) +#define EMMC_CARD_SIG (CR_BASE_ADDR + 0x484) +#define EMMC_DQS_CTRL1 (CR_BASE_ADDR + 0x498) +#define EMMC_DQS_CTRL2 (CR_BASE_ADDR + 0x49c) +#define EMMC_IP_DESC0 (CR_BASE_ADDR + 0x4a0) +#define EMMC_IP_DESC1 (CR_BASE_ADDR + 0x4a4) +#define EMMC_IP_DESC2 (CR_BASE_ADDR + 0x4a8) +#define EMMC_IP_DESC3 (CR_BASE_ADDR + 0x4ac) +#define EMMC_PROTECT0 (CR_BASE_ADDR + 0x4c0) +#define EMMC_PROTECT1 (CR_BASE_ADDR + 0x4c4) +#define EMMC_PROTECT2 (CR_BASE_ADDR + 0x4c8) +#define EMMC_PROTECT3 (CR_BASE_ADDR + 0x4cc) +#define EMMC_SWC_SEL_CHK (CR_BASE_ADDR + 0x4e4) +#define EMMC_DUMMY_SYS1 (CR_BASE_ADDR + 0x500) +#define EMMC_CLK_DET_PLLEMMC (CR_BASE_ADDR + 0x504) +#define EMMC_DQ_CTRL_SET (CR_BASE_ADDR + 0x50c) +#define EMMC_WDQ_CTRL0 (CR_BASE_ADDR + 0x510) +#define EMMC_WDQ_CTRL1 (CR_BASE_ADDR + 0x514) +#define EMMC_WDQ_CTRL2 (CR_BASE_ADDR + 0x518) +#define EMMC_WDQ_CTRL3 (CR_BASE_ADDR + 0x51c) +#define EMMC_WDQ_CTRL4 (CR_BASE_ADDR + 0x520) +#define EMMC_WDQ_CTRL5 (CR_BASE_ADDR + 0x524) +#define EMMC_WDQ_CTRL6 (CR_BASE_ADDR + 0x528) +#define EMMC_WDQ_CTRL7 (CR_BASE_ADDR + 0x52c) +#define EMMC_RDQ_CTRL0 (CR_BASE_ADDR + 0x530) +#define EMMC_RDQ_CTRL1 (CR_BASE_ADDR + 0x534) +#define EMMC_RDQ_CTRL2 (CR_BASE_ADDR + 0x538) +#define EMMC_RDQ_CTRL3 (CR_BASE_ADDR + 0x53c) +#define EMMC_RDQ_CTRL4 (CR_BASE_ADDR + 0x540) +#define EMMC_RDQ_CTRL5 (CR_BASE_ADDR + 0x544) +#define EMMC_RDQ_CTRL6 (CR_BASE_ADDR + 0x548) +#define EMMC_RDQ_CTRL7 (CR_BASE_ADDR + 0x54c) +#define EMMC_CMD_CTRL_SET (CR_BASE_ADDR + 0x550) +#define EMMC_WCMD_CTRL (CR_BASE_ADDR + 0x554) +#define EMMC_RCMD_CTRL (CR_BASE_ADDR + 0x558) +#define EMMC_PLL_STATUS (CR_BASE_ADDR + 0x55c) + +#define EMMC_PON_DES0 (CR_BASE_ADDR + 0x800) +#define EMMC_PON_DES1 (CR_BASE_ADDR + 0x804) +#define EMMC_PON_DES2 (CR_BASE_ADDR + 0x808) +#define EMMC_PON_CTRL (CR_BASE_ADDR + 0x80c) +#define EMMC_PON_ID (CR_BASE_ADDR + 0x810) +#define EMMC_PON_ADDR (CR_BASE_ADDR + 0x814) +#define EMMC_PON_ST (CR_BASE_ADDR + 0x818) +#define EMMC_PON_SAVE (CR_BASE_ADDR + 0x81c) +#define EMMC_PON_DBUS_SLV (CR_BASE_ADDR + 0x820) +#define EMMC_PON_DBG_CTRL (CR_BASE_ADDR + 0x824) +#define EMMC_PON_DBUS_SLV_DBG (CR_BASE_ADDR + 0x828) +#define EMMC_PON_MEM (CR_BASE_ADDR + 0x82c) +#define EMMC_PON_DBG0 (CR_BASE_ADDR + 0x830) +#define EMMC_PON_DBG1 (CR_BASE_ADDR + 0x834) +#define EMMC_PON_DBG2 (CR_BASE_ADDR + 0x838) +#define EMMC_PON_DBG3 (CR_BASE_ADDR + 0x83c) +#define EMMC_PON_DBG_CTRL1 (CR_BASE_ADDR + 0x840) + +#define EMMC_HD_SEM (CR_BASE_ADDR + 0x900) + +//0x98012030 status bitmap +#define EMMC_STATUS_ALL (0xffff) +#define EMMC_ERR_INTERRUPT BIT(15) +#define EMMC_CQE_EVENT BIT(14) +#define EMMC_FX_EVENT BIT(13) +#define EMMC_RE_TUNE_EVENT BIT(12) +#define EMMC_INT_C BIT(11) +#define EMMC_INT_B BIT(10) +#define EMMC_INT_A BIT(9) +#define EMMC_CARD_INTERRUPT BIT(8) +#define EMMC_CARD_REMOVAL BIT(7) +#define EMMC_CARD_INSERTION BIT(6) +#define EMMC_BUF_RD_READY BIT(5) +#define EMMC_BUF_WR_READY BIT(4) +#define EMMC_DMA_INTERRPT BIT(3) +#define EMMC_BGAP_EVENT BIT(2) +#define EMMC_XFER_COMPLETE BIT(1) +#define EMMC_CMD_COMPLETE BIT(0) + +//0x98012032 error bitmap +#define EMMC_VENDOR_ERR3 BIT(15) +#define EMMC_VENDOR_ERR2 BIT(14) +#define EMMC_VENDOR_ERR1 BIT(13) +#define EMMC_BOOT_ACK_ERR BIT(12) +#define EMMC_RESP_ERR BIT(11) +#define EMMC_TUNING_ERR BIT(10) +#define EMMC_ADMA_ERR BIT(9) +#define EMMC_AUTO_CMD_ERR BIT(8) +#define EMMC_CUR_LMT_ERR BIT(7) +#define EMMC_DATA_END_BIT_ERR BIT(6) +#define EMMC_DATA_CRC_ERR BIT(5) +#define EMMC_DATA_TOUT_ERR BIT(4) +#define EMMC_CMD_IDX_ERR BIT(3) +#define EMMC_CMD_END_BIT_ERR BIT(2) +#define EMMC_CMD_CRC_ERR BIT(1) +#define EMMC_CMD_TOUT_ERR BIT(0) + +//0x98012034 status enable bitmap +#define EMMC_CQE_EVENT_STAT_EN BIT(14) +#define EMMC_FX_EVENT_STAT_EN BIT(13) +#define EMMC_RE_TUNE_EVENT_STAT_EN BIT(12) +#define EMMC_INT_C_STAT_EN BIT(11) +#define EMMC_INT_B_STAT_EN BIT(10) +#define EMMC_INT_A_STAT_EN BIT(9) +#define EMMC_CARD_INTERRUPT_STAT_EN BIT(8) +#define EMMC_CARD_REMOVAL_STAT_EN BIT(7) +#define EMMC_CARD_INSERTION_STAT_EN BIT(6) +#define EMMC_BUF_RD_READY_STAT_EN BIT(5) +#define EMMC_BUF_WR_READY_STAT_EN BIT(4) +#define EMMC_DMA_INTERRPT_STAT_EN BIT(3) +#define EMMC_BGAP_EVENT_STAT_EN BIT(2) +#define EMMC_XFER_COMPLETE_STAT_EN BIT(1) +#define EMMC_CMD_COMPLETE_STAT_EN BIT(0) + +//0x98012036 error status enable bitmap +#define EMMC_VENDOR_ERR_STAT_EN3 BIT(15) +#define EMMC_VENDOR_ERR_STAT_EN2 BIT(14) +#define EMMC_VENDOR_ERR_STAT_EN1 BIT(13) +#define EMMC_BOOT_ACK_ERR_STAT_EN BIT(12) +#define EMMC_RESP_ERR_STAT_EN BIT(11) +#define EMMC_TUNING_ERR_STAT_EN BIT(10) +#define EMMC_ADMA_ERR_STAT_EN BIT(9) +#define EMMC_AUTO_CMD_ERR_STAT_EN BIT(8) +#define EMMC_CUR_LMT_ERR_STAT_EN BIT(7) +#define EMMC_DATA_END_BIT_ERR_STAT_EN BIT(6) +#define EMMC_DATA_CRC_ERR_STAT_EN BIT(5) +#define EMMC_DATA_TOUT_ERR_STAT_EN BIT(4) +#define EMMC_CMD_IDX_ERR_STAT_EN BIT(3) +#define EMMC_CMD_END_BIT_ERR_STAT_EN BIT(2) +#define EMMC_CMD_CRC_ERR_STAT_EN BIT(1) +#define EMMC_CMD_TOUT_ERR_STAT_EN BIT(0) + +//0x98012038 signal interrupt enable +#define EMMC_CQE_EVENT_SIGNAL_EN BIT(14) +#define EMMC_FX_EVENT_SIGNAL_EN BIT(13) +#define EMMC_RE_TUNE_EVENT_SIGNAL_EN BIT(12) +#define EMMC_INT_C_SIGNAL_EN BIT(11) +#define EMMC_INT_B_SIGNAL_EN BIT(10) +#define EMMC_INT_A_SIGNAL_EN BIT(9) +#define EMMC_CARD_INTERRUPT_SIGNAL_EN BIT(8) +#define EMMC_CARD_REMOVAL_SIGNAL_EN BIT(7) +#define EMMC_CARD_INSERTION_SIGNAL_EN BIT(6) +#define EMMC_BUF_RD_READY_SIGNAL_EN BIT(5) +#define EMMC_BUF_WR_READY_SIGNAL_EN BIT(4) +#define EMMC_DMA_INTERRPT_SIGNAL_EN BIT(3) +#define EMMC_BGAP_EVENT_SIGNAL_EN BIT(2) +#define EMMC_XFER_COMPLETE_SIGNAL_EN BIT(1) +#define EMMC_CMD_COMPLETE_SIGNAL_EN BIT(0) + +//0x9801203a error ssignal enable bitmap +#define EMMC_VENDOR_ERR_SIGNAL_EN3 BIT(15) +#define EMMC_VENDOR_ERR_SIGNAL_EN2 BIT(14) +#define EMMC_VENDOR_ERR_SIGNAL_EN1 BIT(13) +#define EMMC_BOOT_ACK_ERR_SIGNAL_EN BIT(12) +#define EMMC_RESP_ERR_SIGNAL_EN BIT(11) +#define EMMC_TUNING_ERR_SIGNAL_EN BIT(10) +#define EMMC_ADMA_ERR_SIGNAL_EN BIT(9) +#define EMMC_AUTO_CMD_ERR_SIGNAL_EN BIT(8) +#define EMMC_CUR_LMT_ERR_SIGNAL_EN BIT(7) +#define EMMC_DATA_END_BIT_ERR_SIGNAL_EN BIT(6) +#define EMMC_DATA_CRC_ERR_SIGNAL_EN BIT(5) +#define EMMC_DATA_TOUT_ERR_SIGNAL_EN BIT(4) +#define EMMC_CMD_IDX_ERR_SIGNAL_EN BIT(3) +#define EMMC_CMD_END_BIT_ERR_SIGNAL_EN BIT(2) +#define EMMC_CMD_CRC_ERR_SIGNAL_EN BIT(1) +#define EMMC_CMD_TOUT_ERR_STAT_EN BIT(0) + +#define EMMC_ALL_NORMAL_STAT_EN (0xfeff) +#define EMMC_ALL_ERR_STAT_EN (0xffff) //enablle all error interrupt in 0x98012036 +#define EMMC_ALL_SIGNAL_STAT_EN (0xfeff) +#define EMMC_ALL_ERR_SIGNAL_EN (0xffff) //enable all singal error interrupt in 0x9801203a + + +#define CMD_IDX_MASK(x) ((x >> 8)&0x3f) + +//0x9801200e +#define EMMC_RESP_TYPE_SELECT 0 +#define EMMC_CMD_TYPE 6 +#define EMMC_NO_RESP 0x0 +#define EMMC_RESP_LEN_136 0x1 +#define EMMC_RESP_LEN_48 0x2 +#define EMMC_RESP_LEN_48B 0x3 +#define EMMC_CMD_CHK_RESP_CRC (1<<3) +#define EMMC_CMD_IDX_CHK_ENABLE (1<<4) +#define EMMC_DATA (1<<5) +#define EMMC_ABORT_CMD 0x3 +#define EMMC_RESUME_CMD 0x2 +#define EMMC_SUSPEND_CMD 0x1 +#define EMMC_NORMAL_CMD 0x0 + +//0x98012028 +#define EMMC_DMA_SEL 3 +#define EMMC_SDMA (0x0) +#define EMMC_ADMA2_32 (0x2) +#define EMMC_ADMA2_64 (0x3) +#define EMMC_EXT_DAT_XFER BIT(5) +#define EMMC_EXT_DAT_XFER_MASK (~EMMC_EXT_DAT_XFER & 0xff) +#define EMMC_HIGH_SPEED_EN BIT(2) +#define EMMC_HIGH_SPEED_MASK ((~BIT(2)) & 0xff) +#define EMMC_UHS_MODE_SEL_MASK ((~(BIT(0)|BIT(1)|BIT(2))) & 0xffff) +#define EMMC_DAT_XFER_WIDTH BIT(1) +#define EMMC_DAT_XFER_WIDTH_MASK (~EMMC_DAT_XFER_WIDTH & 0xff) +#define EMMC_BUS_WIDTH_8 EMMC_EXT_DAT_XFER +#define EMMC_BUS_WIDTH_4 EMMC_DAT_XFER_WIDTH +#define EMMC_BUS_WIDTH_1 (0) +#define EMMC_DMA_SEL_CLR (0xff & (~(0x3<> 2) + +/* SD_STATUS2 */ +#define SD_CMD_RESP_INVALID (0x01 << 1) +#define SD_CMD_RESP_TIMEOUT (0x01) + +/* SD_BUS_STATUS */ +#define SD_CLK_TOG_EN (0x01 << 7) +#define SD_CLK_TOG_STOP (0x01 << 6) +#define SD_DAT3_0_LEVEL (0x0F << 1) +#define SD_CMD_LEVEL (0x01 << 0) + +#define WRITE_DATA (0x01) +#define CLR_WRITE_DATA (0x00) + +/* CR_IP_CARD_INT_EN */ + +/* CR_SD_ISR */ +#define ISRSTA_INT1 (0x01 << 1) //card end +#define ISRSTA_INT2 (0x01 << 2) //card error +#define ISRSTA_INT4 (0x01 << 4) //DMA done + +/* CR_SD_ISREN */ +#define ISRSTA_INT1EN (0x01 << 1) //card end +#define ISRSTA_INT2EN (0x01 << 2) //card error +#define ISRSTA_INT4EN (0x01 << 4) //DMA done + +#endif /* DRIVERS_MMC_HOST_RTK_SDMMC_REG_H_ */ diff --git a/drivers/mmc/host/rtk-sdmmc.c b/drivers/mmc/host/rtk-sdmmc.c new file mode 100644 index 000000000000..67931a669d1e --- /dev/null +++ b/drivers/mmc/host/rtk-sdmmc.c @@ -0,0 +1,3542 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek SD/MMC/mini SD card driver + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core/card.h" +#include "rtk-sdmmc-reg.h" +#include "rtk-sdmmc.h" + +#define DRIVER_NAME "rtk-sdmmc" +#define BANNER "Realtek SD/MMC Host Driver" + +#define SD_ALLOC_LENGTH 2048 +#define MAX_PHASE 31 +#define TUNING_CNT 3 + +/* #define CMD25_WO_STOP_COMMAND */ + +#define PM_SD_SUSPEND_ON 0 +#define PM_SD_SUSPEND_FREEZE 1 +#define PM_SD_SUSPEND_STANDBY 2 +#define PM_SD_SUSPEND_MEM 3 +#define PM_SD_SUSPEND_MIN PM_SD_SUSPEND_FREEZE +#define PM_SD_SUSPEND_MAX 4 + +enum eINT_enable_mode { + CMD_RSP_ONLY = 0, + DATA_ONLY, + CMD_RSP_DATA_WRITE, + CMD_RSP_DATA_READ, + CMD_RSP_DATA_WRITE_TUNNING, + CMD_RSP_DATA_READ_TUNNING, + DATA_WRITE_ONLY, + DATA_READ_ONLY, +}; + +static volatile u32 data_xfer_mode; + +DECLARE_COMPLETION(rtk_sdmmc_wait); + +#ifdef CONFIG_MMC_RTK_EMMC +int get_RTK_initial_flag(void); +#endif + +static unsigned int sd_in_receive_data_state; //CMD25_WO_STOP_COMMAND +static unsigned int sd_current_blk_address; //CMD25_WO_STOP_COMMAND +static u32 *dma_phy_addr; +static u32 *dma_virt_addr; +static unsigned int g_crinit; +static unsigned int sdmmc_rca; +static unsigned int mmc_detected; +static u8 g_cmd[6]; +bool suspend_SD_insert_flag; +int poll; +int pre_cmd; +static volatile u32 wait_stop_command_irq_done; +static volatile u32 do_stop_command_wo_complete; +static struct semaphore cr_sd_sem; + +#ifdef CMD25_WO_STOP_COMMAND +struct task_struct *rtk_SD_task; +struct mmc_command cmd12_stop_cmd; +#endif + +struct rtk_sdmmc_host *rtk_global_host; +bool INT4_flag; +bool CMD8_SD1; +bool CMD55_MMC; +int driving_capacity; +bool suspend_flag; +int mini_SD; +bool broken_flag; +unsigned int g_ro; +int irq_error_bit; +int clk_disabled; +bool re_initialize; +bool compatible_flag; +static struct clk *clk_cr; +static struct clk *clk_sd_ip; +static struct reset_control *rstc_cr; + +static enum rtd_chip_id chip_id; + +static struct scatterlist *sdmmc_alloc_sg(int sg_len, gfp_t gfp) +{ + struct scatterlist *sg; + + sg = kmalloc_array(sg_len, sizeof(*sg), gfp); + if (sg) + sg_init_table(sg, sg_len); + + return sg; +} + +void rtk_sdmmc_wait_stop_cmd_irq_done(void) +{ + unsigned long timeout; + unsigned int istimeout = 1; + timeout = jiffies + msecs_to_jiffies(100); + + while( time_before(jiffies, timeout) ) { + //printk(KERN_ERR "<<%d>>(%d)\n", __LINE__, wait_stop_command_irq_done); + if ( wait_stop_command_irq_done == 0 ) { + istimeout = 0; + break;; + } + } + + do_stop_command_wo_complete = 0; + if ( istimeout ) { + printk(KERN_ERR "****** WAIT wait_stop_command_irq_done TIMEOUT(%d,%d))\n", + do_stop_command_wo_complete, wait_stop_command_irq_done);\ + } +} + +static void rtk_sdmmc_pad_pwrctrl(struct rtk_sdmmc_host *rtk_host, int voltage) +{ + void __iomem *pll_base = rtk_host->pll; + void __iomem *isopad_base = rtk_host->isopad; + u32 reg_sel3318; + + /* [14:13] 11:1.8v 01:3.3v*/ + reg_sel3318 = (readl(pll_base+CR_PLL_SD1) & 0x00006000) >> 13; + + switch (voltage) { + case MMC_SIGNAL_VOLTAGE_330: + if (reg_sel3318 == 0x1) { + pr_err("[MSG] %s 1E0 = %x reg_sel3318 = %x keep 3.3v\n", + __func__, readl(pll_base+CR_PLL_SD1), reg_sel3318); + } else if (reg_sel3318 == 0x3){ + writel((readl(pll_base+CR_PLL_SD1) & 0xffffdfff) , pll_base+CR_PLL_SD1); + mdelay(1); + writel((readl(isopad_base+0x78) | 0x02001000) , isopad_base+0x78); + writel((readl(isopad_base+0x7c) | 0x00080040) , isopad_base+0x7c); + writel((readl(isopad_base+0x80) | 0x02001000) , isopad_base+0x80); + mdelay(1); + writel((readl(pll_base+CR_PLL_SD1) & 0xFFFF9FFF) , pll_base+CR_PLL_SD1); + mdelay(1); + writel((readl(pll_base+CR_PLL_SD1) | 0x00002000) , pll_base+CR_PLL_SD1); + pr_err("[MSG] %s 1E0 = %x reg_sel3318 = %x switch 1.8v to 3.3v\n", + __func__, readl(pll_base+CR_PLL_SD1), reg_sel3318); + } + break; + case MMC_SIGNAL_VOLTAGE_180: + if (reg_sel3318 == 0x1) { + writel((readl(pll_base+CR_PLL_SD1) & 0xffff9fff) , pll_base+CR_PLL_SD1); + mdelay(1); + writel((readl(pll_base+CR_PLL_SD1) | 0x00004000) , pll_base+CR_PLL_SD1); + mdelay(1); + writel((readl(pll_base+CR_PLL_SD1) | 0x00006000) , pll_base+CR_PLL_SD1); + mdelay(1); + writel((readl(isopad_base+0x78) & 0xfdffefff) , isopad_base+0x78); + writel((readl(isopad_base+0x7c) & 0xfff7ffbf) , isopad_base+0x7c); + writel((readl(isopad_base+0x80) & 0xfdffefff) , isopad_base+0x80); + pr_err("[MSG] %s 1E0 = %x reg_sel3318 = %x switch 3.3v to 1.8v\n", + __func__, readl(pll_base+CR_PLL_SD1), reg_sel3318); + } else if (reg_sel3318 == 0x3){ + pr_err("[MSG] %s 1E0 = %x reg_sel3318 = %x keep 1.8v\n", + __func__, readl(pll_base+CR_PLL_SD1), reg_sel3318); + } + break; + default: + pr_err("[MSG] %s 1E0 = %x reg_sel3318 = %x invalid argument\n", + __func__, readl(pll_base+CR_PLL_SD1), reg_sel3318); + } +} + +void card_broken(struct rtk_sdmmc_host *rtk_host) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + + printk(KERN_ERR "SD Card is broken!!!\n"); + + writel(0x0, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0xff, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state + writeb(0x40, sdmmc_base + SD_BUS_STATUS); + mdelay(10); + writeb(0x3b, sdmmc_base + CARD_CLOCK_EN_CTL); + rtk_host->ops->card_power(rtk_host, 0); + rtk_sdmmc_sync(rtk_host); +} + +void remove_sdcard(struct rtk_sdmmc_host *rtk_host) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + void __iomem *isopad_base = rtk_host->isopad; + u32 det_time = 0; + unsigned int tmp = 0; + + rtk_host->ins_event = EVENT_REMOV; + rtk_host->rtflags &= ~RTKCR_FCARD_DETECTED; + det_time = 1; + + if(down_trylock(&cr_sd_sem)!=0); //check if the lock is occupied, if not, then occupied + up(&cr_sd_sem); //release the lock + + if (chip_id == CHIP_ID_RTD1619B) { + rtk_sdmmc_pad_pwrctrl(rtk_host, MMC_SIGNAL_VOLTAGE_330); + /* Set pad driving */ + tmp = ((readl(isopad_base + 0x78) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base + 0x78); + tmp = ((readl(isopad_base + 0x7c) & 0xfff81fc0) | 0x0003601b); + writel(tmp, isopad_base + 0x7c); + tmp = ((readl(isopad_base + 0x80) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base+0x80); + } else if (chip_id == CHIP_ID_RTD1319) { + tmp = (0x003003) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x003003<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x003003) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + } else if (chip_id == CHIP_ID_RTD1619) { + tmp = (0x3003003 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x00300300, isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x3; + writel(tmp,isopad_base + 0x14); + } else if (chip_id == CHIP_ID_RTD1395) { + writel(0x198CD99B, isopad_base + 0x34); + writel(0x000CF99F, isopad_base + 0x38); + writel(0x000CF99F, isopad_base + 0x3c); + } + + writel(0x0, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0xff, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state + + writeb(0x3b, sdmmc_base + CARD_CLOCK_EN_CTL); + + rtk_host->ops->card_power(rtk_host, 0); //power off, Jim add + rtk_sdmmc_sync(rtk_host); + + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + mmc_detect_change(rtk_host->mmc, msecs_to_jiffies(det_time)); +} + +static void rtk_sdmmc_shutdown(struct platform_device *pdev) +{ + u32 det_time = 0; + u32 reginfo = 0; + struct device *dev = &pdev->dev; + struct mmc_host *mmc = dev_get_drvdata(dev); + struct rtk_sdmmc_host *rtk_host = mmc_priv(mmc); + void __iomem *sdmmc_base = rtk_host->sdmmc; + + printk(KERN_ERR "[SD] Realtek SD card reader shutdown!!\n"); + del_timer_sync(&rtk_host->timer); + + pm_runtime_force_suspend(dev); + reginfo = readl(rtk_host->gpiodir+GPDATI1); + if(!(reginfo & 0x8)) { + printk(KERN_ERR "[SD] Realtek SD turn off card power!!\n"); + suspend_SD_insert_flag=true; + rtk_host->ins_event = EVENT_REMOV; + rtk_host->rtflags &= ~RTKCR_FCARD_DETECTED; + det_time = 1; + writel(readl(sdmmc_base + 0x20) & (~0x01), sdmmc_base + 0x20); //modified by JIM 2016.9.1 for power saving, set L4 gated enabled + writel(readl(sdmmc_base + 0x20) | 0x00000001, sdmmc_base + 0x20); //reset the DMA + writel(0x0, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0xff, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state + + rtk_host->ops->card_power(rtk_host, 0); //power off, Jim add + + rtk_sdmmc_sync(rtk_host); + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + mmc_detect_change(rtk_host->mmc, msecs_to_jiffies(det_time)); + } +} + +#ifdef CONFIG_PM +static int rtk_sdmmc_pm_suspend(struct device *dev) +{ + int ret = 0; + u32 det_time = 0; + + u32 reginfo = 0; + struct mmc_host *mmc = dev_get_drvdata(dev); + struct rtk_sdmmc_host *rtk_host = mmc_priv(mmc); + void __iomem *sdmmc_base = rtk_host->sdmmc; + suspend_flag = true; + + del_timer_sync(&rtk_host->timer); + +#ifdef CMD25_WO_STOP_COMMAND + del_timer_sync(&rtk_host->rtk_sdmmc_stop_cmd); +#endif + + ret = pm_runtime_force_suspend(dev); + reginfo = readl(rtk_host->gpiodir+GPDATI1); + if(!(reginfo & 0x8)) { + printk(KERN_ERR "[SD] Realtek SD turn off card power!!\n"); + suspend_SD_insert_flag=true; + rtk_host->ins_event = EVENT_REMOV; + rtk_host->rtflags &= ~RTKCR_FCARD_DETECTED; + det_time = 1; + + writel(readl(sdmmc_base + 0x20) & (~0x01), sdmmc_base + 0x20); //modified by JIM 2016.9.1 for power saving, set L4 gated enabled + writel(readl(sdmmc_base + 0x20) | 0x00000001, sdmmc_base + 0x20); //reset the DMA + writel(0x0, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0xff, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state + + rtk_host->ops->card_power(rtk_host, 0); //power off, Jim add + + rtk_sdmmc_sync(rtk_host); + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + mmc_detect_change(rtk_host->mmc, msecs_to_jiffies(det_time)); + } else { + suspend_SD_insert_flag=false; + } + + return ret; +} + +static int rtk_sdmmc_pm_resume(struct device *dev) +{ + int ret = 0; + u32 reginfo = 0; + u32 det_time = 0; + struct mmc_host *mmc = dev_get_drvdata(dev); + struct rtk_sdmmc_host *rtk_host = mmc_priv(mmc); + void __iomem *pll_base = rtk_host->pll; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + re_initialize = false; + //in 1395 platform, system will turn off the SD clock if there is no SD card. Therefore, we must add this check for fear that invalid address access + reginfo = readl(rtk_host->gpiodir + GPDATI1); + if (reginfo & 0x8) { + + void __iomem *gpiodir_base = rtk_host->gpiodir; + + reset_control_deassert(rstc_cr); + clk_prepare_enable(clk_cr); + clk_prepare_enable(clk_sd_ip); + + if (chip_id == CHIP_ID_RTD1319) + writel(readl(gpiodir_base + 0x64) | 0xc, gpiodir_base + 0x64); //open the ldo enable + else if (chip_id == CHIP_ID_RTD1619B) + writel(readl(gpiodir_base + 0xc4) | 0xc, gpiodir_base + 0xc4); + + writel(0x00000007, pll_base + CR_PLL_SD4); + + if (chip_id == CHIP_ID_RTD1319) { + while((readl(rtk_host->sdmmc+0x2c)&0x1)==0) + printk(KERN_INFO "wait until clk open...\n"); + } else if (chip_id == CHIP_ID_RTD1619B) { + while((readl(rtk_host->sdmmc + 0xb4) & 0x80000000) == 0) + printk(KERN_INFO "wait until clk open...\n"); + } + + } else if (!(reginfo & 0x8) && suspend_SD_insert_flag == false) { //this case is to handle that SD card is plugged during suspend + rtk_sdmmc_open_clk(mmc); + re_initialize = true; + } + + rtk_sdmmc_hw_initial(rtk_host); //suspend will cause poweroff and the SD PLL will be set as default, so we need to initial the SD PLL and clock before resume + + reginfo = readl(rtk_host->gpiodir + GPDATI1); + if (!(reginfo & 0x8) && suspend_SD_insert_flag == true) { + printk(KERN_ERR "[SD] Realtek SD turn on card power!!\n"); + rtk_host->rtflags &= ~RTKCR_FCARD_DETECTED; + rtk_host->wp = 0; + + rtk_host->ops->card_power(rtk_host, 1); //power on, Jim add + + rtk_host->ins_event = EVENT_INSER; + rtk_host->rtflags |= RTKCR_FCARD_DETECTED; + det_time = 1; + writel(0x00000000, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0x00, sdmmc_base + CR_CARD_STOP); //SD Card module transfer no stop + writeb(0x02, sdmmc_base + CARD_SELECT); //Specify the current active card module for the coming data transfer, bit 2:0 = 010 + writeb(0x04, sdmmc_base + CR_CARD_OE); //arget module is SD/MMC card module, bit 2 =1 + writeb(0x04, sdmmc_base + CARD_CLOCK_EN_CTL); //SD Card Module Clock Enable, bit 2 = 1 + writeb(0xD0, sdmmc_base + SD_CONFIGURE1); + + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_400KHZ); + + writeb(0x00, sdmmc_base + SD_STATUS2); + rtk_sdmmc_sync(rtk_host); + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + mmc_detect_change(rtk_host->mmc, msecs_to_jiffies(det_time)); + } + + ret = pm_runtime_force_resume(dev); + timer_setup(&rtk_host->timer, rtk_sdmmc_timeout, 0); + +#ifdef CMD25_WO_STOP_COMMAND + timer_setup(&rtk_host->rtk_sdmmc_stop_cmd, rtk_sdmmc_cmd12_fun, 0); +#endif + rtk_sdmmc_sync(rtk_host); + + if(re_initialize) { //this case is to handle that SD card is plugged during suspend + rtk_sdmmc_get_cd(mmc); + re_initialize = false; + } + + suspend_flag = false; + + //in 1395 platform, we turn on the clk in the begining of resume process if no SD card, we have to close the clk after resume + if(reginfo & 0x8) { + void __iomem *gpiodir_base = rtk_host->gpiodir; + + writel(0x00000000, pll_base + CR_PLL_SD4); + clk_disable_unprepare(clk_cr); + clk_disable_unprepare(clk_sd_ip); + reset_control_assert(rstc_cr); + + if (chip_id == CHIP_ID_RTD1319) + writel(readl(gpiodir_base + 0x64) & 0xfffffff3, gpiodir_base + 0x64); //close the ldo enable to power saving + else if (chip_id == CHIP_ID_RTD1619B) + writel(readl(gpiodir_base + 0xc4) & 0xfffffff3, gpiodir_base + 0xc4); + } + + return ret; +} +static const struct dev_pm_ops rtk_sdmmc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rtk_sdmmc_pm_suspend, rtk_sdmmc_pm_resume) +}; +#endif + +static void rtk_sdmmc_reset(struct rtk_sdmmc_host *rtk_host) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + + writel(0x00000000, sdmmc_base + CR_SD_DMA_CTL3); + data_xfer_mode = CMD_RSP_ONLY; + writel(0x00000016, sdmmc_base + CR_SD_ISREN); + writel(0x00000007, sdmmc_base + CR_SD_ISREN); + writeb(0x00, sdmmc_base + SD_TRANSFER); + writeb(0xFF, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state. + writeb(0x00, sdmmc_base + CR_CARD_STOP); //SD Card module transfer start. +} + +void rtk_sdmmc_sync(struct rtk_sdmmc_host *rtk_host) { + writel(0x00000000, rtk_host->sysbrdg + SDMMC_SYNC); +} + +static u8 rtk_sdmmc_get_rsp_type(struct mmc_command* cmd) +{ + u32 rsp_type = 0; + u32 rsp_type_chk = mmc_resp_type(cmd); + + if (rsp_type_chk == MMC_RSP_R1) + rsp_type = SD_R1; + else if (rsp_type_chk == MMC_RSP_R1B) + rsp_type = SD_R1b; + else if (rsp_type_chk == MMC_RSP_R2) + rsp_type = SD_R2; + else if (rsp_type_chk == MMC_RSP_R3) + rsp_type = SD_R3; + else if (rsp_type_chk == MMC_RSP_R6) + rsp_type = SD_R6; + else if (rsp_type_chk == MMC_RSP_R7) + rsp_type = SD_R7; + else + rsp_type = SD_R0; + + return rsp_type; +} + +static u8 rtk_sdmmc_get_rsp_len(u8 rsp_para) +{ + switch(rsp_para & 0x03) { + case 0: + return 0; + case 1: + return 6; + case 2: + return 16; + default: + return 0; + } +} + +static u8 rtk_sdmmc_search_final_phase(struct rtk_sdmmc_host *rtk_host, u32 phase_map) +{ + struct timing_phase_path path[MAX_PHASE + 1]; + struct timing_phase_path swap; + int i = 0; + int j = 0; + int k = 0; + int cont_path_cnt = 0; + int new_block = 1; + int max_len = 0; + int final_path_idx = 0; + u8 final_phase = 0xFF; + + /* Parse phase_map, take it as a bit-ring */ + for (i = 0 ; i < MAX_PHASE + 1 ; i++) { + if (phase_map & (1 << i)) { + if (new_block) { + new_block = 0; + j = cont_path_cnt++; + path[j].start = i; + path[j].end = i; + } else { + path[j].end = i; + } + } else { + new_block = 1; + if (cont_path_cnt) { + /* Calculate path length and middle point */ + int idx = cont_path_cnt - 1; + path[idx].len = path[idx].end - path[idx].start + 1; + path[idx].mid = path[idx].start + path[idx].len / 2; + } + } + } + + if (cont_path_cnt == 0) { + rtk_sdmmc_debug(" %s No continuous phase path\n", __func__); + goto finish; + } else { + /* Calculate last continuous path length and middle point */ + int idx = cont_path_cnt - 1; + path[idx].len = path[idx].end - path[idx].start + 1; + path[idx].mid = path[idx].start + path[idx].len / 2; + } + + /* Connect the first and last continuous paths if they are adjacent */ + if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { + /* Using negative index */ + path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; + path[0].len += path[cont_path_cnt - 1].len; + path[0].mid = path[0].start + path[0].len / 2; + /* Convert negative middle point index to positive one */ + if (path[0].mid < 0) + path[0].mid += MAX_PHASE + 1; + cont_path_cnt--; + } + + for (k = 0 ; k < cont_path_cnt ; ++k) { + for (i = 0 ; i < cont_path_cnt - 1 - k ; ++i) { + if (path[i].len < path[i+1].len) { + swap.end = path[i+1].end; + swap.len = path[i+1].len; + swap.mid = path[i+1].mid; + swap.start = path[i+1].start; + + path[i+1].end = path[i].end; + path[i+1].len = path[i].len; + path[i+1].mid = path[i].mid; + path[i+1].start = path[i].start; + + path[i].end = swap.end; + path[i].len = swap.len; + path[i].mid = swap.mid; + path[i].start = swap.start; + } + } + } + + /* Choose the longest continuous phase path */ + max_len = 0; + final_phase = 0; + final_path_idx = 0; + for (i = 0 ; i < cont_path_cnt ; i++) { + if (path[i].len > max_len) { + max_len = path[i].len; + if (max_len > 6) //for compatibility issue, continue len should bigger than 6 + final_phase = (u8)path[i].mid; + else + final_phase = 0xFF; + final_path_idx = i; + } + + rtk_sdmmc_debug("%s path[%d].start = %d\n", __func__, i, path[i].start); + rtk_sdmmc_debug("%s path[%d].end = %d\n", __func__, i, path[i].end); + rtk_sdmmc_debug("%s path[%d].len = %d\n", __func__, i, path[i].len); + rtk_sdmmc_debug("%s path[%d].mid = %d\n", __func__, i, path[i].mid); + } + +finish: + rtk_sdmmc_debug("%s Final chosen phase: %d\n", __func__, final_phase); + return final_phase; +} + +static int rtk_sdmmc_change_tx_phase(struct rtk_sdmmc_host *rtk_host, u8 sample_point) +{ + void __iomem *pll_base = rtk_host->pll; + unsigned int temp_reg = 0; + writel(readl(pll_base + 0x1E0)&0xfffffffd, pll_base + 0x1E0); + temp_reg = readl(pll_base + CR_PLL_SD1); + temp_reg = (temp_reg & ~0x000000F8) | (sample_point << 3); + writel(temp_reg, pll_base + CR_PLL_SD1); + writel(readl(pll_base + 0x1E0)|0x2, pll_base + 0x1E0); + rtk_sdmmc_sync(rtk_host); + udelay(100); + + writeb(readb(rtk_host->sdmmc + SD_CONFIGURE1)&0xef, rtk_host->sdmmc + SD_CONFIGURE1); + return 0; +} + +static int rtk_sdmmc_change_rx_phase(struct rtk_sdmmc_host *rtk_host, u8 sample_point) +{ + void __iomem *pll_base = rtk_host->pll; + unsigned int temp_reg = 0; + writel(readl(pll_base + 0x1E0)&0xfffffffd, pll_base + 0x1E0); + temp_reg = readl(pll_base + CR_PLL_SD1); + temp_reg = (temp_reg & ~0x00001F00) | (sample_point << 8); + writel(temp_reg, pll_base + CR_PLL_SD1); + writel(readl(pll_base + 0x1E0)|0x2, pll_base + 0x1E0); + rtk_sdmmc_sync(rtk_host); + udelay(100); + + writeb(readb(rtk_host->sdmmc + SD_CONFIGURE1)&0xef, rtk_host->sdmmc + SD_CONFIGURE1); + return 0; +} + +static int rtk_sdmmc_tuning_tx_cmd(struct rtk_sdmmc_host *rtk_host, u8 sample_point) +{ + struct mmc_command cmd; + struct sdmmc_cmd_pkt cmd_info; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + rtk_sdmmc_change_tx_phase(rtk_host, sample_point); + + memset(&cmd, 0x00, sizeof(struct mmc_command)); + memset(&cmd_info, 0x00, sizeof(struct sdmmc_cmd_pkt)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = (sdmmc_rca << RCA_SHIFTER); + cmd_info.cmd = &cmd; + cmd_info.rtk_host = rtk_host; + cmd_info.rsp_para2 = 0x41; + cmd_info.rsp_len = rtk_sdmmc_get_rsp_len(0x41); + + rtk_sdmmc_send_cmd_get_rsp(&cmd_info); + pre_cmd=cmd.opcode; + + if (readb(sdmmc_base + SD_TRANSFER) & 0x10) + return -1; + return 0; +} + +static int rtk_sdmmc_tuning_rx_cmd(struct rtk_sdmmc_host *rtk_host, u8 sample_point, struct scatterlist* p_sg) +{ + struct sdmmc_cmd_pkt cmd_info; + struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + rtk_sdmmc_change_rx_phase(rtk_host, sample_point); + mrq.cmd = &cmd; + mrq.data = &data; + mrq.cmd->data = mrq.data; + mrq.data->error = 0; + mrq.data->mrq = &mrq; + + cmd.opcode = MMC_SEND_TUNING_BLOCK; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = p_sg; + data.sg_len = 1; + + mrq.cmd->error = 0; + mrq.cmd->mrq = &mrq; + mrq.cmd->data = mrq.data; + mrq.data->error = 0; + mrq.data->mrq = &mrq; + + memset(&cmd_info, 0x00, sizeof(struct sdmmc_cmd_pkt)); + cmd_info.cmd = mrq.cmd; + cmd_info.rtk_host = rtk_host; + cmd_info.rsp_para2 = rtk_sdmmc_get_rsp_type(cmd_info.cmd); + cmd_info.rsp_len = rtk_sdmmc_get_rsp_len(cmd_info.rsp_para2); + cmd_info.data = mrq.cmd->data; + + rtk_sdmmc_stream(&cmd_info); + pre_cmd=cmd.opcode; + + if (readb(sdmmc_base + SD_STATUS1) & 0x01) + return -1; + + return 0; +} + +static int rtk_sdmmc_tuning_tx(struct rtk_sdmmc_host *rtk_host) +{ + int sample_point; + int ret = 0; + int i = 0; + u32 raw_phase_map[TUNING_CNT] = {0}; + u32 phase_map = 0; + u8 final_phase = 0; + + for (sample_point = 0 ; sample_point <= MAX_PHASE ; sample_point++) { + for (i = 0 ; i < TUNING_CNT ; i++) { + if (!(rtk_host->rtflags & RTKCR_FCARD_DETECTED)) { + ret = -MMC_ERR_RMOVE; + goto out ; + } + + ret = rtk_sdmmc_tuning_tx_cmd(rtk_host, (u8)sample_point); + if (0 == ret) + raw_phase_map[i] |= (1 << sample_point); + } + } + + phase_map = 0xFFFFFFFF; + for (i = 0 ; i < TUNING_CNT ; i++) { + rtk_sdmmc_debug("%s TX raw_phase_map[%d] = 0x%08x\n", __func__, i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + + printk(KERN_DEBUG "%s TX phase_map = 0x%08x\n", __func__, phase_map); + + if (phase_map) { + final_phase = rtk_sdmmc_search_final_phase(rtk_host, phase_map); + rtk_sdmmc_debug("%s final phase = 0x%08x\n", __func__, final_phase); + if (final_phase == 0xFF) { + rtk_sdmmc_debug("%s final phase = 0x%08x\n", __func__, final_phase); + ret = -EINVAL; + goto out ; + } + rtk_sdmmc_change_tx_phase(rtk_host, final_phase); + ret = 0; + goto out ; + } else { + rtk_sdmmc_debug("%s fail !phase_map\n", __func__); + ret = -EINVAL; + goto out ; + } + +out: + return ret; +} + +static int rtk_sdmmc_tuning_rx(struct rtk_sdmmc_host *rtk_host) +{ + int sample_point = 0; + int ret = 0; + int i = 0; + u32 raw_phase_map[TUNING_CNT] = {0}; + u32 phase_map = 0; + u8 final_phase = 0; + u8 *ssr; + struct scatterlist sg; + + ssr = kmalloc(512, GFP_KERNEL | GFP_DMA); + if (!ssr) + return -ENOMEM; + + sg_init_one(&sg, ssr, 512); + for (sample_point = 0 ; sample_point <= MAX_PHASE ; sample_point++) { + for (i = 0 ; i < TUNING_CNT ; i++) { + if (!(rtk_host->rtflags & RTKCR_FCARD_DETECTED)) { + ret = -MMC_ERR_RMOVE; + goto out ; + } + + ret = rtk_sdmmc_tuning_rx_cmd(rtk_host, (u8)sample_point, &sg); + if (0 == ret) + raw_phase_map[i] |= (1 << sample_point); + } + } + + phase_map = 0xFFFFFFFF; + for (i = 0 ; i < TUNING_CNT ; i++) { + rtk_sdmmc_debug("%s RX raw_phase_map[%d] = 0x%08x\n", __func__, i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + printk(KERN_DEBUG "%s RX phase_map = 0x%08x\n", __func__, phase_map); + + if (phase_map) { + final_phase = rtk_sdmmc_search_final_phase(rtk_host, phase_map); + rtk_sdmmc_debug("%s final phase = 0x%08x\n", __func__, final_phase); + if (final_phase == 0xFF) { + rtk_sdmmc_debug("%s final phase = 0x%08x\n", __func__, final_phase); + ret = -EINVAL; + goto out ; + } + rtk_sdmmc_change_rx_phase(rtk_host, final_phase); + ret = 0; + goto out ; + } else { + rtk_sdmmc_debug("%s fail !phase_map\n", __func__); + ret = -EINVAL; + goto out ; + } + +out: + kfree(ssr); + return ret; +} + +static int rtk_sdmmc_wait_voltage_stable_low(struct rtk_sdmmc_host *rtk_host) +{ + u8 status = 0; + u8 i = 0; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + while(1) { + status = readb(sdmmc_base + SD_BUS_STATUS); + + if ((status & (SD_DAT3_0_LEVEL | SD_CMD_LEVEL)) == 0x0) + break; + + msleep(3); + + if (i++>100) + break; + } + + return 0; +} + +static int rtk_sdmmc_wait_voltage_stable_high(struct rtk_sdmmc_host *rtk_host) +{ + u8 status = 0; + u8 i = 0; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + while (1) { + status = readb(sdmmc_base + SD_BUS_STATUS); + if ((status & (SD_DAT3_0_LEVEL | SD_CMD_LEVEL)) == (SD_DAT3_0_LEVEL | SD_CMD_LEVEL)) + break; + msleep(3); + if (i++>100) + break; + } + + return 0; +} + +static void rtk_sdmmc_set_access_mode(struct rtk_sdmmc_host *rtk_host,u8 level) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + u32 tmp_bits = 0; + tmp_bits = readb(sdmmc_base + SD_CONFIGURE1) & ~MODE_SEL_MASK; + + if (level == ACCESS_MODE_SD20) + tmp_bits |= MODE_SEL_SD20; + else if (level == ACCESS_MODE_DDR) + tmp_bits |= MODE_SEL_DDR; + else if (level == ACCESS_MODE_SD30) + tmp_bits |= (MODE_SEL_SD30 | SD30_ASYNC_FIFO_RST); + else + tmp_bits |= MODE_SEL_SD20; + + writeb(tmp_bits, sdmmc_base + SD_CONFIGURE1); +} + +static void rtk_sdmmc_set_bits(struct rtk_sdmmc_host *rtk_host, u8 set_bit) +{ + void *sdmmc_base = rtk_host->sdmmc; + u32 tmp_bits = 0; + tmp_bits = readb(sdmmc_base + SD_CONFIGURE1); + if ((tmp_bits & MASK_BUS_WIDTH) != set_bit) { + tmp_bits &= ~MASK_BUS_WIDTH; + writeb(tmp_bits | set_bit, sdmmc_base + SD_CONFIGURE1); + } +} + +static void rtk_sdmmc_set_div(struct rtk_sdmmc_host *rtk_host, u32 set_div) { + void __iomem *sdmmc_base = rtk_host->sdmmc; + u8 tmp_div = 0; + + rtk_sdmmc_sync(rtk_host); + tmp_div = readb(sdmmc_base + SD_CONFIGURE1) & ~MASK_CLOCK_DIV; + if (set_div != CLOCK_DIV_NON) { + writeb(tmp_div | set_div | SDCLK_DIV, sdmmc_base + SD_CONFIGURE1); + } else { + writeb(tmp_div, sdmmc_base + SD_CONFIGURE1); + } + rtk_sdmmc_sync(rtk_host); +} + +static void rtk_sdmmc_set_speed(struct rtk_sdmmc_host *rtk_host, u8 level) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + + switch (level) { + case 0: //ddr50 , highest speed + rtk_sdmmc_debug("%s: speed 2100\n", __func__); + writel(0x00002100, sdmmc_base + CR_SD_CKGEN_CTL); + break; + case 1: + rtk_sdmmc_debug("%s: speed 2101\n", __func__); + writel(0x00002101, sdmmc_base + CR_SD_CKGEN_CTL); + break; + case 2: + rtk_sdmmc_debug("%s: speed 2102\n", __func__); + writel(0x00002102, sdmmc_base + CR_SD_CKGEN_CTL); + break; + case 3: + rtk_sdmmc_debug("%s: speed 2103\n", __func__); + writel(0x00002103, sdmmc_base + CR_SD_CKGEN_CTL); + break; + default : + rtk_sdmmc_debug("%s: default speed 2102\n", __func__); + writel(0x00002102, sdmmc_base + CR_SD_CKGEN_CTL); + break; + } + rtk_sdmmc_sync(rtk_host); +} + +static void rtk_sdmmc_speed(struct rtk_sdmmc_host *rtk_host, enum sdmmc_clock_speed sd_speed) +{ + unsigned int tmp=0; + void __iomem *sdmmc_base = rtk_host->sdmmc; + void __iomem *isopad_base = rtk_host->isopad; + void __iomem *pll_base = rtk_host->pll; + + switch (sd_speed) { + case SDMMC_CLOCK_200KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_200KHZ\n", __func__); + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_256); //0x580 = 0xd0 + rtk_sdmmc_set_speed(rtk_host, 1); //0x478 = 0x2101 + break; + case SDMMC_CLOCK_400KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_400KHZ\n", __func__); + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_256); //0x580 = 0xd0 + rtk_sdmmc_set_speed(rtk_host, 0); //0x478 = 0x2100 + break; + case SDMMC_CLOCK_6200KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_6200KHZ\n", __func__); + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 3); //0x478 = 0x2103 + break; + case SDMMC_CLOCK_25000KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_25000KHZ\n", __func__); + if (rtk_host->mmc->ios.timing == MMC_TIMING_UHS_SDR12) { + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 2); //0x478 = 0x2101 + } else { + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 1); //0x478 = 0x2101 + } + break; + case SDMMC_CLOCK_50000KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_50000KHZ\n", __func__); + if (rtk_host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) { + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) | 0x00070000, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to 4MHz by Hsin-yin + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + writel(0x00324388, pll_base + CR_PLL_SD3); + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) & 0xFFF8FFFF, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to normal clock source by Hsin-yin + writeb(readb(sdmmc_base + SD_CONFIGURE1) & 0xEF, sdmmc_base + SD_CONFIGURE1); //Reset FIFO pointer by Hsin-yin + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 0); //0x478 = 0x2100 + } else if (rtk_host->mmc->ios.timing == MMC_TIMING_UHS_SDR25) { + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 1); //0x478 = 0x2101 + } else { + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 0); //0x478 = 0x2100 + } + break; + case SDMMC_CLOCK_100000KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_100000KHZ\n", __func__); + + if (chip_id == CHIP_ID_RTD1619B) { + tmp = ((readl(isopad_base + 0x78) & 0xfe07f03f) | 0x00900480); + writel(tmp, isopad_base + 0x78); + tmp = ((readl(isopad_base + 0x7c) & 0xfff81fc0) | 0x00024012); + writel(tmp, isopad_base + 0x7c); + tmp = ((readl(isopad_base + 0x80) & 0xfe07f03f) | 0x00900480); + writel(tmp, isopad_base+0x80); + } else if (chip_id == CHIP_ID_RTD1319) { + tmp = (0x243243) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x243243<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x243243) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + } else if (chip_id == CHIP_ID_RTD1619) { + tmp = (0x3483483 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x48348348,isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x483; + writel(tmp,isopad_base + 0x14); + } else if (chip_id == CHIP_ID_RTD1395) { + writel(0x198CD99B, isopad_base + 0x34); + writel(0x000CF99F, isopad_base + 0x38); + writel(0x000CF99F, isopad_base + 0x3c); + } + + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 0); //0x478 = 0x2100 + break; + case SDMMC_CLOCK_208000KHZ: + rtk_sdmmc_debug("%s: speed SDMMC_CLOCK_208000KHZ\n", __func__); + + if (chip_id == CHIP_ID_RTD1395) { + writeb(0xd,sdmmc_base + SD_BUS_TA_STATE); + + switch (driving_capacity % 10) { + case 0: + case 1: + writel(0x19A65CCB,isopad_base + 0x34); + writel(0x00267CCF,isopad_base + 0x38); + writel(0x00267CCF,isopad_base + 0x3c); + break; + case 2: + case 3: + writel(0x19AA9D53,isopad_base + 0x34); + writel(0x002ABD57,isopad_base + 0x38); + writel(0x002ABD57,isopad_base + 0x3c); + break; + case 4: + case 5: + writel(0x19AEDDDB,isopad_base + 0x34); + writel(0x002EFDDF,isopad_base + 0x38); + writel(0x002EFDDF,isopad_base + 0x3c); + break; + case 6: + case 7: + writel(0x19B31E63,isopad_base + 0x34); + writel(0x00333E67,isopad_base + 0x38); + writel(0x00333E67,isopad_base + 0x3c); + break; + case 8: + case 9: + writel(0x19B75EEB,isopad_base + 0x34); + writel(0x00377EEF,isopad_base + 0x38); + writel(0x00377EEF,isopad_base + 0x3c); + break; + default: + writel(0x19A65CCB,isopad_base + 0x34); + writel(0x00267CCF,isopad_base + 0x38); + writel(0x00267CCF,isopad_base + 0x3c); + } + } + + if (chip_id == CHIP_ID_RTD1619) { + writeb(0xd,sdmmc_base + SD_BUS_TA_STATE); + + switch (driving_capacity % 10) { + case 0: + case 1: + case 2: + case 3: + tmp = (0x36c36c3 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x6c36c36c, isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x6c3; + writel(tmp, isopad_base + 0x14); + break; + case 4: + case 5: + case 6: + tmp = (0x3903903 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x90390390, isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x903; + writel(tmp, isopad_base + 0x14); + break; + case 7: + case 8: + case 9: + tmp = (0x3b43b43 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0xb43b43b4, isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0xb43; + writel(tmp, isopad_base + 0x14); + break; + default: + tmp = (0x3243243 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x24324324, isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x243; + writel(tmp, isopad_base + 0x14); + } + } + + if (chip_id == CHIP_ID_RTD1319) { + writeb(0xd,sdmmc_base + SD_BUS_TA_STATE); + + switch (driving_capacity % 10) { + case 0: + case 1: + case 2: + case 3: + case 4: + tmp = (0x483483) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x483483<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x483483) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + break; + case 5: + case 6: + case 7: + tmp = (0x6c36c3) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x6c36c3<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x6c36c3) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + break; + case 8: + case 9: + tmp = (0xb43b43) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0xb43b43<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0xb43b43) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + break; + default: + tmp = (0x003003) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x003003<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x003003) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + } + } + + if (chip_id == CHIP_ID_RTD1619B) { + writeb(0xd,sdmmc_base + SD_BUS_TA_STATE); + + switch (driving_capacity % 10) { + case 0: + case 1: + case 2: + case 3: + case 4: + writel((readl(isopad_base+0x78) & 0xfe07f03f) | 0x00d806c0, isopad_base+0x78); + writel((readl(isopad_base+0x7c) & 0xfff81fc0) | 0x0003601b, isopad_base+0x7c); + writel((readl(isopad_base+0x80) & 0xfe07f03f) | 0x00d806c0, isopad_base+0x80); + break; + case 5: + case 6: + case 7: + writel((readl(isopad_base+0x78) & 0xfe07f03f) | 0x01200900, isopad_base+0x78); + writel((readl(isopad_base+0x7c) & 0xfff81fc0) | 0x00048024, isopad_base+0x7c); + writel((readl(isopad_base+0x80) & 0xfe07f03f) | 0x01200900, isopad_base+0x80); + break; + case 8: + case 9: + writel((readl(isopad_base+0x78) & 0xfe07f03f) | 0x01680b40, isopad_base+0x78); + writel((readl(isopad_base+0x7c) & 0xfff81fc0) | 0x0005a02d, isopad_base+0x7c); + writel((readl(isopad_base+0x80) & 0xfe07f03f) | 0x01680b40, isopad_base+0x80); + break; + default: + writel((readl(isopad_base+0x78) & 0xfe07f03f) | 0x00900480, isopad_base+0x78); + writel((readl(isopad_base+0x7c) & 0xfff81fc0) | 0x00024012, isopad_base+0x7c); + writel((readl(isopad_base+0x80) & 0xfe07f03f) | 0x00900480, isopad_base+0x80); + } + } + + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) | 0x00070000, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to 4MHz by Hsin-yin + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + writel(0x00b64388, pll_base + CR_PLL_SD3); //SD clock rate formula: (ssc_div_n +3) *4.5/4 + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) & 0xFFF8FFFF, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to normal clock source by Hsin-yin + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writeb(readb(sdmmc_base + SD_CONFIGURE1) & 0xEF, sdmmc_base + SD_CONFIGURE1); //Reset FIFO pointer by Hsin-yin + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_NON); //0x580 = 0x10 + rtk_sdmmc_set_speed(rtk_host, 0); //0x478 = 0x2100 + break; + default : + rtk_sdmmc_debug("%s: default speed SDMMC_CLOCK_400KHZ\n", __func__); + rtk_sdmmc_set_div(rtk_host, CLOCK_DIV_256); //0x580 = 0xd0 + rtk_sdmmc_set_speed(rtk_host, 0); //0x478 = 0x2100 + break; + } + + rtk_sdmmc_sync(rtk_host); +} + +static int rtk_sdmmc_allocate_dma_buf(struct rtk_sdmmc_host *rtk_host, struct mmc_command *cmd) +{ + if (!dma_virt_addr) { + dma_virt_addr = dma_alloc_coherent(rtk_host->dev, SD_ALLOC_LENGTH, &rtk_host->paddr, GFP_KERNEL); + dma_phy_addr = (u32 *)rtk_host->paddr; + } else { + return 0; + } + + if (!dma_virt_addr) { + WARN_ON(1); + printk(KERN_ERR "%s: allocate rtk sd dma buf FAIL !\n", __func__); + cmd->error = -ENOMEM; + return 0; + } + + return 1; +} + +static int rtk_sdmmc_free_dma_buf(struct rtk_sdmmc_host *rtk_host) +{ + if (dma_virt_addr) + dma_free_coherent(rtk_host->dev, SD_ALLOC_LENGTH, dma_virt_addr ,rtk_host->paddr); + else + return 0; + + return 1; +} + +static u32 rtk_sdmmc_swap_endian(u32 input) +{ + u32 output = 0; + + output = (input & 0xFF000000) >> 24 | + (input & 0x00FF0000) >> 8 | + (input & 0x0000FF00) << 8 | + (input & 0x000000FF) << 24; + return output; +} + +static void rtk_sdmmc_read_rsp(struct rtk_sdmmc_host *rtk_host, u32 *rsp, int reg_count) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + + if (reg_count == 6) { + rsp[0] = readb(sdmmc_base + SD_CMD1) << 24 | + readb(sdmmc_base + SD_CMD2) << 16 | + readb(sdmmc_base + SD_CMD3) << 8 | + readb(sdmmc_base + SD_CMD4); + } else if (reg_count == 16) { + rsp[0] = rtk_sdmmc_swap_endian(rsp[0]); + rsp[1] = rtk_sdmmc_swap_endian(rsp[1]); + rsp[2] = rtk_sdmmc_swap_endian(rsp[2]); + rsp[3] = rtk_sdmmc_swap_endian(rsp[3]); + } +} + +static u32 rtk_sdmmc_get_cmd_timeout(struct sdmmc_cmd_pkt *cmd_info) +{ + struct rtk_sdmmc_host *rtk_host = cmd_info->rtk_host; + u32 timeout = 0; + + timeout += msecs_to_jiffies(1); + cmd_info->timeout = rtk_host->timeout = timeout; + + return 0; +} + +int rtk_sdmmc_cpu_wait(char* drv_name, struct rtk_sdmmc_host *rtk_host, u8 cmdcode) { + + int ret = CR_TRANSFER_TO; + unsigned long old_jiffles = jiffies; + unsigned long timeout = 0; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + poll = 1; + writel(0x00000016, sdmmc_base + CR_SD_ISREN); //disable all + switch( data_xfer_mode ) { + case CMD_RSP_ONLY: + case CMD_RSP_DATA_WRITE: + writel(0x00000007, sdmmc_base + CR_SD_ISREN); + break; + case CMD_RSP_DATA_READ: + case DATA_ONLY: + writel(0x00000015, sdmmc_base + CR_SD_ISREN); + break; + default: + writel(0x00000007, sdmmc_base + CR_SD_ISREN); + break; + } + timeout = 300; + rtk_sdmmc_sync(rtk_host); + + writeb((u8)(cmdcode | START_EN), sdmmc_base + SD_TRANSFER); + + while (time_before(jiffies, old_jiffles + timeout)) { + + rtk_sdmmc_sync(rtk_host); + if ((readb(sdmmc_base + SD_STATUS2) & 0x01) == 1) { + ret = CR_TRANSFER_FAIL; + break; + } + + if (!(rtk_host->rtflags & RTKCR_FCARD_DETECTED)) { + ret = CR_TRANSFER_FAIL; + break; + } + + if ((readb(sdmmc_base + SD_TRANSFER) & (END_STATE | IDLE_STATE)) == (END_STATE | IDLE_STATE)) { + ret = CR_TRANS_OK; + break; + } + + if ((readb(sdmmc_base + SD_TRANSFER) & (ERR_STATUS)) == (ERR_STATUS)) { + ret = CR_TRANSFER_FAIL; + pr_err("%s(%d) trans error(error status) :\n trans: 0x%08x, st1: 0x%08x, st2: 0x%08x, bus: 0x%08x\n", + __func__, + __LINE__, + readb(sdmmc_base + SD_TRANSFER), + readb(sdmmc_base + SD_STATUS1), + readb(sdmmc_base + SD_STATUS2), + readb(sdmmc_base + SD_BUS_STATUS)); + + if (rtk_host != NULL && rtk_host->mrq != NULL && rtk_host->mrq->cmd != NULL) + printk(KERN_ERR "%s: error opcode = %d\n", __func__, rtk_host->mrq->cmd->opcode); + break; + } + } + + if (ret == CR_TRANSFER_TO) { + printk(KERN_ERR "%s(%d) trans error(timeout) :\n trans: 0x%08x, st1: 0x%08x, st2: 0x%08x, bus: 0x%08x\n", + __func__, + __LINE__, + readb(sdmmc_base+SD_TRANSFER), + readb(sdmmc_base+SD_STATUS1), + readb(sdmmc_base+SD_STATUS2), + readb(sdmmc_base+SD_BUS_STATUS)); + + if (rtk_host!=NULL && rtk_host->mrq!=NULL && rtk_host->mrq->cmd!=NULL) + printk(KERN_ERR "%s: error opcode = %d\n", __func__, rtk_host->mrq->cmd->opcode); + + return ret; + } + + return ret; +} + +int rtk_sdmmc_int_wait(char* drv_name, struct rtk_sdmmc_host *rtk_host, u8 cmdcode) +{ + int ret = CR_TRANSFER_TO; + unsigned long timeout = 0; + unsigned int sd_trans = 0; + unsigned long old_jiffles = jiffies; + void __iomem *sdmmc_base = rtk_host->sdmmc; + int cmd_type=0; + + poll=0; + + if (broken_flag==true) + return CR_TRANSFER_FAIL; + + /* timeout timer fire */ + if (&rtk_host->timer) { + if (rtk_host != NULL && rtk_host->mrq != NULL && rtk_host->mrq->cmd != NULL && (rtk_host->mrq->cmd->opcode == 55 || rtk_host->mrq->cmd->opcode == 41 || rtk_host->mrq->cmd->opcode == 8 || (pre_cmd == 41 && rtk_host->mrq->cmd->opcode == 1))) { + timeout = msecs_to_jiffies(100) + rtk_host->timeout; + cmd_type=1; + } + else if (rtk_host != NULL && rtk_host->mrq != NULL && rtk_host->mrq->cmd != NULL && (rtk_host->mrq->cmd->opcode == 2 || rtk_host->mrq->cmd->opcode == 3 || rtk_host->mrq->cmd->opcode == 9)) { + timeout = msecs_to_jiffies(600) + rtk_host->timeout; + cmd_type=2; + } + else { + timeout = msecs_to_jiffies(3000) + rtk_host->timeout; + cmd_type=3; + } + mod_timer(&rtk_host->timer, (jiffies + timeout)); + } + + writel(0x00000016, sdmmc_base + CR_SD_ISREN); //disable all + switch( data_xfer_mode ) { + case CMD_RSP_ONLY: + case DATA_WRITE_ONLY: + case CMD_RSP_DATA_WRITE: + case CMD_RSP_DATA_READ_TUNNING: + writel(0x00000007, sdmmc_base + CR_SD_ISREN); + break; + case CMD_RSP_DATA_READ: + writel(0x00000015, sdmmc_base + CR_SD_ISREN); + break; + default: + writel(0x00000007, sdmmc_base + CR_SD_ISREN); + break; + } + rtk_sdmmc_sync(rtk_host); + irq_error_bit = 0; + writeb((u8) (cmdcode | START_EN), sdmmc_base + SD_TRANSFER); //cmd fire + + wait_for_completion(rtk_host->int_waiting); + + rtk_sdmmc_sync(rtk_host); + + sd_trans = readb(sdmmc_base + SD_TRANSFER); + + if(irq_error_bit==1) { //error handling + if (rtk_host->cmd_opcode==55 && CMD8_SD1==true) { + CMD55_MMC=true; //MMC card + printk(KERN_ERR "Reject SD 1.x command\n"); + ret = CR_TRANSFER_FAIL; + } else { + if(rtk_host!=NULL) + printk(KERN_ERR "rtk_sdmmc_int_wait: reset the card and adjust the driving capacity, cmd=%d, SD_TRANSFER=0x%x\n",rtk_host->cmd_opcode, sd_trans); + driving_capacity++; + compatible_flag = true; + remove_sdcard(rtk_host); + ret = CR_TRANS_OK; + } + } else if ((sd_trans & (END_STATE | IDLE_STATE)) == (END_STATE | IDLE_STATE)) { + ret = CR_TRANS_OK; + } else { + if(cmd_type==1) timeout=10; + else if(cmd_type==2) timeout=60; + else timeout = 300; + while(time_before(jiffies, old_jiffles + timeout)){ + rtk_sdmmc_sync(rtk_host); + sd_trans = readb(sdmmc_base + SD_TRANSFER); + + if ((sd_trans & (END_STATE | IDLE_STATE)) == (END_STATE | IDLE_STATE)) { + ret = CR_TRANS_OK; + break; + } else if ((sd_trans & (ERR_STATUS)) == (ERR_STATUS)) { + ret = CR_TRANSFER_FAIL; + printk(KERN_ERR "%s(%d) trans error(error status) :\n cfg1: 0x%02x, cfg2: 0x%02x, cfg3: 0x%02x, trans: 0x%08x, st1: 0x%08x, st2: 0x%08x, bus: 0x%08x\n", + __func__, + __LINE__, + readb(sdmmc_base + SD_CONFIGURE1), + readb(sdmmc_base + SD_CONFIGURE2), + readb(sdmmc_base + SD_CONFIGURE3), + readb(sdmmc_base + SD_TRANSFER), + readb(sdmmc_base + SD_STATUS1), + readb(sdmmc_base + SD_STATUS2), + readb(sdmmc_base + SD_BUS_STATUS)); + + if (rtk_host!=NULL && rtk_host->mrq!=NULL && rtk_host->mrq->cmd!=NULL) + printk(KERN_ERR "%s: error opcode = %d\n", __func__, rtk_host->mrq->cmd->opcode); + + if (rtk_host!=NULL && rtk_host->mrq!=NULL && rtk_host->mrq->cmd!=NULL && rtk_host->mrq->cmd->opcode!=13 && rtk_host->mrq->cmd->opcode!=19 && CMD8_SD1!=true && CMD55_MMC!=true) { + driving_capacity++; + compatible_flag = true; + remove_sdcard(rtk_host); + ret = CR_TRANS_OK; + } + break; + } else if (rtk_host != NULL && !(rtk_host->rtflags & RTKCR_FCARD_DETECTED)) { + ret = CR_TRANSFER_FAIL; + printk(KERN_ERR "card is being removed...\n"); + break; + } + } + } + if (ret == CR_TRANSFER_TO) { + printk(KERN_ERR "%s(%d) trans error(timeout) :\n trans: 0x%08x, st1: 0x%08x, st2: 0x%08x, bus: 0x%08x\n", + __func__, + __LINE__, + readb(sdmmc_base + SD_TRANSFER), + readb(sdmmc_base + SD_STATUS1), + readb(sdmmc_base + SD_STATUS2), + readb(sdmmc_base + SD_BUS_STATUS)); + + if (rtk_host!=NULL && rtk_host->mrq!=NULL && rtk_host->mrq->cmd!=NULL) + printk(KERN_ERR "%s: error opcode = %d\n", __func__, rtk_host->mrq->cmd->opcode); + } + return ret; +} + +static int rtk_sdmmc_set_rspparam(struct sdmmc_cmd_pkt *cmd_info) +{ + rtk_sdmmc_debug("%s: opcode = %d\n", __func__, cmd_info->cmd->opcode); + + switch (cmd_info->cmd->opcode) { + case MMC_GO_IDLE_STATE: //cmd 0 + cmd_info->rsp_para1 = 0xD0; //SD1_R0; + cmd_info->rsp_para2 = 0x74; //0x50 | SD_R0; + cmd_info->rsp_para3 = 0x00; + break; + case MMC_SEND_OP_COND: + if (mmc_detected == 1) { + cmd_info->rsp_para1 = SD1_R0; + cmd_info->rsp_para2 = 0x45; + cmd_info->rsp_para3 = 0x01; + cmd_info->cmd->arg = MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_SECTOR_ADDR; + } + break; + case MMC_ALL_SEND_CID: //cmd 2 + cmd_info->rsp_para1 = -1; //SD1_R0; + cmd_info->rsp_para2 = 0x42; //SD_R2; + cmd_info->rsp_para3 = 0x05; //SD2_R0; + break; + case MMC_SET_RELATIVE_ADDR: //cmd3 + cmd_info->rsp_para1 = -1; //SD1_R0; + cmd_info->rsp_para2 = 0x41; //SD_R1 | CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x05; + break; + case MMC_SET_DSR: //cmd4 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case SD_APP_SET_BUS_WIDTH: //cmd6 + if ((cmd_info->cmd->flags & (0x3 << 5)) == MMC_CMD_ADTC) { //SD_SWITCH + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; //SD_R1b | CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x05; + } else { + cmd_info->rsp_para1 = -1; + if (mmc_detected == 1) { + cmd_info->rsp_para2 = 0x09; //SD_R1b | CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x05; + } else { + cmd_info->rsp_para2 = 0x61; //SD_R1b | CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x0D; + } + } + break; + case MMC_SELECT_CARD: //cmd7 + if (cmd_info->cmd->flags == (MMC_RSP_R1 | MMC_CMD_AC)) { //select + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x41; //SD_R1b|CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x05; + } else { //deselect + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x40; //SD_R0|CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x05; + } + break; + case SD_SEND_IF_COND: //cmd8 + cmd_info->rsp_para1 = 0xD0; + cmd_info->rsp_para2 = 0x41; //SD_R1; + cmd_info->rsp_para3 = 0x0; + if (cmd_info->rtk_host->rtflags & RTKCR_FCARD_SELECTED && mmc_detected == 1) { + cmd_info->rsp_para1 = 0x50; + cmd_info->rsp_para2 = SD_R1; + cmd_info->rsp_para3 = 0x05; + } + break; + case MMC_SEND_CSD: //cmd9 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x42; //SD_R2; + cmd_info->rsp_para3 = 0x05; + break; + case MMC_SEND_CID://cmd10 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x42; //SD_R2; + cmd_info->rsp_para3 = 0x5; + break; + case SD_SWITCH_VOLTAGE: //cmd11 + cmd_info->rsp_para1 = -1; //0; + cmd_info->rsp_para2 = 0x41; //don't update + cmd_info->rsp_para3 = 0x00; //don't update + break; + case MMC_STOP_TRANSMISSION: //cmd12 + cmd_info->rsp_para1 = -1; + if (suspend_flag == false) + cmd_info->rsp_para2 = 0x7D; //SD_R1 | CRC16_CAL_DIS | 6 bytes response; + else + cmd_info->rsp_para2 = 0x7C; + cmd_info->rsp_para3 = 0x00; + break; + case SD_APP_SD_STATUS: //cmd13 + if ((cmd_info->cmd->flags & (0x3<<5)) == MMC_CMD_ADTC) { //SD_APP_SD_STATUS + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; //SD_R1 | CRC16_CAL_DIS; + cmd_info->rsp_para3 = 0x05; + } else { + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x41; //SD_R1 | CRC16_CAL_DIS; + cmd_info->rsp_para3 = -1; + } + break; + case MMC_GO_INACTIVE_STATE: //cmd15 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_SET_BLOCKLEN: //cmd16 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x41; + cmd_info->rsp_para3 = 0x05; + break; + case MMC_READ_SINGLE_BLOCK: //cmd17 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x1; + cmd_info->rsp_para3 = -1; + break; + case MMC_READ_MULTIPLE_BLOCK: //cmd18 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + if (mmc_detected == 1) { + cmd_info->rsp_para3 = 0x04; //0x04; + } else { + cmd_info->rsp_para3 = 0x00;//0x02; ----jim + } + break; + case MMC_SEND_TUNING_BLOCK: //cmd19 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + cmd_info->rsp_para3 = -1; //0x04; + break; + case MMC_WRITE_DAT_UNTIL_STOP: //cmd20 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case SD_APP_SEND_NUM_WR_BLKS: //cmd22 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_SET_BLOCK_COUNT: //cmd 23 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_WRITE_BLOCK: //cmd24 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + cmd_info->rsp_para3 = -1; + break; + case MMC_WRITE_MULTIPLE_BLOCK: //cmd25 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + cmd_info->rsp_para3 = 0x00;//0x02;--------jim + break; + case MMC_PROGRAM_CSD: //cmd27 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_SET_WRITE_PROT: //cmd28 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_CLR_WRITE_PROT: //cmd29 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_SEND_WRITE_PROT: //cmd30 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case SD_ERASE_WR_BLK_START: //cmd32 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case SD_ERASE_WR_BLK_END: //cmd33 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_ERASE: //cmd38 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case SD_APP_OP_COND: //cmd41 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x45; + cmd_info->rsp_para3 = 0x00; + break; + case MMC_LOCK_UNLOCK: //cmd42 + if ((cmd_info->cmd->flags & (0x3<<5)) == MMC_CMD_ADTC) { //SD_APP_SD_STATUS + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + } else { + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + } + break; + case SD_APP_SEND_SCR: //cmd51 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x41; + cmd_info->rsp_para3 = 0x05; + break; + case MMC_APP_CMD: //cmd55 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x41; + cmd_info->rsp_para3 = 0x05; + break; + case MMC_GEN_CMD: //cmd56 + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + case MMC_EXT_READ_SINGLE: //cmd48 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + cmd_info->rsp_para3 = -1; + break; + case MMC_EXT_WRITE_SINGLE: //cmd49 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + cmd_info->rsp_para3 = -1; + break; + case MMC_EXT_READ_MULTIPLE: //cmd58 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + if (mmc_detected == 1) + cmd_info->rsp_para3 = 0x04; + else + cmd_info->rsp_para3 = 0x02; + break; + case MMC_EXT_WRITE_MULTIPLE: //cmd59 + cmd_info->rsp_para1 = -1; + cmd_info->rsp_para2 = 0x01; + cmd_info->rsp_para3 = 0x02; + break; + default: + cmd_info->rsp_para1 = -1; //don't update + cmd_info->rsp_para3 = -1; //don't update + break; + } + + return 0; +} + +static int rtk_sdmmc_send_stop_cmd(struct mmc_command *cmd, struct rtk_sdmmc_host *rtk_host,int flag) +{ + u8 cmd_idx = 0; + u32 sd_arg = 0; + s8 rsp_para1 = 0; + s8 rsp_para2 = 0; + s8 rsp_para3 = 0; + u8 rsp_len = 0; + int ret = 0; + + void __iomem *sdmmc_base = rtk_host->sdmmc; + struct mmc_command stop_cmd; + struct sdmmc_cmd_pkt stop_cmd_info; + struct sdmmc_cmd_pkt *cmd_info; + + INT4_flag = false; + cmd_info = &stop_cmd_info; + + memset(&stop_cmd, 0x00, sizeof(struct mmc_command)); + memset(&stop_cmd_info, 0x00, sizeof(struct sdmmc_cmd_pkt)); + + stop_cmd.opcode = MMC_STOP_TRANSMISSION; + stop_cmd.arg = 0x00; //cmd->arg; //card's RCA, not necessary for cmd12 + stop_cmd_info.cmd = &stop_cmd; + stop_cmd_info.rtk_host = rtk_host; + stop_cmd_info.rsp_para2 = rtk_sdmmc_get_rsp_type(stop_cmd_info.cmd); + stop_cmd_info.rsp_len = rtk_sdmmc_get_rsp_len(stop_cmd_info.rsp_para2); + cmd_idx = cmd_info->cmd->opcode; + rsp_len = cmd_info->rsp_len; + rtk_host = cmd_info->rtk_host; + + rtk_sdmmc_set_rspparam(cmd_info); + + sd_arg = cmd_info->cmd->arg; + rsp_para1 = cmd_info->rsp_para1; + rsp_para2 = cmd_info->rsp_para2; + rsp_para3 = cmd_info->rsp_para3; + + if (rsp_para1 != -1) + writeb(rsp_para1, sdmmc_base + SD_CONFIGURE1); + + writeb(rsp_para2, sdmmc_base + SD_CONFIGURE2); + + if (rsp_para3 != -1) + writeb(rsp_para3, sdmmc_base + SD_CONFIGURE3); + + g_cmd[0] = (0x40 | cmd_idx); + g_cmd[1] = (sd_arg >> 24) & 0xff; + g_cmd[2] = (sd_arg >> 16) & 0xff; + g_cmd[3] = (sd_arg >> 8) & 0xff; + g_cmd[4] = sd_arg & 0xff; + g_cmd[5] = 0x00; + + writeb(g_cmd[0], sdmmc_base + SD_CMD0); + writeb(g_cmd[1], sdmmc_base + SD_CMD1); + writeb(g_cmd[2], sdmmc_base + SD_CMD2); + writeb(g_cmd[3], sdmmc_base + SD_CMD3); + writeb(g_cmd[4], sdmmc_base + SD_CMD4); + writeb(g_cmd[5], sdmmc_base + SD_CMD5); + rtk_host->cmd_opcode = cmd_idx; + + rtk_sdmmc_get_cmd_timeout(cmd_info); + + data_xfer_mode = CMD_RSP_ONLY; + if (flag == 1) + ret = rtk_sdmmc_cpu_wait(DRIVER_NAME, rtk_host, SD_SENDCMDGETRSP); + else + ret = rtk_sdmmc_int_wait(DRIVER_NAME, rtk_host, SD_SENDCMDGETRSP); + + rtk_sdmmc_sync(rtk_host); + + return ret; +} + +static int rtk_sdmmc_stream_cmd(u16 cmdcode, struct sdmmc_cmd_pkt *cmd_info, u8 data_len) +{ + u8 cmd_idx = cmd_info->cmd->opcode; + u32 sd_arg = 0; + s8 rsp_para1 = 0; + s8 rsp_para2 = 0; + s8 rsp_para3 = 0; + int rsp_len = cmd_info->rsp_len; + int ret = 0; + u32 data = cmd_info->dma_buffer; + u32 sa = 0; + u32 *rsp = (u32 *)&cmd_info->cmd->resp; + u16 byte_count = cmd_info->byte_count; + u16 block_count = cmd_info->block_count; + struct rtk_sdmmc_host *rtk_host = cmd_info->rtk_host; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + INT4_flag=true; + + if (!data || rsp == NULL) { + BUG_ON(1); + } + rtk_sdmmc_set_rspparam(cmd_info); + sd_arg = cmd_info->cmd->arg; + + rsp_para1 = cmd_info->rsp_para1; + + if (cmdcode == SD_AUTOWRITE3) + rsp_para2 = 0; + else + rsp_para2 = cmd_info->rsp_para2; + + rsp_para3 = cmd_info->rsp_para3; + sa = (data / 8); + + if ((cmdcode == SD_NORMALWRITE)) { + byte_count = 512; + } else if (cmdcode == SD_NORMALREAD && mmc_detected == 1) { + byte_count = 512; + } + + g_cmd[0] = (0x40 | cmd_idx); + g_cmd[1] = (sd_arg >> 24) & 0xff; + g_cmd[2] = (sd_arg >> 16) & 0xff; + g_cmd[3] = (sd_arg >> 8) & 0xff; + g_cmd[4] = sd_arg & 0xff; + g_cmd[5] = 0x00; + + writeb(g_cmd[0], sdmmc_base + SD_CMD0); //0x10 + writeb(g_cmd[1], sdmmc_base + SD_CMD1); //0x14 + writeb(g_cmd[2], sdmmc_base + SD_CMD2); //0x18 + writeb(g_cmd[3], sdmmc_base + SD_CMD3); //0x1C + writeb(g_cmd[4], sdmmc_base + SD_CMD4); //0x20 + writeb(g_cmd[5], sdmmc_base + SD_CMD5); //0x20 + + if (rsp_para1 != -1) { + writeb(readb(sdmmc_base + SD_CONFIGURE1) | rsp_para1, sdmmc_base + SD_CONFIGURE1); //0x0C + } + + writeb(rsp_para2, sdmmc_base + SD_CONFIGURE2); //0x0C + + if (rsp_para3 != -1) { + writeb(readb(sdmmc_base + SD_CONFIGURE3) | rsp_para3, sdmmc_base + SD_CONFIGURE3); //0x0C + } + + writeb(byte_count, sdmmc_base + SD_BYTE_CNT_L); //0x24 + writeb(byte_count >> 8, sdmmc_base + SD_BYTE_CNT_H); //0x28 + writeb(block_count, sdmmc_base + SD_BLOCK_CNT_L); //0x2C + writeb(block_count >> 8, sdmmc_base + SD_BLOCK_CNT_H); //0x30 + + if (cmd_info->cmd->data->flags & MMC_DATA_READ) { + writel((u32)sa, sdmmc_base + CR_SD_DMA_CTL1); + writel(block_count, sdmmc_base + CR_SD_DMA_CTL2); + + if (data_len == RESP_LEN64) { + writel(RSP64_SEL | DDR_WR | DMA_XFER, sdmmc_base + CR_SD_DMA_CTL3); + } else if (data_len == RESP_LEN17) { + writel(RSP17_SEL | DDR_WR | DMA_XFER, sdmmc_base + CR_SD_DMA_CTL3); + } else { + writel(DDR_WR | DMA_XFER, sdmmc_base + CR_SD_DMA_CTL3); + } + data_xfer_mode = CMD_RSP_DATA_READ; + if (cmd_info->cmd->opcode == MMC_SEND_TUNING_BLOCK) { + INT4_flag=false; + data_xfer_mode = CMD_RSP_DATA_READ_TUNNING; + } + + } else if (cmd_info->cmd->data->flags & MMC_DATA_WRITE) { + rtk_sdmmc_debug("%s: DMA sa = 0x%x\nDMA len = 0x%x\nDMA set = 0x%x\n", __func__, (u32)sa, block_count, DMA_XFER); + writel((u32)sa, sdmmc_base + CR_SD_DMA_CTL1); + writel(block_count, sdmmc_base + CR_SD_DMA_CTL2); + + if (data_len == RESP_LEN64) { + writel(RSP64_SEL | DMA_XFER, sdmmc_base + CR_SD_DMA_CTL3); + } else if (data_len == RESP_LEN17) { + writel(RSP17_SEL | DMA_XFER, sdmmc_base + CR_SD_DMA_CTL3); + } else { + writel(DMA_XFER, sdmmc_base + CR_SD_DMA_CTL3); + } + data_xfer_mode = CMD_RSP_DATA_WRITE; + if( cmdcode == SD_AUTOWRITE3 ) { + data_xfer_mode = DATA_WRITE_ONLY; + } + } + + rtk_host->cmd_opcode = cmd_idx; + rtk_sdmmc_get_cmd_timeout(cmd_info); + //printk(KERN_ERR "rtk_stream_cmd invoke pre_cmd=%d, cmd=%d, INT4_flag=%d\n",pre_cmd,cmd_info->cmd->opcode,INT4_flag); + ret = rtk_sdmmc_int_wait(DRIVER_NAME, rtk_host, cmdcode); + /* Reset dat64_sel and rsp17_sel, #CMD19 DMA won't be auto-cleared */ + if (cmd_info->cmd->opcode == MMC_SEND_TUNING_BLOCK) { + writel(0x00000000, sdmmc_base + CR_SD_DMA_CTL3); + data_xfer_mode = CMD_RSP_ONLY; + } + + if (ret == CR_TRANS_OK) { + if ((cmdcode == SD_AUTOREAD1) || (cmdcode == SD_AUTOWRITE1)) { + rtk_sdmmc_debug("%s: auto read/write 1 skip response\n", __func__); +#ifdef CMD25_WO_STOP_COMMAND + } else if (cmdcode == SD_AUTOWRITE2) { + rtk_sdmmc_debug("%s: auto write 2 skip response\n", __func__); //CMD + DATA + } else if (cmdcode == SD_AUTOWRITE3) { + rtk_sdmmc_debug("%s: auto write 3 skip response\n", __func__); //DATA only, clear rsp +#endif + } else { + rtk_sdmmc_read_rsp(rtk_host,rsp, rsp_len); + rtk_sdmmc_debug("%s: stream cmd done\n", __func__); + } + } + + return ret; +} + +static int rtk_sdmmc_stream(struct sdmmc_cmd_pkt *cmd_info) +{ + u8 cmd_idx = cmd_info->cmd->opcode; + int ret = 0; + u32 i = 0; + u32 dir = 0; + u32 dma_nents = 0; + u32 dma_leng = 0; + u32 dma_addr = 0; + u32 old_arg = 0; + u16 cmdcode = 0; + u8 data_len = 0; + + struct scatterlist *sg; + struct mmc_host *host = cmd_info->rtk_host->mmc; + struct rtk_sdmmc_host *rtk_host = cmd_info->rtk_host; + +#ifdef CMD25_WO_STOP_COMMAND + /* send stop command only use arg info and we need to save it as global + * variable for fear that timer trigger stop command data corruption + */ + cmd12_stop_cmd.arg = cmd_info->cmd->arg; + rtk_host->rtk_sdmmc_cmd12 = &cmd12_stop_cmd; +#endif + + if (cmd_info->data->flags & MMC_DATA_READ) + dir = DMA_FROM_DEVICE; + else + dir = DMA_TO_DEVICE; + + cmd_info->data->bytes_xfered = 0; + + if (rtk_host->sdmmc_bounce_buf_val) { + int buflen = 0; + + for_each_sg(cmd_info->data->sg, sg, cmd_info->data->sg_len, i) + buflen += sg->length; + + sg_init_one(rtk_host->sdmmc_bounce_sg, + rtk_host->sdmmc_bounce_buf, + buflen); + + if (dir == DMA_TO_DEVICE) + sg_copy_to_buffer(cmd_info->data->sg, + cmd_info->data->sg_len, + rtk_host->sdmmc_bounce_buf, + rtk_host->sdmmc_bounce_sg[0].length); + + dma_nents = dma_map_sg(mmc_dev(host), + rtk_host->sdmmc_bounce_sg, + 1, + dir); + + sg = rtk_host->sdmmc_bounce_sg; + + } else { + dma_nents = dma_map_sg(mmc_dev(host), + cmd_info->data->sg, + cmd_info->data->sg_len, + dir); + + sg = cmd_info->data->sg; + } + + old_arg = cmd_info->cmd->arg; + + for (i = 0 ; i < dma_nents ; i++, sg++) { + u32 blk_cnt = 0; + + dma_leng = sg_dma_len(sg); + dma_addr = sg_dma_address(sg); + + rtk_sdmmc_debug("%s: dma_addr: 0x%x, dma_leng: 0x%x\n", __func__, dma_addr, dma_leng); + + if ((cmd_idx == SD_SWITCH) && (cmd_info->cmd->flags | MMC_CMD_ADTC)) { + cmd_info->byte_count = 0x40; + blk_cnt = dma_leng / 0x40; + data_len = RESP_LEN64; + } else if ((cmd_idx == SD_APP_SD_STATUS) && ((cmd_info->cmd->flags & (0x3<<5)) == MMC_CMD_ADTC)) { + cmd_info->byte_count = 0x40; + blk_cnt = dma_leng / 0x40; + data_len = RESP_LEN64; + } else if ((cmd_idx == MMC_SEND_TUNING_BLOCK) || (cmd_idx == SD_APP_SEND_SCR) || (cmd_idx == SD_APP_SEND_NUM_WR_BLKS)) { + cmd_info->byte_count = 0x40; //rtk HW limite, one trigger 512 byte pass. + blk_cnt = 1; + data_len = RESP_LEN64; + } else if ((cmd_idx == MMC_ALL_SEND_CID) || (cmd_idx == MMC_SEND_CSD) || (cmd_idx == MMC_SEND_CID)) { + cmd_info->byte_count = 0x11; + blk_cnt = dma_leng / 0x11; + data_len = RESP_LEN17; + } else { + cmd_info->byte_count = BYTE_CNT; //rtk HW limite, one trigger 512 byte pass. + blk_cnt = dma_leng / BYTE_CNT; + data_len = 0; + } + + if (blk_cnt == 0 && dma_leng) { + blk_cnt = 1; + } + + cmd_info->block_count = blk_cnt; + cmd_info->dma_buffer = dma_addr; + + cmdcode = rtk_host->ops->chk_cmdcode(cmd_info->cmd); + +#ifdef CMD25_WO_STOP_COMMAND //new write method + if (host->card && mmc_card_blockaddr(host->card) && ( + cmd_info->cmd->opcode == MMC_WRITE_BLOCK || + cmd_info->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || + cmd_info->cmd->opcode == MMC_EXT_WRITE_MULTIPLE)) { + + if (sd_in_receive_data_state) { + if (sd_current_blk_address == cmd_info->cmd->arg) { + cmdcode = SD_AUTOWRITE3; //DATA only + } else { + rtk_sdmmc_send_stop_cmd(cmd_info->cmd, rtk_host, 0); //send stop command first + pre_cmd = 12; + sd_in_receive_data_state = 0; //not set SD in receive-data state + cmdcode = SD_AUTOWRITE2; //CMD + DATA + } + } else { + cmdcode = SD_AUTOWRITE2; //CMD + DATA + } + //alwasy use multi-write command + if (cmd_info->cmd->opcode == MMC_EXT_WRITE_MULTIPLE) + cmd_info->cmd->opcode = MMC_EXT_WRITE_MULTIPLE; + else + cmd_info->cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK; + } else { + if (cmd_info->cmd->opcode == MMC_SEND_STATUS) { //cmd13 + + } else { + if (sd_in_receive_data_state) { + rtk_sdmmc_send_stop_cmd(cmd_info->cmd, rtk_host, 0); //send stop command first + pre_cmd = 12; + /* stop trigger, not set SD in receive-data state */ + sd_in_receive_data_state = 0; + } + } + } +#endif + ret = rtk_sdmmc_stream_cmd(cmdcode, cmd_info, data_len); + if (ret == 0) { +#ifdef CMD25_WO_STOP_COMMAND //new write method + if (host->card && mmc_card_blockaddr(host->card) && ( + cmd_info->cmd->opcode == MMC_WRITE_BLOCK || + cmd_info->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || + cmd_info->cmd->opcode == MMC_EXT_WRITE_MULTIPLE)) { + sd_current_blk_address = cmd_info->cmd->arg + blk_cnt; + sd_in_receive_data_state = 1; + mod_timer(&rtk_host->rtk_sdmmc_stop_cmd, jiffies + 20/*1*HZ*/); + } +#endif + cmd_info->cmd->arg += dma_leng; + cmd_info->data->bytes_xfered += dma_leng; + } + + if (ret) { + cmd_info->cmd->arg = old_arg; + break; + } + + } + + if (rtk_host->sdmmc_bounce_buf_val) { + dma_unmap_sg(mmc_dev(host), rtk_host->sdmmc_bounce_sg, 1, dir); + + if (dir == DMA_FROM_DEVICE) + sg_copy_from_buffer(cmd_info->data->sg, + cmd_info->data->sg_len, + rtk_host->sdmmc_bounce_buf, + rtk_host->sdmmc_bounce_sg[0].length); + } else { + dma_unmap_sg(mmc_dev(host), + cmd_info->data->sg, + cmd_info->data->sg_len, + dir); + } + + g_cmd[0] = 0x00; + + return ret; +} + +static void rtk_sdmmc_swap_data(u8 *buffer, void __iomem *sdmmc_base) +{ + buffer[3] = buffer[2]; + buffer[2] = buffer[1]; + buffer[1] = buffer[0]; + buffer[0] = buffer[3+4]; + buffer[3+4] = buffer[3+3]; + buffer[3+3] = buffer[3+2]; + buffer[3+2] = buffer[3+1]; + buffer[3+1] = buffer[7+4]; + buffer[7+4] = buffer[7+3]; + buffer[7+3] = buffer[7+2]; + buffer[7+2] = buffer[7+1]; + buffer[7+1] = buffer[11+4]; + buffer[11+4] = buffer[11+3]; + buffer[11+3] = buffer[11+2]; + buffer[11+2] = buffer[11+1]; + buffer[11+1] = readb(sdmmc_base + SD_CMD5); +} + +static int rtk_sdmmc_send_cmd_get_rsp(struct sdmmc_cmd_pkt *cmd_info) +{ + u8 cmd_idx = cmd_info->cmd->opcode; + u32 sd_arg = 0; + s8 rsp_para1 = 0; + s8 rsp_para2 = 0; + s8 rsp_para3 = 0; + u8 rsp_len = cmd_info->rsp_len; + u32 *rsp = (u32 *)&cmd_info->cmd->resp; + u32 dma_val = 0; + u32 byte_count = 0x200; + u32 block_count = 1; + u32 sa = 0; + u8 RESP17_buffer[16]; + int ret = 0; + + struct rtk_sdmmc_host *rtk_host = cmd_info->rtk_host; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + INT4_flag=false; + + rtk_sdmmc_set_rspparam(cmd_info); + + sd_arg = cmd_info->cmd->arg; + rsp_para1 = cmd_info->rsp_para1; + rsp_para2 = cmd_info->rsp_para2; + rsp_para3 = cmd_info->rsp_para3; + + if (rsp == NULL) { + BUG_ON(1); + } + if ((cmd_idx == SD_IO_SEND_OP_COND)|(cmd_idx == SD_IO_RW_DIRECT)|(cmd_idx == SD_IO_RW_EXTENDED)) { + printk(KERN_INFO "%s : reject SDIO commands cmd:0x%02x \n", __func__, cmd_idx); + return CR_TRANSFER_FAIL; + } + + if (mini_SD==1 && cmd_idx == 8) { + printk(KERN_INFO "%s : reject SDIO commands cmd:0x%02x \n", __func__, cmd_idx); + return CR_TRANSFER_FAIL; + } + + if (rsp_para1 != -1) + writeb(rsp_para1, sdmmc_base + SD_CONFIGURE1); + + writeb(rsp_para2, sdmmc_base + SD_CONFIGURE2); + + if (rsp_para3 != -1) + writeb(rsp_para3, sdmmc_base + SD_CONFIGURE3); + + g_cmd[0] = (0x40 | cmd_idx); + g_cmd[1] = (sd_arg >> 24) & 0xff; + g_cmd[2] = (sd_arg >> 16) & 0xff; + g_cmd[3] = (sd_arg >> 8) & 0xff; + g_cmd[4] = sd_arg & 0x000000FF; + g_cmd[5] = 0x00000000; + + writeb(g_cmd[0], sdmmc_base + SD_CMD0); + writeb(g_cmd[1], sdmmc_base + SD_CMD1); + writeb(g_cmd[2], sdmmc_base + SD_CMD2); + writeb(g_cmd[3], sdmmc_base + SD_CMD3); + writeb(g_cmd[4], sdmmc_base + SD_CMD4); + writeb(g_cmd[5], sdmmc_base + SD_CMD5); + + rtk_host->cmd_opcode = cmd_idx; + + rtk_sdmmc_get_cmd_timeout(cmd_info); + data_xfer_mode = CMD_RSP_ONLY; + if (RESP_TYPE_17B & rsp_para2) { + INT4_flag = true; + /*remap the resp dst buffer to un-cache*/ + sa = (u32) dma_phy_addr; + sa = sa / 8; + dma_val = RSP17_SEL | DDR_WR | DMA_XFER; + writeb(byte_count, sdmmc_base + SD_BYTE_CNT_L); //0x24 + writeb(byte_count>>8, sdmmc_base + SD_BYTE_CNT_H); //0x28 + writeb(block_count, sdmmc_base + SD_BLOCK_CNT_L); //0x2C + writeb(block_count>>8, sdmmc_base + SD_BLOCK_CNT_H); //0x30 + + writel(sa, sdmmc_base + CR_SD_DMA_CTL1); //espeical for R2 + writel(0x00000001, sdmmc_base + CR_SD_DMA_CTL2); //espeical for R2 + writel(dma_val, sdmmc_base + CR_SD_DMA_CTL3); //espeical for R2 + data_xfer_mode = CMD_RSP_DATA_READ; + + } else if (RESP_TYPE_6B & rsp_para2) { + //do nothing + } + + ret = rtk_sdmmc_int_wait(DRIVER_NAME, rtk_host, SD_SENDCMDGETRSP); + if (ret == CR_TRANS_OK) { + if (dma_virt_addr != 0) { + rtk_sdmmc_read_rsp(rtk_host, (void *)dma_virt_addr, rsp_len); + + if (rsp_len == 16) { + memcpy(RESP17_buffer, (void *)dma_virt_addr, 16); + rtk_sdmmc_swap_data(RESP17_buffer, sdmmc_base); + memcpy(rsp, (void *)RESP17_buffer, 16); + } else { + memcpy(rsp, (void *)dma_virt_addr, 16); + } + } else { + rtk_sdmmc_read_rsp(rtk_host, rsp, rsp_len); + } + + rtk_sdmmc_sync(rtk_host); + + if (cmd_idx == MMC_SET_RELATIVE_ADDR) { + g_crinit = 1; + printk(KERN_INFO "SD/MMC card init done.\n"); + } + } + + memset(dma_virt_addr, 0x00, SD_ALLOC_LENGTH); + + return ret; +} + +static void rtk_sdmmc_send_command(struct rtk_sdmmc_host *rtk_host, struct mmc_command *cmd) +{ + int ret = 0; + + struct sdmmc_cmd_pkt cmd_info; + void __iomem *sdmmc_base = rtk_host->sdmmc; + + memset(&cmd_info, 0, sizeof(struct sdmmc_cmd_pkt)); + + if (!rtk_host || !cmd) { + printk(KERN_ERR "%s: rtk_host or cmd is null\n", __func__); + return; + } + if (cmd->opcode == MMC_SEND_OP_COND) { + mmc_detected = 1; + } + + /*work around of bug switch voltage fail : force clock disable after cmd11*/ + if (cmd->opcode == SD_SWITCH_VOLTAGE) { + writeb(0x40, sdmmc_base + SD_BUS_STATUS); + } + + cmd_info.cmd = cmd; + cmd_info.rtk_host = rtk_host; + cmd_info.rsp_para2 = rtk_sdmmc_get_rsp_type(cmd_info.cmd); + cmd_info.rsp_len = rtk_sdmmc_get_rsp_len(cmd_info.rsp_para2); + + if (cmd->data) { + cmd_info.data = cmd->data; + + if (cmd->data->flags == MMC_DATA_READ) { + /* do nothing */ + } else if (cmd->data->flags == MMC_DATA_WRITE) { + if (rtk_host->wp ==1) { + printk(KERN_ERR "%s: card is locked!", __func__); + ret = -1; + cmd->retries = 0; + goto err_out; + } + } else { + printk(KERN_ERR "%s: error: cmd->data->flags= %d\n", __func__, cmd->data->flags); + cmd->error = -MMC_ERR_INVALID; + cmd->retries = 0; + goto err_out; + } + + if (cmd->opcode != SD_APP_SEND_SCR) { + ret = rtk_sdmmc_stream(&cmd_info); + } else { + struct scatterlist sg; + struct mmc_data data_SCR = {0}; + void *ssr; + + ssr = kmalloc(64, GFP_KERNEL | GFP_DMA); + if (!ssr) { + ret = CR_TRANSFER_FAIL; + goto err_out; + } + + sg_init_one(&sg, ssr, 64); + + rtk_sdmmc_debug("%s: data->blksz= %d, data->blocks= %d \n", __func__, cmd_info.data->blksz, cmd_info.data->blocks); + + data_SCR.blksz = cmd_info.data->blksz; + data_SCR.blocks = cmd_info.data->blocks; + data_SCR.sg = cmd_info.data->sg; + data_SCR.sg_len = cmd_info.data->sg_len; + + cmd_info.data->blksz = 64; + cmd_info.data->blocks = 1; + cmd_info.data->sg = &sg; + cmd_info.data->sg_len = 1; + + ret = rtk_sdmmc_stream(&cmd_info); + + if (!ret) { + sg_copy_from_buffer(data_SCR.sg, data_SCR.sg_len, ssr, data_SCR.blksz); + cmd_info.data->bytes_xfered = data_SCR.blksz; + rtk_sdmmc_debug("%s: SCR =\n", __func__); + } + kfree(ssr); + } + } else { + ret = rtk_sdmmc_send_cmd_get_rsp(&cmd_info); + } + + if (cmd->opcode == MMC_SELECT_CARD) { + rtk_host->rtflags |= RTKCR_FCARD_SELECTED; + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_6200KHZ); + } else if ((cmd->opcode == SD_SEND_RELATIVE_ADDR)&&((cmd->flags & (0x3 << 5)) == MMC_CMD_BCR)) { + sdmmc_rca = ((cmd->resp[0]) >> RCA_SHIFTER); + } + +err_out: + if (ret) { + if (ret == -RTK_RMOV) + cmd->retries = 0; + + if (cmd->opcode == 49 || cmd->opcode == 59 || cmd->opcode == 48|| cmd->opcode == 58) { + rtk_sdmmc_reset(rtk_host); + cmd->error = -110; + } else { + cmd->error = -MMC_ERR_FAILED; + } + } + tasklet_schedule(&rtk_host->req_end_tasklet); +} +static void rtk_sdmmc_request(struct mmc_host *host, struct mmc_request *mrq) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + struct mmc_command *cmd; + unsigned char card_cmd = 0; + + BUG_ON(rtk_host->mrq != NULL); + //down_write(&cr_sd_rw_sem); + down(&cr_sd_sem); + cmd = mrq->cmd; + rtk_host->mrq = mrq; + data_xfer_mode = CMD_RSP_ONLY; // init each request + + if(cmd->opcode == 2) + writel(readl(rtk_host->sdmmc + 0x20) & (~0x02), rtk_host->sdmmc + 0x20); //Enable L4 gate + + if (cmd->opcode == 58 || cmd->opcode == 59) { + card_cmd = host->card->raw_scr[0] & 0x0F; + if ((card_cmd & 0x08) != 0x08) { + cmd->error = -110; + goto done; + } + } + + if (cmd->opcode == 48 || cmd->opcode == 49) { + card_cmd = host->card->raw_scr[0] & 0xF; + if ((card_cmd & 0x8) != 0x8 && (card_cmd & 0x4) != 0x4) { + cmd->error = -110; + goto done; + } + } + + if (!(rtk_host->rtflags & RTKCR_FCARD_DETECTED)) { + cmd->error = -MMC_ERR_RMOVE; + cmd->retries = 0; + goto done; + } + + if (rtk_host && cmd) { + rtk_sdmmc_allocate_dma_buf(rtk_host, cmd); + rtk_sdmmc_send_command(rtk_host, cmd); + } else { +done: + tasklet_schedule(&rtk_host->req_end_tasklet); + } + + pre_cmd=cmd->opcode; + //up_write(&cr_sd_rw_sem); + //down_trylock(&cr_sd_sem); + if (cr_sd_sem.count==0) + up(&cr_sd_sem); //unplug will release semaphore, in this case we do not need to release the semaphore +} + +int rtk_sdmmc_clk_cls_chk(struct mmc_host *host) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + if(rtk_host->ins_event != EVENT_INSER && rtk_host->ins_event !=EVENT_REMOV) return 1; + return 0; +} +EXPORT_SYMBOL(rtk_sdmmc_clk_cls_chk); + +void rtk_sdmmc_close_clk(struct mmc_host *host) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + void __iomem *pll_base = rtk_host->pll; + void __iomem *gpiodir_base = rtk_host->gpiodir; + + int card_exist = readl(rtk_host->gpiodir+GPDATI1); + + if ((card_exist & 0x8) && !clk_disabled) { + clk_disabled=1; + printk(KERN_INFO "SD card does not exist and sd clk is disabled...\n"); + writel(readl(pll_base + CR_PLL_SD1) & 0xfffffffc ,pll_base + CR_PLL_SD1); + writel(readl(pll_base + CR_PLL_SD2) & 0xfffffffe ,pll_base + CR_PLL_SD2); + writel(0x00000000, pll_base + CR_PLL_SD4); + clk_disable_unprepare(clk_cr); + clk_disable_unprepare(clk_sd_ip); + reset_control_assert(rstc_cr); + + if (chip_id == CHIP_ID_RTD1319) + writel(readl(gpiodir_base+0x64)&0xfffffff3,gpiodir_base+0x64); //close the ldo enable to power saving + else if (chip_id == CHIP_ID_RTD1619B) + writel(readl(gpiodir_base+0xc4)&0xfffffff3,gpiodir_base+0xc4); + } +} +EXPORT_SYMBOL(rtk_sdmmc_close_clk); + +void rtk_sdmmc_open_clk(struct mmc_host *host) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + void __iomem *pll_base = rtk_host->pll; + void __iomem *gpiodir_base = rtk_host->gpiodir; + int card_exist = readl(rtk_host->gpiodir+GPDATI1); + + if ((card_exist & 0x8)==0 && clk_disabled) { + printk(KERN_INFO "SD card exists and sd clk is enabled...\n"); + reset_control_deassert(rstc_cr); + clk_prepare_enable(clk_cr); + clk_prepare_enable(clk_sd_ip); + + if (chip_id == CHIP_ID_RTD1319) + writel(readl(gpiodir_base + 0x64) | 0xc, gpiodir_base + 0x64); //open the ldo enable + else if (chip_id == CHIP_ID_RTD1619B) + writel(readl(gpiodir_base + 0xc4) | 0xc, gpiodir_base + 0xc4); + + writel(0x00000007, pll_base + CR_PLL_SD4); + writel(0x0000003, pll_base + CR_PLL_SD1); + mdelay(2); + writel(0x00002003, pll_base + CR_PLL_SD1); //PLL_SD1 + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + if (chip_id == CHIP_ID_RTD1619B) + writel(0x0451942d, pll_base + CR_PLL_SD2); + else + writel(0x04519893, pll_base + CR_PLL_SD2); //change from 4517893 to 0x04519893 for passing the EMI + writel(0x00564388, pll_base + CR_PLL_SD3); //Set PLL clock rate, default clock 100MHz + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + + if (chip_id == CHIP_ID_RTD1319) { + while((readl(rtk_host->sdmmc + 0x2c) & 0x1) == 0) { + printk(KERN_INFO "wait until clk open...\n"); + } + } else if (chip_id == CHIP_ID_RTD1619B) { + while((readl(rtk_host->sdmmc + 0xb4) & 0x80000000) == 0) { + printk(KERN_INFO "wait until clk open...\n"); + } + } + + clk_disabled = 0; + } +} + +static int rtk_sdmmc_get_cd(struct mmc_host *host) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + int card_exist = readl(rtk_host->gpiodir+GPDATI1); + + if(clk_disabled) return 0; //this is workaround for fear that the interrupt is triggered twice + + if (!(card_exist & 0x8)) { + printk(KERN_ERR "%s: SD card exists, card_exist = 0x%x\n", __func__, card_exist); + if(compatible_flag || (rtk_host->ins_event != EVENT_INSER && rtk_host->ins_event !=EVENT_REMOV) || re_initialize==true) { //this two flags is to detect first recognition and error handling + void __iomem *sdmmc_base = rtk_host->sdmmc; + u32 det_time = 0; + + compatible_flag = false; + rtk_host->ops->card_power(rtk_host, 1); //power on, Jim add + + rtk_host->ins_event = EVENT_INSER; + rtk_host->rtflags |= RTKCR_FCARD_DETECTED; + det_time = 1; + CMD8_SD1=false; + CMD55_MMC=false; + writel(0x00000000, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0x00, sdmmc_base + CR_CARD_STOP); //SD Card module transfer no stop + writeb(0x02, sdmmc_base + CARD_SELECT); //Specify the current active card module for the coming data transfer, bit 2:0 = 010 + writeb(0x04, sdmmc_base + CR_CARD_OE); //arget module is SD/MMC card module, bit 2 =1 + writeb(0x04, sdmmc_base + CARD_CLOCK_EN_CTL); //SD Card Module Clock Enable, bit 2 = 1 + writeb(0xD0, sdmmc_base + SD_CONFIGURE1); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_400KHZ); + writeb(0x00, sdmmc_base + SD_STATUS2); + printk(KERN_ERR "%s: SD card is being inserted now...!!!\n", __func__); + rtk_sdmmc_sync(rtk_host); + + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + mmc_detect_change(rtk_host->mmc, msecs_to_jiffies(det_time)); + } + + return 1; + } + + printk(KERN_ERR "%s: SD card does not exist, card_exist = 0x%x\n", __func__, card_exist); + + return 0; +} + +static int rtk_sdmmc_get_ro(struct mmc_host *host) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + int sd_wp = readl(rtk_host->gpiodir+GPDATI1); + if (sd_wp & 0x4) { + printk(KERN_ERR "%s: SD card is write protect\n", __func__); + return 1; + } + + printk(KERN_ERR "%s: SD card is not write protect\n", __func__); + + return 0; +} + +static void rtk_sdmmc_set_ios(struct mmc_host *host, struct mmc_ios *ios) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + u32 reginfo; + reginfo = readl(rtk_host->gpiodir+GPDATI1); + + //in 1395 platform, system will turn off the SD clock. This case is to handle that the SD card si unplugged during suspend + if(reginfo & 0x8) { + reset_control_deassert(rstc_cr); + clk_prepare_enable(clk_cr); + clk_prepare_enable(clk_sd_ip); + writel(0x00000007, rtk_host->pll + CR_PLL_SD4); + } + + if (ios->bus_mode == MMC_BUSMODE_PUSHPULL) { + rtk_sdmmc_debug("%s: ios busmode = pushpull\n", __func__); + if (ios->bus_width == MMC_BUS_WIDTH_8) { + rtk_sdmmc_debug("%s: set bus width 8\n", __func__); + rtk_sdmmc_set_bits(rtk_host, BUS_WIDTH_8); + } else if (ios->bus_width == MMC_BUS_WIDTH_4) { + rtk_sdmmc_debug("%s: set bus width 4\n", __func__); + rtk_sdmmc_set_bits(rtk_host, BUS_WIDTH_4); + } else { + rtk_sdmmc_set_bits(rtk_host, BUS_WIDTH_1); + rtk_sdmmc_debug("%s: set bus width 1\n", __func__); + } + + if (ios->clock >= UHS_SDR104_MAX_DTR && ios->timing == MMC_TIMING_UHS_SDR104) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_SD30); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_208000KHZ); + rtk_sdmmc_debug("%s: UHS SDR104 SDMMC_CLOCK_208000KHZ\n", __func__); + } else if (ios->clock >= UHS_SDR50_MAX_DTR && ios->timing == MMC_TIMING_UHS_SDR50) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_SD30); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_100000KHZ); + rtk_sdmmc_debug("%s: UHS SDR50 SDMMC_CLOCK_100000KHZ\n", __func__); + } else if (ios->clock >= UHS_SDR25_MAX_DTR && ios->timing == MMC_TIMING_UHS_SDR25) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_SD30); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_50000KHZ); + rtk_sdmmc_debug("%s: UHS SDR25 SDMMC_CLOCK_50000KHZ\n", __func__); + } else if (ios->clock >= UHS_SDR12_MAX_DTR && ios->timing == MMC_TIMING_UHS_SDR12) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_SD30); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_25000KHZ); + rtk_sdmmc_debug("%s: UHS SDR12 SDMMC_CLOCK_25000KHZ\n", __func__); + } else if (ios->clock >= UHS_DDR50_MAX_DTR && ios->timing == MMC_TIMING_UHS_DDR50) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_DDR); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_50000KHZ); + rtk_sdmmc_debug("%s: UHS DDR50 SDMMC_CLOCK_50000KHZ\n", __func__); + } else if (ios->clock >= HIGH_SPEED_MAX_DTR && ios->timing == MMC_TIMING_SD_HS) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_SD20); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_50000KHZ); + rtk_sdmmc_debug("%s: High Speed SDMMC_CLOCK_50000KHZ\n", __func__); + } else if (ios->clock >= 25000000) { + rtk_sdmmc_set_access_mode(rtk_host, ACCESS_MODE_SD20); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_25000KHZ); + } else { + if (rtk_host->rtflags & RTKCR_FCARD_SELECTED) { + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_6200KHZ); + rtk_sdmmc_debug("%s: Mid speed RTKCR_FCARD_SELECTED = 1 SDMMC_CLOCK_6200KHZ\n", __func__); + } else { + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_400KHZ); + rtk_sdmmc_debug("%s: Low speed SDMMC_CLOCK_400KHZ\n", __func__); + } + } + } else { //MMC_BUSMODE_OPENDRAIN + rtk_sdmmc_debug("%s: ios busmode != pushpull low speed SDMMC_CLOCK_400KHZ\n", __func__); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_400KHZ); + rtk_sdmmc_set_bits(rtk_host,BUS_WIDTH_1); + } + + if (ios->power_mode == MMC_POWER_UP) { + rtk_host->ops->card_power(rtk_host, 1); //power on + rtk_sdmmc_debug("%s: Power on\n", __func__); + } else if (ios->power_mode == MMC_POWER_OFF) { + rtk_host->ops->card_power(rtk_host, 0); //power off + rtk_sdmmc_debug("%s: Power off\n", __func__); + } + + //in 1395 platform, system will turn off the SD clock. This case is to handle that the SD card si unplugged during suspend + if(reginfo & 0x8) { + clk_disable_unprepare(clk_cr); + clk_disable_unprepare(clk_sd_ip); + } +} + +static void rtk_sdmmc_hw_initial(struct rtk_sdmmc_host *rtk_host) +{ + void __iomem *sdmmc_base = rtk_host->sdmmc; + void __iomem *pll_base = rtk_host->pll; + void __iomem *isopad_base = rtk_host->isopad; + int bErrorRetry_1 = 0; + unsigned int tmp = 0; + + writel(readl(pll_base + CR_PLL_SD4) | 0x00000004, pll_base + CR_PLL_SD4); + writel(readl(pll_base + CR_PLL_SD4) | 0x00000007, pll_base + CR_PLL_SD4); + writel(0x0000003, pll_base + CR_PLL_SD1); + mdelay(2); //change 10 ms to 2ms to shorten suspend/resume timing issue + writel(0x00002003, pll_base + CR_PLL_SD1); //PLL_SD1 + udelay(100); + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC, we modified this part because 1AC is to change SDIO PLL instead of SD card PLL + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) | 0x00070000, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to 4MHz by Hsin-yin + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + if (chip_id == CHIP_ID_RTD1619B) + writel(0x0451942d, pll_base + CR_PLL_SD2); + else + writel(0x04519893, pll_base + CR_PLL_SD2); //change from 4517893 to 0x04519893 for passing the EMI + writel(0x00564388, pll_base + CR_PLL_SD3); //Set PLL clock rate, default clock 100MHz + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writel(readl(sdmmc_base + 0x20) |0x02, sdmmc_base + 0x20); //Disable L4 gate + writeb(0x3,sdmmc_base + SD_BUS_TA_STATE); + writel(readl(sdmmc_base + 0x20) & (~0x01), sdmmc_base + 0x20); + writel(readl(sdmmc_base + 0x20) | 0x00000001, sdmmc_base + 0x20); //reset the DMA + udelay(100); + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) & 0xFFF8FFFF, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to normal clock source by Hsin-yin + udelay(100); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writeb(readb(sdmmc_base + SD_CONFIGURE1) & 0x000000EF, sdmmc_base + SD_CONFIGURE1); //Reset FIFO pointer by Hsin-yin + writel(0x00000007, pll_base + CR_PLL_SD4); //PLL_SD4 + udelay(100); + writeb(0xD0, sdmmc_base + SD_CONFIGURE1); + + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_400KHZ); + + gpiod_set_debounce(rtk_host->sdmmc_wp_gpio, 1000); + gpiod_set_debounce(rtk_host->sdmmc_cd_gpio, 1000); + + if (chip_id == CHIP_ID_RTD1619B) { + tmp = ((readl(isopad_base + 0x78) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base + 0x78); + tmp = ((readl(isopad_base + 0x7c) & 0xfff81fc0) | 0x0003601b); + writel(tmp, isopad_base + 0x7c); + tmp = ((readl(isopad_base + 0x80) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base+0x80); + } else if (chip_id == CHIP_ID_RTD1319) { + tmp = (0x003003) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp,isopad_base + 0x4c); + tmp = (0x003003<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp,isopad_base + 0x50); + tmp = (0x003003) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp,isopad_base + 0x54); + } else if (chip_id == CHIP_ID_RTD1619) { + tmp = (0x3003003 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp,isopad_base + 0xc); + writel(0x00300300,isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x3; + writel(tmp,isopad_base + 0x14); + } else if (chip_id == CHIP_ID_RTD1395) { + writel(0x198CD99B,isopad_base + 0x34); + writel(0x000CF99F,isopad_base + 0x38); + writel(0x000CF99F,isopad_base + 0x3c); + } + + writel(0x00000000, sdmmc_base + CR_SD_PAD_CTL); //change to 3.3v + writel(0x00000016, sdmmc_base + CR_SD_ISR); //enable interrupt + writel(0x00000016, sdmmc_base + CR_SD_ISREN); // disable all + writel(0x00000007, sdmmc_base + CR_SD_ISREN); + rtk_sdmmc_sync(rtk_host); + + writeb(0x02, sdmmc_base + CARD_SELECT); //for emmc, select SD ip + if (bErrorRetry_1) { + writeb(0x08, sdmmc_base + SD_SAMPLE_POINT_CTL); //sample point = SDCLK / 4 + writeb(0x10, sdmmc_base + SD_PUSH_POINT_CTL); //output ahead SDCLK /4 + } else { + writeb(0x00, sdmmc_base + SD_SAMPLE_POINT_CTL); //sample point = SDCLK / 4 + writeb(0x00, sdmmc_base + SD_PUSH_POINT_CTL); //output ahead SDCLK /4 + } +} + +static void rtk_sdmmc_hw_reset(struct mmc_host *host) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(host); + void __iomem *sdmmc_base = rtk_host->sdmmc; + + sd_in_receive_data_state = 0; //CMD25_WO_STOP_COMMAND + sd_current_blk_address = 0; //CMD25_WO_STOP_COMMAND + rtk_host->rtk_sdmmc_cmd12 = NULL; //CMD25_WO_STOP_COMMAND + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + + rtk_sdmmc_hw_initial(rtk_host); + writeb(0xFF, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state + writeb(0x00, sdmmc_base + CR_CARD_STOP); //SD Card module transfer no stop + writeb(0x02, sdmmc_base + CARD_SELECT); //Specify the current active card module for the coming data transfer, bit 2:0 = 010 + writeb(0x04, sdmmc_base + CR_CARD_OE); //arget module is SD/MMC card module, bit 2 =1 + writeb(0x04, sdmmc_base + CARD_CLOCK_EN_CTL); //SD Card Module Clock Enable, bit 2 = 1 + writeb(0xD0, sdmmc_base + SD_CONFIGURE1); + writeb(0x00, sdmmc_base + SD_STATUS2); //SD CMD Response Timeout Error disable //#x /b 0x18010584 + + rtk_host->ops->card_power(rtk_host, 0); //power off + rtk_host->ops->card_power(rtk_host, 1); //power on + + mmc_detected = 0; + + rtk_sdmmc_sync(rtk_host); +} + +static int rtk_sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(mmc); + void __iomem *sdmmc_base = rtk_host->sdmmc; + void __iomem *pll_base = rtk_host->pll; + int ret = 0; + u32 temp=0; + u32 orig=0; + + if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_330) { + + if (chip_id == CHIP_ID_RTD1619B) + rtk_sdmmc_pad_pwrctrl(rtk_host, MMC_SIGNAL_VOLTAGE_180); + + ret = rtk_sdmmc_wait_voltage_stable_low(rtk_host); //check DAT[3:0] are at LOW level + + if (ret < 0) + goto out; + + writeb(0x3B, sdmmc_base + CARD_CLOCK_EN_CTL); //host stop clk + mdelay(10); //delay 5 ms to fit SD spec + + writel(0x00000000, sdmmc_base + CR_SD_PAD_CTL); + + rtk_sdmmc_sync(rtk_host); + + orig = readl(pll_base + CR_PLL_SD1); + + temp = ((orig & 0xffffbfff) | 0x2000); + writel(temp, pll_base + CR_PLL_SD1); + mdelay(10); + temp = (orig & 0xffff9fff); + writel(temp, pll_base + CR_PLL_SD1); + mdelay(10); + temp = ((orig & 0xffffdfff) | 0x4000); + writel(temp, pll_base + CR_PLL_SD1); + mdelay(10); + temp = (orig | 0x6000); + writel(temp, pll_base + CR_PLL_SD1); + mdelay(10); + writeb(0x3F, sdmmc_base + CARD_CLOCK_EN_CTL); //force output clk + writeb(0x80, sdmmc_base + SD_BUS_STATUS); //force a short period 1.8v clk + rtk_sdmmc_sync(rtk_host); + + ret = rtk_sdmmc_wait_voltage_stable_high(rtk_host); //check DAT[3:0] are at HIGH level + if (ret < 0) + goto out; + } + + writeb(0x00, sdmmc_base + SD_BUS_STATUS); //stop 1.8v clk + +out: + return ret; +} + +static int rtk_sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct rtk_sdmmc_host *rtk_host = mmc_priv(mmc); + void __iomem *sdmmc_base = rtk_host->sdmmc; + void __iomem *pll_base = rtk_host->pll; + + int ret = 0; + unsigned int reg_tmp = 0; + unsigned int reg_tmp2 = 0; + unsigned int reg_tuned3318 = 0; + + reg_tmp2 = readl(pll_base + CR_PLL_SD2); //disable spectrum + writel((reg_tmp2 & 0xFFFF1FFF), pll_base + CR_PLL_SD2); //PLL_SD2 clear [15:13] + + /*if tune tx phase fail, down 8MHz and retry*/ + do{ + ret = rtk_sdmmc_tuning_tx(rtk_host); + if (ret == -MMC_ERR_RMOVE) { + printk(KERN_ERR "%s: Tuning TX fail.\n", __func__); + return ret; + } else if (ret) { + reg_tmp = readl(pll_base + CR_PLL_SD3); + reg_tuned3318 = (reg_tmp & 0x03FF0000) >> 16; + if (reg_tuned3318 <= 100) { + printk(KERN_ERR "%s: Tuning TX fail\n", __func__); + return ret; + } + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) | 0x00070000, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to 4MHz by Hsin-yin + reg_tmp = ((reg_tmp & (~0x3FF0000)) | ((reg_tuned3318 - 8) << 16)); //down 8MHz + writel(0x00000006, pll_base + 0x01EC); //JIM modified, 1AC->1EC + writel(reg_tmp, pll_base + CR_PLL_SD3); + mdelay(2); + writel(0x00000007, pll_base + 0x01EC); //JIM modified, 1AC->1EC + udelay(200); + writel(readl(sdmmc_base + CR_SD_CKGEN_CTL) & 0xFFF8FFFF, sdmmc_base + CR_SD_CKGEN_CTL); //Switch SD source clock to normal clock source by Hsin-yin + writeb(readb(sdmmc_base + SD_CONFIGURE1) & 0xEF, sdmmc_base + SD_CONFIGURE1); //Reset FIFO pointer by Hsin-yin + } + } while (ret); + + if (ret) { + printk(KERN_ERR "%s: Tuning TX fail\n", __func__); + return ret; + } + + ret = rtk_sdmmc_tuning_rx(rtk_host); + writel(reg_tmp2, pll_base + CR_PLL_SD2); //enable spectrum + + if (ret) { + printk(KERN_ERR "%s: Tuning RX fail\n", __func__); + return ret; + } + + printk(KERN_INFO "%s CR_PLL_SD3: %d (0x%02x)\n", __func__, (readl(pll_base + CR_PLL_SD3) >> 16), (readl(pll_base + CR_PLL_SD3) >> 16)); + printk(KERN_INFO "%s CLK_GEN DVI: %d\n", __func__, 1 << (readl(sdmmc_base + CR_SD_CKGEN_CTL) & 0x03)); + + return ret; +} + +static void rtk_sdmmc_init_card(struct mmc_host *host, struct mmc_card *card) +{ + host->card = card; +} + +static const struct mmc_host_ops rtk_sdmmc_ops ={ + .request = rtk_sdmmc_request, + .get_ro = rtk_sdmmc_get_ro, + .get_cd = rtk_sdmmc_get_cd, + .set_ios = rtk_sdmmc_set_ios, + .hw_reset = rtk_sdmmc_hw_reset, + .start_signal_voltage_switch = rtk_sdmmc_switch_voltage, + .execute_tuning = rtk_sdmmc_execute_tuning, + .init_card = rtk_sdmmc_init_card, +}; + +#ifdef CMD25_WO_STOP_COMMAND +static void rtk_sdmmc_cmd12_fun(struct timer_list *t) +{ + struct rtk_sdmmc_host *rtk_host = from_timer(rtk_host, t, rtk_sdmmc_stop_cmd); + + if (sd_in_receive_data_state && rtk_host->rtk_sdmmc_cmd12 && rtk_host) { + + if ( down_trylock(&cr_sd_sem) != 0 ) { + mod_timer(&rtk_host->rtk_sdmmc_stop_cmd, jiffies + 20); + } else { + sd_in_receive_data_state = 0; + do_stop_command_wo_complete = 1; + wait_stop_command_irq_done = 1; + rtk_sdmmc_send_stop_cmd(rtk_host->rtk_sdmmc_cmd12, rtk_host, 1); + rtk_sdmmc_wait_stop_cmd_irq_done(); + pre_cmd = 12; + if (cr_sd_sem.count == 0) + up(&cr_sd_sem); // unplug will release semaphore, in this case we do not need to release the semaphore + } + } +} +#endif + +static irqreturn_t rtk_sdmmc_cd_irq(int irq, void *data) +{ + struct rtk_sdmmc_host *rtk_host = (struct rtk_sdmmc_host *)data; + void __iomem *sdmmc_base = rtk_host->sdmmc; + void __iomem *isopad_base = rtk_host->isopad; + u32 det_time = 0; + int card_exist; + unsigned int tmp=0; + + card_exist = readl(rtk_host->gpiodir+GPDATI1); + rtk_host->rtflags &= ~RTKCR_FCARD_DETECTED; + rtk_host->wp = 0; + if(card_exist & 0x8) { + if(clk_disabled) return IRQ_HANDLED; + + rtk_host->ins_event = EVENT_REMOV; + rtk_host->rtflags &= ~RTKCR_FCARD_DETECTED; + det_time = 1; + driving_capacity=0; + + if(down_trylock(&cr_sd_sem)!=0); //check if the lock is occupied, if not, then occupied + up(&cr_sd_sem); + + if (chip_id == CHIP_ID_RTD1395) { + writel(0x198CD99B, isopad_base + 0x34); + writel(0x000CF99F, isopad_base + 0x38); + writel(0x000CF99F, isopad_base + 0x3c); + } else if (chip_id == CHIP_ID_RTD1619) { + tmp = (0x3003003 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x00300300, isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x3; + writel(tmp, isopad_base + 0x14); + } else if (chip_id == CHIP_ID_RTD1319) { + tmp = (0x003003) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x003003 << 4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x003003) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + } else if (chip_id == CHIP_ID_RTD1619B) { + tmp = ((readl(isopad_base + 0x78) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base + 0x78); + tmp = ((readl(isopad_base + 0x7c) & 0xfff81fc0) | 0x0003601b); + writel(tmp, isopad_base + 0x7c); + tmp = ((readl(isopad_base + 0x80) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base+0x80); + } + + mini_SD = 0; + broken_flag = false; + writel(0x0, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0xff, sdmmc_base + CR_CARD_STOP); //SD Card module transfer stop and idle state + + writeb(0x3b, sdmmc_base + CARD_CLOCK_EN_CTL); + + rtk_host->ops->card_power(rtk_host, 0); //power off, Jim add + + if (chip_id == CHIP_ID_RTD1619B) + rtk_sdmmc_pad_pwrctrl(rtk_host, MMC_SIGNAL_VOLTAGE_330); + + printk(KERN_ERR "SD card is being removed now...!!!\n"); + } + else { + rtk_sdmmc_open_clk(rtk_host->mmc); + rtk_host->ops->card_power(rtk_host, 1); //power on, Jim add + if(clk_disabled==0) { + rtk_host->ins_event = EVENT_INSER; + rtk_host->rtflags |= RTKCR_FCARD_DETECTED; + det_time = 1; + CMD8_SD1=false; + CMD55_MMC=false; + + writel(0x00000000, sdmmc_base + CR_SD_DMA_CTL3); //stop dma control + data_xfer_mode = CMD_RSP_ONLY; + writeb(0x00, sdmmc_base + CR_CARD_STOP); //SD Card module transfer no stop + writeb(0x02, sdmmc_base + CARD_SELECT); //Specify the current active card module for the coming data transfer, bit 2:0 = 010 + writeb(0x04, sdmmc_base + CR_CARD_OE); //arget module is SD/MMC card module, bit 2 =1 + writeb(0x04, sdmmc_base + CARD_CLOCK_EN_CTL); //SD Card Module Clock Enable, bit 2 = 1 + writeb(0xD0, sdmmc_base + SD_CONFIGURE1); + rtk_sdmmc_speed(rtk_host, SDMMC_CLOCK_400KHZ); + writeb(0x00, sdmmc_base + SD_STATUS2); + printk(KERN_ERR "%s: SD card is being inserted now...!!!\n", __func__); + } + } + + rtk_sdmmc_sync(rtk_host); + + rtk_host->rtflags &= ~RTKCR_FCARD_SELECTED; + sdmmc_rca = 0; + mmc_detect_change(rtk_host->mmc, msecs_to_jiffies(det_time)); + return IRQ_HANDLED; +} +static irqreturn_t rtk_sdmmc_wp_irq(int irq, void *data) +{ + struct rtk_sdmmc_host *rtk_host = (struct rtk_sdmmc_host *)data; + int sd_wp; + sd_wp = readl(rtk_host->gpiodir+GPDATI1); + if(sd_wp & 0x4) { + rtk_host->wp = 1; + } + else { + rtk_host->wp = 0; + } + return IRQ_HANDLED; +} + +static void rtk_sdmmc_req_end_tasklet(unsigned long param) +{ + struct rtk_sdmmc_host *rtk_host = (struct rtk_sdmmc_host *)param; + struct mmc_request* mrq; + + mrq = rtk_host->mrq; + rtk_host->mrq = NULL; + + mmc_request_done(rtk_host->mmc, mrq); +} + +static void rtk_sdmmc_timeout(struct timer_list *t) +{ + struct rtk_sdmmc_host *rtk_host = from_timer(rtk_host, t, timer); + u32 int_status = readl(rtk_host->sdmmc+CR_SD_ISR); + u32 int_status_en = readl(rtk_host->sdmmc+CR_SD_ISREN); + + if (poll==1) return; //this timeout function is for interrupt mode + + if (rtk_host->ins_event ==EVENT_REMOV) { + printk(KERN_ERR "command timeout because the SD card is removed\n"); + complete(rtk_host->int_waiting); + writel(0x00000016, rtk_host->sdmmc + CR_SD_ISR); + return; + } + + if (broken_flag==true) { + complete(rtk_host->int_waiting); + writel(0x00000016, rtk_host->sdmmc + CR_SD_ISR); + return; + } + + printk(KERN_ERR"%s: command/data timeout, pre_cmd=%d, cmd=%d, poll=%d, ISR=%x, ISR_EN=%x\n", __func__,pre_cmd,rtk_host->cmd_opcode,poll,int_status,int_status_en); + + if (rtk_host->cmd_opcode==8 && int_status==0) { + CMD8_SD1=true; //SD 1.x + printk(KERN_ERR "Reject SD 2.x command\n"); + } else if (rtk_host->cmd_opcode==55 && CMD8_SD1==true && (int_status==0x0||int_status==0x6)) { + CMD55_MMC=true; //MMC card + printk(KERN_ERR "Reject SD 1.x command\n"); + } + + complete(rtk_host->int_waiting); + writel(0x00000016, rtk_host->sdmmc + CR_SD_ISR); + rtk_sdmmc_sync(rtk_host); + + if (pre_cmd==0 && rtk_host->cmd_opcode==1 && (int_status==0x0 || int_status==0x16)) { + if (mini_SD==0) { + printk(KERN_ERR "This might be mini SD card\n"); + mini_SD=1; + compatible_flag = true; + remove_sdcard(rtk_host); + } else { + printk(KERN_ERR "SD/MMC card is broken!\n"); + broken_flag=true; + card_broken(rtk_host); + return; + } + } else if (CMD55_MMC==false && rtk_host->cmd_opcode!=8 && (int_status==0x0 || int_status==0x16)) { + /* this statement is to workaround some SD card cannot be recognized and read command will return error, + * tuning the driving or PLL can fix this issue but put this reset function in case + */ + compatible_flag = true; + printk(KERN_ERR "SD compatible issue: reset the card and adjust the driving capacity!\n"); + driving_capacity++; + remove_sdcard(rtk_host); + } +} + +static void rtk_sdmmc_card_power(struct rtk_sdmmc_host *rtk_host, u8 status) +{ + int res = 0; + u32 power_status = rtk_host->power_status; + u32 tmp; + void __iomem *isopad_base = rtk_host->isopad; + + if (status == power_status) + return; + + if (status) { + res = gpiod_direction_output(rtk_host->sdmmc_gpio, 0); + + if (chip_id == CHIP_ID_RTD1619B) { + /* Set gpio pull down/up function to pull up */ + tmp = ((readl(isopad_base + 0x78) & 0xe3ff1ff8) | 0x1c00e007); + writel(tmp, isopad_base + 0x78); + tmp = ((readl(isopad_base + 0x7c) & 0xfffffc7f) | 0x00000380); + writel(tmp, isopad_base + 0x7c); + tmp = ((readl(isopad_base + 0x80) & 0xffff1ff8) | 0x0000e007); + writel(tmp, isopad_base+0x80); + /* Set pad driving */ + tmp = ((readl(isopad_base + 0x78) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base + 0x78); + tmp = ((readl(isopad_base + 0x7c) & 0xfff81fc0) | 0x0003601b); + writel(tmp, isopad_base + 0x7c); + tmp = ((readl(isopad_base + 0x80) & 0xfe07f03f) | 0x00d806c0); + writel(tmp, isopad_base+0x80); + } else if (chip_id == CHIP_ID_RTD1319) { + tmp = (0x003003) | (readl(isopad_base + 0x4c) & 0xff000000); + writel(tmp, isopad_base + 0x4c); + tmp = (0x003003<<4) | (readl(isopad_base + 0x50) & 0xf000000f); + writel(tmp, isopad_base + 0x50); + tmp = (0x003003) | (readl(isopad_base + 0x54) & 0xff000000); + writel(tmp, isopad_base + 0x54); + } else if (chip_id == CHIP_ID_RTD1619) { + tmp = (0x3003003 << 4) | (readl(isopad_base + 0xc) & 0xf); + writel(tmp, isopad_base + 0xc); + writel(0x00300300,isopad_base + 0x10); + tmp = (readl(isopad_base + 0x14) & 0xfffff000) | 0x3; + writel(tmp, isopad_base + 0x14); + } else if (chip_id == CHIP_ID_RTD1395) { + writel(0x198CD99B, isopad_base + 0x34); + writel(0x000CF99F, isopad_base + 0x38); + writel(0x000CF99F, isopad_base + 0x3c); + } + + if (res < 0) { + printk(KERN_ERR "%s: can't gpio output = %d (power on)\n", __func__, desc_to_gpio(rtk_host->sdmmc_gpio)); + } else { + power_status = 1; //card is power on + mdelay(10); //delay 10 ms after power on + } + } else { + res = gpiod_direction_input(rtk_host->sdmmc_gpio); + + if (chip_id == CHIP_ID_RTD1619B) { + writel(readl(isopad_base + 0x78) & 0xfbffdffe,isopad_base + 0x78); + writel(readl(isopad_base + 0x7c) & 0xffffff7f,isopad_base + 0x7c); + writel(readl(isopad_base + 0x80) & 0xffffdffe,isopad_base + 0x80); + } else if (chip_id == CHIP_ID_RTD1319) { + writel(readl(isopad_base + 0x4c) & 0xffffeffe, isopad_base + 0x4c); + writel(readl(isopad_base + 0x50) & 0xfffeffef, isopad_base + 0x50); + writel(readl(isopad_base + 0x54) & 0xffffeffe, isopad_base + 0x54); + } else if (chip_id == CHIP_ID_RTD1619){ + writel(readl(isopad_base + 0xc) & 0xdffdffdf, isopad_base + 0xc); + writel(readl(isopad_base + 0x10) & 0xffdffdff, isopad_base + 0x10); + writel(readl(isopad_base + 0x14) & 0xfffffffd, isopad_base + 0x14); + } else if (chip_id == CHIP_ID_RTD1395) { + writel(readl(isopad_base + 0x34) & 0xfffff7fe,isopad_base + 0x34); + writel(readl(isopad_base + 0x38) & 0xfffff7fe,isopad_base + 0x38); + writel(readl(isopad_base + 0x3c) & 0xfffff7fe,isopad_base + 0x3c); + } + + if (res < 0) { + printk(KERN_ERR "%s: can't gpio input = %d (power off)\n", __func__, desc_to_gpio(rtk_host->sdmmc_gpio)); + } else { + power_status = 0; //card is power off + mdelay(10); //delay 10 ms after power off + } + } + rtk_host->power_status = power_status; +} + +static u8 rtk_sdmmc_chk_cmdcode(struct mmc_command* cmd) +{ + u8 cmdcode = 0; + + if (cmd->opcode < 59) { + if (cmd->opcode == 8 && mmc_detected == 1) + cmdcode = SD_NORMALREAD; + else + cmdcode = rtk_sdmmc_cmdcode[cmd->opcode][0]; + + WARN_ON(cmd->data == NULL); + + if (cmd->data->flags & MMC_DATA_WRITE) { + if (cmd->opcode == 42) + cmdcode = SD_NORMALWRITE; + else if (cmd->opcode == 56) + cmdcode = SD_AUTOWRITE2; + } + } else { + cmdcode = SD_CMD_UNKNOW; + } + + return cmdcode; +} + +static irqreturn_t rtk_sdmmc_irq(int irq, void *data) +{ + struct rtk_sdmmc_host *rtk_host = (struct rtk_sdmmc_host *)data; + void __iomem *sdmmc_base = rtk_host->sdmmc; + u32 int_status = 0; + + rtk_sdmmc_sync(rtk_host); + + int_status = readl(sdmmc_base + CR_SD_ISR); + if((int_status & ISRSTA_INT2) && rtk_host->cmd_opcode!=13 && rtk_host->cmd_opcode!=19 ) { + irq_error_bit=1; + goto clear_irq; + } + + if (INT4_flag==true) { + if (data_xfer_mode == CMD_RSP_DATA_READ || data_xfer_mode == DATA_ONLY){ + if(!(int_status & ISRSTA_INT4)) + return IRQ_HANDLED; + } else { + if(!(int_status & ISRSTA_INT1)) + return IRQ_HANDLED; + } + } else { + if (!(int_status & ISRSTA_INT1)) + return IRQ_HANDLED; + } + +clear_irq: + if (poll==0) { + del_timer(&rtk_host->timer); + complete(rtk_host->int_waiting); + } + + writel(0x00000016, sdmmc_base + CR_SD_ISR); + rtk_sdmmc_sync(rtk_host); + + if ( wait_stop_command_irq_done ) { + wait_stop_command_irq_done = 0; // irq finish + } + return IRQ_HANDLED; +} + +static struct rtk_sdmmc_host_ops sdmmc_ops = { + .card_power = rtk_sdmmc_card_power, + .chk_cmdcode = rtk_sdmmc_chk_cmdcode, +}; + +static const struct of_device_id rtk_sdmmc_match[] = { + { .compatible = "realtek,rtd129x-sdmmc", }, + { .compatible = "realtek,rtd13xx-sdmmc", }, + { .compatible = "realtek,rtd1619b-sdmmc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtk_sdmmc_match); + +static void rtk_sdmmc_show_version(void) +{ + printk(KERN_INFO "%s: build at : %s \n", DRIVER_NAME, utsname()->version); + +#ifdef CONFIG_MMC_BLOCK_BOUNCE + printk(KERN_INFO "%s: CONFIG_MMC_BLOCK_BOUNCE enable\n", DRIVER_NAME); +#else + printk(KERN_INFO "%s: CONFIG_MMC_BLOCK_BOUNCE disable\n", DRIVER_NAME); +#endif +} + +static int rtk_sdmmc_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc = NULL; + struct rtk_sdmmc_host *rtk_host = NULL; + int ret = 0; + int irq = 0; + struct device_node *sdmmc_node = pdev->dev.of_node; + const u32 *prop; + int size; + + chip_id = get_rtd_chip_id(); + + clk_cr = devm_clk_get(&pdev->dev, "sd"); + if (IS_ERR(clk_cr)) { + printk(KERN_WARNING "%s: clk_get() returns %ld\n", __func__, + PTR_ERR(clk_cr)); + clk_cr = NULL; + } + + clk_sd_ip = devm_clk_get(&pdev->dev, "sd_ip"); + if (IS_ERR(clk_sd_ip)) { + printk(KERN_WARNING "%s: clk_get() returns %ld\n", __func__, + PTR_ERR(clk_sd_ip)); + clk_sd_ip = NULL; + } + + rstc_cr = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(rstc_cr)) { + printk(KERN_WARNING "%s: reset_control_get() returns %ld\n", __func__, + PTR_ERR(rstc_cr)); + rstc_cr = NULL; + } + + rtk_sdmmc_show_version(); + + do_stop_command_wo_complete = 0; // probe stage + wait_stop_command_irq_done = 0; // probe stage + + sema_init( &cr_sd_sem, 1 );//probe stage + + irq = irq_of_parse_and_map(sdmmc_node, 0); + if (!irq) { + printk(KERN_ERR "%s: fail to parse of irq.\n", __func__); + return -ENXIO; + } + + mmc = mmc_alloc_host(sizeof(struct rtk_sdmmc_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + rtk_global_host=rtk_host = mmc_priv(mmc); + memset(rtk_host, 0, sizeof(struct rtk_sdmmc_host)); + + rtk_host->sdmmc = of_iomap(sdmmc_node, 0); + rtk_host->pll = of_iomap(sdmmc_node, 1); + rtk_host->sysbrdg = of_iomap(sdmmc_node, 2); + rtk_host->isopad = of_iomap(sdmmc_node, 3); + rtk_host->gpiodir = of_iomap(sdmmc_node, 5); + rtk_host->int_waiting = &rtk_sdmmc_wait; + + prop = of_get_property(pdev->dev.of_node, "sdmmc-bounce", &size); + if (prop) { + rtk_host->sdmmc_bounce_buf_val = of_read_number(prop, 1); + printk(KERN_ERR "[%s] get sdmmc-bounce value : %d \n",__func__, rtk_host->sdmmc_bounce_buf_val); + } else { + rtk_host->sdmmc_bounce_buf_val = 0; + printk(KERN_ERR "[%s] assign sdmmc-bounce default value %d !!\n",__func__, rtk_host->sdmmc_bounce_buf_val); + } + + rtk_host->sdmmc_gpio = devm_gpiod_get(&pdev->dev, "sd-power", GPIOD_OUT_LOW); + if (IS_ERR(rtk_host->sdmmc_gpio)) { + printk(KERN_ERR "%s: can't request gpio %d\n", __func__, desc_to_gpio(rtk_host->sdmmc_gpio)); + return -EINVAL; + } + + rtk_host->sdmmc_wp_gpio = devm_gpiod_get(&pdev->dev, "sd-wp", GPIOD_IN); + if (IS_ERR(rtk_host->sdmmc_wp_gpio)) { + printk(KERN_ERR "%s: can't request gpio %d\n", __func__, desc_to_gpio(rtk_host->sdmmc_wp_gpio)); + return -EINVAL; + } + + rtk_host->sdmmc_cd_gpio = devm_gpiod_get(&pdev->dev, "sd-cd", GPIOD_IN); + if (IS_ERR(rtk_host->sdmmc_cd_gpio)) { + printk(KERN_ERR "%s: can't request gpio %d\n", __func__, desc_to_gpio(rtk_host->sdmmc_cd_gpio)); + return -EINVAL; + } + + reset_control_deassert(rstc_cr); + clk_prepare_enable(clk_cr); + clk_prepare_enable(clk_sd_ip); + + if (chip_id == CHIP_ID_RTD1319) + writel(readl(rtk_host->gpiodir + 0x64) | 0xc, rtk_host->gpiodir + 0x64); + else if (chip_id == CHIP_ID_RTD1619B) + writel(readl(rtk_host->gpiodir + 0xc4) | 0xc, rtk_host->gpiodir + 0xc4); + + rtk_host->mmc = mmc; + rtk_host->dev = &pdev->dev; + rtk_host->ops = &sdmmc_ops; + + rtk_sdmmc_hw_initial(rtk_host); + + spin_lock_init(&rtk_host->lock); + + mmc->ocr_avail = MMC_VDD_30_31 | + MMC_VDD_31_32 | + MMC_VDD_32_33 | + MMC_VDD_33_34 | + MMC_VDD_165_195; + + mmc->caps = MMC_CAP_4_BIT_DATA | + MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_HW_RESET | + MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR12 | + MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50; + + mmc->caps2 = MMC_CAP2_NO_SDIO; + mmc->f_min = 10000000 >> 8; //RTK min bus clk is 10Mhz/256 + mmc->f_max = 208000000; //RTK max bus clk is 208Mhz + + if(rtk_host->sdmmc_bounce_buf_val == 1) + mmc->max_segs = 256; + else + mmc->max_segs = 1; + + mmc->max_blk_size = 512; + mmc->max_blk_count = 0x1000; + mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + + if(rtk_host->sdmmc_bounce_buf_val==1) { + printk(KERN_ERR "Allocate SDMMC bounce buffer !!!\n"); + + rtk_host->sdmmc_bounce_buf = kmalloc(BOUNCE_SIZE, GFP_KERNEL); + if(!rtk_host->sdmmc_bounce_buf) + printk(KERN_ERR "unable to allocate sdmmc_bounce_buffer !!!\n"); + + rtk_host->sdmmc_bounce_sg = sdmmc_alloc_sg(1, GFP_KERNEL); + if (!rtk_host->sdmmc_bounce_sg) + printk(KERN_ERR "unable to allocate sdmmc_bounce_sg !!!\n"); + } + + tasklet_init(&rtk_host->req_end_tasklet, rtk_sdmmc_req_end_tasklet, (unsigned long)rtk_host); + + ret = request_irq(irq, rtk_sdmmc_irq, IRQF_SHARED, DRIVER_NAME, rtk_host); + if (ret) { + printk(KERN_ERR "%s: cannot assign irq %d\n", __func__, irq); + goto out; + } else { + rtk_host->irq = irq; + } + + rtk_host->cd_irq = gpiod_to_irq(rtk_host->sdmmc_cd_gpio); + if(!rtk_host->cd_irq) + printk(KERN_ERR "Cannot get the SD CD irq...\n"); + else + printk(KERN_INFO "SD CD irq=%d\n",rtk_host->cd_irq); + + rtk_host->wp_irq = gpiod_to_irq(rtk_host->sdmmc_wp_gpio); + if(!rtk_host->wp_irq) + printk(KERN_ERR "Cannot get the SD WP irq...\n"); + else + printk(KERN_INFO "SD WP irq=%d\n",rtk_host->wp_irq); + + irq_set_irq_type(rtk_host->cd_irq, IRQ_TYPE_EDGE_BOTH); + ret = request_irq(rtk_host->cd_irq, rtk_sdmmc_cd_irq, IRQF_SHARED, DRIVER_NAME, rtk_host); + if (ret) { + printk(KERN_ERR "%s: cannot assign irq %d\n", __func__, irq); + goto out; + } + + irq_set_irq_type(rtk_host->wp_irq, IRQ_TYPE_EDGE_BOTH); + + ret = request_irq(rtk_host->wp_irq, rtk_sdmmc_wp_irq, IRQF_SHARED, DRIVER_NAME, rtk_host); + if (ret) { + printk(KERN_ERR "%s: cannot assign irq %d\n", __func__, irq); + goto out; + } + + timer_setup(&rtk_host->timer, rtk_sdmmc_timeout, 0); + +#ifdef CMD25_WO_STOP_COMMAND + timer_setup(&rtk_host->rtk_sdmmc_stop_cmd, rtk_sdmmc_cmd12_fun, 0); +#endif + mmc->ops = &rtk_sdmmc_ops; + rtk_host->rtflags &= ~(RTKCR_FCARD_DETECTED | RTKCR_FCARD_SELECTED); + rtk_host->int_status_old &= ~SD_EXISTENCE; + sdmmc_rca = 0; + g_crinit = 0; + + platform_set_drvdata(pdev, mmc); + + rtk_sdmmc_sync(rtk_host); + + ret = mmc_add_host(mmc); + if (ret) + goto out; + + return 0; +out: + if (mmc) + mmc_free_host(mmc); + + return ret; +} + +static int rtk_sdmmc_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + if (mmc) { + //kthread_stop(rtk_SD_task); + struct rtk_sdmmc_host *rtk_host = mmc_priv(mmc); + + flush_scheduled_work(); + + rtk_sdmmc_free_dma_buf(rtk_host); + + mmc_remove_host(mmc); + if (!mmc) { + printk(KERN_INFO "Realtek SD/MMC host have removed.\n"); + } + + free_irq(rtk_host->irq, rtk_host); + + del_timer_sync(&rtk_host->timer); +#ifdef CMD25_WO_STOP_COMMAND + del_timer_sync(&rtk_host->rtk_sdmmc_stop_cmd); +#endif + if (rtk_host->sdmmc) + iounmap(rtk_host->sdmmc); + + if (rtk_host->pll) + iounmap(rtk_host->pll); + + mmc_free_host(mmc); + gpiod_put(rtk_host->sdmmc_gpio); + if(rtk_host->sdmmc_bounce_buf_val==1) { + printk(KERN_ERR "release SDMMC bounce buffer !!!\n"); + kfree(rtk_host->sdmmc_bounce_buf); + kfree(rtk_host->sdmmc_bounce_sg); + } + } + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver rtk_sdmmc_driver = { + .probe = rtk_sdmmc_probe, + .remove = rtk_sdmmc_remove, + .driver = { + .name = DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &rtk_sdmmc_pm_ops, +#endif + .of_match_table = rtk_sdmmc_match, + }, + .shutdown = rtk_sdmmc_shutdown, +}; +module_platform_driver(rtk_sdmmc_driver); diff --git a/drivers/mmc/host/rtk-sdmmc.h b/drivers/mmc/host/rtk-sdmmc.h new file mode 100644 index 000000000000..f7989ff0ff1d --- /dev/null +++ b/drivers/mmc/host/rtk-sdmmc.h @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek SD/MMC/mini SD card driver + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#ifndef DRIVERS_MMC_HOST_RTK_SDMMC_H_ +#define DRIVERS_MMC_HOST_RTK_SDMMC_H_ + +#ifdef CONFIG_MMC_RTK_SDMMC_DEBUG +#define rtk_sdmmc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args) +#else +#define rtk_sdmmc_debug(fmt, args...) +#endif + +#define BOUNCE_SIZE 0x200000 + +struct rtk_sdmmc_host { + struct mmc_host *mmc; + struct mmc_request *mrq; + struct mmc_command *rtk_sdmmc_cmd12; + struct rtk_sdmmc_host_ops *ops; + volatile u32 rtflags; + + u8 ins_event; + u8 cmd_opcode; + u8 reset_event; + u8 wp; + + void __iomem *sdmmc; + void __iomem *pll; + void __iomem *sysbrdg; + void __iomem *isopad; + void __iomem *gpiodir; + int cd_irq; + int wp_irq; + struct gpio_desc *sdmmc_wp_gpio; + struct gpio_desc *sdmmc_cd_gpio; + + spinlock_t lock; + + struct tasklet_struct req_end_tasklet; + struct timer_list timer; + struct timer_list rtk_sdmmc_stop_cmd; //CMD25_WO_STOP_COMMAND + + struct completion *int_waiting; + struct device *dev; + int irq; + + dma_addr_t paddr; + + struct gpio_desc *sdmmc_gpio; + u32 power_status; + u32 int_status_old; + u32 timeout; + + unsigned int magic_num; + char *sdmmc_bounce_buf; + int sdmmc_bounce_buf_val; + struct scatterlist *sdmmc_bounce_sg; +}; + +struct sdmmc_cmd_pkt { + struct mmc_host *mmc; + struct rtk_sdmmc_host *rtk_host; + struct mmc_command *cmd; + struct mmc_data *data; + u32 dma_buffer; + u16 byte_count; + u16 block_count; + + u32 flags; + s8 rsp_para1; + s8 rsp_para2; + s8 rsp_para3; + u8 rsp_len; + u32 timeout; +}; + +struct rtk_sdmmc_host_ops { + irqreturn_t (*func_irq)(int irq, void *dev); + int (*re_init_proc)(struct mmc_card *card); + int (*card_det)(struct rtk_sdmmc_host *rtk_host); + void (*card_power)(struct rtk_sdmmc_host *rtk_host,u8 status); + void (*chk_card_insert)(struct rtk_sdmmc_host *rtk_host); + void (*set_crt_muxpad)(struct rtk_sdmmc_host *rtk_host); + void (*set_clk)(struct rtk_sdmmc_host *rtk_host,u32 mmc_clk); + void (*reset_card)(struct rtk_sdmmc_host *rtk_host); + void (*reset_host)(struct rtk_sdmmc_host *rtk_host); + void (*bus_speed_down)(struct rtk_sdmmc_host *rtk_host); + u32 (*get_cmdcode)(u32 opcode ); + u32 (*get_r1_type)(u32 opcode ); + u8 (*chk_cmdcode)(struct mmc_command* cmd); + u32 (*chk_r1_type)(struct mmc_command* cmd); +}; + +enum sdmmc_clock_speed { + SDMMC_CLOCK_200KHZ = 0, + SDMMC_CLOCK_400KHZ = 1, + SDMMC_CLOCK_6200KHZ = 2, + SDMMC_CLOCK_20000KHZ = 3, + SDMMC_CLOCK_25000KHZ = 4, + SDMMC_CLOCK_50000KHZ = 5, + SDMMC_CLOCK_208000KHZ = 6, + SDMMC_CLOCK_100000KHZ = 7, +}; + +static const char *const bit_tlb[4] = { + "1bit", + "4bits", + "8bits", + "unknow" +}; + +struct timing_phase_path{ + int start; + int end; + int mid; + int len; +}; + +#define MMC_SECTOR_ADDR 0x40000000 + +#define EVENT_NON 0x0000 +#define EVENT_INSER 0x0001 +#define EVENT_REMOV 0x0002 +#define EVENT_USER 0x0010 + +#define BYTE_CNT 0x0200 +#define RTK_NORMAL_SPEED 0x0000 +#define RTK_HIGH_SPEED 0x0001 + +#define ON 0 +#define OFF 1 +#define GPIO_OUT 1 +#define GPIO_IN 0 +#define GPIO_HIGH 1 +#define GPIO_LOW 0 + +/* MMC configure1, for SD_CONFIGURE1 */ +#define SD30_FIFO_RST (1 << 4) +#define SD1_R0 (SDCLK_DIV | SDCLK_DIV_256 | RST_RDWR_FIFO) + +/* MMC configure2, for SD_CONFIGURE2, response type */ +#define SD_R0 (RESP_TYPE_NON | CRC7_CHK_DIS) +#define SD_R1 RESP_TYPE_6B +#define SD_R1b RESP_TYPE_6B +#define SD_R2 RESP_TYPE_17B +#define SD_R3 (RESP_TYPE_6B | CRC7_CHK_DIS) +#define SD_R4 RESP_TYPE_6B +#define SD_R5 RESP_TYPE_6B +#define SD_R6 RESP_TYPE_6B +#define SD_R7 RESP_TYPE_6B +#define SD_R_NO 0xFF + +static const unsigned char rtk_sdmmc_cmdcode[60][2] = { + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, //0~3 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_NORMALREAD ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, //4~7 + {SD_CMD_UNKNOW ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R1 }, //8~11 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_NORMALREAD ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, //12~15 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_AUTOREAD2 ,SD_R1 }, {SD_AUTOREAD1 ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R1 }, //16~19 + {SD_AUTOWRITE1 ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_NORMALREAD ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, //20~23 +#ifndef CMD25_USE_SD_AUTOWRITE2 + {SD_AUTOWRITE2 ,SD_R1 }, {SD_AUTOWRITE1 ,SD_R1 }, {SD_NORMALWRITE,SD_R1 }, {SD_NORMALWRITE,SD_R1 }, //24~27 +#else + {SD_AUTOWRITE2 ,SD_R1 }, {SD_AUTOWRITE2 ,SD_R1 }, {SD_NORMALWRITE,SD_R1 }, {SD_NORMALWRITE,SD_R1 }, //24~27 +#endif + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_NORMALREAD ,SD_R1 }, {SD_NORMALREAD ,SD_R1 }, //28~31 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, //32~35 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, //36~39 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_NORMALREAD ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, //40~43 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, //44~47 + {SD_AUTOREAD2 ,SD_R1 }, {SD_AUTOWRITE2 ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_NORMALREAD ,SD_R1 }, //48~51 + {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_CMD_UNKNOW ,SD_R0 }, //52~55 + {SD_AUTOREAD2 ,SD_R1 }, {SD_CMD_UNKNOW ,SD_R0 }, {SD_AUTOREAD2 ,SD_R1 }, {SD_AUTOWRITE2 ,SD_R1 } //56~59 +}; + +/* MMC configure3 , for SD_CONFIGURE3 */ +#define SD30_CLK_STOP (1 << 4) +#define SD2_R0 (RESP_CHK_EN | ADDR_BYTE_MODE) + +#define RTKCR_FCARD_DETECTED (0x01 << 0) /* Card is detected */ +#define RTKCR_FCARD_SELECTED (0x01 << 1) /* Card is detected */ +#define RTKCR_USER_PARTITION (0x01 << 2) /* card is working on normal partition */ + +#define MMC_ERR_NONE 0 +#define MMC_ERR_TIMEOUT 1 +#define MMC_ERR_BADCRC 2 +#define MMC_ERR_RMOVE 3 +#define MMC_ERR_FAILED 4 +#define MMC_ERR_INVALID 5 + +#define RCA_SHIFTER 16 + +#define CR_TRANS_OK 0x00 +#define CR_TRANSFER_TO 0x01 +#define CR_BUF_FULL_TO 0x02 +#define CR_DMA_FAIL 0x03 +#define CR_TRANSFER_FAIL 0x04 + +#define RTK_FAIL 3 /* DMA error & cmd parser error */ +#define RTK_RMOV 2 /* card removed */ +#define RTK_TOUT 1 /* time out include DMA finish & cmd parser finish */ +#define RTK_SUCC 0 + +#define MMC_EXT_READ_SINGLE 48 +#define MMC_EXT_WRITE_SINGLE 49 +#define MMC_EXT_READ_MULTIPLE 58 +#define MMC_EXT_WRITE_MULTIPLE 59 + +static int rtk_sdmmc_get_cd(struct mmc_host *host); +static int rtk_sdmmc_send_stop_cmd(struct mmc_command *cmd, struct rtk_sdmmc_host *rtk_host,int flag); +static int rtk_sdmmc_send_cmd_get_rsp(struct sdmmc_cmd_pkt *cmd_info); +static int rtk_sdmmc_stream(struct sdmmc_cmd_pkt *cmd_info); +static void rtk_sdmmc_hw_initial(struct rtk_sdmmc_host *rtk_host); +static void rtk_sdmmc_timeout(struct timer_list *t); +static void rtk_sdmmc_cmd12_fun(struct timer_list *t); +static void rtk_sdmmc_set_access_mode(struct rtk_sdmmc_host *rtk_host,u8 level); +void remove_sdcard(struct rtk_sdmmc_host *rtk_host); +void rtk_sdmmc_sync(struct rtk_sdmmc_host *rtk_host); +static void rtk_sdmmc_speed(struct rtk_sdmmc_host *rtk_host, enum sdmmc_clock_speed sd_speed); +void mmc_blk_set_ro(struct mmc_card* card); +void rtk_sdmmc_open_clk(struct mmc_host *host); +void rtk_sdmmc_close_clk(struct mmc_host *host); +int get_mmc_runtime_resume_flag(void); +void set_mmc_runtime_resume_flag(int flag); +#endif /* DRIVERS_MMC_HOST_RTK_SDMMC_H_ */ diff --git a/drivers/mmc/host/rtkemmc_rtd13xx.c b/drivers/mmc/host/rtkemmc_rtd13xx.c new file mode 100644 index 000000000000..3d3daf53e5c7 --- /dev/null +++ b/drivers/mmc/host/rtkemmc_rtd13xx.c @@ -0,0 +1,4753 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) + +/* + * Realtek EMMC host driver + * + * Copyright (c) 2019-2020 Realtek Semiconductor Corp. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core/card.h" +#include "../core/host.h" +#include "cqhci.h" + +#include "reg_iso.h" +#include "rtkemmc_rtd13xx.h" +#include "mmc_debug.h" + +#define DRIVER_NAME "EMMC" +#define BANNER "Realtek eMMC Driver" +#define VERSION "$Id: rtkemmc.c Hank 2019-1-7 19:00 $" + +#define DMA_ALLOC_LENGTH (0x80000) +#define DESC_ALLOC_LENGTH (1024*1024) +unsigned int GLOBAL=0; +#define PHASE_INHERITED + +#define FORCE_CHECK_CMD_AND_STS + +#define DQS_INHERITED + +#define TIMEOUT_MS 3000 +#define TIMEOUT_DMA 50 +#define TIMEOUT_CMD 10000 //10 secs + +#define TUNING_STAGE1 1 +#define TUNING_STAGE2 2 +#define TUNING_STAGE_BOTH 3 + +//#define RTKEMMC_DEBUG +#define RTKEMMC_PHASE_TRACE + +#ifdef RTKEMMC_PHASE_TRACE +u32 trace_TX_window=0; +u32 trace_RX_window=0; +u32 trace_TX1_window=0; +u32 trace_cur_tuning_cmd=0; +u32 trace_index=0; +u32 trace_phase_bitmap=0; +u32 trace_dqs_counter=0; +u32 trace_desc_counter=0; +u16 trace_err_status=0; +u16 trace_auto_err_status=0; +u16 trace_normal_status=0; +u16 trace_dqs_index=0; +#endif + +static volatile int g_bResuming; +volatile int g_bTuning; + +#define SHA256 + +#define MMC_SEND_WRITE_PROT_TYPE 31 +#define MMC_MANUFACTURER_CMD62 62 +#define MMC_MANUFACTURER_CMD63 63 + +#ifdef SHA256 +struct sdesc { + struct shash_desc shash; + char ctx[]; +}; +static int rtk_get_hash(unsigned char *input, unsigned char *sha256_hash, unsigned int dma_len); +unsigned char *compare3=NULL; +unsigned char *compare4=NULL; +dma_addr_t compare3_phy_addr; +dma_addr_t compare4_phy_addr; +#else +unsigned char compare1[DMA_ALLOC_LENGTH]; +unsigned char compare2[DMA_ALLOC_LENGTH]; +#endif + +static void rtkemmc_request(struct mmc_host *host, struct mmc_request *mrq); +static void rtkemmc_set_ios(struct mmc_host *host, struct mmc_ios *ios); +static void rtkemmc_init_card(struct mmc_host *host, struct mmc_card *card); +static int rtkemmc_hs400_prepare_ddr(struct mmc_host *host); +static void set_cmd_info(struct mmc_card *card,struct mmc_command * cmd, +struct sd_cmd_pkt * cmd_info,u32 opcode,u32 arg,u8 rsp_para); + +static int rtkemmc_stop_transmission(struct mmc_card *card,int bIgnore); +static int rtkemmc_wait_status(struct mmc_card *card,u8 state,u8 divider,int bIgnore); +int rtkemmc_send_cmd6(struct rtkemmc_host *emmc_port, u32 args,u16 * state, int phase); +static int rtkemmc_send_cmd13(struct rtkemmc_host *emmc_port, u16 * state); + +static int mmc_Tuning_DDR50(struct rtkemmc_host *emmc_port); +static int mmc_Tuning_HS200(struct rtkemmc_host *emmc_port); +static int rtkemmc_execute_tuning(struct mmc_host *host, u32 opcode); +static int rtkemmc_prepare_hs400_tuning(struct mmc_host *host, struct mmc_ios *ios); +void phase(struct rtkemmc_host *emmc_port, u32 VP0, u32 VP1); +static void rtkemmc_init(struct rtkemmc_host *emmc_port); +static void rtkemmc_set_pin_mux(struct rtkemmc_host *emmc_port); +static void rtkemmc_set_freq(struct rtkemmc_host *emmc_port, u32 freq, u32 div_ip); +static void rtkemmc_stark_set_freq(struct rtkemmc_host *emmc_port, u32 freq, u32 div_ip); +void error_handling(struct rtkemmc_host *emmc_port); +static int SD_SendCMDGetRSP(struct sd_cmd_pkt * cmd_info,int bIgnore); +static int SD_Stream(struct sd_cmd_pkt *cmd_info, unsigned int bIgnore); +void rtkemmc_set_pad_driving(struct rtkemmc_host *emmc_port, u32 clk_drv, u32 cmd_drv, u32 data_drv, u32 ds_drv); +static int wait_done_timeout(struct rtkemmc_host *emmc_port, volatile u32 *addr, u32 mask, u32 value,const char *string); +static void rtkemmc_dqs_tuning(struct mmc_host *host); +int rtkemmc_set_blocklen(struct mmc_card* card, unsigned int blocklen); +int rtkemmc_write_protect_cmd(struct rtkemmc_host *emmc_port, u32 args, bool is_wrtie_protect); +int rtkemmc_query_protect_cmd(struct rtkemmc_host *emmc_port, unsigned long addr, u32 cmd_idx); + +DECLARE_COMPLETION(rtk_emmc_wait); +typedef void (*set_gpio_func_t)(u32 gpio_num,u8 dir,u8 level); +int rtkemmc_switch(struct rtkemmc_host *emmc_port, u8 set, u8 index, u8 value, unsigned int timeout_ms); +int suspend_VP0=0xff, suspend_VP1=0xff; +int HS200_RX=0xff, HS200_TX=0xff; +int suspend_dqs=0x88; +static u32 HS400_VERSION = 2; + +void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx); +void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx); + +static const struct mmc_host_ops rtkemmc_ops = { + .request = rtkemmc_request, + .set_ios = rtkemmc_set_ios, + .execute_tuning = rtkemmc_execute_tuning, + .prepare_hs400_tuning = rtkemmc_prepare_hs400_tuning, + .hs400_complete = rtkemmc_dqs_tuning, + .hs400_prepare_ddr = rtkemmc_hs400_prepare_ddr, + .init_card = rtkemmc_init_card +}; + +static const struct soc_device_attribute rtk_soc_groot[] = { + { + .family = "Realtek Groot", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_stark[] = { + { + .family = "Realtek Stark", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_hank[] = { + { + .family = "Realtek Hank", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_hank_a00[] = { + { + .family = "Realtek Hank", + .revision = "A00", + }, + { + /* empty */ + } +}; + +// write addr with val +void rtkemmc_write_swc(u32 addr, u32 val) +{ + struct arm_smccc_res res; + + arm_smccc_smc(0x8400ffff, addr, val, 0, 0, 0, 0, 0, &res); +} + +// read addr +u32 rtkemmc_read_swc(u32 addr) +{ + struct arm_smccc_res res; + arm_smccc_smc(0x8400fffe, addr, 0, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +void sync(struct rtkemmc_host *emmc_port) +{ + dmb(sy); + writel(0x0, emmc_port->sb2_membase+0x20); + dmb(sy); +} + +static void rtkemmc_reset_fifo(struct rtkemmc_host *emmc_port) +{ + writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&(~EMMC_TOP_RST_N_FIFO), + emmc_port->emmc_membase+EMMC_OTHER1); + udelay(1); + writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)|EMMC_TOP_RST_N_FIFO, + emmc_port->emmc_membase+EMMC_OTHER1); +} + +static void rtk_cqe_enable(struct mmc_host *host); +static void rtk_cqhci_dumpregs(struct mmc_host *host); +static void rtk_cqhci_setup_tran_desc(struct mmc_data *data, struct cqhci_host *cq_host, u8 *desc, int sg_count); +static void rtkemmc_cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64); + +static const struct cqhci_host_ops rtk_cqhci_host_ops = { + .enable = rtk_cqe_enable, + .dumpregs = rtk_cqhci_dumpregs, + .setup_tran_desc = rtk_cqhci_setup_tran_desc, +}; + +static void rtk_cqhci_dumpregs(struct mmc_host *host) +{ + struct rtkemmc_host *emmc_port; + emmc_port = mmc_priv(host); + + pr_err("%s: Cmd idx 0x%08x\n",__func__, readw(emmc_port->emmc_membase+EMMC_CMD_R)); +} + +static void rtk_cqhci_setup_tran_desc(struct mmc_data *data, + struct cqhci_host *cq_host, u8 *desc, int sg_count) +{ + int i, len; + bool end = false; + bool dma64 = cq_host->dma64; + dma_addr_t addr; + struct scatterlist *sg; + u32 blk_cnt2, remain_blk_cnt; + unsigned int b1, b2; + + for_each_sg(data->sg, sg, sg_count, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + remain_blk_cnt = len >> 9; + + while(remain_blk_cnt) { + if(remain_blk_cnt > EMMC_MAX_SCRIPT_BLK) + blk_cnt2 = EMMC_MAX_SCRIPT_BLK; + else + blk_cnt2 = remain_blk_cnt; + //boundary check + b1 = addr / 0x8000000; //this eMMC ip dma transfer has 128MB limitation + b2 = (addr+blk_cnt2*512) / 0x8000000; + + if(b1 != b2) { + blk_cnt2 = (b2*0x8000000-addr) / 512; + } + if ((i+1) == sg_count && (remain_blk_cnt == blk_cnt2)) + end = true; + rtkemmc_cqhci_set_tran_desc(desc, addr, (blk_cnt2<<9), end, dma64); + + addr = addr+(blk_cnt2<<9); + remain_blk_cnt -= blk_cnt2; + desc += cq_host->trans_desc_len; + } + } +} + +static void rtk_cqe_enable(struct mmc_host *host) +{ + struct rtkemmc_host *emmc_port; + emmc_port = mmc_priv(host); + + //clear data path SW_RST_R.SW_RST_DAT = 1 + rtkemmc_writeb(EMMC_SW_RST_DAT, emmc_port->emmc_membase+EMMC_SW_RST_R); + //0x98012004,Set value corresponding to executed data byte length of one block to BLOCKSIZE_R + rtkemmc_writew(0x200, emmc_port->emmc_membase+EMMC_BLOCKSIZE_R); + rtkemmc_writew(((1<emmc_membase+EMMC_XFER_MODE_R); //0x9801200c + //Set DMA_SEL to ADMA2 only mode in the HOST_CTRL1_R + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R)&0xe7)|(EMMC_ADMA2_32<emmc_membase+EMMC_HOST_CTRL1_R); + rtkemmc_writew(0, emmc_port->emmc_membase+EMMC_BLOCKCOUNT_R); + //Set SDMASA_R (while using 32 bits) to 0 + rtkemmc_writel(0, emmc_port->emmc_membase+EMMC_SDMASA_R); + //we set this register additionally to enhance the IO perofrmance + rtkemmc_writel(0x10, emmc_port->cq_host->mmio+CQHCI_SSC1); + + rtkemmc_writel(0, emmc_port->cq_host->mmio+CQHCI_CTL); + if (readl(emmc_port->cq_host->mmio+CQHCI_CTL) && CQHCI_HALT) { + pr_err("%s: cqhci: CQE failed to exit halt state\n", + mmc_hostname(emmc_port->mmc)); + } + + //cmdq interrupt mode + rtkemmc_hold_int_dec(); + rtkemmc_en_cqe_int(); + + sync(emmc_port); +} + +static void rtkemmc_cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, + bool dma64) +{ + __le32 *attr = (__le32 __force *)desc; + + *attr = (CQHCI_VALID(1) | + CQHCI_END(end ? 1 : 0) | + CQHCI_INT(0) | + CQHCI_ACT(0x4) | + CQHCI_DAT_LENGTH(len)); + + if (dma64) { + __le64 *dataddr = (__le64 __force *)(desc + 4); + + dataddr[0] = cpu_to_le64(addr); + } else { + __le32 *dataddr = (__le32 __force *)(desc + 4); + + dataddr[0] = cpu_to_le32(addr); + } +} + +static int rtkemmc_blk_cmdq_switch(struct mmc_card* card, bool enable) +{ + int ret = 0; + if (!(card->host->caps2 & MMC_CAP2_CQE) || + !card->ext_csd.cmdq_support) + return 0; + + if (enable) { + ret = rtkemmc_set_blocklen(card, 512); + if (ret) { + pr_err("%s: failed (%d) to set block-size\n", + __func__, ret); + goto out; + } + } + ret = rtkemmc_switch(mmc_priv(card->host), EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_CMDQ_MODE_EN, enable, + card->ext_csd.generic_cmd6_time); + if (ret) { + pr_err("%s: cmdq mode %sable failed %d\n", __func__, enable ? "en" : "dis", ret); + goto out; + } + else + card->ext_csd.cmdq_en = enable; + +out: + return ret; +} + +static void rtkemmc_cqhci_dumpregs(struct cqhci_host *cq_host) +{ + struct mmc_host *host = cq_host->mmc; + struct rtkemmc_host *emmc_port; + emmc_port = mmc_priv(host); + + pr_err("============ CQHCI REGISTER DUMP ===========\n"); + + pr_err("Caps: 0x%08x | Version: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_CAP), + cqhci_readl(cq_host, CQHCI_VER)); + pr_err("Config: 0x%08x | Control: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_CFG), + cqhci_readl(cq_host, CQHCI_CTL)); + pr_err("Int stat: 0x%08x | Int enab: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_IS), + cqhci_readl(cq_host, CQHCI_ISTE)); + pr_err("Int sig: 0x%08x | Int Coal: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_ISGE), + cqhci_readl(cq_host, CQHCI_IC)); + pr_err("TDL base: 0x%08x | TDL up32: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_TDLBA), + cqhci_readl(cq_host, CQHCI_TDLBAU)); + pr_err("Doorbell: 0x%08x | TCN: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_TDBR), + cqhci_readl(cq_host, CQHCI_TCN)); + pr_err("Dev queue: 0x%08x | Dev Pend: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_DQS), + cqhci_readl(cq_host, CQHCI_DPT)); + pr_err("Task clr: 0x%08x | SSC1: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_TCLR), + cqhci_readl(cq_host, CQHCI_SSC1)); + pr_err("SSC2: 0x%08x | DCMD rsp: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_SSC2), + cqhci_readl(cq_host, CQHCI_CRDCT)); + pr_err("RED mask: 0x%08x | TERRI: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_RMEM), + cqhci_readl(cq_host, CQHCI_TERRI)); + pr_err("Resp idx: 0x%08x | Resp arg: 0x%08x\n", + cqhci_readl(cq_host, CQHCI_CRI), + cqhci_readl(cq_host, CQHCI_CRA)); + + pr_err("%s: Cmd idx 0x%08x\n",__func__, readw(emmc_port->emmc_membase+EMMC_CMD_R)); +} + +void rtkemmc_dqs_delay_tap(struct rtkemmc_host *emmc_port, u32 dqs_dly) +{ + if(soc_device_match(rtk_soc_hank_a00)) { //hank A00 + //this is a workaround for hank hs400 mode and will be fixed in A01 + u16 state=0; + unsigned long timeout; + bool expired = false; + int err=0; + + rtkemmc_send_cmd6(emmc_port, 0x03b90301, &state, dqs_dly); + rtkemmc_writel(0x80|dqs_dly ,emmc_port->emmc_membase + EMMC_DQS_CTRL1); + rtkemmc_send_cmd6(emmc_port, 0x03b91301, &state, dqs_dly); + + timeout = jiffies + msecs_to_jiffies(3000) + 1; + do { + expired = time_after(jiffies, timeout); + err = rtkemmc_send_cmd13(emmc_port, &state); + if (expired && + (R1_CURRENT_STATE(state) == R1_STATE_PRG)) { + pr_err("%s: Card stuck in programming state! %s\n", + mmc_hostname(emmc_port->mmc), __func__); + break; + } + }while(R1_CURRENT_STATE(state) == R1_STATE_PRG); + } + else if(soc_device_match(rtk_soc_hank)){ //hank + rtkemmc_writel(0x80|dqs_dly ,emmc_port->emmc_membase + EMMC_DQS_CTRL1); + } + else { //stark + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_DQS_CTRL1)&(~(1<<8)), + emmc_port->emmc_membase+EMMC_DQS_CTRL1); + rtkemmc_writel(dqs_dly ,emmc_port->emmc_membase + EMMC_DQS_CTRL1); + rtkemmc_writel(0x100|dqs_dly ,emmc_port->emmc_membase + EMMC_DQS_CTRL1); + } +} + +static void data_delay_tap_setting(struct rtkemmc_host *emmc_port) +{ + if(soc_device_match(rtk_soc_stark) || soc_device_match(rtk_soc_groot)) { + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL0)&(~EMMC_FW_SET), + emmc_port->emmc_membase+EMMC_RDQ_CTRL0); + if(emmc_port->dqs_dly_tape==0) return; + + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL0); + } + else { + rtkemmc_writel(EMMC_FW_SET | emmc_port->dqs_dly_tape, + emmc_port->emmc_membase+EMMC_RDQ_CTRL0); + } + + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL1); + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL2); + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL3); + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL4); + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL5); + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL6); + rtkemmc_writel(emmc_port->dqs_dly_tape, emmc_port->emmc_membase+EMMC_RDQ_CTRL7); + + if(soc_device_match(rtk_soc_stark) || soc_device_match(rtk_soc_groot)){ + rtkemmc_writel(EMMC_FW_SET | readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL0), + emmc_port->emmc_membase+EMMC_RDQ_CTRL0); + } + else + rtkemmc_writel(EMMC_FW_SET_RW, emmc_port->emmc_membase+EMMC_DQ_CTRL_SET); +} + +static void cmd_delay_tap_setting(struct rtkemmc_host *emmc_port, u32 cmd_dly_tape) +{ + if(soc_device_match(rtk_soc_stark) || soc_device_match(rtk_soc_groot)) { + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_WCMD_CTRL)&(~(1<<7)), + emmc_port->emmc_membase+EMMC_WCMD_CTRL); + + if(cmd_dly_tape==0) return; + + rtkemmc_writel(cmd_dly_tape, emmc_port->emmc_membase + EMMC_WCMD_CTRL); + rtkemmc_writel(cmd_dly_tape|0x80, emmc_port->emmc_membase+EMMC_WCMD_CTRL); + } + else { + rtkemmc_writel(cmd_dly_tape, emmc_port->emmc_membase + EMMC_WCMD_CTRL); + if(cmd_dly_tape != 0) + rtkemmc_writel(0x1, emmc_port->emmc_membase + EMMC_CMD_CTRL_SET); + } +} + +static int rtkemmc_prepare_hs400_tuning(struct mmc_host *host, struct mmc_ios *ios) +{ + struct rtkemmc_host *emmc_port; + emmc_port = mmc_priv(host); + printk(KERN_ERR "Prepare HS400 mode...\n"); + + rtkemmc_dqs_delay_tap(emmc_port, 0x88); + + data_delay_tap_setting(emmc_port); + + if(emmc_port->dqs_tuning == 0) { + printk(KERN_ERR "%s: write the saved cmd_dqs_tap 0x%x\n", __func__, emmc_port->cmd_dly_tap); + cmd_delay_tap_setting(emmc_port, emmc_port->cmd_dly_tap); + } + else + cmd_delay_tap_setting(emmc_port, 0); + + return 0; +} + +static void set_cmd_info(struct mmc_card *card,struct mmc_command * cmd, struct sd_cmd_pkt * cmd_info,u32 opcode,u32 arg,u8 rsp_para) +{ + memset(cmd, 0, sizeof(struct mmc_command)); + memset(cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + cmd->opcode = opcode; + cmd->arg = arg; + cmd_info->cmd = cmd; + cmd_info->emmc_port = mmc_priv(card->host); + cmd_info->rsp_len = rsp_para; +} + +#ifdef RTKEMMC_PHASE_TRACE +void print_desc_content(struct rtkemmc_host *emmc_port) +{ + int i =0; + u32* des_base = emmc_port->desc_vaddr ; + + printk(KERN_ERR "%s: descriptor content:\n", __func__); + for(i=0; iemmc_membase+EMMC_NORMAL_INT_STAT_EN_R)); + pr_err("0x98012036 ERROR INTERRUPT EN= 0x%x\n",readw(emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_EN_R)); + pr_err("0x98012038 NORMAL INTERRUPT SIGNAL EN= 0x%x\n",readw(emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R)); + pr_err("0x9801203a ERROR INTERRUPT SIGNAL EN = 0x%x\n",readw(emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R)); + pr_err("0x9801203c EMMC_AUTO_CMD_STAT_R = 0x%08x\n", readw(emmc_port->emmc_membase+EMMC_AUTO_CMD_STAT_R)); + pr_err("0x9801203e HOST CONTROL2 REG = 0x%x\n",readw(emmc_port->emmc_membase+EMMC_HOST_CTRL2_R)); + pr_err("0x98012024 PRESENT STATE REG = 0x%x\n",readl(emmc_port->emmc_membase+EMMC_PSTATE_REG)); + pr_err("0x98012028 HOST CONTROL1 REG= 0x%x\n",readb(emmc_port->emmc_membase+EMMC_HOST_CTRL1_R)); + pr_err("0x9801200c TRANSFER MODE REG = 0x%x\n",readw(emmc_port->emmc_membase+EMMC_XFER_MODE_R)); + pr_err("0x98012004 EMMC BLOCK SIZE = 0x%x\n",readw(emmc_port->emmc_membase+EMMC_BLOCKSIZE_R)); + pr_err("0x98012006 EMMC BLOCK COUNT = 0x%08x\n", readw(emmc_port->emmc_membase+EMMC_BLOCKCOUNT_R)); + pr_err("0x9801200e CMD_IDX = 0x%08x\n",readw(emmc_port->emmc_membase+EMMC_CMD_R)); + pr_err("0x98012008 EMMC CMDARG = 0x%08x\n", readl(emmc_port->emmc_membase+EMMC_ARGUMENT_R)); +} + +void print_err_reg(u32 cmd_idx, u16 normal_interrupt, u16 error_interrupt) +{ + pr_err("=====================================================\n"); + pr_err("g_bTuning=%d cmd_idx 0x%08x, op_code (%d)\n",g_bTuning, cmd_idx, CMD_IDX_MASK(cmd_idx)); + pr_err("0x98012030 NORMAL INTERRUPT STAT = 0x%x\n", normal_interrupt); + pr_err("0x98012032 ERROR INTERRUPT STAT = 0x%x\n", error_interrupt); + if( error_interrupt & EMMC_VENDOR_ERR3 ) { pr_err("bit 15: EMMC_VENDOR_ERR3\n"); } + if( error_interrupt & EMMC_VENDOR_ERR2 ) { pr_err("bit 14: EMMC_VENDOR_ERR2\n"); } + if( error_interrupt & EMMC_VENDOR_ERR1 ) { pr_err("bit 13: EMMC_VENDOR_ERR1\n"); } + if( error_interrupt & EMMC_BOOT_ACK_ERR ) { pr_err("bit 12: EMMC_BOOT_ACK_ERR\n"); } + if( error_interrupt & EMMC_RESP_ERR ) { pr_err("bit 11: EMMC_RESP_ERR\n"); } + if( error_interrupt & EMMC_TUNING_ERR ) { pr_err("bit 10: EMMC_TUNING_ERR\n"); } + if( error_interrupt & EMMC_ADMA_ERR ) { pr_err("bit 9: EMMC_ADMA_ERR\n"); } + if( error_interrupt & EMMC_AUTO_CMD_ERR ) { pr_err("bit 8: EMMC_AUTO_CMD_ERR\n"); } + if( error_interrupt & EMMC_CUR_LMT_ERR ) { pr_err("bit 7: EMMC_CUR_LMT_ERR\n"); } + if( error_interrupt & EMMC_DATA_END_BIT_ERR ) { pr_err("bit 6: EMMC_DATA_END_BIT_ERR\n"); } + if( error_interrupt & EMMC_DATA_CRC_ERR ) { pr_err("bit 5: EMMC_DATA_CRC_ERR\n"); } + if( error_interrupt & EMMC_DATA_TOUT_ERR ) { pr_err("bit 4: EMMC_DATA_TOUT_ERR\n"); } + if( error_interrupt & EMMC_CMD_IDX_ERR ) { pr_err("bit 3: EMMC_CMD_IDX_ERR\n"); } + if( error_interrupt & EMMC_CMD_END_BIT_ERR ) { pr_err("bit 2: EMMC_CMD_END_BIT_ERR\n"); } + if( error_interrupt & EMMC_CMD_CRC_ERR ) { pr_err("bit 1: EMMC_CMD_CRC_ERR\n"); } + if( error_interrupt & EMMC_CMD_TOUT_ERR ) { pr_err("bit 0: EMMC_CMD_TOUT_ERR\n"); } + pr_err("=====================================================\n"); +} + +void print_ip_desc(struct rtkemmc_host *emmc_port) +{ + pr_err("------------------------------>\n"); + pr_err("EMMC IP_DESC0 = 0x%08x\n", readl(emmc_port->emmc_membase+EMMC_IP_DESC0)); + pr_err("EMMC IP_DESC1 = 0x%08x\n", readl(emmc_port->emmc_membase+EMMC_IP_DESC1)); + pr_err("EMMC IP_DESC2 = 0x%08x\n", readl(emmc_port->emmc_membase+EMMC_IP_DESC2)); + pr_err("EMMC IP_DESC3 = 0x%08x\n", readl(emmc_port->emmc_membase+EMMC_IP_DESC3)); + + pr_err("0x98012054 EMMC_ADMA_ERR_STAT_R = 0x%08x\n", readl(emmc_port->emmc_membase+EMMC_ADMA_ERR_STAT_R)); + pr_err("0x98012058 EMMC EMMC_ADMA_SA_LOW_R = 0x%08x\n------------------------------>\n", readl(emmc_port->emmc_membase+EMMC_ADMA_SA_LOW_R)); +} + +static void rtkemmc_shutdown(struct platform_device *pdev) +{ + //struct device *dev = &pdev->dev; + + printk(KERN_ERR "[eMMC] Shutdown\n"); + pm_runtime_force_suspend(&pdev->dev); +} + +#ifdef CONFIG_PM +static int rtkemmc_suspend(struct device *dev) +{ + int ret = 0; + struct rtkemmc_host *emmc_port=NULL; + struct mmc_host *mmc = NULL; + mmc = dev_get_drvdata(dev); + emmc_port = mmc_priv(mmc); + + if(!mmc || !emmc_port) + pr_err("mmc=NULL or emmc_port=NULL\n"); + + emmc_port->suspend = 1; + if(soc_device_match(rtk_soc_hank_a00)) { //in hank A00 version + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)|0x1, emmc_port->emmc_membase+EMMC_OTHER1); //disable L4 gated + isb(); + sync(emmc_port); + } + + if(mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_suspend(mmc); + if (ret) { + pr_err("%s: cqe suspend failed\n", __func__); + return ret; + } + } + ret = pm_runtime_force_suspend(dev); + rtkemmc_writel(0, emmc_port->emmc_membase+EMMC_AHB); + printk(KERN_ERR "[%s] Exit %s, AHB=0x%x\n",DRIVER_NAME,__func__, readl(emmc_port->emmc_membase+EMMC_AHB)); + return ret; +} + +static int rtkemmc_resume(struct device *dev) +{ + int ret = 0; + struct mmc_host *mmc = NULL; + struct rtkemmc_host *emmc_port=NULL; + struct mmc_host *host = NULL; + + mmc = dev_get_drvdata(dev); + emmc_port = mmc_priv(mmc); + if (!emmc_port) + BUG(); + + host = emmc_port->mmc; + host->card->host = mmc; + g_bResuming=1; + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_AHB)|0x4,emmc_port->emmc_membase+EMMC_AHB); + printk(KERN_ERR "%s: EMMC_AHB=0x%x\n", __func__, readl(emmc_port->emmc_membase+EMMC_AHB)); + + if (!ret) + ret = pm_runtime_force_resume(dev); + + rtkemmc_set_pin_mux(emmc_port); + rtkemmc_init(emmc_port); + sync(emmc_port); + + g_bResuming=0; + init_completion(emmc_port->int_waiting); + + if(mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_resume(mmc); + if (ret) + pr_err("%s: cqe resume failed\n", __func__); + } + printk(KERN_ERR "[%s] Exit %s\n",DRIVER_NAME,__func__); + + return ret; +} + +static const struct dev_pm_ops rtk_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rtkemmc_suspend, rtkemmc_resume) +}; +#endif + +void rtkemmc_dump_register(struct rtkemmc_host *emmc_port) +{ + emmc_port->backreg.sdmasa_r = readl(emmc_port->emmc_membase + EMMC_SDMASA_R); + emmc_port->backreg.blocksize_r = readw(emmc_port->emmc_membase + EMMC_BLOCKSIZE_R); + emmc_port->backreg.blockcount_r = readw(emmc_port->emmc_membase + EMMC_BLOCKCOUNT_R); + emmc_port->backreg.xfer_mode_r = readw(emmc_port->emmc_membase + EMMC_XFER_MODE_R); + emmc_port->backreg.host_ctrl1_r = readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + emmc_port->backreg.pwr_ctrl_r = readb(emmc_port->emmc_membase + EMMC_PWR_CTRL_R); + emmc_port->backreg.bgap_ctrl_r = readb(emmc_port->emmc_membase + EMMC_BGAP_CTRL_R); + emmc_port->backreg.clk_ctrl_r = readw(emmc_port->emmc_membase + EMMC_CLK_CTRL_R); + emmc_port->backreg.tout_ctrl_r = readb(emmc_port->emmc_membase + EMMC_TOUT_CTRL_R); + emmc_port->backreg.normal_int_stat_en_r = readw(emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_EN_R); + emmc_port->backreg.error_int_stat_en_r = readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_EN_R); + emmc_port->backreg.normal_int_signal_en_r = readw(emmc_port->emmc_membase + EMMC_NORMAL_INT_SIGNAL_EN_R); + emmc_port->backreg.error_int_signal_en_r = readw(emmc_port->emmc_membase + EMMC_ERROR_INT_SIGNAL_EN_R); + emmc_port->backreg.auto_cmd_stat_r = readw(emmc_port->emmc_membase + EMMC_AUTO_CMD_STAT_R); + emmc_port->backreg.host_ctrl2_r = readw(emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + emmc_port->backreg.adma_sa_low_r = readl(emmc_port->emmc_membase + EMMC_ADMA_SA_LOW_R); + emmc_port->backreg.mshc_ctrl_r = readb(emmc_port->emmc_membase + EMMC_MSHC_CTRL_R); + emmc_port->backreg.ctrl_r = readb(emmc_port->emmc_membase + EMMC_CTRL_R); + emmc_port->backreg.other1 = readl(emmc_port->emmc_membase + EMMC_OTHER1); + emmc_port->backreg.dummy_sys = readl(emmc_port->emmc_membase + EMMC_DUMMY_SYS); + emmc_port->backreg.dqs_ctrl1 = readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1); + emmc_port->backreg.wcmd_ctrl = readl(emmc_port->emmc_membase + EMMC_WCMD_CTRL); + + emmc_port->backreg.rdq_ctrl0 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL0); + emmc_port->backreg.rdq_ctrl1 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL1); + emmc_port->backreg.rdq_ctrl2 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL2); + emmc_port->backreg.rdq_ctrl3 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL3); + emmc_port->backreg.rdq_ctrl4 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL4); + emmc_port->backreg.rdq_ctrl5 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL5); + emmc_port->backreg.rdq_ctrl6 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL6); + emmc_port->backreg.rdq_ctrl7 = readl(emmc_port->emmc_membase+EMMC_RDQ_CTRL7); + emmc_port->backreg.dq_ctrl_set = readl(emmc_port->emmc_membase+EMMC_DQ_CTRL_SET); + emmc_port->backreg.ahb = readl(emmc_port->emmc_membase+EMMC_AHB); +} + +void rtkemmc_restore_register(struct rtkemmc_host *emmc_port) +{ + rtkemmc_writel(emmc_port->backreg.sdmasa_r,emmc_port->emmc_membase + EMMC_SDMASA_R); + rtkemmc_writew(emmc_port->backreg.blocksize_r,emmc_port->emmc_membase + EMMC_BLOCKSIZE_R); + rtkemmc_writew(emmc_port->backreg.blockcount_r,emmc_port->emmc_membase + EMMC_BLOCKCOUNT_R); + rtkemmc_writew(emmc_port->backreg.xfer_mode_r,emmc_port->emmc_membase + EMMC_XFER_MODE_R); + rtkemmc_writeb(emmc_port->backreg.host_ctrl1_r,emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + rtkemmc_writeb(emmc_port->backreg.pwr_ctrl_r,emmc_port->emmc_membase + EMMC_PWR_CTRL_R); + rtkemmc_writeb(emmc_port->backreg.bgap_ctrl_r,emmc_port->emmc_membase + EMMC_BGAP_CTRL_R); + rtkemmc_writew(emmc_port->backreg.clk_ctrl_r,emmc_port->emmc_membase + EMMC_CLK_CTRL_R); + rtkemmc_writeb(emmc_port->backreg.tout_ctrl_r,emmc_port->emmc_membase + EMMC_TOUT_CTRL_R); + rtkemmc_writew(emmc_port->backreg.normal_int_stat_en_r,emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_EN_R); + rtkemmc_writew(emmc_port->backreg.error_int_stat_en_r,emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_EN_R); + rtkemmc_writew(emmc_port->backreg.normal_int_signal_en_r,emmc_port->emmc_membase + EMMC_NORMAL_INT_SIGNAL_EN_R); + rtkemmc_writew(emmc_port->backreg.error_int_signal_en_r,emmc_port->emmc_membase + EMMC_ERROR_INT_SIGNAL_EN_R); + rtkemmc_writew(emmc_port->backreg.auto_cmd_stat_r,emmc_port->emmc_membase + EMMC_AUTO_CMD_STAT_R); + rtkemmc_writew(emmc_port->backreg.host_ctrl2_r,emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + rtkemmc_writel(emmc_port->backreg.adma_sa_low_r,emmc_port->emmc_membase + EMMC_ADMA_SA_LOW_R); + rtkemmc_writeb(emmc_port->backreg.mshc_ctrl_r,emmc_port->emmc_membase + EMMC_MSHC_CTRL_R); + rtkemmc_writeb(emmc_port->backreg.ctrl_r,emmc_port->emmc_membase + EMMC_CTRL_R); + rtkemmc_writel(emmc_port->backreg.dummy_sys,emmc_port->emmc_membase + EMMC_DUMMY_SYS); + + rtkemmc_dqs_delay_tap(emmc_port, emmc_port->backreg.dqs_ctrl1); + cmd_delay_tap_setting(emmc_port, emmc_port->backreg.wcmd_ctrl); + + if((emmc_port->backreg.rdq_ctrl0&0x80)!=0) { + data_delay_tap_setting(emmc_port); + } + + rtkemmc_writel(emmc_port->backreg.ahb, emmc_port->emmc_membase+EMMC_AHB); +} + +void rtkemmc_restore_l4_register(struct rtkemmc_host *emmc_port) +{ + rtkemmc_writel(emmc_port->backreg.other1,emmc_port->emmc_membase + EMMC_OTHER1); +} + +void error_handling(struct rtkemmc_host *emmc_port) +{ + int retry_cnt=0; + int err=0; + + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_AUTO_CMD_ERR|EMMC_CMD_IDX_ERR|EMMC_CMD_END_BIT_ERR|EMMC_CMD_CRC_ERR|EMMC_CMD_TOUT_ERR)) !=0){ //check cmd line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "CMD Line error occurs \n"); +#endif + rtkemmc_writeb(0x2, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x2<<24), 0x0, __func__); //wait for clear 0x2f bit 1 + } + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_ADMA_ERR|EMMC_DATA_END_BIT_ERR|EMMC_DATA_CRC_ERR|EMMC_DATA_TOUT_ERR)) !=0){ //check data line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "DAT Line error occurs \n"); +#endif + rtkemmc_writeb(0x4, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x4<<24), 0x0, __func__); //wait for clear 0x2f bit 2 + } + +retry_L1: + rtkemmc_writew(readw(emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_R)&0xffff, emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_R); + + //synchronous abort: stop host dma + rtkemmc_writeb(0x1, emmc_port->emmc_membase + EMMC_BGAP_CTRL_R); //stop emmc read/write transfer + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_R), 0x2, 0x2, __func__); //wait for xfer complete + rtkemmc_writew(0x2, emmc_port->emmc_membase+EMMC_NORMAL_INT_STAT_R); //clear transfer complete status + + isb(); + sync(emmc_port); +retry_L2: + /*from eMMC Spec. stop command cannot be fired after the cmd 21*/ + if(emmc_port->cmd_opcode!=MMC_SEND_TUNING_BLOCK_HS200) { + rtkemmc_stop_transmission(emmc_port->mmc->card, 1); + mdelay(1); + } + + err = rtkemmc_wait_status(emmc_port->mmc->card,STATE_TRAN,0,1); + + if(err) { + if(err == -9999) { + if((retry_cnt++)<10000) goto retry_L2; + else { + printk(KERN_ERR "%s: status check retry again because of not in trans state after cmd13!!!\n", __func__); + retry_cnt = 0; + goto retry_L2; + } + } + else { + if((retry_cnt++)<30) goto retry_L2; + else { + printk(KERN_ERR "%s: this phase is not recommanded, ret=%d\n", __func__, err); + } + } + } + + rtkemmc_writeb(0x6, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x6<<24), 0x0, __func__); //wait for clear 0x2f bit 1 & 2 + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + EMMC_PSTATE_REG), 0x3, 0x0, __func__); //wait for cmd and data lines are not in use + + udelay(40); + if((readl(emmc_port->emmc_membase + EMMC_PSTATE_REG) &0xf00000)!=0xf00000 || (readl(emmc_port->emmc_membase + EMMC_PSTATE_REG) & 0xf0)!=0xf0) { +#ifdef RTKEMMC_PHASE_TRACE + printk(KERN_INFO "wait for data line signal..., EMMC_PSTATE_REG=0x%x\n", readl(emmc_port->emmc_membase + EMMC_PSTATE_REG)); +#endif + goto retry_L1; + } +} + +static int rtkemmc_send_cmd35(struct rtkemmc_host *emmc_port, u16 * state) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err=0; + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + cmd.opcode = MMC_ERASE_GROUP_START; + cmd.arg = 0x00020000; + cmd_info.cmd = &cmd; + cmd_info.emmc_port = emmc_port; + cmd_info.rsp_len = 6; + + err = SD_SendCMDGetRSP(&cmd_info,1); + + if(err ) { + mmcmsg3(KERN_WARNING "%s: cmd 35 fail\n",DRIVER_NAME); +#ifdef RTKEMMC_PHASE_TRACE + trace_err_status=emmc_port->error_interrupt; + trace_normal_status=emmc_port->normal_interrupt; + trace_auto_err_status=emmc_port->auto_error_interrupt; +#endif + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_AUTO_CMD_ERR|EMMC_CMD_IDX_ERR|EMMC_CMD_END_BIT_ERR|EMMC_CMD_CRC_ERR|EMMC_CMD_TOUT_ERR))!=0){ //check cmd line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "CMD Line error occurs \n"); +#endif + rtkemmc_writeb(0x2, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x2<<24), 0x0, __func__); //wait for clear 0x2f bit 1 + } + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_ADMA_ERR|EMMC_DATA_END_BIT_ERR|EMMC_DATA_CRC_ERR|EMMC_DATA_TOUT_ERR)) !=0){ //check data line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "DAT Line error occurs \n"); +#endif + rtkemmc_writeb(0x4, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x4<<24), 0x0, __func__); //wait for clear 0x2f bit 2 + } + } + else { + u8 cur_state = R1_CURRENT_STATE(cmd.resp[0]); + *state = cur_state; + mmcmsg1("cur_state=%s\n",state_tlb[cur_state]); + } + + return err; +} + +static int rtkemmc_send_cmd13(struct rtkemmc_host *emmc_port, u16 * state) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err=0; + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = (1<error_interrupt; + trace_normal_status=emmc_port->normal_interrupt; + trace_auto_err_status=emmc_port->auto_error_interrupt; +#endif + + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_AUTO_CMD_ERR|EMMC_CMD_IDX_ERR|EMMC_CMD_END_BIT_ERR|EMMC_CMD_CRC_ERR|EMMC_CMD_TOUT_ERR))!=0){ //check cmd line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "CMD Line error occurs \n"); +#endif + rtkemmc_writeb(0x2, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x2<<24), 0x0, __func__); //wait for clear 0x2f bit 1 + } + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_ADMA_ERR|EMMC_DATA_END_BIT_ERR|EMMC_DATA_CRC_ERR|EMMC_DATA_TOUT_ERR)) !=0){ //check data line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "DAT Line error occurs \n"); +#endif + rtkemmc_writeb(0x4, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x4<<24), 0x0, __func__); //wait for clear 0x2f bit 2 + } + } + else { + u8 cur_state = R1_CURRENT_STATE(cmd.resp[0]); + *state = cur_state; + mmcmsg1("cur_state=%s\n",state_tlb[cur_state]); + } + + return err; +} + +int rtkemmc_send_cmd6(struct rtkemmc_host *emmc_port, u32 args, u16 * state, int phase) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err=0; + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + cmd.opcode = MMC_SWITCH; + cmd.arg = args; + cmd.flags = MMC_CMD_AC|MMC_RSP_SPI_R1B | MMC_RSP_R1B; + cmd_info.cmd = &cmd; + cmd_info.emmc_port = emmc_port; + cmd_info.rsp_len = 6; + + err = SD_SendCMDGetRSP(&cmd_info,1); + + if(err ) { +#ifdef RTKEMMC_DEBUG + pr_err("%s error: 0x98012030=0x%x, 0x98012032=0x%x, phase=%d\n", + __func__, emmc_port->normal_interrupt, emmc_port->error_interrupt, phase>>1); +#endif +#ifdef RTKEMMC_PHASE_TRACE + trace_cur_tuning_cmd = 6; + printk(KERN_ERR "%s: trace_TX_window=0x%x, trace_RX_window=0x%x, trace_TX1_window=0x%x, trace_dqs_counter=%d\n", + __func__, trace_TX_window, trace_RX_window, trace_TX1_window, trace_dqs_counter); +#endif +#ifdef RTKEMMC_PHASE_TRACE + trace_err_status=emmc_port->error_interrupt; + trace_normal_status=emmc_port->normal_interrupt; + trace_auto_err_status=emmc_port->auto_error_interrupt; +#endif + error_handling(emmc_port); + } + else { + u8 cur_state = R1_CURRENT_STATE(cmd.resp[0]); + *state = cur_state; + mmcmsg1("cur_state=%s\n",state_tlb[cur_state]); + } + + return err; +} + +int rtkemmc_set_blocklen(struct mmc_card* card, unsigned int blocklen) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err=0; + + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) || + mmc_card_hs400(card) || mmc_card_hs400es(card)) + return 0; + + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = blocklen; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + cmd_info.cmd = &cmd; + cmd_info.emmc_port = mmc_priv(card->host); + cmd_info.rsp_len = 6; + + err = SD_SendCMDGetRSP(&cmd_info, 0); + + if(err) { + pr_err("%s error: 0x98012030=0x%x, 0x98012032=0x%x\n", + __func__, cmd_info.emmc_port->normal_interrupt, cmd_info.emmc_port->error_interrupt); + } + + return err; +} + +int rtkemmc_switch(struct rtkemmc_host *emmc_port, u8 set, u8 index, u8 value, unsigned int timeout_ms) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err=0; + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (index << 16) | + (value << 8) | + set; + cmd.flags = MMC_CMD_AC|MMC_RSP_SPI_R1B | MMC_RSP_R1B; + cmd_info.cmd = &cmd; + cmd_info.emmc_port = emmc_port; + cmd_info.rsp_len = 6; + + err = SD_SendCMDGetRSP(&cmd_info, 0); + + if(err ) { + pr_err("%s error: 0x98012030=0x%x, 0x98012032=0x%x\n", + __func__, emmc_port->normal_interrupt, emmc_port->error_interrupt); + error_handling(emmc_port); + } + + return err; +} + +int rtkemmc_send_cmd18(struct rtkemmc_host *emmc_port, int size, unsigned long addr, unsigned int bIgnore) +{ + int ret_err=0; + struct sd_cmd_pkt cmd_info; + //struct mmc_host *host = emmc_port->mmc; + unsigned char *crd_tmp_buffer=NULL; + struct mmc_data *data=NULL; + struct mmc_command *cmd=NULL; + int i=0; + memset(&cmd_info, 0x00, sizeof(struct sd_cmd_pkt)); + + crd_tmp_buffer = (unsigned char *)emmc_port->dma_paddr; + if (crd_tmp_buffer == NULL) { + pr_err("%s,%s : crd_tmp_buffer == NULL\n",DRIVER_NAME,__func__); + return -5; + } + + for(i=0;i<(size/4);i++) { + *(u32 *)(emmc_port->dma_vaddr+(i*4)) = 0xdeadbeef; + //isb(); + //sync(emmc_port); + } + wmb(); + + if (cmd_info.cmd == NULL) { + cmd = (struct mmc_command*) kmalloc(sizeof(struct mmc_command),GFP_KERNEL); + memset(cmd, 0x00, sizeof(struct mmc_command)); + cmd_info.cmd = (struct mmc_command*) cmd; + } + cmd_info.emmc_port = emmc_port; + cmd_info.cmd->arg = addr; + cmd_info.cmd->opcode = MMC_READ_MULTIPLE_BLOCK; + cmd_info.rsp_len = 6; + cmd_info.byte_count = 0x200; + cmd_info.block_count = size/cmd_info.byte_count; + cmd_info.dma_buffer = crd_tmp_buffer; + + if (cmd_info.cmd->data == NULL) { + data = (struct mmc_data*) kmalloc(sizeof(struct mmc_data),GFP_KERNEL); + memset(data, 0x00, sizeof(struct mmc_data)); + cmd_info.cmd->data = data; + data->flags = MMC_DATA_READ; + } + else + cmd_info.cmd->data->flags = MMC_DATA_READ; + MMCPRINTF("\n*** %s %s %d, cmdidx=0x%02x(%d), resp_type=0x%08x, host=0x%08x, card=0x%08x -------\n", + __FILE__, __func__, __LINE__, cmd_info.cmd->opcode, cmd_info.cmd->opcode, cmd_info.cmd->flags, host, host->card); + ret_err = SD_Stream(&cmd_info, bIgnore); + if (ret_err) { +#ifdef RTKEMMC_DEBUG + printk(KERN_ERR "%s error: 0x98012030=0x%x, 0x98012032=0x%x, cmd->arg=0x%x, block count=%d\n", + __func__, emmc_port->normal_interrupt, emmc_port->error_interrupt, addr, cmd_info.block_count); +#endif +#ifdef RTKEMMC_PHASE_TRACE + trace_err_status=emmc_port->error_interrupt; + trace_normal_status=emmc_port->normal_interrupt; + trace_auto_err_status=emmc_port->auto_error_interrupt; +#endif + error_handling(emmc_port); + } + + if (cmd) { + kfree(cmd); + cmd_info.cmd = NULL; + cmd=NULL; + } + if (data) { + kfree(data); + //cmd_info.cmd->data = NULL; + data=NULL; + } + return ret_err; +} + +int rtkemmc_send_cmd25(struct rtkemmc_host *emmc_port,int size, unsigned long addr, int data_src, int *hs400_data, unsigned int bIgnore) +{ + int ret_err=0,i=0; + struct sd_cmd_pkt cmd_info; +// struct mmc_host *host = emmc_port->mmc; + char *crd_tmp_buffer=NULL; + struct mmc_data *data=NULL; + struct mmc_command *cmd=NULL; +// unsigned long flags=0; + memset(&cmd_info, 0x00, sizeof(struct sd_cmd_pkt)); + + crd_tmp_buffer = (unsigned char *) emmc_port->dma_paddr; + if (crd_tmp_buffer == NULL) + { + pr_err("%s,%s : crd_ext_csd == NULL\n",DRIVER_NAME,__func__); + return -5; + } + + if(data_src==0) { + for(i=0;i<(size/4);i++) + { + if(GLOBAL==0x80000000) GLOBAL=0; + else GLOBAL++; + *(u32 *)(emmc_port->dma_vaddr+(i*4)) = GLOBAL; + } + } + else if(data_src==1) { + for(i=0;i<(size/4);i++) + { + if(GLOBAL==0x80000000) GLOBAL=0; + else GLOBAL++; + *(u32 *)(emmc_port->dma_vaddr+(i*4)) = hs400_data[i]; + } + } + else pr_err("data_source flag should be 0 or 1\n"); + + wmb(); + + if (cmd_info.cmd == NULL) + { + cmd = (struct mmc_command*) kmalloc(sizeof(struct mmc_command),GFP_KERNEL); + memset(cmd, 0x00, sizeof(struct mmc_command)); + cmd_info.cmd = (struct mmc_command*) cmd; + } + + cmd_info.emmc_port = emmc_port; + cmd_info.cmd->arg = addr; + cmd_info.cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK; + cmd_info.rsp_len = 6; + cmd_info.byte_count = 0x200; + cmd_info.block_count = size/cmd_info.byte_count; + cmd_info.dma_buffer = crd_tmp_buffer; + + if (cmd_info.cmd->data == NULL) + { + data = (struct mmc_data*) kmalloc(sizeof(struct mmc_data),GFP_KERNEL); + memset(data, 0x00, sizeof(struct mmc_data)); + cmd_info.cmd->data = data; + data->flags = MMC_DATA_WRITE; + } + else + cmd_info.cmd->data->flags = MMC_DATA_WRITE; + + MMCPRINTF("\n*** %s %s %d, cmdidx=0x%02x(%d), resp_type=0x%08x, host=0x%08x, card=0x%08x , cmd=0x%08x, data=0x%08x-------\n", + __FILE__, __func__, __LINE__, cmd_info.cmd->opcode, cmd_info.cmd->opcode, cmd_info.cmd->flags, host, host->card,cmd,data); + ret_err = SD_Stream(&cmd_info, bIgnore); + if (ret_err) + { +#ifdef RTKEMMC_DEBUG + pr_err("%s error: 0x98012030=0x%x, 0x98012032=0x%x, cmd->arg=0x%x, block count=%d\n", + __func__, emmc_port->normal_interrupt, emmc_port->error_interrupt, addr, cmd_info.block_count); +#endif +#ifdef RTKEMMC_PHASE_TRACE + trace_err_status=emmc_port->error_interrupt; + trace_normal_status=emmc_port->normal_interrupt; + trace_auto_err_status=emmc_port->auto_error_interrupt; +#endif + error_handling(emmc_port); + } + MMCPRINTF("\n*** %s %s %d, cmdidx=0x%02x(%d), resp_type=0x%08x, host=0x%08x, card=0x%08x , cmd=0x%08x, data=0x%08x-------\n", + __FILE__, __func__, __LINE__, cmd_info.cmd->opcode, cmd_info.cmd->opcode, cmd_info.cmd->flags, host, host->card,cmd,data); +#if 1 + if (cmd) + { + cmd_info.cmd = NULL; + kfree(cmd); + cmd=NULL; + } + if (data) + { + //cmd_info.cmd->data = NULL; + kfree(data); + data=NULL; + } +#endif + sync(emmc_port); + return ret_err; +} + +int rtkemmc_send_cmd21(struct rtkemmc_host *emmc_port, int size, unsigned long addr) +{ + int ret_err=0; + struct sd_cmd_pkt cmd_info; + //struct mmc_host *host = emmc_port->mmc; + unsigned char *crd_tmp_buffer=NULL; + struct mmc_data *data=NULL; + struct mmc_command *cmd=NULL; + int i=0; + memset(&cmd_info, 0x00, sizeof(struct sd_cmd_pkt)); + + crd_tmp_buffer = (unsigned char *)emmc_port->dma_paddr; + if (crd_tmp_buffer == NULL) { + pr_err("%s,%s : crd_tmp_buffer == NULL\n",DRIVER_NAME,__func__); + return -5; + } + + for(i=0;i<(size/4);i++) { + *(u32 *)(emmc_port->dma_vaddr+(i*4)) = 0xdeadbeef; + //isb(); + //sync(emmc_port); + } + wmb(); + + if (cmd_info.cmd == NULL) { + cmd = (struct mmc_command*) kmalloc(sizeof(struct mmc_command),GFP_KERNEL); + memset(cmd, 0x00, sizeof(struct mmc_command)); + cmd_info.cmd = (struct mmc_command*) cmd; + } + cmd_info.emmc_port = emmc_port; + cmd_info.cmd->arg = addr; + cmd_info.cmd->opcode = MMC_SEND_TUNING_BLOCK_HS200; + cmd_info.rsp_len = 6; + cmd_info.byte_count = 0x80; + cmd_info.block_count = 1; + cmd_info.dma_buffer = crd_tmp_buffer; + + if (cmd_info.cmd->data == NULL) { + data = (struct mmc_data*) kmalloc(sizeof(struct mmc_data),GFP_KERNEL); + memset(data, 0x00, sizeof(struct mmc_data)); + cmd_info.cmd->data = data; + data->flags = MMC_DATA_READ; + } + else + cmd_info.cmd->data->flags = MMC_DATA_READ; + MMCPRINTF("\n*** %s %s %d, cmdidx=0x%02x(%d), resp_type=0x%08x, host=0x%08x, card=0x%08x -------\n", + __FILE__, __func__, __LINE__, cmd_info.cmd->opcode, cmd_info.cmd->opcode, cmd_info.cmd->flags, host, host->card); + ret_err = SD_Stream(&cmd_info, 1); + if (ret_err) { +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "Tuning rx cmd 21 err and call error handling\n"); +#endif + error_handling(emmc_port); + } + + if (cmd) { + kfree(cmd); + cmd_info.cmd = NULL; + cmd=NULL; + } + if (data) { + kfree(data); + //cmd_info.cmd->data = NULL; + data=NULL; + } + return ret_err; +} + +int rtkemmc_write_protect_cmd(struct rtkemmc_host *emmc_port, u32 args, bool is_wrtie_protect) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err=0; + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + if(is_wrtie_protect) + cmd.opcode = MMC_SET_WRITE_PROT; + else + cmd.opcode = MMC_CLR_WRITE_PROT; + + cmd.arg = args; + cmd.flags = MMC_CMD_AC|MMC_RSP_SPI_R1B | MMC_RSP_R1B; + cmd_info.cmd = &cmd; + cmd_info.emmc_port = emmc_port; + cmd_info.rsp_len = 6; + + err = SD_SendCMDGetRSP(&cmd_info,1); + + if(err ) { + pr_err("%s error: 0x98012030=0x%x, 0x98012032=0x%x\n", + __func__, emmc_port->normal_interrupt, emmc_port->error_interrupt); + + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_AUTO_CMD_ERR|EMMC_CMD_IDX_ERR|EMMC_CMD_END_BIT_ERR|EMMC_CMD_CRC_ERR|EMMC_CMD_TOUT_ERR))!=0){ //check cmd line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "CMD Line error occurs \n"); +#endif + rtkemmc_writeb(0x2, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x2<<24), 0x0, __func__); //wait for clear 0x2f bit 1 + } + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_ADMA_ERR|EMMC_DATA_END_BIT_ERR|EMMC_DATA_CRC_ERR|EMMC_DATA_TOUT_ERR)) !=0){ //check data line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "DAT Line error occurs \n"); +#endif + rtkemmc_writeb(0x4, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x4<<24), 0x0, __func__); //wait for clear 0x2f bit 2 + } + } + + mdelay(1); + return err; +} + +int rtkemmc_query_protect_cmd(struct rtkemmc_host *emmc_port, unsigned long addr, u32 cmd_idx) +{ + int ret_err=0; + struct sd_cmd_pkt cmd_info; + unsigned char *crd_tmp_buffer=NULL; + struct mmc_data *data=NULL; + struct mmc_command *cmd=NULL; + int i=0; + memset(&cmd_info, 0x00, sizeof(struct sd_cmd_pkt)); + + crd_tmp_buffer = (unsigned char *)emmc_port->dma_paddr; + if (crd_tmp_buffer == NULL) { + pr_err(KERN_ERR "%s,%s : crd_tmp_buffer == NULL\n",DRIVER_NAME,__func__); + return -5; + } + + for(i=0;i<(8/4);i++) { + *(u32 *)(emmc_port->dma_vaddr+(i*4)) = 0xdeadbeef; + } + wmb(); + + if (cmd_info.cmd == NULL) { + cmd = (struct mmc_command*) kmalloc(sizeof(struct mmc_command),GFP_KERNEL); + memset(cmd, 0x00, sizeof(struct mmc_command)); + cmd_info.cmd = (struct mmc_command*) cmd; + } + cmd_info.emmc_port = emmc_port; + cmd_info.cmd->arg = addr; + cmd_info.cmd->opcode = cmd_idx; + cmd_info.rsp_len = 6; + if(cmd_idx==MMC_SEND_WRITE_PROT) + cmd_info.byte_count = 0x4; + else + cmd_info.byte_count = 0x8; + cmd_info.block_count = 1; + cmd_info.dma_buffer = crd_tmp_buffer; + + if (cmd_info.cmd->data == NULL) { + data = (struct mmc_data*) kmalloc(sizeof(struct mmc_data),GFP_KERNEL); + memset(data, 0x00, sizeof(struct mmc_data)); + cmd_info.cmd->data = data; + data->flags = MMC_DATA_READ; + } + else + cmd_info.cmd->data->flags = MMC_DATA_READ; + + ret_err = SD_Stream(&cmd_info, 1); + if (ret_err) { +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "cmd %u err and call error handling\n", cmd_idx); +#endif + error_handling(emmc_port); + } + if(cmd_idx==MMC_SEND_WRITE_PROT) + printk(KERN_ERR "cmd30: from sector 0x%x = 0x%x\n", addr, *(u32 *)(emmc_port->dma_vaddr)); + else { + printk(KERN_ERR "cmd31: from sector 0x%x = 0x%x\n", addr, *(u32 *)(emmc_port->dma_vaddr)); + printk(KERN_ERR "cmd31: from sector 0x%x = 0x%x\n", addr, *(u32 *)(emmc_port->dma_vaddr+4)); + } + + if (cmd) { + kfree(cmd); + cmd_info.cmd = NULL; + cmd=NULL; + } + if (data) { + kfree(data); + //cmd_info.cmd->data = NULL; + data=NULL; + } + return ret_err; +} + +int search_best(u32 window, u32 range) +{ + int i, j, k, max; + int window_temp[32]; + int window_start[32]; + int window_end[32]; + int window_max=0; + int window_best=0; + int parse_end=1; + + if(window==0xffffffff){ + window_best=0x10; + return window_best; + } + else if((window==0xffff)&&(range==0x10)){ + window_best=0x8; + return window_best; + } + + for( i=0; i<0x20; i++ ) { + window_temp[i]=0; + window_start[i]=0; + window_end[i]=-1; + } + j=1; + i=0; + k=0; + max=0; + while((i<(range-1)) && (k<(range-1))){ + parse_end=0; + for( i=window_end[j-1]+1; i>i)&1)==1 ){ + window_start[j]=i; + break; + } + } + if( i==range){ + break; + } + for( k=window_start[j]+1; k>k)&1)==0){ + window_end[j]=k-1; + parse_end=1; + break; + } + } + if(parse_end==0){ + window_end[j]=range-1; + } + j++; + } + for(i=1; i>(range-1))&1)==1)) + { + window_temp[1]=window_temp[1]+window_temp[j-1]; + window_start[1]=window_start[j-1]; + } + for(i=1; iwindow_max){ + window_max=window_temp[i]; + max=i; + } + } + + if((((window&1)==1)&&(((window>>(range-1))&1)==1))&&(max==1)){ + window_best=(((window_start[max]+window_end[max]+range)/2)&(range-1)); + } + else { + window_best=((window_start[max]+window_end[max])/2)&0x1f; + } + + if(window_max>4){ + return window_best; + } + + return 0xff; +} + +int rtkemmc_phase_tuning(struct rtkemmc_host *emmc_port,u32 mode,int flag, int stage) +{ + u32 TX_window=0; + u32 RX_window=0; + u32 TX1_window=0; + int TX_best=0x0; + int RX_best=0x0; + int TX1_best=0x0; + int i=0; + u32 range=0; + u32 rx_range=0x20; + u16 state=0; + unsigned int loop_cnt=0; + + if (mode == MODE_HS400 || mode == MODE_DDR) + range = 0x10; + else + range = 0x20; + + if (mode == MODE_HS400) + loop_cnt=0; + else if(mode == MODE_HS200) + loop_cnt=20; + else + loop_cnt=30; + + if(emmc_port->suspend == 1 && (emmc_port->tx_tuning || emmc_port->rx_tuning) && emmc_port->mmc->card->cid.manfid != 0x13) + { + if(emmc_port->tx_tuning==0 && emmc_port->rx_tuning==1) { + phase(emmc_port, emmc_port->tx_phase, suspend_VP1); + } + else if(emmc_port->tx_tuning==1 && emmc_port->rx_tuning==0) + { + phase(emmc_port, suspend_VP0, emmc_port->rx_phase); + } + else { + phase(emmc_port, suspend_VP0, suspend_VP1); + } + + rtkemmc_reset_fifo(emmc_port); + + printk(KERN_ERR "suspend/resume: restore tx & rx phase: TX=0x%x, RX=0x%x\n", suspend_VP0, suspend_VP1); + if(mode == MODE_HS200) { + emmc_port->suspend = 0; + } + return 0; + } +#ifdef PHASE_INHERITED + if (emmc_port->tx_tuning || emmc_port->rx_tuning){ + phase(emmc_port, (emmc_port->tx_tuning)?0xff:emmc_port->tx_phase, (emmc_port->rx_tuning)?0xff:emmc_port->rx_phase); + + rtkemmc_reset_fifo(emmc_port); + } + else { + phase(emmc_port, emmc_port->tx_phase, emmc_port->rx_phase); //VP0, VP1 phase + + rtkemmc_reset_fifo(emmc_port); + + printk(KERN_INFO "Inherit bootcode tuning phase: TX=0x%x, RX=0x%x\n", emmc_port->tx_phase, emmc_port->rx_phase); + return 0; + } +#else + phase(emmc_port, 0, 0); //VP0, VP1 phase + + rtkemmc_reset_fifo(emmc_port); + + mdelay(5); + sync(emmc_port); +#endif + + /*Actually, in Stark, the clock source is from crc, command tx does not need to be tuned, but this action is for safety. + We ecpected that tx phase is 0xffffffff(hs200) or 0xffff(hs400) if the clock source is from crc + if user encounter a bad IC, they can adjust the clock source from 0x98012420 [14:15] 2b' 00 to 2b' 10, + Again, this tx tuning is needed*/ + if((soc_device_match(rtk_soc_stark) || soc_device_match(rtk_soc_groot)) && + (readw(emmc_port->emmc_membase+EMMC_OTHER1)&(0x3<<14))==0) + { + if(mode==MODE_HS400 || mode == MODE_DDR) { + TX_window = 0xffff; + } + else { + TX_window = 0xffffffff; + } + suspend_VP0 = TX_best; + } + else if ((stage==TUNING_STAGE1 || stage==TUNING_STAGE_BOTH) && emmc_port->tx_tuning) { + if (mode == MODE_DDR && flag==1) + printk(KERN_ERR "Start DDR50 TX Tuning:\n"); + else if (mode == MODE_HS400 && flag==1) + printk(KERN_ERR "Start HS400 TX Tuning: \n"); + else if(flag==1) + printk(KERN_ERR "Start HS200 TX Tuning:\n"); + for(i=0;ierror_interrupt&0x01) != 0) + TX_window= TX_window&(~(1<rx_tuning) { + if (mode == MODE_DDR && flag==1) + printk(KERN_ERR "Start DDR50 RX Tuning:\n"); + else if (mode == MODE_HS400 && flag==1) + printk(KERN_ERR "Start HS400 RX Tuning:\n"); + else if(flag==1) + printk(KERN_ERR "Start HS200 RX Tuning:\n "); + +rx_retry: + for(i=0;i60) + pr_err("loop cnt %d: RX_WINDOW = 0x%08x, cannot find a proper rx phase\n", loop_cnt, RX_window); + } + + if(loop_cnt<=60) + goto rx_retry; + } + else { + rtkemmc_set_pad_driving(emmc_port, + emmc_port->pddrive_nf[1], + emmc_port->pddrive_nf[2], + emmc_port->pddrive_nf[3], + emmc_port->pddrive_nf[4]); + } + if(flag==1)printk(KERN_ERR "RX_WINDOW = 0x%08x RX_best=0x%x\n", RX_window,RX_best); + + phase(emmc_port, 0xff, RX_best); + + rtkemmc_reset_fifo(emmc_port); + + suspend_VP1 = RX_best; + + if(RX_best==0xff) return -1; + } +#ifdef RTKEMMC_PHASE_TRACE + trace_index = 1000; +#endif + if (mode == MODE_HS400) + loop_cnt=0; + else + loop_cnt=20; + + if ((stage==TUNING_STAGE2 || stage==TUNING_STAGE_BOTH) && + (mode == MODE_HS400 || mode == MODE_DDR || + soc_device_match(rtk_soc_stark) || soc_device_match(rtk_soc_groot)) && + emmc_port->tx_tuning) { + TX1_window= TX_window; + if(flag==1 && mode == MODE_HS400) printk(KERN_ERR "Start HS400 TX Tuning2:\n"); + else if(flag==1 && mode == MODE_DDR) printk(KERN_ERR "Start DDR50 TX Tuning2:\n"); + else if(flag==1) printk(KERN_ERR "Start HS200 TX Tuning2:\n"); + +tx1_retry: + for(i=0;iemmc_tuning_addr/512),0,NULL ,1) != 0) + TX1_window= TX1_window&(~(1<60) + pr_err("loop cnt %d: TX1_WINDOW = 0x%08x, cannot find a proper tx1 phase\n", loop_cnt, TX1_window); + } + + if(loop_cnt<=60) + goto tx1_retry; + } + else { + rtkemmc_set_pad_driving(emmc_port, + emmc_port->pddrive_nf[1], + emmc_port->pddrive_nf[2], + emmc_port->pddrive_nf[3], + emmc_port->pddrive_nf[4]); + } + + if(flag==1)printk(KERN_ERR "TX1_WINDOW = 0x%08x TX1_best=0x%x\n", TX1_window,TX1_best); + + phase(emmc_port, TX1_best, 0xff); + + rtkemmc_reset_fifo(emmc_port); + + suspend_VP0 = TX1_best; + + if(TX1_best==0xff) return -1; + } + sync(emmc_port); + + return 0; +} + +static int mmc_Tuning_DDR50(struct rtkemmc_host *emmc_port) +{ + if(emmc_port->retune==0) + down_write(&emmc_port->cr_rw_sem); + + if (emmc_port->pddrive_nf[0] != 0 ) + rtkemmc_set_pad_driving(emmc_port, emmc_port->pddrive_nf[1], emmc_port->pddrive_nf[2], emmc_port->pddrive_nf[3], emmc_port->pddrive_nf[4]); + else { + rtkemmc_set_pad_driving(emmc_port,0x0, 0x0, 0x0, 0x0); + } + if(emmc_port->tx_tuning && emmc_port->rx_tuning) { //device tree set kernel tuning for DDR50 + rtkemmc_phase_tuning(emmc_port, MODE_DDR,1, TUNING_STAGE_BOTH); + sync(emmc_port); + mdelay(10); + } + else { + phase(emmc_port, 0x8, 0x9); + + rtkemmc_reset_fifo(emmc_port); + } + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&0xfffffffe, emmc_port->emmc_membase+EMMC_OTHER1); //enable L4 gated after DDR50 finished + + emmc_port->time_setting = 0; + + if(emmc_port->retune==0) + up_write(&emmc_port->cr_rw_sem); + return 0; +} + +static int mmc_Tuning_HS200(struct rtkemmc_host *emmc_port) +{ + MMCPRINTF("%s \n", __func__); + + if(emmc_port->retune==0) + down_write(&emmc_port->cr_rw_sem); + + if (emmc_port->pddrive_nf[0] != 0) + rtkemmc_set_pad_driving(emmc_port, emmc_port->pddrive_nf[1], emmc_port->pddrive_nf[2], emmc_port->pddrive_nf[3], emmc_port->pddrive_nf[4]); + else { + rtkemmc_set_pad_driving(emmc_port,0x2, 0x2, 0x2, 0x0); + } + + rtkemmc_phase_tuning(emmc_port, MODE_HS200,1, TUNING_STAGE_BOTH); + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&0xfffffffe, emmc_port->emmc_membase+EMMC_OTHER1); //enable L4 gated after HS200 finished + sync(emmc_port); + mdelay(10); + emmc_port->time_setting = 0; + + if(emmc_port->retune==0) + up_write(&emmc_port->cr_rw_sem); + + printk(KERN_ERR "HS200: final phase=0x%x\n", readl(emmc_port->crt_membase + SYS_PLL_EMMC1)); + + return 0; +} + +static int mmc_Tuning_HS400(struct rtkemmc_host *emmc_port) +{ + if(emmc_port->retune==0) + down_write(&emmc_port->cr_rw_sem); + + if (emmc_port->pddrive_nf[0] != 0) + rtkemmc_set_pad_driving(emmc_port, emmc_port->pddrive_nf[1], emmc_port->pddrive_nf[2], emmc_port->pddrive_nf[3], emmc_port->pddrive_nf[4]); + else { + rtkemmc_set_pad_driving(emmc_port,0x4, 0x4, 0x4, 0x0); + } + rtkemmc_phase_tuning(emmc_port, MODE_HS400,1, TUNING_STAGE_BOTH); + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&0xfffffffe, emmc_port->emmc_membase+EMMC_OTHER1); //enable L4 gated after HS400 finished + sync(emmc_port); + mdelay(10); + if(emmc_port->retune==0) + up_write(&emmc_port->cr_rw_sem); + printk(KERN_ERR "HS400 first stage: final phase=0x%x\n", readl(emmc_port->crt_membase + SYS_PLL_EMMC1)); + + return 0; +} + +static int rtkemmc_execute_tuning(struct mmc_host *host, u32 opcode) +{ + struct rtkemmc_host *emmc_port; + struct sd_cmd_pkt cmd_info; + MMCPRINTF("%s \n", __func__); + + emmc_port = mmc_priv(host); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + cmd_info.emmc_port = emmc_port; + + if (host->card){ + printk(KERN_INFO "emmc card manid = 0x%08x\n", host->card->cid.manfid); + if (host->card->cid.manfid == 0x13) //micron manfid + emmc_port->rx_tuning = 1; //micron: force to turn on rx tuning + } + else + pr_err("host->card is null! \n"); + + g_bTuning = 1; + + + switch(emmc_port->speed_step) + { + case 0: + break; + case 1: + mmc_Tuning_DDR50(emmc_port); + break; + case 2: + mmc_Tuning_HS200(emmc_port); + break; + case 3: + mmc_Tuning_HS400(emmc_port); //hs400 still have dqs tuning, so set flag as 1 after dqs tuning + break; + default: + break; + } + + g_bTuning = 0; + return 0; +} + +#ifdef SHA256 +static int rtk_get_hash(unsigned char *input, unsigned char *sha256_hash, unsigned int dma_len) +{ + struct crypto_shash *alg = NULL; + struct sdesc *sdesc = NULL; + unsigned char output[32] = {0}; + char *hash_alg_name = "sha256"; + int ret = -1; + int size = 0; + + alg = crypto_alloc_shash(hash_alg_name, 0, 0); + if (IS_ERR(alg)) { + pr_info("%s: can't alloc alg %s\n", __func__, hash_alg_name); + ret = -1; + goto exit; + } + + size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); + sdesc = kmalloc(size, GFP_KERNEL); + if (IS_ERR(sdesc)) { + pr_err("%s: can't alloc sdesc\n", __func__); + ret = -1; + goto exit; + } + + sdesc->shash.tfm = alg; + + ret = crypto_shash_digest(&sdesc->shash, input, dma_len, output); + if (ret != 0) { + pr_err("%s: can't get hash\n", __func__); + ret = -1; + goto exit; + } + + memcpy(sha256_hash, output, 32); + + ret = 0; +exit: + if(alg) + crypto_free_shash(alg); + if(sdesc) + kfree(sdesc); + return ret; +} +#endif + +static int rw_test_tuning(struct rtkemmc_host *emmc_port,unsigned long emmc_blk_addr) +{ + int i; +#ifdef RTKEMMC_PHASE_TRACE + trace_cur_tuning_cmd = 26; +#endif + rtkemmc_send_cmd25(emmc_port,DMA_ALLOC_LENGTH, emmc_blk_addr,0, NULL, 1); +#ifdef SHA256 + rtk_get_hash(emmc_port->dma_vaddr, compare3, DMA_ALLOC_LENGTH); +#else + memcpy(compare1, emmc_port->dma_vaddr, DMA_ALLOC_LENGTH); +#endif +#ifdef RTKEMMC_PHASE_TRACE + trace_cur_tuning_cmd = 27; +#endif + rtkemmc_send_cmd18(emmc_port,DMA_ALLOC_LENGTH, emmc_blk_addr, 1); +#ifdef SHA256 + rtk_get_hash(emmc_port->dma_vaddr, compare4, DMA_ALLOC_LENGTH); +#else + memcpy(compare2, emmc_port->dma_vaddr, DMA_ALLOC_LENGTH); +#endif + +#ifdef SHA256 + for(i=0;i<32;i++) { + if(compare3[i]!=compare4[i]) { + return 1; + } + } +#else + for(i=0;isuspend == 1) + { + if(emmc_port->dqs_tuning == 1) { + rtkemmc_dqs_delay_tap(emmc_port, suspend_dqs); + } + else { + rtkemmc_dqs_delay_tap(emmc_port, emmc_port->dqs); + } + printk(KERN_ERR "suspend/resume: restore DQS=0x%x\n", readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1)); + emmc_port->suspend = 0; + emmc_port->time_setting = 0; + return; + } + if(emmc_port->retune==0) + down_write(&emmc_port->cr_rw_sem); + g_bTuning = 1; + +#ifdef SHA256 + printk(KERN_ERR "[EMMC] SHA256 is enabled for dqs comparison!!!\n"); + if(!compare3) + compare3 = dma_alloc_coherent(emmc_port->dev, 32, &compare3_phy_addr ,GFP_KERNEL); + if(!compare4) + compare4 = dma_alloc_coherent(emmc_port->dev, 32, &compare4_phy_addr ,GFP_KERNEL); +#endif + +#ifdef DQS_INHERITED + if(emmc_port->dqs_tuning == 0) { + rtkemmc_dqs_delay_tap(emmc_port, emmc_port->dqs); + + printk(KERN_ERR "Inherit bootcode dqs: DQS=0x%x\n", readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1)); + printk(KERN_ERR "read/write test for inherit hs400 parameter...\n"); + if( rw_test_tuning(emmc_port, (emmc_port->emmc_tuning_addr/512))==0) { + printk(KERN_ERR "read/write test success for hs400 parameter!!!\n"); + g_bTuning = 0; + emmc_port->time_setting = 0; + if(emmc_port->retune==0) + up_write(&emmc_port->cr_rw_sem); + +#ifdef SHA256 + if(compare3) + dma_free_coherent(emmc_port->dev, 32, compare3 , compare3_phy_addr); + if(compare4) + dma_free_coherent(emmc_port->dev, 32, compare4 , compare4_phy_addr); + compare3 = NULL; + compare4 = NULL; +#endif + return; + } + else { + emmc_port->dqs_tuning=1; + emmc_port->tx_tuning = 1; + emmc_port->rx_tuning = 1; + pr_err("read/write test failed, retune the hs400...\n"); + } + } +#endif + + dqs_tuning_blk_addr = emmc_port->emmc_tuning_addr / 512; //convert from offset to block address + printk(KERN_ERR "emmc_port->emmc_tuning_addr = 0x%lx, dqs_tuning_blk_addr = 0x%lx\n", emmc_port->emmc_tuning_addr, dqs_tuning_blk_addr); + +retry: + bitmap=0; + max=0; + j=0; + ret = -1; +#ifdef RTKEMMC_PHASE_TRACE + trace_dqs_counter++; +#endif + for(i=0; i<0x20; i++) { + if(j>=5) //must be more than 5 continuous tap sample point + max = j; + if(j==0 && max!=0) //find the max tap length + break; +#ifdef RTKEMMC_DEBUG + printk(KERN_ERR "DQS windows tuning: i=0x%x\n",i<<1); +#endif +#ifdef RTKEMMC_PHASE_TRACE + trace_dqs_index = i; +#endif + if(soc_device_match(rtk_soc_hank_a00)) { + ret = rtkemmc_phase_tuning(emmc_port,MODE_HS400,0, TUNING_STAGE1); + rtkemmc_dqs_delay_tap(emmc_port, (i<<1)); + if(ret == 0) + ret = rtkemmc_phase_tuning(emmc_port,MODE_HS400,0, TUNING_STAGE_BOTH); + } + else{ + rtkemmc_dqs_delay_tap(emmc_port, (i<<1)); + ret = rtkemmc_phase_tuning(emmc_port, MODE_HS400, 0, TUNING_STAGE_BOTH); + } + if( ret == 0 && rw_test_tuning(emmc_port, dqs_tuning_blk_addr)==0) { + j++; + bitmap |= (1<0x3e) retry_cmd_dly_tap=0; + printk(KERN_ERR "DQS_RETRY: dqs tap bitmap= 0x%x, EMMC_WCMD_CTRL=0x%x, update EMMC_WCMD_CTRL value 0x%x, retry: %d\n", + bitmap, readl(emmc_port->emmc_membase + EMMC_WCMD_CTRL), retry_cmd_dly_tap, retry_count); + rtkemmc_dump_register(emmc_port); + + clk_disable_unprepare(emmc_port->clk_en_emmc); + clk_disable_unprepare(emmc_port->clk_en_emmc_ip); + sync(emmc_port); + + reset_control_assert(emmc_port->rstc_emmc); + sync(emmc_port); + + reset_control_deassert(emmc_port->rstc_emmc); + sync(emmc_port); + + clk_prepare_enable(emmc_port->clk_en_emmc); + clk_prepare_enable(emmc_port->clk_en_emmc_ip); + sync(emmc_port); + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x55c), 0x1, 0x1, __func__); //wait for clear 0x255c bit 0 + rtkemmc_restore_register(emmc_port); + + cmd_delay_tap_setting(emmc_port, (0x80|retry_cmd_dly_tap)); + + sync(emmc_port); + mdelay(10); + rtkemmc_restore_l4_register(emmc_port); + + retry_cmd_dly_tap += 2; + + goto retry; + } + else { + printk(KERN_ERR RED_BOLD"Cannot find a proper dqs window..., dqs tap bitmap= 0x%x\n"RESET, bitmap); + asm volatile("wait_done_loop4:"); + asm volatile("b wait_done_loop4"); + } + } + else { + retry_count = 0; + rtkemmc_dqs_delay_tap(emmc_port, (readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1)-2-((max/2)*2))); + + suspend_dqs = readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1); +#ifdef RTKEMMC_PHASE_TRACE + printk(KERN_ERR "trace_dqs_counter=%d\n", trace_dqs_counter); +#endif + printk(KERN_ERR "max sample point=%d, bitmap=0x%x, DQS=0x%x EMMC_WCMD_CTRL=0x%x\n", + max, bitmap, readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1), readl(emmc_port->emmc_membase + EMMC_WCMD_CTRL)); +#ifdef RTKEMMC_PHASE_TRACE + trace_dqs_index = 999; +#endif + rtkemmc_phase_tuning(emmc_port,MODE_HS400,1, TUNING_STAGE_BOTH); + emmc_port->time_setting = 0; + printk(KERN_ERR "HS400: final phase=0x%x\n", readl(emmc_port->crt_membase + SYS_PLL_EMMC1)); + } + +#ifdef SHA256 + if(compare3) + dma_free_coherent(emmc_port->dev, 32, compare3 , compare3_phy_addr); + if(compare4) + dma_free_coherent(emmc_port->dev, 32, compare4 , compare4_phy_addr); + compare3 = NULL; + compare4 = NULL; +#endif + sync(emmc_port); + mdelay(10); + g_bTuning = 0; + + buf = nvmem_cell_read(emmc_port->cell, &buf_size); + + printk(KERN_ERR "save eMMC hs400 parameter to emmc dqs_tuning_blk_addr 0x%lx\n", dqs_tuning_blk_addr+1024); + hs400_data[0] = HS400_VERSION; + hs400_data[1] = (readl(emmc_port->crt_membase + SYS_PLL_EMMC1) & 0x000000f8) >> 3; + hs400_data[2] = (readl(emmc_port->crt_membase + SYS_PLL_EMMC1) & 0x00001f00) >> 8; + hs400_data[3] = readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1); + hs400_data[4] = readl(emmc_port->emmc_membase + EMMC_WCMD_CTRL); + hs400_data[5] = hs400_data[0]+ hs400_data[1]*2 + hs400_data[2]*3 + hs400_data[3]*4 + hs400_data[4]*5; + hs400_data[6] = buf[0]; + hs400_data[7] = buf[1]; + hs400_data[8] = buf[2]; + + printk(KERN_ERR "hs400 parameter: hs400_verion[0]=0x%x, hs400_TX[1]=0x%x, hs400_RX[2]=0x%x,hs400_dqs[3]=0x%x,hs400_cmd_dly_tap[4]=0x%x\n", + hs400_data[0], hs400_data[1],hs400_data[2],hs400_data[3],hs400_data[4]); + printk(KERN_ERR "UUID: [0]=0x%x, [1]=0x%x, [2]=0x%x\n", hs400_data[6], hs400_data[7], hs400_data[8]); + rtkemmc_send_cmd25(emmc_port, 512, dqs_tuning_blk_addr+1024, 1, hs400_data, 0); + + kfree(buf); + + if(emmc_port->retune==0) + up_write(&emmc_port->cr_rw_sem); + +} + +static u32 rtkemmc_get_cmd_timeout(struct sd_cmd_pkt *cmd_info) +{ + struct rtkemmc_host *emmc_port = cmd_info->emmc_port; + u16 block_count = cmd_info->block_count; + u32 tmout = 0; + + MMCPRINTF("\n"); + + if(cmd_info->cmd->data) { + tmout = msecs_to_jiffies(2000); + + if(block_count>0x100) + tmout = tmout + 1000 * msecs_to_jiffies(block_count); + } + else + tmout = msecs_to_jiffies(800); + +#ifdef CONFIG_ANDROID + tmout += msecs_to_jiffies(100); +#endif + + cmd_info->timeout = emmc_port->tmout = tmout; + + return 0; +} + +static void rtkemmc_set_bus_width(struct rtkemmc_host *emmc_port, struct mmc_ios *ios) +{ + unsigned long flags; + + if (ios->bus_width == MMC_BUS_WIDTH_8){ + spin_lock_irqsave(&emmc_port->lock,flags); + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R) & + EMMC_EXT_DAT_XFER_MASK) | EMMC_BUS_WIDTH_8, + emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + spin_unlock_irqrestore(&emmc_port->lock, flags); + + pr_info("%s: set bus width 8, EMMC_HOST_CTRL1_R=%08x\n", + DRIVER_NAME, readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R)); + + } + else if (ios->bus_width == MMC_BUS_WIDTH_4){ + spin_lock_irqsave(&emmc_port->lock,flags); + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R) & + (EMMC_EXT_DAT_XFER_MASK & EMMC_DAT_XFER_WIDTH_MASK))|EMMC_BUS_WIDTH_4, + emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + spin_unlock_irqrestore(&emmc_port->lock, flags); + + pr_info("%s: set bus width 4, EMMC_HOST_CTRL1_R=%08x\n", + DRIVER_NAME, readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R)); + } +} + +static void rtkemmc_set_ios(struct mmc_host *host, struct mmc_ios *ios) +{ + struct rtkemmc_host *emmc_port; + u32 cur_timing = 0; + + emmc_port = mmc_priv(host); + cur_timing = ios->timing; + + if (!g_bResuming) { + switch(cur_timing) + { + case MMC_TIMING_MMC_HS400: + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R) & + EMMC_HIGH_SPEED_MASK) | EMMC_HIGH_SPEED_EN, + emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + rtkemmc_writew((readw(emmc_port->emmc_membase + EMMC_HOST_CTRL2_R) & + EMMC_UHS_MODE_SEL_MASK)|MODE_HS400, + emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); //enable HS400 + if(soc_device_match(rtk_soc_hank)) + rtkemmc_set_freq(emmc_port,0xa6, 0x0); //200MHZ + else + rtkemmc_stark_set_freq(emmc_port,0xa6, EMMC_CLK_DIV1); + break; + case MMC_TIMING_MMC_HS200: + rtkemmc_writew((readw(emmc_port->emmc_membase + EMMC_HOST_CTRL2_R) & + EMMC_UHS_MODE_SEL_MASK)|MODE_HS200, + emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + if(soc_device_match(rtk_soc_hank)) + rtkemmc_set_freq(emmc_port,0xa6, 0x0); //200MHZ + else + rtkemmc_stark_set_freq(emmc_port,0xa6, EMMC_CLK_DIV1); + break; + case MMC_TIMING_MMC_DDR52: + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R) & + EMMC_HIGH_SPEED_MASK) | EMMC_HIGH_SPEED_EN, + emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + rtkemmc_writew((readw(emmc_port->emmc_membase + EMMC_HOST_CTRL2_R) & + EMMC_UHS_MODE_SEL_MASK) | MODE_DDR, + emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + if(soc_device_match(rtk_soc_hank)) + rtkemmc_set_freq(emmc_port,0x57, 0x1); //50MB + else + rtkemmc_stark_set_freq(emmc_port,0xa6, EMMC_CLK_DIV4); + break; + case MMC_TIMING_MMC_HS: + rtkemmc_writew((readw(emmc_port->emmc_membase + EMMC_HOST_CTRL2_R)& + EMMC_UHS_MODE_SEL_MASK) | MODE_SDR, + emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + if(soc_device_match(rtk_soc_hank)) + rtkemmc_set_freq(emmc_port,0x57, 0x1); //50Mhz + else + rtkemmc_stark_set_freq(emmc_port,0xa6, EMMC_CLK_DIV4); + /*enable L4 gated after SDR50 finished*/ + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&0xfffffffe, emmc_port->emmc_membase+EMMC_OTHER1); + break; + case MMC_TIMING_LEGACY: + if(soc_device_match(rtk_soc_hank)) + rtkemmc_set_freq(emmc_port,0x46, 0x80); //80Mhz + else + rtkemmc_stark_set_freq(emmc_port,0xa6, EMMC_CLK_DIV512); + rtkemmc_writew((readw(emmc_port->emmc_membase + EMMC_HOST_CTRL2_R) & + EMMC_UHS_MODE_SEL_MASK) | MODE_LEGACY, + emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + break; + default: + printk(KERN_INFO "%s: cur_timing = %u \n", __FILE__, cur_timing); + break; + } + } + rtkemmc_set_bus_width(emmc_port, ios); + emmc_port->time_setting = 1; +} + +static void rtkemmc_req_end_tasklet(unsigned long param) +{ + struct rtkemmc_host *emmc_port; + struct mmc_request* mrq; + unsigned long flags; + MMCPRINTF("%s \n", __func__); + + emmc_port = (struct rtkemmc_host *)param; + spin_lock_irqsave(&emmc_port->lock,flags); + + mrq = emmc_port->mrq; + emmc_port->mrq = NULL; + + spin_unlock_irqrestore(&emmc_port->lock, flags); + + mmc_request_done(emmc_port->mmc, mrq); +} + +static int rtkemmc_free_dma_buf(struct rtkemmc_host *emmc_port) +{ + if (emmc_port->desc_vaddr) + dma_free_coherent(emmc_port->dev, + DESC_ALLOC_LENGTH, + emmc_port->desc_vaddr, + emmc_port->desc_paddr); + + if (emmc_port->dma_vaddr) + dma_free_coherent(emmc_port->dev, + DMA_ALLOC_LENGTH, + emmc_port->dma_vaddr, + emmc_port->dma_paddr); + + return 0; +} + +static int rtkemmc_allocate_dma_buf(struct rtkemmc_host *emmc_port) +{ + if (!emmc_port->desc_vaddr) + emmc_port->desc_vaddr = dma_alloc_coherent(emmc_port->dev, + DESC_ALLOC_LENGTH, + &emmc_port->desc_paddr, + GFP_KERNEL); + + if (!emmc_port->dma_vaddr) + emmc_port->dma_vaddr = dma_alloc_coherent(emmc_port->dev, + DMA_ALLOC_LENGTH, + &emmc_port->dma_paddr, + GFP_KERNEL); + + if(!emmc_port->desc_vaddr || !emmc_port->dma_vaddr) + { + pr_err("Allocate Realtek eMMC DMA failed !!!\n"); + return -ENOMEM; + } + + return 0; +} + +static int wait_done_timeout(struct rtkemmc_host *emmc_port, volatile u32 *addr, u32 mask, u32 value, const char *string) +{ + int n = 0; + while(1) + { + if (((*addr) &mask) == value){ + break; + } + + if((readw(emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_R) & 0x8000)!=0) { + break; + } + + if(n++ > 3000000) { + pr_err("Timeout!!! cmd_opcode=%d, cmd_arg=0x%x, addr=0x%x, mask=0x%x, value=0x%x, emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_R=0x%x \ + emmc_port->emmc_membase + EMMC_ERROR_INT_STA_R=0x%x, *addr=0x%x, pre_func=%s\n", + emmc_port->cmd_opcode, readl(emmc_port->emmc_membase+EMMC_ARGUMENT_R), addr, mask, value, + readw(emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_R), readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R), + readl(addr), string); +#ifdef RTKEMMC_PHASE_TRACE + if(g_bTuning==1) { + printk(KERN_ERR "trace_cur_tuning_cmd = %d, trace_index=%d, trace_phase_bitmap=0x%x, trace_dqs_index=%d\n", + trace_cur_tuning_cmd, trace_index, trace_phase_bitmap, trace_dqs_index); + printk(KERN_ERR "last tuning err status=0x%x, last tuning normal status=0x%x, last tuning auto err status=0x%x\n", + trace_err_status, trace_normal_status, trace_auto_err_status); + printk(KERN_ERR "%s: trace_TX_window=0x%x, trace_RX_window=0x%x, trace_TX1_window=0x%x\n", + __func__, trace_TX_window, trace_RX_window, trace_TX1_window); + } +#endif + printk(KERN_ERR "RESP01=0x%x, RESP23=0x%x, RESP45=0x%x, RESP67=0x%x\n", + readl(emmc_port->emmc_membase + EMMC_RESP01_R), + readl(emmc_port->emmc_membase + EMMC_RESP23_R), + readl(emmc_port->emmc_membase + EMMC_RESP45_R), + readl(emmc_port->emmc_membase + EMMC_RESP67_R)); + print_err_reg(emmc_port->cmd_opcode, emmc_port->normal_interrupt, emmc_port->error_interrupt); + print_ip_desc(emmc_port); + print_reg_info(emmc_port); +#ifdef RTKEMMC_PHASE_TRACE + print_desc_content(emmc_port); +#endif + asm volatile("wait_done_loop:"); + asm volatile("b wait_done_loop"); + return -1; + } + udelay(1); + sync(emmc_port); + } + return 0; +} + +void rtkemmc_set_pad_driving(struct rtkemmc_host *emmc_port, u32 clk_drv, u32 cmd_drv, u32 data_drv, u32 ds_drv) +{ + if(soc_device_match(rtk_soc_hank) || soc_device_match(rtk_soc_groot)) { + u32 clk_drv_t; + u32 cmd_drv_t; + u32 data_drv_t; + + if((clk_drv+1)>7) clk_drv_t= 7; + else clk_drv_t = clk_drv+1; + + if((cmd_drv+1)>7) cmd_drv_t=7; + else cmd_drv_t = cmd_drv+1; + + if((data_drv+1)>7) data_drv_t=7; + else data_drv_t = data_drv+1; + + rtkemmc_writel((readl(emmc_port->mux_mis_membase + EMMC_ISO_PFUNC1)&0xff03f03f)|(clk_drv_t<<6)|(clk_drv<<9)|(cmd_drv_t<<18)|(cmd_drv<<21), + emmc_port->mux_mis_membase + EMMC_ISO_PFUNC1); + rtkemmc_writel((readl(emmc_port->mux_mis_membase + EMMC_ISO_PFUNC2)&0xff03f03f)|(data_drv_t<<6)|(data_drv<<9)|(data_drv_t<<18)|(data_drv<<21), + emmc_port->mux_mis_membase + EMMC_ISO_PFUNC2); + rtkemmc_writel((readl(emmc_port->mux_mis_membase + EMMC_ISO_PFUNC3)&0xff03f03f)|(data_drv_t<<6)|(data_drv<<9)|(data_drv_t<<18)|(data_drv<<21), + emmc_port->mux_mis_membase + EMMC_ISO_PFUNC3); + rtkemmc_writel((readl(emmc_port->mux_mis_membase + EMMC_ISO_PFUNC4)&0xff03f03f)|(data_drv_t<<6)|(data_drv<<9)|(data_drv_t<<18)|(data_drv<<21), + emmc_port->mux_mis_membase + EMMC_ISO_PFUNC4); + rtkemmc_writel((readl(emmc_port->mux_mis_membase + EMMC_ISO_PFUNC5)&0xff03f03f)|(data_drv_t<<6)|(data_drv<<9)|(data_drv_t<<18)|(data_drv<<21), + emmc_port->mux_mis_membase + EMMC_ISO_PFUNC5); + + } + else { + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC4)&0xfff81fff)|(clk_drv<<13)|(clk_drv<<16), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC4); + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC5)&0xfffff03f)|(cmd_drv<<6)|(cmd_drv<<9), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC5); + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC6)&0xfff03fff)|(data_drv<<14)|(data_drv<<17), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC6); + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC7)&0xfe07f03f)|(data_drv<<6)|(data_drv<<9)|(data_drv<<19)|(data_drv<<22), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC7); + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC8)&0xfff81fc0)|(data_drv<<0)|(data_drv<<3)|(data_drv<<13)|(data_drv<<16), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC8); + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC9)&0xfe07f03f)|(data_drv<<6)|(data_drv<<9)|(clk_drv<<19)|(clk_drv<<22), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC9); + rtkemmc_writel((readl(emmc_port->mux_mis_membase+ EMMC_STARK_ISO_PFUNC10)&0xffffffc0)|(clk_drv<<0)|(clk_drv<<3), + emmc_port->mux_mis_membase + EMMC_STARK_ISO_PFUNC10); + } + isb(); + sync(emmc_port); +} + +void phase(struct rtkemmc_host *emmc_port, u32 VP0, u32 VP1) +{ + if((VP0!=0xff) || (VP1!=0xff)) + { + if(soc_device_match(rtk_soc_hank)) { + rtkemmc_writel((readl(emmc_port->emmc_membase + EMMC_CKGEN_CTL)|0x70000), + emmc_port->emmc_membase + EMMC_CKGEN_CTL); //change clock to 4MHz + sync(emmc_port); + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xfffffffd), + emmc_port->crt_membase + SYS_PLL_EMMC1); + if(VP0!=0xff) + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xffffff07)|(VP0<<3), + emmc_port->crt_membase + SYS_PLL_EMMC1); + + if(VP1!=0xff) + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xffffe0ff)|(VP1<<8), + emmc_port->crt_membase + SYS_PLL_EMMC1); + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)|0x2), + emmc_port->crt_membase + SYS_PLL_EMMC1); + sync(emmc_port); + udelay(200); + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x55c), 0x1, 0x1, __func__); //wait for clear 0x255c bit 0 + rtkemmc_writel((readl(emmc_port->emmc_membase + EMMC_CKGEN_CTL)&0xfff8ffff), + emmc_port->emmc_membase + EMMC_CKGEN_CTL); //change clock to PLL + sync(emmc_port); + } + else { + u32 t1=10; //us, after phrt0 = 0 + u32 t2=3; //us, after phse setup + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xfffffffd), + emmc_port->crt_membase + SYS_PLL_EMMC1); + udelay(t1); + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)|(1<<10), + emmc_port->emmc_membase+EMMC_OTHER1); + if(VP0!=0xff) + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xffffff07)|(VP0<<3), + emmc_port->crt_membase + SYS_PLL_EMMC1); + + if(VP1!=0xff) + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xffffe0ff)|(VP1<<8), + emmc_port->crt_membase + SYS_PLL_EMMC1); + udelay(t2); + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&(~(1<<10)), + emmc_port->emmc_membase+EMMC_OTHER1); + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)|0x2), + emmc_port->crt_membase + SYS_PLL_EMMC1); + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x55c), 0x1, 0x1, __func__); + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), 0x3, 0x3, __func__); + } + rtkemmc_writeb(0x6, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x6<<24), 0x0, __func__); + } +} + +static void pll_setup(struct rtkemmc_host *emmc_port, u32 freq) +{ + u32 sscpll_icp = 1; + unsigned int tmp_val=0; + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xfffffffd), emmc_port->crt_membase + SYS_PLL_EMMC1); + udelay(10); // + + tmp_val = (readl(emmc_port->crt_membase + SYS_PLL_EMMC4) & 0x06); + rtkemmc_writel(tmp_val, emmc_port->crt_membase + SYS_PLL_EMMC4); + + tmp_val = (readl(emmc_port->crt_membase + SYS_PLL_EMMC3) & 0xffff)|(freq<<16); + rtkemmc_writel(tmp_val, emmc_port->crt_membase + SYS_PLL_EMMC3); + udelay(3); + + if(soc_device_match(rtk_soc_stark)) { + if(freq<98) + sscpll_icp = 0; + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC2)&0xfffffc1f)|(sscpll_icp<<5), + emmc_port->crt_membase + SYS_PLL_EMMC2); //f=0, rs=5 + } + + tmp_val = (readl(emmc_port->crt_membase + SYS_PLL_EMMC4) | 0x01); + rtkemmc_writel(tmp_val, emmc_port->crt_membase + SYS_PLL_EMMC4); + + udelay(60); + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)|0x2), emmc_port->crt_membase + SYS_PLL_EMMC1); + udelay(10); + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x55c), 0x1, 0x1, __func__); + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), 0x3, 0x3, __func__); + rtkemmc_writeb(0x6, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x6<<24), 0x0, __func__); +} + +static void rtkemmc_stark_set_freq(struct rtkemmc_host *emmc_port, u32 freq, u32 div_ip) +{ + pll_setup(emmc_port, freq); + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xfffffffd), emmc_port->crt_membase + SYS_PLL_EMMC1); //reset pll + udelay(6); + + switch(div_ip) { + case EMMC_CLK_DIV1: + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL) & + (~(EMMC_CRC_CLK_DIV_EN|EMMC_CLK_INV_DIV_SEL)), + emmc_port->emmc_membase+EMMC_CKGEN_CTL); //[9:8]='b00 + break; + case EMMC_CLK_DIV4: + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL) & + (~(EMMC_CRC_CLK_DIV_EN|EMMC_CLK_INV_DIV_SEL)) | + EMMC_CRC_CLK_DIV_EN|EMMC_CLK_INV_DIV_SEL, + emmc_port->emmc_membase+EMMC_CKGEN_CTL); //[9:8]='b11 + break; + case EMMC_CLK_DIV512: + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL) & + (~(EMMC_CRC_CLK_DIV_EN|EMMC_CLK_INV_DIV_SEL)) | + EMMC_CRC_CLK_DIV_EN, + emmc_port->emmc_membase+EMMC_CKGEN_CTL); //[9:8]='b01 + break; + default: + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL) & + (~(EMMC_CRC_CLK_DIV_EN|EMMC_CLK_INV_DIV_SEL)), + emmc_port->emmc_membase+EMMC_CKGEN_CTL); //[9:8]='b00 + break; + } + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL) & ~(1<<20), + emmc_port->emmc_membase+EMMC_CKGEN_CTL); + + udelay(6); + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)|0x2), emmc_port->crt_membase + SYS_PLL_EMMC1); //release reset pll + udelay(6); + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x55c), 0x1, 0x1, __func__); + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), 0x3, 0x3, __func__); + rtkemmc_writeb(0x6, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x6<<24), 0x0, __func__); + + printk(KERN_INFO "%s: div_ip=0x%08x, PLL_EMMC1=%08x, PLL_EMMC2=%08x, PLL_EMMC3=%08x, PLL_EMMC4=%08x\n", + DRIVER_NAME, + readl(emmc_port->emmc_membase + EMMC_CKGEN_CTL), + readl(emmc_port->crt_membase + SYS_PLL_EMMC1), + readl(emmc_port->crt_membase + SYS_PLL_EMMC2), + readl(emmc_port->crt_membase + SYS_PLL_EMMC3), + readl(emmc_port->crt_membase + SYS_PLL_EMMC4)); +} + +static void rtkemmc_set_freq(struct rtkemmc_host *emmc_port, u32 freq, u32 div_ip) +{ + u32 tmp_val=0; + unsigned long flags; + + spin_lock_irqsave(&emmc_port->lock,flags); + + tmp_val = (readl(emmc_port->crt_membase + SYS_PLL_EMMC4) & 0x06); + rtkemmc_writel(tmp_val, emmc_port->crt_membase + SYS_PLL_EMMC4); + isb(); + sync(emmc_port); + + tmp_val = (readl(emmc_port->crt_membase + SYS_PLL_EMMC3) & 0xffff)|(freq<<16); + rtkemmc_writel(tmp_val, emmc_port->crt_membase + SYS_PLL_EMMC3); + isb(); + sync(emmc_port); + + tmp_val = (readl(emmc_port->crt_membase + SYS_PLL_EMMC4) | 0x01); + rtkemmc_writel(tmp_val, emmc_port->crt_membase + SYS_PLL_EMMC4); + isb(); + sync(emmc_port); + + udelay(100); //wait clock stable after crt reset + rtkemmc_dump_register(emmc_port); + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)&0xfffffffd), emmc_port->crt_membase + SYS_PLL_EMMC1); //reset pll + sync(emmc_port); + + clk_disable_unprepare(emmc_port->clk_en_emmc); + clk_disable_unprepare(emmc_port->clk_en_emmc_ip); + sync(emmc_port); + + reset_control_assert(emmc_port->rstc_emmc); + sync(emmc_port); + + udelay(3); + + reset_control_deassert(emmc_port->rstc_emmc); + sync(emmc_port); + + clk_prepare_enable(emmc_port->clk_en_emmc); + clk_prepare_enable(emmc_port->clk_en_emmc_ip); + sync(emmc_port); + + udelay(3); + + rtkemmc_restore_register(emmc_port); + + if(div_ip!=0) { + rtkemmc_writel(((readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL) & + EMMC_CRC_CLK_DIV_MASK) | div_ip) | EMMC_CRC_CLK_DIV_EN, + emmc_port->emmc_membase+EMMC_CKGEN_CTL); //set the enable bit + } + + rtkemmc_writel((readl(emmc_port->crt_membase + SYS_PLL_EMMC1)|0x2), emmc_port->crt_membase + SYS_PLL_EMMC1); //release reset pll + sync(emmc_port); + + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x55c), 0x1, 0x1, __func__); //wait for clear 0x255c bit + udelay(100); + + rtkemmc_restore_l4_register(emmc_port); + + printk(KERN_ERR "%s: emmc_port->emmc_membase+EMMC_CKGEN_CTL = 0x%x\n",__func__, readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL)); + spin_unlock_irqrestore(&emmc_port->lock, flags); + + printk(KERN_INFO "%s: div_ip=0x%08x, PLL_EMMC1=%08x, PLL_EMMC2=%08x, PLL_EMMC3=%08x, PLL_EMMC4=%08x\n", + DRIVER_NAME, + readl(emmc_port->emmc_membase + EMMC_CKGEN_CTL), + readl(emmc_port->crt_membase + SYS_PLL_EMMC1), + readl(emmc_port->crt_membase + SYS_PLL_EMMC2), + readl(emmc_port->crt_membase + SYS_PLL_EMMC3), + readl(emmc_port->crt_membase + SYS_PLL_EMMC4)); +} + +static void rtkemmc_set_pin_mux(struct rtkemmc_host *emmc_port) +{ + MMCPRINTF("rtkemmc_set_pin_mux \n"); + + rtkemmc_writel((readl(emmc_port->mux_mis_membase)&0xff000000)|0x00aaaaaa, emmc_port->mux_mis_membase); //pad mux + sync(emmc_port); +} + +#if 0 +static int rtk_gic_peek_irq(struct rtkemmc_host *emmc_port, u32 irq_num, u32 offset) +{ + u32 hw_irq = irq_num + 32; //0-31 is occuppied by system + u32 mask = 1 << (hw_irq % 32); + + return !!(readl_relaxed(emmc_port->gicd_membase + offset + (hw_irq / 32) * 4) & mask); +} +#endif + +static void rtkemmc_timeout_timer(struct timer_list *t) +{ + struct rtkemmc_host *emmc_port = from_timer(emmc_port, t, timer); + unsigned long flags; + + pr_err("cpuid=%d, opcode=%d, rtkemmc_timeout_timer fired ...\n", + raw_smp_processor_id(), emmc_port->cmd_opcode); +#if 0 + printk(KERN_ERR "emmc irq %d status: IsPender=%d, IsActiver=%d, IsEnabler=%d\n", + emmc_port->irq_num+32, + rtk_gic_peek_irq(emmc_port, emmc_port->irq_num, 0x0200), + rtk_gic_peek_irq(emmc_port, emmc_port->irq_num, 0x0300), + rtk_gic_peek_irq(emmc_port, emmc_port->irq_num, 0x0100)); +#endif +#ifdef RTKEMMC_PHASE_TRACE + if(g_bTuning==1) { + pr_err("trace_cur_tuning_cmd = %d, trace_index=%d, trace_phase_bitmap=0x%x, trace_dqs_index=%d\n", + trace_cur_tuning_cmd, trace_index, trace_phase_bitmap, trace_dqs_index); + pr_err("last tuning err status=0x%x, last tuning normal status=0x%x, last tuning auto err status=0x%x\n", + trace_err_status, trace_normal_status, trace_auto_err_status); + pr_err("%s: trace_TX_window=0x%x, trace_RX_window=0x%x, trace_TX1_window=0x%x\n", + __func__, trace_TX_window, trace_RX_window, trace_TX1_window); + } +#endif + + MMCPRINTF("%s - int_wait=%08x\n", __func__, emmc_port->int_waiting); + + spin_lock_irqsave(&emmc_port->lock,flags); + if(emmc_port->int_waiting) + { + pr_err("%s: before clear signal interrupt\n", __func__); + pr_err("%s: 0x98012038 NORMAL INTERRUPT SIGNAL EN= 0x%x\n", __func__, readw(emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R)); + pr_err("%s: 0x9801203a ERROR INTERRUPT SIGNAL EN = 0x%x\n", __func__, readw(emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R)); + + rtkemmc_hold_int_dec(); + rtkemmc_get_int_sta(&emmc_port->normal_interrupt, &emmc_port->error_interrupt, &emmc_port->auto_error_interrupt); + sync(emmc_port); + pr_err("%s: normal_interrupt =%08x, error_interrupt=0x%08x, auto_error_interrupt=0x%08x\n", + __func__, emmc_port->normal_interrupt, emmc_port->error_interrupt, emmc_port->auto_error_interrupt); + + print_ip_desc(emmc_port); + print_reg_info(emmc_port); + } + else { + WARN_ON(1); + } + + if(emmc_port->int_waiting) + complete(emmc_port->int_waiting); + + spin_unlock_irqrestore(&emmc_port->lock, flags); +} + +static void rtkemmc_interrupt_err_query(u16 intmask, int *cmd_error, int *data_error) +{ + if (intmask & (EMMC_CMD_IDX_ERR | EMMC_CMD_END_BIT_ERR | EMMC_CMD_CRC_ERR)) + *cmd_error = -EILSEQ; + else if (intmask & EMMC_CMD_TOUT_ERR) + *cmd_error = -ETIMEDOUT; + else + *cmd_error = 0; + + if (intmask & (EMMC_DATA_END_BIT_ERR | EMMC_DATA_CRC_ERR)) + *data_error = -EILSEQ; + else if (intmask & EMMC_DATA_TOUT_ERR) + *data_error = -ETIMEDOUT; + else if (intmask & EMMC_ADMA_ERR) + *data_error = -EIO; + else + *data_error = 0; +} + +static irqreturn_t rtkemmc_irq(int irq, void *dev) +{ + struct rtkemmc_host *emmc_port = dev; + struct cqhci_host *cq_host = NULL; + int cmd_error=0, data_error=0; + + if(emmc_port->cmdq==1) + cq_host = emmc_port->mmc->cqe_private; + + + rtkemmc_get_int_sta(&emmc_port->normal_interrupt, &emmc_port->error_interrupt, &emmc_port->auto_error_interrupt); + sync(emmc_port); + + if(emmc_port->cmdq==1) { + if(emmc_port->mmc->cqe_on==false && cq_host->activated==false) + rtkemmc_hold_int_dec(); + } else { + rtkemmc_hold_int_dec(); + } + + if(emmc_port->cmdq==1 && emmc_port->mmc->cqe_on==true && cq_host->activated==true) { //if we run the cmdq mode currently + if(emmc_port->normal_interrupt&0x8000) { + pr_err("%s: cmdq error case: cpuid=%d, normal_interrupt =%08x, error_interrupt=0x%08x, EMMC_CQIS=0x%x, EMMC_CQTCN=0x%x\n", + __func__, raw_smp_processor_id(), emmc_port->normal_interrupt, emmc_port->error_interrupt, + readl(emmc_port->cq_host->mmio+CQHCI_IS), readl(emmc_port->cq_host->mmio+CQHCI_TCN)); + rtkemmc_interrupt_err_query(emmc_port->error_interrupt, &cmd_error, &data_error); + + rtkemmc_cqhci_dumpregs(emmc_port->cq_host); + print_ip_desc(emmc_port); + print_reg_info(emmc_port); + } + cqhci_irq(emmc_port->mmc, (u32)(emmc_port->normal_interrupt), cmd_error, data_error); + rtkemmc_clr_int_sta(); //clear 0x2030 status + + return IRQ_HANDLED; + } + +#ifdef RTKEMMC_DEBUG + printk(KERN_ERR "%s_legacy: cpuid=%d, cmd_idx=%d, normal_interrupt =%08x, error_interrupt=0x%08x\n", + __func__, raw_smp_processor_id(), emmc_port->cmd_opcode, emmc_port->normal_interrupt, emmc_port->error_interrupt); +#endif + if(emmc_port->int_waiting) { + trace_mmc_rtkemmc_legacy_irq_complete(emmc_port->normal_interrupt, emmc_port->error_interrupt); + del_timer(&emmc_port->timer); + if (g_bResuming) //avoid to emit complete in rtkemmc_resume + return IRQ_HANDLED; + complete(emmc_port->int_waiting); + } + + sync(emmc_port); + + return IRQ_HANDLED; +} + +static void rtkemmc_init(struct rtkemmc_host *emmc_port) +{ + struct mmc_host *host=emmc_port->mmc; + unsigned long flags; + + MMCPRINTF("%s : \n", __func__); + +#ifdef PHASE_INHERITED + if (emmc_port->tx_phase == 0xff && emmc_port->rx_phase==0xff){ + HS200_TX = emmc_port->tx_phase = (readl(emmc_port->crt_membase + SYS_PLL_EMMC1) & 0x000000f8) >> 3; + HS200_RX = emmc_port->rx_phase = (readl(emmc_port->crt_membase + SYS_PLL_EMMC1) & 0x00001f00) >> 8; + } + +#endif + if(emmc_port->tx_user_defined) { //if we set user defined tx and rx value, then we won't use the bootcode reference value, always the first priority + HS200_TX = emmc_port->tx_phase = emmc_port->tx_reference_phase; + } + if(emmc_port->rx_user_defined) { + HS200_RX = emmc_port->rx_phase = emmc_port->rx_reference_phase; + } + +#ifdef DQS_INHERITED + if (emmc_port->dqs == 0xff) + emmc_port->dqs = readl(emmc_port->emmc_membase + EMMC_DQS_CTRL1); +#endif + rtkemmc_writel(3, emmc_port->crt_membase + SYS_PLL_EMMC1); //980001f0 + + rtkemmc_reset_fifo(emmc_port); + + isb(); + sync(emmc_port); + + rtkemmc_writeb(0x07, emmc_port->emmc_membase + EMMC_SW_RST_R); //9801202f, Software Reset Register + isb(); + sync(emmc_port); + + rtkemmc_writeb(0x0e, emmc_port->emmc_membase + EMMC_TOUT_CTRL_R); //9801202e, Timeout Control register + isb(); + sync(emmc_port); + + rtkemmc_writew(0x200, emmc_port->emmc_membase + EMMC_BLOCKSIZE_R); //98012004, block size = 512Byte + isb(); + sync(emmc_port); + + rtkemmc_writew(0x1008 ,emmc_port->emmc_membase + EMMC_HOST_CTRL2_R); + isb(); + sync(emmc_port); + + rtkemmc_writew(0xfeff, emmc_port->emmc_membase+EMMC_NORMAL_INT_STAT_EN_R); //98012034, enable all Normal Interrupt Status register + isb(); + sync(emmc_port); + + rtkemmc_writew(EMMC_ALL_ERR_STAT_EN, emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_EN_R); //98012036, enable all error Interrupt Status register + isb(); + sync(emmc_port); + + rtkemmc_writew(0xfeff,emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R); //98012038, enable all Normal SIGNAL Interrupt register + isb(); + sync(emmc_port); + + rtkemmc_writew(EMMC_ALL_ERR_SIGNAL_EN,emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R); //9801203a, enable all error SIGNAL Interrupt register + isb(); + sync(emmc_port); + + rtkemmc_writeb(0x0d, emmc_port->emmc_membase + EMMC_CTRL_R); //9801202f, choose is card emmc bit + isb(); + sync(emmc_port); + + if(soc_device_match(rtk_soc_hank_a00)) { //in hank A00, cannot enable L4 gated in low speed + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)|0x1, emmc_port->emmc_membase+EMMC_OTHER1); //disable L4 gated + } + else { + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)&0xfffffffa, emmc_port->emmc_membase+EMMC_OTHER1); //enable L4 gated + } + + isb(); + sync(emmc_port); + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_DUMMY_SYS)|(EMMC_CLK_O_ICG_EN|EMMC_CARD_STOP_ENABLE), emmc_port->emmc_membase+EMMC_DUMMY_SYS); //enable eMMC command clock + isb(); + sync(emmc_port); + + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R)&0xe7)|(EMMC_ADMA2_32<emmc_membase + EMMC_HOST_CTRL1_R); //ADMA2 32 bit select + isb(); + sync(emmc_port); + + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_MSHC_CTRL_R) & (~EMMC_CMD_CONFLICT_CHECK)), emmc_port->emmc_membase + EMMC_MSHC_CTRL_R); //disable emmc cmd conflict checkout + if(soc_device_match(rtk_soc_stark) || soc_device_match(rtk_soc_groot)) { + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_OTHER1)|EMMC_STARK_CARD_STOP_ENABLE, + emmc_port->emmc_membase+EMMC_OTHER1); + } + + isb(); + sync(emmc_port); + + rtkemmc_writew(readw(emmc_port->emmc_membase + EMMC_CLK_CTRL_R)|0x1, emmc_port->emmc_membase + EMMC_CLK_CTRL_R); //enable internal clock + isb(); + sync(emmc_port); + + rtkemmc_writel(0x1, emmc_port->m2tmx_membase+EMMC_NAND_DMA_SEL); // #sram_ctrl, 0 for nf, 1 for emmc + isb(); + sync(emmc_port); + + rtkemmc_writel(readl(emmc_port->emmc_membase+EMMC_AHB)|0x4,emmc_port->emmc_membase+EMMC_AHB); + spin_lock_irqsave(&emmc_port->lock,flags); + //initially set bus width 1 + rtkemmc_writeb((readb(emmc_port->emmc_membase + EMMC_HOST_CTRL1_R)&0xdd)|EMMC_BUS_WIDTH_1,emmc_port->emmc_membase + EMMC_HOST_CTRL1_R); + sync(emmc_port); + spin_unlock_irqrestore(&emmc_port->lock, flags); + + rtkemmc_set_pad_driving(emmc_port, 0x0, 0x0, 0x0, 0x0); + + + //initially, we do not use pass tuning result from bootcode, so we need to reset the tx ,rx phase to 0 first, + //and then framework call rtkemmc_tuning will set the rx tx register + //Now, we use the mechanism and hold this part for fear that user will use kernel tuning one day in the future + //if we use tuning inherit, the phase will be set to 0 and restore the tx rx from bootcode + phase(emmc_port, 0, 0); //VP0, VP1 phase + + rtkemmc_reset_fifo(emmc_port); + + if(soc_device_match(rtk_soc_hank)) + rtkemmc_set_freq(emmc_port,0x46, 0x80); //80Mhz + else + rtkemmc_stark_set_freq(emmc_port,0xa6, EMMC_CLK_DIV512); //80Mhz + sync(emmc_port); + host->ops = &rtkemmc_ops; +} + +static int rtkemmc_set_rspparam(struct rtkemmc_host *emmc_port, struct sd_cmd_pkt *cmd_info) +{ + switch(cmd_info->cmd->opcode) + { + case MMC_GO_IDLE_STATE: + cmd_info->cmd_para = (EMMC_NO_RESP); + cmd_info->rsp_len = 6; + cmd_info->cmd->arg = 0x00000000; + break; + case MMC_SEND_OP_COND: + cmd_info->cmd_para = (EMMC_RESP_LEN_48); + cmd_info->cmd->arg = MMC_SECTOR_ADDR|MMC_VDD_165_195; + cmd_info->rsp_len = 6; + break; + case MMC_ALL_SEND_CID: + cmd_info->cmd_para = (EMMC_RESP_LEN_136|EMMC_CMD_CHK_RESP_CRC); + cmd_info->rsp_len = 17; + cmd_info->cmd->arg = 0x00000000; + break; + case MMC_SET_RELATIVE_ADDR: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->cmd->arg = (1<rsp_len = 6; + break; + case MMC_SEND_CSD: + case MMC_SEND_CID: + cmd_info->cmd_para = (EMMC_RESP_LEN_136|EMMC_CMD_CHK_RESP_CRC); + cmd_info->cmd->arg = (1<rsp_len = 17; + break; + case MMC_SEND_EXT_CSD: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->cmd->arg = 0; + cmd_info->rsp_len = 6; + break; + case MMC_SLEEP_AWAKE: + cmd_info->cmd_para = (EMMC_RESP_LEN_48B|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + printk(KERN_INFO "%s : cmd5 arg=0x%08x\n",__func__,cmd_info->cmd->arg); + break; + case MMC_SELECT_CARD: + printk(KERN_INFO "%s : cmd7 arg : 0x%08x\n",__func__,cmd_info->cmd->arg); + if (cmd_info->cmd->flags == (MMC_RSP_NONE | MMC_CMD_AC)) { + printk(KERN_INFO "%s : cmd7 with rsp none\n",__func__); + cmd_info->cmd_para = (EMMC_NO_RESP); + } + else { + printk(KERN_INFO "%s : cmd7 with rsp\n",__func__); + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + } + cmd_info->rsp_len = 6; + break; + case MMC_SWITCH: + cmd_info->cmd_para = (EMMC_RESP_LEN_48B|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + break; + case MMC_SEND_STATUS: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->cmd->arg = (1<rsp_len = 6; + break; + case MMC_STOP_TRANSMISSION: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|(EMMC_ABORT_CMD<<6)); + cmd_info->rsp_len = 6; + break; + case MMC_SEND_TUNING_BLOCK_HS200: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->cmd->arg = 0; + cmd_info->rsp_len = 6; + case MMC_READ_MULTIPLE_BLOCK: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + case MMC_SET_BLOCK_COUNT: + case MMC_SET_BLOCKLEN: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + break; + case MMC_WRITE_MULTIPLE_BLOCK: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + case MMC_READ_SINGLE_BLOCK: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + case MMC_WRITE_BLOCK: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + case MMC_SET_WRITE_PROT: + case MMC_CLR_WRITE_PROT: + cmd_info->cmd_para = (EMMC_RESP_LEN_48B|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + break; + case MMC_SEND_WRITE_PROT: + case MMC_SEND_WRITE_PROT_TYPE: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + case MMC_ERASE_GROUP_START: + case MMC_ERASE_GROUP_END: + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + break; + case MMC_ERASE: + cmd_info->cmd_para = (EMMC_RESP_LEN_48B|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + break; + case MMC_GEN_CMD: + if(cmd_info->cmd->arg & 0x1) { //read single block + cmd_info->cmd->arg = 0x1; + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + } + else { //write single block + cmd_info->cmd->arg = 0x0; + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + break; + } + case MMC_MANUFACTURER_CMD62: + if(emmc_port->mmc->card->cid.manfid==0x45) { + cmd_info->cmd_para = (EMMC_RESP_LEN_48B|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE); + cmd_info->rsp_len = 6; + } + else { + printk("command %d for this manufacturer is undefined in Realtek eMMC driver!!!\n", cmd_info->cmd->opcode); + cmd_info->cmd_para = 0; + cmd_info->rsp_len = 6; + } + break; + case MMC_MANUFACTURER_CMD63: + if(emmc_port->mmc->card->cid.manfid==0x45) { + cmd_info->cmd_para = (EMMC_RESP_LEN_48|EMMC_CMD_CHK_RESP_CRC|EMMC_CMD_IDX_CHK_ENABLE|EMMC_DATA); + cmd_info->rsp_len = 6; + } + else { + printk("command %d for this manufacturer is undefined in Realtek eMMC driver!!!\n", cmd_info->cmd->opcode); + cmd_info->cmd_para = 0; + cmd_info->rsp_len = 6; + } + break; + default: + printk("Realtek Unrecognized eMMC command, cmd_idx=%d !!!\n", cmd_info->cmd->opcode); + cmd_info->cmd_para = 0; + cmd_info->rsp_len = 6; + break; + } + + MMCPRINTF(KERN_INFO "%s : cmd=0x%02x rsp_len=0x%02x arg=0x%08x para=0x%08x\n","rtkemmc", cmd_info->cmd->opcode, cmd_info->rsp_len,cmd_info->cmd->arg,cmd_info->cmd_para); + return 0; +} + +static int rtkemmc_stop_transmission(struct mmc_card *card,int bIgnore) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + int err = 0; + int bMalloc=0; + struct mmc_host * mmc = card->host; + + MMCPRINTF("%s : \n", __func__); + + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + if (card == NULL) { + bMalloc=1; + card = (struct mmc_card*)kmalloc(sizeof(struct mmc_card),GFP_KERNEL); + card->host = mmc; + } + set_cmd_info(card,&cmd,&cmd_info, MMC_STOP_TRANSMISSION, 0x00, 6); + err = SD_SendCMDGetRSP(&cmd_info,bIgnore); + if (bMalloc) { + kfree(card); + card = NULL; + } + + if(err) + mmcmsg3(KERN_WARNING "%s: MMC_STOP_TRANSMISSION fail\n",DRIVER_NAME); + + return err; +} + +static int rtkemmc_wait_status(struct mmc_card *card,u8 state,u8 divider,int bIgnore) +{ + struct mmc_command cmd; + struct sd_cmd_pkt cmd_info; + unsigned long timeend; + int err, bMalloc=0; + struct mmc_host * mmc = card->host; + + MMCPRINTF("\n"); + timeend = jiffies + msecs_to_jiffies(100); /* wait 100ms */ + + if (card == NULL) { + bMalloc=1; + card = (struct mmc_card*)kmalloc(sizeof(struct mmc_card),GFP_KERNEL); + card->host = mmc; + } + + do { + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + set_cmd_info(card,&cmd,&cmd_info, MMC_SEND_STATUS, (card->rca)<mmc->card->cid.manfid==0x45) + XFER_flag=1; + break; + } + emmc_port->int_waiting = &rtk_emmc_wait; + /* timeout timer fire */ + timeend = jiffies + msecs_to_jiffies(msec + emmc_port->tmout); + mod_timer(&emmc_port->timer, timeend); + + if (emmc_port->int_waiting) { + rtkemmc_hold_int_dec(); + rtkemmc_clr_int_sta(); + emmc_port->int_waiting = &rtk_emmc_wait; + + if (XFER_flag==1) + rtkemmc_en_xfer_int(); //command with data, r1b case + else + rtkemmc_en_cd_int(); //command case + + if (CMD_IDX_MASK(cmd_idx)==MMC_WRITE_MULTIPLE_BLOCK || CMD_IDX_MASK(cmd_idx)==MMC_READ_MULTIPLE_BLOCK ){ + if (emmc_port->rpmb_cmd) { + rtkemmc_writew(readw(emmc_port->emmc_membase + EMMC_XFER_MODE_R) & ~(1<emmc_membase + EMMC_XFER_MODE_R); + emmc_port->rpmb_cmd = 0; + }//CMD25/18 following CMD13, never set CMD_SEND_AUTO_STOP + } + + if(CMD_IDX_MASK(cmd_idx)==MMC_SEND_TUNING_BLOCK_HS200) { + rtkemmc_writew(0x80, emmc_port->emmc_membase+EMMC_BLOCKSIZE_R); + } + else if(CMD_IDX_MASK(cmd_idx)==MMC_SEND_WRITE_PROT) { + rtkemmc_writew(0x4, emmc_port->emmc_membase+EMMC_BLOCKSIZE_R); + } + else if(CMD_IDX_MASK(cmd_idx)==MMC_SEND_WRITE_PROT_TYPE) { + rtkemmc_writew(0x8, emmc_port->emmc_membase+EMMC_BLOCKSIZE_R); + } + else { + rtkemmc_writew(0x200, emmc_port->emmc_membase+EMMC_BLOCKSIZE_R); + } + //cmd fire + spin_lock_irqsave(&emmc_port->lock,flags); + reg_blksize = readw(emmc_port->emmc_membase+EMMC_BLOCKSIZE_R); + reg_blkcount = readw(emmc_port->emmc_membase+EMMC_BLOCKCOUNT_R); + reg_argu = readl(emmc_port->emmc_membase+EMMC_ARGUMENT_R); + + trace_mmc_rtkemmc_legacy_cmd(reg_blksize, reg_blkcount, CMD_IDX_MASK(cmd_idx), reg_argu); + + rtkemmc_writew(cmd_idx,emmc_port->emmc_membase+EMMC_CMD_R); + reg_cmdidx = readw(emmc_port->emmc_membase+EMMC_CMD_R); + spin_unlock_irqrestore(&emmc_port->lock,flags); + wait_for_completion(emmc_port->int_waiting); + + if(XFER_flag==1) { //cmd with data + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_R), 0x2, 0x2, __func__); + } + else{ + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + EMMC_NORMAL_INT_STAT_R), 0x1, 0x1, __func__); + } + if (emmc_port->normal_interrupt & EMMC_ERR_INTERRUPT) { + if (!ignore_log) { + if (CMD_IDX_MASK(cmd_idx)!=MMC_GO_IDLE_STATE) { + pr_err("0x98012004 EMMC BLOCK SIZE = 0x%x\n",reg_blksize); + pr_err("0x98012006 EMMC BLOCK COUNT = 0x%08x\n", reg_blkcount); + pr_err("0x98012008 EMMC CMDARG = 0x%08x\n", reg_argu); + pr_err("0x9801200e EMMC CMD REG = 0x%08x\n", reg_cmdidx); + print_err_reg(cmd_idx, emmc_port->normal_interrupt, emmc_port->error_interrupt); + print_ip_desc(emmc_port); + print_reg_info(emmc_port); + } + } + else{ //in tuning, only print rintsts +#ifdef RTKEMMC_DEBUG + pr_err("Tuning error case!!!\n"); +#endif + } + + err = RTK_FAIL; + } + } + return err; +} + +static void make_sg_des(struct sd_cmd_pkt *cmd_info, u32 p_des_base, struct rtkemmc_host *emmc_port, + struct scatterlist *sg, u32 dma_nents) +{ + u32 blk_cnt; + u32 blk_cnt2; + u32 remain_blk_cnt; + u32 tmp_val; + u32* des_base = emmc_port->desc_vaddr ; + u32 dma_leng = 0; + u32 dma_addr; + u32 i; + unsigned int b1, b2; + +#ifdef RTKEMMC_PHASE_TRACE + trace_desc_counter = 0; +#endif + for(i=0; i>9; + } + + remain_blk_cnt = blk_cnt; + dma_addr = sg_dma_address(sg); + + while(remain_blk_cnt) { + /* setting des1; buffer size in byte */ + if(remain_blk_cnt > EMMC_MAX_SCRIPT_BLK) + blk_cnt2 = EMMC_MAX_SCRIPT_BLK; + else + blk_cnt2 = remain_blk_cnt; + + //boundary check + b1 = dma_addr / 0x8000000; //this eMMC ip dma transfer has 128MB limitation + b2 = (dma_addr+blk_cnt2*512) / 0x8000000; + if(b1 != b2) { + blk_cnt2 = (b2*0x8000000-dma_addr) / 512; + } + + if(dma_leng<512) tmp_val = ((dma_leng)<<16)|0x21; + else tmp_val = ((blk_cnt2&0x7f)<<25)|0x21; + + if((i==(dma_nents-1)) && (remain_blk_cnt == blk_cnt2)) + tmp_val |= 0x2; + + des_base[0] = tmp_val; + des_base[1] = dma_addr; + + isb(); + sync(emmc_port); + + dma_addr = dma_addr+(blk_cnt2<<9); + remain_blk_cnt -= blk_cnt2; + des_base += 2; + + isb(); + sync(emmc_port); +#ifdef RTKEMMC_PHASE_TRACE + trace_desc_counter += 2; +#endif + } + } + + wmb(); + sync(emmc_port); +} + +static void make_ip_des(u32 dma_addr, u32 dma_length, u32 p_des_base, struct rtkemmc_host *emmc_port) +{ + u32 blk_cnt; + u32 blk_cnt2; + u32 remain_blk_cnt; + u32 tmp_val; + u32* des_base = emmc_port->desc_vaddr ; + unsigned int b1, b2; + + isb(); + sync(emmc_port); + + MMCPRINTF("RTKEMMC: des_base = 0x%08x\n", des_base); + //blk_cnt must be the multiple of 512(0x200) + if(dma_length<512) { + blk_cnt = 1; + } + else{ + blk_cnt = dma_length>>9; + } + remain_blk_cnt = blk_cnt; + + isb(); + sync(emmc_port); +#ifdef RTKEMMC_PHASE_TRACE + trace_desc_counter = 0; +#endif + + while(remain_blk_cnt) { + /* setting des1; buffer size in byte */ + if(remain_blk_cnt > EMMC_MAX_SCRIPT_BLK) + blk_cnt2 = EMMC_MAX_SCRIPT_BLK; + else + blk_cnt2 = remain_blk_cnt; + + //boundary check + b1 = dma_addr / 0x8000000; //this eMMC ip dma transfer has 128MB limitation + b2 = (dma_addr+blk_cnt2*512) / 0x8000000; + if(b1 != b2) { + blk_cnt2 = (b2*0x8000000-dma_addr) / 512; + } + + if(dma_length<512) tmp_val = ((dma_length)<<16)|0x21; + else tmp_val = ((blk_cnt2&0x7f)<<25)|0x21; + + if(remain_blk_cnt == blk_cnt2) + tmp_val |= 0x2; + + des_base[0] = tmp_val; + des_base[1] = dma_addr; + + isb(); + sync(emmc_port); + + MMCPRINTF("%s - remain cnt : 0x%08x, desc[0]=0x%08x, desc[1]=0x%08x\n", + __func__, remain_blk_cnt,des_base[0],des_base[1]); + + dma_addr = dma_addr+(blk_cnt2<<9); + remain_blk_cnt -= blk_cnt2; + des_base += 2; + isb(); + sync(emmc_port); +#ifdef RTKEMMC_PHASE_TRACE + trace_desc_counter +=2; +#endif + } + + wmb(); + sync(emmc_port); +} + +static void rtkemmc_read_rsp(struct rtkemmc_host *emmc_port,u32 *rsp, int reg_count) +{ + MMCPRINTF("rsp addr=0x%p; rsp_count=%u\n", rsp, reg_count); + if ( reg_count==6 ){ + rsp[0] = rsp[1] = 0; + rsp[0] = readl(emmc_port->emmc_membase + EMMC_RESP01_R); + MMCPRINTF(KERN_INFO "rsp[0]=0x%08x, rsp[1]=0x%08x\n",rsp[0],rsp[1]); + }else if(reg_count==17){ + /*1. UNSTUFF_BITS uses the reverse order as: const int __off = 3 - ((start) / 32); + 2. be32_to_cpu is called in mmc_send_csd as csd[i] = be32_to_cpu(csd_tmp[i]);*/ + //in hank eMMC IP, we neeed to rearrange response in 17 bytes case because they save 8-135 bit instead of 0-127 bit + u32 rsp_tmp[4]={0}; + rsp_tmp[3] = readl(emmc_port->emmc_membase + EMMC_RESP01_R); + rsp_tmp[2] = readl(emmc_port->emmc_membase + EMMC_RESP23_R); + rsp_tmp[1] = readl(emmc_port->emmc_membase + EMMC_RESP45_R); + rsp_tmp[0] = readl(emmc_port->emmc_membase + EMMC_RESP67_R); + rsp[3] = (rsp_tmp[3]&0x00ffffff)<<8; + rsp[2] = ((rsp_tmp[2]&0x00ffffff)<<8) | ((rsp_tmp[3]&0xff000000)>>24); + rsp[1] = ((rsp_tmp[1]&0x00ffffff)<<8) | ((rsp_tmp[2]&0xff000000)>>24); + rsp[0] = ((rsp_tmp[0]&0x00ffffff)<<8) | ((rsp_tmp[1]&0xff000000)>>24); + MMCPRINTF(KERN_INFO "rsp[0]=0x%08x, rsp[1]=0x%08x, rsp[2]=0x%08x, rsp[3]=0x%08x\n",rsp[0],rsp[1],rsp[2],rsp[3]); + } + else + MMCPRINTF("rsp[0]=0x%08x\n",rsp[0]); +} + +static int SD_SendCMDGetRSP(struct sd_cmd_pkt *cmd_info,int bIgnore) +{ + volatile u8 cmd_idx = cmd_info->cmd->opcode; + u32 *rsp = (u32 *)&cmd_info->cmd->resp; + struct rtkemmc_host *emmc_port = cmd_info->emmc_port; + int err;//, retry_count=0; + int rty_cnt =0; + +// wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + EMMC_PSTATE_REG), 0x3, 0x0, __func__); + +SD_SendCMDGetRSP_Cmd_RETRY: + rtkemmc_set_rspparam(emmc_port,cmd_info); //for 1295 + if(rsp == NULL) + BUG_ON(1); + + rtkemmc_writel(cmd_info->cmd->arg, emmc_port->emmc_membase + EMMC_ARGUMENT_R); + isb(); + sync(emmc_port); + + rtkemmc_writew(0, emmc_port->emmc_membase + EMMC_XFER_MODE_R); + + emmc_port->cmd_opcode = cmd_idx; + if (cmd_idx == MMC_SET_BLOCK_COUNT) + emmc_port->rpmb_cmd = 1; + else + emmc_port->rpmb_cmd = 0; + err = rtkemmc_wait_opt_end(emmc_port,((cmd_idx<<8)|cmd_info->cmd_para),bIgnore); + if(err == RTK_SUCC){ + sync(emmc_port); + rtkemmc_read_rsp(emmc_port,rsp, cmd_info->rsp_len); + sync(emmc_port); +#if 0 + printk(KERN_INFO "%s: rsp[0]=0x%x, rsp[1]=0x%x, rsp[2]=0x%x, rsp[3]=0x%x\n",__func__, rsp[0], rsp[1], rsp[2], rsp[3]); +#endif + } + else { + if(!bIgnore) { + pr_err("SD_SendCMDGetRSP_Cmd error...\n"); + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_AUTO_CMD_ERR|EMMC_CMD_IDX_ERR|EMMC_CMD_END_BIT_ERR|EMMC_CMD_CRC_ERR|EMMC_CMD_TOUT_ERR))!=0){ //check cmd line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "CMD Line error occurs \n"); +#endif + rtkemmc_writeb(0x2, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x2<<24), 0x0, __func__); //wait for clear 0x2f bit 1 + } + if((readw(emmc_port->emmc_membase + EMMC_ERROR_INT_STAT_R)& + (EMMC_ADMA_ERR|EMMC_DATA_END_BIT_ERR|EMMC_DATA_CRC_ERR|EMMC_DATA_TOUT_ERR)) !=0){ //check data line +#ifdef RTKEMMC_DEBUG + printk(KERN_INFO "DAT Line error occurs \n"); +#endif + rtkemmc_writeb(0x4, emmc_port->emmc_membase + EMMC_SW_RST_R); //Perform a software reset + wait_done_timeout(emmc_port, (u32*)(emmc_port->emmc_membase + 0x2c), (0x4<<24), 0x0, __func__); //wait for clear 0x2f bit 2 + } + if((rty_cnt++)<10) + goto SD_SendCMDGetRSP_Cmd_RETRY; + } + } + return err; +} + +static int SD_Stream(struct sd_cmd_pkt *cmd_info, unsigned int bIgnore) +{ + u8 cmd_idx = cmd_info->cmd->opcode; + u32 *rsp = (u32 *)&cmd_info->cmd->resp; + u16 block_count = cmd_info->block_count; + u8 *data = cmd_info->dma_buffer; + + int err = 0; + int read_flag=1; + int mul_blk_flag=0; + int auto_stop_flag=0; + int rty_cnt=0; + + struct scatterlist *sg; + u32 dma_nents = 0; + u32 dir = 0; + + struct mmc_host *host; + struct rtkemmc_host *emmc_port = cmd_info->emmc_port; + if(emmc_port==NULL) { + pr_err("emmc_port == NULL\n"); + BUG_ON(1); + } + host = emmc_port->mmc; + + if(rsp == NULL) + BUG_ON(1); + + if(cmd_info->data) + { /*command issued from MMC framework case*/ + cmd_info->data->bytes_xfered=0; + + if(cmd_info->data->flags & MMC_DATA_READ) + dir = DMA_FROM_DEVICE; + else + dir = DMA_TO_DEVICE; + + dma_nents = dma_map_sg( mmc_dev(host), cmd_info->data->sg, cmd_info->data->sg_len, dir); + sg = cmd_info->data->sg; + + make_sg_des(cmd_info, emmc_port->desc_paddr, emmc_port, sg, dma_nents); + } + else if(data) + { + /*command issued by Realtek host driver*/ + if(cmd_idx == MMC_SEND_TUNING_BLOCK_HS200) + make_ip_des(emmc_port->dma_paddr, 0x80, emmc_port->desc_paddr, emmc_port); + else if(cmd_idx==MMC_SEND_WRITE_PROT) + make_ip_des(emmc_port->dma_paddr, 0x4, emmc_port->desc_paddr, emmc_port); + else if(cmd_idx==MMC_SEND_WRITE_PROT_TYPE) + make_ip_des(emmc_port->dma_paddr, 0x8, emmc_port->desc_paddr, emmc_port); + else + make_ip_des(emmc_port->dma_paddr, block_count<<9, emmc_port->desc_paddr, emmc_port); + } + else + BUG_ON(1); + +SD_Stream_Cmd_RETRY: + rtkemmc_set_rspparam(emmc_port,cmd_info); //for 119x + + /*************************************************************************/ + rtkemmc_writel(readl(emmc_port->iso_blk_membase + EMMC_SWC_SEL)|0x10, emmc_port->iso_blk_membase + EMMC_SWC_SEL); + rtkemmc_writel(readl(emmc_port->iso_blk_membase + EMMC_SWC_SEL1)&0xffffffef, emmc_port->iso_blk_membase + EMMC_SWC_SEL1); + rtkemmc_writel(readl(emmc_port->iso_blk_membase + EMMC_SWC_SEL2)|0x10, emmc_port->iso_blk_membase + EMMC_SWC_SEL2); + rtkemmc_writel(readl(emmc_port->iso_blk_membase + EMMC_SWC_SEL3)&0xffffffef, emmc_port->iso_blk_membase + EMMC_SWC_SEL3); + rtkemmc_writel(0, emmc_port->emmc_membase + EMMC_CP); + /*************************************************************************/ + rtkemmc_writew(block_count, emmc_port->emmc_membase + EMMC_BLOCKCOUNT_R); + rtkemmc_writel(emmc_port->desc_paddr, emmc_port->emmc_membase + EMMC_ADMA_SA_LOW_R); + + rtkemmc_writel(cmd_info->cmd->arg, emmc_port->emmc_membase + EMMC_ARGUMENT_R); + + if(cmd_idx==MMC_WRITE_BLOCK || cmd_idx==MMC_WRITE_MULTIPLE_BLOCK || cmd_idx==MMC_LOCK_UNLOCK + ||cmd_idx==47 || cmd_idx==49 || (cmd_idx==MMC_GEN_CMD && cmd_info->cmd->arg==0)) + read_flag=0; + + if(cmd_idx==MMC_WRITE_MULTIPLE_BLOCK || cmd_idx==MMC_READ_MULTIPLE_BLOCK) { + mul_blk_flag=1; + auto_stop_flag=1; + } + + rtkemmc_writew((mul_blk_flag<emmc_membase + EMMC_XFER_MODE_R); + isb(); + sync(emmc_port); + + emmc_port->cmd_opcode = cmd_idx; + + rtkemmc_get_cmd_timeout(cmd_info); + isb(); + sync(emmc_port); + err = rtkemmc_wait_opt_end(emmc_port,((cmd_idx<<8)|cmd_info->cmd_para),bIgnore); + isb(); + sync(emmc_port); + + if(err == RTK_SUCC) { + rtkemmc_read_rsp(emmc_port,rsp, cmd_info->rsp_len); + if(cmd_info->data) + cmd_info->data->bytes_xfered += (block_count << 9); + } + else { + if(!bIgnore) { + pr_err("SD_Stream_Cmd error...\n"); + error_handling(emmc_port); + if((rty_cnt++)<10) + goto SD_Stream_Cmd_RETRY; + } + } + + if(cmd_info->data) + dma_unmap_sg(mmc_dev(host), cmd_info->data->sg, cmd_info->data->sg_len, dir); + + return err; +} + +static void rtkemmc_send_command(struct rtkemmc_host *emmc_port, + struct mmc_command *cmd, + u8 Ignore) +{ + struct sd_cmd_pkt cmd_info; + int rc = 0; + + memset(&cmd_info, 0, sizeof(struct sd_cmd_pkt)); + + if ( !emmc_port || !cmd ){ + pr_err("%s: emmc_port or cmd is null\n",DRIVER_NAME); + return ; + } + + cmd_info.cmd = cmd; + cmd_info.emmc_port = emmc_port; + cmd_info.dma_buffer = NULL; + + if (cmd->data) { + cmd_info.data = cmd->data; + cmd_info.block_count = cmd_info.data->blocks; + cmd_info.byte_count = BYTE_CNT; + rc = SD_Stream(&cmd_info, Ignore); + } + else { + rc = SD_SendCMDGetRSP(&cmd_info, Ignore); + } + + if (rc){ + cmd->error = -MMC_BLK_CMD_ERR; + } +} + +static void read_tuning_parameter(struct rtkemmc_host *emmc_port) +{ + int hs400_data[128]={0}; //4 bytes header, 33aa, 4 bytes for TX, 4 bytes for RX, 4 bytes for dqs + int chk_sum1 = 0, chk_sum2 = 0; + unsigned int *buf; + size_t buf_size; + + buf = nvmem_cell_read(emmc_port->cell, &buf_size); + + rtkemmc_send_cmd18(emmc_port, 512, emmc_port->emmc_tuning_addr/512+1024, 0); //we put the hs400 parameter data before tuning blk addr 1 block + memcpy(hs400_data, emmc_port->dma_vaddr, 512); + + printk(KERN_ERR "read dqs_data from emmc: hs400_version=0x%x, hs400_TX=0x%x, hs400_RX=0x%x, hs400_dqs=0x%x, cmd_dly_tap=0x%x\n", + hs400_data[0], hs400_data[1], hs400_data[2], hs400_data[3], hs400_data[4]); + printk(KERN_ERR "UUID expt: [0]=0x%x, [1]=0x%x, [2]=0x%x\n", hs400_data[6], hs400_data[7], hs400_data[8]); + printk(KERN_ERR "UUID real: [0]=0x%x, [1]=0x%x, [2]=0x%x\n", buf[0], buf[1], buf[2]); + + chk_sum1 = hs400_data[0]+hs400_data[1]*2+hs400_data[2]*3+hs400_data[3]*4+hs400_data[4]*5; + chk_sum2 = HS400_VERSION+hs400_data[1]*2+hs400_data[2]*3+hs400_data[3]*4+hs400_data[4]*5; + + if(chk_sum1==chk_sum2 && hs400_data[5]==chk_sum2 && + buf[0]==hs400_data[6] && buf[1]==hs400_data[7] && + buf[2]==hs400_data[8]) { //inherit from emmc saved data instead of bootcode + emmc_port->dqs_tuning=0; + emmc_port->tx_tuning = 0; + emmc_port->rx_tuning = 0; + + HS200_TX = emmc_port->tx_phase = hs400_data[1]; + HS200_RX = emmc_port->rx_phase = hs400_data[2]; + emmc_port->dqs = hs400_data[3]; + emmc_port->cmd_dly_tap = hs400_data[4]; + + if(emmc_port->tx_user_defined) { //if we set user defined tx and rx value, then we won't use the bootcode reference value, always the first priority + printk(KERN_ERR "tx_user_defined has been set, we still use user define value for usage\n"); + HS200_TX = emmc_port->tx_phase = emmc_port->tx_reference_phase; + } + if(emmc_port->rx_user_defined) { + printk(KERN_ERR "rx_user_defined has been set, we still use user define value for usage\n"); + HS200_RX = emmc_port->rx_phase = emmc_port->rx_reference_phase; + } + } + kfree(buf); +} + +static int rtkemmc_hs400_prepare_ddr(struct mmc_host *host) +{ + if(!host->card) + pr_err("%s: host->card==NULL\n", __func__); + /* in realtek chip, some emmc hs400 mode needs to strengthen the device ability */ + else if(host->card->ext_csd.raw_driver_strength & 0x2) + host->card->drive_strength = 0x1; + printk(KERN_ERR "%s: card->ext_csd.raw_driver_strength=%x\n", + __func__, host->card->ext_csd.raw_driver_strength); + + return 0; +} + +static void rtkemmc_init_card(struct mmc_host *host, struct mmc_card *card) +{ + host->card = card; +} + +static void rtkemmc_request(struct mmc_host *host, struct mmc_request *mrq) +{ + struct rtkemmc_host *emmc_port; + int ret = 0; + + emmc_port = mmc_priv(host); + BUG_ON(emmc_port->mrq != NULL); + + down_write(&emmc_port->cr_rw_sem); + if(emmc_port->cmdq==1) + { + if(host->cqe_on==false && emmc_port->cq_host->activated==true + && emmc_port->switch_partition==0) + cqhci_deactivate(host); + + if(mrq->cmd->opcode==MMC_SWITCH && mrq->cmd->arg==CMDQ_DISABLED) + emmc_port->switch_partition = 1; + + /* we do not need to disable cmdq if it is rpmb request + because rpmb has been changed to rpmb partition in block.c + Also, we do not need to disable cmdq if this command is disable/enable cmdq*/ + if(host->card && host->card->ext_csd.cmdq_en==1 + && emmc_port->switch_partition==0) { + ret = rtkemmc_blk_cmdq_switch(host->card, false); + if(mrq->cmd->opcode==MMC_SLEEP_AWAKE || + (mrq->cmd->opcode==MMC_SELECT_CARD && mrq->cmd->arg==0x0) || + (mrq->cmd->opcode==MMC_SWITCH && mrq->cmd->arg==0x03220301)) { + emmc_port->cmdq_reenable=0; + } + else + emmc_port->cmdq_reenable=1; + if (ret) { + pr_err("%s: disable cmdq failed !\n", __func__); + } + } + + if(mrq->cmd->opcode==MMC_SWITCH && mrq->cmd->arg==CMDQ_ENABLED) + emmc_port->switch_partition = 0; + } + + //emmc_port->cmdq_reenable=1 means curretnly we run under cmdq mode, but disable for the time being + if(mrq->cmd->opcode==MMC_SEND_EXT_CSD && emmc_port->cmdq_reenable==0 && !emmc_port->hs400_force_tuning) + { + //====we add the following program becasue we need to read HS400 parameter in specific emmc block in SDR50 mode if exists==== + //hs400 mode case, we need to eliminate the tuning process, so we read the dqs, phase data from offset that bootcode provided + if((host->caps2 & MMC_CAP2_HS400_1_8V) && emmc_port->dqs_tuning==1 && emmc_port->emmc_tuning_addr!=0) //bootcode doesn't do the hs400 tuning + { + read_tuning_parameter(emmc_port); + } + } + + emmc_port->mrq = mrq; + if(emmc_port->time_setting==1 && mrq->cmd->opcode==MMC_SEND_STATUS) { + /* + we skip this cmd 13 because that might be a cmd CRC error + after the timing setting and before the phase setting + User should avoid sending command when the eMMC is unstable. + */ + goto skip; + } + if(emmc_port && mrq->sbc) + rtkemmc_send_command(emmc_port, mrq->sbc, 0); + + if(emmc_port && mrq->cmd) + rtkemmc_send_command(emmc_port, mrq->cmd, 0); +skip: + emmc_port->time_setting = 0; + + rtkemmc_req_end_tasklet((unsigned long)emmc_port); + + if(emmc_port->cmdq==1 && emmc_port->cmdq_reenable==1) { + if(host->card && host->card->ext_csd.cmdq_en==0) { + ret = rtkemmc_blk_cmdq_switch(host->card, true); + emmc_port->cmdq_reenable=0; + if (ret) { + pr_err("%s: switch cmdq failed !\n", __func__); + } + } + } + + up_write(&emmc_port->cr_rw_sem); +} + +static int rtkemmc_sysfs_cmdq_disable(struct rtkemmc_host *emmc_port, int *cmdq_disable) +{ + struct mmc_host *host = emmc_port->mmc; + int ret=0; + + if(emmc_port->cmdq==1) + { + if(host->cqe_on==true) + host->cqe_ops->cqe_off(host); + + if(emmc_port->cq_host->activated==true) + cqhci_deactivate(host); + + if(host->card && host->card->ext_csd.cmdq_en==1) { + ret = rtkemmc_blk_cmdq_switch(host->card, false); + printk(KERN_ERR "disable command queue mode...,DBR=0x%x, TCN=0x%x\n", + readl(emmc_port->cq_host->mmio+CQHCI_TDBR), readl(emmc_port->cq_host->mmio+CQHCI_TCN)); + (*cmdq_disable)=1; + if (ret) { + pr_err("disable cmdq failed !!!\n"); + } + } + } + + return ret; +} + +static int rtkemmc_sysfs_partition_pre(struct rtkemmc_host *emmc_port) +{ + struct mmc_host *host = emmc_port->mmc; + u8 part_config = host->card->ext_csd.part_config; + int ret=0; + + if((host->card->ext_csd.part_config&0x7)!=0) { //current partition is not uda + printk(KERN_ERR "switch to uda partition...\n"); + part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; + part_config |= 0x0; //uda partition + //switch to uda partition because of tuning process + ret = rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, + part_config, emmc_port->mmc->card->ext_csd.generic_cmd6_time); + } + + return ret; +} + +static int rtkemmc_sysfs_cmdq_enable(struct rtkemmc_host *emmc_port, int cmdq_disable) +{ + struct mmc_host *host = emmc_port->mmc; + int ret=0; + + if(emmc_port->cmdq==1) { + if(cmdq_disable==1 && host->card && host->card->ext_csd.cmdq_en==0) { + printk(KERN_ERR "re-enable command queue mode...\n"); + ret = rtkemmc_blk_cmdq_switch(host->card, true); + if (ret) { + pr_err("enable cmdq failed !!!\n"); + } + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + } + } + + return ret; +} + +static int rtkemmc_sysfs_partition_post(struct rtkemmc_host *emmc_port) +{ + struct mmc_host *host = emmc_port->mmc; + int ret=0; + + if((host->card->ext_csd.part_config&0x7)!=0) { //current partition is not uda + printk(KERN_ERR "switch back to original partition...\n"); + ret = rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, + host->card->ext_csd.part_config, emmc_port->mmc->card->ext_csd.generic_cmd6_time); + } + + return ret; +} + +static ssize_t emmc_info_dev_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mmc_host * host = dev_get_drvdata(dev); + struct rtkemmc_host *emmc_port = mmc_priv(host); + + printk(KERN_INFO "%s(%u)\n",__func__,__LINE__); + + return sprintf(buf, "EMMC SYS_PLL_EMMC1=0x%08x SYS_PLL_EMMC2=0x%08x \nSYS_PLL_EMMC3=0x%08x SYS_PLL_EMMC4=0x%08x HOST_CONTROL2_REG=0x%08x\n \ + PRESENT_STATE_REG=0x%08x HOST CONTROL1 REG=0x%08x TRANSFER_MODE_REG=0x%08x \n EMMC_CKGEN_CTL=0x%08x EMMC_DQS_CTRL1=0x%08x \n", + readl(emmc_port->crt_membase + SYS_PLL_EMMC1), + readl(emmc_port->crt_membase + SYS_PLL_EMMC2), + readl(emmc_port->crt_membase + SYS_PLL_EMMC3), + readl(emmc_port->crt_membase + SYS_PLL_EMMC4), + readw(emmc_port->emmc_membase+EMMC_HOST_CTRL2_R), + readl(emmc_port->emmc_membase+EMMC_PSTATE_REG), + readb(emmc_port->emmc_membase+EMMC_HOST_CTRL1_R), + readw(emmc_port->emmc_membase+EMMC_XFER_MODE_R), + readl(emmc_port->emmc_membase+EMMC_CKGEN_CTL), + readl(emmc_port->emmc_membase+EMMC_DQS_CTRL1)); + +} + +static ssize_t emmc_info_dev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + printk(KERN_ERR "%s(%u)Nothing to do\n",__func__,__LINE__); + + /* return value must be equare or big then "count" to finish this attribute */ + return count; +} +DEVICE_ATTR(emmc_info, S_IRUGO | S_IWUSR, + emmc_info_dev_show,emmc_info_dev_store); + +static ssize_t +tuning_info_dev_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = dev_get_drvdata(dev); + struct rtkemmc_host *emmc_port = mmc_priv(host); + ssize_t size; + int cmdq_disable=0; + int ret = 0; + + down_write(&emmc_port->cr_rw_sem); + + if(emmc_port->cmdq==1) + mmc_get_card(host->card, NULL); + + ret = rtkemmc_sysfs_cmdq_disable(emmc_port, &cmdq_disable); + if(ret!=0) + goto out; + ret = rtkemmc_sysfs_partition_pre(emmc_port); + if(ret!=0) + goto out; + + emmc_port->retune=1; + if(emmc_port->mmc->caps2 & MMC_CAP2_HS400_1_8V) { + int dqs_temp = emmc_port->dqs_tuning; + int tx_temp = emmc_port->tx_tuning; + int rx_temp = emmc_port->rx_tuning; + + emmc_port->dqs_tuning=1; + emmc_port->tx_tuning = 1; + emmc_port->rx_tuning = 1; + + rtkemmc_dqs_tuning(emmc_port->mmc); + + emmc_port->dqs_tuning=dqs_temp; + emmc_port->tx_tuning = tx_temp; + emmc_port->rx_tuning = rx_temp; + + size = sprintf(buf, "The eMMC hs400 tuning finished !!!\n"); + } + else if(emmc_port->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR) { + int tx_temp = emmc_port->tx_tuning; + int rx_temp = emmc_port->rx_tuning; + + emmc_port->tx_tuning = 1; + emmc_port->rx_tuning = 1; + + mmc_Tuning_HS200(emmc_port); + + emmc_port->tx_tuning = tx_temp; + emmc_port->rx_tuning = rx_temp; + + size = sprintf(buf, "The eMMC hs200 tuning finished !!!\n"); + } + else { + size = sprintf(buf, "This function only supports hs400 or hs200 mode !!!\n"); + } + emmc_port->retune=0; + + ret = rtkemmc_sysfs_partition_post(emmc_port); + if(ret) + goto out; + ret = rtkemmc_sysfs_cmdq_enable(emmc_port, cmdq_disable); +out: + if(ret!=0) + size = sprintf(buf, "The eMMC tuning is not finsihed !!!\n"); + + if(emmc_port->cmdq==1) + mmc_put_card(host->card, NULL); + + up_write(&emmc_port->cr_rw_sem); + + return size; +} + +static ssize_t tuning_info_dev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + printk(KERN_ERR "%s(%u)Nothing to do\n",__func__,__LINE__); + + /* return value must be equare or big then "count" to finish this attribute */ + return count; +} +DEVICE_ATTR(tuning_info, S_IRUGO | S_IWUSR, + tuning_info_dev_show, tuning_info_dev_store); + +void euda_gpp_setting(struct mmc_host *host, unsigned long size[], char type[], int gpp_num, unsigned long euda_start_addr, unsigned long euda_size) +{ + struct rtkemmc_host *emmc_port = mmc_priv(host); + + unsigned long mul[4]={0}; + unsigned long temp=0; + int idx=0; + int enhance_attr=0; + int cmdq_disable=0; + int ret; + + for(idx=0; idx<4; idx++) { + if(size[idx]==0) break; + printk(KERN_ERR "gpp%d: size=%lu, type=%c\n", idx, size[idx], type[idx]); + } + printk(KERN_ERR "gpp_num=%d, euda_start_addr=0x%lx, euda_size=%ld\n", gpp_num, euda_start_addr, euda_size); + + down_write(&emmc_port->cr_rw_sem); + + if(emmc_port->cmdq==1) + mmc_get_card(host->card, NULL); + + ret = rtkemmc_sysfs_cmdq_disable(emmc_port, &cmdq_disable); + if(ret!=0) + goto out; + + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_SANITIZE_START, 0x1, host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + + //set euda + if(euda_size !=0) { + enhance_attr |= (1<<0); + temp = euda_size; + mul[2] = (temp >> 16); + temp = temp - (mul[2]<<16); + mul[1] = (temp>>8); + temp = temp - (mul[1]<<8); + mul[0] = temp; + + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 140, mul[0], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 141, mul[1], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 142, mul[2], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + + temp = euda_start_addr; + mul[3] = (temp >> 24); + temp = temp - (mul[3]<<24); + mul[2] = (temp >> 16); + temp = temp - (mul[2]<<16); + mul[1] = (temp>>8); + temp = temp - (mul[1]<<8); + mul[0] = temp; + + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 136, mul[0], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 137, mul[1], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 138, mul[2], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, 139, mul[3], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + } + //set gpp + for(idx=0; idx> 16); + temp = temp - (mul[2]<<16); + mul[1] = (temp>>8); + temp = temp - (mul[1]<<8); + mul[0] = temp; + + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_GP_SIZE_MULT+idx*3, mul[0], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_GP_SIZE_MULT+idx*3+1, mul[1], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_GP_SIZE_MULT+idx*3+2, mul[2], host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + } + printk(KERN_ERR "enhance_attr=0x%x\n", enhance_attr); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PARTITION_ATTRIBUTE, enhance_attr, host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + rtkemmc_switch(emmc_port, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1, host->card->ext_csd.generic_cmd6_time); + rtkemmc_wait_status(host->card,STATE_TRAN,0,0); + + ret = rtkemmc_sysfs_cmdq_enable(emmc_port, cmdq_disable); +out: + if(emmc_port->cmdq==1) + mmc_put_card(host->card, NULL); + + up_write(&emmc_port->cr_rw_sem); +} +EXPORT_SYMBOL(euda_gpp_setting); + +static ssize_t gpp_info_dev_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mmc_host * host = dev_get_drvdata(dev); + struct rtkemmc_host *emmc_port = mmc_priv(host); + + printk(KERN_ERR "the gpp partition based_unit_size is hc_erase_grp_sz*hc_wp_grp_sz*512 Kbytes=%d Kbytes\n", + emmc_port->mmc->card->ext_csd.raw_hc_erase_grp_size*emmc_port->mmc->card->ext_csd.raw_hc_erase_gap_size*512); + printk(KERN_ERR "each gpp partition size = GP_X_2 * 2^16 + GP_X_1 * 2^8 + GP_X_0 * 2^0\n"); + printk(KERN_ERR "X is from 1 to the number of gpp partitions\n"); + printk(KERN_ERR "Ex. echo 8,M,4,S,0,0x80000,20 > gpp_info means to set gpp 1 8*based_unit_size and the type is MLC\n"); + printk(KERN_ERR "gpp 2 4*based_unit_size and the type is SLC\n"); + printk(KERN_ERR "set euda where the start address is 0x80000 and the size is 20*based_unit_size\n"); + printk(KERN_ERR "emmc_port->mmc->card->ext_csd.raw_hc_erase_grp_size*emmc_port->mmc->card->ext_csd.raw_hc_erase_gap_size*512\n"); + + return sprintf(buf, "hc_erase_grp_sz=0x%x, hc_wp_grp_sz=0x%x, EXT_CSD_PARTITION_SUPPORT=0x%x\n", + emmc_port->mmc->card->ext_csd.raw_hc_erase_grp_size, + emmc_port->mmc->card->ext_csd.raw_hc_erase_gap_size, + emmc_port->mmc->card->ext_csd.raw_partition_support); + +} + +static ssize_t gpp_info_dev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + char buffer[200]; + char sep[8][20]; + unsigned long size[4]={0,0,0,0}; + char type[4]; + int para_num=0; + int gpp_num=0; + char* const delim = ","; + char *token, *cur = buffer; + unsigned long euda_start_addr = 0; + unsigned long euda_size = 0; + + struct mmc_host * host = dev_get_drvdata(dev); + struct rtkemmc_host *emmc_port = mmc_priv(host); + + if(!(emmc_port->mmc->card->ext_csd.raw_partition_support & EXT_CSD_PART_SUPPORT_PART_EN)) + return count; + + sscanf(buf, "%s", buffer); + + while ((token = strsep(&cur, delim))) { + if(para_num==9) break; + if(!strcmp(token,"0")) { + token = strsep(&cur, delim); + if(token == NULL) { + euda_size = 0; + printk(KERN_ERR "no euda start_addr: euda_start_addr=0x%lx, euda_size=%lu\n", euda_start_addr, euda_size); + break; + } + + euda_start_addr = simple_strtoul(token, NULL, 16); + token = strsep(&cur, delim); + if(token == NULL) { + euda_size = 0; + printk(KERN_ERR "no euda size: euda_start_addr=0x%lx, euda_size=%lu\n", euda_start_addr, euda_size); + break; + } + euda_size = simple_strtoul(token, NULL, 10); + break; + } + strcpy(sep[para_num], token); + ++para_num; + } + + for(gpp_num=0;gpp_num<(para_num/2);gpp_num++) { + size[gpp_num] = simple_strtoul(sep[gpp_num*2], NULL, 10); + type[gpp_num] = sep[gpp_num*2+1][0]; + } + + euda_gpp_setting(emmc_port->mmc, size, type, para_num/2, euda_start_addr, euda_size); + + return count; +} +DEVICE_ATTR(gpp_info, S_IRUGO | S_IWUSR, + gpp_info_dev_show, gpp_info_dev_store); + +static ssize_t protect_region_setting_dev_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "echo Q > protect_region_setting to show all eMMC protect group regions, \ + echo C > protect_region_setting to clear all eMMC protect group region\n"); +} + +static ssize_t protect_region_setting_dev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host * host = dev_get_drvdata(dev); + struct rtkemmc_host *emmc_port = mmc_priv(host); + unsigned long args=0; + unsigned int wpg_unit=0; + int cmdq_disable=0; + int ret = 0; + + down_write(&emmc_port->cr_rw_sem); + + if(emmc_port->cmdq==1) + mmc_get_card(host->card, NULL); + + ret = rtkemmc_sysfs_cmdq_disable(emmc_port, &cmdq_disable); + if(ret!=0) + goto out; + ret = rtkemmc_sysfs_partition_pre(emmc_port); + if(ret!=0) + goto out; + + wpg_unit= emmc_port->mmc->card->ext_csd.raw_hc_erase_grp_size*emmc_port->mmc->card->ext_csd.raw_hc_erase_gap_size*1024; + if(buf[0]=='Q') { + //wpg_unit is write protect grpoup size (sector unit) + printk(KERN_ERR "curret eMMC protect region status:\n"); + for(args=0; argsmmc->card->ext_csd.sectors;args+=(wpg_unit*0x20)) { + rtkemmc_query_protect_cmd(emmc_port, args, MMC_SEND_WRITE_PROT); + rtkemmc_wait_status(emmc_port->mmc->card,STATE_TRAN,0,0); + } + } + else if(buf[0]=='C') { + printk(KERN_ERR "clear all eMMC protect group regions...\n"); + for(args=0; argsmmc->card->ext_csd.sectors;args+=wpg_unit) { + rtkemmc_write_protect_cmd(emmc_port, args, 0); + rtkemmc_wait_status(emmc_port->mmc->card,STATE_TRAN,0,0); + } + } + + ret = rtkemmc_sysfs_partition_post(emmc_port); + if(ret) + goto out; + ret = rtkemmc_sysfs_cmdq_enable(emmc_port, cmdq_disable); +out: + if(emmc_port->cmdq==1) + mmc_put_card(host->card, NULL); + + up_write(&emmc_port->cr_rw_sem); + + return count; +} + +DEVICE_ATTR(protect_region_setting, S_IRUGO | S_IWUSR, + protect_region_setting_dev_show, protect_region_setting_dev_store); + +static int count_class_dev(struct device *dev, const void *data) +{ + int *p = (void *)data; + + *p += 1; + return 0; +} + +static void rtkemmc_wait_block_dev_ready(struct mmc_host *mmc) +{ + int retry = 500; + int cb = 0, ca = 0; + ktime_t tb, ta; + + tb = ktime_get(); + class_find_device(&block_class, NULL, &cb, count_class_dev); + + while (--retry > 0) { + if (mmc->card && dev_get_drvdata(&mmc->card->dev) != NULL) { + break; + } + msleep(10); + } + + class_find_device(&block_class, NULL, &ca, count_class_dev); + ta = ktime_get(); + printk(KERN_INFO "%s: retry_left=%d, block_dev=[%d -> %d], time=%dms\n", + mmc_hostname(mmc), retry, cb, ca, (int)ktime_to_ms(ktime_sub(ta, tb))); + +} + +static int rtkemmc_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc = NULL; + struct rtkemmc_host *emmc_port = NULL; + int ret = 0; + int att_err; + const u32 *prop; + int size; + struct device_node *emmc_node = NULL; + int i; + int counter=0; + emmc_node = pdev->dev.of_node; + + if (!emmc_node) + pr_err("%s : No emmc of_node found\n",DRIVER_NAME); + else + printk(KERN_ERR "%s : emmc of_node found\n",DRIVER_NAME); + + mmc = mmc_alloc_host(sizeof(struct rtkemmc_host), &pdev->dev); + + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + emmc_port = mmc_priv(mmc); + memset(emmc_port, 0, sizeof(struct rtkemmc_host)); + emmc_port->mmc = mmc; + emmc_port->dev = &pdev->dev; + + att_err = device_create_file(&pdev->dev, &dev_attr_emmc_info); + att_err = device_create_file(&pdev->dev, &dev_attr_tuning_info); + att_err = device_create_file(&pdev->dev, &dev_attr_gpp_info); + att_err = device_create_file(&pdev->dev, &dev_attr_protect_region_setting); + + emmc_port->irq = irq_of_parse_and_map(emmc_node, 0); + if (emmc_port->irq <= 0) { + pr_err("%s : fail to parse of irq.\n",DRIVER_NAME); + return -ENXIO; + } + + emmc_port->emmc_membase = of_iomap(emmc_node, 0); + emmc_port->crt_membase = of_iomap(emmc_node, 1); + emmc_port->sb2_membase = of_iomap(emmc_node, 2); + emmc_port->mux_mis_membase = of_iomap(emmc_node, 3); + emmc_port->iso_blk_membase = of_iomap(emmc_node, 4); + emmc_port->m2tmx_membase = of_iomap(emmc_node, 5); + + if (!emmc_port->emmc_membase || !emmc_port->crt_membase || + !emmc_port->sb2_membase || !emmc_port->mux_mis_membase || + !emmc_port->iso_blk_membase || !emmc_port->m2tmx_membase) { + pr_err("Realtek EMMC Controller Driver probe fail - nomem !!!\n\n"); + ret = -ENOMEM; + goto out; + } + +#if defined(CONFIG_MMC_RTK_EMMC_PON) + emmc_port->norst_membase = of_iomap(emmc_node, 7); + + emmc_port->emmc_pon_gpio = devm_gpiod_get(&pdev->dev, "emmc-pon", GPIOD_OUT_HIGH); + if (IS_ERR(emmc_port->emmc_pon_gpio)) { + pr_err("%s: can't request emmc_pon_gpio %d\n", __func__, desc_to_gpio(emmc_port->emmc_pon_gpio)); + } + + emmc_port->emmc_pon_toggle_gpio = devm_gpiod_get(&pdev->dev, "emmc-pon-toggle", GPIOD_OUT_HIGH); + if (IS_ERR(emmc_port->emmc_pon_toggle_gpio)) { + pr_err("%s: can't request emmc_pon_toggle_gpio %d\n", __func__, desc_to_gpio(emmc_port->emmc_pon_toggle_gpio)); + } +#endif + + emmc_port->dma_vaddr = NULL; + emmc_port->desc_vaddr = NULL; + emmc_port->tx_phase = EMMC_DEFAULT_PHASE_VALUE; + emmc_port->rx_phase = EMMC_DEFAULT_PHASE_VALUE; + emmc_port->dqs = EMMC_DEFAULT_PHASE_VALUE; + emmc_port->cmd_dly_tap = EMMC_DEFAULT_PHASE_VALUE; + emmc_port->cmdq_reenable=0; + emmc_port->retune=0; + emmc_port->switch_partition = 0; + emmc_port->time_setting = 0; + + emmc_port->cell = nvmem_cell_get(&pdev->dev, "uuid"); // get cell + if (IS_ERR(emmc_port->cell)) { + pr_err("cannot get the uuid info !\n"); + } +#if 0 + prop = of_get_property(pdev->dev.of_node, "interrupts", &size); + if (prop) { + emmc_port->irq_num = of_read_number(prop, 2); + printk(KERN_INFO "[%s] get interrupts irq number : %d \n",__func__, emmc_port->irq_num); + }else { + printk(KERN_ERR "[%s] get interrupts irq number error !!\n",__func__); + } +#endif + prop = of_get_property(pdev->dev.of_node, "speed-step", &size); + if (prop) { + emmc_port->speed_step = of_read_number(prop, 1); + printk(KERN_INFO "[%s] get speed-step : %d \n",__func__, emmc_port->speed_step); + } else { + pr_err("[%s] get speed-step error and use default speed-step 0.\n",__func__); + emmc_port->speed_step = 0; + } + + switch(emmc_port->speed_step) { + case 0: + prop = of_get_property(pdev->dev.of_node, "pddrive_nf_s0", &size); + break; + case 1: + prop = of_get_property(pdev->dev.of_node, "pddrive_nf_s1", &size); + break; + case 2: + prop = of_get_property(pdev->dev.of_node, "pddrive_nf_s2", &size); + break; + case 3: + prop = of_get_property(pdev->dev.of_node, "pddrive_nf_s3", &size); + break; + default: + break; + } + + if (prop) { + if (size) + counter = size / sizeof(u32); + + for (i=0; ipddrive_nf[i] = of_read_number(prop, 1 + i); + printk(KERN_ERR "[%s] get pad driving : 0x%x\n",__func__, emmc_port->pddrive_nf[i]); + } + } else { + pr_err("[%s] no driving nf warning !! \n",__func__); + } + + prop = of_get_property(pdev->dev.of_node, "phase_tuning", &size); + if (prop) { + emmc_port->tx_tuning = of_read_number(prop, 1); + emmc_port->rx_tuning = of_read_number(prop, 2); + printk(KERN_ERR "[%s] get tx tuning switch : %u\n",__func__, emmc_port->tx_tuning); + printk(KERN_ERR "[%s] get rx tuning switch : %u\n",__func__, emmc_port->rx_tuning); + } else { + emmc_port->tx_tuning = 1; //if we do not get this node in device tree, we should tune phase by kernel + emmc_port->rx_tuning = 1; + printk(KERN_INFO "[%s] no phase_tuning switch node !! \n",__func__); + } + + prop = of_get_property(pdev->dev.of_node, "dqs_tuning", &size); + if (prop) { + emmc_port->dqs_tuning = of_read_number(prop, 1); + printk(KERN_ERR "[%s] get dqs tuning switch : %u\n",__func__, emmc_port->dqs_tuning); + } else { + emmc_port->dqs_tuning = 1; //if we do not get this node, we should tune dqs value by kernel + printk(KERN_INFO "[%s] no dqs_tuning switch node !! \n",__func__); + } + + if(emmc_port->dqs_tuning==0) { + emmc_port->dqs = of_read_number(prop, 2); + printk(KERN_ERR "[%s] get dqs tuning reference value : %u\n",__func__, emmc_port->dqs); + emmc_port->cmd_dly_tap = of_read_number(prop, 3); + printk(KERN_ERR "[%s] get cmd_dly_tap tuning reference value : %u\n",__func__, emmc_port->cmd_dly_tap); + } + + prop = of_get_property(pdev->dev.of_node, "reference_phase", &size); + if (prop) { + emmc_port->tx_user_defined = of_read_number(prop, 1); + emmc_port->tx_reference_phase = of_read_number(prop, 2); + emmc_port->rx_user_defined = of_read_number(prop, 3); + emmc_port->rx_reference_phase = of_read_number(prop, 4); + if(emmc_port->tx_user_defined) printk(KERN_ERR "[%s] get User defined tx reference phase: %u\n",__func__, emmc_port->tx_reference_phase); + if(emmc_port->rx_user_defined) printk(KERN_ERR "[%s] get User defined rx reference phase: %u\n",__func__, emmc_port->rx_reference_phase); + } else { + emmc_port->tx_user_defined = 0; + emmc_port->tx_reference_phase = 0x0; + emmc_port->rx_user_defined = 0; + emmc_port->rx_reference_phase = 0x0; + printk(KERN_INFO "[%s] no tx & rx reference phase switch node !! \n",__func__); + } + + prop = of_get_property(pdev->dev.of_node, "dqs_dly_tape", &size); + if (prop) { + emmc_port->dqs_dly_tape = of_read_number(prop, 1); + printk(KERN_ERR "[%s] get dqs_dly_tape : %u\n",__func__, emmc_port->dqs_dly_tape); + } else { + emmc_port->dqs_dly_tape = 0x0; //use 0x0 as default + printk(KERN_INFO "[%s] no dqs_dly_tape switch node, use default 0x0 !! \n",__func__); + } + + prop = of_get_property(pdev->dev.of_node, "emmc_tuning_addr", &size); + if (prop) { + emmc_port->emmc_tuning_addr = of_read_number(prop, 1); + printk(KERN_ERR "[%s] GPT format: emmc tuning offset start from 0x%lx\n",__func__, emmc_port->emmc_tuning_addr); + } else { + prop = of_get_property(pdev->dev.of_node, "mbr_tuning_addr", &size); + if (prop) { + emmc_port->emmc_tuning_addr = of_read_number(prop, 1); //if we do not get this node, we assume that the system uses MBR mode before Android O + printk(KERN_ERR "[%s] MBR format: emmc tuning offset start from 0x%lx\n\n",__func__, emmc_port->emmc_tuning_addr); + } + else { + emmc_port->emmc_tuning_addr = 0xa31000; //use default value in the factory partition end block addr - 1025 blocks + printk(KERN_ERR "[%s] Use Default tuning addr: emmc tuning offset start from 0x%lx\n\n",__func__, emmc_port->emmc_tuning_addr); + } + } +#if defined(CONFIG_MMC_RTK_EMMC_PON) + prop = of_get_property(pdev->dev.of_node, "pon_addr", &size); + if (prop) { + emmc_port->pon_blk_addr = of_read_number(prop, 1); + printk(KERN_ERR "[%s] pon address starts from 0x%lx\n",__func__, emmc_port->pon_blk_addr); + } else { + emmc_port->pon_blk_addr = 0; //if we do not get this node, we assume that the system uses MBR mode before Android O + printk(KERN_INFO "[%s] No pon address node, emmc_port->pon_blk_addr = 0 !! \n",__func__); + } +#endif + prop = of_get_property(pdev->dev.of_node, "hs400_force_tuning", &size); + if (prop) { + emmc_port->hs400_force_tuning = of_read_number(prop, 1); + printk(KERN_ERR "[%s] hs400 force tuning setting %u\n",__func__, emmc_port->hs400_force_tuning); + } else { + emmc_port->hs400_force_tuning = 0; //if we do not get this node, we assume that the system uses MBR mode before Android O + printk(KERN_INFO "[%s] No hs400_force_tuning node, emmc_port->hs400_force_tuning = 0 !\n",__func__); + } + + prop = of_get_property(pdev->dev.of_node, "cmdq", &size); + if (prop) { + emmc_port->cmdq = of_read_number(prop, 1); + printk(KERN_ERR "[%s] cmdq enable: %u\n", __func__, emmc_port->cmdq); + } + else { + emmc_port->cmdq = 0; + pr_err("[%s] no cmdq attribute, enable: %u\n",__func__, emmc_port->cmdq); + } + + emmc_port->rstc_emmc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(emmc_port->rstc_emmc)) { + printk(KERN_WARNING "%s: reset_control_get() returns %ld\n", __func__, + PTR_ERR(emmc_port->rstc_emmc)); + emmc_port->rstc_emmc = NULL; + } + + emmc_port->clk_en_emmc = devm_clk_get(&pdev->dev, "emmc"); + if (IS_ERR(emmc_port->clk_en_emmc)) { + printk(KERN_WARNING "%s: clk_get() returns %ld\n", __func__, + PTR_ERR(emmc_port->clk_en_emmc)); + emmc_port->clk_en_emmc = NULL; + } + emmc_port->clk_en_emmc_ip = devm_clk_get(&pdev->dev, "emmc_ip"); + if (IS_ERR(emmc_port->clk_en_emmc_ip)) { + printk(KERN_WARNING "%s: clk_get() returns %ld\n", __func__, + PTR_ERR(emmc_port->clk_en_emmc_ip)); + emmc_port->clk_en_emmc_ip = NULL; + } + clk_prepare_enable(emmc_port->clk_en_emmc); + clk_prepare_enable(emmc_port->clk_en_emmc_ip); + + rtkemmc_writel(readl(emmc_port->crt_membase+0x454)|0x1, emmc_port->crt_membase+0x454); + + mmc->ocr_avail = MMC_VDD_30_31 + | MMC_VDD_31_32 + | MMC_VDD_32_33 + | MMC_VDD_33_34 + | MMC_VDD_165_195; + + mmc->caps = MMC_CAP_4_BIT_DATA + | MMC_CAP_8_BIT_DATA + | MMC_CAP_SD_HIGHSPEED + | MMC_CAP_MMC_HIGHSPEED + | MMC_CAP_NONREMOVABLE + | MMC_CAP_1_8V_DDR + | MMC_CAP_UHS_DDR50 + | MMC_CAP_CMD23 + | MMC_CAP_ERASE; + + mmc->caps2 = (MMC_CAP2_NO_SDIO | MMC_CAP2_NO_SD); + switch(emmc_port->speed_step) + { + case 0: //sdr50 + mmc->caps &= ~(MMC_CAP_UHS_DDR50|MMC_CAP_1_8V_DDR); + mmc->caps2 &= ~(MMC_CAP2_HS200_1_8V_SDR); + break; + case 1: //ddr50 + mmc->caps2 &= ~(MMC_CAP2_HS200_1_8V_SDR); + break; + case 2: //hs200 + mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR; + break; + case 3: //hs400 + mmc->caps2 |= (MMC_CAP2_HS200_1_8V_SDR|MMC_CAP2_HS400_1_8V); + break; + } + + if(emmc_port->cmdq==1) { + mmc->caps2 |= (MMC_CAP2_CQE|MMC_CAP2_CQE_DCMD); + emmc_port->cq_host = cqhci_pltfm_init(pdev); + if(PTR_ERR(emmc_port->cq_host)==-EINVAL || + PTR_ERR(emmc_port->cq_host)==-ENOMEM || + PTR_ERR(emmc_port->cq_host)==-EBUSY) { + pr_err("Unable to get the cmdq related attribute !!!\n"); + emmc_port->cmdq = 0; + mmc->caps2 &= ~(MMC_CAP2_CQE|MMC_CAP2_CQE_DCMD); + } + else { + emmc_port->cq_host->ops = &rtk_cqhci_host_ops; + cqhci_init(emmc_port->cq_host, mmc, 0); + } + } + + ret = rtkemmc_allocate_dma_buf(emmc_port); + if(ret) + goto out; + + mmc->caps2 |= (1 << 9); + mmc->f_min = 300000; //300K + mmc->f_max = 400000000; //400M + mmc->max_segs = 256; //the max number of nodes in the scatterlist + mmc->max_blk_size = 512; + mmc->max_blk_count = 0x800; + mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + + spin_lock_init(&emmc_port->lock); + init_rwsem(&emmc_port->cr_rw_sem); + tasklet_init(&emmc_port->req_end_tasklet, rtkemmc_req_end_tasklet, (unsigned long)emmc_port); + + rtkemmc_hold_int_dec(); /* hold status interrupt */ + rtkemmc_clr_int_sta(); + ret = request_irq(emmc_port->irq, rtkemmc_irq, IRQF_SHARED, DRIVER_NAME, emmc_port); //rtkemmc_interrupt + if (ret) { + pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, emmc_port->irq); + goto out; + } + + timer_setup(&emmc_port->timer, rtkemmc_timeout_timer, 0); + rtkemmc_set_pin_mux(emmc_port); + + rtkemmc_init(emmc_port); + + platform_set_drvdata(pdev, mmc); + + ret = mmc_add_host(mmc); + if (ret) + goto out; + + sync(emmc_port); + g_bResuming=0; + g_bTuning=0; + + printk(KERN_NOTICE "%s: %s driver initialized\n", + mmc_hostname(mmc), DRIVER_NAME); + + rtkemmc_wait_block_dev_ready(mmc); + + return 0; + +out: + if (emmc_port) { + if (emmc_port->irq) + free_irq(emmc_port->irq, emmc_port); + + if (emmc_port->emmc_membase) + iounmap(emmc_port->emmc_membase); + if (emmc_port->crt_membase) + iounmap(emmc_port->crt_membase); + } + + if (mmc) + mmc_free_host(mmc); + + rtkemmc_free_dma_buf(emmc_port); + + return ret; +} + +static int __exit rtkemmc_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + MMCPRINTF("\n"); + + device_remove_file(&pdev->dev, &dev_attr_emmc_info); + device_remove_file(&pdev->dev, &dev_attr_tuning_info); + device_remove_file(&pdev->dev, &dev_attr_gpp_info); + device_remove_file(&pdev->dev, &dev_attr_protect_region_setting); + + if (mmc) { + struct rtkemmc_host *emmc_port = mmc_priv(mmc); + flush_scheduled_work(); + rtkemmc_free_dma_buf(emmc_port); + mmc_remove_host(mmc); + if(!mmc){ + printk("eMMC host have removed.\n"); + } + free_irq(emmc_port->irq, emmc_port); + + del_timer_sync(&emmc_port->timer); + iounmap(emmc_port->emmc_membase); + iounmap(emmc_port->crt_membase); + iounmap(emmc_port->sb2_membase); + iounmap(emmc_port->mux_mis_membase); + iounmap(emmc_port->iso_blk_membase); + iounmap(emmc_port->m2tmx_membase); +#if defined(CONFIG_MMC_RTK_EMMC_PON) + devm_gpiod_put(pdev->dev, emmc_port->emmc_pon_gpio); +#endif + nvmem_cell_put(emmc_port->cell); + mmc_free_host(mmc); + } + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id rtkemmc_ids[] = { + { .compatible = "realtek,rtd13xx-emmc" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, rtkemmc_ids); + +/**************************************************/ +/* driver / device attache area */ +/**************************************************/ +static struct platform_driver rtkemmc_driver = { + .probe = rtkemmc_probe, + .remove = __exit_p(rtkemmc_remove), + .driver = + { + .name = "rtkemmc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtkemmc_ids), +#ifdef CONFIG_PM + .pm = &rtk_dev_pm_ops +#endif + }, + .shutdown = rtkemmc_shutdown, +}; +module_platform_driver(rtkemmc_driver); + +MODULE_AUTHOR("Jim Tsai"); +MODULE_DESCRIPTION("Realtek EMMC Host Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtkemmc"); diff --git a/drivers/mmc/host/rtkemmc_rtd13xx.h b/drivers/mmc/host/rtkemmc_rtd13xx.h new file mode 100644 index 000000000000..abb3f6de48c8 --- /dev/null +++ b/drivers/mmc/host/rtkemmc_rtd13xx.h @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2010 Realtek Semiconductors, 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 as + * published by the Free Software Foundation. + */ + +#ifndef __RTKEMMC_H +#define __RTKEMMC_H + +#include "reg_mmc_rtd13xx.h" +#include "mmc_debug.h" +#include + +#ifdef CONFIG_REALTEK_PCBMGR +#include +#ifdef CONFIG_REALTEK_GPIO +#include +#define EMMC_SHOUTDOWN_PROTECT +#endif +#endif + +#define EMMC_MAX_SCRIPT_BLK 128 + +//debug +//#define MMC_DBG +#ifdef MMC_DBG +#define MMCPRINTF(fmt, args...) printk(fmt,## args) +#else +#define MMCPRINTF(fmt, args...) +#endif + +/* cmd1 sector mode */ +#define MMC_SECTOR_ADDR 0x40000000 + +#define EMMC_DEFAULT_PHASE_VALUE (0xff) +#define EMMC_PLL_HS200 (0xa6) +#define EMMC_PLL_SDR50 (0x57) +#define EMMC_CLK_DIV512 (0x200) +#define EMMC_CLK_DIV4 (0x4) +#define EMMC_CLK_DIV1 (0x1) +#define CMDQ_DISABLED (0x30f0001) +#define CMDQ_ENABLED (0x30f0101) + +#define EMMC_BLK_SZ (0x200) +#define EMMC_CMD21_BLK_SZ (0x80) +#define EMMC_WR_PROT_BLK_SZ (0x4) + +#define RED_BOLD "\033[31;1m" +#define BLU_BOLD "\033[34;1m" +#define YEL_BOLD "\033[33;1m" +#define GRN_BOLD "\033[32;1m" +#define CYAN_BOLD_ITALIC "\033[36;1;3m" +#define RESET "\033[0;m" + +struct backupRegs { + u32 sdmasa_r; //0x98012000 + u16 blocksize_r; //0x98012004 + u16 blockcount_r; //0x98012006 + u16 xfer_mode_r; //0x9801200c + u8 host_ctrl1_r; //0x98012028 + u8 pwr_ctrl_r; //0x98012029 + u8 bgap_ctrl_r; //0x9801202a + u16 clk_ctrl_r; //0x9801202c + u8 tout_ctrl_r; //0x9801202e + + u16 normal_int_stat_en_r; //0x98012034 + u16 error_int_stat_en_r; //0x98012036 + u16 normal_int_signal_en_r; //0x98012038 + u16 error_int_signal_en_r; //0x9801203a + u16 auto_cmd_stat_r; //0x9801203c + u16 host_ctrl2_r; //0x9801203e + u32 adma_sa_low_r; //0x98012058 + u8 mshc_ctrl_r; //0x98012208 + u8 ctrl_r; //0x9801222c + u32 other1; //0x98012420 + u32 dummy_sys; //0x9801242c + u32 dqs_ctrl1; //0x98012498 + u32 wcmd_ctrl; //0x98012554 + + u32 rdq_ctrl0; //0x98012530 + u32 rdq_ctrl1; //0x98012534 + u32 rdq_ctrl2; //0x98012538 + u32 rdq_ctrl3; //0x9801253c + u32 rdq_ctrl4; //0x98012540 + u32 rdq_ctrl5; //0x98012544 + u32 rdq_ctrl6; //0x98012548 + u32 rdq_ctrl7; //0x9801254c + u32 dq_ctrl_set; //0x9801250c + u32 ahb; +}; + +struct rtkemmc_host { + struct mmc_host *mmc; /* MMC structure */ + u8 cmd_opcode; + + struct mmc_request *mrq; /* Current request */ + + volatile void __iomem *emmc_membase; + volatile void __iomem *crt_membase; + volatile void __iomem *sb2_membase; + volatile void __iomem *misc_membase; + volatile void __iomem *mux_mis_membase; + volatile void __iomem *iso_blk_membase; + volatile void __iomem *m2tmx_membase; +#if defined(CONFIG_MMC_RTK_EMMC_PON) + volatile void __iomem *norst_membase; +#endif + u32 pddrive_nf[5]; + struct nvmem_cell *cell; + spinlock_t lock; + struct tasklet_struct req_end_tasklet; + struct rw_semaphore cr_rw_sem; + + struct timer_list timer; + struct completion *int_waiting; + struct device *dev; + int irq; + u8 time_setting; +#if 0 + int irq_num; +#endif + dma_addr_t dma_paddr; + dma_addr_t desc_paddr; + unsigned char* dma_vaddr; + unsigned int* desc_vaddr; + u32 tmout; + u16 normal_interrupt; //2030 + u16 error_interrupt; //2032 + u16 auto_error_interrupt; //203c + u8 rpmb_cmd; // it is rpmb cmd flag. When receiving CMD23, set to 1 + + u32 speed_step; + u32 dqs_dly_tape; + unsigned long emmc_tuning_addr; + + u32 tx_phase; + u32 rx_phase; + u32 dqs; + u32 cmd_dly_tap; + + struct reset_control* rstc_emmc; + struct clk* clk_en_emmc; + struct clk* clk_en_emmc_ip; + + u8 suspend; + struct backupRegs backreg; + + u8 hs400_force_tuning; + u8 tx_tuning; //flag that tx tuning need to be performed + u8 rx_tuning; //flag that rx tuning need to be performed + u8 dqs_tuning; + u8 tx_user_defined; + u8 rx_user_defined; + u8 tx_reference_phase; + u8 rx_reference_phase; + + struct cqhci_host *cq_host; + u8 cmdq; + u8 cmdq_reenable; + u8 retune; + u8 switch_partition; +#if defined(CONFIG_MMC_RTK_EMMC_PON) + unsigned long pon_blk_addr; + struct gpio_desc *emmc_pon_gpio; + struct gpio_desc *emmc_pon_toggle_gpio; +#endif +}; + +struct sd_cmd_pkt { + struct mmc_host *mmc; /* MMC structure */ + struct rtkemmc_host *emmc_port; + struct mmc_command *cmd; /* cmd->opcode; cmd->arg; cmd->resp; cmd->data */ + struct mmc_data *data; + unsigned char *dma_buffer; + u16 byte_count; + u16 block_count; + + u32 flags; + u32 cmd_para; + u8 rsp_len; + u32 timeout; +}; + +#define MAX_CMD_RETRY_COUNT 4 + +#define RCA_SHIFTER 16 + +/* move from c file *** */ +#define BYTE_CNT 0x200 + +#define RTK_FAIL 0x3 /* DMA error & cmd parser error */ +#define RTK_RMOV 0x2 /* card removed */ +#define RTK_TOUT 0x1 /* time out include DMA finish & cmd parser finish */ +#define RTK_SUCC 0x0 +#define CR_TRANSFER_FAIL 0x4 + +/* send status event */ +#define STATE_IDLE 0 +#define STATE_READY 1 +#define STATE_IDENT 2 +#define STATE_STBY 3 +#define STATE_TRAN 4 +#define STATE_DATA 5 +#define STATE_RCV 6 +#define STATE_PRG 7 +#define STATE_DIS 8 + +#define rtkemmc_get_int_sta(normal_interrupt, error_interrupt, auto_error_interrupt) \ + do { \ + sync(emmc_port); \ + *(u16 *)normal_interrupt = readw(emmc_port->emmc_membase+EMMC_NORMAL_INT_STAT_R); \ + *(u16 *)error_interrupt = readw(emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_R); \ + *(u16 *)auto_error_interrupt = readw(emmc_port->emmc_membase+EMMC_AUTO_CMD_STAT_R); \ + } while (0) + +//clear status register, we always keep the card interrupt, card insertion, removal status because the eMMC is unremovable +#define rtkemmc_clr_int_sta() \ + do { \ + rtkemmc_writew(readw(emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_R)&0xffff, emmc_port->emmc_membase+EMMC_ERROR_INT_STAT_R); \ + rtkemmc_writew(readw(emmc_port->emmc_membase+EMMC_NORMAL_INT_STAT_R)&0xfeff, emmc_port->emmc_membase+EMMC_NORMAL_INT_STAT_R); \ + } while(0) + +//mask all emmc interrupts +#define rtkemmc_hold_int_dec() \ + do { \ + writew(0x0,emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R); \ + writew(0x0,emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R); \ + sync(emmc_port); \ + } while(0) + +//for cmdq, we do not need cmd and xfer done, only cqe event +#define rtkemmc_en_cqe_int() \ + do { \ + writew(0xfefc,emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R); \ + writew(EMMC_ALL_ERR_SIGNAL_EN,emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R); \ + sync(emmc_port); \ + } while(0) + +//used for data, r1b case, we mask cmd done interrupt +#define rtkemmc_en_xfer_int() \ + do { \ + writew(0xfefe,emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R); \ + writew(EMMC_ALL_ERR_SIGNAL_EN,emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R); \ + sync(emmc_port); \ + } while(0) + +//used for none-stream case (cmd w/wo/ resp) +#define rtkemmc_en_cd_int() \ + do { \ + writew(0xfefd,emmc_port->emmc_membase+EMMC_NORMAL_INT_SIGNAL_EN_R); \ + writew(EMMC_ALL_ERR_SIGNAL_EN,emmc_port->emmc_membase+EMMC_ERROR_INT_SIGNAL_EN_R); \ + sync(emmc_port); \ + } while(0) + +#define rtkemmc_writel(val, addr) \ + do { \ + sync(emmc_port); \ + writel(val, addr); \ + } while(0) + +#define rtkemmc_writew(val, addr) \ + do { \ + sync(emmc_port); \ + writew(val, addr); \ + } while(0) + +#define rtkemmc_writeb(val, addr) \ + do { \ + sync(emmc_port); \ + writeb(val, addr); \ + } while(0) + +static const char *const state_tlb[11] = { + "STATE_IDLE", + "STATE_READY", + "STATE_IDENT", + "STATE_STBY", + "STATE_TRAN", + "STATE_DATA", + "STATE_RCV", + "STATE_PRG", + "STATE_DIS", + "STATE_BTST", + "STATE_SLEEP" +}; + +/* remove from c file &&& */ + +/* rtk function definition */ + +/* rtk function definition */ +int rtkemmc_send_cmd25(struct rtkemmc_host *emmc_port,int,unsigned long, int,int*, unsigned int); +int rtkemmc_send_cmd18(struct rtkemmc_host *emmc_port,int,unsigned long, unsigned int); + +irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, int data_error); +int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64); +struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev); +void cqhci_dumpregs(struct cqhci_host *cq_host); +#endif diff --git a/drivers/mmc/host/sdhci-rtk.c b/drivers/mmc/host/sdhci-rtk.c new file mode 100644 index 000000000000..2b779931d8c3 --- /dev/null +++ b/drivers/mmc/host/sdhci-rtk.c @@ -0,0 +1,921 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek SDIO host driver + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" +#include "sdhci-rtk.h" + +#define DRIVER_NAME "Realtek SDIO" +#define BANNER "Realtek SDIO Host Driver" +#define SDIO_CLKEN_REGOFF 0x0C +#define SDIO_CLKEN_REGBIT 30 + +#define MAX_PHASE 31 +#define TUNING_CNT 3 + +#define sdhci_tx_tuning + +static void __iomem *sdio_membase; +static void __iomem *crt_membase; +static struct gpio_desc *sdio_gpio_23; +bool SDIO_module_disable; +bool clock_enable; +bool SDIO_card; +int SDIO_version; +struct sdhci_host *G_host; +unsigned int drive_temp; +static enum rtd_chip_id chip_id; + +struct reset_control *rstc_sdio; +struct clk *clk_en_sdio; +struct clk *clk_en_sdio_ip; + +struct sdhci_rtk_sdio_data { + const struct sdhci_pltfm_data *pdata; +}; + +struct timing_phase_path { + int start; + int end; + int mid; + int len; +}; + +void set_SDIO_version(int version) +{ + SDIO_version = version; +} + +int get_SDIO_version(void) +{ + return SDIO_version; +} + +void disable_sdio_irq(struct sdhci_host *host) +{ + sdhci_writel(host, 0, SDHCI_INT_ENABLE); + sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); +} +EXPORT_SYMBOL(disable_sdio_irq); + +static void rtk_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(0x00000003, crt_membase + 0x010A10); + + sdhci_reset(host, mask); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(0x00000001, crt_membase + 0x010A10); +} + +static void rtk_sdhci_pad_driving_configure(void) +{ + if (chip_id == CHIP_ID_RTD1619) { + writel((readl(crt_membase + 0x4E024) & 0xf) | 0xAF75EEB0, crt_membase + 0x4E024); + writel(0x5EEBDD7B, crt_membase + 0x4E028); + writel((readl(crt_membase + 0x4E02c) & 0xffffffc0) | 0x37, crt_membase + 0x4E02c); + } else if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1319) { + writel((readl(crt_membase + 0x4E058) & 0xff000000) | 0x00483483, crt_membase + 0x4E058); + writel((readl(crt_membase + 0x4E05c) & 0xff000000) | 0x00483483, crt_membase + 0x4E05c); + writel((readl(crt_membase + 0x4E060) & 0xff000000) | 0x00483483, crt_membase + 0x4E060); + } else if (chip_id == CHIP_ID_RTD1619B) { + writel((readl(crt_membase + 0x4E068) & 0xff80ffff) | 0x00240000, crt_membase + 0x4E068); + writel((readl(crt_membase + 0x4E06c) & 0xfc07e03f) | 0x01200900, crt_membase + 0x4E06c); + writel((readl(crt_membase + 0x4E070) & 0xfc07e03f) | 0x01200900, crt_membase + 0x4E070); + writel((readl(crt_membase + 0x4E074) & 0xffffff80) | 0x00000024, crt_membase + 0x4E074); + } +} + +static void rtk_sdhci_pad_pwrctrl(int voltage) +{ + if (voltage == MMC_SIGNAL_VOLTAGE_180) { + writel((readl(crt_membase + 0x4E068) & 0xffbfffff) , crt_membase + 0x4E068); + writel((readl(crt_membase + 0x4E06c) & 0xfdffefff) , crt_membase + 0x4E06c); + writel((readl(crt_membase + 0x4E070) & 0xfdffefff) , crt_membase + 0x4E070); + writel((readl(crt_membase + 0x4E074) & 0xffffffbf) , crt_membase + 0x4E074); + } else if (voltage == MMC_SIGNAL_VOLTAGE_330) { + writel((readl(crt_membase + 0x4E068) | 0x00400000) , crt_membase + 0x4E068); + writel((readl(crt_membase + 0x4E06c) | 0x02001000) , crt_membase + 0x4E06c); + writel((readl(crt_membase + 0x4E070) | 0x02001000) , crt_membase + 0x4E070); + writel((readl(crt_membase + 0x4E074) | 0x00000040) , crt_membase + 0x4E074); + } +} + +static void rtk_sdhci_pll_configure(u32 pll, int execute_tuning) +{ + u32 sscpll; + + writel(0x00000006, crt_membase + 0x01AC); + if (chip_id == CHIP_ID_RTD1619B) + sscpll = 0x0451742d; + else + sscpll = 0x04517893; + /* The SSC shouldn't enable when execute tuning */ + if(!execute_tuning) + writel(sscpll, crt_membase + 0x01A4); + writel(pll, crt_membase + 0x01A8); + mdelay(2); + writel(0x00000007, crt_membase + 0x01AC); + udelay(200); +} + +static void rtk_sdhci_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u16 ctrl_2 = 0; + + sdhci_set_uhs_signaling(host, timing); + + if (timing > MMC_TIMING_SD_HS) { + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + sdhci_writew(host, ctrl_2 | SDHCI_CTRL_VDD_180, SDHCI_HOST_CONTROL2); + } +} + +static void rtk_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + + host->mmc->actual_clock = 0; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_enable_clk(host, clk); + + switch (host->timing) { + + case MMC_TIMING_SD_HS: + set_SDIO_version(2); + rtk_register_set(); + break; + case MMC_TIMING_UHS_SDR12: + case MMC_TIMING_UHS_SDR25: + set_SDIO_version(3); + rtk_register_set(); + break; + case MMC_TIMING_UHS_SDR50: + set_SDIO_version(3); + rtk_register_set(); + sdhci_writew(host, 0x7, SDHCI_CLOCK_CONTROL); + rtk_sdhci_pll_configure(0x00564388, 0); + break; + case MMC_TIMING_UHS_SDR104: + set_SDIO_version(4); + rtk_register_set(); + break; + } + + pr_debug("[SDIO] SDHCI_SPEC_300: %s c3c=%x, PLL=%x, CLK=%x\n", + __func__, readl(host->ioaddr + 0x3c), readl(crt_membase + 0x01A8), + readl(host->ioaddr + SDHCI_CLOCK_CONTROL)); + + if ((clk != 0xfa00) && (clk != 0x0) && (clk != 0x100) && (clk != 0x200)) { + host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + SDIO_card = false; + } +} + +void rtk_register_set(void) +{ + + if (get_SDIO_version() == 3 || get_SDIO_version() == 4) { + + if (chip_id == CHIP_ID_RTD1619) + writel((readl(crt_membase + 0x1A0) & ~0x000000F8) | (0x1d << 3), crt_membase + 0x1A0); + + rtk_sdhci_pad_driving_configure(); + + if (chip_id != CHIP_ID_RTD1619B) + writel(0x00000000, crt_membase + 0x010A40); + + if (get_SDIO_version() == 4) { + /* enlarge wait time for data */ + if (chip_id == CHIP_ID_RTD1619) + writel(0x1d, crt_membase + 0x10a58); + + rtk_sdhci_pll_configure(0x00b64388, 0); + } + } else if (get_SDIO_version() == 2) { + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1319) { + writel(readl(crt_membase + 0x7064) | (0x3 << 4), crt_membase + 0x7064); + } else if (chip_id == CHIP_ID_RTD1619B) { + writel(readl(crt_membase + 0x70c4) | (0x3 << 4), crt_membase + 0x70c4); + rtk_sdhci_pad_pwrctrl(MMC_SIGNAL_VOLTAGE_330); + } else { + writel(0x00000003, crt_membase + 0x01A0); + } + } +} + +void rtk_sdhci_platform_init(void) +{ +#if defined(SD_INTERFACE_SDIO_1619) + unsigned int tmp = 0; +#endif + if (chip_id == CHIP_ID_RTD1619) { + if (get_rtd_chip_revision() == RTD_CHIP_A01) { + writel(readl(crt_membase + 0x1A0) | 0x1, crt_membase + 0x1A0); + writel(readl(crt_membase + 0x1A4) | 0x1, crt_membase + 0x1A4); + udelay(200); + } + } else if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1319) { + writel(readl(crt_membase + 0x7064) | (0x3 << 4), crt_membase + 0x7064); + udelay(200); + } else if (chip_id == CHIP_ID_RTD1619B) { + writel(readl(crt_membase + 0x70c4) | (0x3 << 4), crt_membase + 0x70c4); + udelay(200); + /* The VDD resistor set 1.8v as default */ + rtk_sdhci_pad_pwrctrl(MMC_SIGNAL_VOLTAGE_180); + } + + rtk_sdhci_pll_configure(0x00ae4388, 0); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1319) { + if (get_rtd_chip_revision() == RTD_CHIP_A00){ + writel((readl(crt_membase + 0x1C200) & 0xfffff0ff), crt_membase + 0x1C200); + writel(readl(crt_membase + 0x1C208) | (0x1 << 5), crt_membase + 0x1C208); + } else { + writel(readl(crt_membase + 0x10A58) | 0x80000000, crt_membase + 0x10A58); + } + } + + writel(0x00000011, crt_membase + 0x010A34); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(0x00000001, crt_membase + 0x010A10); + else + writel(0x00000003, crt_membase + 0x010A10); + +#if defined(SD_INTERFACE_SDIO_1619) + writel(readl(crt_membase + 0x4E004) & (~(0x1 << 25)), + crt_membase + 0x4E004); + writel((readl(crt_membase + 0x4E020) & 0xff0fffff) | 0x00600000, + crt_membase + 0x4E020); + mdelay(100); + writel(readl(crt_membase + 0x4E020) & 0xffbfffff, + crt_membase + 0x4E020); + mdelay(100); + + tmp = (0x3243243 << 4) | (readl(crt_membase + 0x4f00c) & 0xf); + writel(tmp, crt_membase + 0x4f00c); + writel(0xd83d83d8, crt_membase + 0x4f010); + tmp = (readl(crt_membase + 0x4f014) & 0xfffff000) | 0xd83; + writel(tmp, crt_membase + 0x4f014); + + writel(0x10, crt_membase + 0x4E048); + writel((readl(crt_membase + 0x4F004) & 0xfff00000) | 0x52492, + crt_membase + 0x4F004); + writel(0x3, crt_membase + 0x1e0); + writel(0x4003, crt_membase + 0x1e0); + writel(0x6003, crt_membase + 0x1e0); +#elif defined(SD_INTERFACE_SDIO_1319) + writel(readl(crt_membase + 0x4E00C) & (~(0x1 << 2)), + crt_membase + 0x4E00C); + writel((readl(crt_membase + 0x4E048) & 0xfff0ffff) | 0x00060000, + crt_membase + 0x4E048); + mdelay(100); + writel(readl(crt_membase + 0x4E048) & 0xfffbffff, + crt_membase + 0x4E048); + mdelay(100); + + writel((readl(crt_membase + 0x4E04C) & 0xff000000) | 0x243243, + crt_membase + 0x4E04C); + writel((readl(crt_membase + 0x4E050) & 0xf000000f) | (0x243243 << 4), + crt_membase + 0x4E050); + writel((readl(crt_membase + 0x4E054) & 0xff000000) | 0x243243, + crt_membase + 0x4E054); + + writel((readl(crt_membase + 0x4E010) & 0xfffffff0) | (0x1 << 1), + crt_membase + 0x4E010); + writel(0x10, crt_membase + 0x4E120); + writel((readl(crt_membase + 0x4E00C) & 0xf00f) | 0x04440480, + crt_membase + 0x4E00C); + writel(0x3, crt_membase + 0x1e0); + writel(0x4003, crt_membase + 0x1e0); + writel(0x6003, crt_membase + 0x1e0); +#elif defined(SD_INTERFACE_SDIO_1619B) + writel(readl(crt_membase + 0x7100) | (0x1 << 30), crt_membase + 0x7100); + writel(readl(crt_membase + 0x7104) | (0x0 << 30), crt_membase + 0x7104); + writel((readl(crt_membase + 0x4E080) & 0xfffFBfff) | 0x00004000, + crt_membase + 0x4E080); + mdelay(10); + + writel((readl(crt_membase + 0x4E078) & 0xfe07f03f) | 0x00d806c0, crt_membase + 0x4E078); + writel((readl(crt_membase + 0x4E07c) & 0xfff81fc0) | 0x0003601b, crt_membase + 0x4E07c); + writel((readl(crt_membase + 0x4E080) & 0xfe07f03f) | 0x00d806c0, crt_membase + 0x4E080); + + writel((readl(crt_membase + 0x4E00c) & 0xff801fff) | 0x00084000, + crt_membase + 0x4E00c); + writel((readl(crt_membase + 0x4E010) & 0xfff80000) | 0x00008842, + crt_membase + 0x4E010); + writel(0x10, crt_membase + 0x4E120); + + writel((readl(crt_membase+0x1e0) & 0xffff9fff) , crt_membase+0x1e0); + mdelay(1); + writel((readl(crt_membase+0x1e0) | 0x00004000) , crt_membase+0x1e0); + mdelay(1); + writel((readl(crt_membase+0x1e0) | 0x00006000) , crt_membase+0x1e0); + mdelay(1); + writel((readl(crt_membase + 0x4E078) & 0xfdffefff) , crt_membase + 0x4E078); + writel((readl(crt_membase + 0x4E07c) & 0xfff7ffbf) , crt_membase + 0x4E07c); + writel((readl(crt_membase + 0x4E080) & 0xfdffefff) , crt_membase + 0x4E080); +#endif +} +EXPORT_SYMBOL(rtk_sdhci_platform_init); + +void rtk_sdhci_close_clk(void) +{ + if (SDIO_module_disable == false) { + clock_enable = false; + G_host->mmc->caps2 |= + (MMC_CAP2_NO_SD | MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) { + pr_err("Do not detect the SDIO card and disable sdio irq\n"); + disable_sdio_irq(G_host); + mdelay(10); + } + + pr_err("Do not detect the SDIO card and close the clock, mmc->caps2=0x%x\n", + G_host->mmc->caps2); + writel(0x0, crt_membase + 0x01AC); + reset_control_assert(rstc_sdio); + clk_disable_unprepare(clk_en_sdio); + clk_disable_unprepare(clk_en_sdio_ip); + /* Ensure sdio irq disable correctly.*/ + wmb(); + mdelay(10); + if (chip_id == CHIP_ID_RTD1619) { + if (get_rtd_chip_revision() == RTD_CHIP_A01) { + writel(readl(crt_membase + 0x1A0) & (~0x1), + crt_membase + 0x1A0); + writel(readl(crt_membase + 0x1A4) & (~0x1), + crt_membase + 0x1A4); + udelay(200); + } + } else if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1319) { + writel(readl(crt_membase + 0x7064) & ~(0x3 << 4), crt_membase + 0x7064); + udelay(200); + } else if (chip_id == CHIP_ID_RTD1619B) { + writel(readl(crt_membase + 0x70c4) & ~(0x3 << 4), crt_membase + 0x70c4); + udelay(200); + } + } +} +EXPORT_SYMBOL(rtk_sdhci_close_clk); + +static void rtk_init_card(struct mmc_host *mmc, struct mmc_card *card) +{ + mmc->card = card; +} + +static int rtk_mmc_send_tuning(struct mmc_host *mmc, u32 opcode, int tx) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_command cmd = {0}; + int err; + + if (tx) { + writew(0x1, host->ioaddr + 0x36); + writew(0x1, host->ioaddr + 0x3A); + + cmd.opcode = opcode; + cmd.arg = 0x2000; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(mmc, &cmd, 0); + if (err) + return err; + } else { + return mmc_send_tuning(mmc, opcode, NULL); + } + + return 0; +} + +static int rtk_sdhci_change_phase(struct sdhci_host *host, u8 sample_point, int tx) +{ + unsigned int temp_reg = 0; + u16 clk = 0; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(readl(crt_membase + 0x1A0) & 0xfffffffd, crt_membase + 0x1A0); + + temp_reg = readl(crt_membase + 0x1A0); + + if (tx) + temp_reg = (temp_reg & ~0x000000F8) | (sample_point << 3); + else + temp_reg = (temp_reg & ~0x00001F00) | (sample_point << 8); + + writel(temp_reg, crt_membase + 0x1A0); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(readl(crt_membase + 0x1A0) | 0x2, crt_membase + 0x1A0); + + udelay(100); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + return 0; +} + +static u8 rtk_sdhci_search_final_phase(u32 phase_map) +{ + struct timing_phase_path path[MAX_PHASE + 1]; + struct timing_phase_path swap; + int i = 0; + int j = 0; + int k = 0; + int cont_path_cnt = 0; + int new_block = 1; + int max_len = 0; + int final_path_idx = 0; + u8 final_phase = 0xFF; + + /* Parse phase_map, take it as a bit-ring */ + for (i = 0; i < MAX_PHASE + 1; i++) { + if (phase_map & (1 << i)) { + if (new_block) { + new_block = 0; + j = cont_path_cnt++; + path[j].start = i; + path[j].end = i; + } else { + path[j].end = i; + } + } else { + new_block = 1; + if (cont_path_cnt) { + /* Calculate path length and middle point */ + int idx = cont_path_cnt - 1; + + path[idx].len = + path[idx].end - path[idx].start + 1; + path[idx].mid = + path[idx].start + path[idx].len / 2; + } + } + } + + if (cont_path_cnt == 0) { + pr_err(" %s No continuous phase path\n", __func__); + goto finish; + } else { + /* Calculate last continuous path length and middle point */ + int idx = cont_path_cnt - 1; + + path[idx].len = path[idx].end - path[idx].start + 1; + path[idx].mid = path[idx].start + path[idx].len / 2; + } + + /* Connect the first and last continuous paths if they are adjacent */ + if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { + /* Using negative index */ + path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; + path[0].len += path[cont_path_cnt - 1].len; + path[0].mid = path[0].start + path[0].len / 2; + /* Convert negative middle point index to positive one */ + if (path[0].mid < 0) + path[0].mid += MAX_PHASE + 1; + cont_path_cnt--; + } + + /* Sorting path array,jamestai20141223 */ + for (k = 0; k < cont_path_cnt; ++k) { + for (i = 0; i < cont_path_cnt - 1 - k; ++i) { + if (path[i].len < path[i + 1].len) { + swap.end = path[i + 1].end; + swap.len = path[i + 1].len; + swap.mid = path[i + 1].mid; + swap.start = path[i + 1].start; + + path[i + 1].end = path[i].end; + path[i + 1].len = path[i].len; + path[i + 1].mid = path[i].mid; + path[i + 1].start = path[i].start; + + path[i].end = swap.end; + path[i].len = swap.len; + path[i].mid = swap.mid; + path[i].start = swap.start; + } + } + } + + /* Choose the longest continuous phase path */ + max_len = 0; + final_phase = 0; + final_path_idx = 0; + for (i = 0; i < cont_path_cnt; i++) { + /* for compatibility issue, continue len should more than 16 */ + if (path[i].len > max_len) { + max_len = path[i].len; + if (max_len > 16) + final_phase = (u8) path[i].mid; + else + final_phase = 0xFF; + final_path_idx = i; + } + } + +finish: + return final_phase; +} + +static int rtk_sdhci_tuning(struct sdhci_host *host, u32 opcode, int tx) +{ + int sample_point = 0; + int ret = 0; + int i = 0; + u32 raw_phase_map[TUNING_CNT] = { 0 }; + u32 phase_map = 0; + u8 final_phase = 0; + + struct mmc_host *mmc = host->mmc; + + for (sample_point = 0; sample_point <= MAX_PHASE; sample_point++) { + for (i = 0; i < TUNING_CNT; i++) { + rtk_sdhci_change_phase(host, (u8) sample_point, tx); + ret = rtk_mmc_send_tuning(mmc, opcode, tx); + if (ret == 0) + raw_phase_map[i] |= (1 << sample_point); + } + } + + phase_map = 0xFFFFFFFF; + for (i = 0; i < TUNING_CNT; i++) + phase_map &= raw_phase_map[i]; + + pr_err("%s %s phase_map = 0x%08x\n", __func__, tx ? "TX" : "RX", phase_map); + + if (phase_map) { + final_phase = rtk_sdhci_search_final_phase(phase_map); + pr_err("%s final phase = 0x%08x\n", __func__, final_phase); + if (final_phase == 0xFF) { + pr_err("%s final phase = 0x%08x\n", __func__, + final_phase); + ret = -EINVAL; + goto out; + } + rtk_sdhci_change_phase(host, final_phase, tx); + ret = 0; + goto out; + } else { + pr_err("%s fail !phase_map\n", __func__); + ret = -EINVAL; + goto out; + } + +out: + return ret; +} + +static int rtk_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + /* [ToDo] SDIO30 clock phase tuning, jamestai20151229 */ + int ret = 0; + unsigned int reg_tmp = 0; + unsigned int reg_tmp2 = 0; + unsigned int reg_tuned3318 = 0; + + pr_err("%s : Execute Clock Phase Tuning\n", __func__); + reg_tmp2 = readl(crt_membase + 0x01A4); /* disable spectrum */ + /* PLL_SD2 clear [15:13] */ + writel((reg_tmp2 & 0xFFFF1FFF), crt_membase + 0x01A4); + + /* rtl8822bs won't stable with sdio clk 208Mhz. Adjust the clk to 200Mhz*/ + if(host->mmc->card->cis.device == 0x0000b822) + rtk_sdhci_pll_configure(0x00ae4388, 1); + +#ifdef sdhci_tx_tuning + ret = rtk_sdhci_tuning(host, SD_IO_RW_DIRECT, 1); +#endif + + do { + ret = rtk_sdhci_tuning(host, MMC_SEND_TUNING_BLOCK, 0); + if (ret) { + reg_tmp = readl(crt_membase + 0x01A8); + reg_tuned3318 = (reg_tmp & 0x03FF0000) >> 16; + if (reg_tuned3318 == 158) { + /* When PLL set to 96, may interference wifi 2.4Ghz */ + reg_tuned3318 = reg_tuned3318 - 8; + } else if (reg_tuned3318 <= 100) { + pr_err("%s: Tuning RX fail\n", __func__); + return ret; + } + /* down 8MHz */ + reg_tmp = ((reg_tmp & (~0x3FF0000)) | + ((reg_tuned3318 - 8) << 16)); + rtk_sdhci_pll_configure(reg_tmp, 1); + } + } while (ret); + + writel(reg_tmp2, crt_membase + 0x01A4); + + pr_err("After tuning, current SDIO PLL = %x\n", + (readl(crt_membase + 0x01A8) & 0x03FF0000) >> 16); + + return 0; +} + +static void rtk_replace_mmc_host_ops(struct sdhci_host *host) +{ + host->mmc_host_ops.init_card = rtk_init_card; +} + +static const struct sdhci_ops rtk_sdhci_ops = { + .reset = rtk_sdhci_reset, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = rtk_sdhci_uhs_signaling, + .set_clock = rtk_sdhci_set_clock, + .platform_execute_tuning = rtk_sdhci_execute_tuning, +}; + +static const struct sdhci_pltfm_data sdhci_rtk_sdio_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50 | SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .ops = &rtk_sdhci_ops, +}; + +static struct sdhci_rtk_sdio_data sdhci_rtk_sdio_data = { + .pdata = &sdhci_rtk_sdio_pdata, +}; + +static const struct of_device_id sdhci_rtk_dt_match[] = { + {.compatible = "realtek,rtd1295-sdio", .data = &sdhci_rtk_sdio_data}, + {.compatible = "realtek,rtd1319-sdio", .data = &sdhci_rtk_sdio_data}, + {.compatible = "realtek,rtd1619b-sdio", .data = &sdhci_rtk_sdio_data}, + {} +}; + +MODULE_DEVICE_TABLE(of, sdhci_rtk_dt_match); + +static int sdhci_rtk_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct sdhci_rtk_sdio_data *soc_data; + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + int rc = 0; + + struct device_node *node = pdev->dev.of_node; + + pr_info("%s: build at : %s\n", DRIVER_NAME, utsname()->version); + + chip_id = get_rtd_chip_id(); + + drive_temp = 0; + SDIO_module_disable = false; + clock_enable = true; + SDIO_card = true; + + sdio_membase = of_iomap(node, 0); + if (!sdio_membase) + return -ENOMEM; + + crt_membase = of_iomap(node, 1); + if (!crt_membase) + return -ENOMEM; + + sdio_gpio_23 = devm_gpiod_get(&pdev->dev, "sdio", GPIOD_OUT_LOW); + if (IS_ERR(sdio_gpio_23)) { + dev_err(&pdev->dev, "sdio gpio missing or invalid\n"); + } else { + gpiod_direction_output(sdio_gpio_23, 0); + mdelay(150); + gpiod_direction_input(sdio_gpio_23); + } + + match = of_match_device(sdhci_rtk_dt_match, &pdev->dev); + if (!match) + return -EINVAL; + soc_data = match->data; + + rstc_sdio = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(rstc_sdio)) { + pr_warn("Failed to get sdio reset control(%ld)\n", PTR_ERR(rstc_sdio)); + rstc_sdio = NULL; + } + + clk_en_sdio = devm_clk_get(&pdev->dev, "sdio"); + if (IS_ERR(clk_en_sdio)) { + pr_warn("Failed to get sdio clk(%ld)\n", PTR_ERR(clk_en_sdio)); + clk_en_sdio = NULL; + } + + clk_en_sdio_ip = devm_clk_get(&pdev->dev, "sdio_ip"); + if (IS_ERR(clk_en_sdio_ip)) { + pr_warn("Failed to get sdio ip clk(%ld)\n", PTR_ERR(clk_en_sdio_ip)); + clk_en_sdio_ip = NULL; + } + + host = sdhci_pltfm_init(pdev, soc_data->pdata, 0); + if (IS_ERR(host)) + return PTR_ERR(host); + + rc = reset_control_deassert(rstc_sdio); + if (rc) { + pr_warn("Can not deassert sdio reset\n"); + goto err_add_host; + } + + rc = clk_prepare_enable(clk_en_sdio); + if (rc) { + pr_warn("Failed to enable sdio clock\n"); + goto err_add_host; + } + + rc = clk_prepare_enable(clk_en_sdio_ip); + if (rc) { + pr_warn("Failed to enable sdio ip clock\n"); + goto err_sdio_clk; + } + + rtk_sdhci_platform_init(); + + pltfm_host = sdhci_priv(host); + + rtk_replace_mmc_host_ops(host); + + rc = mmc_of_parse(host->mmc); + if (rc) + goto err_sdio_ip_clk; + + G_host = host; + + rc = sdhci_add_host(host); + if (rc) + goto err_sdio_ip_clk; + + return 0; + +err_sdio_ip_clk: + clk_disable_unprepare(clk_en_sdio_ip); +err_sdio_clk: + clk_disable_unprepare(clk_en_sdio); +err_add_host: + sdhci_pltfm_free(pdev); + return rc; +} + +static int sdhci_rtk_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xFFFFFFFF); + + sdhci_remove_host(host, dead); + sdhci_pltfm_free(pdev); + + return 0; +} + +static int sdhci_rtk_suspend(struct device *dev) +{ + pr_err("[SDIO] %s start\n", __func__); + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + drive_temp = readl(crt_membase + 0x01A0); + + if (clock_enable == true) { + struct sdhci_host *host = dev_get_drvdata(dev); + + sdhci_suspend_host(host); + } + pr_err("[SDIO] %s OK\n", __func__); + return 0; +} + +static void sdhci_rtk_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + pr_err("[SDIO] %s\n", __func__); + if (clock_enable == true) { + struct sdhci_host *host = dev_get_drvdata(dev); + + sdhci_suspend_host(host); + } +} + +static int sdhci_rtk_resume(struct device *dev) +{ + + struct sdhci_host *host = dev_get_drvdata(dev); + void __iomem *addr; + unsigned int val; + + host->clock = 0; + + pr_err("[SDIO] %s start\n", __func__); + if (clock_enable == true) { + addr = crt_membase + SDIO_CLKEN_REGOFF; + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1319) + writel(readl(crt_membase + 0x10A58) | 0x80000000, crt_membase + 0x10A58); + + if (get_SDIO_version() == 3 || get_SDIO_version() == 4) { + reset_control_deassert(rstc_sdio); + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(drive_temp, crt_membase + 0x01A0); + + rtk_sdhci_pad_driving_configure(); + + if (get_SDIO_version() == 3) { + rtk_sdhci_pll_configure(0x00564388, 0); + } else { + /* enlarge wait time for data */ + if (chip_id == CHIP_ID_RTD1619) + writel(0x1d, crt_membase + 0x10a58); + /* rtl8822bs won't stable with sdio clk 208Mhz. Adjust the clk to 200Mhz*/ + if(host->mmc->card->cis.device == 0x0000b822) + rtk_sdhci_pll_configure(0x00ae4388, 0); + else + rtk_sdhci_pll_configure(0x00b64388, 0); + } + if (chip_id != CHIP_ID_RTD1619B) + writel(0x00000000, crt_membase + 0x010A40); + writel(0x00000011, crt_membase + 0x010A34); + } else { + reset_control_deassert(rstc_sdio); + rtk_sdhci_pll_configure(0x00ae4388, 0); + writel(0x00000011, crt_membase + 0x010A34); + } + + if (chip_id == CHIP_ID_RTD1312C || chip_id == CHIP_ID_RTD1619B || chip_id == CHIP_ID_RTD1319 || chip_id == CHIP_ID_RTD1619) + writel(0x00000001, crt_membase + 0x010A10); + else + writel(0x00000003, crt_membase + 0x010A10); + + val = readl(addr); + val |= 1 << (SDIO_CLKEN_REGBIT); + writel(val, addr); + + val = readl(host->ioaddr + 0x28); + val |= 0x0f << 8; + writel(val, host->ioaddr + 0x28); + val = readl(host->ioaddr + 0x28); + + sdhci_resume_host(host); + } + + pr_err("[SDIO] %s OK\n", __func__); + + return 0; +} + +const struct dev_pm_ops sdhci_rtk_pmops = { + .suspend = sdhci_rtk_suspend, + .resume = sdhci_rtk_resume, +}; + +static struct platform_driver sdhci_rtk_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = sdhci_rtk_dt_match, + .pm = &sdhci_rtk_pmops, + }, + .probe = sdhci_rtk_probe, + .remove = sdhci_rtk_remove, + .shutdown = sdhci_rtk_shutdown, +}; +module_platform_driver(sdhci_rtk_driver); diff --git a/drivers/mmc/host/sdhci-rtk.h b/drivers/mmc/host/sdhci-rtk.h new file mode 100644 index 000000000000..ebcf1976f76f --- /dev/null +++ b/drivers/mmc/host/sdhci-rtk.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek SDIO host driver + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#ifndef _DRIVERS_MMC_SDHCI_OF_RTK_H +#define _DRIVERS_MMC_SDHCI_OF_RTK_H + +#include "sdhci.h" + +void disable_sdio_irq(struct sdhci_host *host); +void rtk_sdhci_close_clk(void); +void rtk_register_set(void); + +#endif /* _DRIVERS_MMC_SDHCI_OF_RTK_H */ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6cdadbb3accd..24e681815345 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver @@ -4145,7 +4148,11 @@ int sdhci_setup_host(struct sdhci_host *host) override_timeout_clk = host->timeout_clk; +#if defined(MY_DEF_HERE) + if (host->version > SDHCI_SPEC_300) { +#else /* MY_DEF_HERE */ if (host->version > SDHCI_SPEC_420) { +#endif /* MY_DEF_HERE */ pr_err("%s: Unknown controller version (%d). You may experience problems.\n", mmc_hostname(mmc), host->version); } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 69fb5dafa9ad..0cff57316281 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright © 1999-2010 David Woodhouse @@ -24,6 +27,10 @@ #include #include +#ifdef MY_DEF_HERE +#include +#include +#endif /* MY_DEF_HERE */ #include "mtdcore.h" @@ -51,6 +58,9 @@ static int mtdchar_open(struct inode *inode, struct file *file) int ret = 0; struct mtd_info *mtd; struct mtd_file_info *mfi; +#ifdef MY_DEF_HERE + int syno_print_mtd_access_log = 1; +#endif /* MY_DEF_HERE */ pr_debug("MTD_open\n"); @@ -61,6 +71,22 @@ static int mtdchar_open(struct inode *inode, struct file *file) mutex_lock(&mtd_mutex); mtd = get_mtd_device(NULL, devnum); +#ifdef MY_DEF_HERE +#ifdef MY_DEF_HERE + if (!strcmp("vendor", mtd->name)) { + syno_print_mtd_access_log = 0; + } +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + if (!strcmp("RedBoot Config", mtd->name)) { + syno_print_mtd_access_log = 0; + } +#endif /* MY_DEF_HERE */ + if (syno_print_mtd_access_log) { + printk(KERN_ERR"open mtd (%s), process=%s\n", mtd->name, current->comm); + } +#endif /* MY_DEF_HERE */ + if (IS_ERR(mtd)) { ret = PTR_ERR(mtd); goto out; @@ -100,9 +126,28 @@ static int mtdchar_close(struct inode *inode, struct file *file) { struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; +#ifdef MY_DEF_HERE + int syno_print_mtd_access_log = 1; +#endif /* MY_DEF_HERE */ pr_debug("MTD_close\n"); +#ifdef MY_DEF_HERE +#ifdef MY_DEF_HERE + if (!strcmp("vendor", mtd->name)) { + syno_print_mtd_access_log = 0; + } +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + if (!strcmp("RedBoot Config", mtd->name)) { + syno_print_mtd_access_log = 0; + } +#endif /* MY_DEF_HERE */ + if (syno_print_mtd_access_log) { + printk(KERN_ERR"close mtd (%s), process=%s\n", mtd->name, current->comm); + } +#endif /* MY_DEF_HERE */ + /* Only sync if opened RW */ if ((file->f_mode & FMODE_WRITE)) mtd_sync(mtd); @@ -222,19 +267,103 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count, return total_retlen; } /* mtdchar_read */ +#ifdef MY_DEF_HERE +static int syno_write_buf_size = 0x1000; + +char *kbuf; +int write_kbuf_len; +struct semaphore write_kbuf_sem; + +static int do_syno_mtd_alloc(bool blMalloc) +{ + int retval = 0; + + down(&write_kbuf_sem); + if (blMalloc) { + if (write_kbuf_len) + goto End; + + write_kbuf_len = syno_write_buf_size; + kbuf = kmalloc(write_kbuf_len, GFP_KERNEL); + if (!kbuf) { + printk(KERN_NOTICE "%s:%d(%s) malloc fail write_kbuf_len=[%d], kbuf=[%p]\n", __FILE__, __LINE__, __func__, write_kbuf_len, kbuf); + write_kbuf_len = 0x0; + retval = -ENOMEM; + } + } else { + if (!write_kbuf_len) + goto End; + write_kbuf_len = 0x0; + kfree(kbuf); + kbuf = NULL; + } +End: + up(&write_kbuf_sem); + return retval; +} + +/** + * This function accuire or release buffer for mtd driver to write flash. + * The updater should call SYNOMTDAlloc() before doing system upgrade, + * and this buffer should not be released before upgrade finished. + * Otherwise, if the buffer is malloc-ed and released within a dd write, + * the kernel may malloc failed somehow. + * + * @author cnliu + * @param blMalloc + * A boolean variable to indicate malloc or release. + * true: To malloc buffer for mtd driver to write before doing mtd_write(). + * false: After mtd_write(), we need to free buffer for mtd driver. + * + * @return + * Upon successful malloc, SYNOMTDAlloc() return 0. + * Otherwise return -ENOMEM. + * + * @example + * if (SYNOMTDAlloc(true) == 0) { + * system("dd if=zImage of=/dev/mtd1 bs=128k"); + * SYNOMTDAlloc(false); + * } + * + * @see init_mtdchar + * @see mtd_write + * @see write_kbuf_sem + * @see lnxsdk/main/updater.c + */ +SYSCALL_DEFINE1(syno_mtd_alloc, bool, blMalloc) +{ + return do_syno_mtd_alloc(blMalloc); +} /* sys_syno_mtd_alloc */ + +#endif /* MY_DEF_HERE */ + static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; +#ifdef MY_DEF_HERE + // do nothing +#else /* MY_DEF_HERE */ size_t size = count; char *kbuf; +#endif /* MY_DEF_HERE */ size_t retlen; size_t total_retlen=0; int ret=0; int len; pr_debug("MTD_write\n"); +#ifdef MY_DEF_HERE + if (syno_write_buf_size < mtd->writesize) { + printk(KERN_ERR "mtd kmalloc size small than mtd driver minimal write size !!\n"); + WARN_ON(1); + syno_write_buf_size = mtd->writesize; + if (write_kbuf_len) + do_syno_mtd_alloc(false); + printk(KERN_ERR "mtd kmalloc size replace with mtd driver minimal write size !!\n"); + } +#endif /* MY_DEF_HERE */ if (*ppos >= mtd->size) return -ENOSPC; @@ -245,15 +374,35 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c if (!count) return 0; +#ifdef MY_DEF_HERE + if (!write_kbuf_len) { + ret = do_syno_mtd_alloc(true); + if (ret != 0) + return ret; + } + down(&write_kbuf_sem); +#else /* MY_DEF_HERE */ kbuf = mtd_kmalloc_up_to(mtd, &size); if (!kbuf) return -ENOMEM; +#endif /* MY_DEF_HERE */ while (count) { +#ifdef MY_DEF_HERE + if (count > syno_write_buf_size) + len = syno_write_buf_size; + else + len = count; +#else /* MY_DEF_HERE */ len = min_t(size_t, count, size); +#endif /* MY_DEF_HERE */ if (copy_from_user(kbuf, buf, len)) { +#ifdef MY_DEF_HERE + up(&write_kbuf_sem); +#else /* MY_DEF_HERE */ kfree(kbuf); +#endif /* MY_DEF_HERE */ return -EFAULT; } @@ -300,12 +449,20 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c buf += retlen; } else { +#ifdef MY_DEF_HERE + up(&write_kbuf_sem); +#else /* MY_DEF_HERE */ kfree(kbuf); +#endif /* MY_DEF_HERE */ return ret; } } +#ifdef MY_DEF_HERE + up(&write_kbuf_sem); +#else /* MY_DEF_HERE */ kfree(kbuf); +#endif /* MY_DEF_HERE */ return total_retlen; } /* mtdchar_write */ @@ -662,6 +819,10 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) case MTDFILEMODE: case BLKPG: case BLKRRPART: +#ifdef MY_DEF_HERE + case MEMMODIFYPARTINFO: + case MEMMODIFYFISINFO: +#endif /* MY_DEF_HERE */ break; /* "dangerous" commands */ @@ -951,6 +1112,41 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) break; } +#ifdef MY_DEF_HERE + case MEMMODIFYPARTINFO: + { + struct erase_info_user einfo32; + + if (copy_from_user(&einfo32, argp, sizeof(struct erase_info_user))) + return -EFAULT; + + ret = SYNOMTDModifyPartInfo(mtd, einfo32.start, einfo32.length); + + break; + } + + case MEMMODIFYFISINFO: + { + struct SYNO_MTD_FIS_INFO SynoMtdFisInfo; + + if (strcmp(mtd->name, "FIS directory") && strcmp(mtd->name, "FIS_directory")) { // cannot apply on other flash partitions + return -EOPNOTSUPP; + } + + if (copy_from_user(&SynoMtdFisInfo, (struct SYNO_MTD_FIS_INFO *)arg, sizeof(struct SYNO_MTD_FIS_INFO))) { + return -EFAULT; + } + + if (!SynoMtdFisInfo.name[0]) { // sanity check + return -EFAULT; + } + + ret = SYNOMTDModifyFisInfo(mtd, SynoMtdFisInfo); + + break; + } +#endif /* MY_DEF_HERE */ + /* This ioctl is being deprecated - it truncates the ECC layout */ case ECCGETLAYOUT: { @@ -1222,6 +1418,11 @@ int __init init_mtdchar(void) return ret; } +#ifdef MY_DEF_HERE + /* Allocate buffer and init spinlock */ + sema_init(&write_kbuf_sem, 1); +#endif /* MY_DEF_HERE */ + return ret; } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 1c8c40728678..d348560d2b64 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Core registration and callback routines for MTD @@ -1085,6 +1088,13 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) struct erase_info adjinstr; int ret; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MTD_PSTORE + unsigned int erasesize = master->erasesize; +#endif /* CONFIG_MTD_PSTORE */ +#endif /* MY_DEF_HERE */ + + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; adjinstr = *instr; @@ -1099,6 +1109,11 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) if (!instr->len) return 0; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MTD_PSTORE + master->erasesize = min(master->erasesize, mtd->erasesize); +#endif /* CONFIG_MTD_PSTORE */ +#endif /* MY_DEF_HERE */ ledtrig_mtd_activity(); if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) { @@ -1122,6 +1137,11 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) } } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_MTD_PSTORE + master->erasesize = erasesize; +#endif /* CONFIG_MTD_PSTORE */ +#endif /* MY_DEF_HERE */ return ret; } EXPORT_SYMBOL_GPL(mtd_erase); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 95d47422bbf2..c07a5f9681b7 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Simple MTD partitioning layer @@ -17,9 +20,24 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "mtdcore.h" +#ifdef MY_ABC_HERE +extern unsigned char grgbLanMac[SYNO_MAC_MAX_NUMBER][16]; +extern int giVenderFormatVersion; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern char gszSerialNum[]; +extern char gszCustomSerialNum[]; +#define SYNO_SN_TAG "SN=" +#define SYNO_CHKSUM_TAG "CHK=" +#define SYNO_SN_12_SIG SYNO_SN_TAG // signature for 12 serial number +#endif /* MY_ABC_HERE */ + /* * MTD methods which simply translate the effective address and pass through * to the _real_ device. @@ -31,6 +49,379 @@ static inline void free_partition(struct mtd_info *mtd) kfree(mtd); } +#ifdef MY_ABC_HERE +#define SYNO_MAC_LEN 6 +#define SYNO_MAC_CHK_LEN 1 +#define SYNO_MAC_MAX_NUM 8 +#define SYNO_MAC_BUF_LEN 16 +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define SYNO_VENDER_HEADER_SIZE 0x10 +#define SYNO_VENDER_SN_SIZE 0x20 +#define SYNO_VENDER_CUSTSN_SIZE 0x20 +#define SYNO_VENDER_TESTFLAG_SIZE 0x80 +#define SYNO_VENDER_MAC_SIZE (SYNO_MAC_LEN + SYNO_MAC_CHK_LEN) + +#define SYNO_VENDER_SN_OFFSET SYNO_VENDER_HEADER_SIZE +#define SYNO_VENDER_CUSTSN_OFFSET (SYNO_VENDER_SN_OFFSET + SYNO_VENDER_SN_SIZE) +#define SYNO_VENDER_TESTFLAG_OFFSET (SYNO_VENDER_CUSTSN_OFFSET + SYNO_VENDER_CUSTSN_SIZE) +#define SYNO_VENDER_MAC_OFFSET (SYNO_VENDER_TESTFLAG_OFFSET + SYNO_VENDER_TESTFLAG_SIZE) + +#define SYNO_VENDER_MAGIC_HEADER "SYNO!!!!" +#define SYNO_VENDER_SN_TOKEN "SN=" +#define SYNO_VENDER_SN_CKSUM_TOKEN "CHK=" + +#ifdef MY_ABC_HERE +static int syno_vender_sn_verify(char *szSN) +{ + int errRes = 0; + char *pSNum = NULL; + char *pCksum = NULL; + unsigned int uiCalChksum = 0, uiReadChksum = 0; + + if (NULL == szSN) { + errRes = -EINVAL; + goto END; + } + + pSNum = strstr(szSN, SYNO_VENDER_SN_TOKEN); + pCksum = strstr(szSN, SYNO_VENDER_SN_CKSUM_TOKEN); + + if (NULL == pSNum || NULL == pCksum) { + errRes = -EBADF; + goto END; + } + + pSNum += strlen(SYNO_VENDER_SN_TOKEN); + pCksum += strlen(SYNO_VENDER_SN_CKSUM_TOKEN); + + while ( '\0' != *pCksum) { + if ('0' > *pCksum || '9' < *pCksum) { + uiReadChksum = 0; + break; + } + + uiReadChksum = (uiReadChksum * 10) + (unsigned int)(*pCksum - '0'); + pCksum++; + } + + while (',' != *pSNum && '\0' != *pSNum) { + uiCalChksum += (unsigned int) *pSNum; + pSNum++; + } + + if ((0 == uiCalChksum) || (uiCalChksum != uiReadChksum)) { + errRes = -EBADF; + goto END; + } + + *pSNum = '\0'; +END: + return errRes; +} + +static int syno_vender_cust_sn_verify(char *szCustSN) +{ + int errRes = 0; + unsigned char uCalCksum = 0; + int iCnt = 0; + + if (NULL == szCustSN) { + errRes = -EINVAL; + goto END; + } + + for (iCnt=0; iCnt<(SYNO_VENDER_CUSTSN_SIZE - 1); iCnt++) { + uCalCksum += szCustSN[iCnt]; + } + + if ((0 == uCalCksum) || + (uCalCksum != szCustSN[(SYNO_VENDER_CUSTSN_SIZE - 1)])) { + errRes = -EBADF; + goto END; + } + + szCustSN[(SYNO_VENDER_CUSTSN_SIZE - 1)] = '\0'; + +END: + return errRes; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int syno_vender_mac_parser(u_char* rgbszBuf) +{ + int errRes = 0; + unsigned char ucMacBuf[SYNO_VENDER_MAC_SIZE] = {0}; + unsigned char ucCksum = 0; + int iCnt = 0, iNrZeroBit, iNrFFBit = 0; + int iMacNum = 0; + + if (!rgbszBuf) { + errRes = -EINVAL; + goto END; + } + + while(SYNO_MAC_MAX_NUM > iMacNum){ + memcpy(ucMacBuf, (rgbszBuf+(iMacNum*SYNO_VENDER_MAC_SIZE)), sizeof(ucMacBuf)); + ucCksum = 0; + + for (iCnt = 0, iNrZeroBit = 0, iNrFFBit = 0; iCnt < SYNO_MAC_LEN; iCnt++) { + if (0 == ucMacBuf[iCnt]) { + iNrZeroBit++; + } else if (0xff == ucMacBuf[iCnt]) { + iNrFFBit++; + } + ucCksum += ucMacBuf[iCnt]; + } + + if (SYNO_MAC_LEN == iNrFFBit) { + break; + } + + if ((SYNO_MAC_LEN > iNrZeroBit) && (ucCksum == ucMacBuf[SYNO_MAC_LEN])) { + snprintf(grgbLanMac[iMacNum], sizeof(grgbLanMac), + "%02x%02x%02x%02x%02x%02x", + ucMacBuf[0], + ucMacBuf[1], + ucMacBuf[2], + ucMacBuf[3], + ucMacBuf[4], + ucMacBuf[5]); + + printk("vender Mac%d address : %c%c:%c%c:%c%c:%c%c:%c%c:%c%c\n", iMacNum, + grgbLanMac[iMacNum][0], + grgbLanMac[iMacNum][1], + grgbLanMac[iMacNum][2], + grgbLanMac[iMacNum][3], + grgbLanMac[iMacNum][4], + grgbLanMac[iMacNum][5], + grgbLanMac[iMacNum][6], + grgbLanMac[iMacNum][7], + grgbLanMac[iMacNum][8], + grgbLanMac[iMacNum][9], + grgbLanMac[iMacNum][10], + grgbLanMac[iMacNum][11]); + + } else { + grgbLanMac[iMacNum][0] = '\0'; + } + + iMacNum++; + } + +END: + return errRes; +} +#endif /* MY_ABC_HERE */ + +static int syno_vender_v2_parser(struct mtd_info *mtd_vender) +{ + int errRes = -1; + u_char rgbszBuf[128]; + size_t retlen; + char szHeader[SYNO_VENDER_HEADER_SIZE] = {0}; + char szSN[SYNO_VENDER_SN_SIZE] = {0}; + char szCustSN[SYNO_VENDER_CUSTSN_SIZE] = {0}; + u_char* ptr = NULL; + + memset(rgbszBuf, 0, 128*sizeof(u_char)); + mtd_read(mtd_vender, 0, 128, &retlen, rgbszBuf); + ptr = rgbszBuf; + + // check header + memcpy(szHeader, ptr, SYNO_VENDER_HEADER_SIZE); + if (0 != strncmp(szHeader, SYNO_VENDER_MAGIC_HEADER, strlen(SYNO_VENDER_MAGIC_HEADER))) { + errRes = -ENOENT; + goto END; + } + +#ifdef MY_ABC_HERE + memset(gszSerialNum, 0, 32); + memset(gszCustomSerialNum, 0, 32); + + // read SN + ptr += SYNO_VENDER_HEADER_SIZE; + memcpy(szSN, ptr, sizeof(szSN)); + errRes = syno_vender_sn_verify(szSN); + if (0 == errRes) { + snprintf(gszSerialNum, 32, "%s", szSN + strlen(SYNO_VENDER_SN_TOKEN)); + } + printk("Serial Number='%s'", gszSerialNum); + + // read custom SN + ptr += SYNO_VENDER_SN_SIZE; + memcpy(szCustSN, ptr, sizeof(szCustSN)); + errRes = syno_vender_cust_sn_verify(szCustSN); + if (0 == errRes) { + snprintf(gszCustomSerialNum, 32, "%s", szCustSN); + printk("Custom Serial Number: %s\n", gszCustomSerialNum); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + memset(rgbszBuf, 0, 128*sizeof(u_char)); + mtd_read(mtd_vender, SYNO_VENDER_MAC_OFFSET, (SYNO_MAC_MAX_NUM*SYNO_VENDER_MAC_SIZE), &retlen, rgbszBuf); + + // read MACs + syno_vender_mac_parser(rgbszBuf); +#endif /* MY_ABC_HERE */ + + errRes = 0; +END: + return errRes; +} + +static int syno_vender_v1_parser(struct mtd_info *mtd_vender) +{ + u_char rgbszBuf[128]; + size_t retlen; + + int i = 0, x = 0; + unsigned int Sum; + u_char ucSum; +#ifdef MY_ABC_HERE + int n = 0; + int MacNumber = 4; + char rgbLanMac[SYNO_MAC_MAX_NUMBER][6]; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + char szSerialBuffer[32]; + char *ptr; + char szSerial[32]; + char szCheckSum[32]; + unsigned long ulchksum = 0; + unsigned long ulTemp = 0; +#endif /* MY_ABC_HERE */ + + mtd_read(mtd_vender, 0, 128, &retlen, rgbszBuf); + +#ifdef MY_ABC_HERE + x = 0; + for (n = 0; n < MacNumber; n++) { + for (Sum=0,ucSum=0,i=0; i<6; i++) { + Sum+=rgbszBuf[i+x]; + ucSum+=rgbszBuf[i+x]; + rgbLanMac[n][i] = rgbszBuf[i+x]; + } + x+=6; + + if (0==Sum) { + printk("vender Mac%d doesn't set ucSum:0x%02x Buf:0x%02x Sum:%d.\n", + n, ucSum, rgbszBuf[x], Sum); + } else if (ucSum!=rgbszBuf[x]) { + printk("vender Mac%d checksum error ucSum:0x%02x Buf:0x%02x Sum:%d.\n", + n, ucSum, rgbszBuf[x], Sum); + grgbLanMac[n][0] = '\0'; + } else { + printk("vender Mac%d address : %02x:%02x:%02x:%02x:%02x:%02x\n",n,rgbLanMac[n][0], + rgbLanMac[n][1], + rgbLanMac[n][2], + rgbLanMac[n][3], + rgbLanMac[n][4], + rgbLanMac[n][5]); + snprintf(grgbLanMac[n], sizeof(grgbLanMac), + "%02x%02x%02x%02x%02x%02x", + rgbLanMac[n][0], + rgbLanMac[n][1], + rgbLanMac[n][2], + rgbLanMac[n][3], + rgbLanMac[n][4], + rgbLanMac[n][5]); + } + + x++; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + memset(szSerial, 0, sizeof(szSerial)); + memset(szCheckSum, 0, sizeof(szCheckSum)); + memset(gszSerialNum, 0, 32); + memcpy(szSerialBuffer, &(rgbszBuf[32]), 32); + + // this is new defined SN + if (0 == strncmp(szSerialBuffer, SYNO_SN_12_SIG,strlen(SYNO_SN_12_SIG))) { + //paring serial number with format 'SN=1350KKN99999' + ptr = strstr(szSerialBuffer, SYNO_SN_TAG); + if (NULL == ptr) { + printk("no serial tag found, serial buffer='%s'\n", szSerialBuffer); + goto SKIP_SERIAL; + } + ptr += strlen(SYNO_SN_TAG); + i = 0; + while (0 != *ptr && ',' != *ptr) { + szSerial[i++] = *ptr; + ptr++; + } + szSerial[i] = '\0'; + + //paring serial number with format 'CHK=125' + ptr = strstr(szSerialBuffer, SYNO_CHKSUM_TAG); + if (NULL == ptr) { + printk("no checksum tag found, serial buffer='%s'\n", szSerialBuffer); + goto SKIP_SERIAL; + } + ptr += strlen(SYNO_CHKSUM_TAG); + i = 0; + while (0 != *ptr && ',' != *ptr) { + szCheckSum[i++] = *ptr; + ptr++; + } + szCheckSum[i] = '\0'; + + //calculate checksum + for (i = 0 ; i < strlen(szSerial); i++) { + ulchksum += szSerial[i]; + } + + //------ check checksum ------ + if (0 != kstrtoul(szCheckSum, 10, &ulTemp)) { + printk("string conversion error: '%s'\n", szCheckSum); + goto SKIP_SERIAL; + } else if (ulchksum != ulTemp) { + printk("serial number checksum error, serial='%s', checksum='%lu' not '%lu'\n", szSerial, ulchksum, ulTemp); + goto SKIP_SERIAL; + } + } else { + unsigned char ucChkSum = 0; + //calculate checksum + for (i = 0 ; i < 10; i++) { + ucChkSum += szSerialBuffer[i]; + } + //------ check checksum ------ + if (ucChkSum != szSerialBuffer[10]) { + printk("serial number checksum error, serial='%s', checksum='%d' not '%d'", szSerialBuffer, ucChkSum, szSerialBuffer[10]); + goto SKIP_SERIAL; + } else { + memcpy(szSerial, szSerialBuffer, 10); + } + } + snprintf(gszSerialNum, 32, "%s", szSerial); +SKIP_SERIAL: + printk("Serial Number='%s'", gszSerialNum); + + //read custom serial number out, it is in the vender partion shift 64 bytes. + x = 64; + for (Sum=0,ucSum=0,i=0; i<31; i++) { + Sum+=rgbszBuf[i+x]; + ucSum+=rgbszBuf[i+x]; + gszCustomSerialNum[i] = rgbszBuf[i+x]; + } + x+=31; + if (Sum==0 || ucSum!=rgbszBuf[x]) { + for (i=0; i<32; i++) { + gszCustomSerialNum[i] = 0; + } + } else { + printk("Custom Serial Number: %s\n", gszCustomSerialNum); + } +#endif /* MY_ABC_HERE */ + + return 0; +} +#endif /* MY_ABC_HERE) || MY_ABC_HERE */ + static struct mtd_info *allocate_partition(struct mtd_info *parent, const struct mtd_partition *part, int partno, uint64_t cur_offset) @@ -209,6 +600,22 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, } out_register: +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + if ((memcmp(part->name, "vender", 7)==0) || + (memcmp(part->name, "vendor", 7)==0)) { + + switch (giVenderFormatVersion) { + case 1: + syno_vender_v1_parser(child); + break; + case 2: + syno_vender_v2_parser(child); + break; + default: + printk(KERN_ERR "Undefined verder version %d\n", giVenderFormatVersion); + } + } +#endif /* MY_ABC_HERE || MY_ABC_HERE */ return child; } @@ -716,3 +1123,21 @@ uint64_t mtd_get_device_size(const struct mtd_info *mtd) return master->size; } EXPORT_SYMBOL_GPL(mtd_get_device_size); + +#ifdef MY_DEF_HERE +int SYNOMTDModifyPartInfo(struct mtd_info *mtd, unsigned long offset, unsigned long length) +{ + struct mtd_info *master = mtd_get_master((struct mtd_info *)mtd); + + mtd->part.offset = offset; + mtd->part.offset &= master->size-1; + + mtd->part.size = length; + + if (mtd->part.offset + mtd->part.size > master->size) { + return -EFAULT; + } + + return 0; +} +#endif /* MY_DEF_HERE */ diff --git a/drivers/mtd/mtdpstore.c b/drivers/mtd/mtdpstore.c index a3ae8778f6a9..7caa6f8dbd50 100644 --- a/drivers/mtd/mtdpstore.c +++ b/drivers/mtd/mtdpstore.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #define dev_fmt(fmt) "mtdoops-pstore: " fmt @@ -182,13 +185,24 @@ static int mtdpstore_block_is_removed(struct mtdpstore_context *cxt, static int mtdpstore_erase_do(struct mtdpstore_context *cxt, loff_t off) { +#if defined(MY_DEF_HERE) + struct pstore_blk_config *info = &cxt->info; +#endif /* MY_DEF_HERE */ struct mtd_info *mtd = cxt->mtd; struct erase_info erase; int ret; +#if defined(MY_DEF_HERE) + unsigned int erasesize = cxt->mtd->erasesize; + cxt->mtd->erasesize = 4096; /* force 4k erasesize */ +#endif /* MY_DEF_HERE */ off = ALIGN_DOWN(off, cxt->mtd->erasesize); dev_dbg(&mtd->dev, "try to erase off 0x%llx\n", off); +#if defined(MY_DEF_HERE) + erase.len = info->kmsg_size; +#else /* MY_DEF_HERE */ erase.len = cxt->mtd->erasesize; +#endif /* MY_DEF_HERE */ erase.addr = off; ret = mtd_erase(cxt->mtd, &erase); if (!ret) @@ -197,6 +211,10 @@ static int mtdpstore_erase_do(struct mtdpstore_context *cxt, loff_t off) dev_err(&mtd->dev, "erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", (unsigned long long)erase.addr, (unsigned long long)erase.len, cxt->info.device); +#if defined(MY_DEF_HERE) + + cxt->mtd->erasesize = erasesize; +#endif /* MY_DEF_HERE */ return ret; } @@ -219,7 +237,11 @@ static ssize_t mtdpstore_erase(size_t size, loff_t off) /* If the block still has valid data, mtdpstore do erase lazily */ if (likely(mtdpstore_block_is_used(cxt, off))) { mtdpstore_mark_removed(cxt, off); +#if defined(MY_DEF_HERE) + /* return 0; */ +#else /* MY_DEF_HERE */ return 0; +#endif /* MY_DEF_HERE */ } /* all zones are unused, erase it */ @@ -348,8 +370,13 @@ static ssize_t mtdpstore_read(char *buf, size_t size, loff_t off) mtdpstore_mark_unused(cxt, off); else mtdpstore_mark_used(cxt, off); - +#if defined(MY_DEF_HERE) +#if 0 mtdpstore_security(cxt, off); +#endif +#else /* MY_DEF_HERE */ + mtdpstore_security(cxt, off); +#endif /* MY_DEF_HERE */ return retlen; } @@ -405,9 +432,18 @@ static void mtdpstore_notify_add(struct mtd_info *mtd) * is designed on it. */ if (mtd->erasesize < info->kmsg_size) { +#ifdef MY_DEF_HERE + mtd->erasesize = info->kmsg_size; + // mtd->erasesize determines how many pstore zone to be erase together. + // for more information, please reference the following statement, + // u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size; + dev_err(&mtd->dev, "force setting eraseblock size of MTD partition %d to KMSG_SIZE\n", + mtd->index); +#else /* MY_DEF_HERE */ dev_err(&mtd->dev, "eraseblock size of MTD partition %d too small\n", mtd->index); return; +#endif /* MY_DEF_HERE */ } if (unlikely(info->kmsg_size % mtd->writesize)) { dev_err(&mtd->dev, "record size %lu KB must align to write size %d KB\n", diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 6c46f25b57e2..ffbed216302d 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -395,6 +395,26 @@ config MTD_NAND_MTK Enables support for NAND controller on MTK SoCs. This controller is found on mt27xx, mt81xx, mt65xx SoCs. +if SYNO_LSP_RTD1619B +config MTD_NAND_RTK + tristate "RTK NAND controller" + help + Enables support for NAND controller on Realtek SoCs. + This controller is found on rtd12xx, rtd13xx SoCs. + +config MTD_NAND_RTK_BBM + bool "RTK NAND Flash Bad Block Management" + depends on MTD_NAND_RTK + help + Enables RTK Bad Block Management. + +config MTD_NAND_RTK_BBTCRC + bool "RTK BBT CRC Check" + depends on MTD_NAND_RTK_BBM + help + Enables RTK CRC check for BBT. + +endif # SYNO_LSP_RTD1619B config MTD_NAND_MXIC tristate "Macronix raw NAND controller" depends on HAS_IOMEM || COMPILE_TEST diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 2930f5b9015d..f3d86d29d594 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -58,6 +58,10 @@ obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_MTD_NAND_RTK) += rtk_nand.o +obj-$(CONFIG_MTD_NAND_RTK_BBM) += rtk_bbm.o +endif # CONFIG_SYNO_LSP_RTD1619B nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs += nand_onfi.o diff --git a/drivers/mtd/nand/raw/rtk_bbm.c b/drivers/mtd/nand/raw/rtk_bbm.c new file mode 100644 index 000000000000..8c10ccd8605d --- /dev/null +++ b/drivers/mtd/nand/raw/rtk_bbm.c @@ -0,0 +1,499 @@ +/* + * RTK NAND Flash controller driver. + * Copyright (C) 2020 Realtek Inc. + * Authors : PK Chuang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_nand.h" + +#if defined(CONFIG_MTD_NAND_RTK_BBTCRC) +#define CRCLEN 4 +#else +#define CRCLEN 0 +#endif + +#define TAGOFFSET 4 + +#define BBT1 64 +#define BBT2 128 + +static inline struct rtk_nf *to_rtk_nand(struct nand_chip *chip) +{ + return container_of(chip, struct rtk_nf, chip); +} + +static unsigned int rtk_nf_page_to_block(struct nand_chip *chip, int page) +{ + struct nand_memory_organization *memorg = &chip->base.memorg; + + return page / memorg->pages_per_eraseblock; +} + +static unsigned int rtk_nf_page_offset_in_block(struct nand_chip *chip, + int page) +{ + struct nand_memory_organization *memorg = &chip->base.memorg; + + return page % memorg->pages_per_eraseblock; +} + +static int rtk_nf_bbt_page_count(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + u32 byte, p = 1; + + byte = sizeof(BB_t) * nf->RBA; + while ( (byte = byte - mtd->writesize) > 0) { + p++; + } + + return p; +} + +#ifdef CONFIG_MTD_NAND_RTK_BBTCRC +static int rtk_nf_bbt_crc_calculate(struct rtk_nf *nf) +{ + BB_t *bbt = nf->bbt; + char hash_temp[64] = {0}; + u32 hash_value_temp = 0; + int i; + + for (i=0; iRBA; i++) { + if ((bbt[i].BB_die != BB_DIE_INIT) && + (bbt[i].bad_block != BB_INIT)) { + hash_value_temp = hash_value_temp + + bbt[i].BB_die + bbt[i].bad_block + + bbt[i].RB_die + bbt[i].remap_block; + } + } + + sprintf(hash_temp, "%u", hash_value_temp); + + return crc32(~0, (u8 *)hash_temp, sizeof(hash_temp)); +} +#endif + +int rtk_nf_get_realpage(struct nand_chip *chip, int page) +{ + struct nand_memory_organization *memorg = &chip->base.memorg; + struct rtk_nf *nf = to_rtk_nand(chip); + BB_t *bbt = nf->bbt; + int offset, block; + int i; + + offset = rtk_nf_page_offset_in_block(chip, page); + block = rtk_nf_page_to_block(chip, page); + + for (i=0; iRBA; i++) { + if (bbt[i].bad_block != BB_INIT) { + if (block == bbt[i].bad_block) { + block = bbt[i].remap_block; + break; + } + } + } + + return (block * memorg->pages_per_eraseblock) + offset; +} + +static void rtk_nf_update_BBT(struct nand_chip *chip, int o_blk, + int s_blk, int m_blk) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + u64 blk = nf->size; + + do_div(blk, mtd->erasesize); + + if (s_blk == 0) { + nf->bbt[(blk-1) - m_blk].bad_block = BAD_RESERVED; + nf->bbt[(blk-1) - m_blk].BB_die = 0; + } + else { + if (o_blk != s_blk) { + nf->bbt[(blk-1) - s_blk].bad_block = BAD_RESERVED; + nf->bbt[(blk-1) - s_blk].BB_die = 0; + } + + nf->bbt[(blk-1) - m_blk].bad_block = o_blk; + nf->bbt[(blk-1) - m_blk].BB_die = 0; + } + + return; +} + +static int rtk_nf_backup_block(struct nand_chip *chip, int src_b, int map_b, + int offset, int mode) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct device *dev = nf->dev; + struct rtk_buffer *buffer = &nf->nandbuf; + int s_page = src_b * 64; + int b_page = map_b * 64; + char *buf; + int ret; + int i; + + dev_info(dev, "RTK %s(%d) backup %d to %d.\n", + __func__, __LINE__, src_b, map_b); + + buf = kmalloc(mtd->writesize, GFP_KERNEL); + if (!buf) { + ret = -2; + goto rtk_nf_backup_block_exit; + } + + chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, b_page); + + for (i=0; i<64; i++) { + ret = chip->ecc.read_oob(chip, s_page + i); + if (ret == -1) + goto rtk_nf_backup_block_exit; + else if ((ret == 1) || ((i == offset) && (mode == NFWRITE))) + continue; + + memcpy(buf, buffer->dataBuf, mtd->writesize); + + ret = chip->ecc.write_page(chip, buf, 0, s_page + i); + if (ret < 0) + goto rtk_nf_backup_block_exit; + } + +rtk_nf_backup_block_exit: + if (buf) + kfree(buf); + + return ret; +} + +static int rtk_nf_find_available_reserved_block(struct nand_chip *chip) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + struct device *dev = nf->dev; + int i; + + for (i = 0; i < nf->RBA; i++) { + if (nf->bbt[i].bad_block == BB_INIT) { + return nf->bbt[i].remap_block; + } + } + + dev_err(dev, "RTK %s(%d) No available reserved block.\n", + __func__, __LINE__); + + return -1; +} + +static int rtk_nf_write_bbt(struct nand_chip *chip, unsigned int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + struct device *dev = nf->dev; + u8 *tmp; + u32 p, len, wlen; + int ret; + int i = 0; +#ifdef CONFIG_MTD_NAND_RTK_BBTCRC + u32 crc = 0; +#endif + + p = rtk_nf_bbt_page_count(chip); + + len = CRCLEN + sizeof(BB_t)*nf->RBA; + tmp = kmalloc(len, GFP_KERNEL); + if (!tmp) { + dev_err(dev, "RTK %s(%d) alloc tmp fail.\n", + __func__, __LINE__); + return -ENOMEM; + } + + chip->legacy.select_chip(chip, 0); + + chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, page); +#ifdef CONFIG_MTD_NAND_RTK_BBTCRC + crc = rtk_nf_bbt_crc_calculate(nf); + memcpy(tmp, &crc, 4); +#endif + memcpy(tmp + CRCLEN, nf->bbt, sizeof(BB_t)*nf->RBA); + + while (len > 0) { + memset(buffer->dataBuf, 0xff, mtd->writesize + mtd->oobsize); + + wlen = (len > mtd->writesize) ? mtd->writesize : len; + *(buffer->dataBuf + mtd->writesize + TAGOFFSET) = BBT_TAG; + memcpy(buffer->dataBuf, tmp, wlen); + ret = chip->ecc.write_page(chip, NULL, 0, page + i); + if (ret) { + dev_info(dev, "RTK %s(%d) write bbt%d fail.(%d)\n", + __func__, __LINE__, + (page == BBT1) ? 1 : 2, ret); + goto rtk_nf_write_bbt_exit; + } + + len = len - mtd->writesize; + i++; + } + +rtk_nf_write_bbt_exit: + if (tmp) + kfree(tmp); + + return ret; +} + +static int rtk_nf_update_bbt_to_flash(struct nand_chip *chip) +{ + int ret1, ret2; + + ret1 = rtk_nf_write_bbt(chip, BBT1); + + ret2 = rtk_nf_write_bbt(chip, BBT2); + + return ((ret1 < 0) && (ret2 < 0)) ? -1 : 0; +} + +int rtk_nf_bb_handle(struct nand_chip *chip, int o_blk, + int page, int backup, int mode) +{ + int s_blk = rtk_nf_page_to_block(chip, page); + int m_blk = 0; + int offset = rtk_nf_page_offset_in_block(chip, page); + int ret = 0; + +rtk_nf_bb_handle_redo: + m_blk = rtk_nf_find_available_reserved_block(chip); + if (m_blk <= 0) + return -1; + + if (backup) { + ret = rtk_nf_backup_block(chip, s_blk, m_blk, offset, mode); + if (ret < 0) { + if (ret == -1) { + rtk_nf_update_BBT(chip, 0, 0, m_blk); + goto rtk_nf_bb_handle_redo; + } else { + return ret; + } + } + } + + rtk_nf_update_BBT(chip, o_blk, s_blk, m_blk); + + return rtk_nf_update_bbt_to_flash(chip); +} + +static void rtk_nf_bbt_sync(struct nand_chip *chip, u32 bbtid) +{ + int ret; + + ret = rtk_nf_write_bbt(chip, bbtid); +} + +#ifdef CONFIG_MTD_NAND_RTK_BBTCRC +static unsigned int rtk_nf_bbt_crc_check(struct rtk_nf *nf, u8 *data) +{ + u32 crc = 0; + u32 crc_c = 0; + BB_t *bbt = (BB_t *)(data + CRCLEN); + u8 hash_temp[64] = {0}; + u32 hash_value_temp = 0; + int count; + int i; + + count = 0; + + memcpy(&crc, data, sizeof(u32)); + + for (i=0; iRBA; i++) { + if ((bbt[i].BB_die != BB_DIE_INIT) && + (bbt[i].bad_block != BB_INIT)) { + hash_value_temp = hash_value_temp + + bbt[i].BB_die + bbt[i].bad_block + + bbt[i].RB_die + bbt[i].remap_block; + + count++; + } + } + + sprintf(hash_temp, "%u", hash_value_temp); + crc_c = crc32(~0, (u8 *)hash_temp, sizeof(hash_temp)); + + if (crc != crc_c) + return -1; + + return count; +} +#endif + +static int rtk_nf_read_bbt_page(struct nand_chip *chip, u8 *buf, u32 page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + int ret; + + ret = chip->ecc.read_oob(chip, page); + if (ret != 0) + return -1; + + if (*(buffer->dataBuf + mtd->writesize + TAGOFFSET) != BBT_TAG) + return -1; + + memcpy(buf, buffer->dataBuf, mtd->writesize); + + return ret; +} + +static int rtk_nf_read_bbt(struct nand_chip *chip, u8 *bbt, u32 bbtid, u32 p) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + u32 page; + u8 *buf; + int ret; + int i; + + for (i=0; iwritesize * i); + ret = rtk_nf_read_bbt_page(chip, buf, page); + if (ret != 0) + break; + } + + return ret; +} + +int rtk_nf_scan_bbt(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct device *dev = nf->dev; + int c1 = -1, c2 = -1; + u32 b; + u32 p = 0; + u8 *bbt1 = NULL; + u8 *bbt2 = NULL; + int ret = 0; + + /* calculate RBA */ + b = nf->size; + b = b / mtd->erasesize; + nf->RBA = b * 5; + nf->RBA = nf->RBA / 100; + + p = rtk_nf_bbt_page_count(chip); + + nf->bbt = kmalloc(sizeof(BB_t) * nf->RBA, GFP_KERNEL); + if (nf->bbt) { + dev_err(dev, "RTK %s(%d) alloc bbt1 fail.\n", + __func__, __LINE__); + return -ENOMEM; + } + memset(nf->bbt, 0xff, sizeof(BB_t) * nf->RBA); + + bbt1 = kmalloc((mtd->writesize * p), GFP_KERNEL); + if (!bbt1) { + dev_err(dev, "RTK %s(%d) alloc bbt1 fail.\n", + __func__, __LINE__); + return -ENOMEM; + } + memset(bbt1, 0xff, (mtd->writesize * p)); + + bbt2 = kmalloc((mtd->writesize * p), GFP_KERNEL); + if (!bbt2) { + dev_err(dev, "RTK %s(%d) alloc bbt2 fail.\n", + __func__, __LINE__); + return -ENOMEM; + } + memset(bbt2, 0xff, (mtd->writesize * p)); + + /* read bbt from block 1 */ + ret = rtk_nf_read_bbt(chip, bbt1, BBT1, p); + if (ret != 0) + dev_err(dev, "RTK %s(%d) read bbt1 fail.\n", + __func__, __LINE__); +#ifdef CONFIG_MTD_NAND_RTK_BBTCRC + else { + c1 = rtk_nf_bbt_crc_check(nf, bbt1); + if (c1 < 0) + dev_err(dev, "RTK %s(%d) check bbt1 fail.\n", + __func__, __LINE__); + } +#endif + + /* read bbt from block 2 */ + ret = rtk_nf_read_bbt(chip, bbt2, BBT2, p); + if (ret != 0) + dev_err(dev, "RTK %s(%d) read bbt2 fail.\n", + __func__, __LINE__); +#ifdef CONFIG_MTD_NAND_RTK_BBTCRC + else { + c2 = rtk_nf_bbt_crc_check(nf, bbt2); + if (c2 < 0) + dev_err(dev, "RTK %s(%d) check bbt2 fail.\n", + __func__, __LINE__); + } +#endif + + if ((c1 == c2) && (c1 >= 0) && (c2 >= 0)) { + dev_info(dev, "RTK %s(%d) load bbt from bbt1.\n", + __func__, __LINE__); + memcpy(nf->bbt, bbt1 + CRCLEN, sizeof(BB_t)*nf->RBA); + } + else if (c1 > c2) { + dev_info(dev, "RTK %s(%d) load bbt from bbt1.\n", + __func__, __LINE__); + memcpy(nf->bbt, bbt1 + CRCLEN, sizeof(BB_t)*nf->RBA); + rtk_nf_bbt_sync(chip, BBT2); + } + else if (c2 > c1) { + dev_info(dev, "RTK %s(%d) load bbt from bbt2.\n", + __func__, __LINE__); + memcpy(nf->bbt, bbt2 + CRCLEN, sizeof(BB_t)*nf->RBA); + rtk_nf_bbt_sync(chip, BBT1); + } + else { + dev_info(dev, "RTK %s(%d) load bbt fail.\n", + __func__, __LINE__); + return -1; + } + + return 0; +} diff --git a/drivers/mtd/nand/raw/rtk_nand.c b/drivers/mtd/nand/raw/rtk_nand.c new file mode 100644 index 000000000000..7dd1972a13b3 --- /dev/null +++ b/drivers/mtd/nand/raw/rtk_nand.c @@ -0,0 +1,1209 @@ +/* + * RTK NAND Flash controller driver. + * Copyright (C) 2020 Realtek Inc. + * Authors : PK Chuang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_nand.h" + + +#define RTK_NAME "rtk-nand" +#define RTK_TIMEOUT (500000) +#define RTK_RESET_TIMEOUT (1000000) + +#define NF_CTL_ENABLE 1 +#define NF_CTL_DISABLE 0 +#define RTK_DMABUF_LEN 1024*256 +#define RTK_OOBBUF_LEN 1024 + +#define ECC 0 +#define RAW 1 +#define NoOOB 0 +#define OOB 1 + +struct nand_flash_dev rtk_nand_flash_ids[] = { + {"W29N04GV 4G", + { .id = {0xef, 0xdc, 0x90, 0x95, 0x54, 0x00, 0xff, 0xff} }, + SZ_2K, SZ_256M, SZ_128K, 0, 6, 64, NAND_ECC_INFO(6, 1), + 2 }, + {NULL} +}; + +static inline struct rtk_nf *to_rtk_nand(struct nand_chip *chip) +{ + return container_of(chip, struct rtk_nf, chip); +} + +static int rtk_nf_wait_down(void __iomem *regs, u64 mask, unsigned int value) +{ + u32 val; + int ret; + + ret = readl_poll_timeout_atomic(regs, val, (val & mask) == value, 10, + RTK_TIMEOUT); + if (ret) + return -EIO; + + return 0; +} + +static void rtk_nf_reset_nandbuf(struct rtk_nf *nf) +{ + struct nand_chip *chip = &nf->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_buffer *buf = &nf->nandbuf; + + memset(buf->tempbuf, 0x0, sizeof(buf->tempbuf)); + + if (buf->dataBuf) + memset(buf->dataBuf, 0x0, mtd->writesize + mtd->oobsize); + + buf->index_r = 0; + buf->index_w = 0; +} + +static int rtk_nf_init_nandbuf(struct nand_chip *chip) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + struct mtd_info *mtd = mtd = nand_to_mtd(chip); + struct rtk_buffer *buf = &nf->nandbuf; + + buf->dataBuf = (unsigned char *)dma_alloc_coherent(nf->dev, + mtd->writesize + mtd->oobsize, &buf->dataPhys, + GFP_DMA | GFP_KERNEL); + if ( !buf->dataBuf ) { + dev_err(nf->dev, "no enough memory for dataBuf\n"); + return -ENOMEM; + } + + memset(buf->dataBuf, 0x0, mtd->writesize + mtd->oobsize); + + buf->index_r = 0; + buf->index_w = 0; + + return 0; +} + +static inline void rtk_nf_write_byte(struct nand_chip *chip, unsigned char val) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buf = &nf->nandbuf; + + if (buf->dataBuf) + buf->dataBuf[buf->index_w] = val; + else + buf->tempbuf[buf->index_w] = val; + + buf->index_w++; +} + +static inline u8 rtk_nf_read_byte(struct nand_chip *chip) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buf = &nf->nandbuf; + u8 byte; + + if (buf->dataBuf) + byte = buf->dataBuf[buf->index_r]; + else + byte = buf->tempbuf[buf->index_r]; + + buf->index_r++; + + return byte; +} + +static void rtk_nf_read_buf(struct nand_chip *chip, u8 *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + buf[i] = rtk_nf_read_byte(chip); +} + +static int rtk_nf_do_write_page(struct nand_chip *chip, int page, int raw) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + void __iomem *base = nf->regs; + unsigned int dram_sa, dma_len, spare_dram_sa; + struct rtk_buffer *buffer = &nf->nandbuf; + dma_addr_t dataPhy = buffer->dataPhys; + u32 ecc = (mtd->ecc_strength == 6) ? 0x0 : 0x1; + int ret = 0; + + writel(NF_DATA_TL0_length0(0), base + REG_DATA_TL0); + + writel(0x1, base + REG_RND_EN); + writel(0x85, base + REG_RND_CMD1); + writel(0x0, base + REG_RND_DATA_STR_COL_H); + writel((mtd->writesize >> 8), base + REG_RND_SPR_STR_COL_H); + writel((mtd->writesize & 0xff), base + REG_RND_SPR_STR_COL_L); + writel(NF_DATA_TL1_length1(2), base + REG_DATA_TL1); + + writel(NF_PAGE_LEN_page_len(mtd->writesize >> 9), base + REG_PAGE_LEN); + + /* Set PP */ + writel(NF_READ_BY_PP_read_by_pp(0), base + REG_READ_BY_PP); + writel(NF_PP_CTL1_pp_start_addr(0), base + REG_PP_CTL1); + writel(0x0, base + REG_PP_CTL0); + + /* Set command */ + writel(NF_ND_CMD_cmd(NAND_CMD_SEQIN), base + REG_ND_CMD); + writel(NF_CMD2_cmd2(NAND_CMD_PAGEPROG), base + REG_CMD2); + writel(NF_CMD3_cmd3(NAND_CMD_STATUS), base + REG_CMD3); + + /* set address */ + writel(NF_ND_PA0_page_addr0(page), base + REG_ND_PA0); + writel(NF_ND_PA1_page_addr1(page >> 8), base + REG_ND_PA1); + writel(NF_ND_PA2_addr_mode(1) | NF_ND_PA2_page_addr2(page >> 16), + base + REG_ND_PA2); + writel(NF_ND_PA3_page_addr3((page >> 21) & 0x7), base + REG_ND_PA3); + writel(0x0, base + REG_ND_CA0); + writel(0x0, base + REG_ND_CA1); + + /* set ECC */ + writel(NF_MULTI_CHNL_MODE_edo(1), base + REG_MULTI_CHNL_MODE); + writel(NF_ECC_STOP_ecc_n_stop(1), base + REG_ECC_STOP); + writel(ecc, base + REG_ECC_SEL); + + dram_sa = ((uintptr_t)dataPhy >> 3); + dma_len = mtd->writesize >> 9; + writel(NF_DMA_CTL1_dram_sa(dram_sa), base + REG_DMA_CTL1); + writel(NF_DMA_CTL2_dma_len(dma_len), base + REG_DMA_CTL2); + + spare_dram_sa = ( (uintptr_t)(dataPhy + mtd->writesize) >> 3); + writel(0x60000000 | NF_SPR_DDR_CTL_spare_dram_sa(spare_dram_sa), + base + REG_SPR_DDR_CTL); + writel(NF_DMA_CTL3_ddr_wr(0)|NF_DMA_CTL3_dma_xfer(1), + base + REG_DMA_CTL3); + + writel(NF_AUTO_TRIG_auto_trig(1) | NF_AUTO_TRIG_spec_auto_case(0) | + NF_AUTO_TRIG_auto_case(1), + base + REG_AUTO_TRIG); + + if ((ret = rtk_nf_wait_down(base + REG_AUTO_TRIG, 0x80, 0x0)) != 0) { + goto rtk_nf_do_write_page_exit; + } + + if ((ret = rtk_nf_wait_down(base + REG_DMA_CTL3, 0x1, 0x0)) != 0) { + goto rtk_nf_do_write_page_exit; + } + + writel(NF_POLL_FSTS_bit_sel(6) | NF_POLL_FSTS_trig_poll(1), + base + REG_POLL_FSTS); + if ((ret = rtk_nf_wait_down(base + REG_POLL_FSTS, 0x1, 0x0)) != 0) { + goto rtk_nf_do_write_page_exit; + } + + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x40, 0x40)) != 0) { + goto rtk_nf_do_write_page_exit; + } + + if (readl(base + REG_ND_DAT) & 0x1) { + ret = -1; + } + +rtk_nf_do_write_page_exit: + return ret; +} + +static int rtk_nf_write_page(struct nand_chip *chip, + const u8 *buf, int page, int raw) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + int r_page = page; + int ret; +#if defined(CONFIG_MTD_NAND_RTK_BBM) + struct nand_memory_organization *memorg = &chip->base.memorg; + int o_blk = page / memorg->pages_per_eraseblock; + +rtk_nf_write_page_retry: + r_page = rtk_nf_get_realpage(chip, page); +#endif + + memset(buffer->dataBuf, 0xFF, mtd->writesize + mtd->oobsize); + + if (!buf) { /* write oob only */ + ret = chip->ecc.read_oob(chip, page); + if (ret) + return -1; + + memcpy(buffer->dataBuf + mtd->writesize, chip->oob_poi, + mtd->oobsize); + } else { + memcpy(buffer->dataBuf, buf, mtd->writesize); + } + + ret = rtk_nf_do_write_page(chip, r_page, raw); + +#if defined(CONFIG_MTD_NAND_RTK_BBM) + if (ret) { + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 1, NFWRITE); + if (!ret) + goto rtk_nf_write_page_retry; + } +#endif + return ret; +} + +static int rtk_nf_write_page_raw(struct nand_chip *chip, const u8 *buf, + int oob_on, int page) +{ + return rtk_nf_write_page(chip, buf, page, 1); +} + +static int rtk_nf_write_page_hwecc(struct nand_chip *chip, const u8 *buf, + int oob_on, int page) +{ + return rtk_nf_write_page(chip, buf, page, 0); +} + +static int rtk_nf_write_oob(struct nand_chip *chip, int page) +{ + + return rtk_nf_write_page(chip, NULL, page, 0); +} + +static void rtk_read_oob_from_SRAM(struct mtd_info *mtd, __u8 *oobbuf) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct rtk_nf *nf = to_rtk_nand(chip); + void __iomem *base = nf->regs; + unsigned int reg_oob; + int i; + char r_oobbuf[256]; + int oobuse_size = 0; + u32 ecc = (mtd->ecc_strength == 6) ? 0x0 : 0x1; + + writel(0x0, base + REG_READ_BY_PP); +//#ifdef CONFIG_ARCH_RTD13xx + writel(0x30 | 0x02, base + REG_SRAM_CTL); +//#else +// writel(0x30 | 0x04, base + REG_SRAM_CTL); +//#endif + + memset(r_oobbuf, 0xFF, 256); + memset(oobbuf, 0xFF, mtd->oobsize); + + switch (ecc) { + case 0x0: + oobuse_size = 6 + 10; + break; + case 0x1: + oobuse_size = 6 + 20; + break; + default: + oobuse_size = 6 + 10; + break; + } + + for (i = 0; i < (mtd->oobsize/4); i++) { + reg_oob = readl(base+(i*4)); + + r_oobbuf[i*4] = reg_oob & 0xff; + r_oobbuf[(i*4)+1] = (reg_oob >> 8) & 0xff; + r_oobbuf[(i*4)+2] = (reg_oob >> 16) & 0xff; + r_oobbuf[(i*4)+3] = (reg_oob >> 24) & 0xff; + } + + for (i = 0; i < 4; i++) { + memcpy(oobbuf+(i*oobuse_size), r_oobbuf+(i*(mtd->oobsize/4)), + oobuse_size); + } + + writel(0x0, base + REG_SRAM_CTL); + writel(0x80, base + REG_READ_BY_PP); + + return; +} + +static int rtk_nf_do_read_page(struct mtd_info *mtd, int page, + int oob, int raw) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct rtk_nf *nf = to_rtk_nand(chip); + struct device *dev = nf->dev; + void __iomem *base = nf->regs; + unsigned int dram_sa, dma_len; + struct rtk_buffer *buffer = &nf->nandbuf; + dma_addr_t dataPhy = buffer->dataPhys; + u32 ecc = (mtd->ecc_strength == 6) ? 0x0 : 0x1; + int ret; + unsigned int eccNum = 0; + unsigned int blank_check = 0; + unsigned int blank_confirm = 0; + +blank_confirm_read: + writel(0x1, base + REG_RND_EN); + writel(0x5, base + REG_RND_CMD1); + writel(0xe0, base + REG_RND_CMD2); + writel(0x0, base + REG_RND_DATA_STR_COL_H); + writel((mtd->writesize >> 8), base + REG_RND_SPR_STR_COL_H); + writel((mtd->writesize & 0xff), base + REG_RND_SPR_STR_COL_L); + writel(NF_DATA_TL0_length0(512), base + REG_DATA_TL0); + writel(NF_DATA_TL1_access_mode(1) | NF_DATA_TL1_length1(2), + base + REG_DATA_TL1); + writel(NF_PAGE_LEN_page_len((mtd->writesize >> 9)), + base + REG_PAGE_LEN); + + /* set PP */ + writel(NF_READ_BY_PP_read_by_pp(1), base + REG_READ_BY_PP); + writel(NF_PP_CTL1_pp_start_addr(0), base + REG_PP_CTL1); + writel(0x0, base + REG_PP_CTL0); + + /* enable blank PP */ + if (blank_confirm) { + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(1), + base + REG_BLANK_CHK); + } else { + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + } + + /* set command */ + writel(NF_ND_CMD_cmd(NAND_CMD_READ0), base + REG_ND_CMD); + writel(NF_CMD2_cmd2(NAND_CMD_READSTART), base + REG_CMD2); + writel(NF_CMD3_cmd3(NAND_CMD_STATUS), base + REG_CMD3); + + /* set address */ + writel(NF_ND_PA0_page_addr0(0xff&page), base + REG_ND_PA0); + writel(NF_ND_PA1_page_addr1(0xff&(page>>8)), base + REG_ND_PA1); + writel(NF_ND_PA2_addr_mode(0x1) | + NF_ND_PA2_page_addr2(0x1f&(page>>16)), base + REG_ND_PA2); + writel(NF_ND_PA3_page_addr3(0x7&(page>>21)), base + REG_ND_PA3); + writel(0x0, base + REG_ND_CA0); + writel(0x0, base + REG_ND_CA1); + + /* Set ECC */ + writel(NF_MULTI_CHNL_MODE_edo(0x1), base + REG_MULTI_CHNL_MODE); + writel(NF_ECC_STOP_ecc_n_stop(0x1), base + REG_ECC_STOP); + writel(ecc, base + REG_ECC_SEL); + + dram_sa = ((uintptr_t)dataPhy >> 3); + dma_len = mtd->writesize >> 9; + writel(NF_DMA_CTL1_dram_sa(dram_sa), base + REG_DMA_CTL1); + writel(NF_DMA_CTL2_dma_len(dma_len), base + REG_DMA_CTL2); + + writel(NF_DMA_CTL3_ddr_wr(1)|NF_DMA_CTL3_dma_xfer(1), + base + REG_DMA_CTL3); + + + /* Enable Auto mode */ + writel(NF_AUTO_TRIG_auto_trig(1) | NF_AUTO_TRIG_spec_auto_case(0) | + NF_AUTO_TRIG_auto_case(2), base + REG_AUTO_TRIG); + + if ((ret = rtk_nf_wait_down(base + REG_AUTO_TRIG, 0x80, 0x0)) != 0) { + goto rtk_nf_do_read_page_exit; + } + + if ((ret = rtk_nf_wait_down(base + REG_DMA_CTL3, 0x1, 0x0)) != 0) { + goto rtk_nf_do_read_page_exit; + } + + if (oob) + rtk_read_oob_from_SRAM(mtd, buffer->dataBuf + mtd->writesize); + + if (blank_confirm) { + blank_confirm = 0; + + if (readl(base + REG_ND_ECC) & 0x8) { + dev_err(dev, "RTK %s(%d) read error, page:0x%x\n", + __func__, __LINE__, page); + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + ret = -1; + goto rtk_nf_do_read_page_exit; + } else { + if (oob) + memset(buffer->dataBuf + mtd->writesize + , 0xFF, mtd->oobsize); + + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + ret = 1; + goto rtk_nf_do_read_page_exit; + } + } else { + blank_check = readl(base + REG_BLANK_CHK); + if (blank_check & 0x2) { + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + ret = 1; + goto rtk_nf_do_read_page_exit; + } else if (readl(base + REG_ND_ECC) & 0x8) { + blank_confirm = 1; + dev_err(dev, "RTK %s(%d) ecc error...blank_confirm_read.\n", + __func__, __LINE__); + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + goto blank_confirm_read; + } else { + if (readl(base + REG_ND_ECC) & 0x04) { + eccNum = readl(base + REG_MAX_ECC_NUM)&0xff; + if (eccNum > (mtd->ecc_strength - 2)) { + dev_warn(dev, "RTK %s(%d) ecc over threshold.\n", + __func__, __LINE__); + + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + ret = 2; + goto rtk_nf_do_read_page_exit; + } + + writel(NF_BLANK_CHK_blank_ena(1) | + NF_BLANK_CHK_read_ecc_xnor_ena(0), + base + REG_BLANK_CHK); + ret = 0; + goto rtk_nf_do_read_page_exit; + } + } + } + +rtk_nf_do_read_page_exit: + return ret; +} + +static int rtk_nf_read_page_raw(struct nand_chip *chip, u8 *p, + int oob_on, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + int r_page = page; + int ret; +#if defined(CONFIG_MTD_NAND_RTK_BBM) + struct nand_memory_organization *memorg = &chip->base.memorg; + int o_blk = page / memorg->pages_per_eraseblock; + r_page = rtk_nf_get_realpage(chip, page); +#endif + ret = rtk_nf_do_read_page(mtd, r_page, NoOOB, RAW); + if (ret >= 0) + memcpy(p, buffer->dataBuf, mtd->writesize); + +#if defined(CONFIG_MTD_NAND_RTK_BBM) + if (ret < 0) + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 0, NFREAD); + else if (ret == 2) /* ecc bit over threshold */ + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 1, NFREAD); +#endif + + return ret; +} + +static int rtk_nf_read_page_hwecc(struct nand_chip *chip, u8 *p, + int oob_on, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + int r_page = page; + int ret; +#if defined(CONFIG_MTD_NAND_RTK_BBM) + struct nand_memory_organization *memorg = &chip->base.memorg; + int o_blk = page / memorg->pages_per_eraseblock; + r_page = rtk_nf_get_realpage(chip, page); +#endif + ret = rtk_nf_do_read_page(mtd, r_page, NoOOB, ECC); + if (ret >= 0) + memcpy(p, buffer->dataBuf, mtd->writesize); + +#if defined(CONFIG_MTD_NAND_RTK_BBM) + if (ret < 0) + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 0, NFREAD); + else if (ret == 2) /* ecc bit over threshold */ + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 1, NFREAD); +#endif + + return ret; +} + +static int rtk_nf_read_oob(struct nand_chip *chip, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + int r_page = page; + int ret; +#if defined(CONFIG_MTD_NAND_RTK_BBM) + struct nand_memory_organization *memorg = &chip->base.memorg; + int o_blk = page / memorg->pages_per_eraseblock; + r_page = rtk_nf_get_realpage(chip, page); +#endif + ret = rtk_nf_do_read_page(mtd, r_page, OOB, ECC); + if (ret >= 0) + memcpy(chip->oob_poi, buffer->dataBuf + mtd->writesize, mtd->oobsize); + +#if defined(CONFIG_MTD_NAND_RTK_BBM) + if (ret < 0) + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 0, NFREAD); + else if (ret == 2) /* ecc bit over threshold */ + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 1, NFREAD); +#endif + + return ret; +} + +static int rtk_nf_do_erase_block(struct nand_chip *chip, int page) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + struct device *dev = nf->dev; + void __iomem *base = nf->regs; + int ret = 0; + + writel(NF_MULTI_CHNL_MODE_no_wait_busy(1) | NF_MULTI_CHNL_MODE_edo(1), + base + REG_MULTI_CHNL_MODE); + + writel(NF_ND_CMD_cmd(NAND_CMD_ERASE1), base + REG_ND_CMD); + writel(NF_CMD2_cmd2(NAND_CMD_ERASE2), base + REG_CMD2); + writel(NF_CMD3_cmd3(NAND_CMD_STATUS), base + REG_CMD3); + + writel(NF_ND_PA0_page_addr0(page), base + REG_ND_PA0); + writel(NF_ND_PA1_page_addr1(page>>8), base + REG_ND_PA1); + writel(NF_ND_PA2_addr_mode(0x04) | NF_ND_PA2_page_addr2(page >> 16), + base + REG_ND_PA2); + writel(NF_ND_PA3_page_addr3((page >> 21) & 0x7), base + REG_ND_PA3); + + writel(NF_AUTO_TRIG_auto_trig(1) | NF_AUTO_TRIG_spec_auto_case(1) | + NF_AUTO_TRIG_auto_case(2), base + REG_AUTO_TRIG); + if ((ret = rtk_nf_wait_down(base + REG_AUTO_TRIG, 0x80, 0x0)) != 0) { + goto rtk_nf_do_erase_block_exit; + } + + writel(NF_POLL_FSTS_bit_sel(6) | NF_POLL_FSTS_trig_poll(1), + base + REG_POLL_FSTS); + if ((ret = rtk_nf_wait_down(base + REG_POLL_FSTS, 0x1, 0x0)) != 0) { + goto rtk_nf_do_erase_block_exit; + } + + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x40, 0x40)) != 0) { + goto rtk_nf_do_erase_block_exit; + } + + if (readl(base + REG_ND_DAT) & 0x1) { + dev_err(dev, "RTK %s(%d) erase fail.\n", __func__, __LINE__); + ret = -1; + } + +rtk_nf_do_erase_block_exit: + return ret; +} + +static int rtk_nf_erase_block(struct nand_chip *chip, int page) +{ + int r_page = page; + int ret; +#if defined(CONFIG_MTD_NAND_RTK_BBM) + struct nand_memory_organization *memorg = &chip->base.memorg; + int o_blk = page / memorg->pages_per_eraseblock; + +rtk_nf_erase_block_retry: + r_page = rtk_nf_get_realpage(chip, page); +#endif + ret = rtk_nf_do_erase_block(chip, r_page); +#if defined(CONFIG_MTD_NAND_RTK_BBM) + if (ret < 0) { + ret = rtk_nf_bb_handle(chip, o_blk, r_page, 0, NFERASE); + if (ret == 0) + goto rtk_nf_erase_block_retry; + } +#endif + return ret; +} + +static int rtk_nf_block_bad(struct nand_chip *chip, loff_t ofs) +{ +#ifndef CONFIG_MTD_NAND_RTK_BBM + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_memory_organization *memorg = &chip->base.memorg; + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buffer = &nf->nandbuf; + u32 ppb = memorg->pages_per_eraseblock; + u64 blk = (u64)ofs; + int i; + + do_div(blk, mtd->erasesize); + + /* check 1st & 2nd page */ + for (i=0; i<2; i++) { + if (chip->ecc.read_oob(chip, blk*ppb + i) < 0) + return -1; + + if (*(buffer->dataBuf + mtd->writesize) != 0xff) + return -1; + } +#endif + return 0; +} + +static void rtk_nf_read_id(struct nand_chip *chip) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + void __iomem *base = nf->regs; + int ret, i; + int id_chain; + + writel(6, base + REG_DATA_TL0); + writel(0x80, base + REG_DATA_TL1); + + /* Set PP */ + writel(0x0, base + REG_READ_BY_PP); + writel(0x01, base + REG_PP_CTL0); + writel(0x0, base + REG_PP_CTL1); + + /* Set command */ + writel(0x90, base + REG_ND_CMD); + writel(0x80, base + REG_ND_CTL); + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x80, 0x0)) != 0) { + return; + } + + /* Set address */ + writel(0x0, base + REG_ND_PA0); + writel(0x0, base + REG_ND_PA1); + writel(0x7 << 5, base + REG_ND_PA2); + writel(0x81, base + REG_ND_CTL); + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x80, 0x0)) != 0) { + return; + } + + /* Enable XFER mode */ + writel(0x84, base + REG_ND_CTL); + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x80, 0x0)) != 0) { + return; + } + + /* reset PP */ + writel(0x2, base + REG_PP_CTL0); + + /* Move data to DRAM from SRAM */ + writel(0x30, base + REG_SRAM_CTL); + + id_chain = readl(base + REG_ND_PA0); + for (i = 0; i < 4; i++) { + rtk_nf_write_byte(chip, (id_chain >> (8*i)) & 0xff); + } + + id_chain = readl(base + REG_ND_PA1); + for (i = 0; i < 4; i++) { + rtk_nf_write_byte(chip, (id_chain >> (8*i)) & 0xff); + } + + writel(0x0, base + REG_SRAM_CTL); + + return; + +} + +static void rtk_nf_status(struct nand_chip *chip) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + struct rtk_buffer *buf = &nf->nandbuf; + u32 val = 0x0; + + val |= NAND_STATUS_WP; + val |= NAND_STATUS_READY; + + buf->dataBuf[buf->index_w] = val; + buf->index_w++; +} + +static int rtk_nf_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; + + oobregion->offset = mtd->writesize; + oobregion->length = 6; + + return 0; +} + +static int rtk_nf_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; + + oobregion->length = 6; + oobregion->offset = mtd->writesize + (section * 16); + + return 0; +} + +static const struct mtd_ooblayout_ops rtk_nf_ooblayout_ops = { + .ecc = rtk_nf_ooblayout_ecc, + .free = rtk_nf_ooblayout_free, +}; + +static void rtk_nf_update_ecc_info(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (chip->ecc.mode != NAND_ECC_HW) { + return; + } + + if (mtd->writesize == SZ_2K) + mtd->ecc_strength = 6; + else if (mtd->writesize == SZ_4K) + mtd->ecc_strength = 12; + + chip->ecc.steps = 4; + chip->ecc.size = 512; + chip->ecc.bytes = (mtd->writesize == SZ_2K) ? 10 : 20; + chip->ecc.strength = mtd->ecc_strength; + + mtd_set_ooblayout(mtd, &rtk_nf_ooblayout_ops); +} + +static int rtk_nf_wait(struct nand_chip *chip) +{ + /* nop */ + return 0; +} + +static void rtk_nf_command(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + + rtk_nf_reset_nandbuf(nf); + + switch (command) { + case NAND_CMD_RESET: + break; + + case NAND_CMD_READID: + rtk_nf_read_id(chip); + break; + + case NAND_CMD_READ0: + break; + + case NAND_CMD_STATUS: + rtk_nf_status(chip); + break; + + case NAND_CMD_ERASE1: + rtk_nf_erase_block(chip, page_addr); + break; + + default: + break; + } +} + +static void rtk_nf_select_chip(struct nand_chip *chip, int cs) +{ + struct rtk_nf *nf = to_rtk_nand(chip); + void __iomem *base = nf->regs; + unsigned long value = 0x0; + + switch (cs) { + case -1: + value = 0xff; + break; + case 0: + case 1: + case 2: + case 3: + value = ~(BIT(cs)); + break; + default: + value = ~(BIT(0)); + } + + writel(value, base + REG_PD); +} + +static inline int rtk_nf_hw_init(struct rtk_nf *nf) +{ + void __iomem *base = nf->regs; + int ret; + + /* init controller */ + writel(0x1E, base + REG_PD); + writel(0x2, base + REG_TIME_PARA3); + writel(0x5, base + REG_TIME_PARA2); + writel(0x2, base + REG_TIME_PARA1); + + writel(0x0, base + REG_MULTI_CHNL_MODE); + writel(0x0, base + REG_READ_BY_PP); + + /* reset nand */ + writel(0xff, base + REG_ND_CMD); + writel(0x80, base + REG_ND_CTL); + + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x80, 0x0)) != 0) + return ret; + + if ((ret = rtk_nf_wait_down(base + REG_ND_CTL, 0x40, 0x40)) != 0) + return ret; +#if 1 + writel(readl(base + REG_NF_LOW_PWR) &~0x10, base + REG_NF_LOW_PWR); + writel(NF_SPR_DDR_CTL_spare_ddr_ena(1) | + NF_SPR_DDR_CTL_per_2k_spr_ena(1) | + NF_SPR_DDR_CTL_spare_dram_sa(0), base + REG_SPR_DDR_CTL); +#endif + return 0; +} + +static int rtk_nand_clk_reset_ctrl(struct device *dev, + struct rtk_nf_clk_rst *clkrst, + int enable) +{ + int ret = 0; + + if (!clkrst->clk) { + clkrst->clk = devm_clk_get(dev, "nand"); + if (IS_ERR(clkrst->clk)) { + printk(KERN_ERR "%s: devm_clk_get() returns %ld\n", + __func__, PTR_ERR(clkrst->clk)); + clkrst->clk = NULL; + goto rtk_nand_clk_reset_ctrl_exit; + } + } + + if (enable == NF_CTL_ENABLE) + ret = clk_prepare_enable(clkrst->clk); + else + clk_disable_unprepare(clkrst->clk); + + if (!ret) + clk_put(clkrst->clk); + +rtk_nand_clk_reset_ctrl_exit: + return ret; +} + +static int rtk_nf_enable_clk(struct device *dev, struct rtk_nf_clk_rst *clkrst) +{ + return rtk_nand_clk_reset_ctrl(dev, clkrst, NF_CTL_ENABLE); + +} + +static int rtk_nf_disable_clk(struct device *dev, struct rtk_nf_clk_rst *clkrst) +{ + return rtk_nand_clk_reset_ctrl(dev, clkrst, NF_CTL_DISABLE); +} + +static int rtk_nf_ecc_init(struct nand_chip *chip) +{ + //struct mtd_info *mtd = nand_to_mtd(chip); + + rtk_nf_update_ecc_info(chip); + + return 0; +} + +static int rtk_nf_attach_chip(struct nand_chip *chip) +{ + int ret; + + if (chip->bbt_options & NAND_BBT_USE_FLASH) + chip->bbt_options |= NAND_BBT_NO_OOB; + + ret = rtk_nf_ecc_init(chip); + if (ret) + return ret; + + ret = rtk_nf_init_nandbuf(chip); + if (ret) + return -ENOMEM; + + return 0; +} + +static const struct nand_controller_ops rtk_nf_controller_ops = { + .attach_chip = rtk_nf_attach_chip, + //.setup_data_interface = rtk_nf_setup_data_interface, +}; + +static int rtk_nf_nand_chip_init(struct device *dev, struct rtk_nf *nf, + struct device_node *np) +{ + struct nand_chip *chip = &nf->chip; + struct mtd_info *mtd; + int ret; + + chip->controller = &nf->controller; + + nand_set_flash_node(chip, np); + nand_set_controller_data(chip, nf); + + mtd = nand_to_mtd(chip); + mtd->owner = THIS_MODULE; + mtd->dev.parent = dev; + mtd->name = RTK_NAME; + + chip->options |= NAND_SKIP_BBTSCAN | NAND_NO_SUBPAGE_WRITE; + + chip->legacy.select_chip = rtk_nf_select_chip; + chip->legacy.read_byte = rtk_nf_read_byte; + chip->legacy.read_buf = rtk_nf_read_buf; + chip->legacy.cmdfunc = rtk_nf_command; + chip->legacy.waitfunc = rtk_nf_wait; + chip->legacy.block_bad = rtk_nf_block_bad; + + chip->ecc.mode = NAND_ECC_HW; + + chip->ecc.write_page_raw = rtk_nf_write_page_raw; + chip->ecc.write_page = rtk_nf_write_page_hwecc; + chip->ecc.write_oob_raw = rtk_nf_write_oob; + chip->ecc.write_oob = rtk_nf_write_oob; + + chip->ecc.read_page_raw = rtk_nf_read_page_raw; + chip->ecc.read_page = rtk_nf_read_page_hwecc; + chip->ecc.read_oob_raw = rtk_nf_read_oob; + chip->ecc.read_oob = rtk_nf_read_oob; + + chip->bbt = NULL; + + ret = rtk_nf_hw_init(nf); + if (ret) + return -ENODEV; + + ret = nand_scan_with_ids(chip, 1, rtk_nand_flash_ids); + if (ret) + return -ENODEV; + +#if defined(CONFIG_MTD_NAND_RTK_BBM) + ret = rtk_nf_scan_bbt(chip); + if (ret) + return -ENODEV; +#endif + + nf->size = mtd->size >> 20; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + dev_err(dev, "mtd parse partition error\n"); + nand_release(chip); + return -ENODEV; + } + + return 0; +} + +static void rtk_nf_pad_setup(struct rtk_nf *nf) +{ + void __iomem *pad_base = nf->pad_regs; + + writel(0x55555555, pad_base+0x0); +} + +static void rtk_nf_pll_setup(struct rtk_nf *nf) +{ + void __iomem *pll_base = nf->pll_regs; + + writel(0x3, pll_base+0x0); + writel(0x4E4388, pll_base+0x8); + writel(0x7, pll_base+0xc); + udelay(200); + + return; +} + +static void rtk_nf_gating(struct rtk_nf *nf) +{ + void __iomem *base = nf->regs; + + writel(readl(0x168 + base) | BIT(0), 0x168 + base); + writel(readl(0x168 + base) | BIT(1), 0x168 + base); + writel(readl(0x314 + base) | BIT(0), 0x314 + base); + writel(readl(0x314 + base) | BIT(1), 0x314 + base); + writel(readl(0x13c + base) | BIT(3), 0x13c + base); + writel(readl(0x13c + base) | BIT(4), 0x13c + base); + writel(readl(0x310 + base) | BIT(5), 0x310 + base); + writel(readl(0x310 + base) | BIT(6), 0x310 + base); + writel(readl(0x318 + base) | BIT(0), 0x318 + base); + + return; +} + +static int rtk_nf_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_nf *nf; + struct resource *res; + int ret; + + nf = devm_kzalloc(dev, sizeof(*nf), GFP_KERNEL); + if (!nf) + return -ENOMEM; + + nand_controller_init(&nf->controller); + nf->controller.ops = &rtk_nf_controller_ops; + +#if defined(CONFIG_MTD_RTK_NAND_HW_SEMAPHORE) + unsigned int addr; + if (of_property_read_u32(np, "hw-semaphore", &addr)) { + addr = 0x9801a63c; + dev_err(dev, "NAND : can't find hw semaphore in dtb, \ + use default - 0x%x\n", addr); + } else { + dev_info(dev, "NAND : find hw semaphore in dtb, 0x%x\n", addr); + } + nf->hwsem_base = ioremap(addr, 1); +#endif + + ret = rtk_nf_enable_clk(dev, &nf->clkrst); + if (ret) + goto rtk_nf_probe_exit; + + nf->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + nf->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(nf->regs)) { + ret = PTR_ERR(nf->regs); + dev_err(dev, "no reg base\n"); + goto rtk_nf_probe_disable_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + nf->pll_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(nf->pll_regs)) { + ret = PTR_ERR(nf->pll_regs); + dev_err(dev, "no pll reg base\n"); + goto rtk_nf_probe_disable_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + nf->pad_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(nf->pad_regs)) { + ret = PTR_ERR(nf->pad_regs); + dev_err(dev, "no pad reg base\n"); + goto rtk_nf_probe_disable_clk; + } + + rtk_nf_pad_setup(nf); + + rtk_nf_pll_setup(nf); + + rtk_nf_gating(nf); + + platform_set_drvdata(pdev, nf); + + ret = rtk_nf_nand_chip_init(dev, nf, np); + if (ret) { + dev_err(dev, "failed to init nand chip\n"); + goto rtk_nf_probe_disable_clk; + } + + return 0; + +rtk_nf_probe_disable_clk: + rtk_nf_disable_clk(dev, &nf->clkrst); + +rtk_nf_probe_exit: + + return ret; +} + +static int rtk_nf_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_nf *nf = platform_get_drvdata(pdev); + + nand_release(&nf->chip); + + rtk_nf_disable_clk(dev, &nf->clkrst); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int rtk_nf_suspend(struct device *dev) +{ + struct rtk_nf *nf = dev_get_drvdata(dev); + + rtk_nf_disable_clk(dev, &nf->clkrst); + + return 0; +} + +static int rtk_nf_resume(struct device *dev) +{ + struct rtk_nf *nf = dev_get_drvdata(dev); + + rtk_nf_enable_clk(dev, &nf->clkrst); + + rtk_nf_hw_init(nf); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(rtk_nf_pm_ops, rtk_nf_suspend, rtk_nf_resume); +#endif + +static const struct of_device_id rtk_nf_id_table[] = { + { .compatible = "realtek,rtd12xx-nf" }, + { .compatible = "realtek,rtd13xx-nf" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_nf_id_table); + +static struct platform_driver rtk_nf_driver = { + .probe = rtk_nf_probe, + .remove = rtk_nf_remove, + .driver = { + .name = RTK_NAME, + .of_match_table = rtk_nf_id_table, +#ifdef CONFIG_PM_SLEEP + .pm = &rtk_nf_pm_ops, +#endif + }, +}; + +module_platform_driver(rtk_nf_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("PK Chuang "); +MODULE_DESCRIPTION("RTK Parallel Nand Flash Controller Driver"); diff --git a/drivers/mtd/nand/raw/rtk_nand.h b/drivers/mtd/nand/raw/rtk_nand.h new file mode 100644 index 000000000000..c9fc3feb84cc --- /dev/null +++ b/drivers/mtd/nand/raw/rtk_nand.h @@ -0,0 +1,244 @@ +/* + * rtk_nand.h - nand driver + * + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + * 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. + */ + +#ifndef __NAND_REG_H +#define __NAND_REG_H + + +/* NAND flash register definition */ +#define REG_ND_PA0 (0x0) +#define REG_ND_PA1 (0x4) +#define REG_ND_PA2 (0x8) +#define REG_ND_CA0 (0xc) +#define REG_ND_CMD (0x10) +#define REG_ND_DAT (0x14) +#define REG_ND_CTL (0x18) +#define REG_CMD3 (0x28) +#define REG_ND_PA3 (0x2c) +#define REG_POLL_FSTS (0x30) +#define REG_BLANK_CHK (0x34) +#define REG_ND_ECC (0x38) +#define REG_ND_CA1 (0x3c) +#define REG_DATA_TL0 (0x100) +#define REG_DATA_TL1 (0x104) +#define REG_DMA1_CTL (0x10c) +#define REG_PP_CTL0 (0x110) +#define REG_ECC_SEL (0x128) +#define REG_PP_CTL1 (0x12c) +#define REG_PD (0x130) +#define REG_NF_LOW_PWR (0x13c) +#define REG_DUMMY_NF1 (0x158) +#define REG_DUMMY_NF2 (0x15c) +#define REG_DUMMY_NF3 (0x160) +#define REG_DUMMY_NF4 (0x164) +#define REG_AUTO_TRIG (0x200) +#define REG_RSECC_NUM (0x204) +#define REG_READ_BY_PP (0x228) +#define REG_MAX_ECC_NUM (0x22c) +#define REG_TIME_PARA3 (0x234) +#define REG_TIME_PARA2 (0x238) +#define REG_TIME_PARA1 (0x23c) +#define REG_PIN_MUX_STOP (0x25c) +#define REG_DELAY_CTL (0x260) +#define REG_ECC_STOP (0x264) +#define REG_ECC_PAGE (0x268) +#define REG_PAGE_CNT (0x26c) +#define REG_PAGE_LEN (0x270) +#define REG_CMD2 (0x274) +#define REG_MULTI_CHNL_MODE (0x27c) +#define REG_SRAM_CTL (0x300) +#define REG_DMA_CTL1 (0x304) +#define REG_DMA_CTL2 (0x308) +#define REG_DMA_CTL3 (0x30c) +#define REG_NAND_ISR (0x324) +#define REG_NAND_ISREN (0x328) +#define REG_DUMMY_SYS (0x32c) +#define REG_DBG (0x344) +#define REG_SPR_DDR_CTL (0x348) +#define REG_CP_LEN (0x34C) +#define REG_RND_CMD1 (0x208) +#define REG_RND_CMD2 (0x20c) +#define REG_RND_DATA_STR_COL_H (0x210) +#define REG_RND_SPR_STR_COL_H (0x214) +#define REG_RND_SPR_STR_COL_L (0x218) +#define REG_RND_EN (0x21c) +#define REG_RMZ_CTRL (0x240) +#define REG_RMZ_SEED_L (0x244) +#define REG_RMZ_SEED_H (0x248) + + +#define NF_ND_PA0_page_addr0(value) (0x000000FF&((value)<<0)) +#define NF_ND_PA1_page_addr1(value) (0x000000FF&((value)<<0)) +#define NF_ND_PA2_addr_mode(value) (0x000000E0&((value)<<5)) +#define NF_ND_PA2_page_addr2(value) (0x0000001F&((value)<<0)) +#define NF_ND_CA0_col_addr0(value) (0x000000FF&((value)<<0)) +#define NF_ND_CMD_cmd(value) (0x000000FF&((value)<<0)) +#define NF_ND_DAT_dat(value) (0x000000FF&((value)<<0)) +#define NF_ND_CTL_xfer(value) (0x00000080&((value)<<7)) +#define NF_ND_CTL_ready_busy(value) (0x00000040&((value)<<6)) +#define NF_ND_CTL_ecc_tran(value) (0x00000020&((value)<<5)) +#define NF_ND_CTL_ecc_enable(value) (0x00000008&((value)<<3)) +#define NF_ND_CTL_tran_mode(value) (0x00000007&((value)<<0)) +#define NF_CMD3_cmd3(value) (0x000000FF&((value)<<0)) +#define NF_ND_PA3_page_addr3(value) (0x000000E0&((value)<<5)) +#define NF_POLL_FSTS_bit_sel(value) (0x0000000E&((value)<<1)) +#define NF_POLL_FSTS_trig_poll(value) (0x00000001&((value)<<0)) +#define NF_BLANK_CHK_read_ecc_xnor_ena(value) (0x00000004&((value)<<2)) +#define NF_BLANK_CHK_blank_all_one(value) (0x00000002&((value)<<1)) +#define NF_BLANK_CHK_blank_ena(value) (0x00000001&((value)<<0)) +#define NF_ND_ECC_ecc_not_clr(value) (0x00000008&((value)<<3)) +#define NF_ND_ECC_ecc_err(value) (0x00000004&((value)<<2)) +#define NF_ND_CA1_col_addr1(value) (0x000000FF&((value)<<0)) +#define NF_DATA_TL0_length0(value) (0x000000FF&((value)<<0)) +#define NF_DATA_TL1_access_mode(value) (0x00000080&((value)<<7)) +#define NF_DATA_TL1_sram_path(value) (0x00000040&((value)<<6)) +#define NF_DATA_TL1_length1(value) (0x0000003F&((value)<<0)) +#define NF_DMA_CTL1_dram_sa(value) (0x0FFFFFFF&((value)<<0)) +#define NF_DMA_CTL2_dma_len(value) (0x0000FFFF&((value)<<0)) +#define NF_DMA1_CTL_eot_gen(value) (0x00000008&((value)<<3)) +#define NF_DMA1_CTL_dma_max_pkt(value) (0x00000004&((value)<<2)) +#define NF_DMA1_CTL_spec_pkt(value) (0x00000002&((value)<<1)) +#define NF_PP_CTL0_pp_start_addr(value) (0x00000030&((value)<<4)) +#define NF_PP_CTL0_pp_busy(value) (0x00000004&((value)<<2)) +#define NF_PP_CTL0_pp_reset(value) (0x00000002&((value)<<1)) +#define NF_PP_CTL0_pp_enable(value) (0x00000001&((value)<<0)) +#define NF_ECC_SEL_ecc_bch_24b_ena(value) (0x00000002&((value)<<1)) +#define NF_ECC_SEL_ecc_bch_12b_ena(value) (0x00000001&((value)<<0)) +#define NF_PP_CTL1_pp_start_addr(value) (0x000000FF&((value)<<0)) +#define NF_PD_pd(value) (0x0000001F&((value)<<0)) +#define NF_DUMMY_NF1_Dmy1(value) (0x000000FF&((value)<<0)) +#define NF_DUMMY_NF2_Dmy2(value) (0x000000FF&((value)<<0)) +#define NF_DUMMY_NF3_Dmy3(value) (0x000000FF&((value)<<0)) +#define NF_DUMMY_NF4_Dmy4(value) (0x000000FF&((value)<<0)) +#define NF_AUTO_TRIG_auto_trig(value) (0x00000080&((value)<<7)) +#define NF_AUTO_TRIG_addr_fbd(value) (0x00000040&((value)<<6)) +#define NF_AUTO_TRIG_pp_empty(value) (0x00000020&((value)<<5)) +#define NF_AUTO_TRIG_spec_auto_case(value) (0x00000018&((value)<<3)) +#define NF_AUTO_TRIG_auto_case(value) (0x00000007&((value)<<0)) +#define NF_RSECC_NUM_ecc_num(value) (0x00000001F&((value)<<0)) +#define NF_READ_BY_PP_read_by_pp(value) (0x00000080&((value)<<7)) +#define REG_MAX_ECC_NUM_max_ecc_num(value) (0x00000001F&((value)<<0)) +#define NF_TIME_PARA3_T3(value) (0x000000FF&((value)<<0)) +#define NF_TIME_PARA2_T2(value) (0x000000FF&((value)<<0)) +#define NF_TIME_PARA1_T1(value) (0x000000FF&((value)<<0)) +#define NF_PIN_MUX_STOP_pin_stop(value) (0x00000004&((value)<<2)) +#define NF_PIN_MUX_STOP_intlev_pin_ena(value) (0x00000002&((value)<<1)) +#define NF_PIN_MUX_STOP_pin_mux_enae(value) (0x00000001&((value)<<0)) +#define NF_DELAY_CTL_T_swait_busy(value) (0x000000C0&((value)<<6)) +#define NF_DELAY_CTL_T_WHR_ADL(value) (0x0000003F&((value)<<0)) +#define NF_ECC_STOP_ecc_n_stop(value) (0x00000080&((value)<<7)) +#define NF_ECC_PAGE_ecc_page(value) (0x000000FF&((value)<<0)) +#define NF_PAGE_CNT_page_cnt(value) (0x000000FF&((value)<<0)) +#define NF_PAGE_LEN_page_len(value) (0x000000FF&((value)<<0)) +#define NF_CMD2_cmd2(value) (0x000000FF&((value)<<0)) +#define NF_MULTI_CHNL_MODE_ecc_pass(value) (0x00000080&((value)<<7)) +#define NF_MULTI_CHNL_MODE_ecc_no_check(value) (0x00000040&((value)<<6)) +#define NF_MULTI_CHNL_MODE_edo(value) (0x00000020&((value)<<5)) +#define NF_MULTI_CHNL_MODE_no_wait_busy(value) (0x00000010&((value)<<4)) +#define NF_MULTI_CHNL_MODE_wait_ready(value) (0x0000000C&((value)<<2)) +#define NF_MULTI_CHNL_MODE_multi_chnl_md(value) (0x00000003&((value)<<0)) +#define NF_SRAM_CTL_map_sel(value) (0x00000020&((value)<<5)) +#define NF_SRAM_CTL_access_en(value) (0x00000010&((value)<<4)) +#define NF_SRAM_CTL_mem_region(value) (0x0000000F&((value)<<0)) +#define NF_DMA_CTL3_cp_first(value) (0x00000008&((value)<<3)) +#define NF_DMA_CTL3_cp_enable(value) (0x00000004&((value)<<2)) +#define NF_DMA_CTL3_ddr_wr(value) (0x00000002&((value)<<1)) +#define NF_DMA_CTL3_dma_xfer(value) (0x00000001&((value)<<0)) +#define NF_NAND_ISR_Int5(value) (0x00000020&((value)<<5)) +#define NF_NAND_ISR_Int4(value) (0x00000010&((value)<<4)) +#define NF_NAND_ISR_Int3(value) (0x00000008&((value)<<3)) +#define NF_NAND_ISR_Int2(value) (0x00000004&((value)<<2)) +#define NF_NAND_ISR_Int1(value) (0x00000002&((value)<<1)) +#define NF_NAND_ISR_write_data(value) (0x00000001&((value)<<0)) +#define NF_NAND_ISREN_Int5En(value) (0x00000020&((value)<<5)) +#define NF_NAND_ISREN_Int4En(value) (0x00000010&((value)<<4)) +#define NF_NAND_ISREN_Int3En(value) (0x00000008&((value)<<3)) +#define NF_NAND_ISREN_Int2En(value) (0x00000004&((value)<<2)) +#define NF_NAND_ISREN_Int1En(value) (0x00000002&((value)<<1)) +#define NF_NAND_ISREN_write_data(value) (0x00000001&((value)<<0)) +#define NF_DUMMY_SYS_dmy(value) (0xFFFFFFFF&((value)<<0)) +#define NF_SPR_DDR_CTL_cr_nf_hw_pinmux_ena(value) (0x40000000&((value)<<30)) +#define NF_SPR_DDR_CTL_spare_ddr_ena(value) (0x20000000&((value)<<29)) +#define NF_SPR_DDR_CTL_per_2k_spr_ena(value) (0x10000000&((value)<<28)) +#define NF_SPR_DDR_CTL_spare_dram_sa(value) (0x1FFFFFFF&((value)<<0)) +#define NF_CP_LEN_cp_length(value) (0x01FFFE00&((value)<<9)) + + +#define NFWRITE 1 +#define NFREAD 2 +#define NFERASE 3 + + +/* Reserve Block Area usage */ +#define BB_INIT 0xFFFE +#define RB_INIT 0xFFFD +#define BBT_TAG 0xBB +#define TAG_FACTORY_PARAM (0x82) +#define BB_DIE_INIT 0xEEEE +#define RB_DIE_INIT BB_DIE_INIT +#define BAD_RESERVED 0x4444 + + +#define RTKNF_PROC_DIR_NAME "rtknf" +#define RTKNF_PROC_INFO_DIR_NAME "rtknf/info" +#define RTKNF_PROC_TEST_DIR_NAME "rtknf/test" + + +typedef struct __attribute__ ((__packed__)) { + u16 BB_die; + u16 bad_block; + u16 RB_die; + u16 remap_block; +} BB_t; + +struct rtk_nf_clk_rst { + struct clk *clk; + struct reset_control *reset; +}; + +struct rtk_buffer { + unsigned char tempbuf[32]; + unsigned char *dataBuf; + dma_addr_t dataPhys; + unsigned int index_r; + unsigned int index_w; +#if defined(CONFIG_MTD_RTK_NAND_BBM) + unsigned char *tmpBuf; + dma_addr_t tmpPhys; +#endif +}; + +struct rtk_nf { + struct nand_chip chip; + struct nand_controller controller; + struct rtk_nf_clk_rst clkrst; + struct device *dev; + void __iomem *regs; + void __iomem *pll_regs; + void __iomem *pad_regs; +#if defined(CONFIG_MTD_RTK_NAND_HW_SEMAPHORE) + void __iomem *hwsem_base; +#endif + struct rtk_buffer nandbuf; + u64 size; + + BB_t *bbt; + u32 bbtcrc; + u32 RBA; + + struct proc_dir_entry *rtknf_proc_dir; +}; + +int rtk_nf_get_realpage(struct nand_chip *chip, int page); +int rtk_nf_scan_bbt(struct nand_chip *chip); +int rtk_nf_bb_handle(struct nand_chip *chip, int o_blk, int page, + int backup, int mode); + +#endif diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c index 3ccd6363ee8c..662ac2f537a4 100644 --- a/drivers/mtd/parsers/redboot.c +++ b/drivers/mtd/parsers/redboot.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Parse RedBoot-style Flash Image System (FIS) tables and @@ -14,6 +17,9 @@ #include #include #include +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ #include struct fis_image_desc { @@ -318,6 +324,89 @@ module_mtd_part_parser(redboot_parser); /* mtd parsers will request the module by parser name */ MODULE_ALIAS("RedBoot"); + +#ifdef MY_DEF_HERE +int SYNOMTDModifyFisInfo(struct mtd_info *mtd, struct SYNO_MTD_FIS_INFO SynoMtdFisInfo) +{ + struct fis_image_desc *buf; + int ret, i; + size_t retlen; + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + + if (!buf) { + return -ENOMEM; + } + + /* Read the start of the last erase block */ + ret = mtd_read(mtd, 0, PAGE_SIZE, &retlen, (void *)buf); + + if (ret) + goto out; + + if (retlen != PAGE_SIZE) { + ret = -EIO; + goto out; + } + + for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) { + if (buf[i].name[0] == 0xff) { /* reach the end of FIS directory */ + ret = -ENOENT; /* not found */ + break; + } + + if (0 == strcmp(buf[i].name, SynoMtdFisInfo.name)) { /* match */ + int lockret, eraseret; + struct erase_info einfo; + + buf[i].flash_base = SynoMtdFisInfo.offset; + buf[i].size = SynoMtdFisInfo.size; + buf[i].data_length = SynoMtdFisInfo.data_length; + lockret = mtd_unlock(mtd, 0, mtd->erasesize); + if (lockret) { + printk(KERN_NOTICE "Failed to unlock [%s], error [%d]\n", mtd->name, lockret*(-1)); + } + + /* erase something... */ + memset (&einfo, 0, sizeof(struct erase_info)); + einfo.addr = 0; + einfo.len = mtd->erasesize; + eraseret = mtd_erase(mtd, &einfo); + if (eraseret) { + ret = eraseret; + printk(KERN_NOTICE "Failed to erase [%s], error [%d]\n", mtd->name, eraseret*(-1)); + } else { + /*ret = mtd->write(mtd, sizeof(struct fis_image_desc)*i, + sizeof(struct fis_image_desc), &retlen, &buf[i]);*/ + ret = mtd_write(mtd, 0, PAGE_SIZE, &retlen, (const u_char*)buf); + if (ret) { + printk(KERN_NOTICE "Failed to write [%s], error [%d]\n", mtd->name, ret*(-1)); + } + } + lockret = mtd_lock(mtd, 0, mtd->erasesize); + if (lockret) { + printk(KERN_NOTICE "Failed to lock [%s], error [%d]\n", mtd->name, lockret*(-1)); + } + if (ret) { + goto out; + } + + /*if (retlen != sizeof(struct fis_image_desc)) {*/ + if (retlen != PAGE_SIZE) { + ret = -EIO; + goto out; + } + break; + } + } /* for */ + +out: + kfree(buf); + return ret; +} +#endif /* MY_DEF_HERE */ + + MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse "); MODULE_DESCRIPTION("Parsing code for RedBoot Flash Image System (FIS) tables"); diff --git a/drivers/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig index 5c0e0ec2e6d1..d05faba3a91e 100644 --- a/drivers/mtd/spi-nor/controllers/Kconfig +++ b/drivers/mtd/spi-nor/controllers/Kconfig @@ -62,3 +62,13 @@ config SPI_INTEL_SPI_PLATFORM To compile this driver as a module, choose M here: the module will be called intel-spi-platform. + +if SYNO_LSP_RTD1619B +config SPI_RTK_SFC + tristate "Realtek SPI-NOR Flash Controller(SFC)" + depends on ARCH_REALTEK + depends on HAS_IOMEM && HAS_DMA + help + This enables support for Realtek SPI-NOR flash controller. +endif # SYNO_LSP_RTD1619B + diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile index e7abba491d98..3739ffd809a5 100644 --- a/drivers/mtd/spi-nor/controllers/Makefile +++ b/drivers/mtd/spi-nor/controllers/Makefile @@ -5,3 +5,6 @@ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_SPI_RTK_SFC) += rtk-sfc.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/mtd/spi-nor/controllers/rtk-sfc.c b/drivers/mtd/spi-nor/controllers/rtk-sfc.c new file mode 100644 index 000000000000..673f027db4b4 --- /dev/null +++ b/drivers/mtd/spi-nor/controllers/rtk-sfc.c @@ -0,0 +1,686 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek SPI Nor Flash Controller Driver + * + * Copyright (c) 2021 Realtek Technologies Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SFC_OPCODE (0x00) +#define SFC_CTL (0x04) +#define SFC_SCK (0x08) +#define SFC_CE (0x0c) +#define SFC_WP (0x10) +#define SFC_POS_LATCH (0x14) +#define SFC_WAIT_WR (0x18) +#define SFC_EN_WR (0x1c) +#define SFC_FAST_RD (0x20) +#define SFC_SCK_TAP (0x24) +#define SFP_OPCODE2 (0x28) + +#define MD_BASE_ADDE 0x9801b700 +#define MD_FDMA_DDR_SADDR (0x0c) +#define MD_FDMA_FL_SADDR (0x10) +#define MD_FDMA_CTRL2 (0x14) +#define MD_FDMA_CTRL1 (0x18) + +#define RTKSFC_DMA_MAX_LEN 0x100 +#define RTKSFC_MAX_CHIP_NUM 1 +#define RTKSFC_WAIT_TIMEOUT 1000000 +#define RTKSFC_OP_READ 0x0 +#define RTKSFC_OP_WRITE 0x1 + +#define NOR_BASE_PHYS 0x88100000 + +struct rtksfc_priv { + u32 chipselect; + u32 clkrate; + struct rtksfc_host *host; +}; + +struct rtksfc_host { + struct device *dev; + struct mutex lock; + void __iomem *regbase; + void __iomem *iobase; + void __iomem *mdbase; + void __iomem *r; + struct clk *clk; + void *buffer; + dma_addr_t dma_buffer; + struct spi_nor *nor[RTKSFC_MAX_CHIP_NUM]; + u32 num_chip; +}; + +#define SFC_SYNC \ + do { \ + asm volatile("DMB SY" : : : "memory"); \ + writel(0x0, host->r); \ + asm volatile("DMB SY" : : : "memory"); \ + } while(0); + +static int rtk_spi_nor_read_status(struct rtksfc_host *host) +{ + int i = 100; + + while (i--) { + writel(0x05, host->regbase + SFC_OPCODE); + udelay(50); + writel(0x10, host->regbase + SFC_CTL); + SFC_SYNC + + if ((*(volatile unsigned char *)host->iobase) & 0x1) + msleep(100); + else + return 0; + } + + return -1; +} + +static inline struct spi_nor *rtk_spi_mtd_to_nor(struct mtd_info *mtd) +{ + return container_of(mtd, struct spi_nor, mtd); +} + +static void rtk_spi_nor_read_mode(struct rtksfc_host *host) +{ + unsigned int tmp; + + writel(0x03, host->regbase + SFC_OPCODE); + udelay(50); + writel(0x18, host->regbase + SFC_CTL); + SFC_SYNC + tmp = *(volatile unsigned int *)(host->iobase); + + return; +} + +static void rtk_spi_nor_write_mode(struct rtksfc_host *host) +{ + writel(0x2, host->regbase + SFC_OPCODE); + udelay(50); + writel(0x18, host->regbase + SFC_CTL); + SFC_SYNC + + return; +} + +static void rtk_spi_nor_enable_auto_write(struct rtksfc_host *host) +{ + writel(0x105, host->regbase + SFC_WAIT_WR); + writel(0x106, host->regbase + SFC_EN_WR); + + return; +} + +static void rtk_spi_nor_disable_auto_write(struct rtksfc_host *host) +{ + writel(0x005, host->regbase + SFC_WAIT_WR); + writel(0x006, host->regbase + SFC_EN_WR); + + return; +} + +unsigned int rtk_set_reg(void __iomem *addr, unsigned int offset, int length, unsigned int value) +{ + unsigned int value1, temp; + int j; + + value1 = readl(addr); + + temp = 1; + + for(j=0; jiobase = ioremap(NOR_BASE_PHYS, 0x2000000); + host->mdbase = ioremap(MD_BASE_ADDE, 0x30); + host->r = ioremap(0x9801a020, 0x4); + + writel(0x00000013, host->regbase + SFC_SCK); + writel(0x001a1307, host->regbase + SFC_CE); + writel(0x00000000, host->regbase + SFC_POS_LATCH); + writel(0x00000005, host->regbase + SFC_WAIT_WR); + writel(0x00000006, host->regbase + SFC_EN_WR); + + rtk_spi_nor_driving(1, 0x1, 0x0); + + return; +} + +static int rtk_spi_nor_prep(struct spi_nor *nor) +{ + return 0; +} + +static void rtk_spi_nor_unprep(struct spi_nor *nor) +{ +#if 0 + switch (ops) { + case SPI_NOR_OPS_READ: + break; + + case SPI_NOR_OPS_WRITE: + break; + + case SPI_NOR_OPS_ERASE: + break; + + default: + break; + } +#endif + return; +} + +static int rtk_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, + size_t len) +{ + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + unsigned int value; + unsigned char val; + + writel(opcode, host->regbase + SFC_OPCODE); + udelay(50); + + switch (opcode) { + case SPINOR_OP_RDID: + writel(0x00000010, host->regbase + SFC_CTL); + value = *(volatile unsigned int *)host->iobase; + dev_info(nor->dev, "SPINOR_OP_RDID:[0x%x]\n", value); + memcpy_fromio(buf, (unsigned char *)host->iobase, len); + break; + + case SPINOR_OP_RDSR: + writel(0x00000010, host->regbase + SFC_CTL); + val = *(volatile unsigned char *)host->iobase; + memcpy_fromio(buf, (unsigned char *)host->iobase, len); + break; + + default: + dev_warn(nor->dev, "rtk_spi_nor_read_reg, unknow command\n"); + break; + } + + return 0; +} + +static int rtk_spi_nor_write_reg(struct spi_nor *nor, u8 opcode, + const u8 *buf, size_t len) +{ + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + unsigned int tmp; + + writel(opcode, host->regbase + SFC_OPCODE); + udelay(50); + + switch (opcode) { + case SPINOR_OP_WRSR: + writel(0x10, host->regbase + SFC_CTL); + *(volatile unsigned char *)(host->iobase) = buf[0]; + break; + + case SPINOR_OP_WREN: + writel(0x0, host->regbase + SFC_CTL); + tmp = *(volatile unsigned char *)(host->iobase); + break; + + case SPINOR_OP_WRDI: + writel(0x0, host->regbase + SFC_CTL); + break; + + case SPINOR_OP_EN4B: + writel(0x0, host->regbase + SFC_CTL); + tmp = *(volatile unsigned int *)(host->iobase); + + /* controller setting */ + writel(0x1, host->regbase + SFP_OPCODE2); + break; + + case SPINOR_OP_EX4B: + writel(0x0, host->regbase + SFC_CTL); + tmp = *(volatile unsigned int *)(host->iobase); + + /* controller setting */ + writel(0x0, host->regbase + SFP_OPCODE2); + break; + + case SPINOR_OP_CHIP_ERASE: + dev_info(nor->dev, "Erase whole flash.\n"); + writel(0x0, host->regbase + SFC_CTL); + tmp = *(volatile unsigned char *)host->iobase; + + tmp = rtk_spi_nor_read_status(host); + break; + + default: + dev_warn(nor->dev, "rtk_spi_nor_write_reg, unknow command\n"); + break; + } + + return 0; +} + +static int rtk_spi_nor_byte_transfer(struct spi_nor *nor, loff_t offset, + size_t len, unsigned char *buf, u8 op_type) +{ + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + + if (op_type == RTKSFC_OP_READ) + memcpy_fromio(buf, (unsigned char *)(host->iobase + offset), len); + else + memcpy_toio((unsigned char *)(host->iobase + offset), buf, len); + + return len; +} + +static int rtk_spi_nor_dma_transfer(struct spi_nor *nor, loff_t offset, + size_t len, u8 op_type) +{ + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + unsigned int val; + + writel(0x0a, host->mdbase + MD_FDMA_CTRL1); + + /* setup MD DDR addr and flash addr */ + writel((unsigned long)(host->dma_buffer), + host->mdbase + MD_FDMA_DDR_SADDR); + writel((unsigned long)((volatile u8*)(NOR_BASE_PHYS + offset)), + host->mdbase + MD_FDMA_FL_SADDR); + + if (op_type == RTKSFC_OP_READ) + val = (0xC000000 | len); + else + val = (0x6000000 | len); + + writel(val, host->mdbase + MD_FDMA_CTRL2); + /* go */ + writel(0x03, host->mdbase + MD_FDMA_CTRL1); + + udelay(100); + + while (readl(host->mdbase + MD_FDMA_CTRL1) & 0x1) { + udelay(100); + } + + return rtk_spi_nor_read_status(host); +} + +static ssize_t rtk_spi_nor_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *read_buf) +{ + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + loff_t n_from; + size_t n_len = 0, r_len = 0; + unsigned int offset; + int ret; + int i; + + rtk_spi_nor_disable_auto_write(host); + + offset = from & 0x3; + + /* Byte stage */ + if (offset != 0) { + r_len = (offset > len) ? len : offset; + rtk_spi_nor_read_mode(host); + ret = rtk_spi_nor_byte_transfer(nor, from, r_len, (u8 *)read_buf, + RTKSFC_OP_READ); + } + + n_from = from + r_len; + n_len = len - r_len; + + /* DMA stage */ + while (n_len > 0) { + r_len = (n_len >= RTKSFC_DMA_MAX_LEN) ? RTKSFC_DMA_MAX_LEN : n_len; + + rtk_spi_nor_read_mode(host); + + ret = rtk_spi_nor_dma_transfer(nor, n_from, r_len, + RTKSFC_OP_READ); + if (ret) { + dev_err(nor->dev, "DMA read timeout\n"); + return ret; + } + + for (i = 0; i < r_len; i++) + *(u8 *)(read_buf + offset + i) = *(u8 *)(host->buffer + i); + + n_len -= r_len; + offset += r_len; + n_from += r_len; + } + + return len; +} + +static ssize_t rtk_spi_nor_write(struct spi_nor *nor, loff_t to, + size_t len, const u_char *write_buf) +{ + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + int r_len = (int)len, w_len = 0; + u_char *w_buf = (u_char *)write_buf; + int offset; + int ret; + int i; + + rtk_spi_nor_enable_auto_write(host); + + offset = to & 0x3; + + /* byte stage */ + if (offset != 0) { + w_len = (offset > len) ? len : offset; + rtk_spi_nor_write_mode(host); + ret = rtk_spi_nor_byte_transfer(nor, to, w_len, (u8 *)w_buf, + RTKSFC_OP_WRITE); + w_buf += w_len; + } + + to = to + w_len; + r_len = (int)len - w_len; + + /* DMA stage */ + offset = 0; + while (r_len > 0) { + w_len = (r_len >= RTKSFC_DMA_MAX_LEN) ? RTKSFC_DMA_MAX_LEN : r_len; + + for(i = 0; i < w_len; i++) + *(u8 *)(host->buffer + i) = *(u8 *)(w_buf + i); + + rtk_spi_nor_write_mode(host); + + ret = rtk_spi_nor_dma_transfer(nor, to + offset, w_len, + RTKSFC_OP_WRITE); + + r_len = r_len - w_len; + offset = offset + w_len; + w_buf += w_len; + } + + rtk_spi_nor_read_mode(host); + + return len; +} + +static int rtk_spi_nor_panic_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct spi_nor *nor = rtk_spi_mtd_to_nor(mtd); + + *retlen = rtk_spi_nor_write(nor, to, len, buf); + + return 0; +} + +static int rtk_spi_nor_erase(struct spi_nor *nor, loff_t offs) +{ + struct mtd_info *mtd = &nor->mtd; + struct rtksfc_priv *priv = nor->priv; + struct rtksfc_host *host = priv->host; + unsigned char tmp; + + rtk_spi_nor_disable_auto_write(host); + + if (mtd->erasesize == 4096) + writel(SPINOR_OP_BE_4K, host->regbase + SFC_OPCODE); + else + writel(nor->erase_opcode, host->regbase + SFC_OPCODE); + udelay(50); + writel(0x08, host->regbase + SFC_CTL); + + tmp = *(volatile unsigned char *)(host->iobase + offs); + SFC_SYNC + + return rtk_spi_nor_read_status(host); +} + +static const struct spi_nor_controller_ops rtk_controller_ops = { + .prepare = rtk_spi_nor_prep, + .unprepare = rtk_spi_nor_unprep, + .read_reg = rtk_spi_nor_read_reg, + .write_reg = rtk_spi_nor_write_reg, + .read = rtk_spi_nor_read, + .write = rtk_spi_nor_write, + .erase = rtk_spi_nor_erase, +}; + +static int rtk_spi_nor_register(struct device_node *np, + struct rtksfc_host *host) +{ + const struct spi_nor_hwcaps hwcaps = { + .mask = SNOR_HWCAPS_READ | + SNOR_HWCAPS_READ_FAST | + SNOR_HWCAPS_READ_1_1_2 | + SNOR_HWCAPS_READ_1_1_4 | + SNOR_HWCAPS_PP, + }; + + struct device *dev = host->dev; + struct spi_nor *nor; + struct rtksfc_priv *priv; + struct mtd_info *mtd; + int ret; + + nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL); + if (!nor) + return -ENOMEM; + + nor->dev = dev; + spi_nor_set_flash_node(nor, np); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->host = host; + nor->priv = priv; + + nor->controller_ops = &rtk_controller_ops; + nor->mtd._panic_write = rtk_spi_nor_panic_write; + + ret = spi_nor_scan(nor, NULL, &hwcaps); + if (ret) + return ret; + + mtd = &nor->mtd; + mtd->writesize = nor->page_size; + + mtd->name = "RtkSFC"; + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + return ret; + + host->nor[host->num_chip] = nor; + host->num_chip++; + + return 0; +} + +static void rtk_spi_nor_unregister_all(struct rtksfc_host *host) +{ + int i; + + for (i = 0; i < host->num_chip; i++) + mtd_device_unregister(&host->nor[i]->mtd); +} + +static int rtk_spi_nor_register_all(struct rtksfc_host *host) +{ +#ifdef MY_DEF_HERE + struct device *dev = host->dev; +#else /* MY_DEF_HERE */ + struct device_node *np = NULL; +#endif /* MY_DEF_HERE */ + int ret; + + //for_each_available_child_of_node(dev->of_node, np) { +#ifdef MY_DEF_HERE + ret = rtk_spi_nor_register(dev->of_node, host); +#else /* MY_DEF_HERE */ + ret = rtk_spi_nor_register(np, host); +#endif /* MY_DEF_HERE */ + if (ret) + goto fail; + //} + + return 0; + +fail: + rtk_spi_nor_unregister_all(host); + return ret; +} + +static int rtk_spi_nor_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct rtksfc_host *host; + int ret; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + platform_set_drvdata(pdev, host); + host->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host->regbase = devm_ioremap_resource(dev, res); + if (IS_ERR(host->regbase)) + return PTR_ERR(host->regbase); + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(dev, "Unable to set dma mask\n"); + return ret; + } + + host->buffer = dmam_alloc_coherent(dev, RTKSFC_DMA_MAX_LEN, + &host->dma_buffer, GFP_KERNEL); + if (!host->buffer) + return -ENOMEM; + + mutex_init(&host->lock); + + rtk_spi_nor_init(host); + + ret = rtk_spi_nor_register_all(host); + if (ret) + mutex_destroy(&host->lock); + + return ret; +} + +static int rtk_spi_nor_remove(struct platform_device *pdev) +{ + struct rtksfc_host *host = platform_get_drvdata(pdev); + + mutex_destroy(&host->lock); + + return 0; +} + +static const struct of_device_id rtk_spi_nor_dt_ids[] = { + { .compatible = "realtek,rtd16xxb-sfc"}, + { .compatible = "realtek,rtd13xx-sfc"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtk_spi_nor_dt_ids); + +static struct platform_driver rtk_spi_nor_driver = { + .driver = { + .name = "rtk-sfc", + .of_match_table = rtk_spi_nor_dt_ids, + }, + .probe = rtk_spi_nor_probe, + .remove = rtk_spi_nor_remove, +}; +module_platform_driver(rtk_spi_nor_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Realtek SPI Nor Flash Controller Driver"); diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 2b26a875a855..a41ce44c14f8 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with @@ -1457,6 +1460,10 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) u32 addr, len; uint32_t rem; int ret; +#ifdef MY_DEF_HERE + u32 origin_erasesize = mtd->erasesize; + u32 origin_erase_opcode = nor->erase_opcode; +#endif /* MY_DEF_HERE */ dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, (long long)instr->len); @@ -1507,6 +1514,15 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) /* "sector"-at-a-time erase */ } else if (spi_nor_has_uniform_erase(nor)) { while (len) { +#ifdef MY_DEF_HERE + if ((len >= nor->info->sector_size) && (0 == addr % nor->info->sector_size)) { + mtd->erasesize = nor->info->sector_size; + nor->erase_opcode = SPINOR_OP_SE; + } else { + mtd->erasesize = origin_erasesize; + nor->erase_opcode = origin_erase_opcode; + } +#endif /* MY_DEF_HERE */ ret = spi_nor_write_enable(nor); if (ret) goto erase_err; @@ -1533,6 +1549,10 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) ret = spi_nor_write_disable(nor); erase_err: +#ifdef MY_DEF_HERE + mtd->erasesize = origin_erasesize; + nor->erase_opcode = origin_erase_opcode; +#endif /* MY_DEF_HERE */ spi_nor_unlock_and_unprep(nor); return ret; @@ -1863,6 +1883,25 @@ static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = { .is_locked = spi_nor_sr_is_locked, }; +#ifdef MY_DEF_HERE +static int syno_null_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return 0; +} + +static int syno_null_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return 0; +} + + +static const struct spi_nor_locking_ops syno_null_locking_ops = { + .lock = syno_null_lock, + .unlock = syno_null_unlock, + .is_locked = NULL, +}; +#endif /* MY_DEF_HERE */ + static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct spi_nor *nor = mtd_to_spi_nor(mtd); @@ -2838,6 +2877,11 @@ static void spi_nor_late_init_params(struct spi_nor *nor) */ if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops) nor->params->locking_ops = &spi_nor_sr_locking_ops; +#ifdef MY_DEF_HERE + else { + nor->params->locking_ops = &syno_null_locking_ops; + } +#endif /* MY_DEF_HERE */ } /** diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index aa001b16765a..c135657649f4 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. @@ -2493,6 +2496,9 @@ void bond_3ad_adapter_speed_duplex_changed(struct slave *slave) spin_lock_bh(&slave->bond->mode_lock); ad_update_actor_keys(port, false); +#ifdef MY_ABC_HERE + port->sm_vars |= AD_PORT_BEGIN; +#endif /* CONFIG_SYNO_8023AD_LINK_STATUS */ spin_unlock_bh(&slave->bond->mode_lock); slave_dbg(slave->bond->dev, slave->dev, "Port %d changed speed/duplex\n", port->actor_port_number); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index c3091e00dd5f..178d94b16ec6 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. @@ -159,8 +162,13 @@ static void tlb_deinitialize(struct bonding *bond) static long long compute_gap(struct slave *slave) { +#ifdef MY_ABC_HERE + return ((s64) (slave->speed) << 20) - /* Convert to Megabit per sec */ + ((s64) (SLAVE_TLB_INFO(slave).load) << 3); /* Bytes to bits */ +#else /* MY_ABC_HERE */ return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */ (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ +#endif /* MY_ABC_HERE */ } static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) @@ -1826,3 +1834,110 @@ void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id) rlb_clear_vlan(bond, vlan_id); } +#if defined(MY_ABC_HERE) +void bond_alb_info_show(struct seq_file *seq) +{ + struct bonding *bond = PDE_DATA(file_inode(seq->file)); + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *rclient_info; + struct tlb_client_info *tclient_info; + struct slave *slave; + u32 index; + struct list_head *iter; + bool rcinfo_visited[RLB_HASH_TABLE_SIZE] = { false }; + + seq_puts(seq, "\nALB info\n"); + seq_puts(seq, "\n Receive Load Balancing table:\n"); + seq_puts(seq, " Index Slave Assigned Client-MAC" + " Server -> Client\n"); + + spin_lock_bh(&bond->mode_lock); + index = bond_info->rx_hashtbl_used_head; + for (; bond_info->rx_hashtbl && index != RLB_NULL_INDEX; + index = rclient_info->used_next) { + if (rcinfo_visited[index]) { + break; + } + rcinfo_visited[index] = true; + rclient_info = &(bond_info->rx_hashtbl[index]); + + if (rclient_info) { + seq_printf(seq, "%6u: %-8s %6s %-17pM ", + index, + (rclient_info->slave && + rclient_info->slave->dev && + rclient_info->slave->dev->name[0] != '\0' ? + rclient_info->slave->dev->name : "(none)"), + (rclient_info->assigned ? "yes" : "no"), + rclient_info->mac_dst); + + /* Implemented as separate outputs to + support IPv6 in the future (if it's supported) */ + seq_printf(seq, NIPQUAD_FMT " -> ", + NIPQUAD(rclient_info->ip_src)); + seq_printf(seq, NIPQUAD_FMT "\n", + NIPQUAD(rclient_info->ip_dst)); + } + } + + seq_puts(seq, "\n Transmit Load Balancing table:\n"); +#ifdef MY_ABC_HERE + seq_printf(seq, " Unbalanced load: %llu\n" +#else /* MY_ABC_HERE */ + seq_printf(seq, " Unbalanced load: %u\n" +#endif /* MY_ABC_HERE */ + " Rebalance interval: %u seconds\n\n", + bond_info->unbalanced_load, + BOND_TLB_REBALANCE_INTERVAL); + + /* Process each slave */ + bond_for_each_slave(bond, slave, iter) { + + if (slave) { + bool tcinfo_visited[TLB_HASH_TABLE_SIZE] = { false }; + seq_puts(seq, " Slave Used Speed Duplex" + " Current load\n"); +#ifdef MY_ABC_HERE + seq_printf(seq, " %-8s %3s %-8u %4s %10llu\n", +#else /* MY_ABC_HERE */ + seq_printf(seq, " %-8s %3s %-8u %4s %10u\n", +#endif /* MY_ABC_HERE */ + (slave->dev->name[0] != '\0' ? + slave->dev->name : "none"), + (bond_slave_can_tx(slave) ? "yes" : "no"), + slave->speed, + (slave->duplex ? "full" : "half"), + SLAVE_TLB_INFO(slave).load); + + seq_puts(seq, " Index TX Bytes " + "Load history\n"); + + index = SLAVE_TLB_INFO(slave).head; + for (; bond_info->tx_hashtbl && index != TLB_NULL_INDEX; + index = tclient_info->next) { + if (tcinfo_visited[index]) { + break; + } + tcinfo_visited[index] = true; + + tclient_info = &(bond_info->tx_hashtbl[index]); + if (tclient_info) + seq_printf(seq, " " +#ifdef MY_ABC_HERE + "%3u: %10llu" + " %10llu\n", +#else /* MY_ABC_HERE */ + "%3u: %10u" + " %10u\n", +#endif /* MY_ABC_HERE */ + index, + tclient_info->tx_bytes, + tclient_info->load_history); + } + seq_puts(seq, "\n"); + } + } + spin_unlock_bh(&bond->mode_lock); +} +#endif /* MY_ABC_HERE */ + diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 018af1e38eb9..af4272dd40c7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * originally based on the dummy device. * @@ -596,6 +599,20 @@ static const struct xfrmdev_ops bond_xfrmdev_ops = { /*------------------------------- Link status -------------------------------*/ +#if defined(MY_ABC_HERE) +static void default_operstate(struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) { + dev->operstate = (dev->ifindex != dev_get_iflink(dev) ? + IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); + } else if (netif_dormant(dev)) { + dev->operstate = IF_OPER_DORMANT; + } else { + dev->operstate = IF_OPER_UP; + } +} +#endif /* MY_ABC_HERE */ + /* Set the carrier state for the master according to the state of its * slaves. If any slaves are up, the master is up. In 802.3ad mode, * do special 802.3ad magic. @@ -881,6 +898,9 @@ static int bond_set_dev_addr(struct net_device *bond_dev, struct net_device *slave_dev) { int err; +#ifdef MY_ABC_HERE + unsigned char szMac[MAX_ADDR_LEN]; +#endif /* MY_ABC_HERE */ slave_dbg(bond_dev, slave_dev, "bond_dev=%p slave_dev=%p slave_dev->addr_len=%d\n", bond_dev, slave_dev, slave_dev->addr_len); @@ -888,7 +908,26 @@ static int bond_set_dev_addr(struct net_device *bond_dev, if (err) return err; +#ifdef MY_ABC_HERE + memset(szMac, 0, sizeof(szMac)); + if (syno_get_dev_vendor_mac(slave_dev->name, szMac, sizeof(szMac))) { + printk("%s:%s(%d) dev:[%s] get vendor mac fail\n", + __FILE__, __FUNCTION__, __LINE__, slave_dev->name); + /** + * Cannot get SYNO's vendor mac, possibly because + * - mac not written to onboard flash, or + * - this eth is on addon card rather than on mainboard. + * Fallback to perm_hwaddr. + */ + memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); + } else { + /* Normal case: set to syno vendor mac */ + memcpy(bond_dev->dev_addr, szMac, ETH_ALEN); + } +#else /* MY_ABC_HERE */ memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); +#endif /* MY_ABC_HERE */ + bond_dev->addr_assign_type = NET_ADDR_STOLEN; call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev); return 0; @@ -1699,6 +1738,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, struct sockaddr_storage ss; int link_reporting; int res = 0, i; +#ifdef MY_ABC_HERE + unsigned char szMac[MAX_ADDR_LEN] = {0}; +#endif /* MY_ABC_HERE */ if (!bond->params.use_carrier && slave_dev->ethtool_ops->get_link == NULL && @@ -1851,8 +1893,29 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, * that need it, and for restoring it upon release, and then * set it to the master's address */ +#ifdef MY_ABC_HERE + memset(szMac, 0, sizeof(szMac)); + + if (syno_get_dev_vendor_mac(slave_dev->name, szMac, sizeof(szMac))) { + netdev_info(bond_dev, "%s:%s(%d) dev:[%s] get vendor mac fail\n", + __FILE__, __FUNCTION__, __LINE__, slave_dev->name); + /** + * Cannot get SYNO's vendor mac, possibly because + * - mac not written to onboard flash, or + * - this eth is on addon card rather than on mainboard. + * Fallback to perm_hwaddr. + */ + bond_hw_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr, + slave_dev->addr_len); + } else { + /* Normal case: set to syno vendor mac */ + bond_hw_addr_copy(new_slave->perm_hwaddr, szMac, + slave_dev->addr_len); + } +#else /* MY_ABC_HERE */ bond_hw_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr, slave_dev->addr_len); +#endif /* MY_ABC_HERE */ if (!bond->params.fail_over_mac || BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { @@ -2089,6 +2152,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, bond->slave_cnt++; bond_compute_features(bond); bond_set_carrier(bond); +#if defined(MY_ABC_HERE) + default_operstate(bond->dev); +#endif /* MY_ABC_HERE */ if (bond_uses_primary(bond)) { block_netpoll_tx(); @@ -2545,6 +2611,27 @@ static void bond_miimon_commit(struct bonding *bond) } else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ bond_set_active_slave(slave); +#if defined(MY_ABC_HERE) + } else if (slave != primary) { + /* While keep changing the MTU of a bonding interface in active backup mode, + * there is a chance that + * (1) the speed of the current active slave remains unknown, or + * (2) the current active slave is not actived + * Either case causes the speed of the current active slave remains unknown. + * If the speed of a bonding interface is unknown, its MTU can not + * be changed again using synonet tool. + * To solve the problem, this workaround changes the current active slave to + * the next upped NIC slave with correct speed. */ + block_netpoll_tx(); + if ((NULL != bond->curr_active_slave) && + (slave != bond->curr_active_slave) && + (((SPEED_UNKNOWN == bond->curr_active_slave->speed) && + (SPEED_UNKNOWN != slave->speed)) || + (!bond_is_active_slave(bond->curr_active_slave)))) { + bond_change_active_slave(bond, slave); + } + unblock_netpoll_tx(); +#endif /* MY_ABC_HERE */ } slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n", diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index fd5c9cbe45b1..eb53af3fe583 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -163,6 +166,10 @@ static void bond_info_show_master(struct seq_file *seq) ad_info.partner_system); } } +#if defined(MY_ABC_HERE) + } else if (bond->params.mode == BOND_MODE_ALB) { + bond_alb_info_show(seq); +#endif /* MY_ABC_HERE */ } } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index b2cd3bdba9f8..89b28d630040 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -1279,6 +1279,14 @@ #define MDIO_PMA_10GBR_FECCTRL 0x00ab #endif +#ifndef MDIO_PMA_RX_EQ_CTRL +#define MDIO_PMA_RX_EQ_CTRL 0x8009 +#endif + +#ifndef MDIO_PMA_RX_CTRL0 +#define MDIO_PMA_RX_CTRL0 0x8050 +#endif + #ifndef MDIO_PMA_RX_CTRL1 #define MDIO_PMA_RX_CTRL1 0x8051 #endif @@ -1327,10 +1335,34 @@ #define MDIO_VEND2_AN_STAT 0x8002 #endif +#ifndef MDIO_PMA_RX_EQ_CTRL +#define MDIO_PMA_RX_EQ_CTRL 0x8009 +#endif + +#ifndef MDIO_MMD_DIGITAL_STAT +#define MDIO_MMD_DIGITAL_STAT 0x8010 +#endif + +#ifndef MDIO_PMA_RX_CTRL0 +#define MDIO_PMA_RX_CTRL0 0x8050 +#endif + +#ifndef MDIO_PMA_RX_CTRL1 +#define MDIO_PMA_RX_CTRL1 0x8051 +#endif + #ifndef MDIO_VEND2_PMA_CDR_CONTROL #define MDIO_VEND2_PMA_CDR_CONTROL 0x8056 #endif +#ifndef MDIO_VEND2_PMA_MISC_CTRL0 +#define MDIO_VEND2_PMA_MISC_CTRL0 0x8090 +#endif + +#ifndef MDIO_VEND2_PMA_MISC_CTRL1 +#define MDIO_VEND2_PMA_MISC_CTRL1 0x8099 +#endif + #ifndef MDIO_CTRL1_SPEED1G #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) #endif @@ -1385,10 +1417,22 @@ #define XGBE_PMA_CDR_TRACK_EN_OFF 0x00 #define XGBE_PMA_CDR_TRACK_EN_ON 0x01 +#define XGBE_PMA_PLL_CTRL_MASK BIT(15) +#define XGBE_PMA_PLL_CTRL_SET BIT(15) +#define XGBE_PMA_PLL_CTRL_CLEAR 0x0000 + #define XGBE_PMA_RX_RST_0_MASK BIT(4) #define XGBE_PMA_RX_RST_0_RESET_ON 0x10 #define XGBE_PMA_RX_RST_0_RESET_OFF 0x00 +#define XGBE_PMA_RX_EQ_MGMT_MODE_MASK BIT(15) +#define XGBE_PMA_RX_EQ_MGMT_MODE_OFF BIT(15) +#define XGBE_PMA_RX_EQ_MGMT_MODE_ON 0x0 + +#define XGBE_PMA_RX_DT_EN_0_MASK BIT(8) +#define XGBE_PMA_RX_DT_EN_0_ON 0x0100 +#define XGBE_PMA_RX_DT_EN_0_OFF 0x0000 + /* Bit setting and getting macros * The get macro will extract the current bit field value from within * the variable diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index b0a6c96b6ef4..76a7c61daf71 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c @@ -217,6 +217,36 @@ static ssize_t xgmac_reg_value_write(struct file *filp, return len; } +static ssize_t xgbe_phy_led_test_mode_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t xgbe_phy_led_test_mode_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct xgbe_prv_data *pdata = filp->private_data; + unsigned int value; + ssize_t len; + + len = xgbe_common_write(buffer, count, ppos, &value); + if (len < 0) + return len; + + pdata->phy_if.phy_impl.phy_led_test_mode(pdata, value); + + return len; +} + +static const struct file_operations xgbe_phy_led_test_mode_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = xgbe_phy_led_test_mode_read, + .write = xgbe_phy_led_test_mode_write, +}; + static const struct file_operations xgmac_reg_addr_fops = { .owner = THIS_MODULE, .open = simple_open, @@ -454,6 +484,9 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata) debugfs_create_file("xgmac_register", 0600, pdata->xgbe_debugfs, pdata, &xgmac_reg_addr_fops); + debugfs_create_file("xgbe_phy_led_test_mode", 0600, pdata->xgbe_debugfs, pdata, + &xgbe_phy_led_test_mode_fops); + debugfs_create_file("xgmac_register_value", 0600, pdata->xgbe_debugfs, pdata, &xgmac_reg_value_fops); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 395eb0b52680..6022f2027a1b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -629,7 +632,11 @@ static irqreturn_t xgbe_dma_isr(int irq, void *data) disable_irq_nosync(channel->dma_irq); /* Turn on polling */ +#ifdef MY_DEF_HERE + __napi_schedule(&channel->napi); +#else /* MY_DEF_HERE */ __napi_schedule_irqoff(&channel->napi); +#endif /* MY_DEF_HERE */ } /* Clear Tx/Rx signals */ @@ -1296,6 +1303,8 @@ static int xgbe_start(struct xgbe_prv_data *pdata) unsigned int i; int ret; + pdata->ext_fixed_phy = 0; + /* Set the number of queues */ ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count); if (ret) { @@ -1367,6 +1376,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) if (test_bit(XGBE_STOPPED, &pdata->dev_state)) return; + pdata->ext_fixed_phy = 0; netif_tx_stop_all_queues(netdev); netif_carrier_off(pdata->netdev); @@ -2067,12 +2077,59 @@ static int xgbe_change_mtu(struct net_device *netdev, int mtu) return 0; } +#ifdef MY_DEF_HERE +static int xgbe_tx_poll(struct xgbe_channel *channel); + +static int syno_xgbe_fake_tx_timeout_check(struct net_device *netdev) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + int queue = 0; + struct xgbe_ring *ring = NULL; + struct xgbe_channel *channel = NULL; + struct netdev_queue *txq = NULL; + unsigned long trans_start = 0; + + for (queue = 0 ; queue < pdata->tx_q_count ; queue++) { + txq = netdev_get_tx_queue(netdev, queue); + trans_start = txq->trans_start ? : dev_trans_start(netdev); + if (netif_xmit_stopped(txq) && + time_after(jiffies, (trans_start + netdev->watchdog_timeo))) { + + ring = pdata->channel[queue]->tx_ring; + channel = pdata->channel[queue]; + + /* Clear tx descriptor if possible */ + xgbe_disable_rx_tx_int(pdata, channel); + xgbe_tx_poll(channel); + + if (ring->dirty != ring->cur) { + /* tx hang */ + return 1; + } else { + xgbe_enable_rx_tx_int(pdata, channel); + netdev_warn(netdev, "fake tx timeout, clear the tx descriptor \n"); + } + } + } + return 0; +} +#endif /* MY_DEF_HERE */ + static void xgbe_tx_timeout(struct net_device *netdev, unsigned int txqueue) { struct xgbe_prv_data *pdata = netdev_priv(netdev); +#ifdef MY_DEF_HERE + int ret = 0; + ret = syno_xgbe_fake_tx_timeout_check(netdev); + if (ret) { + netdev_warn(netdev, "tx timeout, device restarting\n"); + schedule_work(&pdata->restart_work); + } +#else /* MY_DEF_HERE */ netdev_warn(netdev, "tx timeout, device restarting\n"); schedule_work(&pdata->restart_work); +#endif /* MY_DEF_HERE */ } static void xgbe_get_stats64(struct net_device *netdev, @@ -2087,18 +2144,37 @@ static void xgbe_get_stats64(struct net_device *netdev, s->rx_packets = pstats->rxframecount_gb; s->rx_bytes = pstats->rxoctetcount_gb; +#if defined(MY_DEF_HERE) + s->rx_errors = (pstats->rxframecount_gb > (pstats->rxbroadcastframes_g + + pstats->rxmulticastframes_g + + pstats->rxunicastframes_g))? \ + (pstats->rxframecount_gb - + pstats->rxbroadcastframes_g - + pstats->rxmulticastframes_g - + pstats->rxunicastframes_g) : 0; +#else /* MY_DEF_HERE */ s->rx_errors = pstats->rxframecount_gb - pstats->rxbroadcastframes_g - pstats->rxmulticastframes_g - pstats->rxunicastframes_g; +#endif /* MY_DEF_HERE */ s->multicast = pstats->rxmulticastframes_g; s->rx_length_errors = pstats->rxlengtherror; s->rx_crc_errors = pstats->rxcrcerror; +#if defined(MY_DEF_HERE) + /* Don't update RX FIFO overflow error */ +#else /* MY_DEF_HERE */ s->rx_fifo_errors = pstats->rxfifooverflow; +#endif /* MY_DEF_HERE */ s->tx_packets = pstats->txframecount_gb; s->tx_bytes = pstats->txoctetcount_gb; +#if defined(MY_DEF_HERE) + s->tx_errors = (pstats->txframecount_gb > pstats->txframecount_g)? \ + pstats->txframecount_gb - pstats->txframecount_g : 0; +#else /* MY_DEF_HERE */ s->tx_errors = pstats->txframecount_gb - pstats->txframecount_g; +#endif /* MY_DEF_HERE */ s->tx_dropped = netdev->stats.tx_dropped; DBGPR("<--%s\n", __func__); @@ -2557,6 +2633,14 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) buf2_len = xgbe_rx_buf2_len(rdata, packet, len); len += buf2_len; + if (buf2_len > rdata->rx.buf.dma_len) { + /* Hardware inconsistency within the descriptors + * that has resulted in a length underflow. + */ + error = 1; + goto skip_data; + } + if (!skb) { skb = xgbe_create_skb(pdata, napi, rdata, buf1_len); @@ -2586,8 +2670,10 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) if (!last || context_next) goto read_again; - if (!skb) + if (!skb || error) { + dev_kfree_skb(skb); goto next_packet; + } /* Be sure we don't exceed the configured MTU */ max_len = netdev->mtu + ETH_HLEN; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 61f39a0e04f9..60a7aa5e2350 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -381,16 +384,30 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, } ret = 0; +#if defined(MY_DEF_HERE) + pdata->phy.autoneg = AUTONEG_ENABLE; +#else /* MY_DEF_HERE */ pdata->phy.autoneg = cmd->base.autoneg; +#endif /* MY_DEF_HERE */ pdata->phy.speed = speed; pdata->phy.duplex = cmd->base.duplex; bitmap_copy(lks->link_modes.advertising, advertising, __ETHTOOL_LINK_MODE_MASK_NBITS); +#if defined(MY_DEF_HERE) + XGBE_SET_ADV(lks, Autoneg); + + if (cmd->base.autoneg == AUTONEG_DISABLE && speed == SPEED_1000) { + pdata->phy_if.phy_impl.force_1g(pdata); + } else { + pdata->phy_if.phy_impl.resume_autoneg(pdata); + } +#else /* MY_DEF_HERE */ if (cmd->base.autoneg == AUTONEG_ENABLE) XGBE_SET_ADV(lks, Autoneg); else XGBE_CLR_ADV(lks, Autoneg); +#endif /* MY_DEF_HERE */ if (netif_running(netdev)) ret = pdata->phy_if.phy_config_aneg(pdata); @@ -812,6 +829,31 @@ static int xgbe_set_channels(struct net_device *netdev, return 0; } +#if defined(MY_DEF_HERE) +static void syno_xgbe_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct xgbe_prv_data *pdata = netdev_priv(dev); + + wol->supported = WAKE_MAGIC; + + if (pdata->wol_flag & WAKE_MAGIC) { + wol->wolopts |= WAKE_MAGIC; + } +} + +static int syno_xgbe_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct xgbe_prv_data *pdata = netdev_priv(dev); + + if (wol->wolopts & WAKE_MAGIC) + pdata->wol_flag |= WAKE_MAGIC; + else + pdata->wol_flag &= ~WAKE_MAGIC; + + return 0; +} +#endif /* MY_DEF_HERE */ + static const struct ethtool_ops xgbe_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -840,6 +882,10 @@ static const struct ethtool_ops xgbe_ethtool_ops = { .set_ringparam = xgbe_set_ringparam, .get_channels = xgbe_get_channels, .set_channels = xgbe_set_channels, +#if defined(MY_DEF_HERE) + .get_wol = syno_xgbe_get_wol, + .set_wol = syno_xgbe_set_wol, +#endif /* MY_DEF_HERE */ }; const struct ethtool_ops *xgbe_get_ethtool_ops(void) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index a218dc6f2edd..54687437cb80 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -387,7 +390,11 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) netdev->max_mtu = XGMAC_JUMBO_PACKET_MTU; /* Use default watchdog timeout */ +#ifdef MY_DEF_HERE + netdev->watchdog_timeo = 10 * HZ; +#else /* MY_DEF_HERE */ netdev->watchdog_timeo = 0; +#endif /* MY_DEF_HERE */ xgbe_init_rx_coalesce(pdata); xgbe_init_tx_coalesce(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 4e97b4869522..c84b473b1dd8 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -402,14 +405,27 @@ static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, reg |= MDIO_AN_CTRL1_RESTART; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); + + if (xgbe_in_kr_mode(pdata) && (enable || restart)) { + reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); + reg |= XGBE_KR_TRAINING_ENABLE; + reg |= XGBE_KR_TRAINING_START; + XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); + + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL, + BIT(15), BIT(15)); /* Disable RX Adapter */ + } } static void xgbe_an73_restart(struct xgbe_prv_data *pdata) { - xgbe_an73_enable_interrupts(pdata); - xgbe_an73_set(pdata, true, true); + /* When an_kr_workaround is enabled, AN is already done for KR mode */ + if (!pdata->vdata->an_kr_workaround || !xgbe_in_kr_mode(pdata)) { + xgbe_an73_enable_interrupts(pdata); + xgbe_an73_set(pdata, true, true); + } - netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted\n"); + netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted, CL72 started\n"); } static void xgbe_an73_disable(struct xgbe_prv_data *pdata) @@ -489,20 +505,41 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg); /* Start KR training */ + if (!pdata->phy_if.phy_impl.kr_training_cdroff(pdata)) + netif_dbg(pdata, link, pdata->netdev, "setting phy_data->phy_cdr_notrack\n"); + + pdata->cdr_delay_required = 1; + if (pdata->phy_if.phy_impl.kr_training_pre) pdata->phy_if.phy_impl.kr_training_pre(pdata); reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); - reg |= XGBE_KR_TRAINING_ENABLE; reg |= XGBE_KR_TRAINING_START; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); + pdata->kr_done = 1; + pdata->kr_start_time = jiffies; + netif_dbg(pdata, link, pdata->netdev, "KR training initiated\n"); + /* set RX_EQ_MGMT_MODE to disable RX Adapt Requests */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL, BIT(15), BIT(15)); + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, + XGBE_PMA_CDR_TRACK_EN_MASK, + XGBE_PMA_CDR_TRACK_EN_OFF); + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL0, BIT(8), 0); if (pdata->phy_if.phy_impl.kr_training_post) pdata->phy_if.phy_impl.kr_training_post(pdata); + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL0, BIT(8), BIT(8)); + pdata->cdr_delay_required = 0; + udelay(1); + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL, + BIT(15), 0); + if (pdata->phy_if.phy_impl.update_cdr_delay) + pdata->phy_if.phy_impl.update_cdr_delay(pdata); + return XGBE_AN_PAGE_RECEIVED; } @@ -632,6 +669,8 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) xgbe_switch_mode(pdata); + pdata->an_result = XGBE_AN_READY; + xgbe_an_restart(pdata); return XGBE_AN_INCOMPAT_LINK; @@ -854,6 +893,8 @@ static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata) break; case XGBE_AN_PAGE_RECEIVED: + if (xgbe_in_kr_mode(pdata)) + pdata->an_int = 0; pdata->an_state = xgbe_an73_page_received(pdata); pdata->an_supported++; break; @@ -897,8 +938,6 @@ static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata) pdata->kx_state = XGBE_RX_BPA; pdata->an_start = 0; - if (pdata->phy_if.phy_impl.an_post) - pdata->phy_if.phy_impl.an_post(pdata); netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n", xgbe_state_as_string(pdata->an_result)); @@ -1131,7 +1170,11 @@ static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) new_state = 1; pdata->phy_link = pdata->phy.link; } +#ifdef MY_DEF_HERE + } else if (0 < pdata->phy_link) { +#else /* MY_DEF_HERE */ } else if (pdata->phy_link) { +#endif /* MY_DEF_HERE */ new_state = 1; pdata->phy_link = 0; pdata->phy_speed = SPEED_UNKNOWN; @@ -1177,6 +1220,12 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) xgbe_set_mode(pdata, mode); + if (pdata->phy.autoneg == AUTONEG_DISABLE) { + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, + XGBE_PMA_PLL_CTRL_MASK, XGBE_PMA_PLL_CTRL_SET); + usleep_range(100, 200); + } + return 0; } @@ -1243,6 +1292,9 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode) /* Re-enable auto-negotiation interrupt */ enable_irq(pdata->an_irq); + if (pdata->phy_if.phy_impl.an_post) + pdata->phy_if.phy_impl.an_post(pdata); + xgbe_an_init(pdata); xgbe_an_restart(pdata); @@ -1275,11 +1327,34 @@ static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata) { unsigned long link_timeout; + int wait = 100; + unsigned long kr_time; + unsigned long rrc_time; link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ); if (time_after(jiffies, link_timeout)) { netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n"); - xgbe_phy_config_aneg(pdata); + /* AN restart should not happen within 500ms of start of RRC or KR tarining */ + /* This loop ensures no AN restart during RRC window and KR training window */ + while (wait--) { + mutex_lock(&pdata->an_mutex); + kr_time = pdata->kr_start_time + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); + rrc_time = pdata->rrc_start_time + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); + mutex_unlock(&pdata->an_mutex); + if (time_after(jiffies, kr_time) && time_after(jiffies, rrc_time)) + break; + if (pdata->an_result == XGBE_AN_COMPLETE) + break; + + usleep_range(5000, 6000); + } + /* AN restart is required, if AN result is not COMPLETE */ + if (pdata->an_result != XGBE_AN_COMPLETE) + xgbe_phy_config_aneg(pdata); + else if ((pdata->an_result == XGBE_AN_COMPLETE) && + (xgbe_cur_mode(pdata) == XGBE_MODE_KX_1000)) + xgbe_phy_config_aneg(pdata); + } } @@ -1350,6 +1425,8 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata) if (pdata->phy.link) { if (link_aneg && !xgbe_phy_aneg_done(pdata)) { + pdata->phy.link = 0; + xgbe_phy_adjust_link(pdata); xgbe_check_link_timeout(pdata); return; } @@ -1360,17 +1437,34 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata) clear_bit(XGBE_LINK_INIT, &pdata->dev_state); netif_carrier_on(pdata->netdev); + + if (link_aneg && pdata->kr_done) + pdata->phy_if.phy_impl.reset_cdr_delay(pdata); + } else { if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { xgbe_check_link_timeout(pdata); +#ifdef MY_DEF_HERE + /* Bug fix for AN failure in KR mode */ + if (link_aneg && !xgbe_phy_aneg_done(pdata)) { + return; + } +#else /* MY_DEF_HERE */ if (link_aneg) return; +#endif /* MY_DEF_HERE */ } xgbe_phy_status_result(pdata); netif_carrier_off(pdata->netdev); + + if (link_aneg && ((pdata->phy_if.phy_impl.cur_mode(pdata) == XGBE_MODE_KR) || + (pdata->phy_if.phy_impl.cur_mode(pdata) == XGBE_MODE_KX_1000))) { + if (!test_bit(XGBE_LINK_INIT, &pdata->dev_state)) + set_bit(XGBE_LINK_INIT, &pdata->dev_state); + } } adjust_link: diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 90cb55eb5466..ebfb31a0107d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -118,6 +121,9 @@ #include #include #include +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ #include "xgbe.h" #include "xgbe-common.h" @@ -473,6 +479,7 @@ static const struct xgbe_version_data xgbe_v2a = { .tx_desc_prefetch = 5, .rx_desc_prefetch = 5, .an_cdr_workaround = 1, + .an_kr_workaround = 1, }; static const struct xgbe_version_data xgbe_v2b = { @@ -488,6 +495,7 @@ static const struct xgbe_version_data xgbe_v2b = { .tx_desc_prefetch = 5, .rx_desc_prefetch = 5, .an_cdr_workaround = 1, + .an_kr_workaround = 1, }; static const struct pci_device_id xgbe_pci_table[] = { @@ -500,6 +508,24 @@ static const struct pci_device_id xgbe_pci_table[] = { }; MODULE_DEVICE_TABLE(pci, xgbe_pci_table); +#if defined(MY_DEF_HERE) +static void syno_xgbe_pci_shutdown(struct pci_dev *pdev) +{ + struct xgbe_prv_data *pdata = pci_get_drvdata(pdev); + struct net_device *netdev = pdata->netdev; + int ret = 0; + + if (pdata->wol_flag & WAKE_MAGIC) { + pdata->phy_if.phy_impl.wol_enable(pdata); + } else { + if (netif_running(netdev)) + ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT); + + pdata->phy_if.phy_stop(pdata); + } +} +#endif /* MY_DEF_HERE */ + static SIMPLE_DEV_PM_OPS(xgbe_pci_pm_ops, xgbe_pci_suspend, xgbe_pci_resume); static struct pci_driver xgbe_driver = { @@ -507,6 +533,9 @@ static struct pci_driver xgbe_driver = { .id_table = xgbe_pci_table, .probe = xgbe_pci_probe, .remove = xgbe_pci_remove, +#if defined(MY_DEF_HERE) + .shutdown = syno_xgbe_pci_shutdown, +#endif /* MY_DEF_HERE */ .driver = { .pm = &xgbe_pci_pm_ops, } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 18e48b3bc402..c7a3d0b51906 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -149,12 +152,12 @@ #define XGBE_RATECHANGE_COUNT 500 /* CDR delay values for KR support (in usec) */ -#define XGBE_CDR_DELAY_INIT 10000 -#define XGBE_CDR_DELAY_INC 10000 -#define XGBE_CDR_DELAY_MAX 100000 +#define XGBE_CDR_DELAY_INIT 22000 +#define XGBE_CDR_DELAY_INC 22000 +#define XGBE_CDR_DELAY_MAX 110000 /* RRC frequency during link status check */ -#define XGBE_RRC_FREQUENCY 10 +#define XGBE_RRC_FREQUENCY 1 enum xgbe_port_mode { XGBE_PORT_MODE_RSVD = 0, @@ -380,6 +383,7 @@ struct xgbe_phy_data { /* KR AN support */ unsigned int phy_cdr_notrack; unsigned int phy_cdr_delay; + unsigned int phy_cdr_delay_required; }; /* I2C, MDIO and GPIO lines are muxed, so only one device at a time */ @@ -849,10 +853,12 @@ static void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; if (phy_data->phydev) { - phy_detach(phy_data->phydev); - phy_device_remove(phy_data->phydev); - phy_device_free(phy_data->phydev); - phy_data->phydev = NULL; + if(!pdata->ext_fixed_phy) { + phy_detach(phy_data->phydev); + phy_device_remove(phy_data->phydev); + phy_device_free(phy_data->phydev); + phy_data->phydev = NULL; + } } } @@ -1001,6 +1007,36 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) /* Clear the extra AN flag */ pdata->an_again = 0; + netif_dbg(pdata, drv, pdata->netdev, "xgbe portmode = %d, phy_mode = %d, con_type= %d\n", phy_data->port_mode,phy_data->phydev_mode,phy_data->conn_type); + + /* Check for the presence of an external PHY in KR mode, example Bilby platform */ + if(phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) { + int addr = 0; + int reg = MII_ADDR_C45 | 1 << 16 | 2; + enum xgbe_conn_type conn_type = phy_data->conn_type; + enum xgbe_mdio_mode phy_mode = phy_data->phydev_mode; + + pdata->ext_fixed_phy = 0; + phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; + phy_data->conn_type = XGBE_CONN_TYPE_MDIO; + + ret = xgbe_phy_get_comm_ownership(pdata); + if(ret) { + return ret; + } + ret = xgbe_phy_mdio_mii_read(pdata, addr, reg); + /* for Marvell PHY on bilby this is 0x2b , this is a workaround for Bilby , issue EMBDEV-10275*/ + if((ret & 0x1FFF) == 0x2b){ + pdata->ext_fixed_phy = 1; + } + xgbe_phy_put_comm_ownership(pdata); + + if(!pdata->ext_fixed_phy) { + phy_data->phydev_mode = phy_mode; + phy_data->conn_type = conn_type; + } + } + /* Check for the use of an external PHY */ if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) return 0; @@ -1024,11 +1060,17 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) phydev = get_phy_device(phy_data->mii, phy_data->mdio_addr, (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45)); if (IS_ERR(phydev)) { - netdev_err(pdata->netdev, "get_phy_device failed\n"); + netdev_err(pdata->netdev, "get_phy_device failed portmode = %d phydev_mode = %d\n", phy_data->port_mode,phy_data->phydev_mode); return -ENODEV; } netif_dbg(pdata, drv, pdata->netdev, "external PHY id is %#010x\n", - phydev->phy_id); + (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45) ? phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] : phydev->phy_id); + + if(((phy_data->phydev_mode == XGBE_MDIO_MODE_CL45) ? phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] : phydev->phy_id) == 0xFFFFFFFF) { + pdata->ext_fixed_phy = 0; + phy_device_free(phydev); + return 0; + } /*TODO: If c45, add request_module based on one of the MMD ids? */ @@ -1040,7 +1082,7 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) } ret = phy_attach_direct(pdata->netdev, phydev, phydev->dev_flags, - PHY_INTERFACE_MODE_SGMII); + (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45) ? PHY_INTERFACE_MODE_10GKR : PHY_INTERFACE_MODE_SGMII); if (ret) { netdev_err(pdata->netdev, "phy_attach_direct failed\n"); phy_device_remove(phydev); @@ -1049,11 +1091,31 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) } phy_data->phydev = phydev; + switch (phy_data->port_mode) { + case XGBE_PORT_MODE_SFP: + /* reset the sfp phy EMBDEV-8951 */ + if(phydev) + genphy_soft_reset(phydev); + else + netdev_err(pdata->netdev, "phy reset failed\n"); + break; + default: + break; + } + xgbe_phy_external_phy_quirks(pdata); linkmode_and(phydev->advertising, phydev->advertising, lks->link_modes.advertising); + if(phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) { + /* to do : add code to set the auto neg mode + phy_data->phydev->drv->config_aneg(phy_data->phydev); + phy_start_aneg() wornt work with Marvell PHY + */ + return 0; + } + phy_start_aneg(phy_data->phydev); return 0; @@ -1283,7 +1345,7 @@ static int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom)); - xgbe_phy_free_phy_device(pdata); + } else { phy_data->sfp_changed = 0; } @@ -1320,7 +1382,6 @@ static void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - xgbe_phy_free_phy_device(pdata); phy_data->sfp_mod_absent = 1; phy_data->sfp_phy_avail = 0; @@ -1372,6 +1433,9 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata) xgbe_phy_sfp_phy_settings(pdata); xgbe_phy_put_comm_ownership(pdata); + + if((phy_data->sfp_mod_absent) || (phy_data->sfp_changed)) + xgbe_phy_free_phy_device(pdata); } static int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata, @@ -1851,6 +1915,14 @@ static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) phy_data->phydev->duplex = pdata->phy.duplex; } + if(phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) { + /* to do : add code to set the auto neg mode + phy_data->phydev->drv->config_aneg(phy_data->phydev); + phy_start_aneg() wornt work with Marvell PHY + */ + return 0; + } + ret = phy_start_aneg(phy_data->phydev); return ret; @@ -1956,38 +2028,23 @@ static void xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata) xgbe_phy_put_comm_ownership(pdata); } -static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata) -{ - int reg; - - reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT, - XGBE_PCS_PSEQ_STATE_MASK); - if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) { - /* Mailbox command timed out, reset of RX block is required. - * This can be done by asseting the reset bit and wait for - * its compeletion. - */ - XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, - XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON); - ndelay(20); - XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, - XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF); - usleep_range(40, 50); - netif_err(pdata, link, pdata->netdev, "firmware mailbox reset performed\n"); - } -} - static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd, unsigned int sub_cmd) { unsigned int s0 = 0; unsigned int wait; + unsigned int i; + int reg; + + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, + XGBE_PMA_PLL_CTRL_MASK, XGBE_PMA_PLL_CTRL_CLEAR); + usleep_range(100, 200); /* Log if a previous command did not complete */ if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) { - netif_dbg(pdata, link, pdata->netdev, + netif_err(pdata, link, pdata->netdev, "firmware mailbox not ready for command\n"); - xgbe_phy_rx_reset(pdata); + goto rx_reset; } /* Construct the command */ @@ -2008,11 +2065,20 @@ static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, usleep_range(1000, 2000); } - netif_dbg(pdata, link, pdata->netdev, - "firmware mailbox command did not complete\n"); +rx_reset: + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_MMD_DIGITAL_STAT); + if (reg & 0x10) { + /* mailbox command timed out, reset Rx block */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, + BIT(4) /* mask */, BIT(4)/* value*/); - /* Reset on error */ - xgbe_phy_rx_reset(pdata); + for (i = 0; i < 100; i++) + usleep_range(1000, 2000); + + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1, + BIT(4) /* mask */, 0/* value*/); + netif_err(pdata, link, pdata->netdev, " rxX_reset done!\n"); + } } static void xgbe_phy_rrc(struct xgbe_prv_data *pdata) @@ -2610,9 +2676,17 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) */ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); + if (reg & MDIO_STAT1_LSTATUS) return 1; +#if defined(MY_DEF_HERE) + if (phy_data->phydev && phy_data->phydev->link) { + dev_warn(pdata->dev, "MDIO_STAT1: 0x%x , but phy_data->phydev->link: 0x%x", reg, phy_data->phydev->link); + return 1; + } +#endif + if (pdata->phy.autoneg == AUTONEG_ENABLE && phy_data->port_mode == XGBE_PORT_MODE_BACKPLANE) { if (!test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { @@ -2624,7 +2698,11 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) /* No link, attempt a receiver reset cycle */ if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { phy_data->rrc_count = 0; - xgbe_phy_rrc(pdata); + if (pdata->phy.autoneg == AUTONEG_DISABLE) { + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, + XGBE_PMA_PLL_CTRL_MASK, XGBE_PMA_PLL_CTRL_SET); + usleep_range(100, 200); + } } return 0; @@ -2935,13 +3013,16 @@ static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata) if (!phy_data->phy_cdr_notrack) return; - usleep_range(phy_data->phy_cdr_delay, - phy_data->phy_cdr_delay + 500); + /* when there is no link, no need to use the cdr delay, when ever a page is */ + /* received , pdata->cdr_delay_required is set to 1 */ + if (pdata->cdr_delay_required) { + usleep_range(phy_data->phy_cdr_delay, + phy_data->phy_cdr_delay + 500); + } XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, XGBE_PMA_CDR_TRACK_EN_MASK, XGBE_PMA_CDR_TRACK_EN_ON); - phy_data->phy_cdr_notrack = 0; } @@ -2958,22 +3039,140 @@ static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata) XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, XGBE_PMA_CDR_TRACK_EN_MASK, XGBE_PMA_CDR_TRACK_EN_OFF); - xgbe_phy_rrc(pdata); - + pdata->rrc_start_time = jiffies; phy_data->phy_cdr_notrack = 1; } +static void xgbe_phy_kr_workaround(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int reg; + + /* Disable KR training for now */ + reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); + reg &= ~XGBE_KR_TRAINING_ENABLE; + XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); + + /* step-4 Start AN */ + reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); + reg &= ~MDIO_AN_CTRL1_ENABLE; + + reg |= MDIO_AN_CTRL1_ENABLE; + + reg |= MDIO_AN_CTRL1_RESTART; + + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); + + if (phy_data->cur_mode == XGBE_MODE_KR) { + /* step-4 Start AN with KR training auto start */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBR_PMD_CTRL, + (XGBE_KR_TRAINING_ENABLE | XGBE_KR_TRAINING_START), + (XGBE_KR_TRAINING_ENABLE | XGBE_KR_TRAINING_START)); + + /* Step-5 Set RX_EQ_MGMT_MODE to disable RX Adapt Requests */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, + MDIO_PMA_RX_EQ_CTRL, + XGBE_PMA_RX_EQ_MGMT_MODE_MASK, + XGBE_PMA_RX_EQ_MGMT_MODE_OFF); + } +} + +static int xgbe_phy_kr_training_cdroff(struct xgbe_prv_data *pdata) +{ + int ret; + struct xgbe_phy_data *phy_data = pdata->phy_data; + + /* set phy_data->phy_cdr_notrack, if it is not set so + * next call to xgbe_phy_cdr_track will work as expected + */ + + ret = phy_data->phy_cdr_notrack; + if (!phy_data->phy_cdr_notrack) { + netif_dbg(pdata, link, pdata->netdev, "setting phy_data->phy_cdr_notrack\n"); + phy_data->phy_cdr_notrack = 1; + } + + return ret; +} + +static void xgbe_phy_update_cdr_delay(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + /* step-12 Increment delay by 22ms. if delay is > 110ms, reset to 22ms */ + if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX) + phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC; + else + phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; +} + static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) { - if (!pdata->debugfs_an_cdr_track_early) - xgbe_phy_cdr_track(pdata); + struct xgbe_phy_data *phy_data = pdata->phy_data; + + /* an_kr_workaround is enabled with kr_training_post routine and + * debugfs_an_cdr_track_early should be disabled + */ + + if (pdata->debugfs_an_cdr_track_early) + return; + + if (pdata->vdata->an_kr_workaround) { + xgbe_phy_kr_training_cdroff(pdata); + + /* step-7 Set RX_EQ_MGMT_MODE to disable RX adapt requests */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL, + XGBE_PMA_RX_EQ_MGMT_MODE_MASK, XGBE_PMA_RX_EQ_MGMT_MODE_OFF); + /* step-8 Set CDR_TRACK_EN to 0 */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, + XGBE_PMA_CDR_TRACK_EN_MASK, + XGBE_PMA_CDR_TRACK_EN_OFF); + /* step-8 Set rx_data_en =0 (Reference tracking mode) */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL0, + XGBE_PMA_RX_DT_EN_0_MASK, XGBE_PMA_RX_DT_EN_0_OFF); + } + /* step-9 Delay and step-10 and Set CDR_TRACK_EN to 1 */ + phy_data->phy_cdr_delay_required = 1; + xgbe_phy_cdr_track(pdata); + phy_data->phy_cdr_delay_required = 0; + + if (pdata->vdata->an_kr_workaround) { + /*step-10 rx_data_en = 1 (Data tracking mode) */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL0, + XGBE_PMA_RX_DT_EN_0_MASK, XGBE_PMA_RX_DT_EN_0_ON); + /* step-11. Wait for 1 usec (for CDR to lock to data) */ + usleep_range(1, 2); + /* step-11. Clear RX_EQ_MGMT_MODE to allow RX Adapt rquests */ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL, + XGBE_PMA_RX_EQ_MGMT_MODE_MASK, XGBE_PMA_RX_EQ_MGMT_MODE_ON); + } + /* step-12 Increment delay by 22ms. if delay is > 110ms, reset to 22ms */ + xgbe_phy_update_cdr_delay(pdata); + +} + +static void xgbe_phy_reset_cdr_delay(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; + pdata->kr_done = 0; } static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) { - if (pdata->debugfs_an_cdr_track_early) + struct xgbe_phy_data *phy_data = pdata->phy_data; + + /* an_kr_workaround is not enabled with kr_training_pre routine */ + if (pdata->debugfs_an_cdr_track_early) { + phy_data->phy_cdr_delay_required = 1; xgbe_phy_cdr_track(pdata); + phy_data->phy_cdr_delay_required = 0; + /* step-12 Increment delay by 22ms. if delay is > 110ms, reset to 22ms */ + xgbe_phy_update_cdr_delay(pdata); + } } static void xgbe_phy_an_post(struct xgbe_prv_data *pdata) @@ -2987,18 +3186,6 @@ static void xgbe_phy_an_post(struct xgbe_prv_data *pdata) break; xgbe_phy_cdr_track(pdata); - - switch (pdata->an_result) { - case XGBE_AN_READY: - case XGBE_AN_COMPLETE: - break; - default: - if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX) - phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC; - else - phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; - break; - } break; default: break; @@ -3016,6 +3203,14 @@ static void xgbe_phy_an_pre(struct xgbe_prv_data *pdata) break; xgbe_phy_cdr_notrack(pdata); + if (pdata->vdata->an_kr_workaround) { + /* Enable interrupt when KR workaround is used */ + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK); + /* Step 4 and step 5 for KR workaround + * Start AN and disable RX Adapt Requests + */ + xgbe_phy_kr_workaround(pdata); + } break; default: break; @@ -3104,7 +3299,7 @@ static int xgbe_phy_reset(struct xgbe_prv_data *pdata) xgbe_phy_power_off(pdata); xgbe_phy_set_mode(pdata, cur_mode); - if (!phy_data->phydev) + if (!phy_data->phydev || !pdata->phy_started) return 0; /* Reset the external PHY */ @@ -3403,6 +3598,204 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) return 0; } +#if defined(MY_DEF_HERE) +static void syno_force_1g(struct xgbe_prv_data *pdata) +{ + int reg; + struct xgbe_phy_data *phy_data = pdata->phy_data; + int temp_m, temp_c; + enum xgbe_mode cur_mode; + + reg = xgbe_phy_get_comm_ownership(pdata); + if (reg){ + printk("get ownership fail \n"); + return ; + } + + temp_c = phy_data->conn_type; + temp_m = phy_data->phydev_mode; + + phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; + phy_data->conn_type = XGBE_CONN_TYPE_MDIO; + + /* Do not advertise PHY as 10G */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0020); + reg &= ~0x1000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0020, reg); + + /* Disable extended next pages */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0000); + reg &= ~0x2000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0000, reg); + + /* Extended next page not capable */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0010); + reg &= ~0x1000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0010, reg); + + /* Speed Select 1000 Mbps */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_PMAPMD << 16) | 0x0000); + reg &= ~0x2000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_PMAPMD << 16) | 0x0000, reg); + + /* Reset by power cycling the PHY */ + cur_mode = phy_data->cur_mode; + xgbe_phy_power_off(pdata); + xgbe_phy_set_mode(pdata, cur_mode); + phy_init_hw(phy_data->phydev); + + /* Disable auto-negotiation for now */ + reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); + reg &= ~MDIO_AN_CTRL1_ENABLE; + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); + + // Disable auto-negotiation interrupts + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); + pdata->an_start = 0; + + /* Clear auto-negotiation interrupts */ + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); + + xgbe_phy_put_comm_ownership(pdata); + + phy_data->phydev_mode = temp_m; + phy_data->conn_type = temp_c; +} + +static void syno_phy_led_test_mode(struct xgbe_prv_data *pdata, unsigned int test_mode) +{ + int reg, reg_led_act, reg_led_orange, reg_led_green; + struct xgbe_phy_data *phy_data = pdata->phy_data; + int temp_m, temp_c; + + reg = xgbe_phy_get_comm_ownership(pdata); + if (reg){ + printk("get ownership fail \n"); + return ; + } + + temp_c = phy_data->conn_type; + temp_m = phy_data->phydev_mode; + + phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; + phy_data->conn_type = XGBE_CONN_TYPE_MDIO; + + reg_led_act = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | 0xf020); + reg_led_orange = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | 0xf022); + reg_led_green = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | 0xf023); + + reg_led_act &= 0xE000; + reg_led_orange &= 0xE000; + reg_led_green &= 0xE000; + + + switch (test_mode) { + case 0 : + reg_led_act |= 0x128; + reg_led_orange |= 0x68; + reg_led_green |= 0x58; + break; + case 1 : + reg_led_act |= 0x1728; + reg_led_orange |= 0xB8; + break; + case 2 : + reg_led_act |= 0x1728; + reg_led_green |= 0xB8; + break; + default : + break; + } + + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | 0xf020, reg_led_act); + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | 0xf022, reg_led_orange); + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_VEND2 << 16) | 0xf023, reg_led_green); + + xgbe_phy_put_comm_ownership(pdata); + phy_data->phydev_mode = temp_m; + phy_data->conn_type = temp_c; +} + +static void syno_resume_autoneg(struct xgbe_prv_data *pdata) +{ + int reg; + struct xgbe_phy_data *phy_data = pdata->phy_data; + int temp_m, temp_c; + enum xgbe_mode cur_mode; + + reg = xgbe_phy_get_comm_ownership(pdata); + if (reg){ + printk("get ownership fail \n"); + return ; + } + + temp_c = phy_data->conn_type; + temp_m = phy_data->phydev_mode; + + phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; + phy_data->conn_type = XGBE_CONN_TYPE_MDIO; + + /* Advertise PHY as 10G */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0020); + reg |= 0x1000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0020, reg); + + /* Enable extended next pages */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0000); + reg |= 0x2000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0000, reg); + + /* Extended next page capable */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0010); + reg |= 0x1000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_AN << 16) | 0x0010, reg); + + /* Speed Select 10 Gbps */ + reg = xgbe_phy_mdio_mii_read(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_PMAPMD << 16) | 0x0000); + reg |= 0x2000; + xgbe_phy_mdio_mii_write(pdata, 0, MII_ADDR_C45 | (MDIO_MMD_PMAPMD << 16) | 0x0000, reg); + + /* Reset by power cycling the PHY */ + cur_mode = phy_data->cur_mode; + xgbe_phy_power_off(pdata); + xgbe_phy_set_mode(pdata, cur_mode); + phy_init_hw(phy_data->phydev); + + /* Disable auto-negotiation for now */ + reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); + reg &= ~MDIO_AN_CTRL1_ENABLE; + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); + + // Disable auto-negotiation interrupts + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); + pdata->an_start = 0; + + /* Clear auto-negotiation interrupts */ + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); + + xgbe_phy_put_comm_ownership(pdata); + + phy_data->phydev_mode = temp_m; + phy_data->conn_type = temp_c; +} + +static void syno_xgbe_wol_enable(struct xgbe_prv_data *pdata) +{ + int ret; + struct xgbe_phy_data *phy_data = pdata->phy_data; + + if (phy_data->phydev && phy_data->phydev->drv->set_wol) { + /* Pass MAC address to PHY */ + memcpy(phy_data->phydev->attached_dev->dev_addr, pdata->netdev->dev_addr, pdata->netdev->addr_len); + + ret = phy_ethtool_set_wol(phy_data->phydev, NULL); + if (ret) { + dev_err(pdata->dev, "WOL set failed\n"); + } + } +} +#endif /* MY_DEF_HERE */ + void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if) { struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; @@ -3437,7 +3830,16 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if) phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; phy_impl->kr_training_post = xgbe_phy_kr_training_post; + phy_impl->kr_training_cdroff = xgbe_phy_kr_training_cdroff; + phy_impl->reset_cdr_delay = xgbe_phy_reset_cdr_delay; + phy_impl->update_cdr_delay = xgbe_phy_update_cdr_delay; phy_impl->module_info = xgbe_phy_module_info; phy_impl->module_eeprom = xgbe_phy_module_eeprom; +#if defined(MY_DEF_HERE) + phy_impl->wol_enable = syno_xgbe_wol_enable; + phy_impl->force_1g = syno_force_1g; + phy_impl->resume_autoneg = syno_resume_autoneg; + phy_impl->phy_led_test_mode = syno_phy_led_test_mode; +#endif /* MY_DEF_HERE */ } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 3305979a9f7c..df30775eeea2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * AMD 10Gb Ethernet driver * @@ -288,7 +291,7 @@ /* Auto-negotiation */ #define XGBE_AN_MS_TIMEOUT 500 -#define XGBE_LINK_TIMEOUT 5 +#define XGBE_LINK_TIMEOUT 1 #define XGBE_SGMII_AN_LINK_STATUS BIT(1) #define XGBE_SGMII_AN_LINK_SPEED (BIT(2) | BIT(3)) @@ -888,12 +891,24 @@ struct xgbe_phy_impl_if { /* Pre/Post KR training enablement support */ void (*kr_training_pre)(struct xgbe_prv_data *); void (*kr_training_post)(struct xgbe_prv_data *); + int (*kr_training_cdroff)(struct xgbe_prv_data *pdata); + void (*reset_cdr_delay)(struct xgbe_prv_data *pdata); + void (*update_cdr_delay)(struct xgbe_prv_data *pdata); /* SFP module related info */ int (*module_info)(struct xgbe_prv_data *pdata, struct ethtool_modinfo *modinfo); int (*module_eeprom)(struct xgbe_prv_data *pdata, struct ethtool_eeprom *eeprom, u8 *data); + +#if defined(MY_DEF_HERE) + /* WOL setting Enable */ + void (*wol_enable)(struct xgbe_prv_data *); + void (*force_1g)(struct xgbe_prv_data *); + void (*resume_autoneg)(struct xgbe_prv_data *); + void (*phy_led_test_mode)(struct xgbe_prv_data *, unsigned int); +#endif /* MY_DEF_HERE */ + }; struct xgbe_phy_if { @@ -1012,6 +1027,7 @@ struct xgbe_version_data { unsigned int tx_desc_prefetch; unsigned int rx_desc_prefetch; unsigned int an_cdr_workaround; + unsigned int an_kr_workaround; }; struct xgbe_prv_data { @@ -1230,6 +1246,7 @@ struct xgbe_prv_data { int mdio_mmd; unsigned long link_check; struct completion mdio_complete; + unsigned int ext_fixed_phy; unsigned int kr_redrv; @@ -1254,6 +1271,10 @@ struct xgbe_prv_data { unsigned int fec_ability; unsigned long an_start; enum xgbe_an_mode an_mode; + unsigned int kr_done; + unsigned long kr_start_time; + unsigned long rrc_start_time; + unsigned int cdr_delay_required; /* I2C support */ struct xgbe_i2c i2c; @@ -1282,6 +1303,10 @@ struct xgbe_prv_data { bool debugfs_an_cdr_workaround; bool debugfs_an_cdr_track_early; + +#if defined(MY_DEF_HERE) + int wol_flag; +#endif /* MY_DEF_HERE */ }; /* Function prototypes*/ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 89697cb09d1c..881a5d4d8c25 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005 - 2016 Broadcom @@ -21,6 +24,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + MODULE_DESCRIPTION(DRV_DESC); MODULE_AUTHOR("Emulex Corporation"); MODULE_LICENSE("GPL"); @@ -36,6 +43,13 @@ static ushort rx_frag_size = 2048; module_param(rx_frag_size, ushort, 0444); MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); +#ifdef MY_ABC_HERE +static unsigned int syno_hide_vf = 1; +module_param(syno_hide_vf, uint, S_IRUGO); +MODULE_PARM_DESC(syno_hide_vf, "Don't create interface when probing VF." + " Enabled by default"); +#endif /* MY_ABC_HERE */ + /* Per-module error detection/recovery workq shared across all functions. * Each function schedules its own work request on this shared workq. */ @@ -5494,6 +5508,14 @@ static void be_log_sfp_info(struct be_adapter *adapter) adapter->flags &= ~BE_FLAGS_PHY_MISCONFIGURED; } +#ifdef MY_ABC_HERE + +static char *uevent_envp[2] = {"SYNO_SFP=unsupported", NULL}; +/* linux-ver/kernel/sysctrl.c */ +extern void SynoSfpUnsupportNotifySet(const char* ethName, SYNO_SFP_UNSUPPORTED_NOTIFY_TYPE val); + +#endif /* MY_ABC_HERE */ + static void be_worker(struct work_struct *work) { struct be_adapter *adapter = @@ -5535,8 +5557,16 @@ static void be_worker(struct work_struct *work) if (!skyhawk_chip(adapter)) be_eqd_update(adapter, false); +#ifdef MY_ABC_HERE + if (adapter->flags & BE_FLAGS_PHY_MISCONFIGURED) { + be_log_sfp_info(adapter); + SynoSfpUnsupportNotifySet(adapter->netdev->name, SFP_NOTIFY_NOT_SUPPORT_WARN); + kobject_uevent_env(&adapter->netdev->dev.kobj, KOBJ_CHANGE, uevent_envp); + } +#else /* MY_ABC_HERE */ if (adapter->flags & BE_FLAGS_PHY_MISCONFIGURED) be_log_sfp_info(adapter); +#endif /* MY_ABC_HERE */ reschedule: adapter->work_counter++; @@ -5827,6 +5857,9 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) struct be_adapter *adapter; struct net_device *netdev; int status = 0; +#ifdef MY_ABC_HERE + bool blHideVF = false; +#endif /* MY_ABC_HERE */ status = pci_enable_device(pdev); if (status) @@ -5867,6 +5900,16 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) if (status) goto free_netdev; +#ifdef MY_ABC_HERE + if (syno_hide_vf) { + if (be_virtfn(adapter)) { + /* don't want vf appear in host */ + blHideVF = true; + goto unmap_bars; + } + } +#endif /* MY_ABC_HERE */ + status = be_drv_init(adapter); if (status) goto unmap_bars; @@ -5914,7 +5957,13 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) disable_dev: pci_disable_device(pdev); do_none: +#ifdef MY_ABC_HERE + if (!blHideVF) { + dev_err(&pdev->dev, "%s initialization failed\n", nic_name(pdev)); + } +#else /* !MY_ABC_HERE */ dev_err(&pdev->dev, "%s initialization failed\n", nic_name(pdev)); +#endif /* MY_ABC_HERE */ return status; } diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index 93d9df55b361..df7c0a676afa 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -6,7 +6,7 @@ config NET_VENDOR_REALTEK bool "Realtek devices" default y - depends on PCI || (PARPORT && X86) + depends on PCI || (PARPORT && X86) || ARCH_REALTEK help If you have a network (Ethernet) card belonging to this class, say Y. @@ -113,4 +113,26 @@ config R8169 To compile this driver as a module, choose M here: the module will be called r8169. This is recommended. +if SYNO_LSP_RTD1619B +config R8169SOC + tristate "Realtek 8169SoC gigabit ethernet support" + depends on ARCH_REALTEK + select CRC32 + select MII + help + Say Y here if you have a Realtek 8169 SoC for RTK Gigabit Ethernet adapter. + + To compile this driver as a module, choose M here: the module + will be called r8169soc. This is recommended. + +config RTL_RX_NO_COPY + bool "Support to receive packets without memory copy" + default n + depends on R8169SOC + help + This is a feature of Realtek 8169SoC gigabit ethernet driver. + Say Y here to impove performance and reduce CPU loading. + Say N here to save memory for packet buffers. + +endif # SYNO_LSP_RTD1619B endif # NET_VENDOR_REALTEK diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile index 2e1d78b106b0..2c815f01199a 100644 --- a/drivers/net/ethernet/realtek/Makefile +++ b/drivers/net/ethernet/realtek/Makefile @@ -8,3 +8,6 @@ obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_ATP) += atp.o r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o obj-$(CONFIG_R8169) += r8169.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_R8169SOC) += r8169soc.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/net/ethernet/realtek/r8169soc.c b/drivers/net/ethernet/realtek/r8169soc.c new file mode 100644 index 000000000000..883fdc63f96c --- /dev/null +++ b/drivers/net/ethernet/realtek/r8169soc.c @@ -0,0 +1,11033 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* r8169soc.c: RealTek 8169soc ethernet driver. + * + * Copyright (c) 2002 ShuChen + * Copyright (c) 2003 - 2007 Francois Romieu + * Copyright (c) 2014 YuKuen Wu + * Copyright (c) 2015 Eric Wang + * Copyright (c) 2019 Realtek Semiconductor Corp. + * Copyright (c) a lot of people too. Please respect their work. + * + * See MAINTAINERS file for support contact information. + */ + +#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 +#include +#include +#include +#include +#include +#include +#include + +#define RTL8169_VERSION "1.3.2" +#define MODULENAME "r8169" +#define PFX MODULENAME ": " +#define CURRENT_MDIO_PAGE 0xFFFFFFFF + +#ifdef RTL8169_DEBUG +#define assert(expr) \ +do { \ + if (!(expr)) { \ + pr_debug("Assertion failed! %s,%s,%s,line=%d\n", \ + #expr, __FILE__, __func__, __LINE__); \ + } \ +} while (0) +#define dprintk(fmt, args...) pr_debug(PFX fmt, ## args) +#else +#define assert(expr) do {} while (0) +#define dprintk(fmt, args...) do {} while (0) +#endif /* RTL8169_DEBUG */ + +#define R8169_MSG_DEFAULT \ + (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN) + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + * The RTL chips use a 64 element hash table based on the Ethernet CRC. + */ +static const int multicast_filter_limit = 32; + +#define MAX_READ_REQUEST_SHIFT 12 +#define TX_DMA_BURST 4 /* Maximum DMA burst, '7' is unlimited */ +#define INTER_FRAME_GAP 0x03 /* 3 means INTER_FRAME_GAP = the shortest one */ + +#define R8169_REGS_SIZE 256 +#define R8169_NAPI_WEIGHT 64 +#define NUM_TX_DESC 1024 /* Number of Tx descriptor registers */ +#if defined(CONFIG_RTL_RX_NO_COPY) +#define NUM_RX_DESC 4096 /* Number of Rx descriptor registers */ +#else +#define NUM_RX_DESC 1024 /* Number of Rx descriptor registers */ +#endif /* CONFIG_RTL_RX_NO_COPY */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct tx_desc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct rx_desc)) + +#define RTL8169_TX_TIMEOUT (6 * HZ) +#define MAC_INIT_TIMEOUT 20 +#define PHY_LOCK_TIMEOUT 1000 + +#if defined(CONFIG_RTL_RX_NO_COPY) +#define RX_BUF_SIZE 0x05F3 /* 0x05F3 = 1522bye + 1 */ +#define RTK_RX_ALIGN 8 +#endif /* CONFIG_RTL_RX_NO_COPY */ + +#define RTL_PROC 1 + +/* write/read MMIO register */ +#define RTL_W8(reg, val8) (writeb((val8), ioaddr + (reg))) +#define RTL_W16(reg, val16) (writew((val16), ioaddr + (reg))) +#define RTL_W32(reg, val32) (writel((val32), ioaddr + (reg))) +#define RTL_R8(reg) (readb(ioaddr + (reg))) +#define RTL_R16(reg) (readw(ioaddr + (reg))) +#define RTL_R32(reg) (readl(ioaddr + (reg))) + +enum rtl_tx_desc_version { + RTL_TD_0 = 0, + RTL_TD_1 = 1, +}; + +#define JUMBO_1K ETH_DATA_LEN +#define JUMBO_4K (4 * 1024 - ETH_HLEN - 2) +#define JUMBO_6K (6 * 1024 - ETH_HLEN - 2) +#define JUMBO_7K (7 * 1024 - ETH_HLEN - 2) +#define JUMBO_9K (9 * 1024 - ETH_HLEN - 2) + +enum cfg_version { + RTL_CFG_0 = 0x00, + RTL_CFG_1, + RTL_CFG_2 +}; + +#if defined(CONFIG_RTL_RX_NO_COPY) +static int rx_buf_sz = 1523; /* 0x05F3 = 1522bye + 1 */ +static int rx_buf_sz_new = 1523; +#else +static int rx_buf_sz = 16383; +#endif /* CONFIG_RTL_RX_NO_COPY */ + +static struct { + u32 msg_enable; +} debug = {-1}; + +enum rtl_registers { + MAC0 = 0, /* Ethernet hardware address. */ + MAC4 = 4, + MAR0 = 8, /* Multicast filter. */ + COUNTER_ADDR_LOW = 0x10, + COUNTER_ADDR_HIGH = 0x14, + LEDSEL = 0x18, + TX_DESC_START_ADDR_LOW = 0x20, + TX_DESC_START_ADDR_HIGH = 0x24, + TXH_DESC_START_ADDR_LOW = 0x28, + TXH_DESC_START_ADDR_HIGH = 0x2c, + FLASH = 0x30, + ERSR = 0x36, + CHIP_CMD = 0x37, + TX_POLL = 0x38, + INTR_MASK = 0x3c, + INTR_STATUS = 0x3e, + + TX_CONFIG = 0x40, +#define TXCFG_AUTO_FIFO BIT(7) /* 8111e-vl */ +#define TXCFG_EMPTY BIT(11) /* 8111e-vl */ + + RX_CONFIG = 0x44, +#define RX128_INT_EN BIT(15) /* 8111c and later */ +#define RX_MULTI_EN BIT(14) /* 8111c only */ +#define RXCFG_FIFO_SHIFT 13 + /* No threshold before first PCI xfer */ +#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT) +#define RX_EARLY_OFF BIT(11) +#define RXCFG_DMA_SHIFT 8 + /* Unlimited maximum PCI burst. */ +#define RX_DMA_BURST (3 << RXCFG_DMA_SHIFT) /* 128 bytes */ + + RX_MISSED = 0x4c, + CFG9346 = 0x50, + CONFIG0 = 0x51, + CONFIG1 = 0x52, + CONFIG2 = 0x53, +#define PME_SIGNAL BIT(5) /* 8168c and later */ + + CONFIG3 = 0x54, + CONFIG4 = 0x55, + CONFIG5 = 0x56, + MULTI_INTR = 0x5c, + PHYAR = 0x60, + PHY_STATUS = 0x6c, + RX_MAX_SIZE = 0xda, + C_PLUS_CMD = 0xe0, + INTR_MITIGATE = 0xe2, + RX_DESC_ADDR_LOW = 0xe4, + RX_DESC_ADDR_HIGH = 0xe8, + EARLY_TX_THRES = 0xec, /* 8169. Unit of 32 bytes. */ + +#define NO_EARLY_TX 0x3f /* Max value : no early transmit. */ + + MAX_TX_PACKET_SIZE = 0xec, /* Unit of 128 bytes. */ + +#define TX_PACKET_MAX (8064 >> 7) +#define EARLY_SIZE 0x27 + + FUNC_EVENT = 0xf0, + FUNC_EVENT_MASK = 0xf4, + FUNC_PRESET_STATE = 0xf8, + FUNC_FORCE_EVENT = 0xfc, +}; + +enum rtl8168_8101_registers { + CSIDR = 0x64, + CSIAR = 0x68, +#define CSIAR_FLAG 0x80000000 +#define CSIAR_WRITE_CMD 0x80000000 +#define CSIAR_BYTE_ENABLE 0x0f +#define CSIAR_BYTE_ENABLE_SHIFT 12 +#define CSIAR_ADDR_MASK 0x0fff +#define CSIAR_FUNC_CARD 0x00000000 +#define CSIAR_FUNC_SDIO 0x00010000 +#define CSIAR_FUNC_NIC 0x00020000 + PMCH = 0x6f, + EPHYAR = 0x80, +#define EPHYAR_FLAG 0x80000000 +#define EPHYAR_WRITE_CMD 0x80000000 +#define EPHYAR_REG_MASK 0x1f +#define EPHYAR_REG_SHIFT 16 +#define EPHYAR_DATA_MASK 0xffff + DLLPR = 0xd0, +#define PFM_EN BIT(6) + DBG_REG = 0xd1, +#define FIX_NAK_1 BIT(4) +#define FIX_NAK_2 BIT(3) + TWSI = 0xd2, + MCU = 0xd3, +#define NOW_IS_OOB BIT(7) +#define TX_EMPTY BIT(5) +#define RX_EMPTY BIT(4) +#define RXTX_EMPTY (TX_EMPTY | RX_EMPTY) +#define EN_NDP BIT(3) +#define EN_OOB_RESET BIT(2) +#define LINK_LIST_RDY BIT(1) +#define DIS_MCU_CLROOB BIT(0) + EFUSEAR = 0xdc, +#define EFUSEAR_FLAG 0x80000000 +#define EFUSEAR_WRITE_CMD 0x80000000 +#define EFUSEAR_READ_CMD 0x00000000 +#define EFUSEAR_REG_MASK 0x03ff +#define EFUSEAR_REG_SHIFT 8 +#define EFUSEAR_DATA_MASK 0xff +}; + +enum rtl8168_registers { + LED_FREQ = 0x1a, + EEE_LED = 0x1b, + ERIDR = 0x70, + ERIAR = 0x74, +#define ERIAR_FLAG 0x80000000 +#define ERIAR_WRITE_CMD 0x80000000 +#define ERIAR_READ_CMD 0x00000000 +#define ERIAR_ADDR_BYTE_ALIGN 4 +#define ERIAR_TYPE_SHIFT 16 +#define ERIAR_EXGMAC (0x00 << ERIAR_TYPE_SHIFT) +#define ERIAR_MSIX (0x01 << ERIAR_TYPE_SHIFT) +#define ERIAR_ASF (0x02 << ERIAR_TYPE_SHIFT) +#define ERIAR_MASK_SHIFT 12 +#define ERIAR_MASK_0001 (0x1 << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_0010 (0x2 << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_0011 (0x3 << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_0100 (0x4 << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_0101 (0x5 << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_1000 (0x8 << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_1100 (0xc << ERIAR_MASK_SHIFT) +#define ERIAR_MASK_1111 (0xf << ERIAR_MASK_SHIFT) + EPHY_RXER_NUM = 0x7c, + OCPDR = 0xb0, /* OCP GPHY access */ +#define OCPDR_WRITE_CMD 0x80000000 +#define OCPDR_READ_CMD 0x00000000 +#define OCPDR_REG_MASK 0x7fff +#define OCPDR_REG_SHIFT 16 +#define OCPDR_DATA_MASK 0xffff + RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */ + MISC = 0xf0, /* 8168e only. */ +#define TXPLA_RST BIT(29) +#define DISABLE_LAN_EN BIT(23) /* Enable GPIO pin */ +#define PWM_EN BIT(22) +#define RXDV_GATED_EN BIT(19) +#define EARLY_TALLY_EN BIT(16) +}; + +enum r8169soc_registers { + TX_DESC_TAIL_IDX = 0x20, /* the last descriptor index */ + TX_DESC_CLOSE_IDX = 0x22, /* the closed descriptor index */ +#define TX_DESC_CNT_MASK 0x3FFF +#define TX_DESC_CNT_SIZE 0x4000 +}; + +enum rtl_register_content { + /* InterruptStatusBits */ + SYS_ERR = 0x8000, + PCS_TIMEOUT = 0x4000, + SW_INT = 0x0100, + TX_DESC_UNAVAIL = 0x0080, + RX_FIFO_OVER = 0x0040, + LINK_CHG = 0x0020, + RX_OVERFLOW = 0x0010, + TX_ERR = 0x0008, + TX_OK = 0x0004, + RX_ERR = 0x0002, + RX_OK = 0x0001, + + /* RxStatusDesc */ + RX_BOVF = BIT(24), + RX_FOVF = BIT(23), + RX_RWT = BIT(22), + RX_RES = BIT(21), + RX_RUNT = BIT(20), + RX_CRC = BIT(19), + + /* ChipCmdBits */ + STOP_REQ = 0x80, + CMD_RESET = 0x10, + CMD_RX_ENB = 0x08, + CMD_TX_ENB = 0x04, + RX_BUF_EMPTY = 0x01, + + /* TXPoll register p.5 */ + HPQ = 0x80, /* Poll cmd on the high prio queue */ + NPQ = 0x40, /* Poll cmd on the low prio queue */ + FSW_INT = 0x01, /* Forced software interrupt */ + + /* Cfg9346Bits */ + CFG9346_LOCK = 0x00, + CFG9346_UNLOCK = 0xc0, + + /* rx_mode_bits */ + ACCEPT_ERR = 0x20, + ACCEPT_RUNT = 0x10, + ACCEPT_BROADCAST = 0x08, + ACCEPT_MULTICAST = 0x04, + ACCEPT_MY_PHYS = 0x02, + ACCEPT_ALL_PHYS = 0x01, +#define RX_CONFIG_ACCEPT_MASK 0x3f + + /* TxConfigBits */ + TX_INTER_FRAME_GAP_SHIFT = 24, + TX_DMA_SHIFT = 8, /* DMA burst value (0-7) + * is shift this many bits + */ + + /* CONFIG1 register p.24 */ + LEDS1 = BIT(7), + LEDS0 = BIT(6), + SPEED_DOWN = BIT(4), + MEMMAP = BIT(3), + IOMAP = BIT(2), + VPD = BIT(1), + PM_ENABLE = BIT(0), /* Power Management Enable */ + + /* CONFIG2 register p. 25 */ + CLK_REQ_EN = BIT(7), /* Clock Request Enable */ + MSI_ENABLE = BIT(5), /* 8169 only. Reserved in the 8168. */ + PCI_CLOCK_66MHZ = 0x01, + PCI_CLOCK_33MHZ = 0x00, + + /* CONFIG3 register p.25 */ + MAGIC_PKT = BIT(5), /* Wake up when receives a Magic Pkt */ + LINK_UP = BIT(4), /* Wake up when the cable connection + * is re-established + */ + JUMBO_EN0 = BIT(2), /* 8168 only. Reserved in the 8168b */ + BEACON_EN = BIT(0), /* 8168 only. Reserved in the 8168b */ + + /* CONFIG4 register */ + JUMBO_EN1 = BIT(1), /* 8168 only. Reserved in the 8168b */ + + /* CONFIG5 register p.27 */ + BWF = BIT(6), /* Accept Broadcast wakeup frame */ + MWF = BIT(5), /* Accept Multicast wakeup frame */ + UWF = BIT(4), /* Accept Unicast wakeup frame */ + SPI_EN = BIT(3), + LAN_WAKE = BIT(1), /* LAN_WAKE enable/disable */ + PME_STATUS = BIT(0), /* PME status can be reset by PCI RST */ + ASPM_EN = BIT(0), /* ASPM enable */ + + /* C_PLUS_CMD p.31 */ + ENABLE_BIST = BIT(15), /* 8168 8101 */ + MAC_DBGO_OE = BIT(14), /* 8168 8101 */ + NORMAL_MODE = BIT(13), /* unused */ + FORCE_HALF_DUP = BIT(12), /* 8168 8101 */ + FORCE_RXFLOW_EN = BIT(11), /* 8168 8101 */ + FORCE_TXFLOW_EN = BIT(10), /* 8168 8101 */ + CXPL_DBG_SEL = BIT(9), /* 8168 8101 */ + ASF = BIT(8), /* 8168 8101 */ + PKT_CNTR_DISABLE = BIT(7), /* 8168 8101 */ + MAC_DBGO_SEL = 0x001c, /* 8168 */ + RX_VLAN = BIT(6), + RX_CHK_SUM = BIT(5), + PCIDAC = BIT(4), + PCI_MUL_RW = BIT(3), + INTT_0 = 0x0000, /* 8168 */ + INTT_1 = 0x0001, /* 8168 */ + INTT_2 = 0x0002, /* 8168 */ + INTT_3 = 0x0003, /* 8168 */ + + /* rtl8169_PHYstatus */ + PWR_SAVE_STATUS = 0x80, + TX_FLOW_CTRL = 0x40, + RX_FLOW_CTRL = 0x20, + _1000BPSF = 0x10, + _100BPS = 0x08, + _10BPS = 0x04, + LINK_STATUS = 0x02, + FULL_DUP = 0x01, + + /* DumpCounterCommand */ + COUNTER_DUMP = 0x8, +}; + +enum rtl_desc_bit { + /* First doubleword. */ + DESC_OWN = BIT(31), /* Descriptor is owned by NIC */ + RING_END = BIT(30), /* End of descriptor ring */ + FIRST_FRAG = BIT(29), /* First segment of a packet */ + LAST_FRAG = BIT(28), /* Final segment of a packet */ +}; + +/* Generic case. */ +enum rtl_tx_desc_bit { + /* First doubleword. */ + TD_LSO = BIT(27), /* Large Send Offload */ +#define TD_MSS_MAX 0x07ffu /* MSS value */ + + /* Second doubleword. */ + TX_VLAN_TAG = BIT(17), /* Add VLAN tag */ +}; + +/* 8169, 8168b and 810x except 8102e. */ +enum rtl_tx_desc_bit_0 { + /* First doubleword. */ +#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */ + TD0_TCP_CS = BIT(16), /* Calculate TCP/IP checksum */ + TD0_UDP_CS = BIT(17), /* Calculate UDP/IP checksum */ + TD0_IP_CS = BIT(18), /* Calculate IP checksum */ +}; + +/* 8102e, 8168c and beyond. */ +enum rtl_tx_desc_bit_1 { + /* Second doubleword. */ +#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ + TD1_IP_CS = BIT(29), /* Calculate IP checksum */ + TD1_TCP_CS = BIT(30), /* Calculate TCP/IP checksum */ + TD1_UDP_CS = BIT(31), /* Calculate UDP/IP checksum */ +}; + +static const struct rtl_tx_desc_info { + struct { + u32 udp; + u32 tcp; + } checksum; + u16 mss_shift; + u16 opts_offset; +} tx_desc_info = { + .checksum = { + .udp = TD1_IP_CS | TD1_UDP_CS, + .tcp = TD1_IP_CS | TD1_TCP_CS + }, + .mss_shift = TD1_MSS_SHIFT, + .opts_offset = 1 +}; + +enum rtl_rx_desc_bit { + /* Rx private */ + PID1 = BIT(18), /* Protocol ID bit 1/2 */ + PID0 = BIT(17), /* Protocol ID bit 2/2 */ + +#define RX_PROTO_UDP (PID1) +#define RX_PROTO_TCP (PID0) +#define RX_PROTO_IP (PID1 | PID0) +#define RX_PROTO_MASK RX_PROTO_IP + + IP_FAIL = BIT(16), /* IP checksum failed */ + UDP_FAIL = BIT(15), /* UDP/IP checksum failed */ + TCP_FAIL = BIT(14), /* TCP/IP checksum failed */ + RX_VLAN_TAG = BIT(16), /* VLAN tag available */ +}; + +#define RSVD_MASK 0x3fffc000 + +struct tx_desc { + __le32 opts1; + __le32 opts2; + __le64 addr; +}; + +struct rx_desc { + __le32 opts1; + __le32 opts2; + __le64 addr; +}; + +struct ring_info { + struct sk_buff *skb; + u32 len; + u8 __pad[sizeof(void *) - sizeof(u32)]; +}; + +enum features { + RTL_FEATURE_WOL = BIT(0), + RTL_FEATURE_MSI = BIT(1), + RTL_FEATURE_GMII = BIT(2), + RTL_FEATURE_TX_NO_CLOSE = BIT(3), + RTL_FEATURE_RX_NO_COPY = BIT(4), + RTL_FEATURE_ADJUST_FIFO = BIT(5), + RTL_FEATURE_ACP = BIT(6), + RTL_FEATURE_EEE = BIT(7), + RTL_FEATURE_OCP_MDIO = BIT(8), + RTL_FEATURE_PAT_WAKE = BIT(9), +}; + +struct rtl8169_counters { + __le64 tx_packets; + __le64 rx_packets; + __le64 tx_errors; + __le32 rx_errors; + __le16 rx_missed; + __le16 align_errors; + __le32 tx_one_collision; + __le32 tx_multi_collision; + __le64 rx_unicast; + __le64 rx_broadcast; + __le32 rx_multicast; + __le16 tx_aborted; + __le16 tx_underrun; +}; + +enum rtl_flag { + RTL_FLAG_TASK_ENABLED, + RTL_FLAG_TASK_SLOW_PENDING, + RTL_FLAG_TASK_RESET_PENDING, + RTL_FLAG_TASK_PHY_PENDING, + RTL_FLAG_MAX +}; + +struct rtl8169_stats { + u64 packets; + u64 bytes; + struct u64_stats_sync syncp; +}; + +enum rtl_output_mode { + OUTPUT_EMBEDDED_PHY, + OUTPUT_RGMII_TO_MAC, + OUTPUT_RGMII_TO_PHY, + OUTPUT_SGMII_TO_MAC, + OUTPUT_SGMII_TO_PHY, + OUTPUT_RMII, + OUTPUT_FORCE_LINK, + OUTPUT_MAX +}; + +enum drv_status { + RTL_STATUS_DOWN = BIT(0), +}; + +/* ISO base addr 0x98007000 */ +enum common_iso_registers { + ISO_UMSK_ISR = 0x0004, + ISO_PWRCUT_ETN = 0x005c, + ISO_ETN_TESTIO = 0x0060, + ISO_PLL_WDOUT = 0x0070, + ISO_SOFT_RESET = 0x0088, + ISO_CLOCK_ENABLE = 0x008c, + ISO_POR_CTRL = 0x0210, + ISO_POR_VTH = 0x0214, + ISO_POR_DATAI = 0x0218, +}; + +#define POR_XV_MASK 0x00000111 +#define POR_NUM 3 + +/* RTD119X */ +enum rtd119x_iso_registers { + RTD119X_ISO_MUXPAD0 = 0x0310, +}; + +/* RTD129X */ +/* ISO base addr 0x98007000 */ +enum rtd129x_iso_registers { + RTD129X_ISO_RGMII_MDIO_TO_GMAC = 0x0064, + RTD129X_ISO_MUXPAD0 = 0x0310, + RTD129X_ISO_DBUS_CTRL = 0x0fc0, +}; + +/* SB2 base addr 0x9801a000 */ +enum rtd129x_sb2_registers { + RTD129X_SB2_PFUNC_RG0 = 0x0960, + RTD129X_SB2_PFUNC_RG1 = 0x0964, + RTD129X_SB2_PFUNC_RG2 = 0x0968, +}; + +enum rtd129x_rgmii_voltage { + RTD129X_VOLTAGE_1_DOT_8V = 1, + RTD129X_VOLTAGE_2_DOT_5V, + RTD129X_VOLTAGE_3_DOT_3V, + RTD129X_VOLTAGE_MAX +}; + +enum rtd129x_rgmii_delay { + RTD129X_RGMII_DELAY_0NS, + RTD129X_RGMII_DELAY_2NS, + RTD129X_RGMII_DELAY_MAX +}; + +/* RTD139X */ +#define RTD139X_R_K_DEFAULT 0x8 +#define RTD139X_IDAC_FINE_DEFAULT 0x33 + +/* SDS base addr 0x981c8000 */ +enum rtd139x_sds_registers { + RTD139X_SDS_REG02 = 0x0008, + RTD139X_SDS_REG28 = 0x0070, + RTD139X_SDS_REG29 = 0x0074, + RTD139X_SDS_MISC = 0x1804, + RTD139X_SDS_LINK = 0x1810, +}; + +/* ISO testmux base addr 0x9804e000 */ +enum rtd139x_testmux_registers { + RTD139X_ISO_TESTMUX_MUXPAD0 = 0x0000, + RTD139X_ISO_TESTMUX_MUXPAD1 = 0x0004, + RTD139X_ISO_TESTMUX_MUXPAD2 = 0x0008, +}; + +/* SBX base addr 0x9801c000 */ +enum rtd139x_sbx_registers { + RTD139X_SBX_SB3_CHANNEL_REQ_MASK = 0x020c, + RTD139X_SBX_SB3_CHANNEL_REQ_BUSY = 0x0210, + RTD139X_SBX_ACP_CHANNEL_REQ_MASK = 0x080c, + RTD139X_SBX_ACP_CHANNEL_REQ_BUSY = 0x0810, + RTD139X_SBX_ACP_MISC_CTRL = 0x0814, +}; + +/* SCPU_WRAPPER base addr 0x9801d000 */ +enum rtd139x_sc_wrap_registers { + RTD139X_SC_WRAP_ACP_CRT_CTRL = 0x0030, + RTD139X_SC_WRAP_CRT_CTRL = 0x0100, + RTD139X_SC_WRAP_INTERFACE_EN = 0x0124, + RTD139X_SC_WRAP_ACP_CTRL = 0x0800, +}; + +enum rtd139x_phy_addr_e { + /* embedded PHY PHY ID */ + RTD139X_INT_PHY_ADDR = 1, + /* embedded SerDes DPHY PHY ID 0, RL6481_T28_SGMII.doc ANA00~ANA0F */ + RTD139X_SERDES_DPHY_0 = 0, + /* embedded SerDes DPHY PHY ID 1, RL6481_T28_SGMII.doc ANA20~ANA2F */ + RTD139X_SERDES_DPHY_1 = 1, + /* external RTL8211FS SGMII PHY ID */ + RTD139X_EXT_PHY_ADDR = 3, +}; + +enum rtd139x_sgmii_swing_e { + RTD139X_TX_SWING_1040MV = (0X0 << 8), /* DEFAULT */ + RTD139X_TX_SWING_693MV = (0X1 << 8), + RTD139X_TX_SWING_474MV = (0X2 << 8), + RTD139X_TX_SWING_352MV = (0X3 << 8), + RTD139X_TX_SWING_312MV = (0X4 << 8), +}; + +#define RTD139X_SGMII_SWING (0X3 << 8) + +/* RTD16XX */ +#define RTD16XX_RC_K_DEFAULT 0x8888 +#define RTD16XX_R_K_DEFAULT 0x8888 +#define RTD16XX_AMP_K_DEFAULT 0x7777 +#define RTD16XX_ADC_BIAS_K_DEFAULT 0x8888 + +/* SDS base addr 0x981c8000 */ +enum rtd16xx_sds_registers { + RTD16XX_SDS_REG02 = 0x0008, + RTD16XX_SDS_MISC = 0x1804, + RTD16XX_SDS_LINK = 0x180c, + RTD16XX_SDS_DEBUG = 0x1810, +}; + +/* ISO testmux base addr 0x9804e000 */ +enum rtd16xx_testmux_registers { + RTD16XX_ISO_TESTMUX_MUXPAD0 = 0x0000, + RTD16XX_ISO_TESTMUX_MUXPAD1 = 0x0004, + RTD16XX_ISO_TESTMUX_MUXPAD2 = 0x0008, +}; + +/* SBX base addr 0x9801c000 */ +enum rtd16xx_sbx_registers { + RTD16XX_SBX_SB3_CHANNEL_REQ_MASK = 0x020c, + RTD16XX_SBX_SB3_CHANNEL_REQ_BUSY = 0x0210, + RTD16XX_SBX_ACP_CHANNEL_REQ_MASK = 0x080c, + RTD16XX_SBX_ACP_CHANNEL_REQ_BUSY = 0x0810, + RTD16XX_SBX_ACP_MISC_CTRL = 0x0814, +}; + +/* SCPU_WRAPPER base addr 0x9801d000 */ +enum rtd16xx_sc_wrap_registers { + RTD16XX_SC_WRAP_ACP_CRT_CTRL = 0x0030, + RTD16XX_SC_WRAP_CRT_CTRL = 0x0100, + RTD16XX_SC_WRAP_INTERFACE_EN = 0x0124, + RTD16XX_SC_WRAP_ACP_CTRL = 0x0800, +}; + +enum rtd16xx_phy_addr_e { + /* embedded PHY PHY ID */ + RTD16XX_INT_PHY_ADDR = 1, + /* embedded SerDes DPHY PHY ID 0, RL6481_T28_SGMII.doc ANA00~ANA0F */ + RTD16XX_SERDES_DPHY_0 = 0, + /* embedded SerDes DPHY PHY ID 1, RL6481_T28_SGMII.doc ANA20~ANA2F */ + RTD16XX_SERDES_DPHY_1 = 1, + /* external RTL8211FS SGMII PHY ID */ + RTD16XX_EXT_PHY_ADDR = 3, +}; + +enum rtd16xx_sgmii_swing_e { + RTD16XX_TX_SWING_550MV, + RTD16XX_TX_SWING_380MV, + RTD16XX_TX_SWING_250MV, + RTD16XX_TX_SWING_190MV +}; + +/* RTD13XX */ +#define RTD13XX_R_K_DEFAULT 0x8 +#define RTD13XX_IDAC_FINE_DEFAULT 0x77 + +/* ISO testmux base addr 0x9804e000 */ +enum rtd13xx_testmux_registers { + RTD13XX_ISO_TESTMUX_MUXPAD0 = 0x0000, + RTD13XX_ISO_TESTMUX_MUXPAD1 = 0x0004, + RTD13XX_ISO_TESTMUX_MUXPAD2 = 0x0008, + RTD13XX_ISO_TESTMUX_MUXPAD5 = 0x0014, + RTD13XX_ISO_TESTMUX_MUXPAD6 = 0x0018, + RTD13XX_ISO_TESTMUX_PFUNC9 = 0x0040, /* MDC/MDIO current */ + RTD13XX_ISO_TESTMUX_PFUNC20 = 0x006c, /* RGMII current */ + RTD13XX_ISO_TESTMUX_PFUNC21 = 0x0070, /* RGMII current */ + RTD13XX_ISO_TESTMUX_PFUNC25 = 0x0090, /* RGMII BIAS */ +}; + +/* SBX base addr 0x9801c000 */ +enum rtd13xx_sbx_registers { + RTD13XX_SBX_SB3_CHANNEL_REQ_MASK = 0x020c, + RTD13XX_SBX_SB3_CHANNEL_REQ_BUSY = 0x0210, + RTD13XX_SBX_ACP_CHANNEL_REQ_MASK = 0x080c, + RTD13XX_SBX_ACP_CHANNEL_REQ_BUSY = 0x0810, + RTD13XX_SBX_ACP_MISC_CTRL = 0x0814, +}; + +/* SCPU_WRAPPER base addr 0x9801d000 */ +enum rtd13xx_sc_wrap_registers { + RTD13XX_SC_WRAP_ACP_CRT_CTRL = 0x0030, + RTD13XX_SC_WRAP_CRT_CTRL = 0x0100, + RTD13XX_SC_WRAP_INTERFACE_EN = 0x0124, + RTD13XX_SC_WRAP_ACP_CTRL = 0x0800, +}; + +enum rtd13xx_phy_addr_e { + /* embedded PHY PHY ID */ + RTD13XX_INT_PHY_ADDR = 1, + /* external PHY ID */ + RTD13XX_EXT_PHY_ADDR = 1, +}; + +/* RTD16XXB */ +#define RTD16XXB_R_K_DEFAULT 0x8 +#define RTD16XXB_AMP_K_DEFAULT 0x7777 +#define RTD16XXB_RC_K_DEFAULT 0x8888 + +/* ISO testmux base addr 0x9804e000 */ +enum rtd16xxb_testmux_registers { + RTD16XXB_ISO_TESTMUX_MUXPAD2 = 0x0008, /* LED */ + RTD16XXB_ISO_TESTMUX_PFUNC12 = 0x0050, /* MDC/MDIO current */ +}; + +enum rtd16xxb_phy_addr_e { + /* embedded PHY PHY ID */ + RTD16XXB_INT_PHY_ADDR = 1, + /* external PHY ID */ + RTD16XXB_EXT_PHY_ADDR = 1, +}; + +/* end of register locations per chip */ + +#ifdef RTL_PROC +static struct proc_dir_entry *rtw_proc; +#endif +/* wol_enable + * BIT 0: WoL enable + * BIT 1: CRC match + * BIT 2: WPD + */ +enum wol_flags { + WOL_MAGIC = 0x1, + WOL_CRC_MATCH = 0x2, + WOL_WPD = 0x4, +}; + +#define WOL_BUF_LEN 128 + +/* CRC WAKE UP supports 16 rules */ +/* EXACTLY PATTERN WAKE UP supports 32 rules */ +#define RTL_WAKE_SIZE 32 +#define RTL_WAKE_SIZE_CRC 16 + +/* CRC WAKE UP supports 128-bit mask (16 bytes) */ +/* EXACTLY PATTERN WAKE UP supports 128-bit mask + 8-bit padding (17 bytes) */ +#define RTL_WAKE_MASK_SIZE 17 +#define RTL_WAKE_MASK_SIZE_CRC 16 + +#define RTL_WAKE_MASK_REG_SIZE 32 +#define RTL_WAKE_PATTERN_SIZE 136 +struct rtl_wake_rule_s { + u8 flag; + #define WAKE_FLAG_ENABLE 0x01 + u8 mask_size; /* 0 ~ 17, include padding */ + u8 pattern_size; /* 0 ~ 136, include padding */ + u16 crc; /* CRC-16 */ + u16 offset; /* 0 ~ 1535 */ + u8 mask[RTL_WAKE_MASK_SIZE]; + u8 pattern[RTL_WAKE_PATTERN_SIZE]; +}; + +struct rtl8169_rgmii_info { + u8 voltage; /* 1:1.8V, 2: 2.5V, 3:3.3V */ + u8 tx_delay; /* 0: 0ns, 1: 2ns */ + u8 rx_delay; /* 0: 0ns, 1: 2ns */ +}; + +struct rtl8169_sgmii_info { + u8 swing; /* 0:640mV, 1:380mV, 2:250mV, 3:190mV */ +}; + +struct rtl8169_rmii_info { + u8 voltage; /* 1:1.8V, 2: 2.5V, 3:3.3V */ + u8 tx_delay; /* 0: 0ns, 1: 2ns */ + u8 rx_delay; /* 0 ~ 7 x 0.5ns */ +}; + +struct rtl8169_private { + void __iomem *mmio_addr; /* memory map physical address */ + struct regmap *iso_base; + struct regmap *sb2_base; + struct regmap *sbx_base; + struct regmap *scpu_wrap_base; + struct regmap *pinctrl_base; + struct regmap *sds_base; + + struct platform_device *pdev; + struct net_device *dev; + struct napi_struct napi; + u32 msg_enable; + u16 txd_version; + u16 mac_version; + u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ + u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ + u32 dirty_tx; + +#if defined(CONFIG_RTL_RX_NO_COPY) + u32 dirty_rx; + u32 last_dirty_tx; + u32 tx_reset_count; + u32 last_cur_rx; + u32 rx_reset_count; + u8 check_rdu; +#endif /* CONFIG_RTL_RX_NO_COPY */ + + struct rtl8169_stats rx_stats; + struct rtl8169_stats tx_stats; + struct tx_desc *tx_desc_array; /* 256-aligned Tx descriptor ring */ + struct rx_desc *rx_desc_array; /* 256-aligned Rx descriptor ring */ + dma_addr_t tx_phy_addr; + dma_addr_t rx_phy_addr; + + /* Rx data buffers */ + #if defined(CONFIG_RTL_RX_NO_COPY) + struct sk_buff *rx_databuff[NUM_RX_DESC]; /* RTL_FEATURE_RX_NO_COPY */ + #else + void *rx_databuff[NUM_RX_DESC]; + #endif /* CONFIG_RTL_RX_NO_COPY */ + + struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ + u16 cp_cmd; + + u16 event_slow; + +#ifdef RTL_PROC + struct proc_dir_entry *dir_dev; +#endif + + struct { + DECLARE_BITMAP(flags, RTL_FLAG_MAX); + struct mutex mutex; /* mutex for work */ + struct work_struct work; + } wk; + + unsigned int features; + + struct mii_if_info mii; + struct rtl8169_counters counters; + u32 saved_wolopts; + u32 opts1_mask; + + u8 wol_enable; + u8 wol_crc_cnt; + struct rtl_wake_rule_s wol_rule[RTL_WAKE_SIZE]; + struct rtl_wake_rule_s wol_rule_buf; + + u32 ocp_base; + u32 led_cfg; + + struct r8169soc_chip_info *chip; + u32 phy_irq[POR_NUM]; + u8 phy_irq_map[POR_NUM]; + u8 phy_irq_num; + u32 phy_por_xv_mask; + atomic_t phy_reinit_flag; + enum rtl_output_mode output_mode; + union { + struct rtl8169_rgmii_info rgmii; + struct rtl8169_sgmii_info sgmii; + struct rtl8169_rmii_info rmii; + }; + + bool bypass_enable; /* 0: disable, 1: enable */ + u8 ext_phy_id; /* 0 ~ 31 */ + bool eee_enable; /* 0: disable, 1: enable */ + bool acp_enable; /* 0: disable, 1: enable */ + bool ext_phy; + bool pwr_saving; /* power saving of suspend mode */ + bool netif_is_running; + u32 status; +}; + +#define REVISION_A00 0xA00 +#define REVISION_A01 0xA01 +#define REVISION_A02 0xA02 +#define REVISION_B00 0xB00 +#define REVISION_B01 0xB01 +#define REVISION_B02 0xB02 +#define REVISION_NONE 0xFFF + +struct r8169soc_chip_info { + const char *name; + void (*mdio_write)(struct rtl8169_private *tp, int page, int reg, int value); + int (*mdio_read)(struct rtl8169_private *tp, int page, int reg); + void (*mmd_write)(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr, u32 value); + u32 (*mmd_read)(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr); + void (*mdio_lock)(struct rtl8169_private *tp); + void (*mdio_unlock)(struct rtl8169_private *tp); + void (*pll_power_down)(struct rtl8169_private *tp); + void (*pll_power_up)(struct rtl8169_private *tp); + void (*csi_write)(struct rtl8169_private *tp, int addr, int value); + u32 (*csi_read)(struct rtl8169_private *tp, int addr); + int (*set_speed)(struct net_device *dev, u8 aneg, u16 sp, u8 dpx, + u32 adv); + void (*phy_reset_enable)(struct rtl8169_private *tp); + u32 (*phy_reset_pending)(struct rtl8169_private *tp); + u32 (*link_ok)(void __iomem *ioaddr); + int (*do_ioctl)(struct rtl8169_private *tp, + struct mii_ioctl_data *data, int cmd); + void (*hw_start)(struct net_device *dev); + void (*reset_phy_gmac)(struct rtl8169_private *tp); + void (*acp_init)(struct rtl8169_private *tp); + void (*pll_clock_init)(struct rtl8169_private *tp); + void (*mdio_init)(struct rtl8169_private *tp); + void (*mac_mcu_patch)(struct rtl8169_private *tp); + void (*hw_phy_config)(struct rtl8169_private *tp); + void (*wakeup_set)(struct rtl8169_private *tp, bool enable); + void (*eee_set)(struct rtl8169_private *tp, bool enable); + void (*led_set)(struct rtl8169_private *tp, bool enable); + void (*dump_regs)(struct seq_file *m, struct rtl8169_private *tp); + void (*dump_var)(struct seq_file *m, struct rtl8169_private *tp); + + int mac_version; + int cfg_version; + enum rtl_tx_desc_version txd_version; + u32 led_cfg; + u32 region; + u32 align; + u32 features; + u16 event_slow; + u16 jumbo_max; + bool jumbo_tx_csum; +}; + +MODULE_AUTHOR("Realtek and the Linux r8169soc crew "); +MODULE_DESCRIPTION("RealTek RTL-8169soc Gigabit Ethernet driver"); +module_param_named(debug, debug.msg_enable, int, 0644); + +MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(RTL8169_VERSION); + +static void rtl_lock_work(struct rtl8169_private *tp) +{ + mutex_lock(&tp->wk.mutex); +} + +static void rtl_unlock_work(struct rtl8169_private *tp) +{ + mutex_unlock(&tp->wk.mutex); +} + +struct rtl_cond { + bool (*check)(struct rtl8169_private *tp); + const char *msg; +}; + +static void rtl_udelay(unsigned int d) +{ + usleep_range(d, d + 1); +} + +static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c, + void (*delay)(unsigned int), + unsigned int d, int n, bool high) +{ + int i; + + for (i = 0; i < n; i++) { + delay(d); + if (c->check(tp) == high) + return true; + } + netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n", + c->msg, !high, n, d); + return false; +} + +static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp, + const struct rtl_cond *c, + unsigned int d, int n) +{ + return rtl_loop_wait(tp, c, rtl_udelay, d, n, true); +} + +static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp, + const struct rtl_cond *c, + unsigned int d, int n) +{ + return rtl_loop_wait(tp, c, rtl_udelay, d, n, false); +} + +static __maybe_unused bool +rtl_msleep_loop_wait_high(struct rtl8169_private *tp, + const struct rtl_cond *c, unsigned int d, int n) +{ + return rtl_loop_wait(tp, c, msleep, d, n, true); +} + +static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp, + const struct rtl_cond *c, + unsigned int d, int n) +{ + return rtl_loop_wait(tp, c, msleep, d, n, false); +} + +#define DECLARE_RTL_COND(name) \ +static bool name ## _check(struct rtl8169_private *); \ + \ +static const struct rtl_cond name = { \ + .check = name ## _check, \ + .msg = #name \ +}; \ + \ +static bool name ## _check(struct rtl8169_private *tp) + +DECLARE_RTL_COND(rtl_eriar_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(ERIAR) & ERIAR_FLAG; +} + +static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg) +{ + if (reg & 0xffff0001) { + netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg); + return true; + } + return false; +} + +static void rtl_ocp_write(struct rtl8169_private *tp, u32 reg, u32 value) +{ + void __iomem *ioaddr = tp->mmio_addr; + unsigned int wdata; + + if (rtl_ocp_reg_failure(tp, reg)) + return; + + wdata = OCPDR_WRITE_CMD | + (((reg >> 1) & OCPDR_REG_MASK) << OCPDR_REG_SHIFT) | + (value & OCPDR_DATA_MASK); + RTL_W32(OCPDR, wdata); +} + +static u32 rtl_ocp_read(struct rtl8169_private *tp, u32 reg) +{ + void __iomem *ioaddr = tp->mmio_addr; + unsigned int wdata; + unsigned int rdata; + + if (rtl_ocp_reg_failure(tp, reg)) + return 0; + + wdata = OCPDR_READ_CMD | + (((reg >> 1) & OCPDR_REG_MASK) << OCPDR_REG_SHIFT); + RTL_W32(OCPDR, wdata); + rdata = RTL_R32(OCPDR); + return (rdata & OCPDR_DATA_MASK); +} + +#define OCP_STD_PHY_BASE 0xa400 + +static __maybe_unused void mac_mcu_write(struct rtl8169_private *tp, int reg, + int value) +{ + if (reg == 0x1f) { + tp->ocp_base = value << 4; + return; + } + + rtl_ocp_write(tp, tp->ocp_base + reg, value); +} + +static __maybe_unused int mac_mcu_read(struct rtl8169_private *tp, int reg) +{ + return rtl_ocp_read(tp, tp->ocp_base + reg); +} + +DECLARE_RTL_COND(rtl_int_phyar_cond) +{ + return rtl_ocp_read(tp, 0xDE0A) & BIT(14); +} + +DECLARE_RTL_COND(rtl_phyar_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(PHYAR) & 0x80000000; +} + +static void __int_set_phy_addr(struct rtl8169_private *tp, int phy_addr) +{ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + GENMASK(20, 16), (phy_addr << 16), + NULL, false, true); +} + +static inline int __int_mdio_read(struct rtl8169_private *tp, int reg) +{ + int value; + void __iomem *ioaddr = tp->mmio_addr; + + /* read reg */ + RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16); + + value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ? + RTL_R32(PHYAR) & 0xffff : ~0; + + /* According to hardware specs a 20us delay is required after read + * complete indication, but before sending next command. + */ + usleep_range(20, 21); + + return value; +} + +static inline void __int_mdio_write(struct rtl8169_private *tp, int reg, int value) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* write reg */ + RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff)); + + rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20); + /* According to hardware specs a 20us delay is required after write + * complete indication, but before sending next command. + */ + usleep_range(20, 21); +} + +static int int_mdio_read(struct rtl8169_private *tp, int page, int reg) +{ + int value; + + tp->chip->mdio_lock(tp); + + /* write page */ + if (page != CURRENT_MDIO_PAGE) + __int_mdio_write(tp, 0x1f, page); + + /* read reg */ + value = __int_mdio_read(tp, reg); + + tp->chip->mdio_unlock(tp); + return value; +} + +static void int_mdio_write(struct rtl8169_private *tp, int page, int reg, int value) +{ + tp->chip->mdio_lock(tp); + + /* write page */ + if (page != CURRENT_MDIO_PAGE) + __int_mdio_write(tp, 0x1f, page); + + /* write reg */ + __int_mdio_write(tp, reg, value); + + tp->chip->mdio_unlock(tp); +} + +static int int_ocp_mdio_read(struct rtl8169_private *tp, int page, int reg) +{ + int value; + + rtl_ocp_write(tp, 0xDE0C, page); + rtl_ocp_write(tp, 0xDE0A, reg & 0x1f); + + value = rtl_udelay_loop_wait_low(tp, &rtl_int_phyar_cond, 25, 20) ? + rtl_ocp_read(tp, 0xDE08) & 0xffff : ~0; + + return value; +} + +static void int_ocp_mdio_write(struct rtl8169_private *tp, int page, int reg, int value) +{ + rtl_ocp_write(tp, 0xDE0C, page); + rtl_ocp_write(tp, 0xDE08, value); + rtl_ocp_write(tp, 0xDE0A, BIT(15) | (reg & 0x1f)); + + rtl_udelay_loop_wait_low(tp, &rtl_int_phyar_cond, 25, 20); +} + +DECLARE_RTL_COND(rtl_ext_phyar_cond) +{ + return rtl_ocp_read(tp, 0xDE2A) & BIT(14); +} + +DECLARE_RTL_COND(rtl_ephyar_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(EPHYAR) & EPHYAR_FLAG; +} + +static void __ext_set_phy_addr(struct rtl8169_private *tp, int phy_addr) +{ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + GENMASK(25, 21), (phy_addr << 21), + NULL, false, true); +} + +static inline int __ext_mdio_read(struct rtl8169_private *tp, int reg) +{ + int value; + void __iomem *ioaddr = tp->mmio_addr; + + /* read reg */ + RTL_W32(EPHYAR, (reg & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + value = rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ? + RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0; + + return value; +} + +static inline void __ext_mdio_write(struct rtl8169_private *tp, int reg, int value) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* write reg */ + RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | + (reg & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100); + + usleep_range(10, 11); +} + +static int ext_mdio_read(struct rtl8169_private *tp, int page, int reg) +{ + int value; + + tp->chip->mdio_lock(tp); + + /* write page */ + if (page != CURRENT_MDIO_PAGE) + __ext_mdio_write(tp, 0x1f, page); + + /* read reg */ + value = __ext_mdio_read(tp, reg); + + tp->chip->mdio_unlock(tp); + return value; +} + +static void ext_mdio_write(struct rtl8169_private *tp, int page, int reg, int value) +{ + tp->chip->mdio_lock(tp); + + /* write page */ + if (page != CURRENT_MDIO_PAGE) + __ext_mdio_write(tp, 0x1f, page); + + /* write reg */ + __ext_mdio_write(tp, reg, value); + + tp->chip->mdio_unlock(tp); +} + +static int ext_ocp_mdio_read(struct rtl8169_private *tp, int page, int reg) +{ + int value; + + rtl_ocp_write(tp, 0xDE2C, page); + rtl_ocp_write(tp, 0xDE2A, reg & 0x1f); + + value = rtl_udelay_loop_wait_low(tp, &rtl_ext_phyar_cond, 25, 20) ? + rtl_ocp_read(tp, 0xDE28) & 0xffff : ~0; + return value; +} + +static void ext_ocp_mdio_write(struct rtl8169_private *tp, int page, int reg, int value) +{ + rtl_ocp_write(tp, 0xDE2C, page); + rtl_ocp_write(tp, 0xDE28, value); + rtl_ocp_write(tp, 0xDE2A, BIT(15) | (reg & 0x1f)); + + rtl_udelay_loop_wait_low(tp, &rtl_ext_phyar_cond, 25, 20); +} + +static void rtl_init_mdio_ops(struct rtl8169_private *tp) +{ + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + if (tp->chip->features & RTL_FEATURE_OCP_MDIO) { + tp->chip->mdio_write = int_ocp_mdio_write; + tp->chip->mdio_read = int_ocp_mdio_read; + } else { + tp->chip->mdio_write = int_mdio_write; + tp->chip->mdio_read = int_mdio_read; + } + } else { + if (tp->chip->features & RTL_FEATURE_OCP_MDIO) { + tp->chip->mdio_write = ext_ocp_mdio_write; + tp->chip->mdio_read = ext_ocp_mdio_read; + } else { + tp->chip->mdio_write = ext_mdio_write; + tp->chip->mdio_read = ext_mdio_read; + } + } +} + +static inline void rtl_phy_write(struct rtl8169_private *tp, int page, int reg, u32 val) +{ + tp->chip->mdio_write(tp, page, reg, val); +} + +static inline int rtl_phy_read(struct rtl8169_private *tp, int page, int reg) +{ + return tp->chip->mdio_read(tp, page, reg); +} + +static void rtl_mdio_write(struct net_device *dev, int phy_id, int location, int val) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_phy_write(tp, 0, location, val); +} + +static int rtl_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + return rtl_phy_read(tp, 0, location); +} + +static inline void rtl_patchphy(struct rtl8169_private *tp, int page, + int reg_addr, int value) +{ + rtl_phy_write(tp, page, reg_addr, + rtl_phy_read(tp, page, reg_addr) | value); +} + +static inline void rtl_w1w0_phy(struct rtl8169_private *tp, int page, + int reg_addr, int p, int m) +{ + rtl_phy_write(tp, page, reg_addr, + (rtl_phy_read(tp, page, reg_addr) | p) & ~m); +} + +void int_mmd_write(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr, u32 value) +{ + tp->chip->mdio_lock(tp); + + /* set page 0 */ + __int_mdio_write(tp, 0x1f, 0); + /* address mode */ + __int_mdio_write(tp, 13, (0x1f & dev_addr)); + /* write the desired address */ + __int_mdio_write(tp, 14, reg_addr); + /* data mode, no post increment */ + __int_mdio_write(tp, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* write the content of the selected register */ + __int_mdio_write(tp, 14, value); + + tp->chip->mdio_unlock(tp); +} + +u32 int_mmd_read(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr) +{ + u32 value; + + tp->chip->mdio_lock(tp); + + /* set page 0 */ + __int_mdio_write(tp, 0x1f, 0); + /* address mode */ + __int_mdio_write(tp, 13, (0x1f & dev_addr)); + /* write the desired address */ + __int_mdio_write(tp, 14, reg_addr); + /* data mode, no post increment */ + __int_mdio_write(tp, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* read the content of the selected register */ + value = __int_mdio_read(tp, 14); + + tp->chip->mdio_unlock(tp); + return value; +} + +void ext_mmd_write(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr, u32 value) +{ + tp->chip->mdio_lock(tp); + + /* set page 0 */ + __ext_mdio_write(tp, 0x1f, 0); + /* address mode */ + __ext_mdio_write(tp, 13, (0x1f & dev_addr)); + /* write the desired address */ + __ext_mdio_write(tp, 14, reg_addr); + /* data mode, no post increment */ + __ext_mdio_write(tp, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* write the content of the selected register */ + __ext_mdio_write(tp, 14, value); + + tp->chip->mdio_unlock(tp); +} + +u32 ext_mmd_read(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr) +{ + u32 value; + + tp->chip->mdio_lock(tp); + + /* set page 0 */ + __ext_mdio_write(tp, 0x1f, 0); + /* address mode */ + __ext_mdio_write(tp, 13, (0x1f & dev_addr)); + /* write the desired address */ + __ext_mdio_write(tp, 14, reg_addr); + /* data mode, no post increment */ + __ext_mdio_write(tp, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* read the content of the selected register */ + value = __ext_mdio_read(tp, 14); + + tp->chip->mdio_unlock(tp); + return value; +} + +void int_ocp_mmd_write(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr, u32 value) +{ + /* address mode */ + int_ocp_mdio_write(tp, 0, 13, (0x1f & dev_addr)); + /* write the desired address */ + int_ocp_mdio_write(tp, 0, 14, reg_addr); + /* data mode, no post increment */ + int_ocp_mdio_write(tp, 0, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* write the content of the selected register */ + int_ocp_mdio_write(tp, 0, 14, value); +} + +u32 int_ocp_mmd_read(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr) +{ + /* address mode */ + int_ocp_mdio_write(tp, 0, 13, (0x1f & dev_addr)); + /* write the desired address */ + int_ocp_mdio_write(tp, 0, 14, reg_addr); + /* data mode, no post increment */ + int_ocp_mdio_write(tp, 0, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* read the content of the selected register */ + return int_ocp_mdio_read(tp, 0, 14); +} + +void ext_ocp_mmd_write(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr, u32 value) +{ + /* address mode */ + ext_ocp_mdio_write(tp, 0, 13, (0x1f & dev_addr)); + /* write the desired address */ + ext_ocp_mdio_write(tp, 0, 14, reg_addr); + /* data mode, no post increment */ + ext_ocp_mdio_write(tp, 0, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* write the content of the selected register */ + ext_ocp_mdio_write(tp, 0, 14, value); +} + +u32 ext_ocp_mmd_read(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr) +{ + /* address mode */ + ext_ocp_mdio_write(tp, 0, 13, (0x1f & dev_addr)); + /* write the desired address */ + ext_ocp_mdio_write(tp, 0, 14, reg_addr); + /* data mode, no post increment */ + ext_ocp_mdio_write(tp, 0, 13, ((0x1f & dev_addr) | (0x1 << 14))); + /* read the content of the selected register */ + return ext_ocp_mdio_read(tp, 0, 14); +} + +static void rtl_init_mmd_ops(struct rtl8169_private *tp) +{ + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + if (tp->chip->features & RTL_FEATURE_OCP_MDIO) { + tp->chip->mmd_write = int_ocp_mmd_write; + tp->chip->mmd_read = int_ocp_mmd_read; + } else { + tp->chip->mmd_write = int_mmd_write; + tp->chip->mmd_read = int_mmd_read; + } + } else { + if (tp->chip->features & RTL_FEATURE_OCP_MDIO) { + tp->chip->mmd_write = ext_ocp_mmd_write; + tp->chip->mmd_read = ext_ocp_mmd_read; + } else { + tp->chip->mmd_write = ext_mmd_write; + tp->chip->mmd_read = ext_mmd_read; + } + } +} + +void rtl_mmd_write(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr, u32 value) +{ + tp->chip->mmd_write(tp, dev_addr, reg_addr, value); +} + +u32 rtl_mmd_read(struct rtl8169_private *tp, u32 dev_addr, u32 reg_addr) +{ + return tp->chip->mmd_read(tp, dev_addr, reg_addr); +} + +static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask, + u32 val, int type) +{ + void __iomem *ioaddr = tp->mmio_addr; + + WARN_ON((addr & 3) || (mask == 0)); + RTL_W32(ERIDR, val); + RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr); + + rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100); +} + +static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr); + + return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ? + RTL_R32(ERIDR) : ~0; +} + +static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p, + u32 m, int type) +{ + u32 val; + + val = rtl_eri_read(tp, addr, type); + rtl_eri_write(tp, addr, mask, (val & ~m) | p, type); +} + +struct exgmac_reg { + u16 addr; + u16 mask; + u32 val; +}; + +static void rtl_write_exgmac_batch(struct rtl8169_private *tp, + const struct exgmac_reg *r, int len) +{ + while (len-- > 0) { + rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC); + r++; + } +} + +static u16 rtl_get_events(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R16(INTR_STATUS); +} + +static void rtl_ack_events(struct rtl8169_private *tp, u16 bits) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W16(INTR_STATUS, bits); +} + +static void rtl_irq_disable(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W16(INTR_MASK, 0); +} + +static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W16(INTR_MASK, bits); +} + +#define RTL_EVENT_NAPI_RX (RX_OK | RX_ERR | RX_OVERFLOW) +#define RTL_EVENT_NAPI_TX (TX_OK | TX_ERR) +#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX) + +static void rtl_irq_enable_all(struct rtl8169_private *tp) +{ + rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow); +} + +static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + rtl_irq_disable(tp); + rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow); + RTL_R8(CHIP_CMD); +} + +static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp) +{ + int ret; + + ret = rtl_phy_read(tp, 0, MII_BMCR); + return ret & BMCR_RESET; +} + +static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr) +{ + return RTL_R8(PHY_STATUS) & LINK_STATUS; +} + +static unsigned int rtl8169_xmii_always_link_ok(void __iomem *ioaddr) +{ + return true; +} + +static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp) +{ + unsigned int val; + + val = rtl_phy_read(tp, 0, MII_BMCR) | BMCR_RESET; + rtl_phy_write(tp, 0, MII_BMCR, val & 0xffff); +} + +void r8169_display_eee_info(struct net_device *dev, struct seq_file *m, + struct rtl8169_private *tp) +{ + /* display DUT and link partner EEE capability */ + unsigned int temp, tmp1, tmp2; + int speed = 0; + bool eee1000, eee100, eee10; + int duplex; + + temp = rtl_phy_read(tp, 0x0a43, 26); + if (0 == ((0x1 << 2) & temp)) { + seq_printf(m, "%s: link is down\n", dev->name); + return; + } + + if ((0x1 << 3) & temp) + duplex = 1; + else + duplex = 0; + + if ((0x0 << 4) == ((0x3 << 4) & temp)) { + speed = 10; + + tmp1 = rtl_phy_read(tp, 0x0bcd, 19); + + tmp2 = rtl_phy_read(tp, 0xa60, 16); + + if (0 == ((0x1 << 4) & tmp1)) + eee10 = false; + else + eee10 = true; + + seq_printf(m, "%s: link speed = %dM %s, EEE = %s, PCS_Status = 0x%02x\n", + dev->name, speed, + duplex ? "full" : "half", + eee10 ? "Y" : "N", + tmp2 & 0xff); + return; + } + if ((0x1 << 4) == ((0x3 << 4) & temp)) + speed = 100; + if ((0x2 << 4) == ((0x3 << 4) & temp)) + speed = 1000; + if ((0x1 << 8) == ((0x1 << 8) & temp)) { + seq_printf(m, "%s: link speed = %dM %s, EEE = Y\n", dev->name, + speed, duplex ? "full" : "half"); + + tmp1 = rtl_phy_read(tp, 0xa60, 16); + + tmp2 = rtl_phy_read(tp, 0xa5c, 19); + seq_printf(m, "PCS_Status = 0x%02x, EEE_wake_error = 0x%04x\n", + tmp1 & 0xff, tmp2); + } else { + seq_printf(m, "%s: link speed = %dM %s, EEE = N\n", dev->name, + speed, duplex ? "full" : "half"); + + temp = rtl_mmd_read(tp, 0x7, 0x3d); + if (0 == (temp & (0x1 << 2))) + eee1000 = false; + else + eee1000 = true; + + if (0 == (temp & (0x1 << 1))) + eee100 = false; + else + eee100 = true; + + seq_printf(m, "%s: Link Partner EEE1000=%s, EEE100=%s\n", + dev->name, eee1000 ? "Y" : "N", eee100 ? "Y" : "N"); + } +} + +static void __rtl8169_check_link_status(struct net_device *dev, + struct rtl8169_private *tp, + void __iomem *ioaddr, bool pm) +{ + if (tp->chip->link_ok(ioaddr)) { + /* This is to cancel a scheduled suspend if there's one. */ + if (pm) + pm_request_resume(&tp->pdev->dev); + netif_carrier_on(dev); + if (net_ratelimit()) + netif_info(tp, ifup, dev, "link up\n"); + } else { + netif_carrier_off(dev); + netif_info(tp, ifdown, dev, "link down\n"); + if (pm) + pm_schedule_suspend(&tp->pdev->dev, 5000); + } +} + +static void rtl8169_check_link_status(struct net_device *dev, + struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + __rtl8169_check_link_status(dev, tp, ioaddr, false); +} + +#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) + +static u32 __rtl8169_get_wol(struct rtl8169_private *tp) +{ + u32 wolopts = 0; + + if (tp->wol_enable & WOL_MAGIC) + wolopts |= WAKE_MAGIC; + + return wolopts; +} + +static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + + wol->supported = WAKE_ANY; + wol->wolopts = __rtl8169_get_wol(tp); + + rtl_unlock_work(tp); +} + +static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) +{ + if (wolopts & WAKE_MAGIC) + tp->wol_enable |= WOL_MAGIC; + else + tp->wol_enable &= ~WOL_MAGIC; +} + +static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + + if (wol->wolopts) + tp->features |= RTL_FEATURE_WOL; + else + tp->features &= ~RTL_FEATURE_WOL; + __rtl8169_set_wol(tp, wol->wolopts); + + rtl_unlock_work(tp); + + device_set_wakeup_enable(&tp->pdev->dev, wol->wolopts); + + return 0; +} + +static void rtl8169_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strscpy(info->driver, MODULENAME, sizeof(info->driver)); + strscpy(info->version, RTL8169_VERSION, sizeof(info->version)); + strscpy(info->bus_info, "RTK-ETN", sizeof(info->bus_info)); +} + +static int rtl8169_get_regs_len(struct net_device *dev) +{ + return R8169_REGS_SIZE; +} + +static int rtl8169_set_speed_xmii(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex, u32 adv) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int giga_ctrl, bmcr; + int rc = -EINVAL; + + if (autoneg == AUTONEG_ENABLE) { + int auto_nego; + + auto_nego = rtl_phy_read(tp, 0, MII_ADVERTISE); + auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL); + + if (adv & ADVERTISED_10baseT_Half) + auto_nego |= ADVERTISE_10HALF; + if (adv & ADVERTISED_10baseT_Full) + auto_nego |= ADVERTISE_10FULL; + if (adv & ADVERTISED_100baseT_Half) + auto_nego |= ADVERTISE_100HALF; + if (adv & ADVERTISED_100baseT_Full) + auto_nego |= ADVERTISE_100FULL; + + auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + + giga_ctrl = rtl_phy_read(tp, 0, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + + /* The 8100e/8101e/8102e do Fast Ethernet only. */ + if (tp->mii.supports_gmii) { + if (adv & ADVERTISED_1000baseT_Half) + giga_ctrl |= ADVERTISE_1000HALF; + if (adv & ADVERTISED_1000baseT_Full) + giga_ctrl |= ADVERTISE_1000FULL; + } else if (adv & (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full)) { + netif_info(tp, link, dev, + "PHY does not support 1000Mbps\n"); + goto out; + } + + bmcr = BMCR_ANENABLE | BMCR_ANRESTART; + + rtl_phy_write(tp, 0, MII_ADVERTISE, auto_nego); + rtl_phy_write(tp, 0, MII_CTRL1000, giga_ctrl); + } else { + giga_ctrl = 0; + + if (speed == SPEED_10) + bmcr = 0; + else if (speed == SPEED_100) + bmcr = BMCR_SPEED100; + else + goto out; + + if (duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + } + + rtl_phy_write(tp, 0, MII_BMCR, bmcr); + + rc = 0; +out: + return rc; +} + +static int rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex, u32 advertising) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + ret = tp->chip->set_speed(dev, autoneg, speed, duplex, advertising); + return ret; +} + +static netdev_features_t rtl8169_fix_features(struct net_device *dev, + netdev_features_t features) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (dev->mtu > TD_MSS_MAX) + features &= ~NETIF_F_ALL_TSO; + + if (dev->mtu > JUMBO_1K && !tp->chip->jumbo_tx_csum) + features &= ~NETIF_F_IP_CSUM; + + return features; +} + +static void __rtl8169_set_features(struct net_device *dev, + netdev_features_t features) +{ + struct rtl8169_private *tp = netdev_priv(dev); + netdev_features_t changed = features ^ dev->features; + void __iomem *ioaddr = tp->mmio_addr; + + if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_RX))) + return; + + if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX)) { + if (features & NETIF_F_RXCSUM) + tp->cp_cmd |= RX_CHK_SUM; + else + tp->cp_cmd &= ~RX_CHK_SUM; + + if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) + tp->cp_cmd |= RX_VLAN; + else + tp->cp_cmd &= ~RX_VLAN; + + RTL_W16(C_PLUS_CMD, tp->cp_cmd); + RTL_R16(C_PLUS_CMD); + } + if (changed & NETIF_F_RXALL) { + int tmp = (RTL_R32(RX_CONFIG) & ~(ACCEPT_ERR | ACCEPT_RUNT)); + + if (features & NETIF_F_RXALL) + tmp |= (ACCEPT_ERR | ACCEPT_RUNT); + RTL_W32(RX_CONFIG, tmp); + } +} + +static int rtl8169_set_features(struct net_device *dev, + netdev_features_t features) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + __rtl8169_set_features(dev, features); + rtl_unlock_work(tp); + + return 0; +} + +static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb) +{ + return (skb_vlan_tag_present(skb)) ? + TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb)) : 0x00; +} + +static void rtl8169_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb) +{ + u32 opts2 = le32_to_cpu(desc->opts2); + + if (opts2 & RX_VLAN_TAG) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + swab16(opts2 & 0xffff)); +} + +static int rtl8169_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + mii_ethtool_get_link_ksettings(&tp->mii, cmd); + rtl_unlock_work(tp); + + return 0; +} + +static int rtl8169_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + u32 advertising; + + ethtool_convert_link_mode_to_legacy_u32(&advertising, cmd->link_modes.advertising); + + rtl_lock_work(tp); + ret = rtl8169_set_speed(dev, cmd->base.autoneg, cmd->base.speed, + cmd->base.duplex, advertising); + rtl_unlock_work(tp); + + return ret; +} + +static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct rtl8169_private *tp = netdev_priv(dev); + u32 __iomem *data = tp->mmio_addr; + u32 *dw = p; + int i; + + rtl_lock_work(tp); + for (i = 0; i < R8169_REGS_SIZE; i += 4) + memcpy_fromio(dw++, data++, 4); + rtl_unlock_work(tp); +} + +static u32 rtl8169_get_msglevel(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + return tp->msg_enable; +} + +static void rtl8169_set_msglevel(struct net_device *dev, u32 value) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + tp->msg_enable = value; +} + +static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { + "tx_packets", + "rx_packets", + "tx_errors", + "rx_errors", + "rx_missed", + "align_errors", + "tx_single_collisions", + "tx_multi_collisions", + "unicast", + "broadcast", + "multicast", + "tx_aborted", + "tx_underrun", +}; + +static int rtl8169_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(rtl8169_gstrings); + default: + return -EOPNOTSUPP; + } +} + +DECLARE_RTL_COND(rtl_counters_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(COUNTER_ADDR_LOW) & COUNTER_DUMP; +} + +static void rtl8169_update_counters(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pdev->dev; + struct rtl8169_counters *counters; + dma_addr_t paddr; + u32 cmd; + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; + + /* Some chips are unable to dump tally counters when the receiver + * is disabled. + */ + if ((RTL_R8(CHIP_CMD) & CMD_RX_ENB) == 0) + return; + + if (tp->acp_enable) { + counters = kzalloc_node(sizeof(*counters), GFP_KERNEL, node); + paddr = virt_to_phys(counters); + } else { + counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, + GFP_KERNEL); + } + if (!counters) + return; + + RTL_W32(COUNTER_ADDR_HIGH, (u64)paddr >> 32); + cmd = (u64)paddr & DMA_BIT_MASK(32); + RTL_W32(COUNTER_ADDR_LOW, cmd); + RTL_W32(COUNTER_ADDR_LOW, cmd | COUNTER_DUMP); + + if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000)) + memcpy(&tp->counters, counters, sizeof(*counters)); + + RTL_W32(COUNTER_ADDR_LOW, 0); + RTL_W32(COUNTER_ADDR_HIGH, 0); + + if (tp->acp_enable) + kfree(counters); + else + dma_free_coherent(d, sizeof(*counters), counters, paddr); +} + +static void rtl8169_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + ASSERT_RTNL(); + + rtl8169_update_counters(dev); + + data[0] = le64_to_cpu(tp->counters.tx_packets); + data[1] = le64_to_cpu(tp->counters.rx_packets); + data[2] = le64_to_cpu(tp->counters.tx_errors); + data[3] = le32_to_cpu(tp->counters.rx_errors); + data[4] = le16_to_cpu(tp->counters.rx_missed); + data[5] = le16_to_cpu(tp->counters.align_errors); + data[6] = le32_to_cpu(tp->counters.tx_one_collision); + data[7] = le32_to_cpu(tp->counters.tx_multi_collision); + data[8] = le64_to_cpu(tp->counters.rx_unicast); + data[9] = le64_to_cpu(tp->counters.rx_broadcast); + data[10] = le32_to_cpu(tp->counters.rx_multicast); + data[11] = le16_to_cpu(tp->counters.tx_aborted); + data[12] = le16_to_cpu(tp->counters.tx_underrun); +} + +static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, rtl8169_gstrings, sizeof(rtl8169_gstrings)); + break; + } +} + +static const struct ethtool_ops rtl8169_ethtool_ops = { + .get_link_ksettings = rtl8169_get_link_ksettings, + .set_link_ksettings = rtl8169_set_link_ksettings, + .get_drvinfo = rtl8169_get_drvinfo, + .get_regs_len = rtl8169_get_regs_len, + .get_link = ethtool_op_get_link, + .get_msglevel = rtl8169_get_msglevel, + .set_msglevel = rtl8169_set_msglevel, + .get_regs = rtl8169_get_regs, + .get_wol = rtl8169_get_wol, + .set_wol = rtl8169_set_wol, + .get_strings = rtl8169_get_strings, + .get_sset_count = rtl8169_get_sset_count, + .get_ethtool_stats = rtl8169_get_ethtool_stats, + .get_ts_info = ethtool_op_get_ts_info, +}; + +struct phy_reg { + u16 reg; + u16 val; +}; + +static __maybe_unused void rtl_rar_exgmac_set(struct rtl8169_private *tp, + u8 *addr) +{ + const u16 w[] = { + addr[0] | (addr[1] << 8), + addr[2] | (addr[3] << 8), + addr[4] | (addr[5] << 8) + }; + const struct exgmac_reg e[] = { + {.addr = 0xe0, ERIAR_MASK_1111, .val = w[0] | (w[1] << 16)}, + {.addr = 0xe4, ERIAR_MASK_1111, .val = w[2]}, + {.addr = 0xf0, ERIAR_MASK_1111, .val = w[0] << 16}, + {.addr = 0xf4, ERIAR_MASK_1111, .val = w[1] | (w[2] << 16)} + }; + + rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e)); +} + +static void rtl8168g_2_hw_mac_mcu_patch(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* power down PHY */ + rtl_phy_write(tp, 0, MII_BMCR, + rtl_phy_read(tp, 0, MII_BMCR) | BMCR_PDOWN); + + tp->chip->mac_mcu_patch(tp); + + /* set dis_mcu_clroob to avoid WOL fail when ALDPS mode is enabled */ + RTL_W8(MCU, RTL_R8(MCU) | DIS_MCU_CLROOB); +} + +static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp) +{ + tp->chip->hw_phy_config(tp); +} + +static void rtl_hw_phy_config(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl8168g_2_hw_mac_mcu_patch(tp); + rtl8168g_2_hw_phy_config(tp); +} + +static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) +{ + if (!test_and_set_bit(flag, tp->wk.flags)) + schedule_work(&tp->wk.work); +} + +static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) +{ + void __iomem *ioaddr = tp->mmio_addr; + + rtl_lock_work(tp); + + RTL_W8(CFG9346, CFG9346_UNLOCK); + + RTL_W32(MAC4, addr[4] | addr[5] << 8); + RTL_R32(MAC4); + + RTL_W32(MAC0, addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); + RTL_R32(MAC0); + + RTL_W8(CFG9346, CFG9346_LOCK); + + rtl_unlock_work(tp); +} + +static void rtl_phy_reinit(struct rtl8169_private *tp) +{ + u32 tmp; + + /* fill fuse_rdy & rg_ext_ini_done */ + rtl_phy_write(tp, 0x0a46, 20, + rtl_phy_read(tp, 0x0a46, 20) | (BIT(1) | BIT(0))); + + /* init_autoload_done = 1 */ + tmp = rtl_ocp_read(tp, 0xe004); + tmp |= BIT(7); + rtl_ocp_write(tp, 0xe004, tmp); + + /* wait LAN-ON */ + tmp = 0; + do { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err("PHY status is not 0x3, current = 0x%02x\n", + (rtl_phy_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } while (0x3 != (rtl_phy_read(tp, 0x0a42, 16) & 0x07)); + pr_info("wait %d ms for PHY ready, current = 0x%x\n", + tmp, rtl_phy_read(tp, 0x0a42, 16)); + + tp->chip->phy_reset_enable(tp); +} + +static void rtl_phy_work(struct rtl8169_private *tp) +{ + rtl_phy_reinit(tp); + atomic_dec(&tp->phy_reinit_flag); +} + +static void rtl8169_release_board(struct platform_device *pdev, + struct net_device *dev, void __iomem *ioaddr) +{ + iounmap(ioaddr); + free_netdev(dev); +} + +DECLARE_RTL_COND(rtl_phy_reset_cond) +{ + return tp->chip->phy_reset_pending(tp); +} + +static void rtl8169_phy_reset(struct net_device *dev, + struct rtl8169_private *tp) +{ + tp->chip->phy_reset_enable(tp); + rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100); +} + +static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + rtl_hw_phy_config(dev); + + /* disable now_is_oob */ + RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); + + rtl8169_phy_reset(dev, tp); + + rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, + ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + (tp->mii.supports_gmii ? + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full : 0)); +} + +static int rtl_set_mac_address(struct net_device *dev, void *p) +{ + struct rtl8169_private *tp = netdev_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + rtl_rar_set(tp, dev->dev_addr); + + return 0; +} + +static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + struct mii_ioctl_data *data = if_mii(ifr); + + return netif_running(dev) ? tp->chip->do_ioctl(tp, data, cmd) : -ENODEV; +} + +static int rtl_xmii_ioctl(struct rtl8169_private *tp, + struct mii_ioctl_data *data, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = 32; /* Internal PHY */ + return 0; + + case SIOCGMIIREG: + data->val_out = rtl_phy_read(tp, 0, data->reg_num & 0x1f); + return 0; + + case SIOCSMIIREG: + rtl_phy_write(tp, 0, data->reg_num & 0x1f, data->val_in); + return 0; + } + return -EOPNOTSUPP; +} + +static void rtl_wpd_set(struct rtl8169_private *tp) +{ + u32 tmp; + u32 i; + + /* clear WPD registers */ + rtl_ocp_write(tp, 0xD23A, 0); + rtl_ocp_write(tp, 0xD23C, 0); + rtl_ocp_write(tp, 0xD23E, 0); + for (i = 0; i < 128; i += 2) + rtl_ocp_write(tp, 0xD240 + i, 0); + + tmp = rtl_ocp_read(tp, 0xC0C2); + tmp &= ~BIT(4); + rtl_ocp_write(tp, 0xC0C2, tmp); + + /* enable WPD */ + tmp = rtl_ocp_read(tp, 0xC0C2); + tmp |= BIT(0); + rtl_ocp_write(tp, 0xC0C2, tmp); +} + +/* EXACTLY PATTERN WAKE UP */ +static int rtl_cp_reduced_pattern(struct rtl8169_private *tp, u32 idx, + u8 *src, u32 len) +{ + u32 i; + u32 j; + u32 src_offset = 0; + u32 dst_offset = 0; + + memset(&tp->wol_rule[idx].pattern[0], 0, RTL_WAKE_PATTERN_SIZE); + + if (tp->wol_rule[idx].mask_size >= RTL_WAKE_MASK_SIZE) { + pr_err("WOL rule[%d]: incorrect mask size %d\n", idx, + tp->wol_rule[idx].mask_size); + return 0; + } + + for (i = 0; i < tp->wol_rule[idx].mask_size; i++) { + for (j = 0; j < 8; j++) { + if (tp->wol_rule[idx].mask[i] & (1 << j)) { + dst_offset = (i * 8) + j; + tp->wol_rule[idx].pattern[dst_offset] = + src[src_offset++]; + } + } + } + + if (src_offset != len) + pr_err("WOL rule[%d]: expected pattern len %d, actual len %d\n", + idx, len, src_offset); + + return (dst_offset + 1); +} + +static void rtl_write_pat_wakeup_pattern(struct rtl8169_private *tp, u32 idx) +{ + u8 i; + u32 reg_shift; + u32 reg_offset; + u16 mask_sel; + u16 cross_flag; + u8 zero_prefix; + u16 tmp; + u16 reg; + u8 temp_mask[RTL_WAKE_MASK_REG_SIZE]; + u8 zero_mask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F}; + u16 data_byte; + u16 half_byte; + u8 temp_pattern[RTL_WAKE_PATTERN_SIZE + 2]; + u16 *ptr; + + /* check size of wake-mask */ + if (tp->wol_rule[idx].mask_size > RTL_WAKE_MASK_SIZE) { + pr_err("[%s] size of WoL wake-mask%d is too long\n", + MODULENAME, idx); + pr_err("mask size %d (max %d)\n", + tp->wol_rule[idx].mask_size, RTL_WAKE_MASK_SIZE); + return; + } + + /* check size of wake-pattern */ + if (tp->wol_rule[idx].pattern_size >= RTL_WAKE_PATTERN_SIZE) { + pr_err("[%s] size of WoL wake-pattern%d is too long\n", + MODULENAME, idx); + pr_err("pattern size %d (max %d)\n", + tp->wol_rule[idx].pattern_size, RTL_WAKE_PATTERN_SIZE); + return; + } + + /* make sure mask contains correct zero prefix */ + zero_prefix = zero_mask[tp->wol_rule[idx].offset % 8]; + if (tp->wol_rule[idx].mask[0] & zero_prefix) { + pr_err("[%s] incorrect zero prefix of WoL wake-mask%d\n", + MODULENAME, idx); + pr_err("offset %d, zero prefix 0x%x, mask[0] 0x%x\n", + tp->wol_rule[idx].offset, zero_prefix, + tp->wol_rule[idx].mask[0]); + return; + } + + /* make sure pattern contains correct zero prefix */ + tmp = tp->wol_rule[idx].offset % 8; + for (i = 0; i < tmp; i++) { + if (tp->wol_rule[idx].pattern[i] == 0x00) + continue; + pr_err("[%s] incorrect zero prefix of WoL wake-pattern%d\n", + MODULENAME, idx); + pr_err("offset %d, zero prefix cnt %d, pattern[i] 0x%x\n", + tp->wol_rule[idx].offset, tmp, + tp->wol_rule[idx].pattern[i]); + return; + } + + /* fill CRC_MASK_SEL_SET reg */ + reg_offset = (idx / 4) * 2; + reg_shift = idx % 4; + + cross_flag = ((tp->wol_rule[idx].offset % 256) >= 128) ? 1 : 0; + mask_sel = ((tp->wol_rule[idx].offset / 256) << 1) | cross_flag; + + reg = 0xC130 + reg_offset; + tmp = rtl_ocp_read(tp, reg); + tmp &= ~(0xF << reg_shift); + tmp |= mask_sel << reg_shift; + rtl_ocp_write(tp, reg, tmp); + + /* create 32-byte WAKE_MASK according to 17-byte tp->wol_rule[idx].mask */ + memset(temp_mask, 0, RTL_WAKE_MASK_REG_SIZE); + tmp = (tp->wol_rule[idx].offset % 256) / 8; + for (i = 0; i < tp->wol_rule[idx].mask_size; i++) + temp_mask[(tmp + i) % RTL_WAKE_MASK_REG_SIZE] = + tp->wol_rule[idx].mask[i]; + + /* fill WAKE_MASK reg */ + reg_offset = (idx / 4) * 2; + reg_shift = (idx % 4) * 4; + + for (i = 0; i < 64; i++) { + reg = 0x7C00 + reg_offset + (i * 16); + tmp = rtl_ocp_read(tp, reg); + tmp &= ~(0xF << reg_shift); + data_byte = temp_mask[(i * 4) / 8]; + half_byte = (data_byte >> ((i * 4) % 8)) & 0xF; + tmp |= half_byte << reg_shift; + rtl_ocp_write(tp, reg, tmp); + } + + /* fill CRC reg */ + if (idx < 8) + reg = 0xC020 + (idx * 2); + else + reg = 0xC100 + ((idx - 8) * 2); + rtl_ocp_write(tp, reg, tp->wol_rule[idx].crc); + + /* fill start byte and exactly match pattern */ + memset(temp_pattern, 0, sizeof(temp_pattern)); + ptr = (u16 *)&temp_pattern[0]; + *ptr = tp->wol_rule[idx].offset & 0x7F8; /* 8 alignment */ + + for (i = 0; i < tp->wol_rule[idx].pattern_size; i++) + temp_pattern[i + 2] = tp->wol_rule[idx].pattern[i]; + + for (i = 0; i < (RTL_WAKE_PATTERN_SIZE + 2) / 2; i++) { + reg = 0x6A00 + (idx * 138) + (i * 2); + ptr = (u16 *)&temp_pattern[i * 2]; + rtl_ocp_write(tp, reg, *ptr); + } +} + +static void rtl_mdns_pat_wakeup(struct rtl8169_private *tp) +{ + int i; + + for (i = 0; i < RTL_WAKE_SIZE; i++) + if (tp->wol_rule[i].flag & WAKE_FLAG_ENABLE) + rtl_write_pat_wakeup_pattern(tp, i); +} + +static void rtl_clear_pat_wakeup_pattern(struct rtl8169_private *tp) +{ + rtl_ocp_write(tp, 0xC140, 0xFFFF); + rtl_ocp_write(tp, 0xC142, 0xFFFF); +} + +static void rtl_pat_wakeup_set(struct rtl8169_private *tp, bool enable) +{ + u16 tmp; + + rtl_clear_pat_wakeup_pattern(tp); + if (tp->wol_crc_cnt > 0 && (tp->wol_enable & WOL_CRC_MATCH)) { + if (enable) { + rtl_mdns_pat_wakeup(tp); + + tmp = rtl_ocp_read(tp, 0xE8DE); + tmp |= BIT(14); /* borrow 8K SRAM */ + rtl_ocp_write(tp, 0xE8DE, tmp); + + tmp = rtl_ocp_read(tp, 0xC0C2); + tmp |= BIT(3); /* enable wol exactly pattern match */ + rtl_ocp_write(tp, 0xC0C2, tmp); + } else { + tmp = rtl_ocp_read(tp, 0xC0C2); + tmp &= ~BIT(3); /* disable wol exactly pattern match */ + rtl_ocp_write(tp, 0xC0C2, tmp); + + tmp = rtl_ocp_read(tp, 0xE8DE); + tmp &= ~BIT(14); /* stop borrow 8K SRAM */ + rtl_ocp_write(tp, 0xE8DE, tmp); + } + } +} + +/* CRC WAKE UP */ +static void rtl_write_crc_wakeup_pattern(struct rtl8169_private *tp, u32 idx) +{ + u8 i; + u8 j; + u32 reg_mask; + u32 reg_shift; + u32 reg_offset; + + reg_offset = idx & ~(BIT(0) | BIT(1)); + reg_shift = (idx % 4) * 8; + switch (reg_shift) { + case 0: + reg_mask = ERIAR_MASK_0001; + break; + case 8: + reg_mask = ERIAR_MASK_0010; + break; + case 16: + reg_mask = ERIAR_MASK_0100; + break; + case 24: + reg_mask = ERIAR_MASK_1000; + break; + default: + pr_err(PFX "Invalid shift bit 0x%x, idx = %d\n", reg_shift, idx); + return; + } + + for (i = 0, j = 0; i < 0x80; i += 8, j++) { + rtl_eri_write(tp, i + reg_offset, reg_mask, + tp->wol_rule[idx].mask[j] << reg_shift, ERIAR_EXGMAC); + } + + reg_offset = idx * 2; + if (idx % 2) { + reg_mask = ERIAR_MASK_1100; + reg_offset -= 2; + reg_shift = 16; + } else { + reg_mask = ERIAR_MASK_0011; + reg_shift = 0; + } + rtl_eri_write(tp, (int)(0x80 + reg_offset), reg_mask, + tp->wol_rule[idx].crc << reg_shift, ERIAR_EXGMAC); +} + +static void rtl_mdns_crc_wakeup(struct rtl8169_private *tp) +{ + int i; + + for (i = 0; i < RTL_WAKE_SIZE_CRC; i++) + if (tp->wol_rule[i].flag & WAKE_FLAG_ENABLE) + rtl_write_crc_wakeup_pattern(tp, i); +} + +static void rtl_clear_crc_wakeup_pattern(struct rtl8169_private *tp) +{ + u8 i; + + for (i = 0; i < 0x80; i += 4) + rtl_eri_write(tp, i, ERIAR_MASK_1111, 0x0, ERIAR_EXGMAC); + + for (i = 0x80; i < 0x90; i += 4) + rtl_eri_write(tp, i, ERIAR_MASK_1111, 0x0, ERIAR_EXGMAC); +} + +static void rtl_crc_wakeup_set(struct rtl8169_private *tp, bool enable) +{ + rtl_clear_crc_wakeup_pattern(tp); + if (tp->wol_crc_cnt > 0 && (tp->wol_enable & WOL_CRC_MATCH) && enable) + rtl_mdns_crc_wakeup(tp); +} + +static void rtl_speed_down(struct rtl8169_private *tp) +{ + u32 adv; + int lpa; + + lpa = rtl_phy_read(tp, 0, MII_LPA); + + if (lpa & (LPA_10HALF | LPA_10FULL)) + adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full; + else if (lpa & (LPA_100HALF | LPA_100FULL)) + adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; + else + adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + (tp->mii.supports_gmii ? + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full : 0); + + rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, + adv); +} + +static void rtl_wol_suspend_quirk(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W32(RX_CONFIG, RTL_R32(RX_CONFIG) | + ACCEPT_BROADCAST | ACCEPT_MULTICAST | ACCEPT_MY_PHYS); +} + +static bool rtl_wol_pll_power_down(struct rtl8169_private *tp) +{ + if (!(__rtl8169_get_wol(tp) & WAKE_ANY)) + return false; + + rtl_speed_down(tp); + rtl_wol_suspend_quirk(tp); + + return true; +} + +static void r8168_phy_power_up(struct rtl8169_private *tp) +{ + rtl_phy_write(tp, 0, MII_BMCR, BMCR_ANENABLE); +} + +static void r8168_phy_power_down(struct rtl8169_private *tp) +{ + rtl_phy_write(tp, 0, MII_BMCR, BMCR_PDOWN); +} + +static void r8168_pll_power_down(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W8(CFG9346, CFG9346_UNLOCK); + if (tp->wol_enable & WOL_MAGIC) { + /* enable now_is_oob */ + RTL_W8(MCU, RTL_R8(MCU) | NOW_IS_OOB); + RTL_W8(CONFIG5, RTL_R8(CONFIG5) | LAN_WAKE); + RTL_W8(CONFIG3, RTL_R8(CONFIG3) | MAGIC_PKT); + + tp->chip->wakeup_set(tp, true); + if (tp->wol_enable & WOL_WPD) + rtl_wpd_set(tp); + } else { + RTL_W8(CONFIG5, RTL_R8(CONFIG5) & ~LAN_WAKE); + RTL_W8(CONFIG3, RTL_R8(CONFIG3) & ~MAGIC_PKT); + } + RTL_W8(CFG9346, CFG9346_LOCK); + + if (rtl_wol_pll_power_down(tp)) + return; + + r8168_phy_power_down(tp); +} + +static void r8168_pll_power_up(struct rtl8169_private *tp) +{ + r8168_phy_power_up(tp); +} + +static inline void rtl_generic_op(struct rtl8169_private *tp, + void (*op)(struct rtl8169_private *)) +{ + if (op) + op(tp); +} + +static inline void rtl_pll_power_down(struct rtl8169_private *tp) +{ + rtl_generic_op(tp, tp->chip->pll_power_down); +} + +static inline void rtl_pll_power_up(struct rtl8169_private *tp) +{ + rtl_generic_op(tp, tp->chip->pll_power_up); +} + +static void rtl_init_rxcfg(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* disable RX128_INT_EN to reduce CPU loading */ + RTL_W32(RX_CONFIG, RX_DMA_BURST | RX_EARLY_OFF); +} + +static void rtl8169_init_ring_indexes(struct rtl8169_private *tp) +{ + tp->dirty_tx = 0; + tp->cur_tx = 0; + tp->cur_rx = 0; + +#if defined(CONFIG_RTL_RX_NO_COPY) + tp->dirty_rx = 0; +#endif /* CONFIG_RTL_RX_NO_COPY */ +} + +DECLARE_RTL_COND(rtl_chipcmd_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R8(CHIP_CMD) & CMD_RESET; +} + +static void rtl_hw_reset(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W8(CHIP_CMD, CMD_RESET); + + rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); +} + +static void rtl_rx_close(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W32(RX_CONFIG, RTL_R32(RX_CONFIG) & ~RX_CONFIG_ACCEPT_MASK); +} + +DECLARE_RTL_COND(rtl_txcfg_empty_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(TX_CONFIG) & TXCFG_EMPTY; +} + +static void rtl8169_hw_reset(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* Disable interrupts */ + rtl8169_irq_mask_and_ack(tp); + + rtl_rx_close(tp); + + RTL_W8(CHIP_CMD, RTL_R8(CHIP_CMD) | STOP_REQ); + rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); + + rtl_hw_reset(tp); + + if (tp->chip->features & RTL_FEATURE_TX_NO_CLOSE) { + /* disable tx no close mode */ + rtl_ocp_write(tp, 0xE610, + rtl_ocp_read(tp, 0xE610) & ~(BIT(4) | BIT(6))); + }; +} + +static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32(TX_CONFIG, (TX_DMA_BURST << TX_DMA_SHIFT) | + (INTER_FRAME_GAP << TX_INTER_FRAME_GAP_SHIFT)); +} + +static void rtl_hw_start(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + tp->chip->hw_start(dev); + + rtl_irq_enable_all(tp); +} + +static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + /* Magic spell: some iop3xx ARM board needs the TxDescAddrHigh + * register to be written before TxDescAddrLow to work. + * Switching from MMIO to I/O access fixes the issue as well. + */ + RTL_W32(TX_DESC_START_ADDR_HIGH, ((u64)tp->tx_phy_addr) >> 32); + RTL_W32(TX_DESC_START_ADDR_LOW, + ((u64)tp->tx_phy_addr) & DMA_BIT_MASK(32)); + RTL_W32(RX_DESC_ADDR_HIGH, ((u64)tp->rx_phy_addr) >> 32); + RTL_W32(RX_DESC_ADDR_LOW, ((u64)tp->rx_phy_addr) & DMA_BIT_MASK(32)); +} + +static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz) +{ + /* Low hurts. Let's disable the filtering. */ + RTL_W16(RX_MAX_SIZE, rx_buf_sz); +} + +static void rtl_set_rx_mode(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u32 mc_filter[2]; /* Multicast hash filter */ + int rx_mode; + u32 tmp = 0; + u32 data; + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + netif_notice(tp, link, dev, "Promiscuous mode enabled\n"); + rx_mode = + ACCEPT_BROADCAST | ACCEPT_MULTICAST | ACCEPT_MY_PHYS | + ACCEPT_ALL_PHYS; + mc_filter[1] = 0xffffffff; + mc_filter[0] = 0xffffffff; + } else if ((netdev_mc_count(dev) > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + rx_mode = ACCEPT_BROADCAST | ACCEPT_MULTICAST | ACCEPT_MY_PHYS; + mc_filter[1] = 0xffffffff; + mc_filter[0] = 0xffffffff; + } else { + struct netdev_hw_addr *ha; + + rx_mode = ACCEPT_BROADCAST | ACCEPT_MY_PHYS; + mc_filter[1] = 0; + mc_filter[0] = 0; + netdev_for_each_mc_addr(ha, dev) { + int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; + + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + rx_mode |= ACCEPT_MULTICAST; + } + } + + if (dev->features & NETIF_F_RXALL) + rx_mode |= (ACCEPT_ERR | ACCEPT_RUNT); + + tmp = (RTL_R32(RX_CONFIG) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode; + + data = mc_filter[0]; + + mc_filter[0] = swab32(mc_filter[1]); + mc_filter[1] = swab32(data); + + RTL_W32(MAR0 + 4, mc_filter[1]); + RTL_W32(MAR0 + 0, mc_filter[0]); + + RTL_W32(RX_CONFIG, tmp); +} + +static inline void rtl_csi_write(struct rtl8169_private *tp, int addr, + int value) +{ + tp->chip->csi_write(tp, addr, value); +} + +static inline u32 rtl_csi_read(struct rtl8169_private *tp, int addr) +{ + return tp->chip->csi_read(tp, addr); +} + +static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits) +{ + u32 csi; + + csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff; + rtl_csi_write(tp, 0x070c, csi | bits); +} + +static void rtl_csi_access_enable_1(struct rtl8169_private *tp) +{ + rtl_csi_access_enable(tp, 0x17000000); +} + +DECLARE_RTL_COND(rtl_csiar_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(CSIAR) & CSIAR_FLAG; +} + +static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100); +} + +static u32 r8169_csi_read(struct rtl8169_private *tp, int addr) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ? + RTL_R32(CSIDR) : ~0; +} + +static void rtl_led_set(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* LED setting */ + if (tp->led_cfg) + RTL_W32(LEDSEL, 0x00060000 | tp->led_cfg); + else + RTL_W32(LEDSEL, tp->chip->led_cfg); +} + +static void rtl_hw_start_8168g_1(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W32(TX_CONFIG, RTL_R32(TX_CONFIG) | TXCFG_AUTO_FIFO); + + rtl_csi_access_enable_1(tp); + + rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); + rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); + rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f, ERIAR_EXGMAC); + + RTL_W8(CHIP_CMD, CMD_TX_ENB | CMD_RX_ENB); + RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN); + RTL_W8(MAX_TX_PACKET_SIZE, EARLY_SIZE); + + rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); + rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); + + /* Adjust EEE LED frequency */ + RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07); + + rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x06, ERIAR_EXGMAC); + rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC); +} + +static void rtl_hw_start_8168g_2(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + rtl_hw_start_8168g_1(tp); + + rtl_led_set(tp); + + /* disable aspm and clock request before access ephy */ + RTL_W8(CONFIG2, RTL_R8(CONFIG2) & ~CLK_REQ_EN); + RTL_W8(CONFIG5, RTL_R8(CONFIG5) & ~ASPM_EN); +} + +static void rtl_hw_start_8168(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u32 tmp; + u32 phy_status; + const struct soc_device_attribute rtk_soc_rtd161x_a01[] = { + { + .family = "Realtek Thor", + .revision = "A01", + }, + { + /* empty */ + } + }; + const struct soc_device_attribute rtk_soc_rtd131x[] = { + { + .family = "Realtek Hank", + }, + { + /* empty */ + } + }; + + RTL_W8(CFG9346, CFG9346_UNLOCK); + + RTL_W8(MAX_TX_PACKET_SIZE, TX_PACKET_MAX); + + rtl_set_rx_max_size(ioaddr, rx_buf_sz); + +#if defined(CONFIG_RTL_RX_NO_COPY) + tp->cp_cmd |= RTL_R16(C_PLUS_CMD) | PKT_CNTR_DISABLE | INTT_3; +#else + tp->cp_cmd |= RTL_R16(C_PLUS_CMD) | PKT_CNTR_DISABLE | INTT_1; +#endif /* CONFIG_RTL_RX_NO_COPY */ + /* Disable VLAN De-tagging */ + tp->cp_cmd &= ~RX_VLAN; + + RTL_W16(C_PLUS_CMD, tp->cp_cmd); + +#if defined(MY_DEF_HERE) + RTL_W16(INTR_MITIGATE, 0x1111); +#else /* MY_DEF_HERE */ + RTL_W16(INTR_MITIGATE, 0x5151); +#endif /* MY_DEF_HERE */ + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + rtl_set_rx_tx_config_registers(tp); + + if (tp->chip->features & RTL_FEATURE_TX_NO_CLOSE) { + /* enable tx no close mode */ + rtl_ocp_write(tp, 0xE610, + rtl_ocp_read(tp, 0xE610) | (BIT(4) | BIT(6))); + } + + /* disable pause frame resend caused by nearfull for rtd161x A01 */ + if (soc_device_match(rtk_soc_rtd161x_a01)) + rtl_ocp_write(tp, 0xE862, rtl_ocp_read(tp, 0xE862) | BIT(0)); + + tp->event_slow &= ~RX_OVERFLOW; + + if (tp->chip->features & RTL_FEATURE_ADJUST_FIFO) { + /* TX FIFO threshold */ + rtl_ocp_write(tp, 0xE618, 0x0006); + rtl_ocp_write(tp, 0xE61A, 0x0010); + + /* RX FIFO threshold */ + rtl_ocp_write(tp, 0xC0A0, 0x0002); + rtl_ocp_write(tp, 0xC0A2, 0x0008); + + phy_status = rtl_ocp_read(tp, 0xde40); + if ((phy_status & 0x0030) == 0x0020) { + /* 1000 Mbps */ + rtl_ocp_write(tp, 0xC0A4, 0x0088); + rtl_ocp_write(tp, 0xC0A8, 0x00A8); + } else { + /* 10/100 Mbps */ + rtl_ocp_write(tp, 0xC0A4, 0x0038); + rtl_ocp_write(tp, 0xC0A8, 0x0048); + } + } else { + /* TX FIFO threshold */ + rtl_ocp_write(tp, 0xE618, 0x0006); + rtl_ocp_write(tp, 0xE61A, 0x0010); + + /* RX FIFO threshold */ + rtl_ocp_write(tp, 0xC0A0, 0x0002); + rtl_ocp_write(tp, 0xC0A2, 0x0008); + rtl_ocp_write(tp, 0xC0A4, 0x0038); + rtl_ocp_write(tp, 0xC0A8, 0x0048); + } + + tp->chip->wakeup_set(tp, false); + RTL_W8(CONFIG5, RTL_R8(CONFIG5) & ~LAN_WAKE); + RTL_W8(CONFIG3, RTL_R8(CONFIG3) & ~MAGIC_PKT); + + RTL_R8(INTR_MASK); + + rtl_hw_start_8168g_2(tp); + + RTL_W8(CFG9346, CFG9346_LOCK); + + RTL_W8(CHIP_CMD, CMD_TX_ENB | CMD_RX_ENB); + + if (soc_device_match(rtk_soc_rtd131x)) { + phy_status = rtl_ocp_read(tp, 0xde40); + switch (tp->output_mode) { + case OUTPUT_EMBEDDED_PHY: + /* do nothing */ + break; + case OUTPUT_RMII: + /* adjust RMII interface setting, speed */ + tmp = rtl_ocp_read(tp, 0xea30) & ~(BIT(6) | BIT(5)); + switch (phy_status & 0x0030) { /* link speed */ + case 0x0000: + /* 10M, RGMII clock speed = 2.5MHz */ + break; + case 0x0010: + /* 100M, RGMII clock speed = 25MHz */ + tmp |= BIT(5); + } + /* adjust RGMII interface setting, duplex */ + if ((phy_status & BIT(3)) == 0) + /* ETN spec, half duplex */ + tmp &= ~BIT(4); + else /* ETN spec, full duplex */ + tmp |= BIT(4); + rtl_ocp_write(tp, 0xea30, tmp); + break; + case OUTPUT_RGMII_TO_MAC: + case OUTPUT_RGMII_TO_PHY: + /* adjust RGMII interface setting, duplex */ + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(4) | BIT(3)); + switch (phy_status & 0x0030) { /* link speed */ + case 0x0000: + /* 10M, RGMII clock speed = 2.5MHz */ + break; + case 0x0010: + /* 100M, RGMII clock speed = 25MHz */ + tmp |= BIT(3); + break; + case 0x0020: + /* 1000M, RGMII clock speed = 125MHz */ + tmp |= BIT(4); + break; + } + /* adjust RGMII interface setting, duplex */ + if ((phy_status & BIT(3)) == 0) + /* ETN spec, half duplex */ + tmp &= ~BIT(2); + else /* ETN spec, full duplex */ + tmp |= BIT(2); + rtl_ocp_write(tp, 0xea34, tmp); + break; + default: + pr_err(PFX "invalid output mode %d\n", tp->output_mode); + return; + } + } + + rtl_set_rx_mode(dev); + + RTL_W16(MULTI_INTR, RTL_R16(MULTI_INTR) & 0xF000); +} + +static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) +{ +#if defined(CONFIG_RTL_RX_NO_COPY) + struct rtl8169_private *tp = netdev_priv(dev); + + if (!netif_running(dev)) { + rx_buf_sz_new = (new_mtu > ETH_DATA_LEN) ? + new_mtu + ETH_HLEN + 8 + 1 : RX_BUF_SIZE; + rx_buf_sz = rx_buf_sz_new; + goto out; + } + + rx_buf_sz_new = (new_mtu > ETH_DATA_LEN) ? + new_mtu + ETH_HLEN + 8 + 1 : RX_BUF_SIZE; + + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); + +out: +#endif /* CONFIG_RTL_RX_NO_COPY */ + + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static inline void rtl8169_make_unusable_by_asic(struct rx_desc *desc) +{ + desc->addr = cpu_to_le64(0x0badbadbadbadbadull); + desc->opts1 &= ~cpu_to_le32(DESC_OWN | RSVD_MASK); +} + +#if defined(CONFIG_RTL_RX_NO_COPY) +static void rtl8169_free_rx_databuff(struct rtl8169_private *tp, + struct sk_buff **data_buff, + struct rx_desc *desc) +{ + if (!tp->acp_enable) + dma_unmap_single(&tp->pdev->dev, le64_to_cpu(desc->addr), + rx_buf_sz, DMA_FROM_DEVICE); + + dev_kfree_skb(*data_buff); + *data_buff = NULL; + rtl8169_make_unusable_by_asic(desc); +} +#else +static void rtl8169_free_rx_databuff(struct rtl8169_private *tp, + void **data_buff, struct rx_desc *desc) +{ + if (!tp->acp_enable) + dma_unmap_single(&tp->pdev->dev, le64_to_cpu(desc->addr), + rx_buf_sz, DMA_FROM_DEVICE); + + kfree(*data_buff); + *data_buff = NULL; + rtl8169_make_unusable_by_asic(desc); +} +#endif /* CONFIG_RTL_RX_NO_COPY */ + +static inline void rtl8169_mark_to_asic(struct rx_desc *desc, u32 rx_buf_sz) +{ + u32 eor = le32_to_cpu(desc->opts1) & RING_END; + + desc->opts1 = cpu_to_le32(DESC_OWN | eor | rx_buf_sz); +} + +static inline void rtl8169_map_to_asic(struct rx_desc *desc, dma_addr_t mapping, + u32 rx_buf_sz) +{ + desc->addr = cpu_to_le64(mapping); + wmb(); /* make sure this RX descriptor is ready */ + rtl8169_mark_to_asic(desc, rx_buf_sz); +} + +static inline void *rtl8169_align(void *data) +{ + return (void *)ALIGN((long)data, 16); +} + +#if defined(CONFIG_RTL_RX_NO_COPY) +static int +rtl8168_alloc_rx_skb(struct rtl8169_private *tp, struct sk_buff **sk_buff, + struct rx_desc *desc, int rx_buf_sz) +{ + struct device *d = &tp->pdev->dev; + struct sk_buff *skb; + dma_addr_t mapping; + int ret = 0; + + skb = dev_alloc_skb(rx_buf_sz + RTK_RX_ALIGN); + if (!skb) + goto err_out; + + skb_reserve(skb, RTK_RX_ALIGN); + + if (tp->acp_enable) { + mapping = virt_to_phys(skb->data); + } else { + mapping = dma_map_single(d, skb->data, rx_buf_sz, + DMA_FROM_DEVICE); + + if (unlikely(dma_mapping_error(d, mapping))) { + if (unlikely(net_ratelimit())) + netif_err(tp, drv, tp->dev, + "Failed to map RX DMA!\n"); + goto err_out; + } + } + *sk_buff = skb; + rtl8169_map_to_asic(desc, mapping, rx_buf_sz); + +out: + return ret; + +err_out: + if (skb) + dev_kfree_skb(skb); + ret = -ENOMEM; + rtl8169_make_unusable_by_asic(desc); + goto out; +} +#else +static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp, + struct rx_desc *desc) +{ + void *data; + dma_addr_t mapping; + struct device *d = &tp->pdev->dev; + struct net_device *dev = tp->dev; + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; + + data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node); + if (!data) + return NULL; + + if (rtl8169_align(data) != data) { + kfree(data); + data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node); + if (!data) + return NULL; + } + + if (tp->acp_enable) { + mapping = virt_to_phys(rtl8169_align(data)); + } else { + mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(d, mapping))) { + if (net_ratelimit()) + netif_err(tp, drv, tp->dev, + "Failed to map RX DMA!\n"); + goto err_out; + } + } + + rtl8169_map_to_asic(desc, mapping, rx_buf_sz); + return data; + +err_out: + kfree(data); + return NULL; +} +#endif /* CONFIG_RTL_RX_NO_COPY */ + +static void rtl8169_rx_clear(struct rtl8169_private *tp) +{ + unsigned int i; + + for (i = 0; i < NUM_RX_DESC; i++) { + if (tp->rx_databuff[i]) { + rtl8169_free_rx_databuff(tp, tp->rx_databuff + i, + tp->rx_desc_array + i); + } + } +} + +static inline void rtl8169_mark_as_last_descriptor(struct rx_desc *desc) +{ + desc->opts1 |= cpu_to_le32(RING_END); +} + +#if defined(CONFIG_RTL_RX_NO_COPY) +static u32 +rtl8168_rx_fill(struct rtl8169_private *tp, + struct net_device *dev, u32 start, u32 end) +{ + u32 cur; + + for (cur = start; end - cur > 0; cur++) { + int ret, i = cur % NUM_RX_DESC; + + if (tp->rx_databuff[i]) + continue; + ret = rtl8168_alloc_rx_skb(tp, tp->rx_databuff + i, + tp->rx_desc_array + i, rx_buf_sz); + if (ret < 0) + break; + if (i == (NUM_RX_DESC - 1)) + rtl8169_mark_as_last_descriptor(tp->rx_desc_array + + NUM_RX_DESC - 1); + } + return cur - start; +} +#else +static int rtl8169_rx_fill(struct rtl8169_private *tp) +{ + unsigned int i; + + for (i = 0; i < NUM_RX_DESC; i++) { + void *data; + + if (tp->rx_databuff[i]) + continue; + + data = rtl8169_alloc_rx_data(tp, tp->rx_desc_array + i); + if (!data) { + rtl8169_make_unusable_by_asic(tp->rx_desc_array + i); + goto err_out; + } + tp->rx_databuff[i] = data; + } + + rtl8169_mark_as_last_descriptor(tp->rx_desc_array + NUM_RX_DESC - 1); + return 0; + +err_out: + rtl8169_rx_clear(tp); + return -ENOMEM; +} +#endif /* CONFIG_RTL_RX_NO_COPY */ + +static int rtl8169_init_ring(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + rtl8169_init_ring_indexes(tp); + + memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info)); + memset(tp->rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *)); + +#if defined(CONFIG_RTL_RX_NO_COPY) + ret = rtl8168_rx_fill(tp, dev, 0, NUM_RX_DESC); + if (ret < NUM_RX_DESC) + ret = -ENOMEM; + else + ret = 0; +#else + ret = rtl8169_rx_fill(tp); +#endif /* CONFIG_RTL_RX_NO_COPY */ + + return ret; +} + +static void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, struct device *d, + struct ring_info *tx_skb, struct tx_desc *desc) +{ + unsigned int len = tx_skb->len; + + if (!tp->acp_enable) + dma_unmap_single(d, le64_to_cpu(desc->addr), len, + DMA_TO_DEVICE); + + desc->opts1 = 0x00; + desc->opts2 = 0x00; + desc->addr = 0x00; + tx_skb->len = 0; +} + +static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start, + unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; i++) { + unsigned int entry = (start + i) % NUM_TX_DESC; + struct ring_info *tx_skb = tp->tx_skb + entry; + unsigned int len = tx_skb->len; + + if (len) { + struct sk_buff *skb = tx_skb->skb; + + rtl8169_unmap_tx_skb(tp, &tp->pdev->dev, tx_skb, + tp->tx_desc_array + entry); + if (skb) { + tp->dev->stats.tx_dropped++; + dev_kfree_skb(skb); + tx_skb->skb = NULL; + } + } + } +} + +static void rtl8169_tx_clear(struct rtl8169_private *tp) +{ + rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC); + tp->cur_tx = 0; + tp->dirty_tx = 0; +} + +static void rtl_reset_work(struct rtl8169_private *tp) +{ + struct net_device *dev = tp->dev; + int i; + + napi_disable(&tp->napi); + netif_stop_queue(dev); + synchronize_rcu(); + + rtl8169_hw_reset(tp); + +#if defined(CONFIG_RTL_RX_NO_COPY) + rtl8169_rx_clear(tp); + rtl8169_tx_clear(tp); + + if (rx_buf_sz_new != rx_buf_sz) + rx_buf_sz = rx_buf_sz_new; + + memset(tp->tx_desc_array, 0x0, NUM_TX_DESC * sizeof(struct tx_desc)); + for (i = 0; i < NUM_TX_DESC; i++) { + if (i == (NUM_TX_DESC - 1)) + tp->tx_desc_array[i].opts1 = cpu_to_le32(RING_END); + } + memset(tp->rx_desc_array, 0x0, NUM_RX_DESC * sizeof(struct rx_desc)); + + if (rtl8169_init_ring(dev) < 0) { + napi_enable(&tp->napi); + netif_wake_queue(dev); + netif_warn(tp, drv, dev, "No memory. Try to restart......\n"); + msleep(1000); + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); + return; + } +#else + for (i = 0; i < NUM_RX_DESC; i++) + rtl8169_mark_to_asic(tp->rx_desc_array + i, rx_buf_sz); + + rtl8169_tx_clear(tp); + rtl8169_init_ring_indexes(tp); +#endif /* CONFIG_RTL_RX_NO_COPY */ + + napi_enable(&tp->napi); + rtl_hw_start(dev); + netif_wake_queue(dev); + rtl8169_check_link_status(dev, tp, tp->mmio_addr); +} + +static void rtl8169_tx_timeout(struct net_device *dev, unsigned int nouse) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); +} + +static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, + u32 *opts) +{ + struct skb_shared_info *info = skb_shinfo(skb); + unsigned int cur_frag, entry; + struct tx_desc *txd = NULL; + struct device *d = &tp->pdev->dev; + + entry = tp->cur_tx; + for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) { + const skb_frag_t *frag = info->frags + cur_frag; + dma_addr_t mapping; + u32 status, len; + void *addr; + + entry = (entry + 1) % NUM_TX_DESC; + + txd = tp->tx_desc_array + entry; + len = skb_frag_size(frag); + addr = skb_frag_address(frag); + if (tp->acp_enable) { + mapping = virt_to_phys(addr); + } else { + mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(d, mapping))) { + if (net_ratelimit()) + netif_err(tp, drv, tp->dev, + "Failed to map TX fragments DMA!\n"); + goto err_out; + } + } + + /* Anti gcc 2.95.3 bugware (sic) */ + status = opts[0] | len | + (RING_END * !((entry + 1) % NUM_TX_DESC)); + + txd->opts1 = cpu_to_le32(status); + txd->opts2 = cpu_to_le32(opts[1]); + txd->addr = cpu_to_le64(mapping); + + tp->tx_skb[entry].len = len; + } + + if (cur_frag) { + tp->tx_skb[entry].skb = skb; + txd->opts1 |= cpu_to_le32(LAST_FRAG); + } + + return cur_frag; + +err_out: + rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag); + return -EIO; +} + +static inline bool rtl8169_tso_csum(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) +{ + const struct rtl_tx_desc_info *info = &tx_desc_info; + u32 mss = skb_shinfo(skb)->gso_size; + int offset = info->opts_offset; + + if (mss) { + opts[0] |= TD_LSO; + opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct iphdr *ip = ip_hdr(skb); + + if (ip->protocol == IPPROTO_TCP) + opts[offset] |= info->checksum.tcp; + else if (ip->protocol == IPPROTO_UDP) + opts[offset] |= info->checksum.udp; + else + WARN_ON_ONCE(1); + } + return true; +} + +static inline bool rtl_tx_slots_avail(struct rtl8169_private *tp, + unsigned int nr_frags) +{ + unsigned int slots_avail = tp->dirty_tx + NUM_TX_DESC - tp->cur_tx; + + /* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */ + return slots_avail > nr_frags; +} + +/* TX w/ own flag */ +static netdev_tx_t rtl_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned int entry = tp->cur_tx % NUM_TX_DESC; + struct tx_desc *txd = tp->tx_desc_array + entry; + void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pdev->dev; + dma_addr_t mapping; + u32 status, len; + u32 opts[2]; + int frags; + + if (unlikely(!rtl_tx_slots_avail(tp, skb_shinfo(skb)->nr_frags))) { + netif_err(tp, drv, dev, + "BUG! Tx Ring full when queue awake!\n"); + goto err_stop_0; + } + if (unlikely(le32_to_cpu(txd->opts1) & DESC_OWN)) + goto err_stop_0; + + opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); + opts[0] = DESC_OWN; + + if (!rtl8169_tso_csum(tp, skb, opts)) + goto err_update_stats; + + len = skb_headlen(skb); + if (tp->acp_enable) { + mapping = virt_to_phys(skb->data); + } else { + mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(d, mapping))) { + if (net_ratelimit()) + netif_err(tp, drv, dev, + "Failed to map TX DMA!\n"); + goto err_dma_0; + } + } + + tp->tx_skb[entry].len = len; + txd->addr = cpu_to_le64(mapping); + + frags = rtl8169_xmit_frags(tp, skb, opts); + if (frags < 0) { + goto err_dma_1; + } else if (frags) { + opts[0] |= FIRST_FRAG; + } else { + opts[0] |= FIRST_FRAG | LAST_FRAG; + tp->tx_skb[entry].skb = skb; + } + + txd->opts2 = cpu_to_le32(opts[1]); + + skb_tx_timestamp(skb); + + wmb(); /* make sure txd->addr and txd->opts2 is ready */ + + /* Anti gcc 2.95.3 bugware (sic) */ + status = opts[0] | len | (RING_END * !((entry + 1) % NUM_TX_DESC)); + txd->opts1 = cpu_to_le32(status); + + tp->cur_tx += frags + 1; + + wmb(); /* make sure this TX descriptor is ready */ + + RTL_W8(TX_POLL, NPQ); + + if (!rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) { + /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must + * not miss a ring update when it notices a stopped queue. + */ + smp_wmb(); + netif_stop_queue(dev); + /* Sync with rtl_tx: + * - publish queue status and cur_tx ring index (write barrier) + * - refresh dirty_tx ring index (read barrier). + * May the current thread have a pessimistic view of the ring + * status and forget to wake up queue, a racing rtl_tx thread + * can't. + */ + smp_mb(); + if (rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) + netif_wake_queue(dev); + } + + return NETDEV_TX_OK; + +err_dma_1: + rtl8169_unmap_tx_skb(tp, d, tp->tx_skb + entry, txd); +err_dma_0: + dev_kfree_skb(skb); +err_update_stats: + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + +err_stop_0: + netif_stop_queue(dev); + dev->stats.tx_dropped++; + return NETDEV_TX_BUSY; +} + +static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) +{ + unsigned int dirty_tx, tx_left; + + dirty_tx = tp->dirty_tx; + smp_rmb(); /* make sure dirty_tx is updated */ + tx_left = tp->cur_tx - dirty_tx; + + while (tx_left > 0) { + unsigned int entry = dirty_tx % NUM_TX_DESC; + struct ring_info *tx_skb = tp->tx_skb + entry; + u32 status; + + rmb(); /* make sure this TX descriptor is ready */ + status = le32_to_cpu(tp->tx_desc_array[entry].opts1); + if (status & DESC_OWN) + break; + + rtl8169_unmap_tx_skb(tp, &tp->pdev->dev, tx_skb, + tp->tx_desc_array + entry); + if (status & LAST_FRAG) { + u64_stats_update_begin(&tp->tx_stats.syncp); + tp->tx_stats.packets++; + tp->tx_stats.bytes += tx_skb->skb->len; + u64_stats_update_end(&tp->tx_stats.syncp); + dev_kfree_skb(tx_skb->skb); + tx_skb->skb = NULL; + } + dirty_tx++; + tx_left--; + } + + if (tp->dirty_tx != dirty_tx) { + tp->dirty_tx = dirty_tx; + /* Sync with rtl_start_xmit: + * - publish dirty_tx ring index (write barrier) + * - refresh cur_tx ring index and queue status (read barrier) + * May the current thread miss the stopped queue condition, + * a racing xmit thread can only have a right view of the + * ring status. + */ + smp_mb(); + if (netif_queue_stopped(dev) && + rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) { + netif_wake_queue(dev); + } + /* 8168 hack: TX_POLL requests are lost when the Tx packets are + * too close. Let's kick an extra TX_POLL request when a burst + * of start_xmit activity is detected (if it is not detected, + * it is slow enough). -- FR + */ + if (tp->cur_tx != dirty_tx) { + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W8(TX_POLL, NPQ); + } + } +} + +/* TX w/o own flag; + * start of RTL_FEATURE_TX_NO_CLOSE + */ +static netdev_tx_t rtl_start_xmit_no_close(struct sk_buff *skb, + struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned int entry = tp->cur_tx % NUM_TX_DESC; + struct tx_desc *txd = tp->tx_desc_array + entry; + void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pdev->dev; + dma_addr_t mapping; + u32 status, len; + u32 opts[2]; + int frags; + u16 close_idx; + u16 tail_idx; + + if (unlikely(!rtl_tx_slots_avail(tp, skb_shinfo(skb)->nr_frags))) { + netif_err(tp, drv, dev, + "BUG! Tx Ring full when queue awake!\n"); + goto err_stop_0; + } + + close_idx = RTL_R16(TX_DESC_CLOSE_IDX) & TX_DESC_CNT_MASK; + tail_idx = tp->cur_tx & TX_DESC_CNT_MASK; + if ((tail_idx > close_idx && (tail_idx - close_idx == NUM_TX_DESC)) || + (tail_idx < close_idx && + (TX_DESC_CNT_SIZE - close_idx + tail_idx == NUM_TX_DESC))) + goto err_stop_0; + + opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); + opts[0] = DESC_OWN; + + if (!rtl8169_tso_csum(tp, skb, opts)) + goto err_update_stats; + + len = skb_headlen(skb); + if (tp->acp_enable) { + mapping = virt_to_phys(skb->data); + } else { + mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(d, mapping))) { + if (net_ratelimit()) + netif_err(tp, drv, dev, + "Failed to map TX DMA!\n"); + goto err_dma_0; + } + } + + tp->tx_skb[entry].len = len; + txd->addr = cpu_to_le64(mapping); + + frags = rtl8169_xmit_frags(tp, skb, opts); + if (frags < 0) { + goto err_dma_1; + } else if (frags) { + opts[0] |= FIRST_FRAG; + } else { + opts[0] |= FIRST_FRAG | LAST_FRAG; + tp->tx_skb[entry].skb = skb; + } + + txd->opts2 = cpu_to_le32(opts[1]); + + skb_tx_timestamp(skb); + + wmb(); /* make sure txd->addr and txd->opts2 is ready */ + + /* Anti gcc 2.95.3 bugware (sic) */ + status = opts[0] | len | (RING_END * !((entry + 1) % NUM_TX_DESC)); + txd->opts1 = cpu_to_le32(status); + + tp->cur_tx += frags + 1; + + RTL_W16(TX_DESC_TAIL_IDX, tp->cur_tx & TX_DESC_CNT_MASK); + + wmb(); /* make sure this TX descriptor is ready */ + + RTL_W8(TX_POLL, NPQ); + + if (!rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) { + /* Avoid wrongly optimistic queue wake-up: + * rtl_tx_no_close thread must + * not miss a ring update when it notices a stopped queue. + */ + smp_wmb(); + netif_stop_queue(dev); + /* Sync with rtl_tx_no_close: + * - publish queue status and cur_tx ring index (write barrier) + * - refresh dirty_tx ring index (read barrier). + * May the current thread have a pessimistic view of the ring + * status and forget to wake up queue, a racing rtl_tx thread + * can't. + */ + smp_mb(); + if (rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) + netif_wake_queue(dev); + } + + return NETDEV_TX_OK; + +err_dma_1: + rtl8169_unmap_tx_skb(tp, d, tp->tx_skb + entry, txd); +err_dma_0: + dev_kfree_skb(skb); +err_update_stats: + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + +err_stop_0: + netif_stop_queue(dev); + dev->stats.tx_dropped++; + return NETDEV_TX_BUSY; +} + +static void rtl_tx_no_close(struct net_device *dev, struct rtl8169_private *tp) +{ + unsigned int dirty_tx, tx_left; + u16 close_idx; + u16 dirty_tx_idx; + void __iomem *ioaddr = tp->mmio_addr; + + dirty_tx = tp->dirty_tx; + close_idx = RTL_R16(TX_DESC_CLOSE_IDX) & TX_DESC_CNT_MASK; + dirty_tx_idx = dirty_tx & TX_DESC_CNT_MASK; + smp_rmb(); /* make sure dirty_tx and close_idx are updated */ + + if (dirty_tx_idx <= close_idx) + tx_left = close_idx - dirty_tx_idx; + else + tx_left = close_idx + TX_DESC_CNT_SIZE - dirty_tx_idx; + + while (tx_left > 0) { + unsigned int entry = dirty_tx % NUM_TX_DESC; + struct ring_info *tx_skb = tp->tx_skb + entry; + u32 status; + + rmb(); /* make sure this TX descriptor is ready */ + status = le32_to_cpu(tp->tx_desc_array[entry].opts1); + + rtl8169_unmap_tx_skb(tp, &tp->pdev->dev, tx_skb, + tp->tx_desc_array + entry); + if (status & LAST_FRAG) { + u64_stats_update_begin(&tp->tx_stats.syncp); + tp->tx_stats.packets++; + tp->tx_stats.bytes += tx_skb->skb->len; + u64_stats_update_end(&tp->tx_stats.syncp); + dev_kfree_skb(tx_skb->skb); + tx_skb->skb = NULL; + } + dirty_tx++; + tx_left--; + } + + if (tp->dirty_tx != dirty_tx) { + tp->dirty_tx = dirty_tx; + /* Sync with rtl_start_xmit_no_close: + * - publish dirty_tx ring index (write barrier) + * - refresh cur_tx ring index and queue status (read barrier) + * May the current thread miss the stopped queue condition, + * a racing xmit thread can only have a right view of the + * ring status. + */ + smp_mb(); + if (netif_queue_stopped(dev) && + rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) { + netif_wake_queue(dev); + } + /* 8168 hack: TX_POLL requests are lost when the Tx packets are + * too close. Let's kick an extra TX_POLL request when a burst + * of start_xmit activity is detected (if it is not detected, + * it is slow enough). -- FR + */ + if (tp->cur_tx != dirty_tx) { + void __iomem *ioaddr = tp->mmio_addr; + + RTL_W8(TX_POLL, NPQ); + } + } +} + +/* end of RTL_FEATURE_TX_NO_CLOSE */ + +static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (tp->chip->features & RTL_FEATURE_TX_NO_CLOSE) + return rtl_start_xmit_no_close(skb, dev); + else + return rtl_start_xmit(skb, dev); +} + +static inline int rtl8169_fragmented_frame(u32 status) +{ + return (status & (FIRST_FRAG | LAST_FRAG)) != (FIRST_FRAG | LAST_FRAG); +} + +static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1) +{ + u32 status = opts1 & RX_PROTO_MASK; + + if ((status == RX_PROTO_TCP && !(opts1 & TCP_FAIL)) || + (status == RX_PROTO_UDP && !(opts1 & UDP_FAIL))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb_checksum_none_assert(skb); +} + +#if defined(CONFIG_RTL_RX_NO_COPY) +static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, + u32 budget) +{ + unsigned int cur_rx, rx_left; + unsigned int count, delta; + struct device *d = &tp->pdev->dev; + + cur_rx = tp->cur_rx; + + rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; + rx_left = min(budget, rx_left); + + for (; rx_left > 0; rx_left--, cur_rx++) { + unsigned int entry = cur_rx % NUM_RX_DESC; + struct rx_desc *desc = tp->rx_desc_array + entry; + u32 status; + + rmb(); /* make sure this RX descriptor is ready */ + status = le32_to_cpu(desc->opts1) & tp->opts1_mask; + + if (status & DESC_OWN) + break; + if (unlikely(status & RX_RES)) { + netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n", + status); + dev->stats.rx_errors++; + if (status & (RX_RWT | RX_RUNT)) + dev->stats.rx_length_errors++; + if (status & RX_CRC) + dev->stats.rx_crc_errors++; + if (status & RX_FOVF) { + rtl_schedule_task(tp, + RTL_FLAG_TASK_RESET_PENDING); + dev->stats.rx_fifo_errors++; + } + if ((status & (RX_RUNT | RX_CRC)) && + !(status & (RX_RWT | RX_FOVF)) && + (dev->features & NETIF_F_RXALL)) + goto process_pkt; + } else { + struct sk_buff *skb; + dma_addr_t addr; + int pkt_size; + +process_pkt: + + skb = tp->rx_databuff[entry]; + addr = le64_to_cpu(desc->addr); + if (likely(!(dev->features & NETIF_F_RXFCS))) + pkt_size = (status & 0x00003fff) - 4; + else + pkt_size = status & 0x00003fff; + + /* The driver does not support incoming fragmented + * frames. They are seen as a symptom of over-mtu + * sized frames. + */ + if (unlikely(rtl8169_fragmented_frame(status))) { + dev->stats.rx_dropped++; + dev->stats.rx_length_errors++; + continue; + } + + if (!tp->acp_enable) + dma_sync_single_for_cpu(d, addr, pkt_size, + DMA_FROM_DEVICE); + tp->rx_databuff[entry] = NULL; + if (!tp->acp_enable) + dma_unmap_single(d, addr, pkt_size, + DMA_FROM_DEVICE); + + rtl8169_rx_csum(skb, status); + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + + rtl8169_rx_vlan_tag(desc, skb); + + napi_gro_receive(&tp->napi, skb); + + u64_stats_update_begin(&tp->rx_stats.syncp); + tp->rx_stats.packets++; + tp->rx_stats.bytes += pkt_size; + u64_stats_update_end(&tp->rx_stats.syncp); + } + } + + count = cur_rx - tp->cur_rx; + tp->cur_rx = cur_rx; + + delta = rtl8168_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + /* netif_err(tp, drv, tp->dev, "delta =%x\n",delta); */ + tp->dirty_rx += delta; + + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) { + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); + netif_err(tp, drv, tp->dev, "%s: Rx buffers exhausted\n", + dev->name); + } + + return count; +} +#else +static struct sk_buff *rtl8169_try_rx_copy(void *data, + struct rtl8169_private *tp, + int pkt_size, dma_addr_t addr) +{ + struct sk_buff *skb; + struct device *d = &tp->pdev->dev; + + data = rtl8169_align(data); + if (!tp->acp_enable) + dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE); + prefetch(data); + skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size); + if (skb) + memcpy(skb->data, data, pkt_size); + if (!tp->acp_enable) + dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE); + + return skb; +} + +static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, + u32 budget) +{ + unsigned int cur_rx, rx_left; + unsigned int count; + const unsigned int num_rx_desc = NUM_RX_DESC; + + cur_rx = tp->cur_rx; + + for (rx_left = min(budget, num_rx_desc); rx_left > 0; + rx_left--, cur_rx++) { + unsigned int entry = cur_rx % NUM_RX_DESC; + struct rx_desc *desc = tp->rx_desc_array + entry; + u32 status; + + rmb(); /* make sure this RX descriptor is ready */ + status = le32_to_cpu(desc->opts1) & tp->opts1_mask; + + if (status & DESC_OWN) + break; + if (unlikely(status & RX_RES)) { + netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n", + status); + dev->stats.rx_errors++; + if (status & (RX_RWT | RX_RUNT)) + dev->stats.rx_length_errors++; + if (status & RX_CRC) + dev->stats.rx_crc_errors++; + if (status & RX_FOVF) { + rtl_schedule_task(tp, + RTL_FLAG_TASK_RESET_PENDING); + dev->stats.rx_fifo_errors++; + } + if ((status & (RX_RUNT | RX_CRC)) && + !(status & (RX_RWT | RX_FOVF)) && + (dev->features & NETIF_F_RXALL)) + goto process_pkt; + } else { + struct sk_buff *skb; + dma_addr_t addr; + int pkt_size; + +process_pkt: + addr = le64_to_cpu(desc->addr); + if (likely(!(dev->features & NETIF_F_RXFCS))) + pkt_size = (status & 0x00003fff) - 4; + else + pkt_size = status & 0x00003fff; + + /* The driver does not support incoming fragmented + * frames. They are seen as a symptom of over-mtu + * sized frames. + */ + if (unlikely(rtl8169_fragmented_frame(status))) { + dev->stats.rx_dropped++; + dev->stats.rx_length_errors++; + goto release_descriptor; + } + + skb = rtl8169_try_rx_copy(tp->rx_databuff[entry], + tp, pkt_size, addr); + if (!skb) { + dev->stats.rx_dropped++; + goto release_descriptor; + } + + rtl8169_rx_csum(skb, status); + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + + rtl8169_rx_vlan_tag(desc, skb); + + napi_gro_receive(&tp->napi, skb); + + u64_stats_update_begin(&tp->rx_stats.syncp); + tp->rx_stats.packets++; + tp->rx_stats.bytes += pkt_size; + u64_stats_update_end(&tp->rx_stats.syncp); + } +release_descriptor: + desc->opts2 = 0; + wmb(); /* make sure this RX descriptor is useless */ + rtl8169_mark_to_asic(desc, rx_buf_sz); + } + + count = cur_rx - tp->cur_rx; + tp->cur_rx = cur_rx; + + return count; +} +#endif /* CONFIG_RTL_RX_NO_COPY */ + +static irqreturn_t phy_irq_handler(int irq, void *dev_instance) +{ + struct rtl8169_private *tp = dev_instance; + u32 isr; + u32 por; + int i; + bool hit = false; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &isr); + pr_info(PFX "ISO_UMSK_ISR\t[0x98007004] = %08x\n", isr); + regmap_read(tp->iso_base, ISO_POR_DATAI, &por); + pr_info(PFX "ISO_POR_DATAI\t[0x98007218] = %08x\n", por); + + for (i = 0; i < tp->phy_irq_num; i++) { + if (irq == tp->phy_irq[i] && + (isr & (1 << tp->phy_irq_map[i]))) { + pr_info(PFX "phy_0: get IRQ %d for GPHY POR interrupt (%d)\n", + irq, tp->phy_irq_map[i]); + regmap_write(tp->iso_base, ISO_UMSK_ISR, 1 << tp->phy_irq_map[i]); + hit = true; + break; + } + } + + if (hit) { + if ((por & tp->phy_por_xv_mask) != tp->phy_por_xv_mask) { + pr_err(PFX "phy_0: GPHY has power issue (0x%x)\n", por); + goto out; + } + + if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) + rtl_phy_reinit(tp); + else if (atomic_inc_return(&tp->phy_reinit_flag) == 1) + rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING); + else + atomic_dec(&tp->phy_reinit_flag); + } + +out: + return IRQ_RETVAL(IRQ_HANDLED); +} + +static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct rtl8169_private *tp = netdev_priv(dev); + int handled = 0; + u16 status; + + status = rtl_get_events(tp); + if (status && status != 0xffff) { + status &= RTL_EVENT_NAPI | tp->event_slow; + if (status) { + handled = 1; + + rtl_irq_disable(tp); + napi_schedule(&tp->napi); + } + } + return IRQ_RETVAL(handled); +} + +/* Workqueue context. + */ +static void rtl_slow_event_work(struct rtl8169_private *tp) +{ + struct net_device *dev = tp->dev; + void __iomem *ioaddr = tp->mmio_addr; + u16 status; + + status = rtl_get_events(tp) & tp->event_slow; + rtl_ack_events(tp, status); + + if (status & LINK_CHG) { + __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true); + + /* prevet ALDPS enter MAC Powercut Tx/Rx disable */ + /* use MAC reset to set counter to offset 0 */ + if (tp->chip->link_ok(ioaddr)) + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); + } + + rtl_irq_enable_all(tp); +} + +static void rtl_task(struct work_struct *work) +{ + static const struct { + int bitnr; + void (*action)(struct rtl8169_private *tp); + } rtl_work[] = { + /* XXX - keep rtl_slow_event_work() as first element. */ + { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work }, + { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work }, + { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work } + }; + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, wk.work); + struct net_device *dev = tp->dev; + int i; + + rtl_lock_work(tp); + + if (!netif_running(dev) || + !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) + goto out_unlock; + + for (i = 0; i < ARRAY_SIZE(rtl_work); i++) { + bool pending; + + pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags); + if (pending) + rtl_work[i].action(tp); + } + +out_unlock: + rtl_unlock_work(tp); +} + +static int rtl8169_poll(struct napi_struct *napi, int budget) +{ + struct rtl8169_private *tp = + container_of(napi, struct rtl8169_private, napi); + struct net_device *dev = tp->dev; + u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow; + int work_done = 0; + u16 status; + +#if defined(CONFIG_RTL_RX_NO_COPY) + u32 old_dirty_rx; +#endif /* CONFIG_RTL_RX_NO_COPY */ + + status = rtl_get_events(tp); + rtl_ack_events(tp, status & ~(tp->event_slow | RX_OVERFLOW)); + +#if defined(CONFIG_RTL_RX_NO_COPY) + old_dirty_rx = tp->dirty_rx; +#endif /* CONFIG_RTL_RX_NO_COPY */ + + /* always check rx queue */ + work_done = rtl_rx(dev, tp, (u32)budget); + +#if defined(CONFIG_RTL_RX_NO_COPY) + if ((status & RX_OVERFLOW) && tp->dirty_rx != old_dirty_rx) + rtl_ack_events(tp, RX_OVERFLOW); +#else + if ((status & RX_OVERFLOW) && work_done > 0) + rtl_ack_events(tp, RX_OVERFLOW); +#endif /* CONFIG_RTL_RX_NO_COPY */ + + if (status & RTL_EVENT_NAPI_TX) { + if (tp->chip->features & RTL_FEATURE_TX_NO_CLOSE) + rtl_tx_no_close(dev, tp); + else + rtl_tx(dev, tp); + } + + if (status & tp->event_slow) { + enable_mask &= ~tp->event_slow; + + rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING); + } + + if (work_done < budget) { + napi_complete(napi); + + rtl_irq_enable(tp, enable_mask); + } + + return work_done; +} + +static void rtl8169_down(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + napi_disable(&tp->napi); + netif_stop_queue(dev); + + rtl8169_hw_reset(tp); + /* At this point device interrupts can not be enabled in any function, + * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task) + * and napi is disabled (rtl8169_poll). + */ + + /* Give a racing hard_start_xmit a few cycles to complete. */ + synchronize_rcu(); + + rtl8169_tx_clear(tp); + + rtl8169_rx_clear(tp); + + rtl_pll_power_down(tp); + + tp->status |= RTL_STATUS_DOWN; +} + +static int rtl8169_close(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + struct platform_device *pdev = tp->pdev; + + /* Update counters before going down */ + rtl8169_update_counters(dev); + + rtl_lock_work(tp); + clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + + rtl8169_down(dev); + + rtl_unlock_work(tp); + + free_irq(dev->irq, dev); + + if (tp->acp_enable) { + kfree(tp->rx_desc_array); + kfree(tp->tx_desc_array); + } else { + dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, + tp->rx_desc_array, tp->rx_phy_addr); + dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, + tp->tx_desc_array, tp->tx_phy_addr); + } + tp->tx_desc_array = NULL; + tp->rx_desc_array = NULL; + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void rtl8169_netpoll(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl8169_interrupt(tp->pdev->irq, dev); +} +#endif + +static int rtl_open(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct platform_device *pdev = tp->pdev; + int retval = -ENOMEM; + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; + + /* Rx and Tx descriptors needs 256 bytes alignment. + * dma_alloc_coherent provides more. + */ + if (tp->acp_enable) { + tp->tx_desc_array = kzalloc_node(R8169_TX_RING_BYTES, + GFP_KERNEL, node); + tp->tx_phy_addr = virt_to_phys(tp->tx_desc_array); + } else { + tp->tx_desc_array = dma_alloc_coherent(&pdev->dev, + R8169_TX_RING_BYTES, + &tp->tx_phy_addr, + GFP_KERNEL); + } + if (!tp->tx_desc_array) + goto err_pm_runtime_put; + + if (tp->acp_enable) { + tp->rx_desc_array = kzalloc_node(R8169_RX_RING_BYTES, + GFP_KERNEL, node); + tp->rx_phy_addr = virt_to_phys(tp->rx_desc_array); + } else { + tp->rx_desc_array = dma_alloc_coherent(&pdev->dev, + R8169_RX_RING_BYTES, + &tp->rx_phy_addr, + GFP_KERNEL); + } + if (!tp->rx_desc_array) + goto err_free_tx_0; + + retval = rtl8169_init_ring(dev); + if (retval < 0) + goto err_free_rx_1; + + INIT_WORK(&tp->wk.work, rtl_task); + + smp_mb(); /* make sure TX/RX rings are ready */ + + retval = request_irq(dev->irq, rtl8169_interrupt, + (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, + dev->name, dev); + if (retval < 0) + goto err_free_rx_2; + + rtl_lock_work(tp); + + set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + + napi_enable(&tp->napi); + + if (tp->status & RTL_STATUS_DOWN) { + tp->status &= ~RTL_STATUS_DOWN; + rtl8169_init_phy(dev, tp); + } + + __rtl8169_set_features(dev, dev->features); + + rtl_pll_power_up(tp); + + rtl_hw_start(dev); + + netif_start_queue(dev); + + rtl_unlock_work(tp); + + tp->saved_wolopts = 0; + + rtl8169_check_link_status(dev, tp, ioaddr); +out: + return retval; + +err_free_rx_2: + rtl8169_rx_clear(tp); +err_free_rx_1: + if (tp->acp_enable) + kfree(tp->rx_desc_array); + else + dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, + tp->rx_desc_array, tp->rx_phy_addr); + tp->rx_desc_array = NULL; +err_free_tx_0: + if (tp->acp_enable) + kfree(tp->tx_desc_array); + else + dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, + tp->tx_desc_array, tp->tx_phy_addr); + tp->tx_desc_array = NULL; +err_pm_runtime_put: + goto out; +} + +static void +rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned int start; + + do { + start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp); + stats->rx_packets = tp->rx_stats.packets; + stats->rx_bytes = tp->rx_stats.bytes; + } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start)); + + do { + start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp); + stats->tx_packets = tp->tx_stats.packets; + stats->tx_bytes = tp->tx_stats.bytes; + } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start)); + + stats->rx_dropped = dev->stats.rx_dropped; + stats->tx_dropped = dev->stats.tx_dropped; + stats->rx_length_errors = dev->stats.rx_length_errors; + stats->rx_errors = dev->stats.rx_errors; + stats->rx_crc_errors = dev->stats.rx_crc_errors; + stats->rx_fifo_errors = dev->stats.rx_fifo_errors; + stats->rx_missed_errors = dev->stats.rx_missed_errors; +} + +static void rtl8169_protocol_offload(struct rtl8169_private *tp); +static void rtl8169_net_suspend(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!netif_running(dev)) + return; + + netif_device_detach(dev); + netif_stop_queue(dev); + + rtl_lock_work(tp); + napi_disable(&tp->napi); + clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + rtl_unlock_work(tp); + + /* disable EEE if it is enabled */ + if (tp->eee_enable) + tp->chip->eee_set(tp, false); + + rtl8169_protocol_offload(tp); + + rtl_pll_power_down(tp); +} + +static void rtl_hw_initialize(struct rtl8169_private *tp); +static void rtl_reinit_mac_phy(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + rtl_lock_work(tp); + tp->chip->reset_phy_gmac(tp); + tp->chip->acp_init(tp); + tp->chip->pll_clock_init(tp); + tp->chip->mdio_init(tp); + /* after r8169soc_mdio_init(), + * SGMII : tp->ext_phy == true ==> external MDIO, + * RGMII : tp->ext_phy == true ==> external MDIO, + * RMII : tp->ext_phy == false ==> internal MDIO, + * FE PHY: tp->ext_phy == false ==> internal MDIO + */ + + /* Enable ALDPS */ + rtl_phy_write(tp, 0x0a43, 24, + rtl_phy_read(tp, 0x0a43, 24) | BIT(2)); + + rtl_init_rxcfg(tp); + + rtl_irq_disable(tp); + + rtl_hw_initialize(tp); + + rtl_hw_reset(tp); + + rtl_ack_events(tp, 0xffff); + + RTL_W8(CFG9346, CFG9346_UNLOCK); + RTL_W8(CONFIG1, RTL_R8(CONFIG1) | PM_ENABLE); + RTL_W8(CONFIG5, RTL_R8(CONFIG5) & PME_STATUS); + + /* disable magic packet WOL */ + RTL_W8(CONFIG3, RTL_R8(CONFIG3) & ~MAGIC_PKT); + RTL_W8(CFG9346, CFG9346_LOCK); + + rtl_unlock_work(tp); + + /* Set MAC address */ + rtl_rar_set(tp, tp->dev->dev_addr); + + rtl_led_set(tp); +} + +static __maybe_unused void rtl_mac_reinit(struct rtl8169_private *tp) +{ + if (netif_running(tp->dev)) { + tp->netif_is_running = true; + pr_info(PFX "take %s down\n", tp->dev->name); + rtl8169_close(tp->dev); + } else { + tp->netif_is_running = false; + } + + rtl_reinit_mac_phy(tp); + + if (tp->netif_is_running) { + pr_info(PFX "bring %s up\n", tp->dev->name); + rtl_open(tp->dev); + } + + rtl_lock_work(tp); + /* enable EEE according to tp->eee_enable */ + tp->chip->eee_set(tp, tp->eee_enable); + + rtl8169_init_phy(tp->dev, tp); + rtl_unlock_work(tp); +} + +#ifdef CONFIG_PM + +static int rtl8169_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rtl8169_private *tp = netdev_priv(ndev); + + pr_info(PFX "Enter %s\n", __func__); + + if (tp->pwr_saving) { + if (netif_running(ndev)) { + tp->netif_is_running = true; + pr_info(PFX "take %s down\n", ndev->name); + rtl8169_close(ndev); + } else { + tp->netif_is_running = false; + } + + pr_info(PFX "disable ETN clk and reset\n"); + tp->chip->reset_phy_gmac(tp); + } else { + rtl8169_net_suspend(ndev); + } + + /* turn off LED, and current solution is switch pad to GPIO input */ + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) + tp->chip->led_set(tp, false); + + pr_info(PFX "Exit %s\n", __func__); + + return 0; +} + +static void __rtl8169_resume(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + netif_device_attach(dev); + + /* turn on LED */ + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) + tp->chip->led_set(tp, true); + + tp->chip->wakeup_set(tp, false); + + rtl_pll_power_up(tp); + rtl_rar_set(tp, tp->dev->dev_addr); + + rtl_lock_work(tp); + napi_enable(&tp->napi); + set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + rtl_unlock_work(tp); + + rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); +} + +static int rtl8169_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rtl8169_private *tp = netdev_priv(ndev); + + pr_info(PFX "Enter %s\n", __func__); + + if (tp->pwr_saving) { + pr_info(PFX "enable ETN clk and reset\n"); + rtl_reinit_mac_phy(tp); + + if (tp->netif_is_running) { + pr_info(PFX "bring %s up\n", ndev->name); + rtl_open(ndev); + } + } else if (netif_running(ndev)) { + __rtl8169_resume(ndev); + } + + /* enable EEE according to tp->eee_enable */ + tp->chip->eee_set(tp, tp->eee_enable); + + rtl8169_init_phy(ndev, tp); + + pr_info(PFX "Exit %s\n", __func__); + + return 0; +} + +static __maybe_unused int rtl8169_runtime_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rtl8169_private *tp = netdev_priv(ndev); + + if (!tp->tx_desc_array) + return 0; + + rtl_lock_work(tp); + tp->saved_wolopts = __rtl8169_get_wol(tp); + __rtl8169_set_wol(tp, WAKE_ANY); + rtl_unlock_work(tp); + + rtl8169_net_suspend(ndev); + + return 0; +} + +static __maybe_unused int rtl8169_runtime_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rtl8169_private *tp = netdev_priv(ndev); + + if (!tp->tx_desc_array) + return 0; + + rtl_lock_work(tp); + __rtl8169_set_wol(tp, tp->saved_wolopts); + tp->saved_wolopts = 0; + rtl_unlock_work(tp); + + rtl8169_init_phy(ndev, tp); + + __rtl8169_resume(ndev); + + return 0; +} + +static __maybe_unused int rtl8169_runtime_idle(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct rtl8169_private *tp = netdev_priv(ndev); + + return tp->tx_desc_array ? -EBUSY : 0; +} + +static const struct dev_pm_ops rtl8169_pm_ops = { + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, + .freeze = rtl8169_suspend, + .thaw = rtl8169_resume, + .poweroff = rtl8169_suspend, + .restore = rtl8169_resume, + .runtime_suspend = rtl8169_runtime_suspend, + .runtime_resume = rtl8169_runtime_resume, + .runtime_idle = rtl8169_runtime_idle, +}; + +#define RTL8169_PM_OPS (&rtl8169_pm_ops) + +#else /* !CONFIG_PM */ + +#define RTL8169_PM_OPS NULL + +#endif /* !CONFIG_PM */ + +static void rtl_shutdown(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + + rtl8169_net_suspend(dev); + +#ifdef MY_ABC_HERE + // We customize MAC(s), avoid restoring original mac address when shutdown. +#else /* MY_ABC_HERE */ + /* Restore original MAC address */ + rtl_rar_set(tp, dev->perm_addr); +#endif /* MY_ABC_HERE */ + + rtl8169_hw_reset(tp); + + if (system_state == SYSTEM_POWER_OFF) { + if (__rtl8169_get_wol(tp) & WAKE_ANY) + rtl_wol_suspend_quirk(tp); + } +} + +static int rtl_remove_one(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int i; + +#ifdef RTL_PROC + do { + if (!tp->dir_dev) + break; + + remove_proc_entry("wol_enable", tp->dir_dev); + remove_proc_entry("pwr_saving", tp->dir_dev); + remove_proc_entry("mac_reinit", tp->dir_dev); + remove_proc_entry("phy_reinit", tp->dir_dev); + remove_proc_entry("eee", tp->dir_dev); + remove_proc_entry("driver_var", tp->dir_dev); + remove_proc_entry("eth_phy", tp->dir_dev); + remove_proc_entry("ext_regs", tp->dir_dev); + remove_proc_entry("registers", tp->dir_dev); + remove_proc_entry("tx_desc", tp->dir_dev); + remove_proc_entry("rx_desc", tp->dir_dev); + remove_proc_entry("tally", tp->dir_dev); + remove_proc_entry("wpd_event", tp->dir_dev); + remove_proc_entry("wol_packet", tp->dir_dev); + remove_proc_entry("wake_mask", tp->dir_dev); + remove_proc_entry("wake_crc", tp->dir_dev); + remove_proc_entry("wake_idx_en", tp->dir_dev); + remove_proc_entry("wake_dump", tp->dir_dev); + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + remove_proc_entry("wake_offset", tp->dir_dev); + remove_proc_entry("wake_pattern", tp->dir_dev); + } + + if (!rtw_proc) + break; + + remove_proc_entry(MODULENAME, rtw_proc); + remove_proc_entry("eth0", init_net.proc_net); + + rtw_proc = NULL; + + } while (0); +#endif + + cancel_work_sync(&tp->wk.work); + + netif_napi_del(&tp->napi); + + unregister_netdev(dev); + + /* restore original MAC address */ + rtl_rar_set(tp, dev->perm_addr); + + for (i = 0; i < tp->phy_irq_num; i++) + free_irq(tp->phy_irq[i], tp); + + rtl8169_release_board(pdev, dev, tp->mmio_addr); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct net_device_ops rtl_netdev_ops = { + .ndo_open = rtl_open, + .ndo_stop = rtl8169_close, + .ndo_get_stats64 = rtl8169_get_stats64, + .ndo_start_xmit = rtl8169_start_xmit, + .ndo_tx_timeout = rtl8169_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = rtl8169_change_mtu, + .ndo_fix_features = rtl8169_fix_features, + .ndo_set_features = rtl8169_set_features, + .ndo_set_mac_address = rtl_set_mac_address, + .ndo_do_ioctl = rtl8169_ioctl, + .ndo_set_rx_mode = rtl_set_rx_mode, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rtl8169_netpoll, +#endif + +}; + +DECLARE_RTL_COND(rtl_link_list_ready_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R8(MCU) & LINK_LIST_RDY; +} + +DECLARE_RTL_COND(rtl_rxtx_empty_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY; +} + +/* protocol offload driver flow */ +static void rtl8169_protocol_offload(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + u32 tmp; + + /* Set Now_is_OOB = 0 */ + RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); + + /* Flow control related (only for OOB) */ + /* RX FIFO threshold */ + rtl_ocp_write(tp, 0xC0A0, 0x0003); + rtl_ocp_write(tp, 0xC0A2, 0x0180); + rtl_ocp_write(tp, 0xC0A4, 0x004A); + rtl_ocp_write(tp, 0xC0A8, 0x005A); + + /* Turn off RCR (IO offset 0x44 set to 0) */ + rtl_rx_close(tp); + + /* Set rxdv_gated_en (IO 0xF2 bit3 = 1) */ + RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN); + + /* check FIFO empty (IO 0xD2 bit[12:13]) */ + if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42)) + return; + + /* disable Tx/Rx enable = 0 (IO 0x36 bit[10:11]=0b) */ + RTL_W8(CHIP_CMD, RTL_R8(CHIP_CMD) & ~(CMD_TX_ENB | CMD_RX_ENB)); + usleep_range(1000, 1100); + + /* check link_list ready =1 (IO 0xD2 bit9=1) */ + if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42)) + return; + + /* set re_ini_ll =1 (MACOCP : 0xE8DE bit15=1) */ + tmp = rtl_ocp_read(tp, 0xE8DE); + tmp |= BIT(15); + rtl_ocp_write(tp, 0xE8DE, tmp); + + /* check link_list ready =1 (IO 0xD2 bit9=1) */ + if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42)) + return; + + /* Setting RMS (IO offset 0xdb-0xda set to 0x05F3) */ + rtl_set_rx_max_size(ioaddr, 0x05F3); + + /* Enable VLAN De-tagging (IO offset 0xE0 bit6 set to 1) */ + RTL_W16(C_PLUS_CMD, RTL_R16(C_PLUS_CMD) | RX_VLAN); + + /* Enable now_is_oob (IO offset 0xd3 bit 7 set to 1b) */ + RTL_W8(MCU, RTL_R8(MCU) | NOW_IS_OOB); + + /* set MACOCP 0xE8DE bit14 mcu_borw_en to 1b for modifying ShareFIFO's points */ + tmp = rtl_ocp_read(tp, 0xE8DE); + tmp |= BIT(14); /* borrow 8K SRAM */ + rtl_ocp_write(tp, 0xE8DE, tmp); + + /* Patch code to share FIFO if need */ + + /* Set rxdv_gated_en = 0 (IO 0xF2 bit3=0) */ + RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN); + + /* Turn on RCR (IO offset 0x44 set to 0x0e) */ + tmp = RTL_R32(RX_CONFIG) & ~RX_CONFIG_ACCEPT_MASK; + tmp |= ACCEPT_BROADCAST | ACCEPT_MULTICAST | ACCEPT_MY_PHYS; + RTL_W32(RX_CONFIG, tmp); + + /* Set Multicast Registers to accept all addresses */ + RTL_W32(MAR0, 0xFFFFFFFF); + RTL_W32(MAR0 + 4, 0xFFFFFFFF); +} + +static void rtl_hw_init_8168g(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + u32 data; + + tp->ocp_base = OCP_STD_PHY_BASE; + + RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN); + + if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42)) + return; + + if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42)) + return; + + RTL_W8(CHIP_CMD, RTL_R8(CHIP_CMD) & ~(CMD_TX_ENB | CMD_RX_ENB)); + usleep_range(1000, 1100); + RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); + + data = rtl_ocp_read(tp, 0xe8de); + data &= ~BIT(14); + rtl_ocp_write(tp, 0xe8de, data); + + if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42)) + return; + + data = rtl_ocp_read(tp, 0xe8de); + data |= BIT(15); + rtl_ocp_write(tp, 0xe8de, data); + + if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42)) + return; +} + +static void rtl_hw_initialize(struct rtl8169_private *tp) +{ + rtl_hw_init_8168g(tp); +} + +#ifdef RTL_PROC +static int wol_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + pr_info("WoL setting:\n"); + pr_info("\tBIT 0:\t WoL enable\n"); + pr_info("\tBIT 1:\t CRC match\n"); + pr_info("\tBIT 2:\t WPD\n"); + pr_info("wol_enable = 0x%x\n", tp->wol_enable); + seq_printf(m, "%d\n", tp->wol_enable); + return 0; +} + +static ssize_t wol_write_proc(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + char tmp[32]; + u32 val = 0; + u32 len = 0; + int ret; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou32(tmp, 0, &val); + if (ret) { + pr_err("invalid WoL setting [%s], ret = %d\n", + tmp, ret); + return count; + } + tp->wol_enable = val; + pr_info("set wol_enable = %x\n", tp->wol_enable); + } + return count; +} + +static int wol_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wol_read_proc, dev); +} + +static const struct proc_ops wol_proc_fops = { + .proc_open = wol_proc_open, + .proc_read = seq_read, + .proc_write = wol_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int pwr_saving_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + pr_info("Power saving of suspend mode:\n"); + pr_info("pwr_saving = 0x%x\n", tp->pwr_saving); + seq_printf(m, "%d\n", tp->pwr_saving); + return 0; +} + +static ssize_t pwr_saving_write_proc(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + char tmp[32]; + u32 val = 0; + u32 len = 0; + int ret; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou32(tmp, 0, &val); + if (ret) { + pr_err("invalid power saving setting [%s], ret = %d\n", + tmp, ret); + return count; + } + tp->pwr_saving = val; + pr_info("set pwr_saving = %x\n", tp->pwr_saving); + } + return count; +} + +static int pwr_saving_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, pwr_saving_read_proc, dev); +} + +static const struct proc_ops pwr_saving_proc_fops = { + .proc_open = pwr_saving_proc_open, + .proc_read = seq_read, + .proc_write = pwr_saving_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int mac_reinit_read_proc(struct seq_file *m, void *v) +{ + seq_puts(m, "\n\nUsage: echo 1 > mac_reinit\n"); + + return 0; +} + +static ssize_t mac_reinit_write_proc(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + char tmp[32]; + u32 val = 0; + u32 len = 0; + int ret; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou32(tmp, 0, &val); + if (ret || val == 0) { + pr_err("invalid mac_reinit [%s], ret = %d\n", + tmp, ret); + return count; + } + pr_info("mac_reinit = %x\n", val); + + rtl_mac_reinit(tp); + } + return count; +} + +static int mac_reinit_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, mac_reinit_read_proc, dev); +} + +static const struct proc_ops mac_reinit_proc_fops = { + .proc_open = mac_reinit_proc_open, + .proc_read = seq_read, + .proc_write = mac_reinit_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int phy_reinit_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + u32 isr; + u32 por; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &isr); + seq_printf(m, "ISO_UMSK_ISR\t[0x98007004] = %08x\n", isr); + regmap_read(tp->iso_base, ISO_POR_DATAI, &por); + seq_printf(m, "ISO_POR_DATAI\t[0x98007218] = %08x\n", por); + + seq_puts(m, "\n\nUsage: echo 1 > phy_reinit\n"); + + return 0; +} + +static ssize_t phy_reinit_write_proc(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + char tmp[32]; + u32 val = 0; + u32 len = 0; + int ret; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou32(tmp, 0, &val); + if (ret || val == 0) { + pr_err("invalid phy_reinit [%s], ret = %d\n", + tmp, ret); + return count; + } + pr_info("phy_reinit = %x\n", val); + + if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) + rtl_phy_reinit(tp); + else if (atomic_inc_return(&tp->phy_reinit_flag) == 1) + rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING); + else + atomic_dec(&tp->phy_reinit_flag); + } + return count; +} + +static int phy_reinit_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, phy_reinit_read_proc, dev); +} + +static const struct proc_ops phy_reinit_proc_fops = { + .proc_open = phy_reinit_proc_open, + .proc_read = seq_read, + .proc_write = phy_reinit_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int eee_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + unsigned short e040, e080; + + rtl_lock_work(tp); + e040 = rtl_ocp_read(tp, 0xe040); /* EEE */ + e080 = rtl_ocp_read(tp, 0xe080); /* EEE+ */ + seq_printf(m, "%s: eee = %d, OCP 0xe040 = 0x%x, OCP 0xe080 = 0x%x\n", + dev->name, tp->eee_enable, e040, e080); + r8169_display_eee_info(dev, m, tp); + rtl_unlock_work(tp); + + return 0; +} + +static ssize_t eee_write_proc(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[32]; + u32 val = 0; + u32 len = 0; + int ret; + bool chg = false; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou32(tmp, 0, &val); + if (ret) { + pr_err("invalid EEE setting [%s], ret = %d\n", + tmp, ret); + return count; + } + pr_err("write %s eee = %x\n", dev->name, val); + + if (val > 0 && !tp->eee_enable) { + tp->eee_enable = true; + chg = true; + } else if (val == 0 && tp->eee_enable) { + tp->eee_enable = false; + chg = true; + } + } + + if (!chg) + goto done; + + rtl_lock_work(tp); + /* power down PHY */ + rtl_phy_write(tp, 0, MII_BMCR, + rtl_phy_read(tp, 0, MII_BMCR) | BMCR_PDOWN); + + tp->chip->eee_set(tp, tp->eee_enable); + mdelay(100); /* wait PHY ready */ + rtl8169_phy_reset(dev, tp); + rtl_unlock_work(tp); + +done: + return count; +} + +/* seq_file wrappers for procfile show routines. */ +static int eee_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, eee_read_proc, dev); +} + +static const struct proc_ops eee_proc_fops = { + .proc_open = eee_proc_open, + .proc_read = seq_read, + .proc_write = eee_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static void r8169soc_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + u32 addr; + u32 val; + u32 i; + + tp->chip->dump_regs(m, tp); + + seq_puts(m, "ETN MAC regs:\n"); + for (i = 0; i < 256; i += 4) { + addr = 0x98016000 + i; + val = readl(tp->mmio_addr + i); + seq_printf(m, "[%08x] = %08x\n", addr, val); + } +} + +static int registers_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + r8169soc_dump_regs(m, tp); + rtl_unlock_work(tp); + + return 0; +} + +/* seq_file wrappers for procfile show routines. */ +static int registers_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, registers_read_proc, dev); +} + +static const struct proc_ops registers_proc_fops = { + .proc_open = registers_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static void r8169soc_dump_tx_desc(struct seq_file *m, + struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + u32 i; + + if (!tp->tx_desc_array) { + seq_puts(m, "no tx_desc_array\n"); + return; + } + + seq_printf(m, "SW TX INDEX: %d\n", tp->cur_tx % NUM_TX_DESC); + seq_printf(m, "RECYCLED TX INDEX: %d\n", tp->dirty_tx % NUM_TX_DESC); + if (tp->chip->features & RTL_FEATURE_TX_NO_CLOSE) { + i = RTL_R16(TX_DESC_CLOSE_IDX) & TX_DESC_CNT_MASK; + seq_printf(m, "HW TX INDEX: %d\n", i % NUM_TX_DESC); + } + seq_puts(m, "TX DESC:\n"); + for (i = 0; i < NUM_TX_DESC; i++) + seq_printf(m, "Desc[%04d] opts1 0x%08x, opts2 0x%08x, addr 0x%llx\n", + i, tp->tx_desc_array[i].opts1, + tp->tx_desc_array[i].opts2, + tp->tx_desc_array[i].addr); +} + +static int tx_desc_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + r8169soc_dump_tx_desc(m, tp); + rtl_unlock_work(tp); + + return 0; +} + +/* seq_file wrappers for procfile show routines. */ +static int tx_desc_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, tx_desc_read_proc, dev); +} + +static const struct proc_ops tx_desc_proc_fops = { + .proc_open = tx_desc_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static void r8169soc_dump_rx_desc(struct seq_file *m, + struct rtl8169_private *tp) +{ + u32 i; + + if (!tp->rx_desc_array) { + seq_puts(m, "no rx_desc_array\n"); + return; + } + + seq_printf(m, "SW RX INDEX: %d\n", tp->cur_rx % NUM_RX_DESC); + #if defined(CONFIG_RTL_RX_NO_COPY) + seq_printf(m, "REFILLED RX INDEX: %d\n", tp->dirty_rx % NUM_RX_DESC); + #endif /* CONFIG_RTL_RX_NO_COPY */ + seq_puts(m, "RX DESC:\n"); + for (i = 0; i < NUM_RX_DESC; i++) + seq_printf(m, "Desc[%04d] opts1 0x%08x, opts2 0x%08x, addr 0x%llx\n", + i, tp->rx_desc_array[i].opts1, + tp->rx_desc_array[i].opts2, + tp->rx_desc_array[i].addr); +} + +static int rx_desc_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + rtl_lock_work(tp); + r8169soc_dump_rx_desc(m, tp); + rtl_unlock_work(tp); + + return 0; +} + +/* seq_file wrappers for procfile show routines. */ +static int rx_desc_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, rx_desc_read_proc, dev); +} + +static const struct proc_ops rx_desc_proc_fops = { + .proc_open = rx_desc_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int driver_var_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + int i; + + seq_puts(m, "\nDump Driver Variable\n"); + + rtl_lock_work(tp); + seq_puts(m, "Variable\tValue\n----------\t-----\n"); + seq_printf(m, "MODULENAME\t%s\n", MODULENAME); + seq_printf(m, "mac version\t%d\n", tp->chip->mac_version); + seq_printf(m, "chipset_name\t%s\n", tp->chip->name); + seq_printf(m, "driver version\t%s\n", RTL8169_VERSION); + seq_printf(m, "txd version\t%d\n", tp->chip->txd_version); + seq_printf(m, "chip features\t0x%x\n", tp->chip->features); + seq_printf(m, "msg_enable\t0x%x\n", tp->msg_enable); + seq_printf(m, "mtu\t\t%d\n", dev->mtu); + seq_printf(m, "NUM_RX_DESC\t0x%x\n", NUM_RX_DESC); + seq_printf(m, "cur_rx\t\t0x%x\n", tp->cur_rx); +#if defined(CONFIG_RTL_RX_NO_COPY) + seq_printf(m, "dirty_rx\t0x%x\n", tp->dirty_rx); +#endif /* CONFIG_RTL_RX_NO_COPY */ + seq_printf(m, "NUM_TX_DESC\t0x%x\n", NUM_TX_DESC); + seq_printf(m, "cur_tx\t\t0x%x\n", tp->cur_tx); + seq_printf(m, "dirty_tx\t0x%x\n", tp->dirty_tx); + seq_printf(m, "rx_buf_sz\t%d\n", rx_buf_sz); + seq_printf(m, "cp_cmd\t\t0x%x\n", tp->cp_cmd); + seq_printf(m, "event_slow\t0x%x\n", tp->event_slow); + seq_printf(m, "wol_enable\t0x%x\n", tp->wol_enable); + seq_printf(m, "pwr_saving\t0x%x\n", tp->pwr_saving); + seq_printf(m, "saved_wolopts\t0x%x\n", tp->saved_wolopts); + seq_printf(m, "opts1_mask\t0x%x\n", tp->opts1_mask); + seq_printf(m, "wol_crc_cnt\t%d\n", tp->wol_crc_cnt); + seq_printf(m, "led_cfg\t\t0x%x\n", tp->led_cfg); + seq_printf(m, "cur_features\t0x%x\n", tp->features); + seq_printf(m, "eee_enable\t%d\n", tp->eee_enable); + seq_printf(m, "acp_enable\t%d\n", tp->acp_enable); + seq_printf(m, "ext_phy\t\t%d\n", tp->ext_phy); + seq_printf(m, "output_mode\t%d\n", tp->output_mode); + tp->chip->dump_var(m, tp); + seq_printf(m, "ETN IRQ\t\t%d\n", dev->irq); + seq_printf(m, "phy_irq_num\t%d\n", tp->phy_irq_num); + for (i = 0; i < tp->phy_irq_num; i++) + seq_printf(m, "GPHY IRQ\t%d maps to ISR bit %d\n", + tp->phy_irq[i], tp->phy_irq_map[i]); + seq_printf(m, "perm_addr\t%pM\n", dev->perm_addr); + seq_printf(m, "dev_addr\t%pM\n", dev->dev_addr); + rtl_unlock_work(tp); + + seq_putc(m, '\n'); + return 0; +} + +static int driver_var_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, driver_var_read_proc, dev); +} + +static const struct proc_ops driver_var_proc_fops = { + .proc_open = driver_var_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int tally_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_counters *counters = &tp->counters; + + rtl8169_update_counters(dev); + + seq_puts(m, "\nDump Tally Counter\n"); + seq_puts(m, "Statistics\t\tValue\n----------\t\t-----\n"); + seq_printf(m, "tx_packets\t\t%lld\n", + le64_to_cpu(counters->tx_packets)); + seq_printf(m, "rx_packets\t\t%lld\n", + le64_to_cpu(counters->rx_packets)); + seq_printf(m, "tx_errors\t\t%lld\n", le64_to_cpu(counters->tx_errors)); + seq_printf(m, "rx_errors\t\t%d\n", le32_to_cpu(counters->rx_errors)); + seq_printf(m, "rx_missed\t\t%d\n", le16_to_cpu(counters->rx_missed)); + seq_printf(m, "align_errors\t\t%d\n", + le16_to_cpu(counters->align_errors)); + seq_printf(m, "tx_one_collision\t%d\n", + le32_to_cpu(counters->tx_one_collision)); + seq_printf(m, "tx_multi_collision\t%d\n", + le32_to_cpu(counters->tx_multi_collision)); + seq_printf(m, "rx_unicast\t\t%lld\n", + le64_to_cpu(counters->rx_unicast)); + seq_printf(m, "rx_broadcast\t\t%lld\n", + le64_to_cpu(counters->rx_broadcast)); + seq_printf(m, "rx_multicast\t\t%d\n", + le32_to_cpu(counters->rx_multicast)); + seq_printf(m, "tx_aborted\t\t%d\n", le16_to_cpu(counters->tx_aborted)); + seq_printf(m, "tx_underrun\t\t%d\n", + le16_to_cpu(counters->tx_underrun)); + + seq_putc(m, '\n'); + return 0; +} + +static int tally_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, tally_read_proc, dev); +} + +static const struct proc_ops tally_proc_fops = { + .proc_open = tally_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int eth_phy_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + int i, n, max = 16; + u16 word_rd; + struct rtl8169_private *tp = netdev_priv(dev); + + seq_puts(m, "\nDump Ethernet PHY\n"); + seq_puts(m, "\nOffset\tValue\n------\t-----\n "); + + rtl_lock_work(tp); + seq_puts(m, "\n####################page 0##################\n "); + for (n = 0; n < max;) { + seq_printf(m, "\n0x%02x:\t", n); + + for (i = 0; i < 8 && n < max; i++, n++) { + word_rd = rtl_phy_read(tp, 0, n); + seq_printf(m, "%04x ", word_rd); + } + } + rtl_unlock_work(tp); + + seq_putc(m, '\n'); + return 0; +} + +static ssize_t eth_phy_write_proc(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[32]; + u32 page; + u32 reg; + u32 val; + u32 len; + int ret; + char *p; + char *t; + char *delim = " "; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + + p = tmp; + t = strsep(&p, delim); + if (!t) + goto usage; + ret = kstrtou32(t, 0, &page); + if (ret) { + pr_err("invalid page [%s], ret = %d\n", t, ret); + goto usage; + } + + t = strsep(&p, delim); + if (!t) + goto usage; + ret = kstrtou32(t, 0, ®); + if (ret) { + pr_err("invalid reg [%s], ret = %d\n", t, ret); + goto usage; + } + + t = strsep(&p, delim); + if (!t) { + /* read cmd */ + val = rtl_phy_read(tp, page, reg & 0x1f); + pr_err("Read page 0x%x reg 0x%x, value = 0x%04x\n", page, reg & 0x1f, val); + goto out; + } + ret = kstrtou32(t, 0, &val); + if (ret) { + pr_err("invalid value [%s], ret = %d\n", t, ret); + goto usage; + } else { + /* write cmd */ + rtl_phy_write(tp, page, reg & 0x1f, val); + pr_info("Write page 0x%x reg 0x%x value 0x%04x\n", page, reg & 0x1f, val); + goto out; + } + } + +usage: + pr_err("USAGE: echo \" []\" > eth_phy\n"); +out: + return count; +} + +static int eth_phy_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, eth_phy_read_proc, dev); +} + +static const struct proc_ops eth_phy_proc_fops = { + .proc_open = eth_phy_proc_open, + .proc_read = seq_read, + .proc_write = eth_phy_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int ext_regs_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + int i, n, max = 256; + u32 dword_rd; + struct rtl8169_private *tp = netdev_priv(dev); + + seq_puts(m, "\nDump Extended Registers\n"); + seq_puts(m, "\nOffset\tValue\n------\t-----\n "); + + rtl_lock_work(tp); + for (n = 0; n < max;) { + seq_printf(m, "\n0x%02x:\t", n); + + for (i = 0; i < 4 && n < max; i++, n += 4) { + dword_rd = rtl_eri_read(tp, n, ERIAR_EXGMAC); + seq_printf(m, "%08x ", dword_rd); + } + } + rtl_unlock_work(tp); + + seq_putc(m, '\n'); + return 0; +} + +static int ext_regs_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, ext_regs_read_proc, dev); +} + +static const struct proc_ops ext_regs_proc_fops = { + .proc_open = ext_regs_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wpd_evt_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + u32 tmp; + + rtl_lock_work(tp); + /* check if wol_own and wpd_en are both set */ + tmp = rtl_ocp_read(tp, 0xC0C2); + if ((tmp & BIT(4)) == 0 || (tmp & BIT(0)) == 0) { + seq_puts(m, "\nNo WPD event\n"); + rtl_unlock_work(tp); + return 0; + } + + seq_puts(m, "\nWPD event:\n"); + tmp = rtl_ocp_read(tp, 0xD23A) & 0x0F01; + seq_printf(m, "Type (0: CRC match, 1: magic pkt) = %d\n", + tmp & 0x1); + if ((tmp & 0x1) == 0) + seq_printf(m, "CRC match ID = %d\n", tmp >> 8); + seq_printf(m, "Original packet length = %d\n", + rtl_ocp_read(tp, 0xD23C)); + seq_printf(m, "Stored packet length = %d\n", + rtl_ocp_read(tp, 0xD23E)); + rtl_unlock_work(tp); + + seq_putc(m, '\n'); + return 0; +} + +static int wpd_evt_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wpd_evt_read_proc, dev); +} + +static const struct proc_ops wpd_evt_proc_fops = { + .proc_open = wpd_evt_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wol_pkt_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + int i; + char wol_pkt[WOL_BUF_LEN]; + u32 len; + u32 tmp; + u16 *ptr; + + memset(wol_pkt, 0, WOL_BUF_LEN); + + rtl_lock_work(tp); + /* check if wol_own and wpd_en are both set */ + tmp = rtl_ocp_read(tp, 0xC0C2); + if ((tmp & BIT(4)) == 0 || (tmp & BIT(0)) == 0) { + rtl_unlock_work(tp); + return 0; + } + + /* read 128-byte packet buffer */ + for (i = 0; i < 128; i += 2) { + ptr = (u16 *)&wol_pkt[i]; + *ptr = rtl_ocp_read(tp, 0xD240 + i); + } + + /* get stored packet length */ + len = rtl_ocp_read(tp, 0xD23E); + for (i = 0; i < len; i++) { + if ((i % 16) == 0) + seq_puts(m, "\n"); + else if ((i % 8) == 0) + seq_puts(m, " "); + seq_printf(m, "%02x ", wol_pkt[i]); + } + rtl_unlock_work(tp); + + seq_putc(m, '\n'); + return 0; +} + +static int wol_pkt_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wol_pkt_read_proc, dev); +} + +static const struct proc_ops wol_pkt_proc_fops = { + .proc_open = wol_pkt_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static void rtl_proc_hex_dump(struct seq_file *m, char *ptr, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if ((i % 16) == 0) + seq_putc(m, '\n'); + else if ((i % 8) == 0) + seq_puts(m, "- "); + + seq_printf(m, "%02X ", ptr[i]); + } +} + +static int rtl_str2hex(char *src, char *dst) +{ + int i = 0; + char *p; + char *t; + char *delim = " "; + int ret; + + p = src; + while ((t = strsep(&p, delim)) != NULL) { + ret = kstrtou8(t, 16, &dst[i]); + if (ret) { + pr_err("%s:%d: invalid token[%s] to hex, ret 0x%x\n", + __func__, __LINE__, + t, ret); + return i; + } + i++; + } + + return i; +} + +static int wake_mask_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + seq_puts(m, "\nMASK = ["); + rtl_proc_hex_dump(m, tp->wol_rule_buf.mask, tp->wol_rule_buf.mask_size); + seq_puts(m, "\n]\n"); + + return 0; +} + +static ssize_t wake_mask_write_proc(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[512]; + u32 len; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + + if (strlen(tmp) >= (RTL_WAKE_MASK_SIZE * 3)) { + pr_err("input length should be smaller than %d\n", + RTL_WAKE_MASK_SIZE * 3); + goto out; + } + memset(tp->wol_rule_buf.mask, 0, RTL_WAKE_MASK_SIZE); + + tp->wol_rule_buf.mask_size = + rtl_str2hex(tmp, tp->wol_rule_buf.mask); + } + +out: + return count; +} + +static int wake_mask_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wake_mask_read_proc, dev); +} + +static const struct proc_ops wake_mask_proc_fops = { + .proc_open = wake_mask_proc_open, + .proc_read = seq_read, + .proc_write = wake_mask_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wake_crc_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + seq_printf(m, "CRC16 = [0x%04X]\n", tp->wol_rule_buf.crc); + + return 0; +} + +static ssize_t wake_crc_write_proc(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[80]; + u32 len; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou16(tmp, 16, &tp->wol_rule_buf.crc); + if (ret) { + pr_err("%s:%d: invalid token[%s] to hex, ret 0x%x\n", + __func__, __LINE__, + tmp, ret); + return count; + } + } + + return count; +} + +static int wake_crc_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wake_crc_read_proc, dev); +} + +static const struct proc_ops wake_crc_proc_fops = { + .proc_open = wake_crc_proc_open, + .proc_read = seq_read, + .proc_write = wake_crc_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wake_offset_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + seq_printf(m, "OFFSET = [0x%04X]\n", tp->wol_rule_buf.offset); + + return 0; +} + +static ssize_t wake_offset_write_proc(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[80]; + u32 len; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + ret = kstrtou16(tmp, 0, &tp->wol_rule_buf.offset); + if (ret) { + pr_err("%s:%d: invalid token[%s] to hex, ret 0x%x\n", + __func__, __LINE__, + tmp, ret); + return count; + } + } + + return count; +} + +static int wake_offset_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wake_offset_read_proc, dev); +} + +static const struct proc_ops wake_offset_proc_fops = { + .proc_open = wake_offset_proc_open, + .proc_read = seq_read, + .proc_write = wake_offset_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wake_pattern_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + + seq_puts(m, "\nPATTERN = ["); + rtl_proc_hex_dump(m, tp->wol_rule_buf.pattern, + tp->wol_rule_buf.pattern_size); + seq_puts(m, "\n]\n"); + + return 0; +} + +static ssize_t wake_pattern_write_proc(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[512]; + u32 len; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + if (strlen(tmp) >= (RTL_WAKE_PATTERN_SIZE * 3)) { + pr_err("input length should be smaller than %d\n", + RTL_WAKE_PATTERN_SIZE * 3); + goto out; + } + memset(tp->wol_rule_buf.pattern, 0, RTL_WAKE_PATTERN_SIZE); + + tp->wol_rule_buf.pattern_size = + rtl_str2hex(tmp, tp->wol_rule_buf.pattern); + } + +out: + return count; +} + +static int wake_pattern_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wake_pattern_read_proc, dev); +} + +static const struct proc_ops wake_pattern_proc_fops = { + .proc_open = wake_pattern_proc_open, + .proc_read = seq_read, + .proc_write = wake_pattern_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wake_idx_en_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + int wake_size; + int i; + + seq_puts(m, "USAGE:\necho \"[index] [enable]\" > wake_idx_en\n"); + seq_puts(m, "\tindex\t0 ~ 31\n"); + seq_puts(m, "\tenable\t0 ~ 1\n"); + seq_puts(m, "\t\tenable = 0 ==> remove rule[index]\n"); + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + seq_puts(m, "\t\tenable = 1 ==> add {wake_mask, wake_crc, "); + seq_puts(m, "wake_offset, wake_pattern} to rule[index]\n"); + } else { + seq_puts(m, "\t\tenable = 1 ==> add {wake_mask, wake_crc} to "); + seq_puts(m, "rule[index]\n"); + } + + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) + wake_size = RTL_WAKE_SIZE; + else + wake_size = RTL_WAKE_SIZE_CRC; + + seq_printf(m, "## Total rules = %d\n", tp->wol_crc_cnt); + for (i = 0; i < wake_size; i++) + seq_printf(m, "rule[%d] = %s\n", i, + tp->wol_rule[i].flag & WAKE_FLAG_ENABLE ? "enable" : "disable"); + return 0; +} + +static ssize_t wake_idx_en_write_proc(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + char tmp[80]; + u32 len; + struct net_device *dev = (struct net_device *) + ((struct seq_file *)file->private_data)->private; + struct rtl8169_private *tp = netdev_priv(dev); + char *p; + char *t; + char *delim = " "; + int ret; + u8 idx; + u8 en; + + len = min(count, sizeof(tmp) - 1); + if (buffer && !copy_from_user(tmp, buffer, len)) { + if (len) + tmp[len - 1] = '\0'; + + p = tmp; + t = strsep(&p, delim); + if (!t) + goto usage; + ret = kstrtou8(t, 0, &idx); + if (ret) { + pr_err("invalid idx token[%s], ret 0x%x\n", t, ret); + goto usage; + } + + if (idx > 31) { + pr_err("invalid idx [%d] (idx <= 31)\n", idx); + goto usage; + } + + t = strsep(&p, delim); + if (!t) + goto usage; + ret = kstrtou8(t, 0, &en); + if (ret) { + pr_err("invalid en token[%s], ret 0x%x\n", t, ret); + goto usage; + } + + if (en > 1) { + pr_err("invalid en [%d] (en = 0 or 1)\n", idx); + goto usage; + } + + if (en == 1) { + if (!(tp->wol_rule[idx].flag & WAKE_FLAG_ENABLE)) + tp->wol_crc_cnt++; + /* add/replace a rule */ + tp->wol_rule_buf.flag = WAKE_FLAG_ENABLE; + memcpy(&tp->wol_rule[idx], &tp->wol_rule_buf, + sizeof(struct rtl_wake_rule_s)); + } else { + if (tp->wol_rule[idx].flag & WAKE_FLAG_ENABLE) + tp->wol_crc_cnt--; + /* del a rule */ + tp->wol_rule_buf.flag &= ~WAKE_FLAG_ENABLE; + tp->wol_rule[idx].flag &= ~WAKE_FLAG_ENABLE; + } + goto out; + } + +usage: + pr_info("USAGE:\necho \"[index] [enable]\" > wake_idx_en\n"); + pr_info("\tindex\t0 ~ 31\n"); + pr_info("\tenable\t0 ~ 1\n"); + pr_info("\t\tenable = 0 ==> remove rule[index]\n"); + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + pr_info("\t\tenable = 1 ==> add {wake_mask, wake_crc, "); + pr_info("wake_offset, wake_pattern} to rule[index]\n"); + } else { + pr_info("\t\tenable = 1 ==> add {wake_mask, wake_crc} to "); + pr_info("rule[index]\n"); + } + +out: + return count; +} + +static int wake_idx_en_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wake_idx_en_read_proc, dev); +} + +static const struct proc_ops wake_idx_en_proc_fops = { + .proc_open = wake_idx_en_proc_open, + .proc_read = seq_read, + .proc_write = wake_idx_en_write_proc, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int wake_dump_read_proc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8169_private *tp = netdev_priv(dev); + int i; + + seq_puts(m, "\nWOL rules dump:\n"); + for (i = 0; i < RTL_WAKE_SIZE; i++) { + if (!(tp->wol_rule[i].flag & WAKE_FLAG_ENABLE)) + continue; + + seq_printf(m, "##### index %d #####\n", i); + + seq_puts(m, "\nMASK = ["); + rtl_proc_hex_dump(m, tp->wol_rule[i].mask, + tp->wol_rule[i].mask_size); + seq_puts(m, "\n]\n"); + + seq_printf(m, "CRC16 = 0x%04X\n", tp->wol_rule[i].crc); + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + seq_printf(m, "OFFSET = 0x%04X\n", tp->wol_rule[i].offset); + seq_puts(m, "\nPATTERN = ["); + rtl_proc_hex_dump(m, tp->wol_rule[i].pattern, + tp->wol_rule[i].pattern_size); + seq_puts(m, "\n]\n"); + } + } + + seq_putc(m, '\n'); + return 0; +} + +static int wake_dump_proc_open(struct inode *inode, struct file *file) +{ + struct net_device *dev = proc_get_parent_data(inode); + + return single_open(file, wake_dump_read_proc, dev); +} + +static const struct proc_ops wake_dump_proc_fops = { + .proc_open = wake_dump_proc_open, + .proc_read = seq_read, + .proc_write = NULL, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +#endif + +static __must_check +void *r8169soc_read_otp(struct rtl8169_private *tp, const char *name) +{ + struct device *dev = &tp->pdev->dev; + struct device_node *np = dev->of_node; + struct nvmem_cell *cell; + unsigned char *buf; + size_t buf_size; + + cell = of_nvmem_cell_get(np, name); + if (IS_ERR(cell)) { + dev_err(dev, "failed to get nvmem cell %s: %ld\n", + name, PTR_ERR(cell)); + return ERR_CAST(cell); + } + + buf = nvmem_cell_read(cell, &buf_size); + if (IS_ERR(buf)) + dev_err(dev, "failed to read nvmem cell %s: %ld\n", + name, PTR_ERR(buf)); + nvmem_cell_put(cell); + return buf; +} + +/* dummy functions */ +static void dummy_mdio_lock(struct rtl8169_private *tp) +{ + /* no lock */ +} + +static void dummy_mdio_unlock(struct rtl8169_private *tp) +{ + /* no unlock */ +} + +static void dummy_wakeup_set(struct rtl8169_private *tp, bool enable) +{ + /* no wake up */ +} + +static void dummy_reset_phy_gmac(struct rtl8169_private *tp) +{ + pr_info(PFX "%s is called\n", __func__); +} + +static void dummy_pll_clock_init(struct rtl8169_private *tp) +{ + pr_info(PFX "%s is called\n", __func__); +} + +static void dummy_acp_init(struct rtl8169_private *tp) +{ + /* no acp */ +} + +static void dummy_mdio_init(struct rtl8169_private *tp) +{ + /* no MDIO init */ +} + +static void dummy_mac_mcu_patch(struct rtl8169_private *tp) +{ + /* no patch */ +} + +static void dummy_hw_phy_config(struct rtl8169_private *tp) +{ + /* no config */ +} + +static void dummy_eee_set(struct rtl8169_private *tp, bool enable) +{ + /* no EEE */ +} + +static void dummy_led_set(struct rtl8169_private *tp, bool enable) +{ + /* no LED */ +} + +static void dummy_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + /* no special registers */ +} + +static void dummy_dump_var(struct seq_file *m, struct rtl8169_private *tp) +{ + /* no special variables */ +} + +/* RTD119X */ +static void rtd119x_reset_phy_gmac(struct rtl8169_private *tp) +{ + struct clk *clk_etn = clk_get(&tp->pdev->dev, "etn"); + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_etn = + reset_control_get_exclusive(&tp->pdev->dev, "rst_etn"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + /* pre-init clk */ + clk_prepare_enable(clk_etn); + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* disable clk and hold reset bits */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + clk_disable_unprepare(clk_etn); + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + reset_control_assert(rstc_etn); + + /* release resource */ + reset_control_put(rstc_etn); + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd119x_pll_clock_init(struct rtl8169_private *tp) +{ + struct clk *clk_etn = clk_get(&tp->pdev->dev, "etn"); + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_etn = + reset_control_get_exclusive(&tp->pdev->dev, "rst_etn"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + /* enable clk bits and release reset bits */ + clk_prepare_enable(clk_etn); + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + reset_control_deassert(rstc_etn); + reset_control_deassert(rstc_gphy); + reset_control_deassert(rstc_gmac); + + mdelay(10); /* wait 10ms for GMAC uC to be stable */ + + /* release resource */ + reset_control_put(rstc_etn); + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd119x_mdio_init(struct rtl8169_private *tp) +{ +} + +static void rtd119x_mac_mcu_patch(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + const struct soc_device_attribute rtk_soc_rtd119x_a00[] = { + { + .family = "Realtek Phoenix", + .revision = "A00", + }, + { + /* empty */ + } + }; + + if (soc_device_match(rtk_soc_rtd119x_a00)) + return; + + /* Fix ALDPS */ + RTL_W32(OCPDR, 0xFE140000); + RTL_W32(OCPDR, 0xFE150000); + RTL_W32(OCPDR, 0xFE160000); + RTL_W32(OCPDR, 0xFE170000); + RTL_W32(OCPDR, 0xFE180000); + RTL_W32(OCPDR, 0xFE190000); + RTL_W32(OCPDR, 0xFE1A0000); + RTL_W32(OCPDR, 0xFE1B0000); + mdelay(3); + RTL_W32(OCPDR, 0xFE130000); + + RTL_W32(OCPDR, 0xFC00E008); + RTL_W32(OCPDR, 0xFC01E051); + RTL_W32(OCPDR, 0xFC02E059); + RTL_W32(OCPDR, 0xFC03E05B); + RTL_W32(OCPDR, 0xFC04E05D); + RTL_W32(OCPDR, 0xFC05E05F); + RTL_W32(OCPDR, 0xFC06E061); + RTL_W32(OCPDR, 0xFC07E063); + RTL_W32(OCPDR, 0xFC08C422); + RTL_W32(OCPDR, 0xFC097380); + RTL_W32(OCPDR, 0xFC0A49B7); + RTL_W32(OCPDR, 0xFC0BF003); + RTL_W32(OCPDR, 0xFC0C1D02); + RTL_W32(OCPDR, 0xFC0D8D80); + RTL_W32(OCPDR, 0xFC0EC51D); + RTL_W32(OCPDR, 0xFC0F73A0); + RTL_W32(OCPDR, 0xFC101300); + RTL_W32(OCPDR, 0xFC11F104); + RTL_W32(OCPDR, 0xFC1273A2); + RTL_W32(OCPDR, 0xFC131300); + RTL_W32(OCPDR, 0xFC14F010); + RTL_W32(OCPDR, 0xFC15C517); + RTL_W32(OCPDR, 0xFC1676A0); + RTL_W32(OCPDR, 0xFC1774A2); + RTL_W32(OCPDR, 0xFC180601); + RTL_W32(OCPDR, 0xFC193720); + RTL_W32(OCPDR, 0xFC1A9EA0); + RTL_W32(OCPDR, 0xFC1B9CA2); + RTL_W32(OCPDR, 0xFC1CC50F); + RTL_W32(OCPDR, 0xFC1D73A2); + RTL_W32(OCPDR, 0xFC1E4023); + RTL_W32(OCPDR, 0xFC1FF813); + RTL_W32(OCPDR, 0xFC20F304); + RTL_W32(OCPDR, 0xFC2173A0); + RTL_W32(OCPDR, 0xFC224033); + RTL_W32(OCPDR, 0xFC23F80F); + RTL_W32(OCPDR, 0xFC24C206); + RTL_W32(OCPDR, 0xFC257340); + RTL_W32(OCPDR, 0xFC2649B7); + RTL_W32(OCPDR, 0xFC27F013); + RTL_W32(OCPDR, 0xFC28C207); + RTL_W32(OCPDR, 0xFC29BA00); + RTL_W32(OCPDR, 0xFC2AC0BC); + RTL_W32(OCPDR, 0xFC2BD2C8); + RTL_W32(OCPDR, 0xFC2CD2CC); + RTL_W32(OCPDR, 0xFC2DC0C4); + RTL_W32(OCPDR, 0xFC2ED2E4); + RTL_W32(OCPDR, 0xFC2F100A); + RTL_W32(OCPDR, 0xFC30104C); + RTL_W32(OCPDR, 0xFC310C7E); + RTL_W32(OCPDR, 0xFC321D02); + RTL_W32(OCPDR, 0xFC33C6F7); + RTL_W32(OCPDR, 0xFC348DC0); + RTL_W32(OCPDR, 0xFC351C01); + RTL_W32(OCPDR, 0xFC36C5F7); + RTL_W32(OCPDR, 0xFC378CA1); + RTL_W32(OCPDR, 0xFC38C6F8); + RTL_W32(OCPDR, 0xFC39BE00); + RTL_W32(OCPDR, 0xFC3AC5F4); + RTL_W32(OCPDR, 0xFC3B74A0); + RTL_W32(OCPDR, 0xFC3C49C0); + RTL_W32(OCPDR, 0xFC3DF010); + RTL_W32(OCPDR, 0xFC3E74A2); + RTL_W32(OCPDR, 0xFC3F76A4); + RTL_W32(OCPDR, 0xFC404034); + RTL_W32(OCPDR, 0xFC41F804); + RTL_W32(OCPDR, 0xFC420601); + RTL_W32(OCPDR, 0xFC439EA4); + RTL_W32(OCPDR, 0xFC44E009); + RTL_W32(OCPDR, 0xFC451D02); + RTL_W32(OCPDR, 0xFC46C4E4); + RTL_W32(OCPDR, 0xFC478D80); + RTL_W32(OCPDR, 0xFC48C5E5); + RTL_W32(OCPDR, 0xFC4964A1); + RTL_W32(OCPDR, 0xFC4A4845); + RTL_W32(OCPDR, 0xFC4B8CA1); + RTL_W32(OCPDR, 0xFC4CE7EC); + RTL_W32(OCPDR, 0xFC4D1C20); + RTL_W32(OCPDR, 0xFC4EC5DC); + RTL_W32(OCPDR, 0xFC4F8CA1); + RTL_W32(OCPDR, 0xFC50C2E1); + RTL_W32(OCPDR, 0xFC51BA00); + RTL_W32(OCPDR, 0xFC521D02); + RTL_W32(OCPDR, 0xFC53C606); + RTL_W32(OCPDR, 0xFC548DC0); + RTL_W32(OCPDR, 0xFC551D20); + RTL_W32(OCPDR, 0xFC568DC0); + RTL_W32(OCPDR, 0xFC57C603); + RTL_W32(OCPDR, 0xFC58BE00); + RTL_W32(OCPDR, 0xFC59C0BC); + RTL_W32(OCPDR, 0xFC5A0E22); + RTL_W32(OCPDR, 0xFC5BC102); + RTL_W32(OCPDR, 0xFC5CB900); + RTL_W32(OCPDR, 0xFC5D02A2); + RTL_W32(OCPDR, 0xFC5EC602); + RTL_W32(OCPDR, 0xFC5FBE00); + RTL_W32(OCPDR, 0xFC600000); + RTL_W32(OCPDR, 0xFC61C602); + RTL_W32(OCPDR, 0xFC62BE00); + RTL_W32(OCPDR, 0xFC630000); + RTL_W32(OCPDR, 0xFC64C602); + RTL_W32(OCPDR, 0xFC65BE00); + RTL_W32(OCPDR, 0xFC660000); + RTL_W32(OCPDR, 0xFC67C602); + RTL_W32(OCPDR, 0xFC68BE00); + RTL_W32(OCPDR, 0xFC690000); + RTL_W32(OCPDR, 0xFC6AC602); + RTL_W32(OCPDR, 0xFC6BBE00); + RTL_W32(OCPDR, 0xFC6C0000); + + RTL_W32(OCPDR, 0xFE138000); + RTL_W32(OCPDR, 0xFE140FD1); + RTL_W32(OCPDR, 0xFE150D21); + RTL_W32(OCPDR, 0xFE16029D); + + /* MDC/MDIO clock speedup */ + RTL_W32(OCPDR, 0xEf080040); +} + +static void rtd119x_hw_phy_config(struct rtl8169_private *tp) +{ + int revision = REVISION_NONE; + const struct soc_device_attribute *soc; + const struct soc_device_attribute rtk_soc_rtd119x[] = { + { + .family = "Realtek Phoenix", + .revision = "A00", + .data = (void *)REVISION_A00, + }, + { + .family = "Realtek Phoenix", + .revision = "A01", + .data = (void *)REVISION_A01, + }, + { + /* empty */ + } + }; + + soc = soc_device_match(rtk_soc_rtd119x); + if (soc) + revision = (uintptr_t)soc->data; + + switch (revision) { + case REVISION_A00: + /* disable green */ + rtl_phy_write(tp, 0x0a43, 0x1b, 0x8011); + rtl_phy_write(tp, 0x0a43, 0x1c, 0x1737); + + /* write abiq /ldvbias */ + rtl_phy_write(tp, 0x0bcc, 0x11, 0x4444); + + /* R/RC auto k */ + /* default ff08 disable auto k RC/R */ + rtl_phy_write(tp, 0x0a43, 0x1b, 0x8013); + rtl_phy_write(tp, 0x0a43, 0x1c, 0x0F08); + + /* force tapbin = 4 */ + rtl_phy_write(tp, 0x0bce, 0x10, 0x4444); + + rtl_phy_write(tp, 0x0bcd, 0x17, 0x8888); /* tx rc */ + rtl_phy_write(tp, 0x0bcd, 0x16, 0x9999); /* rx rc */ + + /* increase sd thd */ + /* master sd : 0x1e00 */ + rtl_phy_write(tp, 0x0a43, 0x1b, 0x8101); + rtl_phy_write(tp, 0x0a43, 0x1c, 0x3E00); + + /* default sd : 0x0e00 */ + rtl_phy_write(tp, 0x0a43, 0x1b, 0x80E2); + rtl_phy_write(tp, 0x0a43, 0x1c, 0x3E00); + + /* slave sd : 0x0e00 */ + rtl_phy_write(tp, 0x0a43, 0x1b, 0x8120); + rtl_phy_write(tp, 0x0a43, 0x1c, 0x3E00); + break; + case REVISION_A01: + /* GDAC updown */ + rtl_phy_write(tp, 0x0bcc, 0x12, 0x00BE); + + /* R_RC */ + /* fbfe [15:8] tapbin tx -3, [7:0] tapbin rx -2 */ + rtl_phy_write(tp, 0x0a43, 0x1b, 0x81DE); + rtl_phy_write(tp, 0x0a43, 0x1c, 0xFDFE); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x81E0); + rtl_phy_write(tp, 0x0a43, 0x1c, 0xFDFF); /* [15:8] rlen -3 */ + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x81E2); + /* [15:8] rlen_100 +4, -3+4=1 */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x0400); + rtl_phy_write(tp, 0x0a43, 0x1b, 0x80d3); + /* fnet cable length constant 0aa4 */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x04a4); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x8111); + /* slave cable length constant fa7f */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x0a7f); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x810d); + /* slave const dagc 0606 */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x5604); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x80f4); + /* master cable length delta 3df7 */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x5df7); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x80f2); + /* master cable length constant fa8f */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x0a8f); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x80f6); + /* master delta dagc 63ca */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x54ca); + + rtl_phy_write(tp, 0x0a43, 0x1b, 0x80ec); + /* master aagc 146c */ + rtl_phy_write(tp, 0x0a43, 0x1c, 0x007c); + + /* disable ALDPS interrupt */ + rtl_phy_write(tp, 0x0a42, 0x12, + rtl_phy_read(tp, 0x0a42, 0x12) & ~BIT(9)); + + /* enable ALDPS */ + rtl_phy_write(tp, 0x0a43, 0x10, + rtl_phy_read(tp, 0x0a43, 0x10) | BIT(2)); + } +} + +static void rtd119x_eee_set(struct rtl8169_private *tp, bool enable) +{ +} + +static void rtd119x_led_set(struct rtl8169_private *tp, bool enable) +{ + struct reset_control *rstc_etn = + reset_control_get_exclusive(&tp->pdev->dev, "rst_etn"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + if (enable) { + /* hold reset bits */ + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + reset_control_assert(rstc_etn); + + /* release reset bits */ + reset_control_deassert(rstc_etn); + reset_control_deassert(rstc_gphy); + reset_control_deassert(rstc_gmac); + + msleep(300); + + regmap_update_bits_base(tp->iso_base, RTD119X_ISO_MUXPAD0, + GENMASK(31, 28), (5 << 28), NULL, false, true); + } else { + regmap_update_bits_base(tp->iso_base, RTD119X_ISO_MUXPAD0, + GENMASK(31, 28), 0, NULL, false, true); + } + + /* release resource */ + reset_control_put(rstc_etn); + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd119x_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ +} + +static void rtd119x_dump_var(struct seq_file *m, struct rtl8169_private *tp) +{ +} + +/******************* END of RTD119X ****************************/ + +/* RTD129X */ +static void rtd129x_mdio_lock(struct rtl8169_private *tp) +{ + /* disable interrupt from PHY to MCU */ + rtl_ocp_write(tp, 0xFC1E, + rtl_ocp_read(tp, 0xFC1E) & ~(BIT(1) | BIT(11) | BIT(12))); +} + +static void rtd129x_mdio_unlock(struct rtl8169_private *tp) +{ + u32 tmp; + + /* enable interrupt from PHY to MCU */ + tmp = rtl_ocp_read(tp, 0xFC1E); + if (tp->output_mode == OUTPUT_RGMII_TO_MAC) + tmp |= (BIT(11) | BIT(12)); /* ignore BIT(1):mac_intr*/ + else + tmp |= (BIT(1) | BIT(11) | BIT(12)); + rtl_ocp_write(tp, 0xFC1E, tmp); +} + +static void rtd129x_reset_phy_gmac(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + if (unlikely(!__clk_is_enabled(clk_etn_sys) || !__clk_is_enabled(clk_etn_250m))) { + /* pre-init clk bits */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* disable clk bits and hold reset bits */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + } + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd129x_pll_clock_init(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + if (likely(__clk_is_enabled(clk_etn_sys) && __clk_is_enabled(clk_etn_250m))) { + /* enable again to prevent clk framework from disabling them */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + } else { + /* 1. reg_0x98007088[10] = 1 */ + /* ISO spec, reset bit of gphy */ + reset_control_deassert(rstc_gphy); + + /* 2. CPU software waiting 200uS */ + usleep_range(200, 210); + + /* 3. reg_0x98007060[1] = 0 */ + /* ISO spec, Ethernet Boot up bypass gphy ready mode */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), 0, NULL, false, true); + + /* 4. reg_0x98007fc0[0] = 0 */ + /* ISO spec, Ethernet Boot up disable dbus clock gating */ + regmap_update_bits_base(tp->iso_base, RTD129X_ISO_DBUS_CTRL, + BIT(0), 0, NULL, false, true); + + /* 5. CPU software waiting 200uS */ + usleep_range(200, 210); + + /* 6. reg_0x9800708c[12:11] = 11 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* 7. reg_0x9800708c[12:11] = 00 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + + /* 8. reg_0x98007088[9] = 1 */ + /* ISO spec, reset bit of gmac */ + reset_control_deassert(rstc_gmac); + + /* 9. reg_0x9800708c[12:11] = 11 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + msleep(100); + } + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd129x_mac_setup(struct rtl8169_private *tp) +{ + unsigned int tmp; + + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + tmp = rtl_ocp_read(tp, 0xea34) & + ~(BIT(0) | BIT(1)); + tmp |= BIT(1); /* MII */ + rtl_ocp_write(tp, 0xea34, tmp); + } else { /* RGMII */ + if (tp->output_mode == OUTPUT_RGMII_TO_PHY) { + /* # ETN spec, MDC freq=2.5MHz */ + tmp = rtl_ocp_read(tp, 0xde30); + rtl_ocp_write(tp, 0xde30, tmp & ~(BIT(6) | BIT(7))); + /* # ETN spec, set external PHY addr */ + tmp = rtl_ocp_read(tp, 0xde24) & ~(0x1F); + rtl_ocp_write(tp, 0xde24, + tmp | (tp->ext_phy_id & 0x1F)); + } + + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(0) | BIT(1)); + tmp |= BIT(0); /* RGMII */ + + if (tp->output_mode == OUTPUT_RGMII_TO_MAC) { + tmp &= ~(BIT(3) | BIT(4)); + tmp |= BIT(4); /* speed: 1G */ + tmp |= BIT(2); /* full duplex */ + } + if (tp->rgmii.rx_delay == RTD129X_RGMII_DELAY_0NS) + tmp &= ~BIT(6); + else + tmp |= BIT(6); + + if (tp->rgmii.tx_delay == RTD129X_RGMII_DELAY_0NS) + tmp &= ~BIT(7); + else + tmp |= BIT(7); + + rtl_ocp_write(tp, 0xea34, tmp); + + /* adjust RGMII voltage */ + switch (tp->rgmii.voltage) { + case RTD129X_VOLTAGE_1_DOT_8V: + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG0, 0); + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG1, 0x44444444); + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG2, 0x24444444); + break; + case RTD129X_VOLTAGE_2_DOT_5V: + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG0, 0); + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG1, 0x44444444); + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG2, 0x64444444); + break; + case RTD129X_VOLTAGE_3_DOT_3V: + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG0, 0x3F); + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG1, 0); + regmap_write(tp->sb2_base, RTD129X_SB2_PFUNC_RG2, 0xA4000000); + } + + /* switch RGMII/MDIO to GMAC */ + regmap_update_bits_base(tp->iso_base, RTD129X_ISO_RGMII_MDIO_TO_GMAC, + BIT(1), BIT(1), NULL, false, true); + + if (tp->output_mode == OUTPUT_RGMII_TO_MAC) { + /* force GMAC link up */ + rtl_ocp_write(tp, 0xde40, 0x30EC); + /* ignore mac_intr from PHY */ + tmp = rtl_ocp_read(tp, 0xfc1e) & ~BIT(1); + rtl_ocp_write(tp, 0xfc1e, tmp); + } + } +} + +static void rtd129x_mac_mcu_patch(struct rtl8169_private *tp) +{ + const struct soc_device_attribute rtk_soc_rtd129x_bxx[] = { + { + .family = "Realtek Kylin", + .revision = "B0*", + }, + { + /* empty */ + } + }; + + /* disable break point */ + rtl_ocp_write(tp, 0xfc28, 0); + rtl_ocp_write(tp, 0xfc2a, 0); + rtl_ocp_write(tp, 0xfc2c, 0); + rtl_ocp_write(tp, 0xfc2e, 0); + rtl_ocp_write(tp, 0xfc30, 0); + rtl_ocp_write(tp, 0xfc32, 0); + rtl_ocp_write(tp, 0xfc34, 0); + rtl_ocp_write(tp, 0xfc36, 0); + mdelay(3); + + /* disable base address */ + rtl_ocp_write(tp, 0xfc26, 0); + + /* patch code */ + rtl_ocp_write(tp, 0xf800, 0xE008); + rtl_ocp_write(tp, 0xf802, 0xE012); + rtl_ocp_write(tp, 0xf804, 0xE044); + rtl_ocp_write(tp, 0xf806, 0xE046); + rtl_ocp_write(tp, 0xf808, 0xE048); + rtl_ocp_write(tp, 0xf80a, 0xE04A); + rtl_ocp_write(tp, 0xf80c, 0xE04C); + rtl_ocp_write(tp, 0xf80e, 0xE04E); + rtl_ocp_write(tp, 0xf810, 0x44E3); + rtl_ocp_write(tp, 0xf812, 0xC708); + rtl_ocp_write(tp, 0xf814, 0x75E0); + rtl_ocp_write(tp, 0xf816, 0x485D); + rtl_ocp_write(tp, 0xf818, 0x9DE0); + rtl_ocp_write(tp, 0xf81a, 0xC705); + rtl_ocp_write(tp, 0xf81c, 0xC502); + rtl_ocp_write(tp, 0xf81e, 0xBD00); + rtl_ocp_write(tp, 0xf820, 0x01EE); + rtl_ocp_write(tp, 0xf822, 0xE85A); + rtl_ocp_write(tp, 0xf824, 0xE000); + rtl_ocp_write(tp, 0xf826, 0xC72D); + rtl_ocp_write(tp, 0xf828, 0x76E0); + rtl_ocp_write(tp, 0xf82a, 0x49ED); + rtl_ocp_write(tp, 0xf82c, 0xF026); + rtl_ocp_write(tp, 0xf82e, 0xC02A); + rtl_ocp_write(tp, 0xf830, 0x7400); + rtl_ocp_write(tp, 0xf832, 0xC526); + rtl_ocp_write(tp, 0xf834, 0xC228); + rtl_ocp_write(tp, 0xf836, 0x9AA0); + rtl_ocp_write(tp, 0xf838, 0x73A2); + rtl_ocp_write(tp, 0xf83a, 0x49BE); + rtl_ocp_write(tp, 0xf83c, 0xF11E); + rtl_ocp_write(tp, 0xf83e, 0xC324); + rtl_ocp_write(tp, 0xf840, 0x9BA2); + rtl_ocp_write(tp, 0xf842, 0x73A2); + rtl_ocp_write(tp, 0xf844, 0x49BE); + rtl_ocp_write(tp, 0xf846, 0xF0FE); + rtl_ocp_write(tp, 0xf848, 0x73A2); + rtl_ocp_write(tp, 0xf84a, 0x49BE); + rtl_ocp_write(tp, 0xf84c, 0xF1FE); + rtl_ocp_write(tp, 0xf84e, 0x1A02); + rtl_ocp_write(tp, 0xf850, 0x49C9); + rtl_ocp_write(tp, 0xf852, 0xF003); + rtl_ocp_write(tp, 0xf854, 0x4821); + rtl_ocp_write(tp, 0xf856, 0xE002); + rtl_ocp_write(tp, 0xf858, 0x48A1); + rtl_ocp_write(tp, 0xf85a, 0x73A2); + rtl_ocp_write(tp, 0xf85c, 0x49BE); + rtl_ocp_write(tp, 0xf85e, 0xF10D); + rtl_ocp_write(tp, 0xf860, 0xC313); + rtl_ocp_write(tp, 0xf862, 0x9AA0); + rtl_ocp_write(tp, 0xf864, 0xC312); + rtl_ocp_write(tp, 0xf866, 0x9BA2); + rtl_ocp_write(tp, 0xf868, 0x73A2); + rtl_ocp_write(tp, 0xf86a, 0x49BE); + rtl_ocp_write(tp, 0xf86c, 0xF0FE); + rtl_ocp_write(tp, 0xf86e, 0x73A2); + rtl_ocp_write(tp, 0xf870, 0x49BE); + rtl_ocp_write(tp, 0xf872, 0xF1FE); + rtl_ocp_write(tp, 0xf874, 0x48ED); + rtl_ocp_write(tp, 0xf876, 0x9EE0); + rtl_ocp_write(tp, 0xf878, 0xC602); + rtl_ocp_write(tp, 0xf87a, 0xBE00); + rtl_ocp_write(tp, 0xf87c, 0x0532); + rtl_ocp_write(tp, 0xf87e, 0xDE00); + rtl_ocp_write(tp, 0xf880, 0xE85A); + rtl_ocp_write(tp, 0xf882, 0xE086); + rtl_ocp_write(tp, 0xf884, 0x0A44); + rtl_ocp_write(tp, 0xf886, 0x801F); + rtl_ocp_write(tp, 0xf888, 0x8015); + rtl_ocp_write(tp, 0xf88a, 0x0015); + rtl_ocp_write(tp, 0xf88c, 0xC602); + rtl_ocp_write(tp, 0xf88e, 0xBE00); + rtl_ocp_write(tp, 0xf890, 0x0000); + rtl_ocp_write(tp, 0xf892, 0xC602); + rtl_ocp_write(tp, 0xf894, 0xBE00); + rtl_ocp_write(tp, 0xf896, 0x0000); + rtl_ocp_write(tp, 0xf898, 0xC602); + rtl_ocp_write(tp, 0xf89a, 0xBE00); + rtl_ocp_write(tp, 0xf89c, 0x0000); + rtl_ocp_write(tp, 0xf89e, 0xC602); + rtl_ocp_write(tp, 0xf8a0, 0xBE00); + rtl_ocp_write(tp, 0xf8a2, 0x0000); + rtl_ocp_write(tp, 0xf8a4, 0xC602); + rtl_ocp_write(tp, 0xf8a6, 0xBE00); + rtl_ocp_write(tp, 0xf8a8, 0x0000); + rtl_ocp_write(tp, 0xf8aa, 0xC602); + rtl_ocp_write(tp, 0xf8ac, 0xBE00); + rtl_ocp_write(tp, 0xf8ae, 0x0000); + + /* enable base address */ + rtl_ocp_write(tp, 0xfc26, 0x8000); + + /* enable breakpoint */ + rtl_ocp_write(tp, 0xfc28, 0x01ED); + rtl_ocp_write(tp, 0xfc2a, 0x0531); + + if (tp->eee_enable) { + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) | (BIT(1) | BIT(0))); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) | BIT(1)); + /* enable EEE of 10Mbps */ + rtl_patchphy(tp, 0x0a43, 25, BIT(4)); + } + + if (soc_device_match(rtk_soc_rtd129x_bxx)) + rtd129x_mac_setup(tp); +} + +static void rtd129x_hw_phy_config(struct rtl8169_private *tp) +{ + /* enable ALDPS mode */ + rtl_w1w0_phy(tp, 0x0a43, 24, BIT(2), BIT(12) | BIT(1) | BIT(0)); +} + +static void rtd129x_eee_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + rtl_mmd_write(tp, 0x7, 0x3c, 0x6); + + /* turn on EEE */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) | BIT(1) | BIT(0)); + /* turn on EEE+ */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) | BIT(1)); + } else { + rtl_mmd_write(tp, 0x7, 0x3c, 0); + + /* turn off EEE */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) & ~(BIT(1) | BIT(0))); + /* turn off EEE+ */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) & ~BIT(1)); + } +} + +static void rtd129x_led_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + regmap_update_bits_base(tp->iso_base, RTD129X_ISO_MUXPAD0, + GENMASK(29, 26), (5 << 26), NULL, false, true); + } else { + regmap_update_bits_base(tp->iso_base, RTD129X_ISO_MUXPAD0, + GENMASK(29, 26), 0, NULL, false, true); + } +} + +static void rtd129x_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + u32 val; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + seq_printf(m, "ISO_UMSK_ISR\t[0x98007004] = %08x\n", val); + regmap_read(tp->iso_base, ISO_PWRCUT_ETN, &val); + seq_printf(m, "ISO_PWRCUT_ETN\t[0x9800705c] = %08x\n", val); + regmap_read(tp->iso_base, ISO_ETN_TESTIO, &val); + seq_printf(m, "ISO_ETN_TESTIO\t[0x98007060] = %08x\n", val); + regmap_read(tp->iso_base, ISO_SOFT_RESET, &val); + seq_printf(m, "ETN_RESET_CTRL\t[0x98007088] = %08x\n", val); + regmap_read(tp->iso_base, ISO_CLOCK_ENABLE, &val); + seq_printf(m, "ETN_CLK_CTRL\t[0x9800708c] = %08x\n", val); +} + +static void rtd129x_dump_var(struct seq_file *m, struct rtl8169_private *tp) +{ + seq_printf(m, "rgmii_voltage\t%d\n", tp->rgmii.voltage); + seq_printf(m, "rgmii_tx_delay\t%d\n", tp->rgmii.tx_delay); + seq_printf(m, "rgmii_rx_delay\t%d\n", tp->rgmii.rx_delay); +} + +/******************* END of RTD129X ****************************/ + +/* RTD139X */ +#define MDIO_WAIT_TIMEOUT 100 +static void rtd139x_mdio_lock(struct rtl8169_private *tp) +{ + u32 wait_cnt = 0; + u32 log_de4e = 0; + + /* disable EEE IMR */ + rtl_ocp_write(tp, 0xE044, + rtl_ocp_read(tp, 0xE044) & + ~(BIT(3) | BIT(2) | BIT(1) | BIT(0))); + /* disable timer 2 */ + rtl_ocp_write(tp, 0xE404, + rtl_ocp_read(tp, 0xE404) | BIT(9)); + /* wait MDIO channel is free */ + log_de4e = BIT(0) & rtl_ocp_read(tp, 0xDE4E); + log_de4e = (log_de4e << 1) | + (BIT(0) & rtl_ocp_read(tp, 0xDE4E)); + /* check if 0 for continuous 2 times */ + while (0 != (((0x1 << 2) - 1) & log_de4e)) { + wait_cnt++; + udelay(1); + log_de4e = (log_de4e << 1) | (BIT(0) & + rtl_ocp_read(tp, 0xDE4E)); + if (wait_cnt > MDIO_WAIT_TIMEOUT) + break; + } + /* enter driver mode */ + rtl_ocp_write(tp, 0xDE42, rtl_ocp_read(tp, 0xDE42) | BIT(0)); + if (wait_cnt > MDIO_WAIT_TIMEOUT) + pr_err(PFX "%s:%d: MDIO lock failed\n", __func__, __LINE__); +} + +static void rtd139x_mdio_unlock(struct rtl8169_private *tp) +{ + /* exit driver mode */ + rtl_ocp_write(tp, 0xDE42, rtl_ocp_read(tp, 0xDE42) & ~BIT(0)); + /* enable timer 2 */ + rtl_ocp_write(tp, 0xE404, + rtl_ocp_read(tp, 0xE404) & ~BIT(9)); + /* enable EEE IMR */ + rtl_ocp_write(tp, 0xE044, + rtl_ocp_read(tp, 0xE044) | BIT(3) | BIT(2) | BIT(1) | + BIT(0)); +} + +static void rtd139x_reset_phy_gmac(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + struct clk *clk_en_sds = NULL; + struct reset_control *rstc_sds_reg = NULL; + struct reset_control *rstc_sds = NULL; + struct reset_control *rstc_pcie0_power = NULL; + struct reset_control *rstc_pcie0_phy = NULL; + struct reset_control *rstc_pcie0_sgmii_mdio = NULL; + struct reset_control *rstc_pcie0_phy_mdio = NULL; + + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* reg_0x9800708c[12:11] = 00 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + + /* reg_0x98007088[10:9] = 00 */ + /* ISO spec, rstn_gphy & rstn_gmac */ + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x9800705c = 0x00616703 */ + /* ISO spec, default value */ + regmap_write(tp->iso_base, ISO_PWRCUT_ETN, 0x00616703); + + /* RESET for SGMII if needed */ + if (tp->output_mode != OUTPUT_EMBEDDED_PHY) { + clk_en_sds = clk_get(&tp->pdev->dev, "sds"); + rstc_sds_reg = reset_control_get_exclusive(&tp->pdev->dev, + "sds_reg"); + rstc_sds = reset_control_get_exclusive(&tp->pdev->dev, "sds"); + rstc_pcie0_power = + reset_control_get_exclusive(&tp->pdev->dev, + "pcie0_power"); + rstc_pcie0_phy = + reset_control_get_exclusive(&tp->pdev->dev, + "pcie0_phy"); + rstc_pcie0_sgmii_mdio = + reset_control_get_exclusive(&tp->pdev->dev, + "pcie0_sgmii_mdio"); + rstc_pcie0_phy_mdio = + reset_control_get_exclusive(&tp->pdev->dev, + "pcie0_phy_mdio"); + + clk_prepare_enable(clk_en_sds); + + /* reg_0x9800000c[7] = 0 */ + /* CRT spec, clk_en_sds */ + clk_disable_unprepare(clk_en_sds); + + /* reg_0x98000000[4:3] = 00 */ + /* CRT spec, rstn_sds_reg & rstn_sds */ + reset_control_assert(rstc_sds); + reset_control_assert(rstc_sds_reg); + + /* reg_0x98000004[7] = 0 */ + /* reg_0x98000004[14] = 0 */ + /* CRT spec, rstn_pcie0_power & rstn_pcie0_phy */ + reset_control_assert(rstc_pcie0_power); + reset_control_assert(rstc_pcie0_phy); + + /* reg_0x98000050[13] = 0 */ + /* reg_0x98000050[16] = 0 */ + /* CRT spec, rstn_pcie0_sgmii_mdio & rstn_pcie0_phy_mdio */ + reset_control_assert(rstc_pcie0_sgmii_mdio); + reset_control_assert(rstc_pcie0_phy_mdio); + + reset_control_put(rstc_sds_reg); + reset_control_put(rstc_sds); + reset_control_put(rstc_pcie0_power); + reset_control_put(rstc_pcie0_phy); + reset_control_put(rstc_pcie0_sgmii_mdio); + reset_control_put(rstc_pcie0_phy_mdio); + } + + mdelay(1); + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd139x_acp_init(struct rtl8169_private *tp) +{ + u32 tmp; + u32 val; + + /* SBX spec, Select ETN access DDR path. */ + if (tp->acp_enable) { + /* reg_0x9801c20c[6] = 1 */ + /* SBX spec, Mask ETN_ALL to SB3 DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD139X_SBX_SB3_CHANNEL_REQ_MASK, + BIT(6), BIT(6), NULL, false, true); + + pr_info(PFX "wait all SB3 access finished..."); + tmp = 0; + regmap_read(tp->sbx_base, RTD139X_SBX_SB3_CHANNEL_REQ_BUSY, &val); + while ((val & BIT(6)) != 0) { + mdelay(1); + tmp += 1; + if (tmp >= 100) { + pr_err("\n wait SB3 access failed (wait %d ms)\n", + tmp); + break; + } + regmap_read(tp->sbx_base, RTD139X_SBX_SB3_CHANNEL_REQ_BUSY, &val); + } + if (tmp < 100) + pr_info("done.\n"); + + /* reg_0x9801d100[29] = 0 */ + /* SCPU wrapper spec, CLKACP division, 0 = div 2, 1 = div 3 */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_CRT_CTRL, + BIT(29), 0, NULL, false, true); + + /* reg_0x9801d124[1:0] = 00 */ + /* SCPU wrapper spec, ACP master active, 0 = active */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_INTERFACE_EN, + GENMASK(1, 0), 0, NULL, false, true); + + /* reg_0x9801d100[30] = 1 */ + /* SCPU wrapper spec, dy_icg_en_acp */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_CRT_CTRL, + BIT(30), BIT(30), NULL, false, true); + + /* reg_0x9801d100[21] = 1 */ + /* SCPU wrapper spec, ACP CLK enable */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_CRT_CTRL, + BIT(21), BIT(21), NULL, false, true); + + /* reg_0x9801d100[14] = 1 */ + /* Do not apply reset to ACP port axi3 master */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_CRT_CTRL, + BIT(14), BIT(14), NULL, false, true); + + /* reg_0x9801d800[3:0] = 0111 */ + /* reg_0x9801d800[7:4] = 0111 */ + /* reg_0x9801d800[9] = 1 */ + /* reg_0x9801d800[20:16] = 01100 */ + /* reg_0x9801d800[28:24] = 01110 */ + /* Configure control of ACP port */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_ACP_CTRL, + GENMASK(28, 24) | GENMASK(20, 16) | + BIT(9) | GENMASK(7, 4) | GENMASK(3, 0), + (0x0e << 24) | (0x0c << 16) | BIT(9) | + (0x7 << 4) | (0x7 << 0), + NULL, false, true); + + /* reg_0x9801d030[28] = 1 */ + /* SCPU wrapper spec, dy_icg_en_acp */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_ACP_CRT_CTRL, + BIT(28), BIT(28), NULL, false, true); + + /* reg_0x9801d030[16] = 1 */ + /* SCPU wrapper spec, ACP CLK Enable for acp of scpu_chip_top */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_ACP_CRT_CTRL, + BIT(16), BIT(16), NULL, false, true); + + /* reg_0x9801d030[0] = 1 */ + /* Do not apply reset to ACP port axi3 master */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD139X_SC_WRAP_ACP_CRT_CTRL, + BIT(0), BIT(0), NULL, false, true); + + /* reg_0x9801c814[17] = 1 */ + /* through ACP to SCPU_ACP */ + regmap_update_bits_base(tp->sbx_base, RTD139X_SBX_ACP_MISC_CTRL, + BIT(17), BIT(17), NULL, false, true); + + pr_info(PFX "ARM ACP on\n."); + } +} + +static void rtd139x_pll_clock_init(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + /* reg_0x98007004[27] = 1 */ + /* ISO spec, ETN_PHY_INTR, clear ETN interrupt for ByPassMode */ + regmap_write(tp->iso_base, ISO_UMSK_ISR, BIT(27)); + + /* reg_0x98007088[10] = 1 */ + /* ISO spec, reset bit of gphy */ + reset_control_deassert(rstc_gphy); + + mdelay(1); /* wait 1ms for PHY PLL stable */ + + /* In Hercules, EPHY need choose the bypass mode or Non-bypass mode */ + /* Bypass mode : ETN MAC bypass efuse update flow. + * SW need to take this sequence. + */ + /* Non-Bypass mode : ETN MAC set efuse update and efuse_rdy setting */ + /* Default : Bypass mode (0x9800_7060[1] = 1'b1) */ + if (!tp->bypass_enable) { + /* reg_0x98007060[1] = 0 */ + /* ISO spec, bypass mode disable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), 0, NULL, false, true); + } else { + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + /* bypass mode, SW need to handle the EPHY Status check , + * EFUSE data update and EPHY fuse_rdy setting. + */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + } + + /* reg_0x98007088[9] = 1 */ + /* ISO spec, reset bit of gmac */ + reset_control_deassert(rstc_gmac); + + /* reg_0x9800708c[12:11] = 11 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + mdelay(10); /* wait 10ms for GMAC uC to be stable */ + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +/* Hercules only uses 13 bits in OTP 0x9801_72C8[12:8] and 0x9801_72D8[7:0] + * if 0x9801_72C8[12] is 1, then + * 0x9801_72C8[11:8] (R-calibration) is used to set PHY + * 0x9801_72D8[7:0] is used to set idac_fine for PHY + */ +static void rtd139x_load_otp_content(struct rtl8169_private *tp) +{ + u32 otp; + u16 tmp; + u8 *buf; + + buf = r8169soc_read_otp(tp, "para"); + if (IS_ERR(buf)) + goto set_idac; + + otp = *buf; + /* OTP[4] = valid flag, OTP[3:0] = content */ + if (0 != ((0x1 << 4) & otp)) { + /* frc_r_value_default = 0x8 */ + tmp = otp ^ RTD139X_R_K_DEFAULT; + rtl_phy_write(tp, 0x0bc0, 20, + tmp | (rtl_phy_read(tp, 0x0bc0, 20) & ~(0x1f << 0))); + } + + kfree(buf); + +set_idac: + + buf = r8169soc_read_otp(tp, "idac"); + if (IS_ERR(buf)) + return; + + otp = *buf; + tmp = otp ^ RTD139X_IDAC_FINE_DEFAULT; /* IDAC_FINE_DEFAULT = 0x33 */ + rtl_phy_write(tp, 0x0bc0, 23, + tmp | (rtl_phy_read(tp, 0x0bc0, 23) & ~(0xff << 0))); + + kfree(buf); +} + +static u32 rtd139x_serdes_init(struct rtl8169_private *tp) +{ + u32 stable_ticks; + u32 tmp; + u32 val; + struct clk *clk_en_sds = clk_get(&tp->pdev->dev, "sds"); + struct reset_control *rstc_sds_reg = + reset_control_get_exclusive(&tp->pdev->dev, "sds_reg"); + struct reset_control *rstc_sds = + reset_control_get_exclusive(&tp->pdev->dev, "sds"); + struct reset_control *rstc_pcie0_power = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_power"); + struct reset_control *rstc_pcie0_phy = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_phy"); + struct reset_control *rstc_pcie0_sgmii_mdio = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_sgmii_mdio"); + struct reset_control *rstc_pcie0_phy_mdio = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_phy_mdio"); + + /* reg_0x98000000[4:3] = 11 */ + /* CRT spec, rstn_sds_reg & rstn_sds */ + reset_control_deassert(rstc_sds); + reset_control_deassert(rstc_sds_reg); + + /* reg_0x98000004[7] = 1 */ + /* reg_0x98000004[14] = 1 */ + /* CRT spec, rstn_pcie0_power & rstn_pcie0_phy */ + reset_control_deassert(rstc_pcie0_power); + reset_control_deassert(rstc_pcie0_phy); + + /* reg_0x98000050[13] = 1 */ + /* reg_0x98000050[16] = 1 */ + /* CRT spec, rstn_pcie0_sgmii_mdio & rstn_pcie0_phy_mdio */ + reset_control_deassert(rstc_pcie0_sgmii_mdio); + reset_control_deassert(rstc_pcie0_phy_mdio); + + /* reg_0x9800000c[7] = 1 */ + /* CRT spec, clk_en_sds */ + clk_prepare_enable(clk_en_sds); + + /* reg_0x9800705c[6] = 1 */ + /* ISO spec, set PCIE channel to SGMII */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(6), BIT(6), NULL, false, true); + + /* reg_0x9800705c[7] = 1 */ + /* ISO spec, set internal MDIO to PCIE */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(7), BIT(7), NULL, false, true); + + /* ### Beginning of SGMII DPHY register tuning ### */ + /* reg_0x9800705c[20:16] = 00000 */ + /* ISO spec, set internal PHY addr to SERDES_DPHY_0 */ + __int_set_phy_addr(tp, RTD139X_SERDES_DPHY_0); + + /* # DPHY spec, DPHY reg13[8:7]=00, choose 1.25GHz */ + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x0d, + int_mdio_read(tp, CURRENT_MDIO_PAGE, 0x0d) & ~(BIT(8) | BIT(7))); + + /* # DPHY spec, 5GHz tuning */ + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x4, 0x52f5); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x5, 0xead7); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x6, 0x0010); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0xa, 0xc653); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0xa830); + + /* reg_0x9800705c[20:16] = 00001 */ + /* ISO spec, set internal PHY addr to SERDES_DPHY_1 */ + __int_set_phy_addr(tp, RTD139X_SERDES_DPHY_1); + + /* RTD139X_TX_SWING_1040MV */ + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x0, 0xd4aa); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0x88aa); + + /* reg_0x9800705c[20:16] = 00001 */ + /* ISO spec, set internal PHY addr to INT_PHY_ADDR */ + __int_set_phy_addr(tp, RTD139X_INT_PHY_ADDR); + + tp->ext_phy = true; + mdelay(10); /* wait for clock stable */ + /* ext_phy == true now */ + + /* reg_0x981c8070[9:0] = 0000000110 */ + /* SDS spec, set SP_CFG_SDS_DBG_SEL to get PHY_Ready */ + regmap_update_bits_base(tp->sds_base, RTD139X_SDS_REG28, + GENMASK(9, 0), (0x006 << 0), NULL, false, true); + + tmp = 0; + stable_ticks = 0; + while (stable_ticks < 10) { + /* # SDS spec, wait for phy ready */ + regmap_read(tp->sds_base, RTD139X_SDS_REG29, &val); + while ((val & BIT(14)) == 0) { + stable_ticks = 0; + if (tmp >= 100) { + stable_ticks = 10; + pr_err(PFX "SGMII PHY not ready in 100ms\n"); + break; + } + regmap_read(tp->sds_base, RTD139X_SDS_REG29, &val); + } + stable_ticks++; + tmp++; + mdelay(1); + } + pr_info(PFX "SGMII PHY is ready in %d ms", tmp); + + /* reg_0x9800705c[4] = 1 */ + /* ISO spec, set data path to SGMII */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(4), BIT(4), NULL, false, true); + + /* reg_0x981c8008[9:8] = 00 */ + /* # SDS spec, SP_SDS_FRC_AN, SERDES auto mode */ + regmap_update_bits_base(tp->sds_base, RTD139X_SDS_REG02, + GENMASK(9, 8), 0, NULL, false, true); + + /* # SDS spec, wait for SERDES link up */ + tmp = 0; + stable_ticks = 0; + while (stable_ticks < 10) { + regmap_read(tp->sds_base, RTD139X_SDS_MISC, &val); + while ((val & GENMASK(13, 12)) != GENMASK(13, 12)) { + stable_ticks = 0; + if (tmp >= 100) { + stable_ticks = 10; + pr_err(PFX "SGMII link down in 100ms\n"); + break; + } + regmap_read(tp->sds_base, RTD139X_SDS_MISC, &val); + } + stable_ticks++; + tmp++; + mdelay(1); + } + pr_info(PFX "SGMII link up in %d ms", tmp); + + reset_control_put(rstc_sds_reg); + reset_control_put(rstc_sds); + reset_control_put(rstc_pcie0_power); + reset_control_put(rstc_pcie0_phy); + reset_control_put(rstc_pcie0_sgmii_mdio); + reset_control_put(rstc_pcie0_phy_mdio); + return 0; +} + +static void rtd139x_phy_iol_tuning(struct rtl8169_private *tp) +{ + int revision = REVISION_NONE; + const struct soc_device_attribute *soc; + const struct soc_device_attribute rtk_soc_rtd139x[] = { + { + .family = "Realtek Hercules", + .revision = "A00", + .data = (void *)REVISION_A00, + }, + { + .family = "Realtek Hercules", + .revision = "A01", + .data = (void *)REVISION_A01, + }, + { + .family = "Realtek Hercules", + .revision = "A02", + .data = (void *)REVISION_A02, + }, + { + /* empty */ + } + }; + + soc = soc_device_match(rtk_soc_rtd139x); + if (soc) + revision = (uintptr_t)soc->data; + + switch (revision) { + case REVISION_A00: /* TSMC, cut A */ + case REVISION_A01: /* TSMC, cut B */ + /* idacfine */ + int_mdio_write(tp, 0x0bc0, 23, 0x0088); + + /* abiq */ + int_mdio_write(tp, 0x0bc0, 21, 0x0004); + + /* ldvbias */ + int_mdio_write(tp, 0x0bc0, 22, 0x0777); + + /* iatt */ + int_mdio_write(tp, 0x0bd0, 16, 0x0300); + + /* vcm_ref, cf_l */ + int_mdio_write(tp, 0x0bd0, 17, 0xe8ca); + break; + case REVISION_A02: /* UMC, cut C */ + /* 100M Swing */ + /* idac_fine_mdix, idac_fine_mdi */ + int_mdio_write(tp, 0x0bc0, 23, 0x0044); + + /* 100M Tr/Tf */ + /* abiq_10m=0x0, abiq_100m_short=0x4, abiq_normal=0x6 */ + int_mdio_write(tp, 0x0bc0, 21, 0x0046); + + /* 10M */ + /* ldvbias_10m=0x7, ldvbias_10m_short=0x4, ldvbias_normal=0x4 */ + int_mdio_write(tp, 0x0bc0, 22, 0x0744); + + /* vcmref=0x0, cf_l=0x3 */ + int_mdio_write(tp, 0x0bd0, 17, 0x18ca); + + /* iatt=0x2 */ + int_mdio_write(tp, 0x0bd0, 16, 0x0200); + break; + + /* default: */ + } +} + +static void rtd139x_mdio_init(struct rtl8169_private *tp) +{ + u32 tmp; + u32 val; + struct pinctrl *p_sgmii_mdio; + struct pinctrl_state *ps_sgmii_mdio; + void __iomem *ioaddr = tp->mmio_addr; + + /* ETN_PHY_INTR, wait interrupt from PHY and it means MDIO is ready */ + tmp = 0; + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + while ((val & BIT(27)) == 0) { + tmp += 1; + mdelay(1); + if (tmp >= 100) { + pr_err(PFX "PHY PHY_Status timeout.\n"); + break; + } + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + } + pr_info(PFX "wait %d ms for PHY interrupt. UMSK_ISR = 0x%x\n", tmp, val); + + /* In Hercules ByPass mode, + * SW need to handle the EPHY Status check , + * OTP data update and EPHY fuse_rdy setting. + */ + if (tp->bypass_enable) { + /* PHY will stay in state 1 mode */ + tmp = 0; + while (0x1 != (int_mdio_read(tp, 0x0a42, 16) & 0x07)) { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x1 in bypass mode, current = 0x%02x\n", + (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } + + /* adjust FE PHY electrical characteristics */ + rtd139x_phy_iol_tuning(tp); + + /* 1. read OTP 0x9801_72C8[12:8] + * 2. xor 0x08 + * 3. set value to PHY registers to correct R-calibration + * 4. read OTP 0x9801_72D8[7:0] + * 5. xor 0x33 + * 6. set value to PHY registers to correct AMP + */ + rtd139x_load_otp_content(tp); + + /* fill fuse_rdy & rg_ext_ini_done */ + int_mdio_write(tp, 0x0a46, 20, + (int_mdio_read(tp, 0x0a46, 20) | (BIT(1) | BIT(0)))); + } else { + /* adjust FE PHY electrical characteristics */ + rtd139x_phy_iol_tuning(tp); + } + + /* init_autoload_done = 1 */ + tmp = rtl_ocp_read(tp, 0xe004); + tmp |= BIT(7); + rtl_ocp_write(tp, 0xe004, tmp); + /* ee_mode = 3 */ + RTL_W8(CFG9346, CFG9346_UNLOCK); + + /* wait LAN-ON */ + tmp = 0; + do { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x3, current = 0x%02x\n", + (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } while (0x3 != (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + pr_info(PFX "wait %d ms for PHY ready, current = 0x%x\n", + tmp, int_mdio_read(tp, 0x0a42, 16)); + + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* Init PHY path */ + /* reg_0x9800705c[5] = 0 */ + /* reg_0x9800705c[7] = 0 */ + /* ISO spec, set internal MDIO to access PHY */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(7) | BIT(5), 0, NULL, false, true); + + /* reg_0x9800705c[4] = 0 */ + /* ISO spec, set data path to access PHY */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(4), 0, NULL, false, true); + + /* # ETN spec, GMAC data path select MII-like(embedded GPHY), + * not SGMII(external PHY) + */ + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(0) | BIT(1)); + tmp |= BIT(1); /* MII */ + rtl_ocp_write(tp, 0xea34, tmp); + } else { + /* SGMII */ + /* # ETN spec, adjust MDC freq=2.5MHz */ + rtl_ocp_write(tp, 0xDE30, + rtl_ocp_read(tp, 0xDE30) & ~(BIT(7) | BIT(6))); + /* # ETN spec, set external PHY addr */ + rtl_ocp_write(tp, 0xDE24, + ((rtl_ocp_read(tp, 0xDE24) & ~(0x1f << 0)) | + (tp->ext_phy_id & 0x1f))); + /* ISO mux spec, GPIO29 is set to MDC pin */ + /* ISO mux spec, GPIO46 is set to MDIO pin */ + p_sgmii_mdio = devm_pinctrl_get(&tp->pdev->dev); + ps_sgmii_mdio = pinctrl_lookup_state(p_sgmii_mdio, "sgmii"); + pinctrl_select_state(p_sgmii_mdio, ps_sgmii_mdio); + + /* check if external PHY is available */ + pr_info(PFX "Searching external PHY..."); + tp->ext_phy = true; + tmp = 0; + while (ext_mdio_read(tp, 0x0a43, 31) != 0x0a43) { + pr_info("."); + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err("\n External SGMII PHY not found, current = 0x%02x\n", + ext_mdio_read(tp, 0x0a43, 31)); + break; + } + } + if (tmp < 2000) + pr_info("found.\n"); + + /* lower SGMII TX swing of RTL8211FS to reduce EMI */ + /* TX swing = 470mV, default value */ + ext_mdio_write(tp, 0x0dcd, 16, 0x104e); + + tp->ext_phy = false; + + /* # ETN spec, GMAC data path select SGMII(external PHY), + * not MII-like(embedded GPHY) + */ + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(0) | BIT(1)); + tmp |= BIT(1) | BIT(0); /* SGMII */ + rtl_ocp_write(tp, 0xea34, tmp); + + if (rtd139x_serdes_init(tp) != 0) + pr_err(PFX "SERDES init failed\n"); + /* ext_phy == true now */ + + /* SDS spec, auto update SGMII link capability */ + regmap_update_bits_base(tp->sds_base, RTD139X_SDS_LINK, + BIT(2), BIT(2), NULL, false, true); + } +} + +static void rtd139x_eee_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + tp->chip->mdio_lock(tp); + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* 100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, BIT(1)); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | BIT(4) | BIT(2)); + /* disable dynamic RX power in PHY */ + rtl_phy_write(tp, 0x0bd0, 21, + (rtl_phy_read(tp, 0x0bd0, 21) & ~BIT(8)) | BIT(9)); + } else { /* SGMII */ + /* 1000M & 100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, (BIT(2) | BIT(1))); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | BIT(4) | BIT(2)); + } + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) | BIT(1) | BIT(0)); + /* EEE+ MAC mode */ + /* timer to wait FEPHY ready */ + rtl_ocp_write(tp, 0xe08a, 0x00a7); + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) | BIT(1)); + } else { + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* no EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + } else { /* SGMII */ + /* no EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + } + /* reset to default value */ + rtl_ocp_write(tp, 0xe040, rtl_ocp_read(tp, 0xe040) | BIT(13)); + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) & ~(BIT(1) | BIT(0))); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) & ~BIT(1)); + rtl_ocp_write(tp, 0xe08a, 0x003f); /* default value */ + } +} + +static void rtd139x_led_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + regmap_update_bits_base(tp->pinctrl_base, RTD139X_ISO_TESTMUX_MUXPAD1, + GENMASK(7, 4), (5 << 4), NULL, false, true); + } else { + regmap_update_bits_base(tp->pinctrl_base, RTD139X_ISO_TESTMUX_MUXPAD1, + GENMASK(7, 4), 0, NULL, false, true); + } +} + +static void rtd139x_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + u32 val; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + seq_printf(m, "ISO_UMSK_ISR\t[0x98007004] = %08x\n", val); + regmap_read(tp->iso_base, ISO_PWRCUT_ETN, &val); + seq_printf(m, "ISO_PWRCUT_ETN\t[0x9800705c] = %08x\n", val); + regmap_read(tp->iso_base, ISO_ETN_TESTIO, &val); + seq_printf(m, "ISO_ETN_TESTIO\t[0x98007060] = %08x\n", val); + regmap_read(tp->iso_base, ISO_SOFT_RESET, &val); + seq_printf(m, "ETN_RESET_CTRL\t[0x98007088] = %08x\n", val); + regmap_read(tp->iso_base, ISO_CLOCK_ENABLE, &val); + seq_printf(m, "ETN_CLK_CTRL\t[0x9800708c] = %08x\n", val); + if (tp->output_mode != OUTPUT_EMBEDDED_PHY) { + regmap_read(tp->sds_base, RTD139X_SDS_REG02, &val); + seq_printf(m, "SDS_REG02\t[0x981c8008] = %08x\n", val); + regmap_read(tp->sds_base, RTD139X_SDS_REG28, &val); + seq_printf(m, "SDS_REG28\t[0x981c8070] = %08x\n", val); + regmap_read(tp->sds_base, RTD139X_SDS_REG29, &val); + seq_printf(m, "SDS_REG29\t[0x981c8074] = %08x\n", val); + regmap_read(tp->sds_base, RTD139X_SDS_MISC, &val); + seq_printf(m, "SDS_MISC\t\t[0x981c9804] = %08x\n", val); + regmap_read(tp->sds_base, RTD139X_SDS_LINK, &val); + seq_printf(m, "SDS_LINK\t\t[0x981c9810] = %08x\n", val); + } +} + +static void rtd139x_dump_var(struct seq_file *m, struct rtl8169_private *tp) +{ + seq_printf(m, "bypass_enable\t%d\n", tp->bypass_enable); +} + +/******************* END of RTD139X ****************************/ + +/* RTD16XX */ +static void rtd16xx_mdio_lock(struct rtl8169_private *tp) +{ + rtd139x_mdio_lock(tp); +} + +static void rtd16xx_mdio_unlock(struct rtl8169_private *tp) +{ + rtd139x_mdio_unlock(tp); +} + +static void rtd16xx_reset_phy_gmac(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + struct clk *clk_en_sds = NULL; + struct reset_control *rstc_sds_reg = NULL; + struct reset_control *rstc_sds = NULL; + struct reset_control *rstc_pcie0_power = NULL; + struct reset_control *rstc_pcie0_phy = NULL; + struct reset_control *rstc_pcie0_sgmii_mdio = NULL; + struct reset_control *rstc_pcie0_phy_mdio = NULL; + + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + if (tp->output_mode != OUTPUT_EMBEDDED_PHY) { + clk_en_sds = clk_get(&tp->pdev->dev, "sds"); + rstc_sds_reg = + reset_control_get_exclusive(&tp->pdev->dev, "sds_reg"); + rstc_sds = reset_control_get_exclusive(&tp->pdev->dev, "sds"); + rstc_pcie0_power = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_power"); + rstc_pcie0_phy = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_phy"); + rstc_pcie0_sgmii_mdio = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_sgmii_mdio"); + rstc_pcie0_phy_mdio = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_phy_mdio"); + } + + /* reg_0x9800708c[12:11] = 00 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + + /* reg_0x98007088[10:9] = 00 */ + /* ISO spec, rstn_gphy & rstn_gmac */ + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x9800705c = 0x00616703 */ + /* ISO spec, default value */ + regmap_write(tp->iso_base, ISO_PWRCUT_ETN, 0x00616703); + + if (tp->output_mode != OUTPUT_EMBEDDED_PHY) { + /* RESET for SGMII if needed */ + clk_prepare_enable(clk_en_sds); + + /* reg_0x98000050[13:12] = 10 */ + /* CRT spec, clk_en_sds */ + clk_disable_unprepare(clk_en_sds); + + /* reg_0x98000000[7:6] = 10 */ + /* reg_0x98000000[9:8] = 10 */ + /* CRT spec, rstn_sds_reg & rstn_sds */ + reset_control_assert(rstc_sds); + reset_control_assert(rstc_sds_reg); + + /* reg_0x98000004[25:24] = 10 CRT spec, rstn_pcie0_sgmii_mdio */ + /* reg_0x98000004[23:22] = 10 CRT spec, rstn_pcie0_phy_mdio */ + /* reg_0x98000004[19:18] = 10 CRT spec, rstn_pcie0_power */ + /* reg_0x98000004[13:12] = 10 CRT spec, rstn_pcie0_phy */ + reset_control_assert(rstc_pcie0_sgmii_mdio); + reset_control_assert(rstc_pcie0_phy_mdio); + reset_control_assert(rstc_pcie0_power); + reset_control_assert(rstc_pcie0_phy); + } + + mdelay(1); + + /* release resource */ + if (tp->output_mode != OUTPUT_EMBEDDED_PHY) { + reset_control_put(rstc_sds_reg); + reset_control_put(rstc_sds); + reset_control_put(rstc_pcie0_power); + reset_control_put(rstc_pcie0_phy); + reset_control_put(rstc_pcie0_sgmii_mdio); + reset_control_put(rstc_pcie0_phy_mdio); + } + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd16xx_acp_init(struct rtl8169_private *tp) +{ + u32 tmp; + u32 val; + + /* SBX spec, Select ETN access DDR path. */ + if (tp->acp_enable) { + /* reg_0x9801c20c[6] = 1 */ + /* SBX spec, Mask ETN_ALL to SB3 DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD16XX_SBX_SB3_CHANNEL_REQ_MASK, + BIT(6), BIT(6), NULL, false, true); + + pr_info(PFX "wait all SB3 access finished..."); + tmp = 0; + regmap_read(tp->sbx_base, RTD16XX_SBX_SB3_CHANNEL_REQ_BUSY, &val); + while (val & BIT(6)) { + mdelay(1); + tmp += 1; + if (tmp >= 100) { + pr_err("\n wait SB3 access failed (wait %d ms)\n", tmp); + break; + } + regmap_read(tp->sbx_base, RTD16XX_SBX_SB3_CHANNEL_REQ_BUSY, &val); + } + if (tmp < 100) + pr_info("done.\n"); + + /* reg_0x9801d100[29] = 0 */ + /* SCPU wrapper spec, CLKACP division, 0 = div 2, 1 = div 3 */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_CRT_CTRL, + BIT(29), 0, NULL, false, true); + + /* reg_0x9801d124[1:0] = 00 */ + /* SCPU wrapper spec, ACP master active, 0 = active */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_INTERFACE_EN, + GENMASK(1, 0), 0, NULL, false, true); + + /* reg_0x9801d100[30] = 1 */ + /* SCPU wrapper spec, dy_icg_en_acp */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_CRT_CTRL, + BIT(30), BIT(30), NULL, false, true); + + /* reg_0x9801d100[21] = 1 */ + /* SCPU wrapper spec, ACP CLK enable */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_CRT_CTRL, + BIT(21), BIT(21), NULL, false, true); + + /* reg_0x9801d100[14] = 1 */ + /* SCPU wrapper spec, + * Do not apply reset to ACP port axi3 master + */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_CRT_CTRL, + BIT(14), BIT(14), NULL, false, true); + + /* reg_0x9801d800[3:0] = 0111 */ + /* reg_0x9801d800[7:4] = 0111 */ + /* reg_0x9801d800[9] = 1 */ + /* reg_0x9801d800[20:16] = 01100 */ + /* reg_0x9801d800[28:24] = 01110 */ + /* Configure control of ACP port */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_ACP_CTRL, + GENMASK(28, 24) | GENMASK(20, 16) | + BIT(9) | GENMASK(7, 4) | GENMASK(3, 0), + (0x0e << 24) | (0x0c << 16) | BIT(9) | + (0x7 << 4) | (0x7 << 0), + NULL, false, true); + + /* reg_0x9801d030[28] = 1 */ + /* SCPU wrapper spec, dy_icg_en_acp */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_ACP_CRT_CTRL, + BIT(28), BIT(28), NULL, false, true); + + /* reg_0x9801d030[16] = 1 */ + /* SCPU wrapper spec, ACP CLK Enable for acp of scpu_chip_top */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_ACP_CRT_CTRL, + BIT(16), BIT(16), NULL, false, true); + + /* reg_0x9801d030[0] = 1 */ + /* SCPU wrapper spec, + * Do not apply reset to ACP port axi3 master + */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_ACP_CRT_CTRL, + BIT(0), BIT(0), NULL, false, true); + + /* reg_0x9801c814[17] = 1 */ + /* through ACP to SCPU_ACP */ + regmap_update_bits_base(tp->sbx_base, RTD16XX_SBX_ACP_MISC_CTRL, + BIT(17), BIT(17), NULL, false, true); + + /* SBX spec, Remove mask ETN_ALL to ACP DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD16XX_SBX_ACP_CHANNEL_REQ_MASK, + BIT(1), 0, NULL, false, true); + + pr_info(PFX "ARM ACP on\n."); + } else { + /* SBX spec, Mask ETN_ALL to ACP DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD16XX_SBX_ACP_CHANNEL_REQ_MASK, + BIT(1), BIT(1), NULL, false, true); + + pr_info(PFX "wait all ACP access finished..."); + tmp = 0; + regmap_read(tp->sbx_base, RTD16XX_SBX_ACP_CHANNEL_REQ_BUSY, &val); + while (val & BIT(1)) { + mdelay(1); + tmp += 1; + if (tmp >= 100) { + pr_err("\n ACP channel is still busy (wait %d ms)\n", tmp); + break; + } + regmap_read(tp->sbx_base, RTD16XX_SBX_ACP_CHANNEL_REQ_BUSY, &val); + } + if (tmp < 100) + pr_info("done.\n"); + + /* SCPU wrapper spec, Inactive MP4 AINACTS signal */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_INTERFACE_EN, + GENMASK(1, 0), GENMASK(1, 0), NULL, false, true); + + /* SCPU wrapper spec, nACPRESET_DVFS & CLKENACP_DVFS */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_CRT_CTRL, + (BIT(21) | BIT(14)), 0, NULL, false, true); + + /* SCPU wrapper spec, nACPRESET & CLKENACP */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD16XX_SC_WRAP_ACP_CRT_CTRL, + (BIT(16) | BIT(0)), 0, NULL, false, true); + + /* reg_0x9801c814[17] = 0 */ + /* SBX spec, Switch ETN_ALL to DC_SYS path */ + regmap_update_bits_base(tp->sbx_base, RTD16XX_SBX_ACP_MISC_CTRL, + BIT(17), 0, NULL, false, true); + + /* SBX spec, Remove mask ETN_ALL to SB3 DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD16XX_SBX_SB3_CHANNEL_REQ_MASK, + BIT(6), 0, NULL, false, true); + + pr_info(PFX "ARM ACP off\n."); + } +} + +static void rtd16xx_pll_clock_init(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + /* reg_0x98007004[27] = 1 */ + /* ISO spec, ETN_PHY_INTR, clear ETN interrupt for ByPassMode */ + regmap_write(tp->iso_base, ISO_UMSK_ISR, BIT(27)); + + /* reg_0x98007088[10] = 1 */ + /* ISO spec, reset bit of gphy */ + reset_control_deassert(rstc_gphy); + + mdelay(1); /* wait 1ms for PHY PLL stable */ + + /* Thor only supports the bypass mode */ + /* Bypass mode : ETN MAC bypass efuse update flow. + * SW need to take this sequence. + */ + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + /* bypass mode, SW need to handle the EPHY Status check , + * EFUSE data update and EPHY fuse_rdy setting. + */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x98007088[9] = 1 */ + /* ISO spec, reset bit of gmac */ + reset_control_deassert(rstc_gmac); + + /* reg_0x9800708c[12:11] = 11 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + mdelay(10); /* wait 10ms for GMAC uC to be stable */ + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd16xx_load_otp_content(struct rtl8169_private *tp) +{ + u32 otp; + u16 tmp; + u8 *buf; + + /* RC-K 0x980174F8[27:24] */ + buf = r8169soc_read_otp(tp, "rc_k"); + if (IS_ERR(buf)) + goto set_r_amp_cal; + + otp = *buf; + tmp = (otp << 12) | (otp << 8) | (otp << 4) | otp; + tmp ^= RTD16XX_RC_K_DEFAULT; + int_mdio_write(tp, 0x0bcd, 22, tmp); + int_mdio_write(tp, 0x0bcd, 23, tmp); + + kfree(buf); + +set_r_amp_cal: + + buf = r8169soc_read_otp(tp, "r_amp_k"); + if (IS_ERR(buf)) + return; + + /* R-K 0x98017500[18:15] */ + otp = ((buf[5] & 0x80) >> 7) | ((buf[6] & 0x07) << 1); + tmp = (otp << 12) | (otp << 8) | (otp << 4) | otp; + tmp ^= RTD16XX_R_K_DEFAULT; + int_mdio_write(tp, 0x0bce, 16, tmp); + int_mdio_write(tp, 0x0bce, 17, tmp); + + /* Amp-K 0x980174FC[15:0] */ + otp = buf[0] | (buf[1] << 8); + tmp = otp ^ RTD16XX_AMP_K_DEFAULT; + int_mdio_write(tp, 0x0bca, 22, tmp); + + /* Bias-K 0x980174FC[31:16] */ + otp = buf[2] | (buf[3] << 8); + tmp = otp ^ RTD16XX_ADC_BIAS_K_DEFAULT; + int_mdio_write(tp, 0x0bcf, 22, tmp); + + kfree(buf); +} + +static u32 rtd16xx_serdes_init(struct rtl8169_private *tp) +{ + u32 stable_ticks; + u32 tmp; + u32 val; + struct clk *clk_en_sds = clk_get(&tp->pdev->dev, "sds"); + struct reset_control *rstc_sds_reg = + reset_control_get_exclusive(&tp->pdev->dev, "sds_reg"); + struct reset_control *rstc_sds = + reset_control_get_exclusive(&tp->pdev->dev, "sds"); + struct reset_control *rstc_pcie0_power = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_power"); + struct reset_control *rstc_pcie0_phy = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_phy"); + struct reset_control *rstc_pcie0_sgmii_mdio = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_sgmii_mdio"); + struct reset_control *rstc_pcie0_phy_mdio = + reset_control_get_exclusive(&tp->pdev->dev, "pcie0_phy_mdio"); + + /* reg_0x98000050[13:12] = 11 */ + /* CRT spec, clk_en_sds */ + clk_prepare_enable(clk_en_sds); + + /* reg_0x98000000[9:8] = 11 */ + /* reg_0x98000000[7:6] = 11 */ + /* CRT spec, rstn_sds_reg & rstn_sds */ + reset_control_deassert(rstc_sds); + reset_control_deassert(rstc_sds_reg); + + /* reg_0x98000004[25:24] = 11 CRT spec, rstn_pcie0_sgmii_mdio */ + /* reg_0x98000004[23:22] = 11 CRT spec, rstn_pcie0_phy_mdio */ + /* reg_0x98000004[19:18] = 11 CRT spec, rstn_pcie0_power */ + /* reg_0x98000004[13:12] = 11 CRT spec, rstn_pcie0_phy */ + reset_control_deassert(rstc_pcie0_power); + reset_control_deassert(rstc_pcie0_phy); + reset_control_deassert(rstc_pcie0_sgmii_mdio); + reset_control_deassert(rstc_pcie0_phy_mdio); + + /* reg_0x9800705c[6] = 1 */ + /* ISO spec, set PCIe channel to SGMII */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(6), BIT(6), NULL, false, true); + + /* ### Beginning of SGMII DPHY register tuning ### */ + /* reg_0x9800705c[7] = 1 */ + /* ISO spec, set internal MDIO to PCIe */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(7), BIT(7), NULL, false, true); + + /* reg_0x9800705c[20:16] = 00000 */ + /* ISO spec, set internal PHY addr to SERDES_DPHY_0 */ + __int_set_phy_addr(tp, RTD16XX_SERDES_DPHY_0); + + /* # DPHY spec, 5GHz tuning */ + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x4, 0x52f5); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x5, 0xead7); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x6, 0x0010); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0xa, 0xc653); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0xe030); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0xd, 0xee1c); + + /* reg_0x9800705c[20:16] = 00001 */ + /* ISO spec, set internal PHY addr to SERDES_DPHY_1 */ + __int_set_phy_addr(tp, RTD16XX_SERDES_DPHY_1); + + /* tx_swing_550mv by default */ + switch (tp->sgmii.swing) { + case RTD16XX_TX_SWING_190MV: + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x0, 0xd411); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0x2277); + break; + case RTD16XX_TX_SWING_250MV: + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x0, 0xd433); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0x2244); + break; + case RTD16XX_TX_SWING_380MV: + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x0, 0xd433); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0x22aa); + break; + case RTD16XX_TX_SWING_550MV: /* recommended by RDC */ + default: + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x0, 0xd455); + int_mdio_write(tp, CURRENT_MDIO_PAGE, 0x1, 0x2828); + } + + /* reg_0x9800705c[20:16] = 00001 */ + /* ISO spec, set internal PHY addr to INT_PHY_ADDR */ + __int_set_phy_addr(tp, RTD16XX_INT_PHY_ADDR); + + mdelay(10); /* wait for clock stable */ + + /* reg_0x9800705c[5] = 0 */ + /* reg_0x9800705c[7] = 0 */ + /* ISO spec, set internal MDIO to GPHY */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + (BIT(7) | BIT(5)), 0, NULL, false, true); + + tp->ext_phy = true; + /* ext_phy == true now */ + + tmp = 0; + stable_ticks = 0; + while (stable_ticks < 10) { + /* # SDS spec, wait for phy ready */ + regmap_read(tp->sds_base, RTD16XX_SDS_LINK, &val); + while ((val & BIT(24)) == 0) { + stable_ticks = 0; + if (tmp >= 100) { + stable_ticks = 10; + pr_err(PFX "SGMII PHY not ready in 100ms\n"); + break; + } + regmap_read(tp->sds_base, RTD16XX_SDS_LINK, &val); + } + stable_ticks++; + tmp++; + mdelay(1); + } + pr_info(PFX "SGMII PHY is ready in %d ms", tmp); + + /* reg_0x9800705c[4] = 1 */ + /* ISO spec, set data path to SGMII */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(4), BIT(4), NULL, false, true); + + /* reg_0x981c8008[9:8] = 00 */ + /* # SDS spec, SP_SDS_FRC_AN, SERDES auto mode */ + regmap_update_bits_base(tp->sds_base, RTD16XX_SDS_REG02, + GENMASK(9, 8), 0, NULL, false, true); + + /* # SDS spec, wait for SERDES link up */ + tmp = 0; + stable_ticks = 0; + while (stable_ticks < 10) { + regmap_read(tp->sds_base, RTD16XX_SDS_MISC, &val); + while ((val & BIT(12)) == 0) { + stable_ticks = 0; + if (tmp >= 100) { + stable_ticks = 10; + pr_err(PFX "SGMII link down in 100ms\n"); + break; + } + regmap_read(tp->sds_base, RTD16XX_SDS_MISC, &val); + } + stable_ticks++; + tmp++; + mdelay(1); + } + pr_info(PFX "SGMII link up in %d ms", tmp); + + reset_control_put(rstc_sds_reg); + reset_control_put(rstc_sds); + reset_control_put(rstc_pcie0_power); + reset_control_put(rstc_pcie0_phy); + reset_control_put(rstc_pcie0_sgmii_mdio); + reset_control_put(rstc_pcie0_phy_mdio); + return 0; +} + +static void rtd16xx_phy_iol_tuning(struct rtl8169_private *tp) +{ + /* for common mode voltage */ + int_mdio_write(tp, 0x0bc0, 17, + (int_mdio_read(tp, 0x0bc0, 17) & ~(0xff << 4)) | (0xb4 << 4)); + + /* for 1000 Base-T, Transmitter Distortion */ + int_mdio_write(tp, 0x0a43, 27, 0x8082); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | (0xae << 8)); + + /* for 1000 Base-T, Master Filtered Jitter */ + int_mdio_write(tp, 0x0a43, 27, 0x807c); + /* adjust ldvbias_busy, abiq_busy, gdac_ib_up_tm + * to accelerate slew rate + */ + int_mdio_write(tp, 0x0a43, 28, 0xf001); + /* set CP_27to25=7 and REF_27to25_L=4 to decrease jitter */ + int_mdio_write(tp, 0x0bc5, 16, 0xc67f); +} + +static void rtd16xx_phy_sram_table(struct rtl8169_private *tp) +{ + /* enable echo power*2 */ + int_mdio_write(tp, 0x0a42, 22, 0x0f10); + + /* Channel estimation, 100Mbps adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x8087); /* gain_i slope */ + int_mdio_write(tp, 0x0a43, 28, 0x42f0); /* 0x43 => 0x42 */ + int_mdio_write(tp, 0x0a43, 27, 0x808e); /* clen_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0x14a4); /* 0x13 => 0x14 */ + /* adc peak adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x8088); /* aagc_lvl_c initial value 0x3f0 => ok */ + int_mdio_write(tp, 0x0a43, 28, 0xf0eb); /* delta_a slope 0x1e => 0x1d */ + /* cb0 adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x808c); /* cb0_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0xef09); /* 0x9ef => ok */ + int_mdio_write(tp, 0x0a43, 27, 0x808f); /* delta_b slope */ + int_mdio_write(tp, 0x0a43, 28, 0xa4c6); /* 0xa4 => ok */ + /* DAGC adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x808a); /* cg_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0x400a); /* 0xb40 => 0xa40 */ + int_mdio_write(tp, 0x0a43, 27, 0x8092); /* delta_g slope */ + int_mdio_write(tp, 0x0a43, 28, 0xc21e); /* 0x0c0 => 0x0c2 */ + + /* 1000Mbps master adjustment */ + /* line adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x8099); /* gain_i slope */ + int_mdio_write(tp, 0x0a43, 28, 0x2ae0); /* 0x2e => 0x2a */ + int_mdio_write(tp, 0x0a43, 27, 0x80a0); /* clen_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0xf28f); /* 0xfe => 0xf2 */ + /* adc peak adjustment */ + /* aagc_lvl_c initial value 0x3e0 => 0x470 */ + int_mdio_write(tp, 0x0a43, 27, 0x809a); + int_mdio_write(tp, 0x0a43, 28, 0x7084); /* delta_a slope 0x0d => 0x10 */ + /* cb0 adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x809e); /* cb0_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0xa008); /* 0x7a1 => 0x8a0 */ + int_mdio_write(tp, 0x0a43, 27, 0x80a1); /* delta_b slope */ + int_mdio_write(tp, 0x0a43, 28, 0x783d); /* 0x8f => 0x78 */ + /* DAGC adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x809c); /* cg_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0x8008); /* 0xb00 => 0x880 */ + int_mdio_write(tp, 0x0a43, 27, 0x80a4); /* delta_g slope */ + int_mdio_write(tp, 0x0a43, 28, 0x580c); /* 0x063 => 0x058 */ + + /* 1000Mbps slave adjustment */ + /* line adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x80ab); /* gain_i slope */ + int_mdio_write(tp, 0x0a43, 28, 0x2b4a); /* 0x2e => 0x2b */ + int_mdio_write(tp, 0x0a43, 27, 0x80b2); /* clen_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0xf47f); /* 0xfa => 0xf4 */ + /* adc peak adjustment */ + /* aagc_lvl_c initial value 0x44a => 0x488 */ + int_mdio_write(tp, 0x0a43, 27, 0x80ac); + int_mdio_write(tp, 0x0a43, 28, 0x8884); /* delta_a slope 0x0e => 0x10 */ + /* cb0 adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x80b0); /* cb0_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0xa107); /* 0x6a1 => 0x7a1 */ + int_mdio_write(tp, 0x0a43, 27, 0x80b3); /* delta_b slope */ + int_mdio_write(tp, 0x0a43, 28, 0x683d); /* 0x7f => 0x68 */ + /* DAGC adjustment */ + int_mdio_write(tp, 0x0a43, 27, 0x80ae); /* cg_i_c initial value */ + int_mdio_write(tp, 0x0a43, 28, 0x2006); /* 0x760 => 0x620 */ + int_mdio_write(tp, 0x0a43, 27, 0x80b6); /* delta_g slope */ + int_mdio_write(tp, 0x0a43, 28, 0x850c); /* 0x090 => 0x085 */ +} + +static void rtd16xx_patch_gphy_uc_code(struct rtl8169_private *tp) +{ + u32 tmp; + + /* patch for GPHY uC firmware, + * adjust 1000M EEE lpi_waketx_timer = 1.3uS + */ +#define PATCH_KEY_ADDR 0x8028 /* for RL6525 */ +#define PATCH_KEY 0x5600 /* for RL6525 */ + + /* Patch request & wait for the asserting of patch_rdy */ + int_mdio_write(tp, 0x0b82, 16, + int_mdio_read(tp, 0x0b82, 16) | BIT(4)); + + tmp = 0; + while ((int_mdio_read(tp, 0x0b80, 16) & BIT(6)) == 0) { + tmp += 1; + mdelay(1); + if (tmp >= 100) { + pr_err(PFX "GPHY patch_rdy timeout.\n"); + break; + } + } + pr_info(PFX "wait %d ms for GPHY patch_rdy. reg = 0x%x\n", + tmp, int_mdio_read(tp, 0x0b80, 16)); + pr_info(PFX "patch_rdy is asserted!!\n"); + + /* Set patch_key & patch_lock */ + int_mdio_write(tp, 0, 27, PATCH_KEY_ADDR); + int_mdio_write(tp, 0, 28, PATCH_KEY); + int_mdio_write(tp, 0, 27, PATCH_KEY_ADDR); + pr_info(PFX "check patch key = %04x\n", int_mdio_read(tp, 0, 28)); + int_mdio_write(tp, 0, 27, 0xb82e); + int_mdio_write(tp, 0, 28, 0x0001); + + /* uC patch code, released by Digital Designer */ + int_mdio_write(tp, 0, 27, 0xb820); + int_mdio_write(tp, 0, 28, 0x0290); + + int_mdio_write(tp, 0, 27, 0xa012); + int_mdio_write(tp, 0, 28, 0x0000); + + int_mdio_write(tp, 0, 27, 0xa014); + int_mdio_write(tp, 0, 28, 0x2c04); + int_mdio_write(tp, 0, 28, 0x2c06); + int_mdio_write(tp, 0, 28, 0x2c09); + int_mdio_write(tp, 0, 28, 0x2c0c); + int_mdio_write(tp, 0, 28, 0xd093); + int_mdio_write(tp, 0, 28, 0x2265); + int_mdio_write(tp, 0, 28, 0x9e20); + int_mdio_write(tp, 0, 28, 0xd703); + int_mdio_write(tp, 0, 28, 0x2502); + int_mdio_write(tp, 0, 28, 0x9e40); + int_mdio_write(tp, 0, 28, 0xd700); + int_mdio_write(tp, 0, 28, 0x0800); + int_mdio_write(tp, 0, 28, 0x9e80); + int_mdio_write(tp, 0, 28, 0xd70d); + int_mdio_write(tp, 0, 28, 0x202e); + + int_mdio_write(tp, 0, 27, 0xa01a); + int_mdio_write(tp, 0, 28, 0x0000); + + int_mdio_write(tp, 0, 27, 0xa006); + int_mdio_write(tp, 0, 28, 0x002d); + + int_mdio_write(tp, 0, 27, 0xa004); + int_mdio_write(tp, 0, 28, 0x0507); + + int_mdio_write(tp, 0, 27, 0xa002); + int_mdio_write(tp, 0, 28, 0x0501); + + int_mdio_write(tp, 0, 27, 0xa000); + int_mdio_write(tp, 0, 28, 0x1264); + + int_mdio_write(tp, 0, 27, 0xb820); + int_mdio_write(tp, 0, 28, 0x0210); + + mdelay(10); + + /* Clear patch_key & patch_lock */ + int_mdio_write(tp, 0, 27, PATCH_KEY_ADDR); + int_mdio_write(tp, 0, 28, 0); + int_mdio_write(tp, 0x0b82, 23, 0); + + /* Release patch request & wait for the deasserting of patch_rdy. */ + int_mdio_write(tp, 0x0b82, 16, + int_mdio_read(tp, 0x0b82, 16) & ~BIT(4)); + + tmp = 0; + while ((int_mdio_read(tp, 0x0b80, 16) & BIT(6)) != 0) { + tmp += 1; + mdelay(1); + if (tmp >= 100) { + pr_err(PFX "GPHY patch_rdy timeout.\n"); + break; + } + } + pr_info(PFX "wait %d ms for GPHY patch_rdy. reg = 0x%x\n", + tmp, int_mdio_read(tp, 0x0b80, 16)); + + pr_info(PFX "patch_rdy is de-asserted!!\n"); + pr_info(PFX "GPHY uC code patched.\n"); +} + +static void rtd16xx_mdio_init(struct rtl8169_private *tp) +{ + u32 tmp; + u32 val; + struct pinctrl *p_sgmii_mdio; + struct pinctrl_state *ps_sgmii_mdio; + void __iomem *ioaddr = tp->mmio_addr; + + /* ISO spec, ETN_PHY_INTR, + * wait interrupt from PHY and it means MDIO is ready + */ + tmp = 0; + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + while ((val & BIT(27)) == 0) { + tmp += 1; + mdelay(1); + if (tmp >= 100) { + pr_err(PFX "PHY PHY_Status timeout.\n"); + break; + } + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + } + pr_info(PFX "wait %d ms for PHY interrupt. UMSK_ISR = 0x%x\n", tmp, val); + + /* In ByPass mode, + * SW need to handle the EPHY Status check , + * OTP data update and EPHY fuse_rdy setting. + */ + /* PHY will stay in state 1 mode */ + tmp = 0; + while ((int_mdio_read(tp, 0x0a42, 16) & 0x07) != 0x1) { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x1 in bypass mode, current = 0x%02x\n", + int_mdio_read(tp, 0x0a42, 16) & 0x07); + break; + } + } + + /* fill fuse_rdy & rg_ext_ini_done */ + int_mdio_write(tp, 0x0a46, 20, + int_mdio_read(tp, 0x0a46, 20) | (BIT(1) | BIT(0))); + + /* init_autoload_done = 1 */ + tmp = rtl_ocp_read(tp, 0xe004); + tmp |= BIT(7); + rtl_ocp_write(tp, 0xe004, tmp); + + /* ee_mode = 3 */ + RTL_W8(CFG9346, CFG9346_UNLOCK); + + /* wait LAN-ON */ + tmp = 0; + do { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x3, current = 0x%02x\n", + int_mdio_read(tp, 0x0a42, 16) & 0x07); + break; + } + } while ((int_mdio_read(tp, 0x0a42, 16) & 0x07) != 0x3); + pr_info(PFX "wait %d ms for PHY ready, current = 0x%x\n", + tmp, int_mdio_read(tp, 0x0a42, 16)); + + /* adjust PHY SRAM table */ + rtd16xx_phy_sram_table(tp); + + /* GPHY patch code */ + rtd16xx_patch_gphy_uc_code(tp); + + /* adjust PHY electrical characteristics */ + rtd16xx_phy_iol_tuning(tp); + + /* load OTP contents (RC-K, R-K, Amp-K, and Bias-K) + * RC-K: 0x980174F8[27:24] + * R-K: 0x98017500[18:15] + * Amp-K: 0x980174FC[15:0] + * Bias-K: 0x980174FC[31:16] + */ + rtd16xx_load_otp_content(tp); + + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* Init PHY path */ + /* reg_0x9800705c[5] = 0 */ + /* reg_0x9800705c[7] = 0 */ + /* ISO spec, set internal MDIO to access PHY */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + (BIT(7) | BIT(5)), 0, NULL, false, true); + + /* reg_0x9800705c[4] = 0 */ + /* ISO spec, set data path to access PHY */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(4), 0, NULL, false, true); + + /* ETN spec, GMAC data path select MII-like(embedded GPHY), + * not SGMII(external PHY) + */ + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(0) | BIT(1)); + tmp |= BIT(1); /* MII */ + rtl_ocp_write(tp, 0xea34, tmp); + } else { + /* SGMII */ + /* ETN spec, adjust MDC freq=2.5MHz */ + tmp = rtl_ocp_read(tp, 0xDE30) & ~(BIT(7) | BIT(6)); + rtl_ocp_write(tp, 0xDE30, tmp); + /* ETN spec, set external PHY addr */ + tmp = rtl_ocp_read(tp, 0xDE24) & ~(0x1f << 0); + rtl_ocp_write(tp, 0xDE24, tmp | (tp->ext_phy_id & 0x1f)); + /* ISO mux spec, GPIO29 is set to MDC pin */ + /* ISO mux spec, GPIO46 is set to MDIO pin */ + p_sgmii_mdio = devm_pinctrl_get(&tp->pdev->dev); + ps_sgmii_mdio = pinctrl_lookup_state(p_sgmii_mdio, "sgmii"); + pinctrl_select_state(p_sgmii_mdio, ps_sgmii_mdio); + + /* check if external PHY is available */ + pr_info(PFX "Searching external PHY..."); + tp->ext_phy = true; + tmp = 0; + while (ext_mdio_read(tp, 0x0a43, 31) != 0x0a43) { + pr_info("."); + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err("\n External SGMII PHY not found, current = 0x%02x\n", + ext_mdio_read(tp, 0x0a43, 31)); + return; + } + } + if (tmp < 2000) + pr_info("found.\n"); + + /* lower SGMII TX swing of RTL8211FS to reduce EMI */ + /* TX swing = 470mV, default value */ + ext_mdio_write(tp, 0x0dcd, 16, 0x104e); + + tp->ext_phy = false; + + /* ETN spec, GMAC data path select SGMII(external PHY), + * not MII-like(embedded GPHY) + */ + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(0) | BIT(1)); + tmp |= BIT(1) | BIT(0); /* SGMII */ + rtl_ocp_write(tp, 0xea34, tmp); + + if (rtd16xx_serdes_init(tp) != 0) + pr_err(PFX "SERDES init failed\n"); + /* ext_phy == true now */ + + /* SDS spec, auto update SGMII link capability */ + regmap_update_bits_base(tp->sds_base, RTD16XX_SDS_DEBUG, + BIT(2), BIT(2), NULL, false, true); + + /* enable 8b/10b symbol error + * even it is only valid in 1000Mbps + */ + ext_mdio_write(tp, 0x0dcf, 16, + (ext_mdio_read(tp, 0x0dcf, 16) & + ~(BIT(2) | BIT(1) | BIT(0)))); + ext_mdio_read(tp, 0x0dcf, 17); /* dummy read */ + } +} + +static void rtd16xx_eee_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + tp->chip->mdio_lock(tp); + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* 1000M/100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, (BIT(2) | BIT(1))); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | (BIT(4) | BIT(2))); + /* disable dynamic RX power in PHY */ + rtl_phy_write(tp, 0x0bd0, 21, + (rtl_phy_read(tp, 0x0bd0, 21) & ~BIT(8)) | BIT(9)); + } else { /* SGMII */ + /* 1000M & 100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, (BIT(2) | BIT(1))); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | (BIT(4) | BIT(2))); + } + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) | (BIT(1) | BIT(0))); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) | BIT(1)); + } else { + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* no EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + } else { /* SGMII */ + /* no EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + } + /* reset to default value */ + rtl_ocp_write(tp, 0xe040, rtl_ocp_read(tp, 0xe040) | BIT(13)); + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) & ~(BIT(1) | BIT(0))); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) & ~BIT(1)); + } +} + +static void rtd16xx_led_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + regmap_update_bits_base(tp->pinctrl_base, RTD16XX_ISO_TESTMUX_MUXPAD0, + GENMASK(29, 26), (5 << 26), NULL, false, true); + regmap_update_bits_base(tp->pinctrl_base, RTD16XX_ISO_TESTMUX_MUXPAD2, + GENMASK(29, 27), (3 << 27), NULL, false, true); + } else { + regmap_update_bits_base(tp->pinctrl_base, RTD16XX_ISO_TESTMUX_MUXPAD0, + GENMASK(29, 26), 0, NULL, false, true); + regmap_update_bits_base(tp->pinctrl_base, RTD16XX_ISO_TESTMUX_MUXPAD2, + GENMASK(29, 27), 0, NULL, false, true); + } +} + +static void rtd16xx_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + u32 val; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + seq_printf(m, "ISO_UMSK_ISR\t[0x98007004] = %08x\n", val); + regmap_read(tp->iso_base, ISO_PWRCUT_ETN, &val); + seq_printf(m, "ISO_PWRCUT_ETN\t[0x9800705c] = %08x\n", val); + regmap_read(tp->iso_base, ISO_ETN_TESTIO, &val); + seq_printf(m, "ISO_ETN_TESTIO\t[0x98007060] = %08x\n", val); + regmap_read(tp->iso_base, ISO_SOFT_RESET, &val); + seq_printf(m, "ETN_RESET_CTRL\t[0x98007088] = %08x\n", val); + regmap_read(tp->iso_base, ISO_CLOCK_ENABLE, &val); + seq_printf(m, "ETN_CLK_CTRL\t[0x9800708c] = %08x\n", val); + if (tp->output_mode != OUTPUT_EMBEDDED_PHY) { + regmap_read(tp->sds_base, RTD16XX_SDS_REG02, &val); + seq_printf(m, "SDS_REG02\t[0x981c8008] = %08x\n", val); + regmap_read(tp->sds_base, RTD16XX_SDS_MISC, &val); + seq_printf(m, "SDS_MISC\t\t[0x981c9804] = %08x\n", val); + regmap_read(tp->sds_base, RTD16XX_SDS_LINK, &val); + seq_printf(m, "SDS_LINK\t\t[0x981c980c] = %08x\n", val); + regmap_read(tp->sds_base, RTD16XX_SDS_DEBUG, &val); + seq_printf(m, "SDS_DEBUG\t\t[0x981c9810] = %08x\n", val); + } +} + +static void rtd16xx_dump_var(struct seq_file *m, struct rtl8169_private *tp) +{ + seq_printf(m, "sgmii_swing\t%d\n", tp->sgmii.swing); +} + +/******************* END of RTD16XX ****************************/ + +/* RTD13XX */ +static void rtd13xx_mdio_lock(struct rtl8169_private *tp) +{ + rtd139x_mdio_lock(tp); +} + +static void rtd13xx_mdio_unlock(struct rtl8169_private *tp) +{ + rtd139x_mdio_unlock(tp); +} + +static void rtd13xx_reset_phy_gmac(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* reg_0x9800708c[12:11] = 00 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + + /* reg_0x98007088[10:9] = 00 */ + /* ISO spec, rstn_gphy & rstn_gmac */ + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x9800705c[5] = 0 */ + /* ISO spec, default value and specify internal/external PHY ID as 1 */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(5), 0, NULL, false, true); + /* set int PHY addr */ + __int_set_phy_addr(tp, RTD13XX_INT_PHY_ADDR); + /* set ext PHY addr */ + __ext_set_phy_addr(tp, RTD13XX_EXT_PHY_ADDR); + + mdelay(1); + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd13xx_acp_init(struct rtl8169_private *tp) +{ + u32 tmp; + u32 val; + + /* SBX spec, Select ETN access DDR path. */ + if (tp->acp_enable) { + /* reg_0x9801c20c[6] = 1 */ + /* SBX spec, Mask ETN_ALL to SB3 DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD13XX_SBX_SB3_CHANNEL_REQ_MASK, + BIT(6), BIT(6), NULL, false, true); + + pr_info(PFX "wait all SB3 access finished..."); + tmp = 0; + regmap_read(tp->sbx_base, RTD13XX_SBX_SB3_CHANNEL_REQ_BUSY, &val); + while (val & BIT(6)) { + mdelay(10); + tmp += 10; + if (tmp >= 100) { + pr_err("\n wait SB3 access failed (wait %d ms)\n", tmp); + break; + } + regmap_read(tp->sbx_base, RTD13XX_SBX_SB3_CHANNEL_REQ_BUSY, &val); + } + if (tmp < 100) + pr_info("done.\n"); + + /* reg_0x9801d100[29] = 0 */ + /* SCPU wrapper spec, CLKACP division, 0 = div 2, 1 = div 3 */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_CRT_CTRL, + BIT(29), 0, NULL, false, true); + + /* reg_0x9801d124[1:0] = 00 */ + /* SCPU wrapper spec, ACP master active, 0 = active */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_INTERFACE_EN, + GENMASK(1, 0), 0, NULL, false, true); + + /* reg_0x9801d100[30] = 1 */ + /* SCPU wrapper spec, dy_icg_en_acp */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_CRT_CTRL, + BIT(30), BIT(30), NULL, false, true); + + /* reg_0x9801d100[21] = 1 */ + /* SCPU wrapper spec, ACP CLK enable */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_CRT_CTRL, + BIT(21), BIT(21), NULL, false, true); + + /* reg_0x9801d100[14] = 1 */ + /* Do not apply reset to ACP port axi3 master */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_CRT_CTRL, + BIT(14), BIT(14), NULL, false, true); + + /* reg_0x9801d800[3:0] = 0111 */ + /* reg_0x9801d800[7:4] = 0111 */ + /* reg_0x9801d800[9] = 1 */ + /* reg_0x9801d800[20:16] = 01100 */ + /* reg_0x9801d800[28:24] = 01110 */ + /* Configure control of ACP port */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_ACP_CTRL, + GENMASK(28, 24) | GENMASK(20, 16) | + BIT(9) | GENMASK(7, 4) | GENMASK(3, 0), + (0x0e << 24) | (0x0c << 16) | BIT(9) | + (0x7 << 4) | (0x7 << 0), + NULL, false, true); + + /* reg_0x9801d030[28] = 1 */ + /* SCPU wrapper spec, dy_icg_en_acp */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_ACP_CRT_CTRL, + BIT(28), BIT(28), NULL, false, true); + + /* reg_0x9801d030[16] = 1 */ + /* ACP CLK Enable for acp of scpu_chip_top */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_ACP_CRT_CTRL, + BIT(16), BIT(16), NULL, false, true); + + /* reg_0x9801d030[0] = 1 */ + /* Do not apply reset to ACP port axi3 master */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_ACP_CRT_CTRL, + BIT(0), BIT(0), NULL, false, true); + + /* reg_0x9801c814[17] = 1 */ + /* through ACP to SCPU_ACP */ + regmap_update_bits_base(tp->sbx_base, RTD13XX_SBX_ACP_MISC_CTRL, + BIT(17), BIT(17), NULL, false, true); + + /* SBX spec, Remove mask ETN_ALL to ACP DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD13XX_SBX_ACP_CHANNEL_REQ_MASK, + BIT(1), 0, NULL, false, true); + + pr_info(PFX "ARM ACP on\n."); + } else { + /* SBX spec, Mask ETN_ALL to ACP DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD13XX_SBX_ACP_CHANNEL_REQ_MASK, + BIT(1), BIT(1), NULL, false, true); + + pr_info(PFX "wait all ACP access finished..."); + tmp = 0; + regmap_read(tp->sbx_base, RTD13XX_SBX_ACP_CHANNEL_REQ_BUSY, &val); + while (val & BIT(1)) { + mdelay(1); + tmp += 1; + if (tmp >= 100) { + pr_err("\n ACP channel is still busy (wait %d ms)\n", tmp); + break; + } + regmap_read(tp->sbx_base, RTD13XX_SBX_ACP_CHANNEL_REQ_BUSY, &val); + } + if (tmp < 100) + pr_info("done.\n"); + + /* SCPU wrapper spec, Inactive MP4 AINACTS signal */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_INTERFACE_EN, + GENMASK(1, 0), GENMASK(1, 0), NULL, false, true); + + /* SCPU wrapper spec, nACPRESET_DVFS & CLKENACP_DVFS */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_CRT_CTRL, + (BIT(21) | BIT(14)), 0, NULL, false, true); + + /* SCPU wrapper spec, nACPRESET & CLKENACP */ + regmap_update_bits_base(tp->scpu_wrap_base, RTD13XX_SC_WRAP_ACP_CRT_CTRL, + (BIT(16) | BIT(0)), 0, NULL, false, true); + + /* reg_0x9801c814[17] = 0 */ + /* SBX spec, Switch ETN_ALL to DC_SYS path */ + regmap_update_bits_base(tp->sbx_base, RTD13XX_SBX_ACP_MISC_CTRL, + BIT(17), 0, NULL, false, true); + + /* SBX spec, Remove mask ETN_ALL to SB3 DBUS REQ */ + regmap_update_bits_base(tp->sbx_base, RTD13XX_SBX_SB3_CHANNEL_REQ_MASK, + BIT(6), 0, NULL, false, true); + + pr_info(PFX "ARM ACP off\n."); + } +} + +static void rtd13xx_pll_clock_init(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + /* reg_0x98007004[27] = 1 */ + /* ISO spec, ETN_PHY_INTR, clear ETN interrupt for ByPassMode */ + regmap_write(tp->iso_base, ISO_UMSK_ISR, BIT(27)); + + /* reg_0x98007088[10] = 1 */ + /* ISO spec, reset bit of fephy */ + reset_control_deassert(rstc_gphy); + + mdelay(1); /* wait 1ms for PHY PLL stable */ + + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x98007088[9] = 1 */ + /* ISO spec, reset bit of gmac */ + reset_control_deassert(rstc_gmac); + + /* reg_0x9800708c[12:11] = 11 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + mdelay(10); /* wait 10ms for GMAC uC to be stable */ + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd13xx_load_otp_content(struct rtl8169_private *tp) +{ + u32 otp; + u16 tmp; + u8 *buf; + + buf = r8169soc_read_otp(tp, "para"); + if (IS_ERR(buf)) + goto set_idac; + + /* enable 0x980174FC[4] */ + /* R-K 0x980174FC[3:0] */ + otp = *buf; + if (otp & BIT(4)) { + tmp = otp ^ RTD13XX_R_K_DEFAULT; + int_mdio_write(tp, 0x0bc0, 20, + (int_mdio_read(tp, 0x0bc0, 20) & ~(0x1f << 0)) | tmp); + } + + kfree(buf); + +set_idac: + + buf = r8169soc_read_otp(tp, "idac"); + if (IS_ERR(buf)) + return; + + /* Amp-K 0x98017500[7:0] */ + otp = *buf; + tmp = otp ^ RTD13XX_IDAC_FINE_DEFAULT; + int_mdio_write(tp, 0x0bc0, 23, + (int_mdio_read(tp, 0x0bc0, 23) & ~(0xff << 0)) | tmp); + + kfree(buf); +} + +static void rtd13xx_phy_iol_tuning(struct rtl8169_private *tp) +{ + u16 tmp; + + /* rs_offset=rsw_offset=0xc */ + tmp = 0xcc << 8; + int_mdio_write(tp, 0x0bc0, 20, + (int_mdio_read(tp, 0x0bc0, 20) & ~(0xff << 8)) | tmp); + + /* 100M Tr/Tf */ + /* reg_cf_l=0x2 */ + tmp = 0x2 << 11; + int_mdio_write(tp, 0x0bd0, 17, + (int_mdio_read(tp, 0x0bd0, 17) & ~(0x7 << 11)) | tmp); + + /* 100M Swing */ + /* idac_fine_mdix, idac_fine_mdi */ + tmp = 0x55 << 0; + int_mdio_write(tp, 0x0bc0, 23, + (int_mdio_read(tp, 0x0bc0, 23) & ~(0xff << 0)) | tmp); +} + +static void rtd13xx_mdio_init(struct rtl8169_private *tp) +{ + u32 tmp; + u32 val; + struct pinctrl *p_rgmii_mdio; + struct pinctrl_state *ps_rgmii_mdio; + void __iomem *ioaddr = tp->mmio_addr; + const struct soc_device_attribute rtk_soc_rtd13xx_a00[] = { + { + .family = "Realtek Hank", + .revision = "A00", + }, + { + /* empty */ + } + }; + + /* ETN_PHY_INTR, wait interrupt from PHY and it means MDIO is ready */ + tmp = 0; + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + while ((val & BIT(27)) == 0) { + tmp += 1; + mdelay(1); + if (tmp >= 100) { + pr_err(PFX "PHY PHY_Status timeout.\n"); + break; + } + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + } + pr_info(PFX "wait %d ms for PHY interrupt. UMSK_ISR = 0x%x\n", tmp, val); + + /* In ByPass mode, + * SW need to handle the EPHY Status check , + * OTP data update and EPHY fuse_rdy setting. + */ + /* PHY will stay in state 1 mode */ + tmp = 0; + while (0x1 != (int_mdio_read(tp, 0x0a42, 16) & 0x07)) { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x1 in bypass mode, current = 0x%02x\n", + (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } + + /* fix A00 known issue */ + if (soc_device_match(rtk_soc_rtd13xx_a00)) { + /* fix AFE RX power as 1 */ + int_mdio_write(tp, 0x0bd0, 21, 0x7201); + } + + /* ETN spec. set MDC freq = 8.9MHZ */ + tmp = rtl_ocp_read(tp, 0xde10) & ~(BIT(7) | BIT(6)); + tmp |= BIT(6); /* MDC freq = 8.9MHz */ + rtl_ocp_write(tp, 0xde10, tmp); + + /* fill fuse_rdy & rg_ext_ini_done */ + int_mdio_write(tp, 0x0a46, 20, + int_mdio_read(tp, 0x0a46, 20) | (BIT(1) | BIT(0))); + + /* init_autoload_done = 1 */ + tmp = rtl_ocp_read(tp, 0xe004); + tmp |= BIT(7); + rtl_ocp_write(tp, 0xe004, tmp); + + /* ee_mode = 3 */ + RTL_W8(CFG9346, CFG9346_UNLOCK); + + /* wait LAN-ON */ + tmp = 0; + do { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x3, current = 0x%02x\n", + (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } while (0x3 != (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + pr_info(PFX "wait %d ms for PHY ready, current = 0x%x\n", + tmp, int_mdio_read(tp, 0x0a42, 16)); + + /* adjust PHY electrical characteristics */ + rtd13xx_phy_iol_tuning(tp); + + /* load OTP contents (R-K, Amp) + * R-K: 0x980174FC[4:0] + * Amp: 0x98017500[7:0] + */ + rtd13xx_load_otp_content(tp); + + switch (tp->output_mode) { + case OUTPUT_EMBEDDED_PHY: + /* ISO spec, set data path to FEPHY */ + tmp = rtl_ocp_read(tp, 0xea30); + tmp &= ~(BIT(0)); + rtl_ocp_write(tp, 0xea30, tmp); + + tmp = rtl_ocp_read(tp, 0xea34); + tmp &= ~(BIT(1) | BIT(0)); + tmp |= BIT(1); /* FEPHY */ + rtl_ocp_write(tp, 0xea34, tmp); + + /* LED high active circuit */ + /* output current: 4mA */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC9, + GENMASK(23, 16), 0, NULL, false, true); + break; + case OUTPUT_RGMII_TO_MAC: + pr_err(PFX "%s:%d: FIXME! PHY_TYPE_RGMII_MAC\n", __func__, __LINE__); + break; + case OUTPUT_RMII: + pr_err(PFX "%s:%d: FIXME! PHY_TYPE_RMII\n", __func__, __LINE__); + break; + case OUTPUT_RGMII_TO_PHY: + /* ISO mux spec, GPIO15 is set to MDC pin */ + /* ISO mux spec, GPIO14 is set to MDIO pin */ + /* ISO mux spec, GPIO65~76 is set to TX/RX pin */ + p_rgmii_mdio = devm_pinctrl_get(&tp->pdev->dev); + ps_rgmii_mdio = pinctrl_lookup_state(p_rgmii_mdio, "rgmii"); + pinctrl_select_state(p_rgmii_mdio, ps_rgmii_mdio); + + /* no Schmitt_Trigger */ + switch (tp->rgmii.voltage) { + case 3: /* 3.3v */ + /* MODE2=1, MODE=0, SR=1, smt=0, pudsel=0, puden=0, + * E2=0 + */ + /* GPIO[70:65] */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC20, + GENMASK(27, 4), 0, NULL, false, true); + + /* GPIO[76:71] */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC21, + GENMASK(31, 0), + (0x2 << 30) | (0x10 << 25) | (0x10 << 20) | + (0x10 << 15) | (0x10 << 10) | (0x10 << 5) | + (0x10 << 0), + NULL, false, true); + + /* DP=000, DN=111 */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC25, + GENMASK(5, 0), + (0x0 << 3) | (0x7 << 0), + NULL, false, true); + break; + case 2: /* 2.5v */ + /* MODE2=0, MODE=1, SR=0, smt=0, pudsel=0, puden=0, + * E2=1 + */ + /* GPIO[70:65] */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC20, + GENMASK(27, 4), + (0x1 << 24) | (0x1 << 20) | (0x1 << 16) | + (0x1 << 12) | (0x1 << 8) | (0x1 << 4), + NULL, false, true); + + /* GPIO[76:71] */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC21, + GENMASK(31, 0), + (0x1 << 30) | (0x1 << 25) | (0x1 << 20) | + (0x1 << 15) | (0x1 << 10) | (0x1 << 5) | + (0x1 << 0), + NULL, false, true); + + /* DP=000, DN=111 */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC25, + GENMASK(5, 0), + (0x0 << 3) | (0x7 << 0), + NULL, false, true); + break; + case 1: /* 1.8v */ + default: + /* MODE2=0, MODE=0, SR=0, smt=0, pudsel=0, puden=0, + * E2=1 + */ + /* GPIO[70:65] */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC20, + GENMASK(27, 4), + (0x1 << 24) | (0x1 << 20) | (0x1 << 16) | + (0x1 << 12) | (0x1 << 8) | (0x1 << 4), + NULL, false, true); + + /* GPIO[76:71] */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC21, + GENMASK(31, 0), + (0x0 << 30) | (0x1 << 25) | (0x1 << 20) | + (0x1 << 15) | (0x1 << 10) | (0x1 << 5) | + (0x1 << 0), + NULL, false, true); + + /* DP=001, DN=110 */ + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_PFUNC25, + GENMASK(5, 0), + (0x1 << 3) | (0x6 << 0), + NULL, false, true); + } + + /* check if external PHY is available */ + pr_info(PFX "Searching external PHY..."); + tp->ext_phy = true; + tmp = 0; + while (ext_mdio_read(tp, 0x0a43, 31) != 0x0a43) { + pr_info("."); + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err("\n External RGMII PHY not found, current = 0x%02x\n", + ext_mdio_read(tp, 0x0a43, 31)); + return; + } + } + if (tmp < 2000) + pr_info("found.\n"); + + /* set RGMII RX delay */ + tmp = rtl_ocp_read(tp, 0xea34) & + ~(BIT(14) | BIT(9) | BIT(8) | BIT(6)); + switch (tp->rgmii.rx_delay) { + case 1: + tmp |= (0x0 << 6) | (0x1 << 8); + break; + case 2: + tmp |= (0x0 << 6) | (0x2 << 8); + break; + case 3: + tmp |= (0x0 << 6) | (0x3 << 8); + break; + case 4: + tmp |= (0x1 << 6) | (0x0 << 8); + break; + case 5: + tmp |= (0x1 << 6) | (0x1 << 8); + break; + case 6: + tmp |= (0x1 << 6) | (0x2 << 8); + break; + case 7: + tmp |= (0x1 << 6) | (0x3 << 8); + } + rtl_ocp_write(tp, 0xea34, tmp); + + tmp = rtl_ocp_read(tp, 0xea36) & ~(BIT(0)); /* rg_clk_en */ + rtl_ocp_write(tp, 0xea36, tmp); + + /* external PHY RGMII timing tuning, + * rg_rgmii_id_mode = 1 (default) + */ + tmp = ext_mdio_read(tp, 0x0d08, 21); + switch (tp->rgmii.rx_delay) { + case 0: + case 1: + case 2: + case 3: + tmp |= BIT(3); + break; + case 4: + case 5: + case 6: + case 7: + tmp &= ~BIT(3); + } + ext_mdio_write(tp, 0x0d08, 21, tmp); + + /* set RGMII TX delay */ + if (tp->rgmii.tx_delay == 0) { + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(7)); + rtl_ocp_write(tp, 0xea34, tmp); + + /* external PHY RGMII timing tuning, tx_dly_mode = 1 */ + ext_mdio_write(tp, 0x0d08, 17, + ext_mdio_read(tp, 0x0d08, 17) | BIT(8)); + } else { /* tp->tx_delay == 1 (2ns) */ + tmp = rtl_ocp_read(tp, 0xea34) | (BIT(7)); + rtl_ocp_write(tp, 0xea34, tmp); + + /* external PHY RGMII timing tuning, tx_dly_mode = 0 */ + ext_mdio_write(tp, 0x0d08, 17, + ext_mdio_read(tp, 0x0d08, 17) & ~BIT(8)); + } + + /* ISO spec, data path is set to RGMII */ + tmp = rtl_ocp_read(tp, 0xea30) & ~(BIT(0)); + rtl_ocp_write(tp, 0xea30, tmp); + + tmp = rtl_ocp_read(tp, 0xea34) & ~(BIT(0) | BIT(1)); + tmp |= BIT(0); /* RGMII */ + rtl_ocp_write(tp, 0xea34, tmp); + + /* ext_phy == true now */ + + break; + default: + pr_err(PFX "%s:%d: unsupport output mode (%d) in FPGA\n", + __func__, __LINE__, tp->output_mode); + } +} + +static void rtd13xx_eee_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + tp->chip->mdio_lock(tp); + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* enable eee auto fallback function */ + rtl_phy_write(tp, 0x0a4b, 17, + rtl_phy_read(tp, 0x0a4b, 17) | BIT(2)); + /* 1000M/100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, (BIT(2) | BIT(1))); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | BIT(4) | BIT(2)); + /* keep RXC in LPI mode */ + rtl_mmd_write(tp, 0x3, 0, + rtl_mmd_read(tp, 0x3, 0) & ~BIT(10)); + } else { /* RGMII */ + /* enable eee auto fallback function */ + rtl_phy_write(tp, 0x0a4b, 17, + rtl_phy_read(tp, 0x0a4b, 17) | BIT(2)); + /* 1000M & 100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, (BIT(2) | BIT(1))); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | BIT(4) | BIT(2)); + /* stop RXC in LPI mode */ + rtl_mmd_write(tp, 0x3, 0, + rtl_mmd_read(tp, 0x3, 0) | BIT(10)); + } + /* EEE Tw_sys_tx timing adjustment, + * make sure MAC would send data after FEPHY wake up + */ + /* default 0x001F, 100M EEE */ + rtl_ocp_write(tp, 0xe04a, 0x002f); + /* default 0x0011, 1000M EEE */ + rtl_ocp_write(tp, 0xe04c, 0x001a); + /* EEEP Tw_sys_tx timing adjustment, + * make sure MAC would send data after FEPHY wake up + */ + /* default 0x3f, 10M EEEP */ + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* FEPHY needs 160us */ + rtl_ocp_write(tp, 0xe08a, 0x00a8); + } else { /* RGMII, GPHY needs 25us */ + rtl_ocp_write(tp, 0xe08a, 0x0020); + } + /* default 0x0005, 100M/1000M EEEP */ + rtl_ocp_write(tp, 0xe08c, 0x0008); + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) | BIT(1) | BIT(0)); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) | BIT(1)); + } else { + tp->chip->mdio_lock(tp); + if (tp->output_mode == OUTPUT_EMBEDDED_PHY) { + /* disable eee auto fallback function */ + rtl_phy_write(tp, 0x0a4b, 17, + rtl_phy_read(tp, 0x0a4b, 17) & ~BIT(2)); + /* 100M & 1000M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + /* keep RXC in LPI mode */ + rtl_mmd_write(tp, 0x3, 0, + rtl_mmd_read(tp, 0x3, 0) & ~BIT(10)); + } else { /* RGMII */ + /* disable eee auto fallback function */ + rtl_phy_write(tp, 0x0a4b, 17, + rtl_phy_read(tp, 0x0a4b, 17) & ~BIT(2)); + /* 100M & 1000M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + /* keep RXC in LPI mode */ + rtl_mmd_write(tp, 0x3, 0, + rtl_mmd_read(tp, 0x3, 0) & ~BIT(10)); + } + /* reset to default value */ + rtl_ocp_write(tp, 0xe040, rtl_ocp_read(tp, 0xe040) | BIT(13)); + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) & ~(BIT(1) | BIT(0))); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) & ~BIT(1)); + /* EEE Tw_sys_tx timing restore */ + /* default 0x001F, 100M EEE */ + rtl_ocp_write(tp, 0xe04a, 0x001f); + /* default 0x0011, 1000M EEE */ + rtl_ocp_write(tp, 0xe04c, 0x0011); + /* EEEP Tw_sys_tx timing restore */ + /* default 0x3f, 10M EEEP */ + rtl_ocp_write(tp, 0xe08a, 0x003f); + /* default 0x0005, 100M/1000M EEEP */ + rtl_ocp_write(tp, 0xe08c, 0x0005); + } +} + +static void rtd13xx_led_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_MUXPAD2, + GENMASK(9, 4), (9 << 4), NULL, false, true); + } else { + regmap_update_bits_base(tp->pinctrl_base, RTD13XX_ISO_TESTMUX_MUXPAD2, + GENMASK(9, 4), 0, NULL, false, true); + } +} + +static void rtd13xx_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + u32 val; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + seq_printf(m, "ISO_UMSK_ISR\t[0x98007004] = %08x\n", val); + regmap_read(tp->iso_base, ISO_PWRCUT_ETN, &val); + seq_printf(m, "ISO_PWRCUT_ETN\t[0x9800705c] = %08x\n", val); + regmap_read(tp->iso_base, ISO_ETN_TESTIO, &val); + seq_printf(m, "ISO_ETN_TESTIO\t[0x98007060] = %08x\n", val); + regmap_read(tp->iso_base, ISO_SOFT_RESET, &val); + seq_printf(m, "ETN_RESET_CTRL\t[0x98007088] = %08x\n", val); + regmap_read(tp->iso_base, ISO_CLOCK_ENABLE, &val); + seq_printf(m, "ETN_CLK_CTRL\t[0x9800708c] = %08x\n", val); +} + +static void rtd13xx_dump_var(struct seq_file *m, struct rtl8169_private *tp) +{ + seq_printf(m, "voltage \t%d\n", tp->rgmii.voltage); + seq_printf(m, "tx_delay\t%d\n", tp->rgmii.tx_delay); + seq_printf(m, "rx_delay\t%d\n", tp->rgmii.rx_delay); +} + +/******************* END of RTD13XX ****************************/ + +/* RTD16XXB */ +static void rtd16xxb_mdio_lock(struct rtl8169_private *tp) +{ + rtd139x_mdio_lock(tp); +} + +static void rtd16xxb_mdio_unlock(struct rtl8169_private *tp) +{ + rtd139x_mdio_unlock(tp); +} + +static void rtd16xxb_reset_phy_gmac(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* reg_0x9800708c[12:11] = 00 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_disable_unprepare(clk_etn_sys); + clk_disable_unprepare(clk_etn_250m); + + /* reg_0x98007088[10:9] = 00 */ + /* ISO spec, rstn_gphy & rstn_gmac */ + reset_control_assert(rstc_gphy); + reset_control_assert(rstc_gmac); + + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x9800705c[5] = 0 */ + /* ISO spec, default value and specify internal/external PHY ID as 1 */ + regmap_update_bits_base(tp->iso_base, ISO_PWRCUT_ETN, + BIT(5), 0, NULL, false, true); + /* set int PHY addr */ + __int_set_phy_addr(tp, RTD16XXB_INT_PHY_ADDR); + /* set ext PHY addr */ + __ext_set_phy_addr(tp, RTD16XXB_EXT_PHY_ADDR); + + mdelay(1); + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd16xxb_pll_clock_init(struct rtl8169_private *tp) +{ + struct clk *clk_etn_sys = clk_get(&tp->pdev->dev, "etn_sys"); + struct clk *clk_etn_250m = clk_get(&tp->pdev->dev, "etn_250m"); + struct reset_control *rstc_gphy = + reset_control_get_exclusive(&tp->pdev->dev, "gphy"); + struct reset_control *rstc_gmac = + reset_control_get_exclusive(&tp->pdev->dev, "gmac"); + u32 tmp; + u32 val; + + /* reg_0x98007004[27] = 1 */ + /* ISO spec, ETN_PHY_INTR, clear ETN interrupt for ByPassMode */ + regmap_write(tp->iso_base, ISO_UMSK_ISR, BIT(27)); + + /* reg_0x98007088[10] = 1 */ + /* ISO spec, reset bit of fephy */ + reset_control_deassert(rstc_gphy); + + mdelay(1); /* wait 1ms for PHY PLL stable */ + + /* reg_0x98007060[1] = 1 */ + /* ISO spec, bypass mode enable */ + regmap_update_bits_base(tp->iso_base, ISO_ETN_TESTIO, + BIT(1), BIT(1), NULL, false, true); + + /* reg_0x98007088[9] = 1 */ + /* ISO spec, reset bit of gmac */ + reset_control_deassert(rstc_gmac); + + /* reg_0x9800708c[12:11] = 11 */ + /* ISO spec, clock enable bit for etn clock & etn 250MHz */ + clk_prepare_enable(clk_etn_sys); + clk_prepare_enable(clk_etn_250m); + + /* Check ETN MAC init_autoload_done reg_0x98007070[0] = 1 */ + /* Bit 0 changes to 1 means ETN Rbus is valid */ + regmap_read(tp->iso_base, ISO_PLL_WDOUT, &val); + tmp = 0; + while (0x1 != (val & BIT(0))) { + tmp += 1; + mdelay(1); + if (tmp >= MAC_INIT_TIMEOUT) { + pr_err("GMAC init timeout\n"); + break; + } + regmap_read(tp->iso_base, ISO_PLL_WDOUT, &val); + } + if (tmp < MAC_INIT_TIMEOUT) + pr_info("GMAC wait %d ms for init_autoload_done\n", tmp); + + /* release resource */ + reset_control_put(rstc_gphy); + reset_control_put(rstc_gmac); +} + +static void rtd16xxb_load_otp_content(struct rtl8169_private *tp) +{ + u32 otp; + u16 tmp; + u8 *buf; + + /* R-K 0x9803_2504[3:0] : 4 bits, common setting + * Amp-K 0x9803_2504[31:16]: total 16 bits, 4 bits/channel + * RC-K 0x9803_2508[15:0] : total 16 bits, 4 bits/channel + */ + + buf = r8169soc_read_otp(tp, "rc_r_amp_cal"); + if (IS_ERR(buf)) + return; + + /* R-K 0x9803_2504[3:0] */ + otp = *buf & 0xF; + tmp = otp ^ RTD16XXB_R_K_DEFAULT; + /* Set tapbin_p3 & tapbin_p2 */ + int_mdio_write(tp, 0x0bcf, 18, ((tmp << 8) | tmp)); + /* Set tapbin_p1 & tapbin_p0 */ + int_mdio_write(tp, 0x0bcf, 19, ((tmp << 8) | tmp)); + /* Set tapbin_pm_p3 & tapbin_pm_p2 */ + int_mdio_write(tp, 0x0bcf, 20, ((tmp << 8) | tmp)); + /* Set tapbin_pm_p1 & tapbin_pm_p0 */ + int_mdio_write(tp, 0x0bcf, 21, ((tmp << 8) | tmp)); + + /* Amp-K 0x9803_2504[31:16] */ + otp = buf[2] | (buf[3] << 8); + tmp = otp ^ RTD16XXB_AMP_K_DEFAULT; + int_mdio_write(tp, 0x0bca, 22, tmp); + + /* RC-K 0x9803_2508[15:0] */ + otp = buf[4] | (buf[5] << 8); + tmp = otp ^ RTD16XXB_RC_K_DEFAULT; + int_mdio_write(tp, 0x0bcd, 22, tmp); /* len_p[3:0] */ + int_mdio_write(tp, 0x0bcd, 23, tmp); /* rlen_p[3:0] */ + + kfree(buf); +} + +static void rtd16xxb_phy_iol_tuning(struct rtl8169_private *tp) +{ + u32 otp; + u8 *buf; + u16 tmp; + + /* for common mode voltage */ + tmp = 0xb4 << 4; + int_mdio_write(tp, 0x0bc0, 17, + (int_mdio_read(tp, 0x0bc0, 17) & ~(0xff << 4)) | tmp); + + /* Set LD_COMP to 0x0 */ + tmp = 0 << 9; + int_mdio_write(tp, 0x0bc0, 23, + (int_mdio_read(tp, 0x0bc0, 23) & ~(0x3 << 9)) | tmp); + + /* set lock main */ + tmp = 0x1 << 1; + int_mdio_write(tp, 0x0a46, 21, + int_mdio_read(tp, 0x0a46, 21) | tmp); + /* wait until locked */ + tmp = 0; + while (0x1 != (int_mdio_read(tp, 0x0a60, 16) & (0xff << 0))) { + tmp += 10; + usleep_range(10, 11); + if (tmp >= PHY_LOCK_TIMEOUT) { + pr_err("Ethernet PHY is not locked (0x1), current = 0x%02x\n", + (int_mdio_read(tp, 0x0a60, 16) & (0xff << 0))); + break; + } + } + if (tmp < PHY_LOCK_TIMEOUT) + pr_info("Ethernet PHY: wait %d ns to start IOL tuning\n", tmp); + + /* Change green table default LDVBIAS to 0x66 */ + tmp = 0x66 << 8; + int_mdio_write(tp, 0x0a43, 27, 0x8049); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Change green table 10M LDVBIAS to 0x66 */ + int_mdio_write(tp, 0x0a43, 27, 0x8050); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Change green table 100M short LDVBIAS to 0x66 */ + int_mdio_write(tp, 0x0a43, 27, 0x8057); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Change green table 100M long LDVBIAS to 0x66 */ + int_mdio_write(tp, 0x0a43, 27, 0x805e); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Change green table GIGA short LDVBIAS to 0x66 */ + int_mdio_write(tp, 0x0a43, 27, 0x8065); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Change green table GIGA middle LDVBIAS to 0x66 */ + int_mdio_write(tp, 0x0a43, 27, 0x806c); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Change green table GIGA long LDVBIAS to 0x66 */ + int_mdio_write(tp, 0x0a43, 27, 0x8073); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0xff << 8)) | tmp); + + /* Use OTP 0x98032508 bit[17:16] to identify amp-k pattern version */ + /* b'00: original amp-k pattern */ + /* b'01: new amp-k pattern (rg_cal_itune = 0, LDVDC = 1, LD_CMFB = 2). + * Change LD_CMFB to 0x2 and LDVDC to 0x5 in normal mode. + */ + buf = r8169soc_read_otp(tp, "rc_r_amp_cal"); + if (IS_ERR(buf)) + goto out; + + otp = buf[6]; + kfree(buf); + + if ((otp & 0x3) == 0x1) { + /* Change LD_CMFB to 0x2 */ + tmp = 0x2 << 12; + int_mdio_write(tp, 0x0bc0, 23, + (int_mdio_read(tp, 0x0bc0, 23) & ~(0x3 << 12)) | tmp); + + /* Change green table default LDVDC to 0x5 */ + tmp = 0x5 << 8; + int_mdio_write(tp, 0x0a43, 27, 0x804d); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + + /* Change green table 10M LDVDC to 0x5 */ + int_mdio_write(tp, 0x0a43, 27, 0x8054); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + + /* Change green table 100M short LDVDC to 0x5 */ + int_mdio_write(tp, 0x0a43, 27, 0x805b); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + + /* Change green table 100M long LDVDC to 0x5 */ + int_mdio_write(tp, 0x0a43, 27, 0x8062); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + + /* Change green table Giga short LDVDC to 0x5 */ + int_mdio_write(tp, 0x0a43, 27, 0x8069); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + + /* Change green table Giga middle LDVDC to 0x5 */ + int_mdio_write(tp, 0x0a43, 27, 0x8070); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + + /* Change green table Giga long LDVDC to 0x5 */ + int_mdio_write(tp, 0x0a43, 27, 0x8077); + int_mdio_write(tp, 0x0a43, 28, + (int_mdio_read(tp, 0x0a43, 28) & ~(0x7 << 8)) | tmp); + } + +out: + /* release lock main */ + tmp = 0x0 << 1; + int_mdio_write(tp, 0x0a46, 21, + (int_mdio_read(tp, 0x0a46, 21) & ~(0x1 << 1)) | tmp); +} + +static void rtd16xxb_mdio_init(struct rtl8169_private *tp) +{ + u32 tmp; + void __iomem *ioaddr = tp->mmio_addr; + + mdelay(10); /* wait for MDIO ready */ + + /* PHY will stay in state 1 mode */ + tmp = 0; + while (0x1 != (int_mdio_read(tp, 0x0a42, 16) & 0x07)) { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x1 in bypass mode, current = 0x%02x\n", + (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } + + /* ETN spec. set MDC freq = 8.9MHZ */ + tmp = rtl_ocp_read(tp, 0xde10) & ~(BIT(7) | BIT(6)); + tmp |= BIT(6); /* MDC freq = 8.9MHz */ + rtl_ocp_write(tp, 0xde10, tmp); + + /* fill fuse_rdy & rg_ext_ini_done */ + int_mdio_write(tp, 0x0a46, 20, + int_mdio_read(tp, 0x0a46, 20) | (BIT(1) | BIT(0))); + + /* init_autoload_done = 1 */ + tmp = rtl_ocp_read(tp, 0xe004); + tmp |= BIT(7); + rtl_ocp_write(tp, 0xe004, tmp); + + /* ee_mode = 3 */ + RTL_W8(CFG9346, CFG9346_UNLOCK); + + /* wait LAN-ON */ + tmp = 0; + do { + tmp += 1; + mdelay(1); + if (tmp >= 2000) { + pr_err(PFX "PHY status is not 0x3, current = 0x%02x\n", + (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + break; + } + } while (0x3 != (int_mdio_read(tp, 0x0a42, 16) & 0x07)); + pr_info(PFX "wait %d ms for PHY ready, current = 0x%x\n", + tmp, int_mdio_read(tp, 0x0a42, 16)); + + /* adjust PHY electrical characteristics */ + rtd16xxb_phy_iol_tuning(tp); + + /* load OTP contents (R-K, Amp) + */ + rtd16xxb_load_otp_content(tp); + + switch (tp->output_mode) { + case OUTPUT_EMBEDDED_PHY: + /* ISO spec, set data path to FEPHY */ + tmp = rtl_ocp_read(tp, 0xea30); + tmp &= ~(BIT(0)); + rtl_ocp_write(tp, 0xea30, tmp); + + tmp = rtl_ocp_read(tp, 0xea34); + tmp &= ~(BIT(1) | BIT(0)); + tmp |= BIT(1); /* FEPHY */ + rtl_ocp_write(tp, 0xea34, tmp); + + /* LED low active circuit */ + /* output current: 4mA */ + regmap_update_bits_base(tp->pinctrl_base, RTD16XXB_ISO_TESTMUX_PFUNC12, + GENMASK(14, 0), + (0x16 << 10) | (0x16 << 5) | (0x16 << 0), + NULL, false, true); + break; + default: + pr_err(PFX "%s:%d: unsupport output mode (%d)\n", + __func__, __LINE__, tp->output_mode); + } +} + +static void rtd16xxb_eee_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + /* enable eee auto fallback function */ + rtl_phy_write(tp, 0x0a4b, 17, + rtl_phy_read(tp, 0x0a4b, 17) | BIT(2)); + /* 1000M/100M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, (BIT(2) | BIT(1))); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) | (BIT(4) | BIT(2))); + /* keep RXC in LPI mode */ + rtl_mmd_write(tp, 0x3, 0, + rtl_mmd_read(tp, 0x3, 0) & ~BIT(10)); + /* EEE Tw_sys_tx timing adjustment, + * make sure MAC would send data after FEPHY wake up + */ + /* default 0x001F, 100M EEE */ + rtl_ocp_write(tp, 0xe04a, 0x002f); + /* default 0x0011, 1000M EEE */ + rtl_ocp_write(tp, 0xe04c, 0x001a); + /* EEEP Tw_sys_tx timing adjustment, + * make sure MAC would send data after FEPHY wake up + */ + /* default 0x3f, 10M EEEP */ + /* FEPHY needs 160us */ + rtl_ocp_write(tp, 0xe08a, 0x00a8); + /* default 0x0005, 100M/1000M EEEP */ + rtl_ocp_write(tp, 0xe08c, 0x0008); + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) | BIT(1) | BIT(0)); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) | BIT(1)); + } else { + /* disable eee auto fallback function */ + rtl_phy_write(tp, 0x0a4b, 17, + rtl_phy_read(tp, 0x0a4b, 17) & ~BIT(2)); + /* 100M & 1000M EEE capability */ + rtl_mmd_write(tp, 0x7, 60, 0); + /* 10M EEE */ + rtl_phy_write(tp, 0x0a43, 25, + rtl_phy_read(tp, 0x0a43, 25) & ~(BIT(4) | BIT(2))); + /* keep RXC in LPI mode */ + rtl_mmd_write(tp, 0x3, 0, + rtl_mmd_read(tp, 0x3, 0) & ~BIT(10)); + /* reset to default value */ + rtl_ocp_write(tp, 0xe040, rtl_ocp_read(tp, 0xe040) | BIT(13)); + /* EEE MAC mode */ + rtl_ocp_write(tp, 0xe040, + rtl_ocp_read(tp, 0xe040) & ~(BIT(1) | BIT(0))); + /* EEE+ MAC mode */ + rtl_ocp_write(tp, 0xe080, rtl_ocp_read(tp, 0xe080) & ~BIT(1)); + /* EEE Tw_sys_tx timing restore */ + /* default 0x001F, 100M EEE */ + rtl_ocp_write(tp, 0xe04a, 0x001f); + /* default 0x0011, 1000M EEE */ + rtl_ocp_write(tp, 0xe04c, 0x0011); + /* EEEP Tw_sys_tx timing restore */ + /* default 0x3f, 10M EEEP */ + rtl_ocp_write(tp, 0xe08a, 0x003f); + /* default 0x0005, 100M/1000M EEEP */ + rtl_ocp_write(tp, 0xe08c, 0x0005); + } +} + +static void rtd16xxb_led_set(struct rtl8169_private *tp, bool enable) +{ + if (enable) { + regmap_update_bits_base(tp->pinctrl_base, RTD16XXB_ISO_TESTMUX_MUXPAD2, + GENMASK(30, 29) | GENMASK(12, 8), + (0x1 << 29) | (0x1 << 11) | (0x1 << 8), + NULL, false, true); + } else { + regmap_update_bits_base(tp->pinctrl_base, RTD16XXB_ISO_TESTMUX_MUXPAD2, + GENMASK(30, 29) | GENMASK(12, 8), + 0, NULL, false, true); + } +} + +static void rtd16xxb_dump_regs(struct seq_file *m, struct rtl8169_private *tp) +{ + u32 val; + + regmap_read(tp->iso_base, ISO_UMSK_ISR, &val); + seq_printf(m, "ISO_UMSK_ISR\t[0x98007004] = %08x\n", val); + regmap_read(tp->iso_base, ISO_PWRCUT_ETN, &val); + seq_printf(m, "ISO_PWRCUT_ETN\t[0x9800705c] = %08x\n", val); + regmap_read(tp->iso_base, ISO_ETN_TESTIO, &val); + seq_printf(m, "ISO_ETN_TESTIO\t[0x98007060] = %08x\n", val); + regmap_read(tp->iso_base, ISO_SOFT_RESET, &val); + seq_printf(m, "ETN_RESET_CTRL\t[0x98007088] = %08x\n", val); + regmap_read(tp->iso_base, ISO_CLOCK_ENABLE, &val); + seq_printf(m, "ETN_CLK_CTRL\t[0x9800708c] = %08x\n", val); +} + +/******************* END of RTD16XXB ****************************/ +static struct r8169soc_chip_info rtd119x_info = { + .name = "RTD119X", + .reset_phy_gmac = rtd119x_reset_phy_gmac, + .acp_init = NULL, + .pll_clock_init = rtd119x_pll_clock_init, + .mdio_init = rtd119x_mdio_init, + .mac_mcu_patch = rtd119x_mac_mcu_patch, + .hw_phy_config = rtd119x_hw_phy_config, + .eee_set = rtd119x_eee_set, + .led_set = rtd119x_led_set, + .dump_regs = rtd119x_dump_regs, + .dump_var = rtd119x_dump_var, + .mac_version = 41, + .cfg_version = RTL_CFG_1, + .txd_version = RTL_TD_1, + .jumbo_max = JUMBO_9K, + .jumbo_tx_csum = false, + .led_cfg = 0x000670CA, + .region = 2, + .align = 8, + .event_slow = SYS_ERR | LINK_CHG | RX_OVERFLOW, + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI, +}; + +static struct r8169soc_chip_info rtd129x_info = { + .name = "RTD129X", + .mdio_lock = rtd129x_mdio_lock, + .mdio_unlock = rtd129x_mdio_unlock, + .reset_phy_gmac = rtd129x_reset_phy_gmac, + .acp_init = NULL, + .pll_clock_init = rtd129x_pll_clock_init, + .mac_mcu_patch = rtd129x_mac_mcu_patch, + .hw_phy_config = rtd129x_hw_phy_config, + .eee_set = rtd129x_eee_set, + .led_set = rtd129x_led_set, + .dump_regs = rtd129x_dump_regs, + .dump_var = rtd129x_dump_var, + .mac_version = 41, + .cfg_version = RTL_CFG_1, + .txd_version = RTL_TD_1, + .jumbo_max = JUMBO_9K, + .jumbo_tx_csum = false, + .led_cfg = 0x000670CA, + .region = 2, + .align = 8, + .event_slow = SYS_ERR | LINK_CHG | RX_OVERFLOW, + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI | + RTL_FEATURE_EEE, +}; + +static struct r8169soc_chip_info rtd139x_info = { + .name = "RTD139X", + .mdio_lock = rtd139x_mdio_lock, + .mdio_unlock = rtd139x_mdio_unlock, + .reset_phy_gmac = rtd139x_reset_phy_gmac, + .acp_init = rtd139x_acp_init, + .pll_clock_init = rtd139x_pll_clock_init, + .mdio_init = rtd139x_mdio_init, + .wakeup_set = rtl_crc_wakeup_set, + .eee_set = rtd139x_eee_set, + .led_set = rtd139x_led_set, + .dump_regs = rtd139x_dump_regs, + .dump_var = rtd139x_dump_var, + .mac_version = 41, + .cfg_version = RTL_CFG_1, + .txd_version = RTL_TD_1, + .jumbo_max = JUMBO_9K, + .jumbo_tx_csum = false, + .led_cfg = 0x000679A9, + .region = 2, + .align = 8, + .event_slow = SYS_ERR | LINK_CHG | RX_OVERFLOW, + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI | + RTL_FEATURE_ACP | RTL_FEATURE_EEE, +}; + +static struct r8169soc_chip_info rtd16xx_info = { + .name = "RTD16XX", + .mdio_lock = rtd16xx_mdio_lock, + .mdio_unlock = rtd16xx_mdio_unlock, + .reset_phy_gmac = rtd16xx_reset_phy_gmac, + .acp_init = rtd16xx_acp_init, + .pll_clock_init = rtd16xx_pll_clock_init, + .mdio_init = rtd16xx_mdio_init, + .wakeup_set = rtl_crc_wakeup_set, + .eee_set = rtd16xx_eee_set, + .led_set = rtd16xx_led_set, + .dump_regs = rtd16xx_dump_regs, + .dump_var = rtd16xx_dump_var, + .mac_version = 41, + .cfg_version = RTL_CFG_1, + .txd_version = RTL_TD_1, + .jumbo_max = JUMBO_9K, + .jumbo_tx_csum = false, + .led_cfg = 0x00067CA9, + .region = 2, + .align = 8, + .event_slow = SYS_ERR | LINK_CHG | RX_OVERFLOW, + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI | + RTL_FEATURE_TX_NO_CLOSE | + RTL_FEATURE_ADJUST_FIFO | + RTL_FEATURE_ACP | RTL_FEATURE_EEE, +}; + +static struct r8169soc_chip_info rtd13xx_info = { + .name = "RTD13XX", + .mdio_lock = rtd13xx_mdio_lock, + .mdio_unlock = rtd13xx_mdio_unlock, + .reset_phy_gmac = rtd13xx_reset_phy_gmac, + .acp_init = rtd13xx_acp_init, + .pll_clock_init = rtd13xx_pll_clock_init, + .mdio_init = rtd13xx_mdio_init, + .wakeup_set = rtl_crc_wakeup_set, + .eee_set = rtd13xx_eee_set, + .led_set = rtd13xx_led_set, + .dump_regs = rtd13xx_dump_regs, + .dump_var = rtd13xx_dump_var, + .mac_version = 41, + .cfg_version = RTL_CFG_1, + .txd_version = RTL_TD_1, + .jumbo_max = JUMBO_9K, + .jumbo_tx_csum = false, + .led_cfg = 0x00067CA9, + .region = 2, + .align = 8, + .event_slow = SYS_ERR | LINK_CHG | RX_OVERFLOW, + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI | + RTL_FEATURE_TX_NO_CLOSE | + RTL_FEATURE_ADJUST_FIFO | + RTL_FEATURE_ACP | RTL_FEATURE_EEE, +}; + +static struct r8169soc_chip_info rtd16xxb_info = { + .name = "RTD16XXB", + .mdio_lock = rtd16xxb_mdio_lock, + .mdio_unlock = rtd16xxb_mdio_unlock, + .reset_phy_gmac = rtd16xxb_reset_phy_gmac, + .pll_clock_init = rtd16xxb_pll_clock_init, + .mdio_init = rtd16xxb_mdio_init, + .wakeup_set = rtl_pat_wakeup_set, + .eee_set = rtd16xxb_eee_set, + .led_set = rtd16xxb_led_set, + .dump_regs = rtd16xxb_dump_regs, + .mac_version = 41, + .cfg_version = RTL_CFG_1, + .txd_version = RTL_TD_1, + .jumbo_max = JUMBO_9K, + .jumbo_tx_csum = false, + .led_cfg = 0x17000CA9, + .region = 2, + .align = 8, + .event_slow = SYS_ERR | LINK_CHG | RX_OVERFLOW, + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI | + RTL_FEATURE_TX_NO_CLOSE | + RTL_FEATURE_ADJUST_FIFO | + RTL_FEATURE_EEE | + RTL_FEATURE_OCP_MDIO | + RTL_FEATURE_PAT_WAKE, +}; + +static const struct of_device_id r8169soc_dt_ids[] = { + { + .compatible = "realtek,rtd119x-r8169soc", + .data = &rtd119x_info, + }, + { + .compatible = "realtek,rtd129x-r8169soc", + .data = &rtd129x_info, + }, + { + .compatible = "realtek,rtd139x-r8169soc", + .data = &rtd139x_info, + }, + { + .compatible = "realtek,rtd16xx-r8169soc", + .data = &rtd16xx_info, + }, + { + .compatible = "realtek,rtd13xx-r8169soc", + .data = &rtd13xx_info, + }, + { + .compatible = "realtek,rtd16xxb-r8169soc", + .data = &rtd16xxb_info, + }, + { + } +}; + +MODULE_DEVICE_TABLE(of, r8169soc_dt_ids); + +static void rtk_chip_info_check(struct r8169soc_chip_info *chip) +{ + if (!chip) + return; + + if (!chip->mdio_lock) + chip->mdio_lock = dummy_mdio_lock; + if (!chip->mdio_unlock) + chip->mdio_unlock = dummy_mdio_unlock; + if (!chip->pll_power_down) + chip->pll_power_down = r8168_pll_power_down; + if (!chip->pll_power_up) + chip->pll_power_up = r8168_pll_power_up; + if (!chip->csi_write) + chip->csi_write = r8169_csi_write; + if (!chip->csi_read) + chip->csi_read = r8169_csi_read; + if (!chip->set_speed) + chip->set_speed = rtl8169_set_speed_xmii; + if (!chip->phy_reset_enable) + chip->phy_reset_enable = rtl8169_xmii_reset_enable; + if (!chip->phy_reset_pending) + chip->phy_reset_pending = rtl8169_xmii_reset_pending; + if (!chip->link_ok) + chip->link_ok = rtl8169_xmii_link_ok; + if (!chip->do_ioctl) + chip->do_ioctl = rtl_xmii_ioctl; + if (!chip->hw_start) + chip->hw_start = rtl_hw_start_8168; + if (!chip->reset_phy_gmac) + chip->reset_phy_gmac = dummy_reset_phy_gmac; + if (!chip->acp_init) + chip->acp_init = dummy_acp_init; + if (!chip->pll_clock_init) + chip->pll_clock_init = dummy_pll_clock_init; + if (!chip->mdio_init) + chip->mdio_init = dummy_mdio_init; + if (!chip->mac_mcu_patch) + chip->mac_mcu_patch = dummy_mac_mcu_patch; + if (!chip->hw_phy_config) + chip->hw_phy_config = dummy_hw_phy_config; + if (!chip->wakeup_set) + chip->wakeup_set = dummy_wakeup_set; + if (!chip->eee_set) + chip->eee_set = dummy_eee_set; + if (!chip->led_set) + chip->led_set = dummy_led_set; + if (!chip->dump_regs) + chip->dump_regs = dummy_dump_regs; + if (!chip->dump_var) + chip->dump_var = dummy_dump_var; + + #if defined(CONFIG_RTL_RX_NO_COPY) + chip->features |= RTL_FEATURE_RX_NO_COPY; + #endif /* CONFIG_RTL_RX_NO_COPY */ +} + +static int rtl_init_one(struct platform_device *pdev) +{ + struct r8169soc_chip_info *chip; + struct rtl8169_private *tp; + struct mii_if_info *mii; + struct net_device *ndev; + void __iomem *ioaddr; + int i; + int rc; + int led_config; + u32 tmp; + int irq; + int retry; + const char *mac_addr; + struct property *wake_mask; + struct property *wake_pattern; + char tmp_str[80]; + int wake_size; + int wake_mask_size; + struct device_node *phy_0; + u32 phy_irq_num = 0; + u32 phy_irq_mask = 0; + u32 phy_irq[POR_NUM] = {0, 0, 0}; + u8 phy_irq_map[POR_NUM + 1] = {0, 0, 0, 0}; + u32 phy_por_xv_mask; + static char phy_irq_name[POR_NUM][IFNAMSIZ]; +#ifdef RTL_PROC + struct proc_dir_entry *dir_dev = NULL; + struct proc_dir_entry *entry = NULL; +#endif + u32 bypass_enable = 0; + u32 acp_enable = 0; + u32 sgmii_swing = 0; + u32 voltage = 1; + u32 tx_delay = 0; + u32 rx_delay = 0; + u32 output_mode = 0; + u32 ext_phy_id = 1; + u32 eee_enable = 0; + u32 wol_enable = 0; + + if (netif_msg_drv(&debug)) { + pr_info("%s Gigabit Ethernet driver %s loaded\n", + MODULENAME, RTL8169_VERSION); + } + + chip = (struct r8169soc_chip_info *)of_device_get_match_data(&pdev->dev); + if (chip) { + rtk_chip_info_check(chip); + } else { + pr_err(PFX "%s no proper chip matched\n", __func__); + rc = -EINVAL; + goto out; + } + if (of_property_read_u32(pdev->dev.of_node, "output-mode", &output_mode)) + dprintk("%s can't get output mode", __func__); + if (of_property_read_u32(pdev->dev.of_node, "wol-enable", &wol_enable)) + dprintk("%s can't get wol_enable", __func__); + if (of_property_read_u32(pdev->dev.of_node, "eee", &eee_enable)) + dprintk("%s can't get eee_enable", __func__); + if (of_property_read_u32(pdev->dev.of_node, "acp", &acp_enable)) + dprintk("%s can't get acp", __func__); + + /* optional properties */ + if (of_property_read_u32(pdev->dev.of_node, "bypass", + &bypass_enable)) + bypass_enable = 1; + if (of_property_read_u32(pdev->dev.of_node, "led-cfg", &led_config)) + led_config = 0; + if (of_property_read_u32(pdev->dev.of_node, "ext-phy-id", &ext_phy_id)) + ext_phy_id = 0; + if (of_property_read_u32(pdev->dev.of_node, "sgmii-swing", + &sgmii_swing)) + sgmii_swing = 0; + if (of_property_read_u32(pdev->dev.of_node, "voltage", &voltage)) + voltage = 1; + if (of_property_read_u32(pdev->dev.of_node, "tx-delay", &tx_delay)) + tx_delay = 0; + if (of_property_read_u32(pdev->dev.of_node, "rx-delay", &rx_delay)) + rx_delay = 0; + if (of_get_property(pdev->dev.of_node, "force-Gb-off", NULL)) { + pr_info(PFX "~~~ disable Gb features~~~\n"); + chip->features &= ~RTL_FEATURE_GMII; + } + + phy_0 = of_get_child_by_name(pdev->dev.of_node, "phy_0"); + if (phy_0) { + phy_irq_num = of_irq_count(phy_0); + pr_info(PFX "get %d phy_irq\n", phy_irq_num); + if (phy_irq_num > POR_NUM) { + pr_err(PFX "%d exceed max. GPHY IRQ number\n", + phy_irq_num); + phy_irq_num = POR_NUM; + } + + if (of_property_read_u32(phy_0, "irq-mask", &phy_irq_mask)) { + pr_err(PFX "no irq-mask is defined\n"); + phy_irq_num = 0; + } else { + tmp = 0; + for (i = 0; i < 32; i++) { + if (phy_irq_mask & (1 << i)) + phy_irq_map[tmp++] = i; + + if (tmp > phy_irq_num) + break; + } + if (tmp != phy_irq_num) { + pr_err(PFX "IRQ number %d and IRQ mask 0x%08x don't match\n", + phy_irq_num, phy_irq_mask); + phy_irq_num = min(tmp, phy_irq_num); + } + } + for (i = 0; i < phy_irq_num; i++) { + phy_irq[i] = irq_of_parse_and_map(phy_0, i); + pr_info(PFX "get phy_irq %d for bit %d\n", + phy_irq[i], phy_irq_map[i]); + } + + if (of_property_read_u32(phy_0, "por-xv-mask", + &phy_por_xv_mask)) { + pr_info(PFX "no por-xv-mask is defined\n"); + phy_por_xv_mask = POR_XV_MASK; + } + } + /* end of optional properties */ + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + ioaddr = of_iomap(pdev->dev.of_node, 0); + + ndev = alloc_etherdev(sizeof(*tp)); + if (!ndev) { + rc = -ENOMEM; + goto err_out_iomap; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + ndev->irq = irq; + ndev->netdev_ops = &rtl_netdev_ops; + tp = netdev_priv(ndev); + tp->dev = ndev; + tp->pdev = pdev; + tp->chip = chip; + tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); + tp->mac_version = tp->chip->mac_version; + tp->mmio_addr = ioaddr; + tp->led_cfg = led_config; + tp->output_mode = output_mode; + tp->ext_phy_id = ext_phy_id; + if ((tp->chip->features & RTL_FEATURE_EEE) && eee_enable > 0) + tp->eee_enable = true; + else + tp->eee_enable = false; + tp->phy_irq_num = phy_irq_num; + tp->phy_por_xv_mask = phy_por_xv_mask; + for (i = 0; i < tp->phy_irq_num; i++) { + tp->phy_irq[i] = phy_irq[i]; + tp->phy_irq_map[i] = phy_irq_map[i]; + } + atomic_set(&tp->phy_reinit_flag, 0); + + /* ISO regs 0x98007000 */ + tp->iso_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "realtek,iso"); + if (IS_ERR_OR_NULL(tp->iso_base)) { + pr_err(PFX "Fail to get iso_base address\n"); + rc = -ENODEV; + goto err_out_netdev; + } else { + pr_info(PFX "Get iso_base address\n"); + } + + /* SB2 regs 0x9801a000 (optional) */ + /* it should be valid for rtd129x */ + tp->sb2_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "realtek,sb2"); + if (IS_ERR_OR_NULL(tp->sb2_base)) { + if (tp->chip == &rtd129x_info) { + pr_err(PFX "Fail to get sb2_base address\n"); + rc = -ENODEV; + goto err_out_netdev; + } + } else { + pr_info(PFX "Get sb2_base address\n"); + } + + /* SBX regs 0x9801c000 (optional) */ + /* it is not used by rtd119x, rtd129x, and rtd16xxb */ + /* it should be valid for rtd139x, rtd16xx, and rtd13xx */ + tp->sbx_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "realtek,sbx"); + if (IS_ERR_OR_NULL(tp->sbx_base)) { + if (tp->chip != &rtd119x_info && + tp->chip != &rtd129x_info && + tp->chip != &rtd16xxb_info) { + pr_err(PFX "Fail to get sbx_base address\n"); + rc = -ENODEV; + goto err_out_netdev; + } + } else { + pr_info(PFX "Get sbx_base address\n"); + } + + /* SCPU wrapper regs 0x9801d000 (optional) */ + /* it is not used by rtd119x, rtd129x, and rtd16xxb */ + /* it should be valid for rtd139x, rtd16xx, and rtd13xx */ + tp->scpu_wrap_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "realtek,scpu_wrapper"); + if (IS_ERR_OR_NULL(tp->scpu_wrap_base)) { + if (tp->chip != &rtd119x_info && + tp->chip != &rtd129x_info && + tp->chip != &rtd16xxb_info) { + pr_err(PFX "Fail to get scpu_wrap_base address\n"); + rc = -ENODEV; + goto err_out_netdev; + } + } else { + pr_info(PFX "Get scpu_wrap_base address\n"); + } + + /* pinctrl regs 0x9804e000 (optional) */ + /* it is not used by rtd119x and rtd129x */ + /* it should be valid for rtd139x, rtd16xx, and rtd13xx */ + tp->pinctrl_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "realtek,pinctrl"); + if (IS_ERR_OR_NULL(tp->pinctrl_base)) { + if (tp->chip != &rtd119x_info && tp->chip != &rtd129x_info) { + pr_err(PFX "Fail to get pinctrl_base address\n"); + rc = -ENODEV; + goto err_out_netdev; + } + } else { + pr_info(PFX "Get pinctrl_base address\n"); + } + + /* SDS regs 0x981c8000 (optional) */ + /* it should be valid for rtd139x and rtd16xx */ + tp->sds_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "realtek,sds"); + if (IS_ERR_OR_NULL(tp->sds_base)) { + if (tp->chip == &rtd139x_info || tp->chip == &rtd16xx_info) { + pr_err(PFX "Fail to get sds_base address\n"); + rc = -ENODEV; + goto err_out_netdev; + } + } else { + pr_info(PFX "Get sds_base address\n"); + } + + tp->bypass_enable = !!(bypass_enable > 0); + if ((tp->chip->features & RTL_FEATURE_ACP) && acp_enable > 0) + tp->acp_enable = true; + else + tp->acp_enable = false; + tp->ext_phy = false; + + switch (tp->output_mode) { + case OUTPUT_RGMII_TO_MAC: + case OUTPUT_RGMII_TO_PHY: + tp->rgmii.voltage = voltage; + tp->rgmii.tx_delay = tx_delay; + tp->rgmii.rx_delay = rx_delay; + break; + case OUTPUT_SGMII_TO_MAC: + case OUTPUT_SGMII_TO_PHY: + tp->sgmii.swing = sgmii_swing; + break; + case OUTPUT_RMII: + tp->rmii.voltage = voltage; + tp->rmii.tx_delay = tx_delay; + tp->rmii.rx_delay = rx_delay; + break; + case OUTPUT_EMBEDDED_PHY: + case OUTPUT_FORCE_LINK: + default: + /* do nothing */ + break; + } + + mii = &tp->mii; + mii->dev = ndev; + mii->mdio_read = rtl_mdio_read; + mii->mdio_write = rtl_mdio_write; + mii->phy_id_mask = 0x1f; + mii->reg_num_mask = 0x1f; + mii->supports_gmii = !!(tp->chip->features & RTL_FEATURE_GMII); + + rtl_init_mdio_ops(tp); + rtl_init_mmd_ops(tp); + tp->chip->reset_phy_gmac(tp); + tp->chip->acp_init(tp); + tp->chip->pll_clock_init(tp); + tp->chip->mdio_init(tp); + /* after r8169soc_mdio_init(), + * SGMII : tp->ext_phy == true ==> external MDIO, + * RGMII : tp->ext_phy == true ==> external MDIO, + * RMII : tp->ext_phy == false ==> internal MDIO, + * FE PHY: tp->ext_phy == false ==> internal MDIO + */ + + tp->chip->eee_set(tp, tp->eee_enable); + + /* Enable ALDPS */ + rtl_phy_write(tp, 0x0a43, 24, + rtl_phy_read(tp, 0x0a43, 24) | BIT(2)); + + tp->wol_enable = wol_enable; + tp->wol_crc_cnt = 0; + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + wake_size = RTL_WAKE_SIZE; + wake_mask_size = RTL_WAKE_MASK_SIZE; + } else { + wake_size = RTL_WAKE_SIZE_CRC; + wake_mask_size = RTL_WAKE_MASK_SIZE_CRC; + } + for (i = 0; i < wake_size; i++) { + memset(tmp_str, 0, 80); + sprintf(tmp_str, "wake-mask%d", i); + wake_mask = of_find_property(pdev->dev.of_node, tmp_str, NULL); + if (!wake_mask) + break; + tp->wol_rule[i].mask_size = wake_mask->length; + memcpy(&tp->wol_rule[i].mask[0], wake_mask->value, + (wake_mask->length > wake_mask_size) ? + wake_mask_size : wake_mask->length); + + sprintf(tmp_str, "wake-crc%d", i); + if (of_property_read_u32(pdev->dev.of_node, tmp_str, &tmp)) + break; + tp->wol_rule[i].crc = tmp & 0xFFFF; + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + sprintf(tmp_str, "wake-pattern%d", i); + wake_pattern = of_find_property(pdev->dev.of_node, tmp_str, NULL); + if (!wake_pattern) + break; + tmp = (wake_pattern->length > RTL_WAKE_PATTERN_SIZE) ? + RTL_WAKE_PATTERN_SIZE : wake_pattern->length; + tp->wol_rule[i].pattern_size = + rtl_cp_reduced_pattern(tp, i, wake_pattern->value, tmp); + + sprintf(tmp_str, "wake-offset%d", i); + if (of_property_read_u32(pdev->dev.of_node, tmp_str, &tmp)) + break; + tp->wol_rule[i].offset = tmp & 0xFFFF; + } + tp->wol_crc_cnt += 1; + tp->wol_rule[i].flag |= WAKE_FLAG_ENABLE; + } + +#ifdef RTL_PROC + do { + /* create /proc/net/$rtw_proc_name */ + rtw_proc = proc_mkdir_data("eth0", 0555, + init_net.proc_net, NULL); + + if (!rtw_proc) { + pr_info(PFX "procfs:create /proc/net/eth0 failed\n"); + break; + } + + /* create /proc/net/$rtw_proc_name/$dev->name */ + if (!tp->dir_dev) { + tp->dir_dev = proc_mkdir_data(MODULENAME, + S_IFDIR | 0555, + rtw_proc, ndev); + dir_dev = tp->dir_dev; + + if (!dir_dev) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169 failed\n"); + + if (rtw_proc) { + remove_proc_entry("eth0", + init_net.proc_net); + rtw_proc = NULL; + } + break; + } + } else { + break; + } + + entry = proc_create_data("wol_enable", S_IFREG | 0644, + dir_dev, &wol_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wol_enable failed\n"); + break; + } + + entry = proc_create_data("pwr_saving", S_IFREG | 0644, + dir_dev, &pwr_saving_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/pwr_saving failed\n"); + break; + } + + entry = proc_create_data("mac_reinit", S_IFREG | 0644, + dir_dev, &mac_reinit_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/mac_reinit failed\n"); + break; + } + + entry = proc_create_data("phy_reinit", S_IFREG | 0644, + dir_dev, &phy_reinit_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/phy_reinit failed\n"); + break; + } + + entry = proc_create_data("eee", S_IFREG | 0644, + dir_dev, &eee_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/eee failed\n"); + break; + } + + entry = proc_create_data("driver_var", S_IFREG | 0444, + dir_dev, &driver_var_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/driver_var failed\n"); + break; + } + + entry = proc_create_data("eth_phy", S_IFREG | 0666, + dir_dev, ð_phy_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/eth_phy failed\n"); + break; + } + + entry = proc_create_data("ext_regs", S_IFREG | 0444, + dir_dev, &ext_regs_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/ext_regs failed\n"); + break; + } + + entry = proc_create_data("registers", S_IFREG | 0444, + dir_dev, ®isters_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/registers failed\n"); + break; + } + + entry = proc_create_data("tx_desc", S_IFREG | 0444, + dir_dev, &tx_desc_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/tx_desc failed\n"); + break; + } + + entry = proc_create_data("rx_desc", S_IFREG | 0444, + dir_dev, &rx_desc_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/rx_desc failed\n"); + break; + } + + entry = proc_create_data("tally", S_IFREG | 0444, + dir_dev, &tally_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/tally failed\n"); + break; + } + + entry = proc_create_data("wpd_event", S_IFREG | 0444, + dir_dev, &wpd_evt_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wpd_event failed\n"); + break; + } + + entry = proc_create_data("wol_packet", S_IFREG | 0444, + dir_dev, &wol_pkt_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wol_packet failed\n"); + break; + } + + entry = proc_create_data("wake_mask", S_IFREG | 0644, + dir_dev, &wake_mask_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wake_mask failed\n"); + break; + } + + entry = proc_create_data("wake_crc", S_IFREG | 0644, + dir_dev, &wake_crc_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wake_crc failed\n"); + break; + } + + entry = proc_create_data("wake_idx_en", S_IFREG | 0644, + dir_dev, &wake_idx_en_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wake_idx_en failed\n"); + break; + } + + entry = proc_create_data("wake_dump", S_IFREG | 0444, + dir_dev, &wake_dump_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wake_dump failed\n"); + break; + } + + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + entry = proc_create_data("wake_offset", S_IFREG | 0644, + dir_dev, &wake_offset_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wake_offset failed\n"); + break; + } + + entry = proc_create_data("wake_pattern", S_IFREG | 0644, + dir_dev, &wake_pattern_proc_fops, NULL); + if (!entry) { + pr_info(PFX "procfs:create /proc/net/eth0/r8169/wake_pattern failed\n"); + break; + } + } + } while (0); +#endif + + rtl_init_rxcfg(tp); + + rtl_irq_disable(tp); + + rtl_hw_initialize(tp); + + rtl_hw_reset(tp); + + rtl_ack_events(tp, 0xffff); + + tp->txd_version = tp->chip->txd_version; + + RTL_W8(CFG9346, CFG9346_UNLOCK); + RTL_W8(CONFIG1, RTL_R8(CONFIG1) | PM_ENABLE); + RTL_W8(CONFIG5, RTL_R8(CONFIG5) & PME_STATUS); + + /* disable magic packet WOL */ + RTL_W8(CONFIG3, RTL_R8(CONFIG3) & ~MAGIC_PKT); + + if ((RTL_R8(CONFIG3) & (LINK_UP | MAGIC_PKT)) != 0) + tp->features |= RTL_FEATURE_WOL; + if ((RTL_R8(CONFIG5) & (UWF | BWF | MWF)) != 0) + tp->features |= RTL_FEATURE_WOL; + RTL_W8(CFG9346, CFG9346_LOCK); + + if (tp->output_mode == OUTPUT_SGMII_TO_MAC || + tp->output_mode == OUTPUT_RGMII_TO_MAC) + tp->chip->link_ok = rtl8169_xmii_always_link_ok; + + mutex_init(&tp->wk.mutex); + + /* Get MAC address */ + mac_addr = of_get_mac_address(pdev->dev.of_node); + if (mac_addr) + rtl_rar_set(tp, (u8 *)mac_addr); + + /* workaround: avoid getting deadbeef */ +#define RETRY_MAX 10 + for (retry = 0; retry < RETRY_MAX; retry++) { + for (i = 0; i < ETH_ALEN; i++) + ndev->dev_addr[i] = RTL_R8(MAC0 + i); + + if (*(u32 *)ndev->dev_addr == 0xdeadbeef) { + pr_err(PFX "get invalid MAC address %pM, retry %d\n", + ndev->dev_addr, retry); + tmp = RTL_R32(PHYAR); /* read something else */ + usleep_range(10000, 11000); + } else { + break; + } + } + if (retry == RETRY_MAX) + pr_err(PFX "get invalid MAC address %pM, give up!\n", ndev->dev_addr); + + rtl_led_set(tp); + + ndev->ethtool_ops = &rtl8169_ethtool_ops; + ndev->watchdog_timeo = RTL8169_TX_TIMEOUT; + + netif_napi_add(ndev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); + + /* don't enable SG, IP_CSUM and TSO by default - it might not work + * properly for all devices + */ + ndev->features |= + NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX; + ndev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HIGHDMA; + + ndev->hw_features |= NETIF_F_RXALL; + ndev->hw_features |= NETIF_F_RXFCS; + + ndev->min_mtu = ETH_ZLEN; + ndev->max_mtu = tp->chip->jumbo_max; + + tp->event_slow = tp->chip->event_slow; + + tp->opts1_mask = ~(RX_BOVF | RX_FOVF); + + rc = register_netdev(ndev); + if (rc < 0) + goto err_out_napi; + + platform_set_drvdata(pdev, ndev); + + netif_info(tp, probe, ndev, "%s, XID %08x IRQ %d\n", + tp->chip->name, + (u32)(RTL_R32(TX_CONFIG) & 0x9cf0f8ff), ndev->irq); + if (tp->chip->jumbo_max != JUMBO_1K) { + netif_info(tp, probe, ndev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n", + tp->chip->jumbo_max, + tp->chip->jumbo_tx_csum ? "ok" : "ko"); + } + + device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL); + + netif_carrier_off(ndev); + + if (tp->phy_irq_num) { + /* monitor rising edge of POR interrupts */ + regmap_write(tp->iso_base, ISO_POR_CTRL, 0x00000333); + /* clear GPHY HV/DV/AV POR interrupts */ + regmap_write(tp->iso_base, ISO_UMSK_ISR, 0x70000000); + } + + for (i = 0; i < tp->phy_irq_num; i++) { + memset(phy_irq_name[i], 0, IFNAMSIZ); + sprintf(phy_irq_name[i], "eth_phy%d", i); + rc = request_irq(tp->phy_irq[i], phy_irq_handler, IRQF_SHARED, + phy_irq_name[i], tp); + if (rc < 0) { + pr_err(PFX "unable to request %s IRQ %d, ret = 0x%x\n", + phy_irq_name[i], tp->phy_irq[i], rc); + } else { + pr_info(PFX "request %s IRQ %d successfully\n", + phy_irq_name[i], tp->phy_irq[i]); + } + } + + rtl8169_init_phy(ndev, tp); +out: + return rc; + +err_out_napi: + netif_napi_del(&tp->napi); + +#ifdef RTL_PROC + do { + if (!tp->dir_dev) + break; + + remove_proc_entry("wol_enable", tp->dir_dev); + remove_proc_entry("pwr_saving", tp->dir_dev); + remove_proc_entry("mac_reinit", tp->dir_dev); + remove_proc_entry("phy_reinit", tp->dir_dev); + remove_proc_entry("eee", tp->dir_dev); + remove_proc_entry("driver_var", tp->dir_dev); + remove_proc_entry("eth_phy", tp->dir_dev); + remove_proc_entry("ext_regs", tp->dir_dev); + remove_proc_entry("registers", tp->dir_dev); + remove_proc_entry("tx_desc", tp->dir_dev); + remove_proc_entry("rx_desc", tp->dir_dev); + remove_proc_entry("tally", tp->dir_dev); + remove_proc_entry("wpd_event", tp->dir_dev); + remove_proc_entry("wol_packet", tp->dir_dev); + remove_proc_entry("wake_mask", tp->dir_dev); + remove_proc_entry("wake_crc", tp->dir_dev); + remove_proc_entry("wake_idx_en", tp->dir_dev); + remove_proc_entry("wake_dump", tp->dir_dev); + if (tp->chip->features & RTL_FEATURE_PAT_WAKE) { + remove_proc_entry("wake_offset", tp->dir_dev); + remove_proc_entry("wake_pattern", tp->dir_dev); + } + + if (!rtw_proc) + break; + + remove_proc_entry(MODULENAME, rtw_proc); + remove_proc_entry("eth0", init_net.proc_net); + + rtw_proc = NULL; + + } while (0); +#endif + +err_out_netdev: + free_netdev(ndev); + +err_out_iomap: + iounmap(ioaddr); + return rc; +} + +static struct platform_driver rtl8169_soc_driver = { + .probe = rtl_init_one, + .remove = rtl_remove_one, + .shutdown = rtl_shutdown, + .driver = { + .name = MODULENAME, + .owner = THIS_MODULE, + .pm = RTL8169_PM_OPS, + .of_match_table = of_match_ptr(r8169soc_dt_ids), + }, +}; + +module_platform_driver(rtl8169_soc_driver); diff --git a/drivers/net/mii.c b/drivers/net/mii.c index f6a97c859f3a..021805161f58 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* mii.c: MII interface library @@ -57,6 +60,9 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) struct net_device *dev = mii->dev; u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; u32 nego; +#ifdef MY_ABC_HERE + int cur_link = mii_link_ok(mii); +#endif /* MY_ABC_HERE */ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -129,6 +135,14 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) mii->full_duplex = ecmd->duplex; +#ifdef MY_ABC_HERE + if (!cur_link) { + ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); + ecmd->duplex = DUPLEX_UNKNOWN; + mii->full_duplex = ecmd->duplex; + } +#endif /* MY_ABC_HERE */ + /* ignore maxtxpkt, maxrxpkt for now */ return 0; @@ -197,10 +211,21 @@ void mii_ethtool_get_link_ksettings(struct mii_if_info *mii, ADVERTISED_100baseT_Half)) { cmd->base.speed = SPEED_100; cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full); +#ifdef MY_ABC_HERE + } else if (nego & (ADVERTISED_10baseT_Full | + ADVERTISED_10baseT_Half)){ + cmd->base.speed = SPEED_10; + cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full); + } else { + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; + } +#else /* MY_ABC_HERE */ } else { cmd->base.speed = SPEED_10; cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full); } +#endif /* MY_ABC_HERE */ } else { cmd->base.autoneg = AUTONEG_DISABLE; diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index b1bb9b8e1e4e..c92ec64cb93d 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Marvell 10G 88x3310 PHY driver @@ -28,6 +31,9 @@ #include #include #include +#if defined(MY_DEF_HERE) +#include +#endif /* MY_DEF_HERE */ #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe #define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa) @@ -89,6 +95,23 @@ enum { MV_V2_TEMP_CTRL_DISABLE = 0xc000, MV_V2_TEMP = 0xf08c, MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */ + +#if defined(MY_DEF_HERE) + /* Vendor2 MMD registers */ + MV_AN_CTRL1_MG = 0x0020, + MV_V2_MODE_CFG = 0xf000, + MV_V2_LED0_CTRL = 0xf020, + MV_V2_LED1_CTRL = 0xf021, + MV_V2_LED2_CTRL = 0xf022, + MV_V2_LED3_CTRL = 0xf023, + MV_V2_PORT_INT_MASK = 0xf043, + MV_V2_HOST_KR_ENABLE = 0xf084, + MV_V2_MAC_ADDR_LSB = 0xf06b, + MV_V2_MAC_ADDR_ISB = 0xf06c, + MV_V2_MAC_ADDR_HSB = 0xf06d, + MV_V2_WOL_CTRL = 0xf06e, + MV_V2_HOST_KR_TUNE = 0xf07c, +#endif /* MY_DEF_HERE */ }; struct mv3310_priv { @@ -99,6 +122,112 @@ struct mv3310_priv { char *hwmon_name; }; +#if defined(MY_DEF_HERE) +/* Some PHYs within the Alaska family like 88x3310 has problems with the + * KR Auto-negotiation. marvell datasheet for 88x3310 section 6.2.11 says that + * KR auto-negotitaion can be enabled to adapt to the incoming SERDES by writing + * to autoneg registers and the PMA/PMD registers + */ +static int mv3310_amd_quirk(struct phy_device *phydev) +{ + int reg=0, count=0; + int version, subversion; + + version = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0xC011); + subversion = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0xC012); + dev_dbg(&phydev->mdio.dev,"%s: Marvell FW Version: %x.%x \n", __func__, version, subversion); + + reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_ENABLE); + reg |= 0x8000; + phy_write_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_ENABLE, reg); + + reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_TUNE); + reg = (reg & ~0x8000) | 0x4000; + phy_write_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_TUNE, reg); + + if((reg & BIT(8)) && (reg & BIT(11))) { + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R); + + /* disable BASE-R */ + phy_write_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R, reg); + } else { + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R); + /* enable BASE-R for KR initiation */ + reg |= 0x1000; + phy_write_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R, reg); + } + + /* down the port if no link */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MODE_CFG); + reg &= 0xFFF7; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MODE_CFG, reg); + + /* Do not advertise 2.5Gbe & 5GbE */ + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_CTRL1_MG); + reg &= ~0x0180; + phy_write_mmd(phydev, MDIO_MMD_AN, MV_AN_CTRL1_MG, reg); + + /* Do not advertise 100M & 10M */ + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + reg &= ~0x01e0; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); + + /* reset port to effect above change */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); + reg |= 0x8018; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, reg); + + /* wait till reset complete */ + + count = 50; + do { + msleep(10); + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); + } while ((reg & 0x8000) && --count); + + if(reg & 0x8000){ + dev_err(&phydev->mdio.dev,"%s: Port Reset taking long time\n", __func__); + return -ETIMEDOUT; + } + + /* Set LED0 Activtiy Status LED */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED0_CTRL); + reg &= 0xE000; + reg |= 0x128; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED0_CTRL, reg); + + /* Set LED2 1GbE Link LED */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED2_CTRL); + reg &= 0xE000; + reg |= 0x68; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED2_CTRL, reg); + + /* Set LED3 10GbE Link LED */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED3_CTRL); + reg &= 0xE000; + reg |= 0x58; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED3_CTRL, reg); + + /* Set PCS, PMA/PMD to normal mode */ + reg = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); + reg &= ~0x0800; + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, reg); + + reg = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); + reg &= ~0x0800; + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); + + /* PHY reusme */ + phydev->drv->resume(phydev); + + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); + + dev_err(&phydev->mdio.dev,"%s: quirk applied, 0x%x \n", __func__, reg); + + return 0; +} +#endif /* MY_DEF_HERE */ + #ifdef CONFIG_HWMON static umode_t mv3310_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, @@ -460,7 +589,11 @@ static int mv3310_config_init(struct phy_device *phydev) int val; /* Check that the PHY interface type is compatible */ - if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + if ( +#if defined(MY_DEF_HERE) + phydev->interface != PHY_INTERFACE_MODE_10GKR && +#endif /* MY_DEF_HERE */ + phydev->interface != PHY_INTERFACE_MODE_SGMII && phydev->interface != PHY_INTERFACE_MODE_2500BASEX && phydev->interface != PHY_INTERFACE_MODE_XAUI && phydev->interface != PHY_INTERFACE_MODE_RXAUI && @@ -474,6 +607,10 @@ static int mv3310_config_init(struct phy_device *phydev) if (err) return err; +#if defined(MY_DEF_HERE) + mv3310_amd_quirk(phydev); +#endif /* MY_DEF_HERE */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); if (val < 0) return val; @@ -765,6 +902,85 @@ static int mv3310_set_tunable(struct phy_device *phydev, } } +#if defined(MY_DEF_HERE) +static int syno_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + int ret, val; + + /* Force PHY not the advertise 10GbE */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_CTRL1_MG); + val &= ~0x1000; + ret = phy_write_mmd(phydev, MDIO_MMD_AN, MV_AN_CTRL1_MG, val); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to config advertise\n", __func__); + return ret; + } + + /* advertise 100M & 10M */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + val |= 0x01e0; + ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, val); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to config advertise\n", __func__); + return ret; + } + + /* Enable PHY WOL interrupt */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_INT_MASK); + val |= 0x0100; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_INT_MASK, val); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to enable wol int\n", __func__); + return ret; + } + + /* Set MAC address for magic packet detection */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MAC_ADDR_HSB, + ((phydev->attached_dev->dev_addr[5] << 8) | + phydev->attached_dev->dev_addr[4])); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to set MAC address HSB\n", __func__); + return ret; + } + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MAC_ADDR_ISB, + ((phydev->attached_dev->dev_addr[3] << 8) | + phydev->attached_dev->dev_addr[2])); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to set MAC address ISB\n", __func__); + return ret; + } + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MAC_ADDR_LSB, + ((phydev->attached_dev->dev_addr[1] << 8) | + phydev->attached_dev->dev_addr[0])); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to set MAC address LSB\n", __func__); + return ret; + } + + /* Magic packet detection enabled */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_WOL_CTRL); + val |= 0x01; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_WOL_CTRL, val); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to enable magic packet detection \n", __func__); + return ret; + } + + /* Softreset to effect above change */ + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); + val |= 0x8000; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, val); + if (ret) { + dev_err(&phydev->mdio.dev,"%s: failed to softreset phy \n", __func__); + return ret; + } + msleep(500); + + return 0; +} +#endif /* MY_DEF_HERE */ + + static struct phy_driver mv3310_drivers[] = { { .phy_id = MARVELL_PHY_ID_88X3310, @@ -781,6 +997,9 @@ static struct phy_driver mv3310_drivers[] = { .get_tunable = mv3310_get_tunable, .set_tunable = mv3310_set_tunable, .remove = mv3310_remove, +#if defined(MY_DEF_HERE) + .set_wol = syno_set_wol, +#endif /* MY_DEF_HERE */ }, { .phy_id = MARVELL_PHY_ID_88E2110, diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index 8bcc1cdcb75b..89984f9c224c 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -3273,5 +3273,3 @@ EXPORT_SYMBOL(hostap_init_ap_proc); EXPORT_SYMBOL(hostap_free_data); EXPORT_SYMBOL(hostap_check_sta_fw_version); EXPORT_SYMBOL(hostap_handle_sta_tx_exc); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 4a02561cfb96..f6d50ce32c1c 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. @@ -116,6 +119,10 @@ struct ntb_queue_entry { int errors; unsigned int tx_index; unsigned int rx_index; +#ifdef MY_DEF_HERE + // the entry is used for which round of an qp. + u16 num_qp_round; +#endif /* MY_DEF_HERE */ struct ntb_transport_qp *qp; union { @@ -194,6 +201,15 @@ struct ntb_transport_qp { u64 tx_err_no_buf; u64 tx_memcpy; u64 tx_async; +#ifdef MY_DEF_HERE + // record which round the qp is. This will plus 1 when qp link is down. + unsigned int ucRound; + // used for the entry data to indicate which round the entry is creatd + // this counter will be plused one after link up. This is also used for + // ntb_queue_entry->num_qp_round to remaind which round the entry is c- + // alled. + unsigned int ucRoundForEntry; +#endif /* MY_DEF_HERE */ bool use_msi; int msi_irq; @@ -251,7 +267,13 @@ enum { struct ntb_payload_header { unsigned int ver; unsigned int len; +#ifdef MY_DEF_HERE + u16 flags; + // Indicates which qp round creates the ntb payload. + u16 num_qp_round; +#else /* MY_DEF_HERE */ unsigned int flags; +#endif /* MY_DEF_HERE */ }; enum { @@ -261,8 +283,36 @@ enum { NUM_MWS, MW0_SZ_HIGH, MW0_SZ_LOW, +#ifdef MY_DEF_HERE + QP_DATA_VERSION = 12, + // every 4 bit is used for a queue to record the number of link down (ucRound in qp struct) + QP_NUM_ROUND = 13, +#endif /* MY_DEF_HERE */ }; +#ifdef MY_DEF_HERE +// the version of QP_DATA +// if this does not match, MY_DEF_HERE will not work. +#define SYNO_QP_DATA_VER 1 +// mask to get the QP data from a 32-bit register (key: QP_NUM_ROUND) +unsigned int gSynoQPRoundMask[8] = { + 0x0000000f, // qp0 + 0x000000f0, // qp1 + 0x00000f00, // qp2 + 0x0000f000, // qp3 + 0x000f0000, // qp4 + 0x00f00000, // qp5 + 0x0f000000, // qp6 + 0xf0000000, // qp7 +}; +// SYNO_QP_ROUND_MOD = 2 ^ SYNO_QP_ROUND_SHIFT_BIT +#define SYNO_QP_ROUND_SHIFT_BIT 4 +#define SYNO_QP_ROUND_MOD 16 +// consistency of qp data version between local and remote +// true means that versions are the same. +static bool gblQPDataVersionConsistency = true; +#endif /* MY_DEF_HERE */ + #define dev_client_dev(__dev) \ container_of((__dev), struct ntb_transport_client_dev, dev) @@ -281,7 +331,9 @@ static int ntb_async_tx_submit(struct ntb_transport_qp *qp, static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset); static int ntb_async_rx_submit(struct ntb_queue_entry *entry, void *offset); static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset); - +#ifdef MY_DEF_HERE +static unsigned int SYNONtbQPGetLinkdownNum(struct ntb_dev *ndev, u8 qp_num); +#endif /* MY_DEF_HERE */ static int ntb_transport_bus_match(struct device *dev, struct device_driver *drv) @@ -471,7 +523,7 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, qp = filp->private_data; - if (!qp || !qp->link_is_up) + if (!qp) return 0; out_count = 1000; @@ -481,9 +533,24 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, return -ENOMEM; out_offset = 0; - out_offset += scnprintf(buf + out_offset, out_count - out_offset, + out_offset += snprintf(buf + out_offset, out_count - out_offset, "\nNTB QP stats:\n\n"); - out_offset += scnprintf(buf + out_offset, out_count - out_offset, +#ifdef MY_DEF_HERE + if (!qp->link_is_up){ + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "qp data version consistency - \t%s\n", + gblQPDataVersionConsistency ? "Yes" : "No"); + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "num round - \t%u\n", qp->ucRound); + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "num round for entry - \t%u\n", qp->ucRoundForEntry); + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "num round on register (remote) - \t%u\n", + SYNONtbQPGetLinkdownNum(qp->ndev, qp->qp_num)); + goto END; + } +#endif /* MY_DEF_HERE */ + out_offset += snprintf(buf + out_offset, out_count - out_offset, "rx_bytes - \t%llu\n", qp->rx_bytes); out_offset += scnprintf(buf + out_offset, out_count - out_offset, "rx_pkts - \t%llu\n", qp->rx_pkts); @@ -544,6 +611,19 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, out_offset += scnprintf(buf + out_offset, out_count - out_offset, "QP Link - \t%s\n", qp->link_is_up ? "Up" : "Down"); +#ifdef MY_DEF_HERE + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "qp data version consistency - \t%s\n", + gblQPDataVersionConsistency ? "Yes" : "No"); + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "num round - \t%u\n", qp->ucRound); + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "num round for entry - \t%u\n", qp->ucRoundForEntry); + out_offset += scnprintf(buf + out_offset, out_count - out_offset, + "num round on register (remote) - \t%u\n", + SYNONtbQPGetLinkdownNum(qp->ndev, qp->qp_num)); +END: +#endif /* MY_DEF_HERE */ out_offset += scnprintf(buf + out_offset, out_count - out_offset, "\n"); @@ -1026,6 +1106,10 @@ static void ntb_transport_link_work(struct work_struct *work) resource_size_t size; u32 val; int rc = 0, i, spad; +#ifdef MY_DEF_HERE + /* initialized QP_DATA_VERSION */ + ntb_peer_spad_write(ndev, PIDX, QP_DATA_VERSION, SYNO_QP_DATA_VER); +#endif /* MY_DEF_HERE */ /* send the local info, in the opposite order of the way we read it */ @@ -1121,6 +1205,44 @@ static void ntb_transport_link_work(struct work_struct *work) msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } +#ifdef MY_DEF_HERE +/** +* This function is used to get the number of round for a specific qp. +* First, get register result from spad. +* Second, process the result by qp_num (qp index). Currently, each qp has 4 bits. +* +* @param nt the ntb_transport_ctx, used to read register. +* @param qp_num the index of qp +* +* @return unsigned int of the qp. +*/ +static unsigned int SYNONtbQPGetLinkdownNum(struct ntb_dev *ndev, u8 qp_num) +{ + unsigned int remote_num_round = 0; // the qp rounds from spad register + remote_num_round = ntb_spad_read(ndev, QP_NUM_ROUND); + return (gSynoQPRoundMask[qp_num] & remote_num_round) >> (qp_num * SYNO_QP_ROUND_SHIFT_BIT); +} + +/** +* This function is used to set the number of link down count to spad register. +* +* @param nt the ntb_transport_ctx, used to read register. +* @param qp_num the index of qp +* @param num_round the number of qp rounds +* +* @return unsigned int of the qp. +*/ +static void SYNONtbQPSetLinkdownNum(struct ntb_dev *ndev, u8 qp_num, unsigned int num_round) +{ + unsigned int processed_num_round = (num_round << (qp_num * SYNO_QP_ROUND_SHIFT_BIT)); + unsigned int original_num_round = ntb_peer_spad_read(ndev, PIDX, QP_NUM_ROUND); + // remove the original result but keep other qp's results + original_num_round = (~gSynoQPRoundMask[qp_num]) & original_num_round; + // merge the orignal number and the processed number + ntb_peer_spad_write(ndev, PIDX, QP_NUM_ROUND, processed_num_round | original_num_round); +} +#endif /* MY_DEF_HERE */ + static void ntb_qp_link_work(struct work_struct *work) { struct ntb_transport_qp *qp = container_of(work, @@ -1129,6 +1251,11 @@ static void ntb_qp_link_work(struct work_struct *work) struct pci_dev *pdev = qp->ndev->pdev; struct ntb_transport_ctx *nt = qp->transport; int val; +#ifdef MY_DEF_HERE + unsigned int remote_qp_num_round = 0; + bool blLinkdownFlag = true; + int cReLinkCount = 0; // if this is not zero, reschedule the down up and update ucRound +#endif /* MY_DEF_HERE */ WARN_ON(!nt->link_is_up); @@ -1140,8 +1267,52 @@ static void ntb_qp_link_work(struct work_struct *work) dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val); /* See if the remote side is up */ +#ifdef MY_DEF_HERE + // check the num of round of remote and local + gblQPDataVersionConsistency = (SYNO_QP_DATA_VER == ntb_spad_read(nt->ndev, QP_DATA_VERSION)); + remote_qp_num_round = SYNONtbQPGetLinkdownNum(nt->ndev, qp->qp_num); + if (qp->ucRound == -1) { // reset the qp->ucRound first + qp->ucRound = remote_qp_num_round; + SYNONtbQPSetLinkdownNum(nt->ndev, qp->qp_num, qp->ucRound); + } + if (false == gblQPDataVersionConsistency) { + // reset the ucRound if qp version mismatches. + qp->ucRound = 0; + } + if (gblQPDataVersionConsistency + && remote_qp_num_round != qp->ucRound) { + blLinkdownFlag = false; + SYNONtbQPSetLinkdownNum(nt->ndev, qp->qp_num, qp->ucRound); + // determine which one will have less steps to follow up + if (remote_qp_num_round == 15 && qp->ucRound == 0) { + cReLinkCount = 0; + } else if (remote_qp_num_round == 0 && qp->ucRound == 15) { + cReLinkCount = 1; + } else if (remote_qp_num_round > qp->ucRound) { + cReLinkCount = remote_qp_num_round - qp->ucRound; + } + if(cReLinkCount) { + // re-schedule a linkdown without notifying the remote device + qp->ucRound += cReLinkCount; + qp->ucRound %= SYNO_QP_ROUND_MOD; + if (cReLinkCount > 1) { + printk("Re-schedule down/up more than one time. Num of rounds (mod 16), Remote: %u, Local: %u\n", + remote_qp_num_round, qp->ucRound + ); + } + SYNONtbQPSetLinkdownNum(nt->ndev, qp->qp_num, qp->ucRound); + ntb_qp_link_down(qp); + } + } + if ((val & BIT(qp->qp_num)) && blLinkdownFlag) { +#else /* MY_DEF_HERE */ if (val & BIT(qp->qp_num)) { +#endif /* MY_DEF_HERE */ dev_info(&pdev->dev, "qp %d: Link Up\n", qp->qp_num); +#ifdef MY_DEF_HERE + // update the ucRoundForEntry by qp->ucRound + qp->ucRoundForEntry = qp->ucRound; +#endif /* MY_DEF_HERE */ qp->link_is_up = true; qp->active = true; @@ -1236,6 +1407,10 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, tasklet_init(&qp->rxc_db_work, ntb_transport_rxc_db, (unsigned long)qp); +#ifdef MY_DEF_HERE + qp->ucRound = -1; + qp->ucRoundForEntry = -1; +#endif /* MY_DEF_HERE */ return 0; } @@ -1622,17 +1797,44 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index; hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header); +#ifdef MY_DEF_HERE + dev_dbg(&qp->ndev->pdev->dev, "qp %d: RX ver %u len %d flags %x num of round: %d\n", + qp->qp_num, hdr->ver, hdr->len, hdr->flags, hdr->num_qp_round); + if (!qp->link_is_up){ + // link is not up, don't process any rx + return -EAGAIN; + } +#else /* MY_DEF_HERE */ dev_dbg(&qp->ndev->pdev->dev, "qp %d: RX ver %u len %d flags %x\n", qp->qp_num, hdr->ver, hdr->len, hdr->flags); +#endif /* MY_DEF_HERE */ if (!(hdr->flags & DESC_DONE_FLAG)) { dev_dbg(&qp->ndev->pdev->dev, "done flag not set\n"); qp->rx_ring_empty++; return -EAGAIN; } +#ifdef MY_DEF_HERE + // check the round count, if this does not match, it + // means this rx is came from other round, don't read it. + if (gblQPDataVersionConsistency + && hdr->num_qp_round != (u16)qp->ucRoundForEntry) { + dev_dbg(&qp->ndev->pdev->dev, "round count mismatch, expected %u - got %u\n", + qp->ucRoundForEntry, hdr->num_qp_round); + return -EAGAIN; + } +#endif /* MY_DEF_HERE */ if (hdr->flags & LINK_DOWN_FLAG) { dev_dbg(&qp->ndev->pdev->dev, "link down flag set\n"); +#ifdef MY_DEF_HERE + if (gblQPDataVersionConsistency) { + // update qp->ucRound when receive a LINK_DOWN_FLAG + qp->ucRound++; + qp->ucRound %= SYNO_QP_ROUND_MOD;; + SYNONtbQPSetLinkdownNum(qp->ndev, qp->qp_num, qp->ucRound); + } +#endif /* MY_DEF_HERE */ ntb_qp_link_down(qp); hdr->flags = 0; return -EAGAIN; @@ -1758,7 +1960,11 @@ static void ntb_tx_copy_callback(void *data, } } +#ifdef MY_DEF_HERE + iowrite16(entry->flags | DESC_DONE_FLAG, &hdr->flags); +#else /* MY_DEF_HERE */ iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags); +#endif /* MY_DEF_HERE */ if (qp->use_msi) ntb_msi_peer_trigger(qp->ndev, PIDX, &qp->peer_msi_desc); @@ -1871,6 +2077,9 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, entry->tx_hdr = hdr; iowrite32(entry->len, &hdr->len); +#ifdef MY_DEF_HERE + iowrite16(entry->num_qp_round, &hdr->num_qp_round); +#endif /* MY_DEF_HERE */ iowrite32((u32)qp->tx_pkts, &hdr->ver); if (!chan) @@ -1896,6 +2105,12 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, static int ntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry) { +#ifdef MY_DEF_HERE + // don't process tx if link is not up + if (!qp->link_is_up){ + return -EAGAIN; + } +#endif /* MY_DEF_HERE */ if (qp->tx_index == qp->remote_rx_info->entry) { qp->tx_ring_full++; return -EAGAIN; @@ -1910,6 +2125,11 @@ static int ntb_process_tx(struct ntb_transport_qp *qp, return 0; } +#ifdef MY_DEF_HERE + // assign ucRoundForEntry to an entry, this entry will be discarded if + // round idx mismatches in ntb_process_rxc + entry->num_qp_round = (u16)qp->ucRoundForEntry; +#endif /* MY_DEF_HERE */ ntb_async_tx(qp, entry); qp->tx_index++; @@ -2158,6 +2378,9 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) ntb_db_set_mask(qp->ndev, qp_bit); tasklet_kill(&qp->rxc_db_work); +#ifdef MY_DEF_HERE + cancel_work_sync(&qp->link_cleanup); +#endif /*SYNO_NTB_FIX_CLEANUP_WORK_PANIC*/ cancel_delayed_work_sync(&qp->link_work); qp->cb_data = NULL; @@ -2312,13 +2535,30 @@ EXPORT_SYMBOL_GPL(ntb_transport_tx_enqueue); */ void ntb_transport_link_up(struct ntb_transport_qp *qp) { +#ifdef MY_DEF_HERE + int val; +#endif /* MY_DEF_HERE */ if (!qp) return; qp->client_ready = true; - if (qp->transport->link_is_up) + if (qp->transport->link_is_up) { +#ifdef MY_DEF_HERE + if (qp->link_is_up) { + val = ntb_spad_read(qp->ndev, QP_LINKS); + ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num)); + if (qp->event_handler) + qp->event_handler(qp->cb_data, qp->link_is_up); + if (qp->active) + tasklet_schedule(&qp->rxc_db_work); + } else { + schedule_delayed_work(&qp->link_work, 0); + } +#else /* MY_DEF_HERE */ schedule_delayed_work(&qp->link_work, 0); +#endif /* MY_DEF_HERE */ + } } EXPORT_SYMBOL_GPL(ntb_transport_link_up); @@ -2344,7 +2584,17 @@ void ntb_transport_link_down(struct ntb_transport_qp *qp) ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num)); if (qp->link_is_up) + { +#ifdef MY_DEF_HERE + if (gblQPDataVersionConsistency) { + // update qp's round when ntb_transport calls link down + qp->ucRound++; + qp->ucRound %= SYNO_QP_ROUND_MOD; + SYNONtbQPSetLinkdownNum(qp->ndev, qp->qp_num, qp->ucRound); + } +#endif /* MY_DEF_HERE */ ntb_send_link_down(qp); + } else cancel_delayed_work_sync(&qp->link_work); } diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index ff5a16b17133..4fa9f22160ec 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * NVM Express device driver @@ -21,6 +24,9 @@ #include #include #include +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ #include "nvme.h" #include "fabrics.h" @@ -28,6 +34,10 @@ #define CREATE_TRACE_POINTS #include "trace.h" +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#include +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ + #define NVME_MINORS (1U << MINORBITS) unsigned int admin_timeout = 60; @@ -35,7 +45,11 @@ module_param(admin_timeout, uint, 0644); MODULE_PARM_DESC(admin_timeout, "timeout in seconds for admin commands"); EXPORT_SYMBOL_GPL(admin_timeout); +#ifdef MY_ABC_HERE +unsigned int nvme_io_timeout = 60; +#else unsigned int nvme_io_timeout = 30; +#endif /* MY_ABC_HERE */ module_param_named(io_timeout, nvme_io_timeout, uint, 0644); MODULE_PARM_DESC(io_timeout, "timeout in seconds for I/O"); EXPORT_SYMBOL_GPL(nvme_io_timeout); @@ -53,6 +67,12 @@ module_param(default_ps_max_latency_us, ulong, 0644); MODULE_PARM_DESC(default_ps_max_latency_us, "max power saving latency for new devices; use PM QOS to change per device"); +#ifdef MY_ABC_HERE +unsigned int syno_force_timeout_default = 0; +module_param(syno_force_timeout_default, uint, 0644); +MODULE_PARM_DESC(syno_force_timeout_default, "type of force timeout for debug"); +#endif /* MY_ABC_HERE */ + static bool force_apst; module_param(force_apst, bool, 0644); MODULE_PARM_DESC(force_apst, "allow APST for newly enumerated devices even if quirked off"); @@ -93,6 +113,14 @@ static void nvme_put_subsystem(struct nvme_subsystem *subsys); static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl, unsigned nsid); +#ifdef MY_DEF_HERE +static void (*syno_sw_activity)(struct nvme_ctrl *ctrl); + +#ifdef MY_ABC_HERE +void syno_nvme_sw_activity_by_lp3943(struct nvme_ctrl *ctrl); +#endif /* MY_ABC_HERE */ +#endif /* MY_DEF_HERE */ + static void nvme_update_bdev_size(struct gendisk *disk) { struct block_device *bdev = bdget_disk(disk, 0); @@ -301,6 +329,10 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req) return RETRY; } +#ifdef MY_ABC_HERE +int syno_nvme_do_remap_req(struct request *req); +#endif /* MY_ABC_HERE */ + static inline void nvme_end_req(struct request *req) { blk_status_t status = nvme_error_status(nvme_req(req)->status); @@ -310,6 +342,18 @@ static inline void nvme_end_req(struct request *req) req->__sector = nvme_lba_to_sect(req->q->queuedata, le64_to_cpu(nvme_req(req)->result.u64)); +#ifdef MY_ABC_HERE + /* The read data could not be recovered from the media */ + if ((nvme_req(req)->status & 0x7ff) == NVME_SC_READ_ERROR) { + if (syno_nvme_do_remap_req(req) < 0) { + pr_warn("out of memory to check read error\n"); + } else { + // It's remap work's responsibility to end the request + return; + } + } +#endif /* MY_ABC_HERE */ + nvme_trace_bio_complete(req, status); blk_mq_end_request(req, status); } @@ -336,6 +380,21 @@ void nvme_complete_rq(struct request *req) } EXPORT_SYMBOL_GPL(nvme_complete_rq); +/* + * Called to unwind from ->queue_rq on a failed command submission so that the + * multipathing code gets called to potentially failover to another path. + * The caller needs to unwind all transport specific resource allocations and + * must return propagate the return value. + */ +blk_status_t nvme_host_path_error(struct request *req) +{ + nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR; + blk_mq_set_request_complete(req); + nvme_complete_rq(req); + return BLK_STS_OK; +} +EXPORT_SYMBOL_GPL(nvme_host_path_error); + bool nvme_cancel_request(struct request *req, void *data, bool reserved) { dev_dbg_ratelimited(((struct nvme_ctrl *) data)->device, @@ -562,6 +621,66 @@ struct request *nvme_alloc_request(struct request_queue *q, } EXPORT_SYMBOL_GPL(nvme_alloc_request); +/* + * For something we're not in a state to send to the device the default action + * is to busy it and retry it after the controller state is recovered. However, + * if the controller is deleting or if anything is marked for failfast or + * nvme multipath it is immediately failed. + * + * Note: commands used to initialize the controller will be marked for failfast. + * Note: nvme cli/ioctl commands are marked for failfast. + */ +blk_status_t nvme_fail_nonready_command(struct nvme_ctrl *ctrl, + struct request *rq) +{ + if (ctrl->state != NVME_CTRL_DELETING_NOIO && + ctrl->state != NVME_CTRL_DEAD && + /* remove NVME_CTRL_FAILFAST_EXPIRED test to fit our kernel */ + !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH)) + return BLK_STS_RESOURCE; + return nvme_host_path_error(rq); +} +EXPORT_SYMBOL_GPL(nvme_fail_nonready_command); + +bool __nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq, + bool queue_live) +{ + struct nvme_request *req = nvme_req(rq); + + /* + * currently we have a problem sending passthru commands + * on the admin_q if the controller is not LIVE because we can't + * make sure that they are going out after the admin connect, + * controller enable and/or other commands in the initialization + * sequence. until the controller will be LIVE, fail with + * BLK_STS_RESOURCE so that they will be rescheduled. + */ + if (rq->q == ctrl->admin_q && (req->flags & NVME_REQ_USERCMD)) + return false; + + if (ctrl->ops->flags & NVME_F_FABRICS) { + /* + * Only allow commands on a live queue, except for the connect + * command, which is require to set the queue live in the + * appropinquate states. + */ + switch (ctrl->state) { + case NVME_CTRL_CONNECTING: + if (blk_rq_is_passthrough(rq) && nvme_is_fabrics(req->cmd) && + req->cmd->fabrics.fctype == nvme_fabrics_type_connect) + return true; + break; + default: + break; + case NVME_CTRL_DEAD: + return false; + } + } + + return queue_live; +} +EXPORT_SYMBOL_GPL(__nvme_check_ready); + static int nvme_toggle_streams(struct nvme_ctrl *ctrl, bool enable) { struct nvme_command c; @@ -774,6 +893,10 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, if (req->cmd_flags & REQ_RAHEAD) dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH; +#ifdef MY_ABC_HERE + ns->ctrl->idle = jiffies; +#endif /* MY_ABC_HERE */ + cmnd->rw.opcode = op; cmnd->rw.nsid = cpu_to_le32(ns->head->ns_id); cmnd->rw.slba = cpu_to_le64(nvme_sect_to_lba(ns, blk_rq_pos(req))); @@ -812,6 +935,13 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, cmnd->rw.control = cpu_to_le16(control); cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); + +#ifdef MY_DEF_HERE + if (syno_sw_activity) { + syno_sw_activity(ctrl); + } +#endif /* MY_DEF_HERE */ + return 0; } @@ -1430,6 +1560,65 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid, } EXPORT_SYMBOL_GPL(nvme_get_features); +#ifdef MY_ABC_HERE +int syno_nvme_get_error_log_page(struct nvme_ctrl *dev, + struct syno_nvme_error_log_page **err_log, int *err_entries) +{ + struct nvme_command c = { }; + size_t log_bytes = 0; + int error; + + *err_entries = dev->syno_elpe + 1; + log_bytes = *err_entries * sizeof(struct syno_nvme_error_log_page); + + c.common.opcode = nvme_admin_get_log_page; + c.common.nsid = cpu_to_le32(0xFFFFFFFF); + c.common.cdw10 = cpu_to_le32((((log_bytes / 4) - 1) << 16) | NVME_LOG_ERROR); + + *err_log = kmalloc(log_bytes, GFP_KERNEL); + if (!*err_log) + return -ENOMEM; + + error = nvme_submit_sync_cmd(dev->admin_q, &c, *err_log, log_bytes); + if (error) { + kfree(*err_log); + *err_log = NULL; + } + return error; +} + +int syno_nvme_lba_write_pattern(struct nvme_ns *ns, u64 lba) +{ + struct nvme_command c = { }; + char *buf = NULL, *p = NULL; + unsigned int length = 0; + int error; + + length = 1 << ns->lba_shift; + + c.rw.opcode = nvme_cmd_write; + c.rw.nsid = cpu_to_le32(ns->head->ns_id); + c.rw.slba = cpu_to_le64(lba); + c.rw.length = cpu_to_le16(0); + + buf = kmalloc(length, GFP_KERNEL); + if (!buf) { + pr_warn("%s:%s(%d) failed to allocate remap page memory, so use zero page instead.\n", + __FILE__, __func__, __LINE__); + p = page_address(ZERO_PAGE(0)); + } else { + syno_draw_auto_remap_buffer(buf, length); + p = buf; + } + + error = nvme_submit_sync_cmd(ns->queue, &c, p, length); + + kfree(buf); + buf = NULL; + return error; +} +#endif /* MY_ABC_HERE */ + int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count) { u32 q_count = (*count - 1) | ((*count - 1) << 16); @@ -2124,11 +2313,49 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id) blk_queue_chunk_sectors(ns->queue, iob); } +#ifdef MY_ABC_HERE +static int syno_nvme_update_nsattr(struct nvme_ns *ns, struct nvme_id_ns *id) +{ + u8 smart_log_buf[4] ={0}; + int ret; + + /* + * nvme get-log command uses dword as unit of log-size. Hence, provide + * buffer with size of one dword here. + */ + ret = nvme_get_log(ns->ctrl, 0xFFFFFFFF, NVME_LOG_SMART, 0, 0, + smart_log_buf, sizeof(smart_log_buf), 0); + if (ret) { + dev_warn(disk_to_dev(ns->disk), "%s: Get smart log failed (%d)\n", + __func__, ret); + return ret; + } + if (smart_log_buf[0] & NVME_SMART_CRIT_MEDIA) + id->nsattr |= NVME_NS_ATTR_RO; + return ret; +} +#endif /* MY_ABC_HERE */ + static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id) { +#ifdef MY_ABC_HERE + struct pci_dev *pdev = to_pci_dev(ns->ctrl->dev); + bool is_snv3400_series = (pdev->vendor == 0x1987 && + pdev->device == 0x5012 && + pdev->subsystem_vendor == 0x7053 && + pdev->subsystem_device == 0x4001); +#endif /* CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_ROi */ unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK; int ret; +#ifdef MY_ABC_HERE + if (is_snv3400_series) { + ret = syno_nvme_update_nsattr(ns, id); + if (ret) + return ret; + } +#endif /* MY_ABC_HERE */ + blk_mq_freeze_queue(ns->disk->queue); ns->lba_shift = id->lbaf[lbaf].ds; nvme_set_queue_limits(ns->ctrl, ns->queue); @@ -2337,6 +2564,14 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled) ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; u32 csts, bit = enabled ? NVME_CSTS_RDY : 0; int ret; +#ifdef MY_ABC_HERE + if (unlikely(ctrl->syno_force_timeout & (2 << enabled))) { + dev_err(ctrl->dev, + "Device not ready; aborting %s\n", + enabled ? "initialisation" : "reset"); + return -ENODEV; + } +#endif /* MY_ABC_HERE */ while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) { if (csts == ~0) @@ -2422,6 +2657,13 @@ int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl) unsigned long timeout = jiffies + (ctrl->shutdown_timeout * HZ); u32 csts; int ret; +#ifdef MY_ABC_HERE + if (unlikely(ctrl->syno_force_timeout & (2 << 2))) { + dev_err(ctrl->dev, + "Device shutdown incomplete; abort shutdown\n"); + return -ENODEV; + } +#endif /* MY_ABC_HERE */ ctrl->ctrl_config &= ~NVME_CC_SHN_MASK; ctrl->ctrl_config |= NVME_CC_SHN_NORMAL; @@ -3087,6 +3329,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) } else ctrl->shutdown_timeout = shutdown_timeout; +#ifdef MY_ABC_HERE + ctrl->syno_elpe = id->elpe; +#endif /* MY_ABC_HERE */ ctrl->npss = id->npss; ctrl->apsta = id->apsta; prev_apst_enabled = ctrl->apst_enabled; @@ -3301,6 +3546,94 @@ static ssize_t nvme_sysfs_rescan(struct device *dev, } static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan); +#ifdef MY_ABC_HERE +static ssize_t +sdev_show_syno_idle_time(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nvme_ctrl *ctrl = dev_get_drvdata(dev); + int iRet = -EFAULT; + + if (NULL == ctrl) { + goto END; + } + + iRet = snprintf(buf, 20, "%lu\n", (jiffies - ctrl->idle) / HZ + 1); + +END: + return iRet; +} + +static ssize_t +sdev_store_syno_idle_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct nvme_ctrl *ctrl = dev_get_drvdata(dev); + unsigned long idletime; + + if (NULL == ctrl) { + goto END; + } + + sscanf(buf, "%lu", &idletime); + // idletime = (jiffies - sdev->idle) / HZ + 1 + ctrl->idle = jiffies - (idletime - 1) * HZ; + +END: + return count; +} + +static DEVICE_ATTR(syno_idle_time, S_IRUGO | S_IWUSR, sdev_show_syno_idle_time, sdev_store_syno_idle_time); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t syno_show_force_timeout(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nvme_ctrl *ctrl = dev_get_drvdata(dev); + ssize_t len = -EFAULT; + + if (NULL == ctrl) { + goto END; + } + + len = snprintf(buf, sizeof(unsigned), "%u", ctrl->syno_force_timeout); +END: + return len; +} + +#ifdef MY_ABC_HERE +static ssize_t syno_block_info_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct nvme_ctrl *ctrl = dev_get_drvdata(device); + ssize_t len = -EFAULT; + + if (NULL == ctrl) { + goto END; + } + + len = snprintf(buf, BLOCK_INFO_SIZE , "%s", ctrl->syno_block_info); +END: + return len; +} +static DEVICE_ATTR(syno_block_info, S_IRUGO, syno_block_info_show, NULL); +#endif /* MY_ABC_HERE */ + +static ssize_t syno_store_force_timeout(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct nvme_ctrl *ctrl = dev_get_drvdata(dev); + + if (NULL == ctrl) { + goto END; + } + + sscanf(buf, "%u", &ctrl->syno_force_timeout); +END: + return count; +} +static DEVICE_ATTR(syno_force_timeout, S_IWUSR | S_IRUSR, syno_show_force_timeout, syno_store_force_timeout); +#endif /* MY_ABC_HERE */ + static inline struct nvme_ns_head *dev_to_ns_head(struct device *dev) { struct gendisk *disk = dev_to_disk(dev); @@ -3612,6 +3945,15 @@ static DEVICE_ATTR(reconnect_delay, S_IRUGO | S_IWUSR, static struct attribute *nvme_dev_attrs[] = { &dev_attr_reset_controller.attr, +#ifdef MY_ABC_HERE + &dev_attr_syno_idle_time.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_force_timeout.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_block_info.attr, +#endif /* MY_ABC_HERE */ &dev_attr_rescan_controller.attr, &dev_attr_model.attr, &dev_attr_serial.attr, @@ -3828,6 +4170,52 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid) } EXPORT_SYMBOL_NS_GPL(nvme_find_get_ns, NVME_TARGET_PASSTHRU); +#ifdef MY_ABC_HERE +void syno_nvme_put_ns(struct nvme_ns *ns) +{ + nvme_put_ns(ns); +} + +struct nvme_ns *syno_nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned int nsid) +{ + return nvme_find_get_ns(ctrl, nsid); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static bool syno_is_nvme_device_disappear(struct gendisk *disk) +{ + struct nvme_ns *ns = disk->private_data; + struct nvme_ctrl *ctrl = ns->ctrl; + bool ret = false; + + if (pci_channel_offline(to_pci_dev(ctrl->dev))) { + ret = true; + goto end; + } + + if (ctrl->state == NVME_CTRL_DELETING) { + ret = true; + goto end; + } + + ret = false; +end: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static const struct syno_gendisk_operations syno_nvme_gd_ops = { +#ifdef MY_ABC_HERE + .is_device_disappear = syno_is_nvme_device_disappear, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .get_device_index = SynoNVMeGetDeviceIndex, +#endif /* MY_ABC_HERE */ +}; +#endif /* MY_ABC_HERE */ + static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, struct nvme_ns_ids *ids) { @@ -3875,6 +4263,10 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, memcpy(disk->disk_name, disk_name, DISK_NAME_LEN); ns->disk = disk; +#ifdef MY_ABC_HERE + disk->syno_ops = &syno_nvme_gd_ops; +#endif /* MY_ABC_HERE */ + if (nvme_update_ns_info(ns, id)) goto out_put_disk; @@ -3918,11 +4310,21 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, kfree(id); } +#ifdef MY_ABC_HERE +int (*syno_raid_nvme_unplug)(char *szNVMeName) = NULL; +EXPORT_SYMBOL(syno_raid_nvme_unplug); +#endif /* MY_ABC_HERE */ static void nvme_ns_remove(struct nvme_ns *ns) { +#ifdef MY_ABC_HERE + char device_name[16] = {0}; +#endif /* MY_ABC_HERE */ if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags)) return; +#ifdef MY_ABC_HERE + strlcpy(device_name, ns->disk->disk_name, sizeof(device_name)); +#endif /* MY_ABC_HERE */ set_capacity(ns->disk, 0); nvme_fault_inject_fini(&ns->fault_inject); @@ -3949,6 +4351,10 @@ static void nvme_ns_remove(struct nvme_ns *ns) nvme_mpath_check_last_path(ns); nvme_put_ns(ns); +#ifdef MY_ABC_HERE + if (syno_raid_nvme_unplug) + syno_raid_nvme_unplug(device_name); +#endif /* MY_ABC_HERE */ } static void nvme_ns_remove_by_nsid(struct nvme_ctrl *ctrl, u32 nsid) @@ -4468,6 +4874,20 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, ctrl->dev = dev; ctrl->ops = ops; ctrl->quirks = quirks; +#ifdef MY_ABC_HERE + ctrl->syno_force_timeout = syno_force_timeout_default; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ctrl->quirks |= NVME_QUIRK_NO_APST; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ctrl->idle = jiffies; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&ctrl->syno_remap_reqs); + spin_lock_init(&ctrl->syno_remap_reqs_lock); +#endif /* MY_ABC_HERE */ + ctrl->numa_node = NUMA_NO_NODE; INIT_WORK(&ctrl->scan_work, nvme_scan_work); INIT_WORK(&ctrl->async_event_work, nvme_async_event_work); @@ -4720,6 +5140,17 @@ static int __init nvme_core_init(void) result = PTR_ERR(nvme_subsys_class); goto destroy_class; } + +#ifdef MY_DEF_HERE + syno_sw_activity = NULL; + +#ifdef MY_ABC_HERE + if (syno_is_hw_version(HW_SA6500)) { + syno_sw_activity = syno_nvme_sw_activity_by_lp3943; + } +#endif /* MY_ABC_HERE */ +#endif /* MY_DEF_HERE */ + return 0; destroy_class: diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 7015fba2e512..3cf05d93ccba 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -540,66 +540,6 @@ static struct nvmf_transport_ops *nvmf_lookup_transport( return NULL; } -/* - * For something we're not in a state to send to the device the default action - * is to busy it and retry it after the controller state is recovered. However, - * if the controller is deleting or if anything is marked for failfast or - * nvme multipath it is immediately failed. - * - * Note: commands used to initialize the controller will be marked for failfast. - * Note: nvme cli/ioctl commands are marked for failfast. - */ -blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl, - struct request *rq) -{ - if (ctrl->state != NVME_CTRL_DELETING_NOIO && - ctrl->state != NVME_CTRL_DEAD && - !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH)) - return BLK_STS_RESOURCE; - - nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR; - blk_mq_start_request(rq); - nvme_complete_rq(rq); - return BLK_STS_OK; -} -EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command); - -bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, - bool queue_live) -{ - struct nvme_request *req = nvme_req(rq); - - /* - * currently we have a problem sending passthru commands - * on the admin_q if the controller is not LIVE because we can't - * make sure that they are going out after the admin connect, - * controller enable and/or other commands in the initialization - * sequence. until the controller will be LIVE, fail with - * BLK_STS_RESOURCE so that they will be rescheduled. - */ - if (rq->q == ctrl->admin_q && (req->flags & NVME_REQ_USERCMD)) - return false; - - /* - * Only allow commands on a live queue, except for the connect command, - * which is require to set the queue live in the appropinquate states. - */ - switch (ctrl->state) { - case NVME_CTRL_CONNECTING: - if (blk_rq_is_passthrough(rq) && nvme_is_fabrics(req->cmd) && - req->cmd->fabrics.fctype == nvme_fabrics_type_connect) - return true; - break; - default: - break; - case NVME_CTRL_DEAD: - return false; - } - - return queue_live; -} -EXPORT_SYMBOL_GPL(__nvmf_check_ready); - static const match_table_t opt_tokens = { { NVMF_OPT_TRANSPORT, "transport=%s" }, { NVMF_OPT_TRADDR, "traddr=%s" }, diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index a9c1e3b4585e..da56b9cba1f5 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -172,20 +172,7 @@ void nvmf_unregister_transport(struct nvmf_transport_ops *ops); void nvmf_free_options(struct nvmf_ctrl_options *opts); int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size); bool nvmf_should_reconnect(struct nvme_ctrl *ctrl); -blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl, - struct request *rq); -bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, - bool queue_live); bool nvmf_ip_options_match(struct nvme_ctrl *ctrl, struct nvmf_ctrl_options *opts); -static inline bool nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, - bool queue_live) -{ - if (likely(ctrl->state == NVME_CTRL_LIVE || - ctrl->state == NVME_CTRL_DELETING)) - return true; - return __nvmf_check_ready(ctrl, rq, queue_live); -} - #endif /* _NVME_FABRICS_H */ diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index a0bcec33b020..617508e02555 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2779,8 +2779,8 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx, blk_status_t ret; if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE || - !nvmf_check_ready(&queue->ctrl->ctrl, rq, queue_ready)) - return nvmf_fail_nonready_command(&queue->ctrl->ctrl, rq); + !nvme_check_ready(&queue->ctrl->ctrl, rq, queue_ready)) + return nvme_fail_nonready_command(&queue->ctrl->ctrl, rq); ret = nvme_setup_cmd(ns, rq, sqe); if (ret) diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 3cb3c82061d7..2d2730b43087 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2011-2014, Intel Corporation. @@ -291,6 +294,22 @@ struct nvme_ctrl { unsigned int shutdown_timeout; unsigned int kato; bool subsystem; +#ifdef MY_ABC_HERE + unsigned long idle; /* nvme device idle time in jiffies */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned syno_force_timeout; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BLOCK_INFO_SIZE 512 /* Largest string for a nvme device block information */ + char syno_block_info[BLOCK_INFO_SIZE]; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct list_head syno_remap_reqs; + spinlock_t syno_remap_reqs_lock; + u8 syno_elpe; +#endif /* MY_ABC_HERE */ + unsigned long quirks; struct nvme_id_power_state psd[32]; struct nvme_effects_log *effects; @@ -570,6 +589,7 @@ static inline bool nvme_is_aen_req(u16 qid, __u16 command_id) } void nvme_complete_rq(struct request *req); +blk_status_t nvme_host_path_error(struct request *req); bool nvme_cancel_request(struct request *req, void *data, bool reserved); void nvme_cancel_tagset(struct nvme_ctrl *ctrl); void nvme_cancel_admin_tagset(struct nvme_ctrl *ctrl); @@ -610,6 +630,21 @@ struct request *nvme_alloc_request(struct request_queue *q, void nvme_cleanup_cmd(struct request *req); blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req, struct nvme_command *cmd); +blk_status_t nvme_fail_nonready_command(struct nvme_ctrl *ctrl, + struct request *req); +bool __nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq, + bool queue_live); + +static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq, + bool queue_live) +{ + if (likely(ctrl->state == NVME_CTRL_LIVE)) + return true; + if (ctrl->ops->flags & NVME_F_FABRICS && + ctrl->state == NVME_CTRL_DELETING) + return true; + return __nvme_check_ready(ctrl, rq, queue_live); +} int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, void *buf, unsigned bufflen); int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, @@ -619,6 +654,13 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid, unsigned int dword11, void *buffer, size_t buflen, u32 *result); +#ifdef MY_ABC_HERE +int syno_nvme_get_error_log_page(struct nvme_ctrl *dev, + struct syno_nvme_error_log_page **err_log, int *err_entries); +int syno_nvme_lba_write_pattern(struct nvme_ns *ns, u64 lba); +void syno_nvme_put_ns(struct nvme_ns *ns); +struct nvme_ns *syno_nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned int nsid); +#endif /* MY_ABC_HERE */ int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid, unsigned int dword11, void *buffer, size_t buflen, u32 *result); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index fb48a88d1acb..90ef2a24fd60 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * NVM Express device driver @@ -29,6 +32,18 @@ #include "trace.h" #include "nvme.h" +#ifdef MY_ABC_HERE +#include +#include +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, + const int size); +extern int syno_compare_dts_pciepath(const struct pci_dev *pdev, + const struct device_node *pDeviceNode); +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE +extern void syno_disk_not_ready_count_increase(void); +extern void syno_disk_not_ready_count_decrease(void); +#endif /* MY_DEF_HERE */ #define SQ_SIZE(q) ((q)->q_depth << (q)->sqes) #define CQ_SIZE(q) ((q)->q_depth * sizeof(struct nvme_completion)) @@ -153,6 +168,12 @@ struct nvme_dev { unsigned int nr_allocated_queues; unsigned int nr_write_queues; unsigned int nr_poll_queues; +#ifdef MY_DEF_HERE + int syno_disk_index; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + struct work_struct syno_remap_work; +#endif /* MY_ABC_HERE */ }; static int io_queue_depth_set(const char *val, const struct kernel_param *kp) @@ -216,6 +237,21 @@ struct nvme_queue { struct completion delete_done; }; +#ifdef MY_ABC_HERE +#define SYNO_NVME_INDEX_OFFSET 1000 +int SynoNVMeGetDeviceIndex(struct gendisk *disk) +{ + struct nvme_ns *ns = NULL; + + BUG_ON(NULL == disk); + + ns = (struct nvme_ns *)disk->private_data; + + return ns->ctrl->instance + SYNO_NVME_INDEX_OFFSET; +} +EXPORT_SYMBOL(SynoNVMeGetDeviceIndex); +#endif /* MY_ABC_HERE */ + /* * The nvme_iod describes the data in an I/O. * @@ -235,6 +271,13 @@ struct nvme_iod { struct scatterlist *sg; }; +#ifdef MY_ABC_HERE +struct syno_nvme_remap_req { + struct list_head list; + struct request *req; +}; +#endif /* MY_ABC_HERE */ + static inline unsigned int nvme_dbbuf_size(struct nvme_dev *dev) { return dev->nr_allocated_queues * 8 * dev->db_stride; @@ -931,6 +974,9 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx, if (unlikely(!test_bit(NVMEQ_ENABLED, &nvmeq->flags))) return BLK_STS_IOERR; + if (!nvme_check_ready(&dev->ctrl, req, true)) + return nvme_fail_nonready_command(&dev->ctrl, req); + ret = nvme_setup_cmd(ns, req, &cmnd); if (ret) return ret; @@ -974,6 +1020,15 @@ static void nvme_pci_complete_rq(struct request *req) static inline bool nvme_cqe_pending(struct nvme_queue *nvmeq) { struct nvme_completion *hcqe = &nvmeq->cqes[nvmeq->cq_head]; +#ifdef MY_ABC_HERE + if (unlikely(nvmeq->dev->ctrl.syno_force_timeout)) { + /* + * Not respond to any IRQ to simulate the NVMe device controller + * was dead. + */ + return false; + } +#endif /* MY_ABC_HERE */ return (le16_to_cpu(READ_ONCE(hcqe->status)) & 1) == nvmeq->cq_phase; } @@ -1125,6 +1180,210 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl) nvme_submit_cmd(nvmeq, &c, true); } +#ifdef MY_ABC_HERE +static int get_req_error_log(struct request *req, + struct syno_nvme_error_log_page *log_pages, int entries, + struct syno_nvme_error_log_page **err_idx) +{ + struct syno_nvme_error_log_page *log_page = NULL; + int ret = -1; + int i; + + for (i = 0; i < entries; i++) { + log_page = &log_pages[i]; + + if (req->tag == log_page->cmdid && + nvme_req(req)->status == (log_page->status_field >> 1)) { + *err_idx = log_page; + ret = 1; + goto end; + } + } + + /* corresponding error log not found */ + ret = 0; +end: + return ret; +} + +extern unsigned char +syno_is_sector_need_auto_remap(struct gendisk *disk, sector_t lba); +#ifdef MY_ABC_HERE +extern void syno_req_set_bio_auto_remap_flag(struct request *req, sector_t lba); +#endif /* MY_ABC_HERE */ + +static int process_req(struct nvme_ctrl *ctrl, + struct syno_nvme_remap_req *remap_req, + struct syno_nvme_error_log_page *err_log, int err_entries, + bool skip_req) +{ + struct request *req = NULL; + struct nvme_ns *ns = NULL; + struct syno_nvme_error_log_page *err_idx = NULL; + int ret = -1; + int status = -1; + + req = remap_req->req; + + if (!req) { + dev_warn(ctrl->device, "invalid request\n"); + goto err; + } + + if (skip_req) { + dev_warn(ctrl->device, "skip request tag: %u\n", req->tag); + goto end; + } + + if (err_log == NULL) { + dev_warn(ctrl->device, "empty error log page\n"); + goto err; + } + + if (get_req_error_log(req, err_log, err_entries, &err_idx) != 1) { + dev_warn(ctrl->device, "failed to get corresponding error log of tag: %u\n", + req->tag); + goto err; + } + + status = nvme_req(req)->status & 0x7ff; + if (status == NVME_SC_SUCCESS) + status = 0; + else if (status == NVME_SC_CAP_EXCEEDED) + status = -ENOSPC; + else + status = -EIO; + + ns = syno_nvme_find_get_ns(ctrl, err_idx->nsid); + + if (ns == NULL) { + dev_warn(ctrl->device, "failed to find ns of nsid %u\n", + err_idx->nsid); + goto err; + } + + dev_warn(ctrl->device, "%s read unc at %llu\n", + ns->disk->disk_name, err_idx->lba); + + if (!syno_is_sector_need_auto_remap(ns->disk, err_idx->lba)) { + /* do not need to remap */ + goto end; + } + + if (syno_nvme_lba_write_pattern(ns, err_idx->lba) != 0) { + dev_warn(ctrl->device, "failed to remap lba at %llu\n", + err_idx->lba); + goto err; + } + +#ifdef MY_ABC_HERE + syno_req_set_bio_auto_remap_flag(req, err_idx->lba); +#endif /* MY_ABC_HERE */ + +end: + ret = 0; + +err: + if (ns) { + syno_nvme_put_ns(ns); + ns = NULL; + } + + if (req) { + blk_mq_end_request(req, errno_to_blk_status(status)); + req = NULL; + } + kfree(remap_req); + remap_req = NULL; + + return ret; +} + +static void process_all_reqs(struct nvme_ctrl *ctrl, + struct syno_nvme_error_log_page *err_log, int err_entries, + bool skip_req) +{ + struct syno_nvme_remap_req *remap_req = NULL; + unsigned long flags; + + do { + spin_lock_irqsave(&ctrl->syno_remap_reqs_lock, flags); + if (list_empty(&ctrl->syno_remap_reqs)) { + /* no more request to be processed */ + remap_req = NULL; + } else { + /* pop up the first unprocessed read failed request */ + remap_req = list_first_entry(&ctrl->syno_remap_reqs, + struct syno_nvme_remap_req, list); + list_del(&remap_req->list); + } + spin_unlock_irqrestore(&ctrl->syno_remap_reqs_lock, flags); + } while (remap_req != NULL && + process_req(ctrl, remap_req, err_log, err_entries, skip_req) == 0); +} + +static void release_all_reqs(struct nvme_ctrl *ctrl) +{ + process_all_reqs(ctrl, NULL, 0, true); +} + +static void syno_nvme_remap_work(struct work_struct *work) +{ + struct nvme_dev *dev = container_of(work, struct nvme_dev, syno_remap_work); + struct nvme_ctrl *ctrl = &dev->ctrl; + struct syno_nvme_error_log_page *err_log = NULL; + int error = 0; + int entries = 0; + + error = syno_nvme_get_error_log_page(ctrl, &err_log, &entries); + if (error) { + dev_warn(ctrl->device, "failed to get error page\n"); + dev_warn(ctrl->device, "\tmodel: %s\n", ctrl->subsys->model); + dev_warn(ctrl->device, "\tfirmware rev: %s\n", ctrl->subsys->firmware_rev); + dev_warn(ctrl->device, "\terror log page entries: %u\n", ctrl->syno_elpe); + dev_warn(ctrl->device, "\terror: %d\n", error); + goto err; + } + + process_all_reqs(ctrl, err_log, entries, false); + +err: + release_all_reqs(ctrl); + kfree(err_log); + err_log = NULL; +} + +int syno_nvme_do_remap_req(struct request *req) +{ + struct nvme_iod *iod = blk_mq_rq_to_pdu(req); + struct nvme_dev *dev = iod->nvmeq->dev; + struct nvme_ctrl *ctrl = &dev->ctrl; + struct syno_nvme_remap_req *remap_req = NULL; + unsigned long flags; + int ret = -EPERM; + + remap_req = kmalloc(sizeof(*remap_req), GFP_ATOMIC | __GFP_NOWARN); + + if (!remap_req) { + ret = -ENOMEM; + goto err; + } + + remap_req->req = req; + + spin_lock_irqsave(&ctrl->syno_remap_reqs_lock, flags); + list_add_tail(&remap_req->list, &ctrl->syno_remap_reqs); + spin_unlock_irqrestore(&ctrl->syno_remap_reqs_lock, flags); + + queue_work(nvme_wq, &dev->syno_remap_work); + + ret = 0; +err: + return ret; +} +EXPORT_SYMBOL(syno_nvme_do_remap_req); +#endif /* MY_ABC_HERE */ + static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) { struct nvme_command c; @@ -2423,6 +2682,12 @@ static int nvme_pci_enable(struct nvme_dev *dev) dev->q_depth = 64; dev_err(dev->ctrl.device, "detected PM1725 NVMe controller, " "set queue depth=%u\n", dev->q_depth); +#ifdef MY_DEF_HERE + } else if (pdev->vendor == PCI_VENDOR_ID_SAMSUNG && pdev->device == 0xa808) { + dev->q_depth = 64; + dev_err(dev->ctrl.device, "detected samsung 970 EVO controller, " + "set queue depth=%u\n", dev->q_depth); +#endif /* MY_DEF_HERE */ } /* @@ -2475,6 +2740,11 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) mutex_lock(&dev->shutdown_lock); if (pci_is_enabled(pdev)) { u32 csts = readl(dev->bar + NVME_REG_CSTS); +#ifdef MY_ABC_HERE + if (unlikely(dev->ctrl.syno_force_timeout)) { + csts |= NVME_CSTS_CFS; + } +#endif /* MY_ABC_HERE */ if (dev->ctrl.state == NVME_CTRL_LIVE || dev->ctrl.state == NVME_CTRL_RESETTING) { @@ -2725,6 +2995,7 @@ static void nvme_reset_work(struct work_struct *work) if (result) dev_warn(dev->ctrl.device, "Removing after probe failure status: %d\n", result); + nvme_remove_dead_ctrl(dev); } @@ -2868,8 +3139,91 @@ static void nvme_async_probe(void *data, async_cookie_t cookie) flush_work(&dev->ctrl.reset_work); flush_work(&dev->ctrl.scan_work); nvme_put_ctrl(&dev->ctrl); + +#ifdef MY_DEF_HERE + syno_disk_not_ready_count_decrease(); +#endif /* MY_DEF_HERE */ + } +#ifdef MY_DEF_HERE +#ifdef MY_ABC_HERE +static int syno_nvme_index_get(const struct pci_dev *pdev) +{ + int iIndex = -1; + struct device_node *pDeviceNode = NULL; + + if (NULL == pdev || NULL == of_root) { + goto END; + } + + for_each_child_of_node(of_root, pDeviceNode) { + if (pDeviceNode->full_name && + 0 == strncmp(pDeviceNode->full_name, DT_INTERNAL_SLOT, + strlen(DT_INTERNAL_SLOT))) { + /* skip non-internal nvme device */ + if (!of_find_property(pDeviceNode, DT_PCIE_ROOT, + NULL)) { + continue; + } + + if (0 == syno_compare_dts_pciepath(pdev, pDeviceNode)) { + /* + * get index number of nvme_slot + * e.g. internal_slot@4 --> 4 + */ + sscanf(pDeviceNode->full_name, + DT_INTERNAL_SLOT "@%d", &iIndex); + of_node_put(pDeviceNode); + break; + } + } + } +END: + return iIndex; +} +#else /* MY_ABC_HERE */ +static int syno_nvme_index_get(const struct pci_dev *pdev) +{ + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void syno_ledtrig_active_set(int iLedNum); +extern int *gpGreenLedMap; + +void syno_nvme_sw_activity_by_lp3943(struct nvme_ctrl *ctrl) +{ + struct nvme_dev *dev = to_nvme_dev(ctrl); + if (NULL == gpGreenLedMap || 0 > dev->syno_disk_index) { + return; + } + syno_ledtrig_active_set(gpGreenLedMap[dev->syno_disk_index]); +} +EXPORT_SYMBOL(syno_nvme_sw_activity_by_lp3943); +#endif /* MY_ABC_HERE */ +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +/* copy from driver/scsi/sd.c */ +static void syno_pciepath_enum(struct device *dev, char *buf) { + struct pci_dev *pdev = NULL; + char sztemp[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (NULL == buf || NULL == dev) { + return; + } + pdev = to_pci_dev(dev); + + if (-1 == syno_pciepath_dts_pattern_get(pdev, sztemp, sizeof(sztemp))) { + return; + } + + snprintf(buf, BLOCK_INFO_SIZE, "%spciepath=%s\n", buf, sztemp); +} +#endif /* MY_ABC_HERE */ + static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int node, result = -ENOMEM; @@ -2902,6 +3256,9 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work); INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work); +#ifdef MY_ABC_HERE + INIT_WORK(&dev->syno_remap_work, syno_nvme_remap_work); +#endif /* MY_ABC_HERE */ mutex_init(&dev->shutdown_lock); result = nvme_setup_prp_pools(dev); @@ -2941,8 +3298,19 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (result) goto release_mempool; +#ifdef MY_ABC_HERE + syno_pciepath_enum(&pdev->dev, dev->ctrl.syno_block_info); +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + dev->syno_disk_index = syno_nvme_index_get(pdev) - 1; +#endif /* MY_DEF_HERE */ + dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev)); +#ifdef MY_DEF_HERE + syno_disk_not_ready_count_increase(); +#endif /* MY_DEF_HERE */ + nvme_reset_ctrl(&dev->ctrl); async_schedule(nvme_async_probe, dev); @@ -3007,6 +3375,9 @@ static void nvme_remove(struct pci_dev *pdev) nvme_dev_disable(dev, true); } +#ifdef MY_ABC_HERE + flush_work(&dev->syno_remap_work); +#endif /* MY_ABC_HERE */ flush_work(&dev->ctrl.reset_work); nvme_stop_ctrl(&dev->ctrl); nvme_remove_namespaces(&dev->ctrl); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index e6d58402b829..1f20e9f05a47 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -2058,8 +2058,8 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, WARN_ON_ONCE(rq->tag < 0); - if (!nvmf_check_ready(&queue->ctrl->ctrl, rq, queue_ready)) - return nvmf_fail_nonready_command(&queue->ctrl->ctrl, rq); + if (!nvme_check_ready(&queue->ctrl->ctrl, rq, queue_ready)) + return nvme_fail_nonready_command(&queue->ctrl->ctrl, rq); dev = queue->device->dev; diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 82b2611d39a2..e9800b93f985 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2342,8 +2342,8 @@ static blk_status_t nvme_tcp_queue_rq(struct blk_mq_hw_ctx *hctx, bool queue_ready = test_bit(NVME_TCP_Q_LIVE, &queue->flags); blk_status_t ret; - if (!nvmf_check_ready(&queue->ctrl->ctrl, rq, queue_ready)) - return nvmf_fail_nonready_command(&queue->ctrl->ctrl, rq); + if (!nvme_check_ready(&queue->ctrl->ctrl, rq, queue_ready)) + return nvme_fail_nonready_command(&queue->ctrl->ctrl, rq); ret = nvme_tcp_setup_cmd_pdu(ns, rq); if (unlikely(ret)) diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index 16d71cc5a50e..5949baf07105 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -138,8 +138,8 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, bool queue_ready = test_bit(NVME_LOOP_Q_LIVE, &queue->flags); blk_status_t ret; - if (!nvmf_check_ready(&queue->ctrl->ctrl, req, queue_ready)) - return nvmf_fail_nonready_command(&queue->ctrl->ctrl, req); + if (!nvme_check_ready(&queue->ctrl->ctrl, req, queue_ready)) + return nvme_fail_nonready_command(&queue->ctrl->ctrl, req); ret = nvme_setup_cmd(ns, req, &iod->cmd); if (ret) diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 954d3b4a52ab..922d07d786b6 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -270,4 +270,16 @@ config SPRD_EFUSE This driver can also be built as a module. If so, the module will be called nvmem-sprd-efuse. +if SYNO_LSP_RTD1619B +config RTK_EFUSE + tristate "Realtek SoCs eFuse support" + depends on ARCH_REALTEK || COMPILE_TEST + depends on HAS_IOMEM + help + This is a driver to access specific data from eFuse + + This driver can also be built as a module. If so, the module + will be called efuse-rtk. + +endif # SYNO_LSP_RTD1619B endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index a7c377218341..19c205d9d489 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -33,6 +33,10 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o nvmem_rockchip_efuse-y := rockchip-efuse.o obj-$(CONFIG_ROCKCHIP_OTP) += nvmem-rockchip-otp.o nvmem-rockchip-otp-y := rockchip-otp.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTK_EFUSE) += nvmem_rtk-efuse.o +nvmem_rtk-efuse-y := rtk-efuse.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o nvmem_stm32_romem-y := stm32-romem.o obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o diff --git a/drivers/nvmem/rtk-efuse.c b/drivers/nvmem/rtk-efuse.c new file mode 100644 index 000000000000..458959ba7496 --- /dev/null +++ b/drivers/nvmem/rtk-efuse.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2016-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#define pr_fmt(fmt) "rtk-efuse: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OTP_CTRL 0x000 +#define OTP_CTRL_ST 0x004 +#define OTP_CRC 0x008 +#define OTP_TM 0x00c +#define OTP_DBG 0x010 +#define OTP_TM_ST 0x014 +#define OTP_DUMMY 0x018 +#define OTP_CFG 0x020 +#define OTP_RINGOSC 0x024 +#define OTP_CLK_DTE 0x028 + +struct rtk_efuse_desc { + int size; + int ctl_reg_sel; + int ctl_offset; + int enable_icg : 1; + int writable : 1; +}; + +struct rtk_efuse_device { + struct nvmem_config config; + struct device *dev; + struct list_head list; + void *base; + void *ctl_base; + struct nvmem_device *nvmem; + struct mutex lock; + struct sb2_sem *hwlock; + const struct rtk_efuse_desc *desc; +}; + +static unsigned long rtk_efuse_lock(struct rtk_efuse_device *edev) +{ + unsigned long flags = 0; + + mutex_lock(&edev->lock); + if (edev->hwlock) + sb2_sem_lock(edev->hwlock, 0); + return flags; +} + +static void rtk_efuse_unlock(struct rtk_efuse_device *edev, unsigned long flags) +{ + if (edev->hwlock) + sb2_sem_unlock(edev->hwlock); + mutex_unlock(&edev->lock); +} + +static int rtk_efuse_reg_read_unlocked(struct rtk_efuse_device *edev, unsigned int offset, unsigned char *val, size_t bytes) +{ + int i; + + for (i = 0; i < bytes; i++) + val[i] = readb(edev->base + offset + i); + return 0; +} + +static int rtk_efuse_reg_read(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct rtk_efuse_device *edev = priv; + unsigned long flags; + + dev_dbg(edev->dev, "%s: offset=%03x, size=%zd\n", __func__, offset, bytes); + might_sleep(); + + flags = rtk_efuse_lock(edev); + rtk_efuse_reg_read_unlocked(edev, offset, val, bytes); + rtk_efuse_unlock(edev, flags); + + return 0; +} + +static int rtk_efuse_wait_write_done(struct rtk_efuse_device *edev, int timeout_us) +{ + unsigned int val; + + return readl_poll_timeout(edev->ctl_base + OTP_CTRL_ST, val, !(val & BIT(16)), 0, timeout_us); +} + +static int __rtk_efuse_program(struct rtk_efuse_device *edev, int addr, unsigned char val) +{ + unsigned int cmd, tm_st; + unsigned char cval; + int ret; + + ret = rtk_efuse_wait_write_done(edev, 20); + if (ret) + return ret; + + cmd = 0x31000800 | (val << 16) | addr; + writel(cmd, edev->ctl_base + OTP_CTRL); + + ret = rtk_efuse_wait_write_done(edev, 100); + if (ret) + return ret; + udelay(250); + + tm_st = readl(edev->ctl_base + OTP_TM_ST); + if ((tm_st & 0x300) != 0x100) + ret = -EIO; + + rtk_efuse_reg_read_unlocked(edev, addr, &cval, 1); + + if (ret || cval != val) { + dev_warn(edev->dev, "%s: OTP_CTRL=%08x, OTP_TM_ST=%08x, excepted=%02x, current=%02x, ret=%d\n", __func__, cmd, tm_st, val, cval, ret); + ret = -EBUSY; + } + return ret; +} + +static int rtk_efuse_set_bit(struct rtk_efuse_device *edev, int bit_offset) +{ + unsigned int addr = (bit_offset >> 3); + unsigned int bit = bit_offset & 0x7; + unsigned char val; + unsigned long flags; + int ret; + + flags = rtk_efuse_lock(edev); + + rtk_efuse_reg_read_unlocked(edev, addr, &val, 1); + val = val | BIT(bit); + ret = __rtk_efuse_program(edev, addr, val); + + rtk_efuse_unlock(edev, flags); + return ret; +} + +static int rtk_efuse_write_byte_bit_by_bit(struct rtk_efuse_device *edev, int addr, unsigned char val) +{ + int ret; + int j; + + dev_dbg(edev->dev, "%s: addr=%03x, val=%02x\n", __func__, addr, val); + for (j = 0; j < 8; j++) { + if ((val & BIT(j)) == 0) + continue; + + ret = rtk_efuse_set_bit(edev, addr * 8 + j); + if (ret) + return ret; + } + + return 0; +} + +static int rtk_efuse_write_byte_normal(struct rtk_efuse_device *edev, int addr, unsigned char val) +{ + unsigned long flags; + unsigned char rval; + int ret; + + dev_dbg(edev->dev, "%s: addr=%03x, val=%02x\n", __func__, addr, val); + flags = rtk_efuse_lock(edev); + + rtk_efuse_reg_read_unlocked(edev, addr, &rval, 1); + if (rval & ~val) { + rtk_efuse_unlock(edev, flags); + return -EINVAL; + } + + val = rval | val; + ret = __rtk_efuse_program(edev, addr, val); + + rtk_efuse_unlock(edev, flags); + return ret; +} + +static int rtk_efuse_write_byte(struct rtk_efuse_device *edev, int addr, unsigned char val) +{ + int retry = 20; + int ret; + + if (val == 0) + return 0; + +again: + dev_dbg(edev->dev, "%s: addr=%03x, val=%02x\n", __func__, addr, val); + ret = rtk_efuse_write_byte_normal(edev, addr, val); + + if (ret && ret != -EBUSY) + ret = rtk_efuse_write_byte_bit_by_bit(edev, addr, val); + + if (ret == -EBUSY && retry-- >= 0) + goto again; + return ret; +} + +static int rtk_efuse_reg_write(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct rtk_efuse_device *edev = priv; + unsigned char *p = val; + int i; + int ret; + + dev_dbg(edev->dev, "%s: offset=%03x, size=%zu\n", __func__, offset, bytes); + might_sleep(); + + for (i = 0; i < bytes; i++) { + ret = rtk_efuse_write_byte(edev, offset + i, p[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct rtk_efuse_desc rtd1295_efuse_desc = { + .size = 0x400, + .ctl_offset = 0x400, + .enable_icg = 0, + .writable = 0, +}; + +static const struct rtk_efuse_desc rtd1619_efuse_desc = { + .size = 0x800, + .ctl_offset = 0x800, + .enable_icg = 1, + .writable = 1, +}; + +static const struct rtk_efuse_desc rtd1619b_efuse_desc = { + .size = 0x1000, + .ctl_reg_sel = 1, + .ctl_offset = 0x0, + .enable_icg = 1, + .writable = 1, +}; + +static int rtk_efuse_enable_powersaving(struct rtk_efuse_device *edev) +{ + if (!edev->desc->enable_icg) + return 0; + + writel(0x0C00C000, edev->ctl_base + OTP_CTRL); + return 0; +} + +static int rtk_efuse_probe(struct platform_device *pdev) +{ + struct rtk_efuse_device *edev; + struct device *dev = &pdev->dev; + struct resource *res; + const struct rtk_efuse_desc *desc; + + desc = of_device_get_match_data(dev); + if (!desc) + desc = &rtd1295_efuse_desc; + + edev = devm_kzalloc(dev, sizeof(*edev), GFP_KERNEL); + if (!edev) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + edev->base = devm_ioremap_resource(dev, res); + if (IS_ERR(edev->base)) + return PTR_ERR(edev->base); + + if (desc->ctl_reg_sel) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + edev->ctl_base = devm_ioremap_resource(dev, res); + if (IS_ERR(edev->ctl_base)) { + dev_err(dev, "failed to get ctl_base\n"); + return PTR_ERR(edev->ctl_base); + } + + edev->ctl_base += desc->ctl_offset; + + } else { + edev->ctl_base = edev->base + desc->ctl_offset; + } + + edev->dev = dev; + edev->desc = desc; + mutex_init(&edev->lock); + + edev->hwlock = of_sb2_sem_get(dev->of_node, 0); + if (IS_ERR(edev->hwlock)) { + dev_dbg(dev, "failed to get hw semaphore: %ld\n", + PTR_ERR(edev->hwlock)); + edev->hwlock = NULL; + } + + if (edev->hwlock) + dev_info(dev, "use hw lock\n"); + + edev->config.owner = THIS_MODULE; + edev->config.name = "rtk-efuse"; + edev->config.stride = 1; + edev->config.word_size = 1; + edev->config.reg_read = rtk_efuse_reg_read; + edev->config.reg_write = edev->desc->writable ? rtk_efuse_reg_write : NULL; + edev->config.dev = dev; + edev->config.size = desc->size; + edev->config.priv = edev; + + edev->nvmem = nvmem_register(&edev->config); + if (IS_ERR(edev->nvmem)) + return PTR_ERR(edev->nvmem); + + rtk_efuse_enable_powersaving(edev); + + platform_set_drvdata(pdev, edev); + return 0; +} + +static int rtk_efuse_remove(struct platform_device *pdev) +{ + struct rtk_efuse_device *edev = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + nvmem_unregister(edev->nvmem); + return 0; +} + +static const struct of_device_id rtk_efuse_of_match[] = { + {.compatible = "realtek,efuse", .data = &rtd1295_efuse_desc, }, + {.compatible = "realtek,rtd1619-otp", .data = &rtd1619_efuse_desc, }, + {.compatible = "realtek,rtd1619b-otp", .data = &rtd1619b_efuse_desc, }, + {}, +}; + +static struct platform_driver rtk_efuse_drv = { + .probe = rtk_efuse_probe, + .remove = rtk_efuse_remove, + .driver = { + .name = "rtk-efuse", + .owner = THIS_MODULE, + .of_match_table = rtk_efuse_of_match, + }, +}; + +static __init int rtk_efuse_init(void) +{ + return platform_driver_register(&rtk_efuse_drv); +} +subsys_initcall(rtk_efuse_init); + +MODULE_DESCRIPTION("Realtek eFuse driver"); +MODULE_ALIAS("platform:rtk-efuse"); +MODULE_LICENSE("GPL"); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 57ff31b6b1e4..cd39e30ca3f2 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Functions for working with the Flattened Device Tree data format @@ -31,6 +34,160 @@ #include "of_private.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int gSynoInternalHddNumber; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern char gSynoSmbusHddType[16]; +extern int gSynoSmbusSwitchCount; +extern int gSynoSmbusSwitchAdapters[SMBUS_SWITCH_MAX_COUNT+1]; +extern int gSynoSmbusSwitchAddrs[SMBUS_SWITCH_MAX_COUNT+1]; +extern int gSynoSmbusSwitchVals[SMBUS_SWITCH_MAX_COUNT+1]; +#endif /*MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +extern int gSynoHddPowerupSeq; +extern int giSynoSpinupGroup[SYNO_SPINUP_GROUP_MAX]; +extern int giSynoSpinupGroupNum; +extern int giSynoSpinupGroupDelay; +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +void __init syno_init_internal_hdd_number(void) +{ + int internalHDDNumber = 0; + struct device_node *pSlotNode = NULL; + + for_each_child_of_node(of_root, pSlotNode) { + // get index number of internal_slot, e.g. /internal_slot@4 --> 4 + if (!pSlotNode->full_name || 0 != strncmp(pSlotNode->full_name, DT_INTERNAL_SLOT, strlen(DT_INTERNAL_SLOT))) { + continue; + } + internalHDDNumber++; + } + + gSynoInternalHddNumber = internalHDDNumber; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void __init syno_init_smbus_hdd_pwrctl(void) +{ + int retReadDT = 0; + int smbushddadapter = 0; + int smbushddaddress = 0; + char *smbushddtype = NULL; + int i; + int smbusSwitchAdapter = 0; + int smbusSwitchAddr = 0; + int smbusSwitchVal = 0; + + smbushddtype = (char *)of_get_property(of_root, DT_SYNO_HDD_SMBUS_TYPE, NULL); + + if (smbushddtype != NULL) { + snprintf(gSynoSmbusHddType, sizeof(gSynoSmbusHddType), "%s", smbushddtype); + printk("SYNO Smbus Hdd Type: %s\n", gSynoSmbusHddType); + } + + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_HDD_SMBUS_ADAPTER, 0, &smbushddadapter); + if (0 == retReadDT) { + gSynoSmbusHddAdapter = smbushddadapter; + printk("SYNO Smbus Hdd Adapter: %d\n", gSynoSmbusHddAdapter); + } + + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_HDD_SMBUS_ADDRESS, 0, &smbushddaddress); + if (0 == retReadDT) { + gSynoSmbusHddAddress = smbushddaddress; + printk("SYNO Smbus Hdd Address: 0x%02x\n", gSynoSmbusHddAddress); + } + // set the smbus switch settings to open the switches early + // the last position in the array is used to handle the errors + // note: + // gSynoSmbusSwitchCount is used to record the last index. When there is + // an error occurs, it means the array size is stop here, and therefore + // gSynoSmbusSwitchCount is updated at that moment. After the update, + // break the for loop. + for (i = 0;i <= SMBUS_SWITCH_MAX_COUNT;i++){ + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_SMBUS_SWITCH_ADAPTERS, i, &smbusSwitchAdapter); + if (0 == retReadDT) { + // if the number of switches are more than the maximum setting + if (i == SMBUS_SWITCH_MAX_COUNT){ + printk(KERN_ERR "Smbus switch settings are more than %d. The rest of settings will not be applied.\n", + SMBUS_SWITCH_MAX_COUNT); + gSynoSmbusSwitchCount = i; + break; + } + gSynoSmbusSwitchAdapters[i] = smbusSwitchAdapter; + printk("SYNO Smbus Switch Adapter[%d]: %d\n", i, gSynoSmbusSwitchAdapters[i]); + } else { + gSynoSmbusSwitchCount = i; + printk("System reads %d pairs of smbus configs", i); + break; + } + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_SMBUS_SWITCH_ADDRS, i, &smbusSwitchAddr); + if (0 == retReadDT) { + gSynoSmbusSwitchAddrs[i] = smbusSwitchAddr; + printk("SYNO Smbus Switch Addr[%d]: 0x%02x\n", i, gSynoSmbusSwitchAddrs[i]); + } else { + gSynoSmbusSwitchCount = i; + printk("SYNO Smbus Switch Addr[%d] loads fail, please check\n", i); + break; + } + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_SMBUS_SWITCH_VALS, i, &smbusSwitchVal); + if (0 == retReadDT) { + gSynoSmbusSwitchVals[i] = smbusSwitchVal; + printk("SYNO Smbus Switch Val[%d]: 0x%02x\n", i, gSynoSmbusSwitchVals[i]); + } else { + gSynoSmbusSwitchCount = i; + printk("SYNO Smbus Switch Val[%d] loads fail, please check\n", i); + break; + } + } + gSynoSmbusSwitchAdapters[gSynoSmbusSwitchCount] = -1; + gSynoSmbusSwitchAddrs[gSynoSmbusSwitchCount] = 0; + gSynoSmbusSwitchVals[gSynoSmbusSwitchCount] = 0xff; + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +void __init syno_init_spinup_group(void) +{ + int group_num = 0, retReadDT = 0, spinupGroupMemberNum = 0, spinupGroupDelay = 0; + char *szSynoHddPowerupSeq = NULL; + + szSynoHddPowerupSeq = (char *)of_get_property(of_root, DT_HDD_POWERUP_SEQ, NULL); + + if (szSynoHddPowerupSeq && 0 == strncmp(szSynoHddPowerupSeq, "true", strlen("true"))) { + gSynoHddPowerupSeq = 1; + } + + for (group_num = 0; group_num < sizeof(giSynoSpinupGroup)/sizeof(int); group_num++) { + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_SPINUP_GROUP, group_num, &spinupGroupMemberNum); + // if reading DT error, this means that reading to the end of spinup_group or no spinup_group + if (retReadDT) { + break; + } + giSynoSpinupGroup[group_num] = spinupGroupMemberNum; + printk("SYNO Spinup Group %d: %d\n", group_num, giSynoSpinupGroup[group_num]); + } + giSynoSpinupGroupNum = group_num; + + retReadDT = of_property_read_u32_index(of_root, DT_SYNO_SPINUP_GROUP_DELAY, 0, &spinupGroupDelay); + if (0 == retReadDT) { + giSynoSpinupGroupDelay = spinupGroupDelay; + printk("SYNO Spinup Group Delay: %d\n", giSynoSpinupGroupDelay); + } +} +#endif /* MY_DEF_HERE */ + /* * of_fdt_limit_memory - limit the number of regions in the /memory node * @limit: maximum entries @@ -1235,6 +1392,17 @@ void __init unflatten_device_tree(void) of_alias_scan(early_init_dt_alloc_memory_arch); unittest_unflatten_overlay_base(); + + /* Synology global arguments from dts */ +#ifdef MY_ABC_HERE + syno_init_internal_hdd_number(); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_init_smbus_hdd_pwrctl(); +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + syno_init_spinup_group(); +#endif /* MY_DEF_HERE */ } /** diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 64e2f5e379aa..7ce2514ae6b5 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -305,6 +305,27 @@ config PCIE_HISI_ERR Say Y here if you want error handling support for the PCIe controller's errors on HiSilicon HIP SoCs +if SYNO_LSP_RTD1619B +config PCIE_RTD + bool "Realtek PCIe host controller" + select PHY_RTD_PCIE + select PCI_MSI_ARCH_FALLBACKS + help + Realtek PCIe host controller support. + +config RTD16XXB_PCIE1_ACP + bool "Realtek PCIe host controller ACP support" + depends on PCIE_RTD + help + Enable Realtek RTD16XXB PCIE1 ACP. + +config PCIE_RTD_TRANS + bool "Realtek PCIe tanslation" + depends on PCIE_RTD + help + Realtek PCIe MMIO translation support. + +endif # SYNO_LSP_RTD1619B source "drivers/pci/controller/dwc/Kconfig" source "drivers/pci/controller/mobiveil/Kconfig" source "drivers/pci/controller/cadence/Kconfig" diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 04c6edc285c5..5d084901be5f 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -32,6 +32,10 @@ obj-$(CONFIG_VMD) += vmd.o obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_PCIE_RTD) += pcie-rtd.o +obj-$(CONFIG_PCIE_RTD_TRANS) += pcie-rtd-trans.o +endif # CONFIG_SYNO_LSP_RTD1619B # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW obj-y += dwc/ obj-y += mobiveil/ diff --git a/drivers/pci/controller/pcie-rtd-trans.c b/drivers/pci/controller/pcie-rtd-trans.c new file mode 100644 index 000000000000..d9acaf6f5b90 --- /dev/null +++ b/drivers/pci/controller/pcie-rtd-trans.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Realtek PCIe MMIO Translate driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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 + +#define PCIE_IO_64K_MASK 0xFFFF0000 + +struct regmap *pcie0_base; +struct regmap *pcie1_base; +struct regmap *pcie2_base; + +struct pcie_info { + struct regmap *base; + spinlock_t spinlock; + void __iomem *mmio_base; + struct device *dev; +}; + +struct pcie_info *pcie0_info; +struct pcie_info *pcie1_info; +struct pcie_info *pcie2_info; + + + +u32 rtk_pcie_ctrl_read(struct pcie_info *info, u32 offset) +{ + u32 val; + + regmap_read(info->base, offset, &val); + + return val; +} + +void rtk_pcie_ctrl_write(struct pcie_info *info, u32 offset, u32 val) +{ + regmap_write(info->base, offset, val); +} + +u32 rtk_pcie_mmio_read(struct pcie_info *info, u32 offset, u32 size) +{ + u32 val; + + switch (size) { + case 1: + val = readb(info->mmio_base + offset); + break; + case 2: + val = readw(info->mmio_base + offset); + break; + case 4: + val = readl(info->mmio_base + offset); + break; + default: + dev_err(info->dev, "RTD13xx: %s: wrong size %d\n", __func__, size); + val = 0; + break; + } + + return val; +} + +void rtk_pcie_mmio_write(struct pcie_info *info, u32 offset, u32 val, u32 size) +{ + switch (size) { + case 1: + writeb(val, info->mmio_base + offset); + break; + case 2: + writew(val, info->mmio_base + offset); + break; + case 4: + writel(val, info->mmio_base + offset); + break; + default: + dev_err(info->dev, "RTD13xx: %s: wrong size %d\n", __func__, size); + break; + } +} + + +u32 rtk_pcie_read(struct pcie_info *info, u32 addr, u8 size) +{ + u32 rval = 0; + u32 mask; + u32 translate_val = 0; + unsigned long irqL; + u32 pci_error_status = 0; + int retry_cnt = 0; + u8 retry = 5; + + spin_lock_irqsave(&info->spinlock, irqL); + + if (addr >= 0x10000) { + mask = PCIE_IO_64K_MASK; + translate_val = rtk_pcie_ctrl_read(info, 0xD04); + rtk_pcie_ctrl_write(info, 0xD04, translate_val | (addr & mask)); + } else + mask = 0x0; + +pci_read_13xx_retry: + + rval = rtk_pcie_mmio_read(info, addr & ~mask, size); + + + //DLLP error patch + pci_error_status = rtk_pcie_ctrl_read(info, 0xc7c); + if (pci_error_status & 0x1F) { + rtk_pcie_ctrl_write(info, 0xc7c, pci_error_status); + dev_err(info->dev, "RTD13xx: %s: DLLP(#%d) 0x%x reg=0x%x val=0x%x\n", + __func__, retry_cnt, pci_error_status, addr, rval); + + if (retry_cnt < retry) { + retry_cnt++; + goto pci_read_13xx_retry; + } + } + + if (addr >= 0x10000) + rtk_pcie_ctrl_write(info, 0xD04, translate_val); + + + spin_unlock_irqrestore(&info->spinlock, irqL); + + return rval; +} + + +void rtk_pcie_write(struct pcie_info *info, u32 addr, u8 size, u32 wval) +{ + u32 mask; + u32 translate_val = 0; + unsigned long irqL; + + spin_lock_irqsave(&info->spinlock, irqL); + + if (addr >= 0x10000) { + mask = PCIE_IO_64K_MASK; + translate_val = rtk_pcie_ctrl_read(info, 0xD04); + rtk_pcie_ctrl_write(info, 0xD04, translate_val | (addr & mask)); + } else + mask = 0x0; + + rtk_pcie_mmio_write(info, addr & ~mask, wval, size); + + if (addr >= 0x10000) + rtk_pcie_ctrl_write(info, 0xD04, translate_val); + + + spin_unlock_irqrestore(&info->spinlock, irqL); +} + +u32 rtk_pcie_13xx_read(u32 addr, u8 size) +{ + return rtk_pcie_read(pcie0_info, addr, size); +} +EXPORT_SYMBOL(rtk_pcie_13xx_read); + + +void rtk_pcie_13xx_write(u32 addr, u8 size, u32 wval) +{ + rtk_pcie_write(pcie0_info, addr, size, wval); +} +EXPORT_SYMBOL(rtk_pcie_13xx_write); + + +u32 rtk_pcie2_13xx_read(u32 addr, u8 size) +{ + return rtk_pcie_read(pcie1_info, addr, size); +} +EXPORT_SYMBOL(rtk_pcie2_13xx_read); + + +void rtk_pcie2_13xx_write(u32 addr, u8 size, u32 wval) +{ + rtk_pcie_write(pcie1_info, addr, size, wval); +} +EXPORT_SYMBOL(rtk_pcie2_13xx_write); + + +u32 rtk_pcie3_13xx_read(u32 addr, u8 size) +{ + return rtk_pcie_read(pcie2_info, addr, size); +} +EXPORT_SYMBOL(rtk_pcie3_13xx_read); + + +void rtk_pcie3_13xx_write(u32 addr, u8 size, u32 wval) +{ + rtk_pcie_write(pcie2_info, addr, size, wval); +} +EXPORT_SYMBOL(rtk_pcie3_13xx_write); + + +static int rtd_pcie_trans_probe(struct platform_device *pdev) +{ + struct device_node *syscon_np; + + syscon_np = of_parse_phandle(pdev->dev.of_node, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + pcie0_info = devm_kzalloc(&pdev->dev, sizeof(*pcie0_info), GFP_KERNEL); + pcie0_info->dev = &pdev->dev; + pcie0_info->base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pcie0_info->base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + pcie0_info->mmio_base = of_iomap(pdev->dev.of_node, 0); + if (!pcie0_info->mmio_base) { + dev_err(&pdev->dev, "failed to get pcie0 mmio address\n"); + return -EINVAL; + } + + spin_lock_init(&pcie0_info->spinlock); + + syscon_np = of_parse_phandle(pdev->dev.of_node, "syscon", 1); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + pcie1_info = devm_kzalloc(&pdev->dev, sizeof(*pcie1_info), GFP_KERNEL); + pcie1_info->dev = &pdev->dev; + pcie1_info->base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pcie1_info->base)) { + of_node_put(syscon_np); + return -EINVAL; + } + pcie1_info->mmio_base = of_iomap(pdev->dev.of_node, 1); + if (!pcie1_info->mmio_base) { + dev_err(&pdev->dev, "failed to get pcie1 mmio address\n"); + return -EINVAL; + } + + spin_lock_init(&pcie1_info->spinlock); + + syscon_np = of_parse_phandle(pdev->dev.of_node, "syscon", 2); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + pcie2_info = devm_kzalloc(&pdev->dev, sizeof(*pcie2_info), GFP_KERNEL); + pcie2_info->dev = &pdev->dev; + pcie2_info->base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pcie2_info->base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + pcie2_info->mmio_base = of_iomap(pdev->dev.of_node, 2); + if (!pcie2_info->mmio_base) { + dev_err(&pdev->dev, "failed to get pcie2 mmio address\n"); + return -EINVAL; + } + spin_lock_init(&pcie2_info->spinlock); + + dev_info(&pdev->dev, "\n===========rtd13xx pcie mmio translate ready\n"); + + return 0; +} + +static const struct of_device_id rtd_pcie_trans_match_table[] = { + {.compatible = "realtek,rtd13xx-pcie-trans"}, + {}, +}; + +static struct platform_driver rtd_pcie_trans_driver = { + .driver = { + .name = "Realtek DHC PCIe mmio translate", + .of_match_table = of_match_ptr(rtd_pcie_trans_match_table), + }, + .probe = rtd_pcie_trans_probe, +}; +module_platform_driver(rtd_pcie_trans_driver); + +MODULE_AUTHOR("TYChang "); +MODULE_DESCRIPTION("Realtek PCIe MMIO translate driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/pci/controller/pcie-rtd.c b/drivers/pci/controller/pcie-rtd.c new file mode 100644 index 000000000000..a917d7b4d6e3 --- /dev/null +++ b/drivers/pci/controller/pcie-rtd.c @@ -0,0 +1,1757 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Realtek PCIe host controller driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#include "pcie-rtd.h" + +static inline struct rtd_pcie_port *to_rtd_pcie_port(struct msi_controller *chip) +{ + return container_of(chip, struct rtd_pcie_port, msi_chip); +} + + +irqreturn_t rtd_pcie_handle_mac_msi_irq(int this_irq, void *dev_id) +{ + struct rtd_pcie_port *pp = (struct rtd_pcie_port *)dev_id; + unsigned long val; + int i, pos, irq; + irqreturn_t ret = IRQ_NONE; + + for (i = 0; i < MAX_RTK_MSI_CTRLS; i++) { + val = readl(pp->ctrl_base + PCIE_MSI_INTR0_STATUS + i * 12); + if (val) { + ret = IRQ_HANDLED; + pos = 0; + while ((pos = find_next_bit(&val, 32, pos)) != 32) { + irq = irq_find_mapping(pp->msi_domain, + i * 32 + pos); + writel(1 << pos, pp->ctrl_base + PCIE_MSI_INTR0_STATUS + i * 12); + generic_handle_irq(irq); + pos++; + } + } + } + + return ret; +} + +static void rtd_mac_msi_clear_irq(struct rtd_pcie_port *pp, int irq) +{ + unsigned int res, bit, val; + + res = (irq / 32) * 12; + bit = irq % 32; + val = readl(pp->ctrl_base + PCIE_MSI_INTR0_ENABLE + res); + val &= ~(1 << bit); + writel(val, pp->ctrl_base + PCIE_MSI_INTR0_ENABLE + res); +} + +static void clear_irq_range(struct rtd_pcie_port *pp, unsigned int irq_base, + unsigned int nvec, unsigned int pos) +{ + unsigned int i; + + for (i = 0; i < nvec; i++) { + irq_set_msi_desc_off(irq_base, i, NULL); + /* Disable corresponding interrupt on MSI controller */ + rtd_mac_msi_clear_irq(pp, pos + i); + } + + bitmap_release_region(pp->irq_bitmap, pos, order_base_2(nvec)); +} + + +static void rtd_mac_msi_set_irq(struct rtd_pcie_port *pp, int irq) +{ + unsigned int res, bit, val; + + res = (irq / 32) * 12; + bit = irq % 32; + val = readl(pp->ctrl_base + PCIE_MSI_INTR0_ENABLE + res); + val |= 1 << bit; + writel(val, pp->ctrl_base + PCIE_MSI_INTR0_ENABLE + res); +} + + + +static void rtd_mac_msi_setup_msg(struct rtd_pcie_port *pp, unsigned int irq, u32 pos) +{ + struct msi_msg msg; + u64 msi_target; + + msi_target = (u64)pp->msi_data; + msg.address_lo = lower_32_bits(msi_target); + msg.address_hi = upper_32_bits(msi_target); + + msg.data = pos; + + pci_write_msi_msg(irq, &msg); +} + +static int assign_irq(struct rtd_pcie_port *pp, int no_irqs, struct msi_desc *desc, int *pos) +{ + int irq, pos0, i; + + pos0 = bitmap_find_free_region(pp->irq_bitmap, MAX_RTK_MSI_IRQS, + order_base_2(no_irqs)); + if (pos0 < 0) + goto no_valid_irq; + + irq = irq_find_mapping(pp->msi_domain, pos0); + if (!irq) + goto no_valid_irq; + + /* + * irq_create_mapping (called from dw_pcie_host_init) pre-allocates + * descs so there is no need to allocate descs here. We can therefore + * assume that if irq_find_mapping above returns non-zero, then the + * descs are also successfully allocated. + */ + for (i = 0; i < no_irqs; i++) { + if (irq_set_msi_desc_off(irq, i, desc) != 0) { + clear_irq_range(pp, irq, i, pos0); + goto no_valid_irq; + } + /*Enable corresponding interrupt in MSI interrupt controller */ + /*unsigned int res, bit, val;*/ + rtd_mac_msi_set_irq(pp, pos0 + i); + } + + *pos = pos0; + desc->nvec_used = no_irqs; + desc->msi_attrib.multiple = order_base_2(no_irqs); + + return irq; + +no_valid_irq: + *pos = pos0; + return -ENOSPC; +} + +static int rtd_mac_msi_setup_irq(struct msi_controller *chip, + struct pci_dev *pdev, struct msi_desc *desc) +{ + int irq, pos; + struct rtd_pcie_port *pp = to_rtd_pcie_port(chip); + + if (desc->msi_attrib.is_msix) + return -EINVAL; + + irq = assign_irq(pp, 1, desc, &pos); + if (irq < 0) + return irq; + + rtd_mac_msi_setup_msg(pp, irq, pos); + + return 0; +} + + +static int rtd_mac_msi_setup_irqs(struct msi_controller *chip, + struct pci_dev *pdev, int nvec, int type) +{ + int irq, pos; + struct msi_desc *desc; + struct rtd_pcie_port *pp = to_rtd_pcie_port(chip); + + /* MSI-X interrupts are not supported */ + if (type == PCI_CAP_ID_MSIX) + return -EINVAL; + + WARN_ON(!list_is_singular(&pdev->dev.msi_list)); + desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list); + + irq = assign_irq(pp, nvec, desc, &pos); + if (irq < 0) + return irq; + + rtd_mac_msi_setup_msg(pp, irq, pos); + + return 0; +} + + +static void rtd_mac_msi_teardown_irq(struct msi_controller *chip, + unsigned int irq) +{ + struct irq_data *data = irq_get_irq_data(irq); + struct rtd_pcie_port *pp = to_rtd_pcie_port(chip); + + clear_irq_range(pp, irq, 1, data->hwirq); +} + +static struct irq_chip rtd_msi_irq_chip = { + .name = "RTK-PCIE-MSI", + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, +}; + + +static int rtd_msi_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &rtd_msi_irq_chip, handle_simple_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops rtd_pcie_msi_domain_ops = { + .map = rtd_msi_map, +}; + + +static int rtd_pcie_mac_msi_init(struct rtd_pcie_port *pp) +{ + int ret; + int i; + u64 msi_target; + + raw_spin_lock_init(&pp->lock); + + pp->msi_chip.dev = pp->dev; + pp->msi_chip.setup_irqs = rtd_mac_msi_setup_irqs; + pp->msi_chip.setup_irq = rtd_mac_msi_setup_irq; + pp->msi_chip.teardown_irq = rtd_mac_msi_teardown_irq; + + pp->msi_irq = irq_of_parse_and_map(pp->dev->of_node, 0); + if (pp->msi_irq < 0) { + dev_err(pp->dev, "parse irq failed\n"); + return -EINVAL; + } + ret = request_irq(pp->msi_irq, rtd_pcie_handle_mac_msi_irq, IRQF_SHARED, pp->ops->name, pp); + if (ret) + dev_err(pp->dev, "request irq failed\n"); + + pp->msi_domain = irq_domain_add_linear(NULL, MAX_RTK_MSI_IRQS, &rtd_pcie_msi_domain_ops, &pp->msi_chip); + if (!pp->msi_domain) { + dev_err(pp->dev, "irq domain init failed\n"); + return -ENXIO; + } + + for (i = 0; i < MAX_RTK_MSI_IRQS; i++) + irq_create_mapping(pp->msi_domain, i); + + pp->msi_page = alloc_page(GFP_KERNEL); + pp->msi_data = dma_map_page(pp->dev, pp->msi_page, 0, PAGE_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(pp->dev, pp->msi_data)) { + dev_err(pp->dev, "Failed to map MSI data\n"); + __free_page(pp->msi_page); + pp->msi_page = NULL; + return -ENOMEM; + } + msi_target = (u64)pp->msi_data; + writel(upper_32_bits(msi_target), pp->ctrl_base + PCIE_MSI_ADDR_HI); + writel(lower_32_bits(msi_target), pp->ctrl_base + PCIE_MSI_ADDR_LO); + + return 0; + +} + + + + +irqreturn_t rtd_pcie_handle_wrapper_msi_irq(int this_irq, void *dev_id) +{ + int pos, irq; + struct rtd_pcie_port *pp = (struct rtd_pcie_port *)dev_id; + + if (readl(pp->ctrl_base + PCIE_MSI_DATA) & 0x10000) + writel(0x10000, pp->ctrl_base + PCIE_MSI_DATA); + else + return IRQ_HANDLED; + + pos = 0; + irq = irq_find_mapping(pp->msi_domain, pos); + if (irq != 0) { + generic_handle_irq(irq); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int rtd_msi_alloc(struct rtd_pcie_port *pp) +{ + int msi; + unsigned long flags; + + raw_spin_lock_irqsave(&pp->lock, flags); + + msi = find_first_zero_bit(pp->irq_bitmap, MAX_RTK_MSI_IRQS); + if (msi < MAX_RTK_MSI_IRQS) + set_bit(msi, pp->irq_bitmap); + else + msi = -ENOSPC; + raw_spin_unlock_irqrestore(&pp->lock, flags); + + return msi; +} + +static void rtd_msi_free(struct rtd_pcie_port *pp, unsigned long irq) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pp->lock, flags); + + if (!test_bit(irq, pp->irq_bitmap)) + dev_err(pp->dev, "trying to free unused MSI#%lu\n", irq); + else + clear_bit(irq, pp->irq_bitmap); + + raw_spin_unlock_irqrestore(&pp->lock, flags); +} + +static int rtd_msi_setup_irq(struct msi_controller *chip, + struct pci_dev *pdev, struct msi_desc *desc) +{ + struct msi_msg msg; + unsigned int irq; + int hwirq; + struct rtd_pcie_port *pp = to_rtd_pcie_port(chip); + + hwirq = rtd_msi_alloc(pp); + if (hwirq < 0) + return hwirq; + + irq = irq_find_mapping(pp->msi_domain, hwirq); + if (!irq) { + dev_err(pp->dev, "irq mapping error\n"); + rtd_msi_free(pp, hwirq); + return -EINVAL; + } + + irq_set_msi_desc(irq, desc); + msg.address_lo = pp->msi_data; + msg.address_hi = 0x0; + msg.data = 1 << hwirq; + + pci_write_msi_msg(irq, &msg); + + return 0; +} + +static int rtd_msi_setup_irqs(struct msi_controller *chip, + struct pci_dev *pdev, int nvec, int type) +{ + struct msi_desc *desc; + struct msi_msg msg; + unsigned int irq; + int hwirq; + int i; + struct rtd_pcie_port *pp = to_rtd_pcie_port(chip); + + /* MSI-X interrupts are not supported */ + if (type == PCI_CAP_ID_MSIX) + return -EINVAL; + + WARN_ON(!list_is_singular(&pdev->dev.msi_list)); + desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list); + + hwirq = bitmap_find_free_region(pp->irq_bitmap, MAX_RTK_MSI_IRQS, + order_base_2(nvec)); + if (hwirq < 0) + return -ENOSPC; + + irq = irq_find_mapping(pp->msi_domain, hwirq); + if (!irq) + return -ENOSPC; + + for (i = 0; i < nvec; i++) { + if (irq_set_msi_desc_off(irq, i, desc)) + return -EINVAL; + } + + desc->nvec_used = nvec; + desc->msi_attrib.multiple = order_base_2(nvec); + + msg.address_lo = pp->msi_data; + msg.address_hi = 0x0; + msg.data = 0x0; + + pci_write_msi_msg(irq, &msg); + + return 0; +} + + +static void rtd_msi_teardown_irq(struct msi_controller *chip, + unsigned int irq) +{ + struct irq_data *d = irq_get_irq_data(irq); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct rtd_pcie_port *pp = to_rtd_pcie_port(chip); + + irq_dispose_mapping(irq); + rtd_msi_free(pp, hwirq); +} + + +static int rtd_pcie_wrapper_msi_init(struct rtd_pcie_port *pp) +{ + int ret; + int i; + + raw_spin_lock_init(&pp->lock); + + writel(0x1C00, pp->ctrl_base + PCIE_INT_CTR); + + pp->msi_chip.dev = pp->dev; + pp->msi_chip.setup_irqs = rtd_msi_setup_irqs; + pp->msi_chip.setup_irq = rtd_msi_setup_irq; + pp->msi_chip.teardown_irq = rtd_msi_teardown_irq; + + pp->msi_irq = irq_of_parse_and_map(pp->dev->of_node, 0); + if (pp->msi_irq < 0) { + dev_err(pp->dev, "parse irq failed\n"); + return -EINVAL; + } + ret = request_irq(pp->msi_irq, rtd_pcie_handle_wrapper_msi_irq, IRQF_SHARED, pp->ops->name, pp); + if (ret) + dev_err(pp->dev, "request irq failed\n"); + pp->msi_domain = irq_domain_add_linear(NULL, MAX_RTK_MSI_IRQS, &rtd_pcie_msi_domain_ops, &pp->msi_chip); + if (!pp->msi_domain) { + dev_err(pp->dev, "irq domain init failed\n"); + return -ENXIO; + } + + for (i = 0; i < MAX_RTK_MSI_IRQS; i++) + irq_create_mapping(pp->msi_domain, i); + + pp->msi_data_virt = dma_alloc_coherent(pp->dev, PAGE_SIZE, &pp->msi_data, GFP_KERNEL); + + writel(pp->msi_data, pp->ctrl_base + PCIE_MSI_TRAN); + *pp->msi_data_virt = 0x0; + + return 0; +} + +static unsigned long pci_byte_mask(unsigned long addr, unsigned char size) +{ + unsigned char offset = (addr & 0x03); + + switch (size) { + case 0x01: + return 0x1 << offset; + case 0x02: + if (offset <= 2) + return 0x3 << offset; + break; + + case 0x03: + if (offset <= 1) + return 0x7 << offset; + break; + + case 0x04: + if (offset == 0) + return 0xF; + break; + + default: + break; + } + return 0; +} + +static unsigned long pci_bit_mask(unsigned char byte_mask) +{ + int i; + unsigned long mask = 0; + + for (i = 0; i < 4; i++) { + if ((byte_mask >> i) & 0x1) + mask |= (0xFF << (i << 3)); + } + + return mask; +} + +static unsigned long pci_bit_shift(unsigned long addr) +{ + return ((addr & 0x3) << 3); +} + + +static int indirect_cfg_read(struct rtd_pcie_port *pp, unsigned long addr, u32 *pdata, + unsigned char size) +{ + unsigned long status; + unsigned char mask; + int try_count = 20000; + + if (ADDR_TO_DEVICE_NO(addr) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + mask = pci_byte_mask(addr, size); + + if (!mask) + return PCIBIOS_SET_FAILED; + + writel(0x10, pp->ctrl_base + PCIE_INDIR_CTR); + writel(CFG_ST_ERROR|CFG_ST_DONE, pp->ctrl_base + PCIE_CFG_ST); + writel((addr & ~0x3), pp->ctrl_base + PCIE_CFG_ADDR); + writel(BYTE_CNT(mask) | BYTE_EN | WRRD_EN(0), pp->ctrl_base + PCIE_CFG_EN); + writel(GO_CT, pp->ctrl_base + PCIE_CFG_CT); + + do { + status = readl(pp->ctrl_base + PCIE_CFG_ST); + udelay(50); + } while (!(status & CFG_ST_DONE) && try_count--); + + if (try_count < 0) { + dev_err(pp->dev, "Read config data (%p) failed - timeout\n", + (void *) addr); + goto error_occur; + } + + if (readl(pp->ctrl_base + PCIE_CFG_ST) & CFG_ST_ERROR) { + dev_err(pp->dev, "Read config data failed - error\n"); + goto error_occur; + } + + writel(CFG_ST_ERROR|CFG_ST_DONE, pp->ctrl_base + PCIE_CFG_ST); + *pdata = (readl(pp->ctrl_base + PCIE_CFG_RDATA) & pci_bit_mask(mask)) + >> pci_bit_shift(addr); + return PCIBIOS_SUCCESSFUL; + +error_occur: + writel(CFG_ST_ERROR|CFG_ST_DONE, pp->ctrl_base + PCIE_CFG_ST); + return PCIBIOS_SET_FAILED; +} + +static unsigned long pci_address_conversion(struct pci_bus *bus, + unsigned int devfn, int reg) +{ + int busno = bus->number; + int dev = PCI_SLOT(devfn); + int func = PCI_FUNC(devfn); + + return (busno << 24) | (dev << 19) | (func << 16) | reg; +} + + +static int rtd_pcie_rd_conf(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *pval) +{ + unsigned long address; + int ret = PCIBIOS_DEVICE_NOT_FOUND; + u32 val = 0; + u8 retry = 5; + struct rtd_pcie_port *pp = bus->sysdata; + +again: + /*clear RCPL_ST*/ + writel(0x1f, pp->ctrl_base + PCIE_RCPL_ST); + + if (PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) == 0) { + address = pci_address_conversion(bus, devfn, reg); + ret = indirect_cfg_read(pp, address, pval, size); + } + + val = readl(pp->ctrl_base + PCIE_RCPL_ST); + writel(0x1f, pp->ctrl_base + PCIE_RCPL_ST); + if ((val & 0x1f) && retry) { + /*workaround*/ + if ((val & BIT(4)) && (!(val & GENMASK(7, 5))) && (*pval == 0xFFFF)) + goto out; + + retry--; + if (((val & GENMASK(7, 5)) >> 5) == 0x1) + dev_dbg(&bus->dev, "Unsupport Request ST:0x%x\n", val); + else + dev_err(&bus->dev, "tlp error occur = 0x%x\n", val); + + goto again; + } + + //dev_info(&bus->dev, "rtd_pcie3_13xx_rd_conf reg = 0x%x, devfun:%d, size=%d, *pval = 0x%x\n", + // reg, devfn, size, *pval); + +out: + return ret; +} + +static int indirect_cfg_write(struct rtd_pcie_port *pp, + unsigned long addr, unsigned long data, + unsigned char size) +{ + unsigned long status; + unsigned char mask; + int try_count = 1000; + + if (ADDR_TO_DEVICE_NO(addr) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + mask = pci_byte_mask(addr, size); + + if (!mask) + return PCIBIOS_SET_FAILED; + + data = (data << pci_bit_shift(addr)) & pci_bit_mask(mask); + + writel(0x12, pp->ctrl_base + PCIE_INDIR_CTR); + writel(CFG_ST_ERROR|CFG_ST_DONE, pp->ctrl_base + PCIE_CFG_ST); + writel(addr & ~0x3, pp->ctrl_base + PCIE_CFG_ADDR); + writel(data, pp->ctrl_base + PCIE_CFG_WDATA); + + if (size == 4) + writel(0x1, pp->ctrl_base + PCIE_CFG_EN); + else + writel(BYTE_CNT(mask) | BYTE_EN | WRRD_EN(1), pp->ctrl_base + PCIE_CFG_EN); + + writel(GO_CT, pp->ctrl_base + PCIE_CFG_CT); + + do { + status = readl(pp->ctrl_base + PCIE_CFG_ST); + udelay(50); + } while (!(status & CFG_ST_DONE) && try_count--); + + if (try_count < 0) { + dev_err(pp->dev, "Write config data (%p) failed - timeout\n", + (void *) addr); + goto error_occur; + } + + if (readl(pp->ctrl_base + PCIE_CFG_ST) & CFG_ST_ERROR) { + dev_err(pp->dev, "Write config data (%p) failed - error\n", + (void *) addr); + goto error_occur; + } + + writel(CFG_ST_ERROR|CFG_ST_DONE, pp->ctrl_base + PCIE_CFG_ST); + + return PCIBIOS_SUCCESSFUL; + +error_occur: + + writel(CFG_ST_ERROR|CFG_ST_DONE, pp->ctrl_base + PCIE_CFG_ST); + + return PCIBIOS_SET_FAILED; +} + + +static int rtd_pcie_wr_conf(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + unsigned long address; + int ret = PCIBIOS_DEVICE_NOT_FOUND; + struct rtd_pcie_port *pp = bus->sysdata; + + //dev_info(&bus->dev, "rtd_pcie3_13xx_wr_conf reg = 0x%x, val = 0x%x\n", + // reg, val); + + if (PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) == 0) { + address = pci_address_conversion(bus, devfn, reg); + ret = indirect_cfg_write(pp, address, val, size); + } + + return ret; +} + +static struct pci_ops rtd_pcie_ops = { + .read = rtd_pcie_rd_conf, + .write = rtd_pcie_wr_conf, +}; + +static int pcie_link_init(struct rtd_pcie_port *pp) +{ + int ret = 0; + int timeout; + bool pci_link_detected; + u32 tmp; + + ret = gpiod_direction_output(pp->perst_gpio, 0); + if (ret) + dev_err(pp->dev, "cannot set gpio\n"); + + writel(0x00140010, pp->ctrl_base + PCIE_SYS_CTR); + if (pp->speed_mode == 0) { /* force gen1*/ + tmp = readl(pp->ctrl_base + LINK_CONTROL2_LINK_STATUS2_REG); + writel(tmp | 0x1, pp->ctrl_base + LINK_CONTROL2_LINK_STATUS2_REG); + } + + /*phy mdio setting*/ + phy_init(pp->pcie_phy); + + mdelay(100); + + ret = gpiod_direction_output(pp->perst_gpio, 1); + if (ret) + dev_err(pp->dev, "cannot set gpio\n"); + + writel(0x001E0022, pp->ctrl_base + PCIE_SYS_CTR); + writel(0x00010120, pp->ctrl_base + PORT_LINK_CTRL_OFF); + +#ifdef MY_DEF_HERE + timeout = 1000; +#else /* MY_DEF_HERE */ + timeout = PCIE_CONNECT_TIMEOUT; +#endif /* MY_DEF_HERE */ + do { + pci_link_detected = readl(pp->ctrl_base + PCIE_MAC_ST) & 0x800; + if (pci_link_detected) { +#ifdef MY_DEF_HERE + if (1000 - timeout > PCIE_CONNECT_TIMEOUT) { + dev_err(pp->dev, "error: link up with device timeout %d ms exceed default %d", 1000 - timeout, PCIE_CONNECT_TIMEOUT); + } else { + dev_info(pp->dev, "link up with device"); + } + + // Follow PCIe spec: software must wait for 100 ms after the Data Link Layer Link Active bit reads 1b before initiating a configuration access to the hot added device. + mdelay(100); + +#else /* MY_DEF_HERE */ + dev_info(pp->dev, "link up with device"); +#endif /* MY_DEF_HERE */ + break; + } + mdelay(1); + timeout--; + } while (timeout > 0); + + if (timeout == 0) { + if (!pp->debug_mode) { + ret = pp->ops->deinit(pp); + if (ret) { + dev_err(pp->dev, "deinit failed.\n"); + return ret; + } + } + devm_gpiod_put(pp->dev, pp->perst_gpio); + dev_info(pp->dev, "link down with device"); + return -ENODEV; + } + + writel(0x7, pp->ctrl_base + TYPE1_STATUS_COMMAND_REG); + + ret = pp->ops->hwinit(pp); + if (ret) { + dev_err(pp->dev, "hw init failed.\n"); + return ret; + } + + /*pcie timeout 500us*/ + writel(0xF42401, pp->ctrl_base + PCIE_DIR_EN); + + /* set limit and base register */ + writel(0x0000FFF0, pp->ctrl_base + MEM_LIMIT_MEM_BASE_REG); + writel(0x0000FFF0, pp->ctrl_base + PREF_MEM_LIMIT_PREF_MEM_BASE_REG); + + return 0; +} + +int rtd_pci_get_host_bridge_resources(struct rtd_pcie_port *pp, + unsigned char busno, unsigned char bus_max, + struct list_head *resources, resource_size_t *io_base) +{ + struct device_node *dev_node = pp->dev->of_node; + struct resource *res, tmp_res; + struct resource *bus_range; + struct of_pci_range range; + struct of_pci_range_parser parser; + char range_type[4]; + int err; + int rlen; + + if (io_base) + *io_base = (resource_size_t)OF_BAD_ADDR; + + bus_range = devm_kzalloc(pp->dev, sizeof(*bus_range), GFP_KERNEL); + if (!bus_range) + return -ENOMEM; + + dev_info(pp->dev, "host bridge %pOF ranges:\n", dev_node); + + err = of_pci_parse_bus_range(dev_node, bus_range); + if (err) { + bus_range->start = busno; + bus_range->end = bus_max; + bus_range->flags = IORESOURCE_BUS; + dev_info(pp->dev, " No bus range found for %pOF, using %pR\n", + dev_node, bus_range); + } else { + if (bus_range->end > bus_range->start + bus_max) + bus_range->end = bus_range->start + bus_max; + } + pci_add_resource(resources, bus_range); + + /* Check for ranges property */ + err = of_pci_range_parser_init(&parser, dev_node); + if (err) + goto failed; + + if (pp->workaround) { + parser.range = of_get_property(dev_node, "workaround-ranges", &rlen); + if (parser.range == NULL) + return -ENOENT; + + parser.end = parser.range + rlen / sizeof(__be32); + } + + dev_dbg(pp->dev, "Parsing ranges property...\n"); + for_each_of_pci_range(&parser, &range) { + /* Read next ranges element */ + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) + snprintf(range_type, 4, " IO"); + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) + snprintf(range_type, 4, "MEM"); + else + snprintf(range_type, 4, "err"); + dev_info(pp->dev, " %s %#010llx..%#010llx -> %#010llx\n", + range_type, range.cpu_addr, + range.cpu_addr + range.size - 1, range.pci_addr); + + /* + * If we failed translation or got a zero-sized region + * then skip this range + */ + if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) + continue; + + err = of_pci_range_to_resource(&range, dev_node, &tmp_res); + if (err) + continue; + + res = devm_kmemdup(pp->dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); + if (!res) { + err = -ENOMEM; + goto failed; + } + + if (resource_type(res) == IORESOURCE_IO) { + if (!io_base) { + dev_err(pp->dev, "I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n", + dev_node); + err = -EINVAL; + goto failed; + } + if (*io_base != (resource_size_t)OF_BAD_ADDR) + dev_warn(pp->dev, "More than one I/O resource converted for %pOF. CPU base address for old range lost!\n", + dev_node); + *io_base = range.cpu_addr; + } + + pci_add_resource_offset(resources, res, res->start - range.pci_addr); + } + + return 0; + +failed: + pci_free_resource_list(resources); + return err; +} + + +static int rtd_pcie_probe(struct platform_device *pdev) +{ + struct rtd_pcie_port *pp; + struct device *dev = &pdev->dev; + int ret = 0; + struct pci_host_bridge *bridge; + struct pci_bus *child; + static struct pci_bus *bus; + + resource_size_t iobase = 0; + + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + pp->dev = dev; + pp->ops = (struct rtd_pcie_ops *)of_device_get_match_data(dev); + + dev_info(dev, "host driver initial begin.\n"); + + ret = pp->ops->get_resource(pp); + if (ret) { + dev_err(dev, "get resource failed.\n"); + goto failed; + } + ret = pp->ops->init(pp); + if (ret) { + dev_err(dev, "init failed.\n"); + goto failed; + } + + ret = pcie_link_init(pp); + if (ret) { + dev_err(dev, "link init failed.\n"); + goto failed; + } + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = pp->ops->msi_init(pp); + if (ret) { + dev_err(dev, "msi init failed.\n"); + goto failed; + } + } + + bridge = pci_alloc_host_bridge(0); + if (!bridge) { + dev_err(dev, "alloc host bridge failed.\n"); + ret = -ENOMEM; + goto failed; + } + ret = rtd_pci_get_host_bridge_resources(pp, + 0x1, 0xff, &bridge->windows, &iobase); + if (ret) { + dev_err(dev, "get host bridge resources failed.\n"); + goto failed; + } + ret = devm_request_pci_bus_resources(pp->dev, &bridge->windows); + if (ret) { + dev_err(dev, "cannot request pci bus resources\n"); + goto failed; + } + bridge->dev.parent = &pdev->dev; + bridge->ops = &rtd_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + bridge->sysdata = pp; + if (IS_ENABLED(CONFIG_PCI_MSI)) + bridge->msi = &pp->msi_chip; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret) { + dev_err(pp->dev, "scan root bus failed\n"); + goto failed; + } + bus = bridge->bus; + +#if defined(MY_DEF_HERE) && defined(MY_ABC_HERE) + if (list_empty(&bus->devices) && syno_is_hw_version(HW_DS423)) { + dev_err(dev, "scan child pci device failed\n"); + ret = pcie_link_init(pp); + if (ret) { + dev_err(dev, "link init failed.\n"); + goto failed; + } + pci_scan_child_bus(bridge->bus); + } +#endif /* defined(MY_DEF_HERE) && defined(MY_ABC_HERE) */ + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + pci_bus_add_devices(bus); + + platform_set_drvdata(pdev, pp); + dev_info(pp->dev, "host driver initial done.\n"); + + return ret; +failed: + dev_info(pp->dev, "host driver initial failed.\n"); + return ret; +} + +static int rtd13xx_pcie0_get_res(struct rtd_pcie_port *pp) +{ + struct device_node *syscon_np; + const u32 *prop; + int size = 0; + + pp->ctrl_base = of_iomap(pp->dev->of_node, 0); + if (!pp->ctrl_base) { + dev_err(pp->dev, "failed to get ctrl address\n"); + return -EINVAL; + } + + syscon_np = of_parse_phandle(pp->dev->of_node, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + pp->pinmux_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pp->pinmux_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + prop = of_get_property(pp->dev->of_node, "speed-mode", &size); + if (prop) { + pp->speed_mode = of_read_number(prop, 1); + if (pp->speed_mode == 0) + dev_info(pp->dev, "Speed Mode: GEN1\n"); + else if (pp->speed_mode == 1) + dev_info(pp->dev, "Speed Mode: GEN2\n"); + } else { + pp->speed_mode = 0; + } + + prop = of_get_property(pp->dev->of_node, "debug-mode", &size); + if (prop) { + pp->debug_mode = of_read_number(prop, 1); + if (pp->debug_mode == 0) + dev_info(pp->dev, "PCIE Debug Mode off\n"); + else if (pp->debug_mode == 1) + dev_info(pp->dev, "PCIE Debug Mode on\n"); + } else { + pp->debug_mode = 0; + } + + pp->perst_gpio = devm_gpiod_get(pp->dev, "perst", GPIOD_OUT_LOW); + if (IS_ERR(pp->perst_gpio)) { + dev_err(pp->dev, "PERST gpio missing or invalid\n"); + return -EINVAL; + } + + pp->pcie_clk = devm_clk_get(pp->dev, NULL); + if (IS_ERR(pp->pcie_clk)) { + dev_err(pp->dev, "pcie clock source missing or invalid\n"); + return PTR_ERR(pp->pcie_clk); + } + + pp->rst_stitch = devm_reset_control_get(pp->dev, "stitch"); + if (pp->rst_stitch == NULL) { + dev_err(pp->dev, "stitch source missing or invalid\n"); + return -EINVAL; + } + + pp->rst = devm_reset_control_get(pp->dev, "rstn"); + if (pp->rst == NULL) { + dev_err(pp->dev, "rstn_pcie3 source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_core = devm_reset_control_get(pp->dev, "core"); + if (pp->rst_core == NULL) { + dev_err(pp->dev, "core source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_power = devm_reset_control_get(pp->dev, "power"); + if (pp->rst_power == NULL) { + dev_err(pp->dev, "power source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_nonstitch = devm_reset_control_get(pp->dev, "nonstitch"); + if (pp->rst_nonstitch == NULL) { + dev_err(pp->dev, "nonstitch source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_sgmii_mdio = devm_reset_control_get(pp->dev, "sgmii_mdio"); + if (pp->rst_sgmii_mdio == NULL) { + dev_err(pp->dev, "phy_mdio source missing. or invalid\n"); + return -EINVAL; + } + + pp->pcie_phy = devm_of_phy_get(pp->dev, pp->dev->of_node, NULL); + if (IS_ERR(pp->pcie_phy)) { + dev_err(pp->dev, "pcie phy missing or invalid\n"); + return -EINVAL; + } + + return 0; +} + + +static int rtd13xx_pcie0_init(struct rtd_pcie_port *pp) +{ + u32 tmp; + int ret = 0; + + regmap_read(pp->pinmux_base, ISO_POWERCUT_ETN, &tmp); + tmp &= ~PCIE0_USB_SEL_OFFSET; + regmap_write(pp->pinmux_base, ISO_POWERCUT_ETN, tmp); + reset_control_deassert(pp->rst_stitch); + reset_control_deassert(pp->rst); + reset_control_deassert(pp->rst_core); + reset_control_deassert(pp->rst_power); + reset_control_deassert(pp->rst_nonstitch); + reset_control_deassert(pp->rst_sgmii_mdio); + phy_power_on(pp->pcie_phy); + + ret = clk_prepare_enable(pp->pcie_clk); + + if (ret) { + dev_err(pp->dev, "unable to enable pcie clock\n"); + clk_disable_unprepare(pp->pcie_clk); + return -EINVAL; + } + + return 0; +} + +static int rtd13xx_pcie0_deinit(struct rtd_pcie_port *pp) +{ + clk_disable_unprepare(pp->pcie_clk); + reset_control_assert(pp->rst_stitch); + reset_control_assert(pp->rst); + reset_control_assert(pp->rst_core); + reset_control_assert(pp->rst_power); + reset_control_assert(pp->rst_nonstitch); + reset_control_assert(pp->rst_sgmii_mdio); + phy_power_off(pp->pcie_phy); + + return 0; +} + +static int rtd13xx_pcie0_hw_init(struct rtd_pcie_port *pp) +{ + /* #Base 0 */ + writel(0x98062000, pp->ctrl_base + PCIE_BASE_0); + + /* #Mask 0 */ + writel(0xFFF00000, pp->ctrl_base + PCIE_MASK_0); + + /* #translate for MMIO R/W */ + writel(0x98000000, pp->ctrl_base + PCIE_TRANS_0); + + writel(0x0, pp->ctrl_base + PCIE_SCTCH); + + return 0; +} + +static int rtd13xx_pcie1_get_res(struct rtd_pcie_port *pp) +{ + struct device_node *syscon_np; + const u32 *prop; + int size = 0; + + pp->ctrl_base = of_iomap(pp->dev->of_node, 0); + if (!pp->ctrl_base) { + dev_err(pp->dev, "failed to get ctrl address\n"); + return -EINVAL; + } + + syscon_np = of_parse_phandle(pp->dev->of_node, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + pp->main2_misc_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pp->main2_misc_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + prop = of_get_property(pp->dev->of_node, "speed-mode", &size); + if (prop) { + pp->speed_mode = of_read_number(prop, 1); + if (pp->speed_mode == 0) + dev_info(pp->dev, "Speed Mode: GEN1\n"); + else if (pp->speed_mode == 1) + dev_info(pp->dev, "Speed Mode: GEN2\n"); + } else { + pp->speed_mode = 0; + } + + prop = of_get_property(pp->dev->of_node, "debug-mode", &size); + if (prop) { + pp->debug_mode = of_read_number(prop, 1); + if (pp->debug_mode == 0) + dev_info(pp->dev, "PCIE Debug Mode off\n"); + else if (pp->debug_mode == 1) + dev_info(pp->dev, "PCIE Debug Mode on\n"); + } else { + pp->debug_mode = 0; + } + + prop = of_get_property(pp->dev->of_node, "workaround", &size); + if (prop) { + pp->workaround = of_read_number(prop, 1); + if (pp->workaround == 1) + dev_info(pp->dev, "PCIE workaround on\n"); + } else { + pp->workaround = 0; + } + + pp->perst_gpio = devm_gpiod_get(pp->dev, "perst", GPIOD_OUT_LOW); + if (IS_ERR(pp->perst_gpio)) { + dev_err(pp->dev, "PERST gpio missing or invalid\n"); + return -EINVAL; + } + + pp->pcie_clk = devm_clk_get(pp->dev, NULL); + if (IS_ERR(pp->pcie_clk)) { + dev_err(pp->dev, "pcie clock source missing or invalid\n"); + return PTR_ERR(pp->pcie_clk); + } + + pp->rst_stitch = devm_reset_control_get(pp->dev, "stitch"); + if (pp->rst_stitch == NULL) { + dev_err(pp->dev, "stitch source missing or invalid\n"); + return -EINVAL; + } + + pp->rst = devm_reset_control_get(pp->dev, "rstn"); + if (pp->rst == NULL) { + dev_err(pp->dev, "rstn_pcie3 source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_core = devm_reset_control_get(pp->dev, "core"); + if (pp->rst_core == NULL) { + dev_err(pp->dev, "core source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_power = devm_reset_control_get(pp->dev, "power"); + if (pp->rst_power == NULL) { + dev_err(pp->dev, "power source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_nonstitch = devm_reset_control_get(pp->dev, "nonstitch"); + if (pp->rst_nonstitch == NULL) { + dev_err(pp->dev, "nonstitch source missing or invalid\n"); + return -EINVAL; + } + + pp->pcie_phy = devm_of_phy_get(pp->dev, pp->dev->of_node, NULL); + if (IS_ERR(pp->pcie_phy)) { + dev_err(pp->dev, "pcie phy missing or invalid\n"); + return -EINVAL; + } + + return 0; +} + +static int rtd13xx_pcie1_init(struct rtd_pcie_port *pp) +{ + u32 tmp; + int ret = 0; + + regmap_read(pp->main2_misc_base, MISC_PHY_CTRL, &tmp); + tmp &= ~PCIE1_SATA_SEL_OFFSET; + regmap_write(pp->main2_misc_base, MISC_PHY_CTRL, tmp); + reset_control_deassert(pp->rst_stitch); + reset_control_deassert(pp->rst); + reset_control_deassert(pp->rst_core); + reset_control_deassert(pp->rst_power); + reset_control_deassert(pp->rst_nonstitch); + phy_power_on(pp->pcie_phy); + + ret = clk_prepare_enable(pp->pcie_clk); + + if (ret) { + dev_err(pp->dev, "unable to enable pcie clock\n"); + clk_disable_unprepare(pp->pcie_clk); + return -EINVAL; + } + + return 0; +} + +static int rtd13xx_pcie1_deinit(struct rtd_pcie_port *pp) +{ + clk_disable_unprepare(pp->pcie_clk); + reset_control_assert(pp->rst_stitch); + reset_control_assert(pp->rst); + reset_control_assert(pp->rst_core); + reset_control_assert(pp->rst_power); + reset_control_assert(pp->rst_nonstitch); + phy_power_off(pp->pcie_phy); + + return 0; +} + +static int rtd13xx_pcie1_hw_init(struct rtd_pcie_port *pp) +{ + if (pp->workaround) { + /* #Base 0 */ + writel(0x980B0000, pp->ctrl_base + PCIE_BASE_0); + + /* #Mask 0 */ + writel(0xFFFF0000, pp->ctrl_base + PCIE_MASK_0); + + /* #translate for MMIO R/W */ + writel(0xC0000000, pp->ctrl_base + PCIE_TRANS_0); + } else { + /* #Base 0 */ + writel(0x980A2000, pp->ctrl_base + PCIE_BASE_0); + + /* #Mask 0 */ + writel(0xFFF00000, pp->ctrl_base + PCIE_MASK_0); + + /* #translate for MMIO R/W */ + writel(0x98000000, pp->ctrl_base + PCIE_TRANS_0); + } + + writel(0x0, pp->ctrl_base + PCIE_SCTCH); + + return 0; +} + +static int rtd13xx_pcie2_get_res(struct rtd_pcie_port *pp) +{ + struct device_node *syscon_np; + const u32 *prop; + int size = 0; + + pp->ctrl_base = of_iomap(pp->dev->of_node, 0); + if (!pp->ctrl_base) { + dev_err(pp->dev, "failed to get ctrl address\n"); + return -EINVAL; + } + + syscon_np = of_parse_phandle(pp->dev->of_node, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + pp->main2_misc_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pp->main2_misc_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + prop = of_get_property(pp->dev->of_node, "speed-mode", &size); + if (prop) { + pp->speed_mode = of_read_number(prop, 1); + if (pp->speed_mode == 0) + dev_info(pp->dev, "Speed Mode: GEN1\n"); + else if (pp->speed_mode == 1) + dev_info(pp->dev, "Speed Mode: GEN2\n"); + } else { + pp->speed_mode = 0; + } + + prop = of_get_property(pp->dev->of_node, "debug-mode", &size); + if (prop) { + pp->debug_mode = of_read_number(prop, 1); + if (pp->debug_mode == 0) + dev_info(pp->dev, "PCIE Debug Mode off\n"); + else if (pp->debug_mode == 1) + dev_info(pp->dev, "PCIE Debug Mode on\n"); + } else { + pp->debug_mode = 0; + } + + prop = of_get_property(pp->dev->of_node, "workaround", &size); + if (prop) { + pp->workaround = of_read_number(prop, 1); + if (pp->workaround == 1) + dev_info(pp->dev, "PCIE workaround on\n"); + } else { + pp->workaround = 0; + } + + pp->perst_gpio = devm_gpiod_get(pp->dev, "perst", GPIOD_OUT_LOW); + if (IS_ERR(pp->perst_gpio)) { + dev_err(pp->dev, "PERST gpio missing or invalid\n"); + return -EINVAL; + } + + pp->pcie_clk = devm_clk_get(pp->dev, NULL); + if (IS_ERR(pp->pcie_clk)) { + dev_err(pp->dev, "pcie clock source missing or invalid\n"); + return PTR_ERR(pp->pcie_clk); + } + + pp->rst_stitch = devm_reset_control_get(pp->dev, "stitch"); + if (pp->rst_stitch == NULL) { + dev_err(pp->dev, "stitch source missing or invalid\n"); + return -EINVAL; + } + + pp->rst = devm_reset_control_get(pp->dev, "rstn"); + if (pp->rst == NULL) { + dev_err(pp->dev, "rstn_pcie3 source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_core = devm_reset_control_get(pp->dev, "core"); + if (pp->rst_core == NULL) { + dev_err(pp->dev, "core source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_power = devm_reset_control_get(pp->dev, "power"); + if (pp->rst_power == NULL) { + dev_err(pp->dev, "power source missing or invalid\n"); + return -EINVAL; + } + + pp->rst_nonstitch = devm_reset_control_get(pp->dev, "nonstitch"); + if (pp->rst_nonstitch == NULL) { + dev_err(pp->dev, "nonstitch source missing or invalid\n"); + return -EINVAL; + } + + pp->pcie_phy = devm_of_phy_get(pp->dev, pp->dev->of_node, NULL); + if (IS_ERR(pp->pcie_phy)) { + dev_err(pp->dev, "pcie phy missing or invalid\n"); + return -EINVAL; + } + + return 0; +} + +static int rtd13xx_pcie2_init(struct rtd_pcie_port *pp) +{ + u32 tmp; + int ret = 0; + + regmap_read(pp->main2_misc_base, MISC_PHY_CTRL, &tmp); + tmp &= ~PCIE2_SATA_SEL_OFFSET; + regmap_write(pp->main2_misc_base, MISC_PHY_CTRL, tmp); + reset_control_deassert(pp->rst_stitch); + reset_control_deassert(pp->rst); + reset_control_deassert(pp->rst_core); + reset_control_deassert(pp->rst_power); + reset_control_deassert(pp->rst_nonstitch); + phy_power_on(pp->pcie_phy); + + ret = clk_prepare_enable(pp->pcie_clk); + + if (ret) { + dev_err(pp->dev, "unable to enable pcie clock\n"); + clk_disable_unprepare(pp->pcie_clk); + return -EINVAL; + } + + return 0; +} + +static int rtd13xx_pcie2_deinit(struct rtd_pcie_port *pp) +{ + clk_disable_unprepare(pp->pcie_clk); + reset_control_assert(pp->rst_stitch); + reset_control_assert(pp->rst); + reset_control_assert(pp->rst_core); + reset_control_assert(pp->rst_power); + reset_control_assert(pp->rst_nonstitch); + phy_power_off(pp->pcie_phy); + + return 0; +} + +static int rtd13xx_pcie2_hw_init(struct rtd_pcie_port *pp) +{ + + if (pp->workaround) { + /* #Base 0 */ + writel(0x980D0000, pp->ctrl_base + PCIE_BASE_0); + + /* #Mask 0 */ + writel(0xFFFF0000, pp->ctrl_base + PCIE_MASK_0); + + /* #translate for MMIO R/W */ + writel(0xC1000000, pp->ctrl_base + PCIE_TRANS_0); + } else { + /* #Base 0 */ + writel(0x980C2000, pp->ctrl_base + PCIE_BASE_0); + + /* #Mask 0 */ + writel(0xFFF00000, pp->ctrl_base + PCIE_MASK_0); + + /* #translate for MMIO R/W */ + writel(0x98000000, pp->ctrl_base + PCIE_TRANS_0); + } + + writel(0x0, pp->ctrl_base + PCIE_SCTCH); + + return 0; +} +#ifdef CONFIG_RTD16XXB_PCIE1_ACP +static int acp_init(struct rtd_pcie_port *pp) +{ + struct device_node *syscon_np; + struct regmap *scpu_wrapper_base; + u32 tmp; + + syscon_np = of_parse_phandle(pp->dev->of_node, "syscon-scpu-wrapper", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + scpu_wrapper_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pp->main2_misc_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + /*0x9801D124[0] = 0 SCPU_WRAPPER INTERFACE_EN*/ + regmap_write(scpu_wrapper_base, INTERFACE_EN, 0x0); + /*0x9801D100 SCPU_WRAPPER SC_CRT_CTRL*/ + regmap_read(scpu_wrapper_base, SC_CRT_CTRL, &tmp); + tmp |= 0xA0204000; + regmap_write(scpu_wrapper_base, SC_CRT_CTRL, tmp); + /*0x9801D800 SCPU_WRAPPER SC_ACP_CTRL*/ + regmap_write(scpu_wrapper_base, SC_ACP_CTRL, 0x100F01FF); + /*0x9801D030 SCPU_WRAPPER SC_ACP_CRT_CTRL*/ + regmap_write(scpu_wrapper_base, SC_ACP_CRT_CTRL, 0x10010001); + writel(0x3D820, pp->ctrl_base + PCIE_ACP_CTRL); + + return 0; +} +#endif + +static int rtd16xxb_pcie1_hw_init(struct rtd_pcie_port *pp) +{ + struct device_node *syscon_np; + struct regmap *scpu_wrapper_base; + u32 regmap_st = 0; + int timeout; + + syscon_np = of_parse_phandle(pp->dev->of_node, "syscon-scpu-wrapper", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + scpu_wrapper_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pp->main2_misc_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + regmap_write(scpu_wrapper_base, PCIE1_START, 0xA0000000); + regmap_write(scpu_wrapper_base, PCIE1_END, 0xA00FF000); + regmap_write(scpu_wrapper_base, PCIE1_CTRL, 0x1); + timeout = 500; + while (regmap_st != 0x1 && timeout > 0) { + regmap_read(scpu_wrapper_base, PCIE1_STAT, ®map_st); + mdelay(1); + timeout--; + } + if (timeout == 0) { + dev_err(pp->dev, "failed to set mmio start/end\n"); + return -EINVAL; + } + + writel(0xA0000000, pp->ctrl_base + PCIE_DDR_START); + writel(0xA0FF0000, pp->ctrl_base + PCIE_DDR_END); + writel(readl(pp->ctrl_base + PCIE_SYS_CTR) | 0x24000000, pp->ctrl_base + PCIE_SYS_CTR); + writel(0xA0000000, pp->ctrl_base + PCI_BASE_2); + + writel(0x0, pp->ctrl_base + PCIE_SERVICE_REGION); + +#ifdef CONFIG_RTD16XXB_PCIE1_ACP + if (acp_init(pp)) + dev_err(pp->dev, "acp init failed.\n"); +#endif + + return 0; +} + +static int rtd16xxb_pcie2_hw_init(struct rtd_pcie_port *pp) +{ + struct device_node *syscon_np; + struct regmap *scpu_wrapper_base; + u32 regmap_st = 0; + int timeout; + + syscon_np = of_parse_phandle(pp->dev->of_node, "syscon-scpu-wrapper", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + scpu_wrapper_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(pp->main2_misc_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + regmap_write(scpu_wrapper_base, PCIE2_START, 0xA0100000); + regmap_write(scpu_wrapper_base, PCIE2_END, 0xA01FF000); + regmap_write(scpu_wrapper_base, PCIE2_CTRL, 0x1); + timeout = 500; + while (regmap_st != 0x1 && timeout > 0) { + regmap_read(scpu_wrapper_base, PCIE2_STAT, ®map_st); + mdelay(1); + timeout--; + } + if (timeout == 0) { + dev_err(pp->dev, "failed to set mmio start/end\n"); + return -EINVAL; + } + + writel(0xA0100000, pp->ctrl_base + PCIE_DDR_START); + writel(0xA01FF000, pp->ctrl_base + PCIE_DDR_END); + writel(readl(pp->ctrl_base + PCIE_SYS_CTR) | 0x24000000, pp->ctrl_base + PCIE_SYS_CTR); + writel(0xA0100000, pp->ctrl_base + PCI_BASE_2); + + writel(0x0, pp->ctrl_base + PCIE_SERVICE_REGION); + + return 0; +} + + +static const struct rtd_pcie_ops rtd13xx_pcie0_ops = { + .name = "pcie0", + .get_resource = rtd13xx_pcie0_get_res, + .init = rtd13xx_pcie0_init, + .deinit = rtd13xx_pcie0_deinit, + .hwinit = rtd13xx_pcie0_hw_init, + .msi_init = rtd_pcie_wrapper_msi_init, +}; + +static const struct rtd_pcie_ops rtd13xx_pcie1_ops = { + .name = "pcie1", + .get_resource = rtd13xx_pcie1_get_res, + .init = rtd13xx_pcie1_init, + .deinit = rtd13xx_pcie1_deinit, + .hwinit = rtd13xx_pcie1_hw_init, + .msi_init = rtd_pcie_wrapper_msi_init, +}; + +static const struct rtd_pcie_ops rtd13xx_pcie2_ops = { + .name = "pcie2", + .get_resource = rtd13xx_pcie2_get_res, + .init = rtd13xx_pcie2_init, + .deinit = rtd13xx_pcie2_deinit, + .hwinit = rtd13xx_pcie2_hw_init, + .msi_init = rtd_pcie_wrapper_msi_init, +}; + +static const struct rtd_pcie_ops rtd16xxb_pcie1_ops = { + .name = "pcie1", + .get_resource = rtd13xx_pcie1_get_res, + .init = rtd13xx_pcie1_init, + .deinit = rtd13xx_pcie1_deinit, + .hwinit = rtd16xxb_pcie1_hw_init, + .msi_init = rtd_pcie_mac_msi_init, +}; + +static const struct rtd_pcie_ops rtd16xxb_pcie2_ops = { + .name = "pcie2", + .get_resource = rtd13xx_pcie2_get_res, + .init = rtd13xx_pcie2_init, + .deinit = rtd13xx_pcie2_deinit, + .hwinit = rtd16xxb_pcie2_hw_init, + .msi_init = rtd_pcie_mac_msi_init, +}; + +static const struct of_device_id rtd_pcie_match_table[] = { + {.compatible = "realtek,rtd13xx-pcie-slot0", .data = &rtd13xx_pcie0_ops}, + {.compatible = "realtek,rtd13xx-pcie-slot1", .data = &rtd13xx_pcie1_ops}, + {.compatible = "realtek,rtd13xx-pcie-slot2", .data = &rtd13xx_pcie2_ops}, + {.compatible = "realtek,rtd16xxb-pcie-slot1", .data = &rtd16xxb_pcie1_ops}, + {.compatible = "realtek,rtd16xxb-pcie-slot2", .data = &rtd16xxb_pcie2_ops}, + {}, +}; + +static int rtd_pcie_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtd_pcie_port *pp = platform_get_drvdata(pdev); + int ret = 0; + + dev_info(dev, "suspend enter ...\n"); + + ret = gpiod_direction_output(pp->perst_gpio, 0); + if (ret) + dev_err(pp->dev, "cannot set gpio\n"); + + ret = pp->ops->deinit(pp); + if (ret) { + dev_err(dev, "deinit failed.\n"); + return ret; + } + + dev_info(dev, "suspend exit ...\n"); + + return 0; +} + +static int rtd_pcie_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtd_pcie_port *pp = platform_get_drvdata(pdev); + int ret = 0; + + dev_info(dev, "resume enter ...\n"); + + ret = pp->ops->init(pp); + if (ret) { + dev_err(dev, "init failed.\n"); + return ret; + } + + ret = gpiod_direction_output(pp->perst_gpio, 1); + if (ret) + dev_err(pp->dev, "cannot set gpio\n"); + + ret = pcie_link_init(pp); + if (ret) { + dev_err(dev, "link init failed.\n"); + return ret; + } + writel(pp->msi_data, pp->ctrl_base + PCIE_MSI_TRAN); + + dev_info(dev, "resume exit ...\n"); + + return ret; +} + +static void rtd_pcie_shutdown(struct platform_device *pdev) +{ + struct rtd_pcie_port *pp = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int ret = 0; + + dev_info(dev, "shutdown enter ...\n"); + + ret = gpiod_direction_output(pp->perst_gpio, 0); + if (ret) + dev_err(pp->dev, "cannot set gpio\n"); + + ret = pp->ops->deinit(pp); + if (ret) + dev_err(dev, "deinit failed.\n"); + + dev_info(&pdev->dev, "shutdown exit ...\n"); +} + +static const struct dev_pm_ops rtd_pcie_pm_ops = { + .suspend_noirq = rtd_pcie_suspend, + .resume_noirq = rtd_pcie_resume, +}; + +static struct platform_driver rtd_pcie_driver = { + .driver = { + .name = "Realtek DHC PCIe", + .of_match_table = of_match_ptr(rtd_pcie_match_table), +#ifdef CONFIG_SUSPEND + .pm = &rtd_pcie_pm_ops, +#endif + }, + .probe = rtd_pcie_probe, + .shutdown = rtd_pcie_shutdown, +}; +module_platform_driver(rtd_pcie_driver); + +MODULE_AUTHOR("TYChang "); +MODULE_DESCRIPTION("Realtek PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/controller/pcie-rtd.h b/drivers/pci/controller/pcie-rtd.h new file mode 100644 index 000000000000..5d75e1178df4 --- /dev/null +++ b/drivers/pci/controller/pcie-rtd.h @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Realtek PCIe host controller driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + */ +#ifndef RTK_PCIE_13xx_H_ +#define RTK_PCIE_13xx_H_ + +#include +#include +#include +#include +#include +#include + +#include "../pci.h" + + +#define PCIE_IO_2K_MASK 0xFFFFF800 +#define PCIE_IO_4K_MASK 0xFFFFF000 +#define PCIE_IO_64K_MASK 0xFFFF0000 +#define MAX_RTK_MSI_IRQS 16 +#define MAX_RTK_MSI_CTRLS (MAX_RTK_MSI_IRQS / 16) + + +struct rtd_pcie_port { + struct rtd_pcie_ops *ops; + struct platform_device *pdev; + struct device *dev; + void __iomem *ctrl_base; + void __iomem *cfg_base; + struct regmap *main2_misc_base; + struct regmap *pinmux_base; + struct clk *pcie_clk; + struct reset_control *rst; + struct reset_control *rst_stitch; + struct reset_control *rst_core; + struct reset_control *rst_power; + struct reset_control *rst_nonstitch; + struct reset_control *rst_phy; + struct reset_control *rst_phy_mdio; + struct reset_control *rst_sgmii_mdio; + struct phy *pcie_phy; + int speed_mode; + int debug_mode; + int workaround; + struct gpio_desc *perst_gpio; + int msi_irq; + struct irq_domain *irq_domain; + struct irq_domain *msi_domain; + dma_addr_t msi_data; + u32 *msi_data_virt; + struct page *msi_page; + struct irq_chip *msi_irq_chip; + raw_spinlock_t lock; + DECLARE_BITMAP(irq_bitmap, MAX_RTK_MSI_IRQS); + struct msi_controller msi_chip; +}; + +struct rtd_pcie_ops { + char name[10]; + int (*get_resource)(struct rtd_pcie_port *pcie); + int (*init)(struct rtd_pcie_port *pcie); + int (*deinit)(struct rtd_pcie_port *pcie); + int (*hwinit)(struct rtd_pcie_port *pcie); + int (*msi_init)(struct rtd_pcie_port *pcie); +}; + + +#define ISO_POWERCUT_ETN 0x5c +#define PCIE0_USB_SEL_OFFSET BIT(6) + +#define MISC_PHY_CTRL 0x50 +#define PCIE1_SATA_SEL_OFFSET BIT(8) +#define PCIE2_SATA_SEL_OFFSET BIT(9) + +/* SCPU Wrapper PCIe MMIO REG*/ +#define PCIE1_START 0x630 +#define PCIE1_END 0x634 +#define PCIE1_CTRL 0x638 +#define PCIE1_STAT 0x63C +#define PCIE2_START 0x640 +#define PCIE2_END 0x644 +#define PCIE2_CTRL 0x648 +#define PCIE2_STAT 0x64C +#define INTERFACE_EN 0x124 +#define SC_CRT_CTRL 0x100 +#define SC_ACP_CTRL 0x800 +#define SC_ACP_CRT_CTRL 0x030 + + +/* PCIE_MAC_REG */ +#define LINK_CONTROL2_LINK_STATUS2_REG 0xa0 +#define PORT_LINK_CTRL_OFF 0x710 +#define MEM_LIMIT_MEM_BASE_REG 0x20 +#define PREF_MEM_LIMIT_PREF_MEM_BASE_REG 0x24 +#define TYPE1_STATUS_COMMAND_REG 0x4 +#define PCIE_MSI_ADDR_LO 0x820 +#define PCIE_MSI_ADDR_HI 0x824 +#define PCIE_MSI_INTR0_ENABLE 0x828 +#define PCIE_MSI_INTR0_MASK 0x82C +#define PCIE_MSI_INTR0_STATUS 0x830 + + +/* + * PCI-DVR Bridge + */ +#define PCIE_SYS_CTR 0x00000C00U +#define PCIE_BASE_0 0xCFC +#define PCIE_MASK_0 0xD00 +#define PCIE_TRANS_0 0xD04 +#define PCIE_DIR_EN 0xC78 +#define PCIE_RCPL_ST 0xC7C +#define PCIE_MDIO_CTR 0xC1C +#define PCIE_SCTCH 0xCBC +#define PCIE_SERVICE_REGION 0xD30 +#define PCIE_MSI_TRAN 0xCD0 +#define PCIE_INT_CTR 0xC04 +#define PCIE_MSI_DATA 0xCD4 +#define TRANS_EN (1 << 20) +#define PHY_MMIO_TYPE (1 << 19) +#define PHY_MDIO_OE (1 << 18) +#define PHY_MDIO_RSTN (1 << 17) +#define APP_INIT_RST (1 << 16) +#define LOOPBACK_EN (1 << 9) +#define DIR_REQ_INFO_EN (1 << 8) +#define RX_LANE_REVERSAL_EN (1 << 7) +#define TX_LANE_REVERSAL_EN (1 << 6) +#define INDOR_CFG_EN (1 << 5) +#define DIR_CFG_EN (1 << 4) +#define RCV_ADDR0_EN (1 << 3) +#define RCV_ADDR1_EN (1 << 2) +#define APP_LTSSM_EN (1 << 1) +#define RCV_TRANS_EN (1) +#define PCIE_DDR_START 0xD70 +#define PCIE_DDR_END 0xD74 +#define PCI_BASE_2 0xD5C +#define PCIE_ACP_CTRL 0xD40 + +#define DVR_GNR_INT 0x00000C08U +#define S_INTP_PCIE_LEGACY_MSI_INT 14 +#define S_INTP_PM_TO_ACK_INT 13 +#define S_INTP_CFG_SYS_ERR_RC_INT 12 +#define S_INTP_PCIE_LEGACY_INT 11 +#define S_INTP_CFG_RSDM_VENDOR_MSG_INT 10 +#define S_INTP_CFG_PME_MSI 9 +#define S_INTP_CFG_PME_INT 8 +#define S_INTP_CFG_AER_RC_MSI 7 +#define S_INTP_CFG_AER_RC_ERR 6 +#define S_INTP_RTGT 5 /* Slave Receiver Interrupt */ +#define S_INTP_RCPL 4 /* Master Receiver Interrupt */ +#define S_INTP_DIR_CFG 3 /* Direct CFG Interrupt */ +#define S_INTP_DIR_MIO 2 /* Direct MIO Interrupt */ +#define S_INTP_CFG 1 /* Indirect CFG Interrupt */ +#define S_INTP_MIO 0 /* Indirect MIO Interrupt */ +#define INTP_PCIE_LEGACY_MSI_INT (1 << INTP_PCIE_LEGACY_MSI_INT) +#define INTP_PM_TO_ACK_INT (1 << INTP_PM_TO_ACK_INT) +#define INTP_CFG_SYS_ERR_RC_INT (1 << INTP_CFG_SYS_ERR_RC_INT) +#define INTP_PCIE_LEGACY_INT (1 << INTP_PCIE_LEGACY_INT) +#define INTP_CFG_RSDM_VENDOR_MSG_INT (1 << INTP_CFG_RSDM_VENDOR_MSG_INT) +#define INTP_CFG_PME_MSI (1 << INTP_CFG_PME_MSI) +#define INTP_CFG_PME_INT (1 << INTP_CFG_PME_INT) +#define INTP_CFG_AER_RC_MSI (1 << INTP_CFG_AER_RC_MSI) +#define INTP_CFG_AER_RC_ERR (1 << INTP_CFG_AER_RC_ERR) +#define INTP_RTGT (1 << INTP_RTGT) +#define INTP_RCPL (1 << INTP_RCPL) +#define INTP_DIR_CFG (1 << INTP_DIR_CFG) +#define INTP_DIR_MIO (1 << INTP_DIR_MIO) +#define INTP_CFG (1 << INTP_CFG) +#define INTP_MIO (1 << INTP_MIO) + +#define DVR_PCIE_INT 0x00000C0CU +#define PCIE_INTP_INTD (0x1U << 3) +#define PCIE_INTP_INTC (0x1U << 2) +#define PCIE_INTP_INTB (0x1U << 1) +#define PCIE_INTP_INTA (0x1U) + +#define PCIE_DBI_CTR 0x00000C10U +#define DBI_IO_ACCESS (0x1U << 9) +#define DBI_ROM_ACCESS (0x1U << 8) +#define DBI_BAR_NUM(x) ((x & 0x7) << 5) +#define DBI_FUNC_NUM(x) ((x & 0x7) << 2) +#define DBI_SC2_ACCESS (0x1U << 1) +#define DBI_CMD_ACCESS (0x1U) + +#define PCIE_INDIR_CTR 0x00000C14 +#define PCIE_DIR_CTR 0x00000018U +#define REQ_INFO_ALIGN (0x1U << 13) +#define REQ_INFO_ATTR(x) ((x & 0x3) << 11) +#define REQ_INFO_EP (0x1U << 10) +#define REQ_INFO_TC(x) ((x & 0x7) << 7) +#define REQ_INFO_TYPE(x) ((x & 0x1F) << 2) +#define REQ_INFO_FMT(x) (x & 0x3) + +#define MDIO_DATA(x) ((x & 0xFFFF) << 16) /* MDIO Data */ +#define MDIO_PHY_ADDR(x) ((x & 0x7) << 13) /* MDIO PHY Address */ +#define MDIO_REG_ADDR(x) ((x & 0x1F) << 8) /* MDIO Register Address */ +#define MDIO_BUSY (0x1U << 7) +#define MDIO_ST(x) ((x & 0x03) << 5) /* MDIO Host Control State Monitor */ +#define MDIO_RDY (0x1U << 4) /* MDIO PREAMBLE Signal Monitor */ +#define MDIO_RATE(x) ((x & 0x3) << 2) /* MDIO Clock Rate */ +#define CLK_SYS_1_32(x) 0 /* MDIO Clock Rate = 1/32 */ +#define CLK_SYS_1_16(x) 1 /* MDIO Clock Rate = 1/16 */ +#define CLK_SYS_1_8(x) 2 /* MDIO Clock Rate = 1/8 */ +#define CLK_SYS_1_4(x) 3 /* MDIO Clock Rate = 1/4 */ +#define MDIO_SRST (0x1U << 1) +#define MDIO_RDWR(x) (x & 0x1) /* MDIO Read/Write : 0 read, 1 write */ + +/* + * Address Translation + * PCI-E Bridge provides 2 set of control registers + * for in-bound address translation + */ +#define PCIE_BASE0 0x00000C20U +#define PCIE_BASE1 0x00000C24U +#define PCIE_MASK0 0x00000C28U +#define PCIE_MASK1 0x00000C2CU +#define PCIE_TRAN0 0x00000C30U +#define PCIE_TRAN1 0x00000C34U + +/* + * Configuration Access + * the following registers are used to access configuration + * space + */ +#define PCIE_CFG_CT 0x00000C38U +#define GO_CT (0x1U) + +#define PCIE_CFG_EN 0x00000C3CU +#define BUS_NUM(x) ((x & 0xFF) << 16) /* Bus number */ +#define DEV_NUM(x) ((x & 0xF) << 11) /* Device number */ +#define FUN_NUM(x) ((x & 0x7) << 8) /* Function number */ +#define BYTE_CNT(x) ((x & 0xF) << 4) /* Byte enable bits */ +#define ERROR_EN(x) ((x & 0x1) << 2) /* Enable error timeout counter */ +#define BYTE_EN (0x1 << 1) /* Byte enable bits enable */ +#define WRRD_EN(x) (x & 0x01) +#define WRITE_CFG WRRD_EN(1) +#define READ_CFG WRRD_EN(0) + +#define PCIE_CFG_ST 0x00000C40U +#define CFG_ST_ERROR (0x1U << 1) +#define CFG_ST_DONE 0x1U + +#define PCIE_CFG_ADDR 0x00000C44U +#define PCIE_CFG_WDATA 0x00000C48U +#define PCIE_CFG_RDATA 0x00000C4CU + +/* + * Memory / IO Access + * the following registers are used to access configuration + * space + */ +#define PCIE_MIO_CT 0x00000C50U +#define PCIE_MIO_EN 0x00000C54U + +#define TIMEOUT_CNT_VAL(x) ((x & 0xFFFFFFF) << 8) + +#define PCIE_MIO_ST 0x00000C58U +#define PCIE_MIO_ADDR 0x00000C5CU +#define PCIE_MIO_WDATA 0x00000C60U +#define PCIE_MIO_RDATA 0x00000C64U + +/* + * MISC + */ +#define PCIE_CTR 0x00000C68U +#define PCIE_PWR_CTR 0x00000C6CU +#define PCIE_DBG 0x00000C70U +#define PCIE_DIR_ST 0x00000C74U /* Status for Direct Access */ +#define CFG_RERROR_ST (0x1U << 1) +#define MIO_RERROR_ST (0x1U) +#define TIMEOUT_EN (0x1U) + +#define PCIE_MAC_ST 0x00000CB4 +#define RDLH_LINK_UP (0x1U << 14) +#define PM_XTLH_BLOCK_TLP (0x1U << 13) +#define CFG_BUS_MASTER_EN (0x1U << 12) +#define CFG_PM_NO_SOFT_RST (0x1U << 11) +#define XMLH_LINK_UP (0x1U << 10) +#define LINK_REQ_RST_NOT (0x1U << 9) +#define XMLH_LTSSM_STATE(x) ((x & 0xF) << 4) +#define PM_CURNT_STATE(x) ((x & 0x7) << 1) +#define CFG_CLK_REQ_N (0x1U) + +/* + * PCI-E RC registers + */ +#define PCI_CFG_REG 0x00000000U /* PCI compatible registers */ +#define PCIE_DEV_REG 0x00000040U /* PCI-E Device Configuration Space */ +#define PCIE_EXT_REG 0x00000100U /* PCI-E Extend Configuration Space */ +#define PCIE_DVR_REG 0x00000C00U /* DVR space register */ + +#define CFG(addr) (PCI_CFG_REG + (addr)) +#define BAR1 0x10 +#define BAR2 0x14 +#define BAR3 0x18 +#define BAR4 0x1C + +#define CFG_ST_DETEC_PAR_ERROR (1 << 31) +#define CFG_ST_SIGNAL_SYS_ERROR (1 << 30) +#define CFG_ST_REC_MASTER_ABORT (1 << 29) +#define CFG_ST_REC_TARGET_ABORT (1 << 28) +#define CFG_ST_SIG_TAR_ABORT (1 << 27) + +#define PCIE_CONNECT_TIMEOUT 60 +#define ADDR_TO_DEVICE_NO(addr) ((addr >> 19) & 0x1F) +#endif + diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ece90a23936d..e490b6ae0378 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * PCI detection and setup code @@ -21,6 +24,10 @@ #include #include "pci.h" +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ + #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_RESERVE_BUSNR 3 @@ -1732,6 +1739,47 @@ static void pci_msi_setup_pci_dev(struct pci_dev *dev) pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); } +#ifdef MY_ABC_HERE +extern int gSynoResetFlag; +void syno_pcie_nvme_check(struct pci_dev *dev) +{ + u16 slotStat = 0; + u16 linkStat = 0; + u16 linkStat2 = 0; + + // For RTK 2824 switch and synology subsystem_vendor + if (0x1b21 == dev->vendor && 0x2824 == dev->device && 0x7053 == dev->subsystem_vendor) { + // For M2D20 and E10M20-T1 + if ((0x3001 == dev->subsystem_device && (0x4 == PCI_SLOT(dev->devfn) || 0x8 == PCI_SLOT(dev->devfn))) || + (0x2002 == dev->subsystem_device && (0x4 == PCI_SLOT(dev->devfn) || 0x8 == PCI_SLOT(dev->devfn)))) { + if (0 != pcie_capability_read_word(dev, PCI_EXP_SLTSTA, &slotStat)) { + goto END; + } + if (0 != pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &linkStat)) { + goto END; + } + if (0 != pcie_capability_read_word(dev, PCI_EXP_LNKSTA2, &linkStat2)) { + goto END; + } + dev_printk(KERN_ERR, &dev->dev, "Present %d Active %d Sta2 reg: %x\n", !!(slotStat & PCI_EXP_SLTSTA_PDS), + !!(linkStat & PCI_EXP_LNKSTA_DLLLA), linkStat2); + /* + * We check 2 situations + * 1. present = 1 but active = 0 + * 2. present = 0 but Equalization Complete | Equalization 1 success | Equalization 2 success | Equalization 3 success + * Ref: Link Status 2 Register (Offset 32h) + */ + if ((0 != (slotStat & PCI_EXP_SLTSTA_PDS) && 0 == (linkStat & PCI_EXP_LNKSTA_DLLLA)) || + (0 == (slotStat & PCI_EXP_SLTSTA_PDS) && (0 != (linkStat2 & 0x1E)))) { + gSynoResetFlag = 1; + } + } + } +END: + return; +} +#endif /* MY_ABC_HERE */ + /** * pci_intx_mask_broken - Test PCI_COMMAND_INTX_DISABLE writability * @dev: PCI device @@ -1924,6 +1972,16 @@ int pci_setup_device(struct pci_dev *dev) pci_read_config_word(dev, pos + PCI_SSVID_VENDOR_ID, &dev->subsystem_vendor); pci_read_config_word(dev, pos + PCI_SSVID_DEVICE_ID, &dev->subsystem_device); } + +#ifdef MY_DEF_HERE + if (syno_is_hw_version(HW_DS1621p) || syno_is_hw_version(HW_DS1520p)) { + if ( 0x1b21 == dev->vendor && 0x1806 == dev->device ) { + dev->subsystem_vendor = 0; + dev->subsystem_device = 0; + } + } +#endif /* MY_DEF_HERE */ + break; case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ @@ -1946,6 +2004,9 @@ int pci_setup_device(struct pci_dev *dev) dev->class = PCI_CLASS_NOT_DEFINED << 8; } +#ifdef MY_ABC_HERE + syno_pcie_nvme_check(dev); +#endif /* MY_ABC_HERE */ /* We found a fine healthy device, go go go... */ return 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bb1122e257dd..9408850252d8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * This file contains work-arounds for many known PCI hardware bugs. @@ -5699,3 +5702,180 @@ static void apex_pci_fixup_class(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a, PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class); + +#ifdef MY_ABC_HERE +/* + * Marvell provide PCI Programming steps for 88SE9235 without SPI flash + * to slove some compatibility issue. + * + * The reference document is put in SynoStorage + * HW_Docs\datasheets_Roadmaps\SATA\marvell\SATA6g_88SE923x\software\ + * Marvell_SE92159235_NonSPI__flash_Support_App_Note_r1.0.doc + */ +static void mv9235_non_spi_programming(struct pci_dev *dev) +{ + void __iomem *bar5; + + bar5 = ioremap(pci_resource_start(dev, 5), pci_resource_len(dev, 5)); + if (!bar5) { + dev_warn(&dev->dev, "Can't map mv9235 registers\n"); + return; + } + + dev_info(&dev->dev, "Apply mv9235 specific programming steps\n"); + + // sata port0-interrupt boundary of command + writel(0x00000104, bar5+0x178); + ndelay(80); + // Disable the interrupt blocking; port interrupt coalescing count + writel(0x00500B03, bar5+0x17C); + ndelay(80); + // sata port1-interrupt boundary of command + writel(0x00000104, bar5+0x1F8); + ndelay(80); + // Disable the interrupt blocking; port interrupt coalescing count + writel(0x00500B03, bar5+0x1FC); + ndelay(80); + // sata port2-interrupt boundary of command + writel(0x00000104, bar5+0x278); + ndelay(80); + // Disable the interrupt blocking; port interrupt coalescing count + writel(0x00500B03, bar5+0x27C); + ndelay(80); + // sata port3-interrupt boundary of command + writel(0x00000104, bar5+0x2F8); + ndelay(80); + // Disable the interrupt blocking; port interrupt coalescing count + writel(0x00500B03, bar5+0x2FC); + ndelay(80); + // 6G drives issue/HW CC + writel(0x0000001C, bar5+0xA0); + ndelay(80); + writel(0x00935038, bar5+0xA4); + ndelay(80); + // SSC parameter calculate in PLL CTL2 + writel(0x0000000C, bar5+0xA0); + ndelay(80); + writel(0xA5A58757, bar5+0xA4); + ndelay(80); + // SSC parameter calculate in PLL CTL1 + writel(0x00000008, bar5+0xA0); + ndelay(80); + writel(0x0001388F, bar5+0xA4); + ndelay(80); +} +DECLARE_PCI_FIXUP_FINAL(0x1b4b, 0x9235, mv9235_non_spi_programming); +DECLARE_PCI_FIXUP_FINAL(0x1b4b, 0x9215, mv9235_non_spi_programming); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * Marvell provide PCI Programming steps for 88SE9170 without SPI flash + * to slove some compatibility issue. + */ +static void mv9170_non_spi_programming(struct pci_dev *dev) +{ + void __iomem *bar5; + + bar5 = ioremap(pci_resource_start(dev, 5), pci_resource_len(dev, 5)); + if (!bar5) { + dev_warn(&dev->dev, "Can't map mv9170 registers\n"); + return; + } + + dev_info(&dev->dev, "Apply mv9170 specific programming steps\n"); + + //port0-GEN1 + writel(0x0000008D, bar5+0x178); + ndelay(80); + writel(0x0000C962, bar5+0x17C); + ndelay(80); + //port1-GEN1 + writel(0x0000008D, bar5+0x1F8); + ndelay(80); + writel(0x0000C962, bar5+0x1FC); + ndelay(80); + //port0-GEN3 + writel(0x00000091, bar5+0x178); + ndelay(80); + writel(0x00000E75, bar5+0x17C); + ndelay(80); + //port1-GEN3 + writel(0x00000091, bar5+0x1F8); + ndelay(80); + writel(0x00000E75, bar5+0x1FC); + ndelay(80); + //port0-password + writel(0x000000A2, bar5+0x178); + ndelay(80); + writel(0x00000046, bar5+0x17C); + ndelay(80); + //port1-password + writel(0x000000A2, bar5+0x1F8); + ndelay(80); + writel(0x00000046, bar5+0x1FC); + ndelay(80); + //port0-ffe-isel + writel(0x000000ED, bar5+0x178); + ndelay(80); + writel(0x00002400, bar5+0x17C); + ndelay(80); + //port1-ffe-isel + writel(0x000000ED, bar5+0x1F8); + ndelay(80); + writel(0x00002400, bar5+0x1FC); + ndelay(80); + //port0-sampler-scale + writel(0x000000DB, bar5+0x178); + ndelay(80); + writel(0x00000000, bar5+0x17C); + ndelay(80); + //port1-sampler-scale + writel(0x000000DB, bar5+0x1F8); + ndelay(80); + writel(0x00000000, bar5+0x1FC); + ndelay(80); + //port0-vset + writel(0x000000A9, bar5+0x178); + ndelay(80); + writel(0x00005556, bar5+0x17C); + ndelay(80); + //port1-vset + writel(0x000000A9, bar5+0x1F8); + ndelay(80); + writel(0x00005556, bar5+0x1FC); + ndelay(80); + //port0-cal-sampler-start + writel(0x000000D6, bar5+0x178); + ndelay(80); + writel(0x00000000, bar5+0x17C); + ndelay(80); + //port1-cal-sampler-start + writel(0x000000D6, bar5+0x1F8); + ndelay(80); + writel(0x00000000, bar5+0x1FC); + ndelay(80); + //port0-cal-sampler-start + writel(0x000000D6, bar5+0x178); + ndelay(80); + writel(0x00000200, bar5+0x17C); + ndelay(80); + //port1-cal-sampler-start + writel(0x000000D6, bar5+0x1F8); + ndelay(80); + writel(0x00000200, bar5+0x1FC); + ndelay(80); + //set the amplitude to 3.5% + writel(0x00000008, bar5+0xA0); + ndelay(80); + writel(0x11888EAE, bar5+0xA4); + ndelay(80); + //enable SSC + writel(0x00000004, bar5+0xA0); + ndelay(80); + writel(0x00009C4F, bar5+0xA4); + ndelay(80); +} +DECLARE_PCI_FIXUP_FINAL(0x1b4b, 0x9170, mv9170_non_spi_programming); +#endif /* MY_ABC_HERE */ + diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 9ed5f167a9f3..f1e8f95397da 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -74,6 +74,9 @@ source "drivers/phy/motorola/Kconfig" source "drivers/phy/mscc/Kconfig" source "drivers/phy/qualcomm/Kconfig" source "drivers/phy/ralink/Kconfig" +if SYNO_LSP_RTD1619B +source "drivers/phy/realtek/Kconfig" +endif # SYNO_LSP_RTD1619B source "drivers/phy/renesas/Kconfig" source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 6eb2916773c5..2f82bb7cbea0 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -9,6 +9,9 @@ obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_ARCH_REALTEK) += realtek/ +endif # CONFIG_SYNO_LSP_RTD1619B obj-y += allwinner/ \ amlogic/ \ broadcom/ \ diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig new file mode 100644 index 000000000000..7a19f80c2042 --- /dev/null +++ b/drivers/phy/realtek/Kconfig @@ -0,0 +1,17 @@ +# +# Phy drivers for Realtek devices +# + +config PHY_RTK_SATA + tristate "Realtek SATA PHY driver" + depends on OF + select GENERIC_PHY + help + Support for SATA GEN3 PHY on realtek chipsets. + +config PHY_RTD_PCIE + tristate "Realtek PCIe PHY driver" + depends on OF + select GENERIC_PHY + help + Support for PCIe PHY on realtek chipsets. diff --git a/drivers/phy/realtek/Makefile b/drivers/phy/realtek/Makefile new file mode 100644 index 000000000000..1de9a14d9cea --- /dev/null +++ b/drivers/phy/realtek/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the phy drivers. +# + +obj-$(CONFIG_PHY_RTK_SATA) += phy-rtk-sata.o +obj-$(CONFIG_PHY_RTD_PCIE) += phy-rtk-pcie.o diff --git a/drivers/phy/realtek/phy-rtk-pcie.c b/drivers/phy/realtek/phy-rtk-pcie.c new file mode 100644 index 000000000000..21c2a80ad8f3 --- /dev/null +++ b/drivers/phy/realtek/phy-rtk-pcie.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek PCIe Controller PHY Driver + * + * Copyright (C) 2020 Realtek + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define DRV_NAME "rtd-pcie-phy" + +#define PCIE_MDIO_CTR 0xC1C +#define PCIE_SYS_CTR 0xC00 +#define MDIO_BUSY BIT(7) +#define MDIO_RDY BIT(4) +#define MDIO_WRITE BIT(0) +#define MDIO_REG_SHIFT 8 +#define MDIO_DATA_SHIFT 16 + +struct rtd_pcie_phy { + struct device *dev; + struct reset_control *rst_phy; + struct reset_control *rst_phy_mdio; + struct regmap *pcie_base; +}; + +static int mdio_wait_busy(struct rtd_pcie_phy *rtd_phy) +{ + unsigned int val; + int cnt = 0; + + regmap_read(rtd_phy->pcie_base, PCIE_MDIO_CTR, &val); + while ((val & MDIO_BUSY) && cnt < 10) { + udelay(10); + regmap_read(rtd_phy->pcie_base, PCIE_MDIO_CTR, &val); + cnt++; + } + + if (val & MDIO_BUSY) + return -EBUSY; + + return 0; +} + +static int write_mdio_reg(struct rtd_pcie_phy *rtd_phy, u8 reg, u16 data) +{ + unsigned int val; + + if (mdio_wait_busy(rtd_phy)) + goto mdio_busy; + + val = (reg << MDIO_REG_SHIFT) | + (data << MDIO_DATA_SHIFT) | MDIO_WRITE; + regmap_write(rtd_phy->pcie_base, PCIE_MDIO_CTR, val); + + return 0; +mdio_busy: + dev_err(rtd_phy->dev, "%s - mdio is busy\n", __func__); + return -EBUSY; +} + +static int read_mdio_reg(struct rtd_pcie_phy *rtd_phy, u8 reg) +{ + unsigned int addr; + unsigned int val; + + if (mdio_wait_busy(rtd_phy)) + goto mdio_busy; + + addr = reg << MDIO_REG_SHIFT; + regmap_write(rtd_phy->pcie_base, PCIE_MDIO_CTR, addr); + + if (mdio_wait_busy(rtd_phy)) + goto mdio_busy; + + regmap_read(rtd_phy->pcie_base, PCIE_MDIO_CTR, &val); + return val >> MDIO_DATA_SHIFT; +mdio_busy: + dev_err(rtd_phy->dev, "%s - mdio is busy\n", __func__); + return -EBUSY; +} + +static int rtd13xx_pcie_phy_power_on(struct phy *phy) +{ + struct rtd_pcie_phy *rtd_phy = phy_get_drvdata(phy); + + reset_control_deassert(rtd_phy->rst_phy); + reset_control_deassert(rtd_phy->rst_phy_mdio); + + return 0; +} + +static int rtd13xx_pcie_phy_power_off(struct phy *phy) +{ + struct rtd_pcie_phy *rtd_phy = phy_get_drvdata(phy); + + reset_control_assert(rtd_phy->rst_phy); + reset_control_assert(rtd_phy->rst_phy_mdio); + + return 0; +} + +static int rtd13xx_pcie_phy_init(struct phy *phy) +{ + struct rtd_pcie_phy *rtd_phy = phy_get_drvdata(phy); + + write_mdio_reg(rtd_phy, 0x06, 0x000C); + write_mdio_reg(rtd_phy, 0x04, 0x52F5); + write_mdio_reg(rtd_phy, 0x06, 0x000C); + write_mdio_reg(rtd_phy, 0x0A, 0xC210); + write_mdio_reg(rtd_phy, 0x29, 0xFF00); + write_mdio_reg(rtd_phy, 0x01, 0xA852); + write_mdio_reg(rtd_phy, 0x0B, 0xB905); + write_mdio_reg(rtd_phy, 0x09, 0x620C); + write_mdio_reg(rtd_phy, 0x24, 0x4F08); + write_mdio_reg(rtd_phy, 0x0D, 0xF712); + write_mdio_reg(rtd_phy, 0x23, 0xCB66); + write_mdio_reg(rtd_phy, 0x20, 0xC466); + write_mdio_reg(rtd_phy, 0x21, 0x5577); + write_mdio_reg(rtd_phy, 0x22, 0x0033); + write_mdio_reg(rtd_phy, 0x2F, 0x61BD); + write_mdio_reg(rtd_phy, 0x0E, 0x1000); + write_mdio_reg(rtd_phy, 0x2B, 0xB801); + write_mdio_reg(rtd_phy, 0x1B, 0x8EA1); + write_mdio_reg(rtd_phy, 0x09, 0x600C); + write_mdio_reg(rtd_phy, 0x09, 0x620C); + write_mdio_reg(rtd_phy, 0x46, 0x000C); + write_mdio_reg(rtd_phy, 0x44, 0x52F5); + write_mdio_reg(rtd_phy, 0x4A, 0xC210); + write_mdio_reg(rtd_phy, 0x69, 0xFF00); + write_mdio_reg(rtd_phy, 0x41, 0xA84A); + write_mdio_reg(rtd_phy, 0x4B, 0xB905); + write_mdio_reg(rtd_phy, 0x49, 0x620C); + write_mdio_reg(rtd_phy, 0x64, 0x4F0C); + write_mdio_reg(rtd_phy, 0x4D, 0xF712); + write_mdio_reg(rtd_phy, 0x63, 0xCB66); + write_mdio_reg(rtd_phy, 0x60, 0xC466); + write_mdio_reg(rtd_phy, 0x61, 0x8866); + write_mdio_reg(rtd_phy, 0x62, 0x0033); + write_mdio_reg(rtd_phy, 0x6F, 0x91BD); + write_mdio_reg(rtd_phy, 0x4E, 0x1000); + write_mdio_reg(rtd_phy, 0x6B, 0xB801); + write_mdio_reg(rtd_phy, 0x49, 0x600C); + write_mdio_reg(rtd_phy, 0x49, 0x620C); + + return 0; +} + +static int rtd16xxb_pcie_phy_init(struct phy *phy) +{ + struct rtd_pcie_phy *rtd_phy = phy_get_drvdata(phy); + int val; + int cnt; + int tmp; + + + /*Gen1*/ + write_mdio_reg(rtd_phy, 0x29, 0xFF13); + write_mdio_reg(rtd_phy, 0x2A, 0x3D60); + write_mdio_reg(rtd_phy, 0x05, 0xFAD3); + write_mdio_reg(rtd_phy, 0x06, 0x0013); + write_mdio_reg(rtd_phy, 0x01, 0xA852); + write_mdio_reg(rtd_phy, 0x0A, 0xB650); + write_mdio_reg(rtd_phy, 0x28, 0xF802); + write_mdio_reg(rtd_phy, 0x0A, 0xB670); + write_mdio_reg(rtd_phy, 0x24, 0x4F10); + write_mdio_reg(rtd_phy, 0x23, 0xCB66); + write_mdio_reg(rtd_phy, 0x20, 0xC4CC); + write_mdio_reg(rtd_phy, 0x22, 0x0013); + write_mdio_reg(rtd_phy, 0x21, 0x55AA); + write_mdio_reg(rtd_phy, 0x2B, 0xA801); + write_mdio_reg(rtd_phy, 0x2F, 0xA008); + write_mdio_reg(rtd_phy, 0x0B, 0x9905); + write_mdio_reg(rtd_phy, 0x09, 0x720C); + write_mdio_reg(rtd_phy, 0x29, 0xFF13); + /*Gen2*/ + write_mdio_reg(rtd_phy, 0x69, 0xFF13); + write_mdio_reg(rtd_phy, 0x6A, 0x3D60); + write_mdio_reg(rtd_phy, 0x45, 0xFAD3); + write_mdio_reg(rtd_phy, 0x5E, 0x6EEB); + write_mdio_reg(rtd_phy, 0x46, 0x0013); + write_mdio_reg(rtd_phy, 0x41, 0xA84A); + write_mdio_reg(rtd_phy, 0x4A, 0xB650); + write_mdio_reg(rtd_phy, 0x68, 0xF802); + write_mdio_reg(rtd_phy, 0x63, 0xCB66); + write_mdio_reg(rtd_phy, 0x60, 0xC4EE); + write_mdio_reg(rtd_phy, 0x62, 0x0013); + write_mdio_reg(rtd_phy, 0x61, 0x55AA); + write_mdio_reg(rtd_phy, 0x6B, 0xA801); + write_mdio_reg(rtd_phy, 0x6F, 0xA008); + write_mdio_reg(rtd_phy, 0x4B, 0x9905); + write_mdio_reg(rtd_phy, 0x49, 0x720C); + write_mdio_reg(rtd_phy, 0x69, 0xFF13); + /*OOBS*/ + write_mdio_reg(rtd_phy, 0x09, 0x720C); + write_mdio_reg(rtd_phy, 0x49, 0x720C); + write_mdio_reg(rtd_phy, 0x09, 0x700C); + write_mdio_reg(rtd_phy, 0x49, 0x700C); + write_mdio_reg(rtd_phy, 0x09, 0x720C); + write_mdio_reg(rtd_phy, 0x49, 0x720C); + val = read_mdio_reg(rtd_phy, 0x0D); + val |= BIT(6); + write_mdio_reg(rtd_phy, 0x0D, val); + val = read_mdio_reg(rtd_phy, 0x4D); + val |= BIT(6); + write_mdio_reg(rtd_phy, 0x4D, val); + val = read_mdio_reg(rtd_phy, 0x19); + val |= BIT(2); + write_mdio_reg(rtd_phy, 0x19, val); + val = read_mdio_reg(rtd_phy, 0x59); + val |= BIT(2); + write_mdio_reg(rtd_phy, 0x59, val); + write_mdio_reg(rtd_phy, 0x10, 0x03C4); + write_mdio_reg(rtd_phy, 0x50, 0x03C4); + + cnt = 0; + val = read_mdio_reg(rtd_phy, 0x1f); + while ((val & BIT(6)) != 0 && cnt < 10) { + udelay(10); + val = read_mdio_reg(rtd_phy, 0x1f); + cnt++; + } + if (cnt == 10) { + dev_err(rtd_phy->dev, "wait mdio reg(0x1f) bit6 == 0 timeout\n"); + return -EBUSY; + } + cnt = 0; + val = read_mdio_reg(rtd_phy, 0x5f); + while ((val & BIT(6)) != 0 && cnt < 10) { + udelay(10); + val = read_mdio_reg(rtd_phy, 0x5f); + cnt++; + } + if (cnt == 10) { + dev_err(rtd_phy->dev, "wait mdio reg(0x5f) bit6 == 0 timeout\n"); + return -EBUSY; + } + mdelay(1); + val = read_mdio_reg(rtd_phy, 0x19); + val |= BIT(2); + write_mdio_reg(rtd_phy, 0x19, val); + val = read_mdio_reg(rtd_phy, 0x59); + val |= BIT(2); + write_mdio_reg(rtd_phy, 0x59, val); + write_mdio_reg(rtd_phy, 0x10, 0x03C4); + write_mdio_reg(rtd_phy, 0x50, 0x03C4); + tmp = read_mdio_reg(rtd_phy, 0x1f); + tmp = (tmp & GENMASK(12, 8)) >> 8; + val = read_mdio_reg(rtd_phy, 0x03); + val = (val & ~ GENMASK(5, 1)) | (tmp << 1); + write_mdio_reg(rtd_phy, 0x03, val); + tmp = read_mdio_reg(rtd_phy, 0x5f); + tmp = (tmp & GENMASK(12, 8)) >> 8; + + val = read_mdio_reg(rtd_phy, 0x43); + val = (val & ~ GENMASK(5, 1)) | (tmp << 1); + write_mdio_reg(rtd_phy, 0x43, val); + write_mdio_reg(rtd_phy, 0x09, 0x721C); + write_mdio_reg(rtd_phy, 0x49, 0x721C); + cnt = 0; + val = read_mdio_reg(rtd_phy, 0x1f); + while (!(val & BIT(15)) && cnt < 10) { + udelay(10); + val = read_mdio_reg(rtd_phy, 0x1f); + cnt++; + } + if (cnt == 10) { + dev_err(rtd_phy->dev, "wait mdio reg(0x1f) bit15 == 1 timeout\n"); + return -EBUSY; + } + cnt = 0; + val = read_mdio_reg(rtd_phy, 0x5f); + while (!(val & BIT(15)) && cnt < 10) { + udelay(10); + val = read_mdio_reg(rtd_phy, 0x5f); + cnt++; + } + if (cnt == 10) { + dev_err(rtd_phy->dev, "wait mdio reg(0x5f) bit15 == 1 timeout\n"); + return -EBUSY; + } + + regmap_write(rtd_phy->pcie_base, PCIE_SYS_CTR, 0x00140012); + + mdelay(1); + val = read_mdio_reg(rtd_phy, 0x19); + val &= ~BIT(2); + write_mdio_reg(rtd_phy, 0x19, val); + val = read_mdio_reg(rtd_phy, 0x59); + val &= ~BIT(2); + write_mdio_reg(rtd_phy, 0x59, val); + write_mdio_reg(rtd_phy, 0x10, 0x000C); + write_mdio_reg(rtd_phy, 0x50, 0x000C); + val = read_mdio_reg(rtd_phy, 0x0D); + val &= ~BIT(6); + write_mdio_reg(rtd_phy, 0x0D, val); + val = read_mdio_reg(rtd_phy, 0x4D); + val &= ~BIT(6); + write_mdio_reg(rtd_phy, 0x4D, val); + + return 0; + +} + +static const struct phy_ops rtd13xx_pcie_phy_ops = { + .init = rtd13xx_pcie_phy_init, + .power_on = rtd13xx_pcie_phy_power_on, + .power_off = rtd13xx_pcie_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct phy_ops rtd16xxb_pcie_phy_ops = { + .init = rtd16xxb_pcie_phy_init, + .power_on = rtd13xx_pcie_phy_power_on, + .power_off = rtd13xx_pcie_phy_power_off, + .owner = THIS_MODULE, +}; + +static int rtd_pcie_phy_probe(struct platform_device *pdev) +{ + struct device_node *syscon_np; + struct rtd_pcie_phy *rtd_phy; + struct phy_ops *ops; + struct phy_provider *phy_provider; + struct phy *phy; + + rtd_phy = devm_kzalloc(&pdev->dev, sizeof(*rtd_phy), GFP_KERNEL); + if (!rtd_phy) + return -ENOMEM; + + rtd_phy->dev = &pdev->dev; + + ops = (struct phy_ops *)of_device_get_match_data(rtd_phy->dev); + + syscon_np = of_parse_phandle(rtd_phy->dev->of_node, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + rtd_phy->pcie_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(rtd_phy->pcie_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + + rtd_phy->rst_phy = devm_reset_control_get(rtd_phy->dev, "phy"); + if (rtd_phy->rst_phy == NULL) { + dev_err(rtd_phy->dev, "phy source missing or invalid\n"); + return -EINVAL; + } + + rtd_phy->rst_phy_mdio = devm_reset_control_get(rtd_phy->dev, "phy_mdio"); + if (rtd_phy->rst_phy_mdio == NULL) { + dev_err(rtd_phy->dev, "phy_mdio source missing. or invalid\n"); + return -EINVAL; + } + + phy = devm_phy_create(rtd_phy->dev, rtd_phy->dev->of_node, ops); + if (IS_ERR(phy)) { + dev_err(rtd_phy->dev, "failed to create phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, rtd_phy); + + phy_provider = devm_of_phy_provider_register(rtd_phy->dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + dev_err(rtd_phy->dev, "failed to register phy provider\n"); + + dev_info(rtd_phy->dev, "init done\n"); + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id rtd_pcie_phy_of_match[] = { + { .compatible = "realtek,rtd13xx-pcie-slot0-phy", .data = &rtd13xx_pcie_phy_ops}, + { .compatible = "realtek,rtd13xx-pcie-slot1-phy", .data = &rtd13xx_pcie_phy_ops}, + { .compatible = "realtek,rtd13xx-pcie-slot2-phy", .data = &rtd13xx_pcie_phy_ops}, + { .compatible = "realtek,rtd16xxb-pcie-slot1-phy", .data = &rtd16xxb_pcie_phy_ops}, + { .compatible = "realtek,rtd16xxb-pcie-slot2-phy", .data = &rtd16xxb_pcie_phy_ops}, + { }, +}; + +static struct platform_driver rtd_pcie_phy_driver = { + .probe = rtd_pcie_phy_probe, + .driver = { + .name = DRV_NAME, + .of_match_table = rtd_pcie_phy_of_match, + }, +}; + +module_platform_driver(rtd_pcie_phy_driver); + +MODULE_DESCRIPTION("Realtek PCIe PHY driver"); +MODULE_AUTHOR("TYChang "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/realtek/phy-rtk-sata.c b/drivers/phy/realtek/phy-rtk-sata.c new file mode 100644 index 000000000000..78e20f9814a8 --- /dev/null +++ b/drivers/phy/realtek/phy-rtk-sata.c @@ -0,0 +1,809 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek SATA3 AHCI Controller PHY Driver + * + * Copyright (C) 2020 Realtek + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "rtk-sata-phy" + +#define RTK_SATA_PHY_NUMBER 2 +#define PHY_MAX_CLK 5 +#define PHY_MAX_RST 5 + +#define REG_PHY_CTRL 0x50 +#define REG_SB2_PHY_CTRL 0x980 + +#define REG_CLKEN 0x18 +#define CLKEN_SHIFT 7 + +#define REG_SATA_CTRL 0x20 +#define OOBS_EN0 BIT(20) +#define OOBS_EN1 BIT(21) +#define OOBS_DATA0 BIT(22) +#define OOBS_DATA1 BIT(23) + +#define REG_PHY0_ADJ 0x28 +#define REG_PHY1_ADJ 0x2C + +#define REG_MDIO_CTRL 0x60 +#define MDIO_REG_SHIFT 8 +#define MDIO_PHYADDR_SHIFT 14 +#define MDIO_DATA_SHIFT 16 +#define MDIO_BUSY BIT(7) +#define MDIO_RDY BIT(4) +#define MDIO_WRITE BIT(0) + +#define TCALR_MSK GENMASK(4, 0) + +#define REG_MDIO_CTRL1 0x64 +#define REG_PHY_SPD 0x68 + +#define OOBS_K_count_limit 9 + +enum mdio_phy_addr { + PHY_ADDR_SATA1 = 0, + PHY_ADDR_SATA2 = 1, + PHY_ADDR_SATA3 = 2, + PHY_ADDR_ALL = 3, +}; + +static const struct soc_device_attribute rtk_soc_kylin[] = { + { .family = "Realtek Kylin", }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_kylin_a00[] = { + { .family = "Realtek Kylin", .revision = "A00" }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_kylin_a01[] = { + { .family = "Realtek Kylin", .revision = "A01" }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_kylin_b00[] = { + { .family = "Realtek Kylin", .revision = "B00" }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_kylin_b01[] = { + { .family = "Realtek Kylin", .revision = "B01" }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_thor[] = { + { .family = "Realtek Thor", }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_hank[] = { + { .family = "Realtek Hank", }, + { /* empty */ } +}; + +static const struct soc_device_attribute rtk_soc_stark[] = { + { .family = "Realtek Stark", }, + { /* empty */ } +}; + +struct rtk_sata_port { + unsigned int index; + unsigned int param_size; + unsigned int *param_table; + int tx_swing[PHY_ADDR_ALL]; + int tx_emphasis[PHY_ADDR_ALL]; + struct phy *phy; + struct reset_control *rsts[PHY_MAX_RST]; +}; + +struct rtk_sata_phy { + struct device *dev; + struct rtk_sata_port **phys; + + void __iomem *base; + struct regmap *phyctl; + struct regmap *crt; + + unsigned int nphys; + + struct reset_control *rsts[PHY_MAX_RST]; +}; + +static int mdio_wait_busy(void __iomem *base) +{ + unsigned int val; + int cnt = 0; + + val = readl(base + REG_MDIO_CTRL); + while((val & MDIO_BUSY) && cnt++ < 5) { + udelay(10); + val = readl(base + REG_MDIO_CTRL); + } + + if (val & MDIO_BUSY) + return -EBUSY; + return 0; +} + +static int write_mdio_reg(void __iomem *base, unsigned int phyaddr, + unsigned int reg, unsigned int value) +{ + unsigned int val; + int i; + + if (mdio_wait_busy(base)) + goto mdio_busy; + + if (phyaddr == PHY_ADDR_ALL) { + for (i = 0; i < PHY_ADDR_ALL; i++) { + val = (i << MDIO_PHYADDR_SHIFT) | + (value << MDIO_DATA_SHIFT) | + (reg << MDIO_REG_SHIFT) | + MDIO_RDY | MDIO_WRITE; + writel(val, base + REG_MDIO_CTRL); + + if (mdio_wait_busy(base)) + goto mdio_busy; + } + } else { + val = (phyaddr << MDIO_PHYADDR_SHIFT) | + (value << MDIO_DATA_SHIFT) | + (reg << MDIO_REG_SHIFT) | + MDIO_RDY | MDIO_WRITE; + writel(val, base + REG_MDIO_CTRL); + } + + return 0; +mdio_busy: + pr_err(DRV_NAME ": %s - mdio is busy\n", __func__); + return -EBUSY; +} + +__attribute__((unused)) static unsigned int +read_mdio_reg(void __iomem *base, unsigned int phyaddr, unsigned int reg) +{ + unsigned int addr; + + if (mdio_wait_busy(base)) + goto mdio_busy; + + addr = (phyaddr << MDIO_PHYADDR_SHIFT) | (reg << MDIO_REG_SHIFT); + writel(addr | MDIO_RDY, base + REG_MDIO_CTRL); + + if (mdio_wait_busy(base)) + goto mdio_busy; + + return readl(base + REG_MDIO_CTRL) >> MDIO_DATA_SHIFT; +mdio_busy: + pr_err(DRV_NAME ": %s - mdio is busy\n", __func__); + return -EBUSY; +} + +static void rtk_sata_phy_enable(struct rtk_sata_phy *priv) +{ + struct device *dev = priv->dev; + struct clk *clk; + int i; + + for (i = 0; i < PHY_MAX_CLK; i++) { + clk = of_clk_get(dev->of_node, i); + if (IS_ERR(clk)) + break; + clk_prepare_enable(clk); + } + + for (i = 0; i < PHY_MAX_RST; i++) { + if (IS_ERR(priv->rsts[i])) + break; + reset_control_deassert(priv->rsts[i]); + } +} + +static void rtk_sata_phy_disable(struct rtk_sata_phy *priv) +{ + struct device *dev = priv->dev; + struct clk *clk; + int i; + + for (i=0; irsts[i])) + break; + reset_control_assert(priv->rsts[i]); + } + for (i=0; iof_node, i); + if (IS_ERR(clk)) + break; + clk_disable_unprepare(clk); + } + + return; +} + +static void bubble_sort(unsigned int *qq, unsigned int count) +{ + unsigned int i, j; + + for (i = 1; i < count; i++) { + for (j = 0; j < (count-i); j++) { + if (qq[j] > qq[j+1]) { + unsigned int t; + + t = qq[j]; + qq[j] = qq[j+1]; + qq[j+1] = t; + } + } + } +} + +static unsigned int find_mode(unsigned int *qq, unsigned int count) +{ + unsigned int i, j; + unsigned int cnt[3]; + + cnt[0] = 1; + j = cnt[1] = cnt[2] = 0; + for (i = 0; i < (count-1); i++) { + if ((qq[i] != qq[i+1]) && (3 > j)) + j++; + cnt[j]++; + } + if (cnt[0] >= cnt[1]) { + if (cnt[0] >= cnt[2]) + return(qq[0]); + else + return(qq[cnt[0]+cnt[1]]); + } else { + if (cnt[1] >= cnt[2]) + return(qq[cnt[0]]); + else + return(qq[cnt[0]+cnt[1]]); + } +} + +static void phy_rxidle_adjust(struct phy *phy) +{ + struct rtk_sata_port *port = phy_get_drvdata(phy); + struct rtk_sata_phy *priv = dev_get_drvdata(phy->dev.parent); + void __iomem *base = priv->base; + unsigned int reg; + unsigned int PreDIV, N_code, F_code, DIV, DIVMODE, DCSB_Freq_Sel; + unsigned int preset, tmp, gap, up, down, BUS_H_KHz; + + regmap_read(priv->crt, 0x1b0, ®); + PreDIV = ((0x3 << 18) & reg) >> 18; + DIV = ((0x7 << 22) & reg) >> 22; + DIVMODE = ((0x1 << 25) & reg) >> 25; + + regmap_read(priv->crt, 0x544, ®); + N_code = ((0xff << 11) & reg) >> 11; + F_code = (0x7ff << 0) & reg; + + regmap_read(priv->crt, 0x30, ®); + DCSB_Freq_Sel = ((0x3 << 2) & reg) >> 2; + + if (DIVMODE == 0) + N_code = N_code + 4; + else + N_code = N_code + 3; + + switch (PreDIV) { + case 0: BUS_H_KHz = 100 * 270 * (N_code * 2048 + F_code); break; + case 1: BUS_H_KHz = 100 * 135 * (N_code * 2048 + F_code); break; + case 2: BUS_H_KHz = 100 * 90 * (N_code * 2048 + F_code); break; + case 3: BUS_H_KHz = 10 * 675 * (N_code * 2048 + F_code); break; + } + + BUS_H_KHz = BUS_H_KHz / 2048 / (DIV + 1); + + switch (DCSB_Freq_Sel) { + case 2: BUS_H_KHz /= 2; break; + case 3: BUS_H_KHz /= 4; break; + } + + up = 1120 * BUS_H_KHz / 10000000; + tmp = (1120 * BUS_H_KHz) % 10000000; + if (0 != tmp) up++; + + down = 1013 * BUS_H_KHz / 10000000; + tmp = (1013 * BUS_H_KHz) % 10000000; + if (0 == tmp) down--; + + gap = BUS_H_KHz / 100000; + tmp = BUS_H_KHz % 100000; + if (0 != tmp) gap++; + + preset = (0x1 << 26) | (0x1 << 24) | ((0xf & gap) << 16) | ((0xff & down) << 8) | (0xff & up); + + if (port->index == 0) + writel(preset, base + REG_PHY0_ADJ); + else if (port->index == 1) + writel(preset, base + REG_PHY1_ADJ); +} + +static int rtk_sata_phy_calibration(struct phy *phy, unsigned int addr) +{ + struct rtk_sata_port *port = phy_get_drvdata(phy); + struct rtk_sata_phy *priv = dev_get_drvdata(phy->dev.parent); + struct device *dev = priv->dev; + void __iomem *base = priv->base; + + unsigned int i, val, TCALR, taclr[OOBS_K_count_limit], cnt = 0; + + val = readl(base + REG_SATA_CTRL); + if (port->index == 0) + val = (val & ~OOBS_DATA0) | OOBS_EN0; + else + val = (val & ~OOBS_DATA1) | OOBS_EN1; + writel(val, base + REG_SATA_CTRL); + + for (i = 0; i < OOBS_K_count_limit; i++) { + val = read_mdio_reg(base, addr, 0x9); + val = (val & ~BIT(4)) | BIT(9); + write_mdio_reg(base, addr, 0x9, val); + + val = read_mdio_reg(base, addr, 0x9); + val = val & ~BIT(9); + write_mdio_reg(base, addr, 0x9, val); + + val = read_mdio_reg(base, addr, 0x9); + val = val | BIT(9); + write_mdio_reg(base, addr, 0x9, val); + + val = read_mdio_reg(base, addr, 0xd); + val = val | BIT(6); + write_mdio_reg(base, addr, 0xd, val); + + val = read_mdio_reg(base, addr, 0x1e); + val = (val & ~BIT(12) & ~BIT(14) & ~BIT(7)) | BIT(13); + write_mdio_reg(base, addr, 0x1e, val); + + val = read_mdio_reg(base, addr, 0x35); + while(val & BIT(14)) { + msleep(1); + val = read_mdio_reg(base, addr, 0x35); + if (cnt++ >= 10) + goto calibration_err; + } + + val = read_mdio_reg(base, addr, 0x1e); + val = (val & ~BIT(14) & ~BIT(7)) | BIT(13) | BIT(12); + write_mdio_reg(base, addr, 0x1e, val); + + mdelay(1); + + taclr[i] = read_mdio_reg(base, addr, 0x36) & TCALR_MSK; + } + + bubble_sort(taclr, OOBS_K_count_limit); + TCALR = find_mode(taclr, OOBS_K_count_limit); + + val = read_mdio_reg(base, addr, 0x3); + val = (val & ~(TCALR_MSK << 1)) | (TCALR << 1); + write_mdio_reg(base, addr, 0x3, val); + + val = read_mdio_reg(base, addr, 0x9); + val = val | BIT(4); + write_mdio_reg(base, addr, 0x9, val); + + val = read_mdio_reg(base, addr, 0x1e); + val = (val & ~BIT(14) & ~BIT(13) & ~BIT(7)) | BIT(13) | BIT(12); + write_mdio_reg(base, addr, 0x1e, val); + + val = readl(base + REG_SATA_CTRL); + if (port->index == 0) + val = (val & ~OOBS_EN0) | OOBS_DATA0; + else + val = (val & ~OOBS_EN1) | OOBS_DATA1; + writel(val, base + REG_SATA_CTRL); + + val = read_mdio_reg(base, addr, 0x36); + while(!(val & BIT(7))) { + msleep(1); + val = read_mdio_reg(base, addr, 0x36); + if (cnt++ >= 10) + goto calibration_err; + } + + return TCALR; + +calibration_err: + dev_err(dev, "port%d gen%d rx calibration err\n", port->index, addr+1); + return -1; +} + +static int rtk_sata_phy_init(struct phy *phy) +{ + struct rtk_sata_port *port = phy_get_drvdata(phy); + struct rtk_sata_phy *priv = dev_get_drvdata(phy->dev.parent); + struct nvmem_cell *cell; + void __iomem *base = priv->base; + unsigned int reg_phy_ctrl; + unsigned int phy_en; + unsigned int tcalr; + unsigned int reg; + unsigned char *buf; + size_t buf_size; + int i, swing[PHY_ADDR_ALL], emphasis[PHY_ADDR_ALL]; + + for (i = 0; i < PHY_MAX_RST; i++) { + if (IS_ERR(port->rsts[i])) + break; + reset_control_deassert(port->rsts[i]); + } + + if (!soc_device_match(rtk_soc_kylin)) { + reg_phy_ctrl = REG_PHY_CTRL; + phy_en = (BIT(0) | BIT(2) | BIT(4) | BIT(8)) << port->index; + + regmap_read(priv->phyctl, reg_phy_ctrl, ®); + phy_en |= reg; + regmap_update_bits(priv->phyctl, reg_phy_ctrl, phy_en, phy_en); + reg = readl(base + REG_CLKEN) | (1 << (port->index + CLKEN_SHIFT)); + writel(reg, base + REG_CLKEN); + } + + if (soc_device_match(rtk_soc_stark)) { + cell = nvmem_cell_get(priv->dev, "sata-cal"); + + buf = nvmem_cell_read(cell, &buf_size); + + swing[PHY_ADDR_SATA1] = ((buf[port->index] & 0xf) ^ 0xB) + + port->tx_swing[PHY_ADDR_SATA1]; + swing[PHY_ADDR_SATA2] = (((buf[port->index] & 0xf0) >> 4) ^ 0xB) + + port->tx_swing[PHY_ADDR_SATA2]; + swing[PHY_ADDR_SATA3] = port->tx_swing[PHY_ADDR_SATA3] + 0xc; + emphasis[PHY_ADDR_SATA1] = port->tx_emphasis[PHY_ADDR_SATA1]; + emphasis[PHY_ADDR_SATA2] = port->tx_emphasis[PHY_ADDR_SATA2]; + emphasis[PHY_ADDR_SATA3] = port->tx_emphasis[PHY_ADDR_SATA3] + 0xb; + + if (port->index == 0) + tcalr = buf[2] & TCALR_MSK; + else if (port->index == 1) + tcalr = ((buf[2] & 0xe0) >> 5) | ((buf[3] & 0x3) << 3); + + for (i = 0; i < PHY_ADDR_ALL; i++) { + if (swing[i] < 0) + swing[i] = 0; + if (swing[i] > 0xf) + swing[i] = 0xf; + if (emphasis[i] < 0) + emphasis[i] = 0; + if (emphasis[i] > 0xf) + emphasis[i] = 0xf; + } + + nvmem_cell_put(cell); + } + writel(port->index, base + REG_MDIO_CTRL1); + + if (soc_device_match(rtk_soc_kylin)) { + write_mdio_reg(base, PHY_ADDR_ALL, 0x2, 0x7000); + write_mdio_reg(base, PHY_ADDR_ALL, 0x5, 0x336a); + write_mdio_reg(base, PHY_ADDR_ALL, 0x11, 0x0); + write_mdio_reg(base, PHY_ADDR_SATA1, 0x1, 0xe070); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x1, 0xe05c); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x1, 0xe04a); + write_mdio_reg(base, PHY_ADDR_ALL, 0x6, 0x15); + write_mdio_reg(base, PHY_ADDR_ALL, 0xa, 0xc660); + write_mdio_reg(base, PHY_ADDR_ALL, 0x19, 0x2004); + write_mdio_reg(base, PHY_ADDR_ALL, 0x16, 0x770); + write_mdio_reg(base, PHY_ADDR_ALL, 0x10, 0x2900); + write_mdio_reg(base, PHY_ADDR_ALL, 0xc, 0x4000); + write_mdio_reg(base, PHY_ADDR_ALL, 0x17, 0x27); + write_mdio_reg(base, PHY_ADDR_ALL, 0x4, 0x538e); + if (soc_device_match(rtk_soc_kylin_a00) || soc_device_match(rtk_soc_kylin_a01)) { + write_mdio_reg(base, PHY_ADDR_ALL, 0x9, 0x7210); + write_mdio_reg(base, PHY_ADDR_ALL, 0x2a, 0x4000); + write_mdio_reg(base, PHY_ADDR_SATA1, 0x3, 0x2775); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x3, 0x276e); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x3, 0x276c); + } else { + write_mdio_reg(base, PHY_ADDR_ALL, 0x9, 0x4210); + write_mdio_reg(base, PHY_ADDR_ALL, 0x2a, 0x7c00); + write_mdio_reg(base, PHY_ADDR_SATA1, 0x3, 0x276f); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x3, 0x276d); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x3, 0x276d); + } + } else if (soc_device_match(rtk_soc_hank)) { + write_mdio_reg(base, PHY_ADDR_ALL, 0xe, 0x2010); + write_mdio_reg(base, PHY_ADDR_ALL, 0x6, 0x000e); + write_mdio_reg(base, PHY_ADDR_ALL, 0xa, 0x8660); + write_mdio_reg(base, PHY_ADDR_ALL, 0x26, 0x040E); + write_mdio_reg(base, PHY_ADDR_SATA1, 0x1, 0xE054); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x1, 0xE048); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x1, 0xE044); + write_mdio_reg(base, PHY_ADDR_ALL, 0xd, 0xEF54); + write_mdio_reg(base, PHY_ADDR_ALL, 0x22, 0x0013); + write_mdio_reg(base, PHY_ADDR_ALL, 0x23, 0xBB76); + write_mdio_reg(base, PHY_ADDR_ALL, 0x1b, 0xFF04); + write_mdio_reg(base, PHY_ADDR_ALL, 0x2, 0x6046); + write_mdio_reg(base, PHY_ADDR_ALL, 0xb, 0x9904); + } else if (soc_device_match(rtk_soc_stark)) { + write_mdio_reg(base, PHY_ADDR_ALL, 0x6, 0x1f); + write_mdio_reg(base, PHY_ADDR_SATA1, 0xa, 0xb670); + write_mdio_reg(base, PHY_ADDR_SATA2, 0xa, 0xb670); + write_mdio_reg(base, PHY_ADDR_SATA3, 0xa, 0xb650); + write_mdio_reg(base, PHY_ADDR_ALL, 0x1b, 0xff13); + write_mdio_reg(base, PHY_ADDR_ALL, 0x19, 0x1900); + write_mdio_reg(base, PHY_ADDR_ALL, 0x26, 0x040e); + write_mdio_reg(base, PHY_ADDR_SATA1, 0x1, 0xe055); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x1, 0xe048); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x1, 0xe046); + write_mdio_reg(base, PHY_ADDR_ALL, 0x5, 0x336a); + write_mdio_reg(base, PHY_ADDR_ALL, 0x9, 0x721c); + write_mdio_reg(base, PHY_ADDR_ALL, 0xb, 0x9904); + write_mdio_reg(base, PHY_ADDR_ALL, 0x22, 0x13); + write_mdio_reg(base, PHY_ADDR_ALL, 0x23, 0xcb66); + } + + if (port->param_size) { + for (i = 0; i < port->param_size; i++) { + reg = port->param_table[i]; + write_mdio_reg(base, + (reg >> MDIO_PHYADDR_SHIFT) & 0x3, + (reg >> MDIO_REG_SHIFT) & 0x3f, + (reg >> MDIO_DATA_SHIFT) & 0xffff); + } + } else { + if (soc_device_match(rtk_soc_kylin)) { + write_mdio_reg(base, PHY_ADDR_ALL, 0x20, 0x94aa); + write_mdio_reg(base, PHY_ADDR_ALL, 0x21, 0x88aa); + } else if (soc_device_match(rtk_soc_hank)) { + write_mdio_reg(base, PHY_ADDR_SATA1, 0x20, 0x40a5); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x20, 0x40a5); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x20, 0x40a8); + write_mdio_reg(base, PHY_ADDR_SATA1, 0x21, 0x384A); + write_mdio_reg(base, PHY_ADDR_SATA2, 0x21, 0x385A); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x21, 0xC88A); + } else if (soc_device_match(rtk_soc_stark)) { + for (i = 0; i < PHY_ADDR_ALL; i++) { + write_mdio_reg(base, i, 0x20, 0x40a0 | swing[i]); + write_mdio_reg(base, i, 0x1a, 0x1260 | emphasis[i]); + } + } + } + + if (soc_device_match(rtk_soc_stark)) { + if (!IS_ERR(priv->crt)) + phy_rxidle_adjust(phy); + + rtk_sata_phy_calibration(phy, PHY_ADDR_SATA1); + rtk_sata_phy_calibration(phy, PHY_ADDR_SATA2); + + reg = read_mdio_reg(base, PHY_ADDR_SATA3, 0x3) & ~(TCALR_MSK << 1); + reg |= ((tcalr ^ 0x18) << 1); + write_mdio_reg(base, PHY_ADDR_SATA3, 0x3, reg); + + for (i = 0; i < PHY_ADDR_ALL; i++) { + reg = read_mdio_reg(base, i, 0x20); + dev_info(priv->dev, "port%d gen%d tx swing = 0x%x\n", + port->index, i+1, reg); + reg = read_mdio_reg(base, i, 0x1a); + dev_info(priv->dev, "port%d gen%d tx emphasis = 0x%x\n", + port->index, i+1, reg); + } + } + + return 0; +} + +static int rtk_sata_phy_power_on(struct phy *phy) +{ + struct rtk_sata_port *port = phy_get_drvdata(phy); + struct rtk_sata_phy *priv = dev_get_drvdata(phy->dev.parent); + unsigned int reg; + unsigned int reg_phy_ctrl; + unsigned int phy_en; + + if (soc_device_match(rtk_soc_kylin)) { + reg_phy_ctrl = REG_SB2_PHY_CTRL; + phy_en = ((BIT(0) | BIT(2) | BIT(4)) << port->index) | BIT(8); + regmap_read(priv->phyctl, reg_phy_ctrl, ®); + phy_en |= reg; + regmap_update_bits(priv->phyctl, reg_phy_ctrl, phy_en, phy_en); + } + + return 0; +} + +static int rtk_sata_phy_power_off(struct phy *phy) +{ + struct rtk_sata_port *port = phy_get_drvdata(phy); + int i; + + for (i = 0; i < PHY_MAX_RST; i++) { + if (IS_ERR(port->rsts[i])) + break; + reset_control_assert(port->rsts[i]); + } + return 0; +} + +static struct phy_ops rtk_sata_phy_ops = { + .init = rtk_sata_phy_init, + .power_on = rtk_sata_phy_power_on, + .power_off = rtk_sata_phy_power_off, +// .set_mode = phy_rtk_sata_set_mode, + .owner = THIS_MODULE, +}; + +static struct phy *rtk_sata_phy_xlate(struct device *dev, struct of_phandle_args *args) +{ + struct rtk_sata_phy *priv = dev_get_drvdata(dev); + int i; + + for (i = 0; i < priv->nphys; i++) { + if (!priv->phys[i]) + continue; + if (priv->phys[i]->index == args->args[0]) + break; + } + if (i == priv->nphys) + return ERR_PTR(-ENODEV); + + return priv->phys[i]->phy; +} + +static int rtk_sata_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *child; + struct rtk_sata_phy *priv; + struct phy_provider *phy_provider; + struct resource *res; + unsigned int idx = 0; + int i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + dev_set_drvdata(dev, priv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) { + dev_err(dev, "failed to remap phy base regs\n"); + return PTR_ERR(priv->base); + } + + priv->phyctl = syscon_regmap_lookup_by_phandle(node, "realtek,phyctl"); + if (IS_ERR(priv->phyctl)) { + dev_err(dev, "failed to remap phy select regs\n"); + return PTR_ERR(priv->phyctl); + } + + priv->crt = syscon_regmap_lookup_by_phandle(node, "realtek,crt"); + if (IS_ERR(priv->crt)) + dev_info(dev, "can't find crt regmap\n"); + + + for (i = 0; i < PHY_MAX_RST; i++) { + priv->rsts[i] = of_reset_control_get_by_index(dev->of_node, i); + if (PTR_ERR(priv->rsts[i]) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (IS_ERR(priv->rsts[i])) + break; + } + + rtk_sata_phy_enable(priv); + + priv->nphys = of_get_child_count(dev->of_node); + if (priv->nphys == 0 || priv->nphys > RTK_SATA_PHY_NUMBER) + return -ENODEV; + + priv->phys = devm_kcalloc(dev, priv->nphys, sizeof(*priv->phys), GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + + for_each_available_child_of_node(node, child) { + struct rtk_sata_port *port; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + of_property_read_u32(child, "reg", &port->index); + + i = of_property_count_u32_elems(child, "tx-drv"); + if (i > 0) { + port->param_size = i; + port->param_table = devm_kzalloc(dev, + sizeof(unsigned int)*i, GFP_KERNEL); + if (!port->param_table) + return -ENOMEM; + of_property_read_u32_array(child, "tx-drv", + port->param_table, port->param_size); + } + + for (i = 0; i < PHY_ADDR_ALL; i++) { + of_property_read_u32_index(child, "tx-swing", i, &port->tx_swing[i]); + of_property_read_u32_index(child, "tx-emphasis", i, &port->tx_emphasis[i]); + } + + for (i = 0; i < PHY_MAX_RST; i++) { + port->rsts[i] = of_reset_control_get_exclusive_by_index(child, i); + if (PTR_ERR(port->rsts[i]) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (IS_ERR(port->rsts[i])) + break; + } + + port->phy = devm_phy_create(dev, child, &rtk_sata_phy_ops); + if (IS_ERR(port->phy)) { + dev_err(dev, "failed to create phy %d\n", port->index); + return PTR_ERR(port->phy); + } + phy_set_drvdata(port->phy, port); + priv->phys[idx++] = port; + } + + phy_provider = devm_of_phy_provider_register(dev, rtk_sata_phy_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +#ifdef CONFIG_PM_SLEEP +static int rtk_sata_phy_suspend(struct device *dev) +{ + struct rtk_sata_phy *priv = dev_get_drvdata(dev); + + rtk_sata_phy_disable(priv); + + return 0; +} + +static int rtk_sata_phy_resume(struct device *dev) +{ + struct rtk_sata_phy *priv = dev_get_drvdata(dev); + + rtk_sata_phy_enable(priv); + + return 0; +} + +static const struct dev_pm_ops rtk_sata_phy_pm_ops = { + .suspend = rtk_sata_phy_suspend, + .resume = rtk_sata_phy_resume, +}; +#else +static const struct dev_pm_ops rtk_sata_phy_pm_ops = {}; +#endif + +static const struct of_device_id rtk_sata_phy_of_match[] = { + { .compatible = "realtek,rtk-sata-phy" }, + { }, +}; + +static struct platform_driver rtk_sata_phy_driver = { + .probe = rtk_sata_phy_probe, + + .driver = { + .name = DRV_NAME, + .of_match_table = rtk_sata_phy_of_match, + .pm = &rtk_sata_phy_pm_ops, + }, +}; +module_platform_driver(rtk_sata_phy_driver); + +MODULE_DESCRIPTION("Realtek SATA PHY driver"); +MODULE_AUTHOR("Simon HSU "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 815095326e2d..37ac0733c31a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -385,6 +385,9 @@ source "drivers/pinctrl/nomadik/Kconfig" source "drivers/pinctrl/nuvoton/Kconfig" source "drivers/pinctrl/pxa/Kconfig" source "drivers/pinctrl/qcom/Kconfig" +if SYNO_LSP_RTD1619B +source "drivers/pinctrl/realtek/Kconfig" +endif # SYNO_LSP_RTD1619B source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/samsung/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f53933b2ff02..a2d6cbbe0607 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -59,6 +59,9 @@ obj-y += nomadik/ obj-$(CONFIG_ARCH_NPCM7XX) += nuvoton/ obj-$(CONFIG_PINCTRL_PXA) += pxa/ obj-$(CONFIG_ARCH_QCOM) += qcom/ +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_ARCH_REALTEK) += realtek/ +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_PINCTRL_RENESAS) += renesas/ obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ obj-$(CONFIG_PINCTRL_SPEAR) += spear/ diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig index 28e5f824ba45..e8df55f11182 100644 --- a/drivers/pinctrl/intel/Kconfig +++ b/drivers/pinctrl/intel/Kconfig @@ -144,3 +144,12 @@ config PINCTRL_TIGERLAKE This pinctrl driver provides an interface that allows configuring of Intel Tiger Lake PCH pins and using them as GPIOs. endif + +config SYNO_PINCTRL_LEWISBURG + tristate "Intel Lweisburg pinctrl and GPIO driver" + depends on ACPI + depends on (SYNO_PURLEY || SYNO_SKYLAKED) + select PINCTRL_INTEL + help + LEWISBURG pinctrl driver provides an interface that allows + configuring of SoC pins and using them as GPIOs. diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile index 1c1c316f98b9..d75521ef1fee 100644 --- a/drivers/pinctrl/intel/Makefile +++ b/drivers/pinctrl/intel/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_PINCTRL_JASPERLAKE) += pinctrl-jasperlake.o obj-$(CONFIG_PINCTRL_LEWISBURG) += pinctrl-lewisburg.o obj-$(CONFIG_PINCTRL_SUNRISEPOINT) += pinctrl-sunrisepoint.o obj-$(CONFIG_PINCTRL_TIGERLAKE) += pinctrl-tigerlake.o +obj-$(CONFIG_SYNO_PINCTRL_LEWISBURG)+= syno-pinctrl-lewisburg.o diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index b6ef1911c1dd..0bc7f44e1814 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Intel pinctrl/GPIO core driver. @@ -1428,8 +1431,13 @@ static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) return 0; } +#ifdef MY_DEF_HERE +int intel_pinctrl_probe(struct platform_device *pdev, + const struct intel_pinctrl_soc_data *soc_data) +#else /* MY_DEF_HERE */ static int intel_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data) +#endif /* MY_DEF_HERE */ { struct intel_pinctrl *pctrl; int i, ret, irq; @@ -1516,6 +1524,9 @@ static int intel_pinctrl_probe(struct platform_device *pdev, return 0; } +#ifdef MY_DEF_HERE +EXPORT_SYMBOL_GPL(intel_pinctrl_probe); +#endif /* MY_DEF_HERE */ int intel_pinctrl_probe_by_hid(struct platform_device *pdev) { diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h index ad34b7a3f6ed..b14268f3ad5e 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.h +++ b/drivers/pinctrl/intel/pinctrl-intel.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Core pinctrl/GPIO driver for Intel GPIO controllers @@ -240,6 +243,11 @@ struct intel_pinctrl { int irq; }; +#ifdef MY_DEF_HERE +int intel_pinctrl_probe(struct platform_device *pdev, + const struct intel_pinctrl_soc_data *soc_data); +#endif /* MY_DEF_HERE */ + int intel_pinctrl_probe_by_hid(struct platform_device *pdev); int intel_pinctrl_probe_by_uid(struct platform_device *pdev); diff --git a/drivers/pinctrl/intel/syno-pinctrl-lewisburg.c b/drivers/pinctrl/intel/syno-pinctrl-lewisburg.c new file mode 100644 index 000000000000..7eced3768c9b --- /dev/null +++ b/drivers/pinctrl/intel/syno-pinctrl-lewisburg.c @@ -0,0 +1,472 @@ +/* + * Intel Lewisburg PCH pinctrl/GPIO driver + * + * Copyright (C) 2016, Synology Corporation + * Authors: Ricky Chang + * + * 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 "pinctrl-intel.h" + +#define LWB_PAD_OWN 0x020 +#define LWB_PADCFGLOCK 0x060 +#define LWB_HOSTSW_OWN 0x080 +#define LWB_GPI_IE 0x100 + +#define LWB_COMMUNITY(s, e) \ + { \ + .padown_offset = LWB_PAD_OWN, \ + .padcfglock_offset = LWB_PADCFGLOCK, \ + .hostown_offset = LWB_HOSTSW_OWN, \ + .ie_offset = LWB_GPI_IE, \ + .gpp_size = 24, \ + .pin_base = (s), \ + .npins = ((e) - (s) + 1), \ + } + +/* Lewisburg */ +static const struct pinctrl_pin_desc lwb_cm0_pins[] = { + /*Community 0 Registers are for GPP_A, GPP_B and GPP_F groups, refer to lewisburg EDS*/ + /* GPP_A */ + PINCTRL_PIN(0, "RCINB"), + PINCTRL_PIN(1, "LAD_0"), + PINCTRL_PIN(2, "LAD_1"), + PINCTRL_PIN(3, "LAD_2"), + PINCTRL_PIN(4, "LAD_3"), + PINCTRL_PIN(5, "LFRAMEB"), + PINCTRL_PIN(6, "SERIQ"), + PINCTRL_PIN(7, "PIRQAB"), + PINCTRL_PIN(8, "CLKRUNB"), + PINCTRL_PIN(9, "CLKOUT_LPC_0"), + PINCTRL_PIN(10, "CLKOUT_LPC_1"), + PINCTRL_PIN(11, "PMEB"), + PINCTRL_PIN(12, "BM_BUSYB"), + PINCTRL_PIN(13, "SUSWARNB_SUS_PWRDNACK"), + PINCTRL_PIN(14, "SUS_STATB"), + PINCTRL_PIN(15, "SUSACKB"), + PINCTRL_PIN(16, "CLKOUT_LPC2"), + PINCTRL_PIN(17, "PU_UPI_SLOW_MODE_N"), + PINCTRL_PIN(18, "PD_BIOS_ADV_FUNCTIONS"), + PINCTRL_PIN(19, "FM_ME_RCVR_N"), + PINCTRL_PIN(20, "GPP_A20"), + PINCTRL_PIN(21, "GPP_A21"), + PINCTRL_PIN(22, "GPP_A22"), + PINCTRL_PIN(23, "GPP_A23"), + /* GPP_B */ + PINCTRL_PIN(24, "CORE_VID_0"), + PINCTRL_PIN(25, "CORE_VID_1"), + PINCTRL_PIN(26, "PU_QAT_ENABLE_N"), + PINCTRL_PIN(27, "GPP_B3"), + PINCTRL_PIN(28, "GPP_B4"), + PINCTRL_PIN(29, "GPP_B5"), + PINCTRL_PIN(30, "GPP_B6"), + PINCTRL_PIN(31, "GPP_B7"), + PINCTRL_PIN(32, "GPP_B8"), + PINCTRL_PIN(33, "uP_PWR_BTN_N"), + PINCTRL_PIN(34, "FP_RST_BTN_N"), + PINCTRL_PIN(35, "FAN_BMC_R_PWM0"), + PINCTRL_PIN(36, "TP_SLP_S0_N"), + PINCTRL_PIN(37, "PLTRSTB"), + PINCTRL_PIN(38, "FM_PCH_BIOS_RCVR_SPKR"), + PINCTRL_PIN(39, "FM_PERST_SEL_BIT0"), + PINCTRL_PIN(40, "FM_PERST_SEL_BIT1"), + PINCTRL_PIN(41, "FM_PERST_SEL_BIT2"), + PINCTRL_PIN(42, "PU_NO_REBOOT"), + PINCTRL_PIN(43, "FM_PERST_SEL_BIT3"), + PINCTRL_PIN(44, "FM_BIOS_POST_CMPLT_N"), + PINCTRL_PIN(45, "FM_BIOS_SPI_BMC_CTRL"), + PINCTRL_PIN(46, "PD_PCH_BOOT_BIOS_DEVICE"), + PINCTRL_PIN(47, "FM_PCH_BMC_THERMTRIP_EXI_STRAP_N"), + /* GPP_F */ + PINCTRL_PIN(48, "GPP_F0"), + PINCTRL_PIN(49, "GPP_F1"), + PINCTRL_PIN(50, "GPP_F2"), + PINCTRL_PIN(51, "GPP_F3"), + PINCTRL_PIN(52, "GPP_F4"), + PINCTRL_PIN(53, "FM_SYS_THROTTLE_LVC3"), + PINCTRL_PIN(54, "JTAG_PCH_PLD_TCK_R"), + PINCTRL_PIN(55, "JTAG_PCH_PLD_TDI"), + PINCTRL_PIN(56, "JTAG_PCH_PLD_TMS"), + PINCTRL_PIN(57, "JTAG_PCH_PLD_TDO"), + PINCTRL_PIN(58, "GPP_F10"), + PINCTRL_PIN(59, "GPP_F11"), + PINCTRL_PIN(60, "GPP_F12"), + PINCTRL_PIN(61, "GPP_F13"), + PINCTRL_PIN(62, "GPP_F14"), + PINCTRL_PIN(63, "FM_FORCE_ADR_N"), + PINCTRL_PIN(64, "FM_IE_DISABLE_N"), + PINCTRL_PIN(65, "GPP_F17"), + PINCTRL_PIN(66, "FM_MEM_THERM_EVENT_PCH_N"), + PINCTRL_PIN(67, "GPP_F19"), + PINCTRL_PIN(68, "GPP_F20"), + PINCTRL_PIN(69, "GPP_F21"), + PINCTRL_PIN(70, "GPP_F22"), + PINCTRL_PIN(71, "GPP_F23"), +}; +static const struct intel_community lwb_cm0_communities[] = { + LWB_COMMUNITY(0, 71), +}; + +static const struct intel_pinctrl_soc_data lwb_cm0_soc_data = { + .uid = "1", + .pins = lwb_cm0_pins, + .npins = ARRAY_SIZE(lwb_cm0_pins), + .communities = lwb_cm0_communities, + .ncommunities = ARRAY_SIZE(lwb_cm0_communities), +}; + + +static const struct pinctrl_pin_desc lwb_cm1_pins[] = { + /*Community 1 Registers are for GPP_C, GPP_D, and GPP_E groups.*/ + /* GPP_C */ + PINCTRL_PIN(0, "SMBCLK"), + PINCTRL_PIN(1, "SMBDATA"), + PINCTRL_PIN(2, "PU_PCH_TLS_ENABLE_STRAP"), + PINCTRL_PIN(3, "SML0CLK"), + PINCTRL_PIN(4, "SML0DATA"), + PINCTRL_PIN(5, "SML0ALERTB"), + PINCTRL_PIN(6, "SMB_PMBUS_BMC_STBY_LVC3_CLK_R2"), + PINCTRL_PIN(7, "SMB_PMBUS_BMC_STBY_LVC3_DATA_R2"), + PINCTRL_PIN(8, "FM_PASSWORD_CLEAR_N"), + PINCTRL_PIN(9, "FM_MFG_MODE"), + PINCTRL_PIN(10, "FM_PCH_SATA_RAID_KEY"), + PINCTRL_PIN(11, "PU_GPP_C_11_UART0_CTSB"), + PINCTRL_PIN(12, "FM_BOARD_REV_ID0"), + PINCTRL_PIN(13, "FM_BOARD_REV_ID1"), + PINCTRL_PIN(14, "IRQ_BMC_PCH_SCI_LPC_N"), + PINCTRL_PIN(15, "GPP_C15"), + PINCTRL_PIN(16, "GPP_C16"), + PINCTRL_PIN(17, "GPP_C17"), + PINCTRL_PIN(18, "GPP_C18"), + PINCTRL_PIN(19, "GPP_C19"), + PINCTRL_PIN(20, "FM_THROTTLE_N"), + PINCTRL_PIN(21, "RST_PCH_MIC_MUX_R_N"), + PINCTRL_PIN(22, "IRQ_BMC_PCH_SMI_LPC_N"), + PINCTRL_PIN(23, "FM_CPU_CATERR_DLY_LVT3_N"), + /* GPP_D */ + PINCTRL_PIN(24, "IRQ_BMC_PCH_NMI"), + PINCTRL_PIN(25, "FP_PWR_LED_N"), + PINCTRL_PIN(26, "TP_PCH_GPP_D_2"), + PINCTRL_PIN(27, "FP_LD_DEFAULT_RST_BTN_PCH_N"), + PINCTRL_PIN(28, "FM_PLD_PCH_DATA"), + PINCTRL_PIN(29, "SPI_BMC_BOOT_CS0_N"), + PINCTRL_PIN(30, "GPP_D6"), + PINCTRL_PIN(31, "FM_BMC_CPLD_GPO"), + PINCTRL_PIN(32, "GPP_D8"), + PINCTRL_PIN(33, "PU_GPP_D_9_ISH_SPI_CSB"), + PINCTRL_PIN(34, "PU_GPP_D_10_ISH_SPI_CLK"), + PINCTRL_PIN(35, "PU_GPP_D_11_ISH_SPI_MISO"), + PINCTRL_PIN(36, "TP_SGPIO_SSATA_DATAOUT1"), + PINCTRL_PIN(37, "SML0BCLK"), + PINCTRL_PIN(38, "SML0BDATA"), + PINCTRL_PIN(39, "GPP_D15"), + PINCTRL_PIN(40, "GPP_D16"), + PINCTRL_PIN(41, "BUZZER_MUTE_BOT_PCH_GPO"), + PINCTRL_PIN(42, "BUZZER_MUTE_BOT_PCH_GPI"), + PINCTRL_PIN(43, "FM_PS_PWROK_DLY_SEL"), + PINCTRL_PIN(44, "LED_BMC_HB_LED_N"), + PINCTRL_PIN(45, "SP2_BMC_CM_UART_RX"), + PINCTRL_PIN(46, "SP2_BMC_CM_UART_TX"), + PINCTRL_PIN(47, "GPP_D23"), + /* GPP_E */ + PINCTRL_PIN(48, "GPP_E0"), + PINCTRL_PIN(49, "GPP_E1"), + PINCTRL_PIN(50, "GPP_E2"), + PINCTRL_PIN(51, "FM_ADR_TRIGGER_N"), + PINCTRL_PIN(52, "FM_CPU_ERR2_LVT3_N"), + PINCTRL_PIN(53, "FM_CPU_MSMI_LVT3_N"), + PINCTRL_PIN(54, "GPP_E6"), + PINCTRL_PIN(55, "FM_ADR_SMI_GPIO_N"), + PINCTRL_PIN(56, "RST_PCH_SYSRST_BTN_OUT_N"), + PINCTRL_PIN(57, "FM_USB_OC0_REAR_N"), + PINCTRL_PIN(58, "FM_USB_OC1_BRDG_N"), + PINCTRL_PIN(59, "FM_PCH_PWRBTN_OUT_N"), + PINCTRL_PIN(60, "GPP_E12"), +}; + +static const struct intel_community lwb_cm1_communities[] = { + LWB_COMMUNITY(0, 60), +}; + +static const struct intel_pinctrl_soc_data lwb_cm1_soc_data = { + .uid = "2", + .pins = lwb_cm1_pins, + .npins = ARRAY_SIZE(lwb_cm1_pins), + .communities = lwb_cm1_communities, + .ncommunities = ARRAY_SIZE(lwb_cm1_communities), +}; + + +static const struct pinctrl_pin_desc lwb_cm2_pins[] = { + /*Community 2 Registers are for GPP_DSW group.*/ + /* GPD */ + PINCTRL_PIN(0, "FM_PCH_HOOK2_N"), + PINCTRL_PIN(1, "PU_ACPRESENT"), + PINCTRL_PIN(2, "PU_LAN_WAKE_N"), + PINCTRL_PIN(3, "FM_SLPS3_N"), + PINCTRL_PIN(4, "FM_SLPS3_N"), + PINCTRL_PIN(5, "FM_SLPS4_N"), + PINCTRL_PIN(6, "TP_SLPA_N"), + PINCTRL_PIN(7, "TP_GPD_7"), + PINCTRL_PIN(8, "TP_PCH_GPD_8"), + PINCTRL_PIN(9, "TP_SLP_WLAN"), + PINCTRL_PIN(10, "TP_SLPS5_N"), + PINCTRL_PIN(11, "TP_GPD_11_GBEPHY"), +}; +static const struct intel_community lwb_cm2_communities[] = { + LWB_COMMUNITY(0, 11), +}; + +static const struct intel_pinctrl_soc_data lwb_cm2_soc_data = { + .uid = "3", + .pins = lwb_cm2_pins, + .npins = ARRAY_SIZE(lwb_cm2_pins), + .communities = lwb_cm2_communities, + .ncommunities = ARRAY_SIZE(lwb_cm2_communities), +}; + +static const struct pinctrl_pin_desc lwb_cm3_pins[] = { + /*Community 3 Registers are for GPP_I group.*/ + /* GPP_I */ + PINCTRL_PIN(0, "PU_GPP_I_0_DDSP_HPD_0"), + PINCTRL_PIN(1, "PD_GPP_I_1_DDSP_HPD_1"), + PINCTRL_PIN(2, "GPP_I2"), + PINCTRL_PIN(3, "GPP_I3"), + PINCTRL_PIN(4, "IRQ_DIMM_SAVE_LVT3_N"), + PINCTRL_PIN(5, "GPP_I5"), + PINCTRL_PIN(6, "GPP_I6"), + PINCTRL_PIN(7, "IRQ_DIMM_SAVE_LVT3_N"), + PINCTRL_PIN(8, "GPP_I8"), + PINCTRL_PIN(9, "GPP_I9"), + PINCTRL_PIN(10, "REAR_USB3_PWR_EN"), +}; +static const struct intel_community lwb_cm3_communities[] = { + LWB_COMMUNITY(0, 10), +}; + +static const struct intel_pinctrl_soc_data lwb_cm3_soc_data = { + .uid = "4", + .pins = lwb_cm3_pins, + .npins = ARRAY_SIZE(lwb_cm3_pins), + .communities = lwb_cm3_communities, + .ncommunities = ARRAY_SIZE(lwb_cm3_communities), +}; + +static const struct pinctrl_pin_desc lwb_cm4_pins[] = { + /*Community 4 Registers are for GPP_J,and GPP_K groups.*/ + /* GPP_J */ + PINCTRL_PIN(0, "GPP_J0"), + PINCTRL_PIN(1, "GPP_J1"), + PINCTRL_PIN(2, "GPP_J2"), + PINCTRL_PIN(3, "GPP_J3"), + PINCTRL_PIN(4, "GPP_J4"), + PINCTRL_PIN(5, "GPP_J5"), + PINCTRL_PIN(6, "GPP_J6"), + PINCTRL_PIN(7, "GPP_J7"), + PINCTRL_PIN(8, "PU_PCH_GPP_J_8"), + PINCTRL_PIN(9, "PU_PCH_GPP_J_9"), + PINCTRL_PIN(10, "PU_PCH_GPP_J_10"), + PINCTRL_PIN(11, "PU_PCH_GPP_J_11"), + PINCTRL_PIN(12, "PU_PCH_GPP_J_12"), + PINCTRL_PIN(13, "PU_PCH_GPP_J_13"), + PINCTRL_PIN(14, "PU_PCH_GPP_J_14"), + PINCTRL_PIN(15, "PU_PCH_GPP_J_15"), + PINCTRL_PIN(16, "FM_CPU_ERR0_LVT3_N"), + PINCTRL_PIN(17, "FM_CPU_ERR1_LVT3_N"), + PINCTRL_PIN(18, "FM_CPU1_THERMTRIP_LATCH_LVT3_N"), + PINCTRL_PIN(19, "FM_CPU0_THERMTRIP_LATCH_LVT3_N"), + PINCTRL_PIN(20, "FM_CPU_CATERR_PLD_LVT3_N"), + PINCTRL_PIN(21, "GPP_J21"), + PINCTRL_PIN(22, "GPP_J22"), + PINCTRL_PIN(23, "GPP_J23"), + /* GPP_K */ + PINCTRL_PIN(24, "PD_CLK_50M_CKMNG_PCH"), + PINCTRL_PIN(25, "IRQ_CPU0_PROCHOT_R_N"), + PINCTRL_PIN(26, "IRQ_CPU1_PROCHOT_R_N"), + PINCTRL_PIN(27, "IRQ_PVDDQ_CPU1_DEF_VRHOT_LVC3_N"), + PINCTRL_PIN(28, "IRQ_PVDDQ_CPU1_ABC_VRHOT_LVC3_N"), + PINCTRL_PIN(29, "IRQ_PVDDQ_CPU0_DEF_VRHOT_LVC3_N"), + PINCTRL_PIN(30, "IRQ_PVDDQ_CPU0_ABC_VRHOT_LVC3_N"), + PINCTRL_PIN(31, "PD_RMII_PCH_BMC_RX_ER"), + PINCTRL_PIN(32, "PD_RMII_PCH_ARB_IN"), + PINCTRL_PIN(33, "PU_RMII_PCH_ARB_OUT"), + PINCTRL_PIN(34, "RST_PCIE_PCH_PERST_N"), +}; +static const struct intel_community lwb_cm4_communities[] = { + LWB_COMMUNITY(0, 34), +}; + +static const struct intel_pinctrl_soc_data lwb_cm4_soc_data = { + .uid = "5", + .pins = lwb_cm4_pins, + .npins = ARRAY_SIZE(lwb_cm4_pins), + .communities = lwb_cm4_communities, + .ncommunities = ARRAY_SIZE(lwb_cm4_communities), +}; + +static const struct pinctrl_pin_desc lwb_cm5_pins[] = { + /*Community 5 Registers are for GPP_G, GPP_H and GPP_L groups.*/ + /* GPP_G */ + PINCTRL_PIN(0, "FAN_BMC_TACH0"), + PINCTRL_PIN(1, "FAN_BMC_TACH1"), + PINCTRL_PIN(2, "FAN_BMC_TACH2"), + PINCTRL_PIN(3, "FAN_BMC_TACH3"), + PINCTRL_PIN(4, "IRQ_PVCCIN_CPU0_VRHOT_LVC3_N"), + PINCTRL_PIN(5, "IRQ_PVCCIN_CPU1_VRHOT_LVC3_N"), + PINCTRL_PIN(6, "FM_CPU0_FIVR_FAULT_LVT3_N"), + PINCTRL_PIN(7, "FM_CPU1_FIVR_FAULT_LVT3_N"), + PINCTRL_PIN(8, "FAN_BMC_R_PWM0"), + PINCTRL_PIN(9, "FAN_BMC_R_PWM1"), + PINCTRL_PIN(10, "FAN_BMC_R_PWM2"), + PINCTRL_PIN(11, "FAN_BMC_R_PWM3"), + PINCTRL_PIN(12, "FM_BOARD_SKU_ID0"), + PINCTRL_PIN(13, "FM_BOARD_SKU_ID1"), + PINCTRL_PIN(14, "FM_BOARD_SKU_ID2"), + PINCTRL_PIN(15, "FM_BOARD_SKU_ID3"), + PINCTRL_PIN(16, "FM_BOARD_SKU_ID4"), + PINCTRL_PIN(17, "FM_ADR_COMPLETE"), + PINCTRL_PIN(18, "IRQ_NMI_EVENT_N"), + PINCTRL_PIN(19, "IRQ_SMI_ACTIVE_N"), + PINCTRL_PIN(20, "IRQ_SML1_PMBUS_ALERT_N"), + PINCTRL_PIN(21, "PCH_SYNO_SASCARD_CTRL"), + PINCTRL_PIN(22, "GPP_G22"), + PINCTRL_PIN(23, "PCH_PHY_RST_RTL8211E_N"), + /* GPP_H */ + PINCTRL_PIN(24, "FM_BACKUP_BIOS_SEL_N"), + PINCTRL_PIN(25, "CPLD_LED_CTRL_N"), + PINCTRL_PIN(26, "LED_CONTROL_0"), + PINCTRL_PIN(27, "LED_CONTROL_1"), + PINCTRL_PIN(28, "LED_CONTROL_2"), + PINCTRL_PIN(29, "LED_CONTROL_3"), + PINCTRL_PIN(30, "LED_CONTROL_4"), + PINCTRL_PIN(31, "LED_CONTROL_5"), + PINCTRL_PIN(32, "LED_CONTROL_6"), + PINCTRL_PIN(33, "LED_CONTROL_7"), + PINCTRL_PIN(34, "SMB_SML2_VR_CLK"), + PINCTRL_PIN(35, "SMB_SML2_VR_DIA"), + PINCTRL_PIN(36, "PU_ESPI_FLASH_MODE"), + PINCTRL_PIN(37, "SMB_SENSOR_STBY_LVC3_SCL_R1"), + PINCTRL_PIN(38, "SMB_SENSOR_STBY_LVC3_SDA_R1"), + PINCTRL_PIN(39, "PU_ADR_TIMER_HOLD_OFF_N"), + PINCTRL_PIN(40, "SMB_SMLINK4_STBY_LVC3_SCL_R1"), + PINCTRL_PIN(41, "SMB_SMLINK4_STBY_LVC3_SDA_R1"), + PINCTRL_PIN(42, "IRQ_SML4_ALERT_R_N"), + PINCTRL_PIN(43, "FM_PCH_BMC_THERMTRIP_N"), + PINCTRL_PIN(44, "FM_PCH_LAN0_DISABLE_N"), + PINCTRL_PIN(45, "FM_PCH_LAN1_DISABLE_N"), + PINCTRL_PIN(46, "LAN2_DEV_OFF_L"), + PINCTRL_PIN(47, "LAN1_DEV_OFF_L"), + /* GPP_L */ + PINCTRL_PIN(48, "XDP_VISA_2CH0_D0"), + PINCTRL_PIN(49, "XDP_VISA_2CH0_D1"), + PINCTRL_PIN(50, "XDP_VISA_2CH0_D2"), + PINCTRL_PIN(51, "XDP_VISA_2CH0_D3"), + PINCTRL_PIN(52, "XDP_VISA_2CH0_D4"), + PINCTRL_PIN(53, "XDP_VISA_2CH0_D5"), + PINCTRL_PIN(54, "XDP_VISA_2CH0_D6"), + PINCTRL_PIN(55, "XDP_VISA_2CH0_D7"), + PINCTRL_PIN(56, "XDP_VISA_2CH0_CLK"), + PINCTRL_PIN(57, "XDP_VISA_2CH1_D0"), + PINCTRL_PIN(58, "XDP_VISA_2CH1_D1"), + PINCTRL_PIN(59, "XDP_VISA_2CH1_D2"), + PINCTRL_PIN(60, "XDP_VISA_2CH1_D3"), + PINCTRL_PIN(61, "XDP_VISA_2CH1_D4"), + PINCTRL_PIN(62, "XDP_VISA_2CH1_D5"), + PINCTRL_PIN(63, "XDP_VISA_2CH1_D6"), + PINCTRL_PIN(64, "XDP_VISA_2CH1_D7"), + PINCTRL_PIN(65, "XDP_VISA_2CH1_CLK"), +}; +static const struct intel_community lwb_cm5_communities[] = { + LWB_COMMUNITY(0, 65), +}; + +static const struct intel_pinctrl_soc_data lwb_cm5_soc_data = { + .uid = "6", + .pins = lwb_cm5_pins, + .npins = ARRAY_SIZE(lwb_cm5_pins), + .communities = lwb_cm5_communities, + .ncommunities = ARRAY_SIZE(lwb_cm5_communities), +}; + +static const struct intel_pinctrl_soc_data *lwb_soc_data[] = { + &lwb_cm0_soc_data, + &lwb_cm1_soc_data, + &lwb_cm2_soc_data, + &lwb_cm3_soc_data, + &lwb_cm4_soc_data, + &lwb_cm5_soc_data, + NULL, +}; + +static const struct acpi_device_id lwb_pinctrl_acpi_match[] = { + { "INT5566", (kernel_ulong_t)lwb_soc_data }, + { } +}; +MODULE_DEVICE_TABLE(acpi, lwb_pinctrl_acpi_match); + +static int lwb_pinctrl_probe(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *soc_data = NULL; + const struct intel_pinctrl_soc_data **soc_table = NULL; + const struct acpi_device_id *id; + struct acpi_device *adev; + int i; + + adev = ACPI_COMPANION(&pdev->dev); + if (!adev) + return -ENODEV; + + id = acpi_match_device(lwb_pinctrl_acpi_match, &pdev->dev); + if (!id || !id->driver_data) + return -ENODEV; + + soc_table = (const struct intel_pinctrl_soc_data **)id->driver_data; + + for (i = 0; soc_table[i]; i++) { + if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) { + soc_data = soc_table[i]; + break; + } + } + + return intel_pinctrl_probe(pdev, soc_data); +} + +static const struct dev_pm_ops lwb_pinctrl_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend_noirq, + intel_pinctrl_resume_noirq) +}; + +static struct platform_driver lwb_pinctrl_driver = { + .probe = lwb_pinctrl_probe, + .driver = { + .name = "lewisburg-pinctrl", + .acpi_match_table = lwb_pinctrl_acpi_match, + .pm = &lwb_pinctrl_pm_ops, + }, +}; + +static int __init lwb_pinctrl_init(void) +{ + return platform_driver_register(&lwb_pinctrl_driver); +} +subsys_initcall(lwb_pinctrl_init); + +static void __exit lwb_pinctrl_exit(void) +{ + platform_driver_unregister(&lwb_pinctrl_driver); +} +module_exit(lwb_pinctrl_exit); + +MODULE_AUTHOR("Ricky Chang "); +MODULE_DESCRIPTION("Intel Rewisurg PCH pinctrl/GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/realtek/Kconfig b/drivers/pinctrl/realtek/Kconfig new file mode 100644 index 000000000000..6652e21865ea --- /dev/null +++ b/drivers/pinctrl/realtek/Kconfig @@ -0,0 +1,12 @@ + +config PINCTRL_RTD + bool "Realtek DHC pin controller driver" + depends on ARCH_REALTEK + default y + select PINMUX + select GENERIC_PINCONF + +config PINCTRL_RTD_SELFTEST + bool "Realtek DHC pin controller driver self test" + depends on PINCTRL_RTD + default n diff --git a/drivers/pinctrl/realtek/Makefile b/drivers/pinctrl/realtek/Makefile new file mode 100644 index 000000000000..036ecdc821b5 --- /dev/null +++ b/drivers/pinctrl/realtek/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_PINCTRL_RTD) += pinctrl-rtd.o diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c new file mode 100644 index 000000000000..a9851a2efec1 --- /dev/null +++ b/drivers/pinctrl/realtek/pinctrl-rtd.c @@ -0,0 +1,749 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Realtek DHC pin controller driver + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * Copyright (c) 2017 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../core.h" +#include "../pinctrl-utils.h" + +struct rtd_pin_group_desc { + const char *name; + const unsigned int *pins; + unsigned int num_pins; +}; + +struct rtd_pin_func_desc { + const char *name; + const char * const *groups; + unsigned int num_groups; +}; + +struct rtd_pin_mux_desc { + const char *name; + u32 mux_value; +}; + +struct rtd_pin_config_desc { + const char *name; + unsigned int reg_offset; + unsigned int base_bit; + unsigned int pud_en_offset; + unsigned int pud_sel_offset; + unsigned int curr_offset; + unsigned int smt_offset; + unsigned int power_offset; + unsigned int curr_type; +}; + +struct rtd_pin_sconfig_desc { + const char *name; + unsigned int reg_offset; + unsigned int dcycle_offset; + unsigned int dcycle_maskbits; + unsigned int ndrive_offset; + unsigned int ndrive_maskbits; + unsigned int pdrive_offset; + unsigned int pdrive_maskbits; +}; + + + +struct rtd_pin_desc { + const char *name; + unsigned int mux_offset; + u32 mux_mask; + const struct rtd_pin_mux_desc *functions; +}; + +struct rtd_pin_reg_list { + unsigned int reg_offset; + unsigned int val; +}; + + +#define SHIFT_LEFT(_val, _shift) (_val << _shift) + +#define RTK_PIN_MUX(_name, _mux_off, _mux_mask, ...) \ + { \ + .name = # _name, \ + .mux_offset = _mux_off, \ + .mux_mask = _mux_mask, \ + .functions = (const struct rtd_pin_mux_desc []) { \ + __VA_ARGS__, { } \ + }, \ + } + +#define RTK_PIN_CONFIG(_name, _reg_off, _base_bit, _pud_en_off, \ + _pud_sel_off, _curr_off, _smt_off, _pow_off, _curr_type) \ + { \ + .name = # _name, \ + .reg_offset = _reg_off, \ + .base_bit = _base_bit, \ + .pud_en_offset = _pud_en_off, \ + .pud_sel_offset = _pud_sel_off, \ + .curr_offset = _curr_off, \ + .smt_offset = _smt_off, \ + .power_offset = _pow_off, \ + .curr_type = _curr_type, \ + } + +#define RTK_PIN_SCONFIG(_name, _reg_off, _d_offset, _d_mask, _n_offset, _n_mask, _p_offset, _p_mask) \ + { \ + .name = # _name, \ + .reg_offset = _reg_off, \ + .dcycle_offset = _d_offset, \ + .dcycle_maskbits = _d_mask, \ + .ndrive_offset = _n_offset, \ + .ndrive_maskbits = _n_mask, \ + .pdrive_offset = _p_offset, \ + .pdrive_maskbits = _p_mask, \ + } + + +#define RTK_PIN_FUNC(_mux_val, _name) \ + { \ + .name = _name, \ + .mux_value = _mux_val, \ + } + +struct rtd_pinctrl_desc { + const struct pinctrl_pin_desc *pins; + unsigned int num_pins; + const struct rtd_pin_group_desc *groups; + unsigned int num_groups; + const struct rtd_pin_func_desc *functions; + unsigned int num_functions; + const struct rtd_pin_desc *muxes; + unsigned int num_muxes; + const struct rtd_pin_config_desc *configs; + unsigned int num_configs; + const struct rtd_pin_sconfig_desc *sconfigs; + unsigned int num_sconfigs; + struct rtd_pin_reg_list *lists; + unsigned int num_regs; +}; + +#define PCONF_UNSUPP 0xffffffff +#define PADDRI_4_8 1 +#define PADDRI_2_4 0 + +#include "pinctrl-rtd1319.h" +#include "pinctrl-rtd1619b.h" + + +struct rtd_pinctrl { + struct pinctrl_dev *pcdev; + void __iomem *base; + struct pinctrl_desc desc; + const struct rtd_pinctrl_desc *info; +}; + +/* custom pinconf parameters */ +#define RTD_P_DRIVE (PIN_CONFIG_END + 1) +#define RTD_N_DRIVE (PIN_CONFIG_END + 2) +#define RTD_D_CYCLE (PIN_CONFIG_END + 3) + + +static const struct pinconf_generic_params rtd_custom_bindings[] = { + {"realtek,pdrive", RTD_P_DRIVE, 0}, + {"realtek,ndrive", RTD_N_DRIVE, 0}, + {"realtek,dcycle", RTD_D_CYCLE, 0}, +}; + +static int rtd_pinctrl_get_groups_count(struct pinctrl_dev *pcdev) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + + return data->info->num_groups; +} + +static const char *rtd_pinctrl_get_group_name(struct pinctrl_dev *pcdev, + unsigned int selector) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + + return data->info->groups[selector].name; +} + +static int rtd_pinctrl_get_group_pins(struct pinctrl_dev *pcdev, + unsigned int selector, const unsigned int **pins, unsigned int *num_pins) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + + *pins = data->info->groups[selector].pins; + *num_pins = data->info->groups[selector].num_pins; + + return 0; +} + +static const struct pinctrl_ops rtd_pinctrl_ops = { + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_free_map, + .get_groups_count = rtd_pinctrl_get_groups_count, + .get_group_name = rtd_pinctrl_get_group_name, + .get_group_pins = rtd_pinctrl_get_group_pins, +}; + +static int rtd_pinctrl_get_functions_count(struct pinctrl_dev *pcdev) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + + return data->info->num_functions; +} + +static const char *rtd_pinctrl_get_function_name(struct pinctrl_dev *pcdev, + unsigned int selector) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + + return data->info->functions[selector].name; +} + +static int rtd_pinctrl_get_function_groups(struct pinctrl_dev *pcdev, + unsigned int selector, const char * const **groups, + unsigned int * const num_groups) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + + *groups = data->info->functions[selector].groups; + *num_groups = data->info->functions[selector].num_groups; + + return 0; +} + +static const struct rtd_pin_desc *rtd_pinctrl_find_mux(struct rtd_pinctrl *data, unsigned int pin) +{ + + if (data->info->muxes[pin].name != 0) + return &data->info->muxes[pin]; + + return NULL; +} + + +static int rtd_pinctrl_set_one_mux(struct pinctrl_dev *pcdev, + unsigned int pin, const char *func_name) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + const struct rtd_pin_desc *mux; + const char *pin_name; + u32 val; + int i; + + mux = rtd_pinctrl_find_mux(data, pin); + if (!mux) + return -ENOTSUPP; + + if (!mux->functions) { + dev_err(pcdev->dev, "No functions available for pin %s\n", pin_name); + return -ENOTSUPP; + } + + for (i = 0; mux->functions[i].name; i++) { + if (strcmp(mux->functions[i].name, func_name) != 0) + continue; + val = readl_relaxed(data->base + mux->mux_offset); + val &= ~mux->mux_mask; + val |= mux->functions[i].mux_value & mux->mux_mask; + writel_relaxed(val, data->base + mux->mux_offset); + return 0; + } + + dev_err(pcdev->dev, "No function %s available for pin %s\n", func_name, pin_name); + return -EINVAL; +} + +static int rtd_pinctrl_set_mux(struct pinctrl_dev *pcdev, + unsigned int function, unsigned int group) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + const unsigned int *pins; + unsigned int num_pins; + const char *func_name; + const char *group_name; + int i, ret; + + func_name = data->info->functions[function].name; + group_name = data->info->groups[group].name; + + ret = rtd_pinctrl_get_group_pins(pcdev, group, &pins, &num_pins); + if (ret) { + dev_err(pcdev->dev, "Getting pins for group %s failed\n", group_name); + return ret; + } + + for (i = 0; i < num_pins; i++) { + ret = rtd_pinctrl_set_one_mux(pcdev, pins[i], func_name); + if (ret) + return ret; + } + + return 0; +} + +static int rtd_pinctrl_gpio_request_enable(struct pinctrl_dev *pcdev, + struct pinctrl_gpio_range *range, unsigned int offset) +{ + return rtd_pinctrl_set_one_mux(pcdev, offset, "gpio"); +} + +static const struct pinmux_ops rtd_pinmux_ops = { + .get_functions_count = rtd_pinctrl_get_functions_count, + .get_function_name = rtd_pinctrl_get_function_name, + .get_function_groups = rtd_pinctrl_get_function_groups, + .set_mux = rtd_pinctrl_set_mux, + .gpio_request_enable = rtd_pinctrl_gpio_request_enable, +}; + + +static const struct pinctrl_pin_desc *rtd_pinctrl_get_pin_by_number(struct rtd_pinctrl *data, int number) +{ + int i; + + for (i = 0; i < data->info->num_pins; i++) { + if (data->info->pins[i].number == number) + return &data->info->pins[i]; + } + + return NULL; +} + +static const struct rtd_pin_config_desc *rtd_pinctrl_find_config(struct rtd_pinctrl *data, unsigned int pin) +{ + + if (data->info->configs[pin].name != 0) + return &data->info->configs[pin]; + + return NULL; +} + +static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pinctrl *data, unsigned int pin) +{ + + int i; + const struct pinctrl_pin_desc *pin_desc; + const char *pin_name; + + pin_desc = rtd_pinctrl_get_pin_by_number(data, pin); + if (!pin_desc) + return NULL; + + pin_name = pin_desc->name; + + for (i = 0; i < data->info->num_sconfigs; i++) { + if (strcmp(data->info->sconfigs[i].name, pin_name) == 0) + return &data->info->sconfigs[i]; + } + + return NULL; +} + + +static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + unsigned int pinnr, enum pin_config_param param, + enum pin_config_param arg) +{ + u8 set_val = 0; + u16 strength; + u32 val; + u32 mask; + u32 pulsel_off, pulen_off, smt_off, curr_off, pow_off, reg_off, + p_off, n_off; + const struct rtd_pin_config_desc *config_desc; + const struct rtd_pin_sconfig_desc *sconfig_desc; + + + config_desc = rtd_pinctrl_find_config(data, pinnr); + if (!config_desc) + return -ENOTSUPP; + + switch ((u32)param) { + case PIN_CONFIG_INPUT_SCHMITT: + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (config_desc->smt_offset == PCONF_UNSUPP) { + pr_err("[rtd_pinctrl][%s] not support input schmitt\n", config_desc->name); + return -ENOTSUPP; + } + smt_off = config_desc->base_bit + config_desc->smt_offset; + set_val = arg; + val = readl(data->base + config_desc->reg_offset); + if (set_val) + val |= BIT(smt_off); + else + val &= ~BIT(smt_off); + writel(val, data->base + config_desc->reg_offset); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (config_desc->pud_en_offset == PCONF_UNSUPP) { + pr_err("[rtd_pinctrl][%s] not support input bias\n", config_desc->name); + return -ENOTSUPP; + } + pulen_off = config_desc->base_bit + config_desc->pud_en_offset; + val = readl(data->base + config_desc->reg_offset); + if (set_val) + val |= BIT(pulen_off); + else + val &= ~BIT(pulen_off); + writel(val, data->base + config_desc->reg_offset); + break; + case PIN_CONFIG_BIAS_DISABLE: + if (config_desc->pud_en_offset == PCONF_UNSUPP) { + pr_err("[rtd_pinctrl][%s] not support input bias\n", config_desc->name); + return -ENOTSUPP; + } + pulen_off = config_desc->base_bit + config_desc->pud_en_offset; + val = readl(data->base + config_desc->reg_offset); + val &= ~BIT(pulen_off); + writel(val, data->base + config_desc->reg_offset); + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (config_desc->pud_en_offset == PCONF_UNSUPP) { + pr_err("[rtd_pinctrl][%s] not support input bias\n", config_desc->name); + return -ENOTSUPP; + } + pulen_off = config_desc->base_bit + config_desc->pud_en_offset; + pulsel_off = config_desc->base_bit + config_desc->pud_sel_offset; + val = readl(data->base + config_desc->reg_offset); + val |= BIT(pulen_off) | BIT(pulsel_off); + writel(val, data->base + config_desc->reg_offset); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (config_desc->pud_en_offset == PCONF_UNSUPP) { + pr_err("[rtd_pinctrl][%s] not support input bias\n", config_desc->name); + return -ENOTSUPP; + } + pulen_off = config_desc->base_bit + config_desc->pud_en_offset; + pulsel_off = config_desc->base_bit + config_desc->pud_sel_offset; + val = readl(data->base + config_desc->reg_offset); + val |= BIT(pulen_off); + val &= ~BIT(pulsel_off); + writel(val, data->base + config_desc->reg_offset); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + curr_off = config_desc->base_bit + config_desc->curr_offset; + strength = arg; + val = readl(data->base + config_desc->reg_offset); + switch (config_desc->curr_type) { + case PADDRI_4_8: + if (strength == 4) + val &= ~BIT(curr_off); + else if (strength == 8) + val |= BIT(curr_off); + else + return -EINVAL; + break; + case PADDRI_2_4: + if (strength == 2) + val &= ~BIT(curr_off); + else if (strength == 4) + val |= BIT(curr_off); + else + return -EINVAL; + break; + case PCONF_UNSUPP: + pr_err("[rtd_pinctrl][%s] not support drive strength\n", config_desc->name); + return -ENOTSUPP; + default: + return -EINVAL; + } + writel(val, data->base + config_desc->reg_offset); + break; + + case PIN_CONFIG_POWER_SOURCE: + if (config_desc->power_offset == PCONF_UNSUPP) { + pr_err("[rtd_pinctrl][%s] not support power source\n", config_desc->name); + return -ENOTSUPP; + } + pow_off = config_desc->base_bit + config_desc->power_offset; + if (pow_off / 32) { + reg_off = config_desc->reg_offset + 0x4; + pow_off %= 32; + } else { + reg_off = config_desc->reg_offset; + } + set_val = arg; + val = readl(data->base + reg_off); + if (set_val) + val |= BIT(pow_off); + else + val &= ~BIT(pow_off); + writel(val, data->base + reg_off); + break; + case RTD_P_DRIVE: + sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr); + if (!sconfig_desc) + return -ENOTSUPP; + set_val = arg; + if (sconfig_desc->pdrive_offset / 31) { + p_off = sconfig_desc->pdrive_offset % 32; + reg_off = sconfig_desc->reg_offset + 0x4; + } else { + p_off = sconfig_desc->pdrive_offset; + reg_off = sconfig_desc->reg_offset; + } + val = readl(data->base + reg_off); + mask = GENMASK(p_off + sconfig_desc->pdrive_maskbits - 1, p_off); + val = (val & ~mask) | (set_val << p_off); + writel(val, data->base + reg_off); + break; + case RTD_N_DRIVE: + sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr); + if (!sconfig_desc) + return -ENOTSUPP; + set_val = arg; + if (sconfig_desc->ndrive_offset / 31) { + n_off = sconfig_desc->ndrive_offset % 32; + reg_off = sconfig_desc->reg_offset + 0x4; + } else { + n_off = sconfig_desc->ndrive_offset; + reg_off = sconfig_desc->reg_offset; + } + val = readl(data->base + reg_off); + mask = GENMASK(n_off + sconfig_desc->ndrive_maskbits - 1, n_off); + val = (val & ~mask) | (set_val << n_off); + writel(val, data->base + reg_off); + break; + case RTD_D_CYCLE: + sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr); + if (!sconfig_desc) + return -ENOTSUPP; + set_val = arg; + val = readl(data->base + sconfig_desc->reg_offset); + mask = GENMASK(sconfig_desc->dcycle_offset + + sconfig_desc->dcycle_maskbits - 1, sconfig_desc->dcycle_offset); + val = (val & ~mask) | (set_val << sconfig_desc->dcycle_offset); + writel(val, data->base + sconfig_desc->reg_offset); + break; + default: + break; + } + + return 0; +} + + +static int rtd_pin_config_get(struct pinctrl_dev *pcdev, unsigned int pinnr, + unsigned long *config) +{ + //struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + unsigned int param = pinconf_to_config_param(*config); + unsigned int arg = 0; + + switch (param) { + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int rtd_pin_config_set(struct pinctrl_dev *pcdev, unsigned int pinnr, + unsigned long *configs, unsigned int num_configs) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + int i; + int ret = 0; + + + for (i = 0; i < num_configs; i++) { + ret = rtd_pconf_parse_conf(data, pinnr, + pinconf_to_config_param(configs[i]), + pinconf_to_config_argument(configs[i])); + if (ret < 0) + return ret; + } + + return 0; +} + + +static int rtd_pin_config_group_set(struct pinctrl_dev *pcdev, unsigned int group, + unsigned long *configs, unsigned int num_configs) +{ + struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev); + const unsigned int *pins; + unsigned int num_pins; + const char *group_name; + int i, ret; + + group_name = data->info->groups[group].name; + + ret = rtd_pinctrl_get_group_pins(pcdev, group, &pins, &num_pins); + if (ret) { + dev_err(pcdev->dev, "Getting pins for group %s failed\n", group_name); + return ret; + } + + for (i = 0; i < num_pins; i++) { + ret = rtd_pin_config_set(pcdev, pins[i], configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + + +static const struct pinconf_ops rtd_pinconf_ops = { + .is_generic = true, + .pin_config_get = rtd_pin_config_get, + .pin_config_set = rtd_pin_config_set, + .pin_config_group_set = rtd_pin_config_group_set, +}; + +#ifdef CONFIG_PINCTRL_RTD_SELFTEST +static void rtd_pinctrl_selftest(struct rtd_pinctrl *data) +{ + int i, j, k, l; + int f; + + for (i = 0; i < data->info->num_muxes; i++) { + if (data->info->muxes[i].name == 0) + continue; + //Check for pin + if (strcmp(data->info->pins[i].name, data->info->muxes[i].name) != 0) + dev_warn(data->pcdev->dev, "Mux %s lacking matching pin\n", + data->info->muxes[i].name); + + //Check for group + if (strcmp(data->info->groups[i].name, data->info->muxes[i].name) != 0) + dev_warn(data->pcdev->dev, "Mux %s lacking matching group\n", + data->info->muxes[i].name); + + for (j = 0; data->info->muxes[i].functions[j].name; j++) { + //Check for function + for (k = 0; k < data->info->num_functions; k++) { + if (strcmp(data->info->functions[k].name, + data->info->muxes[i].functions[j].name) == 0) + break; + } + if (k == data->info->num_functions) + dev_warn(data->pcdev->dev, "Mux %s lacking function %s\n", + data->info->muxes[i].name, + data->info->muxes[i].functions[j].name); + for (l = 0; l < data->info->functions[k].num_groups; l++) { + if (strcmp(data->info->muxes[i].name, + data->info->functions[k].groups[l]) == 0) + break; + } + if (l == data->info->functions[k].num_groups) { + dev_warn(data->pcdev->dev, "function %s lacking mux %s\n", + data->info->functions[k].name, data->info->muxes[i].name); + } + + //Check for duplicate mux value - assumption: ascending order + if (j > 0 && data->info->muxes[i].functions[j].mux_value + <= data->info->muxes[i].functions[j - 1].mux_value) + dev_warn(data->pcdev->dev, "Mux %s function %s has unexpected value\n", + data->info->muxes[i].name, + data->info->muxes[i].functions[j].name); + + } + } + + for (i = 0; i < data->info->num_functions; i++) { + for (j = 0; j < data->info->functions[i].num_groups; j++) { + for (k = 0; k < data->info->num_muxes; k++) { + if (strcmp(data->info->functions[i].groups[j], data->info->muxes[k].name) == 0) + break; + } + if (k == data->info->num_muxes) { + dev_warn(data->pcdev->dev, "group mux %s could not find\n", + data->info->functions[i].groups[j]); + break; + } + f = 0; + for (l = 0; data->info->muxes[k].functions[l].name; l++) { + if (strcmp(data->info->muxes[k].functions[l].name, data->info->functions[i].name) == 0) { + f = 1; + break; + } + } + if (f != 1) + dev_warn(data->pcdev->dev, "function %s lacking in mux %s\n", + data->info->functions[i].name, data->info->muxes[k].name); + } + } +} +#endif + + +static const struct of_device_id rtd_pinctrl_dt_ids[] = { + { .compatible = "realtek,rtd13xx-pinctrl", .data = &rtd1319_iso_pinctrl_desc }, + { .compatible = "realtek,rtd16xxb-pinctrl", .data = &rtd1619b_iso_pinctrl_desc }, + { } +}; + +static int rtd_pinctrl_probe(struct platform_device *pdev) +{ + struct rtd_pinctrl *data; + const struct of_device_id *match; + + match = of_match_node(rtd_pinctrl_dt_ids, pdev->dev.of_node); + if (!match) + return -EINVAL; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->base = of_iomap(pdev->dev.of_node, 0); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + data->info = match->data; + data->desc.name = "foo"; + data->desc.pins = data->info->pins; + data->desc.npins = data->info->num_pins; + data->desc.pctlops = &rtd_pinctrl_ops; + data->desc.pmxops = &rtd_pinmux_ops; + data->desc.confops = &rtd_pinconf_ops; + data->desc.custom_params = rtd_custom_bindings; + data->desc.num_custom_params = ARRAY_SIZE(rtd_custom_bindings); + data->desc.owner = THIS_MODULE; + + data->pcdev = pinctrl_register(&data->desc, &pdev->dev, data); + if (!data->pcdev) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + +#ifdef CONFIG_PINCTRL_RTD_SELFTEST + rtd_pinctrl_selftest(data); +#endif + dev_info(&pdev->dev, "probed\n"); + + return 0; +} + + +static struct platform_driver rtd_pinctrl_driver = { + .probe = rtd_pinctrl_probe, + .driver = { + .name = "rtd-pinctrl", + .of_match_table = rtd_pinctrl_dt_ids, + }, +}; + +static int rtd_pinctrl_init(void) +{ + return platform_driver_register(&rtd_pinctrl_driver); +} +postcore_initcall(rtd_pinctrl_init); diff --git a/drivers/pinctrl/realtek/pinctrl-rtd1319.h b/drivers/pinctrl/realtek/pinctrl-rtd1319.h new file mode 100644 index 000000000000..6b36ffbf579a --- /dev/null +++ b/drivers/pinctrl/realtek/pinctrl-rtd1319.h @@ -0,0 +1,1390 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later*/ + +/* + * Realtek DHC pin controller driver + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef PINCTRL_RTD13xx_H +#define PINCTRL_RTD13xx_H + +enum rtd13xx_iso_pins { + RTD1319_ISO_GPIO_0 = 0, + RTD1319_ISO_GPIO_1, + RTD1319_ISO_GPIO_2, + RTD1319_ISO_GPIO_3, + RTD1319_ISO_GPIO_4, + RTD1319_ISO_GPIO_5, + RTD1319_ISO_GPIO_6, + RTD1319_ISO_GPIO_7, + RTD1319_ISO_GPIO_8, + RTD1319_ISO_GPIO_9, + RTD1319_ISO_GPIO_10, + RTD1319_ISO_GPIO_11, + RTD1319_ISO_GPIO_12, + RTD1319_ISO_GPIO_13, + RTD1319_ISO_GPIO_14, + RTD1319_ISO_GPIO_15, + RTD1319_ISO_GPIO_16, + RTD1319_ISO_GPIO_17, + RTD1319_ISO_GPIO_18, + RTD1319_ISO_GPIO_19, + RTD1319_ISO_GPIO_20, + RTD1319_ISO_GPIO_21, + RTD1319_ISO_GPIO_22, + RTD1319_ISO_GPIO_23, + RTD1319_ISO_USB_CC2, + RTD1319_ISO_GPIO_25, + RTD1319_ISO_GPIO_26, + RTD1319_ISO_GPIO_27, + RTD1319_ISO_GPIO_28, + RTD1319_ISO_GPIO_29, + RTD1319_ISO_GPIO_30, + RTD1319_ISO_GPIO_31, + RTD1319_ISO_GPIO_32, + RTD1319_ISO_GPIO_33, + RTD1319_ISO_GPIO_34, + RTD1319_ISO_GPIO_35, + RTD1319_ISO_HIF_DATA, + RTD1319_ISO_HIF_EN, + RTD1319_ISO_HIF_RDY, + RTD1319_ISO_HIF_CLK, + RTD1319_ISO_GPIO_40, + RTD1319_ISO_GPIO_41, + RTD1319_ISO_GPIO_42, + RTD1319_ISO_GPIO_43, + RTD1319_ISO_GPIO_44, + RTD1319_ISO_GPIO_45, + RTD1319_ISO_GPIO_46, + RTD1319_ISO_GPIO_47, + RTD1319_ISO_GPIO_48, + RTD1319_ISO_GPIO_49, + RTD1319_ISO_GPIO_50, + RTD1319_ISO_USB_CC1, + RTD1319_ISO_GPIO_52, + RTD1319_ISO_GPIO_53, + RTD1319_ISO_IR_RX, + RTD1319_ISO_UR0_RX, + RTD1319_ISO_UR0_TX, + RTD1319_ISO_GPIO_57, + RTD1319_ISO_GPIO_58, + RTD1319_ISO_GPIO_59, + RTD1319_ISO_GPIO_60, + RTD1319_ISO_GPIO_61, + RTD1319_ISO_GPIO_62, + RTD1319_ISO_GPIO_63, + RTD1319_ISO_GPIO_64, + RTD1319_ISO_GPIO_65, + RTD1319_ISO_GPIO_66, + RTD1319_ISO_GPIO_67, + RTD1319_ISO_GPIO_68, + RTD1319_ISO_GPIO_69, + RTD1319_ISO_GPIO_70, + RTD1319_ISO_GPIO_71, + RTD1319_ISO_GPIO_72, + RTD1319_ISO_GPIO_73, + RTD1319_ISO_GPIO_74, + RTD1319_ISO_GPIO_75, + RTD1319_ISO_GPIO_76, + RTD1319_ISO_EMMC_CMD, + RTD1319_ISO_SPI_CE_N, + RTD1319_ISO_SPI_SCK, + RTD1319_ISO_SPI_SO, + RTD1319_ISO_SPI_SI, + RTD1319_ISO_EMMC_RST_N, + RTD1319_ISO_EMMC_DD_SB, + RTD1319_ISO_EMMC_CLK, + RTD1319_ISO_EMMC_DATA_0, + RTD1319_ISO_EMMC_DATA_1, + RTD1319_ISO_EMMC_DATA_2, + RTD1319_ISO_EMMC_DATA_3, + RTD1319_ISO_EMMC_DATA_4, + RTD1319_ISO_EMMC_DATA_5, + RTD1319_ISO_EMMC_DATA_6, + RTD1319_ISO_EMMC_DATA_7, + RTD1319_ISO_UR2_LOC, + RTD1319_ISO_GSPI_LOC, + RTD1319_ISO_SDIO_LOC, + RTD1319_ISO_HI_LOC, + RTD1319_ISO_HI_WIDTH, + RTD1319_ISO_DEBUG_P2S_ENABLE, + RTD1319_ISO_SF_EN, + RTD1319_ISO_ARM_TRACE_DBG_EN, + RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC0, + RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC0, + RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC1, + RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC1, + RTD1319_ISO_EJTAG_ACPU_LOC, + RTD1319_ISO_EJTAG_VCPU_LOC, + RTD1319_ISO_EJTAG_SCPU_LOC, + RTD1319_ISO_DMIC_LOC, + RTD1319_ISO_ISO_GSPI_LOC, +}; + +static const struct pinctrl_pin_desc rtd1319_iso_pins[] = { + PINCTRL_PIN(RTD1319_ISO_GPIO_0, "gpio_0"), + PINCTRL_PIN(RTD1319_ISO_GPIO_1, "gpio_1"), + PINCTRL_PIN(RTD1319_ISO_GPIO_2, "gpio_2"), + PINCTRL_PIN(RTD1319_ISO_GPIO_3, "gpio_3"), + PINCTRL_PIN(RTD1319_ISO_GPIO_4, "gpio_4"), + PINCTRL_PIN(RTD1319_ISO_GPIO_5, "gpio_5"), + PINCTRL_PIN(RTD1319_ISO_GPIO_6, "gpio_6"), + PINCTRL_PIN(RTD1319_ISO_GPIO_7, "gpio_7"), + PINCTRL_PIN(RTD1319_ISO_GPIO_8, "gpio_8"), + PINCTRL_PIN(RTD1319_ISO_GPIO_9, "gpio_9"), + PINCTRL_PIN(RTD1319_ISO_GPIO_10, "gpio_10"), + PINCTRL_PIN(RTD1319_ISO_GPIO_11, "gpio_11"), + PINCTRL_PIN(RTD1319_ISO_GPIO_12, "gpio_12"), + PINCTRL_PIN(RTD1319_ISO_GPIO_13, "gpio_13"), + PINCTRL_PIN(RTD1319_ISO_GPIO_14, "gpio_14"), + PINCTRL_PIN(RTD1319_ISO_GPIO_15, "gpio_15"), + PINCTRL_PIN(RTD1319_ISO_GPIO_16, "gpio_16"), + PINCTRL_PIN(RTD1319_ISO_GPIO_17, "gpio_17"), + PINCTRL_PIN(RTD1319_ISO_GPIO_18, "gpio_18"), + PINCTRL_PIN(RTD1319_ISO_GPIO_19, "gpio_19"), + PINCTRL_PIN(RTD1319_ISO_GPIO_20, "gpio_20"), + PINCTRL_PIN(RTD1319_ISO_GPIO_21, "gpio_21"), + PINCTRL_PIN(RTD1319_ISO_GPIO_22, "gpio_22"), + PINCTRL_PIN(RTD1319_ISO_GPIO_23, "gpio_23"), + PINCTRL_PIN(RTD1319_ISO_USB_CC2, "usb_cc2"), + PINCTRL_PIN(RTD1319_ISO_GPIO_25, "gpio_25"), + PINCTRL_PIN(RTD1319_ISO_GPIO_26, "gpio_26"), + PINCTRL_PIN(RTD1319_ISO_GPIO_27, "gpio_27"), + PINCTRL_PIN(RTD1319_ISO_GPIO_28, "gpio_28"), + PINCTRL_PIN(RTD1319_ISO_GPIO_29, "gpio_29"), + PINCTRL_PIN(RTD1319_ISO_GPIO_30, "gpio_30"), + PINCTRL_PIN(RTD1319_ISO_GPIO_31, "gpio_31"), + PINCTRL_PIN(RTD1319_ISO_GPIO_32, "gpio_32"), + PINCTRL_PIN(RTD1319_ISO_GPIO_33, "gpio_33"), + PINCTRL_PIN(RTD1319_ISO_GPIO_34, "gpio_34"), + PINCTRL_PIN(RTD1319_ISO_GPIO_35, "gpio_35"), + PINCTRL_PIN(RTD1319_ISO_HIF_DATA, "hif_data"), + PINCTRL_PIN(RTD1319_ISO_HIF_EN, "hif_en"), + PINCTRL_PIN(RTD1319_ISO_HIF_RDY, "hif_rdy"), + PINCTRL_PIN(RTD1319_ISO_HIF_CLK, "hif_clk"), + PINCTRL_PIN(RTD1319_ISO_GPIO_40, "gpio_40"), + PINCTRL_PIN(RTD1319_ISO_GPIO_41, "gpio_41"), + PINCTRL_PIN(RTD1319_ISO_GPIO_42, "gpio_42"), + PINCTRL_PIN(RTD1319_ISO_GPIO_43, "gpio_43"), + PINCTRL_PIN(RTD1319_ISO_GPIO_44, "gpio_44"), + PINCTRL_PIN(RTD1319_ISO_GPIO_45, "gpio_45"), + PINCTRL_PIN(RTD1319_ISO_GPIO_46, "gpio_46"), + PINCTRL_PIN(RTD1319_ISO_GPIO_47, "gpio_47"), + PINCTRL_PIN(RTD1319_ISO_GPIO_48, "gpio_48"), + PINCTRL_PIN(RTD1319_ISO_GPIO_49, "gpio_49"), + PINCTRL_PIN(RTD1319_ISO_GPIO_50, "gpio_50"), + PINCTRL_PIN(RTD1319_ISO_USB_CC1, "usb_cc1"), + PINCTRL_PIN(RTD1319_ISO_GPIO_52, "gpio_52"), + PINCTRL_PIN(RTD1319_ISO_GPIO_53, "gpio_53"), + PINCTRL_PIN(RTD1319_ISO_IR_RX, "ir_rx"), + PINCTRL_PIN(RTD1319_ISO_UR0_RX, "ur0_rx"), + PINCTRL_PIN(RTD1319_ISO_UR0_TX, "ur0_tx"), + PINCTRL_PIN(RTD1319_ISO_GPIO_57, "gpio_57"), + PINCTRL_PIN(RTD1319_ISO_GPIO_58, "gpio_58"), + PINCTRL_PIN(RTD1319_ISO_GPIO_59, "gpio_59"), + PINCTRL_PIN(RTD1319_ISO_GPIO_60, "gpio_60"), + PINCTRL_PIN(RTD1319_ISO_GPIO_61, "gpio_61"), + PINCTRL_PIN(RTD1319_ISO_GPIO_62, "gpio_62"), + PINCTRL_PIN(RTD1319_ISO_GPIO_63, "gpio_63"), + PINCTRL_PIN(RTD1319_ISO_GPIO_64, "gpio_64"), + PINCTRL_PIN(RTD1319_ISO_GPIO_65, "gpio_65"), + PINCTRL_PIN(RTD1319_ISO_GPIO_66, "gpio_66"), + PINCTRL_PIN(RTD1319_ISO_GPIO_67, "gpio_67"), + PINCTRL_PIN(RTD1319_ISO_GPIO_68, "gpio_68"), + PINCTRL_PIN(RTD1319_ISO_GPIO_69, "gpio_69"), + PINCTRL_PIN(RTD1319_ISO_GPIO_70, "gpio_70"), + PINCTRL_PIN(RTD1319_ISO_GPIO_71, "gpio_71"), + PINCTRL_PIN(RTD1319_ISO_GPIO_72, "gpio_72"), + PINCTRL_PIN(RTD1319_ISO_GPIO_73, "gpio_73"), + PINCTRL_PIN(RTD1319_ISO_GPIO_74, "gpio_74"), + PINCTRL_PIN(RTD1319_ISO_GPIO_75, "gpio_75"), + PINCTRL_PIN(RTD1319_ISO_GPIO_76, "gpio_76"), + PINCTRL_PIN(RTD1319_ISO_EMMC_CMD, "emmc_cmd"), + PINCTRL_PIN(RTD1319_ISO_SPI_CE_N, "spi_ce_n"), + PINCTRL_PIN(RTD1319_ISO_SPI_SCK, "spi_sck"), + PINCTRL_PIN(RTD1319_ISO_SPI_SO, "spi_so"), + PINCTRL_PIN(RTD1319_ISO_SPI_SI, "spi_si"), + PINCTRL_PIN(RTD1319_ISO_EMMC_RST_N, "emmc_rst_n"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DD_SB, "emmc_dd_sb"), + PINCTRL_PIN(RTD1319_ISO_EMMC_CLK, "emmc_clk"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_0, "emmc_data_0"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_1, "emmc_data_1"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_2, "emmc_data_2"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_3, "emmc_data_3"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_4, "emmc_data_4"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_5, "emmc_data_5"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_6, "emmc_data_6"), + PINCTRL_PIN(RTD1319_ISO_EMMC_DATA_7, "emmc_data_7"), + PINCTRL_PIN(RTD1319_ISO_UR2_LOC, "ur2_loc"), + PINCTRL_PIN(RTD1319_ISO_GSPI_LOC, "gspi_loc"), + PINCTRL_PIN(RTD1319_ISO_SDIO_LOC, "sdio_loc"), + PINCTRL_PIN(RTD1319_ISO_HI_LOC, "hi_loc"), + PINCTRL_PIN(RTD1319_ISO_HI_WIDTH, "hi_width"), + PINCTRL_PIN(RTD1319_ISO_DEBUG_P2S_ENABLE, "debug_p2s_enable"), + PINCTRL_PIN(RTD1319_ISO_SF_EN, "sf_en"), + PINCTRL_PIN(RTD1319_ISO_ARM_TRACE_DBG_EN, "arm_trace_dbg_en"), + PINCTRL_PIN(RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC0, "pwm_01_open_drain_en_loc0"), + PINCTRL_PIN(RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC0, "pwm_23_open_drain_en_loc0"), + PINCTRL_PIN(RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC1, "pwm_01_open_drain_en_loc1"), + PINCTRL_PIN(RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC1, "pwm_23_open_drain_en_loc1"), + PINCTRL_PIN(RTD1319_ISO_EJTAG_ACPU_LOC, "ejtag_acpu_loc"), + PINCTRL_PIN(RTD1319_ISO_EJTAG_VCPU_LOC, "ejtag_vcpu_loc"), + PINCTRL_PIN(RTD1319_ISO_EJTAG_SCPU_LOC, "ejtag_scpu_loc"), + PINCTRL_PIN(RTD1319_ISO_DMIC_LOC, "dmic_loc"), + PINCTRL_PIN(RTD1319_ISO_ISO_GSPI_LOC, "iso_gspi_loc"), +}; + +#define DECLARE_RTD1319_PIN(_pin, _name) static const unsigned int rtd1319_## _name ##_pins[] = { _pin } + +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_0, gpio_0); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_1, gpio_1); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_2, gpio_2); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_3, gpio_3); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_4, gpio_4); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_5, gpio_5); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_6, gpio_6); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_7, gpio_7); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_8, gpio_8); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_9, gpio_9); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_10, gpio_10); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_11, gpio_11); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_12, gpio_12); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_13, gpio_13); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_14, gpio_14); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_15, gpio_15); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_16, gpio_16); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_17, gpio_17); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_18, gpio_18); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_19, gpio_19); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_20, gpio_20); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_21, gpio_21); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_22, gpio_22); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_23, gpio_23); +DECLARE_RTD1319_PIN(RTD1319_ISO_USB_CC2, usb_cc2); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_25, gpio_25); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_26, gpio_26); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_27, gpio_27); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_28, gpio_28); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_29, gpio_29); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_30, gpio_30); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_31, gpio_31); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_32, gpio_32); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_33, gpio_33); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_34, gpio_34); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_35, gpio_35); +DECLARE_RTD1319_PIN(RTD1319_ISO_HIF_DATA, hif_data); +DECLARE_RTD1319_PIN(RTD1319_ISO_HIF_EN, hif_en); +DECLARE_RTD1319_PIN(RTD1319_ISO_HIF_RDY, hif_rdy); +DECLARE_RTD1319_PIN(RTD1319_ISO_HIF_CLK, hif_clk); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_40, gpio_40); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_41, gpio_41); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_42, gpio_42); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_43, gpio_43); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_44, gpio_44); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_45, gpio_45); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_46, gpio_46); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_47, gpio_47); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_48, gpio_48); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_49, gpio_49); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_50, gpio_50); +DECLARE_RTD1319_PIN(RTD1319_ISO_USB_CC1, usb_cc1); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_52, gpio_52); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_53, gpio_53); +DECLARE_RTD1319_PIN(RTD1319_ISO_IR_RX, ir_rx); +DECLARE_RTD1319_PIN(RTD1319_ISO_UR0_RX, ur0_rx); +DECLARE_RTD1319_PIN(RTD1319_ISO_UR0_TX, ur0_tx); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_57, gpio_57); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_58, gpio_58); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_59, gpio_59); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_60, gpio_60); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_61, gpio_61); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_62, gpio_62); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_63, gpio_63); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_64, gpio_64); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_65, gpio_65); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_66, gpio_66); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_67, gpio_67); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_68, gpio_68); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_69, gpio_69); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_70, gpio_70); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_71, gpio_71); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_72, gpio_72); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_73, gpio_73); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_74, gpio_74); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_75, gpio_75); +DECLARE_RTD1319_PIN(RTD1319_ISO_GPIO_76, gpio_76); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_CMD, emmc_cmd); +DECLARE_RTD1319_PIN(RTD1319_ISO_SPI_CE_N, spi_ce_n); +DECLARE_RTD1319_PIN(RTD1319_ISO_SPI_SCK, spi_sck); +DECLARE_RTD1319_PIN(RTD1319_ISO_SPI_SO, spi_so); +DECLARE_RTD1319_PIN(RTD1319_ISO_SPI_SI, spi_si); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_RST_N, emmc_rst_n); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DD_SB, emmc_dd_sb); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_CLK, emmc_clk); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_0, emmc_data_0); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_1, emmc_data_1); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_2, emmc_data_2); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_3, emmc_data_3); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_4, emmc_data_4); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_5, emmc_data_5); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_6, emmc_data_6); +DECLARE_RTD1319_PIN(RTD1319_ISO_EMMC_DATA_7, emmc_data_7); +DECLARE_RTD1319_PIN(RTD1319_ISO_UR2_LOC, ur2_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_GSPI_LOC, gspi_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_SDIO_LOC, sdio_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_HI_LOC, hi_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_HI_WIDTH, hi_width); +DECLARE_RTD1319_PIN(RTD1319_ISO_DEBUG_P2S_ENABLE, debug_p2s_enable); +DECLARE_RTD1319_PIN(RTD1319_ISO_SF_EN, sf_en); +DECLARE_RTD1319_PIN(RTD1319_ISO_ARM_TRACE_DBG_EN, arm_trace_dbg_en); +DECLARE_RTD1319_PIN(RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC0, pwm_01_open_drain_en_loc0); +DECLARE_RTD1319_PIN(RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC0, pwm_23_open_drain_en_loc0); +DECLARE_RTD1319_PIN(RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC1, pwm_01_open_drain_en_loc1); +DECLARE_RTD1319_PIN(RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC1, pwm_23_open_drain_en_loc1); +DECLARE_RTD1319_PIN(RTD1319_ISO_EJTAG_ACPU_LOC, ejtag_acpu_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_EJTAG_VCPU_LOC, ejtag_vcpu_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_EJTAG_SCPU_LOC, ejtag_scpu_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_DMIC_LOC, dmic_loc); +DECLARE_RTD1319_PIN(RTD1319_ISO_ISO_GSPI_LOC, iso_gspi_loc); + + + +#define RTD1319_GROUP(_name) \ + { \ + .name = # _name, \ + .pins = rtd1319_ ## _name ## _pins, \ + .num_pins = ARRAY_SIZE(rtd1319_ ## _name ## _pins), \ + } + +static const struct rtd_pin_group_desc rtd1319_pin_groups[] = { + RTD1319_GROUP(gpio_0), + RTD1319_GROUP(gpio_1), + RTD1319_GROUP(gpio_2), + RTD1319_GROUP(gpio_3), + RTD1319_GROUP(gpio_4), + RTD1319_GROUP(gpio_5), + RTD1319_GROUP(gpio_6), + RTD1319_GROUP(gpio_7), + RTD1319_GROUP(gpio_8), + RTD1319_GROUP(gpio_9), + RTD1319_GROUP(gpio_10), + RTD1319_GROUP(gpio_11), + RTD1319_GROUP(gpio_12), + RTD1319_GROUP(gpio_13), + RTD1319_GROUP(gpio_14), + RTD1319_GROUP(gpio_15), + RTD1319_GROUP(gpio_16), + RTD1319_GROUP(gpio_17), + RTD1319_GROUP(gpio_18), + RTD1319_GROUP(gpio_19), + RTD1319_GROUP(gpio_20), + RTD1319_GROUP(gpio_21), + RTD1319_GROUP(gpio_22), + RTD1319_GROUP(gpio_23), + RTD1319_GROUP(usb_cc2), + RTD1319_GROUP(gpio_25), + RTD1319_GROUP(gpio_26), + RTD1319_GROUP(gpio_27), + RTD1319_GROUP(gpio_28), + RTD1319_GROUP(gpio_29), + RTD1319_GROUP(gpio_30), + RTD1319_GROUP(gpio_31), + RTD1319_GROUP(gpio_32), + RTD1319_GROUP(gpio_33), + RTD1319_GROUP(gpio_34), + RTD1319_GROUP(gpio_35), + RTD1319_GROUP(hif_data), + RTD1319_GROUP(hif_en), + RTD1319_GROUP(hif_rdy), + RTD1319_GROUP(hif_clk), + RTD1319_GROUP(gpio_40), + RTD1319_GROUP(gpio_41), + RTD1319_GROUP(gpio_42), + RTD1319_GROUP(gpio_43), + RTD1319_GROUP(gpio_44), + RTD1319_GROUP(gpio_45), + RTD1319_GROUP(gpio_46), + RTD1319_GROUP(gpio_47), + RTD1319_GROUP(gpio_48), + RTD1319_GROUP(gpio_49), + RTD1319_GROUP(gpio_50), + RTD1319_GROUP(usb_cc1), + RTD1319_GROUP(gpio_52), + RTD1319_GROUP(gpio_53), + RTD1319_GROUP(ir_rx), + RTD1319_GROUP(ur0_rx), + RTD1319_GROUP(ur0_tx), + RTD1319_GROUP(gpio_57), + RTD1319_GROUP(gpio_58), + RTD1319_GROUP(gpio_59), + RTD1319_GROUP(gpio_60), + RTD1319_GROUP(gpio_61), + RTD1319_GROUP(gpio_62), + RTD1319_GROUP(gpio_63), + RTD1319_GROUP(gpio_64), + RTD1319_GROUP(gpio_65), + RTD1319_GROUP(gpio_66), + RTD1319_GROUP(gpio_67), + RTD1319_GROUP(gpio_68), + RTD1319_GROUP(gpio_69), + RTD1319_GROUP(gpio_70), + RTD1319_GROUP(gpio_71), + RTD1319_GROUP(gpio_72), + RTD1319_GROUP(gpio_73), + RTD1319_GROUP(gpio_74), + RTD1319_GROUP(gpio_75), + RTD1319_GROUP(gpio_76), + RTD1319_GROUP(emmc_cmd), + RTD1319_GROUP(spi_ce_n), + RTD1319_GROUP(spi_sck), + RTD1319_GROUP(spi_so), + RTD1319_GROUP(spi_si), + RTD1319_GROUP(emmc_rst_n), + RTD1319_GROUP(emmc_dd_sb), + RTD1319_GROUP(emmc_clk), + RTD1319_GROUP(emmc_data_0), + RTD1319_GROUP(emmc_data_1), + RTD1319_GROUP(emmc_data_2), + RTD1319_GROUP(emmc_data_3), + RTD1319_GROUP(emmc_data_4), + RTD1319_GROUP(emmc_data_5), + RTD1319_GROUP(emmc_data_6), + RTD1319_GROUP(emmc_data_7), + RTD1319_GROUP(ur2_loc), + RTD1319_GROUP(gspi_loc), + RTD1319_GROUP(sdio_loc), + RTD1319_GROUP(hi_loc), + RTD1319_GROUP(hi_width), + RTD1319_GROUP(debug_p2s_enable), + RTD1319_GROUP(sf_en), + RTD1319_GROUP(arm_trace_dbg_en), + RTD1319_GROUP(pwm_01_open_drain_en_loc0), + RTD1319_GROUP(pwm_23_open_drain_en_loc0), + RTD1319_GROUP(pwm_01_open_drain_en_loc1), + RTD1319_GROUP(pwm_23_open_drain_en_loc1), + RTD1319_GROUP(ejtag_acpu_loc), + RTD1319_GROUP(ejtag_vcpu_loc), + RTD1319_GROUP(ejtag_scpu_loc), + RTD1319_GROUP(dmic_loc), + RTD1319_GROUP(iso_gspi_loc), +}; + +static const char * const rtd1319_gpio_groups[] = { + "gpio_0", "gpio_1", "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "gpio_7", "gpio_8", "gpio_9", + "gpio_10", "gpio_11", "gpio_12", "gpio_13", "gpio_14", + "gpio_15", "gpio_16", "gpio_17", "gpio_18", "gpio_19", + "gpio_20", "gpio_21", "gpio_22", "gpio_23", "usb_cc2", + "gpio_25", "gpio_26", "gpio_27", "gpio_28", "gpio_29", + "gpio_30", "gpio_31", "gpio_32", "gpio_33", "gpio_34", + "gpio_35", "hif_data", "hif_en", "hif_rdy", "hif_clk", + "gpio_40", "gpio_41", "gpio_42", "gpio_43", "gpio_44", + "gpio_45", "gpio_46", "gpio_47", "gpio_48", "gpio_49", + "gpio_50", "usb_cc1", "gpio_52", "gpio_53", "ir_rx", + "ur0_rx", "ur0_tx", "gpio_57", "gpio_58", "gpio_59", + "gpio_60", "gpio_61", "gpio_62", "gpio_63", "gpio_64", + "gpio_65", "gpio_66", "gpio_67", "gpio_68", "gpio_69", + "gpio_70", "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "emmc_cmd", "spi_ce_n", "spi_sck", + "spi_so", "spi_si" }; +static const char * const rtd1319_nf_groups[] = { + "emmc_rst_n", "emmc_clk", "emmc_data_0", "emmc_data_1", + "emmc_data_2", "emmc_data_3", "emmc_data_4", + "emmc_data_5", "emmc_data_6", "emmc_data_7", "spi_ce_n", + "spi_sck", "spi_so", "spi_si" }; +static const char * const rtd1319_nf_spi_groups[] = { + "emmc_cmd", "emmc_data_0", "emmc_data_1", + "emmc_data_2", "emmc_data_3", "emmc_data_4", + "emmc_data_5" }; +static const char * const rtd1319_spi_groups[] = { + "spi_ce_n", "spi_sck", "spi_so", "spi_si" }; +static const char * const rtd1319_emmc_groups[] = { + "emmc_rst_n", "emmc_clk", "emmc_data_0", "emmc_data_1", + "emmc_data_2", "emmc_data_3", "emmc_data_4", + "emmc_data_5", "emmc_data_6", "emmc_data_7", + "emmc_dd_sb", "emmc_cmd"}; + +static const char * const rtd1319_pmic_groups[] = { "spi_ce_n" }; +static const char * const rtd1319_spdif_groups[] = { + "spi_sck", "gpio_1", "gpio_6", "gpio_50"}; +static const char * const rtd1319_emmc_spi_groups[] = { + "gpio_1", "gpio_2", "gpio_3", "gpio_4", "gpio_5", "gpio_6" }; +static const char * const rtd1319_sc1_groups[] = { + "gpio_2", "gpio_3", "gpio_4", "gpio_5" }; +static const char * const rtd1319_uart0_groups[] = { "ur0_rx", "ur0_tx" }; +static const char * const rtd1319_uart1_groups[] = { + "gpio_8", "gpio_9", "gpio_10", "gpio_11" }; +static const char * const rtd1319_uart2_loc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31", "ur2_loc" }; +static const char * const rtd1319_uart2_loc1_groups[] = { + "gpio_25", "gpio_26", "gpio_27", "gpio_28", "ur2_loc" }; +static const char * const rtd1319_gspi_loc1_groups[] = { + "gpio_8", "gpio_9", "gpio_10", "gpio_11", "gspi_loc" }; +static const char * const rtd1319_iso_gspi_loc1_groups[] = { + "gpio_8", "gpio_9", "gpio_10", "gpio_11", "iso_gspi_loc" }; +static const char * const rtd1319_rtc_dig_groups[] = { "gpio_11" }; +static const char * const rtd1319_rtc_ana_groups[] = { "gpio_11" }; +static const char * const rtd1319_i2c0_groups[] = { "gpio_12", "gpio_13" }; +static const char * const rtd1319_i2c1_groups[] = { "gpio_16", "gpio_17" }; +static const char * const rtd1319_i2c3_groups[] = { "gpio_63", "gpio_64" }; +static const char * const rtd1319_i2c5_groups[] = { "gpio_29", "gpio_46" }; +static const char * const rtd1319_pwm0_groups[] = { "gpio_12", "gpio_20" }; +static const char * const rtd1319_pwm1_groups[] = { "gpio_13", "gpio_21" }; +static const char * const rtd1319_pwm2_groups[] = { "gpio_14", "gpio_22" }; +static const char * const rtd1319_pwm3_groups[] = { "gpio_15", "gpio_23" }; +static const char * const rtd1319_etn_led_groups[] = { "gpio_14", "gpio_15" }; +static const char * const rtd1319_etn_phy_groups[] = { "gpio_14", "gpio_15" }; +static const char * const rtd1319_rgmii_groups[] = { + "gpio_14", "gpio_15", "gpio_65", "gpio_66", "gpio_67", + "gpio_68", "gpio_69", "gpio_70", "gpio_71", "gpio_72", + "gpio_73", "gpio_74", "gpio_75", "gpio_76"}; +static const char * const rtd1319_sc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31" }; +static const char * const rtd1319_gspi_loc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31", "gspi_loc" }; +static const char * const rtd1319_iso_gspi_loc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31", "iso_gspi_loc" }; +static const char * const rtd1319_qam_agc_if_groups[] = { "gpio_21" }; +static const char * const rtd1319_pcie1_groups[] = { "gpio_25" }; +static const char * const rtd1319_pcie2_groups[] = { "gpio_52" }; +static const char * const rtd1319_sd_groups[] = { + "gpio_32", "gpio_33", "gpio_34", "gpio_35", "hif_data", + "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1319_sdio_loc0_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_rdy", "hif_clk", "sdio_loc" }; +static const char * const rtd1319_sdio_loc1_groups[] = { + "gpio_40", "gpio_41", "gpio_42", "gpio_43", "gpio_44", + "gpio_45", "gpio_46", "sdio_loc" }; +static const char * const rtd1319_hi_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1319_dc_fan_groups[] = { "gpio_47" }; +static const char * const rtd1319_pll_test_loc0_groups[] = { "gpio_52", "gpio_53" }; +static const char * const rtd1319_pll_test_loc1_groups[] = { "gpio_48", "gpio_49" }; +static const char * const rtd1319_debug_p2s_groups[] = { "gpio_52", "gpio_53", "debug_p2s_enable"}; +static const char * const rtd1319_tdm_ai_loc0_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60" }; +static const char * const rtd1319_tdm_ai_loc1_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1319_dmic_loc0_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60", "gpio_61", + "gpio_62", "gpio_63", "gpio_64", "dmic_loc"}; +static const char * const rtd1319_dmic_loc1_groups[] = { + "gpio_32", "gpio_33", "gpio_34", "gpio_35", "hif_data", + "hif_en", "hif_rdy", "hif_clk", "dmic_loc" }; +static const char * const rtd1319_ai_loc0_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60", "gpio_61", + "gpio_62", "gpio_63" }; +static const char * const rtd1319_ai_loc1_groups[] = { + "gpio_32", "gpio_33", "gpio_34", "hif_data", + "hif_en", "hif_rdy", "hif_clk"}; +static const char * const rtd1319_tp0_groups[] = { + "gpio_66", "gpio_67", "gpio_68", "gpio_69", + "gpio_70", "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76" }; +static const char * const rtd1319_tp1_groups[] = { + "gpio_69", "gpio_70", "gpio_71", "gpio_72" }; +static const char * const rtd1319_ao_groups[] = { + "gpio_66", "gpio_67", "gpio_68", "gpio_69", + "gpio_70", "gpio_71", "gpio_72" }; +static const char * const rtd1319_rmii_groups[] = { + "gpio_68", "gpio_69", "gpio_70", "gpio_71", + "gpio_72", "gpio_73", "gpio_74"}; +static const char * const rtd1319_uart2_disable_groups[] = { "ur2_loc" }; +static const char * const rtd1319_gspi_disable_groups[] = { "gspi_loc" }; +static const char * const rtd1319_sdio_disable_groups[] = { "sdio_loc" }; +static const char * const rtd1319_hi_loc_disable_groups[] = { "hi_loc" }; +static const char * const rtd1319_hi_loc0_groups[] = { "hi_loc" }; +static const char * const rtd1319_hi_loc1_groups[] = { "hi_loc" }; +static const char * const rtd1319_hi_width_disable_groups[] = { "hi_width" }; +static const char * const rtd1319_hi_width_1bit_groups[] = { "hi_width" }; +static const char * const rtd1319_hi_width_8bit_groups[] = { "hi_width" }; +static const char * const rtd1319_hi_width_16bit_groups[] = { "hi_width" }; +static const char * const rtd1319_scpu_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_scpu_loc" }; +static const char * const rtd1319_acpu_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_acpu_loc" }; +static const char * const rtd1319_vcpu_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_vcpu_loc" }; +static const char * const rtd1319_scpu_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_scpu_loc" }; +static const char * const rtd1319_acpu_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_acpu_loc" }; +static const char * const rtd1319_vcpu_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_vcpu_loc" }; +static const char * const rtd1319_acpu_ejtag_disable_groups[] = { "ejtag_acpu_loc" }; +static const char * const rtd1319_vcpu_ejtag_disable_groups[] = { "ejtag_vcpu_loc" }; +static const char * const rtd1319_scpu_ejtag_disable_groups[] = { "ejtag_scpu_loc" }; +static const char * const rtd1319_p2s_disable_groups[] = { "debug_p2s_enable" }; +static const char * const rtd1319_sf_disable_groups[] = { "sf_en" }; +static const char * const rtd1319_sf_enable_groups[] = { "sf_en" }; +static const char * const rtd1319_arm_trace_debug_disable_groups[] = { "arm_trace_dbg_en" }; +static const char * const rtd1319_arm_trace_debug_enable_groups[] = { "arm_trace_dbg_en" }; +static const char * const rtd1319_pwm_normal_groups[] = { + "pwm_01_open_drain_en_loc0", "pwm_23_open_drain_en_loc0", "pwm_01_open_drain_en_loc1", "pwm_23_open_drain_en_loc1" }; +static const char * const rtd1319_pwm_open_drain_groups[] = { + "pwm_01_open_drain_en_loc0", "pwm_23_open_drain_en_loc0", "pwm_01_open_drain_en_loc1", "pwm_23_open_drain_en_loc1" }; +static const char * const rtd1319_standby_dbg_groups[] = { + "gpio_2", "gpio_3", "ir_rx" }; + +static const char * const rtd1319_usb_cc1_groups[] = { "usb_cc1" }; +static const char * const rtd1319_usb_cc2_groups[] = { "usb_cc2" }; +static const char * const rtd1319_ir_rx_groups[] = { "ir_rx" }; +static const char * const rtd1319_test_loop_dis_groups[] = { "gpio_50" }; + +#define RTD1319_FUNC(_name) \ + { \ + .name = # _name, \ + .groups = rtd1319_ ## _name ## _groups, \ + .num_groups = ARRAY_SIZE(rtd1319_ ## _name ## _groups), \ + } + +static const struct rtd_pin_func_desc rtd1319_pin_functions[] = { + RTD1319_FUNC(gpio), + RTD1319_FUNC(nf), + RTD1319_FUNC(nf_spi), + RTD1319_FUNC(spi), + RTD1319_FUNC(pmic), + RTD1319_FUNC(spdif), + RTD1319_FUNC(emmc_spi), + RTD1319_FUNC(emmc), + RTD1319_FUNC(sc1), + RTD1319_FUNC(uart0), + RTD1319_FUNC(uart1), + RTD1319_FUNC(uart2_loc0), + RTD1319_FUNC(uart2_loc1), + RTD1319_FUNC(gspi_loc1), + RTD1319_FUNC(iso_gspi_loc1), + RTD1319_FUNC(rtc_dig), + RTD1319_FUNC(rtc_ana), + RTD1319_FUNC(i2c0), + RTD1319_FUNC(i2c1), + RTD1319_FUNC(i2c3), + RTD1319_FUNC(i2c5), + RTD1319_FUNC(pwm0), + RTD1319_FUNC(pwm1), + RTD1319_FUNC(pwm2), + RTD1319_FUNC(pwm3), + RTD1319_FUNC(etn_led), + RTD1319_FUNC(etn_phy), + RTD1319_FUNC(rgmii), + RTD1319_FUNC(sc0), + RTD1319_FUNC(gspi_loc0), + RTD1319_FUNC(iso_gspi_loc0), + RTD1319_FUNC(qam_agc_if), + RTD1319_FUNC(pcie1), + RTD1319_FUNC(pcie2), + RTD1319_FUNC(sd), + RTD1319_FUNC(sdio_loc0), + RTD1319_FUNC(sdio_loc1), + RTD1319_FUNC(hi), + RTD1319_FUNC(dc_fan), + RTD1319_FUNC(pll_test_loc0), + RTD1319_FUNC(pll_test_loc1), + RTD1319_FUNC(usb_cc1), + RTD1319_FUNC(usb_cc2), + RTD1319_FUNC(debug_p2s), + RTD1319_FUNC(ir_rx), + RTD1319_FUNC(tdm_ai_loc0), + RTD1319_FUNC(tdm_ai_loc1), + RTD1319_FUNC(dmic_loc0), + RTD1319_FUNC(dmic_loc1), + RTD1319_FUNC(ai_loc0), + RTD1319_FUNC(ai_loc1), + RTD1319_FUNC(tp0), + RTD1319_FUNC(tp1), + RTD1319_FUNC(ao), + RTD1319_FUNC(rmii), + RTD1319_FUNC(uart2_disable), + RTD1319_FUNC(gspi_disable), + RTD1319_FUNC(sdio_disable), + RTD1319_FUNC(hi_loc_disable), + RTD1319_FUNC(hi_loc0), + RTD1319_FUNC(hi_loc1), + RTD1319_FUNC(hi_width_disable), + RTD1319_FUNC(hi_width_1bit), + RTD1319_FUNC(hi_width_8bit), + RTD1319_FUNC(hi_width_16bit), + RTD1319_FUNC(scpu_ejtag_loc0), + RTD1319_FUNC(acpu_ejtag_loc0), + RTD1319_FUNC(vcpu_ejtag_loc0), + RTD1319_FUNC(scpu_ejtag_loc1), + RTD1319_FUNC(acpu_ejtag_loc1), + RTD1319_FUNC(vcpu_ejtag_loc1), + RTD1319_FUNC(acpu_ejtag_disable), + RTD1319_FUNC(vcpu_ejtag_disable), + RTD1319_FUNC(scpu_ejtag_disable), + RTD1319_FUNC(p2s_disable), + RTD1319_FUNC(sf_disable), + RTD1319_FUNC(sf_enable), + RTD1319_FUNC(arm_trace_debug_disable), + RTD1319_FUNC(arm_trace_debug_enable), + RTD1319_FUNC(pwm_normal), + RTD1319_FUNC(pwm_open_drain), + RTD1319_FUNC(standby_dbg), + RTD1319_FUNC(test_loop_dis), +}; + +#undef RTD1319_FUNC + +static const struct rtd_pin_desc rtd1319_iso_muxes[] = { + [RTD1319_ISO_EMMC_RST_N] = RTK_PIN_MUX(emmc_rst_n, 0x0, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "emmc")), + [RTD1319_ISO_EMMC_DD_SB] = RTK_PIN_MUX(emmc_dd_sb, 0x0, GENMASK(3, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 2), "emmc")), + [RTD1319_ISO_EMMC_CLK] = RTK_PIN_MUX(emmc_clk, 0x0, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "emmc")), + [RTD1319_ISO_EMMC_CMD] = RTK_PIN_MUX(emmc_cmd, 0x0, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 6), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_0] = RTK_PIN_MUX(emmc_data_0, 0x0, GENMASK(9, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 8), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 8), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_1] = RTK_PIN_MUX(emmc_data_1, 0x0, GENMASK(11, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 10), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 10), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_2] = RTK_PIN_MUX(emmc_data_2, 0x0, GENMASK(13, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 12), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 12), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_3] = RTK_PIN_MUX(emmc_data_3, 0x0, GENMASK(15, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 14), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 14), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_4] = RTK_PIN_MUX(emmc_data_4, 0x0, GENMASK(17, 16), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 16), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 16), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 16), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_5] = RTK_PIN_MUX(emmc_data_5, 0x0, GENMASK(19, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 18), "nf_spi")), + [RTD1319_ISO_EMMC_DATA_6] = RTK_PIN_MUX(emmc_data_6, 0x0, GENMASK(21, 20), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 20), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 20), "emmc")), + [RTD1319_ISO_EMMC_DATA_7] = RTK_PIN_MUX(emmc_data_7, 0x0, GENMASK(23, 22), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 22), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 22), "emmc")), + [RTD1319_ISO_SPI_CE_N] = RTK_PIN_MUX(spi_ce_n, 0x0, GENMASK(25, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 24), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 24), "spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 24), "pmic")), + [RTD1319_ISO_SPI_SCK] = RTK_PIN_MUX(spi_sck, 0x0, GENMASK(27, 26), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 26), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 26), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 26), "spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 26), "spdif")), + [RTD1319_ISO_SPI_SO] = RTK_PIN_MUX(spi_so, 0x0, GENMASK(29, 28), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 28), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 28), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 28), "spi")), + [RTD1319_ISO_SPI_SI] = RTK_PIN_MUX(spi_si, 0x0, GENMASK(31, 30), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 30), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 30), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 30), "spi")), + + [RTD1319_ISO_GPIO_0] = RTK_PIN_MUX(gpio_0, 0x4, GENMASK(0, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio")), + [RTD1319_ISO_GPIO_1] = RTK_PIN_MUX(gpio_1, 0x4, GENMASK(2, 1), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 1), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 1), "spdif"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 1), "emmc_spi")), + [RTD1319_ISO_GPIO_2] = RTK_PIN_MUX(gpio_2, 0x4, GENMASK(5, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 3), "standby_dbg"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 3), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 3), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 3), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 3), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 3), "vcpu_ejtag_loc0")), + [RTD1319_ISO_GPIO_3] = RTK_PIN_MUX(gpio_3, 0x4, GENMASK(8, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "standby_dbg"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 6), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 6), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 6), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 6), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 6), "vcpu_ejtag_loc0")), + [RTD1319_ISO_GPIO_4] = RTK_PIN_MUX(gpio_4, 0x4, GENMASK(11, 9), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 9), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 9), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 9), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 9), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 9), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 9), "vcpu_ejtag_loc0")), + [RTD1319_ISO_GPIO_5] = RTK_PIN_MUX(gpio_5, 0x4, GENMASK(14, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 12), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 12), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 12), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 12), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 12), "vcpu_ejtag_loc0")), + [RTD1319_ISO_GPIO_6] = RTK_PIN_MUX(gpio_6, 0x4, GENMASK(17, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "spdif"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 15), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 15), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 15), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 15), "vcpu_ejtag_loc0")), + [RTD1319_ISO_GPIO_7] = RTK_PIN_MUX(gpio_7, 0x4, GENMASK(18, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio")), + [RTD1319_ISO_GPIO_8] = RTK_PIN_MUX(gpio_8, 0x4, GENMASK(21, 19), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 19), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 19), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 19), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 19), "iso_gspi_loc1")), + [RTD1319_ISO_GPIO_9] = RTK_PIN_MUX(gpio_9, 0x4, GENMASK(24, 22), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 22), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 22), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 22), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 22), "iso_gspi_loc1")), + [RTD1319_ISO_GPIO_10] = RTK_PIN_MUX(gpio_10, 0x4, GENMASK(27, 25), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 25), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 25), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 25), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 25), "iso_gspi_loc1")), + [RTD1319_ISO_GPIO_11] = RTK_PIN_MUX(gpio_11, 0x4, GENMASK(30, 28), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 28), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 28), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 28), "rtc_dig"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 28), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 28), "rtc_ana"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 28), "iso_gspi_loc1")), + + [RTD1319_ISO_GPIO_12] = RTK_PIN_MUX(gpio_12, 0x8, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "i2c0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "pwm0")), + [RTD1319_ISO_GPIO_13] = RTK_PIN_MUX(gpio_13, 0x8, GENMASK(3, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 2), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 2), "i2c0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 2), "pwm1")), + [RTD1319_ISO_GPIO_14] = RTK_PIN_MUX(gpio_14, 0x8, GENMASK(6, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "etn_led"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "pwm2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 4), "etn_phy"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 4), "rgmii")), + [RTD1319_ISO_GPIO_15] = RTK_PIN_MUX(gpio_15, 0x8, GENMASK(9, 7), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 7), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 7), "etn_led"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 7), "pwm3"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 7), "etn_phy"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 7), "rgmii")), + [RTD1319_ISO_GPIO_16] = RTK_PIN_MUX(gpio_16, 0x8, GENMASK(10, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "i2c1")), + [RTD1319_ISO_GPIO_17] = RTK_PIN_MUX(gpio_17, 0x8, GENMASK(11, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 11), "i2c1")), + [RTD1319_ISO_GPIO_18] = RTK_PIN_MUX(gpio_18, 0x8, GENMASK(14, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 12), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 12), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 12), "iso_gspi_loc0")), + [RTD1319_ISO_GPIO_19] = RTK_PIN_MUX(gpio_19, 0x8, GENMASK(17, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 15), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 15), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 15), "iso_gspi_loc0")), + [RTD1319_ISO_GPIO_20] = RTK_PIN_MUX(gpio_20, 0x8, GENMASK(20, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "pwm0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 18), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 18), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 18), "iso_gspi_loc0")), + [RTD1319_ISO_GPIO_21] = RTK_PIN_MUX(gpio_21, 0x8, GENMASK(22, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "qam_agc_if"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "pwm1")), + [RTD1319_ISO_GPIO_22] = RTK_PIN_MUX(gpio_22, 0x8, GENMASK(24, 23), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 23), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 23), "pwm2")), + [RTD1319_ISO_GPIO_23] = RTK_PIN_MUX(gpio_23, 0x8, GENMASK(26, 25), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 25), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 25), "pwm3")), + [RTD1319_ISO_USB_CC2] = RTK_PIN_MUX(usb_cc2, 0x8, GENMASK(27, 27), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 27), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 27), "usb_cc2")), + [RTD1319_ISO_GPIO_25] = RTK_PIN_MUX(gpio_25, 0x8, GENMASK(29, 28), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 28), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 28), "uart2_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 28), "pcie1")), + [RTD1319_ISO_GPIO_26] = RTK_PIN_MUX(gpio_26, 0x8, GENMASK(30, 30), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 30), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 30), "uart2_loc1")), + [RTD1319_ISO_GPIO_27] = RTK_PIN_MUX(gpio_27, 0x8, GENMASK(31, 31), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 31), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 31), "uart2_loc1")), + + + [RTD1319_ISO_GPIO_28] = RTK_PIN_MUX(gpio_28, 0xc, GENMASK(0, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "uart2_loc1")), + [RTD1319_ISO_GPIO_29] = RTK_PIN_MUX(gpio_29, 0xc, GENMASK(1, 1), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 1), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 1), "i2c5")), + [RTD1319_ISO_GPIO_30] = RTK_PIN_MUX(gpio_30, 0xc, GENMASK(2, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 2), "gpio")), + [RTD1319_ISO_GPIO_31] = RTK_PIN_MUX(gpio_31, 0xc, GENMASK(5, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 3), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 3), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 3), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 3), "iso_gspi_loc0")), + [RTD1319_ISO_GPIO_32] = RTK_PIN_MUX(gpio_32, 0xc, GENMASK(8, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 6), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 6), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 6), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 6), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 6), "vcpu_ejtag_loc1")), + [RTD1319_ISO_GPIO_33] = RTK_PIN_MUX(gpio_33, 0xc, GENMASK(11, 9), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 9), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 9), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 9), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 9), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 9), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 9), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 9), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 9), "vcpu_ejtag_loc1")), + [RTD1319_ISO_GPIO_34] = RTK_PIN_MUX(gpio_34, 0xc, GENMASK(14, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 12), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 12), "ai_loc1")), + [RTD1319_ISO_GPIO_35] = RTK_PIN_MUX(gpio_35, 0xc, GENMASK(16, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 15), "dmic_loc1")), + [RTD1319_ISO_HIF_DATA] = RTK_PIN_MUX(hif_data, 0xc, GENMASK(20, 17), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 17), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 17), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 17), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 17), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 17), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 17), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 17), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 17), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 17), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 17), "hi")), + [RTD1319_ISO_HIF_EN] = RTK_PIN_MUX(hif_en, 0xc, GENMASK(24, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 21), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 21), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 21), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 21), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 21), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 21), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 21), "hi")), + [RTD1319_ISO_HIF_RDY] = RTK_PIN_MUX(hif_rdy, 0xc, GENMASK(28, 25), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 25), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 25), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 25), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 25), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 25), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 25), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 25), "hi")), + + + [RTD1319_ISO_HIF_CLK] = RTK_PIN_MUX(hif_clk, 0x10, GENMASK(3, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 0), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 0), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 0), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 0), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 0), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 0), "hi")), + [RTD1319_ISO_GPIO_40] = RTK_PIN_MUX(gpio_40, 0x10, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "sdio_loc1")), + [RTD1319_ISO_GPIO_41] = RTK_PIN_MUX(gpio_41, 0x10, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "sdio_loc1")), + [RTD1319_ISO_GPIO_42] = RTK_PIN_MUX(gpio_42, 0x10, GENMASK(9, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 8), "sdio_loc1")), + [RTD1319_ISO_GPIO_43] = RTK_PIN_MUX(gpio_43, 0x10, GENMASK(11, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 10), "sdio_loc1")), + [RTD1319_ISO_GPIO_44] = RTK_PIN_MUX(gpio_44, 0x10, GENMASK(13, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 12), "sdio_loc1")), + [RTD1319_ISO_GPIO_45] = RTK_PIN_MUX(gpio_45, 0x10, GENMASK(15, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 14), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 14), "sdio_loc1")), + [RTD1319_ISO_GPIO_46] = RTK_PIN_MUX(gpio_46, 0x10, GENMASK(17, 16), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 16), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 16), "i2c5"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 16), "sdio_loc1")), + [RTD1319_ISO_GPIO_47] = RTK_PIN_MUX(gpio_47, 0x10, GENMASK(19, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "dc_fan")), + [RTD1319_ISO_GPIO_48] = RTK_PIN_MUX(gpio_48, 0x10, GENMASK(20, 20), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 20), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 20), "pll_test_loc1")), + [RTD1319_ISO_GPIO_49] = RTK_PIN_MUX(gpio_49, 0x10, GENMASK(21, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "pll_test_loc1")), + [RTD1319_ISO_GPIO_50] = RTK_PIN_MUX(gpio_50, 0x10, GENMASK(23, 22), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 22), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 22), "spdif"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 22), "test_loop_dis")), + [RTD1319_ISO_USB_CC1] = RTK_PIN_MUX(usb_cc1, 0x10, GENMASK(24, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 24), "usb_cc1")), + [RTD1319_ISO_GPIO_52] = RTK_PIN_MUX(gpio_52, 0x10, GENMASK(26, 25), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 25), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 25), "pll_test_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 25), "debug_p2s"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 25), "pcie2")), + [RTD1319_ISO_GPIO_53] = RTK_PIN_MUX(gpio_53, 0x10, GENMASK(28, 27), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 27), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 27), "pll_test_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 27), "debug_p2s")), + [RTD1319_ISO_IR_RX] = RTK_PIN_MUX(ir_rx, 0x10, GENMASK(30, 29), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 29), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 29), "ir_rx"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 29), "standby_dbg")), + [RTD1319_ISO_UR0_RX] = RTK_PIN_MUX(ur0_rx, 0x10, GENMASK(31, 31), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 31), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 31), "uart0")), + + + [RTD1319_ISO_UR0_TX] = RTK_PIN_MUX(ur0_tx, 0x14, GENMASK(0, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "uart0")), + [RTD1319_ISO_GPIO_57] = RTK_PIN_MUX(gpio_57, 0x14, GENMASK(2, 1), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 1), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 1), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 1), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 1), "dmic_loc0")), + [RTD1319_ISO_GPIO_58] = RTK_PIN_MUX(gpio_58, 0x14, GENMASK(4, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 3), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 3), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 3), "dmic_loc0")), + [RTD1319_ISO_GPIO_59] = RTK_PIN_MUX(gpio_59, 0x14, GENMASK(6, 5), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 5), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 5), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 5), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 5), "dmic_loc0")), + [RTD1319_ISO_GPIO_60] = RTK_PIN_MUX(gpio_60, 0x14, GENMASK(8, 7), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 7), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 7), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 7), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 7), "dmic_loc0")), + [RTD1319_ISO_GPIO_61] = RTK_PIN_MUX(gpio_61, 0x14, GENMASK(10, 9), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 9), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 9), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 9), "dmic_loc0")), + [RTD1319_ISO_GPIO_62] = RTK_PIN_MUX(gpio_62, 0x14, GENMASK(12, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 11), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 11), "dmic_loc0")), + [RTD1319_ISO_GPIO_63] = RTK_PIN_MUX(gpio_63, 0x14, GENMASK(14, 13), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 13), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 13), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 13), "i2c3"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 13), "dmic_loc0")), + [RTD1319_ISO_GPIO_64] = RTK_PIN_MUX(gpio_64, 0x14, GENMASK(16, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 15), "i2c3"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 15), "dmic_loc0")), + [RTD1319_ISO_GPIO_65] = RTK_PIN_MUX(gpio_65, 0x14, GENMASK(17, 17), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 17), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 17), "rgmii")), + [RTD1319_ISO_GPIO_66] = RTK_PIN_MUX(gpio_66, 0x14, GENMASK(20, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 18), "ao")), + [RTD1319_ISO_GPIO_67] = RTK_PIN_MUX(gpio_67, 0x14, GENMASK(23, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 21), "ao")), + [RTD1319_ISO_GPIO_68] = RTK_PIN_MUX(gpio_68, 0x14, GENMASK(26, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 24), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 24), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 24), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 24), "rmii")), + [RTD1319_ISO_GPIO_69] = RTK_PIN_MUX(gpio_69, 0x14, GENMASK(29, 27), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 27), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 27), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 27), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 27), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 27), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 27), "rmii")), + + [RTD1319_ISO_GPIO_70] = RTK_PIN_MUX(gpio_70, 0x18, GENMASK(2, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 0), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 0), "rmii")), + [RTD1319_ISO_GPIO_71] = RTK_PIN_MUX(gpio_71, 0x18, GENMASK(5, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 3), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 3), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 3), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 3), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 3), "rmii")), + [RTD1319_ISO_GPIO_72] = RTK_PIN_MUX(gpio_72, 0x18, GENMASK(8, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 6), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 6), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 6), "rmii")), + [RTD1319_ISO_GPIO_73] = RTK_PIN_MUX(gpio_73, 0x18, GENMASK(11, 9), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 9), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 9), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 9), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 9), "rmii")), + [RTD1319_ISO_GPIO_74] = RTK_PIN_MUX(gpio_74, 0x18, GENMASK(14, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 12), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 12), "rmii")), + [RTD1319_ISO_GPIO_75] = RTK_PIN_MUX(gpio_75, 0x18, GENMASK(16, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 15), "tp0")), + [RTD1319_ISO_GPIO_76] = RTK_PIN_MUX(gpio_76, 0x18, GENMASK(18, 17), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 17), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 17), "rgmii"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 17), "tp0")), + + + [RTD1319_ISO_UR2_LOC] = RTK_PIN_MUX(ur2_loc, 0x120, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "uart2_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "uart2_loc1")), + [RTD1319_ISO_GSPI_LOC] = RTK_PIN_MUX(gspi_loc, 0x120, GENMASK(3, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 2), "gspi_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 2), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 2), "gspi_loc1")), + [RTD1319_ISO_SDIO_LOC] = RTK_PIN_MUX(sdio_loc, 0x120, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "sdio_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "sdio_loc1")), + [RTD1319_ISO_HI_LOC] = RTK_PIN_MUX(hi_loc, 0x120, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "hi_loc_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "hi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "hi_loc1")), + [RTD1319_ISO_HI_WIDTH] = RTK_PIN_MUX(hi_width, 0x120, GENMASK(9, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "hi_width_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "hi_width_1bit"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 8), "hi_width_8bit"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 8), "hi_width_16bit")), + [RTD1319_ISO_DEBUG_P2S_ENABLE] = RTK_PIN_MUX(debug_p2s_enable, 0x120, GENMASK(10, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "p2s_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "debug_p2s")), + [RTD1319_ISO_SF_EN] = RTK_PIN_MUX(sf_en, 0x120, GENMASK(11, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "sf_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 11), "sf_enable")), + [RTD1319_ISO_ARM_TRACE_DBG_EN] = RTK_PIN_MUX(arm_trace_dbg_en, 0x120, GENMASK(12, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "arm_trace_debug_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "arm_trace_debug_enable")), + [RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC0] = RTK_PIN_MUX(pwm_01_open_drain_en_loc0, 0x120, GENMASK(13, 13), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 13), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 13), "pwm_open_drain")), + [RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC0] = RTK_PIN_MUX(pwm_23_open_drain_en_loc0, 0x120, GENMASK(14, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 14), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "pwm_open_drain")), + [RTD1319_ISO_PWM_01_OPEN_DRAIN_EN_LOC1] = RTK_PIN_MUX(pwm_01_open_drain_en_loc1, 0x120, GENMASK(15, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "pwm_open_drain")), + [RTD1319_ISO_PWM_23_OPEN_DRAIN_EN_LOC1] = RTK_PIN_MUX(pwm_23_open_drain_en_loc1, 0x120, GENMASK(16, 16), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 16), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 16), "pwm_open_drain")), + [RTD1319_ISO_EJTAG_ACPU_LOC] = RTK_PIN_MUX(ejtag_acpu_loc, 0x120, GENMASK(18, 17), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 17), "acpu_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 17), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 17), "acpu_ejtag_loc1")), + [RTD1319_ISO_EJTAG_VCPU_LOC] = RTK_PIN_MUX(ejtag_vcpu_loc, 0x120, GENMASK(20, 19), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 19), "vcpu_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 19), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 19), "vcpu_ejtag_loc1")), + [RTD1319_ISO_EJTAG_SCPU_LOC] = RTK_PIN_MUX(ejtag_scpu_loc, 0x120, GENMASK(22, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "scpu_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "scpu_ejtag_loc1")), + [RTD1319_ISO_DMIC_LOC] = RTK_PIN_MUX(dmic_loc, 0x120, GENMASK(25, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 24), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 24), "dmic_loc1")), + [RTD1319_ISO_ISO_GSPI_LOC] = RTK_PIN_MUX(iso_gspi_loc, 0x120, GENMASK(27, 26), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 26), "iso_gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 26), "iso_gspi_loc1")), +}; + +static const struct rtd_pin_config_desc rtd1319_iso_configs[] = { + [RTD1319_ISO_EMMC_RST_N] = RTK_PIN_CONFIG(emmc_rst_n, 0x1c, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DD_SB] = RTK_PIN_CONFIG(emmc_dd_sb, 0x1c, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_CLK] = RTK_PIN_CONFIG(emmc_clk, 0x20, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_CMD] = RTK_PIN_CONFIG(emmc_cmd, 0x20, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_0] = RTK_PIN_CONFIG(emmc_data_0, 0x24, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_1] = RTK_PIN_CONFIG(emmc_data_1, 0x24, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_2] = RTK_PIN_CONFIG(emmc_data_2, 0x28, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_3] = RTK_PIN_CONFIG(emmc_data_3, 0x28, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_4] = RTK_PIN_CONFIG(emmc_data_4, 0x2c, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_5] = RTK_PIN_CONFIG(emmc_data_5, 0x2c, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_6] = RTK_PIN_CONFIG(emmc_data_6, 0x30, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_EMMC_DATA_7] = RTK_PIN_CONFIG(emmc_data_7, 0x30, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_SPI_CE_N] = RTK_PIN_CONFIG(spi_ce_n, 0x34, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_SPI_SCK] = RTK_PIN_CONFIG(spi_sck, 0x34, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_SPI_SO] = RTK_PIN_CONFIG(spi_so, 0x38, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_SPI_SI] = RTK_PIN_CONFIG(spi_si, 0x38, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_0] = RTK_PIN_CONFIG(gpio_0, 0x38, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_1] = RTK_PIN_CONFIG(gpio_1, 0x38, 28, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_2] = RTK_PIN_CONFIG(gpio_2, 0x3c, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_3] = RTK_PIN_CONFIG(gpio_3, 0x3c, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_4] = RTK_PIN_CONFIG(gpio_4, 0x3c, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_5] = RTK_PIN_CONFIG(gpio_5, 0x3c, 12, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_6] = RTK_PIN_CONFIG(gpio_6, 0x3c, 16, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_7] = RTK_PIN_CONFIG(gpio_7, 0x3c, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_8] = RTK_PIN_CONFIG(gpio_8, 0x3c, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_9] = RTK_PIN_CONFIG(gpio_9, 0x3c, 28, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_10] = RTK_PIN_CONFIG(gpio_10, 0x40, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_11] = RTK_PIN_CONFIG(gpio_11, 0x40, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_12] = RTK_PIN_CONFIG(gpio_12, 0x40, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_13] = RTK_PIN_CONFIG(gpio_13, 0x40, 12, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_14] = RTK_PIN_CONFIG(gpio_14, 0x40, 16, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_15] = RTK_PIN_CONFIG(gpio_15, 0x40, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_16] = RTK_PIN_CONFIG(gpio_16, 0x40, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_17] = RTK_PIN_CONFIG(gpio_17, 0x40, 28, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_18] = RTK_PIN_CONFIG(gpio_18, 0x44, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_19] = RTK_PIN_CONFIG(gpio_19, 0x44, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_20] = RTK_PIN_CONFIG(gpio_20, 0x44, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_21] = RTK_PIN_CONFIG(gpio_21, 0x44, 12, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_22] = RTK_PIN_CONFIG(gpio_22, 0x44, 16, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_23] = RTK_PIN_CONFIG(gpio_23, 0x44, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_USB_CC2] = RTK_PIN_CONFIG(usb_cc2, 0x44, 24, PCONF_UNSUPP, PCONF_UNSUPP, 0, 1, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_25] = RTK_PIN_CONFIG(gpio_25, 0x44, 26, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_26] = RTK_PIN_CONFIG(gpio_26, 0x48, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_27] = RTK_PIN_CONFIG(gpio_27, 0x48, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_28] = RTK_PIN_CONFIG(gpio_28, 0x48, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_29] = RTK_PIN_CONFIG(gpio_29, 0x48, 12, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_30] = RTK_PIN_CONFIG(gpio_30, 0x48, 16, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_31] = RTK_PIN_CONFIG(gpio_31, 0x48, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_32] = RTK_PIN_CONFIG(gpio_32, 0x4c, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_33] = RTK_PIN_CONFIG(gpio_33, 0x4c, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_34] = RTK_PIN_CONFIG(gpio_34, 0x4c, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_35] = RTK_PIN_CONFIG(gpio_35, 0x50, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_HIF_DATA] = RTK_PIN_CONFIG(hif_data, 0x50, 4, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_HIF_EN] = RTK_PIN_CONFIG(hif_en, 0x50, 16, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_HIF_RDY] = RTK_PIN_CONFIG(hif_rdy, 0x54, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_HIF_CLK] = RTK_PIN_CONFIG(hif_clk, 0x54, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_40] = RTK_PIN_CONFIG(gpio_40, 0x58, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_41] = RTK_PIN_CONFIG(gpio_41, 0x58, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_42] = RTK_PIN_CONFIG(gpio_42, 0x5c, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_43] = RTK_PIN_CONFIG(gpio_43, 0x5c, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_44] = RTK_PIN_CONFIG(gpio_44, 0x60, 0, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_45] = RTK_PIN_CONFIG(gpio_45, 0x60, 12, 0, 1, 3, 2, PCONF_UNSUPP, PCONF_UNSUPP), + [RTD1319_ISO_GPIO_46] = RTK_PIN_CONFIG(gpio_46, 0x60, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_47] = RTK_PIN_CONFIG(gpio_47, 0x60, 28, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_48] = RTK_PIN_CONFIG(gpio_48, 0x64, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_49] = RTK_PIN_CONFIG(gpio_49, 0x64, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_50] = RTK_PIN_CONFIG(gpio_50, 0x64, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_USB_CC1] = RTK_PIN_CONFIG(usb_cc1, 0x64, 12, PCONF_UNSUPP, PCONF_UNSUPP, 0, 1, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_52] = RTK_PIN_CONFIG(gpio_52, 0x64, 14, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_53] = RTK_PIN_CONFIG(gpio_53, 0x64, 18, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_IR_RX] = RTK_PIN_CONFIG(ir_rx, 0x64, 22, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_UR0_RX] = RTK_PIN_CONFIG(ur0_rx, 0x64, 26, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_UR0_TX] = RTK_PIN_CONFIG(ur0_tx, 0x68, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_57] = RTK_PIN_CONFIG(gpio_57, 0x68, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_58] = RTK_PIN_CONFIG(gpio_58, 0x68, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_59] = RTK_PIN_CONFIG(gpio_59, 0x68, 12, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_60] = RTK_PIN_CONFIG(gpio_60, 0x68, 16, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_61] = RTK_PIN_CONFIG(gpio_61, 0x68, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_62] = RTK_PIN_CONFIG(gpio_62, 0x68, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_63] = RTK_PIN_CONFIG(gpio_63, 0x68, 28, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_64] = RTK_PIN_CONFIG(gpio_64, 0x6c, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_65] = RTK_PIN_CONFIG(gpio_65, 0x6c, 4, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_66] = RTK_PIN_CONFIG(gpio_66, 0x6c, 8, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_67] = RTK_PIN_CONFIG(gpio_67, 0x6c, 12, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_68] = RTK_PIN_CONFIG(gpio_68, 0x6c, 16, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_69] = RTK_PIN_CONFIG(gpio_69, 0x6c, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_70] = RTK_PIN_CONFIG(gpio_70, 0x6c, 24, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_71] = RTK_PIN_CONFIG(gpio_71, 0x70, 0, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_72] = RTK_PIN_CONFIG(gpio_72, 0x70, 5, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_73] = RTK_PIN_CONFIG(gpio_73, 0x70, 10, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_74] = RTK_PIN_CONFIG(gpio_74, 0x70, 15, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_75] = RTK_PIN_CONFIG(gpio_75, 0x70, 20, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), + [RTD1319_ISO_GPIO_76] = RTK_PIN_CONFIG(gpio_76, 0x70, 25, 1, 2, 0, 3, PCONF_UNSUPP, PADDRI_4_8), +}; + +static const struct rtd_pin_sconfig_desc rtd1319_iso_sconfigs[] = { + RTK_PIN_SCONFIG(emmc_rst_n, 0x1c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_dd_sb, 0x1c, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(emmc_clk, 0x20, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_cmd, 0x20, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(emmc_data_0, 0x24, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_data_1, 0x24, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(emmc_data_2, 0x28, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_data_3, 0x28, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(emmc_data_4, 0x2c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_data_5, 0x2c, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(emmc_data_6, 0x30, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_data_7, 0x30, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(spi_ce_n, 0x34, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(spi_sck, 0x34, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(spi_so, 0x38, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(spi_si, 0x38, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(gpio_32, 0x4c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(gpio_33, 0x4c, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(hif_data, 0x50, 7, 3, 10, 3, 13, 3), + RTK_PIN_SCONFIG(hif_en, 0x50, 19, 3, 22, 3, 25, 3), + RTK_PIN_SCONFIG(hif_rdy, 0x54, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(hif_clk, 0x54, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(gpio_40, 0x58, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(gpio_41, 0x58, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(gpio_42, 0x5c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(gpio_43, 0x5c, 15, 3, 18, 3, 21, 3), + RTK_PIN_SCONFIG(gpio_44, 0x60, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(gpio_45, 0x60, 15, 3, 18, 3, 21, 3), +}; + + + +static const struct rtd_pinctrl_desc rtd1319_iso_pinctrl_desc = { + .pins = rtd1319_iso_pins, + .num_pins = ARRAY_SIZE(rtd1319_iso_pins), + .groups = rtd1319_pin_groups, + .num_groups = ARRAY_SIZE(rtd1319_pin_groups), + .functions = rtd1319_pin_functions, + .num_functions = ARRAY_SIZE(rtd1319_pin_functions), + .muxes = rtd1319_iso_muxes, + .num_muxes = ARRAY_SIZE(rtd1319_iso_muxes), + .configs = rtd1319_iso_configs, + .num_configs = ARRAY_SIZE(rtd1319_iso_configs), + .sconfigs = rtd1319_iso_sconfigs, + .num_sconfigs = ARRAY_SIZE(rtd1319_iso_sconfigs), +}; +#endif diff --git a/drivers/pinctrl/realtek/pinctrl-rtd1619b.h b/drivers/pinctrl/realtek/pinctrl-rtd1619b.h new file mode 100644 index 000000000000..5c0cb284959f --- /dev/null +++ b/drivers/pinctrl/realtek/pinctrl-rtd1619b.h @@ -0,0 +1,1566 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later*/ + +/* + * Realtek DHC pin controller driver + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef PINCTRL_RTD1619B_H +#define PINCTRL_RTD1619B_H + +enum rtd16xxb_iso_pins { + RTD1619B_ISO_GPIO_0 = 0, + RTD1619B_ISO_GPIO_1, + RTD1619B_ISO_GPIO_2, + RTD1619B_ISO_GPIO_3, + RTD1619B_ISO_GPIO_4, + RTD1619B_ISO_GPIO_5, + RTD1619B_ISO_GPIO_6, + RTD1619B_ISO_GPIO_7, + RTD1619B_ISO_GPIO_8, + RTD1619B_ISO_GPIO_9, + RTD1619B_ISO_GPIO_10, + RTD1619B_ISO_GPIO_11, + RTD1619B_ISO_GPIO_12, + RTD1619B_ISO_GPIO_13, + RTD1619B_ISO_GPIO_14, + RTD1619B_ISO_GPIO_15, + RTD1619B_ISO_GPIO_16, + RTD1619B_ISO_GPIO_17, + RTD1619B_ISO_GPIO_18, + RTD1619B_ISO_GPIO_19, + RTD1619B_ISO_GPIO_20, + RTD1619B_ISO_GPIO_21, + RTD1619B_ISO_GPIO_22, + RTD1619B_ISO_GPIO_23, + RTD1619B_ISO_USB_CC2, + RTD1619B_ISO_GPIO_25, + RTD1619B_ISO_GPIO_26, + RTD1619B_ISO_GPIO_27, + RTD1619B_ISO_GPIO_28, + RTD1619B_ISO_GPIO_29, + RTD1619B_ISO_GPIO_30, + RTD1619B_ISO_GPIO_31, + RTD1619B_ISO_GPIO_32, + RTD1619B_ISO_GPIO_33, + RTD1619B_ISO_GPIO_34, + RTD1619B_ISO_GPIO_35, + RTD1619B_ISO_HIF_DATA, + RTD1619B_ISO_HIF_EN, + RTD1619B_ISO_HIF_RDY, + RTD1619B_ISO_HIF_CLK, + RTD1619B_ISO_GPIO_40, + RTD1619B_ISO_GPIO_41, + RTD1619B_ISO_GPIO_42, + RTD1619B_ISO_GPIO_43, + RTD1619B_ISO_GPIO_44, + RTD1619B_ISO_GPIO_45, + RTD1619B_ISO_GPIO_46, + RTD1619B_ISO_GPIO_47, + RTD1619B_ISO_GPIO_48, + RTD1619B_ISO_GPIO_49, + RTD1619B_ISO_GPIO_50, + RTD1619B_ISO_USB_CC1, + RTD1619B_ISO_GPIO_52, + RTD1619B_ISO_GPIO_53, + RTD1619B_ISO_IR_RX, + RTD1619B_ISO_UR0_RX, + RTD1619B_ISO_UR0_TX, + RTD1619B_ISO_GPIO_57, + RTD1619B_ISO_GPIO_58, + RTD1619B_ISO_GPIO_59, + RTD1619B_ISO_GPIO_60, + RTD1619B_ISO_GPIO_61, + RTD1619B_ISO_GPIO_62, + RTD1619B_ISO_GPIO_63, + RTD1619B_ISO_GPIO_64, + RTD1619B_ISO_GPIO_65, + RTD1619B_ISO_GPIO_66, + RTD1619B_ISO_GPIO_67, + RTD1619B_ISO_GPIO_68, + RTD1619B_ISO_GPIO_69, + RTD1619B_ISO_GPIO_70, + RTD1619B_ISO_GPIO_71, + RTD1619B_ISO_GPIO_72, + RTD1619B_ISO_GPIO_73, + RTD1619B_ISO_GPIO_74, + RTD1619B_ISO_GPIO_75, + RTD1619B_ISO_GPIO_76, + RTD1619B_ISO_EMMC_CMD, + RTD1619B_ISO_SPI_CE_N, + RTD1619B_ISO_SPI_SCK, + RTD1619B_ISO_SPI_SO, + RTD1619B_ISO_SPI_SI, + RTD1619B_ISO_EMMC_RST_N, + RTD1619B_ISO_EMMC_DD_SB, + RTD1619B_ISO_EMMC_CLK, + RTD1619B_ISO_EMMC_DATA_0, + RTD1619B_ISO_EMMC_DATA_1, + RTD1619B_ISO_EMMC_DATA_2, + RTD1619B_ISO_EMMC_DATA_3, + RTD1619B_ISO_EMMC_DATA_4, + RTD1619B_ISO_EMMC_DATA_5, + RTD1619B_ISO_EMMC_DATA_6, + RTD1619B_ISO_EMMC_DATA_7, + RTD1619B_ISO_UR2_LOC, + RTD1619B_ISO_GSPI_LOC, + RTD1619B_ISO_SDIO_LOC, + RTD1619B_ISO_HI_LOC, + RTD1619B_ISO_HI_WIDTH, + RTD1619B_ISO_SF_EN, + RTD1619B_ISO_ARM_TRACE_DBG_EN, + RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC0, + RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC0, + RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC1, + RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC1, + RTD1619B_ISO_EJTAG_ACPU_LOC, + RTD1619B_ISO_EJTAG_VCPU_LOC, + RTD1619B_ISO_EJTAG_SCPU_LOC, + RTD1619B_ISO_DMIC_LOC, + RTD1619B_ISO_ISO_GSPI_LOC, + RTD1619B_ISO_EJTAG_VE3_LOC, + RTD1619B_ISO_EJTAG_AUCPU0_LOC, + RTD1619B_ISO_EJTAG_AUCPU1_LOC, +}; + +static const struct pinctrl_pin_desc rtd1619b_iso_pins[] = { + PINCTRL_PIN(RTD1619B_ISO_GPIO_0, "gpio_0"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_1, "gpio_1"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_2, "gpio_2"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_3, "gpio_3"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_4, "gpio_4"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_5, "gpio_5"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_6, "gpio_6"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_7, "gpio_7"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_8, "gpio_8"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_9, "gpio_9"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_10, "gpio_10"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_11, "gpio_11"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_12, "gpio_12"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_13, "gpio_13"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_14, "gpio_14"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_15, "gpio_15"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_16, "gpio_16"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_17, "gpio_17"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_18, "gpio_18"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_19, "gpio_19"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_20, "gpio_20"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_21, "gpio_21"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_22, "gpio_22"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_23, "gpio_23"), + PINCTRL_PIN(RTD1619B_ISO_USB_CC2, "usb_cc2"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_25, "gpio_25"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_26, "gpio_26"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_27, "gpio_27"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_28, "gpio_28"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_29, "gpio_29"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_30, "gpio_30"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_31, "gpio_31"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_32, "gpio_32"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_33, "gpio_33"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_34, "gpio_34"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_35, "gpio_35"), + PINCTRL_PIN(RTD1619B_ISO_HIF_DATA, "hif_data"), + PINCTRL_PIN(RTD1619B_ISO_HIF_EN, "hif_en"), + PINCTRL_PIN(RTD1619B_ISO_HIF_RDY, "hif_rdy"), + PINCTRL_PIN(RTD1619B_ISO_HIF_CLK, "hif_clk"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_40, "gpio_40"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_41, "gpio_41"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_42, "gpio_42"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_43, "gpio_43"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_44, "gpio_44"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_45, "gpio_45"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_46, "gpio_46"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_47, "gpio_47"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_48, "gpio_48"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_49, "gpio_49"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_50, "gpio_50"), + PINCTRL_PIN(RTD1619B_ISO_USB_CC1, "usb_cc1"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_52, "gpio_52"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_53, "gpio_53"), + PINCTRL_PIN(RTD1619B_ISO_IR_RX, "ir_rx"), + PINCTRL_PIN(RTD1619B_ISO_UR0_RX, "ur0_rx"), + PINCTRL_PIN(RTD1619B_ISO_UR0_TX, "ur0_tx"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_57, "gpio_57"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_58, "gpio_58"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_59, "gpio_59"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_60, "gpio_60"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_61, "gpio_61"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_62, "gpio_62"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_63, "gpio_63"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_64, "gpio_64"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_65, "gpio_65"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_66, "gpio_66"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_67, "gpio_67"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_68, "gpio_68"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_69, "gpio_69"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_70, "gpio_70"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_71, "gpio_71"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_72, "gpio_72"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_73, "gpio_73"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_74, "gpio_74"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_75, "gpio_75"), + PINCTRL_PIN(RTD1619B_ISO_GPIO_76, "gpio_76"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_CMD, "emmc_cmd"), + PINCTRL_PIN(RTD1619B_ISO_SPI_CE_N, "spi_ce_n"), + PINCTRL_PIN(RTD1619B_ISO_SPI_SCK, "spi_sck"), + PINCTRL_PIN(RTD1619B_ISO_SPI_SO, "spi_so"), + PINCTRL_PIN(RTD1619B_ISO_SPI_SI, "spi_si"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_RST_N, "emmc_rst_n"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DD_SB, "emmc_dd_sb"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_CLK, "emmc_clk"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_0, "emmc_data_0"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_1, "emmc_data_1"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_2, "emmc_data_2"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_3, "emmc_data_3"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_4, "emmc_data_4"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_5, "emmc_data_5"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_6, "emmc_data_6"), + PINCTRL_PIN(RTD1619B_ISO_EMMC_DATA_7, "emmc_data_7"), + PINCTRL_PIN(RTD1619B_ISO_UR2_LOC, "ur2_loc"), + PINCTRL_PIN(RTD1619B_ISO_GSPI_LOC, "gspi_loc"), + PINCTRL_PIN(RTD1619B_ISO_SDIO_LOC, "sdio_loc"), + PINCTRL_PIN(RTD1619B_ISO_HI_LOC, "hi_loc"), + PINCTRL_PIN(RTD1619B_ISO_HI_WIDTH, "hi_width"), + PINCTRL_PIN(RTD1619B_ISO_SF_EN, "sf_en"), + PINCTRL_PIN(RTD1619B_ISO_ARM_TRACE_DBG_EN, "arm_trace_dbg_en"), + PINCTRL_PIN(RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC0, "pwm_01_open_drain_en_loc0"), + PINCTRL_PIN(RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC0, "pwm_23_open_drain_en_loc0"), + PINCTRL_PIN(RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC1, "pwm_01_open_drain_en_loc1"), + PINCTRL_PIN(RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC1, "pwm_23_open_drain_en_loc1"), + PINCTRL_PIN(RTD1619B_ISO_EJTAG_ACPU_LOC, "ejtag_acpu_loc"), + PINCTRL_PIN(RTD1619B_ISO_EJTAG_VCPU_LOC, "ejtag_vcpu_loc"), + PINCTRL_PIN(RTD1619B_ISO_EJTAG_SCPU_LOC, "ejtag_scpu_loc"), + PINCTRL_PIN(RTD1619B_ISO_DMIC_LOC, "dmic_loc"), + PINCTRL_PIN(RTD1619B_ISO_ISO_GSPI_LOC, "iso_gspi_loc"), + PINCTRL_PIN(RTD1619B_ISO_EJTAG_VE3_LOC, "ejtag_ve3_loc"), + PINCTRL_PIN(RTD1619B_ISO_EJTAG_AUCPU0_LOC, "ejtag_aucpu0_loc"), + PINCTRL_PIN(RTD1619B_ISO_EJTAG_AUCPU1_LOC, "ejtag_aucpu1_loc"), +}; + +#define DECLARE_RTD1619B_PIN(_pin, _name) static const unsigned int rtd1619b_## _name ##_pins[] = { _pin } + +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_0, gpio_0); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_1, gpio_1); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_2, gpio_2); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_3, gpio_3); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_4, gpio_4); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_5, gpio_5); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_6, gpio_6); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_7, gpio_7); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_8, gpio_8); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_9, gpio_9); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_10, gpio_10); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_11, gpio_11); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_12, gpio_12); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_13, gpio_13); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_14, gpio_14); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_15, gpio_15); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_16, gpio_16); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_17, gpio_17); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_18, gpio_18); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_19, gpio_19); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_20, gpio_20); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_21, gpio_21); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_22, gpio_22); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_23, gpio_23); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_USB_CC2, usb_cc2); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_25, gpio_25); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_26, gpio_26); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_27, gpio_27); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_28, gpio_28); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_29, gpio_29); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_30, gpio_30); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_31, gpio_31); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_32, gpio_32); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_33, gpio_33); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_34, gpio_34); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_35, gpio_35); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_HIF_DATA, hif_data); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_HIF_EN, hif_en); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_HIF_RDY, hif_rdy); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_HIF_CLK, hif_clk); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_40, gpio_40); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_41, gpio_41); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_42, gpio_42); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_43, gpio_43); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_44, gpio_44); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_45, gpio_45); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_46, gpio_46); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_47, gpio_47); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_48, gpio_48); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_49, gpio_49); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_50, gpio_50); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_USB_CC1, usb_cc1); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_52, gpio_52); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_53, gpio_53); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_IR_RX, ir_rx); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_UR0_RX, ur0_rx); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_UR0_TX, ur0_tx); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_57, gpio_57); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_58, gpio_58); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_59, gpio_59); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_60, gpio_60); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_61, gpio_61); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_62, gpio_62); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_63, gpio_63); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_64, gpio_64); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_65, gpio_65); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_66, gpio_66); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_67, gpio_67); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_68, gpio_68); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_69, gpio_69); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_70, gpio_70); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_71, gpio_71); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_72, gpio_72); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_73, gpio_73); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_74, gpio_74); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_75, gpio_75); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GPIO_76, gpio_76); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_CMD, emmc_cmd); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_SPI_CE_N, spi_ce_n); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_SPI_SCK, spi_sck); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_SPI_SO, spi_so); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_SPI_SI, spi_si); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_RST_N, emmc_rst_n); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DD_SB, emmc_dd_sb); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_CLK, emmc_clk); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_0, emmc_data_0); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_1, emmc_data_1); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_2, emmc_data_2); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_3, emmc_data_3); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_4, emmc_data_4); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_5, emmc_data_5); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_6, emmc_data_6); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EMMC_DATA_7, emmc_data_7); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_UR2_LOC, ur2_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_GSPI_LOC, gspi_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_SDIO_LOC, sdio_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_HI_LOC, hi_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_HI_WIDTH, hi_width); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_SF_EN, sf_en); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_ARM_TRACE_DBG_EN, arm_trace_dbg_en); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC0, pwm_01_open_drain_en_loc0); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC0, pwm_23_open_drain_en_loc0); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC1, pwm_01_open_drain_en_loc1); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC1, pwm_23_open_drain_en_loc1); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EJTAG_ACPU_LOC, ejtag_acpu_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EJTAG_VCPU_LOC, ejtag_vcpu_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EJTAG_SCPU_LOC, ejtag_scpu_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_DMIC_LOC, dmic_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_ISO_GSPI_LOC, iso_gspi_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EJTAG_VE3_LOC, ejtag_ve3_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EJTAG_AUCPU0_LOC, ejtag_aucpu0_loc); +DECLARE_RTD1619B_PIN(RTD1619B_ISO_EJTAG_AUCPU1_LOC, ejtag_aucpu1_loc); + + + + +#define RTD1619B_GROUP(_name) \ + { \ + .name = # _name, \ + .pins = rtd1619b_ ## _name ## _pins, \ + .num_pins = ARRAY_SIZE(rtd1619b_ ## _name ## _pins), \ + } + +static const struct rtd_pin_group_desc rtd1619b_pin_groups[] = { + RTD1619B_GROUP(gpio_0), + RTD1619B_GROUP(gpio_1), + RTD1619B_GROUP(gpio_2), + RTD1619B_GROUP(gpio_3), + RTD1619B_GROUP(gpio_4), + RTD1619B_GROUP(gpio_5), + RTD1619B_GROUP(gpio_6), + RTD1619B_GROUP(gpio_7), + RTD1619B_GROUP(gpio_8), + RTD1619B_GROUP(gpio_9), + RTD1619B_GROUP(gpio_10), + RTD1619B_GROUP(gpio_11), + RTD1619B_GROUP(gpio_12), + RTD1619B_GROUP(gpio_13), + RTD1619B_GROUP(gpio_14), + RTD1619B_GROUP(gpio_15), + RTD1619B_GROUP(gpio_16), + RTD1619B_GROUP(gpio_17), + RTD1619B_GROUP(gpio_18), + RTD1619B_GROUP(gpio_19), + RTD1619B_GROUP(gpio_20), + RTD1619B_GROUP(gpio_21), + RTD1619B_GROUP(gpio_22), + RTD1619B_GROUP(gpio_23), + RTD1619B_GROUP(usb_cc2), + RTD1619B_GROUP(gpio_25), + RTD1619B_GROUP(gpio_26), + RTD1619B_GROUP(gpio_27), + RTD1619B_GROUP(gpio_28), + RTD1619B_GROUP(gpio_29), + RTD1619B_GROUP(gpio_30), + RTD1619B_GROUP(gpio_31), + RTD1619B_GROUP(gpio_32), + RTD1619B_GROUP(gpio_33), + RTD1619B_GROUP(gpio_34), + RTD1619B_GROUP(gpio_35), + RTD1619B_GROUP(hif_data), + RTD1619B_GROUP(hif_en), + RTD1619B_GROUP(hif_rdy), + RTD1619B_GROUP(hif_clk), + RTD1619B_GROUP(gpio_40), + RTD1619B_GROUP(gpio_41), + RTD1619B_GROUP(gpio_42), + RTD1619B_GROUP(gpio_43), + RTD1619B_GROUP(gpio_44), + RTD1619B_GROUP(gpio_45), + RTD1619B_GROUP(gpio_46), + RTD1619B_GROUP(gpio_47), + RTD1619B_GROUP(gpio_48), + RTD1619B_GROUP(gpio_49), + RTD1619B_GROUP(gpio_50), + RTD1619B_GROUP(usb_cc1), + RTD1619B_GROUP(gpio_52), + RTD1619B_GROUP(gpio_53), + RTD1619B_GROUP(ir_rx), + RTD1619B_GROUP(ur0_rx), + RTD1619B_GROUP(ur0_tx), + RTD1619B_GROUP(gpio_57), + RTD1619B_GROUP(gpio_58), + RTD1619B_GROUP(gpio_59), + RTD1619B_GROUP(gpio_60), + RTD1619B_GROUP(gpio_61), + RTD1619B_GROUP(gpio_62), + RTD1619B_GROUP(gpio_63), + RTD1619B_GROUP(gpio_64), + RTD1619B_GROUP(gpio_65), + RTD1619B_GROUP(gpio_66), + RTD1619B_GROUP(gpio_67), + RTD1619B_GROUP(gpio_68), + RTD1619B_GROUP(gpio_69), + RTD1619B_GROUP(gpio_70), + RTD1619B_GROUP(gpio_71), + RTD1619B_GROUP(gpio_72), + RTD1619B_GROUP(gpio_73), + RTD1619B_GROUP(gpio_74), + RTD1619B_GROUP(gpio_75), + RTD1619B_GROUP(gpio_76), + RTD1619B_GROUP(emmc_cmd), + RTD1619B_GROUP(spi_ce_n), + RTD1619B_GROUP(spi_sck), + RTD1619B_GROUP(spi_so), + RTD1619B_GROUP(spi_si), + RTD1619B_GROUP(emmc_rst_n), + RTD1619B_GROUP(emmc_dd_sb), + RTD1619B_GROUP(emmc_clk), + RTD1619B_GROUP(emmc_data_0), + RTD1619B_GROUP(emmc_data_1), + RTD1619B_GROUP(emmc_data_2), + RTD1619B_GROUP(emmc_data_3), + RTD1619B_GROUP(emmc_data_4), + RTD1619B_GROUP(emmc_data_5), + RTD1619B_GROUP(emmc_data_6), + RTD1619B_GROUP(emmc_data_7), + RTD1619B_GROUP(ur2_loc), + RTD1619B_GROUP(gspi_loc), + RTD1619B_GROUP(sdio_loc), + RTD1619B_GROUP(hi_loc), + RTD1619B_GROUP(hi_width), + RTD1619B_GROUP(sf_en), + RTD1619B_GROUP(arm_trace_dbg_en), + RTD1619B_GROUP(pwm_01_open_drain_en_loc0), + RTD1619B_GROUP(pwm_23_open_drain_en_loc0), + RTD1619B_GROUP(pwm_01_open_drain_en_loc1), + RTD1619B_GROUP(pwm_23_open_drain_en_loc1), + RTD1619B_GROUP(ejtag_acpu_loc), + RTD1619B_GROUP(ejtag_vcpu_loc), + RTD1619B_GROUP(ejtag_scpu_loc), + RTD1619B_GROUP(dmic_loc), + RTD1619B_GROUP(iso_gspi_loc), + RTD1619B_GROUP(ejtag_ve3_loc), + RTD1619B_GROUP(ejtag_aucpu0_loc), + RTD1619B_GROUP(ejtag_aucpu1_loc), +}; + +static const char * const rtd1619b_gpio_groups[] = { + "gpio_0", "gpio_1", "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "gpio_7", "gpio_8", "gpio_9", + "gpio_10", "gpio_11", "gpio_12", "gpio_13", "gpio_14", + "gpio_15", "gpio_16", "gpio_17", "gpio_18", "gpio_19", + "gpio_20", "gpio_21", "gpio_22", "gpio_23", "usb_cc2", + "gpio_25", "gpio_26", "gpio_27", "gpio_28", "gpio_29", + "gpio_30", "gpio_31", "gpio_32", "gpio_33", "gpio_34", + "gpio_35", "hif_data", "hif_en", "hif_rdy", "hif_clk", + "gpio_40", "gpio_41", "gpio_42", "gpio_43", "gpio_44", + "gpio_45", "gpio_46", "gpio_47", "gpio_48", "gpio_49", + "gpio_50", "usb_cc1", "gpio_52", "gpio_53", "ir_rx", + "ur0_rx", "ur0_tx", "gpio_57", "gpio_58", "gpio_59", + "gpio_60", "gpio_61", "gpio_62", "gpio_63", "gpio_64", + "gpio_65", "gpio_66", "gpio_67", "gpio_68", "gpio_69", + "gpio_70", "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "emmc_cmd", "spi_ce_n", "spi_sck", + "spi_so", "spi_si"}; +static const char * const rtd1619b_nf_groups[] = { + "emmc_rst_n", "emmc_clk", "emmc_cmd", "emmc_data_0", "emmc_data_1", + "emmc_data_2", "emmc_data_3", "emmc_data_4", + "emmc_data_5", "emmc_data_6", "emmc_data_7", "spi_ce_n", + "spi_sck", "spi_so", "spi_si" }; +static const char * const rtd1619b_nf_spi_groups[] = { + "emmc_data_0", "emmc_data_1", + "emmc_data_2", "emmc_data_3", "emmc_data_4", + "emmc_data_5" }; +static const char * const rtd1619b_spi_groups[] = { + "spi_ce_n", "spi_sck", "spi_so", "spi_si" }; +static const char * const rtd1619b_emmc_groups[] = { + "emmc_rst_n", "emmc_clk", "emmc_data_0", "emmc_data_1", + "emmc_data_2", "emmc_data_3", "emmc_data_4", + "emmc_data_5", "emmc_data_6", "emmc_data_7", + "emmc_dd_sb", "emmc_cmd"}; + +static const char * const rtd1619b_pmic_groups[] = { "spi_ce_n" }; +static const char * const rtd1619b_spdif_groups[] = { "gpio_50" }; +static const char * const rtd1619b_spdif_coaxial_groups[] = { "gpio_1" }; +static const char * const rtd1619b_spdif_optical_loc0_groups[] = { "gpio_6" }; +static const char * const rtd1619b_spdif_optical_loc1_groups[] = { "gpio_21" }; + +static const char * const rtd1619b_emmc_spi_groups[] = { + "gpio_1", "gpio_2", "gpio_3", "gpio_4", "gpio_5", "gpio_6" }; +static const char * const rtd1619b_sc1_groups[] = { + "gpio_2", "gpio_3", "gpio_4", "gpio_5" }; +static const char * const rtd1619b_uart0_groups[] = { "ur0_rx", "ur0_tx" }; +static const char * const rtd1619b_uart1_groups[] = { + "gpio_8", "gpio_9", "gpio_10", "gpio_11" }; +static const char * const rtd1619b_uart2_loc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31", "ur2_loc" }; +static const char * const rtd1619b_uart2_loc1_groups[] = { + "gpio_25", "gpio_26", "gpio_27", "gpio_28", "ur2_loc" }; +static const char * const rtd1619b_gspi_loc1_groups[] = { + "gpio_8", "gpio_9", "gpio_10", "gpio_11", "gspi_loc" }; +static const char * const rtd1619b_iso_gspi_loc1_groups[] = { + "gpio_8", "gpio_9", "gpio_10", "gpio_11", "iso_gspi_loc" }; +static const char * const rtd1619b_i2c0_groups[] = { "gpio_12", "gpio_13" }; +static const char * const rtd1619b_i2c1_groups[] = { "gpio_16", "gpio_17" }; +static const char * const rtd1619b_i2c3_groups[] = { "gpio_63", "gpio_64" }; +static const char * const rtd1619b_i2c4_groups[] = { "gpio_34", "gpio_35" }; +static const char * const rtd1619b_i2c5_groups[] = { "gpio_29", "gpio_46" }; +static const char * const rtd1619b_pwm0_groups[] = { "gpio_20", "gpio_26" }; +static const char * const rtd1619b_pwm1_groups[] = { "gpio_21", "gpio_27" }; +static const char * const rtd1619b_pwm2_groups[] = { "gpio_22", "gpio_28" }; +static const char * const rtd1619b_pwm3_groups[] = { "gpio_23", "gpio_47" }; +static const char * const rtd1619b_etn_led_groups[] = { "gpio_14", "gpio_15", "gpio_23" }; +static const char * const rtd1619b_etn_phy_groups[] = { "gpio_14", "gpio_15" }; +static const char * const rtd1619b_etn_clk_groups[] = { "gpio_14" }; +static const char * const rtd1619b_sc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31" }; +static const char * const rtd1619b_vfd_groups[] = { + "gpio_26", "gpio_27", "gpio_28" }; + +static const char * const rtd1619b_gspi_loc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31", "gspi_loc" }; +static const char * const rtd1619b_iso_gspi_loc0_groups[] = { + "gpio_18", "gpio_19", "gpio_20", "gpio_31", "iso_gspi_loc" }; +static const char * const rtd1619b_pcie1_groups[] = { "gpio_25" }; +static const char * const rtd1619b_pcie2_groups[] = { "gpio_52" }; +static const char * const rtd1619b_sd_groups[] = { + "gpio_32", "gpio_33", "gpio_34", "gpio_35", "hif_data", + "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_sdio_loc0_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_rdy", "hif_clk", "sdio_loc" }; +static const char * const rtd1619b_sdio_loc1_groups[] = { + "gpio_40", "gpio_41", "gpio_42", "gpio_43", "gpio_44", + "gpio_45", "sdio_loc" }; +static const char * const rtd1619b_hi_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_hi_m_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_dc_fan_groups[] = { "gpio_47" }; +static const char * const rtd1619b_pll_test_loc0_groups[] = { "gpio_52", "gpio_53" }; +static const char * const rtd1619b_pll_test_loc1_groups[] = { "gpio_48", "gpio_49" }; +static const char * const rtd1619b_tdm_ai_loc0_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60" }; +static const char * const rtd1619b_tdm_ai_loc1_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_dmic_loc0_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60", "gpio_61", + "gpio_62", "gpio_63", "gpio_64", "dmic_loc"}; +static const char * const rtd1619b_dmic_loc1_groups[] = { + "gpio_32", "gpio_33", "gpio_34", "gpio_35", "hif_data", + "hif_en", "hif_rdy", "hif_clk", "dmic_loc" }; +static const char * const rtd1619b_ai_loc0_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60", "gpio_61", + "gpio_62", "gpio_63" }; +static const char * const rtd1619b_ai_loc1_groups[] = { + "gpio_32", "gpio_33", "gpio_34", "hif_data", + "hif_en", "hif_rdy", "hif_clk"}; +static const char * const rtd1619b_tp0_groups[] = { + "gpio_66", "gpio_67", "gpio_68", "gpio_69", + "gpio_70", "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76" }; +static const char * const rtd1619b_tp1_groups[] = { + "gpio_69", "gpio_70", "gpio_71", "gpio_72" }; +static const char * const rtd1619b_ao_groups[] = { + "gpio_66", "gpio_67", "gpio_68", "gpio_69", + "gpio_70", "gpio_71", "gpio_72" }; +static const char * const rtd1619b_uart2_disable_groups[] = { "ur2_loc" }; +static const char * const rtd1619b_gspi_disable_groups[] = { "gspi_loc" }; +static const char * const rtd1619b_sdio_disable_groups[] = { "sdio_loc" }; +static const char * const rtd1619b_hi_loc_disable_groups[] = { "hi_loc" }; +static const char * const rtd1619b_hi_loc0_groups[] = { "hi_loc" }; +static const char * const rtd1619b_hi_width_disable_groups[] = { "hi_width" }; +static const char * const rtd1619b_hi_width_1bit_groups[] = { "hi_width" }; + +static const char * const rtd1619b_vtc_i2si_loc0_groups[] = { + "gpio_32", "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_vtc_tdm_loc0_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_vtc_dmic_loc0_groups[] = { + "hif_data", "hif_en", "hif_rdy", "hif_clk" }; +static const char * const rtd1619b_vtc_i2si_loc1_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60", "gpio_61" }; +static const char * const rtd1619b_vtc_tdm_loc1_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60" }; +static const char * const rtd1619b_vtc_dmic_loc1_groups[] = { + "gpio_57", "gpio_58", "gpio_59", "gpio_60" }; +static const char * const rtd1619b_vtc_i2so_groups[] = { + "gpio_66", "gpio_67", "gpio_68", "gpio_69" }; +static const char * const rtd1619b_ve3_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_ve3_loc" }; +static const char * const rtd1619b_aucpu0_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_aucpu0_loc" }; +static const char * const rtd1619b_aucpu1_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_aucpu1_loc" }; +static const char * const rtd1619b_ve3_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_ve3_loc" }; +static const char * const rtd1619b_aucpu0_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_aucpu0_loc" }; +static const char * const rtd1619b_aucpu1_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_aucpu1_loc" }; + +static const char * const rtd1619b_ve3_ejtag_loc2_groups[] = { + "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "ejtag_ve3_loc" }; +static const char * const rtd1619b_aucpu0_ejtag_loc2_groups[] = { + "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "ejtag_aucpu0_loc" }; +static const char * const rtd1619b_aucpu1_ejtag_loc2_groups[] = { + "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "ejtag_aucpu1_loc" }; + +static const char * const rtd1619b_scpu_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_scpu_loc" }; +static const char * const rtd1619b_acpu_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_acpu_loc" }; +static const char * const rtd1619b_vcpu_ejtag_loc0_groups[] = { + "gpio_2", "gpio_3", "gpio_4", + "gpio_5", "gpio_6", "ejtag_vcpu_loc" }; +static const char * const rtd1619b_scpu_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_scpu_loc" }; +static const char * const rtd1619b_acpu_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_acpu_loc" }; +static const char * const rtd1619b_vcpu_ejtag_loc1_groups[] = { + "gpio_32", "gpio_33", "hif_data", "hif_en", + "hif_clk", "ejtag_vcpu_loc" }; + +static const char * const rtd1619b_scpu_ejtag_loc2_groups[] = { + "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "ejtag_scpu_loc" }; +static const char * const rtd1619b_acpu_ejtag_loc2_groups[] = { + "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "ejtag_acpu_loc" }; +static const char * const rtd1619b_vcpu_ejtag_loc2_groups[] = { + "gpio_71", "gpio_72", "gpio_73", "gpio_74", + "gpio_75", "gpio_76", "ejtag_vcpu_loc"}; +static const char * const rtd1619b_ve3_ejtag_disable_groups[] = { "ejtag_ve3_loc" }; +static const char * const rtd1619b_aucpu0_ejtag_disable_groups[] = { "ejtag_aucpu0_loc" }; +static const char * const rtd1619b_aucpu1_ejtag_disable_groups[] = { "ejtag_aucpu1_loc" }; + +static const char * const rtd1619b_acpu_ejtag_disable_groups[] = { "ejtag_acpu_loc" }; +static const char * const rtd1619b_vcpu_ejtag_disable_groups[] = { "ejtag_vcpu_loc" }; +static const char * const rtd1619b_scpu_ejtag_disable_groups[] = { "ejtag_scpu_loc" }; +static const char * const rtd1619b_sf_disable_groups[] = { "sf_en" }; +static const char * const rtd1619b_sf_enable_groups[] = { "sf_en" }; +static const char * const rtd1619b_iso_gspi_disable_groups[] = { "iso_gspi_loc" }; +static const char * const rtd1619b_arm_trace_debug_disable_groups[] = { "arm_trace_dbg_en" }; +static const char * const rtd1619b_arm_trace_debug_enable_groups[] = { "arm_trace_dbg_en" }; +static const char * const rtd1619b_pwm_normal_groups[] = { + "pwm_01_open_drain_en_loc0", "pwm_23_open_drain_en_loc0", "pwm_01_open_drain_en_loc1", "pwm_23_open_drain_en_loc1" }; +static const char * const rtd1619b_pwm_open_drain_groups[] = { + "pwm_01_open_drain_en_loc0", "pwm_23_open_drain_en_loc0", "pwm_01_open_drain_en_loc1", "pwm_23_open_drain_en_loc1" }; +static const char * const rtd1619b_standby_dbg_groups[] = { + "gpio_2", "gpio_3", "ir_rx" }; + +static const char * const rtd1619b_usb_cc1_groups[] = { "usb_cc1" }; +static const char * const rtd1619b_usb_cc2_groups[] = { "usb_cc2" }; +static const char * const rtd1619b_ir_rx_groups[] = { "ir_rx" }; +static const char * const rtd1619b_test_loop_dis_groups[] = { "gpio_50" }; + +#define RTD1619B_FUNC(_name) \ + { \ + .name = # _name, \ + .groups = rtd1619b_ ## _name ## _groups, \ + .num_groups = ARRAY_SIZE(rtd1619b_ ## _name ## _groups), \ + } + +static const struct rtd_pin_func_desc rtd1619b_pin_functions[] = { + RTD1619B_FUNC(gpio), + RTD1619B_FUNC(nf), + RTD1619B_FUNC(nf_spi), + RTD1619B_FUNC(spi), + RTD1619B_FUNC(pmic), + RTD1619B_FUNC(spdif), + RTD1619B_FUNC(spdif_coaxial), + RTD1619B_FUNC(spdif_optical_loc0), + RTD1619B_FUNC(spdif_optical_loc1), + RTD1619B_FUNC(emmc_spi), + RTD1619B_FUNC(emmc), + RTD1619B_FUNC(sc1), + RTD1619B_FUNC(uart0), + RTD1619B_FUNC(uart1), + RTD1619B_FUNC(uart2_loc0), + RTD1619B_FUNC(uart2_loc1), + RTD1619B_FUNC(gspi_loc1), + RTD1619B_FUNC(iso_gspi_loc1), + RTD1619B_FUNC(i2c0), + RTD1619B_FUNC(i2c1), + RTD1619B_FUNC(i2c3), + RTD1619B_FUNC(i2c4), + RTD1619B_FUNC(i2c5), + RTD1619B_FUNC(pwm0), + RTD1619B_FUNC(pwm1), + RTD1619B_FUNC(pwm2), + RTD1619B_FUNC(pwm3), + RTD1619B_FUNC(etn_led), + RTD1619B_FUNC(etn_phy), + RTD1619B_FUNC(etn_clk), + RTD1619B_FUNC(sc0), + RTD1619B_FUNC(vfd), + RTD1619B_FUNC(gspi_loc0), + RTD1619B_FUNC(iso_gspi_loc0), + RTD1619B_FUNC(pcie1), + RTD1619B_FUNC(pcie2), + RTD1619B_FUNC(sd), + RTD1619B_FUNC(sdio_loc0), + RTD1619B_FUNC(sdio_loc1), + RTD1619B_FUNC(hi), + RTD1619B_FUNC(hi_m), + RTD1619B_FUNC(dc_fan), + RTD1619B_FUNC(pll_test_loc0), + RTD1619B_FUNC(pll_test_loc1), + RTD1619B_FUNC(usb_cc1), + RTD1619B_FUNC(usb_cc2), + RTD1619B_FUNC(ir_rx), + RTD1619B_FUNC(tdm_ai_loc0), + RTD1619B_FUNC(tdm_ai_loc1), + RTD1619B_FUNC(dmic_loc0), + RTD1619B_FUNC(dmic_loc1), + RTD1619B_FUNC(ai_loc0), + RTD1619B_FUNC(ai_loc1), + RTD1619B_FUNC(tp0), + RTD1619B_FUNC(tp1), + RTD1619B_FUNC(ao), + RTD1619B_FUNC(uart2_disable), + RTD1619B_FUNC(gspi_disable), + RTD1619B_FUNC(sdio_disable), + RTD1619B_FUNC(hi_loc_disable), + RTD1619B_FUNC(hi_loc0), + RTD1619B_FUNC(hi_width_disable), + RTD1619B_FUNC(hi_width_1bit), + RTD1619B_FUNC(vtc_i2si_loc0), + RTD1619B_FUNC(vtc_tdm_loc0), + RTD1619B_FUNC(vtc_dmic_loc0), + RTD1619B_FUNC(vtc_i2si_loc1), + RTD1619B_FUNC(vtc_tdm_loc1), + RTD1619B_FUNC(vtc_dmic_loc1), + RTD1619B_FUNC(vtc_i2so), + RTD1619B_FUNC(ve3_ejtag_loc0), + RTD1619B_FUNC(aucpu0_ejtag_loc0), + RTD1619B_FUNC(aucpu1_ejtag_loc0), + RTD1619B_FUNC(ve3_ejtag_loc1), + RTD1619B_FUNC(aucpu0_ejtag_loc1), + RTD1619B_FUNC(aucpu1_ejtag_loc1), + RTD1619B_FUNC(ve3_ejtag_loc2), + RTD1619B_FUNC(aucpu0_ejtag_loc2), + RTD1619B_FUNC(aucpu1_ejtag_loc2), + RTD1619B_FUNC(scpu_ejtag_loc0), + RTD1619B_FUNC(acpu_ejtag_loc0), + RTD1619B_FUNC(vcpu_ejtag_loc0), + RTD1619B_FUNC(scpu_ejtag_loc1), + RTD1619B_FUNC(acpu_ejtag_loc1), + RTD1619B_FUNC(vcpu_ejtag_loc1), + RTD1619B_FUNC(scpu_ejtag_loc2), + RTD1619B_FUNC(acpu_ejtag_loc2), + RTD1619B_FUNC(vcpu_ejtag_loc2), + RTD1619B_FUNC(ve3_ejtag_disable), + RTD1619B_FUNC(aucpu0_ejtag_disable), + RTD1619B_FUNC(aucpu1_ejtag_disable), + RTD1619B_FUNC(acpu_ejtag_disable), + RTD1619B_FUNC(vcpu_ejtag_disable), + RTD1619B_FUNC(scpu_ejtag_disable), + RTD1619B_FUNC(iso_gspi_disable), + RTD1619B_FUNC(sf_disable), + RTD1619B_FUNC(sf_enable), + RTD1619B_FUNC(arm_trace_debug_disable), + RTD1619B_FUNC(arm_trace_debug_enable), + RTD1619B_FUNC(pwm_normal), + RTD1619B_FUNC(pwm_open_drain), + RTD1619B_FUNC(standby_dbg), + RTD1619B_FUNC(test_loop_dis), +}; + +#undef RTD1619B_FUNC + +static const struct rtd_pin_desc rtd1619b_iso_muxes[] = { + [RTD1619B_ISO_EMMC_RST_N] = RTK_PIN_MUX(emmc_rst_n, 0x0, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "emmc")), + [RTD1619B_ISO_EMMC_DD_SB] = RTK_PIN_MUX(emmc_dd_sb, 0x0, GENMASK(3, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 2), "emmc")), + [RTD1619B_ISO_EMMC_CLK] = RTK_PIN_MUX(emmc_clk, 0x0, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "emmc")), + [RTD1619B_ISO_EMMC_CMD] = RTK_PIN_MUX(emmc_cmd, 0x0, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "emmc")), + [RTD1619B_ISO_EMMC_DATA_0] = RTK_PIN_MUX(emmc_data_0, 0x0, GENMASK(9, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 8), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 8), "nf_spi")), + [RTD1619B_ISO_EMMC_DATA_1] = RTK_PIN_MUX(emmc_data_1, 0x0, GENMASK(11, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 10), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 10), "nf_spi")), + [RTD1619B_ISO_EMMC_DATA_2] = RTK_PIN_MUX(emmc_data_2, 0x0, GENMASK(13, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 12), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 12), "nf_spi")), + [RTD1619B_ISO_EMMC_DATA_3] = RTK_PIN_MUX(emmc_data_3, 0x0, GENMASK(15, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 14), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 14), "nf_spi")), + [RTD1619B_ISO_EMMC_DATA_4] = RTK_PIN_MUX(emmc_data_4, 0x0, GENMASK(17, 16), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 16), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 16), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 16), "nf_spi")), + [RTD1619B_ISO_EMMC_DATA_5] = RTK_PIN_MUX(emmc_data_5, 0x0, GENMASK(19, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "emmc"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 18), "nf_spi")), + [RTD1619B_ISO_EMMC_DATA_6] = RTK_PIN_MUX(emmc_data_6, 0x0, GENMASK(21, 20), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 20), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 20), "emmc")), + [RTD1619B_ISO_EMMC_DATA_7] = RTK_PIN_MUX(emmc_data_7, 0x0, GENMASK(23, 22), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 22), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 22), "emmc")), + [RTD1619B_ISO_SPI_CE_N] = RTK_PIN_MUX(spi_ce_n, 0x0, GENMASK(25, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 24), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 24), "spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 24), "pmic")), + [RTD1619B_ISO_SPI_SCK] = RTK_PIN_MUX(spi_sck, 0x0, GENMASK(27, 26), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 26), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 26), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 26), "spi")), + [RTD1619B_ISO_SPI_SO] = RTK_PIN_MUX(spi_so, 0x0, GENMASK(29, 28), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 28), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 28), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 28), "spi")), + [RTD1619B_ISO_SPI_SI] = RTK_PIN_MUX(spi_si, 0x0, GENMASK(31, 30), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 30), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 30), "nf"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 30), "spi")), + + [RTD1619B_ISO_GPIO_0] = RTK_PIN_MUX(gpio_0, 0x4, GENMASK(0, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio")), + [RTD1619B_ISO_GPIO_1] = RTK_PIN_MUX(gpio_1, 0x4, GENMASK(3, 1), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 1), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 1), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 1), "spdif_coaxial")), + [RTD1619B_ISO_GPIO_2] = RTK_PIN_MUX(gpio_2, 0x4, GENMASK(7, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "standby_dbg"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 4), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 4), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 4), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 4), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 4), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 4), "ve3_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 4), "aucpu0_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 4), "aucpu1_ejtag_loc0")), + [RTD1619B_ISO_GPIO_3] = RTK_PIN_MUX(gpio_3, 0x4, GENMASK(11, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "standby_dbg"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 8), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 8), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 8), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 8), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 8), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 8), "ve3_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 8), "aucpu0_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 8), "aucpu1_ejtag_loc0")), + [RTD1619B_ISO_GPIO_4] = RTK_PIN_MUX(gpio_4, 0x4, GENMASK(15, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 12), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 12), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 12), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 12), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 12), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 12), "ve3_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 12), "aucpu0_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 12), "aucpu1_ejtag_loc0")), + [RTD1619B_ISO_GPIO_5] = RTK_PIN_MUX(gpio_5, 0x4, GENMASK(19, 16), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 16), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 16), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 16), "sc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 16), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 16), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 16), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 16), "ve3_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 16), "aucpu0_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 16), "aucpu1_ejtag_loc0")), + [RTD1619B_ISO_GPIO_6] = RTK_PIN_MUX(gpio_6, 0x4, GENMASK(23, 20), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 20), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 20), "emmc_spi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 20), "spdif_optical_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 20), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 20), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 20), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 20), "ve3_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 20), "aucpu0_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 20), "aucpu1_ejtag_loc0")), + [RTD1619B_ISO_GPIO_7] = RTK_PIN_MUX(gpio_7, 0x4, GENMASK(24, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "gpio")), + [RTD1619B_ISO_GPIO_8] = RTK_PIN_MUX(gpio_8, 0x4, GENMASK(27, 25), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 25), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 25), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 25), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 25), "iso_gspi_loc1")), + [RTD1619B_ISO_GPIO_9] = RTK_PIN_MUX(gpio_9, 0x4, GENMASK(30, 28), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 28), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 28), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 28), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 28), "iso_gspi_loc1")), + [RTD1619B_ISO_GPIO_10] = RTK_PIN_MUX(gpio_10, 0x8, GENMASK(2, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 0), "iso_gspi_loc1")), + [RTD1619B_ISO_GPIO_11] = RTK_PIN_MUX(gpio_11, 0x8, GENMASK(5, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 3), "uart1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 3), "gspi_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 3), "iso_gspi_loc1")), + + [RTD1619B_ISO_GPIO_12] = RTK_PIN_MUX(gpio_12, 0x8, GENMASK(6, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "i2c0")), + [RTD1619B_ISO_GPIO_13] = RTK_PIN_MUX(gpio_13, 0x8, GENMASK(7, 7), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 7), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 7), "i2c0")), + [RTD1619B_ISO_GPIO_14] = RTK_PIN_MUX(gpio_14, 0x8, GENMASK(10, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "etn_led"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 8), "etn_phy"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 8), "etn_clk")), + [RTD1619B_ISO_GPIO_15] = RTK_PIN_MUX(gpio_15, 0x8, GENMASK(12, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 11), "etn_led"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 11), "etn_phy")), + [RTD1619B_ISO_GPIO_16] = RTK_PIN_MUX(gpio_16, 0x8, GENMASK(13, 13), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 13), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 13), "i2c1")), + [RTD1619B_ISO_GPIO_17] = RTK_PIN_MUX(gpio_17, 0x8, GENMASK(14, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 14), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "i2c1")), + [RTD1619B_ISO_GPIO_18] = RTK_PIN_MUX(gpio_18, 0x8, GENMASK(17, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 15), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 15), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 15), "iso_gspi_loc0")), + [RTD1619B_ISO_GPIO_19] = RTK_PIN_MUX(gpio_19, 0x8, GENMASK(20, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 18), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 18), "iso_gspi_loc0")), + [RTD1619B_ISO_GPIO_20] = RTK_PIN_MUX(gpio_20, 0x8, GENMASK(23, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "pwm0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 21), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 21), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 21), "iso_gspi_loc0")), + [RTD1619B_ISO_GPIO_21] = RTK_PIN_MUX(gpio_21, 0x8, GENMASK(26, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 24), "pwm1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 24), "spdif_optical_loc1")), + [RTD1619B_ISO_GPIO_22] = RTK_PIN_MUX(gpio_22, 0x8, GENMASK(28, 27), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 27), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 27), "pwm2")), + [RTD1619B_ISO_GPIO_23] = RTK_PIN_MUX(gpio_23, 0x8, GENMASK(30, 29), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 29), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 29), "etn_led"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 29), "pwm3")), + [RTD1619B_ISO_USB_CC2] = RTK_PIN_MUX(usb_cc2, 0x8, GENMASK(31, 31), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 31), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 31), "usb_cc2")), + [RTD1619B_ISO_GPIO_25] = RTK_PIN_MUX(gpio_25, 0xc, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "uart2_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "pcie1")), + [RTD1619B_ISO_GPIO_26] = RTK_PIN_MUX(gpio_26, 0xc, GENMASK(3, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 2), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 2), "uart2_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 2), "vfd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 2), "pwm0")), + [RTD1619B_ISO_GPIO_27] = RTK_PIN_MUX(gpio_27, 0xc, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "uart2_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "vfd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 4), "pwm1")), + + + [RTD1619B_ISO_GPIO_28] = RTK_PIN_MUX(gpio_28, 0xc, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "uart2_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "vfd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 6), "pwm2")), + [RTD1619B_ISO_GPIO_29] = RTK_PIN_MUX(gpio_29, 0xc, GENMASK(8, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "i2c5")), + [RTD1619B_ISO_GPIO_30] = RTK_PIN_MUX(gpio_30, 0xc, GENMASK(9, 9), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 9), "gpio")), + [RTD1619B_ISO_GPIO_31] = RTK_PIN_MUX(gpio_31, 0xc, GENMASK(12, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 10), "sc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 10), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 10), "iso_gspi_loc0")), + [RTD1619B_ISO_GPIO_32] = RTK_PIN_MUX(gpio_32, 0xc, GENMASK(17, 13), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 13), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 13), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 13), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 13), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 13), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 13), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 13), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 13), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 13), "vtc_i2si_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x14, 13), "ve3_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x15, 13), "aucpu0_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x16, 13), "aucpu1_ejtag_loc1")), + [RTD1619B_ISO_GPIO_33] = RTK_PIN_MUX(gpio_33, 0xc, GENMASK(22, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 18), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 18), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 18), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 18), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 18), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x14, 18), "ve3_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x15, 18), "aucpu0_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x16, 18), "aucpu1_ejtag_loc1")), + [RTD1619B_ISO_GPIO_34] = RTK_PIN_MUX(gpio_34, 0xc, GENMASK(25, 23), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 23), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 23), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 23), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 23), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 23), "i2c4")), + [RTD1619B_ISO_GPIO_35] = RTK_PIN_MUX(gpio_35, 0xc, GENMASK(28, 26), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 26), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 26), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 26), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 26), "i2c4")), + [RTD1619B_ISO_HIF_DATA] = RTK_PIN_MUX(hif_data, 0x10, GENMASK(4, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 0), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 0), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 0), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 0), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 0), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 0), "hi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 0), "hi_m"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 0), "vtc_i2si_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 0), "vtc_tdm_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 0), "vtc_dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x14, 0), "ve3_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x15, 0), "aucpu0_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x16, 0), "aucpu1_ejtag_loc1")), + [RTD1619B_ISO_HIF_EN] = RTK_PIN_MUX(hif_en, 0x10, GENMASK(9, 5), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 5), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 5), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 5), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 5), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 5), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 5), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 5), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 5), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 5), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 5), "hi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 5), "hi_m"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 5), "vtc_i2si_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 5), "vtc_tdm_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 5), "vtc_dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x14, 5), "ve3_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x15, 5), "aucpu0_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x16, 5), "aucpu1_ejtag_loc1")), + [RTD1619B_ISO_HIF_RDY] = RTK_PIN_MUX(hif_rdy, 0x10, GENMASK(13, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 10), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 10), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 10), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 10), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 10), "hi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 10), "hi_m"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 10), "vtc_i2si_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 10), "vtc_tdm_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 10), "vtc_dmic_loc0")), + + + [RTD1619B_ISO_HIF_CLK] = RTK_PIN_MUX(hif_clk, 0x10, GENMASK(18, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 14), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "sd"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 14), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 14), "dmic_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 14), "tdm_ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 14), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 14), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 14), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 14), "ai_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 14), "hi"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 14), "hi_m"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 14), "vtc_i2si_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 14), "vtc_tdm_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 14), "vtc_dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x14, 14), "ve3_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x15, 14), "aucpu0_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x16, 14), "aucpu1_ejtag_loc1")), + [RTD1619B_ISO_GPIO_40] = RTK_PIN_MUX(gpio_40, 0x10, GENMASK(20, 19), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 19), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 19), "sdio_loc1")), + [RTD1619B_ISO_GPIO_41] = RTK_PIN_MUX(gpio_41, 0x10, GENMASK(22, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "sdio_loc1")), + [RTD1619B_ISO_GPIO_42] = RTK_PIN_MUX(gpio_42, 0x10, GENMASK(24, 23), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 23), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 23), "sdio_loc1")), + [RTD1619B_ISO_GPIO_43] = RTK_PIN_MUX(gpio_43, 0x10, GENMASK(26, 25), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 25), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 25), "sdio_loc1")), + [RTD1619B_ISO_GPIO_44] = RTK_PIN_MUX(gpio_44, 0x10, GENMASK(28, 27), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 27), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 27), "sdio_loc1")), + [RTD1619B_ISO_GPIO_45] = RTK_PIN_MUX(gpio_45, 0x10, GENMASK(30, 29), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 29), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 29), "sdio_loc1")), + [RTD1619B_ISO_GPIO_46] = RTK_PIN_MUX(gpio_46, 0x10, GENMASK(31, 31), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 31), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 31), "i2c5")), + [RTD1619B_ISO_GPIO_47] = RTK_PIN_MUX(gpio_47, 0x14, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "dc_fan"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "pwm3")), + [RTD1619B_ISO_GPIO_48] = RTK_PIN_MUX(gpio_48, 0x14, GENMASK(2, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 2), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 2), "pll_test_loc1")), + [RTD1619B_ISO_GPIO_49] = RTK_PIN_MUX(gpio_49, 0x14, GENMASK(3, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 3), "pll_test_loc1")), + [RTD1619B_ISO_GPIO_50] = RTK_PIN_MUX(gpio_50, 0x14, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "spdif"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "test_loop_dis")), + [RTD1619B_ISO_USB_CC1] = RTK_PIN_MUX(usb_cc1, 0x14, GENMASK(6, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "usb_cc1")), + [RTD1619B_ISO_GPIO_52] = RTK_PIN_MUX(gpio_52, 0x14, GENMASK(8, 7), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 7), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 7), "pll_test_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 7), "pcie2")), + [RTD1619B_ISO_GPIO_53] = RTK_PIN_MUX(gpio_53, 0x14, GENMASK(9, 9), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 9), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 9), "pll_test_loc0")), + [RTD1619B_ISO_IR_RX] = RTK_PIN_MUX(ir_rx, 0x14, GENMASK(11, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 10), "ir_rx"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 10), "standby_dbg")), + [RTD1619B_ISO_UR0_RX] = RTK_PIN_MUX(ur0_rx, 0x14, GENMASK(12, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "uart0")), + + + [RTD1619B_ISO_UR0_TX] = RTK_PIN_MUX(ur0_tx, 0x14, GENMASK(13, 13), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 13), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 13), "uart0")), + [RTD1619B_ISO_GPIO_57] = RTK_PIN_MUX(gpio_57, 0x14, GENMASK(17, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 14), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 14), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 14), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 14), "vtc_i2si_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 14), "vtc_tdm_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 14), "vtc_dmic_loc1")), + [RTD1619B_ISO_GPIO_58] = RTK_PIN_MUX(gpio_58, 0x14, GENMASK(21, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 18), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 18), "vtc_i2si_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 18), "vtc_tdm_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 18), "vtc_dmic_loc1")), + [RTD1619B_ISO_GPIO_59] = RTK_PIN_MUX(gpio_59, 0x14, GENMASK(25, 22), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 22), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 22), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 22), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 22), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 22), "vtc_i2si_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 22), "vtc_tdm_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 22), "vtc_dmic_loc1")), + [RTD1619B_ISO_GPIO_60] = RTK_PIN_MUX(gpio_60, 0x14, GENMASK(29, 26), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 26), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 26), "tdm_ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 26), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 26), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 26), "vtc_i2si_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x12, 26), "vtc_tdm_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x13, 26), "vtc_dmic_loc1")), + [RTD1619B_ISO_GPIO_61] = RTK_PIN_MUX(gpio_61, 0x18, GENMASK(3, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 0), "vtc_i2si_loc1")), + [RTD1619B_ISO_GPIO_62] = RTK_PIN_MUX(gpio_62, 0x18, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 4), "dmic_loc0")), + [RTD1619B_ISO_GPIO_63] = RTK_PIN_MUX(gpio_63, 0x18, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "ai_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 6), "i2c3"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 6), "dmic_loc0")), + [RTD1619B_ISO_GPIO_64] = RTK_PIN_MUX(gpio_64, 0x18, GENMASK(9, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 8), "i2c3"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 8), "dmic_loc0")), + [RTD1619B_ISO_GPIO_65] = RTK_PIN_MUX(gpio_65, 0x18, GENMASK(10, 10), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 10), "gpio")), + [RTD1619B_ISO_GPIO_66] = RTK_PIN_MUX(gpio_66, 0x18, GENMASK(14, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 11), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 11), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 11), "vtc_i2so")), + [RTD1619B_ISO_GPIO_67] = RTK_PIN_MUX(gpio_67, 0x18, GENMASK(18, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 15), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 15), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 15), "vtc_i2so")), + [RTD1619B_ISO_GPIO_68] = RTK_PIN_MUX(gpio_68, 0x18, GENMASK(22, 19), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 19), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 19), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 19), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 19), "vtc_i2so")), + [RTD1619B_ISO_GPIO_69] = RTK_PIN_MUX(gpio_69, 0x18, GENMASK(26, 23), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 23), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 23), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 23), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 23), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x11, 23), "vtc_i2so")), + + [RTD1619B_ISO_GPIO_70] = RTK_PIN_MUX(gpio_70, 0x18, GENMASK(29, 27), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 27), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 27), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 27), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 27), "ao")), + [RTD1619B_ISO_GPIO_71] = RTK_PIN_MUX(gpio_71, 0x1c, GENMASK(2, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 0), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 0), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 0), "scpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 0), "acpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 0), "vcpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 0), "ve3_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 0), "aucpu0_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 0), "aucpu1_ejtag_loc2")), + [RTD1619B_ISO_GPIO_72] = RTK_PIN_MUX(gpio_72, 0x1c, GENMASK(6, 3), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 3), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 3), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x3, 3), "tp1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 3), "ao"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 3), "scpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 3), "acpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 3), "vcpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 3), "ve3_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 3), "aucpu0_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 3), "aucpu1_ejtag_loc2")), + [RTD1619B_ISO_GPIO_73] = RTK_PIN_MUX(gpio_73, 0x1c, GENMASK(10, 7), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 7), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 7), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 7), "scpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 7), "acpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 7), "vcpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 7), "ve3_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 7), "aucpu0_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 7), "aucpu1_ejtag_loc2")), + [RTD1619B_ISO_GPIO_74] = RTK_PIN_MUX(gpio_74, 0x1c, GENMASK(14, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 11), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 11), "scpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 11), "acpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 11), "vcpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 11), "ve3_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 11), "aucpu0_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 11), "aucpu1_ejtag_loc2")), + [RTD1619B_ISO_GPIO_75] = RTK_PIN_MUX(gpio_75, 0x1c, GENMASK(18, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 15), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 15), "scpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 15), "acpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 15), "vcpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 15), "ve3_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 15), "aucpu0_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 15), "aucpu1_ejtag_loc2")), + [RTD1619B_ISO_GPIO_76] = RTK_PIN_MUX(gpio_76, 0x1c, GENMASK(22, 19), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 19), "gpio"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 19), "tp0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x5, 19), "scpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x6, 19), "acpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x7, 19), "vcpu_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x8, 19), "ve3_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x9, 19), "aucpu0_ejtag_loc2"), + RTK_PIN_FUNC(SHIFT_LEFT(0x10, 19), "aucpu1_ejtag_loc2")), + + + [RTD1619B_ISO_UR2_LOC] = RTK_PIN_MUX(ur2_loc, 0x120, GENMASK(1, 0), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 0), "uart2_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 0), "uart2_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 0), "uart2_loc1")), + [RTD1619B_ISO_GSPI_LOC] = RTK_PIN_MUX(gspi_loc, 0x120, GENMASK(3, 2), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 2), "gspi_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 2), "gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 2), "gspi_loc1")), + [RTD1619B_ISO_SDIO_LOC] = RTK_PIN_MUX(sdio_loc, 0x120, GENMASK(5, 4), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 4), "sdio_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 4), "sdio_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 4), "sdio_loc1")), + [RTD1619B_ISO_HI_LOC] = RTK_PIN_MUX(hi_loc, 0x120, GENMASK(7, 6), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 6), "hi_loc_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 6), "hi_loc0")), + [RTD1619B_ISO_HI_WIDTH] = RTK_PIN_MUX(hi_width, 0x120, GENMASK(9, 8), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 8), "hi_width_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 8), "hi_width_1bit")), + [RTD1619B_ISO_SF_EN] = RTK_PIN_MUX(sf_en, 0x120, GENMASK(11, 11), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 11), "sf_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 11), "sf_enable")), + [RTD1619B_ISO_ARM_TRACE_DBG_EN] = RTK_PIN_MUX(arm_trace_dbg_en, 0x120, GENMASK(12, 12), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 12), "arm_trace_debug_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 12), "arm_trace_debug_enable")), + [RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC0] = RTK_PIN_MUX(pwm_01_open_drain_en_loc0, 0x120, GENMASK(13, 13), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 13), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 13), "pwm_open_drain")), + [RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC0] = RTK_PIN_MUX(pwm_23_open_drain_en_loc0, 0x120, GENMASK(14, 14), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 14), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 14), "pwm_open_drain")), + [RTD1619B_ISO_PWM_01_OPEN_DRAIN_EN_LOC1] = RTK_PIN_MUX(pwm_01_open_drain_en_loc1, 0x120, GENMASK(15, 15), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 15), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 15), "pwm_open_drain")), + [RTD1619B_ISO_PWM_23_OPEN_DRAIN_EN_LOC1] = RTK_PIN_MUX(pwm_23_open_drain_en_loc1, 0x120, GENMASK(16, 16), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 16), "pwm_normal"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 16), "pwm_open_drain")), + [RTD1619B_ISO_EJTAG_ACPU_LOC] = RTK_PIN_MUX(ejtag_acpu_loc, 0x120, GENMASK(19, 17), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 17), "acpu_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 17), "acpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 17), "acpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 17), "acpu_ejtag_loc2")), + [RTD1619B_ISO_EJTAG_VCPU_LOC] = RTK_PIN_MUX(ejtag_vcpu_loc, 0x120, GENMASK(22, 20), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 20), "vcpu_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 20), "vcpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 20), "vcpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 20), "vcpu_ejtag_loc2")), + [RTD1619B_ISO_EJTAG_SCPU_LOC] = RTK_PIN_MUX(ejtag_scpu_loc, 0x120, GENMASK(25, 23), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 23), "scpu_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 23), "scpu_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 23), "scpu_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 23), "scpu_ejtag_loc2")), + [RTD1619B_ISO_DMIC_LOC] = RTK_PIN_MUX(dmic_loc, 0x120, GENMASK(27, 26), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 26), "dmic_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 26), "dmic_loc1")), + [RTD1619B_ISO_ISO_GSPI_LOC] = RTK_PIN_MUX(iso_gspi_loc, 0x120, GENMASK(29, 28), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 28), "iso_gspi_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 28), "iso_gspi_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 28), "iso_gspi_loc1")), + [RTD1619B_ISO_EJTAG_VE3_LOC] = RTK_PIN_MUX(ejtag_ve3_loc, 0x124, GENMASK(20, 18), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 18), "ve3_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 18), "ve3_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 18), "ve3_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 18), "ve3_ejtag_loc2")), + [RTD1619B_ISO_EJTAG_AUCPU1_LOC] = RTK_PIN_MUX(ejtag_aucpu1_loc, 0x124, GENMASK(23, 21), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 21), "aucpu1_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 21), "aucpu1_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 21), "aucpu1_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 21), "aucpu1_ejtag_loc2")), + [RTD1619B_ISO_EJTAG_AUCPU0_LOC] = RTK_PIN_MUX(ejtag_aucpu0_loc, 0x124, GENMASK(26, 24), + RTK_PIN_FUNC(SHIFT_LEFT(0x0, 24), "aucpu0_ejtag_disable"), + RTK_PIN_FUNC(SHIFT_LEFT(0x1, 24), "aucpu0_ejtag_loc0"), + RTK_PIN_FUNC(SHIFT_LEFT(0x2, 24), "aucpu0_ejtag_loc1"), + RTK_PIN_FUNC(SHIFT_LEFT(0x4, 24), "aucpu0_ejtag_loc2")), +}; + +static const struct rtd_pin_config_desc rtd1619b_iso_configs[] = { + [RTD1619B_ISO_GPIO_17] = RTK_PIN_CONFIG(gpio_17, 0x20, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_19] = RTK_PIN_CONFIG(gpio_19, 0x20, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_50] = RTK_PIN_CONFIG(gpio_50, 0x20, 10, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_21] = RTK_PIN_CONFIG(gpio_21, 0x20, 15, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_66] = RTK_PIN_CONFIG(gpio_66, 0x20, 20, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_67] = RTK_PIN_CONFIG(gpio_67, 0x20, 25, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_68] = RTK_PIN_CONFIG(gpio_68, 0x24, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_69] = RTK_PIN_CONFIG(gpio_69, 0x24, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_70] = RTK_PIN_CONFIG(gpio_70, 0x24, 10, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_71] = RTK_PIN_CONFIG(gpio_71, 0x24, 15, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_72] = RTK_PIN_CONFIG(gpio_72, 0x24, 20, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_73] = RTK_PIN_CONFIG(gpio_73, 0x24, 25, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_74] = RTK_PIN_CONFIG(gpio_74, 0x28, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_75] = RTK_PIN_CONFIG(gpio_75, 0x28, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_76] = RTK_PIN_CONFIG(gpio_76, 0x28, 10, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_SPI_SI] = RTK_PIN_CONFIG(spi_si, 0x28, 15, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_SPI_SCK] = RTK_PIN_CONFIG(spi_sck, 0x2c, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_SPI_CE_N] = RTK_PIN_CONFIG(spi_ce_n, 0x2c, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_SPI_SO] = RTK_PIN_CONFIG(spi_so, 0x2c, 26, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_CLK] = RTK_PIN_CONFIG(emmc_clk, 0x30, 7, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_CMD] = RTK_PIN_CONFIG(emmc_cmd, 0x34, 0, 0, 1, 3, 2, 13, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_RST_N] = RTK_PIN_CONFIG(emmc_rst_n, 0x34, 14, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DD_SB] = RTK_PIN_CONFIG(emmc_dd_sb, 0x34, 27, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_5] = RTK_PIN_CONFIG(emmc_data_5, 0x38, 8, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_3] = RTK_PIN_CONFIG(emmc_data_3, 0x3c, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_4] = RTK_PIN_CONFIG(emmc_data_4, 0x3c, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_0] = RTK_PIN_CONFIG(emmc_data_0, 0x3c, 26, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_1] = RTK_PIN_CONFIG(emmc_data_1, 0x40, 7, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_2] = RTK_PIN_CONFIG(emmc_data_2, 0x44, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_7] = RTK_PIN_CONFIG(emmc_data_7, 0x44, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_EMMC_DATA_6] = RTK_PIN_CONFIG(emmc_data_6, 0x44, 26, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_USB_CC1] = RTK_PIN_CONFIG(usb_cc1, 0x48, 7, PCONF_UNSUPP, PCONF_UNSUPP, 0, 1, 9, PADDRI_4_8), + [RTD1619B_ISO_USB_CC2] = RTK_PIN_CONFIG(usb_cc2, 0x48, 10, PCONF_UNSUPP, PCONF_UNSUPP, 0, 1, 9, PADDRI_4_8), + [RTD1619B_ISO_GPIO_26] = RTK_PIN_CONFIG(gpio_26, 0x48, 13, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_27] = RTK_PIN_CONFIG(gpio_27, 0x48, 18, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_28] = RTK_PIN_CONFIG(gpio_28, 0x48, 23, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_29] = RTK_PIN_CONFIG(gpio_29, 0x4c, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_46] = RTK_PIN_CONFIG(gpio_46, 0x4c, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_48] = RTK_PIN_CONFIG(gpio_48, 0x4c, 10, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_49] = RTK_PIN_CONFIG(gpio_49, 0x4c, 15, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_53] = RTK_PIN_CONFIG(gpio_53, 0x4c, 20, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_65] = RTK_PIN_CONFIG(gpio_65, 0x4c, 25, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_14] = RTK_PIN_CONFIG(gpio_14, 0x50, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_15] = RTK_PIN_CONFIG(gpio_15, 0x50, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_23] = RTK_PIN_CONFIG(gpio_23, 0x50, 10, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_IR_RX] = RTK_PIN_CONFIG(ir_rx, 0x50, 20, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_57] = RTK_PIN_CONFIG(gpio_57, 0x50, 25, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_58] = RTK_PIN_CONFIG(gpio_58, 0x50, 30, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_59] = RTK_PIN_CONFIG(gpio_59, 0x54, 3, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_60] = RTK_PIN_CONFIG(gpio_60, 0x54, 8, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_61] = RTK_PIN_CONFIG(gpio_61, 0x54, 13, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_62] = RTK_PIN_CONFIG(gpio_62, 0x54, 18, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_63] = RTK_PIN_CONFIG(gpio_63, 0x54, 23, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_64] = RTK_PIN_CONFIG(gpio_64, 0x58, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_UR0_TX] = RTK_PIN_CONFIG(ur0_tx, 0x58, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_UR0_RX] = RTK_PIN_CONFIG(ur0_rx, 0x58, 13, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_12] = RTK_PIN_CONFIG(gpio_12, 0x58, 18, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_13] = RTK_PIN_CONFIG(gpio_13, 0x58, 23, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_30] = RTK_PIN_CONFIG(gpio_30, 0x58, 28, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_7] = RTK_PIN_CONFIG(gpio_7, 0x5c, 1, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_16] = RTK_PIN_CONFIG(gpio_16, 0x5c, 6, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_18] = RTK_PIN_CONFIG(gpio_18, 0x5c, 11, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_20] = RTK_PIN_CONFIG(gpio_20, 0x5c, 16, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_22] = RTK_PIN_CONFIG(gpio_22, 0x5c, 21, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_31] = RTK_PIN_CONFIG(gpio_31, 0x5c, 26, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_47] = RTK_PIN_CONFIG(gpio_47, 0x60, 12, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_25] = RTK_PIN_CONFIG(gpio_25, 0x60, 17, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_6] = RTK_PIN_CONFIG(gpio_6, 0x60, 22, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_5] = RTK_PIN_CONFIG(gpio_5, 0x60, 27, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_4] = RTK_PIN_CONFIG(gpio_4, 0x64, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_3] = RTK_PIN_CONFIG(gpio_3, 0x64, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_2] = RTK_PIN_CONFIG(gpio_2, 0x64, 10, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_1] = RTK_PIN_CONFIG(gpio_1, 0x64, 15, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_0] = RTK_PIN_CONFIG(gpio_0, 0x64, 20, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_52] = RTK_PIN_CONFIG(gpio_52, 0x64, 25, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_35] = RTK_PIN_CONFIG(gpio_35, 0x68, 0, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_34] = RTK_PIN_CONFIG(gpio_34, 0x68, 5, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_40] = RTK_PIN_CONFIG(gpio_40, 0x68, 10, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_41] = RTK_PIN_CONFIG(gpio_41, 0x6c, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_42] = RTK_PIN_CONFIG(gpio_42, 0x6c, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_43] = RTK_PIN_CONFIG(gpio_43, 0x70, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_44] = RTK_PIN_CONFIG(gpio_44, 0x70, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_45] = RTK_PIN_CONFIG(gpio_45, 0x70, 26, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_8] = RTK_PIN_CONFIG(gpio_8, 0x74, 7, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_9] = RTK_PIN_CONFIG(gpio_9, 0x74, 12, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_10] = RTK_PIN_CONFIG(gpio_10, 0x74, 17, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_GPIO_11] = RTK_PIN_CONFIG(gpio_11, 0x74, 22, 1, 2, 0, 3, 4, PADDRI_4_8), + [RTD1619B_ISO_HIF_RDY] = RTK_PIN_CONFIG(hif_rdy, 0x78, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_HIF_CLK] = RTK_PIN_CONFIG(hif_clk, 0x78, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_32] = RTK_PIN_CONFIG(gpio_32, 0x78, 26, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_GPIO_33] = RTK_PIN_CONFIG(gpio_33, 0x7c, 7, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_HIF_DATA] = RTK_PIN_CONFIG(hif_data, 0x80, 0, 0, 1, 3, 2, 12, PCONF_UNSUPP), + [RTD1619B_ISO_HIF_EN] = RTK_PIN_CONFIG(hif_en, 0x80, 13, 0, 1, 3, 2, 12, PCONF_UNSUPP), +}; + +static const struct rtd_pin_sconfig_desc rtd1619b_iso_sconfigs[] = { + RTK_PIN_SCONFIG(spi_si, 0x28, 18, 3, 21, 3, 24, 3), + RTK_PIN_SCONFIG(spi_sck, 0x2c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(spi_ce_n, 0x2c, 16, 3, 19, 3, 22, 3), + RTK_PIN_SCONFIG(spi_so, 0x2c, 29, 3, 32, 3, 35, 3), + RTK_PIN_SCONFIG(emmc_clk, 0x30, 10, 3, 13, 3, 16, 3), + RTK_PIN_SCONFIG(emmc_cmd, 0x34, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_rst_n, 0x34, 17, 3, 20, 3, 23, 3), + RTK_PIN_SCONFIG(emmc_dd_sb, 0x34, 30, 3, 33, 3, 36, 3), + RTK_PIN_SCONFIG(emmc_data_5, 0x38, 11, 3, 14, 3, 17, 3), + RTK_PIN_SCONFIG(emmc_data_3, 0x3c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_data_4, 0x3c, 16, 3, 19, 3, 22, 3), + RTK_PIN_SCONFIG(emmc_data_0, 0x3c, 29, 3, 32, 3, 35, 3), + RTK_PIN_SCONFIG(emmc_data_1, 0x40, 10, 3, 13, 3, 16, 3), + RTK_PIN_SCONFIG(emmc_data_2, 0x44, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(emmc_data_7, 0x44, 16, 3, 19, 3, 22, 3), + RTK_PIN_SCONFIG(emmc_data_6, 0x44, 29, 3, 32, 3, 35, 3), + RTK_PIN_SCONFIG(gpio_40, 0x68, 13, 3, 16, 3, 19, 3), + RTK_PIN_SCONFIG(gpio_41, 0x6c, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(gpio_42, 0x6c, 16, 3, 19, 3, 22, 3), + RTK_PIN_SCONFIG(gpio_43, 0x70, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(gpio_44, 0x70, 16, 3, 19, 3, 22, 3), + RTK_PIN_SCONFIG(gpio_45, 0x70, 29, 3, 32, 3, 35, 3), + RTK_PIN_SCONFIG(hif_rdy, 0x78, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(hif_clk, 0x78, 16, 3, 19, 3, 22, 3), + RTK_PIN_SCONFIG(gpio_32, 0x78, 29, 3, 32, 3, 35, 3), + RTK_PIN_SCONFIG(gpio_33, 0x7c, 10, 3, 13, 3, 16, 3), + RTK_PIN_SCONFIG(hif_data, 0x80, 3, 3, 6, 3, 9, 3), + RTK_PIN_SCONFIG(hif_en, 0x80, 16, 3, 19, 3, 22, 3), +}; + + + +static const struct rtd_pinctrl_desc rtd1619b_iso_pinctrl_desc = { + .pins = rtd1619b_iso_pins, + .num_pins = ARRAY_SIZE(rtd1619b_iso_pins), + .groups = rtd1619b_pin_groups, + .num_groups = ARRAY_SIZE(rtd1619b_pin_groups), + .functions = rtd1619b_pin_functions, + .num_functions = ARRAY_SIZE(rtd1619b_pin_functions), + .muxes = rtd1619b_iso_muxes, + .num_muxes = ARRAY_SIZE(rtd1619b_iso_muxes), + .configs = rtd1619b_iso_configs, + .num_configs = ARRAY_SIZE(rtd1619b_iso_configs), + .sconfigs = rtd1619b_iso_sconfigs, + .num_sconfigs = ARRAY_SIZE(rtd1619b_iso_sconfigs), +}; +#endif diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index d55b3727e00e..c3d8807ec3ae 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -237,6 +237,15 @@ config POWER_RESET_SYSCON_POWEROFF help Poweroff support for generic SYSCON mapped register poweroff. +if SYNO_LSP_RTD1619B +config POWER_RESET_REGMAP_POWEROFF + bool "Simple Regmap poweroff driver" + depends on OF + depends on REGMAP + help + Poweroff support for Regmap mapped register poweroff + +endif # SYNO_LSP_RTD1619B config POWER_RESET_RMOBILE tristate "Renesas R-Mobile reset driver" depends on ARCH_RMOBILE || COMPILE_TEST @@ -284,5 +293,20 @@ config NVMEM_REBOOT_MODE then the bootloader can read it and take different action according to the mode. +if SYNO_LSP_RTD1619B +config POWER_RESET_RTK + bool "Realtek reset driver" + depends on ARCH_REALTEK + default y + help + Reboot support for Realtek SoCs. + +config RTK_REBOOT_MODE + bool "Realtek reboot mode driver" + depends on ARCH_REALTEK + help + Realtek reboot mode driver. + +endif # SYNO_LSP_RTD1619B endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index c51eceba9ea3..028c7bd56bbf 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -27,9 +27,19 @@ obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_POWER_RESET_REGMAP_POWEROFF) += regmap-poweroff.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_POWER_RESET_RTK) += rtk-reboot.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTK_REBOOT_MODE) += rtk-reboot-mode.o + +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/power/reset/regmap-poweroff.c b/drivers/power/reset/regmap-poweroff.c new file mode 100644 index 000000000000..4eba678d2969 --- /dev/null +++ b/drivers/power/reset/regmap-poweroff.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Regmap Poweroff Driver + * Copyright (C) 2020 Realtek Semiconductor Corporation + */ + +#include +#include +#include +#include +#include + +static struct regmap *map; +static u32 offset; +static u32 mask; +static u32 val; + +static void regmap_poweroff(void) +{ + regmap_update_bits(map, offset, mask, val); + mdelay(1000); + + pr_emerg("Unable to poweroff system\n"); +} + +static int regmap_poweroff_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + if (map) + return -EINVAL; + + map = dev_get_regmap(dev->parent, NULL); + if (!map) + return -ENODEV; + + if (of_property_read_u32(np, "poweroff-offset", &offset)) { + dev_err(dev, "unable to read 'poweroff-offset'"); + return -EINVAL; + } + + if (of_property_read_u32(np, "poweroff-mask", &mask)) { + dev_err(dev, "unable to read 'poweroff-mask'"); + return -EINVAL; + } + + if (of_property_read_u32(np, "poweroff-value", &val)) { + dev_err(dev, "unable to read 'poweroff-value'"); + return -EINVAL; + } + + if (!of_device_is_system_power_controller(dev->of_node)) { + dev_info(dev, "not a system power controller\n"); + return 0; + } + + WARN(pm_power_off, "pm_power_off is already assigned with %pf\n", + pm_power_off); + pm_power_off = regmap_poweroff; + + return 0; +} + +static int regmap_poweroff_remove(struct platform_device *pdev) +{ + if (pm_power_off == regmap_poweroff) + pm_power_off = NULL; + + return 0; +} + +static const struct of_device_id regmap_poweroff_of_match[] = { + { .compatible = "regmap-poweroff" }, + {} +}; + +static struct platform_driver regmap_poweroff_driver = { + .probe = regmap_poweroff_probe, + .remove = regmap_poweroff_remove, + .driver = { + .name = "regmap-poweroff", + .of_match_table = regmap_poweroff_of_match, + }, +}; +module_platform_driver(regmap_poweroff_driver); diff --git a/drivers/power/reset/rtk-reboot-mode.c b/drivers/power/reset/rtk-reboot-mode.c new file mode 100644 index 000000000000..5ad03232d5a3 --- /dev/null +++ b/drivers/power/reset/rtk-reboot-mode.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtk-reboot-mode.c + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include + +struct rtk_reboot_mode_data { + struct device *dev; + struct notifier_block reboot_nb; + void *base; +}; + +static int rtk_reboot_mode_cb(struct notifier_block *nb, unsigned long mode, + void *cmd) +{ + struct rtk_reboot_mode_data *d; + u32 act = RESET_ACTION_NO_ACTION; + + d = container_of(nb, struct rtk_reboot_mode_data, reboot_nb); + if (cmd) { + if (!strncmp("bootloader", cmd, 11)) + act = RESET_ACTION_FASTBOOT; + else if (!strncmp("recovery", cmd, 9)) + act = RESET_ACTION_RECOVERY; + else if (!strncmp("quiescent", cmd, 10)) + act = RESET_ACTION_QUIESCENT; +#ifdef CONFIG_RTK_VMX_ULTRA + else if (!strncmp("dm-verity device corrupted", cmd, 27)) + act = RESET_ACTION_RESCUE; +#endif + dev_info(d->dev, "reboot-mode is %s(%x)\n", (const char *)cmd, act); + } + + writel(act | RESET_MAGIC, d->base); + return NOTIFY_OK; +} + +static int rtk_reboot_mode_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_reboot_mode_data *d; + struct resource *res; + int ret; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + d->base = devm_ioremap_resource(dev, res); + if (IS_ERR(d->base)) + return PTR_ERR(d->base); + + d->reboot_nb.notifier_call = rtk_reboot_mode_cb; + ret = register_reboot_notifier(&d->reboot_nb); + if (ret) + return ret; + + writel(RESET_ACTION_ABNORMAL | RESET_MAGIC, d->base); + return 0; +} + +static struct of_device_id rtk_reboot_mode_match[] = { + { .compatible = "realtek,reboot-mode", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_rtk_reboot_mode_match); + +static struct platform_driver rtk_reboot_mode_driver = { + .probe = rtk_reboot_mode_probe, + .driver = { + .name = "rtk-reboot-mode", + .of_match_table = of_match_ptr(rtk_reboot_mode_match), + }, +}; + +static int __init rtk_reboot_mode_init(void) +{ + return platform_driver_register(&rtk_reboot_mode_driver); +} +module_init(rtk_reboot_mode_init); + +static void __exit rtk_reboot_mode_exit(void) +{ + platform_driver_unregister(&rtk_reboot_mode_driver); +} +module_exit(rtk_reboot_mode_exit); + + +MODULE_DESCRIPTION("Reatek Reboot Mode Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/power/reset/rtk-reboot.c b/drivers/power/reset/rtk-reboot.c new file mode 100644 index 000000000000..3706259a2379 --- /dev/null +++ b/drivers/power/reset/rtk-reboot.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtk-reboot.c + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include + +#define ISO_TCWCR 0x00 +#define ISO_TCWTR 0x04 +#define ISO_TCWNMI 0x08 +#define ISO_TCWOV 0x0c +#define ISO_TCWOV_RSTB_CNT 0x40 +#define ISO_TCWOV_RSTB_PAD 0x44 + +#define OE_INVALID (-1) + +struct rtk_reboot_data { + struct device *dev; + struct notifier_block reboot_nb; + struct notifier_block restart_nb; + int oe; + int oe_init; + void *base; +}; + +static void rtk_reboot_set_oe(struct rtk_reboot_data *d, int oe) +{ + u32 val; + + val = readl(d->base + ISO_TCWOV_RSTB_PAD); + val &= ~0x1; + val |= oe & 0x1; + writel(val, d->base + ISO_TCWOV_RSTB_PAD); +} + +static int rtk_reboot_cb(struct notifier_block *nb, unsigned long mode, + void *cmd) +{ + struct rtk_reboot_data *d; + + d = container_of(nb, struct rtk_reboot_data, reboot_nb); + + if (d->oe < 0) + return NOTIFY_DONE; + + dev_info(d->dev, "set oe to %d\n", d->oe); + rtk_reboot_set_oe(d, d->oe); + return NOTIFY_OK; +} + +static int rtk_reboot_restart_handler(struct notifier_block *nb, + unsigned long mode, void *cmd) +{ + struct rtk_reboot_data *d; + + d = container_of(nb, struct rtk_reboot_data, restart_nb); + + dev_emerg(d->dev, "Restarting...\n"); + + writel(0xA5, d->base + ISO_TCWCR); + writel(0x01, d->base + ISO_TCWTR); + writel(0x04, d->base + ISO_TCWOV); + writel(0x00, d->base + ISO_TCWCR); + + mdelay(10000); + dev_emerg(d->dev, "Unable to restart system\n"); + + return NOTIFY_DONE; +} + +static int rtk_reboot_parse_args(struct rtk_reboot_data *d) +{ + struct device_node *np = d->dev->of_node; + + d->oe_init = OE_INVALID; + d->oe = OE_INVALID; + + of_property_read_u32(np, "rst-oe-for-init", &d->oe_init); + of_property_read_u32(np, "rst-oe", &d->oe); + return 0; +} + +static int rtk_reboot_init_tcw(struct rtk_reboot_data *d) +{ + if (d->oe_init == OE_INVALID) + return 0; + + dev_info(d->dev, "set oe to %d\n", d->oe_init); + writel(0x00800000, d->base + ISO_TCWOV_RSTB_CNT); + rtk_reboot_set_oe(d, d->oe_init); + return 0; +}; + +static int rtk_reboot_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_reboot_data *d; + struct resource *res; + int ret; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + d->base = devm_ioremap_resource(dev, res); + if (IS_ERR(d->base)) + return PTR_ERR(d->base); + + d->reboot_nb.notifier_call = rtk_reboot_cb; + ret = register_reboot_notifier(&d->reboot_nb); + if (ret) + return ret; + + d->restart_nb.notifier_call = rtk_reboot_restart_handler; + ret = register_restart_handler(&d->restart_nb); + if (ret) { + dev_err(dev, "failed to register restart_handler: %d\n", ret); + unregister_reboot_notifier(&d->reboot_nb); + return ret; + } + + rtk_reboot_parse_args(d); + rtk_reboot_init_tcw(d); + return 0; +} + +static const struct of_device_id rtk_reboot_match[] = { + { .compatible = "realtek,reboot", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_rtk_reboot_match); + +static struct platform_driver rtk_reboot_driver = { + .probe = rtk_reboot_probe, + .driver = { + .name = "rtk-reboot", + .of_match_table = of_match_ptr(rtk_reboot_match), + }, +}; + +static int __init rtk_reboot_init(void) +{ + return platform_driver_register(&rtk_reboot_driver); +} +module_init(rtk_reboot_init); + +static void __exit rtk_reboot_exit(void) +{ + platform_driver_unregister(&rtk_reboot_driver); +} +module_exit(rtk_reboot_exit); + +MODULE_DESCRIPTION("Reatek Reboot Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 63be5362fd3a..b725ac6adfe7 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -408,6 +408,15 @@ config PWM_ROCKCHIP Generic PWM framework driver for the PWM controller found on Rockchip SoCs. +if SYNO_LSP_RTD1619B +config PWM_RTK + tristate "Realtek PWM support" + depends on ARCH_REALTEK + default n + help + Say Y, if you want to enable PWM feature on Realtek platform. + +endif # SYNO_LSP_RTD1619B config PWM_SAMSUNG tristate "Samsung PWM support" depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index cbdcd55d69ee..cd1fecf3ba21 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -38,6 +38,9 @@ obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_PWM_RTK) += pwm-rtk.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o diff --git a/drivers/pwm/pwm-rtk.c b/drivers/pwm/pwm-rtk.c new file mode 100644 index 000000000000..ef385332c7a5 --- /dev/null +++ b/drivers/pwm/pwm-rtk.c @@ -0,0 +1,934 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* Realtek pulse-width-modulation controller driver + * + * Copyright (C) 2017 Realtek Semiconductor Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PWM V1 */ +#define RTK_ADDR_PWM_V1_OCD (0x0) +#define RTK_ADDR_PWM_V1_CD (0x4) +#define RTK_ADDR_PWM_V1_CSD (0x8) + +#define RTK_PWM_V1_OCD_SHIFT (8) +#define RTK_PWM_V1_CD_SHIFT (8) +#define RTK_PWM_V1_CSD_SHIFT (4) + +#define RTK_PWM_V1_OCD_MASK (0xff) +#define RTK_PWM_V1_CD_MASK (0xff) +#define RTK_PWM_V1_CSD_MASK (0xf) + +/* PWM V2 */ +#define RTK_ADDR_PWM0_V2 (0x4) +#define RTK_ADDR_PWM1_V2 (0x8) +#define RTK_ADDR_PWM2_V2 (0xc) +#define RTK_ADDR_PWM3_V2 (0x0) + +#define RTK_PWM_V2_OCD_SHIFT (8) +#define RTK_PWM_V2_CD_SHIFT (0) +#define RTK_PWM_V2_CSD_SHIFT (16) + +#define RTK_PWM_V2_OCD_MASK (0xff) +#define RTK_PWM_V2_CD_MASK (0xff) +#define RTK_PWM_V2_CSD_MASK (0x1f) + +/* COMMON */ +#define RTK_PWM_OCD_DEFAULT (0xff) +#define RTK_PWM_CD_DEFAULT (0x1) +#define RTK_PWM_CSD_DEFAULT (0x1) + +#define NUM_PWM 4 +#define DEV_NAME "[RTK_PWM]" +#define RTK_27MHZ 27000000 +#define RTK_1SEC_TO_NS 1000000000 + +#define RTK_PWM_V1_UPD 0x54 + +struct rtk_pwm_map { + int duty_rate; + int ocd_data; + int cd_data; +}; + +struct rtk_pwm_chip { + struct pwm_chip chip; + struct device *dev; + void __iomem *mmio_pwm_reg_base; + struct regmap *iso_base; + spinlock_t lock; + int proc_id; + int base_freq; + int out_freq[NUM_PWM]; /* Hz */ + int duty_rate[NUM_PWM]; + int enable[NUM_PWM]; + int clksrc_div[NUM_PWM]; + int clkout_div[NUM_PWM]; + int clk_duty[NUM_PWM]; + int flags[NUM_PWM]; + void (*pwm_reg_set)(struct rtk_pwm_chip *pc, int hwpwm); +}; + +#define RTK_PWM_FLAGS_PULSE_LOW_ON_CHANGE 0x1 + +#define to_rtk_pwm_chip(d) container_of(d, struct rtk_pwm_chip, chip) + +#if defined(MY_DEF_HERE) +struct rtk_pwm_chip *gSynoPwmChip = NULL; +#endif /* MY_DEF_HERE */ +int set_real_freq_by_target_freq(struct rtk_pwm_chip *pc, int hwpwm, + int target_freq) +{ + int base_freq = pc->base_freq; + int real_freq; + int ocd, csd, div, opt_div; + int min_ocd = 0; + int max_ocd = 255; + int min_csd = 0; + int max_csd = 15; + int i; + + div = base_freq / target_freq; + + /* give a div to get max ocd and min csd */ + + /* find max bit */ + for (i = 0; i < 32; i++) { + if ((div << i) & BIT(31)) + break; + } + csd = (32 - (i + 8)) - 1; + if (csd > max_csd) + csd = max_csd; + else if (csd < min_csd) + csd = min_csd; + + ocd = (div >> (csd + 1)) - 1; + if (ocd > max_ocd) + ocd = max_ocd; + else if (ocd < min_ocd) + ocd = min_ocd; + + opt_div = BIT(csd + 1) * (ocd + 1); + + real_freq = base_freq / opt_div; + pc->clkout_div[hwpwm] = ocd; + pc->clksrc_div[hwpwm] = csd; + + pc->out_freq[hwpwm] = real_freq; + + return real_freq; +} + +int set_real_period_by_target_period(struct rtk_pwm_chip *pc, int hwpwm, + int target_period_ns) +{ + int base_ns = RTK_1SEC_TO_NS; + int real_period_ns; + int target_freq, real_freq; + + target_freq = base_ns / target_period_ns; + real_freq = set_real_freq_by_target_freq(pc, hwpwm, target_freq); + real_period_ns = base_ns / real_freq; + + return real_period_ns; +} + +int set_real_freq_by_target_div(struct rtk_pwm_chip *pc, int hwpwm, + int clksrc_div, int clkout_div) +{ + int base_freq = pc->base_freq; + int real_freq, div; + + div = BIT(clksrc_div + 1) * (clkout_div + 1); + real_freq = base_freq / div; + + pc->clkout_div[hwpwm] = clkout_div; + pc->clksrc_div[hwpwm] = clksrc_div; + + pc->out_freq[hwpwm] = real_freq; + + return real_freq; +} + +int set_clk_duty(struct rtk_pwm_chip *pc, int hwpwm, int duty_rate) +{ + int clkout_div = pc->clkout_div[hwpwm]; + + if (duty_rate < 0) + duty_rate = 0; + if (duty_rate > 100) + duty_rate = 100; + + pc->duty_rate[hwpwm] = duty_rate; + pc->clk_duty[hwpwm] = (duty_rate * (clkout_div + 1) / 100) - 1; + + if (pc->clk_duty[hwpwm] < 0) + pc->clk_duty[hwpwm] = 0; + if (pc->clk_duty[hwpwm] > clkout_div) + pc->clk_duty[hwpwm] = clkout_div; + + return 0; +} + +static inline void pwm_update_v1(struct rtk_pwm_chip *pc, int hwpwm) +{ + u32 val; + + if (IS_ERR_OR_NULL(pc->iso_base)) + return; + + val = 1 << hwpwm; + regmap_update_bits_base(pc->iso_base, RTK_PWM_V1_UPD, + val, val, NULL, false, true); +} + +static void pwm_reg_set_v1(struct rtk_pwm_chip *pc, int hwpwm) +{ + u32 value; + u32 old_val; + int clkout_div = 0; + int clk_duty = 0; + int clksrc_div = 0; + unsigned long flags; + + if (pc->enable[hwpwm] && pc->duty_rate[hwpwm]) { + clkout_div = pc->clkout_div[hwpwm]; + clk_duty = pc->clk_duty[hwpwm]; + clksrc_div = pc->clksrc_div[hwpwm]; + } + + spin_lock_irqsave(&pc->lock, flags); + + value = readl(pc->mmio_pwm_reg_base + RTK_ADDR_PWM_V1_OCD); + old_val = value; + value &= ~(RTK_PWM_V1_OCD_MASK << (hwpwm * RTK_PWM_V1_OCD_SHIFT)); + value |= clkout_div << (hwpwm * RTK_PWM_V1_OCD_SHIFT); + if (value != old_val) + writel(value, pc->mmio_pwm_reg_base + RTK_ADDR_PWM_V1_OCD); + + value = readl(pc->mmio_pwm_reg_base + RTK_ADDR_PWM_V1_CD); + old_val = value; + value &= ~(RTK_PWM_V1_CD_MASK << (hwpwm * RTK_PWM_V1_CD_SHIFT)); + value |= clk_duty << (hwpwm * RTK_PWM_V1_CD_SHIFT); + if (value != old_val) + writel(value, pc->mmio_pwm_reg_base + RTK_ADDR_PWM_V1_CD); + + value = readl(pc->mmio_pwm_reg_base + RTK_ADDR_PWM_V1_CSD); + old_val = value; + value &= ~(RTK_PWM_V1_CSD_MASK << (hwpwm * RTK_PWM_V1_CSD_SHIFT)); + value |= clksrc_div << (hwpwm * RTK_PWM_V1_CSD_SHIFT); + if (value != old_val) + writel(value, pc->mmio_pwm_reg_base + RTK_ADDR_PWM_V1_CSD); + + pwm_update_v1(pc, hwpwm); + spin_unlock_irqrestore(&pc->lock, flags); +} + +static void pwm_reg_set_v2(struct rtk_pwm_chip *pc, int hwpwm) +{ + void __iomem *reg; + u32 value; + u32 old_val; + int clkout_div = 0; + int clk_duty = 0; + int clksrc_div = 0; + unsigned long flags; + + if (pc->enable[hwpwm] && pc->duty_rate[hwpwm]) { + clkout_div = pc->clkout_div[hwpwm]; + clk_duty = pc->clk_duty[hwpwm]; + clksrc_div = pc->clksrc_div[hwpwm]; + } + + switch (hwpwm) { + case 0: + reg = pc->mmio_pwm_reg_base + RTK_ADDR_PWM0_V2; + break; + case 1: + reg = pc->mmio_pwm_reg_base + RTK_ADDR_PWM1_V2; + break; + case 2: + reg = pc->mmio_pwm_reg_base + RTK_ADDR_PWM2_V2; + break; + case 3: + reg = pc->mmio_pwm_reg_base + RTK_ADDR_PWM3_V2; + break; + default: + dev_err(pc->dev, "invalid index: PWM %d\n", hwpwm); + return; + } + + spin_lock_irqsave(&pc->lock, flags); + + old_val = readl(reg); + value = ((clksrc_div & RTK_PWM_V2_CSD_MASK) << RTK_PWM_V2_CSD_SHIFT) | + ((clkout_div & RTK_PWM_V2_OCD_MASK) << RTK_PWM_V2_OCD_SHIFT) | + ((clk_duty & RTK_PWM_V2_CD_MASK) << RTK_PWM_V2_CD_SHIFT); + if (value != old_val) + writel(value, reg); + + spin_unlock_irqrestore(&pc->lock, flags); +} + +static void pwm_set_register(struct rtk_pwm_chip *pc, int hwpwm) +{ + if (pc == NULL) { + pr_err("%s %s -- parameter error!--\n", DEV_NAME, __func__); + return; + } + + pc->pwm_reg_set(pc, hwpwm); +} + +static int rtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct rtk_pwm_chip *pc = to_rtk_pwm_chip(chip); + int real_period_ns, duty_rate; + + real_period_ns = + set_real_period_by_target_period(pc, pwm->hwpwm, period_ns); + + duty_rate = (int)div64_s64((s64)duty_ns * 100, period_ns); + + set_clk_duty(pc, pwm->hwpwm, duty_rate); + + pwm_set_register(pc, pwm->hwpwm); + + return 0; +} + +static int rtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct rtk_pwm_chip *pc = to_rtk_pwm_chip(chip); + + pc->enable[pwm->hwpwm] = 1; + pwm_set_register(pc, pwm->hwpwm); + + return 0; +} + +static void rtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct rtk_pwm_chip *pc = to_rtk_pwm_chip(chip); + + pc->enable[pwm->hwpwm] = 0; + pwm_set_register(pc, pwm->hwpwm); + +} + +static void rtk_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct rtk_pwm_chip *pc = to_rtk_pwm_chip(chip); + int id = pwm->hwpwm; + int base_freq = pc->base_freq; + int real_freq, div; + + if (pc->enable[id] == 0) { + state->period = 0; + state->duty_cycle = 0; + state->enabled = 0; + return; + } + + div = BIT(pc->clksrc_div[id] + 1) * (pc->clkout_div[id] + 1); + real_freq = base_freq / div; + + state->period = DIV_ROUND_UP(RTK_1SEC_TO_NS, real_freq); + state->duty_cycle = DIV_ROUND_UP_SECTOR_T(state->period * pc->duty_rate[id], 100); + state->enabled = pc->enable[id]; +} + +static const struct pwm_ops rtk_pwm_ops = { + .config = rtk_pwm_config, + .enable = rtk_pwm_enable, + .disable = rtk_pwm_disable, + .get_state = rtk_pwm_get_state, + .owner = THIS_MODULE, +}; + +/** define show/store API for each file here **/ +static ssize_t duty_rate_show(struct device *dev, + struct device_attribute *attr, + char *buf, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + return sprintf(buf, "%d%%\n", pc->duty_rate[hwpwm]); +} + +static ssize_t duty_rate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int hwpwm) +{ + int value = 0; + int ret = -1; + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + if (count < 1) { + pr_err("%s %s , count is too small, return\n", + DEV_NAME, __func__); + return count; + } + ret = kstrtoint(buf, 10, &value); + if (ret != 0) { + pr_err("%s %s , parse buf error! ret=%d\n", + DEV_NAME, __func__, ret); + return count; + } + if (value < 0 || value > 100) { + pr_err("%s %s ==== input should between 0 ~ 100\n", + DEV_NAME, __func__); + return count; + } + if (pc->duty_rate[hwpwm] == value) { + pr_info(" %s %s -- duty_rate value is not change, return!\n", + DEV_NAME, __func__); + return count; + } + pr_info("%s %s -- assign [%d] to duty_rate now!\n", + DEV_NAME, __func__, value); + + set_clk_duty(pc, hwpwm, value); + pwm_set_register(pc, hwpwm); + + return count; +} + +static ssize_t pwm_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + return sprintf(buf, "%d\n", pc->enable[hwpwm]); +} + +static ssize_t pwm_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + int value = 0; + + if (buf == NULL) { + pr_err("%s %s ==== buffer is null, return\n", + DEV_NAME, __func__); + return count; + } + sscanf(buf, "%d", &value); + + if (pc->enable[hwpwm] == value) { + pr_info("%s %s ==== the same, do nothing (hwpwm=%d, value=%d)\n", + DEV_NAME, __func__, hwpwm, value); + return count; + } + + pc->enable[hwpwm] = value; + pwm_set_register(pc, hwpwm); + + return count; +} + +static ssize_t clk_src_div_show(struct device *dev, + struct device_attribute *attr, + char *buf, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + return sprintf(buf, "%d\n", pc->clksrc_div[hwpwm]); +} + +static ssize_t clk_src_div_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + int value = 0; + int max_val; + + if (buf == NULL) { + pr_err("%s %s ==== buffer is null, return\n", + DEV_NAME, __func__); + return count; + } + sscanf(buf, "%d", &value); + + if (pc->pwm_reg_set == pwm_reg_set_v1) + max_val = RTK_PWM_V1_CSD_MASK; + else + max_val = RTK_PWM_V2_CSD_MASK; + + if (value < 0 || value > max_val) { + pr_err("%s %s ==== input should between 0 ~ %d\n", + DEV_NAME, __func__, max_val); + return count; + } + + if (pc->clksrc_div[hwpwm] == value) { + pr_info("%s %s ==== hwpwm=%d, input is the same=%d, do nothing!\n", + DEV_NAME, __func__, hwpwm, value); + return count; + } + + set_real_freq_by_target_div(pc, hwpwm, value, pc->clkout_div[hwpwm]); + + pwm_set_register(pc, hwpwm); + + return count; +} + +static ssize_t clk_out_div_show(struct device *dev, + struct device_attribute *attr, + char *buf, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + return sprintf(buf, "%d\n", pc->clkout_div[hwpwm]); +} + +static ssize_t clk_out_div_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + int value = 0; + + if (buf == NULL) { + pr_err("%s %s ==== buffer is null, return\n", + DEV_NAME, __func__); + return count; + } + sscanf(buf, "%d", &value); + + if (value < 0 || value > 255) { + pr_err("%s %s ==== input should between 0 ~ 255\n", + DEV_NAME, __func__); + return count; + } + + if (pc->clkout_div[hwpwm] == value) { + pr_info("%s %s ==== hwpwm=%d, input is the same=%d, do nothing!\n", + DEV_NAME, __func__, hwpwm, value); + return count; + } + + set_real_freq_by_target_div(pc, hwpwm, pc->clksrc_div[hwpwm], value); + + pwm_set_register(pc, hwpwm); + + return count; +} + +static ssize_t out_freq_show(struct device *dev, + struct device_attribute *attr, + char *buf, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + return sprintf(buf, "%dHz\n", pc->out_freq[hwpwm]); +} + +static ssize_t out_freq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int hwpwm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + + int value = 0; + + if (buf == NULL) { + pr_err("%s %s ==== buffer is null, return\n", + DEV_NAME, __func__); + return count; + } + sscanf(buf, "%d", &value); + + if (value < 0 || value > RTK_27MHZ) { + pr_err("%s %s ==== input should between 0 ~ 27MHz\n", + DEV_NAME, __func__); + return count; + } + + if (pc->out_freq[hwpwm] == value) { + pr_info("%s %s ==== hwpwm=%d, input is the same=%d, do nothing!\n", + DEV_NAME, __func__, hwpwm, value); + return count; + } + + set_real_freq_by_target_freq(pc, hwpwm, value); + + /* update CD since OCD is changed */ + set_clk_duty(pc, hwpwm, pc->duty_rate[hwpwm]); + + pwm_set_register(pc, hwpwm); + + return count; +} + +#define RTK_PWM_HANDLE(name, n, mode) \ +static ssize_t name ## n ## _show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return name ## _show(dev, attr, buf, n); \ +} \ + \ +static ssize_t name ## n ## _store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return name ## _store(dev, attr, buf, count, n); \ +} \ + \ +static DEVICE_ATTR(name ## n, \ + mode, \ + name ## n ## _show, \ + name ## n ## _store) + +RTK_PWM_HANDLE(duty_rate, 0, 0664); +RTK_PWM_HANDLE(pwm_enable, 0, 0664); +RTK_PWM_HANDLE(clk_src_div, 0, 0664); +RTK_PWM_HANDLE(clk_out_div, 0, 0664); +RTK_PWM_HANDLE(out_freq, 0, 0444); + +RTK_PWM_HANDLE(duty_rate, 1, 0664); +RTK_PWM_HANDLE(pwm_enable, 1, 0664); +RTK_PWM_HANDLE(clk_src_div, 1, 0664); +RTK_PWM_HANDLE(clk_out_div, 1, 0664); +RTK_PWM_HANDLE(out_freq, 1, 0444); + +RTK_PWM_HANDLE(duty_rate, 2, 0664); +RTK_PWM_HANDLE(pwm_enable, 2, 0664); +RTK_PWM_HANDLE(clk_src_div, 2, 0664); +RTK_PWM_HANDLE(clk_out_div, 2, 0664); +RTK_PWM_HANDLE(out_freq, 2, 0444); + +RTK_PWM_HANDLE(duty_rate, 3, 0664); +RTK_PWM_HANDLE(pwm_enable, 3, 0664); +RTK_PWM_HANDLE(clk_src_div, 3, 0664); +RTK_PWM_HANDLE(clk_out_div, 3, 0664); +RTK_PWM_HANDLE(out_freq, 3, 0444); + +static struct attribute *pwm_dev_attrs[] = { + &dev_attr_duty_rate0.attr, + &dev_attr_pwm_enable0.attr, + &dev_attr_clk_src_div0.attr, + &dev_attr_clk_out_div0.attr, + &dev_attr_out_freq0.attr, + &dev_attr_duty_rate1.attr, + &dev_attr_pwm_enable1.attr, + &dev_attr_clk_src_div1.attr, + &dev_attr_clk_out_div1.attr, + &dev_attr_out_freq1.attr, + &dev_attr_duty_rate2.attr, + &dev_attr_pwm_enable2.attr, + &dev_attr_clk_src_div2.attr, + &dev_attr_clk_out_div2.attr, + &dev_attr_out_freq2.attr, + &dev_attr_duty_rate3.attr, + &dev_attr_pwm_enable3.attr, + &dev_attr_clk_src_div3.attr, + &dev_attr_clk_out_div3.attr, + &dev_attr_out_freq3.attr, + NULL, +}; + +static struct attribute_group pwm_dev_attr_group = { + .attrs = pwm_dev_attrs, +}; + +static int rtk_pwm_probe(struct platform_device *pdev) +{ + struct rtk_pwm_chip *pwm; + struct device_node *node = pdev->dev.of_node; + struct device_node *pwm0, *pwm1, *pwm2, *pwm3; + int ret = 0; + u32 val = 0; + int i; + + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); + if (!pwm) + return -ENOMEM; + + pwm->proc_id = pdev->id; + pwm->dev = &pdev->dev; + + platform_set_drvdata(pdev, pwm); + + pwm->mmio_pwm_reg_base = of_iomap(node, 0); + + pwm->pwm_reg_set = of_device_get_match_data(&pdev->dev); + if (!pwm->pwm_reg_set) { + dev_err(&pdev->dev, "no proper pwm_reg_set()\n"); + return -EINVAL; + } + + spin_lock_init(&pwm->lock); + + pwm->base_freq = RTK_27MHZ; + + pwm->iso_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "realtek,iso"); + + for (i = 0; i < NUM_PWM; i++) { + pwm->out_freq[i] = 0; + pwm->enable[i] = 0; + pwm->clkout_div[i] = RTK_PWM_OCD_DEFAULT; + pwm->clksrc_div[i] = RTK_PWM_CD_DEFAULT; + pwm->clk_duty[i] = RTK_PWM_CSD_DEFAULT; + pwm->duty_rate[i] = 0; + } + + pwm0 = of_get_child_by_name(node, "pwm_0"); + if (!pwm0) { + dev_err(&pdev->dev, "could not find [pwm_0] sub-node\n"); + return -EINVAL; + } + + pwm1 = of_get_child_by_name(node, "pwm_1"); + if (!pwm1) { + dev_err(&pdev->dev, "could not find [pwm_1] sub-node\n"); + return -EINVAL; + } + + pwm2 = of_get_child_by_name(node, "pwm_2"); + if (!pwm2) { + dev_err(&pdev->dev, "could not find [pwm_2] sub-node\n"); + return -EINVAL; + } + + pwm3 = of_get_child_by_name(node, "pwm_3"); + if (!pwm3) { + dev_err(&pdev->dev, "could not find [pwm_3] sub-node\n"); + return -EINVAL; + } + + /* PWM0 */ + if (!of_property_read_u32(pwm0, "clkout_div", &val)) + pwm->clkout_div[0] = val; + + if (!of_property_read_u32(pwm0, "clksrc_div", &val)) + pwm->clksrc_div[0] = val; + + set_real_freq_by_target_div(pwm, 0, pwm->clksrc_div[0], + pwm->clkout_div[0]); + + if (!of_property_read_u32(pwm0, "enable", &val)) + pwm->enable[0] = val; + + if (!of_property_read_u32(pwm0, "duty_rate", &val)) + set_clk_duty(pwm, 0, val); + + if (of_find_property(pwm0, "pulse-low-on-change", NULL)) + pwm->flags[0] |= RTK_PWM_FLAGS_PULSE_LOW_ON_CHANGE; + + pr_info("%s %s - hwpwm=(%d) enable=(%d) duty_rate=(%d) clksrc_div=(%d) clkout_div=(%d)---\n", + DEV_NAME, __func__, 0, pwm->enable[0], pwm->duty_rate[0], + pwm->clksrc_div[0], pwm->clkout_div[0]); + pr_info("%s %s - defualt output frequence = %dHz ---\n", + DEV_NAME, __func__, pwm->out_freq[0]); + + /* PWM1 */ + if (!of_property_read_u32(pwm1, "clkout_div", &val)) + pwm->clkout_div[1] = val; + + if (!of_property_read_u32(pwm1, "clksrc_div", &val)) + pwm->clksrc_div[1] = val; + + set_real_freq_by_target_div(pwm, 1, pwm->clksrc_div[1], + pwm->clkout_div[1]); + + if (!of_property_read_u32(pwm1, "enable", &val)) + pwm->enable[1] = val; + + if (!of_property_read_u32(pwm1, "duty_rate", &val)) + set_clk_duty(pwm, 1, val); + + if (of_find_property(pwm1, "pulse-low-on-change", NULL)) + pwm->flags[1] |= RTK_PWM_FLAGS_PULSE_LOW_ON_CHANGE; + + pr_info("%s %s - hwpwm=(%d) enable=(%d) duty_rate=(%d) clksrc_div=(%d) clkout_div=(%d)---\n", + DEV_NAME, __func__, 1, pwm->enable[1], pwm->duty_rate[1], + pwm->clksrc_div[1], pwm->clkout_div[1]); + pr_info("%s %s - defualt output frequence = %dHz ---\n", + DEV_NAME, __func__, pwm->out_freq[1]); + + /* PWM2 */ + if (!of_property_read_u32(pwm2, "clkout_div", &val)) + pwm->clkout_div[2] = val; + + if (!of_property_read_u32(pwm2, "clksrc_div", &val)) + pwm->clksrc_div[2] = val; + + set_real_freq_by_target_div(pwm, 2, pwm->clksrc_div[2], + pwm->clkout_div[2]); + + if (!of_property_read_u32(pwm2, "enable", &val)) + pwm->enable[2] = val; + + if (!of_property_read_u32(pwm2, "duty_rate", &val)) + set_clk_duty(pwm, 2, val); + + if (of_find_property(pwm2, "pulse-low-on-change", NULL)) + pwm->flags[2] |= RTK_PWM_FLAGS_PULSE_LOW_ON_CHANGE; + + pr_info("%s %s - hwpwm=(%d) enable=(%d) duty_rate=(%d) clksrc_div=(%d) clkout_div=(%d)---\n", + DEV_NAME, __func__, 2, pwm->enable[2], pwm->duty_rate[2], + pwm->clksrc_div[2], pwm->clkout_div[2]); + pr_info("%s %s - defualt output frequence = %dHz ---\n", + DEV_NAME, __func__, pwm->out_freq[2]); + + /* PWM3 */ + if (!of_property_read_u32(pwm3, "clkout_div", &val)) + pwm->clkout_div[3] = val; + + if (!of_property_read_u32(pwm3, "clksrc_div", &val)) + pwm->clksrc_div[3] = val; + + set_real_freq_by_target_div(pwm, 3, pwm->clksrc_div[3], + pwm->clkout_div[3]); + + if (!of_property_read_u32(pwm3, "enable", &val)) + pwm->enable[3] = val; + + if (!of_property_read_u32(pwm3, "duty_rate", &val)) + set_clk_duty(pwm, 3, val); + + if (of_find_property(pwm3, "pulse-low-on-change", NULL)) + pwm->flags[3] |= RTK_PWM_FLAGS_PULSE_LOW_ON_CHANGE; + + pr_info("%s %s - hwpwm=(%d) enable=(%d) duty_rate=(%d) clksrc_div=(%d) clkout_div=(%d)---\n", + DEV_NAME, __func__, 3, pwm->enable[3], pwm->duty_rate[3], + pwm->clksrc_div[3], pwm->clkout_div[3]); + pr_info("%s %s - defualt output frequence = %dHz ---\n", + DEV_NAME, __func__, pwm->out_freq[3]); + + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &rtk_pwm_ops; + pwm->chip.base = 0; + pwm->chip.npwm = NUM_PWM; + + ret = sysfs_create_group(&pdev->dev.kobj, &pwm_dev_attr_group); + if (ret < 0) { + dev_err(&pdev->dev, "sysfs_create_group() failed: %d\n", ret); + return ret; + } + + ret = pwmchip_add(&pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); + sysfs_remove_group(&pdev->dev.kobj, &pwm_dev_attr_group); + return ret; + } + + for (i = 0; i < NUM_PWM; i++) + pwm_set_register(pwm, i); + +#if defined(MY_DEF_HERE) + gSynoPwmChip = pwm; +#endif /* MY_DEF_HERE */ + return 0; +} + +#if defined(MY_DEF_HERE) +int SynoRTKPWMSet(const int id, const int enable, const int clkout_div, const int clksrc_div, const int duty_rate) +{ + + if (0 > id || 3 < id || NULL == gSynoPwmChip) { + WARN_ON(1); + return -EINVAL; + } + gSynoPwmChip->clkout_div[id] = clkout_div; + + gSynoPwmChip->clksrc_div[id] = clksrc_div; + + set_real_freq_by_target_div(gSynoPwmChip, id, gSynoPwmChip->clksrc_div[id], + gSynoPwmChip->clkout_div[id]); + + gSynoPwmChip->enable[id] = enable; + + set_clk_duty(gSynoPwmChip, id, duty_rate); + pr_debug("%s %s - hwpwm=(%d) enable=(%d) duty_rate=(%d) clksrc_div=(%d) clkout_div=(%d)---\n", + DEV_NAME, __func__, id, gSynoPwmChip->enable[id], gSynoPwmChip->duty_rate[id], + gSynoPwmChip->clksrc_div[id], gSynoPwmChip->clkout_div[id]); + pwm_set_register(gSynoPwmChip, id); + return 0; +} +EXPORT_SYMBOL(SynoRTKPWMSet); +#endif /* MY_DEF_HERE */ + +static int rtk_pwm_remove(struct platform_device *pdev) +{ + struct rtk_pwm_chip *pc = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < NUM_PWM; i++) { + pc->enable[i] = 0; + pwm_set_register(pc, i); + } + sysfs_remove_group(&pdev->dev.kobj, &pwm_dev_attr_group); + +#if defined(MY_DEF_HERE) + gSynoPwmChip = NULL; +#endif /* MY_DEF_HERE */ + return pwmchip_remove(&pc->chip); +} + +static const struct of_device_id rtk_pwm_of_match[] = { + { + .compatible = "realtek,rtk-pwm", + .data = pwm_reg_set_v1, + }, + { + .compatible = "realtek,rtk-pwm-v2", + .data = pwm_reg_set_v2, + }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, rtk_pwm_of_match); + +static struct platform_driver rtk_pwm_platform_driver = { + .driver = { + .name = "rtk-pwm", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtk_pwm_of_match), + }, + .probe = rtk_pwm_probe, + .remove = rtk_pwm_remove, +}; + +module_platform_driver(rtk_pwm_platform_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("REALTEK Corporation"); +MODULE_ALIAS("platform:rtk-pwm"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 020a00d6696b..2db71980ec8a 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -56,6 +56,17 @@ config REGULATOR_USERSPACE_CONSUMER If unsure, say no. +if SYNO_LSP_RTD1619B +config REGULATOR_VIRTUAL_CONSUMER_HELPER + tristate "Virtual regulator consumer helper support" + select REGULATOR_VIRTUAL_CONSUMER + help + This drivers provdes a helper to add a virtual consumer for + each regulator class device. + + If unsure, say no. + +endif # SYNO_LSP_RTD1619B config REGULATOR_88PG86X tristate "Marvell 88PG86X voltage regulators" depends on I2C @@ -1279,5 +1290,25 @@ config REGULATOR_QCOM_LABIBB boost regulator and IBB can be used as a negative boost regulator for LCD display panel. +if SYNO_LSP_RTD1619B +config REGULATOR_APW888X_CORE + tristate + +config REGULATOR_APW8889 + tristate "ANPEC APW8889 Power regulators" + depends on MFD_APW8889_I2C + select REGULATOR_APW888X_CORE + help + This driver provides support for the voltage regulators on the + Anpec APW8889. + +config REGULATOR_APW8886 + tristate "ANPEC APW8886 Power regulators" + depends on MFD_APW8886_I2C + select REGULATOR_APW888X_CORE + help + This driver provides support for the voltage regulators on the + Anpec APW8886. +endif # SYNO_LSP_RTD1619B endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 6ebae516258e..e5cd0098ee0b 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -9,6 +9,9 @@ obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER_HELPER) += virtual-helper.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o @@ -157,5 +160,10 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_REGULATOR_APW888X_CORE) += apw888x-regulator-core.o +obj-$(CONFIG_REGULATOR_APW8889) += apw8889-regulator.o +obj-$(CONFIG_REGULATOR_APW8886) += apw8886-regulator.o +endif # CONFIG_SYNO_LSP_RTD1619B ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/apw8886-regulator.c b/drivers/regulator/apw8886-regulator.c new file mode 100644 index 000000000000..d0b71ea9cb4a --- /dev/null +++ b/drivers/regulator/apw8886-regulator.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "apw888x-regulator.h" + + +/* regulator id */ +enum { + APW8886_ID_DC1 = 0, + APW8886_ID_DC2, + APW8886_ID_DC3, + APW8886_ID_DC4, + APW8886_ID_DC5, + APW8886_ID_LDO1, + APW8886_ID_VFB5, + APW8886_ID_MAX +}; + +#define APW8886_DESC(_id, _name, _min_uV, _uV_step, _n_volt, _type)\ +{ \ + .desc = { \ + .owner = THIS_MODULE, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &apw888x_regulator_ops, \ + .name = _name, \ + .n_voltages = _n_volt, \ + .min_uV = _min_uV, \ + .uV_step = _uV_step, \ + .id = APW8886_ID_ ## _id, \ + .vsel_reg = APW8886_REG_ ## _id ## _NRMVOLT, \ + .vsel_mask = APW8886_ ## _id ## _NRMVOLT_MASK, \ + .enable_reg = APW8886_REG_ONOFF, \ + .enable_mask = APW8886_ ## _id ## _ON_MASK, \ + .enable_val = APW8886_ ## _id ## _ON_MASK, \ + .of_map_mode = apw888x_regulator_ ## _type ##_of_map_mode, \ + }, \ + .nmode_reg = APW8886_REG_ ## _id ## _MODE, \ + .nmode_mask = APW8886_ ## _id ## _NRMMODE_MASK, \ + .smode_reg = APW8886_REG_ ## _id ## _MODE, \ + .smode_mask = APW8886_ ## _id ## _SLPMODE_MASK, \ + .svsel_reg = APW8886_REG_ ## _id ## _SLPVOLT, \ + .svsel_mask = APW8886_ ## _id ## _SLPVOLT_MASK, \ +} + +#define APW8886_DESC_CLP(_id, _name, _min_uV, _uV_step, _n_volt, _type) \ +{ \ + .desc = { \ + .owner = THIS_MODULE, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &apw888x_regulator_ops, \ + .name = _name, \ + .n_voltages = _n_volt, \ + .min_uV = _min_uV, \ + .uV_step = _uV_step, \ + .id = APW8886_ID_ ## _id, \ + .vsel_reg = APW8886_REG_ ## _id ## _NRMVOLT, \ + .vsel_mask = APW8886_ ## _id ## _NRMVOLT_MASK, \ + .enable_reg = APW8886_REG_ONOFF, \ + .enable_mask = APW8886_ ## _id ## _ON_MASK, \ + .enable_val = APW8886_ ## _id ## _ON_MASK, \ + .of_map_mode = apw888x_regulator_ ## _type ##_of_map_mode, \ + }, \ + .nmode_reg = APW8886_REG_ ## _id ## _MODE, \ + .nmode_mask = APW8886_ ## _id ## _NRMMODE_MASK, \ + .smode_reg = APW8886_REG_ ## _id ## _MODE, \ + .smode_mask = APW8886_ ## _id ## _SLPMODE_MASK, \ + .svsel_reg = APW8886_REG_ ## _id ## _SLPVOLT, \ + .svsel_mask = APW8886_ ## _id ## _SLPVOLT_MASK, \ +} + +#define APW8886_DESC_FIXED_UV(_id, _name, _fixed_uV) \ +{ \ + .desc = { \ + .owner = THIS_MODULE, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &apw888x_regulator_fixed_uV_ops, \ + .name = _name, \ + .n_voltages = 1, \ + .fixed_uV = _fixed_uV, \ + .id = APW8886_ID_ ## _id, \ + .enable_reg = APW8886_REG_ONOFF, \ + .enable_mask = APW8886_ ## _id ## _ON_MASK, \ + .enable_val = APW8886_ ## _id ## _ON_MASK, \ + .of_map_mode = apw888x_regulator_dc_of_map_mode, \ + }, \ + .nmode_reg = APW8886_REG_ ## _id ## _MODE, \ + .nmode_mask = APW8886_ ## _id ## _NRMMODE_MASK, \ + .smode_reg = APW8886_REG_ ## _id ## _MODE, \ + .smode_mask = APW8886_ ## _id ## _SLPMODE_MASK, \ +} + +static struct apw888x_regulator_desc desc[] = { + [APW8886_ID_DC1] = APW8886_DESC(DC1, "dc1", 2200000, 25000, 64, dc), + [APW8886_ID_DC2] = APW8886_DESC_CLP(DC2, "dc2", 550000, 12500, 64, dc), + [APW8886_ID_DC3] = APW8886_DESC_CLP(DC3, "dc3", 550000, 12500, 64, dc), + [APW8886_ID_DC4] = APW8886_DESC(DC4, "dc4", 800000, 20000, 64, dc), + [APW8886_ID_DC5] = APW8886_DESC_FIXED_UV(DC5, "dc5", 0), + [APW8886_ID_LDO1] = APW8886_DESC(LDO1, "ldo1", 1780000, 40000, 32, ldo), + [APW8886_ID_VFB5] = { + .desc = { + .owner = THIS_MODULE, + .type = REGULATOR_VOLTAGE, + .ops = &apw888x_regulator_vfb5_ops, + .name = "vfb5", + .n_voltages = 16, + .min_uV = 512500, + .uV_step = 12500, + .id = APW8886_ID_VFB5, + .vsel_reg = APW8886_REG_VFB5_REF_VOLT_DAC, + .vsel_mask = 0xf, + }, + }, +}; + +/* pm */ +static int apw8886_regulator_suspend(struct device *dev) +{ + struct apw888x_regulator_device *regdev = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + apw888x_regulator_device_generic_suspend(regdev); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static int apw8886_regulator_resume(struct device *dev) +{ + struct apw888x_regulator_device *regdev = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + apw888x_regulator_device_generic_resume(regdev); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops apw8886_regulator_pm_ops = { + .suspend = apw8886_regulator_suspend, + .resume = apw8886_regulator_resume, +}; + +static int apw8886_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apw888x_regulator_device *regdev; + int i, ret; + + regdev = devm_kzalloc(dev, sizeof(*regdev), GFP_KERNEL); + if (!regdev) + return -ENOMEM; + + regdev->regmap = dev_get_regmap(dev->parent, NULL); + if (!regdev->regmap) + return -EINVAL; + + regdev->dev = dev; + INIT_LIST_HEAD(®dev->list); + + for (i = 0; i < ARRAY_SIZE(desc); i++) { + ret = apw888x_regulator_register(regdev, &desc[i]); + if (ret) { + dev_err(dev, "failed to register %s: %d\n", + desc[i].desc.name, ret); + return ret; + } + } + + platform_set_drvdata(pdev, regdev); + return 0; +} + +static void apw8886_regulator_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apw888x_regulator_device *regdev = platform_get_drvdata(pdev); + + dev_info(dev, "enter %s\n", __func__); + apw888x_regulator_device_generic_shutdown(regdev); + dev_info(dev, "exit %s\n", __func__); +} + +static const struct of_device_id apw8886_regulator_ids[] = { + { .compatible = "anpec,apw8886-regulator", }, + {} +}; +MODULE_DEVICE_TABLE(of, apw8886_regulator_ids); + +static struct platform_driver apw8886_regulator_driver = { + .driver = { + .name = "apw8886-regulator", + .owner = THIS_MODULE, + .pm = &apw8886_regulator_pm_ops, + .of_match_table = apw8886_regulator_ids, + }, + .probe = apw8886_regulator_probe, + .shutdown = apw8886_regulator_shutdown, +}; +module_platform_driver(apw8886_regulator_driver); + +MODULE_DESCRIPTION("Anpec APW8886 Regulator Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + + diff --git a/drivers/regulator/apw8889-regulator.c b/drivers/regulator/apw8889-regulator.c new file mode 100644 index 000000000000..9aa79f4ac3ca --- /dev/null +++ b/drivers/regulator/apw8889-regulator.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "apw888x-regulator.h" + +/* regulator id */ +enum { + APW8889_ID_DC1 = 0, + APW8889_ID_DC2, + APW8889_ID_DC3, + APW8889_ID_DC4, + APW8889_ID_DC5, + APW8889_ID_DC6, + APW8889_ID_LDO1, + APW8889_ID_MAX +}; + +#define APW8889_DESC(_id, _name, _min_uV, _uV_step, _n_volt, _type)\ +{ \ + .desc = { \ + .owner = THIS_MODULE, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &apw888x_regulator_ops, \ + .name = _name, \ + .n_voltages = _n_volt, \ + .min_uV = _min_uV, \ + .uV_step = _uV_step, \ + .id = APW8889_ID_ ## _id, \ + .vsel_reg = APW8889_REG_ ## _id ## _NRMVOLT, \ + .vsel_mask = APW8889_ ## _id ## _NRMVOLT_MASK, \ + .enable_reg = APW8889_REG_ONOFF, \ + .enable_mask = APW8889_ ## _id ## _ON_MASK, \ + .enable_val = APW8889_ ## _id ## _ON_MASK, \ + .of_map_mode = apw888x_regulator_ ## _type ##_of_map_mode, \ + }, \ + .nmode_reg = APW8889_REG_ ## _id ## _MODE, \ + .nmode_mask = APW8889_ ## _id ## _NRMMODE_MASK, \ + .smode_reg = APW8889_REG_ ## _id ## _MODE, \ + .smode_mask = APW8889_ ## _id ## _SLPMODE_MASK, \ + .svsel_reg = APW8889_REG_ ## _id ## _SLPVOLT, \ + .svsel_mask = APW8889_ ## _id ## _SLPVOLT_MASK, \ + .dischg_reg = APW8889_REG_DISCHG, \ + .dischg_mask = APW8889_ ## _id ## _DISCHG_MASK, \ +} + +#define APW8889_DESC_CLP(_id, _name, _min_uV, _uV_step, _n_volt, _type) \ +{ \ + .desc = { \ + .owner = THIS_MODULE, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &apw888x_regulator_ops, \ + .name = _name, \ + .n_voltages = _n_volt, \ + .min_uV = _min_uV, \ + .uV_step = _uV_step, \ + .id = APW8889_ID_ ## _id, \ + .vsel_reg = APW8889_REG_ ## _id ## _NRMVOLT, \ + .vsel_mask = APW8889_ ## _id ## _NRMVOLT_MASK, \ + .enable_reg = APW8889_REG_ONOFF, \ + .enable_mask = APW8889_ ## _id ## _ON_MASK, \ + .enable_val = APW8889_ ## _id ## _ON_MASK, \ + .of_map_mode = apw888x_regulator_ ## _type ##_of_map_mode, \ + }, \ + .nmode_reg = APW8889_REG_ ## _id ## _MODE, \ + .nmode_mask = APW8889_ ## _id ## _NRMMODE_MASK, \ + .smode_reg = APW8889_REG_ ## _id ## _MODE, \ + .smode_mask = APW8889_ ## _id ## _SLPMODE_MASK, \ + .svsel_reg = APW8889_REG_ ## _id ## _SLPVOLT, \ + .svsel_mask = APW8889_ ## _id ## _SLPVOLT_MASK, \ + .dischg_reg = APW8889_REG_DISCHG, \ + .dischg_mask = APW8889_ ## _id ## _DISCHG_MASK, \ +} + +#define APW8889_DESC_FIXED_UV(_id, _name, _fixed_uV) \ +{ \ + .desc = { \ + .owner = THIS_MODULE, \ + .type = REGULATOR_VOLTAGE, \ + .ops = &apw888x_regulator_fixed_uV_ops, \ + .name = _name, \ + .n_voltages = 1, \ + .fixed_uV = _fixed_uV, \ + .id = APW8889_ID_ ## _id, \ + .enable_reg = APW8889_REG_ONOFF, \ + .enable_mask = APW8889_ ## _id ## _ON_MASK, \ + .enable_val = APW8889_ ## _id ## _ON_MASK, \ + .of_map_mode = apw888x_regulator_dc_of_map_mode, \ + }, \ + .nmode_reg = APW8889_REG_ ## _id ## _MODE, \ + .nmode_mask = APW8889_ ## _id ## _NRMMODE_MASK, \ + .smode_reg = APW8889_REG_ ## _id ## _MODE, \ + .smode_mask = APW8889_ ## _id ## _SLPMODE_MASK, \ + .dischg_reg = APW8889_REG_DISCHG, \ + .dischg_mask = APW8889_ ## _id ## _DISCHG_MASK, \ +} + +static struct apw888x_regulator_desc desc[] = { + [APW8889_ID_DC1] = APW8889_DESC(DC1, "dc1", 2200000, 25000, 64, dc), + [APW8889_ID_DC2] = APW8889_DESC_CLP(DC2, "dc2", 550000, 12500, 64, dc), + [APW8889_ID_DC3] = APW8889_DESC_CLP(DC3, "dc3", 550000, 12500, 64, dc), + [APW8889_ID_DC4] = APW8889_DESC_CLP(DC4, "dc4", 550000, 12500, 64, dc), + [APW8889_ID_DC5] = APW8889_DESC_FIXED_UV(DC5, "dc5", 0), + [APW8889_ID_DC6] = APW8889_DESC(DC6, "dc6", 800000, 20000, 64, dc), + [APW8889_ID_LDO1] = APW8889_DESC(LDO1, "ldo1", 1780000, 40000, 32, ldo), +}; + +static int apw8889_regulator_suspend(struct device *dev) +{ + struct apw888x_regulator_device *regdev = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + apw888x_regulator_device_generic_suspend(regdev); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static int apw8889_regulator_resume(struct device *dev) +{ + struct apw888x_regulator_device *regdev = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + apw888x_regulator_device_generic_resume(regdev); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops apw8889_regulator_pm_ops = { + .suspend = apw8889_regulator_suspend, + .resume = apw8889_regulator_resume, +}; + +static int apw8889_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apw888x_regulator_device *regdev; + int i, ret; + + regdev = devm_kzalloc(dev, sizeof(*regdev), GFP_KERNEL); + if (!regdev) + return -ENOMEM; + + regdev->regmap = dev_get_regmap(dev->parent, NULL); + if (!regdev->regmap) + return -EINVAL; + + regdev->dev = dev; + INIT_LIST_HEAD(®dev->list); + + regcache_cache_bypass(regdev->regmap, true); + ret = regmap_write(regdev->regmap, APW8889_REG_DISCHG, 0xfd); + if (ret) + dev_warn(dev, "failed to reset dischg: %d\n", ret); + regcache_cache_bypass(regdev->regmap, false); + + for (i = 0; i < ARRAY_SIZE(desc); i++) { + ret = apw888x_regulator_register(regdev, &desc[i]); + if (ret) { + dev_err(dev, "failed to register %s: %d\n", + desc[i].desc.name, ret); + return ret; + } + } + + platform_set_drvdata(pdev, regdev); + return 0; +} + +static void apw8889_regulator_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apw888x_regulator_device *regdev = platform_get_drvdata(pdev); + + dev_info(dev, "enter %s\n", __func__); + apw888x_regulator_device_generic_shutdown(regdev); + dev_info(dev, "exit %s\n", __func__); +} + +static const struct of_device_id apw8889_regulator_ids[] = { + { .compatible = "anpec,apw8889-regulator", }, + {} +}; +MODULE_DEVICE_TABLE(of, apw8889_regulator_ids); + +static struct platform_driver apw8889_regulator_driver = { + .driver = { + .name = "apw8889-regulator", + .owner = THIS_MODULE, + .pm = &apw8889_regulator_pm_ops, + .of_match_table = apw8889_regulator_ids, + }, + .probe = apw8889_regulator_probe, + .shutdown = apw8889_regulator_shutdown, +}; +module_platform_driver(apw8889_regulator_driver); + +MODULE_DESCRIPTION("Anpec APW8889 Regulator Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL vw"); + + diff --git a/drivers/regulator/apw888x-regulator-core.c b/drivers/regulator/apw888x-regulator-core.c new file mode 100644 index 000000000000..11dff5a0cb1a --- /dev/null +++ b/drivers/regulator/apw888x-regulator-core.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "apw888x-regulator.h" + + +#define APW888X_SLEEP_MODE_NRM_VOLT 0x0 +#define APW888X_SLEEP_MODE_SLP_VOLT 0x2 +#define APW888X_SLEEP_MODE_SHUTDOWN 0x3 +static int apw888x_set_sleep_mode(struct regulator_dev *rdev, int mode); + +static int +apw888x_regulator_of_parse_data(struct device_node *np, + const struct regulator_desc *desc, + struct apw888x_regulator_data *data) +{ + unsigned int val; + struct device_node *child; + struct regulator_state *rstate = &data->state_shutdown; + + child = of_get_child_by_name(np, "regulator-state-shutdown"); + if (!child) + child = of_get_child_by_name(np, "regulator-state-mem"); + if (!child) { + rstate->enabled = ENABLE_IN_SUSPEND; + } else { + if (of_property_read_bool(child, "regulator-on-in-suspend")) + rstate->enabled = ENABLE_IN_SUSPEND; + + if (of_property_read_bool(child, "regulator-off-in-suspend")) + rstate->enabled = DISABLE_IN_SUSPEND; + + if (!of_property_read_u32(child, "regulator-suspend-microvolt", &val)) + rstate->uV = val; + + of_node_put(child); + } + + if (desc->n_voltages == 1 && desc->fixed_uV == 0) { + u32 min = 0, max = 0; + + of_property_read_u32(np, "regulator-min-microvolt", &min); + of_property_read_u32(np, "regulator-max-microvolt", &max); + WARN_ON(min != max); + data->fixed_uV = max; + } + + if (of_find_property(np, "apw888x-discharge-disable", NULL)) + data->dischg_dis = 1; + + return 0; +} + +unsigned int apw888x_regulator_dc_of_map_mode(unsigned int mode) +{ + switch (mode) { + case APW8889_DC_MODE_FORCE_PWM: + return REGULATOR_MODE_FAST; + default: + break; + } + return REGULATOR_MODE_NORMAL; +} + +unsigned int apw888x_regulator_ldo_of_map_mode(unsigned int mode) +{ + return REGULATOR_MODE_NORMAL; +} + +/* regulator_ops */ +static int apw888x_regulator_set_mode_regmap(struct regulator_dev *rdev, + unsigned int mode) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + struct apw888x_regulator_desc *desc = data->desc; + unsigned int val = 0; + + dev_dbg(rdev_get_dev(rdev), "%s\n", __func__); + if (!data->nmode) + return -EINVAL; + + if (apw888x_regulator_type_is_ldo(desc)) + val = 0; + else + val = (mode & REGULATOR_MODE_FAST) ? 2 : 0; + + return regmap_field_write(data->nmode, val); +} + +static +unsigned int apw888x_regulator_get_mode_regmap(struct regulator_dev *rdev) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + struct apw888x_regulator_desc *desc = data->desc; + unsigned int val; + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s\n", __func__); + if (!data->nmode) + return -EINVAL; + + ret = regmap_field_read(data->nmode, &val); + if (ret) + return 0; + + if (apw888x_regulator_type_is_ldo(desc) && val == 2) + return REGULATOR_MODE_IDLE; + else if (val == 2) + return REGULATOR_MODE_FAST; + return REGULATOR_MODE_NORMAL; +} + +static int apw888x_set_sleep_mode(struct regulator_dev *rdev, int mode) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + + if (!data->smode) + return -EINVAL; + + dev_dbg(rdev_get_dev(rdev), "%s to %d\n", __func__, mode); + return regmap_field_write(data->smode, mode); +} + +static int apw888x_regulator_set_suspend_enable(struct regulator_dev *rdev) +{ + return apw888x_set_sleep_mode(rdev, APW888X_SLEEP_MODE_NRM_VOLT); +} + +static int apw888x_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + struct device *dev = rdev_get_dev(rdev); + + dev_dbg(dev, "%s\n", __func__); + if (!data->smode) + return -EINVAL; + + apw888x_set_sleep_mode(rdev, APW888X_SLEEP_MODE_SHUTDOWN); + + /* dischg only vaild when shutdown */ + if (data->dischg && data->dischg_dis) { + dev_info(dev, "%s: set dischg disabled\n", __func__); + regmap_field_write(data->dischg, 0x0); + } + return 0; +} + +static int apw888x_regulator_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + int vsel; + + dev_dbg(rdev_get_dev(rdev), "%s: uV=%d\n", __func__, uV); + vsel = regulator_map_voltage_iterate(rdev, uV, uV); + if (vsel < 0) + return -EINVAL; + + if (!data->smode || !data->svsel) + return -EINVAL; + + apw888x_set_sleep_mode(rdev, APW888X_SLEEP_MODE_SLP_VOLT); + regmap_field_write(data->svsel, vsel); + return 0; +} + +static int apw888x_regulator_resume(struct regulator_dev *rdev) +{ + dev_dbg(rdev_get_dev(rdev), "%s\n", __func__); + return apw888x_set_sleep_mode(rdev, APW888X_SLEEP_MODE_NRM_VOLT); +} + +static int apw888x_regulator_get_voltage_fixed(struct regulator_dev *rdev) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + + if (data->fixed_uV) + return data->fixed_uV; + return -EINVAL; +} + +const struct regulator_ops apw888x_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_mode = apw888x_regulator_get_mode_regmap, + .set_mode = apw888x_regulator_set_mode_regmap, + .set_suspend_voltage = apw888x_regulator_set_suspend_voltage, + .set_suspend_enable = apw888x_regulator_set_suspend_enable, + .set_suspend_disable = apw888x_regulator_set_suspend_disable, + .resume = apw888x_regulator_resume, +}; + +const struct regulator_ops apw888x_regulator_fixed_uV_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_mode = apw888x_regulator_get_mode_regmap, + .set_mode = apw888x_regulator_set_mode_regmap, + .set_suspend_voltage = apw888x_regulator_set_suspend_voltage, + .set_suspend_enable = apw888x_regulator_set_suspend_enable, + .set_suspend_disable = apw888x_regulator_set_suspend_disable, + .get_voltage = apw888x_regulator_get_voltage_fixed, + .resume = apw888x_regulator_resume, +}; + +const struct regulator_ops apw888x_regulator_vfb5_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static ssize_t regulator_shutdown_uV_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + + return sprintf(buf, "%d\n", data->state_shutdown .uV); +} +static DEVICE_ATTR(shutdown_microvolts, 0444, regulator_shutdown_uV_show, NULL); + +static ssize_t regulator_shutdown_state_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + int state = data->state_shutdown.enabled; + + if (state == ENABLE_IN_SUSPEND) + return sprintf(buf, "enabled\n"); + else if (state == DISABLE_IN_SUSPEND) + return sprintf(buf, "disabled\n"); + else + return sprintf(buf, "unknown\n"); +} +static DEVICE_ATTR(shutdown_state, 0444, regulator_shutdown_state_show, NULL); + +static struct attribute *apw888x_regulator_dev_attrs[] = { + &dev_attr_shutdown_microvolts.attr, + &dev_attr_shutdown_state.attr, + NULL +}; + +static const struct attribute_group apw888x_regulator_dev_group = { + .attrs = apw888x_regulator_dev_attrs, +}; + +static struct regmap_field * +create_regmap_field(struct apw888x_regulator_device *regdev, u32 reg, u32 mask) +{ + u32 msb = fls(mask) - 1; + u32 lsb = ffs(mask) - 1; + struct reg_field map = REG_FIELD(reg, lsb, msb); + struct regmap_field *rmap; + + if (reg == 0 && mask == 0) + return NULL; + + dev_dbg(regdev->dev, "reg=%02x, mask=%02x, lsb=%d, msb=%d\n", + reg, mask, lsb, msb); + rmap = devm_regmap_field_alloc(regdev->dev, regdev->regmap, map); + if (IS_ERR(rmap)) { + dev_err(regdev->dev, "failed to alloc regmap field for (reg=%02x, mask=%02x): %ld\n", + reg, mask, PTR_ERR(rmap)); + } + return rmap; +} + + +#define APW888X_DC_MODE_MASK (REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST) +#define APW888X_LDO_MODE_MASK (REGULATOR_MODE_NORMAL) + +int apw888x_regulator_register(struct apw888x_regulator_device *regdev, + struct apw888x_regulator_desc *desc) +{ + struct device *dev = regdev->dev; + struct apw888x_regulator_data *data; + struct regulator_config config = {}; + struct regulator_init_data *init_data = NULL; + struct regulation_constraints *c; + struct device_node *child; + int ret; + + for_each_child_of_node(dev->of_node, child) { + if (of_node_cmp(child->name, desc->desc.name)) + continue; + + init_data = of_get_regulator_init_data(dev, child, &desc->desc); + break; + } + if (!init_data) + return -EINVAL; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->desc = desc; + list_add_tail(&data->list, ®dev->list); + + c = &init_data->constraints; + c->initial_state = 0; + c->valid_ops_mask |= REGULATOR_CHANGE_MODE; + c->valid_modes_mask |= apw888x_regulator_type_is_ldo(data->desc) ? + APW888X_LDO_MODE_MASK : APW888X_DC_MODE_MASK; + apw888x_regulator_of_parse_data(child, &desc->desc, data); + + data->nmode = create_regmap_field(regdev, desc->nmode_reg, + desc->nmode_mask); + if (IS_ERR(data->nmode)) + return PTR_ERR(data->nmode); + data->smode = create_regmap_field(regdev, desc->smode_reg, + desc->smode_mask); + if (IS_ERR(data->smode)) + return PTR_ERR(data->smode); + data->svsel = create_regmap_field(regdev, desc->svsel_reg, + desc->svsel_mask); + if (IS_ERR(data->svsel)) + return PTR_ERR(data->svsel); + data->dischg = create_regmap_field(regdev, desc->dischg_reg, + desc->dischg_mask); + if (IS_ERR(data->dischg)) + return PTR_ERR(data->dischg); + + config.dev = regdev->dev; + config.regmap = regdev->regmap; + config.driver_data = data; + config.of_node = child; + config.init_data = init_data; + + data->rdev = devm_regulator_register(dev, &desc->desc, &config); + if (IS_ERR(data->rdev)) + return PTR_ERR(data->rdev); + + ret = sysfs_create_group(&data->rdev->dev.kobj, &apw888x_regulator_dev_group); + if (ret) + return ret; + + apw888x_set_sleep_mode(data->rdev, APW888X_SLEEP_MODE_NRM_VOLT); + + return 0; +} + +static int apw888x_regulator_set_sleep_state(struct regulator_dev *rdev, int is_shutdown) +{ + struct apw888x_regulator_data *data = rdev_get_drvdata(rdev); + struct regulator_state *rstate; + + if (!data->smode) + return -EINVAL; + + rstate = is_shutdown ? &data->state_shutdown : &rdev->constraints->state_mem; + + if (rstate->enabled == ENABLE_IN_SUSPEND) + apw888x_regulator_set_suspend_enable(rdev); + + if (rstate->enabled == ENABLE_IN_SUSPEND && rstate->uV) + apw888x_regulator_set_suspend_voltage(rdev, rstate->uV); + + if (rstate->enabled == DISABLE_IN_SUSPEND) + apw888x_regulator_set_suspend_disable(rdev); + + return -EINVAL; +} + +int apw888x_regulator_device_generic_suspend(struct apw888x_regulator_device *regdev) +{ + return 0; +} + +int apw888x_regulator_device_generic_resume(struct apw888x_regulator_device *regdev) +{ + return 0; +} + +int apw888x_regulator_device_generic_shutdown(struct apw888x_regulator_device *regdev) +{ + struct apw888x_regulator_data *pos; + + list_for_each_entry(pos, ®dev->list, list) + apw888x_regulator_set_sleep_state(pos->rdev, 1); + return 0; +} diff --git a/drivers/regulator/apw888x-regulator.h b/drivers/regulator/apw888x-regulator.h new file mode 100644 index 000000000000..e5b4e4176543 --- /dev/null +++ b/drivers/regulator/apw888x-regulator.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __APW888X_REGULATOR_H +#define __APW888X_REGULATOR_H + +#include +#include +#include +#include +#include +#include + +struct apw888x_regulator_desc { + struct regulator_desc desc; + u8 nmode_reg; + u8 nmode_mask; + u8 smode_reg; + u8 smode_mask; + u8 svsel_reg; + u8 svsel_mask; + u8 dischg_reg; + u8 dischg_mask; +}; + +struct apw888x_regulator_device { + struct device *dev; + struct regmap *regmap; + struct list_head list; +}; + +struct apw888x_regulator_data { + struct list_head list; + struct regulator_dev *rdev; + struct apw888x_regulator_desc *desc; + + struct regmap_field *svsel; + struct regmap_field *smode; + struct regmap_field *nmode; + struct regmap_field *clamp; + struct regmap_field *dischg; + + struct regulator_state state_shutdown; + u32 dischg_dis; + + u32 fixed_uV; +}; + +int apw888x_regulator_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config); +unsigned int apw888x_regulator_dc_of_map_mode(unsigned int mode); +unsigned int apw888x_regulator_ldo_of_map_mode(unsigned int mode); + +static inline int apw888x_regulator_type_is_ldo(struct apw888x_regulator_desc *gd) +{ + return gd->desc.of_map_mode == apw888x_regulator_ldo_of_map_mode; +} + +extern const struct regulator_ops apw888x_regulator_ops; +extern const struct regulator_ops apw888x_regulator_fixed_uV_ops; +extern const struct regulator_ops apw888x_regulator_vfb5_ops; +/* + * apw888x_regulator_set_state - set apw888x suspend state + * + * @rdev: regulator device + * @state: state selection + */ +int apw888x_regulator_set_state(struct regulator_dev *rdev, int state); + +#define APW888X_DC_MODE_MASK (REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST) +#define APW888X_LDO_MODE_MASK (REGULATOR_MODE_NORMAL) + +int apw888x_regulator_register(struct apw888x_regulator_device *regdev, + struct apw888x_regulator_desc *desc); + +int apw888x_regulator_device_generic_suspend(struct apw888x_regulator_device *regdev); +int apw888x_regulator_device_generic_resume(struct apw888x_regulator_device *regdev); +int apw888x_regulator_device_generic_shutdown(struct apw888x_regulator_device *regdev); + +#endif /* __APW888X_REGULATOR_H */ diff --git a/drivers/regulator/virtual-helper.c b/drivers/regulator/virtual-helper.c new file mode 100644 index 000000000000..515b92569ae0 --- /dev/null +++ b/drivers/regulator/virtual-helper.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +static const char *rdev_get_name(struct regulator_dev *rdev) +{ + if (rdev->constraints && rdev->constraints->name) + return rdev->constraints->name; + else if (rdev->desc->name) + return rdev->desc->name; + else + return ""; +} + +static int match_device_parent(struct device *dev, const void *data) +{ + return dev->parent == data; +} + +static struct platform_device * +virt_helper_create_platform_device(struct device *dev) +{ + struct platform_device *pdev; + struct regulator_dev *rdev = dev_to_rdev(dev); + const char *name = rdev_get_name(rdev); + int ret; + char devname[40]; + + snprintf(devname, sizeof(devname), "%s-virt", dev_name(dev)); + + pdev = platform_device_alloc(devname, PLATFORM_DEVID_NONE); + if (!pdev) + return ERR_PTR(-ENOMEM); + + ret = platform_device_add_data(pdev, name, strlen(name) + 1); + if (ret) + goto fail; + + pdev->dev.parent = dev; + ret = platform_device_add(pdev); + if (ret) + goto fail; + + /* add driver_override after platform device added to prevent probe + * immediately. + */ + pdev->driver_override = kstrdup("reg-virt-consumer", GFP_KERNEL); + if (!pdev->driver_override) + dev_warn(dev, "driver_override is not set\n"); + + return pdev; + +fail: + platform_device_put(pdev); + return ERR_PTR(ret); +} + + +static int virt_helper_add_consumer(struct device *dev, + struct class_interface *class_intf) +{ + struct platform_device *pdev; + struct regulator_dev *rdev = dev_to_rdev(dev); + const char *name = rdev_get_name(rdev); + int ret; + + dev_info(dev, "add virtual consumer for '%s'\n", name); + + pdev = virt_helper_create_platform_device(dev); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + dev_err(dev, "failed to create platform device: %d\n", ret); + return ret; + } + return 0; +} + +static void virt_helper_remove_consumer(struct device *dev, + struct class_interface *class_intf) +{ + struct device *res; + struct platform_device *pdev; + + res = bus_find_device(&platform_bus_type, NULL, dev, + match_device_parent); + if (!res) + return; + + pdev = to_platform_device(res); + platform_device_unregister(pdev); +} + +static struct class_interface virt_helper_interface = { + .add_dev = virt_helper_add_consumer, + .remove_dev = virt_helper_remove_consumer, +}; + +static struct class *virt_helper_get_regulator_class(void) +{ + struct regulator *regulator; + struct class *cls; + + regulator = regulator_get(NULL, "regulator-dummy"); + + if (IS_ERR_OR_NULL(regulator)) + return NULL; + cls = regulator->rdev->dev.class; + regulator_put(regulator); + return cls; +} + +static int __init virt_helper_init(void) +{ + struct class *cls; + + cls = virt_helper_get_regulator_class(); + if (!cls) + return -EINVAL; + + virt_helper_interface.class = cls; + return class_interface_register(&virt_helper_interface); +} +module_init(virt_helper_init); + +static void __exit virt_helper_exit(void) +{ + class_interface_unregister(&virt_helper_interface); +} +module_exit(virt_helper_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 147543ad303f..f7e8b332530a 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -247,6 +247,15 @@ config RESET_ZYNQ help This enables the reset controller driver for Xilinx Zynq SoCs. +if SYNO_LSP_RTD1619B +config RESET_RTK_M2TMX + bool "Realtek M2TMX Reset Driver" + depends on OF && MFD_SYSCON + default n + help + This enable Realtek M2TMX Reset Driver + +endif # SYNO_LSP_RTD1619B source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" source "drivers/reset/tegra/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 16947610cc3b..770d56e9dad6 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -34,3 +34,6 @@ obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RESET_RTK_M2TMX) += reset-rtk-m2tmx.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/reset/reset-rtk-m2tmx.c b/drivers/reset/reset-rtk-m2tmx.c new file mode 100644 index 000000000000..dda849325276 --- /dev/null +++ b/drivers/reset/reset-rtk-m2tmx.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019-2020 Realtek Semiconductor Corporatio + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define M2TMX_VE_AXI_ARB_CTRL_0 0x0B0 + +struct m2tmx_reset_controller_dev { + struct device *dev; + struct reset_controller_dev rcdev; + spinlock_t lock; + struct regmap *regmap; + struct clk *clk[RTD1319_M2TMX_RSTN_MAX]; +}; + +static +int rtk_m2tmx_reset_update_bits(struct m2tmx_reset_controller_dev *m2rcdev, + unsigned int offset, unsigned int mask, + unsigned int val) +{ + trace_rtk_pm_reg_update_bits("reset.m2tmx", offset, mask, val); + + return regmap_update_bits(m2rcdev->regmap, offset, mask, val); +} + +static int rtk_m2tmx_reset_reset(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct m2tmx_reset_controller_dev *m2rcdev = container_of(rcdev, + struct m2tmx_reset_controller_dev, rcdev); + unsigned int val = BIT(8 + idx * 2); + unsigned int en = BIT(8 + idx * 2 + 1); + unsigned int mask = val | en; + unsigned long flags; + + dev_dbg(m2rcdev->dev, "reset idx=%lu, en_mask=%x, val_mask=%x\n", idx, + en, val); + + clk_prepare_enable(m2rcdev->clk[idx]); + + spin_lock_irqsave(&m2rcdev->lock, flags); + + rtk_m2tmx_reset_update_bits(m2rcdev, M2TMX_VE_AXI_ARB_CTRL_0, mask, en); + udelay(10); + rtk_m2tmx_reset_update_bits(m2rcdev, M2TMX_VE_AXI_ARB_CTRL_0, mask, val); + + spin_unlock_irqrestore(&m2rcdev->lock, flags); + + clk_disable_unprepare(m2rcdev->clk[idx]); + return 0; +} + +static const struct reset_control_ops rtk_m2tmx_reset_ops = { + .reset = rtk_m2tmx_reset_reset, +}; + +static int rtk_m2tmx_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct m2tmx_reset_controller_dev *m2rcdev; + int ret; + int i; + const char *name; + + m2rcdev = devm_kzalloc(dev, sizeof(*m2rcdev), GFP_KERNEL); + if (!m2rcdev) + return -EINVAL; + + m2rcdev->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, + "realtek,m2tmx"); + if (IS_ERR(m2rcdev->regmap)) { + ret = PTR_ERR(m2rcdev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + + for (i = 0; i < RTD1319_M2TMX_RSTN_MAX; i++) { + name = NULL; + of_property_read_string_index(np, "clock-names", i, &name); + m2rcdev->clk[i] = devm_clk_get(dev, name); + if (IS_ERR(m2rcdev->clk[i])) { + dev_warn(dev, "invalid clocks at index %d: %ld\n", i, PTR_ERR(m2rcdev->clk[i])); + m2rcdev->clk[i] = NULL; + } + } + + m2rcdev->dev = dev; + + spin_lock_init(&m2rcdev->lock); + m2rcdev->rcdev.owner = THIS_MODULE; + m2rcdev->rcdev.nr_resets = RTD1319_M2TMX_RSTN_MAX; + m2rcdev->rcdev.ops = &rtk_m2tmx_reset_ops; + m2rcdev->rcdev.of_node = dev->of_node; + return devm_reset_controller_register(dev, &m2rcdev->rcdev); +} + + +static const struct of_device_id rtk_m2tmx_reset_dt_ids[] = { + { .compatible = "realtek,rtd1319-m2tmx-reset", }, + { /* sentinel */ } +}; + +static struct platform_driver rtk_m2tmx_reset_driver = { + .probe = rtk_m2tmx_reset_probe, + .driver = { + .name = "rtk-m2tmx-reset", + .of_match_table = rtk_m2tmx_reset_dt_ids, + }, +}; +static int __init rtk_m2tmx_reset_init(void) +{ + return platform_driver_register(&rtk_m2tmx_reset_driver); +} +arch_initcall(rtk_m2tmx_reset_init); + diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 33e4ecd6c665..6c6cdaeef899 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1312,6 +1312,15 @@ config RTC_DRV_CROS_EC This driver can also be built as a module. If so, the module will be called rtc-cros-ec. +if SYNO_LSP_RTD1619B +config RTC_DRV_RTK + tristate "Realtek RTC" + depends on ARCH_REALTEK + select MFD_SYSCON + help + Realtek RTC support. + +endif # SYNO_LSP_RTD1619B comment "on-CPU RTC drivers" config RTC_DRV_ASM9260 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index bfb57464118d..1847e057170c 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -183,3 +183,6 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTC_DRV_RTK) += rtc-rtk.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index c633319cdb91..d7ac2c2041f0 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * RTC class driver for "CMOS RTC": PCs, ACPI, etc @@ -1168,9 +1171,25 @@ static u32 rtc_handler(void *context) spin_unlock_irqrestore(&rtc_lock, flags); } +#ifdef MY_ABC_HERE + spin_lock_irqsave(&rtc_lock, flags); + // read to clear irq status + CMOS_READ(RTC_INTR_FLAGS); + rtc_control = CMOS_READ(RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); +#endif /* MY_ABC_HERE */ + pm_wakeup_hard_event(dev); acpi_clear_event(ACPI_EVENT_RTC); +#ifdef MY_ABC_HERE + if (rtc_control & RTC_AIE) { + acpi_enable_event(ACPI_EVENT_RTC, 0); + } else { + acpi_disable_event(ACPI_EVENT_RTC, 0); + } +#else /* MY_ABC_HERE */ acpi_disable_event(ACPI_EVENT_RTC, 0); +#endif /* MY_ABC_HERE */ return ACPI_INTERRUPT_HANDLED; } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 07a9cc91671b..dfc3c46b1f48 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips. @@ -993,6 +996,9 @@ static const struct rtc_class_ops m41txx_rtc_ops = { static const struct chip_desc chips[last_ds_type] = { [ds_1307] = { +#ifdef MY_DEF_HERE + .alarm = 1, +#endif /* MY_DEF_HERE */ .nvram_offset = 8, .nvram_size = 56, }, @@ -1091,6 +1097,9 @@ static const struct i2c_device_id ds1307_id[] = { { "mcp7940x", mcp794xx }, { "mcp7941x", mcp794xx }, { "pt7c4338", ds_1307 }, +#ifdef MY_DEF_HERE + { "pt7c4337", ds_1307 }, +#endif /* MY_DEF_HERE */ { "rx8025", rx_8025 }, { "isl12057", ds_1337 }, { "rx8130", rx_8130 }, diff --git a/drivers/rtc/rtc-rtk.c b/drivers/rtc/rtc-rtk.c new file mode 100644 index 000000000000..c57de8cc8d0d --- /dev/null +++ b/drivers/rtc/rtc-rtk.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017,2019,2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIS_RTCSEC 0x00 +#define MIS_ALMMIN 0x14 +#define MIS_RTCSTOP 0x24 +#define MIS_RTCACR 0x28 +#define MIS_RTCEN 0x2C +#define MIS_RTCCR 0x30 +#define MIS_RTCACR2 0x34 + +struct rtk_rtc_device { + struct rtc_device *rtc; + struct device *dev; + struct regmap *regmap; + void __iomem *base; + unsigned long features; + struct clk *clk; + struct reset_control *rstc; + int irq; + time64_t base_time; + int bias; + spinlock_t lock; +}; + +#define RTK_RTC_HAS_CLK_EN 0x1 +#define RTK_RTC_HAS_RSTC 0x2 +#define RTK_RTK_HAS_BIAS 0x4 + +static inline int rtk_rtc_clk_is_required(struct rtk_rtc_device *rdev) +{ + return !!(rdev->features & RTK_RTC_HAS_CLK_EN); +} + +static inline int rtk_rtc_rstc_is_required(struct rtk_rtc_device *rdev) +{ + return !!(rdev->features & RTK_RTC_HAS_RSTC); +} + +static inline int rtk_rtc_bias_is_supported(struct rtk_rtc_device *rdev) +{ + return !!(rdev->features & RTK_RTK_HAS_BIAS); +} + +static inline int rtk_rtc_reg_read(struct rtk_rtc_device *rdev, + unsigned int offset, unsigned int *val) +{ + *val = readl(rdev->base + offset); + return 0; +} + +static inline int rtk_rtc_reg_bulk_read(struct rtk_rtc_device *rdev, + unsigned int offset, unsigned int *val, + size_t val_count) +{ + int i; + + for (i = 0; i < val_count; i++) + rtk_rtc_reg_read(rdev, offset + i * 4, val + i); + return 0; +} + +static inline int rtk_rtc_reg_write(struct rtk_rtc_device *rdev, + unsigned int offset, unsigned int val) +{ + writel(val, rdev->base + offset); + return 0; +} + +static inline int rtk_rtc_reg_bulk_write(struct rtk_rtc_device *rdev, + unsigned int offset, unsigned int *val, + size_t val_count) +{ + int i; + + for (i = 0; i < val_count; i++) + rtk_rtc_reg_write(rdev, offset + i * 4, *(val + i)); + return 0; +} + +static void rtk_rtc_enable(struct rtk_rtc_device *rdev, int enabled) +{ + rtk_rtc_reg_write(rdev, MIS_RTCEN, enabled ? 0x5A : 0x00); +} + +static inline +int time2reg(struct rtk_rtc_device *rdev, time64_t time, unsigned int *reg) +{ + unsigned int t; + + if (time < rdev->base_time) + return -EINVAL; + + t = time - rdev->base_time; + reg[0] = (t % 60) << 1; + reg[1] = (t / 60) % 60; + reg[2] = (t / 3600) % 24; + reg[3] = (t / 86400) & 0xFF; + reg[4] = (t / 86400) >> 8; + if (reg[4] > 0x3F) + return -EOVERFLOW; + return 0; +} + +static inline +time64_t reg2time(struct rtk_rtc_device *rdev, unsigned int *reg) +{ + time64_t time; + + time = (time64_t)reg[4] * (86400 * 256) + reg[3] * 86400 + + reg[2] * 3600 + reg[1] * 60 + (reg[0] >> 1) + rdev->base_time; + return time; +} + + +static void rtk_rtc_check_rtcacr(struct rtk_rtc_device *rdev) +{ + unsigned long flags; + unsigned int val; + unsigned int reg[5] = { 0 }; + + spin_lock_irqsave(&rdev->lock, flags); + + rtk_rtc_reg_read(rdev, MIS_RTCACR, &val); + if ((val & 0x80) == 0x80) { + spin_unlock_irqrestore(&rdev->lock, flags); + return; + } + + rtk_rtc_reg_write(rdev, MIS_RTCACR, 0x80); + rtk_rtc_reg_write(rdev, MIS_RTCCR, 0x40); + rtk_rtc_reg_write(rdev, MIS_RTCCR, 0x00); + if (rtk_rtc_bias_is_supported(rdev)) + rtk_rtc_reg_write(rdev, MIS_RTCACR2, rdev->bias); + rtk_rtc_reg_bulk_write(rdev, MIS_RTCSEC, reg, 5); + rtk_rtc_enable(rdev, 1); + spin_unlock_irqrestore(&rdev->lock, flags); +} + +static inline +time64_t rtk_rtc_time64_get(struct rtk_rtc_device *rdev) +{ + unsigned int reg[5]; + unsigned long flags; + + spin_lock_irqsave(&rdev->lock, flags); + rtk_rtc_reg_bulk_read(rdev, MIS_RTCSEC, reg, 5); + if (reg[0] == 0) + rtk_rtc_reg_bulk_read(rdev, MIS_RTCSEC, reg, 5); + spin_unlock_irqrestore(&rdev->lock, flags); + + return reg2time(rdev, reg); +} + +static inline +int rtk_rtc_time64_set(struct rtk_rtc_device *rdev, time64_t time) +{ + unsigned long flags; + unsigned int reg[5]; + int ret; + + ret = time2reg(rdev, time, reg); + if (ret) + return ret; + + spin_lock_irqsave(&rdev->lock, flags); + rtk_rtc_enable(rdev, 0); + rtk_rtc_reg_bulk_write(rdev, MIS_RTCSEC, reg, 5); + rtk_rtc_enable(rdev, 1); + spin_unlock_irqrestore(&rdev->lock, flags); + + return 0; +} + +static inline +time64_t rtk_rtc_alarm_time64_get(struct rtk_rtc_device *rdev) +{ + unsigned int reg[5] = { 0 }; + unsigned long flags; + + spin_lock_irqsave(&rdev->lock, flags); + rtk_rtc_reg_bulk_read(rdev, MIS_ALMMIN, reg + 1, 4); + spin_unlock_irqrestore(&rdev->lock, flags); + + return reg2time(rdev, reg); +} + +static inline +int rtk_rtc_alarm_time64_set(struct rtk_rtc_device *rdev, time64_t time) +{ + unsigned long flags; + unsigned int reg[5]; + int ret; + + ret = time2reg(rdev, time, reg); + if (ret) + return ret; + + spin_lock_irqsave(&rdev->lock, flags); + rtk_rtc_reg_bulk_write(rdev, MIS_ALMMIN, reg + 1, 4); + spin_unlock_irqrestore(&rdev->lock, flags); + + return 0; +} + +static int rtk_rtc_alarm_enabled(struct rtk_rtc_device *rdev) +{ + int val; + + regmap_read(rdev->regmap, ISO_RTC, &val); + return val & 0x1; +} + +static void rtk_rtc_alarm_enable(struct rtk_rtc_device *rdev, int enabled) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->lock, flags); + if (enabled) { + regmap_write(rdev->regmap, ISO_RTC, ISO_RTC_ALARM_INT_EN); + } else { + regmap_write(rdev->regmap, ISO_RTC, 0x0); + } + spin_unlock_irqrestore(&rdev->lock, flags); +} + +static int rtk_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rtk_rtc_device *rdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(rtk_rtc_time64_get(rdev), tm); + + dev_dbg(dev, "%s: %04d.%02d.%02d %02d:%02d:%02d", __func__, + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, + tm->tm_min, tm->tm_sec); + + return rtc_valid_tm(tm); +} + +static int rtk_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rtk_rtc_device *rdev = dev_get_drvdata(dev); + + dev_dbg(dev, "%s: %04d.%02d.%02d %02d:%02d:%02d", __func__, + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, + tm->tm_min, tm->tm_sec); + + return rtk_rtc_time64_set(rdev, rtc_tm_to_time64(tm)); +} + +static int rtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rtk_rtc_device *rdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(rtk_rtc_alarm_time64_get(rdev), &alrm->time); + alrm->enabled = rtk_rtc_alarm_enabled(rdev); + return 0; +} + +static int rtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rtk_rtc_device *rdev = dev_get_drvdata(dev); + int ret = 0; + time64_t now; + time64_t alarm_time = rtc_tm_to_time64(&alrm->time); + + rtk_rtc_alarm_enable(rdev, 0); + + if (alrm->time.tm_sec) + alarm_time += 60 - alrm->time.tm_sec; + + now = rtk_rtc_time64_get(rdev); + if (now > alarm_time) + return -EINVAL; + ret = rtk_rtc_alarm_time64_set(rdev, alarm_time); + if (!ret) + rtk_rtc_alarm_enable(rdev, alrm->enabled); + return ret; +} + +static int rtk_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct rtk_rtc_device *rdev = dev_get_drvdata(dev); + + rtk_rtc_alarm_enable(rdev, enabled); + return 0; +} + +static irqreturn_t rtk_rtc_irq_handler(int irq, void *data) +{ + struct platform_device *pdev = data; + struct rtk_rtc_device *rdev = platform_get_drvdata(pdev); + + rtc_update_irq(rdev->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops rtk_rtc_alarm_ops = { + .read_time = rtk_rtc_read_time, + .set_time = rtk_rtc_set_time, + .read_alarm = rtk_rtc_read_alarm, + .set_alarm = rtk_rtc_set_alarm, + .alarm_irq_enable = rtk_rtc_alarm_irq_enable, +}; + +static const struct rtc_class_ops rtk_rtc_ops = { + .read_time = rtk_rtc_read_time, + .set_time = rtk_rtc_set_time, +}; + +static int of_rtk_rtc_get_config(struct device_node *np, + struct rtk_rtc_device *rdev) +{ + unsigned int base_year; + + base_year = 1900; + of_property_read_u32(np, "rtc-base-year", &base_year); + rdev->base_time = mktime64(base_year, 1, 1, 0, 0, 0); + + if (!rtk_rtc_bias_is_supported(rdev)) + return 0; + + rdev->bias = 2; + of_property_read_u32(np, "rtc-bias", &rdev->bias); + return 0; + +} + +static int rtk_rtc_probe(struct platform_device *pdev) +{ + struct rtk_rtc_device *rdev; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct rtc_class_ops *ops = &rtk_rtc_ops; + int ret; + struct resource *res; + + rdev = devm_kzalloc(dev, sizeof(*rdev), GFP_KERNEL); + if (!rdev) + return -ENOMEM; + + rdev->features = (unsigned long)of_device_get_match_data(dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "invalid resource\n"); + return -EINVAL; + } + rdev->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!rdev->base) + return -ENOMEM; + + rdev->regmap = syscon_regmap_lookup_by_phandle(np, "realtek,iso"); + if (IS_ERR(rdev->regmap)) { + ret = PTR_ERR(rdev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + + if (rtk_rtc_clk_is_required(rdev)) { + rdev->clk = devm_clk_get(dev, NULL); + if (IS_ERR(rdev->clk)) { + ret = PTR_ERR(rdev->clk); + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + } + + if (rtk_rtc_rstc_is_required(rdev)) { + rdev->rstc = devm_reset_control_get(dev, NULL); + if (IS_ERR(rdev->rstc)) { + ret = PTR_ERR(rdev->rstc); + dev_err(dev, "failed to get reset control: %d\n", ret); + return ret; + } + } + + of_rtk_rtc_get_config(np, rdev); + spin_lock_init(&rdev->lock); + rdev->dev = dev; + rdev->irq = platform_get_irq(pdev, 0); + + if (rdev->irq > 0) { + ret = devm_request_threaded_irq(dev, rdev->irq, NULL, + rtk_rtc_irq_handler, + IRQF_ONESHOT, dev_name(dev), + pdev); + if (ret) { + dev_err(dev, "failed to request irq%d: %d\n", rdev->irq, + ret); + return ret; + } + + device_init_wakeup(&pdev->dev, true); + ops = &rtk_rtc_alarm_ops; + } + + platform_set_drvdata(pdev, rdev); + reset_control_deassert(rdev->rstc); + clk_prepare_enable(rdev->clk); + + rtk_rtc_check_rtcacr(rdev); + + rdev->rtc = devm_rtc_device_register(&pdev->dev, "rtk-rtc", ops, + THIS_MODULE); + if (IS_ERR(rdev->rtc)) { + ret = PTR_ERR(rdev->rtc); + dev_err(dev, "cannot attach rtc: %d\n", ret); + goto err_nortc; + } + rdev->rtc->uie_unsupported = 1; + + return 0; + +err_nortc: + clk_disable_unprepare(rdev->clk); + if (rdev->rstc) + reset_control_assert(rdev->rstc); + return ret; +} + +static int rtk_rtc_remove(struct platform_device *pdev) +{ + struct rtk_rtc_device *rdev = platform_get_drvdata(pdev); + + clk_disable_unprepare(rdev->clk); + reset_control_assert(rdev->rstc); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id rtk_rtc_ids[] = { + { + .compatible = "realtek,rtd1195-rtc", + .data = (void *)(RTK_RTC_HAS_CLK_EN | RTK_RTC_HAS_RSTC), + }, + { + .compatible = "realtek,rtd1295-rtc", + .data = (void *)(RTK_RTC_HAS_CLK_EN), + }, + { + .compatible = "realtek,rtd1619-rtc", + .data = (void *)(RTK_RTK_HAS_BIAS), + }, + { + .compatible = "realtek,rtd1319-rtc", + .data = (void *)(RTK_RTK_HAS_BIAS), + }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_rtc_ids); + +static struct platform_driver rtk_rtc_driver = { + .probe = rtk_rtc_probe, + .remove = rtk_rtc_remove, + .driver = { + .name = "rtk-rtc", + .of_match_table = rtk_rtc_ids, + }, +}; +module_platform_driver(rtk_rtc_driver); + +MODULE_DESCRIPTION("Realtek Real-time Clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index 03672a246356..d7080da4884e 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Seiko Instruments S-35390A RTC Driver @@ -12,6 +15,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #define S35390A_CMD_STATUS1 0 #define S35390A_CMD_STATUS2 1 @@ -62,6 +68,14 @@ static const struct of_device_id s35390a_of_match[] = { }; MODULE_DEVICE_TABLE(of, s35390a_of_match); +#ifdef MY_ABC_HERE +static const struct acpi_device_id s35390a_acpi_ids[] = { + { "RTC35390", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, s35390a_acpi_ids); +#endif /* MY_ABC_HERE */ + struct s35390a { struct i2c_client *client[8]; struct rtc_device *rtc; @@ -118,7 +132,13 @@ static int s35390a_init(struct s35390a *s35390a) * The 24H bit is kept over reset, so set it already here. */ initialize: +#ifdef MY_ABC_HERE + /* Synology use 12H mode, don't switch to 24H */ + buf = S35390A_FLAG_RESET; +#else /* MY_ABC_HERE */ buf = S35390A_FLAG_RESET | S35390A_FLAG_24H; +#endif /* MY_ABC_HERE */ + ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1); if (ret < 0) @@ -464,10 +484,27 @@ static int s35390a_probe(struct i2c_client *client, return err_read; } +#ifdef MY_ABC_HERE + if (status1 & S35390A_FLAG_24H) { + dev_info(dev, "24H mode !! switch to 12H mode"); + + buf = status1; + buf &= ~S35390A_FLAG_24H; + + err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1); + if (err < 0) { + dev_err(dev, "error to set 12H mode"); + return err; + } + } + + s35390a->twentyfourhour = 0; +#else /* MY_ABC_HERE */ if (status1 & S35390A_FLAG_24H) s35390a->twentyfourhour = 1; else s35390a->twentyfourhour = 0; +#endif /* MY_ABC_HERE */ if (status1 & S35390A_FLAG_INT2) { /* disable alarm (and maybe test mode) */ @@ -504,6 +541,9 @@ static struct i2c_driver s35390a_driver = { .driver = { .name = "rtc-s35390a", .of_match_table = of_match_ptr(s35390a_of_match), +#ifdef MY_ABC_HERE + .acpi_match_table = ACPI_PTR(s35390a_acpi_ids), +#endif /* MY_ABC_HERE */ }, .probe = s35390a_probe, .id_table = s35390a_id, diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index c00e3dd57990..7ddb7f8d9c44 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -158,6 +158,7 @@ obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas/ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o scsi_mod-y += scsi.o hosts.o scsi_ioctl.o \ scsicam.o scsi_error.o scsi_lib.o +scsi_mod-$(CONFIG_SYNO_SCSI_DISK_ERROR_REPORT) += libsyno_report.o scsi_mod-$(CONFIG_SCSI_CONSTANTS) += constants.o scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index a13c203ef7a9..c4881657a807 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -182,6 +182,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, struct beiscsi_endpoint *beiscsi_ep; struct iscsi_endpoint *ep; uint16_t cri_index; + int rc = 0; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) @@ -189,15 +190,17 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, beiscsi_ep = ep->dd_data; - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) { + rc = -EINVAL; + goto put_ep; + } if (beiscsi_ep->phba != phba) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n", beiscsi_ep->phba, phba); - - return -EEXIST; + rc = -EEXIST; + goto put_ep; } cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid); if (phba->conn_table[cri_index]) { @@ -209,7 +212,8 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, beiscsi_ep->ep_cid, beiscsi_conn, phba->conn_table[cri_index]); - return -EINVAL; + rc = -EINVAL; + goto put_ep; } } @@ -226,7 +230,10 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, "BS_%d : cid %d phba->conn_table[%u]=%p\n", beiscsi_ep->ep_cid, cri_index, beiscsi_conn); phba->conn_table[cri_index] = beiscsi_conn; - return 0; + +put_ep: + iscsi_put_endpoint(ep); + return rc; } static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba) diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 21efc73b87be..21828f41478f 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1422,17 +1422,23 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, * Forcefully terminate all in progress connection recovery at the * earliest, either in bind(), send_pdu(LOGIN), or conn_start() */ - if (bnx2i_adapter_ready(hba)) - return -EIO; + if (bnx2i_adapter_ready(hba)) { + ret_code = -EIO; + goto put_ep; + } bnx2i_ep = ep->dd_data; if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) || - (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) + (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) { /* Peer disconnect via' FIN or RST */ - return -EINVAL; + ret_code = -EINVAL; + goto put_ep; + } - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) { + ret_code = -EINVAL; + goto put_ep; + } if (bnx2i_ep->hba != hba) { /* Error - TCP connection does not belong to this device @@ -1443,7 +1449,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data, "belong to hba (%s)\n", hba->netdev->name); - return -EEXIST; + ret_code = -EEXIST; + goto put_ep; } bnx2i_ep->conn = bnx2i_conn; bnx2i_conn->ep = bnx2i_ep; @@ -1460,6 +1467,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, bnx2i_put_rq_buf(bnx2i_conn, 0); bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE); +put_ep: + iscsi_put_endpoint(ep); return ret_code; } diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index ecb134b4699f..506b561670af 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -2690,11 +2690,13 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session, err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid, ppm->tformat.pgsz_idx_dflt); if (err < 0) - return err; + goto put_ep; err = iscsi_conn_bind(cls_session, cls_conn, is_leading); - if (err) - return -EINVAL; + if (err) { + err = -EINVAL; + goto put_ep; + } /* calculate the tag idx bits needed for this conn based on cmds_max */ cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; @@ -2715,7 +2717,9 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session, /* init recv engine */ iscsi_tcp_hdr_recv_prep(tcp_conn); - return 0; +put_ep: + iscsi_put_endpoint(ep); + return err; } EXPORT_SYMBOL_GPL(cxgbi_bind_conn); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index da3920a19d53..b3c1639cc4ac 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * hosts.c Copyright (C) 1992 Drew Eckhardt @@ -43,6 +46,9 @@ #include "scsi_priv.h" #include "scsi_logging.h" +#ifdef MY_ABC_HERE +extern int syno_disk_paraldown_wait(struct device *dev); +#endif /* MY_ABC_HERE */ static int shost_eh_deadline = -1; @@ -58,9 +64,19 @@ static void scsi_host_cls_release(struct device *dev) put_device(&class_to_shost(dev)->shost_gendev); } +#ifdef MY_ABC_HERE +static int syno_scsi_host_shutdown_pre(struct device *dev) +{ + return syno_disk_paraldown_wait(dev); +} +#endif /* MY_ABC_HERE */ + static struct class shost_class = { .name = "scsi_host", .dev_release = scsi_host_cls_release, +#ifdef MY_ABC_HERE + .shutdown_pre = syno_scsi_host_shutdown_pre, +#endif /* MY_ABC_HERE */ }; /** @@ -388,6 +404,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->host_lock = &shost->default_lock; spin_lock_init(shost->host_lock); +#ifdef MY_ABC_HERE + /* + * This special lock is used to power on eunit in deep sleep state. + * The true lock configuration is setup later in ata eh, so we set 0 to eunit_lock_configured here. + */ + shost->peunit_poweron_lock = &shost->eunit_poweron_lock; + spin_lock_init(shost->peunit_poweron_lock); + shost->puiata_eh_flag = &shost->uiata_eh_flag; + shost->uiata_eh_flag = 0; + shost->eunit_lock_configured = 0; + shost->is_eunit_deepsleep = 0; +#endif /* MY_ABC_HERE */ shost->shost_state = SHOST_CREATED; INIT_LIST_HEAD(&shost->__devices); INIT_LIST_HEAD(&shost->__targets); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 30d27b670674..3d4dad9c5888 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * iSCSI lib functions @@ -657,6 +660,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK; struct iscsi_task *task; itt_t itt; +#ifdef MY_ABC_HERE + unsigned long flags; +#endif /* MY_ABC_HERE */ if (session->state == ISCSI_STATE_TERMINATE) return NULL; @@ -743,9 +749,17 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (session->tt->xmit_task(task)) goto free_task; } else { +#ifdef MY_ABC_HERE + spin_lock_irqsave(&conn->taskqueuelock, flags); +#else /* MY_ABC_HERE */ spin_lock_bh(&conn->taskqueuelock); +#endif /* MY_ABC_HERE */ list_add_tail(&task->running, &conn->mgmtqueue); +#ifdef MY_ABC_HERE + spin_unlock_irqrestore(&conn->taskqueuelock, flags); +#else /* MY_ABC_HERE */ spin_unlock_bh(&conn->taskqueuelock); +#endif /* MY_ABC_HERE */ iscsi_conn_queue_work(conn); } @@ -753,9 +767,17 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, free_task: /* regular RX path uses back_lock */ +#ifdef MY_ABC_HERE + spin_lock_irqsave(&session->back_lock, flags); +#else /* MY_ABC_HERE */ spin_lock(&session->back_lock); +#endif /* MY_ABC_HERE */ __iscsi_put_task(task); +#ifdef MY_ABC_HERE + spin_unlock_irqrestore(&session->back_lock, flags); +#else /* MY_ABC_HERE */ spin_unlock(&session->back_lock); +#endif /* MY_ABC_HERE */ return NULL; } diff --git a/drivers/scsi/libsyno_report.c b/drivers/scsi/libsyno_report.c new file mode 100644 index 000000000000..a4d1dc4bdd10 --- /dev/null +++ b/drivers/scsi/libsyno_report.c @@ -0,0 +1,71 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include +#include + +#include "libsyno_report.h" + +#ifdef MY_ABC_HERE +void SynoSendScsiErrorEvent(struct work_struct *work) +{ + struct scsi_device *psdev = + container_of(work, struct scsi_device, sendScsiErrorEventTask); + + if (func_synobios_event_handler && psdev) { + func_synobios_event_handler(SYNO_EVENT_SCSI_ERROR, 4, psdev->scsiErrorEventParm.data[0], + psdev->scsiErrorEventParm.data[1], psdev->scsiErrorEventParm.data[2], psdev->scsiErrorEventParm.data[3]); + } +} + +static inline unsigned int +SynoAssembleScsiSense(u8 sense_key, u8 asc, u8 ascq) +{ + return (((sense_key & 0xFF) << 16) + | ((asc & 0xFF) << 8) | ((ascq & 0xFF))); +} + +void SynoScsiErrorWithSenseReport(struct scsi_device *psdev, + u8 sense_key, u8 asc, u8 ascq, sector_t lba) +{ + int index = -1; + + // For those not physical drive, do not send notity to synobios/scemd + // It will interrupt user with wrong device, eg. iscsi{N}. + if(!SynoIsPhysicalDrive(psdev)) { + return ; + } + index = SynoScsiDeviceToDiskIndex(psdev); + if (0 <= index) { + psdev->scsiErrorEventParm.data[0] = SYNO_SCSI_ERROR_WITH_SENSE; + psdev->scsiErrorEventParm.data[1] = index; + psdev->scsiErrorEventParm.data[2] = + SynoAssembleScsiSense(sense_key, asc, ascq); + psdev->scsiErrorEventParm.data[3] = lba; + schedule_work(&(psdev->sendScsiErrorEventTask)); + } +} + +void SynoScsiTimeoutReport(struct scsi_device *psdev, + unsigned char op, int iRetries) +{ + int index = -1; + + // For those not physical drive, do not send notity to synobios/scemd + // It will interrupt user with wrong device, eg. iscsi{N}. + if(!SynoIsPhysicalDrive(psdev)) { + return ; + } + index = SynoScsiDeviceToDiskIndex(psdev); + if (0 <= index) { + psdev->scsiErrorEventParm.data[0] = SYNO_SCSI_ERROR_TIMEOUT; + psdev->scsiErrorEventParm.data[1] = index; + psdev->scsiErrorEventParm.data[2] = op; + psdev->scsiErrorEventParm.data[3] = iRetries; + schedule_work(&(psdev->sendScsiErrorEventTask)); + } +} +#endif /* MY_ABC_HERE */ + diff --git a/drivers/scsi/libsyno_report.h b/drivers/scsi/libsyno_report.h new file mode 100644 index 000000000000..ff588f949e49 --- /dev/null +++ b/drivers/scsi/libsyno_report.h @@ -0,0 +1,24 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. +#ifndef _SCSI_LIBSYNO_REPORT_H +#define _SCSI_LIBSYNO_REPORT_H +#include + +#ifdef MY_ABC_HERE +int SynoScsiDeviceToDiskIndex(const struct scsi_device *psdev); + +void SynoSendScsiErrorEvent(struct work_struct *work); + +void SynoScsiErrorWithSenseReport(struct scsi_device *psdev, + u8 sense_key, u8 asc, u8 ascq, sector_t lba); + +void SynoScsiTimeoutReport(struct scsi_device *psdev, + unsigned char op, int iRetries); + +bool SynoIsPhysicalDrive(const struct scsi_device *psdev); +#endif /* MY_ABC_HERE */ + +#endif /* _SCSI_LIBSYNO_REPORT_H */ + diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index f51723e2d522..013278182c4b 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -387,6 +387,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, struct qedi_ctx *qedi = iscsi_host_priv(shost); struct qedi_endpoint *qedi_ep; struct iscsi_endpoint *ep; + int rc = 0; ep = iscsi_lookup_endpoint(transport_fd); if (!ep) @@ -394,11 +395,16 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, qedi_ep = ep->dd_data; if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) || - (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) - return -EINVAL; + (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) { + rc = -EINVAL; + goto put_ep; + } + + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) { + rc = -EINVAL; + goto put_ep; + } - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; qedi_ep->conn = qedi_conn; qedi_conn->ep = qedi_ep; @@ -408,13 +414,18 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session, qedi_conn->cmd_cleanup_req = 0; qedi_conn->cmd_cleanup_cmpl = 0; - if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) - return -EINVAL; + if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) { + rc = -EINVAL; + goto put_ep; + } + spin_lock_init(&qedi_conn->tmf_work_lock); INIT_LIST_HEAD(&qedi_conn->tmf_work_list); init_waitqueue_head(&qedi_conn->wait_queue); - return 0; +put_ep: + iscsi_put_endpoint(ep); + return rc; } static int qedi_iscsi_update_conn(struct qedi_ctx *qedi, diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2c23b692e318..dac4129885d7 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -3237,6 +3237,7 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, conn = cls_conn->dd_data; qla_conn = conn->dd_data; qla_conn->qla_ep = ep->dd_data; + iscsi_put_endpoint(ep); return 0; } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 9a8f9f902f3b..df7b11f913a1 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include @@ -635,7 +638,11 @@ static int devinfo_seq_show(struct seq_file *m, void *v) devinfo_table->name) seq_printf(m, "[%s]:\n", devinfo_table->name); +#ifdef MY_ABC_HERE + seq_printf(m, "'%.8s' '%."SYNO_DISK_MODEL_LEN"s' 0x%llx\n", +#else /* MY_ABC_HERE */ seq_printf(m, "'%.8s' '%.16s' 0x%llx\n", +#endif /* MY_ABC_HERE */ devinfo->vendor, devinfo->model, devinfo->flags); return 0; } diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f11f51e2465f..d892e7765b7f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * scsi_error.c Copyright (C) 1997 Eric Youngdale @@ -45,11 +48,21 @@ #include "scsi_priv.h" #include "scsi_logging.h" #include "scsi_transport_api.h" +#ifdef MY_ABC_HERE +#include "libsyno_report.h" +#endif /* MY_ABC_HERE */ #include #include +#ifdef MY_ABC_HERE +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_NOTICE +#endif +#endif /* MY_ABC_HERE */ + static void scsi_eh_done(struct scsi_cmnd *scmd); /* @@ -279,6 +292,36 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) call_rcu(&scmd->rcu, scsi_eh_inc_host_failed); } +#ifdef MY_ABC_HERE +static inline bool +SynoTimeoutCmdNeedReport(unsigned char op) +{ + return op == READ_6 || op == WRITE_6 || + op == READ_10 || op == WRITE_10 || + op == READ_12 || op == WRITE_12 || + op == READ_16 || op == WRITE_16 || + SYNCHRONIZE_CACHE || SYNCHRONIZE_CACHE_16; +} + +static void +SynoScsiTimeout(struct scsi_cmnd *scsi_cmd) +{ + if (NULL == scsi_cmd || NULL == scsi_cmd->device + || NULL == scsi_cmd->cmnd) { + printk(KERN_ERR "%s:%s(%d) Ivalid scsi_cmd format", + __FILE__, __FUNCTION__, __LINE__); + goto END; + } + if (!SynoTimeoutCmdNeedReport(scsi_cmd->cmnd[0])) { + goto END; + } + SynoScsiTimeoutReport(scsi_cmd->device, + scsi_cmd->cmnd[0], scsi_cmd->retries); +END: + return; +} +#endif /* MY_ABC_HERE */ + /** * scsi_times_out - Timeout function for normal scsi commands. * @req: request that is timing out. @@ -319,6 +362,12 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) */ if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state)) return BLK_EH_RESET_TIMER; + +#ifdef MY_ABC_HERE + /* record timeout event */ + SynoScsiTimeout(scmd); +#endif /* MY_ABC_HERE */ + if (scsi_abort_command(scmd) != SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); scsi_eh_scmd_add(scmd); diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 14872c9dc78c..99622282588d 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Changes: @@ -26,6 +29,13 @@ #include "scsi_logging.h" +#ifdef MY_ABC_HERE +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_NOTICE +#endif +#endif /* MY_ABC_HERE */ + #define NORMAL_RETRIES 5 #define IOCTL_NORMAL_TIMEOUT (10 * HZ) @@ -103,6 +113,15 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, if (driver_byte(result) == DRIVER_SENSE && scsi_sense_valid(&sshdr)) { +#ifdef MY_ABC_HERE + if (START_STOP == cmd[0]) { + if (0 == sdev->nospindown) { + sdev->nospindown = 1; + printk(KERN_WARNING"host %d, id %d, lun %lld, does not support spindown\n", + sdev->host->host_no, sdev->id, sdev->lun); + } + } +#endif /* MY_ABC_HERE */ switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d89db29fa829..f076a92a4876 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 1999 Eric Youngdale @@ -40,6 +43,33 @@ #include "scsi_priv.h" #include "scsi_logging.h" +#ifdef MY_ABC_HERE +#include "libsyno_report.h" +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#include "scsi_transport_api.h" +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_NOTICE +#endif +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SYNO_SMART_CMD_TIMEOUT 30 * HZ +#endif /* MY_ABC_HERE */ + /* * Size of integrity metadata is usually small, 1 inline sg should * cover normal cases. @@ -262,7 +292,17 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, rq->cmd_len = COMMAND_SIZE(cmd[0]); memcpy(rq->cmd, cmd, rq->cmd_len); rq->retries = retries; +#ifdef MY_ABC_HERE + req->timeout = ((sdev->scmd_timeout_sec*HZ) > timeout ? (sdev->scmd_timeout_sec*HZ) : timeout); + // Set smart command timeout at least 30s + if ((ATA_CMD_SMART == rq->cmd[0] || + (ATA_16 == rq->cmd[0] && ATA_CMD_SMART == rq->cmd[14])) && + SYNO_SMART_CMD_TIMEOUT > req->timeout) { + req->timeout = SYNO_SMART_CMD_TIMEOUT; + } +#else /* MY_ABC_HERE */ req->timeout = timeout; +#endif /* MY_ABC_HERE */ req->cmd_flags |= flags; req->rq_flags |= rq_flags | RQF_QUIET; @@ -559,6 +599,66 @@ static void scsi_run_queue_async(struct scsi_device *sdev) } } +#ifdef MY_DEF_HERE +static void SynoSpinupDone(struct request *req, blk_status_t status) +{ + struct scsi_device *sdev = req->q->queuedata; + + blk_put_request(req); + + SynoSpinupEnd(sdev); +} + +extern struct workqueue_struct *spinup_workqueue; +void SynoQueueSpinupReq (struct scsi_device *sdev) +{ + if (spinup_workqueue) { + queue_work(spinup_workqueue, &sdev->spinup_work); + } else { + schedule_work(&sdev->spinup_work); + } +} + +void SynoSubmitSpinupReq(struct work_struct *work) +{ + struct request *req; + struct scsi_request *rq; + struct scsi_device *sdev; + + sdev = container_of(work, struct scsi_device, spinup_work); + + req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, BLK_MQ_REQ_PM); + if (IS_ERR(req)) { + SynoQueueSpinupReq(sdev); + printk(KERN_ERR "%s: Can't get request, retry it", __FUNCTION__); + return; + } + + rq = scsi_req(req); + + rq->cmd[0] = START_STOP; + rq->cmd[1] = 0; + rq->cmd[2] = 0; + rq->cmd[3] = 0; + rq->cmd[4] = 1; /* START */ + rq->cmd[5] = 0; + + rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); + + req->rq_flags |= RQF_PM | RQF_QUIET; + req->timeout = 60 * HZ; + rq->retries = 5; + + blk_execute_rq_nowait(req->q, NULL, req, 1, SynoSpinupDone); +} +static void SynoSpinupDisk(struct scsi_device *device) +{ + if (SynoSpinupBegin(device)) { + SynoQueueSpinupReq(device); + } +} +#endif /* MY_DEF_HERE */ + /* Returns false when no more bytes to process, true if there are more */ static bool scsi_end_request(struct request *req, blk_status_t error, unsigned int bytes) @@ -673,6 +773,270 @@ static bool scsi_cmd_runtime_exceeced(struct scsi_cmnd *cmd) return false; } +#ifdef MY_ABC_HERE +static inline bool +SynoCmdNeedReport(unsigned char op) +{ + return op == READ_6 || op == WRITE_6 || + op == READ_10 || op == WRITE_10 || + op == READ_12 || op == WRITE_12 || + op == READ_16 || op == WRITE_16; +} + +static void +SynoScsiErrorCheck(struct scsi_cmnd *scsi_cmd, + struct scsi_sense_hdr *psshdr) +{ + sector_t badLba = 0; + if (NULL == scsi_cmd || NULL == scsi_cmd->device + || NULL == scsi_cmd->sense_buffer || NULL == scsi_cmd->cmnd + || NULL == psshdr) { + printk("%s:%s(%d) Ivalid scsi_cmd format", + __FILE__, __FUNCTION__, __LINE__); + goto END; + } + if (!SynoCmdNeedReport(scsi_cmd->cmnd[0])) { + goto END; + } + switch (psshdr->sense_key) { + case MEDIUM_ERROR: + /* FALLTHROUGH */ + case HARDWARE_ERROR: + if (0 == scsi_get_sense_info_fld(scsi_cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, (u64*) &badLba)) { + printk("%s:%s(%d) sense info in sense data invalid\n", + __FILE__, __FUNCTION__, __LINE__); + goto END; + } + SynoScsiErrorWithSenseReport(scsi_cmd->device, + psshdr->sense_key, psshdr->asc, psshdr->ascq, badLba); + break; + default: + // We only report MEDIUM_ERROR and HARDWARE_ERROR + goto END; + } + +END: + return; +} +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern unsigned char +syno_is_sector_need_auto_remap(struct gendisk *disk, sector_t lba); +#ifdef MY_ABC_HERE +extern void syno_req_set_bio_auto_remap_flag(struct request *req, sector_t lba); +#endif /* MY_ABC_HERE */ + +static void +syno_scsi_do_remap_done(struct request *req, blk_status_t status) +{ + blk_put_request(req); +} + +static unsigned int +syno_scsi_do_remap(struct scsi_cmnd *scsi_cmd, sector_t badLba) +{ + unsigned int iRet = -1, iCheck = 0, i = 0; + unsigned int uSectors = 0; + struct request_queue *q = NULL; + struct scsi_request *rq; + + u8 lbal = 0; + size_t size = 0; + struct scsi_device *device = NULL; + struct request *req = NULL; + char *buf = NULL, *p = NULL; + + if (scsi_cmd == NULL) { + pr_warn("%s:%s(%d) Failed to get scsi_cmd", __FILE__, __func__, __LINE__); + goto OUT; + } + + device = scsi_cmd->device; + if (device == NULL) { + pr_warn("%s:%s(%d) Failed to get device", __FILE__, __func__, __LINE__); + goto OUT; + } + + q = device->request_queue; + if (q == NULL) { + pr_warn("%s:%s(%d) Failed to get request_queue\n", __FILE__, __func__, __LINE__); + goto OUT; + } + + uSectors = queue_physical_block_size(q) / queue_logical_block_size(q); + lbal = (u8)(badLba & 0xff); + lbal = (lbal & (~(uSectors - 1))); // move lbal to first logical block of physical block + size = SYNO_SCSI_SECT_SIZE * uSectors; + + req = blk_get_request(q, WRITE, BLK_MQ_REQ_NOWAIT); + if (IS_ERR(req)) { + pr_warn("%s:%s(%d) Failed to get request\n", __FILE__, __func__, __LINE__); + goto ERR; + } + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) { + pr_warn("%s:%s(%d) Failed to allocate remap page memory, so use zero page instead.\n", + __FILE__, __func__, __LINE__); + p = page_address(ZERO_PAGE(0)); + } else { + syno_draw_auto_remap_buffer(buf, size); + p = buf; + } + + rq = scsi_req(req); + //16 types write + rq->cmd[0] = WRITE_16; + rq->cmd[1] = 0; + // lba + rq->cmd[2] = (u8)((badLba & 0xff00000000000000) >> 56); + rq->cmd[3] = (u8)((badLba & 0xff000000000000) >> 48); + rq->cmd[4] = (u8)((badLba & 0xff0000000000) >> 40); + rq->cmd[5] = (u8)((badLba & 0xff00000000) >> 32); + rq->cmd[6] = (u8)((badLba & 0xff000000) >> 24); + rq->cmd[7] = (u8)((badLba & 0xff0000) >> 16); + rq->cmd[8] = (u8)((badLba & 0xff00) >> 8); + rq->cmd[9] = lbal; + // sector counts + rq->cmd[10] = (u8)((uSectors & 0xff000000) >> 24); + rq->cmd[11] = (u8)((uSectors & 0xff0000) >> 16); + rq->cmd[12] = (u8)((uSectors & 0xff00) >> 8); + rq->cmd[13] = (u8)(uSectors & 0xff); + + rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); + req->cmd_flags = REQ_OP_SCSI_OUT; + req->rq_flags |= RQF_QUIET; + req->timeout = 60 * HZ; + rq->retries = 0; + + iCheck = blk_rq_map_kern(q, req, p, size, GFP_DMA | GFP_KERNEL); + if (iCheck) { + pr_warn("%s:%s(%d) blk_rq_map_kern return != 0\n", + __FILE__, __func__, __LINE__); + goto ERR; + } + + sdev_printk(KERN_WARNING, device, "Insert write command :"); + for (i = 0; i < rq->cmd_len; ++i) + pr_warn("%02x ", rq->cmd[i]); + pr_info("\n"); + + blk_execute_rq_nowait(q, NULL, req, 1, syno_scsi_do_remap_done); + + iRet = 0; + goto OUT; +ERR: + if (!IS_ERR(req)) + blk_put_request(req); + kfree(buf); + buf = NULL; +OUT: + return iRet; +} + +static int +syno_scsi_check_ncq_fake_unc(const u8 *sense_buffer, int iSbLen) +{ + int iRet = 0; + const u8 *desc = NULL; + u8 format = 0; + + if (iSbLen < 7) + goto OUT; + + format = 0x7f & sense_buffer[0]; + if (format == 0x72 || format == 0x73) { + desc = scsi_sense_desc_find(sense_buffer, iSbLen, 0 /* info desc */); + if (desc && (desc[1] == 0xa)) + iRet = SYNO_NCQ_FAKE_UNC & desc[SYNO_DESCRIPTOR_RESERVED_INDEX]; + } +OUT: + return iRet; +} + +static unsigned int +syno_scsi_writes_sector(struct scsi_cmnd *scsi_cmd) +{ + unsigned int iRet = -1, iCheck = 0; + sector_t badLba = 0; + u8 blIsWrite = 0; + struct gendisk *gd = NULL; + + if (scsi_cmd == NULL) { + pr_warn("%s:%s(%d) Failed to get scsi_cmd", __FILE__, __func__, __LINE__); + goto ERR; + } + + if (scsi_cmd->request == NULL) { + pr_warn("%s:%s(%d) Failed to get scsi_cmd request\n", + __FILE__, __func__, __LINE__); + goto ERR; + } + + if (scsi_cmd->sense_buffer == NULL) { + pr_warn("%s:%s(%d) Failed to get scsi_cmd sense_buffer\n", + __FILE__, __func__, __LINE__); + goto ERR; + } + + if (scsi_cmd->cmnd == NULL) { + pr_warn("%s:%s(%d) Failed to get scsi_cmd cmnd\n", __FILE__, __func__, __LINE__); + goto ERR; + } + + gd = scsi_cmd->request->rq_disk; + if (!gd) { + pr_warn("%s:%s(%d) Failed to get general disk\n", __FILE__, __func__, __LINE__); + goto ERR; + } + + iCheck = scsi_get_sense_info_fld(scsi_cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + (u64 *) &badLba); + if (!iCheck) { + pr_warn("%s:%s(%d) sense info in sense data invalid\n", + __FILE__, __func__, __LINE__); + goto ERR; + } + + if (syno_scsi_check_ncq_fake_unc(scsi_cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE)) { + scmd_printk(KERN_INFO, scsi_cmd, "UNC ERROR code but NCQ abort, do NOT remap"); + goto ERR; + } + + switch (scsi_cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case WRITE_32: + blIsWrite = 1; + break; + default: + if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) + blIsWrite = 1; + } + + scmd_printk(KERN_INFO, scsi_cmd, "%s unc at %llu\n", + (blIsWrite) ? "write" : "read", + (unsigned long long)badLba); + + if (!blIsWrite && !syno_is_sector_need_auto_remap(gd, badLba)) + goto ERR; + +#ifdef MY_ABC_HERE + // only report auto-remap in read + if (!blIsWrite) + syno_req_set_bio_auto_remap_flag(scsi_cmd->request, badLba); +#endif /* MY_ABC_HERE */ + + syno_scsi_do_remap(scsi_cmd, badLba); + iRet = 0; +ERR: + return iRet; +} +#endif /* MY_ABC_HERE */ + /* Helper for scsi_io_completion() when special action required. */ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) { @@ -692,6 +1056,16 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) blk_stat = scsi_result_to_blk_status(cmd, result); +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + if (0x1b == cmd->cmnd[0]) { + sdev_printk(KERN_ERR, cmd->device, + "START_STOP done - tag %02x %s - %02x %02x %02x %02x %02x %02x\n", + cmd->tag, (cmd->cmnd[4]&0x01)?"START":"STOP ", + cmd->cmnd[0], cmd->cmnd[1], cmd->cmnd[2], + cmd->cmnd[3], cmd->cmnd[4], cmd->cmnd[5]); + } +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + if (host_byte(result) == DID_RESET) { /* Third party bus reset or reset for error recovery * reasons. Just retry the command and see what @@ -753,6 +1127,21 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) */ if (sshdr.asc == 0x04) { switch (sshdr.ascq) { +#ifdef MY_DEF_HERE + case 0x02: /* INITIALIZING COMMAND REQUIRED */ + action = ACTION_FAIL; + if ((cmd->cmnd[0] != TEST_UNIT_READY) && (cmd->cmnd[0] != REQUEST_SENSE)) { + /* + * Leave TUR & REQUEST_SENSE results untouched for upper layers + * Only spin up on read/write commands + */ + if (cmd->device->spinup_queue) { + SynoSpinupDisk(cmd->device); + action = ACTION_DELAYED_RETRY; + } + } + break; +#endif /* MY_DEF_HERE */ case 0x01: /* becoming ready */ case 0x04: /* format in progress */ case 0x05: /* rebuild in progress */ @@ -779,6 +1168,28 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) /* See SSC3rXX or current. */ action = ACTION_FAIL; break; +#ifdef MY_ABC_HERE + case MEDIUM_ERROR: + switch (sshdr.asc) { + case 0x11: + switch (sshdr.ascq) { + case 0x00: + case 0x04: + case 0x14: + syno_scsi_writes_sector(cmd); + action = ACTION_FAIL; + break; + default: + action = ACTION_FAIL; + break; + } + break; + default: + action = ACTION_FAIL; + break; + } + break; +#endif /* MY_ABC_HERE */ case DATA_PROTECT: action = ACTION_FAIL; if ((sshdr.asc == 0x0C && sshdr.ascq == 0x12) || @@ -792,6 +1203,9 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) action = ACTION_FAIL; break; } +#ifdef MY_ABC_HERE + SynoScsiErrorCheck(cmd, &sshdr); +#endif /* MY_ABC_HERE */ } else action = ACTION_FAIL; @@ -875,6 +1289,7 @@ static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result, */ *blk_statp = scsi_result_to_blk_status(cmd, result); } + /* * Recovered errors need reporting, but they're always treated as * success, so fiddle the result code here. For passthrough requests @@ -959,6 +1374,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) "%u sectors total, %d bytes done.\n", blk_rq_sectors(req), good_bytes)); + /* * Failed, zero length commands always need to drop down * to retry code. Fast path should return in this block. @@ -1458,6 +1874,103 @@ static void scsi_softirq_done(struct request *rq) } } +#ifdef MY_DEF_HERE +extern int g_is_sas_model; +static int scsi_white_list_cmd_in_hibernation(struct scsi_cmnd *cmd) +{ + int ret = 0; + + switch (cmd->cmnd[0]) { + /* Only spin up on read/write commands */ + case TEST_UNIT_READY: + case REQUEST_SENSE: + case START_STOP: + /*sas standby cmd*/ + ret = 1; + break; + case ATA_16: + /*ata passthrough standby immediate*/ + if (g_is_sas_model && (0xe0 == cmd->cmnd[14])) { + ret = 1; + } + break; + default: + break; + } + + return ret; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static int cmd_in_ignore_list(struct scsi_cmnd *cmd) +{ +#ifdef MY_ABC_HERE + /* Ignore EUnit control command */ + if (cmd->device->spindown && ATA_16 == cmd->cmnd[0] && + (ATA_CMD_PMP_WRITE == cmd->cmnd[14] || ATA_CMD_PMP_READ == cmd->cmnd[14])) { + return 1; + } +#endif /* MY_ABC_HERE */ + + /* this is for SATA disk only, in SATA disk, we don't know which command to wake up disk + * so we need spindown to help us to remember whichever disk is sleeping + * So if disk is sleeping, then we assume any command will wake up this disk, and update the idle time */ + if (cmd->device->spindown && TEST_UNIT_READY != cmd->cmnd[0]) { + cmd->device->spindown = 0; + if (0 == cmd->device->do_standby_syncing) { + return 0; + } + } + + /* generally, we should assume all commands should wake up disk and idle time should be reset, + * but we need to check smart(0x0C & ATA_16) in scemd loop and sync cache before call disk to sleep + * so we must skip these commands here, and we also skip TEST_UNIT_READY, LOG_SENSE, and START_STOP for SAS disks */ + /* mvSata */ + if (0x0C == cmd->cmnd[0]) { + struct scatterlist *sg; + unsigned char* pBuffer; + + if (cmd->sdb.table.nents) { + sg = (struct scatterlist *)cmd->sdb.table.sgl; + pBuffer = kmap_atomic(sg_page(sg)) + sg->offset; + } else { + pBuffer = (char *)cmd->sdb.table.sgl; + } + + /* set disk to standby command */ + if (0xE0 == pBuffer[0]) { + cmd->device->spindown = 1; + } + + if (cmd->sdb.table.nents) { + kunmap_atomic(pBuffer - sg->offset); + } + } else if (ATA_16 == cmd->cmnd[0]) { + /* set disk to standby command */ + if (0xE0 == cmd->cmnd[14]) { + cmd->device->spindown = 1; + } + } else if (START_STOP == cmd->cmnd[0]) { + if (0x01 == cmd->cmnd[4]) { + // start disks + if (0 == cmd->device->do_standby_syncing) { + return 0; + } + } + } else if (LOG_SENSE != cmd->cmnd[0] && + TEST_UNIT_READY != cmd->cmnd[0] && + SYNCHRONIZE_CACHE != cmd->cmnd[0]) { + + if (0 == cmd->device->do_standby_syncing) { + return 0; + } + } + + return 1; +} +#endif /* MY_ABC_HERE */ + /** * scsi_dispatch_command - Dispatch a command to the low-level driver. * @cmd: command block we are dispatching. @@ -1469,6 +1982,10 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; int rtn = 0; +#ifdef MY_ABC_HERE + unsigned long ulflags; + struct Scsi_Host *pMaster_host = NULL; +#endif /* MY_ABC_HERE */ atomic_inc(&cmd->device->iorequest_cnt); @@ -1495,6 +2012,20 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) return SCSI_MLQUEUE_DEVICE_BUSY; } +#ifdef MY_DEF_HERE + if (g_is_sas_model && (SYNO_PORT_TYPE_SAS == cmd->device->host->hostt->syno_port_type)) { + if ((START_STOP == cmd->cmnd[0] && (0 == (cmd->cmnd[4] & 0x01)))/*sas standby cmd*/ || + ((ATA_16 == cmd->cmnd[0]) && (0xe0 == cmd->cmnd[14]))/*ata passthrough standby immediate*/) { + set_bit(0, &cmd->device->sas_sata_standby_flag); + } + + if (test_bit(0, &cmd->device->sas_sata_standby_flag) && !scsi_white_list_cmd_in_hibernation(cmd)) { + SynoSpinupDisk(cmd->device); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + } +#endif /* MY_DEF_HERE */ + /* Store the LUN value in cmnd, if needed. */ if (cmd->device->lun_in_cdb) cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | @@ -1521,6 +2052,51 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) } +#ifdef MY_ABC_HERE + /* + * Power on eunit from deep sleep will fail after another ata command is dispatched, + * so NO ata commands sent to the same eunit can be further dispatched until error handler is done. + */ + if (host->transportt->is_eunit_deepsleep && host->is_eunit_deepsleep && host->eunit_lock_configured){ + spin_lock_irqsave(host->peunit_poweron_lock, ulflags); + if (*(host->puiata_eh_flag)) { + spin_unlock_irqrestore(host->peunit_poweron_lock, ulflags); + return SCSI_MLQUEUE_HOST_BUSY; + } + (*(host->puiata_eh_flag)) ++; + spin_unlock_irqrestore(host->peunit_poweron_lock, ulflags); + if ((pMaster_host = host->transportt->is_eunit_deepsleep(host))) { + /* Need to power on and reset the port by EH. */ + scsi_schedule_eh(host); + } + (*(host->puiata_eh_flag)) --; + } +#endif /* MY_ABC_HERE */ + +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + /* print out START_STOP commands */ + if (0x1b == cmd->cmnd[0]) { + sdev_printk(KERN_ERR, cmd->device, + "START_STOP run - tag %02x %s - %02x %02x %02x %02x %02x %02x\n", + cmd->tag, (cmd->cmnd[4]&0x01)?"START":"STOP ", + cmd->cmnd[0], cmd->cmnd[1], cmd->cmnd[2], + cmd->cmnd[3], cmd->cmnd[4], cmd->cmnd[5]); + } +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + +#ifdef MY_ABC_HERE + if(cmd_in_ignore_list(cmd)){ + goto IGNORE; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + cmd->device->last_accessed = jiffies; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +IGNORE: +#endif /* MY_ABC_HERE */ trace_scsi_dispatch_cmd_start(cmd); rtn = host->hostt->queuecommand(host, cmd); if (rtn) { diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index 8ea44c6595ef..bd75298f9d07 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * scsi_logging.c @@ -15,6 +18,13 @@ #include #include +#ifdef MY_ABC_HERE +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_NOTICE +#endif +#endif /* MY_ABC_HERE */ + static char *scsi_log_reserve_buffer(size_t *len) { *len = 128; diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index d6982d355739..8fd2c0c6087d 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/drivers/scsi/scsi_proc.c @@ -196,7 +199,11 @@ static int proc_print_scsidevice(struct device *dev, void *data) } seq_puts(s, " Model: "); +#ifdef MY_ABC_HERE + for (i = 0; i < SYNO_DISK_MODEL_NUM; i++) { +#else /* MY_ABC_HERE */ for (i = 0; i < 16; i++) { +#endif /* MY_ABC_HERE */ if (sdev->model[i] >= 0x20) seq_putc(s, sdev->model[i]); else diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 9af50e6f94c4..78534ca583a3 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * scsi_scan.c @@ -49,6 +52,40 @@ #include "scsi_priv.h" #include "scsi_logging.h" +#ifdef MY_ABC_HERE +#include "libsyno_report.h" +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#define to_ata_port(d) container_of(d, struct ata_port, tdev) +extern u8 syno_is_synology_pm(const struct ata_port *ap); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SYNO_INQUIRY_TMP_LEN 32 +#define SZ_STAT_DISK_VENDOR "ATA " +#define SYNO_INQUIRY_VENDOR_LEN 8 +typedef struct _tag_SYNO_DISK_VENDOR { + const char *szName; /* name of vendor, or NULL for list end */ + const int iLength; /* length of vendor */ +} SYNO_DISK_VENDOR; + +SYNO_DISK_VENDOR gDiskVendor[] = { + {"OCZ", 3}, + {"Crucial", 7}, + {"Micron", 6}, + {"MICRON", 6}, + {NULL, 0} +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SYNO_RESULT_LEN 512 +/* The IDENTIFY DEVICE command will get most 40 characters */ +#define SYNO_IDENTIFY_DEVICE_TMP_LEN 40 +extern int syno_get_ata_identity(struct scsi_device *sdev, u16 *id); +#endif /* MY_ABC_HERE */ #define ALLOC_FAILURE_MSG KERN_ERR "%s: Allocation failure during" \ " SCSI scanning, some SCSI devices might not be configured\n" @@ -218,6 +255,9 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, struct scsi_device *sdev; int display_failure_msg = 1, ret; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); +#ifdef MY_DEF_HERE + extern void SynoSubmitSpinupReq(struct work_struct *work); +#endif /* MY_DEF_HERE */ sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, GFP_KERNEL); @@ -225,7 +265,10 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, goto out; sdev->vendor = scsi_null_device_strs; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ sdev->model = scsi_null_device_strs; +#endif /* !MY_ABC_HERE */ sdev->rev = scsi_null_device_strs; sdev->host = shost; sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; @@ -242,6 +285,17 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, mutex_init(&sdev->inquiry_mutex); INIT_WORK(&sdev->event_work, scsi_evt_thread); INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue); +#ifdef MY_DEF_HERE + INIT_WORK(&sdev->spinup_work, SynoSubmitSpinupReq); + INIT_LIST_HEAD(&sdev->spinup_list); + sdev->spinup_in_process = 0; + sdev->spinup_timer = 0; + sdev->spinup_queue = NULL; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + INIT_WORK(&sdev->sendScsiErrorEventTask, SynoSendScsiErrorEvent); + memset(&sdev->scsiErrorEventParm, 0, sizeof(sdev->scsiErrorEventParm)); +#endif /* MY_ABC_HERE */ sdev->sdev_gendev.parent = get_device(&starget->dev); sdev->sdev_target = starget; @@ -294,6 +348,10 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, } } +#ifdef MY_DEF_HERE + sdev->sas_sata_standby_flag = 0; +#endif /* MY_DEF_HERE */ + return sdev; out_device_destroy: @@ -514,6 +572,208 @@ void scsi_target_reap(struct scsi_target *starget) scsi_target_reap_ref_put(starget); } +#ifdef MY_ABC_HERE +/** + * ssyno_standard_inquiry_strin - refine the vendor and model strings of SATA disks + * @szInqStr: INQUIRY result string to be refined + * @uiLen: length of the string + * + * Description: + * The result of INQUIRY from a SATA disk might set vendor as "ATA" + * and set model as "vendor model." This would confuse the userspace + * applications. + * This function refines the INQUIRY result of SATA disks to correctly + * fill the vendor and model entries. This function resets the result + * string and parses the original model string and fills the correct + * data into each entry. + **/ +static void syno_standard_inquiry_string(unsigned char *szInqStr, unsigned int uiLen) +{ + char szRevStr[4] = {'\0'}; + char szTmpStr[SYNO_INQUIRY_TMP_LEN] = {'\0'}; + int iCharIdx; + int blPreIsSpace = 0, blSegmented = 0; + int blSpecialVendor = 0; + int i = 0; + + if (NULL == szInqStr || 0 == uiLen) { + goto END; + } + + if (uiLen > SYNO_INQUIRY_TMP_LEN) { + uiLen = SYNO_INQUIRY_TMP_LEN; + } + + memcpy(szRevStr, szInqStr + uiLen - 4, 4); + memcpy(szTmpStr, szInqStr + 8, uiLen - 4 - 8); + + for (i = 0; NULL != gDiskVendor[i].szName; i++) { + if (!strncmp(gDiskVendor[i].szName, szTmpStr, gDiskVendor[i].iLength)) { + blSpecialVendor = 1; + break; + } + } + + if (1 == blSpecialVendor) { + iCharIdx = gDiskVendor[i].iLength; + } else { + for (iCharIdx = 0; iCharIdx < sizeof(szTmpStr); iCharIdx++) { + if ('\0' == szTmpStr[iCharIdx]) { + break; + } + + if (' ' == szTmpStr[iCharIdx]) { + blPreIsSpace = 1; + } else { + if (blPreIsSpace) { + blSegmented = 1; + break; + } + } + } + + if (!blSegmented) { + goto END; + } + } + + memset(szInqStr, 0, uiLen); + + memcpy(szInqStr, szTmpStr, iCharIdx); + memcpy(szInqStr + 8, szTmpStr + iCharIdx, strlen(szTmpStr) - iCharIdx); + memcpy(szInqStr + (uiLen - 4), szRevStr, 4); +END: + return; +} + +/** + * syno_standard_vendor_string - refine the vendor strings of SATA disks + * @szInqStr: INQUIRY result string to be refined + * @uiLen: length of the string + * + * Description: + * The verder name is not correct in some disk. For example, the vendor name of + * "OCZ-VERTEX3 MI" is "OCZ-VERT". + * This function refines the INQUIRY result of SATA disks to correctly + * fill the vendor name by vendor list gDiskVendor. + **/ +static void syno_standard_vendor_string(unsigned char *szInqStr, unsigned int uiLen) +{ + int i = 0; + + if (NULL == szInqStr || 0 == uiLen) { + goto END; + } + + if (uiLen > SYNO_INQUIRY_VENDOR_LEN) { + uiLen = SYNO_INQUIRY_VENDOR_LEN; + } + + for (i = 0; NULL != gDiskVendor[i].szName; i++) { + if (!strncmp(gDiskVendor[i].szName, szInqStr, gDiskVendor[i].iLength)) { + memset(szInqStr, 0, uiLen); + memcpy(szInqStr, gDiskVendor[i].szName, gDiskVendor[i].iLength); + break; + } + } +END: + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * Description: + * The result of SCSI INQUIRY from a SATA disk might set vendor as "ATA" + * and set model as "vendor model" in 16 characters. This could let model + * name obtain incomplete. For expample, model will be "KINGSTON SKC100S" + * after INQUIRY command executes. But the complete model name of the disk + * is "SKC100S3120G". + * This function use ATA command to obtain SATA disk informatiom and then + * refines the INQUIRY result of SATA disks to correctly fill the vendor + * and model entries. This function resets the result string and parses the + * original model string and fills the correct data into each entry. + * References: + * 1. Information Technology - AT Attachment with Packet Interface - 5 (ATA/ATAPI-5) + * 2. ATA Command Pass-Through + * + * @param + * sdev[IN]: send ATA command to the SCSI device + * szInqReturn[OUT]: INQUIRY result string to be refined + * + **/ + +static void scsi_ata_identify_device_get_model_name(struct scsi_device *sdev, unsigned char *szInqReturn) +{ + int i = 0; + int blSpecialVendor = 0; + int blPreIsSpace = 0; + int blSegmented = 0; + int iRes = 0; + u16 id[SYNO_RESULT_LEN / 2] = {0}; + unsigned char szInqResult[SYNO_RESULT_LEN] = {0}; + + iRes = syno_get_ata_identity(sdev, id); + memcpy(szInqResult, id, SYNO_RESULT_LEN); + + /* Swap string for endian problems */ + for (i = 0; i < SYNO_RESULT_LEN - 1; i += 2) + { + char tmp = szInqResult[i]; + szInqResult[i] = szInqResult[i+1]; + szInqResult[i+1] = tmp; + } + + if (!iRes || '\0' == szInqResult[54]) { + return; + } + + for (i = 0; NULL != gDiskVendor[i].szName; i++) { + /* The disk model name start from word 27 in the buffer */ + if (!strncmp(gDiskVendor[i].szName, &szInqResult[54], gDiskVendor[i].iLength)) { + blSpecialVendor = 1; + break; + } + } + + if (1 == blSpecialVendor) { + if (' ' == szInqResult[54 + gDiskVendor[i].iLength] || + '-' == szInqResult[54 + gDiskVendor[i].iLength] || + '_' == szInqResult[54 + gDiskVendor[i].iLength]) { + i = gDiskVendor[i].iLength + 1; + } else { + i = gDiskVendor[i].iLength; + } + } else { + /* Search the end of vendor name */ + for (i = 0; i < SYNO_IDENTIFY_DEVICE_TMP_LEN; i++) { + if ('\0' == szInqResult[54 + i]) { + break; + } + + if (' ' == szInqResult[54 + i]) { + if (1 == blPreIsSpace){ + break; + } + blPreIsSpace = 1; + } else if (blPreIsSpace) { + blSegmented = 1; + break; + } + } + + if (!blSegmented){ + i = 0; + } + } + + /* The disk model name start from word 27 in the buffer */ + memcpy(szInqReturn, &szInqResult[54 + i], SYNO_DISK_MODEL_NUM); + + return; +} +#endif /* MY_ABC_HERE */ + /** * scsi_sanitize_inquiry_string - remove non-graphical chars from an * INQUIRY result string @@ -542,6 +802,116 @@ void scsi_sanitize_inquiry_string(unsigned char *s, int len) } EXPORT_SYMBOL(scsi_sanitize_inquiry_string); +#ifdef MY_ABC_HERE +static int syno_is_pmp_device(struct device *dev) +{ + struct ata_port *pPmPort = NULL; + int iRet = 0; + + if (!dev || !dev->type) { + goto End; + } + + while (strcmp(dev->type->name, "ata_port")) { + if (!dev->type->name || !dev->parent) { + goto End; + } + dev = dev->parent; + } + + pPmPort = to_ata_port(dev); + if (!pPmPort || !syno_is_synology_pm(pPmPort)) { + goto End; + } + + iRet = 1; +End: + return iRet; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SERIAL_RESULT_BUF_SIZE 252 +#define VPD_SUPPORTED_VPDS 0x00 +#define VPD_UNIT_SERIAL_NUM 0x80 +static int syno_fetch_unit_serial_num(struct scsi_device *sdev) +{ + int ret = -1, result = 0, k = 0, len = 0; + unsigned char scsi_cmd[MAX_COMMAND_SIZE]; + struct scsi_sense_hdr sshdr; + unsigned char serial_num_result[SERIAL_RESULT_BUF_SIZE]; + + if (NULL == sdev) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi_device null pointer\n")); + goto END; + } + + memset(scsi_cmd, 0, 6); + scsi_cmd[0] = INQUIRY; + scsi_cmd[1] = 0x01; + scsi_cmd[2] = VPD_SUPPORTED_VPDS; + scsi_cmd[4] = SERIAL_RESULT_BUF_SIZE; + memset(serial_num_result, 0, SERIAL_RESULT_BUF_SIZE); + + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + serial_num_result, SERIAL_RESULT_BUF_SIZE, &sshdr, + HZ / 2 + HZ * scsi_inq_timeout, 3, + NULL); + + if (result) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "get serial num INQUIRY failed with code 0x%x\n", result)); + goto END; + } + + if (VPD_SUPPORTED_VPDS != serial_num_result[1] || + 0x00 != serial_num_result[2]) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "bad supported VPDs page\n")); + goto END; + } + + len = (serial_num_result[2] << 8) + serial_num_result[3]; // spc4r25 + for (k = 0; k < len; ++k) { + if (VPD_UNIT_SERIAL_NUM == serial_num_result[k + 4]) + break; + } + if (k >= len) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "without serial num page\n")); + goto END; + } + + memset(scsi_cmd, 0, 6); + scsi_cmd[0] = INQUIRY; + scsi_cmd[1] = 0x01; + scsi_cmd[2] = VPD_UNIT_SERIAL_NUM; + scsi_cmd[4] = SERIAL_RESULT_BUF_SIZE; + memset(serial_num_result, 0, SERIAL_RESULT_BUF_SIZE); + + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + serial_num_result, SERIAL_RESULT_BUF_SIZE, &sshdr, + HZ / 2 + HZ * scsi_inq_timeout, 3, + NULL); + + if (result) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "get serial num INQUIRY failed with code 0x%x\n", result)); + goto END; + } + + len = (serial_num_result[2] << 8) + serial_num_result[3]; // spc4r25 + len = (len > SERIAL_NUM_SIZE) ? SERIAL_NUM_SIZE : len; + if (VPD_UNIT_SERIAL_NUM != serial_num_result[1] || + 0 >= len) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "bad serial number length VPD page\n")); + goto END; + } + + scsi_sanitize_inquiry_string(serial_num_result + 4, len); + memcpy(sdev->syno_disk_serial, serial_num_result + 4, len); + ret = 0; +END: + return ret; +} +#endif /* MY_ABC_HERE */ + /** * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY * @sdev: scsi_device to probe @@ -564,6 +934,17 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, int response_len = 0; int pass, count, result; struct scsi_sense_hdr sshdr; +#ifdef MY_ABC_HERE + /* Standard Inquiry Data for Virtual Device */ + unsigned char SYNO_INQUIRY_VIRTUALD_DATA[] = { + 0x03,0x00,0x04,0x02,0x20,0x00,0x00,0x00, + 'S', 'y', 'n', 'o', 'l', 'o', 'g', 'y', + 'V', 'i', 'r', 't', 'u', 'a', 'l', ' ', + 'D', 'e', 'v', 'i', 'c', 'e', ' ', ' ', + 0x31,0x2E,0x30,0x30 + }; + int iVirtualInquiryLen = 36; +#endif /* MY_ABC_HERE */ *bflags = 0; @@ -589,10 +970,23 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, memset(inq_result, 0, try_inquiry_len); +#ifdef MY_ABC_HERE + if (sdev->channel == SYNO_PM_VIRTUAL_SCSI_CHANNEL) { + result = 0; + if (syno_is_pmp_device(&sdev->sdev_gendev)) { + memset(inq_result, 0, iVirtualInquiryLen); + memcpy(inq_result, SYNO_INQUIRY_VIRTUALD_DATA, iVirtualInquiryLen); + sdev->inquiry_len = iVirtualInquiryLen; + } + } else { +#endif /* MY_ABC_HERE */ result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, inq_result, try_inquiry_len, &sshdr, HZ / 2 + HZ * scsi_inq_timeout, 3, &resid); +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, "scsi scan: INQUIRY %s with code 0x%x\n", @@ -626,6 +1020,17 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, } if (result == 0) { +#ifdef MY_ABC_HERE + /* + * Only transfering the strings that vendor is ATA. + * vendor set as "ATA" means the disk is a SATA disk + */ + if (!strncmp(&inq_result[8], SZ_STAT_DISK_VENDOR, 8)) { + syno_standard_inquiry_string(&inq_result[8], 28); + } else { + syno_standard_vendor_string(&inq_result[8], 8); + } +#endif /* MY_ABC_HERE */ scsi_sanitize_inquiry_string(&inq_result[8], 8); scsi_sanitize_inquiry_string(&inq_result[16], 16); scsi_sanitize_inquiry_string(&inq_result[32], 4); @@ -742,6 +1147,11 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, !sdev->host->no_scsi2_lun_in_cdb) sdev->lun_in_cdb = 1; +#ifdef MY_ABC_HERE + memset(sdev->syno_disk_serial, 0, sizeof(sdev->syno_disk_serial)); + syno_fetch_unit_serial_num(sdev); +#endif /* MY_ABC_HERE */ + return 0; } @@ -764,6 +1174,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, blist_flags_t *bflags, int async) { int ret; +#ifdef MY_ABC_HERE + unsigned char szDiskModel[SYNO_DISK_MODEL_NUM + 4] = {'\0'}; +#endif /* MY_ABC_HERE */ /* * XXX do not save the inquiry, since it can change underneath us, @@ -792,7 +1205,34 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, return SCSI_SCAN_NO_RESPONSE; sdev->vendor = (char *) (sdev->inquiry + 8); +#ifdef MY_ABC_HERE + if (!(SYNO_PORT_TYPE_USB == sdev->host->hostt->syno_port_type)) { +#ifdef MY_ABC_HERE + if(sdev->channel != SYNO_PM_VIRTUAL_SCSI_CHANNEL || + !syno_is_pmp_device(&sdev->sdev_gendev)) +#endif /* MY_ABC_HERE */ + scsi_ata_identify_device_get_model_name(sdev, (unsigned char *)&szDiskModel); + } + + if (0 != strlen(szDiskModel)) { + sdev->model = kmemdup(szDiskModel, SYNO_DISK_MODEL_NUM, GFP_ATOMIC); + } else { + /* + * Can't get disk model name by using ATA IDENTIFY DEVICE command. + * eg. SAS disk, Enclosure ... + * So we copy disk model name from INQUIRY result. + */ + memset (szDiskModel, ' ', SYNO_DISK_MODEL_NUM); + memcpy(szDiskModel, (char *) (sdev->inquiry + 16), 16); + sdev->model = kmemdup(szDiskModel, SYNO_DISK_MODEL_NUM, GFP_ATOMIC); + } + if (sdev->model == NULL) + return SCSI_SCAN_NO_RESPONSE; + + scsi_sanitize_inquiry_string((unsigned char *) sdev->model, SYNO_DISK_MODEL_NUM); +#else /* MY_ABC_HERE */ sdev->model = (char *) (sdev->inquiry + 16); +#endif /* MY_ABC_HERE */ sdev->rev = (char *) (sdev->inquiry + 32); if (strncmp(sdev->vendor, "ATA ", 8) == 0) { @@ -863,7 +1303,11 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, if (inq_result[7] & 0x10) sdev->sdtr = 1; +#ifdef MY_ABC_HERE + sdev_printk(KERN_NOTICE, sdev, "%s %.8s %."SYNO_DISK_MODEL_LEN"s %.4s PQ: %d " +#else /* MY_ABC_HERE */ sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d " +#endif /* MY_ABC_HERE */ "ANSI: %d%s\n", scsi_device_type(sdev->type), sdev->vendor, sdev->model, sdev->rev, sdev->inq_periph_qual, inq_result[2] & 0x07, diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index d6e344fa33ad..2cbf226d1247 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * scsi_sysfs.c @@ -26,6 +29,13 @@ #include "scsi_priv.h" #include "scsi_logging.h" +#ifdef MY_ABC_HERE +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_NOTICE +#endif +#endif /* MY_ABC_HERE */ + static struct device_type scsi_dev_type; static const struct { @@ -497,6 +507,9 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) if (vpd_pg89) kfree_rcu(vpd_pg89, rcu); kfree(sdev->inquiry); +#ifdef MY_ABC_HERE + kfree(sdev->model); +#endif /* MY_ABC_HERE */ kfree(sdev); if (parent) @@ -576,6 +589,18 @@ void scsi_sysfs_unregister(void) * sdev_show_function: macro to create an attr function that can be used to * show a non-bit field. */ +#ifdef MY_ABC_HERE +#define sdev_show_function(field, format_string) \ +static ssize_t \ +sdev_show_##field (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct scsi_device *sdev; \ + sdev = to_scsi_device(dev); \ + return snprintf (buf, SYNO_DISK_MODEL_NUM + 4, format_string, sdev->field); \ +} \ + +#else /* MY_ABC_HERE */ #define sdev_show_function(field, format_string) \ static ssize_t \ sdev_show_##field (struct device *dev, struct device_attribute *attr, \ @@ -586,6 +611,8 @@ sdev_show_##field (struct device *dev, struct device_attribute *attr, \ return snprintf (buf, 20, format_string, sdev->field); \ } \ +#endif /* MY_ABC_HERE */ + /* * sdev_rd_attr: macro to create a function and attribute variable for a * read only field. @@ -656,13 +683,267 @@ static int scsi_sdev_check_buf_bit(const char *buf) return -EINVAL; } #endif + +#ifdef MY_ABC_HERE +static ssize_t +syno_disk_serial_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = NULL; + ssize_t len = -EFAULT; + + if (NULL == (sdev = to_scsi_device(device))) { + goto END; + } + + len = snprintf(buf, SERIAL_NUM_SIZE + 2, "%s\n", sdev->syno_disk_serial); +END: + return len; +} +static DEVICE_ATTR(syno_disk_serial, S_IRUGO, syno_disk_serial_show, NULL); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +syno_block_info_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = NULL; + ssize_t len = -EFAULT; + + if (NULL == (sdev = to_scsi_device(device))) { + goto END; + } + + len = snprintf(buf, BLOCK_INFO_SIZE , "%s", sdev->syno_block_info); +END: + return len; +} +static DEVICE_ATTR(syno_block_info, S_IRUGO, syno_block_info_show, NULL); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* FIXME: We don't know why SAS disks led blinking when open it, so we add a sysfs interface to prevent it + * The following code is copied from "case SD_IOCTL_IDLE: " ind "sd.c" */ +static ssize_t +sdev_show_syno_idle_time(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev; + int iRet = -EFAULT; + + if (NULL == (sdev = to_scsi_device(dev))) { + goto END; + } + + iRet = snprintf(buf, 20, "%lu\n", (jiffies - sdev->last_accessed) / HZ + 1); + +END: + return iRet; +} + +static ssize_t +sdev_store_syno_idle_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev; + unsigned long idletime; + + if (NULL == (sdev = to_scsi_device(dev))) { + goto END; + } + + sscanf(buf, "%lu", &idletime); + // idletime = (jiffies - sdev->last_accessed) / HZ + 1 + sdev->last_accessed = jiffies - (idletime - 1) * HZ; + +END: + return count; +} + +static DEVICE_ATTR(syno_idle_time, S_IRUGO | S_IWUSR, sdev_show_syno_idle_time, sdev_store_syno_idle_time); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t +sdev_show_syno_spindown(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev; + int iRet = -EFAULT; + + if (NULL == (sdev = to_scsi_device(dev))) { + goto END; + } + + iRet = snprintf(buf, 20, "%d\n", sdev->spindown); + +END: + return iRet; +} + +static DEVICE_ATTR(syno_spindown, S_IRUGO, sdev_show_syno_spindown, NULL); + + +#ifdef MY_DEF_HERE +static ssize_t +sdev_show_syno_sas_sata_standby_flag(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev; + int iRet = -EFAULT; + + if (NULL == (sdev = to_scsi_device(dev))) { + goto END; + } + + iRet = snprintf(buf, 20, "%ld\n", sdev->sas_sata_standby_flag); + +END: + return iRet; +} + +static DEVICE_ATTR(syno_sas_sata_standby_flag, S_IRUGO, sdev_show_syno_sas_sata_standby_flag, NULL); +#endif /* MY_DEF_HERE */ + +static ssize_t +sdev_show_syno_standby_syncing(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev; + int iRet = -EFAULT; + + if (NULL == (sdev = to_scsi_device(dev))) { + goto END; + } + + iRet = snprintf (buf, 20, "%u\n", sdev->do_standby_syncing); + +END: + return iRet; +} + +static ssize_t +sdev_store_syno_standby_syncing(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev; + unsigned long ulstandby_syncing; + + if (NULL == (sdev = to_scsi_device(dev))) { + goto END; + } + + sscanf(buf, "%lu", &ulstandby_syncing); + if (0 < ulstandby_syncing) { + sdev->do_standby_syncing = 1; + } else { + sdev->do_standby_syncing = 0; + } + +END: + return count; +} + +static DEVICE_ATTR(syno_standby_syncing, S_IRUGO | S_IWUSR, sdev_show_syno_standby_syncing, sdev_store_syno_standby_syncing); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * Show customized timeout of the disk + */ +static ssize_t +syno_scmd_min_timeout_show (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + ssize_t len = -EIO; + + if (!sdev) { + goto END; + } + + if (0 == sdev->scmd_timeout_sec) { + len = sprintf(buf, "%s", "\n"); + } else { + len = sprintf(buf, "%d%s", sdev->scmd_timeout_sec, "\n"); + } + +END: + return len; +} + +/** + * Set customized timeout of the disk + */ +static ssize_t +syno_scmd_min_timeout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + int iTimeoutSec = 0; + ssize_t ret = -EIO; + + if (!sdev) { + goto END; + } + + /* Check the input value is in the available range [1 - 60] */ + sscanf(buf, "%d", &iTimeoutSec); + if (0 >= iTimeoutSec || 60 < iTimeoutSec) { + printk(KERN_ERR "Invalid argument !!\n"); + goto END; + } + sdev->scmd_timeout_sec = iTimeoutSec; + + ret = count; + +END: + return ret; +} +DEVICE_ATTR(syno_scmd_min_timeout, S_IRUGO | S_IWUSR, syno_scmd_min_timeout_show, syno_scmd_min_timeout_store); +#endif /* MY_ABC_HERE */ + +#ifdef CONFIG_SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF +static ssize_t +syno_spindown_before_poweroff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + ssize_t len = -EIO; + + if (!sdev) { + goto END; + } + + len = sprintf(buf, "%u", sdev->manage_start_stop); + +END: + return len; +} + +static ssize_t +syno_spindown_before_poweroff_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + unsigned uVal; + if (1 != sscanf (buf, "%u\n", &uVal)) { + return -EINVAL; + } + if (1 < uVal) { + return -EINVAL; + } + sdev->manage_start_stop = uVal; + return count; +} + +static DEVICE_ATTR(syno_spindown_before_poweroff, S_IRUGO | S_IWUSR, + syno_spindown_before_poweroff_show, + syno_spindown_before_poweroff_store); +#endif /* CONFIG_SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF */ /* * Create the actual show/store functions and data structures. */ sdev_rd_attr (type, "%d\n"); sdev_rd_attr (scsi_level, "%d\n"); sdev_rd_attr (vendor, "%.8s\n"); +#ifdef MY_ABC_HERE +sdev_rd_attr (model, "%."SYNO_DISK_MODEL_LEN"s\n"); +#else /* MY_ABC_HERE */ sdev_rd_attr (model, "%.16s\n"); +#endif /* MY_ABC_HERE */ sdev_rd_attr (rev, "%.4s\n"); static ssize_t @@ -1266,6 +1547,28 @@ static struct attribute *scsi_sdev_attrs[] = { &dev_attr_preferred_path.attr, #endif &dev_attr_queue_ramp_up_period.attr, +#ifdef MY_ABC_HERE + &dev_attr_syno_block_info.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_idle_time.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_spindown.attr, +#ifdef MY_DEF_HERE + &dev_attr_syno_sas_sata_standby_flag.attr, +#endif /* MY_DEF_HERE */ + &dev_attr_syno_standby_syncing.attr, +#endif /* MY_ABC_HERE */ +#ifdef CONFIG_SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF + &dev_attr_syno_spindown_before_poweroff.attr, +#endif /* CONFIG_SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF */ +#ifdef MY_ABC_HERE + &dev_attr_syno_disk_serial.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_scmd_min_timeout.attr, +#endif /* MY_ABC_HERE */ REF_EVT(media_change), REF_EVT(inquiry_change_reported), REF_EVT(capacity_change_reported), @@ -1466,6 +1769,10 @@ void __scsi_remove_device(struct scsi_device *sdev) put_device(dev); } +#ifdef MY_ABC_HERE +int (*syno_raid_scsi_unplug)(char *szDiskName) = NULL; +EXPORT_SYMBOL(syno_raid_scsi_unplug); +#endif /* MY_ABC_HERE */ /** * scsi_remove_device - unregister a device from the scsi bus * @sdev: scsi_device to unregister @@ -1477,6 +1784,15 @@ void scsi_remove_device(struct scsi_device *sdev) mutex_lock(&shost->scan_mutex); __scsi_remove_device(sdev); mutex_unlock(&shost->scan_mutex); +#ifdef MY_DEF_HERE + SynoSpinupRemove(sdev); +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (syno_raid_scsi_unplug) + syno_raid_scsi_unplug(sdev->syno_disk_name); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ } EXPORT_SYMBOL(scsi_remove_device); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index ac07a9ef3578..b5a039de0c61 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -86,16 +86,10 @@ struct iscsi_internal { struct transport_container session_cont; }; -/* Worker to perform connection failure on unresponsive connections - * completely in kernel space. - */ -static void stop_conn_work_fn(struct work_struct *work); -static DECLARE_WORK(stop_conn_work, stop_conn_work_fn); - static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ static struct workqueue_struct *iscsi_eh_timer_workq; -static struct workqueue_struct *iscsi_destroy_workq; +static struct workqueue_struct *iscsi_conn_cleanup_workq; static DEFINE_IDA(iscsi_sess_ida); /* @@ -268,9 +262,20 @@ void iscsi_destroy_endpoint(struct iscsi_endpoint *ep) } EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint); +void iscsi_put_endpoint(struct iscsi_endpoint *ep) +{ + put_device(&ep->dev); +} +EXPORT_SYMBOL_GPL(iscsi_put_endpoint); + +/** + * iscsi_lookup_endpoint - get ep from handle + * @handle: endpoint handle + * + * Caller must do a iscsi_put_endpoint. + */ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle) { - struct iscsi_endpoint *ep; struct device *dev; dev = class_find_device(&iscsi_endpoint_class, NULL, &handle, @@ -278,13 +283,7 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle) if (!dev) return NULL; - ep = iscsi_dev_to_endpoint(dev); - /* - * we can drop this now because the interface will prevent - * removals and lookups from racing. - */ - put_device(dev); - return ep; + return iscsi_dev_to_endpoint(dev); } EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); @@ -1598,12 +1597,6 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class, static struct sock *nls; static DEFINE_MUTEX(rx_queue_mutex); -/* - * conn_mutex protects the {start,bind,stop,destroy}_conn from racing - * against the kernel stop_connection recovery mechanism - */ -static DEFINE_MUTEX(conn_mutex); - static LIST_HEAD(sesslist); static DEFINE_SPINLOCK(sesslock); static LIST_HEAD(connlist); @@ -2225,6 +2218,123 @@ void iscsi_remove_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_remove_session); +static void iscsi_stop_conn(struct iscsi_cls_conn *conn, int flag) +{ + ISCSI_DBG_TRANS_CONN(conn, "Stopping conn.\n"); + + switch (flag) { + case STOP_CONN_RECOVER: + conn->state = ISCSI_CONN_FAILED; + break; + case STOP_CONN_TERM: + conn->state = ISCSI_CONN_DOWN; + break; + default: + iscsi_cls_conn_printk(KERN_ERR, conn, "invalid stop flag %d\n", + flag); + return; + } + + conn->transport->stop_conn(conn, flag); + ISCSI_DBG_TRANS_CONN(conn, "Stopping conn done.\n"); +} + +static int iscsi_if_stop_conn(struct iscsi_transport *transport, + struct iscsi_uevent *ev) +{ + int flag = ev->u.stop_conn.flag; + struct iscsi_cls_conn *conn; + + conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); + if (!conn) + return -EINVAL; + + ISCSI_DBG_TRANS_CONN(conn, "iscsi if conn stop.\n"); + /* + * If this is a termination we have to call stop_conn with that flag + * so the correct states get set. If we haven't run the work yet try to + * avoid the extra run. + */ + if (flag == STOP_CONN_TERM) { + cancel_work_sync(&conn->cleanup_work); + iscsi_stop_conn(conn, flag); + } else { + /* + * Figure out if it was the kernel or userspace initiating this. + */ + if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) { + iscsi_stop_conn(conn, flag); + } else { + ISCSI_DBG_TRANS_CONN(conn, + "flush kernel conn cleanup.\n"); + flush_work(&conn->cleanup_work); + } + /* + * Only clear for recovery to avoid extra cleanup runs during + * termination. + */ + clear_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags); + } + ISCSI_DBG_TRANS_CONN(conn, "iscsi if conn stop done.\n"); + return 0; +} + +static void iscsi_ep_disconnect(struct iscsi_cls_conn *conn, bool is_active) +{ + struct iscsi_cls_session *session = iscsi_conn_to_session(conn); + struct iscsi_endpoint *ep; + + ISCSI_DBG_TRANS_CONN(conn, "disconnect ep.\n"); + conn->state = ISCSI_CONN_FAILED; + + if (!conn->ep || !session->transport->ep_disconnect) + return; + + ep = conn->ep; + conn->ep = NULL; + + // session->transport->unbind_conn(conn, is_active); + session->transport->ep_disconnect(ep); + ISCSI_DBG_TRANS_CONN(conn, "disconnect ep done.\n"); +} + +static void iscsi_cleanup_conn_work_fn(struct work_struct *work) +{ + struct iscsi_cls_conn *conn = container_of(work, struct iscsi_cls_conn, + cleanup_work); + struct iscsi_cls_session *session = iscsi_conn_to_session(conn); + + mutex_lock(&conn->ep_mutex); + /* + * If we are not at least bound there is nothing for us to do. Userspace + * will do a ep_disconnect call if offload is used, but will not be + * doing a stop since there is nothing to clean up, so we have to clear + * the cleanup bit here. + */ + if (conn->state != ISCSI_CONN_BOUND && conn->state != ISCSI_CONN_UP) { + ISCSI_DBG_TRANS_CONN(conn, "Got error while conn is already failed. Ignoring.\n"); + clear_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags); + mutex_unlock(&conn->ep_mutex); + return; + } + + iscsi_ep_disconnect(conn, false); + + if (system_state != SYSTEM_RUNNING) { + /* + * If the user has set up for the session to never timeout + * then hang like they wanted. For all other cases fail right + * away since userspace is not going to relogin. + */ + if (session->recovery_tmo > 0) + session->recovery_tmo = 0; + } + + iscsi_stop_conn(conn, STOP_CONN_RECOVER); + mutex_unlock(&conn->ep_mutex); + ISCSI_DBG_TRANS_CONN(conn, "cleanup done.\n"); +} + void iscsi_free_session(struct iscsi_cls_session *session) { ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n"); @@ -2264,7 +2374,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) mutex_init(&conn->ep_mutex); INIT_LIST_HEAD(&conn->conn_list); - INIT_LIST_HEAD(&conn->conn_list_err); + INIT_WORK(&conn->cleanup_work, iscsi_cleanup_conn_work_fn); conn->transport = transport; conn->cid = cid; conn->state = ISCSI_CONN_DOWN; @@ -2321,7 +2431,6 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) spin_lock_irqsave(&connlock, flags); list_del(&conn->conn_list); - list_del(&conn->conn_list_err); spin_unlock_irqrestore(&connlock, flags); transport_unregister_device(&conn->dev); @@ -2448,77 +2557,6 @@ int iscsi_offload_mesg(struct Scsi_Host *shost, } EXPORT_SYMBOL_GPL(iscsi_offload_mesg); -/* - * This can be called without the rx_queue_mutex, if invoked by the kernel - * stop work. But, in that case, it is guaranteed not to race with - * iscsi_destroy by conn_mutex. - */ -static void iscsi_if_stop_conn(struct iscsi_cls_conn *conn, int flag) -{ - /* - * It is important that this path doesn't rely on - * rx_queue_mutex, otherwise, a thread doing allocation on a - * start_session/start_connection could sleep waiting on a - * writeback to a failed iscsi device, that cannot be recovered - * because the lock is held. If we don't hold it here, the - * kernel stop_conn_work_fn has a chance to stop the broken - * session and resolve the allocation. - * - * Still, the user invoked .stop_conn() needs to be serialized - * with stop_conn_work_fn by a private mutex. Not pretty, but - * it works. - */ - mutex_lock(&conn_mutex); - switch (flag) { - case STOP_CONN_RECOVER: - conn->state = ISCSI_CONN_FAILED; - break; - case STOP_CONN_TERM: - conn->state = ISCSI_CONN_DOWN; - break; - default: - iscsi_cls_conn_printk(KERN_ERR, conn, - "invalid stop flag %d\n", flag); - goto unlock; - } - - conn->transport->stop_conn(conn, flag); -unlock: - mutex_unlock(&conn_mutex); -} - -static void stop_conn_work_fn(struct work_struct *work) -{ - struct iscsi_cls_conn *conn, *tmp; - unsigned long flags; - LIST_HEAD(recovery_list); - - spin_lock_irqsave(&connlock, flags); - if (list_empty(&connlist_err)) { - spin_unlock_irqrestore(&connlock, flags); - return; - } - list_splice_init(&connlist_err, &recovery_list); - spin_unlock_irqrestore(&connlock, flags); - - list_for_each_entry_safe(conn, tmp, &recovery_list, conn_list_err) { - uint32_t sid = iscsi_conn_get_sid(conn); - struct iscsi_cls_session *session; - - session = iscsi_session_lookup(sid); - if (session) { - if (system_state != SYSTEM_RUNNING) { - session->recovery_tmo = 0; - iscsi_if_stop_conn(conn, STOP_CONN_TERM); - } else { - iscsi_if_stop_conn(conn, STOP_CONN_RECOVER); - } - } - - list_del_init(&conn->conn_list_err); - } -} - void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) { struct nlmsghdr *nlh; @@ -2526,12 +2564,9 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = nlmsg_total_size(sizeof(*ev)); - unsigned long flags; - spin_lock_irqsave(&connlock, flags); - list_add(&conn->conn_list_err, &connlist_err); - spin_unlock_irqrestore(&connlock, flags); - queue_work(system_unbound_wq, &stop_conn_work); + if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) + queue_work(iscsi_conn_cleanup_workq, &conn->cleanup_work); priv = iscsi_if_transport_lookup(conn->transport); if (!priv) @@ -2861,25 +2896,17 @@ static int iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) { struct iscsi_cls_conn *conn; - unsigned long flags; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) return -EINVAL; - spin_lock_irqsave(&connlock, flags); - if (!list_empty(&conn->conn_list_err)) { - spin_unlock_irqrestore(&connlock, flags); - return -EAGAIN; - } - spin_unlock_irqrestore(&connlock, flags); - + ISCSI_DBG_TRANS_CONN(conn, "Flushing cleanup during destruction\n"); + flush_work(&conn->cleanup_work); ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n"); - mutex_lock(&conn_mutex); if (transport->destroy_conn) transport->destroy_conn(conn); - mutex_unlock(&conn_mutex); return 0; } @@ -2970,15 +2997,31 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport, ep = iscsi_lookup_endpoint(ep_handle); if (!ep) return -EINVAL; + conn = ep->conn; - if (conn) { - mutex_lock(&conn->ep_mutex); - conn->ep = NULL; - mutex_unlock(&conn->ep_mutex); - conn->state = ISCSI_CONN_FAILED; + if (!conn) { + /* + * conn was not even bound yet, so we can't get iscsi conn + * failures yet. + */ + transport->ep_disconnect(ep); + goto put_ep; } - transport->ep_disconnect(ep); + mutex_lock(&conn->ep_mutex); + /* Check if this was a conn error and the kernel took ownership */ + if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) { + ISCSI_DBG_TRANS_CONN(conn, "flush kernel conn cleanup.\n"); + mutex_unlock(&conn->ep_mutex); + + flush_work(&conn->cleanup_work); + goto put_ep; + } + + iscsi_ep_disconnect(conn, false); + mutex_unlock(&conn->ep_mutex); +put_ep: + iscsi_put_endpoint(ep); return 0; } @@ -3004,6 +3047,7 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, ev->r.retcode = transport->ep_poll(ep, ev->u.ep_poll.timeout_ms); + iscsi_put_endpoint(ep); break; case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: rc = iscsi_if_ep_disconnect(transport, @@ -3634,18 +3678,129 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) return err; } +static int iscsi_if_transport_conn(struct iscsi_transport *transport, + struct nlmsghdr *nlh) +{ + struct iscsi_uevent *ev = nlmsg_data(nlh); + struct iscsi_cls_session *session; + struct iscsi_cls_conn *conn = NULL; + struct iscsi_endpoint *ep; + uint32_t pdu_len; + int err = 0; + + switch (nlh->nlmsg_type) { + case ISCSI_UEVENT_CREATE_CONN: + return iscsi_if_create_conn(transport, ev); + case ISCSI_UEVENT_DESTROY_CONN: + return iscsi_if_destroy_conn(transport, ev); + case ISCSI_UEVENT_STOP_CONN: + return iscsi_if_stop_conn(transport, ev); + } + + /* + * The following cmds need to be run under the ep_mutex so in kernel + * conn cleanup (ep_disconnect + unbind and conn) is not done while + * these are running. They also must not run if we have just run a conn + * cleanup because they would set the state in a way that might allow + * IO or send IO themselves. + */ + switch (nlh->nlmsg_type) { + case ISCSI_UEVENT_START_CONN: + conn = iscsi_conn_lookup(ev->u.start_conn.sid, + ev->u.start_conn.cid); + break; + case ISCSI_UEVENT_BIND_CONN: + conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid); + break; + case ISCSI_UEVENT_SEND_PDU: + conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid); + break; + } + + if (!conn) + return -EINVAL; + + mutex_lock(&conn->ep_mutex); + if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) { + mutex_unlock(&conn->ep_mutex); + ev->r.retcode = -ENOTCONN; + return 0; + } + + switch (nlh->nlmsg_type) { + case ISCSI_UEVENT_BIND_CONN: + if (conn->ep) { + /* + * For offload boot support where iscsid is restarted + * during the pivot root stage, the ep will be intact + * here when the new iscsid instance starts up and + * reconnects. + */ + iscsi_ep_disconnect(conn, true); + } + + session = iscsi_session_lookup(ev->u.b_conn.sid); + if (!session) { + err = -EINVAL; + break; + } + + ev->r.retcode = transport->bind_conn(session, conn, + ev->u.b_conn.transport_eph, + ev->u.b_conn.is_leading); + if (!ev->r.retcode) + conn->state = ISCSI_CONN_BOUND; + + if (ev->r.retcode || !transport->ep_connect) + break; + + ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph); + if (ep) { + ep->conn = conn; + conn->ep = ep; + iscsi_put_endpoint(ep); + } else { + err = -ENOTCONN; + iscsi_cls_conn_printk(KERN_ERR, conn, + "Could not set ep conn binding\n"); + } + break; + case ISCSI_UEVENT_START_CONN: + ev->r.retcode = transport->start_conn(conn); + if (!ev->r.retcode) + conn->state = ISCSI_CONN_UP; + break; + case ISCSI_UEVENT_SEND_PDU: + pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); + + if ((ev->u.send_pdu.hdr_size > pdu_len) || + (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) { + err = -EINVAL; + break; + } + + ev->r.retcode = transport->send_pdu(conn, + (struct iscsi_hdr *)((char *)ev + sizeof(*ev)), + (char *)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size, + ev->u.send_pdu.data_size); + break; + default: + err = -ENOSYS; + } + + mutex_unlock(&conn->ep_mutex); + return err; +} static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { int err = 0; u32 portid; - u32 pdu_len; struct iscsi_uevent *ev = nlmsg_data(nlh); struct iscsi_transport *transport = NULL; struct iscsi_internal *priv; struct iscsi_cls_session *session; - struct iscsi_cls_conn *conn; struct iscsi_endpoint *ep = NULL; if (!netlink_capable(skb, CAP_SYS_ADMIN)) @@ -3686,6 +3841,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) ev->u.c_bound_session.initial_cmdsn, ev->u.c_bound_session.cmds_max, ev->u.c_bound_session.queue_depth); + iscsi_put_endpoint(ep); break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); @@ -3710,7 +3866,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) list_del_init(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); - queue_work(iscsi_destroy_workq, &session->destroy_work); + queue_work(system_unbound_wq, &session->destroy_work); } break; case ISCSI_UEVENT_UNBIND_SESSION: @@ -3721,89 +3877,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) else err = -EINVAL; break; - case ISCSI_UEVENT_CREATE_CONN: - err = iscsi_if_create_conn(transport, ev); - break; - case ISCSI_UEVENT_DESTROY_CONN: - err = iscsi_if_destroy_conn(transport, ev); - break; - case ISCSI_UEVENT_BIND_CONN: - session = iscsi_session_lookup(ev->u.b_conn.sid); - conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid); - - if (conn && conn->ep) - iscsi_if_ep_disconnect(transport, conn->ep->id); - - if (!session || !conn) { - err = -EINVAL; - break; - } - - mutex_lock(&conn_mutex); - ev->r.retcode = transport->bind_conn(session, conn, - ev->u.b_conn.transport_eph, - ev->u.b_conn.is_leading); - if (!ev->r.retcode) - conn->state = ISCSI_CONN_BOUND; - mutex_unlock(&conn_mutex); - - if (ev->r.retcode || !transport->ep_connect) - break; - - ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph); - if (ep) { - ep->conn = conn; - - mutex_lock(&conn->ep_mutex); - conn->ep = ep; - mutex_unlock(&conn->ep_mutex); - } else - iscsi_cls_conn_printk(KERN_ERR, conn, - "Could not set ep conn " - "binding\n"); - break; case ISCSI_UEVENT_SET_PARAM: err = iscsi_set_param(transport, ev); break; - case ISCSI_UEVENT_START_CONN: - conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); - if (conn) { - mutex_lock(&conn_mutex); - ev->r.retcode = transport->start_conn(conn); - if (!ev->r.retcode) - conn->state = ISCSI_CONN_UP; - mutex_unlock(&conn_mutex); - } - else - err = -EINVAL; - break; + case ISCSI_UEVENT_CREATE_CONN: + case ISCSI_UEVENT_DESTROY_CONN: case ISCSI_UEVENT_STOP_CONN: - conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); - if (conn) - iscsi_if_stop_conn(conn, ev->u.stop_conn.flag); - else - err = -EINVAL; - break; + case ISCSI_UEVENT_START_CONN: + case ISCSI_UEVENT_BIND_CONN: case ISCSI_UEVENT_SEND_PDU: - pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); - - if ((ev->u.send_pdu.hdr_size > pdu_len) || - (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) { - err = -EINVAL; - break; - } - - conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid); - if (conn) { - mutex_lock(&conn_mutex); - ev->r.retcode = transport->send_pdu(conn, - (struct iscsi_hdr*)((char*)ev + sizeof(*ev)), - (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size, - ev->u.send_pdu.data_size); - mutex_unlock(&conn_mutex); - } - else - err = -EINVAL; + err = iscsi_if_transport_conn(transport, nlh); break; case ISCSI_UEVENT_GET_STATS: err = iscsi_if_get_stats(transport, nlh); @@ -4805,10 +4888,10 @@ static __init int iscsi_transport_init(void) goto release_nls; } - iscsi_destroy_workq = alloc_workqueue("%s", - WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, - 1, "iscsi_destroy"); - if (!iscsi_destroy_workq) { + iscsi_conn_cleanup_workq = alloc_workqueue("%s", + WQ_SYSFS | WQ_MEM_RECLAIM | WQ_UNBOUND, 0, + "iscsi_conn_cleanup"); + if (!iscsi_conn_cleanup_workq) { err = -ENOMEM; goto destroy_wq; } @@ -4838,7 +4921,7 @@ static __init int iscsi_transport_init(void) static void __exit iscsi_transport_exit(void) { - destroy_workqueue(iscsi_destroy_workq); + destroy_workqueue(iscsi_conn_cleanup_workq); destroy_workqueue(iscsi_eh_timer_workq); netlink_kernel_release(nls); bus_unregister(&iscsi_flashnode_bus); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f0c0935d7909..540bcda7264b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * sd.c Copyright (C) 1992 Drew Eckhardt @@ -73,6 +76,36 @@ #include "scsi_priv.h" #include "scsi_logging.h" +#ifdef MY_ABC_HERE +#include +#endif + +#if defined(MY_ABC_HERE) +#include +#include "../usb/storage/usb.h" +#include + +#ifdef CONFIG_SYNO_VIRTIO_SCSI_DEVICE +#include +#endif /* CONFIG_SYNO_VIRTIO_SCSI_DEVICE */ + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_NOTICE +#endif +#endif /* MY_ABC_HERE */ + MODULE_AUTHOR("Eric Youngdale"); MODULE_DESCRIPTION("SCSI disk (sd) driver"); MODULE_LICENSE("GPL"); @@ -104,6 +137,22 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); #define SD_MINORS 0 #endif +#ifdef MY_DEF_HERE +struct SpinupQueue { + spinlock_t q_lock; + unsigned int q_id; + atomic_t q_spinup_quota; + struct list_head q_disk_list; + struct list_head q_head; +}; + +LIST_HEAD(SpinupListHead); +DEFINE_SPINLOCK(SpinupListLock); + +#define MAX_ALLOWED_SPINUP_NUM 12 +atomic_t gSpinupCmdNum = ATOMIC_INIT(0); +#endif /* MY_DEF_HERE */ + static void sd_config_discard(struct scsi_disk *, unsigned int); static void sd_config_write_same(struct scsi_disk *); static int sd_revalidate_disk(struct gendisk *); @@ -124,6 +173,22 @@ static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); static void scsi_disk_release(struct device *cdev); static DEFINE_IDA(sd_index_ida); +#ifdef MY_ABC_HERE +static DEFINE_IDA(usb_index_ida); +static DEFINE_IDA(sata_index_ida); +#ifdef MY_ABC_HERE +static DEFINE_IDA(iscsi_index_ida); +#endif +#ifdef MY_DEF_HERE +static DEFINE_IDA(sas_index_ida); +extern int g_is_sas_model; +#endif /* MY_DEF_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void syno_disk_paraldown_wait_inc(void); +extern void syno_disk_paraldown_wait_dec(void); +#endif /* MY_ABC_HERE */ /* This semaphore is used to mediate the 0->1 reference get in the * face of object destruction (i.e. we can't allow a get on an @@ -251,6 +316,353 @@ manage_start_stop_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(manage_start_stop); +#ifdef MY_DEF_HERE + +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG +static void +SpinupQueueDump(struct SpinupQueue *q) +{ + struct scsi_device *d; + + printk(" QUEUE %d:\n", q->q_id); + list_for_each_entry(d, &(q->q_disk_list), spinup_list) { + printk(" disk [%d]\n", d->id); + } +} + +static void +SpinupQueueDumpAll(void) +{ + struct SpinupQueue *q; + + printk(" -------- queue dump\n"); + list_for_each_entry(q, &SpinupListHead, q_head) { + SpinupQueueDump(q); + } + printk(" ======== queue dump\n"); +} +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + +/** + * + * Must be called with lock held. + */ +static struct SpinupQueue * +SpinupQueueFindById(unsigned int id) +{ + struct SpinupQueue *q; + + list_for_each_entry(q, &SpinupListHead, q_head) { + if (q->q_id == id) { + return q; + } + } + return NULL; +} + +/** + * + * Must be called with lock held. + */ +static struct SpinupQueue * +SpinupQueueAlloc(unsigned int id) +{ + struct SpinupQueue *qNew; + + /* TODO check parameter */ + + qNew = kmalloc(sizeof(struct SpinupQueue), GFP_ATOMIC); + if (NULL == qNew) { + printk(" == Failed to alloc memory queue for id %d\n", id); + return qNew; + } + INIT_LIST_HEAD(&(qNew->q_disk_list)); + INIT_LIST_HEAD(&(qNew->q_head)); + qNew->q_id = id; + spin_lock_init(&(qNew->q_lock)); + if (syno_is_hw_version(HW_HD3400) || syno_is_hw_version(HW_HD6500)) { + atomic_set(&(qNew->q_spinup_quota), 15); /* Maximum 15 HDD hibernation wake (spin-up) due to power consumption concern */ + } else { + atomic_set(&(qNew->q_spinup_quota), 4); /* TODO set to some changable default value */ + } + +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + printk(" == add queue %p for id %d\n", qNew, id); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + return qNew; +} + +static int +SpinupQueueDiskAdd(struct SpinupQueue *sq, struct scsi_device *sd) +{ + unsigned long flags; + + spin_lock_irqsave(&(sq->q_lock), flags); + + list_add_tail(&(sd->spinup_list), &(sq->q_disk_list)); + sd->spinup_queue = sq; + + spin_unlock_irqrestore(&(sq->q_lock), flags); + return 0; +} + +static int +SpinupQueueDiskRemove(struct SpinupQueue *pSQ, struct scsi_device *pSD) +{ + unsigned long flags; + + if (NULL == pSD->spinup_queue) { + return 0; + } + spin_lock_irqsave(&(pSQ->q_lock), flags); + + BUG_ON(pSQ != pSD->spinup_queue); + + list_del(&(pSD->spinup_list)); + pSD->spinup_queue = NULL; + + spin_unlock_irqrestore(&(pSQ->q_lock), flags); + return 0; +} + +static int +SpinupQueueSet(struct scsi_device *sdp, unsigned int new_id) +{ + int iRet = -1; + unsigned int old_id; + struct SpinupQueue *qOld; + struct SpinupQueue *qNew; + + unsigned long flags; + + /* lock */ + spin_lock_irqsave(&SpinupListLock, flags); + + old_id = sdp->spinup_queue_id; + + if (old_id == new_id) { + /* No change. Do nothing. */ + iRet = 0; + goto END; + } + /* If it was in another queue, remove first. */ + if (NULL != sdp->spinup_queue) { + unsigned long flags_sd; + +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, sdp, " = remove disk from queue %d\n", + sdp->spinup_queue->q_id); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + /* delete disk from old list */ + qOld = sdp->spinup_queue; + BUG_ON(NULL == qOld); + SpinupQueueDiskRemove(qOld, sdp); + + /* Delete the queue if it is empty */ + spin_lock_irqsave(&(qOld->q_lock), flags_sd); + if (list_empty(&(qOld->q_disk_list))) { + list_del(&(qOld->q_head)); + } + spin_unlock_irqrestore(&(qOld->q_lock), flags_sd); + } + if (new_id) { /* Want to be added to a new queue */ +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, sdp, " = add disk to queue %d\n", + new_id); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + + /* Find list of the given id */ + + qNew = SpinupQueueFindById(new_id); + /* if not found, create a new list for this id. */ + if (NULL == qNew) { + /* alloc & init */ + qNew = SpinupQueueAlloc(new_id); + if (NULL == qNew) { + iRet = -ENOMEM; + goto END; + } + /* Insert into queue list */ + list_add_tail( &(qNew->q_head), &SpinupListHead); + } + /* then add self into disk list of queue. */ + SpinupQueueDiskAdd(qNew, sdp); + + } + sdp->spinup_queue_id = new_id; + +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + SpinupQueueDumpAll(); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + iRet = 0; +END: + /* TODO create queue, add to existing queue, or remove queue */ + spin_unlock_irqrestore(&SpinupListLock, flags); + return iRet; + +} + +static ssize_t +spinup_queue_id_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + + return snprintf(buf, 20, "%u\n", sdp->spinup_queue_id); +} + +static ssize_t +spinup_queue_id_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + unsigned int new_id; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + new_id = simple_strtoul(buf, NULL, 10); + + if (0 != SpinupQueueSet(sdp, new_id)) { + return -ENOMEM; + } + + return count; +} +static DEVICE_ATTR_RW(spinup_queue_id); + +/** + * + * Check if disk can spin up, and log spinup status. + * + * To be called from scsi midlayer to reflect spinup status. + * + * Return: + * - 1 if caller can spinup disk + * - 0 if caller must not spin up disk. + */ +int +SynoSpinupBegin(struct scsi_device *device) +{ + int ret = 0; + struct SpinupQueue *q = NULL; + unsigned long flags; + + /* Only handle disks that has been added to queue. */ + if (device && device->spinup_queue) { + q = device->spinup_queue; + } + if (NULL == q) { + goto Return; + } + spin_lock_irqsave(&(q->q_lock), flags); + /* Check if this disk is spinning up */ + if (device->spinup_in_process) { + /* Already spinning up. */ + if (jiffies - device->spinup_timer > SYNO_SPINUP_RESEND_TIMER) { +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, device, "Retry spinup disk...\n"); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + device->spinup_timer = jiffies; + ret = 1; + } + goto Return; + } + /* Atomic dec */ + if (atomic_read(&(q->q_spinup_quota))) { + atomic_dec(&(q->q_spinup_quota)); + } else { +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, device, "No quota to spinup disk...\n"); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + /* No quota to spin up more disks. Just let it retry. */ + goto Return; + } + +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, device, "Spinup disk...\n"); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + device->spinup_in_process = 1; + device->spinup_timer = jiffies; + + /* caller can spin up disk now. */ + ret = 1; +Return: + if (NULL != q) { + spin_unlock_irqrestore(&(q->q_lock), flags); + } + return ret; +} + + +/** + * Clean up spinup status. + * + * Called from SCSI midlayer when spinup is done. + */ +void SynoSpinupEnd(struct scsi_device *sdev) +{ + struct SpinupQueue *q = NULL; + unsigned long flags; + + if (sdev && sdev->spinup_queue) { + q = sdev->spinup_queue; + } + + if(NULL == q) { + goto Return; + } + + spin_lock_irqsave(&(q->q_lock), flags); + if (sdev->spinup_in_process == 0) { +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, sdev, "Spinup should be done already. Q %d remaining %d \n", + sdev->spinup_queue_id, + atomic_read(&(q->q_spinup_quota))); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + goto Return; + } + +#ifdef MY_DEF_HERE + /* + * Clearing the standby flag if START_STOP is success or fail time over threshold. + * Device may be in error state(e.g. removed) and START_STOP may never successed. + * + * Even if it failed many times, we unblock the other I/O command and let them fail, after that we can + * do the corresponding action, like waking up the disk agagin. + */ + clear_bit(0, &sdev->sas_sata_standby_flag); +#endif /* MY_DEF_HERE */ + + atomic_inc(&(q->q_spinup_quota)); + sdev->spinup_in_process = 0; +#ifdef CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG + sdev_printk(KERN_ERR, sdev, "Spinup done. Q %d remaining %d \n", + sdev->spinup_queue_id, + atomic_read(&(q->q_spinup_quota))); +#endif /* CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG */ + +Return: + if (NULL != q) { + spin_unlock_irqrestore(&(q->q_lock), flags); + } +} + +int SynoSpinupRemove(struct scsi_device *sdev) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&SpinupListLock, flags); + ret = SpinupQueueDiskRemove(sdev->spinup_queue, sdev); + spin_unlock_irqrestore(&SpinupListLock, flags); + + return ret; +} +#endif /* MY_DEF_HERE */ + static ssize_t allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -299,7 +711,41 @@ FUA_show(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%u\n", sdkp->DPOFUA); } + +#ifdef MY_ABC_HERE +static ssize_t +FUA_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + bool v; + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct request_queue *q = sdkp->disk->queue; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (kstrtobool(buf, &v)) + return -EINVAL; + + if (v) { + if (!sdkp->support_fua || !test_bit(QUEUE_FLAG_WC, &q->queue_flags)) { + return -EOPNOTSUPP; + } + + sdkp->DPOFUA = 1; + blk_queue_flag_set(QUEUE_FLAG_FUA, q); + } else { + sdkp->DPOFUA = 0; + blk_queue_flag_clear(QUEUE_FLAG_FUA, q); + } + + return count; +} + +static DEVICE_ATTR_RW(FUA); +#else /* MY_ABC_HERE */ static DEVICE_ATTR_RO(FUA); +#endif /* MY_ABC_HERE */ static ssize_t protection_type_show(struct device *dev, struct device_attribute *attr, @@ -581,6 +1027,9 @@ static struct attribute *sd_disk_attrs[] = { &dev_attr_FUA.attr, &dev_attr_allow_restart.attr, &dev_attr_manage_start_stop.attr, +#ifdef MY_DEF_HERE + &dev_attr_spinup_queue_id.attr, +#endif /* MY_DEF_HERE */ &dev_attr_protection_type.attr, &dev_attr_protection_mode.attr, &dev_attr_app_tag_own.attr, @@ -1587,6 +2036,25 @@ static int sd_ioctl_common(struct block_device *bdev, fmode_t mode, case SCSI_IOCTL_GET_BUS_NUMBER: error = scsi_ioctl(sdp, cmd, p); break; +#ifdef MY_ABC_HERE + case SD_IOCTL_IDLE: + return (jiffies - sdp->last_accessed) / HZ + 1; + case SD_IOCTL_SUPPORT_SLEEP: + { + const int iCanSleep = sdp->nospindown ? 0 : 1; + if (copy_to_user(p, &iCanSleep, sizeof(iCanSleep))) { + return -EINVAL; + } + return 0; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + case SD_IOCTL_SASHOST_DISK_LED: + if (NULL == sdp->host->hostt->syno_set_sashost_disk_led){ + break; + } + return sdp->host->hostt->syno_set_sashost_disk_led(sdp, (unsigned long)p); +#endif /* MY_DEF_HERE */ default: error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); break; @@ -2849,6 +3317,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->DPOFUA = 0; } +#ifdef MY_ABC_HERE + sdkp->support_fua = sdkp->DPOFUA; + if (sdp->default_disable_fua && !old_dpofua) { + sdkp->DPOFUA = 0; + } +#endif /* MY_ABC_HERE */ + /* No cache flush allowed for write protected devices */ if (sdkp->WCE && sdkp->write_prot) sdkp->WCE = 0; @@ -2859,8 +3334,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) "Write cache: %s, read cache: %s, %s\n", sdkp->WCE ? "enabled" : "disabled", sdkp->RCD ? "disabled" : "enabled", +#ifdef MY_ABC_HERE + sdkp->support_fua ? "supports DPO and FUA" + : "doesn't support DPO or FUA"); +#else /* MY_ABC_HERE */ sdkp->DPOFUA ? "supports DPO and FUA" : "doesn't support DPO or FUA"); +#endif /* MY_ABC_HERE */ return; } @@ -2935,6 +3415,37 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) return; } +#ifdef MY_ABC_HERE +/** + * syno_get_ata_identity - Get ATA IDENTITY via ATA PASS-THRU command + * @sdev: the disk you want to get ata identity + * @id: ata identity result will stored in here + * + * return 0: if it's SAS disk or failed + * 1: success + */ +int +syno_get_ata_identity(struct scsi_device *sdev, u16 *id) +{ + unsigned char scsi_cmd[MAX_COMMAND_SIZE] = {0}; + + /* ATA IDENTIFY DEVICE via ATA PASS-THRU(16)*/ + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = 0x08; /* PIO Data-in */ + scsi_cmd[2] = 0x0e; /* T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + scsi_cmd[14] = ATA_CMD_ID_ATA; + + /* if it's SAS disk, ATA PASS-THRU will fail. Return -1 */ + if (scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + id, 512, NULL, 10 * HZ, 5, NULL)) { + return 0; + } + + return 1; +} +EXPORT_SYMBOL(syno_get_ata_identity); +#endif /* MY_ABC_HERE */ + /** * sd_read_block_limits - Query disk device for preferred I/O sizes. * @sdkp: disk to query @@ -2984,12 +3495,20 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) sd_config_discard(sdkp, SD_LBP_WS16); } else { /* LBP VPD page tells us what to use */ +#ifdef MY_ABC_HERE + if (sdkp->lbpu && sdkp->max_unmap_blocks && !sdkp->lbprz) +#else if (sdkp->lbpu && sdkp->max_unmap_blocks) +#endif sd_config_discard(sdkp, SD_LBP_UNMAP); else if (sdkp->lbpws) sd_config_discard(sdkp, SD_LBP_WS16); else if (sdkp->lbpws10) sd_config_discard(sdkp, SD_LBP_WS10); +#ifdef MY_ABC_HERE + else if (sdkp->lbpu && sdkp->max_unmap_blocks) + sd_config_discard(sdkp, SD_LBP_UNMAP); +#endif else sd_config_discard(sdkp, SD_LBP_DISABLE); } @@ -3211,7 +3730,22 @@ static int sd_revalidate_disk(struct gendisk *disk) goto out; } +#ifdef MY_DEF_HERE + if (1 == g_is_sas_model) { + /* Too much spin up cmd, wait here */ + while (MAX_ALLOWED_SPINUP_NUM < atomic_read(&(gSpinupCmdNum))) { + msleep(1000); + } + + atomic_inc(&(gSpinupCmdNum)); + sd_spinup_disk(sdkp); + atomic_dec(&(gSpinupCmdNum)); + } else { +#endif /* MY_DEF_HERE */ sd_spinup_disk(sdkp); +#ifdef MY_DEF_HERE + } +#endif /* MY_DEF_HERE */ /* * Without media there is no reason to ask; moreover, some devices @@ -3318,6 +3852,339 @@ static void sd_unlock_native_capacity(struct gendisk *disk) sdev->host->hostt->unlock_native_capacity(sdev); } +#ifdef MY_ABC_HERE +#define IS_SYNO_OOBUSB_ID_VENDOR(VENDOR) (0xF400 == (VENDOR)) +#define IS_SYNO_OOBUSB_ID_PRODUCT(PRODUCT) (0xF425 == (PRODUCT)) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * We use 0xF400 as synoboot device + */ +#define IS_SYNO_USBBOOT_ID_VENDOR(VENDOR) (0xF400 == (VENDOR)) +#define IS_SYNO_USBBOOT_ID_PRODUCT(PRODUCT) (0xF400 == (PRODUCT)) + +static bool syno_find_synoboot(void) +{ + bool find = false; + struct scsi_disk *sdisk = NULL; + struct class_dev_iter iter; + struct device *dev; + + class_dev_iter_init(&iter, &sd_disk_class, NULL, NULL); + dev = class_dev_iter_next(&iter); + while (dev) { + if (!dev->parent) { + dev = class_dev_iter_next(&iter); + continue; + } + sdisk = dev_get_drvdata(dev->parent); + if (sdisk && sdisk->disk) { + if (0 == strcmp(CONFIG_SYNO_USB_FLASH_DEVICE_NAME, sdisk->disk->disk_name)) { + find = true; + goto OUT; + } + } + dev = class_dev_iter_next(&iter); + } +OUT: + class_dev_iter_exit(&iter); + return find; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static SYNO_DISK_TYPE syno_disk_type_get(struct scsi_device *sdp) +{ +#ifdef MY_ABC_HERE + // iscsi + if (0 == strcmp(sdp->host->hostt->name, "iSCSI Initiator over TCP/IP")) { + return SYNO_DISK_ISCSI; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if(0 == strcmp(sdp->host->hostt->name, "TCM_Loopback")){ + return SYNO_DISK_ISCSI; + } +#endif /* MY_ABC_HERE */ + + if (SYNO_PORT_TYPE_USB == sdp->host->hostt->syno_port_type) { +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + struct us_data *us = host_to_us(sdp->host); + struct usb_device *usbdev = us->pusb_dev; + //Since the UAS doesn't has the us_data structure , the us will be NULL , avoid the NULL pointer accessing + if (NULL == us) { + return SYNO_DISK_USB; + } + if (NULL == usbdev) { + return SYNO_DISK_USB; + } +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (IS_SYNO_USBBOOT_ID_VENDOR(le16_to_cpu(usbdev->descriptor.idVendor)) && + IS_SYNO_USBBOOT_ID_PRODUCT(le16_to_cpu(usbdev->descriptor.idProduct))) { + if (!syno_find_synoboot()) { + return SYNO_DISK_SYNOBOOT; + } + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (IS_SYNO_OOBUSB_ID_VENDOR(le16_to_cpu(usbdev->descriptor.idVendor)) && + IS_SYNO_OOBUSB_ID_PRODUCT(le16_to_cpu(usbdev->descriptor.idProduct))) { + return SYNO_DISK_OOB; + } +#endif /* MY_ABC_HERE */ + + return SYNO_DISK_USB; + } +#ifdef CONFIG_SYNO_VIRTIO_SCSI_DEVICE + /* virtio-scsi */ + if (strcmp(sdp->host->hostt->name, "Virtio SCSI HBA") == 0) { + struct device *virtdev = sdp->host->shost_gendev.parent; + struct pci_dev *pcidev = NULL; + while (virtdev) { + if (virtdev->driver && virtdev->driver->name && !strcmp(virtdev->driver->name, "virtio-pci")) { + pcidev = to_pci_dev(virtdev); + break; + } + virtdev = virtdev->parent; + } + if (pcidev && PCI_SLOT(pcidev->devfn) == CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT) { + return SYNO_DISK_SYNOBOOT; + } + return SYNO_DISK_VIRTIO_SCSI; + } +#endif /* CONFIG_SYNO_VIRTIO_SCSI_DEVICE */ + + if (SYNO_PORT_TYPE_SATA == sdp->host->hostt->syno_port_type) { + return SYNO_DISK_SATA; + } + +#ifdef MY_DEF_HERE + //sas disks + if (SYNO_PORT_TYPE_SAS == sdp->host->hostt->syno_port_type) { + return SYNO_DISK_SAS; + } +#endif /* MY_DEF_HERE */ + + return SYNO_DISK_UNKNOWN; +} + +/** + * syno_sd_format_numeric_disk_name - format numeric disk name + * + * @prefix: name prefix - ie. "sas" for SAS disks + * @synoindex: index of the disk to format name for + * @buf: output buffer + * @buflen: length of the output buffer + * + * Numeric disk names starts at 1. Take SAS disk as examplr, the 26th device is sas26 and the + * 27th is sas27. + * + * CONTEXT: + * Don't care. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int syno_sd_format_numeric_disk_name(char *prefix, int synoindex, char *buf, int buflen) +{ + int synoindex_digits = 0; + int var = synoindex + 1; + + while (var != 0) { + var /= 10; + synoindex_digits++; + } + + // Full disk name lenth must less or equal to buflen (e.g., Full disk name = "SAS" + "1~XXXX" + "\0") + // + if (buflen <= (strlen(prefix) + synoindex_digits + 1)) { + return -EINVAL; + } + + if (snprintf(buf, buflen, "%s%d", prefix, synoindex + 1) <= 0) { + return -EINVAL; + } + + return 0; +} + +static int syno_sd_format_disk_name(struct scsi_device *sdp, struct scsi_disk *sdkp, struct gendisk *gd) +{ + int ret = -1; + struct ida *syno_disk_type_ida = NULL; + char *syno_disk_type_prefix = NULL; + int syno_index = 0; + + /* Initialize default value of synoindex and synodisktype. It means getting index fail */ + sdkp->synoindex = UINT_MAX; + sdkp->synodisktype = SYNO_DISK_UNKNOWN; + + sdkp->synodisktype = syno_disk_type_get(sdp); + switch (sdkp->synodisktype) { +#ifdef MY_ABC_HERE + /* XXX + Special Case 1: we assume synoboot will be plugged only once. + No need to use ida, just format fixed device name and return pass. + */ + case SYNO_DISK_SYNOBOOT: + sprintf(gd->disk_name, CONFIG_SYNO_USB_FLASH_DEVICE_NAME); + sdkp->synoindex = CONFIG_SYNO_USB_FLASH_DEVICE_INDEX; + ret = 0; + goto out_put; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* XXX + Special Case 2: OOB use fixed device name. + */ + case SYNO_DISK_OOB: + sprintf(gd->disk_name, CONFIG_SYNO_OOB_LOG_DEVICE_NAME); + ret = 0; + goto out_put; +#endif /* MY_ABC_HERE */ + case SYNO_DISK_USB: + syno_disk_type_ida = &usb_index_ida; + syno_disk_type_prefix = CONFIG_SYNO_USB_DEVICE_PREFIX; + break; + case SYNO_DISK_SATA: + syno_disk_type_ida = &sata_index_ida; + syno_disk_type_prefix = CONFIG_SYNO_SATA_DEVICE_PREFIX; + break; +#ifdef MY_ABC_HERE + case SYNO_DISK_ISCSI: + syno_disk_type_ida = &iscsi_index_ida; + syno_disk_type_prefix = CONFIG_SYNO_ISCSI_DEVICE_PREFIX; + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + case SYNO_DISK_SAS: + syno_disk_type_ida = &sas_index_ida; + syno_disk_type_prefix = CONFIG_SYNO_SAS_DEVICE_PREFIX; + break; +#endif /* MY_DEF_HERE */ +#ifdef CONFIG_SYNO_VIRTIO_SCSI_DEVICE + case SYNO_DISK_VIRTIO_SCSI: + syno_disk_type_ida = &sata_index_ida; + syno_disk_type_prefix = CONFIG_SYNO_SATA_DEVICE_PREFIX; + break; +#endif /* CONFIG_SYNO_VIRTIO_SCSI_DEVICE */ + + default: + sdev_printk(KERN_ERR, sdp, "sd_probe: unknown type %d.\n", sdkp->synodisktype); + ret = -EINVAL; + goto out_put; + } + + syno_index = ida_alloc(syno_disk_type_ida, GFP_KERNEL); + if (syno_index < 0) { + sdev_printk(KERN_WARNING, sdp, "sd_probe: memory exhausted when alloc %s disk.\n", syno_disk_type_prefix); + ret = -ENOMEM; + goto out_put; + } + + ret = syno_sd_format_numeric_disk_name(syno_disk_type_prefix, syno_index, gd->disk_name, DISK_NAME_LEN); + if (ret < 0) { + sdev_printk(KERN_WARNING, sdp, "SCSI disk name length exceeded.\n"); + goto out_put; + } + + sdev_printk(KERN_WARNING, sdp, "got %s disk[%d]\n", syno_disk_type_prefix, syno_index); + sdkp->synoindex = syno_index; + + ret = 0; + +out_put: + return ret; +} + +static void syno_ida_free(struct scsi_disk *sdkp) +{ + if (sdkp == NULL) { + return; + } + + /* Get index fail, don't free */ + if (sdkp->synoindex == UINT_MAX) { + return; + } + + switch (sdkp->synodisktype) { +#ifdef MY_ABC_HERE + case SYNO_DISK_ISCSI: + ida_free(&iscsi_index_ida, sdkp->synoindex); + break; +#endif /* MY_ABC_HERE */ + case SYNO_DISK_USB: + ida_free(&usb_index_ida, sdkp->synoindex); + break; + case SYNO_DISK_SATA: + ida_free(&sata_index_ida, sdkp->synoindex); + break; +#ifdef MY_DEF_HERE + case SYNO_DISK_SAS: + ida_free(&sas_index_ida, sdkp->synoindex); + break; +#endif /* MY_DEF_HERE */ + + default: + break; + } +} + +static int SynoSCSIGetDeviceIndex(struct gendisk *pDisk) +{ + BUG_ON(NULL == pDisk); + + return container_of(pDisk->private_data, struct scsi_disk, driver)->synoindex; +} + +int SynoScsiDeviceToDiskIndex(const struct scsi_device *psdev) +{ + struct scsi_disk *psdisk = NULL; + + if (!psdev || TYPE_DISK != psdev->type) { + return -1; + } + + psdisk = dev_get_drvdata(&psdev->sdev_gendev); + if (NULL == psdisk) { + return -1; + } + + return psdisk->synoindex; +} +EXPORT_SYMBOL(SynoScsiDeviceToDiskIndex); + +/** + * We established disk health prediction rule fot SAS at DSM#137866, DSM#106198 + * It only considers device types with SAS, SATA and NVC + * + * @param scsi_device + * @return Check if it belongs to physical drive(HDD, SSD..) + **/ +bool SynoIsPhysicalDrive(const struct scsi_device *psdev) +{ + bool ret = false; + struct scsi_disk *psdisk = NULL; + if (!psdev || TYPE_DISK != psdev->type) { + goto END; + } + + psdisk = dev_get_drvdata(&psdev->sdev_gendev); + if (NULL == psdisk) { + goto END; + } + + if(SYNO_DISK_SATA == psdisk->synodisktype + || SYNO_DISK_SAS == psdisk->synodisktype) { + ret = true; + } +END: + return ret; +} +EXPORT_SYMBOL(SynoIsPhysicalDrive); +#else /* MY_ABC_HERE */ /** * sd_format_disk_name - format disk name * @prefix: name prefix - ie. "sd" for SCSI disks @@ -3364,6 +4231,48 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) return 0; } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static bool syno_is_scsi_device_disappear(struct gendisk *disk) +{ + struct scsi_disk *sdkp; + bool ret = false; + + /* is whole disk */ + sdkp = container_of(disk->private_data, struct scsi_disk, driver); + if (!sdkp) { + WARN_ON(!sdkp); + goto END; + } + + switch (sdkp->device->sdev_state) { + case SDEV_OFFLINE: + case SDEV_DEL: + case SDEV_CANCEL: + ret = true; + break; + default: + break; + } +END: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static const struct syno_gendisk_operations syno_scsi_gd_ops = { +#ifdef MY_ABC_HERE + .get_device_index = SynoSCSIGetDeviceIndex, +#else /* MY_ABC_HERE */ + .get_device_index = NULL, +#endif /* ONFIG_SYNO_PORT_MAPPING_V2 */ +#ifdef MY_ABC_HERE + .is_device_disappear = syno_is_scsi_device_disappear, +#endif /* MY_ABC_HERE */ +}; +#endif /* MY_ABC_HERE */ + /** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once @@ -3420,11 +4329,34 @@ static int sd_probe(struct device *dev) goto out_put; } +#if defined(MY_ABC_HERE) + error = syno_sd_format_disk_name(sdp, sdkp, gd); + if (error) { + goto out_free_index; + } + + /* + * fill syno_block_info if syno_sdev_info_enum exist + */ + if (NULL != sdp->host->hostt->syno_sdev_info_enum) { + sdp->host->hostt->syno_sdev_info_enum(sdp); + } +#else /* MY_ABC_HERE */ error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); if (error) { sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n"); goto out_free_index; } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + sdp->last_accessed = jiffies; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + sdp->nospindown = 0; + sdp->spindown = 0; + sdp->do_standby_syncing = 0; +#endif /* MY_ABC_HERE */ sdkp->device = sdp; sdkp->driver = &sd_template; @@ -3434,13 +4366,19 @@ static int sd_probe(struct device *dev) atomic_set(&sdkp->openers, 0); atomic_set(&sdkp->device->ioerr_cnt, 0); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ if (!sdp->request_queue->rq_timeout) { +#endif /* MY_ABC_HERE */ if (sdp->type != TYPE_MOD) blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT); else blk_queue_rq_timeout(sdp->request_queue, SD_MOD_TIMEOUT); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ } +#endif /* MY_ABC_HERE */ device_initialize(&sdkp->dev); sdkp->dev.parent = dev; @@ -3461,6 +4399,14 @@ static int sd_probe(struct device *dev) gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; +#ifdef MY_ABC_HERE + gd->syno_ops = &syno_scsi_gd_ops; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + strlcpy(sdp->syno_disk_name, gd->disk_name, BDEVNAME_SIZE); +#endif /* MY_ABC_HERE */ + /* defaults, until the device tells us otherwise */ sdp->sector_size = 512; sdkp->capacity = 0; @@ -3506,6 +4452,9 @@ static int sd_probe(struct device *dev) return 0; out_free_index: +#ifdef MY_ABC_HERE + syno_ida_free(sdkp); +#endif /* MY_ABC_HERE */ ida_free(&sd_index_ida, index); out_put: put_disk(gd); @@ -3570,6 +4519,9 @@ static void scsi_disk_release(struct device *dev) struct gendisk *disk = sdkp->disk; struct request_queue *q = disk->queue; +#ifdef MY_ABC_HERE + syno_ida_free(sdkp); +#endif /* MY_ABC_HERE */ ida_free(&sd_index_ida, sdkp->index); /* @@ -3627,6 +4579,25 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start) return 0; } +#ifdef MY_ABC_HERE +static void syno_disk_paraldown_workfn(struct work_struct *work) +{ + struct scsi_disk *sdkp; + + sdkp = container_of(work, struct scsi_disk, syno_disk_paraldown); + + sd_printk(KERN_NOTICE, sdkp, "Spindown disk start\n"); + + if (sd_start_stop_device(sdkp, 0) == 0) { + sd_printk(KERN_NOTICE, sdkp, "Spindown disk complete\n"); + } else { + sd_printk(KERN_NOTICE, sdkp, "Error : Spindown disk failed\n"); + } + + syno_disk_paraldown_wait_dec(); +} +#endif /* MY_ABC_HERE */ + /* * Send a SYNCHRONIZE CACHE instruction down to the device through * the normal SCSI command structure. Wait for the command to @@ -3648,9 +4619,39 @@ static void sd_shutdown(struct device *dev) } if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) { +#ifdef MY_ABC_HERE + if (system_state == SYSTEM_POWER_OFF) { + // System shutdown + syno_disk_paraldown_wait_inc(); + INIT_WORK(&sdkp->syno_disk_paraldown, syno_disk_paraldown_workfn); + schedule_work(&sdkp->syno_disk_paraldown); + } else { + // Disk unplug, or Deep Sleep + sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); + sd_start_stop_device(sdkp, 0); + } +#else sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); sd_start_stop_device(sdkp, 0); +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE + else if (system_state == SYSTEM_RESTART && sdkp->device->manage_start_stop) { + /* The models which support deep sleep will cut the power of sata port + * when reboot the machine, so issue STOP command before reboot */ + if (sdkp->device->power_loss_during_reboot) { +#ifdef MY_ABC_HERE + syno_disk_paraldown_wait_inc(); + INIT_WORK(&sdkp->syno_disk_paraldown, syno_disk_paraldown_workfn); + schedule_work(&sdkp->syno_disk_paraldown); +#else + sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); + sd_start_stop_device(sdkp, 0); +#endif /* MY_ABC_HERE */ + } + } +#endif /* MY_ABC_HERE */ + } static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) @@ -3723,6 +4724,9 @@ static int sd_resume(struct device *dev) return ret; } +#ifdef MY_DEF_HERE +struct workqueue_struct *spinup_workqueue = NULL; +#endif /* MY_DEF_HERE */ /** * init_sd - entry point for this driver (both when built in or when * a module). @@ -3776,6 +4780,13 @@ static int __init init_sd(void) if (err) goto err_out_driver; +#ifdef MY_DEF_HERE + spinup_workqueue = create_workqueue("spinup_wq"); + if (NULL == spinup_workqueue) { + printk(KERN_ERR "sd: can't init spinup_wq, fall back to global queue\n"); + } +#endif /* MY_DEF_HERE */ + return 0; err_out_driver: diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index b59136c4125b..58c29eb33f06 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _SCSI_DISK_H #define _SCSI_DISK_H @@ -12,7 +15,11 @@ /* * Time out in seconds for disks and Magneto-opticals (which are slower). */ +#if defined(MY_ABC_HERE) +#define SD_TIMEOUT (60 * HZ) +#else /* MY_ABC_HERE */ #define SD_TIMEOUT (30 * HZ) +#endif /* MY_ABC_HERE */ #define SD_MOD_TIMEOUT (75 * HZ) /* * Flush timeout is a multiplier over the standard device timeout which is @@ -26,7 +33,11 @@ */ #define SD_MAX_RETRIES 5 #define SD_PASSTHROUGH_RETRIES 1 +#ifdef MY_DEF_HERE +#define SD_MAX_MEDIUM_TIMEOUTS 1024 +#else #define SD_MAX_MEDIUM_TIMEOUTS 2 +#endif /* MY_DEF_HERE */ /* * Size of the initial data buffer for mode and read capacity data @@ -67,6 +78,22 @@ enum { SD_ZERO_WS10_UNMAP, /* Use WRITE SAME(10) with UNMAP */ }; +#ifdef MY_ABC_HERE +typedef enum __syno_disk_type { + SYNO_DISK_UNKNOWN = 0, + SYNO_DISK_SATA, + SYNO_DISK_USB, + SYNO_DISK_SYNOBOOT, + SYNO_DISK_ISCSI, + SYNO_DISK_SAS, + SYNO_DISK_VIRTIO_SCSI, +#ifdef MY_ABC_HERE + SYNO_DISK_OOB, +#endif /* MY_ABC_HERE */ + SYNO_DISK_END, // end of enum +} SYNO_DISK_TYPE; +#endif /* MY_ABC_HERE */ + struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; @@ -98,6 +125,10 @@ struct scsi_disk { u32 unmap_granularity; u32 unmap_alignment; u32 index; +#ifdef MY_ABC_HERE + SYNO_DISK_TYPE synodisktype; + u32 synoindex; +#endif /* MY_ABC_HERE */ unsigned int physical_block_size; unsigned int max_medium_access_timeouts; unsigned int medium_access_timed_out; @@ -125,6 +156,12 @@ struct scsi_disk { unsigned urswrz : 1; unsigned security : 1; unsigned ignore_medium_access_errors : 1; +#ifdef MY_ABC_HERE + struct work_struct syno_disk_paraldown; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned support_fua : 1; +#endif /* MY_ABC_HERE */ }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index c2afba2a5414..05947d4ba95d 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * SCSI Enclosure Services @@ -633,6 +636,9 @@ static int ses_intf_add(struct device *cdev, int num_enclosures; struct enclosure_device *edev; struct ses_component *scomp = NULL; +#ifdef MY_DEF_HERE + int retry_count = SES_RETRIES; +#endif /* MY_DEF_HERE */ if (!scsi_device_enclosure(sdev)) { /* not an enclosure, but might be in one */ @@ -655,7 +661,17 @@ static int ses_intf_add(struct device *cdev, goto err_init_free; page = 1; +#ifdef MY_DEF_HERE + retry_count = SES_RETRIES; + do { + result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE); + if (result) { + sdev_printk(KERN_ERR, sdev, "result(%x), page1 retry_count(%d)\n", result, retry_count); + } + } while (result && ((--retry_count) >= 0)); +#else /* MY_DEF_HERE */ result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE); +#endif /* MY_DEF_HERE */ if (result) goto recv_failed; @@ -664,7 +680,17 @@ static int ses_intf_add(struct device *cdev, if (!buf) goto err_free; +#ifdef MY_DEF_HERE + retry_count = SES_RETRIES; + do { + result = ses_recv_diag(sdev, page, buf, len); + if (result) { + sdev_printk(KERN_ERR, sdev, "result(%x), page1 retry_count(%d)\n", result, retry_count); + } + } while (result && ((--retry_count) >= 0)); +#else /* MY_DEF_HERE */ result = ses_recv_diag(sdev, page, buf, len); +#endif /* MY_DEF_HERE */ if (result) goto recv_failed; @@ -695,7 +721,17 @@ static int ses_intf_add(struct device *cdev, buf = NULL; page = 2; +#ifdef MY_DEF_HERE + retry_count = SES_RETRIES; + do { + result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE); + if (result) { + sdev_printk(KERN_ERR, sdev, "result(%x), page2 retry_count(%d)\n", result, retry_count); + } + } while (result && ((--retry_count) >= 0)); +#else /* MY_DEF_HERE */ result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE); +#endif /* MY_DEF_HERE */ if (result) goto page2_not_supported; @@ -703,9 +739,19 @@ static int ses_intf_add(struct device *cdev, buf = kzalloc(len, GFP_KERNEL); if (!buf) goto err_free; - +#ifdef MY_DEF_HERE + retry_count = SES_RETRIES; + do { + /* make sure getting page 2 actually works */ + result = ses_recv_diag(sdev, 2, buf, len); + if (result) { + sdev_printk(KERN_ERR, sdev, "result(%x), page2 retry_count(%d)\n", result, retry_count); + } + } while (result && ((--retry_count) >= 0)); +#else /* MY_DEF_HERE */ /* make sure getting page 2 actually works */ result = ses_recv_diag(sdev, 2, buf, len); +#endif /* MY_DEF_HERE */ if (result) goto recv_failed; ses_dev->page2 = buf; @@ -715,7 +761,14 @@ static int ses_intf_add(struct device *cdev, /* The additional information page --- allows us * to match up the devices */ page = 10; +#ifdef MY_DEF_HERE + retry_count = SES_RETRIES; + do { + result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE); + } while (result && ((--retry_count) >= 0)); +#else /* MY_DEF_HERE */ result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE); +#endif /* MY_DEF_HERE */ if (!result) { len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; @@ -723,7 +776,17 @@ static int ses_intf_add(struct device *cdev, if (!buf) goto err_free; +#ifdef MY_DEF_HERE + retry_count = SES_RETRIES; + do { + result = ses_recv_diag(sdev, page, buf, len); + if (result) { + sdev_printk(KERN_ERR, sdev, "result(%x), page10 retry_count(%d)\n", result, retry_count); + } + } while (result && ((--retry_count) >= 0)); +#else /* MY_DEF_HERE */ result = ses_recv_diag(sdev, page, buf, len); +#endif /* MY_DEF_HERE */ if (result) goto recv_failed; ses_dev->page10 = buf; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index bfa8d77322d7..83c89f44e2bf 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * History: @@ -2522,7 +2525,11 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) sdp = it ? sg_lookup_dev(it->index) : NULL; scsidp = sdp ? sdp->device : NULL; if (sdp && scsidp && (!atomic_read(&sdp->detaching))) +#ifdef MY_ABC_HERE + seq_printf(s, "%8.8s\t%"SYNO_DISK_MODEL_LEN"."SYNO_DISK_MODEL_LEN"s\t%4.4s\n", +#else /* MY_ABC_HERE */ seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n", +#endif /* MY_ABC_HERE */ scsidp->vendor, scsidp->model, scsidp->rev); else seq_puts(s, "\n"); diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index b9c86a7e3b97..c4bbacafdc88 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Virtio SCSI HBA driver @@ -30,6 +33,11 @@ #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ + #include "sd.h" #define VIRTIO_SCSI_MEMPOOL_SZ 64 @@ -738,6 +746,29 @@ static enum blk_eh_timer_return virtscsi_eh_timed_out(struct scsi_cmnd *scmnd) return BLK_EH_RESET_TIMER; } +#ifdef MY_ABC_HERE +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size); +static void syno_virtio_info_enum(struct scsi_device *sdev) { + struct pci_dev *pdev = NULL; + char sztemp[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + struct device *virtdev = sdev->host->shost_gendev.parent; + while (virtdev) { + if (virtdev->driver && virtdev->driver->name && !strcmp(virtdev->driver->name, "virtio-pci")) { + break; + } + virtdev = virtdev->parent; + } + + pdev = to_pci_dev(virtdev); + + if (-1 == syno_pciepath_dts_pattern_get(pdev, sztemp, sizeof(sztemp))) { + return; + } + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%spciepath=%s\n", sdev->syno_block_info, sztemp); + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%sdriver=%s\n", sdev->syno_block_info, DT_VIRTIO); +} +#endif /* MY_ABC_HERE */ + static struct scsi_host_template virtscsi_host_template = { .module = THIS_MODULE, .name = "Virtio SCSI HBA", @@ -755,6 +786,9 @@ static struct scsi_host_template virtscsi_host_template = { .dma_boundary = UINT_MAX, .map_queues = virtscsi_map_queues, .track_queue_depth = 1, +#ifdef MY_ABC_HERE + .syno_sdev_info_enum = syno_virtio_info_enum, +#endif /* MY_ABC_HERE */ }; #define virtscsi_config_get(vdev, fld) \ diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 425ab6f7e375..b093027f030a 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -11,6 +11,9 @@ source "drivers/soc/imx/Kconfig" source "drivers/soc/ixp4xx/Kconfig" source "drivers/soc/mediatek/Kconfig" source "drivers/soc/qcom/Kconfig" +if SYNO_LSP_RTD1619B +source "drivers/soc/realtek/Kconfig" +endif # SYNO_LSP_RTD1619B source "drivers/soc/renesas/Kconfig" source "drivers/soc/rockchip/Kconfig" source "drivers/soc/samsung/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 36452bed86ef..333f35034855 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -17,6 +17,9 @@ obj-$(CONFIG_SOC_XWAY) += lantiq/ obj-y += mediatek/ obj-y += amlogic/ obj-y += qcom/ +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_ARCH_REALTEK) += realtek/ +endif # CONFIG_SYNO_LSP_RTD1619B obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ diff --git a/drivers/soc/realtek/Kconfig b/drivers/soc/realtek/Kconfig new file mode 100644 index 000000000000..64aa34c42844 --- /dev/null +++ b/drivers/soc/realtek/Kconfig @@ -0,0 +1,59 @@ +menu "Realtek SoC drivers" + +menuconfig RTD13XX_RTK_CODEC + bool "Realtek RTD13XX Codec" + default n + help + Realtek RTD13XX codec support. + + If unsure, say N. + +config RTK_RESERVE_MEMORY + bool "RTK Reserve Memory for Video/Image Codec" + depends on ION_REALTEK && RTD13XX_RTK_CODEC + default n + +config RTD13XX_VE1_CODEC + bool "RTK Video Engine 1 Codec" + depends on RTD13XX_RTK_CODEC + default n + +config RTD13XX_IMAGE_CODEC + bool "RTK Image Codec" + depends on RTD13XX_RTK_CODEC + default n + +menuconfig RTD16XXB_RTK_CODEC + bool "Realtek RTD16XXB Codec" + default n + help + Realtek RTD16XXB codec support. + + If unsure, say N. + +config RTK_RESERVE_MEMORY + bool "RTK Reserve Memory for Video/Image Codec" + depends on ION_REALTEK && RTD16XXB_RTK_CODEC + default n + +config RTD16XXB_VE1_CODEC + bool "RTK Video Engine 1 Codec" + depends on RTD16XXB_RTK_CODEC + default n + +config RTD16XXB_IMAGE_CODEC + bool "RTK Image Codec" + depends on RTD16XXB_RTK_CODEC + default n + +config REALTEK_SOC + bool + depends on ARCH_REALTEK + default y + help + Realtek SoC drivers. + + If unsure, say N. + +source "drivers/soc/realtek/common/Kconfig" +endmenu diff --git a/drivers/soc/realtek/Makefile b/drivers/soc/realtek/Makefile new file mode 100644 index 000000000000..2cda236f549d --- /dev/null +++ b/drivers/soc/realtek/Makefile @@ -0,0 +1,5 @@ +obj-y += trace/ +obj-y += common/ +obj-y += rtd13xx/ +obj-y += rtd16xxb/ + diff --git a/drivers/soc/realtek/common/Kconfig b/drivers/soc/realtek/common/Kconfig new file mode 100644 index 000000000000..2864853e2486 --- /dev/null +++ b/drivers/soc/realtek/common/Kconfig @@ -0,0 +1,105 @@ + +config REALTEK_PM + tristate "Realtek power management driver" + default y + help + Suspend to RAM and shutdown support. + +config RTK_MCP + bool "Realtek MCP driver" + default n + help + Realtek MCP driver + +config RTK_SC_WRAP_FSS + bool "Realtek FSS Driver" + default n + help + This enable FSS control interface, if not sure say N. + +config RTK_USB_CTRL_MANAGER + tristate "RTK Multiple USB Host/Device Controller Manager" + default y if USB_OHCI_RTK || USB_EHCI_RTK || USB_DWC3_RTK + help + The Realtek chips are Multiple host/peripheral USB controllers. + Enable the driver to control clock, reset and usb power gpio. + +config REALTEK_CHIP_INFO + bool "Realtek SoC information" + default y + select SOC_BUS + help + The Realtek chips information. + +config RTK_FAN + bool "RTK Fan driver" + default n + help + Realtek Fan driver + +config RTK_FSS_SCAN + bool "Realtek FSS Scan Driver" + default n + help + This enable FSS Scan control interface, if not sure say N. + +config RTK_VCPU + bool "Realtek VCPU driver" + select DEVFREQ_GOV_USERSPACE if PM_DEVFREQ + default y + help + This enables Realtek VCPU driver. + +config RTK_VE3_UART + bool "Realtek VE3 uart driver" + default y + help + This enables Realtek VE3 Pseudo Uart driver. + +config RTK_WATCHDOG_STATUS + tristate "Realtek Watchdog Status Driver" + default n + help + This enables Realtek Watchdog Status Driver to show + information of hardware controlled watchdog. + +config RTK_GPIO_DEFAULT + bool "Realtek GPIO default setting driver" + default y + help + This enables Realtek GPIO default setting driver to set gpio default value. + +config RTK_VSFC_CTRL + bool "Realtek VSFC Controller" + depends on COMMON_CLK && REGULATOR + help + This enables Realtek VSFC controller + +config RTK_CPUHP_QOS + bool + +config RTK_CPUHP_CONTROL + bool "Realtek CPU Hotplug Controller" + select RTK_CPUHP_QOS + help + This enables Realtek CPU Hotplug Controller + +config RTK_CPU_VCLK + bool "Realtek CPU virtual Clock" + select RTK_CPUHP_QOS + help + This driver provides equivalent frequencies of CPU clocks. + +config RTK_BSV_CTRL + bool "Realtek BSV Controller for CPU DVFS" + help + This driver provides CPU voltage conversion based + on input frequency, if BSV OTP is valid. + +source "drivers/soc/realtek/common/rpc/Kconfig" +source "drivers/soc/realtek/common/mem_allocator/Kconfig" +source "drivers/soc/realtek/common/hse/Kconfig" +source "drivers/soc/realtek/common/rtk_pd/Kconfig" +source "drivers/soc/realtek/common/info/Kconfig" +source "drivers/soc/realtek/common/dvfs/Kconfig" +source "drivers/soc/realtek/common/buflock/Kconfig" diff --git a/drivers/soc/realtek/common/Makefile b/drivers/soc/realtek/common/Makefile new file mode 100644 index 000000000000..83180ccea147 --- /dev/null +++ b/drivers/soc/realtek/common/Makefile @@ -0,0 +1,52 @@ +obj-y += rtk_memory_remap.o +obj-y += rtk_crt.o +obj-y += rtk_refclk.o +obj-y += rtk_sb2.o +obj-y += rtk_sb2_dbg.o +obj-y += rtk_sb2_inv.o +obj-y += rtk_sb2_sem.o +obj-y += info/ +obj-y += dvfs/ +obj-y += rtk_bootstatus.o +obj-y += rtk_sc_wrap.o +obj-$(CONFIG_RTK_FSS_SCAN) += rtk_fss_scan.o +obj-$(CONFIG_REALTEK_CHIP_INFO) += chip.o +obj-$(CONFIG_REALTEK_RPC) += rpc/ +obj-$(CONFIG_RTK_MCP) += rtk_mcp.o rtk_sha1.o +obj-$(CONFIG_PD_REALTEK) += rtk_pd/ +obj-$(CONFIG_RTK_HSE) += hse/ +ifeq ($(CONFIG_SYNO_RTD1619B), y) +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk-usb-manager.o +rtk-usb-manager-y += rtk_usb_manager.o +rtk-usb-manager-y += rtk_usb_manager.o +rtk-usb-manager-y += rtk_usb_rtd119x.o +rtk-usb-manager-y += rtk_usb_rtd129x.o +rtk-usb-manager-y += rtk_usb_rtd13xx.o +rtk-usb-manager-y += rtk_usb_rtd139x.o +rtk-usb-manager-y += rtk_usb_rtd16xx.o +rtk-usb-manager-y += rtk_usb_rtd16xxb.o +rtk-usb-manager-y += rtk_usb_rtd1312c.o +else #CONFIG_SYNO_RTD1619B +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_manager.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd119x.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd129x.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd1312c.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd13xx.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd139x.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd16xx.o +obj-$(CONFIG_RTK_USB_CTRL_MANAGER) += rtk_usb_rtd16xxb.o +endif #CONFIG_SYNO_RTD1619B +obj-$(CONFIG_ION_REALTEK) += mem_allocator/ +obj-$(CONFIG_RTK_FAN) += rtk_fan.o +obj-$(CONFIG_SUSPEND) += rtk_pm_common.o rtk_pm.o rtk_pm_sysfs.o rtk_fw_pm.o +obj-$(CONFIG_RTK_VCPU) += rtk_vcpu.o +obj-$(CONFIG_RTK_VE3_UART) += rtk_ve3_uart.o +obj-$(CONFIG_RTK_WATCHDOG_STATUS) += rtk_watchdog_status.o +obj-$(CONFIG_RTK_GPIO_DEFAULT) += rtk_gpio_default.o +obj-$(CONFIG_RTK_VSFC_CTRL) += rtk_vsfc_ctrl.o +obj-$(CONFIG_RTK_CPUHP_QOS) += rtk_cpuhp.o +obj-$(CONFIG_RTK_CPUHP_CONTROL) += rtk_cpuhp_ctrl.o +obj-$(CONFIG_RTK_CPU_VCLK) += rtk_cpu_vclk.o +obj-y += rtk_iso_wa.o +obj-$(CONFIG_RTK_BUFLOCK) += buflock/ +obj-$(CONFIG_RTK_BSV_CTRL) += rtk_bsv_ctrl.o diff --git a/drivers/soc/realtek/common/buflock/Kconfig b/drivers/soc/realtek/common/buflock/Kconfig new file mode 100644 index 000000000000..7a9ec935b09e --- /dev/null +++ b/drivers/soc/realtek/common/buflock/Kconfig @@ -0,0 +1,6 @@ +config RTK_BUFLOCK + bool "Realtek BUFLOCK driver" + default n + help + Realtek BUFLOCK driver + diff --git a/drivers/soc/realtek/common/buflock/Makefile b/drivers/soc/realtek/common/buflock/Makefile new file mode 100644 index 000000000000..d31cde791d16 --- /dev/null +++ b/drivers/soc/realtek/common/buflock/Makefile @@ -0,0 +1,10 @@ +MODULE_NAME := buflock + +ccflags-y := -I$(obj)/inc +ccflags-y += -I$(obj)/uapi +ccflags-y += -DMODULE_NAME='"$(MODULE_NAME)"' +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/rtk/inc + +obj-y := $(MODULE_NAME).o +$(MODULE_NAME)-objs := src/buflock.o diff --git a/drivers/soc/realtek/common/buflock/src/buflock.c b/drivers/soc/realtek/common/buflock/src/buflock.c new file mode 100644 index 000000000000..23cd9cefd74f --- /dev/null +++ b/drivers/soc/realtek/common/buflock/src/buflock.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2020 Realtek Semiconductor Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "buflock.h" +#include "mem_allocator/ion.h" + +#include +#define ion_alloc ext_rtk_ion_alloc + +#define OFFSET_FROM_ID(id) (id * 4) + +#define MODULE_TAG "buflock :" + +struct buflock_module; /* main module */ +struct buflock_client; /* fd */ +struct buflock_handle; /* slot */ + +struct buflock_handle { + struct buflock_module * module; + struct kref ref; + struct list_head list; /* module->handles */ + struct mutex mutex; + + size_t id; + unsigned int fwid; + buflock_status_t * pStatus; + + struct { + ktime_t create; + ktime_t lastSet; + ktime_t destroy; + } sTime; + + void (*destroy) (struct kref *kref); + unsigned int (*getFWID) (struct buflock_handle * handle); + void (*get) (struct buflock_handle * handle); + void (*put) (struct buflock_handle * handle); + unsigned int (*refCount) (struct buflock_handle * handle); + int (*setStatus) (struct buflock_handle * handle, buflock_status_t status); + buflock_status_t(*getStatus) (struct buflock_handle * handle); +}; + +struct buflock_slot { + struct buflock_handle * handle; + struct list_head list; /* client->list */ + struct mutex mutex; +}; + +struct buflock_client { + struct buflock_module * module; + struct mutex mutex; + struct list_head slots; /* buflock_slot */ + struct list_head list; /* module->clients */ + + /* client info. */ + pid_t pid; + pid_t tgid; + char task_comm[TASK_COMM_LEN]; +}; + +struct buflock_module { + struct mutex handles_lock; + struct list_head handles; + struct list_head free_handles; + wait_queue_head_t free_queue; + size_t next_id; + + struct mutex clients_lock; + struct list_head clients; /* buflock_client */ + + struct task_struct *kthread; + + dev_t dev_num; + struct device * device; + struct cdev dev; + struct class * dev_class; + + buflock_status_t * pStatusMemory; + unsigned int uStatusPhyAddr; + + unsigned int release_loop_ms; + unsigned int destroy_timeout_ms; + size_t max_handles; + struct dma_buf *dmabuf; + int ion_handle; +}; + +static struct buflock_handle * buflock_handle_create (struct buflock_module * module, size_t id, buflock_fwid_t fwid, buflock_status_t * pStatus); +static void buflock_handle_destroy (struct kref *kref); +static unsigned int buflock_handle_get_fwid (struct buflock_handle * handle); +static void buflock_handle_get (struct buflock_handle * handle); +static void buflock_handle_put (struct buflock_handle * handle); +static unsigned int buflock_handle_refCount (struct buflock_handle * handle); +static int buflock_handle_setStatus (struct buflock_handle * handle, buflock_status_t status); +static buflock_status_t buflock_handle_getStatus (struct buflock_handle * handle); +static size_t buflock_module_get_unused_id_unlock (struct buflock_module * module); +static struct buflock_handle * buflock_module_handle_create (struct buflock_module * module); +static struct buflock_handle * buflock_module_handle_get_by_fwid (struct buflock_module * module, buflock_fwid_t fwid); +static int buflock_module_independent (struct buflock_module * module, buflock_fwid_t fwid, struct buflock_client * pClient); +static void buflock_module_handle_destroy (struct kref *kref); +static int buflock_fops_open (struct inode *inode, struct file *file); +static int buflock_fops_close (struct inode *inode, struct file *file); +static ssize_t buflock_fops_read (struct file *file, char *buf, size_t size, loff_t *f_pos); +static ssize_t buflock_fops_write (struct file *file, const char *buf, size_t size, loff_t *f_pos); +static long buflock_fops_ioctl (struct file *file, unsigned int cmd, unsigned long arg); +static int buflock_client_release_get_fwid (struct buflock_client * client, buflock_fwid_t fwid); + +static struct file_operations buflock_fops = { + .owner = THIS_MODULE, + .open = buflock_fops_open, + .release = buflock_fops_close, + .read = buflock_fops_read, + .write = buflock_fops_write, + .unlocked_ioctl = buflock_fops_ioctl, + .compat_ioctl = buflock_fops_ioctl, +}; + +static char * getStatusStr (buflock_status_t st) { + switch (st) { + case E_BUFLOCK_ST_LOCK : return "LOCK" ; + case E_BUFLOCK_ST_UNLOCK : return "UNLOCK" ; + case E_BUFLOCK_ST_RELEASE : return "RELEASE" ; + case E_BUFLOCK_ST_NORMAL : return "NORMAL" ; + case E_BUFLOCK_ST_TOUCH : return "TOUCH" ; + case E_BUFLOCK_ST_ERROR : return "ERROR" ; + default: return "ERROR2"; + }; +} + +static struct buflock_handle * buflock_handle_create(struct buflock_module * module, + size_t id, buflock_fwid_t fwid, buflock_status_t * pStatus) +{ + struct buflock_handle * ret = NULL; + do { + ret = (struct buflock_handle *) kzalloc(sizeof(struct buflock_handle), GFP_KERNEL); + + kref_init (&ret->ref); + mutex_init (&ret->mutex); + INIT_LIST_HEAD (&ret->list); + + ret->module = module; + ret->id = id; + ret->fwid = fwid; + ret->pStatus = pStatus; + + ret->destroy = buflock_handle_destroy; + ret->getFWID = buflock_handle_get_fwid; + ret->get = buflock_handle_get; + ret->put = buflock_handle_put; + ret->refCount = buflock_handle_refCount; + ret->setStatus = buflock_handle_setStatus; + ret->getStatus = buflock_handle_getStatus; + + } while (0); + return ret; +} + +static void buflock_handle_destroy(struct kref *kref) +{ + struct buflock_handle * handle = container_of(kref, struct buflock_handle, ref); + mutex_destroy(&handle->mutex); + kfree(handle); +} + +static unsigned int buflock_handle_get_fwid (struct buflock_handle * handle) +{ + unsigned int ret; + mutex_lock(&handle->mutex); + ret = handle->fwid; + mutex_unlock(&handle->mutex); + return ret; +} + +static void buflock_handle_get(struct buflock_handle * handle) +{ + kref_get(&handle->ref); +} + +static void buflock_handle_put(struct buflock_handle * handle) +{ + kref_put(&handle->ref, handle->destroy); +} + +static unsigned int buflock_handle_refCount(struct buflock_handle * handle) +{ + return kref_read(&handle->ref); +} + +static int buflock_handle_setStatus (struct buflock_handle * handle, buflock_status_t status) +{ + int ret = -1; + mutex_lock(&handle->mutex); + if (handle->pStatus) { + writel(status, handle->pStatus); + ret = 0; + } + + handle->sTime.lastSet = ktime_get(); + + mutex_unlock(&handle->mutex); + return ret; +} + +static buflock_status_t buflock_handle_getStatus(struct buflock_handle * handle) +{ + buflock_status_t ret = E_BUFLOCK_ST_ERROR; + mutex_lock(&handle->mutex); + if (handle->pStatus) + ret = readl(handle->pStatus); + mutex_unlock(&handle->mutex); + return ret; +} + +/****************************************************************/ + +static struct buflock_handle * buflock_module_handle_create (struct buflock_module * module) +{ + struct buflock_handle * ret = NULL; + mutex_lock(&module->handles_lock); + do { + size_t id = buflock_module_get_unused_id_unlock(module); + buflock_fwid_t fwid = module->uStatusPhyAddr + OFFSET_FROM_ID(id); + buflock_status_t * pStatus = &module->pStatusMemory[OFFSET_FROM_ID(id)]; + struct buflock_handle * handle; + + if (id >= module->max_handles) + break; + + module->next_id = id + 1; + if (module->next_id >= module->max_handles) + module->next_id = 0; + + handle = buflock_handle_create(module, id, fwid, pStatus); + + if (!handle) + break; + + handle->sTime.create = ktime_get(); + + handle->module = module; + handle->destroy = buflock_module_handle_destroy; + handle->setStatus(handle, E_BUFLOCK_ST_NORMAL); + list_add(&handle->list, &module->handles); + + pr_debug("%s [+] handle=%p (id=%zu fwid=%u, status=%s)\n", MODULE_TAG, handle, + id, fwid, getStatusStr(handle->getStatus(handle))); + + ret = handle; + } while(0); + mutex_unlock(&module->handles_lock); + return ret; +} + +static size_t buflock_module_get_unused_id_unlock (struct buflock_module * module) +{ + size_t ret = module->next_id; + struct buflock_handle * handle, * tmp_handle; +REDISCOVER: + list_for_each_entry_safe(handle, tmp_handle, &module->handles, list) { + if (handle && handle->id == ret) { + ret++; + goto REDISCOVER; + } + } + list_for_each_entry_safe(handle, tmp_handle, &module->free_handles, list) { + if (handle && handle->id == ret) { + ret++; + goto REDISCOVER; + } + } + + if (ret == module->max_handles && module->next_id != 0) { + module->next_id = 0; + ret = 0; + goto REDISCOVER; + } + + return ret; +} + +static void buflock_module_handle_destroy (struct kref *kref) +{ + struct buflock_handle * handle = container_of(kref, struct buflock_handle, ref); + struct buflock_module * module = handle->module; + bool delayed_release = true; + + mutex_lock(&module->handles_lock); + list_del(&handle->list); + + pr_debug("%s [-] handle=%p (id=%zu fwid=%u, status=%s)\n", MODULE_TAG, handle, + handle->id, handle->getFWID(handle), getStatusStr(handle->getStatus(handle))); + + handle->sTime.destroy = ktime_get(); + + switch (handle->getStatus(handle)) { + case E_BUFLOCK_ST_NORMAL: + case E_BUFLOCK_ST_RELEASE: + break; + case E_BUFLOCK_ST_LOCK: + handle->setStatus(handle, E_BUFLOCK_ST_UNLOCK); + delayed_release = true; + break; + case E_BUFLOCK_ST_UNLOCK: + delayed_release = true; + break; + default: + pr_debug("%s [DEBUG STATE] handle=%p (id=%zu fwid=%u, status=%s)\n", MODULE_TAG, handle, + handle->id, handle->getFWID(handle), getStatusStr(handle->getStatus(handle))); + break; + } + + if (delayed_release) { + list_add(&handle->list, &module->free_handles); + } else { + handle->setStatus(handle, E_BUFLOCK_ST_ERROR); + buflock_handle_destroy(&handle->ref); + } + + wake_up(&module->free_queue); + mutex_unlock(&module->handles_lock); +} + +static size_t buflock_module_free_count (struct buflock_module * module) +{ + size_t ret = 0; + mutex_lock(&module->handles_lock); + { + struct buflock_handle * handle, * tmp_handle; + list_for_each_entry_safe(handle, tmp_handle, &module->free_handles, list) { + if (handle) + ret++; + } + } + mutex_unlock(&module->handles_lock); + return ret; +} + +static int buflock_module_free_thread(void *data) +{ + struct buflock_module * module = (struct buflock_module *)data; + size_t free_cnt = 0; + for (;;) { + if (kthread_should_stop()) + break; + + wait_event_interruptible_timeout(module->free_queue, + (free_cnt != buflock_module_free_count(module)), + msecs_to_jiffies(module->release_loop_ms)); + + mutex_lock(&module->handles_lock); + { + struct buflock_handle * handle, * tmp_handle; + list_for_each_entry_safe(handle, tmp_handle, &module->free_handles, list) { + bool remove = false; + if (!handle) + continue; + switch (handle->getStatus(handle)) { + case E_BUFLOCK_ST_NORMAL: + case E_BUFLOCK_ST_RELEASE: + remove = true; + break; + default: + { + ktime_t now = ktime_get(); + if (ktime_ms_delta(now, handle->sTime.destroy) > module->destroy_timeout_ms) { + remove = true; + pr_err("%s Destroy handle(%p) timeout! ***FORCED RELEASE*** (id=%zu fwid=%u, status=%s)\n", + MODULE_TAG, handle, + handle->id, handle->getFWID(handle), getStatusStr(handle->getStatus(handle))); + } + } + break; + } + + if (remove) { + handle->setStatus(handle, E_BUFLOCK_ST_ERROR); + list_del(&handle->list); + buflock_handle_destroy(&handle->ref); + } + } + } + mutex_unlock(&module->handles_lock); + + free_cnt = buflock_module_free_count(module); + } + + return 0; +} + +static struct buflock_handle * buflock_module_handle_get_by_fwid (struct buflock_module * module, buflock_fwid_t fwid) +{ + struct buflock_handle * ret = NULL; + + mutex_lock(&module->handles_lock); + { + struct buflock_handle * handle, * tmp_handle; + list_for_each_entry_safe(handle, tmp_handle, &module->handles, list) { + if (handle && buflock_handle_get_fwid(handle) == fwid) { + buflock_handle_get(handle); + ret = handle; + break; + } + } + } + mutex_unlock(&module->handles_lock); + return ret; +} + +static int buflock_module_independent (struct buflock_module * module, + buflock_fwid_t fwid, struct buflock_client * pClient) +{ + int ret = -1; + + mutex_lock(&module->clients_lock); + { + struct buflock_client * client, * tmp_client; + list_for_each_entry_safe(client, tmp_client, &module->clients, list) { + if (!client || pClient == client) + continue; + if (buflock_client_release_get_fwid(client, fwid) == 0) + ret = 0; + } + } + mutex_unlock(&module->clients_lock); + return ret; +} + +static phys_addr_t buflock_mem_pa(struct ion_buffer *buffer) +{ + unsigned long ret = -1UL; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + + mutex_lock(&buffer->lock); + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + mutex_unlock(&buffer->lock); + + ret = paddr; + + return ret; +} + +static void *buflock_mem_va(struct ion_buffer *buffer) +{ + void *ret = NULL; + void *vaddr; + + mutex_lock(&buffer->lock); + vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer); + mutex_unlock(&buffer->lock); + + ret = vaddr; + + return ret; +} + +static struct buflock_module * gModule = NULL; +static int __init buflock_module_init (void) +{ + int ret = -1; + do { + struct buflock_module * module; + + if (gModule) { + ret = 0; + break; + } + + gModule = (struct buflock_module *) kzalloc(sizeof(struct buflock_module), GFP_KERNEL); + + module = gModule; + + module->release_loop_ms = 5; + module->destroy_timeout_ms = 5000; + module->max_handles = 4096; + module->next_id = 0; + INIT_LIST_HEAD(&module->handles); + INIT_LIST_HEAD(&module->free_handles); + mutex_init(&module->handles_lock); + + INIT_LIST_HEAD(&module->clients); + mutex_init(&module->clients_lock); + + do { + phys_addr_t ion_phyAddr; + size_t ion_size; + unsigned int ion_flag_mask = ION_FLAG_NONCACHED | ION_USAGE_MMAP_NONCACHED; + ion_flag_mask |= ION_FLAG_SCPUACC | ION_FLAG_ACPUACC | ION_FLAG_VCPU_FWACC; + + module->ion_handle = ion_alloc(sizeof(unsigned int) * module->max_handles, + RTK_ION_HEAP_AUDIO_MASK, ion_flag_mask); + if (IS_ERR(module->ion_handle)) + module->ion_handle = ion_alloc(sizeof(unsigned int) * module->max_handles, + RTK_ION_HEAP_MEDIA_MASK, ion_flag_mask); + + if (IS_ERR(module->ion_handle)) { + module->ion_handle = 0; + break; + } + + module->dmabuf = dma_buf_get(module->ion_handle); + if (IS_ERR(module->dmabuf)) { + ret = PTR_ERR(module->dmabuf); + break; + } + + __close_fd(current->files, module->ion_handle); + + ion_phyAddr = buflock_mem_pa(module->dmabuf->priv); + + if (ion_phyAddr == 0) { + dma_buf_put(module->dmabuf); + module->ion_handle = 0; + break; + } + + module->uStatusPhyAddr = (unsigned int) ion_phyAddr; + module->pStatusMemory = buflock_mem_va(module->dmabuf->priv); + break; + } while (0); + + if (!module->pStatusMemory) { + module->pStatusMemory = (buflock_status_t *) kzalloc(sizeof(unsigned int) * module->max_handles, GFP_KERNEL); + module->uStatusPhyAddr = (unsigned int) virt_to_phys(module->pStatusMemory); + } + + { + cdev_init(&module->dev, &buflock_fops); + if (alloc_chrdev_region(&module->dev_num, 0, 1, MODULE_NAME)!=0) { + cdev_del(&module->dev); + kfree(module); + gModule = NULL; + break; + } + + if (cdev_add(&module->dev, module->dev_num, 1)<0) { + cdev_del(&module->dev); + kfree(module); + gModule = NULL; + break; + } + + module->dev_class = class_create(THIS_MODULE, MODULE_NAME); + + module->device = device_create( + module->dev_class, // class + NULL, // parent + module->dev_num, // dev number + NULL, // driver data + MODULE_NAME); // device name + } + + init_waitqueue_head(&module->free_queue); + module->kthread = kthread_create(buflock_module_free_thread, module, "buflock_release_thread"); + wake_up_process(module->kthread); + + ret = 0; + } while (0); + return ret; +} + +static void __exit buflock_module_exit(void) +{ + struct buflock_module * module = gModule; + if (!module) + return; + + kthread_stop(module->kthread); + + { + struct buflock_handle * handle, * tmp_handle; + list_for_each_entry_safe(handle, tmp_handle, &module->free_handles, list) { + if (handle) { + list_del(&handle->list); + buflock_handle_destroy(&handle->ref); + } + } + + list_for_each_entry_safe(handle, tmp_handle, &module->handles, list) { + if (handle) { + list_del(&handle->list); + buflock_handle_destroy(&handle->ref); + } + } + } + + { + device_destroy(module->dev_class, module->device->devt); + class_destroy(module->dev_class); + cdev_del(&module->dev); + unregister_chrdev_region(module->dev_num, 1); + } + + if (module->ion_handle) { + dma_buf_put(module->dmabuf); + } else if (module->pStatusMemory) + kfree(module->pStatusMemory); + + mutex_destroy(&module->handles_lock); + mutex_destroy(&module->clients_lock); + + kfree(module); + gModule = NULL; +} + +static struct buflock_slot * buflock_slot_create(struct buflock_handle * handle) +{ + struct buflock_slot * slot = NULL; + do { + slot = (struct buflock_slot *) + kzalloc(sizeof(struct buflock_slot), GFP_KERNEL); + + mutex_init (&slot->mutex); + INIT_LIST_HEAD (&slot->list); + slot->handle = handle; + } while (0); + return slot; +} + +static void buflock_slot_destroy(struct buflock_slot * slot) +{ + if (slot->handle) + slot->handle->put(slot->handle); + kfree(slot); +} + +static struct buflock_client * buflock_client_create(struct buflock_module * module) +{ + struct buflock_client * ret = NULL; + do { + ret = (struct buflock_client *) kzalloc(sizeof(struct buflock_client), GFP_KERNEL); + mutex_init (&ret->mutex); + INIT_LIST_HEAD (&ret->slots); + INIT_LIST_HEAD (&ret->list); + ret->module = module; + + { + struct task_struct *task; + get_task_struct(current->group_leader); + + task_lock(current->group_leader); + ret->pid = task_pid_nr(current->group_leader); + ret->tgid = task_tgid_nr(current->group_leader); + if (current->group_leader->flags & PF_KTHREAD) + task = NULL; + else + task = current->group_leader; + task_unlock(current->group_leader); + + if (task) + get_task_comm(ret->task_comm, task); + else + strncpy(ret->task_comm, "KTHREAD", sizeof(ret->task_comm)); + + put_task_struct(current->group_leader); + } + } while (0); + return ret; +} + +static void buflock_client_destroy(struct buflock_client * client) +{ + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + list_del(&slot->list); + buflock_slot_destroy(slot); + } + } + mutex_unlock(&client->mutex); + mutex_destroy(&client->mutex); + kfree(client); +} + +static int buflock_client_alloc_get_fwid (struct buflock_client * client, buflock_fwid_t * fwid) +{ + int ret = -1; + mutex_lock(&client->mutex); + do { + struct buflock_handle * handle; + struct buflock_slot * slot; + + if (!fwid) + break; + + handle = buflock_module_handle_create(client->module); + + if (!handle) + break; + + slot = buflock_slot_create(handle); + + if (!slot) { + handle->put(handle); + break; + } + + list_add (&slot->list, &client->slots); + + *fwid = handle->getFWID(handle); + + ret = 0; + } while (0); + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_client_import_get_fwid (struct buflock_client * client, buflock_fwid_t fwid) +{ + int ret = -1; + mutex_lock(&client->mutex); + do { + struct buflock_handle * handle = NULL; + struct buflock_slot * slot, * tmp_slot; + + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (slot && slot->handle && slot->handle->getFWID(slot->handle) == fwid) { + handle = slot->handle; + break; + } + } + + if (handle) { + ret = 0; + break; + } + + handle = buflock_module_handle_get_by_fwid(client->module, fwid); + + if (!handle) + break; + + slot = buflock_slot_create(handle); + + if (!slot) { + handle->put(handle); + break; + } + + list_add (&slot->list, &client->slots); + + ret = 0; + } while (0); + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_client_release_get_fwid (struct buflock_client * client, buflock_fwid_t fwid) +{ + int ret = -1; + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (slot && slot->handle && slot->handle->getFWID(slot->handle) == fwid) { + list_del(&slot->list); + buflock_slot_destroy(slot); + ret = 0; + break; + } + } + } + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_client_set_status(struct buflock_client * client, + buflock_fwid_t fwid, buflock_status_t status) +{ + int ret = -1; + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (slot && slot->handle && slot->handle->getFWID(slot->handle) == fwid) { + struct buflock_handle * handle = slot->handle; + ret = handle->setStatus(handle, status); + break; + } + } + } + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_client_get_status(struct buflock_client * client, + buflock_fwid_t fwid, buflock_status_t * status) +{ + int ret = -1; + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (slot && slot->handle && slot->handle->getFWID(slot->handle) == fwid) { + struct buflock_handle * handle = slot->handle; + *status = handle->getStatus(handle); + ret = 0; + break; + } + } + } + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_client_get_refCount(struct buflock_client * client, + buflock_fwid_t fwid, unsigned int * pCount) +{ + int ret = -1; + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (slot && slot->handle && slot->handle->getFWID(slot->handle) == fwid) { + struct buflock_handle * handle = slot->handle; + *pCount = handle->refCount(handle); + ret = 0; + break; + } + } + } + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_client_independent(struct buflock_client * client, + buflock_fwid_t fwid) +{ + int ret = -1; + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (slot && slot->handle && slot->handle->getFWID(slot->handle) == fwid) { + ret = buflock_module_independent(client->module, fwid, client); + break; + } + } + } + mutex_unlock(&client->mutex); + return ret; +} + +static int buflock_fops_open (struct inode *inode, struct file *file) +{ + int ret = -1; + do { + struct cdev * dev = inode->i_cdev; + struct buflock_module * module = container_of(dev, struct buflock_module, dev); + struct buflock_client * client = buflock_client_create(module); + if (!client) + break; + + mutex_lock(&module->clients_lock); + list_add(&client->list, &module->clients); + mutex_unlock(&module->clients_lock); + + file->private_data = client; + ret = 0; + } while (0); + return ret; +} + +static int buflock_fops_close (struct inode *inode, struct file *file) +{ + struct buflock_client * client = file->private_data; + struct buflock_module * module = client->module; + if (module) { + mutex_lock(&module->clients_lock); + list_del(&client->list); + mutex_unlock(&module->clients_lock); + } + buflock_client_destroy(client); + return 0; +} + +static ssize_t buflock_fops_read (struct file *file, char *buf, size_t size, loff_t *f_pos) +{ + ssize_t ret = 0; + struct buflock_client * f_client = file->private_data; + struct buflock_module * module = f_client->module; + do { + ktime_t now = ktime_get(); + char * str = (char *) kzalloc(size, GFP_KERNEL); + char * s = str; + if (!s) + break; + + s += sprintf(s, "#%s ion(%p) phy=%08zx max=%zu checkloop_ms=%d destroy_timeout_ms=%d\n", MODULE_NAME, + module->dmabuf, module->uStatusPhyAddr, module->max_handles, module->release_loop_ms, module->destroy_timeout_ms); + + s += sprintf(s, " clients:\n"); + mutex_lock(&module->clients_lock); + { + struct buflock_client * client, * tmp_client; + list_for_each_entry_safe(client, tmp_client, &module->clients, list) { + if (!client) + continue; + s += sprintf(s, " %u %u [%s]\n", client->pid, client->tgid, client->task_comm); + mutex_lock(&client->mutex); + { + struct buflock_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &client->slots, list) { + if (!slot) + continue; + s += sprintf(s, " %p\n", slot->handle); + } + } + mutex_unlock(&client->mutex); + } + } + mutex_unlock(&module->clients_lock); + + mutex_lock(&module->handles_lock); + + s += sprintf(s, " active handle:\n"); + { + struct buflock_handle * handle, * tmp_handle; + list_for_each_entry_safe(handle, tmp_handle, &module->handles, list) { + unsigned int lastSet_delta_us; + if (!handle) + continue; + lastSet_delta_us = ktime_us_delta(now, handle->sTime.lastSet) & -1U; + s += sprintf(s, " %p (id=%08x, %.8s) lastSet(%5d.%03d ms)\n", handle, + handle->getFWID(handle), getStatusStr(handle->getStatus(handle)), + lastSet_delta_us/1000, lastSet_delta_us%1000 + ); + } + } + + s += sprintf(s, " inactive handle:\n"); + { + struct buflock_handle * handle, * tmp_handle; + list_for_each_entry_safe(handle, tmp_handle, &module->free_handles, list) { + unsigned int lastSet_delta_us; + unsigned int destroy_delta_us; + if (!handle) + continue; + lastSet_delta_us = ktime_us_delta(now, handle->sTime.lastSet) & -1U; + destroy_delta_us = ktime_us_delta(now, handle->sTime.destroy) & -1U; + s += sprintf(s, " %p (id=%08x, %.8s) lastSet(%5d.%03d ms), Destroy(%5d.%03d ms)\n", handle, + handle->getFWID(handle), getStatusStr(handle->getStatus(handle)), + lastSet_delta_us/1000, lastSet_delta_us%1000, + destroy_delta_us/1000, destroy_delta_us%1000 + ); + } + } + + mutex_unlock(&module->handles_lock); + + ret = simple_read_from_buffer(buf, size, f_pos, str, s-str); + kfree(str); + } while (0); + return ret; +} + +static ssize_t buflock_fops_write (struct file *file, const char *buf, size_t size, loff_t *f_pos) +{ + return 0; +} + +static long buflock_fops_ioctl (struct file *file, unsigned int cmd, unsigned long arg) +{ + long ret = -1L; + struct buflock_client * client = (struct buflock_client *) file->private_data; + switch (cmd) { + case BUFLOCK_IOC_ALLOC: + { + struct buflock_alloc_data data; + + if (buflock_client_alloc_get_fwid(client, &data.fwid) != 0) + break; + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + buflock_client_release_get_fwid(client, data.fwid); + break; + } + + ret = 0; + } + break; + case BUFLOCK_IOC_FREE: + { + struct buflock_import_data data; + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + break; + + if (buflock_client_release_get_fwid(client, data.fwid) != 0) + break; + ret = 0; + } + break; + case BUFLOCK_IOC_IMPORT: + { + struct buflock_import_data data; + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + break; + + if (buflock_client_import_get_fwid(client, data.fwid) != 0) + break; + ret = 0; + } + break; + case BUFLOCK_IOC_SET_STATUS: + { + struct buflock_status_data data; + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + break; + + if (buflock_client_set_status(client, data.fwid, data.status) != 0) + break; + ret = 0; + } + break; + case BUFLOCK_IOC_GET_STATUS: + { + struct buflock_status_data data; + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + break; + + if (buflock_client_get_status(client, data.fwid, &data.status) != 0) + break; + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + buflock_client_release_get_fwid(client, data.fwid); + break; + } + ret = 0; + } + break; + case BUFLOCK_IOC_GET_REF: + { + struct buflock_reference_data data; + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + break; + + if (buflock_client_get_refCount(client, data.fwid, &data.count) != 0) + break; + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + buflock_client_release_get_fwid(client, data.fwid); + break; + } + ret = 0; + } + break; + case BUFLOCK_IOC_SET_INDIE: + { + struct buflock_independent_data data; + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) + break; + + if (buflock_client_independent(client, data.fwid) != 0) + break; + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + break; + } + ret = 0; + } + break; + default: + break; + } + return ret; +} + +module_init(buflock_module_init); +module_exit(buflock_module_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/realtek/common/buflock/uapi/buflock.h b/drivers/soc/realtek/common/buflock/uapi/buflock.h new file mode 100644 index 000000000000..103d27e65cb2 --- /dev/null +++ b/drivers/soc/realtek/common/buflock/uapi/buflock.h @@ -0,0 +1,53 @@ +#ifndef __RTK_BUFLOCK_H__ +#define __RTK_BUFLOCK_H__ + +#include + +enum buflock_status { + E_BUFLOCK_ST_ERROR, + E_BUFLOCK_ST_NORMAL, + E_BUFLOCK_ST_TOUCH, + E_BUFLOCK_ST_LOCK, + E_BUFLOCK_ST_UNLOCK, + E_BUFLOCK_ST_RELEASE, +}; + +typedef unsigned char buflock_status_t; +typedef unsigned int buflock_fwid_t; + +struct buflock_alloc_data { + buflock_fwid_t fwid; +}; + +struct buflock_import_data { + buflock_fwid_t fwid; +}; + +struct buflock_free_data { + buflock_fwid_t fwid; +}; + +struct buflock_status_data { + buflock_fwid_t fwid; + buflock_status_t status; +}; + +struct buflock_reference_data { + buflock_fwid_t fwid; + unsigned int count; +}; + +struct buflock_independent_data { + buflock_fwid_t fwid; +}; + +#define BUFLOCK_IOC_MAGIC 'B' +#define BUFLOCK_IOC_ALLOC _IOWR(BUFLOCK_IOC_MAGIC, 1, struct buflock_alloc_data) +#define BUFLOCK_IOC_FREE _IOWR(BUFLOCK_IOC_MAGIC, 2, struct buflock_free_data) +#define BUFLOCK_IOC_IMPORT _IOWR(BUFLOCK_IOC_MAGIC, 3, struct buflock_import_data) +#define BUFLOCK_IOC_SET_STATUS _IOWR(BUFLOCK_IOC_MAGIC, 4, struct buflock_status_data) +#define BUFLOCK_IOC_GET_STATUS _IOWR(BUFLOCK_IOC_MAGIC, 5, struct buflock_status_data) +#define BUFLOCK_IOC_GET_REF _IOWR(BUFLOCK_IOC_MAGIC, 6, struct buflock_reference_data) +#define BUFLOCK_IOC_SET_INDIE _IOWR(BUFLOCK_IOC_MAGIC, 7, struct buflock_independent_data) + +#endif /* __RTK_BUF_LOCK_H__ */ diff --git a/drivers/soc/realtek/common/chip.c b/drivers/soc/realtek/common/chip.c new file mode 100644 index 000000000000..075d9d6100f4 --- /dev/null +++ b/drivers/soc/realtek/common/chip.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek System-on-Chip info + * + * Copyright (c) 2017-2019 Andreas Färber + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_CHIP_ID 0x0 +#define REG_CHIP_REV 0x4 + +static int of_rtd_soc_read_efuse(struct device_node *np, const char *name, + unsigned char *val, size_t size) +{ + struct nvmem_cell *cell; + char *buf; + size_t buf_size; + int ret = 0; + + cell = of_nvmem_cell_get(np, name); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = nvmem_cell_read(cell, &buf_size); + nvmem_cell_put(cell); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + if (buf_size > size) + ret = -E2BIG; + else + memcpy(val, buf, size); + kfree(buf); + return ret; +} + +static int of_get_bond_id(struct device_node *np, u32 *bond) +{ + return of_rtd_soc_read_efuse(np, "bond_id", (u8 *)bond, sizeof(*bond)); +} + +static int of_get_package_id(struct device_node *np, u32 *package) +{ + return of_rtd_soc_read_efuse(np, "package_id", (u8 *)package, + sizeof(*package)); +} + +struct rtd_soc_revision { + const char *name; + u32 chip_rev; +}; + +static const struct rtd_soc_revision rtd1195_revisions[] = { + { "A", 0x00000000 }, + { "B", 0x00010000 }, + { "C", 0x00020000 }, + { "D", 0x00030000 }, + { } +}; + +static const struct rtd_soc_revision rtd1295_revisions[] = { + { "A00", 0x00000000 }, + { "A01", 0x00010000 }, + { "B00", 0x00020000 }, + { "B01", 0x00030000 }, + { } +}; + +static const struct rtd_soc_revision rtd1395_revisions[] = { + { "A00", 0x00000000}, + { "A01", 0x00010000}, + { "A02", 0x00020000}, + { } +}; + +static const struct rtd_soc_revision rtd1619_revisions[] = { + { "A00", 0x00000000}, + { "A01", 0x00010000}, + { } +}; + +static const struct rtd_soc_revision rtd1319_revisions[] = { + { "A00", 0x00000000}, + { "B00", 0x00010000}, + { "B01", 0x00020000}, + { "B02", 0x00030000}, + { } +}; + +static const struct rtd_soc_revision rtd161xb_revisions[] = { + { "A00", 0x00000000}, + { } +}; + +static const struct rtd_soc_revision rtd1312c_revisions[] = { + { "A00", 0x00000000}, + { } +}; + +struct rtd_soc { + u32 chip_id; + const char *(*get_name)(struct device *dev, const struct rtd_soc *s); + const char *(*get_chip_type)(struct device *dev, const struct rtd_soc *s); + const struct rtd_soc_revision *revisions; + const char *codename; +}; + +static const char *rtd119x_name(struct device *dev, const struct rtd_soc *s) +{ + return "RTD1195"; +} + +static const char *rtd129x_name(struct device *dev, const struct rtd_soc *s) +{ + void __iomem *base; + u32 package_id; + int ret; + + ret = of_get_package_id(dev->of_node, &package_id); + if (!ret) { + dev_info(dev, "package_id: 0x%08x\n", package_id); + if (package_id == 0x1) + return "RTD1294"; + } + + base = of_iomap(dev->of_node, 1); + if (base) { + u32 chipinfo1 = readl_relaxed(base); + iounmap(base); + dev_info(dev, "chipinfo1: 0x%08x\n", chipinfo1); + if (chipinfo1 & BIT(11)) { + if (chipinfo1 & BIT(4)) + return "RTD1293"; + + return "RTD1296"; + } + } + + return "RTD1295"; +} + +static const char *rtd139x_name(struct device *dev, const struct rtd_soc *s) +{ + void __iomem *base; + + base = of_iomap(dev->of_node, 1); + if (base) { + u32 chipinfo1 = readl_relaxed(base); + iounmap(base); + dev_info(dev, "chipinfo1: 0x%08x\n", chipinfo1); + if (chipinfo1 & BIT(12)) + return "RTD1392"; + } + + return "RTD1395"; +} + +static const char *rtd161x_name(struct device *dev, const struct rtd_soc *s) +{ + return "RTD1619"; +} + +static const char *rtd131x_name(struct device *dev, const struct rtd_soc *s) +{ + u32 bond_id; + int ret; + +#define OTP_CHIP_MASK 0x000F0000 +#define RTD1319 0x00000000 +#define RTD1317 0x00010000 +#define RTD1315 0x00020000 + + ret = of_get_bond_id(dev->of_node, &bond_id); + if (!ret) { + dev_info(dev, "bond_id: 0x%08x\n", bond_id); + switch (bond_id & OTP_CHIP_MASK) { + case (RTD1319): + break; + case (RTD1317): + return "RTD1317"; + case (RTD1315): + return "RTD1315"; + default: + pr_err("%s: Not define chip id 0x%x\n", + __func__, bond_id); + } + } + + return "RTD1319"; +} + +static const char *rtd131x_chip_type(struct device *dev, const struct rtd_soc *s) +{ + u32 bond_id; + int ret; + +#define CHIP_TYPE_1319_EI (0x00000000) +#define CHIP_TYPE_1319_ES (0x00300001) +#define CHIP_TYPE_1319_PB (0x1FB00007) +#define CHIP_TYPE_1319_DV (0x1B30000F) +#define CHIP_TYPE_1319_VS (0x1B30001B) +#define CHIP_TYPE_1311_EI (0x0000F000) +#define CHIP_TYPE_1311_ES (0x0030F001) +#define CHIP_TYPE_1311_PB (0x1FB07007) +#define CHIP_TYPE_1311_DV (0x1B30700F) +#define CHIP_TYPE_1311_VS (0x1B307013) + + ret = of_get_bond_id(dev->of_node, &bond_id); + if (!ret) { + dev_info(dev, "bond_id: 0x%08x\n", bond_id); + switch (bond_id) { + case (CHIP_TYPE_1319_EI): + return "1319_EI"; + case (CHIP_TYPE_1319_ES): + return "1319_ES"; + case (CHIP_TYPE_1319_PB): + return "1319_PB"; + case (CHIP_TYPE_1319_DV): + return "1319_DV"; + case (CHIP_TYPE_1319_VS): + return "1319_VS"; + case (CHIP_TYPE_1311_EI): + return "1311_EI"; + case (CHIP_TYPE_1311_ES): + return "1311_ES"; + case (CHIP_TYPE_1311_PB): + return "1311_PB"; + case (CHIP_TYPE_1311_DV): + return "1311_DV"; + case (CHIP_TYPE_1311_VS): + return "1311_VS"; + default: + pr_err("%s: Not define chip type 0x%x\n", + __func__, bond_id); + } + } + + return "unknown"; +} + +static const char *rtd161xb_name(struct device *dev, const struct rtd_soc *s) +{ + u32 bond_id; + int ret; + +#define OTP_STARK_CHIP_MASK 0x00007000 +#define RTD1619B 0x00000000 +#define RTD1315C 0x00020000 + + ret = of_get_bond_id(dev->of_node, &bond_id); + if (!ret) { + dev_info(dev, "bond_id: 0x%08x\n", bond_id); + switch (bond_id & OTP_STARK_CHIP_MASK) { + case (RTD1619B): + break; + case (RTD1315C): + return "RTD1315C"; + default: + pr_err("%s: Not define chip id 0x%x\n", + __func__, bond_id); + } + } + + return "RTD1619B"; +} + +static const char *rtd161xb_chip_type(struct device *dev, const struct rtd_soc *s) +{ + u32 bond_id; + int ret; + +#define CHIP_TYPE_1619B_EI (0x00000000) + + ret = of_get_bond_id(dev->of_node, &bond_id); + if (!ret) { + dev_info(dev, "bond_id: 0x%08x\n", bond_id); + switch (bond_id) { + case (CHIP_TYPE_1619B_EI): + return "1619B_EI"; + default: + pr_err("%s: Not define chip type 0x%x\n", + __func__, bond_id); + } + } + + return "unknown"; +} + +static const char *rtd1312c_name(struct device *dev, const struct rtd_soc *s) +{ + return "RTD1312C"; +} + +static const struct rtd_soc rtd_soc_families[] = { + { 0x00006329, rtd119x_name, NULL, rtd1195_revisions, "Phoenix" }, + { 0x00006421, rtd129x_name, NULL, rtd1295_revisions, "Kylin" }, + { 0x00006481, rtd139x_name, NULL, rtd1395_revisions, "Hercules" }, + { 0x00006525, rtd161x_name, NULL, rtd1619_revisions, "Thor" }, + { 0x00006570, rtd131x_name, rtd131x_chip_type, rtd1319_revisions, "Hank" }, + { 0x00006698, rtd161xb_name, rtd161xb_chip_type, rtd161xb_revisions, "Stark" }, + { 0x00006820, rtd1312c_name, NULL, rtd1312c_revisions, "Groot" }, +}; + +static const struct rtd_soc *rtd_soc_by_chip_id(u32 chip_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rtd_soc_families); i++) { + const struct rtd_soc *family = &rtd_soc_families[i]; + + if (family->chip_id == chip_id) + return family; + } + return NULL; +} + +static const char *rtd_soc_rev(const struct rtd_soc *family, u32 chip_rev) +{ + if (family) { + const struct rtd_soc_revision *rev = family->revisions; + + while (rev && rev->name) { + if (rev->chip_rev == chip_rev) { + return rev->name; + } + rev++; + } + } + return "unknown"; +} + +struct custom_device_attribute { + const char *chip_type; +}; + +static ssize_t custom_info_get(struct device *dev, + struct device_attribute *attr, + char *buf); + +static DEVICE_ATTR(chip_type, S_IRUGO, custom_info_get, NULL); + +static umode_t custom_attribute_mode(struct kobject *kobj, + struct attribute *attr, + int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); + + if ((attr == &dev_attr_chip_type.attr) + && (soc_dev->attr->data)) { + struct custom_device_attribute *custom_dev_attr; + + custom_dev_attr = (struct custom_device_attribute *) + (soc_dev->attr->data); + if (custom_dev_attr->chip_type) + return attr->mode; + } + /* Unknown or unfilled attribute. */ + return 0; +} + + +static ssize_t custom_info_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); + + if (attr == &dev_attr_chip_type && + soc_dev->attr->data) { + struct custom_device_attribute *custom_dev_attr; + + custom_dev_attr = (struct custom_device_attribute *) + (soc_dev->attr->data); + if (custom_dev_attr->chip_type) + return sprintf(buf, "%s\n", custom_dev_attr->chip_type); + } + + return -EINVAL; +} + +static struct attribute *custom_attr[] = { + &dev_attr_chip_type.attr, + NULL, +}; + +static const struct attribute_group custom_attr_group = { + .attrs = custom_attr, + .is_visible = custom_attribute_mode, +}; + +static int rtd_soc_probe(struct platform_device *pdev) +{ + const struct rtd_soc *s; + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device_node *node; + struct custom_device_attribute *custom_dev_attr; + void __iomem *base; + u32 chip_id, chip_rev; + + base = of_iomap(pdev->dev.of_node, 0); + if (!base) + return -ENODEV; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + chip_id = readl_relaxed(base + REG_CHIP_ID); + chip_rev = readl_relaxed(base + REG_CHIP_REV); + + node = of_find_node_by_path("/"); + of_property_read_string(node, "model", &soc_dev_attr->machine); + of_node_put(node); + + s = rtd_soc_by_chip_id(chip_id); + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "Realtek %s", + (s && s->codename) ? s->codename : "Digital Home Center"); + + if (likely(s && s->get_name)) + soc_dev_attr->soc_id = s->get_name(&pdev->dev, s); + else + soc_dev_attr->soc_id = "unknown"; + + soc_dev_attr->revision = rtd_soc_rev(s, chip_rev); + + custom_dev_attr = kzalloc(sizeof(*custom_dev_attr), GFP_KERNEL); + if (!custom_dev_attr) + return -ENOMEM; + + if (likely(s && s->get_chip_type)) + custom_dev_attr->chip_type = s->get_chip_type(&pdev->dev, s); + else + custom_dev_attr->chip_type = NULL; + + soc_dev_attr->data = (void *)custom_dev_attr; + + soc_dev_attr->custom_attr_group = &custom_attr_group; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->family); + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + platform_set_drvdata(pdev, soc_dev); + + pr_info("%s %s (0x%08x) rev %s (0x%08x) detected\n", + soc_dev_attr->family, soc_dev_attr->soc_id, chip_id, + soc_dev_attr->revision, chip_rev); + + return 0; +} + +static int rtd_soc_remove(struct platform_device *pdev) +{ + struct soc_device *soc_dev = platform_get_drvdata(pdev); + + soc_device_unregister(soc_dev); + + return 0; +} + +static const struct of_device_id rtd_soc_dt_ids[] = { + { .compatible = "realtek,soc-chip" }, + { } +}; + +static struct platform_driver rtd_soc_driver = { + .probe = rtd_soc_probe, + .remove = rtd_soc_remove, + .driver = { + .name = "rtk-soc", + .of_match_table = rtd_soc_dt_ids, + }, +}; + +static int __init rtd_soc_driver_init(void) +{ + return platform_driver_register(&(rtd_soc_driver)); +} +subsys_initcall_sync(rtd_soc_driver_init); + +static void __exit rtd_soc_driver_exit(void) +{ + platform_driver_unregister(&(rtd_soc_driver)); +} + +MODULE_DESCRIPTION("Realtek SoC identification"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/realtek/common/dvfs/Kconfig b/drivers/soc/realtek/common/dvfs/Kconfig new file mode 100644 index 000000000000..21f446832e8a --- /dev/null +++ b/drivers/soc/realtek/common/dvfs/Kconfig @@ -0,0 +1,4 @@ +config RTK_CPU_VOLT_SEL + bool "Add OPP prop extn to CPU device" + default y + diff --git a/drivers/soc/realtek/common/dvfs/Makefile b/drivers/soc/realtek/common/dvfs/Makefile new file mode 100644 index 000000000000..ad547857e217 --- /dev/null +++ b/drivers/soc/realtek/common/dvfs/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_RTK_CPU_VOLT_SEL) += cpu-volt-sel.o diff --git a/drivers/soc/realtek/common/dvfs/cpu-volt-sel.c b/drivers/soc/realtek/common/dvfs/cpu-volt-sel.c new file mode 100644 index 000000000000..66f110f8df91 --- /dev/null +++ b/drivers/soc/realtek/common/dvfs/cpu-volt-sel.c @@ -0,0 +1,212 @@ +/* + * Realtek CPU volt sel + * + * Copyright (c) 2019, Realtek Semiconductor Corporation + * + * Author: + * Cheng-Yu Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#define pr_fmt(fmt) "cpu-volt-sel: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char prop_name[40]; +static int prop_name_inited; +static struct opp_table *opp_table; + +static int prop_from_chip_rev(char *name, size_t size) +{ + unsigned int val; + + val = get_rtd_chip_revision(); + if ((val & 0xFFF) == 0) { + pr_err("%s: invalid chip revision\n", __func__); + return -EINVAL; + } + snprintf(name, size, "%x", val); + return 0; +} + +static int prop_from_dss(char *name, size_t size) +{ + struct device_node *np; + unsigned int val; + struct nvmem_cell *cell; + int ret = 0; + unsigned char *buf; + size_t buf_size; + + + np = of_find_node_by_path("/cpu-dvfs"); + if (!np) { + pr_err("%s: failed to find device node\n", __func__); + return -ENODEV; + } + + cell = of_nvmem_cell_get(np, "cpu-dss"); + if (IS_ERR(cell)) { + ret = PTR_ERR(cell); + pr_debug("%s: failed to get dss cell: %d\n", __func__, ret); + return -ENOTSUPP; + } + + buf = nvmem_cell_read(cell, &buf_size); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + pr_err("%s: failed to read dss cell: %d\n", __func__, ret); + goto done; + } + + val = (buf[15] << 12) | (buf[16] << 4) | (buf[17] >> 4); + + pr_info("%s: dss val=%d\n", __func__, val); + if (val > 23000) { + WARN(val > 26000, "dss value too large\n"); + snprintf(name, size, "ss"); + } else { + WARN(val && val < 18000, "dss value too small\n"); + snprintf(name, size, "tt"); + } + + kfree(buf); +done: + nvmem_cell_put(cell); + return ret; +} + +static int prop_from_dt(char *name, size_t size) +{ + struct device_node *np; + unsigned int val; + int ret = 0; + + np = of_find_node_by_path("/cpu-dvfs"); + if (!np) { + pr_err("%s: failed to find device node\n", __func__); + return -ENODEV; + } + + ret = of_property_read_u32(np, "bsv,opp-updated", &val); + if (!ret && val == 1) { + snprintf(name, size, "bsv"); + return 0; + } + + ret = of_property_read_u32(np, "fss,opp-updated", &val); + if (ret || val == 0) + return -ENOTSUPP; + + snprintf(name, size, "fss"); + return 0; +} + +static int cpu_volt_set_init_prop_name(void) +{ + int ret; + + ret = prop_from_dt(prop_name, sizeof(prop_name)); + if (ret == -ENOTSUPP) + ret = prop_from_dss(prop_name, sizeof(prop_name)); + if (ret == -ENOTSUPP) + ret = prop_from_chip_rev(prop_name, sizeof(prop_name)); + if (ret) + return ret; + + pr_info("prop_name is %s\n", prop_name); + prop_name_inited = 1; + return 0; +} + +static void cpu_volt_sel_set_prop_name(void) +{ + struct device *dev; + + dev = get_cpu_device(0); + if (!dev) { + pr_err("failed to get cpu device\n"); + return; + } + + if (WARN_ON(opp_table)) { + pr_err("opp table not clear\n"); + return; + } + + pr_info("dev_pm_opp_set_prop_name: name=%s\n", prop_name); + opp_table = dev_pm_opp_set_prop_name(dev, prop_name); + return; +} + +static void cpu_volt_sel_put_opp_table(void) +{ + if (!opp_table) + return; + + dev_pm_opp_put_prop_name(opp_table); + opp_table = NULL; +} + +static int cpu_volt_sel_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct device *dev = data; + + if (!prop_name_inited) + return NOTIFY_DONE; + + if (strcmp("cpufreq-dt", dev_name(dev))) + return NOTIFY_DONE; + + dev_dbg(dev, "cpufreq-dt receive bus event %ld\n", event); + + switch (event) { + case BUS_NOTIFY_BIND_DRIVER: + cpu_volt_sel_set_prop_name(); + return NOTIFY_OK; + + case BUS_NOTIFY_UNBOUND_DRIVER: + case BUS_NOTIFY_DRIVER_NOT_BOUND: + cpu_volt_sel_put_opp_table(); + return NOTIFY_OK; + } + return NOTIFY_DONE; +} + +static struct notifier_block cpu_volt_sel_nb = { + .notifier_call = cpu_volt_sel_cb, +}; + +static __init int cpu_volt_sel_init(void) +{ + int ret; + + ret = cpu_volt_set_init_prop_name(); + if (ret) + return ret; + + return bus_register_notifier(&platform_bus_type, &cpu_volt_sel_nb); +} +fs_initcall(cpu_volt_sel_init); diff --git a/drivers/soc/realtek/common/hse/Kconfig b/drivers/soc/realtek/common/hse/Kconfig new file mode 100644 index 000000000000..8c048c4339dd --- /dev/null +++ b/drivers/soc/realtek/common/hse/Kconfig @@ -0,0 +1,6 @@ + +config RTK_HSE + bool "Realtek Highspeed Streaming Engine driver" + default y if ARCH_REALTEK + help + Enable Realtek HSE driver. If unsure, say N. diff --git a/drivers/soc/realtek/common/hse/Makefile b/drivers/soc/realtek/common/hse/Makefile new file mode 100644 index 000000000000..74f816fc9f0c --- /dev/null +++ b/drivers/soc/realtek/common/hse/Makefile @@ -0,0 +1,7 @@ +ccflags-y += -I$(src)/include +obj-y += rtk-hse.o + +rtk-hse-y += platform.o +rtk-hse-y += engine.o +rtk-hse-y += device.o +rtk-hse-y += cq.o diff --git a/drivers/soc/realtek/common/hse/cq.c b/drivers/soc/realtek/common/hse/cq.c new file mode 100644 index 000000000000..1abbea1efe14 --- /dev/null +++ b/drivers/soc/realtek/common/hse/cq.c @@ -0,0 +1,90 @@ +#include +#include +#include "hse.h" + +struct hse_command_queue *hse_cq_alloc(struct hse_device *hdev) +{ + struct device *dev = hdev->dev; + struct hse_command_queue *cq = NULL; + + cq = kzalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) + return NULL; + + cq->hdev = hdev; + cq->size = PAGE_SIZE; + cq->virt = dma_alloc_coherent(dev, cq->size, &cq->phys, + GFP_KERNEL | GFP_DMA); + if (!cq->virt) + goto free_cq; + + dev_dbg(hdev->dev, "%s: phys:%pad, virt=%p\n", __func__, + &cq->phys, cq->virt); + return cq; + +free_cq: + kfree(cq); + return NULL; +} + +void hse_cq_free(struct hse_command_queue *cq) +{ + struct device *dev = cq->hdev->dev; + + dma_free_coherent(dev, cq->size, cq->virt, cq->phys); + kfree(cq); +} + +static inline void __hse_cq_add_data_one(struct hse_command_queue *cq, u32 data) +{ + u32 *ptr = (cq->virt + cq->pos); + + if (cq->pos >= cq->size) { + WARN(1, "cq full\n"); + return; + } + + pr_debug("%s: add data=%08x to %p\n", __func__, data, ptr); + *ptr++ = data; + cq->pos += 4; + + if ((cq->pos % 16) == 0) { + u32 tmp; + + ptr -= 4; + + tmp = ptr[0]; + ptr[0] = ptr[3]; + ptr[3] = tmp; + + tmp = ptr[1]; + ptr[1] = ptr[2]; + ptr[2] = tmp; + } +} + + +void hse_cq_add_data(struct hse_command_queue *cq, u32 *data, size_t size) +{ + struct device *dev = cq->hdev->dev; + int i; + + for (i = 0; i < size; i++) + __hse_cq_add_data_one(cq, data[i]); + dma_sync_single_for_device(dev, cq->phys, cq->size, DMA_TO_DEVICE); +} + +void hse_cq_pad(struct hse_command_queue *cq) +{ + struct device *dev = cq->hdev->dev; + + __hse_cq_add_data_one(cq, 0); + while (cq->pos % 16) + __hse_cq_add_data_one(cq, 0); + dma_sync_single_for_device(dev, cq->phys, cq->size, DMA_TO_DEVICE); +} + +void hse_cq_reset(struct hse_command_queue *cq) +{ + cq->pos = 0; +} diff --git a/drivers/soc/realtek/common/hse/device.c b/drivers/soc/realtek/common/hse/device.c new file mode 100644 index 000000000000..969c284a719f --- /dev/null +++ b/drivers/soc/realtek/common/hse/device.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include "hse.h" +#include "include/hsectl.h" + +#include +#include + +struct hse_file_data { + struct hse_device *hdev; + struct hse_command_queue *cq; + atomic_t busy; +}; + +static int hse_open(struct inode *inode, struct file *filp) +{ + struct hse_device *hdev = container_of(filp->private_data, + struct hse_device, mdev); + struct hse_file_data *data; + int ret; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->hdev = hdev; + atomic_set(&data->busy, 0); + data->cq = hse_cq_alloc(hdev); + if (!data->cq) { + ret = -ENOMEM; + goto free_data; + } + + filp->private_data = data; + pm_runtime_get_sync(hdev->dev); + return 0; +free_data: + kfree(data); + return ret; +} + +static int hse_release(struct inode *inode, struct file *filp) +{ + struct hse_file_data *data = filp->private_data; + struct hse_command_queue *cq = data->cq; + + pm_runtime_put_sync(cq->hdev->dev); + hse_cq_free(cq); + kfree(data); + return 0; +} + +static const struct vm_operations_struct hse_vm_ops = { +#ifdef CONFIG_HAVE_IOREMAP_PROT + .access = generic_access_phys, +#endif +}; + +static long hse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct hse_file_data *data = filp->private_data; + struct hse_command_queue *cq = data->cq; + int ret; + struct hse_cmd c; + struct hse_engine *eng; + int busy; + + switch (cmd) { + case HSE_IOCTL_ADD_CMD: + busy = atomic_xchg(&data->busy, 1); + if (busy) + return -EBUSY; + + ret = copy_from_user(&c, (unsigned int __user *)arg, sizeof(c)); + if (ret) + return ret; + + hse_cq_add_data(cq, c.cmds, c.size); + atomic_set(&data->busy, 0); + break; + + case HSE_IOCTL_START: + busy = atomic_xchg(&data->busy, 1); + if (busy) + return -EBUSY; + + hse_cq_pad(cq); + eng = hse_engine_get_any(cq->hdev); + if (!eng) { + atomic_set(&data->busy, 0); + return -EBUSY; + } + ret = hse_engine_execute_cq(eng, cq); + hse_engine_put(eng); + hse_cq_reset(cq); + atomic_set(&data->busy, 0); + + return ret; + + case HSE_IOCTL_HW_RESET: + case HSE_IOCTL_HW_RESET_FORCE: + return -EINVAL; + } + + return 0; +} + +static long hse_compact_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return hse_ioctl(filp, cmd, arg); +} + +const struct file_operations hse_fops = { + .owner = THIS_MODULE, + .open = hse_open, + .unlocked_ioctl = hse_ioctl, + .compat_ioctl = hse_compact_ioctl, + .release = hse_release, +}; + diff --git a/drivers/soc/realtek/common/hse/engine.c b/drivers/soc/realtek/common/hse/engine.c new file mode 100644 index 000000000000..29f034f79954 --- /dev/null +++ b/drivers/soc/realtek/common/hse/engine.c @@ -0,0 +1,170 @@ +#include +#include +#include "hse.h" + +static inline int hse_engine_read(struct hse_engine *eng, int offset) +{ + return hse_read(eng->hdev, eng->base_offset + offset); +} + +static inline void hse_engine_write(struct hse_engine *eng, int offset, + unsigned int val) +{ + hse_write(eng->hdev, eng->base_offset + offset, val); +} + +int hse_engine_suspend(struct hse_engine *eng) +{ + if (!eng) + return -EINVAL; + + // TODO + + return 0; +} + +int hse_engine_resume(struct hse_engine *eng) +{ + if (!eng) + return -EINVAL; + + // TODO + + return 0; +} + +static void hse_engine_cmd_done(struct hse_engine *eng) +{ + eng->cmd_done = true; + wake_up_interruptible(&eng->cmd_done_wait); +} + +void hse_engine_check_ints(struct hse_engine *eng) +{ + u32 ints; + + ints = hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_INTS); + if (ints == 0) + return; + if (ints & 0x4) + eng->status |= HSE_STATUS_IRQ_CMD_ERR; + if (ints & 0x2) + eng->status |= HSE_STATUS_IRQ_OK; + + /* stop the engine */ + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_INTC, 0); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_Q, 0); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_INTS, 0x6); + + hse_engine_cmd_done(eng); +} + +void hse_engine_wait(struct hse_engine *eng) +{ + int ret; + + ret = wait_event_interruptible_timeout(eng->cmd_done_wait, + (eng->cmd_done), msecs_to_jiffies(500)); + if (ret == 0) + eng->status |= HSE_STATUS_TIMEOUT; + eng->cmd_done = false; +} + +int hse_engine_execute_cq(struct hse_engine *eng, struct hse_command_queue *cq) +{ + struct device *dev = eng->hdev->dev; + int ret = 0; + + ret = mutex_lock_interruptible(&eng->req_lock); + if (ret) + return ret; + + pm_runtime_get_sync(dev); + + eng->cq = cq; + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_QB, cq->phys); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_QL, cq->phys + cq->size); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_QR, cq->phys); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_QW, cq->phys + cq->pos); + + dev_dbg(dev, "qb = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QB)); + dev_dbg(dev, "ql = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QL)); + dev_dbg(dev, "qr = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QR)); + dev_dbg(dev, "qw = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QW)); + + /* start the engine */ + eng->status = 0; + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_INTC, 0x6); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_Q, 0x1); + + /* wait */ + hse_engine_wait(eng); + // check result + if (eng->status & ~HSE_STATUS_IRQ_OK) { + dev_info(dev, "engine->status=%04x\n", eng->status); + ret = -ETIME; + } + dev_dbg(dev, "qb = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QB)); + dev_dbg(dev, "ql = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QL)); + dev_dbg(dev, "qr = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QR)); + dev_dbg(dev, "qw = %08x\n", hse_engine_read(eng, HSE_REG_ENGINE_OFFSET_QW)); + + eng->cq = NULL; + + pm_runtime_put_sync(dev); + + mutex_unlock(&eng->req_lock); + + return ret; +} + +struct hse_engine *hse_engine_get_any(struct hse_device *hdev) +{ + int i; + struct hse_engine *eng; + + for (i = 0; i < HSE_MAX_ENGINES; i++) { + eng = hdev->engs[i]; + if (eng) + return eng; + } + return NULL; +} + +void hse_engine_put(struct hse_engine *eng) +{ + if (!eng) + return; +} + +int hse_engine_init(struct hse_device *hdev, int index) +{ + struct hse_engine *eng; + struct device *dev = hdev->dev; + + eng = devm_kzalloc(dev, sizeof(*eng), GFP_KERNEL); + if (!eng) + return -ENOMEM; + + eng->hdev = hdev; + eng->base_offset = HSE_REG_ENGINE_BASE(index); + + mutex_init(&eng->req_lock); + init_waitqueue_head(&eng->cmd_done_wait); + eng->cmd_done = false; + + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_Q, 0); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_QCL, 0); + hse_engine_write(eng, HSE_REG_ENGINE_OFFSET_QCH, 0); + + hdev->engs[index] = eng; + + return 0; +} + +void hse_engine_fini(struct hse_device *hdev, int index) +{ + // TODO ... +} + + diff --git a/drivers/soc/realtek/common/hse/hse.h b/drivers/soc/realtek/common/hse/hse.h new file mode 100644 index 000000000000..335dcb56b688 --- /dev/null +++ b/drivers/soc/realtek/common/hse/hse.h @@ -0,0 +1,117 @@ +#ifndef __SOC_REALTEK_HSE_H__ +#define __SOC_REALTEK_HSE_H__ + +#include +#include +#include +#include +#include +#include + +#define HSE_MAX_ENGINES (2) + +#define HSE_REG_ENGINE_BASE(i) (0x200 + 0x100 * (i)) +#define HSE_REG_ENGINE_OFFSET_QB 0x00 +#define HSE_REG_ENGINE_OFFSET_QL 0x04 +#define HSE_REG_ENGINE_OFFSET_QR 0x08 +#define HSE_REG_ENGINE_OFFSET_QW 0x0C +#define HSE_REG_ENGINE_OFFSET_Q 0x10 +#define HSE_REG_ENGINE_OFFSET_INTS 0x14 +#define HSE_REG_ENGINE_OFFSET_SWAP 0x18 +#define HSE_REG_ENGINE_OFFSET_QCL 0x1C +#define HSE_REG_ENGINE_OFFSET_QCH 0x20 +#define HSE_REG_ENGINE_OFFSET_INTC 0x24 + +#define HSE_REG_BYPASS 0x41c + +enum { + HSE_STATUS_IRQ_OK = 0x1, + HSE_STATUS_IRQ_CMD_ERR = 0x2, + HSE_STATUS_TIMEOUT = 0x4, +}; + +struct hse_device; +struct hse_command_queue; + +struct hse_engine { + struct hse_device *hdev; + int base_offset; + unsigned int status; + struct mutex req_lock; + int req; + wait_queue_head_t cmd_done_wait; + bool cmd_done; + struct hse_command_queue *cq; +}; + + +int hse_engine_init(struct hse_device *hdev, int index); +void hse_engine_fini(struct hse_device *hdev, int index); +int hse_engine_suspend(struct hse_engine *eng); +int hse_engine_resume(struct hse_engine *eng); + +struct hse_engine *hse_engine_get_any(struct hse_device *hdev); +void hse_engine_put(struct hse_engine *eng); + +void hse_engine_check_ints(struct hse_engine *eng); +int hse_engine_execute_cq(struct hse_engine *eng, struct hse_command_queue *cq); + + +struct hse_command_queue { + struct hse_device *hdev; + dma_addr_t phys; + void *virt; + size_t size; + int pos; +}; + +struct hse_command_queue *hse_cq_alloc(struct hse_device *hdev); +void hse_cq_free(struct hse_command_queue *cq); +void hse_cq_add_data(struct hse_command_queue *cq, u32 *data, size_t size); +void hse_cq_pad(struct hse_command_queue *cq); +void hse_cq_reset(struct hse_command_queue *cq); + + +struct hse_quirks { + unsigned int bypass_en_disable : 1; +}; + +struct hse_device { + struct miscdevice mdev; + struct device *dev; + struct clk *clk; + struct reset_control *rstc; + struct reset_control *rstc_bist; + void *base; + struct hse_engine *engs[HSE_MAX_ENGINES]; + unsigned int engine_mask; + int irq; + const struct hse_quirks *quirks; +}; + +static inline void hse_write(struct hse_device *hdev, unsigned int offset, + u32 val) +{ + dev_dbg(hdev->dev, "w: offset=%03x, val=%08x\n", offset, val); + writel(val, hdev->base + offset); +} + +static inline int hse_read(struct hse_device *hdev, unsigned int offset) +{ + u32 v; + + v = readl(hdev->base + offset); + dev_dbg(hdev->dev, "r: offset=%03x, val=%08x\n", offset, v); + return v; +} + +static inline int hse_should_disable_bypass_en(struct hse_device *hdev) +{ + if (!hdev->quirks) + return 0; + return hdev->quirks->bypass_en_disable; +} + +extern const struct file_operations hse_fops; + +#endif /* __SOC_REALTEK_HSE_H__ */ diff --git a/drivers/soc/realtek/common/hse/include/hse-sw.h b/drivers/soc/realtek/common/hse/include/hse-sw.h new file mode 100644 index 000000000000..9c1eb425d12b --- /dev/null +++ b/drivers/soc/realtek/common/hse/include/hse-sw.h @@ -0,0 +1,26 @@ +#ifndef __HSE_SW_H__ +#define __HSE_SW_H__ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +void __hse_sw_yuyv2nv12(void *dst0, + void *dst1, + void *src, + uint32_t width, + uint32_t height, + uint32_t src_pitch, + uint32_t dst_pitch); + +void __hse_sw_rotate(void *src, + void *dst, + uint32_t mode, + uint32_t width, + uint32_t height, + uint32_t src_pitch, + uint32_t dst_pitch); + +#endif /*__HSE_SW_H__ */ diff --git a/drivers/soc/realtek/common/hse/include/hsectl.h b/drivers/soc/realtek/common/hse/include/hsectl.h new file mode 100644 index 000000000000..d648cd7d4371 --- /dev/null +++ b/drivers/soc/realtek/common/hse/include/hsectl.h @@ -0,0 +1,26 @@ +#ifndef __HSECTL_H__ +#define __HSECTL_H__ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +struct hse_cmd { + uint32_t size; + uint32_t cmds[32]; +}; + +#define HSE_IOCTL_VERSION _IOR('H', 0x00, unsigned int) +#define HSE_IOCTL_ADD_CMD _IOW('H', 0x01, struct hse_cmd) +#define HSE_IOCTL_START _IO('H', 0x02) +#define HSE_IOCTL_HW_RESET _IO('H', 0x04) +#define HSE_IOCTL_HW_RESET_FORCE _IO('H', 0x05) + + +#define HSE_ROTATE_MODE_90 0 +#define HSE_ROTATE_MODE_180 1 +#define HSE_ROTATE_MODE_270 2 + +#endif /* __HSECTL_H__ */ diff --git a/drivers/soc/realtek/common/hse/platform.c b/drivers/soc/realtek/common/hse/platform.c new file mode 100644 index 000000000000..63ba79a4e16f --- /dev/null +++ b/drivers/soc/realtek/common/hse/platform.c @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "hse.h" + +static int hse_hw_init(struct hse_device *hdev) +{ + unsigned int val; + + val = hse_should_disable_bypass_en(hdev) ? 0 : 1; + hse_write(hdev, HSE_REG_BYPASS, val); + return 0; +} + +static int hse_runtime_suspend(struct device *dev) +{ + struct hse_device *hdev = dev_get_drvdata(dev); + int i; + + dev_dbg(dev, "%s\n", __func__); + for (i = 0; i < HSE_MAX_ENGINES; i++) + hse_engine_suspend(hdev->engs[i]); + clk_disable_unprepare(hdev->clk); + reset_control_assert(hdev->rstc_bist); + reset_control_assert(hdev->rstc); + + return 0; +} + +static int hse_runtime_resume(struct device *dev) +{ + struct hse_device *hdev = dev_get_drvdata(dev); + int i; + + dev_dbg(dev, "%s\n", __func__); + reset_control_deassert(hdev->rstc); + reset_control_deassert(hdev->rstc_bist); + clk_prepare_enable(hdev->clk); + hse_hw_init(hdev); + for (i = 0; i < HSE_MAX_ENGINES; i++) + hse_engine_resume(hdev->engs[i]); + + return 0; +} + +static const struct dev_pm_ops hse_pm_ops = { + .runtime_suspend = hse_runtime_suspend, + .runtime_resume = hse_runtime_resume, +}; + +static irqreturn_t hse_interrupt(int irq, void *dev_id) +{ + struct hse_device *hdev = dev_id; + int i; + + for (i = 0 ; i < HSE_MAX_ENGINES; i++) { + if (!hdev->engs[i]) + continue; + if (!(BIT(i) & hdev->engine_mask)) + continue; + dev_dbg(hdev->dev, "irq:%d fire to engine%d\n", irq, i); + hse_engine_check_ints(hdev->engs[i]); + } + return IRQ_HANDLED; +} + +static int of_parse_engine_mask(struct device_node *np, int *mask) +{ + *mask = 0; + if (of_find_property(np, "engine-0-enabled", NULL)) + *mask |= 0x1; + if (of_find_property(np, "engine-1-enabled", NULL)) + *mask |= 0x2; + + return *mask == 0 ? -EINVAL : 0; +} + +int hse_hw_reset(struct hse_device *hdev) +{ + if (!hdev->rstc) { + dev_err(hdev->dev, "no reset control\n"); + return -EINVAL; + } + reset_control_reset(hdev->rstc); + hse_hw_init(hdev); + return 0; +} + +static int hse_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct hse_device *hdev; + struct resource res; + int ret; + int i; + + hdev = devm_kzalloc(dev, sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return -ENOMEM; + + platform_set_drvdata(pdev, hdev); + hdev->dev = dev; + hdev->quirks = of_device_get_match_data(dev); + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(dev, "failed to get recource: %d\n", ret); + return -ENODEV; + } + + hdev->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!hdev->base) + return -ENOMEM; + + hdev->clk = devm_clk_get(dev, NULL); + if (IS_ERR(hdev->clk)) { + ret = PTR_ERR(hdev->clk); + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + hdev->rstc = devm_reset_control_get_optional(dev, "core"); + if (IS_ERR(hdev->rstc)) { + ret = PTR_ERR(hdev->rstc); + dev_dbg(dev, "failed to get reset control: %d\n", ret); + hdev->rstc = NULL; + } + + hdev->rstc_bist = devm_reset_control_get_optional(dev, "bist"); + if (IS_ERR(hdev->rstc_bist)) { + ret = PTR_ERR(hdev->rstc_bist); + dev_dbg(dev, "failed to get reset control: %d\n", ret); + hdev->rstc_bist = NULL; + } + + ret = of_parse_engine_mask(np, &hdev->engine_mask); + if (ret) { + dev_err(dev, "no engine enabled\n"); + return -ENODEV; + } + dev_dbg(dev, "engine_mask=%x\n", hdev->engine_mask); + + hdev->irq = platform_get_irq(pdev, 0); + if (hdev->irq < 0) { + ret = hdev->irq; + dev_err(dev, "failed to get irq: %d\n", ret); + return ret; + } + + ret = devm_request_irq(dev, hdev->irq, hse_interrupt, IRQF_SHARED, + dev_name(dev), hdev); + if (ret) { + dev_err(dev, "failed to request irq: %d\n", ret); + return ret; + } + + hdev->mdev.minor = MISC_DYNAMIC_MINOR; + hdev->mdev.name = "hse"; + hdev->mdev.fops = &hse_fops; + hdev->mdev.parent = NULL; + ret = misc_register(&hdev->mdev); + if (ret) { + dev_err(dev, "failed to register misc device: %d\n", ret); + return ret; + } + + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + + pm_runtime_get_sync(dev); + for (i = 0; i < HSE_MAX_ENGINES; i++) { + if (!(hdev->engine_mask & BIT(i))) + continue; + + ret = hse_engine_init(hdev, i); + WARN(ret, "engine%d: failed to init: %d\n", i, ret); + } + + if (!of_property_read_bool(np, "realtek,device-is-exclusive")) { + dev_info(dev, "shared mode\n"); + pm_runtime_forbid(dev); + } + pm_runtime_put_sync(dev); + return 0; +} + +static int hse_remove(struct platform_device *pdev) +{ + struct hse_device *hdev = platform_get_drvdata(pdev); + + pm_runtime_disable(hdev->dev); + reset_control_assert(hdev->rstc); + return 0; +} + +static const struct hse_quirks rtd1619b_quirks = { 1 }; + +static const struct of_device_id hse_ids[] = { + { .compatible = "realtek,highspeed-streaming-engine" }, + { .compatible = "realtek,rtd1619b-highspeed-streaming-engine", .data = &rtd1619b_quirks, }, + {} +}; + +static struct platform_driver hse_driver = { + .probe = hse_probe, + .remove = hse_remove, + .driver = { + .name = "rtk-hse", + .owner = THIS_MODULE, + .of_match_table = hse_ids, + .pm = &hse_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; +module_platform_driver(hse_driver); diff --git a/drivers/soc/realtek/common/info/Kconfig b/drivers/soc/realtek/common/info/Kconfig new file mode 100644 index 000000000000..00aee8c2fdb1 --- /dev/null +++ b/drivers/soc/realtek/common/info/Kconfig @@ -0,0 +1,5 @@ +config RTK_INFO_PLL + bool "add DebugFs for PLL info" + depends on ARCH_REALTEK + depends on DEBUG_FS + default y diff --git a/drivers/soc/realtek/common/info/Makefile b/drivers/soc/realtek/common/info/Makefile new file mode 100644 index 000000000000..8b16b8d24bb5 --- /dev/null +++ b/drivers/soc/realtek/common/info/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DEBUG_FS) += rtk_info.o + +obj-$(CONFIG_RTK_INFO_PLL) += rtk_info_pll.o diff --git a/drivers/soc/realtek/common/info/rtk_info.c b/drivers/soc/realtek/common/info/rtk_info.c new file mode 100644 index 000000000000..9404b7e8ffc8 --- /dev/null +++ b/drivers/soc/realtek/common/info/rtk_info.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017,2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include + +struct dentry *rtk_info_debugfs_root; + +static int __init rtk_info_debugfs_init(void) +{ + rtk_info_debugfs_root = debugfs_create_dir("info", NULL); + return 0; +} +arch_initcall(rtk_info_debugfs_init); + diff --git a/drivers/soc/realtek/common/info/rtk_info.h b/drivers/soc/realtek/common/info/rtk_info.h new file mode 100644 index 000000000000..ddd47935bfcc --- /dev/null +++ b/drivers/soc/realtek/common/info/rtk_info.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017,2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __SOC_REALTEK_INFO_H +#define __SOC_REALTEK_INFO_H + +struct dentry; +extern struct dentry *rtk_info_debugfs_root; + +#endif diff --git a/drivers/soc/realtek/common/info/rtk_info_pll.c b/drivers/soc/realtek/common/info/rtk_info_pll.c new file mode 100644 index 000000000000..16998a1b3ad9 --- /dev/null +++ b/drivers/soc/realtek/common/info/rtk_info_pll.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017,2019,2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_info.h" + +#define SYS_PLL_DIV 0x030 +#define SYS_PLL_SCPU3 0x108 + +struct pll_info_device; + +struct pll_info_pll_data { + const char *name; + int (*get_div)(struct pll_info_device *); + struct clk *clk; +}; + +struct pll_info_device_desc { + int scpu_div_version; + int scpu_div_loc_pll_scpu : 1; +}; + +struct pll_info_device { + struct device *dev; + struct regmap *regmap; + struct dentry *dentry; + const struct pll_info_device_desc *desc; +}; + +static void pll_info_show_pll_one(struct seq_file *s, + struct pll_info_device *pxdev, + const struct pll_info_pll_data *pll_data) +{ + uint32_t freq; + int ret; + if (!pll_data->clk) + return; + + seq_printf(s, "%-11s ", pll_data->name + 4); + + freq = clk_get_rate(pll_data->clk) / 1000000; + if (!freq) { + seq_puts(s, " -- MHz - -- MHz POWER_OFF\n"); + return; + } else if (!pll_data->get_div) { + seq_printf(s, "%4d MHz - %4d MHz\n", freq, freq); + return; + } + + ret = pll_data->get_div(pxdev); + if (ret < 0) + seq_printf(s, "%4d MHz ? ?? MHz NO_PERMISSION\n", freq); + else if (ret == 0) + seq_printf(s, "%4d MHz ? ?? MHz INVALID_DIV\n", freq); + else + seq_printf(s, "%4d MHz %3d %4d MHz\n", freq, ret, freq / ret); +} + +#define DIV_GET_VAL(_v, _h, _l) \ + (((_v) >> (_l)) & (BIT((_h) - (_l) + 1) - 1)) + +static int pll_info_get_pll_bus_div(struct pll_info_device *pxdev) +{ + uint32_t div, val; + + regmap_read(pxdev->regmap, SYS_PLL_DIV, &div); + if (div == 0xdeadbeaf || div == 0xdeaddead) + return -EINVAL; + + val = DIV_GET_VAL(div, 1, 0); + + if (val & BIT(1)) + return (val & BIT(0)) ? 4 : 2; + return 1; +} + +static int pll_info_get_pll_dcsb_div(struct pll_info_device *pxdev) +{ + uint32_t div, val; + + regmap_read(pxdev->regmap, SYS_PLL_DIV, &div); + if (div == 0xdeadbeaf || div == 0xdeaddead) + return -EINVAL; + + val = DIV_GET_VAL(div, 26, 22); + if (val & BIT(1)) + return (val & BIT(0)) ? 4 : 2; + return 1; +} + +static int pll_info_get_pll_acpu_div(struct pll_info_device *pxdev) +{ + uint32_t div, val; + + regmap_read(pxdev->regmap, SYS_PLL_DIV, &div); + if (div == 0xdeadbeaf || div == 0xdeaddead) + return -EINVAL; + + val = DIV_GET_VAL(div, 1, 0); + return 1 << (ffs(~val) - 1); +} + +static int __get_pll_scpu_div_v1(uint32_t val) +{ + if (val & BIT(7)) { + val = (val & ~BIT(7)) >> 2; + switch (val) { + case 5: case 6: case 7: case 8: case 10: case 13: + return val; + default: + return 3; + } + } else if (val & BIT(1)) { + return (val & BIT(0)) ? 4 : 2; + } + return 1; +} + +static int __get_pll_scpu_div_v2(uint32_t val) +{ + if (val < 0x80) + return 1; + val = (val & ~0x80) >> 2; + return val > 16 || val < 2 ? 2 : val; +} + +static int pll_info_get_pll_scpu_div(struct pll_info_device *pxdev) +{ + const struct pll_info_device_desc *desc = pxdev->desc; + uint32_t div, val; + + if (desc->scpu_div_loc_pll_scpu) { + regmap_read(pxdev->regmap, SYS_PLL_SCPU3, &div); + val = DIV_GET_VAL(div, 15, 8); + } else { + regmap_read(pxdev->regmap, SYS_PLL_DIV, &div); + val = DIV_GET_VAL(div, 13, 6); + } + if (div == 0xdeadbeaf || div == 0xdeaddead) + return -EINVAL; + + switch (desc->scpu_div_version) { + default: + case 1: + return __get_pll_scpu_div_v1(val); + case 2: + return __get_pll_scpu_div_v2(val); + } +} + +static struct pll_info_pll_data pll_data_list[] = { + { "ref_pll_scpu", pll_info_get_pll_scpu_div, }, + { "ref_pll_bus", pll_info_get_pll_bus_div, }, + { "ref_pll_dcsb", pll_info_get_pll_dcsb_div, }, + { "ref_pll_acpu", pll_info_get_pll_acpu_div, }, + { "ref_pll_ddsa", }, + { "ref_pll_ddsb", }, + { "ref_pll_gpu", }, + { "ref_pll_ve1", }, + { "ref_pll_ve2", }, + { "ref_pll_npu", }, + { "ref_pll_hifi", }, +}; + +static int info_pll_pll_show(struct seq_file *s, void *u) +{ + struct pll_info_device *pxdev = s->private; + int i; + + seq_puts(s, "name pll_freq div out_freq state\n"); + seq_puts(s, "--------------------------------------------------\n"); + + for (i = 0; i < ARRAY_SIZE(pll_data_list); i++) + pll_info_show_pll_one(s, pxdev, &pll_data_list[i]); + + return 0; +} + +static int info_pll_pll_open(struct inode *inode, struct file *file) +{ + return single_open(file, info_pll_pll_show, inode->i_private); +} + +static const struct file_operations info_pll_pll_fops = { + .owner = THIS_MODULE, + .open = info_pll_pll_open, + .read = seq_read, + .release = single_release, +}; + +static +int pll_info_setup_device(struct pll_info_device *pxdev) +{ + struct device *dev = pxdev->dev; + struct device_node *np = dev->of_node; + + pxdev->regmap = syscon_regmap_lookup_by_phandle(np, "realtek,crt"); + if (IS_ERR(pxdev->regmap)) + return PTR_ERR(pxdev->regmap); + + pxdev->desc = of_device_get_match_data(dev); + + return 0; +} + +static int pll_info_setup_clks(struct device *dev) +{ + int i; + int clk_num = 0; + + for (i = 0; i< ARRAY_SIZE(pll_data_list); i++) { + struct pll_info_pll_data *pll_data = &pll_data_list[i]; + + pll_data->clk = clk_get(NULL, pll_data->name); + if (IS_ERR_OR_NULL(pll_data->clk)) { + dev_info(dev, "%s: ignore clk %s\n", __func__, pll_data->name); + pll_data->clk = NULL; + } else + clk_num += 1; + + } + return clk_num ? 0 : -EINVAL; +} + +static int pll_info_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pll_info_device *pxdev; + int ret; + + pxdev = devm_kzalloc(dev, sizeof(*pxdev), GFP_KERNEL); + if (!pxdev) + return -ENOMEM; + pxdev->dev = dev; + + ret = pll_info_setup_device(pxdev); + if (ret) + return ret; + + pxdev->dentry = debugfs_create_file("pll", 0644, rtk_info_debugfs_root, + pxdev, &info_pll_pll_fops); + if (!pxdev->dentry) + return -ENOMEM; + + ret = pll_info_setup_clks(dev); + if (ret) + return ret; + + return 0; +} + +const struct pll_info_device_desc desc_rtd1395 = { + .scpu_div_version = 1, +}; + +const struct pll_info_device_desc desc_rtd1619 = { + .scpu_div_version = 2, +}; + +const struct pll_info_device_desc desc_rtd1619b = { + .scpu_div_version = 2, + .scpu_div_loc_pll_scpu = 1, +}; + +static const struct of_device_id pll_info_ids[] = { + { .compatible = "realtek,rtd139x-pll-info", .data = &desc_rtd1395, }, + { .compatible = "realtek,rtd161x-pll-info", .data = &desc_rtd1619, }, + { .compatible = "realtek,rtd161xb-pll-info", .data = &desc_rtd1619b, }, + {} +}; +MODULE_DEVICE_TABLE(of, pll_info_ids); + +static struct platform_driver pll_info_drv = { + .driver = { + .name = "rtk-pll-info", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pll_info_ids), + }, + .probe = pll_info_probe, +}; +module_platform_driver(pll_info_drv); + +MODULE_DESCRIPTION("Realtek PLL Information driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rtk-pll-info"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/soc/realtek/common/mem_allocator/Kconfig b/drivers/soc/realtek/common/mem_allocator/Kconfig new file mode 100644 index 000000000000..ee03c57d6d0a --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/Kconfig @@ -0,0 +1,46 @@ +menuconfig ION_REALTEK + bool "Ion Memory Manager (Realtek)" + depends on HAS_DMA && MMU + select GENERIC_ALLOCATOR + select DMA_SHARED_BUFFER + help + Chose this option to enable the ION Memory Manager, + used by Android to efficiently allocate buffers + from userspace that can be shared between drivers. + If you're not using Android its probably safe to + say N here. + +config ION_SYSTEM_HEAP_REALTEK + bool "Ion system heap" + depends on ION_REALTEK + help + Choose this option to enable the Ion system heap. The system heap + is backed by pages from the buddy allocator. If in doubt, say Y. + +config ION_CARVEOUT_HEAP_REALTEK + bool "Ion carveout heap support" + depends on ION_REALTEK + help + Choose this option to enable carveout heaps with Ion. Carveout heaps + are backed by memory reserved from the system. Allocation times are + typically faster at the cost of memory not being used. Unless you + know your system has these regions, you should say N here. + +config ION_CHUNK_HEAP_REALTEK + bool "Ion chunk heap support" + depends on ION_REALTEK + help + Choose this option to enable chunk heaps with Ion. This heap is + similar in function the carveout heap but memory is broken down + into smaller chunk sizes, typically corresponding to a TLB size. + Unless you know your system has these regions, you should say N here. + +config ION_CMA_HEAP_REALTEK + bool "Ion CMA heap support" + depends on ION_REALTEK && DMA_CMA + help + Choose this option to enable CMA heaps with Ion. This heap is backed + by the Contiguous Memory Allocator (CMA). If your system has these + regions, you should say Y here. + +source "drivers/soc/realtek/common/mem_allocator/rtk/Kconfig" diff --git a/drivers/soc/realtek/common/mem_allocator/Makefile b/drivers/soc/realtek/common/mem_allocator/Makefile new file mode 100644 index 000000000000..64e754ee18b8 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_ION_REALTEK) += ion.o ion-ioctl.o ion_heap.o +obj-$(CONFIG_ION_SYSTEM_HEAP_REALTEK) += ion_system_heap.o ion_page_pool.o +obj-$(CONFIG_ION_CARVEOUT_HEAP_REALTEK) += ion_carveout_heap.o +obj-$(CONFIG_ION_CHUNK_HEAP_REALTEK) += ion_chunk_heap.o +obj-$(CONFIG_ION_CMA_HEAP_REALTEK) += ion_cma_heap.o + +obj-$(CONFIG_ION_RTK_DHC_HEAP) += rtk/ diff --git a/drivers/soc/realtek/common/mem_allocator/ion-ioctl.c b/drivers/soc/realtek/common/mem_allocator/ion-ioctl.c new file mode 100644 index 000000000000..021a956db1a8 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion-ioctl.c @@ -0,0 +1,109 @@ +/* + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +union ion_ioctl_arg { + struct ion_allocation_data allocation; + struct ion_heap_query query; +}; + +static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg) +{ + int ret = 0; + + switch (cmd) { + case ION_IOC_HEAP_QUERY: + ret = arg->query.reserved0 != 0; + ret |= arg->query.reserved1 != 0; + ret |= arg->query.reserved2 != 0; + break; + default: + break; + } + + return ret ? -EINVAL : 0; +} + +/* fix up the cases where the ioctl direction bits are incorrect */ +static unsigned int ion_ioctl_dir(unsigned int cmd) +{ + switch (cmd) { + default: + return _IOC_DIR(cmd); + } +} + +long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + unsigned int dir; + union ion_ioctl_arg data; + + dir = ion_ioctl_dir(cmd); + + if (_IOC_SIZE(cmd) > sizeof(data)) + return -EINVAL; + + /* + * The copy_from_user is unconditional here for both read and write + * to do the validate. If there is no write for the ioctl, the + * buffer is cleared + */ + if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) + return -EFAULT; + + ret = validate_ioctl_arg(cmd, &data); + if (ret) { + pr_warn_once("%s: ioctl validate failed\n", __func__); + return ret; + } + + if (!(dir & _IOC_WRITE)) + memset(&data, 0, sizeof(data)); + + switch (cmd) { + case ION_IOC_ALLOC: + { + int fd; + + fd = ion_alloc(data.allocation.len, + data.allocation.heap_id_mask, + data.allocation.flags); + if (fd < 0) + return fd; + + data.allocation.fd = fd; + + break; + } + case ION_IOC_HEAP_QUERY: + ret = ion_query_heaps(&data.query); + break; + default: + return -ENOTTY; + } + + if (dir & _IOC_READ) { + if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) + return -EFAULT; + } + return ret; +} diff --git a/drivers/soc/realtek/common/mem_allocator/ion.c b/drivers/soc/realtek/common/mem_allocator/ion.c new file mode 100644 index 000000000000..9bc89820b07b --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion.c @@ -0,0 +1,817 @@ +/* + * + * drivers/staging/android/ion/ion.c + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include + +#include "ion.h" + +static struct ion_device *internal_dev; +static int heap_id; +static atomic_long_t total_heap_bytes; + +#define CHECK_PROTECT_FLAG + +#ifdef CHECK_PROTECT_FLAG +static bool ion_buffer_is_protected(struct ion_buffer *buffer) +{ + unsigned int prot_flags; + /* buffer->flags[BIT24 BIT25 BIT26]: 3b'001 ~ 3b'111 (6 types) */ + prot_flags = ION_PROTECTED_TYPE_GET(buffer->flags); + + /* add your code here for more protected types support */ + if( prot_flags /*== 2*/ ) { + return true; + } + return false; +} +#endif + +bool ion_buffer_cached(struct ion_buffer *buffer) +{ + return !!(buffer->flags & ION_FLAG_CACHED); +} + +/* this function should only be called while dev->lock is held */ +static void ion_buffer_add(struct ion_device *dev, + struct ion_buffer *buffer) +{ + struct rb_node **p = &dev->buffers.rb_node; + struct rb_node *parent = NULL; + struct ion_buffer *entry; + + while (*p) { + parent = *p; + entry = rb_entry(parent, struct ion_buffer, node); + + if (buffer < entry) { + p = &(*p)->rb_left; + } else if (buffer > entry) { + p = &(*p)->rb_right; + } else { + pr_err("%s: buffer already found.", __func__); + BUG(); + } + } + + rb_link_node(&buffer->node, parent, p); + rb_insert_color(&buffer->node, &dev->buffers); +} + +/* this function should only be called while dev->lock is held */ +static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, + struct ion_device *dev, + unsigned long len, + unsigned long flags) +{ + struct ion_buffer *buffer; + struct sg_table *table; + int ret; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + + buffer->heap = heap; + buffer->flags = flags; + + { + pid_t tgid; + get_task_struct(current->group_leader); + task_lock(current->group_leader); + tgid = task_tgid_nr(current->group_leader); + task_unlock(current->group_leader); + put_task_struct(current->group_leader); + buffer->pid = (int) tgid; + } + + ret = heap->ops->allocate(heap, buffer, len, flags); + + if (ret) { + if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE)) + goto err2; + + ion_heap_freelist_drain(heap, 0); + ret = heap->ops->allocate(heap, buffer, len, flags); + if (ret) + goto err2; + } + + if (!buffer->sg_table) { + WARN_ONCE(1, "This heap needs to set the sgtable"); + ret = -EINVAL; + goto err1; + } + + table = buffer->sg_table; + buffer->dev = dev; + buffer->size = len; + + buffer->dev = dev; + buffer->size = len; + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->lock); + mutex_lock(&dev->buffer_lock); + ion_buffer_add(dev, buffer); + mutex_unlock(&dev->buffer_lock); + atomic_long_add(len, &total_heap_bytes); + return buffer; + +err1: + heap->ops->free(buffer); +err2: + kfree(buffer); + return ERR_PTR(ret); +} + +void ion_buffer_destroy(struct ion_buffer *buffer) +{ + if (buffer->kmap_cnt > 0) { + pr_warn_once("%s: buffer still mapped in the kernel\n", + __func__); + buffer->heap->ops->unmap_kernel(buffer->heap, buffer); + } + buffer->heap->ops->free(buffer); + kfree(buffer); +} + +static void _ion_buffer_destroy(struct ion_buffer *buffer) +{ + struct ion_heap *heap = buffer->heap; + struct ion_device *dev = buffer->dev; + + mutex_lock(&dev->buffer_lock); + rb_erase(&buffer->node, &dev->buffers); + mutex_unlock(&dev->buffer_lock); + atomic_long_sub(buffer->size, &total_heap_bytes); + + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) + ion_heap_freelist_add(heap, buffer); + else + ion_buffer_destroy(buffer); +} + +static void *ion_buffer_kmap_get(struct ion_buffer *buffer) +{ + void *vaddr; + + if (buffer->kmap_cnt) { + buffer->kmap_cnt++; + return buffer->vaddr; + } + vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer); + if (WARN_ONCE(!vaddr, + "heap->ops->map_kernel should return ERR_PTR on error")) + return ERR_PTR(-EINVAL); + if (IS_ERR(vaddr)) + return vaddr; + buffer->vaddr = vaddr; + buffer->kmap_cnt++; + return vaddr; +} + +static void ion_buffer_kmap_put(struct ion_buffer *buffer) +{ + buffer->kmap_cnt--; + if (!buffer->kmap_cnt) { + buffer->heap->ops->unmap_kernel(buffer->heap, buffer); + buffer->vaddr = NULL; + } +} + +static struct sg_table *dup_sg_table(struct sg_table *table) +{ + struct sg_table *new_table; + int ret, i; + struct scatterlist *sg, *new_sg; + + new_table = kzalloc(sizeof(*new_table), GFP_KERNEL); + if (!new_table) + return ERR_PTR(-ENOMEM); + + ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL); + if (ret) { + kfree(new_table); + return ERR_PTR(-ENOMEM); + } + + new_sg = new_table->sgl; + for_each_sg(table->sgl, sg, table->nents, i) { + memcpy(new_sg, sg, sizeof(*sg)); + sg->dma_address = 0; + new_sg = sg_next(new_sg); + } + + return new_table; +} + +static void free_duped_table(struct sg_table *table) +{ + sg_free_table(table); + kfree(table); +} + +struct ion_dma_buf_attachment { + struct device *dev; + struct sg_table *table; + struct list_head list; +#ifdef CHECK_PROTECT_FLAG + struct ion_buffer *buffer; +#endif +}; + +static int ion_dma_buf_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct ion_dma_buf_attachment *a; + struct sg_table *table; + struct ion_buffer *buffer = dmabuf->priv; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + table = dup_sg_table(buffer->sg_table); + if (IS_ERR(table)) { + kfree(a); + return -ENOMEM; + } + + a->table = table; + a->dev = attachment->dev; +#ifdef CHECK_PROTECT_FLAG + a->buffer = buffer; +#endif + INIT_LIST_HEAD(&a->list); + + attachment->priv = a; + + mutex_lock(&buffer->lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->lock); + + return 0; +} + +static void ion_dma_buf_detatch(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct ion_dma_buf_attachment *a = attachment->priv; + struct ion_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->lock); + list_del(&a->list); + mutex_unlock(&buffer->lock); + free_duped_table(a->table); + + kfree(a); +} + +static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct ion_dma_buf_attachment *a = attachment->priv; + struct sg_table *table; +#ifdef CHECK_PROTECT_FLAG + struct ion_buffer *buffer; +#endif + + table = a->table; + +#ifdef CHECK_PROTECT_FLAG + // sanity check first + if (attachment && attachment->priv) { + a = attachment->priv; + buffer = a->buffer; + if( buffer && ion_buffer_is_protected(buffer)) { + if (!dma_map_sg_attrs(attachment->dev, table->sgl, table->nents, + direction, DMA_ATTR_SKIP_CPU_SYNC)) + return ERR_PTR(-ENOMEM); + return table; + } + } +#endif + + if (!dma_map_sg(attachment->dev, table->sgl, table->nents, + direction)) + return ERR_PTR(-ENOMEM); + + return table; +} + +static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ +#ifdef CHECK_PROTECT_FLAG + struct ion_dma_buf_attachment *a; + struct ion_buffer *buffer; + // sanity check + if (attachment && attachment->priv) { + a = attachment->priv; + buffer = a->buffer; + if (buffer && ion_buffer_is_protected(buffer)) { + dma_unmap_sg_attrs(attachment->dev, table->sgl, table->nents, + direction, DMA_ATTR_SKIP_CPU_SYNC); + return; + } + } +#endif + + dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction); +} + +static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct ion_buffer *buffer = dmabuf->priv; + int ret = 0; + + if (!buffer->heap->ops->map_user) { + pr_err("%s: this heap does not define a method for mapping to userspace\n", + __func__); + return -EINVAL; + } + + if (!(buffer->flags & ION_FLAG_CACHED)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + mutex_lock(&buffer->lock); + /* now map it to userspace */ + ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma); + mutex_unlock(&buffer->lock); + + if (ret) + pr_err("%s: failure mapping buffer to userspace\n", + __func__); + + return ret; +} + +static void ion_dma_buf_release(struct dma_buf *dmabuf) +{ + struct ion_buffer *buffer = dmabuf->priv; + + _ion_buffer_destroy(buffer); +} + +static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) +{ + struct ion_buffer *buffer = dmabuf->priv; + + return buffer->vaddr + offset * PAGE_SIZE; +} + +static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset, + void *ptr) +{ +} + +static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct ion_buffer *buffer = dmabuf->priv; + void *vaddr; + struct ion_dma_buf_attachment *a; + + /* + * TODO: Move this elsewhere because we don't always need a vaddr + */ + if (buffer->heap->ops->map_kernel) { + mutex_lock(&buffer->lock); + vaddr = ion_buffer_kmap_get(buffer); + mutex_unlock(&buffer->lock); + } + + mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents, + direction); + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct ion_buffer *buffer = dmabuf->priv; + struct ion_dma_buf_attachment *a; + + if (buffer->heap->ops->map_kernel) { + mutex_lock(&buffer->lock); + ion_buffer_kmap_put(buffer); + mutex_unlock(&buffer->lock); + } + + mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents, + direction); + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static const struct dma_buf_ops dma_buf_ops = { + .map_dma_buf = ion_map_dma_buf, + .unmap_dma_buf = ion_unmap_dma_buf, + .mmap = ion_mmap, + .release = ion_dma_buf_release, + .attach = ion_dma_buf_attach, + .detach = ion_dma_buf_detatch, + .begin_cpu_access = ion_dma_buf_begin_cpu_access, + .end_cpu_access = ion_dma_buf_end_cpu_access, + .map = ion_dma_buf_kmap, + .unmap = ion_dma_buf_kunmap, +}; + +int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags) +{ + struct ion_device *dev = internal_dev; + struct ion_buffer *buffer = NULL; + struct ion_heap *heap; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + int fd; + struct dma_buf *dmabuf; + + pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__, + len, heap_id_mask, flags); + /* + * traverse the list of heaps available in this system in priority + * order. If the heap type is supported by the client, and matches the + * request of the caller allocate from it. Repeat until allocate has + * succeeded or all heaps have been tried + */ + len = PAGE_ALIGN(len); + + if (!len) + return -EINVAL; + + down_read(&dev->lock); + plist_for_each_entry(heap, &dev->heaps, node) { + /* if the caller didn't specify this heap id */ + if (!((1 << heap->id) & heap_id_mask)) + continue; + buffer = ion_buffer_create(heap, dev, len, flags); + if (!IS_ERR(buffer)) + break; + } + up_read(&dev->lock); + + if (!buffer) + return -ENODEV; + + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + exp_info.ops = &dma_buf_ops; + exp_info.size = buffer->size; + exp_info.flags = O_RDWR; + exp_info.priv = buffer; + + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + _ion_buffer_destroy(buffer); + return PTR_ERR(dmabuf); + } + + fd = dma_buf_fd(dmabuf, O_CLOEXEC); + if (fd < 0) + dma_buf_put(dmabuf); + + return fd; +} + +int ion_query_heaps(struct ion_heap_query *query) +{ + struct ion_device *dev = internal_dev; + struct ion_heap_data __user *buffer = u64_to_user_ptr(query->heaps); + int ret = -EINVAL, cnt = 0, max_cnt; + struct ion_heap *heap; + struct ion_heap_data hdata; + + memset(&hdata, 0, sizeof(hdata)); + + down_read(&dev->lock); + if (!buffer) { + query->cnt = dev->heap_cnt; + ret = 0; + goto out; + } + + if (query->cnt <= 0) + goto out; + + max_cnt = query->cnt; + + plist_for_each_entry(heap, &dev->heaps, node) { + strncpy(hdata.name, heap->name, MAX_HEAP_NAME); + hdata.name[sizeof(hdata.name) - 1] = '\0'; + hdata.type = heap->type; + hdata.heap_id = heap->id; + + if (copy_to_user(&buffer[cnt], &hdata, sizeof(hdata))) { + ret = -EFAULT; + goto out; + } + + cnt++; + if (cnt >= max_cnt) + break; + } + + query->cnt = cnt; + ret = 0; +out: + up_read(&dev->lock); + return ret; +} + +static const struct file_operations ion_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = ion_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ion_ioctl, +#endif +}; + +static int debug_shrink_set(void *data, u64 val) +{ + struct ion_heap *heap = data; + struct shrink_control sc; + int objs; + + sc.gfp_mask = GFP_HIGHUSER; + sc.nr_to_scan = val; + + if (!val) { + objs = heap->shrinker.count_objects(&heap->shrinker, &sc); + sc.nr_to_scan = objs; + } + + heap->shrinker.scan_objects(&heap->shrinker, &sc); + return 0; +} + +static int debug_shrink_get(void *data, u64 *val) +{ + struct ion_heap *heap = data; + struct shrink_control sc; + int objs; + + sc.gfp_mask = GFP_HIGHUSER; + sc.nr_to_scan = 0; + + objs = heap->shrinker.count_objects(&heap->shrinker, &sc); + *val = objs; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, + debug_shrink_set, "%llu\n"); + +void ion_device_add_heap(struct ion_heap *heap) +{ + struct dentry *debug_file; + struct ion_device *dev = internal_dev; + + if (!heap->ops->allocate || !heap->ops->free) + pr_err("%s: can not add heap with invalid ops struct.\n", + __func__); + + spin_lock_init(&heap->free_lock); + heap->free_list_size = 0; + + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) + ion_heap_init_deferred_free(heap); + + if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink) + ion_heap_init_shrinker(heap); + + heap->dev = dev; + + if (dev == NULL) + WARN_ON(1); + + down_write(&dev->lock); + heap->id = heap_id++; + /* + * use negative heap->id to reverse the priority -- when traversing + * the list later attempt higher id numbers first + */ + plist_node_init(&heap->node, -heap->id); + plist_add(&heap->node, &dev->heaps); + + if (heap->shrinker.count_objects && heap->shrinker.scan_objects) { + char debug_name[64]; + + snprintf(debug_name, 64, "%s_shrink", heap->name); + debug_file = debugfs_create_file( + debug_name, 0644, dev->debug_root, heap, + &debug_shrink_fops); + if (!debug_file) { + char buf[256], *path; + + path = dentry_path(dev->debug_root, buf, 256); + pr_err("Failed to create heap shrinker debugfs at %s/%s\n", + path, debug_name); + } + } + + dev->heap_cnt++; + up_write(&dev->lock); +} +EXPORT_SYMBOL(ion_device_add_heap); + +static ssize_t +total_heaps_kb_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + u64 size_in_bytes = atomic_long_read(&total_heap_bytes); + + return sprintf(buf, "%llu\n", div_u64(size_in_bytes, 1024)); +} + +static ssize_t +total_pools_kb_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + u64 size_in_bytes = ion_page_pool_nr_pages() * PAGE_SIZE; + + return sprintf(buf, "%llu\n", div_u64(size_in_bytes, 1024)); +} + +static ssize_t +memory_usage_kb_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int n = 0; + struct ion_device *dev = internal_dev; + down_read(&dev->lock); + mutex_lock(&dev->buffer_lock); + n += sprintf(buf+n, "%16s %16s\n", "pid", "size"); + n += sprintf(buf+n, "-----------------------\n"); + do { + struct rb_node *p = rb_first(&dev->buffers); + size_t i; + const size_t slot_count = 2048; + struct slot { + bool valid; + int pid; + unsigned long long size; + } * slots = NULL; + slots = (struct slot *) kzalloc(sizeof(struct slot) * slot_count, GFP_KERNEL); + if (!slots) { + break; + } + while (p) { + struct ion_buffer *buffer = rb_entry(p, struct ion_buffer, node); + for (i=0;ivalid) { + slot->pid = buffer->pid; + slot->size = buffer->size; + slot->valid = true; + break; + } + if (slot->pid == buffer->pid) { + slot->size += buffer->size; + break; + } + } + p = rb_next(p); + } + + for (i=0;ivalid) + break; + n += sprintf(buf+n, "%16d %16llu\n", slot->pid, div_u64(slot->size, 1024)); + } + + kfree(slots); + } while (0); + mutex_unlock(&dev->buffer_lock); + up_read(&dev->lock); + return n; +} + +static struct kobj_attribute total_heaps_kb_attr = + __ATTR_RO(total_heaps_kb); + +static struct kobj_attribute total_pools_kb_attr = + __ATTR_RO(total_pools_kb); + +static struct kobj_attribute memory_usage_kb_attr = + __ATTR_RO(memory_usage_kb); + +static struct attribute *ion_device_attrs[] = { + &total_heaps_kb_attr.attr, + &total_pools_kb_attr.attr, + &memory_usage_kb_attr.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(ion_device); + +static int ion_init_sysfs(void) +{ + struct kobject *ion_kobj; + int ret; + + ion_kobj = kobject_create_and_add("ion", kernel_kobj); + if (!ion_kobj) + return -ENOMEM; + + ret = sysfs_create_groups(ion_kobj, ion_device_groups); + if (ret) { + kobject_put(ion_kobj); + return ret; + } + + return 0; +} + +static int ion_device_create(void) +{ + struct ion_device *idev; + int ret; + + idev = kzalloc(sizeof(*idev), GFP_KERNEL); + if (!idev) + return -ENOMEM; + + idev->dev.minor = MISC_DYNAMIC_MINOR; + idev->dev.name = "ion"; + idev->dev.fops = &ion_fops; + idev->dev.parent = NULL; + ret = misc_register(&idev->dev); + if (ret) { + pr_err("ion: failed to register misc device.\n"); + goto err_reg; + } + + ret = ion_init_sysfs(); + if (ret) { + pr_err("ion: failed to add sysfs attributes.\n"); + goto err_sysfs; + } + + idev->debug_root = debugfs_create_dir("ion", NULL); + if (!idev->debug_root) { + pr_err("ion: failed to create debugfs root directory.\n"); + goto debugfs_done; + } + +debugfs_done: + idev->buffers = RB_ROOT; + mutex_init(&idev->buffer_lock); + init_rwsem(&idev->lock); + plist_head_init(&idev->heaps); + internal_dev = idev; + return 0; + +err_sysfs: + misc_deregister(&idev->dev); +err_reg: + kfree(idev); + return ret; +} +subsys_initcall_sync(ion_device_create); diff --git a/drivers/soc/realtek/common/mem_allocator/ion.h b/drivers/soc/realtek/common/mem_allocator/ion.h new file mode 100644 index 000000000000..9f2123405c8e --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion.h @@ -0,0 +1,364 @@ +/* + * drivers/staging/android/ion/ion.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 _ION_H +#define _ION_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/** + * struct ion_platform_heap - defines a heap in the given platform + * @type: type of the heap from ion_heap_type enum + * @id: unique identifier for heap. When allocating higher numb ers + * will be allocated from first. At allocation these are passed + * as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS. + * @name: used for debug purposes + * @base: base address of heap in physical memory if applicable + * @size: size of the heap in bytes if applicable + * @priv: private info passed from the board file + * + * Provided by the board file. + */ +struct ion_platform_heap { + enum ion_heap_type type; + unsigned int id; + const char *name; + phys_addr_t base; + size_t size; + phys_addr_t align; + void *priv; +}; + +/** + * struct ion_buffer - metadata for a particular buffer + * @ref: reference count + * @node: node in the ion_device buffers tree + * @dev: back pointer to the ion_device + * @heap: back pointer to the heap the buffer came from + * @flags: buffer specific flags + * @private_flags: internal buffer specific flags + * @size: size of the buffer + * @priv_virt: private data to the buffer representable as + * a void * + * @lock: protects the buffers cnt fields + * @kmap_cnt: number of times the buffer is mapped to the kernel + * @vaddr: the kernel mapping if kmap_cnt is not zero + * @sg_table: the sg table for the buffer if dmap_cnt is not zero + */ +struct ion_buffer { + union { + struct rb_node node; + struct list_head list; + }; + struct ion_device *dev; + struct ion_heap *heap; + unsigned long flags; + unsigned long private_flags; + size_t size; + void *priv_virt; + struct mutex lock; + int kmap_cnt; + void *vaddr; + struct sg_table *sg_table; + struct list_head attachments; + int pid; +}; +void ion_buffer_destroy(struct ion_buffer *buffer); + +/** + * struct ion_device - the metadata of the ion device node + * @dev: the actual misc device + * @buffers: an rb tree of all the existing buffers + * @buffer_lock: lock protecting the tree of buffers + * @lock: rwsem protecting the tree of heaps and clients + */ +struct ion_device { + struct miscdevice dev; + struct rb_root buffers; + struct mutex buffer_lock; + struct rw_semaphore lock; + struct plist_head heaps; + struct dentry *debug_root; + int heap_cnt; +}; + +/** + * struct ion_heap_ops - ops to operate on a given heap + * @allocate: allocate memory + * @free: free memory + * @map_kernel map memory to the kernel + * @unmap_kernel unmap memory to the kernel + * @map_user map memory to userspace + * + * allocate, phys, and map_user return 0 on success, -errno on error. + * map_dma and map_kernel return pointer on success, ERR_PTR on + * error. @free will be called with ION_PRIV_FLAG_SHRINKER_FREE set in + * the buffer's private_flags when called from a shrinker. In that + * case, the pages being free'd must be truly free'd back to the + * system, not put in a page pool or otherwise cached. + */ +struct ion_heap_ops { + int (*allocate)(struct ion_heap *heap, + struct ion_buffer *buffer, unsigned long len, + unsigned long flags); + void (*free)(struct ion_buffer *buffer); + void * (*map_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); + void (*unmap_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); + int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer, + struct vm_area_struct *vma); + int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan); +}; + +/** + * heap flags - flags between the heaps and core ion code + */ +#define ION_HEAP_FLAG_DEFER_FREE BIT(0) + +/** + * private flags - flags internal to ion + */ +/* + * Buffer is being freed from a shrinker function. Skip any possible + * heap-specific caching mechanism (e.g. page pools). Guarantees that + * any buffer storage that came from the system allocator will be + * returned to the system allocator. + */ +#define ION_PRIV_FLAG_SHRINKER_FREE BIT(0) + +/** + * struct ion_heap - represents a heap in the system + * @node: rb node to put the heap on the device's tree of heaps + * @dev: back pointer to the ion_device + * @type: type of heap + * @ops: ops struct as above + * @flags: flags + * @id: id of heap, also indicates priority of this heap when + * allocating. These are specified by platform data and + * MUST be unique + * @name: used for debugging + * @shrinker: a shrinker for the heap + * @free_list: free list head if deferred free is used + * @free_list_size size of the deferred free list in bytes + * @lock: protects the free list + * @waitqueue: queue to wait on from deferred free thread + * @task: task struct of deferred free thread + * @debug_show: called when heap debug file is read to add any + * heap specific debug info to output + * + * Represents a pool of memory from which buffers can be made. In some + * systems the only heap is regular system memory allocated via vmalloc. + * On others, some blocks might require large physically contiguous buffers + * that are allocated from a specially reserved heap. + */ +struct ion_heap { + struct plist_node node; + struct ion_device *dev; + enum ion_heap_type type; + struct ion_heap_ops *ops; + unsigned long flags; + unsigned int id; + const char *name; + struct shrinker shrinker; + struct list_head free_list; + size_t free_list_size; + spinlock_t free_lock; + wait_queue_head_t waitqueue; + struct task_struct *task; + + int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); +}; + +/** + * ion_buffer_cached - this ion buffer is cached + * @buffer: buffer + * + * indicates whether this ion buffer is cached + */ +bool ion_buffer_cached(struct ion_buffer *buffer); + +/** + * ion_buffer_fault_user_mappings - fault in user mappings of this buffer + * @buffer: buffer + * + * indicates whether userspace mappings of this buffer will be faulted + * in, this can affect how buffers are allocated from the heap. + */ +bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer); + +/** + * ion_device_add_heap - adds a heap to the ion device + * @heap: the heap to add + */ +void ion_device_add_heap(struct ion_heap *heap); + +/** + * some helpers for common operations on buffers using the sg_table + * and vaddr fields + */ +void *ion_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer); +void ion_heap_unmap_kernel(struct ion_heap *heap, struct ion_buffer *buffer); +int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, + struct vm_area_struct *vma); +int ion_heap_buffer_zero(struct ion_buffer *buffer); +int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); + +int ion_alloc(size_t len, + unsigned int heap_id_mask, + unsigned int flags); + +/** + * ion_heap_init_shrinker + * @heap: the heap + * + * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op + * this function will be called to setup a shrinker to shrink the freelists + * and call the heap's shrink op. + */ +void ion_heap_init_shrinker(struct ion_heap *heap); + +/** + * ion_heap_init_deferred_free -- initialize deferred free functionality + * @heap: the heap + * + * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag this function will + * be called to setup deferred frees. Calls to free the buffer will + * return immediately and the actual free will occur some time later + */ +int ion_heap_init_deferred_free(struct ion_heap *heap); + +/** + * ion_heap_freelist_add - add a buffer to the deferred free list + * @heap: the heap + * @buffer: the buffer + * + * Adds an item to the deferred freelist. + */ +void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer); + +/** + * ion_heap_freelist_drain - drain the deferred free list + * @heap: the heap + * @size: amount of memory to drain in bytes + * + * Drains the indicated amount of memory from the deferred freelist immediately. + * Returns the total amount freed. The total freed may be higher depending + * on the size of the items in the list, or lower if there is insufficient + * total memory on the freelist. + */ +size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size); + +/** + * ion_heap_freelist_shrink - drain the deferred free + * list, skipping any heap-specific + * pooling or caching mechanisms + * + * @heap: the heap + * @size: amount of memory to drain in bytes + * + * Drains the indicated amount of memory from the deferred freelist immediately. + * Returns the total amount freed. The total freed may be higher depending + * on the size of the items in the list, or lower if there is insufficient + * total memory on the freelist. + * + * Unlike with @ion_heap_freelist_drain, don't put any pages back into + * page pools or otherwise cache the pages. Everything must be + * genuinely free'd back to the system. If you're free'ing from a + * shrinker you probably want to use this. Note that this relies on + * the heap.ops.free callback honoring the ION_PRIV_FLAG_SHRINKER_FREE + * flag. + */ +size_t ion_heap_freelist_shrink(struct ion_heap *heap, + size_t size); + +/** + * ion_heap_freelist_size - returns the size of the freelist in bytes + * @heap: the heap + */ +size_t ion_heap_freelist_size(struct ion_heap *heap); + + +/** + * functions for creating and destroying a heap pool -- allows you + * to keep a pool of pre allocated memory to use from your heap. Keeping + * a pool of memory that is ready for dma, ie any cached mapping have been + * invalidated from the cache, provides a significant performance benefit on + * many systems + */ + +/** + * struct ion_page_pool - pagepool struct + * @high_count: number of highmem items in the pool + * @low_count: number of lowmem items in the pool + * @high_items: list of highmem items + * @low_items: list of lowmem items + * @mutex: lock protecting this struct and especially the count + * item list + * @gfp_mask: gfp_mask to use from alloc + * @order: order of pages in the pool + * @list: plist node for list of pools + * @cached: it's cached pool or not + * + * Allows you to keep a pool of pre allocated pages to use from your heap. + * Keeping a pool of pages that is ready for dma, ie any cached mapping have + * been invalidated from the cache, provides a significant performance benefit + * on many systems + */ +struct ion_page_pool { + int high_count; + int low_count; + bool cached; + struct list_head high_items; + struct list_head low_items; + struct mutex mutex; + gfp_t gfp_mask; + unsigned int order; + struct plist_node list; +}; + +struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order, + bool cached); +void ion_page_pool_destroy(struct ion_page_pool *pool); +struct page *ion_page_pool_alloc(struct ion_page_pool *pool); +void ion_page_pool_free(struct ion_page_pool *pool, struct page *page); + +long ion_page_pool_nr_pages(void); + +/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool + * @pool: the pool + * @gfp_mask: the memory type to reclaim + * @nr_to_scan: number of items to shrink in pages + * + * returns the number of items freed in pages + */ +int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, + int nr_to_scan); + +long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +int ion_query_heaps(struct ion_heap_query *query); + +#endif /* _ION_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/ion_carveout_heap.c b/drivers/soc/realtek/common/mem_allocator/ion_carveout_heap.c new file mode 100644 index 000000000000..fee7650d6fbb --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion_carveout_heap.c @@ -0,0 +1,147 @@ +/* + * drivers/staging/android/ion/ion_carveout_heap.c + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +#define ION_CARVEOUT_ALLOCATE_FAIL -1 + +struct ion_carveout_heap { + struct ion_heap heap; + struct gen_pool *pool; + phys_addr_t base; +}; + +static phys_addr_t ion_carveout_allocate(struct ion_heap *heap, + unsigned long size) +{ + struct ion_carveout_heap *carveout_heap = + container_of(heap, struct ion_carveout_heap, heap); + unsigned long offset = gen_pool_alloc(carveout_heap->pool, size); + + if (!offset) + return ION_CARVEOUT_ALLOCATE_FAIL; + + return offset; +} + +static void ion_carveout_free(struct ion_heap *heap, phys_addr_t addr, + unsigned long size) +{ + struct ion_carveout_heap *carveout_heap = + container_of(heap, struct ion_carveout_heap, heap); + + if (addr == ION_CARVEOUT_ALLOCATE_FAIL) + return; + gen_pool_free(carveout_heap->pool, addr, size); +} + +static int ion_carveout_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned long flags) +{ + struct sg_table *table; + phys_addr_t paddr; + int ret; + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + return -ENOMEM; + ret = sg_alloc_table(table, 1, GFP_KERNEL); + if (ret) + goto err_free; + + paddr = ion_carveout_allocate(heap, size); + if (paddr == ION_CARVEOUT_ALLOCATE_FAIL) { + ret = -ENOMEM; + goto err_free_table; + } + + sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0); + buffer->sg_table = table; + + return 0; + +err_free_table: + sg_free_table(table); +err_free: + kfree(table); + return ret; +} + +static void ion_carveout_heap_free(struct ion_buffer *buffer) +{ + struct ion_heap *heap = buffer->heap; + struct sg_table *table = buffer->sg_table; + struct page *page = sg_page(table->sgl); + phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); + + ion_heap_buffer_zero(buffer); + + ion_carveout_free(heap, paddr, buffer->size); + sg_free_table(table); + kfree(table); +} + +static struct ion_heap_ops carveout_heap_ops = { + .allocate = ion_carveout_heap_allocate, + .free = ion_carveout_heap_free, + .map_user = ion_heap_map_user, + .map_kernel = ion_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, +}; + +struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data) +{ + struct ion_carveout_heap *carveout_heap; + int ret; + + struct page *page; + size_t size; + + page = pfn_to_page(PFN_DOWN(heap_data->base)); + size = heap_data->size; + + ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); + if (ret) + return ERR_PTR(ret); + + carveout_heap = kzalloc(sizeof(*carveout_heap), GFP_KERNEL); + if (!carveout_heap) + return ERR_PTR(-ENOMEM); + + carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1); + if (!carveout_heap->pool) { + kfree(carveout_heap); + return ERR_PTR(-ENOMEM); + } + carveout_heap->base = heap_data->base; + gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size, + -1); + carveout_heap->heap.ops = &carveout_heap_ops; + carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT; + carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; + + return &carveout_heap->heap; +} diff --git a/drivers/soc/realtek/common/mem_allocator/ion_chunk_heap.c b/drivers/soc/realtek/common/mem_allocator/ion_chunk_heap.c new file mode 100644 index 000000000000..102c09398317 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion_chunk_heap.c @@ -0,0 +1,162 @@ +/* + * drivers/staging/android/ion/ion_chunk_heap.c + * + * Copyright (C) 2012 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +struct ion_chunk_heap { + struct ion_heap heap; + struct gen_pool *pool; + phys_addr_t base; + unsigned long chunk_size; + unsigned long size; + unsigned long allocated; +}; + +static int ion_chunk_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned long flags) +{ + struct ion_chunk_heap *chunk_heap = + container_of(heap, struct ion_chunk_heap, heap); + struct sg_table *table; + struct scatterlist *sg; + int ret, i; + unsigned long num_chunks; + unsigned long allocated_size; + + allocated_size = ALIGN(size, chunk_heap->chunk_size); + num_chunks = allocated_size / chunk_heap->chunk_size; + + if (allocated_size > chunk_heap->size - chunk_heap->allocated) + return -ENOMEM; + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + return -ENOMEM; + ret = sg_alloc_table(table, num_chunks, GFP_KERNEL); + if (ret) { + kfree(table); + return ret; + } + + sg = table->sgl; + for (i = 0; i < num_chunks; i++) { + unsigned long paddr = gen_pool_alloc(chunk_heap->pool, + chunk_heap->chunk_size); + if (!paddr) + goto err; + sg_set_page(sg, pfn_to_page(PFN_DOWN(paddr)), + chunk_heap->chunk_size, 0); + sg = sg_next(sg); + } + + buffer->sg_table = table; + chunk_heap->allocated += allocated_size; + return 0; +err: + sg = table->sgl; + for (i -= 1; i >= 0; i--) { + gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), + sg->length); + sg = sg_next(sg); + } + sg_free_table(table); + kfree(table); + return -ENOMEM; +} + +static void ion_chunk_heap_free(struct ion_buffer *buffer) +{ + struct ion_heap *heap = buffer->heap; + struct ion_chunk_heap *chunk_heap = + container_of(heap, struct ion_chunk_heap, heap); + struct sg_table *table = buffer->sg_table; + struct scatterlist *sg; + int i; + unsigned long allocated_size; + + allocated_size = ALIGN(buffer->size, chunk_heap->chunk_size); + + ion_heap_buffer_zero(buffer); + + for_each_sg(table->sgl, sg, table->nents, i) { + gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), + sg->length); + } + chunk_heap->allocated -= allocated_size; + sg_free_table(table); + kfree(table); +} + +static struct ion_heap_ops chunk_heap_ops = { + .allocate = ion_chunk_heap_allocate, + .free = ion_chunk_heap_free, + .map_user = ion_heap_map_user, + .map_kernel = ion_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, +}; + +struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) +{ + struct ion_chunk_heap *chunk_heap; + int ret; + struct page *page; + size_t size; + + page = pfn_to_page(PFN_DOWN(heap_data->base)); + size = heap_data->size; + + ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); + if (ret) + return ERR_PTR(ret); + + chunk_heap = kzalloc(sizeof(*chunk_heap), GFP_KERNEL); + if (!chunk_heap) + return ERR_PTR(-ENOMEM); + + chunk_heap->chunk_size = (unsigned long)heap_data->priv; + chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) + + PAGE_SHIFT, -1); + if (!chunk_heap->pool) { + ret = -ENOMEM; + goto error_gen_pool_create; + } + chunk_heap->base = heap_data->base; + chunk_heap->size = heap_data->size; + chunk_heap->allocated = 0; + + gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1); + chunk_heap->heap.ops = &chunk_heap_ops; + chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK; + chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; + pr_debug("%s: base %pa size %zu\n", __func__, + &chunk_heap->base, heap_data->size); + + return &chunk_heap->heap; + +error_gen_pool_create: + kfree(chunk_heap); + return ERR_PTR(ret); +} + diff --git a/drivers/soc/realtek/common/mem_allocator/ion_cma_heap.c b/drivers/soc/realtek/common/mem_allocator/ion_cma_heap.c new file mode 100644 index 000000000000..cfee54e29c80 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion_cma_heap.c @@ -0,0 +1,173 @@ +/* + * drivers/staging/android/ion/ion_cma_heap.c + * + * Copyright (C) Linaro 2012 + * Author: for ST-Ericsson. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +struct ion_cma_heap { + struct ion_heap heap; + struct cma *cma; +}; + +#define to_cma_heap(x) container_of(x, struct ion_cma_heap, heap) + +/* ION CMA heap operations functions */ +static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, + unsigned long len, + unsigned long flags) +{ + struct ion_cma_heap *cma_heap = to_cma_heap(heap); + struct sg_table *table; + struct page *pages; + unsigned long size = PAGE_ALIGN(len); + unsigned long nr_pages = size >> PAGE_SHIFT; + unsigned long align = get_order(size); + int ret; + + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + + pages = cma_alloc(cma_heap->cma, nr_pages, align, GFP_KERNEL); + if (!pages) + return -ENOMEM; + + if (PageHighMem(pages)) { + unsigned long nr_clear_pages = nr_pages; + struct page *page = pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + +#if defined(CONFIG_ARM64) + memset_io(vaddr, 0, PAGE_SIZE); + if (!(buffer->flags & ION_FLAG_CACHED)) + __dma_flush_area(vaddr, PAGE_SIZE); +#else + memset(vaddr, 0, PAGE_SIZE); + if (!(buffer->flags & ION_FLAG_CACHED)) + dmac_flush_range(vaddr, vaddr + PAGE_SIZE); +#endif + kunmap_atomic(vaddr); + page++; + nr_clear_pages--; + } + } else { +#if (defined(CONFIG_ARM) || defined(CONFIG_ARM64)) + void *ptr = page_address(pages); +#endif + +#if defined(CONFIG_ARM64) + memset_io(page_address(pages), 0, size); + if (!(buffer->flags & ION_FLAG_CACHED)) + __dma_flush_area(ptr, size); +#else + memset(page_address(pages), 0, size); + if (!(buffer->flags & ION_FLAG_CACHED)) { + dmac_flush_range(ptr, ptr + size); + outer_flush_range(__pa(ptr), __pa(ptr) + size); + } +#endif + } + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + goto err; + + ret = sg_alloc_table(table, 1, GFP_KERNEL); + if (ret) + goto free_mem; + + sg_set_page(table->sgl, pages, size, 0); + + buffer->priv_virt = pages; + buffer->sg_table = table; + return 0; + +free_mem: + kfree(table); +err: + cma_release(cma_heap->cma, pages, nr_pages); + return -ENOMEM; +} + +static void ion_cma_free(struct ion_buffer *buffer) +{ + struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); + struct page *pages = buffer->priv_virt; + unsigned long nr_pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; + + /* release memory */ + cma_release(cma_heap->cma, pages, nr_pages); + /* release sg table */ + sg_free_table(buffer->sg_table); + kfree(buffer->sg_table); +} + +static struct ion_heap_ops ion_cma_ops = { + .allocate = ion_cma_allocate, + .free = ion_cma_free, + .map_user = ion_heap_map_user, + .map_kernel = ion_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, +}; + +static struct ion_heap *__ion_cma_heap_create(struct cma *cma) +{ + struct ion_cma_heap *cma_heap; + + cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); + + if (!cma_heap) + return ERR_PTR(-ENOMEM); + + cma_heap->heap.ops = &ion_cma_ops; + /* + * get device from private heaps data, later it will be + * used to make the link with reserved CMA memory + */ + cma_heap->cma = cma; + cma_heap->heap.type = ION_HEAP_TYPE_DMA; + return &cma_heap->heap; +} + +static int __ion_add_cma_heaps(struct cma *cma, void *data) +{ + struct ion_heap *heap; + + heap = __ion_cma_heap_create(cma); + if (IS_ERR(heap)) + return PTR_ERR(heap); + + heap->name = cma_get_name(cma); + + ion_device_add_heap(heap); + return 0; +} + +static int ion_add_cma_heaps(void) +{ + cma_for_each_area(__ion_add_cma_heaps, NULL); + return 0; +} +device_initcall(ion_add_cma_heaps); diff --git a/drivers/soc/realtek/common/mem_allocator/ion_heap.c b/drivers/soc/realtek/common/mem_allocator/ion_heap.c new file mode 100644 index 000000000000..33a9777e7a99 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion_heap.c @@ -0,0 +1,316 @@ +/* + * drivers/staging/android/ion/ion_heap.c + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +void *ion_heap_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + struct scatterlist *sg; + int i, j; + void *vaddr; + pgprot_t pgprot; + struct sg_table *table = buffer->sg_table; + int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **tmp = pages; + + if (!pages) + return ERR_PTR(-ENOMEM); + + if (buffer->flags & ION_FLAG_CACHED) + pgprot = PAGE_KERNEL; + else + pgprot = pgprot_writecombine(PAGE_KERNEL); + + for_each_sg(table->sgl, sg, table->nents, i) { + int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE; + struct page *page = sg_page(sg); + + BUG_ON(i >= npages); + for (j = 0; j < npages_this_entry; j++) + *(tmp++) = page++; + } + vaddr = vmap(pages, npages, VM_MAP, pgprot); + vfree(pages); + + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +void ion_heap_unmap_kernel(struct ion_heap *heap, + struct ion_buffer *buffer) +{ + vunmap(buffer->vaddr); +} + +int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + struct sg_table *table = buffer->sg_table; + unsigned long addr = vma->vm_start; + unsigned long offset = vma->vm_pgoff * PAGE_SIZE; + struct scatterlist *sg; + int i; + int ret; + + for_each_sg(table->sgl, sg, table->nents, i) { + struct page *page = sg_page(sg); + unsigned long remainder = vma->vm_end - addr; + unsigned long len = sg->length; + + if (offset >= sg->length) { + offset -= sg->length; + continue; + } else if (offset) { + page += offset / PAGE_SIZE; + len = sg->length - offset; + offset = 0; + } + len = min(len, remainder); + ret = remap_pfn_range(vma, addr, page_to_pfn(page), len, + vma->vm_page_prot); + if (ret) + return ret; + addr += len; + if (addr >= vma->vm_end) + return 0; + } + return 0; +} + +static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot) +{ + void *addr = vmap(pages, num, VM_MAP, pgprot); + + if (!addr) + return -ENOMEM; + memset(addr, 0, PAGE_SIZE * num); + vunmap(addr); + + return 0; +} + +static int ion_heap_sglist_zero(struct scatterlist *sgl, unsigned int nents, + pgprot_t pgprot) +{ + int p = 0; + int ret = 0; + struct sg_page_iter piter; + struct page *pages[32]; + + for_each_sg_page(sgl, &piter, nents, 0) { + pages[p++] = sg_page_iter_page(&piter); + if (p == ARRAY_SIZE(pages)) { + ret = ion_heap_clear_pages(pages, p, pgprot); + if (ret) + return ret; + p = 0; + } + } + if (p) + ret = ion_heap_clear_pages(pages, p, pgprot); + + return ret; +} + +int ion_heap_buffer_zero(struct ion_buffer *buffer) +{ + struct sg_table *table = buffer->sg_table; + pgprot_t pgprot; + + if (buffer->flags & ION_FLAG_CACHED) + pgprot = PAGE_KERNEL; + else + pgprot = pgprot_writecombine(PAGE_KERNEL); + + return ion_heap_sglist_zero(table->sgl, table->nents, pgprot); +} + +int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot) +{ + struct scatterlist sg; + + sg_init_table(&sg, 1); + sg_set_page(&sg, page, size, 0); + return ion_heap_sglist_zero(&sg, 1, pgprot); +} + +void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer) +{ + spin_lock(&heap->free_lock); + list_add(&buffer->list, &heap->free_list); + heap->free_list_size += buffer->size; + spin_unlock(&heap->free_lock); + wake_up(&heap->waitqueue); +} + +size_t ion_heap_freelist_size(struct ion_heap *heap) +{ + size_t size; + + spin_lock(&heap->free_lock); + size = heap->free_list_size; + spin_unlock(&heap->free_lock); + + return size; +} + +static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size, + bool skip_pools) +{ + struct ion_buffer *buffer; + size_t total_drained = 0; + + if (ion_heap_freelist_size(heap) == 0) + return 0; + + spin_lock(&heap->free_lock); + if (size == 0) + size = heap->free_list_size; + + while (!list_empty(&heap->free_list)) { + if (total_drained >= size) + break; + buffer = list_first_entry(&heap->free_list, struct ion_buffer, + list); + list_del(&buffer->list); + heap->free_list_size -= buffer->size; + if (skip_pools) + buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE; + total_drained += buffer->size; + spin_unlock(&heap->free_lock); + ion_buffer_destroy(buffer); + spin_lock(&heap->free_lock); + } + spin_unlock(&heap->free_lock); + + return total_drained; +} + +size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) +{ + return _ion_heap_freelist_drain(heap, size, false); +} + +size_t ion_heap_freelist_shrink(struct ion_heap *heap, size_t size) +{ + return _ion_heap_freelist_drain(heap, size, true); +} + +static int ion_heap_deferred_free(void *data) +{ + struct ion_heap *heap = data; + + while (true) { + struct ion_buffer *buffer; + + wait_event_freezable(heap->waitqueue, + ion_heap_freelist_size(heap) > 0); + + spin_lock(&heap->free_lock); + if (list_empty(&heap->free_list)) { + spin_unlock(&heap->free_lock); + continue; + } + buffer = list_first_entry(&heap->free_list, struct ion_buffer, + list); + list_del(&buffer->list); + heap->free_list_size -= buffer->size; + spin_unlock(&heap->free_lock); + ion_buffer_destroy(buffer); + } + + return 0; +} + +int ion_heap_init_deferred_free(struct ion_heap *heap) +{ + struct sched_param param = { .sched_priority = 0 }; + + INIT_LIST_HEAD(&heap->free_list); + init_waitqueue_head(&heap->waitqueue); + heap->task = kthread_run(ion_heap_deferred_free, heap, + "%s", heap->name); + if (IS_ERR(heap->task)) { + pr_err("%s: creating thread for deferred free failed\n", + __func__); + return PTR_ERR_OR_ZERO(heap->task); + } + sched_setscheduler(heap->task, SCHED_IDLE, ¶m); + return 0; +} + +static unsigned long ion_heap_shrink_count(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct ion_heap *heap = container_of(shrinker, struct ion_heap, + shrinker); + int total = 0; + + total = ion_heap_freelist_size(heap) / PAGE_SIZE; + if (heap->ops->shrink) + total += heap->ops->shrink(heap, sc->gfp_mask, 0); + return total; +} + +static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct ion_heap *heap = container_of(shrinker, struct ion_heap, + shrinker); + int freed = 0; + int to_scan = sc->nr_to_scan; + + if (to_scan == 0) + return 0; + + /* + * shrink the free list first, no point in zeroing the memory if we're + * just going to reclaim it. Also, skip any possible page pooling. + */ + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) + freed = ion_heap_freelist_shrink(heap, to_scan * PAGE_SIZE) / + PAGE_SIZE; + + to_scan -= freed; + if (to_scan <= 0) + return freed; + + if (heap->ops->shrink) + freed += heap->ops->shrink(heap, sc->gfp_mask, to_scan); + return freed; +} + +void ion_heap_init_shrinker(struct ion_heap *heap) +{ + heap->shrinker.count_objects = ion_heap_shrink_count; + heap->shrinker.scan_objects = ion_heap_shrink_scan; + heap->shrinker.seeks = DEFAULT_SEEKS; + heap->shrinker.batch = 0; + register_shrinker(&heap->shrinker); +} diff --git a/drivers/soc/realtek/common/mem_allocator/ion_page_pool.c b/drivers/soc/realtek/common/mem_allocator/ion_page_pool.c new file mode 100644 index 000000000000..b5d8f71ba6b7 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion_page_pool.c @@ -0,0 +1,201 @@ +/* + * drivers/staging/android/ion/ion_mem_pool.c + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +/* + * We avoid atomic_long_t to minimize cache flushes at the cost of possible + * race which would result in a small accounting inaccuracy that we can + * tolerate. + */ +static long nr_total_pages; + +static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) +{ + struct page *page = alloc_pages(pool->gfp_mask, pool->order); + + if (!page) + return NULL; + return page; +} + +static void ion_page_pool_free_pages(struct ion_page_pool *pool, + struct page *page) +{ + __free_pages(page, pool->order); +} + +static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) +{ + mutex_lock(&pool->mutex); + if (PageHighMem(page)) { + list_add_tail(&page->lru, &pool->high_items); + pool->high_count++; + } else { + list_add_tail(&page->lru, &pool->low_items); + pool->low_count++; + } + + nr_total_pages += 1 << pool->order; + mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE, + 1 << pool->order); + mutex_unlock(&pool->mutex); + return 0; +} + +static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) +{ + struct page *page; + + if (high) { + BUG_ON(!pool->high_count); + page = list_first_entry(&pool->high_items, struct page, lru); + pool->high_count--; + } else { + BUG_ON(!pool->low_count); + page = list_first_entry(&pool->low_items, struct page, lru); + pool->low_count--; + } + + list_del(&page->lru); + nr_total_pages -= 1 << pool->order; + mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE, + -(1 << pool->order)); + return page; +} + +struct page *ion_page_pool_alloc(struct ion_page_pool *pool) +{ + struct page *page = NULL; + + BUG_ON(!pool); + + mutex_lock(&pool->mutex); + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + mutex_unlock(&pool->mutex); + + if (!page) + page = ion_page_pool_alloc_pages(pool); + + return page; +} + +void ion_page_pool_free(struct ion_page_pool *pool, struct page *page) +{ + int ret; + + BUG_ON(pool->order != compound_order(page)); + + ret = ion_page_pool_add(pool, page); + if (ret) + ion_page_pool_free_pages(pool, page); +} + +static int ion_page_pool_total(struct ion_page_pool *pool, bool high) +{ + int count = pool->low_count; + + if (high) + count += pool->high_count; + + return count << pool->order; +} + +long ion_page_pool_nr_pages(void) +{ + /* Correct possible overflow caused by racing writes */ + if (nr_total_pages < 0) + nr_total_pages = 0; + return nr_total_pages; +} + +int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, + int nr_to_scan) +{ + int freed = 0; + bool high; + + if (current_is_kswapd()) + high = true; + else + high = !!(gfp_mask & __GFP_HIGHMEM); + + if (nr_to_scan == 0) + return ion_page_pool_total(pool, high); + + while (freed < nr_to_scan) { + struct page *page; + + mutex_lock(&pool->mutex); + if (pool->low_count) { + page = ion_page_pool_remove(pool, false); + } else if (high && pool->high_count) { + page = ion_page_pool_remove(pool, true); + } else { + mutex_unlock(&pool->mutex); + break; + } + mutex_unlock(&pool->mutex); + ion_page_pool_free_pages(pool, page); + freed += (1 << pool->order); + } + + return freed; +} + +struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order, + bool cached) +{ + struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL); + + if (!pool) + return NULL; + pool->high_count = 0; + pool->low_count = 0; + INIT_LIST_HEAD(&pool->low_items); + INIT_LIST_HEAD(&pool->high_items); + pool->gfp_mask = gfp_mask | __GFP_COMP; + pool->order = order; + mutex_init(&pool->mutex); + plist_node_init(&pool->list, order); + if (cached) + pool->cached = true; + + return pool; +} + +void ion_page_pool_destroy(struct ion_page_pool *pool) +{ + kfree(pool); +} + +static int __init ion_page_pool_init(void) +{ + return 0; +} +device_initcall(ion_page_pool_init); diff --git a/drivers/soc/realtek/common/mem_allocator/ion_system_heap.c b/drivers/soc/realtek/common/mem_allocator/ion_system_heap.c new file mode 100644 index 000000000000..67c6b1489b54 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/ion_system_heap.c @@ -0,0 +1,455 @@ +/* + * drivers/staging/android/ion/ion_system_heap.c + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ion.h" + +#define NUM_ORDERS ARRAY_SIZE(orders) + +static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN | + __GFP_NORETRY) & ~__GFP_RECLAIM; +static gfp_t low_order_gfp_flags = GFP_HIGHUSER | __GFP_ZERO; +static const unsigned int orders[] = {8, 4, 0}; + +static int order_to_index(unsigned int order) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) + if (order == orders[i]) + return i; + BUG(); + return -1; +} + +static inline unsigned int order_to_size(int order) +{ + return PAGE_SIZE << order; +} + +struct ion_system_heap { + struct ion_heap heap; + struct ion_page_pool *uncached_pools[NUM_ORDERS]; + struct ion_page_pool *cached_pools[NUM_ORDERS]; +}; + +/** + * The page from page-pool are all zeroed before. We need do cache + * clean for cached buffer. The uncached buffer are always non-cached + * since it's allocated. So no need for non-cached pages. + */ +static struct page *alloc_buffer_page(struct ion_system_heap *heap, + struct ion_buffer *buffer, + unsigned long order) +{ + bool cached = ion_buffer_cached(buffer); + struct ion_page_pool *pool; + struct page *page; + + if (!cached) + pool = heap->uncached_pools[order_to_index(order)]; + else + pool = heap->cached_pools[order_to_index(order)]; + + page = ion_page_pool_alloc(pool); + + return page; +} + +static void free_buffer_page(struct ion_system_heap *heap, + struct ion_buffer *buffer, struct page *page) +{ + struct ion_page_pool *pool; + unsigned int order = compound_order(page); + bool cached = ion_buffer_cached(buffer); + + /* go to system */ + if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) { + __free_pages(page, order); + return; + } + + if (!cached) + pool = heap->uncached_pools[order_to_index(order)]; + else + pool = heap->cached_pools[order_to_index(order)]; + + ion_page_pool_free(pool, page); +} + +static struct page *alloc_largest_available(struct ion_system_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned int max_order) +{ + struct page *page; + int i; + + for (i = 0; i < NUM_ORDERS; i++) { + if (size < order_to_size(orders[i])) + continue; + if (max_order < orders[i]) + continue; + + page = alloc_buffer_page(heap, buffer, orders[i]); + if (!page) + continue; + + return page; + } + + return NULL; +} + +static int ion_system_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned long flags) +{ + struct ion_system_heap *sys_heap = container_of(heap, + struct ion_system_heap, + heap); + struct sg_table *table; + struct scatterlist *sg; + struct list_head pages; + struct page *page, *tmp_page; + int i = 0; + unsigned long size_remaining = PAGE_ALIGN(size); + unsigned int max_order = orders[0]; + + if (size / PAGE_SIZE > totalram_pages() / 2) + return -ENOMEM; + + INIT_LIST_HEAD(&pages); + while (size_remaining > 0) { + page = alloc_largest_available(sys_heap, buffer, size_remaining, + max_order); + if (!page) + goto free_pages; + list_add_tail(&page->lru, &pages); + size_remaining -= PAGE_SIZE << compound_order(page); + max_order = compound_order(page); + i++; + } + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + goto free_pages; + + if (sg_alloc_table(table, i, GFP_KERNEL)) + goto free_table; + + sg = table->sgl; + list_for_each_entry_safe(page, tmp_page, &pages, lru) { + sg_set_page(sg, page, PAGE_SIZE << compound_order(page), 0); + sg = sg_next(sg); + list_del(&page->lru); + } + + buffer->sg_table = table; + return 0; + +free_table: + kfree(table); +free_pages: + list_for_each_entry_safe(page, tmp_page, &pages, lru) + free_buffer_page(sys_heap, buffer, page); + return -ENOMEM; +} + +static void ion_system_heap_free(struct ion_buffer *buffer) +{ + struct ion_system_heap *sys_heap = container_of(buffer->heap, + struct ion_system_heap, + heap); + struct sg_table *table = buffer->sg_table; + struct scatterlist *sg; + int i; + + /* zero the buffer before goto page pool */ + if (!(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) + ion_heap_buffer_zero(buffer); + + for_each_sg(table->sgl, sg, table->nents, i) + free_buffer_page(sys_heap, buffer, sg_page(sg)); + sg_free_table(table); + kfree(table); +} + +static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, + int nr_to_scan) +{ + struct ion_page_pool *uncached_pool; + struct ion_page_pool *cached_pool; + struct ion_system_heap *sys_heap; + int nr_total = 0; + int i, nr_freed; + int only_scan = 0; + + sys_heap = container_of(heap, struct ion_system_heap, heap); + + if (!nr_to_scan) + only_scan = 1; + + for (i = 0; i < NUM_ORDERS; i++) { + uncached_pool = sys_heap->uncached_pools[i]; + cached_pool = sys_heap->cached_pools[i]; + + if (only_scan) { + nr_total += ion_page_pool_shrink(uncached_pool, + gfp_mask, + nr_to_scan); + + nr_total += ion_page_pool_shrink(cached_pool, + gfp_mask, + nr_to_scan); + } else { + nr_freed = ion_page_pool_shrink(uncached_pool, + gfp_mask, + nr_to_scan); + nr_to_scan -= nr_freed; + nr_total += nr_freed; + if (nr_to_scan <= 0) + break; + nr_freed = ion_page_pool_shrink(cached_pool, + gfp_mask, + nr_to_scan); + nr_to_scan -= nr_freed; + nr_total += nr_freed; + if (nr_to_scan <= 0) + break; + } + } + return nr_total; +} + +static struct ion_heap_ops system_heap_ops = { + .allocate = ion_system_heap_allocate, + .free = ion_system_heap_free, + .map_kernel = ion_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, + .map_user = ion_heap_map_user, + .shrink = ion_system_heap_shrink, +}; + +static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, + void *unused) +{ + struct ion_system_heap *sys_heap = container_of(heap, + struct ion_system_heap, + heap); + int i; + struct ion_page_pool *pool; + + for (i = 0; i < NUM_ORDERS; i++) { + pool = sys_heap->uncached_pools[i]; + + seq_printf(s, "%d order %u highmem pages uncached %lu total\n", + pool->high_count, pool->order, + (PAGE_SIZE << pool->order) * pool->high_count); + seq_printf(s, "%d order %u lowmem pages uncached %lu total\n", + pool->low_count, pool->order, + (PAGE_SIZE << pool->order) * pool->low_count); + } + + for (i = 0; i < NUM_ORDERS; i++) { + pool = sys_heap->cached_pools[i]; + + seq_printf(s, "%d order %u highmem pages cached %lu total\n", + pool->high_count, pool->order, + (PAGE_SIZE << pool->order) * pool->high_count); + seq_printf(s, "%d order %u lowmem pages cached %lu total\n", + pool->low_count, pool->order, + (PAGE_SIZE << pool->order) * pool->low_count); + } + return 0; +} + +static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) + if (pools[i]) + ion_page_pool_destroy(pools[i]); +} + +static int ion_system_heap_create_pools(struct ion_page_pool **pools, + bool cached) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) { + struct ion_page_pool *pool; + gfp_t gfp_flags = low_order_gfp_flags; + + if (orders[i] > 4) + gfp_flags = high_order_gfp_flags; + + pool = ion_page_pool_create(gfp_flags, orders[i], cached); + if (!pool) + goto err_create_pool; + pools[i] = pool; + } + return 0; + +err_create_pool: + ion_system_heap_destroy_pools(pools); + return -ENOMEM; +} + +static struct ion_heap *__ion_system_heap_create(void) +{ + struct ion_system_heap *heap; + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); + heap->heap.ops = &system_heap_ops; + heap->heap.type = ION_HEAP_TYPE_SYSTEM; + heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; + + if (ion_system_heap_create_pools(heap->uncached_pools, false)) + goto free_heap; + + if (ion_system_heap_create_pools(heap->cached_pools, true)) + goto destroy_uncached_pools; + + heap->heap.debug_show = ion_system_heap_debug_show; + return &heap->heap; + +destroy_uncached_pools: + ion_system_heap_destroy_pools(heap->uncached_pools); + +free_heap: + kfree(heap); + return ERR_PTR(-ENOMEM); +} + +static int ion_system_heap_create(void) +{ + struct ion_heap *heap; + + heap = __ion_system_heap_create(); + if (IS_ERR(heap)) + return PTR_ERR(heap); + heap->name = "ion_system_heap"; + + ion_device_add_heap(heap); + return 0; +} +device_initcall(ion_system_heap_create); + +static int ion_system_contig_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long len, + unsigned long flags) +{ + int order = get_order(len); + struct page *page; + struct sg_table *table; + unsigned long i; + int ret; + + page = alloc_pages(low_order_gfp_flags | __GFP_NOWARN, order); + if (!page) + return -ENOMEM; + + split_page(page, order); + + len = PAGE_ALIGN(len); + for (i = len >> PAGE_SHIFT; i < (1 << order); i++) + __free_page(page + i); + + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) { + ret = -ENOMEM; + goto free_pages; + } + + ret = sg_alloc_table(table, 1, GFP_KERNEL); + if (ret) + goto free_table; + + sg_set_page(table->sgl, page, len, 0); + + buffer->sg_table = table; + + return 0; + +free_table: + kfree(table); +free_pages: + for (i = 0; i < len >> PAGE_SHIFT; i++) + __free_page(page + i); + + return ret; +} + +static void ion_system_contig_heap_free(struct ion_buffer *buffer) +{ + struct sg_table *table = buffer->sg_table; + struct page *page = sg_page(table->sgl); + unsigned long pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; + unsigned long i; + + for (i = 0; i < pages; i++) + __free_page(page + i); + sg_free_table(table); + kfree(table); +} + +static struct ion_heap_ops kmalloc_ops = { + .allocate = ion_system_contig_heap_allocate, + .free = ion_system_contig_heap_free, + .map_kernel = ion_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, + .map_user = ion_heap_map_user, +}; + +static struct ion_heap *__ion_system_contig_heap_create(void) +{ + struct ion_heap *heap; + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); + heap->ops = &kmalloc_ops; + heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; + heap->name = "ion_system_contig_heap"; + return heap; +} + +static int ion_system_contig_heap_create(void) +{ + struct ion_heap *heap; + + heap = __ion_system_contig_heap_create(); + if (IS_ERR(heap)) + return PTR_ERR(heap); + + ion_device_add_heap(heap); + return 0; +} +device_initcall(ion_system_contig_heap_create); + diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/Kconfig b/drivers/soc/realtek/common/mem_allocator/rtk/Kconfig new file mode 100644 index 000000000000..bf0afa29dd5f --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/Kconfig @@ -0,0 +1,12 @@ +config ION_RTK_DHC_HEAP + bool "Ion heap for Realtek DHC platform" + depends on ION_REALTEK + help + Choose this option if you wish to use customize ION heap for Realtek DHC platform. + +config ION_RTK_LEGACY_DEVICE + bool "Legacy ion device to match old usage" + default n + depends on ION_RTK_DHC_HEAP + help + Choose this option if you wish to use legacy device /dev/ion_legacy . diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/Makefile b/drivers/soc/realtek/common/mem_allocator/rtk/Makefile new file mode 100644 index 000000000000..988b1c781af0 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/Makefile @@ -0,0 +1,16 @@ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator +ccflags-y += -I$(srctree)/mm + +obj-$(CONFIG_ION_RTK_DHC_HEAP) += rtk_ion.o +rtk_ion-objs := src/pool_common.o +rtk_ion-objs += src/pool_gen.o +rtk_ion-objs += src/pool_cma.o +rtk_ion-objs += src/carveout_heap.o +rtk_ion-objs += src/dev.o +rtk_ion-objs += src/ioctl.o +rtk_ion-objs += src/protected.o +obj-$(CONFIG_DEBUG_FS) += src/debugfs.o + +obj-$(CONFIG_ION_RTK_LEGACY_DEVICE) += src/dev_legacy.o + +obj-$(CONFIG_ION_RTK_DHC_HEAP) += test/ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_alloc.h b/drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_alloc.h new file mode 100644 index 000000000000..f64f43c9a875 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_alloc.h @@ -0,0 +1,11 @@ +#ifndef _LINUX_ION_RTK_ALLOC_H +#define _LINUX_ION_RTK_ALLOC_H + +#include +#include + +int ext_rtk_ion_alloc(size_t len, unsigned int heap_type_mask, + unsigned int flags); +int ext_rtk_ion_close_fd(struct files_struct *files, unsigned fd); + +#endif /* _LINUX_ION_RTK_ALLOC_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_protected_notifier.h b/drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_protected_notifier.h new file mode 100644 index 000000000000..faa667c8853f --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/inc/ion_rtk_protected_notifier.h @@ -0,0 +1,85 @@ +#ifndef _LINUX_ION_RTK_PROTECTED_NOTIFIER_H +#define _LINUX_ION_RTK_PROTECTED_NOTIFIER_H + +#include +#include + +enum E_ION_NOTIFIER_PROTECTED_TYPE { + ION_NOTIFIER_PROTECTED_TYPE_NONE = 0, + ION_NOTIFIER_PROTECTED_TYPE_1, + ION_NOTIFIER_PROTECTED_TYPE_2, + ION_NOTIFIER_PROTECTED_TYPE_3, + ION_NOTIFIER_PROTECTED_TYPE_4, + ION_NOTIFIER_PROTECTED_TYPE_5, + ION_NOTIFIER_PROTECTED_TYPE_6, + ION_NOTIFIER_PROTECTED_TYPE_7, + ION_NOTIFIER_PROTECTED_TYPE_8, + ION_NOTIFIER_PROTECTED_TYPE_9, + ION_NOTIFIER_PROTECTED_TYPE_10, + ION_NOTIFIER_PROTECTED_TYPE_11, + ION_NOTIFIER_PROTECTED_TYPE_12, + ION_NOTIFIER_PROTECTED_TYPE_13, + ION_NOTIFIER_PROTECTED_TYPE_14, + ION_NOTIFIER_PROTECTED_TYPE_15, + ION_NOTIFIER_PROTECTED_TYPE_MAX, +}; + +enum E_ION_NOTIFIER_PROTECTED_EXT { + ION_NOTIFIER_PROTECTED_EXT_NONE = 0, + ION_NOTIFIER_PROTECTED_EXT_1, + ION_NOTIFIER_PROTECTED_EXT_2, + ION_NOTIFIER_PROTECTED_EXT_3, + ION_NOTIFIER_PROTECTED_EXT_4, + ION_NOTIFIER_PROTECTED_EXT_5, + ION_NOTIFIER_PROTECTED_EXT_6, + ION_NOTIFIER_PROTECTED_EXT_7, + ION_NOTIFIER_PROTECTED_EXT_MAX, +}; + +struct protected_region { + enum E_ION_NOTIFIER_PROTECTED_TYPE type; + unsigned long base; + size_t size; +}; + +struct protected_ext_region { + enum E_ION_NOTIFIER_PROTECTED_EXT ext; + unsigned long base; + size_t size; + void *parent_priv; +}; + +struct ion_rtk_protected_create_info { + struct protected_region mem; // info to TEE + void *priv_virt; // write by TEE +}; + +struct ion_rtk_protected_change_info { + struct protected_region mem; + void *priv_virt; +}; + +struct ion_rtk_protected_destroy_info { + void *priv_virt; +}; + +struct ion_rtk_protected_ext_set { + struct protected_ext_region mem; + void *priv_virt; +}; + +struct ion_rtk_protected_ext_unset { + void *priv_virt; +}; + +enum ion_rtk_protected_notify_cmd { + PROTECTED_REGION_CREATE, + PROTECTED_REGION_CHANGE, + PROTECTED_REGION_DESTROY, + PROTECTED_REGION_EXTENSION_SET, + PROTECTED_REGION_EXTENSION_UNSET, +}; + +int ion_rtk_protected_notifier_register(struct notifier_block *nb); +void ion_rtk_protected_notifier_unregister(struct notifier_block *nb); +#endif /* _LINUX_ION_RTK_PROTECTED_NOTIFIER_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.c new file mode 100644 index 000000000000..c80caff0bac6 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.c @@ -0,0 +1,1052 @@ +/* ion_rtk_carveout_heap.c + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "carveout_heap.h" +#include "pool.h" + +struct prealloc_pool { + struct ion_buffer buffer; + struct pool_info * pool; + struct list_head list; +}; + +struct ion_rtk_carveout_heap { + struct ion_heap heap; + unsigned long version; + struct ion_rtk_carveout_ops *priv_ops; + struct mutex lock; + struct list_head pools; + struct list_head prealloc_pools; + struct list_head ion_flag_replace; + struct seq_buf trace_seq_buf; + char *trace_message; +}; + +struct pool_score_slot { + struct pool_info *pool_info; + int score; +}; +unsigned int retry_count_value = 50; +unsigned int retry_delay_value = 300; + +static size_t heap_pool_count(struct ion_rtk_carveout_heap *rtk_carveout_heap); +static int pool_score_cmp(const void *r, const void *c); +static int pool_score(struct pool_info *pool_info, + unsigned long size, unsigned long flags); + +static unsigned int ion_rtk_carveout_get_version(struct ion_heap *heap); +static int ion_rtk_carveout_get_meminfo(struct ion_heap *heap, + unsigned int flags, + struct ion_rtk_carveout_meminfo *info); +static int ion_rtk_carveout_trace_dump(struct ion_heap *heap, + struct seq_file *s); + +static struct ion_rtk_carveout_ops rtk_carveout_heap_priv_ops = { + .getVersion = ion_rtk_carveout_get_version, + .getMemInfo = ion_rtk_carveout_get_meminfo, + .traceDump = ion_rtk_carveout_trace_dump, +}; + +struct ion_rtk_carveout_ops *get_rtk_carveout_ops(struct ion_heap *heap); + +static int ion_carveout_heap_dump(struct ion_rtk_carveout_heap + *rtk_carveout_heap, struct seq_buf *s, + void *prefix); +static int ion_carveout_heap_debug_show(struct ion_heap *heap, + struct seq_file *s, void *unused); +static int ion_rtk_carveout_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned long flags); +static void ion_rtk_carveout_heap_free(struct ion_buffer *buffer); +static int ion_rtk_heap_map_user(struct ion_heap *heap, + struct ion_buffer *buffer, + struct vm_area_struct *vma); +static void *ion_rtk_heap_map_kernel(struct ion_heap *heap, + struct ion_buffer *buffer); +static struct ion_heap_ops rtk_carveout_heap_ops = { + .allocate = ion_rtk_carveout_heap_allocate, + .free = ion_rtk_carveout_heap_free, + .map_user = ion_rtk_heap_map_user, + .map_kernel = ion_rtk_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, +}; + +struct ion_heap *ion_rtk_carveout_heap_create(struct device *dev, + struct ion_platform_heap *heap_data); +void ion_rtk_carveout_heap_destroy(struct ion_heap *heap); + +/* + * + */ +#ifdef CONFIG_VIRTUAL_PMU + +extern int rtk_vpmu_api_add_to_available(unsigned long addr); +extern int rtk_vpmu_api_is_enable(int vpmu_reg_idx); +extern void rtk_vpmu_api_update_count(unsigned long long count, int vpmu_reg_idx); + +static int vpmu_reg_idx_media_gen; +static int vpmu_reg_idx_media_cma; +static int vpmu_reg_idx_audio_gen; +static int vpmu_reg_idx_audio_cma; + +extern unsigned long long ion_gen_pool_get_size(struct pool_info *pool_info); +extern unsigned long long ion_cma_pool_get_size(struct pool_info *pool_info); +/* + * + */ +unsigned long long +ion_get_heap_size_info(struct ion_heap *heap, enum pool_type type) +{ + char symname[KSYM_NAME_LEN]; + unsigned long long allocSize; + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + + allocSize = 0; + //printk(KERN_ERR "\033[1;33m" "| %s %d: pool type %d" "\033[m\n", __FUNCTION__, __LINE__, type); + + mutex_lock(&rtk_carveout_heap->lock); + + do { + struct pool_info *pool_info = NULL; + + list_for_each_entry(pool_info, &rtk_carveout_heap->pools, list) { + if (!pool_info) { + continue; + } + //pool_info->debug_show(pool_info, s, prefix); + //ion_gen_pool_debug_show ==> ion_gen_pool_get_size + //ion_cma_pool_debug_show ==> ion_cma_pool_get_size + if( pool_info->type == type && + type == GEN_POOL ) { + //printk(KERN_ERR "\033[1;33m" "| %s %d: pool_info->type %d, pool type %d, get GEN pool used size" "\033[m\n", + // __FUNCTION__, __LINE__, pool_info->type, type); + allocSize += ion_gen_pool_get_size(pool_info); + } + else if( pool_info->type == type && + type == CMA_POOL ) { + //printk(KERN_ERR "\033[1;33m" "| %s %d: pool_info->type %d, pool type %d, get CMA pool used size" "\033[m\n", + // __FUNCTION__, __LINE__, pool_info->type, type); + allocSize += ion_cma_pool_get_size(pool_info); + } + + //if( lookup_symbol_name(pool_info->debug_show,symname) == 0 ) + // printk(KERN_ERR "\033[1;33m" "| %s %d: %p [%s]" "\033[m\n", __FUNCTION__, __LINE__, pool_info->debug_show, symname); + //else + // printk(KERN_ERR "\033[1;33m" "| %s %d: %p" "\033[m\n", __FUNCTION__, __LINE__, pool_info->debug_show); + //allocSize += 1000000; + } + } + while (0); + + mutex_unlock(&rtk_carveout_heap->lock); + + return allocSize; +} + +void ion_update_media_heap_size_info_in_gen(struct ion_heap *heap, int vpmu_reg_idx) +{ + //struct ion_rtk_carveout_heap *rtk_carveout_heap = + // container_of(heap, struct ion_rtk_carveout_heap, heap); + //struct ION_RTK_CARVEOUT_PAGE_INFO * page_info; + //struct ION_RTK_CARVEOUT_POOL_INFO * phandler; + //unsigned long offset; + unsigned long long allocSize; + + if (heap && + (int)heap->type == 7 /* (int)RTK_PHOENIX_ION_HEAP_TYPE_MEDIA */) { + allocSize = ion_get_heap_size_info(heap, GEN_POOL); + rtk_vpmu_api_update_count(allocSize, vpmu_reg_idx); + } +} + +void ion_update_media_heap_size_info_in_cma(struct ion_heap *heap, int vpmu_reg_idx) +{ + //struct ion_rtk_carveout_heap *rtk_carveout_heap = + // container_of(heap, struct ion_rtk_carveout_heap, heap); + //struct ION_RTK_CARVEOUT_PAGE_INFO * page_info; + //struct ION_RTK_CARVEOUT_POOL_INFO * phandler; + //unsigned long offset; + unsigned long long allocSize; + + if (heap && + (int)heap->type == 7 /* (int)RTK_PHOENIX_ION_HEAP_TYPE_MEDIA */) { + allocSize = ion_get_heap_size_info(heap, CMA_POOL); + rtk_vpmu_api_update_count(allocSize, vpmu_reg_idx); + } +} + +void ion_update_audio_heap_size_info_in_gen(struct ion_heap *heap, int vpmu_reg_idx) +{ + //struct ion_rtk_carveout_heap *rtk_carveout_heap = + // container_of(heap, struct ion_rtk_carveout_heap, heap); + //struct ION_RTK_CARVEOUT_PAGE_INFO * page_info; + //struct ION_RTK_CARVEOUT_POOL_INFO * phandler; + //unsigned long offset; + unsigned long long allocSize; + + if (heap && + (int)heap->type == 8 /* (int)RTK_PHOENIX_ION_HEAP_TYPE_AUDIO */) { + allocSize = ion_get_heap_size_info(heap, GEN_POOL); + rtk_vpmu_api_update_count(allocSize, vpmu_reg_idx); + } +} + +void ion_update_audio_heap_size_info_in_cma(struct ion_heap *heap, int vpmu_reg_idx) +{ + //struct ion_rtk_carveout_heap *rtk_carveout_heap = + // container_of(heap, struct ion_rtk_carveout_heap, heap); + //struct ION_RTK_CARVEOUT_PAGE_INFO * page_info; + //struct ION_RTK_CARVEOUT_POOL_INFO * phandler; + //unsigned long offset; + unsigned long long allocSize; + + if (heap && + (int)heap->type == 8 /* (int)RTK_PHOENIX_ION_HEAP_TYPE_AUDIO */) { + + allocSize = ion_get_heap_size_info(heap, CMA_POOL); + + rtk_vpmu_api_update_count(allocSize, vpmu_reg_idx); + } +} + +void ion_update_heap_size_info(struct ion_heap *heap) +{ + // only update if function is added to /proc/rtk_vpmu/filter + if( rtk_vpmu_api_is_enable(vpmu_reg_idx_media_gen) ) + { + ion_update_media_heap_size_info_in_gen(heap,vpmu_reg_idx_media_gen); + } + if( rtk_vpmu_api_is_enable(vpmu_reg_idx_media_cma) ) + { + ion_update_media_heap_size_info_in_cma(heap,vpmu_reg_idx_media_cma); + } + if( rtk_vpmu_api_is_enable(vpmu_reg_idx_audio_gen) ) + { + ion_update_audio_heap_size_info_in_gen(heap,vpmu_reg_idx_audio_gen); + } + if( rtk_vpmu_api_is_enable(vpmu_reg_idx_audio_cma) ) + { + ion_update_audio_heap_size_info_in_cma(heap,vpmu_reg_idx_audio_cma); + } +} +#endif // end of CONFIG_VIRTUAL_PMU + +static size_t print_time(u64 ts, char *buf) +{ + unsigned long rem_nsec; + rem_nsec = do_div(ts, 1000000000); + if (!buf) + return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); + + return sprintf(buf, "[%5lu.%06lu] ", + (unsigned long)ts, rem_nsec / 1000); +} + +#ifdef CONFIG_DEBUG_FS +static int debugfs_retry_count_show(struct seq_file *s, void *unused) +{ + seq_printf(s, "%d\n", retry_count_value); + return 0; +} +static int debugfs_retry_delay_show(struct seq_file *s, void *unused) +{ + seq_printf(s, "%d\n", retry_delay_value); + return 0; +} + +static int debugfs_retry_count_open(struct inode *inode, struct file *file) +{ + return single_open(file, debugfs_retry_count_show, inode->i_private); +} + +static int debugfs_retry_delay_open(struct inode *inode, struct file *file) +{ + return single_open(file, debugfs_retry_delay_show, inode->i_private); +} + +static ssize_t debugfs_retry_count_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char retry_buf[10]= {0}; + int ret = 0; + + if (*ppos > 10) + return -EINVAL; + if (copy_from_user(retry_buf, userbuf, min(count, sizeof(retry_buf)))) + return -EFAULT; + ret = kstrtouint(retry_buf, 10, &retry_count_value); + return count; +} + +static ssize_t debugfs_retry_delay_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char retry_buf[10] = {0}; + int ret = 0; + + if (*ppos > 10) + return -EINVAL; + if (copy_from_user(retry_buf, userbuf, min(count, sizeof(retry_buf)))) + return -EFAULT; + ret = kstrtouint(retry_buf, 10, &retry_delay_value); + return count; +} + + +static const struct file_operations debug_retry_delay_fops = { + .open = debugfs_retry_delay_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debugfs_retry_delay_write, +}; + + +static const struct file_operations debug_retry_count_fops = { + .open = debugfs_retry_count_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debugfs_retry_count_write, +}; +#endif +static int pool_score_cmp(const void *r, const void *c) +{ + struct pool_score_slot *slot_r = (struct pool_score_slot *)r; + struct pool_score_slot *slot_c = (struct pool_score_slot *)c; + return slot_c->score - slot_r->score; +} + +static int pool_score(struct pool_info *pool_info, + unsigned long size, unsigned long flags) +{ + const int step = 100; + const int half_step = step / 2; + int score = -1; + do { + size_t space; + + if (ion_flag_mismatch_pool_condition + (flags, pool_info->rtk_flags)) + break; + + space = pool_info->getSpace(pool_info, flags); + + if (space < size || space <= 0) + break; + + score = + (sizeof(flags) * 8 * step) + half_step /* propected */ + + half_step /* cma */ + 1; + + if (rtk_flag_is_protected(pool_info->rtk_flags)) + score -= half_step; + + score -= + hweight_long((pool_info->rtk_flags & + ~(RTK_FLAG_PROTECTED_MASK | RTK_FLAG_PROTECTED_EXT_MASK))) * step; + + if (pool_info->type == CMA_POOL) + score -= half_step; + + if (pool_info->type == PREALLOC_POOL) + score += half_step; + + break; + } while (0); + return score; +} + +static struct pool_info * ion_rtk_carveout_heap_find_pool_info(struct ion_rtk_carveout_heap *rtk_carveout_heap, unsigned long base) +{ + struct pool_info * ret = NULL; + struct pool_info * pool_info; + list_for_each_entry(pool_info, &rtk_carveout_heap->pools, list) { + if (pool_info && base >= pool_info->base && base < (pool_info->base + pool_info->size)) { + ret = pool_info; + break; + } + } + return ret; +} + +struct ion_heap *ion_rtk_carveout_heap_create(struct device *dev, + struct ion_platform_heap *heap_data) +{ + struct ion_rtk_carveout_heap *rtk_carveout_heap; + struct ion_rtk_heap_create_priv * priv_data = (struct ion_rtk_heap_create_priv *)heap_data->priv; + struct list_head *pool_list = &priv_data->pools; + struct ion_rtk_priv_pool *pool; + struct dentry __maybe_unused *debug_root; + + if (!pool_list) { + pr_err("[%s] pool_list is NULL!!!!\n", __func__); + return ERR_PTR(-ENOMEM); + } + + rtk_carveout_heap = + kzalloc(sizeof(struct ion_rtk_carveout_heap), GFP_KERNEL); + + if (!rtk_carveout_heap) + return ERR_PTR(-ENOMEM); + + { + const size_t seq_buf_size = PAGE_SIZE * 10; + rtk_carveout_heap->trace_message = + kzalloc(seq_buf_size, GFP_KERNEL); + if (!rtk_carveout_heap->trace_message) { + kfree(rtk_carveout_heap); + return ERR_PTR(-ENOMEM); + } + seq_buf_init(&rtk_carveout_heap->trace_seq_buf, + rtk_carveout_heap->trace_message, seq_buf_size); + } + + mutex_init(&rtk_carveout_heap->lock); + INIT_LIST_HEAD(&rtk_carveout_heap->pools); + INIT_LIST_HEAD(&rtk_carveout_heap->prealloc_pools); + INIT_LIST_HEAD(&rtk_carveout_heap->ion_flag_replace); + + list_for_each_entry(pool, pool_list, list) { + struct pool_info *sub_pool = NULL; + if (pool->type == RTK_CARVEOUT_GEN_POOL_TYPE) { + sub_pool = + ion_gen_pool_create(GEN_POOL, + pool->base, + pool->size, + pool->flags, + pool->from_reserved_memory, + dev); + } else if (pool->type == RTK_CARVEOUT_CMA_POOL_TYPE) { + sub_pool = + ion_cma_pool_create(pool->cma_pool, pool->flags); + } + if (sub_pool) + list_add(&sub_pool->list, &rtk_carveout_heap->pools); + } + + { + struct ion_flag_replace *rtk_replace, *tmp_rtk_replace; + list_for_each_entry_safe(rtk_replace, tmp_rtk_replace, + &priv_data->rtk_flag_replace, list) { + if (rtk_replace) { + do { + struct ion_flag_replace * ion_replace = kzalloc(sizeof(struct ion_flag_replace), GFP_KERNEL); + if (!ion_replace) + break; + INIT_LIST_HEAD(&ion_replace->list); + ion_replace->condition = ion_flag_mapping_from_rtk(rtk_replace->condition); + ion_replace->replace = ion_flag_mapping_from_rtk(rtk_replace->replace); + list_add_tail(&ion_replace->list, &rtk_carveout_heap->ion_flag_replace); + } while(0); + } + } + } + + rtk_carveout_heap->heap.ops = &rtk_carveout_heap_ops; + rtk_carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT; + rtk_carveout_heap->heap.flags = 0; + rtk_carveout_heap->heap.debug_show = ion_carveout_heap_debug_show; + rtk_carveout_heap->priv_ops = &rtk_carveout_heap_priv_ops; + rtk_carveout_heap->version = sizeof(*rtk_carveout_heap); +#ifdef CONFIG_DEBUG_FS + debug_root = debugfs_create_dir("ion_retry", NULL); + debugfs_create_file("retry_count", 0644, debug_root, pool, &debug_retry_count_fops); + debugfs_create_file("retry_delay", 0644, debug_root, pool, &debug_retry_delay_fops); +#endif + + { + struct ion_rtk_pre_alloc * pre_alloc, *tmp_pre_alloc; + list_for_each_entry_safe(pre_alloc, tmp_pre_alloc, + &priv_data->pre_alloc, list) { + if (pre_alloc) { + do { + unsigned long rtk_flags = pre_alloc->rtk_flags; + struct prealloc_pool * prealloc_pool = (struct prealloc_pool *) kzalloc(sizeof(struct prealloc_pool), GFP_KERNEL); + struct pool_info * parent; + struct pool_info * pool; + struct page_info *page_info = NULL; + struct ion_buffer *buffer = NULL; + if (!prealloc_pool) + break; + INIT_LIST_HEAD(&prealloc_pool->list); + buffer = &prealloc_pool->buffer; + buffer->heap = &rtk_carveout_heap->heap; + buffer->flags = ion_flag_mapping_from_rtk(rtk_flags); + if (ion_rtk_carveout_heap_allocate(buffer->heap, buffer, + pre_alloc->size, + buffer->flags) != 0) { + kfree(prealloc_pool); + break; + } + buffer->size = pre_alloc->size; + page_info = (struct page_info *)buffer->priv_virt; + parent = ion_rtk_carveout_heap_find_pool_info(rtk_carveout_heap, page_info->base); + if (!parent) { + ion_rtk_carveout_heap_free(buffer); + kfree(prealloc_pool); + break; + + } + rtk_flags |= parent->rtk_flags & ~RTK_FLAG_PROTECTED_DYNAMIC; + if (!ion_flag_is_protected(buffer->flags)) { + rtk_flags &= ~(RTK_FLAG_PROTECTED_MASK | RTK_FLAG_PROTECTED_EXT_MASK); + } + pool = ion_gen_pool_create(PREALLOC_POOL, page_info->base, page_info->size, + rtk_flags, false /*from_reserved_memory*/, dev); + if (!pool) { + ion_rtk_carveout_heap_free(buffer); + kfree(prealloc_pool); + break; + } + list_add(&pool->list, &rtk_carveout_heap->pools); + prealloc_pool->pool = pool; + + list_add(&prealloc_pool->list, &rtk_carveout_heap->prealloc_pools); + } while(0); + } + } + } +#ifdef CONFIG_VIRTUAL_PMU + printk(KERN_ERR "\033[1;33m" "%s %d: name %s, type %d, id %d" "\033[m\n", + __FUNCTION__, __LINE__, heap_data->name, heap_data->type, heap_data->id); + if( (int)heap_data->type == 7 /* (int)RTK_PHOENIX_ION_HEAP_TYPE_MEDIA */) { + vpmu_reg_idx_media_gen = rtk_vpmu_api_add_to_available( + (unsigned long)ion_update_media_heap_size_info_in_gen); + printk(KERN_ERR "\033[1;33m" "%s %d: vpmu_reg_idx_media_gen 0x%08x" "\033[m\n", + __FUNCTION__, __LINE__, vpmu_reg_idx_media_gen); + + vpmu_reg_idx_media_cma = rtk_vpmu_api_add_to_available( + (unsigned long)ion_update_media_heap_size_info_in_cma); + printk(KERN_ERR "\033[1;33m" "%s %d: vpmu_reg_idx_media_cma 0x%08x" "\033[m\n", + __FUNCTION__, __LINE__, vpmu_reg_idx_media_cma); + } + + if( (int)heap_data->type == 8 /* (int)RTK_PHOENIX_ION_HEAP_TYPE_AUDIO */) { + vpmu_reg_idx_audio_gen = rtk_vpmu_api_add_to_available( + (unsigned long)ion_update_audio_heap_size_info_in_gen); + printk(KERN_ERR "\033[1;33m" "%s %d: vpmu_reg_idx_audio_gen 0x%08x" "\033[m\n", + __FUNCTION__, __LINE__, vpmu_reg_idx_audio_gen); + + vpmu_reg_idx_audio_cma = rtk_vpmu_api_add_to_available( + (unsigned long)ion_update_audio_heap_size_info_in_cma); + printk(KERN_ERR "\033[1;33m" "%s %d: vpmu_reg_idx_audio_cma 0x%08x" "\033[m\n", + __FUNCTION__, __LINE__, vpmu_reg_idx_audio_cma); + } +#endif + return &rtk_carveout_heap->heap; +} + +void ion_rtk_carveout_heap_destroy(struct ion_heap *heap) +{ + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + struct pool_info *pool_info, *tmp_pool_info; + struct prealloc_pool *prealloc_pool, *tmp_prealloc_pool; + struct ion_flag_replace * ion_replace, *tmp_ion_replace; + + mutex_lock(&rtk_carveout_heap->lock); + list_for_each_entry_safe(ion_replace, tmp_ion_replace, + &rtk_carveout_heap->ion_flag_replace, list) { + if (ion_replace) { + list_del(&ion_replace->list); + kfree(ion_replace); + } + } + list_for_each_entry_safe(prealloc_pool, tmp_prealloc_pool, + &rtk_carveout_heap->prealloc_pools, list) { + if (prealloc_pool) { + pool_info = prealloc_pool->pool; + list_del(&prealloc_pool->list); + ion_rtk_carveout_heap_free(&prealloc_pool->buffer); + list_del(&pool_info->list); + pool_info->destroy(pool_info); + kfree(prealloc_pool); + } + } + list_for_each_entry_safe(pool_info, tmp_pool_info, + &rtk_carveout_heap->pools, list) { + if (pool_info) { + list_del(&pool_info->list); + pool_info->destroy(pool_info); + } + } + mutex_unlock(&rtk_carveout_heap->lock); + kfree(rtk_carveout_heap->trace_message); + kfree(rtk_carveout_heap); +} + +static unsigned int ion_rtk_carveout_get_version(struct ion_heap *heap) +{ + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + + if (rtk_carveout_heap->version != sizeof(struct ion_rtk_carveout_heap)) + goto err; + + return (unsigned int)rtk_carveout_heap->version & -1U; + +err: + return 0; +} + +static size_t heap_pool_count(struct ion_rtk_carveout_heap *rtk_carveout_heap) +{ + size_t ret = 0; + struct pool_info *pool_info = NULL; + list_for_each_entry(pool_info, &rtk_carveout_heap->pools, list) { + if (pool_info) + ret++; + } + return ret; +} + +static int ion_rtk_carveout_get_meminfo(struct ion_heap *heap, + unsigned int flags, + struct ion_rtk_carveout_meminfo *info) +{ + int ret = -1; + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + mutex_lock(&rtk_carveout_heap->lock); + do { + struct pool_info *pool_info = NULL; + unsigned long usedSize = 0, freeSize = 0; + + if (!info) + break; + + list_for_each_entry(pool_info, &rtk_carveout_heap->pools, list) { + size_t sUsed, sSpace; + if (!pool_info) + continue; + sUsed = pool_info->getUsage(pool_info, flags); + sSpace = pool_info->getSpace(pool_info, flags); + usedSize += sUsed; + freeSize += sSpace - sUsed; + } + info->usedSize = usedSize; + info->freeSize = freeSize; + ret = 0; + } + while (0); + mutex_unlock(&rtk_carveout_heap->lock); + return ret; +} + +static int ion_rtk_carveout_trace_dump(struct ion_heap *heap, + struct seq_file *s) +{ + int ret = -ENOMEM; + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + mutex_lock(&rtk_carveout_heap->lock); + ret = seq_buf_print_seq(s, &rtk_carveout_heap->trace_seq_buf); + mutex_unlock(&rtk_carveout_heap->lock); + return ret; + +} + +struct ion_rtk_carveout_ops *get_rtk_carveout_ops(struct ion_heap *heap) +{ + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + + if (rtk_carveout_heap->version != sizeof(struct ion_rtk_carveout_heap)) + return NULL; + + return rtk_carveout_heap->priv_ops; +} + +static void carveout_heap_allocate_fail_trace(struct ion_rtk_carveout_heap *rtk_carveout_heap, + unsigned long size, + unsigned long flags) +{ + struct task_struct *task; + pid_t pid, tgid; + char task_comm[TASK_COMM_LEN]; + struct seq_buf *s = &rtk_carveout_heap->trace_seq_buf; + char prefix [100]; + print_time(local_clock(), &prefix[0]); + + get_task_struct(current->group_leader); + { + task_lock(current->group_leader); + pid = task_pid_nr(current->group_leader); + tgid = task_tgid_nr(current->group_leader); + if (current->group_leader->flags & PF_KTHREAD) + task = NULL; + else + task = current->group_leader; + task_unlock(current->group_leader); + + if (task) + get_task_comm(task_comm, task); + else + strncpy(task_comm, "KTHREAD", sizeof(task_comm)); + } + put_task_struct(current->group_leader); + + seq_buf_clear(s); + + seq_buf_printf(s, "%s(%s PID:%d TID:%d) Alloc failed! size:%lu flags:0x%08lx ", + &prefix[0], task_comm, pid, tgid, size, flags); + + seq_buf_printf(s, "("); + seq_buf_printf_ion_flags(s, flags); + seq_buf_printf(s, ")\n"); + + ion_carveout_heap_dump(rtk_carveout_heap, s, &prefix[0]); +} + +static void ion_rtk_carveout_heap_flags_preprocess(struct ion_rtk_carveout_heap *rtk_carveout_heap, unsigned long * pflags) +{ + struct ion_flag_replace *ion_replace; + unsigned long flags = *pflags; + if ((flags & RTK_ION_FLAG_POOL_CONDITION) == 0) { + pr_err + (" Warning: flags is 0x%lx!! The default value is set (ION_FLAG_ACPUACC | ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_USAGE_MMAP_NONCACHED) \n", + flags); + flags = + ION_FLAG_ACPUACC | ION_FLAG_SCPUACC | + ION_FLAG_HWIPACC | ION_USAGE_MMAP_NONCACHED; + } + + list_for_each_entry(ion_replace, &rtk_carveout_heap->ion_flag_replace, list) { + if (ion_replace) { + unsigned long condition = ion_replace->condition | ION_FLAG_PROTECTED_MASK | ION_FLAG_PROTECTED_EXT_MASK; + if ((flags & condition) == ion_replace->condition) { + flags &= ~condition; + flags |= ion_replace->replace; + } + } + } + + *pflags = flags; +} + +static int ion_rtk_carveout_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned long flags) +{ + int ret = -ENOMEM; + unsigned int retry_count = 0; + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + mutex_lock(&rtk_carveout_heap->lock); + do { + size_t pool_count = heap_pool_count(rtk_carveout_heap); + struct pool_score_slot *pool_score_array = NULL; + struct page_info *page_info = NULL; + + ion_rtk_carveout_heap_flags_preprocess(rtk_carveout_heap, &flags); + + if (pool_count <= 0) { + break; + } + + pool_score_array = + kzalloc(sizeof(struct pool_score_slot) * pool_count, + GFP_KERNEL); + + if (!pool_score_array) { + break; + } + + do { + size_t i; + struct pool_info *pool_info = NULL; + struct pool_score_slot *pool_score_slot = + pool_score_array; + + list_for_each_entry(pool_info, + &rtk_carveout_heap->pools, list) { + pool_score_slot->pool_info = pool_info; + pool_score_slot->score = + pool_score(pool_info, PAGE_ALIGN(size), + flags); + pool_score_slot++; + } + + sort((void *)pool_score_array, pool_count, + sizeof(struct pool_score_slot), pool_score_cmp, + NULL); + + for (i = 0; i < pool_count; i++) { + pool_score_slot = &pool_score_array[i]; + pool_info = pool_score_slot->pool_info; + pr_debug + ("alloc[size=%-10ld flags=%08lx] score[%2zu]=%-5d pool[base=%08lx size=%-10zu flags=%08lx space=%zu]\n", + size, flags, i, pool_score_slot->score, + pool_info->base, pool_info->size, + pool_info->rtk_flags, + pool_info->getSpace(pool_info, flags)); + } +retry: + for (i = 0; i < pool_count; i++) { + pool_score_slot = &pool_score_array[i]; + pool_info = pool_score_slot->pool_info; + + if (!pool_info || pool_score_slot->score <= 0) + continue; + + page_info = + pool_info->alloc(pool_info, size, + PAGE_ALIGN(size), flags); + + if (page_info) + break; + } + if (page_info == NULL && retry_count < retry_count_value && rtk_flag_is_protected_dynamic(flags)) { + msleep(retry_delay_value-100*(retry_count%3)); + retry_count++; + goto retry; + } + if (retry_count > 0) + pr_err("%s: ion cma_alloc page_info = 0x%p, retry_delay = %d, count = %d, MAX_COUNT = %d\n", + __func__, page_info, retry_delay_value, retry_count, retry_count_value); + } while (0); + + kfree(pool_score_array); + + if (!page_info) + break; + + buffer->flags |= page_info->flags; + + if (buffer->flags & ION_USAGE_MMAP_NONCACHED) { + /* NONCACHED */ + buffer->flags |= ION_FLAG_CACHED; + buffer->flags |= ION_FLAG_NONCACHED; + buffer->flags &= ~ION_FLAG_CACHED_NEEDS_SYNC; + } else if (buffer->flags & ION_USAGE_MMAP_WRITECOMBINE) { + /* WRITECOMBINE */ + buffer->flags &= ~ION_FLAG_CACHED; + buffer->flags &= ~ION_FLAG_NONCACHED; + buffer->flags &= ~ION_FLAG_CACHED_NEEDS_SYNC; + } else if ((buffer->flags & ION_USAGE_MMAP_CACHED) + || (!(buffer->flags & ION_FLAG_NONCACHED))) { + /* CACHED */ + buffer->flags |= ION_FLAG_CACHED; + buffer->flags &= ~ION_FLAG_NONCACHED; + buffer->flags |= ION_FLAG_CACHED_NEEDS_SYNC; + } + + if (!(buffer->flags & ION_FLAG_SCPUACC) + || (buffer->flags & ION_USAGE_PROTECTED)) { + buffer->flags |= ION_FLAG_CACHED; + buffer->flags |= ION_FLAG_NONCACHED; + buffer->flags &= ~ION_FLAG_CACHED_NEEDS_SYNC; + } + + buffer->sg_table = page_info->get_sg_table(page_info); + buffer->priv_virt = page_info; + ret = 0; + } + while (0); + + if (ret != 0) { + carveout_heap_allocate_fail_trace(rtk_carveout_heap, size, flags); + } + + mutex_unlock(&rtk_carveout_heap->lock); +#ifdef CONFIG_VIRTUAL_PMU + ion_update_heap_size_info(heap); +#endif + return ret; +} + +static void ion_rtk_carveout_heap_free(struct ion_buffer *buffer) +{ + struct page_info *page_info = NULL; + if (buffer) + page_info = (struct page_info *)buffer->priv_virt; + + if (page_info) { + if (ion_flag_canAccess(page_info->flags)) { + ion_heap_buffer_zero(buffer); + if(!!(buffer->flags & ION_FLAG_CACHED)) + page_info->sync(buffer->dev->dev.this_device, page_info, DMA_TO_DEVICE); + } + page_info->destroy(page_info); +#ifdef CONFIG_VIRTUAL_PMU + if (buffer->heap) { + ion_update_heap_size_info(buffer->heap); + } +#endif + } +} + +static int ion_carveout_heap_debug_show(struct ion_heap *heap, + struct seq_file *s, void *prefix) +{ + int ret = -1; + struct ion_rtk_carveout_heap *rtk_carveout_heap = + container_of(heap, struct ion_rtk_carveout_heap, heap); + mutex_lock(&rtk_carveout_heap->lock); + do { + const size_t seq_buf_size = PAGE_SIZE * 10; + struct seq_buf seq_buf; + char *seq_buf_message = kzalloc(seq_buf_size, GFP_KERNEL); + if (!seq_buf_message) + break; + + seq_buf_init(&seq_buf, seq_buf_message, seq_buf_size); + + ret = + ion_carveout_heap_dump(rtk_carveout_heap, &seq_buf, prefix); + + seq_buf_print_seq(s, &seq_buf); + + kfree(seq_buf_message); + + } while (0); + mutex_unlock(&rtk_carveout_heap->lock); + return ret; +} + +static int ion_carveout_heap_dump(struct ion_rtk_carveout_heap + *rtk_carveout_heap, struct seq_buf *s, + void *prefix) +{ + int ret = -1; + do { + struct ion_flag_replace *ion_replace; + struct pool_info *pool_info = NULL; + + if (!prefix) + prefix = ""; + + list_for_each_entry(ion_replace, &rtk_carveout_heap->ion_flag_replace, list) { + if (!ion_replace) + continue; + seq_buf_printf(s, "replace-table[%pK] 0x%08lx :", + prefix, ion_replace->condition); + seq_buf_printf_ion_flags(s, ion_replace->condition); + seq_buf_printf(s, "\n"); + seq_buf_printf(s, "replace-table[%pK] 0x%08lx :", + prefix, ion_replace->replace); + seq_buf_printf_ion_flags(s, ion_replace->replace); + seq_buf_printf(s, "\n"); + } + + list_for_each_entry(pool_info, &rtk_carveout_heap->pools, list) { + if (!pool_info) + continue; + pool_info->debug_show(pool_info, s, prefix); + } + ret = 0; + } + while (0); + return ret; +} + +int ion_rtk_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + struct sg_table *table = buffer->sg_table; + unsigned long addr = vma->vm_start; + unsigned long offset = vma->vm_pgoff * PAGE_SIZE; + struct scatterlist *sg; + int i; + int ret; + + if (buffer->flags & ION_FLAG_NONCACHED) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + for_each_sg(table->sgl, sg, table->nents, i) { + struct page *page = sg_page(sg); + unsigned long remainder = vma->vm_end - addr; + unsigned long len = sg->length; + + if (offset >= sg->length) { + offset -= sg->length; + continue; + } else if (offset) { + page += offset / PAGE_SIZE; + len = sg->length - offset; + offset = 0; + } + len = min(len, remainder); + ret = + remap_pfn_range(vma, addr, page_to_pfn(page), len, + vma->vm_page_prot); + if (ret) + return ret; + addr += len; + if (addr >= vma->vm_end) + return 0; + } + return 0; +} + +void *ion_rtk_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) +{ + struct scatterlist *sg; + int i, j; + void *vaddr; + pgprot_t pgprot; + struct sg_table *table = buffer->sg_table; + int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **tmp = pages; + + if (!pages) + return ERR_PTR(-ENOMEM); + + if (buffer->flags & ION_FLAG_NONCACHED) + pgprot = pgprot_noncached(PAGE_KERNEL); + else if (buffer->flags & ION_FLAG_CACHED) + pgprot = PAGE_KERNEL; + else + pgprot = pgprot_writecombine(PAGE_KERNEL); + + for_each_sg(table->sgl, sg, table->nents, i) { + int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE; + struct page *page = sg_page(sg); + + BUG_ON(i >= npages); + for (j = 0; j < npages_this_entry; j++) + *(tmp++) = page++; + } + vaddr = vmap(pages, npages, VM_MAP, pgprot); + vfree(pages); + + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.h new file mode 100644 index 000000000000..1c3297644ae3 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/carveout_heap.h @@ -0,0 +1,69 @@ +/* carveout_heap.h + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#ifndef _LINUX_ION_RTK_CARVEOUT_HEAP_H +#define _LINUX_ION_RTK_CARVEOUT_HEAP_H + +#include +#include +#include +#include "ion.h" + +enum ion_rtk_carveout_pool_type { + RTK_CARVEOUT_GEN_POOL_TYPE = 0, + RTK_CARVEOUT_CMA_POOL_TYPE, +}; + +struct ion_rtk_priv_pool { + enum ion_rtk_carveout_pool_type type; + phys_addr_t base; + struct cma *cma_pool; + size_t size; + unsigned long flags; + struct list_head list; + bool from_reserved_memory; +}; + +struct ion_flag_replace { + unsigned long condition; + unsigned long replace; + struct list_head list; +}; + +struct ion_rtk_pre_alloc { + unsigned long rtk_flags; + unsigned long size; + struct list_head list; +}; + +struct ion_rtk_heap_create_priv { + struct list_head pools; + struct list_head rtk_flag_replace; + struct list_head pre_alloc; +}; + +struct ion_rtk_carveout_meminfo { + unsigned long usedSize; + unsigned long freeSize; +}; + +struct ion_rtk_carveout_ops { + unsigned int (*getVersion) (struct ion_heap * heap); + int (*getMemInfo) (struct ion_heap * heap, unsigned int flags, + struct ion_rtk_carveout_meminfo * info); + int (*traceDump) (struct ion_heap * heap, struct seq_file * s); +}; + +struct ion_heap *ion_rtk_carveout_heap_create(struct device *dev, struct ion_platform_heap *); +void ion_rtk_carveout_heap_destroy(struct ion_heap *); + +struct ion_rtk_carveout_ops *get_rtk_carveout_ops(struct ion_heap *heap); + +#endif /* End of _LINUX_ION_RTK_CARVEOUT_HEAP_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.c new file mode 100644 index 000000000000..97b8b44dc0c1 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.c @@ -0,0 +1,73 @@ +#include "debugfs.h" +#include +#include +#include "carveout_heap.h" + +#define DEBUGFS_NAME "ion_rtk" + +struct debugfs_device { + struct dentry *debug_root; +}; + +static struct debugfs_device *debug_dev = NULL; + +static struct debugfs_device *get_debug_dev(void) +{ + do { + struct debugfs_device *tmp = NULL; + if (debug_dev) + break; + + tmp = kzalloc(sizeof(struct debugfs_device), GFP_KERNEL); + if (!tmp) + break; + + tmp->debug_root = debugfs_create_dir(DEBUGFS_NAME, NULL); + if (!tmp->debug_root) { + kfree(tmp); + break; + } + + debug_dev = tmp; + break; + } while (0); + return debug_dev; +} + +static int debugfs_heap_show(struct seq_file *s, void *unused) +{ + struct ion_heap *heap = s->private; + struct ion_rtk_carveout_ops *ops = get_rtk_carveout_ops(heap); + if (heap && heap->debug_show) + heap->debug_show(heap, s, ""); + if (ops && ops->traceDump) + ops->traceDump(heap, s); + return 0; +} + +static int debugfs_heap_open(struct inode *inode, struct file *file) +{ + return single_open(file, debugfs_heap_show, inode->i_private); +} + +static const struct file_operations debug_heap_fops = { + .open = debugfs_heap_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void debugfs_add_heap(struct ion_heap *heap) +{ + do { + struct debugfs_device *dev = get_debug_dev(); + struct dentry *debug_file; + if (!dev) + break; + + debug_file = + debugfs_create_file(heap->name, 0644, dev->debug_root, heap, + &debug_heap_fops); + + } while (0); +} diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.h new file mode 100644 index 000000000000..a36853c81887 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/debugfs.h @@ -0,0 +1,14 @@ +#ifndef _LINUX_ION_RTK_CARVEOUT_HEAP_DEBUGFS_H +#define _LINUX_ION_RTK_CARVEOUT_HEAP_DEBUGFS_H + +#include "ion.h" + +#if defined(CONFIG_DEBUG_FS) +void debugfs_add_heap(struct ion_heap *heap); +#else +void debugfs_add_heap(struct ion_heap *heap) +{ +} +#endif + +#endif /* _LINUX_ION_RTK_CARVEOUT_HEAP_DEBUGFS_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/dev.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/dev.c new file mode 100644 index 000000000000..bbb32b0a6b32 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/dev.c @@ -0,0 +1,744 @@ +/* rtk_ion_of.c + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ion.h" +#include "cma.h" +#include "../inc/ion_rtk_alloc.h" + +#include "carveout_heap.h" +#include "ioctl.h" +#include "debugfs.h" + +static struct device *idev; + +struct ion_platform_data { + int nr; + struct ion_platform_heap *heaps; +}; + +struct ion_heap_desc { + unsigned int id; + enum ion_heap_type type; + const char *name; + unsigned int permission_type; +}; + +enum ion_heap_ids { + INVALID_HEAP_ID = -1, + RTK_ION_HEAP_TYPE_MEDIA_ID = 7, + RTK_ION_HEAP_TYPE_AUDIO_ID = 8, + RTK_ION_HEAP_TYPE_SECURE_ID = 9, +}; + +struct gen_reserved { + struct resource r; + void __iomem *vaddr; + unsigned int flags; + struct list_head list; +}; +static LIST_HEAD(gen_reserved_list); + +#define COLUMN 3 + +static struct ion_heap_desc ion_heap_meta[] = { + { + .type = RTK_ION_HEAP_TYPE_MEDIA, + .id = RTK_ION_HEAP_TYPE_MEDIA_ID, + .name = "Media", + }, + { + .type = RTK_ION_HEAP_TYPE_AUDIO, + .id = RTK_ION_HEAP_TYPE_AUDIO_ID, + .name = "Audio", + }, + { + .type = RTK_ION_HEAP_TYPE_SECURE, + .id = RTK_ION_HEAP_TYPE_SECURE_ID, + .name = "Secure", + }, +}; + +static int rtk_ion_populate_heap(struct ion_platform_heap *heap) +{ + unsigned int i; + int ret = -EINVAL; + unsigned int len = ARRAY_SIZE(ion_heap_meta); + + for (i = 0; i < len; i++) { + if (ion_heap_meta[i].id == heap->id) { + heap->name = ion_heap_meta[i].name; + heap->type = ion_heap_meta[i].type; + ret = 0; + break; + } + } + + if (ret) + dev_err(idev, "unable to populate heap, error:%d", ret); + + return ret; +} + +struct gen_reserved *create_gen_reserved(struct device_node *node) +{ + struct gen_reserved *ret = NULL; + do { + struct resource r; + void __iomem *vaddr; + int gen_flags = 0; + + struct device_node *dt_node = + of_parse_phandle(node, "memory-region", 0); + if (!dt_node) + break; + + if (of_property_read_u32(node, "rtk,gen-pool-Flags", &gen_flags) + != 0) { + break; + } + + if (gen_flags == 0) { + pr_err("%s : Error! rtk,gen-pool-Flags is zero\n", + __func__); + break; + } + + if (of_address_to_resource(dt_node, 0, &r)) { + pr_err + ("%s : No memory address assigned to the region\n", + __func__); + break; + } + + { + phys_addr_t paddr = r.start; + size_t size = resource_size(&r); + vaddr = memremap(paddr, size, MEMREMAP_WB); + if (!vaddr) { + pr_err + ("%s : Could not map the region. (paddr: 0x%08llx, size: 0x%08lx)\n", + __func__, paddr, size); + break; + } + + } + + ret = + (struct gen_reserved *)kzalloc(sizeof(struct gen_reserved), + GFP_KERNEL); + if (!ret) { + pr_err("%s : kzalloc gen_reserved failed!\n", __func__); + break; + } + + memcpy(&ret->r, &r, sizeof(struct resource)); + ret->vaddr = vaddr; + ret->flags = gen_flags; + break; + } while (0); + return ret; +} + +phys_addr_t gen_reserved_base(struct gen_reserved * gen_reserved) +{ + return gen_reserved->r.start; +} + +size_t gen_reserved_size(struct gen_reserved * gen_reserved) +{ + return resource_size(&gen_reserved->r); +} + +unsigned int gen_reserved_flags(struct gen_reserved *gen_reserved) +{ + return gen_reserved->flags; +} + +struct cma *find_reserved_cma(struct device_node *node) +{ + struct cma *ret = NULL; + + do { + if (of_reserved_mem_device_init_by_idx(idev, node, 0) == 0) { + ret = idev->cma_area; + of_reserved_mem_device_release(idev); + } + } while (0); + + return ret; +} + +static unsigned int rtk_ion_cma_extFlags(struct device_node *node, + struct cma *cma) +{ + unsigned long pool_base = cma_get_base(cma); + size_t pool_size = cma_get_size(cma); + unsigned int ret = 0; + const u32 *prop; + int size = 0; + int i; + prop = of_get_property(node, "rtk,cma-pool-extFlags-info", &size); + if (prop && (size % (sizeof(u32) * 3)) == 0) { + for (i = 0; i < (size / (sizeof(u32) * 3)); i += 1) { + u32 extFlag = (u32) of_read_number(prop, 1 + (i * 3)); + u32 extFlag_base = + (u32) of_read_number(prop, 2 + (i * 3)); + u32 extFlag_size = + (u32) of_read_number(prop, 3 + (i * 3)); + if (((u32) pool_base & -1U) >= extFlag_base + && (((u32) (pool_base + pool_size) & -1U) <= + (extFlag_base + extFlag_size))) + ret |= extFlag; + } + } + + { + struct device_node *sub_node; + for_each_child_of_node(node, sub_node) { + struct cma *tmp = find_reserved_cma(sub_node); + if (tmp && tmp == cma) { + int cma_flags = 0; + if (of_property_read_u32 + (sub_node, "rtk,cma-pool-extFlags", + &cma_flags) == 0) { + ret |= cma_flags; + } + } + } + } + return ret; +} + +static struct ion_platform_data *rtk_ion_parse_dt(const struct device_node + *dt_node) +{ + struct ion_platform_data *pdata; + struct ion_platform_heap *heap_data; + struct device_node *node; + + uint32_t val = 0; + int ret = 0; + uint32_t num_heaps = 0; + const u32 *prop; + int err = 0; + int size = 0; + int i = 0; + struct list_head *pools; + bool use_cma_pools = 0; + int cma_pool_flags = 0; + bool skip_dma_default_array = 0; + int counter = 0; + + for_each_child_of_node(dt_node, node) + num_heaps++; + + if (!num_heaps) + return ERR_PTR(-EINVAL); + + pdata = kzalloc(sizeof(struct ion_platform_data), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->nr = num_heaps; + + pdata->heaps = + kcalloc(num_heaps, sizeof(struct ion_platform_heap), GFP_KERNEL); + if (!pdata->heaps) { + ret = -ENOMEM; + goto free_pdata; + } + + heap_data = pdata->heaps; + for_each_child_of_node(dt_node, node) { + struct ion_rtk_heap_create_priv * priv_data = NULL; + struct list_head * rtk_flag_replace; + struct list_head * pre_alloc; + + ret = of_property_read_u32(node, "reg", &val); + if (ret) { + dev_err(idev, "unable to find reg key"); + goto free_heaps; + } + + heap_data->id = val; + ret = rtk_ion_populate_heap(heap_data); + if (ret) { + pdata->nr--; + continue; + //goto free_heaps; + } + + heap_data->base = 0; + heap_data->size = 0; + heap_data->priv = NULL; + + priv_data = (struct ion_rtk_heap_create_priv *) kzalloc(sizeof(struct ion_rtk_heap_create_priv), GFP_KERNEL); + pools = &priv_data->pools; + rtk_flag_replace = &priv_data->rtk_flag_replace; + pre_alloc = &priv_data->pre_alloc; + use_cma_pools = + of_find_property(node, "rtk,use-cma-pools", + NULL) ? true : false; + cma_pool_flags = RTK_FLAG_SCPUACC | RTK_FLAG_ACPUACC | RTK_FLAG_HWIPACC; /* defaule */ + skip_dma_default_array = + of_find_property(node, + "rtk,cma-pools-skip-dma-default-array", + NULL) ? true : false; + + INIT_LIST_HEAD(pools); + INIT_LIST_HEAD(rtk_flag_replace); + INIT_LIST_HEAD(pre_alloc); + + prop = of_get_property(node, "rtk,memory-reserve", &size); + err = size % (sizeof(u32) * COLUMN); + if ((prop) && (!err)) { + counter = size / (sizeof(u32) * COLUMN); + for (i = 0; i < counter; i += 1) { + struct ion_rtk_priv_pool *pool = + kzalloc(sizeof(struct ion_rtk_priv_pool), + GFP_KERNEL); + pool->type = RTK_CARVEOUT_GEN_POOL_TYPE; + pool->base = (phys_addr_t) ((u32) + of_read_number(prop, + 1 + + (i * + COLUMN))); + pool->size = (size_t) ((u32) + of_read_number(prop, + 2 + + (i * + COLUMN))); + pool->flags = (unsigned long)((u32) + of_read_number + (prop, + 3 + + (i * COLUMN))); + + list_add(&pool->list, pools); + } + heap_data->priv = (void *)priv_data; + } + + { + struct device_node *sub_node; + for_each_child_of_node(node, sub_node) { + struct gen_reserved *tmp = + create_gen_reserved(sub_node); + if (tmp) { + struct ion_rtk_priv_pool *pool = + kzalloc(sizeof + (struct ion_rtk_priv_pool), + GFP_KERNEL); + pool->type = RTK_CARVEOUT_GEN_POOL_TYPE; + pool->base = gen_reserved_base(tmp); + pool->size = gen_reserved_size(tmp); + pool->flags = gen_reserved_flags(tmp); + pool->from_reserved_memory = true; + list_add(&pool->list, pools); + list_add(&tmp->list, + &gen_reserved_list); + } + } + heap_data->priv = (void *)priv_data; + } + + if (use_cma_pools + && of_find_property(node, "rtk,cma-pool-flags", NULL)) { + unsigned int flags; + if (of_property_read_u32 + (node, "rtk,cma-pool-flags", &flags) == 0 + && flags != 0) { + cma_pool_flags = flags; + } + } + + /*** legacy ***/ + if (heap_data->id == RTK_ION_HEAP_TYPE_MEDIA_ID + && !of_find_property(node, "rtk,use-cma-pools", NULL)) { + use_cma_pools = true; + if (cma_area_count == 1) { + cma_pool_flags = + RTK_FLAG_SCPUACC | RTK_FLAG_NONCACHED | + RTK_FLAG_HWIPACC; + } else { + skip_dma_default_array = true; + } + } + + if (use_cma_pools) { + for (i = 0; i < cma_area_count; i += 1) { + struct ion_rtk_priv_pool *pool; + struct cma *cma = &cma_areas[i]; + + if (skip_dma_default_array + && cma == dma_contiguous_default_area) { + dev_err(idev, + "do not add dma_contiguous_default_area to the pool list. (cma_area_count=%d)\n", + cma_area_count); + continue; + } + + if (cma_get_size(cma) == 0) + continue; + + pool = kzalloc(sizeof(struct ion_rtk_priv_pool), GFP_KERNEL); + pool->type = RTK_CARVEOUT_CMA_POOL_TYPE; + pool->cma_pool = cma; + pool->base = cma_get_base(pool->cma_pool); + pool->size = cma_get_size(pool->cma_pool); + pool->flags = cma_pool_flags; + pool->flags |= rtk_ion_cma_extFlags(node, cma); + list_add(&pool->list, pools); + } + heap_data->priv = (void *)priv_data; + } + + if (heap_data->priv == NULL) { + kfree(priv_data); + } else { + prop = of_get_property(node, "rtk,flag-replace-table", &size); + if (prop && (size % (sizeof(u32) * 2)) == 0) { + for (i = 0; i < size/sizeof(u32) ; i += 2) { + struct ion_flag_replace * replace = (struct ion_flag_replace *) kzalloc(sizeof(struct ion_flag_replace), GFP_KERNEL); + if (!replace) + continue; + INIT_LIST_HEAD(&replace->list); + replace->condition = (unsigned long) ((u32)of_read_number(prop, i + 1)); + replace->replace = (unsigned long) ((u32)of_read_number(prop, i + 2)); + list_add_tail(&replace->list, &priv_data->rtk_flag_replace); + } + } + + prop = of_get_property(node, "rtk,pre-alloc", &size); + if (prop && (size % (sizeof(u32) * 2)) == 0) { + for (i = 0; i < size/sizeof(u32) ; i += 2) { + struct ion_rtk_pre_alloc * pre_alloc = (struct ion_rtk_pre_alloc *) kzalloc(sizeof(struct ion_rtk_pre_alloc), GFP_KERNEL); + if (!pre_alloc) + continue; + INIT_LIST_HEAD(&pre_alloc->list); + pre_alloc->rtk_flags = (unsigned long) ((u32)of_read_number(prop, i + 1)); + pre_alloc->size = (unsigned long) ((u32)of_read_number(prop, i + 2)); + list_add(&pre_alloc->list, &priv_data->pre_alloc); + } + } + } + + heap_data++; + } + return pdata; + +free_heaps: + kfree(pdata->heaps); +free_pdata: + kfree(pdata); + return ERR_PTR(ret); +} + +struct ion_heap *ion_heap_create(struct device *dev, + struct ion_platform_heap *heap_data) +{ + struct ion_heap *heap = NULL; + + switch ((int)heap_data->type) { + case RTK_ION_HEAP_TYPE_MEDIA: + case RTK_ION_HEAP_TYPE_AUDIO: + case RTK_ION_HEAP_TYPE_SECURE: + heap = ion_rtk_carveout_heap_create(dev, heap_data); + if (!IS_ERR_OR_NULL(heap)) + heap->type = heap_data->type; + break; + default: + dev_warn(idev, "invalid heap type %d\n", heap_data->type); + return ERR_PTR(-EINVAL); + } + + if (IS_ERR_OR_NULL(heap)) { + dev_err(idev, + "error creating heap %s type %d base %llx size %zu\n", + heap_data->name, heap_data->type, heap_data->base, + heap_data->size); + return ERR_PTR(-EINVAL); + } + + heap->name = heap_data->name; + debugfs_add_heap(heap); + + return heap; +} + +static const struct file_operations ion_rtk_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = ion_rtk_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ion_rtk_ioctl, +#endif +}; + +int ion_rtk_device_create(void) +{ + struct miscdevice *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->minor = MISC_DYNAMIC_MINOR; + dev->name = "ion_rtk"; + dev->fops = &ion_rtk_fops; + dev->parent = NULL; + + ret = misc_register(dev); + if (ret) { + pr_err("ion_rtk: failed to register misc device.\n"); + kfree(dev); + return ret; + } + + return 0; +} + +static int rtk_ion_probe(struct platform_device *pdev) +{ + struct ion_platform_data *pdata; + struct ion_platform_heap *heap_data; + unsigned int pdata_needs_freed; + int err = -1; + int i = 0; + struct ion_heap **heaps; + + idev = &pdev->dev; + + if (pdev->dev.of_node) { + pdata = rtk_ion_parse_dt(pdev->dev.of_node); + if (IS_ERR(pdata)) { + err = PTR_ERR(pdata); + goto out; + } + pdata_needs_freed = 1; + } else { + pdata = pdev->dev.platform_data; + pdata_needs_freed = 0; + } + + dev_info(idev, "number of_heaps: %d\n", pdata->nr); + + heaps = devm_kzalloc(&pdev->dev, sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL); + if (!heaps) { + err = -ENOMEM; + goto out; + } + + /* create the heaps as specified in the board file */ + heap_data = pdata->heaps; + + for (i = 0; i < pdata->nr; i++) { + + heaps[i] = ion_heap_create(idev, heap_data); + if (IS_ERR_OR_NULL(heaps[i])) { + heaps[i] = 0; + heap_data++; + continue; + } + + ion_device_add_heap(heaps[i]); + + if (heap_data->priv) { + struct ion_rtk_heap_create_priv * priv_data = (struct ion_rtk_heap_create_priv *) heap_data->priv; + struct ion_rtk_priv_pool *pool, *tmp_pool; + struct ion_flag_replace * replace, *tmp_replace; + struct ion_rtk_pre_alloc *pre_alloc, *tmp_pre_alloc; + list_for_each_entry_safe(pool, tmp_pool, &priv_data->pools, list) { + dev_err(idev, + "adding heap %s of type %d with %llx@%lx (type:%s)", + heap_data->name, heap_data->type, + pool->base, pool->size, + (pool->type == + RTK_CARVEOUT_GEN_POOL_TYPE) ? + "GEN_POOL" : (pool->type == + RTK_CARVEOUT_CMA_POOL_TYPE) + ? "CMA_POOL" : "Unknown"); + + list_del(&pool->list); + kfree(pool); + } + list_for_each_entry_safe(replace, tmp_replace, &priv_data->rtk_flag_replace, list) { + list_del(&replace->list); + kfree(replace); + } + list_for_each_entry_safe(pre_alloc, tmp_pre_alloc, &priv_data->pre_alloc, list) { + list_del(&pre_alloc->list); + kfree(pre_alloc); + } + kfree(priv_data); + } + heap_data++; + } + + ion_rtk_device_create(); + + if (pdata_needs_freed) { + kfree(pdata->heaps); + kfree(pdata); + } + + return 0; + +out: + return err; +} + +static int rtk_ion_remove(struct platform_device *pdev) +{ + /* [TODO]: destroy heap + for (int i = 0; i < num_heaps; i++) + ion_heap_destroy(heaps[i]); + + kfree(heaps); + */ + return 0; +} + +static struct of_device_id rtk_ion_ids[] = { + {.compatible = "realtek,rtk-ion"}, + { /* Sentinel */ }, +}; + +static struct platform_driver rtk_ion_driver = { + .probe = rtk_ion_probe, + .remove = rtk_ion_remove, + .driver = { + .name = "realtek-ion", + .of_match_table = rtk_ion_ids, + }, +}; + +static int __init rtk_ion_init(void) +{ + return platform_driver_register(&rtk_ion_driver); +} + +static void __exit rtk_ion_exit(void) +{ + platform_driver_unregister(&rtk_ion_driver); +} + +fs_initcall(rtk_ion_init); +module_exit(rtk_ion_exit); + +static struct ion_heap_data *rtk_ion_get_heaps_buffer(size_t * cnt) +{ + static size_t ion_heap_cnt = 0; + static struct ion_heap_data *buffer = NULL; + do { + static struct ion_heap_query query; + mm_segment_t oldfs; + + memset(&query, 0, sizeof(struct ion_heap_query)); + + if (ion_query_heaps(&query) != 0 || query.cnt == 0) { + pr_err("%s ion_query_heaps error!\n", __func__); + break; + } + + if (buffer && query.cnt == ion_heap_cnt) + break; + + oldfs = get_fs(); + + set_fs(KERNEL_DS); + + if (buffer) + kfree(buffer); + + buffer = + kzalloc(sizeof(struct ion_heap_data) * query.cnt, + GFP_KERNEL); + + if (buffer == NULL) { + set_fs(oldfs); + break; + } + + query.heaps = (uintptr_t) buffer; + + if (ion_query_heaps(&query) != 0) { + kfree(buffer); + set_fs(oldfs); + buffer = NULL; + break; + } + + ion_heap_cnt = query.cnt; + + set_fs(oldfs); + } while (0); + + if (cnt) + *cnt = ion_heap_cnt; + + return buffer; +} + +unsigned int rtk_ion_heap_id_mask_tr(unsigned int heap_type_mask) +{ + unsigned int heap_id_mask = 0; + do { + size_t i; + size_t heap_cnt = 0; + struct ion_heap_data *buffer = + rtk_ion_get_heaps_buffer(&heap_cnt); + + if (buffer == NULL || heap_cnt == 0) + break; + + for (i = 0; i < heap_cnt; i++) { + if (((1U << buffer[i].type) & heap_type_mask) == 0) + continue; + heap_id_mask |= 1U << buffer[i].heap_id; + } + + break; + } while (0); + return heap_id_mask; +} + +int ext_rtk_ion_alloc(size_t len, unsigned int heap_type_mask, + unsigned int flags) +{ + unsigned int heap_id_mask = rtk_ion_heap_id_mask_tr(heap_type_mask); + return ion_alloc(len, heap_id_mask, flags); +} +EXPORT_SYMBOL(ext_rtk_ion_alloc); + +int ext_rtk_ion_close_fd(struct files_struct *files, unsigned fd) +{ + return __close_fd(files, fd); +} +EXPORT_SYMBOL(ext_rtk_ion_close_fd); diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.c new file mode 100644 index 000000000000..a73a0be77003 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.c @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include +#include + +#include "ion_old/ion.h" +#include "uapi_old/ion_rtk.h" +#include "carveout_heap.h" +#include "flags.h" +#include "dev_legacy.h" +#include "../inc/ion_rtk_alloc.h" + +static u64 dma_mask; + +static bool is_dma_buf_fd(int fd) +{ + struct dma_buf *dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return false; + + dma_buf_put(dmabuf); + return true; +} + +static int dma_buf_fd_dup(int fd) +{ + int ret = -1; + do { + struct dma_buf *dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) { + pr_err("%s dma_buf_get error! (fd:%d)\n", __func__, fd); + break; + } + + ret = dma_buf_fd(dmabuf, O_CLOEXEC); + if (ret < 0) { + dma_buf_put(dmabuf); + pr_err + ("%s dma_buf_fd error! (fd:%d dmabuf=%p)\n", + __func__, fd, dmabuf); + break; + } + + break; + } while (0); + return ret; +} + +static int legacy_ion_get_phys(int handle, phys_addr_t * addr, size_t * len) +{ + struct ion_buffer *buffer; + struct dma_buf *dmabuf; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + + dmabuf = dma_buf_get(handle); + if (IS_ERR(dmabuf)) + return -ENODEV; + + buffer = dmabuf->priv; + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + *addr = paddr; + *len = buffer->size; + + dma_buf_put(dmabuf); + return 0; +} + +static int legacy_ion_sync(int fd, enum dma_data_direction dir) +{ + struct dma_buf *dmabuf; + struct ion_buffer *buffer; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + buffer = dmabuf->priv; + if (!ion_flag_is_protected(buffer->flags)) { + dma_mask = 0xffffffff; + buffer->dev->dev.this_device->dma_mask = &dma_mask; + int nents = dma_map_sg(buffer->dev->dev.this_device, buffer->sg_table->sgl, + buffer->sg_table->nents, dir); + dma_sync_sg_for_device(buffer->dev->dev.this_device, buffer->sg_table->sgl, + buffer->sg_table->nents, dir); + if (nents > 0) + dma_unmap_sg(buffer->dev->dev.this_device, buffer->sg_table->sgl, + buffer->sg_table->nents, dir); + } + + dma_buf_put(dmabuf); + return 0; +} + +static int legacy_ion_sync_range(int fd, enum dma_data_direction dir, + unsigned long phyAddr, size_t len) +{ + struct dma_buf *dmabuf; + struct ion_buffer *buffer; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + buffer = dmabuf->priv; + dma_mask = 0xffffffff; + buffer->dev->dev.this_device->dma_mask = &dma_mask; + if (!ion_flag_is_protected(buffer->flags)) { + phys_addr_t addr; + size_t len; + if (legacy_ion_get_phys(fd, &addr, &len) == 0) { + size_t offset = phyAddr - addr; + dma_addr_t paddr = dma_map_single(buffer->dev->dev.this_device, + sg_virt + (buffer->sg_table-> + sgl) + + offset, + len, dir); + dma_sync_single_for_device(buffer->dev->dev.this_device, phyAddr, len, dir); + if (paddr) + dma_unmap_single(buffer->dev->dev.this_device, paddr, len, dir); + } + } + + dma_buf_put(dmabuf); + return 0; +} + +static long legacy_ion_rtk_custom_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + long ret = -ENOTTY; + switch (cmd) { + case LEGACY_RTK_ION_IOC_INVALIDATE: + { + int fd = arg; + if (legacy_ion_sync(fd, DMA_FROM_DEVICE)) { + pr_err("%s: legacy_ion_sync failed!(fd=%d)\n", + __func__, fd); + break; + } + ret = 0; + break; + } + case LEGACY_RTK_ION_IOC_FLUSH: + { + int fd = arg; + if (legacy_ion_sync(fd, DMA_TO_DEVICE)) { + pr_err("%s: legacy_ion_sync failed!(fd=%d)\n", + __func__, fd); + break; + } + ret = 0; + break; + } + case LEGACY_RTK_ION_IOC_INVALIDATE_RANGE: + { + struct legacy_rtk_ion_ioc_sync_rane data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + if (legacy_ion_sync_range + (data.handle, DMA_FROM_DEVICE, data.phyAddr, + data.len)) { + pr_err + ("%s: legacy_ion_sync_range failed!(fd=%d)\n", + __func__, data.handle); + break; + } + ret = 0; + break; + } + case LEGACY_RTK_ION_IOC_FLUSH_RANGE: + { + struct legacy_rtk_ion_ioc_sync_rane data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + if (legacy_ion_sync_range + (data.handle, DMA_TO_DEVICE, data.phyAddr, + data.len)) { + pr_err + ("%s: legacy_ion_sync_range failed!(fd=%d)\n", + __func__, data.handle); + break; + } + ret = 0; + break; + } + case LEGACY_RTK_ION_IOC_GET_PHYINFO: + { + struct legacy_rtk_ion_ioc_phy_info data; + phys_addr_t addr; + size_t len; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + if (data.handle < 0) { + pr_err("%s : invalid handle=%d\n", __func__, + data.handle); + break; + } + + if (legacy_ion_get_phys(data.handle, &addr, &len)) { + pr_err + ("%s: legacy_ion_get_phys failed!(fd=%d)\n", + __func__, data.handle); + break; + } + + data.addr = addr; + data.len = len; + + if (copy_to_user + ((void __user *)arg, &data, sizeof(data))) { + pr_err + ("%s : copy_to_user failed! (fd=%d, phyAddr=0x%08x, len=%zu)\n", + __func__, data.handle, addr, len); + break; + } + + ret = 0; + break; + } + default: + pr_err("%s: Unknown custom ioctl (cmd=0x%08x)\n", __func__, + cmd); + break; + } + return ret; +} + +static long legacy_ion_rtk_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + long ret = -ENOTTY; + switch (cmd) { + case LEGACY_ION_IOC_ALLOC: + { + struct legacy_ion_allocation_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + data.handle = + ext_rtk_ion_alloc(data.len, data.heap_id_mask, + data.flags); + if (data.handle < 0) { + pr_err + ("%s : alloc failed! (len:%zu heaps=0x%x flags=0x%x)\n", + __func__, data.len, data.heap_id_mask, + data.flags); + break; + } + + if (copy_to_user + ((void __user *)arg, &data, sizeof(data))) { + ext_rtk_ion_close_fd(current->files, + data.handle); + pr_err + ("%s : copy_to_user failed! (len:%zu heaps=0x%x flags=0x%x)\n", + __func__, data.len, data.heap_id_mask, + data.flags); + break; + } + ret = 0; + break; + } + case LEGACY_ION_IOC_FREE: + { + struct legacy_ion_handle_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + if (data.handle < 0 || !is_dma_buf_fd(data.handle)) { + pr_err + ("%s : (cmd=0x%08x) invalid handle=%d\n", + __func__, cmd, data.handle); + break; + } + + ext_rtk_ion_close_fd(current->files, data.handle); + ret = 0; + break; + } + case LEGACY_ION_IOC_SHARE: + case LEGACY_ION_IOC_MAP: + { + struct legacy_ion_fd_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + if (data.handle < 0 || !is_dma_buf_fd(data.handle)) { + pr_err + ("%s : (cmd=0x%08x) invalid handle=%d\n", + __func__, cmd, data.handle); + break; + } + + data.fd = dma_buf_fd_dup(data.handle); + if (data.fd < 0) { + pr_err + ("%s (cmd=0x%08x) dma_buf_fd_dup error! (fd:%d)\n", + __func__, cmd, data.handle); + break; + } + + if (copy_to_user + ((void __user *)arg, &data, sizeof(data))) { + ext_rtk_ion_close_fd(current->files, data.fd); + pr_err + ("%s : copy_to_user failed! (handle=%d)\n", + __func__, data.handle); + break; + } + ret = 0; + break; + } + case LEGACY_ION_IOC_IMPORT: + { + struct legacy_ion_fd_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + if (data.fd < 0 || !is_dma_buf_fd(data.fd)) { + pr_err + ("%s : (cmd=0x%08x) invalid fd=%d\n", + __func__, cmd, data.fd); + break; + } + + data.handle = dma_buf_fd_dup(data.fd); + if (data.handle < 0) { + pr_err + ("%s (cmd=0x%08x) dma_buf_fd_dup error! (fd:%d)\n", + __func__, cmd, data.fd); + break; + } + + if (copy_to_user + ((void __user *)arg, &data, sizeof(data))) { + ext_rtk_ion_close_fd(current->files, + data.handle); + pr_err + ("%s : copy_to_user failed! (handle=%d)\n", + __func__, data.handle); + break; + } + ret = 0; + break; + } + case LEGACY_ION_IOC_SYNC: + { + struct legacy_ion_fd_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + if (data.fd < 0 || !is_dma_buf_fd(data.fd)) { + pr_err + ("%s : (cmd=0x%08x) invalid fd=%d\n", + __func__, cmd, data.fd); + break; + } + + if (legacy_ion_sync(data.fd, DMA_BIDIRECTIONAL)) { + pr_err("%s : error sync (fd=%d)\n", __func__, + data.fd); + break; + } + ret = 0; + break; + } + case LEGACY_ION_IOC_CUSTOM: + { + struct legacy_ion_custom_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + ret = + legacy_ion_rtk_custom_ioctl(filp, data.cmd, + data.arg); + break; + } + case LEGACY_ION_IOC_PHYS: + { + struct legacy_ion_phys_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + if (data.handle < 0 || !is_dma_buf_fd(data.handle)) { + pr_err + ("%s : (cmd=0x%08x) invalid fd=%d\n", + __func__, cmd, data.handle); + break; + } + + { + phys_addr_t addr; + size_t len; + if (legacy_ion_get_phys + (data.handle, &addr, &len)) { + pr_err + ("%s: (cmd=0x%08x) legacy_ion_get_phys failed!(fd=%d)\n", + __func__, cmd, data.handle); + break; + } + data.addr = addr; + data.len = len; + } + + if (copy_to_user + ((void __user *)arg, &data, sizeof(data))) { + pr_err + ("%s : (cmd=0x%08x) copy_to_user failed! (handle=%d)\n", + __func__, cmd, data.handle); + break; + } + + ret = 0; + break; + } + default: + pr_err("%s: Unknown custom ioctl (cmd=0x%08x)\n", __func__, + cmd); + ret = -ENOTTY; + break; + } + return ret; +} + +static const struct file_operations legacy_ion_rtk_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = legacy_ion_rtk_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = legacy_ion_rtk_ioctl, +#endif +}; + +static int legacy_ion_device_create(void) +{ + struct miscdevice *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->minor = MISC_DYNAMIC_MINOR; + dev->name = "ion_legacy"; + dev->fops = &legacy_ion_rtk_fops; + dev->parent = NULL; + + ret = misc_register(dev); + if (ret) { + pr_err("ion_legacy: failed to register misc device.\n"); + kfree(dev); + return ret; + } + + return 0; +} + +fs_initcall(legacy_ion_device_create); diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.h new file mode 100644 index 000000000000..9cf489b638c5 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/dev_legacy.h @@ -0,0 +1,213 @@ +#ifndef _LINUX_ION_RTK_DEV_LEGACY_H +#define _LINUX_ION_RTK_DEV_LEGACY_H + +#include +#include + +typedef int legacy_ion_user_handle_t; + +enum legacy_ion_heap_type { + LEGACY_ION_HEAP_TYPE_SYSTEM, + LEGACY_ION_HEAP_TYPE_SYSTEM_CONTIG, + LEGACY_ION_HEAP_TYPE_CARVEOUT, + LEGACY_ION_HEAP_TYPE_CHUNK, + LEGACY_ION_HEAP_TYPE_DMA, + LEGACY_ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always + are at the end of this enum */ + LEGACY_ION_NUM_HEAPS = 16, +}; + +#define LEGACY_ION_HEAP_SYSTEM_MASK (1 << LEGACY_ION_HEAP_TYPE_SYSTEM) +#define LEGACY_ION_HEAP_SYSTEM_CONTIG_MASK (1 << LEGACY_ION_HEAP_TYPE_SYSTEM_CONTIG) +#define LEGACY_ION_HEAP_CARVEOUT_MASK (1 << LEGACY_ION_HEAP_TYPE_CARVEOUT) +#define LEGACY_ION_HEAP_TYPE_DMA_MASK (1 << LEGACY_ION_HEAP_TYPE_DMA) + +/** + * allocation flags - the lower 16 bits are used by core ion, the upper 16 + * bits are reserved for use by the heaps themselves. + */ +#define LEGACY_ION_FLAG_CACHED 1 /* mappings of this buffer should be + cached, ion will do cache + maintenance when the buffer is + mapped for dma */ +#define LEGACY_ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created + at mmap time, if this is set + caches must be managed manually */ + +/** + * DOC: Ion Userspace API + * + * create a client by opening /dev/ion + * most operations handled via following ioctls + * + */ + +/** + * struct legacy_ion_allocation_data - metadata passed from userspace for allocations + * @len: size of the allocation + * @align: required alignment of the allocation + * @heap_id_mask: mask of heap ids to allocate from + * @flags: flags passed to heap + * @handle: pointer that will be populated with a cookie to use to + * refer to this allocation + * + * Provided by userspace as an argument to the ioctl + */ +struct legacy_ion_allocation_data { + size_t len; + size_t align; + unsigned int heap_id_mask; + unsigned int flags; + legacy_ion_user_handle_t handle; +}; + +/** + * struct legacy_ion_fd_data - metadata passed to/from userspace for a handle/fd pair + * @handle: a handle + * @fd: a file descriptor representing that handle + * + * For LEGACY_ION_IOC_SHARE or LEGACY_ION_IOC_MAP userspace populates the handle field with + * the handle returned from ion alloc, and the kernel returns the file + * descriptor to share or map in the fd field. For LEGACY_ION_IOC_IMPORT, userspace + * provides the file descriptor and the kernel returns the handle. + */ +struct legacy_ion_fd_data { + legacy_ion_user_handle_t handle; + int fd; +}; + +/** + * struct legacy_ion_handle_data - a handle passed to/from the kernel + * @handle: a handle + */ +struct legacy_ion_handle_data { + legacy_ion_user_handle_t handle; +}; + +/** + * struct legacy_ion_custom_data - metadata passed to/from userspace for a custom ioctl + * @cmd: the custom ioctl function to call + * @arg: additional data to pass to the custom ioctl, typically a user + * pointer to a predefined structure + * + * This works just like the regular cmd and arg fields of an ioctl. + */ +struct legacy_ion_custom_data { + unsigned int cmd; + unsigned long arg; +}; + +/** + * struct legacy_ion_phys_data - metadata passed to/from userspace for a handle pair + * @handle: a handle + * @addr: the physical address + * @len: the allocate size + * + * For LEGACY_ION_IOC_PHYS userspace populates the handle field with + * the handle returned from ion alloc, and the kernel returns the specific info of the handle. + */ +struct legacy_ion_phys_data { + legacy_ion_user_handle_t handle; + unsigned long addr; + unsigned int len; +}; + +#define LEGACY_ION_IOC_MAGIC 'I' + +/** + * DOC: LEGACY_ION_IOC_ALLOC - allocate memory + * + * Takes an legacy_ion_allocation_data struct and returns it with the handle field + * populated with the opaque handle for the allocation. + */ +#define LEGACY_ION_IOC_ALLOC _IOWR(LEGACY_ION_IOC_MAGIC, 0, \ + struct legacy_ion_allocation_data) + +/** + * DOC: LEGACY_ION_IOC_FREE - free memory + * + * Takes an legacy_ion_handle_data struct and frees the handle. + */ +#define LEGACY_ION_IOC_FREE _IOWR(LEGACY_ION_IOC_MAGIC, 1, struct legacy_ion_handle_data) + +/** + * DOC: LEGACY_ION_IOC_MAP - get a file descriptor to mmap + * + * Takes an legacy_ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be used as an argument to mmap. + */ +#define LEGACY_ION_IOC_MAP _IOWR(LEGACY_ION_IOC_MAGIC, 2, struct legacy_ion_fd_data) + +/** + * DOC: LEGACY_ION_IOC_SHARE - creates a file descriptor to use to share an allocation + * + * Takes an legacy_ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be passed to another process. The corresponding opaque handle can + * be retrieved via LEGACY_ION_IOC_IMPORT. + */ +#define LEGACY_ION_IOC_SHARE _IOWR(LEGACY_ION_IOC_MAGIC, 4, struct legacy_ion_fd_data) + +/** + * DOC: LEGACY_ION_IOC_IMPORT - imports a shared file descriptor + * + * Takes an legacy_ion_fd_data struct with the fd field populated with a valid file + * descriptor obtained from LEGACY_ION_IOC_SHARE and returns the struct with the handle + * filed set to the corresponding opaque handle. + */ +#define LEGACY_ION_IOC_IMPORT _IOWR(LEGACY_ION_IOC_MAGIC, 5, struct legacy_ion_fd_data) + +/** + * DOC: LEGACY_ION_IOC_SYNC - syncs a shared file descriptors to memory + * + * Deprecated in favor of using the dma_buf api's correctly (syncing + * will happend automatically when the buffer is mapped to a device). + * If necessary should be used after touching a cached buffer from the cpu, + * this will make the buffer in memory coherent. + */ +#define LEGACY_ION_IOC_SYNC _IOWR(LEGACY_ION_IOC_MAGIC, 7, struct legacy_ion_fd_data) + +/** + * DOC: LEGACY_ION_IOC_CUSTOM - call architecture specific ion ioctl + * + * Takes the argument of the architecture specific ioctl to call and + * passes appropriate userdata for that ioctl + */ +#define LEGACY_ION_IOC_CUSTOM _IOWR(LEGACY_ION_IOC_MAGIC, 6, struct legacy_ion_custom_data) + +/** + * DOC: LEGACY_ION_IOC_PHYS - query specific information of the ion handle + * + * Takes an legacy_ion_phys_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the phyAddr and len. + */ +#define LEGACY_ION_IOC_PHYS _IOWR(LEGACY_ION_IOC_MAGIC, 8, struct legacy_ion_phys_data) + +/*******************************************/ + +struct legacy_rtk_ion_ioc_sync_rane { + legacy_ion_user_handle_t handle; + unsigned long long phyAddr; + unsigned int len; +}; + +struct legacy_rtk_ion_ioc_phy_info { + legacy_ion_user_handle_t handle; + unsigned long long addr; + unsigned long long len; +}; + +enum { + LEGACY_RTK_PHOENIX_ION_TILER_ALLOC, + LEGACY_RTK_PHOENIX_ION_GET_LAST_ALLOC_ADDR, + LEGACY_RTK_ION_IOC_INVALIDATE = 0x10, + LEGACY_RTK_ION_IOC_FLUSH, + LEGACY_RTK_ION_IOC_INVALIDATE_RANGE = 0x13, + LEGACY_RTK_ION_IOC_FLUSH_RANGE, + LEGACY_RTK_ION_IOC_GET_PHYINFO, +}; + +#endif /* End of _LINUX_ION_RTK_DEV_LEGACY_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/flags.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/flags.h new file mode 100644 index 000000000000..66a4f6f347b2 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/flags.h @@ -0,0 +1,297 @@ +#ifndef _LINUX_ION_RTK_FLAGS_H +#define _LINUX_ION_RTK_FLAGS_H + +#include +#include +#include "../inc/ion_rtk_protected_notifier.h" + +static struct protected_mapping_slot { + int rtk_type; + enum E_ION_PROTECTED_TYPE ion_type; + enum E_ION_NOTIFIER_PROTECTED_TYPE notifier_type; +} protected_mapping_table[] = { + { + RTK_PROTECTED_TYPE_1, ION_PROTECTED_TYPE_1, + ION_NOTIFIER_PROTECTED_TYPE_1} + , { + RTK_PROTECTED_TYPE_2, ION_PROTECTED_TYPE_2, + ION_NOTIFIER_PROTECTED_TYPE_2} + , { + RTK_PROTECTED_TYPE_3, ION_PROTECTED_TYPE_3, + ION_NOTIFIER_PROTECTED_TYPE_3} + , { + RTK_PROTECTED_TYPE_4, ION_PROTECTED_TYPE_4, + ION_NOTIFIER_PROTECTED_TYPE_4} + , { + RTK_PROTECTED_TYPE_5, ION_PROTECTED_TYPE_5, + ION_NOTIFIER_PROTECTED_TYPE_5} + , { + RTK_PROTECTED_TYPE_6, ION_PROTECTED_TYPE_6, + ION_NOTIFIER_PROTECTED_TYPE_6} + , { + RTK_PROTECTED_TYPE_7, ION_PROTECTED_TYPE_7, + ION_NOTIFIER_PROTECTED_TYPE_7} + , { + RTK_PROTECTED_TYPE_8, ION_PROTECTED_TYPE_8, + ION_NOTIFIER_PROTECTED_TYPE_8} + , { + RTK_PROTECTED_TYPE_9, ION_PROTECTED_TYPE_9, + ION_NOTIFIER_PROTECTED_TYPE_9} + , { + RTK_PROTECTED_TYPE_10, ION_PROTECTED_TYPE_10, + ION_NOTIFIER_PROTECTED_TYPE_10} + , { + RTK_PROTECTED_TYPE_11, ION_PROTECTED_TYPE_11, + ION_NOTIFIER_PROTECTED_TYPE_11} + , { + RTK_PROTECTED_TYPE_12, ION_PROTECTED_TYPE_12, + ION_NOTIFIER_PROTECTED_TYPE_12} + , { + RTK_PROTECTED_TYPE_13, ION_PROTECTED_TYPE_13, + ION_NOTIFIER_PROTECTED_TYPE_13} + , { + RTK_PROTECTED_TYPE_14, ION_PROTECTED_TYPE_14, + ION_NOTIFIER_PROTECTED_TYPE_14} + , { + RTK_PROTECTED_TYPE_15, ION_PROTECTED_TYPE_15, + ION_NOTIFIER_PROTECTED_TYPE_15} +}; + +static inline enum E_ION_NOTIFIER_PROTECTED_TYPE +ion_flags_to_notifier_protected_type(unsigned long flags) +{ + enum E_ION_NOTIFIER_PROTECTED_TYPE ret = + ION_NOTIFIER_PROTECTED_TYPE_NONE; + size_t i = 0; + for (i = 0; i < ARRAY_SIZE(protected_mapping_table); i++) { + if (protected_mapping_table[i].ion_type == + ION_PROTECTED_TYPE_GET(flags)) { + ret = protected_mapping_table[i].notifier_type; + break; + } + } + return ret; +} + +static inline enum E_ION_PROTECTED_TYPE rtk_flags_to_ion_protected_type(unsigned + long + flags) +{ + enum E_ION_PROTECTED_TYPE ret = ION_PROTECTED_TYPE_NONE; + size_t i = 0; + for (i = 0; i < ARRAY_SIZE(protected_mapping_table); i++) { + if (protected_mapping_table[i].rtk_type == + RTK_PROTECTED_TYPE_GET(flags)) { + ret = protected_mapping_table[i].ion_type; + break; + } + } + return ret; +} + +static inline enum E_ION_NOTIFIER_PROTECTED_TYPE +rtk_flags_to_notifier_protected_type(unsigned long flags) +{ + enum E_ION_NOTIFIER_PROTECTED_TYPE ret = + ION_NOTIFIER_PROTECTED_TYPE_NONE; + size_t i = 0; + for (i = 0; i < ARRAY_SIZE(protected_mapping_table); i++) { + if (protected_mapping_table[i].rtk_type == + RTK_PROTECTED_TYPE_GET(flags)) { + ret = protected_mapping_table[i].notifier_type; + break; + } + } + return ret; +} + +static inline bool rtk_flag_is_protected_dynamic(unsigned long flags) +{ + return ((flags & RTK_FLAG_PROTECTED_DYNAMIC) && + (RTK_PROTECTED_TYPE_GET(flags) != + RTK_PROTECTED_TYPE_NONE)) ? true : false; +} + +static inline bool rtk_flag_is_protected_static(unsigned long flags) +{ + return (!(flags & RTK_FLAG_PROTECTED_DYNAMIC) && + (RTK_PROTECTED_TYPE_GET(flags) != + RTK_PROTECTED_TYPE_NONE)) ? true : false; +} + +static inline bool rtk_flag_is_protected(unsigned long flags) +{ + return (flags & RTK_FLAG_PROTECTED_MASK) ? true : false; +} + +static inline bool rtk_flag_has_protected_ext(unsigned long flags) +{ + return (flags & RTK_FLAG_PROTECTED_EXT_MASK) ? true : false; +} + +static inline bool rtk_flag_canAccess(unsigned long flags) +{ + bool access = false; + do { + if (!(flags & RTK_FLAG_SCPUACC)) + break; + + if (!rtk_flag_is_protected_dynamic(flags)) { + if (RTK_PROTECTED_TYPE_GET(flags) != + RTK_PROTECTED_TYPE_NONE) + break; + } + access = true; + break; + } while (0); + return access; +} + +static inline bool ion_flag_is_protected(unsigned long flags) +{ + bool ret = true; + do { + if (flags & ION_FLAG_PROTECTED_MASK) + break; + ret = false; + break; + } while (0); + return ret; +} + +static inline bool ion_flag_is_noncached(unsigned long flags) +{ + bool ret = true; + do { + if (flags & ION_FLAG_NONCACHED) + break; + ret = false; + break; + } while (0); + return ret; +} + +static inline bool ion_flag_canAccess(unsigned long flags) +{ + bool access = false; + do { + if (!(flags & ION_FLAG_SCPUACC)) + break; + + if (ion_flag_is_protected(flags)) + break; + + access = true; + break; + } while (0); + return access; +} + +static inline unsigned long ion_flag_pool_condition(unsigned long flags) +{ + return flags & RTK_ION_FLAG_POOL_CONDITION; +} + +static inline unsigned long ion_flag_condition_from_rtk(unsigned long rtk_flags) +{ + unsigned long flags = rtk_flags; + unsigned long out = 0; + //out |= (flags & RTK_FLAG_NONCACHED) ? ION_FLAG_NONCACHED : 0; + out |= (flags & RTK_FLAG_SCPUACC) ? ION_FLAG_SCPUACC : 0; + out |= (flags & RTK_FLAG_ACPUACC) ? ION_FLAG_ACPUACC : 0; + out |= (flags & RTK_FLAG_HWIPACC) ? ION_FLAG_HWIPACC : 0; + out |= (flags & RTK_FLAG_VE_SPEC) ? ION_FLAG_VE_SPEC : 0; + out |= (flags & RTK_FLAG_VCPU_FWACC) ? ION_FLAG_VCPU_FWACC : 0; + out |= (flags & RTK_FLAG_CMA) ? ION_FLAG_CMA : 0; + out |= ION_FLAG_PROTECTED_BITS(rtk_flags_to_ion_protected_type(flags)); + return out; +} + +static inline unsigned long ion_flag_mapping_from_rtk(unsigned long rtk_flags) +{ + unsigned long out = ion_flag_condition_from_rtk(rtk_flags); + if (rtk_flag_has_protected_ext(rtk_flags)) { + out |= ION_FLAG_PROTECTED_EXT_BITS(RTK_PROTECTED_EXT_GET(rtk_flags)); + } + return out; +} + +static inline unsigned long ion_flag_from_rtk(unsigned long rtk_flags) +{ + unsigned long flags = rtk_flags; + unsigned long out = 0; + //out |= (flags & RTK_FLAG_NONCACHED) ? ION_FLAG_NONCACHED : 0; + out |= (flags & RTK_FLAG_SCPUACC) ? ION_FLAG_SCPUACC : 0; + out |= (flags & RTK_FLAG_ACPUACC) ? ION_FLAG_ACPUACC : 0; + out |= (flags & RTK_FLAG_HWIPACC) ? ION_FLAG_HWIPACC : 0; + out |= (flags & RTK_FLAG_VE_SPEC) ? ION_FLAG_VE_SPEC : 0; + out |= (flags & RTK_FLAG_VCPU_FWACC) ? ION_FLAG_VCPU_FWACC : 0; + out |= (flags & RTK_FLAG_CMA) ? ION_FLAG_CMA : 0; + if (!rtk_flag_is_protected_dynamic(flags)) { + out |= + ION_FLAG_PROTECTED_BITS(rtk_flags_to_ion_protected_type + (flags)); + } + return out; +} + +static inline bool ion_flag_match_pool_condition(unsigned long flags, + unsigned long rtk_flags) +{ + bool ret = false; + unsigned long target = ion_flag_pool_condition(flags); + unsigned long condition = ion_flag_condition_from_rtk(rtk_flags); + do { + if ((target & condition) != target) + break; + if (ion_flag_is_protected(flags)) { + if (ION_PROTECTED_TYPE_GET(flags) != + rtk_flags_to_ion_protected_type(rtk_flags)) + break; + } else if (rtk_flag_is_protected_static(rtk_flags)) { + break; + } + + if (rtk_flag_has_protected_ext(rtk_flags) && + RTK_PROTECTED_EXT_GET(rtk_flags) != + ION_PROTECTED_EXT_GET(flags)) { + break; + } + + ret = true; + } while (0); + return ret; +} + +static inline bool ion_flag_mismatch_pool_condition(unsigned long flags, + unsigned long rtk_flags) +{ + return !ion_flag_match_pool_condition(flags, rtk_flags); +} + +static inline bool ion_flag_match_condition(unsigned long flags_target, + unsigned long flags_condition) +{ + unsigned long target = ion_flag_pool_condition(flags_target); + unsigned long condition = ion_flag_pool_condition(flags_condition); + return ((target & condition) == target) ? true : false; +} + +static inline bool ion_flag_is_algo_last_fit(unsigned long flags) +{ + return (flags & ION_USAGE_ALGO_LAST_FIT) ? true : false; +} + +static inline bool ion_flag_has_protected_ext(unsigned long flags) +{ + return (flags & ION_FLAG_PROTECTED_EXT_MASK) ? true : false; +} + +static inline enum E_ION_NOTIFIER_PROTECTED_EXT +ion_flag_to_notifier_protected_ext(unsigned long flags) +{ + enum E_ION_NOTIFIER_PROTECTED_EXT ret = + (enum E_ION_NOTIFIER_PROTECTED_EXT) ION_PROTECTED_EXT_GET(flags); + return ret; +} +#endif /* _LINUX_ION_RTK_FLAGS_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.c new file mode 100644 index 000000000000..52586f1dfd94 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.c @@ -0,0 +1,369 @@ +/* ion_rtk_ioctl.c + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#include "ion.h" +#include +#include "carveout_heap.h" +#include "flags.h" + +#define ALIGNTO 32U +#define ION_ALIGN(len) (((len) + ALIGNTO - 1) & ~(ALIGNTO - 1)) + +static u64 dma_mask; + +extern struct ion_device *ion_dev; + +int ion_rtk_get_phys(int handle, phys_addr_t * addr, size_t * len) +{ + struct ion_buffer *buffer; + struct dma_buf *dmabuf; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + int ret = 0; + + dmabuf = dma_buf_get(handle); + if (IS_ERR(dmabuf)) { + ret = -ENODEV; + goto err; + } + + buffer = dmabuf->priv; + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + *addr = paddr; + *len = buffer->size; + +err: + dma_buf_put(dmabuf); + return ret; +} + +struct ion_heap *ion_get_client_heap_by_mask(struct ion_device *dev, + unsigned int heap_id_mask) +{ + struct ion_heap *heap = NULL; + + down_read(&dev->lock); + plist_for_each_entry(heap, &dev->heaps, node) { + /* if the caller didn't specify this heap id */ + if (!((1 << heap->id) & heap_id_mask)) + continue; + break; + } + up_read(&dev->lock); + + return heap; +} + +static int rtk_ion_sync_for_device(int fd, int cmd) +{ + struct dma_buf *dmabuf; + struct ion_buffer *buffer; + enum dma_data_direction dir = (cmd == RTK_ION_IOC_INVALIDATE) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + switch (cmd) { + case RTK_ION_IOC_INVALIDATE: + case RTK_ION_IOC_FLUSH: + break; + default: + return -EINVAL; + } + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + buffer = dmabuf->priv; + dma_mask = 0xffffffff; + buffer->dev->dev.this_device->dma_mask = &dma_mask; + + if (!ion_flag_is_protected(buffer->flags) && + !ion_flag_is_noncached(buffer->flags)) { + int nents = dma_map_sg(buffer->dev->dev.this_device, buffer->sg_table->sgl, + buffer->sg_table->nents, dir); + dma_sync_sg_for_device(buffer->dev->dev.this_device, buffer->sg_table->sgl, + buffer->sg_table->nents, dir); + if (nents > 0) + dma_unmap_sg(buffer->dev->dev.this_device, buffer->sg_table->sgl, + buffer->sg_table->nents, dir); + } + + dma_buf_put(dmabuf); + return 0; +} + +static int rtk_ion_sync_range_for_device(int handle, int cmd, struct rtk_ion_ioc_sync_rane + *range_data) +{ + struct dma_buf *dmabuf; + struct ion_buffer *buffer; + enum dma_data_direction dir = + (cmd == + RTK_ION_IOC_INVALIDATE_RANGE) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + int fd; + + switch (cmd) { + case RTK_ION_IOC_INVALIDATE_RANGE: + case RTK_ION_IOC_FLUSH_RANGE: + break; + default: + return -EINVAL; + } + + fd = (int)range_data->handle & -1U; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + buffer = dmabuf->priv; + dma_mask = 0xffffffff; + buffer->dev->dev.this_device->dma_mask = &dma_mask; + + if (!ion_flag_is_protected(buffer->flags) && + !ion_flag_is_noncached(buffer->flags)) { + phys_addr_t addr; + size_t len; + if (ion_rtk_get_phys(handle, &addr, &len) == 0) { + size_t offset = range_data->phyAddr - addr; + dma_addr_t paddr = dma_map_page(buffer->dev->dev.this_device, + sg_page(buffer->sg_table->sgl), + offset, + range_data->len, dir); + dma_sync_single_for_device(buffer->dev->dev.this_device, range_data->phyAddr, + range_data->len, dir); + dma_unmap_page(buffer->dev->dev.this_device, paddr, range_data->len, dir); + } + } + + dma_buf_put(dmabuf); + return 0; +} + +static int rtk_ion_get_memory_info(int handle, unsigned int heapMask, + unsigned int flags, + struct ion_rtk_carveout_meminfo *info) +{ + int i; + struct ion_buffer *buffer; + struct dma_buf *dmabuf; + int ret; + + if (info == NULL) + goto err; + + dmabuf = dma_buf_get(handle); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto err; + } + + buffer = dmabuf->priv; + + info->usedSize = 0; + info->freeSize = 0; + + for (i = 0; i < 32; i++) { + struct ion_heap *heap; + struct ion_rtk_carveout_ops *ops; + struct ion_rtk_carveout_meminfo tmp_info; + unsigned int target_heap_id_mask = 0x1U << i; + + if ((target_heap_id_mask & heapMask) == 0) + continue; + + heap = + ion_get_client_heap_by_mask(buffer->dev, + target_heap_id_mask); + if (heap == NULL) + continue; + + ops = get_rtk_carveout_ops(heap); + if (ops == NULL) + continue; + + if (ops->getMemInfo(heap, flags, &tmp_info) == 0) { + info->usedSize += tmp_info.usedSize; + info->freeSize += tmp_info.freeSize; + } + } + + dma_buf_put(dmabuf); + + return 0; +err: + return -1; +} + +static int rtk_ion_get_phy_info(struct rtk_ion_ioc_phy_info *phyInfo) +{ + int ret = 0; + phys_addr_t addr; + size_t len; + + if (phyInfo->handle < 0) { + ret = -EINVAL; + goto err; + } + + ret = ion_rtk_get_phys(phyInfo->handle, &addr, &len); + + phyInfo->addr = addr; + phyInfo->len = len; + +err: + return ret; +} + +long ion_rtk_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = -1; + switch (cmd) { + case RTK_ION_GET_LAST_ALLOC_ADDR:{ + pr_err + ("%s: Outdated ioctl : RTK_PHOENIX_ION_GET_LAST_ALLOC_ADDR\n", + __func__); + ret = -EFAULT; + break; + } + case RTK_ION_IOC_INVALIDATE: + case RTK_ION_IOC_FLUSH:{ + int fd = -1; + ret = + copy_from_user(&fd, (void __user *)arg, sizeof(fd)); + if (rtk_ion_sync_for_device(fd, cmd) != 0) { + pr_err + ("%s: rtk_ion_sync_for_device failed! (cmd:%x fd:%d)\n", + __func__, cmd, fd); + ret = -EFAULT; + } + + break; + } + case RTK_ION_IOC_FLUSH_RANGE: + case RTK_ION_IOC_INVALIDATE_RANGE:{ + + struct rtk_ion_ioc_sync_rane range_data; + ret = + copy_from_user(&range_data, (void __user *)arg, + sizeof(range_data)); + if (ret) { + pr_err + ("%s:%d copy_from_user failed! (ret = %d)\n", + __func__, __LINE__, ret); + ret = -EFAULT; + } + + if (rtk_ion_sync_range_for_device + (range_data.handle, cmd, &range_data) != 0) { + pr_err + ("%s: rtk_ion_sync_range_for_device failed! (cmd:%d handle:%d)\n", + __func__, cmd, (int)range_data.handle); + ret = -EFAULT; + } + + break; + } + + case RTK_ION_IOC_GET_PHYINFO:{ + struct rtk_ion_ioc_phy_info phyInfo; + ret = + copy_from_user(&phyInfo, (void __user *)arg, + sizeof(phyInfo)); + if (ret) { + pr_err + ("%s:%d copy_from_user failed! (ret = %d)\n", + __func__, __LINE__, ret); + ret = -EFAULT; + break; + } + + ret = rtk_ion_get_phy_info(&phyInfo); + if (ret != 0) { + pr_err + ("%s:%d rtk_ion_get_phy_info failed! (ret = %d)\n", + __func__, __LINE__, ret); + ret = -EFAULT; + break; + } + + ret = + copy_to_user((void __user *)arg, &phyInfo, + sizeof(phyInfo)); + if (ret) { + pr_err + ("%s:%d copy_to_user failed! (ret = %d)\n", + __func__, __LINE__, ret); + return -EFAULT; + } + + break; + } + case RTK_ION_IOC_GET_MEMORY_INFO:{ + struct rtk_ion_ioc_get_memory_info_s user_info; + struct ion_rtk_carveout_meminfo ion_info; + + ret = + copy_from_user(&user_info, (void __user *)arg, + sizeof(user_info)); + if (ret) { + pr_err + ("%s:%d copy_from_user failed! (ret = %d)\n", + __func__, __LINE__, ret); + ret = -EFAULT; + break; + } + + ret = + rtk_ion_get_memory_info(user_info.handle, + user_info.heapMask, + user_info.flags, &ion_info); + if (ret) { + pr_err + ("%s:%d rtk_ion_get_memory_info failed! (ret = %d)\n", + __func__, __LINE__, ret); + ret = -EFAULT; + break; + } + + user_info.usedSize = + (unsigned int)ion_info.usedSize & -1U; + user_info.freeSize = + (unsigned int)ion_info.freeSize & -1U; + + ret = + copy_to_user((void __user *)arg, &user_info, + sizeof(user_info)); + if (ret) { + pr_err + ("%s:%d copy_to_user failed! (ret = %d)\n", + __func__, __LINE__, ret); + ret = -EFAULT; + } + + break; + } + + default: + pr_err("%s: Unknown custom ioctl\n", __func__); + ret = -ENOTTY; + break; + } + return ret; +} diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.h new file mode 100644 index 000000000000..65dee90333a5 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/ioctl.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_ION_RTK_IOCTL_H +#define _LINUX_ION_RTK_IOCTL_H + +#include + +long ion_rtk_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#endif /* _LINUX_ION_RTK_IOCTL_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/pool.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool.h new file mode 100644 index 000000000000..3fbb5c592022 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool.h @@ -0,0 +1,75 @@ +#ifndef _LINUX_ION_RTK_CARVEOUT_HEAP_POOL_H +#define _LINUX_ION_RTK_CARVEOUT_HEAP_POOL_H + +#include +#include +#include +#include +#include "carveout_heap.h" +#include "flags.h" + +struct page_info; +struct pool_info; + +enum pool_type { + GEN_POOL, + CMA_POOL, + PREALLOC_POOL, +}; + +struct pool_info { + enum pool_type type; + unsigned long base; + size_t size; + unsigned long rtk_flags; + struct list_head list; + + struct page_info *(*alloc) (struct pool_info * pool_info, + unsigned long size, unsigned long align, + unsigned long flags); + size_t(*getSpace) (struct pool_info * pool_info, unsigned long flags); + size_t(*getUsage) (struct pool_info * pool_info, unsigned long flags); + int (*debug_show) (struct pool_info * pool_info, struct seq_buf *, + char *); + void (*destroy) (struct pool_info * pool_info); +}; + +struct page_info { + unsigned long base; + size_t size; + unsigned long flags; + char task_comm[TASK_COMM_LEN]; + pid_t pid; + pid_t tgid; + + struct sg_table *(*get_sg_table) (struct page_info * page_info); + void (*sync) (struct device *dev, struct page_info * page_info, enum dma_data_direction dir); + void (*sync_range) (struct device *dev, struct page_info * page_info, + enum dma_data_direction dir, unsigned long addr, + size_t size); + void (*destroy) (struct page_info * page_info); +}; + +struct pool_info *ion_gen_pool_create(enum pool_type type, unsigned long base, size_t size, + unsigned long rtk_flags, + bool from_reserved_memory, + struct device *dev); +struct pool_info *ion_cma_pool_create(struct cma *cma, unsigned long rtk_flags); + +void page_common_init(struct page_info *info, unsigned long base, size_t size, + unsigned long flags); +void page_common_sync(struct device *dev, struct page_info *page_info, enum dma_data_direction dir); +void page_common_sync_range(struct device *dev, struct page_info *page_info, + enum dma_data_direction dir, unsigned long addr, + size_t size); + +void pool_common_init(struct pool_info *info, enum pool_type type, + unsigned long base, size_t size, unsigned long rtk_flags); + +void seq_buf_printf_ion_flags(struct seq_buf *s, unsigned long flags); + +void page_common_debug_show(struct page_info *page_info, + struct seq_buf *s, char *prefix); +void pool_common_debug_show(struct pool_info *pool_info, + struct seq_buf *s, char *prefix); +#endif /* End of _LINUX_ION_RTK_CARVEOUT_HEAP_POOL_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_cma.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_cma.c new file mode 100644 index 000000000000..214e6d9c8827 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_cma.c @@ -0,0 +1,1067 @@ +#include "pool.h" +#include "protected.h" +#include +#include +#include +#include +#include "cma.h" + +extern struct mutex cma_mutex; + +struct cma_pool_info { + struct pool_info common; + struct mutex lock; + struct list_head pages; + struct cma *cpool; + struct list_head protected_list; + unsigned long *protected_reserved_bitmap; + struct page *protected_static_page; +}; + +struct cma_page_info { + struct page_info common; + struct cma_pool_info *parent; + struct page *page; + struct list_head list; + struct sg_table *sg_table; + struct RTK_PROTECTED_EXT_INFO * protected_ext_info; +}; + +/* public api */ +struct pool_info *ion_cma_pool_create(struct cma *cma, unsigned long rtk_flags); +static struct page_info *ion_cma_pool_alloc(struct pool_info *pool_info, + unsigned long size, + unsigned long align, + unsigned long flags); +static size_t ion_cma_pool_getSpace(struct pool_info *pool_info, + unsigned long flags); +static size_t ion_cma_pool_getUsage(struct pool_info *pool_info, + unsigned long flags); +static int ion_cma_pool_debug_show(struct pool_info *pool_info, + struct seq_buf *, char *prefix); +static void ion_cma_pool_destroy(struct pool_info *pool_info); +static void ion_cma_page_destroy(struct page_info *page_info); +static struct sg_table *ion_cma_page_get_sg_table(struct page_info *page_info); + +/* private func */ +static struct cma_page_info *ion_cma_page_alloc(void); +static void ion_cma_page_free(struct cma_page_info *page); +static void ion_cma_page_info_init(struct cma_page_info *page, size_t count, + unsigned long flags, + unsigned long rtk_flags); +static struct page *ion_cma_pool_alloc_taile(struct cma_pool_info *pool, + size_t count, unsigned int align); +static struct page *ion_cma_pool_alloc_from_protected(struct cma_pool_info + *pool, size_t count, + unsigned int align); +struct RTK_PROTECTED_INFO * ion_cma_pool_find_protected_info(struct cma_pool_info *pool, struct page *page); +static bool ion_cma_pool_check_region_is_safe(struct cma_pool_info *pool, + enum E_ION_NOTIFIER_PROTECTED_TYPE + protected_type, struct page *page, + size_t count); +static void ion_cma_pool_refresh_protected_range(struct cma_pool_info *pool, struct cma_page_info + *cma_page); +static size_t ion_cma_free_pages(struct cma_pool_info *pool); + +static size_t bitmap_seq_printf(struct seq_buf *s, unsigned long *bitmap, + int nbits) +{ + /* current bit is 'cur', most recently seen range is [rbot, rtop] */ + int cur, rbot; + bool first = true; + + cur = find_first_bit(bitmap, nbits); + while (cur < nbits) { + rbot = cur; + cur = find_next_zero_bit(bitmap, nbits, cur + 1); + + if (!first) + seq_buf_printf(s, ","); + first = false; + + seq_buf_printf(s, "%d", rbot); + + seq_buf_printf(s, "-%d", cur - 1); + + cur = find_next_bit(bitmap, nbits, cur + 1); + } + return 0; +} + + + +struct pool_info *ion_cma_pool_create(struct cma *cma, unsigned long rtk_flags) +{ + struct pool_info *ret = NULL; + + do { + struct cma_pool_info *pool = (struct cma_pool_info *) + kzalloc(sizeof(struct cma_pool_info), GFP_KERNEL); + struct pool_info *common; + unsigned long base; + size_t size; + + if (!pool) + break; + + common = &pool->common; + base = cma_get_base(cma); + size = cma_get_size(cma); + + pool_common_init(common, CMA_POOL, base, size, rtk_flags); + common->alloc = ion_cma_pool_alloc; + common->getSpace = ion_cma_pool_getSpace; + common->getUsage = ion_cma_pool_getUsage; + common->debug_show = ion_cma_pool_debug_show; + common->destroy = ion_cma_pool_destroy; + + pool->cpool = cma; + INIT_LIST_HEAD(&pool->pages); + INIT_LIST_HEAD(&pool->protected_list); + if (rtk_flag_is_protected_dynamic(rtk_flags)) { + int bitmap_count = cma_bitmap_maxno(pool->cpool); + int bitmap_size = + BITS_TO_LONGS(bitmap_count) * sizeof(long); + pool->protected_reserved_bitmap = + kzalloc(bitmap_size, GFP_KERNEL); + bitmap_set(pool->protected_reserved_bitmap, + 0 /*start */, bitmap_count /*len */); + } else if (rtk_flag_is_protected_static(rtk_flags)) { + do { + int bitmap_count = + cma_bitmap_maxno(pool->cpool); + int bitmap_size = + BITS_TO_LONGS(bitmap_count) * sizeof(long); + + pool->protected_static_page = + cma_alloc(pool->cpool, bitmap_count, 0, + GFP_KERNEL | GFP_DMA); + + if (!pool->protected_static_page) { + pr_err + ("%s : cma area creation failed! (cma = %p, rtk_flags = 0x%lx)\n", + __func__, pool->cpool, rtk_flags); + break; + } + + if (!ion_cma_pool_check_region_is_safe + (pool, + rtk_flags_to_notifier_protected_type + (rtk_flags), pool->protected_static_page, + bitmap_count)) { + cma_release(pool->cpool, + pool->protected_static_page, + bitmap_count); + pool->protected_static_page = NULL; + pr_err + ("%s : Protected area creation failed! (cma = %p, rtk_flags = 0x%lx)\n", + __func__, pool->cpool, rtk_flags); + break; + } + + pool->protected_reserved_bitmap = + kzalloc(bitmap_size, GFP_KERNEL); + + bitmap_clear(pool->protected_reserved_bitmap, + 0 /*start */, + bitmap_count /*len */); + break; + } while (0); + + if (!pool->protected_reserved_bitmap) { + pool->common.rtk_flags &= + ~(RTK_FLAG_PROTECTED_DYNAMIC | + RTK_FLAG_PROTECTED_MASK); + } + } + + mutex_init(&pool->lock); + ret = &pool->common; + break; + } while (0); + return ret; +} + +void ion_cma_pool_destroy(struct pool_info *pool_info) +{ + struct cma_pool_info *pool = + container_of(pool_info, struct cma_pool_info, common); + mutex_lock(&pool->lock); + //TODO + if (pool->protected_reserved_bitmap) + kfree(pool->protected_reserved_bitmap); + mutex_unlock(&pool->lock); + kfree(pool); +} + +static void ion_cma_page_zero(struct page *page, size_t count) +{ + if (PageHighMem(page)) { + unsigned long nr_clear_pages = count; + struct page *ppage = page; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(ppage); + + memset(vaddr, 0, PAGE_SIZE); +#ifdef CONFIG_ARM64 + __dma_flush_area(vaddr, PAGE_SIZE); +#elif defined(CONFIG_ARM) + dmac_flush_range(vaddr, vaddr + PAGE_SIZE); +#endif + kunmap_atomic(vaddr); + ppage++; + nr_clear_pages--; + } + } else { + void *ptr = page_address(page); + size_t flush_size = PAGE_SIZE * count; + memset(ptr, 0, flush_size); +#ifdef CONFIG_ARM64 + __dma_flush_area(ptr, flush_size); +#elif defined(CONFIG_ARM) + dmac_flush_range(ptr, ptr + flush_size); + outer_flush_range(__pa(ptr), __pa(ptr) + flush_size); +#endif + } +} + +static struct page_info *ion_cma_pool_alloc(struct pool_info *pool_info, + unsigned long size, + unsigned long align, + unsigned long flags) +{ + struct page_info *ret = NULL; + struct cma_pool_info *pool = + container_of(pool_info, struct cma_pool_info, common); + struct pool_info *common = &pool->common; + + mutex_lock(&pool->lock); + do { + struct cma_page_info *page = NULL; + size_t cma_count = size >> PAGE_SHIFT; + unsigned int cma_align = 0; /* closely spaced */ + + if (ion_flag_mismatch_pool_condition(flags, common->rtk_flags)) + break; + + page = ion_cma_page_alloc(); + if (!page) + break; + + if (rtk_flag_is_protected(common->rtk_flags) && + ion_flag_is_protected(flags)) { + if (rtk_flag_is_protected_dynamic(common->rtk_flags)) { + const size_t protected_align_size = + 2 * 1024 * 1024; + cma_align = protected_align_size >> PAGE_SHIFT; + cma_count = ALIGN(cma_count, cma_align); + } + page->page = + ion_cma_pool_alloc_from_protected(pool, cma_count, + cma_align); + if (!page->page) { + page->page = + ion_cma_pool_alloc_taile(pool, cma_count, + cma_align); + if (!page->page) { + ion_cma_page_free(page); + break; + } + + if (!ion_cma_pool_check_region_is_safe + (pool, + ion_flags_to_notifier_protected_type + (flags), page->page, cma_count)) { + cma_release(pool->cpool, page->page, + cma_count); + ion_cma_page_free(page); + break; + } + } + } else { + cma_align = get_order(size); + if (cma_align > CONFIG_CMA_ALIGNMENT) + cma_align = CONFIG_CMA_ALIGNMENT; + + page->page = + cma_alloc(pool->cpool, cma_count, cma_align, + GFP_KERNEL | GFP_DMA); + } + + if (!page->page) { + ion_cma_page_free(page); + break; + } + + if (rtk_flag_is_protected(common->rtk_flags) && + !rtk_flag_has_protected_ext(common->rtk_flags) && + ion_flag_has_protected_ext(flags)) { + + page->protected_ext_info = create_protected_ext_info( + ion_flag_to_notifier_protected_ext(flags), + page_to_phys(page->page), cma_count << PAGE_SHIFT, + ion_cma_pool_find_protected_info(pool, page->page)); + + if (!page->protected_ext_info) { + cma_release(pool->cpool, page->page, cma_count); + ion_cma_page_free(page); + break; + } + } + + if (!ion_flag_is_protected(flags)) + ion_cma_page_zero(page->page, cma_count); + + ion_cma_page_info_init(page, cma_count, flags, + common->rtk_flags); + + list_add(&page->list, &pool->pages); + page->parent = pool; + + ret = &page->common; + } while (0); + mutex_unlock(&pool->lock); + + return ret; +} + +static struct page *ion_cma_pool_alloc_from_protected(struct cma_pool_info + *pool, size_t count, + unsigned int align) +{ + struct cma *cma = pool->cpool; + unsigned long mask, offset; + unsigned long pfn = -1; + unsigned long start = 0; + unsigned long bitmap_maxno, bitmap_no, bitmap_count; + struct page *page = NULL; + + if (!cma || !cma->count) + return NULL; + + if (!count) + return NULL; + + mask = + (align <= + cma->order_per_bit) ? 0 : (1UL << (align - cma->order_per_bit)) - + 1; + offset = (cma->base_pfn & ((1UL << align) - 1)) >> cma->order_per_bit; + bitmap_maxno = cma_bitmap_maxno(cma); + bitmap_count = + ALIGN(count, 1UL << cma->order_per_bit) >> cma->order_per_bit; + + if (bitmap_count > bitmap_maxno) + return NULL; + + do { + bitmap_no = + bitmap_find_next_zero_area_off + (pool->protected_reserved_bitmap, bitmap_maxno, start, + bitmap_count, mask, offset); + + if (bitmap_no >= bitmap_maxno) { + break; + } + + pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit); + + page = pfn_to_page(pfn); + + bitmap_set(pool->protected_reserved_bitmap, bitmap_no, + bitmap_count); + } while (0); + return page; +} + +static struct page *ion_cma_pool_alloc_taile(struct cma_pool_info *pool, + size_t count, unsigned int align) +{ + struct cma *cma = pool->cpool; + unsigned long mask, offset; + unsigned long pfn = -1; + unsigned long start = 0; + unsigned long bitmap_maxno, bitmap_no, bitmap_count; + struct page *page = NULL; + int ret; + + if (!cma || !cma->count) + return NULL; + + pr_debug("%s(cma %p, count %zu, align %d)\n", __func__, (void *)cma, + count, align); + + if (!count) + return NULL; + + mask = + (align <= + cma->order_per_bit) ? 0 : (1UL << (align - cma->order_per_bit)) - + 1; + offset = (cma->base_pfn & ((1UL << align) - 1)) >> cma->order_per_bit; + bitmap_maxno = cma_bitmap_maxno(cma); + bitmap_count = + ALIGN(count, 1UL << cma->order_per_bit) >> cma->order_per_bit; + + if (bitmap_count > bitmap_maxno) + return NULL; + + start = bitmap_maxno; + + while (start > bitmap_count) { + start -= bitmap_count; + mutex_lock(&cma->lock); + bitmap_no = bitmap_find_next_zero_area_off(cma->bitmap, + bitmap_maxno, start, + bitmap_count, mask, + offset); + + if (bitmap_no >= bitmap_maxno) { + start = find_next_bit(cma->bitmap, bitmap_maxno, start); + mutex_unlock(&cma->lock); + continue; + } + bitmap_set(cma->bitmap, bitmap_no, bitmap_count); + mutex_unlock(&cma->lock); + + pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit); + mutex_lock(&cma_mutex); + ret = + alloc_contig_range(pfn, pfn + count, MIGRATE_CMA, + GFP_KERNEL | GFP_DMA); + mutex_unlock(&cma_mutex); + + if (ret == 0) { + page = pfn_to_page(pfn); + break; + } + + mutex_lock(&cma->lock); + bitmap_clear(cma->bitmap, bitmap_no, bitmap_count); + mutex_unlock(&cma->lock); + + }; + + return page; +} + +struct RTK_PROTECTED_INFO * ion_cma_pool_find_protected_info(struct cma_pool_info *pool, struct page *page) +{ + struct RTK_PROTECTED_INFO * ret = NULL; + struct RTK_PROTECTED_INFO *protected_info; + unsigned long offset = page_to_phys(page); + list_for_each_entry(protected_info, &pool->protected_list, list) { + if (offset >= get_protected_base(protected_info) && + offset < get_protected_limit(protected_info)) { + ret = protected_info; + break; + } + + } + return ret; +} + +static bool ion_cma_pool_check_region_is_safe(struct cma_pool_info *pool, + enum E_ION_NOTIFIER_PROTECTED_TYPE + protected_type, struct page *page, + size_t count) +{ + bool safe = false; + do { + struct RTK_PROTECTED_INFO *protected_info; + struct cma *cma = pool->cpool; + unsigned long bitmap_count = ALIGN(count, + 1UL << cma->order_per_bit) >> + cma->order_per_bit; + unsigned long offset = page_to_phys(page); + size_t size = bitmap_count << PAGE_SHIFT; + unsigned long limit = offset + size; + list_for_each_entry(protected_info, &pool->protected_list, list) { + if (get_protected_base(protected_info) == limit) { + unsigned long next_protected_base = offset; + unsigned long next_protected_limit = + get_protected_limit(protected_info); + struct ion_rtk_protected_change_info info; + + info.mem.base = next_protected_base; + info.mem.size = + next_protected_limit - next_protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + info.priv_virt = + get_protected_priv(protected_info); + if (ion_rtk_protected_change_notify(&info) != + NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + continue; + } + set_protected_range(protected_info, + next_protected_base, + next_protected_limit); + safe = true; + break; + } else if (get_protected_limit(protected_info) == + offset) { + unsigned long next_protected_base = + get_protected_base(protected_info); + unsigned long next_protected_limit = + offset + size; + struct ion_rtk_protected_change_info info; + + info.mem.base = next_protected_base; + info.mem.size = + next_protected_limit - next_protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + info.priv_virt = + get_protected_priv(protected_info); + if (ion_rtk_protected_change_notify(&info) != + NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + continue; + } + set_protected_range(protected_info, + next_protected_base, + next_protected_limit); + safe = true; + break; + } + } + + if (!safe) { + struct RTK_PROTECTED_INFO *protected_info = + kzalloc(sizeof(struct RTK_PROTECTED_INFO), + GFP_KERNEL); + struct ion_rtk_protected_create_info info; + + info.mem.base = offset; + info.mem.size = size; + info.mem.type = protected_type; + + if (protected_info == NULL) { + pr_err("%s:%d ERROR!\n", __func__, __LINE__); + break; + } + + if (ion_rtk_protected_create_notify(&info) != NOTIFY_OK) { + kfree(protected_info); + pr_err + ("%s:%d ion_rtk_protected_create_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv(protected_info)); + break; + } + + init_protected_info(protected_info); + set_protected_range(protected_info, offset, + offset + size); + set_protected_type(protected_info, protected_type); + set_protected_priv(protected_info, info.priv_virt); + list_add(&protected_info->list, &pool->protected_list); + safe = true; + break; + } + + if (!safe) { + pr_err("%s:%d ERROR!\n", __func__, __LINE__); + } + + break; + } while (0); + + return safe; +} + +struct cma_page_info *ion_cma_page_alloc(void) +{ + struct cma_page_info *ret = NULL; + do { + struct cma_page_info *page = (struct cma_page_info *) + kzalloc(sizeof(struct cma_page_info), GFP_KERNEL); + + if (!page) { + pr_err("%s kzalloc return NULL!", __func__); + break; + } + + page->sg_table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!page->sg_table) { + kfree(page); + break; + } + + if (sg_alloc_table(page->sg_table, 1, GFP_KERNEL) != 0) { + kfree(page->sg_table); + kfree(page); + break; + } + + ret = page; + } while (0); + return ret; +} + +void ion_cma_page_free(struct cma_page_info *page) +{ + sg_free_table(page->sg_table); + kfree(page->sg_table); + kfree(page); +} + +void ion_cma_page_info_init(struct cma_page_info *page, size_t count, + unsigned long flags, unsigned long rtk_flags) +{ + unsigned long base = page_to_phys(page->page); + size_t size = count << PAGE_SHIFT; + + page_common_init(&page->common, base, size, + flags | ion_flag_from_rtk(rtk_flags)); + + sg_set_page(page->sg_table->sgl, page->page, size, 0); + + { + size_t i; + struct scatterlist *sg; + for_each_sg(page->sg_table->sgl, sg, page->sg_table->nents, i) { + sg_dma_address(sg) = sg_phys(sg); + sg_dma_len(sg) = sg->length; + } + } + page->common.destroy = ion_cma_page_destroy; + page->common.get_sg_table = ion_cma_page_get_sg_table; + page->common.sync_range = page_common_sync_range; + page->common.sync = page_common_sync; + INIT_LIST_HEAD(&page->list); +} + +void ion_cma_page_destroy(struct page_info *page_info) +{ + struct cma_page_info *page = + container_of(page_info, struct cma_page_info, common); + struct cma_pool_info *pool = page->parent; + mutex_lock(&pool->lock); + do { + + list_del(&page->list); + + if (page->protected_ext_info) { + if (destroy_protected_ext_info(page->protected_ext_info) != 0) + pr_err("[%s] destroy_protected_ext_info return ERROR! (base=0x%08lx, size=0x%lx, flags=0x%lx)\n", __func__, + page->common.base, page->common.size, page->common.flags); + page->protected_ext_info = NULL; + } + + if (rtk_flag_is_protected(pool->common.rtk_flags) + && ion_flag_is_protected(page->common.flags)) + ion_cma_pool_refresh_protected_range(pool, page); + else + cma_release(pool->cpool, page->page, + page->common.size >> PAGE_SHIFT); + + ion_cma_page_free(page); + break; + } while (0); + mutex_unlock(&pool->lock); +} + +static struct sg_table *ion_cma_page_get_sg_table(struct page_info *page_info) +{ + struct cma_page_info *page = + container_of(page_info, struct cma_page_info, common); + return page->sg_table; +} + +static void ion_cma_pool_refresh_protected_range(struct cma_pool_info *pool, + struct cma_page_info *cma_page) +{ + struct cma *cma = pool->cpool; + { + /* release to protected_reserved_bitmap */ + unsigned long pfn = page_to_pfn(cma_page->page); + unsigned long bitmap_no = + (pfn - cma->base_pfn) >> cma->order_per_bit; + unsigned long bitmap_count = + ALIGN(cma_page->common.size >> PAGE_SHIFT, + 1UL << cma->order_per_bit) >> cma->order_per_bit; + bitmap_clear(pool->protected_reserved_bitmap, bitmap_no, + bitmap_count); + } + + if (rtk_flag_is_protected_dynamic(pool->common.rtk_flags)) { + int bitmap_count = cma_bitmap_maxno(cma); + unsigned long bitmap_offset = + find_first_zero_bit(pool->protected_reserved_bitmap, + bitmap_count); + + while (bitmap_offset < bitmap_count) { + struct RTK_PROTECTED_INFO *protected_info, + *tmp_protected_info; + unsigned long bitmap_limit = + find_next_bit(pool->protected_reserved_bitmap, + bitmap_count, bitmap_offset + 1); + unsigned long bitmap_size = + bitmap_limit - bitmap_offset; + unsigned long pfn = + (bitmap_offset << cma->order_per_bit) + + cma->base_pfn; + struct page *page = pfn_to_page(pfn); + unsigned long phyAddr = page_to_phys(page); + size_t size = bitmap_size << PAGE_SHIFT; + list_for_each_entry_safe(protected_info, + tmp_protected_info, + &pool->protected_list, list) { + if (phyAddr == + get_protected_base(protected_info)) { + if (size == + get_protected_size(protected_info)) + { + struct + ion_rtk_protected_destroy_info + info; + info.priv_virt = + get_protected_priv + (protected_info); + if (ion_rtk_protected_destroy_notify(&info) != NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_destroy_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + continue; + } + bitmap_set + (pool-> + protected_reserved_bitmap, + bitmap_offset, + bitmap_size); + cma_release(cma, page, + bitmap_size); + list_del(&protected_info->list); + kfree(protected_info); + } else { + unsigned long + next_protected_base = + get_protected_base + (protected_info) + size; + unsigned long + next_protected_limit = + get_protected_limit + (protected_info); + struct + ion_rtk_protected_change_info + info; + info.mem.base = + next_protected_base; + info.mem.size = + next_protected_limit - + next_protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + info.priv_virt = + get_protected_priv + (protected_info); + if (ion_rtk_protected_change_notify(&info) != NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + continue; + } + bitmap_set + (pool-> + protected_reserved_bitmap, + bitmap_offset, + bitmap_size); + cma_release(cma, page, + bitmap_size); + set_protected_range + (protected_info, + next_protected_base, + next_protected_limit); + } + } else if ((phyAddr + size) == + get_protected_limit(protected_info)) + { + unsigned long next_protected_base = + get_protected_base(protected_info); + unsigned long next_protected_limit = + get_protected_limit(protected_info) + - size; + struct ion_rtk_protected_change_info + info; + info.mem.base = next_protected_base; + info.mem.size = + next_protected_limit - + next_protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + info.priv_virt = + get_protected_priv(protected_info); + if (ion_rtk_protected_change_notify + (&info) != NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + continue; + } + bitmap_set + (pool->protected_reserved_bitmap, + bitmap_offset, bitmap_size); + cma_release(cma, page, bitmap_size); + set_protected_range(protected_info, + next_protected_base, + next_protected_limit); + } + } /* End of list_for_each_entry_safe(protected_info... */ + bitmap_offset = + find_next_zero_bit(pool->protected_reserved_bitmap, + bitmap_count, bitmap_limit + 1); + } /* End of while (bitmap_offset < bitmap_count) { */ + } +} + +static size_t ion_cma_free_pages(struct cma_pool_info *pool) +{ + size_t ret = 0; + struct cma *cma = pool->cpool; + mutex_lock(&cma->lock); + do { + unsigned long start = 0; + unsigned long nr_total = 0; + unsigned long nbits = cma_bitmap_maxno(cma); + for (;;) { + unsigned long next_zero_bit, next_set_bit, nr_zero, + nr_part; + next_zero_bit = + find_next_zero_bit(cma->bitmap, nbits, start); + if (next_zero_bit >= nbits) + break; + next_set_bit = + find_next_bit(cma->bitmap, nbits, next_zero_bit); + nr_zero = next_set_bit - next_zero_bit; + nr_part = nr_zero << cma->order_per_bit; + nr_total += nr_part; + start = next_zero_bit + nr_zero; + } + + ret = nr_total; + } while (0); + mutex_unlock(&cma->lock); + return ret; +} + +static size_t ion_protected_free_pages(struct cma_pool_info *pool) +{ + size_t ret = 0; + struct cma *cma = pool->cpool; + mutex_lock(&cma->lock); + do { + unsigned long start = 0; + unsigned long nr_total = 0; + unsigned long nbits = cma_bitmap_maxno(cma); + + if (!rtk_flag_is_protected(pool->common.rtk_flags)) + break; + + for (;;) { + unsigned long next_zero_bit, next_set_bit, nr_zero, + nr_part; + next_zero_bit = + find_next_zero_bit(pool->protected_reserved_bitmap, + nbits, start); + if (next_zero_bit >= nbits) + break; + next_set_bit = + find_next_bit(pool->protected_reserved_bitmap, + nbits, next_zero_bit); + nr_zero = next_set_bit - next_zero_bit; + nr_part = nr_zero << cma->order_per_bit; + nr_total += nr_part; + start = next_zero_bit + nr_zero; + } + + ret = nr_total; + } while (0); + mutex_unlock(&cma->lock); + return ret; +} + +size_t ion_cma_pool_getSpace(struct pool_info * pool_info, unsigned long flags) +{ + size_t ret = 0; + struct cma_pool_info *pool = + container_of(pool_info, struct cma_pool_info, common); + mutex_lock(&pool->lock); + do { + if (ion_flag_mismatch_pool_condition + (flags, pool->common.rtk_flags)) + break; + + ret = ion_cma_free_pages(pool) << PAGE_SHIFT; + + if (ion_flag_is_protected(flags)) + ret += ion_protected_free_pages(pool) << PAGE_SHIFT; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +size_t ion_cma_pool_getUsage(struct pool_info * pool_info, unsigned long flags) +{ + size_t ret = 0; + struct cma_pool_info *pool = + container_of(pool_info, struct cma_pool_info, common); + mutex_lock(&pool->lock); + do { + if (ion_flag_mismatch_pool_condition + (flags, pool->common.rtk_flags)) + break; + + ret = + (pool->cpool->count - + ion_cma_free_pages(pool)) << PAGE_SHIFT; + + ret -= ion_protected_free_pages(pool) << PAGE_SHIFT; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +int ion_cma_pool_debug_show(struct pool_info *pool_info, struct seq_buf *s, + char *prefix) +{ + int ret = -1; + struct cma_pool_info *pool = + container_of(pool_info, struct cma_pool_info, common); + struct cma *cma = pool->cpool; + if (!prefix) + prefix = ""; + mutex_lock(&pool->lock); + pool_common_debug_show(pool_info, s, prefix); + do { + char *space_prefix = " "; + char *sub_prefix = + kzalloc(strlen(prefix) + strlen(space_prefix), GFP_KERNEL); + if (!sub_prefix) + break; + strcpy(sub_prefix, prefix); + strcat(sub_prefix, space_prefix); + { + struct cma_page_info *info; + list_for_each_entry(info, &pool->pages, list) { + if (info) + page_common_debug_show(&info->common, s, + sub_prefix); + } + } + { + seq_buf_printf(s, "%sFree pages : %zu\n", sub_prefix, + ion_cma_free_pages(pool)); + if (rtk_flag_is_protected(pool->common.rtk_flags)) { + seq_buf_printf(s, "%sProtected Free pages : %zu\n", + sub_prefix, + ion_protected_free_pages(pool)); + } + mutex_lock(&cma->lock); + seq_buf_printf(s, "%sBitmap : ", sub_prefix); + bitmap_seq_printf(s, + cma->bitmap, (int) + cma_bitmap_maxno + (pool->cpool)); + seq_buf_printf(s, "\n"); + mutex_unlock(&cma->lock); + + if (rtk_flag_is_protected(pool_info->rtk_flags)) { + int protected_count = 0; + struct RTK_PROTECTED_INFO *protected_info; + list_for_each_entry(protected_info, + &pool->protected_list, + list) { + if (protected_info) + protected_count++; + } + seq_buf_printf(s, + "%sNumber of protection areas : %d\n", + sub_prefix, protected_count); + seq_buf_printf(s, + "%sUnreserved protection bitmap : ", + sub_prefix); + bitmap_seq_printf(s, + pool->protected_reserved_bitmap, + (int) + cma_bitmap_maxno + (pool->cpool)); + seq_buf_printf(s, "\n"); + protected_count = 0; + list_for_each_entry(protected_info, + &pool->protected_list, + list) { + if (protected_info) { + seq_buf_printf(s, + "%sprotected[%d] : 0x%08lX~0x%08lX\n", + sub_prefix, + protected_count, + get_protected_base + (protected_info), + get_protected_limit + (protected_info)); + protected_count++; + } + } + } + } + kfree(sub_prefix); + ret = 0; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +#ifdef CONFIG_VIRTUAL_PMU + +/* + * ref. from int ion_cma_pool_debug_show(..) + */ +unsigned long long ion_cma_pool_get_size(struct pool_info *pool_info) +{ + size_t pool_pages_size; + struct cma_pool_info *pool = + container_of(pool_info, struct cma_pool_info, common); + struct cma_page_info *info; + + pool_pages_size = 0; + + info = NULL; + + mutex_lock(&pool->lock); + + list_for_each_entry(info, &pool->pages, list) { + if (info) { + //page_common_debug_show(&info->common, s, + // sub_prefix); + pool_pages_size += info->common.size; + } + } + + mutex_unlock(&pool->lock); + + return (unsigned long long)pool_pages_size; +} + +#endif diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_common.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_common.c new file mode 100644 index 000000000000..6bbe415d70f0 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_common.c @@ -0,0 +1,205 @@ +#include "pool.h" +#include +#include + +static u64 dma_mask; + +void page_common_init(struct page_info *info, unsigned long base, size_t size, + unsigned long flags) +{ + + struct task_struct *task; + pid_t pid, tgid; + char task_comm[TASK_COMM_LEN]; + + get_task_struct(current->group_leader); + + task_lock(current->group_leader); + pid = task_pid_nr(current->group_leader); + tgid = task_tgid_nr(current->group_leader); + if (current->group_leader->flags & PF_KTHREAD) + task = NULL; + else + task = current->group_leader; + task_unlock(current->group_leader); + + if (task) + get_task_comm(task_comm, task); + else + strncpy(task_comm, "KTHREAD", sizeof(task_comm)); + + /* decrease usage count */ + put_task_struct(current->group_leader); + + memset(info, 0, sizeof(struct pool_info)); + info->base = base; + info->size = size; + info->flags = flags; + info->pid = pid; + info->tgid = tgid; + strncpy(info->task_comm, task_comm, sizeof(info->task_comm)); +} + +void page_common_sync(struct device *dev, struct page_info *page_info, enum dma_data_direction dir) +{ + struct sg_table *sg_table = page_info->get_sg_table(page_info); + int nents; + + if (!ion_flag_canAccess(page_info->flags)) { + pr_err + ("%s : can not access [base=0x%08lx, size=%zu, flags=0x%lx]", + __func__, page_info->base, page_info->size, + page_info->flags); + return; + } + + dma_mask = 0xffffffff; + dev->dma_mask = &dma_mask; + nents = dma_map_sg(dev, sg_table->sgl, sg_table->nents, dir); + dma_sync_sg_for_device(dev, sg_table->sgl, sg_table->nents, dir); + if (nents > 0) + dma_unmap_sg(dev, sg_table->sgl, sg_table->nents, dir); +} + +void page_common_sync_range(struct device *dev, struct page_info *page_info, + enum dma_data_direction dir, unsigned long addr, + size_t size) +{ + struct sg_table *sg_table = page_info->get_sg_table(page_info); + int nents; + + if (!ion_flag_canAccess(page_info->flags)) { + pr_err + ("%s : can not access [base=0x%08lx, size=%zu, flags=0x%lx]", + __func__, page_info->base, page_info->size, + page_info->flags); + return; + } + + if (addr < page_info->base + || (addr + size) > (page_info->base + page_info->size)) { + pr_err + ("%s : range(0x%08lx, %zu) is mismatch! [base=0x%08lx, size=%zu, flags=0x%lx]", + __func__, addr, size, page_info->base, page_info->size, + page_info->flags); + return; + } + + dma_mask = 0xffffffff; + dev->dma_mask = &dma_mask; + nents = dma_map_sg(dev, sg_table->sgl, sg_table->nents, dir); + dma_sync_single_for_device(dev, addr, size, dir); + if (nents > 0) + dma_unmap_sg(dev, sg_table->sgl, sg_table->nents, dir); +} + +void pool_common_init(struct pool_info *info, enum pool_type type, + unsigned long base, size_t size, unsigned long rtk_flags) +{ + memset(info, 0, sizeof(struct pool_info)); + INIT_LIST_HEAD(&info->list); + info->type = type; + info->base = base; + info->size = size; + info->rtk_flags = rtk_flags; +} + +void page_common_debug_show(struct page_info *page_info, + struct seq_buf *s, char *prefix) +{ + if (!prefix) + prefix = ""; + + if (!s || !page_info) + return; + + seq_buf_printf(s, + "%s%-16s : flags=%08lx | %08lx ~ %08lx | %11zu\t", + prefix, &page_info->task_comm[0], page_info->flags, + page_info->base, page_info->base + page_info->size - 1, + page_info->size); + + seq_buf_printf_ion_flags(s, page_info->flags); + + seq_buf_printf(s, "\n"); +} + +void seq_buf_printf_ion_flags(struct seq_buf *s, unsigned long flags) +{ + if (flags & ION_FLAG_CACHED) + seq_buf_printf(s, " CACHED"); + if (flags & ION_FLAG_CACHED_NEEDS_SYNC) + seq_buf_printf(s, " CACHED_NEEDS_SYNC"); + if (flags & ION_FLAG_NONCACHED) + seq_buf_printf(s, " NONCACHED"); + if (flags & ION_FLAG_SCPUACC) + seq_buf_printf(s, " SCPUACC"); + if (flags & ION_FLAG_ACPUACC) + seq_buf_printf(s, " ACPUACC"); + if (flags & ION_FLAG_HWIPACC) + seq_buf_printf(s, " HWIPACC"); + if (flags & ION_FLAG_VE_SPEC) + seq_buf_printf(s, " VE"); + if (flags & ION_FLAG_PROTECTED_MASK) + seq_buf_printf(s, " PROTECTED(%d)", + ION_PROTECTED_TYPE_GET(flags)); + if (flags & ION_FLAG_VCPU_FWACC) + seq_buf_printf(s, " VFWACC"); + if (flags & ION_FLAG_CMA) + seq_buf_printf(s, " CMA"); + if (flags & ION_USAGE_PROTECTED) + seq_buf_printf(s, " USAGE_PROTECTED"); + if (flags & ION_USAGE_MMAP_NONCACHED) + seq_buf_printf(s, " USAGE_MMAP_NONCACHED"); + if (flags & ION_USAGE_MMAP_CACHED) + seq_buf_printf(s, " USAGE_MMAP_CACHED"); + if (flags & ION_USAGE_MMAP_WRITECOMBINE) + seq_buf_printf(s, " USAGE_MMAP_WRITECOMBINE"); + if (flags & ION_USAGE_ALGO_LAST_FIT) + seq_buf_printf(s, " USAGE_ALGO_LAST_FIT"); + if (flags & ION_FLAG_PROTECTED_EXT_MASK) + seq_buf_printf(s, " PROTECTED_EXT(%d)", + ION_PROTECTED_EXT_GET(flags)); +} + +void pool_common_debug_show(struct pool_info *pool_info, + struct seq_buf *s, char *prefix) +{ + if (!prefix) + prefix = ""; + + if (!s || !pool_info) + return; + + seq_buf_printf(s, + "%s[%s] base=0x%08lx size=%zu(0x%zx) rtk_flags=%lx\t", + prefix, + (pool_info->type == GEN_POOL) ? "GEN" : + (pool_info->type == CMA_POOL) ? "CMA" : + (pool_info->type == PREALLOC_POOL) ? "PREALLOC" : + "ERR", + pool_info->base, pool_info->size, pool_info->size, + pool_info->rtk_flags); + + if (pool_info->rtk_flags & RTK_FLAG_SCPUACC) + seq_buf_printf(s, " SCPUACC"); + if (pool_info->rtk_flags & RTK_FLAG_ACPUACC) + seq_buf_printf(s, " ACPUACC"); + if (pool_info->rtk_flags & RTK_FLAG_HWIPACC) + seq_buf_printf(s, " HWIPACC"); + if (pool_info->rtk_flags & RTK_FLAG_VE_SPEC) + seq_buf_printf(s, " VE"); + if (pool_info->rtk_flags & RTK_FLAG_PROTECTED_MASK) + seq_buf_printf(s, " PROTECTED(%d)", + RTK_PROTECTED_TYPE_GET(pool_info->rtk_flags)); + if (pool_info->rtk_flags & RTK_FLAG_PROTECTED_DYNAMIC) + seq_buf_printf(s, " PROTECTED_DYNAMIC"); + if (pool_info->rtk_flags & RTK_FLAG_VCPU_FWACC) + seq_buf_printf(s, " VFWACC"); + if (pool_info->rtk_flags & RTK_FLAG_CMA) + seq_buf_printf(s, " CMA"); + if (pool_info->rtk_flags & RTK_FLAG_PROTECTED_EXT_MASK) + seq_buf_printf(s, " PROTECTED_EXT(%d)", + RTK_PROTECTED_EXT_GET(pool_info->rtk_flags)); + seq_buf_printf(s, "\n"); +} diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_gen.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_gen.c new file mode 100644 index 000000000000..7a1a08c4dcdb --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/pool_gen.c @@ -0,0 +1,819 @@ +#include "pool.h" +#include "protected.h" +#include +#include +#include + +static u64 dma_mask; + +enum rtk_algo_mode { + ALGO_FIRST_FIT = 0, + ALGO_LAST_FIT, +}; + +struct gen_pool_info { + struct pool_info common; + struct gen_pool *gpool; + enum rtk_algo_mode algo_mode; + struct mutex lock; + struct list_head pages; + struct RTK_PROTECTED_INFO protected_info; +}; + +struct gen_page_info { + struct page_info common; + struct gen_pool_info *parent; + struct list_head list; + struct sg_table *sg_table; + struct RTK_PROTECTED_EXT_INFO * protected_ext_info; +}; + +/* public api */ +struct pool_info *ion_gen_pool_create(enum pool_type type, + unsigned long base, + size_t size, + unsigned long rtk_flags, + bool from_reserved_memory, + struct device *dev); +static struct page_info *ion_gen_pool_alloc(struct pool_info *pool_info, + unsigned long size, + unsigned long align, + unsigned long flags); +static size_t ion_gen_pool_getSpace(struct pool_info *pool_info, + unsigned long flags); +static size_t ion_gen_pool_getUsage(struct pool_info *pool_info, + unsigned long flags); +static int ion_gen_pool_debug_show(struct pool_info *pool_info, + struct seq_buf *, char *); +static void ion_gen_pool_destroy(struct pool_info *pool_info); +static void ion_gen_page_destroy(struct page_info *page_info); +static struct sg_table *ion_gen_page_get_sg_table(struct page_info *page_info); + +/* private func */ +static struct gen_page_info *ion_gen_page_alloc(void); +static void ion_gen_page_free(struct gen_page_info *page); +static void ion_gen_page_info_init(struct gen_page_info *page, + unsigned long base, size_t size, + unsigned long flags, + unsigned long rtk_flags); +static bool ion_gen_pool_check_region_is_safe(struct gen_pool_info *pool, + bool protected, + unsigned long base, size_t size); +static void ion_gen_pool_refresh_protected_range(struct gen_pool_info *pool); +static unsigned long ion_gen_pool_algo_last_fit(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, void *data); +static unsigned long ion_gen_pool_algo(unsigned long *map, unsigned long size, + unsigned long start, unsigned int nr, + void *data, struct gen_pool *pool, + unsigned long start_addr); +static void ion_pages_sync_for_device(struct device *dev, struct page *page, + size_t size, enum dma_data_direction dir); +static size_t ion_gen_pool_pages_size(struct gen_pool_info *pool, + unsigned long flags); + +static inline bool mem_is_within_range(unsigned long offset, size_t size, + unsigned long base, unsigned long limit) +{ + if (offset >= base && (offset + size) <= limit) + return true; + return false; +} + +inline bool mem_is_some_overlap(unsigned long offset, size_t size, + unsigned long base, unsigned long limit) +{ + if (offset <= base && (offset + size) > base) + return true; + if (offset < limit && (offset + size) > limit) + return true; + return false; +} + +inline bool mem_is_overlap_range(unsigned long offset, size_t size, + unsigned long base, unsigned long limit) +{ + if (mem_is_within_range(offset, size, base, limit)) + return true; + if (mem_is_some_overlap(offset, size, base, limit)) + return true; + return false; +} + +struct pool_info *ion_gen_pool_create(enum pool_type type, + unsigned long base, + size_t size, + unsigned long rtk_flags, + bool from_reserved_memory, + struct device *dev) +{ + struct pool_info *ret = NULL; + + do { + struct gen_pool_info *pool; + struct pool_info *common; + + pool = (struct gen_pool_info *) kzalloc(sizeof(struct gen_pool_info), GFP_KERNEL); + + if (!pool) + break; + + common = &pool->common; + + init_protected_info(&pool->protected_info); + INIT_LIST_HEAD(&pool->pages); + mutex_init(&pool->lock); + + if (rtk_flag_is_protected_static(rtk_flags)) { + if (from_reserved_memory) { + struct ion_rtk_protected_create_info info; + info.mem.base = base; + info.mem.size = size; + info.mem.type = + rtk_flags_to_notifier_protected_type(rtk_flags); + if (ion_rtk_protected_create_notify(&info) != NOTIFY_OK) { + pr_err("%s : Protected area creation failed! (rtk_flags = 0x%lx)\n", + __func__, rtk_flags); + rtk_flags &= + ~(RTK_FLAG_PROTECTED_DYNAMIC | + RTK_FLAG_PROTECTED_MASK); + } + } + } + + if (rtk_flag_is_protected_static(rtk_flags)) { + set_protected_range(&pool->protected_info, + base, base+size); + } + + pool_common_init(common, type, base, size, rtk_flags); + common->alloc = ion_gen_pool_alloc; + common->getSpace = ion_gen_pool_getSpace; + common->getUsage = ion_gen_pool_getUsage; + common->debug_show = ion_gen_pool_debug_show; + common->destroy = ion_gen_pool_destroy; + + pool->gpool = gen_pool_create(PAGE_SHIFT, -1); + if (!pool->gpool) { + kfree(pool); + break; + } + + if (rtk_flag_canAccess(rtk_flags)) { + struct page *page = pfn_to_page(PFN_DOWN(base)); + ion_pages_sync_for_device(dev, page, size, DMA_BIDIRECTIONAL); + ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL)); + } + + gen_pool_set_algo(pool->gpool, ion_gen_pool_algo, (void *)pool); + gen_pool_add(pool->gpool, base, size, -1); + + ret = common; + break; + } while (0); + return ret; +} + +static void ion_gen_pool_destroy(struct pool_info *pool_info) +{ + struct gen_pool_info *pool = + container_of(pool_info, struct gen_pool_info, common); + if (!pool) + return; + + mutex_lock(&pool->lock); + do { + struct gen_page_info *page_info, *tmp_page_info; + list_for_each_entry_safe(page_info, tmp_page_info, &pool->pages, + list) { + // TODO ADD LOG + list_del(&page_info->list); + ion_gen_page_free(page_info); + } + + gen_pool_destroy(pool->gpool); + + ion_gen_pool_refresh_protected_range(pool); + } while (0); + mutex_unlock(&pool->lock); + mutex_destroy(&pool->lock); + kfree(pool); +} + +static struct page_info *ion_gen_pool_alloc(struct pool_info *pool_info, + unsigned long size, + unsigned long align, + unsigned long flags) +{ + struct page_info *ret = NULL; + struct gen_pool_info *pool = + container_of(pool_info, struct gen_pool_info, common); + struct pool_info *common = &pool->common; + mutex_lock(&pool->lock); + do { + struct gen_page_info *page = NULL; + unsigned long offset = 0; + + if (ion_flag_mismatch_pool_condition(flags, common->rtk_flags)) + break; + + page = ion_gen_page_alloc(); + if (!page) + break; + + if (rtk_flag_is_protected_dynamic(common->rtk_flags)) { + if (ion_flag_is_protected(flags)) + pool->algo_mode = ALGO_LAST_FIT; + else + pool->algo_mode = ALGO_FIRST_FIT; + } else { + if (ion_flag_is_algo_last_fit(flags)) + pool->algo_mode = ALGO_LAST_FIT; + else + pool->algo_mode = ALGO_FIRST_FIT; + } + + offset = gen_pool_alloc(pool->gpool, size); + if (offset == 0) { + ion_gen_page_free(page); + break; + } + + if (rtk_flag_is_protected_dynamic(common->rtk_flags)) { + if (!ion_gen_pool_check_region_is_safe + (pool, ion_flag_is_protected(flags), offset, + size)) { + gen_pool_free(pool->gpool, offset, size); + ion_gen_page_free(page); + break; + } + } + + if (rtk_flag_is_protected(common->rtk_flags) && + !rtk_flag_has_protected_ext(common->rtk_flags) && + ion_flag_has_protected_ext(flags)) { + + page->protected_ext_info = create_protected_ext_info( + ion_flag_to_notifier_protected_ext(flags), + offset, size, + &pool->protected_info); + + if (!page->protected_ext_info) { + gen_pool_free(pool->gpool, offset, size); + ion_gen_page_free(page); + break; + } + } + + ion_gen_page_info_init(page, offset, size, flags, + common->rtk_flags); + + list_add(&page->list, &pool->pages); + page->parent = pool; + + ret = &page->common; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +static unsigned long ion_gen_pool_algo_last_fit(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, void *data) +{ + unsigned long start_bit = size; + unsigned long index = size; + + if (start_bit <= nr) + return index; + + do { + if (start_bit > nr) { + unsigned long start_bit_next = start_bit; + start_bit_next -= nr; + start_bit_next = + find_next_bit(map, size, start_bit_next) - nr; + if (start_bit_next >= start_bit) { + pr_err + ("[%s:%d] Warning! start_bit=%ld start_bit_next=%ld size=%ld nr=%d\n", + __func__, __LINE__, start_bit, + start_bit_next, size, nr); + break; + } + start_bit = start_bit_next; + } else + start_bit -= 1; + + index = bitmap_find_next_zero_area(map, size, start_bit, nr, 0); + + if (start_bit <= 0) + break; + + } while (index >= size); + + return index; +} + +static unsigned long ion_gen_pool_algo(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, + void *data, + struct gen_pool *pool, + unsigned long start_addr) +{ + struct gen_pool_info *pool_t = (struct gen_pool_info *)data; + + if (pool_t) { + switch (pool_t->algo_mode) { + case ALGO_FIRST_FIT: + return gen_pool_first_fit(map, size, start, nr, data, + NULL, 0); + case ALGO_LAST_FIT: + return ion_gen_pool_algo_last_fit(map, size, start, nr, + data); + default: + break; + } + } + + pr_err("[%s] Warning: pool_t=%p", __func__, pool_t); + if (pool_t != NULL) + pr_err(" algo_mode=0x%x", pool_t->algo_mode); + pr_err(" size=%ld start=%ld, nr=%d\n", size, start, nr); + return gen_pool_first_fit(map, size, start, nr, data, NULL, 0); +} + +static void ion_gen_page_destroy(struct page_info *page_info) +{ + struct gen_page_info *page = + container_of(page_info, struct gen_page_info, common); + struct gen_pool_info *pool = page->parent; + mutex_lock(&pool->lock); + do { + list_del(&page->list); + + if (page->protected_ext_info) { + if (destroy_protected_ext_info(page->protected_ext_info) != 0) + pr_err("[%s] ion_rtk_protected_ext_unset_notify return ERROR! (base=0x%08lx, size=0x%lx, flags=0x%lx)\n", __func__, + page->common.base, page->common.size, page->common.flags); + page->protected_ext_info = NULL; + } + + if (rtk_flag_is_protected_dynamic(pool->common.rtk_flags) && + ion_flag_is_protected(page->common.flags)) + ion_gen_pool_refresh_protected_range(pool); + + gen_pool_free(pool->gpool, page->common.base, + page->common.size); + + ion_gen_page_free(page); + break; + } while (0); + mutex_unlock(&pool->lock); +} + +static struct sg_table *ion_gen_page_get_sg_table(struct page_info *page_info) +{ + struct gen_page_info *page = + container_of(page_info, struct gen_page_info, common); + return page->sg_table; +} + +static size_t ion_gen_pool_pages_size(struct gen_pool_info *pool, + unsigned long flags) +{ + size_t ret = 0; + struct gen_page_info *info; + list_for_each_entry(info, &pool->pages, list) { + if (info && ion_flag_match_condition(flags, info->common.flags)) + ret += info->common.size; + } + return ret; +} + +static size_t ion_gen_pool_getSpace(struct pool_info *pool_info, + unsigned long flags) +{ + size_t ret = 0; + struct gen_pool_info *pool = + container_of(pool_info, struct gen_pool_info, common); + mutex_lock(&pool->lock); + do { + if (ion_flag_mismatch_pool_condition + (flags, pool->common.rtk_flags)) + break; + + ret = pool->common.size; + ret -= ion_gen_pool_pages_size(pool, 0); + break; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +static size_t ion_gen_pool_getUsage(struct pool_info *pool_info, + unsigned long flags) +{ + size_t ret = 0; + struct gen_pool_info *pool = + container_of(pool_info, struct gen_pool_info, common); + mutex_lock(&pool->lock); + do { + if (ion_flag_mismatch_pool_condition + (flags, pool->common.rtk_flags)) + break; + + ret = ion_gen_pool_pages_size(pool, flags); + break; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +static int ion_gen_pool_debug_show(struct pool_info *pool_info, + struct seq_buf *s, char *prefix) +{ + int ret = 0; + struct gen_pool_info *pool = + container_of(pool_info, struct gen_pool_info, common); + if (!prefix) + prefix = ""; + mutex_lock(&pool->lock); + pool_common_debug_show(pool_info, s, prefix); + seq_buf_printf(s, "%s Usage : %zu\n", prefix, + ion_gen_pool_pages_size(pool, 0)); + do { + char *space_prefix = " "; + char *sub_prefix = + kzalloc(strlen(prefix) + strlen(space_prefix), GFP_KERNEL); + if (!sub_prefix) + break; + strcpy(sub_prefix, prefix); + strcat(sub_prefix, space_prefix); + { + struct gen_page_info *info; + list_for_each_entry(info, &pool->pages, list) { + if (info) + page_common_debug_show(&info->common, s, + sub_prefix); + } + } + { + struct gen_page_info *info; + unsigned long slot_offset = pool->common.base; + size_t slot_size = 0; + unsigned long next_offset, close_offet; + seq_buf_printf(s, "%s+---------------------+\n", + sub_prefix); +FIND_NEXD: + next_offset = slot_offset + slot_size; + close_offet = pool->common.base + pool->common.size; + list_for_each_entry(info, &pool->pages, list) { + if (!info) + continue; + if (info->common.base == next_offset) { + slot_size += info->common.size; + goto FIND_NEXD; + } + if (info->common.base > next_offset + && info->common.base < close_offet) + close_offet = info->common.base; + } + + { + unsigned long next_search_offset; + if (slot_size) { + seq_buf_printf(s, + "%s| %08lx ~ %08lx | used %10zu\n", + sub_prefix, slot_offset, + slot_offset + slot_size - 1, + slot_size); + next_search_offset = + slot_offset + slot_size; + } else { + seq_buf_printf(s, + "%s| %08lx ~ %08lx | free %10zu\n", + sub_prefix, slot_offset, + close_offet - 1, + (size_t) close_offet - + slot_offset); + next_search_offset = close_offet; + } + + if (next_search_offset < + (pool->common.base + pool->common.size)) { + slot_offset = next_search_offset; + slot_size = 0; + goto FIND_NEXD; + } + } + seq_buf_printf(s, "%s+---------------------+\n", + sub_prefix); + } + + kfree(sub_prefix); + break; + } while (0); + mutex_unlock(&pool->lock); + return ret; +} + +static struct gen_page_info *ion_gen_page_alloc(void) +{ + struct gen_page_info *ret = NULL; + do { + struct gen_page_info *page = (struct gen_page_info *) + kzalloc(sizeof(struct gen_page_info), GFP_KERNEL); + if (!page) + break; + + page->sg_table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!page->sg_table) { + kfree(page); + break; + } + + if (sg_alloc_table(page->sg_table, 1, GFP_KERNEL) != 0) { + kfree(page->sg_table); + kfree(page); + break; + } + + ret = page; + } while (0); + return ret; +} + +static void ion_gen_page_free(struct gen_page_info *page) +{ + sg_free_table(page->sg_table); + kfree(page->sg_table); + kfree(page); +} + +static void ion_gen_page_info_init(struct gen_page_info *page, + unsigned long base, size_t size, + unsigned long flags, unsigned long rtk_flags) +{ + page_common_init(&page->common, base, size, + flags | ion_flag_from_rtk(rtk_flags)); + sg_set_page(page->sg_table->sgl, pfn_to_page(PFN_DOWN(base)), size, 0); + + { + size_t i; + struct scatterlist *sg; + for_each_sg(page->sg_table->sgl, sg, page->sg_table->nents, i) { + sg_dma_address(sg) = sg_phys(sg); + sg_dma_len(sg) = sg->length; + } + } + + page->common.destroy = ion_gen_page_destroy; + page->common.get_sg_table = ion_gen_page_get_sg_table; + page->common.sync_range = page_common_sync_range; + page->common.sync = page_common_sync; + INIT_LIST_HEAD(&page->list); + +} + +static bool ion_gen_pool_check_region_is_safe(struct gen_pool_info *pool, + bool protected, + unsigned long offset, size_t size) +{ + bool safe = false; + do { + struct RTK_PROTECTED_INFO *protected_info = + &pool->protected_info; + unsigned long protected_base = + get_protected_base(protected_info); + unsigned long protected_limit = + get_protected_limit(protected_info); + size_t protected_size = get_protected_size(protected_info); + + if (protected) { + if (mem_is_within_range + (offset, size, protected_base, protected_limit)) { + safe = true; + break; + } + + if (protected_size == 0) { + struct ion_rtk_protected_create_info info; + info.mem.base = offset; + info.mem.size = size; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + if (ion_rtk_protected_create_notify(&info) != + NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_create_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + break; + } + set_protected_range(protected_info, offset, + offset + size); + set_protected_priv(protected_info, + info.priv_virt); + safe = true; + break; + } else if (offset == protected_limit) { + unsigned long next_protected_limit = + offset + size; + struct ion_rtk_protected_change_info info; + info.mem.base = protected_base; + info.mem.size = + next_protected_limit - protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + info.priv_virt = + get_protected_priv(protected_info); + if (ion_rtk_protected_change_notify(&info) != + NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + break; + } + set_protected_range(protected_info, + protected_base, + next_protected_limit); + safe = true; + break; + } else if ((offset + size) == protected_base) { + unsigned long next_protected_base = offset; + struct ion_rtk_protected_change_info info; + info.mem.base = next_protected_base; + info.mem.size = + protected_limit - next_protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type + (pool->common.rtk_flags); + info.priv_virt = + get_protected_priv(protected_info); + if (ion_rtk_protected_change_notify(&info) != + NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv + (protected_info)); + break; + } + set_protected_range(protected_info, + next_protected_base, + protected_limit); + safe = true; + break; + } + + break; + } else { + if (!mem_is_overlap_range + (offset, size, protected_base, protected_limit)) { + safe = true; + break; + } + break; + } + + break; + } while (0); + return safe; +} + +static void ion_gen_pool_refresh_protected_range(struct gen_pool_info *pool) +{ + struct pool_info *pool_info = &pool->common; + do { + struct RTK_PROTECTED_INFO *protected_info = + &pool->protected_info; + unsigned long protected_base = + get_protected_base(protected_info); + unsigned long protected_limit = + get_protected_limit(protected_info); + size_t protected_size = get_protected_size(protected_info); + unsigned long next_protected_base = + pool_info->base + pool_info->size; + unsigned long next_protected_limit = pool_info->base; + int protected_count = 0; + + struct gen_page_info *page, *tmp_page; + + if (protected_size == 0) + break; + + list_for_each_entry_safe(page, tmp_page, &pool->pages, list) { + struct page_info *page_info = &page->common; + if (ion_flag_is_protected(page_info->flags)) { + unsigned long base = page_info->base; + unsigned long limit = + page_info->base + page_info->size; + if (next_protected_limit < limit) + next_protected_limit = limit; + if (next_protected_base > base) + next_protected_base = base; + protected_count++; + } + } + + if (protected_count == 0) { + struct ion_rtk_protected_destroy_info info; + info.priv_virt = get_protected_priv(protected_info); + if (ion_rtk_protected_destroy_notify(&info) != + NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_destroy_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv(protected_info)); + } + init_protected_info(protected_info); + break; + } + + if (next_protected_base != protected_base + || next_protected_limit != protected_limit) { + struct ion_rtk_protected_change_info info; + info.mem.base = next_protected_base; + info.mem.size = + next_protected_limit - next_protected_base; + info.mem.type = + rtk_flags_to_notifier_protected_type(pool->common. + rtk_flags); + info.priv_virt = get_protected_priv(protected_info); + if (ion_rtk_protected_change_notify(&info) != NOTIFY_OK) { + pr_err + ("%s:%d ion_rtk_protected_change_notify return ERROR! (priv_virt=%p)\n", + __func__, __LINE__, + get_protected_priv(protected_info)); + break; + } + set_protected_range(protected_info, next_protected_base, + next_protected_limit); + } + } while (0); +} + +void ion_pages_sync_for_device(struct device *dev, struct page *page, + size_t size, enum dma_data_direction dir) +{ + struct scatterlist sg; + int nents; + + sg_init_table(&sg, 1); + sg_set_page(&sg, page, size, 0); + /* + * This is not correct - sg_dma_address needs a dma_addr_t that is valid + * for the targeted device, but this works on the currently targeted + * hardware. + */ + sg_dma_address(&sg) = page_to_phys(page); + dma_mask = 0xffffffff; + dev->dma_mask = &dma_mask; + nents = dma_map_sg(dev, &sg, 1, dir); + dma_sync_sg_for_device(dev, &sg, 1, dir); + if (nents > 0) + dma_unmap_sg(dev, &sg, 1, dir); +} + +#ifdef CONFIG_VIRTUAL_PMU + +/* + * ref. from static int ion_gen_pool_debug_show( + */ +unsigned long long ion_gen_pool_get_size(struct pool_info *pool_info) +{ + size_t pool_pages_size; + struct gen_pool_info *pool = + container_of(pool_info, struct gen_pool_info, common); + struct gen_page_info *info; + + pool_pages_size = 0; + + info = NULL; + + mutex_lock(&pool->lock); + + //pool_pages_size = + // (unsigned long long) (ion_gen_pool_pages_size(pool, 0)); + list_for_each_entry(info, &pool->pages, list) { + //if (info && ion_flag_match_condition(0, info->common.flags)) + if (info) { + pool_pages_size += info->common.size; + } + } + + mutex_unlock(&pool->lock); + + return (unsigned long long)pool_pages_size; +} + +#endif diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/protected.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/protected.c new file mode 100644 index 000000000000..4fb4e2d58665 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/protected.c @@ -0,0 +1,172 @@ +#include "protected.h" +#include "linux/slab.h" + +static RAW_NOTIFIER_HEAD(protected_notifier_list); + +unsigned long get_protected_base(const struct RTK_PROTECTED_INFO *info) +{ + return info->mem.base; +} + +unsigned long get_protected_limit(const struct RTK_PROTECTED_INFO *info) +{ + return info->mem.base + info->mem.size; +} + +size_t get_protected_size(const struct RTK_PROTECTED_INFO * info) +{ + return info->mem.size; +} + +void *get_protected_priv(const struct RTK_PROTECTED_INFO *info) +{ + return info->priv_virt; +} + +void set_protected_range(struct RTK_PROTECTED_INFO *info, unsigned long base, + unsigned long limit) +{ + info->mem.base = base; + info->mem.size = limit - base; +} + +void set_protected_priv(struct RTK_PROTECTED_INFO *info, void *priv_virt) +{ + info->priv_virt = priv_virt; +} + +void init_protected_info(struct RTK_PROTECTED_INFO *info) +{ + memset((void *)info, 0, sizeof(struct RTK_PROTECTED_INFO)); + INIT_LIST_HEAD(&info->list); +} + +enum E_ION_NOTIFIER_PROTECTED_TYPE get_protected_type(const struct + RTK_PROTECTED_INFO *info) +{ + return info->mem.type; +} + +void set_protected_type(struct RTK_PROTECTED_INFO *info, + enum E_ION_NOTIFIER_PROTECTED_TYPE type) +{ + info->mem.type = type; +} + +void init_protected_ext_info(struct RTK_PROTECTED_EXT_INFO *info) +{ + memset((void *)info, 0, sizeof(struct RTK_PROTECTED_EXT_INFO)); +} + +void set_protected_ext_priv(struct RTK_PROTECTED_EXT_INFO *info, void *priv_virt) +{ + info->priv_virt = priv_virt; +} + +void *get_protected_ext_priv(struct RTK_PROTECTED_EXT_INFO *info) +{ + return info->priv_virt; +} + +void set_protected_ext_info(struct RTK_PROTECTED_EXT_INFO *info, enum E_ION_NOTIFIER_PROTECTED_EXT ext, + unsigned long base, unsigned long size, void * parent_priv) +{ + info->mem.ext = ext; + info->mem.base = base; + info->mem.size = size; + info->mem.parent_priv = parent_priv; +} + +struct RTK_PROTECTED_EXT_INFO * create_protected_ext_info(enum E_ION_NOTIFIER_PROTECTED_EXT ext, + unsigned long base, unsigned long size, struct RTK_PROTECTED_INFO * parent) +{ + struct RTK_PROTECTED_EXT_INFO * ret = NULL; + do { + struct ion_rtk_protected_ext_set config; + struct RTK_PROTECTED_EXT_INFO * ext_info = NULL; + ext_info = (struct RTK_PROTECTED_EXT_INFO *) kzalloc(sizeof(struct RTK_PROTECTED_EXT_INFO), GFP_KERNEL); + if (!ext_info) + break; + init_protected_ext_info(ext_info); + set_protected_ext_info(ext_info, ext, base, size, get_protected_priv(parent)); + memcpy(&config.mem, &ext_info->mem, sizeof(ext_info->mem)); + if (ion_rtk_protected_ext_set_notify(&config) != NOTIFY_OK) { + kfree(ext_info); + break; + } + set_protected_ext_priv(ext_info, config.priv_virt); + ret = ext_info; + } while (0); + return ret; +} + +int destroy_protected_ext_info(struct RTK_PROTECTED_EXT_INFO * info) +{ + int ret = -1; + do { + struct ion_rtk_protected_ext_unset config; + + if (!info) + break; + + config.priv_virt = get_protected_ext_priv(info); + if (ion_rtk_protected_ext_unset_notify(&config) != NOTIFY_OK) { + kfree(info); + break; + } + + kfree(info); + ret = 0; + } while(0); + return ret; +} + +int ion_rtk_protected_notifier_register(struct notifier_block *nb) +{ + return raw_notifier_chain_register(&protected_notifier_list, nb); +} + +EXPORT_SYMBOL(ion_rtk_protected_notifier_register); + +void ion_rtk_protected_notifier_unregister(struct notifier_block *nb) +{ + raw_notifier_chain_unregister(&protected_notifier_list, nb); +} + +EXPORT_SYMBOL(ion_rtk_protected_notifier_unregister); + +int ion_rtk_protected_create_notify(struct ion_rtk_protected_create_info *info) +{ + int ret = raw_notifier_call_chain(&protected_notifier_list, + PROTECTED_REGION_CREATE, info); + return ret; +} + +int ion_rtk_protected_change_notify(struct ion_rtk_protected_change_info *info) +{ + int ret = raw_notifier_call_chain(&protected_notifier_list, + PROTECTED_REGION_CHANGE, info); + return ret; +} + +int ion_rtk_protected_destroy_notify(struct ion_rtk_protected_destroy_info + *info) +{ + int ret = raw_notifier_call_chain(&protected_notifier_list, + PROTECTED_REGION_DESTROY, info); + return ret; +} + +int ion_rtk_protected_ext_set_notify(struct ion_rtk_protected_ext_set * config) +{ + int ret = raw_notifier_call_chain(&protected_notifier_list, + PROTECTED_REGION_EXTENSION_SET, config); + return ret; +} + +int ion_rtk_protected_ext_unset_notify(struct ion_rtk_protected_ext_unset * config) +{ + int ret = raw_notifier_call_chain(&protected_notifier_list, + PROTECTED_REGION_EXTENSION_UNSET, config); + return ret; +} diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/protected.h b/drivers/soc/realtek/common/mem_allocator/rtk/src/protected.h new file mode 100644 index 000000000000..c876bd4360bb --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/protected.h @@ -0,0 +1,50 @@ +#ifndef _LINUX_ION_RTK_CARVEOUT_HEAP_PROTECTED_H +#define _LINUX_ION_RTK_CARVEOUT_HEAP_PROTECTED_H + +#include +#include "../inc/ion_rtk_protected_notifier.h" + +struct RTK_PROTECTED_INFO { + struct protected_region mem; + struct list_head list; + void *priv_virt; +}; + +struct RTK_PROTECTED_EXT_INFO { + struct protected_ext_region mem; + void * priv_virt; +}; + +unsigned long get_protected_base(const struct RTK_PROTECTED_INFO *info); +unsigned long get_protected_limit(const struct RTK_PROTECTED_INFO *info); +size_t get_protected_size(const struct RTK_PROTECTED_INFO *info); +void *get_protected_priv(const struct RTK_PROTECTED_INFO *info); +void set_protected_range(struct RTK_PROTECTED_INFO *info, unsigned long base, + unsigned long limit); +void set_protected_priv(struct RTK_PROTECTED_INFO *info, void *priv_virt); +void init_protected_info(struct RTK_PROTECTED_INFO *info); + +enum E_ION_NOTIFIER_PROTECTED_TYPE get_protected_type(const struct + RTK_PROTECTED_INFO *info); +void set_protected_type(struct RTK_PROTECTED_INFO *info, + enum E_ION_NOTIFIER_PROTECTED_TYPE type); + +void init_protected_ext_info(struct RTK_PROTECTED_EXT_INFO *info); +void set_protected_ext_priv(struct RTK_PROTECTED_EXT_INFO *info, void *priv_virt); +void *get_protected_ext_priv(struct RTK_PROTECTED_EXT_INFO *info); +void set_protected_ext_info(struct RTK_PROTECTED_EXT_INFO *info, enum E_ION_NOTIFIER_PROTECTED_EXT ext, + unsigned long base, unsigned long size, void * parent_priv); + +struct RTK_PROTECTED_EXT_INFO * create_protected_ext_info(enum E_ION_NOTIFIER_PROTECTED_EXT ext, + unsigned long base, unsigned long size, struct RTK_PROTECTED_INFO * parent); + +int destroy_protected_ext_info(struct RTK_PROTECTED_EXT_INFO * info); + +int ion_rtk_protected_create_notify(struct ion_rtk_protected_create_info *info); +int ion_rtk_protected_change_notify(struct ion_rtk_protected_change_info *info); +int ion_rtk_protected_destroy_notify(struct ion_rtk_protected_destroy_info + *info); +int ion_rtk_protected_ext_set_notify(struct ion_rtk_protected_ext_set * config); +int ion_rtk_protected_ext_unset_notify(struct ion_rtk_protected_ext_unset * config); + +#endif /* _LINUX_ION_RTK_CARVEOUT_HEAP_PROTECTED_H */ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/src/sys_heap.c b/drivers/soc/realtek/common/mem_allocator/rtk/src/sys_heap.c new file mode 100644 index 000000000000..745f8e35d1e9 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/src/sys_heap.c @@ -0,0 +1,403 @@ +/* ion_rtk_sys_heap.c + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ion_old/ion.h" +#include "uapi_old/ion.h" +#include "uapi_old/ion_rtk.h" + +static const unsigned int orders[] = { 8, 4, 0 }; + +#define NUM_ORDERS ARRAY_SIZE(orders) + +static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN | + __GFP_NORETRY) & ~__GFP_RECLAIM; +static gfp_t low_order_gfp_flags = GFP_HIGHUSER | __GFP_ZERO; + +static int order_to_index(unsigned int order) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) + if (order == orders[i]) + return i; + BUG(); + return -1; +} + +static inline unsigned int order_to_size(int order) +{ + return PAGE_SIZE << order; +} + +struct rtk_ion_sys_heap { + struct ion_heap heap; + struct ion_page_pool *uncached_pools[NUM_ORDERS]; + struct ion_page_pool *cached_pools[NUM_ORDERS]; +}; + +/** + * The page from page-pool are all zeroed before. We need do cache + * clean for cached buffer. The uncached buffer are always non-cached + * since it's allocated. So no need for non-cached pages. + */ +static struct page *alloc_buffer_page(struct rtk_ion_sys_heap *heap, + struct ion_buffer *buffer, + unsigned long order) +{ + bool cached = ion_buffer_cached(buffer); + struct ion_page_pool *pool; + struct page *page; + + if (!cached) + pool = heap->uncached_pools[order_to_index(order)]; + else + pool = heap->cached_pools[order_to_index(order)]; + + page = ion_page_pool_alloc(pool); + + return page; +} + +static void free_buffer_page(struct rtk_ion_sys_heap *heap, + struct ion_buffer *buffer, struct page *page) +{ + struct ion_page_pool *pool; + unsigned int order = compound_order(page); + bool cached = ion_buffer_cached(buffer); + + /* go to system */ + if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) { + __free_pages(page, order); + return; + } + + if (!cached) + pool = heap->uncached_pools[order_to_index(order)]; + else + pool = heap->cached_pools[order_to_index(order)]; + + ion_page_pool_free(pool, page); +} + +static struct page *alloc_largest_available(struct rtk_ion_sys_heap *heap, + struct ion_buffer *buffer, + unsigned long size, + unsigned int max_order) +{ + struct page *page; + int i; + + for (i = 0; i < NUM_ORDERS; i++) { + if (size < order_to_size(orders[i])) + continue; + if (max_order < orders[i]) + continue; + + page = alloc_buffer_page(heap, buffer, orders[i]); + if (!page) + continue; + + return page; + } + + return NULL; +} + +static int rtk_ion_sys_heap_allocate(struct ion_heap *heap, + struct ion_buffer *buffer, + unsigned long size, unsigned long flags) +{ + struct rtk_ion_sys_heap *sys_heap = container_of(heap, + struct + rtk_ion_sys_heap, + heap); + struct sg_table *table; + struct scatterlist *sg; + struct list_head pages; + struct page *page, *tmp_page; + int i = 0; + unsigned long size_remaining = PAGE_ALIGN(size); + unsigned int max_order = orders[0]; + + if (size / PAGE_SIZE > totalram_pages / 2) + return -ENOMEM; + + buffer->flags |= ION_FLAG_CACHED; + + INIT_LIST_HEAD(&pages); + while (size_remaining > 0) { + page = alloc_largest_available(sys_heap, buffer, size_remaining, + max_order); + if (!page) + goto free_pages; + list_add_tail(&page->lru, &pages); + size_remaining -= PAGE_SIZE << compound_order(page); + max_order = compound_order(page); + i++; + } + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + goto free_pages; + + if (sg_alloc_table(table, i, GFP_KERNEL)) + goto free_table; + + sg = table->sgl; + list_for_each_entry_safe(page, tmp_page, &pages, lru) { + sg_set_page(sg, page, PAGE_SIZE << compound_order(page), 0); + sg = sg_next(sg); + list_del(&page->lru); + } + + buffer->sg_table = table; + return 0; + +free_table: + kfree(table); +free_pages: + list_for_each_entry_safe(page, tmp_page, &pages, lru) + free_buffer_page(sys_heap, buffer, page); + return -ENOMEM; +} + +static void rtk_ion_sys_heap_free(struct ion_buffer *buffer) +{ + struct rtk_ion_sys_heap *sys_heap = container_of(buffer->heap, + struct + rtk_ion_sys_heap, + heap); + struct sg_table *table = buffer->sg_table; + struct scatterlist *sg; + int i; + + /* zero the buffer before goto page pool */ + if (!(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) + ion_heap_buffer_zero(buffer); + + for_each_sg(table->sgl, sg, table->nents, i) + free_buffer_page(sys_heap, buffer, sg_page(sg)); + sg_free_table(table); + kfree(table); +} + +static int rtk_ion_sys_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, + int nr_to_scan) +{ + struct ion_page_pool *uncached_pool; + struct ion_page_pool *cached_pool; + struct rtk_ion_sys_heap *sys_heap; + int nr_total = 0; + int i, nr_freed; + int only_scan = 0; + + sys_heap = container_of(heap, struct rtk_ion_sys_heap, heap); + + if (!nr_to_scan) + only_scan = 1; + + for (i = 0; i < NUM_ORDERS; i++) { + uncached_pool = sys_heap->uncached_pools[i]; + cached_pool = sys_heap->cached_pools[i]; + + if (only_scan) { + nr_total += ion_page_pool_shrink(uncached_pool, + gfp_mask, nr_to_scan); + + nr_total += ion_page_pool_shrink(cached_pool, + gfp_mask, nr_to_scan); + } else { + nr_freed = ion_page_pool_shrink(uncached_pool, + gfp_mask, nr_to_scan); + nr_to_scan -= nr_freed; + nr_total += nr_freed; + if (nr_to_scan <= 0) + break; + nr_freed = ion_page_pool_shrink(cached_pool, + gfp_mask, nr_to_scan); + nr_to_scan -= nr_freed; + nr_total += nr_freed; + if (nr_to_scan <= 0) + break; + } + } + return nr_total; +} + +void *rtk_ion_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) +{ + struct scatterlist *sg; + int i, j; + void *vaddr; + pgprot_t pgprot; + struct sg_table *table = buffer->sg_table; + int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **tmp = pages; + + if (!pages) + return ERR_PTR(-ENOMEM); + + if (buffer->flags & ION_FLAG_CACHED) + pgprot = PAGE_KERNEL; + else + pgprot = pgprot_noncached(PAGE_KERNEL); + + for_each_sg(table->sgl, sg, table->nents, i) { + int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE; + struct page *page = sg_page(sg); + + BUG_ON(i >= npages); + for (j = 0; j < npages_this_entry; j++) + *(tmp++) = page++; + } + vaddr = vmap(pages, npages, VM_MAP, pgprot); + vfree(pages); + + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +static struct ion_heap_ops system_heap_ops = { + .allocate = rtk_ion_sys_heap_allocate, + .free = rtk_ion_sys_heap_free, + .map_kernel = rtk_ion_heap_map_kernel, + .unmap_kernel = ion_heap_unmap_kernel, + .map_user = ion_heap_map_user, + .shrink = rtk_ion_sys_heap_shrink, +}; + +static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) + if (pools[i]) + ion_page_pool_destroy(pools[i]); +} + +static int rtk_ion_sys_heap_create_pools(struct ion_page_pool **pools, + bool cached) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) { + struct ion_page_pool *pool; + gfp_t gfp_flags = low_order_gfp_flags; + + if (orders[i] > 4) + gfp_flags = high_order_gfp_flags; + + pool = ion_page_pool_create(gfp_flags, orders[i], cached); + if (!pool) + goto err_create_pool; + pools[i] = pool; + } + return 0; + +err_create_pool: + ion_system_heap_destroy_pools(pools); + return -ENOMEM; +} + +static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, + void *unused) +{ + struct rtk_ion_sys_heap *sys_heap = container_of(heap, + struct + rtk_ion_sys_heap, + heap); + int i; + struct ion_page_pool *pool; + + for (i = 0; i < NUM_ORDERS; i++) { + pool = sys_heap->uncached_pools[i]; + + seq_printf(s, "%d order %u highmem pages uncached %lu total\n", + pool->high_count, pool->order, + (PAGE_SIZE << pool->order) * pool->high_count); + seq_printf(s, "%d order %u lowmem pages uncached %lu total\n", + pool->low_count, pool->order, + (PAGE_SIZE << pool->order) * pool->low_count); + } + + for (i = 0; i < NUM_ORDERS; i++) { + pool = sys_heap->cached_pools[i]; + + seq_printf(s, "%d order %u highmem pages cached %lu total\n", + pool->high_count, pool->order, + (PAGE_SIZE << pool->order) * pool->high_count); + seq_printf(s, "%d order %u lowmem pages cached %lu total\n", + pool->low_count, pool->order, + (PAGE_SIZE << pool->order) * pool->low_count); + } + return 0; +} + +static void rtk_ion_sys_heap_destroy_pools(struct ion_page_pool **pools) +{ + int i; + + for (i = 0; i < NUM_ORDERS; i++) + if (pools[i]) + ion_page_pool_destroy(pools[i]); +} + +static struct ion_heap *__rtk_ion_sys_heap_create(void) +{ + struct rtk_ion_sys_heap *heap; + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); + heap->heap.ops = &system_heap_ops; + heap->heap.type = ION_HEAP_TYPE_CUSTOM; + + if (rtk_ion_sys_heap_create_pools(heap->uncached_pools, false)) + goto free_heap; + + if (rtk_ion_sys_heap_create_pools(heap->cached_pools, true)) + goto destroy_uncached_pools; + + heap->heap.debug_show = ion_system_heap_debug_show; + return &heap->heap; + +destroy_uncached_pools: + rtk_ion_sys_heap_destroy_pools(heap->uncached_pools); + +free_heap: + kfree(heap); + return ERR_PTR(-ENOMEM); +} + +static int rtk_ion_sys_heap_create(void) +{ + struct ion_heap *heap; + + heap = __rtk_ion_sys_heap_create(); + if (IS_ERR(heap)) + return PTR_ERR(heap); + heap->name = "rtk_ion_system_heap"; + + ion_device_add_heap(heap); + return 0; +} + +late_initcall_sync(rtk_ion_sys_heap_create); diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/test/Makefile b/drivers/soc/realtek/common/mem_allocator/rtk/test/Makefile new file mode 100644 index 000000000000..295308fa6096 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/test/Makefile @@ -0,0 +1,4 @@ +#ifndef CONFIG_TEE +obj-y += notifier/ +#endif +obj-y += protected-alloc/ diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/Makefile b/drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/Makefile new file mode 100644 index 000000000000..b8b8bc9131ca --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/rtk/inc +obj-m += test-protecteds-_notifier.o diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/test-protecteds-_notifier.c b/drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/test-protecteds-_notifier.c new file mode 100644 index 000000000000..b59105cfcb2e --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/test/notifier/test-protecteds-_notifier.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include "ion_rtk_protected_notifier.h" + +struct protected_info { + unsigned long base; + size_t size; +}; + +static int protected_handler(struct notifier_block *self, + unsigned long val, void *data) +{ + switch (val) { + case PROTECTED_REGION_CREATE: + { + struct protected_info *info = + kzalloc(sizeof(struct protected_info), GFP_KERNEL); + struct ion_rtk_protected_create_info *create_info = + (struct ion_rtk_protected_create_info *)data; + info->base = create_info->mem.base; + info->size = create_info->mem.size; + pr_info("PROTECTED_REGION_CREATE: 0x%08lx ~ 0x%08lx\n", + info->base, info->base + info->size); + create_info->priv_virt = (void *)info; + } + break; + case PROTECTED_REGION_CHANGE: + { + struct ion_rtk_protected_change_info *change_info = + (struct ion_rtk_protected_change_info *)data; + struct protected_info *info = + (struct protected_info *)change_info->priv_virt; + pr_info + ("PROTECTED_REGION_CHANGE: 0x%08lx ~ 0x%08lx => 0x%08lx ~ 0x%08lx\n", + info->base, info->base + info->size, + change_info->mem.base, + change_info->mem.base + change_info->mem.size); + info->base = change_info->mem.base; + info->size = change_info->mem.size; + } + break; + case PROTECTED_REGION_DESTROY: + { + struct ion_rtk_protected_destroy_info *destroy_info = + (struct ion_rtk_protected_destroy_info *)data; + struct protected_info *info = + (struct protected_info *)destroy_info->priv_virt; + pr_info("PROTECTED_REGION_DESTROY: 0x%08lx ~ 0x%08lx\n", + info->base, info->base + info->size); + kfree(info); + } + break; + default: + return NOTIFY_BAD; + } + return NOTIFY_OK; +} + +static struct notifier_block protected_notifier = { + .notifier_call = protected_handler, +}; + +static int __init ion_rtk_notifier_init(void) +{ + return ion_rtk_protected_notifier_register(&protected_notifier); +} + +static void ion_rtk_notifier_exit(void) +{ + ion_rtk_protected_notifier_unregister(&protected_notifier); +} + +module_init(ion_rtk_notifier_init); +module_exit(ion_rtk_notifier_exit); +MODULE_AUTHOR("Otto Chen "); +MODULE_DESCRIPTION("test of protected memory"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/Makefile b/drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/Makefile new file mode 100644 index 000000000000..a4530ce7964b --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/rtk/inc +obj-m += test-alloc-ion-protected.o + diff --git a/drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/test-alloc-ion-protected.c b/drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/test-alloc-ion-protected.c new file mode 100644 index 000000000000..29c753901f17 --- /dev/null +++ b/drivers/soc/realtek/common/mem_allocator/rtk/test/protected-alloc/test-alloc-ion-protected.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include /* usleep_range */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mem_allocator/ion.h" +#include + +extern struct ion_device *rtk_phoenix_ion_device; + +struct protected_mem { + struct dma_buf *dmabuf; + size_t size; + struct list_head list; // list of pool_handlers +}; + +struct alloc_protected_module { + struct mutex protected_lock; + struct list_head protected_list; + size_t alloc_size; + struct task_struct *alloc_thread; + struct task_struct *free_thread; +}; + +struct alloc_protected_module *gModule = NULL; + +#define TEST_ALLOC_THRESHOLD_MB (128) +#define TEST_ALLOC_MAX_MB (32) + +static int alloc_work(void *data) +{ + struct alloc_protected_module *module = + (struct alloc_protected_module *)data; + while (!kthread_should_stop()) { + uint32_t ion_heap_mask = RTK_ION_HEAP_MEDIA_MASK; + uint32_t ion_heap_flag = ION_FLAG_PROTECTED_IO; + size_t alloc_size = + ((get_random_int() + + 1) % TEST_ALLOC_MAX_MB) * (1024 * 1024); + mutex_lock(&module->protected_lock); + do { + struct protected_mem *mem; + int handle; + + if (module->alloc_size > + (TEST_ALLOC_THRESHOLD_MB * 1024 * 1024)) + break; + + mem = kzalloc(sizeof(struct protected_mem), GFP_KERNEL); + if (!mem) + break; + INIT_LIST_HEAD(&mem->list); + handle = + ext_rtk_ion_alloc(alloc_size, ion_heap_mask, + ion_heap_flag); + if (handle < 0) { + kfree(mem); + break; + } + + mem->dmabuf = dma_buf_get(handle); + + if (IS_ERR(mem->dmabuf)) { + break; + } + ext_rtk_ion_close_fd(current->files, handle); + + mem->size = alloc_size; + module->alloc_size += alloc_size; + list_add_tail(&mem->list, &module->protected_list); + } while (0); + mutex_unlock(&module->protected_lock); + msleep(get_random_int() % 16); + } + return 0; +} + +static int free_work(void *data) +{ + struct alloc_protected_module *module = + (struct alloc_protected_module *)data; + while (!kthread_should_stop()) { + mutex_lock(&module->protected_lock); + do { + struct protected_mem *mem; + if (list_empty(&module->protected_list)) + break; +#if 0 + mem = + list_first_entry(&module->protected_list, + struct protected_mem, list); +#else + { + int slot, total = 0; + list_for_each_entry(mem, + &module->protected_list, + list) + total++; + slot = get_random_int() % total; + list_for_each_entry(mem, + &module->protected_list, + list) { + if (slot == 0) + break; + slot--; + } + } +#endif + list_del(&mem->list); + dma_buf_put(mem->dmabuf); + module->alloc_size -= mem->size; + kfree(mem); + break; + } while (0); + mutex_unlock(&module->protected_lock); + msleep(get_random_int() % 16); + } + return 0; +} + +static int alloc_protected_module_init(void) +{ + int ret = -1; + + pr_err("[DEBUG] ******** %s\n", __func__); + + do { + struct alloc_protected_module *module = NULL; + gModule = + kzalloc(sizeof(struct alloc_protected_module), GFP_KERNEL); + if (!gModule) + break; + + module = gModule; + + mutex_init(&module->protected_lock); + INIT_LIST_HEAD(&module->protected_list); + module->alloc_thread = + kthread_create(alloc_work, module, + "test-ion-protected-alloc"); + module->free_thread = + kthread_create(free_work, module, + "test-ion-protected-free"); + wake_up_process(module->alloc_thread); + wake_up_process(module->free_thread); + ret = 0; + } while (0); + return ret; +} + +static void alloc_protected_module_release_all(struct alloc_protected_module + *module) +{ + struct protected_mem *protected_mem, *tmp_protected_mem; + mutex_lock(&module->protected_lock); + list_for_each_entry_safe(protected_mem, tmp_protected_mem, + &module->protected_list, list) { + list_del(&protected_mem->list); + dma_buf_put(protected_mem->dmabuf); + module->alloc_size -= protected_mem->size; + kfree(protected_mem); + } + mutex_unlock(&module->protected_lock); +} + +static void alloc_protected_module_exit(void) +{ + struct alloc_protected_module *module = gModule; + kthread_stop(module->alloc_thread); + kthread_stop(module->free_thread); + alloc_protected_module_release_all(module); + kfree(module); +} + +module_init(alloc_protected_module_init); +module_exit(alloc_protected_module_exit); +MODULE_AUTHOR("Otto Chen "); +MODULE_DESCRIPTION("pressure test of protected memory"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); diff --git a/drivers/soc/realtek/common/rpc/Kconfig b/drivers/soc/realtek/common/rpc/Kconfig new file mode 100644 index 000000000000..3a3b441c13af --- /dev/null +++ b/drivers/soc/realtek/common/rpc/Kconfig @@ -0,0 +1,12 @@ +config REALTEK_RPC + bool "Realtek RPC driver" + depends on REALTEK_SOC + default y + help + Realtek RPC driver. + +config REALTEK_RPC_VE3 + bool "Realtek VE3 RPC" + depends on REALTEK_RPC + help + Enable Realtek VE3 RPC. diff --git a/drivers/soc/realtek/common/rpc/Makefile b/drivers/soc/realtek/common/rpc/Makefile new file mode 100644 index 000000000000..3c3d05fd3965 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/Makefile @@ -0,0 +1,8 @@ +ccflags-$(CONFIG_REALTEK_RPC) += -Idrivers/soc/realtek/common +ccflags-$(CONFIG_REALTEK_RPC) += -Idrivers/soc/realtek/common/include +ccflags-y += -Idrivers/video/fbdev/rtk +ccflags-y += -Idrivers/soc/realtek/common/mem_allocator/rtk/inc +obj-$(CONFIG_REALTEK_RPC) += rpc_mem.o rtk_rpc_intr.o rtk_rpc_kern.o rtk_rpc_poll.o rtk_rpc.o +ifdef CONFIG_COMPAT +obj-$(CONFIG_REALTEK_RPC) += compat_rpc_mem.o +endif diff --git a/drivers/soc/realtek/common/rpc/compat_rpc_mem.c b/drivers/soc/realtek/common/rpc/compat_rpc_mem.c new file mode 100644 index 000000000000..5c9a39b4e4a7 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/compat_rpc_mem.c @@ -0,0 +1,95 @@ +#include +#include +#include + +#include "rpc_mem_uapi.h" +#include "compat_rpc_mem.h" + +struct compat_rpc_mem_fd_data { + compat_ulong_t phyAddr; + compat_ulong_t ret_offset; + compat_ulong_t ret_size; + compat_int_t ret_fd; +}; + +#define COMPAT_RPC_MEM_IOC_EXPORT _IOWR(RPC_MEM_IOC_MAGIC, 0, struct compat_rpc_mem_fd_data) + +static int compat_get_rpc_mem_fd_data( + struct compat_rpc_mem_fd_data __user *data32, + struct rpc_mem_fd_data __user *data) +{ + compat_ulong_t p; + compat_ulong_t o; + compat_ulong_t s; + compat_int_t f; + int err; + + err = get_user(p, &data32->phyAddr); + err |= put_user(p, &data->phyAddr); + err |= get_user(o, &data32->ret_offset); + err |= put_user(o, &data->ret_offset); + err |= get_user(s, &data32->ret_size); + err |= put_user(s, &data->ret_size); + err |= get_user(f, &data32->ret_fd); + err |= put_user(f, &data->ret_fd); + + return err; +} + +static int compat_put_rpc_mem_fd_data( + struct compat_rpc_mem_fd_data __user *data32, + struct rpc_mem_fd_data __user *data) +{ + compat_ulong_t p; + compat_ulong_t o; + compat_ulong_t s; + compat_int_t f; + int err; + + err = get_user(p, &data->phyAddr); + err |= put_user(p, &data32->phyAddr); + err |= get_user(o, &data->ret_offset); + err |= put_user(o, &data32->ret_offset); + err |= get_user(s, &data->ret_size); + err |= put_user(s, &data32->ret_size); + err |= get_user(f, &data->ret_fd); + err |= put_user(f, &data32->ret_fd); + + return err; +} + +long compat_rpc_mem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + + if (!filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) { + case COMPAT_RPC_MEM_IOC_EXPORT: + { + struct compat_rpc_mem_fd_data __user *data32; + struct rpc_mem_fd_data __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_rpc_mem_fd_data(data32, data); + if (err) + return err; + + ret = filp->f_op->unlocked_ioctl(filp, RPC_MEM_IOC_EXPORT, (unsigned long)data); + err = compat_put_rpc_mem_fd_data(data32, data); + return ret ? ret : err; + } + + default: + { + printk(KERN_ERR "[COMPAT_RPC_MEM] No such IOCTL, cmd is %d\n", cmd); + return -ENOIOCTLCMD; + } + } +} diff --git a/drivers/soc/realtek/common/rpc/compat_rpc_mem.h b/drivers/soc/realtek/common/rpc/compat_rpc_mem.h new file mode 100644 index 000000000000..d07abf2a7a2d --- /dev/null +++ b/drivers/soc/realtek/common/rpc/compat_rpc_mem.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_COMPAT_RPC_MEM_H +#define _LINUX_COMPAT_RPC_MEM_H + +#if IS_ENABLED(CONFIG_COMPAT) + +long compat_rpc_mem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +#define compat_rpc_mem_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_RPC_MEM_H */ diff --git a/drivers/soc/realtek/common/rpc/rpc_mem.c b/drivers/soc/realtek/common/rpc/rpc_mem.c new file mode 100644 index 000000000000..c85c4bdd9176 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rpc_mem.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mem_allocator/ion.h" +#include +#include "rpc_mem.h" +#include "rpc_mem_uapi.h" +#include "compat_rpc_mem.h" + +static DEFINE_SPINLOCK(rpc_alloc_lock); +static r_program_entry_t *r_program_head = NULL; +static int r_program_count = 0; + +void r_program_add(r_program_entry_t * entry) +{ + spin_lock_bh(&rpc_alloc_lock); + entry->next = r_program_head; + r_program_head = entry; + r_program_count++; + spin_unlock_bh(&rpc_alloc_lock); +} + +r_program_entry_t *r_program_remove(unsigned long phys_addr) +{ + r_program_entry_t *prev = NULL; + r_program_entry_t *curr = NULL; + + spin_lock_bh(&rpc_alloc_lock); + curr = r_program_head; + while (curr != NULL) { + if (curr->phys_addr != phys_addr) { + prev = curr; + curr = curr->next; + continue; + } + + if (prev == NULL) { + r_program_head = curr->next; + } else { + prev->next = curr->next; + } + r_program_count--; + spin_unlock_bh(&rpc_alloc_lock); + + return curr; + } + spin_unlock_bh(&rpc_alloc_lock); + return NULL; +} + +int r_program_fd(unsigned long phys_addr, unsigned long *offset, + unsigned long *size) +{ + int ret_fd = -1; + spin_lock_bh(&rpc_alloc_lock); + do { + r_program_entry_t *curr = r_program_head; + while (curr != NULL) { + if (phys_addr >= curr->phys_addr && + phys_addr < (curr->phys_addr + curr->size)) { + + ret_fd = + dma_buf_fd(curr->rpc_dmabuf, O_CLOEXEC); + + if (ret_fd >= 0) { + struct dma_buf *dmabuf = + dma_buf_get(ret_fd); + if (IS_ERR(dmabuf)) + pr_err + ("%s : dma=%p (phy=0x%08lx) fd=%d\n", + __func__, dmabuf, + phys_addr, ret_fd); + else + curr->rpc_dmabuf = dmabuf; + } + + if (offset) + *offset = phys_addr - curr->phys_addr; + + if (size) + *size = curr->size; + + break; + } else { + curr = curr->next; + } + } + } while (0); + spin_unlock_bh(&rpc_alloc_lock); + return ret_fd; +} + +static long rpc_mem_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + long ret = -ENOTTY; + switch (cmd) { + case RPC_MEM_IOC_EXPORT: + { + struct rpc_mem_fd_data data; + if (copy_from_user + (&data, (void __user *)arg, sizeof(data))) { + pr_err("%s: copy_from_user ERROR!\n", __func__); + break; + } + + data.ret_fd = + r_program_fd(data.phyAddr, &data.ret_offset, + &data.ret_size); + + if (data.ret_fd < 0) { + pr_err("%s : ret_fd = %d\n", __func__, + data.ret_fd); + break; + } + + if (copy_to_user + ((void __user *)arg, &data, sizeof(data))) { + ext_rtk_ion_close_fd(current->files, + data.ret_fd); + pr_err + ("%s : copy_to_user failed! (phyAddr=0x%08lx)\n", + __func__, data.phyAddr); + break; + } + ret = 0; + break; + } + default: + pr_err("%s: Unknown ioctl (cmd=0x%08x)\n", __func__, cmd); + ret = -ENOTTY; + break; + } + return ret; +} + +static const struct file_operations rpc_mem_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = rpc_mem_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_rpc_mem_ioctl, +#endif +}; + +static int rpc_mem_device_create(void) +{ + struct miscdevice *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->minor = MISC_DYNAMIC_MINOR; + dev->name = "rpc_mem"; + dev->fops = &rpc_mem_fops; + dev->parent = NULL; + + ret = misc_register(dev); + if (ret) { + pr_err("rpc_mem: failed to register misc device.\n"); + kfree(dev); + return ret; + } + + return 0; +} + +fs_initcall(rpc_mem_device_create); diff --git a/drivers/soc/realtek/common/rpc/rpc_mem.h b/drivers/soc/realtek/common/rpc/rpc_mem.h new file mode 100644 index 000000000000..e449b0b4af76 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rpc_mem.h @@ -0,0 +1,17 @@ +#ifndef _RTK_RPC_MEM_H +#define _RTK_RPC_MEM_H + +#include +#include + +typedef struct r_program_entry { + unsigned long phys_addr; + unsigned long size; + struct dma_buf *rpc_dmabuf; + struct r_program_entry *next; +} r_program_entry_t; + +void r_program_add(r_program_entry_t * entry); +r_program_entry_t *r_program_remove(unsigned long phys_addr); + +#endif /* _RTK_RPC_MEM_H */ diff --git a/drivers/soc/realtek/common/rpc/rpc_mem_uapi.h b/drivers/soc/realtek/common/rpc/rpc_mem_uapi.h new file mode 100644 index 000000000000..abb74618e05b --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rpc_mem_uapi.h @@ -0,0 +1,17 @@ +#ifndef _RTK_RPC_MEM_UAPI_H +#define _RTK_RPC_MEM_UAPI_H + +#include +#include + +struct rpc_mem_fd_data { + unsigned long phyAddr; + unsigned long ret_offset; + unsigned long ret_size; + int ret_fd; +}; + +#define RPC_MEM_IOC_MAGIC 'R' +#define RPC_MEM_IOC_EXPORT _IOWR(RPC_MEM_IOC_MAGIC, 0, struct rpc_mem_fd_data) + +#endif /* _RTK_RPC_MEM_UAPI_H */ diff --git a/drivers/soc/realtek/common/rpc/rtk_rpc.c b/drivers/soc/realtek/common/rpc/rtk_rpc.c new file mode 100644 index 000000000000..eef97b4fe983 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rtk_rpc.c @@ -0,0 +1,886 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek RPC driver + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#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 +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#include "rtk_rpc.h" +#include "mem_allocator/ion.h" + +#define SHOW_TASKS_ON_DEBUGFS + +EXPORT_TRACEPOINT_SYMBOL_GPL(rtk_rpc_peek_rpc_request); +EXPORT_TRACEPOINT_SYMBOL_GPL(rtk_rpc_peek_rpc_reply); + +void __iomem *rpc_int_base; +void __iomem *rpc_acpu_int_flag; +EXPORT_SYMBOL(rpc_acpu_int_flag); +void __iomem *rpc_vcpu_int_flag; +EXPORT_SYMBOL(rpc_vcpu_int_flag); + +#ifdef CONFIG_REALTEK_RPC_VE3 +void __iomem *rpc_ve3_int_flag; +struct regmap *rpc_ve3_base; +#endif + +struct refclk_device *refclk; +struct device *rpc_dev; +EXPORT_SYMBOL(rpc_dev); + +int chip_id; +EXPORT_SYMBOL(chip_id); + +#ifdef CONFIG_FB_RTK +extern spinlock_t gASLock; +extern void dc_irq_handler(void); +#else +static DEFINE_SPINLOCK(gASLock); +#endif /* CONFIG_FB_RTK */ + + +static int rpc_major; +static int rpc_acpu_irq; +static int rpc_vcpu_irq; +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ +static int rpc_ve3_irq; +#endif /* MY_DEF_HERE */ + + +#ifdef SHOW_TASKS_ON_DEBUGFS +static int rpc_debug_node_show(struct seq_file *s, void *unused) +{ + int i; + RPC_DEV_EXTRA *extra = (RPC_DEV_EXTRA *)s->private; + RPC_DEV *dev = extra->dev; + RPC_PROCESS *curr = (RPC_PROCESS *)extra->currProc; + RPC_HANDLER *handler; + RPC_PROCESS *proc; + RPC_THREAD *thread; + struct task_struct *task; + + seq_printf(s, "name: %s\n", extra->name); + seq_printf(s, "currProc: %d\n", curr ? curr->pid : 0); + seq_printf(s, "nextRpc: %x\n", extra->nextRpc); + seq_printf(s, "RingBuf: %x\n", dev->ringBuf); + seq_printf(s, "RingStart: %x\n", dev->ringStart); + seq_printf(s, "RingIn: %x\n", dev->ringIn); + seq_printf(s, "RingOut: %x\n", dev->ringOut); + seq_printf(s, "RingEnd: %x\n", dev->ringEnd); + + seq_printf(s, "\nRingBuffer:\n"); + for (i = 0; i < RPC_RING_SIZE; i += 16) { + uint32_t *addr = (uint32_t *)(AVCPU2SCPU(dev->ringStart) + i); + seq_printf(s, "%x: %08x %08x %08x %08x\n", + dev->ringStart + i, + ntohl(*(addr + 0)), + ntohl(*(addr + 1)), + ntohl(*(addr + 2)), + ntohl(*(addr + 3))); + } + + spin_lock_bh(&extra->lock); + list_for_each_entry(proc, &extra->tasks, list) { + task = find_task_by_vpid(proc->pid); + + seq_printf(s, "\nProcess:%s\n", task ? task->comm : "N/A"); + + list_for_each_entry(handler, &proc->handlers, list) { + seq_printf(s, "\tprogramID:%u\n", handler->programID); + } + + seq_printf(s, "\tp:%d\n", proc->pid); + + list_for_each_entry(thread, &proc->threads, list) { + seq_printf(s, "\tt:%d\n", thread->pid); + } + } + spin_unlock_bh(&extra->lock); + return 0; +} + +static int rpc_debug_node_open(struct inode *inode, struct file *file) +{ + return single_open(file, rpc_debug_node_show, inode->i_private); +} + +static const struct file_operations rpc_debug_node_ops = { + .open = rpc_debug_node_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* SHOW_TASKS_ON_DEBUGFS */ + +struct file_operations *rpc_fop_array[] = { + &rpc_poll_fops, /* poll */ + &rpc_intr_fops /* intr */ +}; + +void **rpc_data_ptr_array[] = { + (void **) &rpc_poll_devices, /* poll */ + (void **) &rpc_intr_devices /* intr */ +}; + +int rpc_data_size_array[] = { + sizeof(RPC_DEV), /* poll */ + sizeof(RPC_DEV) /* intr */ +}; + +/* + * Finally, the module stuff + */ +static struct class *rpc_class; + +void rpc_set_ir_wakeup_key(uint32_t uScancode, uint32_t uScancode_msk) +{ + struct rtk_ipc_shm __iomem *ipc = (void __iomem *)IPC_SHM_VIRT; + + dev_info(rpc_dev, "uScancode = 0x%x , uScancode_msk = 0x%x ", uScancode, + uScancode_msk); + /* audio RPC flag for scancode mask */ + writel(__cpu_to_be32(uScancode_msk), &(ipc->ir_scancode_mask)); + /* audio RPC flag for scancode key */ + writel(__cpu_to_be32(uScancode), &(ipc->ir_wakeup_scancode)); +} + +void rpc_set_flag(int type, uint32_t flag) +{ + struct rtk_ipc_shm __iomem *ipc = (void __iomem *) IPC_SHM_VIRT; + + /* audio RPC flag */ + if (type == RPC_AUDIO) + writel(__cpu_to_be32(flag), &(ipc->audio_rpc_flag)); + + /* video RPC flag */ + if (type == RPC_VIDEO) + writel(__cpu_to_be32(flag), &(ipc->video_rpc_flag)); + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (type == RPC_VE3) + writel(__cpu_to_be32(flag), &(ipc->ve3_rpc_flag)); +#endif +} + +uint32_t rpc_get_flag(int type) +{ + struct rtk_ipc_shm __iomem *ipc = (void __iomem *)IPC_SHM_VIRT; + + if (type == RPC_AUDIO) { + return __be32_to_cpu(readl(&(ipc->audio_rpc_flag))); + } + + if (type == RPC_VIDEO) + return __be32_to_cpu(readl(&(ipc->video_rpc_flag))); + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (type == RPC_VE3) + return __be32_to_cpu(readl(&(ipc->ve3_rpc_flag))); +#endif + + dev_err(rpc_dev, "rpc_get_flag type error!\n"); + + return 0xdeaddead; +} + +void rpc_send_interrupt(int type) +{ + switch (type) { + case RPC_AUDIO: + if (rpc_acpu_int_flag != NULL && RPC_HAS_BIT(rpc_acpu_int_flag, AUDIO_RPC_SET_NOTIFY)) { + spin_lock_irq(&gASLock); + RPC_SET_BIT(rpc_acpu_int_flag, AUDIO_RPC_FEEDBACK_NOTIFY); + spin_unlock_irq(&gASLock); + } + dev_dbg(rpc_dev, "send audio interrupt\n"); + writel_relaxed((RPC_INT_SA | RPC_INT_WRITE_1), rpc_int_base + RPC_SB2_INT); + break; + case RPC_VIDEO: + + if (rpc_vcpu_int_flag != NULL && RPC_HAS_BIT(rpc_vcpu_int_flag, VIDEO_RPC_SET_NOTIFY)) + RPC_SET_BIT(rpc_vcpu_int_flag, VIDEO_RPC_FEEDBACK_NOTIFY); + + dev_dbg(rpc_dev, "send video interrupt\n"); + writel_relaxed((RPC_INT_SV | RPC_INT_WRITE_1), rpc_int_base + RPC_SB2_INT); + + break; +#ifdef CONFIG_REALTEK_RPC_VE3 + case RPC_VE3: + if (rpc_ve3_int_flag != NULL && RPC_HAS_BIT(rpc_ve3_int_flag, VE3_RPC_SET_NOTIFY)) + RPC_SET_BIT(rpc_ve3_int_flag, VE3_RPC_FEEDBACK_NOTIFY); + + dev_dbg(rpc_dev, "send ve3 interrupt\n"); + regmap_write(rpc_ve3_base, 0x78, RPC_INT_SVE3); + + break; +#endif + default: + break; + } + +} +EXPORT_SYMBOL(rpc_send_interrupt); + +#ifdef MY_COPY +int my_copy_to_user(int *des, int *src, int size) +{ + char buf[256]; + int count = size; + void *pSrc = (void *)src; + int ret = 0; + int i = 0; + + if (size > 256) { + BUG(); + } + + while (size >= 4) { + *(int *)&buf[i] = __raw_readl(pSrc); + i += 4; + pSrc += 4; + size -= 4; + } + + while (size > 0) { + buf[i] = __raw_readb(pSrc); + i++; + pSrc++; + size--; + } + + ret = copy_to_user((int *)des, (int *)buf, count); + + return ret; +} + +int my_copy_from_user(volatile void __iomem *des, const void *src, int size) +{ + + char buf[256]; + int ret = 0; + int i = 0; + volatile char *cdes; + + if (size > 256) { + BUG(); + } + + dev_dbg(rpc_dev, "(des:%p, src:%p, size:%d) pid:%d tid:%d comm:%s\n", + des, src, size, current->tgid, current->pid, current->comm); + + ret = copy_from_user((unsigned int *) buf, (unsigned int __user *) src, size); + + if (ret != 0) + dev_err(rpc_dev, "copy_from_user error: %d bytes\n", ret); + + cdes = (char *)des; + for (i = 0 ; i < size ; i++) + cdes[i] = buf[i]; + + return 0; +} + + +int my_copy_user(int *des, int *src, int size) +{ + char *csrc, *cdes; + int i; + + dev_dbg(rpc_dev, "(des:%p, src:%p, size:%d) pid:%d tid:%d comm:%s\n", + des, src, size, current->tgid, current->pid, current->comm); + + might_fault(); + + if ((unsigned long)des < 0xc0000000 && + access_ok(des, size) == 0) + BUG(); + + if ((unsigned long)src < 0xc0000000 && + access_ok(src, size) == 0) + BUG(); + + if (((unsigned long)src & 0x3) || ((unsigned long)des & 0x3)) + dev_warn(rpc_dev, "my_copy_user: unaligned happen...\n"); + + while (size >= 4) { + *des++ = *src++; + size -= 4; + } + + csrc = (char *)src; + cdes = (char *)des; + + for (i = 0 ; i < size ; i++) + cdes[i] = csrc[i]; + + return 0; +} +#endif /* MY_COPY */ + +irqreturn_t rpc_isr(int irq, void *dev_id) +{ + int itr; + + itr = readl_relaxed(rpc_int_base + RPC_SB2_INT_ST); + + if (RPC_HAS_BIT(rpc_acpu_int_flag, RPC_AUDIO_FEEDBACK_NOTIFY)) { + RPC_RESET_BIT(rpc_acpu_int_flag, RPC_AUDIO_FEEDBACK_NOTIFY); + } else if (RPC_HAS_BIT(rpc_vcpu_int_flag, RPC_VIDEO_FEEDBACK_NOTIFY)) { + RPC_RESET_BIT(rpc_vcpu_int_flag, RPC_VIDEO_FEEDBACK_NOTIFY); + } else { + /* to clear interrupt, set bit[0] to 0 then we can clear A2S int */ + if (itr & (1 << 1)) + writel_relaxed(1 << 1, rpc_int_base + RPC_SB2_INT_ST); + if (itr & (RPC_INT_VS)) + writel_relaxed(RPC_INT_VS, rpc_int_base + RPC_SB2_INT_ST); + + return IRQ_HANDLED; + } + + while ((itr & 1 << 1) || (itr & RPC_INT_VS)) { + if (itr & 1 << 1) { + /* to clear interrupt, set bit[0] to 0 then we can clear A2S int */ + writel_relaxed(1 << 1, rpc_int_base + RPC_SB2_INT_ST); + + if (rpc_intr_devices[RPC_INTR_DEV_AS_ID1].ringIn != + rpc_intr_devices[RPC_INTR_DEV_AS_ID1].ringOut) { + tasklet_schedule(&(rpc_intr_extra[RPC_INTR_DEV_AS_ID1].tasklet)); + } + + if (rpc_kern_devices[RPC_KERN_DEV_AS_ID1].ringIn != + rpc_kern_devices[RPC_KERN_DEV_AS_ID1].ringOut) { + wake_up_interruptible(&(rpc_kern_devices[RPC_KERN_DEV_AS_ID1].ptrSync->waitQueue)); + } + } + + if (itr & RPC_INT_VS) { + /* to clear interrupt, set bit[0] to 0 then we can clear A2S int */ + writel_relaxed(RPC_INT_VS, rpc_int_base + RPC_SB2_INT_ST); + + if (rpc_intr_devices[RPC_INTR_DEV_V1S_ID3].ringIn != + rpc_intr_devices[RPC_INTR_DEV_V1S_ID3].ringOut) { + tasklet_schedule(&(rpc_intr_extra[RPC_INTR_DEV_V1S_ID3].tasklet)); + } + + if (rpc_kern_devices[RPC_KERN_DEV_V1S_ID3].ringIn != + rpc_kern_devices[RPC_KERN_DEV_V1S_ID3].ringOut) { + wake_up_interruptible(&(rpc_kern_devices[RPC_KERN_DEV_V1S_ID3].ptrSync->waitQueue)); + } + } + itr = readl_relaxed(rpc_int_base + RPC_SB2_INT_ST); + } + + return IRQ_HANDLED; +} + +#ifdef CONFIG_REALTEK_RPC_VE3 +irqreturn_t rpc_ve3_isr(int irq, void *dev_id) +{ + int itr; + + regmap_read(rpc_ve3_base, 0x88, &itr); + + if (RPC_HAS_BIT(rpc_ve3_int_flag, RPC_VE3_FEEDBACK_NOTIFY)) { + RPC_RESET_BIT(rpc_ve3_int_flag, RPC_VE3_FEEDBACK_NOTIFY); + } else { + /* to clear interrupt, set bit[0] to 0 then we can clear A2S int */ + if (itr & RPC_INT_VE3S_ST) { + regmap_write(rpc_ve3_base, 0x88, itr & (~RPC_INT_VE3S_ST)); + } + return IRQ_HANDLED; + } + + while (itr & RPC_INT_VE3S_ST) { + + /* to clear interrupt, set bit[0] to 0 then we can clear A2S int */ + regmap_write(rpc_ve3_base, 0x88, itr & (~RPC_INT_VE3S_ST)); + + if (rpc_intr_ve3_devices[RPC_INTR_DEV_VE3S_ID1].ringIn != + rpc_intr_ve3_devices[RPC_INTR_DEV_VE3S_ID1].ringOut) { + tasklet_schedule(&(rpc_intr_extra[RPC_INTR_DEV_VE3S_ID1 + RPC_INTR_DEV_TOTAL].tasklet)); + } + + if (rpc_kern_ve3_devices[RPC_KERN_DEV_VE3S_ID1].ringIn != + rpc_kern_ve3_devices[RPC_KERN_DEV_VE3S_ID1].ringOut) { + wake_up_interruptible(&(rpc_kern_ve3_devices[RPC_KERN_DEV_AS_ID1].ptrSync->waitQueue)); + } + + regmap_read(rpc_ve3_base, 0x88, &itr); + } + + return IRQ_HANDLED; +} +#endif + +static char *rpc_devnode(struct device *dev, umode_t *mode) +{ + *mode = 0666; + return NULL; +} + +static ssize_t kernel_remote_allocate_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", 1); +} + +static CLASS_ATTR_RO(kernel_remote_allocate); + +static int rpc_interrupt_init(struct device_node *np) +{ + int max_count = 5000; + int wait_time = 0; + int ret = -1; + + spin_lock_irq(&gASLock); + RPC_SET_BIT(rpc_acpu_int_flag, RPC_AUDIO_SET_NOTIFY); + spin_unlock_irq(&gASLock); + + RPC_SET_BIT(rpc_vcpu_int_flag, RPC_VIDEO_SET_NOTIFY); + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + RPC_SET_BIT(rpc_ve3_int_flag, RPC_VE3_SET_NOTIFY); + } +#endif + + writel_relaxed(RPC_INT_SA | RPC_INT_SV | RPC_INT_WRITE_1, + rpc_int_base + RPC_SB2_INT_EN); + + rpc_acpu_irq = irq_of_parse_and_map(np, 0); + if (WARN_ON(!rpc_acpu_irq)) + dev_warn(rpc_dev, "can not parse ACPU irq\n"); + + dev_info(rpc_dev, "rpc_int_base: %p\n", rpc_int_base); + dev_info(rpc_dev, "acpu irq: %d\n", rpc_acpu_irq); + + ret = request_irq(rpc_acpu_irq, + rpc_isr, IRQF_SHARED | IRQF_NO_SUSPEND, + "a_rpc", + (void *) RPC_ID); + if (ret) { + dev_err(rpc_dev, "register acpu irq handler failed\n"); + goto exit; + } + + /* Enable the interrupt from system to audio & video */ + rpc_send_interrupt(RPC_AUDIO); + rpc_set_flag(RPC_AUDIO, 0xffffffff); + + rpc_vcpu_irq = irq_of_parse_and_map(np, 1); + if (WARN_ON(!rpc_vcpu_irq)) + dev_warn(rpc_dev, "can not parse VCPU irq\n"); + + dev_info(rpc_dev, "vcpu irq: %d\n", rpc_vcpu_irq); + + ret = request_irq(rpc_vcpu_irq, + rpc_isr, IRQF_SHARED | IRQF_NO_SUSPEND, + "v_rpc", + (void *)RPC_ID); + if (ret) { + dev_err(rpc_dev, "register vcpu irq handler failed\n"); + goto exit; + } + + rpc_send_interrupt(RPC_VIDEO); + rpc_set_flag(RPC_VIDEO, 0xffffffff); + + dev_warn(rpc_dev, "wait vcpu ready"); + + while ((rpc_get_flag(RPC_VIDEO) == 0xffffffff) && ((max_count--) > 0)) { + mdelay(1); + if ((++wait_time) == 10) + wait_time = 0; + } + + while ((--wait_time) > 0) + dev_warn(rpc_dev, "."); + + dev_warn(rpc_dev, "%s (RPC_VIDEO FLAG = 0x%08x)\n", + (max_count > 0) ? "OK" : "timeout", rpc_get_flag(RPC_VIDEO)); + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + max_count = 5000; + rpc_ve3_irq = irq_of_parse_and_map(np, 2); + if (WARN_ON(!rpc_ve3_irq)) + dev_warn(rpc_dev, "can not parse VE3 irq\n"); + + dev_info(rpc_dev, "ve3 irq: %d\n", rpc_ve3_irq); + + ret = request_irq(rpc_ve3_irq, + rpc_ve3_isr, IRQF_SHARED | IRQF_NO_SUSPEND, + "ve3_rpc", + (void *)RPC_ID); + if (ret) { + dev_err(rpc_dev, "register ve3 irq handler failed\n"); + goto exit; + } + rpc_send_interrupt(RPC_VE3); + rpc_set_flag(RPC_VE3, 0xffffffff); + + dev_warn(rpc_dev, "wait ve3 ready"); + + while ((rpc_get_flag(RPC_VE3) == 0xffffffff) && ((max_count--) > 0)) { + mdelay(1); + if ((++wait_time) == 10) + wait_time = 0; + } + + while ((--wait_time) > 0) + dev_warn(rpc_dev, "."); + + dev_warn(rpc_dev, "%s (RPC_VE3 FLAG = 0x%08x)\n", + (max_count > 0) ? "OK" : "timeout", rpc_get_flag(RPC_VE3)); + } +#endif +exit: + return ret; +} + +static int rpc_fs_init(void) +{ + char buf[16]; + int ret = -1; + struct device *dev; + int i = 0; + int node_num; + RPC_DEV_EXTRA *extra; + +#ifdef SHOW_TASKS_ON_DEBUGFS + struct dentry *rpcnode; + struct dentry *rpcroot; +#endif /* SHOW_TASKS_ON_DEBUGFS */ + + /* register rpc_poll_fops as default file operation */ + rpc_major = RPC_MAJOR; + ret = register_chrdev(rpc_major, "realtek-rpc", &rpc_poll_fops); + if (ret < 0) { + dev_dbg(rpc_dev, "can not get major %d\n", rpc_major); + goto exit; + } + + if (rpc_major == 0) + rpc_major = ret; /* dynamic */ + + dev_dbg(rpc_dev, "rpc major number: %d\n", rpc_major); + + rpc_class = class_create(THIS_MODULE, "rpc"); + if (IS_ERR(rpc_class)) { + ret = PTR_ERR(rpc_class); + goto exit; + } + + rpc_class->devnode = rpc_devnode; + + ret = class_create_file(rpc_class, &class_attr_kernel_remote_allocate); + if (ret) { + dev_err(rpc_dev, "create class file failed\n"); + ret = -EINVAL; + goto exit; + } + +#ifdef SHOW_TASKS_ON_DEBUGFS + rpcroot = debugfs_create_dir("rpc", NULL); +#endif /* SHOW_TASKS_ON_DEBUGFS */ + + if (chip_id == CHIP_ID_RTD1619B) + node_num = RPC_NR_DEVS + RPC_INTR_VE3_DEV_TOTAL; + else + node_num = RPC_NR_DEVS; + + for (i = 0; i < node_num; i++) { + if (i >= RPC_NR_DEVS) { + if (i % RPC_NR_PAIR == 0) + extra = &rpc_intr_extra[i / RPC_NR_PAIR]; + else + extra = &rpc_intr_extra[i / RPC_NR_PAIR + 1]; + } else { + extra = ((i % RPC_NR_PAIR) == 0) ? + &rpc_poll_extra[i / RPC_NR_PAIR] : + &rpc_intr_extra[i / RPC_NR_PAIR]; + } + + dev = device_create(rpc_class, + NULL, + MKDEV(rpc_major, i), + NULL, + "rpc%d", + i); + +#ifdef SHOW_TASKS_ON_SYSFS + device_create_file(dev, &dev_attr_tasks); +#endif /* SHOW_TASKS_ON_SYSFS */ + +#ifdef SHOW_TASKS_ON_DEBUGFS + sprintf(buf, "rpc%d", i); + rpcnode = debugfs_create_file(buf, + 0444, + rpcroot, + extra, + &rpc_debug_node_ops); +#endif /* SHOW_TASKS_ON_DEBUGFS */ + + extra->sdev = dev; + dev_set_drvdata(dev, extra); + } + + device_create(rpc_class, NULL, MKDEV(rpc_major, 100), NULL, "rpc100"); +exit: + return ret; +} + +static int rtk_rpc_probe(struct platform_device *pdev) +{ + int ret = -1; + struct device_node *np = pdev->dev.of_node; + struct rtk_ipc_shm __iomem *ipc = (void __iomem *) IPC_SHM_VIRT; +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ + struct device_node *syscon_np; +#endif /* MY_DEF_HERE */ + + rpc_dev = &pdev->dev; + chip_id = get_rtd_chip_id(); + + dev_info(rpc_dev, "enter %s\n", __func__); + + if (WARN_ON(!np)) + dev_err(rpc_dev, "can not found device node\n"); + + rpc_int_base = of_iomap(np, 0); + if (WARN_ON(!rpc_int_base)) { + dev_warn(rpc_dev, "can not map regnsters for %s\n", np->name); + goto exit; + } + + refclk = of_refclk_get(np, 0); + if (IS_ERR(refclk)) { + ret = PTR_ERR(refclk); + if (ret == -EPROBE_DEFER) { + dev_dbg(rpc_dev, "refclk not ready, retry\n"); + goto exit; + } else { + dev_err(rpc_dev, "failed to get refclk: %d\n", ret); + goto exit; + } + } + + rpc_acpu_int_flag = (void __iomem *)&ipc->vo_int_sync; + /* todo: use chipinfo replace it */ + + rpc_vcpu_int_flag = (void __iomem *)&ipc->video_int_sync; + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + rpc_ve3_int_flag = (void __iomem *)&ipc->ve3_int_sync; + syscon_np = of_parse_phandle(np, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) + return -ENODEV; + + rpc_ve3_base = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(rpc_ve3_base)) { + of_node_put(syscon_np); + return -EINVAL; + } + } +#endif + + ret = rpc_poll_init(); + ret = rpc_intr_init(); + ret = rpc_kern_init(); + ret = rpc_interrupt_init(np); + ret = rpc_fs_init(); + + dev_info(rpc_dev, "exit %s\n", __func__); +exit: + return ret; +} + +static int __maybe_unused rtk_rpc_remove(struct platform_device *pdev) +{ + return 0; +} + +#ifdef CONFIG_PM +/* + * Disable the interrupt from system to audio & video + */ +static int rtk_rpc_pm_suspend(struct device *dev) +{ + int max_count = 500; + +#ifdef CONFIG_RTK_XEN_SUPPORT + if (xen_domain() && !xen_initial_domain()) { + dev_info(dev, "skip %s in DomU\n"); + return 0; + } +#endif + dev_info(dev, "enter %s\n", __func__); + + rpc_set_flag(RPC_AUDIO, 0xdaedffff); /* STOP AUDIO HAS_CHECK */ + while ((rpc_get_flag(RPC_AUDIO) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + RPC_RESET_BIT(rpc_acpu_int_flag, RPC_AUDIO_SET_NOTIFY); /* Disable Interrupt */ + + wmb(); + + rpc_set_flag(RPC_AUDIO, 0xdeadffff); /* WAIT AUDIO RPC SUSPEND READY */ + while ((rpc_get_flag(RPC_AUDIO) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + dev_info(dev, "wait %d ms\n", (500 - max_count)); + + + dev_info(dev, "exit %s\n", __func__); + + return 0; +} + +static void rtk_rpc_pm_shutdown(struct platform_device *pdev) +{ + int max_count = 500; + struct device *dev = &pdev->dev; + + dev_info(dev, "enter %s\n", __func__); + + rpc_set_flag(RPC_AUDIO, 0xdaedffff); /* STOP AUDIO HAS_CHECK */ + while ((rpc_get_flag(RPC_AUDIO) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + + rpc_set_flag(RPC_VIDEO, 0xdaedffff); /* STOP VIDEO HAS_CHECK */ + while ((rpc_get_flag(RPC_VIDEO) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + + /* disable Interrupt */ + RPC_RESET_BIT(rpc_acpu_int_flag, RPC_AUDIO_SET_NOTIFY); + + /* disable interrupt */ + RPC_RESET_BIT(rpc_vcpu_int_flag, RPC_VIDEO_SET_NOTIFY); + + wmb(); + + rpc_set_flag(RPC_AUDIO, 0xdeadffff); /* WAIT AUDIO RPC SUSPEND READY */ + while ((rpc_get_flag(RPC_AUDIO) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + rpc_set_flag(RPC_VIDEO, 0xdaedffff); /* STOP VIDEO HAS_CHECK */ + while ((rpc_get_flag(RPC_VIDEO) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + dev_info(dev, "wait %d ms\n", (500 - max_count)); + dev_info(dev, "Exit %s\n", __func__); +} + +/* + * Enable the interrupt from system to audio & video + */ +static int rtk_rpc_pm_resume(struct device *dev) +{ +#ifdef CONFIG_RTK_XEN_SUPPORT + if (xen_domain() && !xen_initial_domain()) { + dev_info(dev, "skip %s in DomU\n", __func__); + return 0; + } +#endif + + dev_info(dev, "enter %s\n", __func__); + + RPC_SET_BIT(rpc_acpu_int_flag, RPC_AUDIO_SET_NOTIFY); + rpc_set_flag(RPC_AUDIO, 0xffffffff); + + dev_info(dev, "exit %s\n", __func__); + + return 0; +} + +static const struct dev_pm_ops rtk_rpc_pm_ops = { + .suspend_late = rtk_rpc_pm_suspend, + .resume_early = rtk_rpc_pm_resume, + .poweroff = rtk_rpc_pm_suspend, +#ifdef CONFIG_HIBERNATION + .freeze = rtk_rpc_pm_suspend, + .thaw = rtk_rpc_pm_resume, + .restore = rtk_rpc_pm_resume, +#endif +}; +#endif /* CONFIG_PM */ + +static struct of_device_id rtk_rpc_ids[] = { + {.compatible = "realtek,rpc" }, + {/* Sentinel */ }, +}; + +static struct platform_driver rtk_rpc_driver = { + .probe = rtk_rpc_probe, + .remove = rtk_rpc_remove, +#ifdef CONFIG_PM + .shutdown = rtk_rpc_pm_shutdown, +#endif /* CONFIG_PM */ + .driver = { + .name = "realtek-rpc", + .bus = &platform_bus_type, + .of_match_table = rtk_rpc_ids, +#ifdef CONFIG_PM + .pm = &rtk_rpc_pm_ops, +#endif /* CONFIG_PM */ + }, +}; + +static int rtk_rpc_init(void) +{ + return platform_driver_register(&rtk_rpc_driver); +} +device_initcall(rtk_rpc_init); diff --git a/drivers/soc/realtek/common/rpc/rtk_rpc.h b/drivers/soc/realtek/common/rpc/rtk_rpc.h new file mode 100644 index 000000000000..cec8af3537d0 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rtk_rpc.h @@ -0,0 +1,899 @@ +/* + * Realtek RPC driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + */ + +#ifndef _RTK_RPC_H +#define _RTK_RPC_H +#include +#include +#include +#include +#include + +#ifdef CONFIG_DEVFS_FS +#include +#endif +#include "soc/realtek/memory.h" + +#define MY_COPY + +extern const char *rpc_name; + +extern void __iomem *rpc_ringbuf_base; + +#define RPC_SB2_INT 0x0 +#define RPC_SB2_INT_EN 0x4 +#define RPC_SB2_INT_ST 0x8 + +#define RPC_INT_WRITE_1 1 +#define RPC_INT_SA (1 << 1) + +/* + * for Hank SoC + * RPC_INT_AS (1 << 1) + * for other SoC + * RPC_INT_AS (1 << 3) + */ +#define RPC_INT_VS (1 << 2) +#define RPC_INT_SV (1 << 2) +#define RPC_INT_SVE3 0x1 +#define RPC_INT_VE3S_ST (1 << 4) + + +#if 0 +#define __read_32bit_caller_register() \ +{ int __res; \ +__asm__ __volatile__( \ +"mov\t%0, lr\n\t" \ +: "=r" (__res)); \ +__res; \ +} +#endif + +#define CONFIG_REALTEK_RPC_PROGRAM_REGISTER +#define RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + +#define R_PROGRAM 98 +#define AUDIO_SYSTEM 201 +#define AUDIO_AGENT 202 +#define VIDEO_AGENT 300 +#define VENC_AGENT 400 + +#define KERNELID 98 +#define REPLYID 99 +#define RPC_AUDIO 0x0 +#define RPC_VIDEO 0x1 +#define RPC_VE3 0x2 +#define RPC_KCPU 0x3 +#define RPC_OK 0 +#define RPC_FAIL -1 + +#ifndef RPC_ID +#define RPC_ID 0x5566 +#endif + +#ifndef RPC_MAJOR +#define RPC_MAJOR 240 /* dynamic major by default */ +#endif + +#ifndef RPC_NR_DEVS + +/* + * 2 for S-A, + * 2 for A-S, + * 2 for S-V1, + * 2 for V1-S, + * 2 for S-V2, + * 2 for V2-S + */ +typedef enum { + RPC_POLL_DEV_SA_ID0, /* poll audio write */ + RPC_POLL_DEV_AS_ID1, /*poll audio read */ + RPC_POLL_DEV_SV1_ID2, /*poll video write */ + RPC_POLL_DEV_V1S_ID3, /*poll video read */ +// RPC_POLL_DEV_SV2_ID4, +// RPC_POLL_DEV_V2S_ID5, + RPC_POLL_DEV_TOTAL +} NUM_POLL_DEV; + +typedef enum { + RPC_INTR_DEV_SA_ID0, /* intr audio write */ + RPC_INTR_DEV_AS_ID1, /*intr audio read */ + RPC_INTR_DEV_SV1_ID2, /* intr video write */ + RPC_INTR_DEV_V1S_ID3, /* intr video read */ +// RPC_INTR_DEV_SV2_ID4, +// RPC_INTR_DEV_V2S_ID5, + RPC_INTR_DEV_TOTAL +} NUM_INTR_DEV; + +#ifdef CONFIG_REALTEK_RPC_VE3 +typedef enum { + RPC_INTR_DEV_SVE3_ID0, /* intr VE3 write */ + RPC_INTR_DEV_VE3S_ID1, /*intr VE3s read */ + RPC_INTR_VE3_DEV_TOTAL +} NUM_INTR_VE3_DEV; +#else +#define RPC_INTR_VE3_DEV_TOTAL 0 +#endif + +/* total ring buffer number */ +#define RPC_NR_DEVS (RPC_POLL_DEV_TOTAL + RPC_INTR_DEV_TOTAL) +#endif /* RPC_NR_DEVS */ + +#ifndef RPC_NR_PAIR +#define RPC_NR_PAIR 2 /* for interrupt and polling mode */ +#endif /* RPC_NR_PAIR */ + +#ifndef RPC_NR_KERN_DEVS +/* + * S-A, + * A-S, + * S-V1, + * V1-S, + * S-V2, + * V2-S + */ +typedef enum { + RPC_KERN_DEV_SA_ID0, /* kern audio write */ + RPC_KERN_DEV_AS_ID1, /* kern audio read */ + RPC_KERN_DEV_SV1_ID2, /* kern video write */ + RPC_KERN_DEV_V1S_ID3, /* kern video read */ + // RPC_KERN_DEV_SV2_ID4, + // RPC_KERN_DEV_V2S_ID5, + RPC_NR_KERN_DEVS /* total ring buffer number */ +} NUM_KERN_DEV; + +#ifdef CONFIG_REALTEK_RPC_VE3 +typedef enum { + RPC_KERN_DEV_SVE3_ID0, /* kern VE3 write */ + RPC_KERN_DEV_VE3S_ID1, /* kern VE3 read */ + RPC_NR_KERN_VE3_DEVS /* total ring buffer number */ +} NUM_KERN_VE3_DEV; +#else +#define RPC_NR_KERN_VE3_DEVS 0 +#endif + +//#define RPC_NR_KERN_DEVS 6 /* total ring buffer number */ +#endif /* RPC_NR_KERN_DEVS */ + +//extern void __iomem *rpc_rbussync_base; + +#if 0 +#define rtk_rpc_wmb(start, size) \ +do { \ +smp_mb(); \ +__flush_dcache_area(start, size); \ +writel(0x1234, rpc_rbussync_base); \ +smp_mb(); \ +} while (0) +#endif + +#define rtk_rpc_wmb(start, size) wmb() + +#if defined(CONFIG_ARCH_RTD129x) || defined(CONFIG_ARCH_RTD119X) +#define AVCPU_NOCACHE 0xa0000000 +#else +#define AVCPU_NOCACHE 0x0 +#endif + +#if 0 +#define AVCPU_SCPU_OFFSET (AVCPU_NOCACHE + RPC_RINGBUF_PHYS - \ + (unsigned long)RPC_RINGBUF_VIRT) +#endif + +#define AVCPU_SCPU_OFFSET (AVCPU_NOCACHE + RPC_RINGBUF_PHYS \ +- (unsigned long)rpc_ringbuf_base) +#define AVCPU2SCPU(x) ((char *)(x - AVCPU_SCPU_OFFSET)) +#define SCPU2AVCPU(x) ((unsigned long)x + AVCPU_SCPU_OFFSET) +#define RPCREAD32(addr) AVCPU2SCPU(addr) +#define RPCWRITE32(addr, val) \ +do { \ +AVCPU2SCPU(addr) = val; \ +} while (0) + +#ifndef RPC_RING_SIZE +#define RPC_RING_SIZE 512 /* size of ring buffer */ +#endif /* RPC_RING_SIZE */ + +#ifndef RPC_POLL_DEV_ADDR +#define RPC_POLL_DEV_ADDR (AVCPU_NOCACHE + 0x040FF000) +#endif /* RPC_POLL_DEV_ADDR */ + +#ifndef RPC_INTR_DEV_ADDR +#define RPC_INTR_DEV_ADDR (RPC_POLL_DEV_ADDR+RPC_RING_SIZE) +#endif /* RPC_INTR_DEV_ADDR */ + +#ifndef RPC_KERN_DEV_ADDR +#define RPC_KERN_DEV_ADDR (AVCPU_NOCACHE + 0x04100200) +#endif /* RPC_KERN_DEV_ADDR */ + +#ifndef RPC_RECORD_SIZE +#define RPC_RECORD_SIZE 64 /* size of ring buffer record */ +#endif /* RPC_RECORD_SIZE */ + +#ifndef RPC_POLL_RECORD_ADDR +#define RPC_POLL_RECORD_ADDR (AVCPU_NOCACHE + 0x04100000) +#endif /* RPC_POLL_RECORD_ADDR */ + +#ifndef RPC_INTR_RECORD_ADDR +#define RPC_INTR_RECORD_ADDR (RPC_POLL_RECORD_ADDR+RPC_RECORD_SIZE \ +*(RPC_NR_DEVS/RPC_NR_PAIR)) +#endif /* RPC_INTR_RECORD_ADDR */ + +#ifndef RPC_KERN_RECORD_ADDR +#define RPC_KERN_RECORD_ADDR (AVCPU_NOCACHE + 0x04100a00) +#endif /* RPC_KERN_RECORD_ADDR */ + +#ifdef CONFIG_REALTEK_RPC_VE3 +#ifndef RPC_INTR_VE3_RECORD_ADDR +#define RPC_INTR_VE3_RECORD_ADDR (AVCPU_NOCACHE + 0x04101800) +#endif /* RPC_INTR_VE3_RECORD_ADDR */ +#ifndef RPC_INTR_VE3_DEV_ADDR +#define RPC_INTR_VE3_DEV_ADDR (AVCPU_NOCACHE + 0x04101000) +#endif /* RPC_INTR_VE3_DEV_ADDR */ + +#ifndef RPC_KERN_VE3_RECORD_ADDR +#define RPC_KERN_VE3_RECORD_ADDR (AVCPU_NOCACHE + 0x04101880) +#endif /* RPC_KERN_VE3_RECORD_ADDR */ +#ifndef RPC_KERN_VE3_DEV_ADDR +#define RPC_KERN_VE3_DEV_ADDR (AVCPU_NOCACHE + 0x04101400) +#endif /* RPC_KERN_VE3_DEV_ADDR */ +#endif + +extern struct file_operations rpc_poll_fops; /* for poll mode */ +extern struct file_operations rpc_intr_fops; /* for intr mode */ +extern struct file_operations rpc_ctrl_fops; /* for ctrl mode */ + +extern struct file_operations *rpc_fop_array[]; + +/* + *struct RPC_STRUCT + *@uint32_t programID: program ID defined in IDL file + *@uint32_t versionID: version ID defined in IDL file + *@uint32_t procedureID: function ID defined in IDL file + *@uint32_t taskID: the caller's task ID, assign 0 if NONBLOCK_MODE + *@uint32_t sysTID: N/A + *@uint32_t sysPID: the callee's task ID + *@uint32_t parameterSize: packet's body size + *@uint32_t mycontext: return address of reply value + */ +typedef struct RPC_STRUCT { + uint32_t programID; + uint32_t versionID; + uint32_t procedureID; + uint32_t taskID; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + uint32_t sysTID; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + uint32_t sysPID; + uint32_t parameterSize; + uint32_t mycontext; +} RPC_STRUCT; + +/* + *struct RPC_SYNC_Struct + *@wait_queue_head_t waitQueue: for blocking read + */ +typedef struct RPC_SYNC_Struct { + wait_queue_head_t waitQueue; + struct rw_semaphore readSem; + struct rw_semaphore writeSem; +} RPC_SYNC_Struct; + +/* + *struct RPC_DEV + *@uint32_t ringBuf: buffer for interrupt mode + *@uint32_t ringStart: pointer to start of ring buffer + *@uint32_t ringEnd: pointer to end of ring buffer + *@volatile uint32_t ringIn: pointer to where next data will be inserted in + *the ring buffer + *@volatile uint32_t ringOut: pointer to where next data will + *be extracted from the ring buffer + */ + +#ifdef CONFIG_ARCH_RTD119X + +typedef struct RPC_DEV { /*size should be 64 bytes*/ + uint32_t ringBuf; + uint32_t ringStart; + uint32_t ringEnd; + volatile uint32_t ringIn; + volatile uint32_t ringOut; + /* scpu internal use */ + RPC_SYNC_Struct *ptrSync; + uint32_t reserved1[7]; +} RPC_DEV; + + +#else + +typedef struct RPC_DEV { /*size should be 64 bytes*/ + uint32_t ringBuf; + uint32_t ringStart; + uint32_t ringEnd; + volatile uint32_t ringIn; + volatile uint32_t ringOut; + /* scpu internal use */ + uint32_t reserved1; + RPC_SYNC_Struct *ptrSync; + uint32_t reserved2[8]; + +#if defined(CONFIG_CPU_V7) + uint32_t reserved3; +#endif + +} RPC_DEV; + +#endif + +/* + *struct RPC_DEV_EXTRA + *@volatile void *currProc: current process which handles rpc command + *@char *name: the rpc device name + *@struct list_head tasks: tasks that open this rpc device + *@struct tasklet_struct tasklet: schedule a tasklet for bottom half + *@volatile uint32_t nextRpc: points to next Rpc + *@spinlock_t lock: lock to protect data synchronization + *@struct device *sdev: struct device + */ +typedef struct RPC_DEV_EXTRA { + RPC_DEV *dev; + volatile void *currProc; + char *name; + struct list_head tasks; + struct tasklet_struct tasklet; + volatile uint32_t nextRpc; + spinlock_t lock; + struct device *sdev; +} RPC_DEV_EXTRA; + +/* + * struct RPC_THREAD + * maintain a list of threads in the same process + */ +typedef struct RPC_THREAD { + pid_t pid; + struct list_head list; +} RPC_THREAD; + +/* + * struct RPC_PROCESS + * @struct list_head threads: pids that share the same file descriptor + * + * maintain a list of processes that use the same RPC device + */ +typedef struct RPC_PROCESS { + pid_t pid; + wait_queue_head_t waitQueue; + RPC_DEV *dev; + RPC_DEV_EXTRA *extra; +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + struct list_head handlers; +#endif /* CONFIG_REALTEK_RPC_PROGRAM_REGISTER */ + struct list_head threads; + struct list_head list; + bool bStayActive; // If true, then FW will not be notified when process is destroyed. + bool bExit; +} RPC_PROCESS; + +struct RPC_RELEASE_LIST { + phys_addr_t paddr; + void *vaddr; + int pid; + int type; + char comm[TASK_COMM_LEN]; + struct dma_buf *rpc_dmabuf; + struct list_head list; +}; + + +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER +/* + * struct RPC_HANDLER + * maintain a list of handlers + */ +typedef struct RPC_HANDLER { + uint32_t programID; + struct list_head list; +} RPC_HANDLER; +#endif /* CONFIG_REALTEK_RPC_PROGRAM_REGISTER */ + +/* + * struct RPC_DBG_FLAG + * @uint32_t op: 0:get, 1:set + */ +typedef struct RPC_DBG_FLAG { + uint32_t op; + uint32_t flagValue; + uint32_t flagAddr; +} RPC_DBG_FLAG; + +extern int pid_max; + +#ifdef CONFIG_REALTEK_RPC_VE3 +extern RPC_DEV_EXTRA rpc_intr_extra[RPC_NR_DEVS/RPC_NR_PAIR + RPC_INTR_VE3_DEV_TOTAL]; +#else +extern RPC_DEV_EXTRA rpc_intr_extra[RPC_NR_DEVS/RPC_NR_PAIR]; +#endif + +extern RPC_DEV_EXTRA rpc_poll_extra[RPC_NR_DEVS/RPC_NR_PAIR]; +void rpc_dispatch(unsigned long data); + +#ifdef MY_COPY +//FIXME: accepts SCPU addr +static inline int my_memcpy(int *des, int *src, int size) +{ + +#if defined(CONFIG_CPU_V7) + _memcpy_fromio(des, src, size); + return 0; +#else + __memcpy_fromio(des, src, size); + return 0; +#endif + +} +#endif + +//FIXME: must use the same type of addr (AVCPU addr or SCPU addr) +static inline int __get_ring_data_size(uint32_t start, uint32_t end, + uint32_t in, uint32_t out) +{ + int32_t ringsize = end - start; + int32_t datasize = (ringsize + in - out) % ringsize; + + pr_debug("%s ringsize:%d datasize:%d start:%x end:%x in:%x out:%x\n", + __func__, ringsize, datasize, start, end, in, out); + return datasize; +} + +static inline int get_ring_data_size(RPC_DEV *dev) +{ + return __get_ring_data_size(dev->ringStart, dev->ringEnd, + dev->ringIn, dev->ringOut); +} + +/* + * get ring data in buf and return next data pointer + */ +//FIXME: out is AVCPU addr +static inline uint32_t get_ring_data(const char *func, RPC_DEV *dev, + uint32_t out, char *buf, int datasize) +{ + int size = __get_ring_data_size(dev->ringStart, dev->ringEnd, + dev->ringIn, out); + int tail = dev->ringEnd - out; + + if (size < datasize) { + pr_debug("%s: Size not enough %d < %d\n", func, size, datasize); + return 0; + } + + if (tail >= datasize) { +#ifdef MY_COPY + my_memcpy((int *)buf, (int *)AVCPU2SCPU(out), datasize); +#else + memcpy(buf, AVCPU2SCPU(out), datasize); +#endif + out += datasize; + } else { +#ifdef MY_COPY + my_memcpy((int *)buf, (int *)AVCPU2SCPU(out), tail); + my_memcpy((int *)(buf + tail), (int *)AVCPU2SCPU(dev->ringStart), + datasize - tail); +#else + memcpy(buf, AVCPU2SCPU(out), tail); + memcpy(buf + tail, AVCPU2SCPU(dev->ringStart), datasize - tail); +#endif + out = dev->ringStart + datasize - tail; + } + + return out; +} + +static inline void dump_ring_buffer(const char *func, RPC_DEV_EXTRA *extra) +{ + int i; + RPC_DEV *dev = extra->dev; + + char *bufaddr = AVCPU2SCPU(dev->ringStart); + pr_err("==*== %s Start:%p Out:%p next:%p In:%p End:%p size:%d %s ==*==\n", + func, AVCPU2SCPU(dev->ringStart), + AVCPU2SCPU(dev->ringOut), + AVCPU2SCPU(extra->nextRpc), + AVCPU2SCPU(dev->ringIn), + AVCPU2SCPU(dev->ringEnd), + get_ring_data_size(dev), + in_atomic() ? "atomic" : ""); + for (i = 0; i < RPC_RING_SIZE ; i += 16) { + uint32_t *addr = (uint32_t *)(bufaddr + i); + pr_err("%p: %08x %08x %08x %08x\n", + addr, ntohl(*(addr + 0)), + ntohl(*(addr + 1)), + ntohl(*(addr + 2)), + ntohl(*(addr + 3))); + } +} + +static inline void convert_rpc_struct(const char *func, RPC_STRUCT *rpc) +{ + rpc->programID = ntohl(rpc->programID); + rpc->versionID = ntohl(rpc->versionID); + rpc->procedureID = ntohl(rpc->procedureID); + rpc->taskID = ntohl(rpc->taskID); +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + rpc->sysTID = ntohl(rpc->sysTID); +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + rpc->sysPID = ntohl(rpc->sysPID); + rpc->parameterSize = ntohl(rpc->parameterSize); + rpc->mycontext = ntohl(rpc->mycontext); +} + +#include +extern struct refclk_device *refclk; +static inline void show_rpc_struct(const char *func, RPC_STRUCT *rpc) +{ +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + pr_debug("%s: program:%u version:%u procedure:%u taskID:%u sysTID:%u sysPID:%u size:%u context:%x 90k:%u %s\n", + func, rpc->programID, rpc->versionID, rpc->procedureID, rpc->taskID, rpc->sysTID, rpc->sysPID, + rpc->parameterSize, rpc->mycontext, (u32)refclk_get_counter(refclk), in_atomic() ? "atomic" : ""); +#else + pr_debug("%s: program:%u version:%u procedure:%u taskID:%u sysPID:%u size:%u context:%x 90k:u %s\n", + func, rpc->programID, rpc->versionID, rpc->procedureID, rpc->taskID, rpc->sysPID, rpc->parameterSize, + rpc->mycontext, (u32)refclk_get_counter(refclk), in_atomic() ? "atomic" : ""); +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ +} + +static inline void peek_rpc_struct(const char *func, RPC_DEV *dev, loff_t num) +{ + RPC_STRUCT rpc; + uint32_t pid; + uint32_t arg; + uint32_t out = dev->ringOut; + + out = get_ring_data(func, dev, out, (char *)&rpc, sizeof(RPC_STRUCT)); + if (out == 0) + return; + convert_rpc_struct(func, &rpc); + show_rpc_struct(func, &rpc); + + if (rpc.programID == AUDIO_AGENT && rpc.versionID == 0) { + //Parse more information here + } else if (rpc.programID == VIDEO_AGENT && rpc.versionID == 0) { + //Parse more information here + } else if (rpc.programID == R_PROGRAM && rpc.versionID == 0) { + out = get_ring_data(func, dev, out, (char *)&arg, sizeof(uint32_t)); + if (out == 0) + return; + arg = ntohl(arg); + if (rpc.procedureID == 1) + pr_debug("%s: alloc %u bytes\n", func, arg); + else + pr_debug("%s: free addr %x\n", func, arg); + } else if (rpc.programID == REPLYID && rpc.versionID == REPLYID) { + out = get_ring_data(func, dev, out, (char *)&pid, sizeof(uint32_t)); + if (out == 0) + return; + pid = ntohl(pid); + pr_debug("%s: reply to taskid:%u\n", func, pid); + } + + if (rpc.programID == REPLYID && rpc.versionID == REPLYID) + trace_rtk_rpc_peek_rpc_reply((struct rpc_struct_tp *)&rpc, + (u32)refclk_get_counter(refclk), num, pid); + else + trace_rtk_rpc_peek_rpc_request((struct rpc_struct_tp *)&rpc, + (u32)refclk_get_counter(refclk), num, rpc.taskID); +} + +#if 0 +static inline void update_currProc(RPC_DEV_EXTRA *extra, RPC_PROCESS *proc) +{ + extra->currProc = proc; +} + +//FIXME: accept AVCPU addr +static inline void update_nextRpc(RPC_DEV_EXTRA *extra, char *nextRpc) +{ + extra->nextRpc = nextRpc; +} + +static inline int rpc_done(RPC_DEV_EXTRA *extra) +{ + RPC_DEV *dev = extra->dev; + + return dev->ringOut == extra->nextRpc; +} + +static inline int ring_empty(RPC_DEV *dev) +{ + return dev->ringOut == dev->ringIn; +} + +static inline int need_dispatch(RPC_DEV_EXTRA *extra) +{ + //size is not zero and previous rpc is done + return extra->currProc == NULL && !ring_empty(extra->dev) && rpc_done(extra); +} +#else +#define update_currProc(extra, proc) \ +do { \ +extra->currProc = proc; \ +} while (0) + +#define update_nextRpc(extra, next) \ +do { \ +extra->nextRpc = next; \ +} while (0) + +#define rpc_done(extra) (extra->dev->ringOut == extra->nextRpc) + +#define ring_empty(dev) (dev->ringOut == dev->ringIn) + +#define need_dispatch(extra) (extra->currProc == NULL && !ring_empty(extra->dev) && rpc_done(extra)) +#endif + +static inline RPC_PROCESS *pick_one_proc(RPC_DEV_EXTRA *extra) +{ + RPC_PROCESS *proc = NULL; + + spin_lock_bh(&extra->lock); + if (!list_empty(&extra->tasks)) { + proc = list_first_entry(&extra->tasks, RPC_PROCESS, list); + pr_debug("%s:%d Pick process:%d\n", extra->name, __LINE__, proc->pid); + } else { + pr_debug("%s:%d No available process\n", extra->name, __LINE__); + } + spin_unlock_bh(&extra->lock); + return proc; +} + +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER +static inline RPC_PROCESS *pick_supported_proc(RPC_DEV_EXTRA *extra, + uint32_t programID) +{ + RPC_PROCESS *proc; + RPC_HANDLER *handler; + + spin_lock_bh(&extra->lock); + list_for_each_entry(proc, &extra->tasks, list) { + list_for_each_entry(handler, &proc->handlers, list) { + if (handler->programID == programID) { + spin_unlock_bh(&extra->lock); + pr_debug("%s:%d pid:%d supports programID:%u\n", __func__, + __LINE__, proc->pid, programID); + return proc; + } + } + } + spin_unlock_bh(&extra->lock); + pr_debug("%s:%d can't find any process supports programID:%u\n", __func__, + __LINE__, programID); + return NULL; +} +#endif /* CONFIG_REALTEK_RPC_PROGRAM_REGISTER */ + +static inline RPC_PROCESS *lookup_by_taskID(RPC_DEV_EXTRA *extra, + uint32_t taskID) +{ + pid_t pid; + RPC_PROCESS *proc = NULL; + struct task_struct *task; + + /* sanity check */ + if (unlikely(taskID >= pid_max)) { + pr_err("%s:%d invalid taskID:%u >= pid_max:%d\n", extra->name, + __LINE__, taskID, pid_max); + return NULL; + } + + task = find_task_by_pid_ns(taskID, &init_pid_ns); + if (task == NULL) { + pr_warn("%s:%d can't find_task_by_pid_ns! taskID:%u, thread may be dead\n", + extra->name, __LINE__, taskID); + + //BUG(); + + /* + * taskID may be dead, use it directly, risky!! + * the same taskID may exist in more than one thread list + */ + pid = taskID; + } else { + pid = task->tgid; + pr_debug("%s:%d find_task_by_pid_ns taskID:%u => pid:%d tgid:%d comm:%s\n", + extra->name, __LINE__, taskID, task->pid, task->tgid, task->comm); + } + + spin_lock_bh(&extra->lock); + list_for_each_entry(proc, &extra->tasks, list) { + pr_debug("%s:%d proc->pid:%d target-pid:%d\n", + extra->name, __LINE__, proc->pid, pid); + + if (proc->pid == pid) { + spin_unlock_bh(&extra->lock); + pr_debug("%s:%d found process:%d\n", extra->name, __LINE__, pid); + return proc; + } else { + RPC_THREAD *thread; + + list_for_each_entry(thread, &proc->threads, list) { + if (thread->pid == pid) { + spin_unlock_bh(&extra->lock); + pr_debug("%s:%d found thread:%d in process:%d\n", + extra->name, __LINE__, pid, proc->pid); + return proc; + } + } + } + } + spin_unlock_bh(&extra->lock); + pr_err("%s:%d taskID:%u never shows in thread list\n", + extra->name, __LINE__, taskID); + return NULL; +} + +/* lock before call this function */ +static inline int update_thread_list(RPC_DEV_EXTRA *extra, pid_t pid) +{ + RPC_PROCESS *proc = NULL; + RPC_PROCESS *proctmp; + RPC_THREAD *thread; + + spin_lock_bh(&extra->lock); + list_for_each_entry(proctmp, &extra->tasks, list) { + /* find the entry in read device task list with the same pid */ + if (proctmp->pid == pid) { + proc = proctmp; + break; + } + } + spin_unlock_bh(&extra->lock); + + /* no found, should not happen */ + if (proc == NULL) + return 0; + + /* current thread is main thread or the thread that open this device */ + if (current->pid == proc->pid) + return 0; + + spin_lock_bh(&extra->lock); + list_for_each_entry(thread, &proc->threads, list) { + /* current is already in thread list */ + if (thread->pid == current->pid) { + spin_unlock_bh(&extra->lock); + return 0; + } + } + spin_unlock_bh(&extra->lock); + + /* not found, so add new thread to list */ + thread = kmalloc(sizeof(RPC_THREAD), GFP_KERNEL); + if (thread == NULL) { + pr_err("%s: failed to allocate RPC_THREAD\n", __func__); + return -ENOMEM; + } + pr_debug("%s:%d add thread:%s,%d,%d to thread list of process:%d\n", + __func__, __LINE__, current->comm, current->pid, current->tgid, + proc->pid); + thread->pid = current->pid; + spin_lock_bh(&extra->lock); + list_add(&thread->list, &proc->threads); + spin_unlock_bh(&extra->lock); + + return 1; +} + +/* Prototypes for shared functions */ +#ifdef MY_COPY +int my_copy_to_user(int *des, int *src, int size); +int my_copy_from_user(volatile void __iomem *des, const void *src, int size); + +int my_copy_user(int *des, int *src, int size); +#endif + +int rpc_poll_init(void); +int rpc_poll_pause(void); +int rpc_poll_suspend(void); +int rpc_poll_resume(void); +void rpc_poll_cleanup(void); +int rpc_intr_init(void); +int rpc_intr_pause(void); +int rpc_intr_suspend(void); +int rpc_intr_resume(void); +void rpc_intr_cleanup(void); + +int rpc_kern_init(void); +int rpc_kern_pause(void); +int rpc_kern_suspend(void); +int rpc_kern_resume(void); +ssize_t rpc_kern_read(int opt, char *buf, size_t count); +ssize_t rpc_kern_write(int opt, const char *buf, size_t count); +#define RPC_DVR_MALLOC 0x1 +#define RPC_DVR_FREE 0x2 +#define RPC_SIO_INIT 0x3 + +typedef unsigned long (*FUNC_PTR)(unsigned long, unsigned long); +//int register_kernel_rpc(unsigned long command, FUNC_PTR ptr); + +extern volatile RPC_DEV *rpc_poll_devices; +extern volatile RPC_DEV *rpc_intr_devices; +extern volatile RPC_DEV *rpc_kern_devices; +#ifdef CONFIG_REALTEK_RPC_VE3 +extern volatile RPC_DEV *rpc_intr_ve3_devices; +extern volatile RPC_DEV *rpc_kern_ve3_devices; +#endif + +extern void __iomem *rpc_int_base; +extern void rpc_set_flag(int, uint32_t); + +/* Use 'k' as magic number */ +#define RPC_IOC_MAGIC 'k' + +/* + * S means "Set": through a ptr, + * T means "Tell": directly with the argument value + * G means "Get": reply by setting through a pointer + * Q means "Query": response is on the return value + * X means "eXchange": G and S atomically + * H means "sHift": T and Q atomically + */ +#define RPC_IOCTTIMEOUT _IO(RPC_IOC_MAGIC, 0) +#define RPC_IOCQTIMEOUT _IO(RPC_IOC_MAGIC, 1) +#define RPC_IOCTRESET _IO(RPC_IOC_MAGIC, 2) +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER +#define RPC_IOCTHANDLER _IO(RPC_IOC_MAGIC, 3) +#endif + + +struct S_RPC_IOC_PROCESS_CONFIG_0 { + int bStayActive; + int reserved[16-1]; +}; +#define RPC_IOC_PROCESS_CONFIG_0 _IOW(RPC_IOC_MAGIC, 4, struct S_RPC_IOC_PROCESS_CONFIG_0) +#define RPC_IOCTGETGPID _IOR(RPC_IOC_MAGIC, 6, int) +#define RPC_IOCTGETGTGID _IOR(RPC_IOC_MAGIC, 7, int) + +#define RPC_IOCTEXITLOOP _IO(RPC_IOC_MAGIC, 5) + +#define RPC_DBGREG_GET 0 +#define RPC_DBGREG_SET 1 +#define RPC_IOCTRGETDBGREG_A _IOWR(RPC_IOC_MAGIC, 0x10, RPC_DBG_FLAG) +#define RPC_IOCTRGETDBGREG_V _IOWR(RPC_IOC_MAGIC, 0x11, RPC_DBG_FLAG) +#define RPC_IOCTRGETDBGPRINT_V _IOWR(RPC_IOC_MAGIC, 0x12, RPC_DBG_FLAG) + +#define RPC_HAS_BIT(addr, bit) (readl(addr) & bit) +#define RPC_SET_BIT(addr,bit) (writel((readl(addr)|bit), addr)) +#define RPC_RESET_BIT(addr,bit) (writel((readl(addr)&~bit), addr)) + +#define VO_DC_SET_NOTIFY (__cpu_to_be32(1U << 16)) /* ACPU write */ +#define VO_DC_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 17)) +#define AUDIO_RPC_SET_NOTIFY (__cpu_to_be32(1U << 24)) /* ACPU write */ +#define AUDIO_RPC_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 25)) +#define VIDEO_RPC_SET_NOTIFY (__cpu_to_be32(1U << 0)) /* VCPU write */ +#define VIDEO_RPC_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 1)) + + +#define DC_VO_SET_NOTIFY (__cpu_to_be32(1U << 0)) /* SCPU write */ +#define DC_VO_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 1)) +#define RPC_AUDIO_SET_NOTIFY (__cpu_to_be32(1U << 8)) /* SCPU write */ +#define RPC_AUDIO_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 9)) +#define RPC_VIDEO_SET_NOTIFY (__cpu_to_be32(1U << 2)) /* SCPU write */ +#define RPC_VIDEO_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 3)) + +#ifdef CONFIG_REALTEK_RPC_VE3 +#define VE3_RPC_SET_NOTIFY (__cpu_to_be32(1U << 0)) /* VE3 write */ +#define VE3_RPC_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 1)) +#define RPC_VE3_SET_NOTIFY (__cpu_to_be32(1U << 2)) /* SCPU write */ +#define RPC_VE3_FEEDBACK_NOTIFY (__cpu_to_be32(1U << 3)) +#endif + +#endif /* _RTK_RPC_H */ diff --git a/drivers/soc/realtek/common/rpc/rtk_rpc_intr.c b/drivers/soc/realtek/common/rpc/rtk_rpc_intr.c new file mode 100644 index 000000000000..9bee7e8edfbb --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rtk_rpc_intr.c @@ -0,0 +1,2383 @@ +/* + * Realtek RPC driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "rtk_rpc.h" +#include "mem_allocator/ion.h" +#include +#include "rpc_mem.h" +#include + +enum ENUM_AUDIO_KERNEL_RPC_CMD { + ENUM_KERNEL_RPC_CREATE_AGENT, // 0 + ENUM_KERNEL_RPC_INIT_RINGBUF, + ENUM_KERNEL_RPC_PRIVATEINFO, + ENUM_KERNEL_RPC_RUN, + ENUM_KERNEL_RPC_PAUSE, + ENUM_KERNEL_RPC_SWITCH_FOCUS, // 5 + ENUM_KERNEL_RPC_MALLOC_ADDR, + ENUM_KERNEL_RPC_VOLUME_CONTROL, // AUDIO_CONFIG_COMMAND + ENUM_KERNEL_RPC_FLUSH, // AUDIO_RPC_SENDIO + ENUM_KERNEL_RPC_CONNECT, // AUDIO_RPC_CONNECTION + ENUM_KERNEL_RPC_SETREFCLOCK, // 10 // AUDIO_RPC_REFCLOCK + ENUM_KERNEL_RPC_DAC_I2S_CONFIG, // AUDIO_CONFIG_DAC_I2S + ENUM_KERNEL_RPC_DAC_SPDIF_CONFIG, // AUDIO_CONFIG_DAC_SPDIF + ENUM_KERNEL_RPC_HDMI_OUT_EDID, // AUDIO_HDMI_OUT_EDID_DATA + ENUM_KERNEL_RPC_HDMI_OUT_EDID2, // AUDIO_HDMI_OUT_EDID_DATA2 + ENUM_KERNEL_RPC_HDMI_SET, // 15 // AUDIO_HDMI_SET + ENUM_KERNEL_RPC_HDMI_MUTE, //AUDIO_HDMI_MUTE_INFO + ENUM_KERNEL_RPC_ASK_DBG_MEM_ADDR, + ENUM_KERNEL_RPC_DESTROY, + ENUM_KERNEL_RPC_STOP, + ENUM_KERNEL_RPC_CHECK_READY, // 20 // check if Audio get memory pool from AP + ENUM_KERNEL_RPC_GET_MUTE_N_VOLUME, // get mute and volume level + ENUM_KERNEL_RPC_EOS, + ENUM_KERNEL_RPC_ADC0_CONFIG, + ENUM_KERNEL_RPC_ADC1_CONFIG, + ENUM_KERNEL_RPC_ADC2_CONFIG, // 25 +#if defined(AUDIO_TV_PLATFORM) + ENUM_KERNEL_RPC_BBADC_CONFIG, + ENUM_KERNEL_RPC_I2SI_CONFIG, + ENUM_KERNEL_RPC_SPDIFI_CONFIG, +#endif // AUDIO_TV_PLATFORM + ENUM_KERNEL_RPC_HDMI_OUT_VSDB, + ENUM_VIDEO_KERNEL_RPC_CONFIG_TV_SYSTEM, + ENUM_VIDEO_KERNEL_RPC_CONFIG_HDMI_INFO_FRAME, + ENUM_VIDEO_KERNEL_RPC_QUERY_DISPLAY_WIN, + ENUM_VIDEO_KERNEL_RPC_PP_INIT_PIN, + ENUM_KERNEL_RPC_INIT_RINGBUF_AO, //need check this enum + ENUM_VIDEO_KERNEL_RPC_VOUT_EDID_DATA, + ENUM_KERNEL_RPC_AUDIO_POWER_SET, + ENUM_VIDEO_KERNEL_RPC_VOUT_VDAC_SET, + ENUM_VIDEO_KERNEL_RPC_QUERY_CONFIG_TV_SYSTEM, + ENUM_KERNEL_RPC_AUDIO_CONFIG, + ENUM_KERNEL_RPC_AIO_PRIVATEINFO, + ENUM_KERNEL_RPC_QUERY_FW_DEBUG_INFO, + ENUM_KERNEL_RPC_HDMI_RX_LATENCY_MEM, + ENUM_KERNEL_RPC_EQ_CONFIG, +}; + + +enum AUDIO_ENUM_PRIVAETINFO { + ENUM_PRIVATEINFO_AUDIO_FORMAT_PARSER_CAPABILITY = 0, + ENUM_PRIVATEINFO_AUDIO_DECODER_CAPABILITY = 1, + ENUM_PRIVATEINFO_AUDIO_CONFIG_CMD_BS_INFO = 2, + ENUM_PRIVATEINFO_AUDIO_CHECK_LPCM_ENDIANESS = 3, + ENUM_PRIVATEINFO_AUDIO_CONFIG_CMD_AO_DELAY_INFO = 4, + ENUM_PRIVATEINFO_AUDIO_AO_CHANNEL_VOLUME_LEVEL = 5, + ENUM_PRIVATEINFO_AUDIO_GET_FLASH_PIN = 6, + ENUM_PRIVATEINFO_AUDIO_RELEASE_FLASH_PIN = 7, + ENUM_PRIVATEINFO_AUDIO_GET_MUTE_N_VOLUME = 8, + ENUM_PRIVATEINFO_AUDIO_AO_MONITOR_FULLNESS = 9, + ENUM_PRIVATEINFO_AUDIO_CONTROL_FLASH_VOLUME = 10, + ENUM_PRIVATEINFO_AUDIO_CONTROL_DAC_SWITCH = 11, + ENUM_PRIVATEINFO_AUDIO_PREPROCESS_CONFIG = 12, + ENUM_PRIVATEINFO_AUDIO_CHECK_SECURITY_ID = 13, + ENUM_PRIVATEINFO_AUDIO_LOW_DELAY_PARAMETERS = 14, + ENUM_PRIVATEINFO_AUDIO_SET_NETWORK_JITTER = 15, + ENUM_PRIVATEINFO_AUDIO_GET_QUEUE_DATA_SIZE = 16, + ENUM_PRIVATEINFO_AUDIO_GET_SHARE_MEMORY_FROM_ALSA = 17, + ENUM_PRIVATEINFO_AUDIO_AI_CONNECT_ALSA = 18, + ENUM_PRIVATEINFO_AUDIO_SET_PCM_FORMAT = 19, + ENUM_PRIVATEINFO_AUDIO_DO_SELF_DESTROY_FLOW = 20, + ENUM_PRIVATEINFO_AUDIO_GET_SAMPLING_RATE = 21, + ENUM_PRIVATEINFO_AUDIO_SLAVE_TIMEOUT_THRESHOLD = 22, + ENUM_PRIVATEINFO_AUDIO_GET_GLOBAL_AO_INSTANCEID = 23, + ENUM_PRIVATEINFO_AUDIO_SET_CEC_PARAMETERS = 24, + ENUM_PRIVATEINFO_AUDIO_INIT_DBG_DUMP_MEM = 25, + ENUM_PRIVATEINFO_AUDIO_AI_GET_AO_FLASH_PIN = 26, + ENUM_PRIVATEINFO_AUDIO_AI_SET_AO_FLASH_PIN = 27, + ENUM_PRIVATEINFO_AUDIO_GET_PP_FREE_PINID = 28, + ENUM_PRIVATEINFO_AUDIO_HDMI_RX_CONNECT_TO_BT = 29, + ENUM_PRIVATEINFO_AUDIO_GET_BS_ERR_RATE = 30, + ENUM_PRIVATEINFO_AUDIO_SET_RESUME_IR_KEYS = 31, + ENUM_PRIVATEINFO_SET_GSTREAMER_PTS_ACC_MODE = 32, + ENUM_PRIVATEINFO_AUDIO_GET_BONDING_TYPE = 33, + ENUM_PRIVATEINFO_AUDIO_SHARE_MEMORY_FOR_PORTING_FIRMWARE = 34, + ENUM_PRIVATEINFO_AUDIO_SET_DVDPLAYER_AO_VERSION = 35, + ENUM_PRIVATEINFO_AUDIO_MS_PP_CERT = 36, + ENUM_PRIVATEINFO_AUDIO_TRIGGER_EVENT = 37, + ENUM_PRIVATEINFO_AUDIO_AI_NON_PCM_IN = 38, + ENUM_PRIVATEINFO_OMX_AUDIO_VERSION = 39, + ENUM_PRIVATEINFO_AUDIO_AI_PAD_IN = 40, + ENUM_PRIVATEINFO_AUDIO_MS_MAJOR_DECODER_PIN = 41, + ENUM_PRIVATEINFO_AUDIO_PROVIDE_RAWOUT_LATENCY = 42, + ENUM_PRIVATEINFO_AUDIO_MS_MIXER_IGNORE_PIN = 43, + ENUM_PRIVATEINFO_AUDIO_MS_CERTIFICATION_PLATFORM = 44, + ENUM_PRIVATEINFO_AUDIO_MS_MIXER_PIN_NEW_SEG = 45, + ENUM_PRIVATEINFO_AUDIO_MS_DEC_DROP_BY_PTS = 46, + ENUM_PRIVATEINFO_AUDIO_MS_DEC_INIT_PTS_OFFSET = 47, + ENUM_PRIVATEINFO_AUDIO_MS_PP_OUTPUT_TYPE = 48, + ENUM_PRIVATEINFO_AUDIO_DTS_ENCODER_CONFIG = 49, + ENUM_PRIVATEINFO_AUDIO_GET_FW_VERSION = 50, + ENUM_PRIVATEINFO_AUDIO_DTS_M8_IN_CONFIG = 51, + ENUM_PRIVATEINFO_AUDIO_DTS_M8_LA_NUM = 52, + ENUM_PRIVATEINFO_AUDIO_DTS_M8_SET_OUTPUT_FORMAT = 53, + ENUM_PRIVATEINFO_AUDIO_SET_DRC_CFG = 54, + ENUM_PRIVATEINFO_AUDIO_DTS_M8_LA_ERROR_MSG = 55, + ENUM_PRIVATEINFO_GET_B_VALUE = 56, + ENUM_PRIVATEINFO_AUDIO_ENTER_SUSPEND = 57, + ENUM_PRIVATEINFO_AUDIO_MPEGH_IN_CONFIG = 58, + ENUM_PRIVATEINFO_AUDIO_SET_LOW_WATERLEVEL = 59, +}; + + +struct AUDIO_RPC_PRIVATEINFO_PARAMETERS { + int instanceID; + enum AUDIO_ENUM_PRIVAETINFO type; + volatile int privateInfo[16]; +}; + +struct AUDIO_RPC_PRIVATEINFO_RETURNVAL { + int instanceID; + volatile int privateInfo[16]; +}; + +#define S_OK 0x10000000 + + +#define ion_alloc ext_rtk_ion_alloc + +/* + * dump ring buffer rate limiting: + * not more than 1 ring buffer dumping every 3s + */ +DEFINE_RATELIMIT_STATE(ring_dump_state, 3 * HZ, 1); +static DEFINE_SPINLOCK(rpc_release_lock); +static DEFINE_SPINLOCK(release_proc_lock); + +struct release_process_lists +{ + int pid; + int cnt; + struct list_head list; +}; + +struct release_process_lists release_proc_lists; + + +volatile RPC_DEV *rpc_intr_devices; + +#ifdef CONFIG_REALTEK_RPC_VE3 +volatile RPC_DEV *rpc_intr_ve3_devices; +#endif + +int rpc_intr_is_paused; +int rpc_intr_is_suspend; + +int timeout = HZ; //HZ / 40; /* jiffies */ + +#ifdef CONFIG_REALTEK_RPC_VE3 +RPC_DEV_EXTRA rpc_intr_extra[RPC_NR_DEVS/RPC_NR_PAIR + RPC_INTR_VE3_DEV_TOTAL]; +#else +RPC_DEV_EXTRA rpc_intr_extra[RPC_NR_DEVS/RPC_NR_PAIR]; +#endif + +extern struct device *rpc_dev; +extern int chip_id; +extern void rpc_send_interrupt(int type); + +struct RPC_RELEASE_LIST rpc_release_lists; +RPC_PROCESS *remote_proc; + +struct task_struct *acpu_r_program_kthread; +wait_queue_head_t acpu_r_program_waitQueue; +int acpu_r_program_flag = 0; + +struct task_struct *vcpu_r_program_kthread; +wait_queue_head_t vcpu_r_program_waitQueue; +int vcpu_r_program_flag = 0; + +#ifdef CONFIG_REALTEK_RPC_VE3 +struct task_struct *ve3_r_program_kthread; +wait_queue_head_t ve3_r_program_waitQueue; +int ve3_r_program_flag = 0; +#endif + +ssize_t r_program_read(RPC_DEV_EXTRA *extra, RPC_DEV *dev, char *buf, size_t count) +{ + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + int rpc_ring_size = dev->ringEnd - dev->ringStart; + + down_write(&dev->ptrSync->readSem); + + if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = rpc_ring_size + dev->ringIn - dev->ringOut; + + pr_debug("%s:%d ==going read== count:%zu avail:%d " + "ringOut:%x ringIn:%x nextRPC:%x", + extra->name, __LINE__, count, size, dev->ringOut, dev->ringIn, + extra->nextRpc); + + if (count > size) + count = size; + temp = dev->ringEnd - dev->ringOut; + wmb(); + + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), count); +#else + r = copy_to_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), count); +#endif /* MY_COPY */ + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + extra->name, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + ret = count; + ptmp = dev->ringOut + ((count+3) & 0xfffffffc); + if (ptmp == dev->ringEnd) + dev->ringOut = dev->ringStart; + else + dev->ringOut = ptmp; + + //pr_debug("RPC Read is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), temp); +#else + r = copy_to_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), temp); +#endif /* MY_COPY */ + + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + extra->name, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + count -= temp; + +#ifdef MY_COPY + r = my_copy_user((int *)(buf+temp), + (int *)AVCPU2SCPU(dev->ringStart), count); +#else + r = copy_to_user((int *)(buf+temp), + (int *)AVCPU2SCPU(dev->ringStart), count); +#endif /* MY_COPY */ + + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + extra->name, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + ret = (temp + count); + dev->ringOut = dev->ringStart+((count+3) & 0xfffffffc); + + //pr_debug("RPC Read is in 2nd kind...\n"); + } + spin_lock_bh(&extra->lock); + + if (rpc_done(extra)) { + pr_debug("%s: Previous RPC is done, unregister myself\n", extra->name); + update_currProc(extra, NULL); + } + + spin_unlock_bh(&extra->lock); + + if (need_dispatch(extra)) + tasklet_schedule(&(extra->tasklet)); + up_write(&dev->ptrSync->readSem); + return ret; +out: + pr_err("[%s] read error occur\n", __func__); + up_write(&dev->ptrSync->readSem); + return ret; + +} + + +ssize_t r_program_write(int opt, RPC_DEV_EXTRA *extra, RPC_DEV *dev, char *buf, size_t count) +{ + + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + RPC_STRUCT *rpc; + + rpc = (RPC_STRUCT *)(buf); + pr_debug("%s: program:%u version:%u procedure:%u taskID:%u sysTID:%u sysPID:%u size:%u context:%x 90k:%u %s\n", + __func__, ntohl(rpc->programID), ntohl(rpc->versionID), ntohl(rpc->procedureID), ntohl(rpc->taskID), ntohl(rpc->sysTID), ntohl(rpc->sysPID), + ntohl(rpc->parameterSize),ntohl(rpc->mycontext), (u32)refclk_get_counter(refclk), in_atomic() ? "atomic" : ""); + down_write(&dev->ptrSync->writeSem); + + if (dev->ringIn == dev->ringOut) + size = 0; // the ring is empty + else if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = RPC_RING_SIZE + dev->ringIn - dev->ringOut; + + if (count > (RPC_RING_SIZE - size - 1)) + goto out; + + temp = dev->ringEnd - dev->ringIn; + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count); +#else + r = ((int *)AVCPU2SCPU(dev->ringIn) != + memcpy((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count)); +#endif /* MY_COPY */ + if (r) { + ret = -EFAULT; + goto out; + } + ret += count; + ptmp = dev->ringIn + ((count+3) & 0xfffffffc); + + //asm("DSB"); + mb(); + + if (ptmp == dev->ringEnd) + dev->ringIn = dev->ringStart; + else + dev->ringIn = ptmp; + + pr_debug("RPC Write is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp); +#else + r = ((int *)AVCPU2SCPU(dev->ringIn) != + memcpy((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp)); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + count -= temp; + +#ifdef MY_COPY + r = my_copy_user((int *)AVCPU2SCPU(dev->ringStart), + (int *)(buf+temp), count); +#else + r = ((int *)AVCPU2SCPU(dev->ringStart) != memcpy((int *)AVCPU2SCPU(dev->ringStart), (int *)(buf+temp), count)); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + ret += (temp + count); + + //asm("DSB"); + mb(); + + dev->ringIn = dev->ringStart+((count+3) & 0xfffffffc); + + pr_debug("RPC Write is in 2nd kind...\n"); + } + + wmb(); + + + rpc_send_interrupt(opt); + + + up_write(&dev->ptrSync->writeSem); + return ret; +out: + pr_err("[%s]RingBuf full! RPC FW intr write ringIn pointer is : %p\n", __func__, AVCPU2SCPU(dev->ringIn)); + up_write(&dev->ptrSync->writeSem); + return ret; +} + + +phys_addr_t rtk_rpc_ion_pa(struct ion_buffer *buffer) +{ + unsigned long ret = -1UL; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + + mutex_lock(&buffer->lock); + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + mutex_unlock(&buffer->lock); + + ret = paddr; + + return ret; +} + +static void *rtk_rpc_ion_va(struct dma_buf *dmabuf) +{ + struct ion_buffer *buffer; + int ret = -1; + + ret = dma_buf_begin_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + + if (ret != 0) + return NULL; + + buffer = (struct ion_buffer *)dmabuf->priv; + + return buffer->vaddr; +} + +static void rtk_rpc_free_ion(struct dma_buf *dmabuf) +{ + pr_err("%s free ion buffer\n", __func__); + + dma_buf_put(dmabuf); +} + +#if 1 + +enum RPC_REMOTE_CMD { + RPC_REMOTE_CMD_ALLOC = 1, + RPC_REMOTE_CMD_FREE = 2, + RPC_REMOTE_CMD_ALLOC_SECURE_LEGACY = 3, /* legacy */ +}; + +struct fw_alloc_parameter_legacy { + uint32_t size; +} __attribute__((aligned(1))); + +struct fw_free_parameter { + uint32_t phys_addr; +} __attribute__((aligned(1))); + +enum E_FW_ALLOC_FLAGS { + eAlloc_Flag_SCPUACC = 1U << 31, + eAlloc_Flag_ACPUACC = 1U << 30, + eAlloc_Flag_HWIPACC = 1U << 29, + eAlloc_Flag_VE_SPEC = 1U << 28, + eAlloc_Flag_PROTECTED_AUDIO_POOL = 1U << 27, + eAlloc_Flag_PROTECTED_TP_POOL = 1U << 26, + eAlloc_Flag_PROTECTED_VO_POOL = 1U << 25, + eAlloc_Flag_PROTECTED_VIDEO_POOL = 1U << 24, + eAlloc_Flag_PROTECTED_AO_POOL = 1U << 23, + eAlloc_Flag_PROTECTED_METADATA_POOL = 1U << 22, + eAlloc_Flag_VCPU_FWACC = 1U << 21, + eAlloc_Flag_CMA = 1U << 20, + eAlloc_Flag_PROTECTED_FW_STACK = 1U << 19, + eAlloc_Flag_PROTECTED_EXT_BIT0 = 1U << 18, + eAlloc_Flag_PROTECTED_EXT_BIT1 = 1U << 17, + eAlloc_Flag_PROTECTED_EXT_BIT2 = 1U << 16, +}; + +struct fw_alloc_parameter { + uint32_t size; + uint32_t flags; /* enum E_FW_ALLOC_FLAGS */ +} __attribute__((aligned(1))); + +struct reply_fw_parameter { + uint32_t taskID; + uint32_t reply_value; +} __attribute__((aligned(1))); + + +bool is_AudioIntrRead(const RPC_DEV_EXTRA *extra) +{ + return (!strcmp(extra->name, "AudioIntrRead")) ? true : false; +} + +bool is_Video1IntrRead(const RPC_DEV_EXTRA *extra) +{ + return (!strcmp(extra->name, "Video1IntrRead")) ? true : false; +} + +#ifdef CONFIG_REALTEK_RPC_VE3 +bool is_VE3IntrRead(const RPC_DEV_EXTRA *extra) +{ + return (!strcmp(extra->name, "VE3IntrRead")) ? true : false; +} +#endif +RPC_DEV_EXTRA * get_write_extra(const RPC_DEV_EXTRA *extra) +{ + RPC_DEV_EXTRA * ret = NULL; + if (is_AudioIntrRead(extra)) { + ret = &rpc_intr_extra[0]; + } else if (is_Video1IntrRead(extra)) { + ret = &rpc_intr_extra[2]; + } +#ifdef CONFIG_REALTEK_RPC_VE3 + else if (is_VE3IntrRead(extra)) { + ret = &rpc_intr_extra[4]; + } +#endif + return ret; +} + +int get_opt(const RPC_DEV_EXTRA *extra) +{ + if (is_AudioIntrRead(extra)) + return RPC_AUDIO; + else if (is_Video1IntrRead(extra)) + return RPC_VIDEO; +#ifdef CONFIG_REALTEK_RPC_VE3 + else if (is_VE3IntrRead(extra)) + return RPC_VE3; +#endif + return 0;//RPC_FAIL; +} + +void endian_swap_32_read (void * buf, size_t size) +{ + if ((size%sizeof(int)) != 0) { + pr_err("%s : Illegal size %zu\n", __func__, size); + return; + } else { + unsigned int * pData = (unsigned int *) buf; + size_t i; + for (i=0; i<(size/sizeof(int));i++) { + pData[i] = ntohl(pData[i]); + } + } +} + +void endian_swap_32_write (void * buf, size_t size) +{ + if ((size%sizeof(int)) != 0) { + pr_err("%s : Illegal size %zu\n", __func__, size); + return; + } else { + unsigned int * pData = (unsigned int *) buf; + size_t i; + for (i=0; i<(size/sizeof(int));i++) { + pData[i] = htonl(pData[i]); + } + } +} + +unsigned int rpc_ion_alloc_handler_legacy (RPC_DEV_EXTRA *extra, bool bSecure, const struct fw_alloc_parameter_legacy * param) +{ +#define FW_ALLOC_SPEC_MASK 0xC0000000 +#define FW_ALLOC_VCPU_FWACC 0x40000000 +#define FW_ALLOC_VCPU_EXTRA 0x80000000 + unsigned int reply_value = 0; + do { + unsigned int fw_send_value = param->size; + size_t alloc_val = 0; + int handle = -1; + + unsigned int ion_alloc_heap_mask; + unsigned int ion_alloc_flags; + + if (bSecure) { + ion_alloc_heap_mask = RTK_ION_HEAP_MEDIA_MASK | RTK_ION_HEAP_SECURE_MASK; + ion_alloc_flags = ION_FLAG_PROTECTED_V2_VO_POOL | ION_FLAG_HWIPACC; + if (is_AudioIntrRead(extra)) + ion_alloc_flags |= ION_FLAG_ACPUACC; + } else { + ion_alloc_heap_mask = RTK_ION_HEAP_MEDIA_MASK; + ion_alloc_flags = ION_FLAG_NONCACHED | ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_ACPUACC; + } + + alloc_val = PAGE_ALIGN(fw_send_value & ~FW_ALLOC_SPEC_MASK); + + if (fw_send_value & FW_ALLOC_VCPU_FWACC) { + ion_alloc_flags |= ION_FLAG_VCPU_FWACC; + } + + if (fw_send_value & FW_ALLOC_VCPU_EXTRA) { + handle = ion_alloc(alloc_val, ion_alloc_heap_mask, ion_alloc_flags | ION_FLAG_CMA); + ion_alloc_flags |= ION_USAGE_ALGO_LAST_FIT; + } + + if (handle < 0) + handle = ion_alloc(alloc_val, ion_alloc_heap_mask, ion_alloc_flags); + + if (handle < 0) { + pr_err("[%s] ERROR: ion_alloc fail %d(heap:0x%x flags:0x%x)\n", __func__, + handle, ion_alloc_heap_mask, ion_alloc_flags); + reply_value = -1U; + break; + } + + { + struct r_program_entry * rpc_entry = kmalloc(sizeof(struct r_program_entry), GFP_KERNEL); + rpc_entry->next = NULL; + rpc_entry->rpc_dmabuf = dma_buf_get(handle); + rpc_entry->phys_addr = rtk_rpc_ion_pa(rpc_entry->rpc_dmabuf->priv); + rpc_entry->size = alloc_val; + r_program_add(rpc_entry); + + reply_value = rpc_entry->phys_addr; + + __close_fd(current->files, handle); + } + + pr_debug("[%s] ion_alloc addr : 0x%x (heap:0x%x flags:0x%x)\n", __func__, + reply_value, ion_alloc_heap_mask, ion_alloc_flags); + + } while (0); + return reply_value; +} + +unsigned int rpc_ion_alloc_handler(RPC_DEV_EXTRA *extra, const struct fw_alloc_parameter * param) +{ + unsigned int reply_value = 0; + do { + size_t alloc_size = param->size; + unsigned int alloc_flags = param->flags; + int handle = -1; + unsigned int ion_alloc_heap_mask = RTK_ION_HEAP_MEDIA_MASK | RTK_ION_HEAP_SECURE_MASK; + unsigned int ion_alloc_flags = 0; + + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_SCPUACC ) ? ION_FLAG_SCPUACC : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_ACPUACC ) ? ION_FLAG_ACPUACC : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_HWIPACC ) ? ION_FLAG_HWIPACC : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_VE_SPEC ) ? ION_FLAG_VE_SPEC : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_AUDIO_POOL ) ? ION_FLAG_PROTECTED_V2_AUDIO_POOL : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_TP_POOL ) ? ION_FLAG_PROTECTED_V2_TP_POOL : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_VO_POOL ) ? ION_FLAG_PROTECTED_V2_VO_POOL : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_VIDEO_POOL ) ? ION_FLAG_PROTECTED_V2_VIDEO_POOL : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_AO_POOL ) ? ION_FLAG_PROTECTED_V2_AO_POOL : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_METADATA_POOL ) ? ION_FLAG_PROTECTED_V2_METADATA_POOL : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_VCPU_FWACC ) ? ION_FLAG_VCPU_FWACC : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_CMA ) ? ION_FLAG_CMA : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_FW_STACK ) ? ION_FLAG_PROTECTED_V2_FW_STACK : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_EXT_BIT0 ) ? ION_FLAG_PROTECTED_EXT_BIT0 : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_EXT_BIT1 ) ? ION_FLAG_PROTECTED_EXT_BIT1 : 0; + ion_alloc_flags |= (alloc_flags & eAlloc_Flag_PROTECTED_EXT_BIT2 ) ? ION_FLAG_PROTECTED_EXT_BIT2 : 0; + + handle = ion_alloc(alloc_size, ion_alloc_heap_mask, ion_alloc_flags); + + if ((handle < 0 ) && (ion_alloc_flags & ION_FLAG_CMA)) { + ion_alloc_flags &= ~ION_FLAG_CMA; + handle = ion_alloc(alloc_size, ion_alloc_heap_mask, ion_alloc_flags); + } + + if (handle < 0) { + pr_err("[%s] ERROR: ion_alloc fail %d(heap:0x%x flags:0x%x)\n", __func__, + handle, ion_alloc_heap_mask, ion_alloc_flags); + reply_value = -1U; + break; + } + + { + struct r_program_entry * rpc_entry = kmalloc(sizeof(struct r_program_entry), GFP_KERNEL); + rpc_entry->next = NULL; + rpc_entry->rpc_dmabuf = dma_buf_get(handle); + rpc_entry->phys_addr = rtk_rpc_ion_pa(rpc_entry->rpc_dmabuf->priv); + rpc_entry->size = alloc_size; + r_program_add(rpc_entry); + + reply_value = rpc_entry->phys_addr; + + __close_fd(current->files, handle); + } + + pr_debug("[%s] ion_alloc addr : 0x%x (heap:0x%x flags:0x%x)\n", __func__, + reply_value, ion_alloc_heap_mask, ion_alloc_flags); + } while (0); + return reply_value; +} + +unsigned int rpc_ion_free_handler(RPC_DEV_EXTRA *extra, const struct fw_free_parameter * param) +{ + unsigned int reply_value = 0; + unsigned int phys_addr = param->phys_addr; + struct r_program_entry * rpc_entry = r_program_remove(phys_addr); + if (rpc_entry) { + rtk_rpc_free_ion(rpc_entry->rpc_dmabuf); + kfree(rpc_entry); + pr_debug("[%s] ion_free addr : 0x%x (reply_value : 0x%x)\n", __func__, phys_addr, reply_value); + reply_value = 0; + } else { + pr_err("[%s]cannot find rpc_entry to free:phys_addr:%x\n", __func__, phys_addr); + reply_value = -1U; + } + return reply_value; +} + +void rpc_ion_handler(RPC_DEV_EXTRA *extra) +{ + do { + unsigned int reply_value = 0; + RPC_STRUCT rpc_header; + RPC_STRUCT * rpc = &rpc_header; + enum RPC_REMOTE_CMD remote_cmd = 0; + + peek_rpc_struct(__func__, extra->dev, 0); + + if (r_program_read(extra, extra->dev, (char *) rpc, sizeof(RPC_STRUCT)) != sizeof(RPC_STRUCT)) { + pr_err("%s:%d\n", __func__, __LINE__); + break; + } + + endian_swap_32_read(rpc, sizeof(*rpc)); + + pr_debug("%s: program:%u version:%u procedure:%u taskID:%u sysTID:%u sysPID:%u size:%u context:%x 90k:%u %s\n", + __func__, (rpc->programID), (rpc->versionID), (rpc->procedureID), (rpc->taskID), (rpc->sysTID), (rpc->sysPID), + (rpc->parameterSize), (rpc->mycontext), (u32)refclk_get_counter(refclk), in_atomic() ? "atomic" : ""); + + if (rpc->parameterSize == 0) { + pr_err("%s: parameterSize is zero!!\n", __func__); + break; + } + + remote_cmd = (enum RPC_REMOTE_CMD) rpc->procedureID; + + switch (remote_cmd) { + case RPC_REMOTE_CMD_ALLOC_SECURE_LEGACY: + case RPC_REMOTE_CMD_ALLOC: + if (rpc->parameterSize == sizeof(struct fw_alloc_parameter_legacy)) { + bool bSecure = (remote_cmd == RPC_REMOTE_CMD_ALLOC_SECURE_LEGACY) ? true : false; + struct fw_alloc_parameter_legacy param; + + if (r_program_read(extra, extra->dev, (char *) ¶m, sizeof(param)) != sizeof(param)) { + pr_err("%s : read struct fw_alloc_parameter_legacy failed!\n", __func__); + break; + } + + endian_swap_32_read(¶m, sizeof(param)); + + reply_value = rpc_ion_alloc_handler_legacy(extra, bSecure, ¶m); + + } else if (rpc->parameterSize == sizeof(struct fw_alloc_parameter)) { + struct fw_alloc_parameter param; + + if (r_program_read(extra, extra->dev, (char *) ¶m, sizeof(param)) != sizeof(param)) { + pr_err("%s : read struct fw_alloc_parameter failed!\n", __func__); + break; + } + + endian_swap_32_read(¶m, sizeof(param)); + + reply_value = rpc_ion_alloc_handler(extra, ¶m); + } else { + pr_err("%s : parameterSize(%d) mismatch!\n", __func__, rpc->parameterSize); + break; + } + + rpc->mycontext &= 0xfffffffc; + break; + case RPC_REMOTE_CMD_FREE: + if (rpc->parameterSize == sizeof(struct fw_free_parameter)) { + struct fw_free_parameter param; + + if (r_program_read(extra, extra->dev, (char *) ¶m, sizeof(param)) != sizeof(param)) { + pr_err("%s : read struct fw_alloc_parameter failed!\n", __func__); + break; + } + + endian_swap_32_read(¶m, sizeof(param)); + + reply_value = rpc_ion_free_handler(extra, ¶m); + + + } else { + pr_err("%s : parameterSize(%d) mismatch!\n", __func__, rpc->parameterSize); + break; + } + rpc->mycontext &= 0xfffffffc; + break; + default: + reply_value = 0; + pr_err("%s : Unknow cmd 0x%x parameterSize = %d\n", __func__, remote_cmd, rpc->parameterSize); + break; + } + + { + /*Reply RPC*/ + RPC_DEV_EXTRA *extra_w = get_write_extra(extra); + struct { + RPC_STRUCT header; + struct reply_fw_parameter reply; + } __attribute__((aligned(1))) reply_rpc; + + reply_rpc.header.programID = REPLYID; + reply_rpc.header.versionID = REPLYID; + reply_rpc.header.procedureID = 0; + reply_rpc.header.taskID = 0; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + reply_rpc.header.sysTID = 0; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + reply_rpc.header.sysPID = 0; + reply_rpc.header.parameterSize = (unsigned int) sizeof(struct reply_fw_parameter); + reply_rpc.header.mycontext = rpc->mycontext; + reply_rpc.reply.taskID = rpc->taskID; + reply_rpc.reply.reply_value = reply_value; + + trace_rtk_rpc_peek_rpc_reply((struct rpc_struct_tp *)&reply_rpc.header, + (u32)refclk_get_counter(refclk), 0, rpc->taskID); + + endian_swap_32_write(&reply_rpc, sizeof(reply_rpc)); + + while (r_program_write( + get_opt(extra), extra_w, extra_w->dev, (char *) &reply_rpc, sizeof(reply_rpc)) != (sizeof(reply_rpc))) { + pr_err("[%s] r_program_write error...\n", __func__); + msleep(1); + } + } + //tasklet_schedule(&(extra->tasklet)); + break; + } while (0); +} + +#else + +void rpc_ion_handler(RPC_DEV_EXTRA *extra) +{ + int handle = -1; + phys_addr_t phys_addr; + unsigned long reply_value = 0; + char tmpbuf[sizeof(RPC_STRUCT) + sizeof(uint32_t)]; + uint32_t *tmp; + char replybuf[sizeof(RPC_STRUCT) + 2*sizeof(uint32_t)]; + RPC_STRUCT *rpc; + RPC_STRUCT *rrpc; + unsigned long map_addr; + RPC_DEV_EXTRA *extra_w; + r_program_entry_t *rpc_entry; + int opt = 0; + + if(!strcmp(extra->name, "AudioIntrRead")) { + extra_w = &rpc_intr_extra[0]; + opt = RPC_AUDIO; + } else if (!strcmp(extra->name, "Video1IntrRead")){ + extra_w = &rpc_intr_extra[2]; + opt = RPC_VIDEO; + } else if (!strcmp(extra->name, "VE3IntrRead") { + extra_w = &rpc_intr_extra[4]; + opt = RPC_VE3; + } + + pr_debug("[%s] handle %s rpc\n", extra->name); + if (r_program_read(extra, extra->dev, (char *) &tmpbuf, sizeof(RPC_STRUCT) + sizeof(uint32_t)) != (sizeof(RPC_STRUCT) + sizeof(uint32_t))) { + pr_err("[%s] remote allocate read error...\n", __func__); + return; + } + + rpc = (RPC_STRUCT *)(tmpbuf); + + //convert_rpc_struct(extra->name, rpc); + pr_debug("%s: program:%u version:%u procedure:%u taskID:%u sysTID:%u sysPID:%u size:%u context:%x 90k:%u %s\n", + __func__, ntohl(rpc->programID), ntohl(rpc->versionID), ntohl(rpc->procedureID), ntohl(rpc->taskID), ntohl(rpc->sysTID), ntohl(rpc->sysPID), + ntohl(rpc->parameterSize), ntohl(rpc->mycontext), (u32)refclk_get_counter(refclk), in_atomic() ? "atomic" : ""); + +{ +#if defined(CONFIG_ARCH_RTD129x) || defined(CONFIG_ARCH_RTD119X) + const bool match_old_mapping = true; +#else + const bool match_old_mapping = false; +#endif + enum RPC_REMOTE_CMD { + RPC_REMOTE_CMD_ALLOC = 1, + RPC_REMOTE_CMD_FREE = 2, + RPC_REMOTE_CMD_ALLOC_SECURE = 3, + } remote_cmd; + + size_t align; + size_t alloc_val; + unsigned int fw_send_value; + tmp = (uint32_t *)(tmpbuf + sizeof(RPC_STRUCT)); + + fw_send_value = ntohl(*tmp); + remote_cmd = (enum RPC_REMOTE_CMD) ntohl(rpc->procedureID); + + switch (remote_cmd) { + case RPC_REMOTE_CMD_ALLOC: + case RPC_REMOTE_CMD_ALLOC_SECURE: + { +#define FW_ALLOC_SPEC_MASK 0xC0000000 +#define FW_ALLOC_VCPU_FWACC 0x40000000 +#define FW_ALLOC_VCPU_EXTRA 0x80000000 + unsigned int ion_alloc_heap_mask; + unsigned int ion_alloc_flags; + + if (remote_cmd == RPC_REMOTE_CMD_ALLOC_SECURE) { + ion_alloc_heap_mask = RTK_ION_HEAP_MEDIA_MASK | RTK_ION_HEAP_SECURE_MASK; + ion_alloc_flags = ION_FLAG_PROTECTED_V2_VO_POOL | ION_FLAG_HWIPACC; + if (opt == RPC_AUDIO) + ion_alloc_flags |= ION_FLAG_ACPUACC; + } else { + ion_alloc_heap_mask = RTK_ION_HEAP_MEDIA_MASK; + ion_alloc_flags = ION_FLAG_NONCACHED | ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_ACPUACC; + } + + alloc_val = PAGE_ALIGN(fw_send_value & ~FW_ALLOC_SPEC_MASK); + + if (fw_send_value & FW_ALLOC_VCPU_FWACC) { + ion_alloc_flags |= ION_FLAG_VCPU_FWACC; + } + + if (fw_send_value & FW_ALLOC_VCPU_EXTRA) { + handle = ion_alloc(alloc_val, ion_alloc_heap_mask, ion_alloc_flags | ION_FLAG_CMA); + ion_alloc_flags |= ION_USAGE_ALGO_LAST_FIT; + } + + if (handle < 0) + handle = ion_alloc(alloc_val, ion_alloc_heap_mask, ion_alloc_flags); + + rpc->mycontext = htonl(ntohl(rpc->mycontext) & 0xfffffffc); + + if (handle < 0) { + pr_err("[%s] ERROR: ion_alloc fail %d(heap:0x%x flags:0x%x)\n", __func__, (int *) handle, ion_alloc_heap_mask, ion_alloc_flags); + reply_value = -1U; + break; + } + + rpc_entry = kmalloc(sizeof(struct r_program_entry), GFP_KERNEL); + rpc_entry->rpc_dmabuf = dma_buf_get(handle); + rpc_entry->phys_addr = rtk_rpc_ion_pa(rpc_entry->rpc_dmabuf->priv); + rpc_entry->size = alloc_val; + r_program_add(rpc_entry); + reply_value = rpc_entry->phys_addr; + + __close_fd(current->files, handle); + + if (match_old_mapping) + reply_value += 0x80000000; + pr_debug("[%s] ion_alloc addr : 0x%x (heap:0x%x flags:0x%x)\n", __func__, reply_value, ion_alloc_heap_mask, ion_alloc_flags); + } + + break; + case RPC_REMOTE_CMD_FREE: + { + phys_addr = fw_send_value; + if (match_old_mapping) + phys_addr -= 0x80000000; + + rpc_entry = r_program_remove(phys_addr); + + if (rpc_entry) { + rtk_rpc_free_ion(rpc_entry->rpc_dmabuf); + kfree(rpc_entry); + pr_debug("[%s] ion_free addr : 0x%x (reply_value : 0x%lx)\n", __func__, phys_addr, reply_value); + reply_value = 0; + } else { + pr_err("[%s]cannot find rpc_entry to free:phys_addr:%x\n", __func__, phys_addr); + reply_value = -1U; +#if 0 /* WORKAROUND : Avoid FW deadlock when phys_addr is illegal */ + return; +#endif + } + + rpc->mycontext = htonl(ntohl(rpc->mycontext) & 0xfffffffc); + } + break; + default: + break; + } +} + + /*Reply RPC*/ + rrpc = (RPC_STRUCT *)replybuf; + rrpc->programID = htonl(REPLYID); + rrpc->versionID = htonl(REPLYID); + rrpc->procedureID = 0; + rrpc->taskID = 0; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + rrpc->sysTID = 0; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + rrpc->sysPID = 0; + rrpc->parameterSize = htonl(2*sizeof(uint32_t)); + rrpc->mycontext = rpc->mycontext; + + /* fill the parameters... */ + tmp = (uint32_t *)(replybuf + sizeof(RPC_STRUCT)); + *(tmp+0) = rpc->taskID; /* FIXME: should be 64bit */ + *(tmp+1) = htonl(reply_value); + + if (r_program_write(opt, extra_w, extra_w->dev, (char *) &replybuf, sizeof(RPC_STRUCT) + 2*sizeof(uint32_t)) != (sizeof(RPC_STRUCT) + 2*sizeof(uint32_t))) { + pr_err("[%s] remote allocate reply error...\n", __func__); + return; + } + +} +#endif + +void add_release_list(int pid) +{ + struct release_process_lists *proc_entry; + struct release_process_lists *tmp_entry; + struct list_head *listptr; + + spin_lock_bh(&release_proc_lock); + list_for_each(listptr, &release_proc_lists.list) { + tmp_entry = list_entry(listptr, struct release_process_lists, list); + if (tmp_entry->pid == pid){ + spin_unlock_bh(&release_proc_lock); + return; + } + } + spin_unlock_bh(&release_proc_lock); + + proc_entry = kmalloc(sizeof(struct release_process_lists), GFP_KERNEL); + proc_entry->pid = pid; + proc_entry->cnt = 4; + + spin_lock_bh(&release_proc_lock); + list_add(&proc_entry->list, &release_proc_lists.list); + spin_unlock_bh(&release_proc_lock); +} + +void rm_release_list(int pid) +{ + struct list_head *listptr; + struct release_process_lists *entry; + + spin_lock_bh(&release_proc_lock); + list_for_each(listptr, &release_proc_lists.list) { + entry = list_entry(listptr, struct release_process_lists, list); + if (entry->pid == pid) { + entry->cnt--; + if (entry->cnt == 0) { + list_del(listptr); + kfree(entry); + } + spin_unlock_bh(&release_proc_lock); + return; + } + } + spin_unlock_bh(&release_proc_lock); +} + + + +int check_dead_process(int pid){ + + struct list_head *listptr; + struct release_process_lists *entry; + + spin_lock_bh(&release_proc_lock); + list_for_each(listptr, &release_proc_lists.list) { + entry = list_entry(listptr, struct release_process_lists, list); + if (entry->pid == pid) { + spin_unlock_bh(&release_proc_lock); + return 0; + } + } + spin_unlock_bh(&release_proc_lock); + return -EINVAL; +} + +void ignore_rpc(RPC_DEV_EXTRA *extra, uint32_t data_size) +{ + RPC_DEV *dev = extra->dev; + + dev->ringOut = dev->ringOut + sizeof(RPC_STRUCT) + data_size; + if (dev->ringOut >= dev->ringEnd) + dev->ringOut = dev->ringStart + (dev->ringOut - dev->ringEnd); +} + + +void handle_dead_process_reply(RPC_STRUCT rpc, RPC_DEV_EXTRA *extra) +{ + RPC_STRUCT *rrpc; + uint32_t *tmp; + char replybuf[sizeof(RPC_STRUCT) + 2*sizeof(uint32_t)]; + RPC_DEV_EXTRA *extra_w; + int opt; + + if (rpc.taskID == 0) { + ignore_rpc(extra, rpc.parameterSize); + return; + } + + if(!strcmp(extra->name, "AudioIntrRead")) { + extra_w = &rpc_intr_extra[0]; + opt = RPC_AUDIO; + } else if (!strcmp(extra->name, "Video1IntrRead")){ + extra_w = &rpc_intr_extra[2]; + opt = RPC_VIDEO; + } +#ifdef CONFIG_REALTEK_RPC_VE3 + else if (!strcmp(extra->name, "VE3IntrRead")){ + extra_w = &rpc_intr_extra[4]; + opt = RPC_VE3; + } +#endif + else { + return; + } + /*Reply RPC*/ + rrpc = (RPC_STRUCT *)replybuf; + rrpc->programID = htonl(REPLYID); + rrpc->versionID = htonl(REPLYID); + rrpc->procedureID = 0; + rrpc->taskID = 0; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + rrpc->sysTID = 0; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + rrpc->sysPID = 0; + rrpc->parameterSize = htonl(2*sizeof(uint32_t)); + rrpc->mycontext = htonl(rpc.mycontext); + + /* fill the parameters... */ + tmp = (uint32_t *)(replybuf + sizeof(RPC_STRUCT)); + *(tmp+0) = htonl(rpc.taskID); /* FIXME: should be 64bit */ + *(tmp+1) = htonl(0xdead); + + ignore_rpc(extra, rpc.parameterSize); + + if (r_program_write(opt, extra_w, extra_w->dev, (char *) &replybuf, sizeof(RPC_STRUCT) + 2*sizeof(uint32_t)) != (sizeof(RPC_STRUCT) + 2*sizeof(uint32_t))) { + pr_err("[%s] handle_dead_process_reply error...\n", __func__); + return; + } + +} + +static int acpu_remote_alloc_thread(void * p) +{ + RPC_DEV_EXTRA *extra = &rpc_intr_extra[1]; + + while (1) { + if (wait_event_interruptible(acpu_r_program_waitQueue, acpu_r_program_flag || kthread_should_stop())) { + pr_notice("%s got signal or should stop...\n", current->comm); + continue; + } + + if (kthread_should_stop()) { + pr_notice("%s exit...\n", current->comm); + break; + } + spin_lock_bh(&extra->lock); + acpu_r_program_flag = 0; + spin_unlock_bh(&extra->lock); + rpc_ion_handler(extra); + } + return 0; +} + + +static int vcpu_remote_alloc_thread(void * p) +{ + RPC_DEV_EXTRA *extra = &rpc_intr_extra[3]; + + while (1) { + if (wait_event_interruptible(vcpu_r_program_waitQueue, vcpu_r_program_flag || kthread_should_stop())) { + pr_notice("%s got signal or should stop...\n", current->comm); + continue; + } + + if (kthread_should_stop()) { + pr_notice("%s exit...\n", current->comm); + break; + } + spin_lock_bh(&extra->lock); + vcpu_r_program_flag = 0; + spin_unlock_bh(&extra->lock); + rpc_ion_handler(extra); + } + return 0; +} + +#ifdef CONFIG_REALTEK_RPC_VE3 +static int ve3_remote_alloc_thread(void * p) +{ + RPC_DEV_EXTRA *extra = &rpc_intr_extra[5]; + + while (1) { + if (wait_event_interruptible(ve3_r_program_waitQueue, ve3_r_program_flag || kthread_should_stop())) { + pr_notice("%s got signal or should stop...\n", current->comm); + continue; + } + + if (kthread_should_stop()) { + pr_notice("%s exit...\n", current->comm); + break; + } + spin_lock_bh(&extra->lock); + ve3_r_program_flag = 0; + spin_unlock_bh(&extra->lock); + rpc_ion_handler(extra); + } + return 0; +} +#endif + +/* + * This function may be called by tasklet and rpc_intr_read(), + * rpc_poll_read() + */ +void rpc_dispatch(unsigned long data) +{ + RPC_DEV_EXTRA *extra = (RPC_DEV_EXTRA *) data; + RPC_DEV *dev = extra->dev; + RPC_PROCESS *proc = NULL; + uint32_t out; + RPC_STRUCT rpc; + int found = 0; + uint32_t ringOut = dev->ringOut; + uint32_t ringIn = dev->ringIn; + uint32_t nextRpc = extra->nextRpc; + RPC_PROCESS *curr = (RPC_PROCESS *)extra->currProc; + int taskID = 0; + + pr_debug("==*==*==%s Out:%x next:%x In:%x size:%d %s==*==*==\n", + extra->name, ringOut, nextRpc, ringIn, get_ring_data_size(dev), in_atomic() ? "atomic" : ""); + if (curr != NULL || ringOut == ringIn || ringOut != nextRpc) { + pr_debug("%s: unable to disp. currProc:%d Out:%x next:%x " + "In:%x size:%d %s\n", + extra->name, curr ? curr->pid : 0, ringOut, nextRpc, ringIn, + get_ring_data_size(dev), in_atomic() ? "atomic" : ""); + if (curr != NULL && check_dead_process(curr->pid) == 0) { + pr_debug("[rpc_dispatch]: process has been closed. ignore RPC.\n"); + if (!rpc_done(extra)){ + dev->ringOut = extra->nextRpc; + } + spin_lock_bh(&extra->lock); + update_currProc(extra, NULL); + spin_unlock_bh(&extra->lock); + if (need_dispatch(extra)) { + tasklet_schedule(&(extra->tasklet)); + } + } + return; + } + + //peek_rpc_struct(extra->name, dev); + out = get_ring_data(extra->name, dev, ringOut, (char *) &rpc, + sizeof(RPC_STRUCT)); + if (out == 0) + return; + + convert_rpc_struct(extra->name, &rpc); + show_rpc_struct(__func__, &rpc); + + switch (rpc.programID) { + case R_PROGRAM: + pr_debug("%s: program:%u version:%u procedure:%u taskID:%u sysTID:%u sysPID:%u size:%u context:%x 90k:%u %s\n", + __func__, rpc.programID, rpc.versionID, rpc.procedureID, rpc.taskID, rpc.sysTID, rpc.sysPID, + rpc.parameterSize, rpc.mycontext, (u32)refclk_get_counter(refclk), in_atomic() ? "atomic" : ""); + + out += rpc.parameterSize; + if (out >= dev->ringEnd) + out = dev->ringStart + (out - dev->ringEnd); + if ((rpc.mycontext & 0x1) == 1) {/*audio remote allocate*/ + spin_lock_bh(&extra->lock); + update_nextRpc(extra, out); + update_currProc(extra, remote_proc); + acpu_r_program_flag = 1; + wake_up_interruptible(&acpu_r_program_waitQueue); + spin_unlock_bh(&extra->lock); + } else if ((rpc.mycontext & 0x1) == 0) {/*video remote allocate*/ + spin_lock_bh(&extra->lock); + update_nextRpc(extra, out); + update_currProc(extra, remote_proc); + vcpu_r_program_flag = 1; + wake_up_interruptible(&vcpu_r_program_waitQueue); + spin_unlock_bh(&extra->lock); + } else { + pr_err("[%s] Unknow Request Remote Allocate\n", __func__); + } + + return; + case AUDIO_AGENT: + case VIDEO_AGENT: + case VENC_AGENT: + proc = NULL; + /* use sysPID directly */ + if (rpc.sysPID > 0 && rpc.sysPID < pid_max) { + pr_info("[%s]lookup by sysPID:%d\n", __func__, rpc.sysPID); + taskID = rpc.sysPID; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + /* lookup pid by sysTID */ + } else if (rpc.sysTID > 0 && rpc.sysTID < pid_max) { + pr_info("[%s]lookup by sysTID:%d\n", __func__, rpc.sysTID); + taskID = rpc.sysTID; + } +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + else { + pr_err("PID is out of range: sysPID:%d sysTID:%d\n", rpc.sysPID, rpc.sysTID); + return; + } + proc = lookup_by_taskID(extra, taskID); + if (unlikely(proc == NULL)) { +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + proc = pick_supported_proc(extra, rpc.programID); +#else + proc = pick_one_proc(extra); +#endif + } + if (proc == NULL || check_dead_process(taskID) == 0) { + pr_err("[%s] cannot find process by pid(%d)", __func__, taskID); + handle_dead_process_reply(rpc, extra); + proc = NULL; + } + break; + case REPLYID: + if (rpc.versionID == REPLYID && + rpc.parameterSize >= sizeof(uint32_t)) { + uint32_t taskID; + if (get_ring_data(extra->name, dev, out, (char *) &taskID, + sizeof(uint32_t)) == 0) + return; + + taskID = ntohl(taskID); + pr_debug("[%s]Reply: %s:%d taskID:%u\n", __func__, extra->name, __LINE__, taskID); + proc = lookup_by_taskID(extra, taskID); + if (proc == NULL || check_dead_process(proc->pid) == 0) { + pr_err("%s: ignore RPC!! clear %s(%p) current process\n", + __func__, extra->name, dev); + ignore_rpc(extra, rpc.parameterSize); + proc = NULL; + } + } + break; + default: + if (in_atomic() && __ratelimit(&ring_dump_state)) { + pr_err("%s:%d invalid programID:%u!!! Out:%x next:%x In:%x\n", + __func__, __LINE__, rpc.programID, ringOut, nextRpc, + ringIn); + show_rpc_struct(extra->name, &rpc); + dump_ring_buffer(extra->name, extra); + } + return; + } + + if (proc) { + found = 1; + } else if (__ratelimit(&ring_dump_state)) { + pr_err("%s:%d can't find process for handling %s programID:%u\n", + extra->name, __LINE__, extra->name, rpc.programID); + show_rpc_struct(extra->name, &rpc); + } + + out += rpc.parameterSize; + if (out >= dev->ringEnd) + out = dev->ringStart + (out - dev->ringEnd); + + spin_lock_bh(&extra->lock); + update_nextRpc(extra, out); + + if (found) { + update_currProc(extra, proc); + wake_up_interruptible(&proc->waitQueue); + pr_debug("%s:%d ###Wakeup### proc:%p(%d) process:%p(%d) and \ + update nextRpc:%x for programID:%u\n", + extra->name, __LINE__, proc, proc ? proc->pid : 0, + extra->currProc, + extra->currProc ? ((RPC_PROCESS *)extra->currProc)->pid : 0, + extra->nextRpc, rpc.programID); + } else { + update_currProc(extra, NULL); + if (need_dispatch(extra)) { + tasklet_schedule(&(extra->tasklet)); + } + } + + spin_unlock_bh(&extra->lock); +} + +int rpc_intr_init(void) +{ + static int is_init; + int result = 0, i; + int j = 0; + is_init = 0; + + /* Create corresponding structures for each device. */ + rpc_intr_devices = (RPC_DEV *) AVCPU2SCPU(RPC_INTR_RECORD_ADDR); + + for (i = 0; i < RPC_INTR_DEV_TOTAL; i++) { + pr_debug("rpc_intr_device %d addr: %p\n", i, &rpc_intr_devices[i]); + rpc_intr_devices[i].ringBuf = RPC_INTR_DEV_ADDR + + i * RPC_RING_SIZE * 2; + + /* Initialize pointers... */ + rpc_intr_devices[i].ringStart = rpc_intr_devices[i].ringBuf; + rpc_intr_devices[i].ringEnd = rpc_intr_devices[i].ringBuf + + RPC_RING_SIZE; + rpc_intr_devices[i].ringIn = rpc_intr_devices[i].ringBuf; + rpc_intr_devices[i].ringOut = rpc_intr_devices[i].ringBuf; + + pr_debug("The %dth intr dev:\n", i); + pr_debug("RPC ringStart: %p\n", + AVCPU2SCPU(rpc_intr_devices[i].ringStart)); + pr_debug("RPC ringEnd: %p\n", + AVCPU2SCPU(rpc_intr_devices[i].ringEnd)); + pr_debug("RPC ringIn: %p\n", + AVCPU2SCPU(rpc_intr_devices[i].ringIn)); + pr_debug("RPC ringOut: %p\n", + AVCPU2SCPU(rpc_intr_devices[i].ringOut)); + + rpc_intr_extra[i].nextRpc = rpc_intr_devices[i].ringOut; + rpc_intr_extra[i].currProc = NULL; + + if (!is_init) { + rpc_intr_devices[i].ptrSync = kmalloc(sizeof(RPC_SYNC_Struct), + GFP_KERNEL); + kmemleak_not_leak(rpc_intr_devices[i].ptrSync); + + /* Initialize wait queue... */ + init_waitqueue_head(&(rpc_intr_devices[i].ptrSync->waitQueue)); + + /* Initialize sempahores... */ + init_rwsem(&rpc_intr_devices[i].ptrSync->readSem); + init_rwsem(&rpc_intr_devices[i].ptrSync->writeSem); + + rpc_intr_extra[i].dev = (void *) &rpc_intr_devices[i]; + INIT_LIST_HEAD(&rpc_intr_extra[i].tasks); + tasklet_init(&rpc_intr_extra[i].tasklet, rpc_dispatch, + (unsigned long) &rpc_intr_extra[i]); + spin_lock_init(&rpc_intr_extra[i].lock); + switch (i) { + case 0: + rpc_intr_extra[i].name = "AudioIntrWrite"; + break; + case 1: + rpc_intr_extra[i].name = "AudioIntrRead"; + break; + case 2: + rpc_intr_extra[i].name = "Video1IntrWrite"; + break; + case 3: + rpc_intr_extra[i].name = "Video1IntrRead"; + break; + case 4: + rpc_intr_extra[i].name = "Video2IntrWrite"; + break; + case 5: + rpc_intr_extra[i].name = "Video2IntrRead"; + break; + } + } + } + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + rpc_intr_ve3_devices = (RPC_DEV *) AVCPU2SCPU(RPC_INTR_VE3_RECORD_ADDR); + + for (i = 0; i < RPC_INTR_VE3_DEV_TOTAL; i++) { + pr_debug("rpc_intr_ve3_device %d addr: %p\n", i, &rpc_intr_ve3_devices[i]); + rpc_intr_ve3_devices[i].ringBuf = RPC_INTR_VE3_DEV_ADDR + + i * RPC_RING_SIZE; + + /* Initialize pointers... */ + rpc_intr_ve3_devices[i].ringStart = rpc_intr_ve3_devices[i].ringBuf; + rpc_intr_ve3_devices[i].ringEnd = rpc_intr_ve3_devices[i].ringBuf + + RPC_RING_SIZE; + rpc_intr_ve3_devices[i].ringIn = rpc_intr_ve3_devices[i].ringBuf; + rpc_intr_ve3_devices[i].ringOut = rpc_intr_ve3_devices[i].ringBuf; + + pr_debug("The %dth intr dev:\n", i + RPC_INTR_DEV_TOTAL); + pr_debug("RPC ringStart: %p\n", + AVCPU2SCPU(rpc_intr_ve3_devices[i].ringStart)); + pr_debug("RPC ringEnd: %p\n", + AVCPU2SCPU(rpc_intr_ve3_devices[i].ringEnd)); + pr_debug("RPC ringIn: %p\n", + AVCPU2SCPU(rpc_intr_ve3_devices[i].ringIn)); + pr_debug("RPC ringOut: %p\n", + AVCPU2SCPU(rpc_intr_ve3_devices[i].ringOut)); + + rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].nextRpc = rpc_intr_ve3_devices[i].ringOut; + rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].currProc = NULL; + + if (!is_init) { + rpc_intr_ve3_devices[i].ptrSync = kmalloc(sizeof(RPC_SYNC_Struct), + GFP_KERNEL); + kmemleak_not_leak(rpc_intr_ve3_devices[i].ptrSync); + + /* Initialize wait queue... */ + init_waitqueue_head(&(rpc_intr_ve3_devices[i].ptrSync->waitQueue)); + + /* Initialize sempahores... */ + init_rwsem(&rpc_intr_ve3_devices[i].ptrSync->readSem); + init_rwsem(&rpc_intr_ve3_devices[i].ptrSync->writeSem); + + rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].dev = (void *) &rpc_intr_ve3_devices[i]; + INIT_LIST_HEAD(&rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].tasks); + tasklet_init(&rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].tasklet, rpc_dispatch, + (unsigned long) &rpc_intr_extra[i + RPC_INTR_DEV_TOTAL]); + spin_lock_init(&rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].lock); + switch (i) { + case 0: + rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].name = "VE3IntrWrite"; + break; + case 1: + rpc_intr_extra[i + RPC_INTR_DEV_TOTAL].name = "VE3IntrRead"; + break; + } + } + } + } +#endif + init_waitqueue_head(&acpu_r_program_waitQueue); + acpu_r_program_kthread = kthread_run(acpu_remote_alloc_thread, (void *)&j, "acpu_r_program"); + + + init_waitqueue_head(&vcpu_r_program_waitQueue); + vcpu_r_program_kthread = kthread_run(vcpu_remote_alloc_thread, (void *)&j, "vcpu_r_program"); + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + init_waitqueue_head(&ve3_r_program_waitQueue); + ve3_r_program_kthread = kthread_run(ve3_remote_alloc_thread, (void *)&j, "ve3_r_program"); + } +#endif + is_init = 1; + rpc_intr_is_paused = 0; + rpc_intr_is_suspend = 0; + + remote_proc = kmalloc(sizeof(RPC_PROCESS), GFP_KERNEL | __GFP_ZERO); + remote_proc->pid = 0; + + INIT_LIST_HEAD(&rpc_release_lists.list); + INIT_LIST_HEAD(&release_proc_lists.list); + + dev_info(rpc_dev, "\033[31mrpc is not paused & suspended\033[m\n"); + + return result; +} + +int rpc_intr_pause(void) +{ + rpc_intr_is_paused = 1; + pr_info("\033[31mrpc is paused\033[m\n"); + return 0; +} + +int rpc_intr_suspend(void) +{ + rpc_intr_is_suspend = 1; + pr_info("\033[31mrpc is suspended\033[m\n"); + return 0; +} + +int rpc_intr_resume(void) +{ + rpc_intr_is_suspend = 0; + pr_info("\033[31mrpc is not suspended\033[m\n"); + return 0; +} + +void rpc_intr_cleanup(void) +{ + int i; + + /* Clean corresponding structures for each device. */ + if (rpc_intr_devices) { + /* Clean ring buffers. */ + for (i = 0; i < RPC_INTR_DEV_TOTAL; i++) { + //if (rpc_intr_devices[i].ringBuf) + //kfree(rpc_intr_devices[i].ringBuf); + kfree(rpc_intr_devices[i].ptrSync); + } + //kfree(rpc_intr_devices); + } + + return; +} + +#define AUDIO_ION_FLAG (ION_FLAG_NONCACHED |ION_FLAG_SCPUACC | ION_FLAG_ACPUACC) + + +int update_rpc_release_lists(int type) +{ + struct RPC_RELEASE_LIST *release_entry; + int handle = 0; + struct list_head *listptr; + struct RPC_RELEASE_LIST *tmp_entry; + int ret = 0; + + spin_lock_bh(&rpc_release_lock); + list_for_each(listptr, &rpc_release_lists.list) { + tmp_entry = list_entry(listptr, struct RPC_RELEASE_LIST, list); + if (tmp_entry->pid == current->tgid && tmp_entry->type == type){ + spin_unlock_bh(&rpc_release_lock); + return 0; + } + } + spin_unlock_bh(&rpc_release_lock); + + release_entry = kmalloc(sizeof(struct RPC_RELEASE_LIST), GFP_KERNEL); + if (!release_entry) { + pr_err("[%s] kmalloc failed\n", __func__); + ret = -ENOMEM; + goto free_entry; + } + strcpy(release_entry->comm, current->comm); + + release_entry->pid = current->tgid; + release_entry->type = type; + + handle = ion_alloc(4096, RTK_ION_HEAP_AUDIO_MASK, AUDIO_ION_FLAG); + if (handle < 0) { + pr_err("[%s] ion_alloc failed\n", __func__); + ret = -ENOMEM; + goto put_dma_buf; + } + + release_entry->rpc_dmabuf = dma_buf_get(handle); + + __close_fd(current->files, handle); + + release_entry->paddr = rtk_rpc_ion_pa(release_entry->rpc_dmabuf->priv); + if (release_entry->paddr == -1) { + pr_err("[%s] get paddr failed\n", __func__); + ret = -EINVAL; + goto put_dma_buf; + } + + release_entry->vaddr = rtk_rpc_ion_va(release_entry->rpc_dmabuf); + if (!release_entry->vaddr) { + pr_err("[%s] get vaddr failed\n", __func__); + ret = -EINVAL; + goto put_dma_buf; + } + spin_lock_bh(&rpc_release_lock); + list_add(&release_entry->list, &rpc_release_lists.list); + spin_unlock_bh(&rpc_release_lock); + + return 0; + +put_dma_buf: + dma_buf_put(release_entry->rpc_dmabuf); +free_entry: + kfree(release_entry); + + return ret; +} + +struct RPC_RELEASE_LIST *rpc_find_release_list(int type, int pid){ + + struct list_head *listptr; + struct RPC_RELEASE_LIST *entry; + + list_for_each(listptr, &rpc_release_lists.list) { + entry = list_entry(listptr, struct RPC_RELEASE_LIST, list); + if (entry->pid == pid && entry->type == type) { + list_del(listptr); + return entry; + } + } + return NULL; +} + +int rpc_intr_open(struct inode *inode, struct file *filp) +{ + int minor = MINOR(inode->i_rdev); + int rpc_type = minor / RPC_NR_PAIR; + int ret = 0; + + pr_debug("RPC intr open with minor number: %d\n", minor); + + if (!filp->private_data) { + RPC_PROCESS *proc = kmalloc(sizeof(RPC_PROCESS), GFP_KERNEL | __GFP_ZERO); + if (proc == NULL) { + pr_err("%s: failed to allocate RPC_PROCESS", __func__); + return -ENOMEM; + } + + if (minor < 8) { + proc->extra = &rpc_intr_extra[minor / RPC_NR_PAIR]; + } +#ifdef CONFIG_REALTEK_RPC_VE3 + else { + if (minor == 8) { + proc->extra = &rpc_intr_extra[4]; + } else if (minor == 9) { + proc->extra = &rpc_intr_extra[5]; + } + } +#endif + proc->dev = proc->extra->dev; + /* current->tgid = process id, current->pid = thread id */ + proc->pid = current->tgid; + proc->bStayActive = false; + init_waitqueue_head(&proc->waitQueue); + INIT_LIST_HEAD(&proc->threads); +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + INIT_LIST_HEAD(&proc->handlers); +#endif + spin_lock_bh(&proc->extra->lock); + list_add(&proc->list, &proc->extra->tasks); + spin_unlock_bh(&proc->extra->lock); + pr_debug("%s: Current process pid:%d tgid:%d => %d(%p) for %s(%p)\n", + __func__, current->pid, current->tgid, proc->pid, + &proc->waitQueue, proc->extra->name, proc->dev); + + filp->private_data = proc; + filp->f_pos = (loff_t) minor; + if (rpc_type == 1) + ret = update_rpc_release_lists(RPC_AUDIO); + else if (rpc_type == 3) + ret = update_rpc_release_lists(RPC_VIDEO); +#ifdef CONFIG_REALTEK_RPC_VE3 + else if (rpc_type == 5) + ret = update_rpc_release_lists(RPC_VE3); +#endif + if (ret) { + pr_err("%s: update_rpc_release_lists failed err:%d\n", __func__, ret); + return ret; + } + } + + /* Before we maybe sleep */ + //MOD_INC_USE_COUNT; + + return 0; /* success */ +} + +int RPC_DESTROY_AUDIO_FLOW(int pid, phys_addr_t paddr, void *vaddr) +{ + struct AUDIO_RPC_PRIVATEINFO_PARAMETERS *cmd = NULL; + struct AUDIO_RPC_PRIVATEINFO_RETURNVAL *res; + uint32_t RPC_ret; + int ret = -1; + phys_addr_t dat; + unsigned int offset; + + cmd = (struct AUDIO_RPC_PRIVATEINFO_PARAMETERS *)vaddr; + dat = paddr; + offset = get_rpc_alignment_offset(sizeof(struct AUDIO_RPC_PRIVATEINFO_PARAMETERS)); + res = (struct AUDIO_RPC_PRIVATEINFO_RETURNVAL *)((unsigned long)cmd + offset); + memset(cmd, 0, sizeof(struct AUDIO_RPC_PRIVATEINFO_PARAMETERS)); + cmd->instanceID = htonl(-1); + cmd->type = htonl(ENUM_PRIVATEINFO_AUDIO_DO_SELF_DESTROY_FLOW); + cmd->privateInfo[0] = htonl(pid); + + if (send_rpc_command(RPC_AUDIO, + ENUM_KERNEL_RPC_PRIVATEINFO, + dat, dat + offset, + &RPC_ret)) { + pr_err("[RPC] %s send RPC failed!\n", __func__); + } + + if (RPC_ret != S_OK) { + pr_err("[RPC] %s received RPC failed!\n", __func__); + goto exit; + } + +exit: + + return ret; +} + +int RPC_DESTROY_VIDEO_FLOW(int pid, phys_addr_t paddr, void *vaddr) +{ + uint32_t *pid_info; + uint32_t *res; + uint32_t RPC_ret; + int ret = -1; + phys_addr_t dat; + unsigned int offset; + + pid_info = (uint32_t *)vaddr; + dat = paddr; + offset = get_rpc_alignment_offset(sizeof(uint32_t)); + res = (uint32_t *)(pid_info + offset); + memset(pid_info, 0, sizeof(uint32_t)); + *pid_info = htonl(pid); + + if (send_rpc_command(RPC_VIDEO, + 170, + dat, dat + offset, + &RPC_ret)) { + pr_err("[RPC] %s send RPC failed!\n", __func__); + } + + if (RPC_ret != S_OK) { + pr_err("[RPC] %s received RPC failed!\n", __func__); + goto exit; + } +exit: + + return ret; +} + +int rpc_intr_release(struct inode *inode, struct file *filp) +{ +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + RPC_HANDLER *handler, *hdltmp; +#endif /* CONFIG_REALTEK_RPC_PROGRAM_REGISTER */ + RPC_THREAD *th, *thtmp; + int minor = MINOR(inode->i_rdev); + + RPC_PROCESS *proc = filp->private_data; + RPC_DEV_EXTRA *extra = proc->extra; + + spin_lock_bh(&extra->lock); + +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + /* unregister myself from handler list */ + list_for_each_entry_safe(handler, hdltmp, &proc->handlers, list) { + list_del(&handler->list); + kfree(handler); + } +#endif /* CONFIG_REALTEK_RPC_PROGRAM_REGISTER */ + + list_for_each_entry_safe(th, thtmp, &proc->threads, list) { + list_del(&th->list); + kfree(th); + } + + /* remove myself from task list*/ + list_del(&proc->list); + kfree(proc); + + spin_unlock_bh(&extra->lock); + + pr_debug("RPC intr close with minor number: %d\n", minor); + + //MOD_DEC_USE_COUNT; + + return 0; +} + +static int rpc_intr_flush(struct file *filp, fl_owner_t id) +{ + + struct RPC_RELEASE_LIST *rpc_release_entry = NULL; + + int minor = MINOR(filp->f_inode->i_rdev); + int rpc_type = minor / RPC_NR_PAIR; + + RPC_PROCESS *proc = filp->private_data; + RPC_DEV *dev = proc->dev; /* the first listitem */ + RPC_DEV_EXTRA *extra = proc->extra; + struct task_struct *task; + + if (file_count(filp) > 1) + return 0; + + add_release_list(proc->pid); + + if (extra->currProc == proc) { + pr_debug("%s: clear %s(%p) current process\n", __func__, + proc->extra->name, dev); + update_currProc(extra, NULL); + /* intr read device (ugly code)*/ + if (minor == 3 || minor == 7 || minor == 9) { + if (!rpc_done(extra)) { + pr_debug("%s: previous rpc hasn't finished, force clear!! ringOut %p => %p\n", + __func__, AVCPU2SCPU(dev->ringOut), + AVCPU2SCPU(extra->nextRpc)); + down_write(&dev->ptrSync->readSem); + dev->ringOut = extra->nextRpc; + up_write(&dev->ptrSync->readSem); + } + } + } + + spin_lock_bh(&rpc_release_lock); + if (rpc_type == 1) + rpc_release_entry = rpc_find_release_list(RPC_AUDIO, proc->pid); + else if (rpc_type == 3) + rpc_release_entry = rpc_find_release_list(RPC_VIDEO, proc->pid); +#ifdef CONFIG_REALTEK_RPC_VE3 + else if (rpc_type == 5) + rpc_release_entry = rpc_find_release_list(RPC_VE3, proc->pid); +#endif + spin_unlock_bh(&rpc_release_lock); + if (rpc_intr_is_paused) { + pr_err("rpc is paused, no self destroy: %d\n", proc->pid); + } else if (proc->bStayActive) { + pr_err("bStayActive is true, no self destroy: %d\n", proc->pid); + } else { + task = find_task_by_pid_ns(proc->pid, &init_pid_ns); + if (task != NULL && (task->flags & PF_SIGNALED)) + task = NULL; + + if (rpc_release_entry!=NULL && task == NULL) { + pr_err("self destroy in flush: %d extra->name:%s\n", proc->pid, extra->name); + if(!strcmp(extra->name, "AudioIntrRead")) { + RPC_DESTROY_AUDIO_FLOW(proc->pid, rpc_release_entry->paddr, rpc_release_entry->vaddr); + } else if (!strcmp(extra->name, "Video1IntrRead")) { + RPC_DESTROY_VIDEO_FLOW(proc->pid, rpc_release_entry->paddr, rpc_release_entry->vaddr); + } + } + } + if (rpc_release_entry!=NULL) { + dma_buf_end_cpu_access(rpc_release_entry->rpc_dmabuf, DMA_BIDIRECTIONAL); + dma_buf_put(rpc_release_entry->rpc_dmabuf); + kfree(rpc_release_entry); + } + + + rm_release_list(proc->pid); + + return 0; +} + +/* + * We don't need parameter f_pos here... + * note:rpc_intr_read support both blocking & nonblocking modes + */ +ssize_t rpc_intr_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + RPC_PROCESS *proc = filp->private_data; + RPC_DEV *dev = proc->dev; /* the first listitem */ + RPC_DEV_EXTRA *extra = proc->extra; + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + int rpc_ring_size = dev->ringEnd - dev->ringStart; + long k; + + //pr_debug("%s:%d thread:%s pid:%d tgid:%d device:%s\n", + //__func__, __LINE__, current->comm, current->pid, current->tgid, + //extra->name); + if (rpc_intr_is_paused) { + pr_err("RPCintr: someone access rpc intr during the pause...\n"); + pr_err("%s:%d buf:%p count:%lu EAGAIN\n", extra->name, __LINE__, buf, + count); + msleep(1000); + return -EAGAIN; + } + + if (need_dispatch(extra)) + tasklet_schedule(&(extra->tasklet)); + //pr_debug("%s: dev:%p currProc:%p\n", + //extra->name, dev, extra->currProc); + if ((extra->currProc != proc) || (ring_empty(dev))) { + if (filp->f_flags & O_NONBLOCK) + goto done; + +wait_again: + + k = wait_event_interruptible_timeout(proc->waitQueue, + (((extra->currProc == proc) && (!ring_empty(dev))) || proc->bExit), + timeout); + if (k == 0) + goto done; /* timeout */ + + //if (current->flags & PF_FREEZE) { + //refrigerator(PF_FREEZE); + //if (!signal_pending(current)) + //goto wait_again; + //} + + if (try_to_freeze()) { + if (!signal_pending(current)) + goto wait_again; + } + + if (signal_pending(current)) { + pr_debug("RPC deblock because of receiving a signal...\n"); + goto done; + } + + if (proc->bExit) { + pr_info("user request to exit\n"); + goto done; + } + } + + down_write(&dev->ptrSync->readSem); + + if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = rpc_ring_size + dev->ringIn - dev->ringOut; + + pr_debug("%s:%d ==going read== count:%zu avail:%d " + "ringOut:%x ringIn:%x nextRPC:%x", + extra->name, __LINE__, count, size, dev->ringOut, dev->ringIn, + extra->nextRpc); + peek_rpc_struct(__func__, dev, *f_pos); + + if (count > size) + count = size; + + + temp = dev->ringEnd - dev->ringOut; + wmb(); + + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_to_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), count); +#else + r = copy_to_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), count); +#endif /* MY_COPY */ + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + extra->name, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + ret = count; + ptmp = dev->ringOut + ((count+3) & 0xfffffffc); + if (ptmp == dev->ringEnd) + dev->ringOut = dev->ringStart; + else + dev->ringOut = ptmp; + + //pr_debug("RPC Read is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_to_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), temp); +#else + r = copy_to_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), temp); +#endif /* MY_COPY */ + + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + extra->name, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + count -= temp; + +#ifdef MY_COPY + r = my_copy_to_user((int *)(buf+temp), + (int *)AVCPU2SCPU(dev->ringStart), count); +#else + r = copy_to_user((int *)(buf+temp), + (int *)AVCPU2SCPU(dev->ringStart), count); +#endif /* MY_COPY */ + + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + extra->name, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + ret = (temp + count); + dev->ringOut = dev->ringStart+((count+3) & 0xfffffffc); + + //pr_debug("RPC Read is in 2nd kind...\n"); + } + + /* + * NOTE: we do not need spin lock here because we are protected by + * semaphore already + */ + spin_lock_bh(&extra->lock); + if (rpc_done(extra) && extra->currProc == proc) { + pr_debug("%s: Previous RPC is done, unregister myself\n", extra->name); + update_currProc(extra, NULL); + } + spin_unlock_bh(&extra->lock); + + /* process next rpc command if any */ + if (need_dispatch(extra)) + tasklet_schedule(&(extra->tasklet)); + + pr_debug("%s:%d pid:%d tgid:%d count:%lu actual:%ld ringOut:%x " + "ringIn:%x nextRpc:%x currProc:%p(%d)\n", + extra->name, __LINE__, current->pid, current->tgid, count, ret, + dev->ringOut, dev->ringIn, extra->nextRpc, extra->currProc, + extra->currProc ? ((RPC_PROCESS *)extra->currProc)->pid : 0); +out: + up_write(&dev->ptrSync->readSem); +done: + //pr_debug("RPC intr ringOut pointer is : 0x%8x\n", + // (int)AVCPU2SCPU(dev->ringOut)); + //pr_debug("%s:%d pid:%d reads %d bytes\n", + // extra->name, __LINE__, current->pid, ret); + return ret; +} + +/* + * We don't need parameter f_pos here... + * note: rpc_intr_write only support nonblocking mode + */ +ssize_t rpc_intr_write(struct file *filp, const char *buf, size_t count, + loff_t *f_pos) +{ + RPC_PROCESS *proc = filp->private_data; + RPC_DEV *dev = proc->dev; /* the first listitem */ + RPC_DEV_EXTRA *extra = proc->extra; + RPC_DEV_EXTRA *rextra = extra + 1; + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + int rpc_ring_size = dev->ringEnd - dev->ringStart; + + + //pr_debug("%s:%d buf:%p count:%u\n", __func__, __LINE__, buf, count); + + if (rpc_intr_is_paused) { + pr_err("RPCintr: someone access rpc intr during the pause...\n"); + pr_err("%s:%d buf:%p count:%lu EAGAIN\n", __func__, __LINE__, buf, + count); + msleep(1000); + return -EAGAIN; + } + + down_write(&dev->ptrSync->writeSem); + +#if 1 + /* + * Threads that share the same file descriptor should have the same tgid + * However, with uClibc pthread library, pthread_create() creates threads + * with pid == tgid So the tgid is not real tgid, we have to maintain the + * thread list that we can lookup later + */ + if (current->pid != proc->pid) + update_thread_list(rextra, proc->pid); +#endif + + if (ring_empty(dev)) + size = 0; /* the ring is empty */ + else if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = rpc_ring_size + dev->ringIn - dev->ringOut; + + //pr_debug("%s: count:%d space:%d\n", + // extra->name, count, rpc_ring_size - size - 1); + //pr_debug("%s: pid:%d tgid:%d\n", + // extra->name, current->pid, current->tgid); + + if (count > (rpc_ring_size - size - 1)) + goto out; + +#if 0 + if (access_ok(VERIFY_READ, buf, sizeof(RPC_STRUCT))) { + RPC_STRUCT *rpc = (RPC_STRUCT *)buf; + uint32_t programID = ntohl(rpc->programID); + + if (programID == AUDIO_SYSTEM || programID == REPLYID || programID == 97) { + rpc->versionID = htonl((u32)refclk_get_counter(refclk)); + } else { + pr_warn("%s: invalid programID:%u\n", __func__, programID); + } + } +#endif + + temp = dev->ringEnd - dev->ringIn; + + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count); +#else + r = copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count); +#endif /* MY_COPY */ + + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + __func__, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + ret += count; + ptmp = dev->ringIn + ((count+3) & 0xfffffffc); + + //asm("DSB"); + mb(); + + if (ptmp == dev->ringEnd) + dev->ringIn = dev->ringStart; + else + dev->ringIn = ptmp; + + //pr_debug("RPC Write is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp); +#else + r = copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp); +#endif /* MY_COPY */ + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + __func__, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + count -= temp; + +#ifdef MY_COPY + r = my_copy_from_user((int *)AVCPU2SCPU(dev->ringStart), (int *)(buf+temp), count); +#else + r = copy_from_user((int *)AVCPU2SCPU(dev->ringStart), (int *)(buf+temp), count); +#endif /* MY_COPY */ + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", + __func__, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + ret += (temp + count); + + //asm("DSB"); + mb(); + + dev->ringIn = dev->ringStart+((count+3) & 0xfffffffc); + //pr_debug("RPC Write is in 2nd kind...\n"); + } + + peek_rpc_struct(__func__, dev, *f_pos); + wmb(); + + /* notify all the processes in the wait queue */ + //wake_up_interruptible(&dev->waitQueue); + + /* use the "f_pos" of file object to store the device number */ + temp = (int) *f_pos; + //if (temp == 1) + if (temp == 1) { + rpc_send_interrupt(RPC_AUDIO); + } else if (temp == 5) { + rpc_send_interrupt(RPC_VIDEO); +#ifdef CONFIG_REALTEK_RPC_VE3 + } else if (temp == 8) { + rpc_send_interrupt(RPC_VE3); +#endif + } else { + pr_err("error device number..."); + } + + pr_debug("%s:%d thread:%s pid:%d tgid:%d device:%s\n", + __func__, __LINE__, current->comm, current->pid, + current->tgid, extra->name); + pr_debug("%s:%d buf:%p count:%lu actual:%ld\n", + __func__, __LINE__, buf, count, ret); +out: + //pr_debug("RPC intr ringIn pointer is : 0x%8x\n", + // (int)AVCPU2SCPU(dev->ringIn)); + up_write(&dev->ptrSync->writeSem); + return ret; +} + +long rpc_intr_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + pid_t g_pid; + pid_t g_tgid; + + while (rpc_intr_is_suspend) { + pr_warn("RPCintr: someone access rpc poll during the suspend!!!...\n"); + msleep(1000); + } + + switch (cmd) { + case RPC_IOCTTIMEOUT: + timeout = arg; + break; + case RPC_IOCQTIMEOUT: + return timeout; + case RPC_IOCTEXITLOOP: { + RPC_PROCESS *proc = filp->private_data; + proc->bExit = true; + wake_up_interruptible(&proc->waitQueue); + return 0; + } +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + case RPC_IOCTHANDLER: { + int found; + RPC_PROCESS *proc = filp->private_data; + RPC_DEV_EXTRA *extra = proc->extra; + RPC_HANDLER *handler; + + pr_debug("%s:%d : Register handler for programID:%lu\n", + __func__, __LINE__, arg); + found = 0; + list_for_each_entry(handler, &proc->handlers, list) { + if (handler->programID == arg) { + found = 1; + break; + } + } + + if (found) + break; + + /* not found, add to handler list */ + handler = kmalloc(sizeof(RPC_HANDLER), GFP_KERNEL); + if (handler == NULL) { + pr_err("%s: failed to allocate RPC_HANDLER", __func__); + return -ENOMEM; + } + handler->programID = arg; + spin_lock_bh(&extra->lock); + list_add(&handler->list, &proc->handlers); + spin_unlock_bh(&extra->lock); + pr_debug("%s:%d %s: Add handler pid:%d for programID:%lu\n", + __func__, __LINE__, proc->extra->name, proc->pid, arg); + break; + } +#endif /* CONFIG_REALTEK_RPC_PROGRAM_REGISTER */ + case RPC_IOC_PROCESS_CONFIG_0: + { + RPC_PROCESS *proc = filp->private_data; + struct S_RPC_IOC_PROCESS_CONFIG_0 config; + if (copy_from_user(&config, (void __user *)arg, sizeof(struct S_RPC_IOC_PROCESS_CONFIG_0))) { + pr_err("ERROR! %s cmd:RPC_IOC_PROCESS_CONFIG_0 copy_from_user failed\n", __func__); + return -ENOMEM; + } + if (proc == NULL) { + pr_err("ERROR! %s cmd:RPC_IOC_PROCESS_CONFIG_0 proc:%p\n", __func__, proc); + return -ENOMEM; + } + proc->bStayActive = (config.bStayActive > 0) ? true : false; + break; + } + case RPC_IOCTGETGPID: + g_tgid = task_tgid_nr(current); + pr_debug("[%s][RPC_IOCTGETGPID]get current global g_tgid:%d \n", __func__, g_tgid); + if(copy_to_user((int __user *)arg, &g_tgid, sizeof(g_tgid))) { + pr_err("failed to memcpy!!!!\n"); + return -1; + } + break; + + case RPC_IOCTGETGTGID: + g_pid = task_pid_nr(current); + pr_debug("[%s][RPC_IOCTGETGTGID]get current global g_pid:%d \n", __func__, g_pid); + if(copy_to_user((int __user *)arg, &g_pid, sizeof(g_tgid))) { + pr_err("failed to memcpy!!!!\n"); + return -1; + } + break; + + default: /* redundant, as cmd was checked against MAXNR */ + pr_err("%s:%d unsupported ioctl cmd:%x arg:%lx", __func__, + __LINE__, cmd, arg); + return -ENOTTY; + } + + return ret; +} + +struct file_operations rpc_intr_fops = { + //.llseek = scull_llseek, + .unlocked_ioctl = rpc_intr_ioctl, + .compat_ioctl = rpc_intr_ioctl, + .read = rpc_intr_read, + .write = rpc_intr_write, + .open = rpc_intr_open, + .release = rpc_intr_release, + .flush = rpc_intr_flush, +}; diff --git a/drivers/soc/realtek/common/rpc/rtk_rpc_kern.c b/drivers/soc/realtek/common/rpc/rtk_rpc_kern.c new file mode 100644 index 000000000000..ce84a85ccf81 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rtk_rpc_kern.c @@ -0,0 +1,734 @@ +/* + * Realtek RPC driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "rtk_rpc.h" + +#define TIMEOUT (5*HZ) + +extern int chip_id; + +static struct radix_tree_root kernel_rpc_tree = RADIX_TREE_INIT(RPC, GFP_ATOMIC); +//static struct semaphore kernel_rpc_sem; +DECLARE_RWSEM(kernel_rpc_sem); + +//static DECLARE_MUTEX(kernel_rpc_sem); + +volatile RPC_DEV *rpc_kern_devices; +int rpc_kern_is_paused; +int rpc_kern_is_suspend; +#ifdef CONFIG_REALTEK_RPC_VE3 +volatile RPC_DEV *rpc_kern_ve3_devices; +struct task_struct *rpc_kthread[(RPC_NR_KERN_DEVS + RPC_NR_KERN_VE3_DEVS)/RPC_NR_PAIR] = {NULL}; +static wait_queue_head_t rpc_wq[(RPC_NR_KERN_DEVS + RPC_NR_KERN_VE3_DEVS)/RPC_NR_PAIR]; +static uint32_t *rpc_retval[(RPC_NR_KERN_DEVS + RPC_NR_KERN_VE3_DEVS)/RPC_NR_PAIR] = {NULL}; +static int complete_condition[(RPC_NR_KERN_DEVS + RPC_NR_KERN_VE3_DEVS)/RPC_NR_PAIR]; +static struct mutex rpc_kern_lock[(RPC_NR_KERN_DEVS + RPC_NR_KERN_VE3_DEVS)/RPC_NR_PAIR]; +#else +struct task_struct *rpc_kthread[RPC_NR_KERN_DEVS/RPC_NR_PAIR] = {NULL}; +static wait_queue_head_t rpc_wq[RPC_NR_KERN_DEVS/RPC_NR_PAIR]; +static uint32_t *rpc_retval[RPC_NR_KERN_DEVS/RPC_NR_PAIR] = {NULL}; +static int complete_condition[RPC_NR_KERN_DEVS/RPC_NR_PAIR]; +static struct mutex rpc_kern_lock[RPC_NR_KERN_DEVS/RPC_NR_PAIR]; + +#endif +static int rpc_kernel_thread(void *p); + +extern void rpc_send_interrupt(int type); + +int rpc_kern_init(void) +{ + static int is_init; + int result = 0, num; + unsigned long i; + + is_init = 0; + + /* Create corresponding structures for each device. */ + rpc_kern_devices = (RPC_DEV *)AVCPU2SCPU(RPC_KERN_RECORD_ADDR); + + num = RPC_NR_KERN_DEVS; + for (i = 0; i < num; i++) { + pr_debug("rpc_kern_device %lu addr: %p\n", i, &rpc_kern_devices[i]); + rpc_kern_devices[i].ringBuf = RPC_KERN_DEV_ADDR + i*RPC_RING_SIZE; + + /* Initialize pointers... */ + rpc_kern_devices[i].ringStart = rpc_kern_devices[i].ringBuf; + rpc_kern_devices[i].ringEnd = + rpc_kern_devices[i].ringBuf + RPC_RING_SIZE; + rpc_kern_devices[i].ringIn = rpc_kern_devices[i].ringBuf; + rpc_kern_devices[i].ringOut = rpc_kern_devices[i].ringBuf; + + pr_debug("The %luth kern dev:\n", i); + pr_debug("RPC ringStart: %p\n", + AVCPU2SCPU(rpc_kern_devices[i].ringStart)); + pr_debug("RPC ringEnd: %p\n", + AVCPU2SCPU(rpc_kern_devices[i].ringEnd)); + pr_debug("RPC ringIn: %p\n", + AVCPU2SCPU(rpc_kern_devices[i].ringIn)); + pr_debug("RPC ringOut: %p\n", + AVCPU2SCPU(rpc_kern_devices[i].ringOut)); + pr_debug("\n"); + + if (!is_init) { + rpc_kern_devices[i].ptrSync = + kmalloc(sizeof(RPC_SYNC_Struct), GFP_KERNEL); + kmemleak_not_leak(rpc_kern_devices[i].ptrSync); + + /* Initialize wait queue... */ + init_waitqueue_head(&(rpc_kern_devices[i].ptrSync->waitQueue)); + + /* Initialize sempahores... */ + init_rwsem(&rpc_kern_devices[i].ptrSync->readSem); + init_rwsem(&rpc_kern_devices[i].ptrSync->writeSem); + } + + if (i%RPC_NR_PAIR == 1) { + if (rpc_kthread[i/RPC_NR_PAIR] == NULL) + rpc_kthread[i/RPC_NR_PAIR] = + kthread_run(rpc_kernel_thread, + (void *)i, "rpc-%lu", i); + } + } +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + /* Create corresponding structures for each device. */ + rpc_kern_ve3_devices = (RPC_DEV *)AVCPU2SCPU(RPC_KERN_VE3_RECORD_ADDR); + + num = RPC_NR_KERN_VE3_DEVS; + for (i = 0; i < num; i++) { + pr_debug("rpc_kern_device %lu addr: %p\n", i, &rpc_kern_ve3_devices[i]); + rpc_kern_ve3_devices[i].ringBuf = RPC_KERN_VE3_DEV_ADDR + i*RPC_RING_SIZE; + + /* Initialize pointers... */ + rpc_kern_ve3_devices[i].ringStart = rpc_kern_ve3_devices[i].ringBuf; + rpc_kern_ve3_devices[i].ringEnd = + rpc_kern_ve3_devices[i].ringBuf + RPC_RING_SIZE; + rpc_kern_ve3_devices[i].ringIn = rpc_kern_ve3_devices[i].ringBuf; + rpc_kern_ve3_devices[i].ringOut = rpc_kern_ve3_devices[i].ringBuf; + + pr_debug("The %luth kern dev:\n", i + RPC_NR_KERN_DEVS); + pr_debug("RPC ringStart: %p\n", + AVCPU2SCPU(rpc_kern_ve3_devices[i].ringStart)); + pr_debug("RPC ringEnd: %p\n", + AVCPU2SCPU(rpc_kern_ve3_devices[i].ringEnd)); + pr_debug("RPC ringIn: %p\n", + AVCPU2SCPU(rpc_kern_ve3_devices[i].ringIn)); + pr_debug("RPC ringOut: %p\n", + AVCPU2SCPU(rpc_kern_ve3_devices[i].ringOut)); + pr_debug("\n"); + + if (!is_init) { + rpc_kern_ve3_devices[i].ptrSync = + kmalloc(sizeof(RPC_SYNC_Struct), GFP_KERNEL); + kmemleak_not_leak(rpc_kern_ve3_devices[i].ptrSync); + + /* Initialize wait queue... */ + init_waitqueue_head(&(rpc_kern_ve3_devices[i].ptrSync->waitQueue)); + + /* Initialize sempahores... */ + init_rwsem(&rpc_kern_ve3_devices[i].ptrSync->readSem); + init_rwsem(&rpc_kern_ve3_devices[i].ptrSync->writeSem); + } + + if (i%RPC_NR_PAIR == 1) { + if (rpc_kthread[(i + RPC_NR_KERN_DEVS)/RPC_NR_PAIR] == NULL) + rpc_kthread[(i + RPC_NR_KERN_DEVS)/RPC_NR_PAIR] = + kthread_run(rpc_kernel_thread, + (void *)((i + RPC_NR_KERN_DEVS)/RPC_NR_PAIR), "rpc-%lu", (i + RPC_NR_KERN_DEVS)/RPC_NR_PAIR); + } + } + } +#endif + if (!is_init) { + for (i = 0; i < RPC_NR_KERN_DEVS/RPC_NR_PAIR; i++) { + init_waitqueue_head(&(rpc_wq[i])); + mutex_init(&rpc_kern_lock[i]); + } +#ifdef CONFIG_REALTEK_RPC_VE3 + if (chip_id == CHIP_ID_RTD1619B) { + for (i = RPC_NR_KERN_DEVS/RPC_NR_PAIR; i < (RPC_NR_KERN_DEVS+RPC_NR_KERN_VE3_DEVS)/RPC_NR_PAIR; i++) { + init_waitqueue_head(&(rpc_wq[i])); + mutex_init(&rpc_kern_lock[i]); + } + } +#endif + } + is_init = 1; + rpc_kern_is_paused = 0; + rpc_kern_is_suspend = 0; + + return result; +} + +int rpc_kern_pause(void) +{ + rpc_kern_is_paused = 1; + return 0; +} + +int rpc_kern_suspend(void) +{ + rpc_kern_is_suspend = 1; + return 0; +} + +int rpc_kern_resume(void) +{ + rpc_kern_is_suspend = 0; + return 0; +} + +ssize_t rpc_kern_read(int opt, char *buf, size_t count) +{ + RPC_DEV *dev; + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (opt == RPC_VE3) { + dev = (RPC_DEV *)&rpc_kern_ve3_devices[1]; + } else { + dev = (RPC_DEV *)&rpc_kern_devices[opt*RPC_NR_PAIR+1]; + } +#else + dev = (RPC_DEV *)&rpc_kern_devices[opt*RPC_NR_PAIR+1]; +#endif + + pr_debug("read rpc_kern_device: %p\n", dev); + down_write(&dev->ptrSync->readSem); + + if (dev->ringIn == dev->ringOut) + goto out; // the ring is empty... + else if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = RPC_RING_SIZE + dev->ringIn - dev->ringOut; + + if (count > size) + count = size; + + temp = dev->ringEnd - dev->ringOut; + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_user((int *)buf, + (int *)AVCPU2SCPU(dev->ringOut), count); +#else + r = ((int *)buf != + memcpy((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), count)); +#endif /* MY_COPY */ + if (r) { + ret = -EFAULT; + goto out; + } + ret += count; + ptmp = dev->ringOut + ((count+3) & 0xfffffffc); + if (ptmp == dev->ringEnd) + dev->ringOut = dev->ringStart; + else + dev->ringOut = ptmp; + + pr_debug("RPC Read is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), temp); +#else + r = ((int *)buf != + memcpy((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), temp)); +#endif /* MY_COPY */ + if (r) { + ret = -EFAULT; + goto out; + } + count -= temp; + +#ifdef MY_COPY + r = my_copy_user((int *)(buf+temp), + (int *)AVCPU2SCPU(dev->ringStart), count); +#else + r = ((int *)(buf+temp) != + memcpy((int *)(buf+temp), + (int *)AVCPU2SCPU(dev->ringStart), count)); +#endif /* MY_COPY */ + if (r) { + ret = -EFAULT; + goto out; + } + ret += (temp + count); + dev->ringOut = dev->ringStart+((count+3) & 0xfffffffc); + + pr_debug("RPC Read is in 2nd kind...\n"); + } +out: + pr_debug("RPC kern ringOut pointer is : %p\n", AVCPU2SCPU(dev->ringOut)); + up_write(&dev->ptrSync->readSem); + return ret; +} + +ssize_t rpc_kern_write(int opt, const char *buf, size_t count) +{ + RPC_DEV *dev; + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (opt == RPC_VE3) { + dev = (RPC_DEV *)&rpc_kern_ve3_devices[0]; + } else { + dev = (RPC_DEV *)&rpc_kern_devices[opt*RPC_NR_PAIR]; + } +#else + dev = (RPC_DEV *)&rpc_kern_devices[opt*RPC_NR_PAIR]; +#endif + + pr_debug("write rpc_kern_device: %p\n", dev); + //pr_debug("[rpc_kern_write] write rpc_kern_device: caller%x, *buf:0x%x\n", + // (unsigned int) __read_32bit_caller_register(), + // *(unsigned int *)buf); + down_write(&dev->ptrSync->writeSem); + + if (dev->ringIn == dev->ringOut) + size = 0; // the ring is empty + else if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = RPC_RING_SIZE + dev->ringIn - dev->ringOut; + + if (count > (RPC_RING_SIZE - size - 1)) + goto out; + + temp = dev->ringEnd - dev->ringIn; + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count); +#else + r = ((int *)AVCPU2SCPU(dev->ringIn) != + memcpy((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count)); +#endif /* MY_COPY */ + if (r) { + ret = -EFAULT; + goto out; + } + ret += count; + ptmp = dev->ringIn + ((count+3) & 0xfffffffc); + + //asm("DSB"); + mb(); + + if (ptmp == dev->ringEnd) + dev->ringIn = dev->ringStart; + else + dev->ringIn = ptmp; + + pr_debug("RPC Write is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp); +#else + r = ((int *)AVCPU2SCPU(dev->ringIn) != + memcpy((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp)); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + count -= temp; + +#ifdef MY_COPY + r = my_copy_user((int *)AVCPU2SCPU(dev->ringStart), + (int *)(buf+temp), count); +#else + r = ((int *)AVCPU2SCPU(dev->ringStart) != memcpy((int *)AVCPU2SCPU(dev->ringStart), (int *)(buf+temp), count)); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + ret += (temp + count); + + //asm("DSB"); + mb(); + + dev->ringIn = dev->ringStart+((count+3) & 0xfffffffc); + + pr_debug("RPC Write is in 2nd kind...\n"); + } + + //if (opt == RPC_AUDIO) + if (opt == RPC_AUDIO) { + rpc_send_interrupt(RPC_AUDIO); + } else if (opt == RPC_VIDEO) { + rpc_send_interrupt(RPC_VIDEO); +#ifdef CONFIG_REALTEK_RPC_VE3 + } else if (opt == RPC_VE3) { + rpc_send_interrupt(RPC_VE3); +#endif + } else { + pr_err("error device number...\n"); + } +out: + pr_debug("RPC kern ringIn pointer is : %p\n", AVCPU2SCPU(dev->ringIn)); + up_write(&dev->ptrSync->writeSem); + return ret; +} + +#if 0 +int register_kernel_rpc(unsigned long command, FUNC_PTR ptr) +{ + int error; + + error = radix_tree_preload(GFP_KERNEL); + if (error == 0) { + down_write(&kernel_rpc_sem); + error = radix_tree_insert(&kernel_rpc_tree, command, (void *)ptr); + if (error) + pr_err("RPC: register kernel rpc %ld error...\n", command); + up_write(&kernel_rpc_sem); + radix_tree_preload_end(); + } + + return error; +} +#endif + +uint32_t handle_command(uint32_t command, uint32_t param1, uint32_t param2) +{ + FUNC_PTR ptr; + int ret = 0; + + pr_info("Handle command %x, param1: %x, param2: %x...\n", + command, param1, param2); + down_write(&kernel_rpc_sem); + ptr = radix_tree_lookup(&kernel_rpc_tree, command); + if (ptr) + ret = ptr(param1, param2); + else + pr_err("RPC: lookup kernel rpc %d error...\n", command); + up_write(&kernel_rpc_sem); + + return ret; +} + +static int rpc_kernel_thread(void *p) +{ + char readbuf[sizeof(RPC_STRUCT) + 3*sizeof(uint32_t)]; + RPC_DEV *dev; + RPC_STRUCT *rpc; + uint32_t *tmp; + unsigned long idx = (unsigned long)p; + unsigned int opt = idx / RPC_NR_PAIR; + + //daemonize(current->comm); + +#ifdef CONFIG_REALTEK_RPC_VE3 + if (idx >= 4) + dev = (RPC_DEV *)&rpc_kern_ve3_devices[idx - 4]; + else +#endif + dev = (RPC_DEV *)&rpc_kern_devices[idx]; + + while (1) { + //if (current->flags & PF_FREEZE) + //refrigerator(PF_FREEZE); + //try_to_freeze(); + + //pr_info(" #@# wait %s %x %x \n", current->comm, dev, dev->waitQueue); + if (wait_event_interruptible(dev->ptrSync->waitQueue, dev->ringIn != + dev->ringOut || kthread_should_stop())) { + pr_notice("%s got signal or should stop...\n", current->comm); + continue; + } + //pr_info(" #@# wakeup %s \n", current->comm); + + if (kthread_should_stop()) { + pr_notice("%s exit...\n", current->comm); + break; + } + + /* read the reply data... */ + if (rpc_kern_read(opt, readbuf, sizeof(RPC_STRUCT)) != + sizeof(RPC_STRUCT)) { + pr_err("ERROR in read opt(%d) kernel RPC...\n", opt); + continue; + } + + rpc = (RPC_STRUCT *)readbuf; + tmp = (uint32_t *)(readbuf + sizeof(RPC_STRUCT)); + if (rpc->taskID) { + /* handle the request... */ + char replybuf[sizeof(RPC_STRUCT) + 2*sizeof(uint32_t)]; + uint32_t ret; + RPC_STRUCT *rrpc = (RPC_STRUCT *)replybuf; + + /* read the payload... */ + if (rpc_kern_read(opt, readbuf + sizeof(RPC_STRUCT), + 3*sizeof(uint32_t)) != 3*sizeof(uint32_t)) { + pr_err("ERROR in read payload...\n"); + continue; + } + + ret = handle_command(ntohl(*tmp), + ntohl(*(tmp+1)), ntohl(*(tmp+2))); + + /* fill the RPC_STRUCT... */ + rrpc->programID = htonl(REPLYID); + rrpc->versionID = htonl(REPLYID); + rrpc->procedureID = 0; + rrpc->taskID = 0; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + rrpc->sysTID = 0; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + rrpc->sysPID = 0; + rrpc->parameterSize = htonl(2*sizeof(uint32_t)); + rrpc->mycontext = rpc->mycontext; + + /* fill the parameters... */ + tmp = (uint32_t *)(replybuf + sizeof(RPC_STRUCT)); + *(tmp+0) = rpc->taskID; /* FIXME: should be 64bit */ + *(tmp+1) = htonl(ret); + + if (rpc_kern_write(opt, replybuf, sizeof(replybuf)) != + sizeof(replybuf)) { + pr_err("ERROR in send kernel RPC...\n"); + return RPC_FAIL; + } + } else { + /* read the payload... */ + if (rpc_kern_read(opt, readbuf+sizeof(RPC_STRUCT), + 2*sizeof(uint32_t)) != 2*sizeof(uint32_t)) { + pr_err("ERROR in read payload...\n"); + continue; + } + + /* parse the reply data... */ +#if 0 + /* FIXME: mycontext should be 64bit */ + *((uint32_t *)ntohl(rpc->mycontext)) = ntohl(*(tmp+1)); +#else + *rpc_retval[opt] = ntohl(*(tmp+1)); +#endif + //pr_info("tmp %x opt %d\n", ntohl(*tmp), opt); + complete_condition[opt] = 1; +#if 0 + /* FIXME: wait_queue_head_t * should be 64bit */ + //wake_up((wait_queue_head_t *)ntohl(*tmp)); /* ack the sync... */ +#else + wake_up(&rpc_wq[opt]); // ack the sync... +#endif + } + } + + return 0; +} + +int dump_kern_rpc(void) +{ + int i, j; + RPC_DEV *dev; + + for(j = 0; j < RPC_NR_KERN_DEVS; j++){ + dev = (RPC_DEV *)&rpc_kern_devices[j]; + pr_info("\nname: %sKern%s\n", (j<2) ? "Audio" : "Video", (j % RPC_NR_PAIR == 0) ? "Write" : "Read"); + pr_info("RingBuf: %x\n", dev->ringBuf); + pr_info("RingStart: %x\n", dev->ringStart); + pr_info("RingIn: %x\n", dev->ringIn); + pr_info("RingOut: %x\n", dev->ringOut); + pr_info("RingEnd: %x\n", dev->ringEnd); + + pr_info("RingBuffer:\n"); + for (i = 0; i < RPC_RING_SIZE; i += 16) { + uint32_t *addr = (uint32_t *)(AVCPU2SCPU(dev->ringStart) + i); + pr_info("%x: %08x %08x %08x %08x\n", + dev->ringStart + i, + ntohl(*(addr + 0)), + ntohl(*(addr + 1)), + ntohl(*(addr + 2)), + ntohl(*(addr + 3))); + } + } + + for(j = 0; j < RPC_INTR_DEV_TOTAL; j++){ + dev = (RPC_DEV *)&rpc_intr_devices[j]; + pr_info("\nname: %sIntr%s\n", (j<2) ? "Audio" : "Video", (j % RPC_NR_PAIR == 0) ? "Write" : "Read"); + pr_info("RingBuf: %x\n", dev->ringBuf); + pr_info("RingStart: %x\n", dev->ringStart); + pr_info("RingIn: %x\n", dev->ringIn); + pr_info("RingOut: %x\n", dev->ringOut); + pr_info("RingEnd: %x\n", dev->ringEnd); + + pr_info("RingBuffer:\n"); + for (i = 0; i < RPC_RING_SIZE; i += 16) { + uint32_t *addr = (uint32_t *)(AVCPU2SCPU(dev->ringStart) + i); + pr_info("%x: %08x %08x %08x %08x\n", + dev->ringStart + i, + ntohl(*(addr + 0)), + ntohl(*(addr + 1)), + ntohl(*(addr + 2)), + ntohl(*(addr + 3))); + } + } + if (chip_id != CHIP_ID_RTD1619B) + return 0; + +#ifdef CONFIG_REALTEK_RPC_VE3 + for(j = 0; j < RPC_NR_KERN_VE3_DEVS; j++){ + dev = (RPC_DEV *)&rpc_kern_ve3_devices[j]; + pr_info("\nname: %sKern%s\n","VE3", (j % RPC_NR_PAIR == 0) ? "Write" : "Read"); + pr_info("RingBuf: %x\n", dev->ringBuf); + pr_info("RingStart: %x\n", dev->ringStart); + pr_info("RingIn: %x\n", dev->ringIn); + pr_info("RingOut: %x\n", dev->ringOut); + pr_info("RingEnd: %x\n", dev->ringEnd); + + pr_info("RingBuffer:\n"); + for (i = 0; i < RPC_RING_SIZE; i += 16) { + uint32_t *addr = (uint32_t *)(AVCPU2SCPU(dev->ringStart) + i); + pr_info("%x: %08x %08x %08x %08x\n", + dev->ringStart + i, + ntohl(*(addr + 0)), + ntohl(*(addr + 1)), + ntohl(*(addr + 2)), + ntohl(*(addr + 3))); + } + } + + for(j = 0; j < RPC_INTR_VE3_DEV_TOTAL; j++){ + dev = (RPC_DEV *)&rpc_intr_ve3_devices[j]; + pr_info("\nname: %sIntr%s\n", "VE3", (j % RPC_NR_PAIR == 0) ? "Write" : "Read"); + pr_info("RingBuf: %x\n", dev->ringBuf); + pr_info("RingStart: %x\n", dev->ringStart); + pr_info("RingIn: %x\n", dev->ringIn); + pr_info("RingOut: %x\n", dev->ringOut); + pr_info("RingEnd: %x\n", dev->ringEnd); + + pr_info("RingBuffer:\n"); + for (i = 0; i < RPC_RING_SIZE; i += 16) { + uint32_t *addr = (uint32_t *)(AVCPU2SCPU(dev->ringStart) + i); + pr_info("%x: %08x %08x %08x %08x\n", + dev->ringStart + i, + ntohl(*(addr + 0)), + ntohl(*(addr + 1)), + ntohl(*(addr + 2)), + ntohl(*(addr + 3))); + } + } +#endif + return 0; +} + +int send_rpc_command(int opt, uint32_t command, uint32_t param1, + uint32_t param2, uint32_t *retvalue) +{ + char sendbuf[sizeof(RPC_STRUCT) + 3*sizeof(uint32_t)]; + RPC_STRUCT *rpc = (RPC_STRUCT *)sendbuf; + uint32_t *tmp; + + if (rpc_kern_is_paused) { + pr_warn("RPCkern: someone access rpc kern during the pause...\n"); + return RPC_FAIL; + } + + mutex_lock(&rpc_kern_lock[opt]); + + while (rpc_kern_is_suspend) { + pr_warn("RPCkern: someone access rpc poll during the suspend!!!...\n"); + msleep(1000); + } + + if (rpc_kthread[opt] == 0) { + pr_warn("RPCkern: %s is disabled...\n", rpc_kthread[opt]->comm); + mutex_unlock(&rpc_kern_lock[opt]); + return RPC_FAIL; + } + + //pr_info(" #@# sendbuf: %d cmd %x param1 %x param2 %x\n", + // sizeof(sendbuf), command, param1, param2); + + /* fill the RPC_STRUCT... */ + rpc->programID = htonl(KERNELID); + rpc->versionID = htonl(KERNELID); + rpc->procedureID = 0; +#if 0 + /* FIXME: should be 64bit */ + /* using taskID to store wait queue address */ + rpc->taskID = htonl((uint32_t)&rpc_wq[opt]); +#else + //rpc->taskID = 0; + rpc->taskID = htonl(current->pid);// 0; +#endif +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + rpc->sysTID = 0; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + rpc->sysPID = 0; + rpc->parameterSize = htonl(3*sizeof(uint32_t)); +#if 0 + /* FIXME: mycontext should be 64bit */ + rpc->mycontext = htonl((uint32_t)retvalue); +#else + rpc->mycontext = 0; + rpc_retval[opt] = retvalue; +#endif + + /* fill the parameters... */ + tmp = (uint32_t *)(sendbuf+sizeof(RPC_STRUCT)); + //pr_info(" aaa: %x bbb: %x \n", sendbuf, tmp); + *tmp = htonl(command); + *(tmp+1) = htonl(param1); + *(tmp+2) = htonl(param2); + + complete_condition[opt] = 0; + if (rpc_kern_write(opt, sendbuf, sizeof(sendbuf)) != sizeof(sendbuf)) { + pr_err("ERROR in send kernel RPC...\n"); + mutex_unlock(&rpc_kern_lock[opt]); + return RPC_FAIL; + } + + /* wait the result... */ + //if (!sleep_on_timeout(&rpc_wq[opt], TIMEOUT)) { + if (!wait_event_timeout(rpc_wq[opt], complete_condition[opt], TIMEOUT)) { + pr_err("kernel rpc timeout -> disable %s...\n", rpc_kthread[opt]->comm); + WARN(1, " #@# sendbuf: size%lu cmd:%x param1:%x param2:%x\n", + sizeof(sendbuf), command, param1, param2); + dump_kern_rpc(); + + kthread_stop(rpc_kthread[opt]); + rpc_kthread[opt] = 0; + mutex_unlock(&rpc_kern_lock[opt]); + return RPC_FAIL; + } else { + pr_debug(" #@# ret: %d \n", *retvalue); + mutex_unlock(&rpc_kern_lock[opt]); + return RPC_OK; + } +} +EXPORT_SYMBOL(send_rpc_command); diff --git a/drivers/soc/realtek/common/rpc/rtk_rpc_poll.c b/drivers/soc/realtek/common/rpc/rtk_rpc_poll.c new file mode 100644 index 000000000000..54fdc4d07730 --- /dev/null +++ b/drivers/soc/realtek/common/rpc/rtk_rpc_poll.c @@ -0,0 +1,892 @@ +/* + * Realtek RPC driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "rtk_rpc.h" +#include "mem_allocator/ion.h" + +#include +#define ion_alloc ext_rtk_ion_alloc + +volatile RPC_DEV *rpc_poll_devices; + +#ifdef CONFIG_REALTEK_RPC_KCPU +volatile RPC_DEV *rpc_poll_kcpu_devices; +#endif + +int rpc_poll_is_paused; +int rpc_poll_is_suspend; + +extern int chip_id; + +struct rpc_debug_flag { + unsigned int acpu; + unsigned int reserve_acpu[127]; + unsigned int vcpu; + unsigned int reserve_vcpu[127]; +}; + +struct rpc_debug_flag_memory { + int handle; + struct rpc_debug_flag *debug_flag; + phys_addr_t debug_phys; + size_t debug_size; + struct dma_buf *dmabuf; +}; + +struct rpc_debug_print_memory { + int handle; + void *debug_hdr; + phys_addr_t debug_phys; + size_t debug_size; + struct dma_buf *dmabuf_orig; + struct dma_buf *dmabuf; + int32_t fd; +}; + +static struct rpc_debug_flag_memory *mDebugFlagMemory = NULL; +static struct rpc_debug_print_memory * mDebugPrintMemory = NULL; + +static phys_addr_t rpc_mem_pa(struct ion_buffer *buffer) +{ + unsigned long ret = -1UL; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + + mutex_lock(&buffer->lock); + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + mutex_unlock(&buffer->lock); + + ret = paddr; + + return ret; +} + +static void *rpc_mem_va(struct ion_buffer *buffer) +{ + void *ret = NULL; + void *vaddr; + + mutex_lock(&buffer->lock); + vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer); + mutex_unlock(&buffer->lock); + + ret = vaddr; + + return ret; +} + +static struct rpc_debug_flag_memory * get_debug_flag_memory(void) +{ + do { + if (mDebugFlagMemory == NULL) { + struct rpc_debug_flag_memory * tmp = (struct rpc_debug_flag_memory *) kzalloc( + sizeof(struct rpc_debug_flag_memory), GFP_KERNEL); + unsigned int ion_flag_mask = ION_FLAG_NONCACHED | ION_USAGE_MMAP_NONCACHED; + + if (tmp == NULL) + break; + + ion_flag_mask |= ION_FLAG_SCPUACC | ION_FLAG_ACPUACC; + + ion_flag_mask |= ION_FLAG_VCPU_FWACC; + + tmp->handle = ion_alloc(sizeof(struct rpc_debug_flag) , + RTK_ION_HEAP_AUDIO_MASK, ion_flag_mask); + + if (0 > tmp->handle) + tmp->handle = ion_alloc(sizeof(struct rpc_debug_flag), + RTK_ION_HEAP_MEDIA_MASK, ion_flag_mask); + + tmp->dmabuf = dma_buf_get(tmp->handle); + if (IS_ERR(tmp->dmabuf)) + break; + + __close_fd(current->files, tmp->handle); + + if (0 > tmp->handle) { + dma_buf_put(tmp->dmabuf); + kfree(tmp); + break; + } + + tmp->debug_phys = rpc_mem_pa(tmp->dmabuf->priv); + + if (tmp->debug_phys == 0) { + dma_buf_put(tmp->dmabuf); + kfree(tmp); + break; + } + + tmp->debug_flag = (struct rpc_debug_flag *) rpc_mem_va(tmp->dmabuf->priv); + + mDebugFlagMemory = tmp; + } + } while (0); + + return mDebugFlagMemory; +} + +static struct rpc_debug_print_memory * get_debug_print_memory(void) +{ + do { + if (mDebugPrintMemory == NULL) { + struct rpc_debug_print_memory * tmp = (struct rpc_debug_print_memory *) kzalloc( + sizeof(struct rpc_debug_print_memory), GFP_KERNEL); + unsigned int ion_flag_mask = ION_FLAG_NONCACHED | ION_USAGE_MMAP_NONCACHED; + + if (tmp == NULL) + break; + + ion_flag_mask |= ION_FLAG_SCPUACC | ION_FLAG_ACPUACC; + + ion_flag_mask |= ION_FLAG_VCPU_FWACC; + + tmp->dmabuf = dma_buf_get(tmp->handle); + if (IS_ERR(tmp->dmabuf)) + break; + + __close_fd(current->files, tmp->handle); + + if (0 > tmp->handle) { + dma_buf_put(tmp->dmabuf); + kfree(tmp); + break; + } + + tmp->debug_phys = rpc_mem_pa(tmp->dmabuf->priv); + + if (tmp->debug_phys == 0) { + dma_buf_put(tmp->dmabuf); + kfree(tmp); + break; + } + + tmp->debug_hdr = (void *) rpc_mem_va(tmp->dmabuf->priv); + + mDebugPrintMemory = tmp; + } + } while (0); + + return mDebugPrintMemory; +} + +static struct rpc_debug_flag *get_debug_flag(void) +{ + struct rpc_debug_flag_memory * debug_memory = get_debug_flag_memory(); + return (debug_memory) ? debug_memory->debug_flag : NULL; +} + +static phys_addr_t get_debug_flag_phyAddr(void) +{ + struct rpc_debug_flag_memory * debug_memory = get_debug_flag_memory(); + return (debug_memory) ? debug_memory->debug_phys : -1UL; +} + +static struct rpc_debug_print_memory *get_debug_print(void) +{ + struct rpc_debug_print_memory * debug_print = get_debug_print_memory(); + return (debug_print) ? debug_print : NULL; +} + +static phys_addr_t get_debug_print_phyAddr(void) +{ + struct rpc_debug_print_memory * debug_print = get_debug_print_memory(); + return (debug_print) ? debug_print->debug_phys : -1UL; +} + +RPC_DEV_EXTRA rpc_poll_extra[RPC_NR_DEVS/RPC_NR_PAIR]; + +int rpc_poll_init(void) +{ + static int is_init; + int result = 0, i; + + is_init = 0; + + /* Create corresponding structures for each device. */ + rpc_poll_devices = (RPC_DEV *)AVCPU2SCPU(RPC_POLL_RECORD_ADDR); + + for (i = 0; i < RPC_INTR_DEV_TOTAL; i++) { + pr_debug("rpc_poll_device %d addr: %p\n", i, &rpc_poll_devices[i]); + rpc_poll_devices[i].ringBuf = RPC_POLL_DEV_ADDR + i*RPC_RING_SIZE*2; + + /* Initialize pointers... */ + rpc_poll_devices[i].ringStart = rpc_poll_devices[i].ringBuf; + rpc_poll_devices[i].ringEnd = rpc_poll_devices[i].ringBuf + RPC_RING_SIZE; + rpc_poll_devices[i].ringIn = rpc_poll_devices[i].ringBuf; + rpc_poll_devices[i].ringOut = rpc_poll_devices[i].ringBuf; + + pr_debug("The %dth poll dev:\n", i); + pr_debug("RPC ringStart: %p\n", AVCPU2SCPU(rpc_poll_devices[i].ringStart)); + pr_debug("RPC ringEnd: %p\n", AVCPU2SCPU(rpc_poll_devices[i].ringEnd)); + pr_debug("RPC ringIn: %p\n", AVCPU2SCPU(rpc_poll_devices[i].ringIn)); + pr_debug("RPC ringOut: %p\n", AVCPU2SCPU(rpc_poll_devices[i].ringOut)); + pr_debug("\n"); + + rpc_poll_extra[i].nextRpc = rpc_poll_devices[i].ringOut; + rpc_poll_extra[i].currProc = NULL; + + if (!is_init) { + rpc_poll_devices[i].ptrSync = kmalloc(sizeof(RPC_SYNC_Struct), GFP_KERNEL); + kmemleak_not_leak(rpc_poll_devices[i].ptrSync); + + /* Initialize wait queue... */ + //init_waitqueue_head(&(rpc_poll_devices[i].ptrSync->waitQueue)); + + /* Initialize sempahores... */ + init_rwsem(&rpc_poll_devices[i].ptrSync->readSem); + init_rwsem(&rpc_poll_devices[i].ptrSync->writeSem); + + rpc_poll_extra[i].dev = (void *)&rpc_poll_devices[i]; + INIT_LIST_HEAD(&rpc_poll_extra[i].tasks); + //tasklet_init(&rpc_poll_extra[i].tasklet, rpc_dispatch, (unsigned long)&rpc_poll_extra[i]); + spin_lock_init(&rpc_poll_extra[i].lock); + switch (i) { + case 0: + rpc_poll_extra[i].name = "AudioPollWrite"; + break; + case 1: + rpc_poll_extra[i].name = "AudioPollRead"; + break; + case 2: + rpc_poll_extra[i].name = "Video1PollWrite"; + break; + case 3: + rpc_poll_extra[i].name = "Video1PollRead"; + break; + case 4: + rpc_poll_extra[i].name = "Video2PollWrite"; + break; + case 5: + rpc_poll_extra[i].name = "Video2PollRead"; + break; + } + } + } + + is_init = 1; + rpc_poll_is_paused = 0; + rpc_poll_is_suspend = 0; + + return result; +} + +int rpc_poll_pause(void) +{ + rpc_poll_is_paused = 1; + return 0; +} + +int rpc_poll_suspend(void) +{ + rpc_poll_is_suspend = 1; + return 0; +} + +int rpc_poll_resume(void) +{ + rpc_poll_is_suspend = 0; + return 0; +} + +void rpc_poll_cleanup(void) +{ + int num = RPC_NR_DEVS/RPC_NR_PAIR, i; + + /* Clean corresponding structures for each device. */ + if (rpc_poll_devices) { + /* Clean ring buffers. */ + for (i = 0; i < num; i++) { + //if (rpc_poll_devices[i].ringBuf) + //kfree(rpc_poll_devices[i].ringBuf); + } + //kfree(rpc_poll_devices); + } + + return; +} + +int rpc_poll_open(struct inode *inode, struct file *filp) +{ + int minor = MINOR(inode->i_rdev); + + if (minor == 100) { + filp->f_op = &rpc_ctrl_fops; + return filp->f_op->open(inode, filp); /* dispatch to specific open */ + } + + /* + * If private data is not valid, we are not using devfs + * so use the minor number to select a new f_op + */ + if (!filp->private_data && (minor >= RPC_NR_DEVS)) { + filp->f_op = rpc_fop_array[1]; + return filp->f_op->open(inode, filp); + } + if (!filp->private_data && (minor%RPC_NR_PAIR != 0)) { + filp->f_op = rpc_fop_array[minor%RPC_NR_PAIR]; + return filp->f_op->open(inode, filp); /* dispatch to specific open */ + } + + pr_debug("RPC poll open with minor number: %d\n", minor); + + if (!filp->private_data) { + RPC_PROCESS *proc = kmalloc(sizeof(RPC_PROCESS), GFP_KERNEL | __GFP_ZERO); + + if (proc == NULL) { + pr_err("%s: failed to allocate RPC_PROCESS", __func__); + return -ENOMEM; + } + +#ifdef CONFIG_REALTEK_RPC_KCPU + if (minor >= RPC_NR_DEVS) + proc->dev = &rpc_poll_kcpu_devices[(minor-RPC_NR_DEVS)/RPC_NR_PAIR]; + else +#endif + proc->dev = (RPC_DEV *)&rpc_poll_devices[minor/RPC_NR_PAIR]; + + proc->extra = &rpc_poll_extra[minor/RPC_NR_PAIR]; + /* current->tgid = process id, current->pid = thread id */ + proc->pid = current->tgid; + proc->bStayActive = false; + + init_waitqueue_head(&proc->waitQueue); + INIT_LIST_HEAD(&proc->threads); +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + INIT_LIST_HEAD(&proc->handlers); +#endif + spin_lock_bh(&proc->extra->lock); + list_add(&proc->list, &proc->extra->tasks); + spin_unlock_bh(&proc->extra->lock); + pr_debug("%s: Current process pid:%d tgid:%d => %d(%p) for %s(%p)\n", __func__, current->pid, current->tgid, proc->pid, &proc->waitQueue, proc->extra->name, proc->dev); + + filp->private_data = proc; + } + + //MOD_INC_USE_COUNT; /* Before we maybe sleep */ + + return 0; +} + +int rpc_poll_release(struct inode *inode, struct file *filp) +{ +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + RPC_HANDLER *handler, *hdltmp; +#endif + RPC_THREAD *th, *thtmp; + int minor = MINOR(inode->i_rdev); + + RPC_PROCESS *proc = filp->private_data; + RPC_DEV *dev = proc->dev; /* the first listitem */ + RPC_DEV_EXTRA *extra = proc->extra; + + if (extra->currProc == proc) { + pr_debug("%s: clear %s(%p) current process\n", __func__, proc->extra->name, dev); + update_currProc(extra, NULL); + if (minor == 2 || minor == 6 || minor == 10) { /* poll read device (ugly code) */ + if (!rpc_done(extra)) { + pr_err("%s: previous rpc hasn't finished, force clear!! ringOut %p => %p\n", __func__, + AVCPU2SCPU(dev->ringOut), AVCPU2SCPU(extra->nextRpc)); + down_write(&dev->ptrSync->readSem); + dev->ringOut = extra->nextRpc; + up_write(&dev->ptrSync->readSem); + } + } + } + + spin_lock_bh(&extra->lock); + +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + //unregister myself from handler list + list_for_each_entry_safe(handler, hdltmp, &proc->handlers, list) { + list_del(&handler->list); + kfree(handler); + } +#endif + + list_for_each_entry_safe(th, thtmp, &proc->threads, list) { + list_del(&th->list); + kfree(th); + } + + /* remove myself from task list */ + list_del(&proc->list); + kfree(proc); + + spin_unlock_bh(&extra->lock); + + pr_debug("RPC poll close with minor number: %d\n", minor); + +// MOD_DEC_USE_COUNT; + + return 0; +} + +/* We don't need parameter f_pos here... */ +ssize_t rpc_poll_read(struct file *filp, char *buf, size_t count, + loff_t *f_pos) +{ + RPC_PROCESS *proc = filp->private_data; + RPC_DEV *dev = proc->dev; /* the first listitem */ + RPC_DEV_EXTRA *extra = proc->extra; + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + int rpc_ring_size = dev->ringEnd - dev->ringStart; + + //pr_debug("%s:%d thread:%s pid:%d tgid:%d device:%s\n", __func__, __LINE__, current->comm, current->pid, current->tgid, extra->name); + if (rpc_poll_is_paused) { + pr_err("RPCpoll: someone access rpc poll during the pause...\n"); + pr_err("%s:%d buf:%p count:%lu EAGAIN\n", __func__, __LINE__, buf, count); + msleep(1000); + return -EAGAIN; + } + + while (rpc_poll_is_suspend) { + pr_warn("RPCpoll: someone access rpc poll during the suspend!!!...\n"); + msleep(1000); + } + + wmb(); + down_write(&dev->ptrSync->readSem); + + if (need_dispatch(extra)) { + tasklet_schedule(&(extra->tasklet)); + } + + //pr_debug("%s: dev:%s(%p) currProc:%p\n", __func__, extra->name, dev, extra->currProc); + if ((extra->currProc != proc) || (ring_empty(dev))) { + if (unlikely(!(filp->f_flags & O_NONBLOCK))) { + //pr_warn("%s:%d:%s Warning: pid:%d use blocking mode with poll buffer!\n", __func__, __LINE__, extra->name, current->pid); + } + goto out; //return anyway + } + + if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = rpc_ring_size + dev->ringIn - dev->ringOut; + + //pr_debug("%s: %s: count:%lu size:%d\n", __func__, extra->name, count, size); + //peek_rpc_struct(__func__, dev, f_pos); + if (count > size) + count = size; + + temp = dev->ringEnd - dev->ringOut; + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_to_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), count); +#else + r = copy_to_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), count); +#endif + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", __func__, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + ret += count; + ptmp = dev->ringOut + ((count+3) & 0xfffffffc); + + if (ptmp == dev->ringEnd) + dev->ringOut = dev->ringStart; + else + dev->ringOut = ptmp; + + //pr_debug("RPC Read is in 1st kind...\n"); + } else { +#ifdef MY_COYP + r = my_copy_to_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), temp); +#else + r = copy_to_user((int *)buf, (int *)AVCPU2SCPU(dev->ringOut), temp); +#endif + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", __func__, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + count -= temp; + +#ifdef MY_COPY + r = my_copy_to_user((int *)(buf+temp), (int *)AVCPU2SCPU(dev->ringStart), count); +#else + r = copy_to_user((int *)(buf+temp), (int *)AVCPU2SCPU(dev->ringStart), count); +#endif + if (r) { + pr_err("%s:%d buf:%p count:%lu EFAULT\n", __func__, __LINE__, buf, count); + ret = -EFAULT; + goto out; + } + + ret += (temp + count); + dev->ringOut = dev->ringStart+((count+3) & 0xfffffffc); + + //pr_debug("RPC Read is in 2nd kind...\n"); + } + + spin_lock_bh(&extra->lock); + if (rpc_done(extra)) { + pr_debug("%s: Previous RPC is done, unregister myself\n", __func__); + update_currProc(extra, NULL); + } + spin_unlock_bh(&extra->lock); + + //process next rpc command if any + if (need_dispatch(extra)) + tasklet_schedule(&(extra->tasklet)); + + pr_debug("%s:%d buf:%p count:%lu actual:%lu\n", __func__, __LINE__, buf, count, ret); + +out: + up_write(&dev->ptrSync->readSem); + wmb(); + //pr_debug("RPC poll ringOut pointer is : 0x%8x\n", (int)AVCPU2SCPU(dev->ringOut)); + //pr_debug("%s:%d pid:%d reads %d bytes\n", extra->name, __LINE__, current->pid, ret); + return ret; +} + +/* We don't need parameter f_pos here... */ +ssize_t rpc_poll_write(struct file *filp, const char *buf, size_t count, + loff_t *f_pos) +{ + RPC_PROCESS *proc = filp->private_data; + RPC_DEV *dev = proc->dev; /* the first listitem */ + RPC_DEV_EXTRA *extra = proc->extra; + RPC_DEV_EXTRA *rextra = extra + 1; + int temp, size; + size_t r; + ssize_t ret = 0; + uint32_t ptmp; + int rpc_ring_size = dev->ringEnd - dev->ringStart; + + if (rpc_poll_is_paused) { + pr_warn("RPCpoll: someone access rpc poll during the pause...\n"); + msleep(1000); + return -EAGAIN; + } + + while (rpc_poll_is_suspend) { + pr_warn("RPCpoll: someone access rpc poll during the suspend!!!...\n"); + msleep(1000); + } + + wmb(); + down_write(&dev->ptrSync->writeSem); + +#if 1 + /* Threads that share the same file descriptor should have the same tgid + * However, with uClibc pthread library, pthread_create() creates threads with pid == tgid + * So the tgid is not real tgid, we have to maintain the thread list that we can lookup later + */ + if (current->pid != proc->pid) + update_thread_list(rextra, proc->pid); +#endif + + if (ring_empty(dev)) + size = 0; // the ring is empty + else if (dev->ringIn > dev->ringOut) + size = dev->ringIn - dev->ringOut; + else + size = rpc_ring_size + dev->ringIn - dev->ringOut; + + pr_debug("%s: count:%lu space:%d\n", extra->name, count, rpc_ring_size - size - 1); + pr_debug("%s: pid:%d tgid:%d\n", extra->name, current->pid, current->tgid); + + if (count > (rpc_ring_size - size - 1)) + goto out; + + temp = dev->ringEnd - dev->ringIn; + + if (temp >= count) { +#ifdef MY_COPY + r = my_copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count); +#else + r = copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, count); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + + ret += count; + ptmp = dev->ringIn + ((count+3) & 0xfffffffc); + + //asm("DSB"); + mb(); + + if (ptmp == dev->ringEnd) + dev->ringIn = dev->ringStart; + else + dev->ringIn = ptmp; + + //pr_debug("RPC Write is in 1st kind...\n"); + } else { +#ifdef MY_COPY + r = my_copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp); +#else + r = copy_from_user((int *)AVCPU2SCPU(dev->ringIn), (int *)buf, temp); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + + count -= temp; + +#ifdef MY_COPY + r = my_copy_from_user((int *)AVCPU2SCPU(dev->ringStart), (int *)(buf+temp), count); +#else + r = copy_from_user((int *)AVCPU2SCPU(dev->ringStart), (int *)(buf+temp), count); +#endif + if (r) { + ret = -EFAULT; + goto out; + } + + ret += (temp + count); + + //asm("DSB"); + mb(); + + dev->ringIn = dev->ringStart+((count+3) & 0xfffffffc); + //pr_debug("RPC Write is in 2nd kind...\n"); + } + + //peek_rpc_struct(extra->name, dev, f_pos); + +out: + pr_debug("RPC poll ringIn pointer is : %p\n", AVCPU2SCPU(dev->ringIn)); + up_write(&dev->ptrSync->writeSem); + wmb(); + + return ret; +} + +long rpc_poll_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int found; + RPC_PROCESS *proc = filp->private_data; + RPC_DEV_EXTRA *extra = proc->extra; + RPC_HANDLER *handler; + + while (rpc_poll_is_suspend) { + pr_warn("RPCpoll: someone access rpc poll during the suspend!!!...\n"); + msleep(1000); + } + + switch (cmd) { +#ifdef CONFIG_REALTEK_RPC_PROGRAM_REGISTER + case RPC_IOCTHANDLER: + + pr_debug("%s:%d : Register handler for programID:%lu\n", __func__, __LINE__, arg); + found = 0; + list_for_each_entry(handler, &proc->handlers, list) { + if (handler->programID == arg) { + found = 1; + break; + } + } + + if (found) + break; + + /* not found, add to handler list */ + handler = kmalloc(sizeof(RPC_HANDLER), GFP_KERNEL); + if (handler == NULL) { + pr_err("%s: failed to allocate RPC_HANDLER\n", __func__); + return -ENOMEM; + } + + handler->programID = arg; + spin_lock_bh(&extra->lock); + list_add(&handler->list, &proc->handlers); + spin_unlock_bh(&extra->lock); + pr_debug("%s:%d %s: Add handler pid:%d for programID:%lu\n", __func__, __LINE__, proc->extra->name, proc->pid, arg); + break; +#endif + case RPC_IOC_PROCESS_CONFIG_0: + { + struct S_RPC_IOC_PROCESS_CONFIG_0 config; + + if (copy_from_user(&config, (void __user *)arg, sizeof(struct S_RPC_IOC_PROCESS_CONFIG_0))) { + pr_err("ERROR! %s cmd:RPC_IOC_PROCESS_CONFIG_0 copy_from_user failed\n", __func__); + return -ENOMEM; + } + + if (proc == NULL) { + pr_err("ERROR! %s cmd:RPC_IOC_PROCESS_CONFIG_0 proc:%p\n", __func__, proc); + return -ENOMEM; + } + + proc->bStayActive = (config.bStayActive > 0) ? true : false; + break; + } + default: + pr_warn("%s:%d unsupported ioctl cmd:%x arg:%lx\n", __func__, __LINE__, cmd, arg); + return -ENOTTY; + } + + return ret; +} + +long rpc_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + RPC_DBG_FLAG dFlag; + + while (rpc_poll_is_suspend) { + pr_warn("RPCpoll: someone access rpc poll during the suspend!!!...\n"); + msleep(1000); + } + + switch (cmd) { + case RPC_IOCTRESET: + + pr_info("[RPC]start reset...\n"); + rpc_poll_init(); + rpc_intr_init(); + rpc_kern_init(); + + /* clear the inter-processor interrupts */ + + writel_relaxed(1 << 1, rpc_int_base+RPC_SB2_INT); + + writel(RPC_INT_SA, rpc_int_base+RPC_SB2_INT); + + rpc_set_flag(RPC_AUDIO, 0xffffffff); + + pr_info("[RPC]done...\n"); + break; + + case RPC_IOCTRGETDBGREG_A: + case RPC_IOCTRGETDBGREG_V: + + if (copy_from_user(&dFlag, (void __user *)arg, sizeof(dFlag))) + return -EFAULT; + else { + unsigned int *puDebugFlag = NULL; + struct rpc_debug_flag * debug_flag = get_debug_flag(); + phys_addr_t debug_flag_phyAddr = get_debug_flag_phyAddr(); + + if (debug_flag == NULL || -1 == debug_flag_phyAddr) + return -EFAULT; + + if (cmd == RPC_IOCTRGETDBGREG_V) { + puDebugFlag = &debug_flag->vcpu; + debug_flag_phyAddr = debug_flag_phyAddr + offsetof(struct rpc_debug_flag, vcpu); + } else { + puDebugFlag = &debug_flag->acpu; + debug_flag_phyAddr = debug_flag_phyAddr + offsetof(struct rpc_debug_flag, acpu); + } + + if (dFlag.op == RPC_DBGREG_SET) + *puDebugFlag = dFlag.flagValue; + else { + dFlag.flagValue = (unsigned int)*puDebugFlag; + dFlag.flagAddr = (uint32_t) debug_flag_phyAddr & -1U; + if (copy_to_user((void __user *)arg, &dFlag, sizeof(dFlag))) + return -EFAULT; + } + + pr_debug("RPC_DEBUG cmd=%s op=%s phyAddr=0x%08llx flag=0x%08x", + (cmd == RPC_IOCTRGETDBGREG_V) ? "RPC_IOCTRGETDBGREG_V" : "RPC_IOCTRGETDBGREG_A", + (dFlag.op == RPC_DBGREG_SET) ? "SET" : "GET", + debug_flag_phyAddr, *puDebugFlag); + } + + break; + case RPC_IOCTRGETDBGPRINT_V: + + if (copy_from_user(&dFlag, (void __user *)arg, sizeof(dFlag))) + return -EFAULT; + else { + struct rpc_debug_print_memory * debug_print = get_debug_print(); + phys_addr_t debug_print_phyAddr = get_debug_print_phyAddr(); + struct dma_buf * dmabuf; + + if (debug_print == NULL || -1 == debug_print_phyAddr) + return -EFAULT; + + dFlag.flagAddr = (uint32_t) debug_print_phyAddr & -1U; +// dFlag.flagValue = dma_buf_fd(debug_print->dmabuf, debug_print->handle); + debug_print->fd = dma_buf_fd(debug_print->dmabuf, O_CLOEXEC); + dmabuf = dma_buf_get(debug_print->fd); + if (IS_ERR(dmabuf)) { + pr_err("%s : ERROR! dma_buf_get return %p", __func__, dmabuf); + return -EFAULT; + } + + debug_print->dmabuf = dmabuf; +// dFlag.flagValue = dma_buf_fd(debug_print->dmabuf, O_CLOEXEC); + dFlag.flagValue = debug_print->fd; + + if (copy_to_user((void __user *)arg, &dFlag, sizeof(dFlag))) + return -EFAULT; + + } + break; + default: + pr_warn("[RPC]: error ioctl command...\n"); + break; + } + + return ret; +} + +int rpc_ctrl_open(struct inode *inode, struct file *filp) +{ + pr_info("[RPC]open for RPC ioctl...\n"); + + return 0; +} + +struct file_operations rpc_poll_fops = { + //llseek:scull_llseek, + .unlocked_ioctl = rpc_poll_ioctl, + .compat_ioctl = rpc_poll_ioctl, + .read = rpc_poll_read, + .write = rpc_poll_write, + .open = rpc_poll_open, + .release = rpc_poll_release, +}; + +struct file_operations rpc_ctrl_fops = { + .unlocked_ioctl = rpc_ctrl_ioctl, + .compat_ioctl = rpc_ctrl_ioctl, + .open = rpc_ctrl_open, +}; + diff --git a/drivers/soc/realtek/common/rtk_bootstatus.c b/drivers/soc/realtek/common/rtk_bootstatus.c new file mode 100644 index 000000000000..fbd3813143df --- /dev/null +++ b/drivers/soc/realtek/common/rtk_bootstatus.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + REBOOT_REASON_INVALID = 0, + REBOOT_REASON_SOFTWARE, + REBOOT_REASON_WATCHDOG, + REBOOT_REASON_SUSPEND_ABNORMAL, + REBOOT_REASON_SHUTDOWN_ABNORMAL, +}; + +enum { + BOOT_TYPE_EMMC, + BOOT_TYPE_USB_DEVICE, + BOOT_TYPE_NOR, + BOOT_TYPE_NAND, + BOOT_TYPE_NAND_SERIAL, + BOOT_TYPE_NAND_SERIAL_3V3, + BOOT_TYPE_NAND_SERIAL_1V8, + BOOT_TYPE_NAND_PARALLEL, +}; + +static const char *reboot_reason_strings[] = { + "invalid", "software", "watchdog", "suspend_error", "shutdown_error", +}; + +static const char *boot_type_strings[] = { + [BOOT_TYPE_EMMC] = "emmc", + [BOOT_TYPE_USB_DEVICE] = "usb-device", + [BOOT_TYPE_NOR] = "nor", + [BOOT_TYPE_NAND] = "nand", + [BOOT_TYPE_NAND_SERIAL] = "nand-serial", + [BOOT_TYPE_NAND_SERIAL_3V3] = "nand-serial-3v3", + [BOOT_TYPE_NAND_SERIAL_1V8] = "nand-serial-1v8", + [BOOT_TYPE_NAND_PARALLEL] = "nand-parellel", +}; + +struct bootstatus_plat_desc { + const char *(*boot_type_string)(int opt); +}; + +struct bootstatus_data { + const struct bootstatus_plat_desc *desc; + unsigned int boot_option; + unsigned int sw_cold_boot_counter; +}; + +static const char *bootstatus_get_boot_type(struct bootstatus_data *data) +{ + if (!data->desc || !data->desc->boot_type_string) + return "invalid"; + + return data->desc->boot_type_string(data->boot_option); +} + +static int bootstatus_get_sw_cold_boot_counter(struct bootstatus_data *data) +{ + return data->sw_cold_boot_counter; +} + +static const unsigned int rtd1619_boot_type_map[] = { + BOOT_TYPE_NAND, BOOT_TYPE_NOR, BOOT_TYPE_USB_DEVICE, BOOT_TYPE_EMMC +}; + +static const char *rtd1619_boot_type_string(int opt) +{ + int sel = (opt >> 29) & 0x3; + + return boot_type_strings[rtd1619_boot_type_map[sel]]; +} + +static const struct bootstatus_plat_desc rtd1619_desc = { + .boot_type_string = rtd1619_boot_type_string, +}; + +static const unsigned int rtd1319_boot_type_map[] = { + BOOT_TYPE_NAND_SERIAL, BOOT_TYPE_NAND_PARALLEL, + BOOT_TYPE_NOR, BOOT_TYPE_NOR, + BOOT_TYPE_USB_DEVICE, BOOT_TYPE_USB_DEVICE, + BOOT_TYPE_EMMC, BOOT_TYPE_EMMC +}; + +static const char *rtd1319_boot_type_string(int opt) +{ + int sel = (opt >> 28) & 0x7; + + return boot_type_strings[rtd1319_boot_type_map[sel]]; +} + +static const struct bootstatus_plat_desc rtd1319_desc = { + .boot_type_string = rtd1319_boot_type_string, +}; + +static const unsigned int rtd1619b_boot_type_map[] = { + BOOT_TYPE_NAND_SERIAL_1V8, BOOT_TYPE_NAND_SERIAL_3V3, + BOOT_TYPE_NOR, BOOT_TYPE_NAND_PARALLEL, + BOOT_TYPE_USB_DEVICE, BOOT_TYPE_USB_DEVICE, + BOOT_TYPE_EMMC, BOOT_TYPE_EMMC +}; + +static const char *rtd1619b_boot_type_string(int opt) +{ + int sel = (opt >> 28) & 0x7; + + return boot_type_strings[rtd1619b_boot_type_map[sel]]; +} + +static const struct bootstatus_plat_desc rtd1619b_desc = { + .boot_type_string = rtd1619b_boot_type_string, +}; + +static struct bootstatus_data *bootstatus_data; +static long reboot_reason; + +static int reboot_reason_config(char *str) +{ + if (!str) + return -EINVAL; + + if (strcmp(str, "hardware") == 0) // off -> on + reboot_reason = REBOOT_REASON_INVALID; + else if (strcmp(str, "str_warm") == 0) // suspend_to_ram -> on + reboot_reason = REBOOT_REASON_SUSPEND_ABNORMAL; + else if (strcmp(str, "str_cold") == 0) // shutdown -> on + reboot_reason = REBOOT_REASON_SHUTDOWN_ABNORMAL; + else if (strcmp(str, "software") == 0) // reboot -> on + reboot_reason = REBOOT_REASON_SOFTWARE; + else if (strcmp(str, "watchdog") == 0) // reboot_trigger_by_watchdog -> on + reboot_reason = REBOOT_REASON_WATCHDOG; + else + pr_err("%s: invalid wakeupreason value \"%s\"\n", __func__, str); + return 0; +} +__setup("wakeupreason=", reboot_reason_config); + +static ssize_t reboot_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", reboot_reason_strings[reboot_reason]); +} + +static struct kobj_attribute reboot_reason_attr = __ATTR_RO(reboot_reason); + +static ssize_t boot_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", bootstatus_get_boot_type(bootstatus_data)); +} + +static struct kobj_attribute boot_type_attr = __ATTR_RO(boot_type); + +static ssize_t sw_cold_boot_counter_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", bootstatus_get_sw_cold_boot_counter(bootstatus_data)); +} + +static struct kobj_attribute sw_cold_boot_counter_attr = __ATTR_RO(sw_cold_boot_counter); + +static struct attribute *rtk_bootstatus_attrs[] = { + &reboot_reason_attr.attr, + &boot_type_attr.attr, + &sw_cold_boot_counter_attr.attr, + NULL, +}; + +static umode_t rtk_bootstatus_attr_is_visible(struct kobject *kobj, struct attribute *attr, int unused) +{ + if (attr == &boot_type_attr.attr || attr == &sw_cold_boot_counter_attr.attr) + return bootstatus_data ? attr->mode : 0; + return attr->mode; +} + +static struct attribute_group rtk_bootstatus_attr_group = { + .attrs = rtk_bootstatus_attrs, + .is_visible = rtk_bootstatus_attr_is_visible, +}; + +static struct regmap *get_iso_syscon(void) +{ + struct device_node *np; + struct regmap *map; + + np = of_find_node_by_path("/iso@98007000"); + if (!np) + np = of_find_node_by_path("/soc@0/rbus@98000000/syscon@7000"); + if (!np) + return NULL; + + map = syscon_node_to_regmap(np); + of_node_put(np); + return IS_ERR(map) ? NULL : map; +} + +static void bootinfo_init(struct bootstatus_data *data) +{ + struct regmap *map = get_iso_syscon(); + + if (WARN_ON(!map)) + return; + + regmap_read(map, 0x678, &data->boot_option); + regmap_read(map, 0x644, &data->sw_cold_boot_counter); +} + +static const struct of_device_id machines[] __initconst = { + { .compatible = "realtek,rtd1619", .data = &rtd1619_desc, }, + { .compatible = "realtek,rtd1319", .data = &rtd1319_desc, }, + { .compatible = "realtek,rtd1619b", .data = &rtd1619b_desc, }, + { .compatible = "realtek,rtd1315c", .data = &rtd1619b_desc, }, + {} +}; + +static int platform_init(struct bootstatus_data *data) +{ + struct device_node *np = of_find_node_by_path("/"); + const struct of_device_id *match; + + if (!np) + return -ENODEV; + + match = of_match_node(machines, np); + of_node_put(np); + if (!match) + return -ENODEV; + + data->desc = match->data; + return 0; +} + +struct kobject *rtk_bootstatus_kobj; + +static int __init rtk_bootstatus_init(void) +{ + int ret = 0; + + bootstatus_data = kzalloc(sizeof(*bootstatus_data), GFP_KERNEL); + WARN_ON(!bootstatus_data); + + if (bootstatus_data) { + bootinfo_init(bootstatus_data); + platform_init(bootstatus_data); + } + + rtk_bootstatus_kobj = kobject_create_and_add("bootstatus", kernel_kobj); + if (!rtk_bootstatus_kobj) + return -ENOMEM; + + ret = sysfs_create_group(rtk_bootstatus_kobj, &rtk_bootstatus_attr_group); + if (ret) + kobject_put(rtk_bootstatus_kobj); + + return ret; +} +module_init(rtk_bootstatus_init); diff --git a/drivers/soc/realtek/common/rtk_bsv_ctrl.c b/drivers/soc/realtek/common/rtk_bsv_ctrl.c new file mode 100644 index 000000000000..bc69577eb25f --- /dev/null +++ b/drivers/soc/realtek/common/rtk_bsv_ctrl.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BSV_CTRL_MAX_OPP 2 + +struct bsv_opp { + unsigned int freq_mhz; + unsigned int volt_uv; +}; + +struct bsv_config { + unsigned int volt_max; + unsigned int volt_min; + unsigned int volt_step; + unsigned int volt_round; + unsigned int volt_correct[BSV_CTRL_MAX_OPP]; + unsigned int num_volt_correct; +}; + +struct bsv_ctrl_data { + struct device *dev; + struct clk_hw hw; + struct clk *clk; + struct regulator *supply; + unsigned int cur_volt; + struct bsv_opp opps[BSV_CTRL_MAX_OPP]; + int num_opps; + const struct bsv_config *config; +}; + +static int bsv_ctrl_should_bypass(struct bsv_ctrl_data *data) +{ + return data->num_opps == 0; +} + +static unsigned int bsv_ctrl_volt(struct bsv_ctrl_data *data, int i) +{ + const struct bsv_config *cfg = data->config; + + return data->opps[i].volt_uv + (cfg->num_volt_correct == 1 ? cfg->volt_correct[0] : cfg->volt_correct[i]); +} + +static int bsv_ctrl_freq_to_volt(struct bsv_ctrl_data *data, int freq_mhz) +{ + const struct bsv_config *cfg = data->config; + int i; + int va, fa, vb, fb; + + for (i = 0; i < data->num_opps; i++) + if (freq_mhz < data->opps[i].freq_mhz) + break; + + if (i == data->num_opps) + return 0; + + if (i == 0) + return bsv_ctrl_volt(data, i) - (data->opps[i].freq_mhz - freq_mhz) / 100 * cfg->volt_step; + + va = bsv_ctrl_volt(data, i - 1); + fa = data->opps[i - 1].freq_mhz; + vb = bsv_ctrl_volt(data, i); + fb = data->opps[i].freq_mhz; + + return (vb - va) * (freq_mhz - fa) / (fb - fa) + va; +} + +static int bsv_ctrl_freq_to_volt_with_limit(struct bsv_ctrl_data *data, int freq_mhz) +{ + const struct bsv_config *cfg = data->config; + int target_volt = bsv_ctrl_freq_to_volt(data, freq_mhz); + + if (!target_volt) + return 0; + + if (target_volt < cfg->volt_min) + return cfg->volt_min; + + if (target_volt > cfg->volt_max) + return 0; + + return DIV_ROUND_UP(target_volt - cfg->volt_min, cfg->volt_round) * cfg->volt_round + + cfg->volt_min; +} + +static int bsv_ctrl_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +{ + struct bsv_ctrl_data *data = container_of(hw, struct bsv_ctrl_data, hw); + int ret; + int target_volt; + + if (bsv_ctrl_should_bypass(data)) + return clk_set_rate(data->clk, rate); + + target_volt = bsv_ctrl_freq_to_volt_with_limit(data, rate / 1000000); + if (!target_volt) + return -EINVAL; + + if (data->cur_volt < target_volt) { + ret = regulator_set_voltage(data->supply, target_volt, target_volt); + if (ret) + dev_warn(data->dev, "failed to set voltage: %d\n", ret); + } + + dev_dbg(data->dev, "%s: freq=%lu, volt=%d\n", __func__, rate, target_volt); + ret = clk_set_rate(data->clk, rate); + if (ret) + dev_warn(data->dev, "failed to set frequency: %d\n", ret); + + if (data->cur_volt > target_volt) { + ret = regulator_set_voltage(data->supply, target_volt, target_volt); + if (ret) + dev_warn(data->dev, "failed to set voltage: %d\n", ret); + } + + data->cur_volt = target_volt; + return 0; +} + +static unsigned long bsv_ctrl_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct bsv_ctrl_data *data = container_of(hw, struct bsv_ctrl_data, hw); + + return clk_get_rate(data->clk); +} + +static long bsv_ctrl_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) +{ + struct bsv_ctrl_data *data = container_of(hw, struct bsv_ctrl_data, hw); + + return clk_round_rate(data->clk, rate); +} + +static const struct clk_ops bsv_ctrl_clk_ops = { + .round_rate = bsv_ctrl_clk_round_rate, + .recalc_rate = bsv_ctrl_clk_recalc_rate, + .set_rate = bsv_ctrl_clk_set_rate, +}; + +static void bsv_ctrl_remove_of_clk_provider(void *d) +{ + struct bsv_ctrl_data *data = d; + + of_clk_del_provider(data->dev->of_node); +} + +static int bsv_ctrl_add_clk(struct bsv_ctrl_data *data) +{ + struct device *dev = data->dev; + struct device_node *np = dev->of_node; + struct clk_init_data init_data = { + .name = "bsv_vclk", + .ops = &bsv_ctrl_clk_ops, + .num_parents = 0, + .flags = CLK_GET_RATE_NOCACHE, + }; + int ret; + + data->hw.init = &init_data; + ret = devm_clk_hw_register(dev, &data->hw); + if (ret) + return ret; + + ret = of_clk_add_provider(np, of_clk_src_simple_get, data->hw.clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, bsv_ctrl_remove_of_clk_provider, data); + if (ret) + return ret; + + return 0; +} + +static int bsv_ctrl_regulator_list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct bsv_ctrl_data *data = rdev_get_drvdata(rdev); + + return regulator_list_voltage(data->supply, selector); +} + +static int bsv_ctrl_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct bsv_ctrl_data *data = rdev_get_drvdata(rdev); + + return regulator_get_voltage(data->supply); +} + +static int bsv_ctrl_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct bsv_ctrl_data *data = rdev_get_drvdata(rdev); + + if (bsv_ctrl_should_bypass(data)) + return regulator_set_voltage(data->supply, min_uV, max_uV); + + dev_dbg(data->dev, "%s: regulator_set_voltage() ignored\n", __func__); + return 0; +} + +static const struct regulator_ops bsv_ctrl_regulator_ops = { + .get_voltage = bsv_ctrl_regulator_get_voltage, + .set_voltage = bsv_ctrl_regulator_set_voltage, + .list_voltage = bsv_ctrl_regulator_list_voltage, +}; + +static struct regulator_desc bsv_ctrl_supply_desc = { + .owner = THIS_MODULE, + .ops = &bsv_ctrl_regulator_ops, + .type = REGULATOR_VOLTAGE, + .name = "bsv_cpudvs", +}; + +static int bsv_ctrl_add_supply(struct bsv_ctrl_data *data) +{ + struct regulator_config config = { + .dev = data->dev, + .of_node = data->dev->of_node, + .driver_data = data, + }; + + bsv_ctrl_supply_desc.n_voltages = regulator_count_voltages(data->supply); + + config.init_data = of_get_regulator_init_data(data->dev, data->dev->of_node, + &bsv_ctrl_supply_desc); + + if (!config.init_data) + return -ENOMEM; + + return PTR_ERR_OR_ZERO(devm_regulator_register(data->dev, &bsv_ctrl_supply_desc, &config)); +} + +static int bsv_ctrl_add_suppliers(struct bsv_ctrl_data *data) +{ + int ret; + + ret = bsv_ctrl_add_clk(data); + if (ret) { + dev_err(data->dev, "failed to add clk: %d\n", ret); + return ret; + } + + ret = bsv_ctrl_add_supply(data); + if (ret) { + dev_err(data->dev, "failed to add supply: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct bsv_config default_config = { + .volt_max = 1050000, + .volt_min = 800000, + .volt_step = 25000, + .volt_round = 12500, + .volt_correct = {150000, 175000}, + .num_volt_correct = 2, +}; + +static int bsv_ctrl_get_otp_val(struct bsv_ctrl_data *data, unsigned int *val) +{ + struct device *dev = data->dev; + struct nvmem_cell *cell; + int ret = -EINVAL; + unsigned char *buf; + size_t buf_size; + + cell = nvmem_cell_get(dev, "bsv"); + if (IS_ERR(cell)) { + ret = PTR_ERR(cell); + dev_warn(dev, "invalid nvmem cell: %d\n", ret); + return ret; + } + + buf = nvmem_cell_read(cell, &buf_size); + + val[0] = val[1] = 0; + if (buf_size == 4) { + dev_info(dev, "otp_val=%d,%d\n", buf[1], buf[3]); + val[0] = buf[1]; + val[1] = buf[3]; + } + + kfree(buf); + nvmem_cell_put(cell); + return val[0] && val[1] ? 0 : -EINVAL; +} + +static int bsv_ctrl_setup_opps(struct bsv_ctrl_data *data) +{ + unsigned int val[2]; + + if (bsv_ctrl_get_otp_val(data, val)) + return 0; + + data->opps[0].freq_mhz = 1400; + data->opps[0].volt_uv = val[0] * 10000; + + data->opps[1].freq_mhz = 1800; + data->opps[1].volt_uv = val[1] * 10000; + + data->num_opps = 2; + + return 0; +} + +static int bsv_ctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bsv_ctrl_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->dev = dev; + + data->clk = devm_clk_get(dev, NULL); + if (IS_ERR(data->clk)) { + ret = PTR_ERR(data->clk); + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + data->supply = devm_regulator_get(dev, "cpu"); + if (IS_ERR(data->supply)) { + ret = PTR_ERR(data->supply); + dev_err(dev, "failed to get supply: %d\n", ret); + return ret; + } + + data->config = &default_config; + data->cur_volt = regulator_get_voltage(data->supply); + bsv_ctrl_setup_opps(data); + + return bsv_ctrl_add_suppliers(data); +} + +static const struct of_device_id bsv_ctrl_match[] = { + { .compatible = "realtek,bsv-controller", }, + {} +}; + +static struct platform_driver bsv_ctrl_driver = { + .probe = bsv_ctrl_probe, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-bsv-ctrl", + .of_match_table = of_match_ptr(bsv_ctrl_match), + }, +}; +module_platform_driver(bsv_ctrl_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rtk-bsv-ctrl"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_DESCRIPTION("Realtek BSV Supply"); diff --git a/drivers/soc/realtek/common/rtk_cpu_vclk.c b/drivers/soc/realtek/common/rtk_cpu_vclk.c new file mode 100644 index 000000000000..070596123c46 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_cpu_vclk.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include + +struct freq_map { + unsigned long freq; + unsigned long target_freq; + int cpuhp_num; +}; + +struct rtk_cpu_vclk_data { + struct device *dev; + struct clk_hw hw; + struct rtk_cpuhp_qos_request req; + unsigned long cur; + const struct freq_map *maps; + int num_maps; + struct clk *clk; +}; + +static const struct freq_map *lookup_freq_map(struct rtk_cpu_vclk_data *data, unsigned long freq) +{ + int i; + + for (i = 0; i < data->num_maps; i++) { + if (data->maps[i].freq == freq) + return &data->maps[i]; + } + return NULL; +} + +static int rtk_cpu_vclk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +{ + struct rtk_cpu_vclk_data *data = container_of(hw, struct rtk_cpu_vclk_data, hw); + const struct freq_map *map; + int ret; + unsigned long target_freq = rate; + int cpuhp_num = 0; + + dev_dbg(data->dev, "%s: rate=%lu\n", __func__, rate); + + map = lookup_freq_map(data, rate); + if (map) { + target_freq = map->target_freq; + cpuhp_num = map->cpuhp_num; + } + + ret = clk_set_rate(data->clk, target_freq); + if (ret) + return ret; + rtk_cpuhp_qos_update_request(&data->req, cpuhp_num); + data->cur = rate; + return ret; +} + +static unsigned long rtk_cpu_vclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct rtk_cpu_vclk_data *data = container_of(hw, struct rtk_cpu_vclk_data, hw); + + return data->cur ?: clk_get_rate(data->clk); +} + +static long rtk_cpu_vclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) +{ + struct rtk_cpu_vclk_data *data = container_of(hw, struct rtk_cpu_vclk_data, hw); + + return clk_round_rate(data->clk, rate); +} + +static const struct clk_ops rtk_cpu_vclk_ops = { + .round_rate = rtk_cpu_vclk_round_rate, + .recalc_rate = rtk_cpu_vclk_recalc_rate, + .set_rate = rtk_cpu_vclk_set_rate, +}; + +static int rtk_cpu_vclk_parse_freq_maps(struct rtk_cpu_vclk_data *data) +{ + struct device_node *np = data->dev->of_node; + const struct property *prop; + const __be32 *val; + int len; + struct freq_map *maps; + int i; + + prop = of_find_property(np, "freq-maps", NULL); + if (!prop || !prop->value || (prop->length % 12) != 0) + return -EINVAL; + + len = prop->length / 12; + val = prop->value; + + maps = devm_kcalloc(data->dev, len, sizeof(*maps), GFP_KERNEL); + if (!maps) + return -ENOMEM; + + for (i = 0; i < len; i++) { + maps[i].freq = be32_to_cpup(val++) * 1000; + maps[i].target_freq = be32_to_cpup(val++) * 1000; + maps[i].cpuhp_num = be32_to_cpup(val++); + } + + data->maps = maps; + data->num_maps = len; + return 0; +} + +static void rtk_cpu_vclk_remove_of_clk_provider(void *d) +{ + struct rtk_cpu_vclk_data *data = d; + + of_clk_del_provider(data->dev->of_node); +} + +static int rtk_cpu_vclk_add_clk(struct rtk_cpu_vclk_data *data) +{ + struct device *dev = data->dev; + struct clk_init_data init_data = { + .name = "vclk_scpu", + .ops = &rtk_cpu_vclk_ops, + .num_parents = 0, + .flags = CLK_GET_RATE_NOCACHE, + }; + int ret; + + data->hw.init = &init_data; + ret = devm_clk_hw_register(dev, &data->hw); + if (ret) + return ret; + + ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get, data->hw.clk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, rtk_cpu_vclk_remove_of_clk_provider, data); +} + +static int rtk_cpu_vclk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_cpu_vclk_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->dev = dev; + + data->clk = devm_clk_get(dev, NULL); + ret = PTR_ERR_OR_ZERO(data->clk); + if (ret) { + if (ret == -EPROBE_DEFER) + dev_info(dev, "clock not ready, retry\n"); + else + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + ret = rtk_cpu_vclk_parse_freq_maps(data); + if (ret) { + dev_err(dev, "failed to parse freq map: %d\n", ret); + return ret; + } + + ret = rtk_cpu_vclk_add_clk(data); + if (ret) { + dev_err(dev, "failed to add clk: %d\n", ret); + return ret; + } + + ret = rtk_cpuhp_qos_add_request(&data->req, 0); + if (ret) { + dev_err(dev, "failed to add cpuhp qos request: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, data); + return 0; +} + +static int rtk_cpu_vclk_remove(struct platform_device *pdev) +{ + struct rtk_cpu_vclk_data *data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + rtk_cpuhp_qos_remove_request(&data->req); + return 0; +} + +static const struct of_device_id rtk_cpu_vclk_ids[] = { + { .compatible = "realtek,cpu-vclk" }, + {} +}; + +static struct platform_driver rtk_cpu_vclk_driver = { + .probe = rtk_cpu_vclk_probe, + .remove = rtk_cpu_vclk_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-cpu-vclk", + .of_match_table = rtk_cpu_vclk_ids, + }, +}; +module_platform_driver(rtk_cpu_vclk_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rtk-cpu-vclk"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_DESCRIPTION("Realtek CPU Virtual Clock Controller"); diff --git a/drivers/soc/realtek/common/rtk_cpuhp.c b/drivers/soc/realtek/common/rtk_cpuhp.c new file mode 100644 index 000000000000..06f5757c8c66 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_cpuhp.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include + +#define RTK_CPUHP_DEFAULT_VALUE 0 + +static BLOCKING_NOTIFIER_HEAD(rtk_cpuhp_notifiers); +static struct pm_qos_constraints rtk_cpuhp_constraints = { + .list = PLIST_HEAD_INIT(rtk_cpuhp_constraints.list), + .target_value = RTK_CPUHP_DEFAULT_VALUE, + .default_value = RTK_CPUHP_DEFAULT_VALUE, + .no_constraint_value = RTK_CPUHP_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &rtk_cpuhp_notifiers, +}; + +s32 rtk_cpuhp_qos_read_value(void) +{ + return pm_qos_read_value(&rtk_cpuhp_constraints); +} + +int rtk_cpuhp_qos_add_request(struct rtk_cpuhp_qos_request *req, s32 value) +{ + int ret; + + if (!req) + return -EINVAL; + + if (WARN(rtk_cpuhp_qos_request_active(req), + "%s() called for active request\n", __func__)) + return -EINVAL; + + req->qos = &rtk_cpuhp_constraints; + ret = pm_qos_update_target(req->qos, &req->pnode, PM_QOS_ADD_REQ, value); + if (ret < 0) + req->qos = NULL; + return ret; +} + +int rtk_cpuhp_qos_update_request(struct rtk_cpuhp_qos_request *req, s32 new_value) +{ + if (!req) + return -EINVAL; + + if (WARN(!rtk_cpuhp_qos_request_active(req), + "%s() called for unknown object\n", __func__)) + return -EINVAL; + + if (req->pnode.prio == new_value) + return 0; + + return pm_qos_update_target(req->qos, &req->pnode, PM_QOS_UPDATE_REQ, new_value); +} + +int rtk_cpuhp_qos_remove_request(struct rtk_cpuhp_qos_request *req) +{ + int ret; + + if (!req) + return -EINVAL; + + if (WARN(!rtk_cpuhp_qos_request_active(req), + "%s() called for unknown object\n", __func__)) + return -EINVAL; + + ret = pm_qos_update_target(req->qos, &req->pnode, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); + req->qos = NULL; + return ret; +} + +int rtk_cpuhp_qos_add_notifier(struct notifier_block *notifier) +{ + return blocking_notifier_chain_register(rtk_cpuhp_constraints.notifiers, + notifier); +} + +int rtk_cpuhp_qos_remove_notifier(struct notifier_block *notifier) +{ + return blocking_notifier_chain_unregister(rtk_cpuhp_constraints.notifiers, + notifier); +} diff --git a/drivers/soc/realtek/common/rtk_cpuhp_ctrl.c b/drivers/soc/realtek/common/rtk_cpuhp_ctrl.c new file mode 100644 index 000000000000..eceb0be67cc9 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_cpuhp_ctrl.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rtk_cpuhp_ctrl_data { + struct device *dev; + struct completion complete; + struct task_struct *task; + struct notifier_block cpuhp_nb; + int dyn_state; +}; + +static struct rtk_cpuhp_ctrl_data *ctrl_data; + +static void set_cpu_device_offline(int cpu_id) +{ + struct device *cpu_dev = get_cpu_device(cpu_id); + + if (WARN_ON(cpu_id == 0)) + return; + + device_offline(cpu_dev); +} + +static void set_cpu_device_online(int cpu_id) +{ + struct device *cpu_dev = get_cpu_device(cpu_id); + + device_online(cpu_dev); +} + +static int next_cpu_to_online(void) +{ + struct cpumask v; + + cpumask_xor(&v, cpu_possible_mask, cpu_online_mask); + return cpumask_first(&v); +} + +static int next_cpu_to_offline(void) +{ + return find_last_bit(cpumask_bits(cpu_online_mask), nr_cpumask_bits); +} + +static int get_offline_cpu_num(struct rtk_cpuhp_ctrl_data *c) +{ + int v; + + get_online_cpus(); + v = num_online_cpus(); + put_online_cpus(); + return num_possible_cpus() - v; +} + +static int rtk_cpuhp_ctrl_do_task(void *data) +{ + struct rtk_cpuhp_ctrl_data *c = data; + int ret; + unsigned int n_off, excepted; + int cpu; + + for (;;) { + ret = wait_for_completion_timeout(&c->complete, 2 * HZ); + if (kthread_should_stop()) { + pr_debug("stop %s\n", __func__); + break; + } + + reinit_completion(&c->complete); + if (ret == 0) + continue; + + excepted = rtk_cpuhp_qos_read_value(); + n_off = get_offline_cpu_num(c); + + pr_debug("%s: cpu_num=%d, excepted=%d\n", __func__, + n_off, excepted); + if (n_off == excepted) + continue; + + if (n_off > excepted) { + cpu = next_cpu_to_online(); + pr_debug("set cpu%d online\n", cpu); + set_cpu_device_online(cpu); + } else { + cpu = next_cpu_to_offline(); + pr_debug("set cpu%d offline\n", cpu); + set_cpu_device_offline(cpu); + } + + msleep(500); + } + return 0; +} + +static int rtk_cpuhp_ctrl_cpu_online(unsigned int cpu) +{ + struct rtk_cpuhp_ctrl_data *c = ctrl_data; + + complete(&c->complete); + pr_debug("start task from %s", __func__); + return 0; +} + +static int rtk_cpuhp_ctrl_cpu_offline(unsigned int cpu) +{ + struct rtk_cpuhp_ctrl_data *c = ctrl_data; + + complete(&c->complete); + pr_debug("start task from %s", __func__); + return 0; +} + +static int rtk_cpuhp_ctrl_callback(struct notifier_block *nb, unsigned long action, void *data) +{ + struct rtk_cpuhp_ctrl_data *c = container_of(nb, struct rtk_cpuhp_ctrl_data, cpuhp_nb); + + complete(&c->complete); + pr_debug("start task from %s", __func__); + return NOTIFY_OK; +} + +static __init int rtk_cpuhp_ctrl_init(void) +{ + struct rtk_cpuhp_ctrl_data *c; + int ret; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + init_completion(&c->complete); + + c->task = kthread_create(rtk_cpuhp_ctrl_do_task, c, "cpuhp_ctrl_task"); + if (IS_ERR(c->task)) { + ret = PTR_ERR(c->task); + pr_err("failed to create kthread: %d\n", ret); + return ret; + } + kthread_bind(c->task, 0); + wake_up_process(c->task); + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "cpuhp_ctrl_data:online", + rtk_cpuhp_ctrl_cpu_online, rtk_cpuhp_ctrl_cpu_offline); + if (ret < 0) { + pr_err("failed to steup cpuhp state: %d\n", ret); + goto remove_kthread; + } + c->dyn_state = ret; + + c->cpuhp_nb.notifier_call = rtk_cpuhp_ctrl_callback; + ret = rtk_cpuhp_qos_add_notifier(&c->cpuhp_nb); + if (ret) { + pr_err("failed add cpuhp qos notifier: %d\n", ret); + goto remove_cpuhp_state; + } + + ctrl_data = c; + return 0; + +remove_cpuhp_state: + cpuhp_remove_state_nocalls(c->dyn_state); +remove_kthread: + kthread_stop(c->task); + kfree(c); + return ret; +} +module_init(rtk_cpuhp_ctrl_init); + +static __exit void rtk_cpuhp_ctrl_exit(void) +{ + struct rtk_cpuhp_ctrl_data *c = ctrl_data; + + rtk_cpuhp_qos_remove_notifier(&c->cpuhp_nb); + cpuhp_remove_state_nocalls(c->dyn_state); + kthread_stop(c->task); + + kfree(c); + ctrl_data = NULL; +} +module_exit(rtk_cpuhp_ctrl_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_DESCRIPTION("Realtek CPU Hotplug Controller"); + diff --git a/drivers/soc/realtek/common/rtk_crt.c b/drivers/soc/realtek/common/rtk_crt.c new file mode 100644 index 000000000000..a41c4624ab7f --- /dev/null +++ b/drivers/soc/realtek/common/rtk_crt.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct rtk_crt_pm_data { + int ofs; + uint32_t ignore_bits; + uint32_t write_en_bits; + uint32_t val; +}; + +struct rtk_crt_platform_desc { + int pm_data_num; + struct rtk_crt_pm_data *pm_data; +}; + +struct rtk_crt_data { + struct regmap *regmap; + const struct rtk_crt_platform_desc *desc; +}; + +static struct rtk_crt_pm_data rtd1295_pm_data[] = { + /* SOFT_RESET */ + { .ofs = 0x000, .ignore_bits = 0x00001000, }, + { .ofs = 0x004, }, + /* CLK_EN */ + { .ofs = 0x00C, .ignore_bits = 0x0001C100, }, + { .ofs = 0x010, }, + { .ofs = 0x450, .ignore_bits = 0xFFFFFFFB, }, + /* PLL_GPU */ + { .ofs = 0x1C4, }, + { .ofs = 0x5A4, .ignore_bits = ~(0x7FFFF), }, + /* PLL_VE1 */ + { .ofs = 0x118, }, + { .ofs = 0x114, .ignore_bits = ~(0x63FF0), }, + /* PLL_VE2 */ + { .ofs = 0x1D4, }, + { .ofs = 0x1D0, .ignore_bits = ~(0x63FF0), }, +}; + +static const struct rtk_crt_platform_desc rtd1295_crt_desc = { + .pm_data_num = ARRAY_SIZE(rtd1295_pm_data), + .pm_data = rtd1295_pm_data, +}; + +static struct rtk_crt_pm_data rtd1395_pm_data[] = { + /* SOFT_RESET */ + { .ofs = 0x00, .ignore_bits = 0x00001000, }, + { .ofs = 0x04, }, + { .ofs = 0x50, }, + /* CLK_EN */ + { .ofs = 0x0C, .ignore_bits = 0x0004c524, }, + { .ofs = 0x10, .ignore_bits = 0xc0fe0030, }, + /* PLL_GPU */ + { .ofs = 0x1C4, }, + { .ofs = 0x5A4, .ignore_bits = ~(0x7FFFF), }, + /* PLL_VE1 */ + { .ofs = 0x118, }, + { .ofs = 0x114, .ignore_bits = ~(0x63FF0), }, + /* PLL_VE2 */ + { .ofs = 0x1D4, }, + { .ofs = 0x1D0, .ignore_bits = ~(0x63FF0), }, +}; + +static const struct rtk_crt_platform_desc rtd1395_crt_desc = { + .pm_data_num = ARRAY_SIZE(rtd1395_pm_data), + .pm_data = rtd1395_pm_data, +}; + +static struct rtk_crt_pm_data rtd1619_pm_data[] = { + /* SOFT_RESET */ + { .ofs = 0x00, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x04, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x08, .write_en_bits = 0x0A80AAAA, }, + { .ofs = 0x0C, .write_en_bits = 0x2AAAAAAA, }, + { .ofs = 0x68, .write_en_bits = 0xAAAAAAAA, }, + /* CLK_EN */ + { .ofs = 0x50, .write_en_bits = 0xA0A8288A, }, + { .ofs = 0x54, .write_en_bits = 0xAAAAAAA8, }, + { .ofs = 0x58, .write_en_bits = 0xA800082A, }, + { .ofs = 0x5C, .write_en_bits = 0xAAAAAA0A, }, + /* PLL_GPU */ + { .ofs = 0x1C4, }, + { .ofs = 0x5A4, .ignore_bits = ~(0x7FFFF), }, + /* PLL_VE1 */ + { .ofs = 0x118, }, + { .ofs = 0x114, .ignore_bits = ~(0x63FF0), }, + /* PLL_VE2 */ + { .ofs = 0x1D4, }, + { .ofs = 0x1D0, .ignore_bits = ~(0x63FF0), }, +}; + +static const struct rtk_crt_platform_desc rtd1619_crt_desc = { + .pm_data_num = ARRAY_SIZE(rtd1619_pm_data), + .pm_data = rtd1619_pm_data, +}; + +static struct rtk_crt_pm_data rtd1319_pm_data[] = { + /* SOFT_RESET */ + { .ofs = 0x000, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x004, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x008, .write_en_bits = 0x0A80AAAA, }, + { .ofs = 0x00C, .write_en_bits = 0x2AAAAAAA, }, + { .ofs = 0x068, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x090, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x454, .ignore_bits = 0xFFFFFFFE, }, + { .ofs = 0x458, .ignore_bits = 0xFFFFFFFE, }, + { .ofs = 0x464, .ignore_bits = 0xFFFFFFFE, }, + /* CLK_EN */ + { .ofs = 0x050, .write_en_bits = 0xA0A8288A, }, + { .ofs = 0x054, .write_en_bits = 0xAAAAAAA8, }, + { .ofs = 0x058, .write_en_bits = 0xA800082A, }, + { .ofs = 0x05C, .write_en_bits = 0xAAAAAA0A, }, + { .ofs = 0x08C, .write_en_bits = 0xAAAAAAAA, }, + /* PLL_GPU */ + { .ofs = 0x1C4, }, + { .ofs = 0x5A4, .ignore_bits = ~(0x7FFFF), }, + /* PLL_VE1 */ + { .ofs = 0x118, }, + { .ofs = 0x114, .ignore_bits = ~(0x63FF0), }, + /* PLL_VE2 */ + { .ofs = 0x1D4, }, + { .ofs = 0x1D0, .ignore_bits = ~(0x63FF0), }, +}; + +static const struct rtk_crt_platform_desc rtd1319_crt_desc = { + .pm_data_num = ARRAY_SIZE(rtd1319_pm_data), + .pm_data = rtd1319_pm_data, +}; + +static struct rtk_crt_pm_data rtd1619b_pm_data[] = { + /* SOFT_RESET */ + { .ofs = 0x000, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x004, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x008, .write_en_bits = 0x0A80AAAA, }, + { .ofs = 0x00C, .write_en_bits = 0x2AAAAAAA, }, + { .ofs = 0x068, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x090, .write_en_bits = 0xAAAAAAAA, }, + { .ofs = 0x454, .ignore_bits = 0xFFFFFFFE, }, + { .ofs = 0x458, .ignore_bits = 0xFFFFFFFE, }, + { .ofs = 0x464, .ignore_bits = 0xFFFFFFFE, }, + /* CLK_EN */ + { .ofs = 0x050, .write_en_bits = 0xA0A8288A, }, + { .ofs = 0x054, .write_en_bits = 0xAAAAAAA8, }, + { .ofs = 0x058, .write_en_bits = 0xA800082A, }, + { .ofs = 0x05C, .write_en_bits = 0xAAAAAA0A, }, + { .ofs = 0x08C, .write_en_bits = 0xAAAAAAAA, }, + /* PLL_GPU */ + { .ofs = 0x1C4, }, + { .ofs = 0x5A4, .ignore_bits = ~(0x7FFFF), }, + /* PLL_VE1 */ + { .ofs = 0x118, }, + { .ofs = 0x114, .ignore_bits = ~(0x63FF0), }, + /* PLL_VE2 */ + { .ofs = 0x1D4, }, + { .ofs = 0x1D0, .ignore_bits = ~(0x63FF0), }, +}; + +static const struct rtk_crt_platform_desc rtd1619b_crt_desc = { + .pm_data_num = ARRAY_SIZE(rtd1619b_pm_data), + .pm_data = rtd1619b_pm_data, +}; + + +static int rtk_crt_suspend(struct device *dev) +{ + struct rtk_crt_data *crt = dev_get_drvdata(dev); + const struct rtk_crt_platform_desc *desc = crt->desc; + int i; + + for (i = 0; i < desc->pm_data_num; i++) { + struct rtk_crt_pm_data *pm_data = &desc->pm_data[i]; + + regmap_read(crt->regmap, pm_data->ofs, &pm_data->val); + } + return 0; +} + +static int rtk_crt_resume(struct device *dev) +{ + struct rtk_crt_data *crt = dev_get_drvdata(dev); + const struct rtk_crt_platform_desc *desc = crt->desc; + int i; + + for (i = desc->pm_data_num - 1; i >= 0; i--) { + struct rtk_crt_pm_data *pm_data = &desc->pm_data[i]; + uint32_t val = pm_data->val; + uint32_t mask = ~0x0; + + if (pm_data->write_en_bits) + val |= pm_data->write_en_bits; + if (pm_data->ignore_bits) + mask &= ~pm_data->ignore_bits; + dev_info(dev, "resuming: ofs=%03x, vs=%08x vr=%08x m=%08x\n", + pm_data->ofs, pm_data->val, val, mask); + regmap_update_bits(crt->regmap, pm_data->ofs, mask, val); + } + return 0; +} + +const struct dev_pm_ops rtk_crt_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rtk_crt_suspend, rtk_crt_resume) +}; + +static int rtk_crt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_crt_data *crt; + int ret; + + crt = devm_kzalloc(dev, sizeof(*crt), GFP_KERNEL); + if (!crt) + return -ENOMEM; + + crt->desc = of_device_get_match_data(dev); + if (!crt->desc) + return -EINVAL; + + crt->regmap = syscon_node_to_regmap(np); + if (IS_ERR(crt->regmap)) { + ret = PTR_ERR(crt->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, crt); + return 0; +} + +static const struct of_device_id rtk_crt_match[] = { + { .compatible = "realtek,rtd1295-crt", .data = &rtd1295_crt_desc, }, + { .compatible = "realtek,rtd1395-crt", .data = &rtd1395_crt_desc, }, + { .compatible = "realtek,rtd1619-crt", .data = &rtd1619_crt_desc, }, + { .compatible = "realtek,rtd1319-crt", .data = &rtd1319_crt_desc, }, + { .compatible = "realtek,rtd1619b-crt", .data = &rtd1619b_crt_desc, }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_crt_match); + +static struct platform_driver rtk_crt_driver = { + .probe = rtk_crt_probe, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-crt", + .pm = &rtk_crt_pm_ops, + .of_match_table = of_match_ptr(of_match_ptr(rtk_crt_match)), + }, +}; +module_platform_driver(rtk_crt_driver); + +MODULE_DESCRIPTION("Realtek CRT driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-crt"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/soc/realtek/common/rtk_fan.c b/drivers/soc/realtek/common/rtk_fan.c new file mode 100644 index 000000000000..ed1845af146b --- /dev/null +++ b/drivers/soc/realtek/common/rtk_fan.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtd129x_fan.c - fan driver + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Copyright (C) 2020 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_FAN_CTRL 0x0 +#define REG_FAN_DEBOUNCE 0x4 +#define REG_FAN_TIMER_TV 0x8 +#define REG_FAN_TIMER_CV 0xC +#define REG_FAN_COUNTER_CV 0x10 + +#define FAN_EN BIT(0) +#define FAN_INT_EN BIT(1) + +#define FAN_DEBOUNCE_W_EN BIT(3) +#define FAN_DEBOUNCE_MASK 0x7 + +#define FAN_DEBOUNCE_DEFAULT 0x0 +#define FAN_TIMER_TV_DEFAULT 0x100 + +#define SB2_MUXPAD4_FAN_EN_MASK (0x3 << 22) +#define SB2_MUXPAD4_FAN_EN (0x2 << 22) + +#define TIMER_CLK90K 90000 + +struct rtk_fan_data { + void __iomem *reg_base; + + struct device *dev; + struct pwm_device *pwm; + + int fan_debounce; + int timer_target; + uint32_t fan_factor; + uint64_t speed_rpm; + + int ctrl_speed; +#define MAX_CTRL_SPEED 10 +}; + +static int rtk_fan_enable(struct rtk_fan_data *fan_data) { + void __iomem *reg_base = fan_data->reg_base; + + writel(FAN_EN | FAN_INT_EN, reg_base + REG_FAN_CTRL); + + dev_dbg(fan_data->dev, "%s REG_FAN_CTRL=0x%x", + __func__, readl(reg_base + REG_FAN_CTRL)); + + return 0; +} + +static int rtk_fan_disable(struct rtk_fan_data *fan_data) { + void __iomem *reg_base = fan_data->reg_base; + + writel(0x0, reg_base + REG_FAN_CTRL); + + dev_dbg(fan_data->dev, "%s REG_FAN_CTRL=0x%x", + __func__, readl(reg_base + REG_FAN_CTRL)); + + return 0; +} + +static int rtk_fan_get_debound_time(struct rtk_fan_data *fan_data) { + void __iomem *reg_base = fan_data->reg_base; + int fan_debounce; + + fan_debounce = readl(reg_base + REG_FAN_DEBOUNCE) & FAN_DEBOUNCE_MASK; + + if (fan_debounce != fan_data->fan_debounce) { + dev_err(fan_data->dev, "%s ERROR fan_debounce = %x, but set fan_debounce = %x", + __func__, fan_debounce, fan_data->fan_debounce); + } + return fan_debounce; +} + +static int rtk_fan_set_debound_time(struct rtk_fan_data *fan_data, int fan_debounce_new) { + void __iomem *reg_base = fan_data->reg_base; + int fan_debounce; + + fan_debounce = rtk_fan_get_debound_time(fan_data); + if (fan_debounce != fan_debounce_new) { + writel(FAN_DEBOUNCE_W_EN | + (fan_debounce_new & FAN_DEBOUNCE_MASK), + reg_base + REG_FAN_DEBOUNCE); + fan_data->fan_debounce = fan_debounce; + } + return 0; +} + +static int rtk_fan_get_timer_target(struct rtk_fan_data *fan_data) { + void __iomem *reg_base = fan_data->reg_base; + int timer_target; + + timer_target = readl(reg_base + REG_FAN_TIMER_TV); + + if (timer_target != fan_data->timer_target) { + dev_err(fan_data->dev, "%s ERROR timer_target = %d, but set timer_target = %d", + __func__, timer_target, fan_data->timer_target); + } + return timer_target; +} + +static int rtk_fan_set_timer_target(struct rtk_fan_data *fan_data, int timer_target_new) { + void __iomem *reg_base = fan_data->reg_base; + int timer_target; + + timer_target = rtk_fan_get_timer_target(fan_data); + if (timer_target != timer_target_new) { + writel(timer_target_new, reg_base + REG_FAN_TIMER_TV); + fan_data->timer_target = timer_target_new; + } + return 0; +} + +static int rtk_fan_get_speed(struct rtk_fan_data *fan_data) { + return fan_data->speed_rpm; +} + +static int rtk_fan_ctrl_speed(struct rtk_fan_data *fan_data, int ctrl_speed) { + if (ctrl_speed > MAX_CTRL_SPEED) ctrl_speed = MAX_CTRL_SPEED; + + if (fan_data->pwm) { + int period_ns = pwm_get_period(fan_data->pwm); + int duty_ns = period_ns * ctrl_speed / MAX_CTRL_SPEED; + dev_dbg(fan_data->dev, "%s to set pwm default duty_ns =%d, period_ns = %d!", + __func__, duty_ns, period_ns); + pwm_config(fan_data->pwm, duty_ns, period_ns); + } + fan_data->ctrl_speed = ctrl_speed; + + return 0; +} + +static int rtk_fan_compute_speed(struct rtk_fan_data *fan_data) { + void __iomem *reg_base = fan_data->reg_base; + + int timer_target, counter_value; + uint64_t factor = TIMER_CLK90K * 60; /* second to minute */ + uint64_t speed; + + timer_target = fan_data->timer_target; + counter_value = readl(reg_base + REG_FAN_COUNTER_CV); + + if (!timer_target) + return 0; + + counter_value = counter_value / fan_data->fan_factor; + + /* For example */ + /* speed is RPM */ + /* speed = ((counter_value / fan_factor) / (timer / TIMER_CLK90K)) * 60 */ + + speed = div_u64((counter_value * factor), timer_target); + + fan_data->speed_rpm = speed; + + dev_dbg(fan_data->dev, "%s speed =%llu (RPM)\n", __func__, speed); + dev_dbg(fan_data->dev, "%s timer_target=%d, counter_value=%d factor=%lld\n", + __func__, timer_target, counter_value, factor); + + return 0; +} + +static irqreturn_t rtk_fan_irq(int irq, void *data) { + struct rtk_fan_data *fan_data = (struct rtk_fan_data *) data; + struct device *dev = fan_data->dev; + + dev_dbg(dev, "%s Enter ...", __func__); + + rtk_fan_compute_speed(fan_data); + + dev_dbg(dev, "%s Exit ...", __func__); + return IRQ_HANDLED; +} + +static ssize_t fan_debounce_show(struct device *dev, struct device_attribute *attr, char *buffer) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + + return sprintf(buffer, "%d\n", rtk_fan_get_debound_time(fan_data)); +} + +static ssize_t fan_debounce_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t size) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + int ret; + int value; + + ret = sscanf(buffer, "%d", &value); + if (ret != 1) + return -EINVAL; + + rtk_fan_set_debound_time(fan_data, value); + + return size; +} + +static ssize_t fan_timer_target_show(struct device *dev, + struct device_attribute *attr, char *buffer) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + + return sprintf(buffer, "%d\n", rtk_fan_get_timer_target(fan_data)); +} + +static ssize_t fan_timer_target_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t size) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + int ret; + int value; + + ret = sscanf(buffer, "%d", &value); + if (ret != 1) + return -EINVAL; + + rtk_fan_set_timer_target(fan_data, value); + + return size; +} + +static ssize_t fan_timer_value_show(struct device *dev, + struct device_attribute *attr, char *buffer) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + + return sprintf(buffer, "real-time timer value %d\n", readl(fan_data->reg_base + REG_FAN_TIMER_CV)); +} + +static ssize_t fan_counter_value_show(struct device *dev, + struct device_attribute *attr, char *buffer) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + + return sprintf(buffer, "real-time counter value %d\n", readl(fan_data->reg_base + REG_FAN_COUNTER_CV)); +} + +static ssize_t fan_speed_show(struct device *dev, + struct device_attribute *attr, char *buffer) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + + return sprintf(buffer, "%u (RPM)\n", rtk_fan_get_speed(fan_data)); +} + +static ssize_t fan_ctrl_speed_show(struct device *dev, + struct device_attribute *attr, char *buffer) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + + return sprintf(buffer, "now %d of %d (set 0~10)\n", fan_data->ctrl_speed, MAX_CTRL_SPEED); +} + +static ssize_t fan_ctrl_speed_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t size) { + struct rtk_fan_data *fan_data = dev_get_drvdata(dev); + int ret; + int value; + + ret = sscanf(buffer, "%d", &value); + if (ret != 1) + return -EINVAL; + + rtk_fan_disable(fan_data); + + rtk_fan_ctrl_speed(fan_data, value); + + rtk_fan_enable(fan_data); + + return size; +} + +static DEVICE_ATTR(fan_debounce, 0644, fan_debounce_show, fan_debounce_store); +static DEVICE_ATTR(fan_timer_target, 0644, fan_timer_target_show, fan_timer_target_store); +static DEVICE_ATTR_RO(fan_timer_value); +static DEVICE_ATTR_RO(fan_counter_value); +static DEVICE_ATTR_RO(fan_speed); +static DEVICE_ATTR(fan_ctrl_speed, 0644, fan_ctrl_speed_show, fan_ctrl_speed_store); + +static const struct attribute *rtk_fan_attrs[] = { + &dev_attr_fan_debounce.attr, + &dev_attr_fan_timer_target.attr, + &dev_attr_fan_timer_value.attr, + &dev_attr_fan_counter_value.attr, + &dev_attr_fan_speed.attr, + &dev_attr_fan_ctrl_speed.attr, + NULL +}; + +static int rtk_fan_create_sysfs(struct rtk_fan_data *fan_data) +{ + struct device *dev = fan_data->dev; + int retval; + + retval = sysfs_create_files(&dev->kobj, + (const struct attribute **)rtk_fan_attrs); + + return retval; +} + +static int rtk_fan_init(struct rtk_fan_data *fan_data, struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + int ret; + int fan_debounce, timer_target; + + /* GET clock */ + struct clk *clk_fan = clk_get(dev, NULL); + /* GET reset controller */ + struct reset_control *reset_fan = reset_control_get_exclusive(dev, NULL); + + reset_control_deassert(reset_fan); + clk_prepare_enable(clk_fan); + + ret = of_property_read_u32(node, "fan_debounce", + &fan_debounce); + if (ret < 0) { + dev_info(dev, "%s NO set debounce time!", __func__); + fan_debounce = FAN_DEBOUNCE_DEFAULT; + } + rtk_fan_set_debound_time(fan_data, fan_debounce); + + ret = of_property_read_u32(node, "timer_target", + &timer_target); + if (ret < 0) { + dev_info(dev, "%s NO set timer_target!", __func__); + timer_target = FAN_TIMER_TV_DEFAULT; + } + + ret = of_property_read_u32(node, "fan_factor", + &(fan_data->fan_factor)); + if (ret < 0) { + dev_info(dev, "%s NO set speed_factor!", __func__); + fan_data->fan_factor = 2; + } + + rtk_fan_set_timer_target(fan_data, timer_target); + + /* For speed control */ + fan_data->pwm = pwm_get(dev, NULL); + rtk_fan_ctrl_speed(fan_data, MAX_CTRL_SPEED / 2); + + /* Start Fan */ + rtk_fan_enable(fan_data); + + return 0; +} + +static int rtk_fan_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct device_node *node = NULL; + struct rtk_fan_data *fan_data; + int irq, ret; + + dev_info(dev, "%s Enter ..", __func__); + node = pdev->dev.of_node; + if (!node) { + dev_err(dev, "%s Fail to get device tree node", __func__); + return -ENODEV; + } + + fan_data = devm_kzalloc(&pdev->dev, sizeof(*fan_data), GFP_KERNEL); + if (!fan_data) { + dev_err(dev, "%s No memory!", __func__); + return -ENOMEM; + } + + fan_data->dev = dev; + + fan_data->reg_base = of_iomap(node, 0); + + //irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "%s No IRQ. Check %s setup!\n", + __func__, dev_name(&pdev->dev)); + ret = -ENODEV; + goto err1; + } + + ret = request_irq(irq, rtk_fan_irq, + IRQF_SHARED, "rtk_fan_irq", fan_data); + + if (ret < 0) { + dev_err(dev, "%s Fail to request_irq (ret=%d)", __func__, ret); + goto err1; + } + + ret = rtk_fan_init(fan_data, pdev); + if (ret < 0) { + dev_err(dev, "%s Fail to init rtk_fan (ret=%d)", __func__, ret); + goto err1; + } + + ret = rtk_fan_create_sysfs(fan_data); + if (ret < 0) { + dev_err(dev, "%s Fail to create sysfs (ret=%d)", __func__, ret); + goto err1; + } + + platform_set_drvdata(pdev, fan_data); + + dev_info(dev, "%s Exit", __func__); + return 0; + +err1: + kfree(fan_data); + dev_err(dev, "%s Probe Fail (ret=%d)", __func__, ret); + return ret; +} + +static int rtk_fan_remove(struct platform_device *pdev) { + struct rtk_fan_data *fan_data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + if (fan_data) + kfree(fan_data); + + return 0; +} + +static const struct of_device_id rtk_fan_of_match[] = { + {.compatible = "realtek,rtk-fan",}, + { /* Sentinel */ }, +}; + +static struct platform_driver rtk_fan_driver = { + .probe = rtk_fan_probe, + .remove = rtk_fan_remove, + .driver = { + .name = "rtk-fan", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtk_fan_of_match), + }, +}; + +static int __init rtk_fan_probe_init(void) +{ + return platform_driver_probe(&rtk_fan_driver, rtk_fan_probe); +} + +late_initcall(rtk_fan_probe_init); + diff --git a/drivers/soc/realtek/common/rtk_fss_scan.c b/drivers/soc/realtek/common/rtk_fss_scan.c new file mode 100644 index 000000000000..ac8dffd905e0 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_fss_scan.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Realtek FSS Scan Driver + * + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SC_WRAP_DVFS_FSS_CTRL0 0x00 +#define SC_WRAP_DVFS_FSS_CTRL1 0x04 +#define SC_WRAP_DVFS_FSS_ST0 0x14 +#define SC_WRAP_DVFS_FSS_ST2 0x1c +#define SC_WRAP_DVFS_FSS_ST3 0x20 + +#define SC_WRAP_DVFS_FSS_ST0_CAL_DONE_MASK 0x1f000000 + +struct fss_fv_desc { + int freq; + int volt_init; + int volt_min; + int volt_max; + int scan_num; +}; + +struct fss_device { + struct device *dev; + void *base; + + struct clk *clk; + struct regulator *supply; + int num_volts; + int *volts; + const struct fss_fv_desc *descs; + int num_descs; + const int *targets; + int num_targets; + + unsigned long saved_freq; + int saved_volt; + int *results; + struct work_struct work; + +}; + +static int fss_set_freq_volt(struct fss_device *fdev, int freq, int volt) +{ + long old_freq = clk_get_rate(fdev->clk); + + /* always set the voltage */ + if (freq >= old_freq) + regulator_set_voltage(fdev->supply, volt, volt); + + clk_set_rate(fdev->clk, freq); + + if (freq < old_freq) + regulator_set_voltage(fdev->supply, volt, volt); + return 0; +} + +static int fss_reg_read(struct fss_device *fdev, unsigned int ofsset, + unsigned int *val) +{ + *val = readl(fdev->base + ofsset); + return 0; +} + +static int fss_reg_write(struct fss_device *fdev, unsigned int ofsset, + unsigned int val) +{ + writel(val, fdev->base + ofsset); + return 0; +} + +static inline int fss_check_cal_done(unsigned int val) +{ + const unsigned int mask = SC_WRAP_DVFS_FSS_ST0_CAL_DONE_MASK; + + return (val & mask) == mask; +} + +static int fss_wait_cal_done(struct fss_device *fdev) +{ + unsigned int cal_done; + + return readl_poll_timeout_atomic(fdev->base + SC_WRAP_DVFS_FSS_ST0, + cal_done, fss_check_cal_done(cal_done), 0, 1); +} + +static int fss_get_cal_min_cdl1(struct fss_device *fdev, + unsigned int *cal_min_cdl1) +{ + int ret; + + fss_reg_write(fdev, SC_WRAP_DVFS_FSS_CTRL0, 0x1F000000); + fss_reg_write(fdev, SC_WRAP_DVFS_FSS_CTRL1, 0x00077777); + fss_reg_write(fdev, SC_WRAP_DVFS_FSS_CTRL0, 0x1F1F0000); + + ret = fss_wait_cal_done(fdev); + if (ret) + return ret; + + mdelay(10); + fss_reg_read(fdev, SC_WRAP_DVFS_FSS_ST3, cal_min_cdl1); + fss_reg_write(fdev, SC_WRAP_DVFS_FSS_CTRL0, 0x00000000); + + return 0; +} + +static int min_cdl_compare(unsigned int min_cdl, unsigned int target) +{ + while (target != 0) { + + if ((min_cdl & 0xf) < (target & 0xf)) + return 0; + + min_cdl >>= 4; + target >>= 4; + } + return 1; +} + +static int fss_scan_check_voltage(struct fss_device *fdev, + int volt, int target) +{ + int cal_min_cdl1; + int ret; + + dev_info(fdev->dev, "set volt to %d\n", volt); + ret = regulator_set_voltage(fdev->supply, volt, volt); + if (ret) { + dev_err(fdev->dev, "faied to set voltage: %d\n", ret); + return 0; + } + + /* must wait more time, when lowering voltage */ + msleep(20); + + ret = fss_get_cal_min_cdl1(fdev, &cal_min_cdl1); + if (ret) { + dev_err(fdev->dev, "faied to get cal_min_cdl1: %d\n", ret); + return 0; + } + + dev_info(fdev->dev, "cal_min_cdl1 is %08x\n", cal_min_cdl1); + return min_cdl_compare(cal_min_cdl1, target); +} + +static int fss_voltage_to_idx(struct fss_device *fdev, int volt) +{ + int i; + int closest = 0; + int min = volt; + int v; + + if (volt >= fdev->volts[fdev->num_volts - 1]) + return fdev->num_volts - 1; + + if (volt <= fdev->volts[0]) + return 0; + + for (i = 0; i < fdev->num_volts; i++) { + if (fdev->volts[i] == volt) + return i; + + v = fdev->volts[i] > volt ? fdev->volts[i] - volt : volt - fdev->volts[i]; + if (v < min) { + closest = i; + min = v; + } + } + return closest; +} + +static int fss_scan(struct fss_device *fdev, int volt, int min, int max, + unsigned int target) +{ + int i; + int voidx, vobound; + + if (!volt) + return 0; + + voidx = fss_voltage_to_idx(fdev, volt); + + if (fss_scan_check_voltage(fdev, volt, target)) { + vobound = fss_voltage_to_idx(fdev, min); + + for (i = voidx - 1; i >= vobound; i--) { + if (!fss_scan_check_voltage(fdev, fdev->volts[i], target)) + break; + volt = fdev->volts[i]; + } + return volt; + } + + vobound = fss_voltage_to_idx(fdev, max); + + for (i = voidx + 1; i <= vobound; i++) + if (fss_scan_check_voltage(fdev, fdev->volts[i], target)) + return fdev->volts[i]; + return 0; +} + +static +int fss_scan_desc(struct fss_device *fdev, const struct fss_fv_desc *desc) +{ + int i; + int init, min, max, ret; + + fss_set_freq_volt(fdev, desc->freq, desc->volt_init); + msleep(200); + dev_info(fdev->dev, "scan for frequency: %d MHz\n", + (int)desc->freq / 1000000); + + init = desc->volt_init; + min = desc->volt_min; + max = desc->volt_max; + + for (i = 0; i < fdev->num_targets; i++) { + + ret = fss_scan(fdev, init , min, max, fdev->targets[i]); + + dev_info(fdev->dev, "fss_scan freq=%d, target=%08x: input=(%d, %d, %d), output=%d\n", + desc->freq, fdev->targets[i], init, min, max, ret); + if (!ret) + return 0; + init = min = ret; + } + + return ret; +} + +static void fss_save_state(struct fss_device *fdev) +{ + fdev->saved_volt = regulator_get_voltage(fdev->supply); + fdev->saved_freq = clk_get_rate(fdev->clk); +} + +static void fss_restore_state(struct fss_device *fdev) +{ + fss_set_freq_volt(fdev, fdev->saved_freq, fdev->saved_volt); +} + +static void fss_scan_work(struct work_struct *work) +{ + struct fss_device *fdev = container_of(work, struct fss_device, work); + int i, j; + + fdev->supply = regulator_get(fdev->dev, "cpu"); + if (IS_ERR(fdev->supply)) { + dev_err(fdev->dev, "failed to get regulator: %ld\n", + PTR_ERR(fdev->supply)); + return; + } + + fss_save_state(fdev); + + for (i = 0; i < fdev->num_descs; i++) { + int best = 0; + int res; + const struct fss_fv_desc *d = &fdev->descs[i]; + + for (j = 0; j < d->scan_num; j++) { + res = fss_scan_desc(fdev, d); + if (res == 0) + continue; + if (best == 0 || best > res) + best = res; + } + fdev->results[i] = best; + } + + fss_restore_state(fdev); + + regulator_put(fdev->supply); +} + +static void fss_scan_wait(struct fss_device *fdev) +{ + flush_work(&fdev->work); +} + +static int fss_scan_start(struct fss_device *fdev) +{ + if (!queue_work_on(0, system_highpri_wq, &fdev->work)) + return -EBUSY; + return 0; +} + +static ssize_t control_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fss_device *fdev = dev_get_drvdata(dev); + int ret = 0; + + if (!strncmp("start", buf, 5)) + ret = fss_scan_start(fdev); + else if (!strncmp("wait", buf, 4)) + fss_scan_wait(fdev); + + return ret ?: count; +} +DEVICE_ATTR_WO(control); + +static +ssize_t frequencies_mhz_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int len = 0; + int i; + struct fss_device *fdev = dev_get_drvdata(dev); + const struct fss_fv_desc *d = fdev->descs; + + len += snprintf(buf + len, PAGE_SIZE - len, "%d", (int)d[0].freq / 1000000); + for (i = 1; i < fdev->num_descs; i++) + len += snprintf(buf + len, PAGE_SIZE - len, " %d", (int)d[i].freq / 1000000); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} +DEVICE_ATTR_RO(frequencies_mhz); + +static ssize_t voltages_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fss_device *fdev = dev_get_drvdata(dev); + int len = 0; + int i; + + len += snprintf(buf + len, PAGE_SIZE - len, "%d", fdev->results[0]); + for (i = 1; i < fdev->num_descs; i++) + len += snprintf(buf + len, PAGE_SIZE - len, " %d", + fdev->results[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} +DEVICE_ATTR_RO(voltages); + +static ssize_t targets_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fss_device *fdev = dev_get_drvdata(dev); + int len = 0; + int i; + + len += snprintf(buf + len, PAGE_SIZE - len, "%08x", fdev->targets[0]); + for (i = 1; i < fdev->num_targets; i++) + len += snprintf(buf + len, PAGE_SIZE - len, " %08x", + fdev->targets[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} +DEVICE_ATTR_RO(targets); + +static ssize_t configs_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fss_device *fdev = dev_get_drvdata(dev); + int len = 0; + int i; + + len += snprintf(buf + len, PAGE_SIZE - len, "%-4s %9s %9s %9s %s\n", "freq", "volt-init", "volt-min", "volt-max", "scan-num"); + for (i = 0; i < fdev->num_descs; i++) { + const struct fss_fv_desc *d = &fdev->descs[i]; + + len += snprintf(buf + len, PAGE_SIZE - len, "%4dMHz %7dmV %7dmV %7dmV %8d\n", + (int)d->freq / 1000000, d->volt_init / 1000, d->volt_min / 1000, d->volt_max / 1000, d->scan_num); + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} +DEVICE_ATTR_RO(configs); + +static struct attribute *fss_attrs[] = { + &dev_attr_control.attr, + &dev_attr_voltages.attr, + &dev_attr_frequencies_mhz.attr, + &dev_attr_targets.attr, + &dev_attr_configs.attr, + NULL +}; + +static struct attribute_group fss_attr_group = { + .name = "fss", + .attrs = fss_attrs, +}; + +static int volt_cmp(const void *a, const void *b) +{ + int va = *(int *)a; + int vb = *(int *)b; + + return va - vb; +} + +static void volt_swap(void *a, void *b, int size) +{ + int *pa = a; + int *pb = b; + int t; + + t = *pa; + *pa = *pb; + *pb = t; +} + +static int fss_get_voltage_table(struct fss_device *fdev) +{ + int i; + + fdev->num_volts = regulator_count_voltages(fdev->supply); + fdev->volts = devm_kcalloc(fdev->dev, fdev->num_volts, + sizeof(*fdev->volts), GFP_KERNEL); + if (!fdev->volts) + return -ENOMEM; + + for (i = 0; i < fdev->num_volts; i++) + fdev->volts[i] = regulator_list_voltage(fdev->supply, i); + + sort(fdev->volts, fdev->num_volts, sizeof(*fdev->volts), volt_cmp, + volt_swap); + + return 0; +} + +static int of_parse_config(struct fss_device *fdev, struct device_node *np) +{ + int num_targets; + unsigned int *targets; + int num_childs, num_descs = 0; + struct device_node *child; + struct fss_fv_desc *descs; + int ret; + + num_targets = of_property_count_elems_of_size(np, "fss,targets", sizeof(*targets)); + if (num_targets <= 0) + return -EINVAL; + + targets = devm_kcalloc(fdev->dev, num_targets, sizeof(*targets), GFP_KERNEL); + if (!targets) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "fss,targets", targets, num_targets); + if (ret) + goto free_targets; + + num_childs = of_get_child_count(np); + if (num_childs <= 0) { + ret = -EINVAL; + goto free_targets; + } + + descs = devm_kcalloc(fdev->dev, num_childs, sizeof(*descs), GFP_KERNEL); + if (!descs) { + ret = -ENOMEM; + goto free_targets; + } + + for_each_child_of_node(np, child) { + struct fss_fv_desc *d = &descs[num_descs]; + u32 f, v[3], s; + + if (of_property_read_u32_array(child, "fss,voltage", v, 3)) + continue; + + if (of_property_read_u32(child, "fss,frequency", &f)) + continue; + + if (of_property_read_u32(child, "fss,scan-num", &s)) + s = 3; + + d->freq = f; + d->volt_init = v[0]; + d->volt_min = v[1]; + d->volt_max = v[2]; + d->scan_num = s; + num_descs += 1; + } + + fdev->descs = descs; + fdev->num_descs = num_descs; + fdev->targets = targets; + fdev->num_targets = num_targets; + return 0; + +free_targets: + devm_kfree(fdev->dev, targets); + return ret; +} + +static const unsigned int rtd1319_targets[] = { 0xbbbbb, 0xccccc }; +static const struct fss_fv_desc rtd1319_desc[] = { + { 1200000000, 1000000, 800000, 1087500, 3, }, + { 1300000000, 1000000, 850000, 1100000, 3, }, + { 1400000000, 1050000, 900000, 1150000, 3, }, +}; + +static void use_default_config(struct fss_device *fdev) +{ + fdev->descs = rtd1319_desc; + fdev->num_descs = ARRAY_SIZE(rtd1319_desc); + fdev->targets = rtd1319_targets; + fdev->num_targets = ARRAY_SIZE(rtd1319_targets); +} + +static int fss_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct resource res; + struct fss_device *fdev; + int ret; + + fdev = devm_kzalloc(dev, sizeof(*fdev), GFP_KERNEL); + if (!fdev) + return -ENOMEM; + fdev->dev = dev; + + if (of_parse_config(fdev, np)) { + dev_info(dev, "failed to get config from dt, use default\n"); + use_default_config(fdev); + } + + fdev->results = devm_kcalloc(dev, fdev->num_descs, + sizeof(*fdev->results), GFP_KERNEL); + if (!fdev->results) + return -ENOMEM; + + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + fdev->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!fdev->base) + return -ENOMEM; + + fdev->clk = devm_clk_get(dev, NULL); + if (IS_ERR(fdev->clk)) { + ret = PTR_ERR(fdev->clk); + if (ret == -EPROBE_DEFER) + dev_dbg(dev, "clk is not ready, retry\n"); + else + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + fdev->supply = devm_regulator_get(dev, "cpu"); + if (IS_ERR(fdev->supply)) { + ret = PTR_ERR(fdev->supply); + if (ret == -EPROBE_DEFER) + dev_dbg(dev, "regulator is not ready, retry\n"); + else + dev_err(dev, "failed to get regulator: %d\n", ret); + return ret; + } + + ret = fss_get_voltage_table(fdev); + if (ret) { + dev_err(dev, "failed to get voltage table: %d\n", ret); + return ret; + } + devm_regulator_put(fdev->supply); + + platform_set_drvdata(pdev, fdev); + INIT_WORK(&fdev->work, fss_scan_work); + + ret = sysfs_create_group(&dev->kobj, &fss_attr_group); + if (ret) { + dev_err(dev, "failed to create sysfs group: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id fss_ids[] = { + { .compatible = "realtek,fss-scan" }, + {} +}; + +static struct platform_driver fss_drv = { + .driver = { + .name = "rtk-fss-scan", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(fss_ids), + }, + .probe = fss_probe, +}; +module_platform_driver(fss_drv); + +MODULE_DESCRIPTION("Realtek FSS Scan driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rtk-fss-scan"); + diff --git a/drivers/soc/realtek/common/rtk_fw_pm.c b/drivers/soc/realtek/common/rtk_fw_pm.c new file mode 100644 index 000000000000..8d824cb3aba7 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_fw_pm.c @@ -0,0 +1,256 @@ + +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek DHC SoC family FW power management driver + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum cpu_id { + SCPU = 0x1, + ACPU, + VCPU, +}; + +#define RPC_AUDIO_SET_NOTIFY (__cpu_to_be32(BIT(8))) +#define RPC_VIDEO_SET_NOTIFY (__cpu_to_be32(BIT(2))) + +#define RPC_HAS_BIT(addr, bit) (readl(addr) & bit) +#define RPC_SET_BIT(addr, bit) (writel((readl(addr)|bit), addr)) +#define RPC_RESET_BIT(addr, bit) (writel((readl(addr)&~bit), addr)) + +static void rtk_writel_swc(u32 val, u32 addr) +{ + struct arm_smccc_res res; + + arm_smccc_smc(0x8400ffff, addr, val, 0, 0, 0, 0, 0, &res); +} + +static void rpc_set_flag(int type, uint32_t flag) +{ + struct rtk_ipc_shm __iomem *ipc = (void __iomem *)IPC_SHM_VIRT; + + if (type == ACPU) + writel(__cpu_to_be32(flag), &(ipc->audio_rpc_flag)); + else if (type == VCPU) + writel(__cpu_to_be32(flag), &(ipc->video_rpc_flag)); + +} + +static uint32_t rpc_get_flag(int type) +{ + struct rtk_ipc_shm __iomem *ipc = (void __iomem *)IPC_SHM_VIRT; + + if (type == ACPU) + return __be32_to_cpu(readl(&(ipc->audio_rpc_flag))); + else if (type == VCPU) + return __be32_to_cpu(readl(&(ipc->video_rpc_flag))); + + return 0xdeaddead; +} + +unsigned int rtk_fw_pm_cpu_on(uint32_t cpu) +{ + unsigned int ret = 0; + + if (cpu == ACPU) { + rtk_writel_swc(0xacd1, 0x9801a360); /* ACPU */ + rtk_writel_swc(0x30, 0x98000014); /* ACPU reset 1 */ + rtk_writel_swc(0xc0, 0x98000058); /* ACPU enable clock */ + } else { + rtk_writel_swc(0xacd1, 0x9801b7f0); /* VCPU */ + rtk_writel_swc(0x1, 0x98000464); /* VCPU reset 1 */ + rtk_writel_swc(0xc00000, 0x98000050); /* VCPU enable clock */ + } + + return ret; +} +EXPORT_SYMBOL(rtk_fw_pm_cpu_on); + +int rtk_fw_pm_cpu_off(uint32_t cpu) +{ + unsigned int i = 0; + unsigned int ret = 0; + + struct rtk_ipc_shm __iomem *ipc = (void __iomem *)IPC_SHM_VIRT; + + for (i = 0 ; i < 1000; i++) { + + if (cpu == ACPU) + ret = readl(&(ipc->audio_rpc_flag)); + else + ret = readl(&(ipc->video_rpc_flag)); + + if (ret == 0) { + ret = 1; + break; + } + + mdelay(1); + ret = -ENOTTY; + } + + if (ret == -ENOTTY) + goto err; + + if (cpu == ACPU) { + rtk_writel_swc(0x80, 0x98000058); /* ACPU disable clock */ + rtk_writel_swc(0x20, 0x98000014); /* ACPU reset 0 */ + } else { + rtk_writel_swc(0x800000, 0x98000050); /* VCPU disable clock */ + rtk_writel_swc(0x0, 0x98000464); /* VCPU reset 0 */ + } + +err: + return ret; +} +EXPORT_SYMBOL(rtk_fw_pm_cpu_off); + +void rtk_fw_rpc_suspend(int cpu) +{ + int max_count = 500; + + if (cpu == ACPU) { + rpc_set_flag(ACPU, 0xdaedffff); /* stop audio has_check */ + while ((rpc_get_flag(ACPU) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + /* disable interrupt */ + RPC_RESET_BIT(rpc_acpu_int_flag, RPC_AUDIO_SET_NOTIFY); + + /* sync rpc memory */ + wmb(); + + /* wait audio rpc suspend ready */ + rpc_set_flag(ACPU, 0xdeadffff); + while ((rpc_get_flag(ACPU) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + } else { + rpc_set_flag(VCPU, 0xdaedffff); /* stop video has_check */ + while ((rpc_get_flag(VCPU) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + + /* disable interrupt */ + RPC_RESET_BIT(rpc_vcpu_int_flag, RPC_VIDEO_SET_NOTIFY); + + /* sync rpc memory */ + wmb(); + + /* wait video rpc suspend ready */ + rpc_set_flag(VCPU, 0xdeadffff); + while ((rpc_get_flag(VCPU) != 0x0) && (max_count > 0)) { + mdelay(1); + max_count--; + } + } +} +EXPORT_SYMBOL(rtk_fw_rpc_suspend); + +void rtk_fw_rpc_resume(int cpu) +{ + if (cpu == ACPU) { + RPC_SET_BIT(rpc_acpu_int_flag, RPC_AUDIO_SET_NOTIFY); + rpc_set_flag(ACPU, 0xffffffff); + } else { + RPC_SET_BIT(rpc_vcpu_int_flag, RPC_VIDEO_SET_NOTIFY); + rpc_set_flag(VCPU, 0xffffffff); + } +} +EXPORT_SYMBOL(rtk_fw_rpc_resume); + +static int rtk_fw_pm_suspend(struct device *dev) +{ + int ret = 0; + + dev_info(dev, "%s\n", __func__); + + rtk_fw_rpc_suspend(ACPU); + rtk_fw_rpc_suspend(VCPU); + + if (!rtk_fw_pm_cpu_off(ACPU)) { + dev_err(dev, "ACPU FW not ready to stop\n"); + ret = -EINVAL; + goto err; + } + + if (!rtk_fw_pm_cpu_off(VCPU)) { + dev_err(dev, "VCPU FW not ready to stop\n"); + ret = -EINVAL; + goto err; + } + +err: + return ret; +} + +static int rtk_fw_pm_resume(struct device *dev) +{ + int ret = 0; + + dev_info(dev, "%s\n", __func__); + + rtk_fw_pm_cpu_on(ACPU); + rtk_fw_pm_cpu_on(VCPU); + rtk_fw_rpc_resume(ACPU); + rtk_fw_rpc_resume(VCPU); + + return ret; +} + +static int rtk_fw_pm_probe(struct platform_device *pdev) +{ + int ret = 0; + + dev_info(&pdev->dev, "%s\n", __func__); + + return ret; +} + +static const struct dev_pm_ops rtk_fw_pm_ops = { + .suspend = rtk_fw_pm_suspend, + .resume = rtk_fw_pm_resume, +}; + +static const struct of_device_id rtk_fw_pm_ids[] = { + { .compatible = "realtek,fw_pm" }, + {} +}; + +static struct platform_driver rtk_fw_pm = { + .driver = { + .name = "realtek-fw-pm", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtk_fw_pm_ids), + .pm = &rtk_fw_pm_ops, + }, + .probe = rtk_fw_pm_probe, +}; +module_platform_driver(rtk_fw_pm); + +MODULE_AUTHOR("James Tai "); +MODULE_DESCRIPTION("Realtek FW power management driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/realtek/common/rtk_gpio_default.c b/drivers/soc/realtek/common/rtk_gpio_default.c new file mode 100644 index 000000000000..2e0a25361bc4 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_gpio_default.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Realtek DHC gpio default init driver + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include + + + +struct rtd_gpio_default_state { + struct gpio_descs *gpio; + int *values; +}; + + + +static int rtd_gpio_default_probe(struct platform_device *pdev) +{ + struct gpio_descs *rtd_gpios; + int num = 0; + int value = 0; + int i; + int ret = 0; + + rtd_gpios = gpiod_get_array(&pdev->dev, NULL, GPIOD_ASIS); + if (IS_ERR(rtd_gpios)) { + dev_err(&pdev->dev, "No default gpios need to be set\n"); + return 0; + } else + dev_err(&pdev->dev, "set %d gpios to default value\n", rtd_gpios->ndescs); + + + num = of_property_count_u32_elems(pdev->dev.of_node, "gpio-default"); + if (num < 0 || num != rtd_gpios-> ndescs) { + dev_err(&pdev->dev, "number of gpio-default is not match to number of gpios\n"); + goto out; + } + for (i = 0; i < num; i++) { + of_property_read_u32_index(pdev->dev.of_node, "gpio-default", i, &value); + switch (value) { + case 0: + ret = gpiod_direction_output(rtd_gpios->desc[i], 0); + if (ret) + dev_err(&pdev->dev, "cannot set gpio %d", desc_to_gpio(rtd_gpios->desc[i])); + break; + case 1: + ret = gpiod_direction_output(rtd_gpios->desc[i], 1); + if (ret) + dev_err(&pdev->dev, "cannot set gpio %d", desc_to_gpio(rtd_gpios->desc[i])); + break; + case 2: + ret = gpiod_direction_input(rtd_gpios->desc[i]); + if (ret) + dev_err(&pdev->dev, "cannot set gpio %d", desc_to_gpio(rtd_gpios->desc[i])); + break; + default: + dev_err(&pdev->dev, "default value is not support for gpio %d", desc_to_gpio(rtd_gpios->desc[i])); + + } + } + +out: + gpiod_put_array(rtd_gpios); + + return 0; +} + +static const struct of_device_id rtd_gpio_default_of_matches[] = { + { .compatible = "realtek,gpio-set-default",} +}; + + +static struct platform_driver rtd_gpio_default_driver = { + .driver = { + .name = "gpio-rtd-default", + .of_match_table = rtd_gpio_default_of_matches, + }, + .probe = rtd_gpio_default_probe, +}; + + +static int rtd_gpio_default(void) +{ + return platform_driver_register(&rtd_gpio_default_driver); +} + +postcore_initcall(rtd_gpio_default); + diff --git a/drivers/soc/realtek/common/rtk_iso_wa.c b/drivers/soc/realtek/common/rtk_iso_wa.c new file mode 100644 index 000000000000..eca733495f44 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_iso_wa.c @@ -0,0 +1,148 @@ +#define pr_fmt(fmt) "iso_wa: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regmap *regmap; +static int completed; + +static int set_gpu_on(void) +{ + struct device_node *np; + struct platform_device *pdev; + int ret = 0; + + np = of_find_compatible_node(NULL, NULL, "arm,mali-midgard"); + if (!np) + return -ENODEV; + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) + return -ENODEV; + + if (!device_is_bound(&pdev->dev)) + return -EINVAL; + + get_device(&pdev->dev); + if (pm_runtime_enabled(&pdev->dev)) { + pr_emerg("force gpu on\n"); + pm_runtime_get_sync(&pdev->dev); + } else + ret = -EINVAL; + put_device(&pdev->dev); + return ret; +} + +static int set_gpu_sram_on(void) +{ + if (completed) + return 0; + + if (!regmap) { + pr_emerg("no regmap\n"); + return -EINVAL; + } + + pr_emerg("force gpu sram on\n"); + + regmap_update_bits(regmap, 0xfd0, BIT(3), BIT(3)); + regmap_write(regmap, 0xb70, 0xf00); + completed = 1; + + return 0; +} + +static int reboot_cb(struct notifier_block *nb, unsigned long act, void *cmd) +{ + int ret; + + ret = set_gpu_on(); + if (ret) + ret = set_gpu_sram_on(); + if (ret) + return NOTIFY_DONE; + return NOTIFY_OK; +} + +static struct notifier_block reboot_nb = { + .notifier_call = reboot_cb, +}; + +static int panic_cb(struct notifier_block *nb, unsigned long act, void *cmd) +{ + int ret; + + ret = set_gpu_sram_on(); + return ret ? NOTIFY_DONE : NOTIFY_OK; +} + +static struct notifier_block panic_nb = { + .notifier_call = panic_cb, + .priority = 255, +}; + +static int regmap_get(void) +{ + struct device_node *np; + + np = of_find_node_by_path("/soc@0/rbus@98000000/syscon@7000"); + if (WARN_ON(!np)) + return -EINVAL; + + regmap = syscon_node_to_regmap(np); + of_node_put(np); + if (WARN_ON(IS_ERR_OR_NULL(regmap))) { + regmap = NULL; + return -EINVAL; + } + return 0; +} + +static int resource_init(void) +{ + int ret; + + ret = regmap_get(); + if (ret) + return ret; + + ret = register_reboot_notifier(&reboot_nb); + if (ret) + return ret; + + ret = atomic_notifier_chain_register(&panic_notifier_list, &panic_nb); + if (ret) + unregister_reboot_notifier(&reboot_nb); + return ret; +} + +static int match_platform(void) +{ + struct soc_device_attribute stark_a00[] = { + { .family = "Realtek Stark", .revision = "A00" }, + { /* sentinel */ } + }; + return soc_device_match(stark_a00) != NULL; +} + +static int __init iso_wa_init(void) +{ + if (match_platform()) + return resource_init(); + return -EINVAL; +} +module_init(iso_wa_init); + +static void __exit iso_wa_exit(void) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, &panic_nb); + unregister_reboot_notifier(&reboot_nb); +} +module_exit(iso_wa_exit); diff --git a/drivers/soc/realtek/common/rtk_mcp.c b/drivers/soc/realtek/common/rtk_mcp.c new file mode 100644 index 000000000000..8b6cb778db5f --- /dev/null +++ b/drivers/soc/realtek/common/rtk_mcp.c @@ -0,0 +1,1088 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * rtk_mcp.c - MCP driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtk_mcp.h" + +#define MCP_DEVICE_NAME "mcp" + +static void __iomem *RTK_MCP_BASE; +static void __iomem *RTK_TP_BASE; + +static struct platform_device* local_pdev; +static struct device* mcp_device; +static struct cdev mcp_dev; +static dev_t devno; +struct class * mcp_dev_class = NULL; + +static DEFINE_SPINLOCK(mcp_buffer_lock); +static DEFINE_MUTEX(mcp_mutex); + +#define _mcp_map_single(p_data, len, dir) dma_map_single(mcp_device, (void*) p_data, (size_t) len, dir) +#define _mcp_unmap_single(p_data, len, dir) dma_unmap_single(mcp_device, (dma_addr_t) p_data, (size_t) len, dir) +//#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); +//#define nop() __asm__ __volatile__("nop"); + +void mcp_dump_all_regieters(void); +void mcp_dump_descriptor(mcp_desc *p_desc); +void mcp_dump_mem(unsigned char* data, unsigned int len); +void MCP_AES_128_ECB_DataEncryptTest(void); + +int mcp_do_command( + mcp_desc* p_desc, + int n_desc +); + +int MCP_AES_Encryption( + unsigned char mode, + unsigned char key[16], + unsigned char iv[16], + unsigned char* p_in, + unsigned char* p_out, + unsigned long len +); + +/* + * writeSRAM + * Parameter : + * id : offset in cw + * data : data array to be written + * cnt : entry count for data writing in SRAM + * Return : + * true : successful + * false : false + */ +unsigned char writeSRAM(unsigned int id, unsigned int data[8], unsigned int cnt) +{ + int i=0, y=0; + +#if 0 + if ((id & 0x7f) > 0){ + printf("*** %s %s %d\n", __FILE__, __FUNCTION__, __LINE__ ); + return FALSE; + } + if (((id + cnt) & 0x7f) > 0){ + printf("*** %s %s %d\n", __FILE__, __FUNCTION__, __LINE__ ); + return FALSE; + } +#endif + + for (i = 0 ; i < cnt ; i++){ + //dbg_info("%s %s %d==>data: %x",__FILE__, __func__,__LINE__,data[y]); + SET_TP_KEYINFO_0(data[y++], RTK_TP_BASE); + //dbg_info("%s %s %d==>data: %x",__FILE__, __func__,__LINE__,data[y]); + SET_TP_KEYINFO_1(data[y++], RTK_TP_BASE); + SET_TP_KEY_CTRL((id+i) | 0x80, RTK_TP_BASE); // write 8 bytes + nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop();nop(); + } + + SET_TP_KEYINFO_0(0x0, RTK_TP_BASE); + SET_TP_KEYINFO_1(0x0, RTK_TP_BASE); + return 0; +} + +/* MISC */ +/*------------------------------------------------------------------ + * Func : mcp_malloc + * Desc : allocate memory + * Parm : size : size of data + * Retn : start address of data + *------------------------------------------------------------------*/ +void* mcp_malloc(unsigned long size) +{ +#ifdef USE_DVR_MALLOC + if (system_state == SYSTEM_BOOTING) + return (void*) kmalloc(size, GFP_KERNEL); + else + return (size >= PAGE_SIZE) ? (void*) dvr_malloc(size) : (void*) kmalloc(size, GFP_KERNEL); +#else + return (size >= PAGE_SIZE) ? (void*) __get_free_pages(GFP_KERNEL, get_order(size)) : (void*) kmalloc(size, GFP_KERNEL); +#endif +} + +/*------------------------------------------------------------------ + * Func : mcp_free + * Desc : release memory + * Parm : addr : Start address of data + * size : size of data + * Retn : N/A + *------------------------------------------------------------------*/ +void mcp_free(void* addr, unsigned long size) +{ + if (system_state == SYSTEM_BOOTING) { + kfree(addr) ; + return; + } + + if (size >= PAGE_SIZE) +#ifdef USE_DVR_MALLOC + dvr_free(addr); +#else + free_pages((unsigned long)addr, get_order(size)); +#endif + else + kfree(addr); +} + +/*************************************************************************** + File Operations +****************************************************************************/ + +/*------------------------------------------------------------------ + * Func : mcp_dev_open + * Desc : open function of mcp dev + * Parm : inode : inode of dev + * file : context of file + * Retn : 0 : success, others fail + *------------------------------------------------------------------*/ +static int mcp_dev_open(struct inode *inode, struct file *file) +{ + //mcp_warning("mcp_dev_open\n"); + + file->private_data = mcp_malloc(sizeof(mcp_desc) * MCP_DESC_ENTRY_COUNT); + if (file->private_data == NULL){ + mcp_warning("open mcp failed - allocate mcp descriptor buffer failed\n"); + return -ENOMEM; + } + + return 0; +} + +/*------------------------------------------------------------------ + * Func : mcp_dev_release + * Desc : release function of mcp dev + * Parm : inode : inode of dev + * file : context of file + * Retn : 0 : success, others fail + *------------------------------------------------------------------*/ +static int mcp_dev_release(struct inode* inode, struct file* file) +{ + if (file->private_data) + mcp_free(file->private_data, sizeof(mcp_desc) * MCP_DESC_ENTRY_COUNT); + return 0; +} + +#if 0 //Defined but not used +typedef struct { + compat_uint_t flags; + compat_uint_t key[6]; + compat_uint_t iv[4]; + compat_uint_t data_in; // data in : physical address + compat_uint_t data_out; // data out : physical address + compat_uint_t length; // data length +}compat_mcp_desc_t; + +static int compat_get_mcp_desc_data(compat_mcp_desc_t __user *data32, mcp_desc __user *data) +{ + //compat_uint_t s; + compat_uint_t c; + compat_uint_t b[6]; + compat_uint_t k[4]; + compat_uint_t t; + compat_uint_t p; + compat_uint_t q; + + int err; + + err = get_user(c, &data32->flags); + err |= put_user(c, &data->flags); + err |= copy_from_user(b, data32->key, sizeof(b)); + err |= copy_to_user(data->key, b, sizeof(b)); + err |= copy_from_user(k, data32->iv, sizeof(k)); + err |= copy_to_user(data->iv, k, sizeof(k)); + err |= get_user(t, &data32->data_in); + err |= put_user(t, &data->data_in); + err |= get_user(p, &data32->data_out); + err |= put_user(p, &data->data_out); + err |= get_user(q, &data32->length); + err |= put_user(q, &data->length); + + return err; +} + +static int compat_put_mcp_desc_data(compat_mcp_desc_t __user *data32, mcp_desc __user *data) +{ + //compat_uint_t s; + compat_uint_t c; + compat_uint_t b[6]; + compat_uint_t k[4]; + compat_uint_t t; + compat_uint_t p; + compat_uint_t q; + + int err; + + err = get_user(c, &data->flags); + err |= put_user(c, &data32->flags); + err |= copy_from_user(b, data->key, sizeof(b)); + err |= copy_to_user(data32->key, b, sizeof(b)); + err |= copy_from_user(k, data->iv, sizeof(k)); + err |= copy_to_user(data32->iv, k, sizeof(k)); + err |= get_user(t, &data->data_in); + err |= put_user(t, &data32->data_in); + err |= get_user(p, &data->data_out); + err |= put_user(p, &data32->data_out); + err |= get_user(q, &data->length); + err |= put_user(q, &data32->length); + + return err; +} +#endif + +/*------------------------------------------------------------------ + * Func : mcp_dev_ioctl + * Desc : ioctl function of mcp dev + * Parm : inode : inode of dev + * file : context o le + * cmd : control command + * arg : arguments + * Retn : 0 : success, others fail + *------------------------------------------------------------------*/ +static long compat_mcp_dev_ioctl(struct file* file, unsigned int cmd, unsigned long arg) +{ + mcp_desc_set desc_set; + //mcp_desc* desc_list = (mcp_desc*) KSEG1ADDR(file->private_data); + mcp_desc* desc_list = (mcp_desc*)(file->private_data); + mcp_desc* p_desc; + int n_desc; + +#if !defined(CONFIG_CPU_V7) + void __user *arg64; +#endif /* CONFIG_CPU_V7 */ + + int key_cnt = 0; + + //mcp_info("[MCP] =====>compat_mcp_dev_ioctl:\n"); + + switch (cmd){ + case MCP_IOCTL_DO_COMMAND: + +#if !defined(CONFIG_CPU_V7) + arg64 = compat_ptr(arg); + + if(copy_from_user(&desc_set, (void *)arg64, sizeof(mcp_desc_set))){ + mcp_warning("do ioctl command failed - copy desc_set from user failed 1\n"); + return -EFAULT; + } +#if defined(MY_DEF_HERE) + p_desc = compat_ptr((uintptr_t)desc_set.p_desc); +#else /* MY_DEF_HERE */ + p_desc = compat_ptr(desc_set.p_desc); +#endif /* MY_DEF_HERE */ +#else + if(copy_from_user(&desc_set, (void *)arg, sizeof(mcp_desc_set))){ + mcp_warning("do ioctl command failed - copy desc_set from user failed 1\n"); + return -EFAULT; + } + p_desc = desc_set.p_desc; +#endif /* CONFIG_CPU_V7 */ + + while(desc_set.n_desc){ + n_desc = (desc_set.n_desc >= MCP_DESC_ENTRY_COUNT) ? MCP_DESC_ENTRY_COUNT : desc_set.n_desc; + + if(copy_from_user(desc_list, (void *)p_desc, sizeof(mcp_desc) * n_desc)){ + mcp_warning("do ioctl command failed - copy desc from user failed 2\n"); + return -EFAULT; + } + + if(desc_list->flags & ((0x1) << 13)){ + mcp_info("%s %s %d==>flags s:%x\n", __FILE__, __func__, __LINE__, desc_list->flags); + + if(desc_list->flags & ((0x1) << 3)){ + mcp_info("%s %s %d==>AES 192 mode key in CW\n", __FILE__, __func__, __LINE__); + key_cnt=3; + }else{ + mcp_info("%s %s %d==>AES 256 mode key in CW\n", __FILE__, __func__, __LINE__); + key_cnt=4; + } + + // write key from cw offset 0x00 + if(writeSRAM(0, desc_list->key, key_cnt) == -1){ + mcp_warning("%s %s %d==>writeSRAM fail\n",__FILE__, __func__,__LINE__); + return -EFAULT; + } + desc_list->key[0]=0x0; + } + + if(mcp_do_command(desc_list, n_desc) < 0){ + mcp_warning("do command failed\n"); + return -EFAULT; + } + + p_desc += n_desc; + desc_set.n_desc -= n_desc; + } + break; + + /* for testing only */ + case MCP_IOCTL_TEST_AES_H: + //MCP_AES_H_DataHashTest(); + break; + + case MCP_IOCTL_ENABLE_AUTO_PADDING: + SET_MCP_CTRL1(GET_MCP_CTRL1(RTK_MCP_BASE) & ~(1 << 11), RTK_MCP_BASE); + break; + + case MCP_IOCTL_DISABLE_AUTO_PADDING: + SET_MCP_CTRL1(GET_MCP_CTRL1(RTK_MCP_BASE) | (1 << 11), RTK_MCP_BASE); + break; + + default: + mcp_warning("do ioctl command failed - unknown ioctl command(%d)\n", cmd); + return -EFAULT; + } + + return 0; +} + +/*------------------------------------------------------------------ + * Func : mcp_dev_ioctl + * Desc : ioctl function of mcp dev + * Parm : inode : inode of dev + * file : context of file + * cmd : control command + * arg : arguments + * Retn : 0 : success, others fail + *------------------------------------------------------------------*/ +static long mcp_dev_ioctl(struct file* file, unsigned int cmd, unsigned long arg) +{ + mcp_desc_set desc_set; + //mcp_desc* desc_list = (mcp_desc*) KSEG1ADDR(file->private_data); + mcp_desc* desc_list = (mcp_desc*)(file->private_data); + mcp_desc* p_desc; + int n_desc; + + int key_cnt = 0; + + //mcp_info("[MCP] =====>mcp_dev_ioctl:\n"); + + switch (cmd){ + case MCP_IOCTL_DO_COMMAND: + if(copy_from_user(&desc_set, (mcp_desc_set __user *)arg, sizeof(mcp_desc_set))){ + mcp_warning("do ioctl command failed - copy desc_set from user failed 1\n"); + return -EFAULT; + } + p_desc = desc_set.p_desc; + + while(desc_set.n_desc){ + n_desc = (desc_set.n_desc >= MCP_DESC_ENTRY_COUNT) ? MCP_DESC_ENTRY_COUNT : desc_set.n_desc; + + if (copy_from_user(desc_list, (mcp_desc __user *)p_desc, sizeof(mcp_desc) * n_desc)){ + mcp_warning("do ioctl command failed - copy desc from user failed 2\n"); + return -EFAULT; + } + + if(desc_list->flags & ((0x1) << 13)){ + mcp_info("%s %s %d==>flags s:%x\n", __FILE__, __func__, __LINE__, desc_list->flags); + + if(desc_list->flags & ((0x1) << 3)){ + mcp_info("%s %s %d==>AES 192 mode key in CW\n", __FILE__, __func__, __LINE__); + key_cnt=3; + } else { + mcp_info("%s %s %d==>AES 256 mode key in CW\n", __FILE__, __func__, __LINE__); + key_cnt=4; + } + + // write key from cw offset 0x00 + if (writeSRAM(0, desc_list->key, key_cnt) == -1){ + mcp_warning("%s %s %d==>writeSRAM fail\n",__FILE__, __func__,__LINE__); + return -EFAULT; + } + desc_list->key[0]=0x0; + } + + if (mcp_do_command(desc_list, n_desc) < 0){ + mcp_warning("do command failed\n"); + return -EFAULT; + } + p_desc += n_desc; + desc_set.n_desc -= n_desc; + } + break; + + /* for testing only */ + case MCP_IOCTL_TEST_AES_H: + //MCP_AES_H_DataHashTest(); + break; + + case MCP_IOCTL_ENABLE_AUTO_PADDING: + SET_MCP_CTRL1(GET_MCP_CTRL1(RTK_MCP_BASE) & ~(1 << 11), RTK_MCP_BASE); + break; + + case MCP_IOCTL_DISABLE_AUTO_PADDING: + SET_MCP_CTRL1(GET_MCP_CTRL1(RTK_MCP_BASE) | (1 << 11), RTK_MCP_BASE); + break; + + default: + mcp_warning("do ioctl command failed - unknown ioctl command(%d)\n", cmd); + return -EFAULT; + } + + return 0; +} + +static struct file_operations mcp_ops = +{ + .owner = THIS_MODULE, + //.ioctl = mcp_dev_ioctl, + .unlocked_ioctl = mcp_dev_ioctl, + .compat_ioctl = compat_mcp_dev_ioctl, + .open = mcp_dev_open, + .release = mcp_dev_release, +}; + +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ +/*------------------------------------------------------------------ + * Func : _mcp_load_otp + * Desc : load otp key + * Parm : N/A + * Retn : N/A + *------------------------------------------------------------------*/ +static void _mcp_load_otp(void) +{ + int i = 0; + + SET_MCP_OTP_LOAD(1, RTK_MCP_BASE); + + while(GET_MCP_OTP_LOAD(RTK_MCP_BASE)){ + if(i++ > 100){ + mcp_warning("Load OTP Key Timeout\n"); + } + + udelay(10); + } +} + +#endif /* MY_DEF_HERE */ +/*------------------------------------------------------------------ + * Func : _mcp_phy_init + * Desc : init mcp engine + * Parm : N/A + * Retn : N/A + *------------------------------------------------------------------*/ +static int _mcp_phy_init(void) +{ +#ifdef CONFIG_ARCH_RTD139x + unsigned int cur_value; +#endif + + + //_mcp_load_otp(); + SET_MCP_CTRL(MCP_GO, RTK_MCP_BASE); // dessert go bit + SET_MCP_EN(0xFE, RTK_MCP_BASE); // disable all interrupts + SET_MCP_STATUS(0xFE, RTK_MCP_BASE); // clear interrupts status + SET_MCP_BASE (0, RTK_MCP_BASE); + SET_MCP_LIMIT(0, RTK_MCP_BASE); + SET_MCP_RDPTR(0, RTK_MCP_BASE); + SET_MCP_WRPTR(0, RTK_MCP_BASE); + +#ifdef CONFIG_ARCH_RTD139x + /* auto power management */ + cur_value = GET_PWM_CTRL(RTK_MCP_BASE); + cur_value |= (1 << 22) | (1 << 23) | (1 << 24) | (1 << 25) | (1 << 27) | (1 << 28); + SET_PWM_CTRL(cur_value, RTK_MCP_BASE); +#endif + + return 0; +} + +/*------------------------------------------------------------------ + * Func : mcp_init + * Desc : init mcp engine + * Parm : N/A + * Retn : N/A + *------------------------------------------------------------------*/ +static int mcp_init(void) +{ + if (_mcp_phy_init()<0) + return -1; + +#if 0//def MCP_INTERRUPT_ENABLE + if (request_irq(MCP_IRQ, mcp_isr, SA_INTERRUPT | SA_SHIRQ, "MCP", &mcp_wait_queue) < 0){ + mcp_warning("Request irq %d failed\n", MCP_IRQ); + return -ENODEV; + } +#endif + + return 0; +} + +/*------------------------------------------------------------------ + * Func : mcp_uninit + * Desc : uninit mcp engine + * Parm : N/A + * Retn : N/A + *------------------------------------------------------------------*/ +static void mcp_uninit(void) +{ + SET_MCP_CTRL(MCP_GO, RTK_MCP_BASE); // dessert go bit + SET_MCP_EN(0xFE, RTK_MCP_BASE); // disable all interrupts + msleep(10); // wait for hw stop + SET_MCP_BASE (0, RTK_MCP_BASE); + SET_MCP_LIMIT(0, RTK_MCP_BASE); + SET_MCP_RDPTR(0, RTK_MCP_BASE); + SET_MCP_WRPTR(0, RTK_MCP_BASE); +#if 0 //def MCP_INTERRUPT_ENABLE + free_irq(MCP_IRQ, &mcp_wait_queue); +#endif +} + +/*---------------------------------------------------------------------- + * Func : mcp_dump_mem + * Desc : dump data in memory + * Parm : data : start address of data + * len : length of data + * Retn : N/A + *----------------------------------------------------------------------*/ +void mcp_dump_mem(unsigned char* data, unsigned int len) +{ + int i; + for (i = 0 ; i < len ; i++){ + if ((i & 0xF)==0) + printk("\n %04x | ", i); + printk("%02x ", data[i]); + } + printk("\n"); +} + +/*---------------------------------------------------------------------- + * Func : mcp_dump_all_registers + * Desc : dump mcp registers + * Parm : N/A + * Retn : N/A + *----------------------------------------------------------------------*/ +void mcp_dump_all_registers(void) +{ + mcp_info("****** MCP Registers ******\n"); + mcp_info("MCP_CTRL addr:0x%x, value:0x%x\n", MCP_CTRL, GET_MCP_CTRL(RTK_MCP_BASE)); + mcp_info("MCP_STATUS addr:0x%x, value:0x%x\n", MCP_STATUS, GET_MCP_STATUS(RTK_MCP_BASE)); + mcp_info("MCP_EN addr:0x%x, value:0x%x\n", MCP_EN, GET_MCP_EN(RTK_MCP_BASE)); + mcp_info("MCP_BASE addr:0x%p, value:0x%x\n", RTK_MCP_BASE, GET_MCP_BASE(RTK_MCP_BASE)); + mcp_info("MCP_LIMIT addr:0x%x, value:0x%x\n", MCP_LIMIT, GET_MCP_LIMIT(RTK_MCP_BASE)); + mcp_info("MCP_RDPTR addr:0x%x, value:0x%x\n", MCP_RDPTR, GET_MCP_RDPTR(RTK_MCP_BASE)); + mcp_info("MCP_WRPTR addr:0x%x, value:0x%x\n", MCP_WRPTR, GET_MCP_WRPTR(RTK_MCP_BASE)); + mcp_info("MCP_DES_COUNT addr:0x%x, value:0x%x\n", MCP_DES_COUNT, GET_MCP_DES_COUNT(RTK_MCP_BASE)); + mcp_info("MCP_DES_COMPARE addr:0x%x, value:0x%x\n", MCP_DES_COMPARE, GET_MCP_DES_COMPARE(RTK_MCP_BASE)); +} + +/*---------------------------------------------------------------------- + * Func : mcp_dump_descriptor + * Desc : dump mcp descriptor + * Parm : p_desc: pointer to descriptor + * Retn : N/A + *----------------------------------------------------------------------*/ +void mcp_dump_descriptor(mcp_desc *p_desc) +{ + int i = 0; + + mcp_info("****** MCP Descriptor ******\n"); + mcp_info("p_desc->flags:0x%0x\n", p_desc->flags); + + for(i = 0 ; i < sizeof(p_desc->key)/sizeof(p_desc->key[0]) ; i++){ + mcp_info("p_desc->key[%d]:0x%0x\n", i, p_desc->key[i]); + } + + for(i = 0 ; i < sizeof(p_desc->iv)/sizeof(p_desc->iv[0]) ; i++){ + mcp_info("p_desc->iv[%d]:0x%0x\n", i, p_desc->iv[i]); + } + + mcp_info("p_desc->data_in:0x%0x\n", p_desc->data_in); + mcp_info("p_desc->data_out:0x%0x\n", p_desc->data_out); + mcp_info("p_desc->length:0x%0x\n", p_desc->length); +} + +/*------------------------------------------------------------------ + * Func : _mcp_set_desc_buffer + * Desc : set descriptors buffer + * Parm : base : base address of descriptor buffer + * limit : limit address of descriptor buffer + * rp : read pointer of descriptor buffer + * wp : write pointer of descriptor buffer + * Retn : 0 + *------------------------------------------------------------------*/ +int _mcp_set_desc_buffer(unsigned long base, unsigned long limit, unsigned long rp, unsigned long wp) +{ + unsigned long event; + + spin_lock_irqsave(&mcp_buffer_lock, event); + SET_MCP_BASE (base, RTK_MCP_BASE); + SET_MCP_LIMIT(limit, RTK_MCP_BASE); + SET_MCP_RDPTR(rp, RTK_MCP_BASE); + SET_MCP_WRPTR(wp, RTK_MCP_BASE); + spin_unlock_irqrestore(&mcp_buffer_lock, event); + + return 0; +} + +/*------------------------------------------------------------------ + * Func : _mcp_start_xfer + * Desc : Start Xfer + * Parm : N/A + * Retn : S_OK / S_FALSE + *------------------------------------------------------------------*/ +int _mcp_start_xfer(void) +{ + int ret = -1; + int WaitTime = 0x3FF << 2; + int wiat_clear_timeout = 0; + + SET_MCP_DES_COUNT(0x0, RTK_MCP_BASE); // descriptor in ddr + SET_MCP_CTRL(MCP_CLEAR | MCP_WRITE_DATA, RTK_MCP_BASE); // issue clear + + while ((GET_MCP_CTRL(RTK_MCP_BASE) & MCP_CLEAR) && wiat_clear_timeout++ < 30); + + if (GET_MCP_CTRL(RTK_MCP_BASE) & MCP_CLEAR){ + mcp_warning("wait clear bit deassert timeout, force unset clear bit, (CTRL=%08x, STATUS=%08x)\n", GET_MCP_CTRL(RTK_MCP_BASE), GET_MCP_STATUS(RTK_MCP_BASE)); + SET_MCP_CTRL(MCP_CLEAR, RTK_MCP_BASE); // issue clear + mcp_warning("CTRL=%08x, STATUS=%08x)\n",GET_MCP_CTRL(RTK_MCP_BASE), GET_MCP_STATUS(RTK_MCP_BASE)); + } + + SET_MCP_EN(0xFE, RTK_MCP_BASE); + SET_MCP_STATUS(0xFE, RTK_MCP_BASE); // clear status + + //mcp_info("before go:\n"); + //mcp_dump_all_registers(); + + SET_MCP_CTRL(MCP_GO | MCP_WRITE_DATA, RTK_MCP_BASE); + + while (WaitTime--){ + mcp_debug("STATUS=%08x, CTRL=%08x\n",GET_MCP_STATUS(RTK_MCP_BASE), GET_MCP_CTRL(RTK_MCP_BASE)); + if (!(GET_MCP_CTRL(RTK_MCP_BASE) & MCP_GO)) { + //mcp_info("ctrl break\n"); + break; + } + + if (GET_MCP_STATUS(RTK_MCP_BASE)&0x6) { + //mcp_info("status break\n"); + break; + } + + msleep(1); + } + + ret = ((GET_MCP_STATUS(RTK_MCP_BASE) & ~(MCP_RING_EMPTY | MCP_COMPARE|MCP_KL_DONE|MCP_K_KL_DONE))) ? -1 : 0; + + //mcp_info("after go:\n"); + //mcp_dump_all_registers(); + + if (ret <0) + mcp_warning("do mcp command failed, (MCP_Status %08x)\n", GET_MCP_STATUS(RTK_MCP_BASE)); + + SET_MCP_CTRL(MCP_GO, RTK_MCP_BASE); // clear go bit + SET_MCP_STATUS(0xFE, RTK_MCP_BASE); // clear ring empty + + return ret; +} + +/*------------------------------------------------------------------ + * Func : mcp_do_command + * Desc : Do Command + * Parm : p_desc : number of Descriptor to be Execute + * n_desc : number of Descriptor to be Execute + * Retn : 0 : success, others fail + *------------------------------------------------------------------*/ +int mcp_do_command(mcp_desc* p_desc, int n_desc) +{ + int ret = 0; + int len = sizeof(mcp_desc) * n_desc; + + int i, j; + unsigned long desc_dma_vaddr; + dma_addr_t desc_dma; + mcp_desc *p_desc_vaddr; + + if(n_desc){ + mutex_lock(&mcp_mutex); + + desc_dma_vaddr = (unsigned long)dma_alloc_coherent(&local_pdev->dev, n_desc * sizeof(mcp_desc) + sizeof(mcp_desc), &desc_dma, GFP_ATOMIC|GFP_DMA); + + if (desc_dma_vaddr){ + + p_desc_vaddr = (mcp_desc *)desc_dma_vaddr; + + for (i = 0; i < n_desc ; i++){ + p_desc_vaddr->flags = p_desc->flags; + + for (j = 0 ; j < sizeof(p_desc->key) / sizeof(p_desc->key[0]) ; j++) { + p_desc_vaddr->key[j] = p_desc->key[j]; + } + + for (j = 0 ; j < sizeof(p_desc->iv) / sizeof(p_desc->iv[0]) ; j++) { + p_desc_vaddr->iv[j] = p_desc->iv[j]; + } + + p_desc_vaddr->data_in = p_desc->data_in; + p_desc_vaddr->data_out = p_desc->data_out; + p_desc_vaddr->length = p_desc->length; +#ifdef MCP_DEBUG_EN + mcp_dump_descriptor(p_desc_vaddr); +#else + //mcp_info("Do command, flags:0x%0x\n", p_desc->flags); +#endif + p_desc_vaddr++; + p_desc++; + } + + p_desc_vaddr = p_desc_vaddr - n_desc; + p_desc = p_desc - n_desc; + + _mcp_set_desc_buffer(desc_dma, desc_dma + len + sizeof(mcp_desc), desc_dma, desc_dma + len); + + ret = _mcp_start_xfer(); + }else{ + mcp_warning("no dma buffer for descriptor!\n"); + ret = -1; // error, no dma buffer for descriptor + } + + dma_free_coherent(&local_pdev->dev, n_desc * sizeof(mcp_desc), (void *)desc_dma_vaddr, desc_dma); + + mutex_unlock(&mcp_mutex); + } + + return ret; +} + +/******************************************************************************** + AES + ********************************************************************************/ +/*------------------------------------------------------------------ + * Func : MCP_AES_DESC_INIT + * Desc : Init AES Descriptor + * Parm : pDesc : Descriptor to be Load + * EnDe : Encryption/Descryption + * 0 for Decryption / 1 for Encryption + * Mode : Operation Mode + * Key : Key Value + * IV : Initial Vector + * Retn : S_OK / S_FALSE + *------------------------------------------------------------------*/ +int MCP_AES_DESC_INIT(mcp_desc* pDesc, unsigned char EnDe, unsigned char Mode, unsigned char Key[16], unsigned char IV[16]) +{ + memset(pDesc, 0, sizeof(mcp_desc)); + + switch (Mode){ + case MCP_BCM_ECB: + case MCP_BCM_CBC: + case MCP_BCM_CTR: + pDesc->flags = MARS_MCP_MODE(MCP_ALGO_AES) | MARS_MCP_BCM(Mode) | MARS_MCP_ENC(EnDe); + + if(Key){ + pDesc->key[0] = (Key[ 0]<<24) + (Key[ 1]<<16) + (Key[ 2]<<8) + Key[ 3]; + pDesc->key[1] = (Key[ 4]<<24) + (Key[ 5]<<16) + (Key[ 6]<<8) + Key[ 7]; + pDesc->key[2] = (Key[ 8]<<24) + (Key[ 9]<<16) + (Key[10]<<8) + Key[11]; + pDesc->key[3] = (Key[12]<<24) + (Key[13]<<16) + (Key[14]<<8) + Key[15]; + }else + pDesc->flags |= MARS_MCP_KEY_SEL(MCP_KEY_SEL_OTP); + + if(IV){ + pDesc->iv[0] = (IV[ 0]<<24) + (IV[ 1]<<16) + (IV[ 2]<<8) + IV[ 3]; + pDesc->iv[1] = (IV[ 4]<<24) + (IV[ 5]<<16) + (IV[ 6]<<8) + IV[ 7]; + pDesc->iv[2] = (IV[ 8]<<24) + (IV[ 9]<<16) + (IV[10]<<8) + IV[11]; + pDesc->iv[3] = (IV[12]<<24) + (IV[13]<<16) + (IV[14]<<8) + IV[15]; + } + return 0; + default: + mcp_warning("Init AES descriptor failed - invalid mode (%d)\n", Mode); + return -1; + } +} + +/*------------------------------------------------------------------ + * Func : MCP_AES_Decryption + * Desc : Do AES Decryption + * Parm : mode : Operation Mode + * key : Key Value + * iv : Initial Vector + * p_in : Data In + * p_out : Data Out + * len : Data Length + * Retn : 0 for success, others failed + *------------------------------------------------------------------*/ +int MCP_AES_Decryption(unsigned char Mode, unsigned char Key[16], unsigned char IV[16], unsigned char* p_in, unsigned char* p_out, unsigned long len) +{ + mcp_desc desc; + int ret; + //dma_addr_t addr1; + //dma_addr_t addr2; + + MCP_AES_DESC_INIT(&desc, 0, Mode, Key, IV); + + //addr1 = _mcp_map_single(p_in, len, DMA_TO_DEVICE); + //addr2 = _mcp_map_single(p_out, len, DMA_FROM_DEVICE); + +#if defined(MY_DEF_HERE) + desc.data_in = (uintptr_t)p_in; + desc.data_out = (uintptr_t)p_out; +#else /* MY_DEF_HERE */ + desc.data_in = p_in; + desc.data_out = p_out; +#endif /* MY_DEF_HERE */ + desc.length = len & ~0xF; + + ret = mcp_do_command(&desc, 1); + + //_mcp_unmap_single(addr1, len, DMA_TO_DEVICE); + //_mcp_unmap_single(addr2, len, DMA_FROM_DEVICE); + + return ret; +} + +/*------------------------------------------------------------------ + * Func : MCP_AES_Encryption + * Desc : Do AES Encryption + * Parm : mode : Operation Mode + * key : Key Value + * iv : Initial Vector + * p_in : Data In + * p_out : Data Out + * len : Data Length + * Retn : 0 for success, others failed + *------------------------------------------------------------------*/ +int MCP_AES_Encryption(unsigned char mode, unsigned char key[16], unsigned char iv[16], unsigned char* p_in, unsigned char* p_out, unsigned long len) +{ + mcp_desc desc; + int ret; + //dma_addr_t addr1; + //dma_addr_t addr2; + + MCP_AES_DESC_INIT(&desc, 1, mode, key, iv); + + //addr1 = _mcp_map_single(p_in, len, DMA_TO_DEVICE); + //addr2 = _mcp_map_single(p_out, len, DMA_FROM_DEVICE); + +#if defined(MY_DEF_HERE) + desc.data_in = (uintptr_t)p_in; + desc.data_out = (uintptr_t)p_out; +#else /* MY_DEF_HERE */ + desc.data_in = p_in; + desc.data_out = p_out; +#endif /* MY_DEF_HERE */ + desc.length = len & ~0xF; + + ret = mcp_do_command(&desc, 1); + + //_mcp_unmap_single(addr1, len, DMA_TO_DEVICE); + //_mcp_unmap_single(addr2, len, DMA_FROM_DEVICE); + + return ret; +} + +void MCP_SHA256_DESC_INIT(mcp_desc *pDesc, unsigned int iv[8]) +{ + memset(pDesc, 0, sizeof(mcp_desc)); + + pDesc->flags = MARS_MCP_MODE(MCP_ALGO_SHA256); + + if (iv == NULL) { + pDesc->key[0] = SHA256_H0; + pDesc->key[1] = SHA256_H1; + pDesc->key[2] = SHA256_H2; + pDesc->key[3] = SHA256_H3; + pDesc->key[4] = SHA256_H4; + pDesc->key[5] = SHA256_H5; + pDesc->iv[0] = SHA256_H6; + pDesc->iv[1] = SHA256_H7; + } + else { + pDesc->key[0] = iv[0]; + pDesc->key[1] = iv[1]; + pDesc->key[2] = iv[2]; + pDesc->key[3] = iv[3]; + pDesc->key[4] = iv[4]; + pDesc->key[5] = iv[5]; + pDesc->iv[0] = iv[6]; + pDesc->iv[1] = iv[7]; + } +} + +int MCP_SHA256(unsigned char *p_in, unsigned char *p_out, unsigned long len, unsigned int iv[8]) +{ + mcp_desc desc; + int ret; + + MCP_SHA256_DESC_INIT(&desc, iv); + +#if defined(MY_DEF_HERE) + desc.data_in = (uintptr_t)p_in; + desc.data_out = (uintptr_t)p_out; +#else /* MY_DEF_HERE */ + desc.data_in = p_in; + desc.data_out = p_out; +#endif /* MY_DEF_HERE */ + desc.length = len; + + ret = mcp_do_command(&desc, 1); + + return ret; +} + +EXPORT_SYMBOL(MCP_SHA256); + +/*------------------------------------------------------------------ + * Func : MCP_AES_128_ECB_DataEncryptTest + * Desc : Test AES 128 ECB + * Parm : N/A + * Retn : N/A + *------------------------------------------------------------------*/ +void MCP_AES_128_ECB_DataEncryptTest(void) +{ + unsigned char Data[16]={0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}; + unsigned char Key[16]; + + unsigned long data_dma_vaddr; + dma_addr_t data_dma_phyaddr; + unsigned char *pData = NULL; + int i = 0; + + data_dma_vaddr = (unsigned long)dma_alloc_coherent(&local_pdev->dev, sizeof(Data), &data_dma_phyaddr, GFP_ATOMIC|GFP_DMA); + + if (data_dma_vaddr) { + memset(Key, 'b', sizeof(Key)); + + pData = (unsigned char *)data_dma_vaddr; + + for (i = 0; i < sizeof(Data); i++) { + pData[i] = Data[i]; + } + + MCP_AES_ECB_Encryption(Key, (unsigned char *)data_dma_phyaddr, (unsigned char *)data_dma_phyaddr, 16); + + mcp_dump_data_with_text(pData, 16, "encrypted value : "); + + MCP_AES_ECB_Decryption(Key, (unsigned char *)data_dma_phyaddr, (unsigned char *)data_dma_phyaddr, 16); + + mcp_dump_data_with_text(pData, 16, "decrypted value : "); + }else{ + mcp_warning("test dma alloc fail"); + } + + dma_free_coherent(&local_pdev->dev, sizeof(Data), (void *)data_dma_vaddr, data_dma_phyaddr); +} + +static int mcp_probe(struct platform_device *pdev) +{ + local_pdev = pdev; + + printk(KERN_INFO "[RTK MCP] MCP driver initial begin.\n"); + + RTK_MCP_BASE = of_iomap(pdev->dev.of_node, 0); + if (!MCP_BASE) { + dev_err(&pdev->dev, "no mcp address\n"); + return -EINVAL; + } + + RTK_TP_BASE = of_iomap(pdev->dev.of_node, 1); + if (!RTK_TP_BASE) { + dev_err(&pdev->dev, "no tp address\n"); + return -EINVAL; + } + + printk(KERN_INFO "[RTK MCP] MCP Base: 0x%p\n", RTK_MCP_BASE); + printk(KERN_INFO "[RTK MCP] TP Base: 0x%p\n", RTK_TP_BASE); + + if (mcp_init()<0) + return -ENODEV; + + cdev_init(&mcp_dev, &mcp_ops); + + if (alloc_chrdev_region(&devno, 0, 1, MCP_DEVICE_NAME) != 0){ + cdev_del(&mcp_dev); + printk("%s %s %d",__FILE__, __func__,__LINE__); + return -EFAULT; + } + + if (cdev_add(&mcp_dev, devno, 1) < 0) + return -EFAULT; + + mcp_dev_class = class_create(THIS_MODULE, MCP_DEVICE_NAME); // create a new class for mcp + + mcp_device = device_create(mcp_dev_class, NULL, devno, NULL, "mcp_core"); + + printk(KERN_INFO "[RTK MCP] MCP driver initial done.\n"); + + return 0; +} + +static int mcp_remove(struct platform_device *dev) +{ + printk(KERN_INFO "[RTK MCP] MCP driver remove begin.\n"); + + device_destroy(mcp_dev_class, mcp_device->devt); + + cdev_del(&mcp_dev); + + unregister_chrdev_region(devno, 1); + + mcp_uninit(); + + printk(KERN_INFO "[RTK MCP] MCP driver remove done.\n"); + + return 0; +} + +static int mcp_suspend(struct platform_device *dev, pm_message_t state) +{ + printk(KERN_INFO "[RTK MCP] Suspend Enter\n"); + printk(KERN_INFO "[RTK MCP] Suspend Exit\n"); + return 0; +} + +static int mcp_resume(struct platform_device *dev) +{ + printk(KERN_INFO "[RTK MCP] Resume Enter\n"); + printk(KERN_INFO "[RTK MCP] Resume Exit\n"); + return 0; +} + +static struct of_device_id rtk_mcp_ids[] = { + { .compatible = "realtek,rtk-mcp" }, + { /* Sentinel */ }, +}; + +static struct platform_driver rtk_mcp_driver = { + .probe = mcp_probe, + .remove = mcp_remove, + .suspend = mcp_suspend, + .resume = mcp_resume, + .driver = { + .name = "RTK_MCP", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtk_mcp_ids), + }, +}; + +module_platform_driver(rtk_mcp_driver); diff --git a/drivers/soc/realtek/common/rtk_mcp.h b/drivers/soc/realtek/common/rtk_mcp.h new file mode 100644 index 000000000000..aa17ddf3e210 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_mcp.h @@ -0,0 +1,178 @@ +/* + * rtk_mcp.h - MCP driver + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#define CP_REG_BASE 0x0 +#define TP_REG_BASE 0x0 +#define CP_OTP_LOAD (CP_REG_BASE + 0x19c) + +/* for SCPU */ +/* MCP General Registers */ +#define MCP_CTRL (CP_REG_BASE + 0x100) +#define MCP_CTRL1 (CP_REG_BASE + 0x198) +#define MCP_STATUS (CP_REG_BASE + 0x104) +#define MCP_EN (CP_REG_BASE + 0x108) + +/* MCP Ring-Buffer Registers */ +#define MCP_BASE (CP_REG_BASE + 0x10c) +#define MCP_LIMIT (CP_REG_BASE + 0x110) +#define MCP_RDPTR (CP_REG_BASE + 0x114) +#define MCP_WRPTR (CP_REG_BASE + 0x118) +#define MCP_DES_COUNT (CP_REG_BASE + 0x134) +#define MCP_DES_COMPARE (CP_REG_BASE + 0x138) + +/* MCP Ini_Key Registers */ +#define MCP_DES_INI_KEY (CP_REG_BASE + 0x11C) +#define MCP_AES_INI_KEY (CP_REG_BASE + 0x124) + +/* CP Power Management */ +#define PWM_CTRL (CP_REG_BASE + 0x1e0) + +/* TP registers */ +#define TP_KEY_INFO_0 (TP_REG_BASE + 0x58) +#define TP_KEY_INFO_1 (TP_REG_BASE + 0x5c) +#define TP_KEY_CTRL (TP_REG_BASE + 0x60) + +#if 1 + +#define SET_TP_KEY_CTRL(x,y) writel((x), (volatile unsigned int*) (TP_KEY_CTRL+y)) +#define SET_TP_KEYINFO_0(x,y) writel((x), (volatile unsigned int*) (TP_KEY_INFO_0+y)) +#define SET_TP_KEYINFO_1(x,y) writel((x), (volatile unsigned int*) (TP_KEY_INFO_1+y)) + +#define SET_MCP_CTRL(x,y) writel((x), (volatile unsigned int*) (MCP_CTRL+y)) +#define SET_MCP_CTRL1(x,y) writel((x), (volatile unsigned int*) (MCP_CTRL1+y)) +#define SET_MCP_STATUS(x,y) writel((x), (volatile unsigned int*) (MCP_STATUS+y)) +#define SET_MCP_EN(x,y) writel((x), (volatile unsigned int*) (MCP_EN+y)) +#define SET_MCP_BASE(x,y) writel((x), (volatile unsigned int*) (MCP_BASE+y)) +#define SET_MCP_LIMIT(x,y) writel((x), (volatile unsigned int*) (MCP_LIMIT+y)) +#define SET_MCP_RDPTR(x,y) writel((x), (volatile unsigned int*) (MCP_RDPTR+y)) +#define SET_MCP_WRPTR(x,y) writel((x), (volatile unsigned int*) (MCP_WRPTR+y)) +#define SET_MCP_OTP_LOAD(x,y) writel((x), (volatile unsigned int*) (CP_OTP_LOAD+y)) /* for Jupiter only */ +#define SET_MCP_DES_COUNT(x,y) writel((x), (volatile unsigned int*) (MCP_DES_COUNT+y)) +#define SET_MCP_DES_COMPARE(x,y) writel((x), (volatile unsigned int*) (MCP_DES_COMPARE+y)) + +#define SET_PWM_CTRL(x,y) writel((x), (volatile unsigned int*) (PWM_CTRL+y)) + +#define GET_MCP_CTRL(y) readl((volatile unsigned int*) (MCP_CTRL+y)) +#define GET_MCP_CTRL1(y) readl((volatile unsigned int*) (MCP_CTRL1+y)) +#define GET_MCP_STATUS(y) readl((volatile unsigned int*) (MCP_STATUS+y)) +#define GET_MCP_EN(y) readl((volatile unsigned int*) (MCP_EN+y)) +#define GET_MCP_BASE(y) readl((volatile unsigned int*) (MCP_BASE+y)) +#define GET_MCP_LIMIT(y) readl((volatile unsigned int*) (MCP_LIMIT+y)) +#define GET_MCP_RDPTR(y) readl((volatile unsigned int*) (MCP_RDPTR+y)) +#define GET_MCP_WRPTR(y) readl((volatile unsigned int*) (MCP_WRPTR+y)) +#define GET_MCP_OTP_LOAD(y) readl((volatile unsigned int*) (CP_OTP_LOAD+y)) /* for Jupiter only */ +#define GET_MCP_DES_COUNT(y) readl((volatile unsigned int*) (MCP_DES_COUNT+y)) +#define GET_MCP_DES_COMPARE(y) readl((volatile unsigned int*) (MCP_DES_COMPARE+y)) + +#define GET_PWM_CTRL(y) readl((volatile unsigned int*) (PWM_CTRL+y)) + +#endif + +//for IOCTL +#define MCP_IOC_MAGIC 'm' +#define MCP_DESC_ENTRY_COUNT 64 +#define MCP_IOCTL_DO_COMMAND 0x70000001 +#define MCP_IOCTL_TEST_AES_H 0x71000001 +#define MCP_IOCTL_ENABLE_AUTO_PADDING _IO (MCP_IOC_MAGIC, 2) +#define MCP_IOCTL_DISABLE_AUTO_PADDING _IO (MCP_IOC_MAGIC, 3) + +#define MCP_BCM_ECB 0x0 +#define MCP_BCM_CBC 0x1 +#define MCP_BCM_CTR 0x2 + +#define MCP_WRITE_DATA (0x01) +#define MCP_RING_EMPTY (0x01 <<1) +#define MCP_ERROR (0x01 <<2) +#define MCP_COMPARE (0x01 <<3) +#define MCP_KL_DONE (0x01 <<20) +#define MCP_K_KL_DONE (0x01 <<13) + +#define MCP_GO (0x01<<1) +#define MCP_IDEL (0x01<<2) +#define MCP_SWAP (0x01<<3) +#define MCP_CLEAR (0x01<<4) + +// Descriptor Definition +#define MARS_MCP_MODE(x) (x & 0x1F) + +#define MCP_ALGO_DES 0x00 +#define MCP_ALGO_3DES 0x01 +#define MCP_ALGO_RC4 0x02 +#define MCP_ALGO_MD5 0x03 +#define MCP_ALGO_SHA_1 0x04 +#define MCP_ALGO_AES 0x05 +#define MCP_ALGO_AES_G 0x06 +#define MCP_ALGO_AES_H 0x07 +#define MCP_ALGO_CMAC 0x08 +#define MCP_ALGO_SHA256 0x0b + +#define MARS_MCP_BCM(x) ((x & 0x3) << 6) +#define MCP_BCM_ECB 0x0 +#define MCP_BCM_CBC 0x1 +#define MCP_BCM_CTR 0x2 + +#define MARS_MCP_ENC(x) ((x & 0x1) << 5) + +#define MARS_MCP_KEY_SEL(x) ((x & 0x1) << 12) +#define MCP_KEY_SEL_OTP 0x1 +#define MCP_KEY_SEL_DESC 0x0 + +#define MARS_MCP_IV_SEL(x) ((x & 0x1) << 11) +#define MCP_IV_SEL_REG 0x1 +#define MCP_IV_SEL_DESC 0x0 + +#define MCP_AES_ECB_Decryption(key, p_in, p_out, len) MCP_AES_Decryption(MCP_BCM_ECB, key, NULL, p_in, p_out, len) +#define MCP_AES_ECB_Encryption(key, p_in, p_out, len) MCP_AES_Encryption(MCP_BCM_ECB, key, NULL, p_in, p_out, len) + +#define mcp_dump_data_with_text(data, len ,fmt, args...) do {\ + printk(fmt, ## args);\ + mcp_dump_mem(data, len);\ + }while(0) + +/* Debug */ +//#define MCP_DEBUG_EN +#ifdef MCP_DEBUG_EN +#define mcp_debug(fmt, args...) printk("[MCP] Debug, " fmt, ## args) +#else +#define mcp_debug(fmt, args...) +#endif + +#define mcp_info(fmt, args...) printk("[MCP] " fmt, ## args) +#define mcp_warning(fmt, args...) pr_err("[MCP] Warning, " fmt, ## args) + +typedef struct { + uint32_t flags; + uint32_t key[6]; + uint32_t iv[4]; + uint32_t data_in; /* data in : physical address */ + uint32_t data_out; /* data out : physical address */ + uint32_t length; /* data length */ +}mcp_desc; + +typedef struct { + union { + mcp_desc __user *p_desc; + uint64_t padding_p_desc; + }; + + uint32_t n_desc; + int32_t reserved; +}mcp_desc_set; + +/* 256 bit SHA256 initial vector */ +#define SHA256_H0 0x6A09E667 +#define SHA256_H1 0xBB67AE85 +#define SHA256_H2 0x3C6EF372 +#define SHA256_H3 0xA54FF53A +#define SHA256_H4 0x510E527F +#define SHA256_H5 0x9B05688C +#define SHA256_H6 0x1F83D9AB +#define SHA256_H7 0x5BE0CD19 diff --git a/drivers/soc/realtek/common/rtk_memory_remap.c b/drivers/soc/realtek/common/rtk_memory_remap.c new file mode 100644 index 000000000000..57c3731e77be --- /dev/null +++ b/drivers/soc/realtek/common/rtk_memory_remap.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * rpc memory remapping + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ +#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 + +#define VT100_NONE "\033[m\n" +#define VT100_LIGHT_RED "\033[1;31m" + +void __iomem *rpc_common_base; +EXPORT_SYMBOL(rpc_common_base); + +void __iomem *rpc_ringbuf_base; +EXPORT_SYMBOL(rpc_ringbuf_base); + +static __init int rpc_comm_init(void) +{ + int i = 0; + int npages = 0; + int ret = -1; + struct page **pages; + struct page **tmp; + struct device_node *node; + struct resource res; + + node = of_find_compatible_node(NULL, NULL, "comm"); + if (!node) { + pr_err("%s: Unable to find comm node", __func__); + goto err; + } + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + pr_err("%s: Unable to get resource", __func__); + goto err; + } + + npages = resource_size(&res) >> PAGE_SHIFT; + pages = vmalloc(sizeof(struct page *) * npages); + if (!pages) { + pr_info(VT100_LIGHT_RED "%s, fail to allocate memory" + VT100_NONE, __func__); + ret = -1; + goto err; + } + + for (i = 0, tmp = pages; i < npages; i++) + *(tmp++) = phys_to_page(res.start + (PAGE_SIZE * i)); + + rpc_common_base = vmap(pages, + npages, + VM_MAP, + pgprot_noncached(PAGE_KERNEL)); + vfree(pages); +err: + return ret; +} +arch_initcall(rpc_comm_init); + +static __init int rpc_ringbuf_init(void) +{ + int i = 0; + int npages = 0; + int ret = -1; + struct page **pages; + struct page **tmp; + struct device_node *node; + struct resource res; + + node = of_find_compatible_node(NULL, NULL, "ringbuf"); + if (!node) { + pr_err("%s: Unable to find ringbuf node", __func__); + goto err; + } + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + pr_err("%s: Unable to get resource", __func__); + goto err; + } + + npages = resource_size(&res) >> PAGE_SHIFT; + pages = vmalloc(sizeof(struct page *) * npages); + if (!pages) { + pr_info(VT100_LIGHT_RED "%s, fail to allocate memory" + VT100_NONE, __func__); + ret = -1; + goto err; + } + + for (i = 0, tmp = pages; i < npages; i++) + *(tmp++) = phys_to_page(res.start + (PAGE_SIZE * i)); + + rpc_ringbuf_base = vmap(pages, + npages, + VM_MAP, + pgprot_noncached(PAGE_KERNEL)); + vfree(pages); +err: + return ret; +} +arch_initcall(rpc_ringbuf_init); diff --git a/drivers/soc/realtek/common/rtk_pd/Kconfig b/drivers/soc/realtek/common/rtk_pd/Kconfig new file mode 100644 index 000000000000..8262ad1a8da6 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/Kconfig @@ -0,0 +1,38 @@ +menu "Realtek Power Domain" + +config PD_REALTEK + bool "Realtek Power Domain Support" + depends on PM + depends on ARCH_REALTEK + select PM_GENERIC_DOMAINS + default y + +config PD_RTD1295 + bool "Realtek RTD1295 Power Domain Driver" + depends on PD_REALTEK + default y + help + Realtek RTD1295 Power Domain Driver Support + +config PD_RTD1395 + bool "Realtek RTD1395 Power Domain Driver" + depends on PD_REALTEK + default y + help + Realtek RTD1395 Power Domain Driver Support + +config PD_RTD1619 + bool "Realtek RTD1619 Power Domain Driver" + depends on PD_REALTEK + default y + help + Realtek RTD1619 Power Domain Driver Support + +config PD_RTD1619B + bool "Realtek RTD1619B Power Domain Driver" + depends on PD_REALTEK + default y + help + Realtek RTD1619B Power Domain Driver Support + +endmenu diff --git a/drivers/soc/realtek/common/rtk_pd/Makefile b/drivers/soc/realtek/common/rtk_pd/Makefile new file mode 100644 index 000000000000..6a1eaf6ecae7 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += rtk_gpc.o +obj-y += rtk_pd.o +obj-y += rtk_sram.o rtk_iso.o +obj-$(CONFIG_PM) += rtk_pd-pm.o + +obj-$(CONFIG_PD_RTD1295) += rtk_pd-rtd1295.o +obj-$(CONFIG_PD_RTD1395) += rtk_pd-rtd1395.o +obj-$(CONFIG_PD_RTD1619) += rtk_pd-rtd1619.o +obj-$(CONFIG_PD_RTD1619B) += rtk_pd-rtd1619b.o diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_gpc.c b/drivers/soc/realtek/common/rtk_pd/rtk_gpc.c new file mode 100644 index 000000000000..7f764c9954d6 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_gpc.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Realtek Generic Power Controller + * + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtk_sram.h" +#include "rtk_iso.h" + +struct rtk_power_desc { + const char *name; + struct rtk_sram_desc sram; + struct rtk_iso_desc iso; + int no_suppliers; + int rst_only_reset; +}; + +#define SET_PWR(_name, _ofs, _iso_bit) \ + .name = _name, \ + .sram = { SET_RTK_SRAM_CONF(_ofs, 0xf), }, \ + .iso = { SET_RTK_ISO_CONF(0xfd0, _iso_bit), } + +struct rtk_power_data { + struct device *dev; + struct generic_pm_domain genpd; + const struct rtk_power_desc *desc; + struct regmap *regmap; + struct clk *clk; + struct reset_control *rstn; + struct reset_control *rstn_bist; + struct reset_controller_dev rcdev; +}; + +static struct rtk_power_desc desc_ve1_rtd1319 = { + SET_PWR("ve1", 0xb00, 0), + .rst_only_reset = 1 +}; + +static struct rtk_power_desc desc_ve2_rtd1319 = { + SET_PWR("ve2", 0xb20, 1), +}; + +static struct rtk_power_desc desc_gpu = { + SET_PWR("gpu", 0xb60, 3), + .no_suppliers = 1, +}; + +static struct rtk_power_desc desc_ve3_rtd1319 = { + SET_PWR("ve3", 0x290, 10), + .rst_only_reset = 1 +}; + +static void rtk_power_setup_suppliers(struct rtk_power_data *pd, int already_power_on) +{ + if (pd->desc->no_suppliers) + return; + + clk_prepare_enable(pd->clk); + + if (pd->desc->rst_only_reset) { + if (!already_power_on) { + reset_control_assert(pd->rstn_bist); + reset_control_reset(pd->rstn); + } + reset_control_deassert(pd->rstn_bist); + } else { + if (!already_power_on) + reset_control_assert(pd->rstn_bist); + reset_control_deassert(pd->rstn); + reset_control_deassert(pd->rstn_bist); + } +} + +static void rtk_power_shutdown_suppliers(struct rtk_power_data *pd) +{ + if (pd->desc->no_suppliers) + return; + + if (!pd->desc->rst_only_reset) + reset_control_assert(pd->rstn); + clk_disable_unprepare(pd->clk); +} + +static int rtk_power_is_on(struct rtk_power_data *pd) +{ + return rtk_sram_power_state(pd->regmap, &pd->desc->sram); +} + +static int rtk_power_genpd_power_on(struct generic_pm_domain *genpd) +{ + struct rtk_power_data *pd = container_of(genpd, struct rtk_power_data, genpd); + int ret; + + trace_rtk_pm_event(dev_name(pd->dev), "genpd_power_on"); + + ret = rtk_sram_power_on(pd->regmap, &pd->desc->sram); + + rtk_power_setup_suppliers(pd, ret > 0); + + rtk_iso_power_on(pd->regmap, &pd->desc->iso); + + trace_rtk_pm_event(dev_name(pd->dev), "genpd_power_on_completed"); + return 0; +} + +static int rtk_power_genpd_power_off(struct generic_pm_domain *genpd) +{ + struct rtk_power_data *pd = container_of(genpd, struct rtk_power_data, genpd); + + trace_rtk_pm_event(dev_name(pd->dev), "genpd_power_off"); + + rtk_iso_power_off(pd->regmap, &pd->desc->iso); + + rtk_power_shutdown_suppliers(pd); + + rtk_sram_power_off(pd->regmap, &pd->desc->sram); + + trace_rtk_pm_event(dev_name(pd->dev), "genpd_power_off_completed"); + return 0; +} + +static int rtk_power_genpd_attach_dev(struct generic_pm_domain *genpd, struct device *dev) +{ + struct rtk_power_data *pd = container_of(genpd, struct rtk_power_data, genpd); + + trace_rtk_pm_event(dev_name(pd->dev), "genpd_attach_dev"); + + pr_debug("%s: %s %s %s\n", genpd->name, __func__, dev_driver_string(dev), dev_name(dev)); + + return 0; +} + +static void rtk_power_genpd_detach_dev(struct generic_pm_domain *genpd, struct device *dev) +{ + struct rtk_power_data *pd = container_of(genpd, struct rtk_power_data, genpd); + + trace_rtk_pm_event(dev_name(pd->dev), "genpd_detach_dev"); + + pr_debug("%s: %s %s %s\n", genpd->name, __func__, dev_driver_string(dev), dev_name(dev)); +} + +static int rtk_power_reset_reset(struct reset_controller_dev *rcdev, unsigned long idx) +{ + struct rtk_power_data *pd = container_of(rcdev, struct rtk_power_data, rcdev); + + trace_rtk_pm_event(dev_name(pd->dev), "reset_reset"); + return reset_control_reset(pd->rstn); +} + +static const struct reset_control_ops rtk_power_reset_ops = { + .reset = rtk_power_reset_reset, +}; + +static int rtk_power_reset_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + if (WARN_ON(reset_spec->args_count != 0)) + return -EINVAL; + + return 0; +} + + +static int rtk_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_power_data *pd; + int ret; + int power_off; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + pd->dev = dev; + pd->desc = of_device_get_match_data(dev); + if (!pd->desc) { + dev_err(dev, "no match data\n"); + return -EINVAL; + } + + pd->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(pd->regmap)) { + ret = PTR_ERR(pd->regmap); + dev_err(dev, "failed to get syscon regmap from parent: %d\n", ret); + return ret; + } + + if (pd->desc->no_suppliers) + goto skip_init_suppliers; + + pd->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pd->clk)) { + ret = PTR_ERR(pd->clk); + if (ret == -EPROBE_DEFER) + dev_err(dev, "clk not ready, retry\n"); + else + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + pd->rstn = devm_reset_control_get_exclusive(dev, "reset"); + if (IS_ERR(pd->rstn)) { + ret = PTR_ERR(pd->rstn); + if (ret == -EPROBE_DEFER) + dev_err(dev, "rstn not ready, retry\n"); + else + dev_err(dev, "failed to get rstn: %d\n", ret); + return ret; + } + + pd->rstn_bist = devm_reset_control_get_optional_exclusive(dev, "bist"); + if (IS_ERR(pd->rstn_bist)) { + ret = PTR_ERR(pd->rstn_bist); + if (ret == -EPROBE_DEFER) + dev_err(dev, "rstn_bist not ready, retry\n"); + else + dev_err(dev, "failed to get rstn_bist: %d\n", ret); + return ret; + } + + if (pd->rstn) { + pd->rcdev.owner = THIS_MODULE; + pd->rcdev.ops = &rtk_power_reset_ops; + pd->rcdev.nr_resets = 1, + pd->rcdev.of_node = dev->of_node; + pd->rcdev.of_reset_n_cells = 0; + pd->rcdev.of_xlate = rtk_power_reset_of_xlate; + + ret = devm_reset_controller_register(dev, &pd->rcdev); + if (ret) { + dev_err(dev, "failed to register reset_controller: %d\n", ret); + return ret; + } + } + +skip_init_suppliers: + + trace_rtk_pm_event(dev_name(dev), "init"); + + power_off = !rtk_power_is_on(pd); + if (!power_off) + rtk_power_setup_suppliers(pd, 1); + + trace_rtk_pm_event(dev_name(dev), "init_completed"); + + pd->genpd.name = dev_name(dev); + pd->genpd.power_on = rtk_power_genpd_power_on; + pd->genpd.power_off = rtk_power_genpd_power_off; + pd->genpd.attach_dev = rtk_power_genpd_attach_dev; + pd->genpd.detach_dev = rtk_power_genpd_detach_dev; + ret = pm_genpd_init(&pd->genpd, NULL, power_off); + if (ret) { + dev_err(dev, "failed to init genpd: %d\n", ret); + return ret; + } + + ret = of_genpd_add_provider_simple(np, &pd->genpd); + if (ret) { + dev_err(dev, "failed to add genpd of provider: %d\n", ret); + pm_genpd_remove(&pd->genpd); + } + return ret; +} + +static const struct of_device_id rtk_power_match[] = { + { .compatible = "realtek,gpu-power", .data = &desc_gpu, }, + { .compatible = "realtek,rtd1319-ve1-power", .data = &desc_ve1_rtd1319, }, + { .compatible = "realtek,rtd1319-ve2-power", .data = &desc_ve2_rtd1319, }, + { .compatible = "realtek,rtd1319-ve3-power", .data = &desc_ve3_rtd1319, }, + {} +}; + +static struct platform_driver rtk_power_driver = { + .probe = rtk_power_probe, + .driver = { + .name = "rtk-gpc", + .of_match_table = of_match_ptr(rtk_power_match), + }, +}; + +static int __init rtk_power_init(void) +{ + return platform_driver_register(&rtk_power_driver); +} +fs_initcall(rtk_power_init); + +MODULE_DESCRIPTION("Realtek Generic Power Controller"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_iso.c b/drivers/soc/realtek/common/rtk_pd/rtk_iso.c new file mode 100644 index 000000000000..aeca2b64d33e --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_iso.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include "rtk_iso.h" + +MODULE_LICENSE("GPL v2"); + +static void update_iso_bit(struct regmap *regmap, int offset, int bit, int is_set) +{ + unsigned int mask, val; + + mask = BIT(bit); + val = is_set ? mask : 0; + + trace_rtk_pm_reg_update_bits("iso", offset, mask, val); + + regmap_update_bits(regmap, offset, mask, val); +} + +void rtk_iso_power_on(struct regmap *regmap, const struct rtk_iso_desc *desc) +{ + update_iso_bit(regmap, desc->iso_offset, desc->iso_bit, 0); + + if (!desc->iso_2_offset) + return; + + update_iso_bit(regmap, desc->iso_2_offset, desc->iso_2_bit, 0); +} + +void rtk_iso_power_off(struct regmap *regmap, const struct rtk_iso_desc *desc) +{ + update_iso_bit(regmap, desc->iso_offset, desc->iso_bit, 1); + + if (!desc->iso_2_offset) + return; + update_iso_bit(regmap, desc->iso_2_offset, desc->iso_2_bit, 1); +} + +int rtk_iso_power_state(struct regmap *regmap, const struct rtk_iso_desc *desc) +{ + unsigned int val; + unsigned int pwr; + + regmap_read(regmap, desc->iso_offset, &val); + pwr = (val & BIT(desc->iso_bit)) == 0 ? 1 : 0; + + if (!desc->iso_2_offset) + return pwr; + + regmap_read(regmap, desc->iso_2_offset, &val); + pwr |= (val & BIT(desc->iso_2_bit)) == 0 ? 2 : 0; + return pwr; +} diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_iso.h b/drivers/soc/realtek/common/rtk_pd/rtk_iso.h new file mode 100644 index 000000000000..6ddf053348b7 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_iso.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ +#ifndef __SOC_REALTEK_ISO_H +#define __SOC_REALTEK_ISO_H + +struct rtk_iso_desc { + unsigned int iso_offset; + unsigned int iso_bit; + unsigned int iso_2_offset; + unsigned int iso_2_bit; +}; + +#define SET_RTK_ISO_CONF(_off, _bit) \ + .iso_offset = _off, \ + .iso_bit = _bit + +#define SET_RTK_ISO_2_CONF(_off, _bit) \ + .iso_2_offset = _off, \ + .iso_2_bit = _bit + +struct regmap; +void rtk_iso_power_on(struct regmap *regmap, const struct rtk_iso_desc *desc); +void rtk_iso_power_off(struct regmap *regmap, const struct rtk_iso_desc *desc); +int rtk_iso_power_state(struct regmap *regmap, const struct rtk_iso_desc *desc); + +#endif diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd-pm.c b/drivers/soc/realtek/common/rtk_pd/rtk_pd-pm.c new file mode 100644 index 000000000000..bc5ea22f9358 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd-pm.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include + +#include "rtk_pd_internal.h" + +static int rtk_pd_generic_prepare(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static void rtk_pd_generic_complete(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); +} + +static int rtk_pd_generic_suspend(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_pd_generic_resume(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_pd_generic_suspend_late(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_pd_generic_resume_early(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_pd_generic_suspend_noirq(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_pd_generic_resume_noirq(struct device *dev) +{ + struct rtk_pd_device *pd_dev = dev_get_drvdata(dev); + + dev_info(dev, "Enter %s\n", __func__); + rtk_pd_device_show_power_state(pd_dev); + dev_info(dev, "Exit %s\n", __func__); + return 0; +} + +const struct dev_pm_ops rtk_pd_generic_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rtk_pd_generic_suspend, + rtk_pd_generic_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(rtk_pd_generic_suspend_late, + rtk_pd_generic_resume_early) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rtk_pd_generic_suspend_noirq, + rtk_pd_generic_resume_noirq) + .prepare = rtk_pd_generic_prepare, + .complete = rtk_pd_generic_complete, +}; diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1295.c b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1295.c new file mode 100644 index 000000000000..b4c229cc906f --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1295.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Power Controller of RTD-1295 SoC + * + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_pd_internal.h" + +static struct rtk_pd pd_ve1 = { + SET_PD_NAME("ve1"), + SET_RTK_PD_SRAM_CONF_PWR5(0x380, 0x3a8, 0xf), + SET_RTK_PD_ISO_CONF(0x400, 0), +}; + +static struct rtk_pd pd_ve2 = { + SET_PD_NAME("ve2"), + SET_RTK_PD_SRAM_CONF(0x3c0, 0xf), + SET_RTK_PD_ISO_CONF(0x400, 4), +}; + +static struct rtk_pd pd_ve3 = { + SET_PD_NAME("ve3"), + SET_RTK_PD_SRAM_CONF(0x3e0, 0xf), + SET_RTK_PD_ISO_CONF(0x400, 6), +}; + +static struct rtk_pd pd_gpu = { + SET_PD_NAME("gpu"), + SET_RTK_PD_SRAM_CONF_PWR5(0x394, 0x3ac, 0xf), + SET_RTK_PD_ISO_CONF(0x400, 1), +}; + +static struct rtk_pd pd_nat = { + SET_PD_NAME("nat"), + SET_RTK_PD_SRAM_CONF(0x420, 0xf), + SET_RTK_PD_ISO_CONF(0x400, 18), +}; + +static struct generic_pm_domain *rtd1295_domains[RTD1295_PD_MAX] = { + [RTD1295_PD_VE1] = rtk_pd_to_genpd(&pd_ve1), + [RTD1295_PD_VE2] = rtk_pd_to_genpd(&pd_ve2), + [RTD1295_PD_VE3] = rtk_pd_to_genpd(&pd_ve3), + [RTD1295_PD_GPU] = rtk_pd_to_genpd(&pd_gpu), + [RTD1295_PD_NAT] = rtk_pd_to_genpd(&pd_nat), +}; + +static int rtd1295_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_pd_device *pd_dev; + int ret; + + pd_dev = devm_kzalloc(dev, sizeof(*pd_dev), GFP_KERNEL); + if (!pd_dev) + return -ENOMEM; + + pd_dev->dev = dev; + pd_dev->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(pd_dev->regmap)) { + ret = PTR_ERR(pd_dev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + INIT_LIST_HEAD(&pd_dev->list); + + rtk_pd_device_add_domains(pd_dev, rtd1295_domains, ARRAY_SIZE(rtd1295_domains)); + + pd_dev->of_provider_data.domains = rtd1295_domains; + pd_dev->of_provider_data.num_domains = ARRAY_SIZE(rtd1295_domains); + ret = of_genpd_add_provider_onecell(np, &pd_dev->of_provider_data); + WARN(ret, "of_genpd_add_provider_onecell() returns %d\n", ret); + + dev_set_drvdata(dev, pd_dev); + return 0; +} + +static const struct of_device_id rtd1295_power_match[] = { + { .compatible = "realtek,rtd1295-power" }, + {} +}; + +static struct platform_driver rtd1295_power_driver = { + .probe = rtd1295_power_probe, + .driver = { + .name = "rtk-rtd1295-power", + .of_match_table = of_match_ptr(rtd1295_power_match), + .pm = &rtk_pd_generic_pm_ops, + }, +}; + +static int __init rtd1295_power_init(void) +{ + return platform_driver_register(&rtd1295_power_driver); +} +arch_initcall(rtd1295_power_init); + +MODULE_DESCRIPTION("Realtek RTD1295 Power Controller"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1395.c b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1395.c new file mode 100644 index 000000000000..12363b4e3b8a --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1395.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Power Controller of RTD-1395 SoC + * + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_pd_internal.h" + +static struct rtk_pd pd_gpu = { + SET_PD_NAME("gpu"), + SET_RTK_PD_SRAM_CONF(0xb60, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 3), +}; + +static struct rtk_pd pd_ve1 = { + SET_PD_NAME("ve1"), + SET_RTK_PD_SRAM_CONF(0xb00, 0xf), + SET_RTK_PD_SRAM_CONF_MANUAL_MASK(0x00008000), + SET_RTK_PD_ISO_CONF(0xfd0, 0), +}; + +static struct rtk_pd pd_ve2 = { + SET_PD_NAME("ve2"), + SET_RTK_PD_SRAM_CONF(0xb20, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 1), +}; + +static struct generic_pm_domain *rtd1395_domains[RTD1395_PD_MAX] = { + [RTD1395_PD_VE1] = rtk_pd_to_genpd(&pd_ve1), + [RTD1395_PD_VE2] = rtk_pd_to_genpd(&pd_ve2), + [RTD1395_PD_GPU] = rtk_pd_to_genpd(&pd_gpu), +}; + +static int rtd1395_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_pd_device *pd_dev; + int ret; + + pd_dev = devm_kzalloc(dev, sizeof(*pd_dev), GFP_KERNEL); + if (!pd_dev) + return -ENOMEM; + + pd_dev->dev = dev; + pd_dev->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(pd_dev->regmap)) { + ret = PTR_ERR(pd_dev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + INIT_LIST_HEAD(&pd_dev->list); + + rtk_pd_device_add_domains(pd_dev, rtd1395_domains, ARRAY_SIZE(rtd1395_domains)); + + pd_dev->of_provider_data.domains = rtd1395_domains; + pd_dev->of_provider_data.num_domains = ARRAY_SIZE(rtd1395_domains); + ret = of_genpd_add_provider_onecell(np, &pd_dev->of_provider_data); + WARN(ret, "of_genpd_add_provider_onecell() returns %d\n", ret); + + dev_set_drvdata(dev, pd_dev); + return 0; +} + +static const struct of_device_id rtd1395_power_match[] = { + { .compatible = "realtek,rtd1395-power" }, + {} +}; + +static struct platform_driver rtd1395_power_driver = { + .probe = rtd1395_power_probe, + .driver = { + .name = "rtk-rtd1395-power", + .of_match_table = of_match_ptr(rtd1395_power_match), + .pm = &rtk_pd_generic_pm_ops, + }, +}; + +static int __init rtd1395_power_init(void) +{ + return platform_driver_register(&rtd1395_power_driver); +} +arch_initcall(rtd1395_power_init); + +MODULE_DESCRIPTION("Realtek RTD1395 Power Controller"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619.c b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619.c new file mode 100644 index 000000000000..b1fa85c4cf6b --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Power Controller of RTD-1619 SoC + * + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_pd_internal.h" + +static struct rtk_pd pd_gpu = { + SET_PD_NAME("gpu"), + SET_RTK_PD_SRAM_CONF(0xb60, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 3), + SET_RTK_PD_ISO_2_CONF(0x078, 1), +}; + +static struct rtk_pd pd_ve1 = { + SET_PD_NAME("ve1"), + SET_RTK_PD_SRAM_CONF(0xb00, 0xf), + SET_RTK_PD_SRAM_CONF_MANUAL_MASK(0x00008000), + SET_RTK_PD_ISO_CONF(0xfd0, 0), +}; + +static struct rtk_pd pd_ve2 = { + SET_PD_NAME("ve2"), + SET_RTK_PD_SRAM_CONF(0xb20, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 1), +}; + +static struct rtk_pd pd_ve3 = { + SET_PD_NAME("ve3"), + SET_RTK_PD_SRAM_CONF(0x290, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 10), +}; + +static struct rtk_pd pd_hdmirx = { + SET_PD_NAME("hdmirx"), + SET_RTK_PD_SRAM_CONF(0x260, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 9), +}; + +static struct generic_pm_domain *rtd1619_domains[RTD1619_PD_MAX] = { + [RTD1619_PD_VE1] = rtk_pd_to_genpd(&pd_ve1), + [RTD1619_PD_VE2] = rtk_pd_to_genpd(&pd_ve2), + [RTD1619_PD_VE3] = rtk_pd_to_genpd(&pd_ve3), + [RTD1619_PD_GPU] = rtk_pd_to_genpd(&pd_gpu), + [RTD1619_PD_HDMIRX] = rtk_pd_to_genpd(&pd_hdmirx), +}; + +static int rtd1619_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_pd_device *pd_dev; + int ret; + + pd_dev = devm_kzalloc(dev, sizeof(*pd_dev), GFP_KERNEL); + if (!pd_dev) + return -ENOMEM; + + pd_dev->dev = dev; + pd_dev->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(pd_dev->regmap)) { + ret = PTR_ERR(pd_dev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + INIT_LIST_HEAD(&pd_dev->list); + + rtk_pd_device_add_domains(pd_dev, rtd1619_domains, ARRAY_SIZE(rtd1619_domains)); + + pd_dev->of_provider_data.domains = rtd1619_domains; + pd_dev->of_provider_data.num_domains = ARRAY_SIZE(rtd1619_domains); + ret = of_genpd_add_provider_onecell(np, &pd_dev->of_provider_data); + WARN(ret, "of_genpd_add_provider_onecell() returns %d\n", ret); + + dev_set_drvdata(dev, pd_dev); + return 0; +} + +static const struct of_device_id rtd1619_power_match[] = { + { .compatible = "realtek,rtd1619-power" }, + {} +}; + +static struct platform_driver rtd1619_power_driver = { + .probe = rtd1619_power_probe, + .driver = { + .name = "rtk-rtd1619-power", + .of_match_table = of_match_ptr(rtd1619_power_match), + .pm = &rtk_pd_generic_pm_ops, + }, +}; + +static int __init rtd1619_power_init(void) +{ + return platform_driver_register(&rtd1619_power_driver); +} +arch_initcall(rtd1619_power_init); + +MODULE_DESCRIPTION("Realtek RTD1619 Power Controller"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619b.c b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619b.c new file mode 100644 index 000000000000..5a51d1397844 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd-rtd1619b.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Power Controller of RTD-1619B SoC + * + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtk_pd_internal.h" + +static struct rtk_pd pd_gpu = { + SET_PD_NAME("gpu"), + SET_RTK_PD_SRAM_CONF(0xb60, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 3), +}; + +static struct rtk_pd pd_ve1 = { + SET_PD_NAME("ve1"), + SET_RTK_PD_SRAM_CONF(0xb00, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 0), +}; + +static struct rtk_pd pd_ve2 = { + SET_PD_NAME("ve2"), + .pd_iso.pd.flags = GENPD_FLAG_ALWAYS_ON, + SET_RTK_PD_SRAM_CONF(0xb20, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 1), +}; + +static struct rtk_pd pd_ve3 = { + SET_PD_NAME("ve3"), + SET_RTK_PD_SRAM_CONF(0x290, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 10), +}; + +static struct rtk_pd pd_npu = { + SET_PD_NAME("npu"), + SET_RTK_PD_SRAM_CONF(0x3b0, 0xf), + SET_RTK_PD_SRAM_DELAY(0xf, 0xf), + SET_RTK_PD_SRAM_STD_DELAY(0x28c, 0x32), + SET_RTK_PD_ISO_CONF(0xfd0, 12), +}; + +static struct rtk_pd pd_hifi0 = { + SET_PD_NAME("hifi0"), + SET_RTK_PD_SRAM_CONF(0x238, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 13), +}; + +static struct rtk_pd pd_hifi1 = { + SET_PD_NAME("hifi1"), + SET_RTK_PD_SRAM_CONF(0x260, 0xf), + SET_RTK_PD_ISO_CONF(0xfd0, 14), +}; + +static struct generic_pm_domain *rtd1619b_domains[RTD1619B_PD_MAX] = { + [RTD1619B_PD_VE1] = rtk_pd_to_genpd(&pd_ve1), + [RTD1619B_PD_VE2] = rtk_pd_to_genpd(&pd_ve2), + [RTD1619B_PD_VE3] = rtk_pd_to_genpd(&pd_ve3), + [RTD1619B_PD_GPU] = rtk_pd_to_genpd(&pd_gpu), + [RTD1619B_PD_HIFI0] = rtk_pd_to_genpd(&pd_hifi0), + [RTD1619B_PD_HIFI1] = rtk_pd_to_genpd(&pd_hifi1), + [RTD1619B_PD_NPU] = rtk_pd_to_genpd(&pd_npu), +}; + +static void rtd1619b_power_post_setup(void) +{ + rtd1619b_domains[RTD1619B_PD_NPU_SRAM] = &pd_npu.pd_sram.pd; +} + +static int rtd1619b_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rtk_pd_device *pd_dev; + int ret; + + pd_dev = devm_kzalloc(dev, sizeof(*pd_dev), GFP_KERNEL); + if (!pd_dev) + return -ENOMEM; + + pd_dev->dev = dev; + pd_dev->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(pd_dev->regmap)) { + ret = PTR_ERR(pd_dev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + INIT_LIST_HEAD(&pd_dev->list); + + rtk_pd_device_add_domains(pd_dev, rtd1619b_domains, ARRAY_SIZE(rtd1619b_domains)); + + rtd1619b_power_post_setup(); + + pd_dev->of_provider_data.domains = rtd1619b_domains; + pd_dev->of_provider_data.num_domains = ARRAY_SIZE(rtd1619b_domains); + ret = of_genpd_add_provider_onecell(np, &pd_dev->of_provider_data); + WARN(ret, "of_genpd_add_provider_onecell() returns %d\n", ret); + + dev_set_drvdata(dev, pd_dev); + return 0; +} + +static const struct of_device_id rtd1619b_power_match[] = { + { .compatible = "realtek,rtd1619b-power" }, + {} +}; + +static struct platform_driver rtd1619b_power_driver = { + .probe = rtd1619b_power_probe, + .driver = { + .name = "rtk-rtd1619b-power", + .of_match_table = of_match_ptr(rtd1619b_power_match), + .pm = &rtk_pd_generic_pm_ops, + }, +}; + +static int __init rtd1619b_power_init(void) +{ + return platform_driver_register(&rtd1619b_power_driver); +} +arch_initcall(rtd1619b_power_init); + +MODULE_DESCRIPTION("Realtek RTD1619B Power Controller"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd.c b/drivers/soc/realtek/common/rtk_pd/rtk_pd.c new file mode 100644 index 000000000000..deb55c3e3c71 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include "rtk_pd_internal.h" + +static inline unsigned long rtk_pd_lock(struct rtk_pd *pd) +{ + unsigned long flags = 0; + + mutex_lock(&pd->lock); + return flags; +} + +static inline void rtk_pd_unlock(struct rtk_pd *pd, unsigned long flags) +{ + mutex_unlock(&pd->lock); +} + +static int sram_power_on(struct rtk_pd *pd) +{ + unsigned long flags; + int ret; + + pr_debug("%s: %s\n", rtk_pd_name(pd), __func__); + flags = rtk_pd_lock(pd); + ret = rtk_sram_power_on(pd->pd_dev->regmap, &pd->sram); + rtk_pd_unlock(pd, flags); + return ret; +} + +static int sram_power_off(struct rtk_pd *pd) +{ + unsigned long flags; + int ret; + + pr_debug("%s: %s\n", rtk_pd_name(pd), __func__); + flags = rtk_pd_lock(pd); + ret = rtk_sram_power_off(pd->pd_dev->regmap, &pd->sram); + rtk_pd_unlock(pd, flags); + + return 0; +} + +static int sram_power_state(struct rtk_pd *pd) +{ + unsigned long flags; + unsigned int val; + + flags = rtk_pd_lock(pd); + val = rtk_sram_power_state(pd->pd_dev->regmap, &pd->sram); + rtk_pd_unlock(pd, flags); + return val; +} + +static int rtk_pd_sram_power_on(struct generic_pm_domain *genpd) +{ + struct rtk_pd_instance *ins = genpd_to_rtk_pd_instance(genpd); + int ret; + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_PRE_ON); + + ret = sram_power_on(rtk_pd_instance_to_rtk_pd(sram, ins)); + if (ret < 0) + pr_warn("%s: failed to power on sram: %d\n", ins->pd.name, ret); + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_ON); + + return 0; +} + +static int rtk_pd_sram_power_off(struct generic_pm_domain *genpd) +{ + struct rtk_pd_instance *ins = genpd_to_rtk_pd_instance(genpd); + int ret; + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_PRE_OFF); + + ret = sram_power_off(rtk_pd_instance_to_rtk_pd(sram, ins)); + if (ret < 0) + pr_warn("%s: failed to power on sram: %d\n", ins->pd.name, ret); + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_OFF); + + return 0; +} + +static void iso_power_on(struct rtk_pd *pd) +{ + pr_debug("%s: %s\n", rtk_pd_name(pd), __func__); + rtk_iso_power_on(pd->pd_dev->regmap, &pd->iso); +} + +static void iso_power_off(struct rtk_pd *pd) +{ + pr_debug("%s: %s\n", rtk_pd_name(pd), __func__); + rtk_iso_power_off(pd->pd_dev->regmap, &pd->iso); +} + +static int iso_power_state(struct rtk_pd *pd) +{ + return rtk_iso_power_state(pd->pd_dev->regmap, &pd->iso); +} + +static int rtk_pd_iso_power_on(struct generic_pm_domain *genpd) +{ + struct rtk_pd_instance *ins = genpd_to_rtk_pd_instance(genpd); + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_PRE_ON); + + iso_power_on(rtk_pd_instance_to_rtk_pd(iso, ins)); + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_ON); + + return 0; +} + +static int rtk_pd_iso_power_off(struct generic_pm_domain *genpd) +{ + struct rtk_pd_instance *ins = genpd_to_rtk_pd_instance(genpd); + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_PRE_OFF); + + iso_power_off(rtk_pd_instance_to_rtk_pd(iso, ins)); + + rtk_pd_instance_notify(ins, RTK_PD_NOTIFY_OFF); + + return 0; +} + +static int rtk_genpd_attach_dev(struct generic_pm_domain *genpd, struct device *dev) +{ + pr_debug("%s: %s %s %s\n", genpd->name, __func__, dev_driver_string(dev), dev_name(dev)); + return 0; +} + +static void rtk_genpd_detach_dev(struct generic_pm_domain *genpd, struct device *dev) +{ + pr_debug("%s: %s %s %s\n", genpd->name, __func__, dev_driver_string(dev), dev_name(dev)); +} + +int rtk_pd_dev_pm_add_notifier(struct device *dev, struct notifier_block *nb) +{ + struct rtk_pd_instance *ins; + + if (IS_ERR_OR_NULL(dev->pm_domain)) + return -EINVAL; + + ins = genpd_to_rtk_pd_instance(pd_to_genpd(dev->pm_domain)); + if (ins->nb) + return -EEXIST; + + ins->nb = nb; + return raw_notifier_chain_register(&ins->power_notifiers, nb); +} +EXPORT_SYMBOL_GPL(rtk_pd_dev_pm_add_notifier); + +void rtk_pd_dev_pm_remove_notifier(struct device *dev) +{ + struct rtk_pd_instance *ins; + + if (IS_ERR_OR_NULL(dev->pm_domain)) + return; + + ins = genpd_to_rtk_pd_instance(pd_to_genpd(dev->pm_domain)); + if (!ins->nb) + return; + + raw_notifier_chain_unregister(&ins->power_notifiers, ins->nb); + ins->nb = NULL; +} +EXPORT_SYMBOL_GPL(rtk_pd_dev_pm_remove_notifier); + +int rtk_pd_init(struct rtk_pd_device *pd_dev, struct rtk_pd *pd) +{ + int st_sram, st_iso; + struct dev_power_governor *gov = rtk_pd_get_gov(pd); + char name[20]; + + pd->pd_dev = pd_dev; + mutex_init(&pd->lock); + + st_sram = sram_power_state(pd); + st_iso = iso_power_state(pd); + pr_info("%s: %s: default power state: sram=%d iso=%d\n", rtk_pd_name(pd), __func__, st_sram, st_iso); + + pd->pd_iso.pd.attach_dev = rtk_genpd_attach_dev; + pd->pd_iso.pd.detach_dev = rtk_genpd_detach_dev; + pd->pd_iso.pd.power_on = rtk_pd_iso_power_on; + pd->pd_iso.pd.power_off = rtk_pd_iso_power_off; + pm_genpd_init(&pd->pd_iso.pd, gov, !st_iso); + RAW_INIT_NOTIFIER_HEAD(&pd->pd_iso.power_notifiers); + + snprintf(name, sizeof(name), "sram_%s", rtk_pd_name(pd)); + pd->pd_sram.pd.name = kstrdup(name, GFP_KERNEL); + pd->pd_sram.pd.flags = pd->pd_iso.pd.flags; + pd->pd_sram.pd.attach_dev = rtk_genpd_attach_dev; + pd->pd_sram.pd.detach_dev = rtk_genpd_detach_dev; + pd->pd_sram.pd.power_on = rtk_pd_sram_power_on; + pd->pd_sram.pd.power_off = rtk_pd_sram_power_off; + pm_genpd_init(&pd->pd_sram.pd, gov, !st_sram); + RAW_INIT_NOTIFIER_HEAD(&pd->pd_sram.power_notifiers); + + pm_genpd_add_subdomain(&pd->pd_sram.pd, &pd->pd_iso.pd); + + list_add(&pd->list, &pd_dev->list); + return 0; +} +EXPORT_SYMBOL_GPL(rtk_pd_init); + +int rtk_pd_device_add_domains(struct rtk_pd_device *pd_dev, struct generic_pm_domain **domains, int num_domains) +{ + struct generic_pm_domain *domain; + int i; + int ret; + + pd_dev->domains = domains; + pd_dev->num_domains = num_domains; + + for (i = 0; i < num_domains; i++) { + domain = domains[i]; + if (!domain) + continue; + + ret = rtk_pd_init(pd_dev, genpd_to_rtk_pd(domain)); + WARN(ret, "rtk_pd_init() returns %d\n", ret); + } + return 0; +} + +void rtk_pd_device_show_power_state(struct rtk_pd_device *pd_dev) +{ + struct rtk_pd *p; + + dev_info(pd_dev->dev, "list power state:\n"); + list_for_each_entry(p, &pd_dev->list, list) { + dev_info(pd_dev->dev, " %s: sram=%d, iso=%d\n", rtk_pd_name(p), sram_power_state(p), iso_power_state(p)); + } +} + +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd.h b/drivers/soc/realtek/common/rtk_pd/rtk_pd.h new file mode 100644 index 000000000000..6f71c7fb3860 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ +#ifndef __SOC_REALTEK_PD_H +#define __SOC_REALTEK_PD_H + +#include +#include +#include +#include +#include + +struct rtk_pd_device { + struct regmap *regmap; + struct list_head list; + struct device *dev; + + struct generic_pm_domain **domains; + int num_domains; + struct genpd_onecell_data of_provider_data; +}; + +static inline int rtk_pd_device_reg_read(struct rtk_pd_device *pd_dev, unsigned int offset, unsigned int *val) +{ + return regmap_read(pd_dev->regmap, offset, val); +} + +static inline int rtk_pd_device_reg_write(struct rtk_pd_device *pd_dev, unsigned int offset, unsigned int val) +{ + return regmap_write(pd_dev->regmap, offset, val); +} + +static inline int rtk_pd_device_reg_update_bits(struct rtk_pd_device *pd_dev, + unsigned int offset, unsigned int mask, unsigned int val) +{ + return regmap_update_bits(pd_dev->regmap, offset, mask, val); +} + +extern const struct dev_pm_ops rtk_pd_generic_pm_ops; + +struct rtk_pd; + +struct rtk_pd_ops { + int (*power_on)(struct rtk_pd *pd); + int (*power_off)(struct rtk_pd *pd); + int (*power_state)(struct rtk_pd *pd); +}; + +struct rtk_pd { + struct generic_pm_domain pd; + struct rtk_pd_device *pd_dev; + const struct rtk_pd_ops *ops; + struct list_head list; +}; + +#define gen_pd_to_rtk_pd(_pd) container_of(_pd, struct rtk_pd, pd) + +#define rtk_pd_name(_pd) ((_pd)->pd.name) +int rtk_pd_init(struct rtk_pd_device *, struct rtk_pd *); +int rtk_pd_device_add_domains(struct rtk_pd_device *pd_dev, struct generic_pm_domain **domains, int num_domains); +void rtk_pd_device_show_power_state(struct rtk_pd_device *pd_dev); +int rtk_pd_setup_power_tree(struct rtk_pd_device *pd_dev, int map[][2], int num_maps); + +static inline int rtk_pd_power_on(struct rtk_pd *pd) +{ + if (pd->ops && pd->ops->power_on) + return pd->ops->power_on(pd); + return 0; +} + +static inline int rtk_pd_power_off(struct rtk_pd *pd) +{ + if (pd->ops && pd->ops->power_off) + return pd->ops->power_off(pd); + return 0; +} + +static inline int rtk_pd_power_state(struct rtk_pd *pd) +{ + if (pd->ops && pd->ops->power_state) + return pd->ops->power_state(pd); + return 1; +} + +#define INIT_RTK_PD(_name, _flags, _ops) \ +{ \ + .pd = { \ + .name = _name, \ + .flags = _flags, \ + }, \ + .ops = _ops, \ +} + +struct rtk_pd_sram { + struct rtk_pd core; + spinlock_t *lock; + unsigned int pwr_offset; + unsigned int pwr5_offset; + unsigned int last_sd_ch; + unsigned int val_on; + unsigned int val_off; +}; + +#define rtk_pd_to_sram(pd) container_of(pd, struct rtk_pd_sram, core) +extern const struct rtk_pd_ops rtk_pd_sram_ops; + +#define INIT_RTK_PD_SRAM_COMM(_name, _off, _off_pwr5, _ch, _val_on, _val_off, _lock) \ +{ \ + .core = INIT_RTK_PD(_name, 0, &rtk_pd_sram_ops), \ + .lock = _lock, \ + .pwr_offset = _off, \ + .pwr5_offset = _off_pwr5, \ + .last_sd_ch = _ch, \ + .val_on = _val_on, \ + .val_off = _val_off, \ +} + +#define INIT_RTK_PD_SRAM(_name, _off, _ch, _lock) \ + INIT_RTK_PD_SRAM_COMM(_name, _off, 0, _ch, 0, 1, _lock) +#define INIT_RTK_PD_SRAM_NCONT(_name, _off, _off_pwr5, _ch, _lock) \ + INIT_RTK_PD_SRAM_COMM(_name, _off, _off_pwr5, _ch, 0, 1, _lock) + +struct rtk_pd_simple { + struct rtk_pd core; + spinlock_t *lock; + unsigned int offset; + unsigned int mask; + unsigned int val_on; + unsigned int val_off; +}; + +#define rtk_pd_to_simple(pd) container_of(pd, struct rtk_pd_simple, core) +extern const struct rtk_pd_ops rtk_pd_simple_ops; + +#define INIT_RTK_PD_SIMPLE(_name, _off, _val_on, _val_off, _mask, _lock) \ +{ \ + .core = INIT_RTK_PD(_name, 0, &rtk_pd_simple_ops), \ + .offset = _off, \ + .mask = _mask, \ + .val_on = 0, \ + .val_off = _mask, \ + .lock = _lock, \ +} + +#define INIT_RTK_PD_ISO(_name, _off, _bit, _lock) \ + INIT_RTK_PD_SIMPLE(_name, _off, 0, BIT(_bit), BIT(_bit), _lock) + +#endif diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_pd_internal.h b/drivers/soc/realtek/common/rtk_pd/rtk_pd_internal.h new file mode 100644 index 000000000000..ce6410a7470b --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_pd_internal.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017-2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ +#ifndef __SOC_REALTEK_PD_INTERNAL_H +#define __SOC_REALTEK_PD_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtk_sram.h" +#include "rtk_iso.h" + +struct rtk_pd_device { + struct regmap *regmap; + struct list_head list; + struct device *dev; + + struct generic_pm_domain **domains; + int num_domains; + struct genpd_onecell_data of_provider_data; +}; + +static inline int rtk_pd_device_reg_read(struct rtk_pd_device *pd_dev, unsigned int offset, unsigned int *val) +{ + return regmap_read(pd_dev->regmap, offset, val); +} + +static inline int rtk_pd_device_reg_write(struct rtk_pd_device *pd_dev, unsigned int offset, unsigned int val) +{ + return regmap_write(pd_dev->regmap, offset, val); +} + +static inline int rtk_pd_device_reg_update_bits(struct rtk_pd_device *pd_dev, + unsigned int offset, unsigned int mask, unsigned int val) +{ + return regmap_update_bits(pd_dev->regmap, offset, mask, val); +} + +extern const struct dev_pm_ops rtk_pd_generic_pm_ops; +struct device; + +struct rtk_pd_instance { + struct generic_pm_domain pd; + struct raw_notifier_head power_notifiers; + struct notifier_block *nb; +}; + +#define genpd_to_rtk_pd_instance(_genpd) container_of(_genpd, struct rtk_pd_instance, pd) + +static inline void rtk_pd_instance_notify(struct rtk_pd_instance *ins, long event) +{ + raw_notifier_call_chain(&ins->power_notifiers, event, NULL); +} + +struct rtk_pd { + struct rtk_pd_instance pd_iso; + struct rtk_pd_instance pd_sram; + + struct list_head list; + struct rtk_pd_device *pd_dev; + struct device *dev; + struct mutex lock; + + struct rtk_sram_desc sram; + struct rtk_iso_desc iso; +}; + +static inline struct dev_power_governor *rtk_pd_get_gov(struct rtk_pd *pd) +{ + return NULL; +} + +#define rtk_pd_name(_pd) ((_pd)->pd_iso.pd.name) +#define rtk_pd_to_genpd(_pd) (&((_pd)->pd_iso.pd)) +#define genpd_to_rtk_pd(_genpd) container_of(_genpd, struct rtk_pd, pd_iso.pd) +#define rtk_pd_instance_to_rtk_pd(_n, _ins) container_of(_ins, struct rtk_pd, pd_ ## _n) + +int rtk_pd_init(struct rtk_pd_device *, struct rtk_pd *); +int rtk_pd_device_add_domains(struct rtk_pd_device *pd_dev, struct generic_pm_domain **domains, int num_domains); +void rtk_pd_device_show_power_state(struct rtk_pd_device *pd_dev); + +#define SET_PD_NAME(_name) \ + .pd_iso.pd.name = _name + +#define SET_RTK_PD_SRAM_CONF_COMM(_off, _off_pwr5, _ch, _on_val, _off_val) \ + .sram = { \ + SET_RTK_SRAM_CONF_COMM(_off, _off_pwr5, _ch, _on_val, _off_val) \ + } + +#define SET_RTK_PD_SRAM_CONF(_off, _ch) \ + SET_RTK_PD_SRAM_CONF_COMM(_off, 0, _ch, 0, 1) + +#define SET_RTK_PD_SRAM_CONF_PWR5(_off, _off_pwr5, _ch) \ + SET_RTK_PD_SRAM_CONF_COMM(_off, _off_pwr5, _ch, 0, 1) + +#define SET_RTK_PD_SRAM_CONF_MANUAL_MASK(_mask) \ + .sram.manual_mask = (_mask) + +#define SET_RTK_PD_ISO_CONF(_off, _bit) \ + .iso.iso_offset = _off, \ + .iso.iso_bit = _bit + +#define SET_RTK_PD_ISO_2_CONF(_off, _bit) \ + .iso.iso_2_offset = _off, \ + .iso.iso_2_bit = _bit + +#define SET_RTK_PD_SRAM_DELAY(_l2h, _h2l) \ + .sram.l2h_delay = (_l2h), \ + .sram.h2l_delay = (_h2l) + +#define SET_RTK_PD_SRAM_STD_DELAY(_off, _std) \ + .sram.pwr8_offset = (_off), \ + .sram.std_delay = (_std) + +#endif diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_sram.c b/drivers/soc/realtek/common/rtk_pd/rtk_sram.c new file mode 100644 index 000000000000..2b63605d4ee0 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_sram.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include "rtk_sram.h" + +MODULE_LICENSE("GPL v2"); + +#define SRAM_PWR0 0x0 +#define SRAM_PWR1 0x4 +#define SRAM_PWR2 0x8 +#define SRAM_PWR3 0xC +#define SRAM_PWR4 0x10 +#define SRAM_PWR5 0x14 +#define SRAM_PWR6 0x18 + +static inline unsigned int pwr5_offset(const struct rtk_sram_desc *desc) +{ + return desc->pwr5_offset ?: (desc->pwr_offset + SRAM_PWR5); +} + +static void sram_clear_ints(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + regmap_write(regmap, pwr5_offset(desc), 0x4); +} + +static void sram_setup_l2h_delay(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + if (!desc->l2h_delay) + return; + + regmap_write(regmap, desc->pwr_offset + SRAM_PWR0, desc->l2h_delay); +} + +static void sram_setup_h2l_delay(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + if (!desc->h2l_delay) + return; + + regmap_write(regmap, desc->pwr_offset + SRAM_PWR1, desc->h2l_delay); +} + +static void sram_setup_manual_mask(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + if (!desc->manual_mask) + return; + + regmap_write(regmap, desc->pwr_offset + SRAM_PWR3, desc->manual_mask); +} + +static void sram_setup_std_delay(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + if (!desc->pwr8_offset || !desc->std_delay) + return; + + regmap_write(regmap, desc->pwr8_offset, desc->std_delay); +} + +static void sram_setup_config(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + sram_setup_l2h_delay(regmap, desc); + + sram_setup_h2l_delay(regmap, desc); + + sram_setup_manual_mask(regmap, desc); + + sram_setup_std_delay(regmap, desc); +} + +static int sram_poll_ints(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + unsigned int pollval; + + return regmap_read_poll_timeout(regmap, pwr5_offset(desc), + pollval, pollval == 0x4, 0, 500); +} + +static int sram_set_power(struct regmap *regmap, const struct rtk_sram_desc *desc, int on_off) +{ + unsigned int pwr4 = desc->pwr_offset + SRAM_PWR4; + unsigned int val = on_off ? desc->val_on : desc->val_off; + unsigned int reg; + + sram_setup_config(regmap, desc); + + regmap_read(regmap, pwr4, ®); + if ((reg & 0xff) == val) + return 1; + val |= desc->last_sd_ch << 8; + + trace_rtk_pm_reg_set("sram", pwr4, val); + + regmap_write(regmap, pwr4, val); + + return sram_poll_ints(regmap, desc); +} + +int rtk_sram_power_on(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + int ret; + + ret = sram_set_power(regmap, desc, 1); + sram_clear_ints(regmap, desc); + return ret; +} + +int rtk_sram_power_off(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + int ret; + + ret = sram_set_power(regmap, desc, 0); + sram_clear_ints(regmap, desc); + return 0; +} + +int rtk_sram_power_state(struct regmap *regmap, const struct rtk_sram_desc *desc) +{ + unsigned int val; + unsigned int pwr4 = desc->pwr_offset + SRAM_PWR4; + + regmap_read(regmap, pwr4, &val); + return (val & 0xff) == desc->val_on; +} + diff --git a/drivers/soc/realtek/common/rtk_pd/rtk_sram.h b/drivers/soc/realtek/common/rtk_pd/rtk_sram.h new file mode 100644 index 000000000000..6e82f86ee98c --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pd/rtk_sram.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ +#ifndef __SOC_REALTEK_SRAM_H +#define __SOC_REALTEK_SRAM_H + +struct rtk_sram_desc { + unsigned int pwr_offset; + unsigned int pwr5_offset; + unsigned int pwr8_offset; + unsigned int last_sd_ch; + unsigned int val_on; + unsigned int val_off; + unsigned int l2h_delay; + unsigned int h2l_delay; + unsigned int manual_mask; + unsigned int std_delay; +}; + +#define SET_RTK_SRAM_CONF_COMM(_off, _off_pwr5, _ch, _on_val, _off_val) \ + .pwr_offset = _off, \ + .pwr5_offset = _off_pwr5, \ + .last_sd_ch = _ch, \ + .val_on = _on_val, \ + .val_off = _off_val + +#define SET_RTK_SRAM_CONF(_off, _ch) \ + SET_RTK_SRAM_CONF_COMM(_off, 0, _ch, 0, 1) + +#define SET_RTK_SRAM_CONF_PWR5(_off, _off_pwr5, _ch) \ + SET_RTK_SRAM_CONF_COMM(_off, _off_pwr5, _ch, 0, 1) + +#define SET_RTK_SRAM_CONF_MANUAL_MASK(_mask) \ + .manual_mask = (_mask) + +#define SET_RTK_SRAM_DELAY(_l2h, _h2l) \ + .l2h_delay = (_l2h), \ + .h2l_delay = (_h2l) + +#define SET_RTK_SRAM_STD_DELAY(_off, _std) \ + .pwr8_offset = (_off), \ + .std_delay = (_std) + +struct regmap; +int rtk_sram_power_on(struct regmap *regmap, const struct rtk_sram_desc *desc); +int rtk_sram_power_off(struct regmap *regmap, const struct rtk_sram_desc *desc); +int rtk_sram_power_state(struct regmap *regmap, const struct rtk_sram_desc *desc); + +#endif diff --git a/drivers/soc/realtek/common/rtk_pm.c b/drivers/soc/realtek/common/rtk_pm.c new file mode 100644 index 000000000000..c7b107292c6f --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pm.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek DHC SoC family power management driver + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void rtk_pm_adjust_dco(unsigned int tc_emb, unsigned int s_emb, struct pm_private *dev_pm) +{ + unsigned int tmp = 0; + + regmap_write(dev_pm->syscon_iso, PLL_ETN_OSC, 0); + + tmp = (tc_emb << 9) | (s_emb << 1); + regmap_write(dev_pm->syscon_iso, PLL_ETN_OSC, tmp); + tmp |= 0x1; + regmap_write(dev_pm->syscon_iso, PLL_ETN_OSC, tmp); + + regmap_read(dev_pm->syscon_iso, PLL_ETN_OSC, &tmp); + dev_info(dev_pm->dev, "PLL_ETN_OSC= %x\n", tmp); +} + +static unsigned int rtk_pm_get_dco_cnt(struct pm_private *dev_pm) +{ + unsigned int tmp = 0; + unsigned int retry_count = 0; + + regmap_write(dev_pm->syscon_iso, DCO0, 0); + regmap_write(dev_pm->syscon_iso, DCO1, 0); + + tmp = (OSC_COUNT_LIMIT << 10) | 0x1; + regmap_write(dev_pm->syscon_iso, DCO0, tmp); + + mdelay(1); + + regmap_read(dev_pm->syscon_iso, DCO1, &tmp); + while (!(0x1 & tmp)) { + if (retry_count == 500) { + tmp = 0x0; + goto error; + } + regmap_read(dev_pm->syscon_iso, DCO1, &tmp); + retry_count++; + } + + tmp = (tmp >> 13) & 0xfff; +error: + return tmp; +} + +static unsigned int rtk_pm_get_xtal_cnt(struct pm_private *dev_pm) +{ + unsigned int tmp = 0; + unsigned int retry_count = 0; + + regmap_write(dev_pm->syscon_iso, DCO0, 0); + regmap_write(dev_pm->syscon_iso, DCO1, 0); + + tmp = (OSC_COUNT_LIMIT << 10) | (0x1 << 1) | 0x1; + regmap_write(dev_pm->syscon_iso, DCO0, tmp); + + mdelay(1); + + regmap_read(dev_pm->syscon_iso, DCO1, &tmp); + while (!(0x1 & tmp)) { + if (retry_count == 500) { + tmp = 0x0; + goto error; + } + regmap_read(dev_pm->syscon_iso, DCO1, &tmp); + retry_count++; + } + + tmp = (tmp >> 1) & 0xfff; +error: + return tmp; +} + +static int rtk_pm_doc(struct pm_private *dev_pm) +{ + unsigned int tc_emb = 4; + unsigned int s_emb = 0x40; + unsigned int xtal_cnt = 0; + unsigned int dco_cnt = 0; + unsigned int tmp = 0; + unsigned int retry_count = 0; + unsigned int ret = 0; + + rtk_pm_adjust_dco(tc_emb, s_emb, dev_pm); + dco_cnt = rtk_pm_get_dco_cnt(dev_pm); + + while (1) { + if (retry_count == 500) { + dev_err(dev_pm->dev, "The calibration can not be found!\n"); + ret = -1; + goto error; + } + + tmp = 2700 * dco_cnt / OSC_COUNT_LIMIT ; + if ((tmp / 100) == 27) { + if ((tmp % 100) < 20) { + xtal_cnt = rtk_pm_get_xtal_cnt(dev_pm); + ret = 0; + break; + } + s_emb--; + } else if ((tmp / 100) > 27) + s_emb--; + else if ((tmp / 100) < 27) + s_emb++; + + dev_info(dev_pm->dev, "s_emb = %x\n", s_emb); + + rtk_pm_adjust_dco(tc_emb, s_emb, dev_pm); + dco_cnt = rtk_pm_get_dco_cnt(dev_pm); + retry_count++; + } + + dev_info(dev_pm->dev, "dco count latch = %x\n", dco_cnt); + dev_info(dev_pm->dev, "xtal count latch = %x\n", xtal_cnt); + + tmp = 2700 * dco_cnt / OSC_COUNT_LIMIT; + dev_info(dev_pm->dev, "dco freq = %u.%02uMHz", (tmp / 100), (tmp % 100)); + + tmp = 2700 * OSC_COUNT_LIMIT / xtal_cnt; + dev_info(dev_pm->dev, "xtal freq = %u.%02uMHz\n", (tmp / 100), (tmp % 100)); +error: + return ret; +} + +static void rtk_pm_get_gpio_param(struct pm_private *dev_pm) +{ + struct device *dev = dev_pm->dev; + struct pm_pcpu_param *pcpu_param = dev_pm->pcpu_param; + int num_row = 0; + int i = 0; + u32 gpio_act = 0; + u32 gpio_en = 0; + u32 gpio_num = 0; + char *pname = "wakeup-gpio-list"; + const u32 element = 3; + + num_row = of_property_count_u32_elems(dev->of_node, pname); + if (num_row < 0) { + dev_err(dev, "Not found '%s' property\n", pname); + return; + } + + num_row /= element; + + for (i = 0; i < num_row; i++) { + of_property_read_u32_index(dev->of_node, pname, i * element, + &gpio_num); + of_property_read_u32_index(dev->of_node, pname, i * element + 1, + &gpio_en); + of_property_read_u32_index(dev->of_node, pname, i * element + 2, + &gpio_act); + pcpu_param->wu_gpio_en[gpio_num] = (char) gpio_en; + pcpu_param->wu_gpio_act[gpio_num] = (char) gpio_act; + } +} + +static void rtk_pm_shutdown(struct platform_device *pdev) +{ + rtk_pm_set_pcpu_param(&pdev->dev); +}; + +static int rtk_pm_prepare(struct device *dev) +{ + struct pm_private *dev_pm = dev_get_drvdata(dev); + int ret = 0; + + dev_pm->wakeup_reason = MAX_EVENT; + dev_pm->device_param->data = &dev_pm->wakeup_reason; + + return ret; +} + +static int rtk_pm_suspend(struct device *dev) +{ + struct pm_private *dev_pm = dev_get_drvdata(dev); + int ret = 0; + + ret = rtk_pm_doc(dev_pm); + + dev_pm->wakeup_reason = MAX_EVENT; + regmap_read(dev_pm->syscon_iso, 0x640, &dev_pm->reboot_reasons); + + rtk_pm_set_pcpu_param(dev); + + return ret; +} + +static int rtk_pm_resume(struct device *dev) +{ + struct pm_private *dev_pm = dev_get_drvdata(dev); + struct pm_pcpu_param *pcpu_param = dev_pm->pcpu_param; + int ret = 0; + + pcpu_param->wakeup_source = htonl(pcpu_param->wakeup_source); + pcpu_param->timerout_val = htonl(pcpu_param->timerout_val); + + regmap_read(dev_pm->syscon_iso, 0x640, &dev_pm->wakeup_reason); + dev_pm->wakeup_reason = (dev_pm->wakeup_reason >> 16) & 0x00ff; + + regmap_write(dev_pm->syscon_iso, 0x640, dev_pm->reboot_reasons); + + dev_pm->device_param->data = &dev_pm->wakeup_reason; + dev_pm->suspend_context++; + + return ret; +} + +static int rtk_pm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *syscon_np; + struct pm_private *dev_pm; + struct pm_dev_param *dev_param; + struct pm_pcpu_param *pcpu_param; + const u32 *prop; + u32 timer_value = 0; + int ret = 0; + int size = 0; + unsigned int test = 0; + + rtk_pm_init_list(); + + dev_pm = devm_kzalloc(dev, sizeof(*dev_pm), GFP_KERNEL); + if (!dev_pm) { + ret = -ENOMEM; + goto error_mem; + } + + pcpu_param = dma_alloc_coherent(dev, sizeof(*pcpu_param), &dev_pm->pcpu_param_pa, GFP_KERNEL); + if (!pcpu_param) { + ret = -ENOMEM; + goto error_mem; + } + + dev_param = devm_kzalloc(dev, sizeof(*dev_param), GFP_KERNEL); + if (!dev_param) { + ret = -ENOMEM; + goto error_mem; + } + + dev_pm->pm_dbg = false; + dev_pm->dev = dev; + + dev_param->dev = dev; + dev_param->dev_type = PM; + + pcpu_param->wakeup_source = 0; + pcpu_param->timerout_val = 0; + + dev_pm->pcpu_param = pcpu_param; + dev_pm->device_param = dev_param; + + syscon_np = of_parse_phandle(dev->of_node, "syscon", 0); + if (IS_ERR_OR_NULL(syscon_np)) { + dev_err(dev, "Not found syscon property\n"); + ret = -ENODEV; + goto error_mem; + } + + dev_pm->syscon_iso = syscon_node_to_regmap(syscon_np); + if (IS_ERR_OR_NULL(dev_pm->syscon_iso)) { + dev_err(dev, "Cannot get parent's regmap\n"); + ret = PTR_ERR(dev_pm->syscon_iso); + goto error_syscon; + } + + prop = of_get_property(dev->of_node, "wakeup-flags", &size); + if (of_read_number(prop, 1)) + pcpu_param->wakeup_source = of_read_number(prop, 1); + else + dev_err(dev, "Not found wakeup-flags property\n"); + + prop = of_get_property(dev->of_node, "pm-dbg", &size); + if (of_read_number(prop, 1)) + dev_pm->pm_dbg = true; + else + dev_pm->pm_dbg = false; + + ret = of_property_read_u32(dev->of_node, "wakeup-timer", &timer_value); + if (ret) + dev_err(dev, "Not found wakeup-timer property\n"); + else + pcpu_param->timerout_val = timer_value; + + ret = rtk_pm_create_sysfs(); + if (ret) + dev_err(dev, "Cannot create sysfs\n"); + + regmap_read(dev_pm->syscon_iso, 0x640, &dev_pm->wakeup_reason); + test = (dev_pm->wakeup_reason >> 16) & 0x00ff; + if (test > MAX_EVENT || test < IR_EVENT) + dev_pm->wakeup_reason = MAX_EVENT; + else + dev_pm->wakeup_reason = test; + + dev_param->data = &dev_pm->wakeup_reason; + + rtk_pm_get_gpio_param(dev_pm); + rtk_pm_add_list(dev_param); + platform_set_drvdata(pdev, dev_pm); + +error_syscon: + of_node_put(syscon_np); + +error_mem: + return ret; +}; + +static int rtk_pm_remove(struct platform_device *pdev) +{ + int ret = 0; + + dev_info(&pdev->dev, "%s\n", __func__); + + return ret; +} + +static const struct dev_pm_ops rtk_pm_ops = { + .prepare = rtk_pm_prepare, + .suspend_noirq = rtk_pm_suspend, + .resume_noirq = rtk_pm_resume, +}; + +static struct of_device_id rtk_pm_ids[] = { + { .compatible = "realtek,rtd13xx_pm" }, + { .compatible = "realtek,rtd16xxb_pm" }, + { /* Sentinel */ }, +}; + +static struct platform_driver rtk_pm_driver = { + .probe = rtk_pm_probe, + .remove = rtk_pm_remove, + .shutdown = rtk_pm_shutdown, + .driver = { + .name = "realtek-pm", + .owner = THIS_MODULE, + .of_match_table = rtk_pm_ids, + .pm = &rtk_pm_ops, + }, +}; +module_platform_driver(rtk_pm_driver); + +MODULE_AUTHOR("James Tai "); +MODULE_DESCRIPTION("Realtek power management driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/realtek/common/rtk_pm_common.c b/drivers/soc/realtek/common/rtk_pm_common.c new file mode 100644 index 000000000000..933b37632700 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pm_common.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek DHC SoC family power management driver + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include + +#include + +static struct list_head rtk_pm_param_list; + +void rtk_pm_init_list(void) +{ + INIT_LIST_HEAD(&rtk_pm_param_list); +} +EXPORT_SYMBOL(rtk_pm_init_list); + +void rtk_pm_add_list(struct pm_dev_param *pm_node) +{ + list_add(&pm_node->list, &rtk_pm_param_list); +} +EXPORT_SYMBOL(rtk_pm_add_list); + +struct pm_dev_param *rtk_pm_get_param(unsigned int id) +{ + struct pm_dev_param *node; + + list_for_each_entry(node, &rtk_pm_param_list, list) { + if (node->dev_type == id) + break; + } + + return node; +} +EXPORT_SYMBOL(rtk_pm_get_param); + +void rtk_pm_set_pcpu_param(struct device *dev) +{ + struct pm_private *dev_pm = dev_get_drvdata(dev); + struct pm_pcpu_param *pcpu_param = dev_pm->pcpu_param; + struct arm_smccc_res res; + struct pm_dev_param *node; + struct ipc_shm_irda *irda = &pcpu_param->irda_info; + struct ipc_shm_cec *cec = &pcpu_param->cec_info; + + pcpu_param->wakeup_source = htonl(pcpu_param->wakeup_source); + pcpu_param->timerout_val = htonl(pcpu_param->timerout_val); + + list_for_each_entry(node, &rtk_pm_param_list, list) { + switch (node->dev_type) { + case LAN: + break; + case IRDA: + memcpy(irda, node->data, sizeof(*irda)); + break; + case GPIO: + break; + case ALARM_TIMER: + break; + case TIMER: + break; + case CEC: + memcpy(cec, node->data, sizeof(*cec)); + break; + case USB: + break; + default: + break; + } + } + + arm_smccc_smc(0x8400ff04, dev_pm->pcpu_param_pa, 0, 0, 0, 0, 0, 0, &res); +} +EXPORT_SYMBOL(rtk_pm_set_pcpu_param); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/realtek/common/rtk_pm_sysfs.c b/drivers/soc/realtek/common/rtk_pm_sysfs.c new file mode 100644 index 000000000000..7019d0f9fa8b --- /dev/null +++ b/drivers/soc/realtek/common/rtk_pm_sysfs.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * Realtek DHC SoC family power management + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +const char *const rtk_pm_event_states[MAX_EVENT + 1] = { + [LAN_EVENT] = "lan", + [IR_EVENT] = "irda", + [GPIO_EVENT] = "gpio", + [ALARM_EVENT] = "alarm", + [TIMER_EVENT] = "timer", + [CEC_EVENT] = "cec", + [USB_EVENT] = "usb", + [HIFI_EVENT] = "hifi", + [VTC_EVENT] = "vtc", + [PON_EVENT] = "pon", + [MAX_EVENT] = "invalid", +}; + +#define RTK_PM_ATTR(_name) \ +{ \ + .attr = {.name = #_name, .mode = 0644}, \ + .show = rtk_pm_##_name##_show, \ + .store = rtk_pm_##_name##_store, \ +} + +static enum rtk_wakeup_event rtk_pm_decode_states(const char *buf, size_t n) +{ + const char *const *s; + char *p; + int len = 0; + int i = 0; + + p = memchr(buf, '\n', n); + len = p ? p - buf : n; + + for (i = 0; i < MAX_EVENT; i++) { + s = &rtk_pm_event_states[i]; + if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) + return i; + } + + return MAX_EVENT; +} + +static ssize_t rtk_pm_wakeup_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int i = 0; + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + unsigned int n = 0; + + for (i = 0; i < MAX_EVENT; i++) { + if (dev_pm->pcpu_param->wakeup_source & BIT(i)) + n += sprintf(buf + n, " * "); + else + n += sprintf(buf + n, " "); + + n += sprintf(buf + n, "%s\n", rtk_pm_event_states[i]); + } + + n += sprintf(buf + n, "\n"); + + return n; +} + +static ssize_t rtk_pm_wakeup_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + enum rtk_wakeup_event wakeup = rtk_pm_decode_states(buf, count); + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + + if (wakeup < MAX_EVENT) { + dev_pm->pcpu_param->wakeup_source ^= BIT(wakeup); + return count; + } + + return -ENOMEM; +} + +static ssize_t rtk_pm_timer_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + + return sprintf(buf, " %d sec (reciprocal timer)\n", + dev_pm->pcpu_param->timerout_val); +} + +static ssize_t rtk_pm_timer_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + long val = 0; + int ret = kstrtol(buf, 10, &val); + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + + if (ret < 0) + return -ENOMEM; + + dev_pm->pcpu_param->timerout_val = val; + return count; +} + +static ssize_t rtk_pm_context_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + + return sprintf(buf, "%d\n", dev_pm->suspend_context); +} + +static ssize_t rtk_pm_context_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + long val; + int ret = kstrtol(buf, 10, &val); + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + + if (ret < 0) + return -ENOMEM; + + dev_pm->suspend_context = val; + return count; +} + +static ssize_t rtk_pm_reasons_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + + return sprintf(buf, "%s\n", rtk_pm_event_states[dev_pm->wakeup_reason]); +} + +static ssize_t rtk_pm_reasons_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t rtk_pm_gpio_en_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + int i = 0; + int n = 0; + + n += sprintf(buf + n, "EN | GPIO\n"); + n += sprintf(buf + n, "----+--------\n"); + + for (i = 0 ; i < GPIO_MAX_SIZE ; i++) { + if (dev_pm->pcpu_param->wu_gpio_en[i]) + n += sprintf(buf + n, " * | %d\n", i); + else + n += sprintf(buf + n, " | %d\n", i); + } + + n += sprintf(buf + n, "\n"); + + return n; +} + +static ssize_t rtk_pm_gpio_en_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t rtk_pm_gpio_act_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct pm_dev_param *pm_param = rtk_pm_get_param(PM); + struct pm_private *dev_pm = dev_get_drvdata(pm_param->dev); + int i = 0; + int n = 0; + + n += sprintf(buf + n, "ACT | GPIO\n"); + n += sprintf(buf + n, "----+--------\n"); + + for (i = 0 ; i < GPIO_MAX_SIZE ; i++) { + if (!dev_pm->pcpu_param->wu_gpio_en[i]) + n += sprintf(buf + n, " | %d\n", i); + else if (dev_pm->pcpu_param->wu_gpio_act[i]) + n += sprintf(buf + n, " H | %d\n", i); + else + n += sprintf(buf + n, " L | %d\n", i); + } + + n += sprintf(buf + n, "\n"); + + return n; +} + +static ssize_t rtk_pm_gpio_act_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static struct kobj_attribute rtk_pm_wakeup_attr = + RTK_PM_ATTR(wakeup); +static struct kobj_attribute rtk_pm_timer_attr = + RTK_PM_ATTR(timer); +static struct kobj_attribute rtk_pm_context_attr = + RTK_PM_ATTR(context); +static struct kobj_attribute rtk_pm_reasons_attr = + RTK_PM_ATTR(reasons); +static struct kobj_attribute rtk_pm_gpio_en_attr = + RTK_PM_ATTR(gpio_en); +static struct kobj_attribute rtk_pm_gpio_act_attr = + RTK_PM_ATTR(gpio_act); + +static struct attribute *rtk_pm_attrs[] = { + &rtk_pm_wakeup_attr.attr, + &rtk_pm_timer_attr.attr, + &rtk_pm_context_attr.attr, + &rtk_pm_reasons_attr.attr, + &rtk_pm_gpio_en_attr.attr, + &rtk_pm_gpio_act_attr.attr, + NULL, +}; + +static struct attribute_group rtk_pm_attr_group = { + .attrs = rtk_pm_attrs, +}; + +int rtk_pm_create_sysfs(void) +{ + int ret = 0; + struct kobject *rtk_pm_kobj; + + rtk_pm_kobj = kobject_create_and_add("suspend", kernel_kobj); + if (!rtk_pm_kobj) + return -ENOMEM; + + ret = sysfs_create_group(rtk_pm_kobj, &rtk_pm_attr_group); + if (ret) + kobject_put(rtk_pm_kobj); + + return ret; +} +EXPORT_SYMBOL(rtk_pm_create_sysfs); + +MODULE_AUTHOR("James Tai "); +MODULE_DESCRIPTION("Realtek suspend sysfs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/realtek/common/rtk_refclk.c b/drivers/soc/realtek/common/rtk_refclk.c new file mode 100644 index 000000000000..a1b10d962d5a --- /dev/null +++ b/drivers/soc/realtek/common/rtk_refclk.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIS_CLK90K_CTRL 0x0 +#define MIS_SCPU_CLK90K_LO 0x8 +#define MIS_SCPU_CLK90K_HI 0xC + +struct refclk_device { + void *base; + struct device *dev; +}; + +static struct platform_driver refclk_driver; + +static int refclk_reg_read(struct refclk_device *refclk, int offset, u32 *val) +{ + *val = readl(refclk->base + offset); + return 0; +} + +static int refclk_reg_write(struct refclk_device *refclk, int offset, u32 val) +{ + writel(val, refclk->base + offset); + return 0; +} + +/** + * of_refclk_get - lookup and obtain a refclk device. + * @np: device node to request + * @index: index of the refclk + * + * Returns the refclk device on success, and returns -EINVAL if failed to + * get the refclk, and returns -EPROBE_DERFER if refclk device is not ready. + */ +struct refclk_device *of_refclk_get(struct device_node *np, int index) +{ + struct refclk_device *refclk = ERR_PTR(-EINVAL); + struct device_node *refclk_np; + struct platform_device *pdev; + + refclk_np = of_parse_phandle(np, "realtek,refclk", index); + + if (!refclk_np) + return refclk; + + pdev = of_find_device_by_node(refclk_np); + of_node_put(refclk_np); + if (!pdev) + return refclk; + + refclk = platform_get_drvdata(pdev); + if (!refclk) + return ERR_PTR(-EPROBE_DEFER); + + get_device(&pdev->dev); + return refclk; +} +EXPORT_SYMBOL_GPL(of_refclk_get); + +struct platform_match_data { + struct device_driver *drv; + const char *name; +}; + +static int platform_match(struct device *dev, const void *d) +{ + const struct platform_match_data *data = d; + + return dev->driver == data->drv && !strcmp(dev_name(dev), data->name); +} + +/** + * refclk_get_by_name - lookup and obtain a refclk device by name + * name: device name + * + * Returns the refclk device on success, and returns -EINVAL if failed to + * get the refclk, and returns -EPROBE_DERFER if refclk device is not ready. + */ +struct refclk_device *refclk_get_by_name(const char *name) +{ + struct refclk_device *refclk; + struct platform_match_data data = { + .drv = &refclk_driver.driver, + .name = name, + }; + struct device *dev = NULL; + + dev = bus_find_device(&platform_bus_type, NULL, &data, platform_match); + if (!dev) + return ERR_PTR(-EINVAL); + + refclk = platform_get_drvdata(to_platform_device(dev)); + if (!refclk) + return ERR_PTR(-EPROBE_DEFER); + + get_device(dev); + return refclk; +} +EXPORT_SYMBOL_GPL(refclk_get_by_name); + +/** + * refclk_put - free the refclk device + * @refclk: refclk device + */ +void refclk_put(struct refclk_device *refclk) +{ + put_device(refclk->dev); +} +EXPORT_SYMBOL_GPL(refclk_put); + +static void refclk_set_enable(struct refclk_device *refclk, u32 val) +{ + refclk_reg_write(refclk, MIS_CLK90K_CTRL, val); +} + +static u32 refclk_get_enable(struct refclk_device *refclk) +{ + u32 val; + + refclk_reg_read(refclk, MIS_CLK90K_CTRL, &val); + return val; +} + +/** + * refclk_get_counter - get the counter value + * @refclk: refclk device + * + * Return the counter value of the refclk device. + */ +u64 refclk_get_counter(struct refclk_device *refclk) +{ + u32 lo; + u32 hi0, hi1; + + if (!refclk) + return 0; + if (WARN_ON(IS_ERR(refclk))) + return (u64)-EINVAL; + + refclk_reg_read(refclk, MIS_SCPU_CLK90K_HI, &hi0); + refclk_reg_read(refclk, MIS_SCPU_CLK90K_LO, &lo); + refclk_reg_read(refclk, MIS_SCPU_CLK90K_HI, &hi1); + if (hi0 != hi1) + refclk_reg_read(refclk, MIS_SCPU_CLK90K_LO, &lo); + + return ((u64)hi1 << 32) | lo; +} +EXPORT_SYMBOL_GPL(refclk_get_counter); + +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct refclk_device *refclk = dev_get_drvdata(dev); + int ret; + u32 val; + + ret = kstrtou32(buf, 10, &val); + if (ret) + return ret; + if (val) { + refclk_set_enable(refclk, 1); + } else { + refclk_set_enable(refclk, 0); + } + + return count; +} + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct refclk_device *refclk = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", refclk_get_enable(refclk)); +} +DEVICE_ATTR_RW(enable); + +static ssize_t counter_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct refclk_device *refclk = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%llu\n", refclk_get_counter(refclk)); +} +DEVICE_ATTR_RO(counter); + +static struct attribute *refclk_attrs[] = { + &dev_attr_counter.attr, + &dev_attr_enable.attr, + NULL +}; + +static struct attribute_group refclk_attr_group = { + .name = "refclk", + .attrs = refclk_attrs, +}; + +static int refclk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct refclk_device *refclk; + int ret; + + refclk = devm_kzalloc(dev, sizeof(*refclk), GFP_KERNEL); + if (!refclk) + return -ENOMEM; + refclk->dev = dev; + + refclk->base = of_iomap(np, 0); + if (!refclk->base) + return -ENOMEM; + + ret = sysfs_create_group(&dev->kobj, &refclk_attr_group); + if (ret) { + dev_err(dev, "failed to create sysfs group: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, refclk); + return 0; +} + +static int refclk_remove(struct platform_device *pdev) +{ + struct refclk_device *refclk = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + sysfs_remove_group(&pdev->dev.kobj, &refclk_attr_group); + iounmap(refclk->base); + return 0; +} + +static const struct of_device_id refclk_match[] = { + {.compatible = "realtek,refclk"}, + {} +}; +MODULE_DEVICE_TABLE(of, refclk_match); + +static struct platform_driver refclk_driver = { + .probe = refclk_probe, + .remove = refclk_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-refclk", + .of_match_table = of_match_ptr(refclk_match), + }, +}; +module_platform_driver(refclk_driver); + +MODULE_DESCRIPTION("Realtek Refclk driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-refclk"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/soc/realtek/common/rtk_sb2.c b/drivers/soc/realtek/common/rtk_sb2.c new file mode 100644 index 000000000000..17955f9ca8cc --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sb2.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtk_sb2.h" + +#define SB2_ICG_REG_MAX 4 + +struct sb2_icg_desc { + int offset; + int num_icg_reg; + unsigned int icg_val[SB2_ICG_REG_MAX]; + +}; + +static void sb2_enable_icg(struct sb2_device *sb2_dev) +{ + const struct sb2_icg_desc *desc = sb2_dev->icg_desc; + + regmap_bulk_write(sb2_dev->regmap, desc->offset, desc->icg_val, + desc->num_icg_reg); +} + +static const struct sb2_icg_desc sb2_icg_desc_rtd1295 = { + .offset = 0x308, + .num_icg_reg = 3, + .icg_val = { 0xffffffff, 0x0000ffff, 0x00000007 }, +}; + +static const struct sb2_icg_desc sb2_icg_desc_rtd1395 = { + .offset = 0x308, + .num_icg_reg = 3, + .icg_val = { 0xffffffff, 0x000fe7ff, 0x03ff003f }, +}; + +static const struct sb2_icg_desc sb2_icg_desc_rtd1619 = { + .offset = 0x308, + .num_icg_reg = 3, + .icg_val = { 0xffffffff, 0xffffffff, 0xf73f007f }, +}; + +static const struct sb2_icg_desc sb2_icg_desc_rtd1319 = { + .offset = 0xff0, + .num_icg_reg = 4, + .icg_val = { 0xffffffff, 0xffffffff, 0x00000007, 0xff7f00ff }, +}; + + +static int rtk_sb2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct sb2_device *sb2_dev; + int ret; + + const struct sb2_icg_desc *desc; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + sb2_dev = devm_kzalloc(dev, sizeof(*sb2_dev), GFP_KERNEL); + if (!sb2_dev) + return -ENOMEM; + + sb2_dev->regmap = syscon_node_to_regmap(np); + if (IS_ERR(sb2_dev->regmap)) { + ret = PTR_ERR(sb2_dev->regmap); + dev_err(dev, "failed to get syscon: %d\n", ret); + return ret; + } + + sb2_dev->icg_desc = desc; + + platform_set_drvdata(pdev, sb2_dev); + sb2_enable_icg(sb2_dev); + return 0; +} + +static int rtk_sb2_resume(struct device *dev) +{ + struct sb2_device *sb2_dev = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + sb2_enable_icg(sb2_dev); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops rtk_sb2_pm_ops = { + .resume = rtk_sb2_resume, +}; + +static const struct of_device_id rtk_sb2_match[] = { + { + .compatible = "realtek,rtd1295-sysbrg2", + .data = &sb2_icg_desc_rtd1295, + }, + { + .compatible = "realtek,rtd1395-sysbrg2", + .data = &sb2_icg_desc_rtd1395, + }, + { + .compatible = "realtek,rtd1619-sysbrg2", + .data = &sb2_icg_desc_rtd1619, + }, + { + .compatible = "realtek,rtd1319-sysbrg2", + .data = &sb2_icg_desc_rtd1319, + }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_sb2_match); + +static struct platform_driver rtk_sb2_driver = { + .probe = rtk_sb2_probe, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-sb2", + .pm = &rtk_sb2_pm_ops, + .of_match_table = of_match_ptr(rtk_sb2_match), + }, +}; + +static int __init rtk_sb2_init(void) +{ + return platform_driver_register(&rtk_sb2_driver); +} +subsys_initcall_sync(rtk_sb2_init); + +MODULE_DESCRIPTION("Realtek SB2 driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-sb2"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/soc/realtek/common/rtk_sb2.h b/drivers/soc/realtek/common/rtk_sb2.h new file mode 100644 index 000000000000..be26c735b709 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sb2.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only + /* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ +#ifndef __SOC_REALTEK_SB2_H +#define __SOC_REALTEK_SB2_H + +#include +#include +#include +#include +#include + +struct sb2_icg_desc; + +struct sb2_device { + struct regmap *regmap; + const struct sb2_icg_desc *icg_desc; +}; + +/* common data */ +struct sb2_common_data { + struct device *dev; + void *base; + int irq; +}; + +static inline int sb2_check_perm(struct sb2_common_data *data) +{ + struct device *dev = data->dev; + struct device_node *np = dev->of_node; + struct nvmem_cell *cell; + unsigned char *buf; + size_t buf_size; + unsigned char val = 0; + + cell = of_nvmem_cell_get(np, "secure_en"); + if (!IS_ERR(cell)) { + buf = nvmem_cell_read(cell, &buf_size); + nvmem_cell_put(cell); + if (!IS_ERR(buf)) { + val = buf[0]; + kfree(buf); + } + + if (val == 0 || val == 1) + return 0; + + return -EACCES; + } + return 0; +} + +static inline +void sb2_reg_read(struct sb2_common_data *data, int offset, unsigned int *val) +{ + *val = readl(data->base + offset); +} + +static inline +void sb2_reg_write(struct sb2_common_data *data, int offset, unsigned int val) +{ + writel(val, data->base + offset); +} + +#endif diff --git a/drivers/soc/realtek/common/rtk_sb2_dbg.c b/drivers/soc/realtek/common/rtk_sb2_dbg.c new file mode 100644 index 000000000000..9717ec0f602e --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sb2_dbg.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "rtk_sb2.h" + +#define SB2_DBG_START(i) (0x0 + (i) * 4) +#define SB2_DBG_END(i) (0x20 + (i) * 4) +#define SB2_DBG_CTRL(i) (0x40 + (i) * 4) +#define SB2_DBG_ADDR_ACPU (0x60) +#define SB2_DBG_ADDR_PCPU (0x64) +#define SB2_DBG_ADDR_SCPU (0x68) +#define SB2_DBG_ADDR_VCPU (0x6C) +#define SB2_DBG_ADDR1 (0x70) +#define SB2_DBG_INT (0x88) + +#define SB2_DBG_CTRL_WRITE_EN7 0x00008000 +#define SB2_DBG_CTRL_DBG_VCPU_CHK_EN 0x00004000 +#define SB2_DBG_CTRL_WRITE_EN6 0x00002000 +#define SB2_DBG_CTRL_DBG_ACPU_CHK_EN 0x00001000 +#define SB2_DBG_CTRL_WRITE_EN5 0x00000800 +#define SB2_DBG_CTRL_DBG_PCPU_CHK_EN 0x00000400 +#define SB2_DBG_CTRL_WRITE_EN4 0x00000200 +#define SB2_DBG_CTRL_DBG_SCPU_CHK_EN 0x00000100 +#define SB2_DBG_CTRL_WRITE_EN3 0x00000080 +#define SB2_DBG_CTRL_DBG_WR_CHK 0x00000060 +#define SB2_DBG_CTRL_WRITE_EN2 0x00000010 +#define SB2_DBG_CTRL_DBG_ID_CHK 0x0000000C +#define SB2_DBG_CTRL_WRITE_EN1 0x00000002 +#define SB2_DBG_CTRL_DBG_EN 0x00000001 + +#define SB2_DBG_CTRL_DISABLE \ + (SB2_DBG_CTRL_WRITE_EN6 | \ + SB2_DBG_CTRL_WRITE_EN4 | \ + SB2_DBG_CTRL_WRITE_EN1) +#define SB2_DBG_CTRL_ENABLE_ACPU \ + (SB2_DBG_CTRL_WRITE_EN6 | SB2_DBG_CTRL_DBG_ACPU_CHK_EN | \ + SB2_DBG_CTRL_WRITE_EN4 | \ + SB2_DBG_CTRL_WRITE_EN1 | SB2_DBG_CTRL_DBG_EN) +#define SB2_DBG_CTRL_ENABLE_SCPU \ + (SB2_DBG_CTRL_WRITE_EN6 | \ + SB2_DBG_CTRL_WRITE_EN4 | SB2_DBG_CTRL_DBG_SCPU_CHK_EN | \ + SB2_DBG_CTRL_WRITE_EN1 | SB2_DBG_CTRL_DBG_EN) + +#define SB2_DBG_ADDR1_VCPU_DBG_WRITE 0x00000200 +#define SB2_DBG_ADDR1_VCPU_DBG_DACC 0x00000100 +#define SB2_DBG_ADDR1_PCPU_DBG_WRITE 0x00000080 +#define SB2_DBG_ADDR1_PCPU_DBG_DACC 0x00000040 +#define SB2_DBG_ADDR1_ACPU_DBG_WRITE 0x00000020 +#define SB2_DBG_ADDR1_ACPU_DBG_DACC 0x00000010 +#define SB2_DBG_ADDR1_SCPU_DBG_WRITE 0x00000008 +#define SB2_DBG_ADDR1_SCPU_DBG_DACC 0x00000004 + +#define SB2_DBG_INT_VCPU_INT 0x00010000 +#define SB2_DBG_INT_VCPU_INT_EN 0x00008000 +#define SB2_DBG_INT_VCPU_NEG_INT 0x00004000 +#define SB2_DBG_INT_VCPU_NEG_INT_EN 0x00002000 +#define SB2_DBG_INT_ACPU_INT 0x00001000 +#define SB2_DBG_INT_PCPU_INT 0x00000800 +#define SB2_DBG_INT_SCPU_INT 0x00000400 +#define SB2_DBG_INT_ACPU_INT_EN 0x00000200 +#define SB2_DBG_INT_PCPU_INT_EN 0x00000100 +#define SB2_DBG_INT_SCPU_INT_EN 0x00000080 +#define SB2_DBG_INT_ACPU_NEG_INT 0x00000040 +#define SB2_DBG_INT_PCPU_NEG_INT 0x00000020 +#define SB2_DBG_INT_SCPU_NEG_INT 0x00000010 +#define SB2_DBG_INT_ACPU_NEG_INT_EN 0x00000008 +#define SB2_DBG_INT_PCPU_NEG_INT_EN 0x00000004 +#define SB2_DBG_INT_SCPU_NEG_INT_EN 0x00000002 +#define SB2_DBG_INT_WRITE_DATA 0x00000001 +#define SB2_DBG_INT_EN_DEFAULT \ + (SB2_DBG_INT_SCPU_INT_EN | SB2_DBG_INT_ACPU_INT_EN | \ + SB2_DBG_INT_WRITE_DATA) +#define SB2_DBG_INT_INT_STATUS \ + (SB2_DBG_INT_SCPU_INT | SB2_DBG_INT_PCPU_INT | \ + SB2_DBG_INT_ACPU_INT | SB2_DBG_INT_VCPU_INT) + +static struct sb2_common_data *dbg_data; + +int sb2_dbg_ready(void) +{ + return dbg_data != NULL; +} +EXPORT_SYMBOL_GPL(sb2_dbg_ready); + +int sb2_dbg_disable(int i) +{ + struct sb2_common_data *sb2 = dbg_data; + if (!sb2_dbg_ready()) + return -ENODEV; + + sb2_reg_write(sb2, SB2_DBG_CTRL(i), SB2_DBG_CTRL_DISABLE); + return 0; +} +EXPORT_SYMBOL(sb2_dbg_disable); + +static int __sb2_dbg_setup(int i, u32 start, u32 end, u32 ctrl) +{ + struct sb2_common_data *sb2 = dbg_data; + if (!sb2_dbg_ready()) + return -ENODEV; + + /* disable this set first */ + sb2_dbg_disable(i); + + pr_info("%s: dbg%d addr %08x-%08x flag %08x\n", __func__, + i, start, end, ctrl); + sb2_reg_write(sb2, SB2_DBG_START(i), start); + sb2_reg_write(sb2, SB2_DBG_END(i), end); + sb2_reg_write(sb2, SB2_DBG_CTRL(i), ctrl); + return 0; +} + +int sb2_dbg_monitor_scpu(int i, u32 start, u32 end, u32 d_i, u32 r_w) +{ + unsigned int ctrl = SB2_DBG_CTRL_ENABLE_SCPU | + SB2_DBG_CTRL_WRITE_EN3 | r_w | + SB2_DBG_CTRL_WRITE_EN2 | d_i; + + return __sb2_dbg_setup(i, start, end, ctrl); +} +EXPORT_SYMBOL(sb2_dbg_monitor_scpu); + +int sb2_dbg_monitor_acpu(int i, u32 start, u32 end, u32 d_i, u32 r_w) +{ + unsigned int ctrl = SB2_DBG_CTRL_ENABLE_ACPU | + SB2_DBG_CTRL_WRITE_EN3 | r_w | + SB2_DBG_CTRL_WRITE_EN2 | d_i; + + return __sb2_dbg_setup(i, start, end, ctrl); +} +EXPORT_SYMBOL(sb2_dbg_monitor_acpu); + + +static void sb2_dbg_handle_event(struct sb2_dbg_event_data *evd) +{ + pr_err("RAW_STATUS=%08x, SRC=%d, ADDR=%08x, RW=%d, DI=%d\n", + evd->raw_ints, evd->source, evd->addr, evd->rw, evd->di); +} + +static irqreturn_t sb2_dbg_int_handler(int irq, void *id) +{ + struct platform_device *pdev = id; + struct sb2_common_data *sb2 = platform_get_drvdata(pdev); + u32 offset = 0; + u32 acc_shift = 0; + struct sb2_dbg_event_data evd = { 0 }; + u32 val; + u32 ints; + + sb2_reg_read(sb2, SB2_DBG_INT, &ints); + if (!(ints & SB2_DBG_INT_INT_STATUS)) + return IRQ_NONE; + + /* clear ints */ + sb2_reg_write(sb2, SB2_DBG_INT, SB2_DBG_INT_EN_DEFAULT); + + if (ints & SB2_DBG_INT_SCPU_INT) { + evd.source = SB2_DBG_SOURCE_SCPU; + offset = SB2_DBG_ADDR_SCPU; + acc_shift = 0; + } else if (ints & SB2_DBG_INT_ACPU_INT) { + evd.source = SB2_DBG_SOURCE_ACPU; + offset = SB2_DBG_ADDR_ACPU; + acc_shift = 2; + } else if (ints & SB2_DBG_INT_PCPU_INT) { + evd.source = SB2_DBG_SOURCE_PCPU; + offset = SB2_DBG_ADDR_PCPU; + acc_shift = 4; + } else if (ints & SB2_DBG_INT_VCPU_INT) { + evd.source = SB2_DBG_SOURCE_VCPU; + offset = SB2_DBG_ADDR_VCPU; + acc_shift = 8; + } + + evd.raw_ints = ints; + sb2_reg_read(sb2, offset, &evd.addr); + sb2_reg_read(sb2, SB2_DBG_ADDR1, &val); + val >>= acc_shift; + evd.rw = (val & 0x2) ? SB2_DBG_ACCESS_WRITE : SB2_DBG_ACCESS_READ; + evd.di = (val & 0x1) ? SB2_DBG_ACCESS_DATA : SB2_DBG_ACCESS_INST; + + sb2_dbg_handle_event(&evd); + + return IRQ_HANDLED; +} + +static void sb2_dbg_enable_interrupt(struct sb2_common_data *sb2) +{ + sb2_reg_write(sb2, SB2_DBG_INT, SB2_DBG_INT_EN_DEFAULT); +} + +static void sb2_dbg_disable_interrupt(struct sb2_common_data *sb2) +{ + sb2_reg_write(sb2, SB2_DBG_INT, 0); +} + +static int sb2_dbg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sb2_common_data *sb2; + struct device_node *np = dev->of_node; + struct resource res; + int ret; + + sb2 = devm_kzalloc(dev, sizeof(*sb2), GFP_KERNEL); + if (!sb2) + return -ENOMEM; + sb2->dev = dev; + + if (sb2_check_perm(sb2) != 0) { + dev_err(dev, "no permission\n"); + return -ENODEV; + } + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + sb2->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!sb2->base) + return -ENOMEM; + + sb2->irq = irq_of_parse_and_map(np, 0); + if (!sb2->irq) { + dev_err(dev, "failed to parse irq: %d\n", sb2->irq); + return -ENXIO; + } + + ret = devm_request_irq(dev, sb2->irq, sb2_dbg_int_handler, IRQF_SHARED, + dev_name(dev), pdev); + if (ret) { + dev_err(dev, "failed to request irq: %d\n", ret); + return -ENXIO; + } + + dbg_data = sb2; + platform_set_drvdata(pdev, sb2); + sb2_dbg_enable_interrupt(sb2); + return 0; +} + +static int sb2_dbg_remove(struct platform_device *pdev) +{ + struct sb2_common_data *sb2 = platform_get_drvdata(pdev); + + sb2_dbg_disable_interrupt(sb2); + platform_set_drvdata(pdev, NULL); + dbg_data = NULL; + return 0; +} + +static int sb2_dbg_suspend(struct device *dev) +{ + struct sb2_common_data *sb2 = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + sb2_dbg_disable_interrupt(sb2); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static int sb2_dbg_resume(struct device *dev) +{ + struct sb2_common_data *sb2 = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + sb2_dbg_enable_interrupt(sb2); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static struct dev_pm_ops sb2_dbg_pm_ops = { + .suspend_noirq = sb2_dbg_suspend, + .resume_noirq = sb2_dbg_resume, +}; + +static const struct of_device_id sb2_dbg_match[] = { + {.compatible = "realtek,sysbrg2-dbg"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sb2_dbg_match); + +static struct platform_driver sb2_dbg_driver = { + .probe = sb2_dbg_probe, + .remove = sb2_dbg_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-sb2-dbg", + .pm = &sb2_dbg_pm_ops, + .of_match_table = of_match_ptr(sb2_dbg_match), + }, +}; + +static void __exit sb2_dbg_exit(void) +{ + platform_driver_unregister(&sb2_dbg_driver); +} +module_exit(sb2_dbg_exit); + +static int __init sb2_dbg_init(void) +{ + return platform_driver_register(&sb2_dbg_driver); +} +subsys_initcall_sync(sb2_dbg_init); + +MODULE_DESCRIPTION("Realtek SB2 DBG driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-sb2-dbg"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/soc/realtek/common/rtk_sb2_inv.c b/drivers/soc/realtek/common/rtk_sb2_inv.c new file mode 100644 index 000000000000..cd39b3bdf9aa --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sb2_inv.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include "rtk_sb2.h" + +#define SB2_INV_INTEN 0x0 +#define SB2_INV_INTSTAT 0x4 +#define SB2_INV_ADDR 0x8 +#define SB2_DEBUG_REG 0xC + +#define SB2_INV_INTEN_VCIVAIRQ_EN 0x00000400 +#define SB2_INV_INTEN_PCIVAIRQ2_EN 0x00000100 +#define SB2_INV_INTEN_SWCIVAIRQ_EN 0x00000040 +#define SB2_INV_INTEN_ACIVAIRQ_EN 0x00000008 +#define SB2_INV_INTEN_PCIVAIRQ_EN 0x00000004 +#define SB2_INV_INTEN_SCIVAIRQ_EN 0x00000002 +#define SB2_INV_INTEN_WRITE_DATA 0x00000001 +#define SB2_INV_INTEN_CLEAR_DATA 0x00000000 +#define SB2_INV_INTEN_ENABLE_DEFAULT_CPUS \ + (SB2_INV_INTEN_SWCIVAIRQ_EN | SB2_INV_INTEN_SCIVAIRQ_EN | \ + SB2_INV_INTEN_PCIVAIRQ_EN | SB2_INV_INTEN_PCIVAIRQ2_EN | \ + SB2_INV_INTEN_WRITE_DATA) + +#define SB2_INV_INTSTAT_VCIVA_INT 0x00000040 +#define SB2_INV_INTSTAT_PCIVA2_INT 0x00000020 +#define SB2_INV_INTSTAT_SWCIVA_INT 0x00000010 +#define SB2_INV_INTSTAT_ACIVA_INT 0x00000008 +#define SB2_INV_INTSTAT_PCIVA_INT 0x00000004 +#define SB2_INV_INTSTAT_SCIVA_INT 0x00000002 +#define SB2_INV_INTSTAT_WRITE_DATA 0x00000001 +#define SB2_INV_INTSTAT_CLEAR_DATA 0x00000000 + +static const char *inv_cpu_str[] = { + [SB2_INV_UNKNOWN] = "Unknown CPU", + [SB2_INV_SCPU] = "SCPU", + [SB2_INV_PCPU] = "PCPU", + [SB2_INV_ACPU] = "ACPU", + [SB2_INV_SCPU_SWC] = "SCPU security world", + [SB2_INV_PCPU_2] = "PCPU_2", + [SB2_INV_VCPU] = "VCPU", +}; + +static const char *get_cpu_id(int id) +{ + if (id > SB2_INV_VCPU) + id = 0; + return inv_cpu_str[id]; +} + +static void sb2_inv_print_inv_event(struct sb2_inv_event_data *d) +{ + pr_err("sb2 get int 0x%08x from SB2_INV_INTSTAT\n", d->raw_ints); + pr_err("\033[0;31mInvalid access issued by %s\033[m\n", get_cpu_id(d->inv_cpu)); + pr_err("\033[0;31mInvalid address is 0x%08x\033[m\n", d->addr); + pr_err("Timeout threshold(0x%08x)\n", d->timeout_th); +} + +static irqreturn_t sb2_inv_int_handler(int irq, void *id) +{ + struct platform_device *pdev = id; + struct sb2_common_data *sb2 = platform_get_drvdata(pdev); + u32 ints; + + sb2_reg_read(sb2, SB2_INV_INTSTAT, &ints); + if (ints) { + struct sb2_inv_event_data d; + + /* clear ints */ + sb2_reg_write(sb2, SB2_INV_INTSTAT, 0xfffffffe); + + d.raw_ints = ints; + sb2_reg_read(sb2, SB2_INV_ADDR, &d.addr); + sb2_reg_read(sb2, SB2_DEBUG_REG, &d.timeout_th); + d.inv_cpu = ffs(ints) - 1; + sb2_inv_print_inv_event(&d); + + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void sb2_inv_enable_inv_int(struct sb2_common_data *sb2) +{ + sb2_reg_write(sb2, SB2_INV_INTSTAT, 0xfffffffe); + sb2_reg_write(sb2, SB2_INV_INTEN, SB2_INV_INTEN_ENABLE_DEFAULT_CPUS); +} + +static int sb2_inv_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sb2_common_data *sb2; + struct device_node *np = dev->of_node; + struct resource res; + int ret; + + sb2 = devm_kzalloc(dev, sizeof(*sb2), GFP_KERNEL); + if (!sb2) + return -ENOMEM; + sb2->dev = dev; + + if (sb2_check_perm(sb2) != 0) { + dev_err(dev, "no permission\n"); + return -ENODEV; + } + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + sb2->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!sb2->base) + return -ENOMEM; + + sb2->irq = irq_of_parse_and_map(np, 0); + if (!sb2->irq) { + dev_err(dev, "failed to parse irq: %d\n", sb2->irq); + return -ENXIO; + } + + ret = devm_request_irq(dev, sb2->irq, sb2_inv_int_handler, IRQF_SHARED, + dev_name(dev), pdev); + if (ret) { + dev_err(dev, "failed to request irq: %d\n", ret); + return -ENXIO; + } + + platform_set_drvdata(pdev, sb2); + sb2_inv_enable_inv_int(sb2); + return 0; +} + +static int sb2_inv_resume(struct device *dev) +{ + struct sb2_common_data *sb2 = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + sb2_inv_enable_inv_int(sb2); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static struct dev_pm_ops sb2_inv_pm_ops = { + .resume_noirq = sb2_inv_resume, +}; + +static const struct of_device_id sb2_inv_match[] = { + {.compatible = "realtek,sysbrg2-inv"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sb2_inv_match); + +static struct platform_driver sb2_inv_driver = { + .probe = sb2_inv_probe, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-sb2-inv", + .pm = &sb2_inv_pm_ops, + .of_match_table = of_match_ptr(sb2_inv_match), + }, +}; + +static int __init rtk_sb2_init(void) +{ + return platform_driver_register(&sb2_inv_driver); +} +subsys_initcall_sync(rtk_sb2_init); + +MODULE_DESCRIPTION("Realtek SB2 Invaild Access driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-sb2-inv"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/soc/realtek/common/rtk_sb2_sem.c b/drivers/soc/realtek/common/rtk_sb2_sem.c new file mode 100644 index 000000000000..22caf31ab17d --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sb2_sem.c @@ -0,0 +1,148 @@ +/* + * rtk_sb2_sem.c - Realtek SB2 HW semaphore API + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Copyright (C) 2017 Cheng-Yu Lee + * + * 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 + + +#define SB2_SEM_TRYLOCK_MAX 1024 +#define SB2_SEM_RETRY_MAX 10 + +struct sb2_sem { + int id; + struct list_head list; + struct device_node *np; + void __iomem *reg; +}; + +int sb2_sem_try_lock(struct sb2_sem *sem, unsigned int flags) +{ + unsigned int val; + + if (IS_ERR_OR_NULL(sem)) + return -EINVAL; + + val = readl(sem->reg); + return val; + +} + +void sb2_sem_lock(struct sb2_sem *sem, unsigned int flags) +{ + int i; + unsigned int val; + int cnt = 0; + + if (IS_ERR_OR_NULL(sem)) + return; + +retry: + for (i = 0; i < SB2_SEM_TRYLOCK_MAX; i++) { + val = sb2_sem_try_lock(sem, flags); + if (val) + return; + } + + if (flags & SB2_SEM_TIMEOUT_INFINITY) + goto retry; + + if (!(flags & SB2_SEM_NO_WARNING)) + pr_warn("sb2-sem: trylock fail\n"); + cnt++; + if (cnt < SB2_SEM_RETRY_MAX) + goto retry; + + if (!(flags & SB2_SEM_NO_WARNING)) + pr_warn("sb2-sem: ignore lock\n"); +} + +void sb2_sem_unlock(struct sb2_sem *sem) +{ + if (IS_ERR_OR_NULL(sem)) + return; + + writel(0, sem->reg); +} + +static LIST_HEAD(sb2_list); +static DEFINE_SPINLOCK(sb2_list_lock); + +struct sb2_sem *sb2_sem_get(unsigned int index) +{ + struct sb2_sem *sb2 = ERR_PTR(-EINVAL), *p; + + spin_lock(&sb2_list_lock); + list_for_each_entry(p, &sb2_list, list) + if (!index--) { + sb2 = p; + break; + } + spin_unlock(&sb2_list_lock); + + return sb2; +} +static struct sb2_sem *create_sb2_sem(struct device_node *np) +{ + struct sb2_sem *sb2; + + sb2 = kzalloc(sizeof(*sb2), GFP_KERNEL); + if (!sb2) + return ERR_PTR(-ENOMEM); + + sb2->np = np; + sb2->reg = of_iomap(np, 0); + + spin_lock(&sb2_list_lock); + list_add_tail(&sb2->list, &sb2_list); + spin_unlock(&sb2_list_lock); + + return sb2; +} + +struct sb2_sem *sb2_sem_node_to_lock(struct device_node *np) +{ + struct sb2_sem *sb2 = NULL, *p; + + spin_lock(&sb2_list_lock); + list_for_each_entry(p, &sb2_list, list) + if (p->np == np) { + sb2 = p; + break; + } + spin_unlock(&sb2_list_lock); + + if (!sb2) + sb2 = create_sb2_sem(np); + + return sb2; +} + +static __init int init_sb2_sem(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "realtek,sb2-sem") { + sb2_sem_node_to_lock(np); + } + return 0; +} +early_initcall(init_sb2_sem); + diff --git a/drivers/soc/realtek/common/rtk_sc_wrap.c b/drivers/soc/realtek/common/rtk_sc_wrap.c new file mode 100644 index 000000000000..0e659ef7151a --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sc_wrap.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include + +#define SCW_CTRL 0x000 +#define SCW_CTRL1 0x024 +#define SC_ACP_CRT_CTRL 0x030 +#define SC_CRT_CTRL 0x100 +#define SC_DUMMY_2 0x608 + +struct sc_wrap_data; + +struct sc_wrap_ops { + void (*setup_icg)(struct sc_wrap_data *data); + void (*setup_pmu)(struct sc_wrap_data *data); +}; + +struct sc_wrap_data { + struct device *dev; + void *base; + const struct sc_wrap_ops *ops; +}; + +static void rtd1319_sc_wrap_setup_icg(struct sc_wrap_data *data) +{ + uint32_t val; + + val = readl(data->base + SCW_CTRL); + val |= 0xff3c0000; + writel(val, data->base + SCW_CTRL); + + val = readl(data->base + SC_ACP_CRT_CTRL); + val |= 0x10000000; + writel(val, data->base + SC_ACP_CRT_CTRL); + + val = readl(data->base + SC_CRT_CTRL); + val |= 0xc0000000; + writel(val, data->base + SC_CRT_CTRL); +} + +static const struct sc_wrap_ops rtd1319_sc_wrap_ops = { + .setup_icg = rtd1319_sc_wrap_setup_icg, +}; + +static void rtd1619b_sc_wrap_setup_icg(struct sc_wrap_data *data) +{ + uint32_t val; + + val = readl(data->base + SCW_CTRL); + val |= 0xff3c0000; + writel(val, data->base + SCW_CTRL); + + val = readl(data->base + SCW_CTRL1); + val |= 0x00000101; + writel(val, data->base + SCW_CTRL1); + + val = readl(data->base + SC_ACP_CRT_CTRL); + val |= 0x10000000; + writel(val, data->base + SC_ACP_CRT_CTRL); + + val = readl(data->base + SC_CRT_CTRL); + val |= 0xc0000000; + writel(val, data->base + SC_CRT_CTRL); +} + +static const struct sc_wrap_ops rtd1619b_sc_wrap_ops = { + .setup_icg = rtd1619b_sc_wrap_setup_icg, +}; + +static void sc_wrap_init(struct sc_wrap_data *data) +{ + if (!data->ops) + return; + + if (data->ops->setup_icg) + data->ops->setup_icg(data); + + if (data->ops->setup_pmu) + data->ops->setup_pmu(data); +} + +static int sc_wrap_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct sc_wrap_data *data; + struct resource res; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + data->ops = of_device_get_match_data(dev); + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(dev, "failed to get recource: %d\n", ret); + return -ENODEV; + } + + data->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!data->base) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + sc_wrap_init(data); + + return 0; +} + +static const struct of_device_id sc_wrap_ids[] = { + { .compatible = "realtek,rtd1319-scpu-wrapper", .data = &rtd1319_sc_wrap_ops, }, + { .compatible = "realtek,rtd1619b-scpu-wrapper", .data = &rtd1619b_sc_wrap_ops, }, + {} +}; + +static struct platform_driver sc_wrap_driver = { + .probe = sc_wrap_probe, + .driver = { + .name = "rtk-sc-wrap", + .owner = THIS_MODULE, + .of_match_table = sc_wrap_ids, + }, +}; +module_platform_driver(sc_wrap_driver); + +MODULE_DESCRIPTION("Reatek SCPU Wrapper Driver"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/soc/realtek/common/rtk_sha1.c b/drivers/soc/realtek/common/rtk_sha1.c new file mode 100644 index 000000000000..210223e5dd00 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_sha1.c @@ -0,0 +1,381 @@ +/* + * rtk_sha1.c - sha1 API + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + + +/* + * sftware base SHA1 tool + * porting form http://svn.ghostscript.com/jbig2dec/trunk/sha1.c + * jinncheng@realtek.com +*/ + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 07/2002 +By Ralph Giles +Still 100% public domain +modified for use with stdint types, autoconf +code cleanup, removed attribution comments +switched SHA1Final() argument order for consistency +use SHA1_ prefix for public api +move public api to sha1.h +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +void SHA1_Transform(unsigned int state[5], const unsigned char buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +/* FIXME: can we do this in an endian-proof way? */ +#ifdef WORDS_BIGENDIAN +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00)|(rol(block->l[i],8)&0x00FF00FF)) +#endif + +#define blk(i) (block->l[i&15] = rol( \ + block->l[(i+13)&15]^ \ + block->l[(i+8)&15]^ \ + block->l[(i+2)&15]^ \ + block->l[i&15],1) ) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +#ifdef VERBOSE /* SAK */ + void SHAPrintContext(SHA1_CTX *context, char *msg){ + printk("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); + } +#endif /* VERBOSE */ + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +void SHA1_Transform(unsigned int state[5], const unsigned char buffer[64]) +{ + unsigned int a, b, c, d, e; + typedef union { + unsigned char c[64]; + unsigned int l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + +#ifdef SHA1HANDSOFF + static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ +void SHA1_Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ +void SHA1_Update(SHA1_CTX* context, const unsigned char * data, const size_t len) +{ + size_t i, j; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) { + context->count[1]++; + } + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + j = 0; + } + else { + i = 0; + } + memcpy(&context->buffer[j], &data[i], len - i); + +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ +void SHA1_Final(SHA1_CTX* context, unsigned char digest[SHA1_DIGEST_SIZE]) +{ + unsigned int i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1_Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (unsigned char *)"\0", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); /* SWR */ + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} + +int MCP_SHA1_Get_Hash( + unsigned char * source, + unsigned int source_len, + unsigned char * hash ) +{ + SHA1_CTX context; + unsigned char digest[SHA1_DIGEST_SIZE]; + void * tmp_buffer; + + //printk(KERN_INFO "*** %s %d, source_len %d\n", __FILE__, __LINE__, source_len); + + tmp_buffer = kmalloc(source_len, GFP_KERNEL); + if( !tmp_buffer ) { + printk(KERN_WARNING "%s %d, alloc memory %d faild\n", __FILE__, __LINE__, source_len); + return -ENOMEM; + } + + memcpy( tmp_buffer, source, source_len ); + + SHA1_Init(&context); + SHA1_Update(&context, tmp_buffer, source_len); + SHA1_Final(&context, digest); + + if( tmp_buffer ) { + kfree(tmp_buffer); + } + + //printk(KERN_INFO "*** %s %d\n", __FILE__, __LINE__); + + //MCP_SHA1_dump_hex(digest, SHA1_DIGEST_SIZE); + + memcpy( hash, digest, SHA1_DIGEST_SIZE ); + + return 0; +} + +#if 0 // sample code for SHA1 + +void MCP_SHA1_dump_hex( unsigned char * pbuf, unsigned int len ) +{ + int i, j; + printk(KERN_INFO "********************************************************************\n"); + for( i = 0; i < len; i++ ) { + if( i && !( i & 0xF ) ) { + printk("\n"); + } + printk(" %02x", pbuf[i]); + } + printk("\n"); + printk(KERN_INFO "********************************************************************\n"); +} + +void MCP_Sha1_test( void ) +{ + void * data_buffer; + unsigned char sha1[SHA1_DIGEST_SIZE]; + + data_buffer = kmalloc(32<<10, GFP_KERNEL); + if( !data_buffer ) { + printk(KERN_WARNING "%s %d, alloc memory 32K faild\n", __FILE__, __LINE__); + return; + } + printk(KERN_INFO "%s %d, data_buffer vaddr 0x%08x\n", __FILE__, __LINE__, (unsigned int)data_buffer); + printk(KERN_INFO "%s %d, data_buffer paddr 0x%08x\n", __FILE__, __LINE__, (unsigned int)__pa(data_buffer)); + + memset( data_buffer, '0', 32<<10 ); + + MCP_SHA1_Get_Hash(data_buffer, 20, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 40, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 60, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 64, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 128, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 256, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 512, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 1024, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 2048, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 4096, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 8192, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 16<<10, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + MCP_SHA1_Get_Hash(data_buffer, 32<<10, sha1); + MCP_SHA1_dump_hex(sha1,SHA1_DIGEST_SIZE); + + if( data_buffer ) { + kfree(data_buffer); + } +} +#endif + diff --git a/drivers/soc/realtek/common/rtk_usb.h b/drivers/soc/realtek/common/rtk_usb.h new file mode 100644 index 000000000000..458f38def0d1 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rtk_usb.h + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#ifndef __RTK_USB_H_INCLUDED_ +#define __RTK_USB_H_INCLUDED_ + +struct device_node; +struct rtk_usb; + +enum usb_port_num { + USB_PORT_0 = 0, + USB_PORT_1 = 1, + USB_PORT_2 = 2, + USB_PORT_3 = 3, +}; + +struct rtk_usb_ops { + struct rtk_usb *rtk_usb; + + struct rtk_usb *(*usb_soc_init)(struct device_node *node); + int (*usb_soc_free)(struct rtk_usb **rtk_usb); + + int (*usb_port_suspend_resume)(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend); + int (*usb_set_hw_l4icg_on_off)(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on); + + int (*usb_iso_power_ctrl)(struct rtk_usb *rtk_usb, + bool power_on); + + void (*usb_set_charger_power)(struct rtk_usb *rtk_usb, + unsigned int val); + + /* For Type c */ + int (*type_c_init)(struct rtk_usb *rtk_usb); + int (*type_c_plug_config)(struct rtk_usb *rtk_usb, + int dr_mode, int cc); +}; + +static inline int rtk_usb_soc_init(struct rtk_usb_ops *ops, + struct device_node *node) +{ + if (ops == NULL) + return -EPERM; + else if (ops->usb_soc_init == NULL) + return -EPERM; + + ops->rtk_usb = ops->usb_soc_init(node); + + return 0; +} + +static inline int rtk_usb_soc_free(struct rtk_usb_ops *ops) +{ + if (ops == NULL) + return -EPERM; + else if (ops->usb_soc_free == NULL) + return -EPERM; + + ops->usb_soc_free(&(ops->rtk_usb)); + + return 0; +} + +static inline int rtk_usb_port_suspend_resume(struct rtk_usb_ops *ops, + enum usb_port_num port_num, bool is_suspend) +{ + if (ops == NULL) + return -EPERM; + if (ops->usb_port_suspend_resume) + ops->usb_port_suspend_resume(ops->rtk_usb, + port_num, is_suspend); + + return 0; +} + +static inline int rtk_usb_set_hw_l4icg_on_off(struct rtk_usb_ops *ops, + enum usb_port_num port_num, bool on) +{ + if (ops == NULL) + return -EPERM; + if (ops->usb_set_hw_l4icg_on_off) + ops->usb_set_hw_l4icg_on_off(ops->rtk_usb, port_num, on); + + return 0; +} + +static inline int rtk_usb_iso_power_ctrl(struct rtk_usb_ops *ops, + bool power_on) +{ + if (ops == NULL) + return -EPERM; + if (ops->usb_iso_power_ctrl) + ops->usb_iso_power_ctrl(ops->rtk_usb, power_on); + + return 0; +} + +static inline void rtk_usb_set_charger_power(struct rtk_usb_ops *ops, + unsigned int val) +{ + if (ops == NULL) + return; + if (ops->usb_set_charger_power) + ops->usb_set_charger_power(ops->rtk_usb, val); +} + +/* For Type c */ +static inline int rtk_type_c_init(struct rtk_usb_ops *ops) +{ + if (ops == NULL) + return -EPERM; + if (ops->type_c_init) + ops->type_c_init(ops->rtk_usb); + + return 0; +} + +static inline int rtk_type_c_plug_config(struct rtk_usb_ops *ops, + int dr_mode, int cc) +{ + if (ops == NULL) + return -EPERM; + if (ops->type_c_plug_config) + ops->type_c_plug_config(ops->rtk_usb, dr_mode, cc); + + return 0; +} + +/* For platform */ +int rtk_usb_rtd119x_init(struct rtk_usb_ops *ops); +int rtk_usb_rtd129x_init(struct rtk_usb_ops *ops); +int rtk_usb_rtd139x_init(struct rtk_usb_ops *ops); +int rtk_usb_rtd16xx_init(struct rtk_usb_ops *ops); +int rtk_usb_rtd13xx_init(struct rtk_usb_ops *ops); +int rtk_usb_rtd16xxb_init(struct rtk_usb_ops *ops); +int rtk_usb_rtd1312c_init(struct rtk_usb_ops *ops); + +#endif // __RTK_USB_H_INCLUDED_ diff --git a/drivers/soc/realtek/common/rtk_usb_manager.c b/drivers/soc/realtek/common/rtk_usb_manager.c new file mode 100644 index 000000000000..22c571e8843e --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_manager.c @@ -0,0 +1,2760 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtk-usb-manager.c RTK Manager Driver for All USB. + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Copyright (C) 2020 Realtek Semiconductor Corporation + * + */ + +//#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtk_usb.h" + +#define CRT_SOFT_RESET1 0x0 +#define CRT_SOFT_RESET2 0x4 +#define CRT_CLOCK_ENABLE1 0xc + +#define REALTEK_USB_MANAGER_STR "realtek,usb-manager" + +#define CLOCK_RESET_NAME_MAX 32 +#define CLOCK_NAME_USB "clk_en_usb" +#define CLOCK_NAME_USB_PORT0 "clk_en_phy0_to_host" +#define CLOCK_NAME_USB_PORT1 "clk_en_phy1_to_host" +#define CLOCK_NAME_USB_PORT2 "clk_en_phy2_to_host" +#define CLOCK_NAME_USB_PORT3 "clk_en_phy3_to_host" + +#define RESET_NAME_USB "usb" +#define RESET_NAME_TYPEC "type_c" +#define RESET_NAME_U2PHY0 "u2phy0" +#define RESET_NAME_U2PHY1 "u2phy1" +#define RESET_NAME_U2PHY2 "u2phy2" +#define RESET_NAME_U2PHY3 "u2phy3" +#define RESET_NAME_U3PHY0 "u3phy0" +#define RESET_NAME_U3PHY1 "u3phy1" +#define RESET_NAME_U3PHY2 "u3phy2" +#define RESET_NAME_U3PHY3 "u3phy3" +#define RESET_NAME_U3MDIO0 "u3mdio0" +#define RESET_NAME_U3MDIO1 "u3mdio1" +#define RESET_NAME_U3MDIO2 "u3mdio2" +#define RESET_NAME_U3MDIO3 "u3mdio3" +#define RESET_NAME_USB_MAC0 "usb_host0" +#define RESET_NAME_USB_MAC1 "usb_host1" +#define RESET_NAME_USB_MAC2 "usb_host2" +#define RESET_NAME_USB_MAC3 "usb_host3" + +struct gpio_data { + struct gpio_desc *gpio_desc; + + int active_port; + int active_port_mask; /* bit 0~3 mapping to port 0~3*/ + /*port GPIO*/ + /* port power on off */ + bool power_on; + bool power_low_active; + + struct device_node *node; +}; + +struct port_data { + int port_num; + + struct gpio_data *power_gpio; + + /* port mapping to host */ + struct device_node *mac_node; + struct device_node *slave_mac_node; /* for ohci */ + bool support_usb3; + + int active; + int enable_mask; /* bit 0: master; bit 1: slave */ + int enable; + + struct device_node *node; + + /* clock and reset */ + char clock[CLOCK_RESET_NAME_MAX]; + char reset_u2phy[CLOCK_RESET_NAME_MAX]; + char reset_u3phy[CLOCK_RESET_NAME_MAX]; + char reset_u3mdio[CLOCK_RESET_NAME_MAX]; + char reset_usb_mac[CLOCK_RESET_NAME_MAX]; +}; + +struct manager_data { + void __iomem *crt_base; + struct device *dev; + + struct port_data port0; + struct port_data port1; + struct port_data port2; + struct port_data port3; + + /* usb power gpio */ + struct gpio_data gpio0; + struct gpio_data gpio1; + struct gpio_data gpio2; + struct gpio_data gpio3; + + bool disable_usb; + + bool usb_iso_mode; + bool en_usb_storage_reprobe; + bool rescue_usb; + bool dis_hub_autosuspend; + + struct rtk_usb_ops *rtk_usb; + + struct workqueue_struct *wq_usb_manager; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debug_dir; +#endif + + struct mutex lock; + + /* clock and reset */ + char clock[CLOCK_RESET_NAME_MAX]; + char reset_usb[CLOCK_RESET_NAME_MAX]; + char reset_type_c[CLOCK_RESET_NAME_MAX]; +}; + +static inline bool port_can_enable(struct port_data *port) +{ + bool can_enable = true; + + if (port->port_num < 0) + can_enable = false; + if (port->enable_mask == 0) + can_enable = false; + + return can_enable; +} + +static struct manager_data *get_rtk_usb_manager(void) +{ + struct device_node *node; + struct platform_device *pdev; + static struct manager_data *data; + + if (data == NULL) { + node = of_find_compatible_node(NULL, NULL, + REALTEK_USB_MANAGER_STR); + if (node != NULL) + pdev = of_find_device_by_node(node); + if (pdev != NULL) + data = platform_get_drvdata(pdev); + } + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return NULL; + } + + return data; +} + +#ifdef CONFIG_USB_PATCH_ON_RTK +/* [ROOT_CAUSE]: quirk device result in compatibility issue + * [SOLUTION]: clear port power and reset port if got error + * commit 42e905e60eaadd3fd8374db23dc644b98080717e + */ +extern int RTK_usb_probe_device(struct device *dev); +extern int RTK_usb_unbind_device(struct device *dev); + +int RTK_usb_reprobe_usb_storage(struct usb_device *udev) +{ + struct manager_data *data; + int usb_storage = 0; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + + /* [ROOT_CAUSE]: quirk device result in compatibility issue + * [SOLUTION]: clear port power and reset port if got error + * commit 42e905e60eaadd3fd8374db23dc644b98080717e + * [DEV_FIX]MediaNAS_V0.1 can't recognise the 5411 hub after power on + * [SOLUTION] dont unbind and probe again after usb_add_device, + * and set it as quirk device + * commit 75b83399dcf5e38ae39ce16d730f5824fccbb3bf + * [DEV_FIX]xhci hub 2.0 can't be recognize after + * unplug and plug again + * commit fbb4cc12d549b5193d51e88d6d0bc916a6e4d5d3 + * [ROOT_CAUSE] USB hdd can't be mounted cuz scsi not stable + * during power-on stage + * commit dbb572028226bba6b504ff859fe3f05e5b7efbdf + * [ROOT_CAUSE] USB hdd can't be mounted cuz scsi not stable + * during power-on stage + * commit 8fa320af443950c0dbc9875546159d9c57cd97f2 + * [ROOT_CAUSE]config USB device error ,result in NULL pointer + * commit 0d7ba5cbee8ff84a99f926a0a00128fe9c6c6104 + * [ROOT_CAUSE] usb SATA not stable after power on + * commit ba77afca700fa8586607fcfa9091b863f4a3b620 + * [ROOT_CAUSE] if se config err , udev->actconfig will be NULL + * commit 2ebede9fe6b6347ecf446a06e958dfd0a671b27d + */ + //hcy added for quirk HDD + if (!data->en_usb_storage_reprobe) + return 0; + + if (udev->actconfig) { + int i; + + for (i = 0; i < 1/*udev->actconfig->desc.bNumInterfaces*/; + i++) { + struct usb_host_config *config = udev->actconfig; + struct usb_interface *intf = config->interface[i]; + struct usb_interface_descriptor *desc; + + desc = &intf->cur_altsetting->desc; + + dev_info(&udev->dev, "bInterfaceClass = %d (jiffies 0x%lx = %d ms)\n", + desc->bInterfaceClass, + jiffies - INITIAL_JIFFIES, + jiffies_to_msecs(jiffies - + INITIAL_JIFFIES)); + if (desc->bInterfaceClass == USB_CLASS_MASS_STORAGE) { + usb_storage = 1; + break; + } + } + } + + if ((jiffies - INITIAL_JIFFIES) < 0x400 + && (usb_storage || + udev->descriptor.bDeviceClass == USB_CLASS_MASS_STORAGE)) { + msleep(100); + dev_info(&udev->dev, "%s unbind-probe dev_name = %s (jiffies= 0x%lx = %d ms)\n", + __func__, + dev_name(&udev->dev), jiffies - INITIAL_JIFFIES, + jiffies_to_msecs(jiffies - INITIAL_JIFFIES)); + RTK_usb_unbind_device(&udev->dev); + //hcy added for waiting some scsi HDD stable after power on + if (data->rescue_usb) { + dev_err(&udev->dev, "** rescue type **\n"); + msleep(5000); + } else { + msleep(10000); + } + + dev_info(&udev->dev, "%s bind-probe dev_name = %s (jiffies= 0x%lx = %d ms)\n", + __func__, + dev_name(&udev->dev), jiffies - INITIAL_JIFFIES, + jiffies_to_msecs(jiffies - INITIAL_JIFFIES)); + RTK_usb_probe_device(&udev->dev); + } + + return 0; +} + +bool RTK_usb_disable_hub_autosuspend(void) +{ + struct manager_data *data; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return false; + } + + return data->dis_hub_autosuspend; +} +#endif // CONFIG_USB_PATCH_ON_RTK + +int rtk_usb_manager_is_iso_mode(struct device *usb_dev) +{ + struct manager_data *data = NULL; + struct device *dev = NULL; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + dev = data->dev; + if (data->usb_iso_mode) { + dev_dbg(data->dev, "%s is usb_iso_mode", __func__); + return 1; + } + dev_dbg(data->dev, "%s Not usb_iso_mode", __func__); + return 0; +} + +int rtk_usb_manager_schedule_work(struct device *usb_dev, + struct work_struct *work) +{ + struct manager_data *data = NULL; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + dev_dbg(data->dev, "%s Enter ..\n", __func__); + + dev_info(data->dev, "%s for %s", __func__, dev_name(usb_dev)); + + if (work == NULL) { + dev_err(data->dev, "%s, work is NULL", __func__); + return -1; + } + mutex_lock(&data->lock); + + queue_work(data->wq_usb_manager, work); + + mutex_unlock(&data->lock); + + dev_dbg(data->dev, "%s Exit ..\n", __func__); + return 0; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(rtk_usb_manager_schedule_work); +#endif /* MY_DEF_HERE */ + +/* enable hw_pm (L4 ICG) + * The hw_pm function will be reset after doing soft_reset, so + * only enable is provided. + */ +static __maybe_unused void __rtk_usb_set_hw_pm_enable(struct manager_data *data) +{ + struct device *dev = data->dev; + bool on = true; + + if (!data->rtk_usb) + return; + + dev_dbg(dev, "set usb_hw_pm\n"); + + /* for hw_pm, enable is equal to power_off */ + if (port_can_enable(&data->port0)) + rtk_usb_set_hw_l4icg_on_off(data->rtk_usb, USB_PORT_0, on); + if (port_can_enable(&data->port1)) + rtk_usb_set_hw_l4icg_on_off(data->rtk_usb, USB_PORT_1, on); + if (port_can_enable(&data->port2)) + rtk_usb_set_hw_l4icg_on_off(data->rtk_usb, USB_PORT_2, on); + if (port_can_enable(&data->port3)) + rtk_usb_set_hw_l4icg_on_off(data->rtk_usb, USB_PORT_3, on); +} + +/* set usb charger power */ +static __maybe_unused void __usb_set_charger_power( + struct manager_data *data, bool power_on) +{ + struct device *dev = data->dev; + unsigned int val = 0; + + if (!data->rtk_usb) + return; + + if (power_on) { + if (port_can_enable(&data->port0)) + val |= BIT(0); + if (port_can_enable(&data->port1)) + val |= BIT(1); + if (port_can_enable(&data->port2)) + val |= BIT(2); + if (port_can_enable(&data->port3)) + val |= BIT(3); + } + + dev_dbg(dev, "%s set usb_charger %x\n", __func__, val); + + rtk_usb_set_charger_power(data->rtk_usb, val); +} + +/* set usb power domain */ +static void __usb_set_pd_power(struct manager_data *data, bool power_on) +{ + //struct device *dev = data->dev; + + if (power_on && !data->disable_usb) { + if (!data->rtk_usb) + return; + rtk_usb_iso_power_ctrl(data->rtk_usb, true); + } else { + if (!data->rtk_usb) + return; + rtk_usb_iso_power_ctrl(data->rtk_usb, false); + } +} + +static inline struct reset_control *USB_reset_get(struct device *dev, + const char *str) +{ + struct reset_control *reset; + + reset = reset_control_get_exclusive(dev, str); + if (IS_ERR(reset)) { + dev_dbg(dev, "No controller reset %s\n", str); + reset = NULL; + } + return reset; +} + +static inline void USB_reset_put(struct reset_control *reset) +{ + if (reset) + reset_control_put(reset); +} + +static inline int USB_reset_deassert(struct reset_control *reset) +{ + if (!reset) + return 0; + + return reset_control_deassert(reset); +} + +static inline int USB_reset_assert(struct reset_control *reset) +{ + if (!reset) + return 0; + + return reset_control_assert(reset); +} + +static inline struct clk *USB_clk_get(struct device *dev, const char *str) +{ + struct clk *clk; + + clk = clk_get(dev, str); + if (IS_ERR(clk)) { + dev_dbg(dev, "No clk %s\n", str); + clk = NULL; + } + return clk; +} + +static bool __usb_workaround_port0_enable(struct manager_data *data) +{ + const struct soc_device_attribute *soc_att_match = NULL; + struct soc_device_attribute rtk_soc[] = { + { + .family = "Realtek Phoenix", + }, + { + .family = "Realtek Kylin", + }, + { + .family = "Realtek Hercules", + }, + { + .family = "Realtek Thor", + }, + { + .family = "Realtek Hank", + }, + { + /* empty */ + } + }; + + if (!data) { + pr_err("%s ERROR: data is NULL\n", __func__); + return false; + } + + soc_att_match = soc_device_match(rtk_soc); + if (soc_att_match) { + pr_info("%s Workaround port 0 reset enable match chip: %s\n", + __func__, + soc_att_match->family); + return true; + } + return false; +} + +static int __usb_init_clock_reset(struct manager_data *data) +{ + struct device *dev = data->dev; + /* GET clock */ + struct clk *clk_usb_phy0_to_host = USB_clk_get(dev, data->port0.clock); + struct clk *clk_usb_phy1_to_host = USB_clk_get(dev, data->port1.clock); + struct clk *clk_usb_phy2_to_host = USB_clk_get(dev, data->port2.clock); + struct clk *clk_usb_phy3_to_host = USB_clk_get(dev, data->port3.clock); + struct clk *clk_usb = USB_clk_get(dev, data->clock); + + /* GET reset controller */ + struct reset_control *reset_u2phy0 = USB_reset_get(dev, + data->port0.reset_u2phy); + struct reset_control *reset_u2phy1 = USB_reset_get(dev, + data->port1.reset_u2phy); + struct reset_control *reset_u2phy2 = USB_reset_get(dev, + data->port2.reset_u2phy); + struct reset_control *reset_u2phy3 = USB_reset_get(dev, + data->port3.reset_u2phy); + + struct reset_control *reset_u3phy0 = USB_reset_get(dev, + data->port0.reset_u3phy); + struct reset_control *reset_u3phy1 = USB_reset_get(dev, + data->port1.reset_u3phy); + struct reset_control *reset_u3phy2 = USB_reset_get(dev, + data->port2.reset_u3phy); + struct reset_control *reset_u3phy3 = USB_reset_get(dev, + data->port3.reset_u3phy); + struct reset_control *reset_u3mdio0 = USB_reset_get(dev, + data->port0.reset_u3mdio); + struct reset_control *reset_u3mdio1 = USB_reset_get(dev, + data->port1.reset_u3mdio); + struct reset_control *reset_u3mdio2 = USB_reset_get(dev, + data->port2.reset_u3mdio); + struct reset_control *reset_u3mdio3 = USB_reset_get(dev, + data->port3.reset_u3mdio); + + struct reset_control *reset_usb_mac0 = USB_reset_get(dev, + data->port0.reset_usb_mac); + struct reset_control *reset_usb_mac1 = USB_reset_get(dev, + data->port1.reset_usb_mac); + struct reset_control *reset_usb_mac2 = USB_reset_get(dev, + data->port2.reset_usb_mac); + struct reset_control *reset_usb_mac3 = USB_reset_get(dev, + data->port3.reset_usb_mac); + struct reset_control *reset_usb = USB_reset_get(dev, + data->reset_usb); + struct reset_control *reset_type_c = USB_reset_get(dev, + data->reset_type_c); + + struct reset_control *reset_usb_apply = USB_reset_get(dev, "apply"); + + dev_dbg(dev, "Realtek USB init\n"); + + USB_reset_assert(reset_u2phy0); + USB_reset_assert(reset_u2phy1); + USB_reset_assert(reset_u2phy2); + USB_reset_assert(reset_u2phy3); + USB_reset_assert(reset_u3phy0); + USB_reset_assert(reset_u3phy1); + USB_reset_assert(reset_u3phy2); + USB_reset_assert(reset_u3phy3); + USB_reset_assert(reset_u3mdio0); + USB_reset_assert(reset_u3mdio1); + USB_reset_assert(reset_u3mdio2); + USB_reset_assert(reset_u3mdio3); + USB_reset_assert(reset_usb_mac0); + USB_reset_assert(reset_usb_mac1); + USB_reset_assert(reset_usb_mac2); + USB_reset_assert(reset_usb_mac3); + USB_reset_assert(reset_usb); + USB_reset_assert(reset_type_c); + /* Do wmb */ + wmb(); + + // Enable usb phy reset + /* DEASSERT: set rstn bit to 1 */ + dev_dbg(dev, "Realtek USB init: Set phy reset to 1\n"); + if (port_can_enable(&data->port0)) { + USB_reset_deassert(reset_u2phy0); + if (data->port0.support_usb3) + USB_reset_deassert(reset_u3phy0); + } + if (port_can_enable(&data->port1)) { + USB_reset_deassert(reset_u2phy1); + if (data->port1.support_usb3) + USB_reset_deassert(reset_u3phy1); + } + if (port_can_enable(&data->port2)) { + USB_reset_deassert(reset_u2phy2); + if (data->port2.support_usb3) + USB_reset_deassert(reset_u3phy2); + } + if (port_can_enable(&data->port3)) { + USB_reset_deassert(reset_u2phy3); + if (data->port3.support_usb3) + USB_reset_deassert(reset_u3phy3); + } + + USB_reset_deassert(reset_usb_apply); + + udelay(300); + + dev_dbg(dev, "Realtek USB init: Trigger usb clk\n"); + // Trigger USB clk (enable -> disable) + clk_prepare_enable(clk_usb); // = clk_prepare + clk_enable + clk_disable_unprepare(clk_usb); // = clk_disable + clk_unprepare + + dev_dbg(dev, "Realtek USB init: Set u3phy mdio reset to 1\n"); + // Enable USB reset + if (port_can_enable(&data->port0) && data->port0.support_usb3) + USB_reset_deassert(reset_u3mdio0); + if (port_can_enable(&data->port1) && data->port1.support_usb3) + USB_reset_deassert(reset_u3mdio1); + if (port_can_enable(&data->port2) && data->port2.support_usb3) + USB_reset_deassert(reset_u3mdio2); + if (port_can_enable(&data->port3) && data->port3.support_usb3) + USB_reset_deassert(reset_u3mdio3); + + USB_reset_deassert(reset_usb_apply); + + dev_dbg(dev, "Realtek USB init: Set usb reset to 1\n"); + + /* port0 mac's reset bit must always enable for some platforms */ + if (port_can_enable(&data->port0) || + __usb_workaround_port0_enable(data)) + USB_reset_deassert(reset_usb_mac0); + if (port_can_enable(&data->port1)) + USB_reset_deassert(reset_usb_mac1); + if (port_can_enable(&data->port2)) + USB_reset_deassert(reset_usb_mac2); + if (port_can_enable(&data->port3)) + USB_reset_deassert(reset_usb_mac3); + USB_reset_deassert(reset_usb); + USB_reset_deassert(reset_type_c); + dev_dbg(dev, "Realtek USB init: enable usb clk\n"); + + // Enable USB clk + clk_prepare_enable(clk_usb); // = clk_prepare + clk_enable + if (port_can_enable(&data->port0)) + clk_prepare_enable(clk_usb_phy0_to_host); + if (port_can_enable(&data->port1)) + clk_prepare_enable(clk_usb_phy1_to_host); + if (port_can_enable(&data->port2)) + clk_prepare_enable(clk_usb_phy2_to_host); + if (port_can_enable(&data->port3)) + clk_prepare_enable(clk_usb_phy3_to_host); + + dev_info(dev, "Realtek USB init OK\n"); + + clk_put(clk_usb); + clk_put(clk_usb_phy0_to_host); + clk_put(clk_usb_phy1_to_host); + clk_put(clk_usb_phy2_to_host); + clk_put(clk_usb_phy3_to_host); + + USB_reset_put(reset_u2phy0); + USB_reset_put(reset_u2phy1); + USB_reset_put(reset_u2phy2); + USB_reset_put(reset_u2phy3); + + USB_reset_put(reset_u3phy0); + USB_reset_put(reset_u3phy1); + USB_reset_put(reset_u3phy2); + USB_reset_put(reset_u3phy3); + USB_reset_put(reset_u3mdio0); + USB_reset_put(reset_u3mdio1); + USB_reset_put(reset_u3mdio2); + USB_reset_put(reset_u3mdio3); + + USB_reset_put(reset_usb_mac0); + USB_reset_put(reset_usb_mac1); + USB_reset_put(reset_usb_mac2); + USB_reset_put(reset_usb_mac3); + USB_reset_put(reset_usb); + USB_reset_put(reset_type_c); + + USB_reset_put(reset_usb_apply); + + return 0; +} + +static int __usb_clear_clock_reset(struct manager_data *data) +{ + struct device *dev = data->dev; + /* GET clock */ + struct clk *clk_usb_phy0_to_host = USB_clk_get(dev, data->port0.clock); + struct clk *clk_usb_phy1_to_host = USB_clk_get(dev, data->port1.clock); + struct clk *clk_usb_phy2_to_host = USB_clk_get(dev, data->port2.clock); + struct clk *clk_usb_phy3_to_host = USB_clk_get(dev, data->port3.clock); + struct clk *clk_usb = USB_clk_get(dev, data->clock); + + /* GET reset controller */ + struct reset_control *reset_u2phy0 = USB_reset_get(dev, + data->port0.reset_u2phy); + struct reset_control *reset_u2phy1 = USB_reset_get(dev, + data->port1.reset_u2phy); + struct reset_control *reset_u2phy2 = USB_reset_get(dev, + data->port2.reset_u2phy); + struct reset_control *reset_u2phy3 = USB_reset_get(dev, + data->port3.reset_u2phy); + + struct reset_control *reset_u3phy0 = USB_reset_get(dev, + data->port0.reset_u3phy); + struct reset_control *reset_u3phy1 = USB_reset_get(dev, + data->port1.reset_u3phy); + struct reset_control *reset_u3phy2 = USB_reset_get(dev, + data->port2.reset_u3phy); + struct reset_control *reset_u3phy3 = USB_reset_get(dev, + data->port3.reset_u3phy); + struct reset_control *reset_u3mdio0 = USB_reset_get(dev, + data->port0.reset_u3mdio); + struct reset_control *reset_u3mdio1 = USB_reset_get(dev, + data->port1.reset_u3mdio); + struct reset_control *reset_u3mdio2 = USB_reset_get(dev, + data->port2.reset_u3mdio); + struct reset_control *reset_u3mdio3 = USB_reset_get(dev, + data->port3.reset_u3mdio); + + struct reset_control *reset_usb_mac0 = USB_reset_get(dev, + data->port0.reset_usb_mac); + struct reset_control *reset_usb_mac1 = USB_reset_get(dev, + data->port1.reset_usb_mac); + struct reset_control *reset_usb_mac2 = USB_reset_get(dev, + data->port2.reset_usb_mac); + struct reset_control *reset_usb_mac3 = USB_reset_get(dev, + data->port3.reset_usb_mac); + struct reset_control *reset_usb = USB_reset_get(dev, + data->reset_usb); + struct reset_control *reset_type_c = USB_reset_get(dev, + data->reset_type_c); + + struct reset_control *reset_usb_apply = USB_reset_get(dev, "apply"); + + dev_dbg(dev, "Realtek USB clear clock and reset\n"); + + USB_reset_assert(reset_u2phy0); + USB_reset_assert(reset_u2phy1); + USB_reset_assert(reset_u2phy2); + USB_reset_assert(reset_u2phy3); + USB_reset_assert(reset_u3phy0); + USB_reset_assert(reset_u3phy1); + USB_reset_assert(reset_u3phy2); + USB_reset_assert(reset_u3phy3); + USB_reset_assert(reset_u3mdio0); + USB_reset_assert(reset_u3mdio1); + USB_reset_assert(reset_u3mdio2); + USB_reset_assert(reset_u3mdio3); + USB_reset_assert(reset_usb_mac0); + USB_reset_assert(reset_usb_mac1); + USB_reset_assert(reset_usb_mac2); + USB_reset_assert(reset_usb_mac3); + USB_reset_assert(reset_usb); + USB_reset_assert(reset_type_c); + /* Do wmb */ + wmb(); + + clk_disable_unprepare(clk_usb); // = clk_disable + clk_unprepare + if (port_can_enable(&data->port0)) + clk_disable_unprepare(clk_usb_phy0_to_host); + if (port_can_enable(&data->port1)) + clk_disable_unprepare(clk_usb_phy1_to_host); + if (port_can_enable(&data->port2)) + clk_disable_unprepare(clk_usb_phy2_to_host); + if (port_can_enable(&data->port3)) + clk_disable_unprepare(clk_usb_phy3_to_host); + + dev_info(dev, "Realtek USB clear clock and reset... OK\n"); + + clk_put(clk_usb); + clk_put(clk_usb_phy0_to_host); + clk_put(clk_usb_phy1_to_host); + clk_put(clk_usb_phy2_to_host); + clk_put(clk_usb_phy3_to_host); + + USB_reset_put(reset_u2phy0); + USB_reset_put(reset_u2phy1); + USB_reset_put(reset_u2phy2); + USB_reset_put(reset_u2phy3); + + USB_reset_put(reset_u3phy0); + USB_reset_put(reset_u3phy1); + USB_reset_put(reset_u3phy2); + USB_reset_put(reset_u3phy3); + USB_reset_put(reset_u3mdio0); + USB_reset_put(reset_u3mdio1); + USB_reset_put(reset_u3mdio2); + USB_reset_put(reset_u3mdio3); + + USB_reset_put(reset_usb_mac0); + USB_reset_put(reset_usb_mac1); + USB_reset_put(reset_usb_mac2); + USB_reset_put(reset_usb_mac3); + USB_reset_put(reset_usb); + USB_reset_put(reset_type_c); + + USB_reset_put(reset_usb_apply); + + return 0; +} + +static int __usb_port_clock_reset_enable(struct manager_data *data, + struct port_data *port) +{ + struct device *dev = data->dev; + /* GET clock */ + struct clk *clk_usb_phy_to_host = USB_clk_get(dev, port->clock); + + /* GET reset controller */ + struct reset_control *reset_u2phy = USB_reset_get(dev, + port->reset_u2phy); + + struct reset_control *reset_u3phy = USB_reset_get(dev, + port->reset_u3phy); + struct reset_control *reset_u3mdio = USB_reset_get(dev, + port->reset_u3mdio); + + struct reset_control *reset_usb_mac = USB_reset_get(dev, + port->reset_usb_mac); + + dev_info(dev, "%s: port%d clock/reset enable\n", + __func__, port->port_num); + + /* Enable USB port reset */ + if (port_can_enable(port)) { + USB_reset_deassert(reset_u2phy); + if (port->support_usb3) + USB_reset_deassert(reset_u3phy); + } + udelay(300); + + if (port_can_enable(port) && port->support_usb3) + USB_reset_deassert(reset_u3mdio); + + if (port_can_enable(port)) + USB_reset_deassert(reset_usb_mac); + + udelay(300); + /* Enable USB port clock */ + if (port_can_enable(port)) + clk_prepare_enable(clk_usb_phy_to_host); + + clk_put(clk_usb_phy_to_host); + + USB_reset_put(reset_u2phy); + USB_reset_put(reset_u3phy); + USB_reset_put(reset_u3mdio); + + USB_reset_put(reset_usb_mac); + + return 0; +} + +static int __usb_port_clock_reset_disable(struct manager_data *data, + struct port_data *port) +{ + struct device *dev = data->dev; + /* GET clock */ + struct clk *clk_usb_phy_to_host = USB_clk_get(dev, port->clock); + + /* GET reset controller */ + struct reset_control *reset_u2phy = USB_reset_get(dev, + port->reset_u2phy); + + struct reset_control *reset_u3phy = USB_reset_get(dev, + port->reset_u3phy); + struct reset_control *reset_u3mdio = USB_reset_get(dev, + port->reset_u3mdio); + + struct reset_control *reset_usb_mac = USB_reset_get(dev, + port->reset_usb_mac); + + dev_info(dev, "%s: port%d clock/reset disable\n", + __func__, port->port_num); + + clk_disable_unprepare(clk_usb_phy_to_host); + + /* Do wmb */ + wmb(); + + USB_reset_assert(reset_u2phy); + USB_reset_assert(reset_u3phy); + USB_reset_assert(reset_u3mdio); + udelay(300); + + if (port->port_num !=0 || + !__usb_workaround_port0_enable(data)) + USB_reset_assert(reset_usb_mac); + + clk_put(clk_usb_phy_to_host); + + USB_reset_put(reset_u2phy); + USB_reset_put(reset_u3phy); + USB_reset_put(reset_u3mdio); + + USB_reset_put(reset_usb_mac); + + return 0; +} + +int rtk_usb_type_c_init(struct device *type_c_dev) +{ + struct manager_data *data = NULL; + struct device *dev = NULL; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + dev = data->dev; + if (data->rtk_usb) + rtk_type_c_init(data->rtk_usb); + else + dev_info(data->dev, "%s No rtk_usb data", __func__); + + return 0; +} + +int rtk_usb_type_c_plug_config(struct device *type_c_dev, + int dr_mode, int cc) +{ + struct manager_data *data = NULL; + struct device *dev = NULL; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + dev = data->dev; + if (data->rtk_usb) + rtk_type_c_plug_config(data->rtk_usb, dr_mode, cc); + else + dev_info(data->dev, "%s No rtk_usb data", __func__); + + return 0; +} + +static int __usb_port_power_on_off(struct device *dev, + struct port_data *port, bool on, + struct device_node *node); + +int rtk_usb_port_power_on_off(struct device *usb_dev, bool on) +{ + struct manager_data *data = NULL; + int ret; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + + dev_dbg(data->dev, "%s power %s for %s", __func__, + on?"on":"off", dev_name(usb_dev)); + + mutex_lock(&data->lock); + + ret = __usb_port_power_on_off(data->dev, &data->port0, on, + usb_dev->of_node); + if (ret) + ret = __usb_port_power_on_off(data->dev, &data->port1, on, + usb_dev->of_node); + if (ret) + ret = __usb_port_power_on_off(data->dev, &data->port2, on, + usb_dev->of_node); + if (ret) + ret = __usb_port_power_on_off(data->dev, &data->port3, on, + usb_dev->of_node); + + mutex_unlock(&data->lock); + + return ret; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(rtk_usb_port_power_on_off); +#endif /* MY_DEF_HERE */ + +static int __gpio_on_off(struct device *dev, int port, + struct gpio_data *gpio, bool on) +{ + int ret = 0; + int active_port_mask = gpio->active_port_mask; + bool power_low_active = gpio->power_low_active; + + if (IS_ERR(gpio->gpio_desc)) { + dev_dbg(dev, "%s No gpio config\n", __func__); + return 0; + } + + if (on) { + gpio->active_port |= BIT(port); + if ((gpio->active_port & active_port_mask) != + active_port_mask) { + dev_info(dev, "gpio_num=%d active_port=0x%x active_port_mask=0x%x ==> No turn on\n", + desc_to_gpio(gpio->gpio_desc), gpio->active_port, + active_port_mask); + return -1; + } + } else { + gpio->active_port &= ~BIT(port); + if (gpio->active_port != 0) { + dev_info(dev, "gpio_num=%d active_port=0x%x active_port_mask=0x%x ==> No turn off\n", + desc_to_gpio(gpio->gpio_desc), gpio->active_port, + gpio->active_port_mask); + return -1; + } + } + + if (!IS_ERR(gpio->gpio_desc)) { + if (gpiod_direction_output(gpio->gpio_desc, + power_low_active ? !on:on)) { + dev_err(dev, "%s ERROR set gpio fail\n", + __func__); + ret = -1; + } else { + dev_info(dev, "%s to set power%s %s by gpio (id=%d) OK\n", + __func__, + power_low_active ? + " (power_low_active)":"", + on?"on":"off", desc_to_gpio(gpio->gpio_desc)); + gpio->power_on = on; + } + gpiod_put(gpio->gpio_desc); + } + return ret; +} + +static int __usb_port_power_on_off(struct device *dev, + struct port_data *port, bool on, + struct device_node *node) +{ + struct device_node *usb_node = node; + int enable_mask = port->enable_mask; + + if (port->mac_node && usb_node && + port->mac_node->phandle == usb_node->phandle) { + if (on) + port->active |= BIT(0); + else + port->active &= ~BIT(0); + } else if (port->slave_mac_node && usb_node && + port->slave_mac_node->phandle == usb_node->phandle) { + if (on) + port->active |= BIT(1); + else + port->active &= ~BIT(1); + } else { + dev_dbg(dev, "%s port%d is not match\n", + __func__, port->port_num); + return -ENODEV; + } + + dev_info(dev, "%s port%d power=%s active=0x%x enable_mask=0x%x\n", + __func__, port->port_num, on?"on":"off", + port->active, port->enable_mask); + if (((port->active & enable_mask) == enable_mask) || + (!port->active && !on)) { + if (port->power_gpio) + __gpio_on_off(dev, port->port_num, + port->power_gpio, on); + else + dev_info(dev, "%s port%d no gpio\n", + __func__, port->port_num); + } + return 0; +} + +static int __usb_port_suspend(struct manager_data *data) +{ + struct device *dev = data->dev; + bool is_suspend = true; + + if (!data->rtk_usb) + return 0; + + dev_info(dev, "%s", __func__); + if (port_can_enable(&data->port0)) { + dev_dbg(dev, "set port 0 phy suspend\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_0, + is_suspend); + } + if (port_can_enable(&data->port1)) { + dev_dbg(dev, "set port 1 phy suspend\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_1, + is_suspend); + } + if (port_can_enable(&data->port2)) { + dev_dbg(dev, "set port 2 phy suspend\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_2, + is_suspend); + } + if (port_can_enable(&data->port3)) { + dev_dbg(dev, "set port 3 phy suspend\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_3, + is_suspend); + } + return 0; +} + +static int __usb_port_resume(struct manager_data *data) +{ + struct device *dev = data->dev; + //void __iomem *reg_u3_port; + //void __iomem *reg_u2_port; + bool is_suspend = false; + + if (!data->rtk_usb) + return 0; + + dev_info(dev, "%s", __func__); + if (port_can_enable(&data->port0)) { + dev_dbg(dev, "set port 0 phy resume\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_0, + is_suspend); + } + if (port_can_enable(&data->port1)) { + dev_dbg(dev, "set port 1 phy resume\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_1, + is_suspend); + } + if (port_can_enable(&data->port2)) { + dev_dbg(dev, "set port 2 phy resume\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_2, + is_suspend); + } + if (port_can_enable(&data->port3)) { + dev_dbg(dev, "set port 3 phy resume\n"); + rtk_usb_port_suspend_resume(data->rtk_usb, USB_PORT_3, + is_suspend); + } + return 0; +} + +static int __usb_port_gpio_off(struct manager_data *data) +{ + struct device *dev = data->dev; + struct device_node *usb_node; + bool off = false; + + dev_info(dev, "%s", __func__); + mutex_lock(&data->lock); + + usb_node = data->port0.mac_node; + __usb_port_power_on_off(data->dev, &data->port0, off, usb_node); + usb_node = data->port0.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port0, off, usb_node); + + usb_node = data->port1.mac_node; + __usb_port_power_on_off(data->dev, &data->port1, off, usb_node); + usb_node = data->port1.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port1, off, usb_node); + + usb_node = data->port2.mac_node; + __usb_port_power_on_off(data->dev, &data->port2, off, usb_node); + usb_node = data->port2.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port2, off, usb_node); + + usb_node = data->port3.mac_node; + __usb_port_power_on_off(data->dev, &data->port3, off, usb_node); + usb_node = data->port3.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port3, off, usb_node); + + mutex_unlock(&data->lock); + + return 0; +} + +static int __usb_port_gpio_on(struct manager_data *data) +{ + struct device *dev = data->dev; + struct device_node *usb_node; + bool on = true; + + dev_info(dev, "%s", __func__); + + mutex_lock(&data->lock); + + usb_node = data->port0.mac_node; + __usb_port_power_on_off(data->dev, &data->port0, on, usb_node); + usb_node = data->port0.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port0, on, usb_node); + + usb_node = data->port1.mac_node; + __usb_port_power_on_off(data->dev, &data->port1, on, usb_node); + usb_node = data->port1.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port1, on, usb_node); + + usb_node = data->port2.mac_node; + __usb_port_power_on_off(data->dev, &data->port2, on, usb_node); + usb_node = data->port2.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port2, on, usb_node); + + usb_node = data->port3.mac_node; + __usb_port_power_on_off(data->dev, &data->port3, on, usb_node); + usb_node = data->port3.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port3, on, usb_node); + + mutex_unlock(&data->lock); + + return 0; +} + +int rtk_usb_init_port_power_on(struct device *usb_dev) +{ + struct device_node *usb_node; + static struct manager_data *data; + bool on = true; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + if (usb_dev == NULL) { + dev_err(data->dev, "%s ERROR no manager_data", __func__); + return -ENODEV; + } + + usb_node = usb_dev->of_node; + + dev_info(data->dev, "%s for %s", __func__, dev_name(usb_dev)); + mutex_lock(&data->lock); + + __usb_port_power_on_off(data->dev, &data->port0, on, usb_node); + __usb_port_power_on_off(data->dev, &data->port1, on, usb_node); + __usb_port_power_on_off(data->dev, &data->port2, on, usb_node); + __usb_port_power_on_off(data->dev, &data->port3, on, usb_node); + + mutex_unlock(&data->lock); + return 0; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(rtk_usb_init_port_power_on); +#endif /* MY_DEF_HERE */ + +static int __usb_port_enable(struct manager_data *data, struct port_data *port, + struct device_node *usb_node, bool enable) +{ + if (port->mac_node && usb_node && + port->mac_node->phandle == usb_node->phandle) { + if (enable) + port->enable |= BIT(0); + else + port->enable &= ~BIT(0); + } else if (port->slave_mac_node && usb_node && + port->slave_mac_node->phandle == usb_node->phandle) { + if (enable) + port->enable |= BIT(1); + else + port->enable &= ~BIT(1); + } + return 0; +} + +int rtk_usb_init_port_power_on_off(struct device *usb_dev, bool on) +{ + struct device_node *usb_node; + static struct manager_data *data; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + if (usb_dev == NULL) { + dev_err(data->dev, "%s ERROR no usb_dev", __func__); + return -ENODEV; + } + + usb_node = usb_dev->of_node; + + dev_info(data->dev, "%s for %s", __func__, dev_name(usb_dev)); + mutex_lock(&data->lock); + + if (!__usb_port_power_on_off(data->dev, &data->port0, on, usb_node)) + __usb_port_enable(data, &data->port0, usb_node, true); + else if (!__usb_port_power_on_off(data->dev, &data->port1, on, usb_node)) + __usb_port_enable(data, &data->port1, usb_node, true); + else if (!__usb_port_power_on_off(data->dev, &data->port2, on, usb_node)) + __usb_port_enable(data, &data->port2, usb_node, true); + else if (!__usb_port_power_on_off(data->dev, &data->port3, on, usb_node)) + __usb_port_enable(data, &data->port3, usb_node, true); + + mutex_unlock(&data->lock); + return 0; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(rtk_usb_init_port_power_on_off); +#endif /* MY_DEF_HERE */ + +int rtk_usb_remove_port_power_on_off(struct device *usb_dev, bool on) +{ + struct device_node *usb_node; + static struct manager_data *data; + + data = get_rtk_usb_manager(); + if (data == NULL) { + pr_err("%s ERROR no manager_data", __func__); + return -ENODEV; + } + if (usb_dev == NULL) { + dev_err(data->dev, "%s ERROR no usb_dev", __func__); + return -ENODEV; + } + + usb_node = usb_dev->of_node; + + dev_info(data->dev, "%s for %s", __func__, dev_name(usb_dev)); + mutex_lock(&data->lock); + + if (!__usb_port_power_on_off(data->dev, &data->port0, on, usb_node)) + __usb_port_enable(data, &data->port0, usb_node, false); + else if (!__usb_port_power_on_off(data->dev, &data->port1, on, usb_node)) + __usb_port_enable(data, &data->port1, usb_node, false); + else if (!__usb_port_power_on_off(data->dev, &data->port2, on, usb_node)) + __usb_port_enable(data, &data->port2, usb_node, false); + else if (!__usb_port_power_on_off(data->dev, &data->port3, on, usb_node)) + __usb_port_enable(data, &data->port3, usb_node, false); + + mutex_unlock(&data->lock); + return 0; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(rtk_usb_remove_port_power_on_off); +#endif /* MY_DEF_HERE */ + +static void __usb_gpio_init(struct device *dev, struct gpio_data *gpio) +{ + bool off = false; + + gpio->active_port = 0; + __gpio_on_off(dev, -1, gpio, off); + +} +static int rtk_usb_gpio_init(struct manager_data *data) +{ + __usb_gpio_init(data->dev, &data->gpio0); + __usb_gpio_init(data->dev, &data->gpio1); + __usb_gpio_init(data->dev, &data->gpio2); + __usb_gpio_init(data->dev, &data->gpio3); + + return 0; +} + +static int rtk_usb_manager_init(struct manager_data *data) +{ + struct device *dev = data->dev; + + dev_dbg(dev, "Realtek USB init ....\n"); + + __usb_set_pd_power(data, 1); + + if (data->disable_usb) { + dev_err(dev, "Realtek USB No any usb be enabled ....\n"); + return 0; + } + + __usb_init_clock_reset(data); + + rtk_usb_gpio_init(data); + + __rtk_usb_set_hw_pm_enable(data); + + dev_dbg(dev, "Realtek USB init Done\n"); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void __debug_dump_gpio_info(struct seq_file *s, struct gpio_data *gpio) +{ + if (!gpio) + return; + + seq_puts(s, " gpio info:\n"); + if (IS_ERR(gpio->gpio_desc)) { + seq_puts(s, " No gpio\n"); + return; + } + seq_printf(s, " gpio_num=%d\n", desc_to_gpio(gpio->gpio_desc)); + seq_printf(s, " active_port=0x%x active_port_mask=0x%x\n", + gpio->active_port, gpio->active_port_mask); + seq_printf(s, " power %s%s\n", + gpio->power_on?"on":"off", + gpio->power_low_active?" (power_low_active)":""); +} + +static void __debug_dump_port_info(struct seq_file *s, struct port_data *port) +{ + if (port->port_num < 0) + return; + + seq_printf(s, "port%d info:\n", port->port_num); + seq_printf(s, " port_num=%d\n", port->port_num); + seq_printf(s, " power_gpio@%p\n", port->power_gpio); + __debug_dump_gpio_info(s, port->power_gpio); + seq_printf(s, " mac_node=%s\n", + port->mac_node?port->mac_node->name:"NULL"); + seq_printf(s, " slave_mac_node=%s\n", + port->slave_mac_node?port->slave_mac_node->name:"NULL"); + seq_printf(s, " active=0x%x (enable_mask=0x%x)\n", + port->active, port->enable_mask); +} + +static int rtk_usb_debug_show(struct seq_file *s, void *unused) +{ + struct manager_data *data = s->private; + + seq_puts(s, "rtk usb manager info:\n"); + __debug_dump_port_info(s, &data->port0); + __debug_dump_port_info(s, &data->port1); + __debug_dump_port_info(s, &data->port2); + __debug_dump_port_info(s, &data->port3); + + return 0; +} + +static int rtk_usb_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb_debug_show, inode->i_private); +} + +static const struct file_operations rtk_usb_debug_fops = { + .open = rtk_usb_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void create_debug_files(struct manager_data *data) +{ + + dev_dbg(data->dev, "%s", __func__); + + data->debug_dir = debugfs_create_dir("usb_manager", usb_debug_root); + if (!data->debug_dir) { + dev_err(data->dev, "%s Error debug_dir is NULL", __func__); + return; + } + + if (!debugfs_create_file("debug", 0444, data->debug_dir, data, + &rtk_usb_debug_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(data->debug_dir); +} + +static inline void remove_debug_files(struct manager_data *data) +{ + debugfs_remove_recursive(data->debug_dir); +} +#endif //CONFIG_DEBUG_FS + +static ssize_t port0_power_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, "To Control Port 0\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"on\" > port0_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"off\" > port0_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "\n"); + ptr += n; + count -= n; + + if (data->port0.power_gpio) { + struct gpio_data *gpio = data->port0.power_gpio; + + n = scnprintf(ptr, count, "Now port0 %s\n", + gpio->power_on?"on":"off"); + ptr += n; + count -= n; + } else { + n = scnprintf(ptr, count, "port0 No control gpio\n"); + ptr += n; + count -= n; + } + + return ptr - buf; +} + +static ssize_t port0_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct device_node *usb_node; + + mutex_lock(&data->lock); + if (!strncmp(buf, "on", 2)) { + usb_node = data->port0.mac_node; + __usb_port_power_on_off(data->dev, &data->port0, true, + usb_node); + usb_node = data->port0.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port0, true, + usb_node); + } else if (!strncmp(buf, "off", 3)) { + usb_node = data->port0.mac_node; + __usb_port_power_on_off(data->dev, &data->port0, false, + usb_node); + usb_node = data->port0.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port0, false, + usb_node); + } else + dev_err(data->dev, "UNKNOWN input (%s)", buf); + + mutex_unlock(&data->lock); + return count; +} +static DEVICE_ATTR_RW(port0_power); + +static ssize_t port1_power_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, "To Control Port 1\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"on\" > port1_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"off\" > port1_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "\n"); + ptr += n; + count -= n; + + if (data->port1.power_gpio) { + struct gpio_data *gpio = data->port1.power_gpio; + + n = scnprintf(ptr, count, "Now port1 %s\n", + gpio->power_on?"on":"off"); + ptr += n; + count -= n; + } else { + n = scnprintf(ptr, count, "port1 No control gpio\n"); + ptr += n; + count -= n; + } + + return ptr - buf; +} + +static ssize_t port1_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct device_node *usb_node; + + mutex_lock(&data->lock); + if (!strncmp(buf, "on", 2)) { + usb_node = data->port1.mac_node; + __usb_port_power_on_off(data->dev, &data->port1, true, + usb_node); + usb_node = data->port1.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port1, true, + usb_node); + } else if (!strncmp(buf, "off", 3)) { + usb_node = data->port1.mac_node; + __usb_port_power_on_off(data->dev, &data->port1, false, + usb_node); + usb_node = data->port1.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port1, false, + usb_node); + } else + dev_err(data->dev, "UNKNOWN input (%s)", buf); + + mutex_unlock(&data->lock); + return count; +} +static DEVICE_ATTR_RW(port1_power); + +static ssize_t port2_power_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, "To Control Port 2\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"on\" > port2_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"off\" > port2_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "\n"); + ptr += n; + count -= n; + + if (data->port2.power_gpio) { + struct gpio_data *gpio = data->port2.power_gpio; + + n = scnprintf(ptr, count, "Now port2 %s\n", + gpio->power_on?"on":"off"); + ptr += n; + count -= n; + } else { + n = scnprintf(ptr, count, "port2 No control gpio\n"); + ptr += n; + count -= n; + } + + return ptr - buf; +} + +static ssize_t port2_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct device_node *usb_node; + + mutex_lock(&data->lock); + if (!strncmp(buf, "on", 2)) { + usb_node = data->port2.mac_node; + __usb_port_power_on_off(data->dev, &data->port2, true, + usb_node); + usb_node = data->port2.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port2, true, + usb_node); + + } else if (!strncmp(buf, "off", 3)) { + usb_node = data->port2.mac_node; + __usb_port_power_on_off(data->dev, &data->port2, false, + usb_node); + usb_node = data->port2.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port2, false, + usb_node); + } else + dev_err(data->dev, "UNKNOWN input (%s)", buf); + + mutex_unlock(&data->lock); + return count; +} +static DEVICE_ATTR_RW(port2_power); + +static ssize_t port3_power_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, "To Control Port 3\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"on\" > port3_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "echo \"off\" > port3_power\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, "\n"); + ptr += n; + count -= n; + + if (data->port3.power_gpio) { + struct gpio_data *gpio = data->port3.power_gpio; + + n = scnprintf(ptr, count, "Now port3 %s\n", + gpio->power_on?"on":"off"); + ptr += n; + count -= n; + } else { + n = scnprintf(ptr, count, "port3 No control gpio\n"); + ptr += n; + count -= n; + } + + return ptr - buf; +} + +static ssize_t port3_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct device_node *usb_node; + + mutex_lock(&data->lock); + if (!strncmp(buf, "on", 2)) { + usb_node = data->port3.mac_node; + __usb_port_power_on_off(data->dev, &data->port3, true, + usb_node); + usb_node = data->port3.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port3, true, + usb_node); + } else if (!strncmp(buf, "off", 3)) { + usb_node = data->port3.mac_node; + __usb_port_power_on_off(data->dev, &data->port3, false, + usb_node); + usb_node = data->port3.slave_mac_node; + __usb_port_power_on_off(data->dev, &data->port3, false, + usb_node); + } else + dev_err(data->dev, "UNKNOWN input (%s)", buf); + + mutex_unlock(&data->lock); + return count; +} +static DEVICE_ATTR_RW(port3_power); + +static ssize_t iso_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + mutex_lock(&data->lock); + + n = scnprintf(ptr, count, "usb_iso_mode %s\n", + data->usb_iso_mode?"Enable":"Disable"); + ptr += n; + count -= n; + + mutex_unlock(&data->lock); + + return ptr - buf; +} + +static ssize_t iso_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->lock); + if (!strncmp(buf, "enable", 6)) + data->usb_iso_mode = true; + else if (!strncmp(buf, "disable", 7)) + data->usb_iso_mode = false; + else + dev_err(data->dev, "UNKNOWN input (%s)", buf); + + mutex_unlock(&data->lock); + return count; +} +DEVICE_ATTR_RW(iso_mode); + +static int __usb_bind_driver(struct manager_data *data, + struct port_data *port) +{ + struct device_node *usb_node; + + dev_info(data->dev, "%s: To bind usb port%d\n", + __func__, port->port_num); + + usb_node = port->mac_node; + if (usb_node != NULL) { + struct platform_device *pdev; + struct device *dev; + + pdev = of_find_device_by_node(usb_node); + if (pdev != NULL) + dev = &pdev->dev; + + if (dev && !dev->driver) { + int ret = 0; + + if (dev->parent && dev->bus->need_parent_lock) + device_lock(dev->parent); + ret = device_attach(dev); + if (dev->parent && dev->bus->need_parent_lock) + device_unlock(dev->parent); + if (ret < 0) + dev_err(data->dev, + "%s Error: device_attach fail (ret=%d)", + __func__, ret); + else + dev_info(data->dev, + "%s device %s attach OK\n", + __func__, dev_name(dev)); + put_device(dev); + } + } + usb_node = port->slave_mac_node; + if (usb_node != NULL) { + struct platform_device *pdev; + struct device *dev; + + pdev = of_find_device_by_node(usb_node); + if (pdev != NULL) + dev = &pdev->dev; + + if (dev && !dev->driver) { + int ret = 0; + + if (dev->parent && dev->bus->need_parent_lock) + device_lock(dev->parent); + ret = device_attach(dev); + if (dev->parent && dev->bus->need_parent_lock) + device_unlock(dev->parent); + if (ret < 0) + dev_err(data->dev, + "%s Error: device_attach fail (ret=%d)", + __func__, ret); + else + dev_info(data->dev, + "%s device %s attach OK\n", + __func__, dev_name(dev)); + put_device(dev); + } + } + return 0; +} + +static int __usb_unbind_driver(struct manager_data *data, + struct port_data *port) +{ + struct device_node *usb_node; + + dev_info(data->dev, "%s: To unbind usb port%d\n", + __func__, port->port_num); + + usb_node = port->mac_node; + if (usb_node != NULL) { + struct platform_device *pdev; + struct device *dev; + + pdev = of_find_device_by_node(usb_node); + if (pdev != NULL) + dev = &pdev->dev; + + if (dev && dev->driver) { + if (dev->parent && dev->bus->need_parent_lock) + device_lock(dev->parent); + device_release_driver(dev); + if (dev->parent && dev->bus->need_parent_lock) + device_unlock(dev->parent); + put_device(dev); + } + } + usb_node = port->slave_mac_node; + if (usb_node != NULL) { + struct platform_device *pdev; + struct device *dev; + + pdev = of_find_device_by_node(usb_node); + if (pdev != NULL) + dev = &pdev->dev; + + if (dev && dev->driver) { + if (dev->parent && dev->bus->need_parent_lock) + device_lock(dev->parent); + device_release_driver(dev); + if (dev->parent && dev->bus->need_parent_lock) + device_unlock(dev->parent); + put_device(dev); + } + } + return 0; +} + +static ssize_t port0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now Port0 is %s\n", + data->port0.enable?"enable":"disable"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo disable > port0 ==> to disable port0\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo enable > port0 ==> to enable port0\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t port0_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct port_data *port = &data->port0; + + if (!strncmp(buf, "disable", 7)) { + if ((port->enable & port->enable_mask) == port->enable_mask) { + __usb_unbind_driver(data, port); + __usb_port_clock_reset_disable(data, port); + dev_info(data->dev, "port0 disable OK\n"); + } else { + dev_info(data->dev, "port0 is disable\n"); + } + } else if (!strncmp(buf, "enable", 6)) { + if (!port->enable && port->enable_mask) { + __usb_port_clock_reset_enable(data, port); + __usb_bind_driver(data, port); + dev_info(data->dev, "port0 enable OK\n"); + } else { + dev_info(data->dev, "port0 is enable\n"); + } + } + + return count; +} +static DEVICE_ATTR_RW(port0); + +static ssize_t port1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now Port1 is %s\n", + data->port1.enable?"enable":"disable"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo disable > port1 ==> to disable port1\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo enable > port1 ==> to enable port1\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t port1_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct port_data *port = &data->port1; + + if (!strncmp(buf, "disable", 7)) { + if ((port->enable & port->enable_mask) == port->enable_mask) { + __usb_unbind_driver(data, port); + __usb_port_clock_reset_disable(data, port); + dev_info(data->dev, "port1 disable OK\n"); + } else { + dev_info(data->dev, "port1 is disable\n"); + } + } else if (!strncmp(buf, "enable", 6)) { + if (!port->enable && port->enable_mask) { + __usb_port_clock_reset_enable(data, port); + __usb_bind_driver(data, port); + dev_info(data->dev, "port1 enable OK\n"); + } else { + dev_info(data->dev, "port1 is enable\n"); + } + } + + return count; +} +static DEVICE_ATTR_RW(port1); + +static ssize_t port2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now Port2 is %s\n", + data->port2.enable?"enable":"disable"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo disable > port2 ==> to disable port2\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo enable > port2 ==> to enable port2\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t port2_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct port_data *port = &data->port2; + + if (!strncmp(buf, "disable", 7)) { + if ((port->enable & port->enable_mask) == port->enable_mask) { + __usb_unbind_driver(data, port); + __usb_port_clock_reset_disable(data, port); + dev_info(data->dev, "port2 disable OK\n"); + } else { + dev_info(data->dev, "port2 is disable\n"); + } + } else if (!strncmp(buf, "enable", 6)) { + if (!port->enable && port->enable_mask) { + __usb_port_clock_reset_enable(data, port); + __usb_bind_driver(data, port); + dev_info(data->dev, "port2 enable OK\n"); + } else { + dev_info(data->dev, "port2 is enable\n"); + } + } + + return count; +} +static DEVICE_ATTR_RW(port2); + +static ssize_t port3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct manager_data *data = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now Port3 is %s\n", + data->port3.enable?"enable":"disable"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo disable > port3 ==> to disable port3\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "echo enable > port3 ==> to enable port3\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t port3_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct port_data *port = &data->port3; + + if (!strncmp(buf, "disable", 7)) { + if ((port->enable & port->enable_mask) == port->enable_mask) { + __usb_unbind_driver(data, port); + __usb_port_clock_reset_disable(data, port); + dev_info(data->dev, "port3 disable OK\n"); + } else { + dev_info(data->dev, "port3 is disable\n"); + } + } else if (!strncmp(buf, "enable", 6)) { + if (!port->enable && port->enable_mask) { + __usb_port_clock_reset_enable(data, port); + __usb_bind_driver(data, port); + dev_info(data->dev, "port3 enable OK\n"); + } else { + dev_info(data->dev, "port3 is enable\n"); + } + } + + return count; +} +static DEVICE_ATTR_RW(port3); + +static inline void create_device_files(struct manager_data *data) +{ + struct device *dev = data->dev; + + dev_dbg(data->dev, "%s", __func__); + + if (data->port0.port_num >= 0) { + device_create_file(dev, &dev_attr_port0_power); + device_create_file(dev, &dev_attr_port0); + } + + if (data->port1.port_num >= 0) { + device_create_file(dev, &dev_attr_port1_power); + device_create_file(dev, &dev_attr_port1); + } + + if (data->port2.port_num >= 0) { + device_create_file(dev, &dev_attr_port2_power); + device_create_file(dev, &dev_attr_port2); + } + + if (data->port3.port_num >= 0) { + device_create_file(dev, &dev_attr_port3_power); + device_create_file(dev, &dev_attr_port3); + } + + device_create_file(dev, &dev_attr_iso_mode); +} + +static inline void remove_device_files(struct manager_data *data) +{ + struct device *dev = data->dev; + + dev_dbg(data->dev, "%s", __func__); + + if (data->port0.port_num >= 0) { + device_remove_file(dev, &dev_attr_port0_power); + device_remove_file(dev, &dev_attr_port0); + } + + if (data->port1.port_num >= 0) { + device_remove_file(dev, &dev_attr_port1_power); + device_remove_file(dev, &dev_attr_port1); + } + + if (data->port2.port_num >= 0) { + device_remove_file(dev, &dev_attr_port2_power); + device_remove_file(dev, &dev_attr_port2); + } + + if (data->port3.port_num >= 0) { + device_remove_file(dev, &dev_attr_port3_power); + device_remove_file(dev, &dev_attr_port3); + } + + device_remove_file(dev, &dev_attr_iso_mode); +} + +static inline int __of_parse_gpio_setting(struct manager_data *data, + struct gpio_data *gpio, + struct device_node *sub_node) +{ + if (!sub_node) { + gpio->gpio_desc = ERR_PTR(-ENOSYS); + return -1; + } + + gpio->node = sub_node; + + gpio->gpio_desc = gpiod_get_from_of_node(sub_node, "realtek,power-gpio", + 0, GPIOD_OUT_HIGH, "usb-power-gpio"); + + if (IS_ERR(gpio->gpio_desc)) { + dev_info(data->dev, "%s power-gpio no found\n", __func__); + return -1; + } + + if (of_property_read_bool(sub_node, "power_low_active")) + gpio->power_low_active = true; + else + gpio->power_low_active = false; + + return 0; +} + +static int parse_gpio_setting(struct manager_data *data, + struct device_node *node) +{ + struct device *dev = data->dev; + struct device_node *sub_node; + + sub_node = of_get_child_by_name(node, "gpio0"); + + if (__of_parse_gpio_setting(data, &data->gpio0, sub_node)) { + dev_dbg(dev, "node gpio0 no found in dts\n"); + } else { + dev_info(dev, "%s get power-gpio (id=%d) OK\n", + __func__, desc_to_gpio(data->gpio0.gpio_desc)); + } + + sub_node = of_get_child_by_name(node, "gpio1"); + if (__of_parse_gpio_setting(data, &data->gpio1, sub_node)) { + dev_dbg(dev, "node gpio1 no found in dts\n"); + } else { + dev_info(dev, "%s get power-gpio (id=%d) OK\n", + __func__, desc_to_gpio(data->gpio1.gpio_desc)); + } + + sub_node = of_get_child_by_name(node, "gpio2"); + if (__of_parse_gpio_setting(data, &data->gpio2, sub_node)) { + dev_dbg(dev, "node gpio2 no found in dts\n"); + } else { + dev_info(dev, "%s get power-gpio (id=%d) OK\n", + __func__, desc_to_gpio(data->gpio2.gpio_desc)); + } + + sub_node = of_get_child_by_name(node, "gpio3"); + if (__of_parse_gpio_setting(data, &data->gpio3, sub_node)) { + dev_dbg(dev, "node gpio3 no found in dts\n"); + } else { + dev_info(dev, "%s get power-gpio (id=%d) OK\n", + __func__, desc_to_gpio(data->gpio3.gpio_desc)); + } + + return 0; +} + +static inline struct gpio_data *__of_parse_port_gpio_mapping( + struct manager_data *data, + struct device_node *port_node, int port_num) +{ + struct device_node *gpio_node; + struct gpio_data *gpio; + + gpio_node = of_parse_phandle(port_node, "usb_gpio", 0); + + gpio = &data->gpio0; + if (!IS_ERR(gpio->gpio_desc) && + gpio->node && gpio_node && + gpio->node->phandle == gpio_node->phandle) { + gpio->active_port_mask |= BIT(port_num); + dev_info(data->dev, "%s port%d mapping gpio_num=%d\n", + __func__, port_num, desc_to_gpio(gpio->gpio_desc)); + return gpio; + } + + gpio = &data->gpio1; + if (!IS_ERR(gpio->gpio_desc) && + gpio->node && gpio_node && + gpio->node->phandle == gpio_node->phandle) { + gpio->active_port_mask |= BIT(port_num); + dev_info(data->dev, "%s port%d mapping gpio_num=%d\n", + __func__, port_num, desc_to_gpio(gpio->gpio_desc)); + return gpio; + } + + gpio = &data->gpio2; + if (!IS_ERR(gpio->gpio_desc) && + gpio->node && gpio_node && + gpio->node->phandle == gpio_node->phandle) { + gpio->active_port_mask |= BIT(port_num); + dev_info(data->dev, "%s port%d mapping gpio_num=%d\n", + __func__, port_num, desc_to_gpio(gpio->gpio_desc)); + return gpio; + } + + gpio = &data->gpio3; + if (!IS_ERR(gpio->gpio_desc) && + gpio->node && gpio_node && + gpio->node->phandle == gpio_node->phandle) { + gpio->active_port_mask |= BIT(port_num); + dev_info(data->dev, "%s port%d mapping gpio_num=%d\n", + __func__, port_num, desc_to_gpio(gpio->gpio_desc)); + return gpio; + } + + dev_info(data->dev, "%s port%d No mapping GPIO\n", __func__, port_num); + return NULL; +} + +static inline void __of_parse_port_setting(struct manager_data *data, + struct port_data *port, + struct device_node *port_node, int port_num) +{ + if (!port_node) { + port->port_num = -1; + return; + } + + port->port_num = port_num; + + port->mac_node = of_parse_phandle(port_node, "usb", 0); + port->slave_mac_node = of_parse_phandle(port_node, "usb", 1); + + port->active = 0; + port->enable_mask = 0; + port->enable = 0; + + if (port->mac_node && + of_device_is_available(port->mac_node)) { + pr_info("mac_node: %s status is okay\n", + port->mac_node->name); + port->enable_mask |= BIT(0); + } + if (port->slave_mac_node && + of_device_is_available(port->slave_mac_node)) { + pr_info("slave_mac_node: %s status is okay\n", + port->slave_mac_node->name); + port->enable_mask |= BIT(1); + } + + if (port->enable_mask) + port->power_gpio = __of_parse_port_gpio_mapping(data, + port_node, port->port_num); + + port->node = port_node; + + port->support_usb3 = true; + if (of_property_read_bool(port_node, "disable_usb3")) + port->support_usb3 = false; +} + +static int parse_port_setting(struct manager_data *data, + struct device_node *node) +{ + struct device_node *sub_node; + + data->disable_usb = true; + + sub_node = of_get_child_by_name(node, "port0"); + __of_parse_port_setting(data, &data->port0, sub_node, 0); + sub_node = of_get_child_by_name(node, "port1"); + __of_parse_port_setting(data, &data->port1, sub_node, 1); + sub_node = of_get_child_by_name(node, "port2"); + __of_parse_port_setting(data, &data->port2, sub_node, 2); + sub_node = of_get_child_by_name(node, "port3"); + __of_parse_port_setting(data, &data->port3, sub_node, 3); + + if (port_can_enable(&data->port0) || + port_can_enable(&data->port1) || + port_can_enable(&data->port2) || + port_can_enable(&data->port3)) + data->disable_usb = false; + + return 0; +} + +static void rtk_usb_platform_init(struct manager_data *data) +{ + int (*rtk_usb_init)(struct rtk_usb_ops *ops) = NULL; + const struct soc_device_attribute *soc_att_match = NULL; + struct soc_device_attribute rtk_soc[] = { + { + .family = "Realtek Phoenix", + .data = (void *)rtk_usb_rtd119x_init, + }, + { + .family = "Realtek Kylin", + .data = (void *)rtk_usb_rtd129x_init, + }, + { + .family = "Realtek Hercules", + .data = (void *)rtk_usb_rtd139x_init, + }, + { + .family = "Realtek Thor", + .data = (void *)rtk_usb_rtd16xx_init, + }, + { + .family = "Realtek Hank", + .data = (void *)rtk_usb_rtd13xx_init, + }, + { + .family = "Realtek Stark", + .data = (void *)rtk_usb_rtd16xxb_init, + }, + { + .family = "Realtek Groot", + .data = (void *)rtk_usb_rtd1312c_init, + }, + { + /* empty */ + } + }; + + if (!data) { + pr_err("%s ERROR: data is NULL\n", __func__); + return; + } + data->rtk_usb = kzalloc(sizeof(struct rtk_usb_ops), GFP_KERNEL); + + soc_att_match = soc_device_match(rtk_soc); + if (soc_att_match) { + pr_info("%s match chip: %s\n", __func__, + soc_att_match->family); + rtk_usb_init = (void *)soc_att_match->data; + if (rtk_usb_init) + rtk_usb_init(data->rtk_usb); + else + pr_err("%s ERROR: rtk_usb_init is NULL\n", __func__); + } else { + pr_err("%s ERROR: no match chip\n", __func__); + } +} + +static void rtk_usb_platform_free(struct manager_data *data) +{ + kfree(data->rtk_usb); + data->rtk_usb = NULL; +} + +static void rtk_usb_set_clock_reset_name(struct manager_data *data) +{ + struct port_data *port; + + /* For All port */ + snprintf(data->clock, CLOCK_RESET_NAME_MAX, "%s", CLOCK_NAME_USB); + snprintf(data->reset_usb, CLOCK_RESET_NAME_MAX, "%s", RESET_NAME_USB); + snprintf(data->reset_type_c, CLOCK_RESET_NAME_MAX, "%s", + RESET_NAME_TYPEC); + /* For Port 0 */ + port = &data->port0; + snprintf(port->clock, CLOCK_RESET_NAME_MAX, "%s", CLOCK_NAME_USB_PORT0); + snprintf(port->reset_u2phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U2PHY0); + snprintf(port->reset_u3phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3PHY0); + snprintf(port->reset_u3mdio, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3MDIO0); + snprintf(port->reset_usb_mac, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_USB_MAC0); + /* For Port 1 */ + port = &data->port1; + snprintf(port->clock, CLOCK_RESET_NAME_MAX, "%s", CLOCK_NAME_USB_PORT1); + snprintf(port->reset_u2phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U2PHY1); + snprintf(port->reset_u3phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3PHY1); + snprintf(port->reset_u3mdio, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3MDIO1); + snprintf(port->reset_usb_mac, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_USB_MAC1); + /* For Port 2 */ + port = &data->port2; + snprintf(port->clock, CLOCK_RESET_NAME_MAX, "%s", CLOCK_NAME_USB_PORT2); + snprintf(port->reset_u2phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U2PHY2); + snprintf(port->reset_u3phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3PHY2); + snprintf(port->reset_u3mdio, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3MDIO2); + snprintf(port->reset_usb_mac, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_USB_MAC2); + /* For Port 3 */ + port = &data->port3; + snprintf(port->clock, CLOCK_RESET_NAME_MAX, "%s", CLOCK_NAME_USB_PORT3); + snprintf(port->reset_u2phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U2PHY3); + snprintf(port->reset_u3phy, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3PHY3); + snprintf(port->reset_u3mdio, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_U3MDIO3); + snprintf(port->reset_usb_mac, CLOCK_RESET_NAME_MAX, + "%s", RESET_NAME_USB_MAC3); +} + +static int rtk_usb_manager_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *sub_node; + struct manager_data *data; + int ret = 0; + unsigned long probe_time = jiffies; + + dev_info(dev, "ENTER %s", __func__); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + + rtk_usb_platform_init(data); + + rtk_usb_set_clock_reset_name(data); + + if (node && of_device_is_available(node)) { + if (of_property_read_bool(node, "usb_iso_mode")) + data->usb_iso_mode = true; + else + data->usb_iso_mode = false; + + if (of_property_read_bool(node, "en_usb_storage_reprobe")) + data->en_usb_storage_reprobe = true; + else + data->en_usb_storage_reprobe = false; + + if (of_property_read_bool(node, "rescue_usb")) + data->rescue_usb = true; + else + data->rescue_usb = false; + + if (of_property_read_bool(node, "dis_hub_autosuspend")) + data->dis_hub_autosuspend = true; + else + data->dis_hub_autosuspend = false; + } + + if (node && of_device_is_available(node)) { + + ret = parse_gpio_setting(data, node); + + ret = parse_port_setting(data, node); + + sub_node = of_get_child_by_name(node, "rtk_usb"); + if (sub_node) + rtk_usb_soc_init(data->rtk_usb, sub_node); + } + + mutex_init(&data->lock); + + rtk_usb_manager_init(data); + + platform_set_drvdata(pdev, data); + + data->wq_usb_manager = create_singlethread_workqueue("rtk_usb_manager"); + +#ifdef CONFIG_DEBUG_FS + create_debug_files(data); +#endif + + create_device_files(data); + + dev_info(&pdev->dev, "%s OK (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); + return 0; +} + +static int rtk_usb_manager_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct manager_data *data = dev_get_drvdata(dev); + + dev_info(&pdev->dev, "%s\n", __func__); + + remove_device_files(data); + +#ifdef CONFIG_DEBUG_FS + remove_debug_files(data); +#endif + + rtk_usb_soc_free(data->rtk_usb); + + rtk_usb_platform_free(data); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rtk_usb_manager_match[] = { + { .compatible = "realtek,usb-manager" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtk_usb_manager_match); +#endif + +#ifdef CONFIG_PM_SLEEP + +static int rtk_usb_manager_prepare(struct device *dev) +{ + struct manager_data *data = dev_get_drvdata(dev); + int ret = 0; + + dev_info(dev, "[USB] Enter %s\n", __func__); + if (!data) { + dev_err(dev, "[USB] %s No manager_data!\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + dev_info(dev, "[USB] %s Suspend mode\n", __func__); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return ret; +} + +static void rtk_usb_manager_complete(struct device *dev) +{ + struct manager_data *data = dev_get_drvdata(dev); + + dev_info(dev, "[USB] Enter %s\n", __func__); + + if (!data) { + dev_err(dev, "[USB] %s No manager_data!\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s S1 (Standby mode)\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + dev_info(dev, "[USB] %s S3 (Suspend-to-RAM mode)\n", __func__); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); +} + +static int rtk_usb_manager_suspend(struct device *dev) +{ + struct manager_data *data = dev_get_drvdata(dev); + + dev_info(dev, "[USB] Enter %s\n", __func__); + + if (!data) { + dev_err(dev, "[USB] %s No manager_data!\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s S1 (Standby mode)\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + //For suspend mode + dev_info(dev, "[USB] %s S3 (Suspend-to-RAM mode) %susb_iso_mode\n", + __func__, data->usb_iso_mode?"":"NOT "); + if (!data->usb_iso_mode) { + __usb_port_gpio_off(data); + __usb_set_pd_power(data, 0); + __usb_clear_clock_reset(data); + } else { + __usb_port_suspend(data); + } + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return 0; +} + +static int rtk_usb_manager_resume(struct device *dev) +{ + struct manager_data *data = dev_get_drvdata(dev); + struct clk *clk_usb = USB_clk_get(NULL, "clk_en_usb"); + + dev_info(dev, "[USB] Enter %s\n", __func__); + + if (!data) { + dev_err(dev, "[USB] %s No manager_data!\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s S1 (Standby mode)\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + //For suspend mode + dev_info(dev, "[USB] %s S3 (Suspend-to-RAM mode) %susb_iso_mode\n", + __func__, data->usb_iso_mode?"":"NOT "); + + if (!data->usb_iso_mode) { + __usb_set_pd_power(data, 1); + + clk_disable_unprepare(clk_usb); + __usb_init_clock_reset(data); + + __rtk_usb_set_hw_pm_enable(data); + + } else { + __usb_port_resume(data); + } + __usb_port_gpio_on(data); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops rtk_usb_manager_pm_ops = { + .prepare = rtk_usb_manager_prepare, + .complete = rtk_usb_manager_complete, + SET_LATE_SYSTEM_SLEEP_PM_OPS(rtk_usb_manager_suspend, + rtk_usb_manager_resume) +}; + +#define DEV_PM_OPS (&rtk_usb_manager_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static void rtk_usb_manager_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct manager_data *data = dev_get_drvdata(dev); + + dev_info(dev, "[USB] Enter %s S5 (shutdown)\n", + __func__); + + rtk_usb_gpio_init(data); + __usb_set_pd_power(data, 0); + __usb_clear_clock_reset(data); + + dev_info(dev, "[USB] Exit %s\n", __func__); +} + +static struct platform_driver rtk_usb_manager_driver = { + .probe = rtk_usb_manager_probe, + .remove = rtk_usb_manager_remove, + .driver = { + .name = "rtk-usb-manager", + .of_match_table = of_match_ptr(rtk_usb_manager_match), + .pm = DEV_PM_OPS, + }, + .shutdown = rtk_usb_manager_shutdown, +}; + +static int __init rtk_usb_manager_driver_init(void) +{ + return platform_driver_register(&(rtk_usb_manager_driver)); +} +subsys_initcall_sync(rtk_usb_manager_driver_init); + +static void __exit rtk_usb_manager_driver_exit(void) +{ + platform_driver_unregister(&(rtk_usb_manager_driver)); +} +#if defined(MY_DEF_HERE) +module_exit(rtk_usb_manager_driver_exit); +#endif /* MY_DEF_HERE */ + +MODULE_ALIAS("platform:rtk-usb-manager"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/realtek/common/rtk_usb_rtd119x.c b/drivers/soc/realtek/common/rtk_usb_rtd119x.c new file mode 100644 index 000000000000..05b633e9d9a5 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd119x.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtk_usb.c + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include + +#include "rtk_usb.h" + +struct rtk_usb { + struct power_ctrl_reg { + } power_ctrl_reg; + + bool usb_power_cut; +}; + +static struct rtk_usb *rtk_usb; + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *sub_node) +{ + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + + return 0; +} + +int rtk_usb_rtd119x_init(struct rtk_usb_ops *ops) +{ + + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_usb_rtd129x.c b/drivers/soc/realtek/common/rtk_usb_rtd129x.c new file mode 100644 index 000000000000..4b73bdf945b2 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd129x.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtk_usb.c + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include +#include +#include +//#include + +#include "rtk_usb.h" + +static struct soc_device_attribute rtk_soc_rtd1296[] = { + { + .family = "Realtek Kylin", + .soc_id = "RTD1296", + }, + { + /* empty */ + } +}; + +static struct soc_device_attribute rtk_soc_a00[] = { + { + .revision = "A00", + }, + { + /* empty */ + } +}; + +static struct soc_device_attribute rtk_soc_BXX[] = { + { + .revision = "B0*", + }, + { + /* empty */ + } +}; + +struct rtk_usb { + struct power_ctrl_reg { + u32 usb_ctrl; + /* Port 0~2 */ + u32 usb0_sram_pwr; + u32 usb0_sram_pwr_ctrl; + /* Port 3 */ + u32 usb1_sram_pwr; + u32 usb1_sram_pwr_ctrl; + /* l4_icg */ + u32 p0_l4_icg; + u32 p1_l4_icg; + u32 p2_l4_icg; + u32 p3_l4_icg; + + /* for power cut */ + u32 usb_phy_ctrl; + + u32 p0_utmi_reset; + u32 p1_utmi_reset; + u32 p2_utmi_reset; + u32 p3_utmi_reset; + + u32 p0_pipe_reset; + u32 p1_pipe_reset; + u32 p2_pipe_reset; + u32 p3_pipe_reset; + + /* for suspend */ + u32 p0_gusb2phycfg; + u32 p0_gusb3pipectl; + + u32 p1_gusb2phycfg; + u32 p1_gusb3pipectl; + + u32 p2_gusb2phycfg; + u32 p2_gusb3pipectl; + + u32 p3_gusb2phycfg; + u32 p3_gusb3pipectl; + + u32 usb_charger; + } power_ctrl_reg; + + bool usb_power_cut; + + struct type_c { + u32 usb_typec_ctrl_cc1_0; + } type_c; +}; + +static struct rtk_usb *rtk_usb; + +#define TYPE_C_EN_SWITCH BIT(29) +#define TYPE_C_TxRX_sel (BIT(28) | BIT(27)) +#define TYPE_C_SWITCH_MASK (TYPE_C_EN_SWITCH | TYPE_C_TxRX_sel) +#define TYPE_C_enable_cc1 TYPE_C_EN_SWITCH +#define TYPE_C_enable_cc2 (TYPE_C_EN_SWITCH | TYPE_C_TxRX_sel) +#define TYPE_C_disable_cc ~TYPE_C_SWITCH_MASK +#define disable_cc 0x0 +#define enable_cc1 0x1 +#define enable_cc2 0x2 + +/* set usb charger power */ +static void usb_set_charger_power(struct rtk_usb *rtk_usb, unsigned int val) +{ + void __iomem *reg_charger; + + if (!rtk_usb || !rtk_usb->power_ctrl_reg.usb_charger) + return; + + reg_charger = ioremap(rtk_usb->power_ctrl_reg.usb_charger, 0x4); + + pr_debug("set usb_charger to 0x%08x\n", val); + + writel(val, reg_charger); + + iounmap(reg_charger); +} + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + void __iomem *reg; + + if (!rtk_usb) + return 0; + + switch (port_num) { + case USB_PORT_0: + if (rtk_usb->power_ctrl_reg.p0_l4_icg) { + reg = ioremap(rtk_usb->power_ctrl_reg.p0_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_1: + if (rtk_usb->power_ctrl_reg.p1_l4_icg) { + reg = ioremap(rtk_usb->power_ctrl_reg.p1_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_2: + if (rtk_usb->power_ctrl_reg.p2_l4_icg) { + reg = ioremap(rtk_usb->power_ctrl_reg.p3_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_3: + if (rtk_usb->power_ctrl_reg.p3_l4_icg) { + reg = ioremap(rtk_usb->power_ctrl_reg.p3_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + default: + pr_err("%s Error Port num %d\n", __func__, port_num); + break; + } + + return 0; +} + +static int __isolate_phy_from_a_to_d(struct rtk_usb *rtk_usb) +{ + void __iomem *reg; + + /* isolate UPHY A->D */ + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + + pr_debug("set USB Analog phy power off\n"); + + if (rtk_usb->power_ctrl_reg.usb_phy_ctrl) { + reg = ioremap(rtk_usb->power_ctrl_reg.usb_phy_ctrl, 0x4); + writel(BIT(0) | BIT(1) | readl(reg), reg); + iounmap(reg); + } + if (rtk_usb->power_ctrl_reg.p0_utmi_reset) { + reg = ioremap(rtk_usb->power_ctrl_reg.p0_utmi_reset, 0x4); + writel(BIT(0) | readl(reg), reg); + iounmap(reg); + } + if (rtk_usb->power_ctrl_reg.p1_utmi_reset) { + reg = ioremap(rtk_usb->power_ctrl_reg.p1_utmi_reset, 0x4); + writel(BIT(0) | readl(reg), reg); + iounmap(reg); + } + if (rtk_usb->power_ctrl_reg.p2_utmi_reset) { + reg = ioremap(rtk_usb->power_ctrl_reg.p2_utmi_reset, 0x4); + writel(BIT(0) | readl(reg), reg); + iounmap(reg); + } + if (soc_device_match(rtk_soc_rtd1296) && + rtk_usb->power_ctrl_reg.p3_utmi_reset) { + reg = ioremap(rtk_usb->power_ctrl_reg.p3_utmi_reset, 0x4); + writel(BIT(0) | readl(reg), reg); + iounmap(reg); + } + if (rtk_usb->power_ctrl_reg.usb_ctrl) { + reg = ioremap(rtk_usb->power_ctrl_reg.usb_ctrl, 0x4); + writel(~(BIT(4) | BIT(5) | BIT(6)) & readl(reg), reg); + + iounmap(reg); + } + pr_debug("%s END\n", __func__); + + return 0; +} + +static inline void __power_control_set_power(const char *name, bool power_on) +{ +#if 0 + struct power_control *pctrl = power_control_get(name); + + if (!pctrl) { + pr_debug("%s: Failed to get power_control %s\n", + __func__, name); + return; + } + if (power_on) + power_control_power_on(pctrl); + else + power_control_power_off(pctrl); +#endif +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + + if (rtk_usb->power_ctrl_reg.usb_ctrl && + rtk_usb->power_ctrl_reg.usb0_sram_pwr && + rtk_usb->power_ctrl_reg.usb0_sram_pwr_ctrl && + rtk_usb->power_ctrl_reg.usb1_sram_pwr && + rtk_usb->power_ctrl_reg.usb1_sram_pwr_ctrl) { + void __iomem *usb_ctrl = + ioremap(rtk_usb->power_ctrl_reg.usb_ctrl, 0x4); + void __iomem *usb0_sram_pwr = + ioremap(rtk_usb->power_ctrl_reg.usb0_sram_pwr, 0x4); + void __iomem *usb0_sram_pwr_ctrl = + ioremap(rtk_usb->power_ctrl_reg.usb0_sram_pwr_ctrl, + 0x4); + void __iomem *usb1_sram_pwr = + ioremap(rtk_usb->power_ctrl_reg.usb1_sram_pwr, 0x4); + void __iomem *usb1_sram_pwr_ctrl = + ioremap(rtk_usb->power_ctrl_reg.usb1_sram_pwr_ctrl, + 0x4); + + pr_info("%s power_%s ([0x%x=0x%08x)\n", __func__, + power_on?"on":"off", + rtk_usb->power_ctrl_reg.usb_ctrl, readl(usb_ctrl)); + + if (power_on) { + pr_debug("%s power_on\n", __func__); + + pr_debug("set usb_power_domain/p0 on\n"); +#if 1 + /* set power gating control */ + writel((BIT(0) | BIT(4) | BIT(6)) | + readl(usb_ctrl), usb_ctrl); + /* port0-port2 sram power */ + //writel(0, usb0_sram_pwr); + writel(0x00000f00, usb0_sram_pwr_ctrl); + /* port3 sram power */ + if (soc_device_match(rtk_soc_rtd1296)) { + pr_info("set usb_power_domain/p3 on\n"); + writel((BIT(1) | BIT(5)) | + readl(usb_ctrl), usb_ctrl); + //writel(0, usb1_sram_pwr); + if (soc_device_match(rtk_soc_a00)) + writel(0x00000f05, usb1_sram_pwr_ctrl); + else + writel(0x00000f00, usb1_sram_pwr_ctrl); + } + /* disable isolation cell */ + writel(~(BIT(8) | BIT(9)) & readl(usb_ctrl), usb_ctrl); +#else + __power_control_set_power("pctrl_usb_p0_mac", 1); + __power_control_set_power("pctrl_usb_p0_phy", 1); + __power_control_set_power("pctrl_usb_p0_iso", 0); + if (soc_device_match(rtk_soc_rtd1296)) { + pr_info("set usb_power_domain/p3 on\n"); + __power_control_set_power("pctrl_usb_p3_phy", + 1); + __power_control_set_power("pctrl_usb_p3_mac", + 1); + __power_control_set_power("pctrl_usb_p3_iso", + 0); + } +#endif + } else { + pr_debug("%s power_off\n", __func__); + __isolate_phy_from_a_to_d(rtk_usb); + if (rtk_usb->usb_power_cut && + soc_device_match(rtk_soc_BXX)) { + writel((BIT(8) | BIT(9)) | readl(usb_ctrl), + usb_ctrl); + // port0-port2 sram + writel(0, usb0_sram_pwr); + writel(0x00000f01, usb0_sram_pwr_ctrl); + // port3 sram + writel(0, usb1_sram_pwr); + writel(0x00000f01, usb1_sram_pwr_ctrl); + + writel(~(BIT(0) | BIT(1) | BIT(4) | BIT(5) | + BIT(6)) & readl(usb_ctrl), usb_ctrl); + } + } + pr_info("set power_domain %s ([0x%x]=0x%08x)\n", + power_on?"on":"off", + rtk_usb->power_ctrl_reg.usb_ctrl, readl(usb_ctrl)); + iounmap(usb_ctrl); + iounmap(usb0_sram_pwr); + iounmap(usb0_sram_pwr_ctrl); + iounmap(usb1_sram_pwr); + iounmap(usb1_sram_pwr_ctrl); + } + pr_debug("%s END\n", __func__); + + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + void __iomem *reg_u3_port; + void __iomem *reg_u2_port; + + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + switch (port_num) { + case USB_PORT_0: + pr_debug("set port 0 phy suspend\n"); + if (rtk_usb->power_ctrl_reg.p0_gusb3pipectl) { + reg_u3_port = ioremap( + rtk_usb->power_ctrl_reg.p0_gusb3pipectl, 0x4); + if (is_suspend) + writel(readl(reg_u3_port) | BIT(17), + reg_u3_port); + else + writel(readl(reg_u3_port) & ~BIT(17), + reg_u3_port); + iounmap(reg_u3_port); + } + if (rtk_usb->power_ctrl_reg.p0_gusb2phycfg) { + reg_u2_port = ioremap( + rtk_usb->power_ctrl_reg.p0_gusb2phycfg, 0x4); + if (is_suspend) + writel(readl(reg_u2_port) | BIT(6), + reg_u2_port); + else + writel(readl(reg_u2_port) & ~BIT(6), + reg_u2_port); + iounmap(reg_u2_port); + } + break; + case USB_PORT_1: + pr_debug("set port 1 phy suspend\n"); + if (rtk_usb->power_ctrl_reg.p1_gusb3pipectl) { + reg_u3_port = ioremap( + rtk_usb->power_ctrl_reg.p1_gusb3pipectl, 0x4); + writel(readl(reg_u3_port) | BIT(17), reg_u3_port); + iounmap(reg_u3_port); + } + if (rtk_usb->power_ctrl_reg.p1_gusb2phycfg) { + reg_u2_port = ioremap( + rtk_usb->power_ctrl_reg.p1_gusb2phycfg, 0x4); + writel(readl(reg_u2_port) | BIT(6), reg_u2_port); + iounmap(reg_u2_port); + } + break; + case USB_PORT_2: + pr_debug("TODO set port 2 phy suspend\n"); + break; + case USB_PORT_3: + pr_debug("set port 3 phy suspend\n"); + if (rtk_usb->power_ctrl_reg.p3_gusb3pipectl) { + reg_u3_port = ioremap( + rtk_usb->power_ctrl_reg.p3_gusb3pipectl, 0x4); + writel(readl(reg_u3_port) | BIT(17), reg_u3_port); + iounmap(reg_u3_port); + } + if (rtk_usb->power_ctrl_reg.p3_gusb2phycfg) { + reg_u2_port = ioremap( + rtk_usb->power_ctrl_reg.p3_gusb2phycfg, 0x4); + writel(readl(reg_u2_port) | BIT(6), reg_u2_port); + iounmap(reg_u2_port); + } + break; + default: + pr_err("Error port num %d\n", port_num); + } + pr_debug("%s END\n", __func__); + return 0; +} + +static int type_c_init(struct rtk_usb *rtk_usb) +{ + if (!rtk_usb) { + pr_info("%s: rtk_usb is NULL\n", __func__); + return 0; + } + + return 0; +} + +static int type_c_plug_config(struct rtk_usb *rtk_usb, int dr_mode, int cc) +{ + void __iomem *usb_typec_ctrl_cc1_0; + int val_cc; + + if (!rtk_usb) { + pr_info("%s: rtk_usb is NULL\n", __func__); + return 0; + } + + if (!rtk_usb->type_c.usb_typec_ctrl_cc1_0) { + pr_info("%s: rtk_usb no usb_typec_ctrl_cc1_0 reg\n", __func__); + return 0; + } + + usb_typec_ctrl_cc1_0 = ioremap(rtk_usb->type_c.usb_typec_ctrl_cc1_0, + 0x4); + val_cc = readl(usb_typec_ctrl_cc1_0); + val_cc &= ~TYPE_C_SWITCH_MASK; + + if (cc == disable_cc) { + val_cc &= TYPE_C_disable_cc; + } else if (cc == enable_cc1) { + val_cc |= TYPE_C_enable_cc1; + } else if (cc == enable_cc2) { + val_cc |= TYPE_C_enable_cc2; + } else { + pr_err("%s: Error cc setting cc=0x%x\n", __func__, cc); + return -1; + } + writel(val_cc, usb_typec_ctrl_cc1_0); + + mdelay(1); + + pr_info("%s: cc=0x%x val_cc=0x%x usb_typec_ctrl_cc1_0=0x%x\n", + __func__, cc, val_cc, readl(usb_typec_ctrl_cc1_0)); + + iounmap(usb_typec_ctrl_cc1_0); + + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *node) +{ + struct device_node *sub_node; + int ret; + + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + if (!rtk_usb) { + //pr_err("%s: No Memeory to kzalloc rtk_usb!\n", __func__); + return NULL; + } + + pr_info("%s START (%s)\n", __func__, __FILE__); + + sub_node = of_get_child_by_name(node, "power_ctrl_reg"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + of_property_read_u32(sub_node, + "usb_ctrl", &rtk_usb->power_ctrl_reg.usb_ctrl); + /* Port 0~2 */ + of_property_read_u32(sub_node, + "usb0_sram_pwr", + &rtk_usb->power_ctrl_reg.usb0_sram_pwr); + of_property_read_u32(sub_node, + "usb0_sram_pwr_ctrl", + &rtk_usb->power_ctrl_reg.usb0_sram_pwr_ctrl); + /* Port 3 */ + of_property_read_u32(sub_node, + "usb1_sram_pwr", + &rtk_usb->power_ctrl_reg.usb1_sram_pwr); + of_property_read_u32(sub_node, + "usb1_sram_pwr_ctrl", + &rtk_usb->power_ctrl_reg.usb1_sram_pwr_ctrl); + + of_property_read_u32(sub_node, + "p0_l4_icg", &rtk_usb->power_ctrl_reg.p0_l4_icg); + of_property_read_u32(sub_node, + "p1_l4_icg", &rtk_usb->power_ctrl_reg.p1_l4_icg); + of_property_read_u32(sub_node, + "p2_l4_icg", &rtk_usb->power_ctrl_reg.p2_l4_icg); + of_property_read_u32(sub_node, + "p3_l4_icg", &rtk_usb->power_ctrl_reg.p3_l4_icg); + + /* for power cut */ + of_property_read_u32(sub_node, + "usb_phy_ctrl", + &rtk_usb->power_ctrl_reg.usb_phy_ctrl); + + of_property_read_u32(sub_node, + "p0_utmi_reset", + &rtk_usb->power_ctrl_reg.p0_utmi_reset); + of_property_read_u32(sub_node, + "p1_utmi_reset", + &rtk_usb->power_ctrl_reg.p1_utmi_reset); + of_property_read_u32(sub_node, + "p2_utmi_reset", + &rtk_usb->power_ctrl_reg.p2_utmi_reset); + of_property_read_u32(sub_node, + "p3_utmi_reset", + &rtk_usb->power_ctrl_reg.p3_utmi_reset); + + of_property_read_u32(sub_node, + "p0_pipe_reset", + &rtk_usb->power_ctrl_reg.p0_pipe_reset); + of_property_read_u32(sub_node, + "p1_pipe_reset", + &rtk_usb->power_ctrl_reg.p1_pipe_reset); + of_property_read_u32(sub_node, + "p2_pipe_reset", + &rtk_usb->power_ctrl_reg.p2_pipe_reset); + of_property_read_u32(sub_node, + "p3_pipe_reset", + &rtk_usb->power_ctrl_reg.p3_pipe_reset); + + /* for suspend */ + of_property_read_u32(sub_node, + "p0_gusb2phycfg", + &rtk_usb->power_ctrl_reg.p0_gusb2phycfg); + of_property_read_u32(sub_node, + "p0_gusb3pipectl", + &rtk_usb->power_ctrl_reg.p0_gusb3pipectl); + + of_property_read_u32(sub_node, + "p1_gusb2phycfg", + &rtk_usb->power_ctrl_reg.p1_gusb2phycfg); + of_property_read_u32(sub_node, + "p1_gusb3pipectl", + &rtk_usb->power_ctrl_reg.p1_gusb3pipectl); + + of_property_read_u32(sub_node, + "p2_gusb2phycfg", + &rtk_usb->power_ctrl_reg.p2_gusb2phycfg); + of_property_read_u32(sub_node, + "p2_gusb3pipectl", + &rtk_usb->power_ctrl_reg.p2_gusb3pipectl); + + of_property_read_u32(sub_node, + "p3_gusb2phycfg", + &rtk_usb->power_ctrl_reg.p3_gusb2phycfg); + of_property_read_u32(sub_node, + "p3_gusb3pipectl", + &rtk_usb->power_ctrl_reg.p3_gusb3pipectl); + + of_property_read_u32(sub_node, + "usb_charger", + &rtk_usb->power_ctrl_reg.usb_charger); + + if (of_property_read_bool(sub_node, "usb_power_cut")) + rtk_usb->usb_power_cut = true; + else + rtk_usb->usb_power_cut = false; + + } + + sub_node = of_get_child_by_name(node, "type_c"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + ret = of_property_read_u32(sub_node, + "usb_typec_ctrl_cc1_0", + &rtk_usb->type_c.usb_typec_ctrl_cc1_0); + if (ret) + rtk_usb->type_c.usb_typec_ctrl_cc1_0 = 0; + } + + pr_debug("%s END\n", __func__); + + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + return 0; +} + +int rtk_usb_rtd129x_init(struct rtk_usb_ops *ops) +{ + + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + ops->usb_set_charger_power = &usb_set_charger_power; + + /* For Type c */ + ops->type_c_init = &type_c_init; + ops->type_c_plug_config = &type_c_plug_config; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_usb_rtd1312c.c b/drivers/soc/realtek/common/rtk_usb_rtd1312c.c new file mode 100644 index 000000000000..74dbd5c2e7ec --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd1312c.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include +#include +#include + +#include "rtk_usb.h" + +struct rtk_usb { + struct power_ctrl_reg { + u32 usb_ctrl; + /* Port 0~2 */ + u32 usb0_sram_pwr3; + u32 usb0_sram_pwr4; + /* l4_icg */ + u32 p0_l4_icg; + u32 p1_l4_icg; + } power_ctrl_reg; + + bool usb_power_cut; + + struct type_c { + struct gpio_desc *connector_switch_gpio; + } type_c; +}; + +static struct rtk_usb *rtk_usb; + +/* set usb charger power */ +static void usb_set_charger_power(struct rtk_usb *rtk_usb, unsigned int val) +{ + if (!rtk_usb) + return; +} + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + void __iomem *reg; + + if (!rtk_usb) + return 0; + + switch (port_num) { + case USB_PORT_0: + if (rtk_usb->power_ctrl_reg.p0_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p0_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_1: + case USB_PORT_2: + if (rtk_usb->power_ctrl_reg.p1_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p1_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + default: + pr_err("%s Error Port num %d\n", __func__, port_num); + break; + } + + return 0; +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + + if (rtk_usb->usb_power_cut && + rtk_usb->power_ctrl_reg.usb_ctrl && + rtk_usb->power_ctrl_reg.usb0_sram_pwr3 && + rtk_usb->power_ctrl_reg.usb0_sram_pwr4) { + void __iomem *usb0_sram_pwr3 = + ioremap(rtk_usb->power_ctrl_reg.usb0_sram_pwr3, + 0x4); + void __iomem *usb0_sram_pwr4 = + ioremap(rtk_usb->power_ctrl_reg.usb0_sram_pwr4, + 0x4); + void __iomem *usb_ctrl = ioremap( + rtk_usb->power_ctrl_reg.usb_ctrl, 0x4); + + pr_info("%s power_%s ([0x%x=0x%08x)\n", __func__, + power_on?"on":"off", + rtk_usb->power_ctrl_reg.usb_ctrl, readl(usb_ctrl)); + if (power_on) { + writel((BIT(0) | BIT(1) | BIT(4) | BIT(5) | BIT(6)) | + readl(usb_ctrl), usb_ctrl); + writel(0x00000f00, usb0_sram_pwr4); + writel(~(BIT(8) | BIT(9)) & readl(usb_ctrl), usb_ctrl); + } else { + writel((BIT(8) | BIT(9)) | readl(usb_ctrl), usb_ctrl); + // port0-port2 sram + writel(0, usb0_sram_pwr3); + writel(0x00000f01, usb0_sram_pwr4); + writel(~(BIT(0) | BIT(1) | BIT(4) | BIT(5) | BIT(6)) & + readl(usb_ctrl), usb_ctrl); + } + pr_info("set power_domain %s ([0x%x]=0x%08x)\n", + power_on?"on":"off", + rtk_usb->power_ctrl_reg.usb_ctrl, readl(usb_ctrl)); + iounmap(usb_ctrl); + iounmap(usb0_sram_pwr3); + iounmap(usb0_sram_pwr4); + } + pr_debug("%s END\n", __func__); + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_init(struct rtk_usb *rtk_usb) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_plug_config(struct rtk_usb *rtk_usb, int dr_mode, int cc) +{ + bool high; + + /* host / device */ + if (dr_mode == USB_DR_MODE_PERIPHERAL) + high = true; + else if (dr_mode == USB_DR_MODE_HOST) + high = false; + else + goto out; + + if (!IS_ERR(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("%s Set connector to %s by gpio %d\n", + __func__, high?"device":"host", + desc_to_gpio(rtk_usb->type_c.connector_switch_gpio)); + if (gpiod_direction_output( + rtk_usb->type_c.connector_switch_gpio, high)) + pr_err("%s ERROR connector_switch_ctrl_gpio fail\n", + __func__); + } + +out: + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *node) +{ + struct device_node *sub_node; + + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + + pr_info("%s START (%s)\n", __func__, __FILE__); + sub_node = of_get_child_by_name(node, "power_ctrl_reg"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + of_property_read_u32(sub_node, + "usb_ctrl", &rtk_usb->power_ctrl_reg.usb_ctrl); + /* Port 0~2 */ + of_property_read_u32(sub_node, + "usb0_sram_pwr3", + &rtk_usb->power_ctrl_reg.usb0_sram_pwr3); + of_property_read_u32(sub_node, + "usb0_sram_pwr4", + &rtk_usb->power_ctrl_reg.usb0_sram_pwr4); + + of_property_read_u32(sub_node, + "p0_l4_icg", &rtk_usb->power_ctrl_reg.p0_l4_icg); + of_property_read_u32(sub_node, + "p1_l4_icg", &rtk_usb->power_ctrl_reg.p1_l4_icg); + + if (of_property_read_bool(sub_node, "usb_power_cut")) + rtk_usb->usb_power_cut = true; + else + rtk_usb->usb_power_cut = false; + + } + + sub_node = of_get_child_by_name(node, "type_c"); + if (sub_node) { + + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + rtk_usb->type_c.connector_switch_gpio = gpiod_get_from_of_node(sub_node, "realtek,connector_switch-gpio", + 0, GPIOD_OUT_HIGH, "usb-connector_switch"); + if (IS_ERR(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("connector_switch-gpio no found"); + } else { + pr_info("%s get connector_switch-gpio (id=%d) OK\n", + __func__, desc_to_gpio(rtk_usb->type_c.connector_switch_gpio)); + } + + } + + pr_info("%s END\n", __func__); + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + return 0; +} + +int rtk_usb_rtd1312c_init(struct rtk_usb_ops *ops) +{ + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + ops->usb_set_charger_power = &usb_set_charger_power; + + /* For Type c */ + ops->type_c_init = &type_c_init; + ops->type_c_plug_config = &type_c_plug_config; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_usb_rtd139x.c b/drivers/soc/realtek/common/rtk_usb_rtd139x.c new file mode 100644 index 000000000000..a7b1cc89260d --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd139x.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include +#include +#include + +#include "rtk_usb.h" + +struct rtk_usb { + struct power_ctrl_reg { + u32 usb_ctrl; + /* Port 0~2 */ + u32 usb0_sram_pwr3; + u32 usb0_sram_pwr4; + /* l4_icg */ + u32 p0_l4_icg; + u32 p1_l4_icg; + } power_ctrl_reg; + + bool usb_power_cut; + + struct type_c { + int connector_switch_gpio; + } type_c; +}; + +static struct rtk_usb *rtk_usb; + +/* set usb charger power */ +static void usb_set_charger_power(struct rtk_usb *rtk_usb, unsigned int val) +{ + if (!rtk_usb) + return; +} + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + void __iomem *reg; + + if (!rtk_usb) + return 0; + + switch (port_num) { + case USB_PORT_0: + if (rtk_usb->power_ctrl_reg.p0_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p0_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_1: + case USB_PORT_2: + if (rtk_usb->power_ctrl_reg.p1_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p1_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + default: + pr_err("%s Error Port num %d\n", __func__, port_num); + break; + } + + return 0; +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + + if (rtk_usb->usb_power_cut && + rtk_usb->power_ctrl_reg.usb_ctrl && + rtk_usb->power_ctrl_reg.usb0_sram_pwr3 && + rtk_usb->power_ctrl_reg.usb0_sram_pwr4) { + void __iomem *usb0_sram_pwr3 = + ioremap(rtk_usb->power_ctrl_reg.usb0_sram_pwr3, + 0x4); + void __iomem *usb0_sram_pwr4 = + ioremap(rtk_usb->power_ctrl_reg.usb0_sram_pwr4, + 0x4); + void __iomem *usb_ctrl = ioremap( + rtk_usb->power_ctrl_reg.usb_ctrl, 0x4); + + pr_info("%s power_%s ([0x%x=0x%08x)\n", __func__, + power_on?"on":"off", + rtk_usb->power_ctrl_reg.usb_ctrl, readl(usb_ctrl)); + if (power_on) { + writel((BIT(0) | BIT(1) | BIT(4) | BIT(5) | BIT(6)) | + readl(usb_ctrl), usb_ctrl); + writel(0x00000f00, usb0_sram_pwr4); + writel(~(BIT(8) | BIT(9)) & readl(usb_ctrl), usb_ctrl); + } else { + writel((BIT(8) | BIT(9)) | readl(usb_ctrl), usb_ctrl); + // port0-port2 sram + writel(0, usb0_sram_pwr3); + writel(0x00000f01, usb0_sram_pwr4); + writel(~(BIT(0) | BIT(1) | BIT(4) | BIT(5) | BIT(6)) & + readl(usb_ctrl), usb_ctrl); + } + pr_info("set power_domain %s ([0x%x]=0x%08x)\n", + power_on?"on":"off", + rtk_usb->power_ctrl_reg.usb_ctrl, readl(usb_ctrl)); + iounmap(usb_ctrl); + iounmap(usb0_sram_pwr3); + iounmap(usb0_sram_pwr4); + } + pr_debug("%s END\n", __func__); + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_init(struct rtk_usb *rtk_usb) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_plug_config(struct rtk_usb *rtk_usb, int dr_mode, int cc) +{ + bool high; + + /* host / device */ + if (dr_mode == USB_DR_MODE_PERIPHERAL) + high = true; + else if (dr_mode == USB_DR_MODE_HOST) + high = false; + else + goto out; + + if (rtk_usb->type_c.connector_switch_gpio != -1 && + gpio_is_valid(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("%s Set connector to %s by gpio %d\n", + __func__, high?"device":"host", + rtk_usb->type_c.connector_switch_gpio); + if (gpio_direction_output( + rtk_usb->type_c.connector_switch_gpio, high)) + pr_err("%s ERROR set connector_switch_gpio fail\n", + __func__); + } + +out: + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *node) +{ + struct device_node *sub_node; + + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + + pr_info("%s START (%s)\n", __func__, __FILE__); + sub_node = of_get_child_by_name(node, "power_ctrl_reg"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + of_property_read_u32(sub_node, + "usb_ctrl", &rtk_usb->power_ctrl_reg.usb_ctrl); + /* Port 0~2 */ + of_property_read_u32(sub_node, + "usb0_sram_pwr3", + &rtk_usb->power_ctrl_reg.usb0_sram_pwr3); + of_property_read_u32(sub_node, + "usb0_sram_pwr4", + &rtk_usb->power_ctrl_reg.usb0_sram_pwr4); + + of_property_read_u32(sub_node, + "p0_l4_icg", &rtk_usb->power_ctrl_reg.p0_l4_icg); + of_property_read_u32(sub_node, + "p1_l4_icg", &rtk_usb->power_ctrl_reg.p1_l4_icg); + + if (of_property_read_bool(sub_node, "usb_power_cut")) + rtk_usb->usb_power_cut = true; + else + rtk_usb->usb_power_cut = false; + + } + + sub_node = of_get_child_by_name(node, "type_c"); + if (sub_node) { + int gpio; + + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + gpio = of_get_named_gpio(sub_node, + "realtek,connector_switch-gpio", 0); + if (gpio_is_valid(gpio)) { + rtk_usb->type_c.connector_switch_gpio = gpio; + pr_info("%s get connector_switch-gpio (id=%d) OK\n", + __func__, gpio); + } else { + pr_info("connector_switch-gpio no found"); + rtk_usb->type_c.connector_switch_gpio = -1; + } + } + + pr_info("%s END\n", __func__); + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + return 0; +} + +int rtk_usb_rtd139x_init(struct rtk_usb_ops *ops) +{ + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + ops->usb_set_charger_power = &usb_set_charger_power; + + /* For Type c */ + ops->type_c_init = &type_c_init; + ops->type_c_plug_config = &type_c_plug_config; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_usb_rtd13xx.c b/drivers/soc/realtek/common/rtk_usb_rtd13xx.c new file mode 100644 index 000000000000..5ac7a85994c4 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd13xx.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include +#include +#include + +#include "rtk_usb.h" + +struct rtk_usb { + struct power_ctrl_reg { + /* l4_icg */ + u32 p0_l4_icg; + u32 p1_l4_icg; + u32 p2_l4_icg; + } power_ctrl_reg; + + bool usb_power_cut; + + struct type_c { + struct gpio_desc *connector_switch_gpio; + struct gpio_desc *plug_side_switch_gpio; + } type_c; + + u32 pcie_usb3phy_sel; +}; + +#define disable_cc 0x0 +#define enable_cc1 0x1 +#define enable_cc2 0x2 + +static struct rtk_usb *rtk_usb; + +/* set usb charger power */ +static void usb_set_charger_power(struct rtk_usb *rtk_usb, unsigned int val) +{ + if (!rtk_usb) + return; +} + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + void __iomem *reg; + + if (!rtk_usb) + return 0; + + switch (port_num) { + case USB_PORT_0: + if (rtk_usb->power_ctrl_reg.p0_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p0_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_1: + if (rtk_usb->power_ctrl_reg.p1_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p1_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_2: + if (rtk_usb->power_ctrl_reg.p2_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p2_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + default: + pr_err("%s Error Port num %d\n", __func__, port_num); + break; + } + + return 0; +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + + pr_debug("%s END\n", __func__); + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_init(struct rtk_usb *rtk_usb) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_plug_config(struct rtk_usb *rtk_usb, int dr_mode, int cc) +{ + bool high; + + /* host / device */ + if (dr_mode == USB_DR_MODE_PERIPHERAL) + high = true; + else if (dr_mode == USB_DR_MODE_HOST) + high = false; + else + goto cc_config; + + if (!IS_ERR(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("%s Set connector to %s by gpio %d\n", + __func__, high?"device":"host", + desc_to_gpio(rtk_usb->type_c.connector_switch_gpio)); + if (gpiod_direction_output( + rtk_usb->type_c.connector_switch_gpio, high)) + pr_err("%s ERROR connector_switch_ctrl_gpio fail\n", + __func__); + } + +cc_config: + /* cc pin */ + /* host / device */ + if (cc == enable_cc1) + high = true; + else if (cc == enable_cc2) + high = false; + else + goto out; + + if (!IS_ERR(rtk_usb->type_c.plug_side_switch_gpio)) { + pr_info("%s type plug to %s by gpio %d\n", + __func__, high?"cc1":"cc2", + desc_to_gpio(rtk_usb->type_c.plug_side_switch_gpio)); + if (gpiod_direction_output( + rtk_usb->type_c.plug_side_switch_gpio, high)) + pr_err("%s set ERROR plug_side_switch_gpio fail\n", + __func__); + } + +out: + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *node) +{ + struct device_node *sub_node; + + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + + pr_info("%s START (%s)\n", __func__, __FILE__); + + sub_node = of_get_child_by_name(node, "power_ctrl_reg"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + of_property_read_u32(sub_node, + "p0_l4_icg", &rtk_usb->power_ctrl_reg.p0_l4_icg); + of_property_read_u32(sub_node, + "p1_l4_icg", &rtk_usb->power_ctrl_reg.p1_l4_icg); + of_property_read_u32(sub_node, + "p2_l4_icg", &rtk_usb->power_ctrl_reg.p2_l4_icg); + + if (of_property_read_bool(sub_node, "usb_power_cut")) + rtk_usb->usb_power_cut = true; + else + rtk_usb->usb_power_cut = false; + } + + sub_node = of_get_child_by_name(node, "type_c"); + if (sub_node) { + + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + rtk_usb->type_c.connector_switch_gpio = gpiod_get_from_of_node(sub_node, "realtek,connector_switch-gpio", + 0, GPIOD_OUT_HIGH, "usb-connector_switch"); + if (IS_ERR(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("connector_switch-gpio no found"); + } else { + pr_info("%s get connector_switch-gpio (id=%d) OK\n", + __func__, desc_to_gpio(rtk_usb->type_c.connector_switch_gpio)); + } + + rtk_usb->type_c.plug_side_switch_gpio = gpiod_get_from_of_node(sub_node, "realtek,plug_side_switch-gpio", + 0, GPIOD_OUT_HIGH, "usb-plug_side_switch"); + if (IS_ERR(rtk_usb->type_c.plug_side_switch_gpio)) { + pr_info("plug_side_switch-gpio no found"); + } else { + pr_info("%s get plug_side_switch-gpio (id=%d) OK\n", + __func__, desc_to_gpio(rtk_usb->type_c.plug_side_switch_gpio)); + } + } + if (of_property_read_u32(node, + "pcie_usb3phy_sel", &rtk_usb->pcie_usb3phy_sel)) { + rtk_usb->pcie_usb3phy_sel = -1; + } else { + void __iomem *reg = ioremap(rtk_usb->pcie_usb3phy_sel, 0x4); + int val = readl(reg) | BIT(6); + + writel(val, reg); + + pr_info("%s: pcie_usb3phy_sel=%x to enable usb3phy (val=0x%x)\n", + __func__, rtk_usb->pcie_usb3phy_sel, readl(reg)); + + iounmap(reg); + } + + pr_info("%s END\n", __func__); + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + return 0; +} + +int rtk_usb_rtd13xx_init(struct rtk_usb_ops *ops) +{ + + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + ops->usb_set_charger_power = &usb_set_charger_power; + + /* For Type c */ + ops->type_c_init = &type_c_init; + ops->type_c_plug_config = &type_c_plug_config; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_usb_rtd16xx.c b/drivers/soc/realtek/common/rtk_usb_rtd16xx.c new file mode 100644 index 000000000000..461299c9c50d --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd16xx.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "rtk_usb.h" + +struct rtk_usb { + struct power_ctrl_reg { + /* l4_icg */ + u32 p0_l4_icg; + u32 p1_l4_icg; + u32 p2_l4_icg; + } power_ctrl_reg; + + bool usb_power_cut; + + struct type_c { + u32 drd_wrap_base; /* 0x98013200 */ + u32 u3host_wrap_base; /* 0x98013e00 */ + u32 drd_u3_portsc; /* 0x98020430 */ + u32 drd_u3_sus_en; /* 0x980282c0 */ + u32 u3host_u3_sus_en; /*0x980582c0 */ + } type_c; +}; + +static struct rtk_usb *rtk_usb; + +#define disable_cc 0x0 +#define enable_cc1 0x1 +#define enable_cc2 0x2 + +/* set usb charger power */ +static void usb_set_charger_power(struct rtk_usb *rtk_usb, unsigned int val) +{ + if (!rtk_usb) + return; +} + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + void __iomem *reg; + + if (!rtk_usb) + return 0; + + switch (port_num) { + case USB_PORT_0: + if (rtk_usb->power_ctrl_reg.p0_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p0_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_1: + if (rtk_usb->power_ctrl_reg.p1_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p1_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_2: + if (rtk_usb->power_ctrl_reg.p2_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p2_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + default: + pr_err("%s Error Port num %d\n", __func__, port_num); + break; + } + + return 0; +} + +static inline struct reset_control *USB_reset_get(struct device *dev, + const char *str) +{ + struct reset_control *reset; + + reset = reset_control_get_exclusive(dev, str); + if (IS_ERR(reset)) { + dev_dbg(dev, "No controller reset %s\n", str); + reset = NULL; + } + return reset; +} + +static inline void USB_reset_put(struct reset_control *reset) +{ + if (reset) + reset_control_put(reset); +} + +static inline int USB_reset_deassert(struct reset_control *reset) +{ + if (!reset) + return 0; + + return reset_control_deassert(reset); +} + +static inline int USB_reset_assert(struct reset_control *reset) +{ + if (!reset) + return 0; + + return reset_control_assert(reset); +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + struct platform_device *pdev = NULL; + struct device_node *node; + struct device *dev; + struct reset_control *reset_u2phy0; + struct reset_control *reset_u2phy1; + struct reset_control *reset_u2phy2; + struct reset_control *reset_u2phy3; + struct reset_control *reset_u3phy0; + struct reset_control *reset_u3phy1; + struct reset_control *reset_usb_apply; + + if (!rtk_usb) + return 0; + + pr_debug("%s START power %s\n", __func__, power_on?"on":"off"); + + node = of_find_compatible_node(NULL, NULL, + "Realtek,usb-manager"); + if (node != NULL) + pdev = of_find_device_by_node(node); + if (pdev != NULL) { + dev = &pdev->dev; + } else { + pr_err("%s ERROR no usb-manager", __func__); + return -ENODEV; + } + + /* GET reset controller */ + reset_u2phy0 = USB_reset_get(dev, "u2phy0"); + reset_u2phy1 = USB_reset_get(dev, "u2phy1"); + reset_u2phy2 = USB_reset_get(dev, "u2phy2"); + reset_u2phy3 = USB_reset_get(dev, "u2phy3"); + + reset_u3phy0 = USB_reset_get(dev, "u3phy0"); + reset_u3phy1 = USB_reset_get(dev, "u3phy1"); + + reset_usb_apply = USB_reset_get(dev, "apply"); + + if (rtk_usb->usb_power_cut) { + if (power_on) { + // Enable usb phy reset + /* DEASSERT: set rstn bit to 1 */ + pr_debug("usb power cut No set phy reset by rtk_usb\n"); + } else { + pr_debug("usb power cut set phy reset to 0\n"); + USB_reset_assert(reset_u2phy0); + USB_reset_assert(reset_u2phy1); + USB_reset_assert(reset_u2phy2); + USB_reset_assert(reset_u2phy3); + USB_reset_assert(reset_u3phy0); + USB_reset_assert(reset_u3phy1); + + USB_reset_assert(reset_usb_apply); + } + } + pr_debug("Realtek RTD16xx USB power %s OK\n", power_on?"on":"off"); + + USB_reset_put(reset_u2phy0); + USB_reset_put(reset_u2phy1); + USB_reset_put(reset_u2phy2); + USB_reset_put(reset_u2phy3); + + USB_reset_put(reset_u3phy0); + USB_reset_put(reset_u3phy1); + + USB_reset_put(reset_usb_apply); + + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_init(struct rtk_usb *rtk_usb) +{ + void __iomem *drd_wrap_base, *drd_cc_setting; + void __iomem *u3host_wrap_base, *u3host_mac_ctrl; + int val_u3_tc_mode, val_u3host_mac_ctrl; + + if (!rtk_usb->type_c.drd_wrap_base || + !rtk_usb->type_c.u3host_wrap_base || + !rtk_usb->type_c.drd_u3_portsc || + !rtk_usb->type_c.drd_u3_sus_en || + !rtk_usb->type_c.u3host_u3_sus_en) { + pr_err("%s: Error! No RTD1619 type_c reg\n", __func__); + return -1; + } + + drd_wrap_base = ioremap(rtk_usb->type_c.drd_wrap_base, 0x200); + drd_cc_setting = drd_wrap_base + 0x194; + u3host_wrap_base = ioremap(rtk_usb->type_c.u3host_wrap_base, 0x200); + u3host_mac_ctrl = u3host_wrap_base + 0x60; + val_u3_tc_mode = BIT(0) | readl(drd_cc_setting); + val_u3host_mac_ctrl = BIT(8) | readl(u3host_mac_ctrl); + + writel(val_u3_tc_mode, drd_cc_setting); + writel(val_u3host_mac_ctrl, u3host_mac_ctrl); + + pr_info("%s: set type_c mode (0x%x) and disable u3host u3 port (0x%x) for RTD1619\n", + __func__, readl(drd_cc_setting), readl(u3host_mac_ctrl)); + + iounmap(drd_wrap_base); + iounmap(u3host_mac_ctrl); + return 0; +} + +static int type_c_plug_config(struct rtk_usb *rtk_usb, int dr_mode, int cc) +{ + void __iomem *drd_wrap_base, *u3host_wrap_base; + void __iomem *drd_u3phy_pipe_clock, *u3host_u3phy_pipe_clock; + void __iomem *drd_pclk_u3phy, *u3host_pclk_u3phy; + void __iomem *drd_tc_mux_ctrl; + void __iomem *drd_u3_portsc; + void __iomem *drd_u3_sus_en, *u3host_u3_sus_en; + int wait_count = 1000; + int drd_u3_sus_en_status_save, u3host_u3_sus_en_status_save; + + if (!rtk_usb->type_c.drd_wrap_base || + !rtk_usb->type_c.u3host_wrap_base || + !rtk_usb->type_c.drd_u3_portsc || + !rtk_usb->type_c.drd_u3_sus_en || + !rtk_usb->type_c.u3host_u3_sus_en) { + pr_err("%s: Error! No RTD1619 type_c reg\n", __func__); + return -1; + } + + drd_wrap_base = ioremap(rtk_usb->type_c.drd_wrap_base, 0x200); + u3host_wrap_base = ioremap(rtk_usb->type_c.u3host_wrap_base, 0x100); + drd_u3phy_pipe_clock = drd_wrap_base + 0xc; + u3host_u3phy_pipe_clock = u3host_wrap_base + 0xc; + drd_pclk_u3phy = drd_wrap_base + 0x84; + u3host_pclk_u3phy = u3host_wrap_base + 0x84; + drd_tc_mux_ctrl = drd_wrap_base + 0x194; + drd_u3_portsc = ioremap(rtk_usb->type_c.drd_u3_portsc, 0x4); + drd_u3_sus_en = ioremap(rtk_usb->type_c.drd_u3_sus_en, 0x4); + u3host_u3_sus_en = ioremap(rtk_usb->type_c.u3host_u3_sus_en, 0x4); + drd_u3_sus_en_status_save = readl(drd_u3_sus_en) & BIT(17); + u3host_u3_sus_en_status_save = readl(u3host_u3_sus_en) & BIT(17); + + pr_info("%s: dr_mode=%d cc=0x%x\n", __func__, dr_mode, cc); + /* disable u3phy suspend */ + writel(~BIT(17) & readl(drd_u3_sus_en), drd_u3_sus_en); + writel(~BIT(17) & readl(u3host_u3_sus_en), u3host_u3_sus_en); + + /* check u3phy clock if resume */ + while (wait_count-- > 0 && (!(readl(drd_pclk_u3phy) & BIT(19)) || + !(readl(u3host_pclk_u3phy) & BIT(19)))) { + pr_info("wait drd/u3host u3phy clock\n"); + mdelay(1); + }; + + if (wait_count < 0) { + pr_err("wait u3phy clock fail. drd=0x%x u3host=0x%x\n", + readl(drd_pclk_u3phy), readl(u3host_pclk_u3phy)); + } + + if (cc == disable_cc) { + pr_info("%s: disable drd u3phy for CHIP_ID_RTD1619\n", + __func__); + } else { + /* push drd u3 port status to disable */ + writel(BIT(1) | readl(drd_u3_portsc), drd_u3_portsc); + pr_info("%s: disable drd_u3_portsc=0x%x\n", + __func__, readl(drd_u3_portsc)); + + /* disable u3phy clock */ + writel(~BIT(1) & readl(drd_u3phy_pipe_clock), + drd_u3phy_pipe_clock); + writel(~BIT(1) & readl(u3host_u3phy_pipe_clock), + u3host_u3phy_pipe_clock); + + if (cc == enable_cc1) { + writel(~BIT(1) & readl(drd_tc_mux_ctrl), + drd_tc_mux_ctrl); + pr_info("%s: enable_cc1 drd u3phy for CHIP_ID_RTD1619\n", + __func__); + } else if (cc == enable_cc2) { + writel(BIT(1) | readl(drd_tc_mux_ctrl), + drd_tc_mux_ctrl); + pr_info("%s: enable_cc2 drd u3phy for CHIP_ID_RTD1619\n", + __func__); + } + /* enable u3phy clock */ + writel(BIT(1) | readl(drd_u3phy_pipe_clock), + drd_u3phy_pipe_clock); + writel(BIT(1) | readl(u3host_u3phy_pipe_clock), + u3host_u3phy_pipe_clock); + + /* push drd u3 port status to rxDetect */ + writel(BIT(16) | 0xA0 | + (readl(drd_u3_portsc) & (~0x1E0)), + drd_u3_portsc); + pr_info("%s: drd_u3_portsc=0x%x\n", + __func__, readl(drd_u3_portsc)); + } + + /* enable u3phy suspend */ + pr_info("u3_sus_en_status_save drd=0x%x u3host=0x%x\n", + drd_u3_sus_en_status_save, u3host_u3_sus_en_status_save); + writel(drd_u3_sus_en_status_save | readl(drd_u3_sus_en), drd_u3_sus_en); + writel(u3host_u3_sus_en_status_save | readl(u3host_u3_sus_en), + u3host_u3_sus_en); + + iounmap(drd_u3_portsc); + iounmap(drd_u3_sus_en); + iounmap(u3host_u3_sus_en); + iounmap(u3host_wrap_base); + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *node) +{ + struct device_node *sub_node; + + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + + pr_info("%s START (%s)\n", __func__, __FILE__); + + sub_node = of_get_child_by_name(node, "power_ctrl_reg"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + of_property_read_u32(sub_node, + "p0_l4_icg", &rtk_usb->power_ctrl_reg.p0_l4_icg); + of_property_read_u32(sub_node, + "p1_l4_icg", &rtk_usb->power_ctrl_reg.p1_l4_icg); + of_property_read_u32(sub_node, + "p2_l4_icg", &rtk_usb->power_ctrl_reg.p2_l4_icg); + + if (of_property_read_bool(sub_node, "usb_power_cut")) + rtk_usb->usb_power_cut = true; + else + rtk_usb->usb_power_cut = false; + } + + sub_node = of_get_child_by_name(node, "type_c"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + of_property_read_u32(sub_node, + "drd_wrap_base", &rtk_usb->type_c.drd_wrap_base); + of_property_read_u32(sub_node, + "u3host_wrap_base", + &rtk_usb->type_c.u3host_wrap_base); + of_property_read_u32(sub_node, + "drd_u3_portsc", &rtk_usb->type_c.drd_u3_portsc); + of_property_read_u32(sub_node, + "drd_u3_sus_en", &rtk_usb->type_c.drd_u3_sus_en); + of_property_read_u32(sub_node, + "u3host_u3_sus_en", + &rtk_usb->type_c.u3host_u3_sus_en); + } + + pr_info("%s END\n", __func__); + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + return 0; +} + +int rtk_usb_rtd16xx_init(struct rtk_usb_ops *ops) +{ + + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + ops->usb_set_charger_power = &usb_set_charger_power; + + /* For Type c */ + ops->type_c_init = &type_c_init; + ops->type_c_plug_config = &type_c_plug_config; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_usb_rtd16xxb.c b/drivers/soc/realtek/common/rtk_usb_rtd16xxb.c new file mode 100644 index 000000000000..ce8eea4b7975 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_usb_rtd16xxb.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 Realtek Semiconductor Corp. + * Copyright (c) 2020 Realtek Semiconductor Corp. + * + */ + +#include +#include +#include +#include +#include + +#include "rtk_usb.h" + +struct rtk_usb { + struct power_ctrl_reg { + /* l4_icg */ + u32 p0_l4_icg; + u32 p1_l4_icg; + u32 p2_l4_icg; + } power_ctrl_reg; + + bool usb_power_cut; + + struct type_c { + struct gpio_desc *connector_switch_gpio; + struct gpio_desc *plug_side_switch_gpio; + } type_c; + + u32 pcie_usb3phy_sel; + u32 TP1CK_MEM_TEST1_register; +}; + +#define disable_cc 0x0 +#define enable_cc1 0x1 +#define enable_cc2 0x2 + +static struct rtk_usb *rtk_usb; + +/* set usb charger power */ +static void usb_set_charger_power(struct rtk_usb *rtk_usb, unsigned int val) +{ + if (!rtk_usb) + return; +} + +static int usb_set_hw_l4icg_on_off(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool on) +{ + void __iomem *reg; + + if (!rtk_usb) + return 0; + + switch (port_num) { + case USB_PORT_0: + if (rtk_usb->power_ctrl_reg.p0_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p0_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_1: + if (rtk_usb->power_ctrl_reg.p1_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p1_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + case USB_PORT_2: + if (rtk_usb->power_ctrl_reg.p2_l4_icg) { + pr_info("%s set l4_icg port %d\n", __func__, port_num); + reg = ioremap(rtk_usb->power_ctrl_reg.p2_l4_icg, 0x4); + writel((on&BIT(0)) | readl(reg), reg); + iounmap(reg); + } + break; + default: + pr_err("%s Error Port num %d\n", __func__, port_num); + break; + } + + return 0; +} + +static int usb_iso_power_ctrl(struct rtk_usb *rtk_usb, + bool power_on) +{ + if (!rtk_usb) + return 0; + + pr_debug("%s START\n", __func__); + + pr_debug("%s END\n", __func__); + return 0; +} + +static int usb_port_suspend_resume(struct rtk_usb *rtk_usb, + enum usb_port_num port_num, bool is_suspend) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_init(struct rtk_usb *rtk_usb) +{ + if (!rtk_usb) + return 0; + + return 0; +} + +static int type_c_plug_config(struct rtk_usb *rtk_usb, int dr_mode, int cc) +{ + bool high; + + /* host / device */ + if (dr_mode == USB_DR_MODE_PERIPHERAL) + high = true; + else if (dr_mode == USB_DR_MODE_HOST) + high = false; + else + goto cc_config; + + if (!IS_ERR(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("%s Set connector to %s by gpio %d\n", + __func__, high?"device":"host", + desc_to_gpio(rtk_usb->type_c.connector_switch_gpio)); + if (gpiod_direction_output( + rtk_usb->type_c.connector_switch_gpio, high)) + pr_err("%s ERROR connector_switch_ctrl_gpio fail\n", + __func__); + } + +cc_config: + /* cc pin */ + /* host / device */ + if (cc == enable_cc1) + high = true; + else if (cc == enable_cc2) + high = false; + else + goto out; + + if (!IS_ERR(rtk_usb->type_c.plug_side_switch_gpio)) { + pr_info("%s type plug to %s by gpio %d\n", + __func__, high?"cc1":"cc2", + desc_to_gpio(rtk_usb->type_c.plug_side_switch_gpio)); + if (gpiod_direction_output( + rtk_usb->type_c.plug_side_switch_gpio, high)) + pr_err("%s set ERROR plug_side_switch_gpio fail\n", + __func__); + } + +out: + return 0; +} + +static struct rtk_usb *usb_soc_init(struct device_node *node) +{ + struct device_node *sub_node; + + if (!rtk_usb) + rtk_usb = kzalloc(sizeof(struct rtk_usb), GFP_KERNEL); + + pr_info("%s START (%s)\n", __func__, __FILE__); + + sub_node = of_get_child_by_name(node, "power_ctrl_reg"); + if (sub_node) { + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + of_property_read_u32(sub_node, + "p0_l4_icg", &rtk_usb->power_ctrl_reg.p0_l4_icg); + of_property_read_u32(sub_node, + "p1_l4_icg", &rtk_usb->power_ctrl_reg.p1_l4_icg); + of_property_read_u32(sub_node, + "p2_l4_icg", &rtk_usb->power_ctrl_reg.p2_l4_icg); + + if (of_property_read_bool(sub_node, "usb_power_cut")) + rtk_usb->usb_power_cut = true; + else + rtk_usb->usb_power_cut = false; + } + + sub_node = of_get_child_by_name(node, "type_c"); + if (sub_node) { + + pr_debug("%s sub_node %s\n", __func__, sub_node->name); + + rtk_usb->type_c.connector_switch_gpio = gpiod_get_from_of_node(sub_node, "realtek,connector_switch-gpio", + 0, GPIOD_OUT_HIGH, "usb-connector_switch"); + if (IS_ERR(rtk_usb->type_c.connector_switch_gpio)) { + pr_info("connector_switch-gpio no found"); + } else { + pr_info("%s get connector_switch-gpio (id=%d) OK\n", + __func__, desc_to_gpio(rtk_usb->type_c.connector_switch_gpio)); + } + + rtk_usb->type_c.plug_side_switch_gpio = gpiod_get_from_of_node(sub_node, "realtek,plug_side_switch-gpio", + 0, GPIOD_OUT_HIGH, "usb-plug_side_switch"); + if (IS_ERR(rtk_usb->type_c.plug_side_switch_gpio)) { + pr_info("plug_side_switch-gpio no found"); + } else { + pr_info("%s get plug_side_switch-gpio (id=%d) OK\n", + __func__, desc_to_gpio(rtk_usb->type_c.plug_side_switch_gpio)); + } + } + if (of_property_read_u32(node, + "pcie_usb3phy_sel", &rtk_usb->pcie_usb3phy_sel)) { + rtk_usb->pcie_usb3phy_sel = -1; + } else { + void __iomem *reg = ioremap(rtk_usb->pcie_usb3phy_sel, 0x4); + int val = readl(reg) | BIT(6); + + writel(val, reg); + + pr_info("%s: pcie_usb3phy_sel=%x to enable usb3phy (val=0x%x)\n", + __func__, rtk_usb->pcie_usb3phy_sel, readl(reg)); + + iounmap(reg); + } + + if (of_property_read_u32(node, + "TP1CK_MEM_TEST1_register", + &rtk_usb->TP1CK_MEM_TEST1_register)) { + rtk_usb->TP1CK_MEM_TEST1_register = -1; + } else { + void __iomem *reg = ioremap(rtk_usb->TP1CK_MEM_TEST1_register, 0x4); + int val = readl(reg); + + writel(val | BIT(2), reg); + udelay(1); + writel(val & ~(BIT(2)), reg); + + pr_info("%s: TP1CK_MEM_TEST1_register=%x to toggle bit 2 (val=0x%x)\n", + __func__, rtk_usb->TP1CK_MEM_TEST1_register, val); + + iounmap(reg); + } + + pr_info("%s END\n", __func__); + return rtk_usb; +} + +static int usb_soc_free(struct rtk_usb **rtk_usb) +{ + if (*rtk_usb) { + kfree(*rtk_usb); + *rtk_usb = NULL; + } + return 0; +} + +int rtk_usb_rtd16xxb_init(struct rtk_usb_ops *ops) +{ + + if (ops == NULL) + return -1; + + ops->usb_soc_init = &usb_soc_init; + ops->usb_soc_free = &usb_soc_free; + + ops->usb_port_suspend_resume = &usb_port_suspend_resume; + ops->usb_set_hw_l4icg_on_off = &usb_set_hw_l4icg_on_off; + + ops->usb_iso_power_ctrl = &usb_iso_power_ctrl; + + ops->usb_set_charger_power = &usb_set_charger_power; + + /* For Type c */ + ops->type_c_init = &type_c_init; + ops->type_c_plug_config = &type_c_plug_config; + + return 0; +} diff --git a/drivers/soc/realtek/common/rtk_vcpu.c b/drivers/soc/realtek/common/rtk_vcpu.c new file mode 100644 index 000000000000..484c4d514a86 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_vcpu.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rtk_vcpu_data { + struct device *dev; + struct clk *clk; + struct reset_control *reset; + + struct devfreq_dev_profile profile; + struct devfreq *devfreq; +}; + +static int rtk_vcpu_power_on( struct rtk_vcpu_data *vcpu_data) +{ + reset_control_deassert(vcpu_data->reset); + clk_prepare_enable(vcpu_data->clk); + return 0; +} + +static int rtk_vcpu_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct rtk_vcpu_data *vcpu_data = dev_get_drvdata(dev); + + clk_disable_unprepare(vcpu_data->clk); + clk_set_rate(vcpu_data->clk, *freq); + clk_prepare_enable(vcpu_data->clk); + return 0; +} + +static int rtk_vcpu_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct rtk_vcpu_data *vcpu_data = dev_get_drvdata(dev); + + *freq = clk_get_rate(vcpu_data->clk); + return 0; +} + +static int rtk_vcpu_init_devfreq(struct rtk_vcpu_data *vcpu_data) +{ + struct device *dev = vcpu_data->dev; + struct device_node *np = dev->of_node; + int ret; + + if (!of_find_property(np, "operating-points-v2", NULL)) + return 0; + + ret = dev_pm_opp_of_add_table(dev); + if (ret < 0) { + dev_err(dev, "failed to get OPP table: %d\n", ret); + return ret; + } + + vcpu_data->profile.get_cur_freq = rtk_vcpu_get_cur_freq; + vcpu_data->profile.target = rtk_vcpu_target; + vcpu_data->profile.initial_freq = clk_get_rate(vcpu_data->clk); + vcpu_data->devfreq = devm_devfreq_add_device(dev, &vcpu_data->profile, "userspace", NULL); + if (!IS_ERR(vcpu_data->devfreq)) + return 0; + + ret = PTR_ERR(vcpu_data->devfreq); + dev_err(dev, "failed to add devfreq: %d\n", ret); + dev_pm_opp_of_remove_table(dev); + return ret; +} + +static int rtk_vcpu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_vcpu_data *vcpu_data; + int ret; + + vcpu_data = devm_kzalloc(dev, sizeof(*vcpu_data), GFP_KERNEL); + if (!vcpu_data) + return -ENOMEM; + vcpu_data->dev = dev; + + vcpu_data->clk = devm_clk_get(dev, NULL); + if (IS_ERR(vcpu_data->clk)) { + ret = PTR_ERR(vcpu_data->clk); + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + vcpu_data->reset = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(vcpu_data->reset)) { + ret = PTR_ERR(vcpu_data->reset); + dev_err(dev, "failed to get reset control: %d\n", ret); + return ret; + } + + rtk_vcpu_init_devfreq(vcpu_data); + + rtk_vcpu_power_on(vcpu_data); + platform_set_drvdata(pdev, vcpu_data); + return 0; +} + +static int rtk_vcpu_remove(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, NULL); + return 0; +} + +static void rtk_vcpu_shutdown(struct platform_device *pdev) +{ +} + +static const struct of_device_id rtk_vcpu_match[] = { + { .compatible = "realtek,rtd1319-vcpu-firmware", }, + {} +}; + +static struct platform_driver rtk_vcpu_driver = { + .probe = rtk_vcpu_probe, + .remove = rtk_vcpu_remove, + .shutdown = rtk_vcpu_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-vcpu", + .of_match_table = of_match_ptr(rtk_vcpu_match), + }, +}; +module_platform_driver(rtk_vcpu_driver); + +MODULE_DESCRIPTION("Realtek Video Firmware driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-vcpu"); diff --git a/drivers/soc/realtek/common/rtk_ve3_uart.c b/drivers/soc/realtek/common/rtk_ve3_uart.c new file mode 100644 index 000000000000..c6fffd4103c0 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_ve3_uart.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct class *ve3_log_class; +int ve3_uart_enable = 0; + +#define MODULE_NAME "vcpulog" + +struct task_struct *ve3_uart_kthread; +wait_queue_head_t ve3_uart_waitQueue; + + +static void __iomem *hevc_reg; +#define UFIFO_STATUS 0x18 +#define UFIFO_RD 0x14 +char uart_tx[1024]; +int tx_num = 0; + + +static int ve3_uart_thread(void * p) +{ + int status; + int cnt; + char tx_char; + + while (1) { + if (wait_event_interruptible(ve3_uart_waitQueue, ve3_uart_enable || kthread_should_stop())) { + pr_notice("%s got signal or should stop...\n", current->comm); + continue; + } + + if (kthread_should_stop()) { + pr_notice("%s exit...\n", current->comm); + break; + } + memset(uart_tx, 0, 1024); + tx_num = 0; + while (ve3_uart_enable) { + status = readl(hevc_reg + UFIFO_STATUS); + cnt = (status >> 16) & 0x1f; + while (cnt > 0) { + tx_char = readl(hevc_reg + UFIFO_RD); + if (tx_char == '\n' || tx_num == 1023) { + uart_tx[tx_num] = tx_char; + pr_err("[VE3 LOG] %s \n", uart_tx); + memset(uart_tx, 0, 1024); + tx_num = 0; + } else { + uart_tx[tx_num] = tx_char; + tx_num++; + } + cnt--; + } + mdelay(1); + } + } + return 0; +} + + +static ssize_t ve3_log_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", ve3_uart_enable); +} + +ssize_t ve3_log_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + long val; + int ret = kstrtol(buf, 10, &val); + if (ret < 0) + return -ENOMEM; + + if (val == 0) { + ve3_uart_enable = 0; + } else if (val == 1){ + ve3_uart_enable = 1; + wake_up_interruptible(&ve3_uart_waitQueue); + } + + return count; +} +static CLASS_ATTR_RW(ve3_log); + +static int rtk_ve3_uart_probe(struct platform_device *pdev) +{ + int ret = 0; + int j = 0; + static struct clk *ve3_clk; + const u32 *prop; + int size = 0; + + hevc_reg = of_iomap(pdev->dev.of_node, 0); + if (!hevc_reg) { + pr_err("cannot get hevc reg\n"); + return -EINVAL; + } + + ve3_log_class = class_create(THIS_MODULE, "ve3_log"); + if (ve3_log_class == NULL) + pr_err("failed to create ve3_log attribute!\n"); + ret = class_create_file(ve3_log_class, &class_attr_ve3_log); + + prop = of_get_property(pdev->dev.of_node, "log_enable", &size); + if (prop) { + ve3_uart_enable = of_read_number(prop, 1); + } else { + ve3_uart_enable = 0; + } + + init_waitqueue_head(&ve3_uart_waitQueue); + ve3_uart_kthread = kthread_run(ve3_uart_thread, (void *)&j, "ve3_uart_thread"); + + ve3_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ve3_clk)) { + dev_err(&pdev->dev, "ve3 clock source missing or invalid\n"); + return PTR_ERR(ve3_clk); + } + clk_prepare_enable(ve3_clk); + + return ret; +} + +static int rtk_ve3_uart_remove(struct platform_device *pdev) +{ + class_destroy(ve3_log_class); + + return 0; +} + +static struct of_device_id rtk_ve3_uart_ids[] = { + { .compatible = "realtek,rtk-ve3-uart" }, + { /* Sentinel */ }, +}; + +static struct platform_driver rtk_ve3_uart_driver = { + .probe = rtk_ve3_uart_probe, + .remove = rtk_ve3_uart_remove, + .driver = { + .name = MODULE_NAME, + .bus = &platform_bus_type, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtk_ve3_uart_ids), + }, +}; + + +static int rtk_ve3_uart_init(void) +{ + return platform_driver_register(&rtk_ve3_uart_driver); +} +subsys_initcall(rtk_ve3_uart_init); + +//module_platform_driver(rtk_ve3_uart_driver); + +MODULE_DESCRIPTION("Realtek VE3 Uart driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/soc/realtek/common/rtk_vsfc_ctrl.c b/drivers/soc/realtek/common/rtk_vsfc_ctrl.c new file mode 100644 index 000000000000..3248e4670a39 --- /dev/null +++ b/drivers/soc/realtek/common/rtk_vsfc_ctrl.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum clk_output_sel { + CLK_OUTPUT_DIRECT = 0, + CLK_OUTPUT_VSFC, +}; + +struct vsfc_ctrl_data { + struct device *dev; + struct clk_hw hw; + struct regmap *crt; + struct regmap *sc_wrap; + struct clk *clk; + struct regulator *supply; + enum clk_output_sel output; + unsigned long threshold_freq; + int threshold_volt; +}; + +/* crt register offsets */ +#define SYS_PLL_SCPU1 0x100 +#define SYS_PLL_SCPU3 0x108 + +/* scpu wrapper register offsets */ +#define FSS_CTRL0 0xb70 +#define FSS_CTRL1 0xb74 +#define FSS_CTRL2 0xb78 +#define FSS_CTRL3 0xb7c + +#define VSFC_CTRL 0xf00 +#define VSFC_STATUS 0xf04 +#define VSFC_TRIG_CTRL 0xf08 +#define VSFC_RECV_CTRL0 0xf0c +#define VSFC_RECV_CTRL1 0xf10 +#define VSFC_PROF_CTRL0 0xf24 +#define VSFC_PROF_INTST 0xf3c +#define VSFC_PROF_INTEN 0xf40 + +static void vsfc_ctrl_enable_fss(struct vsfc_ctrl_data *data) +{ + regmap_write(data->sc_wrap, FSS_CTRL0, 0x00000000); + udelay(200); + + regmap_write(data->sc_wrap, FSS_CTRL0, 0x3f000000); + udelay(200); + + regmap_write(data->sc_wrap, FSS_CTRL1, 0x00eeeeee); + regmap_write(data->sc_wrap, FSS_CTRL2, 0x00ffffff); + regmap_write(data->sc_wrap, FSS_CTRL3, 0x00eeeeee); + + regmap_write(data->sc_wrap, FSS_CTRL0, 0x3f00003f); +} + +static void vsfc_ctrl_disable_fss(struct vsfc_ctrl_data *data) +{ + regmap_write(data->sc_wrap, FSS_CTRL0, 0); +} + +static void vsfc_ctrl_set_output_vsfc(struct vsfc_ctrl_data *data) +{ + regmap_update_bits(data->crt, SYS_PLL_SCPU1, 0x43000000, 0x40000000); + regmap_update_bits(data->crt, SYS_PLL_SCPU3, 0x00380000, 0x00280000); +} + +static void vsfc_ctrl_set_output_direct(struct vsfc_ctrl_data *data) +{ + regmap_update_bits(data->crt, SYS_PLL_SCPU1, 0x43000000, 0x00000000); + regmap_update_bits(data->crt, SYS_PLL_SCPU3, 0x00380000, 0x00180000); +} + +static void vsfc_ctrl_setup_vsfc_freq(struct vsfc_ctrl_data *data, uint32_t val) +{ + regmap_write(data->sc_wrap, VSFC_CTRL, 0x00000400); + regmap_write(data->sc_wrap, VSFC_TRIG_CTRL, 0x00000000); + regmap_write(data->sc_wrap, VSFC_RECV_CTRL1, val); + regmap_write(data->sc_wrap, VSFC_RECV_CTRL0, 0x00000002); + regmap_write(data->sc_wrap, VSFC_CTRL, 0x00000401); +} + +static void vsfc_ctrl_update_vsfc_freq(struct vsfc_ctrl_data *data, uint32_t val) +{ + regmap_write(data->sc_wrap, VSFC_CTRL, 0x00000400); + regmap_write(data->sc_wrap, VSFC_RECV_CTRL1, val); + regmap_write(data->sc_wrap, VSFC_CTRL, 0x00000401); +} + +static void vsfc_ctrl_takedown_vsfc(struct vsfc_ctrl_data *data) +{ + regmap_write(data->sc_wrap, VSFC_CTRL, 0x00000000); +} + +struct freq_lowf { + unsigned long freq; + uint32_t lowf; +}; + +static const struct freq_lowf vsfc_freq_table[] = { + { 624000000, 0x49490010 }, + { 806400000, 0x81010010 }, + { 0, 0 } +}; + +static uint32_t freq_to_lowf(unsigned long target) +{ + int i; + + for (i = 0; vsfc_freq_table[i].freq != 0; i++) + if (vsfc_freq_table[i].freq == target) + return vsfc_freq_table[i].lowf; + return 0; +} + +static unsigned long lowf_to_freq(uint32_t target) +{ + int i; + + for (i = 0; vsfc_freq_table[i].freq != 0; i++) + if (vsfc_freq_table[i].lowf == target) + return vsfc_freq_table[i].freq; + return 0; +} + +static unsigned long freq_round(unsigned long target) +{ + int i; + unsigned long closest = 0; + + for (i = 0; vsfc_freq_table[i].freq != 0; i++) { + + if (vsfc_freq_table[i].freq == target) + return target; + + if (vsfc_freq_table[i].freq < target && (target - vsfc_freq_table[i].freq) < (target - closest)) + closest = vsfc_freq_table[i].freq; + } + + return closest; +} + +static int vsfc_ctrl_update_output(struct vsfc_ctrl_data *data, enum clk_output_sel next) +{ + int ret = 0; + + if (data->output != next) + ret = 1; + data->output = next; + return ret; +} + +static int vsfc_ctrl_output_is_direct(struct vsfc_ctrl_data *data) +{ + return data->output == CLK_OUTPUT_DIRECT; +} + +static int vsfc_ctrl_set_vfsc_freq(struct vsfc_ctrl_data *data, unsigned long target) +{ + uint32_t val = freq_to_lowf(target); + + if (!val) + return -EINVAL; + + if (!vsfc_ctrl_update_output(data, CLK_OUTPUT_VSFC)) { + vsfc_ctrl_update_vsfc_freq(data, val); + return 0; + } + + clk_set_rate(data->clk, data->threshold_freq); + + regulator_set_voltage(data->supply, data->threshold_volt, data->threshold_volt); + + vsfc_ctrl_enable_fss(data); + + vsfc_ctrl_set_output_vsfc(data); + + vsfc_ctrl_setup_vsfc_freq(data, val); + + return 0; +} + +static int vsfc_ctrl_set_pll_freq(struct vsfc_ctrl_data *data, unsigned long target) +{ + if (vsfc_ctrl_update_output(data, CLK_OUTPUT_DIRECT)) { + vsfc_ctrl_takedown_vsfc(data); + + vsfc_ctrl_set_output_direct(data); + + vsfc_ctrl_disable_fss(data); + } + + return clk_set_rate(data->clk, target); +} + +static unsigned long vsfc_ctrl_get_current_freq(struct vsfc_ctrl_data *data) +{ + uint32_t val; + + regmap_read(data->sc_wrap, VSFC_RECV_CTRL1, &val); + + return lowf_to_freq(val); +} + +static int vsfc_ctrl_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +{ + struct vsfc_ctrl_data *data = container_of(hw, struct vsfc_ctrl_data, hw); + int ret; + + dev_dbg(data->dev, "%s: rate=%lu\n", __func__, rate); + + if (rate >= data->threshold_freq) + ret = vsfc_ctrl_set_pll_freq(data, rate); + else + ret = vsfc_ctrl_set_vfsc_freq(data, rate); + return ret; +} + +static unsigned long vsfc_ctrl_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct vsfc_ctrl_data *data = container_of(hw, struct vsfc_ctrl_data, hw); + + if (vsfc_ctrl_output_is_direct(data)) + return clk_get_rate(data->clk); + else + return vsfc_ctrl_get_current_freq(data); +} + +static long vsfc_ctrl_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) +{ + struct vsfc_ctrl_data *data = container_of(hw, struct vsfc_ctrl_data, hw); + + if (rate >= data->threshold_freq) + return clk_round_rate(data->clk, rate); + else + return freq_round(rate); +} + +static const struct clk_ops vsfc_ctrl_clk_ops = { + .round_rate = vsfc_ctrl_round_rate, + .recalc_rate = vsfc_ctrl_recalc_rate, + .set_rate = vsfc_ctrl_set_rate, +}; + +static void vsfc_ctrl_remove_of_clk_provider(void *d) +{ + struct vsfc_ctrl_data *data = d; + + of_clk_del_provider(data->dev->of_node); +} + +static int vsfc_ctrl_add_clk(struct vsfc_ctrl_data *data) +{ + struct device *dev = data->dev; + struct device_node *np = dev->of_node; + struct clk_init_data init_data = { + .name = "vsfc", + .ops = &vsfc_ctrl_clk_ops, + .num_parents = 0, + .flags = CLK_GET_RATE_NOCACHE, + }; + int ret; + + data->hw.init = &init_data; + ret = devm_clk_hw_register(dev, &data->hw); + if (ret) + return ret; + + ret = of_clk_add_provider(np, of_clk_src_simple_get, data->hw.clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, vsfc_ctrl_remove_of_clk_provider, data); + if (ret) + return ret; + + return 0; +} + +static int vsfc_ctrl_regulator_list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct vsfc_ctrl_data *data = rdev_get_drvdata(rdev); + + return regulator_list_voltage(data->supply, selector); +} + +static int vsfc_ctrl_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct vsfc_ctrl_data *data = rdev_get_drvdata(rdev); + + return regulator_get_voltage(data->supply); +} + +static int vsfc_ctrl_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct vsfc_ctrl_data *data = rdev_get_drvdata(rdev); + + dev_dbg(data->dev, "%s: voltage=(%d, %d)\n", __func__, min_uV, max_uV); + return regulator_set_voltage(data->supply, min_uV, max_uV); +} + +static const struct regulator_ops vsfc_ctrl_regulator_ops = { + .get_voltage = vsfc_ctrl_regulator_get_voltage, + .set_voltage = vsfc_ctrl_regulator_set_voltage, + .list_voltage = vsfc_ctrl_regulator_list_voltage, +}; + +static struct regulator_desc vsfc_ctrl_supply_desc = { + .owner = THIS_MODULE, + .ops = &vsfc_ctrl_regulator_ops, + .type = REGULATOR_VOLTAGE, + .name = "vsfc", +}; + +static int vsfc_ctrl_add_supply(struct vsfc_ctrl_data *data) +{ + struct regulator_config config = { + .dev = data->dev, + .of_node = data->dev->of_node, + .driver_data = data, + }; + + vsfc_ctrl_supply_desc.n_voltages = regulator_count_voltages(data->supply); + + config.init_data = of_get_regulator_init_data(data->dev, data->dev->of_node, + &vsfc_ctrl_supply_desc); + + if (!config.init_data) + return -ENOMEM; + + return PTR_ERR_OR_ZERO(devm_regulator_register(data->dev, &vsfc_ctrl_supply_desc, &config)); +} + +static int vsfc_ctrl_add_suppliers(struct vsfc_ctrl_data *data) +{ + int ret; + + ret = vsfc_ctrl_add_clk(data); + if (ret) { + dev_err(data->dev, "failed to add clk: %d\n", ret); + return ret; + } + + ret = vsfc_ctrl_add_supply(data); + if (ret) { + dev_err(data->dev, "failed to add supply: %d\n", ret); + return ret; + } + + return 0; +} + +static int vsfc_ctrl_of_parse_threshold(struct device_node *np, struct vsfc_ctrl_data *data) +{ + struct device_node *opp_np; + uint64_t f; + uint32_t v; + int ret; + + opp_np = of_parse_phandle(np, "threshold-opp", 0); + if (!opp_np) + return -EINVAL; + + ret = of_property_read_u64(opp_np, "opp-hz", &f); + if (ret) + return ret; + + ret = of_property_read_u32(opp_np, "opp-microvolt-fss", &v); + if (ret || v == 0) + ret = of_property_read_u32(opp_np, "opp-microvolt", &v); + if (ret) + return ret; + + data->threshold_freq = f; + data->threshold_volt = v; + return 0; +} + +static int vsfc_ctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct vsfc_ctrl_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->dev = dev; + + ret = vsfc_ctrl_of_parse_threshold(np, data); + if (ret) { + dev_err(dev, "failed to parse threshold: %d\n", ret); + return ret; + } + + data->crt = syscon_regmap_lookup_by_phandle(np, "realtek,crt"); + if (IS_ERR(data->crt)) { + ret = PTR_ERR(data->crt); + dev_err(dev, "failed to get crt syscon: %d\n", ret); + return ret; + } + + data->sc_wrap = syscon_regmap_lookup_by_phandle(np, "realtek,sc-wrap"); + if (IS_ERR(data->sc_wrap)) { + ret = PTR_ERR(data->sc_wrap); + dev_err(dev, "failed to get sc_wrap syscon: %d\n", ret); + return ret; + } + + data->clk = devm_clk_get(dev, NULL); + if (IS_ERR(data->clk)) { + ret = PTR_ERR(data->clk); + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + data->supply = devm_regulator_get(dev, "cpu"); + if (IS_ERR(data->supply)) { + ret = PTR_ERR(data->supply); + dev_err(dev, "failed to get supply: %d\n", ret); + return ret; + } + + return vsfc_ctrl_add_suppliers(data); +} + +static const struct of_device_id vsfc_ctrl_match[] = { + { .compatible = "realtek,vsfc-ctrl", }, + {} +}; + +static struct platform_driver vsfc_ctrl_driver = { + .probe = vsfc_ctrl_probe, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-vsfc-ctrl", + .of_match_table = of_match_ptr(vsfc_ctrl_match), + }, +}; +module_platform_driver(vsfc_ctrl_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rtk-vsfc-ctrl"); +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_DESCRIPTION("Realtek VSFC controller"); diff --git a/drivers/soc/realtek/common/rtk_watchdog_status.c b/drivers/soc/realtek/common/rtk_watchdog_status.c new file mode 100644 index 000000000000..72d6abf0338b --- /dev/null +++ b/drivers/soc/realtek/common/rtk_watchdog_status.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCW5ST 0x18 +#define TCWRCR 0x20 + +struct rtk_watchdog_status_data { + void *base; +}; + +static const char *name[] = { + "gpu", "ve2", "ve1", "rng", "r2rdsc", "vo", "pcpu_otp", "pcpu_iso", + "tpb", "main", "sce", "nag", "tmx", "scpu_iso", "scpu_otp", + "emmc", "nf", "cp", "", "tp", "dc", "sb2", "dp", + "rsa", "kt", "uvlo", "npu", "scpu_wrapper", "crt", "aucpu0", "", +}; + +static inline int get_reset_count(struct rtk_watchdog_status_data *data, int id) +{ + unsigned int val = readl(data->base + TCWRCR); + + return (val >> (id * 4)) & 0xf; +} + +static inline unsigned int get_ip_assert_status(struct rtk_watchdog_status_data *data) +{ + return readl(data->base + TCW5ST); +} + +static ssize_t ip_assert_status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct rtk_watchdog_status_data *data = dev_get_drvdata(dev); + unsigned long val = get_ip_assert_status(data); + ssize_t len = 0; + int i; + int first = 0; + + for (i = 0; i < 32; i++) + if (test_bit(i, &val)) { + len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", first == 0 ? "" : " ", name[i]); + first = 1; + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} +static DEVICE_ATTR_RO(ip_assert_status); + +static ssize_t reset_count_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct rtk_watchdog_status_data *data = dev_get_drvdata(dev); + ssize_t len = 0; + int i; + + for (i = 0; i <= 5; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "wdt%d=%d\n", i, get_reset_count(data, i)); + return len; +} +static DEVICE_ATTR_RO(reset_count); + +static struct attribute *watchdog_status_attrs[] = { + &dev_attr_ip_assert_status.attr, + &dev_attr_reset_count.attr, + NULL +}; + +static const struct attribute_group watchdog_status_attr_group = { + .attrs = watchdog_status_attrs, + .name = "watchdog_status", +}; + +static int rtk_watchdog_status_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_watchdog_status_data *data; + int ret; + + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->base = of_iomap(dev->of_node, 0); + if (!data->base) + return -ENOMEM; + + ret = sysfs_create_group(&dev->kobj, &watchdog_status_attr_group); + if (ret) { + iounmap(data->base); + return ret; + } + + platform_set_drvdata(pdev, data); + return 0; +} + +static int rtk_watchdog_status_remove(struct platform_device *pdev) +{ + struct rtk_watchdog_status_data *data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + sysfs_remove_group(&pdev->dev.kobj, &watchdog_status_attr_group); + iounmap(data->base); + return 0; +} + +static const struct of_device_id rtk_watchdog_status_match[] = { + { .compatible = "realtek,rtd1619b-watchdog-status", }, + {} +}; + +static struct platform_driver rtk_watchdog_status_driver = { + .probe = rtk_watchdog_status_probe, + .remove = rtk_watchdog_status_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-wdt-st", + .of_match_table = of_match_ptr(rtk_watchdog_status_match), + }, +}; +module_platform_driver(rtk_watchdog_status_driver); + +MODULE_DESCRIPTION("Realtek Watchdog Status driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-wdt-st"); diff --git a/drivers/soc/realtek/rtd13xx/Makefile b/drivers/soc/realtek/rtd13xx/Makefile new file mode 100644 index 000000000000..b481605c99a0 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_RTD13XX_RTK_CODEC) += rtk_ve/ diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/Makefile b/drivers/soc/realtek/rtd13xx/rtk_ve/Makefile new file mode 100644 index 000000000000..66ea0533a8c5 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Realtek codec drivers. +# +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/rtk/inc +obj-$(CONFIG_RTD13XX_RTK_CODEC) += puwrap.o +obj-$(CONFIG_RTD13XX_VE1_CODEC) += ve1/ +obj-$(CONFIG_RTD13XX_IMAGE_CODEC) += jdi/ diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/Makefile b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/Makefile new file mode 100644 index 000000000000..94198848f853 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/Makefile @@ -0,0 +1,6 @@ +# rtk_jcodec + +obj-$(CONFIG_RTD13XX_IMAGE_CODEC) += jpu.o +ifdef CONFIG_COMPAT +obj-$(CONFIG_RTD13XX_IMAGE_CODEC) += compat_jpu.o +endif diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.c b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.c new file mode 100644 index 000000000000..fb5d79f7087c --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.c @@ -0,0 +1,324 @@ +/* + * drivers/soc/realtek/rtd129x/rtk_ve/jdi/compat_jpu.h + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "jpu.h" +#include "compat_jpu.h" + +/* See drivers/soc/realtek/rtd129x/rtk_ve/jdi/jpu.h for the definition of these structs */ +typedef struct compat_jpudrv_buffer_t { + compat_uint_t size; + compat_ulong_t phys_addr; + compat_ulong_t base; /* kernel logical address in use kernel */ + compat_ulong_t virt_addr; /* virtual user space address */ +} compat_jpudrv_buffer_t; + +typedef struct compat_jpudrv_intr_info_t { + compat_uint_t timeout; + compat_int_t intr_reason; +} compat_jpudrv_intr_info_t; + +typedef struct compat_jpudrv_dovi_info_t{ + compat_uint_t inst_idx; + compat_uint_t enable; +} compat_jpudrv_dovi_info_t; + +#define COMPAT_JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(JDI_IOCTL_MAGIC, 0) +#define COMPAT_JDI_IOCTL_FREE_PHYSICALMEMORY _IO(JDI_IOCTL_MAGIC, 1) +#define COMPAT_JDI_IOCTL_WAIT_INTERRUPT _IO(JDI_IOCTL_MAGIC, 2) +#define COMPAT_JDI_IOCTL_GET_INSTANCE_POOL _IO(JDI_IOCTL_MAGIC, 5) +#define COMPAT_JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(JDI_IOCTL_MAGIC, 6) +#define COMPAT_JDI_IOCTL_GET_REGISTER_INFO _IO(JDI_IOCTL_MAGIC, 11) +#define COMPAT_JDI_IOCTL_GET_BONDING_INFO _IO(JDI_IOCTL_MAGIC, 13) +#define COMPAT_JDI_IOCTL_SET_RTK_DOVI_FLAG _IO(JDI_IOCTL_MAGIC, 14) + +static int compat_get_jpu_buffer_data( + compat_jpudrv_buffer_t __user *data32, + jpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + int err; + + err = get_user(s, &data32->size); + err |= put_user(s, &data->size); + err |= get_user(p, &data32->phys_addr); + err |= put_user(p, &data->phys_addr); + err |= get_user(b, &data32->base); + err |= put_user(b, &data->base); + err |= get_user(v, &data32->virt_addr); + err |= put_user(v, &data->virt_addr); + + return err; +} + +static int compat_get_jpu_intr_info_data( + compat_jpudrv_intr_info_t __user *data32, + jpudrv_intr_info_t __user *data) +{ + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(t, &data32->timeout); + err |= put_user(t, &data->timeout); + err |= get_user(i, &data32->intr_reason); + err |= put_user(i, &data->intr_reason); + + return err; +} + +static int compat_get_jpu_dovi_info( + compat_jpudrv_dovi_info_t __user *data32, + jpudrv_dovi_info_t __user *data) +{ + compat_uint_t e; + compat_uint_t i; + int err; + + err |= get_user(i, &data32->inst_idx); + err |= put_user(i, &data->inst_idx); + err |= get_user(e, &data32->enable); + err |= put_user(e, &data->enable); + + return err; +} + +static int compat_put_jpu_buffer_data( + compat_jpudrv_buffer_t __user *data32, + jpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + int err; + + err = get_user(s, &data->size); + err |= put_user(s, &data32->size); + err |= get_user(p, &data->phys_addr); + err |= put_user(p, &data32->phys_addr); + err |= get_user(b, &data->base); + err |= put_user(b, &data32->base); + err |= get_user(v, &data->virt_addr); + err |= put_user(v, &data32->virt_addr); + + return err; +} + +static int compat_put_jpu_intr_info_data( + compat_jpudrv_intr_info_t __user *data32, + jpudrv_intr_info_t __user *data) +{ + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(t, &data->timeout); + err |= put_user(t, &data32->timeout); + err |= get_user(i, &data->intr_reason); + err |= put_user(i, &data32->intr_reason); + + return err; +} + +static int compat_put_jpu_dovi_info( + compat_jpudrv_dovi_info_t __user *data32, + jpudrv_dovi_info_t __user *data) +{ + compat_uint_t i; + compat_uint_t e; + int err; + + err |= get_user(i, &data->inst_idx); + err |= put_user(i, &data32->inst_idx); + err |= get_user(e, &data->enable); + err |= put_user(e, &data32->enable); + + return err; +} + +long compat_jpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + + if (!filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) + { + case COMPAT_JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_FREE_PHYSICALMEMORY: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_FREE_PHYSICALMEMORY, (unsigned long)data); + } + + case COMPAT_JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_WAIT_INTERRUPT: + { + compat_jpudrv_intr_info_t __user *data32; + jpudrv_intr_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_intr_info_data(data32, data); + if (err) + return err; + + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_WAIT_INTERRUPT, (unsigned long)data); + err = compat_put_jpu_intr_info_data(data32, data); + return ret ? ret : err; + } + + case JDI_IOCTL_ENABLE_INTERRUPT: + case JDI_IOCTL_SET_CLOCK_GATE: + case JDI_IOCTL_OPEN_INSTANCE: + case JDI_IOCTL_CLOSE_INSTANCE: + case JDI_IOCTL_GET_INSTANCE_NUM: + case JDI_IOCTL_RESET: + case JDI_IOCTL_SET_CLOCK_ENABLE: + { + return filp->f_op->unlocked_ioctl(filp, cmd, + (unsigned long)compat_ptr(arg)); + } + + case COMPAT_JDI_IOCTL_GET_INSTANCE_POOL: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_INSTANCE_POOL, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_GET_REGISTER_INFO: + case COMPAT_JDI_IOCTL_GET_BONDING_INFO: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + if (cmd == COMPAT_JDI_IOCTL_GET_REGISTER_INFO) + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_REGISTER_INFO, (unsigned long)data); + else + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_BONDING_INFO, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_SET_RTK_DOVI_FLAG: + { + compat_jpudrv_dovi_info_t __user *data32; + jpudrv_dovi_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_dovi_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_SET_RTK_DOVI_FLAG, (unsigned long)data); + err = compat_put_jpu_dovi_info(data32, data); + return ret ? ret : err; + } + + default: + { + printk(KERN_ERR "[COMPAT JPU]No such IOCTL, cmd is %d\n", cmd); + return -ENOIOCTLCMD; + } + } +} + diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.h b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.h new file mode 100644 index 000000000000..2d920c966187 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/compat_jpu.h @@ -0,0 +1,31 @@ +/* + + * drivers/soc/realtek/rtd129x/rtk_ve/jdi/compat_jpu.h + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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_COMPAT_JPU_H +#define _LINUX_COMPAT_JPU_H + +#if IS_ENABLED(CONFIG_COMPAT) + +long compat_jpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +#define compat_jpu_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_JPU_H */ + diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jmm.h b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jmm.h new file mode 100644 index 000000000000..e54a2284a8a5 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jmm.h @@ -0,0 +1,647 @@ +#ifndef __JPU_MM_H__ +#define __JPU_MM_H__ + + +typedef unsigned long long jmem_key_t; + +#define JMEM_PAGE_SIZE (16*1024) +#define MAKE_KEY(_a, _b) (((jmem_key_t)_a)<<32 | _b) +#define KEY_TO_VALUE(_key) (_key>>32) + +typedef struct page_struct { + int pageno; + unsigned long addr; + int used; + int alloc_pages; + int first_pageno; +} page_t; + + +typedef struct avl_node_struct { + jmem_key_t key; + int height; + page_t* page; + struct avl_node_struct* left; + struct avl_node_struct* right; +} avl_node_t; + + +typedef struct _jpu_mm_struct { + avl_node_t* free_tree; + avl_node_t* alloc_tree; + page_t* page_list; + int num_pages; + unsigned long base_addr; + unsigned long mem_size; + int free_page_count; + int alloc_page_count; +} jpu_mm_t; + + + +#define VMEM_P_ALLOC(_x) kmalloc(_x, GFP_KERNEL) +#define VMEM_P_FREE(_x) kfree(_x) + +#define VMEM_ASSERT(_exp) if (!(_exp)) { printk(KERN_INFO "VMEM_ASSERT at %s:%d\n", __FILE__, __LINE__); /*while(1);*/ +} +#define VMEM_HEIGHT(_tree) (_tree==NULL ? -1 : _tree->height) + + +#define MAX(_a, _b) (_a >= _b ? _a : _b) + +typedef enum { + LEFT, + RIGHT +} rotation_dir_t; + + + +typedef struct avl_node_data_struct { + int key; + page_t* page; +} avl_node_data_t; + +static avl_node_t* +make_avl_node( + jmem_key_t key, + page_t* page +) +{ + avl_node_t* node = (avl_node_t*)VMEM_P_ALLOC(sizeof(avl_node_t)); + node->key = key; + node->page = page; + node->height = 0; + node->left = NULL; + node->right = NULL; + + return node; +} + + +static int +get_balance_factor( + avl_node_t* tree +) +{ + int factor = 0; + if (tree) { + factor = VMEM_HEIGHT(tree->right) - VMEM_HEIGHT(tree->left); + } + + return factor; +} + +/* + * Left Rotation + * + * A B + * \ / \ + * B => A C + * / \ \ + * D C D + * + */ +static avl_node_t* +rotation_left( + avl_node_t* tree +) +{ + avl_node_t* rchild; + avl_node_t* lchild; + + if (tree == NULL) return NULL; + + rchild = tree->right; + if (rchild == NULL) { + return tree; + } + + lchild = rchild->left; + rchild->left = tree; + tree->right = lchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + rchild->height = MAX(VMEM_HEIGHT(rchild->left), VMEM_HEIGHT(rchild->right)) + 1; + + return rchild; +} + + +/* + * Reft Rotation + * + * A B + * \ / \ + * B => D A + * / \ / + * D C C + * + */ +static avl_node_t* +rotation_right( + avl_node_t* tree +) +{ + avl_node_t* rchild; + avl_node_t* lchild; + + if (tree == NULL) return NULL; + + lchild = tree->left; + if (lchild == NULL) return NULL; + + rchild = lchild->right; + lchild->right = tree; + tree->left = rchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + lchild->height = MAX(VMEM_HEIGHT(lchild->left), VMEM_HEIGHT(lchild->right)) + 1; + + return lchild; +} + +static avl_node_t* +do_balance( + avl_node_t* tree +) +{ + int bfactor = 0, child_bfactor; /* balancing factor */ + + bfactor = get_balance_factor(tree); + + if (bfactor >= 2) { + child_bfactor = get_balance_factor(tree->right); + if (child_bfactor == 1 || child_bfactor == 0) { + tree = rotation_left(tree); + } else if (child_bfactor == -1) { + tree->right = rotation_right(tree->right); + tree = rotation_left(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } else if (bfactor <= -2) { + child_bfactor = get_balance_factor(tree->left); + if (child_bfactor == -1 || child_bfactor == 0) { + tree = rotation_right(tree); + } else if (child_bfactor == 1) { + tree->left = rotation_left(tree->left); + tree = rotation_right(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } + + return tree; +} +static avl_node_t* +unlink_end_node( + avl_node_t* tree, + int dir, + avl_node_t** found_node +) +{ + avl_node_t* node; + *found_node = NULL; + + if (tree == NULL) return NULL; + + if (dir == LEFT) { + if (tree->left == NULL) { + *found_node = tree; + return NULL; + } + } else { + if (tree->right == NULL) { + *found_node = tree; + return NULL; + } + } + + if (dir == LEFT) { + node = tree->left; + tree->left = unlink_end_node(tree->left, LEFT, found_node); + if (tree->left == NULL) { + tree->left = (*found_node)->right; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } else { + node = tree->right; + tree->right = unlink_end_node(tree->right, RIGHT, found_node); + if (tree->right == NULL) { + tree->right = (*found_node)->left; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return do_balance(tree); +} + + +static avl_node_t* +avltree_insert( + avl_node_t* tree, + jmem_key_t key, + page_t* page +) +{ + if (tree == NULL) { + tree = make_avl_node(key, page); + } else { + if (key >= tree->key) { + tree->right = avltree_insert(tree->right, key, page); + } else { + tree->left = avltree_insert(tree->left, key, page); + } + } + + tree = do_balance(tree); + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return tree; +} + +static avl_node_t* +do_unlink( + avl_node_t* tree +) +{ + avl_node_t* node; + avl_node_t* end_node; + node = unlink_end_node(tree->right, LEFT, &end_node); + if (node) { + tree->right = node; + } else { + node = unlink_end_node(tree->left, RIGHT, &end_node); + if (node) tree->left = node; + } + + if (node == NULL) { + node = tree->right ? tree->right : tree->left; + end_node = node; + } + + if (end_node) { + end_node->left = (tree->left != end_node) ? tree->left : end_node->left; + end_node->right = (tree->right != end_node) ? tree->right : end_node->right; + end_node->height = MAX(VMEM_HEIGHT(end_node->left), VMEM_HEIGHT(end_node->right)) + 1; + } + + tree = end_node; + + return tree; +} + +static avl_node_t* +avltree_remove( + avl_node_t* tree, + avl_node_t** found_node, + jmem_key_t key +) +{ + *found_node = NULL; + if (tree == NULL) { + printk(KERN_INFO "failed to find key %d\n", (int)key); + return NULL; + } + + if (key == tree->key) { + *found_node = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = avltree_remove(tree->right, found_node, key); + } else { + tree->left = avltree_remove(tree->left, found_node, key); + } + + if (tree) tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +void +jpu_avltree_free( + avl_node_t* tree +) +{ + if (tree == NULL) return; + if (tree->left == NULL && tree->right == NULL) { + VMEM_P_FREE(tree); + return; + } + + jpu_avltree_free(tree->left); + tree->left = NULL; + jpu_avltree_free(tree->right); + tree->right = NULL; +} + + + + +static avl_node_t* +remove_approx_value( + avl_node_t* tree, + avl_node_t** found, + jmem_key_t key +) +{ + *found = NULL; + if (tree == NULL) { + return NULL; + } + + if (key == tree->key) { + *found = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = remove_approx_value(tree->right, found, key); + } else { + tree->left = remove_approx_value(tree->left, found, key); + if (*found == NULL) { + *found = tree; + tree = do_unlink(tree); + } + } + if (tree) tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + tree = do_balance(tree); + + return tree; +} + +static void +set_blocks_free( + jpu_mm_t *mm, + int pageno, + int npages +) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t* page; + page_t* last_page; + + VMEM_ASSERT(npages); + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i=pageno; i<=last_pageno; i++) { + mm->page_list[i].used = 0; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->free_tree = avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page); +} + +static void +set_blocks_alloc( + jpu_mm_t *mm, + int pageno, + int npages +) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t* page; + page_t* last_page; + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i=pageno; i<=last_pageno; i++) { + mm->page_list[i].used = 1; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->alloc_tree = avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page); +} + + +int +jmem_init( + jpu_mm_t* mm, + unsigned long addr, + unsigned long size +) +{ + int i; + + + mm->base_addr = (addr+(JMEM_PAGE_SIZE-1))&~(JMEM_PAGE_SIZE-1); + mm->mem_size = size&~JMEM_PAGE_SIZE; + mm->num_pages = mm->mem_size/JMEM_PAGE_SIZE; + mm->page_list = (page_t*)VMEM_P_ALLOC(mm->num_pages*sizeof(page_t)); + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = mm->num_pages; + mm->alloc_page_count = 0; + + for (i=0; inum_pages; i++) { + mm->page_list[i].pageno = i; + mm->page_list[i].addr = mm->base_addr + i*JMEM_PAGE_SIZE; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].used = 0; + mm->page_list[i].first_pageno = -1; + } + + set_blocks_free(mm, 0, mm->num_pages); + + return 0; +} + +int +jmem_exit( + jpu_mm_t* mm +) +{ + if (mm == NULL) { + printk(KERN_INFO "vmem_exit: invalid handle\n"); + return -1; + } + + if (mm->free_tree) { + jpu_avltree_free(mm->free_tree); + } + if (mm->alloc_tree) { + jpu_avltree_free(mm->alloc_tree); + } + + VMEM_P_FREE(mm->page_list); + + mm->base_addr = 0; + mm->mem_size = 0; + mm->num_pages = 0; + mm->page_list = NULL; + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = 0; + mm->alloc_page_count = 0; + return 0; +} + +unsigned long +jmem_alloc( + jpu_mm_t* mm, + int size, + unsigned long pid +) +{ + avl_node_t* node; + page_t* free_page; + int npages, free_size; + int alloc_pageno; + unsigned long ptr; + + if (mm == NULL) { + printk(KERN_INFO "vmem_alloc: invalid handle\n"); + return -1; + } + + if (size <= 0) return -1; + + npages = (size + JMEM_PAGE_SIZE -1)/JMEM_PAGE_SIZE; + + mm->free_tree = remove_approx_value(mm->free_tree, &node, MAKE_KEY(npages, 0)); + if (node == NULL) { + return -1; + } + free_page = node->page; + free_size = KEY_TO_VALUE(node->key); + + alloc_pageno = free_page->pageno; + set_blocks_alloc(mm, alloc_pageno, npages); + if (npages != free_size) { + int free_pageno = alloc_pageno + npages; + set_blocks_free(mm, free_pageno, (free_size-npages)); + } + + VMEM_P_FREE(node); + + ptr = mm->page_list[alloc_pageno].addr; + mm->alloc_page_count += npages; + mm->free_page_count -= npages; + + + return ptr; +} + +int +jmem_free( + jpu_mm_t* mm, + unsigned long ptr, + unsigned long pid +) +{ + unsigned long addr; + avl_node_t* found; + page_t* page; + int pageno, prev_free_pageno, next_free_pageno; + int prev_size, next_size; + int merge_page_no, merge_page_size, free_page_size; + + + if (mm == NULL) { + printk(KERN_INFO "vmem_free: invalid handle\n"); + return -1; + } + + addr = ptr; + + mm->alloc_tree = avltree_remove(mm->alloc_tree, &found, MAKE_KEY(addr, 0)); + if (found == NULL) { + printk(KERN_INFO "vmem_free: 0x%08x not found\n", (int)addr); + VMEM_ASSERT(0); + return -1; + } + + /* find previous free block */ + page = found->page; + pageno = page->pageno; + free_page_size = page->alloc_pages; + prev_free_pageno = pageno-1; + prev_size = -1; + if (prev_free_pageno >= 0) { + if (mm->page_list[prev_free_pageno].used == 0) { + prev_free_pageno = mm->page_list[prev_free_pageno].first_pageno; + prev_size = mm->page_list[prev_free_pageno].alloc_pages; + } + } + + /* find next free block */ + next_free_pageno = pageno + page->alloc_pages; + next_free_pageno = (next_free_pageno == mm->num_pages) ? -1 : next_free_pageno; + next_size = -1; + if (next_free_pageno >= 0) { + if (mm->page_list[next_free_pageno].used == 0) { + next_size = mm->page_list[next_free_pageno].alloc_pages; + } + } + VMEM_P_FREE(found); + + /* merge */ + merge_page_no = page->pageno; + merge_page_size = page->alloc_pages; + if (prev_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(prev_size, prev_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_no = found->page->pageno; + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + if (next_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(next_size, next_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + + page->alloc_pages = 0; + page->first_pageno = -1; + + set_blocks_free(mm, merge_page_no, merge_page_size); + + mm->alloc_page_count -= free_page_size; + mm->free_page_count += free_page_size; + + return 0; +} + + + +#endif /* __JPU_MM_H__ */ \ No newline at end of file diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.c b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.c new file mode 100644 index 000000000000..f121834c5a3a --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.c @@ -0,0 +1,1056 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jpu.h" +#include "compat_jpu.h" +#include "../puwrap.h" + +//from jpuconfig.h +#define MAX_NUM_INSTANCE 8 +#define MAX_INST_HANDLE_SIZE (12*1024) + +/* definitions to be changed as customer configuration */ +//#define JPU_SUPPORT_CLOCK_CONTROL /if you want to have clock gating scheme frame by frame +#define JPU_SUPPORT_ISR +/* if the platform driver knows the name of this driver. JPU_PLATFORM_DEVICE_NAME */ +#define JPU_SUPPORT_PLATFORM_DRIVER_REGISTER +#ifndef CONFIG_RTK_RESERVE_MEMORY +/* if this driver knows the dedicated video memory address */ +//#define JPU_SUPPORT_RESERVED_VIDEO_MEMORY +#endif +//#define JPU_IRQ_CONTROL +#define DEV_NAME "[RTK_JPU]" +#define JPU_PLATFORM_DEVICE_NAME "jdec" +#define JPU_CLK_NAME "jpeg" +#define JPU_DEV_NAME "jpu" + +#define JPU_BASE_ADDR 0x9803e000 +#define JPU_REG_SIZE 0x1000 + +#ifdef JPU_SUPPORT_ISR +#define JPU_IRQ_NUM 84+32 +#endif + +#ifndef VM_RESERVED /* for kernel up to 3.7.0 version */ +# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) +#endif + +typedef struct jpu_drv_context_t { + struct fasync_struct *async_queue; + unsigned long interrupt_reason; +} jpu_drv_context_t; + +/* To track the allocated memory buffer */ +typedef struct jpudrv_buffer_pool_t { + struct list_head list; + struct jpudrv_buffer_t jb; + struct file *filp; +} jpudrv_buffer_pool_t; + +/* To track the instance index and buffer in instance pool */ +typedef struct jpudrv_instanace_list_t { + struct list_head list; + unsigned long inst_idx; + struct file *filp; +} jpudrv_instanace_list_t; + +typedef struct jpudrv_instance_pool_t { + unsigned char jpgInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE]; +} jpudrv_instance_pool_t; + +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY +#define JPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (16*1024*1024) +#define JPU_DRAM_PHYSICAL_BASE (0x8AA00000) +#include "jmm.h" +static jpu_mm_t s_jmem; +static jpudrv_buffer_t s_image_memory = {0}; +#endif + +static int jpu_hw_reset(void); +static void jpu_clk_disable(struct clk *clk); +static int jpu_clk_enable(struct clk *clk); +static struct clk *jpu_clk_get(struct device *dev); +static void jpu_clk_put(struct clk *clk); +// end customer definition + +static jpudrv_buffer_t s_jpu_instance_pool = {0}; +static jpu_drv_context_t s_jpu_drv_context; +static struct miscdevice s_jpu_dev; +static int s_jpu_open_count; +static struct clk *s_jpu_clk; +static struct reset_control *rstc_jpeg = NULL; +#ifdef JPU_SUPPORT_ISR +static int s_jpu_irq = JPU_IRQ_NUM; +static atomic_t s_interrupt_flag; +#endif +static unsigned long s_jpu_reg_phy_base = JPU_BASE_ADDR; +static void __iomem *s_jpu_reg_virt_base; +static jpudrv_buffer_t s_jpu_register = {0}; +static jpudrv_buffer_t s_bonding_register = {0}; + +static wait_queue_head_t s_interrupt_wait_q; +static int dbus_en = 1; + +#define JPEG_DBUS_REG (0x0000 + 0xF00) + +static spinlock_t s_jpu_lock = __SPIN_LOCK_UNLOCKED(s_jpu_lock); +static DEFINE_SEMAPHORE(s_jpu_sem); +static struct list_head s_jbp_head = LIST_HEAD_INIT(s_jbp_head); +static struct list_head s_jpu_inst_list_head = LIST_HEAD_INIT(s_jpu_inst_list_head); + +/* implement to power management functions */ +#define ReadJpuRegister(addr) *(volatile unsigned int *)(s_jpu_reg_virt_base + addr) +#define WriteJpuRegister(addr, val) *(volatile unsigned int *)(s_jpu_reg_virt_base + addr) = (unsigned int)val; + +static int jpu_alloc_dma_buffer(jpudrv_buffer_t *jb) +{ +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + jb->phys_addr = (unsigned long)jmem_alloc(&s_jmem, jb->size, 0); + + if ((unsigned long)jb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } + + jb->base = (unsigned long)(s_image_memory.base + (jb->phys_addr - s_image_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + unsigned int ret; + ret = pu_alloc_dma_buffer(jb->size, &jb->phys_addr, &jb->base, 0); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#else + jb->base = (unsigned long)dma_alloc_coherent(s_jpu_dev.this_device, PAGE_ALIGN(jb->size), (dma_addr_t *) (&jb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(jb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#endif +// pr_info("%s base:0x%08x, phy_addr:0x%08x, size:%d\n", DEV_NAME, (unsigned int)jb->base, (unsigned int)jb->phys_addr, jb->size); + return 0; +} + +static int jpu_alloc_dma_buffer2(jpudrv_buffer_t *jb) +{ +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + jb->phys_addr = (unsigned long)jmem_alloc(&s_jmem, jb->size, 0); + + if ((unsigned long)jb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } + + jb->base = (unsigned long)(s_image_memory.base + (jb->phys_addr - s_image_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + unsigned int ret; + ret = pu_alloc_dma_buffer(jb->size, &jb->phys_addr, &jb->base, 0); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } + jb->base = pu_mmap_kernel_buffer(jb->phys_addr, jb->size); + if ((void *)(jb->base) == NULL) { + pr_err("%s pu_mmap_kernel_buffer error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#else + jb->base = (unsigned long)dma_alloc_coherent(s_jpu_dev.this_device, PAGE_ALIGN(jb->size), (dma_addr_t *) (&jb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(jb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#endif +// pr_info("%s base:0x%08x, phy_addr:0x%08x, size:%d\n", DEV_NAME, (unsigned int)jb->base, (unsigned int)jb->phys_addr, jb->size); + return 0; +} + +static void jpu_free_dma_buffer(jpudrv_buffer_t *jb) +{ +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (jb->base) + jmem_free(&s_jmem, jb->phys_addr, 0); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + pu_free_dma_buffer(jb->base, jb->phys_addr); +#else + if (jb->base) + dma_free_coherent(s_jpu_dev.this_device, PAGE_ALIGN(jb->size), (void *)jb->base, jb->phys_addr); +#endif +} + +static int jpu_free_instances(struct file *filp) +{ + u32 inst_idx; + jpudrv_instanace_list_t *jil, *n; + jpudrv_instance_pool_t *jip; + void *jip_base; + void* jdi_mutex_base; + const unsigned int PTHREAD_MUTEX_T_DESTROY_VALUE = 0xdead10cc; + + list_for_each_entry_safe(jil, n, &s_jpu_inst_list_head, list) { + if (jil->filp == filp) { + int i; + for (i = 0; i < MAX_NUM_INSTANCE; i++) /* reset dovi flag */ + { + pu_set_dovi_flag(2, i, 0); + } + + inst_idx = jil->inst_idx; + jip_base = (void *)(s_jpu_instance_pool.base); + jip = (jpudrv_instance_pool_t *)jip_base; + if (jip) { + memset(&jip->jpgInstPool[inst_idx], 0x00, 4); // only first 4 byte is key point to free the corresponding instance. +#define PTHREAD_MUTEX_T_HANDLE_SIZE 40 + jdi_mutex_base = (jip_base + (s_jpu_instance_pool.size - PTHREAD_MUTEX_T_HANDLE_SIZE)); + if (jdi_mutex_base) { + memcpy(jdi_mutex_base, &PTHREAD_MUTEX_T_DESTROY_VALUE, sizeof(unsigned int)); + } + } + s_jpu_open_count--; + list_del(&jil->list); + kfree(jil); + } + } + + return s_jpu_open_count; +} + +static int jpu_free_buffers(struct file *filp) +{ + jpudrv_buffer_pool_t *pool, *n; + jpudrv_buffer_t jb; + + list_for_each_entry_safe(pool, n, &s_jbp_head, list) { + if (pool->filp == filp) { + jb = pool->jb; + if (jb.base) { + jpu_free_dma_buffer(&jb); + list_del(&pool->list); + kfree(pool); + } + } + } + + return 0; +} + +#ifdef JPU_SUPPORT_ISR +static irqreturn_t jpu_irq_handler(int irq, void *dev_id) +{ + jpu_drv_context_t *dev = (jpu_drv_context_t *)dev_id; +#ifdef JPU_IRQ_CONTROL + disable_irq_nosync(s_jpu_irq); +#endif + + dev->interrupt_reason = ReadJpuRegister(0x004); /* MJPEG_PIC_STATUS_REG */ + WriteJpuRegister(0x004, dev->interrupt_reason); + if (dev->async_queue) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* notify the interrupt to userspace */ + + atomic_set(&s_interrupt_flag, 1); + + //pr_info("%s jpu_irq_handler\n", DEV_NAME); + wake_up_interruptible(&s_interrupt_wait_q); + + return IRQ_HANDLED; +} +#endif + +static int jpu_open(struct inode *inode, struct file *filp) +{ + spin_lock(&s_jpu_lock); + + filp->private_data = (void *)(&s_jpu_drv_context); + spin_unlock(&s_jpu_lock); + return 0; +} + +static long jpu_ioctl(struct file *filp, u_int cmd, u_long arg) +{ + int ret = 0; + struct jpu_drv_context_t *dev = (struct jpu_drv_context_t *)filp->private_data; + jpudrv_buffer_pool_t *jbp; + jpudrv_buffer_pool_t *n; + jpudrv_buffer_t jb; + jpudrv_intr_info_t info; + jpudrv_instanace_list_t *jil; + jpudrv_instanace_list_t *tmp; + jpudrv_dovi_info_t doviInfo; + u32 inst_idx; + u32 clkgate; + u32 val; + + switch (cmd) { + case JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + down(&s_jpu_sem); + + jbp = kzalloc(sizeof(*jbp), GFP_KERNEL); + if (!jbp) { + up(&s_jpu_sem); + return -ENOMEM; + } + + ret = copy_from_user(&(jbp->jb), (jpudrv_buffer_t *)arg, sizeof(jpudrv_buffer_t)); + if (ret) { + kfree(jbp); + up(&s_jpu_sem); + return -EFAULT; + } + + ret = jpu_alloc_dma_buffer(&(jbp->jb)); + if (ret == -1) { + ret = -ENOMEM; + kfree(jbp); + up(&s_jpu_sem); + break; + } + + ret = copy_to_user((void __user *)arg, &(jbp->jb), sizeof(jpudrv_buffer_t)); + if (ret) { + kfree(jbp); + ret = -EFAULT; + up(&s_jpu_sem); + break; + } + + jbp->filp = filp; + spin_lock(&s_jpu_lock); + list_add(&jbp->list, &s_jbp_head); + spin_unlock(&s_jpu_lock); + + up(&s_jpu_sem); + break; + case JDI_IOCTL_FREE_PHYSICALMEMORY: + down(&s_jpu_sem); + + ret = copy_from_user(&jb, (jpudrv_buffer_t *)arg, sizeof(jpudrv_buffer_t)); + if (ret) { + up(&s_jpu_sem); + return -EACCES; + } + + if (jb.base) + jpu_free_dma_buffer(&jb); + + spin_lock(&s_jpu_lock); + list_for_each_entry_safe(jbp, n, &s_jbp_head, list) { + if (jbp->jb.phys_addr == jb.phys_addr) { + list_del(&jbp->list); + kfree(jbp); + break; + } + } + spin_unlock(&s_jpu_lock); + + up(&s_jpu_sem); + break; + case JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_image_memory.base != 0) { + ret = copy_to_user((void __user *)arg, &s_image_memory, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = -EFAULT; + } +#endif + break; +#ifdef JPU_SUPPORT_ISR + case JDI_IOCTL_WAIT_INTERRUPT: + ret = copy_from_user(&info, (jpudrv_intr_info_t*)arg, sizeof(jpudrv_intr_info_t)); + if (ret != 0) + return -EFAULT; + + smp_rmb(); + ret = wait_event_interruptible_timeout(s_interrupt_wait_q, atomic_read(&s_interrupt_flag) != 0, msecs_to_jiffies(info.timeout)); + if (!ret) { + ret = -ETIME; + //pr_info("%s JDI_IOCTL_WAIT_INTERRUPT fail\n", DEV_NAME); + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + atomic_set(&s_interrupt_flag, 0); + info.intr_reason = dev->interrupt_reason; + ret = copy_to_user((void __user *)arg, &info, sizeof(jpudrv_intr_info_t)); + if (ret != 0) + return -EFAULT; + + //pr_info("%s JDI_IOCTL_WAIT_INTERRUPT done, info.intr_reason:0x%x\n", DEV_NAME, info.intr_reason); + break; +#endif /* JPU_SUPPORT_ISR */ + case JDI_IOCTL_ENABLE_INTERRUPT: +#ifdef JPU_IRQ_CONTROL + enable_irq(s_jpu_irq); +#endif + break; + case JDI_IOCTL_SET_CLOCK_GATE: + if (get_user(clkgate, (u32 __user *) arg)) + return -EFAULT; + +#ifdef JPU_SUPPORT_CLOCK_CONTROL + if (clkgate) + jpu_clk_enable(s_jpu_clk); + else + jpu_clk_disable(s_jpu_clk); +#endif + + break; + case JDI_IOCTL_GET_INSTANCE_POOL: + down(&s_jpu_sem); + + if (s_jpu_instance_pool.base != 0) { + ret = copy_to_user((void __user *)arg, &s_jpu_instance_pool, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = copy_from_user(&s_jpu_instance_pool, (jpudrv_buffer_t *)arg, sizeof(jpudrv_buffer_t)); + if (ret == 0) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + s_jpu_instance_pool.size = PAGE_ALIGN(s_jpu_instance_pool.size); + s_jpu_instance_pool.base = (unsigned long)vmalloc(s_jpu_instance_pool.size); + s_jpu_instance_pool.phys_addr = s_jpu_instance_pool.base; + + if (s_jpu_instance_pool.base != 0) +#else + if (jpu_alloc_dma_buffer2(&s_jpu_instance_pool) != -1) +#endif + { + memset((void *)s_jpu_instance_pool.base, 0x0, s_jpu_instance_pool.size); + ret = copy_to_user((void __user *)arg, &s_jpu_instance_pool, sizeof(jpudrv_buffer_t)); + if (ret == 0) { + // success to get memory for instance pool + up(&s_jpu_sem); + break; + } + } + } + ret = -EFAULT; + } + up(&s_jpu_sem); + + break; + case JDI_IOCTL_OPEN_INSTANCE: + jil = kzalloc(sizeof(*jil), GFP_KERNEL); + if (!jil) + return -ENOMEM; + + if (get_user(inst_idx, (u32 __user *) arg)) + return -EFAULT; + + jil->inst_idx = inst_idx; + jil->filp = filp; + spin_lock(&s_jpu_lock); + list_add(&jil->list, &s_jpu_inst_list_head); + s_jpu_open_count++; + spin_unlock(&s_jpu_lock); + break; + case JDI_IOCTL_CLOSE_INSTANCE: + if (get_user(inst_idx, (u32 __user *) arg)) + return -EFAULT; + + spin_lock(&s_jpu_lock); + + list_for_each_entry_safe(jil, tmp, &s_jpu_inst_list_head, list) { + if (jil->inst_idx == inst_idx) { + s_jpu_open_count--; + list_del(&jil->list); + kfree(jil); +// printk(KERN_INFO "[JPUDRV] JDI_IOCTL_CLOSE_INSTANCE inst_idx=%d, open_count=%d\n", (int)inst_idx, s_jpu_open_count); + break; + } + } + spin_unlock(&s_jpu_lock); + break; + case JDI_IOCTL_GET_INSTANCE_NUM: + down(&s_jpu_sem); + + ret = copy_to_user((void __user *)arg, &s_jpu_open_count, sizeof(int)); + if (ret != 0) + ret = -EFAULT; + + //printk(KERN_INFO "[JPUDRV] VDI_IOCTL_GET_INSTANCE_NUM open_count=%d\n", s_jpu_open_count); + + up(&s_jpu_sem); + break; + case JDI_IOCTL_RESET: + jpu_hw_reset(); + break; + case JDI_IOCTL_GET_REGISTER_INFO: + ret = copy_to_user((void __user *)arg, &s_jpu_register, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + break; + case JDI_IOCTL_GET_BONDING_INFO: + ret = copy_to_user((void __user *)arg, &s_bonding_register, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + break; + case JDI_IOCTL_SET_CLOCK_ENABLE: + + if (get_user(clkgate, (u32 __user *) arg)) + return -EFAULT; + + if (clkgate) { + reset_control_deassert(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); + val = ReadJpuRegister(JPEG_DBUS_REG); + val |= (dbus_en << 0); + val &= ~(1 << 1); //Disable idle gating, fix it later. + WriteJpuRegister(JPEG_DBUS_REG, val); + } else { + jpu_clk_disable(s_jpu_clk); + reset_control_assert(rstc_jpeg); + } + break; + case JDI_IOCTL_SET_RTK_DOVI_FLAG: + //pr_info("%s [+]JDI_IOCTL_SET_RTK_DOVI_FLAG\n", DEV_NAME); + ret = copy_from_user(&doviInfo, (jpudrv_dovi_info_t *)arg, sizeof(jpudrv_dovi_info_t)); + if (ret != 0) + break; + + doviInfo.enable = pu_set_dovi_flag(2, doviInfo.inst_idx, doviInfo.enable); + + ret = copy_to_user((jpudrv_dovi_info_t *)arg, &doviInfo, sizeof(jpudrv_dovi_info_t)); + if (ret != 0) + break; + //pr_info("%s [-]JDI_IOCTL_SET_RTK_DOVI_FLAG doviInfo.inst_idx:%d, doviInfo.value:%d\n", DEV_NAME, doviInfo.inst_idx, doviInfo.enable); + break; + default: + printk(KERN_ERR "No such IOCTL, cmd is %d\n", cmd); + break; + } + + return ret; +} + +static ssize_t jpu_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) +{ + return -1; +} + +static ssize_t jpu_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) +{ + + return -1; +} + +static int jpu_release(struct inode *inode, struct file *filp) +{ +// pr_info("%s jpu_release s_jpu_open_count=%d\n", DEV_NAME, s_jpu_open_count); + + spin_lock(&s_jpu_lock); + + + if (s_jpu_open_count > 0) { + /* found and free the not handled buffer by user applications */ + jpu_free_buffers(filp); + + /* found and free the not closed instance by user applications */ + jpu_free_instances(filp); + } + +#if 1 //Fuchun 20150909, we must not free instance pool and common memory + if (s_jpu_open_count == 0) { + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_jpu_instance_pool.base, s_jpu_instance_pool.phys_addr); + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; +// pr_info("%s jpu_release - free s_jpu_instance_pool\n", DEV_NAME); + } + } +#endif + + spin_unlock(&s_jpu_lock); + + return 0; +} + +static int jpu_fasync(int fd, struct file *filp, int mode) +{ + struct jpu_drv_context_t *dev = (struct jpu_drv_context_t *)filp->private_data; + return fasync_helper(fd, filp, mode, &dev->async_queue); +} + +static int jpu_map_to_register(struct file *fp, struct vm_area_struct *vm) +{ + unsigned long pfn; + + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + pfn = vm->vm_pgoff; + + return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +} + +static int jpu_map_to_physical_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef CONFIG_RTK_RESERVE_MEMORY + return pu_mmap_dma_buffer(vm); +#else + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot); + + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif +} + +static int jpu_map_to_instance_pool_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + int ret; + long length = vm->vm_end - vm->vm_start; + unsigned long start = vm->vm_start; + char *vmalloc_area_ptr = (char *)s_jpu_instance_pool.base; + unsigned long pfn; + + vm->vm_flags |= VM_RESERVED; + + /* loop over all pages, map it page individually */ + while (length > 0) { + pfn = vmalloc_to_pfn(vmalloc_area_ptr); + if ((ret = remap_pfn_range(vm, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0) { + return ret; + } + start += PAGE_SIZE; + vmalloc_area_ptr += PAGE_SIZE; + length -= PAGE_SIZE; + } + + return 0; +#else + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif +} + +/*! + * @brief memory map interface for jpu file operation + * @return 0 on success or negative error code on error + */ +static int jpu_mmap(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + if (vm->vm_pgoff == 0) + return jpu_map_to_instance_pool_memory(fp, vm); + + if ((vm->vm_pgoff == (s_jpu_register.phys_addr>>PAGE_SHIFT)) || (vm->vm_pgoff == (s_bonding_register.phys_addr>>PAGE_SHIFT))) + return jpu_map_to_register(fp, vm); + + return jpu_map_to_physical_memory(fp, vm); +#else + if (vm->vm_pgoff) { + if (vm->vm_pgoff == (s_jpu_instance_pool.phys_addr>>PAGE_SHIFT)) + return jpu_map_to_instance_pool_memory(fp, vm); + + return jpu_map_to_physical_memory(fp, vm); + } else + return jpu_map_to_register(fp, vm); +#endif +} + +struct file_operations jpu_fops = { + .owner = THIS_MODULE, + .open = jpu_open, + .read = jpu_read, + .write = jpu_write, + .unlocked_ioctl = jpu_ioctl, + .compat_ioctl = compat_jpu_ioctl, + .release = jpu_release, + .fasync = jpu_fasync, + .mmap = jpu_mmap, +}; + +static int jpu_probe(struct platform_device *pdev) +{ + int err = 0; + struct resource res; + void __iomem *iobase; + int irq; + struct device_node *node = pdev->dev.of_node; + + pr_info("%s jpu_probe\n", DEV_NAME); + + of_address_to_resource(node, 0, &res); + iobase = of_iomap(node, 0); + + s_jpu_reg_phy_base = res.start; + s_jpu_reg_virt_base = iobase; + s_jpu_register.phys_addr = res.start; + s_jpu_register.virt_addr = (unsigned long)iobase; + s_jpu_register.size = res.end - res.start + 1; + + pr_info("%s jpu base address get from DTB physical base addr=0x%lx, virtual base=0x%lx, size=0x%x\n", DEV_NAME, (unsigned long)s_jpu_reg_phy_base, (unsigned long)s_jpu_reg_virt_base, (unsigned int)(res.end - res.start + 1)); + + of_address_to_resource(node, 1, &res); + iobase = of_iomap(node, 1); + + s_bonding_register.phys_addr = res.start; + s_bonding_register.virt_addr = (unsigned long)iobase; + s_bonding_register.size = res.end - res.start + 1; + + s_jpu_dev.minor = MISC_JPU_MINOR; + s_jpu_dev.name = JPU_DEV_NAME; + s_jpu_dev.fops = &jpu_fops; + s_jpu_dev.parent = NULL; + if (misc_register(&s_jpu_dev)) { + pr_info("%s failed to register misc device.", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + + if (pdev) + s_jpu_clk = jpu_clk_get(&pdev->dev); + else + s_jpu_clk = jpu_clk_get(NULL); + + if (!s_jpu_clk) + pr_err("%s fail to get clock controller, but, do not treat as error, \n", DEV_NAME); + else + pr_info("%s get clock controller s_jpu_clk=0x%p\n", DEV_NAME, s_jpu_clk); + +#ifdef JPU_SUPPORT_CLOCK_CONTROL + jpu_clk_enable(s_jpu_clk); +#endif + + rstc_jpeg = reset_control_get_exclusive(&pdev->dev, NULL); + + /* RTK clock setting */ + reset_control_deassert(rstc_jpeg); // RESET disable +#if 0 //Fuchun disable 20160204, set clock gating by jdi.c + jpu_pll_setting(0x10, (1 << jpg_clk_enable_bit), 0, 1); // CLK enable + + val = ReadJpuRegister(JPEG_DBUS_REG); + val |= (dbus_en << 0); + WriteJpuRegister(JPEG_DBUS_REG, val); +#endif + +#ifdef JPU_SUPPORT_ISR + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + s_jpu_irq = irq; + pr_info("%s s_jpu_irq:%d want to register jpu_irq_handler\n", DEV_NAME, s_jpu_irq); + err = request_irq(s_jpu_irq, jpu_irq_handler, 0, "JPEG_CODEC_IRQ", (void *)(&s_jpu_drv_context)); + err = 0; + if (err != 0) { + if (err == -EINVAL) + pr_err("%s Bad s_jpu_irq number or handler\n", DEV_NAME); + else if (err == -EBUSY) + pr_err("%s s_jpu_irq <%d> busy, change your config\n", DEV_NAME, s_jpu_irq); + + goto ERROR_PROVE_DEVICE; + } +#endif + +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + s_image_memory.size = JPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE; + s_image_memory.phys_addr = JPU_DRAM_PHYSICAL_BASE; + s_image_memory.base = (unsigned long)ioremap(s_image_memory.phys_addr, PAGE_ALIGN(s_image_memory.size)); + + if (!s_image_memory.base) { + pr_err("%s fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n", DEV_NAME, (int)s_image_memory.phys_addr, (int)s_image_memory.base, (int)s_image_memory.size); + goto ERROR_PROVE_DEVICE; + } + + if (jmem_init(&s_jmem, s_image_memory.phys_addr, s_image_memory.size) < 0) { + pr_err("%s fail to init vmem system\n", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + + pr_info("%s success to probe jpu device with reserved video memory phys_addr=0x%x, base = 0x%x\n", DEV_NAME, (int) s_image_memory.phys_addr, (int)s_image_memory.base); +#else + pr_info("%s success to probe jpu device with non reserved video memory\n", DEV_NAME); +#endif + + reset_control_assert(rstc_jpeg); + + return 0; + + +ERROR_PROVE_DEVICE: + + misc_deregister(&s_jpu_dev); + + if (s_jpu_reg_virt_base) + iounmap(s_jpu_reg_virt_base); + + return err; +} + +static int jpu_remove(struct platform_device *pdev) +{ +#ifdef JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + + pr_info("%s jpu_remove\n", DEV_NAME); + + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_jpu_instance_pool.base, s_jpu_instance_pool.phys_addr); + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; + } +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_image_memory.base) { + iounmap((void *)s_image_memory.base); + s_image_memory.base = 0; + jmem_exit(&s_jmem); + } +#endif + + misc_deregister(&s_jpu_dev); + +#ifdef JPU_SUPPORT_ISR + if (s_jpu_irq) + free_irq(s_jpu_irq, &s_jpu_drv_context); +#endif + + if (s_jpu_reg_virt_base) + iounmap(s_jpu_reg_virt_base); + + if (rstc_jpeg != NULL) + reset_control_put(rstc_jpeg); + + jpu_clk_put(s_jpu_clk); + +#endif //JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + + return 0; +} + +#ifdef CONFIG_PM +static int jpu_suspend(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + reset_control_deassert(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); +#if 0 + if (s_jpu_open_count > 0) { + u32 inst_idx; + jpudrv_instanace_list_t *jil, *n; + jpudrv_instance_pool_t *jip; + void *jip_base; + jpudrv_buffer_pool_t *pool, *n; + jpudrv_buffer_t jb; + + s_jpu_open_count = 0; + atomic_set(&s_interrupt_flag, 0); + wake_up_interruptible_all(&s_interrupt_wait_q); + + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; + pr_info("%s jpu_release - free s_jpu_instance_pool\n", DEV_NAME); + } + + list_for_each_entry_safe(jil, n, &s_jpu_inst_list_head, list) { + inst_idx = jil->inst_idx; + jip_base = (void *)(s_jpu_instance_pool.base); + jip = (jpudrv_instance_pool_t *)jip_base; + if (jip) { + memset(&jip->jpgInstPool[inst_idx], 0x00, 4); // only first 4 byte is key point to free the corresponding instance. + } + list_del(&jil->list); + kfree(jil); + } + + list_for_each_entry_safe(pool, n, &s_jbp_head, list) { + jb = pool->jb; + if (jb.base) { + jpu_free_dma_buffer(&jb); + list_del(&pool->list); + kfree(pool); + } + } + } +#endif + jpu_clk_disable(s_jpu_clk); + reset_control_assert(rstc_jpeg); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; + +} + +static int jpu_resume(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + reset_control_deassert(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); + jpu_clk_disable(s_jpu_clk); + reset_control_assert(rstc_jpeg); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; +} +#else +#define jpu_suspend NULL +#define jpu_resume NULL +#endif /* !CONFIG_PM */ + +static int __init jpu_init(void) +{ + int res; + res = 0; + + pr_info("%s jpu_init\n", DEV_NAME); + init_waitqueue_head(&s_interrupt_wait_q); + s_jpu_instance_pool.base = 0; + + pr_info("%s end jpu_init result=0x%x\n", DEV_NAME, res); + return res; +} + +static void __exit jpu_exit(void) +{ +#ifdef JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + pr_info("%s jpu_exit\n", DEV_NAME); +#else + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_jpu_instance_pool.base, s_jpu_instance_pool.phys_addr); + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; + } +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_image_memory.base) { + iounmap((void *)s_image_memory.base); + s_image_memory.base = 0; + } +#endif + + misc_deregister(&s_jpu_dev); + +#ifdef JPU_SUPPORT_ISR + if (s_jpu_irq) + free_irq(s_jpu_irq, &s_jpu_drv_context); +#endif + + if (rstc_jpeg != NULL) + reset_control_put(rstc_jpeg); + + jpu_clk_put(s_jpu_clk); + + + if (s_jpu_reg_virt_base) { + iounmap(s_jpu_reg_virt_base); + s_jpu_reg_virt_base = (void *)0x00; + } + +#endif //JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + + return; +} + +MODULE_AUTHOR("A customer using RTK JPU, Inc."); +MODULE_DESCRIPTION("JPU linux driver"); +MODULE_LICENSE("GPL"); + +module_init(jpu_init); +module_exit(jpu_exit); + +int jpu_hw_reset(void) +{ + u32 val; + + pr_info("%s request jpu reset from application\n", DEV_NAME); + jpu_clk_disable(s_jpu_clk); + reset_control_reset(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); + val = ReadJpuRegister(JPEG_DBUS_REG); + val |= (dbus_en << 0); + val &= ~(1 << 1); //Disable idle gating, fix it later. + WriteJpuRegister(JPEG_DBUS_REG, val); + return 0; +} + +struct clk *jpu_clk_get(struct device *dev) +{ + return clk_get(dev, JPU_CLK_NAME); +} + +void jpu_clk_put(struct clk *clk) +{ + if (!(clk == NULL || IS_ERR(clk))) + clk_put(clk); +} + +int jpu_clk_enable(struct clk *clk) +{ + if (!(clk == NULL || IS_ERR(clk))) { +// pr_info("%s jpu_clk_enable\n", DEV_NAME); + return clk_prepare_enable(clk); + } + return 0; +} + +void jpu_clk_disable(struct clk *clk) +{ + if (!(clk == NULL || IS_ERR(clk))) { +// pr_info("%s jpu_clk_disable\n", DEV_NAME); + clk_disable_unprepare(clk); + } +} + +static const struct of_device_id rtk_jpeg_dt_match[] = { + { .compatible = "realtek,rtd13xx-jpeg" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_jpeg_dt_match); + +const struct dev_pm_ops rtk_jpeg_pmops = { + .suspend = jpu_suspend, + .resume = jpu_resume, +}; + +static struct platform_driver rtk_jpeg_driver = { + .driver = { + .name = "rtk-jpeg", + .owner = THIS_MODULE, + .of_match_table = rtk_jpeg_dt_match, + .pm = &rtk_jpeg_pmops, + }, + .probe = jpu_probe, + .remove = jpu_remove, +}; + +module_platform_driver(rtk_jpeg_driver); diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.h b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.h new file mode 100644 index 000000000000..fce5113b33a4 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/jdi/jpu.h @@ -0,0 +1,47 @@ + + +#ifndef __JPU_DRV_H__ +#define __JPU_DRV_H__ + +#include +#include + +#define J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + +#define JDI_IOCTL_MAGIC 'J' +#define JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(JDI_IOCTL_MAGIC, 0) +#define JDI_IOCTL_FREE_PHYSICALMEMORY _IO(JDI_IOCTL_MAGIC, 1) +#define JDI_IOCTL_WAIT_INTERRUPT _IO(JDI_IOCTL_MAGIC, 2) +#define JDI_IOCTL_SET_CLOCK_GATE _IO(JDI_IOCTL_MAGIC, 3) +#define JDI_IOCTL_RESET _IO(JDI_IOCTL_MAGIC, 4) +#define JDI_IOCTL_GET_INSTANCE_POOL _IO(JDI_IOCTL_MAGIC, 5) +#define JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(JDI_IOCTL_MAGIC, 6) +#define JDI_IOCTL_OPEN_INSTANCE _IO(JDI_IOCTL_MAGIC, 7) +#define JDI_IOCTL_CLOSE_INSTANCE _IO(JDI_IOCTL_MAGIC, 8) +#define JDI_IOCTL_GET_INSTANCE_NUM _IO(JDI_IOCTL_MAGIC, 9) +#define JDI_IOCTL_ENABLE_INTERRUPT _IO(JDI_IOCTL_MAGIC, 10) +#define JDI_IOCTL_GET_REGISTER_INFO _IO(JDI_IOCTL_MAGIC, 11) + +/* RTK ioctl */ +#define JDI_IOCTL_SET_CLOCK_ENABLE _IO(JDI_IOCTL_MAGIC, 12) +#define JDI_IOCTL_GET_BONDING_INFO _IO(JDI_IOCTL_MAGIC, 13) +#define JDI_IOCTL_SET_RTK_DOVI_FLAG _IO(JDI_IOCTL_MAGIC, 14) + +typedef struct jpudrv_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; /* kernel logical address in use kernel */ + unsigned long virt_addr; /* virtual user space address */ +} jpudrv_buffer_t; + +typedef struct jpudrv_intr_info_t { + unsigned int timeout; + int intr_reason; +} jpudrv_intr_info_t; + +typedef struct jpudrv_dovi_info_t{ + unsigned int inst_idx; + unsigned int enable; +} jpudrv_dovi_info_t; + +#endif diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.c b/drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.c new file mode 100644 index 000000000000..dc5adff5544a --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.c @@ -0,0 +1,554 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "puwrap.h" + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#define USE_ION_ALLOCATOR +#ifdef USE_ION_ALLOCATOR +#define NUM_ION_STRUCT 256 + +#if defined(CONFIG_ION_REALTEK) +#include "mem_allocator/ion.h" +#include +#else +#include "../../../../staging/android/ion/ion.h" +#include "../../../../staging/android/uapi/ion_rtk.h" +#endif + +#include +#define ion_alloc ext_rtk_ion_alloc + +struct rtkdrv_ion_buffer_t { + unsigned int size; + unsigned int inUse; + unsigned long phys_addr; + unsigned long dmabuf; + unsigned long pIonHandle; +}; + +struct rtkdrv_ion_buffer_t pu_ion_buffer[NUM_ION_STRUCT]; +static DEFINE_MUTEX(s_pu_mutex); +#else /* else USE_ION_ALLOCATOR */ +typedef struct rtkdrv_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; /* kernel logical address in use kernel */ + unsigned long virt_addr; /* virtual user space address */ +} rtkdrv_buffer_t; + +#define RTK_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (16*1024*1024) +#define RTK_DRAM_PHYSICAL_BASE 0x06000000 +#include "rtk_mm.h" +static video_mm_t s_mem; +static rtkdrv_buffer_t s_memory = {0}; +#endif /* endif USE_ION_ALLOCATOR */ +#define VE_SECURE_NORMAL 1 +#define VE_SECURE_PROTECTION 2 +#endif /* endif CONFIG_RTK_RESERVE_MEMORY */ + +typedef struct rtkdrv_dovi_flag_t{ + int nCoreIdx; + int nInstIdx; + unsigned int bEnable; +} rtkdrv_dovi_flag_t; + +rtkdrv_dovi_flag_t dovi_flag = {-1, -1, 0}; +static DEFINE_MUTEX(s_dovi_mutex); + +#define PU_PLATFORM_DEVICE_NAME "rtk_puwrap" + +#ifdef CONFIG_RTK_RESERVE_MEMORY + +phys_addr_t get_mem_pa(struct ion_buffer *buffer) +{ + unsigned long ret = -1UL; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + + mutex_lock(&buffer->lock); + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + mutex_unlock(&buffer->lock); + + ret = paddr; + + return ret; +} + +int pu_alloc_dma_buffer(unsigned int size, unsigned long *phys_addr, unsigned long *base, unsigned int mem_type) +{ + +#ifdef USE_ION_ALLOCATOR + int ret = -1; + if (!size) + return -1; + + mutex_lock(&s_pu_mutex); + do { + int i; + struct dma_buf *dmabuf; + phys_addr_t dat; + size_t len; + int heap = RTK_ION_HEAP_MEDIA_MASK; + int flags = (ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_NONCACHED); + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].inUse == 0) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] NUM_ION_STRUCT is too small!!!"); + break; + } + + switch(mem_type) + { + case VE_SECURE_NORMAL: + { + heap = RTK_ION_HEAP_MEDIA_MASK; + flags = (ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_NONCACHED | ION_FLAG_VE_SPEC); + break; + } + case VE_SECURE_PROTECTION: + { + heap = RTK_ION_HEAP_SECURE_MASK | RTK_ION_HEAP_MEDIA_MASK; + flags = (ION_FLAG_HWIPACC | ION_FLAG_PROTECTED_V2_VIDEO_POOL); + break; + } + default: + { + heap = RTK_ION_HEAP_MEDIA_MASK; + flags = (ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_NONCACHED); + break; + } + } + + int handle = ion_alloc(size, heap, flags); + if (IS_ERR(handle)) + { + printk(KERN_ERR "[PUWRAP] ion_alloc allocation error size=%d\n", size); + break; + } + + dmabuf = dma_buf_get(handle); + if (IS_ERR(dmabuf)) { + break; + } + + dat = get_mem_pa(dmabuf->priv); + + *base = (unsigned long) dmabuf; // we didn't need base address on user space, but we also need it has value to do detection + *phys_addr = (unsigned long)dat; + pu_ion_buffer[i].size = size; + pu_ion_buffer[i].inUse = 1; + pu_ion_buffer[i].phys_addr = (unsigned long)*phys_addr; + pu_ion_buffer[i].dmabuf = (unsigned long)dmabuf; + pu_ion_buffer[i].pIonHandle = (unsigned long)handle; + + __close_fd(current->files, handle); + + ret = 0; + break; + } while (0); + mutex_unlock(&s_pu_mutex); + return ret; + +#else /* else USE_ION_ALLOCATOR */ + if (!size) + return -1; + + *phys_addr = (unsigned long)vmem_alloc(&s_mem, size, 0); + if (*phys_addr == (unsigned long)-1) + { + printk(KERN_ERR "[PUWRAP] Physical memory allocation error size=%d\n", size); + return -1; + } + + *base = (unsigned long)(s_memory.base + (*phys_addr - s_memory.phys_addr)); + //printk("[PUWARP] base:0x%lx, phy_addr:0x%lx, size:%d\n", *base, (unsigned long)*phys_addr, size); + + return 0; +#endif /* endif USE_ION_ALLOCATOR */ +} + +void pu_free_dma_buffer(unsigned long base, unsigned long phys_addr) +{ + if (!base) + return; + +#ifdef USE_ION_ALLOCATOR + mutex_lock(&s_pu_mutex); + do { + int i; + struct ion_handle *handle; + struct dma_buf *dmabuf; + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + break; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + if (dmabuf != NULL) + { + dma_buf_put(dmabuf); + pu_ion_buffer[i].dmabuf = (unsigned long) NULL; + } + + handle = (struct ion_handle *)pu_ion_buffer[i].pIonHandle; + if(handle != NULL) + { + //ion_free(pu_client, handle); + } + memset(&pu_ion_buffer[i], 0, sizeof(struct rtkdrv_ion_buffer_t)); + } while (0); + mutex_unlock(&s_pu_mutex); +#else + vmem_free(&s_mem, (unsigned long)phys_addr, 0); +#endif +} + +int pu_mmap_dma_buffer(struct vm_area_struct *vm) +{ +#ifdef USE_ION_ALLOCATOR + u32 i; + int ret = 0; + struct dma_buf *dmabuf; + unsigned long phys_addr = (unsigned long)(vm->vm_pgoff << PAGE_SHIFT); + mutex_lock(&s_pu_mutex); + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + mutex_unlock(&s_pu_mutex); + return -EINVAL; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + ret = dma_buf_mmap(dmabuf, vm, 0); + + mutex_unlock(&s_pu_mutex); + + return ret; +#else + return -EINVAL; +#endif +} + +unsigned long pu_mmap_kernel_buffer(unsigned long phys_addr, unsigned int size) +{ +#ifdef USE_ION_ALLOCATOR + unsigned long ret = 0; + + if (!size) + return 0; + + mutex_lock(&s_pu_mutex); + do { + int i; + struct dma_buf *dmabuf; + void * virt_addr; + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + break; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + if(dmabuf != NULL) + { + ret = dma_buf_begin_cpu_access(dmabuf, 0); + if (ret) { + printk(KERN_ERR "[PUWRAP] dma_buf_begin_cpu_access error ret=%d (size=%d) \n", ret, size); + break; + } + virt_addr = dma_buf_kmap(dmabuf, 0); + if (IS_ERR_OR_NULL(virt_addr)) { + printk(KERN_ERR "[PUWRAP] dma_buf_kmap error %p (size=%d) \n", virt_addr, size); + break; + } + + ret = (unsigned long)virt_addr; + } + } while(0); + mutex_unlock(&s_pu_mutex); + + return ret; +#endif +} + +void pu_unmap_kernel_buffer(unsigned long base, unsigned long phys_addr) +{ + if (!base) + return; + +#ifdef USE_ION_ALLOCATOR + mutex_lock(&s_pu_mutex); + do { + int i; + struct dma_buf *dmabuf; + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + break; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + if(dmabuf != NULL) + { + dma_buf_kunmap(dmabuf, 0, (void *)base); + dma_buf_end_cpu_access(dmabuf, 0); + } + } while (0); + mutex_unlock(&s_pu_mutex); +#endif +} +#endif //#ifdef CONFIG_RTK_RESERVE_MEMORY + +int pu_set_dovi_flag(int nCoreIdx, int nInstIdx, unsigned int bEnable) +{ + int ret = 0; + //pr_info("VE1: dovi_flag[%p, %d, %d, %d], input[%d, %d, %d]\n", &dovi_flag, dovi_flag.nCoreIdx, dovi_flag.nInstIdx, dovi_flag.bEnable, nCoreIdx, nInstIdx, bEnable); + + mutex_lock(&s_dovi_mutex); + if (bEnable == 1) + { + if (dovi_flag.bEnable == 0) + { + dovi_flag.bEnable = 1; + dovi_flag.nCoreIdx = nCoreIdx; + dovi_flag.nInstIdx = nInstIdx; + ret = 1; + } + } + else + { + if (dovi_flag.bEnable == 1 && dovi_flag.nCoreIdx == nCoreIdx && dovi_flag.nInstIdx == nInstIdx) + { + dovi_flag.bEnable = 0; + dovi_flag.nCoreIdx = -1; + dovi_flag.nInstIdx = -1; + } + } + mutex_unlock(&s_dovi_mutex); + + return ret; +} + +static int pu_probe(struct platform_device *pdev) +{ + struct resource res; + struct device_node *node; + + printk(KERN_INFO "[PUWRAP] pu_probe\n"); + + node = pdev->dev.of_node; + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#ifdef USE_ION_ALLOCATOR + memset(pu_ion_buffer, 0, sizeof(struct rtkdrv_ion_buffer_t)*NUM_ION_STRUCT); + printk(KERN_INFO "[PUWRAP] success to probe pu wrapper device with USE_ION_ALLOCATOR\n"); +#else /* else USE_ION_ALLOCATOR */ + if(pdev) + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if(res) + { + s_memory.size = res->end - res->start; + s_memory.phys_addr = res->start; + } + else + { + s_memory.size = RTK_INIT_VIDEO_MEMORY_SIZE_IN_BYTE; + s_memory.phys_addr = RTK_DRAM_PHYSICAL_BASE; + } + + s_memory.base = (unsigned long)ioremap(s_memory.phys_addr, PAGE_ALIGN(s_memory.size)); + if (!s_memory.base) + { + printk(KERN_ERR "[PUWRAP] : fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n", (int)s_memory.phys_addr, (int)s_memory.base, (int)s_memory.size); + goto ERROR_PROVE_DEVICE; + } + if (vmem_init(&s_mem, s_memory.phys_addr, s_memory.size) < 0) + { + printk(KERN_ERR "[PUWRAP] : fail to init vmem system\n"); + goto ERROR_PROVE_DEVICE; + } + printk(KERN_INFO "[PUWRAP] success to probe pu wrapper device with reserved video memory phys_addr=0x%x, base = 0x%x\n", (int) s_memory.phys_addr, (int)s_memory.base); +#endif /* endif USE_ION_ALLOCATOR */ +#else /* else CONFIG_RTK_RESERVE_MEMORY */ + printk(KERN_INFO "[PUWRAP] success to probe pu wrapper device\n"); +#endif /* endif CONFIG_RTK_RESERVE_MEMORY */ + + + return 0; + + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#ifndef USE_ION_ALLOCATOR +ERROR_PROVE_DEVICE: + + return 0; +#endif +#endif +} + +static int pu_remove(struct platform_device *pdev) +{ + printk(KERN_INFO "[PUWRAP] pu_remove\n"); + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#ifdef USE_ION_ALLOCATOR + + /* Todo release ion buffer */ + +#else /* else USE_ION_ALLOCATOR */ + if (s_memory.base) + { + iounmap((void *)s_memory.base); + s_memory.base = 0; + vmem_exit(&s_mem); + } +#endif /* endif USE_ION_ALLOCATOR */ +#endif /* endif CONFIG_RTK_RESERVE_MEMORY */ + + return 0; +} + +#if 0 +static struct platform_driver pu_driver = { + .driver = { + .name = PU_PLATFORM_DEVICE_NAME, + }, + .probe = pu_probe, + .remove = pu_remove, +}; +#endif + +static ssize_t pu_memsize_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", (int)(get_num_physpages() << PAGE_SHIFT)); +} + +static struct kobj_attribute pu_memsize_attr = + __ATTR(pu_memsize, 0644, pu_memsize_show, NULL); + +static struct attribute *pu_attrs[] = { + &pu_memsize_attr.attr, + NULL, +}; + +static struct attribute_group rtk_pu_attr_group = { + .attrs = pu_attrs, +}; + +static struct kobject *pu_kobj; + +static int __init pu_init(void) +{ + int res = 0; + + pu_kobj = kobject_create_and_add("rtk_pu", kernel_kobj); + if (pu_kobj) + { + res = sysfs_create_group(pu_kobj, &rtk_pu_attr_group); + if (res) + printk(KERN_WARNING "[PUWRAP] %d: unable to create sysfs entry\n", __LINE__); + } + else + printk(KERN_WARNING "[PUWRAP] %d: unable to create sysfs entry\n", __LINE__); + + printk(KERN_INFO "[PUWRAP] begin pu_init\n"); + //res = platform_driver_register(&pu_driver); + printk(KERN_INFO "[PUWRAP] end pu_init result=0x%x\n", res); + return res; +} + +static void __exit pu_exit(void) +{ + printk(KERN_INFO "[PUWRAP] pu_exit\n"); + //platform_driver_unregister(&pu_driver); + return; +} + + +static const struct of_device_id rtk_pu_dt_match[] = { + { .compatible = "Realtek,rtd13xx-pu_pll" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_pu_dt_match); + +const struct dev_pm_ops rtk_pu_pmops = { + .suspend = NULL, + .resume = NULL, +}; + +static struct platform_driver rtk_pu_driver = { + .driver = { + .name = "rtk-pu", + .owner = THIS_MODULE, + .of_match_table = rtk_pu_dt_match, + //.pm = SDHCI_PLTFM_PMOPS, + .pm = &rtk_pu_pmops, + }, + .probe = pu_probe, + .remove = pu_remove, +}; + +module_platform_driver(rtk_pu_driver); + +MODULE_AUTHOR("RTK Wrapper for JPU & VPU, Inc."); +MODULE_DESCRIPTION("PU WRAPPER linux driver"); +MODULE_LICENSE("GPL"); + +module_init(pu_init); +module_exit(pu_exit); diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.h b/drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.h new file mode 100644 index 000000000000..f065d2157efa --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/puwrap.h @@ -0,0 +1,44 @@ + + +#ifndef __PU_DRV_H__ +#define __PU_DRV_H__ + +#include +#include +#include + +#define PDI_IOCTL_MAGIC 'V' + +#define PLL_CLK_715 (0x10D336) +#define PLL_CLK_702 (0x10C186) +#define PLL_CLK_675 (0x10C176) +#define PLL_CLK_648 (0x10C166) +#define PLL_CLK_594 (0x10C146) +#define PLL_CLK_567 (0x10C136) +#define PLL_CLK_337 (0x12C176) +#define PLL_CLK_297 (0x12C146) + +#define UNUSED_PARAMETER(p) (void)(p) + +#define MISC_JPU_MINOR 107 +#define MISC_MEM_MINOR 108 +#define MISC_VE3_MINOR 109 +#define MISC_VE1_MINOR 110 + +typedef struct pu_drv_context_t { + struct fasync_struct *async_queue; + unsigned long jpu_interrupt_reason; + unsigned long vpu_interrupt_reason; +} pu_drv_context_t; + +#ifdef CONFIG_RTK_RESERVE_MEMORY +int pu_alloc_dma_buffer(unsigned int size, unsigned long *phys_addr, unsigned long *base, unsigned int mem_type); +void pu_free_dma_buffer(unsigned long base, unsigned long phys_addr); +int pu_mmap_dma_buffer(struct vm_area_struct *vm); +unsigned long pu_mmap_kernel_buffer(unsigned long phys_addr, unsigned int size); +void pu_unmap_kernel_buffer(unsigned long base, unsigned long phys_addr); +#endif +void pu_pll_setting(unsigned long offset, unsigned int value, unsigned int bOverwrite, unsigned int bEnable); +int pu_set_dovi_flag(int nCoreIdx, int nInstIdx, unsigned int bEnable); + +#endif diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/Makefile b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/Makefile new file mode 100644 index 000000000000..6f8277875373 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/Makefile @@ -0,0 +1,7 @@ +# rtk_vcodec + +obj-$(CONFIG_RTD13XX_VE1_CODEC) += ve1.o +obj-$(CONFIG_RTD13XX_VE1_CODEC) += ve1_pm.o +ifdef CONFIG_COMPAT +obj-$(CONFIG_RTD13XX_VE1_CODEC) += compat_ve1.o +endif diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.c b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.c new file mode 100644 index 000000000000..c9b4619b89f5 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.c @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ve1.h" +#include "compat_ve1.h" + +/* See drivers/soc/realtek/rtd129x/rtk_ve/ve1/ve1.h for the definition of these structs */ +typedef struct compat_vpudrv_buffer_t { + compat_uint_t size; + compat_ulong_t phys_addr; + compat_ulong_t base; /* kernel logical address in use kernel */ + compat_ulong_t virt_addr; /* virtual user space address */ + compat_uint_t mem_type; +} compat_vpudrv_buffer_t; + +typedef struct compat_vpu_clock_info_t{ + compat_uint_t core_idx; + compat_uint_t enable; + compat_uint_t value; +} compat_vpu_clock_info_t; + +typedef struct compat_vpudrv_inst_info_t { + compat_uint_t core_idx; + compat_uint_t inst_idx; + compat_int_t inst_open_count; /* for output only*/ +} compat_vpudrv_inst_info_t; + +typedef struct compat_vpudrv_intr_info_t { + compat_uint_t core_idx; + compat_uint_t timeout; + compat_int_t intr_reason; +#ifdef SUPPORT_MULTI_INST_INTR + compat_int_t intr_inst_index; +#endif +} compat_vpudrv_intr_info_t; + +typedef struct compat_vpudrv_dovi_info_t{ + compat_uint_t core_idx; + compat_uint_t inst_idx; + compat_uint_t enable; +} compat_vpudrv_dovi_info_t; + +#define COMPAT_VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(VDI_IOCTL_MAGIC, 0) +#define COMPAT_VDI_IOCTL_FREE_PHYSICALMEMORY _IO(VDI_IOCTL_MAGIC, 1) +#define COMPAT_VDI_IOCTL_WAIT_INTERRUPT _IO(VDI_IOCTL_MAGIC, 2) +#define COMPAT_VDI_IOCTL_GET_INSTANCE_POOL _IO(VDI_IOCTL_MAGIC, 5) +#define COMPAT_VDI_IOCTL_GET_COMMON_MEMORY _IO(VDI_IOCTL_MAGIC, 6) +#define COMPAT_VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(VDI_IOCTL_MAGIC, 8) +#define COMPAT_VDI_IOCTL_OPEN_INSTANCE _IO(VDI_IOCTL_MAGIC, 9) +#define COMPAT_VDI_IOCTL_CLOSE_INSTANCE _IO(VDI_IOCTL_MAGIC, 10) +#define COMPAT_VDI_IOCTL_GET_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 11) +#define COMPAT_VDI_IOCTL_GET_REGISTER_INFO _IO(VDI_IOCTL_MAGIC, 12) + +/* RTK ioctl */ +#define COMPAT_VDI_IOCTL_SET_RTK_CLK_GATING _IO(VDI_IOCTL_MAGIC, 16) +#define COMPAT_VDI_IOCTL_SET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 17) +#define COMPAT_VDI_IOCTL_GET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 18) +#define COMPAT_VDI_IOCTL_GET_RTK_SUPPORT_TYPE _IO(VDI_IOCTL_MAGIC, 19) +#define COMPAT_VDI_IOCTL_SET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 21) +#define COMPAT_VDI_IOCTL_GET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 22) +#define COMPAT_VDI_IOCTL_SET_RTK_DOVI_FLAG _IO(VDI_IOCTL_MAGIC, 23) +#define COMPAT_VDI_IOCTL_GET_TOTAL_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 24) +#define COMPAT_VDI_IOCTL_GET_RTK_DCSYS_INFO _IO(VDI_IOCTL_MAGIC, 25) + +static int compat_get_ve1_buffer_data( + compat_vpudrv_buffer_t __user *data32, + vpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + compat_uint_t m; + int err; + + err = get_user(s, &data32->size); + err |= put_user(s, &data->size); + err |= get_user(p, &data32->phys_addr); + err |= put_user(p, &data->phys_addr); + err |= get_user(b, &data32->base); + err |= put_user(b, &data->base); + err |= get_user(v, &data32->virt_addr); + err |= put_user(v, &data->virt_addr); + err |= get_user(m, &data32->mem_type); + err |= put_user(m, &data->mem_type); + + return err; +} + +static int compat_get_ve1_inst_info_data( + compat_vpudrv_inst_info_t __user *data32, + vpudrv_inst_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t i; + compat_int_t ioc; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(i, &data32->inst_idx); + err |= put_user(i, &data->inst_idx); + err |= get_user(ioc, &data32->inst_open_count); + err |= put_user(ioc, &data->inst_open_count); + + return err; +} + +static int compat_get_ve1_intr_info_data( + compat_vpudrv_intr_info_t __user *data32, + vpudrv_intr_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(t, &data32->timeout); + err |= put_user(t, &data->timeout); + err |= get_user(i, &data32->intr_reason); + err |= put_user(i, &data->intr_reason); +#ifdef SUPPORT_MULTI_INST_INTR + err |= get_user(i, &data32->intr_inst_index); + err |= put_user(i, &data->intr_inst_index); +#endif + + return err; +} + +static int compat_get_ve1_clock_info( + compat_vpu_clock_info_t __user *data32, + vpu_clock_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t e; + compat_uint_t v; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(e, &data32->enable); + err |= put_user(e, &data->enable); + err |= get_user(v, &data32->value); + err |= put_user(v, &data->value); + + return err; +} + +static int compat_get_ve1_dovi_info( + compat_vpudrv_dovi_info_t __user *data32, + vpudrv_dovi_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t e; + compat_uint_t i; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(i, &data32->inst_idx); + err |= put_user(i, &data->inst_idx); + err |= get_user(e, &data32->enable); + err |= put_user(e, &data->enable); + + return err; +} + +static int compat_put_ve1_buffer_data( + compat_vpudrv_buffer_t __user *data32, + vpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + compat_uint_t m; + int err; + + err = get_user(s, &data->size); + err |= put_user(s, &data32->size); + err |= get_user(p, &data->phys_addr); + err |= put_user(p, &data32->phys_addr); + err |= get_user(b, &data->base); + err |= put_user(b, &data32->base); + err |= get_user(v, &data->virt_addr); + err |= put_user(v, &data32->virt_addr); + err |= get_user(m, &data->mem_type); + err |= put_user(m, &data32->mem_type); + + return err; +} + +static int compat_put_ve1_inst_info_data( + compat_vpudrv_inst_info_t __user *data32, + vpudrv_inst_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t i; + compat_int_t ioc; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(i, &data->inst_idx); + err |= put_user(i, &data32->inst_idx); + err |= get_user(ioc, &data->inst_open_count); + err |= put_user(ioc, &data32->inst_open_count); + + return err; +} + +static int compat_put_ve1_intr_info_data( + compat_vpudrv_intr_info_t __user *data32, + vpudrv_intr_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(t, &data->timeout); + err |= put_user(t, &data32->timeout); + err |= get_user(i, &data->intr_reason); + err |= put_user(i, &data32->intr_reason); + + return err; +} + +static int compat_put_ve1_clock_info( + compat_vpu_clock_info_t __user *data32, + vpu_clock_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t e; + compat_uint_t v; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(e, &data->enable); + err |= put_user(e, &data32->enable); + err |= get_user(v, &data->value); + err |= put_user(v, &data32->value); + + return err; +} + +static int compat_put_ve1_dovi_info( + compat_vpudrv_dovi_info_t __user *data32, + vpudrv_dovi_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t i; + compat_uint_t e; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(i, &data->inst_idx); + err |= put_user(i, &data32->inst_idx); + err |= get_user(e, &data->enable); + err |= put_user(e, &data32->enable); + + return err; +} + +long compat_vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + + if (!filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) { + case COMPAT_VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_FREE_PHYSICALMEMORY: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_FREE_PHYSICALMEMORY, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_WAIT_INTERRUPT: + { + compat_vpudrv_intr_info_t __user *data32; + vpudrv_intr_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_intr_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_WAIT_INTERRUPT, (unsigned long)data); + err = compat_put_ve1_intr_info_data(data32, data); + return ret ? ret : err; + } + + case VDI_IOCTL_SET_CLOCK_GATE: + case VDI_IOCTL_RESET: + case VDI_IOCTL_GET_RTK_ASIC_REVISION: + { + return filp->f_op->unlocked_ioctl(filp, cmd, + (unsigned long)compat_ptr(arg)); + } + + case COMPAT_VDI_IOCTL_GET_INSTANCE_POOL: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_INSTANCE_POOL, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_COMMON_MEMORY: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_COMMON_MEMORY, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_OPEN_INSTANCE: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_OPEN_INSTANCE, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_CLOSE_INSTANCE: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_CLOSE_INSTANCE, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_INSTANCE_NUM: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_INSTANCE_NUM, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_REGISTER_INFO: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_REGISTER_INFO, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_SET_RTK_CLK_GATING: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_CLK_GATING, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_SET_RTK_CLK_PLL: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_CLK_PLL, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_GET_RTK_CLK_PLL: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_CLK_PLL, (unsigned long)data); + err = compat_put_ve1_clock_info(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_SET_RTK_CLK_SELECT: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_CLK_SELECT, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_GET_RTK_CLK_SELECT: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_CLK_SELECT, (unsigned long)data); + err = compat_put_ve1_clock_info(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_SET_RTK_DOVI_FLAG: + { + compat_vpudrv_dovi_info_t __user *data32; + vpudrv_dovi_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_dovi_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_DOVI_FLAG, (unsigned long)data); + err = compat_put_ve1_dovi_info(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_RTK_SUPPORT_TYPE: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_SUPPORT_TYPE, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_RTK_DCSYS_INFO: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_DCSYS_INFO, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_TOTAL_INSTANCE_NUM: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_TOTAL_INSTANCE_NUM, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + default: + { + printk(KERN_ERR "[COMPAT_VPUDRV] No such IOCTL, cmd is %d\n", cmd); + return -ENOIOCTLCMD; + } + } +} diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.h b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.h new file mode 100644 index 000000000000..15c1161487c6 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/compat_ve1.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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_COMPAT_VE1_H +#define _LINUX_COMPAT_VE1_H + +#if IS_ENABLED(CONFIG_COMPAT) + +typedef struct compat_vpu_bit_firmware_info_t { + compat_uint_t size; /* size of this structure*/ + compat_uint_t core_idx; + compat_ulong_t reg_base_offset; + compat_ushort_t bit_code[512]; +} compat_vpu_bit_firmware_info_t; + +long compat_vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +typedef struct compat_vpu_bit_firmware_info_t { + unsigned int size; /* size of this structure*/ + unsigned int core_idx; + unsigned long reg_base_offset; + unsigned short bit_code[512]; +} compat_vpu_bit_firmware_info_t; + +#define compat_vpu_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_VE1_H */ diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.c b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.c new file mode 100644 index 000000000000..11e5f1b7252c --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1.c @@ -0,0 +1,1896 @@ +/* + * ve1.c + * + * linux device driver for VE1. + * + * Copyright (C) 2006 - 2013 REALTEK INC. + * + * This 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. + * + * This 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 this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_COMPAT +#include +#endif + +#include "ve1config.h" +#include "ve1.h" +#include "ve1_pm.h" +#include "compat_ve1.h" +#include "../puwrap.h" + +//#define ENABLE_DEBUG_MSG +#ifdef ENABLE_DEBUG_MSG +#define DPRINTK(args...) pr_info(args); +#else +#define DPRINTK(args...) +#endif /* ENABLE_DEBUG_MSG */ + +#define DEV_NAME "[RTK_VE1]" +#define DISABLE_ORIGIN_SUSPEND +#define USE_HRTIMEOUT_INSTEAD_OF_TIMEOUT + +/* definitions to be changed as customer configuration */ +/* if you want to have clock gating scheme frame by frame */ +/* #define VPU_SUPPORT_CLOCK_CONTROL */ + +/* if the driver want to use interrupt service from kernel ISR */ +#define VPU_SUPPORT_ISR + +/* if the platform driver knows the name of this driver */ +/* VPU_PLATFORM_DEVICE_NAME */ +#define VPU_SUPPORT_PLATFORM_DRIVER_REGISTER + +/* if this driver knows the dedicated video memory address */ +#ifndef CONFIG_RTK_RESERVE_MEMORY +#ifdef CONFIG_RTK_PLATFORM_FPGA +#define VPU_SUPPORT_RESERVED_VIDEO_MEMORY +#endif +#endif + +#define VPU_PLATFORM_DEVICE_NAME "vdec" +#define VPU_CLK_NAME "vcodec" +#define VPU_DEV_NAME "vpu" + +/* if the platform driver knows this driver */ +/* the definition of VPU_REG_BASE_ADDR and VPU_REG_SIZE are not meaningful */ + +#define VPU_REG_BASE_ADDR 0x98040000 +#define VPU_REG_SIZE (0xC000) +#define MS_TO_NS(x) (x * 1E6L) + +#ifdef VPU_SUPPORT_ISR +#define VE1_IRQ_NUM (85) +#define VE3_IRQ_NUM (87) +#endif + +/* this definition is only for realtek FPGA board env */ +/* so for SOC env of customers can be ignored */ + +#ifndef VM_RESERVED /*for kernel up to 3.7.0 version*/ +# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) +#endif + +typedef struct vpu_drv_context_t { + struct fasync_struct *async_queue; + unsigned long interrupt_reason_ve1; + unsigned long interrupt_reason_ve3; + /* !<< device reference count. Not instance count */ + u32 open_count; +} vpu_drv_context_t; + +/* To track the allocated memory buffer */ +typedef struct vpudrv_buffer_pool_t { + struct list_head list; + struct vpudrv_buffer_t vb; + struct file *filp; +} vpudrv_buffer_pool_t; + +/* To track the instance index and buffer in instance pool */ +typedef struct vpudrv_instanace_list_t { + struct list_head list; + unsigned long inst_idx; + unsigned long core_idx; + struct file *filp; +} vpudrv_instanace_list_t; + +typedef struct vpudrv_instance_pool_t { + unsigned char codecInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE]; + long long pendingInstIdxPlus1; + void *pendingInst; +} vpudrv_instance_pool_t; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY +#define VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE 0x0b800000 //(62*1024*1024) +#define VPU_DRAM_PHYSICAL_BASE 0x03200000 //0x86C00000 +#include "vmm.h" +static video_mm_t s_vmem; +static vpudrv_buffer_t s_video_memory = {0}; +#endif /*VPU_SUPPORT_RESERVED_VIDEO_MEMORY*/ + +static int vpu_hw_reset(u32 coreIdx); + +/* end customer definition */ +static vpudrv_buffer_t s_instance_pool = {0}; +static vpudrv_buffer_t s_common_memory = {0}; +static vpu_drv_context_t s_vpu_drv_context; +static struct miscdevice s_vpu_dev; + +static struct device *p_vpu_dev; +static int s_vpu_open_ref_count; + +#ifdef VPU_SUPPORT_ISR +static int s_ve1_irq = VE1_IRQ_NUM; +static int s_ve3_irq = VE3_IRQ_NUM; +#endif /* VPU_SUPPORT_ISR */ + +static int ve_cti_en = 1; +/* FIX ME after ver.B IC */ +static int ve_idle_en = 0; + +static vpudrv_buffer_t s_vpu_register = {0}; +static vpudrv_buffer_t s_dc_register = {0}; +static vpudrv_buffer_t s_bond_register = {0}; +static vpudrv_buffer_t s_dmc_register = {0}; + +static atomic_t s_interrupt_flag_ve1; +static wait_queue_head_t s_interrupt_wait_q_ve1; +static atomic_t s_interrupt_flag_ve3; +static wait_queue_head_t s_interrupt_wait_q_ve3; + +static spinlock_t s_vpu_lock = __SPIN_LOCK_UNLOCKED(s_vpu_lock); +static spinlock_t s_ve1_lock = __SPIN_LOCK_UNLOCKED(s_ve1_lock); +static spinlock_t s_ve3_lock = __SPIN_LOCK_UNLOCKED(s_ve3_lock); +static DEFINE_SEMAPHORE(s_vpu_sem); +static struct list_head s_vbp_head = LIST_HEAD_INIT(s_vbp_head); +static struct list_head s_inst_list_head = LIST_HEAD_INIT(s_inst_list_head); +static struct reset_control *rstc_ve1; +static struct reset_control *rstc_ve3; + +static vpu_bit_firmware_info_t s_bit_firmware_info[MAX_NUM_VPU_CORE]; + +#define BIT_BASE 0x0000 +#define BIT_INT_STS (BIT_BASE + 0x010) +#define BIT_INT_REASON (BIT_BASE + 0x174) +#define BIT_INT_CLEAR (BIT_BASE + 0x00C) +#define VE_CTRL_REG (BIT_BASE + 0x3000) +#define VE_CTI_GRP_REG (BIT_BASE + 0x3004) +#define VE_INT_STS_REG (BIT_BASE + 0x3020) + +#define VE3_CTRL_REG (BIT_BASE + 0x3E00) + +#define W4_REG_BASE 0x0000 +#define W4_VPU_VINT_CLEAR (W4_REG_BASE + 0x003C) +#define W4_VPU_VPU_INT_STS (W4_REG_BASE + 0x0044) +#define W4_VPU_INT_REASON (W4_REG_BASE + 0x004c) +#define W4_VPU_INT_REASON_CLEAR (W4_REG_BASE + 0x0034) +#ifdef CONFIG_PM +/* implement to power management functions */ +#define BIT_CODE_RUN (BIT_BASE + 0x000) +#define BIT_CODE_DOWN (BIT_BASE + 0x004) +#define BIT_INT_CLEAR (BIT_BASE + 0x00C) +#define BIT_INT_STS (BIT_BASE + 0x010) +#define BIT_CODE_RESET (BIT_BASE + 0x014) +#define BIT_INT_REASON (BIT_BASE + 0x174) +#define BIT_BUSY_FLAG (BIT_BASE + 0x160) +#define BIT_RUN_COMMAND (BIT_BASE + 0x164) +#define BIT_RUN_INDEX (BIT_BASE + 0x168) +#define BIT_RUN_COD_STD (BIT_BASE + 0x16C) + +#define W4_VPU_BUSY_STATUS (W4_REG_BASE + 0x0070) +#define W4_RET_SUCCESS (W4_REG_BASE + 0x0110) +#define W4_RET_FAIL_REASON (W4_REG_BASE + 0x0114) +#define W4_PO_CONF (W4_REG_BASE + 0x0000) +#define W4_VCPU_CUR_PC (W4_REG_BASE + 0x0004) +#define W4_VPU_INT_ENABLE (W4_REG_BASE + 0x0048) +#define W4_VPU_RESET_REQ (W4_REG_BASE + 0x0050) +#define W4_VPU_RESET_STATUS (W4_REG_BASE + 0x0054) +#define W4_VPU_REMAP_CTRL (W4_REG_BASE + 0x0060) +#define W4_VPU_REMAP_VADDR (W4_REG_BASE + 0x0064) +#define W4_VPU_REMAP_PADDR (W4_REG_BASE + 0x0068) +#define W4_VPU_REMAP_PROC_START (W4_REG_BASE + 0x006C) +#define W4_VPU_BUSY_STATUS (W4_REG_BASE + 0x0070) +#define W4_REMAP_CODE_INDEX 0 +enum { + W4_INT_INIT_VPU = 0, + W4_INT_DEC_PIC_HDR = 1, + W4_INT_FINI_SEQ = 2, + W4_INT_DEC_PIC = 3, + W4_INT_SET_FRAMEBUF = 4, + W4_INT_FLUSH_DEC = 5, + W4_INT_GET_FW_VERSION = 9, + W4_INT_QUERY_DEC = 10, + W4_INT_SLEEP_VPU = 11, + W4_INT_WAKEUP_VPU = 12, + W4_INT_CHANGE_INT = 13, + W4_INT_CREATE_INSTANCE = 14, + W4_INT_BSBUF_EMPTY = 15, /*!<< Bitstream buffer empty */ + W4_INT_ENC_SLICE_INT = 15, +}; + +#define W4_HW_OPTION (W4_REG_BASE + 0x0124) +#define W4_CODE_SIZE (W4_REG_BASE + 0x011C) + +#define W4_ADDR_CODE_BASE (W4_REG_BASE + 0x0118) +#define W4_CODE_PARAM (W4_REG_BASE + 0x0120) + +#define W4_ADDR_STACK_BASE (W4_REG_BASE + 0x012C) +#define W4_STACK_SIZE (W4_REG_BASE + 0x0130) +#define W4_INIT_VPU_TIME_OUT_CNT (W4_REG_BASE + 0x0134) + +#define W4_CORE_INDEX (W4_REG_BASE + 0x0104) +#define W4_INST_INDEX (W4_REG_BASE + 0x0108) +#define W4_COMMAND (W4_REG_BASE + 0x0100) +#define W4_VPU_HOST_INT_REQ (W4_REG_BASE + 0x0038) +/* Product register */ +#define VPU_PRODUCT_CODE_REGISTER (BIT_BASE + 0x1044) + +#ifndef DISABLE_ORIGIN_SUSPEND +static u32 s_vpu_reg_store[MAX_NUM_VPU_CORE][64]; +#endif +#endif /* CONFIG_PM */ + +/* + * common struct and definition + */ +#define ReadVpuRegister(addr, core) *(volatile unsigned int *)(s_vpu_register.virt_addr + (0x8000 * core) + addr) +#define WriteVpuRegister(addr, val, core) *(volatile unsigned int *)(s_vpu_register.virt_addr + (0x8000 * core) + addr) = (unsigned int)val +#define WriteVpu(addr, val) *(volatile unsigned int *)(addr) = (unsigned int)val; + +static void ve1_wrapper_setup(unsigned int coreIdx) +{ + unsigned int ctrl_1; + unsigned int ctrl_2; + + /* coreIdx == 0 */ + if ((coreIdx & (1 << 0)) != 0) { + ctrl_1 = ReadVpuRegister(VE_CTRL_REG, 0); + ctrl_2 = ReadVpuRegister(VE_CTI_GRP_REG, 0); + ctrl_1 |= (ve_cti_en << 1 | ve_idle_en << 6); + /* ve1_cti_cmd_depth for 1296 timing issue */ + ctrl_2 = (ctrl_2 & ~(0x3f << 24)) | (0x1a << 24); + WriteVpuRegister(VE_CTRL_REG, ctrl_1, 0); + WriteVpuRegister(VE_CTI_GRP_REG, ctrl_2, 0); + } + + if ((coreIdx & (1 << 1)) != 0) + { + ctrl_1 = ReadVpuRegister(VE3_CTRL_REG, 1); + ctrl_1 |= ve_cti_en; + WriteVpuRegister(VE3_CTRL_REG, ctrl_1, 1); + } +} + +int vpu_hw_reset(u32 coreIdx) +{ + struct reset_control *rstc = coreIdx ? rstc_ve1 : rstc_ve3; + + reset_control_reset(rstc); + ve1_wrapper_setup((1 << coreIdx)); + return 0; +} + +static void vpu_hw_reset_init(struct device *dev) +{ + rstc_ve1 = devm_reset_control_get_exclusive(dev, "ve1"); + if (IS_ERR(rstc_ve1)) + dev_warn(dev, "failed to get ve1 reset control: %ld\n", PTR_ERR(rstc_ve1)); + rstc_ve3 = devm_reset_control_get_exclusive(dev, "ve3"); + if (IS_ERR(rstc_ve3)) + dev_warn(dev, "failed to get ve3 reset control: %ld\n", PTR_ERR(rstc_ve3)); +} + +static int vpu_alloc_dma_buffer(vpudrv_buffer_t *vb) +{ + unsigned int ret; + + if (!vb) + return -1; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + UNUSED_PARAMETER(ret); + vb->phys_addr = (unsigned long)vmem_alloc(&s_vmem, vb->size, 0); + if ((unsigned long)vb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } + + vb->base = (unsigned long)(s_video_memory.base + (vb->phys_addr - s_video_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + ret = pu_alloc_dma_buffer(vb->size, &vb->phys_addr, &vb->base, vb->mem_type); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#else + UNUSED_PARAMETER(ret); + vb->base = (unsigned long)dma_alloc_coherent(s_vpu_dev.this_device, PAGE_ALIGN(vb->size), (dma_addr_t *) (&vb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(vb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + DPRINTK("%s base:0x%lx, phy_addr:0x%lx, size:%d\n", DEV_NAME, vb->base, vb->phys_addr, vb->size); + return 0; +} + +static int vpu_alloc_dma_buffer2(vpudrv_buffer_t *vb) +{ + unsigned int ret; + + if (!vb) + return -1; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + UNUSED_PARAMETER(ret); + vb->phys_addr = (unsigned long)vmem_alloc(&s_vmem, vb->size, 0); + if ((unsigned long)vb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } + + vb->base = (unsigned long)(s_video_memory.base + (vb->phys_addr - s_video_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + ret = pu_alloc_dma_buffer(vb->size, &vb->phys_addr, &vb->base, vb->mem_type); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } + vb->base = pu_mmap_kernel_buffer(vb->phys_addr, vb->size); + if ((void *)(vb->base) == NULL) { + pr_err("%s pu_mmap_kernel_buffer error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#else + UNUSED_PARAMETER(ret); + vb->base = (unsigned long)dma_alloc_coherent(s_vpu_dev.this_device, PAGE_ALIGN(vb->size), (dma_addr_t *) (&vb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(vb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + DPRINTK("%s base:0x%lx, phy_addr:0x%lx, size:%d\n", DEV_NAME, vb->base, vb->phys_addr, vb->size); + return 0; +} + +static void vpu_free_dma_buffer(vpudrv_buffer_t *vb) +{ + if (!vb) + return; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (vb->base) + vmem_free(&s_vmem, vb->phys_addr, 0); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + pu_free_dma_buffer(vb->base, vb->phys_addr); +#else + if (vb->base) { + dma_free_coherent(s_vpu_dev.this_device, PAGE_ALIGN(vb->size), (void *)vb->base, vb->phys_addr); + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ +} + +/* size=40 for Android M */ +#define PTHREAD_MUTEX_T_HANDLE_SIZE 40 + +static int vpu_free_instances(struct file *filp) +{ + vpudrv_instanace_list_t *vil, *n; + vpudrv_instance_pool_t *vip; + void *vip_base; + int instance_pool_size_per_core; + void *vdi_mutexes_base; + const int PTHREAD_MUTEX_T_DESTROY_VALUE = 0xdead10cc; + + DPRINTK("%s vpu_free_instances\n", DEV_NAME); + + /* s_instance_pool.size assigned to the size of all core once call VDI_IOCTL_GET_INSTANCE_POOL by user. */ + instance_pool_size_per_core = (s_instance_pool.size/MAX_NUM_VPU_CORE); + + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->filp == filp) { + int i, j; + for (i = 0; i < MAX_NUM_INSTANCE; i++) /* reset dovi flag */ + { + for (j = 0; j < MAX_NUM_VPU_CORE; j++) + { + pu_set_dovi_flag(j, i, 0); + } + } + + vip_base = (void *)(s_instance_pool.base + (instance_pool_size_per_core*vil->core_idx)); + DPRINTK("%s vpu_free_instances detect instance crash instIdx=%d, coreIdx=%d, vip_base=%p, instance_pool_size_per_core=%d\n", DEV_NAME, (int)vil->inst_idx, (int)vil->core_idx, vip_base, (int)instance_pool_size_per_core); + vip = (vpudrv_instance_pool_t *)vip_base; + + if (vip) { + /* only first 4 byte is key point(inUse of CodecInst in vpuapi) to free the corresponding instance. */ + memset(&vip->codecInstPool[vil->inst_idx], 0x00, 4); + + if (vil->inst_idx == (vip->pendingInstIdxPlus1-1) && vip->pendingInst != 0) { + pr_warn("%s vil->inst_idx:%d, vil->core_idx:%d is pending, clear in here\n", DEV_NAME, (int)vil->inst_idx, (int)vil->core_idx); + vip->pendingInst = 0; + vip->pendingInstIdxPlus1 = 0; + } + + vdi_mutexes_base = (vip_base + (instance_pool_size_per_core - PTHREAD_MUTEX_T_HANDLE_SIZE*4)); + DPRINTK("%s vpu_free_instances : force to destroy vdi_mutexes_base=%p in userspace \n", DEV_NAME, vdi_mutexes_base); + if (vdi_mutexes_base) { + int i; + for (i = 0; i < 4; i++) { + memcpy(vdi_mutexes_base, &PTHREAD_MUTEX_T_DESTROY_VALUE, sizeof(PTHREAD_MUTEX_T_HANDLE_SIZE)); + vdi_mutexes_base += PTHREAD_MUTEX_T_HANDLE_SIZE; + } + } + } + s_vpu_open_ref_count--; + list_del(&vil->list); + kfree(vil); + } + } + return 1; +} + +static int vpu_free_buffers(struct file *filp) +{ + vpudrv_buffer_pool_t *pool, *n; + vpudrv_buffer_t vb; + + DPRINTK("%s vpu_free_buffers\n", DEV_NAME); + + list_for_each_entry_safe(pool, n, &s_vbp_head, list) { + if (pool->filp == filp) { + vb = pool->vb; + if (vb.base) { + vpu_free_dma_buffer(&vb); + list_del(&pool->list); + kfree(pool); + } + } + } + + return 0; +} + +static irqreturn_t ve1_irq_handler(int irq, void *dev_id) +{ + vpu_drv_context_t *dev = (vpu_drv_context_t *)dev_id; + + /* this can be removed. it also work in VPU_WaitInterrupt of API function */ + int core = 0; + unsigned long interrupt_reason_ve1 = 0; + unsigned int vpu_int_sts_ve1 = 0; + unsigned long flags; + + /* it means that we didn't get an information the current core from API layer. No core activated.*/ + if (s_bit_firmware_info[core].size == 0) { + pr_err("[VPUDRV] : s_bit_firmware_info[core].size is zero\n"); + return IRQ_HANDLED; + } + + vpu_int_sts_ve1 = ReadVpuRegister(BIT_INT_STS, core); + if (vpu_int_sts_ve1) { + interrupt_reason_ve1 = ReadVpuRegister(BIT_INT_REASON, core); + WriteVpuRegister(BIT_INT_REASON, 0, core); + WriteVpuRegister(BIT_INT_CLEAR, 0x1, core); + } + + //DPRINTK("%s VE1 intr_reason: 0x%08lx\n", DEV_NAME, dev->interrupt_reason_ve1); + + if (dev->async_queue) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* notify the interrupt to user space */ + + if (vpu_int_sts_ve1) { + if (core == 0) { + dev->interrupt_reason_ve1 = interrupt_reason_ve1; + atomic_set(&s_interrupt_flag_ve1, 1); + wake_up_interruptible(&s_interrupt_wait_q_ve1); + } + //DPRINTK("%s [-]%s\n", DEV_NAME, __func__); + } + + return IRQ_HANDLED; +} + +#ifdef SUPPORT_MULTI_INST_INTR +static inline u32 get_inst_idx(u32 reg_val) +{ + u32 inst_idx; + int i; + for (i=0; i < MAX_NUM_INSTANCE; i++) + { + if(((reg_val >> i)&0x01) == 1) + break; + } + inst_idx = i; + return inst_idx; +} + +static u32 get_vpu_inst_idx(vpu_drv_context_t *dev, u32 *reason, u32 empty_inst, u32 done_inst, u32 other_inst) +{ + u32 inst_idx; + u32 reg_val; + u32 int_reason; + + int_reason = *reason; + DPRINTK("%s [+]%s, int_reason=0x%x, empty_inst=0x%x, done_inst=0x%x\n", DEV_NAME, __func__, int_reason, empty_inst, done_inst); + + if (int_reason & (1 << W4_INT_BSBUF_EMPTY)) + { + reg_val = empty_inst; + inst_idx = get_inst_idx(reg_val); + *reason = (1 << W4_INT_BSBUF_EMPTY); + DPRINTK("%s %s, W4_RET_BS_EMPTY_INST reg_val=0x%x, inst_idx=%d\n", DEV_NAME, __func__, reg_val, inst_idx); + goto GET_VPU_INST_IDX_HANDLED; + } + + if (int_reason & (1 << W4_INT_DEC_PIC)) + { + reg_val = done_inst; + inst_idx = get_inst_idx(reg_val); + *reason = (1 << W4_INT_DEC_PIC); + DPRINTK("[VPUDRV] %s, W4_RET_QUEUE_CMD_DONE_INST DEC_PIC reg_val=0x%x, inst_idx=%d\n", __func__, reg_val, inst_idx); + goto GET_VPU_INST_IDX_HANDLED; + } + // if interrupt is not for empty and dec_pic and init_seq. + reg_val = (other_inst&0xFF); + inst_idx = reg_val; + *reason = int_reason; + DPRINTK("%s %s, W4_RET_DONE_INSTANCE_INFO reg_val=0x%x, inst_idx=%d\n", DEV_NAME, __func__, reg_val, inst_idx); +GET_VPU_INST_IDX_HANDLED: + + DPRINTK("%s [-]%s, inst_idx=%d. *reason=0x%x\n", DEV_NAME, __func__, inst_idx, *reason); + + return inst_idx; +} +#endif +static irqreturn_t ve3_irq_handler(int irq, void *dev_id) +{ + vpu_drv_context_t *dev = (vpu_drv_context_t *)dev_id; + + /* this can be removed. it also work in VPU_WaitInterrupt of API function */ + int core = 1; + unsigned int vpu_int_sts_ve3 = 0; + unsigned long flags; +#ifdef SUPPORT_MULTI_INST_INTR + u32 intr_reason = 0; + u32 intr_inst_index = 0; +#endif + +// pr_err("[VPUDRV][+]%s\n", __func__); + + if (s_bit_firmware_info[core].size == 0) {/* it means that we didn't get an information the current core from API layer. No core activated.*/ + pr_err("[VPUDRV] : s_bit_firmware_info[core].size is zero\n"); + return IRQ_HANDLED; + } + + int product_code = ReadVpuRegister(VPU_PRODUCT_CODE_REGISTER, core); + + if (PRODUCT_CODE_W_SERIES(product_code)) { + if (ReadVpuRegister(W4_VPU_VPU_INT_STS, core)) { + dev->interrupt_reason_ve3 = ReadVpuRegister(W4_VPU_INT_REASON, core); + WriteVpuRegister(W4_VPU_INT_REASON_CLEAR, dev->interrupt_reason_ve3, core); + WriteVpuRegister(W4_VPU_VINT_CLEAR, 0x1, core); +// pr_err("[VPUDRV]have real interrupt!!!\n"); + } + } + else { + pr_err("[VPUDRV] Unknown product id : %08x\n", product_code); + } +// pr_err("[VPUDRV] product: 0x%08x intr_reason: 0x%08lx\n", product_code, dev->interrupt_reason_ve3); + + if (dev->async_queue) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* notify the interrupt to user space */ + + atomic_set(&s_interrupt_flag_ve3, 1); + + wake_up_interruptible(&s_interrupt_wait_q_ve3); +// pr_err("[VPUDRV][-]%s\n", __func__); + return IRQ_HANDLED; +} + + +static int vpu_open(struct inode *inode, struct file *filp) +{ + DPRINTK("%s [+] %s\n", DEV_NAME, __func__); + spin_lock(&s_vpu_lock); + + s_vpu_drv_context.open_count++; + + filp->private_data = (void *)(&s_vpu_drv_context); + spin_unlock(&s_vpu_lock); + + DPRINTK("%s [-] %s\n", DEV_NAME, __func__); + + return 0; +} + +/*static int vpu_ioctl(struct inode *inode, struct file *filp, u_int cmd, u_long arg) // for kernel 2.6.9*/ +static long vpu_ioctl(struct file *filp, u_int cmd, u_long arg) +{ + int ret = 0; + struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)filp->private_data; + + switch (cmd) { + case VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + { + vpudrv_buffer_pool_t *vbp; + + DPRINTK("%s [+]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + vbp = kzalloc(sizeof(*vbp), GFP_KERNEL); + if (!vbp) { + up(&s_vpu_sem); + return -ENOMEM; + } + + ret = copy_from_user(&(vbp->vb), (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret) { + kfree(vbp); + up(&s_vpu_sem); + return -EFAULT; + } + + ret = vpu_alloc_dma_buffer(&(vbp->vb)); + if (ret == -1) { + ret = -ENOMEM; + kfree(vbp); + up(&s_vpu_sem); + break; + } + + ret = copy_to_user((void __user *)arg, &(vbp->vb), sizeof(vpudrv_buffer_t)); + if (ret) { + kfree(vbp); + ret = -EFAULT; + up(&s_vpu_sem); + break; + } + + vbp->filp = filp; + spin_lock(&s_vpu_lock); + list_add(&vbp->list, &s_vbp_head); + spin_unlock(&s_vpu_lock); + + up(&s_vpu_sem); + } + DPRINTK("%s [-]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY\n", DEV_NAME); + } + break; + case VDI_IOCTL_FREE_PHYSICALMEMORY: + { + vpudrv_buffer_pool_t *vbp, *n; + vpudrv_buffer_t vb; + + DPRINTK("%s [+]VDI_IOCTL_FREE_PHYSICALMEMORY\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + ret = copy_from_user(&vb, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret) { + up(&s_vpu_sem); + return -EACCES; + } + + if (vb.base) + vpu_free_dma_buffer(&vb); + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vbp, n, &s_vbp_head, list) { + if (vbp->vb.phys_addr == vb.phys_addr/*vbp->vb.base == vb.base*/) { + list_del(&vbp->list); + kfree(vbp); + break; + } + } + spin_unlock(&s_vpu_lock); + + up(&s_vpu_sem); + } + DPRINTK("%s [-]VDI_IOCTL_FREE_PHYSICALMEMORY\n", DEV_NAME); + } + break; + case VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: + { +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + DPRINTK("%s [+]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n", DEV_NAME); + if (s_video_memory.base != 0) { + ret = copy_to_user((void __user *)arg, &s_video_memory, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = -EFAULT; + } + DPRINTK("%s [-]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n", DEV_NAME); +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + } + break; + + case VDI_IOCTL_WAIT_INTERRUPT: + { + vpudrv_intr_info_t info; + unsigned long flags; +#ifdef SUPPORT_MULTI_INST_INTR + u32 intr_inst_index; + u32 intr_reason_in_q; + u32 interrupt_flag_in_q; +#endif + DPRINTK("[VPUDRV][+]VDI_IOCTL_WAIT_INTERRUPT\n"); + ret = copy_from_user(&info, (vpudrv_intr_info_t *)arg, sizeof(vpudrv_intr_info_t)); + if (ret != 0) + return -EFAULT; + + /* VE1 */ + if (info.core_idx == 0) { + smp_rmb(); + ret = wait_event_interruptible_timeout(s_interrupt_wait_q_ve1, atomic_read(&s_interrupt_flag_ve1) != 0, msecs_to_jiffies(info.timeout)); + if (!ret) { + ret = -ETIME; + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + //DPRINTK("[VPUDRV] s_interrupt_flag_ve1(%d), reason(0x%08lx)\n", atomic_read(&s_interrupt_flag_ve1), dev->interrupt_reason_ve1); + atomic_set(&s_interrupt_flag_ve1, 0); + info.intr_reason = dev->interrupt_reason_ve1; + dev->interrupt_reason_ve1 = 0; + } else { /* VE3 */ + ret = wait_event_interruptible_timeout(s_interrupt_wait_q_ve3, atomic_read(&s_interrupt_flag_ve3) != 0, msecs_to_jiffies(info.timeout)); + if (!ret) { + ret = -ETIME; + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + //DPRINTK("[VPUDRV] s_interrupt_flag_ve1(%d), reason(0x%08lx)\n", atomic_read(&s_interrupt_flag_ve1), dev->interrupt_reason_ve1); + spin_lock_irqsave(&s_ve3_lock, flags); + atomic_set(&s_interrupt_flag_ve3, 0); + + info.intr_reason = dev->interrupt_reason_ve3; + dev->interrupt_reason_ve3 = 0; + spin_unlock_irqrestore(&s_ve3_lock, flags); + } + ret = copy_to_user((void __user *)arg, &info, sizeof(vpudrv_intr_info_t)); + DPRINTK("[VPUDRV][-]VDI_IOCTL_WAIT_INTERRUPT, info.intr_reason[%d]:0x%x\n", intr_inst_index, info.intr_reason); + if (ret != 0) + return -EFAULT; + } + break; + case VDI_IOCTL_SET_CLOCK_GATE: + { + u32 clkgate; + + //DPRINTK("[VPUDRV][+]VDI_IOCTL_SET_CLOCK_GATE\n"); + if (get_user(clkgate, (u32 __user *) arg)) + return -EFAULT; +#ifdef VPU_SUPPORT_CLOCK_CONTROL + return -EFAULT; +#endif /* VPU_SUPPORT_CLOCK_CONTROL */ + //DPRINTK("[VPUDRV][-]VDI_IOCTL_SET_CLOCK_GATE\n"); + } + break; + case VDI_IOCTL_GET_INSTANCE_POOL: + { + DPRINTK("%s [+]VDI_IOCTL_GET_INSTANCE_POOL\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + if (s_instance_pool.base != 0) { + ret = copy_to_user((void __user *)arg, &s_instance_pool, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = copy_from_user(&s_instance_pool, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret == 0) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + s_instance_pool.size = PAGE_ALIGN(s_instance_pool.size); + s_instance_pool.base = (unsigned long)vmalloc(s_instance_pool.size); + s_instance_pool.phys_addr = s_instance_pool.base; + + if (s_instance_pool.base != 0) +#else + if (vpu_alloc_dma_buffer2(&s_instance_pool) != -1) +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + { + memset((void *)s_instance_pool.base, 0x0, s_instance_pool.size); /*clearing memory*/ + ret = copy_to_user((void __user *)arg, &s_instance_pool, sizeof(vpudrv_buffer_t)); + if (ret == 0) { + /* success to get memory for instance pool */ + up(&s_vpu_sem); + break; + } + } + + } + ret = -EFAULT; + } + + up(&s_vpu_sem); + } + + DPRINTK("%s [-]VDI_IOCTL_GET_INSTANCE_POOL\n", DEV_NAME); + } + break; + case VDI_IOCTL_GET_COMMON_MEMORY: + { + DPRINTK("%s [+]VDI_IOCTL_GET_COMMON_MEMORY\n", DEV_NAME); + if (s_common_memory.base != 0) { + ret = copy_to_user((void __user *)arg, &s_common_memory, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = copy_from_user(&s_common_memory, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret == 0) { + if (vpu_alloc_dma_buffer(&s_common_memory) != -1) { + ret = copy_to_user((void __user *)arg, &s_common_memory, sizeof(vpudrv_buffer_t)); + if (ret == 0) { + /* success to get memory for common memory */ + break; + } + } + } + + ret = -EFAULT; + } + DPRINTK("%s [-]VDI_IOCTL_GET_COMMON_MEMORY\n", DEV_NAME); + } + break; + case VDI_IOCTL_OPEN_INSTANCE: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + + vil = kzalloc(sizeof(*vil), GFP_KERNEL); + if (!vil) + return -ENOMEM; + + if (copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t))) { + kfree(vil); + return -EFAULT; + } + + vil->inst_idx = inst_info.inst_idx; + vil->core_idx = inst_info.core_idx; + vil->filp = filp; + + spin_lock(&s_vpu_lock); + list_add(&vil->list, &s_inst_list_head); + + inst_info.inst_open_count = 0; /* counting the current open instance number */ + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->core_idx == inst_info.core_idx) + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + s_vpu_open_ref_count++; /* flag just for that vpu is in opened or closed */ + + if (copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t))) { + kfree(vil); + return -EFAULT; + } + + DPRINTK("%s VDI_IOCTL_OPEN_INSTANCE core_idx=%d, inst_idx=%d, s_vpu_open_ref_count=%d, inst_open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, s_vpu_open_ref_count, inst_info.inst_open_count); + } + break; + case VDI_IOCTL_CLOSE_INSTANCE: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + + DPRINTK("%s [+]VDI_IOCTL_CLOSE_INSTANCE\n", DEV_NAME); + if (copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t))) + return -EFAULT; + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->inst_idx == inst_info.inst_idx && vil->core_idx == inst_info.core_idx) { + list_del(&vil->list); + kfree(vil); + break; + } + } + + inst_info.inst_open_count = 0; /* counting the current open instance number */ + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->core_idx == inst_info.core_idx) + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + s_vpu_open_ref_count--; /* flag just for that vpu is in opened or closed */ + + if (copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t))) + return -EFAULT; + + DPRINTK("%s VDI_IOCTL_CLOSE_INSTANCE core_idx=%d, inst_idx=%d, s_vpu_open_ref_count=%d, inst_open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, s_vpu_open_ref_count, inst_info.inst_open_count); + } + break; + case VDI_IOCTL_GET_INSTANCE_NUM: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + DPRINTK("%s [+]VDI_IOCTL_GET_INSTANCE_NUM\n", DEV_NAME); + + ret = copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t)); + if (ret != 0) + break; + + inst_info.inst_open_count = 0; + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->core_idx == inst_info.core_idx) + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + ret = copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t)); + + DPRINTK("%s VDI_IOCTL_GET_INSTANCE_NUM core_idx=%d, inst_idx=%d, open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, inst_info.inst_open_count); + + } + break; + case VDI_IOCTL_RESET: + { + u32 coreIdx; + if (get_user(coreIdx, (u32 __user *) arg)) + return -EFAULT; + vpu_hw_reset(coreIdx); + } + break; + case VDI_IOCTL_GET_REGISTER_INFO: + { + DPRINTK("%s [+]VDI_IOCTL_GET_REGISTER_INFO\n", DEV_NAME); + ret = copy_to_user((void __user *)arg, &s_vpu_register, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + DPRINTK("%s [-]VDI_IOCTL_GET_REGISTER_INFO s_vpu_register.phys_addr=0x%lx, s_vpu_register.virt_addr=0x%lx, s_vpu_register.size=%d\n", DEV_NAME, s_vpu_register.phys_addr, s_vpu_register.virt_addr, s_vpu_register.size); + } + break; + /* RTK ioctl */ + case VDI_IOCTL_SET_RTK_CLK_GATING: + { + vpu_clock_info_t clockInfo; + + DPRINTK("%s [+]VDI_IOCTL_SET_RTK_CLK_GATING\n", DEV_NAME); + ret = copy_from_user(&clockInfo, (vpu_clock_info_t *)arg, sizeof(vpu_clock_info_t)); + if (ret != 0) + break; + + if (clockInfo.enable) { + ve_pd_power_on(clockInfo.core_idx); + ve1_wrapper_setup((1 << clockInfo.core_idx)); + } else { + ve_pd_power_off(clockInfo.core_idx); + } + + DPRINTK("%s [-]VDI_IOCTL_SET_RTK_CLK_GATING clockInfo.core_idx:%d, clockInfo.enable:%d\n", DEV_NAME, clockInfo.core_idx, clockInfo.enable); + } + break; + case VDI_IOCTL_SET_RTK_CLK_PLL: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_GET_RTK_CLK_PLL: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_SET_RTK_CLK_SELECT: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_GET_RTK_CLK_SELECT: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_GET_RTK_SUPPORT_TYPE: + { + ret = copy_to_user((void __user *)arg, &s_bond_register, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } + break; + case VDI_IOCTL_GET_RTK_DCSYS_INFO: + { + vpudrv_buffer_t vb; + ret = copy_from_user(&vb, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (vb.mem_type == 0) + ret = copy_to_user((void __user *)arg, &s_dc_register, sizeof(vpudrv_buffer_t)); + else + ret = copy_to_user((void __user *)arg, &s_dmc_register, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } + break; + case VDI_IOCTL_GET_RTK_ASIC_REVISION: + { + __put_user(get_rtd_chip_revision()|get_rtd_chip_id(), (unsigned int *) arg); + } + break; + case VDI_IOCTL_SET_RTK_DOVI_FLAG: + { + vpudrv_dovi_info_t doviInfo; + DPRINTK("%s [+]VDI_IOCTL_SET_RTK_DOVI_FLAG\n", DEV_NAME); + ret = copy_from_user(&doviInfo, (vpudrv_dovi_info_t *)arg, sizeof(vpudrv_dovi_info_t)); + if (ret != 0) + break; + + doviInfo.enable = pu_set_dovi_flag(doviInfo.core_idx, doviInfo.inst_idx, doviInfo.enable); + + ret = copy_to_user((vpudrv_dovi_info_t *)arg, &doviInfo, sizeof(vpudrv_dovi_info_t)); + if (ret != 0) + break; + DPRINTK("%s [-]VDI_IOCTL_SET_RTK_DOVI_FLAG doviInfo.core_idx:%d, doviInfo.inst_idx:%d, doviInfo.value:%d\n", DEV_NAME, doviInfo.core_idx, doviInfo.inst_idx, doviInfo.enable); + } + break; + case VDI_IOCTL_GET_TOTAL_INSTANCE_NUM: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + DPRINTK("%s [+]VDI_IOCTL_GET_TOTAL_INSTANCE_NUM\n", DEV_NAME); + + ret = copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t)); + if (ret != 0) + break; + + inst_info.inst_open_count = 0; + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + ret = copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t)); + + DPRINTK("%s VDI_IOCTL_GET_TOTAL_INSTANCE_NUM core_idx=%d, inst_idx=%d, open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, inst_info.inst_open_count); + + } + break; + default: + { + pr_err("%s No such IOCTL, cmd is %d\n", DEV_NAME, cmd); + } + break; + } + + return ret; +} + +static ssize_t vpu_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) +{ + return -1; +} + +static int compat_get_vpu_bit_firmware_info_data( + compat_vpu_bit_firmware_info_t __user *data32, + vpu_bit_firmware_info_t __user *data) +{ +#if defined(CONFIG_CPU_V7) + //u32 s; + u32 c; + u32 r; + u32 b[512]; +#else + //compat_uint_t s; + compat_uint_t c; + compat_ulong_t r; + compat_ushort_t b[512]; +#endif /* CONFIG_CPU_V7 */ + + int err; + + //err = get_user(s, &data32->size); + //err |= put_user(s, &data->size); + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(r, &data32->reg_base_offset); + err |= put_user(r, &data->reg_base_offset); + err |= copy_from_user(b, data32->bit_code, sizeof(b)); + err |= copy_to_user(data->bit_code, b, sizeof(b)); + + return err; +}; + +static ssize_t vpu_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) +{ + + /* DPRINTK("[VPUDRV] vpu_write len=%d\n", (int)len); */ + if (!buf) { + pr_err("%s vpu_write buf = NULL error \n", DEV_NAME); + return -EFAULT; + } + + if (len == sizeof(vpu_bit_firmware_info_t) || len == sizeof(compat_vpu_bit_firmware_info_t)) { + vpu_bit_firmware_info_t *bit_firmware_info; + + bit_firmware_info = kmalloc(sizeof(vpu_bit_firmware_info_t), GFP_KERNEL); + if (!bit_firmware_info) { + pr_err("%s vpu_write bit_firmware_info allocation error\n", DEV_NAME); + return -EFAULT; + } + + if (len == sizeof(vpu_bit_firmware_info_t)) { + if (copy_from_user(bit_firmware_info, buf, len)) { + pr_err("%s vpu_write copy_from_user error for bit_firmware_info\n", DEV_NAME); + kfree(bit_firmware_info); + return -EFAULT; + } + } +#ifdef CONFIG_COMPAT + else { + int err; + compat_vpu_bit_firmware_info_t __user *data32; + vpu_bit_firmware_info_t __user *data; + + data32 = (compat_vpu_bit_firmware_info_t __user *) buf; + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) { + kfree(bit_firmware_info); + return -EFAULT; + } + + err = compat_get_vpu_bit_firmware_info_data(data32, data); + if (err) { + kfree(bit_firmware_info); + return err; + } + + if (copy_from_user(bit_firmware_info, data, sizeof(vpu_bit_firmware_info_t))) { + pr_err("%s vpu_write copy_from_user error for bit_firmware_info\n", DEV_NAME); + kfree(bit_firmware_info); + return -EFAULT; + } + bit_firmware_info->size = sizeof(vpu_bit_firmware_info_t); + } +#endif /* CONFIG_COMPAT */ + + if (bit_firmware_info->size == sizeof(vpu_bit_firmware_info_t)) { + DPRINTK("%s vpu_write set bit_firmware_info coreIdx=0x%x, reg_base_offset=0x%x size=0x%x, bit_code[0]=0x%x\n", + DEV_NAME, bit_firmware_info->core_idx, (int)bit_firmware_info->reg_base_offset, bit_firmware_info->size, bit_firmware_info->bit_code[0]); + + if (bit_firmware_info->core_idx > MAX_NUM_VPU_CORE) { + pr_err("%s vpu_write coreIdx[%d] is exceeded than MAX_NUM_VPU_CORE[%d]\n", DEV_NAME, bit_firmware_info->core_idx, MAX_NUM_VPU_CORE); + kfree(bit_firmware_info); + return -ENODEV; + } + + memcpy((void *)&s_bit_firmware_info[bit_firmware_info->core_idx], bit_firmware_info, sizeof(vpu_bit_firmware_info_t)); + kfree(bit_firmware_info); + + return len; + } + + kfree(bit_firmware_info); + } + + return -1; +} + +static int vpu_release(struct inode *inode, struct file *filp) +{ + int ret = 0; + DPRINTK("%s vpu_release\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + /* found and free the not handled buffer by user applications */ + vpu_free_buffers(filp); + /* found and free the not closed instance by user applications */ + vpu_free_instances(filp); + s_vpu_drv_context.open_count--; + if (s_vpu_drv_context.open_count == 0) { + if (s_instance_pool.base) { + DPRINTK("%s free instance pool\n", DEV_NAME); +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + s_instance_pool.base = 0; + } +#if 0 /* Fuchun 20150909, we must not free instance pool and common memory */ + if (s_common_memory.base) { + DPRINTK("%s free common memory\n", DEV_NAME); + vpu_free_dma_buffer(&s_common_memory); + s_common_memory.base = 0; + } +#endif + } + } + up(&s_vpu_sem); + + return 0; +} + +static int vpu_fasync(int fd, struct file *filp, int mode) +{ + struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)filp->private_data; + return fasync_helper(fd, filp, mode, &dev->async_queue); +} + +static int vpu_map_to_register(struct file *fp, struct vm_area_struct *vm) +{ + unsigned long pfn; + + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + pfn = vm->vm_pgoff; + + return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +} + +static int vpu_map_to_physical_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef CONFIG_RTK_RESERVE_MEMORY + return pu_mmap_dma_buffer(vm); +#else + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot); + + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif /* CONFIG_RTK_RESERVE_MEMORY */ +} + +static int vpu_map_to_instance_pool_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + int ret; + long length = vm->vm_end - vm->vm_start; + unsigned long start = vm->vm_start; + char *vmalloc_area_ptr = (char *)s_instance_pool.base; + unsigned long pfn; + + vm->vm_flags |= VM_RESERVED; + + /* loop over all pages, map it page individually */ + while (length > 0) { + pfn = vmalloc_to_pfn(vmalloc_area_ptr); + ret = remap_pfn_range(vm, start, pfn, PAGE_SIZE, PAGE_SHARED); + if (ret < 0) { + return ret; + } + start += PAGE_SIZE; + vmalloc_area_ptr += PAGE_SIZE; + length -= PAGE_SIZE; + } + + return 0; +#else + vm->vm_flags |= VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ +} + +/*! + * @brief memory map interface for vpu file operation + * @return 0 on success or negative error code on error + */ +static int vpu_mmap(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + if (vm->vm_pgoff == 0) + return vpu_map_to_instance_pool_memory(fp, vm); + + if ((vm->vm_pgoff == (s_vpu_register.phys_addr>>PAGE_SHIFT)) + || (vm->vm_pgoff == (s_bond_register.phys_addr>>PAGE_SHIFT)) + || (vm->vm_pgoff == (s_dc_register.phys_addr>>PAGE_SHIFT)) + || (vm->vm_pgoff == (s_dmc_register.phys_addr>>PAGE_SHIFT))) + return vpu_map_to_register(fp, vm); + + return vpu_map_to_physical_memory(fp, vm); +#else + if (vm->vm_pgoff) { + if (vm->vm_pgoff == (s_instance_pool.phys_addr>>PAGE_SHIFT)) + return vpu_map_to_instance_pool_memory(fp, vm); + + return vpu_map_to_physical_memory(fp, vm); + } else { + return vpu_map_to_register(fp, vm); + } +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ +} + +struct file_operations vpu_fops = { + .owner = THIS_MODULE, + .open = vpu_open, + .read = vpu_read, + .write = vpu_write, + /*.ioctl = vpu_ioctl, // for kernel 2.6.9*/ + .unlocked_ioctl = vpu_ioctl, + .compat_ioctl = compat_vpu_ioctl, + .release = vpu_release, + .fasync = vpu_fasync, + .mmap = vpu_mmap, +}; + + +static int vpu_probe(struct platform_device *pdev) +{ + int err = 0; + u32 bonding_value; + unsigned long virt_addr; + struct resource res; + void __iomem *iobase; + int irq; + struct device_node *node = pdev->dev.of_node; +#if 0 //Fuchun disable 20160204, set clock gating by vdi.c + unsigned int val = 0; +#endif + + pr_info("%s vpu_probe\n", DEV_NAME); + + of_address_to_resource(node, 0, &res); + iobase = of_iomap(node, 0); + + s_vpu_register.phys_addr = res.start; + s_vpu_register.virt_addr = (unsigned long)iobase; + s_vpu_register.size = res.end - res.start + 1; + + pr_info("%s vpu base address get from DTB physical base addr=0x%lx, virtual base=0x%lx, size=0x%x\n", DEV_NAME, s_vpu_register.phys_addr, s_vpu_register.virt_addr, s_vpu_register.size); + + of_address_to_resource(node, 1, &res); + iobase = of_iomap(node, 1); + + s_dc_register.phys_addr = res.start; + s_dc_register.virt_addr = (unsigned long)iobase; + s_dc_register.size = res.end - res.start + 1; + + s_vpu_dev.minor = MISC_VE1_MINOR; + s_vpu_dev.name = VPU_DEV_NAME; + s_vpu_dev.fops = &vpu_fops; + s_vpu_dev.parent = NULL; + if (misc_register(&s_vpu_dev)) { + pr_err("%s failed to register misc device.", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + + of_address_to_resource(node, 2, &res); + iobase = of_iomap(node, 2); + + s_bond_register.phys_addr = res.start; + s_bond_register.virt_addr = (unsigned long)iobase; + s_bond_register.size = res.end - res.start + 1; + + virt_addr = (unsigned long)iobase; + bonding_value = __raw_readl((volatile u8 *)virt_addr); + + pr_info("%s res.start:0x%llx, bonding_value:0x%x\n", DEV_NAME, res.start, bonding_value); + + of_address_to_resource(node, 3, &res); + iobase = of_iomap(node, 3); + + s_dmc_register.phys_addr = res.start; + s_dmc_register.virt_addr = (unsigned long)iobase; + s_dmc_register.size = res.end - res.start + 1; + + ve_pd_init(&pdev->dev); + vpu_hw_reset_init(&pdev->dev); + + p_vpu_dev = &pdev->dev; + + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + s_ve1_irq = irq; + pr_info("%s s_ve1_irq:%d want to register ve1_irq_handler\n", DEV_NAME, s_ve1_irq); + err = request_irq(s_ve1_irq, ve1_irq_handler, 0, "VE1_CODEC_IRQ", (void *)(&s_vpu_drv_context)); + err = 0; + if (err != 0) { + if (err == -EINVAL) + pr_err("%s Bad s_ve1_irq number or handler\n", DEV_NAME); + else if (err == -EBUSY) + pr_err("%s s_ve1_irq <%d> busy, change your config\n", DEV_NAME, s_ve1_irq); + goto ERROR_PROVE_DEVICE; + } + + irq = irq_of_parse_and_map(node, 1); + if (irq <= 0) + panic("Can't parse IRQ"); + + s_ve3_irq = irq; + pr_info("%s s_ve3_irq:%d want to register ve3_irq_handler\n", DEV_NAME, s_ve3_irq); + err = request_irq(s_ve3_irq, ve3_irq_handler, 0, "VE3_CODEC_IRQ", (void *)(&s_vpu_drv_context)); + if (err != 0) { + if (err == -EINVAL) + pr_err("%s Bad s_ve3_irq number or handler\n", DEV_NAME); + else if (err == -EBUSY) + pr_err("%s s_ve3_irq <%d> busy, change your config\n", DEV_NAME, s_ve3_irq); + goto ERROR_PROVE_DEVICE; + } + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + s_video_memory.size = VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE; + s_video_memory.phys_addr = VPU_DRAM_PHYSICAL_BASE; + s_video_memory.base = (unsigned long)ioremap_nocache(s_video_memory.phys_addr, PAGE_ALIGN(s_video_memory.size)); + if (!s_video_memory.base) { + pr_err("%s fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n", DEV_NAME, (int)s_video_memory.phys_addr, (int)s_video_memory.base, (int)s_video_memory.size); + goto ERROR_PROVE_DEVICE; + } + + if (vmem_init(&s_vmem, s_video_memory.phys_addr, s_video_memory.size) < 0) { + pr_err("%s fail to init vmem system\n", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + pr_info("%s success to probe vpu device with reserved video memory phys_addr=0x%x, base = 0x%x\n", DEV_NAME, (int) s_video_memory.phys_addr, (int)s_video_memory.base); +#else + pr_info("%s success to probe vpu device with non reserved video memory\n", DEV_NAME); +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + return 0; + + +ERROR_PROVE_DEVICE: + + ve_pd_exit(&pdev->dev); + misc_deregister(&s_vpu_dev); + + return err; +} + +static int vpu_remove(struct platform_device *pdev) +{ + DPRINTK("%s vpu_remove\n", DEV_NAME); + + ve_pd_exit(&pdev->dev); + +#ifdef VPU_SUPPORT_PLATFORM_DRIVER_REGISTER + if (s_instance_pool.base) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* VPU_SUPPORT_PLATFORM_DRIVER_REGISTER */ + s_instance_pool.base = 0; + } + + if (s_common_memory.base) { + vpu_free_dma_buffer(&s_common_memory); + s_common_memory.base = 0; + } + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_video_memory.base) { + iounmap((void *)s_video_memory.base); + s_video_memory.base = 0; + vmem_exit(&s_vmem); + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + misc_deregister(&s_vpu_dev); + +#ifdef VPU_SUPPORT_ISR + if (s_ve1_irq) + free_irq(s_ve1_irq, &s_vpu_drv_context); + if (s_ve3_irq) + free_irq(s_ve3_irq, &s_vpu_drv_context); +#endif /* VPU_SUPPORT_ISR */ + +#endif /* VPU_SUPPORT_PLATFORM_DRIVER_REGISTER */ + + return 0; +} + +#ifdef CONFIG_PM +/* DO NOT CHANGE */ +#define WAVE5_STACK_SIZE (8*1024) +#define W4_MAX_CODE_BUF_SIZE (512*1024) +#define W4_CMD_INIT_VPU (0x0001) +#define W4_CMD_SLEEP_VPU (0x0400) +#define W4_CMD_WAKEUP_VPU (0x0800) + +static int vpu_suspend(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + ve_pd_power_on(0); + ve_pd_power_on(1); + + /* RTK wrapper */ + ve1_wrapper_setup((1 << 1) | 1); + + if (s_vpu_open_ref_count > 0) { +#ifdef DISABLE_ORIGIN_SUSPEND + vpudrv_instanace_list_t *vil, *n; + vpudrv_instance_pool_t *vip; + void *vip_base; + int instance_pool_size_per_core; + vpudrv_buffer_pool_t *pool, *nn; + vpudrv_buffer_t vb; + s_vpu_drv_context.open_count = 0; + s_vpu_open_ref_count = 0; + + /* s_instance_pool.size assigned to the size of all core once call VDI_IOCTL_GET_INSTANCE_POOL by user. */ + instance_pool_size_per_core = (s_instance_pool.size/MAX_NUM_VPU_CORE); + + wake_up_interruptible_all(&s_interrupt_wait_q_ve1); + atomic_set(&s_interrupt_flag_ve1, 0); + wake_up_interruptible_all(&s_interrupt_wait_q_ve3); + atomic_set(&s_interrupt_flag_ve3, 0); + + + + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + vip_base = (void *)(s_instance_pool.base + (instance_pool_size_per_core*vil->core_idx)); + vip = (vpudrv_instance_pool_t *)vip_base; + if (vip) { + /* only first 4 byte is key point(inUse of CodecInst in vpuapi) to free the corresponding instance. */ + memset(&vip->codecInstPool[vil->inst_idx], 0x00, 4); + } + list_del(&vil->list); + kfree(vil); + } + + list_for_each_entry_safe(pool, nn, &s_vbp_head, list) { + vb = pool->vb; + if (vb.base) { + vpu_free_dma_buffer(&vb); + } + list_del(&pool->list); + kfree(pool); + } + + if (s_instance_pool.base) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + s_instance_pool.base = 0; + } +#else /* else of DISABLE_ORIGIN_SUSPEND */ + int i; + int core; + unsigned long timeout = jiffies + HZ; /* vpu wait timeout to 1sec */ + int product_code = 0; + + for (core = 0; core < MAX_NUM_VPU_CORE; core++) { + if (s_bit_firmware_info[core].size == 0) + continue; + product_code = ReadVpuRegister(VPU_PRODUCT_CODE_REGISTER, core); + + if (PRODUCT_CODE_W_SERIES(product_code)) { + while (ReadVpuRegister(W4_VPU_BUSY_STATUS, core)) { + if (time_after(jiffies, timeout)) { + DPRINTK("%s SLEEP_VPU BUSY timeout", DEV_NAME); + goto DONE_SUSPEND; + } + } + Wave5BitIssueCommand(W4_CMD_SLEEP_VPU); + + while (ReadVpuRegister(W4_VPU_BUSY_STATUS, core)) { + if (time_after(jiffies, timeout)) { + DPRINTK("%s SLEEP_VPU BUSY timeout", DEV_NAME); + goto DONE_SUSPEND; + } + } + if (ReadVpuRegister(W4_RET_SUCCESS, core) == 0) { + DPRINTK("%s SLEEP_VPU failed [0x%x]", DEV_NAME, ReadVpuRegister(W4_RET_FAIL_REASON, core)); + goto DONE_SUSPEND; + } + } else { + while (ReadVpuRegister(BIT_BUSY_FLAG, core)) { + if (time_after(jiffies, timeout)) + goto DONE_SUSPEND; + } + + for (i = 0; i < 64; i++) + s_vpu_reg_store[core][i] = ReadVpuRegister(BIT_BASE+(0x100+(i * 4)), core); + } +#endif /* end of DISABLE_ORIGIN_SUSPEND */ + } + + ve_pd_power_off(0); + ve_pd_power_off(1); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; + +#ifndef DISABLE_ORIGIN_SUSPEND +DONE_SUSPEND: +#endif + + ve_pd_power_off(0); + ve_pd_power_off(1); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return -EAGAIN; +} + +static int vpu_resume(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + ve_pd_power_on(0); + ve_pd_power_on(1); + + //RTK wrapper + ve1_wrapper_setup((1 << 1) | 1); + +#ifdef DISABLE_ORIGIN_SUSPEND +#else /* else of DISABLE_ORIGIN_SUSPEND */ + int i; + int core; + int regVal; + int product_code = 0; + unsigned long timeout = jiffies + HZ; /* vpu wait timeout to 1sec */ + unsigned long code_base; + unsigned long stack_base; + u32 val; + u32 code_size; + u32 stack_size; + u32 remap_size; + u32 hwOption = 0; + + for (core = 0; core < MAX_NUM_VPU_CORE; core++) { + + if (s_bit_firmware_info[core].size == 0) { + continue; + } + + product_code = ReadVpuRegister(VPU_PRODUCT_CODE_REGISTER, core); + + if (PRODUCT_CODE_W_SERIES(product_code)) { + + code_base = s_common_memory.phys_addr; + /* ALIGN TO 4KB */ + code_size = (W4_MAX_CODE_BUF_SIZE&~0xfff); + if (code_size < s_bit_firmware_info[core].size*2) { + goto DONE_WAKEUP; + } + stack_base = code_base + code_size; + stack_size = WAVE5_STACK_SIZE; + + /*---- LOAD BOOT CODE*/ + //for (i = 0; i < 512; i++) { + // val = s_bit_firmware_info[core].bit_code[i]; + // WriteVpu(code_base+(i*4), val); + //} + + regVal = 0; + WriteVpuRegister(W4_PO_CONF, regVal, core); + + /* Reset All blocks */ + regVal = 0x7ffffff; + WriteVpuRegister(W4_RESET_REQ, regVal, core); /*Reset All blocks*/ + + /* Waiting reset done */ + while (ReadVpuRegister(W4_RESET_STATUS, core)) { + if (time_after(jiffies, timeout)) + goto DONE_WAKEUP; + } + + WriteVpuRegister(W4_RESET_REQ, 0, core); + + /* remap page size */ + remap_size = (code_size >> 12) & 0x1ff; + regVal = 0x80000000 | (W4_REMAP_CODE_INDEX<<12) | (0 << 16) | (1<<11) | remap_size; + WriteVpuRegister(W4_VPU_REMAP_CTRL, regVal, core); + WriteVpuRegister(W4_VPU_REMAP_VADDR, 0x00000000, core); /* DO NOT CHANGE! */ + WriteVpuRegister(W4_VPU_REMAP_PADDR, code_base, core); + WriteVpuRegister(W4_ADDR_CODE_BASE, code_base, core); + WriteVpuRegister(W4_CODE_SIZE, code_size, core); + WriteVpuRegister(W4_CODE_PARAM, 0, core); + WriteVpuRegister(W4_INIT_VPU_TIME_OUT_CNT, timeout, core); + + /* Stack */ + WriteVpuRegister(W4_ADDR_STACK_BASE, stack_base, core); + WriteVpuRegister(W4_STACK_SIZE, stack_size, core); + WriteVpuRegister(W4_HW_OPTION, hwOption, core); + + /* Interrupt */ + regVal = (1< +#include + +#define SUPPORT_MULTI_INST_INTR +#define SUPPORT_MULTI_INST_INTR_ERROR_CHECK +#define USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + +#define VDI_IOCTL_MAGIC 'V' +#define VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(VDI_IOCTL_MAGIC, 0) +#define VDI_IOCTL_FREE_PHYSICALMEMORY _IO(VDI_IOCTL_MAGIC, 1) +#define VDI_IOCTL_WAIT_INTERRUPT _IO(VDI_IOCTL_MAGIC, 2) +#define VDI_IOCTL_SET_CLOCK_GATE _IO(VDI_IOCTL_MAGIC, 3) +#define VDI_IOCTL_RESET _IO(VDI_IOCTL_MAGIC, 4) +#define VDI_IOCTL_GET_INSTANCE_POOL _IO(VDI_IOCTL_MAGIC, 5) +#define VDI_IOCTL_GET_COMMON_MEMORY _IO(VDI_IOCTL_MAGIC, 6) +#define VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(VDI_IOCTL_MAGIC, 8) +#define VDI_IOCTL_OPEN_INSTANCE _IO(VDI_IOCTL_MAGIC, 9) +#define VDI_IOCTL_CLOSE_INSTANCE _IO(VDI_IOCTL_MAGIC, 10) +#define VDI_IOCTL_GET_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 11) +#define VDI_IOCTL_GET_REGISTER_INFO _IO(VDI_IOCTL_MAGIC, 12) + +/* RTK ioctl */ +#define VDI_IOCTL_SET_RTK_CLK_GATING _IO(VDI_IOCTL_MAGIC, 16) +#define VDI_IOCTL_SET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 17) +#define VDI_IOCTL_GET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 18) +#define VDI_IOCTL_GET_RTK_SUPPORT_TYPE _IO(VDI_IOCTL_MAGIC, 19) +#define VDI_IOCTL_GET_RTK_ASIC_REVISION _IO(VDI_IOCTL_MAGIC, 20) +#define VDI_IOCTL_SET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 21) +#define VDI_IOCTL_GET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 22) +#define VDI_IOCTL_SET_RTK_DOVI_FLAG _IO(VDI_IOCTL_MAGIC, 23) +#define VDI_IOCTL_GET_TOTAL_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 24) +#define VDI_IOCTL_GET_RTK_DCSYS_INFO _IO(VDI_IOCTL_MAGIC, 25) + +#define VE_PLL_SYSH 0x000 +#define VE_PLL_VE1 0x001 +#define VE_PLL_VE2 0x010 + +typedef struct vpudrv_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; /* kernel logical address in use kernel */ + unsigned long virt_addr; /* virtual user space address */ + unsigned int mem_type; /* RTK, for protect memory */ +} vpudrv_buffer_t; + +typedef struct vpu_bit_firmware_info_t { + unsigned int size; /* size of this structure*/ + unsigned int core_idx; + unsigned long reg_base_offset; + unsigned short bit_code[512]; +} vpu_bit_firmware_info_t; + +typedef struct vpu_clock_info_t{ + unsigned int core_idx; + unsigned int enable; + unsigned int value; +} vpu_clock_info_t; + +typedef struct vpudrv_inst_info_t { + unsigned int core_idx; + unsigned int inst_idx; + int inst_open_count; /* for output only*/ +} vpudrv_inst_info_t; + +typedef struct vpudrv_intr_info_t { + unsigned int core_idx; + unsigned int timeout; + int intr_reason; +#ifdef SUPPORT_MULTI_INST_INTR + int intr_inst_index; +#endif +} vpudrv_intr_info_t; + +typedef struct vpudrv_dovi_info_t{ + unsigned int core_idx; + unsigned int inst_idx; + unsigned int enable; +} vpudrv_dovi_info_t; +#endif diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.c b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.c new file mode 100644 index 000000000000..3bcefdfc9b96 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.c @@ -0,0 +1,129 @@ +/* + * ve1_pm.c - ve1 power management + * + * Copyright (c) 2019 Realtek Semiconductor Corporation + * + * Author: + * Cheng-Yu Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ve1_pm.h" + +#define RTK_ID_VE1 0 +#define RTK_ID_VE3 1 +#define RTK_ID_MAX 2 + +struct ve_pm_data { + struct device *dev; + struct device *pd_dev; +}; + +static struct ve_pm_data ve_pm_data[RTK_ID_MAX]; + +#define get_ve_pm_data_by_id(id) (&ve_pm_data[(id)]) + +int ve_pd_power_on(int id) +{ + struct ve_pm_data *data = get_ve_pm_data_by_id(id); + + pr_debug("%s: id=%d\n", __func__, id); + + if (WARN_ON_ONCE(!data->pd_dev)) + return -ENODEV; + + trace_rtk_pm_event(dev_name(data->pd_dev), "power_on"); + + pm_runtime_get_sync(data->pd_dev); + return 0; +} + +int ve_pd_power_off(int id) +{ + struct ve_pm_data *data = get_ve_pm_data_by_id(id); + + pr_debug("%s: id=%d\n", __func__, id); + + if (WARN_ON_ONCE(!data->pd_dev)) + return -ENODEV; + + trace_rtk_pm_event(dev_name(data->pd_dev), "power_off_async"); + + pm_runtime_mark_last_busy(data->pd_dev); + pm_runtime_put_autosuspend(data->pd_dev); + return 0; +} + +int ve_pd_reset_control_reset(int id) +{ + return -EINVAL; +} + +static void ve_pd_init_pd_dev(struct device *dev, int index) +{ + struct ve_pm_data *data = get_ve_pm_data_by_id(index); + + data->dev = dev; + data->pd_dev = dev_pm_domain_attach_by_id(dev, index); + if (IS_ERR_OR_NULL(data->pd_dev)) { + data->pd_dev = NULL; + dev_warn(dev, "failed to get pm domain %d\n", index); + return; + } + + /* setup */ + pm_runtime_use_autosuspend(data->pd_dev); + pm_runtime_set_autosuspend_delay(data->pd_dev, 15000); + pm_runtime_set_active(data->pd_dev); + + /* power off */ + trace_rtk_pm_event(dev_name(data->pd_dev), "request_power_off"); + pm_runtime_get_sync(data->pd_dev); + pm_runtime_mark_last_busy(data->pd_dev); + pm_runtime_put_autosuspend(data->pd_dev); + trace_rtk_pm_event(dev_name(data->pd_dev), "request_power_off_completed"); +} + +static void ve_pd_fini_pd_dev(int index) +{ + struct ve_pm_data *data = get_ve_pm_data_by_id(index); + + dev_pm_domain_detach(data->pd_dev, 1); +} + +int ve_pd_init(struct device *dev) +{ + ve_pd_init_pd_dev(dev, RTK_ID_VE1); + ve_pd_init_pd_dev(dev, RTK_ID_VE3); + return 0; +} + +void ve_pd_exit(struct device *dev) +{ + ve_pd_fini_pd_dev(RTK_ID_VE1); + ve_pd_fini_pd_dev(RTK_ID_VE3); +} + diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.h b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.h new file mode 100644 index 000000000000..a478abcb3715 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1_pm.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Realtek Semiconductor Corporation + * + * Author: + * Cheng-Yu Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#ifndef __VE1_PM_H +#define __VE1_PM_H + +struct device; + +int ve_pd_init(struct device *dev); +void ve_pd_exit(struct device *dev); +int ve_pd_power_on(int id); +int ve_pd_power_off(int id); +int ve_pd_reset_control_reset(int id); + + +#endif diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1config.h b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1config.h new file mode 100644 index 000000000000..44ff5e24e86c --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/ve1config.h @@ -0,0 +1,110 @@ +/* ========================================================================= + * This file is a part of VE1 Reference API project + * ----------------------------------------------------------------------------- + * + * This confidential and proprietary software may be used only + * as authorized by a licensing agreement from Realtek Inc. + * In the event of publication, the following notice is applicable: + * + * (C) COPYRIGHT 2006 - 2011 REALTEK INC. + * ALL RIGHTS RESERVED + * + * The entire notice above must be reproduced on all authorized + * copies. + * This file should be modified by some customers according to their SOC configuration. + * ========================================================================= + */ + +#ifndef _VPU_CONFIG_H_ +#define _VPU_CONFIG_H_ + +#define BODA7503_CODE 0x7503 +#define CODA7542_CODE 0x7542 +#define BODA950_CODE 0x9500 +#define CODA960_CODE 0x9600 +#define CODA980_CODE 0x9800 +#define WAVE320_CODE 0x3200 +#define WAVE410_CODE 0x4100 /* Wave410 version 1: Single vcore */ +#define WAVE4102_CODE 0x4102 /* Wave410 version 2: Multi vcore */ +#define WAVE420_CODE 0x4200 /* Wave420 */ +#define WAVE420L_CODE 0x4201 /* Wave420 */ +#define WAVE412_CODE 0x4120 +#define WAVE510_CODE 0x5100 +#define WAVE512_CODE 0x5120 +#define WAVE520_CODE 0x5200 + +#define PRODUCT_CODE_W_SERIES(x) (x == WAVE420L_CODE || x == WAVE510_CODE || x == WAVE512_CODE || x == WAVE520_CODE) +#define MAX_INST_HANDLE_SIZE (32*1024) +#define MAX_NUM_INSTANCE 4 +#define MAX_NUM_VPU_CORE 2 +#define MAX_NUM_VCORE 1 + +#define MAX_ENC_AVC_PIC_WIDTH 4096 +#define MAX_ENC_AVC_PIC_HEIGHT 2304 +#define MAX_ENC_PIC_WIDTH 4096 +#define MAX_ENC_PIC_HEIGHT 2304 +#define MIN_ENC_PIC_WIDTH 96 +#define MIN_ENC_PIC_HEIGHT 16 + +/* for WAVE420 */ +#define W4_MIN_ENC_PIC_WIDTH 256 +#define W4_MIN_ENC_PIC_HEIGHT 128 +#define W4_MAX_ENC_PIC_WIDTH 8192 +#define W4_MAX_ENC_PIC_HEIGHT 8192 + +#define MAX_DEC_PIC_WIDTH 4096 +#define MAX_DEC_PIC_HEIGHT 2304 + +/* Application specific configuration */ +#define VPU_ENC_TIMEOUT 5000 +#define VPU_DEC_TIMEOUT 10000 +#define VPU_BUSY_CHECK_TIMEOUT 5000 + +/* codec specific configuration */ +/* it can be set to 1 to handle reordering DPB in host side. */ +#define VPU_REORDER_ENABLE 1 +/* + * [default 1 for BW checking with RTKViedo Conformance] 0 (chroma separate mode), 1 (chroma interleave mode) + * if the type of tiledmap uses the kind of MB_RASTER_MAP. must set to enable CBCR_INTERLEAVE + */ +#define CBCR_INTERLEAVE 1 +#define VPU_ENABLE_BWB 1 +#define VPU_REPORT_USERDATA 0 + +#define HOST_ENDIAN VDI_128BIT_LITTLE_ENDIAN +#define VPU_FRAME_ENDIAN HOST_ENDIAN +#define VPU_STREAM_ENDIAN HOST_ENDIAN +#define VPU_USER_DATA_ENDIAN HOST_ENDIAN +#define DRAM_BUS_WIDTH 16 + +/************************************************************************/ +/* VPU COMMON MEMORY */ +/************************************************************************/ +#define SIZE_COMMON (2*1024*1024) + +/*=====4. VPU REPORT MEMORY ======================*/ +#define SIZE_REPORT_BUF (0x10000) + +#define STREAM_END_SIZE 0 +#define STREAM_END_SET_FLAG 0 +#define STREAM_END_CLEAR_FLAG -1 + +#define USE_BIT_INTERNAL_BUF 1 +#define USE_IP_INTERNAL_BUF 1 +#define USE_DBKY_INTERNAL_BUF 1 +#define USE_DBKC_INTERNAL_BUF 1 +#define USE_OVL_INTERNAL_BUF 1 +#define USE_BTP_INTERNAL_BUF 1 +#define USE_ME_INTERNAL_BUF 1 + +/* WAVE410 only */ +#define USE_BPU_INTERNAL_BUF 1 +#define USE_VCE_IP_INTERNAL_BUF 1 +#define USE_VCE_LF_ROW_INTERNAL_BUF 1 + +/* WAVE420 only */ +#define USE_IMD_INTERNAL_BUF 1 +#define USE_RDO_INTERNAL_BUF 1 +#define USE_LF_INTERNAL_BUF 1 + +#endif /* _VPU_CONFIG_H_ */ diff --git a/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/vmm.h b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/vmm.h new file mode 100644 index 000000000000..5ad579251102 --- /dev/null +++ b/drivers/soc/realtek/rtd13xx/rtk_ve/ve1/vmm.h @@ -0,0 +1,634 @@ +/** + vmm.h + + memory allocator for VE + + Copyright (C) 2006 - 2013 REALTEK INC. + + This 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. + + This 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 this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + +*/ + +#ifndef __RTK_VIDEO_MEMORY_MANAGEMENT_H__ +#define __RTK_VIDEO_MEMORY_MANAGEMENT_H__ + +typedef struct _video_mm_info_struct { + unsigned long total_pages; + unsigned long alloc_pages; + unsigned long free_pages; + unsigned long page_size; +} vmem_info_t; + +typedef unsigned long long vmem_key_t; + +#define VMEM_PAGE_SIZE (16*1024) +#define MAKE_KEY(_a, _b) (((vmem_key_t)_a)<<32 | _b) +#define KEY_TO_VALUE(_key) (_key>>32) + +typedef struct page_struct { + int pageno; + unsigned long addr; + int used; + int alloc_pages; + int first_pageno; +} page_t; + +typedef struct avl_node_struct { + vmem_key_t key; + int height; + page_t *page; + struct avl_node_struct *left; + struct avl_node_struct *right; +} avl_node_t; + +typedef struct _video_mm_struct { + avl_node_t *free_tree; + avl_node_t *alloc_tree; + page_t *page_list; + int num_pages; + unsigned long base_addr; + unsigned long mem_size; + int free_page_count; + int alloc_page_count; +} video_mm_t; + +#define VMEM_P_ALLOC(_x) vmalloc(_x) +#define VMEM_P_FREE(_x) vfree(_x) + +#define VMEM_ASSERT(_exp) if (!(_exp)) { printk(KERN_INFO "VMEM_ASSERT at %s:%d\n", __FILE__, __LINE__); /*while(1);*/ +#define VMEM_HEIGHT(_tree) (_tree == NULL ? -1 : _tree->height) + +#define MAX(_a, _b) (_a >= _b ? _a : _b) + +typedef enum { + LEFT, + RIGHT +} rotation_dir_t; + +typedef struct avl_node_data_struct { + int key; + page_t *page; +} avl_node_data_t; + +static avl_node_t* make_avl_node( vmem_key_t key, page_t *page) +{ + avl_node_t *node = (avl_node_t *)VMEM_P_ALLOC(sizeof(avl_node_t)); + node->key = key; + node->page = page; + node->height = 0; + node->left = NULL; + node->right = NULL; + + return node; +} + +static int get_balance_factor(avl_node_t *tree) +{ + int factor = 0; + if (tree) { + factor = VMEM_HEIGHT(tree->right) - VMEM_HEIGHT(tree->left); + } + + return factor; +} + +/* + * Left Rotation + * + * A B + * \ / \ + * B => A C + * / \ \ + * D C D + * + */ +static avl_node_t* rotation_left(avl_node_t *tree) +{ + avl_node_t *rchild; + avl_node_t *lchild; + + if (tree == NULL) + return NULL; + + rchild = tree->right; + if (rchild == NULL) { + return tree; + } + + lchild = rchild->left; + rchild->left = tree; + tree->right = lchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + rchild->height = MAX(VMEM_HEIGHT(rchild->left), VMEM_HEIGHT(rchild->right)) + 1; + + return rchild; +} + + +/* + * Reft Rotation + * + * A B + * \ / \ + * B => D A + * / \ / + * D C C + * + */ +static avl_node_t *rotation_right(avl_node_t *tree) +{ + avl_node_t *rchild; + avl_node_t *lchild; + + if (tree == NULL) + return NULL; + + lchild = tree->left; + if (lchild == NULL) + return NULL; + + rchild = lchild->right; + lchild->right = tree; + tree->left = rchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + lchild->height = MAX(VMEM_HEIGHT(lchild->left), VMEM_HEIGHT(lchild->right)) + 1; + + return lchild; +} + +static avl_node_t *do_balance(avl_node_t *tree) +{ + int bfactor = 0, child_bfactor; /* balancing factor */ + + bfactor = get_balance_factor(tree); + + if (bfactor >= 2) { + child_bfactor = get_balance_factor(tree->right); + if (child_bfactor == 1 || child_bfactor == 0) { + tree = rotation_left(tree); + } else if (child_bfactor == -1) { + tree->right = rotation_right(tree->right); + tree = rotation_left(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } else if (bfactor <= -2) { + child_bfactor = get_balance_factor(tree->left); + if (child_bfactor == -1 || child_bfactor == 0) { + tree = rotation_right(tree); + } else if (child_bfactor == 1) { + tree->left = rotation_left(tree->left); + tree = rotation_right(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } + + return tree; +} + +static avl_node_t *unlink_end_node(avl_node_t *tree, int dir, avl_node_t **found_node) +{ + avl_node_t *node; + *found_node = NULL; + + if (tree == NULL) + return NULL; + + if (dir == LEFT) { + if (tree->left == NULL) { + *found_node = tree; + return NULL; + } + } else { + if (tree->right == NULL) { + *found_node = tree; + return NULL; + } + } + + if (dir == LEFT) { + node = tree->left; + tree->left = unlink_end_node(tree->left, LEFT, found_node); + if (tree->left == NULL) { + tree->left = (*found_node)->right; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } else { + node = tree->right; + tree->right = unlink_end_node(tree->right, RIGHT, found_node); + if (tree->right == NULL) { + tree->right = (*found_node)->left; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return do_balance(tree); +} + + +static avl_node_t *avltree_insert(avl_node_t *tree, vmem_key_t key, page_t *page) +{ + if (tree == NULL) { + tree = make_avl_node(key, page); + } else { + if (key >= tree->key) { + tree->right = avltree_insert(tree->right, key, page); + } else { + tree->left = avltree_insert(tree->left, key, page); + } + } + + tree = do_balance(tree); + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return tree; +} + +static avl_node_t *do_unlink(avl_node_t *tree) +{ + avl_node_t *node; + avl_node_t *end_node; + + node = unlink_end_node(tree->right, LEFT, &end_node); + if (node) { + tree->right = node; + } else { + node = unlink_end_node(tree->left, RIGHT, &end_node); + if (node) + tree->left = node; + } + + if (node == NULL) { + node = tree->right ? tree->right : tree->left; + end_node = node; + } + + if (end_node) { + end_node->left = (tree->left != end_node) ? tree->left : end_node->left; + end_node->right = (tree->right != end_node) ? tree->right : end_node->right; + end_node->height = MAX(VMEM_HEIGHT(end_node->left), VMEM_HEIGHT(end_node->right)) + 1; + } + + tree = end_node; + + return tree; +} + +static avl_node_t *avltree_remove(avl_node_t *tree, avl_node_t **found_node, vmem_key_t key) +{ + *found_node = NULL; + if (tree == NULL) { + printk(KERN_INFO "failed to find key %d\n", (int)key); + return NULL; + } + + if (key == tree->key) { + *found_node = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = avltree_remove(tree->right, found_node, key); + } else { + tree->left = avltree_remove(tree->left, found_node, key); + } + + if (tree) + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +void avltree_free(avl_node_t *tree) +{ + if (tree == NULL) + return; + if (tree->left == NULL && tree->right == NULL) { + VMEM_P_FREE(tree); + return; + } + + avltree_free(tree->left); + tree->left = NULL; + avltree_free(tree->right); + tree->right = NULL; + VMEM_P_FREE(tree); +} + +static avl_node_t *remove_approx_value(avl_node_t *tree, avl_node_t **found, vmem_key_t key) +{ + *found = NULL; + if (tree == NULL) { + return NULL; + } + + if (key == tree->key) { + *found = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = remove_approx_value(tree->right, found, key); + } else { + tree->left = remove_approx_value(tree->left, found, key); + if (*found == NULL) { + *found = tree; + tree = do_unlink(tree); + } + } + if (tree) + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +static void set_blocks_free(video_mm_t *mm, int pageno, int npages) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t *page; + page_t *last_page; + + VMEM_ASSERT(npages); + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i = pageno; i <= last_pageno; i++) { + mm->page_list[i].used = 0; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->free_tree = avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page); +} + +static void set_blocks_alloc(video_mm_t *mm, int pageno, int npages) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t *page; + page_t *last_page; + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i = pageno; i <= last_pageno; i++) { + mm->page_list[i].used = 1; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->alloc_tree = avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page); +} + + +int vmem_init(video_mm_t *mm, unsigned long addr, unsigned long size) +{ + int i; + + if (NULL == mm) + return -1; + + mm->base_addr = (addr+(VMEM_PAGE_SIZE-1))&~(VMEM_PAGE_SIZE-1); + mm->mem_size = size&~VMEM_PAGE_SIZE; + mm->num_pages = mm->mem_size/VMEM_PAGE_SIZE; + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = mm->num_pages; + mm->alloc_page_count = 0; + mm->page_list = (page_t *)VMEM_P_ALLOC(mm->num_pages*sizeof(page_t)); + if (mm->page_list == NULL) { + printk(KERN_ERR "%s:%d failed to kmalloc(%d)\n", __func__, __LINE__, mm->num_pages*sizeof(page_t)); + return -1; + } + + for (i = 0; i < mm->num_pages; i++) { + mm->page_list[i].pageno = i; + mm->page_list[i].addr = mm->base_addr + i * VMEM_PAGE_SIZE; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].used = 0; + mm->page_list[i].first_pageno = -1; + } + + set_blocks_free(mm, 0, mm->num_pages); + + return 0; +} + +int vmem_exit(video_mm_t *mm) +{ + if (mm == NULL) { + printk(KERN_INFO "vmem_exit: invalid handle\n"); + return -1; + } + + if (mm->free_tree) { + avltree_free(mm->free_tree); + } + if (mm->alloc_tree) { + avltree_free(mm->alloc_tree); + } + + if (mm->page_list) { + VMEM_P_FREE(mm->page_list); + mm->page_list = NULL; + } + + mm->base_addr = 0; + mm->mem_size = 0; + mm->num_pages = 0; + mm->page_list = NULL; + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = 0; + mm->alloc_page_count = 0; + return 0; +} + +unsigned long vmem_alloc(video_mm_t *mm, int size, unsigned long pid) +{ + avl_node_t *node; + page_t *free_page; + int npages, free_size; + int alloc_pageno; + unsigned long ptr; + + if (mm == NULL) { + printk(KERN_INFO "vmem_alloc: invalid handle\n"); + return -1; + } + + if (size <= 0) + return -1; + + npages = (size + VMEM_PAGE_SIZE - 1)/VMEM_PAGE_SIZE; + + mm->free_tree = remove_approx_value(mm->free_tree, &node, MAKE_KEY(npages, 0)); + if (node == NULL) { + return -1; + } + free_page = node->page; + free_size = KEY_TO_VALUE(node->key); + + alloc_pageno = free_page->pageno; + set_blocks_alloc(mm, alloc_pageno, npages); + if (npages != free_size) { + int free_pageno = alloc_pageno + npages; + set_blocks_free(mm, free_pageno, (free_size-npages)); + } + + VMEM_P_FREE(node); + + ptr = mm->page_list[alloc_pageno].addr; + mm->alloc_page_count += npages; + mm->free_page_count -= npages; + + + return ptr; +} + +int vmem_free(video_mm_t *mm, unsigned long ptr, unsigned long pid) +{ + unsigned long addr; + avl_node_t *found; + page_t *page; + int pageno, prev_free_pageno, next_free_pageno; + int prev_size, next_size; + int merge_page_no, merge_page_size, free_page_size; + + + if (mm == NULL) { + printk(KERN_INFO "vmem_free: invalid handle\n"); + return -1; + } + + addr = ptr; + + mm->alloc_tree = avltree_remove(mm->alloc_tree, &found, MAKE_KEY(addr, 0)); + if (found == NULL) { + printk(KERN_INFO "vmem_free: 0x%08x not found\n", (int)addr); + VMEM_ASSERT(0); + return -1; + } + + /* find previous free block */ + page = found->page; + pageno = page->pageno; + free_page_size = page->alloc_pages; + prev_free_pageno = pageno-1; + prev_size = -1; + if (prev_free_pageno >= 0) { + if (mm->page_list[prev_free_pageno].used == 0) { + prev_free_pageno = mm->page_list[prev_free_pageno].first_pageno; + prev_size = mm->page_list[prev_free_pageno].alloc_pages; + } + } + + /* find next free block */ + next_free_pageno = pageno + page->alloc_pages; + next_free_pageno = (next_free_pageno == mm->num_pages) ? -1 : next_free_pageno; + next_size = -1; + if (next_free_pageno >= 0) { + if (mm->page_list[next_free_pageno].used == 0) { + next_size = mm->page_list[next_free_pageno].alloc_pages; + } + } + VMEM_P_FREE(found); + + /* merge */ + merge_page_no = page->pageno; + merge_page_size = page->alloc_pages; + if (prev_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(prev_size, prev_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_no = found->page->pageno; + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + if (next_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(next_size, next_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + + page->alloc_pages = 0; + page->first_pageno = -1; + + set_blocks_free(mm, merge_page_no, merge_page_size); + + mm->alloc_page_count -= free_page_size; + mm->free_page_count += free_page_size; + + return 0; +} + +int vmem_get_info(video_mm_t *mm, vmem_info_t *info) +{ + if (mm == NULL) { + printk(KERN_INFO "vmem_get_info: invalid handle\n"); + return -1; + } + + if (info == NULL) { + return -1; + } + + info->total_pages = mm->num_pages; + info->alloc_pages = mm->alloc_page_count; + info->free_pages = mm->free_page_count; + info->page_size = VMEM_PAGE_SIZE; + + return 0; +} + +#endif /* __RTK_VIDEO_MEMORY_MANAGEMENT_H__ */ diff --git a/drivers/soc/realtek/rtd16xxb/Makefile b/drivers/soc/realtek/rtd16xxb/Makefile new file mode 100644 index 000000000000..d1ad5041724a --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_RTD16XXB_RTK_CODEC) += rtk_ve/ diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/Makefile b/drivers/soc/realtek/rtd16xxb/rtk_ve/Makefile new file mode 100644 index 000000000000..dd892363a0da --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Realtek codec drivers. +# +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/ +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/rtk/inc +obj-$(CONFIG_RTD16XXB_RTK_CODEC) += puwrap.o +obj-$(CONFIG_RTD16XXB_VE1_CODEC) += ve1/ +obj-$(CONFIG_RTD16XXB_IMAGE_CODEC) += jdi/ diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/Makefile b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/Makefile new file mode 100644 index 000000000000..4545fa59e0a5 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/Makefile @@ -0,0 +1,6 @@ +# rtk_jcodec + +obj-$(CONFIG_RTD16XXB_IMAGE_CODEC) += jpu.o +ifdef CONFIG_COMPAT +obj-$(CONFIG_RTD16XXB_IMAGE_CODEC) += compat_jpu.o +endif diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.c b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.c new file mode 100644 index 000000000000..fb5d79f7087c --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.c @@ -0,0 +1,324 @@ +/* + * drivers/soc/realtek/rtd129x/rtk_ve/jdi/compat_jpu.h + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "jpu.h" +#include "compat_jpu.h" + +/* See drivers/soc/realtek/rtd129x/rtk_ve/jdi/jpu.h for the definition of these structs */ +typedef struct compat_jpudrv_buffer_t { + compat_uint_t size; + compat_ulong_t phys_addr; + compat_ulong_t base; /* kernel logical address in use kernel */ + compat_ulong_t virt_addr; /* virtual user space address */ +} compat_jpudrv_buffer_t; + +typedef struct compat_jpudrv_intr_info_t { + compat_uint_t timeout; + compat_int_t intr_reason; +} compat_jpudrv_intr_info_t; + +typedef struct compat_jpudrv_dovi_info_t{ + compat_uint_t inst_idx; + compat_uint_t enable; +} compat_jpudrv_dovi_info_t; + +#define COMPAT_JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(JDI_IOCTL_MAGIC, 0) +#define COMPAT_JDI_IOCTL_FREE_PHYSICALMEMORY _IO(JDI_IOCTL_MAGIC, 1) +#define COMPAT_JDI_IOCTL_WAIT_INTERRUPT _IO(JDI_IOCTL_MAGIC, 2) +#define COMPAT_JDI_IOCTL_GET_INSTANCE_POOL _IO(JDI_IOCTL_MAGIC, 5) +#define COMPAT_JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(JDI_IOCTL_MAGIC, 6) +#define COMPAT_JDI_IOCTL_GET_REGISTER_INFO _IO(JDI_IOCTL_MAGIC, 11) +#define COMPAT_JDI_IOCTL_GET_BONDING_INFO _IO(JDI_IOCTL_MAGIC, 13) +#define COMPAT_JDI_IOCTL_SET_RTK_DOVI_FLAG _IO(JDI_IOCTL_MAGIC, 14) + +static int compat_get_jpu_buffer_data( + compat_jpudrv_buffer_t __user *data32, + jpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + int err; + + err = get_user(s, &data32->size); + err |= put_user(s, &data->size); + err |= get_user(p, &data32->phys_addr); + err |= put_user(p, &data->phys_addr); + err |= get_user(b, &data32->base); + err |= put_user(b, &data->base); + err |= get_user(v, &data32->virt_addr); + err |= put_user(v, &data->virt_addr); + + return err; +} + +static int compat_get_jpu_intr_info_data( + compat_jpudrv_intr_info_t __user *data32, + jpudrv_intr_info_t __user *data) +{ + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(t, &data32->timeout); + err |= put_user(t, &data->timeout); + err |= get_user(i, &data32->intr_reason); + err |= put_user(i, &data->intr_reason); + + return err; +} + +static int compat_get_jpu_dovi_info( + compat_jpudrv_dovi_info_t __user *data32, + jpudrv_dovi_info_t __user *data) +{ + compat_uint_t e; + compat_uint_t i; + int err; + + err |= get_user(i, &data32->inst_idx); + err |= put_user(i, &data->inst_idx); + err |= get_user(e, &data32->enable); + err |= put_user(e, &data->enable); + + return err; +} + +static int compat_put_jpu_buffer_data( + compat_jpudrv_buffer_t __user *data32, + jpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + int err; + + err = get_user(s, &data->size); + err |= put_user(s, &data32->size); + err |= get_user(p, &data->phys_addr); + err |= put_user(p, &data32->phys_addr); + err |= get_user(b, &data->base); + err |= put_user(b, &data32->base); + err |= get_user(v, &data->virt_addr); + err |= put_user(v, &data32->virt_addr); + + return err; +} + +static int compat_put_jpu_intr_info_data( + compat_jpudrv_intr_info_t __user *data32, + jpudrv_intr_info_t __user *data) +{ + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(t, &data->timeout); + err |= put_user(t, &data32->timeout); + err |= get_user(i, &data->intr_reason); + err |= put_user(i, &data32->intr_reason); + + return err; +} + +static int compat_put_jpu_dovi_info( + compat_jpudrv_dovi_info_t __user *data32, + jpudrv_dovi_info_t __user *data) +{ + compat_uint_t i; + compat_uint_t e; + int err; + + err |= get_user(i, &data->inst_idx); + err |= put_user(i, &data32->inst_idx); + err |= get_user(e, &data->enable); + err |= put_user(e, &data32->enable); + + return err; +} + +long compat_jpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + + if (!filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) + { + case COMPAT_JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_FREE_PHYSICALMEMORY: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_FREE_PHYSICALMEMORY, (unsigned long)data); + } + + case COMPAT_JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_WAIT_INTERRUPT: + { + compat_jpudrv_intr_info_t __user *data32; + jpudrv_intr_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_intr_info_data(data32, data); + if (err) + return err; + + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_WAIT_INTERRUPT, (unsigned long)data); + err = compat_put_jpu_intr_info_data(data32, data); + return ret ? ret : err; + } + + case JDI_IOCTL_ENABLE_INTERRUPT: + case JDI_IOCTL_SET_CLOCK_GATE: + case JDI_IOCTL_OPEN_INSTANCE: + case JDI_IOCTL_CLOSE_INSTANCE: + case JDI_IOCTL_GET_INSTANCE_NUM: + case JDI_IOCTL_RESET: + case JDI_IOCTL_SET_CLOCK_ENABLE: + { + return filp->f_op->unlocked_ioctl(filp, cmd, + (unsigned long)compat_ptr(arg)); + } + + case COMPAT_JDI_IOCTL_GET_INSTANCE_POOL: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_INSTANCE_POOL, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_GET_REGISTER_INFO: + case COMPAT_JDI_IOCTL_GET_BONDING_INFO: + { + compat_jpudrv_buffer_t __user *data32; + jpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_buffer_data(data32, data); + if (err) + return err; + if (cmd == COMPAT_JDI_IOCTL_GET_REGISTER_INFO) + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_REGISTER_INFO, (unsigned long)data); + else + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_GET_BONDING_INFO, (unsigned long)data); + err = compat_put_jpu_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_JDI_IOCTL_SET_RTK_DOVI_FLAG: + { + compat_jpudrv_dovi_info_t __user *data32; + jpudrv_dovi_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_jpu_dovi_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, JDI_IOCTL_SET_RTK_DOVI_FLAG, (unsigned long)data); + err = compat_put_jpu_dovi_info(data32, data); + return ret ? ret : err; + } + + default: + { + printk(KERN_ERR "[COMPAT JPU]No such IOCTL, cmd is %d\n", cmd); + return -ENOIOCTLCMD; + } + } +} + diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.h new file mode 100644 index 000000000000..2d920c966187 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/compat_jpu.h @@ -0,0 +1,31 @@ +/* + + * drivers/soc/realtek/rtd129x/rtk_ve/jdi/compat_jpu.h + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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_COMPAT_JPU_H +#define _LINUX_COMPAT_JPU_H + +#if IS_ENABLED(CONFIG_COMPAT) + +long compat_jpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +#define compat_jpu_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_JPU_H */ + diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jmm.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jmm.h new file mode 100644 index 000000000000..e54a2284a8a5 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jmm.h @@ -0,0 +1,647 @@ +#ifndef __JPU_MM_H__ +#define __JPU_MM_H__ + + +typedef unsigned long long jmem_key_t; + +#define JMEM_PAGE_SIZE (16*1024) +#define MAKE_KEY(_a, _b) (((jmem_key_t)_a)<<32 | _b) +#define KEY_TO_VALUE(_key) (_key>>32) + +typedef struct page_struct { + int pageno; + unsigned long addr; + int used; + int alloc_pages; + int first_pageno; +} page_t; + + +typedef struct avl_node_struct { + jmem_key_t key; + int height; + page_t* page; + struct avl_node_struct* left; + struct avl_node_struct* right; +} avl_node_t; + + +typedef struct _jpu_mm_struct { + avl_node_t* free_tree; + avl_node_t* alloc_tree; + page_t* page_list; + int num_pages; + unsigned long base_addr; + unsigned long mem_size; + int free_page_count; + int alloc_page_count; +} jpu_mm_t; + + + +#define VMEM_P_ALLOC(_x) kmalloc(_x, GFP_KERNEL) +#define VMEM_P_FREE(_x) kfree(_x) + +#define VMEM_ASSERT(_exp) if (!(_exp)) { printk(KERN_INFO "VMEM_ASSERT at %s:%d\n", __FILE__, __LINE__); /*while(1);*/ +} +#define VMEM_HEIGHT(_tree) (_tree==NULL ? -1 : _tree->height) + + +#define MAX(_a, _b) (_a >= _b ? _a : _b) + +typedef enum { + LEFT, + RIGHT +} rotation_dir_t; + + + +typedef struct avl_node_data_struct { + int key; + page_t* page; +} avl_node_data_t; + +static avl_node_t* +make_avl_node( + jmem_key_t key, + page_t* page +) +{ + avl_node_t* node = (avl_node_t*)VMEM_P_ALLOC(sizeof(avl_node_t)); + node->key = key; + node->page = page; + node->height = 0; + node->left = NULL; + node->right = NULL; + + return node; +} + + +static int +get_balance_factor( + avl_node_t* tree +) +{ + int factor = 0; + if (tree) { + factor = VMEM_HEIGHT(tree->right) - VMEM_HEIGHT(tree->left); + } + + return factor; +} + +/* + * Left Rotation + * + * A B + * \ / \ + * B => A C + * / \ \ + * D C D + * + */ +static avl_node_t* +rotation_left( + avl_node_t* tree +) +{ + avl_node_t* rchild; + avl_node_t* lchild; + + if (tree == NULL) return NULL; + + rchild = tree->right; + if (rchild == NULL) { + return tree; + } + + lchild = rchild->left; + rchild->left = tree; + tree->right = lchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + rchild->height = MAX(VMEM_HEIGHT(rchild->left), VMEM_HEIGHT(rchild->right)) + 1; + + return rchild; +} + + +/* + * Reft Rotation + * + * A B + * \ / \ + * B => D A + * / \ / + * D C C + * + */ +static avl_node_t* +rotation_right( + avl_node_t* tree +) +{ + avl_node_t* rchild; + avl_node_t* lchild; + + if (tree == NULL) return NULL; + + lchild = tree->left; + if (lchild == NULL) return NULL; + + rchild = lchild->right; + lchild->right = tree; + tree->left = rchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + lchild->height = MAX(VMEM_HEIGHT(lchild->left), VMEM_HEIGHT(lchild->right)) + 1; + + return lchild; +} + +static avl_node_t* +do_balance( + avl_node_t* tree +) +{ + int bfactor = 0, child_bfactor; /* balancing factor */ + + bfactor = get_balance_factor(tree); + + if (bfactor >= 2) { + child_bfactor = get_balance_factor(tree->right); + if (child_bfactor == 1 || child_bfactor == 0) { + tree = rotation_left(tree); + } else if (child_bfactor == -1) { + tree->right = rotation_right(tree->right); + tree = rotation_left(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } else if (bfactor <= -2) { + child_bfactor = get_balance_factor(tree->left); + if (child_bfactor == -1 || child_bfactor == 0) { + tree = rotation_right(tree); + } else if (child_bfactor == 1) { + tree->left = rotation_left(tree->left); + tree = rotation_right(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } + + return tree; +} +static avl_node_t* +unlink_end_node( + avl_node_t* tree, + int dir, + avl_node_t** found_node +) +{ + avl_node_t* node; + *found_node = NULL; + + if (tree == NULL) return NULL; + + if (dir == LEFT) { + if (tree->left == NULL) { + *found_node = tree; + return NULL; + } + } else { + if (tree->right == NULL) { + *found_node = tree; + return NULL; + } + } + + if (dir == LEFT) { + node = tree->left; + tree->left = unlink_end_node(tree->left, LEFT, found_node); + if (tree->left == NULL) { + tree->left = (*found_node)->right; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } else { + node = tree->right; + tree->right = unlink_end_node(tree->right, RIGHT, found_node); + if (tree->right == NULL) { + tree->right = (*found_node)->left; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return do_balance(tree); +} + + +static avl_node_t* +avltree_insert( + avl_node_t* tree, + jmem_key_t key, + page_t* page +) +{ + if (tree == NULL) { + tree = make_avl_node(key, page); + } else { + if (key >= tree->key) { + tree->right = avltree_insert(tree->right, key, page); + } else { + tree->left = avltree_insert(tree->left, key, page); + } + } + + tree = do_balance(tree); + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return tree; +} + +static avl_node_t* +do_unlink( + avl_node_t* tree +) +{ + avl_node_t* node; + avl_node_t* end_node; + node = unlink_end_node(tree->right, LEFT, &end_node); + if (node) { + tree->right = node; + } else { + node = unlink_end_node(tree->left, RIGHT, &end_node); + if (node) tree->left = node; + } + + if (node == NULL) { + node = tree->right ? tree->right : tree->left; + end_node = node; + } + + if (end_node) { + end_node->left = (tree->left != end_node) ? tree->left : end_node->left; + end_node->right = (tree->right != end_node) ? tree->right : end_node->right; + end_node->height = MAX(VMEM_HEIGHT(end_node->left), VMEM_HEIGHT(end_node->right)) + 1; + } + + tree = end_node; + + return tree; +} + +static avl_node_t* +avltree_remove( + avl_node_t* tree, + avl_node_t** found_node, + jmem_key_t key +) +{ + *found_node = NULL; + if (tree == NULL) { + printk(KERN_INFO "failed to find key %d\n", (int)key); + return NULL; + } + + if (key == tree->key) { + *found_node = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = avltree_remove(tree->right, found_node, key); + } else { + tree->left = avltree_remove(tree->left, found_node, key); + } + + if (tree) tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +void +jpu_avltree_free( + avl_node_t* tree +) +{ + if (tree == NULL) return; + if (tree->left == NULL && tree->right == NULL) { + VMEM_P_FREE(tree); + return; + } + + jpu_avltree_free(tree->left); + tree->left = NULL; + jpu_avltree_free(tree->right); + tree->right = NULL; +} + + + + +static avl_node_t* +remove_approx_value( + avl_node_t* tree, + avl_node_t** found, + jmem_key_t key +) +{ + *found = NULL; + if (tree == NULL) { + return NULL; + } + + if (key == tree->key) { + *found = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = remove_approx_value(tree->right, found, key); + } else { + tree->left = remove_approx_value(tree->left, found, key); + if (*found == NULL) { + *found = tree; + tree = do_unlink(tree); + } + } + if (tree) tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + tree = do_balance(tree); + + return tree; +} + +static void +set_blocks_free( + jpu_mm_t *mm, + int pageno, + int npages +) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t* page; + page_t* last_page; + + VMEM_ASSERT(npages); + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i=pageno; i<=last_pageno; i++) { + mm->page_list[i].used = 0; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->free_tree = avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page); +} + +static void +set_blocks_alloc( + jpu_mm_t *mm, + int pageno, + int npages +) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t* page; + page_t* last_page; + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i=pageno; i<=last_pageno; i++) { + mm->page_list[i].used = 1; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->alloc_tree = avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page); +} + + +int +jmem_init( + jpu_mm_t* mm, + unsigned long addr, + unsigned long size +) +{ + int i; + + + mm->base_addr = (addr+(JMEM_PAGE_SIZE-1))&~(JMEM_PAGE_SIZE-1); + mm->mem_size = size&~JMEM_PAGE_SIZE; + mm->num_pages = mm->mem_size/JMEM_PAGE_SIZE; + mm->page_list = (page_t*)VMEM_P_ALLOC(mm->num_pages*sizeof(page_t)); + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = mm->num_pages; + mm->alloc_page_count = 0; + + for (i=0; inum_pages; i++) { + mm->page_list[i].pageno = i; + mm->page_list[i].addr = mm->base_addr + i*JMEM_PAGE_SIZE; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].used = 0; + mm->page_list[i].first_pageno = -1; + } + + set_blocks_free(mm, 0, mm->num_pages); + + return 0; +} + +int +jmem_exit( + jpu_mm_t* mm +) +{ + if (mm == NULL) { + printk(KERN_INFO "vmem_exit: invalid handle\n"); + return -1; + } + + if (mm->free_tree) { + jpu_avltree_free(mm->free_tree); + } + if (mm->alloc_tree) { + jpu_avltree_free(mm->alloc_tree); + } + + VMEM_P_FREE(mm->page_list); + + mm->base_addr = 0; + mm->mem_size = 0; + mm->num_pages = 0; + mm->page_list = NULL; + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = 0; + mm->alloc_page_count = 0; + return 0; +} + +unsigned long +jmem_alloc( + jpu_mm_t* mm, + int size, + unsigned long pid +) +{ + avl_node_t* node; + page_t* free_page; + int npages, free_size; + int alloc_pageno; + unsigned long ptr; + + if (mm == NULL) { + printk(KERN_INFO "vmem_alloc: invalid handle\n"); + return -1; + } + + if (size <= 0) return -1; + + npages = (size + JMEM_PAGE_SIZE -1)/JMEM_PAGE_SIZE; + + mm->free_tree = remove_approx_value(mm->free_tree, &node, MAKE_KEY(npages, 0)); + if (node == NULL) { + return -1; + } + free_page = node->page; + free_size = KEY_TO_VALUE(node->key); + + alloc_pageno = free_page->pageno; + set_blocks_alloc(mm, alloc_pageno, npages); + if (npages != free_size) { + int free_pageno = alloc_pageno + npages; + set_blocks_free(mm, free_pageno, (free_size-npages)); + } + + VMEM_P_FREE(node); + + ptr = mm->page_list[alloc_pageno].addr; + mm->alloc_page_count += npages; + mm->free_page_count -= npages; + + + return ptr; +} + +int +jmem_free( + jpu_mm_t* mm, + unsigned long ptr, + unsigned long pid +) +{ + unsigned long addr; + avl_node_t* found; + page_t* page; + int pageno, prev_free_pageno, next_free_pageno; + int prev_size, next_size; + int merge_page_no, merge_page_size, free_page_size; + + + if (mm == NULL) { + printk(KERN_INFO "vmem_free: invalid handle\n"); + return -1; + } + + addr = ptr; + + mm->alloc_tree = avltree_remove(mm->alloc_tree, &found, MAKE_KEY(addr, 0)); + if (found == NULL) { + printk(KERN_INFO "vmem_free: 0x%08x not found\n", (int)addr); + VMEM_ASSERT(0); + return -1; + } + + /* find previous free block */ + page = found->page; + pageno = page->pageno; + free_page_size = page->alloc_pages; + prev_free_pageno = pageno-1; + prev_size = -1; + if (prev_free_pageno >= 0) { + if (mm->page_list[prev_free_pageno].used == 0) { + prev_free_pageno = mm->page_list[prev_free_pageno].first_pageno; + prev_size = mm->page_list[prev_free_pageno].alloc_pages; + } + } + + /* find next free block */ + next_free_pageno = pageno + page->alloc_pages; + next_free_pageno = (next_free_pageno == mm->num_pages) ? -1 : next_free_pageno; + next_size = -1; + if (next_free_pageno >= 0) { + if (mm->page_list[next_free_pageno].used == 0) { + next_size = mm->page_list[next_free_pageno].alloc_pages; + } + } + VMEM_P_FREE(found); + + /* merge */ + merge_page_no = page->pageno; + merge_page_size = page->alloc_pages; + if (prev_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(prev_size, prev_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_no = found->page->pageno; + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + if (next_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(next_size, next_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + + page->alloc_pages = 0; + page->first_pageno = -1; + + set_blocks_free(mm, merge_page_no, merge_page_size); + + mm->alloc_page_count -= free_page_size; + mm->free_page_count += free_page_size; + + return 0; +} + + + +#endif /* __JPU_MM_H__ */ \ No newline at end of file diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.c b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.c new file mode 100644 index 000000000000..f121834c5a3a --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.c @@ -0,0 +1,1056 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jpu.h" +#include "compat_jpu.h" +#include "../puwrap.h" + +//from jpuconfig.h +#define MAX_NUM_INSTANCE 8 +#define MAX_INST_HANDLE_SIZE (12*1024) + +/* definitions to be changed as customer configuration */ +//#define JPU_SUPPORT_CLOCK_CONTROL /if you want to have clock gating scheme frame by frame +#define JPU_SUPPORT_ISR +/* if the platform driver knows the name of this driver. JPU_PLATFORM_DEVICE_NAME */ +#define JPU_SUPPORT_PLATFORM_DRIVER_REGISTER +#ifndef CONFIG_RTK_RESERVE_MEMORY +/* if this driver knows the dedicated video memory address */ +//#define JPU_SUPPORT_RESERVED_VIDEO_MEMORY +#endif +//#define JPU_IRQ_CONTROL +#define DEV_NAME "[RTK_JPU]" +#define JPU_PLATFORM_DEVICE_NAME "jdec" +#define JPU_CLK_NAME "jpeg" +#define JPU_DEV_NAME "jpu" + +#define JPU_BASE_ADDR 0x9803e000 +#define JPU_REG_SIZE 0x1000 + +#ifdef JPU_SUPPORT_ISR +#define JPU_IRQ_NUM 84+32 +#endif + +#ifndef VM_RESERVED /* for kernel up to 3.7.0 version */ +# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) +#endif + +typedef struct jpu_drv_context_t { + struct fasync_struct *async_queue; + unsigned long interrupt_reason; +} jpu_drv_context_t; + +/* To track the allocated memory buffer */ +typedef struct jpudrv_buffer_pool_t { + struct list_head list; + struct jpudrv_buffer_t jb; + struct file *filp; +} jpudrv_buffer_pool_t; + +/* To track the instance index and buffer in instance pool */ +typedef struct jpudrv_instanace_list_t { + struct list_head list; + unsigned long inst_idx; + struct file *filp; +} jpudrv_instanace_list_t; + +typedef struct jpudrv_instance_pool_t { + unsigned char jpgInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE]; +} jpudrv_instance_pool_t; + +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY +#define JPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (16*1024*1024) +#define JPU_DRAM_PHYSICAL_BASE (0x8AA00000) +#include "jmm.h" +static jpu_mm_t s_jmem; +static jpudrv_buffer_t s_image_memory = {0}; +#endif + +static int jpu_hw_reset(void); +static void jpu_clk_disable(struct clk *clk); +static int jpu_clk_enable(struct clk *clk); +static struct clk *jpu_clk_get(struct device *dev); +static void jpu_clk_put(struct clk *clk); +// end customer definition + +static jpudrv_buffer_t s_jpu_instance_pool = {0}; +static jpu_drv_context_t s_jpu_drv_context; +static struct miscdevice s_jpu_dev; +static int s_jpu_open_count; +static struct clk *s_jpu_clk; +static struct reset_control *rstc_jpeg = NULL; +#ifdef JPU_SUPPORT_ISR +static int s_jpu_irq = JPU_IRQ_NUM; +static atomic_t s_interrupt_flag; +#endif +static unsigned long s_jpu_reg_phy_base = JPU_BASE_ADDR; +static void __iomem *s_jpu_reg_virt_base; +static jpudrv_buffer_t s_jpu_register = {0}; +static jpudrv_buffer_t s_bonding_register = {0}; + +static wait_queue_head_t s_interrupt_wait_q; +static int dbus_en = 1; + +#define JPEG_DBUS_REG (0x0000 + 0xF00) + +static spinlock_t s_jpu_lock = __SPIN_LOCK_UNLOCKED(s_jpu_lock); +static DEFINE_SEMAPHORE(s_jpu_sem); +static struct list_head s_jbp_head = LIST_HEAD_INIT(s_jbp_head); +static struct list_head s_jpu_inst_list_head = LIST_HEAD_INIT(s_jpu_inst_list_head); + +/* implement to power management functions */ +#define ReadJpuRegister(addr) *(volatile unsigned int *)(s_jpu_reg_virt_base + addr) +#define WriteJpuRegister(addr, val) *(volatile unsigned int *)(s_jpu_reg_virt_base + addr) = (unsigned int)val; + +static int jpu_alloc_dma_buffer(jpudrv_buffer_t *jb) +{ +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + jb->phys_addr = (unsigned long)jmem_alloc(&s_jmem, jb->size, 0); + + if ((unsigned long)jb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } + + jb->base = (unsigned long)(s_image_memory.base + (jb->phys_addr - s_image_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + unsigned int ret; + ret = pu_alloc_dma_buffer(jb->size, &jb->phys_addr, &jb->base, 0); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#else + jb->base = (unsigned long)dma_alloc_coherent(s_jpu_dev.this_device, PAGE_ALIGN(jb->size), (dma_addr_t *) (&jb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(jb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#endif +// pr_info("%s base:0x%08x, phy_addr:0x%08x, size:%d\n", DEV_NAME, (unsigned int)jb->base, (unsigned int)jb->phys_addr, jb->size); + return 0; +} + +static int jpu_alloc_dma_buffer2(jpudrv_buffer_t *jb) +{ +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + jb->phys_addr = (unsigned long)jmem_alloc(&s_jmem, jb->size, 0); + + if ((unsigned long)jb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } + + jb->base = (unsigned long)(s_image_memory.base + (jb->phys_addr - s_image_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + unsigned int ret; + ret = pu_alloc_dma_buffer(jb->size, &jb->phys_addr, &jb->base, 0); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } + jb->base = pu_mmap_kernel_buffer(jb->phys_addr, jb->size); + if ((void *)(jb->base) == NULL) { + pr_err("%s pu_mmap_kernel_buffer error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#else + jb->base = (unsigned long)dma_alloc_coherent(s_jpu_dev.this_device, PAGE_ALIGN(jb->size), (dma_addr_t *) (&jb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(jb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, jb->size); + return -1; + } +#endif +// pr_info("%s base:0x%08x, phy_addr:0x%08x, size:%d\n", DEV_NAME, (unsigned int)jb->base, (unsigned int)jb->phys_addr, jb->size); + return 0; +} + +static void jpu_free_dma_buffer(jpudrv_buffer_t *jb) +{ +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (jb->base) + jmem_free(&s_jmem, jb->phys_addr, 0); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + pu_free_dma_buffer(jb->base, jb->phys_addr); +#else + if (jb->base) + dma_free_coherent(s_jpu_dev.this_device, PAGE_ALIGN(jb->size), (void *)jb->base, jb->phys_addr); +#endif +} + +static int jpu_free_instances(struct file *filp) +{ + u32 inst_idx; + jpudrv_instanace_list_t *jil, *n; + jpudrv_instance_pool_t *jip; + void *jip_base; + void* jdi_mutex_base; + const unsigned int PTHREAD_MUTEX_T_DESTROY_VALUE = 0xdead10cc; + + list_for_each_entry_safe(jil, n, &s_jpu_inst_list_head, list) { + if (jil->filp == filp) { + int i; + for (i = 0; i < MAX_NUM_INSTANCE; i++) /* reset dovi flag */ + { + pu_set_dovi_flag(2, i, 0); + } + + inst_idx = jil->inst_idx; + jip_base = (void *)(s_jpu_instance_pool.base); + jip = (jpudrv_instance_pool_t *)jip_base; + if (jip) { + memset(&jip->jpgInstPool[inst_idx], 0x00, 4); // only first 4 byte is key point to free the corresponding instance. +#define PTHREAD_MUTEX_T_HANDLE_SIZE 40 + jdi_mutex_base = (jip_base + (s_jpu_instance_pool.size - PTHREAD_MUTEX_T_HANDLE_SIZE)); + if (jdi_mutex_base) { + memcpy(jdi_mutex_base, &PTHREAD_MUTEX_T_DESTROY_VALUE, sizeof(unsigned int)); + } + } + s_jpu_open_count--; + list_del(&jil->list); + kfree(jil); + } + } + + return s_jpu_open_count; +} + +static int jpu_free_buffers(struct file *filp) +{ + jpudrv_buffer_pool_t *pool, *n; + jpudrv_buffer_t jb; + + list_for_each_entry_safe(pool, n, &s_jbp_head, list) { + if (pool->filp == filp) { + jb = pool->jb; + if (jb.base) { + jpu_free_dma_buffer(&jb); + list_del(&pool->list); + kfree(pool); + } + } + } + + return 0; +} + +#ifdef JPU_SUPPORT_ISR +static irqreturn_t jpu_irq_handler(int irq, void *dev_id) +{ + jpu_drv_context_t *dev = (jpu_drv_context_t *)dev_id; +#ifdef JPU_IRQ_CONTROL + disable_irq_nosync(s_jpu_irq); +#endif + + dev->interrupt_reason = ReadJpuRegister(0x004); /* MJPEG_PIC_STATUS_REG */ + WriteJpuRegister(0x004, dev->interrupt_reason); + if (dev->async_queue) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* notify the interrupt to userspace */ + + atomic_set(&s_interrupt_flag, 1); + + //pr_info("%s jpu_irq_handler\n", DEV_NAME); + wake_up_interruptible(&s_interrupt_wait_q); + + return IRQ_HANDLED; +} +#endif + +static int jpu_open(struct inode *inode, struct file *filp) +{ + spin_lock(&s_jpu_lock); + + filp->private_data = (void *)(&s_jpu_drv_context); + spin_unlock(&s_jpu_lock); + return 0; +} + +static long jpu_ioctl(struct file *filp, u_int cmd, u_long arg) +{ + int ret = 0; + struct jpu_drv_context_t *dev = (struct jpu_drv_context_t *)filp->private_data; + jpudrv_buffer_pool_t *jbp; + jpudrv_buffer_pool_t *n; + jpudrv_buffer_t jb; + jpudrv_intr_info_t info; + jpudrv_instanace_list_t *jil; + jpudrv_instanace_list_t *tmp; + jpudrv_dovi_info_t doviInfo; + u32 inst_idx; + u32 clkgate; + u32 val; + + switch (cmd) { + case JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + down(&s_jpu_sem); + + jbp = kzalloc(sizeof(*jbp), GFP_KERNEL); + if (!jbp) { + up(&s_jpu_sem); + return -ENOMEM; + } + + ret = copy_from_user(&(jbp->jb), (jpudrv_buffer_t *)arg, sizeof(jpudrv_buffer_t)); + if (ret) { + kfree(jbp); + up(&s_jpu_sem); + return -EFAULT; + } + + ret = jpu_alloc_dma_buffer(&(jbp->jb)); + if (ret == -1) { + ret = -ENOMEM; + kfree(jbp); + up(&s_jpu_sem); + break; + } + + ret = copy_to_user((void __user *)arg, &(jbp->jb), sizeof(jpudrv_buffer_t)); + if (ret) { + kfree(jbp); + ret = -EFAULT; + up(&s_jpu_sem); + break; + } + + jbp->filp = filp; + spin_lock(&s_jpu_lock); + list_add(&jbp->list, &s_jbp_head); + spin_unlock(&s_jpu_lock); + + up(&s_jpu_sem); + break; + case JDI_IOCTL_FREE_PHYSICALMEMORY: + down(&s_jpu_sem); + + ret = copy_from_user(&jb, (jpudrv_buffer_t *)arg, sizeof(jpudrv_buffer_t)); + if (ret) { + up(&s_jpu_sem); + return -EACCES; + } + + if (jb.base) + jpu_free_dma_buffer(&jb); + + spin_lock(&s_jpu_lock); + list_for_each_entry_safe(jbp, n, &s_jbp_head, list) { + if (jbp->jb.phys_addr == jb.phys_addr) { + list_del(&jbp->list); + kfree(jbp); + break; + } + } + spin_unlock(&s_jpu_lock); + + up(&s_jpu_sem); + break; + case JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_image_memory.base != 0) { + ret = copy_to_user((void __user *)arg, &s_image_memory, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = -EFAULT; + } +#endif + break; +#ifdef JPU_SUPPORT_ISR + case JDI_IOCTL_WAIT_INTERRUPT: + ret = copy_from_user(&info, (jpudrv_intr_info_t*)arg, sizeof(jpudrv_intr_info_t)); + if (ret != 0) + return -EFAULT; + + smp_rmb(); + ret = wait_event_interruptible_timeout(s_interrupt_wait_q, atomic_read(&s_interrupt_flag) != 0, msecs_to_jiffies(info.timeout)); + if (!ret) { + ret = -ETIME; + //pr_info("%s JDI_IOCTL_WAIT_INTERRUPT fail\n", DEV_NAME); + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + atomic_set(&s_interrupt_flag, 0); + info.intr_reason = dev->interrupt_reason; + ret = copy_to_user((void __user *)arg, &info, sizeof(jpudrv_intr_info_t)); + if (ret != 0) + return -EFAULT; + + //pr_info("%s JDI_IOCTL_WAIT_INTERRUPT done, info.intr_reason:0x%x\n", DEV_NAME, info.intr_reason); + break; +#endif /* JPU_SUPPORT_ISR */ + case JDI_IOCTL_ENABLE_INTERRUPT: +#ifdef JPU_IRQ_CONTROL + enable_irq(s_jpu_irq); +#endif + break; + case JDI_IOCTL_SET_CLOCK_GATE: + if (get_user(clkgate, (u32 __user *) arg)) + return -EFAULT; + +#ifdef JPU_SUPPORT_CLOCK_CONTROL + if (clkgate) + jpu_clk_enable(s_jpu_clk); + else + jpu_clk_disable(s_jpu_clk); +#endif + + break; + case JDI_IOCTL_GET_INSTANCE_POOL: + down(&s_jpu_sem); + + if (s_jpu_instance_pool.base != 0) { + ret = copy_to_user((void __user *)arg, &s_jpu_instance_pool, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = copy_from_user(&s_jpu_instance_pool, (jpudrv_buffer_t *)arg, sizeof(jpudrv_buffer_t)); + if (ret == 0) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + s_jpu_instance_pool.size = PAGE_ALIGN(s_jpu_instance_pool.size); + s_jpu_instance_pool.base = (unsigned long)vmalloc(s_jpu_instance_pool.size); + s_jpu_instance_pool.phys_addr = s_jpu_instance_pool.base; + + if (s_jpu_instance_pool.base != 0) +#else + if (jpu_alloc_dma_buffer2(&s_jpu_instance_pool) != -1) +#endif + { + memset((void *)s_jpu_instance_pool.base, 0x0, s_jpu_instance_pool.size); + ret = copy_to_user((void __user *)arg, &s_jpu_instance_pool, sizeof(jpudrv_buffer_t)); + if (ret == 0) { + // success to get memory for instance pool + up(&s_jpu_sem); + break; + } + } + } + ret = -EFAULT; + } + up(&s_jpu_sem); + + break; + case JDI_IOCTL_OPEN_INSTANCE: + jil = kzalloc(sizeof(*jil), GFP_KERNEL); + if (!jil) + return -ENOMEM; + + if (get_user(inst_idx, (u32 __user *) arg)) + return -EFAULT; + + jil->inst_idx = inst_idx; + jil->filp = filp; + spin_lock(&s_jpu_lock); + list_add(&jil->list, &s_jpu_inst_list_head); + s_jpu_open_count++; + spin_unlock(&s_jpu_lock); + break; + case JDI_IOCTL_CLOSE_INSTANCE: + if (get_user(inst_idx, (u32 __user *) arg)) + return -EFAULT; + + spin_lock(&s_jpu_lock); + + list_for_each_entry_safe(jil, tmp, &s_jpu_inst_list_head, list) { + if (jil->inst_idx == inst_idx) { + s_jpu_open_count--; + list_del(&jil->list); + kfree(jil); +// printk(KERN_INFO "[JPUDRV] JDI_IOCTL_CLOSE_INSTANCE inst_idx=%d, open_count=%d\n", (int)inst_idx, s_jpu_open_count); + break; + } + } + spin_unlock(&s_jpu_lock); + break; + case JDI_IOCTL_GET_INSTANCE_NUM: + down(&s_jpu_sem); + + ret = copy_to_user((void __user *)arg, &s_jpu_open_count, sizeof(int)); + if (ret != 0) + ret = -EFAULT; + + //printk(KERN_INFO "[JPUDRV] VDI_IOCTL_GET_INSTANCE_NUM open_count=%d\n", s_jpu_open_count); + + up(&s_jpu_sem); + break; + case JDI_IOCTL_RESET: + jpu_hw_reset(); + break; + case JDI_IOCTL_GET_REGISTER_INFO: + ret = copy_to_user((void __user *)arg, &s_jpu_register, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + break; + case JDI_IOCTL_GET_BONDING_INFO: + ret = copy_to_user((void __user *)arg, &s_bonding_register, sizeof(jpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + break; + case JDI_IOCTL_SET_CLOCK_ENABLE: + + if (get_user(clkgate, (u32 __user *) arg)) + return -EFAULT; + + if (clkgate) { + reset_control_deassert(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); + val = ReadJpuRegister(JPEG_DBUS_REG); + val |= (dbus_en << 0); + val &= ~(1 << 1); //Disable idle gating, fix it later. + WriteJpuRegister(JPEG_DBUS_REG, val); + } else { + jpu_clk_disable(s_jpu_clk); + reset_control_assert(rstc_jpeg); + } + break; + case JDI_IOCTL_SET_RTK_DOVI_FLAG: + //pr_info("%s [+]JDI_IOCTL_SET_RTK_DOVI_FLAG\n", DEV_NAME); + ret = copy_from_user(&doviInfo, (jpudrv_dovi_info_t *)arg, sizeof(jpudrv_dovi_info_t)); + if (ret != 0) + break; + + doviInfo.enable = pu_set_dovi_flag(2, doviInfo.inst_idx, doviInfo.enable); + + ret = copy_to_user((jpudrv_dovi_info_t *)arg, &doviInfo, sizeof(jpudrv_dovi_info_t)); + if (ret != 0) + break; + //pr_info("%s [-]JDI_IOCTL_SET_RTK_DOVI_FLAG doviInfo.inst_idx:%d, doviInfo.value:%d\n", DEV_NAME, doviInfo.inst_idx, doviInfo.enable); + break; + default: + printk(KERN_ERR "No such IOCTL, cmd is %d\n", cmd); + break; + } + + return ret; +} + +static ssize_t jpu_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) +{ + return -1; +} + +static ssize_t jpu_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) +{ + + return -1; +} + +static int jpu_release(struct inode *inode, struct file *filp) +{ +// pr_info("%s jpu_release s_jpu_open_count=%d\n", DEV_NAME, s_jpu_open_count); + + spin_lock(&s_jpu_lock); + + + if (s_jpu_open_count > 0) { + /* found and free the not handled buffer by user applications */ + jpu_free_buffers(filp); + + /* found and free the not closed instance by user applications */ + jpu_free_instances(filp); + } + +#if 1 //Fuchun 20150909, we must not free instance pool and common memory + if (s_jpu_open_count == 0) { + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_jpu_instance_pool.base, s_jpu_instance_pool.phys_addr); + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; +// pr_info("%s jpu_release - free s_jpu_instance_pool\n", DEV_NAME); + } + } +#endif + + spin_unlock(&s_jpu_lock); + + return 0; +} + +static int jpu_fasync(int fd, struct file *filp, int mode) +{ + struct jpu_drv_context_t *dev = (struct jpu_drv_context_t *)filp->private_data; + return fasync_helper(fd, filp, mode, &dev->async_queue); +} + +static int jpu_map_to_register(struct file *fp, struct vm_area_struct *vm) +{ + unsigned long pfn; + + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + pfn = vm->vm_pgoff; + + return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +} + +static int jpu_map_to_physical_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef CONFIG_RTK_RESERVE_MEMORY + return pu_mmap_dma_buffer(vm); +#else + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot); + + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif +} + +static int jpu_map_to_instance_pool_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + int ret; + long length = vm->vm_end - vm->vm_start; + unsigned long start = vm->vm_start; + char *vmalloc_area_ptr = (char *)s_jpu_instance_pool.base; + unsigned long pfn; + + vm->vm_flags |= VM_RESERVED; + + /* loop over all pages, map it page individually */ + while (length > 0) { + pfn = vmalloc_to_pfn(vmalloc_area_ptr); + if ((ret = remap_pfn_range(vm, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0) { + return ret; + } + start += PAGE_SIZE; + vmalloc_area_ptr += PAGE_SIZE; + length -= PAGE_SIZE; + } + + return 0; +#else + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif +} + +/*! + * @brief memory map interface for jpu file operation + * @return 0 on success or negative error code on error + */ +static int jpu_mmap(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + if (vm->vm_pgoff == 0) + return jpu_map_to_instance_pool_memory(fp, vm); + + if ((vm->vm_pgoff == (s_jpu_register.phys_addr>>PAGE_SHIFT)) || (vm->vm_pgoff == (s_bonding_register.phys_addr>>PAGE_SHIFT))) + return jpu_map_to_register(fp, vm); + + return jpu_map_to_physical_memory(fp, vm); +#else + if (vm->vm_pgoff) { + if (vm->vm_pgoff == (s_jpu_instance_pool.phys_addr>>PAGE_SHIFT)) + return jpu_map_to_instance_pool_memory(fp, vm); + + return jpu_map_to_physical_memory(fp, vm); + } else + return jpu_map_to_register(fp, vm); +#endif +} + +struct file_operations jpu_fops = { + .owner = THIS_MODULE, + .open = jpu_open, + .read = jpu_read, + .write = jpu_write, + .unlocked_ioctl = jpu_ioctl, + .compat_ioctl = compat_jpu_ioctl, + .release = jpu_release, + .fasync = jpu_fasync, + .mmap = jpu_mmap, +}; + +static int jpu_probe(struct platform_device *pdev) +{ + int err = 0; + struct resource res; + void __iomem *iobase; + int irq; + struct device_node *node = pdev->dev.of_node; + + pr_info("%s jpu_probe\n", DEV_NAME); + + of_address_to_resource(node, 0, &res); + iobase = of_iomap(node, 0); + + s_jpu_reg_phy_base = res.start; + s_jpu_reg_virt_base = iobase; + s_jpu_register.phys_addr = res.start; + s_jpu_register.virt_addr = (unsigned long)iobase; + s_jpu_register.size = res.end - res.start + 1; + + pr_info("%s jpu base address get from DTB physical base addr=0x%lx, virtual base=0x%lx, size=0x%x\n", DEV_NAME, (unsigned long)s_jpu_reg_phy_base, (unsigned long)s_jpu_reg_virt_base, (unsigned int)(res.end - res.start + 1)); + + of_address_to_resource(node, 1, &res); + iobase = of_iomap(node, 1); + + s_bonding_register.phys_addr = res.start; + s_bonding_register.virt_addr = (unsigned long)iobase; + s_bonding_register.size = res.end - res.start + 1; + + s_jpu_dev.minor = MISC_JPU_MINOR; + s_jpu_dev.name = JPU_DEV_NAME; + s_jpu_dev.fops = &jpu_fops; + s_jpu_dev.parent = NULL; + if (misc_register(&s_jpu_dev)) { + pr_info("%s failed to register misc device.", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + + if (pdev) + s_jpu_clk = jpu_clk_get(&pdev->dev); + else + s_jpu_clk = jpu_clk_get(NULL); + + if (!s_jpu_clk) + pr_err("%s fail to get clock controller, but, do not treat as error, \n", DEV_NAME); + else + pr_info("%s get clock controller s_jpu_clk=0x%p\n", DEV_NAME, s_jpu_clk); + +#ifdef JPU_SUPPORT_CLOCK_CONTROL + jpu_clk_enable(s_jpu_clk); +#endif + + rstc_jpeg = reset_control_get_exclusive(&pdev->dev, NULL); + + /* RTK clock setting */ + reset_control_deassert(rstc_jpeg); // RESET disable +#if 0 //Fuchun disable 20160204, set clock gating by jdi.c + jpu_pll_setting(0x10, (1 << jpg_clk_enable_bit), 0, 1); // CLK enable + + val = ReadJpuRegister(JPEG_DBUS_REG); + val |= (dbus_en << 0); + WriteJpuRegister(JPEG_DBUS_REG, val); +#endif + +#ifdef JPU_SUPPORT_ISR + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + s_jpu_irq = irq; + pr_info("%s s_jpu_irq:%d want to register jpu_irq_handler\n", DEV_NAME, s_jpu_irq); + err = request_irq(s_jpu_irq, jpu_irq_handler, 0, "JPEG_CODEC_IRQ", (void *)(&s_jpu_drv_context)); + err = 0; + if (err != 0) { + if (err == -EINVAL) + pr_err("%s Bad s_jpu_irq number or handler\n", DEV_NAME); + else if (err == -EBUSY) + pr_err("%s s_jpu_irq <%d> busy, change your config\n", DEV_NAME, s_jpu_irq); + + goto ERROR_PROVE_DEVICE; + } +#endif + +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + s_image_memory.size = JPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE; + s_image_memory.phys_addr = JPU_DRAM_PHYSICAL_BASE; + s_image_memory.base = (unsigned long)ioremap(s_image_memory.phys_addr, PAGE_ALIGN(s_image_memory.size)); + + if (!s_image_memory.base) { + pr_err("%s fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n", DEV_NAME, (int)s_image_memory.phys_addr, (int)s_image_memory.base, (int)s_image_memory.size); + goto ERROR_PROVE_DEVICE; + } + + if (jmem_init(&s_jmem, s_image_memory.phys_addr, s_image_memory.size) < 0) { + pr_err("%s fail to init vmem system\n", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + + pr_info("%s success to probe jpu device with reserved video memory phys_addr=0x%x, base = 0x%x\n", DEV_NAME, (int) s_image_memory.phys_addr, (int)s_image_memory.base); +#else + pr_info("%s success to probe jpu device with non reserved video memory\n", DEV_NAME); +#endif + + reset_control_assert(rstc_jpeg); + + return 0; + + +ERROR_PROVE_DEVICE: + + misc_deregister(&s_jpu_dev); + + if (s_jpu_reg_virt_base) + iounmap(s_jpu_reg_virt_base); + + return err; +} + +static int jpu_remove(struct platform_device *pdev) +{ +#ifdef JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + + pr_info("%s jpu_remove\n", DEV_NAME); + + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_jpu_instance_pool.base, s_jpu_instance_pool.phys_addr); + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; + } +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_image_memory.base) { + iounmap((void *)s_image_memory.base); + s_image_memory.base = 0; + jmem_exit(&s_jmem); + } +#endif + + misc_deregister(&s_jpu_dev); + +#ifdef JPU_SUPPORT_ISR + if (s_jpu_irq) + free_irq(s_jpu_irq, &s_jpu_drv_context); +#endif + + if (s_jpu_reg_virt_base) + iounmap(s_jpu_reg_virt_base); + + if (rstc_jpeg != NULL) + reset_control_put(rstc_jpeg); + + jpu_clk_put(s_jpu_clk); + +#endif //JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + + return 0; +} + +#ifdef CONFIG_PM +static int jpu_suspend(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + reset_control_deassert(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); +#if 0 + if (s_jpu_open_count > 0) { + u32 inst_idx; + jpudrv_instanace_list_t *jil, *n; + jpudrv_instance_pool_t *jip; + void *jip_base; + jpudrv_buffer_pool_t *pool, *n; + jpudrv_buffer_t jb; + + s_jpu_open_count = 0; + atomic_set(&s_interrupt_flag, 0); + wake_up_interruptible_all(&s_interrupt_wait_q); + + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; + pr_info("%s jpu_release - free s_jpu_instance_pool\n", DEV_NAME); + } + + list_for_each_entry_safe(jil, n, &s_jpu_inst_list_head, list) { + inst_idx = jil->inst_idx; + jip_base = (void *)(s_jpu_instance_pool.base); + jip = (jpudrv_instance_pool_t *)jip_base; + if (jip) { + memset(&jip->jpgInstPool[inst_idx], 0x00, 4); // only first 4 byte is key point to free the corresponding instance. + } + list_del(&jil->list); + kfree(jil); + } + + list_for_each_entry_safe(pool, n, &s_jbp_head, list) { + jb = pool->jb; + if (jb.base) { + jpu_free_dma_buffer(&jb); + list_del(&pool->list); + kfree(pool); + } + } + } +#endif + jpu_clk_disable(s_jpu_clk); + reset_control_assert(rstc_jpeg); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; + +} + +static int jpu_resume(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + reset_control_deassert(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); + jpu_clk_disable(s_jpu_clk); + reset_control_assert(rstc_jpeg); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; +} +#else +#define jpu_suspend NULL +#define jpu_resume NULL +#endif /* !CONFIG_PM */ + +static int __init jpu_init(void) +{ + int res; + res = 0; + + pr_info("%s jpu_init\n", DEV_NAME); + init_waitqueue_head(&s_interrupt_wait_q); + s_jpu_instance_pool.base = 0; + + pr_info("%s end jpu_init result=0x%x\n", DEV_NAME, res); + return res; +} + +static void __exit jpu_exit(void) +{ +#ifdef JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + pr_info("%s jpu_exit\n", DEV_NAME); +#else + if (s_jpu_instance_pool.base) { +#ifdef J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_jpu_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_jpu_instance_pool.base, s_jpu_instance_pool.phys_addr); + jpu_free_dma_buffer(&s_jpu_instance_pool); +#endif + s_jpu_instance_pool.base = 0; + } +#ifdef JPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_image_memory.base) { + iounmap((void *)s_image_memory.base); + s_image_memory.base = 0; + } +#endif + + misc_deregister(&s_jpu_dev); + +#ifdef JPU_SUPPORT_ISR + if (s_jpu_irq) + free_irq(s_jpu_irq, &s_jpu_drv_context); +#endif + + if (rstc_jpeg != NULL) + reset_control_put(rstc_jpeg); + + jpu_clk_put(s_jpu_clk); + + + if (s_jpu_reg_virt_base) { + iounmap(s_jpu_reg_virt_base); + s_jpu_reg_virt_base = (void *)0x00; + } + +#endif //JPU_SUPPORT_PLATFORM_DRIVER_REGISTER + + return; +} + +MODULE_AUTHOR("A customer using RTK JPU, Inc."); +MODULE_DESCRIPTION("JPU linux driver"); +MODULE_LICENSE("GPL"); + +module_init(jpu_init); +module_exit(jpu_exit); + +int jpu_hw_reset(void) +{ + u32 val; + + pr_info("%s request jpu reset from application\n", DEV_NAME); + jpu_clk_disable(s_jpu_clk); + reset_control_reset(rstc_jpeg); + jpu_clk_enable(s_jpu_clk); + val = ReadJpuRegister(JPEG_DBUS_REG); + val |= (dbus_en << 0); + val &= ~(1 << 1); //Disable idle gating, fix it later. + WriteJpuRegister(JPEG_DBUS_REG, val); + return 0; +} + +struct clk *jpu_clk_get(struct device *dev) +{ + return clk_get(dev, JPU_CLK_NAME); +} + +void jpu_clk_put(struct clk *clk) +{ + if (!(clk == NULL || IS_ERR(clk))) + clk_put(clk); +} + +int jpu_clk_enable(struct clk *clk) +{ + if (!(clk == NULL || IS_ERR(clk))) { +// pr_info("%s jpu_clk_enable\n", DEV_NAME); + return clk_prepare_enable(clk); + } + return 0; +} + +void jpu_clk_disable(struct clk *clk) +{ + if (!(clk == NULL || IS_ERR(clk))) { +// pr_info("%s jpu_clk_disable\n", DEV_NAME); + clk_disable_unprepare(clk); + } +} + +static const struct of_device_id rtk_jpeg_dt_match[] = { + { .compatible = "realtek,rtd13xx-jpeg" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_jpeg_dt_match); + +const struct dev_pm_ops rtk_jpeg_pmops = { + .suspend = jpu_suspend, + .resume = jpu_resume, +}; + +static struct platform_driver rtk_jpeg_driver = { + .driver = { + .name = "rtk-jpeg", + .owner = THIS_MODULE, + .of_match_table = rtk_jpeg_dt_match, + .pm = &rtk_jpeg_pmops, + }, + .probe = jpu_probe, + .remove = jpu_remove, +}; + +module_platform_driver(rtk_jpeg_driver); diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.h new file mode 100644 index 000000000000..fce5113b33a4 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/jdi/jpu.h @@ -0,0 +1,47 @@ + + +#ifndef __JPU_DRV_H__ +#define __JPU_DRV_H__ + +#include +#include + +#define J_USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + +#define JDI_IOCTL_MAGIC 'J' +#define JDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(JDI_IOCTL_MAGIC, 0) +#define JDI_IOCTL_FREE_PHYSICALMEMORY _IO(JDI_IOCTL_MAGIC, 1) +#define JDI_IOCTL_WAIT_INTERRUPT _IO(JDI_IOCTL_MAGIC, 2) +#define JDI_IOCTL_SET_CLOCK_GATE _IO(JDI_IOCTL_MAGIC, 3) +#define JDI_IOCTL_RESET _IO(JDI_IOCTL_MAGIC, 4) +#define JDI_IOCTL_GET_INSTANCE_POOL _IO(JDI_IOCTL_MAGIC, 5) +#define JDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(JDI_IOCTL_MAGIC, 6) +#define JDI_IOCTL_OPEN_INSTANCE _IO(JDI_IOCTL_MAGIC, 7) +#define JDI_IOCTL_CLOSE_INSTANCE _IO(JDI_IOCTL_MAGIC, 8) +#define JDI_IOCTL_GET_INSTANCE_NUM _IO(JDI_IOCTL_MAGIC, 9) +#define JDI_IOCTL_ENABLE_INTERRUPT _IO(JDI_IOCTL_MAGIC, 10) +#define JDI_IOCTL_GET_REGISTER_INFO _IO(JDI_IOCTL_MAGIC, 11) + +/* RTK ioctl */ +#define JDI_IOCTL_SET_CLOCK_ENABLE _IO(JDI_IOCTL_MAGIC, 12) +#define JDI_IOCTL_GET_BONDING_INFO _IO(JDI_IOCTL_MAGIC, 13) +#define JDI_IOCTL_SET_RTK_DOVI_FLAG _IO(JDI_IOCTL_MAGIC, 14) + +typedef struct jpudrv_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; /* kernel logical address in use kernel */ + unsigned long virt_addr; /* virtual user space address */ +} jpudrv_buffer_t; + +typedef struct jpudrv_intr_info_t { + unsigned int timeout; + int intr_reason; +} jpudrv_intr_info_t; + +typedef struct jpudrv_dovi_info_t{ + unsigned int inst_idx; + unsigned int enable; +} jpudrv_dovi_info_t; + +#endif diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.c b/drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.c new file mode 100644 index 000000000000..dc5adff5544a --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.c @@ -0,0 +1,554 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "puwrap.h" + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#define USE_ION_ALLOCATOR +#ifdef USE_ION_ALLOCATOR +#define NUM_ION_STRUCT 256 + +#if defined(CONFIG_ION_REALTEK) +#include "mem_allocator/ion.h" +#include +#else +#include "../../../../staging/android/ion/ion.h" +#include "../../../../staging/android/uapi/ion_rtk.h" +#endif + +#include +#define ion_alloc ext_rtk_ion_alloc + +struct rtkdrv_ion_buffer_t { + unsigned int size; + unsigned int inUse; + unsigned long phys_addr; + unsigned long dmabuf; + unsigned long pIonHandle; +}; + +struct rtkdrv_ion_buffer_t pu_ion_buffer[NUM_ION_STRUCT]; +static DEFINE_MUTEX(s_pu_mutex); +#else /* else USE_ION_ALLOCATOR */ +typedef struct rtkdrv_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; /* kernel logical address in use kernel */ + unsigned long virt_addr; /* virtual user space address */ +} rtkdrv_buffer_t; + +#define RTK_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (16*1024*1024) +#define RTK_DRAM_PHYSICAL_BASE 0x06000000 +#include "rtk_mm.h" +static video_mm_t s_mem; +static rtkdrv_buffer_t s_memory = {0}; +#endif /* endif USE_ION_ALLOCATOR */ +#define VE_SECURE_NORMAL 1 +#define VE_SECURE_PROTECTION 2 +#endif /* endif CONFIG_RTK_RESERVE_MEMORY */ + +typedef struct rtkdrv_dovi_flag_t{ + int nCoreIdx; + int nInstIdx; + unsigned int bEnable; +} rtkdrv_dovi_flag_t; + +rtkdrv_dovi_flag_t dovi_flag = {-1, -1, 0}; +static DEFINE_MUTEX(s_dovi_mutex); + +#define PU_PLATFORM_DEVICE_NAME "rtk_puwrap" + +#ifdef CONFIG_RTK_RESERVE_MEMORY + +phys_addr_t get_mem_pa(struct ion_buffer *buffer) +{ + unsigned long ret = -1UL; + struct sg_table *table; + struct page *page; + phys_addr_t paddr; + + mutex_lock(&buffer->lock); + table = buffer->sg_table; + page = sg_page(table->sgl); + paddr = PFN_PHYS(page_to_pfn(page)); + mutex_unlock(&buffer->lock); + + ret = paddr; + + return ret; +} + +int pu_alloc_dma_buffer(unsigned int size, unsigned long *phys_addr, unsigned long *base, unsigned int mem_type) +{ + +#ifdef USE_ION_ALLOCATOR + int ret = -1; + if (!size) + return -1; + + mutex_lock(&s_pu_mutex); + do { + int i; + struct dma_buf *dmabuf; + phys_addr_t dat; + size_t len; + int heap = RTK_ION_HEAP_MEDIA_MASK; + int flags = (ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_NONCACHED); + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].inUse == 0) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] NUM_ION_STRUCT is too small!!!"); + break; + } + + switch(mem_type) + { + case VE_SECURE_NORMAL: + { + heap = RTK_ION_HEAP_MEDIA_MASK; + flags = (ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_NONCACHED | ION_FLAG_VE_SPEC); + break; + } + case VE_SECURE_PROTECTION: + { + heap = RTK_ION_HEAP_SECURE_MASK | RTK_ION_HEAP_MEDIA_MASK; + flags = (ION_FLAG_HWIPACC | ION_FLAG_PROTECTED_V2_VIDEO_POOL); + break; + } + default: + { + heap = RTK_ION_HEAP_MEDIA_MASK; + flags = (ION_FLAG_SCPUACC | ION_FLAG_HWIPACC | ION_FLAG_NONCACHED); + break; + } + } + + int handle = ion_alloc(size, heap, flags); + if (IS_ERR(handle)) + { + printk(KERN_ERR "[PUWRAP] ion_alloc allocation error size=%d\n", size); + break; + } + + dmabuf = dma_buf_get(handle); + if (IS_ERR(dmabuf)) { + break; + } + + dat = get_mem_pa(dmabuf->priv); + + *base = (unsigned long) dmabuf; // we didn't need base address on user space, but we also need it has value to do detection + *phys_addr = (unsigned long)dat; + pu_ion_buffer[i].size = size; + pu_ion_buffer[i].inUse = 1; + pu_ion_buffer[i].phys_addr = (unsigned long)*phys_addr; + pu_ion_buffer[i].dmabuf = (unsigned long)dmabuf; + pu_ion_buffer[i].pIonHandle = (unsigned long)handle; + + __close_fd(current->files, handle); + + ret = 0; + break; + } while (0); + mutex_unlock(&s_pu_mutex); + return ret; + +#else /* else USE_ION_ALLOCATOR */ + if (!size) + return -1; + + *phys_addr = (unsigned long)vmem_alloc(&s_mem, size, 0); + if (*phys_addr == (unsigned long)-1) + { + printk(KERN_ERR "[PUWRAP] Physical memory allocation error size=%d\n", size); + return -1; + } + + *base = (unsigned long)(s_memory.base + (*phys_addr - s_memory.phys_addr)); + //printk("[PUWARP] base:0x%lx, phy_addr:0x%lx, size:%d\n", *base, (unsigned long)*phys_addr, size); + + return 0; +#endif /* endif USE_ION_ALLOCATOR */ +} + +void pu_free_dma_buffer(unsigned long base, unsigned long phys_addr) +{ + if (!base) + return; + +#ifdef USE_ION_ALLOCATOR + mutex_lock(&s_pu_mutex); + do { + int i; + struct ion_handle *handle; + struct dma_buf *dmabuf; + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + break; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + if (dmabuf != NULL) + { + dma_buf_put(dmabuf); + pu_ion_buffer[i].dmabuf = (unsigned long) NULL; + } + + handle = (struct ion_handle *)pu_ion_buffer[i].pIonHandle; + if(handle != NULL) + { + //ion_free(pu_client, handle); + } + memset(&pu_ion_buffer[i], 0, sizeof(struct rtkdrv_ion_buffer_t)); + } while (0); + mutex_unlock(&s_pu_mutex); +#else + vmem_free(&s_mem, (unsigned long)phys_addr, 0); +#endif +} + +int pu_mmap_dma_buffer(struct vm_area_struct *vm) +{ +#ifdef USE_ION_ALLOCATOR + u32 i; + int ret = 0; + struct dma_buf *dmabuf; + unsigned long phys_addr = (unsigned long)(vm->vm_pgoff << PAGE_SHIFT); + mutex_lock(&s_pu_mutex); + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + mutex_unlock(&s_pu_mutex); + return -EINVAL; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + ret = dma_buf_mmap(dmabuf, vm, 0); + + mutex_unlock(&s_pu_mutex); + + return ret; +#else + return -EINVAL; +#endif +} + +unsigned long pu_mmap_kernel_buffer(unsigned long phys_addr, unsigned int size) +{ +#ifdef USE_ION_ALLOCATOR + unsigned long ret = 0; + + if (!size) + return 0; + + mutex_lock(&s_pu_mutex); + do { + int i; + struct dma_buf *dmabuf; + void * virt_addr; + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + break; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + if(dmabuf != NULL) + { + ret = dma_buf_begin_cpu_access(dmabuf, 0); + if (ret) { + printk(KERN_ERR "[PUWRAP] dma_buf_begin_cpu_access error ret=%d (size=%d) \n", ret, size); + break; + } + virt_addr = dma_buf_kmap(dmabuf, 0); + if (IS_ERR_OR_NULL(virt_addr)) { + printk(KERN_ERR "[PUWRAP] dma_buf_kmap error %p (size=%d) \n", virt_addr, size); + break; + } + + ret = (unsigned long)virt_addr; + } + } while(0); + mutex_unlock(&s_pu_mutex); + + return ret; +#endif +} + +void pu_unmap_kernel_buffer(unsigned long base, unsigned long phys_addr) +{ + if (!base) + return; + +#ifdef USE_ION_ALLOCATOR + mutex_lock(&s_pu_mutex); + do { + int i; + struct dma_buf *dmabuf; + + for (i = 0; i < NUM_ION_STRUCT; i++) + { + if (pu_ion_buffer[i].phys_addr == phys_addr) + break; + } + if (i == NUM_ION_STRUCT) + { + printk(KERN_ERR "[PUWRAP] can't find phys_addr:0x%lx !!!\n", (unsigned long)phys_addr); + break; + } + + dmabuf = (struct dma_buf *)pu_ion_buffer[i].dmabuf; + if(dmabuf != NULL) + { + dma_buf_kunmap(dmabuf, 0, (void *)base); + dma_buf_end_cpu_access(dmabuf, 0); + } + } while (0); + mutex_unlock(&s_pu_mutex); +#endif +} +#endif //#ifdef CONFIG_RTK_RESERVE_MEMORY + +int pu_set_dovi_flag(int nCoreIdx, int nInstIdx, unsigned int bEnable) +{ + int ret = 0; + //pr_info("VE1: dovi_flag[%p, %d, %d, %d], input[%d, %d, %d]\n", &dovi_flag, dovi_flag.nCoreIdx, dovi_flag.nInstIdx, dovi_flag.bEnable, nCoreIdx, nInstIdx, bEnable); + + mutex_lock(&s_dovi_mutex); + if (bEnable == 1) + { + if (dovi_flag.bEnable == 0) + { + dovi_flag.bEnable = 1; + dovi_flag.nCoreIdx = nCoreIdx; + dovi_flag.nInstIdx = nInstIdx; + ret = 1; + } + } + else + { + if (dovi_flag.bEnable == 1 && dovi_flag.nCoreIdx == nCoreIdx && dovi_flag.nInstIdx == nInstIdx) + { + dovi_flag.bEnable = 0; + dovi_flag.nCoreIdx = -1; + dovi_flag.nInstIdx = -1; + } + } + mutex_unlock(&s_dovi_mutex); + + return ret; +} + +static int pu_probe(struct platform_device *pdev) +{ + struct resource res; + struct device_node *node; + + printk(KERN_INFO "[PUWRAP] pu_probe\n"); + + node = pdev->dev.of_node; + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#ifdef USE_ION_ALLOCATOR + memset(pu_ion_buffer, 0, sizeof(struct rtkdrv_ion_buffer_t)*NUM_ION_STRUCT); + printk(KERN_INFO "[PUWRAP] success to probe pu wrapper device with USE_ION_ALLOCATOR\n"); +#else /* else USE_ION_ALLOCATOR */ + if(pdev) + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if(res) + { + s_memory.size = res->end - res->start; + s_memory.phys_addr = res->start; + } + else + { + s_memory.size = RTK_INIT_VIDEO_MEMORY_SIZE_IN_BYTE; + s_memory.phys_addr = RTK_DRAM_PHYSICAL_BASE; + } + + s_memory.base = (unsigned long)ioremap(s_memory.phys_addr, PAGE_ALIGN(s_memory.size)); + if (!s_memory.base) + { + printk(KERN_ERR "[PUWRAP] : fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n", (int)s_memory.phys_addr, (int)s_memory.base, (int)s_memory.size); + goto ERROR_PROVE_DEVICE; + } + if (vmem_init(&s_mem, s_memory.phys_addr, s_memory.size) < 0) + { + printk(KERN_ERR "[PUWRAP] : fail to init vmem system\n"); + goto ERROR_PROVE_DEVICE; + } + printk(KERN_INFO "[PUWRAP] success to probe pu wrapper device with reserved video memory phys_addr=0x%x, base = 0x%x\n", (int) s_memory.phys_addr, (int)s_memory.base); +#endif /* endif USE_ION_ALLOCATOR */ +#else /* else CONFIG_RTK_RESERVE_MEMORY */ + printk(KERN_INFO "[PUWRAP] success to probe pu wrapper device\n"); +#endif /* endif CONFIG_RTK_RESERVE_MEMORY */ + + + return 0; + + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#ifndef USE_ION_ALLOCATOR +ERROR_PROVE_DEVICE: + + return 0; +#endif +#endif +} + +static int pu_remove(struct platform_device *pdev) +{ + printk(KERN_INFO "[PUWRAP] pu_remove\n"); + +#ifdef CONFIG_RTK_RESERVE_MEMORY +#ifdef USE_ION_ALLOCATOR + + /* Todo release ion buffer */ + +#else /* else USE_ION_ALLOCATOR */ + if (s_memory.base) + { + iounmap((void *)s_memory.base); + s_memory.base = 0; + vmem_exit(&s_mem); + } +#endif /* endif USE_ION_ALLOCATOR */ +#endif /* endif CONFIG_RTK_RESERVE_MEMORY */ + + return 0; +} + +#if 0 +static struct platform_driver pu_driver = { + .driver = { + .name = PU_PLATFORM_DEVICE_NAME, + }, + .probe = pu_probe, + .remove = pu_remove, +}; +#endif + +static ssize_t pu_memsize_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", (int)(get_num_physpages() << PAGE_SHIFT)); +} + +static struct kobj_attribute pu_memsize_attr = + __ATTR(pu_memsize, 0644, pu_memsize_show, NULL); + +static struct attribute *pu_attrs[] = { + &pu_memsize_attr.attr, + NULL, +}; + +static struct attribute_group rtk_pu_attr_group = { + .attrs = pu_attrs, +}; + +static struct kobject *pu_kobj; + +static int __init pu_init(void) +{ + int res = 0; + + pu_kobj = kobject_create_and_add("rtk_pu", kernel_kobj); + if (pu_kobj) + { + res = sysfs_create_group(pu_kobj, &rtk_pu_attr_group); + if (res) + printk(KERN_WARNING "[PUWRAP] %d: unable to create sysfs entry\n", __LINE__); + } + else + printk(KERN_WARNING "[PUWRAP] %d: unable to create sysfs entry\n", __LINE__); + + printk(KERN_INFO "[PUWRAP] begin pu_init\n"); + //res = platform_driver_register(&pu_driver); + printk(KERN_INFO "[PUWRAP] end pu_init result=0x%x\n", res); + return res; +} + +static void __exit pu_exit(void) +{ + printk(KERN_INFO "[PUWRAP] pu_exit\n"); + //platform_driver_unregister(&pu_driver); + return; +} + + +static const struct of_device_id rtk_pu_dt_match[] = { + { .compatible = "Realtek,rtd13xx-pu_pll" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_pu_dt_match); + +const struct dev_pm_ops rtk_pu_pmops = { + .suspend = NULL, + .resume = NULL, +}; + +static struct platform_driver rtk_pu_driver = { + .driver = { + .name = "rtk-pu", + .owner = THIS_MODULE, + .of_match_table = rtk_pu_dt_match, + //.pm = SDHCI_PLTFM_PMOPS, + .pm = &rtk_pu_pmops, + }, + .probe = pu_probe, + .remove = pu_remove, +}; + +module_platform_driver(rtk_pu_driver); + +MODULE_AUTHOR("RTK Wrapper for JPU & VPU, Inc."); +MODULE_DESCRIPTION("PU WRAPPER linux driver"); +MODULE_LICENSE("GPL"); + +module_init(pu_init); +module_exit(pu_exit); diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.h new file mode 100644 index 000000000000..f065d2157efa --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/puwrap.h @@ -0,0 +1,44 @@ + + +#ifndef __PU_DRV_H__ +#define __PU_DRV_H__ + +#include +#include +#include + +#define PDI_IOCTL_MAGIC 'V' + +#define PLL_CLK_715 (0x10D336) +#define PLL_CLK_702 (0x10C186) +#define PLL_CLK_675 (0x10C176) +#define PLL_CLK_648 (0x10C166) +#define PLL_CLK_594 (0x10C146) +#define PLL_CLK_567 (0x10C136) +#define PLL_CLK_337 (0x12C176) +#define PLL_CLK_297 (0x12C146) + +#define UNUSED_PARAMETER(p) (void)(p) + +#define MISC_JPU_MINOR 107 +#define MISC_MEM_MINOR 108 +#define MISC_VE3_MINOR 109 +#define MISC_VE1_MINOR 110 + +typedef struct pu_drv_context_t { + struct fasync_struct *async_queue; + unsigned long jpu_interrupt_reason; + unsigned long vpu_interrupt_reason; +} pu_drv_context_t; + +#ifdef CONFIG_RTK_RESERVE_MEMORY +int pu_alloc_dma_buffer(unsigned int size, unsigned long *phys_addr, unsigned long *base, unsigned int mem_type); +void pu_free_dma_buffer(unsigned long base, unsigned long phys_addr); +int pu_mmap_dma_buffer(struct vm_area_struct *vm); +unsigned long pu_mmap_kernel_buffer(unsigned long phys_addr, unsigned int size); +void pu_unmap_kernel_buffer(unsigned long base, unsigned long phys_addr); +#endif +void pu_pll_setting(unsigned long offset, unsigned int value, unsigned int bOverwrite, unsigned int bEnable); +int pu_set_dovi_flag(int nCoreIdx, int nInstIdx, unsigned int bEnable); + +#endif diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/Makefile b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/Makefile new file mode 100644 index 000000000000..395f0962b1f3 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/Makefile @@ -0,0 +1,6 @@ +# rtk_vcodec + +obj-$(CONFIG_RTD16XXB_VE1_CODEC) += ve1.o +ifdef CONFIG_COMPAT +obj-$(CONFIG_RTD16XXB_VE1_CODEC) += compat_ve1.o +endif diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.c b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.c new file mode 100644 index 000000000000..c9b4619b89f5 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.c @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "ve1.h" +#include "compat_ve1.h" + +/* See drivers/soc/realtek/rtd129x/rtk_ve/ve1/ve1.h for the definition of these structs */ +typedef struct compat_vpudrv_buffer_t { + compat_uint_t size; + compat_ulong_t phys_addr; + compat_ulong_t base; /* kernel logical address in use kernel */ + compat_ulong_t virt_addr; /* virtual user space address */ + compat_uint_t mem_type; +} compat_vpudrv_buffer_t; + +typedef struct compat_vpu_clock_info_t{ + compat_uint_t core_idx; + compat_uint_t enable; + compat_uint_t value; +} compat_vpu_clock_info_t; + +typedef struct compat_vpudrv_inst_info_t { + compat_uint_t core_idx; + compat_uint_t inst_idx; + compat_int_t inst_open_count; /* for output only*/ +} compat_vpudrv_inst_info_t; + +typedef struct compat_vpudrv_intr_info_t { + compat_uint_t core_idx; + compat_uint_t timeout; + compat_int_t intr_reason; +#ifdef SUPPORT_MULTI_INST_INTR + compat_int_t intr_inst_index; +#endif +} compat_vpudrv_intr_info_t; + +typedef struct compat_vpudrv_dovi_info_t{ + compat_uint_t core_idx; + compat_uint_t inst_idx; + compat_uint_t enable; +} compat_vpudrv_dovi_info_t; + +#define COMPAT_VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(VDI_IOCTL_MAGIC, 0) +#define COMPAT_VDI_IOCTL_FREE_PHYSICALMEMORY _IO(VDI_IOCTL_MAGIC, 1) +#define COMPAT_VDI_IOCTL_WAIT_INTERRUPT _IO(VDI_IOCTL_MAGIC, 2) +#define COMPAT_VDI_IOCTL_GET_INSTANCE_POOL _IO(VDI_IOCTL_MAGIC, 5) +#define COMPAT_VDI_IOCTL_GET_COMMON_MEMORY _IO(VDI_IOCTL_MAGIC, 6) +#define COMPAT_VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(VDI_IOCTL_MAGIC, 8) +#define COMPAT_VDI_IOCTL_OPEN_INSTANCE _IO(VDI_IOCTL_MAGIC, 9) +#define COMPAT_VDI_IOCTL_CLOSE_INSTANCE _IO(VDI_IOCTL_MAGIC, 10) +#define COMPAT_VDI_IOCTL_GET_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 11) +#define COMPAT_VDI_IOCTL_GET_REGISTER_INFO _IO(VDI_IOCTL_MAGIC, 12) + +/* RTK ioctl */ +#define COMPAT_VDI_IOCTL_SET_RTK_CLK_GATING _IO(VDI_IOCTL_MAGIC, 16) +#define COMPAT_VDI_IOCTL_SET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 17) +#define COMPAT_VDI_IOCTL_GET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 18) +#define COMPAT_VDI_IOCTL_GET_RTK_SUPPORT_TYPE _IO(VDI_IOCTL_MAGIC, 19) +#define COMPAT_VDI_IOCTL_SET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 21) +#define COMPAT_VDI_IOCTL_GET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 22) +#define COMPAT_VDI_IOCTL_SET_RTK_DOVI_FLAG _IO(VDI_IOCTL_MAGIC, 23) +#define COMPAT_VDI_IOCTL_GET_TOTAL_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 24) +#define COMPAT_VDI_IOCTL_GET_RTK_DCSYS_INFO _IO(VDI_IOCTL_MAGIC, 25) + +static int compat_get_ve1_buffer_data( + compat_vpudrv_buffer_t __user *data32, + vpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + compat_uint_t m; + int err; + + err = get_user(s, &data32->size); + err |= put_user(s, &data->size); + err |= get_user(p, &data32->phys_addr); + err |= put_user(p, &data->phys_addr); + err |= get_user(b, &data32->base); + err |= put_user(b, &data->base); + err |= get_user(v, &data32->virt_addr); + err |= put_user(v, &data->virt_addr); + err |= get_user(m, &data32->mem_type); + err |= put_user(m, &data->mem_type); + + return err; +} + +static int compat_get_ve1_inst_info_data( + compat_vpudrv_inst_info_t __user *data32, + vpudrv_inst_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t i; + compat_int_t ioc; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(i, &data32->inst_idx); + err |= put_user(i, &data->inst_idx); + err |= get_user(ioc, &data32->inst_open_count); + err |= put_user(ioc, &data->inst_open_count); + + return err; +} + +static int compat_get_ve1_intr_info_data( + compat_vpudrv_intr_info_t __user *data32, + vpudrv_intr_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(t, &data32->timeout); + err |= put_user(t, &data->timeout); + err |= get_user(i, &data32->intr_reason); + err |= put_user(i, &data->intr_reason); +#ifdef SUPPORT_MULTI_INST_INTR + err |= get_user(i, &data32->intr_inst_index); + err |= put_user(i, &data->intr_inst_index); +#endif + + return err; +} + +static int compat_get_ve1_clock_info( + compat_vpu_clock_info_t __user *data32, + vpu_clock_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t e; + compat_uint_t v; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(e, &data32->enable); + err |= put_user(e, &data->enable); + err |= get_user(v, &data32->value); + err |= put_user(v, &data->value); + + return err; +} + +static int compat_get_ve1_dovi_info( + compat_vpudrv_dovi_info_t __user *data32, + vpudrv_dovi_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t e; + compat_uint_t i; + int err; + + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(i, &data32->inst_idx); + err |= put_user(i, &data->inst_idx); + err |= get_user(e, &data32->enable); + err |= put_user(e, &data->enable); + + return err; +} + +static int compat_put_ve1_buffer_data( + compat_vpudrv_buffer_t __user *data32, + vpudrv_buffer_t __user *data) +{ + compat_uint_t s; + compat_ulong_t p; + compat_ulong_t b; + compat_ulong_t v; + compat_uint_t m; + int err; + + err = get_user(s, &data->size); + err |= put_user(s, &data32->size); + err |= get_user(p, &data->phys_addr); + err |= put_user(p, &data32->phys_addr); + err |= get_user(b, &data->base); + err |= put_user(b, &data32->base); + err |= get_user(v, &data->virt_addr); + err |= put_user(v, &data32->virt_addr); + err |= get_user(m, &data->mem_type); + err |= put_user(m, &data32->mem_type); + + return err; +} + +static int compat_put_ve1_inst_info_data( + compat_vpudrv_inst_info_t __user *data32, + vpudrv_inst_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t i; + compat_int_t ioc; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(i, &data->inst_idx); + err |= put_user(i, &data32->inst_idx); + err |= get_user(ioc, &data->inst_open_count); + err |= put_user(ioc, &data32->inst_open_count); + + return err; +} + +static int compat_put_ve1_intr_info_data( + compat_vpudrv_intr_info_t __user *data32, + vpudrv_intr_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t t; + compat_int_t i; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(t, &data->timeout); + err |= put_user(t, &data32->timeout); + err |= get_user(i, &data->intr_reason); + err |= put_user(i, &data32->intr_reason); + + return err; +} + +static int compat_put_ve1_clock_info( + compat_vpu_clock_info_t __user *data32, + vpu_clock_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t e; + compat_uint_t v; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(e, &data->enable); + err |= put_user(e, &data32->enable); + err |= get_user(v, &data->value); + err |= put_user(v, &data32->value); + + return err; +} + +static int compat_put_ve1_dovi_info( + compat_vpudrv_dovi_info_t __user *data32, + vpudrv_dovi_info_t __user *data) +{ + compat_uint_t c; + compat_uint_t i; + compat_uint_t e; + int err; + + err = get_user(c, &data->core_idx); + err |= put_user(c, &data32->core_idx); + err |= get_user(i, &data->inst_idx); + err |= put_user(i, &data32->inst_idx); + err |= get_user(e, &data->enable); + err |= put_user(e, &data32->enable); + + return err; +} + +long compat_vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + + if (!filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) { + case COMPAT_VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_FREE_PHYSICALMEMORY: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_FREE_PHYSICALMEMORY, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_WAIT_INTERRUPT: + { + compat_vpudrv_intr_info_t __user *data32; + vpudrv_intr_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_intr_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_WAIT_INTERRUPT, (unsigned long)data); + err = compat_put_ve1_intr_info_data(data32, data); + return ret ? ret : err; + } + + case VDI_IOCTL_SET_CLOCK_GATE: + case VDI_IOCTL_RESET: + case VDI_IOCTL_GET_RTK_ASIC_REVISION: + { + return filp->f_op->unlocked_ioctl(filp, cmd, + (unsigned long)compat_ptr(arg)); + } + + case COMPAT_VDI_IOCTL_GET_INSTANCE_POOL: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_INSTANCE_POOL, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_COMMON_MEMORY: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_COMMON_MEMORY, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_OPEN_INSTANCE: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_OPEN_INSTANCE, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_CLOSE_INSTANCE: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_CLOSE_INSTANCE, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_INSTANCE_NUM: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_INSTANCE_NUM, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_REGISTER_INFO: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_REGISTER_INFO, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_SET_RTK_CLK_GATING: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_CLK_GATING, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_SET_RTK_CLK_PLL: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_CLK_PLL, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_GET_RTK_CLK_PLL: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_CLK_PLL, (unsigned long)data); + err = compat_put_ve1_clock_info(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_SET_RTK_CLK_SELECT: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_CLK_SELECT, (unsigned long)data); + } + + case COMPAT_VDI_IOCTL_GET_RTK_CLK_SELECT: + { + compat_vpu_clock_info_t __user *data32; + vpu_clock_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_clock_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_CLK_SELECT, (unsigned long)data); + err = compat_put_ve1_clock_info(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_SET_RTK_DOVI_FLAG: + { + compat_vpudrv_dovi_info_t __user *data32; + vpudrv_dovi_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_dovi_info(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_SET_RTK_DOVI_FLAG, (unsigned long)data); + err = compat_put_ve1_dovi_info(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_RTK_SUPPORT_TYPE: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_SUPPORT_TYPE, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_RTK_DCSYS_INFO: + { + compat_vpudrv_buffer_t __user *data32; + vpudrv_buffer_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_buffer_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_RTK_DCSYS_INFO, (unsigned long)data); + err = compat_put_ve1_buffer_data(data32, data); + return ret ? ret : err; + } + + case COMPAT_VDI_IOCTL_GET_TOTAL_INSTANCE_NUM: + { + compat_vpudrv_inst_info_t __user *data32; + vpudrv_inst_info_t __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + + err = compat_get_ve1_inst_info_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, VDI_IOCTL_GET_TOTAL_INSTANCE_NUM, (unsigned long)data); + err = compat_put_ve1_inst_info_data(data32, data); + return ret ? ret : err; + } + + default: + { + printk(KERN_ERR "[COMPAT_VPUDRV] No such IOCTL, cmd is %d\n", cmd); + return -ENOIOCTLCMD; + } + } +} diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.h new file mode 100644 index 000000000000..15c1161487c6 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/compat_ve1.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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_COMPAT_VE1_H +#define _LINUX_COMPAT_VE1_H + +#if IS_ENABLED(CONFIG_COMPAT) + +typedef struct compat_vpu_bit_firmware_info_t { + compat_uint_t size; /* size of this structure*/ + compat_uint_t core_idx; + compat_ulong_t reg_base_offset; + compat_ushort_t bit_code[512]; +} compat_vpu_bit_firmware_info_t; + +long compat_vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +typedef struct compat_vpu_bit_firmware_info_t { + unsigned int size; /* size of this structure*/ + unsigned int core_idx; + unsigned long reg_base_offset; + unsigned short bit_code[512]; +} compat_vpu_bit_firmware_info_t; + +#define compat_vpu_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_VE1_H */ diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.c b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.c new file mode 100644 index 000000000000..8acd91e6508b --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.c @@ -0,0 +1,1682 @@ +/* + * ve1.c + * + * linux device driver for VE1. + * + * Copyright (C) 2006 - 2013 REALTEK INC. + * + * This 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. + * + * This 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 this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#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 + +#ifdef CONFIG_COMPAT +#include +#endif + +#include "ve1config.h" +#include "ve1.h" +#include "compat_ve1.h" +#include "../puwrap.h" + +//#define ENABLE_DEBUG_MSG +#ifdef ENABLE_DEBUG_MSG +#define DPRINTK(args...) pr_info(args); +#else +#define DPRINTK(args...) +#endif /* ENABLE_DEBUG_MSG */ + +#define DEV_NAME "[RTK_VE1]" +#define DISABLE_ORIGIN_SUSPEND +#define USE_HRTIMEOUT_INSTEAD_OF_TIMEOUT + +/* definitions to be changed as customer configuration */ +/* if you want to have clock gating scheme frame by frame */ +/* #define VPU_SUPPORT_CLOCK_CONTROL */ + +/* if the driver want to use interrupt service from kernel ISR */ +#define VPU_SUPPORT_ISR + +/* if the platform driver knows the name of this driver */ +/* VPU_PLATFORM_DEVICE_NAME */ +#define VPU_SUPPORT_PLATFORM_DRIVER_REGISTER + +/* if this driver knows the dedicated video memory address */ +#ifndef CONFIG_RTK_RESERVE_MEMORY +#ifdef CONFIG_RTK_PLATFORM_FPGA +#define VPU_SUPPORT_RESERVED_VIDEO_MEMORY +#endif +#endif + +#define VPU_PLATFORM_DEVICE_NAME "vdec" +#define VPU_CLK_NAME "vcodec" +#define VPU_DEV_NAME "vpu" + +/* if the platform driver knows this driver */ +/* the definition of VPU_REG_BASE_ADDR and VPU_REG_SIZE are not meaningful */ + +#define VPU_REG_BASE_ADDR 0x98040000 +#define VPU_REG_SIZE (0xC000) +#define MS_TO_NS(x) (x * 1E6L) + +#ifdef VPU_SUPPORT_ISR +#define VE1_IRQ_NUM (85) +#endif + +/* this definition is only for realtek FPGA board env */ +/* so for SOC env of customers can be ignored */ + +#ifndef VM_RESERVED /*for kernel up to 3.7.0 version*/ +# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) +#endif + +typedef struct vpu_drv_context_t { + struct fasync_struct *async_queue; + unsigned long interrupt_reason_ve1; + /* !<< device reference count. Not instance count */ + u32 open_count; +} vpu_drv_context_t; + +/* To track the allocated memory buffer */ +typedef struct vpudrv_buffer_pool_t { + struct list_head list; + struct vpudrv_buffer_t vb; + struct file *filp; +} vpudrv_buffer_pool_t; + +/* To track the instance index and buffer in instance pool */ +typedef struct vpudrv_instanace_list_t { + struct list_head list; + unsigned long inst_idx; + unsigned long core_idx; + struct file *filp; +} vpudrv_instanace_list_t; + +typedef struct vpudrv_instance_pool_t { + unsigned char codecInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE]; + long long pendingInstIdxPlus1; + void *pendingInst; +} vpudrv_instance_pool_t; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY +#define VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE 0x0b800000 //(62*1024*1024) +#define VPU_DRAM_PHYSICAL_BASE 0x03200000 //0x86C00000 +#include "vmm.h" +static video_mm_t s_vmem; +static vpudrv_buffer_t s_video_memory = {0}; +#endif /*VPU_SUPPORT_RESERVED_VIDEO_MEMORY*/ + +static int vpu_hw_reset(u32 coreIdx); + +/* end customer definition */ +static vpudrv_buffer_t s_instance_pool = {0}; +static vpudrv_buffer_t s_common_memory = {0}; +static vpu_drv_context_t s_vpu_drv_context; +static struct miscdevice s_vpu_dev; + +static struct device *p_vpu_dev; +static int s_vpu_open_ref_count; + +#ifdef VPU_SUPPORT_ISR +static int s_ve1_irq = VE1_IRQ_NUM; +#endif /* VPU_SUPPORT_ISR */ + +static int ve_cti_en = 1; +/* FIX ME after ver.B IC */ +static int ve_idle_en = 0; + +static vpudrv_buffer_t s_vpu_register = {0}; +static vpudrv_buffer_t s_dc_register = {0}; +static vpudrv_buffer_t s_bond_register = {0}; +static vpudrv_buffer_t s_dmc_register = {0}; + +static atomic_t s_interrupt_flag_ve1; +static wait_queue_head_t s_interrupt_wait_q_ve1; + +static spinlock_t s_vpu_lock = __SPIN_LOCK_UNLOCKED(s_vpu_lock); +static spinlock_t s_ve1_lock = __SPIN_LOCK_UNLOCKED(s_ve1_lock); +static DEFINE_SEMAPHORE(s_vpu_sem); +static struct list_head s_vbp_head = LIST_HEAD_INIT(s_vbp_head); +static struct list_head s_inst_list_head = LIST_HEAD_INIT(s_inst_list_head); + +static vpu_bit_firmware_info_t s_bit_firmware_info[MAX_NUM_VPU_CORE]; + +#define BIT_BASE 0x0000 +#define BIT_INT_STS (BIT_BASE + 0x010) +#define BIT_INT_REASON (BIT_BASE + 0x174) +#define BIT_INT_CLEAR (BIT_BASE + 0x00C) +#define VE_CTRL_REG (BIT_BASE + 0x3000) +#define VE_CTI_GRP_REG (BIT_BASE + 0x3004) +#define VE_INT_STS_REG (BIT_BASE + 0x3020) +#define VE_MBIST_CTRL (BIT_BASE + 0x3C08) +#define VE_BISR_POWER_RESET (BIT_BASE + 0x3CB0) + +#ifdef CONFIG_PM +/* implement to power management functions */ +#define BIT_CODE_RUN (BIT_BASE + 0x000) +#define BIT_CODE_DOWN (BIT_BASE + 0x004) +#define BIT_INT_CLEAR (BIT_BASE + 0x00C) +#define BIT_INT_STS (BIT_BASE + 0x010) +#define BIT_CODE_RESET (BIT_BASE + 0x014) +#define BIT_INT_REASON (BIT_BASE + 0x174) +#define BIT_BUSY_FLAG (BIT_BASE + 0x160) +#define BIT_RUN_COMMAND (BIT_BASE + 0x164) +#define BIT_RUN_INDEX (BIT_BASE + 0x168) +#define BIT_RUN_COD_STD (BIT_BASE + 0x16C) + +/* Product register */ +#define VPU_PRODUCT_CODE_REGISTER (BIT_BASE + 0x1044) + +#ifndef DISABLE_ORIGIN_SUSPEND +static u32 s_vpu_reg_store[MAX_NUM_VPU_CORE][64]; +#endif +#endif /* CONFIG_PM */ + +/* + * common struct and definition + */ +#define ReadVpuRegister(addr, core) *(volatile unsigned int *)(s_vpu_register.virt_addr + (0x8000 * core) + addr) +#define WriteVpuRegister(addr, val, core) *(volatile unsigned int *)(s_vpu_register.virt_addr + (0x8000 * core) + addr) = (unsigned int)val +#define WriteVpu(addr, val) *(volatile unsigned int *)(addr) = (unsigned int)val; + +static void ve1_wrapper_setup(unsigned int coreIdx) +{ + unsigned int ctrl_1; + unsigned int ctrl_2; + unsigned int ctrl_3; + unsigned int ctrl_4; + + /* coreIdx == 0 */ + if ((coreIdx & (1 << 0)) != 0) { + ctrl_1 = ReadVpuRegister(VE_CTRL_REG, 0); + ctrl_2 = ReadVpuRegister(VE_CTI_GRP_REG, 0); + ctrl_3 = ReadVpuRegister(VE_BISR_POWER_RESET, 0); + ctrl_1 |= (ve_cti_en << 1 | ve_idle_en << 6); + /* ve1_cti_cmd_depth for 1296 timing issue */ + ctrl_2 = (ctrl_2 & ~(0x3f << 24)) | (0x1a << 24); + ctrl_3 |= (1<<12); + /*Set BISR POWER RESET bit12 to 1, make AXI available in stark*/ + WriteVpuRegister(VE_CTRL_REG, ctrl_1, 0); + WriteVpuRegister(VE_CTI_GRP_REG, ctrl_2, 0); + WriteVpuRegister(VE_BISR_POWER_RESET, ctrl_3, 0); + + int i; + for(i=0;i<2;i++) { //workaround for TP1CK MEM TEST1 in stark + ctrl_4 = ReadVpuRegister(VE_MBIST_CTRL, 0); + ctrl_4 ^= (1<<2); //toggle TEST1 signal of MEM + WriteVpuRegister(VE_MBIST_CTRL, ctrl_4, 0); + } + } +} + +static struct clk *ve_clk; +static struct reset_control *ve_rstc; +static struct reset_control *ve_rstc_bist; + +static void rtk_ve1_power_on(void) +{ + pr_debug("%s\n", __func__); + reset_control_deassert(ve_rstc_bist); + reset_control_deassert(ve_rstc); + clk_prepare_enable(ve_clk); +} + +static void rtk_ve1_power_off(void) +{ + pr_debug("%s\n", __func__); + clk_disable_unprepare(ve_clk); + reset_control_assert(ve_rstc); + reset_control_assert(ve_rstc_bist); +} + +int vpu_hw_reset(u32 coreIdx) +{ + reset_control_reset(ve_rstc); + ve1_wrapper_setup((1 << coreIdx)); + return 0; +} + +static int rtk_power_callback(struct notifier_block *nb, unsigned long action, void *unused) +{ + if (action == RTK_PD_NOTIFY_PRE_ON) { + rtk_ve1_power_on(); + return NOTIFY_OK; + } + + if (action == RTK_PD_NOTIFY_OFF) { + rtk_ve1_power_off(); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static struct notifier_block ve_power_nb = { + .notifier_call = rtk_power_callback, +}; + + +static int vpu_alloc_dma_buffer(vpudrv_buffer_t *vb) +{ + unsigned int ret; + + if (!vb) + return -1; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + UNUSED_PARAMETER(ret); + vb->phys_addr = (unsigned long)vmem_alloc(&s_vmem, vb->size, 0); + if ((unsigned long)vb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } + + vb->base = (unsigned long)(s_video_memory.base + (vb->phys_addr - s_video_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + ret = pu_alloc_dma_buffer(vb->size, &vb->phys_addr, &vb->base, vb->mem_type); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#else + UNUSED_PARAMETER(ret); + vb->base = (unsigned long)dma_alloc_coherent(s_vpu_dev.this_device, PAGE_ALIGN(vb->size), (dma_addr_t *) (&vb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(vb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + DPRINTK("%s base:0x%lx, phy_addr:0x%lx, size:%d\n", DEV_NAME, vb->base, vb->phys_addr, vb->size); + return 0; +} + +static int vpu_alloc_dma_buffer2(vpudrv_buffer_t *vb) +{ + unsigned int ret; + + if (!vb) + return -1; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + UNUSED_PARAMETER(ret); + vb->phys_addr = (unsigned long)vmem_alloc(&s_vmem, vb->size, 0); + if ((unsigned long)vb->phys_addr == (unsigned long)-1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } + + vb->base = (unsigned long)(s_video_memory.base + (vb->phys_addr - s_video_memory.phys_addr)); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + ret = pu_alloc_dma_buffer(vb->size, &vb->phys_addr, &vb->base, vb->mem_type); + if (ret == -1) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } + vb->base = pu_mmap_kernel_buffer(vb->phys_addr, vb->size); + if ((void *)(vb->base) == NULL) { + pr_err("%s pu_mmap_kernel_buffer error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#else + UNUSED_PARAMETER(ret); + vb->base = (unsigned long)dma_alloc_coherent(s_vpu_dev.this_device, PAGE_ALIGN(vb->size), (dma_addr_t *) (&vb->phys_addr), GFP_DMA | GFP_KERNEL); + if ((void *)(vb->base) == NULL) { + pr_err("%s Physical memory allocation error size=%d\n", DEV_NAME, vb->size); + return -1; + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + DPRINTK("%s base:0x%lx, phy_addr:0x%lx, size:%d\n", DEV_NAME, vb->base, vb->phys_addr, vb->size); + return 0; +} + +static void vpu_free_dma_buffer(vpudrv_buffer_t *vb) +{ + if (!vb) + return; + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (vb->base) + vmem_free(&s_vmem, vb->phys_addr, 0); +#elif defined(CONFIG_RTK_RESERVE_MEMORY) + pu_free_dma_buffer(vb->base, vb->phys_addr); +#else + if (vb->base) { + dma_free_coherent(s_vpu_dev.this_device, PAGE_ALIGN(vb->size), (void *)vb->base, vb->phys_addr); + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ +} + +/* size=40 for Android M */ +#define PTHREAD_MUTEX_T_HANDLE_SIZE 40 + +static int vpu_free_instances(struct file *filp) +{ + vpudrv_instanace_list_t *vil, *n; + vpudrv_instance_pool_t *vip; + void *vip_base; + int instance_pool_size_per_core; + void *vdi_mutexes_base; + const int PTHREAD_MUTEX_T_DESTROY_VALUE = 0xdead10cc; + + DPRINTK("%s vpu_free_instances\n", DEV_NAME); + + /* s_instance_pool.size assigned to the size of all core once call VDI_IOCTL_GET_INSTANCE_POOL by user. */ + instance_pool_size_per_core = (s_instance_pool.size/MAX_NUM_VPU_CORE); + + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->filp == filp) { + int i, j; + for (i = 0; i < MAX_NUM_INSTANCE; i++) /* reset dovi flag */ + { + for (j = 0; j < MAX_NUM_VPU_CORE; j++) + { + pu_set_dovi_flag(j, i, 0); + } + } + + vip_base = (void *)(s_instance_pool.base + (instance_pool_size_per_core*vil->core_idx)); + DPRINTK("%s vpu_free_instances detect instance crash instIdx=%d, coreIdx=%d, vip_base=%p, instance_pool_size_per_core=%d\n", DEV_NAME, (int)vil->inst_idx, (int)vil->core_idx, vip_base, (int)instance_pool_size_per_core); + vip = (vpudrv_instance_pool_t *)vip_base; + + if (vip) { + /* only first 4 byte is key point(inUse of CodecInst in vpuapi) to free the corresponding instance. */ + memset(&vip->codecInstPool[vil->inst_idx], 0x00, 4); + + if (vil->inst_idx == (vip->pendingInstIdxPlus1-1) && vip->pendingInst != 0) { + pr_warn("%s vil->inst_idx:%d, vil->core_idx:%d is pending, clear in here\n", DEV_NAME, (int)vil->inst_idx, (int)vil->core_idx); + vip->pendingInst = 0; + vip->pendingInstIdxPlus1 = 0; + } + + vdi_mutexes_base = (vip_base + (instance_pool_size_per_core - PTHREAD_MUTEX_T_HANDLE_SIZE*4)); + DPRINTK("%s vpu_free_instances : force to destroy vdi_mutexes_base=%p in userspace \n", DEV_NAME, vdi_mutexes_base); + if (vdi_mutexes_base) { + int i; + for (i = 0; i < 4; i++) { + memcpy(vdi_mutexes_base, &PTHREAD_MUTEX_T_DESTROY_VALUE, sizeof(PTHREAD_MUTEX_T_DESTROY_VALUE)); + vdi_mutexes_base += PTHREAD_MUTEX_T_HANDLE_SIZE; + } + } + } + s_vpu_open_ref_count--; + list_del(&vil->list); + kfree(vil); + } + } + return 1; +} + +static int vpu_free_buffers(struct file *filp) +{ + vpudrv_buffer_pool_t *pool, *n; + vpudrv_buffer_t vb; + + DPRINTK("%s vpu_free_buffers\n", DEV_NAME); + + list_for_each_entry_safe(pool, n, &s_vbp_head, list) { + if (pool->filp == filp) { + vb = pool->vb; + if (vb.base) { + vpu_free_dma_buffer(&vb); + list_del(&pool->list); + kfree(pool); + } + } + } + + return 0; +} + +static irqreturn_t ve1_irq_handler(int irq, void *dev_id) +{ + vpu_drv_context_t *dev = (vpu_drv_context_t *)dev_id; + + /* this can be removed. it also work in VPU_WaitInterrupt of API function */ + int core = 0; + unsigned long interrupt_reason_ve1 = 0; + unsigned int vpu_int_sts_ve1 = 0; + unsigned long flags; + + /* it means that we didn't get an information the current core from API layer. No core activated.*/ + if (s_bit_firmware_info[core].size == 0) { + pr_err("[VPUDRV] : s_bit_firmware_info[core].size is zero\n"); + return IRQ_HANDLED; + } + + vpu_int_sts_ve1 = ReadVpuRegister(BIT_INT_STS, core); + if (vpu_int_sts_ve1) { + interrupt_reason_ve1 = ReadVpuRegister(BIT_INT_REASON, core); + WriteVpuRegister(BIT_INT_REASON, 0, core); + WriteVpuRegister(BIT_INT_CLEAR, 0x1, core); + } + + //DPRINTK("%s VE1 intr_reason: 0x%08lx\n", DEV_NAME, dev->interrupt_reason_ve1); + + if (dev->async_queue) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* notify the interrupt to user space */ + + if (vpu_int_sts_ve1) { + if (core == 0) { + dev->interrupt_reason_ve1 = interrupt_reason_ve1; + atomic_set(&s_interrupt_flag_ve1, 1); + wake_up_interruptible(&s_interrupt_wait_q_ve1); + } + //DPRINTK("%s [-]%s\n", DEV_NAME, __func__); + } + + return IRQ_HANDLED; +} + +static int vpu_open(struct inode *inode, struct file *filp) +{ + DPRINTK("%s [+] %s\n", DEV_NAME, __func__); + spin_lock(&s_vpu_lock); + + s_vpu_drv_context.open_count++; + + filp->private_data = (void *)(&s_vpu_drv_context); + spin_unlock(&s_vpu_lock); + + DPRINTK("%s [-] %s\n", DEV_NAME, __func__); + + return 0; +} + +/*static int vpu_ioctl(struct inode *inode, struct file *filp, u_int cmd, u_long arg) // for kernel 2.6.9*/ +static long vpu_ioctl(struct file *filp, u_int cmd, u_long arg) +{ + int ret = 0; + struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)filp->private_data; + + switch (cmd) { + case VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY: + { + vpudrv_buffer_pool_t *vbp; + + DPRINTK("%s [+]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + vbp = kzalloc(sizeof(*vbp), GFP_KERNEL); + if (!vbp) { + up(&s_vpu_sem); + return -ENOMEM; + } + + ret = copy_from_user(&(vbp->vb), (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret) { + kfree(vbp); + up(&s_vpu_sem); + return -EFAULT; + } + + ret = vpu_alloc_dma_buffer(&(vbp->vb)); + if (ret == -1) { + ret = -ENOMEM; + kfree(vbp); + up(&s_vpu_sem); + break; + } + + ret = copy_to_user((void __user *)arg, &(vbp->vb), sizeof(vpudrv_buffer_t)); + if (ret) { + kfree(vbp); + ret = -EFAULT; + up(&s_vpu_sem); + break; + } + + vbp->filp = filp; + spin_lock(&s_vpu_lock); + list_add(&vbp->list, &s_vbp_head); + spin_unlock(&s_vpu_lock); + + up(&s_vpu_sem); + } + DPRINTK("%s [-]VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY\n", DEV_NAME); + } + break; + case VDI_IOCTL_FREE_PHYSICALMEMORY: + { + vpudrv_buffer_pool_t *vbp, *n; + vpudrv_buffer_t vb; + + DPRINTK("%s [+]VDI_IOCTL_FREE_PHYSICALMEMORY\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + ret = copy_from_user(&vb, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret) { + up(&s_vpu_sem); + return -EACCES; + } + + if (vb.base) + vpu_free_dma_buffer(&vb); + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vbp, n, &s_vbp_head, list) { + if (vbp->vb.phys_addr == vb.phys_addr/*vbp->vb.base == vb.base*/) { + list_del(&vbp->list); + kfree(vbp); + break; + } + } + spin_unlock(&s_vpu_lock); + + up(&s_vpu_sem); + } + DPRINTK("%s [-]VDI_IOCTL_FREE_PHYSICALMEMORY\n", DEV_NAME); + } + break; + case VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO: + { +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + DPRINTK("%s [+]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n", DEV_NAME); + if (s_video_memory.base != 0) { + ret = copy_to_user((void __user *)arg, &s_video_memory, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = -EFAULT; + } + DPRINTK("%s [-]VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO\n", DEV_NAME); +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + } + break; + + case VDI_IOCTL_WAIT_INTERRUPT: + { + vpudrv_intr_info_t info; + unsigned long flags; +#ifdef SUPPORT_MULTI_INST_INTR + u32 intr_inst_index; + u32 intr_reason_in_q; + u32 interrupt_flag_in_q; +#endif + DPRINTK("[VPUDRV][+]VDI_IOCTL_WAIT_INTERRUPT\n"); + ret = copy_from_user(&info, (vpudrv_intr_info_t *)arg, sizeof(vpudrv_intr_info_t)); + if (ret != 0) + return -EFAULT; + + /* VE1 */ + if (info.core_idx == 0) { + smp_rmb(); + ret = wait_event_interruptible_timeout(s_interrupt_wait_q_ve1, atomic_read(&s_interrupt_flag_ve1) != 0, msecs_to_jiffies(info.timeout)); + if (!ret) { + ret = -ETIME; + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + //DPRINTK("[VPUDRV] s_interrupt_flag_ve1(%d), reason(0x%08lx)\n", atomic_read(&s_interrupt_flag_ve1), dev->interrupt_reason_ve1); + atomic_set(&s_interrupt_flag_ve1, 0); + info.intr_reason = dev->interrupt_reason_ve1; + dev->interrupt_reason_ve1 = 0; + } + ret = copy_to_user((void __user *)arg, &info, sizeof(vpudrv_intr_info_t)); + DPRINTK("[VPUDRV][-]VDI_IOCTL_WAIT_INTERRUPT, info.intr_reason[%d]:0x%x\n", intr_inst_index, info.intr_reason); + if (ret != 0) + return -EFAULT; + } + break; + case VDI_IOCTL_SET_CLOCK_GATE: + { + u32 clkgate; + + //DPRINTK("[VPUDRV][+]VDI_IOCTL_SET_CLOCK_GATE\n"); + if (get_user(clkgate, (u32 __user *) arg)) + return -EFAULT; +#ifdef VPU_SUPPORT_CLOCK_CONTROL + return -EFAULT; +#endif /* VPU_SUPPORT_CLOCK_CONTROL */ + //DPRINTK("[VPUDRV][-]VDI_IOCTL_SET_CLOCK_GATE\n"); + } + break; + case VDI_IOCTL_GET_INSTANCE_POOL: + { + DPRINTK("%s [+]VDI_IOCTL_GET_INSTANCE_POOL\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + if (s_instance_pool.base != 0) { + ret = copy_to_user((void __user *)arg, &s_instance_pool, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = copy_from_user(&s_instance_pool, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret == 0) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + s_instance_pool.size = PAGE_ALIGN(s_instance_pool.size); + s_instance_pool.base = (unsigned long)vmalloc(s_instance_pool.size); + s_instance_pool.phys_addr = s_instance_pool.base; + + if (s_instance_pool.base != 0) +#else + if (vpu_alloc_dma_buffer2(&s_instance_pool) != -1) +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + { + memset((void *)s_instance_pool.base, 0x0, s_instance_pool.size); /*clearing memory*/ + ret = copy_to_user((void __user *)arg, &s_instance_pool, sizeof(vpudrv_buffer_t)); + if (ret == 0) { + /* success to get memory for instance pool */ + up(&s_vpu_sem); + break; + } + } + + } + ret = -EFAULT; + } + + up(&s_vpu_sem); + } + + DPRINTK("%s [-]VDI_IOCTL_GET_INSTANCE_POOL\n", DEV_NAME); + } + break; + case VDI_IOCTL_GET_COMMON_MEMORY: + { + DPRINTK("%s [+]VDI_IOCTL_GET_COMMON_MEMORY\n", DEV_NAME); + if (s_common_memory.base != 0) { + ret = copy_to_user((void __user *)arg, &s_common_memory, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } else { + ret = copy_from_user(&s_common_memory, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (ret == 0) { + if (vpu_alloc_dma_buffer(&s_common_memory) != -1) { + ret = copy_to_user((void __user *)arg, &s_common_memory, sizeof(vpudrv_buffer_t)); + if (ret == 0) { + /* success to get memory for common memory */ + break; + } + } + } + + ret = -EFAULT; + } + DPRINTK("%s [-]VDI_IOCTL_GET_COMMON_MEMORY\n", DEV_NAME); + } + break; + case VDI_IOCTL_OPEN_INSTANCE: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + + vil = kzalloc(sizeof(*vil), GFP_KERNEL); + if (!vil) + return -ENOMEM; + + if (copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t))) { + kfree(vil); + return -EFAULT; + } + + vil->inst_idx = inst_info.inst_idx; + vil->core_idx = inst_info.core_idx; + vil->filp = filp; + + spin_lock(&s_vpu_lock); + list_add(&vil->list, &s_inst_list_head); + + inst_info.inst_open_count = 0; /* counting the current open instance number */ + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->core_idx == inst_info.core_idx) + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + s_vpu_open_ref_count++; /* flag just for that vpu is in opened or closed */ + + if (copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t))) { + kfree(vil); + return -EFAULT; + } + + DPRINTK("%s VDI_IOCTL_OPEN_INSTANCE core_idx=%d, inst_idx=%d, s_vpu_open_ref_count=%d, inst_open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, s_vpu_open_ref_count, inst_info.inst_open_count); + } + break; + case VDI_IOCTL_CLOSE_INSTANCE: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + + DPRINTK("%s [+]VDI_IOCTL_CLOSE_INSTANCE\n", DEV_NAME); + if (copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t))) + return -EFAULT; + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->inst_idx == inst_info.inst_idx && vil->core_idx == inst_info.core_idx) { + list_del(&vil->list); + kfree(vil); + break; + } + } + + inst_info.inst_open_count = 0; /* counting the current open instance number */ + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->core_idx == inst_info.core_idx) + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + s_vpu_open_ref_count--; /* flag just for that vpu is in opened or closed */ + + if (copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t))) + return -EFAULT; + + DPRINTK("%s VDI_IOCTL_CLOSE_INSTANCE core_idx=%d, inst_idx=%d, s_vpu_open_ref_count=%d, inst_open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, s_vpu_open_ref_count, inst_info.inst_open_count); + } + break; + case VDI_IOCTL_GET_INSTANCE_NUM: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + DPRINTK("%s [+]VDI_IOCTL_GET_INSTANCE_NUM\n", DEV_NAME); + + ret = copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t)); + if (ret != 0) + break; + + inst_info.inst_open_count = 0; + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + if (vil->core_idx == inst_info.core_idx) + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + ret = copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t)); + + DPRINTK("%s VDI_IOCTL_GET_INSTANCE_NUM core_idx=%d, inst_idx=%d, open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, inst_info.inst_open_count); + + } + break; + case VDI_IOCTL_RESET: + { + u32 coreIdx; + if (get_user(coreIdx, (u32 __user *) arg)) + return -EFAULT; + vpu_hw_reset(coreIdx); + } + break; + case VDI_IOCTL_GET_REGISTER_INFO: + { + DPRINTK("%s [+]VDI_IOCTL_GET_REGISTER_INFO\n", DEV_NAME); + ret = copy_to_user((void __user *)arg, &s_vpu_register, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + DPRINTK("%s [-]VDI_IOCTL_GET_REGISTER_INFO s_vpu_register.phys_addr=0x%lx, s_vpu_register.virt_addr=0x%lx, s_vpu_register.size=%d\n", DEV_NAME, s_vpu_register.phys_addr, s_vpu_register.virt_addr, s_vpu_register.size); + } + break; + /* RTK ioctl */ + case VDI_IOCTL_SET_RTK_CLK_GATING: + { + vpu_clock_info_t clockInfo; + + DPRINTK("%s [+]VDI_IOCTL_SET_RTK_CLK_GATING\n", DEV_NAME); + ret = copy_from_user(&clockInfo, (vpu_clock_info_t *)arg, sizeof(vpu_clock_info_t)); + if (ret != 0) + break; + + if (clockInfo.enable) { + pm_runtime_get_sync(p_vpu_dev); + } else { + pm_runtime_mark_last_busy(p_vpu_dev); + pm_runtime_put_autosuspend(p_vpu_dev); + } + + DPRINTK("%s [-]VDI_IOCTL_SET_RTK_CLK_GATING clockInfo.core_idx:%d, clockInfo.enable:%d\n", DEV_NAME, clockInfo.core_idx, clockInfo.enable); + } + break; + case VDI_IOCTL_SET_RTK_CLK_PLL: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_GET_RTK_CLK_PLL: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_SET_RTK_CLK_SELECT: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_GET_RTK_CLK_SELECT: + { + return -ENOIOCTLCMD; + } + break; + case VDI_IOCTL_GET_RTK_SUPPORT_TYPE: + { + ret = copy_to_user((void __user *)arg, &s_bond_register, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } + break; + case VDI_IOCTL_GET_RTK_DCSYS_INFO: + { + vpudrv_buffer_t vb; + ret = copy_from_user(&vb, (vpudrv_buffer_t *)arg, sizeof(vpudrv_buffer_t)); + if (vb.mem_type == 0) + ret = copy_to_user((void __user *)arg, &s_dc_register, sizeof(vpudrv_buffer_t)); + else + ret = copy_to_user((void __user *)arg, &s_dmc_register, sizeof(vpudrv_buffer_t)); + if (ret != 0) + ret = -EFAULT; + } + break; + case VDI_IOCTL_GET_RTK_ASIC_REVISION: + { + __put_user(get_rtd_chip_revision()|get_rtd_chip_id(), (unsigned int *) arg); + } + break; + case VDI_IOCTL_SET_RTK_DOVI_FLAG: + { + vpudrv_dovi_info_t doviInfo; + DPRINTK("%s [+]VDI_IOCTL_SET_RTK_DOVI_FLAG\n", DEV_NAME); + ret = copy_from_user(&doviInfo, (vpudrv_dovi_info_t *)arg, sizeof(vpudrv_dovi_info_t)); + if (ret != 0) + break; + + doviInfo.enable = pu_set_dovi_flag(doviInfo.core_idx, doviInfo.inst_idx, doviInfo.enable); + + ret = copy_to_user((vpudrv_dovi_info_t *)arg, &doviInfo, sizeof(vpudrv_dovi_info_t)); + if (ret != 0) + break; + DPRINTK("%s [-]VDI_IOCTL_SET_RTK_DOVI_FLAG doviInfo.core_idx:%d, doviInfo.inst_idx:%d, doviInfo.value:%d\n", DEV_NAME, doviInfo.core_idx, doviInfo.inst_idx, doviInfo.enable); + } + break; + case VDI_IOCTL_GET_TOTAL_INSTANCE_NUM: + { + vpudrv_inst_info_t inst_info; + vpudrv_instanace_list_t *vil, *n; + DPRINTK("%s [+]VDI_IOCTL_GET_TOTAL_INSTANCE_NUM\n", DEV_NAME); + + ret = copy_from_user(&inst_info, (vpudrv_inst_info_t *)arg, sizeof(vpudrv_inst_info_t)); + if (ret != 0) + break; + + inst_info.inst_open_count = 0; + + spin_lock(&s_vpu_lock); + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + inst_info.inst_open_count++; + } + spin_unlock(&s_vpu_lock); + + ret = copy_to_user((void __user *)arg, &inst_info, sizeof(vpudrv_inst_info_t)); + + DPRINTK("%s VDI_IOCTL_GET_TOTAL_INSTANCE_NUM core_idx=%d, inst_idx=%d, open_count=%d\n", DEV_NAME, (int)inst_info.core_idx, (int)inst_info.inst_idx, inst_info.inst_open_count); + + } + break; + default: + { + pr_err("%s No such IOCTL, cmd is %d\n", DEV_NAME, cmd); + } + break; + } + + return ret; +} + +static ssize_t vpu_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) +{ + return -1; +} + +static int compat_get_vpu_bit_firmware_info_data( + compat_vpu_bit_firmware_info_t __user *data32, + vpu_bit_firmware_info_t __user *data) +{ +#if defined(CONFIG_CPU_V7) + //u32 s; + u32 c; + u32 r; + u32 b[512]; +#else + //compat_uint_t s; + compat_uint_t c; + compat_ulong_t r; + compat_ushort_t b[512]; +#endif /* CONFIG_CPU_V7 */ + + int err; + + //err = get_user(s, &data32->size); + //err |= put_user(s, &data->size); + err = get_user(c, &data32->core_idx); + err |= put_user(c, &data->core_idx); + err |= get_user(r, &data32->reg_base_offset); + err |= put_user(r, &data->reg_base_offset); + err |= copy_from_user(b, data32->bit_code, sizeof(b)); + err |= copy_to_user(data->bit_code, b, sizeof(b)); + + return err; +}; + +static ssize_t vpu_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) +{ + + /* DPRINTK("[VPUDRV] vpu_write len=%d\n", (int)len); */ + if (!buf) { + pr_err("%s vpu_write buf = NULL error \n", DEV_NAME); + return -EFAULT; + } + + if (len == sizeof(vpu_bit_firmware_info_t) || len == sizeof(compat_vpu_bit_firmware_info_t)) { + vpu_bit_firmware_info_t *bit_firmware_info; + + bit_firmware_info = kmalloc(sizeof(vpu_bit_firmware_info_t), GFP_KERNEL); + if (!bit_firmware_info) { + pr_err("%s vpu_write bit_firmware_info allocation error\n", DEV_NAME); + return -EFAULT; + } + + if (len == sizeof(vpu_bit_firmware_info_t)) { + if (copy_from_user(bit_firmware_info, buf, len)) { + pr_err("%s vpu_write copy_from_user error for bit_firmware_info\n", DEV_NAME); + kfree(bit_firmware_info); + return -EFAULT; + } + } +#ifdef CONFIG_COMPAT + else { + int err; + compat_vpu_bit_firmware_info_t __user *data32; + vpu_bit_firmware_info_t __user *data; + + data32 = (compat_vpu_bit_firmware_info_t __user *) buf; + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) { + kfree(bit_firmware_info); + return -EFAULT; + } + + err = compat_get_vpu_bit_firmware_info_data(data32, data); + if (err) { + kfree(bit_firmware_info); + return err; + } + + if (copy_from_user(bit_firmware_info, data, sizeof(vpu_bit_firmware_info_t))) { + pr_err("%s vpu_write copy_from_user error for bit_firmware_info\n", DEV_NAME); + kfree(bit_firmware_info); + return -EFAULT; + } + bit_firmware_info->size = sizeof(vpu_bit_firmware_info_t); + } +#endif /* CONFIG_COMPAT */ + + if (bit_firmware_info->size == sizeof(vpu_bit_firmware_info_t)) { + DPRINTK("%s vpu_write set bit_firmware_info coreIdx=0x%x, reg_base_offset=0x%x size=0x%x, bit_code[0]=0x%x\n", + DEV_NAME, bit_firmware_info->core_idx, (int)bit_firmware_info->reg_base_offset, bit_firmware_info->size, bit_firmware_info->bit_code[0]); + + if (bit_firmware_info->core_idx > MAX_NUM_VPU_CORE) { + pr_err("%s vpu_write coreIdx[%d] is exceeded than MAX_NUM_VPU_CORE[%d]\n", DEV_NAME, bit_firmware_info->core_idx, MAX_NUM_VPU_CORE); + kfree(bit_firmware_info); + return -ENODEV; + } + + memcpy((void *)&s_bit_firmware_info[bit_firmware_info->core_idx], bit_firmware_info, sizeof(vpu_bit_firmware_info_t)); + kfree(bit_firmware_info); + + return len; + } + + kfree(bit_firmware_info); + } + + return -1; +} + +static int vpu_release(struct inode *inode, struct file *filp) +{ + int ret = 0; + DPRINTK("%s vpu_release\n", DEV_NAME); + + ret = down_interruptible(&s_vpu_sem); + if (ret == 0) { + /* found and free the not handled buffer by user applications */ + vpu_free_buffers(filp); + /* found and free the not closed instance by user applications */ + vpu_free_instances(filp); + s_vpu_drv_context.open_count--; + if (s_vpu_drv_context.open_count == 0) { + if (s_instance_pool.base) { + DPRINTK("%s free instance pool\n", DEV_NAME); +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + s_instance_pool.base = 0; + } +#if 0 /* Fuchun 20150909, we must not free instance pool and common memory */ + if (s_common_memory.base) { + DPRINTK("%s free common memory\n", DEV_NAME); + vpu_free_dma_buffer(&s_common_memory); + s_common_memory.base = 0; + } +#endif + } + } + up(&s_vpu_sem); + + return 0; +} + +static int vpu_fasync(int fd, struct file *filp, int mode) +{ + struct vpu_drv_context_t *dev = (struct vpu_drv_context_t *)filp->private_data; + return fasync_helper(fd, filp, mode, &dev->async_queue); +} + +static int vpu_map_to_register(struct file *fp, struct vm_area_struct *vm) +{ + unsigned long pfn; + + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + pfn = vm->vm_pgoff; + + return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +} + +static int vpu_map_to_physical_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef CONFIG_RTK_RESERVE_MEMORY + return pu_mmap_dma_buffer(vm); +#else + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot); + + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif /* CONFIG_RTK_RESERVE_MEMORY */ +} + +static int vpu_map_to_instance_pool_memory(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + int ret; + long length = vm->vm_end - vm->vm_start; + unsigned long start = vm->vm_start; + char *vmalloc_area_ptr = (char *)s_instance_pool.base; + unsigned long pfn; + + vm->vm_flags |= VM_RESERVED; + + /* loop over all pages, map it page individually */ + while (length > 0) { + pfn = vmalloc_to_pfn(vmalloc_area_ptr); + ret = remap_pfn_range(vm, start, pfn, PAGE_SIZE, PAGE_SHARED); + if (ret < 0) { + return ret; + } + start += PAGE_SIZE; + vmalloc_area_ptr += PAGE_SIZE; + length -= PAGE_SIZE; + } + + return 0; +#else + vm->vm_flags |= VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end-vm->vm_start, vm->vm_page_prot) ? -EAGAIN : 0; +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ +} + +/*! + * @brief memory map interface for vpu file operation + * @return 0 on success or negative error code on error + */ +static int vpu_mmap(struct file *fp, struct vm_area_struct *vm) +{ +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + if (vm->vm_pgoff == 0) + return vpu_map_to_instance_pool_memory(fp, vm); + + if ((vm->vm_pgoff == (s_vpu_register.phys_addr>>PAGE_SHIFT)) + || (vm->vm_pgoff == (s_bond_register.phys_addr>>PAGE_SHIFT)) + || (vm->vm_pgoff == (s_dc_register.phys_addr>>PAGE_SHIFT)) + || (vm->vm_pgoff == (s_dmc_register.phys_addr>>PAGE_SHIFT))) + return vpu_map_to_register(fp, vm); + + return vpu_map_to_physical_memory(fp, vm); +#else + if (vm->vm_pgoff) { + if (vm->vm_pgoff == (s_instance_pool.phys_addr>>PAGE_SHIFT)) + return vpu_map_to_instance_pool_memory(fp, vm); + + return vpu_map_to_physical_memory(fp, vm); + } else { + return vpu_map_to_register(fp, vm); + } +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ +} + +struct file_operations vpu_fops = { + .owner = THIS_MODULE, + .open = vpu_open, + .read = vpu_read, + .write = vpu_write, + /*.ioctl = vpu_ioctl, // for kernel 2.6.9*/ + .unlocked_ioctl = vpu_ioctl, + .compat_ioctl = compat_vpu_ioctl, + .release = vpu_release, + .fasync = vpu_fasync, + .mmap = vpu_mmap, +}; + + +static int vpu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int err = 0; + u32 bonding_value; + unsigned long virt_addr; + struct resource res; + void __iomem *iobase; + int irq; + struct device_node *node = pdev->dev.of_node; +#if 0 //Fuchun disable 20160204, set clock gating by vdi.c + unsigned int val = 0; +#endif + + pr_info("%s vpu_probe\n", DEV_NAME); + + of_address_to_resource(node, 0, &res); + iobase = of_iomap(node, 0); + + s_vpu_register.phys_addr = res.start; + s_vpu_register.virt_addr = (unsigned long)iobase; + s_vpu_register.size = res.end - res.start + 1; + + pr_info("%s vpu base address get from DTB physical base addr=0x%lx, virtual base=0x%lx, size=0x%x\n", DEV_NAME, s_vpu_register.phys_addr, s_vpu_register.virt_addr, s_vpu_register.size); + + of_address_to_resource(node, 1, &res); + iobase = of_iomap(node, 1); + + s_dc_register.phys_addr = res.start; + s_dc_register.virt_addr = (unsigned long)iobase; + s_dc_register.size = res.end - res.start + 1; + + s_vpu_dev.minor = MISC_VE1_MINOR; + s_vpu_dev.name = VPU_DEV_NAME; + s_vpu_dev.fops = &vpu_fops; + s_vpu_dev.parent = NULL; + if (misc_register(&s_vpu_dev)) { + pr_err("%s failed to register misc device.", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + + of_address_to_resource(node, 2, &res); + iobase = of_iomap(node, 2); + + s_bond_register.phys_addr = res.start; + s_bond_register.virt_addr = (unsigned long)iobase; + s_bond_register.size = res.end - res.start + 1; + + virt_addr = (unsigned long)iobase; + bonding_value = __raw_readl((volatile u8 *)virt_addr); + + pr_info("%s res.start:0x%llx, bonding_value:0x%x\n", DEV_NAME, res.start, bonding_value); + + of_address_to_resource(node, 3, &res); + iobase = of_iomap(node, 3); + + s_dmc_register.phys_addr = res.start; + s_dmc_register.virt_addr = (unsigned long)iobase; + s_dmc_register.size = res.end - res.start + 1; + + p_vpu_dev = &pdev->dev; + + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + s_ve1_irq = irq; + pr_info("%s s_ve1_irq:%d want to register ve1_irq_handler\n", DEV_NAME, s_ve1_irq); + err = request_irq(s_ve1_irq, ve1_irq_handler, 0, "VE1_CODEC_IRQ", (void *)(&s_vpu_drv_context)); + err = 0; + if (err != 0) { + if (err == -EINVAL) + pr_err("%s Bad s_ve1_irq number or handler\n", DEV_NAME); + else if (err == -EBUSY) + pr_err("%s s_ve1_irq <%d> busy, change your config\n", DEV_NAME, s_ve1_irq); + goto ERROR_PROVE_DEVICE; + } + + irq = irq_of_parse_and_map(node, 1); + if (irq <= 0) + panic("Can't parse IRQ"); + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + s_video_memory.size = VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE; + s_video_memory.phys_addr = VPU_DRAM_PHYSICAL_BASE; + s_video_memory.base = (unsigned long)ioremap_nocache(s_video_memory.phys_addr, PAGE_ALIGN(s_video_memory.size)); + if (!s_video_memory.base) { + pr_err("%s fail to remap video memory physical phys_addr=0x%x, base=0x%x, size=%d\n", DEV_NAME, (int)s_video_memory.phys_addr, (int)s_video_memory.base, (int)s_video_memory.size); + goto ERROR_PROVE_DEVICE; + } + + if (vmem_init(&s_vmem, s_video_memory.phys_addr, s_video_memory.size) < 0) { + pr_err("%s fail to init vmem system\n", DEV_NAME); + goto ERROR_PROVE_DEVICE; + } + pr_info("%s success to probe vpu device with reserved video memory phys_addr=0x%x, base = 0x%x\n", DEV_NAME, (int) s_video_memory.phys_addr, (int)s_video_memory.base); +#else + pr_info("%s success to probe vpu device with non reserved video memory\n", DEV_NAME); +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + ve_clk = devm_clk_get(dev, NULL); + if (IS_ERR(ve_clk)) { + dev_warn(dev, "failed to get clk_ve1: %ld\n", PTR_ERR(ve_clk)); + ve_clk = NULL; + } + + ve_rstc = devm_reset_control_get_exclusive(dev, "reset"); + if (IS_ERR(ve_rstc)) { + dev_warn(dev, "failed to get reset control ve1: %ld\n", PTR_ERR(ve_rstc)); + ve_rstc = NULL; + } + + ve_rstc_bist = devm_reset_control_get_optional_exclusive(dev, "bist"); + if (IS_ERR(ve_rstc_bist)) { + dev_warn(dev, "failed to get reset control ve1_bist: %ld\n", PTR_ERR(ve_rstc_bist)); + ve_rstc_bist = NULL; + } + + rtk_pd_dev_pm_add_notifier(dev, &ve_power_nb); + rtk_ve1_power_on(); + + pm_runtime_set_suspended(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, 15000); + pm_runtime_enable(dev); + + /* toggle it */ + pm_runtime_get_sync(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + return 0; + + +ERROR_PROVE_DEVICE: + + misc_deregister(&s_vpu_dev); + + return err; +} + +static int vpu_remove(struct platform_device *pdev) +{ + DPRINTK("%s vpu_remove\n", DEV_NAME); + + pm_runtime_disable(&pdev->dev); + rtk_pd_dev_pm_remove_notifier(&pdev->dev); + +#ifdef VPU_SUPPORT_PLATFORM_DRIVER_REGISTER + if (s_instance_pool.base) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* VPU_SUPPORT_PLATFORM_DRIVER_REGISTER */ + s_instance_pool.base = 0; + } + + if (s_common_memory.base) { + vpu_free_dma_buffer(&s_common_memory); + s_common_memory.base = 0; + } + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_video_memory.base) { + iounmap((void *)s_video_memory.base); + s_video_memory.base = 0; + vmem_exit(&s_vmem); + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + misc_deregister(&s_vpu_dev); + +#ifdef VPU_SUPPORT_ISR + if (s_ve1_irq) + free_irq(s_ve1_irq, &s_vpu_drv_context); +#endif /* VPU_SUPPORT_ISR */ + +#endif /* VPU_SUPPORT_PLATFORM_DRIVER_REGISTER */ + + return 0; +} + +#ifdef CONFIG_PM +/* DO NOT CHANGE */ + +static int vpu_suspend(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + pm_runtime_get_sync(pdev); + + /* RTK wrapper */ + + if (s_vpu_open_ref_count > 0) { +#ifdef DISABLE_ORIGIN_SUSPEND + vpudrv_instanace_list_t *vil, *n; + vpudrv_instance_pool_t *vip; + void *vip_base; + int instance_pool_size_per_core; + vpudrv_buffer_pool_t *pool, *nn; + vpudrv_buffer_t vb; + s_vpu_drv_context.open_count = 0; + s_vpu_open_ref_count = 0; + + /* s_instance_pool.size assigned to the size of all core once call VDI_IOCTL_GET_INSTANCE_POOL by user. */ + instance_pool_size_per_core = (s_instance_pool.size/MAX_NUM_VPU_CORE); + + wake_up_interruptible_all(&s_interrupt_wait_q_ve1); + atomic_set(&s_interrupt_flag_ve1, 0); + + list_for_each_entry_safe(vil, n, &s_inst_list_head, list) { + vip_base = (void *)(s_instance_pool.base + (instance_pool_size_per_core*vil->core_idx)); + vip = (vpudrv_instance_pool_t *)vip_base; + if (vip) { + /* only first 4 byte is key point(inUse of CodecInst in vpuapi) to free the corresponding instance. */ + memset(&vip->codecInstPool[vil->inst_idx], 0x00, 4); + } + list_del(&vil->list); + kfree(vil); + } + + list_for_each_entry_safe(pool, nn, &s_vbp_head, list) { + vb = pool->vb; + if (vb.base) { + vpu_free_dma_buffer(&vb); + } + list_del(&pool->list); + kfree(pool); + } + + if (s_instance_pool.base) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + s_instance_pool.base = 0; + } +#else /* else of DISABLE_ORIGIN_SUSPEND */ + int i; + int core; + unsigned long timeout = jiffies + HZ; /* vpu wait timeout to 1sec */ + int product_code = 0; + + for (core = 0; core < MAX_NUM_VPU_CORE; core++) { + if (s_bit_firmware_info[core].size == 0) + continue; + product_code = ReadVpuRegister(VPU_PRODUCT_CODE_REGISTER, core); + + { + while (ReadVpuRegister(BIT_BUSY_FLAG, core)) { + if (time_after(jiffies, timeout)) + goto DONE_SUSPEND; + } + + for (i = 0; i < 64; i++) + s_vpu_reg_store[core][i] = ReadVpuRegister(BIT_BASE+(0x100+(i * 4)), core); + } +#endif /* end of DISABLE_ORIGIN_SUSPEND */ + } + + pm_runtime_force_suspend(pdev); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; + +#ifndef DISABLE_ORIGIN_SUSPEND +DONE_SUSPEND: +#endif + + pm_runtime_put_sync(pdev); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return -EAGAIN; +} + +static int vpu_resume(struct device *pdev) +{ + pr_info("%s Enter %s\n", DEV_NAME, __func__); + + pm_runtime_force_resume(pdev); + + //RTK wrapper + ve1_wrapper_setup((1 << 1) | 1); + +#ifdef DISABLE_ORIGIN_SUSPEND +#else /* else of DISABLE_ORIGIN_SUSPEND */ + int i; + int core; + int regVal; + int product_code = 0; + unsigned long timeout = jiffies + HZ; /* vpu wait timeout to 1sec */ + unsigned long code_base; + unsigned long stack_base; + u32 val; + u32 code_size; + u32 stack_size; + u32 remap_size; + u32 hwOption = 0; + + for (core = 0; core < MAX_NUM_VPU_CORE; core++) { + + if (s_bit_firmware_info[core].size == 0) { + continue; + } + + product_code = ReadVpuRegister(VPU_PRODUCT_CODE_REGISTER, core); + + { + + WriteVpuRegister(BIT_CODE_RUN, 0, core); + + /*---- LOAD BOOT CODE*/ + for (i = 0; i < 512; i++) { + val = s_bit_firmware_info[core].bit_code[i]; + WriteVpuRegister(BIT_CODE_DOWN, ((i << 16) | val), core); + } + + for (i = 0 ; i < 64 ; i++) + WriteVpuRegister(BIT_BASE+(0x100+(i * 4)), s_vpu_reg_store[core][i], core); + + WriteVpuRegister(BIT_BUSY_FLAG, 1, core); + WriteVpuRegister(BIT_CODE_RESET, 1, core); + WriteVpuRegister(BIT_CODE_RUN, 1, core); + + while (ReadVpuRegister(BIT_BUSY_FLAG, core)) { + if (time_after(jiffies, timeout)) + goto DONE_WAKEUP; + } + + } + + } +#endif /* end of DISABLE_ORIGIN_SUSPEND */ + +#ifndef DISABLE_ORIGIN_SUSPEND +DONE_WAKEUP: +#endif /* DISABLE_ORIGIN_SUSPEND */ + + pm_runtime_put_sync(pdev); + + pr_info("%s Exit %s\n", DEV_NAME, __func__); + + return 0; +} +#else +static int vpu_suspend(struct device *pdev); +static int vpu_resume(struct device *pdev); +#endif /* CONFIG_PM */ + +static int __init vpu_init(void) +{ + int res = 0; + +#ifdef SUPPORT_MULTI_INST_INTR + int i; +#endif + DPRINTK("%s begin vpu_init\n", DEV_NAME); + + init_waitqueue_head(&s_interrupt_wait_q_ve1); + s_common_memory.base = 0; + s_instance_pool.base = 0; + + DPRINTK("%s end vpu_init result=0x%x\n", DEV_NAME, res); + return res; +} + +static void __exit vpu_exit(void) +{ +#ifdef VPU_SUPPORT_PLATFORM_DRIVER_REGISTER + DPRINTK("%s vpu_exit\n", DEV_NAME); +#else + + if (s_instance_pool.base) { +#ifdef USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + vfree((const void *)s_instance_pool.base); +#else + pu_unmap_kernel_buffer(s_instance_pool.base, s_instance_pool.phys_addr); + vpu_free_dma_buffer(&s_instance_pool); +#endif /* USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY */ + s_instance_pool.base = 0; + } + + if (s_common_memory.base) { + vpu_free_dma_buffer(&s_common_memory); + s_common_memory.base = 0; + } + +#ifdef VPU_SUPPORT_RESERVED_VIDEO_MEMORY + if (s_video_memory.base) { + iounmap((void *)s_video_memory.base); + s_video_memory.base = 0; + + vmem_exit(&s_vmem); + } +#endif /* VPU_SUPPORT_RESERVED_VIDEO_MEMORY */ + + misc_deregister(&s_vpu_dev); + +#ifdef VPU_SUPPORT_ISR + if (s_ve1_irq) + free_irq(s_ve1_irq, &s_vpu_drv_context); +#endif /* VPU_SUPPORT_ISR */ + +#endif /* VPU_SUPPORT_PLATFORM_DRIVER_REGISTER */ + + return; +} + +MODULE_AUTHOR("A customer using RTK VPU, Inc."); +MODULE_DESCRIPTION("VPU linux driver"); +MODULE_LICENSE("GPL"); + +module_init(vpu_init); +module_exit(vpu_exit); + +static const struct of_device_id rtk_ve1_dt_match[] = { + { .compatible = "realtek,rtk13xx-ve1" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_ve1_dt_match); + +static int rtk_ve1_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "%s\n", __func__); + return 0; +} + +static int rtk_ve1_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "%s\n", __func__); + ve1_wrapper_setup((1 << 1) | 1); + return 0; +} + +const struct dev_pm_ops rtk_ve1_pmops = { + .runtime_suspend = rtk_ve1_runtime_suspend, + .runtime_resume = rtk_ve1_runtime_resume, + .suspend = vpu_suspend, + .resume = vpu_resume, +}; + +static struct platform_driver rtk_ve1_driver = { + .driver = { + .name = "rtk-ve1", + .owner = THIS_MODULE, + .of_match_table = rtk_ve1_dt_match, + .pm = &rtk_ve1_pmops, + }, + .probe = vpu_probe, + .remove = vpu_remove, +}; + +module_platform_driver(rtk_ve1_driver); diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.h new file mode 100644 index 000000000000..f351f9ddaff7 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1.h @@ -0,0 +1,106 @@ +/** + ve1.c + + linux device driver for VPU. + + Copyright (C) 2006 - 2013 REALTEK INC. + + This 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. + + This 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 this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + +*/ + +#ifndef __VPU_DRV_H__ +#define __VPU_DRV_H__ + +#include +#include + +#define SUPPORT_MULTI_INST_INTR +#define SUPPORT_MULTI_INST_INTR_ERROR_CHECK +#define USE_VMALLOC_FOR_INSTANCE_POOL_MEMORY + +#define VDI_IOCTL_MAGIC 'V' +#define VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY _IO(VDI_IOCTL_MAGIC, 0) +#define VDI_IOCTL_FREE_PHYSICALMEMORY _IO(VDI_IOCTL_MAGIC, 1) +#define VDI_IOCTL_WAIT_INTERRUPT _IO(VDI_IOCTL_MAGIC, 2) +#define VDI_IOCTL_SET_CLOCK_GATE _IO(VDI_IOCTL_MAGIC, 3) +#define VDI_IOCTL_RESET _IO(VDI_IOCTL_MAGIC, 4) +#define VDI_IOCTL_GET_INSTANCE_POOL _IO(VDI_IOCTL_MAGIC, 5) +#define VDI_IOCTL_GET_COMMON_MEMORY _IO(VDI_IOCTL_MAGIC, 6) +#define VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO _IO(VDI_IOCTL_MAGIC, 8) +#define VDI_IOCTL_OPEN_INSTANCE _IO(VDI_IOCTL_MAGIC, 9) +#define VDI_IOCTL_CLOSE_INSTANCE _IO(VDI_IOCTL_MAGIC, 10) +#define VDI_IOCTL_GET_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 11) +#define VDI_IOCTL_GET_REGISTER_INFO _IO(VDI_IOCTL_MAGIC, 12) + +/* RTK ioctl */ +#define VDI_IOCTL_SET_RTK_CLK_GATING _IO(VDI_IOCTL_MAGIC, 16) +#define VDI_IOCTL_SET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 17) +#define VDI_IOCTL_GET_RTK_CLK_PLL _IO(VDI_IOCTL_MAGIC, 18) +#define VDI_IOCTL_GET_RTK_SUPPORT_TYPE _IO(VDI_IOCTL_MAGIC, 19) +#define VDI_IOCTL_GET_RTK_ASIC_REVISION _IO(VDI_IOCTL_MAGIC, 20) +#define VDI_IOCTL_SET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 21) +#define VDI_IOCTL_GET_RTK_CLK_SELECT _IO(VDI_IOCTL_MAGIC, 22) +#define VDI_IOCTL_SET_RTK_DOVI_FLAG _IO(VDI_IOCTL_MAGIC, 23) +#define VDI_IOCTL_GET_TOTAL_INSTANCE_NUM _IO(VDI_IOCTL_MAGIC, 24) +#define VDI_IOCTL_GET_RTK_DCSYS_INFO _IO(VDI_IOCTL_MAGIC, 25) + +#define VE_PLL_SYSH 0x000 +#define VE_PLL_VE1 0x001 +#define VE_PLL_VE2 0x010 + +typedef struct vpudrv_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; /* kernel logical address in use kernel */ + unsigned long virt_addr; /* virtual user space address */ + unsigned int mem_type; /* RTK, for protect memory */ +} vpudrv_buffer_t; + +typedef struct vpu_bit_firmware_info_t { + unsigned int size; /* size of this structure*/ + unsigned int core_idx; + unsigned long reg_base_offset; + unsigned short bit_code[512]; +} vpu_bit_firmware_info_t; + +typedef struct vpu_clock_info_t{ + unsigned int core_idx; + unsigned int enable; + unsigned int value; +} vpu_clock_info_t; + +typedef struct vpudrv_inst_info_t { + unsigned int core_idx; + unsigned int inst_idx; + int inst_open_count; /* for output only*/ +} vpudrv_inst_info_t; + +typedef struct vpudrv_intr_info_t { + unsigned int core_idx; + unsigned int timeout; + int intr_reason; +#ifdef SUPPORT_MULTI_INST_INTR + int intr_inst_index; +#endif +} vpudrv_intr_info_t; + +typedef struct vpudrv_dovi_info_t{ + unsigned int core_idx; + unsigned int inst_idx; + unsigned int enable; +} vpudrv_dovi_info_t; +#endif diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.c b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.c new file mode 100644 index 000000000000..23be54a5625e --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.c @@ -0,0 +1,234 @@ +/* + * ve1_pm.c - ve1 power management + * + * Copyright (c) 2019 Realtek Semiconductor Corporation + * + * Author: + * Cheng-Yu Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#include +#include +#include +#include +#include +#include "ve1_pm.h" + +struct ve_pm_data { + struct device *dev; + struct clk *clk_ve1; + struct clk *clk_ve3; + struct reset_control *rstc_ve1; + struct reset_control *rstc_ve1_bist; + struct reset_control *rstc_ve3; + struct reset_control *rstc_ve3_bist; + atomic_t power_cnt; + int inited; +}; + +static struct ve_pm_data g_vpd; + +int ve_pd_init(struct device *dev) +{ + struct ve_pm_data *vpd = &g_vpd; + struct clk *clk; + struct reset_control *rstc; + + if (vpd->inited) + return -EINVAL; + + vpd->dev = dev; + vpd->inited = 1; + atomic_set(&vpd->power_cnt, 0); + + clk = devm_clk_get(dev, "clk_ve1"); + if (IS_ERR(clk)) { + dev_warn(dev, "failed to get clk_ve1: %ld\n", PTR_ERR(clk)); + clk = NULL; + } + vpd->clk_ve1 = clk; + + clk = devm_clk_get(dev, "clk_ve3"); + if (IS_ERR(clk)) { + dev_warn(dev, "failed to get clk_ve1: %ld\n", PTR_ERR(clk)); + clk = NULL; + } + vpd->clk_ve3 = clk; + + rstc = devm_reset_control_get_exclusive(dev, "ve1"); + if (IS_ERR(rstc)) { + dev_warn(dev, "failed to get reset control ve1: %ld\n", PTR_ERR(rstc)); + rstc = NULL; + } + vpd->rstc_ve1 = rstc; + + rstc = devm_reset_control_get_optional_exclusive(dev, "ve1_bist"); + if (IS_ERR(rstc)) { + dev_warn(dev, "failed to get reset control ve1_bist: %ld\n", PTR_ERR(rstc)); + rstc = NULL; + } + vpd->rstc_ve1_bist = rstc; + + rstc = devm_reset_control_get_exclusive(dev, "ve3"); + if (IS_ERR(rstc)) { + dev_warn(dev, "failed to get reset control ve3: %ld\n", PTR_ERR(rstc)); + rstc = NULL; + } + vpd->rstc_ve3 = rstc; + + rstc = devm_reset_control_get_optional_exclusive(dev, "ve3_bist"); + if (IS_ERR(rstc)) { + dev_warn(dev, "failed to get reset control ve3_bist: %ld\n", PTR_ERR(rstc)); + rstc = NULL; + } + vpd->rstc_ve3_bist = rstc; + + return 0; +} + +void ve_pd_exit(struct device *dev) +{ +} + +int ve_pd_power_on(int no_reset) +{ + struct ve_pm_data *vpd = &g_vpd; + + if (atomic_inc_return(&vpd->power_cnt) != 1) + return -EINVAL; + + dev_info(vpd->dev, "%s\n", __func__); + + reset_control_deassert(vpd->rstc_ve1_bist); + clk_prepare_enable(vpd->clk_ve1); + if (!no_reset) + reset_control_reset(vpd->rstc_ve1); + + reset_control_deassert(vpd->rstc_ve3_bist); + clk_prepare_enable(vpd->clk_ve3); + if (!no_reset) + reset_control_reset(vpd->rstc_ve3); + + return 0; +} + +int ve_pd_power_off(void) +{ + struct ve_pm_data *vpd = &g_vpd; + + if (atomic_dec_return(&vpd->power_cnt) != 0) + return -EINVAL; + + dev_info(vpd->dev, "%s\n", __func__); + + clk_disable_unprepare(vpd->clk_ve1); + reset_control_assert(vpd->rstc_ve1_bist); + + clk_disable_unprepare(vpd->clk_ve3); + reset_control_assert(vpd->rstc_ve3_bist); + + return 0; +} + +int ve_pd_reset_control_reset(int idx) +{ + struct ve_pm_data *vpd = &g_vpd; + struct clk *clk = idx ? vpd->clk_ve3 : vpd->clk_ve1; + struct reset_control *rstc = idx ? vpd->rstc_ve3 : vpd->rstc_ve1; + int ret; + + if (!rstc) + return -EINVAL; + + clk_prepare_enable(clk); + ret = reset_control_reset(rstc); + clk_disable_unprepare(clk); + return ret; +} + +int ve_pd_clk_set_parent(int idx, const char *parent_name) +{ + struct ve_pm_data *vpd = &g_vpd; + struct clk *clk = idx ? vpd->clk_ve3 : vpd->clk_ve1; + struct clk *pclk; + int ret; + + if (!parent_name) + return -EINVAL; + + if (atomic_read(&vpd->power_cnt) != 0) + return -EBUSY; + + pclk = clk_get(NULL, parent_name); + if (IS_ERR_OR_NULL(pclk)) + return -EINVAL; + + dev_info(vpd->dev, "%s: %pC: parent=%s\n", __func__, clk, parent_name); + + ret = clk_set_parent(clk, pclk); + clk_put(pclk); + + return ret; +} + +int ve_pd_clk_parent_match(int idx, const char *clk_name) +{ + struct ve_pm_data *vpd = &g_vpd; + struct clk *clk = idx ? vpd->clk_ve3 : vpd->clk_ve1; + struct clk *rclk; + struct clk *pclk; + bool is_match; + + if (!clk_name) + return -EINVAL; + + rclk = clk_get(NULL, clk_name); + if (IS_ERR_OR_NULL(rclk)) + return -EINVAL; + + pclk = clk_get_parent(clk); + + is_match = clk_is_match(pclk, rclk); + clk_put(rclk); + + return is_match ? 1 : 0; +} + + +int ve_pd_clk_set_rate(int idx, unsigned long rate) +{ + struct ve_pm_data *vpd = &g_vpd; + struct clk *clk = idx ? vpd->clk_ve3 : vpd->clk_ve1; + int ret; + + /* should not set rate if parent is clk_sysh */ + ret = ve_pd_clk_parent_match(idx, "clk_sysh"); + if (ret > 0) + return -EINVAL; + + pr_debug("%s: %pC: rate=%ld\n", __func__, clk, rate); + + return clk_set_rate(clk, rate); +} + +unsigned long ve_pd_clk_get_rate(int idx) +{ + struct ve_pm_data *vpd = &g_vpd; + struct clk *clk = idx ? vpd->clk_ve3 : vpd->clk_ve1; + + return clk_get_rate(clk); +} + diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.h new file mode 100644 index 000000000000..9d72a25b81f0 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1_pm.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 Realtek Semiconductor Corporation + * + * Author: + * Cheng-Yu Lee + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#ifndef __VE1_PM_H +#define __VE1_PM_H + +struct device; + +int ve_pd_init(struct device *dev); +void ve_pd_exit(struct device *dev); +int ve_pd_power_on(int no_reset); +int ve_pd_power_off(void); +int ve_pd_reset_control_reset(int idx); +int ve_pd_clk_set_parent(int idx, const char *parent_name); +int ve_pd_clk_parent_match(int idx, const char *clk_name); +int ve_pd_clk_set_rate(int idx, unsigned long rate); +unsigned long ve_pd_clk_get_rate(int idx); + +#endif diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1config.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1config.h new file mode 100644 index 000000000000..bbb7385411be --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/ve1config.h @@ -0,0 +1,110 @@ +/* ========================================================================= + * This file is a part of VE1 Reference API project + * ----------------------------------------------------------------------------- + * + * This confidential and proprietary software may be used only + * as authorized by a licensing agreement from Realtek Inc. + * In the event of publication, the following notice is applicable: + * + * (C) COPYRIGHT 2006 - 2011 REALTEK INC. + * ALL RIGHTS RESERVED + * + * The entire notice above must be reproduced on all authorized + * copies. + * This file should be modified by some customers according to their SOC configuration. + * ========================================================================= + */ + +#ifndef _VPU_CONFIG_H_ +#define _VPU_CONFIG_H_ + +#define BODA7503_CODE 0x7503 +#define CODA7542_CODE 0x7542 +#define BODA950_CODE 0x9500 +#define CODA960_CODE 0x9600 +#define CODA980_CODE 0x9800 +#define WAVE320_CODE 0x3200 +#define WAVE410_CODE 0x4100 /* Wave410 version 1: Single vcore */ +#define WAVE4102_CODE 0x4102 /* Wave410 version 2: Multi vcore */ +#define WAVE420_CODE 0x4200 /* Wave420 */ +#define WAVE420L_CODE 0x4201 /* Wave420 */ +#define WAVE412_CODE 0x4120 +#define WAVE510_CODE 0x5100 +#define WAVE512_CODE 0x5120 +#define WAVE520_CODE 0x5200 + +#define PRODUCT_CODE_W_SERIES(x) (x == WAVE420L_CODE || x == WAVE510_CODE || x == WAVE512_CODE || x == WAVE520_CODE) +#define MAX_INST_HANDLE_SIZE (32*1024) +#define MAX_NUM_INSTANCE 4 +#define MAX_NUM_VPU_CORE 1 +#define MAX_NUM_VCORE 1 + +#define MAX_ENC_AVC_PIC_WIDTH 4096 +#define MAX_ENC_AVC_PIC_HEIGHT 2304 +#define MAX_ENC_PIC_WIDTH 4096 +#define MAX_ENC_PIC_HEIGHT 2304 +#define MIN_ENC_PIC_WIDTH 96 +#define MIN_ENC_PIC_HEIGHT 16 + +/* for WAVE420 */ +#define W4_MIN_ENC_PIC_WIDTH 256 +#define W4_MIN_ENC_PIC_HEIGHT 128 +#define W4_MAX_ENC_PIC_WIDTH 8192 +#define W4_MAX_ENC_PIC_HEIGHT 8192 + +#define MAX_DEC_PIC_WIDTH 4096 +#define MAX_DEC_PIC_HEIGHT 2304 + +/* Application specific configuration */ +#define VPU_ENC_TIMEOUT 5000 +#define VPU_DEC_TIMEOUT 10000 +#define VPU_BUSY_CHECK_TIMEOUT 5000 + +/* codec specific configuration */ +/* it can be set to 1 to handle reordering DPB in host side. */ +#define VPU_REORDER_ENABLE 1 +/* + * [default 1 for BW checking with RTKViedo Conformance] 0 (chroma separate mode), 1 (chroma interleave mode) + * if the type of tiledmap uses the kind of MB_RASTER_MAP. must set to enable CBCR_INTERLEAVE + */ +#define CBCR_INTERLEAVE 1 +#define VPU_ENABLE_BWB 1 +#define VPU_REPORT_USERDATA 0 + +#define HOST_ENDIAN VDI_128BIT_LITTLE_ENDIAN +#define VPU_FRAME_ENDIAN HOST_ENDIAN +#define VPU_STREAM_ENDIAN HOST_ENDIAN +#define VPU_USER_DATA_ENDIAN HOST_ENDIAN +#define DRAM_BUS_WIDTH 16 + +/************************************************************************/ +/* VPU COMMON MEMORY */ +/************************************************************************/ +#define SIZE_COMMON (2*1024*1024) + +/*=====4. VPU REPORT MEMORY ======================*/ +#define SIZE_REPORT_BUF (0x10000) + +#define STREAM_END_SIZE 0 +#define STREAM_END_SET_FLAG 0 +#define STREAM_END_CLEAR_FLAG -1 + +#define USE_BIT_INTERNAL_BUF 1 +#define USE_IP_INTERNAL_BUF 1 +#define USE_DBKY_INTERNAL_BUF 1 +#define USE_DBKC_INTERNAL_BUF 1 +#define USE_OVL_INTERNAL_BUF 1 +#define USE_BTP_INTERNAL_BUF 1 +#define USE_ME_INTERNAL_BUF 1 + +/* WAVE410 only */ +#define USE_BPU_INTERNAL_BUF 1 +#define USE_VCE_IP_INTERNAL_BUF 1 +#define USE_VCE_LF_ROW_INTERNAL_BUF 1 + +/* WAVE420 only */ +#define USE_IMD_INTERNAL_BUF 1 +#define USE_RDO_INTERNAL_BUF 1 +#define USE_LF_INTERNAL_BUF 1 + +#endif /* _VPU_CONFIG_H_ */ diff --git a/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/vmm.h b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/vmm.h new file mode 100644 index 000000000000..5ad579251102 --- /dev/null +++ b/drivers/soc/realtek/rtd16xxb/rtk_ve/ve1/vmm.h @@ -0,0 +1,634 @@ +/** + vmm.h + + memory allocator for VE + + Copyright (C) 2006 - 2013 REALTEK INC. + + This 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. + + This 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 this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA + +*/ + +#ifndef __RTK_VIDEO_MEMORY_MANAGEMENT_H__ +#define __RTK_VIDEO_MEMORY_MANAGEMENT_H__ + +typedef struct _video_mm_info_struct { + unsigned long total_pages; + unsigned long alloc_pages; + unsigned long free_pages; + unsigned long page_size; +} vmem_info_t; + +typedef unsigned long long vmem_key_t; + +#define VMEM_PAGE_SIZE (16*1024) +#define MAKE_KEY(_a, _b) (((vmem_key_t)_a)<<32 | _b) +#define KEY_TO_VALUE(_key) (_key>>32) + +typedef struct page_struct { + int pageno; + unsigned long addr; + int used; + int alloc_pages; + int first_pageno; +} page_t; + +typedef struct avl_node_struct { + vmem_key_t key; + int height; + page_t *page; + struct avl_node_struct *left; + struct avl_node_struct *right; +} avl_node_t; + +typedef struct _video_mm_struct { + avl_node_t *free_tree; + avl_node_t *alloc_tree; + page_t *page_list; + int num_pages; + unsigned long base_addr; + unsigned long mem_size; + int free_page_count; + int alloc_page_count; +} video_mm_t; + +#define VMEM_P_ALLOC(_x) vmalloc(_x) +#define VMEM_P_FREE(_x) vfree(_x) + +#define VMEM_ASSERT(_exp) if (!(_exp)) { printk(KERN_INFO "VMEM_ASSERT at %s:%d\n", __FILE__, __LINE__); /*while(1);*/ +#define VMEM_HEIGHT(_tree) (_tree == NULL ? -1 : _tree->height) + +#define MAX(_a, _b) (_a >= _b ? _a : _b) + +typedef enum { + LEFT, + RIGHT +} rotation_dir_t; + +typedef struct avl_node_data_struct { + int key; + page_t *page; +} avl_node_data_t; + +static avl_node_t* make_avl_node( vmem_key_t key, page_t *page) +{ + avl_node_t *node = (avl_node_t *)VMEM_P_ALLOC(sizeof(avl_node_t)); + node->key = key; + node->page = page; + node->height = 0; + node->left = NULL; + node->right = NULL; + + return node; +} + +static int get_balance_factor(avl_node_t *tree) +{ + int factor = 0; + if (tree) { + factor = VMEM_HEIGHT(tree->right) - VMEM_HEIGHT(tree->left); + } + + return factor; +} + +/* + * Left Rotation + * + * A B + * \ / \ + * B => A C + * / \ \ + * D C D + * + */ +static avl_node_t* rotation_left(avl_node_t *tree) +{ + avl_node_t *rchild; + avl_node_t *lchild; + + if (tree == NULL) + return NULL; + + rchild = tree->right; + if (rchild == NULL) { + return tree; + } + + lchild = rchild->left; + rchild->left = tree; + tree->right = lchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + rchild->height = MAX(VMEM_HEIGHT(rchild->left), VMEM_HEIGHT(rchild->right)) + 1; + + return rchild; +} + + +/* + * Reft Rotation + * + * A B + * \ / \ + * B => D A + * / \ / + * D C C + * + */ +static avl_node_t *rotation_right(avl_node_t *tree) +{ + avl_node_t *rchild; + avl_node_t *lchild; + + if (tree == NULL) + return NULL; + + lchild = tree->left; + if (lchild == NULL) + return NULL; + + rchild = lchild->right; + lchild->right = tree; + tree->left = rchild; + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + lchild->height = MAX(VMEM_HEIGHT(lchild->left), VMEM_HEIGHT(lchild->right)) + 1; + + return lchild; +} + +static avl_node_t *do_balance(avl_node_t *tree) +{ + int bfactor = 0, child_bfactor; /* balancing factor */ + + bfactor = get_balance_factor(tree); + + if (bfactor >= 2) { + child_bfactor = get_balance_factor(tree->right); + if (child_bfactor == 1 || child_bfactor == 0) { + tree = rotation_left(tree); + } else if (child_bfactor == -1) { + tree->right = rotation_right(tree->right); + tree = rotation_left(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } else if (bfactor <= -2) { + child_bfactor = get_balance_factor(tree->left); + if (child_bfactor == -1 || child_bfactor == 0) { + tree = rotation_right(tree); + } else if (child_bfactor == 1) { + tree->left = rotation_left(tree->left); + tree = rotation_right(tree); + } else { + printk(KERN_INFO "invalid balancing factor: %d\n", child_bfactor); + VMEM_ASSERT(0); + return NULL; + } + } + + return tree; +} + +static avl_node_t *unlink_end_node(avl_node_t *tree, int dir, avl_node_t **found_node) +{ + avl_node_t *node; + *found_node = NULL; + + if (tree == NULL) + return NULL; + + if (dir == LEFT) { + if (tree->left == NULL) { + *found_node = tree; + return NULL; + } + } else { + if (tree->right == NULL) { + *found_node = tree; + return NULL; + } + } + + if (dir == LEFT) { + node = tree->left; + tree->left = unlink_end_node(tree->left, LEFT, found_node); + if (tree->left == NULL) { + tree->left = (*found_node)->right; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } else { + node = tree->right; + tree->right = unlink_end_node(tree->right, RIGHT, found_node); + if (tree->right == NULL) { + tree->right = (*found_node)->left; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return do_balance(tree); +} + + +static avl_node_t *avltree_insert(avl_node_t *tree, vmem_key_t key, page_t *page) +{ + if (tree == NULL) { + tree = make_avl_node(key, page); + } else { + if (key >= tree->key) { + tree->right = avltree_insert(tree->right, key, page); + } else { + tree->left = avltree_insert(tree->left, key, page); + } + } + + tree = do_balance(tree); + + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + return tree; +} + +static avl_node_t *do_unlink(avl_node_t *tree) +{ + avl_node_t *node; + avl_node_t *end_node; + + node = unlink_end_node(tree->right, LEFT, &end_node); + if (node) { + tree->right = node; + } else { + node = unlink_end_node(tree->left, RIGHT, &end_node); + if (node) + tree->left = node; + } + + if (node == NULL) { + node = tree->right ? tree->right : tree->left; + end_node = node; + } + + if (end_node) { + end_node->left = (tree->left != end_node) ? tree->left : end_node->left; + end_node->right = (tree->right != end_node) ? tree->right : end_node->right; + end_node->height = MAX(VMEM_HEIGHT(end_node->left), VMEM_HEIGHT(end_node->right)) + 1; + } + + tree = end_node; + + return tree; +} + +static avl_node_t *avltree_remove(avl_node_t *tree, avl_node_t **found_node, vmem_key_t key) +{ + *found_node = NULL; + if (tree == NULL) { + printk(KERN_INFO "failed to find key %d\n", (int)key); + return NULL; + } + + if (key == tree->key) { + *found_node = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = avltree_remove(tree->right, found_node, key); + } else { + tree->left = avltree_remove(tree->left, found_node, key); + } + + if (tree) + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +void avltree_free(avl_node_t *tree) +{ + if (tree == NULL) + return; + if (tree->left == NULL && tree->right == NULL) { + VMEM_P_FREE(tree); + return; + } + + avltree_free(tree->left); + tree->left = NULL; + avltree_free(tree->right); + tree->right = NULL; + VMEM_P_FREE(tree); +} + +static avl_node_t *remove_approx_value(avl_node_t *tree, avl_node_t **found, vmem_key_t key) +{ + *found = NULL; + if (tree == NULL) { + return NULL; + } + + if (key == tree->key) { + *found = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = remove_approx_value(tree->right, found, key); + } else { + tree->left = remove_approx_value(tree->left, found, key); + if (*found == NULL) { + *found = tree; + tree = do_unlink(tree); + } + } + if (tree) + tree->height = MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +static void set_blocks_free(video_mm_t *mm, int pageno, int npages) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t *page; + page_t *last_page; + + VMEM_ASSERT(npages); + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i = pageno; i <= last_pageno; i++) { + mm->page_list[i].used = 0; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->free_tree = avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page); +} + +static void set_blocks_alloc(video_mm_t *mm, int pageno, int npages) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t *page; + page_t *last_page; + + if (last_pageno >= mm->num_pages) { + printk(KERN_INFO "set_blocks_free: invalid last page number: %d\n", last_pageno); + VMEM_ASSERT(0); + return; + } + + for (i = pageno; i <= last_pageno; i++) { + mm->page_list[i].used = 1; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->alloc_tree = avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page); +} + + +int vmem_init(video_mm_t *mm, unsigned long addr, unsigned long size) +{ + int i; + + if (NULL == mm) + return -1; + + mm->base_addr = (addr+(VMEM_PAGE_SIZE-1))&~(VMEM_PAGE_SIZE-1); + mm->mem_size = size&~VMEM_PAGE_SIZE; + mm->num_pages = mm->mem_size/VMEM_PAGE_SIZE; + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = mm->num_pages; + mm->alloc_page_count = 0; + mm->page_list = (page_t *)VMEM_P_ALLOC(mm->num_pages*sizeof(page_t)); + if (mm->page_list == NULL) { + printk(KERN_ERR "%s:%d failed to kmalloc(%d)\n", __func__, __LINE__, mm->num_pages*sizeof(page_t)); + return -1; + } + + for (i = 0; i < mm->num_pages; i++) { + mm->page_list[i].pageno = i; + mm->page_list[i].addr = mm->base_addr + i * VMEM_PAGE_SIZE; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].used = 0; + mm->page_list[i].first_pageno = -1; + } + + set_blocks_free(mm, 0, mm->num_pages); + + return 0; +} + +int vmem_exit(video_mm_t *mm) +{ + if (mm == NULL) { + printk(KERN_INFO "vmem_exit: invalid handle\n"); + return -1; + } + + if (mm->free_tree) { + avltree_free(mm->free_tree); + } + if (mm->alloc_tree) { + avltree_free(mm->alloc_tree); + } + + if (mm->page_list) { + VMEM_P_FREE(mm->page_list); + mm->page_list = NULL; + } + + mm->base_addr = 0; + mm->mem_size = 0; + mm->num_pages = 0; + mm->page_list = NULL; + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = 0; + mm->alloc_page_count = 0; + return 0; +} + +unsigned long vmem_alloc(video_mm_t *mm, int size, unsigned long pid) +{ + avl_node_t *node; + page_t *free_page; + int npages, free_size; + int alloc_pageno; + unsigned long ptr; + + if (mm == NULL) { + printk(KERN_INFO "vmem_alloc: invalid handle\n"); + return -1; + } + + if (size <= 0) + return -1; + + npages = (size + VMEM_PAGE_SIZE - 1)/VMEM_PAGE_SIZE; + + mm->free_tree = remove_approx_value(mm->free_tree, &node, MAKE_KEY(npages, 0)); + if (node == NULL) { + return -1; + } + free_page = node->page; + free_size = KEY_TO_VALUE(node->key); + + alloc_pageno = free_page->pageno; + set_blocks_alloc(mm, alloc_pageno, npages); + if (npages != free_size) { + int free_pageno = alloc_pageno + npages; + set_blocks_free(mm, free_pageno, (free_size-npages)); + } + + VMEM_P_FREE(node); + + ptr = mm->page_list[alloc_pageno].addr; + mm->alloc_page_count += npages; + mm->free_page_count -= npages; + + + return ptr; +} + +int vmem_free(video_mm_t *mm, unsigned long ptr, unsigned long pid) +{ + unsigned long addr; + avl_node_t *found; + page_t *page; + int pageno, prev_free_pageno, next_free_pageno; + int prev_size, next_size; + int merge_page_no, merge_page_size, free_page_size; + + + if (mm == NULL) { + printk(KERN_INFO "vmem_free: invalid handle\n"); + return -1; + } + + addr = ptr; + + mm->alloc_tree = avltree_remove(mm->alloc_tree, &found, MAKE_KEY(addr, 0)); + if (found == NULL) { + printk(KERN_INFO "vmem_free: 0x%08x not found\n", (int)addr); + VMEM_ASSERT(0); + return -1; + } + + /* find previous free block */ + page = found->page; + pageno = page->pageno; + free_page_size = page->alloc_pages; + prev_free_pageno = pageno-1; + prev_size = -1; + if (prev_free_pageno >= 0) { + if (mm->page_list[prev_free_pageno].used == 0) { + prev_free_pageno = mm->page_list[prev_free_pageno].first_pageno; + prev_size = mm->page_list[prev_free_pageno].alloc_pages; + } + } + + /* find next free block */ + next_free_pageno = pageno + page->alloc_pages; + next_free_pageno = (next_free_pageno == mm->num_pages) ? -1 : next_free_pageno; + next_size = -1; + if (next_free_pageno >= 0) { + if (mm->page_list[next_free_pageno].used == 0) { + next_size = mm->page_list[next_free_pageno].alloc_pages; + } + } + VMEM_P_FREE(found); + + /* merge */ + merge_page_no = page->pageno; + merge_page_size = page->alloc_pages; + if (prev_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(prev_size, prev_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_no = found->page->pageno; + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + if (next_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(next_size, next_free_pageno)); + if (found == NULL) { + VMEM_ASSERT(0); + return -1; + } + merge_page_size += found->page->alloc_pages; + VMEM_P_FREE(found); + } + + page->alloc_pages = 0; + page->first_pageno = -1; + + set_blocks_free(mm, merge_page_no, merge_page_size); + + mm->alloc_page_count -= free_page_size; + mm->free_page_count += free_page_size; + + return 0; +} + +int vmem_get_info(video_mm_t *mm, vmem_info_t *info) +{ + if (mm == NULL) { + printk(KERN_INFO "vmem_get_info: invalid handle\n"); + return -1; + } + + if (info == NULL) { + return -1; + } + + info->total_pages = mm->num_pages; + info->alloc_pages = mm->alloc_page_count; + info->free_pages = mm->free_page_count; + info->page_size = VMEM_PAGE_SIZE; + + return 0; +} + +#endif /* __RTK_VIDEO_MEMORY_MANAGEMENT_H__ */ diff --git a/drivers/soc/realtek/trace/Makefile b/drivers/soc/realtek/trace/Makefile new file mode 100644 index 000000000000..54591f405c86 --- /dev/null +++ b/drivers/soc/realtek/trace/Makefile @@ -0,0 +1 @@ +obj-y += rtk_pm.o diff --git a/drivers/soc/realtek/trace/rtk_pm.c b/drivers/soc/realtek/trace/rtk_pm.c new file mode 100644 index 000000000000..e5cc4e0c85ff --- /dev/null +++ b/drivers/soc/realtek/trace/rtk_pm.c @@ -0,0 +1,2 @@ +#define CREATE_TRACE_POINTS +#include diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aadaea052f51..06d567d834c1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -280,6 +280,16 @@ config SPI_DW_BT1_DIRMAP time-critical tasks (like the SPI memory operations implemented in this driver). +if SYNO_LSP_RTD1619B +config SPI_DW_RTK + tristate "Realtek SPI controller based on DW SPI core" + depends on ARCH_REALTEK + default n + help + Driver for the SPI controller core from DesignWare on + Realtek RTD139x, RTD16xx, RTD13xx, or RTD16xxb platform. + +endif # SYNO_LSP_RTD1619B endif config SPI_DLN2 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6fea5821662e..2d376e75e55a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -42,6 +42,9 @@ spi-dw-$(CONFIG_SPI_DW_DMA) += spi-dw-dma.o obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_SPI_DW_RTK) += spi-dw-rtk.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_SPI_EFM32) += spi-efm32.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o obj-$(CONFIG_SPI_FALCON) += spi-falcon.o diff --git a/drivers/spi/spi-dw-rtk.c b/drivers/spi/spi-dw-rtk.c new file mode 100644 index 000000000000..56fb66ea3817 --- /dev/null +++ b/drivers/spi/spi-dw-rtk.c @@ -0,0 +1,255 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Realtek SPI driver based on DW SPI Core on RTD139x, + * RTD16xx, or RTD13xx platform + * + * Copyright (c) 2020 Realtek Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spi-dw.h" + +#define DRIVER_NAME "spi-dw-rtk" +#define SPI_Wra_CTRL 0 + +struct rtk_spi { + struct dw_spi dws; + + void __iomem *spi_wrapper; + struct clk *clk; + struct reset_control *rstc; + struct device *dev; + u32 clk_div; + #if IS_ENABLED(CONFIG_SPI_SPIDEV) + struct spi_board_info info; + struct spi_device *spidev; + #endif /* CONFIG_SPI_SPIDEV */ +}; + +static inline struct rtk_spi *rtk_spi_to_hw(struct spi_device *spi) +{ + struct dw_spi *dws = spi_controller_get_devdata(spi->master); + struct rtk_spi *hw = container_of(dws, struct rtk_spi, dws); + + return hw; +} + +static inline void rtk_spi_wrap_ctrl(struct spi_device *spi, int val) +{ + struct rtk_spi *hw = rtk_spi_to_hw(spi); + + __raw_writel(val, hw->spi_wrapper + SPI_Wra_CTRL); +} + +static void rtk_spi_set_cs(struct spi_device *spi, bool enable) +{ + rtk_spi_wrap_ctrl(spi, enable ? 0x17 : 0x13); + dw_spi_set_cs(spi, enable); +} + +static int rtk_spi_probe(struct platform_device *pdev) +{ + struct rtk_spi *hw; + struct dw_spi *dws; + struct clk *clk = clk_get(&pdev->dev, NULL); + struct reset_control *rstc = + reset_control_get_exclusive(&pdev->dev, NULL); + u32 val; + int err = -ENODEV; + + if (WARN_ON(!(pdev->dev.of_node))) { + pr_err("[SPI] Error: No node\n"); + return err; + } + + hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + dws = &hw->dws; + /* Enable clk and release reset module */ + reset_control_deassert(rstc); /* release reset */ + clk_prepare_enable(clk); /* enable clk */ + + dev_set_drvdata(&pdev->dev, hw); + dws->set_cs = rtk_spi_set_cs; + + /* Find and map resources */ + dws->regs = of_iomap(pdev->dev.of_node, 0); + if (IS_ERR(dws->regs)) { + dev_err(&pdev->dev, "[SPI] DW SPI region map failed, addr 0x%p\n", dws->regs); + goto exit; + } + hw->spi_wrapper = of_iomap(pdev->dev.of_node, 1); + + if (IS_ERR(dws->regs)) { + dev_err(&pdev->dev, "[SPI] SPI wrapper region map failed, addr 0x%p\n", hw->spi_wrapper); + goto exit; + } + + dws->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (dws->irq < 0) { + dev_err(&pdev->dev, "[SPI] no irq resource?\n"); + err = -ENXIO; + goto exit; + } + + if (!of_property_read_u32(pdev->dev.of_node, "num-chipselect", &val)) + dws->num_cs = val; + if (!of_property_read_u32(pdev->dev.of_node, "bus-num", &val)) + dws->bus_num = val; + if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", &val)) + dws->max_freq = val; + + hw->clk = clk; + hw->rstc = rstc; + hw->dev = &pdev->dev; + + pm_runtime_enable(&pdev->dev); + + /* call setup function */ + err = dw_spi_add_host(&pdev->dev, &hw->dws); + if (err) { + pr_err("[SPI] Init failed, ret = %d\n", err); + goto dw_err_exit; + } + dev_info(&pdev->dev, "[SPI] num_cs %d, bus_num %d, max_freq %d, irq %d\n", + hw->dws.num_cs, hw->dws.bus_num, hw->dws.max_freq, + hw->dws.irq); + + #if IS_ENABLED(CONFIG_SPI_SPIDEV) + /* add spidev */ + strcpy(hw->info.modalias, "spidev"); + hw->info.max_speed_hz = 16 * 1000 * 1000; + hw->info.platform_data = hw; + hw->info.mode = SPI_MODE_0; + + hw->spidev = spi_new_device(hw->dws.master, &hw->info); + if (hw->spidev) { + dev_info(&pdev->dev, "[SPI] add spidev for %s\n", + dev_name(&hw->spidev->dev)); + } else { + dev_err(&pdev->dev, "[SPI] spi_new_device failed\n"); + } + #endif /* CONFIG_SPI_SPIDEV */ + + return 0; + +dw_err_exit: + pm_runtime_disable(&pdev->dev); + +exit: + /* Disable clk and reset module */ + reset_control_assert(hw->rstc); /* reset */ + clk_disable_unprepare(hw->clk); /* disable clk */ + reset_control_put(rstc); + dev_set_drvdata(&pdev->dev, NULL); + return err; +} + +static int rtk_spi_remove(struct platform_device *dev) +{ + struct rtk_spi *hw = platform_get_drvdata(dev); + struct dw_spi *dws = &hw->dws; + + dw_spi_remove_host(dws); + + pm_runtime_disable(&dev->dev); + + /* Disable clk and reset module */ + reset_control_assert(hw->rstc); /* reset */ + clk_disable_unprepare(hw->clk); /* disable clk */ + reset_control_put(hw->rstc); + + dev_set_drvdata(&dev->dev, NULL); + return 0; +} + + +#ifdef CONFIG_PM_SLEEP + +static int rtk_spi_suspend(struct device *dev) +{ + struct rtk_spi *hw = dev_get_drvdata(dev); + struct dw_spi *dws = &hw->dws; + int ret; + + dev_info(dev, "[SPI] Enter %s\n", __func__); + + /* save SPI baud rate */ + hw->clk_div = dw_readl(dws, DW_SPI_BAUDR); + + ret = dw_spi_suspend_host(dws); + + dev_info(dev, "[SPI] Exit %s\n", __func__); + + return ret; +} + +static int rtk_spi_resume(struct device *dev) +{ + struct rtk_spi *hw = dev_get_drvdata(dev); + struct dw_spi *dws = &hw->dws; + int ret; + + dev_info(dev, "[SPI] Enter %s\n", __func__); + + ret = dw_spi_resume_host(dws); + + /* restore SPI baud rate */ + spi_enable_chip(dws, 0); + spi_set_clk(dws, hw->clk_div); + spi_enable_chip(dws, 1); + + dev_info(dev, "[SPI] Exit %s\n", __func__); + + return ret; +} + +static SIMPLE_DEV_PM_OPS(rtk_spi_pm_ops, rtk_spi_suspend, rtk_spi_resume); + +#define RTK_SPI_PM_OPS (&rtk_spi_pm_ops) + +#else /* CONFIG_PM_SLEEP */ +#define RTK_SPI_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + + +static const struct of_device_id rtk_spi_match[] = { + { .compatible = "realtek,rtk-dw-apb-ssi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtk_spi_match); + +static struct platform_driver rtk_spi_driver = { + .probe = rtk_spi_probe, + .remove = rtk_spi_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = RTK_SPI_PM_OPS, + .of_match_table = of_match_ptr(rtk_spi_match), + }, +}; +module_platform_driver(rtk_spi_driver); + +MODULE_AUTHOR("Eric Wang "); +MODULE_DESCRIPTION("SPI driver based on DW SPI Core on RTK platform"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index c73f581aea06..ca6b1443e546 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -476,8 +476,6 @@ struct sdio_data intf_data; static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj) { /* todo: get interface type from dvobj and the return the dev accordingly */ -#ifdef RTW_DVOBJ_CHIP_HW_TYPE -#endif return &dvobj->intf_data.func->dev; } diff --git a/drivers/syno/Kconfig b/drivers/syno/Kconfig new file mode 100644 index 000000000000..4c606d1f1a23 --- /dev/null +++ b/drivers/syno/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +menu "Synology" + +config SYNO_DM_FLASHCACHE + tristate "Block level disk caching target" + depends on BLK_DEV_DM + default n + +config SYNO_SYNOBIOS + tristate "synobios" + default n + +endmenu diff --git a/drivers/syno/Makefile b/drivers/syno/Makefile new file mode 100644 index 000000000000..fa86b5b7a59b --- /dev/null +++ b/drivers/syno/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += syno-flashcache-control-driver/ +obj-y += syno-mem-saving-driver/ +obj-y += synobios/ diff --git a/drivers/syno/syno-flashcache-control-driver/Makefile b/drivers/syno/syno-flashcache-control-driver/Makefile new file mode 100644 index 000000000000..7455f128e697 --- /dev/null +++ b/drivers/syno/syno-flashcache-control-driver/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SYNO_DM_FLASHCACHE) += syno_flashcache_control.o diff --git a/drivers/syno/syno-flashcache-control-driver/syno_flashcache_control.c b/drivers/syno/syno-flashcache-control-driver/syno_flashcache_control.c new file mode 100644 index 000000000000..382fd9821fd2 --- /dev/null +++ b/drivers/syno/syno-flashcache-control-driver/syno_flashcache_control.c @@ -0,0 +1,38 @@ +#include +#include + +#include /* printk() */ +#include /* everything... */ +#include /* size_t */ +#include +#include +#include +#include +#include + +MODULE_LICENSE("Dual BSD/GPL"); + +int flashcache_control_init(void) +{ + return 0; +} + +void flashcache_control_cleanup(void) +{ +} + +// export symbol can be static +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int syno_flashcache_proc_count = 0; +DEFINE_SEMAPHORE(syno_flashcache_proc_mutex); +#else +static int syno_flashcache_proc_count = 0; +static DEFINE_SEMAPHORE(syno_flashcache_proc_mutex); +#endif + +EXPORT_SYMBOL(syno_flashcache_proc_count); +EXPORT_SYMBOL(syno_flashcache_proc_mutex); + +module_init(flashcache_control_init); +module_exit(flashcache_control_cleanup); + diff --git a/drivers/syno/syno-mem-saving-driver/Makefile b/drivers/syno/syno-mem-saving-driver/Makefile new file mode 100644 index 000000000000..84bd514f5577 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_SYNO_DM_FLASHCACHE) += flashcache_syno.o +flashcache_syno-objs := flashcache_conf.o flashcache_main.o flashcache_subr.o flashcache_ioctl.o flashcache_procfs.o syno_functions.o syno_kernel_functions.o syno_quickflush.o syno_md_update.o diff --git a/drivers/syno/syno-mem-saving-driver/dkms.conf b/drivers/syno/syno-mem-saving-driver/dkms.conf new file mode 100644 index 000000000000..3b005bc40020 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/dkms.conf @@ -0,0 +1,7 @@ +BUILT_MODULE_NAME=flashcache +DEST_MODULE_LOCATION=/kernel/drivers/block +PACKAGE_NAME=flashcache +PACKAGE_VERSION= +AUTOINSTALL=yes +REMAKE_INITRD=yes +MAKE="KERNEL_TREE=$kernel_source_dir make modules" diff --git a/drivers/syno/syno-mem-saving-driver/flashcache.h b/drivers/syno/syno-mem-saving-driver/flashcache.h new file mode 100644 index 000000000000..320725552f75 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache.h @@ -0,0 +1,2162 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache.h + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#ifndef FLASHCACHE_H +#define FLASHCACHE_H + +// Add for utils to include following LINUX_VERSION_CODE macro +#include + +#include "syno_feature_defines.h" +#include "syno_common_tool.h" +#include "syno_common_4k_driver.h" + +#define SYNO_VERSION_NAME "v25-pin-file" + +#ifdef __KERNEL__ + +/* + * CONFIG_SYNO_BLOCK_FLASHCACHE_SUPPORT is used in linux 4.4, and is changed to + * a more explict name CONFIG_SYNO_MD_DM_EXTRA_IOCTL in linux 5.10 + */ + +#include +#include +#include +#include +#include + +extern ktime_t ktime_zero; + +#ifdef MY_ABC_HERE +enum { + TEST_VMALLOC_FAIL = 1, + TEST_MALLOC_FAIL_IN_CREATE = 2, + TEST_PIN_FILE_BITMAP_ALLOC_FAIL = 3, + TEST_OQF_INVALIDATE_DELAY = 4, + TEST_OQF_BITMAP_ALLOC_FAIL = 5, + TEST_CORRECTION_LIST_ALLOC_FAIL = 6, + TEST_NEW_DMC_GROUP_ALLOC_FAIL = 7, + TEST_NEW_MU_ALLOC_FAIL = 8, +}; +extern long global_tester; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include "flashcache_pin_file.h" +#endif + +#include "syno_kernel_functions.h" + +/* Like ASSERT() but always compiled in */ + +#define VERIFY(x) do { \ + if (unlikely(!(x))) { \ + dump_stack(); \ + panic("VERIFY: assertion (%s) failed at %s (%d)\n", \ + #x, __FILE__ , __LINE__); \ + } \ +} while(0) + +#define VERIFY_WARN(x) do { \ + if (unlikely(!(x))) { \ + dump_stack(); \ + WARN(1, "VERIFY_WARN: assertion (%s) failed at %s (%d)\n", \ + #x, __FILE__ , __LINE__); \ + } \ +} while(0) + +#define DMC_DEBUG 0 +#define DMC_DEBUG_LITE 0 + +// For DMERR +#include +#include +#define DM_MSG_PREFIX "flashcache" +#define DMC_PREFIX "flashcache: " + +#if DMC_DEBUG +#define DPRINTK( s, arg... ) printk(DMC_PREFIX s "\n", ##arg) +#else +#define DPRINTK( s, arg... ) +#endif + +#if BITS_PER_LONG == 32 +#if defined(CONFIG_SYNO_ALPINE) +#define EC_EMULATE_U64_DIVISION +#endif +#endif + + +/* + * Block checksums : + * Block checksums seem a good idea (especially for debugging, I found a couple + * of bugs with this), but in practice there are a number of issues with this + * in production. + * 1) If a flash write fails, there is no guarantee that the failure was atomic. + * Some sectors may have been written to flash. If so, the checksum we have + * is wrong. We could re-read the flash block and recompute the checksum, but + * the read could fail too. + * 2) On a node crash, we could have crashed between the flash data write and the + * flash metadata update (which updates the new checksum to flash metadata). When + * we reboot, the checksum we read from metadata is wrong. This is worked around + * by having the cache load recompute checksums after an unclean shutdown. + * 3) Checksums require 4 or 8 more bytes per block in terms of metadata overhead. + * Especially because the metadata is wired into memory. + * 4) Checksums force us to do a flash metadata IO on a block re-dirty. If we + * didn't maintain checksums, we could avoid the metadata IO on a re-dirty. + * Therefore in production we disable block checksums. + */ +#if 0 +#define FLASHCACHE_DO_CHECKSUMS +#endif + +/* Fix writethrough error while SSDs are in RAID 0 and polled out */ +/* + * Fix the errors in writeback mode when the second ssd fail. + * Let kernel's dm-io layer can report errors from md1 cache. + */ + +//#define SYNO_FLASHCACHE_DEBUG +#ifdef SYNO_FLASHCACHE_DEBUG +struct _syno_debug { + int entry; +} ; +#endif + + +#if DMC_DEBUG_LITE +#define DPRINTK_LITE( s, arg... ) printk(DMC_PREFIX s "\n", ##arg) +#else +#define DPRINTK_LITE( s, arg... ) +#endif + +/* Number of pages for I/O */ +#define FLASHCACHE_COPY_PAGES (1024) + +/* Default cache parameters */ +#define DEFAULT_CACHE_SIZE 65536 +#define DEFAULT_CACHE_ASSOC 512 +#define DEFAULT_BLOCK_SIZE 8 /* 4 KB */ +#define DEFAULT_MD_BLOCK_SIZE 8 /* 4 KB */ +#define FLASHCACHE_MAX_MD_BLOCK_SIZE 128 /* 64 KB */ + +#define FLASHCACHE_FIFO 0 +#define FLASHCACHE_LRU 1 + +/* + * The LRU pointers are maintained as set-relative offsets, instead of + * pointers. This enables us to store the LRU pointers per cacheblock + * using 4 bytes instead of 16 bytes. The upshot of this is that we + * are required to clamp the associativity at an 8K max. + */ +#define FLASHCACHE_MIN_ASSOC 256 +#define FLASHCACHE_MAX_ASSOC 8192 +#define FLASHCACHE_LRU_NULL 0xFFFF + +struct cacheblock; + +struct cache_set { + u_int32_t set_fifo_next; + u_int32_t set_clean_next; +#ifdef MY_ABC_HERE +#else + u_int16_t clean_inprog; + // use for clean_set() to calculate a threshold for writeback + u_int16_t nr_dirty; + u_int16_t dirty_fallow; + unsigned long fallow_tstamp; + unsigned long fallow_next_cleaning; +#endif + u_int16_t lru_head, lru_tail; +}; + +struct flashcache_errors { + atomic_t disk_read_errors; + atomic_t disk_write_errors; + atomic_t ssd_read_errors; + atomic_t ssd_write_errors; + atomic_t memory_alloc_errors; + atomic_t write_disk_sync_errors; +}; + +enum latency_step { + LAT_PREPROCESS = 0, + LAT_DISK_READ = 1, + LAT_DISK_WRITE = 2, + LAT_SSD_READ = 3, + LAT_SSD_WRITE = 4, + LAT_DISK_READ_MEM = 5, + LAT_MEM_WRITE_SSD = 6, + LAT_PENDING = 7, + LAT_DO_IO_WQ = 8, + LAT_MD_WRITE_SSD = 9, + LAT_MD_WRITE_INPROG_WAIT = 10, + LAT_MD_WRITE_START_WQ = 11, + LAT_MD_WRITE_CALLBACK_WQ = 12, + LAT_UNCACHED_READ = 13, + LAT_UNCACHED_WRITE = 14, + LAT_UNCACHED_IO_COMPLETE_WQ = 15, + LAT_DO_PREREAD_WQ = 16, + LAT_FLUSH_BIO = 17, + LAT_END_BIO = 18, + LAT_MD_WRITE_FUA = 19, + LAT_MD_WRITE_REG = 20, + LAT_TYPE_NUM, +}; + +/* + * Latency Level: we use unsigned char, total 256 available levels. + * for latency below 1000ms, we use step of 5 ms, 200 levels + * for latency from 1 - 20 seconds, we use step of 1 second, 19 levels + * for latency from 20 - 128 seconds, we use step of 4 seconds, 27 levels + * for latency > 128 seconds we use only one level. + * for simplicity, round down. + * implementations are: + * jiffy_to_latency_level + * latency_level_to_ms + */ + +typedef unsigned char lat_level_t; + +struct latency_entry { + unsigned char step; + lat_level_t level; +}; + +enum cache_io_type { + TYPE_DONT_CARE = -1, + TYPE_SSD = 0, + TYPE_DISK = 1, + TYPE_COULD_SSD = 2, + CACHE_IO_TYPE_NUM, +}; + +#define LAT_DIAGNOSE_ENABLED(plat) ((plat)->entry_cnt != LAT_INVALID_ENTRY_CNT) +#define ALT_LAT_STATS_IDX(dmc) (dmc->lat_stats_idx ^ 1) +#define LAT_INVALID_ENTRY_CNT 255 + +#define LAT_LEVEL_NUM (1 << (sizeof(lat_level_t) * 8)) + +struct io_latency { + unsigned long start_jiffy; + unsigned long last_jiffy; + unsigned char next_step; // optional, only used when we cannot distinguish step in callee + unsigned char entry_cnt; + unsigned char io_type; + struct latency_entry entries[LAT_TYPE_NUM]; +}; + +struct io_latency_stats { + unsigned long highest_lat_jiffy; + unsigned char highest_entry_cnt; + struct latency_entry highest_lat_entry[LAT_TYPE_NUM]; + unsigned int lat_table[LAT_TYPE_NUM][LAT_LEVEL_NUM]; + unsigned int over_thres_cnt; +}; + +#ifdef MY_ABC_HERE +struct flush_data { + struct bio *master_bio; + struct cache_c *dmc; + struct io_latency io_lat; +}; +#endif + +/* + * SYNO: + * For the special case that flashcache statistics could have race condition, + * we modify the type of some attributes to atomic64_t + */ +struct flashcache_stats { + atomic64_t reads; /* Number of reads */ + atomic64_t writes; /* Number of writes */ + atomic64_t read_hits; /* Number of cache hits */ + atomic64_t write_hits; /* Number of write hits (includes dirty write hits) */ + atomic64_t dirty_write_hits; /* Number of "dirty" write hits */ + atomic64_t replace; /* Number of cache replacements */ + atomic64_t wr_replace; +#ifdef MY_ABC_HERE + atomic64_t wr_miss_ssd; /* write miss and write into ssd */ +#endif + atomic64_t wr_invalidates; /* Number of write invalidations */ + atomic64_t rd_invalidates; /* Number of read invalidations */ + atomic64_t pending_inval; /* Invalidations due to concurrent ios on same block */ +#ifdef MY_ABC_HERE + atomic64_t pending_preread; /* pending jobs that are prereaded later */ +#endif +#ifdef FLASHCACHE_DO_CHECKSUMS + atomic64_t checksum_store; + atomic64_t checksum_valid; + atomic64_t checksum_invalid; +#endif + atomic64_t enqueues; /* enqueues on pending queue */ + atomic64_t cleanings; /* Total CB written back include error, increased after MD update or error */ + atomic64_t fallow_cleanings; + atomic64_t noroom; /* No room in set */ + atomic64_t md_write_dirty; /* Metadata sector writes dirtying block */ + atomic64_t md_write_clean; /* Metadata sector writes cleaning block */ + atomic64_t md_write_batch; /* How many md updates did we batch ? */ + atomic64_t md_ssd_writes; /* How many md ssd writes did we do ? */ + atomic64_t pid_drops; + atomic64_t pid_adds; + atomic64_t pid_dels; + atomic64_t expiry; + atomic64_t front_merge, back_merge; /* Write Merging */ + atomic64_t uncached_reads, uncached_writes; + atomic64_t uncached_sequential_reads, uncached_sequential_writes; + atomic64_t disk_reads, disk_writes; + atomic64_t ssd_reads, ssd_writes; + atomic64_t uncached_io_requeue; + atomic64_t skipclean; + atomic64_t trim_blocks; +#ifdef MY_ABC_HERE + atomic64_t qf_nr_writes; /* total io sent to ssd for writeback */ + atomic64_t qf_fallow_bits_unset; /* total fallow bits unset from 1 -> 0 */ + atomic64_t qf_bits_mismatch; /* set in volume bitmap but no dirty cb */ + atomic64_t qf_queued_sync_io_processed; +#else + atomic64_t clean_set_ios; + atomic64_t cleanings_over_threshold; +#endif + atomic64_t skip_unaligned_io; + atomic64_t read_hit_match_none_read_disk; + atomic64_t read_hit_match_partial; + atomic64_t read_hit_check_write_ssd; + atomic64_t read_hit_busy_in_io; + atomic64_t read_hit_busy_wait_queue; + atomic64_t write_hit_busy_inval; + atomic64_t do_pending_no_error_drity_writeback; + atomic64_t job_mem_get_in; + atomic64_t job_mem_get_out; + atomic64_t prereads; +#ifdef MY_ABC_HERE + atomic64_t dirty_writeback_sector; + atomic64_t dirty_writeback_sync_sector; +#endif +#ifdef MY_ABC_HERE + atomic64_t inval_dirty_writeback; + atomic64_t write_miss_inval; + atomic64_t map_inval; + atomic64_t uncacheable_inval; + atomic64_t do_pending_no_error_inval; + atomic64_t pending_enqueue_inval_start; + atomic64_t pending_enqueue_inval_done; + atomic64_t disk_flush_start; + atomic64_t disk_flush_done; + atomic64_t dirty_writeback_start; + atomic64_t dirty_writeback_done; + atomic64_t md_flush_start; + atomic64_t md_flush_done; +#endif +}; + +/* + * Sequential block history structure - each one + * records a 'flow' of i/o. + */ +struct sequential_io { + sector_t most_recent_sector; + sector_t last_bio_sectors; + // Support 4k*n bio size + sector_t sequential_sectors; + /* We use LRU replacement when we need to record a new i/o 'flow' */ + struct sequential_io *prev, *next; +}; +#define SKIP_SEQUENTIAL_THRESHOLD 0 /* 0 = cache all, >0 = dont cache sequential i/o more than this (kb) */ +#define SEQUENTIAL_TRACKER_QUEUE_DEPTH 32 /* How many io 'flows' to track (random i/o will hog many). + * This should be large enough so that we don't quickly + * evict sequential i/o when we see some random, + * but small enough that searching through it isn't slow + * (currently we do linear search, we could consider hashed */ +#define SKIP_SEQ_DEFAULT_FGAP_KB 128 +#define SKIP_SEQ_DEFAULT_BGAP_KB 16384 +#ifdef MY_ABC_HERE +// option_string[] +typedef enum _query_type { + QUERY_ERROR = -1, + QUERY_NUM_SETS, + QUERY_SET_NUM, + QUERY_DUMP_SET, + QUERY_DUMP_SET_LRU_LIST, + QUERY_BITMAP, +} query_type_t; + +typedef struct _internal_query_t { + query_type_t query_type; + // QUERY_SET_NUM + u64 block_start_sector; + // QUERY_DUMP_SET + unsigned int set_num; +} internal_query_t; +#endif + +#ifdef MY_ABC_HERE +typedef enum _cache_state { + CACHE_UNKNOWN = -1, + CACHE_DISABLED, + CACHE_ENABLED, + CACHE_WAIT_OLD_IOS_COMPLETED, + CACHE_WAIT_DISABLE, +} cache_state_t; + +typedef enum _dm_attr { + DM_ATTR_CACHE_UNKNOWN = -1, + DM_ATTR_CACHE_DISABLE, + DM_ATTR_CACHE_ENABLE, +} dm_attr_t; + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +typedef struct _bitmap_control { + spinlock_t lock; + int in_use; +} bitmap_control_t; +#endif + +#ifdef MY_ABC_HERE +#define LIMIT_WRITEBACK_ERR 10 +#define LIMIT_WRITEBACK_SYNC_ERR 10 +#define LIMIT_DO_PENDING_ERR 10 +#define LIMIT_DIRTY_INVAL 10 +#define LIMIT_UNCACHED_IO 1 +#define LIMIT_MD_IO_ERROR 10 + +typedef struct _print_limit { + int writeback_err; + int writeback_sync_err; + int do_pending_err; + int dirty_inval; + int uncached_io; + int md_io_error; +} print_limit_t; + +typedef enum _attribute { + ATTR_NONE = 0, // default + ATTR_FORCE_REMOVE = 1, +} attribute_t; + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +typedef enum _WRITEBACK_SYNC_STATE { + SYNC_STATE_RUNNING, + SYNC_STATE_STOPPED, +} WRITEBACK_SYNC_STATE; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +#define NQF_MGMT_ITVL_SEC 2 +#define NQF_TIMESLICE_SEC 10 + +// TODO: rename, online_quickflush -> normal qf, quickflush -> sync qf +typedef struct online_quickflush { + int inited; + + struct mutex mtx; // INSIDE oqf->bitmap_rwsem + + struct delayed_work wb_work; + int sysctl_enable_wb_work; // For develop purpose + + /* Protected by oqf mtx */ + int nqf_inprog; // if syno_start_nqf function is running + int detect_fallow_inprog; // if the detect_fallow inprog + + WRITEBACK_SYNC_STATE sync_state; // under oqf mtx + + atomic_t nr_fallow; + unsigned long last_fallow_tstamp; + + /* + * normal quickflush works by calling main func (syno_start_nqf) + * to send IO, each IO loop back to call main func again. + * trigger_cnt records how many times the main func are expected to be + * called by the loop. The value is decreased at end of main func. + * When trigger_cnt reach 0, nqf process is paused until main func is + * called by external threads. wqh is waked up when trigger_cnt reaches 0 + */ + int trigger_cnt; // protect by mtx + wait_queue_head_t wqh; + + int sync_trigger_cnt; // protect by mtx + + /* use two semaphore to make sure there's at most one job waiting in + * syno_start_sqf */ + struct semaphore sqf_sem2; + struct semaphore sqf_sem1; + + struct rw_semaphore bitmap_rwsem; // OUTSIDE oqf->mtx + + /* + * Every bit implies OQF_VB_PER_BIT volume blocks. + * for 4 VB every bit, 1T volume requires 512KB mem + * Record dirty when in sqf, fallow when in nqf. + * For dirty/fallow cb, the bit MUST be set. + * For a set bit, the cb might not be dirty/fallow. + * Fallow/Dirty set by worker thread, cleaned ONLY by syno_start_nqf/sqf + * + * Read lock: scan, fallow set. + * it's possible to run scan and set fallow at the same time + * since getting a non-fallow for a fallow block is ok. + * The block will be handled in the next round. + * fallow sets always executed by fallow wq in single thread. + * Write lock: reload table, unset, construct sync bitmap + */ + int *volume_bitmap; // protected by bitmap_rwsem + unsigned long bitmap_num_idx; // protected by bitmap_rwsem + /* Index of current bit in bitmap, protected by nqf_inprog in nqf, + * sqf_sem in sqf */ + u64 bit_idx; + + /* if dmc in dmcg->nqf_pending_dmcs, protected by dmcg->rw_sem */ + int dmcg_wb_scheduled; +} online_qf_t; + +#define PLUG_WB_DEFAULT_DISK_WRITE 8 +#define PLUG_WB_DEFAULT_SSD_READ 8 + +#if defined(CONFIG_SYNO_ALPINE) +#define PLUG_WB_DEFAULT_BATCH_SIZE 32 +#define PLUG_WB_SYNC_DISK_WRITE (128 + PLUG_WB_DEFAULT_BATCH_SIZE) +#else +#define PLUG_WB_DEFAULT_BATCH_SIZE 64 +/* 256 is experimental value from quickflush v1, also work for full stripe merge + * since we send a batch at a time, add a batch size as buffer. */ +#define PLUG_WB_SYNC_DISK_WRITE (256 + PLUG_WB_DEFAULT_BATCH_SIZE) +#endif +#define PLUG_WB_SYNC_SSD_READ (PLUG_WB_DEFAULT_BATCH_SIZE * 2) + +#define PLUG_WB_HAS_BATCH(plug_wb) ((plug_wb)->cur_batch_len) +#define PLUG_WB_HAS_BATCH_AND_DISK_WRITE_READY(plug_wb) \ + (PLUG_WB_HAS_BATCH(plug_wb) && 0 == (plug_wb)->unfinished_read_in_batch) + +/* Structure for plug writeback */ +typedef struct _plug_wb_t { + struct list_head io_queue; // jobs put in after ssd read DONE + struct list_head sync_io_queue; // jobs put in after ssd read SENT (to keep order) + struct list_head complete_queue; + struct list_head wb_done_queue; + + unsigned long long seq; + unsigned long long cur_batch_head; + int cur_batch_len; + int unfinished_read_in_batch; + + int ssd_read_inprog; + int disk_write_inprog; + + /* + * Use two copy since the following parameters are protectd by lock. + * data are stored in sysctl_* first then put to the other one under lock + * + * We expect userspace to control ssd_read_ios_limit. + * disk_write_ios_limit is set to sync default value when sync start and + * reset to normal value when sync finished. + */ + int sysctl_disk_write_ios_limit; + int sysctl_ssd_read_ios_limit; + int sysctl_batch_size; + int disk_write_ios_limit; + int ssd_read_ios_limit; // works like the old clean ios total + int batch_size; + + /* We lock the queue while processing, won't loop forever */ + struct work_struct work; + + /* We splice wb_done_queue, process only limited io so won't loop indefinitly */ + struct work_struct wb_done_work; + + /* WARNING: Locked inside cache_spin_lock & oqf lock */ + spinlock_t lock; +} plug_wb_t; + +#endif + +#ifdef MY_ABC_HERE + +/* + * MU_HAS_PENDING_REQ + * Another MU that cannot merge with ongoing MU is queued for this block + * + * MU_FLUSH1/2: + * for need flush MU, since MU might be pending + * (i.e., not belong to the ongoing MU). We need 2 flags to identify which + * CB to update after MU finished. Correspond to SYNCED1/2 + * + * MU_MD_IO_COMBO: + * If the other type of MU (flush/no flush) is MD IO pending when the + * MD IO of the current Mu is going to be issued, then this MD IO counts + * for both types. + * The flag means the other type of current mu block need to be updated too + * when the md io returns + * + * TODO: add NEED_DO_PENDING flag, now FORCED + FORCED_RESTART don't need to + * call do pending on md io error. + * MU_FORCED: + * MU must be handled immediately. For invalidate. Some IO must be pending + * in one or multiple cbs. + * See FORCED_RESTART for more information + * + * MU_IN_QUEUE: + * mask for debug use only + * + * MU_FORCED_RESTART: + * Force mu request come in when normal mu MD_IO_INRPOG. + * Need to restart the MU as soon as md io finish. + * The normal mu blk is marked MU_FORCED so following forced mu won't + * overwrite it. + * If MD IO error happen on such block, no need to do_pending. + * + * MU_PENDING_REQ_FORCED: + * is pending request forced or not, must coexist with MU_HAS_PENDING_REQ + * + * MU_FUA: + * must be no flush MU. Indicate a fua bio is waiting in mu->fua_job_list. + * The corresponding MD IO must also be fua. + * + * MU_MD_IO_NEED_FUA: + * Set after the mu_blk is picked to send md io and unset after io sent. + * MU_FUA will only be set on no flush mu, but for combo io the flush mu + * will always be picked to send io so we need some way to retain fua info. + * Carrying MU_FUA to flush mu makes it too complicated. Use anther flag + * instead. + * + * MU_PENDING_BEFORE_FLUSH: + * If MU_HAS_PENDING_REQ on a no flush mu_blk set before flush bio, the + * pending req should be included by flush bio. Set MU_PENDING_BEFORE_FLUSH + * for mu blocks with pending request when splicing md_io_inprog_queue to + * ext_flush->md_io_inprog_queue. When md io finished, mu block with this + * flag will be requeueud to ext_flush->md_io_pending_queue instead so it + * will be handled by this flush. + */ + +#define MU_MD_IO_PENDING (1 << 0) +#define MU_DISK_FLUSH_PENDING (1 << 1) +#define MU_HAS_PENDING_REQ (1 << 2) +#define MU_INPROG (1 << 3) +#define MU_FLUSH_1 (1 << 4) +#define MU_FLUSH_2 (1 << 5) +#define MU_NEED_FLUSH (MU_FLUSH_1 | MU_FLUSH_2) +#define MU_MD_IO_COMBO (1 << 6) +#define MU_MD_IO_INPROG (1 << 7) +#define MU_FORCED (1 << 8) +#define MU_SSD_FLUSH_PENDING (1 << 9) +#define MU_SSD_FLUSH_INPROG (1 << 10) +#define MU_DISK_FLUSH_INPROG (1 << 11) +#define MU_IN_QUEUE (MU_DISK_FLUSH_PENDING | MU_DISK_FLUSH_INPROG | MU_MD_IO_PENDING | \ + MU_SSD_FLUSH_PENDING | MU_SSD_FLUSH_INPROG | MU_MD_IO_INPROG) +#define MU_FORCED_RESTART (1 << 12) +#define MU_PENDING_REQ_FORCED (1 << 13) +#define MU_SENT_BY_NORMAL (1 << 14) +#define MU_SENT_BY_EXT_FLUSH (1 << 15) +#define MU_SENT_BY_THROTL (1 << 16) +#define MU_SENT_BY_FORCE (1 << 17) +#define MU_SENT_BY_FUA (1 << 18) +#define MU_SENT_BY (MU_SENT_BY_EXT_FLUSH | MU_SENT_BY_NORMAL | MU_SENT_BY_THROTL | \ + MU_SENT_BY_FORCE | MU_SENT_BY_FUA) +#define MU_PENDING_REQ_FUA (1 << 19) +#define MU_FUA (1 << 20) +#define MU_MD_IO_NEED_FUA (1 << 21) +#define MU_PENDING_BEFORE_FLUSH (1 << 22) + +/* Each metadata block takes 32 bytes + * each metadata block represents 16 MB data. + * 1MB cache need 2 bytes of mem. 1T cache need 2MB of mem */ +typedef struct _md_udpate_block { + struct list_head node; + int flags; /* MU_* flags */ + int idx; + + /* For need flush MU, start counting time after disk flush finished + * Flush mu already waited for fallow delays, another 1 min should be ok */ + unsigned long tstamp; + // TODO: bitmap to record what to udpate? +} mu_blk_t; + +/* True if ANY of the flag is set in the mu_blk. + * To check if ALL flags are set, use mu_blk_flagged_all. */ +static inline int mu_blk_flagged_any(mu_blk_t *mu_blk, int flag) +{ + return ((mu_blk->flags & flag)); +} + +static inline int mu_blk_flagged_all(mu_blk_t *mu_blk, int flag) +{ + return ((mu_blk->flags & flag) == flag); +} + +static inline void mu_blk_set_flag(mu_blk_t *mu_blk, int flag) +{ + mu_blk->flags |= flag; +} + +static inline void mu_blk_unset_flag(mu_blk_t *mu_blk, int flag) +{ + mu_blk->flags &= ~(flag); +} + +static inline int mu_blk_test_clear_flag_any(mu_blk_t *mu_blk, int flag) +{ + if (mu_blk_flagged_any(mu_blk, flag)) { + mu_blk_unset_flag(mu_blk, flag); + return 1; + } + + return 0; +} + +enum { + MU_BLK_TYPE_NOFLUSH, + MU_BLK_TYPE_FLUSH, + NUM_MU_BLK_TYPE, +}; + +typedef struct _new_mu_ext_flush_bio_node { + struct list_head node; + struct bio *bio; + struct io_latency io_lat; +} ext_flush_bio_node_t; + +typedef enum _EXT_FLUSH_DRIVE_FLUSH_STAGE { + FLUSH_WAITING, // SSD flush need to wait for all md io done + FLUSH_REQUESTED, + FLUSH_INPROG, + FLUSH_DONE, +} EXT_FLUSH_DRIVE_FLUSH_STAGE; + +typedef struct _new_mu_ext_flush { + int inprog; + + /* might also have flush mu inside, won't be too may, doesn't matter + * Since they are inprog, should finish soon. */ + struct list_head md_io_inprog_queue; + struct list_head md_io_pending_queue; + + struct list_head flush_bios_handling; + struct list_head flush_bios_pending; + + EXT_FLUSH_DRIVE_FLUSH_STAGE disk_flush_stage; + EXT_FLUSH_DRIVE_FLUSH_STAGE ssd_flush_stage; + + /* This wq handles finite number IOs, won't loop forever */ + // TODO: do we need this or we can send io directly + struct work_struct send_io_work; + + int error; +} ext_flush_t; + +typedef struct _md_dev_flush { + struct list_head pending_queue; + struct list_head inprog_queue; + + /* Handle LIMITED number of md io, won't loop forever */ + struct work_struct complete_work; + + struct bio *bio; + + /* don't send flush too often, used to check if we can send next flush */ + unsigned long last_flush_jif; + int inprog; + int forced; // ignore time / item in queue constraint. + +} dev_flush_t; + +#define MU_DEFAULT_FLUSH_ITVL_SEC 30 +#define MU_DEFAULT_DELAY_SEC 30 + +typedef struct _new_md_update { + + dev_flush_t disk_flush; + dev_flush_t ssd_flush; + int flush_itvl_sec; + + struct list_head fua_job_list; + + /* for combo mu, inprog queue doesn't not contains sib mu */ + struct list_head md_io_inprog_queue; + struct list_head md_io_pending_queue; + struct list_head md_io_for_flush_pending_queue; + int md_io_pending_queue_size; // for throttle, target only no flush mu + + /* Handle LIMITED number of md io, won't loop forever */ + struct work_struct md_io_complete_work; + struct kcached_job *md_io_complete_job_queue; + + wait_queue_head_t remove_wqh; + + struct delayed_work dwork; + + mu_blk_t *mu_blocks[NUM_MU_BLK_TYPE]; + int inprog_blk_num[NUM_MU_BLK_TYPE]; + int pending_blk_num[NUM_MU_BLK_TYPE]; + + ext_flush_t ext_flush; + + // TODO: no need mu in var name + int sysctl_mu_ios_total; // will not limit ext flush + int sysctl_mu_delay_sec; + int sysctl_mu_check_itvl_sec; + + int allow_throtl; // Will it be candidate of throttling, protected by dmcg->rw_sem + // TODO: remove and use dmcg->md_io_throtl_thres + int group_throtl_thres; + + spinlock_t lock; // cache_spin_lock under this + int inited; + int remove_flush; + + /* stats */ + atomic_t throtl_help; + atomic_t throtl_self; + + int md_io_inprog_ext_flush; + int md_io_inprog_throtl; + int md_io_inprog_normal; // normal delayed mu, include flush/no flush + int md_io_inprog_force; + int md_io_inprog_fua; + + int sent_md_io_ext_flush_cnt; + int sent_md_io_throtl_cnt; + int sent_md_io_normal_cnt; + int sent_md_io_force_cnt; + int sent_md_io_fua_cnt; + + // TODO: raw debug stats, remove? + atomic_t send_md_io_cnt; + atomic_t md_io_callback_cnt; + atomic_t md_io_in_queue; + atomic_t md_io_to_queue; +} new_mu_t; +#endif + +#ifdef MY_ABC_HERE +typedef struct _dmc_group dmc_group_t; +#endif +typedef struct _dmc_node dmc_node; +/* + * Cache context + * SYNO: only flash_superblock would be saved to metadata + */ +struct cache_c { + +#ifdef MY_ABC_HERE + /* + * XXX: Variables in this section are initizlied in Dummy mode + */ + int cache_mode; + cache_state_t cache_state; + + spinlock_t cache_spin_lock; + spinlock_t reload_lock; + spinlock_t dev_lock; + /* + * WARNING: + * disk_dev might be changed on expansion + * Use get_disk_bdev() instead of disk_dev->bdev + */ + struct dm_dev *disk_dev; /* Source device */ + struct block_device *disk_bdev; + char disk_devname[DEV_PATHLEN]; + + // Used in enable / disable + wait_queue_head_t wait_for_cache_disable_queue; + wait_queue_head_t wait_old_ios_completed_queue; + + // SSD RAID name (dummy mode is "none") + char cache_devname[DEV_PATHLEN]; + char dm_vdevname[DEV_PATHLEN]; + struct dm_target *tgt; + + // In the progress to enable or disable + int in_switching; + atomic_t num_master_io; + + char id[ID_LEN]; // Currently only save disk_devname + struct cache_c *next_cache; + struct rw_semaphore ioctl_rwsem; + dmc_node *node; +#endif /* MY_ABC_HERE */ + + /* + * XXX: + * Variables below are initizlied when cache enabling + * and reset to zero while cache disabling + * + */ +#ifdef MY_ABC_HERE + int point_to_reset; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#else + struct dm_dev *disk_dev; /* Source device */ +#endif /* MY_ABC_HERE */ + + struct dm_dev *cache_dev; /* Cache device */ + +#ifdef MY_ABC_HERE + // Here assume bdev won't be changed even dm_dev is reallocated +#ifdef MY_ABC_HERE +#else + spinlock_t dev_lock; + struct block_device *disk_bdev; +#endif /* MY_ABC_HERE */ + struct block_device *cache_bdev; + + // Save new dm_dev created at expansion + struct dm_dev *disk_dev_reload; + struct dm_dev *cache_dev_reload; +#endif + int on_ssd_version; + +#ifdef MY_ABC_HERE + // Move above +#else + spinlock_t cache_spin_lock; +#endif /* MY_ABC_HERE */ + + struct cacheblock *cache; /* Hash table for cache blocks */ + struct cache_set *cache_sets; + struct cache_md_block_head *md_blocks_buf; + + unsigned int md_block_size; /* Metadata block size in sectors */ + + // SYNO: num of cacheblk + sector_t size; /* Cache size */ + unsigned int assoc; /* Cache associativity */ + unsigned int block_size; /* Cache block size */ + unsigned int block_shift; /* Cache block size in bits */ + unsigned int block_mask; /* Cache block mask */ + unsigned int assoc_shift; /* Consecutive blocks size in bits */ + unsigned int num_sets; /* Number of cache sets */ + +#ifdef MY_ABC_HERE +#else + int cache_mode; +#endif /* MY_ABC_HERE */ + + /* wait for nr_jobs == 0 and sync stopped when sync for removm */ + wait_queue_head_t sync_wqh; /* Wait queue for I/O completion */ + /* XXX - Updates of nr_jobs should happen inside the lock. But doing it outside + * is OK since the filesystem is unmounted at this point + * WARNING: nr_jobs will reach zero before force abort bio finish, so + * there could still be ios inside cache when nr_jobs is zero. + * Use it with num_master_io to ensure no ongoing io. */ + atomic_t nr_jobs; /* Number of I/O jobs */ + +#define SLOW_REMOVE 1 +#define FAST_REMOVE 2 + atomic_t remove_in_prog; + + int dirty_thresh_set; /* Per set dirty threshold to start cleaning */ + int max_clean_ios_set; /* Max cleaning IOs per set */ + int max_clean_ios_total; /* Total max cleaning IOs */ +#ifdef MY_ABC_HERE +#else + int clean_inprog; +#endif + +#ifdef MY_ABC_HERE + /* + * Set this value if dtr() or do_sync has called sync_all() + * This value is only set back to zero when stop_sync is set to 1 + */ + int start_sync_all; +#ifdef MY_ABC_HERE +#else + int sync_index; +#endif + /* + * -1: cache is not flushing (default value) + * >=0: count of dirty blocks when starting flushing + */ + int init_nr_dirty; +#endif + int nr_dirty; + int nr_synced; + /* When a cache block with state DIRTY or PIN_FILE or SYNCED, it is counted as occupied */ + int nr_occupied; + atomic64_t cached_blocks; /* Number of cached blocks */ + unsigned long pending_jobs_count; + int md_blocks; /* Numbers of metadata blocks, including header */ + + /* Stats */ + struct flashcache_stats flashcache_stats; + + /* Errors */ + struct flashcache_errors flashcache_errors; + +#define IO_LATENCY_GRAN_USECS 250 +#define IO_LATENCY_MAX_US_TRACK 10000 /* 10 ms */ +#define IO_LATENCY_BUCKETS (IO_LATENCY_MAX_US_TRACK / IO_LATENCY_GRAN_USECS) + unsigned long latency_hist[IO_LATENCY_BUCKETS]; + unsigned long latency_hist_10ms; + + +#ifdef MY_ABC_HERE +#else + struct delayed_work delayed_clean; +#endif + + unsigned long pid_expire_check; + + struct flashcache_cachectl_pid *blacklist_head, *blacklist_tail; + struct flashcache_cachectl_pid *whitelist_head, *whitelist_tail; + int num_blacklist_pids, num_whitelist_pids; + unsigned long blacklist_expire_check, whitelist_expire_check; + +#define PENDING_JOB_HASH_SIZE 32 + struct pending_job *pending_job_hashbuckets[PENDING_JOB_HASH_SIZE]; + +#ifdef MY_ABC_HERE +#else + struct cache_c *next_cache; +#endif /* MY_ABC_HERE */ + + void *sysctl_handle; + +#ifdef MY_ABC_HERE +#else + // DM virtual device name, stored in superblock and restored on load + char dm_vdevname[DEV_PATHLEN]; + // real device names are now stored as UUIDs + char cache_devname[DEV_PATHLEN]; + char disk_devname[DEV_PATHLEN]; +#endif /* MY_ABC_HERE */ + + /* + * When this is set, all the IOs are bypassed to HDDs + * + * Note: If you get a SSD Read / Write error, you must check if you need to set the value + * because you just got the first IO error + */ + int bypass_cache; // Might not be read under lock since it wont' be set back to 0 from 1 + + /* Per device sysctls */ + int sysctl_io_latency_hist; + int sysctl_do_sync; + int sysctl_stop_sync; + int sysctl_dirty_thresh; + int sysctl_pid_do_expiry; + int sysctl_max_pids; + int sysctl_pid_expiry_secs; + int sysctl_reclaim_policy; + int sysctl_zerostats; + int sysctl_error_inject; + int sysctl_fast_remove; + int sysctl_cache_all; + int sysctl_cache_all_input; + int sysctl_fallow_clean_speed; + int sysctl_fallow_delay; + int sysctl_skip_seq_thresh_kb; + int sysctl_skip_seq_fgap_kb; // forward gap + int sysctl_skip_seq_bgap_kb; // backward gap + int sysctl_new_error_inject; // use number instead of bit + + /* Sequential I/O spotter */ + struct sequential_io seq_recent_ios[SEQUENTIAL_TRACKER_QUEUE_DEPTH]; + struct sequential_io *seq_io_head; + struct sequential_io *seq_io_tail; + spinlock_t seq_io_spin_lock; + + // cacheblk utilization + unsigned long bits_used; + unsigned long bits_all; + + // for checking preread range + sector_t disk_devsize; + int max_io_len; +#ifdef MY_ABC_HERE + // Block sector to query + // Use u64 for alpine & x86_64 compatible issue + u64 query_start_sector; + u64 query_num_sectors; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned long long bitmap_size_byte; + unsigned char *pbitmap_ranges; +#ifdef MY_ABC_HERE + bitmap_control_t bitmap_control; +#endif + internal_query_t internal_query; + int bitmap_is_set; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int reload_table; +#ifdef MY_ABC_HERE +#else + spinlock_t reload_lock; + char id[ID_LEN]; +#endif /* MY_ABC_HERE */ +#endif +#ifdef MY_ABC_HERE + atomic_t num_uncached_write; + atomic_t num_write_cache; + atomic_t num_flush_bio; + atomic_t in_flush; + wait_queue_head_t wait_flush_queue; + wait_queue_head_t wait_io_done_queue; + + struct dm_io_region disk_region; + struct dm_io_region cache_region; +#ifdef MY_ABC_HERE +#else + // For flush bio + spinlock_t disk_flush_lock; + int disk_flushing; + struct list_head disk_flush_queue1; + struct list_head disk_flush_queue2; + struct list_head *disk_flush_pending_queue; + struct list_head *disk_flush_io_queue; + struct list_head *disk_flush_unused_queue; + struct bio *flush_bio; + struct work_struct flush_work; + struct work_struct disk_flush_io_queue_work; + + /* For metadata flush */ + spinlock_t md_flush_lock; + int md_flushing; + atomic_t inflight_md_write_for_flush; + struct list_head md_flush_queue1; + struct list_head md_flush_queue2; + struct list_head *md_flush_unused_queue; + struct list_head *md_flush_io_queue; + struct list_head *md_flush_pending_queue; + struct bio *md_flush_bio; + struct work_struct md_flush_work; + struct work_struct md_flush_io_queue_work; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef CONFIG_SYNO_DATA_CORRECTION + struct correction_entry *correction_list; + spinlock_t corretion_spin_lock; +#endif +#ifdef MY_ABC_HERE + print_limit_t limits; + attribute_t attribute; +#endif +#ifdef MY_ABC_HERE + u_int32_t hash_mapping; + u_int32_t tail_region_idx; + u_int32_t tail_region_num_sets; + u_int32_t region_num_sets; +#endif +#ifdef MY_ABC_HERE + load_action_t load_action; + spinlock_t endio_spin_lock; +#endif + +#ifdef MY_ABC_HERE + plug_wb_t plug_wb; +#else + int sysctl_ssd_read_ios_limit; +#endif + + /* Use double buffer so the timer won't affect latency */ + struct io_latency_stats last_itvl_lat_stats[2][CACHE_IO_TYPE_NUM]; + int lat_stats_idx; + spinlock_t lat_spin_lock; + int sysctl_syno_latency_diagnose; + int sysctl_latency_diagnose_itvl_ms; + int sysctl_io_disk_lat_thres_ms; + int sysctl_io_ssd_lat_thres_ms; + int sysctl_lat_perc_ten_thousandth; + struct timer_list latency_timer; + unsigned long lat_thresholds_jiffies[CACHE_IO_TYPE_NUM]; + + /* To guard the CHANGE of bypass_cache and cache_all + * we need to check cache_all when setting bypass, and check bypass + * when setting cache_all, no need to lock on read */ + spinlock_t bypass_lock; + +#ifdef MY_ABC_HERE + online_qf_t oqf; +#endif + +#ifdef MY_ABC_HERE + new_mu_t new_mu; +#endif +#ifdef MY_ABC_HERE + /* For enable/create get from input arguments + * For load, get from superblock + * For older version this should be emtpy string */ + char group_uuid[GROUP_ID_LEN]; + // Some entries is for sqf or nfq, e.g. writeback in turns + dmc_group_t *dmcg; +#endif +}; + +#ifdef MY_ABC_HERE +typedef struct _job_node { + struct kcached_job *job; + struct list_head list; +} job_node; +#endif + +#define PROCESS_JOB_RESCHED_BATCH 256 + +struct kcached_wq { + void (*fn) (struct kcached_job *); + /* For every PROCESS_JOB_RESCHED_BATCH job we check for reschedule + * in this workqueue to avoid infinite loop */ + struct work_struct kwq_work; + struct list_head jobs; +}; + +typedef enum _kcached_wq_type { + PENDING, + DO_IO, +#ifdef MY_ABC_HERE +#else + MD_IO, + MD_COMPLETE, +#endif + UNCACHED_IO_COMPLETE, + PREREAD, + FREE_JOB, + KCACHED_WQ_SIZE, +} kcwq_type_t; + +extern struct kcached_wq kcached_wq[KCACHED_WQ_SIZE]; +extern struct delayed_work nqf_mgmt_work; + +#define cache_schedule_io() \ + do { cache_schedule_work(&kcached_wq[DO_IO].kwq_work); } while(0) +#define cache_schedule_pending() \ + do { cache_schedule_work(&kcached_wq[PENDING].kwq_work); } while(0) +#define cache_schedule_uncached_io_complete() \ + do { cache_schedule_work(&kcached_wq[UNCACHED_IO_COMPLETE].kwq_work); } while(0) + +#ifdef MY_ABC_HERE +#else +#define cache_schedule_md_io() \ + do { cache_schedule_work(&kcached_wq[MD_IO].kwq_work); } while(0) +#define cache_schedule_md_complete() \ + do { cache_schedule_work(&kcached_wq[MD_COMPLETE].kwq_work); } while(0) +#endif /* !MY_ABC_HERE */ + +#define cache_schedule_preread_io() \ + do { cache_schedule_work(&kcached_wq[PREREAD].kwq_work); } while(0) +#define cache_schedule_to_free_jobs() \ + do { cache_schedule_work(&kcached_wq[FREE_JOB].kwq_work); } while(0) + +void push(struct list_head *jobs, struct kcached_job *job); + +static inline void push_pending(struct kcached_job *job) +{ + push(&kcached_wq[PENDING].jobs, job); +} + +static inline void push_io(struct kcached_job *job) +{ + push(&kcached_wq[DO_IO].jobs, job); +} + +static inline void push_uncached_io_complete(struct kcached_job *job) +{ + push(&kcached_wq[UNCACHED_IO_COMPLETE].jobs, job); +} + +#ifdef MY_ABC_HERE +#else +static inline void push_md_io(struct kcached_job *job) +{ + push(&kcached_wq[MD_IO].jobs, job); +} + +static inline void push_md_complete(struct kcached_job *job) +{ + push(&kcached_wq[MD_COMPLETE].jobs, job); +} +#endif /* !MY_ABC_HERE */ + +static inline void push_preread_io(struct kcached_job *job) +{ + push(&kcached_wq[PREREAD].jobs, job); +} + +static inline void push_to_free_jobs(struct kcached_job *job) +{ + push(&kcached_wq[FREE_JOB].jobs, job); +} + +static inline int flashcache_pending_empty(void) +{ + return list_empty(&kcached_wq[PENDING].jobs); +} + +static inline int flashcache_io_empty(void) +{ + return list_empty(&kcached_wq[DO_IO].jobs); +} + +#ifdef MY_ABC_HERE +#else +static inline int flashcache_md_io_empty(void) +{ + return list_empty(&kcached_wq[MD_IO].jobs); +} + +static inline int flashcache_md_complete_empty(void) +{ + return list_empty(&kcached_wq[MD_COMPLETE].jobs); +} +#endif + +static inline int flashcache_uncached_io_complete_empty(void) +{ + return list_empty(&kcached_wq[UNCACHED_IO_COMPLETE].jobs); +} + +static inline int flashcache_preread_empty(void) +{ + return list_empty(&kcached_wq[PREREAD].jobs); +} + +static inline int flashcache_free_job_empty(void) +{ + return list_empty(&kcached_wq[FREE_JOB].jobs); +} + +#ifdef CONFIG_SYNO_DATA_CORRECTION +typedef enum _use_lock_type { + NO_LOCK=0, + DO_LOCK=1, +} lock_type_t; + +typedef enum _correcting_type { + NO_CORRECTING = -1, + TYPE_UNINITED = 0, + DISK_CORRECTING = 1, + SSD_CORRECTING = 2, +} correcting_type_t; + +#endif + +#ifdef MY_ABC_HERE +#define DMCG_MU_THROTL_REBALANCE_THRES_IOS 10000 +#endif + +#ifdef MY_ABC_HERE +typedef struct _dmc_group { + /* protected by dmcg_mtx */ + struct list_head node; + char uuid[GROUP_ID_LEN]; // will not change after create + + /* following fields are protected by this */ + struct rw_semaphore rw_sem; + + /* House keeping */ + int num_dmc; + struct list_head dmc_list; + +#ifdef MY_ABC_HERE + /* MD update throttle */ + struct cache_c *throtl_dmc; // DMC that is going to be throttled + atomic_t md_io_pending_no_flush; + int md_io_throtl_thres; + atomic_t num_throtl_io; +#endif + + /* Stats */ + atomic_t rebalance_cnt; + + /* Normal Quickflush Control */ + struct list_head nqf_pending_dmcs; + unsigned long nqf_expire_jiffies; + struct cache_c *nqf_dmc; + atomic_t sqf_inprog; + wait_queue_head_t nqf_wqh; + int nqf_yielded; + +} dmc_group_t; +#endif + + +#ifdef MY_ABC_HERE +typedef struct _dmc_node { + struct list_head entry; +#ifdef MY_ABC_HERE + struct list_head group_entry; +#endif + // For writeback in turns + struct list_head nqf_entry; + struct cache_c *pdmc; + char id[ID_LEN]; +} dmc_node; +#endif + +/* kcached/pending job states */ +#define READCACHE 1 +#define WRITECACHE 2 +#define READDISK 3 +#define WRITEDISK 4 +#define READFILL 5 /* Read Cache Miss Fill */ +#define INVALIDATE 6 +#define WRITEDISK_SYNC 7 + +#ifdef MY_ABC_HERE +#define READDISKMEM 8 +#define WRITEMEMCACHE 9 +#endif + +/* + * we need other GFP flag so use __vmalloc, retain original vmalloc flags + * Note: need to check during kernel porting + */ +#define VMALLOC_INT_FLAG (GFP_KERNEL | __GFP_HIGHMEM) + +typedef enum _KCACHED_JOB_FLAG { + /* writeback attributes */ + JOB_WB_READ_DONE = 1 << 0, + JOB_WB_FORCED = 1 << 1, // ignore wb throttle. Used in invalidate + JOB_WB_NQF = 1 << 2, // Trigger clean cache after wb done + + /* job->mem_addr attributres */ + JOB_MEM_VMALLOC = 1 << 3, + JOB_MEM_MEMPOOL = 1 << 4, + + /* To distinguish if mu for job in new_mu->fua_job_list has been sent + * When mu finish, if job mu fua inprog then we can finish the request */ + JOB_FUA_MU_INPROG = 1 << 5, + +} KCACHED_JOB_FLAG; + +struct kcached_job { + struct list_head list; // TODO: change name to node + struct cache_c *dmc; + struct bio *bio; /* Original bio */ + struct job_io_regions { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + struct io_region disk; + struct io_region cache; +#else + struct dm_io_region disk; + struct dm_io_region cache; +#endif + } job_io_regions; + int index; + int action; + int error; + struct flash_cacheblock *md_block; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + struct bio *md_bio; +#else + struct bio_vec md_io_bvec; +#endif + ktime_t io_start_time; + struct kcached_job *next; +#ifdef MY_ABC_HERE + // For preread after read miss, always has the same size as cache block + void * mem_addr; + // Data (bytes) that would be read to mem_addr + unsigned long mem_data_byte; + // Data range this job will act on + bitmap_t action_bitmap; +#endif + struct io_latency io_lat; + int flag; // KCACHED_JOB_FLAG + unsigned long long wb_seq; + // General context + void *ctx; +}; + +struct pending_job { + struct bio *bio; + int action; + int index; + struct pending_job *prev, *next; + struct io_latency io_lat; +}; +#endif /* __KERNEL__ */ + + + +/* Cache block metadata structure */ +#ifdef MY_ABC_HERE + +// convert unsigned int for apline compatible +#define BITMAP_BITS (unsigned int)(sizeof(bitmap_t)*8) +#define SECTOR_PER_BIT 8 // 4kb +#define BITMAP_MASK 0xffff +#define JOB_MEM_BYTE to_bytes(NEW_MODE_BLOCK_SIZE) + +// limit the size of memory used by online writeback / preread / invalidate +#if defined(CONFIG_SYNO_ALPINE) +#define MAX_JOB_MEM_COUNT 512 // vmalloc avalable memory is limited on alpine +#else +#define MAX_JOB_MEM_COUNT 2048 +#endif +#endif + +#ifdef __KERNEL__ + +#ifdef MY_ABC_HERE +extern struct bio_set *pcache_bio_set; +#endif + +#ifdef MY_DEF_HERE +extern mempool_t * _cache_bio_pool; +struct cache_bio { + struct bio *master_bio; + // Total number of sub bios + int num_total_bios; + // Use atomic due to it could be accessed by multiple threads + atomic_t num_completed_bios; + int error; + unsigned long start_jiffy; +}; + +struct shared_data { + struct bio *master_bio; + sector_t unhandled_sectors; + sector_t next_bio_start; + unsigned short next_bv_idx; + int bv_len_sum; +}; + +struct subbio { + sector_t start_sector; + sector_t num_sectors; + unsigned int first_bv_len; + unsigned int first_bv_offset; + unsigned short first_bv_idx; + unsigned int last_bv_len; + unsigned short last_bv_idx; +}; + +#ifdef MY_ABC_HERE +struct subbio_info { + struct cache_bio *pcache_bio; + int is_pin; +}; +#endif +#else /* NOT MY_DEF_HERE */ +extern mempool_t * _cache_bi_private_pool; +struct cache_bi_private { + void *master_bio_private; + unsigned long start_jiffy; + unsigned char is_pin; +}; +#endif /* MY_DEF_HERE */ + +#endif /* __KERNEL__ */ + +#ifdef MY_ABC_HERE +typedef enum _hash_mapping_type { + HASH_MAPPING_DISABLE = 0, + HASH_MAPPING_V1 = 1, + + /* + * Hash Mapping V2 splits cache into multiple default 256GB regions + * when lookup, we first mod the volume lba with cache size and find the + * corresponding cache regions for the lba. Then we apply the hash mapping + * algorithm within region to find the final cache set. + * This keeps data locality within a region, avoid the need to update + * all metadata of cache for random writes within a region. + * + * Special cases: often the cache size will not be multiple of region size, + * in such case if the remained area is larger than half the region we + * consider it a valid region. Otherwise it is combined with the last + * full region. The last region (after combine if needed) is refer to + * as the tail region. + */ + HASH_MAPPING_V2 = 2, +} hash_mapping_t; +#endif + +#define MD_BLOCK_BYTES(DMC) ((DMC)->md_block_size * 512) +#define MD_SECTORS_PER_BLOCK(DMC) ((DMC)->md_block_size) +// SYNO: num of cacheblk in a md blocks +#define MD_SLOTS_PER_BLOCK(DMC) (MD_BLOCK_BYTES(DMC) / (sizeof(struct flash_cacheblock))) + +#define INDEX_TO_MD_BLOCK(DMC, INDEX) compatible_div((INDEX), MD_SLOTS_PER_BLOCK(DMC)) +// SYNO: Index in current md block +#define INDEX_TO_MD_BLOCK_OFFSET(DMC, INDEX) compatible_mod((INDEX), MD_SLOTS_PER_BLOCK(DMC)) + +#define MD_BLOCK_TO_START_IDX(DMC, MD_IDX) ((MD_IDX) * MD_SLOTS_PER_BLOCK(DMC)) + +#define METADATA_IO_NUM_BLOCKS(dmc) (METADATA_IO_BLOCKSIZE / MD_BLOCK_BYTES(dmc)) + +// SYNO: block_shift is cacheblk shift, change block index to sector +#define INDEX_TO_CACHE_ADDR(DMC, INDEX) \ + (((sector_t)(INDEX) << (DMC)->block_shift) + (DMC)->md_blocks * MD_SECTORS_PER_BLOCK((DMC))) + +#ifdef __KERNEL__ + +#ifdef MY_ABC_HERE +extern struct workqueue_struct *cache_workqueue; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define MAX_BIO_SIZE 128 +#define ALIGNED_SECTORS 8 +#define CACHE_BLK_SIZE_SEC MAX_BIO_SIZE + +#ifdef MY_ABC_HERE +#define SUB_BLOCK_SIZE ALIGNED_SECTORS +#define MAX_NUM_LOCATION 16 +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef MY_DEF_HERE +#define MAX_HIST_SECTOR 2048 +#else +#define MAX_HIST_SECTOR NEW_MODE_BLOCK_SIZE +#endif /* MY_DEF_HERE */ +#else +#define MAX_HIST_SECTOR 32 +#endif /* MY_ABC_HERE */ + +#define BIO_STR_MAX 64 +#define JOB_STR_MAX 256 +// USHRT_MAX +#define NR_CONCURRENT_MAX (u_int8_t)(~0U) +#include "syno_functions.h" +#endif /* MY_ABC_HERE */ + +/* Cache persistence */ +#define CACHE_RELOAD 1 +#define CACHE_CREATE 2 +#define CACHE_FORCECREATE 3 + +/* Latency Diagnose */ +#define LAT_HIT_DISK_THRES_MS 2000 +#define LAT_HIT_SSD_THRES_MS 2000 +#define LAT_INTERVAL_MS 1000 +#define LAT_PERC_TEN_THOUSANDTH 9900 + +/* + * We have one of these for *every* cache metadata sector, to keep track + * of metadata ios in progress for blocks covered in this sector. Only + * one metadata IO per sector can be in progress at any given point in + * time + */ +struct cache_md_block_head { + u_int32_t nr_in_prog; + /* + * SYNO: + * queued_updates: list to save queued job when md block is busy + * md_io_inprog: pointer to quque_updates when md_write_kickoff want to process ququed data + */ + struct kcached_job *queued_updates, *md_io_inprog; +}; + +#define MIN_JOBS 1024 +#define MIN_PREREAD_JOBS 32 + +/* Default values for sysctls */ +#define DIRTY_THRESH_MIN 10 +#define DIRTY_THRESH_MAX 90 +#define DIRTY_THRESH_DEF 20 + +#define MAX_CLEAN_IOS_SET 2 +#define MAX_CLEAN_IOS_TOTAL 4 +#define MAX_PIDS 100 +#define PID_EXPIRY_SECS 60 +#define FALLOW_DELAY (60*15) /* 15 Mins default */ +#define FALLOW_SPEED_MIN 1 +#define FALLOW_SPEED_MAX 100 +#define FALLOW_CLEAN_SPEED 2 + +/* DM async IO mempool sizing */ +#define FLASHCACHE_ASYNC_SIZE 1024 + +enum { + FLASHCACHE_WHITELIST=0, + FLASHCACHE_BLACKLIST=1, +}; + +struct flashcache_cachectl_pid { + pid_t pid; + struct flashcache_cachectl_pid *next, *prev; + unsigned long expiry; +}; + +struct dbn_index_pair { + sector_t dbn; + int index; +}; + +#ifdef CONFIG_SYNO_DATA_CORRECTION +#define NUM_SUB_BLOCK (MAX_BIO_SIZE / ALIGNED_SECTORS) +#define CORRECTION_BIO_BYTES 4096 +/* + * Use a entry to records the correction status of a 64KB-aligned block. + * A 64KB block has multiple 4KB ranges to record if each range is performing + * correction on SSD RAID or Disk RAID. + */ +struct correction_entry { + u64 start_sector; + // Which 4k range is correcting, In BTRFS spec, only sends 4KB correction bio. + u16 correcting_bitmap; + u8 correcting_types[NUM_SUB_BLOCK]; // Record the type of each 4KB range + u16 need_abort_bitmap; + sector_t cache_addr; // Record the corresponding LBA in SSD RAID + struct list_head link; +}; + +struct send_force_abort_bio_task { + struct cache_c *dmc; + atomic_t bio_count; + struct bio *bio; + int error; + sector_t entry_start_sector; + u16 need_abort_bitmap; + sector_t cache_addr; + /* Handle one force abort bio only, won't loop forever */ + struct work_struct work; + struct io_latency io_lat; + ktime_t start_time; +}; + +#endif +/* Error injection flags */ +#define READDISK_ERROR 0x00000001 +#define READCACHE_ERROR 0x00000002 +#define READFILL_ERROR 0x00000004 +#define WRITECACHE_ERROR 0x00000008 +#define WRITECACHE_MD_ERROR 0x00000010 +#define WRITEDISK_MD_ERROR 0x00000020 +#define KCOPYD_CALLBACK_ERROR 0x00000040 +#define DIRTY_WRITEBACK_JOB_ALLOC_FAIL 0x00000080 +#define READ_MISS_JOB_ALLOC_FAIL 0x00000100 +#define READ_HIT_JOB_ALLOC_FAIL 0x00000200 +#define READ_HIT_PENDING_JOB_ALLOC_FAIL 0x00000400 +#define INVAL_PENDING_JOB_ALLOC_FAIL 0x00000800 +#define WRITE_HIT_JOB_ALLOC_FAIL 0x00001000 +#define WRITE_HIT_PENDING_JOB_ALLOC_FAIL 0x00002000 +#define WRITE_MISS_JOB_ALLOC_FAIL 0x00004000 +#define WRITES_LIST_ALLOC_FAIL 0x00008000 +#define MD_ALLOC_SECTOR_ERROR 0x00010000 +#ifdef MY_ABC_HERE +// Start from Bit 17 +#define SIMULATE_CACHE_DISABLE_LONG_TIME (1 << 17) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define SIMULATE_DIRTY_WRITEBACK_LONG_TIME (1 << 18) +#endif +#ifdef MY_ABC_HERE +#define QF_ALLOC_BITMAP_ERROR (1 << 19) +#define QF_ALLOC_SEG_NOT_ENOUGH_ERROR (1 << 20) +#define QF_ALLOC_SEG_ENOUGH_ERROR (1 << 21) +#define QF_ALLOC_CACHEBLK_TO_CLEAN_ERROR (1 << 22) +#define QF_ALLOC_WRITEBACK_JOB_ERROR (1 << 23) +#endif +#ifdef MY_ABC_HERE +#define WRITEBACK_JOB_ALLOC_ERROR (1 << 24) +#define READ_HIT_DELAY (1 << 25) +#endif +#ifdef MY_ABC_HERE +#define MD_PREWRITE_DELAY (1 << 26) +#define MD_PREFLUSH_DELAY (1 << 27) +#define MD_POSTFLUSH_DELAY (1 << 28) +#endif +#define READ_HIT_NORMAL_IO_WAIT (1 << 29) +#define READ_HIT_CORR_IO_WAIT (1 << 30) +#ifdef MY_ABC_HERE +#define FLUSH_BIO_ERROR (1 << 31) +#endif + +typedef enum _new_error_inject { + OQF_RELOAD_MEM_ALLOC_FAIL = 1, + OQF_WB_ERROR = 2, + EXT_FLUSH_BIO_LIST_ALLOC_FAIL = 3, + DISK_FLUSH_ERROR = 4, + SSD_FLUSH_ERROR = 5, + FORCE_MD_IO_ERROR = 6, + MD_IO_ERROR = 7, + MU_FORCED_RESTART_TEST = 8, + // HOLE, free to use + MD_BIO_ALLOC_FAIL = 10, + MD_IO_JOB_ALLOC_FAIL = 11, + FORCED_MD_IO_JOB_ALLOC_FAIL = 12, + WB_SSD_READ_ERROR = 13, + WB_DISK_WRITE_ERROR = 14, + SYNCED_STATE_CHANGE_WHEN_FORCE_MU = 15, + WB_MU_REQUEUE_FORCED_TEST = 16, + MD_IO_COMBO_TEST = 17, + FORCE_ABORT_BIO_WQ_DELAY = 18, + FORCE_ABORT_BIO_ALLOC_FAIL = 19, + WRITE_FUA_TEST = 20, + WRITE_FUA_ERROR = 21, + FORCE_NO_FLUSH_PENDING = 22, + IO_INPROG_DELAY = 23, +} new_error_inject_t; + +static inline int +__check_new_error_inject(struct cache_c *dmc, new_error_inject_t err) +{ + return dmc->sysctl_new_error_inject == err; +} + +#define check_new_error_inject(dmc, err) unlikely(__check_new_error_inject(dmc, err)) + +/* Inject a 5s delay between syncing blocks and metadata */ +#define FLASHCACHE_SYNC_REMOVE_DELAY 5000 + +#ifdef MY_ABC_HERE +int flashcache_noclone_map(struct dm_target *ti, struct bio *master_bio); +#endif /* MY_ABC_HERE */ + +int +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) +flashcache_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context); +#else +flashcache_map(struct dm_target *ti, struct bio *bio); +#endif + +int flashcache_ctr(struct dm_target *ti, unsigned int argc, + char **argv); +void flashcache_dtr(struct dm_target *ti); + +struct kcached_job *flashcache_alloc_cache_job(void); +void flashcache_free_cache_job(struct kcached_job *job); +struct pending_job *flashcache_alloc_pending_job(struct cache_c *dmc); +void flashcache_free_pending_job(struct pending_job *job); +#ifdef FLASHCACHE_DO_CHECKSUMS +u_int64_t flashcache_compute_checksum(struct bio *bio); +void flashcache_store_checksum(struct kcached_job *job); +int flashcache_validate_checksum(struct kcached_job *job); +int flashcache_read_compute_checksum(struct cache_c *dmc, int index, void *block); +#endif +struct kcached_job *pop(struct list_head *jobs); +void push(struct list_head *jobs, struct kcached_job *job); +void process_kcached_wq(struct work_struct *work); +struct kcached_job *new_kcached_job(struct cache_c *dmc, struct bio* bio, + int index, struct io_latency *plat, + enum cache_io_type io_type); +void flashcache_do_preread_io(struct kcached_job *job); +void process_free_job(struct kcached_job *job); + +void flashcache_do_pending(struct kcached_job *job); +void flashcache_do_pending_force_mu(struct cache_c *dmc, int idx, int error); +void flashcache_md_write_done(struct kcached_job *job); +void flashcache_md_write(struct kcached_job *job); +void flashcache_md_write_kickoff(struct kcached_job *job); +void flashcache_do_io(struct kcached_job *job); +void flashcache_uncached_io_complete(struct kcached_job *job); +#ifdef MY_ABC_HERE +#else +void flashcache_clean_set(struct cache_c *dmc, int set); +#endif +void flashcache_sync_all(struct cache_c *dmc); +void flashcache_clean_sync_state(struct cache_c *dmc); +void flashcache_reclaim_lru_movetail(struct cache_c *dmc, int index); +#ifdef MY_ABC_HERE +void bitmap_control_get(struct cache_c *dmc); +void bitmap_control_put(struct cache_c *dmc); +#endif +#ifdef MY_ABC_HERE +void flashcache_sort_writes(struct dbn_index_pair *writes_list, int nr_writes, int set); +#endif +void flashcache_merge_writes(struct cache_c *dmc, + struct dbn_index_pair *writes_list, + int *nr_writes, int set); + +int flashcache_dm_io_sync_vm(struct cache_c *dmc, struct dm_io_region *where, + int rw, void *data); + +void flashcache_update_sync_progress(struct cache_c *dmc); +void flashcache_enq_pending(struct cache_c *dmc, struct bio* bio, int index, + int action, struct pending_job *job, + struct io_latency *plat, enum cache_io_type io_type); +struct pending_job *flashcache_deq_pending(struct cache_c *dmc, int index); + +/* job->md_bio exists after 3.14, cannot remove this */ +int dm_io_async_bvec(unsigned int num_regions, + struct dm_io_region *where, + int rw, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + struct bio *bio, io_notify_fn fn, +#else + struct bio_vec *bvec, io_notify_fn fn, +#endif + void *context, unsigned long bi_flags); + +int dm_io_async_bio_wrapper(unsigned int num_regions, struct dm_io_region *where, + int rw, struct bio *bio, io_notify_fn fn, void *context, unsigned long bi_flags); + +void flashcache_detect_fallow(struct cache_c *dmc, int index); +void flashcache_clear_fallow(struct cache_c *dmc, int index); + +void flashcache_bio_endio(struct bio *bio, int error, + struct cache_c *dmc, ktime_t io_start_time, + struct io_latency *plat); +void flashcache_bio_endio_core(struct bio *bio, int error, struct cache_c *dmc, + ktime_t io_start_time, struct io_latency *plat); + +/* procfs */ +void flashcache_module_procfs_init(void); +void flashcache_module_procfs_releae(void); +void flashcache_ctr_procfs(struct cache_c *dmc); +void flashcache_dtr_procfs(struct cache_c *dmc); + +#ifdef MY_ABC_HERE +int quickflush_build_next_bitmap(struct cache_c *dmc); +int quickflush_cacheblk_get_nr_writeback(struct cache_c *dmc, int index); +int quickflush_find_cacheblk_idx(struct cache_c *dmc, unsigned long long disk_blk_idx); +void quickflush_get_next_io_range(bitmap_t data_bitmap, bitmap_t *dirty_bitmap, sector_t *offset, sector_t *size); + +void dmcg_nqf_mgmt(struct work_struct *work); +#endif + +sector_t bio_last_sector(struct bio *bio); + +#ifdef MY_ABC_HERE +struct block_device *get_cache_bdev(struct cache_c *dmc); +struct block_device *get_disk_bdev(struct cache_c *dmc); +fmode_t get_disk_mode(struct cache_c *dmc); +#endif +#ifdef CONFIG_SYNO_DATA_CORRECTION +int correction_handle_abort_io_finish(struct cache_c *dmc, + struct bio *bio, int error, ktime_t start_time, struct io_latency *plat); +#endif /* CONFIG_SYNO_DATA_CORRECTION */ +#ifdef MY_ABC_HERE +void send_disk_flush_bio(struct work_struct *work); +void process_disk_flush_io_queue(struct work_struct *work); +void send_md_flush_bio(struct work_struct *work); +void process_md_flush_io_queue(struct work_struct *work); +#endif +#ifdef MY_ABC_HERE +void handle_master_io_finish(struct cache_c *dmc); +int superblock_cache_state_set(struct cache_c *dmc, cache_state_t state); +#endif /* MY_ABC_HERE */ + +// use macro here to avoid function call when latency diagnose not enabled +#define flashcache_check_record_io_latency(step, plat) do {\ + if (LAT_DIAGNOSE_ENABLED(plat)) flashcache_record_io_latency(step, plat);\ +} while (0) + +#define flashcache_check_process_io_latency(dmc, plat, step) do {\ + if (LAT_DIAGNOSE_ENABLED(plat)) flashcache_process_io_latency(dmc, plat, step);\ +} while (0) + +void flashcache_record_io_latency(enum latency_step step, struct io_latency *plat); +void flashcache_process_io_latency(struct cache_c *dmc, struct io_latency *plat, enum latency_step step); +void flashcache_free_pending_jobs(struct cache_c *dmc, struct cacheblock *cacheblk, int error); +int dm_io_vmem(unsigned int num_regions, struct dm_io_region *where, int rw, + void *mem_addr, io_notify_fn fn, void *context, unsigned long bi_flags); +int cache_schedule_work(struct work_struct *work); +int cache_schedule_delayed_work(struct delayed_work *dwork, unsigned long delay); +int cache_mod_delayed_work(struct delayed_work *dwork, unsigned long delay); + +/* IO with valid bio has preprocess time (from flashcache_map -> flashcache_init_io_latency) + * The start time of master bio is passed in with start_jiffy + * for io without valid bio the start_jiffy should just be the jiffies when this is called. */ +static inline void +flashcache_init_io_latency(struct io_latency *plat, int enable, + enum cache_io_type io_type, + unsigned long start_jiffy, + unsigned int has_preprocess) +{ + if (enable) { + memset(plat, 0, sizeof(*plat)); + plat->start_jiffy = start_jiffy; + plat->last_jiffy = start_jiffy; + plat->io_type = io_type; + if (has_preprocess) { + flashcache_record_io_latency(LAT_PREPROCESS, plat); + } + } else { + plat->entry_cnt = LAT_INVALID_ENTRY_CNT; + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +void flashcache_process_lat_stats(struct timer_list *timer); +#else +void flashcache_process_lat_stats(unsigned long data); +#endif + +static inline unsigned long +bio_get_start_jiffy(struct bio *bio) +{ +#ifdef MY_DEF_HERE +#ifdef MY_ABC_HERE + return ((struct subbio_info*)bio->bi_private)->pcache_bio->start_jiffy; +#else + return ((struct cache_bio*)bio->bi_private)->start_jiffy; +#endif +#else /* NOT MY_DEF_HERE */ + return ((struct cache_bi_private*)bio->bi_private)->start_jiffy; +#endif /* MY_DEF_HERE */ +} + +static inline void +set_bi_op_and_flags(struct dm_io_request *iorq, comp_dm_op_t dm_op) +{ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + iorq->bi_op = dm_op & REQ_OP_MASK; + iorq->bi_op_flags = dm_op & ~(REQ_OP_MASK); +#else + iorq->bi_rw = dm_op; +#endif +} + +#ifdef MY_ABC_HERE +#else +static inline void dec_clean_inprog(struct cache_c *dmc, struct cache_set *set, int nr_write) +{ + VERIFY_WARN(dmc->clean_inprog >= nr_write); + dmc->clean_inprog -= nr_write; + VERIFY_WARN(set->clean_inprog >= nr_write); + set->clean_inprog -= nr_write; +} +#endif + +/* + * Functins to change cache block state bits and do statistics + * + * Must be used inside spin_lock + * + * TODO: Integrate nr_dirty & nr_synced updating into following functions + */ +static inline void cb_state_add_bits_update_counts(struct cache_c *dmc, + struct cacheblock *cb, cb_state_t bits) +{ + if (bits & OCCUPIED_BITS) { + if ((cb->cache_state & OCCUPIED_BITS) == 0) { + dmc->nr_occupied++; + } + } + cb->cache_state |= bits; +} + +/* + * WARNING: Except loading cache to initialize cacheblk from metadata, + * OCCUPIED_BITS should be added by cb_state_add_bits_update_counts() + * for correct calculation + */ +static inline void cb_state_assign_update_counts(struct cache_c *dmc, + struct cacheblock *cb, cb_state_t bits) +{ + if (bits == INVALID){ + // sometime driver might not remove some flag and set INVALID directly + if (cb->cache_state & OCCUPIED_BITS) { + dmc->nr_occupied--; + } + } else if (bits & OCCUPIED_BITS) { + if ((cb->cache_state & OCCUPIED_BITS) == 0) { + dmc->nr_occupied++; + } + } + + cb->cache_state = bits; +} + +static inline void cb_state_remove_bits_update_counts(struct cache_c *dmc, + struct cacheblock *cb, cb_state_t bits) +{ + if ((bits & OCCUPIED_BITS) && (cb->cache_state & bits)) { + if ((cb->cache_state & ~bits & OCCUPIED_BITS) == 0) { + dmc->nr_occupied--; + } + } + cb->cache_state &= ~bits; +} + +/* Must be in lock, only part of the attrs set could be unset together. */ +static inline void unset_partial_cb_writeback_attrs(struct cache_c *dmc, + struct cacheblock* cb, int nr_write) +{ + cacheblk_dec_num_concurrent_by(cb, nr_write); + cacheblk_unset_all_io_range_change_state(dmc, cb); +} + +/* Must be in cache_spin_lock and plug_wb->lock */ +static inline void set_wb_attrs(struct cache_c *dmc, int cb_idx, int nr_write) +{ + struct cacheblock *cb = &dmc->cache[cb_idx]; + + VERIFY_WARN(cb->nr_concurrent == 0); + cb_state_add_bits_update_counts(dmc, cb, DISKWRITEINPROG); + cacheblk_set_all_io_range(cb); + cacheblk_add_num_concurrent_by(cb, nr_write); + flashcache_clear_fallow(dmc, cb_idx); + atomic_add(nr_write, &dmc->nr_jobs); +#ifdef MY_ABC_HERE + dmc->plug_wb.ssd_read_inprog += nr_write; +#else + dmc->clean_inprog += nr_write; + dmc->cache_sets[cb_idx / dmc->assoc].clean_inprog += nr_write; +#endif +} + +void flashcache_free_cache_job_mem(struct kcached_job *job); + +#ifdef MY_ABC_HERE +static inline void schedule_nqf_mgmt_work(void) { + cache_schedule_delayed_work(&nqf_mgmt_work, NQF_MGMT_ITVL_SEC * HZ); +} +#endif + +static inline char* mode_to_str(int mode) +{ + char *str = "Unknown"; + + if (mode == FLASHCACHE_WRITE_BACK) { + str = "WRITE_BACK"; + } else if (mode == FLASHCACHE_WRITE_THROUGH) { + str = "WRITE_THROUGH"; + } else if (mode == FLASHCACHE_DUMMY) { + str = "DUMMY"; + } else { + str = "WRITE_AROUND"; + } + + return str; +} + + +#ifdef MY_ABC_HERE +#else +void flashcache_sync_blocks(struct cache_c *dmc); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +void flashcache_free_md_bio(struct kcached_job *job); +#else +void flashcache_free_md_sector(struct kcached_job *job); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +int flashcache_alloc_md_bio(struct kcached_job *job); +#else +int flashcache_alloc_md_sector(struct kcached_job *job); +#endif + +void flashcache_handle_job_finish(struct cache_c *dmc, struct kcached_job *job); +int is_writeback_crash_safe_set_bypass(struct cache_c *dmc); + +#endif /* __KERNEL__ */ +#endif /* FLASHCACHE_H */ diff --git a/drivers/syno/syno-mem-saving-driver/flashcache.hook b/drivers/syno/syno-mem-saving-driver/flashcache.hook new file mode 100755 index 000000000000..e148ce50a57b --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache.hook @@ -0,0 +1,24 @@ +#!/bin/sh -e +# mkinitramfs hook for flashcache + +PREREQ="mdadm" + +prereqs () { + echo "$PREREQ" +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac + +. /usr/share/initramfs-tools/hook-functions + +manual_add_modules flashcache +copy_exec /sbin/flashcache_load /sbin +copy_exec /sbin/flashcache_create /sbin +copy_exec /sbin/flashcache_destroy /sbin + +exit 0 diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_conf.c b/drivers/syno/syno-mem-saving-driver/flashcache_conf.c new file mode 100644 index 000000000000..9500ff941320 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_conf.c @@ -0,0 +1,4995 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache_conf.c + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#include "dm.h" +#include "dm-io.h" +#include "dm-bio-list.h" +#include "kcopyd.h" +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +#include "dm.h" +#endif +#include +#include +#include +#endif + +#include "flashcache.h" +#include "flashcache_ioctl.h" +#ifdef MY_ABC_HERE +#include "syno_quickflush.h" +#endif + +#ifdef MY_ABC_HERE +#include "syno_md_update.h" +#endif + +#ifdef MY_ABC_HERE +#ifdef CONFIG_DETECT_HUNG_TASK +unsigned long sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT; +#else +unsigned long sysctl_hung_task_timeout_secs = 0; +#endif +#endif + +// All the dmcs, which include dummy caches +struct cache_c *cache_list_head = NULL; +u_int64_t size_hist[MAX_HIST_SECTOR + 1]; + +struct kmem_cache *_job_cache; +mempool_t *_job_pool; +struct kmem_cache *_pending_job_cache; +mempool_t *_pending_job_pool; +#ifdef MY_ABC_HERE +mempool_t *_job_mem_pool; + +// Also for metadata bio & flush bio +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +struct bio_set cache_bio_set; +struct bio_set *pcache_bio_set = &cache_bio_set; +#else +struct bio_set *pcache_bio_set; +#endif + +int job_max_mem_count = MAX_JOB_MEM_COUNT; +module_param(job_max_mem_count, int, S_IRUGO); + +#ifdef MY_DEF_HERE +struct kmem_cache *_cache_bio_kmem_cache; +mempool_t *_cache_bio_pool; +#else +struct kmem_cache *_cache_bi_private_kmem_cache; +mempool_t *_cache_bi_private_pool; +#endif /* MY_DEF_HERE */ + +// Lock for controlling job mem allocated +DEFINE_SPINLOCK(job_mem_lock); // XXX: mutex should be enough +int job_mem_count; +wait_queue_head_t job_mem_wait_queue; +#endif +#ifdef MY_ABC_HERE +struct workqueue_struct *cache_workqueue; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +// TODO: Rename to distinguish online quickflush and offline quickflush. +// Maybe normal/sync quickflush? Put offline quickflush to standalone struct +DEFINE_MUTEX(nqf_mem_mtx); +#endif + +#ifdef MY_ABC_HERE +// Job pool variable +DEFINE_SPINLOCK(jp_lock); +int jp_is_processing; +int jp_ref_count; +#endif + +atomic_t nr_cache_jobs; +atomic_t nr_pending_jobs; + +struct kcached_wq kcached_wq[KCACHED_WQ_SIZE]; +#ifdef MY_ABC_HERE +struct delayed_work nqf_mgmt_work; +#endif + +struct flashcache_control_s { + unsigned long synch_flags; +}; + +struct flashcache_control_s *flashcache_control; + +/* Bit offsets for wait_on_bit_lock() */ +#define FLASHCACHE_UPDATE_LIST 0 + +static int flashcache_notify_reboot(struct notifier_block *this, + unsigned long code, void *x); +static void flashcache_sync_for_remove(struct cache_c *dmc); + +static void set_dm_target_attribute(struct dm_target *ti, struct cache_c *dmc, dm_attr_t dm_attr); + +static void reset_dmc_fields_for_dummy_mode(struct cache_c *dmc); +static inline void stop_wb_works(struct cache_c *dmc); // forward declaration + +#ifdef MY_ABC_HERE +void quickflush_process_wb_ios(struct work_struct *work); +void quickflush_process_wb_done(struct work_struct *wb_done_work); +#endif + +extern char *flashcache_sw_version; + +static int +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +flashcache_wait_schedule(struct wait_bit_key *unused_wait_bit_key, int unused_mode) +#else +flashcache_wait_schedule(void *unused) +#endif +{ + schedule(); + return 0; +} + +#ifdef MY_ABC_HERE +/* + * Special lock to only lock no-memory-allocated part + */ +static void job_pool_lock(void) +{ + unsigned long flags = 0; + int lock = 0; + + while (1) { + spin_lock_irqsave(&jp_lock, flags); + if (jp_is_processing) { + lock = 0; + } else { + // not in processsing + lock = 1; + jp_is_processing = 1; + } + spin_unlock_irqrestore(&jp_lock, flags); + if (lock) { + break; + } else { + msleep(1000); + } + } +} + +/* + * MUST check if being locked first + * + * lock is the return value of job_pool_lock + */ +static void job_pool_unlock(void) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&jp_lock, flags); + if (0 == jp_is_processing) { + serr("Job pool is not processing, no need to unlock?"); + } else { + jp_is_processing = 0; + } + spin_unlock_irqrestore(&jp_lock, flags); +} + +#endif + +static void * do_vmalloc(unsigned long byte) +{ + void *ptr = NULL; + +#ifdef MY_ABC_HERE + if (TEST_VMALLOC_FAIL == global_tester) { + serr("Detect TEST_VMALLOC_FAIL. Simulate vmalloc failed"); + global_tester = 0; + ptr = NULL; + goto end; + } +#endif + ptr = vmalloc(byte); +end: + return ptr; +} + +void *flashcache_mempool_vmalloc(gfp_t gfp_mask, void *pool_data) +{ + void *ret = NULL; + unsigned int noio_flags = memalloc_noio_save(); + ret = vmalloc_wrapper(JOB_MEM_BYTE, gfp_mask | VMALLOC_INT_FLAG); + memalloc_noio_restore(noio_flags); + + return ret; +} + +void flashcache_mempool_vfree(void *element, void *pool_data) +{ + vfree(element); +} + +/* + * Allocate job pool if needed + * To release resource, call job_pool_require() + * + * Note: might sleep to wait + */ +static int +job_pool_require(void) +{ + int alloc_bytes = 0; + int locked = 0; + + sdbg(DF_JOB_POOL_INIT, "Start"); + + job_pool_lock(); + locked = 1; + + if (0 != jp_ref_count) { + // job pools are already initailized + goto end; + } + + if (debug_flags & DF_JOB_POOL_INIT) { + sprint("Detect DF_JOB_POOL_INIT flag, wait 2 minutes to simulate init slow"); + msleep(1000*120); + sprint("Sleep finish"); + } + + _job_cache = kmem_cache_create("kcached-jobs-syno", + sizeof(struct kcached_job), + __alignof__(struct kcached_job), + 0, NULL); + if (!_job_cache) { + goto err; + } + + _job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, + mempool_free_slab, _job_cache); + if (!_job_pool) { + kmem_cache_destroy(_job_cache); + goto err; + } + + alloc_bytes += MIN_JOBS * sizeof(struct kcached_job); + + _pending_job_cache = kmem_cache_create("pending-jobs-syno", + sizeof(struct pending_job), + __alignof__(struct pending_job), + 0, NULL); + if (!_pending_job_cache) { + mempool_destroy(_job_pool); + kmem_cache_destroy(_job_cache); + goto err; + } + + _pending_job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, + mempool_free_slab, _pending_job_cache); + if (!_pending_job_pool) { + kmem_cache_destroy(_pending_job_cache); + mempool_destroy(_job_pool); + kmem_cache_destroy(_job_cache); + goto err; + } + + alloc_bytes += MIN_JOBS * sizeof(struct pending_job); + + // For preread memory + _job_mem_pool = mempool_create(MIN_PREREAD_JOBS, flashcache_mempool_vmalloc, + flashcache_mempool_vfree, NULL); + if (!_job_mem_pool) { + goto err; + } + + alloc_bytes += MIN_PREREAD_JOBS * JOB_MEM_BYTE; +#ifdef MY_DEF_HERE + _cache_bio_kmem_cache = kmem_cache_create("flashcache-cache-bio", sizeof(struct cache_bio), 0, 0, NULL); + if (!_cache_bio_kmem_cache) { + goto err; + } + _cache_bio_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, + mempool_free_slab, _cache_bio_kmem_cache); + if (!_cache_bio_pool) { + goto err; + } + + alloc_bytes += MIN_JOBS * sizeof(struct cache_bio); +#else + _cache_bi_private_kmem_cache = kmem_cache_create("flashcache-cache-bi-private", + sizeof(struct cache_bi_private), 0, 0, NULL); + if (!_cache_bi_private_kmem_cache) { + goto err; + } + _cache_bi_private_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, + mempool_free_slab, _cache_bi_private_kmem_cache); + if (!_cache_bi_private_pool) { + goto err; + } + + alloc_bytes += MIN_JOBS * sizeof(struct cache_bi_private); +#endif /* MY_DEF_HERE */ + + sprint("Preread max memmory count=%d", job_max_mem_count); + sprint("Total pre-allocate bytes=%d", alloc_bytes); + +end: + jp_ref_count++; + + if (locked) { + job_pool_unlock(); + } + sdbg(DF_JOB_POOL_INIT, "Finish"); + return 0; +err: + if (_job_cache) { + kmem_cache_destroy(_job_cache); + } + + if (_job_pool) { + mempool_destroy(_job_pool); + } + + if (_pending_job_cache) { + kmem_cache_destroy(_pending_job_cache); + } + + if (_pending_job_pool) { + mempool_destroy(_pending_job_pool); + } + + if (_job_mem_pool) { + mempool_destroy(_job_mem_pool); + } +#ifdef MY_DEF_HERE + if (_cache_bio_kmem_cache) { + kmem_cache_destroy(_cache_bio_kmem_cache); + } + if (_cache_bio_pool) { + mempool_destroy(_cache_bio_pool); + } +#else + if (_cache_bi_private_kmem_cache) { + kmem_cache_destroy(_cache_bi_private_kmem_cache); + } + if (_cache_bi_private_pool) { + mempool_destroy(_cache_bi_private_pool); + } +#endif /* MY_DEF_HERE */ + if (locked) { + job_pool_unlock(); + } + return -ENOMEM; +} + +static void check_kcached_wq_empty(void) +{ + VERIFY_WARN(flashcache_pending_empty()); + VERIFY_WARN(flashcache_io_empty()); + +#ifdef MY_ABC_HERE +#else + VERIFY_WARN(flashcache_md_io_empty()); + VERIFY_WARN(flashcache_md_complete_empty()); +#endif + + VERIFY_WARN(flashcache_uncached_io_complete_empty()); + VERIFY_WARN(flashcache_preread_empty()); + VERIFY_WARN(flashcache_free_job_empty()); +} + +#ifdef MY_ABC_HERE +/* + * MUST call job_pool_require first + */ +static void +job_pool_release(void) +#else +static void +flashcache_jobs_exit(void) +#endif /* MY_ABC_HERE */ +{ + int locked = 0; + + job_pool_lock(); + locked = 1; + jp_ref_count--; + + if (0 != jp_ref_count) { + sprint("Ref count=%d, no need to destroy jobs", jp_ref_count); + goto end; + } + + sprint("Ref count=0, Start to destroy jobs"); + check_kcached_wq_empty(); + + mempool_destroy(_job_pool); + kmem_cache_destroy(_job_cache); + _job_pool = NULL; + _job_cache = NULL; + mempool_destroy(_pending_job_pool); + kmem_cache_destroy(_pending_job_cache); + _pending_job_pool = NULL; + _pending_job_cache = NULL; + mempool_destroy(_job_mem_pool); + _job_mem_pool = NULL; +#ifdef MY_DEF_HERE + mempool_destroy(_cache_bio_pool); + _cache_bio_pool = NULL; + kmem_cache_destroy(_cache_bio_kmem_cache); + _cache_bio_kmem_cache = NULL; +#else + mempool_destroy(_cache_bi_private_pool); + _cache_bi_private_pool = NULL; + kmem_cache_destroy(_cache_bi_private_kmem_cache); + _cache_bi_private_kmem_cache = NULL; +#endif /* MY_DEF_HERE */ + +end: + if (locked) { + job_pool_unlock(); + } +} + +static int +flashcache_kcached_init(struct cache_c *dmc) +{ + init_waitqueue_head(&dmc->sync_wqh); + atomic_set(&dmc->nr_jobs, 0); + atomic_set(&dmc->remove_in_prog, 0); + return 0; +} + +#ifdef MY_ABC_HERE +int +superblock_cache_state_set(struct cache_c *dmc, cache_state_t state) +{ + struct flash_superblock *header = NULL; + int ret = 1; + struct dm_io_region where = {0}; + + if (!dmc || (CACHE_UNKNOWN == state)) { + serr("Incorrect parameter"); + return -1; + } + + header = (struct flash_superblock *)vmalloc(MD_BLOCK_BYTES(dmc)); + if (!header) { + serr("Allocate memory failed(size=%dbytes)", MD_BLOCK_BYTES(dmc)); + goto err; + } + + memset(header, 0, MD_BLOCK_BYTES(dmc)); + + where.bdev = get_cache_bdev(dmc); + where.sector = 0; + where.count = dmc->md_block_size; + + ret = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_READ, header); + if (ret) { + serr("Can't read header"); + goto err; + } + + // Change state + header->cache_state = state; + + ret = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, header); + if (ret) { + serr("Can't write header"); + goto err; + } + + ret = 0; +err: + if (header) { + vfree((void *)header); + } + + return ret; +} +#endif /* MY_ABC_HERE */ + +/* + * Write out the metadata one sector at a time. + * Then dump out the superblock. + * SYNO: Only call in dtr() or reboot + */ +static int +flashcache_writeback_md_store(struct cache_c *dmc) +{ + struct flash_cacheblock *meta_data_cacheblock, *next_ptr; + struct flash_superblock *header; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + struct io_region where; +#else + struct dm_io_region where; +#endif + int i, j; + int num_valid = 0, num_dirty = 0; + int error; + int write_errors = 0; + int sectors_written = 0, sectors_expected = 0; /* debug */ + int slots_written = 0; /* How many cache slots did we fill in this MD io block ? */ + + meta_data_cacheblock = (struct flash_cacheblock *)vmalloc(METADATA_IO_BLOCKSIZE); + if (!meta_data_cacheblock) { + DMERR("flashcache_writeback_md_store: Unable to allocate memory"); + DMERR("flashcache_writeback_md_store: Could not write out cache metadata !"); + return 1; + } + + where.bdev = get_cache_bdev(dmc); + where.sector = MD_SECTORS_PER_BLOCK(dmc); + slots_written = 0; + next_ptr = meta_data_cacheblock; + j = MD_SLOTS_PER_BLOCK(dmc); + for (i = 0 ; i < dmc->size ; i++) { + if (dmc->cache[i].cache_state & VALID) + num_valid++; + if (dmc->cache[i].cache_state & DIRTY) + num_dirty++; + next_ptr->dbn = dmc->cache[i].dbn; +#ifdef MY_ABC_HERE + next_ptr->data_bitmap = dmc->cache[i].data_bitmap; + next_ptr->dirty_bitmap = dmc->cache[i].dirty_bitmap; +#endif +#ifdef FLASHCACHE_DO_CHECKSUMS + next_ptr->checksum = dmc->cache[i].checksum; +#endif +#ifdef MY_ABC_HERE + next_ptr->cache_state = dmc->cache[i].cache_state & + (INVALID | VALID | DIRTY | PIN_FILE); +#else + next_ptr->cache_state = dmc->cache[i].cache_state & + (INVALID | VALID | DIRTY); +#endif + next_ptr++; + slots_written++; + j--; + if (j == 0) { + /* + * Filled the block, write and goto the next metadata block. + */ + if (slots_written == MD_SLOTS_PER_BLOCK(dmc) * METADATA_IO_NUM_BLOCKS(dmc)) { + /* + * Wrote out an entire metadata IO block, write the block to the ssd. + */ + where.count = (slots_written / MD_SLOTS_PER_BLOCK(dmc)) * + MD_SECTORS_PER_BLOCK(dmc); + slots_written = 0; + sectors_written += where.count; /* debug */ + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, meta_data_cacheblock); + if (error) { + write_errors++; +#ifdef MY_ABC_HERE + // printk_ratelimit start + if (printk_ratelimit()) { +#endif + DMERR("flashcache_writeback_md_store: Could not write out cache metadata block %llu error %d !", + (u64)where.sector, error); +#ifdef MY_ABC_HERE + } + // printk_ratelimit end +#endif + } + where.sector += where.count; /* Advance offset */ + } + /* Move next slot pointer into next block */ + next_ptr = (struct flash_cacheblock *) + ((caddr_t)meta_data_cacheblock + ((slots_written / MD_SLOTS_PER_BLOCK(dmc)) * MD_BLOCK_BYTES(dmc))); + j = MD_SLOTS_PER_BLOCK(dmc); + } + } // for i in dmc->size + + if (next_ptr != meta_data_cacheblock) { + /* Write the remaining last blocks out */ + VERIFY_WARN(slots_written > 0); + where.count = (slots_written / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (slots_written % MD_SLOTS_PER_BLOCK(dmc)) + where.count += MD_SECTORS_PER_BLOCK(dmc); + sectors_written += where.count; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, meta_data_cacheblock); + if (error) { + write_errors++; + if (printk_ratelimit()) { + DMERR("flashcache_writeback_md_store: Could not write out cache metadata block %llu error %d !", + (u64)where.sector, error); + } + } + } + vfree((void *)meta_data_cacheblock); + + /* Debug Tests */ +#ifdef EC_EMULATE_U64_DIVISION + sectors_expected = div64_u64(dmc->size, MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (mod_u64_rem64(dmc->size, MD_SLOTS_PER_BLOCK(dmc))) +#else + sectors_expected = (dmc->size / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (dmc->size % MD_SLOTS_PER_BLOCK(dmc)) +#endif + sectors_expected += MD_SECTORS_PER_BLOCK(dmc); + if (sectors_expected != sectors_written) { + printk("flashcache_writeback_md_store" "Sector Mismatch ! sectors_expected=%d, sectors_written=%d\n", + sectors_expected, sectors_written); + sprint("flashcache_writeback_md_store: sector mismatch\n"); + return 1; + } + + header = (struct flash_superblock *)vmalloc(MD_BLOCK_BYTES(dmc)); + if (!header) { + DMERR("flashcache_writeback_md_store: Unable to allocate memory"); + DMERR("flashcache_writeback_md_store: Could not write out cache metadata !"); + return 1; + } + memset(header, 0, MD_BLOCK_BYTES(dmc)); + + /* Write the header out last */ + if (write_errors == 0) { + if (num_dirty == 0) + header->cache_sb_state = CACHE_MD_STATE_CLEAN; + else + header->cache_sb_state = CACHE_MD_STATE_FASTCLEAN; + } else + header->cache_sb_state = CACHE_MD_STATE_UNSTABLE; + header->block_size = dmc->block_size; + header->md_block_size = dmc->md_block_size; + header->size = dmc->size; + header->assoc = dmc->assoc; + snprintf(header->disk_devname, DEV_PATHLEN, "%s", dmc->disk_devname); + snprintf(header->cache_devname, DEV_PATHLEN, "%s", dmc->dm_vdevname); + header->cache_devsize = to_sector(get_cache_bdev(dmc)->bd_inode->i_size); + header->disk_devsize = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + header->cache_version = dmc->on_ssd_version; +#ifdef MY_ABC_HERE + header->cache_state = dmc->cache_state; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (header->cache_version >= SYNO_FLASHCACHE_VERSION_HASH_MAPPING_V2) { + snprintf(header->group_uuid, sizeof(header->group_uuid), "%s", dmc->group_uuid); + } +#endif + + DPRINTK("Store metadata to disk: block size(%u), md block size(%u), cache size(%llu)" \ + "associativity(%u)", + header->block_size, header->md_block_size, header->size, + header->assoc); + + where.sector = 0; + where.count = dmc->md_block_size; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, header); + if (error) { + write_errors++; + DMERR("flashcache_writeback_md_store: Could not write out cache metadata superblock %llu error %d !", + (u64)where.sector, error); + } + + vfree((void *)header); + + if (write_errors == 0) + DMINFO("Cache metadata saved to disk"); + else { + DMINFO("CRITICAL : There were %d errors in saving cache metadata saved to disk", + write_errors); + if (num_dirty) + DMINFO("CRITICAL : You have likely lost %d dirty blocks", num_dirty); + } + + DMINFO("flashcache_writeback_md_store: valid blocks = %d dirty blocks = %d md_sectors = %d\n", + num_valid, num_dirty, dmc->md_blocks * MD_SECTORS_PER_BLOCK(dmc)); + + return 0; +} + +#ifdef MY_ABC_HERE +static void handle_tail_region(struct cache_c *dmc) +{ + u64 num_cb = dmc->size; + u64 tail_size = compatible_mod(num_cb, HASH_REGION_BLOCK_NUM); + + dmc->region_num_sets = compatible_div(HASH_REGION_BLOCK_NUM, dmc->assoc); + + if (!tail_size) { + dmc->tail_region_idx = compatible_div(num_cb, HASH_REGION_BLOCK_NUM) - 1; + dmc->tail_region_num_sets = dmc->region_num_sets; + } else if (tail_size >= HASH_REGION_BLOCK_NUM / 2) { + /* tail is its own region */ + dmc->tail_region_idx = compatible_div(num_cb, HASH_REGION_BLOCK_NUM); + dmc->tail_region_num_sets = compatible_div(tail_size, dmc->assoc); + } else { + if (num_cb < HASH_REGION_BLOCK_NUM) { + /* only one region in the cache */ + dmc->tail_region_idx = 0; + dmc->tail_region_num_sets = compatible_div(num_cb, dmc->assoc); + } else { + /* tail combine with last region */ + dmc->tail_region_idx = compatible_div(num_cb, HASH_REGION_BLOCK_NUM) - 1; + dmc->tail_region_num_sets = + compatible_div(tail_size + HASH_REGION_BLOCK_NUM, dmc->assoc); + } + } + + sprint("dmc size: %llu, tail region idx: %d num sets: %d", + (u64)dmc->size, dmc->tail_region_idx, dmc->tail_region_num_sets); +} +#endif + +static int +flashcache_writethrough_create(struct cache_c *dmc, int cache_version) +{ + sector_t cache_size, dev_size; + sector_t order; + int i; + + /* + * Convert size (in sectors) to blocks. + * Then round size (in blocks now) down to a multiple of associativity + */ +#ifdef EC_EMULATE_U64_DIVISION + dmc->size = div64_u64(dmc->size, dmc->block_size); + dmc->size = div64_u64(dmc->size, dmc->assoc) * dmc->assoc; +#else + dmc->size /= dmc->block_size; + dmc->size = (dmc->size / dmc->assoc) * dmc->assoc; +#endif + +#ifdef MY_ABC_HERE + handle_tail_region(dmc); +#endif + + /* Check cache size against device size */ + dev_size = to_sector(get_cache_bdev(dmc)->bd_inode->i_size); + cache_size = dmc->size * dmc->block_size; + if (cache_size > dev_size) { + DMERR("Requested cache size exeeds the cache device's capacity" \ + "(%llu>%llu)", + (u64)cache_size, (u64)dev_size); + return 1; + } + order = dmc->size * sizeof(struct cacheblock); + + DMINFO("Allocate %lluKB (%zuB per) mem for %llu-entry cache" \ + "(capacity:%lluMB, associativity:%u, block size:%u " \ + "sectors(%uKB))", + (u64)(order >> 10), sizeof(struct cacheblock), (u64)dmc->size, + (u64)(cache_size >> (20-SECTOR_SHIFT)), dmc->assoc, dmc->block_size, + dmc->block_size >> (10-SECTOR_SHIFT)); + + dmc->cache = (struct cacheblock *)do_vmalloc(order); + if (!dmc->cache) { + DMERR("flashcache_writethrough_create: Unable to allocate cache md"); + return 1; + } + +#ifdef MY_ABC_HERE + // should be set in both WB and WT mode + memset(dmc->cache, 0, order); + dmc->disk_devsize = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); +#endif + + dmc->on_ssd_version = cache_version; + + /* Initialize the cache structs */ + for (i = 0; i < dmc->size ; i++) { + dmc->cache[i].dbn = 0; +#ifdef FLASHCACHE_DO_CHECKSUMS + dmc->cache[i].checksum = 0; +#endif + cb_state_assign_update_counts(dmc, &dmc->cache[i], INVALID); + dmc->cache[i].nr_queued = 0; + } + dmc->md_blocks = 0; + return 0; +} + +static int +flashcache_writeback_create(struct cache_c *dmc, int cache_version, int force) +{ + struct flash_cacheblock *meta_data_cacheblock, *next_ptr; + struct flash_superblock *header; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + struct io_region where; +#else + struct dm_io_region where; +#endif + int i, j, error; + sector_t cache_size, dev_size; + sector_t order; + int sectors_written = 0, sectors_expected = 0; /* debug */ + int slots_written = 0; /* How many cache slots did we fill in this MD io block ? */ + + header = (struct flash_superblock *)vmalloc(MD_BLOCK_BYTES(dmc)); + if (!header) { + DMERR("flashcache_writeback_create: Unable to allocate sector"); + return 1; + } + where.bdev = get_cache_bdev(dmc); + where.sector = 0; + where.count = dmc->md_block_size; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_READ, header); + if (error) { + vfree((void *)header); + DMERR("flashcache_writeback_create: Could not read cache superblock %llu error %d !", + (u64)where.sector, error); + return 1; + } + if (!force && + ((header->cache_sb_state == CACHE_MD_STATE_DIRTY) || + (header->cache_sb_state == CACHE_MD_STATE_CLEAN) || + (header->cache_sb_state == CACHE_MD_STATE_FASTCLEAN))) { + vfree((void *)header); + DMERR("flashcache_writeback_create: Existing Cache Detected, use force to re-create"); + return 1; + } + /* Compute the size of the metadata, including header. + Note dmc->size is in raw sectors */ + dmc->md_blocks = INDEX_TO_MD_BLOCK(dmc, compatible_div(dmc->size, dmc->block_size)) + 1 + 1; + dmc->size -= dmc->md_blocks * MD_SECTORS_PER_BLOCK(dmc); /* total sectors available for cache */ + dmc->size = compatible_div(dmc->size, dmc->block_size); + dmc->size = compatible_div(dmc->size, dmc->assoc) * dmc->assoc; + /* Recompute since dmc->size was possibly trunc'ed down */ + dmc->md_blocks = INDEX_TO_MD_BLOCK(dmc, dmc->size) + 1 + 1; + +#ifdef MY_ABC_HERE + handle_tail_region(dmc); +#endif + + DMINFO("flashcache_writeback_create: md_blocks = %d, md_sectors = %d\n", + dmc->md_blocks, dmc->md_blocks * MD_SECTORS_PER_BLOCK(dmc)); + dev_size = to_sector(get_cache_bdev(dmc)->bd_inode->i_size); + cache_size = dmc->md_blocks * MD_SECTORS_PER_BLOCK(dmc) + (dmc->size * dmc->block_size); + if (cache_size > dev_size) { + DMERR("Requested cache size exceeds the cache device's capacity" \ + "(%llu>%llu)", + (u64)cache_size, (u64)dev_size); + vfree((void *)header); + return 1; + } + order = dmc->size * sizeof(struct cacheblock); + DMINFO("Allocate %lluKB (%zdB per) mem for %llu-entry cache" \ + "(capacity:%lluMB, associativity:%u, block size:%u " \ + "sectors(%uKB))", + (u64)order >> 10, sizeof(struct cacheblock), (u64)dmc->size, + (u64)cache_size >> (20-SECTOR_SHIFT), dmc->assoc, dmc->block_size, + dmc->block_size >> (10-SECTOR_SHIFT)); + dmc->cache = (struct cacheblock *)do_vmalloc(order); + if (!dmc->cache) { + vfree((void *)header); + DMERR("flashcache_writeback_create: Unable to allocate cache md"); + return 1; + } + +#ifdef MY_ABC_HERE + memset(dmc->cache, 0, order); +#endif + + /* Initialize the cache structs */ + for (i = 0; i < dmc->size ; i++) { + dmc->cache[i].dbn = 0; +#ifdef FLASHCACHE_DO_CHECKSUMS + dmc->cache[i].checksum = 0; +#endif + cb_state_assign_update_counts(dmc, &dmc->cache[i], INVALID); + dmc->cache[i].nr_queued = 0; + } + meta_data_cacheblock = (struct flash_cacheblock *)vmalloc(METADATA_IO_BLOCKSIZE); + if (!meta_data_cacheblock) { + DMERR("flashcache_writeback_create: Unable to allocate memory"); + DMERR("flashcache_writeback_create: Could not write out cache metadata !"); + return 1; + } + + where.sector = MD_SECTORS_PER_BLOCK(dmc); + slots_written = 0; + next_ptr = meta_data_cacheblock; + j = MD_SLOTS_PER_BLOCK(dmc); + for (i = 0 ; i < dmc->size ; i++) { + next_ptr->dbn = dmc->cache[i].dbn; +#ifdef FLASHCACHE_DO_CHECKSUMS + next_ptr->checksum = dmc->cache[i].checksum; +#endif + next_ptr->data_bitmap = dmc->cache[i].data_bitmap; + next_ptr->dirty_bitmap = dmc->cache[i].dirty_bitmap; +#ifdef MY_ABC_HERE + next_ptr->cache_state = dmc->cache[i].cache_state & + (INVALID | VALID | DIRTY | PIN_FILE); +#else + next_ptr->cache_state = dmc->cache[i].cache_state & + (INVALID | VALID | DIRTY); +#endif + next_ptr++; + slots_written++; + j--; + if (j == 0) { + /* + * Filled the block, write and goto the next metadata block. + */ + if (slots_written == MD_SLOTS_PER_BLOCK(dmc) * METADATA_IO_NUM_BLOCKS(dmc)) { + /* + * Wrote out an entire metadata IO block, write the block to the ssd. + */ + where.count = (slots_written / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + slots_written = 0; + sectors_written += where.count; /* debug */ + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, + meta_data_cacheblock); + if (error) { + vfree((void *)header); + vfree((void *)meta_data_cacheblock); + vfree(dmc->cache); + DMERR("flashcache_writeback_create: Could not write cache metadata block %llu error %d !", + (u64)where.sector, error); + return 1; + } + where.sector += where.count; /* Advance offset */ + } + /* Move next slot pointer into next metadata block */ + next_ptr = (struct flash_cacheblock *) + ((caddr_t)meta_data_cacheblock + ((slots_written / MD_SLOTS_PER_BLOCK(dmc)) * MD_BLOCK_BYTES(dmc))); + j = MD_SLOTS_PER_BLOCK(dmc); + } + } + if (next_ptr != meta_data_cacheblock) { + /* Write the remaining last blocks out */ + VERIFY_WARN(slots_written > 0); + where.count = (slots_written / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (slots_written % MD_SLOTS_PER_BLOCK(dmc)) + where.count += MD_SECTORS_PER_BLOCK(dmc); + sectors_written += where.count; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, meta_data_cacheblock); + if (error) { + vfree((void *)header); + vfree((void *)meta_data_cacheblock); + vfree(dmc->cache); + DMERR("flashcache_writeback_create: Could not write cache metadata block %llu error %d !", + (u64)where.sector, error); + return 1; + } + } + /* Debug Tests */ +#ifdef EC_EMULATE_U64_DIVISION + sectors_expected = div64_u64(dmc->size, MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (mod_u64_rem64(dmc->size, MD_SLOTS_PER_BLOCK(dmc))) +#else + sectors_expected = (dmc->size / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (dmc->size % MD_SLOTS_PER_BLOCK(dmc)) +#endif + sectors_expected += MD_SECTORS_PER_BLOCK(dmc); + if (sectors_expected != sectors_written) { + printk("flashcache_writeback_create" "Sector Mismatch ! sectors_expected=%d, sectors_written=%d\n", + sectors_expected, sectors_written); +#ifdef MY_ABC_HERE + sprint("flashcache_writeback_create: sector mismatch\n"); + vfree((void *)header); + vfree((void *)meta_data_cacheblock); + vfree(dmc->cache); + return 1; +#else + panic("flashcache_writeback_create: sector mismatch\n"); +#endif + } + vfree((void *)meta_data_cacheblock); + /* Write the header */ + header->cache_sb_state = CACHE_MD_STATE_DIRTY; + header->block_size = dmc->block_size; + header->md_block_size = dmc->md_block_size; + header->size = dmc->size; + header->assoc = dmc->assoc; + snprintf(header->disk_devname, DEV_PATHLEN, "%s", dmc->disk_devname); + snprintf(header->cache_devname, DEV_PATHLEN, "%s", dmc->dm_vdevname); + header->cache_devsize = to_sector(get_cache_bdev(dmc)->bd_inode->i_size); + header->disk_devsize = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + dmc->disk_devsize = header->disk_devsize; + dmc->on_ssd_version = header->cache_version = cache_version; +#ifdef MY_ABC_HERE + // Write to superblock + header->cache_state = CACHE_ENABLED; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + snprintf(header->group_uuid, sizeof(header->group_uuid), "%s", dmc->group_uuid); +#endif + + where.sector = 0; + where.count = dmc->md_block_size; + + printk("flashcache-dbg: cachedev check - %s %s", header->cache_devname, + dmc->dm_vdevname); + + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, header); + if (error) { + vfree((void *)header); + vfree(dmc->cache); + DMERR("flashcache_writeback_create: Could not write cache superblock %llu error %d !", + (u64)where.sector, error); + return 1; + } + vfree((void *)header); + + return 0; +} +#ifdef MY_ABC_HERE + +typedef enum bad_states_action { + BAD_STATES_ACCUME_STAT = 0, + BAD_STATES_RESCUE, +} bad_states_action_t; + +void +set_block_invalid(struct cache_c *dmc, struct cacheblock *pblock) +{ + cb_state_assign_update_counts(dmc, pblock, INVALID); + pblock->data_bitmap = 0; + pblock->dirty_bitmap = 0; + pblock->dbn = 0; +#ifdef FLASHCACHE_DO_CHECKSUMS + pblock->checksum = 0; +#endif +} + +void +handle_bad_states(struct cache_c *dmc, struct cacheblock *pblock, + bad_states_action_t action, bad_states_t *pbad_stat, + sector_t disk_dev_sectors) +{ + if (!pblock || ((BAD_STATES_ACCUME_STAT == action) && !pbad_stat) || !disk_dev_sectors) { + if (printk_ratelimit()) { + serr("Bad parameter"); + } + return; + } + // Check dbn & size + if ((pblock->dbn + MAX_BIO_SIZE) > disk_dev_sectors) { + if (BAD_STATES_RESCUE == action) { + set_block_invalid(dmc, pblock); + } else { + pbad_stat->bad_dbn_size++; + } + goto end; + } + + // Check INVALID + if ((pblock->cache_state & INVALID) == INVALID) { + /* + * Unable to check data_bitmap or dbn since flashcache_inval_block_set() doesn't clear them + * + * Unable to check dirty_bitmap since old flashcache_writeback_create() doesn't initialize it + * to zero, which seems not to cause issues because it just marks some subblocks that is not used + * by file system yet to dirty + */ +#ifdef MY_ABC_HERE + if (pblock->cache_state & (VALID | DIRTY | PIN_FILE)) { +#else + if (pblock->cache_state & (VALID | DIRTY)) { +#endif + if (BAD_STATES_RESCUE == action) { + set_block_invalid(dmc, pblock); + } else { + pbad_stat->invalid++; + } + } + goto end; + } + + // Check VALID & not DIRTY + if ((pblock->cache_state & (DIRTY | VALID)) == VALID) { + /* + * Don't check dirty bitmap since current dirty writeback logic still write old dirty_bitmap + * in md_write_kickoff() + */ + if (pblock->data_bitmap == 0) { + if (BAD_STATES_RESCUE == action) { + set_block_invalid(dmc, pblock); + } else { + pbad_stat->valid++; + } + goto end; + } + } + + // Check DIRTY + if ((pblock->cache_state & DIRTY) == DIRTY) { + if ((pblock->data_bitmap == 0) || (pblock->dirty_bitmap == 0) || + ((pblock->cache_state & VALID) != VALID)) { + if (BAD_STATES_RESCUE == action) { + set_block_invalid(dmc, pblock); + } else { + pbad_stat->dirty++; + } + goto end; + } + } + + // Check dirty_bitmap is a subset of data bitmap + if ((pblock->dirty_bitmap & pblock->data_bitmap) != pblock->dirty_bitmap) { + if (BAD_STATES_RESCUE == action) { + set_block_invalid(dmc, pblock); + } else { + pbad_stat->bitmap++; + } + goto end; + } + + /* + * If VALID & INVALID & DIRTY & PIN state is OK, go here to check extra + * flags + */ + + // Should not happen unless there's memory issue + if ((pblock->cache_state & BLOCK_IO_INPROG)) { + if (BAD_STATES_RESCUE == action) { + cb_state_remove_bits_update_counts(dmc, pblock, BLOCK_IO_INPROG); + } else { + pbad_stat->in_prog++; + } + } + + // Should not happen unless there's memory issue + if ((pblock->cache_state & FALLOW_DOCLEAN)) { + if (BAD_STATES_RESCUE == action) { + cb_state_remove_bits_update_counts(dmc, pblock, FALLOW_DOCLEAN); + } else { + pbad_stat->fallow++; + } + } +end: + return; +} + +#endif + +#ifdef MY_ABC_HERE + +static void free_online_quickflush(struct cache_c *dmc) +{ + if (dmc->oqf.inited) { + cancel_delayed_work_sync(&dmc->oqf.wb_work); + } + + if (dmc->oqf.volume_bitmap) { + vfree(dmc->oqf.volume_bitmap); + dmc->oqf.volume_bitmap = NULL; + } +} + +static int alloc_online_quickflush(struct cache_c *dmc) +{ + int ret = -ENOMEM; + + dmc->oqf.bitmap_num_idx = OQF_FALLOW_MAP_NUM_IDX(dmc); + dmc->oqf.volume_bitmap = (int *) vzalloc(sizeof(int) * dmc->oqf.bitmap_num_idx); + + sdbg(DF_QUICKFLUSH, "Fallow bitmap size: %lu", dmc->oqf.bitmap_num_idx); + + if (TEST_OQF_BITMAP_ALLOC_FAIL == global_tester) { + sprint("Simulate allocate oqf bitmap failed"); + global_tester = 0; + vfree(dmc->oqf.volume_bitmap); + dmc->oqf.volume_bitmap = NULL; + } + + if (NULL == dmc->oqf.volume_bitmap) { + serr("failed to allocate fallow bitmap"); + goto err; + } + + + ret = 0; +err: + if (ret) { + free_online_quickflush(dmc); + } + + return ret; +} + +static void init_online_quickflush(online_qf_t *oqf) +{ + unsigned long i = 0; + + atomic_set(&oqf->nr_fallow, 0); + mutex_init(&oqf->mtx); + oqf->nqf_inprog = 0; + oqf->bit_idx = 0; + oqf->last_fallow_tstamp = jiffies; + oqf->sysctl_enable_wb_work = 1; + oqf->sync_state = SYNC_STATE_STOPPED; + init_waitqueue_head(&oqf->wqh); + INIT_DELAYED_WORK(&oqf->wb_work, quickflush_do_writeback); + + sema_init(&oqf->sqf_sem2, 2); + sema_init(&oqf->sqf_sem1, 1); + init_rwsem(&oqf->bitmap_rwsem); + + for (i = 0; i < oqf->bitmap_num_idx; ++i) { + oqf->volume_bitmap[i] = 0; + } + + oqf->inited = 1; +} + +static void init_plug_wb(plug_wb_t *plug_wb) +{ + INIT_LIST_HEAD(&plug_wb->io_queue); + INIT_LIST_HEAD(&plug_wb->sync_io_queue); + INIT_LIST_HEAD(&plug_wb->complete_queue); + INIT_LIST_HEAD(&plug_wb->wb_done_queue); + + plug_wb->seq = 0; + plug_wb->cur_batch_head = 0; + plug_wb->cur_batch_len = 0; + plug_wb->unfinished_read_in_batch = 0; + + plug_wb->ssd_read_inprog = 0; + plug_wb->disk_write_inprog = 0; + + plug_wb->sysctl_batch_size = PLUG_WB_DEFAULT_BATCH_SIZE; + plug_wb->sysctl_ssd_read_ios_limit = PLUG_WB_DEFAULT_SSD_READ; + plug_wb->sysctl_disk_write_ios_limit = PLUG_WB_DEFAULT_DISK_WRITE; + + plug_wb->batch_size = plug_wb->sysctl_batch_size; + plug_wb->ssd_read_ios_limit = plug_wb->sysctl_ssd_read_ios_limit; + plug_wb->disk_write_ios_limit = plug_wb->sysctl_disk_write_ios_limit; + + INIT_WORK(&plug_wb->work, quickflush_process_wb_ios); + INIT_WORK(&plug_wb->wb_done_work, quickflush_process_wb_done); + + spin_lock_init(&plug_wb->lock); + +} + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void free_new_md_update(new_mu_t *mu) +{ + int i = 0; + + if (mu->inited) { + cancel_delayed_work_sync(&mu->dwork); + cancel_work_sync(&mu->md_io_complete_work); + cancel_work_sync(&mu->disk_flush.complete_work); + cancel_work_sync(&mu->ssd_flush.complete_work); + } + + for (i = 0; i < NUM_MU_BLK_TYPE; ++i) { + if (mu->mu_blocks[i]) { + vfree(mu->mu_blocks[i]); + mu->mu_blocks[i] = NULL; + } + } + + if (mu->disk_flush.bio) { + bio_put(mu->disk_flush.bio); + mu->disk_flush.bio = NULL; + } + + if (mu->ssd_flush.bio) { + bio_put(mu->ssd_flush.bio); + mu->ssd_flush.bio = NULL; + } +} + +static inline mu_blk_t* alloc_md_blocks(struct cache_c *dmc) +{ + if (check_new_error_inject(dmc, TEST_NEW_MU_ALLOC_FAIL)) { + sprint("Simulate mu block alloc fail"); + dmc->sysctl_new_error_inject = 0; + return NULL; + } + + return vzalloc(sizeof(mu_blk_t) * dmc->md_blocks); +} + +static int alloc_new_md_update(struct cache_c *dmc) +{ + int r = -ENOMEM; + int i = 0; + new_mu_t *mu = &dmc->new_mu; + + for (i = 0; i < NUM_MU_BLK_TYPE; ++i) { + mu->mu_blocks[i] = alloc_md_blocks(dmc); + if (NULL == mu->mu_blocks[i]) { + serr("Failed to allocate metadata update blocks"); + goto err; + } + } + + mu->disk_flush.bio = bio_alloc_bioset(GFP_NOIO, 0, pcache_bio_set); + mu->ssd_flush.bio = bio_alloc_bioset(GFP_NOIO, 0, pcache_bio_set); + if (NULL == mu->ssd_flush.bio || NULL == mu->disk_flush.bio) { + serr("Failed to allocate ssd flush bio for metadata update"); + goto err; + } + + r = 0; + +err: + if (r) { + free_new_md_update(mu); + } + + return r; +} + +static void init_ext_flush(ext_flush_t *ext_flush) +{ + INIT_LIST_HEAD(&ext_flush->md_io_inprog_queue); + INIT_LIST_HEAD(&ext_flush->md_io_pending_queue); + INIT_LIST_HEAD(&ext_flush->flush_bios_handling); + INIT_LIST_HEAD(&ext_flush->flush_bios_pending); + + INIT_WORK(&ext_flush->send_io_work, syno_mu_send_md_ios_from_ext_flush); +} + +static void init_dev_flush(dev_flush_t *flush, void (*func)(struct work_struct *)) +{ + INIT_LIST_HEAD(&flush->pending_queue); + INIT_LIST_HEAD(&flush->inprog_queue); + + INIT_WORK(&flush->complete_work, func); + flush->last_flush_jif = jiffies; + + *bio_bi_sector_ptr(flush->bio) = 0; + *bio_bi_size_ptr(flush->bio) = 0; +} + +static void init_new_md_update(struct cache_c *dmc) +{ + int i = 0; + int j = 0; + new_mu_t *mu = &dmc->new_mu; + + for (i = 0; i < NUM_MU_BLK_TYPE; ++i) { + for (j = 0; j < dmc->md_blocks; ++j) { + mu->mu_blocks[i][j].idx = j; + INIT_LIST_HEAD(&mu->mu_blocks[i][j].node); + } + } + + init_dev_flush(&mu->disk_flush, syno_mu_disk_flush_complete); + init_dev_flush(&mu->ssd_flush, syno_mu_ssd_flush_complete); + mu->flush_itvl_sec = MU_DEFAULT_FLUSH_ITVL_SEC; + + INIT_LIST_HEAD(&mu->fua_job_list); + + INIT_LIST_HEAD(&mu->md_io_inprog_queue); + INIT_LIST_HEAD(&mu->md_io_pending_queue); + INIT_LIST_HEAD(&mu->md_io_for_flush_pending_queue); + INIT_WORK(&mu->md_io_complete_work, syno_mu_md_io_complete); + + INIT_DELAYED_WORK(&mu->dwork, syno_mu_do_md_update); + mu->sysctl_mu_ios_total = 32; + mu->sysctl_mu_delay_sec = MU_DEFAULT_DELAY_SEC; + mu->sysctl_mu_check_itvl_sec = 1; + + init_waitqueue_head(&mu->remove_wqh); + + atomic_set(&mu->send_md_io_cnt, 0); + atomic_set(&mu->md_io_callback_cnt, 0); + + init_ext_flush(&mu->ext_flush); + + spin_lock_init(&mu->lock); + mu->inited = 1; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline int get_hash_mapping_from_cache_version(int version) +{ + switch (version) { + case SYNO_FLASHCACHE_VERSION: + return HASH_MAPPING_DISABLE; + case SYNO_FLASHCACHE_VERSION_HASH_MAPPING: + return HASH_MAPPING_V1; + case SYNO_FLASHCACHE_VERSION_HASH_MAPPING_V2: + return HASH_MAPPING_V2; + default: + serr("Invalid cache version: %d", version); + return -1; + } +} +#endif + +static int +flashcache_writeback_load(struct cache_c *dmc) +{ + struct flash_cacheblock *meta_data_cacheblock, *next_ptr; + struct flash_superblock *header; + struct dm_io_region where; + int i, j; + u_int64_t size, slots_read; + int clean_shutdown; + int dirty_loaded = 0; + sector_t order, data_size; + int num_valid = 0; + int error; + int sectors_read = 0, sectors_expected = 0; /* Debug */ + unsigned long long bad_states_cnt = 0; + bad_states_t bad_states; + sector_t disk_dev_sectors = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + + + memset(&bad_states, 0, sizeof(bad_states)); + + /* + * We don't know what the preferred block size is, just read off + * the default md blocksize. + */ + // should convert sectors to bytes + header = (struct flash_superblock *)vmalloc(to_bytes(DEFAULT_MD_BLOCK_SIZE)); + if (!header) { + DMERR("flashcache_writeback_load: Unable to allocate memory"); + return 1; + } + where.bdev = get_cache_bdev(dmc); + where.sector = 0; + where.count = DEFAULT_MD_BLOCK_SIZE; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_READ, header); + if (error) { + vfree((void *)header); + DMERR("flashcache_writeback_load: Could not read cache superblock %llu error %d!", + (u64)where.sector, error); + return 1; + } + + if (header->cache_version == 1) { + /* Backwards compatibility, md was 512 bytes always in V1.0 */ + header->md_block_size = 1; + } else if (!IS_NEW_MODE_VERSION(header->cache_version)) { + DMERR("flashcache_writeback_load: Unknown version %d found in superblock!", header->cache_version); + vfree((void *)header); + return 1; + } + dmc->on_ssd_version = header->cache_version; + + DPRINTK("Loaded cache conf: version(%d), block size(%u), md block size(%u), cache size(%llu), " \ + "associativity(%u)", + header->cache_version, header->block_size, header->md_block_size, header->size, + header->assoc); + if (!((header->cache_sb_state == CACHE_MD_STATE_DIRTY) || + (header->cache_sb_state == CACHE_MD_STATE_CLEAN) || + (header->cache_sb_state == CACHE_MD_STATE_FASTCLEAN))) { + vfree((void *)header); + DMERR("flashcache_writeback_load: Corrupt Cache Superblock"); + return 1; + } + if (header->cache_sb_state == CACHE_MD_STATE_DIRTY) { + DMINFO("Unclean Shutdown Detected"); + printk(KERN_ALERT "Only DIRTY blocks exist in cache"); + clean_shutdown = 0; + } else if (header->cache_sb_state == CACHE_MD_STATE_CLEAN) { + DMINFO("Slow (clean) Shutdown Detected"); + printk(KERN_ALERT "Only CLEAN blocks exist in cache"); + clean_shutdown = 1; + } else { + DMINFO("Fast (clean) Shutdown Detected"); + printk(KERN_ALERT "Both CLEAN and DIRTY blocks exist in cache"); + clean_shutdown = 1; + } + dmc->block_size = header->block_size; + dmc->md_block_size = header->md_block_size; + dmc->block_shift = ffs(dmc->block_size) - 1; + dmc->block_mask = dmc->block_size - 1; + dmc->size = header->size; + dmc->assoc = header->assoc; +#ifdef MY_ABC_HERE + if (header->cache_version >= SYNO_FLASHCACHE_VERSION_HASH_MAPPING_V2) { + snprintf(dmc->group_uuid, sizeof(dmc->group_uuid), "%s", header->group_uuid); + } // empty string for old version +#endif + if (CACHE_ENABLED != header->cache_state) { + sprint("Force change driver's cache state from %d to %d", + header->cache_state, CACHE_ENABLED); + dmc->cache_state = CACHE_ENABLED; + } else { + dmc->cache_state = header->cache_state; + } + +#ifdef MY_ABC_HERE + handle_tail_region(dmc); + dmc->hash_mapping = get_hash_mapping_from_cache_version(header->cache_version); + if (-1 == dmc->hash_mapping) { + serr("Failed to hash mapping from version %d", header->cache_version); + return 1; + } + sprint("Hash mapping = %d", dmc->hash_mapping); +#endif + dmc->assoc_shift = ffs(dmc->assoc) - 1; + + dmc->md_blocks = INDEX_TO_MD_BLOCK(dmc, dmc->size) + 1 + 1; + + sprint("flashcache_writeback_load: md_blocks = %d, md_sectors = %d, md_block_size = %d\n", + dmc->md_blocks, dmc->md_blocks * MD_SECTORS_PER_BLOCK(dmc), dmc->md_block_size); + data_size = dmc->size * dmc->block_size; + order = dmc->size * sizeof(struct cacheblock); + DMINFO("Allocate %lluKB (%zdB per) mem for %llu-entry cache" \ + "(capacity:%lluMB, associativity:%u, block size:%u " \ + "sectors(%uKB))", + (u64)order >> 10, sizeof(struct cacheblock), (u64)dmc->size, + (u64)(dmc->md_blocks * MD_SECTORS_PER_BLOCK(dmc) + data_size) >> (20-SECTOR_SHIFT), + dmc->assoc, dmc->block_size, + dmc->block_size >> (10-SECTOR_SHIFT)); + dmc->cache = (struct cacheblock *)do_vmalloc(order); + if (!dmc->cache) { + DMERR("load_metadata: Unable to allocate memory"); + vfree((void *)header); + return 1; + } + + // should be set in both WB and WT mode + memset(dmc->cache, 0, order); + + /* Read the metadata in large blocks and populate incore state */ + meta_data_cacheblock = (struct flash_cacheblock *)vmalloc(METADATA_IO_BLOCKSIZE); + if (!meta_data_cacheblock) { + vfree((void *)header); + vfree(dmc->cache); + DMERR("flashcache_writeback_load: Unable to allocate memory"); + return 1; + } + where.sector = MD_SECTORS_PER_BLOCK(dmc); + size = dmc->size; + i = 0; + while (size > 0) { + slots_read = min(size, (u_int64_t)(MD_SLOTS_PER_BLOCK(dmc) * METADATA_IO_NUM_BLOCKS(dmc))); +#ifdef EC_EMULATE_U64_DIVISION + if (mod_u64_rem64(slots_read, MD_SLOTS_PER_BLOCK(dmc))) + where.count = (1 + (div64_u64(slots_read, MD_SLOTS_PER_BLOCK(dmc)))) * MD_SECTORS_PER_BLOCK(dmc); + else + where.count = (div64_u64(slots_read, MD_SLOTS_PER_BLOCK(dmc))) * MD_SECTORS_PER_BLOCK(dmc); +#else + if (slots_read % MD_SLOTS_PER_BLOCK(dmc)) + where.count = (1 + (slots_read / MD_SLOTS_PER_BLOCK(dmc))) * MD_SECTORS_PER_BLOCK(dmc); + else + where.count = (slots_read / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); +#endif + sectors_read += where.count; /* Debug */ + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_READ, meta_data_cacheblock); + if (error) { + vfree((void *)header); + vfree(dmc->cache); + vfree((void *)meta_data_cacheblock); + DMERR("flashcache_writeback_load: Could not read cache metadata block %llu error %d !", + (u64)where.sector, error); + return 1; + } + where.sector += where.count; + next_ptr = meta_data_cacheblock; + for (j = 0 ; j < slots_read ; j++) { + /* + * XXX - Now that we force each on-ssd metadata cache slot to be a ^2, where + * we are guaranteed that the slots will exactly fit within a sector (and + * a metadata block), we can simplify this logic. We don't need this next test. + */ + if ((j % MD_SLOTS_PER_BLOCK(dmc)) == 0) { + /* Move onto next block */ + next_ptr = (struct flash_cacheblock *) + ((caddr_t)meta_data_cacheblock + MD_BLOCK_BYTES(dmc) * (j / MD_SLOTS_PER_BLOCK(dmc))); + } + dmc->cache[i].nr_queued = 0; + /* + * If unclean shutdown, only the DIRTY blocks are loaded. + */ + if (clean_shutdown || (next_ptr->cache_state & DIRTY)) { + if (next_ptr->cache_state & DIRTY) + dirty_loaded++; + cb_state_assign_update_counts(dmc, &dmc->cache[i], next_ptr->cache_state); + dmc->cache[i].data_bitmap = next_ptr->data_bitmap; + dmc->cache[i].dirty_bitmap = next_ptr->dirty_bitmap; + + if (dmc->cache[i].cache_state & VALID) + num_valid++; + dmc->cache[i].dbn = next_ptr->dbn; +#ifdef FLASHCACHE_DO_CHECKSUMS + if (clean_shutdown) + dmc->cache[i].checksum = next_ptr->checksum; + else { + error = flashcache_read_compute_checksum(dmc, i, block); + if (error) { + vfree((void *)header); + vfree(dmc->cache); + vfree((void *)meta_data_cacheblock); + DMERR("flashcache_writeback_load: Could not read cache metadata block %llu error %d !", + (u64)dmc->cache[i].dbn, error); + return 1; + } + } +#endif + if (data_rescue_flags & DATA_RESCUE_BLOCK_BAD_STATES) { + handle_bad_states(dmc, &dmc->cache[i], BAD_STATES_RESCUE, NULL, + disk_dev_sectors); + } + handle_bad_states(dmc, &dmc->cache[i], BAD_STATES_ACCUME_STAT, &bad_states, + disk_dev_sectors); + } else { + set_block_invalid(dmc, &dmc->cache[i]); + } + next_ptr++; + i++; + } + size -= slots_read; + } + + bad_states_cnt = bad_states.bad_dbn_size + + bad_states.invalid + bad_states.valid + bad_states.dirty + + bad_states.in_prog + bad_states.fallow + bad_states.bitmap; + + if (bad_states_cnt) { + sprint("Detect bad cache blocks:"); + sprint("Bad start sector or size: %llu", bad_states.bad_dbn_size); + sprint("Bad invalid state: %llu", bad_states.invalid); + sprint("Bad valid state: %llu", bad_states.valid); + sprint("Bad dirty state: %llu", bad_states.dirty); + sprint("Bad inprog state: %llu", bad_states.in_prog); + sprint("Bad fallow state: %llu", bad_states.fallow); + sprint("Bad bitmap : %llu", bad_states.bitmap); + sprint("Bad blocks / Total blocks: %llu / %llu", bad_states_cnt, (u64)dmc->size); + + if (LOAD_ERROR_CHECK == dmc->load_action) { + sprint("Detect incorrect cache block"); + vfree((void *)meta_data_cacheblock); + return 1; + } + } + + if (data_rescue_flags & DATA_RESCUE_BLOCK_BAD_STATES) { + data_rescue_flags &= ~ DATA_RESCUE_BLOCK_BAD_STATES; + sprint("Finish data rescue for cache bad state"); + sprint("NOTE: Reboot your system now to make all cache blocks sates are updated to SSD"); + } + + /* Debug Tests */ +#ifdef EC_EMULATE_U64_DIVISION + sectors_expected = div64_u64(dmc->size, MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (mod_u64_rem64(dmc->size, MD_SLOTS_PER_BLOCK(dmc))) +#else + sectors_expected = (dmc->size / MD_SLOTS_PER_BLOCK(dmc)) * MD_SECTORS_PER_BLOCK(dmc); + if (dmc->size % MD_SLOTS_PER_BLOCK(dmc)) +#endif + sectors_expected += MD_SECTORS_PER_BLOCK(dmc); + if (sectors_expected != sectors_read) { + printk("flashcache_writeback_load" "Sector Mismatch ! sectors_expected=%d, sectors_read=%d\n", + sectors_expected, sectors_read); + vfree((void *)meta_data_cacheblock); + return 1; + } + vfree((void *)meta_data_cacheblock); + /* + * For writing the superblock out, use the preferred blocksize that + * we read from the superblock above. + */ + if (DEFAULT_MD_BLOCK_SIZE != dmc->md_block_size) { + vfree((void *)header); + header = (struct flash_superblock *)vmalloc(MD_BLOCK_BYTES(dmc)); + if (!header) { + DMERR("flashcache_writeback_load: Unable to allocate memory"); + return 1; + } + } + /* Before we finish loading, we need to dirty the superblock and + write it out */ + header->size = dmc->size; + header->block_size = dmc->block_size; + header->md_block_size = dmc->md_block_size; + header->assoc = dmc->assoc; + header->cache_sb_state = CACHE_MD_STATE_DIRTY; + snprintf(header->disk_devname, DEV_PATHLEN, "%s", dmc->disk_devname); + snprintf(header->cache_devname, DEV_PATHLEN, "%s", dmc->dm_vdevname); + header->cache_devsize = to_sector(get_cache_bdev(dmc)->bd_inode->i_size); + header->disk_devsize = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + dmc->disk_devsize = header->disk_devsize; + + header->cache_version = dmc->on_ssd_version; + where.sector = 0; + where.count = dmc->md_block_size; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_WRITE, header); + if (error) { + vfree((void *)header); + vfree(dmc->cache); + DMERR("flashcache_writeback_load: Could not write cache superblock %llu error %d !", + (u64)where.sector, error); + return 1; + } + vfree((void *)header); + DMINFO("flashcache_writeback_load: Cache metadata loaded from disk with %d valid %d DIRTY blocks", + num_valid, dirty_loaded); + return 0; +} + +#ifdef MY_ABC_HERE +#else +static void +flashcache_clean_all_sets(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, + delayed_clean.work); + int i; + sdbg(DF_WORKQUEUE, "function executed from workqueue"); + for (i = 0 ; i < dmc->num_sets ; i++) + flashcache_clean_set(dmc, i); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int is_bdev_in_use(char *path) +{ + int ret = 0; + struct block_device *bdev = NULL; + char *holder = "Holder by flashcache"; + + bdev = blkdev_get_by_path(path, FMODE_EXCL, holder); + + if (IS_ERR(bdev)) { + sprint("%s exclude check failed(%ld)", path, PTR_ERR(bdev)); + ret = 1; + } else { + sprint("%s exclude check success", path); + blkdev_put(bdev, FMODE_EXCL); + } + + return ret; +} +#endif + +typedef enum _CHECK_TYPE { + CHECK_NONE, + CHECK_IN_USE +} CHECK_TYPE; + +// If dmc_dname is NULL, not write pth to dmc_dname +static int inline +flashcache_get_dev(struct dm_target *ti, char *pth, struct dm_dev **dmd, + char *dmc_dname, sector_t tilen, CHECK_TYPE check_type) +{ + int rc; + + if (CHECK_IN_USE == check_type) { + rc = is_bdev_in_use(pth); + if (rc) { + return -EBUSY; + } + } + + rc = dm_get_device(ti, pth, dm_table_get_mode(ti->table), dmd); + if (!rc && dmc_dname) { + snprintf(dmc_dname, DEV_PATHLEN, "%s", pth); + } + return rc; +} + +#ifdef MY_ABC_HERE +// Must have dmc->disk_dev first +static int +dmc_id_set(struct cache_c *dmc) +{ + int ret = -1; + + if (!dmc) { + serr("Incorrect parameter"); + goto err; + } + + dmc->disk_devname[DEV_PATHLEN - 1] = 0; + snprintf(dmc->id, sizeof(dmc->id), "%s", dmc->disk_devname); + + ret = 0; + +err: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + +/* protect the operation of dmc_group_list (add, search, remove) + * for every operation that might involve changing dmc_group_list, this mutex + * must be locked before dmc_group->rw_sem */ +struct mutex dmcg_mtx; + +// TODO: should make an interface to export group uuid to userspace +/* For older version of cache, there's no group uuid available in the superblock + * But we still need dmc group for throttling. Use empty group uuid + * dummy cache are not in dmc group */ +LIST_HEAD(dmc_group_list); +#endif +/* dmc_list is used by online expansion to find the correct dmc to reload */ +LIST_HEAD(dmc_list); + +struct mutex dmc_list_mtx; + +#ifdef MY_ABC_HERE +/* In under dmcg->mtx */ +static dmc_group_t * +dmc_group_new(char *uuid) +{ + dmc_group_t *dmcg = NULL; + + if (global_tester == TEST_NEW_DMC_GROUP_ALLOC_FAIL) { + sprint("Simulate dmc group alloc fail"); + global_tester = 0; + goto err; + } + + if (NULL == (dmcg = kzalloc(sizeof(*dmcg), GFP_NOIO))) { + goto err; + } + + snprintf(dmcg->uuid, sizeof(dmcg->uuid), "%s", uuid); + INIT_LIST_HEAD(&dmcg->node); + INIT_LIST_HEAD(&dmcg->dmc_list); + list_add(&dmcg->node, &dmc_group_list); + init_rwsem(&dmcg->rw_sem); +#ifdef MY_ABC_HERE + dmcg->md_io_throtl_thres = 20000; +#endif + init_waitqueue_head(&dmcg->nqf_wqh); + + INIT_LIST_HEAD(&dmcg->nqf_pending_dmcs); +err: + return dmcg; +} + +/* WARNING: should ONLY be used in dmc_group_add, should held dmcg_mutex */ +static dmc_group_t* +dmc_group_search(char *uuid) +{ + struct list_head *pos = NULL; + dmc_group_t *dmcg = NULL; + + list_for_each(pos, &dmc_group_list) { + dmcg = container_of(pos, dmc_group_t, node); + if (0 == strcmp(uuid, dmcg->uuid)) { + return dmcg; + } + } + + return NULL; +} + +static dmc_group_t * +dmc_group_add(struct cache_c *dmc) +{ + dmc_group_t *dmcg = NULL; + + mutex_lock(&dmcg_mtx); + + /* empty uuid for old version. Has it's own dmc group */ + if (0 == strlen(dmc->group_uuid) || NULL == (dmcg = dmc_group_search(dmc->group_uuid))) { + sdbg(DF_DMCG, "Create new dmcg"); + dmcg = dmc_group_new(dmc->group_uuid); + if (!dmcg) { + serr("Failed to allocate dmc group for %s", dmc->group_uuid); + goto err_unlock; + } + } + + down_write(&dmcg->rw_sem); + +#ifdef MY_ABC_HERE + list_add(&dmc->node->group_entry, &dmcg->dmc_list); +#endif + dmcg->num_dmc++; + sdbg(DF_DMCG, "Add to dmc=%p", dmc); + dmc->dmcg = dmcg; + + up_write(&dmcg->rw_sem); + +err_unlock: + mutex_unlock(&dmcg_mtx); + + sprint("Group UUID: %s", dmc->group_uuid); + return dmcg; +} + +// Note: Dummy cache won't be in a dmc group and no need to remove from it +static void +dmc_group_remove(struct cache_c *dmc) +{ + dmc_group_t *dmcg = dmc->dmcg; + + sdbg(DF_DMCG, "remove dmc=%p from dmcg", dmc); + + mutex_lock(&dmcg_mtx); + if (!dmcg) { + VERIFY_WARN(0); + mutex_unlock(&dmcg_mtx); + return; + } + + /* Need to lock dmcg_mtx first since we might change dmc_group_list */ + down_write(&dmcg->rw_sem); + +#ifdef MY_ABC_HERE + list_del(&dmc->node->group_entry); +#endif + dmcg->num_dmc--; + if (list_empty(&dmcg->dmc_list)) { + /* No entry in dmc group, remove it */ + VERIFY_WARN(0 == dmcg->num_dmc); + list_del(&dmcg->node); + up_write(&dmcg->rw_sem); + kfree(dmcg); + } else { + up_write(&dmcg->rw_sem); + } + + dmc->dmcg = NULL; + mutex_unlock(&dmcg_mtx); +} +#endif + +// Return the count of matched item, in under dmc_list_mtx +static int +dmc_list_search(const char *id, struct cache_c **ppdmc) +{ + int ret = 1; + int count = 0; + dmc_node *pnode = NULL; + + VERIFY_WARN(id && ppdmc); + + list_for_each_entry(pnode, &dmc_list, entry) { + sdbg(DF_RELOAD_TABLE, "search id=%s dmc=%p", pnode->id, pnode->pdmc); + if (0 == strcmp(pnode->id, id)) { + *ppdmc = pnode->pdmc; + ret = 0; + count++; + } + } + + if (count > 1) { + serr("Count should be 0 or 1"); + } + + return count; +} + +static int +dmc_list_add(const char *id, struct cache_c *pdmc) +{ + int ret = 1; + struct cache_c *tmp = NULL; + dmc_node *pnode = NULL; + + sdbg_in(DF_RELOAD_TABLE, "in"); + VERIFY_WARN(id && pdmc); + + mutex_lock(&dmc_list_mtx); + + if (0 < dmc_list_search(id, &tmp)) { + serr("Should not find dmc with the same id"); + goto err_unlock; + } + + pnode = kzalloc(sizeof(dmc_node), GFP_NOIO); + if (!pnode) { + serr("Allocate dmc node failed"); + goto err_unlock; + } + + snprintf(pnode->id, sizeof(pnode->id), "%s", id); + pnode->pdmc = pdmc; + pdmc->node = pnode; + + sdbg(DF_RELOAD_TABLE, "id=%s dmc=%p", pnode->id, pnode->pdmc); + list_add(&pnode->entry, &dmc_list); + + + ret = 0; +err_unlock: + mutex_unlock(&dmc_list_mtx); + sdbg_out(DF_RELOAD_TABLE, "out"); + return ret; +} + +static int +dmc_list_remove(const char *id, struct cache_c *pdmc) +{ + int ret = 1; + dmc_node *pnode = NULL; + dmc_node *next = NULL; + + VERIFY_WARN(id && pdmc); + sdbg(DF_RELOAD_TABLE, "start remove id=\"%s\" dmc=%p", id, pdmc); + + mutex_lock(&dmc_list_mtx); + + list_for_each_entry_safe(pnode, next, &dmc_list, entry) { + sdbg(DF_RELOAD_TABLE, "next node id=\"%s\"", pnode->id); + if (0 == strcmp(pnode->id, id)) { + + if (pnode->pdmc != pdmc) { + serr("dmc doesn't match: dmc=%p", pnode->pdmc); + goto end_unlock; + } + + list_del(&pnode->entry); + kfree(pnode); + pdmc->node = NULL; + ret = 0; + goto end_unlock; + } + } + +end_unlock: + mutex_unlock(&dmc_list_mtx); + sdbg(DF_RELOAD_TABLE, "finish ret=%d", ret); + return ret; +} + +static +void set_dm_target_attribute(struct dm_target *ti, struct cache_c *dmc, dm_attr_t dm_attr) +{ + VERIFY(dmc); + + ti->private = dmc; + + if (DM_ATTR_CACHE_ENABLE == dm_attr) { +#ifdef MY_DEF_HERE + ti->max_io_len = 0; +#else + // Let dm layer split IO automatically + ti->max_io_len = MAX_BIO_SIZE; +#endif + dmc->max_io_len = ti->max_io_len; + sdbg(DF_ONLINE, "cache is enabled, set num_discard_bios = 0"); + // Not support trim as the default driver behavior + ti->num_discard_bios = 0; + } else if (DM_ATTR_CACHE_DISABLE == dm_attr) { + ti->max_io_len = 0; + dmc->max_io_len = ti->max_io_len; + sdbg(DF_ONLINE, "cache is disabled, set num_discard_bios = 1"); + ti->num_discard_bios = 1; + } else { + serr("Incorect dm attr=%d", dm_attr); + } + +#ifdef MY_ABC_HERE + ti->num_flush_bios = 1; + ti->flush_supported = 1; +#endif + +#ifdef CONFIG_SYNO_MD_UNUSED_HINT + if (blk_queue_unused_hint(bdev_get_queue(get_disk_bdev(dmc)))) + ti->num_unused_hint_bios = 1; +#endif +} + +#ifdef MY_ABC_HERE +/* + * WARNING: Only use this function in one-time logic (e.g. reload) + * Use it in frequently-called logic (e.g. IO) might cause performance issue + * since it calls spinlock many times + * + * Use the following functions to eliminate the need + * to allocate / free memory in spin_lock functions + */ +void +bitmap_control_get(struct cache_c *dmc) +{ + int get_control = 0; + unsigned long flags = 0; + + while (1) { + spin_lock_irqsave(&dmc->bitmap_control.lock, flags); + + if (!dmc->bitmap_control.in_use) { + dmc->bitmap_control.in_use = 1; + get_control = 1; + } + + spin_unlock_irqrestore(&dmc->bitmap_control.lock, flags); + + // Prevent to call spin lock too often + mdelay(100); + + if (get_control) { + break; + } + } +} + +void +bitmap_control_put(struct cache_c *dmc) +{ + unsigned long flags; + + spin_lock_irqsave(&dmc->bitmap_control.lock, flags); + + if (dmc->bitmap_control.in_use) { + dmc->bitmap_control.in_use = 0; + } else { + serr("bitmap Must be in use!"); + WARN_ON(1); + } + + spin_unlock_irqrestore(&dmc->bitmap_control.lock, flags); +} +#endif + +#ifdef MY_ABC_HERE +static int +flashcache_create_dummy(struct dm_target *ti, int argc, char **argv) +{ + int r = -EINVAL; + struct cache_c *dmc = NULL; + + sdbg(DF_ONLINE, "start"); + + if (!ti || !argc) { + serr("Incorrect parameter"); + goto err; + } + + if (TEST_MALLOC_FAIL_IN_CREATE == global_tester) { + serr("Simulate memory allocate failed"); + } else { + dmc = vzalloc(sizeof(*dmc)); + } + if (!dmc) { + ti->error = "flashcache: Failed to allocate cache context"; + r = -ENOMEM; + goto err; + } + + dmc->tgt = ti; + + dmc->cache_mode = FLASHCACHE_DUMMY; + dmc->cache_state = CACHE_DISABLED; + + // disk_dev / disk_devname + if ((r = flashcache_get_dev(ti, argv[0], &dmc->disk_dev, + dmc->disk_devname, ti->len, CHECK_IN_USE))) { + if (r == -EBUSY) + ti->error = "flashcache: Disk device is busy, cannot create cache"; + else + ti->error = "flashcache: Disk device lookup failed"; + + serr("initalized disk_dev failed"); + goto err; + } + + // Locks + spin_lock_init(&dmc->cache_spin_lock); + + // For expansion + spin_lock_init(&dmc->reload_lock); + spin_lock_init(&dmc->dev_lock); + init_rwsem(&dmc->ioctl_rwsem); + dmc->disk_bdev = dmc->disk_dev->bdev; + + // Wait queues for enable / disable + init_waitqueue_head(&dmc->wait_for_cache_disable_queue); + init_waitqueue_head(&dmc->wait_old_ios_completed_queue); + + // cache_dev + strncpy(dmc->cache_devname, argv[1], sizeof(dmc->cache_devname) - 1); + + // cachedev_name + if (sscanf(argv[2], "%s", (char *)&dmc->dm_vdevname) != 1) { + ti->error = "flashcache: Virtual device name lookup failed"; + goto err; + } + + if (dmc_id_set(dmc)) { + serr("can't generate id"); + goto err; + } + + // For enabling later + if (dmc_list_add(dmc->id, dmc)) { + serr("Can't add dmc to list"); + goto err; + } + + set_dm_target_attribute(ti, dmc, DM_ATTR_CACHE_DISABLE); + + // Add to global list + (void)wait_on_bit_lock_wrapper(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST, + flashcache_wait_schedule, TASK_UNINTERRUPTIBLE); + dmc->next_cache = cache_list_head; + cache_list_head = dmc; + clear_bit(FLASHCACHE_UPDATE_LIST, &flashcache_control->synch_flags); + smp_mb__after_clear_bit_wrapper(); + wake_up_bit(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST); + + dmc->init_nr_dirty = -1; + + r = 0; + + return r; + +err: + if (dmc && dmc->disk_dev) { + dm_put_device(ti, dmc->disk_dev); + } + + if (dmc) { + vfree(dmc); + } + + return r; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int reload_nqf(struct cache_c *dmc) +{ + int r = -1; + unsigned int noio_flags = 0; + + unsigned long new_bitmap_num_idx = OQF_FALLOW_MAP_NUM_IDX(dmc); + int *old_bitmap = NULL; + int *new_bitmap = NULL; + + if (new_bitmap_num_idx == dmc->oqf.bitmap_num_idx) { + r = 0; + goto end; + } + + noio_flags = memalloc_noio_save(); + new_bitmap = (int *) vzalloc(sizeof(int) * new_bitmap_num_idx); + memalloc_noio_restore(noio_flags); + + if (check_new_error_inject(dmc, OQF_RELOAD_MEM_ALLOC_FAIL)) { + sprint("Error inject reload oqf bitmap mem alloc fail"); + dmc->sysctl_new_error_inject = 0; + vfree(new_bitmap); + new_bitmap = NULL; + } + + if (NULL == new_bitmap) { + serr("Failed to allocate %lu bytes of memory for fallow bitmap", + sizeof(int) * new_bitmap_num_idx); + r = -ENOMEM; + goto err; + } + + down_write(&dmc->oqf.bitmap_rwsem); + memcpy(new_bitmap, dmc->oqf.volume_bitmap, dmc->oqf.bitmap_num_idx * sizeof(int)); + dmc->oqf.bitmap_num_idx = new_bitmap_num_idx; + old_bitmap = dmc->oqf.volume_bitmap; + dmc->oqf.volume_bitmap = new_bitmap; + up_write(&dmc->oqf.bitmap_rwsem); + + vfree(old_bitmap); + + r = 0; +end: +err: + return r; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +// Resize pin bitmap when volume size is changed +static int reload_pinfile(struct cache_c *dmc) +{ + int r = 0; + unsigned char *pnew_bitmap = NULL; + u64 new_size_bit = 0; + u64 new_size_byte = 0; + unsigned int noio_flags = 0; + + new_size_bit = compatible_div(get_disk_bdev(dmc)->bd_inode->i_size, + PIN_BYTES_PER_BIT); + new_size_byte = compatible_div(new_size_bit, 8); + + if (new_size_byte == dmc->bitmap_size_byte) { + goto end; + } + + if (new_size_byte < dmc->bitmap_size_byte) { + serr("New bitmap size (%llu) should not less than the origina bitmap size (%llu)", + (u64)new_size_byte, (u64)dmc->bitmap_size_byte); + r = -EINVAL; + goto err; + } + + noio_flags = memalloc_noio_save(); + pnew_bitmap = vzalloc(new_size_byte); + memalloc_noio_restore(noio_flags); + if (!pnew_bitmap) { + serr("Allocate new bitmap memory (%llu bytes) failed", new_size_byte); + r = -ENOMEM; + goto err; + } + + bitmap_control_get(dmc); + memcpy(pnew_bitmap, dmc->pbitmap_ranges, dmc->bitmap_size_byte); + + sdbg(DF_PIN, "bitmap resize start"); + + vfree(dmc->pbitmap_ranges); + dmc->pbitmap_ranges = pnew_bitmap; + dmc->bitmap_size_byte = new_size_byte; + + bitmap_control_put(dmc); + sdbg(DF_PIN, "bitmap resize end"); + + sdbg(DF_PIN, "Allocate & memcopy size = %llu KB", new_size_byte / 1024); + +end: +err: + return r; +} +#endif /* MY_ABC_HERE */ + +/* + * argv[0]: current disk_path of cache + * argv[1]: current ssd_path of cache. Must be "none" after cache is disabled + */ +static int +flashcache_reload_table(struct dm_target *ti, int argc, char **argv) +{ + int r = 0; + unsigned long flags = 0; + struct cache_c *dmc = NULL; + int can_reload = 0; + struct dm_target *ori_ti = NULL; + sector_t new_disk_size = 0; + + mutex_lock(&dmc_list_mtx); + if (0 == dmc_list_search(argv[0], &dmc)) { + mutex_unlock(&dmc_list_mtx); + serr("Can't find correct dmc, id=%s", argv[0]); + ti->error = "Can't find correct dmc"; + r = -EINVAL; + goto err; + } + mutex_unlock(&dmc_list_mtx); + + /* + * Make sure user doesn't input wrong disk devname or cache devname. + * Otherwise, it might lead to free original block dev to get call trace + * since no other dm_dev use it anymore + */ + + if (0 != strcmp(argv[0], dmc->disk_devname)) { + serr("Disk dev name not match (%s, %s)", argv[0], + dmc->disk_devname) + r = -EPERM; + goto err; + } + + if (0 != strcmp(argv[1], dmc->cache_devname)) { + serr("SSD dev name not match (%s, %s)", argv[1], + dmc->cache_devname) + r = -EPERM; + goto err; + } + + if ((CACHE_DISABLED != dmc->cache_state) && (CACHE_ENABLED != dmc->cache_state)) { + serr("This state (%d) doesn't allow to expand", dmc->cache_state); + r = -EPERM; + goto err; + } + + sdbg(DF_ONLINE, "Get matched dmc !!!"); + + /* + * Prevent the error caused by issuing reload command multiple times + * The reload table flag would be unset after the destroy function ended + */ + spin_lock_irqsave(&dmc->reload_lock, flags); + if (0 == dmc->reload_table) { + dmc->reload_table = 1; + can_reload = 1; + } + spin_unlock_irqrestore(&dmc->reload_lock, flags); + + if (!can_reload) { + serr("Error! cache is in reloading table"); + r = -EPERM; + goto err_can_reload; + } + + ori_ti = dmc->tgt; + dmc->tgt = ti; + + // Access the old dm_dev saved on dmc + new_disk_size = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + + if (new_disk_size < dmc->disk_devsize) { + serr("New disk size (%llu) should be larger then original disk size (%llu)", + (u64)new_disk_size, (u64)dmc->disk_devsize); + r = -EINVAL; + goto err; + } + + /* + * Create new dm_devs for new mapping table + * Ignore the block device reuse check since it is still used by original + * mapping table now + */ + if ((r = flashcache_get_dev(ti, dmc->disk_devname, + &dmc->disk_dev_reload, NULL, ti->len, CHECK_NONE))) { + if (r == -EBUSY) + ti->error = "flashcache: Disk device is busy, cannot create cache"; + else + ti->error = "flashcache: Disk device lookup failed"; + goto err; + } + + if (CACHE_ENABLED == dmc->cache_state) { + // Not dummy cache + if ((r = flashcache_get_dev(ti, dmc->cache_devname, + &dmc->cache_dev_reload, NULL, 0, CHECK_NONE))) { + if (r == -EBUSY) + ti->error = "flashcache: Cache device is busy, cannot create cache"; + else + ti->error = "flashcache: Cache device lookup failed"; + goto err; + } + } + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + if ((r = reload_pinfile(dmc))) { + goto err; + } + } +#endif + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + sdbg(DF_QUICKFLUSH, "Reloading Online Quickflush"); + if ((r = reload_nqf(dmc))) { + goto err; + } + } +#endif + + // Don't really change any value about dmc, only initialize dm_target + if (FLASHCACHE_DUMMY == dmc->cache_mode) { + set_dm_target_attribute(ti, dmc, DM_ATTR_CACHE_DISABLE); + } else if ((FLASHCACHE_WRITE_BACK == dmc->cache_mode) || (FLASHCACHE_WRITE_AROUND == dmc->cache_mode)) { + set_dm_target_attribute(ti, dmc, DM_ATTR_CACHE_ENABLE); + } + + r = 0; + + return r; + +err: + if (dmc && can_reload) { + if (dmc->tgt != ori_ti) { + dmc->tgt = ori_ti; + } + + if (dmc->cache_dev_reload) { + dm_put_device(ti, dmc->cache_dev_reload); + dmc->cache_dev_reload = NULL; + } + + if (dmc->disk_dev_reload) { + dm_put_device(ti, dmc->disk_dev_reload); + dmc->disk_dev_reload = NULL; + } + + spin_lock_irqsave(&dmc->reload_lock, flags); + // Only set to 0 when failed + if (dmc->reload_table) { + dmc->reload_table = 0; + } + spin_unlock_irqrestore(&dmc->reload_lock, flags); + } + +err_can_reload: + // Should not release any resources that are not requested by us + + return r; +} +#endif + +/* + * Construct a cache mapping. + * arg[0]: path to source device + * arg[1]: path to cache device + * arg[2]: md virtual device name + * arg[3]: cache mode (from flashcache.h) + * FLASHCACHE_WRITE_BACK=1 + * FLASHCACHE_WRITE_THROUGH=2 + * FLASHCACHE_WRITE_AROUND=3 + * FLASHCACHE_DUMMY=4 + * arg[4]: cache persistence (if set, cache conf is loaded from disk) + * CACHE_RELOAD=1 (For load) + * CACHE_CREATE=2 + * CACHE_FORCECREATE=3 + * CACHE_RELOAD_TABLE=4 + * Cache configuration parameters (if not set, default values are used. + * arg[5]: + * case 1: "error-check": string, return error when load error + * case 2: cache block size (in sectors) + * arg[6]: cache size (in blocks) + * arg[7]: cache associativity + * arg[8]: md block size (in sectors) + * arg[9]: cache version + * arg[10]: cache group uuid for allocated cache + * + * ================================================================= + * + * WARNING: Three cases use this function: + * 1. Load a cache (dmc doesn't exist) + * 2. Reload (expand) a cache (dmc exists) + * 3. Enable a cache (dmc exists) + */ +// In dummy mode, dmc is already existing and should not be freed +int +flashcache_enable_or_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct cache_c *dmc; + sector_t i, order; + int r = 0; + int persistence = 0; +#ifdef MY_ABC_HERE + unsigned long long bitmap_size_bit = 0; +#endif +#ifdef MY_ABC_HERE + unsigned int cache_mode = -1; + // Already has dummy dmc, just to init it to enable cache + int dummy_mode_to_enable = 0; +#endif /* MY_ABC_HERE */ + int cache_version = -1; + int jp_required = 0; + int procfs_created = 0; + + if (argc < 3) { + ti->error = "flashcache: Need at least 3 arguments"; + serr("need at least 3 arguments"); + r = -EINVAL; + goto bad; + } + +#ifdef MY_ABC_HERE + sdbg(DF_RELOAD_TABLE, "argc=%d", argc); + + if (argc >= 5) { + if (1 != sscanf(argv[4], "%u", &persistence)) { + ti->error = "flashcache: Parse psersistence failed"; + serr("Failed to parse persistence %s", argv[4]); + r = -EINVAL; + goto bad; + } + sdbg(DF_RELOAD_TABLE, "persistence=%d", persistence); + } + + /* + * ########### Reload Table ########### + * e.g. volume expansion + */ + if (CACHE_RELOAD_TABLE == persistence) { + r = flashcache_reload_table(ti, argc, argv); + // Just return r in end + goto end; + } +#endif + +#ifdef MY_ABC_HERE + if (sscanf(argv[3], "%u", &cache_mode) != 1) { + ti->error = "flashcache: sscanf failed, invalid cache mode"; + serr("Failed to parse cache mode: %s", argv[3]); + r = -EINVAL; + goto bad; + } + + if (cache_mode < FLASHCACHE_WRITE_BACK || + cache_mode > FLASHCACHE_DUMMY) { + ti->error = "flashcache: Invalid cache mode"; + serr("cache_mode = %d", cache_mode); + r = -EINVAL; + goto bad; + } + + sdbg(DF_ONLINE, "persiscence=%d cache_mode=%d", persistence, cache_mode); + + /* + * ########### Create Dummy Cache ########### + */ + if ((CACHE_CREATE == persistence) && (FLASHCACHE_DUMMY == cache_mode)) { + // Dummy mode only do here + r = flashcache_create_dummy(ti, argc, argv); + goto end; + } + + /* + * ########### Only Enable / Load / Crate Cache go here ########### + * + * Cases go below: + * - Enable RO/RW cache from dummy mode (dmc exists) + * - Load RW Cache / Create RO Cache at startup (dmc doesn't exsit ) + */ + + r = job_pool_require(); + if (0 != r) { + serr("Failed to requre job pool, ret=%d", r); + goto bad; + } + jp_required = 1; + sprint("Check and init Jobs finish"); + + if (NULL != ti->private) { + // Cases: Enable RO/RW Cache from dummy mode + sdbg(DF_ONLINE, "in dummy mode"); + dummy_mode_to_enable = 1; + + dmc = ti->private; + + if (CACHE_DISABLED != dmc->cache_state) { + ti->error = "flashcache: Cache only only be enabled from disabled state"; + serr("Cache enable not from disable state, current state: %d", dmc->cache_state); + r = -EINVAL; + goto bad; + } + } else { + // Cases: Load RW Cache or create RO Cache at startup + +#endif /* MY_ABC_HERE */ + dmc = vzalloc(sizeof(*dmc)); + if (dmc == NULL) { + ti->error = "flashcache: Failed to allocate cache context"; + serr("Failed to allocate cache context"); + r = -ENOMEM; + goto bad; + } + + dmc->tgt = ti; + +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!dummy_mode_to_enable) { + dmc->init_nr_dirty = -1; + } +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE + if (!dmc->disk_dev) { +#endif /*MY_ABC_HERE */ +#ifdef MY_ABC_HERE + // Check if bdev is in use + if ((r = flashcache_get_dev(ti, argv[0], &dmc->disk_dev, + dmc->disk_devname, ti->len, CHECK_IN_USE))) { +#else + if ((r = flashcache_get_dev(ti, argv[0], &dmc->disk_dev, + dmc->disk_devname, ti->len))) { +#endif + if (r == -EBUSY) { + ti->error = "flashcache: Disk device is busy, cannot create cache"; + serr("disk device busy"); + } else { + ti->error = "flashcache: Disk device lookup failed"; + serr("disk device lookup failed"); + } + goto bad1; + } +#ifdef MY_ABC_HERE + } +#endif /*MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if ((r = flashcache_get_dev(ti, argv[1], &dmc->cache_dev, + dmc->cache_devname, 0, CHECK_IN_USE))) { +#else + if ((r = flashcache_get_dev(ti, argv[1], &dmc->cache_dev, + dmc->cache_devname, 0))) { +#endif + if (r == -EBUSY) { + ti->error = "flashcache: Cache device is busy, cannot create cache"; + serr("cache device busy"); + } else { + ti->error = "flashcache: Cache device lookup failed"; + serr("cache device lookup failed"); + } + goto bad2; + } +#ifdef MY_ABC_HERE + if (dummy_mode_to_enable) { + dmc->cache_bdev = dmc->cache_dev->bdev; + } else { +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + dmc->disk_bdev = dmc->disk_dev->bdev; + dmc->cache_bdev = dmc->cache_dev->bdev; +#ifdef MY_ABC_HERE + if (dmc_id_set(dmc)) { + serr("generate id failed"); + r = -EINVAL; + goto bad3; + } +#else + snprintf(dmc->id, sizeof(dmc->id), "%s-%s", dmc->disk_devname, dmc->cache_devname); +#endif /* MY_ABC_HERE */ +#endif + if (sscanf(argv[2], "%s", (char *)&dmc->dm_vdevname) != 1) { + ti->error = "flashcache: Virtual device name lookup failed"; + serr("virtual device name lookup failed: %s", argv[2]); + r = -EINVAL; + goto bad3; + } +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ + + r = flashcache_kcached_init(dmc); + if (r) { + ti->error = "Failed to initialize kcached"; + serr("Failed to init kcached"); + goto bad3; + } + +#ifdef MY_ABC_HERE + // Move the sscanf above + + dmc->cache_mode = cache_mode; +#else + if (sscanf(argv[3], "%u", &dmc->cache_mode) != 1) { + ti->error = "flashcache: sscanf failed, invalid cache mode"; + serr("failed to get cache mode from %s", argv[3]); + r = -EINVAL; + goto bad3; + } + if (dmc->cache_mode < FLASHCACHE_WRITE_BACK || + dmc->cache_mode > FLASHCACHE_WRITE_AROUND) { + DMERR("cache_mode = %d", dmc->cache_mode); + ti->error = "flashcache: Invalid cache mode"; + serr("invalid cache mode %d", dmc->cache_mode); + r = -EINVAL; + goto bad3; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + bitmap_size_bit = compatible_div(get_disk_bdev(dmc)->bd_inode->i_size, PIN_BYTES_PER_BIT); + dmc->bitmap_size_byte = compatible_div(bitmap_size_bit, 8); + dmc->bitmap_is_set = 0; + sdbg(DF_PIN, "allocate bitmap, size=%llu", dmc->bitmap_size_byte); + + dmc->pbitmap_ranges = vmalloc(dmc->bitmap_size_byte); + if (!dmc->pbitmap_ranges) { + ti->error = "Can't allocate bitmap ranges"; + serr("Failed to allocate bitmap ranges"); + r = -ENOMEM; + goto bad3; + } + + memset(dmc->pbitmap_ranges, 0, dmc->bitmap_size_byte); + + sdbg(DF_PIN, "allocate finish"); + } +#endif + + + /* + * XXX - Persistence is totally ignored for write through and write around. + * Maybe this should really be moved to the end of the param list ? + */ + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + if (argc >= 5) { +#ifdef MY_ABC_HERE + // Move ahead +#else + if (sscanf(argv[4], "%u", &persistence) != 1) { + ti->error = "flashcache: sscanf failed, invalid cache persistence"; + serr("parse cache persistence failed. persistence: %s", argv[4]); + r = -EINVAL; + goto bad3; + } +#endif + if (persistence < CACHE_RELOAD || persistence > CACHE_FORCECREATE) { + ti->error = "flashcache: Invalid cache persistence"; + serr("Invalid cache persistence = %d", persistence); + r = -EINVAL; + goto bad3; + } + } + if (persistence == CACHE_RELOAD) { + dmc->load_action = LOAD_ERROR_IGNORE; + if (argc == 6) { + if (0 == strcmp(argv[5], SZ_LOAD_ERROR_CHECK)) { + sprint("Enable load check"); + dmc->load_action = LOAD_ERROR_CHECK; + } + } + if (flashcache_writeback_load(dmc)) { + ti->error = "flashcache: Cache reload failed"; + serr("writeback cache load failed"); + r = -EINVAL; + goto bad3; + } + goto init; /* Skip reading cache parameters from command line */ + } + } else + persistence = CACHE_CREATE; + + if (argc >= 6) { + if (sscanf(argv[5], "%u", &dmc->block_size) != 1) { + ti->error = "flashcache: Invalid block size"; + serr("Failed to parse block size: %s", argv[5]); + r = -EINVAL; + goto bad3; + } + if (!dmc->block_size || (dmc->block_size & (dmc->block_size - 1))) { + ti->error = "flashcache: Invalid block size"; + serr("Invalid block size: %u", dmc->block_size); + r = -EINVAL; + goto bad3; + } + } + + if (!dmc->block_size) + dmc->block_size = DEFAULT_BLOCK_SIZE; + dmc->block_shift = ffs(dmc->block_size) - 1; + dmc->block_mask = dmc->block_size - 1; + + /* dmc->size is specified in sectors here, and converted to blocks later + * conversion happens in flashcache_xxx_create() */ + if (argc >= 7) { + if (sscanf(argv[6], "%llu", (u64 *)&dmc->size) != 1) { + ti->error = "flashcache: Invalid cache size"; + serr("Failed to parse cache size: %s", argv[6]); + r = -EINVAL; + goto bad3; + } + } + + if (!dmc->size) + dmc->size = to_sector(get_cache_bdev(dmc)->bd_inode->i_size); + + if (argc >= 8) { + if (sscanf(argv[7], "%u", &dmc->assoc) != 1) { + ti->error = "flashcache: Invalid cache associativity"; + serr("Failed to parse associativity: %s", argv[7]); + r = -EINVAL; + goto bad3; + } + if (!dmc->assoc || (dmc->assoc & (dmc->assoc - 1)) || + dmc->assoc > FLASHCACHE_MAX_ASSOC || + dmc->assoc < FLASHCACHE_MIN_ASSOC || + dmc->size < dmc->assoc) { + ti->error = "flashcache: Invalid cache associativity"; + serr("Invalid associativity, %u", dmc->assoc); + r = -EINVAL; + goto bad3; + } + } + + if (!dmc->assoc) + dmc->assoc = DEFAULT_CACHE_ASSOC; + dmc->assoc_shift = ffs(dmc->assoc) - 1; + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + if (argc >= 9) { + if (sscanf(argv[8], "%u", &dmc->md_block_size) != 1) { + ti->error = "flashcache: Invalid metadata block size"; + serr("Failed to parse md block size: %s", argv[8]); + r = -EINVAL; + goto bad3; + } + if (!dmc->md_block_size || (dmc->md_block_size & (dmc->md_block_size - 1)) || + dmc->md_block_size > FLASHCACHE_MAX_MD_BLOCK_SIZE) { + ti->error = "flashcache: Invalid metadata block size"; + serr("invalid md block size: %u", dmc->md_block_size); + r = -EINVAL; + goto bad3; + } + if (dmc->assoc < + (dmc->md_block_size * 512 / sizeof(struct flash_cacheblock))) { + ti->error = "flashcache: Please choose a smaller metadata block size or larger assoc"; + serr("Metadata block size too large or assoc too small"); + r = -EINVAL; + goto bad3; + } + } + + if (!dmc->md_block_size) + dmc->md_block_size = DEFAULT_MD_BLOCK_SIZE; + + /* + * Here should check if md block size is large then block device's sector size + * (as flashcache_create command does). So use following function instead. + */ + if (dmc->md_block_size * 512 < bdev_logical_block_size(get_cache_bdev(dmc))) { + ti->error = "flashcache: Metadata block size must be >= cache device sector size"; + serr("Metadata block size must be >= cache device sector size"); + r = -EINVAL; + goto bad3; + } + } + + // Load RW cache doesn't go here + if (argc >= 10) { + if (sscanf(argv[9], "%d", &cache_version) != 1) { + ti->error = "flashcache: Invalid cache version parameter"; + serr("Failed to parse cache version: %s", argv[9]); + r = -EINVAL; + goto bad3; + } + } + if (!IS_NEW_MODE_VERSION(cache_version)) { + ti->error = "flashcache: Invalid cache version"; + serr("Invalid cache version: %d", cache_version); + r = -EINVAL; + goto bad3; + } + + sprint("Cache Version: %d", cache_version); +#ifdef MY_ABC_HERE + dmc->hash_mapping = get_hash_mapping_from_cache_version(cache_version); + if (-1 == dmc->hash_mapping) { + serr("Failed to get hash mapping version from cache version %d", cache_version); + r = -EINVAL; + goto bad3; + } + sprint("Hash mapping = %d", dmc->hash_mapping); +#endif + +#ifdef MY_ABC_HERE + if (argc >= 11) { + snprintf(dmc->group_uuid, sizeof(dmc->group_uuid), "%s", argv[10]); + } +#endif + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + if (persistence == CACHE_CREATE) { + if (flashcache_writeback_create(dmc, cache_version, 0)) { + ti->error = "flashcache: Cache Create Failed"; + serr("writeback cache create failed"); + r = -EINVAL; + goto bad3; + } + } else { + if (flashcache_writeback_create(dmc, cache_version, 1)) { + ti->error = "flashcache: Cache Force Create Failed"; + serr("writeback cache create failed"); + r = -EINVAL; + goto bad3; + } + } +#ifdef MY_ABC_HERE + } else { + DMERR("Can handle failure in creation"); + // SYNO: Also for WRITE_AROUND + if (flashcache_writethrough_create(dmc, cache_version)) { + ti->error = "flashcache: Cache Create Failed"; + serr("writethough cache create failed"); + r = -EINVAL; + goto bad3; + } + } +#else + } else + flashcache_writethrough_create(dmc); +#endif + + +init: + dmc->num_sets = dmc->size >> dmc->assoc_shift; + order = dmc->num_sets * sizeof(struct cache_set); + dmc->cache_sets = (struct cache_set *)vmalloc(order); + if (!dmc->cache_sets) { + ti->error = "Unable to allocate memory"; + serr("Failed to allocate cache sets"); + r = -ENOMEM; + goto bad3; + } + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + if ((r = alloc_online_quickflush(dmc))) { + ti->error = "Unable to allocate fallow bitmap"; + goto bad3; + } + } +#endif + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + if ((r = alloc_new_md_update(dmc))) { + ti->error = "Unable to allocate md updates"; + serr("Failed to allocate md updates"); + goto bad3; + } + } +#endif + + for (i = 0 ; i < dmc->num_sets ; i++) { + dmc->cache_sets[i].set_fifo_next = i * dmc->assoc; + dmc->cache_sets[i].set_clean_next = i * dmc->assoc; +#ifdef MY_ABC_HERE +#else + dmc->cache_sets[i].nr_dirty = 0; + dmc->cache_sets[i].clean_inprog = 0; + dmc->cache_sets[i].fallow_next_cleaning = jiffies; + dmc->cache_sets[i].dirty_fallow = 0; + dmc->cache_sets[i].fallow_tstamp = jiffies; +#endif + dmc->cache_sets[i].lru_tail = FLASHCACHE_LRU_NULL; + dmc->cache_sets[i].lru_head = FLASHCACHE_LRU_NULL; + } + + /* Push all blocks into the set specific LRUs */ + for (i = 0 ; i < dmc->size ; i++) { + dmc->cache[i].lru_prev = FLASHCACHE_LRU_NULL; + dmc->cache[i].lru_next = FLASHCACHE_LRU_NULL; + flashcache_reclaim_lru_movetail(dmc, i); + } + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + order = (dmc->md_blocks - 1) * sizeof(struct cache_md_block_head); + dmc->md_blocks_buf = (struct cache_md_block_head *)vmalloc(order); + if (!dmc->md_blocks_buf) { + ti->error = "Unable to allocate memory"; + serr("Failed to allocate md_block_buf"); + r = -ENOMEM; + goto bad3; + } + + for (i = 0 ; i < dmc->md_blocks - 1 ; i++) { + dmc->md_blocks_buf[i].nr_in_prog = 0; + dmc->md_blocks_buf[i].queued_updates = NULL; + } + } + +#ifdef MY_ABC_HERE + if (!dummy_mode_to_enable) { +#endif /* MY_ABC_HERE */ + spin_lock_init(&dmc->cache_spin_lock); +#ifdef MY_ABC_HERE + spin_lock_init(&dmc->reload_lock); + spin_lock_init(&dmc->dev_lock); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + init_rwsem(&dmc->ioctl_rwsem); + } +#endif /* MY_ABC_HERE */ + + spin_lock_init(&dmc->endio_spin_lock); + + spin_lock_init(&dmc->bypass_lock); + +#ifdef MY_ABC_HERE + spin_lock_init(&dmc->bitmap_control.lock); +#endif + +#ifdef MY_ABC_HERE +#else + dmc->sync_index = 0; + dmc->clean_inprog = 0; +#endif + + set_dm_target_attribute(ti, dmc, DM_ATTR_CACHE_ENABLE); + + /* Cleaning Thresholds */ + dmc->sysctl_dirty_thresh = DIRTY_THRESH_DEF; + dmc->dirty_thresh_set = (dmc->assoc * dmc->sysctl_dirty_thresh) / 100; + dmc->max_clean_ios_total = MAX_CLEAN_IOS_TOTAL; + dmc->max_clean_ios_set = MAX_CLEAN_IOS_SET; + + /* Other sysctl defaults */ + dmc->sysctl_io_latency_hist = 0; + dmc->sysctl_do_sync = 0; + dmc->sysctl_stop_sync = 0; + dmc->sysctl_pid_do_expiry = 0; + dmc->sysctl_max_pids = MAX_PIDS; + dmc->sysctl_pid_expiry_secs = PID_EXPIRY_SECS; + // 64KB SSD Cache only support LRU + dmc->sysctl_reclaim_policy = FLASHCACHE_LRU; + dmc->sysctl_zerostats = 0; + dmc->sysctl_error_inject = 0; + dmc->sysctl_fast_remove = 0; + dmc->sysctl_cache_all = 1; + dmc->sysctl_cache_all_input = 1; + dmc->sysctl_fallow_clean_speed = FALLOW_CLEAN_SPEED; + dmc->sysctl_fallow_delay = FALLOW_DELAY; + dmc->sysctl_skip_seq_thresh_kb = SKIP_SEQUENTIAL_THRESHOLD; + dmc->sysctl_skip_seq_fgap_kb = SKIP_SEQ_DEFAULT_FGAP_KB; + dmc->sysctl_skip_seq_bgap_kb = SKIP_SEQ_DEFAULT_BGAP_KB; + + /* Latency Diagnose */ + spin_lock_init(&dmc->lat_spin_lock); + dmc->sysctl_syno_latency_diagnose = 0; + dmc->sysctl_latency_diagnose_itvl_ms = LAT_INTERVAL_MS; + dmc->sysctl_io_disk_lat_thres_ms = LAT_HIT_DISK_THRES_MS; + dmc->sysctl_io_ssd_lat_thres_ms = LAT_HIT_SSD_THRES_MS; + dmc->sysctl_lat_perc_ten_thousandth = LAT_PERC_TEN_THOUSANDTH; + dmc->lat_stats_idx = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + timer_setup(&dmc->latency_timer, flashcache_process_lat_stats, 0); +#else + init_timer(&dmc->latency_timer); + dmc->latency_timer.function = flashcache_process_lat_stats; + /* Newer kernel remove data field in timer_list, and pass timer_list + * to the handler function. align behavior */ + dmc->latency_timer.data = (unsigned long)&dmc->latency_timer; +#endif + + /* Sequential i/o spotting */ + for (i = 0; i < SEQUENTIAL_TRACKER_QUEUE_DEPTH; i++) { + dmc->seq_recent_ios[i].most_recent_sector = 0; + dmc->seq_recent_ios[i].last_bio_sectors = 0; + dmc->seq_recent_ios[i].sequential_sectors = 0; + dmc->seq_recent_ios[i].prev = (struct sequential_io *)NULL; + dmc->seq_recent_ios[i].next = (struct sequential_io *)NULL; + seq_io_move_to_lruhead(dmc, &dmc->seq_recent_ios[i]); + } + dmc->seq_io_tail = &dmc->seq_recent_ios[0]; + spin_lock_init(&dmc->seq_io_spin_lock); + + (void)wait_on_bit_lock_wrapper(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST, + flashcache_wait_schedule, TASK_UNINTERRUPTIBLE); +#ifdef MY_ABC_HERE + // dmc has been added to cache_list in dummy mode + if (!dummy_mode_to_enable) { +#endif /* MY_ABC_HERE */ + dmc->next_cache = cache_list_head; + cache_list_head = dmc; +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ + clear_bit(FLASHCACHE_UPDATE_LIST, &flashcache_control->synch_flags); + smp_mb__after_clear_bit_wrapper(); + wake_up_bit(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST); + + for (i = 0 ; i < dmc->size ; i++) { + if (dmc->cache[i].cache_state & VALID) { + atomic64_inc(&dmc->cached_blocks); + } + if (dmc->cache[i].cache_state & DIRTY) { +#ifdef MY_ABC_HERE +#else +#ifdef EC_EMULATE_U64_DIVISION + dmc->cache_sets[div64_u64(i, dmc->assoc)].nr_dirty++; +#else + dmc->cache_sets[i / dmc->assoc].nr_dirty++; +#endif +#endif /* MY_ABC_HERE */ + dmc->nr_dirty++; + } + } + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + init_online_quickflush(&dmc->oqf); + init_plug_wb(&dmc->plug_wb); + } +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&dmc->delayed_clean, flashcache_clean_all_sets, dmc); +#else + INIT_DELAYED_WORK(&dmc->delayed_clean, flashcache_clean_all_sets); +#endif +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + init_new_md_update(dmc); + } +#endif + + dmc->whitelist_head = NULL; + dmc->whitelist_tail = NULL; + dmc->blacklist_head = NULL; + dmc->blacklist_tail = NULL; + dmc->num_whitelist_pids = 0; + dmc->num_blacklist_pids = 0; + + flashcache_ctr_procfs(dmc); + procfs_created = 1; + +#ifdef MY_DEF_HERE + dmc->max_io_len = 0; +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE + if (!dummy_mode_to_enable) { +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (dmc_list_add(dmc->id, dmc)) { + serr("Can't add dmc to list"); + r = -EINVAL; + goto bad3; + } +#endif +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_set(&dmc->num_uncached_write, 0); + atomic_set(&dmc->num_write_cache, 0); + atomic_set(&dmc->in_flush, 0); + atomic_set(&dmc->num_flush_bio, 0); + init_waitqueue_head(&dmc->wait_flush_queue); + init_waitqueue_head(&dmc->wait_io_done_queue); + + dmc->disk_region.bdev = get_disk_bdev(dmc); + dmc->disk_region.sector = 0; + dmc->disk_region.count = 0; + + dmc->cache_region.bdev = get_cache_bdev(dmc); + dmc->cache_region.sector = 0; + dmc->cache_region.count = 0; + +#ifdef MY_ABC_HERE +#else + /* for flush disk bio */ + spin_lock_init(&dmc->disk_flush_lock); + dmc->disk_flushing = 0; + dmc->flush_bio = bio_alloc_bioset(GFP_NOIO, 0, pcache_bio_set); + *bio_bi_sector_ptr(dmc->flush_bio) = 0; + *bio_bi_size_ptr(dmc->flush_bio) = 0; + INIT_LIST_HEAD(&dmc->disk_flush_queue1); + INIT_LIST_HEAD(&dmc->disk_flush_queue2); + dmc->disk_flush_pending_queue = &dmc->disk_flush_queue1; + dmc->disk_flush_unused_queue = &dmc->disk_flush_queue2; + dmc->disk_flush_io_queue = NULL; + INIT_WORK(&dmc->flush_work, send_disk_flush_bio); + INIT_WORK(&dmc->disk_flush_io_queue_work, process_disk_flush_io_queue); + + /* for flush cache bio */ + spin_lock_init(&dmc->md_flush_lock); + dmc->md_flushing = 0; + dmc->md_flush_bio = bio_alloc_bioset(GFP_NOIO, 0, pcache_bio_set); + *bio_bi_sector_ptr(dmc->md_flush_bio) = 0; + *bio_bi_size_ptr(dmc->md_flush_bio) = 0; + INIT_LIST_HEAD(&dmc->md_flush_queue1); + INIT_LIST_HEAD(&dmc->md_flush_queue2); + dmc->md_flush_pending_queue = &dmc->md_flush_queue1; + dmc->md_flush_unused_queue = &dmc->md_flush_queue2; + dmc->md_flush_io_queue = NULL; + INIT_WORK(&dmc->md_flush_work, send_md_flush_bio); + INIT_WORK(&dmc->md_flush_io_queue_work, process_md_flush_io_queue); +#endif /* ! MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!dummy_mode_to_enable) { + atomic_set(&dmc->num_master_io, 0); + init_waitqueue_head(&dmc->wait_for_cache_disable_queue); + init_waitqueue_head(&dmc->wait_old_ios_completed_queue); + } +#endif /* MY_ABC_HERE */ + +#ifdef CONFIG_SYNO_DATA_CORRECTION + dmc->correction_list = kzalloc(sizeof(struct correction_entry), GFP_KERNEL); + if (TEST_CORRECTION_LIST_ALLOC_FAIL == global_tester) { + sprint("Simulate correction list allocate fail"); + global_tester = 0; + kfree(dmc->correction_list); + dmc->correction_list = NULL; + } + if (!dmc->correction_list) { + serr("Allocate dmc correction list failed"); + r = -ENOMEM; + goto bad3; + } + INIT_LIST_HEAD(&dmc->correction_list->link); + + spin_lock_init(&dmc->corretion_spin_lock); +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + +#ifdef MY_ABC_HERE + dmc->limits.writeback_err = LIMIT_WRITEBACK_ERR; + dmc->limits.writeback_sync_err = LIMIT_WRITEBACK_SYNC_ERR; + dmc->limits.do_pending_err = LIMIT_DO_PENDING_ERR; + dmc->limits.dirty_inval = LIMIT_DIRTY_INVAL; + dmc->limits.uncached_io = LIMIT_UNCACHED_IO; + dmc->limits.md_io_error = LIMIT_MD_IO_ERROR; +#endif + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + quickflush_schedule_wb_work(dmc); + } +#endif + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + /* RO need not to be throttled */ + dmc->new_mu.allow_throtl = 1; + } +#endif + +#ifdef MY_ABC_HERE + if (NULL == dmc_group_add(dmc)) { + serr("Failed to add dmc to dmc_group"); + goto bad3; + } +#endif + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + cache_schedule_delayed_work(&dmc->new_mu.dwork, dmc->new_mu.sysctl_mu_check_itvl_sec * HZ); + } +#endif + + // NOTE: most be the last step to do + down_write(&dmc->ioctl_rwsem); + dmc->cache_state = CACHE_ENABLED; + up_write(&dmc->ioctl_rwsem); + + sprint("Create finish"); + r = 0; +end: + return r; + +bad3: + if (dmc) { +#ifdef MY_ABC_HERE + if (dmc->pbitmap_ranges) { + vfree(dmc->pbitmap_ranges); + dmc->pbitmap_ranges = NULL; + } +#endif +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + free_online_quickflush(dmc); + } +#endif + + if (procfs_created) { + flashcache_dtr_procfs(dmc); + procfs_created = 0; + } + + if (dmc->cache) { + vfree(dmc->cache); + dmc->cache = NULL; + } + if (dmc->cache_sets) { + vfree(dmc->cache_sets); + dmc->cache_sets = NULL; + } + if (dmc->md_blocks_buf) { + vfree(dmc->md_blocks_buf); + dmc->md_blocks_buf = NULL; + } +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (dmc->correction_list) { + kfree(dmc->correction_list); + dmc->correction_list = NULL; + } +#endif + dm_put_device(ti, dmc->cache_dev); + if (dummy_mode_to_enable) { + dmc->cache_dev = NULL; + } +#ifdef MY_ABC_HERE +#else + if (dmc->flush_bio) { + bio_put(dmc->flush_bio); + dmc->flush_bio = NULL; // should be freed, set it to NULL + } + if (dmc->md_flush_bio) { + bio_put(dmc->md_flush_bio); + dmc->md_flush_bio = NULL; // should be freed, set it to NULL + } +#endif +#ifdef MY_ABC_HERE + if (dmc->dmcg) { +#ifdef MY_ABC_HERE + if (dmc->new_mu.inited) { + syno_mu_disable_dmcg_throtl(dmc); + } +#endif + dmc_group_remove(dmc); + } +#endif + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + free_new_md_update(&dmc->new_mu); + } +#endif + if (dmc->node && !dummy_mode_to_enable) { + dmc_list_remove(dmc->id, dmc); + } + } +bad2: + if (dmc) { +#ifdef MY_ABC_HERE + if (dummy_mode_to_enable) { + // no need to free disk dev + } else { + dm_put_device(ti, dmc->disk_dev); + } +#else + dm_put_device(ti, dmc->disk_dev); +#endif /* MY_ABC_HERE */ + } +bad1: + if (dmc) { +#ifdef MY_ABC_HERE + if (dummy_mode_to_enable) { + reset_dmc_fields_for_dummy_mode(dmc); + dmc->cache_mode = FLASHCACHE_DUMMY; + } else { + vfree(dmc); + } +#else + kfree(dmc); +#endif /* MY_ABC_HERE */ + } +bad: + if (jp_required) { + job_pool_release(); + } + serr("Failed to create or init dmc"); + VERIFY_WARN(r); + return r; +} + +static void +flashcache_dtr_stats_print(struct cache_c *dmc) +{ + int read_hit_pct, write_hit_pct, dirty_write_hit_pct; + struct flashcache_stats *stats = &dmc->flashcache_stats; + struct flashcache_errors *errors = &dmc->flashcache_errors; + u_int64_t cache_pct, dirty_pct; + char *cache_mode; + int i; + + if (atomic64_read(&stats->reads) > 0) + read_hit_pct = compatible_div(atomic64_read(&stats->read_hits) * 100, atomic64_read(&stats->reads)); + else + read_hit_pct = 0; + if (atomic64_read(&stats->writes) > 0) { + write_hit_pct = compatible_div(atomic64_read(&stats->write_hits) * 100, atomic64_read(&stats->writes)); + dirty_write_hit_pct = compatible_div(atomic64_read(&stats->dirty_write_hits) * 100, atomic64_read(&stats->writes)); + } else { + write_hit_pct = 0; + dirty_write_hit_pct = 0; + } + + DMINFO("stats: \n\treads(%lld), writes(%lld)", + (long long)atomic64_read(&stats->reads), + (long long)atomic64_read(&stats->writes)); + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + DMINFO("\tread hits(%lld), read hit percent(%d)\n" \ + "\twrite hits(%lld) write hit percent(%d)\n" \ + "\tdirty write hits(%lld) dirty write hit percent(%d)\n" \ + "\treplacement(%lld), write replacement(%lld)\n" \ + "\twrite invalidates(%lld), read invalidates(%lld)\n" , + (long long)atomic64_read(&stats->read_hits), read_hit_pct, + (long long)atomic64_read(&stats->write_hits), write_hit_pct, + (long long)atomic64_read(&stats->dirty_write_hits), dirty_write_hit_pct, + (long long)atomic64_read(&stats->replace), (long long)atomic64_read(&stats->wr_replace), + (long long)atomic64_read(&stats->wr_invalidates), (long long)atomic64_read(&stats->rd_invalidates)); +#ifdef FLASHCACHE_DO_CHECKSUMS + DMINFO("\tchecksum store(%lld), checksum valid(%lld), checksum invalid(%lld)\n", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + DMINFO("\tpending enqueues(%lld), pending inval(%lld)\n" \ + "\tmetadata dirties(%lld), metadata cleans(%lld)\n" \ + "\tmetadata batch(%lld) metadata ssd writes(%lld)\n" \ + "\tcleanings(%lld) fallow cleanings(%lld)\n" \ + "\tno room(%lld) front merge(%lld) back merge(%lld)\n", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval), + (long long)atomic64_read(&stats->md_write_dirty), (long long)atomic64_read(&stats->md_write_clean), + (long long)atomic64_read(&stats->md_write_batch), (long long)atomic64_read(&stats->md_ssd_writes), + (long long)atomic64_read(&stats->cleanings), (long long)atomic64_read(&stats->fallow_cleanings), + (long long)atomic64_read(&stats->noroom), (long long)atomic64_read(&stats->front_merge), (long long)atomic64_read(&stats->back_merge)); + } else if (dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) { + DMINFO("\tread hits(%lld), read hit percent(%d)\n" \ + "\twrite hits(%lld) write hit percent(%d)\n" \ + "\treplacement(%lld)\n" \ + "\twrite invalidates(%lld), read invalidates(%lld)\n", + (long long)atomic64_read(&stats->read_hits), read_hit_pct, + (long long)atomic64_read(&stats->write_hits), write_hit_pct, + (long long)atomic64_read(&stats->replace), + (long long)atomic64_read(&stats->wr_invalidates), (long long)atomic64_read(&stats->rd_invalidates)); +#ifdef FLASHCACHE_DO_CHECKSUMS + DMINFO("\tchecksum store(%lld), checksum valid(%lld), checksum invalid(%lld)\n", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + DMINFO("\tpending enqueues(%lld), pending inval(%lld)\n" \ + "\tno room(%lld)\n", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval), + (long long)atomic64_read(&stats->noroom)); + } else { /* WRITE_AROUND */ + DMINFO("\tread hits(%lld), read hit percent(%d)\n" \ + "\treplacement(%lld)\n" \ + "\tinvalidates(%lld)\n", + (long long)atomic64_read(&stats->read_hits), read_hit_pct, + (long long)atomic64_read(&stats->replace), + (long long)atomic64_read(&stats->rd_invalidates)); +#ifdef FLASHCACHE_DO_CHECKSUMS + DMINFO("\tchecksum store(%lld), checksum valid(%lld), checksum invalid(%lld)\n", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + DMINFO("\tpending enqueues(%lld), pending inval(%lld)\n" \ + "\tno room(%lld)\n", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval), + (long long)atomic64_read(&stats->noroom)); + } + /* All modes */ + DMINFO("\tdisk reads(%lld), disk writes(%lld) ssd reads(%lld) ssd writes(%lld)\n" \ + "\tuncached reads(%lld), uncached writes(%lld), uncached IO requeue(%lld)\n" \ + "\tdisk read errors(%d), disk write errors(%d) ssd read errors(%d) ssd write errors(%d)\n" \ + "\tuncached sequential reads(%lld), uncached sequential writes(%lld)\n" \ + "\tpid_adds(%lld), pid_dels(%lld), pid_drops(%lld) pid_expiry(%lld)", + (long long)atomic64_read(&stats->disk_reads), + (long long)atomic64_read(&stats->disk_writes), + (long long)atomic64_read(&stats->ssd_reads), (long long)atomic64_read(&stats->ssd_writes), + (long long)atomic64_read(&stats->uncached_reads), (long long)atomic64_read(&stats->uncached_writes), (long long)atomic64_read(&stats->uncached_io_requeue), + atomic_read(&errors->disk_read_errors), atomic_read(&errors->disk_write_errors), + atomic_read(&errors->ssd_read_errors), atomic_read(&errors->ssd_write_errors), + (long long)atomic64_read(&stats->uncached_sequential_reads), + (long long)atomic64_read(&stats->uncached_sequential_writes), + (long long)atomic64_read(&stats->pid_adds), (long long)atomic64_read(&stats->pid_dels), (long long)atomic64_read(&stats->pid_drops), (long long)atomic64_read(&stats->expiry)); +#ifdef MY_ABC_HERE + DMINFO("\n\twrite miss ssd(%lld)", + (long long)atomic64_read(&stats->wr_miss_ssd)); +#endif + if (dmc->size > 0) { +#ifdef EC_EMULATE_U64_DIVISION + dirty_pct = div64_u64((u_int64_t)dmc->nr_dirty * 100, dmc->size); + cache_pct = div64_u64((u_int64_t)atomic64_read(&dmc->cached_blocks) * 100, dmc->size); +#else + dirty_pct = ((u_int64_t)dmc->nr_dirty * 100) / dmc->size; + cache_pct = ((u_int64_t)atomic64_read(&dmc->cached_blocks) * 100) / dmc->size; +#endif + } else { + cache_pct = 0; + dirty_pct = 0; + } + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) + cache_mode = "WRITE_BACK"; + else if (dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) + cache_mode = "WRITE_THROUGH"; + else + cache_mode = "WRITE_AROUND"; + DMINFO("conf:\n" \ + "\tvirt dev (%s), ssd dev (%s), disk dev (%s) cache mode(%s)\n" \ + "\tcapacity(%lluM), associativity(%u), data block size(%uK) metadata block size(%ub)\n" \ + "\tskip sequential thresh(%uK)\n" \ + "\ttotal blocks(%llu), cached blocks(%lld), cache percent(%d)\n" \ + "\tdirty blocks(%d), dirty percent(%d)\n", + dmc->dm_vdevname, dmc->cache_devname, dmc->disk_devname, + cache_mode, + (u64)dmc->size*dmc->block_size>>11, dmc->assoc, + dmc->block_size>>(10-SECTOR_SHIFT), + dmc->md_block_size * 512, + dmc->sysctl_skip_seq_thresh_kb, + (u64)dmc->size, (long long)atomic64_read(&dmc->cached_blocks), + (int)cache_pct, dmc->nr_dirty, (int)dirty_pct); + + DMINFO("\tnr_queued(%lu)\n", dmc->pending_jobs_count); + DMINFO("Size Hist: "); +#ifdef MY_ABC_HERE + for (i = 1 ; i <= ((sizeof(size_hist)/sizeof(size_hist[0])) - 1) ; i++) { + if (size_hist[i] > 0) { + DMINFO("%d:%llu ", i*512, size_hist[i]); + } + } +#else + for (i = 1 ; i <= 32 ; i++) { + if (size_hist[i] > 0) + DMINFO("%d:%llu ", i*512, size_hist[i]); + } +#endif +} + +#ifdef MY_ABC_HERE +fmode_t get_disk_mode(struct cache_c *dmc) +{ + unsigned long flags = 0; + fmode_t mode = 0; + + // Use lock to prevent the dmc->disk_dev is reallocated during expansion + spin_lock_irqsave(&dmc->dev_lock, flags); + mode = dmc->disk_dev->mode; + spin_unlock_irqrestore(&dmc->dev_lock, flags); + + return mode; +} + +/* + * WARNING: + * disk_dev / cache_dev might be replaced on expansion + * Use get_cache_dev() / get_disk_bdev() instead of disk_dev->bdev + */ +struct block_device *get_cache_bdev(struct cache_c *dmc) +{ + return dmc->cache_bdev; +} + +struct block_device *get_disk_bdev(struct cache_c *dmc) +{ + return dmc->disk_bdev; +} + +#endif + + +#ifdef MY_ABC_HERE +static void +handle_table_reload_at_dtr(struct dm_target *ti) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + unsigned long flags = 0; + struct dm_dev *ori_disk_dev = NULL; + struct dm_dev *ori_cache_dev = NULL; + + sdbg(DF_RELOAD_TABLE, "In reloading table, don't destory anything"); + + ori_disk_dev = dmc->disk_dev; + ori_cache_dev = dmc->cache_dev; + + spin_lock_irqsave(&dmc->dev_lock, flags); + // Just put devices for old dm_target + // Set to new dm_devs + dmc->disk_dev = dmc->disk_dev_reload; + dmc->disk_dev_reload = NULL; +#ifdef MY_ABC_HERE + if (CACHE_DISABLED != dmc->cache_state) { + dmc->cache_dev = dmc->cache_dev_reload; + dmc->cache_dev_reload = NULL; + } +#else + dmc->cache_dev = dmc->cache_dev_reload; + dmc->cache_dev_reload = NULL; +#endif + spin_unlock_irqrestore(&dmc->dev_lock, flags); + + dm_put_device(ti, ori_disk_dev); + if (CACHE_DISABLED != dmc->cache_state) { + dm_put_device(ti, ori_cache_dev); + } + + dmc->disk_devsize = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + + // Finish the reload operation + sdbg(DF_RELOAD_TABLE, "Set dmc->reload_table = 0"); + spin_lock_irqsave(&dmc->reload_lock, flags); + dmc->reload_table = 0; + spin_unlock_irqrestore(&dmc->reload_lock, flags); + sdbg(DF_RELOAD_TABLE, "Reloading finish"); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void +destroy_in_dummy_mode(struct dm_target *ti) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + struct cache_c **nodepp; + + // Only occupy disk_dev & allocate dmc in this mode + dm_put_device(ti, dmc->disk_dev); + + (void)wait_on_bit_lock_wrapper(&flashcache_control->synch_flags, + FLASHCACHE_UPDATE_LIST, + flashcache_wait_schedule, + TASK_UNINTERRUPTIBLE); + // SYNO: Remove cache from the cache list + nodepp = &cache_list_head; + while (*nodepp != NULL) { + if (*nodepp == dmc) { + *nodepp = dmc->next_cache; + break; + } + nodepp = &((*nodepp)->next_cache); + } + clear_bit(FLASHCACHE_UPDATE_LIST, &flashcache_control->synch_flags); + smp_mb__after_clear_bit_wrapper(); + wake_up_bit(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST); + + if (dmc_list_remove(dmc->id, dmc)) { + serr("Can't find dmc with id %s to remove", dmc->id); + } + + vfree(dmc); +} + +static void +reset_dmc_fields_for_dummy_mode(struct cache_c *dmc) +{ + // Reset data starting at the reset point + memset(&dmc->point_to_reset, 0, sizeof(struct cache_c) - ((unsigned char *)&dmc->point_to_reset - (unsigned char *)dmc)); + + // Reset ssd dev name + snprintf(dmc->cache_devname, sizeof(dmc->cache_devname), "none"); + dmc->init_nr_dirty = -1; +} + +static void +free_dmc_resources_for_disable(struct dm_target *ti, disable_type_t disable_type) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + int i = 0; + int nr_queued = 0; + + if (DISABLE_FORCE != disable_type) { + VERIFY_WARN(0 == dmc->nr_dirty); + } + + dmc->sysctl_syno_latency_diagnose = 0; + del_timer_sync(&dmc->latency_timer); + + // Destroy proc & sysctl + flashcache_dtr_procfs(dmc); + + // Partial Steps in destory() + DMINFO("cache jobs %d, pending jobs %d", atomic_read(&nr_cache_jobs), + atomic_read(&nr_pending_jobs)); + for (i = 0 ; i < dmc->size ; i++) + nr_queued += dmc->cache[i].nr_queued; + DMINFO("cache queued jobs %d", nr_queued); + flashcache_dtr_stats_print(dmc); + +#ifdef MY_ABC_HERE + dmc_group_remove(dmc); +#endif + + // Free dynamic resource + vfree((void *)dmc->cache); + vfree((void *)dmc->cache_sets); + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { +#ifdef MY_ABC_HERE + free_online_quickflush(dmc); +#endif +#ifdef MY_ABC_HERE + free_new_md_update(&dmc->new_mu); +#endif + vfree((void *)dmc->md_blocks_buf); + } + + flashcache_del_all_pids(dmc, FLASHCACHE_WHITELIST, 1); + flashcache_del_all_pids(dmc, FLASHCACHE_BLACKLIST, 1); + VERIFY(dmc->num_whitelist_pids == 0); + VERIFY(dmc->num_blacklist_pids == 0); + +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (dmc->correction_list) { + kfree(dmc->correction_list); + dmc->correction_list = NULL; + } +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { +#ifdef MY_ABC_HERE + if (dmc->pbitmap_ranges) { + vfree(dmc->pbitmap_ranges); + } +#endif + } + + // Only release cache device + dm_put_device(ti, dmc->cache_dev); + +#ifdef MY_ABC_HERE +#else + bio_put(dmc->flush_bio); + bio_put(dmc->md_flush_bio); +#endif /* MY_ABC_HERE */ + + reset_dmc_fields_for_dummy_mode(dmc); + + // No need to remove dmc from dmc_list +} +#endif /* MY_ABC_HERE */ + +/* + * Destroy the cache mapping. + */ +void +flashcache_dtr(struct dm_target *ti) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + struct cache_c **nodepp; + int i; + int nr_queued = 0; + +#ifdef MY_ABC_HERE + if (dmc->reload_table) { + handle_table_reload_at_dtr(ti); + return; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // TODO: Handle disable / enable with shutdown at the same time? + if ((CACHE_ENABLED != dmc->cache_state) && (CACHE_DISABLED != dmc->cache_state)) { + serr("Cache state (%d) is not in enabled or disabled states, can't destroy cache mapping", + dmc->cache_state); + return; + } + + if (CACHE_DISABLED == dmc->cache_state) { + destroy_in_dummy_mode(ti); + return; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // Let the proc entry be removed later for showing the flush progress +#else + flashcache_dtr_procfs(dmc); +#endif + + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + sprint("sync for remove"); + flashcache_sync_for_remove(dmc); +#ifdef MY_ABC_HERE + if (1 == dmc->bypass_cache) { + DMERR("flashcache: Due to the cache is crashed, don't write back metadata to it"); + } else { +#ifdef MY_ABC_HERE + /* Clear all md update in progress */ + syno_mu_flush_all_for_remove_sync(dmc); +#endif + sprint("save metadata to ssd"); + flashcache_writeback_md_store(dmc); + } +#else + flashcache_writeback_md_store(dmc); +#endif + } + + dmc->sysctl_syno_latency_diagnose = 0; + del_timer_sync(&dmc->latency_timer); + +#ifdef MY_ABC_HERE + sprint("destroy proc entries and status"); + flashcache_dtr_procfs(dmc); +#endif + + if (!dmc->sysctl_fast_remove && dmc->nr_dirty > 0) + DMERR("Could not sync %d blocks to disk, cache still dirty", + dmc->nr_dirty); + DMINFO("cache jobs %d, pending jobs %d", atomic_read(&nr_cache_jobs), + atomic_read(&nr_pending_jobs)); + for (i = 0 ; i < dmc->size ; i++) + nr_queued += dmc->cache[i].nr_queued; + DMINFO("cache queued jobs %d", nr_queued); + + flashcache_dtr_stats_print(dmc); +#ifdef MY_ABC_HERE + dmc_group_remove(dmc); +#endif + + vfree((void *)dmc->cache); + vfree((void *)dmc->cache_sets); + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) + vfree((void *)dmc->md_blocks_buf); + flashcache_del_all_pids(dmc, FLASHCACHE_WHITELIST, 1); + flashcache_del_all_pids(dmc, FLASHCACHE_BLACKLIST, 1); + VERIFY_WARN(dmc->num_whitelist_pids == 0); + VERIFY_WARN(dmc->num_blacklist_pids == 0); + sprint("start to put devices"); + dm_put_device(ti, dmc->disk_dev); + dm_put_device(ti, dmc->cache_dev); + + sprint("wait on synch flags"); + (void)wait_on_bit_lock_wrapper(&flashcache_control->synch_flags, + FLASHCACHE_UPDATE_LIST, + flashcache_wait_schedule, + TASK_UNINTERRUPTIBLE); + // SYNO: Remove cache from the cache list + nodepp = &cache_list_head; + while (*nodepp != NULL) { + if (*nodepp == dmc) { + *nodepp = dmc->next_cache; + break; + } + nodepp = &((*nodepp)->next_cache); + } + sprint("continue to destroy"); + clear_bit(FLASHCACHE_UPDATE_LIST, &flashcache_control->synch_flags); + smp_mb__after_clear_bit_wrapper(); + wake_up_bit(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST); + + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { +#ifdef MY_ABC_HERE + free_online_quickflush(dmc); +#endif +#ifdef MY_ABC_HERE + free_new_md_update(&dmc->new_mu); +#endif + vfree(dmc->pbitmap_ranges); + } +#endif +#ifdef MY_ABC_HERE + if (dmc_list_remove(dmc->id, dmc)) { + serr("Can't find dmc with id %s to remove", dmc->id); + } +#endif + +#ifdef MY_ABC_HERE +#else +#ifdef MY_ABC_HERE + bio_put(dmc->flush_bio); + bio_put(dmc->md_flush_bio); +#endif +#endif + vfree(dmc); +#ifdef MY_ABC_HERE + job_pool_release(); +#endif + sprint("Destroy finish"); +} + +void +flashcache_status_info(struct cache_c *dmc, status_type_t type, + char *result, unsigned int maxlen) +{ + int read_hit_pct, write_hit_pct, dirty_write_hit_pct; + int sz = 0; /* DMEMIT */ + struct flashcache_stats *stats = &dmc->flashcache_stats; + struct flashcache_errors *errors = &dmc->flashcache_errors; +#ifdef MY_ABC_HERE + plug_wb_t *plug_wb = &dmc->plug_wb; +#endif +#ifdef MY_ABC_HERE + new_mu_t *mu = &dmc->new_mu; +#endif + + if (atomic64_read(&stats->reads) > 0) + read_hit_pct = compatible_div(atomic64_read(&stats->read_hits) * 100, atomic64_read(&stats->reads)); + else + read_hit_pct = 0; + if (atomic64_read(&stats->writes) > 0) { + write_hit_pct = compatible_div(atomic64_read(&stats->write_hits) * 100, atomic64_read(&stats->writes)); + dirty_write_hit_pct = compatible_div(atomic64_read(&stats->dirty_write_hits) * 100, atomic64_read(&stats->writes)); + } else { + write_hit_pct = 0; + dirty_write_hit_pct = 0; + } + DMEMIT("stats: \n\treads(%lld), writes(%lld)\n", + (long long)atomic64_read(&stats->reads), + (long long)atomic64_read(&stats->writes)); + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + DMEMIT("\tread hits(%lld), read hit percent(%d)\n" + "\twrite hits(%lld) write hit percent(%d)\n" + "\tdirty write hits(%lld) dirty write hit percent(%d)\n" + "\treplacement(%lld), write replacement(%lld)\n" + "\twrite invalidates(%lld), read invalidates(%lld)\n", + (long long)atomic64_read(&stats->read_hits), read_hit_pct, + (long long)atomic64_read(&stats->write_hits), write_hit_pct, + (long long)atomic64_read(&stats->dirty_write_hits), dirty_write_hit_pct, + (long long)atomic64_read(&stats->replace), (long long)atomic64_read(&stats->wr_replace), + (long long)atomic64_read(&stats->wr_invalidates), (long long)atomic64_read(&stats->rd_invalidates)); +#ifdef FLASHCACHE_DO_CHECKSUMS + DMEMIT("\tchecksum store(%lld), checksum valid(%lld), checksum invalid(%lld)\n", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + DMEMIT("\tpending enqueues(%lld), pending inval(%lld)\n" + "\tmetadata dirties(%lld), metadata cleans(%lld)\n" + "\tmetadata batch(%lld) metadata ssd writes(%lld)\n" + "\tcleanings(%lld) fallow cleanings(%lld)\n" + "\tno room(%lld) front merge(%lld) back merge(%lld)\n", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval), + (long long)atomic64_read(&stats->md_write_dirty), (long long)atomic64_read(&stats->md_write_clean), + (long long)atomic64_read(&stats->md_write_batch), (long long)atomic64_read(&stats->md_ssd_writes), + (long long)atomic64_read(&stats->cleanings), (long long)atomic64_read(&stats->fallow_cleanings), + (long long)atomic64_read(&stats->noroom), (long long)atomic64_read(&stats->front_merge), (long long)atomic64_read(&stats->back_merge)); + } else if (dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) { + DMEMIT("\tread hits(%lld), read hit percent(%d)\n" + "\twrite hits(%lld) write hit percent(%d)\n" + "\treplacement(%lld), write replacement(%lld)\n" + "\twrite invalidates(%lld), read invalidates(%lld)\n", + (long long)atomic64_read(&stats->read_hits), read_hit_pct, + (long long)atomic64_read(&stats->write_hits), write_hit_pct, + (long long)atomic64_read(&stats->replace), (long long)atomic64_read(&stats->wr_replace), + (long long)atomic64_read(&stats->wr_invalidates), (long long)atomic64_read(&stats->rd_invalidates)); +#ifdef FLASHCACHE_DO_CHECKSUMS + DMEMIT("\tchecksum store(%lld), checksum valid(%lld), checksum invalid(%lld)\n", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + DMEMIT("\tpending enqueues(%lld), pending inval(%lld)\n" + "\tno room(%lld)\n", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval), + (long long)atomic64_read(&stats->noroom)); + } else { /* WRITE_AROUND */ + DMEMIT("\tread hits(%lld), read hit percent(%d)\n" + "\treplacement(%lld), write replacement(%lld)\n" + "\tinvalidates(%lld)\n", + (long long)atomic64_read(&stats->read_hits), read_hit_pct, + (long long)atomic64_read(&stats->replace), (long long)atomic64_read(&stats->wr_replace), + (long long)atomic64_read(&stats->rd_invalidates)); +#ifdef FLASHCACHE_DO_CHECKSUMS + DMEMIT("\tchecksum store(%lld), checksum valid(%lld), checksum invalid(%lld)\n", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + DMEMIT("\tpending enqueues(%lld), pending inval(%lld)\n" + "\tno room(%lld)\n", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval), + (long long)atomic64_read(&stats->noroom)); + } + /* All modes */ + DMEMIT("\tdisk reads(%lld), disk writes(%lld) ssd reads(%lld) ssd writes(%lld)\n" + "\tuncached reads(%lld), uncached writes(%lld), uncached IO requeue(%lld)\n" + "\tdisk read errors(%d), disk write errors(%d) ssd read errors(%d) ssd write errors(%d)\n" + "\tuncached sequential reads(%lld), uncached sequential writes(%lld)\n" + "\tpid_adds(%lld), pid_dels(%lld), pid_drops(%lld) pid_expiry(%lld)", + (long long)atomic64_read(&stats->disk_reads), + (long long)atomic64_read(&stats->disk_writes), + (long long)atomic64_read(&stats->ssd_reads), (long long)atomic64_read(&stats->ssd_writes), + (long long)atomic64_read(&stats->uncached_reads), (long long)atomic64_read(&stats->uncached_writes), (long long)atomic64_read(&stats->uncached_io_requeue), + atomic_read(&errors->disk_read_errors), atomic_read(&errors->disk_write_errors), + atomic_read(&errors->ssd_read_errors), atomic_read(&errors->ssd_write_errors), + (long long)atomic64_read(&stats->uncached_sequential_reads), + (long long)atomic64_read(&stats->uncached_sequential_writes), + (long long)atomic64_read(&stats->pid_adds), (long long)atomic64_read(&stats->pid_dels), (long long)atomic64_read(&stats->pid_drops), (long long)atomic64_read(&stats->expiry)); +#ifdef MY_ABC_HERE + DMEMIT("\n\twrite miss ssd(%lld)", + (long long)atomic64_read(&stats->wr_miss_ssd)); +#endif +#ifdef MY_ABC_HERE + DMEMIT("\n\tdirty writeback kb(%lld), dirty writeback sync kb(%lld)", + compatible_div((long long)atomic64_read(&stats->dirty_writeback_sector), 2), + compatible_div((long long)atomic64_read(&stats->dirty_writeback_sync_sector), 2)); +#endif +#ifdef MY_ABC_HERE + DMEMIT("\n\t==== Internal Diagnosis ====\n" + "\tRead hit statistics:\n" + "\tpending preread(%lld)\n" + "\tmatch none read disk(%lld) busy in io(%lld) busy wait queue(%lld)\n" + "\tmatch partial: total(%lld) check write ssd(%lld) \n" + "\tWrite hit statistics: \n" + "\tbusy inval(%lld)\n" + "\tdo pending write back(%lld)\n" + "\tmap skip_unaligned_io(%lld)\n" + "\tdirty_writeback(%lld)\n" +#ifdef MY_ABC_HERE +#else + "\tcleanings_over_threshold(%lld)\n" + "\tcleanings_total(%lld)\n" +#endif + "\tprereads(%lld)\n" + "\tcurrent job_mem_cnt(%d) job mem get in(%lld) job mem get out(%lld)\n", + (long long)atomic64_read(&stats->pending_preread), + (long long)atomic64_read(&stats->read_hit_match_none_read_disk), + (long long)atomic64_read(&stats->read_hit_busy_in_io), (long long)atomic64_read(&stats->read_hit_busy_wait_queue), + (long long)atomic64_read(&stats->read_hit_match_partial), + (long long)atomic64_read(&stats->read_hit_check_write_ssd), + (long long)atomic64_read(&stats->write_hit_busy_inval), + (long long)atomic64_read(&stats->do_pending_no_error_drity_writeback), + (long long)atomic64_read(&stats->skip_unaligned_io), + (long long)atomic64_read(&stats->dirty_writeback_start), // Do not remove to keep format +#ifdef MY_ABC_HERE +#else + (long long)atomic64_read(&stats->cleanings_over_threshold), + (long long)atomic64_read(&stats->clean_set_ios), +#endif + (long long)atomic64_read(&stats->prereads), + job_mem_count, (long long)atomic64_read(&stats->job_mem_get_in), + (long long)atomic64_read(&stats->job_mem_get_out) + ); +#endif +#ifdef MY_ABC_HERE + DMEMIT("\tnum_uncached_write(%d) num_write_cache(%d) num_flush_bio(%d)\n" + "\tinval dirty writeback(%lld)\n" + "\twrite miss invalidate(%lld)\n" + "\tmap_inval(%lld) uncacheable_inval(%lld) do_pending_no_error_inval(%lld)\n" + "\tpending enqueue inval(%lld) pending enqueue inval handled(%lld)\n" + "\tdisk flush start(%lld) disk flush done(%lld)\n" + "\tcache flush start(%lld) cache flush done(%lld)\n" + "\tdirty writeback start(%lld) dirty writeback done(%lld)\n" + "\tmaster bio in processing(%d)\n", + atomic_read(&dmc->num_uncached_write), + atomic_read(&dmc->num_write_cache), + atomic_read(&dmc->num_flush_bio), + (long long)atomic64_read(&stats->inval_dirty_writeback), + (long long)atomic64_read(&stats->write_miss_inval), + (long long)atomic64_read(&stats->map_inval), (long long)atomic64_read(&stats->uncacheable_inval), + (long long)atomic64_read(&stats->do_pending_no_error_inval), + (long long)atomic64_read(&stats->pending_enqueue_inval_start), + (long long)atomic64_read(&stats->pending_enqueue_inval_done), + (long long)atomic64_read(&stats->disk_flush_start), + (long long)atomic64_read(&stats->disk_flush_done), + (long long)atomic64_read(&stats->md_flush_start), + (long long)atomic64_read(&stats->md_flush_done), + (long long)atomic64_read(&stats->dirty_writeback_start), + (long long)atomic64_read(&stats->dirty_writeback_done), + atomic_read(&dmc->num_master_io)); +#ifdef MY_ABC_HERE + DMEMIT("\tfallow blocks(%d) fallow bits unset(%lld) nr writes(%lld)\n" + "\tbits mismatch(%lld) jobs(%d)\n" + "\tssd wb in progress(%d) disk wb in progress(%d)\n" + "\twb seq(%llu) batch head(%llu) batch len(%d) unfinished read in batch(%d)\n" + "\toqf trigger count(%d) sync trigger count(%d) synced count(%d)\n" +#ifdef MY_ABC_HERE + "\tmd io inprog normal(%d) force(%d) flush(%d) throtl(%d)\n" + "\tmd io sent normal(%d force(%d) flush(%d) throtl(%d)\n" + "\tsend md io cnt(%d) md io callback cnt(%d)\n" + "\tsend md io in queue(%d) md io to queue(%d)\n" + "\tmu flush valid(%d) mu flush pending(%d)\n" + "\tmu no flush valid(%d) mu no flush pending(%d) mu io waiting (%d)\n" + "\tmu throtl self(%d) mu throtl help(%d)\n" + "\tdmcg rebalance cnt(%d) dmcg num io(%d) dmcg io pending(%d)\n" +#endif + , + atomic_read(&dmc->oqf.nr_fallow), + (long long) atomic64_read(&stats->qf_fallow_bits_unset), + (long long) atomic64_read(&stats->qf_nr_writes), + (long long) atomic64_read(&stats->qf_bits_mismatch), + atomic_read(&dmc->nr_jobs), + plug_wb->ssd_read_inprog, plug_wb->disk_write_inprog, + plug_wb->seq, plug_wb->cur_batch_head, plug_wb->cur_batch_len, plug_wb->unfinished_read_in_batch, + dmc->oqf.trigger_cnt, dmc->oqf.sync_trigger_cnt, dmc->nr_synced +#ifdef MY_ABC_HERE + , + mu->md_io_inprog_normal, mu->md_io_inprog_force, + mu->md_io_inprog_ext_flush, mu->md_io_inprog_throtl, + mu->sent_md_io_normal_cnt, mu->sent_md_io_force_cnt, + mu->sent_md_io_ext_flush_cnt, mu->sent_md_io_throtl_cnt, + atomic_read(&mu->send_md_io_cnt), atomic_read(&mu->md_io_callback_cnt), + atomic_read(&mu->md_io_in_queue), atomic_read(&mu->md_io_to_queue), + mu->inprog_blk_num[MU_BLK_TYPE_FLUSH], mu->pending_blk_num[MU_BLK_TYPE_FLUSH], + mu->inprog_blk_num[MU_BLK_TYPE_NOFLUSH], mu->pending_blk_num[MU_BLK_TYPE_NOFLUSH], + mu->md_io_pending_queue_size, + atomic_read(&mu->throtl_self), atomic_read(&mu->throtl_help), + dmc->dmcg ? atomic_read(&dmc->dmcg->rebalance_cnt) : 0, // no dmcg for dummy cache + dmc->dmcg ? atomic_read(&dmc->dmcg->num_throtl_io) : 0, + dmc->dmcg ? atomic_read(&dmc->dmcg->md_io_pending_no_flush) : 0 +#endif + ); +#else + // FIXME: should be removed when original wb is removed + DMEMIT("\tclean in progress(%d)\n", + dmc->clean_inprog); +#endif +#endif + + if (dmc->sysctl_io_latency_hist) { + int i; + + DMEMIT("\nIO Latency Histogram: \n"); + for (i = 1 ; i <= IO_LATENCY_BUCKETS ; i++) { + DMEMIT("< %d\tusecs : %lu\n", i * IO_LATENCY_GRAN_USECS, dmc->latency_hist[i - 1]); + } + DMEMIT("> 10\tmsecs : %lu", dmc->latency_hist_10ms); + } +} + +static void +flashcache_status_table(struct cache_c *dmc, status_type_t type, + char *result, unsigned int maxlen) +{ + u_int64_t cache_pct, dirty_pct; + int i; + int sz = 0; /* DMEMIT */ +#ifdef MY_ABC_HERE + int support_pin = 0; +#endif + + + if (dmc->size > 0) { +#ifdef EC_EMULATE_U64_DIVISION + dirty_pct = div64_u64((u_int64_t)dmc->nr_dirty * 100, dmc->size); + cache_pct = div64_u64((u_int64_t)atomic64_read(&dmc->cached_blocks) * 100, dmc->size); +#else + dirty_pct = ((u_int64_t)dmc->nr_dirty * 100) / dmc->size; + cache_pct = ((u_int64_t)atomic64_read(&dmc->cached_blocks) * 100) / dmc->size; +#endif + } else { + cache_pct = 0; + dirty_pct = 0; + } + + DMEMIT("conf:\n"); + DMEMIT("\tssd dev (%s), disk dev (%s) cache mode(%s)\n", + dmc->cache_devname, dmc->disk_devname, + mode_to_str(dmc->cache_mode)); + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + DMEMIT("\tcapacity(%lluM), associativity(%u), data block size(%uK) metadata block size(%ub)\n", + (u64)dmc->size*dmc->block_size>>11, dmc->assoc, + dmc->block_size>>(10-SECTOR_SHIFT), + dmc->md_block_size * 512); + } else { + DMEMIT("\tcapacity(%lluM), associativity(%u), data block size(%uK)\n", + (u64)dmc->size*dmc->block_size>>11, dmc->assoc, + dmc->block_size>>(10-SECTOR_SHIFT)); + } + DMEMIT("\tskip sequential thresh(%uK)\n", + dmc->sysctl_skip_seq_thresh_kb); + DMEMIT("\ttotal blocks(%llu), cached blocks(%lld), cache percent(%d)\n", + (u64)dmc->size, (long long)atomic64_read(&dmc->cached_blocks), + (int)cache_pct); + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + DMEMIT("\tdirty blocks(%d), dirty percent(%d)\n", + dmc->nr_dirty, (int)dirty_pct); + } + DMEMIT("\tnr_queued(%lu)\n", dmc->pending_jobs_count); + +#ifdef MY_ABC_HERE + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + support_pin = 1; + } +#endif + DMEMIT("\tsplit-io(%d) support pin file(%d) version(%d)\n", dmc->max_io_len, support_pin, dmc->on_ssd_version); + + DMEMIT("Size Hist: "); +#ifdef MY_ABC_HERE + for (i = 1 ; i <= ((sizeof(size_hist)/sizeof(size_hist[0])) - 1) ; i++) { + if (size_hist[i] > 0) { + DMEMIT("%d:%llu ", i*512, size_hist[i]); + } + } + DMEMIT("\nbits_all=%lu bits_used=%lu", dmc->bits_all, dmc->bits_used); +#else + for (i = 1 ; i <= 32 ; i++) { + if (size_hist[i] > 0) + DMEMIT("%d:%llu ", i*512, size_hist[i]); + } +#endif +} + +/* + * Report cache status: + * Output cache stats upon request of device status; + * Output cache configuration upon request of table status. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) +void +flashcache_status(struct dm_target *ti, status_type_t type, + unsigned int unused_status_flags, + char *result, unsigned int maxlen) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) +int +flashcache_status(struct dm_target *ti, status_type_t type, + unsigned int unused_status_flags, + char *result, unsigned int maxlen) +#else +int +flashcache_status(struct dm_target *ti, status_type_t type, + char *result, unsigned int maxlen) +#endif +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + + switch (type) { + case STATUSTYPE_INFO: + flashcache_status_info(dmc, type, result, maxlen); + break; + case STATUSTYPE_TABLE: + flashcache_status_table(dmc, type, result, maxlen); + break; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) + return 0; +#endif +} + +#ifdef MY_DEF_HERE +static int flashcache_handle_4kn_target_support(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct cache_c *dmc = ti->private; + + return fn(ti, dmc->disk_dev, 0, ti->len, data); +} +#endif + +#ifdef MY_ABC_HERE +static int flashcache_support_noclone(struct dm_target *ti) +{ + struct cache_c *dmc = ti->private; + return (CACHE_DISABLED == dmc->cache_state); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int +flashcache_disable(struct dm_target *ti, disable_type_t disable_type) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + unsigned long flags = 0; + int ret = -1; + int cache_mode = dmc->cache_mode; + + sdbg(DF_ONLINE, "enter"); + + if (CACHE_ENABLED != dmc->cache_state) { + serr("Can only switch from cache enabled state"); + goto err; + } + + if (FLASHCACHE_WRITE_BACK == cache_mode) { + if (DISABLE_NORMAL == disable_type) { + if ((0 != dmc->sysctl_cache_all) || (0 != dmc->nr_dirty)) { + serr("Cache can't be disabled (cache_all=%d nr_dirty=%u)", + dmc->sysctl_cache_all, dmc->nr_dirty); + goto err; + } + } else if (DISABLE_FORCE == disable_type) { + sprint("Perfom force disable dirty=%u", dmc->nr_dirty); + } else { + serr("incorrect disable type = %d", disable_type); + goto err; + } + } + + down_write(&dmc->ioctl_rwsem); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (0 != atomic_read(&dmc->num_master_io)) { + dmc->cache_state = CACHE_WAIT_OLD_IOS_COMPLETED; + } else { + dmc->cache_state = CACHE_WAIT_DISABLE; + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + up_write(&dmc->ioctl_rwsem); + + /* The work shouldn't be queued at this point. But it is not guaranteed + * Add here to guarantee no work left. */ + if (FLASHCACHE_WRITE_BACK == cache_mode) { + stop_wb_works(dmc); + } + + if (CACHE_WAIT_OLD_IOS_COMPLETED == dmc->cache_state) { + + sdbg(DF_ONLINE, "wait until no master io start"); + wait_event(dmc->wait_old_ios_completed_queue, + 0 == atomic_read(&dmc->num_master_io)); + sdbg(DF_ONLINE, "wait until no master io finish"); + } + +#ifdef MY_ABC_HERE + if (FLASHCACHE_WRITE_BACK == cache_mode) { + syno_mu_flush_all_for_remove_sync(dmc); + } +#endif + + if (FLASHCACHE_WRITE_BACK == cache_mode) { + superblock_cache_state_set(dmc, CACHE_DISABLED); + } + + if (dmc->sysctl_error_inject & SIMULATE_CACHE_DISABLE_LONG_TIME) { + serr("Simulate a long disable procedure, sleep 60s"); + msleep(60*1000); + dmc->sysctl_error_inject &=~ SIMULATE_CACHE_DISABLE_LONG_TIME; + } + + set_dm_target_attribute(ti, dmc, DM_ATTR_CACHE_DISABLE); + + free_dmc_resources_for_disable(ti, disable_type); + + dmc->cache_mode = FLASHCACHE_DUMMY; + dmc->cache_state = CACHE_DISABLED; + +#ifdef MY_ABC_HERE + job_pool_release(); +#endif + + wake_up(&dmc->wait_for_cache_disable_queue); + + ret = 0; +err: + return ret; +} + +/* + * Param: + * enable + * disable force(0|1) + */ +static int +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +flashcache_message(struct dm_target *ti, unsigned argc, char **argv, char *result, unsigned maxlen) +#else +flashcache_message(struct dm_target *ti, unsigned argc, char **argv) +#endif +{ + struct cache_c *dmc = NULL; + unsigned long flags = 0; + int ret = -EINVAL; + disable_type_t disable_type = DISABLE_UNKNOWN; + /* + * XXX: Make vmalloc calls in following scope with GFP_NOIO + * to avoid deadlock since our tool calls dmsetup suspend to block + * IO before enable & disable operations + */ + unsigned int noio_flags = memalloc_noio_save(); + + dmc = ti->private; + + VERIFY_WARN(dmc); + + if (!argc) { + serr("No arguments"); + goto err; + } + + // Only one can enter here + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (dmc->in_switching) { + serr("Error: cache is changing to disable or enable now"); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + goto err; + } else { + dmc->in_switching = 1; + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + if (!strcasecmp(argv[0], "enable")) { + // Enable + sprint("Online enable"); + ret = flashcache_enable_or_ctr(ti, argc - 1, argv + 1); + } else if (!strcasecmp(argv[0], "disable")) { + // Disable + sprint("Online disable start"); + + if (2 != argc) { + serr("Lack parameter 2"); + goto err; + } + + if (1 != sscanf(argv[1], "%d", &disable_type)) { + serr("Parse parameter fail"); + goto err; + } + sprint("Disable type = %d", disable_type); + + if ((DISABLE_NORMAL != disable_type) && (DISABLE_FORCE != disable_type)) { + serr("Incorrect disable type = %d", disable_type); + goto err; + } + + ret = flashcache_disable(ti, disable_type); + sprint("Online disable finish"); + + } else { + serr("No supported messages = %s" ,argv[0]); + } + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + dmc->in_switching = 0; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + +err: + memalloc_noio_restore(noio_flags); + return ret; +} + +static int flashcache_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct cache_c *dmc = (struct cache_c *)ti->private; + int ret = 0; + + /* + * Refer to device_area_is_invalid() + * the start and len argumetns indicate the data range of a block device + */ + ret = fn(ti, dmc->disk_dev, 0, dmc->disk_devsize, data); + if (ret) { + // finish iteration + goto end; + } + + if (dmc->cache_dev) { + ret = fn(ti, dmc->cache_dev, 0, to_sector(get_cache_bdev(dmc)->bd_inode->i_size), data); + } +end: + return ret; +} +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) && LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) +/* + * Refer to drivers/md/dm-linear.c: linear_merge + * upstream kill merge_bvec_fn from v4.3 + * When implementing iterate_devices, we must implement the merge function, + * otherwise the size of the bio will be limited to 4k for security reasons. + */ +static int flashcache_merge(struct dm_target *ti, struct bvec_merge_data *bvm, + struct bio_vec *biovec, int max_size) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + struct block_device *disk_bdev = get_disk_bdev(dmc); + struct request_queue *disk_queue = bdev_get_queue(disk_bdev); + int min_bytes = 0; + int merge_bytes = 0; + unsigned int bio_sectors = bvm->bi_size >> SECTOR_SHIFT; + + if (disk_queue->merge_bvec_fn) { + bvm->bi_bdev = disk_bdev; + // For RAID 5/6, it will aligned to chunk size + min_bytes = min(max_size, disk_queue->merge_bvec_fn(disk_queue, bvm, biovec)); + } else { + min_bytes = max_size; + } + + if (dmc->cache_mode != FLASHCACHE_DUMMY) { + /* + * RO or RW cache: Aligned to cache block size to avoid IO splitting + * IO splitting is an old feature that aim to allow cache to receive big-size bio for future seq-io judgement. + * However, since the max bio size of btrfs is changed to 64k, this feature is not so usefully now + * So here we don't make bio large than cache block size anymore. + * + * Refer to blk_queue_merge_bvec() and raid5_mergeable_bvec() + */ + unsigned int prev_sectors = bvm->bi_sector % MAX_BIO_SIZE; + + merge_bytes = (MAX_BIO_SIZE - prev_sectors - bio_sectors) << SECTOR_SHIFT; + if (0 > merge_bytes) { + min_bytes = 0; + } else { + min_bytes = min(min_bytes, merge_bytes); + } + } + + sdbg_limit(DF_MERGE,"bio start=%llu size=%u min_bytes=%d", (u64)bvm->bi_sector, bio_sectors, min_bytes); + + return min_bytes; +} +#endif /* defined(MY_ABC_HERE) && LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) */ + +static struct target_type flashcache_target = { +#ifdef MY_ABC_HERE + .name = SYNO_FLASHCACHE_TARGET_TYPE, +#else + .name = "flashcache", +#endif + .version= {1, 0, 3}, + .module = THIS_MODULE, + .ctr = flashcache_enable_or_ctr, + .dtr = flashcache_dtr, + .map = flashcache_map, +#ifdef MY_ABC_HERE + .noclone_map = flashcache_noclone_map, +#endif /* SYNO_MD_SYNO_FLASHCACHE_NOCLONE */ + .status = flashcache_status, +#ifdef MY_ABC_HERE + .extra_ioctl = flashcache_ioctl, +#else + .ioctl = flashcache_ioctl, +#endif +#ifdef MY_DEF_HERE + .handle_4kn_target_support = flashcache_handle_4kn_target_support, +#endif +#ifdef MY_ABC_HERE + .message = flashcache_message, + .iterate_devices = flashcache_iterate_devices, +#endif +#if defined(MY_ABC_HERE) && LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) + .merge = flashcache_merge, +#endif /* defined(MY_ABC_HERE) && LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) */ +#ifdef MY_ABC_HERE + .support_noclone = flashcache_support_noclone, +#endif /* SYNO_MD_SYNO_FLASHCACHE_NOCLONE */ +}; + +static int +sync_for_remove_can_wake_up(struct cache_c *dmc) +{ +#ifdef MY_ABC_HERE + return !atomic_read(&dmc->nr_jobs) && SYNC_STATE_STOPPED == dmc->oqf.sync_state; +#else + return !atomic_read(&dmc->nr_jobs); +#endif +} + +#ifdef MY_ABC_HERE +static void dmcg_remove_from_nqf_mgmt_sync(struct cache_c *dmc) +{ + dmc_group_t *dmcg = dmc->dmcg; + + down_write(&dmcg->rw_sem); + if (dmcg->nqf_dmc == dmc) { + dmcg->nqf_yielded = 1; + up_write(&dmcg->rw_sem); + cache_mod_delayed_work(&nqf_mgmt_work, 0); + /* No need to lock since dmcg->nqf_dmc will never be dmc again */ + wait_event(dmcg->nqf_wqh, dmcg->nqf_dmc != dmc); + } else if (dmc->oqf.dmcg_wb_scheduled) { + list_del(&dmc->node->nqf_entry); + up_write(&dmcg->rw_sem); + } else { + up_write(&dmcg->rw_sem); + } +} +#endif + +/* The function is called in ending phase, either remove in progress or nr_dirty == 0 + * the function makes sure the nqf loop ends */ +static void stop_wb_works(struct cache_c *dmc) +{ +#ifdef MY_ABC_HERE + /* Stop detect fallow. Also stop nqf being scheduled by wb_work */ + cancel_delayed_work_sync(&dmc->oqf.wb_work); + + /* Remove from queue, on going mu won't schedule again because remove in prog or nr_fallow == 0 */ +#ifdef MY_ABC_HERE + dmcg_remove_from_nqf_mgmt_sync(dmc); +#endif + + mutex_lock(&dmc->oqf.mtx); + while (dmc->oqf.trigger_cnt) { + mutex_unlock(&dmc->oqf.mtx); + wait_event(dmc->oqf.wqh, dmc->oqf.trigger_cnt == 0); + mutex_lock(&dmc->oqf.mtx); + } + mutex_unlock(&dmc->oqf.mtx); + + cancel_work_sync(&dmc->plug_wb.work); + cancel_work_sync(&dmc->plug_wb.wb_done_work); +#else + cancel_delayed_work_sync(&dmc->delayed_clean); +#endif +} + +// Do fast remove or slow remove and wait for nr_job to zero +static void +flashcache_sync_for_remove(struct cache_c *dmc) +{ + unsigned long hang_check = sysctl_hung_task_timeout_secs; + int cur_jobs = 0; + do { + if (!dmc->sysctl_fast_remove) { + atomic_set(&dmc->remove_in_prog, SLOW_REMOVE); /* Stop cleaning of sets */ + + /* + * Kick off cache cleaning. client_destroy will wait for cleanings + * to finish. + */ + printk(KERN_ALERT "Cleaning %d blocks please WAIT", dmc->nr_dirty); + /* Tune up the cleaning parameters to clean very aggressively */ + dmc->max_clean_ios_total = 20; + dmc->max_clean_ios_set = 10; + flashcache_sync_all(dmc); + } else { + /* Needed to abort any in-progress cleanings, leave blocks DIRTY */ + atomic_set(&dmc->remove_in_prog, FAST_REMOVE); + printk(KERN_ALERT "Fast flashcache remove Skipping cleaning of %d blocks", + dmc->nr_dirty); + } + /* + * We've prevented new cleanings from starting (for the fast remove case) + * and we will wait for all in progress cleanings to exit. + * Wait a few seconds for everything to quiesce before writing out the + * cache metadata. + */ + msleep(FLASHCACHE_SYNC_REMOVE_DELAY); + /* Wait for all the dirty blocks to get written out, and any other IOs */ + // Refer to block/blk-exec.c + if (hang_check) { + while (0 != (cur_jobs = atomic_read(&dmc->nr_jobs))) { + sprint("current job is %d, do wait", cur_jobs); + wait_event_timeout(dmc->sync_wqh, + sync_for_remove_can_wake_up(dmc), + hang_check * HZ / 2); + } + } else { + wait_event(dmc->sync_wqh, sync_for_remove_can_wake_up(dmc)); + } + sprint("wait event finish"); + } while (!dmc->sysctl_fast_remove && dmc->nr_dirty > 0); + stop_wb_works(dmc); + sprint("syncing for remove finish"); +} + +static int +flashcache_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) +{ + struct cache_c *dmc; + int ori_enabled = 0; + + sprint("Reboot hook start") + + (void)wait_on_bit_lock_wrapper(&flashcache_control->synch_flags, + FLASHCACHE_UPDATE_LIST, + flashcache_wait_schedule, + TASK_UNINTERRUPTIBLE); + for (dmc = cache_list_head ; + dmc != NULL ; + dmc = dmc->next_cache) { + + if ((CACHE_WAIT_OLD_IOS_COMPLETED == dmc->cache_state) + || (CACHE_WAIT_DISABLE == dmc->cache_state)) { + // If cache is disabling, wait for it + sprint("Waiting for cache disable start"); + wait_event(dmc->wait_for_cache_disable_queue, + (CACHE_DISABLED == dmc->cache_state)); + sprint("Waiting for cache disable finished"); + } + + ori_enabled = (CACHE_ENABLED == dmc->cache_state)? 1 : 0; + + // Cache is ENABLED or DISABLED + if ((CACHE_ENABLED == dmc->cache_state) + || (CACHE_DISABLED == dmc->cache_state)) { + /* + * Make proceess wait and wait until + * no master bios to avoid call trace at removing dmc later + */ + sprint("Waiting master bio to zero"); + dmc->cache_state = CACHE_WAIT_OLD_IOS_COMPLETED; + wait_event(dmc->wait_old_ios_completed_queue, + 0 == atomic_read(&dmc->num_master_io)); + } + + if ((dmc->cache_mode == FLASHCACHE_WRITE_BACK)) { + sprint("Do fast remove and wait nr_job to zero") + flashcache_sync_for_remove(dmc); +#ifdef MY_ABC_HERE + sprint("Do MU flush all") + syno_mu_flush_all_for_remove_sync(dmc); +#endif + sprint("Save metadata") + flashcache_writeback_md_store(dmc); + } + +#ifdef MY_ABC_HERE + if (ori_enabled) { + sprint("Remove cache from group") + dmc_group_remove(dmc); + } +#endif + } + + clear_bit(FLASHCACHE_UPDATE_LIST, &flashcache_control->synch_flags); + smp_mb__after_clear_bit_wrapper(); + wake_up_bit(&flashcache_control->synch_flags, FLASHCACHE_UPDATE_LIST); + + sprint("Reboot hook finish") + + return NOTIFY_DONE; +} + +/* + * The notifiers are registered in descending order of priority and + * executed in descending order or priority. We should be run before + * any notifiers of ssd's or other block devices. Typically, devices + * use a priority of 0. + * XXX - If in the future we happen to use a md device as the cache + * block device, we have a problem because md uses a priority of + * INT_MAX as well. But we want to run before the md's reboot notifier ! + */ +static struct notifier_block flashcache_notifier = { + .notifier_call = flashcache_notify_reboot, + .next = NULL, + .priority = INT_MAX, /* should be > ssd pri's and disk dev pri's */ +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +struct dm_kcopyd_client *flashcache_kcp_client; /* Kcopyd client for writing back data */ +#else +struct kcopyd_client *flashcache_kcp_client; /* Kcopyd client for writing back data */ +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +struct dm_io_client *flashcache_io_client; /* Client memory pool*/ +#endif + +// In linux 4.4, ktime_t is a union +ktime_t ktime_zero; +static void flashcache_init_kcached_wq(void) +{ + int i = 0; + + for (i = 0; i < KCACHED_WQ_SIZE; i++) { + INIT_LIST_HEAD(&kcached_wq[i].jobs); + INIT_WORK(&kcached_wq[i].kwq_work, process_kcached_wq); + } + kcached_wq[PENDING].fn = flashcache_do_pending; + kcached_wq[DO_IO].fn = flashcache_do_io; +#ifdef MY_ABC_HERE +#else + kcached_wq[MD_IO].fn = flashcache_md_write_kickoff; + kcached_wq[MD_COMPLETE].fn = flashcache_md_write_done; +#endif + kcached_wq[UNCACHED_IO_COMPLETE].fn = flashcache_uncached_io_complete; + kcached_wq[PREREAD].fn = flashcache_do_preread_io; + kcached_wq[FREE_JOB].fn = process_free_job; +} + +/* + * Initiate a cache target. + */ +int __init +flashcache_init(void) +{ + int r = 0; + + ktime_zero = ktime_set(0, 0); + + if (job_max_mem_count != MAX_JOB_MEM_COUNT) { + sprint("Init driver with job_max_mem_count=%d", job_max_mem_count); + } + init_waitqueue_head(&job_mem_wait_queue); + atomic_set(&nr_cache_jobs, 0); + atomic_set(&nr_pending_jobs, 0); + + flashcache_io_client = dm_io_client_create(); + + if (IS_ERR(flashcache_io_client)) { + DMERR("flashcache_init: Failed to initialize DM IO client"); + return r; + } + + flashcache_kcp_client = dm_kcopyd_client_create(NULL); + if ((r = IS_ERR(flashcache_kcp_client))) { + r = PTR_ERR(flashcache_kcp_client); + } + + if (r) { + dm_io_client_destroy(flashcache_io_client); + DMERR("flashcache_init: Failed to initialize kcopyd client"); + return r; + } + +#ifdef MY_ABC_HERE + /* allow multiple workers threads */ + cache_workqueue = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 0, "ssd-cache"); +#endif /* MY_ABC_HERE */ + + flashcache_init_kcached_wq(); + +#ifdef MY_DEF_HERE + for (r = 0 ; r < sizeof(size_hist)/sizeof(size_hist[0]) ; r++) +#else + for (r = 0 ; r < 33 ; r++) +#endif /* MY_DEF_HERE */ + size_hist[r] = 0; + r = dm_register_target(&flashcache_target); + if (r < 0) { + DMERR("cache: register failed %d", r); + } + + sprint("%s initialized", flashcache_sw_version); + + flashcache_module_procfs_init(); + flashcache_control = (struct flashcache_control_s *) + kmalloc(sizeof(struct flashcache_control_s), GFP_KERNEL); + flashcache_control->synch_flags = 0; + register_reboot_notifier(&flashcache_notifier); + /* + * Initialize global bio_set (global for linux 3.2 compatible) + * bio_set uses similar concept as mempool + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + // BIOSET_NEED_BVECS is refer to md.c + r = bioset_init(pcache_bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (r) { + serr("Failed to init bio set, r = %d", r); + goto err; + } +#else + pcache_bio_set = bioset_create(BIO_POOL_SIZE, 0); + if (NULL == pcache_bio_set) { + serr("Failed to create bioset"); + r = -ENOMEM; + goto err; + } +#endif + +#ifdef MY_ABC_HERE + mutex_init(&dmc_list_mtx); +#endif +#ifdef MY_ABC_HERE + mutex_init(&dmcg_mtx); + INIT_DELAYED_WORK(&nqf_mgmt_work, dmcg_nqf_mgmt); + schedule_nqf_mgmt_work(); +#endif +err: + return r; +} + +/* + * Destroy a cache target. + */ +void +flashcache_exit(void) +{ +#ifdef MY_ABC_HERE + cancel_delayed_work_sync(&nqf_mgmt_work); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + int r = dm_unregister_target(&flashcache_target); + + if (r < 0) + DMERR("cache: unregister failed %d", r); +#else + dm_unregister_target(&flashcache_target); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + kcopyd_client_destroy(flashcache_kcp_client); +#else + dm_kcopyd_client_destroy(flashcache_kcp_client); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + dm_io_client_destroy(flashcache_io_client); +#else + dm_io_put(FLASHCACHE_ASYNC_SIZE); +#endif + unregister_reboot_notifier(&flashcache_notifier); +#ifdef MY_ABC_HERE +#else + flashcache_jobs_exit(); +#endif + flashcache_module_procfs_releae(); + kfree(flashcache_control); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + bioset_exit(pcache_bio_set); +#else + if (pcache_bio_set) { + bioset_free(pcache_bio_set); + } +#endif +#ifdef MY_ABC_HERE + destroy_workqueue(cache_workqueue); +#endif /* MY_ABC_HERE */ +} + +module_init(flashcache_init); +module_exit(flashcache_exit); + +#ifdef MY_ABC_HERE +#else +EXPORT_SYMBOL(flashcache_writeback_load); +EXPORT_SYMBOL(flashcache_writeback_create); +EXPORT_SYMBOL(flashcache_writeback_md_store); +#endif + +MODULE_DESCRIPTION(DM_NAME " Facebook flash cache target"); +MODULE_AUTHOR("Mohan - based on code by Ming"); +MODULE_LICENSE("GPL"); diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_ioctl.c b/drivers/syno/syno-mem-saving-driver/flashcache_ioctl.c new file mode 100644 index 000000000000..3109c1713694 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_ioctl.c @@ -0,0 +1,1009 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache_ioctl.c + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#include "dm.h" +#include "dm-io.h" +#include "dm-bio-list.h" +#include "kcopyd.h" +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +#include "dm.h" +#endif +#include +#include +#include +#endif +#include "flashcache.h" +#include "flashcache_ioctl.h" +#include + +#ifdef MY_ABC_HERE +extern unsigned long hash_block(struct cache_c *dmc, sector_t dbn); +#endif + +static int flashcache_find_pid_locked(struct cache_c *dmc, pid_t pid, + int which_list); +static void flashcache_del_pid_locked(struct cache_c *dmc, pid_t pid, + int which_list); + +static int +flashcache_find_pid_locked(struct cache_c *dmc, pid_t pid, + int which_list) +{ + struct flashcache_cachectl_pid *pid_list; + + pid_list = ((which_list == FLASHCACHE_WHITELIST) ? + dmc->whitelist_head : dmc->blacklist_head); + for ( ; pid_list != NULL ; pid_list = pid_list->next) { + if (pid_list->pid == pid) + return 1; + } + return 0; +} + +static void +flashcache_drop_pids(struct cache_c *dmc, int which_list) +{ + if (which_list == FLASHCACHE_WHITELIST) { + while (dmc->num_whitelist_pids >= dmc->sysctl_max_pids) { + VERIFY_WARN(dmc->whitelist_head != NULL); + flashcache_del_pid_locked(dmc, dmc->whitelist_tail->pid, + which_list); + atomic64_inc(&dmc->flashcache_stats.pid_drops); + } + } else { + while (dmc->num_blacklist_pids >= dmc->sysctl_max_pids) { + VERIFY_WARN(dmc->blacklist_head != NULL); + flashcache_del_pid_locked(dmc, dmc->blacklist_tail->pid, + which_list); + atomic64_inc(&dmc->flashcache_stats.pid_drops); + } + } +} + +static void +flashcache_add_pid(struct cache_c *dmc, pid_t pid, int which_list) +{ + struct flashcache_cachectl_pid *new; + unsigned long flags; + + new = kmalloc(sizeof(struct flashcache_cachectl_pid), GFP_KERNEL); + if (!new) { + serr("Failed to allocate pid when adding pid"); + return; + } + new->pid = pid; + new->next = NULL; + new->expiry = jiffies + dmc->sysctl_pid_expiry_secs * HZ; + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (which_list == FLASHCACHE_WHITELIST) { + if (dmc->num_whitelist_pids > dmc->sysctl_max_pids) + flashcache_drop_pids(dmc, which_list); + } else { + if (dmc->num_blacklist_pids > dmc->sysctl_max_pids) + flashcache_drop_pids(dmc, which_list); + } + if (flashcache_find_pid_locked(dmc, pid, which_list) == 0) { + struct flashcache_cachectl_pid **head, **tail; + + if (which_list == FLASHCACHE_WHITELIST) { + head = &dmc->whitelist_head; + tail = &dmc->whitelist_tail; + } else { + head = &dmc->blacklist_head; + tail = &dmc->blacklist_tail; + } + /* Add the new pid to the tail */ + new->prev = *tail; + if (*head == NULL) { + VERIFY_WARN(*tail == NULL); + *head = new; + } else { + VERIFY_WARN(*tail != NULL); + (*tail)->next = new; + } + *tail = new; + if (which_list == FLASHCACHE_WHITELIST) + dmc->num_whitelist_pids++; + else + dmc->num_blacklist_pids++; + atomic64_inc(&dmc->flashcache_stats.pid_adds); + /* When adding the first entry to list, set expiry check timeout */ + if (*head == new) + dmc->pid_expire_check = + jiffies + ((dmc->sysctl_pid_expiry_secs + 1) * HZ); + } else + kfree(new); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + return; +} + +static void +flashcache_del_pid_locked(struct cache_c *dmc, pid_t pid, int which_list) +{ + struct flashcache_cachectl_pid *node; + struct flashcache_cachectl_pid **head, **tail; + + if (which_list == FLASHCACHE_WHITELIST) { + head = &dmc->whitelist_head; + tail = &dmc->whitelist_tail; + } else { + head = &dmc->blacklist_head; + tail = &dmc->blacklist_tail; + } + for (node = *tail ; node != NULL ; node = node->prev) { + if (which_list == FLASHCACHE_WHITELIST) + VERIFY_WARN(dmc->num_whitelist_pids > 0); + else + VERIFY_WARN(dmc->num_blacklist_pids > 0); + if (node->pid == pid) { + if (node->prev == NULL) { + *head = node->next; + if (node->next) + node->next->prev = NULL; + } else + node->prev->next = node->next; + if (node->next == NULL) { + *tail = node->prev; + if (node->prev) + node->prev->next = NULL; + } else + node->next->prev = node->prev; + kfree(node); + atomic64_inc(&dmc->flashcache_stats.pid_dels); + if (which_list == FLASHCACHE_WHITELIST) + dmc->num_whitelist_pids--; + else + dmc->num_blacklist_pids--; + return; + } + } +} + +static void +flashcache_del_pid(struct cache_c *dmc, pid_t pid, int which_list) +{ + unsigned long flags; + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + flashcache_del_pid_locked(dmc, pid, which_list); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); +} + +/* + * This removes all "dead" pids. Pids that may have not cleaned up. + */ +void +flashcache_del_all_pids(struct cache_c *dmc, int which_list, int force) +{ + struct flashcache_cachectl_pid *node, **tail; + unsigned long flags; + + if (which_list == FLASHCACHE_WHITELIST) + tail = &dmc->whitelist_tail; + else + tail = &dmc->blacklist_tail; + rcu_read_lock(); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + node = *tail; + while (node != NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + if (force == 0) { + struct task_struct *task; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) + task = find_task_by_pid_type(PIDTYPE_PID, node->pid); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + task = find_task_by_vpid(node->pid); +#else + ask = pid_task(find_vpid(node->pid), PIDTYPE_PID); +#endif + /* + * If that task was found, don't remove it ! + * This prevents a rogue "delete all" from removing + * every thread from the list. + */ + if (task) { + node = node->prev; + continue; + } + } +#endif + flashcache_del_pid_locked(dmc, node->pid, which_list); + node = *tail; + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + rcu_read_unlock(); +} + +static void +flashcache_pid_expiry_list_locked(struct cache_c *dmc, int which_list) +{ + struct flashcache_cachectl_pid **head, **tail, *node, *tmp_node; + + if (which_list == FLASHCACHE_WHITELIST) { + head = &dmc->whitelist_head; + tail = &dmc->whitelist_tail; + } else { + head = &dmc->blacklist_head; + tail = &dmc->blacklist_tail; + } + for (node = *head, tmp_node = NULL; node != NULL ; node = tmp_node) { + tmp_node = node->next; + if (which_list == FLASHCACHE_WHITELIST) + VERIFY_WARN(dmc->num_whitelist_pids > 0); + else + VERIFY_WARN(dmc->num_blacklist_pids > 0); + if (time_after(node->expiry, jiffies)) + continue; + if (node->prev == NULL) { + *head = node->next; + if (node->next) + node->next->prev = NULL; + } else + node->prev->next = node->next; + if (node->next == NULL) { + *tail = node->prev; + if (node->prev) + node->prev->next = NULL; + } else + node->next->prev = node->prev; + kfree(node); + if (which_list == FLASHCACHE_WHITELIST) + dmc->num_whitelist_pids--; + else + dmc->num_blacklist_pids--; + atomic64_inc(&dmc->flashcache_stats.expiry); + } +} + +void +flashcache_pid_expiry_all_locked(struct cache_c *dmc) +{ + if (likely(time_before(jiffies, dmc->pid_expire_check))) + return; + flashcache_pid_expiry_list_locked(dmc, FLASHCACHE_WHITELIST); + flashcache_pid_expiry_list_locked(dmc, FLASHCACHE_BLACKLIST); + dmc->pid_expire_check = jiffies + (dmc->sysctl_pid_expiry_secs + 1) * HZ; +} + +/* + * Is the IO cacheable, depending on global cacheability and the white/black + * lists ? This function is a bit confusing because we want to support inheritance + * of cacheability across pthreads (so we use the tgid). But when an entire thread + * group is added to the white/black list, we want to provide for exceptions for + * individual threads as well. + * The Rules (in decreasing order of priority) : + * 1) Check the pid (thread id) against the list. + * 2) Check the tgid against the list, then check for exceptions within the tgid. + * 3) Possibly don't cache sequential i/o. + * + * NOTE: + * 1. XXX: DONT put this function inside cache_spin_lock + * since skip_sequential_io need some time to run seq gap loop that + * affect performance on some models + * 2. This function will update skip_io table + */ +int +flashcache_uncacheable(struct cache_c *dmc, struct bio *bio, int *uncache_seq) +{ + int dontcache = 0; + + if (unlikely(dmc->bypass_cache)) { + dontcache = 1; + goto out; + } + + + if (dmc->sysctl_cache_all) { + dontcache = 0; +#ifdef MY_ABC_HERE + if (bio_is_pin(bio)) { + dontcache = 0; + goto out; + } +#endif +#ifdef MY_ABC_HERE +#else + /* If the tid has been blacklisted, we don't cache at all. + This overrides everything else */ + dontcache = flashcache_find_pid_locked(dmc, current->pid, + FLASHCACHE_BLACKLIST); + if (dontcache) + goto out; + /* Is the tgid in the blacklist ? */ + dontcache = flashcache_find_pid_locked(dmc, current->tgid, + FLASHCACHE_BLACKLIST); + /* + * If we found the tgid in the blacklist, is there a whitelist + * exception entered for this thread ? + */ + if (dontcache) { + if (flashcache_find_pid_locked(dmc, current->pid, + FLASHCACHE_WHITELIST)) { + dontcache = 0; + goto out; + } + } +#endif /* SYNO_FLASHCACHE_BLOCKLIST */ + + /* Finally, if we are neither in a whitelist or a blacklist, + * do a final check to see if this is sequential i/o. If + * the relevant sysctl is set, we will skip it. + */ + *uncache_seq = skip_sequential_io(dmc, bio); + dontcache = *uncache_seq; + } else { /* cache nothing */ + dontcache = 1; +#ifdef MY_ABC_HERE +#else + /* If the tid has been whitelisted, we cache + This overrides everything else */ + dontcache = !flashcache_find_pid_locked(dmc, current->pid, + FLASHCACHE_WHITELIST); + if (!dontcache) + goto out; + /* Is the tgid in the whitelist ? */ + dontcache = !flashcache_find_pid_locked(dmc, current->tgid, + FLASHCACHE_WHITELIST); + /* + * If we found the tgid in the whitelist, is there a black list + * exception entered for this thread ? + */ + if (!dontcache) { + if (flashcache_find_pid_locked(dmc, current->pid, + FLASHCACHE_BLACKLIST)) + dontcache = 1; + } + /* No sequential handling here. If we add to the whitelist, + * everything is cached, sequential or not. + */ +#endif + } +out: + return dontcache; +} + +/* Below 2 functions manage the LRU cache of recent IO 'flows'. + * A sequential IO will only take up one slot (we keep updating the + * last sector seen) but random IO will quickly fill multiple slots. + * We allocate the LRU cache from a small fixed sized buffer at startup. + */ +void +seq_io_remove_from_lru(struct cache_c *dmc, struct sequential_io *seqio) +{ + if (seqio->prev != NULL) + seqio->prev->next = seqio->next; + else { + VERIFY_WARN(dmc->seq_io_head == seqio); + dmc->seq_io_head = seqio->next; + } + if (seqio->next != NULL) + seqio->next->prev = seqio->prev; + else { + VERIFY_WARN(dmc->seq_io_tail == seqio); + dmc->seq_io_tail = seqio->prev; + } +} + +void +seq_io_move_to_lruhead(struct cache_c *dmc, struct sequential_io *seqio) +{ + if (likely(seqio->prev != NULL || seqio->next != NULL)) + seq_io_remove_from_lru(dmc, seqio); + /* Add it to LRU head */ + if (dmc->seq_io_head != NULL) + dmc->seq_io_head->prev = seqio; + seqio->next = dmc->seq_io_head; + seqio->prev = NULL; + dmc->seq_io_head = seqio; +} + +#ifdef MY_ABC_HERE +void dump_seq_io_table(struct cache_c *dmc) +{ + struct sequential_io *seqio = NULL; + int i = 0; + + for (seqio = dmc->seq_io_head; seqio != NULL ; seqio = seqio->next) { + sdbg(DF_DETAIL, "seqio[%d]->most_recent_sector=%llu sequential sectors=%llu", i, (u64)seqio->most_recent_sector, + (u64)seqio->sequential_sectors); + i++; + } +} +#endif + + +/* Look for and maybe skip sequential i/o. + * + * Since performance(SSD) >> performance(HDD) for random i/o, + * but performance(SSD) ~= performance(HDD) for sequential i/o, + * it may be optimal to save (presumably expensive) SSD cache space for random i/o only. + * + * We don't know whether a single request is part of a big sequential read/write. + * So all we can do is monitor a few requests, and try to spot if they are + * continuations of a recent 'flow' of i/o. After several contiguous blocks we consider + * it sequential. + * + * You can tune the threshold with the sysctl skip_seq_thresh_kb (e.g. 64 = 64kb), + * or cache all i/o (without checking whether random or sequential) with skip_seq_thresh_kb = 0. + */ +int +skip_sequential_io(struct cache_c *dmc, struct bio *bio) +{ + struct sequential_io *seqio; + int sequential = 0; /* Saw > 1 in a row? */ + int skip = 0; /* Enough sequential to hit the threshold */ + int move_to_head_check_skip = 0; + sector_t forward_gap_sector = 0; + sector_t backward_gap_sector = 0; + sector_t seqio_end_sector = 0; + + spin_lock_irq(&dmc->seq_io_spin_lock); + + /* sysctl skip sequential threshold = 0 : disable, cache all sequential and random i/o. + * This is the default. */ + if (dmc->sysctl_skip_seq_thresh_kb == 0) { + skip = 0; /* Redundant, for emphasis */ + goto out; + } + + /* Is it a continuation of recent i/o? Try to find a match. */ + DPRINTK("skip_sequential_io: searching for %ld", bio_bi_sector(bio)); + /* search the list in LRU order so single sequential flow hits first slot */ + for (seqio = dmc->seq_io_head; seqio != NULL && sequential == 0; seqio = seqio->next) { + + seqio_end_sector = seqio->most_recent_sector + seqio->last_bio_sectors; + forward_gap_sector = min(seqio->sequential_sectors, to_sector(dmc->sysctl_skip_seq_fgap_kb * 1024)); + + if ((bio_bi_sector(bio) == seqio->most_recent_sector) && + (to_sector(bio_bi_size(bio)) == seqio->last_bio_sectors)) { + + /* Reread or write same sector again. Ignore but move to head */ + DPRINTK("skip_sequential_io: repeat"); + sequential = 1; + if (dmc->seq_io_head != seqio) + seq_io_move_to_lruhead(dmc, seqio); + } + /* i/o to one block more than the previous i/o = sequential */ + else if ((bio_bi_sector(bio) >= seqio_end_sector) && + (bio_bi_sector(bio) <= seqio_end_sector + forward_gap_sector)) { + DPRINTK("skip_sequential_io: sequential found"); + /* Update stats. */ + seqio->sequential_sectors += + to_sector(bio_bi_size(bio)); + seqio->most_recent_sector = bio_bi_sector(bio); + seqio->last_bio_sectors = to_sector(bio_bi_size(bio)); + sequential = 1; + move_to_head_check_skip = 1; + } else if (dmc->sysctl_skip_seq_bgap_kb > 0) { + backward_gap_sector = min(to_sector(dmc->sysctl_skip_seq_bgap_kb * 1024), seqio->sequential_sectors); + if ((bio_bi_sector(bio) >= seqio_end_sector - backward_gap_sector) + && bio_bi_sector(bio) + to_sector(bio_bi_size(bio)) <= seqio_end_sector) { + sequential = 1; + move_to_head_check_skip = 1; + } + } + + if (move_to_head_check_skip) { + /* And move to head, if not head already */ + if (dmc->seq_io_head != seqio) { + seq_io_move_to_lruhead(dmc, seqio); + } + + /* Is it now sequential enough to be sure? (threshold expressed in kb) */ + if (to_bytes(seqio->sequential_sectors) > dmc->sysctl_skip_seq_thresh_kb * 1024) { + DPRINTK("skip_sequential_io: Sequential i/o detected, seq sectors now %llu", + seqio->sequential_sectors); + /* Sufficiently sequential */ + skip = 1; + } + } + } + if (!sequential) { + /* Record the start of some new i/o, maybe we'll spot it as + * sequential soon. */ + DPRINTK("skip_sequential_io: concluded that its random i/o"); + + seqio = dmc->seq_io_tail; + seq_io_move_to_lruhead(dmc, seqio); + + DPRINTK("skip_sequential_io: fill in data"); + + /* Fill in data */ + seqio->most_recent_sector = bio_bi_sector(bio); + seqio->last_bio_sectors = to_sector(bio_bi_size(bio)); + // Reset the vaule + seqio->sequential_sectors = to_sector(bio_bi_size(bio)); + } + DPRINTK("skip_sequential_io: complete."); +out: + spin_unlock_irq(&dmc->seq_io_spin_lock); + + return skip; +} +#ifdef MY_ABC_HERE +static int set_bitmap(struct cache_c *dmc, unsigned long arg) +{ + int ret = -EFAULT; +#ifdef MY_ABC_HERE + int get_control = 0; + BITMAP *pbitmap = NULL; +#endif + + sdbg(DF_PIN, "Set bitmap start"); + +#ifdef MY_ABC_HERE + pbitmap = kzalloc(sizeof(BITMAP), GFP_KERNEL); + if (!pbitmap) { + serr("Vmalloc bitmap failed"); + goto err; + } + + bitmap_control_get(dmc); + get_control = 1; +#endif + + if (0 == dmc->bitmap_size_byte) { + serr("Bitmap table is not allocated"); + goto err; + } + + sdbg(DF_PIN, "Total bytes = %llu", dmc->bitmap_size_byte); + +#ifdef MY_ABC_HERE + if (copy_from_user(pbitmap, (void *)arg, sizeof(BITMAP))) { + serr("Copy bitmap error"); + goto err; + } + + /* + * Support online expansion so that simetimes the recorded bitmap size could be larger + * than the bitmap passed in + */ + if (pbitmap->sizeByte != dmc->bitmap_size_byte) { + sdbg(DF_PIN, "Bitmap size change: input size = %zd cache bitmap size = %llu", + pbitmap->sizeByte, dmc->bitmap_size_byte); + } + + if (pbitmap->sizeByte > dmc->bitmap_size_byte) { + serr("Input bitmap size (%zd) should not large then the cache bitmap size = %llu", + pbitmap->sizeByte, dmc->bitmap_size_byte); + goto err; + } + + if (copy_from_user(dmc->pbitmap_ranges, (void *)pbitmap->data, pbitmap->sizeByte)) { + serr("Copy bitmap error"); + goto err; + } +#else + if (copy_from_user(dmc->pbitmap_ranges, (void *)arg, dmc->bitmap_size_byte)) { + serr("Copy bitmap error"); + goto err; + } +#endif + + dmc->bitmap_is_set = 1; + ret = 0; + +err: +#ifdef MY_ABC_HERE + if (get_control) { + bitmap_control_put(dmc); + } + + if (pbitmap) { + kfree(pbitmap); + } +#endif + sdbg(DF_PIN, "Set bitmap finish"); + return ret ; +} + +static int bitmap_is_set(struct cache_c *dmc, unsigned long arg) +{ + int ret = -EFAULT; + + if (copy_to_user((int *)arg, &dmc->bitmap_is_set, sizeof(int))) { + serr("Can't copy data to user"); + goto err; + } + sdbg(DF_PIN, "Copy data to user finish. bitmap_is_set = %d", dmc->bitmap_is_set); + + ret = 0; +err: + return ret ; +} + +static void unpin_cache_block(struct cache_c *dmc, int disk_start_sector) +{ + unsigned long set_number = 0; + int start_index = 0; + int end_index = 0; + int i = 0; + unsigned long flags; + + VERIFY_WARN(dmc); + + set_number = hash_block(dmc, disk_start_sector); + start_index = dmc->assoc * set_number; + end_index = start_index + dmc->assoc; + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + for (i = start_index ; i < end_index ; i++) { + /* + * Search each cache block and check if bio's start sector (dbn) match a range of an cacheblk + */ + if (disk_start_sector >= dmc->cache[i].dbn && + (disk_start_sector < (dmc->cache[i].dbn + dmc->block_size)) && + dmc->cache[i].cache_state & VALID) { + + if (dmc->cache[i].cache_state & PIN_FILE) { + sdbg(DF_PIN, "unpin cache block start = %llu", (unsigned long long)dmc->cache[i].dbn); + cb_state_remove_bits_update_counts(dmc, &dmc->cache[i], PIN_FILE); + } + + break; + + } + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); +} + +static void unpin_range(struct cache_c *dmc, range_t *range) +{ + u64 next_start_sector = range->disk_start_sector; + u64 last_sector = range->disk_start_sector + range->num_sectors - 1; + + sdbg(DF_PIN, "start sector = %llu num sectors = %llu", range->disk_start_sector, range->num_sectors); + while (next_start_sector < last_sector) { + // Unpin a cache block + unpin_cache_block(dmc, next_start_sector); + next_start_sector = compatible_div(next_start_sector + MAX_BIO_SIZE, MAX_BIO_SIZE) + * MAX_BIO_SIZE; + } +} + +static inline int unpin_range_reasonable(range_t *range, u64 disk_sector_num) +{ + if (range->disk_start_sector + range->num_sectors <= range->disk_start_sector) { + return 0; // overflow + } + + if (range->disk_start_sector + range->num_sectors > disk_sector_num) { + return 0; // range larger than device size + } + + return 1; +} + +range_t ranges[MAX_RANGES]; + +int unpin_ranges(struct cache_c *dmc, unsigned long arg) +{ + int ret = -EFAULT; + int i = 0; + unsigned long num_uncompleted = 0; + u64 disk_sector_num = 0; + + memset(ranges, 0, sizeof(ranges)); + + num_uncompleted = copy_from_user(ranges, (void *)arg, sizeof(ranges)); + if (num_uncompleted) { + serr("Copy ranges error. request size=%zd uncompleted=%lu", sizeof(ranges), num_uncompleted); + goto err; + } + + /* + * A new bitmap should be sent to flashcache driver before starting to unpin cache blocks + * However, some on-going bios might still be labeled as pin and doesn't enter the + * flashcache_lookup function yet + * So it might cause a race condition in following two paths + * Path 1. Query the old bitmap -> bio labeled as pin -> flashcache_lookup + * -> move the cache block to lru tail + * Path 2. Unpin cache block -> move the cache block to the lru head + * Therefore, we add a sleep on Path 2 to wait for those bios to be completed + */ + msleep_interruptible(100); + + disk_sector_num = to_sector(get_disk_bdev(dmc)->bd_inode->i_size); + + while ((MAX_RANGES > i) && (0 != ranges[i].num_sectors)) { + if (unpin_range_reasonable(&ranges[i], disk_sector_num)) { + unpin_range(dmc, &ranges[i]); + } else { + serr("Unreasonable disk_sector: %llu len: %llu", + ranges[i].disk_start_sector, ranges[i].num_sectors) + } + i++; + } + + ret = 0; + +err: + sdbg(DF_PIN, "Unpin ranges finish"); + return ret ; +} + +void zero_cache_bitmap(struct cache_c *dmc) +{ + bitmap_control_get(dmc); + + if (dmc->bitmap_is_set) { + + memset(dmc->pbitmap_ranges, 0, dmc->bitmap_size_byte); + + dmc->bitmap_is_set = 0; + } + + bitmap_control_put(dmc); +} + +int unpin_all_blocks(struct cache_c *dmc, unsigned long arg) +{ + int ret = -EFAULT; + unsigned long long i = 0; + unsigned long flags; + + sdbg(DF_PIN, "Unpin all blocks start"); + + zero_cache_bitmap(dmc); + + for (i = 0; i < dmc->size; i++) { + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (dmc->cache[i].cache_state & PIN_FILE) { + cb_state_remove_bits_update_counts(dmc, &dmc->cache[i], PIN_FILE); + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + } + + ret = 0; + + sdbg(DF_PIN, "Unpin all blocks finish"); + return ret ; +} + +static int is_all_blocks_unpin(struct cache_c *dmc, unsigned long arg) +{ + int ret = -EFAULT; + unsigned long long i = 0; + unsigned long flags; + int all_unpin = 1; + + for (i = 0; i < dmc->size; i++) { + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + if (dmc->cache[i].cache_state & PIN_FILE) { + all_unpin = 0; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + break; + } + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + } + + if (copy_to_user((int *)arg, &all_unpin, sizeof(int))) { + serr("Can't copy data to user"); + goto err; + } + + + ret = 0; +err: + return ret; +} +#endif + +#define GOTO_UNLOCK_AND_RET(val) ret = val; goto unlock_and_ret + +/* + * Add/del pids whose IOs should be non-cacheable. + * We limit this number to 100 (arbitrary and sysctl'able). + * We also add an expiry to each entry (defaluts at 60 sec, + * arbitrary and sysctlable). + * This is needed because Linux lacks an "at_exit()" hook + * that modules can supply to do any cleanup on process + * exit, for cases where the process dies after marking itself + * non-cacheable. + */ +int +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +flashcache_ioctl(struct dm_target *ti, struct inode *inode, + struct file *filp, unsigned int cmd, + unsigned long arg) +#else +flashcache_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) +#endif +{ + int ret = -EFAULT; + struct cache_c *dmc = (struct cache_c *) ti->private; +#ifdef MY_ABC_HERE +#else +#ifdef MY_ABC_HERE + // Save the mode in the beginning of the system call + fmode_t mode = get_disk_mode(dmc); + struct block_device *bdev = get_disk_bdev(dmc); +#else + struct block_device *bdev = dmc->disk_dev->bdev; +#endif + struct file fake_file = {}; + struct dentry fake_dentry = {}; +#endif /* MY_ABC_HERE */ + pid_t pid; + +#ifdef MY_ABC_HERE + // Check block ioctl in include/uapi/linux/fs.h + sdbg(DF_PIN, "Get ioctl command = %d IO type=%d num=%d", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); + sdbg(DF_PIN, "FLASHCACHE_BITMAP_SET=%d", FLASHCACHE_BITMAP_SET); + sdbg(DF_PIN, "FLASHCACHE_UNPIN_RANGES=%d", FLASHCACHE_UNPIN_RANGES); +#endif + + down_read(&dmc->ioctl_rwsem); + + // Lock acquired, need to release before return + + if (CACHE_ENABLED != dmc->cache_state) { + /* Do not support cache specific ioctl after disable. */ + switch (cmd) { +#ifdef MY_ABC_HERE + case FLASHCACHE_BITMAP_SET: + case FLASHCACHE_BITMAP_IS_SET: + case FLASHCACHE_UNPIN_RANGES: + case FLASHCACHE_UNPIN_ALL_BLOCKS: + case FLASHCACHE_IS_ALL_BLOCKS_UNPIN: +#endif + case FLASHCACHEADDBLACKLIST: + case FLASHCACHEDELBLACKLIST: + case FLASHCACHEDELALLBLACKLIST: + case FLASHCACHEADDWHITELIST: + case FLASHCACHEDELWHITELIST: + case FLASHCACHEDELALLWHITELIST: + GOTO_UNLOCK_AND_RET(-ENOTTY); + default: + goto handle_default_ioctl; + } + } else { + switch(cmd) { +#ifdef MY_ABC_HERE + case FLASHCACHE_BITMAP_SET: + if (set_bitmap(dmc, arg)) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + GOTO_UNLOCK_AND_RET(0); + + case FLASHCACHE_BITMAP_IS_SET: + if (bitmap_is_set(dmc, arg)) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + GOTO_UNLOCK_AND_RET(0); + + case FLASHCACHE_UNPIN_RANGES: + sdbg(DF_PIN, "unpin ranges"); + if (unpin_ranges(dmc, arg)) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHE_UNPIN_ALL_BLOCKS: + if (unpin_all_blocks(dmc, arg)) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHE_IS_ALL_BLOCKS_UNPIN: + if (is_all_blocks_unpin(dmc, arg)) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + GOTO_UNLOCK_AND_RET(0); +#endif + case FLASHCACHEADDBLACKLIST: + if (copy_from_user(&pid, (pid_t *)arg, sizeof(pid_t))) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + flashcache_add_pid(dmc, pid, FLASHCACHE_BLACKLIST); + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHEDELBLACKLIST: + if (copy_from_user(&pid, (pid_t *)arg, sizeof(pid_t))) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + flashcache_del_pid(dmc, pid, FLASHCACHE_BLACKLIST); + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHEDELALLBLACKLIST: + flashcache_del_all_pids(dmc, FLASHCACHE_BLACKLIST, 0); + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHEADDWHITELIST: + if (copy_from_user(&pid, (pid_t *)arg, sizeof(pid_t))) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + flashcache_add_pid(dmc, pid, FLASHCACHE_WHITELIST); + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHEDELWHITELIST: + if (copy_from_user(&pid, (pid_t *)arg, sizeof(pid_t))) { + GOTO_UNLOCK_AND_RET(-EFAULT); + } + flashcache_del_pid(dmc, pid, FLASHCACHE_WHITELIST); + GOTO_UNLOCK_AND_RET(0); + case FLASHCACHEDELALLWHITELIST: + flashcache_del_all_pids(dmc, FLASHCACHE_WHITELIST, 0); + GOTO_UNLOCK_AND_RET(0); + default: + goto handle_default_ioctl; + } + } + +handle_default_ioctl: +#ifdef MY_ABC_HERE + // Command is not supported + GOTO_UNLOCK_AND_RET(1); +#else /* Not MY_ABC_HERE */ + up_read(&dmc->ioctl_rwsem); +#ifdef MY_ABC_HERE + fake_file.f_mode = mode; +#else + fake_file.f_mode = dmc->disk_dev->mode; +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + fake_file.f_dentry = &fake_dentry; +#else + fake_file.f_path.dentry = &fake_dentry; +#endif + fake_dentry.d_inode = bdev->bd_inode; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) + return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg); +#else +#ifdef MY_ABC_HERE + return __blkdev_driver_ioctl(get_disk_bdev(dmc), mode, cmd, arg); +#else + return __blkdev_driver_ioctl(dmc->disk_dev->bdev, dmc->disk_dev->mode, cmd, arg); +#endif +#endif +#endif /* MY_ABC_HERE */ + +unlock_and_ret: + up_read(&dmc->ioctl_rwsem); + return ret; +} diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_ioctl.h b/drivers/syno/syno-mem-saving-driver/flashcache_ioctl.h new file mode 100644 index 000000000000..df3b51b874de --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_ioctl.h @@ -0,0 +1,96 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache_ioctl.h + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#ifndef FLASHCACHE_IOCTL_H +#define FLASHCACHE_IOCTL_H + +#include + +#define FLASHCACHE_IOCTL 0xfe + +// Also set in flashcache.h +#if defined(CONFIG_SYNO_ALPINE) +// Alpine doesn't suppot it due to memory limitation +#else +#endif + +enum { + FLASHCACHEADDNCPID_CMD=200, + FLASHCACHEDELNCPID_CMD, + FLASHCACHEDELNCALL_CMD, + FLASHCACHEADDWHITELIST_CMD, + FLASHCACHEDELWHITELIST_CMD, + FLASHCACHEDELWHITELISTALL_CMD, +#ifdef MY_ABC_HERE + FLASHCACHE_BITMAP_iS_SET_CMD, + FLASHCACHE_BITMAP_SET_CMD, + FLASHCACHE_UNPIN_RANGES_CMD, + FLASHCACHE_UNPIN_ALL_BLOCKS_CMD, + FLASHCACHE_IS_ALL_BLOCKS_UNPIN_CMD, +#endif +}; + +#ifdef MY_ABC_HERE +#include "flashcache_pin_file.h" +// Use _IO for pass large data +#define FLASHCACHE_BITMAP_SET _IO(FLASHCACHE_IOCTL, FLASHCACHE_BITMAP_SET_CMD) +#define FLASHCACHE_BITMAP_IS_SET _IOR(FLASHCACHE_IOCTL, FLASHCACHE_BITMAP_SET_CMD, int) +#define FLASHCACHE_UNPIN_RANGES _IO(FLASHCACHE_IOCTL, FLASHCACHE_UNPIN_RANGES_CMD) +#define FLASHCACHE_UNPIN_ALL_BLOCKS _IO(FLASHCACHE_IOCTL, FLASHCACHE_UNPIN_ALL_BLOCKS_CMD) +#define FLASHCACHE_IS_ALL_BLOCKS_UNPIN _IOR(FLASHCACHE_IOCTL, FLASHCACHE_IS_ALL_BLOCKS_UNPIN_CMD, int) +#endif + +#define FLASHCACHEADDNCPID _IOW(FLASHCACHE_IOCTL, FLASHCACHEADDNCPID_CMD, pid_t) +#define FLASHCACHEDELNCPID _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELNCPID_CMD, pid_t) +#define FLASHCACHEDELNCALL _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELNCALL_CMD, pid_t) + +#define FLASHCACHEADDBLACKLIST FLASHCACHEADDNCPID +#define FLASHCACHEDELBLACKLIST FLASHCACHEDELNCPID +#define FLASHCACHEDELALLBLACKLIST FLASHCACHEDELNCALL + +#define FLASHCACHEADDWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEADDWHITELIST_CMD, pid_t) +#define FLASHCACHEDELWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELWHITELIST_CMD, pid_t) +#define FLASHCACHEDELALLWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELWHITELISTALL_CMD, pid_t) + +#ifdef __KERNEL__ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +int flashcache_ioctl(struct dm_target *ti, struct inode *inode, + struct file *filp, unsigned int cmd, + unsigned long arg); +#else +int flashcache_ioctl(struct dm_target *ti, unsigned int cmd, + unsigned long arg); +#endif +void flashcache_pid_expiry_all_locked(struct cache_c *dmc); +int flashcache_uncacheable(struct cache_c *dmc, struct bio *bio, int *uncache_seq); +void seq_io_remove_from_lru(struct cache_c *dmc, struct sequential_io *seqio); +void seq_io_move_to_lruhead(struct cache_c *dmc, struct sequential_io *seqio); +int skip_sequential_io(struct cache_c *dmc, struct bio *bio); +void flashcache_del_all_pids(struct cache_c *dmc, int which_list, int force); +#endif /* __KERNEL__ */ + +#endif diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_main.c b/drivers/syno/syno-mem-saving-driver/flashcache_main.c new file mode 100644 index 000000000000..cda91c849e4b --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_main.c @@ -0,0 +1,5710 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache_main.c + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) +#include +#include +#endif +#include "dm.h" +#include "dm-io.h" +#include "dm-bio-list.h" +#include "kcopyd.h" +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +#include "dm.h" +#endif +#include +#include +#include +#endif +#include "flashcache.h" +#include "flashcache_ioctl.h" +#ifdef MY_ABC_HERE +#include +#endif +#ifdef MY_ABC_HERE +#include +#endif + +#ifdef MY_ABC_HERE +#include "syno_quickflush.h" +#endif + +#ifdef MY_ABC_HERE +#include "syno_md_update.h" +#endif + +#ifndef DM_MAPIO_SUBMITTED +#define DM_MAPIO_SUBMITTED 0 +#endif + +/* + * TODO List : + * 1) Management of non cache pids : Needs improvement. Remove registration + * on process exits (with a pseudo filesstem'ish approach perhaps) ? + * 2) Breaking up the cache spinlock : Right now contention on the spinlock + * is not a problem. Might need change in future. + * 3) Use the standard linked list manipulation macros instead rolling our own. + * 4) Fix a security hole : A malicious process with 'ro' access to a file can + * potentially corrupt file data. This can be fixed by copying the data on a + * cache read miss. + */ + +#ifdef MY_ABC_HERE + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +#define DEBUG_STR "-debug" +#else +#define DEBUG_STR "" +#endif +#define FLASHCACHE_SW_VERSION "flashcache-1.0-syno-"SYNO_VERSION_NAME""DEBUG_STR + +#else +#define FLASHCACHE_SW_VERSION "flashcache-1.0-syno-" + +#endif /* MY_ABC_HERE*/ + +#else +#define FLASHCACHE_SW_VERSION "flashcache-1.0" +#endif +char *flashcache_sw_version = FLASHCACHE_SW_VERSION; + +static void flashcache_read_miss(struct cache_c *dmc, struct bio* bio, + int index); +static void flashcache_write(struct cache_c *dmc, struct bio* bio); +static int flashcache_inval_blocks(struct cache_c *dmc, struct bio *bio, + struct io_latency *plat, enum cache_io_type io_type); +#ifdef MY_ABC_HERE +#else +static void flashcache_dirty_writeback(struct cache_c *dmc, int index); +#endif +void flashcache_sync_blocks(struct cache_c *dmc); +static void flashcache_start_uncached_io(struct cache_c *dmc, struct bio *bio, + struct io_latency *plat, enum cache_io_type io_type); + + +#ifdef CONFIG_SYNO_DATA_CORRECTION +// List +struct correction_entry *correction_list_find_entry(struct cache_c *dmc, u64 bio_sector, + lock_type_t lock_type); + +// Entry +struct correction_entry *correcting_entry_alloc(u64 bio_sector); +int correction_entry_in_correcting(struct cache_c *dmc, u64 bio_sector, lock_type_t lock_type); +void correction_entry_set_abort_bitmap(struct cache_c *dmc, u64 bio_sector); +void correction_entry_record_cache_addr(struct cache_c *dmc, int index, sector_t bio_sector); + +// Range +int correction_range_set_type(struct cache_c *dmc, u64 bio_sector, correcting_type_t device_type); +correcting_type_t correction_range_get_type(struct cache_c *dmc, u64 bio_sector); + +// Flow +int correction_handle_retry_io_start(struct cache_c *dmc, u64 bio_sector); +void correction_send_force_abort_bios(struct work_struct *work); +struct bio* correction_alloc_abort_bio(struct cache_c *dmc, sector_t sector); +int correction_find_cache_index(struct cache_c *dmc, sector_t start_sector); +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + +extern u_int64_t size_hist[]; + +#ifdef MY_ABC_HERE +char *action_str[] = {"NONE", "READ_CACHE", "WRITE_CACHE", "READ_DISK", "WRITE_DISK", "READ_FILL", "INVALIDATE", "WRITEDISK_SYNC", "READDISKMEM", "WRITEMEMCACHE"}; + +static void read_disk_write_cache(struct cache_c *dmc, struct cacheblock *cacheblk, struct bio *bio, int index); + +sector_t bio_last_sector(struct bio *bio) +{ + VERIFY_WARN(bio); + return bio_bi_sector(bio) + bio_sectors(bio) - 1; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +extern struct dm_kcopyd_client *flashcache_kcp_client; /* Kcopyd client for writing back data */ +#else +extern struct kcopyd_client *flashcache_kcp_client; /* Kcopyd client for writing back data */ +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +extern struct dm_io_client *flashcache_io_client; /* Client memory pool*/ +#endif + +#ifdef SYNO_FLASHCACHE_DEBUG +struct _syno_debug syno_debug; +#endif + +int cache_schedule_work(struct work_struct *work) +{ + int ret = 0; +#ifdef MY_ABC_HERE + ret = queue_work(cache_workqueue, work); +#else + ret = schedule_work(work); +#endif /* MY_ABC_HERE */ + return ret; +} + +int cache_schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) +{ + int ret = 0; +#ifdef MY_ABC_HERE + ret = queue_delayed_work(cache_workqueue, dwork, delay); +#else + ret = schedule_delayed_work(dwork, delay); +#endif /* MY_ABC_HERE */ + return ret; +} + +#ifdef MY_ABC_HERE +int cache_mod_delayed_work(struct delayed_work *dwork, unsigned long delay) +{ + return mod_delayed_work(cache_workqueue, dwork, delay); +} +#endif + +#ifdef MY_ABC_HERE +/* Job memory is allocated by vmalloc to prevent the + * PAGE_ALLOC_COSTLY_ORDER constraint in kmalloc */ +int dm_io_vmem(unsigned int num_regions, + struct dm_io_region *where, + int comp_dm_op, + void *mem_addr, io_notify_fn fn, + void *context, unsigned long bi_flags) +{ + struct dm_io_request iorq = {0}; + int ret = 0; + + set_bi_op_and_flags(&iorq, comp_dm_op); + + iorq.mem.type = DM_IO_VMA; + iorq.mem.ptr.addr = mem_addr; + iorq.notify.fn = fn; + iorq.notify.context = context; + iorq.client = flashcache_io_client; + +#ifdef CONFIG_SYNO_DATA_CORRECTION + ret = syno_dm_io(&iorq, num_regions, where, NULL, bi_flags); +#else + ret = dm_io(&iorq, num_regions, where, NULL); +#endif + return ret; +} +#endif + +/* + * SYNO: Don't wrap as a new function in porting due to the arguments are changed + * For example, md_bio only existed for 3.14... + */ +int dm_io_async_bvec(unsigned int num_regions, + struct dm_io_region *where, + int comp_dm_op, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + struct bio *bio, io_notify_fn fn, +#else + struct bio_vec *bvec, io_notify_fn fn, +#endif + void *context, unsigned long bi_flags) +{ + struct dm_io_request iorq = {0}; + int ret = 0; + + set_bi_op_and_flags(&iorq, comp_dm_op); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + iorq.mem.type = DM_IO_BIO; + iorq.mem.ptr.bio = bio; +#else + iorq.mem.type = DM_IO_BVEC; + iorq.mem.ptr.bvec = bvec; +#endif + iorq.notify.fn = fn; + iorq.notify.context = context; + iorq.client = flashcache_io_client; + + /* + * WARNING: Should not pass all bio->bi_flags directly to dm_io + * Since bi_flags contain extran property (e.g. pool) that should not be set to + * a new bio in another pool + */ +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (bi_flags & (~((1 << BIO_CORRECTION_ABORT) | (1 << BIO_CORRECTION_RETRY)))) { + serr("Only allow to set BIO_CORRECTION_ABORT or BIO_CORRECTION_RETRY bitmap"); + VERIFY_WARN(0); + } + ret = syno_dm_io(&iorq, num_regions, where, NULL, bi_flags); +#else + if (bi_flags) { + serr("bi_flags should be 0"); + VERIFY_WARN(0); + } + ret = dm_io(&iorq, num_regions, where, NULL); +#endif + return ret; +} + +int dm_io_async_bio_wrapper(unsigned int num_regions, struct dm_io_region *where, + int comp_dm_op, struct bio *bio, io_notify_fn fn, + void *context, unsigned long bi_flags) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return dm_io_async_bvec(num_regions, where, comp_dm_op, bio, fn, context, bi_flags); +#else + return dm_io_async_bvec(num_regions, where, comp_dm_op, bio->bi_io_vec + bio_bi_idx(bio), + fn, context, bi_flags); +#endif +} + +/* + * A simple 2-hand clock like algorithm is used to identify dirty blocks + * that lie fallow in the cache and thus are candidates for cleaning. + * Note that we could have such fallow blocks in sets where the dirty blocks + * is under the configured threshold. + * The hands are spaced fallow_delay seconds apart (one sweep runs every + * fallow_delay seconds). The interval is configurable via a sysctl. + * Blocks are moved to DIRTY_FALLOW_1, if they are found to be in DIRTY_FALLOW_1 + * for fallow_delay seconds or more, they are moved to DIRTY_FALLOW_1 | DIRTY_FALLOW_2, + * at which point they are eligible for cleaning. Of course any intervening use + * of the block within the interval turns off these 2 bits. + * + * Cleaning of these blocks happens from the flashcache_clean_set() function. + */ +void +flashcache_detect_fallow(struct cache_c *dmc, int index) +{ + struct cacheblock *cacheblk = &dmc->cache[index]; +#ifdef MY_ABC_HERE +#else + struct cache_set *cacheset = &dmc->cache_sets[index / dmc->assoc]; +#endif + + if (dmc->cache_mode != FLASHCACHE_WRITE_BACK) + return; + +#ifdef MY_ABC_HERE + /* Only used as a hint. It's ok if we didn't mark a dirty block as + * fallow due to race condition, it will be handled next round */ + if ((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) != DIRTY || + cacheblk->cache_state & DIRTY_FALLOW_2) { + return; + } + + down_read(&dmc->oqf.bitmap_rwsem); + spin_lock_irq(&dmc->cache_spin_lock); +#endif + if ((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { + if ((cacheblk->cache_state & DIRTY_FALLOW_1) == 0) { + cb_state_add_bits_update_counts(dmc, cacheblk, DIRTY_FALLOW_1); + } else if ((cacheblk->cache_state & DIRTY_FALLOW_2) == 0) { + cb_state_add_bits_update_counts(dmc, cacheblk, DIRTY_FALLOW_2); +#ifdef MY_ABC_HERE + quickflush_set_volume_map(dmc, cacheblk); + atomic_inc(&dmc->oqf.nr_fallow); +#else + cacheset->dirty_fallow++; +#endif + } + } +#ifdef MY_ABC_HERE + spin_unlock_irq(&dmc->cache_spin_lock); + up_read(&dmc->oqf.bitmap_rwsem); +#endif +} + +void +flashcache_clear_fallow(struct cache_c *dmc, int index) +{ + struct cacheblock *cacheblk = &dmc->cache[index]; +#ifdef MY_ABC_HERE +#else + struct cache_set *cacheset = &dmc->cache_sets[index / dmc->assoc]; +#endif + + if (dmc->cache_mode != FLASHCACHE_WRITE_BACK) + return; + if (cacheblk->cache_state & FALLOW_DOCLEAN) { + if (cacheblk->cache_state & DIRTY_FALLOW_2) { +#ifdef MY_ABC_HERE + /* Do not unset fallow bitmap. A bit represents + * multiple volume block, let the writeback thread + * scan the volume blocks to unset it. */ + atomic_dec(&dmc->oqf.nr_fallow); +#else + VERIFY_WARN(cacheset->dirty_fallow > 0); + cacheset->dirty_fallow--; +#endif + } + cb_state_remove_bits_update_counts(dmc, cacheblk, FALLOW_DOCLEAN); + } +} + +#ifdef MY_ABC_HERE +int is_writeback_crash_safe(struct cache_c *dmc) +{ + int ret = 0; + + /* Our daemon has disable cache function and there're no dirty blocks */ + if ((FLASHCACHE_WRITE_BACK == dmc->cache_mode) && (0 == dmc->nr_dirty) && + (0 == dmc->sysctl_cache_all) && (0 == dmc->nr_synced)) { + ret = 1; + } + + return ret; +} + +int is_writeback_crash_safe_set_bypass(struct cache_c *dmc) +{ + int ret = 0; + unsigned long flags = 0; + + spin_lock_irqsave(&dmc->bypass_lock, flags); + if (is_writeback_crash_safe(dmc)) { + dmc->bypass_cache = 1; + ret = 1; + } + spin_unlock_irqrestore(&dmc->bypass_lock, flags); + + return ret; +} +#endif + + +#ifdef MY_ABC_HERE +static DEFINE_SPINLOCK(flashache_kmap_lock); + +/* + * Write job->mem_addr to bio synchronously + */ +static void write_mem_to_bio_sync(void *mem_addr, sector_t sector, struct bio *bio) +{ + unsigned char *mem_start = NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + struct bvec_iter iter = {0}; + struct bio_vec bvl = {0}; +#else + int iter; + struct bio_vec *bvl = NULL; +#endif + struct bio_vec *pbvl = NULL; + void *bvec_page_addr = NULL; + void *bvec_offset_addr = NULL; + unsigned long flags; + unsigned int handled_bytes = 0; + sector_t offset_sectors_in_cache_block = 0; + + VERIFY_WARN(bio); + VERIFY_WARN(mem_addr); + + VERIFY_WARN(bio_bi_sector(bio) >= sector); + offset_sectors_in_cache_block = bio_bi_sector(bio) - sector; + + bio_for_each_segment(bvl, bio, iter) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + pbvl = &bvl; +#else + pbvl = bvl; +#endif + /* + * For alpine platform, a page will accessed by multpile I/Os + * So use a spin_lock here + */ + spin_lock_irqsave(&flashache_kmap_lock, flags); + + // Don't use page_addrss due to it is too low-level function + bvec_page_addr = kmap_atomic(pbvl->bv_page); + VERIFY_WARN(bvec_page_addr != NULL); + + bvec_offset_addr = bvec_page_addr + pbvl->bv_offset; + + // Here to_bytes doesn't overflow here, due to the offset is small + mem_start = (unsigned char *)mem_addr + to_bytes(offset_sectors_in_cache_block) + handled_bytes; + + memcpy(bvec_offset_addr, mem_start, pbvl->bv_len); + + kunmap_atomic(bvec_page_addr); + bvec_page_addr = NULL; + spin_unlock_irqrestore(&flashache_kmap_lock, flags); + + handled_bytes += pbvl->bv_len; + } + + VERIFY_WARN(handled_bytes == bio_bi_size(bio)); +} + +// Dump memory as the output of xxd command +void mem_dump(struct kcached_job *job) +{ + unsigned char *mem_addr = job->mem_addr; + unsigned long bytes = job->mem_data_byte; + int i = 0; + char str[512] = {0}; + int n = 0; + int len = sizeof(str)/sizeof(str[0]); + + sdbg(DF_DETAIL, "dump start mem_addr=%p bytes=%lu bio sector=%llu", + job->mem_addr, bytes, (u64)bio_bi_sector(job->bio)); + + for (i = 0; i < bytes; i += 2) { + if (0 == i % 16) { + n += snprintf(str + n, len - n, "%08x: ", i); + } + n += snprintf(str + n, len - n, "%02x%02x", *(mem_addr + i), *(mem_addr + i + 1)); + + if (0 == ((i + 2) % 16)) { + n += snprintf(str + n, len - n, "\n"); + printk(KERN_DEBUG "%s", str); + n = 0; + } else { + n += snprintf(str + n, len - n, " "); + } + } + + sdbg(DF_DETAIL, "dump finish"); +} +#endif + +#ifdef MY_ABC_HERE +// Don't end bio for performing uncached I/O later +int no_need_to_end_bio(struct cache_c *dmc, int error, int disk_error, struct kcached_job *job) +{ + int no_need = 0; + int ssd_error = 0; + + // For WRITEMEMCACHE, don't set disk_error and treat it as accessing SSD error + if ((0 != error) && (0 == disk_error)) { + ssd_error = 1; + } + + if (!ssd_error) { + // Must end bio + goto end; + } + + // When access SSD error + + if ((FLASHCACHE_WRITE_AROUND == dmc->cache_mode) || + (FLASHCACHE_WRITE_THROUGH == dmc->cache_mode)) { + no_need = 1; + } else { + // WRITE_BACK cache + if (is_writeback_crash_safe(dmc)) { + + // Due to cache_all = 0 + VERIFY_WARN(READFILL != job->action); + VERIFY_WARN(WRITECACHE != job->action); + + if ((READCACHE == job->action) || (WRITEMEMCACHE == job->action)) { + no_need = 1; + } + } + } + + if (1 == no_need) { + if (printk_ratelimit()) { + DMERR("flashcache: Don't end this bio action=%d", job->action); + } + } + +end: + return no_need; +} +#endif + +/* under atomic context */ +void +flashcache_handle_job_finish(struct cache_c *dmc, struct kcached_job *job) +{ + unsigned long flags = 0; + struct cacheblock *cb = &dmc->cache[job->index]; + + /* + * The INPROG flag is still set. We cannot turn that off until all the pending requests + * processed. We need to loop the pending requests back to a workqueue. We have the job, + * add it to the pending req queue. + */ + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + + if (unlikely(job->error || cb->nr_queued > 0)) { + /* + * SYNO: + * Remove io range in do_pending_xxx + * XXX: Must consider following two cases + * Case: nr_queue > 0 + * Case: error + */ + if (!job->error) { + // redundent for WRITECACHE + cacheblk_add_data_range(cb, job->action_bitmap); + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + push_pending(job); + sdbg(DF_DETAIL, "act=%s push_pending - nr_queued=%d", action_str[job->action], cb->nr_queued); + cache_schedule_pending(); + } else { + // READDISKMEM won't go here + if (WRITEMEMCACHE == job->action) { + cacheblk_unset_all_io_range_change_state(dmc, cb); + } else { + cacheblk_remove_io_range_change_state(dmc, cb, job->action_bitmap); + } + + if (WRITECACHE == job->action) { + /* In WRITECACHE case without error, data range and dirty range should be + * set already. (legacy for WT mode?) */ + // TODO: consider remove + VERIFY_WARN(DIRTY & cb->cache_state); + VERIFY_WARN((cb->data_bitmap & job->action_bitmap) == job->action_bitmap); + VERIFY_WARN((cb->dirty_bitmap & job->action_bitmap) == job->action_bitmap); + cacheblk_add_data_range_and_dirty_range(cb, job->action_bitmap); + } else { + cacheblk_add_data_range(cb, job->action_bitmap); + } + cacheblk_dec_num_concurrent_and_return(cb); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + if (WRITECACHE == job->action) { + atomic_dec(&dmc->num_write_cache); + wake_up(&dmc->wait_io_done_queue); + } + push_to_free_jobs(job); + cache_schedule_to_free_jobs(); + sdbg(DF_DETAIL, "act=%s finish io", action_str[job->action]); + } +} + +/* + * SYNO: Change its suffix to _atomic to emphasize this function SHOULD NOT go sleep + * since it might be called under spin lock + */ +void +flashcache_io_callback_atomic(unsigned long error, void *context) +{ + struct kcached_job *job = (struct kcached_job *) context; + struct cache_c *dmc = job->dmc; + struct bio *bio; + unsigned long flags; + int index = job->index; + struct cacheblock *cacheblk = &dmc->cache[index]; + unsigned long disk_error = 0; +#ifdef CONFIG_SYNO_DATA_CORRECTION + int error_bits = 0; +#else + int error_bits = error; /* record the error bit */ +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + + VERIFY_WARN(index != -1); + bio = job->bio; + VERIFY_WARN(bio != NULL); +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (error & (1 << BIO_CORRECTION_ERR)) { + bio->bi_flags |= 1 << BIO_CORRECTION_ERR; + // Remove extra information from DM layer + error &= ~(1 << BIO_CORRECTION_ERR); + sdbg(DF_CORRECTION, "remove BIO_CORRECTION_ERR from bio, error=%lu", error); + } + error_bits = error; +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + if (unlikely(error)) { + error = -EIO; + if (dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) { + /* + * limit the message number to avoid kernel print a lot of messages and busy + * When action is WRITECACHE, it writes to 2 regions (1: disk 2: ssd). + * So when error_bit is 2, it fails to write to SSD + */ + if ((job->action == WRITECACHE && error_bits == 2) + || (job->action == READFILL && error_bits == 1) + || (job->action == READCACHE && error_bits == 1)) { + if (printk_ratelimit()) { + DMERR("flashcache_io_callback_atomic: io error %ld block %llu action %d bypass=%d error_bits=%d", + error, (u64)job->job_io_regions.disk.sector, job->action, dmc->bypass_cache, error_bits); + } + } + } else if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { + if (printk_ratelimit()) { + DMERR("flashcache_io_callback_atomic: WRITE_BACK mode gets error io error %ld action=%d bypass=%d error_bits=%d", + error, job->action, dmc->bypass_cache, error_bits); + } + } else { + DMERR("flashcache_io_callback_atomic: io error %ld block %llu action %d", + error, (u64)job->job_io_regions.disk.sector, job->action); + } + + if (!dmc->bypass_cache) { + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + if (is_writeback_crash_safe_set_bypass(dmc)) { + /* when cache in degradation or recovery mode, and second SSD fail */ + DMERR("flashcache_io_callback_atomic: WRITE_BACK mode enables BYPASS"); + } else { + if (printk_ratelimit()) { + DMERR("flashcache_io_callback_atomic: WRITE_BACK mode fails, can't bypass data"); + } + } + } else { + DMERR("flashcache_io_callback_atomic: switching %s to BYPASS mode", + dmc->cache_devname); + dmc->bypass_cache = 1; + } + } + } + job->error = error; + + switch (job->action) { + case READDISK: + DPRINTK("flashcache_io_callback_atomic: READDISK %d", + index); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (unlikely(dmc->sysctl_error_inject & READDISK_ERROR)) { + error = -EIO; + job->error = -EIO; + dmc->sysctl_error_inject &= ~READDISK_ERROR; + } + VERIFY_WARN(cacheblk->cache_state & DISKREADINPROG); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + flashcache_check_record_io_latency(LAT_DISK_READ, &job->io_lat); + + if (likely(error == 0)) { + /* Kick off the write to the cache */ + job_dbg("READDISK", job); + sdbg(DF_DETAIL, "act=%s call readfill return", action_str[job->action]); + job->action = READFILL; + push_io(job); + cache_schedule_io(); + return; + } else { + disk_error = -EIO; + atomic_inc(&dmc->flashcache_errors.disk_read_errors); + } + break; + case READDISKMEM: + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + VERIFY_WARN(cacheblk->cache_state & DISKREADINPROG); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + flashcache_check_record_io_latency(LAT_DISK_READ_MEM, &job->io_lat); + + if (likely(error == 0)) { + job_dbg("READDISKMEM", job); + sdbg(DF_DETAIL, "act=%s call WRITEMEMCACHE", action_str[job->action]); + job->action = WRITEMEMCACHE; + push_io(job); + cache_schedule_io(); + return; + } else { + disk_error = -EIO; + atomic_inc(&dmc->flashcache_errors.disk_read_errors); + } + + break; + + case WRITEMEMCACHE: + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + if (unlikely(error)) + atomic_inc(&dmc->flashcache_errors.ssd_write_errors); + + VERIFY_WARN(cacheblk->cache_state & DISKREADINPROG); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + flashcache_check_record_io_latency(LAT_MEM_WRITE_SSD, &job->io_lat); + + // In flashacache, read data from disk to cache doesn't update metadata + if (likely(0 == error)) { + // write to bio synchronously + write_mem_to_bio_sync(job->mem_addr, job->job_io_regions.disk.sector, job->bio); + } else { + if (printk_ratelimit()) { + DPRINTK("flashcache_io_callback_atomic: WRITEMEMCACHE failed"); + } + } + break; + case READCACHE: + DPRINTK("flashcache_io_callback_atomic: READCACHE %d", + index); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (unlikely(dmc->sysctl_error_inject & READCACHE_ERROR)) { + error = -EIO; + job->error = -EIO; + dmc->sysctl_error_inject &= ~READCACHE_ERROR; + } + VERIFY_WARN(cacheblk->cache_state & CACHEREADINPROG); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + flashcache_check_record_io_latency(LAT_SSD_READ, &job->io_lat); + + if (unlikely(error)) + atomic_inc(&dmc->flashcache_errors.ssd_read_errors); +#ifdef FLASHCACHE_DO_CHECKSUMS + if (likely(error == 0)) { + if (flashcache_validate_checksum(job)) { + DMERR("flashcache_io_callback_atomic: Checksum mismatch at disk offset %lu", + job->job_io_regions.disk.sector); + error = -EIO; + } + } +#endif + break; + case READFILL: + DPRINTK("flashcache_io_callback_atomic: READFILL %d", + index); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (unlikely(dmc->sysctl_error_inject & READFILL_ERROR)) { + error = -EIO; + job->error = -EIO; + dmc->sysctl_error_inject &= ~READFILL_ERROR; + } + if (unlikely(error)) + atomic_inc(&dmc->flashcache_errors.ssd_write_errors); + VERIFY_WARN(cacheblk->cache_state & DISKREADINPROG); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + flashcache_check_record_io_latency(LAT_SSD_WRITE, &job->io_lat); + + break; + case WRITECACHE: + DPRINTK("flashcache_io_callback_atomic: WRITECACHE %d", + index); + if (unlikely(dmc->sysctl_error_inject & WRITECACHE_ERROR)) { + error = -EIO; + job->error = -EIO; + dmc->sysctl_error_inject &= ~WRITECACHE_ERROR; + } + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + VERIFY_WARN(cacheblk->cache_state & CACHEWRITEINPROG); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + flashcache_check_record_io_latency(LAT_SSD_WRITE, &job->io_lat); + + if (likely(error == 0)) { + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); +#ifdef MY_ABC_HERE + // Set shared data in critical region + atomic64_inc(&dmc->flashcache_stats.md_write_dirty); + if ((cacheblk->cache_state & DIRTY) == 0) { + dmc->nr_dirty++; + } + cb_state_add_bits_update_counts(dmc, cacheblk, DIRTY); + if ((cacheblk->cache_state & SYNCED_BITS)) { + cb_state_remove_bits_update_counts(dmc, cacheblk, SYNCED_BITS); + dmc->nr_synced--; + if (0 == dmc->nr_synced) { + wake_up(&dmc->new_mu.remove_wqh); + } + } +#endif +#ifdef FLASHCACHE_DO_CHECKSUMS + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + atomic64_inc(&dmc->flashcache_stats.checksum_store); + flashcache_store_checksum(job); + // Shared data should be in critical region + sdbg(DF_DETAIL, "act=%s index=%d finish return", action_str[job->action], job->index); + /* + * We need to update the metadata on a DIRTY->DIRTY as well + * since we save the checksums. + */ +#ifdef MY_ABC_HERE + /* Have to queue md update BEFORE endio. So following flush requests + * got correct md updates. */ + syno_mu_queue_no_flush_update(dmc, job); +#else + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + // Should add dta bitmap here for mdblock update + cacheblk_add_data_range_and_dirty_range(cacheblk, job->action_bitmap); + spin_unlock_irqsrestore(&dmc->cache_spin_lock, flags); + flashcache_md_write(job); +#endif +#else // END OF (#ifdef FLASHCACHE_DO_CHECKSUMS) + + /* + * Don't use data bitmap to check if metadata update is needed + * Due to read opertion also set it + * + * FUA always requires md update, since we don't know if the dirty bitmap + * has been written to SSD. + */ + if (cacheblk_is_dirty_range_going_to_change(cacheblk, job->action_bitmap) + || bio_has_fua_flags(job->bio)) { + // Should add data_bitmap before updating metadata blocks + cacheblk_add_data_range_and_dirty_range(cacheblk, job->action_bitmap); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); +#ifdef MY_ABC_HERE + + /* Have to queue md update BEFORE endio. So following flush requests + * got correct md updates. */ + if (bio_has_fua_flags(job->bio)) { + syno_mu_queue_no_flush_fua_update(dmc, job); + return; + } else { + syno_mu_queue_no_flush_update(dmc, job); + } +#else + flashcache_md_write(job); + sdbg(DF_DETAIL, "act=%s index=%d finish return", action_str[job->action], job->index); + return; +#endif + } else { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + } +#endif + } else { /* cache_mode == WRITE_THROUGH */ + /* Writs to both disk and cache completed */ + VERIFY_WARN(dmc->cache_mode == FLASHCACHE_WRITE_THROUGH); +#ifdef FLASHCACHE_DO_CHECKSUMS + flashcache_store_checksum(job); + atomic64_inc(&job->dmc->flashcache_stats.checksum_store); +#endif + } + } else { + /* job error */ + if (dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) { + if (2 == error_bits) { + atomic_inc(&dmc->flashcache_errors.ssd_write_errors); + } else if (1 == error_bits) { + disk_error = -EIO; + atomic_inc(&dmc->flashcache_errors.disk_write_errors); + } + } else { + atomic_inc(&dmc->flashcache_errors.ssd_write_errors); + } + } + break; + } + /* + * If we get an error in write through || write around modes, + * we try the disk directly, after invalidating the cached block. + * see flashcache_do_pending_error(). + * XXX - We can do the same for writeback as well. But that is more + * work. (a) we cannot fall back to disk when a ssd read of a dirty + * cacheblock fails (b) we'd need to handle ssd metadata write + * failures as well and fall back to disk in those cases as well. + * + * We track disk errors separately. If we get a disk error (in + * writethru or writearound modes) end the IO right here. + */ + + /* + * Go Here in normal state + * WRITECACHE / READFILL / READCACHE / WRITECACHE (WT mode) / WRITEMEMCACHE + * + * Go Here only when error + * READDISK + * READDISKMEM + */ + + if (no_need_to_end_bio(dmc, error, disk_error, job)) { + /* + * Don't end bio for performing uncached I/O in error handing + * - WRITE_AROUND & WRITE_THROUGH: Any access SSD error + * - WRITE_BACK: In crash save mode with read SSD error + */ + } else { + /* + * End bio in following cases (Set bio = NULL) + * 1. READ / Write disk with error => do_pendig_error() + * 2. No error happen => do_pending_no_error() + */ + flashcache_bio_endio(bio, error, dmc, job->io_start_time, &job->io_lat); + job->bio = NULL; + } + + flashcache_handle_job_finish(dmc, job); +} + +void +flashcache_free_pending_jobs(struct cache_c *dmc, struct cacheblock *cacheblk, + int error) +{ + struct pending_job *pending_job, *freelist = NULL; + + VERIFY_WARN(spin_is_locked(&dmc->cache_spin_lock)); + freelist = flashcache_deq_pending(dmc, cacheblk - &dmc->cache[0]); + while (freelist != NULL) { + pending_job = freelist; + freelist = pending_job->next; + VERIFY_WARN(cacheblk->nr_queued > 0); + cacheblk->nr_queued--; + flashcache_bio_endio(pending_job->bio, error, dmc, ktime_zero, &pending_job->io_lat); + flashcache_free_pending_job(pending_job); + } + VERIFY_WARN(cacheblk->nr_queued == 0); +} + +typedef struct do_pending_params { + struct cache_c *dmc; + struct bio *bio; + int index; + int error; + int action; + bitmap_t action_bitmap; + struct io_latency *plat; + ktime_t *io_start_time; + void *mem_addr; + sector_t sector; +} dp_params_t; + +/* + * Common error handling for everything. + * 1) If the block isn't dirty, invalidate it. + * 2) De-link all pending IOs that totally or partly overlap this block. + * 3) If it was an SSD error (bio != NULL), issue the invalidated block IO and other de-linked pending IOs uncached to disk. + * 4) Free the job. + * SYNO: + * Handing following cases: + * - Access SSD error (bio != 0) , perform uncached_io for this job and all pending jobs + * (bio != 0 because it's still possbile to access from the disks for workaround) + * - Access Disk error (bio = 0), free all pending job with errror + */ +static void +flashcache_do_pending_error(dp_params_t *params) +{ + struct cache_c *dmc = params->dmc; + struct bio *bio = params->bio; + struct cacheblock *cacheblk = &dmc->cache[params->index]; + struct pending_job *pjob_list = NULL, *pjob = NULL; + int write_back_crash_safe = 0; + int pending_jobs_handled = 0; + u_int8_t nr_concurrent = 0; + int is_last_job = 1; +#ifdef MY_ABC_HERE +#else + struct cache_set *cacheset = &dmc->cache_sets[params->index / dmc->assoc]; +#endif + + + if ((is_writeback_crash_safe_set_bypass(dmc))) { + /* + * Write back cache has degraded before and we already disabled cache and flush all + * dirty blocks + */ + write_back_crash_safe = 1; + // In some paths (e.g. dirty_writeback), the bypass_cache is not set yet, so set here + } + + spin_lock_irq(&dmc->cache_spin_lock); + + // All the WRITEDISK_SYNC jobs that has errors go here + if (WRITEDISK_SYNC == params->action) { + atomic_inc(&dmc->flashcache_errors.write_disk_sync_errors); + } + + if (!dmc->bypass_cache) { + if (0 < dmc->limits.do_pending_err) { + DMERR("flashcache_do_pending_error: error %d block %llu action %d", + params->error, (u64)params->sector, params->action); + dmc->limits.do_pending_err--; + } + } + + VERIFY_WARN(cacheblk->cache_state & VALID); + + nr_concurrent = cacheblk_dec_num_concurrent_and_return(cacheblk); + + if (0 != nr_concurrent) { + is_last_job = 0; + } + + // Only invalidate the cache block when the job is the last job + if (is_last_job) { + /* Invalidate block if possible */ +#ifdef MY_ABC_HERE + /* SYNCED_BITS block can not be invalidated */ + if ((cacheblk->cache_state & DIRTY) == 0 && (cacheblk->cache_state & SYNCED_BITS) == 0) { + /* in new mu we set dirty bitmap along with states */ + VERIFY_WARN(0 == cacheblk->dirty_bitmap); +#else + if ((cacheblk->cache_state & DIRTY) == 0) { + /* + * For our implementation, the dirty_bitmap might be set before an error happens + * At the same time, DIRTY is still 0 + */ + if (0 != cacheblk->dirty_bitmap) { + cacheblk_unset_all_dirty_range(cacheblk); + } +#endif + atomic64_dec(&dmc->cached_blocks); + atomic64_inc(&dmc->flashcache_stats.pending_inval); + cb_state_remove_bits_update_counts(dmc, cacheblk, VALID); +#ifdef MY_ABC_HERE + cacheblk_check_unset_pin_state(dmc, cacheblk); +#endif + cb_state_add_bits_update_counts(dmc, cacheblk, INVALID); + + } else if ((WRITEDISK_SYNC == params->action) && (ATTR_FORCE_REMOVE == dmc->attribute)) { + /* + * WRITEDISK_SYNC: Remove cache or do_sync command + */ + if (0 < dmc->limits.dirty_inval) { + serr("Forcibly remove cacheblock [index=%d dbn=%llu error]," + "invalidate it\n", params->index, (u64)cacheblk->dbn); + dmc->limits.dirty_inval--; + } + + if (cacheblk->cache_state & DIRTY) { + dmc->nr_dirty--; +#ifdef MY_ABC_HERE +#else + cacheset->nr_dirty--; +#endif + cb_state_remove_bits_update_counts(dmc, cacheblk, DIRTY); + } + + +#ifdef MY_ABC_HERE + if (cacheblk->cache_state & SYNCED_BITS) { + cb_state_remove_bits_update_counts(dmc, cacheblk, SYNCED_BITS); + dmc->nr_synced--; + if (0 == dmc->nr_synced) { + wake_up(&dmc->new_mu.remove_wqh); + } + } +#endif + + if (0 != cacheblk->dirty_bitmap) { + cacheblk_unset_all_dirty_range(cacheblk); + } + + atomic64_dec(&dmc->cached_blocks); + atomic64_inc(&dmc->flashcache_stats.pending_inval); + cb_state_remove_bits_update_counts(dmc, cacheblk, VALID); +#ifdef MY_ABC_HERE + cacheblk_check_unset_pin_state(dmc, cacheblk); +#endif + cb_state_add_bits_update_counts(dmc, cacheblk, INVALID); + } else { + // In other cases, if the cache block is dirty, just keep it in SSDs + VERIFY_WARN(dmc->cache_mode == FLASHCACHE_WRITE_BACK); + } + + } // if (is_last_job) + + /* + * Check io_callback and md_write_done + * io_range are not removed before this function if an error happens + * (See kcopyd_callback as a example) + * bio might be NULL shometimes, so don't use bio here + */ + if (READDISKMEM == params->action || WRITEMEMCACHE == params->action + || WRITEDISK == params->action || WRITEDISK_SYNC == params->action) { + cacheblk_unset_all_io_range_change_state(dmc, cacheblk); + } else { + cacheblk_remove_io_range_change_state(dmc, cacheblk, params->action_bitmap); + } + + if (is_last_job) { + VERIFY_WARN(0 == cacheblk->io_bitmap); + } + + if (!is_last_job) { + spin_unlock_irq(&dmc->cache_spin_lock); + goto handle_single_job; + } + + /* + * In case of an error in writethrough or writearound modes, if there + * are pending jobs, de-link them from the cacheblock so we can issue disk + * IOs below. + */ + if (bio != NULL) { + // SYNO: Access SSD error + /* + * If is_writeback_crash_safe is true && bypass mode, the mode can be write back + * Note: By default, in io_callback the bio should be set to NULL in write-back mode + * but we change the behavior ! + */ + if (!(is_writeback_crash_safe(dmc) && dmc->bypass_cache)) { + VERIFY_WARN(dmc->cache_mode != FLASHCACHE_WRITE_BACK); + } + + // SYNO: just to reduce the nr_queue count + pjob_list = flashcache_deq_pending(dmc, cacheblk - &dmc->cache[0]); + for (pjob = pjob_list ; pjob != NULL ; pjob = pjob->next) { + VERIFY_WARN(cacheblk->nr_queued > 0); + cacheblk->nr_queued--; + } + VERIFY_WARN(cacheblk->nr_queued == 0); + } else { + /* + * SYNO: Normal disk IO or dirty block writeback IO error + * Free each pending jobs (return error) + */ + flashcache_free_pending_jobs(dmc, cacheblk, params->error); + } + spin_unlock_irq(&dmc->cache_spin_lock); + +handle_single_job: + + if (bio != NULL) { + /* + * SYNO: Write back mode also go here and only be invalidated in some cases + * + * Cache (read/write) error in write through or write around + * mode. Issue the IO directly to disk. We've already invalidated + * the cache block above. + */ + if (dmc->cache_mode == FLASHCACHE_WRITE_THROUGH && (params->action == WRITECACHE || params->action == READFILL)) { + /* + * Writing to SSD fails in WRITECACHE or READFILL mode + * We discard this bio + */ + params->error = 0; + flashcache_bio_endio(bio, params->error, dmc, *params->io_start_time, params->plat); + + } else if ((FLASHCACHE_WRITE_BACK == dmc->cache_mode) && (0 == write_back_crash_safe)) { + // TODO: Seems it's a dead logic, if a bio is presented here in writeback mode then it must be + // write_back_crash_safe. Replace This logic with VERIFY_WARN(0) + VERIFY_WARN(0); + + // Should return the error to warn the file system as soon as possible + flashcache_bio_endio(bio, params->error, dmc, *params->io_start_time, params->plat); + flashcache_free_pending_jobs(dmc, cacheblk, params->error); + pending_jobs_handled = 1; + } else { + /* + * Other cases enter here: + * - Write through mode: read SSD failed + * - Write back mode (crash save state): read / write SSD failed + * - Write around mode: read SSD failed + */ + spin_lock_irq(&dmc->cache_spin_lock); + if (0 < dmc->limits.uncached_io) { + DMERR("%s: Start to perform uncached io\n", __func__); + dmc->limits.uncached_io--; + } + spin_unlock_irq(&dmc->cache_spin_lock); + VERIFY_WARN(params->plat); + flashcache_start_uncached_io(dmc, bio, params->plat, TYPE_DONT_CARE); + } + + if (is_last_job && (!pending_jobs_handled)) { + while (pjob_list != NULL) { + pjob = pjob_list; + pjob_list = pjob->next; + flashcache_start_uncached_io(dmc, pjob->bio, + &pjob->io_lat, TYPE_DONT_CARE); + flashcache_free_pending_job(pjob); + } + } + } // SYNO: if bio != NULL +} + + +// Must all pending job is READCACHE and no pending job are INVALIDATE +static int +check_can_pending_preread(int action, struct pending_job *freelist) +{ + struct pending_job *pending_job = NULL; + int can_pending_preread = 0; + + VERIFY_WARN(freelist); + + if (WRITEMEMCACHE != action) { + sdbg(DF_DETAIL, "action is not WRITEMEMCACHE"); + return 0; + } + + pending_job = freelist; + + for (pending_job = freelist; pending_job != NULL; pending_job = pending_job->next) { + + if ((READCACHE != pending_job->action) || (INVALIDATE == pending_job->action)) { + goto end; + } + } + + + can_pending_preread = 1; + +end: + return can_pending_preread; +} + +#ifdef MY_ABC_HERE +/* It's only a helper function used by do_pending_noerror/invalid_block_set + * in under cache_spin_lock, out NOT under lock */ +static void start_force_mu_to_invalid(struct cache_c *dmc, int index) +{ + struct cacheblock *cb = &dmc->cache[index]; + + VERIFY_WARN(dmc->cache_mode == FLASHCACHE_WRITE_BACK); + VERIFY_WARN(0 == cb->io_bitmap); + VERIFY_WARN(0 != cb->data_bitmap); + VERIFY_WARN(!(cb->cache_state & BLOCK_IO_INPROG)); + VERIFY_WARN(!(cb->cache_state & FALLOW_DOCLEAN)); + + cb_state_add_bits_update_counts(dmc, cb, DISKWRITEINPROG); + cacheblk_set_all_io_range(cb); + + cacheblk_add_num_concurrent(cb); + spin_unlock_irq(&dmc->cache_spin_lock); + + while (check_new_error_inject(dmc, SYNCED_STATE_CHANGE_WHEN_FORCE_MU)) { + sprint("Detect sync state change when force mu flag, wait, dbn %lld", + (u64)cb->dbn); + msleep(5000); + if (!(cb->cache_state & SYNCED_BITS)) { + sprint("State change from SYNCED_BITS to valid, continue"); + break; + } + } + + /* The status might change from SYNCED_BITS to VALID here */ + syno_mu_queue_force_update(dmc, index); +} +#endif + +/* It's only a helper function used by do_pending_noerror/invalid_block_set + * in under cache_spin_lock, out NOT under lock */ +static void start_force_wb_to_invalid(struct cache_c *dmc, int index) +{ + struct cacheblock *cb = &dmc->cache[index]; + int nr_write = 1; +#ifdef MY_ABC_HERE + cb_wb_param_t wb_param = {0}; + unsigned long wb_flags = 0; +#endif + + VERIFY_WARN(dmc->cache_mode == FLASHCACHE_WRITE_BACK); + VERIFY_WARN(0 == cb->io_bitmap); + VERIFY_WARN(0 != cb->data_bitmap); + VERIFY_WARN(!(cb->cache_state & BLOCK_IO_INPROG)); + +#ifdef MY_ABC_HERE + nr_write = quickflush_cacheblk_get_nr_writeback(dmc, index); + spin_lock_irqsave(&dmc->plug_wb.lock, wb_flags); + set_wb_attrs(dmc, index, nr_write); + spin_unlock_irqrestore(&dmc->plug_wb.lock, wb_flags); +#else + set_wb_attrs(dmc, index, nr_write); +#endif + + spin_unlock_irq(&dmc->cache_spin_lock); +#ifdef MY_ABC_HERE + wb_param.idx = index; + wb_param.nr_write = nr_write; + wb_param.job_flag |= JOB_WB_FORCED; + quickflush_dirty_writeback(dmc, wb_param); +#else + flashcache_dirty_writeback(dmc, index); +#endif +} + +static void +flashcache_do_pending_noerror(dp_params_t *params) +{ + struct cache_c *dmc = params->dmc; + int index = params->index; + struct pending_job *pending_job, *freelist; + int queued; + struct cacheblock *cacheblk = &dmc->cache[index]; + int can_pending_preread = 0; + u_int8_t nr_concurrent = 0; + + spin_lock_irq(&dmc->cache_spin_lock); + + /* + * For partial access, we wait for the last one job (nr_concurrent = 1) to perform this + * It is OK to clear some io_bitmap, due to nr->queue > 0, no one will access anymore + * READFILL / READCACHE / WRITE_DISK(WT mode) enter this function + */ + + nr_concurrent = cacheblk_dec_num_concurrent_and_return(cacheblk); + + // If it can be preread, its io_bitmap will be added back later + if (params->action == WRITEMEMCACHE) { + cacheblk_unset_all_io_range(&dmc->cache[index]); + VERIFY_WARN(0 == nr_concurrent); + } else { + cacheblk_remove_io_range(&dmc->cache[index], params->action_bitmap); + } + + if (0 != nr_concurrent) { + sdbg(DF_DETAIL, "index=%d In io, nr_concurrent=%d act=%s io_bitmap=0x%x cache_state=0x%x ", + index, nr_concurrent, action_str[params->action], cacheblk->io_bitmap, cacheblk->cache_state); + spin_unlock_irq(&dmc->cache_spin_lock); + goto out; + } + + // nr_concurrent is 0 + sdbg(DF_DETAIL, "index=%d Clean pending queue, nr_concurrent=%d act=%s io_bitmap=0x%x cache_state=0x%x ", + index, nr_concurrent, action_str[params->action], cacheblk->io_bitmap, cacheblk->cache_state); + +#ifdef MY_ABC_HERE + if (cacheblk->cache_state & SYNCED_BITS) { + VERIFY_WARN(!(cacheblk->cache_state & FORCEDMU)); + /* Unlocked in function */ + cb_state_remove_bits_update_counts(dmc, cacheblk, BLOCK_IO_INPROG); + start_force_mu_to_invalid(dmc, index); + goto out; + } +#endif + + if (cacheblk->cache_state & DIRTY) { + /* Unlocked in function */ + cb_state_remove_bits_update_counts(dmc, cacheblk, BLOCK_IO_INPROG); + atomic64_inc(&dmc->flashcache_stats.do_pending_no_error_drity_writeback); + start_force_wb_to_invalid(dmc, index); + goto out; + } + + DPRINTK("flashcache_do_pending: Index %d %lx", + index, cacheblk->cache_state); + VERIFY_WARN(cacheblk->cache_state & VALID); + sdbg(DF_DETAIL, "try to deq and invalidate blocks..."); + + freelist = flashcache_deq_pending(dmc, index); + + // This job is WRITEMEMCACHE (preread) + can_pending_preread = check_can_pending_preread(params->action, freelist); + + // reclaim V won't be triggered Because BLOCK_IN_PROG is still set + if (can_pending_preread) { + sdbg(DF_DETAIL, "index=%d can_pending_preread", index); + VERIFY_WARN(cacheblk->io_bitmap == 0); + // don't set to INVALID + cacheblk_set_all_io_range(cacheblk); + } else { +#ifdef CONFIG_SYNO_DATA_CORRECTION + sdbg(DF_CORRECTION, "Set abort bitmap if needed"); + correction_entry_record_cache_addr(dmc, index, cacheblk->dbn); + correction_entry_set_abort_bitmap(dmc, cacheblk->dbn); +#endif + atomic64_dec(&dmc->cached_blocks); + atomic64_inc(&dmc->flashcache_stats.pending_inval); + cb_state_remove_bits_update_counts(dmc, cacheblk, VALID); +#ifdef MY_ABC_HERE + cacheblk_check_unset_pin_state(dmc, cacheblk); + // Here the BLOCK_IN_PROG is still set +#endif + cb_state_add_bits_update_counts(dmc, cacheblk, INVALID); + } + + /* + * Already get freelist in above code + * No need to use "while" freelist, due to we set INVALID for this cacheblock + * No one can get it VALID and enqueue anymore + * XXX: However, it might cause the new I/O will access disks when there pending job + * are performing uncached I/O ? + */ + while (freelist != NULL) { + VERIFY_WARN(!(cacheblk->cache_state & DIRTY)); + VERIFY_WARN(!(cacheblk->cache_state & SYNCED_BITS)); + pending_job = freelist; + freelist = pending_job->next; + VERIFY_WARN(cacheblk->nr_queued > 0); + cacheblk->nr_queued--; + if (pending_job->action == INVALIDATE) { + // job wait for range invalidate, follwoing value should not be set + VERIFY_WARN(0 == can_pending_preread); + DPRINTK("flashcache_do_pending: INVALIDATE %llu", + bio_bi_sector(pending_job->bio)); + VERIFY_WARN(pending_job->bio != NULL); + queued = flashcache_inval_blocks(dmc, pending_job->bio, + &pending_job->io_lat, TYPE_DONT_CARE); + /* The invalidate here might queue becuase below code in + * the loop unlock cache spinlock, external + * IO might come in and create a valid block. */ + if (queued) { + atomic64_inc(&dmc->flashcache_stats.do_pending_no_error_inval); + if (unlikely(queued < 0)) { + /* + * Memory allocation failure inside inval_blocks. + * Fail this io. + */ + flashcache_bio_endio(pending_job->bio, + -EIO, dmc, ktime_zero, &pending_job->io_lat); + } + flashcache_free_pending_job(pending_job); + atomic64_inc(&dmc->flashcache_stats.pending_enqueue_inval_done); + continue; + } + } + if (can_pending_preread) { + // don't unlock irq to avoid new I/O being queue that wont' be handled + write_mem_to_bio_sync(params->mem_addr, params->sector, pending_job->bio); + // Just make io_start_time as NULL + flashcache_bio_endio(pending_job->bio, 0, dmc, ktime_zero, &pending_job->io_lat); + flashcache_free_pending_job(pending_job); + atomic64_inc(&dmc->flashcache_stats.pending_preread); + atomic64_inc(&dmc->flashcache_stats.read_hits); + } else { + /* + * Original logic + * XXX: If unlocking here, new I/O whould be added to the queue list ? + */ + if (INVALIDATE == pending_job->action) { + atomic64_inc(&dmc->flashcache_stats.pending_enqueue_inval_done); + } + spin_unlock_irq(&dmc->cache_spin_lock); + DPRINTK("flashcache_do_pending: Sending down IO %llu", + bio_bi_sector(pending_job->bio)); + /* Start uncached IO */ + flashcache_start_uncached_io(dmc, pending_job->bio, + &pending_job->io_lat, TYPE_DONT_CARE); + flashcache_free_pending_job(pending_job); + spin_lock_irq(&dmc->cache_spin_lock); + + } + + } + VERIFY_WARN(cacheblk->nr_queued == 0); + + if (can_pending_preread) { + cacheblk_unset_all_io_range_change_state(dmc, cacheblk); + } else { + // SYNO: only the last partial access I/O will enter here + VERIFY_WARN(0 == cacheblk->io_bitmap); + + if (global_tester == TEST_OQF_INVALIDATE_DELAY) { + spin_unlock_irq(&dmc->cache_spin_lock); + while (global_tester == TEST_OQF_INVALIDATE_DELAY) { + serr("Get invalidate delay for %d", index); + msleep(5000); + } + serr("invalidate delay done"); + spin_lock_irq(&dmc->cache_spin_lock); + } + + cb_state_remove_bits_update_counts(dmc, cacheblk, BLOCK_IO_INPROG); + } + + spin_unlock_irq(&dmc->cache_spin_lock); +out: + + sdbg(DF_DETAIL, "finish"); +} + +/* + * Call this function when job->error is set or cacheblk->nr_queue > 0 + * + * Note: do_pending* only called from non-atomic context + */ +void +flashcache_do_pending(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + dp_params_t params = { + .dmc = job->dmc, + .bio = job->bio, + .index = job->index, + .error = job->error, + .action = job->action, + .action_bitmap = job->action_bitmap, + .plat = &job->io_lat, + .io_start_time = &job->io_start_time, + .mem_addr = job->mem_addr, + .sector = job->job_io_regions.disk.sector, + }; + + if (job->error) { + flashcache_do_pending_error(¶ms); + } else { + flashcache_do_pending_noerror(¶ms); + } + + if (WRITECACHE == job->action) { + atomic_dec(&dmc->num_write_cache); + wake_up(&dmc->wait_io_done_queue); + } + + flashcache_free_cache_job(job); + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } +} + +#ifdef MY_ABC_HERE +void flashcache_do_pending_force_mu(struct cache_c *dmc, int idx, int error) { + dp_params_t params = { + .dmc = dmc, + .bio = NULL, + .index = idx, + .error = error, + .action = WRITEDISK_SYNC, // to allow force remove + .action_bitmap = BITMAP_MASK, + .plat = NULL, + .io_start_time = NULL, + .mem_addr = NULL, + .sector = 0, + }; + + if (error) { + flashcache_do_pending_error(¶ms); + } else { + flashcache_do_pending_noerror(¶ms); + } + + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } +} +#endif + +void +flashcache_do_io(struct kcached_job *job) +{ + struct bio *bio = job->bio; + int r = 0; + + VERIFY_WARN(job->action == READFILL || job->action == WRITEMEMCACHE); +#ifdef FLASHCACHE_DO_CHECKSUMS + flashcache_store_checksum(job); + atomic64_inc(&job->dmc->flashcache_stats.checksum_store); +#endif + /* Write to cache device */ + atomic64_inc(&job->dmc->flashcache_stats.ssd_writes); + + job_dbg(__func__, job); + + flashcache_check_record_io_latency(LAT_DO_IO_WQ, &job->io_lat); + + if (READFILL == job->action) { + r = dm_io_async_bio_wrapper(1, &job->job_io_regions.cache, COMP_DM_WRITE, + bio, flashcache_io_callback_atomic, job, 0); + } else { + // WRITEMEMCACHE + r = dm_io_vmem(1, &job->job_io_regions.cache, COMP_DM_WRITE, job->mem_addr, + flashcache_io_callback_atomic, job, 0); + } + VERIFY_WARN(r == 0); + /* In our case, dm_io_async_bvec() must always return 0 */ +} + +#ifdef MY_ABC_HERE +// Refer to include/linux/hash.h, copy here to prevent hash function change +static __always_inline u64 hash_64_cache(u64 val, unsigned int bits) +{ + u64 hash = val; + + /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ + u64 n = hash; + n <<= 18; + hash -= n; + n <<= 33; + hash -= n; + n <<= 3; + hash += n; + n <<= 3; + hash -= n; + n <<= 4; + hash += n; + n <<= 2; + hash += n; + + /* High bits are more random, so use them. */ + return hash >> (64 - bits); +} +#endif + +/* + * Map a block from the source device to a block in the cache device. + */ +unsigned long +hash_block(struct cache_c *dmc, sector_t dbn) +{ +#ifdef MY_ABC_HERE + unsigned long hash_res = 0; + unsigned long block_number = 0; + unsigned long region_idx = 0; +#endif + unsigned long set_number = 0, value = 0; + +#ifdef MY_ABC_HERE + switch (dmc->hash_mapping) { + case HASH_MAPPING_V1: + block_number = dbn >> dmc->block_shift; + // Hash value to 64 bit to make it more randomly distributed + hash_res = hash_64_cache(block_number, 64); + set_number = hash_res % dmc->num_sets; + break; + case HASH_MAPPING_V2: + /* Mod cache size to get offset in cache for region calculating. + * Blocks seperate from each other by exact a cache size on volume + * will map to same set in the same region */ + block_number = compatible_mod(dbn >> dmc->block_shift, dmc->size); + region_idx = compatible_div(block_number, HASH_REGION_BLOCK_NUM); + hash_res = hash_64_cache(block_number, 64); + if (region_idx >= dmc->tail_region_idx) { + /* if tail is merged with last full region, the region index will + * be larger than tail_region_idx */ + set_number = compatible_mod(hash_res, dmc->tail_region_num_sets) + + dmc->tail_region_idx * dmc->region_num_sets; + } else { + set_number = compatible_mod(hash_res, dmc->region_num_sets) + + region_idx * dmc->region_num_sets; + } + break; + case HASH_MAPPING_DISABLE: +#endif + value = (unsigned long) + (dbn >> (dmc->block_shift + dmc->assoc_shift)); + set_number = value % dmc->num_sets; +#ifdef MY_ABC_HERE + break; + } +#endif + DPRINTK("Hash: %llu(%lu)->%lu", dbn, value, set_number); + return set_number; +} + +static void +/* + * Find a cacheblock [i] that match the dbn (start sector of the bio) in a set + * + * SYNO: IN: under spin_lock_irq + * + * Return value: + * valid = i (!= -1): cacheblock[i] is VALID and its dbn match the dbn and state is VALID + * invalid = i (!=-1): cacheblock[i] is INVALID + * invalid = -1: Can't find any invalid cacheblock + */ +find_valid_dbn(struct cache_c *dmc, struct bio *bio, + int start_index, int *valid, int *invalid) +{ + int i; + int end_index = start_index + dmc->assoc; + sector_t bi_start_sector = bio_bi_sector(bio); + sector_t bi_size_sector = bio_sectors(bio); + + if (FLASHCACHE_LRU != dmc->sysctl_reclaim_policy) { + serr("flashcache_syno only support LRU algorithm"); + VERIFY_WARN(0); + } + + *valid = *invalid = -1; + for (i = start_index ; i < end_index ; i++) { + /* + * Search each cache block and check if bio's start sector (dbn) match a range of an cacheblk + */ + if (bi_start_sector >= dmc->cache[i].dbn && + (bi_start_sector < (dmc->cache[i].dbn + dmc->block_size)) && + dmc->cache[i].cache_state & VALID) { + + if ((bi_start_sector + bi_size_sector) > (dmc->cache[i].dbn + dmc->block_size)) { + // should not enter here + sdbg(DF_DETAIL, "dbn + size is over the cache's range Bio [sector=%llu size=%llu] \ + cacheblk.dbn=%llu\n", + (u64)bi_start_sector, (u64)bi_size_sector, (u64)dmc->cache[i].dbn); + VERIFY_WARN(0); + } else { + sdbg(DF_DETAIL, "find valid index=%d bi_start_sector=%llu cache dbn=%llu", + i, (u64)bi_start_sector, (u64)dmc->cache[i].dbn); + *valid = i; + + if (dmc->sysctl_reclaim_policy == FLASHCACHE_LRU && + ((dmc->cache[i].cache_state & BLOCK_IO_INPROG) == 0)) { + flashcache_reclaim_lru_movetail(dmc, i); + } + /* + * If the block was DIRTY and earmarked for cleaning because it was old, make + * the block young again. + */ + flashcache_clear_fallow(dmc, i); + return; + } + + } + + if (*invalid == -1 && dmc->cache[i].cache_state == INVALID) { + VERIFY_WARN((dmc->cache[i].cache_state & FALLOW_DOCLEAN) == 0); + *invalid = i; + } + } + + if (*valid == -1 && *invalid != -1) + if (dmc->sysctl_reclaim_policy == FLASHCACHE_LRU) + flashcache_reclaim_lru_movetail(dmc, *invalid); +} + +/* Search for a slot that we can reclaim */ +static void +#ifdef MY_ABC_HERE +/* + * Doesn't set index while there's no cache block to be reclaimed + * SYNO: IN: Under lock + */ +find_reclaim_dbn(struct cache_c *dmc, int start_index, int *index, struct bio *bio) +#else +find_reclaim_dbn(struct cache_c *dmc, int start_index, int *index) +#endif +{ + int set = start_index / dmc->assoc; + struct cache_set *cache_set = &dmc->cache_sets[set]; + struct cacheblock *cacheblk; +#ifdef MY_ABC_HERE + int is_pin = 0; + int first_pin_block_index = -1; + int found_reclaim = 0; + + is_pin = bio_is_pin(bio); +#endif + + if (dmc->sysctl_reclaim_policy == FLASHCACHE_FIFO) { + int end_index = start_index + dmc->assoc; + int slots_searched = 0; + int i; + + i = cache_set->set_fifo_next; + while (slots_searched < dmc->assoc) { + VERIFY_WARN(i >= start_index); + VERIFY_WARN(i < end_index); + if (dmc->cache[i].cache_state == VALID) { + *index = i; + VERIFY_WARN((dmc->cache[*index].cache_state & FALLOW_DOCLEAN) == 0); + break; + } + slots_searched++; + i++; + if (i == end_index) + i = start_index; + } + i++; + if (i == end_index) + i = start_index; + cache_set->set_fifo_next = i; + } else { /* reclaim_policy == FLASHCACHE_LRU */ + int lru_rel_index; + + lru_rel_index = cache_set->lru_head; + while (lru_rel_index != FLASHCACHE_LRU_NULL) { + cacheblk = &dmc->cache[lru_rel_index + start_index]; + +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (correction_entry_in_correcting(dmc, (u64)cacheblk->dbn, DO_LOCK)) { + lru_rel_index = cacheblk->lru_next; + continue; + } +#endif + if (cacheblk->cache_state == VALID) { + + + VERIFY_WARN((cacheblk - &dmc->cache[0]) == + (lru_rel_index + start_index)); + /* + * SYNO: cache block's DIRTY is not set here + * and it is going to be reclaimed + */ + *index = cacheblk - &dmc->cache[0]; +#ifdef MY_ABC_HERE + found_reclaim = 1; +#endif + VERIFY_WARN((dmc->cache[*index].cache_state & FALLOW_DOCLEAN) == 0); + flashcache_reclaim_lru_movetail(dmc, *index); + break; +#ifdef MY_ABC_HERE + } else if ((-1 == first_pin_block_index) && + ((VALID | PIN_FILE) == cacheblk->cache_state)) { + // Record the first pin block + first_pin_block_index = cacheblk - &dmc->cache[0]; +#endif + } + lru_rel_index = cacheblk->lru_next; + } // SYNO: end of while + +#ifdef MY_ABC_HERE + if (is_pin && !found_reclaim && (-1 != first_pin_block_index)) { + /* + * Bio is gonna be pinned and we can't find a VALID cache block + * So we replace the first pinned cache block + */ + *index = first_pin_block_index; + VERIFY_WARN((dmc->cache[*index].cache_state & FALLOW_DOCLEAN) == 0); + flashcache_reclaim_lru_movetail(dmc, *index); + } + +#endif + } +} + +/* + * dbn is the starting sector, io_size is the number of sectors. + * SYNO: + * Also return VALID if io match the partical cache block range + * Return: + * VALID 2 + * INVALID 1 + * -1 (Doesn't find any cache block) + * IN: under lock (spin_lock_irq) + */ +static int +flashcache_lookup(struct cache_c *dmc, struct bio *bio, int *index) +{ + sector_t dbn = bio_bi_sector(bio); +#if DMC_DEBUG + int io_size = to_sector(bio_bi_size(bio)); +#endif + unsigned long set_number = hash_block(dmc, dbn); + int invalid, oldest_clean = -1; + int start_index; + + start_index = dmc->assoc * set_number; + DPRINTK("Cache lookup : dbn %llu(%lu), set = %d", + dbn, io_size, set_number); + // use bio as parameter + find_valid_dbn(dmc, bio, start_index, index, &invalid); + + if (*index >= 0) { + DPRINTK("Cache lookup HIT: Block %llu(%lu): VALID index %d", + dbn, io_size, *index); + /* We found the exact range of blocks we are looking for */ + return VALID; + } + if (invalid == -1) { + /* We didn't find an invalid entry, search for oldest valid entry */ +#ifdef MY_ABC_HERE + find_reclaim_dbn(dmc, start_index, &oldest_clean, bio); +#else + find_reclaim_dbn(dmc, start_index, &oldest_clean); +#endif + } + /* + * Cache miss : + * We can't choose an entry marked INPROG, but choose the oldest + * INVALID or the oldest VALID entry. + */ + *index = start_index + dmc->assoc; + if (invalid != -1) { + DPRINTK("Cache lookup MISS (INVALID): dbn %llu(%lu), set = %d, index = %d, start_index = %d", + dbn, io_size, set_number, invalid, start_index); + // SYNO: get invalid + *index = invalid; + } else if (oldest_clean != -1) { + DPRINTK("Cache lookup MISS (VALID): dbn %llu(%lu), set = %d, index = %d, start_index = %d", + dbn, io_size, set_number, oldest_clean, start_index); + // SYNO: get oldest valid + *index = oldest_clean; + } else { + DPRINTK_LITE("Cache read lookup MISS (NOROOM): dbn %llu(%lu), set = %d", + dbn, io_size, set_number); + } + if (*index < (start_index + dmc->assoc)) + return INVALID; + else { + atomic64_inc(&dmc->flashcache_stats.noroom); + return -1; + } +} + +#ifdef MY_ABC_HERE +#else +/* + * Cache Metadata Update functions + */ +void +flashcache_md_write_callback(unsigned long error, void *context) +{ + struct kcached_job *job = NULL; + struct kcached_job *orig_job = (struct kcached_job *)context; + struct cache_c *dmc = orig_job->dmc; + struct cache_md_block_head *md_block_head = + &dmc->md_blocks_buf[INDEX_TO_MD_BLOCK(dmc, orig_job->index)]; + + flashcache_check_record_io_latency(LAT_MD_WRITE_SSD, &orig_job->io_lat); + + for (job = md_block_head->md_io_inprog; job != NULL; job = job->next) { + flashcache_check_record_io_latency(LAT_MD_WRITE_SSD, &job->io_lat); + } + + if (unlikely(error)) + orig_job->error = -EIO; + else + orig_job->error = 0; + push_md_complete(orig_job); + cache_schedule_md_complete(); +} + +#ifdef MY_ABC_HERE + +void +disk_flush_pending_queue_add(struct cache_c *dmc, job_node *job_node) +{ + list_add_tail(&job_node->list, dmc->disk_flush_pending_queue); +} + +void +flush_disk_complete(unsigned long error, void *context) +{ + struct cache_c *dmc = (struct cache_c *)context; + + if (error & 1) { + serr("Send flush bio to disk failed"); + } + + atomic64_inc(&dmc->flashcache_stats.disk_flush_done); + cache_schedule_work(&dmc->disk_flush_io_queue_work); +} + +void +send_disk_flush_bio(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, flush_work); + + atomic64_inc(&dmc->flashcache_stats.disk_flush_start); + + dm_io_async_bio_wrapper(1, &dmc->disk_region, COMP_DM_WRITE_FLUSH, + dmc->flush_bio, flush_disk_complete, dmc, 0); +} + +static void +md_write_no_flush_callback(unsigned long error, void *context) +{ + struct kcached_job *job = (struct kcached_job *) context; + struct cache_c *dmc = job->dmc; + + if (unlikely(error)) { + job->error = -EIO; + } else { + job->error = 0; + } + + if (atomic_dec_and_test(&dmc->inflight_md_write_for_flush)) { + cache_schedule_work(&dmc->md_flush_work); + } +} + +/* Without lock */ +static void start_md_writes_no_flush(struct cache_c *dmc) +{ + struct kcached_job *next_job = NULL; + struct dm_io_region where; + job_node *cur = NULL; + int job_cnt = 0; + + if (unlikely(dmc->sysctl_error_inject & MD_PREWRITE_DELAY)) { + dmc->sysctl_error_inject &= ~MD_PREWRITE_DELAY; + serr("Cache Metadata Pre Write Delay 10 Sec"); + mdelay(10000); + } + + VERIFY_WARN(0 == atomic_read(&dmc->inflight_md_write_for_flush)); + where.bdev = get_cache_bdev(dmc); + where.count = MD_SECTORS_PER_BLOCK(dmc); + + list_for_each_entry(cur, dmc->md_flush_io_queue, list) { + job_cnt++; + } + + atomic_add(job_cnt, &dmc->inflight_md_write_for_flush); + + list_for_each_entry(cur, dmc->md_flush_io_queue, list) { + next_job = cur->job; + // Update metadata + where.sector = (1 + INDEX_TO_MD_BLOCK(dmc, next_job->index)) * MD_SECTORS_PER_BLOCK(dmc); + atomic64_inc(&dmc->flashcache_stats.ssd_writes); + atomic64_inc(&dmc->flashcache_stats.md_ssd_writes); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + dm_io_async_bvec(1, &where, COMP_DM_WRITE, + next_job->md_bio, + md_write_no_flush_callback, next_job, 0); +#else + dm_io_async_bvec(1, &where, COMP_DM_WRITE, + &next_job->md_io_bvec, + md_write_no_flush_callback, next_job, 0); +#endif + } +} + +void +process_md_flush_io_queue(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, md_flush_io_queue_work); + unsigned long flags = 0; + job_node *cur = NULL; + job_node *next = NULL; + + if (unlikely(dmc->sysctl_error_inject & MD_POSTFLUSH_DELAY)) { + dmc->sysctl_error_inject &= ~MD_POSTFLUSH_DELAY; + serr("Cache Metadata Post Flush Delay 10 Sec"); + mdelay(10000); + } + + list_for_each_entry_safe(cur, next, dmc->md_flush_io_queue, list) { + push_md_complete(cur->job); + // free resource + list_del(&cur->list); + kfree(cur); + cur = NULL; + } + cache_schedule_md_complete(); + + VERIFY_WARN(list_empty(dmc->md_flush_io_queue)); + spin_lock_irqsave(&dmc->md_flush_lock, flags); + if (!list_empty(dmc->md_flush_pending_queue)) { + dmc->md_flush_unused_queue = dmc->md_flush_io_queue; + dmc->md_flush_io_queue = dmc->md_flush_pending_queue; + dmc->md_flush_pending_queue = dmc->md_flush_unused_queue; + dmc->md_flush_unused_queue = NULL; + spin_unlock_irqrestore(&dmc->md_flush_lock, flags); + start_md_writes_no_flush(dmc); + } else { + dmc->md_flush_unused_queue = dmc->md_flush_io_queue; + dmc->md_flush_io_queue = NULL; + dmc->md_flushing = 0; + spin_unlock_irqrestore(&dmc->md_flush_lock, flags); + } +} + +void +flush_md_complete(unsigned long error, void *context) +{ + struct cache_c *dmc = (struct cache_c *) context; + + if (error & 1) { + serr("Send flush bio to cache failed"); + } + + atomic64_inc(&dmc->flashcache_stats.md_flush_done); + cache_schedule_work(&dmc->md_flush_io_queue_work); +} + +void +send_md_flush_bio(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, md_flush_work); + + if (unlikely(dmc->sysctl_error_inject & MD_PREFLUSH_DELAY)) { + dmc->sysctl_error_inject &= ~MD_PREFLUSH_DELAY; + serr("Cache Metadata Pre Flush Delay 10 Sec"); + mdelay(10000); + } + + atomic64_inc(&dmc->flashcache_stats.md_flush_start); + + dm_io_async_bio_wrapper(1, &dmc->cache_region, COMP_DM_WRITE_FLUSH, + dmc->md_flush_bio, flush_md_complete, dmc, 0); +} + +void +process_disk_flush_io_queue(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, disk_flush_io_queue_work); + unsigned long flags = 0; + + spin_lock_irqsave(&dmc->md_flush_lock, flags); + list_splice_tail_init(dmc->disk_flush_io_queue, dmc->md_flush_pending_queue); + VERIFY_WARN(!list_empty(dmc->md_flush_pending_queue)); + VERIFY_WARN(list_empty(dmc->disk_flush_io_queue)); + if (!dmc->md_flushing) { + dmc->md_flushing = 1; + dmc->md_flush_io_queue = dmc->md_flush_pending_queue; + dmc->md_flush_pending_queue = dmc->md_flush_unused_queue; + dmc->md_flush_unused_queue = NULL; + spin_unlock_irqrestore(&dmc->md_flush_lock, flags); + start_md_writes_no_flush(dmc); + } else { + spin_unlock_irqrestore(&dmc->md_flush_lock, flags); + } + + VERIFY_WARN(list_empty(dmc->disk_flush_io_queue)); + + spin_lock_irqsave(&dmc->disk_flush_lock, flags); + + // set back to unused queue + dmc->disk_flush_unused_queue = dmc->disk_flush_io_queue; + dmc->disk_flush_io_queue = NULL; + + // This thread can only stop when no jobs in pending queue while in_flush = 1 + if (!list_empty(dmc->disk_flush_pending_queue)) { + // Change queue + dmc->disk_flush_io_queue = dmc->disk_flush_pending_queue; + dmc->disk_flush_pending_queue = dmc->disk_flush_unused_queue; + spin_unlock_irqrestore(&dmc->disk_flush_lock, flags); + cache_schedule_work(&dmc->flush_work); + + } else { + dmc->disk_flushing = 0; + spin_unlock_irqrestore(&dmc->disk_flush_lock, flags); + } +} + + +job_node * alloc_init_job_node(void) +{ + static int print = 0; + job_node *node = NULL; + + while (1) { + node = kzalloc(sizeof(job_node), GFP_NOIO); + if (node) { + break; + } else { + if (!print) { + serr("retry to get memory for job node"); + print = 1; + } + } + } + + return node; +} + +void +handle_md_write_with_flush(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + unsigned long flags = 0; + job_node *job_node = NULL; + + job_node = alloc_init_job_node(); + job_node->job = job; + + spin_lock_irqsave(&dmc->disk_flush_lock, flags); + + disk_flush_pending_queue_add(dmc, job_node); + + if (dmc->disk_flushing) { + spin_unlock_irqrestore(&dmc->disk_flush_lock, flags); + } else { + dmc->disk_flushing = 1; + // Change queue + dmc->disk_flush_io_queue = dmc->disk_flush_pending_queue; + dmc->disk_flush_pending_queue = dmc->disk_flush_unused_queue; + dmc->disk_flush_unused_queue = NULL; + spin_unlock_irqrestore(&dmc->disk_flush_lock, flags); + cache_schedule_work(&dmc->flush_work); + } +} + + +#endif /* MY_ABC_HERE */ + +void +flashcache_md_write_kickoff(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + struct flash_cacheblock *md_block; + int md_block_ix; + struct dm_io_region where; + int i; + struct cache_md_block_head *md_block_head; + struct kcached_job *orig_job = job; + unsigned long flags; + int need_flush = 0; + + flashcache_check_record_io_latency(job->io_lat.next_step, &job->io_lat); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + if (flashcache_alloc_md_bio(job)) { +#else + if (flashcache_alloc_md_sector(job)) { +#endif + DMERR("flashcache: %d: Cache metadata write failed, cannot alloc page ! block %llu", + job->action, (u64)job->job_io_regions.disk.sector); + flashcache_md_write_callback(-EIO, job); + return; + } + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + /* + * Transfer whatever is on the pending queue to the md_io_inprog queue. + */ + md_block_head = &dmc->md_blocks_buf[INDEX_TO_MD_BLOCK(dmc, job->index)]; + md_block_head->md_io_inprog = md_block_head->queued_updates; + md_block_head->queued_updates = NULL; + md_block = job->md_block; + // SYNO: Get the start cache[index] of the md block + md_block_ix = INDEX_TO_MD_BLOCK(dmc, job->index) * MD_SLOTS_PER_BLOCK(dmc); + + /* First copy out the entire md block */ + for (i = 0 ; + i < MD_SLOTS_PER_BLOCK(dmc) && md_block_ix < dmc->size ; + i++, md_block_ix++) { + md_block[i].dbn = dmc->cache[md_block_ix].dbn; +#ifdef FLASHCACHE_DO_CHECKSUMS + md_block[i].checksum = dmc->cache[md_block_ix].checksum; +#endif + md_block[i].data_bitmap = dmc->cache[md_block_ix].data_bitmap; + md_block[i].dirty_bitmap = dmc->cache[md_block_ix].dirty_bitmap; +#ifdef MY_ABC_HERE + md_block[i].cache_state = + dmc->cache[md_block_ix].cache_state & (VALID | INVALID | DIRTY | PIN_FILE); +#else + md_block[i].cache_state = + dmc->cache[md_block_ix].cache_state & (VALID | INVALID | DIRTY); +#endif + } + /* Then set/clear the DIRTY bit for the "current" index */ + if (job->action == WRITECACHE) { + /* DIRTY the cache block */ + md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state = + (VALID | DIRTY); + } else { /* job->action == WRITEDISK* */ + /* un-DIRTY the cache block */ + md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state = VALID; + need_flush = 1; + } +#ifdef MY_ABC_HERE + // Set Pin_File flag if needed + if (dmc->cache[job->index].cache_state & PIN_FILE) { + md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state |= PIN_FILE; + } +#endif + + for (job = md_block_head->md_io_inprog ; + job != NULL ; + job = job->next) { + atomic64_inc(&dmc->flashcache_stats.md_write_batch); + flashcache_check_record_io_latency(LAT_MD_WRITE_INPROG_WAIT, &job->io_lat); + + if (job->action == WRITECACHE) { + /* DIRTY the cache block */ + md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state = + (VALID | DIRTY); + } else { /* job->action == WRITEDISK* */ + /* un-DIRTY the cache block */ + md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state = VALID; + need_flush = 1; + } + +#ifdef MY_ABC_HERE + // Set Pin_File flag if needed + if (dmc->cache[job->index].cache_state & PIN_FILE) { + md_block[INDEX_TO_MD_BLOCK_OFFSET(dmc, job->index)].cache_state |= PIN_FILE; + } +#endif + + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + if (need_flush) { + handle_md_write_with_flush(orig_job); + return; + } + + where.bdev = get_cache_bdev(dmc); + where.count = MD_SECTORS_PER_BLOCK(dmc); + where.sector = (1 + INDEX_TO_MD_BLOCK(dmc, orig_job->index)) * MD_SECTORS_PER_BLOCK(dmc); + atomic64_inc(&dmc->flashcache_stats.ssd_writes); + atomic64_inc(&dmc->flashcache_stats.md_ssd_writes); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + dm_io_async_bvec(1, &where, COMP_DM_WRITE, + orig_job->md_bio, + flashcache_md_write_callback, orig_job, 0); +#else + dm_io_async_bvec(1, &where, COMP_DM_WRITE, + &orig_job->md_io_bvec, + flashcache_md_write_callback, orig_job, 0); +#endif +} + +void +flashcache_md_write_done(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + struct cache_md_block_head *md_block_head; + int index; + unsigned long flags; + struct kcached_job *job_list; + int error = job->error; + struct kcached_job *next; + struct cacheblock *cacheblk; + struct cache_set *cacheset = NULL; + int oqf_wb = 0; + + VERIFY_WARN(!in_interrupt()); + VERIFY_WARN(job->action == WRITEDISK || job->action == WRITECACHE || + job->action == WRITEDISK_SYNC); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + flashcache_free_md_bio(job); +#else + flashcache_free_md_sector(job); +#endif + job->md_block = NULL; + /* + * SYNO: Might shared by multiple IOs in the same cache block + * Use nr_in_prog as flag in critial section + */ + md_block_head = &dmc->md_blocks_buf[INDEX_TO_MD_BLOCK(dmc, job->index)]; + job_list = job; + job->next = md_block_head->md_io_inprog; + md_block_head->md_io_inprog = NULL; + for (job = job_list ; job != NULL ; job = next) { + next = job->next; + job->error = error; + index = job->index; + cacheblk = &dmc->cache[index]; + cacheset = &dmc->cache_sets[index / dmc->assoc]; + oqf_wb = (job->flag & JOB_WB_NQF); + + flashcache_check_record_io_latency(LAT_MD_WRITE_CALLBACK_WQ, &job->io_lat); + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + if (job->action == WRITECACHE) { + if (unlikely(dmc->sysctl_error_inject & WRITECACHE_MD_ERROR)) { + job->error = -EIO; + dmc->sysctl_error_inject &= ~WRITECACHE_MD_ERROR; + } + if (likely(job->error == 0)) { + if ((cacheblk->cache_state & DIRTY) == 0) { +#ifdef MY_ABC_HERE +#else + cacheset->nr_dirty++; +#endif + dmc->nr_dirty++; + cb_state_add_bits_update_counts(dmc, cacheblk, DIRTY); + } + atomic64_inc(&dmc->flashcache_stats.md_write_dirty); + + if (0 == cacheblk->data_bitmap) { + serr("Set cache[%d] to DIRTY, data bitmap should not be 0!", index); + VERIFY_WARN(0); + } + } else { + atomic_inc(&dmc->flashcache_errors.ssd_write_errors); + } + + flashcache_bio_endio(job->bio, job->error, dmc, job->io_start_time, &job->io_lat); + + // Solve do_pending_error call trace + job->bio = NULL; + if (job->error || cacheblk->nr_queued > 0) { + + /* + * SYNO: Add data range in io_callback for md_block update + * Remove IO range in do_pending_xxx + */ + if (job->error) { + // printk_ratelimit start + if (printk_ratelimit()) { + DMERR("flashcache: WRITE: Cache metadata write failed ! error %d block %llu", + job->error, (u64)cacheblk->dbn); + } + // printk_ratelimit end + } + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + flashcache_do_pending(job); + } else { + // SYNO: Add data range in io_callback for md_block update + cacheblk_remove_io_range_change_state(dmc, cacheblk, job->action_bitmap); + cacheblk_dec_num_concurrent_and_return(cacheblk); + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + atomic_dec(&dmc->num_write_cache); + wake_up(&dmc->wait_io_done_queue); + + flashcache_free_cache_job(job); + if (atomic_dec_and_test(&dmc->nr_jobs)) + wake_up(&dmc->sync_wqh); + } + } else { + /* SYNO: WRITE DISK, WRITE_DISK_SYNC */ + int action = job->action; + + if (unlikely(dmc->sysctl_error_inject & WRITEDISK_MD_ERROR)) { + job->error = -EIO; + dmc->sysctl_error_inject &= ~WRITEDISK_MD_ERROR; + } + /* + * If we have an error on a WRITEDISK*, no choice but to preserve the + * dirty block in cache. Fail any IOs for this block that occurred while + * the block was being cleaned. + */ + if (likely(job->error == 0)) { + atomic64_inc(&dmc->flashcache_stats.md_write_clean); + + VERIFY_WARN(0 == cacheblk->flushing_dirty_bitmap); + cacheblk_unset_all_dirty_range(cacheblk); + + cb_state_remove_bits_update_counts(dmc, cacheblk, DIRTY); +#ifdef MY_ABC_HERE +#else + VERIFY_WARN(cacheset->nr_dirty > 0); + cacheset->nr_dirty--; +#endif + VERIFY_WARN(dmc->nr_dirty > 0); + dmc->nr_dirty--; + } else + // SYNO: Don't unset DIRTY here for updating metadata again ... + atomic_inc(&dmc->flashcache_errors.ssd_write_errors); + +#ifdef MY_ABC_HERE +#else + dec_clean_inprog(dmc, cacheset, 1); +#endif + + if (job->error || cacheblk->nr_queued > 0) { + if (job->error) { + // printk_ratelimit start + if (printk_ratelimit()) { + DMERR("flashcache: CLEAN: Cache metadata write failed ! error %d block %llu", + job->error, (u64)cacheblk->dbn); + } + // printk_ratelimit end + } + /* + * SYNO: + * Don't remove BLOCK_IN_PROG here + * BLOCK_IN_PROG should be removed in do_pending_xxx (as it default behavoir) + */ + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + flashcache_do_pending(job); + } else { + unset_partial_cb_writeback_attrs(dmc, cacheblk, 1); + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + flashcache_free_cache_job(job); + if (atomic_dec_and_test(&dmc->nr_jobs)) + wake_up(&dmc->sync_wqh); + } + /* Kick off more cleanings */ + if (action == WRITEDISK) { +#ifdef MY_ABC_HERE +#else + flashcache_clean_set(dmc, index / dmc->assoc); +#endif + } else { +#ifdef MY_ABC_HERE +#else + flashcache_sync_blocks(dmc); +#endif + } + atomic64_inc(&dmc->flashcache_stats.cleanings); + if (action == WRITEDISK_SYNC) + flashcache_update_sync_progress(dmc); + } + } + + // SYNO: WRITE_CACHE / WRITE_DISK / WRITE_DISK_SYNC go here + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (md_block_head->queued_updates != NULL) { + /* peel off the first job from the pending queue and kick that off */ + job = md_block_head->queued_updates; + md_block_head->queued_updates = job->next; + job->next = NULL; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + VERIFY_WARN(job->action == WRITEDISK || job->action == WRITECACHE || + job->action == WRITEDISK_SYNC); + flashcache_md_write_kickoff(job); + } else { + md_block_head->nr_in_prog = 0; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + } +} + +/* + * Kick off a cache metadata update (called from workqueue). + * Cache metadata update IOs to a given metadata sector are serialized using the + * nr_in_prog bit in the md sector bufhead. + * If a metadata IO is already in progress, we queue up incoming metadata updates + * on the pending_jobs list of the md sector bufhead. When kicking off an IO, we + * cluster all these pending updates and do all of them as 1 flash write (that + * logic is in md_write_kickoff), where it switches out the entire pending_jobs + * list and does all of those updates as 1 ssd write. + */ +void +flashcache_md_write(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + struct cache_md_block_head *md_block_head; + unsigned long flags; + + VERIFY_WARN(job->action == WRITEDISK || job->action == WRITECACHE || + job->action == WRITEDISK_SYNC); + md_block_head = &dmc->md_blocks_buf[INDEX_TO_MD_BLOCK(dmc, job->index)]; + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + /* If a write is in progress for this metadata sector, queue this update up */ + if (md_block_head->nr_in_prog != 0) { + struct kcached_job **nodepp; + + /* A MD update is already in progress, queue this one up for later */ + nodepp = &md_block_head->queued_updates; + while (*nodepp != NULL) + nodepp = &((*nodepp)->next); + job->io_lat.next_step = LAT_MD_WRITE_INPROG_WAIT; + job->next = NULL; + *nodepp = job; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + } else { + md_block_head->nr_in_prog = 1; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + /* + * Always push to a worker thread. If the driver has + * a completion thread, we could end up deadlocking even + * if the context would be safe enough to write from. + * This could be executed from the context of an IO + * completion thread. Kicking off the write from that + * context could result in the IO completion thread + * blocking (eg on memory allocation). That can easily + * deadlock. + */ + job->io_lat.next_step = LAT_MD_WRITE_START_WQ; + push_md_io(job); + cache_schedule_md_io(); + } +} +#endif /* SYNO_FLASHCACHQ_MD_UPDATE_AGGR */ + +#ifdef MY_ABC_HERE +#else +static void +flashcache_kcopyd_callback(int read_err, unsigned int write_err, void *context) +{ + struct kcached_job *job = (struct kcached_job *)context; + struct cache_c *dmc = job->dmc; + int index = job->index; + unsigned long flags; +#ifdef MY_ABC_HERE + struct cacheblock *cacheblk = &dmc->cache[index]; + + job_dbg(__func__, job); +#endif + + VERIFY_WARN(!in_interrupt()); + DPRINTK("kcopyd_callback: Index %d", index); + VERIFY_WARN(job->bio == NULL); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + VERIFY_WARN(dmc->cache[index].cache_state & (DISKWRITEINPROG | VALID | DIRTY)); + if (unlikely(dmc->sysctl_error_inject & KCOPYD_CALLBACK_ERROR)) { + read_err = -EIO; + dmc->sysctl_error_inject &= ~KCOPYD_CALLBACK_ERROR; + } + if (likely(read_err == 0 && write_err == 0)) { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + +#ifdef MY_ABC_HERE + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + cacheblk_unset_lowest_part_of_flushing_dirty_range(cacheblk); + + if (cacheblk_is_flushing_dirty_range_unset(cacheblk)) { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + +#ifdef MY_ABC_HERE + atomic64_inc(&dmc->flashcache_stats.dirty_writeback_done); +#endif + flashcache_md_write(job); + } else { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + flashcache_free_cache_job(job); + + /* + * Don't decrease nr_jog and wake_up here + * Trigger again + */ + flashcache_dirty_writeback(dmc, index); + } +#else + flashcache_md_write(job); +#endif + } else { + if (read_err) + read_err = -EIO; + if (write_err) + write_err = -EIO; + /* Disk write failed. We can not purge this block from flash */ +#ifdef MY_ABC_HERE + if (0 < dmc->limits.writeback_err) { +#endif + DMERR("flashcache: Disk writeback failed ! read error %d write error %d block %llu", + -read_err, -write_err, (u64)job->job_io_regions.disk.sector); +#ifdef MY_ABC_HERE + dmc->limits.writeback_err--; + } +#endif + dec_clean_inprog(dmc, &dmc->cache_sets[index / dmc->assoc], 1); + cacheblk->flushing_dirty_bitmap = 0; + // io_range whould be unset in do_pending_xxx + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + /* Set the error in the job and let do_pending() handle the error */ + if (read_err) { + atomic_inc(&dmc->flashcache_errors.ssd_read_errors); + job->error = read_err; + } else { + atomic_inc(&dmc->flashcache_errors.disk_write_errors); + job->error = write_err; + } + flashcache_do_pending(job); + flashcache_clean_set(dmc, index / dmc->assoc); /* Kick off more cleanings */ + atomic64_inc(&dmc->flashcache_stats.cleanings); + } +} + +static void +flashcache_dirty_writeback(struct cache_c *dmc, int index) +{ + struct kcached_job *job; + unsigned long flags; + struct cacheblock *cacheblk = &dmc->cache[index]; + struct cache_set *cacheset = &dmc->cache_sets[index / dmc->assoc]; + int device_removal = 0; + int first_time_flush = 0; + sector_t offset = 0; + sector_t size = 0; + + DPRINTK("flashcache_dirty_writeback: Index %d", index); + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + VERIFY_WARN((cacheblk->cache_state & BLOCK_IO_INPROG) == DISKWRITEINPROG); + VERIFY_WARN(cacheblk->cache_state & DIRTY); + + // Check data_bitmap inside spin_lock + if (0 == cacheblk->data_bitmap) { + serr("cb index=%d data_bitmap=0", index); + VERIFY_WARN(0); + } + + if (0 == cacheblk->flushing_dirty_bitmap) { + cacheblk->flushing_dirty_bitmap = cacheblk->dirty_bitmap; + first_time_flush = 1; + } + + // Access inside the lock + cacheblk_get_lowest_part_of_flushing_dirty_range(cacheblk, &offset, &size); + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + job = new_kcached_job_no_bio(dmc, index, offset, size); + if (unlikely(dmc->sysctl_error_inject & DIRTY_WRITEBACK_JOB_ALLOC_FAIL)) { + if (job) + flashcache_free_cache_job(job); + job = NULL; + dmc->sysctl_error_inject &= ~DIRTY_WRITEBACK_JOB_ALLOC_FAIL; + } + + if (!first_time_flush && (unlikely(dmc->sysctl_error_inject & SIMULATE_DIRTY_WRITEBACK_LONG_TIME))) { + sprint("Detect sysctl SIMULATE_DIRTY_WRITEBACK_LONG_TIME is set, sleep 15s"); + msleep(15*1000); + dmc->sysctl_error_inject &= ~SIMULATE_DIRTY_WRITEBACK_LONG_TIME; + } + + /* + * If the device is being removed, do not kick off any more cleanings. + */ + if (unlikely(atomic_read(&dmc->remove_in_prog))) { + DMERR("flashcache: Dirty Writeback (for set cleaning) aborted for device removal, block %llu", + (u64)cacheblk->dbn); + if (job) + flashcache_free_cache_job(job); + job = NULL; + device_removal = 1; + } + if (unlikely(job == NULL)) { + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + dec_clean_inprog(dmc, cacheset, 1); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + cacheblk->flushing_dirty_bitmap = 0; + unset_partial_cb_writeback_attrs(dmc, cacheblk, 1); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + if (device_removal == 0) + DMERR("flashcache: Dirty Writeback (for set cleaning) failed ! Can't allocate memory, block %llu", (u64)cacheblk->dbn); + + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } + } else { + job->bio = NULL; + job->action = WRITEDISK; + if (first_time_flush) { + atomic64_inc(&dmc->flashcache_stats.dirty_writeback_start); + } + + job_dbg(__func__, job); + atomic64_inc(&dmc->flashcache_stats.ssd_reads); + atomic64_inc(&dmc->flashcache_stats.disk_writes); +#ifdef MY_ABC_HERE + atomic64_add(size, &dmc->flashcache_stats.dirty_writeback_sector); +#endif + dm_kcopyd_copy(flashcache_kcp_client, &job->job_io_regions.cache, 1, &job->job_io_regions.disk, 0, + (dm_kcopyd_notify_fn) flashcache_kcopyd_callback, + (void *)job); + } +} + + +/* + * This function encodes the background disk cleaning logic. + * Background disk cleaning is triggered for 2 reasons. + A) Dirty blocks are lying fallow in the set, making them good + candidates for being cleaned. + B) This set has dirty blocks over the configured threshold + for a set. + * (A) takes precedence over (B). Fallow dirty blocks are cleaned + * first. + * The cleaning of disk blocks is subject to the write limits per + * set and across the cache, which this function enforces. + * + * 1) Select the n blocks that we want to clean (choosing whatever policy), + * sort them. + * 2) Then sweep the entire set looking for other DIRTY blocks that can be + * tacked onto any of these blocks to form larger contigous writes. + * The idea here is that if you are going to do a write anyway, then we + * might as well opportunistically write out any contigous blocks for + * free. + */ + +/* Are we under the limits for disk cleaning ? */ +static inline int +flashcache_can_clean(struct cache_c *dmc, + struct cache_set *cache_set) +{ + return (cache_set->clean_inprog < dmc->max_clean_ios_set && + dmc->clean_inprog < dmc->max_clean_ios_total); +} + +/* + * SYNO: Just sync dirty block to disks and make its state to VALID + */ +void +flashcache_clean_set(struct cache_c *dmc, int set) +{ + unsigned long flags; + int threshold_clean = 0; + struct dbn_index_pair *writes_list; + int nr_writes = 0, i; + int start_index = set * dmc->assoc; + int end_index = start_index + dmc->assoc; + struct cache_set *cache_set = &dmc->cache_sets[set]; + struct cacheblock *cacheblk; + int do_delayed_clean = 0; + + if (dmc->cache_mode != FLASHCACHE_WRITE_BACK) + return; + + /* + * If a removal of this device is in progress, don't kick off + * any more cleanings. This isn't sufficient though. We still need to + * stop cleanings inside flashcache_dirty_writeback() because we could + * have started a device remove after tested this here. + */ + if (atomic_read(&dmc->remove_in_prog)) + return; + writes_list = kmalloc(dmc->assoc * sizeof(struct dbn_index_pair), GFP_NOIO); + if (unlikely(dmc->sysctl_error_inject & WRITES_LIST_ALLOC_FAIL)) { + if (writes_list) + kfree(writes_list); + writes_list = NULL; + dmc->sysctl_error_inject &= ~WRITES_LIST_ALLOC_FAIL; + } + if (writes_list == NULL) { + atomic_inc(&dmc->flashcache_errors.memory_alloc_errors); +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate write list for clean set"); + } +#endif + return; + } + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + /* + * Before we try to clean any blocks, check the last time the fallow block + * detection was done. If it has been more than "fallow_delay" seconds, make + * a sweep through the set to detect (mark) fallow blocks. + */ + if (dmc->sysctl_fallow_delay && time_after(jiffies, cache_set->fallow_tstamp)) { + for (i = start_index ; i < end_index ; i++) + flashcache_detect_fallow(dmc, i); + cache_set->fallow_tstamp = jiffies + dmc->sysctl_fallow_delay * HZ; + } + /* If there are any dirty fallow blocks, clean them first */ + for (i = start_index ; + (dmc->sysctl_fallow_delay > 0 && + cache_set->dirty_fallow > 0 && + time_after(jiffies, cache_set->fallow_next_cleaning) && + i < end_index) ; + i++) { + cacheblk = &dmc->cache[i]; + if (!(cacheblk->cache_state & DIRTY_FALLOW_2)) + continue; + if (!flashcache_can_clean(dmc, cache_set)) { + /* + * There are fallow blocks that need cleaning, but we + * can't clean them this pass, schedule delayed cleaning + * later. + */ + do_delayed_clean = 1; + goto out; + } + VERIFY_WARN(cacheblk->cache_state & DIRTY); + VERIFY_WARN((cacheblk->cache_state & BLOCK_IO_INPROG) == 0); + set_wb_attrs(dmc, i, 1); + writes_list[nr_writes].dbn = cacheblk->dbn; + writes_list[nr_writes].index = i; + atomic64_inc(&dmc->flashcache_stats.fallow_cleanings); + nr_writes++; + } + if (nr_writes > 0) + cache_set->fallow_next_cleaning = jiffies + HZ / dmc->sysctl_fallow_clean_speed; + if (cache_set->nr_dirty < dmc->dirty_thresh_set || + !flashcache_can_clean(dmc, cache_set)) + goto out; + /* + * We picked up all the dirty fallow blocks we can. We can still clean more to + * remain under the dirty threshold. Clean some more blocks. + */ + threshold_clean = cache_set->nr_dirty - dmc->dirty_thresh_set; + if (dmc->sysctl_reclaim_policy == FLASHCACHE_FIFO) { + int scanned; + + scanned = 0; + i = cache_set->set_clean_next; + DPRINTK("flashcache_clean_set: Set %d", set); + while (scanned < dmc->assoc && + flashcache_can_clean(dmc, cache_set) && + nr_writes < threshold_clean) { + cacheblk = &dmc->cache[i]; + if ((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { + set_wb_attrs(dmc, i, 1); + atomic64_inc(&dmc->flashcache_stats.cleanings_over_threshold); + writes_list[nr_writes].dbn = cacheblk->dbn; + writes_list[nr_writes].index = i; + nr_writes++; + } + scanned++; + i++; + if (i == end_index) + i = start_index; + } + cache_set->set_clean_next = i; + } else { /* reclaim_policy == FLASHCACHE_LRU */ + int lru_rel_index; + + lru_rel_index = cache_set->lru_head; + while (lru_rel_index != FLASHCACHE_LRU_NULL && + flashcache_can_clean(dmc, cache_set) && + nr_writes < threshold_clean) { + cacheblk = &dmc->cache[lru_rel_index + start_index]; + if ((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { + set_wb_attrs(dmc, lru_rel_index + start_index, 1); + atomic64_inc(&dmc->flashcache_stats.cleanings_over_threshold); + writes_list[nr_writes].dbn = cacheblk->dbn; + writes_list[nr_writes].index = cacheblk - &dmc->cache[0]; + nr_writes++; + } + lru_rel_index = cacheblk->lru_next; + } + } +out: + if (nr_writes > 0) { +#ifdef MY_ABC_HERE + /* + * Don't invoke flashcache_merge_writes for new mode + * Or the merge write will be too mush because new cache blocks + * are too easy to be DIRTY. + */ + flashcache_sort_writes(writes_list, nr_writes, set); +#else + flashcache_merge_writes(dmc, writes_list, &nr_writes, set); +#endif + atomic64_add(nr_writes, &dmc->flashcache_stats.clean_set_ios); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + for (i = 0 ; i < nr_writes ; i++) + flashcache_dirty_writeback(dmc, writes_list[i].index); + } else { + if (cache_set->nr_dirty > dmc->dirty_thresh_set) + do_delayed_clean = 1; + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + if (do_delayed_clean) + cache_schedule_delayed_work(&dmc->delayed_clean, 1*HZ); + } + kfree(writes_list); +} +#endif /* MY_ABC_HERE */ + +// match none of the bitmap, read from disk and write to cache +/* + * Use in read hit (match none of the data bitmap) or match partial and no need to invalidate + * IN: under lock + * OUT: release lock + */ +static void +read_disk_write_cache(struct cache_c *dmc, struct cacheblock *cacheblk, struct bio *bio, int index) +{ + + struct kcached_job *job = NULL; + unsigned long flags = 0; + char job_title[JOB_STR_MAX] = {0}; + + VERIFY_WARN(dmc && cacheblk && bio); + VERIFY_WARN(spin_is_locked(&dmc->cache_spin_lock)); + + cb_state_add_bits_update_counts(dmc, cacheblk, DISKREADINPROG); + // This is read hit case, dbn is already set ! + + cacheblk_add_io_range_by_bio(cacheblk, bio); + cacheblk_add_num_concurrent(cacheblk); + + spin_unlock_irq(&dmc->cache_spin_lock); + + job = new_kcached_job(dmc, bio, index, NULL, TYPE_DISK); + + if (unlikely(dmc->sysctl_error_inject & READ_MISS_JOB_ALLOC_FAIL)) { + if (job) + flashcache_free_cache_job(job); + job = NULL; + dmc->sysctl_error_inject &= ~READ_MISS_JOB_ALLOC_FAIL; + } + + if (unlikely(job == NULL)) { + /* + * Refer to read miss + * Can't allocate a job. + * Since we dropped the spinlock, we have to drain any + * pending jobs. + */ + DMERR("flashcache: Read from disk (Not in bitmap )failed ! Can't allocate memory, block %llu", + (u64)cacheblk->dbn); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + // don't set cache block to INVALID due to someone might access it now + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + cacheblk_remove_io_range_change_state_by_bio(dmc, cacheblk, bio); + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + } else { + job->action = READDISK; /* Fetch data from the source device */ + atomic_inc(&dmc->nr_jobs); + atomic64_inc(&dmc->flashcache_stats.disk_reads); + atomic64_inc(&dmc->flashcache_stats.read_hit_match_none_read_disk); + snprintf(job_title, sizeof(job_title), "Read hit match (none/partial) => %s", __func__); + job_dbg(job_title, job); + + dm_io_async_bio_wrapper(1, &job->job_io_regions.disk, COMP_DM_READ, + bio, flashcache_io_callback_atomic, job, 0); + // No need to clean set due to no new cache block is occupied + } +} + +/* + * A wrapper of the original read_disk_write_cache because we have to check + * if cache_all is on before writing the SSD. + * + * IN: Under lock + * OUT: Release lock + */ +static void do_read_disk_write_cache(struct cache_c *dmc, struct cacheblock *cacheblk, struct bio *bio, int index) +{ + int queued = 0; + atomic64_inc(&dmc->flashcache_stats.read_hit_check_write_ssd); + if (dmc->bypass_cache) { + queued = flashcache_inval_blocks(dmc, bio, NULL, TYPE_DISK); + if (queued) { + if (unlikely(queued < 0)) { + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + } + spin_unlock_irq(&dmc->cache_spin_lock); + goto end; + } + + spin_unlock_irq(&dmc->cache_spin_lock); + flashcache_start_uncached_io(dmc, bio, NULL, TYPE_DISK); + } else { + read_disk_write_cache(dmc, cacheblk, bio, index); + } + +end: + return; +} + +/* + * Handle the case that Read I/O request only match partial data in the cache block + * IN: Under lock + * Out: Should release lock + */ +static void +read_hit_match_partial(struct cache_c *dmc, struct cacheblock *cacheblk, struct bio *bio, int index) +{ + int queued; +#ifdef MY_ABC_HERE + char bio_str[BIO_STR_MAX] = {0}; +#endif + + atomic64_inc(&dmc->flashcache_stats.read_hit_match_partial); + + /* + * Fix issue that actually the bio WON'T be queued if the cache block is not in IO or dirty + */ + if (!(cacheblk->cache_state & (BLOCK_IO_INPROG | DIRTY)) && + (cacheblk->nr_queued == 0)) { + + sdbg(DF_DETAIL, "Don't invalidate cache block. Invoke do_read_disk_write_cache"); + do_read_disk_write_cache(dmc, cacheblk, bio, index); + + } else { + queued = flashcache_inval_blocks(dmc, bio, NULL, TYPE_DISK); + + spin_unlock_irq(&dmc->cache_spin_lock); + if (queued) { + // Normal queued case (cache block is dirty or in IO) + sdbg(DF_DETAIL, "queued, %s cacheblk index=%d dbn=%llu data_bitmap=0x%x", + bio_to_str(bio, bio_str, sizeof(bio_str)), index, (u64)cacheblk->dbn, cacheblk->data_bitmap); + if (unlikely(queued < 0)) + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + } else { + serr("Should be queue: %s cacheblk index=%d dbn=%llu data_bitmap=0x%x", + bio_to_str(bio, bio_str, sizeof(bio_str)), index, (u64)cacheblk->dbn, + cacheblk->data_bitmap); + VERIFY_WARN(0); + } + + } +} +char *match_str[] = {"all", "only_partial", "none"}; + +void inject_read_hit_normal_io_wait(struct cache_c *dmc, unsigned long corr_bi_flags, struct bio *bio) +{ + if (unlikely(dmc->sysctl_error_inject & READ_HIT_NORMAL_IO_WAIT) && !corr_bi_flags) { + do { + sprint("Normal IO (start=%llu) is waiting", (u64)bio_bi_sector(bio)); + msleep(5000); + } while (dmc->sysctl_error_inject & READ_HIT_NORMAL_IO_WAIT); + } +} + +void inject_read_hit_corr_io_wait(struct cache_c *dmc, unsigned long corr_bi_flags, struct bio *bio) +{ + if (unlikely(dmc->sysctl_error_inject & READ_HIT_CORR_IO_WAIT) && corr_bi_flags) { + do { + sprint("Correction IO (start=%llu) is waiting", (u64)bio_bi_sector(bio)); + msleep(5000); + } while (dmc->sysctl_error_inject & READ_HIT_CORR_IO_WAIT); + } +} + +// SYNO: In: Under lock +static void +flashcache_read_hit(struct cache_c *dmc, struct bio* bio, int index) +{ + struct cacheblock *cacheblk; + struct pending_job *pjob; + unsigned long corr_bi_flags = 0; +#ifdef CONFIG_SYNO_DATA_CORRECTION + int is_range_dirty = 0; + correcting_type_t correcting_type = NO_CORRECTING; +#endif + u64 bio_start_sector = (u64)bio_bi_sector(bio); + + match_t match_data_range = MATCH_UNSET; + match_t match_io_range = MATCH_UNSET; + + cacheblk = &dmc->cache[index]; +#ifdef CONFIG_SYNO_DATA_CORRECTION + is_range_dirty = cacheblk_is_range_dirty(cacheblk, bio); + correcting_type = correction_range_get_type(dmc, bio_start_sector); + corr_bi_flags = bio->bi_flags & ((1 << BIO_CORRECTION_RETRY) | (1 << BIO_CORRECTION_ABORT)); +#endif + + match_data_range = cacheblk_compare_data_range(cacheblk, bio); + match_io_range = cacheblk_compare_io_range(cacheblk, bio); + +#ifdef MY_ABC_HERE + cacheblk_set_pin_state_by_bio(dmc, cacheblk, bio); +#endif + + // allow read concurrent start + if ((MATCH_NONE == match_io_range) && (cacheblk->nr_queued == 0) && + ((MATCH_ALL == match_data_range) || (MATCH_NONE == match_data_range))) { + + if (MATCH_ALL == match_data_range) { + // Case: Match all + struct kcached_job *job; +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (corr_bi_flags) { + if (is_range_dirty) { + if (TYPE_UNINITED == correcting_type) { + if (-1 == correction_range_set_type(dmc, bio_start_sector, SSD_CORRECTING)) { + serr("Fail to get correction device SSD type: correction entry is null"); + } + } + sdbg(DF_CORRECTION, "Correcting bio_sector=%llu dirty, set SSD_CORRECTING", + bio_start_sector); + } else if (SSD_CORRECTING == correcting_type) { + sdbg(DF_CORRECTION, "Correcting bio_sector=%llu is already SSD_CORRECTING", + bio_start_sector); + } else { + if (TYPE_UNINITED == correcting_type) { + if (-1 == correction_range_set_type(dmc, bio_start_sector, DISK_CORRECTING)) { + serr("Fail to get correction device disk type: correction entry is null"); + } + } + + cacheblk_clear_data_range_by_bio(cacheblk, bio); + spin_unlock_irq(&dmc->cache_spin_lock); + sdbg(DF_CORRECTION, "Correcting bio_sector=%llu non-dirty ", bio_start_sector); + flashcache_start_uncached_io(dmc, bio, NULL, TYPE_DISK); + goto finish; + } + } +#endif + cb_state_add_bits_update_counts(dmc, cacheblk, CACHEREADINPROG); + cacheblk_add_io_range_by_bio(cacheblk, bio); + cacheblk_add_num_concurrent(cacheblk); + atomic64_inc(&dmc->flashcache_stats.read_hits); + spin_unlock_irq(&dmc->cache_spin_lock); + + if (unlikely(dmc->sysctl_error_inject & READ_HIT_DELAY)) { + dmc->sysctl_error_inject &= ~(READ_HIT_DELAY); + sprint("Read Hit Delayed dbn: %llu\n", bio_start_sector); + msleep(30000); + } + + inject_read_hit_normal_io_wait(dmc, corr_bi_flags, bio); + inject_read_hit_corr_io_wait(dmc, corr_bi_flags, bio); + + DPRINTK("Cache read: Block %llu(%lu), index = %d:%s", + bio_start_sector, bio_bi_size(bio), index, "CACHE HIT"); + job = new_kcached_job(dmc, bio, index, NULL, TYPE_SSD); + if (unlikely(dmc->sysctl_error_inject & READ_HIT_JOB_ALLOC_FAIL)) { + if (job) + flashcache_free_cache_job(job); + job = NULL; + dmc->sysctl_error_inject &= ~READ_HIT_JOB_ALLOC_FAIL; + } + if (unlikely(job == NULL)) { + /* + * We have a read hit, and can't allocate a job. + * Since we dropped the spinlock, we have to drain any + * pending jobs. + */ + DMERR("flashcache: Read (hit) failed ! Can't allocate memory for cache IO, block %llu", + (u64)cacheblk->dbn); + spin_lock_irq(&dmc->cache_spin_lock); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + cacheblk_remove_io_range_change_state_by_bio(dmc, cacheblk, bio); + cacheblk_dec_num_concurrent_and_return(cacheblk); + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + spin_unlock_irq(&dmc->cache_spin_lock); + } else { + job->action = READCACHE; /* Fetch data from cache */ + atomic_inc(&dmc->nr_jobs); + atomic64_inc(&dmc->flashcache_stats.ssd_reads); + job_dbg(__func__, job); + + dm_io_async_bio_wrapper(1, &job->job_io_regions.cache, COMP_DM_READ, + bio, flashcache_io_callback_atomic, job, corr_bi_flags); + } + // End of (MATCH_ALL == match_data_range) + } else { + // Case: Match none of data range +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (corr_bi_flags) { + sdbg(DF_CORRECTION, "RW_cache: bio_sector=%llu empty ", bio_start_sector); + spin_unlock_irq(&dmc->cache_spin_lock); + + if ((TYPE_UNINITED == correcting_type) && + (-1 == correction_range_set_type(dmc, bio_start_sector, DISK_CORRECTING))) { + serr("Fail to get correction device SSD type: correction entry is null"); + + } + + flashcache_start_uncached_io(dmc, bio, NULL, TYPE_DISK); + goto finish; + } +#endif + // under lock + do_read_disk_write_cache(dmc, cacheblk, bio, index); + } + } else { + if ((MATCH_NONE != match_io_range) || (cacheblk->nr_queued != 0)) { + // Case: Match partial io range or nr_queue >0 start + + if (MATCH_NONE != match_io_range) { + atomic64_inc(&dmc->flashcache_stats.read_hit_busy_in_io); + } else { + atomic64_inc(&dmc->flashcache_stats.read_hit_busy_wait_queue); + } + pjob = flashcache_alloc_pending_job(dmc); + if (unlikely(dmc->sysctl_error_inject & READ_HIT_PENDING_JOB_ALLOC_FAIL)) { + if (pjob) { + flashcache_free_pending_job(pjob); + pjob = NULL; + } + dmc->sysctl_error_inject &= ~READ_HIT_PENDING_JOB_ALLOC_FAIL; + } + if (pjob == NULL) + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + else { + if (MATCH_NONE != match_io_range) { + sdbg(DF_DETAIL, "match io ranges (io=0x%x bio=0x%x): enq_pending index=%d", + cacheblk->io_bitmap, bitmap_get(cacheblk, bio), index); + } else { + sdbg(DF_DETAIL, "nr_queue != 0: enq_pending index=%d", index); + } + // flush this cache and do uncached io + flashcache_enq_pending(dmc, bio, index, READCACHE, pjob, NULL, + MATCH_ALL == match_data_range ? TYPE_COULD_SSD : TYPE_DISK); + } + + spin_unlock_irq(&dmc->cache_spin_lock); + // Case: Match partial io range or nr_queue >0 end + } else { + // Case: Match partial data range (But doesn't match any IO range and nr_queue = 0) + // Data Correction will not enter here. (range always 4k) + read_hit_match_partial(dmc, cacheblk, bio, index); + } + } +#ifdef CONFIG_SYNO_DATA_CORRECTION +finish: + return; +#endif +} + +/* + * SYNO: In: no lock + */ +static void +flashcache_read_miss(struct cache_c *dmc, struct bio* bio, + int index) +{ + struct kcached_job *job; + struct cacheblock *cacheblk = &dmc->cache[index]; + + job = new_kcached_job_fill_cacheblk(dmc, bio, index); + if (unlikely(dmc->sysctl_error_inject & READ_MISS_JOB_ALLOC_FAIL)) { + if (job) + flashcache_free_cache_job(job); + job = NULL; + dmc->sysctl_error_inject &= ~READ_MISS_JOB_ALLOC_FAIL; + } + if (unlikely(job == NULL)) { + /* + * We have a read miss, and can't allocate a job. + * Since we dropped the spinlock, we have to drain any + * pending jobs. + */ + DMERR("flashcache: Read (miss) failed ! Can't allocate memory for cache IO, block %llu", + (u64)cacheblk->dbn); + + spin_lock_irq(&dmc->cache_spin_lock); + + atomic64_dec(&dmc->cached_blocks); + cb_state_remove_bits_update_counts(dmc, cacheblk, VALID); +#ifdef MY_ABC_HERE + cacheblk_check_unset_pin_state(dmc, cacheblk); +#endif + cb_state_add_bits_update_counts(dmc, cacheblk, INVALID); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + cacheblk_remove_io_range_change_state_by_bio(dmc, cacheblk, bio); + cacheblk_dec_num_concurrent_and_return(cacheblk); + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + + spin_unlock_irq(&dmc->cache_spin_lock); + } else { + /* + * Read whole data to memory first, so later we can get partial data from memory + * to this bio + */ + job->action = READDISKMEM; + atomic_inc(&dmc->nr_jobs); + atomic64_inc(&dmc->flashcache_stats.disk_reads); + + push_preread_io(job); + cache_schedule_preread_io(); + atomic64_inc(&dmc->flashcache_stats.prereads); +#ifdef MY_ABC_HERE +#else + flashcache_clean_set(dmc, index / dmc->assoc); +#endif + } +} + +void +flashcache_do_preread_io(struct kcached_job *job) +{ + job_dbg(__FUNCTION__, job); + + flashcache_check_record_io_latency(LAT_DO_PREREAD_WQ, &job->io_lat); + + dm_io_vmem(1, &job->job_io_regions.disk, COMP_DM_READ, + job->mem_addr, + flashcache_io_callback_atomic, job, 0); +} + +static void +flashcache_read(struct cache_c *dmc, struct bio *bio, int uncacheable, int uncache_seq) +{ + int index; + int res; + struct cacheblock *cacheblk = NULL; + int queued; + +#ifdef CONFIG_SYNO_DATA_CORRECTION + unsigned long corr_bi_flags = 0; + int entry_in_correcting = 0; + + correcting_type_t correcting_type = NO_CORRECTING; + + entry_in_correcting = correction_entry_in_correcting(dmc, bio_bi_sector(bio), DO_LOCK); + correcting_type = correction_range_get_type(dmc, bio_bi_sector(bio)); + corr_bi_flags = bio->bi_flags & ((1 << BIO_CORRECTION_RETRY) | (1 << BIO_CORRECTION_ABORT)); +#endif + + DPRINTK("Got a %s for %llu (%u bytes)", + (bio_rw(bio) == READ ? "READ":"READA"), + bio_bi_sector(bio), bio_bi_size(bio)); + + spin_lock_irq(&dmc->cache_spin_lock); + res = flashcache_lookup(dmc, bio, &index); + /* Cache Read Hit case */ +#ifdef CONFIG_SYNO_DATA_CORRECTION + /* For RO, data on SSD/HDD SHOULD be aligned. Data on SSD MAY be corrupted + * So always do DISK_CORRECTING */ + if ((res > 0) && !(entry_in_correcting && (FLASHCACHE_WRITE_AROUND == dmc->cache_mode))) { +#else + if (res > 0) { +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + cacheblk = &dmc->cache[index]; + /* + * Three cases go here + * 1 VALID with matched cacheblk (Cache state is VALID) + * 2 INVALID with state==INVALID cacheblk + * 3 INVALID with old VALID cacheblk (Cache state == VALID) (reclaim_oldest_clean!) + * To distiguish 1 & 3, the old way is to check if cacheblk->dbn match ! + */ + if ((VALID == res) && (cacheblk->cache_state & VALID)) { + flashcache_read_hit(dmc, bio, index); + return; + } + } + /* + * In all cases except for a cache hit (and VALID), test for potential + * invalidations that we need to do. + */ + queued = flashcache_inval_blocks(dmc, bio, NULL, TYPE_DISK); + if (queued) { + // wait for invalidate + sdbg(DF_DETAIL, "queued for invalidate"); + + if (unlikely(queued < 0)) + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + + spin_unlock_irq(&dmc->cache_spin_lock); + return; + } +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (res == -1 || uncacheable || entry_in_correcting) { + // If any ranges of entry are correcting, should keep doing disk IO + if (corr_bi_flags && (TYPE_UNINITED == correcting_type)) { + if (-1 == correction_range_set_type(dmc, bio_bi_sector(bio), DISK_CORRECTING)) { + serr("Fail to set correction device DISK type on uncache"); + } + } else if (SSD_CORRECTING == correcting_type) { + sdbg(DF_CORRECTION, "Range is already in SSD_CORRECTING state"); + } +#else + if (res == -1 || uncacheable) { +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + + if (uncache_seq) { + atomic64_inc(&dmc->flashcache_stats.uncached_sequential_reads); + } + + /* No room , non-cacheable or sequential i/o means not wanted in cache */ + spin_unlock_irq(&dmc->cache_spin_lock); + DPRINTK("Cache read: Block %llu(%lu):%s", + bio_bi_sector(bio), bio_bi_size(bio), "CACHE MISS & NO ROOM"); +#ifdef MY_ABC_HERE +#else + if (res == -1) { + flashcache_clean_set(dmc, hash_block(dmc, bio_bi_sector(bio))); + } +#endif + sdbg(DF_DETAIL, "start uncached IO"); + + /* Start uncached IO */ + flashcache_start_uncached_io(dmc, bio, NULL, TYPE_DISK); + return; + } + /* + * (res == INVALID) Cache Miss + * And we found cache blocks to replace + * Claim the cache blocks before giving up the spinlock + */ + if (dmc->cache[index].cache_state & VALID) { + atomic64_inc(&dmc->flashcache_stats.replace); + } else { + atomic64_inc(&dmc->cached_blocks); + } + cb_state_assign_update_counts(dmc, &dmc->cache[index], VALID | DISKREADINPROG); +#ifdef MY_ABC_HERE + cacheblk_set_pin_state_by_bio(dmc, &dmc->cache[index], bio); +#endif + cacheblk_unset_all_data_range(&dmc->cache[index]); + dmc->cache[index].dbn = cacheblk_get_start_sector(dmc, bio); + cacheblk_set_all_io_range(&dmc->cache[index]); + cacheblk_add_num_concurrent(&dmc->cache[index]); + spin_unlock_irq(&dmc->cache_spin_lock); + + DPRINTK("Cache read: Block %llu(%lu), index = %d:%s", + bio_bi_sector(bio), bio_bi_size(bio), index, "CACHE MISS & REPLACE"); + flashcache_read_miss(dmc, bio, index); +} + +/* + * Invalidate any colliding blocks if they are !BUSY and !DIRTY. If the colliding + * block is DIRTY, we need to kick off a write. In both cases, we need to wait + * until the underlying IO is finished, and then proceed with the invalidation. + * SYNO: + * Under lock + * plat and io_type are mutual exclusive. Given plat, we use plat->io_type. + */ +static int +flashcache_inval_block_set(struct cache_c *dmc, int set, struct bio *bio, int rw, + struct pending_job *pjob, struct io_latency *plat, + enum cache_io_type io_type) +{ + sector_t io_start = cacheblk_get_start_sector(dmc, bio); + // Assume the bio doesn't across two cacheblocks, checked in flashcache_map + sector_t io_end = io_start + (dmc->block_size - 1); + int start_index = 0, end_index = 0, i = 0; + struct cacheblock *cacheblk = NULL; + sector_t start_dbn = 0; + sector_t end_dbn = 0; + + VERIFY_WARN(io_end >= bio_last_sector(bio)); + + start_index = dmc->assoc * set; + end_index = start_index + dmc->assoc; + for (i = start_index ; i < end_index ; i++) { + start_dbn = dmc->cache[i].dbn; + end_dbn = start_dbn + dmc->block_size; + + cacheblk = &dmc->cache[i]; + if (cacheblk->cache_state & INVALID) + continue; + if (io_start >= start_dbn && io_start < end_dbn) { + break; + } + } + if (i == end_index) { + return 0; + } + + /* We have a match */ + if (rw == WRITE) + atomic64_inc(&dmc->flashcache_stats.wr_invalidates); + else { + sdbg(DF_DETAIL, "bi_sector=%llu bi_size=%llu io_start=%llu" + "io_end=%llu start_dbn=%llu end_dbn=%llu", + (u64)bio_bi_sector(bio), (u64)bio_sectors(bio), (u64)io_start, + (u64)io_end, (u64)start_dbn, (u64)end_dbn); + atomic64_inc(&dmc->flashcache_stats.rd_invalidates); + } + + if (!(cacheblk->cache_state & (BLOCK_IO_INPROG | DIRTY | SYNCED_BITS)) && + (cacheblk->nr_queued == 0)) { +#ifdef CONFIG_SYNO_DATA_CORRECTION + sdbg(DF_CORRECTION, "Check if abort correction"); + correction_entry_record_cache_addr(dmc, i, bio_bi_sector(bio)); + correction_entry_set_abort_bitmap(dmc, bio_bi_sector(bio)); +#endif + atomic64_dec(&dmc->cached_blocks); + cb_state_assign_update_counts(dmc, cacheblk, INVALID); + return 0; + } + /* + * The conflicting block has either IO in progress or is + * Dirty. In all cases, we need to add ourselves to the + * pending queue. Then if the block is dirty, we kick off + * an IO to clean the block. + * Note that if the block is dirty and IO is in progress + * on it, the do_pending handler will clean the block + * and then process the pending queue. + */ + flashcache_enq_pending(dmc, bio, i, INVALIDATE, pjob, plat, io_type); + if (!(cacheblk->cache_state & BLOCK_IO_INPROG)) { + if (cacheblk->cache_state & DIRTY) { + /* + * Kick off block write. + * We can't kick off the write under the spinlock. + * Instead, we mark the slot DISKWRITEINPROG, drop + * the spinlock and kick off the write. A block marked + * DISKWRITEINPROG cannot change underneath us. + * to enqueue ourselves onto it's pending queue. + * + * XXX - The dropping of the lock here can be avoided if + * we punt the cleaning of the block to the worker thread, + * at the cost of a context switch. + */ + atomic64_inc(&dmc->flashcache_stats.inval_dirty_writeback); + start_force_wb_to_invalid(dmc, i); + spin_lock_irq(&dmc->cache_spin_lock); + } else if (cacheblk->cache_state & SYNCED_BITS) { + VERIFY_WARN(!(cacheblk->cache_state & FORCEDMU)); +#ifdef MY_ABC_HERE + start_force_mu_to_invalid(dmc, i); +#endif + spin_lock_irq(&dmc->cache_spin_lock); + } + } + // SYNO: queued + return 1; +} + +/* + * Since md will break up IO into blocksize pieces, we only really need to check + * the start set and the end set for overlaps. + * SYNO: + * Under lock + * plat and io_type are mutual exclusive. Given plat, we use plat->io_type. + * Return: 1 (queued) + * Return: 0 (not queued) + * Return < 0 on error + */ +static int +flashcache_inval_blocks(struct cache_c *dmc, struct bio *bio, struct io_latency *plat, + enum cache_io_type io_type) +{ + // same as invalidate_block_set + sector_t io_start = cacheblk_get_start_sector(dmc, bio); + // Assume the bio won't across two cacheblocks, check it in flashcache_map + int start_set; + int queued; + struct pending_job *pjob = NULL; + + pjob = flashcache_alloc_pending_job(dmc); + if (unlikely(dmc->sysctl_error_inject & INVAL_PENDING_JOB_ALLOC_FAIL)) { + if (pjob) { + flashcache_free_pending_job(pjob); + pjob = NULL; + } + dmc->sysctl_error_inject &= ~INVAL_PENDING_JOB_ALLOC_FAIL; + } + if (pjob == NULL) { + queued = -ENOMEM; + goto out; + } + + start_set = hash_block(dmc, io_start); + queued = flashcache_inval_block_set(dmc, start_set, bio, + bio_data_dir(bio), pjob, plat, io_type); + if (queued) { + goto out; + } else { + flashcache_free_pending_job(pjob); + } +out: + return queued; +} + +// SYNO: Under lock +static void +flashcache_write_miss(struct cache_c *dmc, struct bio *bio, int index) +{ + struct cacheblock *cacheblk; + struct kcached_job *job; + int queued; + int comp_dm_op = bio_has_fua_flags(bio) ? COMP_DM_WRITE_FUA : COMP_DM_WRITE; + + cacheblk = &dmc->cache[index]; + // TODO: maybe can remove, added probably because bio in + // old 4k driver can cross multiple cacheblk + queued = flashcache_inval_blocks(dmc, bio, NULL, TYPE_COULD_SSD); + if (queued) { + VERIFY_WARN(0); + atomic64_inc(&dmc->flashcache_stats.write_miss_inval); + if (unlikely(queued < 0)) { + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + } + sdbg(DF_DETAIL, "enq_pending finish"); + spin_unlock_irq(&dmc->cache_spin_lock); + return; + } +#ifdef MY_ABC_HERE + atomic64_inc(&dmc->flashcache_stats.wr_miss_ssd); +#endif + + if (cacheblk->cache_state & VALID) { + atomic64_inc(&dmc->flashcache_stats.wr_replace); + } else { + atomic64_inc(&dmc->cached_blocks); + } + cb_state_assign_update_counts(dmc, cacheblk, VALID | CACHEWRITEINPROG); +#ifdef MY_ABC_HERE + cacheblk_set_pin_state_by_bio(dmc, cacheblk, bio); +#endif + cacheblk_unset_all_data_range(cacheblk); + cacheblk->dbn = cacheblk_get_start_sector(dmc, bio); + cacheblk_add_io_range_by_bio(cacheblk, bio); + cacheblk_add_num_concurrent(cacheblk); + + if (global_tester == TEST_OQF_INVALIDATE_DELAY) { + serr("write miss idx: %d", index); + } + + spin_unlock_irq(&dmc->cache_spin_lock); + job = new_kcached_job(dmc, bio, index, NULL, TYPE_SSD); + if (unlikely(dmc->sysctl_error_inject & WRITE_MISS_JOB_ALLOC_FAIL)) { + if (job) + flashcache_free_cache_job(job); + job = NULL; + dmc->sysctl_error_inject &= ~WRITE_MISS_JOB_ALLOC_FAIL; + } + if (unlikely(job == NULL)) { + /* + * We have a write miss, and can't allocate a job. + * Since we dropped the spinlock, we have to drain any + * pending jobs. + */ + DMERR("flashcache: Write (miss) failed ! Can't allocate memory for cache IO, block %llu", + (u64)cacheblk->dbn); + + spin_lock_irq(&dmc->cache_spin_lock); + atomic64_dec(&dmc->cached_blocks); + cb_state_remove_bits_update_counts(dmc, cacheblk, VALID); + +#ifdef MY_ABC_HERE + cacheblk_check_unset_pin_state(dmc, cacheblk); +#endif + cb_state_add_bits_update_counts(dmc, cacheblk, INVALID); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + + cacheblk_remove_io_range_change_state_by_bio(dmc, cacheblk, bio); + cacheblk_dec_num_concurrent_and_return(cacheblk); + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + + spin_unlock_irq(&dmc->cache_spin_lock); + } else { + atomic_inc(&dmc->nr_jobs); + atomic64_inc(&dmc->flashcache_stats.ssd_writes); + job->action = WRITECACHE; + atomic_inc(&dmc->num_write_cache); + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + /* Write data to the cache */ + job_dbg(__func__, job); + dm_io_async_bio_wrapper(1, &job->job_io_regions.cache, comp_dm_op, + bio, flashcache_io_callback_atomic, job, 0); + } else { + atomic64_inc(&dmc->flashcache_stats.disk_writes); + + VERIFY_WARN(dmc->cache_mode == FLASHCACHE_WRITE_THROUGH); + /* Write data to both disk and cache */ + dm_io_async_bio_wrapper(2, (struct dm_io_region*)&job->job_io_regions, + comp_dm_op, bio, flashcache_io_callback_atomic, job, 0); + } +#ifdef MY_ABC_HERE +#else + flashcache_clean_set(dmc, index / dmc->assoc); +#endif + } +} + +static void +flashcache_write_hit(struct cache_c *dmc, struct bio *bio, int index) +{ + struct cacheblock *cacheblk; + struct pending_job *pjob; + struct kcached_job *job; + match_t match_io_range = MATCH_UNSET; + unsigned long bi_flags = 0; + int comp_dm_op = bio_has_fua_flags(bio) ? COMP_DM_WRITE_FUA : COMP_DM_WRITE; + + cacheblk = &dmc->cache[index]; +#ifdef MY_ABC_HERE + cacheblk_set_pin_state_by_bio(dmc, cacheblk, bio); +#endif + +#ifdef CONFIG_SYNO_DATA_CORRECTION + bi_flags = bio->bi_flags & ((1 << BIO_CORRECTION_RETRY) | (1 << BIO_CORRECTION_ABORT)); +#endif + + match_io_range = cacheblk_compare_io_range(cacheblk, bio); + + if ((MATCH_NONE == match_io_range) && (cacheblk->nr_queued == 0)) { + /* + * Cases: + * All in data range / Partial in data range / NONE in data range + */ + if (cacheblk->cache_state & DIRTY) { + atomic64_inc(&dmc->flashcache_stats.dirty_write_hits); + } + atomic64_inc(&dmc->flashcache_stats.write_hits); + cb_state_add_bits_update_counts(dmc, cacheblk, CACHEWRITEINPROG); + + cacheblk_add_io_range_by_bio(cacheblk, bio); + cacheblk_add_num_concurrent(cacheblk); + + spin_unlock_irq(&dmc->cache_spin_lock); + job = new_kcached_job(dmc, bio, index, NULL, TYPE_SSD); + if (unlikely(dmc->sysctl_error_inject & WRITE_HIT_JOB_ALLOC_FAIL)) { + if (job) + flashcache_free_cache_job(job); + job = NULL; + dmc->sysctl_error_inject &= ~WRITE_HIT_JOB_ALLOC_FAIL; + } + if (unlikely(job == NULL)) { + /* + * We have a write hit, and can't allocate a job. + * Since we dropped the spinlock, we have to drain any + * pending jobs. + */ + DMERR("flashcache: Write (hit) failed ! Can't allocate memory for cache IO, block %llu", + (u64)cacheblk->dbn); + + spin_lock_irq(&dmc->cache_spin_lock); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + + cacheblk_remove_io_range_change_state_by_bio(dmc, cacheblk, bio); + cacheblk_dec_num_concurrent_and_return(cacheblk); + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + + spin_unlock_irq(&dmc->cache_spin_lock); + } else { + DPRINTK("Queue job for %llu", bio_bi_sector(bio)); + atomic_inc(&dmc->nr_jobs); + atomic64_inc(&dmc->flashcache_stats.ssd_writes); + job->action = WRITECACHE; + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + /* Write data to the cache */ + job_dbg(__func__, job); + atomic_inc(&dmc->num_write_cache); + dm_io_async_bio_wrapper(1, &job->job_io_regions.cache, comp_dm_op, + bio, flashcache_io_callback_atomic, job, bi_flags); + +#ifdef MY_ABC_HERE +#else + flashcache_clean_set(dmc, index / dmc->assoc); +#endif + } else { + VERIFY_WARN(dmc->cache_mode == FLASHCACHE_WRITE_THROUGH); + /* Write data to both disk and cache */ + atomic64_inc(&dmc->flashcache_stats.disk_writes); + dm_io_async_bio_wrapper(2, (struct dm_io_region*)&job->job_io_regions, + comp_dm_op, bio, flashcache_io_callback_atomic, + job, bi_flags); + } + } + } else { + pjob = flashcache_alloc_pending_job(dmc); + if (unlikely(dmc->sysctl_error_inject & WRITE_HIT_PENDING_JOB_ALLOC_FAIL)) { + if (pjob) { + flashcache_free_pending_job(pjob); + pjob = NULL; + } + dmc->sysctl_error_inject &= ~WRITE_HIT_PENDING_JOB_ALLOC_FAIL; + } + atomic64_inc(&dmc->flashcache_stats.write_hit_busy_inval); + + // add braces here + if (unlikely(pjob == NULL)) { + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + } else { + /* + * Do not add pending WRITE_CACHE job to num_write_cache since + * later it would be done by uncached IO + */ + sdbg(DF_DETAIL, "enq_pending"); + flashcache_enq_pending(dmc, bio, index, WRITECACHE, pjob, + NULL, TYPE_COULD_SSD); + } + + spin_unlock_irq(&dmc->cache_spin_lock); + } +} + +static void +flashcache_write(struct cache_c *dmc, struct bio *bio) +{ + int index; + int res; + struct cacheblock *cacheblk; + int queued; +#ifdef CONFIG_SYNO_DATA_CORRECTION + correcting_type_t correcting_type = NO_CORRECTING; + int entry_in_correcting = 0; + + correcting_type = correction_range_get_type(dmc, bio_bi_sector(bio)); + entry_in_correcting = correction_entry_in_correcting(dmc, bio_bi_sector(bio), DO_LOCK); +#endif + + spin_lock_irq(&dmc->cache_spin_lock); + res = flashcache_lookup(dmc, bio, &index); + +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (res != -1 && DISK_CORRECTING != correcting_type) { +#else + if (res != -1) { +#endif + /* Cache Hit */ + cacheblk = &dmc->cache[index]; + /* + * Three cases go here + * 1 VALID with matched cacheblk (Cache state is VALID) + * 2 INVALID with state==INVALID cacheblk + * 3 INVALID with old VALID cacheblk (Cache state == VALID) (reclaim_oldest_clean!) + * To distiguish 1 & 3, the old way is to check if cacheblk->dbn match ! + */ + if ((VALID == res) && (cacheblk->cache_state & VALID)) { + if (bio_bi_sector(bio) < cacheblk->dbn) { + serr("compare_io_range: index=%d cacheblk.dbn=%llu bi_sector=%llu", + index, (u64)cacheblk->dbn, (u64)bio_bi_sector(bio)); + VERIFY_WARN(0); + } + /* Cache Hit */ + flashcache_write_hit(dmc, bio, index); + } else { +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (entry_in_correcting) { + sdbg(DF_CORRECTION, "correcting is now on disk, should not write ssd."); + goto UNCACHE_WRITE; + } +#endif + /* Cache Miss, found block to recycle */ + flashcache_write_miss(dmc, bio, index); + } + return; + } // check res + + sdbg(DF_DETAIL, "write: noroom"); +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (DISK_CORRECTING == correcting_type) { + sdbg(DF_DETAIL, "write: correcting on disk"); + } + +UNCACHE_WRITE: +#endif + /* + * No room in the set. We cannot write to the cache and have to + * send the request to disk. Before we do that, we must check + * for potential invalidations ! + */ + queued = flashcache_inval_blocks(dmc, bio, NULL, TYPE_COULD_SSD); + spin_unlock_irq(&dmc->cache_spin_lock); + if (queued) { + if (unlikely(queued < 0)) + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + return; + } + /* Start uncached IO */ + flashcache_start_uncached_io(dmc, bio, NULL, TYPE_COULD_SSD); +#ifdef MY_ABC_HERE +#else + flashcache_clean_set(dmc, index / dmc->assoc); +#endif +} + +#define bio_barrier(bio) (bio_op_rw(bio) & COMP_REQ_FLUSH) + +#ifdef MY_ABC_HERE +/* + * Assume a bio won't across two cache block + * Due to we set spilt_io to 4KB + */ +int is_across_two_cacheblk(struct cache_c *dmc, struct bio *bio) +{ + int ret = 0; + char bio_str[BIO_STR_MAX] = {0}; + sector_t cacheblk_start_sector = 0; + sector_t cacheblk_end_secotr = 0; + + VERIFY_WARN(dmc && bio); + cacheblk_start_sector = cacheblk_get_start_sector(dmc, bio); + cacheblk_end_secotr = cacheblk_start_sector + dmc->block_size - 1; + + if (bio_last_sector(bio) > cacheblk_end_secotr) { + serr("Should not across two cacheblock %s", bio_to_str(bio, bio_str, sizeof(bio_str))); + VERIFY_WARN(0); + ret = 1; + } + + return ret; +} + +#ifdef MY_DEF_HERE +// Also update cache_bio->next_bv_idx +static void init_subbio_bvec_fields(struct shared_data *shared_data, struct subbio *subbio) +{ + struct bio *master_bio = shared_data->master_bio; + struct bio_vec *bvec = NULL; + int found_first_bv = 0; + int found_last_bv = 0; + int i = 0; + unsigned int first_bv_offset_advance = 0; + int bv_len_occupy = 0; + + u64 bio_offset_byte = to_bytes(subbio->start_sector - bio_bi_sector(master_bio)); + u64 bio_size_bytes = to_bytes(subbio->num_sectors); + + /* + * For kernel 4.4, we hack __bio_clone_fast() to make bi_vcnt of master_bio + * is not zero + */ + VERIFY_WARN(master_bio->bi_vcnt); + + VERIFY_WARN(shared_data && subbio && master_bio); + + for (i = shared_data->next_bv_idx; i < master_bio->bi_vcnt; i++) { + + bvec = &master_bio->bi_io_vec[i]; + + if (!found_first_bv) { + + if ((shared_data->bv_len_sum + bvec->bv_len) > bio_offset_byte) { + // Got first bvec + first_bv_offset_advance = bio_offset_byte - shared_data->bv_len_sum; + subbio->first_bv_offset = bvec->bv_offset + first_bv_offset_advance; + subbio->first_bv_idx = i; + subbio->first_bv_len = bvec->bv_len - first_bv_offset_advance; + found_first_bv = 1; + + bv_len_occupy = subbio->first_bv_len; + + if (bv_len_occupy >= bio_size_bytes) { + // Also the last bv + subbio->first_bv_len = bio_size_bytes; + subbio->last_bv_len = bio_size_bytes; + subbio->last_bv_idx = i; + sdbg(DF_DETAIL, "found last bv"); + found_last_bv = 1; + break; + } + } + shared_data->bv_len_sum += bvec->bv_len; + } else { + // Already found the first bv + if ((bv_len_occupy + bvec->bv_len) >= bio_size_bytes) { + subbio->last_bv_len = bio_size_bytes - bv_len_occupy; + subbio->last_bv_idx = i; + found_last_bv = 1; + break; + } else { + bv_len_occupy += bvec->bv_len; + shared_data->bv_len_sum += bvec->bv_len; + } + } + } + + VERIFY_WARN(found_first_bv); + VERIFY_WARN(found_last_bv); + + shared_data->next_bv_idx = subbio->last_bv_idx; + sdbg(DF_DETAIL, "subbio bi_sector=%llu first_bv_len=%u fisrt_bv_offset=%u first_bv_idx=%hu last_bv_len=%u \ + last_bv_idx=%hu", + (u64)subbio->start_sector, subbio->first_bv_len, subbio->first_bv_offset, + subbio->first_bv_idx, subbio->last_bv_len, subbio->last_bv_idx); +} + +/* + * Return 1 when there's no sub-bios + */ +int cache_bio_get_next_bio_info(struct shared_data *shared_data, struct subbio *subbio) +{ + + sector_t sectors_to_previous_algin = 0; + sector_t sectors_to_next_align = 0; + sector_t sectors_to_handle = 0; + sector_t unhandled_sectors = 0; + + VERIFY_WARN(shared_data && subbio); + + unhandled_sectors = shared_data->unhandled_sectors; + + if (0 == unhandled_sectors) { + sdbg(DF_DETAIL, "No more sub-bios in the cache bio"); + return 1; + } + + subbio->start_sector = shared_data->next_bio_start; + sectors_to_previous_algin = compatible_mod(shared_data->next_bio_start, MAX_BIO_SIZE); + sectors_to_next_align = MAX_BIO_SIZE - sectors_to_previous_algin; + sectors_to_handle = (sectors_to_next_align < unhandled_sectors) ? sectors_to_next_align : unhandled_sectors; + subbio->num_sectors = sectors_to_handle; + + // Update shared data information + shared_data->next_bio_start += sectors_to_handle; + shared_data->unhandled_sectors -= sectors_to_handle; + + init_subbio_bvec_fields(shared_data, subbio); + + return 0; +} + +typedef enum __tag_SUB_BIO_STATUS { + SUB_BIO_CLONE_ERROR = -2, + SUB_BIO_NONE = -1, + SUB_BIO_NORMAL +} SUB_BIO_STATUS; + +struct bio* cache_bio_alloc_subbio(struct shared_data *shared_data, struct subbio *subbio) +{ + struct bio *master_bio = shared_data->master_bio; + struct bio *bio = NULL; + unsigned short bv_count = 0; + + bv_count = subbio->last_bv_idx - subbio->first_bv_idx + 1; + + bio = bio_alloc_bioset(GFP_NOIO, bv_count, pcache_bio_set); + if (!bio) { + serr("blo_alloc_bioset failed"); + return NULL; + } + + /* + * In original bio_clone_bioset() , it deals with bio_integrity property. + * However, this property seems to be reserved for file system to implement + * data integrity and no one use it yet. So we doesn't support it now + */ + if (bio_integrity(bio)) { + serr("Doesn't support bio_integrity"); + VERIFY_WARN(0); + } + + // Refer to bio_clone and md_trim_bio + *bio_bi_sector_ptr(bio) = subbio->start_sector; + *bio_bi_size_ptr(bio) = to_bytes(subbio->num_sectors); + bio_assign_same_dev(bio, master_bio); + + // Set BIO_CLONE to indicate that it doesn't own data + bio->bi_flags |= 1 << BIO_CLONED; + bio_op_rw(bio) = bio_op_rw(master_bio); + + memcpy(bio->bi_io_vec, master_bio->bi_io_vec + subbio->first_bv_idx, + bv_count * sizeof(struct bio_vec)); + + *bio_bi_idx_ptr(bio) = 0; + bio->bi_vcnt = bv_count; + + // Change the first bv + bio->bi_io_vec[0].bv_offset = subbio->first_bv_offset; + bio->bi_io_vec[0].bv_len = subbio->first_bv_len; + + // Change the last bv + bio->bi_io_vec[bv_count - 1].bv_len = subbio->last_bv_len; + + // Drop BIO_SEG_VALID since we change the bi_idx and bi_vcnt (refer to md_trim_bio()) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + bio_clear_flag(bio, BIO_SEG_VALID); +#else + clear_bit(BIO_SEG_VALID, &bio->bi_flags); +#endif + + sdbg(DF_DETAIL, "bi_sector=%llu bi_size=%u bi_idx=%hu bi_vcnt=%hu", (u64)bio_bi_sector(bio), + bio_bi_size(bio), bio_bi_idx(bio), bio->bi_vcnt); + sdbg(DF_DETAIL, "first bv[0]: offset=%u len=%u", bio->bi_io_vec[0].bv_offset, bio->bi_io_vec[0].bv_len); + sdbg(DF_DETAIL, "last bv[%hu]: len=%u", bv_count - 1, bio->bi_io_vec[bv_count - 1].bv_len); + + return bio; +} + +void cache_bio_set_num_total_bios(struct cache_bio *cache_bio, struct bio *master_bio) +{ + sector_t next_start_sector = 0; + int unhandled_sectors = 0; + // Sectors to the previos MAX_BIO_SIZE alignment + int sectors_to_previous_algin = 0; + int sectors_to_next_align = 0; + int next_bio_sectors = 0; + char bio_str[BIO_STR_MAX] = {0}; + + VERIFY_WARN(cache_bio && master_bio); + + sdbg_in(DF_DETAIL, "master_bio=%s", bio_to_str(master_bio, bio_str, sizeof(bio_str))); + + unhandled_sectors = bio_sectors(master_bio); + next_start_sector = bio_bi_sector(master_bio); + + while (1) { + sectors_to_previous_algin = compatible_mod(next_start_sector, MAX_BIO_SIZE); + sectors_to_next_align = MAX_BIO_SIZE - sectors_to_previous_algin; + next_bio_sectors = (sectors_to_next_align < unhandled_sectors) ? sectors_to_next_align : unhandled_sectors; + unhandled_sectors -= next_bio_sectors; + cache_bio->num_total_bios++; + + if (0 == unhandled_sectors) { + break; + } + next_start_sector += next_bio_sectors; + } + + sdbg_out(DF_DETAIL, "master_bio=%s num_total_bios=%d", bio_to_str(master_bio, bio_str, sizeof(bio_str)), cache_bio->num_total_bios); + +} + +static struct cache_bio * cache_bio_alloc_init(struct bio *master_bio, unsigned long start_jiffy) +{ + struct cache_bio *cache_bio = NULL; + char bio_str[BIO_STR_MAX] = {0}; + + VERIFY_WARN(master_bio); + + sdbg_in(DF_DETAIL, "master_bio=%s", bio_to_str(master_bio, bio_str, sizeof(bio_str))); + + cache_bio = mempool_alloc(_cache_bio_pool, GFP_NOIO); + if (NULL == cache_bio) { + serr("Can't allocate cache_bio"); + goto err; + } + + memset(cache_bio, 0, sizeof(struct cache_bio)); + + cache_bio->master_bio = master_bio; + cache_bio_set_num_total_bios(cache_bio, master_bio); + atomic_set(&cache_bio->num_completed_bios, 0); + + cache_bio->start_jiffy = start_jiffy; + + sdbg_out(DF_DETAIL, "master_bio=%s num_total_bios=%d", bio_to_str(master_bio, bio_str, sizeof(bio_str)), cache_bio->num_total_bios); +err: + return cache_bio; +} + +/* + * Return: + * SUB_BIO_CLONE_ERROR: on error + * SUB_BIO_NORMAL: Still has next subbio + * SUB_BIO_NONE: This is the final subbio + */ +static SUB_BIO_STATUS cache_bio_get_next_bio(struct cache_bio *cache_bio, + struct shared_data *shared_data, struct bio **ppbio, struct cache_c *dmc) +{ + SUB_BIO_STATUS status = SUB_BIO_CLONE_ERROR; + struct subbio subbio = {0}; +#ifdef MY_ABC_HERE + struct subbio_info *psubbio_info = NULL; + static int print_retry = 0; + + while (1) { + psubbio_info = kzalloc(sizeof(struct subbio_info), GFP_NOIO); + if (psubbio_info) { + break; + } else { + if (!print_retry) { + serr("Retry to allocate subbio info!"); + print_retry = 1; + } + msleep(100); + } + } +#endif + + VERIFY_WARN(shared_data && ppbio && dmc); + + if (cache_bio_get_next_bio_info(shared_data, &subbio)) { + // No subbio + status = SUB_BIO_NONE; + goto end; + } + + *ppbio = cache_bio_alloc_subbio(shared_data, &subbio); + if (NULL == *ppbio) { + serr("Failed to clone cache bio"); + goto end; + } + +#ifdef MY_ABC_HERE + psubbio_info->pcache_bio = cache_bio; + psubbio_info->is_pin = 0; + (*ppbio)->bi_private = psubbio_info; +#else + (*ppbio)->bi_private = cache_bio; +#endif + status = SUB_BIO_NORMAL; + sdbg(DF_DETAIL, "next bio=%p bi_sector=%llu size=%llu", *ppbio, (u64)bio_bi_sector(*ppbio), (u64)to_sector(bio_bi_size(*ppbio))); + VERIFY_WARN(0 != bio_bi_size(*ppbio)); + +end: +#ifdef MY_ABC_HERE + if (status != SUB_BIO_NORMAL) { + if (psubbio_info) { + kfree(psubbio_info); + } + } +#endif + return status; + +} + +/* + * Return NULL on error + * Note: Can't be called under lock + */ + +struct bio ** cache_bio_get_bios(struct cache_bio *cache_bio, struct cache_c *dmc) +{ + int i = 0; + struct bio **ppbios = NULL; + struct bio *master_bio = cache_bio->master_bio; + struct shared_data shared_data = {0}; + int size = 0; + char bio_str[BIO_STR_MAX] = {0}; + SUB_BIO_STATUS sub_bio_status = SUB_BIO_CLONE_ERROR; + + VERIFY_WARN(cache_bio && dmc); + + sdbg_in(DF_DETAIL, "master bio: %s", bio_to_str(master_bio, bio_str, sizeof(bio_str))); + + size = cache_bio->num_total_bios * sizeof(struct bio *); + + ppbios = kmalloc(size, GFP_NOIO); + if (NULL == ppbios) { + serr("Can't allocate subbio arrsy!"); + return NULL; + } + + memset(ppbios, 0, size); + + shared_data.master_bio = master_bio; + shared_data.next_bio_start = bio_bi_sector(master_bio); + shared_data.unhandled_sectors = bio_sectors(master_bio); + shared_data.next_bv_idx = bio_bi_idx(master_bio); + + for (i = 0; i < cache_bio->num_total_bios ; i++) { + sub_bio_status = cache_bio_get_next_bio(cache_bio, &shared_data, &ppbios[i], dmc); + if (SUB_BIO_CLONE_ERROR == sub_bio_status) { + serr("Get next subbio failed"); + goto err; + } + + // Should get each subbio + VERIFY_WARN(SUB_BIO_NONE != sub_bio_status); + } + + sdbg_out(DF_DETAIL, "master_bio: %s", bio_to_str(master_bio, bio_str, sizeof(bio_str))); + + return ppbios; + +err: + for (i = 0; i < cache_bio->num_total_bios; i++) { + if (NULL != ppbios[i]) { + // For bio_alloc + bio_put(ppbios[i]); + } + } + + if (ppbios) { + kfree(ppbios); + } + + sdbg_out(DF_DETAIL, "master_bio: %s", bio_to_str(cache_bio->master_bio, bio_str, sizeof(bio_str))); + + return NULL; +} + +#else /* NOT MY_DEF_HERE */ + +static struct cache_bi_private * +cache_bi_private_alloc_init(struct bio *master_bio, unsigned long start_jiffy) +{ + struct cache_bi_private *private = NULL; + int err = 0; + + VERIFY_WARN(master_bio); + + private = mempool_alloc(_cache_bi_private_pool, GFP_NOIO); + if (NULL == private) { + serr("Can't allocate cache bi private data"); + err = 1; + goto end; + } + + memset(private, 0, sizeof(struct cache_bi_private)); + private->master_bio_private = master_bio->bi_private; + private->start_jiffy = start_jiffy; + private->is_pin = 0; + +end: + if (err && private) { + mempool_free(private, _cache_bi_private_pool); + private = NULL; + } + return private; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +#else +#ifdef MY_ABC_HERE +void +flush_bios_complete(unsigned long error, void *context) +{ + struct flush_data *data = (struct flush_data *)context; + struct cache_c *dmc = data->dmc; + struct bio *master_bio = data->master_bio; + int bio_error = 0; + + if (dmc->sysctl_error_inject & FLUSH_BIO_ERROR) { + sprint("Detect flag, simulate flush error"); + dmc->sysctl_error_inject &= ~FLUSH_BIO_ERROR; + error = 3; + } + + // Bit 0 + if (error & (1 << 0)) { + if (printk_ratelimit()) { + serr("Send COMP_DM_WRITE_FLUSH to Disk failed"); + } + bio_error = COMP_BIO_ERROR; + } + + // Bit 1 + if (error & (1 << 1)) { + if (dmc->bypass_cache) { + if (printk_ratelimit()) { + serr("Bypass mode, ignore the error of sending COMP_DM_WRITE_FLUSH to SSD"); + } + } else if ((FLASHCACHE_WRITE_AROUND == dmc->cache_mode)) { + // First get error + if (printk_ratelimit()) { + serr("Send COMP_DM_WRITE_FLUSH failed. set to bypass mode"); + } + dmc->bypass_cache = 1; + } else if (is_writeback_crash_safe_set_bypass(dmc)) { + if (printk_ratelimit()) { + serr("Send WRITE_FLUSH failed. set to bypass mode"); + } + } else { + if (printk_ratelimit()) { + serr("Send COMP_DM_WRITE_FLUSH to SSD failed"); + } + bio_error = COMP_BIO_ERROR; + } + } + + VERIFY_WARN(master_bio != NULL); + + flashcache_check_process_io_latency(dmc, &data->io_lat, LAT_FLUSH_BIO); + + /* + * Note: Traced dm.c, found __map_bio->dec_pending() does not return REQ_FLUSH error to + * the upper layer. It just removes REQ_FLUSH and resends the bio ... + */ + bio_endio_wrapper(master_bio, bio_error); +#ifdef MY_ABC_HERE + handle_master_io_finish(dmc); +#endif /* MY_ABC_HERE */ + kfree(data); +} + +struct flush_data * +alloc_flush_data(void) +{ + static int print = 0; + struct flush_data *data = NULL; + + while (1) { + data = kzalloc(sizeof(struct flush_data), GFP_NOIO); + if (data) { + break; + } else { + if (!print) { + serr("Retry to allocate flush_data"); + print = 1; + } + msleep(100); + } + } + + return data; +} + +void +send_flush_bios(struct cache_c *dmc, struct bio *master_bio, unsigned long start_jiffy) +{ + struct dm_io_region io_regions[2]; + struct flush_data *data = NULL; + int send_region = 0; + + memset(io_regions, 0, sizeof(io_regions)); + + atomic_inc(&dmc->in_flush); + + wait_event(dmc->wait_io_done_queue, (!atomic_read(&dmc->num_uncached_write)) + && (!atomic_read(&dmc->num_write_cache))); + + data = alloc_flush_data(); + data->master_bio = master_bio; + data->dmc = dmc; + /* Has preprocess time */ + flashcache_init_io_latency(&data->io_lat, + dmc->sysctl_syno_latency_diagnose, TYPE_DISK, start_jiffy, 1); + + io_regions[0].bdev = get_disk_bdev(dmc); + io_regions[0].sector = 0; + io_regions[0].count = 0; + + io_regions[1].bdev = get_cache_bdev(dmc); + io_regions[1].sector = 0; + io_regions[1].count = 0; + + if (dmc->bypass_cache) { + // SSD RAID crash, only send to disks + send_region = 1; + } else { + send_region = 2; + } + + dm_io_async_bio_wrapper(send_region, io_regions, COMP_DM_WRITE_FLUSH, master_bio, + flush_bios_complete, data, 0); + + atomic_inc(&dmc->num_flush_bio); + atomic_dec(&dmc->in_flush); + wake_up(&dmc->wait_flush_queue); +} +#endif /* MY_ABC_HERE */ +#endif /* ! MY_ABC_HERE */ + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int flashcache_map_core(struct dm_target *ti, struct bio *master_bio, int enable_noclone); +int flashcache_map(struct dm_target *ti, struct bio *master_bio) +{ + return flashcache_map_core(ti, master_bio, 0); +} +int flashcache_noclone_map(struct dm_target *ti, struct bio *master_bio) +{ + return flashcache_map_core(ti, master_bio, 1); +} +#endif /* MY_ABC_HERE */ + +void +process_single_bio(struct cache_c *dmc, struct bio *master_bio, struct bio *bio) +{ + int queued = 0; + int uncacheable = 0; + int uncache_seq = 0; + +#ifdef CONFIG_SYNO_DATA_CORRECTION + if ((master_bio->bi_flags & (1 << BIO_CORRECTION_RETRY))) { + bio->bi_flags |= 1 << BIO_CORRECTION_RETRY; + sdbg(DF_CORRECTION, "cache: bio_sector=%llu set BIO_CORRECTION_RETRY", (u64)bio_bi_sector(bio)); + correction_handle_retry_io_start(dmc, bio_bi_sector(bio)); + } else if (master_bio->bi_flags & (1 << BIO_CORRECTION_ABORT)) { + bio->bi_flags |= 1 << BIO_CORRECTION_ABORT; + sdbg(DF_CORRECTION, "cache: bio_sector=%llu set BIO_CORRECTION_ABORT", (u64)bio_bi_sector(bio)); + } +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + +#ifdef MY_ABC_HERE + bio_set_pin_state(dmc, bio); +#endif + + if (bio_data_dir(bio) == READ) + atomic64_inc(&dmc->flashcache_stats.reads); + else + atomic64_inc(&dmc->flashcache_stats.writes); + + uncacheable = flashcache_uncacheable(dmc, bio, &uncache_seq); + + spin_lock_irq(&dmc->cache_spin_lock); +#ifdef MY_ABC_HERE +#else + if (unlikely(dmc->sysctl_pid_do_expiry && + (dmc->whitelist_head || dmc->blacklist_head))) + flashcache_pid_expiry_all_locked(dmc); +#endif + + if (unlikely(dmc->bypass_cache) || + compatible_mod(bio_bi_sector(bio), ALIGNED_SECTORS) || + compatible_mod(bio_sectors(bio), ALIGNED_SECTORS) || + is_across_two_cacheblk(dmc, bio) || + (bio_data_dir(bio) == WRITE && + (dmc->cache_mode == FLASHCACHE_WRITE_AROUND || uncacheable))) { + + if (compatible_mod(bio_bi_sector(bio), ALIGNED_SECTORS) || + compatible_mod(bio_sectors(bio), ALIGNED_SECTORS)) { + sdbg(DF_DETAIL, "bi_sector=%llu bi_size=%llu is not 4kb align", + (u64)bio_bi_sector(bio), (u64)bio_sectors(bio)); + atomic64_inc(&dmc->flashcache_stats.skip_unaligned_io); + + } else if (is_across_two_cacheblk(dmc, bio)) { + serr("across two cacheblks"); + VERIFY_WARN(0); + } else if (uncacheable) { + sdbg(DF_DETAIL, "bio is uncacheable"); + } else if (dmc->bypass_cache) { + sdbg(DF_DETAIL, "bypass_cache is set !"); + } else { + sdbg(DF_DETAIL, "others reason???"); + } + + if (bio_data_dir(bio) == WRITE && uncache_seq) { + atomic64_inc(&dmc->flashcache_stats.uncached_sequential_writes); + } + + queued = flashcache_inval_blocks(dmc, bio, NULL, TYPE_DISK); + + spin_unlock_irq(&dmc->cache_spin_lock); + if (queued) { + atomic64_inc(&dmc->flashcache_stats.map_inval); + if (uncacheable) { + atomic64_inc(&dmc->flashcache_stats.uncacheable_inval); + } + if (unlikely(queued < 0)) { + serr("unable to queue"); + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, NULL); + } + } else { + /* Start uncached IO */ + flashcache_start_uncached_io(dmc, bio, NULL, TYPE_DISK); + } + } else { + spin_unlock_irq(&dmc->cache_spin_lock); + if (bio_data_dir(bio) == READ) { + flashcache_read(dmc, bio, uncacheable, uncache_seq); + } else { + flashcache_write(dmc, bio); + } + } +} + +/* + * Decide the mapping and perform necessary cache operations for a bio request. + */ + +int +// Use master_bio to record the original bio +#ifdef MY_ABC_HERE +static flashcache_map_core(struct dm_target *ti, struct bio *master_bio, int enable_noclone) +#else +flashcache_map(struct dm_target *ti, struct bio *master_bio) +#endif /* MY_ABC_HERE */ +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + + // Record subbio + struct bio *bio = NULL; + char bio_str[BIO_STR_MAX] = {0}; + int sectors = to_sector(bio_bi_size(master_bio)); + static int print = 0; + unsigned long flags; + int go_wait = 0; + unsigned long start_jiffy = jiffies; +#ifdef MY_DEF_HERE + struct bio **ppbios = NULL; + struct cache_bio *cache_bio = NULL; + int i = 0; + int num_total_bios = 0; +#else + struct cache_bi_private *pcache_bi_private = NULL; +#endif + int err = 0; + + sdbg(DF_DETAIL, "master_bio: %s", bio_to_str(master_bio, bio_str, sizeof(bio_str))); + +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (master_bio->bi_flags & 1 << BIO_CORRECTION_RETRY) { + sdbg(DF_CORRECTION, "cache: get retry bio: %s:", bio_to_str(master_bio, bio_str, + sizeof(bio_str))); + } + if (master_bio->bi_flags & 1 << BIO_CORRECTION_ABORT) { + sdbg(DF_CORRECTION, "cache: get abort bio: %s:", bio_to_str(master_bio, bio_str, + sizeof(bio_str))); + } +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + +#ifdef CONFIG_SYNO_MD_UNUSED_HINT + if (bio_is_unused_hint(master_bio)) { + bio_assign_dev(master_bio, get_disk_bdev(dmc)); + return DM_MAPIO_REMAPPED; + } +#endif /* CONFIG_SYNO_MD_UNUSED_HINT */ + +#ifdef MY_ABC_HERE + if (enable_noclone) { + bio_assign_dev(master_bio, get_disk_bdev(dmc)); + return DM_MAPIO_REMAPPED; + } +#endif /* MY_ABC_HERE */ + + if (sectors <= MAX_HIST_SECTOR) + size_hist[sectors]++; + + // Use spin lock to make sure there're no another IOs enter here + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if ((CACHE_WAIT_OLD_IOS_COMPLETED == dmc->cache_state) + || (CACHE_WAIT_DISABLE == dmc->cache_state)) { + go_wait = 1; + } else { + atomic_inc(&dmc->num_master_io); + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + if (go_wait) { + wait_event(dmc->wait_for_cache_disable_queue, + (CACHE_DISABLED == dmc->cache_state)); + + atomic_inc(&dmc->num_master_io); + } + + if (CACHE_DISABLED == dmc->cache_state) { + bio_assign_dev(master_bio, get_disk_bdev(dmc)); + /* + * Processes in cache disable queue is waiting for cache to be disable, + * So when cache in disable mode, there is no process in queue + */ + atomic_dec(&dmc->num_master_io); + return DM_MAPIO_REMAPPED; + } + + if (bio_barrier(master_bio)) { + if ((0 == bio_bi_sector(master_bio)) + && (0 == bio_bi_size(master_bio)) + && (bio_has_flush_flags(master_bio))) { + // REQ_FLUSH bio + sdbg(DF_FLUSH_BIO, "flush bio: %s", bio_to_str(master_bio, bio_str, sizeof(bio_str))); + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode) { +#ifdef MY_ABC_HERE + syno_mu_start_ext_flush(dmc, master_bio, start_jiffy); +#else + send_flush_bios(dmc, master_bio, start_jiffy); +#endif + goto end; + } else { + bio_assign_dev(master_bio, get_disk_bdev(dmc)); + atomic_dec(&dmc->num_master_io); + return DM_MAPIO_REMAPPED; + } + } else { + if (!print) { + serr("Get unsupported flush bio: %s", bio_to_str(master_bio, bio_str, + sizeof(bio_str))); + print = 1; + } + handle_master_io_finish(dmc); + return -EOPNOTSUPP; + } + } else { + wait_event(dmc->wait_flush_queue, !atomic_read(&dmc->in_flush)); + } + +#ifdef MY_ABC_HERE + /* Force external IO to help send one md io when throttle triggered */ + syno_mu_dmcg_throtl(dmc); +#endif + +#ifdef MY_DEF_HERE + cache_bio = cache_bio_alloc_init(master_bio, start_jiffy); + if (NULL == cache_bio) { + serr("Cache bio can't be allocated"); + // Refer to read_hit allocate memory failed + bio_endio_wrapper(master_bio, -EIO); + handle_master_io_finish(dmc); + err = 1; + goto end; + } + + if (NULL == (ppbios = cache_bio_get_bios(cache_bio, dmc))) { + serr("Can't get subbios"); + bio_endio_wrapper(master_bio, -EIO); + handle_master_io_finish(dmc); + err = 1; + goto end; + } + + /* + * SYNO: cache_bio will be be freed by callback function + * in the following loop. We should keep num_total_bios + * in a local variable to avoid accessing freed memory + */ + num_total_bios = cache_bio->num_total_bios; + + while (i < num_total_bios) { + bio = ppbios[i++]; + process_single_bio(dmc, master_bio, bio); + } + +#else /* NOT MY_DEF_HERE */ + + if (bio_sectors(master_bio) > MAX_BIO_SIZE) { + serr("Error: bio sectors %d > %d", bio_sectors(master_bio), + MAX_BIO_SIZE); + err = 1; + goto end; + } + + pcache_bi_private = cache_bi_private_alloc_init(master_bio, start_jiffy); + if (!pcache_bi_private) { + serr("Failed to allocate cache bio info"); + err = 1; + goto end; + } + + bio = master_bio; + bio->bi_private = pcache_bi_private; + process_single_bio(dmc, master_bio, bio); + +#endif /* MY_DEF_HERE */ + +end: +#ifdef MY_DEF_HERE + if (ppbios) { + kfree(ppbios); + } +#endif + + if (err) { +#ifndef MY_DEF_HERE + if (pcache_bi_private) { + mempool_free(pcache_bi_private, _cache_bi_private_pool); + } +#endif + } + + sdbg(DF_DETAIL, "return, master_bio: %s", bio_str); + + return DM_MAPIO_SUBMITTED; +} + +#ifdef MY_ABC_HERE +#else +// for flashcache_kcopyd_callback_sync to invoke +static void flashcache_dirty_writeback_sync(struct cache_c *dmc, int index); + +/* Block sync support functions */ +static void +flashcache_kcopyd_callback_sync(int read_err, unsigned int write_err, void *context) +{ + struct kcached_job *job = (struct kcached_job *)context; + struct cache_c *dmc = job->dmc; + int index = job->index; + unsigned long flags; +#ifdef MY_ABC_HERE + struct cacheblock *cacheblk = &dmc->cache[index]; + struct cache_set *cacheset = &dmc->cache_sets[index / dmc->assoc]; +#endif + + VERIFY_WARN(!in_interrupt()); + DPRINTK("kcopyd_callback_sync: Index %d", index); + VERIFY_WARN(job->bio == NULL); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + VERIFY_WARN(dmc->cache[index].cache_state & (DISKWRITEINPROG | VALID | DIRTY)); + if (likely(read_err == 0 && write_err == 0)) { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); +#ifdef MY_ABC_HERE + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + cacheblk_unset_lowest_part_of_flushing_dirty_range(cacheblk); + + if (cacheblk_is_flushing_dirty_range_unset(cacheblk)) { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + flashcache_md_write(job); + } else { + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + flashcache_free_cache_job(job); + + /* + * Don't decrease nr_job due to we don't add it twice in partial access + * Trigger again + */ + flashcache_dirty_writeback_sync(dmc, index); + } +#else + flashcache_md_write(job); +#endif + } else { + if (read_err) + read_err = -EIO; + if (write_err) + write_err = -EIO; + /* Disk write failed. We can not purge this cache from flash */ +#ifdef MY_ABC_HERE + if (0 < dmc->limits.writeback_sync_err) { +#endif + DMERR("flashcache: Disk writeback failed ! read error %d write error %d block %llu", + -read_err, -write_err, (u64)job->job_io_regions.disk.sector); +#ifdef MY_ABC_HERE + dmc->limits.writeback_sync_err--; + } +#endif + dec_clean_inprog(dmc, cacheset, 1); + + cacheblk->flushing_dirty_bitmap = 0; + // io_range whould be unset in do_pending_xxx + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + /* Set the error in the job and let do_pending() handle the error */ + if (read_err) { + atomic_inc(&dmc->flashcache_errors.ssd_read_errors); + job->error = read_err; + } else { + atomic_inc(&dmc->flashcache_errors.disk_write_errors); + job->error = write_err; + } + flashcache_do_pending(job); + flashcache_sync_blocks(dmc); /* Kick off more cleanings */ + atomic64_inc(&dmc->flashcache_stats.cleanings); + } +} + +static void +flashcache_dirty_writeback_sync(struct cache_c *dmc, int index) +{ + struct kcached_job *job; + unsigned long flags; + struct cacheblock *cacheblk = &dmc->cache[index]; + struct cache_set *cacheset = &dmc->cache_sets[index / dmc->assoc]; + int device_removal = 0; + int first_time_flush = 0; + sector_t offset = 0; + sector_t size = 0; + int wakeup_sync_wqh = 0; + + VERIFY_WARN((cacheblk->cache_state & FALLOW_DOCLEAN) == 0); + DPRINTK("flashcache_dirty_writeback_sync: Index %d", index); + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + VERIFY_WARN((cacheblk->cache_state & BLOCK_IO_INPROG) == DISKWRITEINPROG); + VERIFY_WARN(cacheblk->cache_state & DIRTY); + + // Debug for call trace + if (0 == cacheblk->data_bitmap) { + serr("cb index=%d data_bitmap=0", index); + VERIFY_WARN(0); + } + + if (0 == cacheblk->flushing_dirty_bitmap) { + cacheblk->flushing_dirty_bitmap = cacheblk->dirty_bitmap; + first_time_flush = 1; + } + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + cacheblk_get_lowest_part_of_flushing_dirty_range(cacheblk, &offset, &size); + job = new_kcached_job_no_bio(dmc, index, offset, size); + VERIFY_WARN(NULL != job); + /* + * If the device is being (fast) removed, do not kick off any more cleanings. + */ + if (unlikely(atomic_read(&dmc->remove_in_prog) == FAST_REMOVE)) { + DMERR("flashcache: Dirty Writeback (for set cleaning) aborted for device removal, block %llu", (u64)cacheblk->dbn); + if (job) + flashcache_free_cache_job(job); + job = NULL; + device_removal = 1; + } +#ifdef MY_ABC_HERE + if (unlikely(dmc->sysctl_error_inject & WRITEBACK_JOB_ALLOC_ERROR)) { + dmc->sysctl_error_inject &= ~(WRITEBACK_JOB_ALLOC_ERROR); + if (job) { + flashcache_free_cache_job(job); + } + job = NULL; + } +#endif + if (unlikely(job == NULL)) { + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + dec_clean_inprog(dmc, cacheset, 1); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + cacheblk->flushing_dirty_bitmap = 0; + unset_partial_cb_writeback_attrs(dmc, cacheblk, 1); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + // cancel in the middle of partial flush + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wakeup_sync_wqh = 1; + } + + if (device_removal == 0) + DMERR("flashcache: Dirty Writeback (for sync) failed ! Can't allocate memory, block %llu", + (u64)cacheblk->dbn); + + if (wakeup_sync_wqh) { + wake_up(&dmc->sync_wqh); + } + } else { + job->bio = NULL; + job->action = WRITEDISK_SYNC; + + atomic64_inc(&dmc->flashcache_stats.ssd_reads); + atomic64_inc(&dmc->flashcache_stats.disk_writes); +#ifdef MY_ABC_HERE + atomic64_add(size, &dmc->flashcache_stats.dirty_writeback_sync_sector); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + kcopyd_copy(flashcache_kcp_client, &job->job_io_regions.cache, 1, &job->job_io_regions.disk, 0, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + flashcache_kcopyd_callback_sync, +#else + (kcopyd_notify_fn) flashcache_kcopyd_callback_sync, +#endif + job); +#else + dm_kcopyd_copy(flashcache_kcp_client, &job->job_io_regions.cache, 1, &job->job_io_regions.disk, 0, + (dm_kcopyd_notify_fn)flashcache_kcopyd_callback_sync, + (void *)job); +#endif + } +} + +/* + * Sync all dirty blocks. We pick off dirty blocks, sort them, merge them with + * any contigous blocks we can within the set and fire off the writes. + * + * NOT atomic context + */ +void +flashcache_sync_blocks(struct cache_c *dmc) +{ + unsigned long flags; + int index; + struct dbn_index_pair *writes_list; + int nr_writes; + int i, set; + struct cacheblock *cacheblk; + + /* + * If a (fast) removal of this device is in progress, don't kick off + * any more cleanings. This isn't sufficient though. We still need to + * stop cleanings inside flashcache_dirty_writeback_sync() because we could + * have started a device remove after tested this here. + */ + if ((atomic_read(&dmc->remove_in_prog) == FAST_REMOVE) || dmc->sysctl_stop_sync) + return; + + writes_list = kmalloc(dmc->assoc * sizeof(struct dbn_index_pair), GFP_NOIO); + if (writes_list == NULL) { + atomic_inc(&dmc->flashcache_errors.memory_alloc_errors); +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate atomic memory for syncing blocks"); + } +#endif + return; + } + nr_writes = 0; + set = -1; + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + index = dmc->sync_index; + while (index < dmc->size && dmc->clean_inprog < dmc->max_clean_ios_total) { + VERIFY_WARN(nr_writes <= dmc->assoc); + if (((index % dmc->assoc) == 0) && (nr_writes > 0)) { + /* + * Crossing a set, sort/merge all the IOs collected so + * far and issue the writes. + */ + VERIFY_WARN(set != -1); + flashcache_merge_writes(dmc, writes_list, &nr_writes, set); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + // SYNO: Set all io_range for drity_writeback_sync in below and merge_write + for (i = 0 ; i < nr_writes ; i++) + flashcache_dirty_writeback_sync(dmc, writes_list[i].index); + nr_writes = 0; + set = -1; + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + } + cacheblk = &dmc->cache[index]; + // SYNO: If BLOCK_IO_INPROG, it won't be flushed + if ((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { + set_wb_attrs(dmc, index, 1); + set = index / dmc->assoc; + writes_list[nr_writes].dbn = cacheblk->dbn; + writes_list[nr_writes].index = index; + nr_writes++; + } + index++; + } + + dmc->sync_index = index; + if (nr_writes > 0) { + VERIFY_WARN(set != -1); + flashcache_merge_writes(dmc, writes_list, &nr_writes, set); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + for (i = 0 ; i < nr_writes ; i++) + flashcache_dirty_writeback_sync(dmc, writes_list[i].index); + } else + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + kfree(writes_list); +} +#endif /* ! MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * ssd_read_ios_limit is controlled by userspace. + * batch size should not be touched except for debug/testing purpose + */ +static inline void update_wb_param_on_sync(plug_wb_t *plug_wb) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&plug_wb->lock, flags); + plug_wb->disk_write_ios_limit = PLUG_WB_SYNC_DISK_WRITE; + spin_unlock_irqrestore(&plug_wb->lock, flags); +} +#endif + +void +flashcache_sync_all(struct cache_c *dmc) +{ + if (dmc->cache_mode != FLASHCACHE_WRITE_BACK) + return; + dmc->sysctl_stop_sync = 0; + spin_lock_irq(&dmc->cache_spin_lock); +#ifdef MY_ABC_HERE + if (!dmc->start_sync_all) { + dmc->start_sync_all = 1; + dmc->init_nr_dirty = dmc->nr_dirty; + } +#endif + +#ifdef MY_ABC_HERE + if (0 == dmc->nr_dirty) { + spin_unlock_irq(&dmc->cache_spin_lock); + return; + } + spin_unlock_irq(&dmc->cache_spin_lock); + + mutex_lock(&dmc->oqf.mtx); + if (dmc->oqf.sync_state == SYNC_STATE_RUNNING) { + mutex_unlock(&dmc->oqf.mtx); + return; + } + atomic_inc(&dmc->dmcg->sqf_inprog); + dmc->oqf.sync_state = SYNC_STATE_RUNNING; + + /* Once the trigger cnt reach zero there won't be new writebacks, even + * if workqueue and increase trigger cnt it won't send IO */ + while (dmc->oqf.trigger_cnt) { + mutex_unlock(&dmc->oqf.mtx); + wait_event(dmc->oqf.wqh, dmc->oqf.trigger_cnt == 0); + mutex_lock(&dmc->oqf.mtx); + } + + VERIFY_WARN(dmc->oqf.sync_trigger_cnt == 0); + + update_wb_param_on_sync(&dmc->plug_wb); + dmc->oqf.bit_idx = 0; + + mutex_unlock(&dmc->oqf.mtx); + + down_write(&dmc->oqf.bitmap_rwsem); + quickflush_construct_bitmap(dmc); + up_write(&dmc->oqf.bitmap_rwsem); + + mutex_lock(&dmc->oqf.mtx); + sdbg(DF_QUICKFLUSH, "Quick Flush"); + + /* WARNING: Finish all preperation before increasing this, + * or syno_start_sqf can be called from plugged wb wq */ + dmc->oqf.sync_trigger_cnt++; + mutex_unlock(&dmc->oqf.mtx); + syno_start_sqf(dmc); + /* TODO: Refine and add Unit tests */ +#else + dmc->sync_index = 0; + spin_unlock_irq(&dmc->cache_spin_lock); + flashcache_sync_blocks(dmc); +#endif /* MY_ABC_HERE */ +} + +/* + * We handle uncached IOs ourselves to deal with the problem of out of ordered + * IOs corrupting the cache. Consider the case where we get 2 concurent IOs + * for the same block Write-Read (or a Write-Write). Consider the case where + * the first Write is uncacheable and the second IO is cacheable. If the + * 2 IOs are out-of-ordered below flashcache, then we will cache inconsistent + * data in flashcache (persistently). + * + * We do invalidations before launching uncacheable IOs to disk. But in case + * of out of ordering the invalidations before launching the IOs does not help. + * We need to invalidate after the IO completes. + * + * Doing invalidations after the completion of an uncacheable IO will cause + * any overlapping dirty blocks in the cache to be written out and the IO + * relaunched. If the overlapping blocks are busy, the IO is relaunched to + * disk also (post invalidation). In these 2 cases, we will end up sending + * 2 disk IOs for the block. But this is a rare case. + * + * When 2 IOs for the same block are sent down (by un co-operating processes) + * the storage stack is allowed to re-order the IOs at will. So the applications + * cannot expect any ordering at all. + * + * What we try to avoid here is inconsistencies between disk and the ssd cache. + */ +void +flashcache_uncached_io_complete(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + unsigned long flags; + int queued; + int error = job->error; + int is_write = (bio_data_dir(job->bio) == WRITE); + + flashcache_check_record_io_latency(LAT_UNCACHED_IO_COMPLETE_WQ, &job->io_lat); + + if (unlikely(error)) { + if (printk_ratelimit()) { + DMERR("flashcache uncached disk IO error: io error %d block %llu R/w %s", + error, (u64)job->job_io_regions.disk.sector, + (bio_data_dir(job->bio) == WRITE) ? "WRITE" : "READ"); + } + if (bio_data_dir(job->bio) == WRITE) + atomic_inc(&dmc->flashcache_errors.disk_write_errors); + else + atomic_inc(&dmc->flashcache_errors.disk_read_errors); + } + + job_dbg(__func__, job); + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); +#ifdef CONFIG_SYNO_DATA_CORRECTION + if (job->bio->bi_flags & ((1 << BIO_CORRECTION_RETRY) | (1 << BIO_CORRECTION_ABORT))) { + //If this is a correction bio, we should not invalidate it. + sdbg(DF_CORRECTION, "Get correcting bio_sector=%llu nerver invalidate", (u64)bio_bi_sector(job->bio)); + queued = 0; + } else { + queued = flashcache_inval_blocks(dmc, job->bio, &job->io_lat, TYPE_DONT_CARE); + } +#else + queued = flashcache_inval_blocks(dmc, job->bio, &job->io_lat, TYPE_DONT_CARE); +#endif + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + if (queued) { + if (unlikely(queued < 0)) + flashcache_bio_endio(job->bio, -EIO, dmc, ktime_zero, &job->io_lat); + /* + * The IO will be re-executed. + * The do_pending logic will re-launch the + * disk IO post-invalidation calling start_uncached_io. + * This should be a rare occurrence. + */ + atomic64_inc(&dmc->flashcache_stats.uncached_io_requeue); + } else { + flashcache_bio_endio(job->bio, error, dmc, job->io_start_time, &job->io_lat); + } + + if (is_write) { + atomic_dec(&dmc->num_uncached_write); + wake_up(&dmc->wait_io_done_queue); + } + + flashcache_free_cache_job(job); + if (atomic_dec_and_test(&dmc->nr_jobs)) + wake_up(&dmc->sync_wqh); +} + +static void +flashcache_uncached_io_callback(unsigned long error, void *context) +{ + struct kcached_job *job = (struct kcached_job *) context; + struct bio *bio = job->bio; + VERIFY_WARN(bio != NULL); + + flashcache_check_record_io_latency( + bio_data_dir(job->bio) == WRITE ? LAT_UNCACHED_WRITE : LAT_UNCACHED_READ, + &job->io_lat); + +#ifdef CONFIG_SYNO_DATA_CORRECTION + + if (error & (1 << BIO_CORRECTION_ERR)) { + bio->bi_flags |= 1 << BIO_CORRECTION_ERR; + error &= ~(1 << BIO_CORRECTION_ERR); + sdbg(DF_CORRECTION, "remove BIO_CORRECTION_ERR from non-cache bio, error=%lu, bio_sector=%llu", error, (u64)bio_bi_sector(bio)); + } +#endif + VERIFY_WARN(job->index == -1); + if (unlikely(error)) + job->error = -EIO; + else + job->error = 0; + push_uncached_io_complete(job); + cache_schedule_uncached_io_complete(); +} + +static inline int get_comp_dm_op_flag(struct cache_c *dmc, struct bio *bio, int is_write) +{ + if (unlikely(bio_has_fua_flags(bio))) { + if (is_write) { + return COMP_DM_WRITE_FUA; + } else { + return COMP_DM_READ; + } + } else { + return (is_write ? COMP_DM_WRITE : COMP_DM_READ); + } +} + +/* + * plat and io_type are mutual exclusive. Given plat, we use plat->io_type. + */ +static void +flashcache_start_uncached_io(struct cache_c *dmc, struct bio *bio, + struct io_latency *plat, enum cache_io_type io_type) +{ + int is_write = (bio_data_dir(bio) == WRITE); + int comp_dm_op = 0; + struct kcached_job *job; + unsigned long bi_flags = 0; + +#ifdef CONFIG_SYNO_DATA_CORRECTION + bi_flags = bio->bi_flags & ((1 << BIO_CORRECTION_ABORT) | (1 << BIO_CORRECTION_RETRY)); +#endif + + if (is_write) { + atomic64_inc(&dmc->flashcache_stats.uncached_writes); + atomic64_inc(&dmc->flashcache_stats.disk_writes); + } else { + atomic64_inc(&dmc->flashcache_stats.uncached_reads); + atomic64_inc(&dmc->flashcache_stats.disk_reads); + } + job = new_kcached_job(dmc, bio, -1, plat, io_type); + + if (global_tester == TEST_OQF_INVALIDATE_DELAY) { + flashcache_free_cache_job(job); + job = NULL; + } + + if (unlikely(job == NULL)) { + flashcache_bio_endio(bio, -EIO, dmc, ktime_zero, plat); + return; + } + atomic_inc(&dmc->nr_jobs); + job_dbg(__func__, job); + if (is_write) { + atomic_inc(&dmc->num_uncached_write); + } + + comp_dm_op = get_comp_dm_op_flag(dmc, bio, is_write); + + dm_io_async_bio_wrapper(1, &job->job_io_regions.disk, comp_dm_op, + bio, flashcache_uncached_io_callback, job, bi_flags); +} + +#ifdef CONFIG_SYNO_DATA_CORRECTION +// Return 0 on success. Otherwise return -1 +int correction_handle_retry_io_start(struct cache_c *dmc, u64 bio_sector) +{ + int ret = -1; + struct correction_entry *entry = NULL; + unsigned long irq_flags = 0; + int exist = 0; + + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + + entry = correction_list_find_entry(dmc, bio_sector, NO_LOCK); + if (entry) { + exist = 1; + } else { + entry = correcting_entry_alloc(bio_sector); + if (!entry) { + sdbg(DF_CORRECTION, "Failed to allocate new entry\n"); + goto err; + } + list_add_tail(&entry->link, &dmc->correction_list->link); + } + + entry->correcting_bitmap |= 1 << ((bio_sector - entry->start_sector) / ALIGNED_SECTORS); + sdbg(DF_CORRECTION, "Entry exist=%d correcting bitmap is updated to 0x%x", + exist, entry->correcting_bitmap); + + ret = 0; +err: + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); + + return ret; +} + +int correction_find_cache_index(struct cache_c *dmc, sector_t start_sector) +{ + unsigned long set_number = 0; + int start_index = 0; + int end_index = 0; + int i =0; + int ret = -1; + + set_number = hash_block(dmc, start_sector); + start_index = dmc->assoc * set_number; + end_index = start_index + dmc->assoc; + + for (i = start_index ; i < end_index ; i++) { + if ((start_sector >= dmc->cache[i].dbn) && + (start_sector < (dmc->cache[i].dbn + dmc->block_size))) { + ret = i; + } + } + + return ret; +} + +/* Return 0 no abort bio work queued, 1 abort bio work queued */ +static int inline queue_force_abort_bio_work(struct cache_c *dmc, struct bio *bio, + int error, ktime_t start_time, struct io_latency *plat, + struct correction_entry *entry) +{ + int ret = 0; + struct send_force_abort_bio_task *task = NULL; + + task = kzalloc(sizeof(*task), GFP_ATOMIC); + if (unlikely(NULL == task)) { + serr("Failed to allocate send force abort bio, entry_sector: " + "%llu need_abort_bitmap: %u cache_addr: %llu", + (u64)entry->start_sector, entry->need_abort_bitmap, (u64)entry->cache_addr); + } else { + task->dmc = dmc; + task->entry_start_sector = entry->start_sector; + task->need_abort_bitmap = entry->need_abort_bitmap; + task->cache_addr = entry->cache_addr; + task->bio = bio; + task->error = error; + task->start_time = start_time; + task->io_lat = *plat; + sdbg(DF_CORRECTION, "need abort bitmap: %d", task->need_abort_bitmap); + + INIT_WORK(&task->work, correction_send_force_abort_bios); + cache_schedule_work(&task->work); + ret = 1; + } + + return ret; +} + +/* Return 0 no need to wait for abort bio, 1 need to wait for abort bio */ +int correction_handle_abort_io_finish(struct cache_c *dmc, + struct bio *bio, int error, ktime_t start_time, struct io_latency *plat) +{ + int ret = 0; + struct correction_entry *entry = NULL; + unsigned long irq_flags = 0; + int index = 0; + sector_t bio_sector = bio_bi_sector(bio); + + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + + entry = correction_list_find_entry(dmc, bio_sector, NO_LOCK); + if (NULL == entry) { + serr("BIO (bio_sector:%llu) has been aborted", (u64)bio_sector); + goto end; + } + + VERIFY_WARN(0 != entry->correcting_bitmap); + + sdbg(DF_CORRECTION, "Current correcting bitmap=0x%x", entry->correcting_bitmap); + + index = (bio_sector - entry->start_sector) / ALIGNED_SECTORS; + entry->correcting_bitmap &= ~(1 << index); + entry->correcting_types[index] = TYPE_UNINITED; + + if (0 == entry->correcting_bitmap) { + list_del(&entry->link); + if (unlikely(entry->need_abort_bitmap)) { + ret = queue_force_abort_bio_work(dmc, bio, error, start_time, plat, entry); + } + + sdbg(DF_CORRECTION, "Free entry (start sector=%llu)", entry->start_sector); + kfree(entry); + entry = NULL; + } + +end: + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); + + return ret; +} + +struct correction_entry *correcting_entry_alloc(u64 bio_sector) +{ + struct correction_entry *new_entry = NULL; + + new_entry = kzalloc(sizeof(struct correction_entry), GFP_ATOMIC); + if (!new_entry) { + serr("Fail to alloc new correction entry"); + goto err; + } + new_entry->start_sector = bio_sector / MAX_BIO_SIZE * MAX_BIO_SIZE; +err: + return new_entry; +} + +struct correction_entry *correction_list_find_entry(struct cache_c *dmc, u64 bio_sector, lock_type_t lock_type) +{ + struct correction_entry *entry = NULL; + struct correction_entry *ret_entry = NULL; + struct correction_entry *list = NULL; + unsigned long irq_flags = 0; + + if (DO_LOCK == lock_type) { + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + } + + list = dmc->correction_list; + list_for_each_entry(entry, &list->link, link){ + if ((bio_sector < (entry->start_sector + MAX_BIO_SIZE)) + && (bio_sector >= entry->start_sector)) { + ret_entry = entry; + goto end; + } + } +end: + if (DO_LOCK == lock_type) { + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); + } + + return ret_entry; +} + +int correction_entry_in_correcting(struct cache_c *dmc, u64 bio_sector, lock_type_t lock_type) +{ + int ret = 0; + + if (correction_list_find_entry(dmc, bio_sector, lock_type)) { + ret = 1; + } + + return ret; +} + +// Get a correctio type of a 4KB range +correcting_type_t correction_range_get_type(struct cache_c *dmc, u64 bio_sector) +{ + correcting_type_t ret = NO_CORRECTING; + struct correction_entry *entry = NULL; + unsigned long irq_flags = 0; + int index = 0; + + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + + entry = correction_list_find_entry(dmc, bio_sector, NO_LOCK); + + if (NULL == entry) { + goto err; + } + + index = (bio_sector - entry->start_sector) / ALIGNED_SECTORS; + ret = entry->correcting_types[index]; +err: + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); + return ret; +} + +int correction_range_set_type(struct cache_c *dmc, u64 bio_sector, correcting_type_t type) +{ + int ret = -1; + struct correction_entry *entry = NULL; + unsigned long irq_flags = 0; + int index = 0; + + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + + entry = correction_list_find_entry(dmc, bio_sector, NO_LOCK); + + if (NULL == entry) { + serr("Can't found entry"); + goto err; + } + + index = (bio_sector - entry->start_sector) / ALIGNED_SECTORS; + if (TYPE_UNINITED == entry->correcting_types[index]) { + entry->correcting_types[index] = type; + sdbg(DF_CORRECTION, "Update entry (start sector=%llu) correcing type [%d] to %d", + entry->start_sector, index, type); + } else { + sdbg(DF_CORRECTION, "Warning : type has been set!!!"); + } + ret = 0; +err: + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); + return ret; +} + +void correction_entry_set_abort_bitmap(struct cache_c *dmc, u64 bio_sector) +{ + struct correction_entry *entry = NULL; + int i = 0; + unsigned long irq_flags = 0; + + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + + sdbg(DF_CORRECTION, "Find entry for bio start=%llu", bio_sector); + + entry = correction_list_find_entry(dmc, bio_sector, NO_LOCK); + if (NULL != entry) { + for (i = 0; i < NUM_SUB_BLOCK; i++) { + if (SSD_CORRECTING == entry->correcting_types[i]) { + entry->need_abort_bitmap |= (1 << i); + } + } + sdbg(DF_CORRECTION, "Update entry (start=%llu) need_abort_bitmap to 0x%x", + entry->start_sector, entry->need_abort_bitmap); + } + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); +} + +void flashcache_correction_abort_callback(unsigned long error, void *context) +{ + struct bio *bio = context; + struct send_force_abort_bio_task *task = bio->bi_private; + + if (error) { + serr ("force abort bio fail error :%lx", error); + } + + sdbg(DF_CORRECTION, "force aborted finish:bi_sector:%llu", (u64)bio_bi_sector(bio)); + __free_page(bio->bi_io_vec[0].bv_page); + bio_put(bio); + + if (atomic_dec_and_test(&task->bio_count)) { + sdbg(DF_CORRECTION, "bio count reach zero end io and release task"); + flashcache_bio_endio_core(task->bio, task->error, + task->dmc, task->start_time, &task->io_lat); + kfree(task); + } +} + +struct bio* correction_alloc_abort_bio(struct cache_c *dmc, sector_t sector) +{ + struct bio *bio = NULL; + struct page *page = NULL; + + bio = bio_alloc_bioset(GFP_NOIO, 1, pcache_bio_set); + if (!bio) { + serr("alloc_aborbio:blo_alloc_bioset failed"); + goto exit; + } + + *bio_bi_sector_ptr(bio) = sector; + *bio_bi_size_ptr(bio) = CORRECTION_BIO_BYTES; + *bio_bi_idx_ptr(bio) = 0; + bio->bi_vcnt = 1; + + page = alloc_page(GFP_ATOMIC); + if (unlikely(!page)) { + serr("alloc_aborbio:alloc_page failed"); + goto free_bio; + } + + bio->bi_io_vec[0].bv_page = page; + bio->bi_io_vec[0].bv_len = CORRECTION_BIO_BYTES; + bio->bi_io_vec[0].bv_offset = 0; + + bio->bi_flags |= (1 << BIO_CORRECTION_ABORT); + + goto exit; + +free_bio: + bio_put(bio); +exit: + return bio; +} + +void correction_send_force_abort_bios(struct work_struct *work) +{ + struct send_force_abort_bio_task *task = container_of(work, struct send_force_abort_bio_task, work); + int i = 0; + int bio_count = 0; + struct bio *bio = NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + struct dm_io_region where = {0}; +#else + struct io_region where = {0}; +#endif + where.bdev = get_cache_bdev(task->dmc); + + if (check_new_error_inject(task->dmc, FORCE_ABORT_BIO_WQ_DELAY)) { + sprint("Simulate force abort bio workqueue delay, sleep 60 sec"); + task->dmc->sysctl_new_error_inject = 0; + msleep(60000); + } + + /* Make there multiple entries in need abort bitmap so we can test the + * case in which some abort bio allocate successfully and some failed. + * Always try to set the last bit, if it's already set, print and ignore */ + if (check_new_error_inject(task->dmc, FORCE_ABORT_BIO_ALLOC_FAIL)) { + sprint("Simulate multiple bit set in abort bitmap"); + if (task->need_abort_bitmap & 1) { + sprint("LSB already set in force abort bitmap"); + } else { + task->need_abort_bitmap |= 1; + } + } + + for (i = 0; i < NUM_SUB_BLOCK; ++i) { + if (task->need_abort_bitmap & (1 << i)) { + bio_count++; + } + } + atomic_set(&task->bio_count, bio_count); + + for (i = 0; i < NUM_SUB_BLOCK; i++) { + if (task->need_abort_bitmap & (1 << i)) { + bio = correction_alloc_abort_bio(task->dmc, task->cache_addr + (i * ALIGNED_SECTORS)); + if (check_new_error_inject(task->dmc, FORCE_ABORT_BIO_ALLOC_FAIL)) { + sprint("Simulate force abort bio alloc fail"); + task->dmc->sysctl_new_error_inject = 0; + if (bio) { + bio_put(bio); + } + bio = NULL; + } + if (bio) { + where.sector = bio_bi_sector(bio); + where.count = to_sector(bio_bi_size(bio)); + bio->bi_private = task; + + sdbg(DF_CORRECTION, "Send abort bio start sector=%llu size=%llu", + (u64)bio_bi_sector(bio), (u64)to_sector(bio_bi_size(bio))); + + dm_io_async_bio_wrapper(1, &where, COMP_DM_READ, bio, + flashcache_correction_abort_callback, bio, + bio->bi_flags & (1 << BIO_CORRECTION_ABORT)); + } else { + serr("Failed to allocate force abort bio for %llu", + (u64)(task->cache_addr + (i * ALIGNED_SECTORS))); + if (atomic_dec_and_test(&task->bio_count)) { + sdbg(DF_CORRECTION, "bio count reach zero end io and release task"); + flashcache_bio_endio_core(task->bio, task->error, + task->dmc, task->start_time, &task->io_lat); + kfree(task); // must be last bio + goto end; + } + } + bio = NULL; + } + } +end: + return; +} + +void correction_entry_record_cache_addr(struct cache_c *dmc, int index, sector_t bio_sector) +{ + struct correction_entry *entry = NULL; + unsigned long irq_flags = 0; + + spin_lock_irqsave(&dmc->corretion_spin_lock, irq_flags); + + entry = correction_list_find_entry(dmc, bio_sector, NO_LOCK); + + if (entry && 0 == entry->cache_addr) { + entry->cache_addr = INDEX_TO_CACHE_ADDR(dmc, index); + sdbg(DF_CORRECTION, "record cache_addr: bio_sector=%llu, cache_addr:%llu ", (u64)bio_sector, (u64)entry->cache_addr); + } + spin_unlock_irqrestore(&dmc->corretion_spin_lock, irq_flags); +} +#endif /* CONFIG_SYNO_DATA_CORRECTION */ diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_pin_file.h b/drivers/syno/syno-mem-saving-driver/flashcache_pin_file.h new file mode 100644 index 000000000000..d0817fd69d08 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_pin_file.h @@ -0,0 +1,31 @@ +#ifndef FLASHCACHE_PIN_FILE_H +#define FLASHCACHE_PIN_FILE_H + +#define PIN_SECTORS_PER_BIT 128 +#define PIN_BYTES_PER_BIT (PIN_SECTORS_PER_BIT * 512) + +/* + * For worse case, each range records 4KB continous block + * Each ioctl can handle 4MB data + */ +#define MAX_RANGES 512 + +#ifndef __KERNEL__ +// For user space compatible +#ifndef u64 +#define u64 unsigned long long +#endif +#endif + +typedef struct _range { + u64 disk_start_sector; + u64 num_sectors; +} range_t; + +typedef struct _BITMAP { + unsigned char *data; + // size_t is unsigned integer, so it supports 2048 TB volume (2^32 * 8 * 64KB) + size_t sizeByte; +} BITMAP; + +#endif diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_procfs.c b/drivers/syno/syno-mem-saving-driver/flashcache_procfs.c new file mode 100644 index 000000000000..70d1f3af8c41 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_procfs.c @@ -0,0 +1,3269 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache_conf.c + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#include "dm.h" +#include "dm-io.h" +#include "dm-bio-list.h" +#include "kcopyd.h" +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +#include "dm.h" +#endif +#include +#include +#include +#endif + +#include "flashcache.h" +#include "flashcache_ioctl.h" +#ifdef MY_ABC_HERE +#include "syno_quickflush.h" +#endif + +#ifdef MY_ABC_HERE +#include +#endif + +static int fallow_clean_speed_min = FALLOW_SPEED_MIN; +static int fallow_clean_speed_max = FALLOW_SPEED_MAX; + +extern u_int64_t size_hist[]; + +#ifdef SYNO_FLASHCACHE_DEBUG +extern struct _syno_debug syno_debug; +#endif + +static char *flashcache_cons_procfs_cachename(struct cache_c *dmc, char *path_component); +#ifdef MY_ABC_HERE +static char *syno_get_sysctl_dirname(struct cache_c *dmc); +#else +static char *flashcache_cons_sysctl_devname(struct cache_c *dmc); +#endif + +#define FLASHCACHE_PROC_ROOTDIR_NAME "flashcache" + +#ifdef MY_ABC_HERE +extern unsigned long hash_block(struct cache_c *dmc, sector_t dbn); +#endif /* MY_ABC_HERE */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +typedef struct ctl_table ctl_table; +#endif + +static char * entry_get_combined_name(const char *ssd_path, const char *disk_path); + +static int +flashcache_io_latency_init(ctl_table *table, int write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct file *file, +#endif + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + proc_dointvec(table, write, file, buffer, length, ppos); +#else + proc_dointvec(table, write, buffer, length, ppos); +#endif + if (write) { + if (dmc->sysctl_io_latency_hist) { + int i; + + for (i = 0 ; i < IO_LATENCY_BUCKETS ; i++) + dmc->latency_hist[i] = 0; + dmc->latency_hist_10ms = 0; + } + } + return 0; +} + +static int +flashcache_sync_sysctl(ctl_table *table, int write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct file *file, +#endif + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + proc_dointvec(table, write, file, buffer, length, ppos); +#else + proc_dointvec(table, write, buffer, length, ppos); +#endif + if (write) { + if (dmc->sysctl_do_sync) { + dmc->sysctl_stop_sync = 0; +#ifdef MY_ABC_HERE +#else + cancel_delayed_work(&dmc->delayed_clean); + flush_workqueue(cache_workqueue); +#endif + /* + * SYNO: + * sync_all won't garantee that all dirty blocks would be SYNCED_BITS (It won't flush + * BLOCK_IN_PROG blocks) + * So in sync_for_remove(), we use do {} while (nr_dirty > 0) to operate it + */ + flashcache_sync_all(dmc); + } + } + return 0; +} + +#ifdef MY_ABC_HERE +static int +flashcache_stop_sync_sysctl(ctl_table *table, int write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct file *file, +#endif + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + + proc_dointvec(table, write, buffer, length, ppos); + if (write) { + if (dmc->sysctl_stop_sync) { + dmc->start_sync_all = 0; + dmc->init_nr_dirty = -1; + } + } + return 0; +} +#endif /* MY_ABC_HERE */ + +static int +flashcache_zerostats_sysctl(ctl_table *table, int write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct file *file, +#endif + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + proc_dointvec(table, write, file, buffer, length, ppos); +#else + proc_dointvec(table, write, buffer, length, ppos); +#endif + if (write) { + if (dmc->sysctl_zerostats) { + int i; + + memset(&dmc->flashcache_stats, 0, sizeof(struct flashcache_stats)); + for (i = 0 ; i < IO_LATENCY_BUCKETS ; i++) + dmc->latency_hist[i] = 0; + dmc->latency_hist_10ms = 0; +#ifdef MY_ABC_HERE + atomic_set(&dmc->num_flush_bio, 0); +#endif + } + } + return 0; +} + +static int +flashcache_fallow_clean_speed_sysctl(ctl_table *table, int write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct file *file, +#endif + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + proc_dointvec(table, write, file, buffer, length, ppos); +#else + proc_dointvec(table, write, buffer, length, ppos); +#endif + if (write) { + if (dmc->sysctl_fallow_clean_speed < fallow_clean_speed_min) + dmc->sysctl_fallow_clean_speed = fallow_clean_speed_min; + + if (dmc->sysctl_fallow_clean_speed > fallow_clean_speed_max) + dmc->sysctl_fallow_clean_speed = fallow_clean_speed_max; + } + return 0; +} + +static int +flashcache_dirty_thresh_sysctl(ctl_table *table, int write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct file *file, +#endif + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + proc_dointvec(table, write, file, buffer, length, ppos); +#else + proc_dointvec(table, write, buffer, length, ppos); +#endif + if (write) { + if (dmc->sysctl_dirty_thresh > DIRTY_THRESH_MAX) + dmc->sysctl_dirty_thresh = DIRTY_THRESH_MAX; + + if (dmc->sysctl_dirty_thresh < DIRTY_THRESH_MIN) + dmc->sysctl_dirty_thresh = DIRTY_THRESH_MIN; + + dmc->dirty_thresh_set = + (dmc->assoc * dmc->sysctl_dirty_thresh) / 100; + } + return 0; +} + +#ifdef MY_ABC_HERE +static int +flashcache_enable_wb_task_sysctl(ctl_table *table, int write, + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + + proc_dointvec(table, write, buffer, length, ppos); + + + if (write) { + if (dmc->oqf.sysctl_enable_wb_work) { + quickflush_schedule_wb_work(dmc); + } else { + cancel_delayed_work_sync(&dmc->oqf.wb_work); + } + } + + return 0; +} +#endif + +static int +flashcache_syno_latency_sysctls(ctl_table *table, int write, + void __user *buffer, + size_t *length, loff_t *ppos) +{ + struct cache_c *dmc = (struct cache_c *)table->extra1; + unsigned long itvl_jiffy = 0; + unsigned long flags = 0; + + proc_dointvec(table, write, buffer, length, ppos); + + if (dmc->sysctl_latency_diagnose_itvl_ms < 100) { + dmc->sysctl_latency_diagnose_itvl_ms = 100; + serr("Invalid sysctl latency diagnose itvl"); + return -1; + } + + if (dmc->sysctl_lat_perc_ten_thousandth < 0 + || 10000 < dmc->sysctl_lat_perc_ten_thousandth) { + dmc->sysctl_lat_perc_ten_thousandth = LAT_PERC_TEN_THOUSANDTH; + serr("Invalid sysctl latency percentile ten thousandth"); + return -1; + } + + if (write) { + sprint("Got latency sysctl"); + del_timer_sync(&dmc->latency_timer); + if (dmc->sysctl_syno_latency_diagnose) { + + spin_lock_irqsave(&dmc->lat_spin_lock, flags); + + dmc->lat_thresholds_jiffies[TYPE_SSD]= + msecs_to_jiffies(dmc->sysctl_io_ssd_lat_thres_ms); + dmc->lat_thresholds_jiffies[TYPE_DISK] = + msecs_to_jiffies(dmc->sysctl_io_disk_lat_thres_ms); + dmc->lat_thresholds_jiffies[TYPE_COULD_SSD] = + msecs_to_jiffies(dmc->sysctl_io_disk_lat_thres_ms); + + memset(&dmc->last_itvl_lat_stats[dmc->lat_stats_idx], + 0, sizeof(dmc->last_itvl_lat_stats[0])); + + spin_unlock_irqrestore(&dmc->lat_spin_lock, flags); + + itvl_jiffy = msecs_to_jiffies(dmc->sysctl_latency_diagnose_itvl_ms); + dmc->latency_timer.expires = jiffies + itvl_jiffy; + add_timer(&dmc->latency_timer); + } + } + return 0; +} + +static int +flashcache_syno_cache_all_sysctl(ctl_table *table, int write, + void __user *buffer, + size_t *length, loff_t *ppos) +{ + int ret = 0; + struct cache_c *dmc = (struct cache_c *)table->extra1; + unsigned long flags = 0; + + proc_dointvec(table, write, buffer, length, ppos); + + if (write) { + spin_lock_irqsave(&dmc->bypass_lock, flags); + if (dmc->bypass_cache && dmc->sysctl_cache_all_input) { + dmc->sysctl_cache_all_input = 0; + ret = -1; + } else { + dmc->sysctl_cache_all = dmc->sysctl_cache_all_input; + } + spin_unlock_irqrestore(&dmc->bypass_lock, flags); + } + + return ret; +} + +static int +syno_wb_sysctl_handler(ctl_table *table, int write, + void __user *buffer, + size_t *length, loff_t *ppos) +{ + int ret = 0; +#ifdef MY_ABC_HERE + struct cache_c *dmc = (struct cache_c *)table->extra1; + unsigned long flags = 0; + plug_wb_t *plug_wb = &dmc->plug_wb; + + /* + * Keep values aligned before proc_dointvec in case driver + * changes the values. + */ + plug_wb->sysctl_disk_write_ios_limit = plug_wb->disk_write_ios_limit; + plug_wb->sysctl_ssd_read_ios_limit = plug_wb->ssd_read_ios_limit; + plug_wb->sysctl_batch_size = plug_wb->batch_size; + + proc_dointvec(table, write, buffer, length, ppos); + + /* + * wb params are protected by lock, proc_dointvec copies from userspace + * so must not underlock, user sysctl_* as temp storage. + */ + if (write) { + spin_lock_irqsave(&dmc->plug_wb.lock, flags); + dmc->plug_wb.batch_size = dmc->plug_wb.sysctl_batch_size; + dmc->plug_wb.disk_write_ios_limit = dmc->plug_wb.sysctl_disk_write_ios_limit; + dmc->plug_wb.ssd_read_ios_limit = dmc->plug_wb.sysctl_ssd_read_ios_limit; + spin_unlock_irqrestore(&dmc->plug_wb.lock, flags); + } +#else + proc_dointvec(table, write, buffer, length, ppos); +#endif + + return ret; +} + +#ifdef MY_ABC_HERE +static int +syno_group_throtl_sysctl_handler(ctl_table *table, int write, + void __user *buffer, + size_t *length, loff_t *ppos) +{ + int ret = 0; + struct cache_c *dmc = (struct cache_c *)table->extra1; + extern struct mutex dmcg_mtx; + int has_dmcg = 0; + + mutex_lock(&dmcg_mtx); + + has_dmcg = (NULL != dmc->dmcg); + + if (has_dmcg) { + down_write(&dmc->dmcg->rw_sem); + dmc->new_mu.group_throtl_thres = dmc->dmcg->md_io_throtl_thres; + } + proc_dointvec(table, write, buffer, length, ppos); + if (has_dmcg) { + dmc->dmcg->md_io_throtl_thres = dmc->new_mu.group_throtl_thres; + up_write(&dmc->dmcg->rw_sem); + } + + mutex_unlock(&dmcg_mtx); + + return ret; +} +#endif + +static ctl_table wb_sysctl_vars[] = { + { + .procname = "io_latency_hist", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_io_latency_init, + }, + { + .procname = "do_sync", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_sync_sysctl, + }, + { + .procname = "stop_sync", + .maxlen = sizeof(int), + .mode = 0644, +#ifdef MY_ABC_HERE + .proc_handler = &flashcache_stop_sync_sysctl, +#else + .proc_handler = &proc_dointvec, +#endif /* MY_ABC_HERE */ + }, + { + .procname = "dirty_thresh_pct", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_dirty_thresh_sysctl, + }, + { + .procname = "max_clean_ios_total", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "max_clean_ios_set", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "do_pid_expiry", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "max_pids", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "pid_expiry_secs", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "reclaim_policy", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "zero_stats", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_zerostats_sysctl, + }, +// SYNO: Enable it +#if 1 + { + .procname = "error_inject", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + { + .procname = "fast_remove", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "cache_all", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_cache_all_sysctl, + }, + { + .procname = "fallow_clean_speed", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_fallow_clean_speed_sysctl, + }, + { + .procname = "fallow_delay", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "skip_seq_thresh_kb", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "skip_seq_forward_gap_kb", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "skip_seq_backward_gap_kb", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + // Export to user space + .procname = "wb_ssd_read_ios_limit", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &syno_wb_sysctl_handler, + }, +#ifdef MY_ABC_HERE + { + .procname = "wb_disk_write_ios_limit", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &syno_wb_sysctl_handler, + }, + { + .procname = "wb_batch_size", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &syno_wb_sysctl_handler, + }, + { + .procname = "enable_writeback_task", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_enable_wb_task_sysctl, + }, +#endif /* MY_ABC_HERE */ + { + .procname = "syno_latency_diagnose", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "latency_diagnose_itvl_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "io_disk_lat_thres_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "io_ssd_lat_thres_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "lat_percentile_ten_thousandth", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "new_error_inject", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#ifdef MY_ABC_HERE + { + .procname = "md_ios_total", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "mu_delay_sec", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "mu_check_itvl_sec", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "mu_group_throtl_thres", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &syno_group_throtl_sysctl_handler, + }, + { + .procname = "mu_flush_itvl_sec", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif +}; + +/* + * Each ctl_table array needs to be 1 more than the actual number of + * entries - zero padded at the end ! Therefore the +1 in the size + */ +static struct flashcache_writeback_sysctl_table { + struct ctl_table_header *sysctl_header; + ctl_table vars[sizeof(wb_sysctl_vars) / sizeof(wb_sysctl_vars[0]) + 1]; + ctl_table dev[2]; + ctl_table dir[2]; + ctl_table root[2]; +} flashcache_writeback_sysctl = { +#ifndef MY_ABC_HERE + .dev = { + { + .procname = "flashcache-dev", + .maxlen = 0, + .mode = S_IRUGO|S_IXUGO, + .child = flashcache_writeback_sysctl.vars, + }, + }, +#endif + .dir = { + { + .procname = FLASHCACHE_PROC_ROOTDIR_NAME, + .maxlen = 0, + .mode = S_IRUGO|S_IXUGO, +#ifdef MY_ABC_HERE + .child = flashcache_writeback_sysctl.vars, +#else + .child = flashcache_writeback_sysctl.dev, +#endif + }, + }, + .root = { + { + .procname = "dev", + .maxlen = 0, + .mode = 0555, + .child = flashcache_writeback_sysctl.dir, + }, + }, +}; + +static ctl_table wt_sysctl_vars[] = { + { + .procname = "io_latency_hist", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_io_latency_init, + }, + { + .procname = "do_pid_expiry", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "max_pids", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "pid_expiry_secs", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "reclaim_policy", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "zero_stats", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_zerostats_sysctl, + }, +// SYNO: Enable it +#if 1 + { + .procname = "error_inject", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + { + .procname = "cache_all", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_cache_all_sysctl, + }, + { + .procname = "skip_seq_thresh_kb", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "skip_seq_forward_gap_kb", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "skip_seq_backward_gap_kb", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .procname = "syno_latency_diagnose", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "latency_diagnose_itvl_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "io_disk_lat_thres_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "io_ssd_lat_thres_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, + { + .procname = "lat_percentile_ten_thousandth", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &flashcache_syno_latency_sysctls, + }, +}; + +/* + * Each ctl_table array needs to be 1 more than the actual number of + * entries - zero padded at the end ! Therefore the +1 in the size + */ +static struct flashcache_writethrough_sysctl_table { + struct ctl_table_header *sysctl_header; + ctl_table vars[sizeof(wt_sysctl_vars) / sizeof(wt_sysctl_vars[0]) + 1]; + ctl_table dev[2]; + ctl_table dir[2]; + ctl_table root[2]; +} flashcache_writethrough_sysctl = { +#ifndef MY_ABC_HERE + .dev = { + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) + .ctl_name = CTL_UNNUMBERED, +#endif + .procname = "flashcache-dev", + .maxlen = 0, + .mode = S_IRUGO|S_IXUGO, + .child = flashcache_writethrough_sysctl.vars, + }, + }, +#endif + .dir = { + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) + .ctl_name = CTL_UNNUMBERED, +#endif + .procname = FLASHCACHE_PROC_ROOTDIR_NAME, + .maxlen = 0, + .mode = S_IRUGO|S_IXUGO, +#ifdef MY_ABC_HERE + .child = flashcache_writethrough_sysctl.vars, +#else + .child = flashcache_writethrough_sysctl.dev, +#endif + }, + }, + .root = { + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) + .ctl_name = CTL_DEV, +#endif + .procname = "dev", + .maxlen = 0, + .mode = 0555, + .child = flashcache_writethrough_sysctl.dir, + }, + }, +}; + +/* TODO: original wb removed, max_clean_ios_total/set can be removed. Also in userspace */ +int * +flashcache_find_sysctl_data(struct cache_c *dmc, ctl_table *vars) +{ + if (strcmp(vars->procname, "io_latency_hist") == 0) + return &dmc->sysctl_io_latency_hist; + else if (strcmp(vars->procname, "do_sync") == 0) + return &dmc->sysctl_do_sync; + else if (strcmp(vars->procname, "stop_sync") == 0) + return &dmc->sysctl_stop_sync; + else if (strcmp(vars->procname, "dirty_thresh_pct") == 0) + return &dmc->sysctl_dirty_thresh; + else if (strcmp(vars->procname, "max_clean_ios_total") == 0) + return &dmc->max_clean_ios_total; + else if (strcmp(vars->procname, "max_clean_ios_set") == 0) + return &dmc->max_clean_ios_set; + else if (strcmp(vars->procname, "do_pid_expiry") == 0) + return &dmc->sysctl_pid_do_expiry; + else if (strcmp(vars->procname, "max_pids") == 0) + return &dmc->sysctl_max_pids; + else if (strcmp(vars->procname, "pid_expiry_secs") == 0) + return &dmc->sysctl_pid_expiry_secs; + else if (strcmp(vars->procname, "reclaim_policy") == 0) + return &dmc->sysctl_reclaim_policy; + else if (strcmp(vars->procname, "zero_stats") == 0) + return &dmc->sysctl_zerostats; + else if (strcmp(vars->procname, "error_inject") == 0) + return &dmc->sysctl_error_inject; + else if (strcmp(vars->procname, "fast_remove") == 0) + return &dmc->sysctl_fast_remove; + else if (strcmp(vars->procname, "cache_all") == 0) + return &dmc->sysctl_cache_all_input; + else if (strcmp(vars->procname, "fallow_clean_speed") == 0) + return &dmc->sysctl_fallow_clean_speed; + else if (strcmp(vars->procname, "fallow_delay") == 0) + return &dmc->sysctl_fallow_delay; + else if (strcmp(vars->procname, "skip_seq_thresh_kb") == 0) + return &dmc->sysctl_skip_seq_thresh_kb; + else if (strcmp(vars->procname, "skip_seq_forward_gap_kb") == 0) + return &dmc->sysctl_skip_seq_fgap_kb; + else if (strcmp(vars->procname, "skip_seq_backward_gap_kb") == 0) + return &dmc->sysctl_skip_seq_bgap_kb; +#ifdef MY_ABC_HERE + else if (strcmp(vars->procname, "enable_writeback_task") == 0) + return &dmc->oqf.sysctl_enable_wb_work; + else if (strcmp(vars->procname, "wb_disk_write_ios_limit") == 0) + return &dmc->plug_wb.sysctl_disk_write_ios_limit; + else if (strcmp(vars->procname, "wb_batch_size") == 0) + return &dmc->plug_wb.sysctl_batch_size; + else if (strcmp(vars->procname, "wb_ssd_read_ios_limit") == 0) + return &dmc->plug_wb.sysctl_ssd_read_ios_limit; +#else + else if (strcmp(vars->procname, "wb_ssd_read_ios_limit") == 0) + return &dmc->sysctl_ssd_read_ios_limit; +#endif + else if (strcmp(vars->procname, "syno_latency_diagnose") == 0) + return &dmc->sysctl_syno_latency_diagnose; + else if (strcmp(vars->procname, "latency_diagnose_itvl_ms") == 0) + return &dmc->sysctl_latency_diagnose_itvl_ms; + else if (strcmp(vars->procname, "io_disk_lat_thres_ms") == 0) + return &dmc->sysctl_io_disk_lat_thres_ms; + else if (strcmp(vars->procname, "io_ssd_lat_thres_ms") == 0) + return &dmc->sysctl_io_ssd_lat_thres_ms; + else if (strcmp(vars->procname, "lat_percentile_ten_thousandth") == 0) + return &dmc->sysctl_lat_perc_ten_thousandth; + else if (strcmp(vars->procname, "new_error_inject") == 0) + return &dmc->sysctl_new_error_inject; +#ifdef MY_ABC_HERE + else if (strcmp(vars->procname, "md_ios_total") == 0) + return &dmc->new_mu.sysctl_mu_ios_total; + else if (strcmp(vars->procname, "mu_delay_sec") == 0) + return &dmc->new_mu.sysctl_mu_delay_sec; + else if (strcmp(vars->procname, "mu_check_itvl_sec") == 0) + return &dmc->new_mu.sysctl_mu_check_itvl_sec; + else if (strcmp(vars->procname, "mu_group_throtl_thres") == 0) + return &dmc->new_mu.group_throtl_thres; + else if (strcmp(vars->procname, "mu_flush_itvl_sec") == 0) + return &dmc->new_mu.flush_itvl_sec; +#endif + VERIFY_WARN(0); + return NULL; +} + +static void +flashcache_writeback_sysctl_register(struct cache_c *dmc) +{ + int i; + struct flashcache_writeback_sysctl_table *t; + + t = kmemdup(&flashcache_writeback_sysctl, sizeof(*t), GFP_KERNEL); + if (t == NULL) + return; + + memcpy(t->vars, wb_sysctl_vars, sizeof(wb_sysctl_vars)); + + for (i = 0 ; i < ARRAY_SIZE(t->vars) - 1 ; i++) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->vars[i].de = NULL; +#endif + t->vars[i].data = flashcache_find_sysctl_data(dmc, &t->vars[i]); + t->vars[i].extra1 = dmc; + } + +#ifdef MY_ABC_HERE + t->dir[0].child = t->vars; +#else + t->dev[0].procname = flashcache_cons_sysctl_devname(dmc); + t->dev[0].child = t->vars; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->dev[0].de = NULL; +#endif + t->dir[0].child = t->dev; +#endif /* End of MY_ABC_HERE */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->dir[0].de = NULL; +#endif +#ifdef MY_ABC_HERE + t->dir[0].procname = syno_get_sysctl_dirname(dmc); +#endif + + t->root[0].child = t->dir; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->root[0].de = NULL; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->sysctl_header = register_sysctl_table(t->root, 0); +#else + t->sysctl_header = register_sysctl_table(t->root); +#endif + if (t->sysctl_header == NULL) + goto out; + + dmc->sysctl_handle = t; + return; + +out: +#ifdef MY_ABC_HERE + kfree(t->dir[0].procname); +#else + kfree(t->dev[0].procname); +#endif + kfree(t); +} + +static void +flashcache_writeback_sysctl_unregister(struct cache_c *dmc) +{ + struct flashcache_writeback_sysctl_table *t; + + t = dmc->sysctl_handle; + if (t != NULL) { + dmc->sysctl_handle = NULL; + unregister_sysctl_table(t->sysctl_header); +#ifdef MY_ABC_HERE + kfree(t->dir[0].procname); +#else + kfree(t->dev[0].procname); +#endif + + kfree(t); + } +} + +static void +flashcache_writethrough_sysctl_register(struct cache_c *dmc) +{ + int i; + struct flashcache_writethrough_sysctl_table *t; + + t = kmemdup(&flashcache_writethrough_sysctl, sizeof(*t), GFP_KERNEL); + if (t == NULL) + return; + + memcpy(t->vars, wt_sysctl_vars, sizeof(wt_sysctl_vars)); + + for (i = 0 ; i < ARRAY_SIZE(t->vars) - 1 ; i++) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->vars[i].de = NULL; +#endif + t->vars[i].data = flashcache_find_sysctl_data(dmc, &t->vars[i]); + t->vars[i].extra1 = dmc; + } + +#ifdef MY_ABC_HERE + t->dir[0].child = t->vars; +#else + t->dev[0].procname = flashcache_cons_sysctl_devname(dmc); + t->dev[0].child = t->vars; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->dev[0].de = NULL; +#endif + t->dir[0].child = t->dev; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->dir[0].de = NULL; +#endif +#ifdef MY_ABC_HERE + t->dir[0].procname = syno_get_sysctl_dirname(dmc); +#endif + + t->root[0].child = t->dir; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->root[0].de = NULL; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) + t->sysctl_header = register_sysctl_table(t->root, 0); +#else + t->sysctl_header = register_sysctl_table(t->root); +#endif + if (t->sysctl_header == NULL) + goto out; + + dmc->sysctl_handle = t; + return; + +out: +#ifdef MY_ABC_HERE + kfree(t->dir[0].procname); +#else + kfree(t->dev[0].procname); +#endif + kfree(t); +} + +static void +flashcache_writethrough_sysctl_unregister(struct cache_c *dmc) +{ + struct flashcache_writethrough_sysctl_table *t; + + t = dmc->sysctl_handle; + if (t != NULL) { + dmc->sysctl_handle = NULL; + unregister_sysctl_table(t->sysctl_header); +#ifdef MY_ABC_HERE + kfree(t->dir[0].procname); +#else + kfree(t->dev[0].procname); +#endif + kfree(t); + } +} + + +static int +flashcache_stats_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + struct flashcache_stats *stats; + int read_hit_pct, write_hit_pct, dirty_write_hit_pct; + + stats = &dmc->flashcache_stats; + if (atomic64_read(&stats->reads) > 0) + read_hit_pct = compatible_div(atomic64_read(&stats->read_hits) * 100, atomic64_read(&stats->reads)); + else + read_hit_pct = 0; + if (atomic64_read(&stats->writes) > 0) { + write_hit_pct = compatible_div(atomic64_read(&stats->write_hits) * 100, atomic64_read(&stats->writes)); + dirty_write_hit_pct = compatible_div((long long)atomic64_read(&stats->dirty_write_hits) * 100, atomic64_read(&stats->writes)); + } else { + write_hit_pct = 0; + dirty_write_hit_pct = 0; + } + seq_printf(seq, "reads=%lld writes=%lld \n", + (long long)atomic64_read(&stats->reads), + (long long)atomic64_read(&stats->writes)); + seq_printf(seq, "read_hits=%lld read_hit_percent=%d ", + (long long)atomic64_read(&stats->read_hits), read_hit_pct); + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK || dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) { + seq_printf(seq, "write_hits=%lld write_hit_percent=%d ", + (long long)atomic64_read(&stats->write_hits), write_hit_pct); +#ifdef MY_ABC_HERE + seq_printf(seq, "write_miss_ssd=%lld ", + (long long)atomic64_read(&stats->wr_miss_ssd)); +#endif +#ifdef MY_ABC_HERE + seq_printf(seq, "dirty_writeback_kb=%lld dirty_writeback_sync_kb=%lld ", + compatible_div((long long)atomic64_read(&stats->dirty_writeback_sector), 2), + compatible_div((long long)atomic64_read(&stats->dirty_writeback_sync_sector), 2)); +#endif + } + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + seq_printf(seq, "dirty_write_hits=%lld dirty_write_hit_percent=%d ", + (long long)atomic64_read(&stats->dirty_write_hits), dirty_write_hit_pct); + } + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK || dmc->cache_mode == FLASHCACHE_WRITE_THROUGH) { + seq_printf(seq, "replacement=%lld write_replacement=%lld ", + (long long)atomic64_read(&stats->replace), (long long)atomic64_read(&stats->wr_replace)); + seq_printf(seq, "write_invalidates=%lld read_invalidates=%lld ", + (long long)atomic64_read(&stats->wr_invalidates), (long long)atomic64_read(&stats->rd_invalidates)); + } else { /* WRITE_AROUND */ + seq_printf(seq, "replacement=%lld ", + (long long)atomic64_read(&stats->replace)); + seq_printf(seq, "read_invalidates=%lld ", + (long long)atomic64_read(&stats->rd_invalidates)); + } +#ifdef FLASHCACHE_DO_CHECKSUMS + seq_printf(seq, "checksum_store=%lld checksum_valid=%lld checksum_invalid=%lld ", + (long long)atomic64_read(&stats->checksum_store), (long long)atomic64_read(&stats->checksum_valid), (long long)atomic64_read(&stats->checksum_invalid)); +#endif + seq_printf(seq, "pending_enqueues=%lld pending_inval=%lld ", + (long long)atomic64_read(&stats->enqueues), (long long)atomic64_read(&stats->pending_inval)); + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + seq_printf(seq, "metadata_dirties=%lld metadata_cleans=%lld ", + (long long)atomic64_read(&stats->md_write_dirty), (long long)atomic64_read(&stats->md_write_clean)); + seq_printf(seq, "metadata_batch=%lld metadata_ssd_writes=%lld ", + (long long)atomic64_read(&stats->md_write_batch), (long long)atomic64_read(&stats->md_ssd_writes)); + seq_printf(seq, "cleanings=%lld fallow_cleanings=%lld ", + (long long)atomic64_read(&stats->cleanings), (long long)atomic64_read(&stats->fallow_cleanings)); + } + seq_printf(seq, "no_room=%lld ", + (long long)atomic64_read(&stats->noroom)); + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) { + seq_printf(seq, "front_merge=%lld back_merge=%lld ", + (long long)atomic64_read(&stats->front_merge), (long long)atomic64_read(&stats->back_merge)); + } + seq_printf(seq, "disk_reads=%lld disk_writes=%lld ssd_reads=%lld ssd_writes=%lld ", + (long long)atomic64_read(&stats->disk_reads), + (long long)atomic64_read(&stats->disk_writes), + (long long)atomic64_read(&stats->ssd_reads), (long long)atomic64_read(&stats->ssd_writes)); + seq_printf(seq, "uncached_reads=%lld uncached_writes=%lld uncached_IO_requeue=%lld ", + (long long)atomic64_read(&stats->uncached_reads), (long long)atomic64_read(&stats->uncached_writes), (long long)atomic64_read(&stats->uncached_io_requeue)); + seq_printf(seq, "uncached_sequential_reads=%lld uncached_sequential_writes=%lld ", + (long long)atomic64_read(&stats->uncached_sequential_reads), + (long long)atomic64_read(&stats->uncached_sequential_writes)); + seq_printf(seq, "pid_adds=%lld pid_dels=%lld pid_drops=%lld pid_expiry=%lld\n", + (long long)atomic64_read(&stats->pid_adds), (long long)atomic64_read(&stats->pid_dels), (long long)atomic64_read(&stats->pid_drops), (long long)atomic64_read(&stats->expiry)); + return 0; +} + +static int +flashcache_stats_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_stats_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_stats_show, PDE_DATA(inode)); + #endif +} +DECLARE_PROC_OPS_OPEN(flashcache_stats_operations, flashcache_stats_open); + +// cache_info_show +static int +cache_info_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + + seq_printf(seq, "ssd_dev=%s ", dmc->cache_devname); + seq_printf(seq, "disk_dev=%s ", dmc->disk_devname); + seq_printf(seq, "mode=%s ", mode_to_str(dmc->cache_mode)); + seq_printf(seq, "capacity_byte=%llu ", (u64)dmc->size*dmc->block_size>>11); + seq_printf(seq, "associativity=%u ", dmc->assoc); + seq_printf(seq, "data_block_size_kb=%u ", dmc->block_size>>(10-SECTOR_SHIFT)); + seq_printf(seq, "metadata_block_size_byte=%u ", dmc->md_block_size * 512); + seq_printf(seq, "total_blocks=%llu ", (u64)dmc->size); + seq_printf(seq, "cached_blocks=%llu ", (u64)atomic64_read(&dmc->cached_blocks)); + seq_printf(seq, "dirty_blocks=%d ", dmc->nr_dirty); + seq_printf(seq, "synced_blocks=%d ", dmc->nr_synced); + seq_printf(seq, "occupied_blocks=%d ", dmc->nr_occupied); +#ifdef MY_ABC_HERE + seq_printf(seq, "support_pin=%d ", dmc->cache_mode == FLASHCACHE_WRITE_BACK? 1 : 0); +#else + seq_printf(seq, "support_pin=0 "); +#endif + seq_printf(seq, "version=%d ", dmc->on_ssd_version); + seq_printf(seq, "queued_sync_io_processed=%llu ", (u64)atomic64_read(&dmc->flashcache_stats.qf_queued_sync_io_processed)); + seq_printf(seq, "\n"); + return 0; +} + +static int +cache_info_open(struct inode *inode, struct file *file) +{ + return single_open(file, &cache_info_show, PDE_DATA(inode)); +} +DECLARE_PROC_OPS_OPEN(cache_info_ops, cache_info_open); + +/* + * WARNING: This is only for internal test since scan all cacheblocks might + * affect performance. + * If you want get inforamtion, query 'cache_info' instead + */ + +// occupied_blocks +static int +occupied_blocks_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + int i = 0; + int nr_pin_only = 0; + int nr_pin_synced = 0; + int nr_pin_dirty = 0; + int nr_synced_only = 0; + int nr_dirty_only = 0; + int nr_total = 0; + u_int16_t state = 0; + + for (i = 0; i < dmc->size; i++) { + + state = dmc->cache[i].cache_state & (PIN_FILE | SYNCED_BITS | DIRTY); + if (state) { + nr_total++; + } + if (state == PIN_FILE) { + nr_pin_only++; + } else if (state == DIRTY) { + nr_dirty_only++; + } else if ((state & SYNCED_BITS) && (0 == (state & (PIN_FILE | DIRTY)))) { + nr_synced_only++; + } else if (state == (PIN_FILE | DIRTY)) { + nr_pin_dirty++; + } else if ((state & PIN_FILE) && (state & SYNCED_BITS) && (0 == (state & DIRTY))) { + nr_pin_synced++; + } + } + + seq_printf(seq, "pin_only=%d dirty_only=%d synced_only=%d pin_dirty=%d " + "pin_synced=%d total=%d\n", nr_pin_only, nr_dirty_only, + nr_synced_only, nr_pin_dirty, nr_pin_synced, nr_total); + return 0; +} + +static int +occupied_blocks_open(struct inode *inode, struct file *file) +{ + return single_open(file, &occupied_blocks_show, PDE_DATA(inode)); +} +DECLARE_PROC_OPS_OPEN(occupied_blocks_ops, occupied_blocks_open); + + +#ifdef MY_ABC_HERE +static int +flashcache_progress_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + int init_nr_dirty = 0; + int cur_nr_dirty = dmc->nr_dirty; + int remaining_dirty = 0; + const char *status = NULL; + + if (0 == dmc->sysctl_cache_all && 0 == dmc->nr_dirty) { + status = "uncacheable_flush_done"; + init_nr_dirty = 0; + remaining_dirty = 0; + } else if (dmc->start_sync_all && dmc->sysctl_cache_all && 0 == dmc->nr_dirty) { + // hibernation flush + status = "cacheable_flush_done"; + init_nr_dirty = 0; + remaining_dirty = 0; + } else if (dmc->start_sync_all && 0 <= dmc->init_nr_dirty) { + status = (dmc->sysctl_cache_all == 1)? "cacheable_flushing" : "uncacheable_flushing"; + init_nr_dirty = dmc->init_nr_dirty; + // when remove a cache with some I/O, remaining > init cause negative percentage in UI + remaining_dirty = cur_nr_dirty > init_nr_dirty ? init_nr_dirty : cur_nr_dirty; + } else { + status = "not_flushing"; + init_nr_dirty = 0; + remaining_dirty = 0; + } + + seq_printf(seq, "status=%s initial_num_of_dirty=%d remaining_num_of_dirty=%d\n", + status, init_nr_dirty, remaining_dirty); + return 0; +} + +static int +flashcache_progress_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_progress_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_progress_show, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_progress_operation, flashcache_progress_open); +#endif + +#ifdef SYNO_FLASHCACHE_DEBUG + +#define SZ_SYNO_DEBUG_INFO "entry=%d\n" +static int +flashcache_debug(struct seq_file *seq, void *v) +{ + struct _syno_debug *d = seq->private; + + seq_printf(seq, SZ_SYNO_DEBUG_INFO, d->entry); + return 0; +} + +static int +flashcache_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, &flashcache_debug, PDE(inode)->data); +} + +DECLARE_PROC_OPS_OPEN(flashcache_debug_operation, flashcache_debug_open); + +#endif +#ifdef MY_ABC_HERE +static int +flashcache_hash_mapping(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + + // TODO: handle userspace? + seq_printf(seq, "%d\n", dmc->hash_mapping); + return 0; +} + +static int +flashcache_hash_mapping_open(struct inode *inode, struct file *file) +{ + return single_open(file, &flashcache_hash_mapping, PDE_DATA(inode)); +} + +DECLARE_PROC_OPS_OPEN(flashcache_hash_mapping_operation, flashcache_hash_mapping_open); + +#endif +#ifdef MY_ABC_HERE +static int +flashcache_writeback_bypass(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + int is_bypass = 0; + + /* + * This entry is read by scemd to check if the SSD can be removed safely + * Here we don't check dmc->bypass_cache due to it won't be set if no further IO on the cache happens + */ + if ((FLASHCACHE_WRITE_BACK == dmc->cache_mode) && (1 == dmc->sysctl_do_sync) + && (0 == dmc->sysctl_cache_all) && (0 == dmc->nr_dirty) && (0 == dmc->nr_synced)) { + is_bypass = 1; + } + seq_printf(seq, "%d\n", is_bypass); + return 0; +} + +static int +flashcache_writeback_bypass_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_writeback_bypass, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_writeback_bypass, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_writeback_bypass_operation, flashcache_writeback_bypass_open); + +#endif + +static int +flashcache_errors_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + struct flashcache_errors *errors = &dmc->flashcache_errors; + + seq_printf(seq, "disk_read_errors=%d disk_write_errors=%d ", + atomic_read(&errors->disk_read_errors), + atomic_read(&errors->disk_write_errors)); + seq_printf(seq, "ssd_read_errors=%d ssd_write_errors=%d ", + atomic_read(&errors->ssd_read_errors), + atomic_read(&errors->ssd_write_errors)); +#ifdef MY_ABC_HERE + seq_printf(seq, "memory_alloc_errors=%d ", + atomic_read(&errors->memory_alloc_errors)); + seq_printf(seq, "write_disk_sync_errors=%d\n", + atomic_read(&errors->write_disk_sync_errors)); +#else + seq_printf(seq, "memory_alloc_errors=%d\n", + atomic_read(&errors->memory_alloc_errors)); +#endif + return 0; +} + +static int +flashcache_errors_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_errors_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_errors_show, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_errors_operations, flashcache_errors_open); + +static int +flashcache_iosize_hist_show(struct seq_file *seq, void *v) +{ + int i; + + for (i = 1 ; i <= 32 ; i++) { + seq_printf(seq, "%d:%llu ", i*512, size_hist[i]); + } + seq_printf(seq, "\n"); + return 0; +} + +static int +flashcache_iosize_hist_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_iosize_hist_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_iosize_hist_show, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_iosize_hist_operations, flashcache_iosize_hist_open); + +static int +flashcache_pidlists_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + struct flashcache_cachectl_pid *pid_list; + unsigned long flags; + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + seq_printf(seq, "Blacklist: "); + pid_list = dmc->blacklist_head; + while (pid_list != NULL) { + seq_printf(seq, "%u ", pid_list->pid); + pid_list = pid_list->next; + } + seq_printf(seq, "\n"); + seq_printf(seq, "Whitelist: "); + pid_list = dmc->whitelist_head; + while (pid_list != NULL) { + seq_printf(seq, "%u ", pid_list->pid); + pid_list = pid_list->next; + } + seq_printf(seq, "\n"); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + return 0; +} + +static int +flashcache_pidlists_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_pidlists_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_pidlists_show, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_pidlists_operations, flashcache_pidlists_open); + +#ifdef CONFIG_SYNO_DATA_CORRECTION +static int +flashcache_correction_list_show(struct seq_file *seq, void *v) +{ + struct cache_c *dmc = seq->private; + struct correction_entry *entry = NULL; + unsigned long flags = 0; + int is_correcting = 0; + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + list_for_each_entry(entry, &dmc->correction_list->link, link){ + is_correcting = 1; + seq_printf(seq, "correction list: range:%llu - %llu , correcting_bitmap:0x%x\n", + entry->start_sector, + entry->start_sector + MAX_BIO_SIZE -1, + entry->correcting_bitmap); + } + + if (0 == is_correcting) { + seq_printf(seq, "0"); + } + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + return 0; +} +static int +flashcache_correction_list_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_correction_list_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_correction_list_show, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_correction_list_operations, flashcache_correction_list_open); + +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +char * data_state_strings[] = {"Uncached", "Cached", "Dirty", "Cached_Pin", "Dirty_Pin"}; +#else +char * data_state_strings[] = {"Uncached", "Cached", "Dirty"}; +#endif +typedef enum _data_state { + DATA_UNKNOWN = -1, + DATA_UNCACHED, + DATA_CACHED, + DATA_DIRTY, +#ifdef MY_ABC_HERE + DATA_CACHED_PIN, + DATA_DIRTY_PIN, +#endif +} data_state; + +typedef struct _ssd_location { + u64 block_start_sector; + u64 block_num_sectors; + u64 cache_start_sector; + data_state state; +} ssd_location; + +typedef struct _data_range +{ + int first_sub_block; + // Only set in the first data range + u64 offset_in_first_sub_block; + int last_sub_block; + // Only set in the last data range + u64 offset_in_last_sub_block; + data_state state; +} data_range; + +typedef struct _cache_block_info +{ + u64 block_start_sector; + u64 ssd_start_sector; +} cache_block_info; + +void ssd_location_init(ssd_location *location, const cache_block_info *info, + const data_range *range) +{ + u64 range_start_sector = range->first_sub_block * SUB_BLOCK_SIZE + range->offset_in_first_sub_block; + u64 range_last_sector = (range->last_sub_block * SUB_BLOCK_SIZE) + range->offset_in_last_sub_block; + + sdbg(DF_LOC, "range->first_sub_block=%d", range->first_sub_block); + sdbg(DF_LOC, "range->offset_in_first_sub_block=%llu", range->offset_in_first_sub_block); + sdbg(DF_LOC, "range->last_sub_block=%d", range->last_sub_block); + sdbg(DF_LOC, "range->offset_in_last_sub_block=%llu", range->offset_in_last_sub_block); + sdbg(DF_LOC, "range->state=%s", data_state_strings[range->state]); + + location->block_start_sector = info->block_start_sector + range_start_sector; + location->block_num_sectors = range_last_sector - range_start_sector + 1; + location->cache_start_sector = info->ssd_start_sector + range_start_sector; + location->state = range->state; + + sdbg(DF_LOC, "block_start_sector=%llu block_num_sectors=%llu cache_start_sector=%llu state=%s", + location->block_start_sector, + location->block_num_sectors, + location->cache_start_sector, + data_state_strings[location->state]); +} + +// Return num location +static int cache_get_locations(struct cache_c *dmc, u64 block_start_sector, u64 block_num_sectors, ssd_location *locations, int max_locations, int cache_index) +{ + struct cacheblock *pcacheblock = NULL; + int next_sub_block = 0; + int num_locations = 0; + int offset_sectors_in_cache_block = compatible_mod(block_start_sector, CACHE_BLK_SIZE_SEC); + u64 block_last_sector = block_start_sector + block_num_sectors - 1; + int offset_in_last_sub_block = compatible_mod(block_last_sector, SUB_BLOCK_SIZE); + int start_sub_block = compatible_div(offset_sectors_in_cache_block, SUB_BLOCK_SIZE); + int last_sub_block = compatible_div(compatible_mod(block_last_sector, CACHE_BLK_SIZE_SEC), SUB_BLOCK_SIZE); + data_range next_range = {0}; + cache_block_info cache_block_info = {0}; + data_state next_state = DATA_UNKNOWN; + data_state last_state = DATA_UNKNOWN; + bitmap_t next_sub_block_bit = 0; + ssd_location *next_location = NULL; + + pcacheblock = &dmc->cache[cache_index]; + next_location = locations; + + cache_block_info.block_start_sector = pcacheblock->dbn; + cache_block_info.ssd_start_sector = INDEX_TO_CACHE_ADDR(dmc, cache_index); + + + sdbg(DF_LOC, "start_sub_block=%d last_sub_block=%d", start_sub_block, last_sub_block); + sdbg(DF_LOC, "cache block data_bitmap=%x dirty_bitmap=%x", pcacheblock->data_bitmap, pcacheblock->dirty_bitmap); + + next_range.first_sub_block = start_sub_block; + + next_range.offset_in_first_sub_block = compatible_mod(block_start_sector, SUB_BLOCK_SIZE); + next_range.state = DATA_UNKNOWN; + + for (next_sub_block = start_sub_block; next_sub_block <= last_sub_block; next_sub_block++) { + + next_sub_block_bit = 1 << next_sub_block; + + // Find next data range state + if (pcacheblock->data_bitmap & next_sub_block_bit) { + if (pcacheblock->dirty_bitmap & next_sub_block_bit) { +#ifdef MY_ABC_HERE + if (pcacheblock->cache_state & PIN_FILE) { + next_state = DATA_DIRTY_PIN; + } else +#endif + next_state = DATA_DIRTY; + } else { +#ifdef MY_ABC_HERE + if (pcacheblock->cache_state & PIN_FILE) { + next_state = DATA_CACHED_PIN; + } else +#endif + next_state = DATA_CACHED; + } + } else { + next_state = DATA_UNCACHED; + } + + if (DATA_UNKNOWN == last_state) { + next_range.state = next_state; + } else if (last_state == next_state) { + // State is keep the same + } else { + // State change, handle the previous range of data + + if (num_locations > max_locations) { + serr("Over the number of locations"); + VERIFY_WARN(0); + } + + next_range.last_sub_block = next_sub_block - 1; + // Data fills the lat sub block + next_range.offset_in_last_sub_block = SUB_BLOCK_SIZE - 1; + + ssd_location_init(next_location, &cache_block_info, &next_range); + + memset(&next_range, 0, sizeof(next_range)); + + // Set for next_range + next_range.first_sub_block = next_sub_block; + next_range.offset_in_first_sub_block = 0; + next_range.state = next_state; + + num_locations++; + next_location++; + } + + last_state = next_state; + } // End of for + + // Handle the the last range of data (contain the last sub block) + sdbg(DF_LOC, "Handle the last group:"); + + if (num_locations > max_locations) { + serr("Over the number of locations"); + VERIFY_WARN(0); + } + + next_range.last_sub_block = next_sub_block - 1; + next_range.offset_in_last_sub_block = offset_in_last_sub_block; + + ssd_location_init(next_location, &cache_block_info, &next_range); + num_locations++; + + sdbg(DF_LOC, "out num_locations=%d", num_locations); + return num_locations; +} + +static int cache_query_ssd_location(struct cache_c *dmc, u64 block_start_sector, u64 block_num_sectors, ssd_location *locations, int max_locations) +{ + unsigned long set_number = 0; + int start_index = 0; + int end_index = 0; + int i = 0; + int num_locations = 0; + unsigned long flags; + + VERIFY_WARN(dmc && locations && max_locations); + + set_number = hash_block(dmc, block_start_sector); + start_index = dmc->assoc * set_number; + end_index = start_index + dmc->assoc; + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + for (i = start_index ; i < end_index ; i++) { + /* + * Search each cache block and check if bio's start sector (dbn) match a range of an cacheblk + */ + if (block_start_sector >= dmc->cache[i].dbn && + (block_start_sector < (dmc->cache[i].dbn + dmc->block_size)) && + dmc->cache[i].cache_state & VALID) { + + if ((block_start_sector + block_num_sectors) > (dmc->cache[i].dbn + dmc->block_size)) { + // Should not enter here + sdbg(DF_LOC, "dbn + size is over the cache's range Bio [sector=%llu size=%llu] \ + cacheblk.dbn=%llu\n", + (u64)block_start_sector, (u64)block_num_sectors, (u64)dmc->cache[i].dbn); + VERIFY_WARN(0); + } else { + // Find match cache block + num_locations = cache_get_locations(dmc, block_start_sector, block_num_sectors, locations, max_locations, i); + break; + } + + } + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + return num_locations; +} + +/* + * buf, count: request and its size from user + * offp: the current access offset + */ +static ssize_t ssd_query_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + static char data[2048]= {0}; + static int len = 0; + static int data_remaining = 0; + int num_read = 0; + ssize_t ret = -EFAULT; + int num_locations = 0; + int i = 0; + char * str_block_start_sector = ""; + char * str_num_sectors = ""; + char * str_cache_start_sector = ""; + char * str_state = ""; + int len_block_start_sector = strlen(str_block_start_sector); + int len_num_sectors = strlen(str_num_sectors); + int len_cache_start_sector = strlen(str_cache_start_sector); + int len_state = strlen(str_state); + char format[256] = {0}; + ssd_location ssd_locations[MAX_NUM_LOCATION] = {}; + ssd_location *next_location = NULL; + + dmc = (struct cache_c*)PDE_DATA(file_inode(filp)); + + sdbg_in(DF_LOC, "in"); + + if (0 == len) { + // First time access, generate data + num_locations = cache_query_ssd_location(dmc, dmc->query_start_sector, dmc->query_num_sectors, + ssd_locations, sizeof(ssd_locations)/sizeof(ssd_locations[0])); + + sdbg(DF_LOC, "num_locations=%d", num_locations); + + if (0 == num_locations) { + len += snprintf(data + len, sizeof(data) - len, "Query data are not in cache!\n"); + } else { + len += snprintf(data + len, sizeof(data) - len, "%s %s %s %s\n", str_block_start_sector, str_num_sectors, str_cache_start_sector, str_state); + + snprintf(format, sizeof(format),"%%%dllu %%%dllu %%%dllu %%%ds\n", len_block_start_sector, + len_num_sectors, len_cache_start_sector, len_state); + + for (i = 0; i < num_locations; i++) { + next_location = &ssd_locations[i]; + len += snprintf(data + len, sizeof(data) - len, format, next_location->block_start_sector, next_location->block_num_sectors, + next_location->cache_start_sector, data_state_strings[next_location->state]); + if (len == sizeof(data)) { + serr("Data array size is not enough"); + break; + } + } + } + } else { + if (*offp == len) { + // No more data, return EOF + len = 0; + *offp = 0; + memset(data, 0, sizeof(data)); + ret = 0; + sdbg(DF_LOC, "return EOF"); + goto end; + } else if (*offp < len) { + // Skill has data to read + } else { + serr("Should not enter here"); + goto end; + } + + } + + data_remaining = len - *offp; + + if (count > data_remaining) { + num_read = data_remaining; + } else { + num_read = count; + } + + sdbg(DF_LOC, "copy to user: *offp=%lld num_read=%d data_len=%d ", *offp, num_read, len); + if (copy_to_user(buf, data + *offp, num_read)) { + serr("Copy to user error"); + goto end; + } + *offp += num_read; + + ret = num_read; +end: + sdbg_out(DF_LOC, "out"); + + return ret; +} + +ssize_t ssd_query_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + ssize_t ret = -EFAULT; + char tmp[512] = {0}; + u64 query_start_sector = 0; + u64 query_num_sectors = 0; + u64 query_last_sector = 0; + u64 start_block_num = 0; + u64 last_block_num = 0; + + dmc = (struct cache_c*)PDE_DATA(file_inode(file)); + + if (copy_from_user(tmp, buffer, count)) { + goto end; + } + + if (2 == sscanf(tmp, "%llu %llu", &query_start_sector, &query_num_sectors)) { + sdbg(DF_LOC, "Query start=%llu num=%llu", query_start_sector, query_num_sectors); + } else { + serr("Parse error"); + goto err; + } + + start_block_num = compatible_div(query_start_sector, MAX_BIO_SIZE); + query_last_sector = query_start_sector + query_num_sectors - 1; + last_block_num = compatible_div(query_last_sector, MAX_BIO_SIZE); + + if (start_block_num != last_block_num) { + serr("Across two cache block, doesn't support: Query start sector=%llu end sector=%llu", query_start_sector, query_last_sector); + goto err; + } + dmc->query_start_sector = query_start_sector; + dmc->query_num_sectors = query_num_sectors; + ret = count; + +end: + return ret; +err: + dmc->query_start_sector = 0; + dmc->query_num_sectors = 0; + + return ret; +} + +DECLARE_PROC_OPS_READ_WRITE(ssd_query_ops, ssd_query_read_proc, ssd_query_write_proc); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +const char * option_string[] = { + /* + * QUERY_NUM_SETS + * get the num of sets in this cache device + */ + "num-sets", + /* + * QUERY_SET_NUM + * parameter: block_start_sector + * calculate the set num from the block device start sector + */ + "get-set-num", + /* + * QUERY_DUMP_SET + * parameter: set_num + * dump cache blocks from 0 to 511 + */ + "dump-set-info", + /* + * QUERY_DUMP_SET_LRU_LIST + * parameter: set_num + * dump the cache blocks in the lru list of this set + */ + "dump-set-lru-list", + /* + * QUERY_BITMAP + * Dump bits set in the bitmap table + */ + "query-bitmap", +}; + +query_type_t get_query_type(char *option) +{ + int i = 0; + query_type_t query_type = QUERY_ERROR; + + for (i = 0; i < sizeof(option_string)/sizeof(option_string[0]); i++) { + if (0 == strncmp(option, option_string[i], strlen(option_string[i]))) { + query_type = i; + break; + } + } + return query_type; +} + +int query_set_num_set(struct cache_c *dmc, char *buf) +{ + int ret = -1; + char option[512] = {0}; + u64 block_start_sector = 0; + internal_query_t *pinternal_query = &(dmc->internal_query); + + if (2 == sscanf(buf, "%s %llu", option, &block_start_sector)) { + sdbg(DF_DETAIL, "Query option=%s block_start_sector=%llu", option, block_start_sector); + pinternal_query->block_start_sector = block_start_sector; + } else { + serr("Parse error"); + goto err; + } + + ret = 0; + +err: + return ret; +} + +int query_set_num_get(struct cache_c *dmc, char *buf, int buf_len) +{ + int len = 0; + u64 set_number = 0; + internal_query_t *pinternal_query = &(dmc->internal_query); + set_number = hash_block(dmc, pinternal_query->block_start_sector); + + len = snprintf(buf, buf_len, "%llu\n", set_number); + + return len; +} + +int query_dump_set_set(struct cache_c *dmc, char *buf) +{ + int ret = -1; + char option[512] = {0}; + unsigned int set_num = 0; + internal_query_t *pinternal_query = &(dmc->internal_query); + + if (2 == sscanf(buf, "%s %d", option, &set_num)) { + sdbg(DF_DETAIL, "Query option=%s set_num=%d", option, set_num); + pinternal_query->set_num = set_num; + } else { + serr("Parse error"); + goto err; + } + + ret = 0; + +err: + return ret; +} + +void query_dump_set_get(struct cache_c *dmc) +{ + internal_query_t *pinternal_query = &(dmc->internal_query); + unsigned int set_num = pinternal_query->set_num; + int start_index = dmc->assoc * set_num; + int end_index = start_index + dmc->assoc; + int i = 0; + + for (i = start_index; i < end_index; i++) { + serr("cacheblk %d start_sector=%llu pin=%d", i, (u64)dmc->cache[i].dbn, + (dmc->cache[i].cache_state & PIN_FILE) ? 1: 0); + } +} + +void query_dump_set_lru_list_get(struct cache_c *dmc) +{ + internal_query_t *pinternal_query = &(dmc->internal_query); + unsigned int set_num = pinternal_query->set_num; + int start_index = set_num * dmc->assoc; + struct cache_set *cache_set = &dmc->cache_sets[set_num]; + int next_set_index = 0; + struct cacheblock *next_cacheblk = NULL; + int lru_count = 0; + unsigned long flags = 0; + + if (FLASHCACHE_LRU_NULL == cache_set->lru_head) { + serr("set [%u]: LRU queue is NULL", set_num); + return; + } + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + next_set_index = cache_set->lru_head; + next_cacheblk = &dmc->cache[start_index + next_set_index]; + + while (FLASHCACHE_LRU_NULL != next_set_index) { + serr("set [%u]'s lru [%d] cacheblk [%d] start_sector=%llu pin=%d state=0x%x", + set_num, lru_count, next_set_index, + (u64)next_cacheblk->dbn, (next_cacheblk->cache_state & PIN_FILE) ? 1: 0, + next_cacheblk->cache_state); + + next_set_index = next_cacheblk->lru_next; + next_cacheblk = &dmc->cache[start_index + next_set_index]; + lru_count++; + } + + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); +} + +int query_check_pin_lru_order(struct cache_c *dmc) +{ + internal_query_t *pinternal_query = &(dmc->internal_query); + unsigned int set_num = pinternal_query->set_num; + int start_index = set_num * dmc->assoc; + struct cache_set *cache_set = &dmc->cache_sets[set_num]; + int next_set_index = 0; + struct cacheblock *next_cacheblk = NULL; + int lru_count = 0; + int start_pin_num = 0; + int got_pin_block = 0; + unsigned long flags = 0; + int ret = 1; + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + + next_set_index = cache_set->lru_head; + next_cacheblk = &dmc->cache[start_index + next_set_index]; + + while (FLASHCACHE_LRU_NULL != next_set_index) { + // Check if LRU list is in Head -> Unpin blocks -> Pin blocks -> Tail order + if (next_cacheblk->cache_state & PIN_FILE) { + got_pin_block = 1; + start_pin_num = lru_count; + } else { + // cache block is not pinned + if (got_pin_block) { + // Should not has unpin blocks after pin blocks + serr("Error: Get unpin cache blocks after cache blocks (currnt lru num = %d start pin num =%d)", + lru_count, start_pin_num); + goto err; + } + } + next_set_index = next_cacheblk->lru_next; + next_cacheblk = &dmc->cache[start_index + next_set_index]; + lru_count++; + } + + if (dmc->assoc != lru_count) { + serr("Error: lru has wrong node (lru_count = %d disk->assoc = %d)", lru_count, dmc->assoc); + goto err; + } + + ret = 0; +err: + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + return ret; +} + + +void query_bitmap_get(struct cache_c *dmc) +{ + unsigned char *pbytes = NULL; + unsigned char next_byte = 0; + int i = 0; + int next_bit = 0; +#ifdef MY_ABC_HERE + + bitmap_control_get(dmc); +#endif + pbytes = (unsigned char *) dmc->pbitmap_ranges; + + for (i = 0; i < dmc->bitmap_size_byte; i++) { + next_byte = pbytes[i]; + for (next_bit = 0; next_bit < 8; next_bit ++) { + if (next_byte & (1 << next_bit)) { + serr("Byte=%d bit=%d is set", i, next_bit); + } + } + } +#ifdef MY_ABC_HERE + bitmap_control_put(dmc); +#endif +} + +static ssize_t internal_query_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + int len = 0; + char tmp[512]= {0}; + ssize_t ret = -EFAULT; + static int finished = 0; + + dmc = (struct cache_c*)PDE_DATA(file_inode(filp)); + + sdbg_in(DF_DETAIL, "in"); + + // Return 0 to indicate EOF (avoid endless loop to read) + if (finished) { + finished = 0; + return 0; + } + finished = 1; + + switch (dmc->internal_query.query_type) { + case QUERY_ERROR: + len += snprintf(tmp + len, sizeof(tmp) - len, "Last query input is incorrect"); + break; + case QUERY_NUM_SETS: + len += snprintf(tmp + len, sizeof(tmp) - len, "%u\n", dmc->num_sets); + break; + case QUERY_SET_NUM: + len += query_set_num_get(dmc, tmp, sizeof(tmp)); + break; + case QUERY_DUMP_SET: + query_dump_set_get(dmc); + /* + * Add a workaround here. This function jsut print message and return 1 + * (return 0 will be treated as EOF) + */ + len = 1; + break; + case QUERY_DUMP_SET_LRU_LIST: + query_dump_set_lru_list_get(dmc); + /* + * Add a workaround here. This function jsut print message and return 1 + * (return 0 will be treated as EOF) + */ + len = 1; + break; + case QUERY_BITMAP: + query_bitmap_get(dmc); + len = 1; + break; + } + + if (count > len) { + count = len; + } + + if (copy_to_user(buf, tmp, count)) { + serr("copy to user error"); + goto end; + } else { + ret = count; + } + +end: + sdbg_out(DF_DETAIL, "out"); + + return ret; +} + + +ssize_t internal_query_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + ssize_t ret = -EFAULT; + char tmp[512] = {0}; + char option[512] = {0}; + + dmc = (struct cache_c*)PDE_DATA(file_inode(file)); + + if (copy_from_user(tmp, buffer, count)) { + goto err; + } + + // Get first sub string + if (1 == sscanf(tmp, "%s", option)) { + sdbg(DF_DETAIL, "Query option=%s", option); + } else { + serr("Parse error"); + goto err; + } + + // Set query type + dmc->internal_query.query_type = get_query_type(option); + + // Set extra information + switch (dmc->internal_query.query_type) { + case QUERY_ERROR: + serr("Query error, option=%s", option); + break; + case QUERY_NUM_SETS: + break; + case QUERY_SET_NUM: + if (query_set_num_set(dmc, tmp)) { + serr("Query set number failed"); + } + break; + case QUERY_DUMP_SET: + if (query_dump_set_set(dmc, tmp)) { + serr("Query dump set failed"); + } + break; + case QUERY_DUMP_SET_LRU_LIST: + if (query_dump_set_set(dmc, tmp)) { + serr("Query dump set failed"); + } + break; + case QUERY_BITMAP: + serr("Query bitmp is set"); + break; + } + ret = count; + +err: + return ret; +} + +DECLARE_PROC_OPS_READ_WRITE(internal_query_ops, internal_query_read_proc, + internal_query_write_proc); +#endif +#ifdef MY_ABC_HERE +static const char *attr_str(attribute_t attr) +{ + switch (attr) { + case ATTR_NONE: + return "none"; + break; + case ATTR_FORCE_REMOVE: + return "force-remove"; + break; + default: + serr("incorrect attribute"); + return ""; + break; + } +} + +static ssize_t attribute_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + int len = 0; + char output[512]= {0}; + ssize_t ret = -EFAULT; + static int finished = 0; + + dmc = (struct cache_c*)PDE_DATA(file_inode(filp)); + + // Return 0 to indicate EOF (avoid endless loop to read) + if (finished) { + finished = 0; + return 0; + } + finished = 1; + + if (ATTR_NONE == dmc->attribute) { + len += snprintf(output + len, sizeof(output) - len, "%s\n", attr_str(ATTR_NONE)); + } else if (ATTR_FORCE_REMOVE == dmc->attribute) { + len += snprintf(output + len, sizeof(output) - len, "%s\n", attr_str(ATTR_FORCE_REMOVE)); + } else { + serr("Incorrect attribute = %d", dmc->attribute); + } + + if (count > len) { + count = len; + } + + if (copy_to_user(buf, output, count)) { + serr("copy to user error"); + goto end; + } else { + ret = count; + } +end: + return ret; +} + + +ssize_t attribute_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + ssize_t ret = -EFAULT; + char input[512] = {0}; + char attr[512] = {0}; + + dmc = (struct cache_c*)PDE_DATA(file_inode(file)); + + if (copy_from_user(input, buffer, count)) { + serr("failed to get data from user space"); + goto err; + } + + if (1 != sscanf(input, "%s", attr)) { + serr("Parse error"); + goto err; + } + if (0 == strcmp(attr_str(ATTR_NONE), attr)) { + dmc->attribute = ATTR_NONE; + } else if (0 == strcmp(attr_str(ATTR_FORCE_REMOVE), attr)) { + dmc->attribute = ATTR_FORCE_REMOVE; + } else { + serr("Incorrect attribute = %s", attr); + goto err; + } + + ret = count; + +err: + return ret; +} + +DECLARE_PROC_OPS_READ_WRITE(attribute_ops, attribute_read_proc, attribute_write_proc); + +#endif +#ifdef MY_ABC_HERE +static ssize_t list_set_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + struct cache_c *dmc = NULL; + int len = 0; + static char output[8192]= {0}; + ssize_t ret = -EFAULT; + + static int finished = 0; + static int proc_next_set = 0; + static int total_valid_count = 0; + + int round_set_max = 20; + int round_set_count = 0; + int next_set = 0; + int start_index = 0; + int last_index = 0; + int valid_count = 0; + int i = 0; + + memset(output, 0, sizeof(output)); + dmc = (struct cache_c*)PDE_DATA(file_inode(filp)); + + // Return 0 to indicate EOF (avoid endless loop to read) + if (finished) { + finished = 0; + proc_next_set = 0; + total_valid_count = 0; + return 0; + } + + if (!proc_next_set) { + len += snprintf(output + len, sizeof(output) - len, "set number, num of data blocks\n"); + } + + for (next_set = proc_next_set; round_set_count < round_set_max; next_set++) { + + proc_next_set++; + + // Finish + if (next_set == dmc->num_sets) { + len += snprintf(output + len, sizeof(output) - len,"Total Valid: %d\n", total_valid_count); + finished = 1; + break; + } + + start_index = next_set * dmc->assoc; + last_index = start_index + dmc->assoc - 1; + valid_count = 0; + + for (i = start_index; i <= last_index; i++) { + if (dmc->cache[i].cache_state & VALID) { + valid_count++; + } + } + len += snprintf(output + len, sizeof(output) - len, "%d, %d\n", next_set, valid_count); + round_set_count++; + total_valid_count += valid_count; + + } + + if (count > len) { + count = len; + } + + if (copy_to_user(buf, output, count)) { + serr("copy to user error"); + goto end; + } else { + ret = count; + } +end: + return ret; +} + + +ssize_t list_set_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + return 0; +} + +DECLARE_PROC_OPS_READ_WRITE(list_set_valid_block_ops, list_set_read_proc, list_set_write_proc); + +#endif + +extern char *flashcache_sw_version; + +static int +flashcache_version_show(struct seq_file *seq, void *v) +{ + seq_printf(seq, "Flashcache Version : %s\n", flashcache_sw_version); +#ifdef COMMIT_REV +#ifdef MY_ABC_HERE + seq_printf(seq, "git commit: %s, MAX_JOB_MEM_COUNT:%d \n", COMMIT_REV, MAX_JOB_MEM_COUNT); +#else + seq_printf(seq, "git commit: %s\n", COMMIT_REV); +#endif +#endif + return 0; +} + +static int +flashcache_version_open(struct inode *inode, struct file *file) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_version_show, PDE(inode)->data); + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + return single_open(file, &flashcache_version_show, PDE_DATA(inode)); + #endif +} + +DECLARE_PROC_OPS_OPEN(flashcache_version_operations, flashcache_version_open); + +#ifdef MY_ABC_HERE +void wrap_create_proc_entry_version(void) +{ + struct proc_dir_entry *entry; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry("flashcache/flashcache_version_syno", 0, NULL); + if (entry) + entry->proc_fops = &flashcache_version_operations; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create("flashcache/flashcache_version_syno", 0, NULL, &flashcache_version_operations); +#endif +} +#endif + + +#ifdef MY_ABC_HERE + +long debug_flags; + +// Return the count of read on success. Otherwise return -EFAULT +static ssize_t common_proc_read_long(char *buf, size_t count, long input) +{ + ssize_t len = 0; + char tmp[512]= {0}; + ssize_t ret = -EFAULT; + static int finished = 0; + + // Return 0 to indicate EOF (avoid endless loop to read) + if (finished) { + finished = 0; + return 0; + } + + finished = 1; + + len = snprintf(tmp, sizeof(tmp), "%ld\n", input); + + if (count > len) { + count = len; + } + + if (copy_to_user(buf, tmp, count)) { + goto end; + } else { + ret = count; + } + +end: + return ret; +} + +// Return the count of write on success, otherwise return -EFAULT +static ssize_t common_proc_write_long(const char __user *buffer, size_t count, long *output) +{ + char tmp[512] = {0}; + int ret = -EFAULT; + + if (copy_from_user(tmp, buffer, count)) { + goto err; + } + + if (0 > kstrtol(tmp, 10, output)) { + printk("kstrtol failed\n"); + goto err; + } else { + ret = count; + } + +err: + return ret; +} + +/* + * /proc/flashcache/debug_flags + */ +static struct proc_dir_entry *debug_entry; +long debug_flags; + +static ssize_t debug_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + return common_proc_read_long(buf, count, debug_flags); +} + +ssize_t debug_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + return common_proc_write_long(buffer, count, &debug_flags); +} + +DECLARE_PROC_OPS_READ_WRITE(debug_flags_ops, debug_read_proc, debug_write_proc); + +static struct proc_dir_entry *debug_entry; + +void create_entry_debug_flags(void) +{ + debug_entry = proc_create("flashcache/debug_flags", 0, NULL, &debug_flags_ops); + if (NULL == debug_entry) { + sprint("Can't create debug entry"); + } +} + +void remove_entry_debug_flags(void) +{ + if (debug_entry) { + remove_proc_entry("flashcache/debug_flags",0); + } +} + +/* + * /proc/flashcache/global_tester + */ + +static struct proc_dir_entry *global_tester_entry; +long global_tester; + +static ssize_t global_tester_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + return common_proc_read_long(buf, count, global_tester); +} + +ssize_t global_tester_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + return common_proc_write_long(buffer, count, &global_tester); +} + +DECLARE_PROC_OPS_READ_WRITE(global_tester_ops, global_tester_read_proc, + global_tester_write_proc); + +void create_entry_global_tester(void) +{ + global_tester_entry = proc_create("flashcache/global_tester", 0, NULL, &global_tester_ops); + if (NULL == global_tester_entry) { + sprint("Can't create global_tester entry"); + } +} + +void remove_entry_global_tester(void) +{ + if (global_tester_entry) { + remove_proc_entry("flashcache/global_tester",0); + } +} + +#endif + +#ifdef MY_ABC_HERE +unsigned long long data_rescue_flags; +static ssize_t data_rescue_read_proc(struct file *filp, char *buf, size_t count, loff_t *offp) +{ + ssize_t len = 0; + char tmp[512]= {0}; + ssize_t ret = -EFAULT; + static int finished = 0; + + // Return 0 to indicate EOF (avoid endless loop to read) + if (finished) { + finished = 0; + return 0; + } + + finished = 1; + + len = snprintf(tmp, sizeof(tmp), "%lld\n", data_rescue_flags); + + if (count > len) { + count = len; + } + + if (copy_to_user(buf, tmp, count)) { + goto end; + } else { + ret = count; + } + +end: + return ret; +} + +ssize_t data_rescue_write_proc(struct file *file, const char __user *buffer, size_t count, loff_t *offp) +{ + ssize_t ret = -EFAULT; + char tmp[512] = {0}; + + if (copy_from_user(tmp, buffer, count)) { + goto end; + } + + if (0 > kstrtoll(tmp, 10, &data_rescue_flags)) { + sprint("kstrtol failed"); + goto end; + } else { + sprint("Set data rescue flags to %lld", data_rescue_flags); + ret = count; + } + +end: + return ret; +} + +DECLARE_PROC_OPS_READ_WRITE(data_rescue_ops, data_rescue_read_proc,data_rescue_write_proc); + +static struct proc_dir_entry *data_rescue_entry; + +void create_entry_data_rescue(void) +{ + data_rescue_entry = proc_create("flashcache/data_rescue_flags", 0, NULL, &data_rescue_ops); + if (NULL == data_rescue_entry) { + sprint("Can't create data_rescue_flags entry"); + } +} + +void remove_entry_data_rescue(void) +{ + if (data_rescue_entry) { + remove_proc_entry("flashcache/data_rescue_flags",0); + data_rescue_entry = NULL; + } +} +#endif /* MY_ABC_HERE */ + +void +flashcache_module_procfs_init(void) +{ +#ifdef CONFIG_PROC_FS +#ifdef MY_ABC_HERE + int ret = -1; + + ret = down_interruptible(&syno_flashcache_proc_mutex); + if (ret) { + serr("Get interrupt while getting mutex"); + return; + } + + if (0 == syno_flashcache_proc_count) { + if (proc_mkdir("flashcache", NULL)) { + wrap_create_proc_entry_version(); + } + } else { + wrap_create_proc_entry_version(); + } + syno_flashcache_proc_count++; + +#ifdef MY_ABC_HERE + create_entry_debug_flags(); + create_entry_global_tester(); +#endif + create_entry_data_rescue(); + up(&syno_flashcache_proc_mutex); +#else + struct proc_dir_entry *entry; + + if (proc_mkdir("flashcache", NULL)) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry("flashcache/flashcache_version", 0, NULL); + if (entry) + entry->proc_fops = &flashcache_version_operations; + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create("flashcache/flashcache_version", 0, NULL, &flashcache_version_operations); + #endif + + } +#endif +#endif /* CONFIG_PROC_FS */ +} + +void +flashcache_module_procfs_releae(void) +{ +#ifdef CONFIG_PROC_FS +#ifdef MY_ABC_HERE + int ret = -1; + + ret = down_interruptible(&syno_flashcache_proc_mutex); + if (ret) { + serr("Get interrupt while getting mutex"); + return; + } + syno_flashcache_proc_count--; +#ifdef MY_ABC_HERE + remove_entry_debug_flags(); + remove_entry_data_rescue(); + remove_entry_global_tester(); +#endif + + if (0 == syno_flashcache_proc_count) { + (void)remove_proc_entry("flashcache/flashcache_version_syno", NULL); + (void)remove_proc_entry("flashcache", NULL); + } else { + (void)remove_proc_entry("flashcache/flashcache_version_syno", NULL); + printk(KERN_INFO "flashcache_syno: /proc/flashcache is still in use, don't remove it\n"); + } + + up(&syno_flashcache_proc_mutex); +#else + (void)remove_proc_entry("flashcache/flashcache_version_syno", NULL); + (void)remove_proc_entry("flashcache", NULL); +#endif +#endif /* CONFIG_PROC_FS */ +} + +#ifdef MY_ABC_HERE +static char * +syno_get_sysctl_dirname(struct cache_c *dmc) +{ + char *path_name = NULL; + int path_len = 0; + char *combined_name = NULL; + char *prefix = "flashcache_"; + int err = 1; + + combined_name = entry_get_combined_name(dmc->cache_devname, dmc->disk_devname); + if (!combined_name) { + serr("Failed to get sysctl dirname by %s + %s", dmc->cache_devname, dmc->disk_devname); + goto err; + } + + // e.g. flashcache_COMBINED_NAME + path_len = strlen(prefix) + strlen(combined_name) + 1; + path_name = kzalloc(path_len, GFP_KERNEL); + if (!path_name) { + serr("Failed to allocate for sysctl dirname"); + goto err; + } + + snprintf(path_name, path_len, "%s%s", prefix, combined_name); + + err = 0; +err: + if (combined_name) { + kfree(combined_name); + } + + if (err && path_name) { + kfree(path_name); + path_name = NULL; + } + return path_name; +} +#else +static char * +flashcache_cons_sysctl_devname(struct cache_c *dmc) +{ + char *pathname; + + // alloc_cache_1+volume_1 + pathname = kzalloc(strlen(dmc->cache_devname) + strlen(dmc->disk_devname) + 2, + GFP_KERNEL); + if (!pathname) { + serr("Failed to allocate for sysctl devname"); + return NULL; + } + strcpy(pathname, strrchr(dmc->cache_devname, '/') + 1); + strcat(pathname, "+"); + strcat(pathname, strrchr(dmc->disk_devname, '/') + 1); + return pathname; +} +#endif +/* + * /dev/shared_cache_vg1/alloc_cache_1 => share_cache_vg1_alloc_cache_1 + * /dev/md4 => md4 + * XXX: SSD entry name must be unique to generate unique entry path + */ +static char * +entry_get_ssd_name(const char *ssd_path) +{ + int i = 0; + char *name = NULL; + int name_len = 0; + int err = 1; + + name_len = strlen(ssd_path) + 1; + name = kzalloc(name_len, GFP_NOIO); + if (!name) { + serr("Failed to allocate memory"); + goto err; + } + + // remove dev + if (1 != sscanf(ssd_path, "/dev/%s", name)) { + serr("No /dev/ in path %s", ssd_path); + goto err; + } + + for (i = 0; i < strlen(name); i++) { + if (name[i] == '/') { + name[i] = '_'; + } + } + + err = 0; +err: + if (err && name) { + kfree(name); + name = NULL; + } + return name; +} + +/* + * Always get the last word + * For example: /dev/vg1000/lv => lv + */ +static const char* +entry_locate_disk_name(const char *disk_path) +{ + const char *s = NULL; + + s = strrchr(disk_path, '/'); + if (s) { + s++; + } else { + s = disk_path; + } + return s; +} + +/* + * NOTE: combined name must be UNIQUE + * + * + * /dev/shared_cache_vg1/alloc_1 /dev/vg1000/lv shared_cache_vg1_alloc_1+lv + * /dev/md4 /dev/vg1000/lv md4+lv (single cache combined name remains unchanged) + */ +static char * +entry_get_combined_name(const char *ssd_path, const char *disk_path) +{ + char *ssd_name = NULL; + const char *disk_name = NULL; + char *comb_name = NULL; + const char *comb_char = "+"; + int comb_len = 0; + int err = 1; + + ssd_name = entry_get_ssd_name(ssd_path); + if (!ssd_name) { + goto err; + } + + disk_name = entry_locate_disk_name(disk_path); + + comb_len = strlen(ssd_name) + strlen(comb_char) + strlen(disk_name) + 1; + comb_name = kzalloc(comb_len, GFP_NOIO); + if (!comb_name) { + serr("Failed to allocate memory"); + goto err; + } + + + snprintf(comb_name, comb_len, "%s%s%s", ssd_name, comb_char, disk_name); + + err = 0; +err: + if (ssd_name) { + kfree(ssd_name); + } + + if (err) { + serr("Failed to get combined name from %s,%s", ssd_path, disk_path); + if (comb_name) { + kfree(comb_name); + comb_name = NULL; + } + } + + return comb_name; +} + +static char * +flashcache_cons_procfs_cachename(struct cache_c *dmc, char *path_component) +{ + char *path_name = NULL; + char *combined_name = NULL; + int err = 1; + int path_len = 0; + int path_comp_len = 0; + + combined_name = entry_get_combined_name(dmc->cache_devname, dmc->disk_devname); + if (!combined_name) { + goto err; + } + + // e.g. flashcache/COMBINED_NAME/flashcache_internal_query + path_comp_len = strlen(path_component); + path_len = strlen(FLASHCACHE_PROC_ROOTDIR_NAME) + strlen(combined_name) + path_comp_len + 3; + + path_name = kzalloc(path_len, GFP_NOIO); + if (!path_name) { + serr("failed to allocate memory for proc name %s/%s", + combined_name, path_component); + goto err; + } + + if (path_comp_len != 0) { + snprintf(path_name, path_len, "%s/%s/%s", FLASHCACHE_PROC_ROOTDIR_NAME, combined_name, path_component); + } else { + snprintf(path_name, path_len, "%s/%s", FLASHCACHE_PROC_ROOTDIR_NAME, combined_name); + } + + err = 0; +err: + if (combined_name) { + kfree(combined_name); + } + + if (err && path_name) { + kfree(path_name); + path_name = NULL; + } + + return path_name; +} + + +void +flashcache_ctr_procfs(struct cache_c *dmc) +{ + char *s; + struct proc_dir_entry *entry; + + /* We can not create proc entries if fail to create folder */ + if ((s = flashcache_cons_procfs_cachename(dmc, ""))) { + entry = proc_mkdir(s, NULL); + kfree(s); + if (entry == NULL) + return; + } else { + return; + } + +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_progress"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_progress_operation; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_progress_operation, dmc); + #endif + kfree(s); + } +#endif +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "hash_mapping"))) { + entry = proc_create_data(s, 0, NULL, &flashcache_hash_mapping_operation, dmc); + kfree(s); + } +#endif +#ifdef SYNO_FLASHCACHE_DEBUG + if ((s = flashcache_cons_procfs_cachename(dmc, "debug"))) { + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_debug_operation; + entry->data = &syno_debug; + } + kfree(s); + } +#endif +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_writeback_bypass"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_writeback_bypass_operation; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_writeback_bypass_operation, dmc); + #endif + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_attribute"))) { + entry = proc_create_data(s, 0, NULL, &attribute_ops, dmc); + kfree(s); + } + +#endif + +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "list_set_valid_block"))) { + entry = proc_create_data(s, 0, NULL, &list_set_valid_block_ops, dmc); + kfree(s); + } +#endif + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_stats"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_stats_operations; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_stats_operations, dmc); + #endif + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "cache_info"))) { + entry = proc_create_data(s, 0, NULL, &cache_info_ops, dmc); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "occupied_blocks_info"))) { + entry = proc_create_data(s, 0, NULL, &occupied_blocks_ops, dmc); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_errors"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_errors_operations; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_errors_operations, dmc); + #endif + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_iosize_hist"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_iosize_hist_operations; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_iosize_hist_operations, dmc); + #endif + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_pidlists"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_pidlists_operations; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_pidlists_operations, dmc); + #endif + kfree(s); + } + +#ifdef CONFIG_SYNO_DATA_CORRECTION + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_correction_list"))) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) + entry = create_proc_entry(s, 0, NULL); + if (entry) { + entry->proc_fops = &flashcache_correction_list_operations; + entry->data = dmc; + } + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) + entry = proc_create_data(s, 0, NULL, &flashcache_correction_list_operations, dmc); + #endif + kfree(s); + } +#endif /* CONFIG_SYNO_DATA_CORRECTION */ + +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_ssd_query"))) { + entry = proc_create_data(s, 0, NULL, &ssd_query_ops, dmc); + kfree(s); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_internal_query"))) { + entry = proc_create_data(s, 0, NULL, &internal_query_ops, dmc); + kfree(s); + } +#endif + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) + flashcache_writeback_sysctl_register(dmc); + else + flashcache_writethrough_sysctl_register(dmc); +} + +void +flashcache_dtr_procfs(struct cache_c *dmc) +{ + char *s; + + /* There'll be warning call trace if the proc is not there or there's leak */ +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_progress"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "hash_mapping"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif +#ifdef SYNO_FLASHCACHE_DEBUG + if ((s = flashcache_cons_procfs_cachename(dmc, "debug"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_writeback_bypass"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_attribute"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "list_set_valid_block"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_stats"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "cache_info"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "occupied_blocks_info"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_errors"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_iosize_hist"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_pidlists"))) { + remove_proc_entry(s, NULL); + kfree(s); + } + +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_ssd_query"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_internal_query"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif +#ifdef CONFIG_SYNO_DATA_CORRECTION + if ((s = flashcache_cons_procfs_cachename(dmc, "flashcache_correction_list"))) { + remove_proc_entry(s, NULL); + kfree(s); + } +#endif + + if ((s = flashcache_cons_procfs_cachename(dmc, ""))) { + remove_proc_entry(s, NULL); + kfree(s); + } + + if (dmc->cache_mode == FLASHCACHE_WRITE_BACK) + flashcache_writeback_sysctl_unregister(dmc); + else + flashcache_writethrough_sysctl_unregister(dmc); + +} diff --git a/drivers/syno/syno-mem-saving-driver/flashcache_subr.c b/drivers/syno/syno-mem-saving-driver/flashcache_subr.c new file mode 100644 index 000000000000..7fe33ae15bf0 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/flashcache_subr.c @@ -0,0 +1,1581 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/**************************************************************************** + * flashcache_subr.c + * FlashCache: Device mapper target for block-level disk caching + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@fb.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * 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; under 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#include // memalloc_noio_* apis +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#include "dm.h" +#include "dm-io.h" +#include "dm-bio-list.h" +#include "kcopyd.h" +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +#include "dm.h" +#endif +#include +#include +#include +#endif +#include "flashcache.h" + +#ifdef MY_ABC_HERE +#include "syno_quickflush.h" +#endif + +static DEFINE_SPINLOCK(_job_lock); + +extern mempool_t *_job_pool; +extern mempool_t *_pending_job_pool; +#ifdef MY_ABC_HERE +extern mempool_t *_job_mem_pool; + +// Lock for controlling job mem allocated +extern spinlock_t job_mem_lock; +extern int job_mem_count; +extern wait_queue_head_t job_mem_wait_queue; +#endif + +extern atomic_t nr_cache_jobs; +extern atomic_t nr_pending_jobs; +extern int job_max_mem_count; + +static void job_mem_mempool_put(void); + + +struct kcached_job * +flashcache_alloc_cache_job(void) +{ + struct kcached_job *job; + + job = mempool_alloc(_job_pool, GFP_NOIO); +#ifdef MY_ABC_HERE + if (likely(job)) { + atomic_inc(&nr_cache_jobs); + memset(job, 0, sizeof(*job)); + } +#ifdef MY_ABC_HERE + else { + if (printk_ratelimit()) { + serr("Failed to allocate memory for cache jobs"); + } + } +#endif +#else + if (likely(job)) + atomic_inc(&nr_cache_jobs); +#endif + return job; +} + +/* + * Might sleep if not in interrupt context (vfree) + */ +void +flashcache_free_cache_job(struct kcached_job *job) +{ + flashcache_free_cache_job_mem(job); + + mempool_free(job, _job_pool); + atomic_dec(&nr_cache_jobs); +} + +/* + * Might sleep if not in interrupt context (vfree) + */ +void +flashcache_free_cache_job_mem(struct kcached_job *job) +{ +#ifdef MY_ABC_HERE + if (NULL != job->mem_addr) { + if (job->flag & JOB_MEM_VMALLOC) { + vfree(job->mem_addr); + job->mem_addr = NULL; + } else if (job->flag & JOB_MEM_MEMPOOL) { + mempool_free(job->mem_addr, _job_mem_pool); + job->mem_addr = NULL; + job_mem_mempool_put(); + } else { + serr("Free %d job memory without type", job->action); + VERIFY_WARN(0); + } + } +#else + if (NULL != job->mem_addr) { + mempool_free(job->mem_addr, _job_mem_pool); + job->mem_addr = NULL; + job_mem_mempool_put(); + } +#endif +} + +struct pending_job * +flashcache_alloc_pending_job(struct cache_c *dmc) +{ + struct pending_job *job; + + job = mempool_alloc(_pending_job_pool, GFP_ATOMIC); + if (likely(job)) { + atomic_inc(&nr_pending_jobs); + } else { + atomic_inc(&dmc->flashcache_errors.memory_alloc_errors); +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate memory for pending jobs"); + } +#endif + } + return job; +} + +void +flashcache_free_pending_job(struct pending_job *job) +{ + mempool_free(job, _pending_job_pool); + atomic_dec(&nr_pending_jobs); +} + +#define FLASHCACHE_PENDING_JOB_HASH(INDEX) ((INDEX) % PENDING_JOB_HASH_SIZE) + +/* + * plat and io_type are mutual exclusive. Given plat, we use plat->io_type. + */ +void +flashcache_enq_pending(struct cache_c *dmc, struct bio* bio, + int index, int action, struct pending_job *job, + struct io_latency *plat, enum cache_io_type io_type) +{ + struct pending_job **head; + + head = &dmc->pending_job_hashbuckets[FLASHCACHE_PENDING_JOB_HASH(index)]; + DPRINTK("flashcache_enq_pending: Queue to pending Q Index %d %llu", + index, bio_bi_sector(bio)); + VERIFY_WARN(job != NULL); + job->action = action; + job->index = index; + job->bio = bio; + job->prev = NULL; + job->next = *head; + if (*head) + (*head)->prev = job; + *head = job; + + if (plat) { + job->io_lat = *plat; + } else { + /* enq pending request must have bio -> have preprocess time */ + flashcache_init_io_latency(&job->io_lat, + dmc->sysctl_syno_latency_diagnose, io_type, + bio_get_start_jiffy(bio), 1); + } + + dmc->cache[index].nr_queued++; + atomic64_inc(&dmc->flashcache_stats.enqueues); + if (INVALIDATE == job->action) { + atomic64_inc(&dmc->flashcache_stats.pending_enqueue_inval_start); + } + dmc->pending_jobs_count++; +} + +/* + * Deq and move all pending jobs that match the index for this slot to list returned + */ +struct pending_job * +flashcache_deq_pending(struct cache_c *dmc, int index) +{ + struct pending_job *node, *next, *movelist = NULL; + int moved = 0; + struct pending_job **head; + + VERIFY_WARN(spin_is_locked(&dmc->cache_spin_lock)); + head = &dmc->pending_job_hashbuckets[FLASHCACHE_PENDING_JOB_HASH(index)]; + for (node = *head ; node != NULL ; node = next) { + next = node->next; + if (node->index == index) { + /* + * Remove pending job from the global list of + * jobs and move it to the private list for freeing + */ + if (node->prev == NULL) { + *head = node->next; + if (node->next) + node->next->prev = NULL; + } else + node->prev->next = node->next; + if (node->next == NULL) { + if (node->prev) + node->prev->next = NULL; + } else + node->next->prev = node->prev; + node->prev = NULL; + node->next = movelist; + flashcache_check_record_io_latency(LAT_PENDING, &node->io_lat); + movelist = node; + moved++; + } + } + VERIFY_WARN(dmc->pending_jobs_count >= moved); + dmc->pending_jobs_count -= moved; + return movelist; +} + +#ifdef FLASHCACHE_DO_CHECKSUMS +int +flashcache_read_compute_checksum(struct cache_c *dmc, int index, void *block) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + struct io_region where; +#else + struct dm_io_region where; +#endif + int error; + u_int64_t sum = 0, *idx; + int cnt; + + where.bdev = get_cache_bdev(dmc); + where.sector = INDEX_TO_CACHE_ADDR(dmc, index); + where.count = dmc->block_size; + error = flashcache_dm_io_sync_vm(dmc, &where, COMP_DM_READ, block); + if (error) + return error; + cnt = dmc->block_size * 512; + idx = (u_int64_t *)block; + while (cnt > 0) { + sum += *idx++; + cnt -= sizeof(u_int64_t); + } + dmc->cache[index].checksum = sum; + return 0; +} + +u_int64_t +flashcache_compute_checksum(struct bio *bio) +{ + int i; + u_int64_t sum = 0, *idx; + int cnt; + int kmap_type; + void *kvaddr; + + if (in_interrupt()) + kmap_type = KM_SOFTIRQ0; + else + kmap_type = KM_USER0; + for (i = bio_bi_idx(bio) ; i < bio->bi_vcnt ; i++) { + kvaddr = kmap_atomic(bio->bi_io_vec[i].bv_page, kmap_type); + idx = (u_int64_t *) + ((char *)kvaddr + bio->bi_io_vec[i].bv_offset); + cnt = bio->bi_io_vec[i].bv_len; + while (cnt > 0) { + sum += *idx++; + cnt -= sizeof(u_int64_t); + } + kunmap_atomic(kvaddr, kmap_type); + } + return sum; +} + +void +flashcache_store_checksum(struct kcached_job *job) +{ + u_int64_t sum; + unsigned long flags; + + sum = flashcache_compute_checksum(job->bio); + spin_lock_irqsave(&job->dmc->cache_spin_lock, flags); + job->dmc->cache[job->index].checksum = sum; + spin_unlock_irqrestore(&job->dmc->cache_spin_lock, flags); +} + +int +flashcache_validate_checksum(struct kcached_job *job) +{ + u_int64_t sum; + int retval; + unsigned long flags; + + sum = flashcache_compute_checksum(job->bio); + spin_lock_irqsave(&job->dmc->cache_spin_lock, flags); + if (likely(job->dmc->cache[job->index].checksum == sum)) { + atomic64_inc(&job->dmc->flashcache_stats.checksum_valid); + retval = 0; + } else { + atomic64_inc(&job->dmc->flashcache_stats.checksum_invalid); + retval = 1; + } + spin_unlock_irqrestore(&job->dmc->cache_spin_lock, flags); + return retval; +} +#endif + +/* + * Functions to push and pop a job onto the head of a given job list. + */ +struct kcached_job * +pop(struct list_head *jobs) +{ + struct kcached_job *job = NULL; + unsigned long flags; + + spin_lock_irqsave(&_job_lock, flags); + if (!list_empty(jobs)) { + job = list_entry(jobs->next, struct kcached_job, list); + list_del(&job->list); + } + spin_unlock_irqrestore(&_job_lock, flags); + return job; +} + +void +push(struct list_head *jobs, struct kcached_job *job) +{ + unsigned long flags; + + spin_lock_irqsave(&_job_lock, flags); + list_add_tail(&job->list, jobs); + spin_unlock_irqrestore(&_job_lock, flags); +} + + +#ifdef MY_ABC_HERE +void process_free_job(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + + flashcache_free_cache_job(job); + + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } +} + +#endif + +static void +process_jobs(struct list_head *jobs, + void (*fn) (struct kcached_job *)) +{ + int done = 0; + struct kcached_job *job; + + while ((job = pop(jobs))) { + (void)fn(job); + + if (++done == PROCESS_JOB_RESCHED_BATCH) { + done = 0; + cond_resched(); + } + } +} + +void process_kcached_wq(struct work_struct *work) +{ + struct kcached_wq *kcwq = + container_of(work, struct kcached_wq, kwq_work); + + process_jobs(&kcwq->jobs, kcwq->fn); +} + +static void job_mem_mempool_get(struct cache_c *dmc) +{ + spin_lock_irq(&job_mem_lock); + + atomic64_inc(&dmc->flashcache_stats.job_mem_get_in); + wait_event_lock_irq(job_mem_wait_queue, job_mem_count < job_max_mem_count, job_mem_lock); + job_mem_count++; + atomic64_inc(&dmc->flashcache_stats.job_mem_get_out); + + spin_unlock_irq(&job_mem_lock); + + return; +} + +static inline void job_mem_mempool_put(void) +{ + spin_lock_irq(&job_mem_lock); + job_mem_count--; + spin_unlock_irq(&job_mem_lock); + + wake_up(&job_mem_wait_queue); +} + +#define JOB_MEM_GFP_FLAG (GFP_NOIO | __GFP_NORETRY) + +#ifdef MY_ABC_HERE +// 0 success, -1 error +static int +job_alloc_mem_vmalloc(struct cache_c *dmc, struct kcached_job *job) +{ + int ret = -1; + unsigned int noio_flags = memalloc_noio_save(); + + job->flag |= JOB_MEM_VMALLOC; + + job->mem_addr = vmalloc_wrapper(JOB_MEM_BYTE, JOB_MEM_GFP_FLAG | VMALLOC_INT_FLAG); + + memalloc_noio_restore(noio_flags); + + if (NULL == job->mem_addr) { + serr("vmalloc failed to allocate job memory"); + goto err; + } + + memset(job->mem_addr, 0, JOB_MEM_BYTE); + + ret = 0; +err: + return ret; +} +#endif + +// 0 success, -1 error +static int +job_alloc_mem_mempool(struct cache_c *dmc, struct kcached_job *job) +{ +#ifdef MY_ABC_HERE + job->flag |= JOB_MEM_MEMPOOL; +#endif + job_mem_mempool_get(dmc); + + job->mem_addr = mempool_alloc(_job_mem_pool, JOB_MEM_GFP_FLAG); + if (NULL == job->mem_addr) { + serr("memory allocation failed from mem pool"); + goto err; + } + + memset(job->mem_addr, 0, JOB_MEM_BYTE); + + return 0; +err: + job_mem_mempool_put(); + return -1; +} + +/* + * Return: + * -1 on error + */ +static int +job_alloc_mem_preread(struct cache_c *dmc, int index, struct kcached_job *job, + sector_t *sectors_to_read) +{ + int ret = -1; + unsigned long bytes = 0; + sector_t sectors_remaining = dmc->disk_devsize - dmc->cache[index].dbn; + + job->flag |= JOB_MEM_MEMPOOL; + + // IO might read the end of disks and can't fill the cacheblk + if (dmc->block_size > sectors_remaining) { + // round to 4k align + sectors_remaining = compatible_div(sectors_remaining, SECTOR_PER_BIT) * SECTOR_PER_BIT; + *sectors_to_read = sectors_remaining; + } else { + *sectors_to_read = dmc->block_size; + } + + bytes = to_bytes(*sectors_to_read); + + VERIFY_WARN((0 != bytes) && NULL == job->mem_addr); + + if (job_alloc_mem_mempool(dmc, job)) { + goto err; + } + + sdbg(DF_DETAIL, "job->mem_addr=%p bytes=%lu", job->mem_addr, bytes); + + job->mem_data_byte = bytes; + + ret = 0; +err: + return ret; +} + +/* + * plat and io_type are mutual exclusive. Given plat, we use plat->io_type. + */ +struct kcached_job * +new_kcached_job_common(struct cache_c *dmc, int index, job_param_t *param, + struct io_latency *plat, enum cache_io_type io_type, void *ctx) +{ + struct kcached_job *job; + struct bio* bio = NULL; + sector_t bio_offset = 0; + sector_t partial_offset = 0; + sector_t partial_size = 0; + sector_t cache_addr = 0; + param_type_t param_type = TYPE_UNKNOWN; + sector_t sectors_to_read = 0; + unsigned long start_jiffy = 0; + + VERIFY_WARN(dmc && param); + + partial_offset = param->partial_offset; + partial_size = param->partial_size; + cache_addr = INDEX_TO_CACHE_ADDR(dmc, index); + param_type = param->type; + + if ((TYPE_BIO_RANGE == param_type) || (TYPE_PREREAD_CACHEBLK == param_type)) { + if (NULL == param->bio) { + serr("bio should not be NULL!"); + VERIFY_WARN(0); + } + bio = param->bio; + } + + + job = flashcache_alloc_cache_job(); + if (unlikely(job == NULL)) { + atomic_inc(&dmc->flashcache_errors.memory_alloc_errors); + return NULL; + } + job->dmc = dmc; + job->index = index; + + /* + * WRITEDISK/ WRITEDISK_sync + * Both regions.cache and regions.disk are used in WRITE_DISK dirty_writeback() + * bio is NULL that time + * READCACHE/WRITECACHE/READFILL(=write to cache) + * Might just use disk or cache + * Uncached IO + * Index= -1 + */ + + switch (param_type) { + +#ifdef MY_ABC_HERE + case TYPE_SQF: + if (job_alloc_mem_vmalloc(dmc, job)) { + flashcache_free_cache_job(job); + return NULL; + } + break; + case TYPE_NQF: + if (job_alloc_mem_mempool(dmc, job)) { + flashcache_free_cache_job(job); + return NULL; + } + break; +#endif + + case TYPE_PREREAD_CACHEBLK: + if (job_alloc_mem_preread(dmc, index, job, §ors_to_read)) { + flashcache_free_cache_job(job); + return NULL; + } + break; + + case TYPE_BIO_RANGE: + case TYPE_NO_BIO: + case TYPE_MD_IO: + break; + + default: + serr("Unknown type=%d", param_type); + VERIFY_WARN(0); + break; + } + + job->job_io_regions.cache.bdev = get_cache_bdev(dmc); + // TODO: another type for uncached io? + if (index != -1) { + /* + * - index != -1: Not uncached I/O and Not MD IO + * - Also set job->action_bitmap here ... + * TODO: For uncached I/O, doesn't set the action bitmap + */ + switch (param_type) { + + case TYPE_BIO_RANGE: + // avoid type overflow + bio_offset = bio_bi_sector(bio) - dmc->cache[index].dbn; + job->job_io_regions.cache.sector = cache_addr + bio_offset; + job->job_io_regions.cache.count = to_sector(bio_bi_size(bio)); + job->action_bitmap = bitmap_get(&dmc->cache[index], bio); + break; + + case TYPE_NO_BIO: +#ifdef MY_ABC_HERE + case TYPE_SQF: + case TYPE_NQF: +#endif + // write disk and write disk sync + job->job_io_regions.cache.sector = cache_addr + partial_offset; + job->job_io_regions.cache.count = partial_size; + // io range should be as BITMAP_MASK + job->action_bitmap = BITMAP_MASK; + break; + + case TYPE_PREREAD_CACHEBLK: + job->job_io_regions.cache.sector = cache_addr; + job->job_io_regions.cache.count = sectors_to_read; + job->action_bitmap = bitmap_get_by_bytes(&dmc->cache[index], bio, job->mem_data_byte); + break; + + case TYPE_MD_IO: + serr("MD IO job idx should be -1"); + VERIFY_WARN(0); + break; + + default: + serr("Unknown type=%d", param_type); + VERIFY_WARN(0); + break; + } + } + job->error = 0; + job->bio = bio; + job->job_io_regions.disk.bdev = get_disk_bdev(dmc); + if (index != -1) { + // not uncached io and not MD IO + switch (param_type) { + + case TYPE_BIO_RANGE: + // CASE: read_miss() and read_disk_write_cache() + // in read_disk_write_cache(), its cacheblk.dbn is NOT THE SAME to bi_sector + job->job_io_regions.disk.sector = bio_bi_sector(bio); + job->job_io_regions.disk.count = to_sector(bio_bi_size(bio)); + break; + + case TYPE_NO_BIO: +#ifdef MY_ABC_HERE + case TYPE_SQF: + case TYPE_NQF: +#endif + // CASE: write disk and write disk sync + job->job_io_regions.disk.sector = dmc->cache[index].dbn + partial_offset; + job->job_io_regions.disk.count = partial_size; + break; + + case TYPE_PREREAD_CACHEBLK: + job->job_io_regions.disk.sector = dmc->cache[index].dbn; + job->job_io_regions.disk.count = sectors_to_read; + VERIFY_WARN((dmc->cache[index].dbn + sectors_to_read - 1) >= bio_last_sector(bio)); + break; + + case TYPE_MD_IO: + serr("MD IO job idx should be -1"); + VERIFY_WARN(0); + break; + + default: + serr("Unknown type=%d", param_type); + VERIFY_WARN(0); + break; + } + } else if (TYPE_MD_IO != param_type) { + // SYNO: for uncached IO + job->job_io_regions.disk.sector = bio_bi_sector(bio); + job->job_io_regions.disk.count = to_sector(bio_bi_size(bio)); + } + + start_jiffy = bio ? bio_get_start_jiffy(bio) : jiffies; + + job->next = NULL; + job->md_block = NULL; + if (dmc->sysctl_io_latency_hist) + job->io_start_time = ktime_get(); + else { + job->io_start_time = ktime_set(0, 0); + } + + if (plat) { + job->io_lat = *plat; + } else { + /* writeback ios (no bio) do not have preprocess stage */ + flashcache_init_io_latency(&job->io_lat, + dmc->sysctl_syno_latency_diagnose, io_type, start_jiffy, + bio != NULL); + } + + INIT_LIST_HEAD(&job->list); + job->ctx = ctx; + + return job; +} + +// Use bio range to access now +// plat and io_type are mutual exclusive. Given plat, we use plat->io_type. +struct kcached_job * +new_kcached_job(struct cache_c *dmc, struct bio* bio, int index, + struct io_latency *plat, enum cache_io_type io_type) +{ + job_param_t param = {0}; + + VERIFY_WARN(bio != NULL); + + param.type = TYPE_BIO_RANGE; + param.bio = bio; + + return new_kcached_job_common(dmc, index, ¶m, plat, io_type, NULL); +} + +// For cache block preread +struct kcached_job * +new_kcached_job_fill_cacheblk(struct cache_c *dmc, struct bio* bio, int index) +{ + + job_param_t param = {0}; + + param.type = TYPE_PREREAD_CACHEBLK; + param.bio = bio; + + return new_kcached_job_common(dmc, index, ¶m, NULL, TYPE_DISK, NULL); +} + + +#ifdef MY_ABC_HERE +#else +// For dirty_writeback* +struct kcached_job * +new_kcached_job_no_bio(struct cache_c *dmc, int index, sector_t offset, sector_t size) +{ + job_param_t param = {0}; + + param.type = TYPE_NO_BIO; + param.partial_offset = offset; + param.partial_size = size; + + return new_kcached_job_common(dmc, index, ¶m, NULL, TYPE_DISK, NULL); +} +#endif + +#ifdef MY_ABC_HERE +// For md update +struct kcached_job * +new_kcached_job_md_io(struct cache_c *dmc, mu_blk_t *mu_blk) +{ + job_param_t param = {0}; + + param.type = TYPE_MD_IO; + + return new_kcached_job_common(dmc, -1, ¶m, NULL, TYPE_SSD, (void*)mu_blk); +} +#endif + +#ifdef MY_ABC_HERE +// type should only be TYPE_NQF / TYPE_SQF +struct kcached_job * +new_kcached_job_qf(struct cache_c *dmc, int index, sector_t offset, sector_t size, param_type_t type) +{ + job_param_t param = {0}; + + VERIFY_WARN(type == TYPE_NQF || type == TYPE_SQF); + + param.type = type; + param.partial_offset = offset; + param.partial_size = size; + + // TODO: prefix for TYPE_DISK. LAT_TYPE_DISK? LAT_CAT_DISK? + return new_kcached_job_common(dmc, index, ¶m, NULL, TYPE_DISK, NULL); +} +#endif + +static void +flashcache_record_latency(struct cache_c *dmc, ktime_t start) +{ + ktime_t now = ktime_get(); + int64_t us; + + us = ktime_us_delta(now, start); +#ifdef EC_EMULATE_U64_DIVISION + us = div64_s64(us, IO_LATENCY_GRAN_USECS); +#else + us /= IO_LATENCY_GRAN_USECS; /* histogram 250us gran, scale 10ms total */ +#endif + if (us < IO_LATENCY_BUCKETS) + /* < 10ms latency, track it */ + dmc->latency_hist[us]++; + else + /* else count it in 10ms+ bucket */ + dmc->latency_hist_10ms++; +} +#ifdef MY_ABC_HERE +void +handle_master_io_finish(struct cache_c *dmc) +{ + atomic_dec(&dmc->num_master_io); + if ((0 == atomic_read(&dmc->num_master_io)) && + (CACHE_WAIT_OLD_IOS_COMPLETED == dmc->cache_state)) { + wake_up(&dmc->wait_old_ios_completed_queue); + } +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +void +flashcache_bio_endio_core(struct bio *bio, int error, struct cache_c *dmc, + ktime_t start_time, struct io_latency *plat) +{ +#ifdef MY_ABC_HERE + struct subbio_info *psubbio_info = bio->bi_private; + struct cache_bio *cache_bio = psubbio_info->pcache_bio; +#else + struct cache_bio *cache_bio = bio->bi_private; +#endif + unsigned long flags = 0; + int last_sub_bio = 0; + char bio_str[BIO_STR_MAX] = {0}; + + if (unlikely(dmc->sysctl_io_latency_hist && + 0 != ktime_compare(start_time, ktime_zero))) + flashcache_record_latency(dmc, start_time); + + // Only -EIO now + if (error && (0 == cache_bio->error)) { + cache_bio->error = error; + } + + spin_lock_irqsave(&dmc->endio_spin_lock, flags); + if (atomic_inc_return(&cache_bio->num_completed_bios) == cache_bio->num_total_bios) { + last_sub_bio = 1; + } + spin_unlock_irqrestore(&dmc->endio_spin_lock, flags); + + if (plat) { + flashcache_check_process_io_latency(dmc, plat, LAT_END_BIO); + } + + if (last_sub_bio) { + sdbg(DF_DETAIL, "End master_bio=%s error=%d", bio_to_str(cache_bio->master_bio, bio_str, sizeof(bio_str)), cache_bio->error); + bio_endio_wrapper(cache_bio->master_bio, cache_bio->error); + handle_master_io_finish(dmc); + mempool_free(cache_bio, _cache_bio_pool); + } else { + // Still has sub bios, just record error + sdbg(DF_DETAIL, "bio=%p error=%d, don't end master_bio=%p", bio, cache_bio->error, cache_bio->master_bio); + } +#ifdef MY_ABC_HERE + // Shouled remove it + kfree(psubbio_info); +#endif + // Free data in sub bio + bio_put(bio); +} + +#else /* NOT MY_DEF_HERE */ + +void +flashcache_bio_endio_core(struct bio *bio, int error, struct cache_c *dmc, + ktime_t start_time, struct io_latency *plat) +{ + struct cache_bi_private *cache_bi_private = (struct cache_bi_private *)bio->bi_private; + + if (unlikely(dmc->sysctl_io_latency_hist && + 0 != ktime_compare(start_time, ktime_zero))) + flashcache_record_latency(dmc, start_time); + + if (plat) { + flashcache_check_process_io_latency(dmc, plat, LAT_END_BIO); + } + + bio->bi_private = cache_bi_private->master_bio_private; + mempool_free(cache_bi_private, _cache_bi_private_pool); + bio_endio_wrapper(bio, error); + handle_master_io_finish(dmc); +} + +#endif /* MY_DEF_HERE */ + +void +flashcache_bio_endio(struct bio *bio, int error, + struct cache_c *dmc, ktime_t start_time, + struct io_latency *plat) +{ +#ifdef CONFIG_SYNO_DATA_CORRECTION +#ifdef MY_DEF_HERE +#ifdef MY_ABC_HERE + struct subbio_info *psubbio_info = bio->bi_private; + struct cache_bio *cache_bio = psubbio_info->pcache_bio; +#else + struct cache_bio *cache_bio = bio->bi_private; +#endif +#endif + int wait_abort_bio = 0; + + if (bio->bi_flags & (1 << BIO_CORRECTION_ERR)) { +#ifdef MY_DEF_HERE + cache_bio->master_bio->bi_flags |= 1 << BIO_CORRECTION_ERR; +#endif + sdbg(DF_CORRECTION, "Finish IO: set cache master bio's BIO_CORRECTION_ERR" + "flags finish, bio_sector=%llu", (u64)bio_bi_sector(bio)); + } else if (bio->bi_flags & (1 << BIO_CORRECTION_ABORT)) { + sdbg(DF_CORRECTION, "Finish IO: correction abort flag to =%llu", (u64)bio_bi_sector(bio)); + wait_abort_bio = correction_handle_abort_io_finish(dmc, bio, error, start_time, plat); + } + if (likely(!wait_abort_bio)) { + flashcache_bio_endio_core(bio, error, dmc, start_time, plat); + } +#else + flashcache_bio_endio_core(bio, error, dmc, start_time, plat); +#endif /* CONFIG_SYNO_DATA_CORRECTION */ +} + +#ifdef MY_ABC_HERE +static void +remove_cacheblk_from_lru_list(struct cache_c *dmc, int set, int start_index, struct cacheblock *cacheblk) +{ + VERIFY_WARN(dmc && cacheblk); + + /* Remove from LRU */ + if (likely((cacheblk->lru_prev != FLASHCACHE_LRU_NULL) || + (cacheblk->lru_next != FLASHCACHE_LRU_NULL))) { + // This node is in the LRU list + + if (cacheblk->lru_prev != FLASHCACHE_LRU_NULL) + // Has an previous Node, No need to change head + dmc->cache[cacheblk->lru_prev + start_index].lru_next = + cacheblk->lru_next; + else + // This is the head node + dmc->cache_sets[set].lru_head = cacheblk->lru_next; + if (cacheblk->lru_next != FLASHCACHE_LRU_NULL) + // Has an next node, No need to change tail + dmc->cache[cacheblk->lru_next + start_index].lru_prev = + cacheblk->lru_prev; + else + // The last node + dmc->cache_sets[set].lru_tail = cacheblk->lru_prev; + } +} + +#endif +void +flashcache_reclaim_lru_movetail(struct cache_c *dmc, int index) +{ + int set = index / dmc->assoc; + int start_index = set * dmc->assoc; + int my_index = index - start_index; + struct cacheblock *cacheblk = &dmc->cache[index]; + +#ifdef MY_ABC_HERE + remove_cacheblk_from_lru_list(dmc, set, start_index, cacheblk); +#else + /* Remove from LRU */ + if (likely((cacheblk->lru_prev != FLASHCACHE_LRU_NULL) || + (cacheblk->lru_next != FLASHCACHE_LRU_NULL))) { + if (cacheblk->lru_prev != FLASHCACHE_LRU_NULL) + dmc->cache[cacheblk->lru_prev + start_index].lru_next = + cacheblk->lru_next; + else + dmc->cache_sets[set].lru_head = cacheblk->lru_next; + if (cacheblk->lru_next != FLASHCACHE_LRU_NULL) + dmc->cache[cacheblk->lru_next + start_index].lru_prev = + cacheblk->lru_prev; + else + dmc->cache_sets[set].lru_tail = cacheblk->lru_prev; + } +#endif + /* And add it to LRU Tail */ + cacheblk->lru_next = FLASHCACHE_LRU_NULL; + cacheblk->lru_prev = dmc->cache_sets[set].lru_tail; + if (dmc->cache_sets[set].lru_tail == FLASHCACHE_LRU_NULL) + dmc->cache_sets[set].lru_head = my_index; + else + dmc->cache[dmc->cache_sets[set].lru_tail + start_index].lru_next = + my_index; + dmc->cache_sets[set].lru_tail = my_index; +} + +#ifdef MY_ABC_HERE +#else +static int +cmp_dbn(const void *a, const void *b) +{ + if (((struct dbn_index_pair *)a)->dbn < ((struct dbn_index_pair *)b)->dbn) + return -1; + else + return 1; +} + +static void +swap_dbn_index_pair(void *a, void *b, int size) +{ + struct dbn_index_pair temp; + + temp = *(struct dbn_index_pair *)a; + *(struct dbn_index_pair *)a = *(struct dbn_index_pair *)b; + *(struct dbn_index_pair *)b = temp; +} + +void +flashcache_sort_writes(struct dbn_index_pair *writes_list, int nr_writes, int set) +{ + if (unlikely(nr_writes == 0)) + return; + + // But due to max_clean_ios_set limitation, most of time it only has one write + sort(writes_list, nr_writes, sizeof(struct dbn_index_pair), + cmp_dbn, swap_dbn_index_pair); +} + +/* + * We have a list of blocks to write out to disk. + * 1) Sort the blocks by dbn. + * 2) (sysctl'able) See if there are any other blocks in the same set + * that are contig to any of the blocks in step 1. If so, include them + * in our "to write" set, maintaining sorted order. + * Has to be called under the cache spinlock ! + */ +void +flashcache_merge_writes(struct cache_c *dmc, struct dbn_index_pair *writes_list, + int *nr_writes, int set) +{ + int start_index = set * dmc->assoc; + int end_index = start_index + dmc->assoc; + int old_writes = *nr_writes; + int new_inserts = 0; + struct dbn_index_pair *set_dirty_list = NULL; + int ix, nr_set_dirty; + struct cacheblock *cacheblk; + + if (unlikely(*nr_writes == 0)) + return; + sort(writes_list, *nr_writes, sizeof(struct dbn_index_pair), + cmp_dbn, swap_dbn_index_pair); + + set_dirty_list = kmalloc(dmc->assoc * sizeof(struct dbn_index_pair), GFP_ATOMIC); + if (set_dirty_list == NULL) { + atomic_inc(&dmc->flashcache_errors.memory_alloc_errors); +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate atomic memory for merge write"); + } +#endif + goto out; + } + nr_set_dirty = 0; + // SYNO: find the dirty block in this set, add to set_dirty_list + for (ix = start_index ; ix < end_index ; ix++) { + cacheblk = &dmc->cache[ix]; + /* + * Any DIRTY block in "writes_list" will be marked as + * DISKWRITEINPROG already, so we'll skip over those here. + */ + if ((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { + set_dirty_list[nr_set_dirty].dbn = cacheblk->dbn; + set_dirty_list[nr_set_dirty].index = ix; + nr_set_dirty++; + } + } + if (nr_set_dirty == 0) + goto out; + sort(set_dirty_list, nr_set_dirty, sizeof(struct dbn_index_pair), + cmp_dbn, swap_dbn_index_pair); + // SYNO: check each dirty block in the set_dirty_list, if they can be merge to existed write_list... + for (ix = 0 ; ix < nr_set_dirty ; ix++) { + int back_merge, k; + int i; + + cacheblk = &dmc->cache[set_dirty_list[ix].index]; + back_merge = -1; + VERIFY_WARN((cacheblk->cache_state & (DIRTY | BLOCK_IO_INPROG)) == DIRTY); + for (i = 0 ; i < *nr_writes ; i++) { + int insert; + int j = 0; + + insert = 0; + if (cacheblk->dbn + dmc->block_size == writes_list[i].dbn) { + /* cacheblk to be inserted above i */ + insert = 1; + j = i; + back_merge = j; + } + if (cacheblk->dbn - dmc->block_size == writes_list[i].dbn ) { + /* cacheblk to be inserted after i */ + insert = 1; + j = i + 1; + } + VERIFY_WARN(j < dmc->assoc); + if (insert) { + set_wb_attrs(dmc, set_dirty_list[ix].index, 1); + /* + * Shift down everthing from j to ((*nr_writes) - 1) to + * make room for the new entry. And add the new entry. + */ + for (k = (*nr_writes) - 1 ; k >= j ; k--) + writes_list[k + 1] = writes_list[k]; + writes_list[j].dbn = cacheblk->dbn; + writes_list[j].index = cacheblk - &dmc->cache[0]; + (*nr_writes)++; + VERIFY_WARN(*nr_writes <= dmc->assoc); + new_inserts++; + if (back_merge == -1) + atomic64_inc(&dmc->flashcache_stats.front_merge); + else + atomic64_inc(&dmc->flashcache_stats.back_merge); + VERIFY_WARN(*nr_writes <= dmc->assoc); + break; + } + } + /* + * If we did a back merge, we need to walk back in the set's dirty list + * to see if we can pick off any more contig blocks. Forward merges don't + * need this special treatment since we are walking the 2 lists in that + * direction. It would be nice to roll this logic into the above. + */ + if (back_merge != -1) { + for (k = ix - 1 ; k >= 0 ; k--) { + int n; + + if (set_dirty_list[k].dbn + dmc->block_size != + writes_list[back_merge].dbn) + break; + set_wb_attrs(dmc, set_dirty_list[k].index, 1); + for (n = (*nr_writes) - 1 ; n >= back_merge ; n--) + writes_list[n + 1] = writes_list[n]; + writes_list[back_merge].dbn = set_dirty_list[k].dbn; + writes_list[back_merge].index = set_dirty_list[k].index; + (*nr_writes)++; + VERIFY_WARN(*nr_writes <= dmc->assoc); + new_inserts++; + atomic64_inc(&dmc->flashcache_stats.back_merge); + VERIFY_WARN(*nr_writes <= dmc->assoc); + } + } + } + VERIFY_WARN((*nr_writes) == (old_writes + new_inserts)); +out: + if (set_dirty_list) + kfree(set_dirty_list); +} + +#endif /* not MY_ABC_HERE */ + +extern struct dm_io_client *flashcache_io_client; /* Client memory pool*/ + +int +flashcache_dm_io_sync_vm(struct cache_c *dmc, struct dm_io_region *where, int comp_dm_op, void *data) +{ + unsigned long error_bits = 0; + int ret = 0; + struct dm_io_request iorq = {0}; + + set_bi_op_and_flags(&iorq, comp_dm_op); + + iorq.mem.type = DM_IO_VMA, + iorq.mem.ptr.vma = data, + iorq.mem.offset = 0, + iorq.notify.fn = NULL, + iorq.client = flashcache_io_client, + + +#ifdef CONFIG_SYNO_DATA_CORRECTION + /* + * Although this function won't get correcting IO, + * use same dm IO function as others for consistency + */ + ret = syno_dm_io(&iorq, 1, where, &error_bits, 0); +#else + ret = dm_io(&iorq, 1, where, &error_bits); +#endif + + if (ret) { + goto err; + } + if (error_bits) { + ret = error_bits; + goto err; + } +err: + return ret; +} + +void +flashcache_update_sync_progress(struct cache_c *dmc) +{ + u_int64_t dirty_pct; +#ifdef MY_ABC_HERE + static u_int64_t last_dirty_pct = -1; +#endif + + if (compatible_mod(atomic64_read(&dmc->flashcache_stats.cleanings), 1000)) + return; +#ifdef MY_ABC_HERE + if (!dmc->nr_dirty || !dmc->size) + return; +#else + if (!dmc->nr_dirty || !dmc->size || !printk_ratelimit()) + return; +#endif + +#ifdef EC_EMULATE_U64_DIVISION + dirty_pct = div64_u64((u_int64_t)dmc->nr_dirty * 100, dmc->size); +#else + dirty_pct = ((u_int64_t)dmc->nr_dirty * 100) / dmc->size; +#endif + +#ifdef MY_ABC_HERE + if (last_dirty_pct == dirty_pct) { + return; + } else { + last_dirty_pct = dirty_pct; + } +#endif + printk(KERN_INFO "Flashcache: Cleaning %d Dirty blocks, Dirty Blocks pct %llu%%", + dmc->nr_dirty, dirty_pct); + printk(KERN_INFO "\r"); +} + +static inline unsigned int latency_level_to_ms(unsigned char level) +{ + if (200 > level) { + return level * 5; + } else if (219 > level) { + return (level - 199) * 1000; + } else if (246 > level) { + return (level - 219) * 4000 + 20000; + } else { + return 128000; + } +} + +static inline unsigned char jiffy_to_latency_level(unsigned long jiffy) +{ + // XXX: change to assembly if we have performance issue? + unsigned int ms = jiffies_to_msecs(jiffy); + + if (1000 > ms) { + // 0 - 199 + return ms / 5; + } else if (20000 > ms) { + // 200 - 218 + return ms / 1000 + 199; // (ms - 1000) / 1000 + 200 + } else if (128000 > ms) { + // 219 - 245 + return ms / 4000 + 214; // (ms - 20000) / 4000 + 219 + } else { + return 246; + } +} + +void +flashcache_record_io_latency(enum latency_step step, struct io_latency *plat) +{ + int i = 0; + unsigned long jiffy = jiffies; + + if (likely(plat->entry_cnt < LAT_TYPE_NUM)) { + plat->entries[plat->entry_cnt].step = step; + plat->entries[plat->entry_cnt].level = + jiffy_to_latency_level(jiffy - plat->last_jiffy); + plat->entry_cnt++; + plat->last_jiffy = jiffy; + } else { + if (printk_ratelimit()) { + serr("IO steps exceeds %d, step: %d", LAT_TYPE_NUM, step); + for (i = 0; i < LAT_TYPE_NUM; ++i) { + serr("step: %d level: %d", plat->entries[i].step, + plat->entries[i].level); + } + } + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +void flashcache_process_lat_stats(struct timer_list *timer) +#else +void flashcache_process_lat_stats(unsigned long data) +#endif +{ + int i = 0, len = 0; + int j = 0; + int type_idx = 0; + unsigned int event_cnt = 0; + unsigned int event_percentile = 0; + unsigned int tmp = 0; + unsigned long lat_sum = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + struct cache_c *dmc = from_timer(dmc, timer, latency_timer); +#else + struct timer_list *timer = (struct timer_list *)data; + struct cache_c *dmc = container_of(timer, struct cache_c, latency_timer); +#endif + struct io_latency_stats *stats_all = NULL; + struct io_latency_stats *stats_per_type = NULL; + unsigned long itvl_jiffy = msecs_to_jiffies(dmc->sysctl_latency_diagnose_itvl_ms); + char output[768] = {0}; + unsigned long flags = 0; + + spin_lock_irqsave(&dmc->lat_spin_lock, flags); + + stats_all = dmc->last_itvl_lat_stats[dmc->lat_stats_idx]; + dmc->lat_stats_idx = ALT_LAT_STATS_IDX(dmc); + + spin_unlock_irqrestore(&dmc->lat_spin_lock, flags); + + for (type_idx = 0, stats_per_type = stats_all; + type_idx < CACHE_IO_TYPE_NUM; + ++type_idx, ++stats_per_type) { + + if (stats_per_type->highest_lat_jiffy < dmc->lat_thresholds_jiffies[type_idx]) { + continue; + } + + for (i = 0; i < stats_per_type->highest_entry_cnt; ++i) { + len += snprintf((char *)output + len, sizeof(output) - len, "%u:%u ", + stats_per_type->highest_lat_entry[i].step, + latency_level_to_ms(stats_per_type->highest_lat_entry[i].level)); + } + + len += snprintf((char *)output + len, sizeof(output) - len, "stats: "); + + for (i = 0; i < LAT_TYPE_NUM; ++i) { + tmp = 0; + event_cnt = 0; + lat_sum = 0; + + for (j = 0; j < LAT_LEVEL_NUM; ++j) { + event_cnt += stats_per_type->lat_table[i][j]; + lat_sum += latency_level_to_ms(j) * stats_per_type->lat_table[i][j]; + } + if (0 == event_cnt) { + continue; + } + + event_percentile = (event_cnt * dmc->sysctl_lat_perc_ten_thousandth) / 10000; + for (j = 0; j < LAT_LEVEL_NUM; ++j) { + tmp += stats_per_type->lat_table[i][j]; + if (tmp >= event_percentile) { + break; + } + } + + len += snprintf((char *)output + len, sizeof(output) - len, "%d:%lu:%u ", + i, lat_sum / event_cnt, latency_level_to_ms(j)); + } + + /* If change format need to change syslog filter as well */ + sprint("[LAT_DIAGNOSE_TAG] %d over_thres: %u Lat: %u ms %s", + type_idx, stats_per_type->over_thres_cnt, + jiffies_to_msecs(stats_per_type->highest_lat_jiffy), output); + memset(output, 0, sizeof(output)); + len = 0; + } + + memset(stats_all, 0, sizeof(dmc->last_itvl_lat_stats[0])); + + timer->expires = jiffies + itvl_jiffy; + add_timer(timer); + return; +} + +void flashcache_process_io_latency(struct cache_c *dmc, struct io_latency *plat, enum latency_step step) +{ + int i = 0; + unsigned long lat_jiffies = 0; + unsigned long flags = 0; + struct io_latency_stats *stats = NULL; + + spin_lock_irqsave(&dmc->lat_spin_lock, flags); + + /* Record last latency in the lock to include the time of waiting */ + flashcache_record_io_latency(step, plat); + + lat_jiffies = plat->last_jiffy - plat->start_jiffy; + + stats = &dmc->last_itvl_lat_stats[dmc->lat_stats_idx][plat->io_type]; + + if (lat_jiffies >= dmc->lat_thresholds_jiffies[plat->io_type]) { + stats->over_thres_cnt++; + } + + if (lat_jiffies > stats->highest_lat_jiffy) { + stats->highest_lat_jiffy = lat_jiffies; + stats->highest_entry_cnt = plat->entry_cnt; + memcpy(stats->highest_lat_entry, plat->entries, sizeof(plat->entries)); + } + + for (i = 0; i < plat->entry_cnt; ++i) { + stats->lat_table[plat->entries[i].step][plat->entries[i].level]++; + } + + spin_unlock_irqrestore(&dmc->lat_spin_lock, flags); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +int +flashcache_alloc_md_bio(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + struct bio_vec *bvec = NULL; + int ret = -1; + struct page *page = NULL; + unsigned long addr = 0; + int page_allocated = 0; + + if (likely((dmc->sysctl_error_inject & MD_ALLOC_SECTOR_ERROR) == 0)) { + // Only 1 bvec + job->md_bio = bio_alloc_bioset(GFP_NOIO, 1, pcache_bio_set); + + } else + dmc->sysctl_error_inject &= ~MD_ALLOC_SECTOR_ERROR; + + // Check if md_bio is allocated + if (unlikely(job->md_bio == NULL)) { + atomic_inc(&job->dmc->flashcache_errors.memory_alloc_errors); +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate md bio"); + } +#endif + ret = -ENOMEM; + goto err; + } + + /* + * NOTE: Original flashcache driver allows bvec to point to pages (instead of a page) + * However, it conflicts with bvec's propery (should point to a single page) + * So it will be checked here + */ + VERIFY_WARN(MD_BLOCK_BYTES(job->dmc) <= PAGE_SIZE); + + addr = __get_free_pages(GFP_NOIO, get_order(MD_BLOCK_BYTES(job->dmc))); + if (addr) + // Convert logical address to page + page = virt_to_page(addr); + + if (unlikely(page == NULL)) { + ret = -ENOMEM; +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate pag"); + } +#endif + goto err; + } + + /* + * Refere to md_super_write() + * For normal bios in block-core, those pages would be freed by kernel's bio_end_io() + * However, this bio is created by ourselves to pass to dm_io function. So its page should be + * freed in flashacache_md_bio() + */ + if (MD_BLOCK_BYTES(job->dmc) != bio_add_page(job->md_bio, page, MD_BLOCK_BYTES(job->dmc), 0)) { + serr("Add page to bio failed"); + goto err; + } + page_allocated = 1; + + bvec = __bvec_iter_bvec(job->md_bio->bi_io_vec, job->md_bio->bi_iter); + if (NULL == bvec) { + serr("Get null bvec"); + goto err; + } + + // Page to virtual address + job->md_block = (struct flash_cacheblock *)page_address(bvec->bv_page); + + ret = 0; +err: + if (ret) { + if (page_allocated) { + bio_free_pages(job->md_bio); + } else if (addr) { + free_pages(addr, get_order(MD_BLOCK_BYTES(job->dmc))); + } + if (job->md_bio) { + bio_put(job->md_bio); + } + } + + return ret; +} +#else +int +flashcache_alloc_md_sector(struct kcached_job *job) +{ + struct page *page = NULL; + struct cache_c *dmc = job->dmc; + + if (likely((dmc->sysctl_error_inject & MD_ALLOC_SECTOR_ERROR) == 0)) { + unsigned long addr; + + /* Get physically consecutive pages */ + // SYNO: NOIO won't get memory from high memory + addr = __get_free_pages(GFP_NOIO, get_order(MD_BLOCK_BYTES(job->dmc))); + if (addr) + page = virt_to_page(addr); + } else + dmc->sysctl_error_inject &= ~MD_ALLOC_SECTOR_ERROR; + job->md_io_bvec.bv_page = page; + if (unlikely(page == NULL)) { + atomic_inc(&job->dmc->flashcache_errors.memory_alloc_errors); +#ifdef MY_ABC_HERE + if (printk_ratelimit()) { + serr("Failed to allocate md sectors"); + } +#endif + return -ENOMEM; + } + job->md_io_bvec.bv_len = MD_BLOCK_BYTES(job->dmc); + job->md_io_bvec.bv_offset = 0; + job->md_block = (struct flash_cacheblock *)page_address(page); + return 0; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +void +flashcache_free_md_bio(struct kcached_job *job) +{ + if (job->md_bio != NULL) { + bio_free_pages(job->md_bio); + bio_put(job->md_bio); + } +} +#else +void +flashcache_free_md_sector(struct kcached_job *job) +{ + if (job->md_io_bvec.bv_page != NULL) + __free_pages(job->md_io_bvec.bv_page, get_order(MD_BLOCK_BYTES(job->dmc))); +} +#endif diff --git a/drivers/syno/syno-mem-saving-driver/ocf/Makefile b/drivers/syno/syno-mem-saving-driver/ocf/Makefile new file mode 100644 index 000000000000..7b67377f27a3 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/ocf/Makefile @@ -0,0 +1,15 @@ +COMMIT_REV ?= $(shell git describe --always --abbrev=12) +CFLAGS += +PROGRAMS += flashcache +INSTALL_DIR = /usr/lib/ocf/resource.d/flashcache + +.PHONY:all +all: $(PROGRAMS) + +.PHONY: install +install: $(PROGRAMS) + install -d -m 755 $(INSTALL_DIR) + install -m 755 $(PROGRAMS) $(INSTALL_DIR) + +.PHONY: clean +clean: diff --git a/drivers/syno/syno-mem-saving-driver/ocf/flashcache b/drivers/syno/syno-mem-saving-driver/ocf/flashcache new file mode 100755 index 000000000000..6855eeaf9d12 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/ocf/flashcache @@ -0,0 +1,265 @@ +#!/bin/sh +# +# License: GNU General Public License (GPL) +# +# Resource Agent for highly available flashcache devices. +# Requires installed flashcache kernel module and utilities. +# +# (c) 2011 Florian Haas + +# Initialization: +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat} +. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs + +# Defaults +OCF_RESKEY_name_default="flashcache" +: ${OCF_RESKEY_name=${OCF_RESKEY_name_default}} + +flashcache_usage() { + echo "usage: $0 {start|stop|status|monitor|meta-data|validate-all}" +} + +flashcache_meta_data() { + cat < + + + 0.1 + +This resource agent manages a flashcache device, loading any existing +cache from the flash device on startup and flushing the cache to the +disk on graceful shutdown. + + Manages a flashcache device map + + + + The name of the flashcache device. This is the device map name + that the agent instructs device-mapper to create, and must hence + follow device-mapper naming restrictions. + + Flashcache device name + + + + + The backing device to be used by flashcache. This is typically a + comparatively high-latency but high-capacity block device, such + as a rotational disk. + + Backing device (typically a rotational + disk) + + + + + The cache device to be used by flashcache. This is typically a + low-latency but limited-capacity block device, such + as a solid-state disk. + + Cache device (typically a solid state disk) + + + + + + + + + + + + +EOF +} + +flashcache_start() { + # exit immediately if configuration is not valid + flashcache_validate_all || exit $? + + # if resource is already running, bail out early + if flashcache_monitor; then + ocf_log info "Resource is already running" + return $OCF_SUCCESS + fi + + # If the file exists here, but flashcache_monitor has determined + # the resource isn't already running, then the file probably is + # owned by something else. Bail out to avoid breaking things. + if [ -e /dev/mapper/${OCF_RESKEY_name} ]; then + ocf_log err "Existing file /dev/mapper/${OCF_RESKEY_name} would be overwritten by ${OCF_RESOURCE_INSTANCE}. Bailing out." + exit $OCF_ERR_INSTALLED + fi + + if [ ! -e /proc/flashcache_version ]; then + ocf_log debug "Flashcache support not loaded, loading module" + ocf_run modprobe -v flashcache || exit $OCF_ERR_INSTALLED + fi + + ocf_log debug "Flashcache module information obtained from kernel: `cat /proc/flashcache_version`" + + # actually start up the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + ocf_run flashcache_load ${OCF_RESKEY_name} \ + ${OCF_RESKEY_cache_device} \ + ${OCF_RESKEY_device} || exit $OCF_ERR_GENERIC + + # After the resource has been started, check whether it started up + # correctly. If the resource starts asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # start up within the defined timeout, the cluster manager will + # consider the start action failed + while ! flashcache_monitor; do + ocf_log debug "Resource has not started yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS +} + +flashcache_stop() { + local rc + + # exit immediately if configuration is not valid + flashcache_validate_all || exit $? + + flashcache_monitor + rc=$? + case "$rc" in + "$OCF_SUCCESS") + # Currently running. Normal, expected behavior. + ocf_log debug "Resource is currently running" + ;; + "$OCF_NOT_RUNNING") + # Currently not running. Nothing to do. + ocf_log info "Resource is already stopped" + return $OCF_SUCCESS + ;; + esac + + # actually shut down the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + ocf_run dmsetup remove ${OCF_RESKEY_name} || exit $OCF_ERR_GENERIC + + # After the resource has been stopped, check whether it shut down + # correctly. If the resource stops asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # shut down within the defined timeout, the cluster manager will + # consider the stop action failed + while flashcache_monitor; do + ocf_log debug "Resource has not stopped yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS + +} + +flashcache_monitor() { + local rc + local blockdev + local device_present + local map_present + + # exit immediately if configuration is not valid + flashcache_validate_all || exit $? + + # First, see if a block device exists in /dev/mapper + blockdev=/dev/mapper/${OCF_RESKEY_name} + if [ -e ${blockdev} ]; then + if [ -b ${blockdev} ]; then + case "`stat -L -c "%t" ${blockdev}`" in + "fc"|"fd") + ocf_log debug "Block device ${blockdev} exists and is a device-mapper device" + ;; + *) + ocf_log warn "Existing block device ${blockdev} is not a device-mapper device!" + return $OCF_NOT_RUNNING + esac + else + ocf_log warn "File ${blockdev} exists, but is not a block device!" + fi + fi + + # OK, we have a block device and it has the correct major + # number. Now, check if there is an entry in the DM table for the + # device. + dmsetup ls | grep -Eq "^${OCF_RESKEY_name}[[:space:]]+" + if [ $? -eq 0 ]; then + ocf_log debug "Device map \"${OCF_RESKEY_name}\" is present" + # So we have a block device, and we have a device mapper table + # entry. Good enough for now. + # + # TODO: For an added paranoia check, test whether the minor + # number in the table matches the one stat() returns on the + # device. + return $OCF_SUCCESS + fi + + return $OCF_NOT_RUNNING +} + +flashcache_validate_all() { + # Check required parameters + if [ -z "${OCF_RESKEY_device}" ]; then + ocf_log err "Required parameter \"device\" not configured!" + exit $OCF_ERR_CONFIGURED + fi + if [ -z "${OCF_RESKEY_cache_device}" ]; then + ocf_log err "Required parameter \"cache_device\" not configured!" + exit $OCF_ERR_CONFIGURED + fi + + # Test for required binaries + check_binary flashcache_load + check_binary dmsetup + check_binary stat + check_binary grep + + if ! ocf_is_probe; then + for dev in ${OCF_RESKEY_device} ${OCF_RESKEY_cache_device}; do + if [ ! -b ${dev} ]; then + ocf_log err "${dev} does not exist or is not a block device!" + exit $OCF_ERR_INSTALLED + fi + done + fi + + return $OCF_SUCCESS +} + +# Make sure meta-data and usage always succeed +case $__OCF_ACTION in +meta-data) flashcache_meta_data + exit $OCF_SUCCESS + ;; +usage|help) flashcache_usage + exit $OCF_SUCCESS + ;; +esac + +# Anything other than meta-data and usage must pass validation +flashcache_validate_all || exit $? + +# Translate each action into the appropriate function call +case $__OCF_ACTION in +start) flashcache_start;; +stop) flashcache_stop;; +status|monitor) flashcache_monitor;; +reload) ocf_log info "Reloading..." + flashcache_start + ;; +validate-all) ;; +*) flashcache_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac +rc=$? + +ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc" +exit $rc diff --git a/drivers/syno/syno-mem-saving-driver/syno_common_4k_driver.h b/drivers/syno/syno-mem-saving-driver/syno_common_4k_driver.h new file mode 100644 index 000000000000..265cc29119d0 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_common_4k_driver.h @@ -0,0 +1,79 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Data shared with original driver and tools + */ + +#ifndef __SYNO_FLASHCACHE_COMMON_4K_DRIVER_H__ +#define __SYNO_FLASHCACHE_COMMON_4K_DRIVER_H__ + +// Share proc and sysctl entries with original driver +extern int syno_flashcache_proc_count; +extern struct semaphore syno_flashcache_proc_mutex; + +/* + * Print Functions + */ +// For old 4k driver, this global variable can only change in compiling time +extern long debug_flags; +// Error: must prink + +#ifdef MY_ABC_HERE +#define TITLE "flashcache_syno: " +#else +#define TITLE "flashcache: " +#endif +#define serr(fmt, args...) printk(KERN_ERR TITLE"%s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); +#define sprint(fmt, args...) printk(KERN_ERR TITLE fmt"\n", ##args); + +typedef enum _DEBUG_FLAG { + DF_CORRECTION = 1 << 0, + DF_RELOAD_TABLE = 1 << 1, /* reload table */ + DF_ONLINE = 1 << 2, /* online managment */ + DF_MERGE = 1 << 3, /* support merge function */ + DF_PIN = 1 << 4, /* pin file */ + DF_JOB = 1 << 5, /* debug job */ + DF_LOC = 1 << 6, /* location for data verifier */ + DF_JOB_POOL_INIT = 1 << 7, /* simulate job pool initilize slow */ + DF_QUICKFLUSH = 1 << 8, /* quick flush */ + DF_WORKQUEUE = 1 << 9, /* workqueue */ + DF_FLUSH_BIO = 1 << 10, /* print flush bio infomation */ + DF_NEW_MU = 1 << 11, /* new metadata update */ + DF_FUA = 1 << 12, /* fua */ + DF_DMCG = 1 << 13, /* dmcg */ + DF_DETAIL = 1 << 31, /* WARNING: print hung IO information, don't set it in user's device */ +} DEBUG_FLAG; +#ifdef MY_ABC_HERE + +#define sdbg_limit(flags, fmt, args...) do { \ + if ((flags & debug_flags) && printk_ratelimit()) { \ + printk(KERN_ERR TITLE"%s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); \ + } \ + } while (0) + +#define sdbg(flags, fmt, args...) do { \ + if (flags & debug_flags) { \ + printk(KERN_ERR TITLE"%s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); \ + } \ + } while (0) + +#define sdbg_in(flags, fmt, args...) do { \ + if (flags & debug_flags) { \ + printk(KERN_ERR TITLE"++++ %s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); \ + } \ + } while (0) + +#define sdbg_out(flags, fmt, args...) do { \ + if (flags & debug_flags) { \ + printk(KERN_ERR TITLE"---- %s [%d]: "fmt"\n", __FUNCTION__, __LINE__, ##args); \ + } \ +} while (0) + +#else +#define sdbgl(flags, fmt, args...) +#define sdbg(flags, fmt, args...) +#define sdbg_in(flags, fmt, args...) +#define sdbg_out(flags, fmt, args...) +#endif +#endif diff --git a/drivers/syno/syno-mem-saving-driver/syno_common_tool.h b/drivers/syno/syno-mem-saving-driver/syno_common_tool.h new file mode 100644 index 000000000000..8b19499bded8 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_common_tool.h @@ -0,0 +1,237 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Data shared with original driver and tools + */ + +#ifndef __SYNO_FLASHCACHE_COMMON_TOOL_H__ +#define __SYNO_FLASHCACHE_COMMON_TOOL_H__ + +#ifdef __KERNEL__ +#else +/* + * Make user space able to detect kernel config + */ +// Macro similar to kernel +#define IS_ENABLED(option) \ + (defined(option) || defined(option##_MODULE)) +#include +#endif + +#include "syno_feature_defines.h" + +#define DEV_PATHLEN 128 + + +#define SZ_LOAD_ERROR_CHECK "error-check" +// Share to userspace (can't contain underline) +#define SYNO_FLASHCACHE_TARGET_TYPE "flashcache-syno" +// For size_hist and userspce command +#define NEW_MODE_BLOCK_SIZE 128 + +// For hash mappin v2 +#define HASH_REGION_BLOCK_NUM (256 * 1024 * 1024 / 64) // 256 GB * 1024 * 1024 / 64 KB +// Reserve small number for origial flashcache driver +// XXX: WARNING version must be larger than 10 +#define FLASHCACHE_VERSION 2 +#define SYNO_FLASHCACHE_VERSION 10 + +#ifdef MY_ABC_HERE +#define SYNO_FLASHCACHE_VERSION_HASH_MAPPING 11 +#define SYNO_FLASHCACHE_VERSION_HASH_MAPPING_V2 12 +#define IS_NEW_MODE_VERSION(version) ( \ + (version) == SYNO_FLASHCACHE_VERSION || \ + (version) == SYNO_FLASHCACHE_VERSION_HASH_MAPPING || \ + (version) == SYNO_FLASHCACHE_VERSION_HASH_MAPPING_V2) +#define SUPPORT_DMC_GROUP_VERSION(version) \ + (version == SYNO_FLASHCACHE_VERSION_HASH_MAPPING_V2) +#else +#define IS_NEW_MODE_VERSION(version) ((version) >= SYNO_FLASHCACHE_VERSION) +#endif + +#define ID_LEN 512 +#define GROUP_ID_LEN 64 + +/* Cache persistence*/ +#define CACHE_RELOAD_TABLE 4 + +typedef enum _disable_type_t { + DISABLE_UNKNOWN = -1, + DISABLE_NORMAL, + DISABLE_FORCE, +} disable_type_t; + +/* Cache Modes */ +enum { + FLASHCACHE_WRITE_BACK=1, + FLASHCACHE_WRITE_THROUGH=2, + FLASHCACHE_WRITE_AROUND=3, + /* + * Note: FLASHCACHE_DUMMY is only for creating + * After creating, check if state is CACHE_DISABLED is sugguested + */ + FLASHCACHE_DUMMY=4, +}; + +#ifndef __KERNEL__ +typedef u_int64_t sector_t; +#endif + +//SYNO: default is 8 sectors +struct flash_superblock { + sector_t size; /* Cache size */ + u_int32_t block_size; /* Cache block size */ + u_int32_t assoc; /* Cache associativity */ + u_int32_t cache_sb_state; /* Clean shutdown ? */ + char cache_devname[DEV_PATHLEN]; /* Contains dm_vdev name as of v2 modifications */ + sector_t cache_devsize; + char disk_devname[DEV_PATHLEN]; /* underlying block device name (use UUID paths!) */ + sector_t disk_devsize; + // SYNO: start in byte 296 + u_int32_t cache_version; + u_int32_t md_block_size; +#ifdef MY_ABC_HERE + u_int32_t cache_state; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + char group_uuid[GROUP_ID_LEN]; +#endif +}; + +/* On Flash (cache metadata) Structures */ +#define CACHE_MD_STATE_DIRTY 0xdeadbeef +#define CACHE_MD_STATE_CLEAN 0xfacecafe +#define CACHE_MD_STATE_FASTCLEAN 0xcafefeed +#define CACHE_MD_STATE_UNSTABLE 0xc8249756 + +typedef u_int16_t bitmap_t; + +/* + * We do metadata updates only when a block trasitions from DIRTY -> CLEAN + * or from CLEAN -> DIRTY. Consequently, on an unclean shutdown, we only + * pick up blocks that are marked (DIRTY | CLEAN), we clean these and stick + * them in the cache. + * On a clean shutdown, we will sync the state for every block, and we will + * load every block back into cache on a restart. + * + * Note: When using larger flashcache metadata blocks, it is important to make + * sure that a flash_cacheblock does not straddle 2 sectors. This avoids + * partial writes of a metadata slot on a powerfail/node crash. Aligning this + * a 16b or 32b struct avoids that issue. + * + * Note: If a on-ssd flash_cacheblock does not fit exactly within a 512b sector, + * (ie. if there are any remainder runt bytes), logic in flashcache_conf.c which + * reads and writes flashcache metadata on create/load/remove will break. + * + * If changing these, make sure they remain a ^2 size ! + */ +#ifdef FLASHCACHE_DO_CHECKSUMS +struct flash_cacheblock { + sector_t dbn; /* Sector number of the cached block */ + u_int64_t checksum; + u_int32_t cache_state; /* MD_POSSIBLE_STATES */ +#ifdef MY_ABC_HERE + bitmap_t data_bitmap; + bitmap_t dirty_bitmap; +#endif +} __attribute__ ((aligned(32))); +#else +struct flash_cacheblock { + sector_t dbn; /* Sector number of the cached block */ + u_int32_t cache_state; /* MD_POSSIBLE_STATES */ +#ifdef MY_ABC_HERE + bitmap_t data_bitmap; + bitmap_t dirty_bitmap; +#endif +} __attribute__ ((aligned(16))); +#endif + +/* + * States of a cache block (cache_state) + * + * WARNING: To change cacheblock->state, must cb_state_* functions to update + */ + +/* WARNING: In current design: + * - State & INVALID means cacheblk is going to be invalid and new IO won't + * be enqueued for this cacheblk + * - see flashcache_inval_block_set() + * - State == INVALID means the cacheblk might be reclaimed after + * getting out of lock immediately, so don't use it anymore + */ +#define INVALID 0x0001 + +#define VALID 0x0002 /* Valid */ +#define DISKREADINPROG 0x0004 /* Read from disk in progress */ +#define DISKWRITEINPROG 0x0008 /* Write to disk in progress */ +#define CACHEREADINPROG 0x0010 /* Read from cache in progress */ +#define CACHEWRITEINPROG 0x0020 /* Write to cache in progress */ +#define DIRTY 0x0040 /* Dirty, needs writeback to disk */ +/* + * Old and Dirty blocks are cleaned with a Clock like algorithm. The leading hand + * marks DIRTY_FALLOW_1. 900 seconds (default) later, the trailing hand comes along and + * marks DIRTY_FALLOW_2 if DIRTY_FALLOW_1 is already set. If the block was used in the + * interim, (DIRTY_FALLOW_1|DIRTY_FALLOW_2) is cleared. Any block that has both + * DIRTY_FALLOW_1 and DIRTY_FALLOW_2 marked is considered old and is eligible + * for cleaning. + */ +#define DIRTY_FALLOW_1 0x0080 +#define DIRTY_FALLOW_2 0x0100 +#define PIN_FILE 0x0200 + +#ifdef MY_ABC_HERE +#define QFSYNCERR 0x0400 /* error in quickflush sync */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* SYNCED_BITS flag means the wb bio for a cb is finished but metadata haven't update + * The data can be clean/dirty dependding on if the corresponding disk flush completed. + * In SYNCED_BITS state, the block cannot be replaced. + * Forced mu must be issued before invalidating a SYNCED_BITS block. + * Each SYNCED_BITS block has a corresponding MU. However, an mu can be pending if + * it cannot merge with the ongoing mu thus we need two flags to identify cbs. + * SYNCED1/2 corresponds to MU_FLUSH1/2 for mu blocks */ + +/* + * Don't wrap SYNDED1 / SYNOCED2 /... in MY_ABC_HERE + * to avoid need to use MY_ABC_HERE to split many codes + */ +#endif +#define SYNCED1 0x0800 +#define SYNCED2 0x1000 +#define SYNCED_BITS (SYNCED1 | SYNCED2) +#define FORCEDMU 0x2000 /* For cb request force md update (invalidating) */ +#define OCCUPIED_BITS (DIRTY | SYNCED_BITS | PIN_FILE) + +#ifdef MY_ABC_HERE +#define MD_POSSIBLE_STATES (VALID | INVALID | DIRTY | PIN_FILE) +#else +#define MD_POSSIBLE_STATES (VALID | INVALID | DIRTY) +#endif + +#define FALLOW_DOCLEAN (DIRTY_FALLOW_1 | DIRTY_FALLOW_2) +#define BLOCK_IO_INPROG (DISKREADINPROG | DISKWRITEINPROG | CACHEREADINPROG | CACHEWRITEINPROG) + + +#define METADATA_IO_BLOCKSIZE (256*1024) + +/* + * SYNO: + * 26 byte for 64KB cacheblock + * 1GB ssd cache only need 416KB memory + */ +typedef u_int16_t cb_state_t; +struct __attribute__((__packed__)) cacheblock { + cb_state_t cache_state; + int16_t nr_queued; /* jobs in pending queue */ + u_int16_t lru_prev, lru_next; + sector_t dbn; /* Sector number of the cached block */ + bitmap_t data_bitmap; + bitmap_t dirty_bitmap; /* Record the dirty sub blocks */ + bitmap_t flushing_dirty_bitmap; /* For recording partial dirty bitmap to be flushed */ + bitmap_t io_bitmap; /* Record subblocks in IO */ + u_int8_t nr_concurrent; +}; + +#endif /* __SYNO_FLASHCACHE_COMMON_TOOL_H__ */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_feature_defines.h b/drivers/syno/syno-mem-saving-driver/syno_feature_defines.h new file mode 100644 index 000000000000..ae9cbcfde962 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_feature_defines.h @@ -0,0 +1,102 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifndef __SYNO_FLASHCACHE_FEATURE_DEFEINES_H__ +#define __SYNO_FLASHCACHE_FEATURE_DEFEINES_H__ + +#include + +/* + * Not use this feature now, disable it for better performance + */ + + + + +/* + * Support /proc/flashcache/node/list_set_valid_block + */ + +/* + * Don't create cache if the block device is in use (Can't be opened excludely) + */ +/* + * Add write miss ssd, insert to flash_stat string, and append in dmsetup + */ +/* + * Add a new mode for saving memory + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + // Not support split io to avoid unexpected cksum error due to hask bio split +#else + /* + * Note: This feature requires changing __bio_clone_fast() behavior + * in linux kernel <= 4.4 + * If you want to enable this feature on kernel > 4.4, you need to port + * old commit in __bio_clone_fast() + * + */ +#endif + +#if defined(CONFIG_SYNO_ALPINE) +// Alpine doesn't suppot it due to memory limitation +#else +#endif + +/* Support REQ_FLUSH (barrier) */ + +/* Print messages when alloc memory failed */ + +/* dirty writeback size show KB */ + + +/* Metadata update aggregate */ +#if IS_ENABLED(CONFIG_SYNO_FS_CACHE_PROTECTION) +/* + * Don't enable MUA since it might cause model + cache protection not work + * in abnormal shutdown case + */ +#else +#endif + + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +/* + * - TODO: Use seq_io to solve frame size > 1024 bytes warning + * - Only support linux-3.10.x now + */ + +/* Data rescue */ +extern unsigned long long data_rescue_flags; +#define DATA_RESCUE_BLOCK_BAD_STATES (1 << 0) +typedef struct bad_states { + unsigned long long bad_dbn_size; + unsigned long long invalid; + unsigned long long valid; + unsigned long long dirty; + unsigned long long in_prog; + unsigned long long fallow; + unsigned long long bitmap; +} bad_states_t; + +typedef enum load_action { + LOAD_ERROR_IGNORE = 0, /* default */ + LOAD_ERROR_CHECK, +} load_action_t; + +#endif + +/* Support online management */ + +#if defined(CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO) && defined(MY_ABC_HERE) +/* Support dummy cache noclone bio */ +#endif + +#endif + + + + + diff --git a/drivers/syno/syno-mem-saving-driver/syno_functions.c b/drivers/syno/syno-mem-saving-driver/syno_functions.c new file mode 100644 index 000000000000..87507f8845ef --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_functions.c @@ -0,0 +1,623 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) +#include +#include +#endif +#include "dm.h" +#include "dm-io.h" +#include "dm-bio-list.h" +#include "kcopyd.h" +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) +#include "dm.h" +#endif +#include +#include +#include +#endif +#include "flashcache.h" +#include "flashcache_ioctl.h" + +void job_dbg(const char *func, struct kcached_job *job) +{ + char job_str[JOB_STR_MAX] = {0}; + + if (!(debug_flags & DF_JOB)) { + return; + } + + job_to_str(job, job_str, sizeof(job_str)); + + sdbg(DF_JOB, "%s: %s", func, job_str); +} + +char * bio_to_str(struct bio *bio, char *str, int len) +{ + VERIFY_WARN(bio && str && len); + snprintf(str, len, "Bio (bi_sector=%llu size=%llu (sectors) direct=%s op_rw=0x%lx)", + (u64)bio_bi_sector(bio), (u64)to_sector(bio_bi_size(bio)), + (bio_data_dir(bio) == READ) ? "read" : "write", (unsigned long)bio_op_rw(bio)); + return str; +} + +void job_to_str(struct kcached_job *job, char *str, int len) +{ + + int n = 0; + struct bio *bio = NULL; + int index = 0; + char bio_str[BIO_STR_MAX] = {0}; + + VERIFY_WARN(job); + VERIFY_WARN(str); + + bio = job->bio; + index = job->index; + + if (job->bio) { + n += snprintf(str + n , len - n, "%s ", bio_to_str(bio, bio_str, sizeof(bio_str))); + } else { + n += snprintf(str + n , len - n, "No bio "); + } + + n += snprintf(str + n , len - n, "act=%s ", action_str[job->action]); + + if (index != -1) { + n += snprintf(str + n, len - n, "[index=%d] cache.sector=%llu cache.count=%llu disk.sector=%llu disk.count=%llu ", + index, (u64)job->job_io_regions.cache.sector, (u64) job->job_io_regions.cache.count + , (u64)job->job_io_regions.disk.sector, (u64) job->job_io_regions.disk.count + ); + } else { + n += snprintf(str + n, len - n, "[uncached] disk.sector=%llu disk.count=%llu direction=%s", + (u64)job->job_io_regions.disk.sector, (u64) job->job_io_regions.disk.count, + (bio_data_dir(bio) == WRITE)? "write" : "read" + ); + } + + if ((READDISKMEM == job->action) || (WRITEMEMCACHE == job->action)) { + n += snprintf(str + n, len - n, "mem_addr=%p mem_data_byte=%lu", job->mem_addr, job->mem_data_byte); + } +} + +// Solve the alpine mod issue +// TODO: shorten function name +u64 compatible_mod(u64 val, u64 mod) +{ +#ifdef EC_EMULATE_U64_DIVISION + return mod_u64_rem64(val, mod); +#else + return val % mod; +#endif +} + +// TODO: shorten function name +unsigned long long compatible_div(unsigned long long v1, unsigned long long v2) +{ + unsigned long long ret = 0; +#ifdef EC_EMULATE_U64_DIVISION + ret = div64_u64(v1, v2); +#else + ret = v1 / v2; +#endif + return ret; +} + +#ifdef MY_ABC_HERE +// cb and bio are not used, just for debug +bitmap_t bitmap_get_by_bytes(struct cacheblock *cb, struct bio *bio, unsigned long mem_data_byte) +{ + int i = 0; + int bit_start = 0; + int bit_end = 0; + + bitmap_t bitmap_new = 0; + + VERIFY_WARN(mem_data_byte); + + // should be 4K align, calculated in new_kcached_job... + VERIFY_WARN(0 == (mem_data_byte % (512*SECTOR_PER_BIT))); + + bit_start = 0; + bit_end = compatible_div(to_sector(mem_data_byte), SECTOR_PER_BIT) - 1; + + if (bit_end > BITMAP_BITS) { + serr("big_end=%d should not > BITMAP_BITS (%u)", bit_end, BITMAP_BITS); + VERIFY_WARN(0); + } + + for (i = bit_start; i <= bit_end; i++) { + bitmap_new |= 1 << i; + } + + return bitmap_new; +} + +bitmap_t bitmap_get(struct cacheblock *cb, struct bio *bio) +{ + int bit_start = 0; + int bit_end = 0; + int i = 0; + bitmap_t bitmap_new = 0; + + if (!cb || !bio) { + serr("Incorrect parameter cb=%p bio=%p", cb, bio); + VERIFY_WARN(0); + } + + // Align issue is checked in map() + bit_start = compatible_div((bio_bi_sector(bio) - cb->dbn), SECTOR_PER_BIT); + bit_end = bit_start + compatible_div(to_sector(bio_bi_size(bio)), SECTOR_PER_BIT) - 1; + + if (bit_end > BITMAP_BITS) { + serr("bi_sector=%llu cb->dbn=%llu", (u64)bio_bi_sector(bio), (u64)cb->dbn); + serr("bit_start=%d size=%llu SECTOR_PER_BIT=%d", bit_start, (u64)to_sector(bio_bi_size(bio)), SECTOR_PER_BIT); + serr("big_end=%d should not > BITMAP_BITS (%u)", bit_end, BITMAP_BITS); + VERIFY_WARN(0); + } + + for (i = bit_start; i <= bit_end; i++) { + bitmap_new |= 1 << i; + } + + return bitmap_new; +} + +int bitmap_is_contain(bitmap_t bitmap, bitmap_t bitmap_partial) +{ + if ((bitmap & bitmap_partial) == bitmap_partial) + return 1; + else + return 0; +} + +match_t bitmap_get_match(bitmap_t bitmap, bitmap_t compare) +{ + bitmap_t res = bitmap & compare; + if (res == compare) { + return MATCH_ALL; + } else if (res == 0) { + return MATCH_NONE; + } else { + return MATCH_ONLY_PARTIAL; + } + +} + +void bitmap_add(bitmap_t *src, bitmap_t add) +{ + if (!src || !add) { + serr("Incorrect parameter"); + VERIFY_WARN(0); + } + *src = *src | add; +} + +void bitmap_remove(bitmap_t *src, bitmap_t remove) +{ + if (!src) { + serr("null pointer"); + VERIFY_WARN(0); + } + + // Must contain the bits to be removed + VERIFY_WARN(remove == (*src & remove)); + + *src = *src & (~remove); +} + +int bitmap_is_unset(bitmap_t bitmap) +{ + return (bitmap == 0)? 1: 0; +} + + +int bitmap_is_all_set(bitmap_t bitmap) +{ + return (bitmap == BITMAP_MASK)? 1: 0; +} + +void cacheblk_add_data_range(struct cacheblock *cb, bitmap_t bitmap) +{ + bitmap_add(&cb->data_bitmap, bitmap); +} + +void cacheblk_add_data_range_and_dirty_range(struct cacheblock *cb, bitmap_t bitmap) +{ + bitmap_add(&cb->data_bitmap, bitmap); + bitmap_add(&cb->dirty_bitmap, bitmap); +} + +#ifdef CONFIG_SYNO_DATA_CORRECTION +int cacheblk_is_range_dirty(struct cacheblock *cb, struct bio *bio) +{ + int ret = 0; + bitmap_t bio_bitmap = bitmap_get(cb, bio); + + if (bio_bitmap & cb->dirty_bitmap) { + ret = 1; + } + + return ret; +} + +void cacheblk_clear_data_range_by_bio(struct cacheblock *cb, struct bio *bio) +{ + bitmap_t bio_bitmap = bitmap_get(cb, bio); + + cb->data_bitmap &= ~bio_bitmap; +} +#endif + +int cacheblk_is_dirty_range_going_to_change(struct cacheblock *cb, bitmap_t new_added_bitmap) +{ + int ret = 0; + bitmap_t new_dirty_bitmap = 0; + + VERIFY_WARN(cb && new_added_bitmap); + + new_dirty_bitmap = cb->dirty_bitmap | new_added_bitmap; + + if (new_dirty_bitmap != cb->dirty_bitmap) { + ret = 1; + } + + return ret; +} + +void cacheblk_add_data_range_by_bio(struct cacheblock *cb, struct bio *bio) +{ + bitmap_t bio_bitmap = 0; + bio_bitmap = bitmap_get(cb, bio); + bitmap_add(&cb->data_bitmap, bio_bitmap); +} + +match_t cacheblk_compare_data_range(struct cacheblock *cb, struct bio *bio) +{ + bitmap_t bio_bitmap = 0; + bio_bitmap = bitmap_get(cb, bio); + return bitmap_get_match(cb->data_bitmap, bio_bitmap); +} + +void cacheblk_set_all_io_range(struct cacheblock *cb) +{ + if (0 != cb->io_bitmap) { + serr("io_bitmap should be zero!"); + VERIFY_WARN(0); + } + + cb->io_bitmap = BITMAP_MASK; +} + +void cacheblk_add_io_range(struct cacheblock *cb, bitmap_t bitmap) +{ + VERIFY_WARN(cb && bitmap); + + bitmap_add(&cb->io_bitmap, bitmap); +} + +/* + * Must be invoked after the dbn of cache block is set, ex in read_miss + */ +void cacheblk_add_io_range_by_bio(struct cacheblock *cb, struct bio *bio) +{ + bitmap_t bio_bitmap = 0; + bio_bitmap = bitmap_get(cb, bio); + bitmap_add(&cb->io_bitmap, bio_bitmap); +} + +void cacheblk_remove_io_range(struct cacheblock *cb, bitmap_t bitmap) +{ + VERIFY_WARN(cb && bitmap); + bitmap_remove(&cb->io_bitmap, bitmap); +} + +void cacheblk_remove_io_range_by_bio(struct cacheblock *cb, struct bio *bio) +{ + + + bitmap_t bio_bitmap = 0; + + VERIFY_WARN(cb && bio); + + bio_bitmap = bitmap_get(cb, bio); + VERIFY_WARN(0 != bio_bitmap); + + bitmap_remove(&cb->io_bitmap, bio_bitmap); +} + +void cacheblk_remove_io_range_change_state(struct cache_c *dmc, + struct cacheblock *cb, bitmap_t bitmap) +{ + + VERIFY_WARN(cb && bitmap); + + cacheblk_remove_io_range(cb, bitmap); + + if (bitmap_is_unset(cb->io_bitmap)) { + cb_state_remove_bits_update_counts(dmc, cb, BLOCK_IO_INPROG); + } +} + +void cacheblk_remove_io_range_change_state_by_bio(struct cache_c *dmc, + struct cacheblock *cb, struct bio *bio) +{ + + VERIFY_WARN(cb && bio); + + cacheblk_remove_io_range_by_bio(cb, bio); + + if (bitmap_is_unset(cb->io_bitmap)) { + cb_state_remove_bits_update_counts(dmc, cb, BLOCK_IO_INPROG); + } +} + +void cacheblk_unset_all_io_range(struct cacheblock *cb) +{ + VERIFY_WARN(cb); + + VERIFY_WARN(0 != cb->io_bitmap); + cb->io_bitmap = 0; +} + +void cacheblk_unset_all_io_range_change_state(struct cache_c *dmc, struct cacheblock *cb) +{ + VERIFY_WARN(cb); + + cacheblk_unset_all_io_range(cb); + + if (0 == (cb->cache_state & BLOCK_IO_INPROG)) { + serr("Error: Should be BLOCK_IN_PROG!"); + VERIFY_WARN(0); + } + + cb_state_remove_bits_update_counts(dmc, cb, BLOCK_IO_INPROG); +} + +match_t cacheblk_compare_io_range(struct cacheblock *cb, struct bio *bio) +{ + bitmap_t bio_bitmap = 0; + bio_bitmap = bitmap_get(cb, bio); + return bitmap_get_match(cb->io_bitmap, bio_bitmap); +} + +int cacheblk_get_lowest_part_of_flushing_dirty_range(struct cacheblock *cb, sector_t *offset, sector_t *size) +{ + int i = 0; + int found = 0; + bitmap_t bitmap = cb->flushing_dirty_bitmap; + + if (0 == bitmap) { + serr("in dirty state, bitmap should not be zero"); + VERIFY_WARN(0); + return 0; + } + + *offset = 0; + *size = 0; + + for (i = 0; i < BITMAP_BITS; i++) { + if (!found) { + if (bitmap & 1 << i) { + *offset = SECTOR_PER_BIT * i; + *size += SECTOR_PER_BIT; + found = 1; + } + } else { + if (bitmap & 1 << i) { + *size += SECTOR_PER_BIT; + } else { + break; + } + } + } + + // offset can be 0 + VERIFY_WARN(0 != *size); + + return 0; +} + +int cacheblk_unset_lowest_part_of_flushing_dirty_range(struct cacheblock *cb) +{ + int i = 0; + int found = 0; + + VERIFY_WARN(cb); + + for (i = 0; i < BITMAP_BITS; i++) { + if (!found) { + if (cb->flushing_dirty_bitmap & 1 << i) { + cb->flushing_dirty_bitmap &= ~(1<flushing_dirty_bitmap & 1 << i) { + cb->flushing_dirty_bitmap &= ~(1<flushing_dirty_bitmap); +} + +void cacheblk_unset_all_dirty_range(struct cacheblock *cb) +{ + VERIFY_WARN(cb); + VERIFY_WARN(0 != cb->dirty_bitmap); + cb->dirty_bitmap = 0; +} + +void cacheblk_add_num_concurrent(struct cacheblock *cb) +{ + VERIFY_WARN(cb); + + cb->nr_concurrent++; + VERIFY_WARN(cb->nr_concurrent <= NR_CONCURRENT_MAX); +} + +void cacheblk_add_num_concurrent_by(struct cacheblock *cb, int num) +{ + VERIFY_WARN(cb); + + cb->nr_concurrent += num; + VERIFY_WARN(cb->nr_concurrent <= NR_CONCURRENT_MAX); +} + +void cacheblk_dec_num_concurrent_by(struct cacheblock *cb, int num) +{ + VERIFY_WARN(cb); + VERIFY_WARN(num <= cb->nr_concurrent); + cb->nr_concurrent -= num; +} + +// return nr_concurrent +u_int8_t cacheblk_dec_num_concurrent_and_return(struct cacheblock *cb) +{ + VERIFY_WARN(cb); + VERIFY_WARN(0 != cb->nr_concurrent); + cb->nr_concurrent--; + return cb->nr_concurrent; +} + +void cacheblk_unset_all_data_range(struct cacheblock *cb) +{ + VERIFY_WARN(cb); + VERIFY_WARN(0 == cb->io_bitmap); + + if (0 != cb->nr_concurrent) { + serr("cb->nr_concurrent=%d (Should be zero) cache_state=%x dirty_bitmap=%x" + , cb->nr_concurrent, cb->cache_state, cb->dirty_bitmap); + VERIFY_WARN(0); + } + VERIFY_WARN(0 == cb->dirty_bitmap); + + cb->data_bitmap = 0; +} + +sector_t cacheblk_get_start_sector(struct cache_c *dmc, struct bio *bio) +{ + sector_t start = 0; + + VERIFY_WARN(bio && dmc); + start = compatible_div(bio_bi_sector(bio), dmc->block_size) * dmc->block_size; + + return start; +} + +#ifdef MY_ABC_HERE +// Since RO cache doesn't support pin, is_pin is always equal to the initial value 0 +int bio_is_pin(struct bio *bio) +{ +#ifdef MY_DEF_HERE + struct subbio_info *psubbio_info = NULL; + + VERIFY_WARN(bio); + + psubbio_info = bio->bi_private; + + return psubbio_info->is_pin; +#else + struct cache_bi_private *private = NULL; + + VERIFY_WARN(bio); + + private = bio->bi_private; + + return private->is_pin; +#endif +} + +/* + * WARNING: ONLY use this function for incoming IOs + */ +void bio_set_pin_state(struct cache_c *dmc, struct bio *bio) +{ + unsigned char *pbytes = NULL; + unsigned char byte_bitmap = 0; + // Each sub bio should only occupy a bit due to 64KB align + u64 bit_num = compatible_div(bio_bi_sector(bio), CACHE_BLK_SIZE_SEC); + u64 byte_num = compatible_div(bit_num, 8); + int bit_offset = compatible_mod(bit_num, 8); +#ifdef MY_DEF_HERE + struct subbio_info *psubbio_info = bio->bi_private; +#else + struct cache_bi_private *cache_bi_private = bio->bi_private; +#endif + + char bio_str[BIO_STR_MAX] = {0}; + + if (FLASHCACHE_WRITE_BACK != dmc->cache_mode) { + return; + } + + /* + * No need to lock for bitmap since it is only changed when execurate "dmsetup reload" + * to do volume online expansion, and "dmsetup suspended" should be called before it + */ + VERIFY_WARN(dmc->pbitmap_ranges); + pbytes = (unsigned char *)dmc->pbitmap_ranges; + byte_bitmap = pbytes[byte_num]; + + if (byte_bitmap & (1 << bit_offset)) { +#ifdef MY_DEF_HERE + psubbio_info->is_pin = 1; +#else + cache_bi_private->is_pin = 1; +#endif + sdbg(DF_PIN, "%s is_pin=1", bio_to_str(bio, bio_str, sizeof(bio_str))); + } else { + sdbg(DF_PIN, "%s is_pin=0", bio_to_str(bio, bio_str, sizeof(bio_str))); + } +} + +void cacheblk_set_pin_state_by_bio(struct cache_c *dmc, struct cacheblock *cb, struct bio *bio) +{ + VERIFY_WARN(dmc && cb && bio); + + if (bio_is_pin(bio) && dmc->bitmap_is_set) { + cb_state_add_bits_update_counts(dmc, cb, PIN_FILE); + } +} + +// When a cache block is going to be replaced or unpin +void cacheblk_check_unset_pin_state(struct cache_c *dmc, struct cacheblock *cb) +{ + VERIFY_WARN(cb); + + if (cb->cache_state & PIN_FILE) { + cb_state_remove_bits_update_counts(dmc, cb, PIN_FILE); + } +} +#endif /* MY_ABC_HERE */ + +#endif /* MY_ABC_HERE */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_functions.h b/drivers/syno/syno-mem-saving-driver/syno_functions.h new file mode 100644 index 000000000000..e8ff1a2b07f7 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_functions.h @@ -0,0 +1,120 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifndef __SYNO_FUNCTIONS_H__ +#define __SYNO_FUNCTIONS_H__ + +typedef enum _param_type { + TYPE_UNKNOWN, + TYPE_BIO_RANGE, + TYPE_NO_BIO, +#ifdef MY_ABC_HERE + TYPE_NQF, /* Normal Quickflush */ + TYPE_SQF, /* Sync Quickflush */ +#endif + TYPE_PREREAD_CACHEBLK, /* For cache block preread */ + TYPE_MD_IO, /* For md io */ +} param_type_t; + +typedef struct _job_param { + param_type_t type; + struct bio* bio; + sector_t partial_offset; + sector_t partial_size; +} job_param_t; + +typedef enum _match_t { + MATCH_UNSET = -1, + MATCH_ALL, + MATCH_ONLY_PARTIAL, + MATCH_NONE, +} match_t; +extern char *match_str[]; + +void job_dbg(const char *func, struct kcached_job *job); +void job_to_str(struct kcached_job *job, char *str, int len); +extern char *action_str[]; +char * bio_to_str(struct bio *bio, char *str, int len); + +u64 compatible_mod(u64 val, u64 mod); +unsigned long long compatible_div(unsigned long long v1, unsigned long long v2); +bitmap_t bitmap_get(struct cacheblock *cb, struct bio *bio); +bitmap_t bitmap_get_by_bytes(struct cacheblock *cb, struct bio *bio, unsigned long mem_data_byte); +int bitmap_is_contain(bitmap_t bitmap, bitmap_t bitmap_partial); +void bitmap_add(bitmap_t *src, bitmap_t add); +void bitmap_remove(bitmap_t *src, bitmap_t remove); +int bitmap_is_unset(bitmap_t bitmap); +int bitmap_is_all_set(bitmap_t bitmap); +match_t bitmap_get_match(bitmap_t bitmap, bitmap_t compare); + +/* + * Common + */ + +void cacheblk_unset_all_data_range(struct cacheblock *cb); +void cacheblk_add_num_concurrent(struct cacheblock *cb); +void cacheblk_add_num_concurrent_by(struct cacheblock *cb, int num); +sector_t cacheblk_get_start_sector(struct cache_c *dmc, struct bio *bio); +// Return nr_concurrent +void cacheblk_dec_num_concurrent_by(struct cacheblock *cb, int num); +u_int8_t cacheblk_dec_num_concurrent_and_return(struct cacheblock *cb); + +// Data bitmap +void cacheblk_add_data_range(struct cacheblock *cb, bitmap_t bio_bitmap); + +void cacheblk_add_data_range_by_bio(struct cacheblock *cb, struct bio *bio); +match_t cacheblk_compare_data_range(struct cacheblock *cb, struct bio *bio); + + +// IO bitmap: use BLOCK_IO_INPROG to check if in io +void cacheblk_add_io_range(struct cacheblock *cb, bitmap_t bio_bitmap); +void cacheblk_add_io_range_by_bio(struct cacheblock *cb, struct bio *bio); + +void cacheblk_remove_io_range(struct cacheblock *cb, bitmap_t bitmap); +void cacheblk_remove_io_range_by_bio(struct cacheblock *cb, struct bio *bio); + +void cacheblk_remove_io_range_change_state(struct cache_c *dmc, struct cacheblock *cb, bitmap_t bitmap); +void cacheblk_remove_io_range_change_state_by_bio(struct cache_c *dmc, struct cacheblock *cb, struct bio *bio); + +match_t cacheblk_compare_io_range(struct cacheblock *cb, struct bio *bio); +void cacheblk_set_all_io_range(struct cacheblock *cb); +void cacheblk_unset_all_io_range(struct cacheblock *cb); +void cacheblk_unset_all_io_range_change_state(struct cache_c *dmc, struct cacheblock *cb); + +// For pin file +int bio_is_pin(struct bio *bio); +// Query pin file bitmap, set pin state if needed +void bio_set_pin_state(struct cache_c *dmc, struct bio *bio); +void cacheblk_set_pin_state_by_bio(struct cache_c *dmc, struct cacheblock *cb, struct bio *bio); +void cacheblk_check_unset_pin_state(struct cache_c *dmc, struct cacheblock *cb); + +/* + * Dirty bitmap + */ +void cacheblk_add_data_range_and_dirty_range(struct cacheblock *cb, bitmap_t bitmap); +int cacheblk_is_dirty_range_going_to_change(struct cacheblock *cb, bitmap_t new_added_bitmap); +void cacheblk_unset_all_dirty_range(struct cacheblock *cb); +#ifdef CONFIG_SYNO_DATA_CORRECTION +int cacheblk_is_range_dirty(struct cacheblock *cb, struct bio *bio); +void cacheblk_clear_data_range_by_bio(struct cacheblock *cb, struct bio *bio); +#endif +// Control temporary flushing dirty_bitmap for write_back_* operation +int cacheblk_is_flushing_dirty_range_unset(struct cacheblock *cb); +int cacheblk_get_lowest_part_of_flushing_dirty_range(struct cacheblock *cb, sector_t *offset, sector_t *size); +int cacheblk_unset_lowest_part_of_flushing_dirty_range(struct cacheblock *cb); + +/* + * Job create + */ +struct kcached_job *new_kcached_job_fill_cacheblk(struct cache_c *dmc, struct bio* bio, int index); +#ifdef MY_ABC_HERE +struct kcached_job *new_kcached_job_md_io(struct cache_c *dmc, mu_blk_t *mu_blk); +#endif + +#ifdef MY_ABC_HERE +struct kcached_job *new_kcached_job_qf(struct cache_c *dmc, int index, sector_t offset, sector_t size, param_type_t type); +#else +struct kcached_job *new_kcached_job_no_bio(struct cache_c *dmc, int index, sector_t offset, sector_t size); +#endif + +#endif /* __SYNO_FUNCTIONS_H__ */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_kernel_functions.c b/drivers/syno/syno-mem-saving-driver/syno_kernel_functions.c new file mode 100644 index 000000000000..51d1dbc9e297 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_kernel_functions.c @@ -0,0 +1,97 @@ +#include +#include "syno_kernel_functions.h" + +sector_t bio_bi_sector(struct bio *bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return bio->bi_iter.bi_sector; +#else + return bio->bi_sector; +#endif +} + +sector_t* bio_bi_sector_ptr(struct bio *bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return &bio->bi_iter.bi_sector; +#else + return &bio->bi_sector; +#endif +} + + +unsigned int bio_bi_size(struct bio *bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return bio->bi_iter.bi_size; +#else + return bio->bi_size; +#endif +} + +unsigned int* bio_bi_size_ptr(struct bio *bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return &bio->bi_iter.bi_size; +#else + return &bio->bi_size; +#endif +} + +unsigned int bio_bi_idx(struct bio *bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return bio->bi_iter.bi_idx; +#else + return bio->bi_idx; +#endif +} + +unsigned int* bio_bi_idx_ptr(struct bio *bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return &bio->bi_iter.bi_idx; +#else + // Original type is unsigned short * + return (unsigned int *)&bio->bi_idx; +#endif +} + +// BLK_STS_IOERR currently is a bit in u8, so int is enough +void bio_endio_wrapper(struct bio *bio, int error) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) + bio_status(bio) = error; + bio_endio(bio); +#else + bio_endio(bio, error); +#endif +} + +// bio_set_dev will be conflict with kernel function +void bio_assign_dev(struct bio *bio, struct block_device *bdev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + bio_set_dev(bio, bdev); +#else + bio->bi_bdev = bdev; +#endif +} + +void bio_assign_same_dev(struct bio *des_bio, struct bio *src_bio) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + bio_copy_dev(des_bio, src_bio); +#else + des_bio->bi_bdev = src_bio->bi_bdev; +#endif +} + +void* vmalloc_wrapper(size_t size, gfp_t gfp_mask) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + return __vmalloc(size, gfp_mask); +#else + return __vmalloc(size, gfp_mask, PAGE_KERNEL); +#endif +} diff --git a/drivers/syno/syno-mem-saving-driver/syno_kernel_functions.h b/drivers/syno/syno-mem-saving-driver/syno_kernel_functions.h new file mode 100644 index 000000000000..2241ecae9a8a --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_kernel_functions.h @@ -0,0 +1,129 @@ +#ifndef SYNO_FLASHCACHE_KERNEL_FUNCTIONS_H +#define SYNO_FLASHCACHE_KERNEL_FUNCTIONS_H +#include +#include +#include +#include + +/* Kernel porting */ +sector_t bio_bi_sector(struct bio *bio); +sector_t* bio_bi_sector_ptr(struct bio *bio); +unsigned int bio_bi_size(struct bio *bio); +unsigned int* bio_bi_size_ptr(struct bio *bio); +unsigned int bio_bi_idx(struct bio *bio); +unsigned int* bio_bi_idx_ptr(struct bio *bio); +void bio_endio_wrapper(struct bio *bio, int error); +void bio_assign_dev(struct bio *bio, struct block_device *bdev); +void bio_assign_same_dev(struct bio *des_bio, struct bio *src_bio); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +typedef enum _comp_dm_op { + /* + * COMP_DM_WRITE_FLUSH Must use REQ_OP_WRITE since dm async_io() only allow op + * is WRITE as linux 4.4 + */ + COMP_DM_WRITE_FLUSH = REQ_OP_WRITE | REQ_PREFLUSH, + COMP_DM_WRITE = REQ_OP_WRITE, + COMP_DM_READ = REQ_OP_READ, + COMP_DM_WRITE_FUA = REQ_OP_WRITE | REQ_FUA, +} comp_dm_op_t; +#else +typedef enum _comp_dm_op { + COMP_DM_WRITE_FLUSH = WRITE_FLUSH, + COMP_DM_WRITE = WRITE, + COMP_DM_READ = READ, + COMP_DM_WRITE_FUA = WRITE_FUA, +} comp_dm_op_t; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#define COMP_REQ_FLUSH REQ_PREFLUSH +#define COMP_BIO_ERROR BLK_STS_IOERR +#else +#define COMP_REQ_FLUSH REQ_FLUSH +#define COMP_BIO_ERROR -EIO +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#define smp_mb__after_clear_bit_wrapper() smp_mb__after_atomic() +#else +#define smp_mb__after_clear_bit_wrapper() smp_mb__after_clear_bit() +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) +#define wait_on_bit_lock_wrapper(...) wait_on_bit_lock_action(__VA_ARGS__) +#else +#define wait_on_bit_lock_wrapper(...) wait_on_bit_lock(__VA_ARGS__) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +/* + * XXX: Print this value must cast to unsigned long + * + * Dont' cast bi_opf to unsigned long here. (it's unsigned short) + * since this function is also used as lvalue + */ +#define bio_op_rw(bio) bio->bi_opf +#else +#define bio_op_rw(bio) bio->bi_rw +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +/* + * Get bio (REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH) from btrfs's write_dev_flush() + */ +#define bio_has_flush_flags(bio) (REQ_PREFLUSH & bio_op_rw(bio)) +#define bio_has_fua_flags(bio) (REQ_FUA & bio_op_rw(bio)) +#else +#define bio_has_flush_flags(bio) (WRITE_FLUSH == bio_op_rw(bio)) // TODO: why not & REQ_FLUSH? +#define bio_has_fua_flags(bio) (WRITE_FUA == bio_op_rw(bio)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#define bio_status(bio) bio->bi_status +#else +#define bio_status(bio) bio->bi_error +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#define DECLARE_PROC_OPS_OPEN(name, open)\ + static struct proc_ops name = {\ + .proc_open = open,\ + .proc_read = seq_read,\ + .proc_lseek = seq_lseek,\ + .proc_release = single_release,\ +}; +#else +#define DECLARE_PROC_OPS_OPEN(name, func_open)\ + static struct file_operations name = {\ + .open = func_open,\ + .read = seq_read,\ + .llseek = seq_lseek,\ + .release = single_release,\ + }; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#define DECLARE_PROC_OPS_READ_WRITE(name, func_read, func_write)\ + struct proc_ops name = {\ + proc_read: func_read,\ + proc_write: func_write,\ + }; +#else +#define DECLARE_PROC_OPS_READ_WRITE(name, func_read, func_write)\ + struct file_operations name = {\ + read: func_read,\ + write: func_write,\ + }; +#endif + +#ifdef CONFIG_SYNO_MD_UNUSED_HINT +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#define bio_is_unused_hint(bio) (REQ_OP_UNUSED_HINT == bio_op(bio)) +#else +#define bio_is_unused_hint(bio) (REQ_UNUSED_HINT & bio_op_rw(bio)) +#endif +#endif /* CONFIG_SYNO_MD_UNUSED_HINT */ + +void* vmalloc_wrapper(size_t size, gfp_t gfp_mask); +#endif /*SYNO_FLASHCACHE_KERNEL_FUNCTIONS_H*/ diff --git a/drivers/syno/syno-mem-saving-driver/syno_md_update.c b/drivers/syno/syno-mem-saving-driver/syno_md_update.c new file mode 100644 index 000000000000..a48b4d0dd30c --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_md_update.c @@ -0,0 +1,2259 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include + +#include "flashcache.h" +#include "syno_md_update.h" + +// REMOVE THE FILE FOR GPL RELEASE +#ifdef MY_ABC_HERE + +void syno_mu_send_disk_flush(struct cache_c *dmc); +void syno_mu_send_ssd_flush(struct cache_c *dmc); +void syno_mu_send_md_ios(struct cache_c *dmc); +extern int cache_schedule_work(struct work_struct *work); + +// FIXME: remove before release +#define debug(mu) // debug_queue(mu) + +void debug_queue(new_mu_t *mu) +{ + struct list_head *pos = NULL; + mu_blk_t *mu_blk = NULL; + static int limit = 1000; + int changed = 0; + + list_for_each(pos, &mu->disk_flush.inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_DISK_FLUSH_INPROG) && limit) { + serr("Invalid flag for disk flush inprog: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->disk_flush.pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_DISK_FLUSH_PENDING) && limit) { + serr("Invalid flag for disk_flush pending: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->ssd_flush.pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_SSD_FLUSH_PENDING) && limit) { + serr("Invalid flag for ssd flush pending: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->ssd_flush.inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_SSD_FLUSH_INPROG) && limit) { + serr("Invalid flag for ssd flush inprog: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->md_io_pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_MD_IO_PENDING) && limit) { + serr("Invalid flag for md io pending: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->md_io_for_flush_pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_MD_IO_PENDING) && limit) { + serr("Invalid flag for md io for flush pending: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->md_io_inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_MD_IO_INPROG) && limit) { + serr("Invalid flag for md io for flush pending: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + if (mu->ext_flush.inprog) { + list_for_each(pos, &mu->ext_flush.md_io_inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_MD_IO_INPROG) && limit) { + serr("Invalid flag for ext flush md io for flush pending: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + + list_for_each(pos, &mu->ext_flush.md_io_inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (((mu_blk->flags & MU_IN_QUEUE) != MU_MD_IO_INPROG) && limit) { + serr("Invalid flag for ext flush md io inprog: %d %x", mu_blk->idx, mu_blk->flags); + limit--; + changed = 1; + } + } + } + + if (changed) { + dump_stack(); + } + + return; +} + +static inline int job_in_mu_blk(struct cache_c *dmc, struct kcached_job *job, mu_blk_t *mu_blk) +{ + const int cb_start_idx = MD_BLOCK_TO_START_IDX(dmc, mu_blk->idx); + return cb_start_idx <= job->index && (cb_start_idx + MD_SLOTS_PER_BLOCK(dmc)) > job->index; +} + +static void set_job_fua_inprog(struct cache_c *dmc, mu_blk_t *mu_blk) +{ + struct list_head *pos = NULL; + struct kcached_job *job = NULL; + + list_for_each(pos, &dmc->new_mu.fua_job_list) { + job = container_of(pos, struct kcached_job, list); + + if (job_in_mu_blk(dmc, job, mu_blk)) { + job->flag |= JOB_FUA_MU_INPROG; + } + } +} + +static void push_mu_blk_to_md_io_pending(new_mu_t *mu, mu_blk_t *mu_blk) +{ + struct cache_c *dmc = container_of(mu, struct cache_c, new_mu); + mu_blk->tstamp = jiffies; + mu_blk_set_flag(mu_blk, MU_MD_IO_PENDING); + + if (unlikely(mu_blk_flagged_any(mu_blk, MU_FUA))) { + set_job_fua_inprog(dmc, mu_blk); + } + + /* Must clear MU_PENDING_BEFORE_FLUSH. It's ok to queue FUA mu to + * ext_flush->md_io_pending_queue since it'll also be handled immediately */ + if (unlikely(mu_blk_test_clear_flag_any(mu_blk, MU_PENDING_BEFORE_FLUSH))) { + VERIFY_WARN(mu->ext_flush.inprog); + + sdbg(DF_NEW_MU, "requeue mu pending before flush idx: %d", mu_blk->idx); + + list_add(&mu_blk->node, &mu->ext_flush.md_io_pending_queue); + cache_schedule_work(&mu->ext_flush.send_io_work); + } else { + if (unlikely(mu_blk_flagged_any(mu_blk, MU_FUA))) { + list_add(&mu_blk->node, &mu->md_io_pending_queue); + } else { + list_add_tail(&mu_blk->node, &mu->md_io_pending_queue); + } + + mu->md_io_pending_queue_size++; + atomic_inc(&dmc->dmcg->md_io_pending_no_flush); + } +} + +static inline int get_current_sync_flag(mu_blk_t *mu_blk) +{ + return mu_blk_flagged_any(mu_blk, MU_FLUSH_1) ? SYNCED1 : SYNCED2; +} + +static inline int get_pending_sync_flag(mu_blk_t *mu_blk) +{ + return mu_blk_flagged_any(mu_blk, MU_FLUSH_1) ? SYNCED2 : SYNCED1; +} + +/* under mu lock */ +static int no_md_updates_queued(new_mu_t *mu) +{ + return list_empty(&mu->disk_flush.pending_queue) && + list_empty(&mu->disk_flush.inprog_queue) && + list_empty(&mu->ssd_flush.pending_queue) && + list_empty(&mu->ssd_flush.inprog_queue) && + list_empty(&mu->md_io_inprog_queue) && + list_empty(&mu->md_io_pending_queue) && + list_empty(&mu->md_io_for_flush_pending_queue); +} + +/* Timeout for flush SYNCED_BITS blocks. If SSD crash during dirty data syncing, + * the workqueue will be blocked here without timeout since it's not possible + * to update metadata on SSD. + * TODO: it's better if we can detect ssd crash. */ +#define FLUSH_SYNCED_TIMEOUT_SEC 60 +static inline int all_synced_flushed_or_timeout(struct cache_c *dmc, unsigned long start_jif) +{ + return (dmc->nr_synced == 0 || time_after(jiffies, start_jif + FLUSH_SYNCED_TIMEOUT_SEC * HZ)); +} + +void syno_mu_flush_all_synced_sync(struct cache_c *dmc) +{ + new_mu_t *mu = &dmc->new_mu; + unsigned long start_jif = jiffies; + + spin_lock_irq(&mu->lock); + + mu->sysctl_mu_delay_sec = 0; + mu->flush_itvl_sec = 0; + + cache_mod_delayed_work(&mu->dwork, 0); + + spin_unlock_irq(&mu->lock); + + sdbg(DF_QUICKFLUSH, "waiting for synced blocks to be cleared"); + + spin_lock_irq(&dmc->cache_spin_lock); + while (!all_synced_flushed_or_timeout(dmc, start_jif)) { + spin_unlock_irq(&dmc->cache_spin_lock); + wait_event_timeout(mu->remove_wqh, all_synced_flushed_or_timeout(dmc, start_jif), 10 * HZ); + spin_lock_irq(&dmc->cache_spin_lock); + } + + if (dmc->nr_synced) { + sdbg(DF_QUICKFLUSH, "Wait for synced blocks timeout. %d synced blocks not cleared.", dmc->nr_synced); + } else { + sdbg(DF_QUICKFLUSH, "wait for synced blocks cleared done"); + } + spin_unlock_irq(&dmc->cache_spin_lock); + + spin_lock_irq(&mu->lock); + mu->sysctl_mu_delay_sec = MU_DEFAULT_DELAY_SEC; + mu->flush_itvl_sec = MU_DEFAULT_FLUSH_ITVL_SEC; + spin_unlock_irq(&mu->lock); +} + +/* The function blocks until all the metadata updates are finished + * NOT atomic context*/ +void syno_mu_flush_all_for_remove_sync(struct cache_c *dmc) +{ + new_mu_t *mu = &dmc->new_mu; + + spin_lock_irq(&mu->lock); + + mu->sysctl_mu_delay_sec = 0; + mu->flush_itvl_sec = 0; + mu->remove_flush = 1; + + cache_mod_delayed_work(&mu->dwork, 0); + + serr("waiting for md update to be cleared"); + + wait_event_lock_irq(mu->remove_wqh, no_md_updates_queued(mu), mu->lock); + + serr("wait for md update cleared done"); + + spin_unlock_irq(&mu->lock); + + cancel_delayed_work_sync(&mu->dwork); + VERIFY_WARN(atomic_read(&dmc->nr_jobs) == 0); + + syno_mu_disable_dmcg_throtl(dmc); +} + +// in under mu lock +static int merge_all_to_force_mu(struct cache_c *dmc, mu_blk_t *mu_blk) +{ + int i = 0; + unsigned long flags = 0; + int pending_sync_flag = get_pending_sync_flag(mu_blk); + new_mu_t *mu = &dmc->new_mu; + int cb_idx = MD_BLOCK_TO_START_IDX(dmc, mu_blk->idx); + + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)); + VERIFY_WARN(!mu_blk_flagged_any(mu_blk, MU_MD_IO_INPROG)); + + if (mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + /* we merge pending with forced, align SYNCED_BITS flags */ + for (i = 0; i < MD_SLOTS_PER_BLOCK(dmc) && cb_idx < dmc->size; ++i, ++cb_idx) { + if (dmc->cache[cb_idx].cache_state & pending_sync_flag) { + VERIFY_WARN((dmc->cache[cb_idx].cache_state & SYNCED_BITS) != SYNCED_BITS); + /* Flip SYNCED_BITS bits */ + dmc->cache[cb_idx].cache_state ^= SYNCED_BITS; + } + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + mu->pending_blk_num[MU_BLK_TYPE_FLUSH]--; + } + + mu_blk->flags &= (MU_INPROG | MU_NEED_FLUSH); + + mu_blk_set_flag(mu_blk, MU_FORCED | MU_DISK_FLUSH_PENDING); + debug(mu); + list_add_tail(&mu_blk->node, &mu->disk_flush.pending_queue); + debug(mu); + mu->disk_flush.forced = 1; + + cache_mod_delayed_work(&mu->dwork, 0); + return get_current_sync_flag(mu_blk); +} + +/* NOT in ATOMIC context */ +void syno_mu_queue_force_update(struct cache_c *dmc, int cb_idx) +{ + int sync_flag = 0; + int do_pending = 0; + unsigned long cache_flags = 0; + unsigned long md_idx = INDEX_TO_MD_BLOCK(dmc, cb_idx); + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = &mu->mu_blocks[MU_BLK_TYPE_FLUSH][md_idx]; + struct cacheblock *cb = &dmc->cache[cb_idx]; + + spin_lock_irq(&mu->lock); + if (!mu_blk_flagged_any(mu_blk, MU_INPROG)) { + + /* New md update */ + mu_blk_set_flag(mu_blk, MU_INPROG | MU_FORCED | MU_DISK_FLUSH_PENDING | MU_FLUSH_1); + + list_add_tail(&mu_blk->node, &mu->disk_flush.pending_queue); + mu->disk_flush.forced = 1; + + sync_flag = SYNCED1; // update sync flag + mu->inprog_blk_num[MU_BLK_TYPE_FLUSH]++; + + } else if (mu_blk_flagged_any(mu_blk, MU_FORCED)) { + /* already have a forced update */ + + if (mu_blk_flagged_any(mu_blk, MU_DISK_FLUSH_PENDING)) { + /* No need to add counter since we merge with existing request */ + sync_flag = get_current_sync_flag(mu_blk); + } else { + if (!mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + mu->pending_blk_num[MU_BLK_TYPE_FLUSH]++; + } else { + /* Merge with existinig pending, don't add counter */ + } + + mu_blk_set_flag(mu_blk, MU_HAS_PENDING_REQ | MU_PENDING_REQ_FORCED); + sync_flag = get_pending_sync_flag(mu_blk); + } + + } else if (mu_blk_flagged_any(mu_blk, MU_MD_IO_INPROG)) { + /* Need to group all updates but current one io inprog, wait + * Merge with existing valid, don't add counter */ + + /* TODO: a possible optimization is to merge this MU with the on going force + * mu if they share the same SYNCED_BITS flag. But we unlock mu lock when + * calling do_pending so we cannot merge when on gonig mu is + * MD_IO_INPROG with error or SSD_FLUSH_INPROG */ + + if (check_new_error_inject(dmc, MU_FORCED_RESTART_TEST)) { + sprint("Force Restart on mu_blk idx: %d", mu_blk->idx); + } + + mu_blk_set_flag(mu_blk, MU_FORCED | MU_FORCED_RESTART); + sync_flag = get_current_sync_flag(mu_blk); + } else { + /* Every other stage except for MD_IO_INPROG we start it over */ + debug(mu); + list_del_init(&mu_blk->node); // From DFPQ, DFIQ, SFPQ, SFIQ, MIFPQ + debug(mu); + // block stats updated in merge_all_to_force_mu + sync_flag = merge_all_to_force_mu(dmc, mu_blk); + } + + spin_lock_irqsave(&dmc->cache_spin_lock, cache_flags); + VERIFY_WARN(cb->nr_concurrent != 0); + VERIFY_WARN(cb->io_bitmap == BITMAP_MASK); + VERIFY_WARN(cb->cache_state & VALID); + VERIFY_WARN(cb->cache_state & DISKWRITEINPROG); + + /* A job is allocated in the original invalidate process. Follow the + * original process to increase nr_job here and dec after do_pending + * even if we don't actually allocate a job. */ + atomic_inc(&dmc->nr_jobs); + + atomic64_inc(&dmc->flashcache_stats.md_write_clean); + if (cb->cache_state & DIRTY) { + cb_state_remove_bits_update_counts(dmc, cb, DIRTY); + VERIFY_WARN(dmc->nr_dirty > 0); + dmc->nr_dirty--; + VERIFY_WARN(!(cb->cache_state & SYNCED_BITS)); + cb_state_add_bits_update_counts(dmc, cb, sync_flag | FORCEDMU); + dmc->nr_synced++; + } else if (cb->cache_state & SYNCED_BITS) { + cb_state_remove_bits_update_counts(dmc, cb, SYNCED_BITS); + cb_state_add_bits_update_counts(dmc, cb, sync_flag | FORCEDMU); + } else { + /* not forced mu already cleared the flag when out of lock, + * no need to update this cache block anymore. + * Don't change the states. */ + if (cb->nr_queued) { + do_pending = 1; + } else { + VERIFY_WARN(0); + } + } + + spin_unlock_irqrestore(&dmc->cache_spin_lock, cache_flags); + + cache_mod_delayed_work(&mu->dwork, 0); + spin_unlock_irq(&mu->lock); + + if (do_pending) { + flashcache_do_pending_force_mu(dmc, cb_idx, 0); + } + + return; +} + +/* + * Called after any fua write after flashcache_io_callback_atomic: + * IN ATOMIC CONTEXT, no io error. cb has partial IO range. + */ +void syno_mu_queue_no_flush_fua_update(struct cache_c *dmc, struct kcached_job *job) +{ + unsigned long flags = 0; + unsigned long md_idx = INDEX_TO_MD_BLOCK(dmc, job->index); + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = &mu->mu_blocks[MU_BLK_TYPE_NOFLUSH][md_idx]; + + sdbg(DF_FUA, "Get FUA Request, CB: %d sector: %llu", job->index, (u64)bio_bi_sector(job->bio)); + + spin_lock_irqsave(&mu->lock, flags); + + VERIFY_WARN(bio_has_fua_flags(job->bio)); + + list_add_tail(&job->list, &mu->fua_job_list); + + /* start new md update */ + if (!mu_blk_flagged_any(mu_blk, MU_INPROG)) { + mu_blk_set_flag(mu_blk, (MU_INPROG | MU_FUA)); + + push_mu_blk_to_md_io_pending(mu, mu_blk); + + mu->inprog_blk_num[MU_BLK_TYPE_NOFLUSH]++; + + goto end_unlock; + } + + /* merge with pending udpate */ + if (mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + /* for no flush mu, has pending means MU_MD_IO_INPROG */ + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_MD_IO_INPROG)); + + /* Mark pending as FUA, so it'll be handled immediately */ + mu_blk_set_flag(mu_blk, MU_PENDING_REQ_FUA); + + goto end_unlock; + } + + /* merge with current update or put to pending */ + if (mu_blk_flagged_any(mu_blk, MU_MD_IO_PENDING)) { + /* merge into md io pending */ + mu_blk_set_flag(mu_blk, MU_FUA); + set_job_fua_inprog(dmc, mu_blk); + + /* Move node to head */ + list_del(&mu_blk->node); // from MIPQ + list_add(&mu_blk->node, &mu->md_io_pending_queue); + + } else { + /* queue to pending mu */ + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_MD_IO_INPROG)); + sdbg(DF_FUA, "Put FUA mu to pending cb idx: %d", job->index); + + mu_blk_set_flag(mu_blk, MU_HAS_PENDING_REQ | MU_PENDING_REQ_FUA); + mu->pending_blk_num[MU_BLK_TYPE_NOFLUSH]++; + } + +end_unlock: + /* As soon as we release the lock the job COULD be freed. */ + flashcache_check_record_io_latency(LAT_MD_WRITE_REG, &job->io_lat); + spin_unlock_irqrestore(&mu->lock, flags); + + /* FUA requires immediate handling */ + cache_mod_delayed_work(&mu->dwork, 0); + + return; +} + +/* + * Called after write dirty range change in flashcache_io_callback_atomic: + * IN ATOMIC CONTEXT, no io error. cb has partial IO range. + */ +void syno_mu_queue_no_flush_update(struct cache_c *dmc, struct kcached_job *job) +{ + unsigned long flags = 0; + unsigned long md_idx = INDEX_TO_MD_BLOCK(dmc, job->index); + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = &mu->mu_blocks[MU_BLK_TYPE_NOFLUSH][md_idx]; + + spin_lock_irqsave(&mu->lock, flags); + + /* start new md update */ + if (mu_blk_flagged_any(mu_blk, MU_INPROG)) { + /* merge with pending udpate */ + if (mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + // merge into pending + goto end_unlock; + } else { + /* merge with current update or put to pending */ + if (mu_blk_flagged_any(mu_blk, MU_MD_IO_PENDING)) { + /* merge into md io pending */ + } else { + mu_blk_set_flag(mu_blk, MU_HAS_PENDING_REQ); + mu->pending_blk_num[MU_BLK_TYPE_NOFLUSH]++; + } + } + } else { + mu_blk_set_flag(mu_blk, MU_INPROG); + push_mu_blk_to_md_io_pending(mu, mu_blk); + + mu->inprog_blk_num[MU_BLK_TYPE_NOFLUSH]++; + goto end_unlock; + } + +end_unlock: + spin_unlock_irqrestore(&mu->lock, flags); + + flashcache_check_record_io_latency(LAT_MD_WRITE_REG, &job->io_lat); + + return; +} + +/* + * Handle MU update (e.g. send to DFPQ) and cache block information update after quick flush writeback + * + * NOT in atomic context, no io error. + * cb in DISKWRITEINPROG & DIRTY state, has all io range + * DISKWRITEINPROG and io range removed, DIRTY -> SYNCED_BITS in function + */ +void syno_mu_queue_flush_update(struct cache_c *dmc, int cb_idx) +{ + int sync_flag = 0; + int requeue_forced = 0; + unsigned long flags = 0; + unsigned long md_idx = INDEX_TO_MD_BLOCK(dmc, cb_idx); + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = &mu->mu_blocks[MU_BLK_TYPE_FLUSH][md_idx]; + struct cacheblock *cb = &dmc->cache[cb_idx]; + + spin_lock_irq(&mu->lock); + + /* start new md update */ + if (!mu_blk_flagged_any(mu_blk, MU_INPROG)) { + mu_blk_set_flag(mu_blk, (MU_INPROG | MU_DISK_FLUSH_PENDING | MU_FLUSH_1)); + debug(mu); + list_add_tail(&mu_blk->node, &mu->disk_flush.pending_queue); + debug(mu); + sync_flag = SYNCED1; + + mu->inprog_blk_num[MU_BLK_TYPE_FLUSH]++; + goto end_unlock; + } + + /* merge with pending udpate */ + if (mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + // merge into pending + sync_flag = get_pending_sync_flag(mu_blk); + goto end_unlock; + } + + /* merge with current update or put to pending */ + if (mu_blk_flagged_any(mu_blk, MU_DISK_FLUSH_PENDING)) { + /* merge into disk flush pending queue */ + sync_flag = get_current_sync_flag(mu_blk); + } else { + mu_blk_set_flag(mu_blk, MU_HAS_PENDING_REQ); + sync_flag = get_pending_sync_flag(mu_blk); + mu->pending_blk_num[MU_BLK_TYPE_FLUSH]++; + } + +end_unlock: + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + if (cb->nr_queued) { + /* someone queued when we are out of cache_spin_lock. + * need a forced md update. No need to cancel this flush one */ + requeue_forced = 1; + } else { + /* Verify states */ + VERIFY_WARN(dmc->nr_dirty > 0); + VERIFY_WARN(cb->cache_state & VALID); + if (!(cb->cache_state & DIRTY)) { + serr("cb %d queue flush mu but not DIRTY, state: %x", + cb_idx, cb->cache_state); + VERIFY_WARN(0); + } + + /* Unset dirty range when issuing md update + * Only unset dirty range if the cb block is still SYNCED + * If any new writes change cb state to DIRTY, we consider WB + * interrupted and keep the dirty range */ + atomic64_inc(&dmc->flashcache_stats.md_write_clean); + cb_state_remove_bits_update_counts(dmc, cb, DIRTY); + dmc->nr_dirty--; + dmc->nr_synced++; + cb_state_add_bits_update_counts(dmc, cb, sync_flag); + VERIFY_WARN(!(cb->cache_state & FORCEDMU)); + VERIFY_WARN(cb->cache_state & SYNCED_BITS); + unset_partial_cb_writeback_attrs(dmc, cb, 1); + } + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + spin_unlock_irq(&mu->lock); + + if (requeue_forced) { + syno_mu_queue_force_update(dmc, cb_idx); + } + + return; +} + +static void set_pending_before_flush(struct list_head *head) +{ + struct list_head *pos = NULL; + mu_blk_t *mu_blk = NULL; + + list_for_each(pos, head) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + sdbg(DF_NEW_MU, "Set pending before flush blk: %d", mu_blk->idx); + mu_blk_set_flag(mu_blk, MU_PENDING_BEFORE_FLUSH); + } + } +} + +static inline void clear_force_no_flush_pending_error_inject(struct cache_c *dmc) +{ + if (check_new_error_inject(dmc, FORCE_NO_FLUSH_PENDING)) { + serr("clear force no flush pending"); + dmc->sysctl_new_error_inject = 0; + } +} + +/* Under mu lock */ +static void __start_ext_flush(new_mu_t *mu) +{ + struct cache_c *dmc = container_of(mu, struct cache_c, new_mu); + ext_flush_t *ext_flush = &mu->ext_flush; + + ext_flush->inprog = 1; + + VERIFY_WARN(list_empty(&ext_flush->flush_bios_handling)); + VERIFY_WARN(!list_empty(&ext_flush->flush_bios_pending)); + VERIFY_WARN(list_empty(&ext_flush->md_io_inprog_queue)); + VERIFY_WARN(list_empty(&ext_flush->md_io_pending_queue)); + + list_splice_init(&ext_flush->flush_bios_pending, &ext_flush->flush_bios_handling); + + atomic_sub(mu->md_io_pending_queue_size, &dmc->dmcg->md_io_pending_no_flush); + mu->md_io_pending_queue_size = 0; + + if (dmc->bypass_cache) { + /* if cache in bypass mode, no need to send ssd flush */ + ext_flush->ssd_flush_stage = FLUSH_DONE; + } else if (list_empty(&mu->md_io_inprog_queue) && list_empty(&mu->md_io_pending_queue)) { + mu->ssd_flush.forced = 1; + ext_flush->ssd_flush_stage = FLUSH_REQUESTED; + } else { + list_splice_init(&mu->md_io_inprog_queue, &ext_flush->md_io_inprog_queue); + list_splice_init(&mu->md_io_pending_queue, &ext_flush->md_io_pending_queue); + set_pending_before_flush(&ext_flush->md_io_inprog_queue); + clear_force_no_flush_pending_error_inject(dmc); + cache_schedule_work(&ext_flush->send_io_work); + } + + /* Disk Flush don't have to wait for anything */ + ext_flush->disk_flush_stage = FLUSH_REQUESTED; + mu->disk_flush.forced = 1; + + cache_mod_delayed_work(&mu->dwork, 0); +} + +static inline ext_flush_bio_node_t* alloc_ext_flush_bio_list(struct cache_c *dmc) +{ + if (check_new_error_inject(dmc, EXT_FLUSH_BIO_LIST_ALLOC_FAIL)) { + sprint("Simulate external flush bio list allocation fail"); + dmc->sysctl_new_error_inject = 0; + return NULL; + } + + return kzalloc(sizeof(ext_flush_bio_node_t), GFP_NOIO); +} + +/* NOT atomic context */ +void syno_mu_start_ext_flush(struct cache_c *dmc, struct bio *flush_bio, + unsigned long start_jiffy) +{ + new_mu_t *mu = &dmc->new_mu; + ext_flush_t *ext_flush = &mu->ext_flush; + ext_flush_bio_node_t *flush_bio_node = NULL; + + sdbg(DF_NEW_MU, "Get external flush"); + + flush_bio_node = alloc_ext_flush_bio_list(dmc); + if (NULL == flush_bio_node) { + serr("Failed to allocate memory for flush bio"); + bio_endio_wrapper(flush_bio, -ENOMEM); + handle_master_io_finish(dmc); + return; + } + flush_bio_node->bio = flush_bio; + flashcache_init_io_latency(&flush_bio_node->io_lat, + dmc->sysctl_syno_latency_diagnose, TYPE_DISK, start_jiffy, 1); + + spin_lock_irq(&mu->lock); + list_add_tail(&flush_bio_node->node, &ext_flush->flush_bios_pending); + if (ext_flush->inprog) { + sdbg(DF_NEW_MU, "External flush queued to pending"); + spin_unlock_irq(&mu->lock); + return; + } + + sdbg(DF_NEW_MU, "Start new external flush"); + __start_ext_flush(mu); + spin_unlock_irq(&mu->lock); +} + +/* under lock */ +void syno_mu_finish_ext_flush(new_mu_t *mu) +{ + struct cache_c *dmc = container_of(mu, struct cache_c, new_mu); + ext_flush_t *ext_flush = &mu->ext_flush; + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + ext_flush_bio_node_t *flush_bio_node = NULL; + + VERIFY_WARN(ext_flush->inprog); + VERIFY_WARN(ext_flush->disk_flush_stage == FLUSH_DONE); + VERIFY_WARN(ext_flush->ssd_flush_stage == FLUSH_DONE); + VERIFY_WARN(list_empty(&ext_flush->md_io_inprog_queue)); + VERIFY_WARN(list_empty(&ext_flush->md_io_pending_queue)); + + list_for_each_safe(pos, tmp, &ext_flush->flush_bios_handling) { + flush_bio_node = container_of(pos, ext_flush_bio_node_t, node); + + list_del(pos); // From ext flush BHQ + + flashcache_check_process_io_latency(dmc, &flush_bio_node->io_lat, LAT_FLUSH_BIO); + + bio_endio_wrapper(flush_bio_node->bio, ext_flush->error); + handle_master_io_finish(dmc); + kfree(flush_bio_node); + } + + VERIFY_WARN(list_empty(&ext_flush->flush_bios_handling)); + + ext_flush->disk_flush_stage = FLUSH_WAITING; + ext_flush->ssd_flush_stage = FLUSH_WAITING; + ext_flush->error = 0; + + if (!list_empty(&ext_flush->flush_bios_pending)) { + __start_ext_flush(mu); + } else { + ext_flush->inprog = 0; + } + +} + +static inline long next_flush_time_up(dev_flush_t *flush, int itvl_sec) +{ + return time_after(jiffies, flush->last_flush_jif + itvl_sec * HZ); +} + +static inline int need_disk_flush(new_mu_t *mu) +{ + return (!mu->disk_flush.inprog && ((next_flush_time_up(&mu->disk_flush, mu->flush_itvl_sec) + && !list_empty(&mu->disk_flush.pending_queue)) || mu->disk_flush.forced)); +} + +static inline int need_ssd_flush(new_mu_t *mu) +{ + return (!mu->ssd_flush.inprog && ((next_flush_time_up(&mu->ssd_flush, mu->flush_itvl_sec) + && !list_empty(&mu->ssd_flush.pending_queue)) || mu->ssd_flush.forced)); +} + +void syno_mu_do_md_update(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, new_mu.dwork.work); + new_mu_t *mu = &dmc->new_mu; + + spin_lock_irq(&mu->lock); + if (need_disk_flush(mu)) { + syno_mu_send_disk_flush(dmc); + spin_lock_irq(&mu->lock); + } + + if (need_ssd_flush(mu)) { + syno_mu_send_ssd_flush(dmc); + } else { + spin_unlock_irq(&mu->lock); + } + + syno_mu_send_md_ios(dmc); + + cache_schedule_delayed_work(&mu->dwork, mu->sysctl_mu_check_itvl_sec * HZ); +} + +void syno_mu_disk_flush_callback(unsigned long error, void *context) +{ + struct cache_c *dmc = (struct cache_c *)context; + new_mu_t *mu = &dmc->new_mu; + ext_flush_t *ext_flush = &mu->ext_flush; + unsigned long flags = 0; + + if (check_new_error_inject(dmc, DISK_FLUSH_ERROR)) { + sprint("simulate disk flush error"); + dmc->sysctl_new_error_inject = 0; + error = 1; + } + + // XXX: will this error handling break abnormal power lost protection? + if (error) { + error = -EIO; + serr("Send flush bio to disk failed"); + } + spin_lock_irqsave(&mu->lock, flags); + if (error && FLUSH_INPROG == ext_flush->disk_flush_stage) { + ext_flush->error = error; + } + spin_unlock_irqrestore(&mu->lock, flags); + + atomic64_inc(&dmc->flashcache_stats.disk_flush_done); + cache_schedule_work(&mu->disk_flush.complete_work); +} + +static void splice_disk_flush_inprog_to_md_io_for_flush_pending(new_mu_t *mu) +{ + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + mu_blk_t *mu_blk = NULL; + + debug(mu); + + list_for_each_safe(pos, tmp, &mu->disk_flush.inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + mu_blk_unset_flag(mu_blk, MU_DISK_FLUSH_INPROG); + mu_blk_set_flag(mu_blk, MU_MD_IO_PENDING); + + list_del_init(pos); // From DFIQ + + mu_blk->tstamp = jiffies; + + if (mu_blk_flagged_any(mu_blk, MU_FORCED)) { + list_add(pos, &mu->md_io_for_flush_pending_queue); + } else { + list_add_tail(pos, &mu->md_io_for_flush_pending_queue); + } + // no need to mod delay work, we send io immediatly after this + } + + VERIFY_WARN(list_empty(&mu->disk_flush.inprog_queue)); + debug(mu); + + return; +} + +void syno_mu_disk_flush_complete(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, new_mu.disk_flush.complete_work); + new_mu_t *mu = &dmc->new_mu; + + sdbg(DF_NEW_MU, "disk flush complete"); + + spin_lock_irq(&mu->lock); + if (FLUSH_INPROG == mu->ext_flush.disk_flush_stage) { + sdbg(DF_NEW_MU, "external flush disk flush done"); + mu->ext_flush.disk_flush_stage = FLUSH_DONE; + if (FLUSH_DONE == mu->ext_flush.ssd_flush_stage) { + syno_mu_finish_ext_flush(mu); + sdbg(DF_NEW_MU, "Finish flush from disk flush"); + } + } + splice_disk_flush_inprog_to_md_io_for_flush_pending(mu); + + mu->disk_flush.inprog = 0; + if (need_disk_flush(mu)) { + syno_mu_send_disk_flush(dmc); + } else { + spin_unlock_irq(&mu->lock); + } + + /* Forced MU need to be handled immediatly */ + syno_mu_send_md_ios(dmc); + + return; +} + +static inline void splice_disk_flush_pending_to_disk_flush_inprog(new_mu_t *mu) +{ + struct list_head *pos = NULL; + mu_blk_t *mu_blk = NULL; + + VERIFY_WARN(list_empty(&mu->disk_flush.inprog_queue)); + + list_for_each(pos, &mu->disk_flush.pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + mu_blk_unset_flag(mu_blk, MU_DISK_FLUSH_PENDING); + mu_blk_set_flag(mu_blk, MU_DISK_FLUSH_INPROG); + } + + list_splice_init(&mu->disk_flush.pending_queue, &mu->disk_flush.inprog_queue); +} + +/* Must in under mu spinlock. Out NOT under lock. might sleep */ +void syno_mu_send_disk_flush(struct cache_c *dmc) +{ + new_mu_t *mu = &dmc->new_mu; + + sdbg(DF_NEW_MU, "Sending Disk Flush"); + + splice_disk_flush_pending_to_disk_flush_inprog(mu); + mu->disk_flush.last_flush_jif = jiffies; + mu->disk_flush.inprog = 1; + mu->disk_flush.forced = 0; + if (FLUSH_REQUESTED == mu->ext_flush.disk_flush_stage) { + mu->ext_flush.disk_flush_stage = FLUSH_INPROG; + } + spin_unlock_irq(&mu->lock); + + atomic64_inc(&dmc->flashcache_stats.disk_flush_start); + dm_io_async_bio_wrapper(1, &dmc->disk_region, COMP_DM_WRITE_FLUSH, mu->disk_flush.bio, + syno_mu_disk_flush_callback, dmc, 0); +} + +static void +update_cb_state_after_ssd_flush_complete(struct cache_c *dmc, mu_blk_t *mu_blk, int forced) +{ + int i = 0; + int cb_idx = MD_BLOCK_TO_START_IDX(dmc, mu_blk->idx); + int target_sync_flag = get_current_sync_flag(mu_blk); + struct cacheblock *cb = NULL; + + for (i = 0; i < MD_SLOTS_PER_BLOCK(dmc) && cb_idx < dmc->size; ++i, ++cb_idx) { + cb = &dmc->cache[cb_idx]; + if (cb->cache_state & target_sync_flag) { + cb_state_remove_bits_update_counts(dmc, cb, target_sync_flag); + dmc->nr_synced--; + if (0 == dmc->nr_synced) { + wake_up(&dmc->new_mu.remove_wqh); + } + + if ((cb->cache_state & FORCEDMU)) { + VERIFY_WARN(forced); + cb_state_remove_bits_update_counts(dmc, cb, FORCEDMU); + spin_unlock_irq(&dmc->cache_spin_lock); + flashcache_do_pending_force_mu(dmc, cb_idx, 0); + spin_lock_irq(&dmc->cache_spin_lock); + } + } + } +} + +static void +handle_pending_or_finish_after_update_cb_state(new_mu_t *mu, mu_blk_t *mu_blk, int forced) +{ + mu_blk_unset_flag(mu_blk, MU_SSD_FLUSH_INPROG); + mu_blk_unset_flag(mu_blk, MU_FORCED); + + if (mu_blk_flagged_any(mu_blk, MU_HAS_PENDING_REQ)) { + mu_blk_unset_flag(mu_blk, MU_HAS_PENDING_REQ); + + /* Toggle FLUSH_1/2 flag */ + mu_blk->flags ^= MU_NEED_FLUSH; + + if (mu_blk_flagged_any(mu_blk, MU_PENDING_REQ_FORCED)) { + VERIFY_WARN(forced); + mu_blk_unset_flag(mu_blk, MU_PENDING_REQ_FORCED); + mu_blk_set_flag(mu_blk, MU_FORCED); + mu->disk_flush.forced = 1; + cache_mod_delayed_work(&mu->dwork, 0); + } + + mu_blk_set_flag(mu_blk, MU_DISK_FLUSH_PENDING); + debug(mu); + list_add_tail(&mu_blk->node, &mu->disk_flush.pending_queue); + debug(mu); + mu->pending_blk_num[MU_BLK_TYPE_FLUSH]--; + } else { + /* no more pending md update */ + mu_blk_unset_flag(mu_blk, MU_INPROG); + mu_blk_unset_flag(mu_blk, MU_NEED_FLUSH); + + mu->inprog_blk_num[MU_BLK_TYPE_FLUSH]--; + } +} + +/* In/Out not under lock */ +static void handle_ssd_flush_complete_for_each_mu(struct cache_c *dmc) +{ + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = NULL; + unsigned long flags = 0; + int forced = 0; + LIST_HEAD(force_queue); + + spin_lock_irq(&mu->lock); + + list_for_each_safe(pos, tmp, &mu->ssd_flush.inprog_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + forced = mu_blk_flagged_any(mu_blk, MU_FORCED); + + /* Need to call do pending out side spinlock, handle seperatly */ + if (forced) { + debug(mu); + list_del_init(pos); // from SFIQ + debug(mu); + list_add(pos, &force_queue); + debug(mu); + continue; + } + + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)); + + spin_lock_irqsave(&dmc->cache_spin_lock, flags); + update_cb_state_after_ssd_flush_complete(dmc, mu_blk, forced); + spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); + + debug(mu); + list_del_init(pos); // from SFIQ + debug(mu); + + handle_pending_or_finish_after_update_cb_state(mu, mu_blk, forced); + } + + spin_unlock_irq(&mu->lock); + + /* All mu handled below are forced */ + forced = 1; + + /* We have FORCED flag set already, safe to drop the mu lock since we won't modify it */ + spin_lock_irq(&dmc->cache_spin_lock); + list_for_each(pos, &force_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_FORCED)); + + update_cb_state_after_ssd_flush_complete(dmc, mu_blk, forced); + } + spin_unlock_irq(&dmc->cache_spin_lock); + + spin_lock_irq(&mu->lock); + list_for_each_safe(pos, tmp, &force_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + debug(mu); + list_del_init(pos); // From local queue + debug(mu); + + handle_pending_or_finish_after_update_cb_state(mu, mu_blk, forced); + } + spin_unlock_irq(&mu->lock); + +} + +void syno_mu_ssd_flush_complete(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, new_mu.ssd_flush.complete_work); + new_mu_t *mu = &dmc->new_mu; + + sdbg(DF_NEW_MU, "ssd flush complete"); + + handle_ssd_flush_complete_for_each_mu(dmc); + + spin_lock_irq(&mu->lock); + + if (FLUSH_INPROG == mu->ext_flush.ssd_flush_stage) { + sdbg(DF_NEW_MU, "external flush ssd flush done"); + mu->ext_flush.ssd_flush_stage = FLUSH_DONE; + if (FLUSH_DONE == mu->ext_flush.disk_flush_stage) { + sdbg(DF_NEW_MU, "finish flush from ssd flush done"); + syno_mu_finish_ext_flush(mu); + } + } + + mu->ssd_flush.inprog = 0; + if (need_ssd_flush(mu)) { + syno_mu_send_ssd_flush(dmc); + } else { + spin_unlock_irq(&mu->lock); + } + + spin_lock_irq(&mu->lock); + if (no_md_updates_queued(mu)) { + wake_up(&mu->remove_wqh); + } + spin_unlock_irq(&mu->lock); + return; +} + +void syno_mu_ssd_flush_callback(unsigned long error, void *context) +{ + struct cache_c *dmc = (struct cache_c *)context; + new_mu_t *mu = &dmc->new_mu; + ext_flush_t *ext_flush = &mu->ext_flush; + unsigned long flags = 0; + + // XXX: will this error handling break abnormal power lost protection? + sdbg(DF_NEW_MU, "ssd flush done"); + + + if (check_new_error_inject(dmc, SSD_FLUSH_ERROR)) { + sprint("Simulate ssd flush error"); + dmc->sysctl_new_error_inject = 0; + error = 1; + } + + if (error) { + if (dmc->bypass_cache || is_writeback_crash_safe_set_bypass(dmc)) { + error = 0; + serr("In bypass mode, ignore ssd flush error"); + } else { + error = -EIO; + serr("Send flush bio to ssd failed"); + } + } + + spin_lock_irqsave(&mu->lock, flags); + if (error && FLUSH_INPROG == ext_flush->ssd_flush_stage) { + ext_flush->error = error; + } + spin_unlock_irqrestore(&mu->lock, flags); + + atomic64_inc(&dmc->flashcache_stats.md_flush_done); + cache_schedule_work(&mu->ssd_flush.complete_work); +} + +static inline void splice_ssd_flush_pending_to_ssd_flush_inprog(new_mu_t *mu) +{ + struct list_head *pos = NULL; + mu_blk_t *mu_blk = NULL; + + VERIFY_WARN(list_empty(&mu->ssd_flush.inprog_queue)); + + list_for_each(pos, &mu->ssd_flush.pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + mu_blk_unset_flag(mu_blk, MU_SSD_FLUSH_PENDING); + // TODO: used only for debug purpose, consider remove + mu_blk_set_flag(mu_blk, MU_SSD_FLUSH_INPROG); + } + + list_splice_init(&mu->ssd_flush.pending_queue, &mu->ssd_flush.inprog_queue); +} + +/* Must in under mu spinlock. Out NOT under lock, might sleep */ +void syno_mu_send_ssd_flush(struct cache_c *dmc) +{ + new_mu_t *mu = &dmc->new_mu; + + sdbg(DF_NEW_MU, "Sending SSD Flush"); + + splice_ssd_flush_pending_to_ssd_flush_inprog(mu); + mu->ssd_flush.last_flush_jif = jiffies; + mu->ssd_flush.inprog = 1; + mu->ssd_flush.forced = 0; + if (FLUSH_REQUESTED == mu->ext_flush.ssd_flush_stage) { + sdbg(DF_NEW_MU, "Sending SSD Flush for external flush"); + mu->ext_flush.ssd_flush_stage = FLUSH_INPROG; + } + spin_unlock_irq(&mu->lock); + + atomic64_inc(&dmc->flashcache_stats.md_flush_start); + dm_io_async_bio_wrapper(1, &dmc->cache_region, COMP_DM_WRITE_FLUSH, + mu->ssd_flush.bio, syno_mu_ssd_flush_callback, dmc, 0); + sdbg(DF_NEW_MU, "Sent SSD Flush"); +} + +static inline mu_blk_t *get_sibling_mu_blk(new_mu_t *mu, mu_blk_t *mu_blk) +{ + int sib_flush = (mu_blk->flags & MU_NEED_FLUSH) ? MU_BLK_TYPE_NOFLUSH : MU_BLK_TYPE_FLUSH; + return mu->mu_blocks[sib_flush] + mu_blk->idx; +} + +static inline int sib_mu_blk_io_inprog(new_mu_t *mu, mu_blk_t *mu_blk) +{ + return mu_blk_flagged_any(get_sibling_mu_blk(mu, mu_blk), MU_MD_IO_INPROG); +} + +static inline int dmcg_need_throtl_for_md_io(dmc_group_t *dmcg) +{ + return atomic_read(&dmcg->md_io_pending_no_flush) > dmcg->md_io_throtl_thres; +} + +static inline int md_io_above_per_cache_throtl_thres(struct cache_c *dmc) +{ + /* No need to lock to get md_io_pending_queue_size, incorrect value won't hurt */ + return dmc->new_mu.md_io_pending_queue_size > dmc->dmcg->md_io_throtl_thres / dmc->dmcg->num_dmc; +} + +static inline int in_throtl_for_md_io(struct cache_c *dmc) +{ + return dmcg_need_throtl_for_md_io(dmc->dmcg) && + md_io_above_per_cache_throtl_thres(dmc); +} + +static inline int mu_blk_expired(new_mu_t *mu, mu_blk_t *mu_blk) +{ + return time_after(jiffies, mu_blk->tstamp + mu->sysctl_mu_delay_sec * HZ); +} + +static mu_blk_t *first_valid_no_flush_mu_for_md_io(struct cache_c *dmc) +{ + new_mu_t *mu = &dmc->new_mu; + struct list_head *pos = NULL; + mu_blk_t *mu_blk = NULL; + + list_for_each(pos, &mu->md_io_pending_queue) { + mu_blk = container_of(pos, mu_blk_t, node); + + if (!in_throtl_for_md_io(dmc) && !mu_blk_expired(mu, mu_blk) && + !mu_blk_flagged_any(mu_blk, MU_FUA)) { + return NULL; + } + + if (sib_mu_blk_io_inprog(mu, mu_blk)) { + /* sibling mu blk io in progress */ + continue; + } + + return mu_blk; + } + + return NULL; +} + +static mu_blk_t *first_valid_flush_mu_for_md_io(new_mu_t *mu) +{ + struct list_head *pos = NULL; + mu_blk_t *mu_blk = NULL; + + list_for_each(pos, &mu->md_io_for_flush_pending_queue) { + + mu_blk = container_of(pos, mu_blk_t, node); + /* Forced mu don't care about jiffies */ + if (!mu_blk_flagged_any(mu_blk, MU_FORCED) && !mu_blk_expired(mu, mu_blk)) { + return NULL; + } + + if (sib_mu_blk_io_inprog(mu, mu_blk)) { + continue; + } + + return mu_blk; + } + + return NULL; +} + +static inline int can_send_more_md_io(new_mu_t *mu) +{ + return mu->md_io_inprog_normal < mu->sysctl_mu_ios_total; +} + +/* Set mu blk state for md io and handle combo */ +static mu_blk_t* setup_and_get_mu_blk_to_update(struct cache_c *dmc, mu_blk_t *mu_blk) +{ + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *sib_mu_blk = get_sibling_mu_blk(mu, mu_blk); + mu_blk_t *ret = mu_blk; + + mu_blk_set_flag(mu_blk, MU_MD_IO_INPROG); + mu_blk_unset_flag(mu_blk, MU_MD_IO_PENDING); + + VERIFY_WARN(!mu_blk_flagged_any(sib_mu_blk, MU_MD_IO_INPROG)); + + /* handle combo io */ + if (mu_blk_flagged_any(sib_mu_blk, MU_MD_IO_PENDING)) { + + VERIFY_WARN(mu_blk_flagged_any(sib_mu_blk, MU_INPROG)); + + if (check_new_error_inject(dmc, MD_IO_COMBO_TEST)) { + sprint("MD IO combo sent idx: %d", mu_blk->idx); + } + + debug(mu); + list_del_init(&sib_mu_blk->node); // From MIPQ, MIFPQ + if (!mu_blk_flagged_any(sib_mu_blk, MU_NEED_FLUSH)) { + mu->md_io_pending_queue_size--; + atomic_dec(&dmc->dmcg->md_io_pending_no_flush); + } + debug(mu); + mu_blk_set_flag(mu_blk, MU_MD_IO_COMBO); + mu_blk_set_flag(sib_mu_blk, MU_MD_IO_COMBO); + mu_blk_set_flag(sib_mu_blk, MU_MD_IO_INPROG); + mu_blk_unset_flag(sib_mu_blk, MU_MD_IO_PENDING); + + /* We must send md io with need flush mu for combo mu for 2 reasons + * 1. we need FLUSH1/2 flag to send correct metadata for SYNCED_BITS cbs + * 2. We handle do pending for forced mu on error before handle COMBO. */ + if (mu_blk_flagged_any(sib_mu_blk, MU_NEED_FLUSH)) { + ret = sib_mu_blk; + } + } + + /* The flag in unset when IO sent */ + if (mu_blk_flagged_any(sib_mu_blk, MU_FUA) || mu_blk_flagged_any(mu_blk, MU_FUA)) { + mu_blk_set_flag(ret, MU_MD_IO_NEED_FUA); + } + + return ret; +} + +static void requeue_mu_io(new_mu_t *mu, mu_blk_t *mu_blk) +{ + if (mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)) { + debug(mu); + mu_blk->tstamp = jiffies; + mu_blk_set_flag(mu_blk, MU_MD_IO_PENDING); + list_add_tail(&mu_blk->node, &mu->md_io_for_flush_pending_queue); + debug(mu); + } else { + // merge pending io + if (mu_blk_test_clear_flag_any(mu_blk, MU_HAS_PENDING_REQ)) { + mu->pending_blk_num[MU_BLK_TYPE_NOFLUSH]--; + } + + if (mu_blk_test_clear_flag_any(mu_blk, MU_PENDING_REQ_FUA)) { + mu_blk_set_flag(mu_blk, MU_FUA); + } + + push_mu_blk_to_md_io_pending(mu, mu_blk); + } +} + +void handle_md_io_complete_for_mu(new_mu_t *mu, mu_blk_t *mu_blk, int err) +{ + if (err) { + requeue_mu_io(mu, mu_blk); + return; + } + + if (mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)) { + mu_blk_set_flag(mu_blk, MU_SSD_FLUSH_PENDING); + debug(mu); + list_add(&mu_blk->node, &mu->ssd_flush.pending_queue); + debug(mu); + } else { + if (mu_blk_test_clear_flag_any(mu_blk, MU_HAS_PENDING_REQ)) { + if (mu_blk_test_clear_flag_any(mu_blk, MU_PENDING_REQ_FUA)) { + sdbg(DF_FUA, "Handle FUA Pending mu idx: %d", mu_blk->idx); + mu_blk_set_flag(mu_blk, MU_FUA); + } + push_mu_blk_to_md_io_pending(mu, mu_blk); + + mu->pending_blk_num[MU_BLK_TYPE_NOFLUSH]--; + } else { + mu_blk_unset_flag(mu_blk, MU_INPROG); + mu->inprog_blk_num[MU_BLK_TYPE_NOFLUSH]--; + } + } +} + +// endio / handle pending +static void handle_fua_ios(struct cache_c *dmc, mu_blk_t *mu_blk, int err) +{ + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + struct kcached_job *job = NULL; + + sdbg(DF_FUA, "Finish FUA mu idx %d", mu_blk->idx); + + list_for_each_safe(pos, tmp, &dmc->new_mu.fua_job_list) { + job = container_of(pos, struct kcached_job, list); + + if (job_in_mu_blk(dmc, job, mu_blk) && (job->flag & JOB_FUA_MU_INPROG)) { + list_del(&job->list); + job->flag &= ~(JOB_FUA_MU_INPROG); + job->error = err; + + flashcache_check_record_io_latency(LAT_MD_WRITE_FUA, &job->io_lat); + + flashcache_bio_endio(job->bio, err, dmc, job->io_start_time, &job->io_lat); + job->bio = NULL; + + sdbg(DF_FUA, "Finish FUA Request, CB: %d", job->index); + flashcache_handle_job_finish(dmc, job); + } + } + +} + +static void handle_md_io_complete_for_fua_mu(new_mu_t *mu, mu_blk_t *mu_blk, int err) +{ + struct cache_c *dmc = container_of(mu, struct cache_c, new_mu); + + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_FUA)); + VERIFY_WARN(!mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)); + + handle_fua_ios(dmc, mu_blk, err); + + mu_blk_unset_flag(mu_blk, MU_FUA); + + handle_md_io_complete_for_mu(mu, mu_blk, err); +} + +void handle_md_io_complete_for_forced_mu(new_mu_t *mu, mu_blk_t *mu_blk, int err) +{ + struct cache_c *dmc = container_of(mu, struct cache_c, new_mu); + + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)); + + if (mu_blk_flagged_any(mu_blk, MU_FORCED_RESTART)) { + // TODO: stats needed + merge_all_to_force_mu(dmc, mu_blk); + return; + } + + if (err) { + if (mu_blk_flagged_any(mu_blk, MU_PENDING_REQ_FORCED)) { + /* Do pending for this forced IO handled befor this. + * It's like we have a new forced mu and an on going + * normal mu. Merge them */ + merge_all_to_force_mu(dmc, mu_blk); + } else { + /* forced handled and no force pending, remove forced flag then requeue */ + mu_blk_unset_flag(mu_blk, MU_FORCED); + requeue_mu_io(mu, mu_blk); + } + } else { + + mu->ssd_flush.forced = 1; + mu_blk_set_flag(mu_blk, MU_SSD_FLUSH_PENDING); + debug(mu); + list_add(&mu_blk->node, &mu->ssd_flush.pending_queue); + debug(mu); + + cache_mod_delayed_work(&mu->dwork, 0); + } +} + +static inline +void handle_mu_io_complete_for_single_mu(new_mu_t *mu, mu_blk_t *mu_blk, int err) +{ + if (unlikely(mu_blk_flagged_any(mu_blk, MU_FORCED))) { + handle_md_io_complete_for_forced_mu(mu, mu_blk, err); + } else if (unlikely(mu_blk_flagged_any(mu_blk, MU_FUA))) { + handle_md_io_complete_for_fua_mu(mu, mu_blk, err); + } else { + handle_md_io_complete_for_mu(mu, mu_blk, err); + } +} + +void handle_md_io_complete(struct cache_c *dmc, mu_blk_t *mu_blk, int err) +{ + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *sib_mu_blk = NULL; + struct list_head *pos = NULL; + + if (err) { + list_for_each(pos, &mu->ext_flush.md_io_inprog_queue) { + if (pos == &mu_blk->node) { + mu->ext_flush.error = err; + } + } + } + list_del(&mu_blk->node); // for ext flush MIIQ or MIIQ + + switch (mu_blk->flags & MU_SENT_BY) { + case MU_SENT_BY_EXT_FLUSH: + mu->md_io_inprog_ext_flush--; + mu->sent_md_io_ext_flush_cnt++; + break; + case MU_SENT_BY_NORMAL: + mu->md_io_inprog_normal--; + mu->sent_md_io_normal_cnt++; + break; + case MU_SENT_BY_THROTL: + mu->md_io_inprog_throtl--; + mu->sent_md_io_throtl_cnt++; + break; + case MU_SENT_BY_FORCE: + mu->md_io_inprog_force--; + mu->sent_md_io_force_cnt++; + break; + case MU_SENT_BY_FUA: + mu->md_io_inprog_fua--; + mu->sent_md_io_fua_cnt++; + break; + default: + serr("Unexpected MU_SENT_BY flag: %x", mu_blk->flags); + break; + } + + mu_blk_unset_flag(mu_blk, MU_SENT_BY); + mu_blk_unset_flag(mu_blk, MU_MD_IO_INPROG); + if (mu_blk_flagged_any(mu_blk, MU_MD_IO_COMBO)) { + sib_mu_blk = get_sibling_mu_blk(mu, mu_blk); + mu_blk_unset_flag(mu_blk, MU_MD_IO_COMBO); + mu_blk_unset_flag(sib_mu_blk, MU_MD_IO_COMBO | MU_MD_IO_INPROG); + } + + handle_mu_io_complete_for_single_mu(mu, mu_blk, err); + + if (sib_mu_blk) { + if (check_new_error_inject(dmc, MD_IO_COMBO_TEST)) { + dmc->sysctl_new_error_inject = 0; + sprint("md io combo test finishes, idx %d", mu_blk->idx); + } + handle_mu_io_complete_for_single_mu(mu, sib_mu_blk, err); + } +} + +/* In under cache_spin_lock */ +void handle_force_mu_io_error_do_pending(struct cache_c *dmc, mu_blk_t *mu_blk, int error) +{ + int i = 0; + int cb_idx = MD_BLOCK_TO_START_IDX(dmc, mu_blk->idx); + int target_sync_flag = get_current_sync_flag(mu_blk); + struct cacheblock *cb = NULL; + + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)); + VERIFY_WARN(!mu_blk_flagged_any(mu_blk, MU_FORCED_RESTART)); + + for (i = 0; i < MD_SLOTS_PER_BLOCK(dmc) && cb_idx < dmc->size; ++i, ++cb_idx) { + cb = &dmc->cache[cb_idx]; + if ((cb->cache_state & target_sync_flag) && (cb->cache_state & FORCEDMU)) { + /* force md update failed, but we still need md update for this + * so leave the SYNCED_BITS flag */ + cb_state_remove_bits_update_counts(dmc, cb, FORCEDMU); + spin_unlock_irq(&dmc->cache_spin_lock); + flashcache_do_pending_force_mu(dmc, cb_idx, error); + spin_lock_irq(&dmc->cache_spin_lock); + } + } + +} + +void handle_delayed_jobs_for_force_mu_io_error(struct cache_c *dmc, struct kcached_job *delayed_jobs) +{ + struct kcached_job *job = delayed_jobs; + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = NULL; + + if (NULL == delayed_jobs) { + return;; + } + + spin_lock_irq(&dmc->cache_spin_lock); + while (job) { + VERIFY_WARN(job->error); + mu_blk = job->ctx; + handle_force_mu_io_error_do_pending(dmc, mu_blk, job->error); + job = job->next; + } + spin_unlock_irq(&dmc->cache_spin_lock); + + spin_lock_irq(&mu->lock); + job = delayed_jobs; + while (job) { + mu_blk = job->ctx; + handle_md_io_complete(dmc, mu_blk, job->error); + + job = job->next; + } + spin_unlock_irq(&mu->lock); +} + +void free_jobs_for_md_io(struct kcached_job *job_list) +{ + struct kcached_job *job = NULL; + + while (job_list) { + job = job_list; + job_list = job_list->next; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + flashcache_free_md_bio(job); +#else + flashcache_free_md_sector(job); +#endif + flashcache_free_cache_job(job); + } +} + +/* under MU lock */ +static void handle_ext_flush_after_md_io(new_mu_t *mu) +{ + ext_flush_t *ext_flush = &mu->ext_flush; + + if (ext_flush->inprog) { + if (!list_empty(&ext_flush->md_io_pending_queue)) { + /* io left in pending queue due to sibling inprog */ + cache_schedule_work(&ext_flush->send_io_work); + } else if (list_empty(&ext_flush->md_io_inprog_queue) && + FLUSH_WAITING == ext_flush->ssd_flush_stage) { + + sdbg(DF_NEW_MU, "All md io done for ext flush, request ssd flush"); + ext_flush->ssd_flush_stage = FLUSH_REQUESTED; + mu->ssd_flush.forced = 1; + cache_mod_delayed_work(&mu->dwork, 0); + } + } +} + +static void +simulate_md_io_complete_errors(struct cache_c *dmc, mu_blk_t *mu_blk, struct kcached_job *job) +{ + if (check_new_error_inject(dmc, FORCE_MD_IO_ERROR)) { + if (mu_blk_flagged_any(mu_blk, MU_FORCED) && + !mu_blk_flagged_any(mu_blk, MU_FORCED_RESTART)) { + sprint("Simulate force md io error"); + dmc->sysctl_new_error_inject = 0; + job->error = -EIO; + } + } + + if (check_new_error_inject(dmc, MD_IO_ERROR)) { + if (!mu_blk_flagged_any(mu_blk, MU_FORCED)) { + sprint("Simulate md io error"); + dmc->sysctl_new_error_inject = 0; + job->error = -EIO; + } + } + + if (check_new_error_inject(dmc, WRITE_FUA_ERROR)) { + if (mu_blk_flagged_any(mu_blk, MU_FUA)) { + sprint("Simulate fua error"); + dmc->sysctl_new_error_inject = 0; + job->error = -EIO; + } + } +} + +void syno_mu_md_io_complete(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, new_mu.md_io_complete_work); + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = NULL; + struct kcached_job *jobs = NULL; + struct kcached_job *delayed_jobs = NULL; + struct kcached_job *job_itr = NULL; + struct kcached_job *prev_job = NULL; + struct kcached_job *next_job = NULL; + int job_cnt = 0; + + spin_lock_irq(&mu->lock); + jobs = mu->md_io_complete_job_queue; + mu->md_io_complete_job_queue = NULL; + + job_itr = jobs; + prev_job = NULL; + while (job_itr) { + job_cnt++; + next_job = job_itr->next; + + mu_blk = job_itr->ctx; + + simulate_md_io_complete_errors(dmc, mu_blk, job_itr); + + if (job_itr->error && mu_blk_flagged_any(mu_blk, MU_FORCED) && + !mu_blk_flagged_any(mu_blk, MU_FORCED_RESTART)) { + /* Need to call do pending, handle outside the lock later */ + if (NULL == prev_job) { + jobs = job_itr->next; + } else { + prev_job->next = job_itr->next; + } + job_itr->next = delayed_jobs; + delayed_jobs = job_itr; + } else { + prev_job = job_itr; + handle_md_io_complete(dmc, mu_blk, job_itr->error); + } + + job_itr = next_job; + } + spin_unlock_irq(&mu->lock); + + // do pending for forced mu on error and process mu_blks + handle_delayed_jobs_for_force_mu_io_error(dmc, delayed_jobs); + + spin_lock_irq(&mu->lock); + handle_ext_flush_after_md_io(mu); + spin_unlock_irq(&mu->lock); + + free_jobs_for_md_io(jobs); + free_jobs_for_md_io(delayed_jobs); + + if (atomic_sub_and_test(job_cnt, &dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } + + syno_mu_send_md_ios(dmc); + + spin_lock_irq(&mu->lock); + if (no_md_updates_queued(mu)) { + wake_up(&mu->remove_wqh); + } + spin_unlock_irq(&mu->lock); +} + +void syno_mu_md_io_callback(unsigned long error, void *ctx) +{ + struct kcached_job *job = (struct kcached_job *)ctx; + struct cache_c *dmc = job->dmc; + new_mu_t *mu = &job->dmc->new_mu; + unsigned long flags = 0; + static int remove_flush_printed = 0; + + atomic_inc(&mu->md_io_callback_cnt); + + //TODO: deal with latency diagnose later + + if (unlikely(error)) { + if (dmc->bypass_cache || is_writeback_crash_safe_set_bypass(dmc)) { + /* We do not expect there'll be md io queueing when in bypass mode + md io queueing implies dirty blocks, since all dirty should + already been written back in bypass mode, all no flush mu should + also be written with the corresponding need flush mu */ + serr("md io error in bypass mode, ignore"); + } else if (mu->remove_flush) { + if (!remove_flush_printed) { + serr("Forced Remove detected on metadata io error, ignore error!"); + remove_flush_printed = 1; + } + } else { + job->error = -EIO; + if (job->dmc->limits.md_io_error > 0) { + job->dmc->limits.md_io_error--; + serr("MD IO Error"); + } + } + } + + spin_lock_irqsave(&mu->lock, flags); + job->next = mu->md_io_complete_job_queue; + mu->md_io_complete_job_queue = job; + spin_unlock_irqrestore(&mu->lock, flags); + cache_schedule_work(&mu->md_io_complete_work); +} + +static inline int job_alloc_md_io_data(struct kcached_job *job) +{ + + if (check_new_error_inject(job->dmc, MD_BIO_ALLOC_FAIL)) { + sprint("Simulate md bio alloc fail"); + job->dmc->sysctl_new_error_inject = 0; + return -1; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + return flashcache_alloc_md_bio(job); +#else + return flashcache_alloc_md_sector(job); +#endif +} + +static inline void handle_force_no_flush_pending_error_inject(struct cache_c *dmc, mu_blk_t *mu_blk) +{ + if (check_new_error_inject(dmc, FORCE_NO_FLUSH_PENDING)) { + serr("Detect force no flush pending flag, force pending idx: %d", mu_blk->idx); + mu_blk_set_flag(mu_blk, MU_HAS_PENDING_REQ); + dmc->new_mu.pending_blk_num[MU_BLK_TYPE_NOFLUSH]++; + while (check_new_error_inject(dmc, FORCE_NO_FLUSH_PENDING)) { + serr("Detect force no flush pending flag, sleep 5 seconds"); + msleep(5000); + } + serr("Force no flush pending flag cleared, continue"); + } +} + +static void syno_mu_send_md_io_from_job(struct kcached_job *job, int need_fua) +{ + int i = 0; + int idx = 0; + struct cache_c *dmc = job->dmc; + mu_blk_t *mu_blk = job->ctx; + struct flash_cacheblock *md_block = NULL; + struct dm_io_region where = {0}; + int sync_flag = 0; + int comp_dm_op = need_fua ? COMP_DM_WRITE_FUA : COMP_DM_WRITE; + struct cacheblock *cb = NULL; + + if (mu_blk_flagged_any(mu_blk, MU_MD_IO_COMBO)) { + VERIFY_WARN(mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)); + } + + if (mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH)) { + sync_flag = get_current_sync_flag(mu_blk); + } + + handle_force_no_flush_pending_error_inject(dmc, mu_blk); + + atomic_inc(&dmc->new_mu.send_md_io_cnt); + + if (job_alloc_md_io_data(job)) { + /* We have job, follow normal error handling process */ + serr("Failed to allocate md bio, mu idx: %d", mu_blk->idx); + syno_mu_md_io_callback(1, job); + return; + } + spin_lock_irq(&dmc->cache_spin_lock); + + md_block = job->md_block; + idx = MD_BLOCK_TO_START_IDX(dmc, mu_blk->idx); + + for (i = 0; i < MD_SLOTS_PER_BLOCK(dmc) && idx < dmc->size; i++, idx++) { + cb = &dmc->cache[idx]; + + while (check_new_error_inject(dmc, MU_FORCED_RESTART_TEST) && + mu_blk_flagged_any(mu_blk, MU_NEED_FLUSH) && cb->cache_state & SYNCED_BITS) { + if (mu_blk_flagged_any(mu_blk, MU_FORCED_RESTART)) { + dmc->sysctl_new_error_inject = 0; + sprint("Detect Force Restart flag, continue"); + break; + } + sprint("Detect Force Restart Test Flag, dbn %lld valid mu_blk idx: %d", + (unsigned long long)cb->dbn, mu_blk->idx); + spin_unlock_irq(&dmc->cache_spin_lock); + msleep(5000); + spin_lock_irq(&dmc->cache_spin_lock); + } + + md_block[i].dbn = cb->dbn; +#ifdef FLASHCACHE_DO_CHECKSUMS + md_block[i].checksum = cb->checksum; +#endif + md_block[i].data_bitmap = cb->data_bitmap; + + // NOTE: sync_flag will be zero for no flush mu + if ((cb->cache_state & sync_flag) && cb->dirty_bitmap) { + /* disk flush done, we are safe to clean dirty bitmap + * If we don't clean dirty bitmap, no flush mu after this + * might write it to disk and cause inconsistency */ + cacheblk_unset_all_dirty_range(cb); + /* cannot clean SYNCED_BITS because it's still not applicable to be replaced */ + } + md_block[i].dirty_bitmap = cb->dirty_bitmap; + md_block[i].cache_state = cb->cache_state & MD_POSSIBLE_STATES; + + if (cb->cache_state & SYNCED_BITS && !(cb->cache_state & sync_flag) && cb->dirty_bitmap) { + /* SYNCED_BITS blocks not belonged to this round and + * haven't issued md io (dirty_bitmap != 0) should be dirty on disk */ + md_block[i].cache_state |= DIRTY; + } + } + + spin_unlock_irq(&dmc->cache_spin_lock); + + where.bdev = get_cache_bdev(dmc); + where.count = MD_SECTORS_PER_BLOCK(dmc); + where.sector = (1 + mu_blk->idx) * MD_SECTORS_PER_BLOCK(dmc); + atomic64_inc(&dmc->flashcache_stats.ssd_writes); + atomic64_inc(&dmc->flashcache_stats.md_ssd_writes); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + dm_io_async_bvec(1, &where, comp_dm_op, job->md_bio, syno_mu_md_io_callback, job, 0); +#else + dm_io_async_bvec(1, &where, comp_dm_op, &job->md_io_bvec, syno_mu_md_io_callback, job, 0); +#endif + +} + +static struct kcached_job* +alloc_md_io_job(struct cache_c *dmc, mu_blk_t *mu_blk) +{ + if (check_new_error_inject(dmc, MD_IO_JOB_ALLOC_FAIL)) { + if (!mu_blk_flagged_any(mu_blk, MU_FORCED)) { + sprint("Simulate md io job alloc fail"); + dmc->sysctl_new_error_inject = 0; + return NULL; + } + } + + if (check_new_error_inject(dmc, FORCED_MD_IO_JOB_ALLOC_FAIL)) { + if (mu_blk_flagged_any(mu_blk, MU_FORCED)) { + sprint("Simulate forced md io job alloc fail"); + dmc->sysctl_new_error_inject = 0; + return NULL; + } + } + + return new_kcached_job_md_io(dmc, mu_blk); +} + +static void handle_io_inprog_delay_error_inject(struct cache_c *dmc) +{ + while (check_new_error_inject(dmc, IO_INPROG_DELAY)) { + serr("Detect IO_INPROG_DELAY error inject, sleep 5 seconds"); + msleep(5000); + } +} + +static void send_md_ios_in_queue(struct cache_c *dmc, struct list_head *start, struct list_head *end) +{ + struct kcached_job *job = NULL; + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = NULL; + + handle_io_inprog_delay_error_inject(dmc); + + pos = start; + while (1) { + /* pos->next will only change AFTER pos/pos->next is submitted + * So it seems we don't need lock here? */ + tmp = pos->next; + mu_blk = container_of(pos, mu_blk_t, node); + atomic_inc(&mu->md_io_in_queue); + + job = alloc_md_io_job(dmc, mu_blk); + if (NULL == job) { + // TODO: stats here + serr("Failed to allocate kcached job for md io, idx %d", mu_blk->idx); + + spin_lock_irq(&dmc->cache_spin_lock); + /* mu should be io inprog. no one changes the state. + * Safe to check without lock */ + if (mu_blk_flagged_any(mu_blk, MU_FORCED) && + !mu_blk_flagged_any(mu_blk, MU_FORCED_RESTART)) { + handle_force_mu_io_error_do_pending(dmc, mu_blk, -EIO); + } + spin_unlock_irq(&dmc->cache_spin_lock); + + spin_lock_irq(&mu->lock); + handle_md_io_complete(dmc, mu_blk, -EIO); + handle_ext_flush_after_md_io(mu); + spin_unlock_irq(&mu->lock); + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } + } else { + syno_mu_send_md_io_from_job(job, mu_blk_test_clear_flag_any(mu_blk, MU_MD_IO_NEED_FUA)); + } + + if (pos == end) { + break; + } else { + pos = tmp; + } + } +} + +void syno_mu_send_md_ios_from_ext_flush(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, new_mu.ext_flush.send_io_work); + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *mu_blk = NULL; + struct list_head *pos1 = NULL; + struct list_head *pos2 = NULL; + ext_flush_t *ext_flush = &mu->ext_flush; + LIST_HEAD(queue); + + sdbg(DF_NEW_MU, "start send md ios for ext flush"); + + spin_lock_irq(&mu->lock); + list_for_each_safe(pos1, pos2, &ext_flush->md_io_pending_queue) { + mu_blk = container_of(pos1, mu_blk_t, node); + + if (sib_mu_blk_io_inprog(mu, mu_blk)) { + continue; + } + + list_del(&mu_blk->node); // from ext flush MIPQ + + mu_blk = setup_and_get_mu_blk_to_update(dmc, mu_blk); + + atomic_inc(&mu->md_io_to_queue); + mu_blk_set_flag(mu_blk, MU_SENT_BY_EXT_FLUSH); + mu->md_io_inprog_ext_flush++; + atomic_inc(&dmc->nr_jobs); + + list_add_tail(&mu_blk->node, &queue); + } + + pos1 = pos2 = NULL; + if (!list_empty(&queue)) { + pos1 = queue.next; + pos2 = queue.prev; + } + list_splice_tail_init(&queue, &ext_flush->md_io_inprog_queue); + spin_unlock_irq(&mu->lock); + + if (pos1) { + send_md_ios_in_queue(dmc, pos1, pos2); + } +} + +/* When there are too many md updates we force external IO to send one MU before endio */ +static void send_md_io_for_throtl_ext_io(struct cache_c *dmc) { + mu_blk_t *mu_blk = NULL; + new_mu_t *mu = &dmc->new_mu; + + spin_lock_irq(&mu->lock); + + mu_blk = first_valid_no_flush_mu_for_md_io(dmc); + + if (NULL == mu_blk) { + goto out_unlock; + } + + debug(mu); + list_del(&mu_blk->node); // from MIPQ + debug(mu); + + atomic_dec(&dmc->dmcg->md_io_pending_no_flush); + mu->md_io_pending_queue_size--; + + mu_blk = setup_and_get_mu_blk_to_update(dmc, mu_blk); + + atomic_inc(&mu->md_io_to_queue); + mu_blk_set_flag(mu_blk, MU_SENT_BY_THROTL); + mu->md_io_inprog_throtl++; + atomic_inc(&dmc->nr_jobs); + + debug(mu); + list_add_tail(&mu_blk->node, &mu->md_io_inprog_queue); + debug(mu); + +out_unlock: + spin_unlock_irq(&mu->lock); + + if (mu_blk) { + send_md_ios_in_queue(dmc, &mu_blk->node, &mu_blk->node); + } + + return; +} + +// in/out under mu lock +static void get_force_mu_to_send(struct cache_c *dmc, struct list_head *out) +{ + new_mu_t *mu = &dmc->new_mu; + mu_blk_t *flush_mu_blk = first_valid_flush_mu_for_md_io(mu); + + flush_mu_blk = first_valid_flush_mu_for_md_io(mu); + + while (flush_mu_blk && mu_blk_flagged_any(flush_mu_blk, MU_FORCED)) { + debug(mu); + list_del(&flush_mu_blk->node); // From MIFPQ + debug(mu); + + flush_mu_blk = setup_and_get_mu_blk_to_update(dmc, flush_mu_blk); + + atomic_inc(&mu->md_io_to_queue); + mu_blk_set_flag(flush_mu_blk, MU_SENT_BY_FORCE); + mu->md_io_inprog_force++; + atomic_inc(&dmc->nr_jobs); + + list_add_tail(&flush_mu_blk->node, out); + + flush_mu_blk = first_valid_flush_mu_for_md_io(mu); + } +} + +// in/out under mu lock +static void get_fua_mu_to_send(struct cache_c *dmc, struct list_head *out) +{ + new_mu_t *mu = &dmc->new_mu; + /* Handle fua MU without throttle */ + mu_blk_t *mu_blk = first_valid_no_flush_mu_for_md_io(dmc); + + while (mu_blk && mu_blk_flagged_any(mu_blk, MU_FUA)) { + list_del(&mu_blk->node); // From MIPQ + atomic_dec(&dmc->dmcg->md_io_pending_no_flush); + mu->md_io_pending_queue_size--; + + /* MU_HAS_PENDING_REQ should NEVER be set at this moment */ + if (check_new_error_inject(dmc, WRITE_FUA_TEST)) { + dmc->sysctl_new_error_inject = 0; + sprint("detect WRITE_FUA_TEST flag, simulate concurrent FUA writes"); + mu_blk_set_flag(mu_blk, MU_HAS_PENDING_REQ | MU_PENDING_REQ_FUA); + mu->pending_blk_num[MU_BLK_TYPE_NOFLUSH]++; + } + + mu_blk = setup_and_get_mu_blk_to_update(dmc, mu_blk); + + atomic_inc(&mu->md_io_to_queue); + mu_blk_set_flag(mu_blk, MU_SENT_BY_FUA); + mu->md_io_inprog_fua++; + atomic_inc(&dmc->nr_jobs); + + list_add_tail(&mu_blk->node, out); + + mu_blk = first_valid_no_flush_mu_for_md_io(dmc); + } +} + +// TODO: move force to standalone function +void syno_mu_send_md_ios(struct cache_c *dmc) +{ + mu_blk_t *mu_blk = NULL; + mu_blk_t *flush_mu_blk = NULL; + mu_blk_t *target_mu_blk = NULL; + new_mu_t *mu = &dmc->new_mu; + LIST_HEAD(queue); + struct list_head *start = NULL; + struct list_head *end = NULL; + + spin_lock_irq(&mu->lock); + + get_force_mu_to_send(dmc, &queue); + get_fua_mu_to_send(dmc, &queue); + + mu_blk = first_valid_no_flush_mu_for_md_io(dmc); + flush_mu_blk = first_valid_flush_mu_for_md_io(mu); + + while ((mu_blk || flush_mu_blk) && can_send_more_md_io(mu)) { + if (NULL == mu_blk) { + target_mu_blk = flush_mu_blk; + } else if (NULL == flush_mu_blk) { + target_mu_blk = mu_blk; + } else if (time_after(flush_mu_blk->tstamp, mu_blk->tstamp)) { + target_mu_blk = mu_blk; + } else { + target_mu_blk = flush_mu_blk; + } + + debug(mu); + list_del(&target_mu_blk->node); // From MIPQ or MIFPQ + debug(mu); + + if (!mu_blk_flagged_any(target_mu_blk, MU_NEED_FLUSH)) { + atomic_dec(&dmc->dmcg->md_io_pending_no_flush); + mu->md_io_pending_queue_size--; + } + + target_mu_blk = setup_and_get_mu_blk_to_update(dmc, target_mu_blk); + + atomic_inc(&mu->md_io_to_queue); + mu_blk_set_flag(target_mu_blk, MU_SENT_BY_NORMAL); + mu->md_io_inprog_normal++; + atomic_inc(&dmc->nr_jobs); + + debug(mu); + list_add_tail(&target_mu_blk->node, &queue); + debug(mu); + + mu_blk = first_valid_no_flush_mu_for_md_io(dmc); + flush_mu_blk = first_valid_flush_mu_for_md_io(mu); + } + + if (!list_empty(&queue)) { + start = queue.next; + end = queue.prev; + } + list_splice_tail_init(&queue, &mu->md_io_inprog_queue); + + spin_unlock_irq(&mu->lock); + + if (start) { + send_md_ios_in_queue(dmc, start, end); + } + + return; +} + +/* In under read lock, out under read lock */ +static void dmcg_throtl_rebalance(struct cache_c *dmc) +{ + dmc_group_t *dmcg = dmc->dmcg; + dmc_node *node = NULL; + struct list_head *pos = NULL; + struct cache_c *throtl_dmc = NULL; + int target_md_io_size = 0; + + up_read(&dmcg->rw_sem); + down_write(&dmcg->rw_sem); + + atomic_inc(&dmcg->rebalance_cnt); + + list_for_each(pos, &dmcg->dmc_list) { + node = container_of(pos, dmc_node, group_entry); + + if (!node->pdmc->new_mu.allow_throtl) { + continue; + } + + if (node->pdmc->new_mu.md_io_pending_queue_size > target_md_io_size) { + throtl_dmc = node->pdmc; + target_md_io_size = throtl_dmc->new_mu.md_io_pending_queue_size; + } + } + + dmcg->throtl_dmc = throtl_dmc; + downgrade_write(&dmcg->rw_sem); +} + +static inline int dmcg_throtl_need_rebalance(dmc_group_t *dmcg) +{ + return 0 == (atomic_inc_return(&dmcg->num_throtl_io) % DMCG_MU_THROTL_REBALANCE_THRES_IOS) || + NULL == dmcg->throtl_dmc; +} + +/* MUST not be in atomic context */ +void syno_mu_dmcg_throtl(struct cache_c *dmc) +{ + dmc_group_t *dmcg = dmc->dmcg; + struct cache_c *throtl_dmc = NULL; + + /* Temporary incorrect thres value shouldn't be a problem, don't lock */ + if (!dmcg_need_throtl_for_md_io(dmcg)) { + return; + } + + down_read(&dmcg->rw_sem); + if (dmcg_throtl_need_rebalance(dmcg)) { + dmcg_throtl_rebalance(dmc); + } + + if (NULL == dmcg->throtl_dmc) { + goto end_unlock; + } + + if (FLASHCACHE_WRITE_BACK == dmc->cache_mode && + md_io_above_per_cache_throtl_thres(dmc)) { + /* dmc itself need throttle */ + throtl_dmc = dmc; + atomic_inc(&dmc->new_mu.throtl_self); + } else { + throtl_dmc = dmcg->throtl_dmc; + atomic_inc(&dmc->new_mu.throtl_help); + } + + send_md_io_for_throtl_ext_io(throtl_dmc); + +end_unlock: + up_read(&dmcg->rw_sem); +} + +void syno_mu_disable_dmcg_throtl(struct cache_c *dmc) +{ + new_mu_t *mu = &dmc->new_mu; + + down_write(&dmc->dmcg->rw_sem); + + if (dmc->cache_mode != FLASHCACHE_WRITE_BACK) { + goto out_unlock; + } + + /* Prevent other dmc from selecting this dmc as the target */ + mu->allow_throtl = 0; + + if (dmc->dmcg->throtl_dmc == dmc) { + dmc->dmcg->throtl_dmc = NULL; + } + +out_unlock: + up_write(&dmc->dmcg->rw_sem); +} + +#endif /* MY_ABC_HERE */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_md_update.h b/drivers/syno/syno-mem-saving-driver/syno_md_update.h new file mode 100644 index 000000000000..b0520901cc73 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_md_update.h @@ -0,0 +1,27 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifndef __SYNO_MD_UPDATE_H__ +#define __SYNO_MD_UPDATE_H__ + +#include "flashcache.h" + +// REMOVE FOR GPL RELEASE +#ifdef MY_ABC_HERE +void syno_mu_queue_no_flush_update(struct cache_c *dmc, struct kcached_job *job); +void syno_mu_queue_no_flush_fua_update(struct cache_c *dmc, struct kcached_job *job); +void syno_mu_queue_flush_update(struct cache_c *dmc, int cb_idx); +void syno_mu_queue_force_update(struct cache_c *dmc, int cb_idx); +void syno_mu_disk_flush_complete(struct work_struct *work); +void syno_mu_ssd_flush_complete(struct work_struct *work); +void syno_mu_do_md_update(struct work_struct *work); +void syno_mu_md_io_complete(struct work_struct *work); +void syno_mu_start_ext_flush(struct cache_c *dmc, struct bio *flush_bio, unsigned long start_jiffy); +void syno_mu_flush_all_synced_sync(struct cache_c *dmc); +void syno_mu_flush_all_for_remove_sync(struct cache_c *dmc); +void syno_mu_send_md_ios_from_ext_flush(struct work_struct *work); +void syno_mu_disable_dmcg_throtl(struct cache_c *dmc); +void syno_mu_dmcg_throtl(struct cache_c *dmc); + +#endif /* MY_ABC_HERE */ +#endif /* __SYNO_MD_UPDATE_H__ */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_quickflush.c b/drivers/syno/syno-mem-saving-driver/syno_quickflush.c new file mode 100644 index 000000000000..c7314389c3f8 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_quickflush.c @@ -0,0 +1,1497 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include + +#include "flashcache.h" +#include "syno_quickflush.h" +#ifdef MY_ABC_HERE +#include "syno_md_update.h" +#endif + +extern struct dm_kcopyd_client *flashcache_kcp_client; +extern unsigned long hash_block(struct cache_c *dmc, sector_t dbn); +extern void flashcache_sync_blocks(struct cache_c *dmc); +extern struct mutex nqf_mem_mtx; + +extern struct delayed_work nqf_mgmt_work; +extern struct list_head dmc_group_list; +extern struct mutex dmcg_mtx; + +// REMOVE THE FILE FOR GPL RELEASE +#ifdef MY_ABC_HERE + +/* Must in plug_wb lock */ +static inline int +ios_can_issue_plug_wb(struct cache_c* dmc, int nr_write) +{ + return (nr_write + dmc->plug_wb.ssd_read_inprog) <= dmc->plug_wb.ssd_read_ios_limit; +} + +static void inline reset_plug_wb_param_to_nqf(struct cache_c *dmc) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&dmc->plug_wb.lock, flags); + /* SSD read is used for throttling by userspace, don't touch it */ + dmc->plug_wb.disk_write_ios_limit = PLUG_WB_DEFAULT_DISK_WRITE; + spin_unlock_irqrestore(&dmc->plug_wb.lock, flags); +} + +/* MUST use INSIDE oqf mtx */ +void +flashcache_clean_sync_state(struct cache_c *dmc) +{ + VERIFY_WARN(0 == dmc->oqf.sync_trigger_cnt); + VERIFY_WARN(dmc->oqf.sync_state == SYNC_STATE_RUNNING); + + /* only change the value after no io left in queue */ + dmc->oqf.bit_idx = 0; + reset_plug_wb_param_to_nqf(dmc); + dmc->oqf.sync_state = SYNC_STATE_STOPPED; + atomic_dec(&dmc->dmcg->sqf_inprog); + wake_up(&dmc->sync_wqh); +} + +/* use INSIDE cache_spin_lock */ +int +quickflush_find_cacheblk_idx(struct cache_c *dmc, unsigned long long disk_blk_idx) +{ + int i = 0; + int ret = -1; + sector_t sector = QF_BLK_IDX_TO_SEC(disk_blk_idx); + unsigned long set_number = hash_block(dmc, sector); + int start_index = dmc->assoc * set_number; + + for (i = start_index; i < start_index + dmc->assoc; ++i) { + if (dmc->cache[i].dbn == sector && (dmc->cache[i].cache_state & VALID)) { + ret = i; + break; + } + } + + return ret; +} + +/* in bitmap_rwsem w lock */ +void +quickflush_construct_bitmap(struct cache_c *dmc) +{ + int i = 0; + + /* Bitmap serves as a hint, not need to lock for 100% correctnes */ + for (i = 0; i < dmc->size; ++i) { + if ((dmc->cache[i].cache_state & DIRTY)) { + quickflush_set_volume_map(dmc, &dmc->cache[i]); + } + } +} + +/* MUST be in cache_spin_lock */ +int +quickflush_cacheblk_get_nr_writeback(struct cache_c *dmc, int index) +{ + int nr_io = 1; + struct cacheblock *cacheblk = &dmc->cache[index]; + bitmap_t tmp_data = cacheblk->data_bitmap; + bitmap_t tmp_dirty = cacheblk->dirty_bitmap; + int can_merge = 0; + + while (tmp_dirty) { + if (tmp_dirty & 1) { + can_merge = 1; + } + if (!(tmp_data & 1)) { + if (can_merge) { + can_merge = 0; + nr_io++; + } + } + tmp_dirty >>= 1; + tmp_data >>= 1; + } + + return nr_io; +} + +static void +quickflush_wb_done(struct kcached_job *job) +{ + struct cache_c *dmc = job->dmc; + int i = 0; + int index = job->index; + struct cacheblock *cacheblk = &dmc->cache[index]; + int offset_bit = compatible_div((job->job_io_regions.disk.sector - cacheblk->dbn), SECTOR_PER_BIT); + int size_bit = compatible_div(job->job_io_regions.disk.count, SECTOR_PER_BIT); + bitmap_t done_bitmap = 0; +#ifdef MY_ABC_HERE + int sync = job->action == WRITEDISK_SYNC; +#endif + + VERIFY_WARN(!in_interrupt()); + VERIFY_WARN(job->bio == NULL); + + for (i = 0; i < size_bit; ++i) { + done_bitmap |= 1 << (offset_bit + i); + } + + spin_lock_irq(&dmc->cache_spin_lock); + VERIFY_WARN((cacheblk->cache_state & (DISKWRITEINPROG | VALID | DIRTY)) + == (DISKWRITEINPROG | VALID | DIRTY)); + cacheblk->flushing_dirty_bitmap &= ~(done_bitmap); + + if (check_new_error_inject(dmc, OQF_WB_ERROR)) { + sprint("Simulate oqf write back error"); + dmc->sysctl_new_error_inject = 0; + job->error = -EIO; + } + + if (job->error) { + cb_state_add_bits_update_counts(dmc, cacheblk, QFSYNCERR); + } + + if (cacheblk->flushing_dirty_bitmap) { + /* Not the last sub job */ + VERIFY_WARN(0 != cacheblk_dec_num_concurrent_and_return(cacheblk)); + spin_unlock_irq(&dmc->cache_spin_lock); + flashcache_free_cache_job(job); + if (atomic_dec_and_test(&dmc->nr_jobs)) { + /* Not the last job, should not enter here */ + serr("not last job but nr_job is zero"); + } + goto end; + } + + /* only the last sub job enter here */ + VERIFY_WARN(cacheblk->nr_concurrent == 1); + + atomic64_inc(&dmc->flashcache_stats.dirty_writeback_done); + if (unlikely(cacheblk->cache_state & QFSYNCERR)) { + cb_state_remove_bits_update_counts(dmc, cacheblk, QFSYNCERR); + spin_unlock_irq(&dmc->cache_spin_lock); + /* Now all io are -EIO, we dont need to distinguish read/write */ + job->error = -EIO; + flashcache_do_pending(job); + atomic64_inc(&dmc->flashcache_stats.cleanings); + goto err; + } + +#ifdef MY_ABC_HERE + /* If there are queued io, the block IS going to be invalidated in + * the writeback case, i.e., we will sent a force mu in do_pending + * since the block is SYNCED. Force the md update directly */ + if (cacheblk->nr_queued) { + spin_unlock_irq(&dmc->cache_spin_lock); + // TODO: io latency will be lost. But I guess we don't care about it? + syno_mu_queue_force_update(dmc, index); + } else { + VERIFY_WARN(!(job->flag & JOB_WB_FORCED)); + spin_unlock_irq(&dmc->cache_spin_lock); + + while (check_new_error_inject(dmc, WB_MU_REQUEUE_FORCED_TEST)) { + sprint("Detect wb mu requeue force test, wait"); + msleep(5000); + if (cacheblk->nr_queued) { + sprint("Detect Queued, continue"); + dmc->sysctl_new_error_inject = 0; + } + } + + /* States/nr_dirty set in function. + * Other IO might queue since we unlocked! */ + syno_mu_queue_flush_update(dmc, index); + } + + flashcache_free_cache_job(job); + if (atomic_dec_and_test(&dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } + + atomic64_inc(&dmc->flashcache_stats.cleanings); + if (sync) { + flashcache_update_sync_progress(dmc); + } +#else + spin_unlock_irq(&dmc->cache_spin_lock); + // Start metadata update + flashcache_md_write(job); +#endif + +end: +err: + return; +} + +void +quickflush_get_next_io_range(bitmap_t data_bitmap, bitmap_t *dirty_bitmap, sector_t *offset, sector_t *size) +{ + int i = 1; + int first_dirty_offset = -1; + int last_dirty_offset = -1; + + VERIFY_WARN(*dirty_bitmap); + + for (i = 0; i < BITMAP_BITS; ++i) { + if ((*dirty_bitmap) & (1 << i)) { + if (-1 == first_dirty_offset) { + first_dirty_offset = i; + } + last_dirty_offset = i; + *dirty_bitmap &= ~(1 << i); + if (!(*dirty_bitmap)) { + break; + } + } + + if (-1 != first_dirty_offset) { + if (!(data_bitmap & (1 << i))) { + break; + } + } + } + + *offset = first_dirty_offset * SECTOR_PER_BIT; + *size = (last_dirty_offset - first_dirty_offset + 1) * SECTOR_PER_BIT; + + VERIFY_WARN(0 != *size); +} + +static inline void +add_writeback_stats(struct cache_c *dmc, int nr_write, sector_t total_size, int sync) +{ + atomic64_inc(&dmc->flashcache_stats.dirty_writeback_start); + atomic64_add(nr_write, &dmc->flashcache_stats.qf_nr_writes); + atomic64_add(nr_write, &dmc->flashcache_stats.ssd_reads); + atomic64_add(nr_write, &dmc->flashcache_stats.disk_writes); + if (sync) { + atomic64_add(total_size, &dmc->flashcache_stats.dirty_writeback_sync_sector); + } else { + atomic64_add(total_size, &dmc->flashcache_stats.dirty_writeback_sector); + } +} + +static void +wb_disk_write_callback(unsigned long error, void *ctx) +{ + unsigned long flags = 0; + struct kcached_job *job = ctx; + struct cache_c *dmc = job->dmc; + plug_wb_t *plug_wb = &dmc->plug_wb; + + if (check_new_error_inject(dmc, WB_DISK_WRITE_ERROR)) { + sprint("Simulate wb disk write error sync: %d", job->action == WRITEDISK_SYNC); + dmc->sysctl_new_error_inject = 0; + error = 1; + } + + if (error) { + job->error = -EIO; + if (0 < dmc->limits.writeback_sync_err) { + serr("plub wb write fail. block %llu", + (u64)job->job_io_regions.disk.sector); + dmc->limits.writeback_sync_err--; + } + atomic_inc(&dmc->flashcache_errors.disk_write_errors); + } + + spin_lock_irqsave(&plug_wb->lock, flags); + list_add_tail(&job->list, &plug_wb->complete_queue); + plug_wb->disk_write_inprog--; + spin_unlock_irqrestore(&plug_wb->lock, flags); + + cache_schedule_work(&plug_wb->work); +} + +void +quickflush_process_wb_done(struct work_struct *wb_done_work) +{ + struct cache_c *dmc = container_of(wb_done_work, struct cache_c, plug_wb.wb_done_work); + plug_wb_t *plug_wb = &dmc->plug_wb; + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + struct kcached_job *job = NULL; + int sync_trigger = 0; + int nqf_trigger = 0; + LIST_HEAD(list); + + spin_lock_irq(&plug_wb->lock); + list_splice_init(&plug_wb->wb_done_queue, &list); + spin_unlock_irq(&plug_wb->lock); + + list_for_each_safe(pos, tmp, &list) { + job = container_of(pos, struct kcached_job, list); + + list_del(pos); + + if (job->action == WRITEDISK_SYNC) { + sync_trigger++; + } else if (job->flag & JOB_WB_NQF) { + nqf_trigger++; + } else { + if (!(job->flag & JOB_WB_FORCED)) { + serr("job->action: %d job->flag %x dmc: %p", job->action, job->flag, dmc); + VERIFY_WARN(0); + } + } + + quickflush_wb_done(job); + } + + /* sync and oqf should not run in parallel */ + VERIFY_WARN(!(sync_trigger && nqf_trigger)); + + mutex_lock(&dmc->oqf.mtx); + if (nqf_trigger) { + dmc->oqf.trigger_cnt -= (nqf_trigger - 1); + } else if (sync_trigger) { + dmc->oqf.sync_trigger_cnt -= (sync_trigger - 1); + } else if (dmc->oqf.sync_trigger_cnt) { + /* Optimization: + * When ssd read batch finished and sent disk write we need to + * send more ssd read and find new batch. Normally this is done + * in disk write finish callback. Trigger it manually if no disk write finish */ + sync_trigger = 1; + dmc->oqf.sync_trigger_cnt++; + } + mutex_unlock(&dmc->oqf.mtx); + + if (nqf_trigger) { + syno_start_nqf(dmc); + } else if (sync_trigger) { + syno_start_sqf(dmc); + } +} + +static void +process_complete_queue(plug_wb_t *plug_wb) +{ + LIST_HEAD(list); + struct list_head *pos = NULL; + struct kcached_job *job = NULL; + + spin_lock_irq(&plug_wb->lock); + list_splice_init(&plug_wb->complete_queue, &list); + spin_unlock_irq(&plug_wb->lock); + + list_for_each(pos, &list) { + job = container_of(pos, struct kcached_job, list); + + VERIFY_WARN(job->action == WRITEDISK || job->action == WRITEDISK_SYNC); + + flashcache_free_cache_job_mem(job); + } + + spin_lock_irq(&plug_wb->lock); + list_splice(&list, &plug_wb->wb_done_queue); + spin_unlock_irq(&plug_wb->lock); + + cache_schedule_work(&plug_wb->wb_done_work); +} + +static inline void +wb_send_disk_write(struct list_head *list) +{ + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + struct kcached_job *job = NULL; + unsigned long bi_flags = 0; + + /* Use safe version since job can be removed from list once io sent */ + list_for_each_safe(pos, tmp, list) { + job = container_of(pos, struct kcached_job, list); + bi_flags = job->action == WRITEDISK_SYNC ? (1 << BIO_SYNO_FULL_STRIPE_MERGE) : 0; + + dm_io_vmem(1, &job->job_io_regions.disk, WRITE, job->mem_addr, + wb_disk_write_callback, job, bi_flags); + } +} + +static inline void +handle_error_or_append_to_disk_write_list(plug_wb_t *plug_wb, struct kcached_job *job, struct list_head *dwl) +{ + plug_wb->ssd_read_inprog--; + + if (job->error) { + list_add_tail(&job->list, &plug_wb->complete_queue); + } else { + // append to disk write list + list_add_tail(&job->list, dwl); + plug_wb->disk_write_inprog++; + } +} + +static void +process_io_queue(plug_wb_t *plug_wb) +{ + LIST_HEAD(list); + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + struct kcached_job *job = NULL; + + spin_lock_irq(&plug_wb->lock); + + list_for_each_safe(pos, tmp, &plug_wb->io_queue) { + job = container_of(pos, struct kcached_job, list); + + VERIFY_WARN(job->flag & JOB_WB_READ_DONE); + + /* FORCED job is guaranteed to be at the head of the queue + * No other thorttling needed for online wb / force wb */ + if (!(job->flag & JOB_WB_FORCED) && + plug_wb->disk_write_inprog >= plug_wb->disk_write_ios_limit) { + /* forced job not throttled */ + break; + } + + list_del(pos); + + handle_error_or_append_to_disk_write_list(plug_wb, job, &list); + } + + spin_unlock_irq(&plug_wb->lock); + + wb_send_disk_write(&list); +} + +static inline int +must_send_batch_under_ios_throtl(plug_wb_t *plug_wb) +{ + return 0 == plug_wb->disk_write_inprog; +} + +static inline int +can_send_batch_under_ios_throtl(struct cache_c *dmc, plug_wb_t *plug_wb) +{ + return (plug_wb->disk_write_inprog + plug_wb->cur_batch_len + + atomic_read(&dmc->num_master_io)) <= plug_wb->disk_write_ios_limit; +} + +static inline int +can_send_disk_write_under_ios_throtl(struct cache_c *dmc, plug_wb_t *plug_wb) +{ + return (plug_wb->disk_write_inprog + atomic_read(&dmc->num_master_io)) < + plug_wb->disk_write_ios_limit; +} + +static void +process_sync_io_queue(plug_wb_t *plug_wb) +{ + LIST_HEAD(list); + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + struct kcached_job *job = NULL; + struct cache_c *dmc = container_of(plug_wb, struct cache_c, plug_wb); + + spin_lock_irq(&plug_wb->lock); + if (!(PLUG_WB_HAS_BATCH_AND_DISK_WRITE_READY(plug_wb))) { + goto end_unlock; + } + + /* The throttle rules: + * 1. Limit disk IO to disk_write_ios_limit, assume all external IO touches disk + * 2. If no disk write in progess, send a batch of io (incase no one triggers wb after that) */ + if (!must_send_batch_under_ios_throtl(plug_wb) && + !can_send_batch_under_ios_throtl(dmc, plug_wb)) { + goto end_unlock; + } + + list_for_each_safe(pos, tmp, &plug_wb->sync_io_queue) { + job = container_of(pos, struct kcached_job, list); + + if (!(job->flag & JOB_WB_READ_DONE)) { + break; + } + + /* Send extra IO after batch if SSD_READ_DONE and pass throttle */ + if (0 != plug_wb->cur_batch_len) { + /* Disk write in this batch already checked throtl cond */ + plug_wb->cur_batch_len--; + } else if (!can_send_disk_write_under_ios_throtl(dmc, plug_wb)) { + break; + } + + list_del(pos); + handle_error_or_append_to_disk_write_list(plug_wb, job, &list); + atomic64_inc(&dmc->flashcache_stats.qf_queued_sync_io_processed); + } + + VERIFY_WARN(0 == plug_wb->cur_batch_len); + +end_unlock: + spin_unlock_irq(&plug_wb->lock); + + wb_send_disk_write(&list); +} + +/* + * Find new batch, queue it if all io in batch are ssd read done + */ +static void sync_wb_handle_batch(plug_wb_t *plug_wb) +{ + unsigned long flags = 0; + struct list_head *pos = NULL; + struct kcached_job *job = NULL; + + spin_lock_irqsave(&plug_wb->lock, flags); + if (PLUG_WB_HAS_BATCH(plug_wb) || list_empty(&plug_wb->sync_io_queue)) { + goto end_unlock; + } + + VERIFY_WARN(0 == plug_wb->cur_batch_len); + VERIFY_WARN(0 == plug_wb->unfinished_read_in_batch); + + job = container_of(plug_wb->sync_io_queue.next, struct kcached_job, list); + plug_wb->cur_batch_head = job->wb_seq; + + list_for_each(pos, &plug_wb->sync_io_queue) { + job = container_of(pos, struct kcached_job, list); + + plug_wb->cur_batch_len++; + if (!(job->flag & JOB_WB_READ_DONE)) { + plug_wb->unfinished_read_in_batch++; + } + + if (plug_wb->cur_batch_len == plug_wb->batch_size) { + break; + } + } + + if (plug_wb->cur_batch_len && 0 == plug_wb->unfinished_read_in_batch) { + /* All ready, start next writeback */ + cache_schedule_work(&plug_wb->work); + } + +end_unlock: + spin_unlock_irqrestore(&plug_wb->lock, flags); +} + +/* Main function for plug wb. + * WARNING: The threads is responsible for releasing job mempool memory + * MUST NOT block trying to get memory from job mempool. (e.g., call syno_start_sqf) */ +void +quickflush_process_wb_ios(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, plug_wb.work); + plug_wb_t *plug_wb = &dmc->plug_wb; + struct blk_plug plug; + + /* Disk writes should be flushed */ + blk_start_plug(&plug); + process_io_queue(plug_wb); + process_sync_io_queue(plug_wb); + blk_finish_plug(&plug); + + /* Free memory and schedule callback work, MUST put at the end */ + process_complete_queue(plug_wb); +} + +static inline int job_in_current_batch(plug_wb_t *plug_wb, struct kcached_job *job) +{ + VERIFY_WARN(job->wb_seq >= plug_wb->cur_batch_head); + return (PLUG_WB_HAS_BATCH(plug_wb) && + job->wb_seq < plug_wb->cur_batch_head + plug_wb->cur_batch_len); +} + +static void +wb_ssd_read_callback(unsigned long error, void *ctx) +{ + unsigned long flags; + struct kcached_job *job = ctx; + struct cache_c *dmc = job->dmc; + int sync = (job->action == WRITEDISK_SYNC); + int schedule_work = 0; + plug_wb_t *plug_wb = &job->dmc->plug_wb; + + spin_lock_irqsave(&plug_wb->lock, flags); + + /* no need to distinguish sync, sync/normal wb is + * unlikely to happen at the same time */ + if (check_new_error_inject(dmc, WB_SSD_READ_ERROR)) { + sprint("Simulate writeback ssd read error, sync: %d", sync); + dmc->sysctl_new_error_inject = 0; + error = 1; + } + + job->flag |= JOB_WB_READ_DONE; + + if (sync) { + if (job_in_current_batch(plug_wb, job)) { + plug_wb->unfinished_read_in_batch--; + if (0 == plug_wb->unfinished_read_in_batch) { + schedule_work = 1; + } + } + } else { + // TODO: use standalone queue for forced job so the order won't be reversed + if (job->flag & JOB_WB_FORCED) { + list_add(&job->list, &plug_wb->io_queue); + } else { + // TODO: will preserve perfect order for nqf help? + // scheduler are expected to handle that case + list_add_tail(&job->list, &plug_wb->io_queue); + } + schedule_work = 1; + } + + if (unlikely(error)) { + if (0 < job->dmc->limits.writeback_sync_err) { + serr("plub wb read fail. block %llu", + (u64)job->job_io_regions.cache.sector); + job->dmc->limits.writeback_sync_err--; + } + atomic_inc(&job->dmc->flashcache_errors.ssd_read_errors); + job->error = -EIO; + } + + spin_unlock_irqrestore(&plug_wb->lock, flags); + + if (schedule_work) { + cache_schedule_work(&plug_wb->work); + } +} + +static void _wb_send_ssd_read_from_jobs(plug_wb_t *plug_wb, struct list_head *job_list, int sync) +{ + struct kcached_job *job = NULL; + struct list_head *pos = NULL; + struct list_head *start = job_list->next; + struct list_head *end = job_list->prev; + + if (list_empty(job_list)) { + return; + } + + spin_lock_irq(&plug_wb->lock); + + list_for_each(pos, job_list) { + job = container_of(pos, struct kcached_job, list); + if (sync) { + job->wb_seq = plug_wb->seq++; + } + } + + if (sync) { + list_splice_tail(job_list, &plug_wb->sync_io_queue); + } // not sync jobs add to io queue after read done + spin_unlock_irq(&plug_wb->lock); + + /* + * No need to lock even if start/end are in sync_io_queue + * As long as the ssd read IO is not sent, the list of job won't be changed + * Record start->next before sending ssd read since 'start' may be removed after that + */ + while (1) { + pos = start->next; + job = container_of(start, struct kcached_job, list); + + dm_io_vmem(1, &job->job_io_regions.cache, READ, + job->mem_addr, wb_ssd_read_callback, job, 0); + + if (start == end) { + break; + } + start = pos; + } +} + +static inline void +wb_send_ssd_read_from_jobs(plug_wb_t *plug_wb, struct list_head *job_list) +{ + _wb_send_ssd_read_from_jobs(plug_wb, job_list, 0); +} + +static inline void +wb_send_ssd_read_from_jobs_sync(plug_wb_t *plug_wb, struct list_head *job_list) +{ + _wb_send_ssd_read_from_jobs(plug_wb, job_list, 1); +} + +static inline void +verify_wb_states(struct cacheblock *cb, int nr_write) +{ + VERIFY_WARN((cb->cache_state & FALLOW_DOCLEAN) == 0); + VERIFY_WARN((cb->cache_state & BLOCK_IO_INPROG) == DISKWRITEINPROG); + VERIFY_WARN(cb->cache_state & DIRTY); + VERIFY_WARN(cb->flushing_dirty_bitmap == 0); + VERIFY_WARN(cb->nr_concurrent == nr_write); +} + +/* Newly allocated jobs are append to out */ +static void +quickflush_wb_jobs_alloc_common(struct cache_c *dmc, cb_wb_param_t param, int sync, struct list_head *out) +{ + LIST_HEAD(list); + struct list_head *pos = NULL; + struct list_head *tmp_list = NULL; + struct kcached_job *tmp_job = NULL; + const int nr_write = param.nr_write; + const int index = param.idx; + int cur_write = 0; + int device_removal = 0; + struct cacheblock *cacheblk = &dmc->cache[index]; + bitmap_t dirty_bitmap = 0; + sector_t offset = 0; + sector_t size = 0; + sector_t total_size = 0; + plug_wb_t *plug_wb = &dmc->plug_wb; + + verify_wb_states(cacheblk, nr_write); + + /* WRITEDISK* flag set for this cb, status shouldn't be changed by + * others, no need to lock */ + cacheblk->flushing_dirty_bitmap = cacheblk->dirty_bitmap; + + dirty_bitmap = cacheblk->dirty_bitmap; + + while (dirty_bitmap) { + quickflush_get_next_io_range(cacheblk->data_bitmap, &dirty_bitmap, &offset, &size); + total_size += size; + + if (sync) { + tmp_job = new_kcached_job_qf(dmc, index, offset, size, TYPE_SQF); + } else { + tmp_job = new_kcached_job_qf(dmc, index, offset, size, TYPE_NQF); + } + + + if (unlikely(dmc->sysctl_error_inject & QF_ALLOC_WRITEBACK_JOB_ERROR)) { + dmc->sysctl_error_inject &= ~(QF_ALLOC_WRITEBACK_JOB_ERROR); + if (tmp_job) { + flashcache_free_cache_job(tmp_job); + tmp_job = NULL; + } + } + + if (unlikely(tmp_job == NULL)) { + serr("Failed to allocate job for quickflush writeback, block %llu", + (u64)cacheblk->dbn); + break; + } + + tmp_job->bio = NULL; + tmp_job->action = sync ? WRITEDISK_SYNC : WRITEDISK; + tmp_job->flag |= param.job_flag; + list_add_tail(&tmp_job->list, &list); + cur_write++; + } + + if (sync) { + device_removal = (atomic_read(&dmc->remove_in_prog) == FAST_REMOVE) ? 1 : 0; + } else { + device_removal = atomic_read(&dmc->remove_in_prog) ? 1 : 0; + } + + if (device_removal) { + sprint("qucikflush writeback aborted for device removal, block %llu", + (u64)cacheblk->dbn); + } + + if (unlikely(cur_write != nr_write || device_removal)) { + spin_lock_irq(&dmc->cache_spin_lock); + flashcache_free_pending_jobs(dmc, cacheblk, -EIO); + cacheblk->flushing_dirty_bitmap = 0; + unset_partial_cb_writeback_attrs(dmc, cacheblk, nr_write); + spin_unlock_irq(&dmc->cache_spin_lock); + + mutex_lock(&dmc->oqf.mtx); + if (sync) { + dmc->oqf.sync_trigger_cnt -= nr_write; + /* always called by sync sorted block, trigger shouldn't be zero */ + VERIFY_WARN(0 < dmc->oqf.sync_trigger_cnt); + } else if(param.job_flag & JOB_WB_NQF) { + dmc->oqf.trigger_cnt -= nr_write; + VERIFY_WARN(0 < dmc->oqf.trigger_cnt); + } + mutex_unlock(&dmc->oqf.mtx); + + list_for_each_safe(pos, tmp_list, &list) { + tmp_job = container_of(pos, struct kcached_job, list); + flashcache_free_cache_job(tmp_job); + } + + spin_lock_irq(&plug_wb->lock); + plug_wb->ssd_read_inprog -= nr_write; + spin_unlock_irq(&plug_wb->lock); + + if (atomic_sub_and_test(nr_write, &dmc->nr_jobs)) { + wake_up(&dmc->sync_wqh); + } + } else { + add_writeback_stats(dmc, nr_write, total_size, sync); + list_splice_tail(&list, out); + } +} + +static inline void +quickflush_wb_job_alloc_sync(struct cache_c *dmc, cb_wb_param_t param, struct list_head *out) +{ + return quickflush_wb_jobs_alloc_common(dmc, param, 1, out); +} + +static inline void +quickflush_wb_job_alloc(struct cache_c *dmc, cb_wb_param_t param, struct list_head *out) +{ + return quickflush_wb_jobs_alloc_common(dmc, param, 0, out); +} + +static void +sync_wb_send_ssd_read(struct cache_c *dmc, cb_wb_param_t *cb_wb_param_list, int nr_blk) +{ + int i = 0; + LIST_HEAD(job_list); + + for (i = 0; i < nr_blk; ++i) { + quickflush_wb_job_alloc_sync(dmc, cb_wb_param_list[i], &job_list); + } + + wb_send_ssd_read_from_jobs_sync(&dmc->plug_wb, &job_list); +} + +void +quickflush_dirty_writeback(struct cache_c *dmc, cb_wb_param_t wb_param) +{ + LIST_HEAD(job_list); + + /* Lock here to avoid deadlock from multiple dmc allocating from mempool + * since writing back a cb might requires multiple job & mem. */ + mutex_lock(&nqf_mem_mtx); + quickflush_wb_job_alloc(dmc, wb_param, &job_list); + mutex_unlock(&nqf_mem_mtx); + + wb_send_ssd_read_from_jobs(&dmc->plug_wb, &job_list); +} + +static inline int +find_cb_check_can_fallow_wb(struct cache_c *dmc, u64 vb_idx) +{ + int cb_idx = quickflush_find_cacheblk_idx(dmc, vb_idx); + + if (-1 == cb_idx || !(dmc->cache[cb_idx].cache_state & DIRTY_FALLOW_2)) { + return -1; + } + + VERIFY_WARN(0 == (dmc->cache[cb_idx].cache_state & BLOCK_IO_INPROG)); + + return cb_idx; +} + +static inline int +find_cb_check_can_sync_wb(struct cache_c *dmc, u64 vb_idx) +{ + int cb_idx = quickflush_find_cacheblk_idx(dmc, vb_idx); + + if (-1 == cb_idx || !(dmc->cache[cb_idx].cache_state & DIRTY) + || dmc->cache[cb_idx].cache_state & BLOCK_IO_INPROG) { + VERIFY_WARN(cb_idx == -1 || !(dmc->cache[cb_idx].cache_state & DIRTY_FALLOW_2)); + return -1; + } + + return cb_idx; +} + +/* return 0: can send more io, continue on next unit. 1: reach io limit. */ +static int +_get_cbs_to_wb_from_bit(struct cache_c *dmc, int *nr_blk, + cb_wb_param_t *cb_param_list, int param_list_size, int sync) +{ + int i = 0; + int ret = 0; + online_qf_t *oqf = &dmc->oqf; + int cb_idx = -1; + const int init_nr_blk = *nr_blk; + int new_writes = 0; + unsigned long wb_flags = 0; + u64 vb_idx = oqf->bit_idx * OQF_VB_PER_BIT; + int (*find_cb_check_can_wb)(struct cache_c*, u64) = + sync ? find_cb_check_can_sync_wb : find_cb_check_can_fallow_wb; + + up_read(&oqf->bitmap_rwsem); + down_write(&oqf->bitmap_rwsem); + mutex_lock(&oqf->mtx); + spin_lock_irq(&dmc->cache_spin_lock); + + for (i = 0; i < OQF_VB_PER_BIT; ++i, ++vb_idx) { + + if (-1 == (cb_idx = find_cb_check_can_wb(dmc, vb_idx))) { + continue; + } + + new_writes = quickflush_cacheblk_get_nr_writeback(dmc, cb_idx); + spin_lock_irqsave(&dmc->plug_wb.lock, wb_flags); + if (*nr_blk < param_list_size && ios_can_issue_plug_wb(dmc, new_writes)) { + cb_param_list[*nr_blk].idx = cb_idx; + cb_param_list[*nr_blk].nr_write = new_writes; + if (!sync) { + cb_param_list[*nr_blk].job_flag |= JOB_WB_NQF; + } + (*nr_blk)++; + set_wb_attrs(dmc, cb_idx, new_writes); + spin_unlock_irqrestore(&dmc->plug_wb.lock, wb_flags); + + if (sync) { + oqf->sync_trigger_cnt += new_writes; + } else { + oqf->trigger_cnt += new_writes; + } + } else { + spin_unlock_irqrestore(&dmc->plug_wb.lock, wb_flags); + ret = 1; + break; + } + + } + + if (!ret) { + if (init_nr_blk == *nr_blk) { + atomic64_inc(&dmc->flashcache_stats.qf_bits_mismatch); + } + quickflush_unset_volume_map(dmc, oqf->bit_idx); + } + + spin_unlock_irq(&dmc->cache_spin_lock); + mutex_unlock(&oqf->mtx); + downgrade_write(&oqf->bitmap_rwsem); + + return ret; +} +static int +get_cbs_to_wb_from_bit_sync(struct cache_c *dmc, int *nr_blk, + cb_wb_param_t *cb_param_list, int param_list_size) +{ + return _get_cbs_to_wb_from_bit(dmc, nr_blk, cb_param_list, param_list_size, 1); +} + +static int +get_cbs_to_wb_from_bit(struct cache_c *dmc, int *nr_blk, + cb_wb_param_t *cb_param_list, int param_list_size) +{ + return _get_cbs_to_wb_from_bit(dmc, nr_blk, cb_param_list, param_list_size, 0); +} + +static inline int +skip_sqf(struct cache_c *dmc) +{ + + if ((atomic_read(&dmc->remove_in_prog) == FAST_REMOVE) || dmc->sysctl_stop_sync) { + return 1; + } + + return 0; +} + +static inline cb_wb_param_t* +alloc_wb_param_list(struct cache_c *dmc, int list_size) +{ + cb_wb_param_t *list = NULL; + + list = kzalloc(sizeof(cb_wb_param_t) * list_size, GFP_NOIO); + if (unlikely(dmc->sysctl_error_inject & QF_ALLOC_CACHEBLK_TO_CLEAN_ERROR)) { + dmc->sysctl_error_inject &= ~(QF_ALLOC_CACHEBLK_TO_CLEAN_ERROR); + if (list) { + kfree(list); + list = NULL; + } + } + + return list; +} + +/* + * Let one thread queue when another is in critical section + * Prevent the race condition where ssd read ios limit is released by thread A + * when thread B in critical section is about to end. + * If we don't queue A, A exits but B might not check and use the released ios limit, + * this might result in premature termination of the syncing process. + */ +static inline int +try_lock_sqf(online_qf_t *oqf) +{ + /* return 1 when failed to lock, already two people in function */ + if (down_trylock(&oqf->sqf_sem2)) { + return 1; + } + + down(&oqf->sqf_sem1); + return 0; +} + +static inline void +release_sqf_lock(online_qf_t *oqf) +{ + /* sem2 should be released first so both threads in sem2 is either in + * syno_start_sqf or will call into it */ + up(&oqf->sqf_sem2); + up(&oqf->sqf_sem1); +} + +void +syno_start_sqf(struct cache_c *dmc) +{ + int nr_blk = 0; + cb_wb_param_t *cb_wb_param_list = NULL; + // prevent oob access of cb_wb_param_list when ssd_read_ios_limit changed by sysctl + int param_list_size = dmc->plug_wb.ssd_read_ios_limit; + online_qf_t *oqf = &dmc->oqf; + unsigned long map_idx = oqf->bit_idx / OQF_BITS_PER_INT; + unsigned long bit_off_in_map_unit = oqf->bit_idx % OQF_BITS_PER_INT; + + // TODO: maybe only one wq calls this function after new metadata update? + // check if we can remove the semaphore + if (try_lock_sqf(&dmc->oqf)) { + /* Already a thread waiting, the critical section is guaranteed + * to run at least once, end directly */ + goto end; + } + /* both semaphore locked */ + + /* The sync process rely on callback to this function to find + * new batch of disk writes to send (sync_wb_handle_batch). + * If sync_wb_handle_batch is skipped, then jobs in sync_io_queue won't finish. + * Skip after obtain the lock and handle batch before end */ + if (skip_sqf(dmc)) { + goto end_unlock; + } + + if (oqf->bit_idx >= oqf->bitmap_num_idx * OQF_BITS_PER_INT) { + goto end_unlock; + } + + cb_wb_param_list = alloc_wb_param_list(dmc, param_list_size); + if (!cb_wb_param_list) { + atomic_inc(&dmc->flashcache_errors.memory_alloc_errors); + serr("Failed to allocate memory for syncing blocks"); + goto err_unlock; + } + + down_read(&oqf->bitmap_rwsem); + while (map_idx < oqf->bitmap_num_idx) { + if (0 == oqf->volume_bitmap[map_idx]) { + map_idx++; + oqf->bit_idx = map_idx * OQF_BITS_PER_INT; + bit_off_in_map_unit = 0; + continue; + } + + if (oqf->volume_bitmap[map_idx] & (1 << bit_off_in_map_unit)) { + if (get_cbs_to_wb_from_bit_sync(dmc, &nr_blk, + cb_wb_param_list, param_list_size)) { + break; + } + } + + oqf->bit_idx++; + map_idx = oqf->bit_idx / OQF_BITS_PER_INT; + bit_off_in_map_unit = oqf->bit_idx % OQF_BITS_PER_INT; + } + up_read(&oqf->bitmap_rwsem); + sync_wb_send_ssd_read(dmc, cb_wb_param_list, nr_blk); + +end_unlock: +err_unlock: + sync_wb_handle_batch(&dmc->plug_wb); + release_sqf_lock(&dmc->oqf); + +end: + mutex_lock(&dmc->oqf.mtx); + dmc->oqf.sync_trigger_cnt--; + VERIFY_WARN(0 <= dmc->oqf.sync_trigger_cnt); + if (0 == dmc->oqf.sync_trigger_cnt) { + // Last sync thread +#ifdef MY_ABC_HERE + mutex_unlock(&dmc->oqf.mtx); + syno_mu_flush_all_synced_sync(dmc); + mutex_lock(&dmc->oqf.mtx); +#endif + flashcache_clean_sync_state(dmc); + } + mutex_unlock(&dmc->oqf.mtx); + + if(cb_wb_param_list) { + kfree(cb_wb_param_list); + cb_wb_param_list = NULL; + } +} + +/* In under read lock, out under read lock + * return 1 cannot writeback more, 0 can writeback more */ +static int +quickflush_writeback_by_fallow_bit(struct cache_c *dmc) +{ + int i = 0; + int ret = 0; + cb_wb_param_t cb_wb_param_list[OQF_VB_PER_BIT] = {0}; + int nr_cb_to_clean = 0; + + ret = get_cbs_to_wb_from_bit(dmc, &nr_cb_to_clean, cb_wb_param_list, OQF_VB_PER_BIT); + + for (i = 0; i < nr_cb_to_clean; ++i) { + quickflush_dirty_writeback(dmc, cb_wb_param_list[i]); + } + + return ret; +} + +enum { + DMCG_NQF_RIGHT_GRANTED, // can do nqf + DMCG_NQF_SCHEDULED, +}; + +/** + * Check if dmc has right to do nqf. + * If dmc doesn't not own right to do nqf, queue dmc into rr queue and + * schedule nqf management work to see if we can rotate. + * + * return DMCG_NQF_RIGHT_GRANTED: can writeback + * DMCG_NQF_SCHEDULED: put this dmc into rr queue in dmc group, schedule mgmt work + */ +static int nqf_request_right_or_schedule(struct cache_c *dmc) +{ + int can_nqf = DMCG_NQF_SCHEDULED; + dmc_group_t *dmcg = dmc->dmcg; + + /* Most of the case */ + down_read(&dmcg->rw_sem); + if (dmcg->nqf_dmc == dmc) { + can_nqf = DMCG_NQF_RIGHT_GRANTED; + up_read(&dmcg->rw_sem); + goto end; + } else if (dmc->oqf.dmcg_wb_scheduled) { + up_read(&dmcg->rw_sem); + goto end; + } + up_read(&dmcg->rw_sem); + + /* Should rarely happen */ + down_write(&dmcg->rw_sem); + + /* Might change between release read lock and obtain write lock, check again */ + if (dmcg->nqf_dmc == dmc) { + can_nqf = DMCG_NQF_RIGHT_GRANTED; + up_write(&dmcg->rw_sem); + goto end; + } else if (dmc->oqf.dmcg_wb_scheduled) { + up_write(&dmcg->rw_sem); + goto end; + } + + /* Request nqf right */ + dmc->oqf.dmcg_wb_scheduled = 1; + list_add_tail(&dmc->node->nqf_entry, &dmcg->nqf_pending_dmcs); + up_write(&dmcg->rw_sem); + + cache_mod_delayed_work(&nqf_mgmt_work, 0); + +end: + return can_nqf; +} + +// TODO: stats +/* When nqf trigger decreased to 0 no wb is running for this dmc + * Give nqf right to other dmc */ +static void nqf_yield_right(struct cache_c *dmc) +{ + dmc_group_t *dmcg = dmc->dmcg; + + down_read(&dmcg->rw_sem); + if (dmcg->nqf_dmc != dmc) { + /* Nothing to yield */ + up_read(&dmcg->rw_sem); + return; + } + up_read(&dmcg->rw_sem); + + down_write(&dmcg->rw_sem); + if (dmcg->nqf_dmc == dmc) { + dmcg->nqf_yielded = 1; + cache_mod_delayed_work(&nqf_mgmt_work, 0); + } + up_write(&dmcg->rw_sem); + + return; +} + +static inline void nqf_schedule(struct cache_c *dmc) +{ + /* If dmc owns current nqf right, i.e., following func return DMCG_NQF_RIGHT_GRANTED + * there should be thread writing back, do nothing. + * Else wb request is registered and will start by mgmt thread when the time comes */ + nqf_request_right_or_schedule(dmc); + return; +} + +static inline int skip_nqf(struct cache_c *dmc) { + return 0 == atomic_read(&dmc->oqf.nr_fallow) || + atomic_read(&dmc->remove_in_prog) || + dmc->oqf.sync_state != SYNC_STATE_STOPPED; +} + +void syno_start_nqf(struct cache_c *dmc) +{ + online_qf_t *oqf = &dmc->oqf; + unsigned long map_idx = oqf->bit_idx / OQF_BITS_PER_INT; + unsigned long bit_off_in_map_unit = oqf->bit_idx % OQF_BITS_PER_INT; + unsigned long init_map_idx = map_idx; + int map_idx_increased = 0; + int yield_nqf_right = 0; + + VERIFY_WARN(oqf->trigger_cnt > 0); + + mutex_lock(&oqf->mtx); + if (oqf->sync_state != SYNC_STATE_STOPPED || oqf->nqf_inprog) { + goto end_unlock; + } else { + oqf->nqf_inprog = 1; + } + mutex_unlock(&oqf->mtx); + + /* For shared cache, dmc group controls who can do online wb + * don't schedule if nqf skipped */ + if (skip_nqf(dmc) || DMCG_NQF_SCHEDULED == nqf_request_right_or_schedule(dmc)) { + goto end; + } + + /* sync state is not under lock cause it don't need to be perfectly synced */ + down_read(&oqf->bitmap_rwsem); + while (!skip_nqf(dmc)) { + + if (map_idx_increased && map_idx == init_map_idx) { + break; + } + + if (0 == oqf->volume_bitmap[map_idx]) { + map_idx++; + map_idx_increased = 1; + if (unlikely(map_idx == oqf->bitmap_num_idx)) { + oqf->bit_idx = 0; + map_idx = 0; + bit_off_in_map_unit = 0; + } else { + oqf->bit_idx = map_idx * OQF_BITS_PER_INT; + bit_off_in_map_unit = 0; + } + continue; + } + + if (oqf->volume_bitmap[map_idx] & (1 << bit_off_in_map_unit)) { + if (quickflush_writeback_by_fallow_bit(dmc)) { + break; + } + } + oqf->bit_idx++; + if (map_idx != oqf->bit_idx / OQF_BITS_PER_INT) { + map_idx_increased = 1; + } + map_idx = oqf->bit_idx / OQF_BITS_PER_INT; + bit_off_in_map_unit = oqf->bit_idx % OQF_BITS_PER_INT; + if (unlikely(map_idx == oqf->bitmap_num_idx)) { + bit_off_in_map_unit = 0; + oqf->bit_idx = 0; + map_idx = 0; + } + + } + up_read(&oqf->bitmap_rwsem); + +end: + mutex_lock(&oqf->mtx); + oqf->nqf_inprog = 0; + +end_unlock: + oqf->trigger_cnt--; + if (0 == oqf->trigger_cnt) { + wake_up(&oqf->wqh); + yield_nqf_right = 1; + } + mutex_unlock(&oqf->mtx); + + if (yield_nqf_right) { + nqf_yield_right(dmc); + } + + return; +} + +// in under bitmap read lock & cache spin lock +void +quickflush_set_volume_map(struct cache_c *dmc, struct cacheblock *cb) +{ + unsigned long bit_idx_in_map = ((cb->dbn / NEW_MODE_BLOCK_SIZE) / OQF_VB_PER_BIT); + unsigned long int_idx_in_map = (bit_idx_in_map / OQF_BITS_PER_INT); + unsigned long bit_off_in_map_unit = (bit_idx_in_map % OQF_BITS_PER_INT); + + dmc->oqf.volume_bitmap[int_idx_in_map] |= 1 << bit_off_in_map_unit; +} + +// in under bitmap write lock & cache spin lock +void +quickflush_unset_volume_map(struct cache_c *dmc, unsigned long bit_idx_in_map) +{ + unsigned long int_idx_in_map = (bit_idx_in_map / OQF_BITS_PER_INT); + unsigned long bit_off_in_map_unit = (bit_idx_in_map % OQF_BITS_PER_INT); + + atomic64_inc(&dmc->flashcache_stats.qf_fallow_bits_unset); + dmc->oqf.volume_bitmap[int_idx_in_map] &= ~(1 << bit_off_in_map_unit); +} + +static inline int +quickflush_no_need_detect_fallow(struct cache_c *dmc) +{ + if (0 == dmc->nr_dirty || atomic_read(&dmc->remove_in_prog)) { + return 1; + } + + return 0; +} + +static inline unsigned long +next_fallow_time(struct cache_c *dmc) +{ + return dmc->oqf.last_fallow_tstamp + dmc->sysctl_fallow_delay * HZ; +} + +// in without lock +void +quickflush_detect_fallow(struct cache_c *dmc) +{ + int i = 0; + int print = 0; // for debug + int counter = 0; // for debug + u64 start = ktime_to_ns(ktime_get()); // FIXME: remove debug messages + ktime_t next_sleep_time; + + if (quickflush_no_need_detect_fallow(dmc)) { + goto end; + } + + mutex_lock(&dmc->oqf.mtx); + if (dmc->oqf.detect_fallow_inprog) { + VERIFY_WARN(0); + mutex_unlock(&dmc->oqf.mtx); + goto end; + } + dmc->oqf.detect_fallow_inprog = 1; + mutex_unlock(&dmc->oqf.mtx); + + if (dmc->sysctl_fallow_delay && time_after(jiffies, next_fallow_time(dmc))) { + print = 1; + next_sleep_time = ktime_add(ktime_get(), ktime_set(0, OQF_MARK_FALLOW_DURATION_NSEC)); + for (i = 0; i < dmc->size ; i++) { + flashcache_detect_fallow(dmc, i); + /* Scan every cacheblock takes a long time. (e.g., 2 seconds for 16T cache in 918+). + * To avoid holding lock for too long, sleep after running for a specific interval. */ + if (unlikely((0 == i % OQF_FALLOW_CHECK_CNT) && ktime_after(ktime_get(), next_sleep_time))) { + counter++; + msleep(OQF_MARK_FALLOW_ITVL_MSEC); + if (quickflush_no_need_detect_fallow(dmc)) { + goto end_reset_inprog; + } + next_sleep_time = ktime_add(ktime_get(), ktime_set(0, OQF_MARK_FALLOW_DURATION_NSEC)); + } + } + dmc->oqf.last_fallow_tstamp = jiffies; + } + + // debug msg + if (print) { + sdbg(DF_QUICKFLUSH, "Time elasped: %llu Time sleeps: %d\n", + ktime_to_ns(ktime_get()) - start, counter); + } + +end_reset_inprog: + mutex_lock(&dmc->oqf.mtx); + dmc->oqf.detect_fallow_inprog = 0; + mutex_unlock(&dmc->oqf.mtx); +end: + return; +} + +void +quickflush_do_writeback(struct work_struct *work) +{ + struct cache_c *dmc = container_of(work, struct cache_c, oqf.wb_work.work); + + sdbg(DF_QUICKFLUSH, "quickflush_do_writeback\n"); + + quickflush_detect_fallow(dmc); + + if (!skip_nqf(dmc)) { + nqf_schedule(dmc); + } + + quickflush_schedule_wb_work(dmc); +} + +static void inline dmcg_grant_next_nqf_right(dmc_group_t *dmcg) +{ + dmc_node *node = container_of(dmcg->nqf_pending_dmcs.next, dmc_node, nqf_entry); + list_del(&node->nqf_entry); + dmcg->nqf_dmc = node->pdmc; + dmcg->nqf_expire_jiffies = jiffies + NQF_TIMESLICE_SEC * HZ; + VERIFY_WARN(node->pdmc->oqf.dmcg_wb_scheduled); + node->pdmc->oqf.dmcg_wb_scheduled = 0; +} + +static inline int dmcg_nqf_need_release_right(dmc_group_t *dmcg) +{ + /* No need to release right if no one is waiting */ + return dmcg->nqf_yielded || + (dmcg->nqf_dmc && + time_after(jiffies, dmcg->nqf_expire_jiffies) && + !list_empty(&dmcg->nqf_pending_dmcs)); +} + +/* In under dmcg->rw_sem WRITE lock */ +static void dmcg_nqf_check_rotate(dmc_group_t *dmcg) +{ + /* Stop nqf if any sqf is on going */ + if (atomic_read(&dmcg->sqf_inprog)) { + dmcg->nqf_dmc = NULL; + return; + } + + if (dmcg_nqf_need_release_right(dmcg)) { + dmcg->nqf_dmc = NULL; + dmcg->nqf_yielded = 0; + } + + if (NULL == dmcg->nqf_dmc && !list_empty(&dmcg->nqf_pending_dmcs)) { + dmcg_grant_next_nqf_right(dmcg); + } + + return; +} + +/* Main function to manage nqf for all dmc group */ +void dmcg_nqf_mgmt(struct work_struct *work) +{ + struct list_head *pos = NULL; + dmc_group_t *dmcg = NULL; + + mutex_lock(&dmcg_mtx); + list_for_each(pos, &dmc_group_list) { + dmcg = container_of(pos, dmc_group_t, node); + + down_write(&dmcg->rw_sem); + dmcg_nqf_check_rotate(dmcg); + up_write(&dmcg->rw_sem); + + /* This is the only thread that will modify dmcg->nqf_dmc, skip lock */ + if (dmcg->nqf_dmc) { + mutex_lock(&dmcg->nqf_dmc->oqf.mtx); + dmcg->nqf_dmc->oqf.trigger_cnt++; + mutex_unlock(&dmcg->nqf_dmc->oqf.mtx); + syno_start_nqf(dmcg->nqf_dmc); + } + + wake_up(&dmcg->nqf_wqh); + } + + mutex_unlock(&dmcg_mtx); + + schedule_nqf_mgmt_work(); +} + +#endif /* MY_ABC_HERE */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_quickflush.h b/drivers/syno/syno-mem-saving-driver/syno_quickflush.h new file mode 100644 index 000000000000..8cbd7293c9e9 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_quickflush.h @@ -0,0 +1,61 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifndef __SYNO_QUICKFLUSH_H__ +#define __SYNO_QUICKFLUSH_H__ + +#include "flashcache.h" + +// REMOVE THE FILE FOR GPL RELEASE +#ifdef MY_ABC_HERE + +#if defined(CONFIG_SYNO_ALPINE) +#define OQF_VB_PER_BIT 8 +#else +#define OQF_VB_PER_BIT 4 // Should be power of 2 +#endif +#define OQF_MARK_FALLOW_DURATION_NSEC 200000 +#define OQF_MARK_FALLOW_ITVL_MSEC 10 +#define OQF_FALLOW_CHECK_CNT 16384 +#define OQF_BITS_PER_INT (sizeof(int) * 8) +#define QF_BLK_IDX_TO_SEC(idx) ((idx) * CACHE_BLK_SIZE_SEC) + +/* wake the writeback thread up every 10 second in case the current writeback + * stop due to error (e.g., not enough memory). */ +#define OQF_WB_WORK_ITVL_SEC 10 +/* Total device bytes / device byte represeted per int + 1 for remainders */ +#define OQF_FALLOW_MAP_NUM_IDX(dmc) (compatible_div(get_disk_bdev(dmc)->bd_inode->i_size, \ + OQF_BITS_PER_INT * OQF_VB_PER_BIT * to_bytes(CACHE_BLK_SIZE_SEC)) + 1) + +typedef struct cb_wb_param { + int idx; + /* Number of non-consecutive dirty blocks in a cache block + * During writeback we merge dirty blocks that are consecutive to each + * other into one IO. So this is how many writeback IO we'll send for a cb + * see quickflush_cacheblk_get_nr_writeback for detail */ + int nr_write; + int job_flag; // KCACHED_JOB_FLAG +} cb_wb_param_t; + +void flashcache_clean_sync_state(struct cache_c *dmc); +int quickflush_find_cacheblk_idx(struct cache_c *dmc, unsigned long long disk_blk_idx); +int quickflush_cacheblk_get_nr_writeback(struct cache_c *dmc, int index); +void quickflush_get_next_io_range(bitmap_t data_bitmap, bitmap_t *dirty_bitmap, sector_t *offset, sector_t *size); +void syno_start_sqf(struct cache_c *dmc); +void quickflush_dirty_writeback(struct cache_c *dmc, cb_wb_param_t param); +void quickflush_construct_bitmap(struct cache_c *dmc); + +void quickflush_set_volume_map(struct cache_c *dmc, struct cacheblock *cb); +void quickflush_unset_volume_map(struct cache_c *dmc, unsigned long bit_idx_in_map); +void quickflush_detect_fallow(struct cache_c *dmc); + +void syno_start_nqf(struct cache_c *dmc); +void quickflush_do_writeback(struct work_struct *work); + +static inline int quickflush_schedule_wb_work(struct cache_c *dmc) +{ + return cache_schedule_delayed_work(&dmc->oqf.wb_work, OQF_WB_WORK_ITVL_SEC * HZ); +} + +#endif /* MY_ABC_HERE */ +#endif /* __SYNO_QUICKFLUSH_H__ */ diff --git a/drivers/syno/syno-mem-saving-driver/syno_unit_test.c b/drivers/syno/syno-mem-saving-driver/syno_unit_test.c new file mode 100644 index 000000000000..d9e7bb0b4edc --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_unit_test.c @@ -0,0 +1,197 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include +#include + +#include "flashcache.h" + +static void +verify_is_dirty(struct cache_c *dmc, unsigned long long disk_blk_idx) +{ + int i = quickflush_find_cacheblk_idx(dmc, disk_blk_idx); + + if (0 > i) { + serr(" dirty test FAILED!!! Block %llu is not in cache\n", disk_blk_idx); + return; + } + + if (DIRTY != (dmc->cache[i].cache_state & DIRTY)) { + serr("dirty test FAILED!!! Block %llu is not dirty\n", disk_blk_idx); + return; + } +} + +void +quickflush_test_io_count(void) +{ + int i = 0; + int fail = 0; + struct cache_c *dmc = NULL; + int tmp = 0; + int result[10] = {2, 3, 1, 3, 1, 1, 1, 2, 0, 0}; + + dmc = kzalloc(sizeof(*dmc), GFP_KERNEL); + if (!dmc) { + serr("Failed to alloc dmc"); + } + dmc->cache = kzalloc(10 * sizeof(struct cacheblock), GFP_KERNEL); + if (!dmc->cache) { + serr("Failed to alloc dmc->cache"); + } + dmc->cache[0].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[0].data_bitmap = (bitmap_t) 0b0001111011111000; + dmc->cache[1].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[1].data_bitmap = (bitmap_t) 0b0001111010111000; + dmc->cache[2].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[2].data_bitmap = (bitmap_t) 0b0001111111111000; + dmc->cache[3].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[3].data_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[4].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[4].data_bitmap = (bitmap_t) 0b1111111111111111; + dmc->cache[5].dirty_bitmap = (bitmap_t) 0b0000000000010000; + dmc->cache[5].data_bitmap = (bitmap_t) 0b1111111111110000; + dmc->cache[6].dirty_bitmap = (bitmap_t) 0b1010101010101010; + dmc->cache[6].data_bitmap = (bitmap_t) 0b1111111111111111; + dmc->cache[7].dirty_bitmap = (bitmap_t) 0b1010101010101010; + dmc->cache[7].data_bitmap = (bitmap_t) 0b1111111011111111; + + for (i = 0; i < 8; ++i) { + tmp = quickflush_cacheblk_get_nr_writeback(dmc, i); + if (result[i] != tmp) { + printk(KERN_ERR "io count test %d failed, should be %d but return %d\n", i, result[i], tmp); + fail = 1; + } + } + + if (0 == fail) { + printk(KERN_ERR "io count test PASSED!\n"); + } + + kfree(dmc->cache); + kfree(dmc); +} + +void +quickflush_test_io_range(void) +{ + int i = 0; + int j = 0; + int fail = 0; + struct cache_c *dmc = NULL; + int result_offset[14] = {3, 11, 3, 7, 11, 3, 3, 7, 11, 3, 4, 1, 1, 9}; + int result_size[14] = {5, 1, 2, 1, 1, 9, 2, 1, 1, 9, 1, 15, 7, 7}; + sector_t offset = 0; + sector_t size = 0; + bitmap_t dirty_bitmap = 0; + + dmc = kzalloc(sizeof(*dmc), GFP_KERNEL); + if (!dmc) { + serr("Failed to alloc dmc"); + } + dmc->cache = kzalloc(10 * sizeof(struct cacheblock), GFP_KERNEL); + if (!dmc->cache) { + serr("Failed to alloc dmc->cache"); + } + dmc->cache[0].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[0].data_bitmap = (bitmap_t) 0b0001111011111000; + dmc->cache[1].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[1].data_bitmap = (bitmap_t) 0b0001111010111000; + dmc->cache[2].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[2].data_bitmap = (bitmap_t) 0b0001111111111000; + dmc->cache[3].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[3].data_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[4].dirty_bitmap = (bitmap_t) 0b0000100010011000; + dmc->cache[4].data_bitmap = (bitmap_t) 0b1111111111111111; + dmc->cache[5].dirty_bitmap = (bitmap_t) 0b0000000000010000; + dmc->cache[5].data_bitmap = (bitmap_t) 0b1111111111110000; + dmc->cache[6].dirty_bitmap = (bitmap_t) 0b1010101010101010; + dmc->cache[6].data_bitmap = (bitmap_t) 0b1111111111111111; + dmc->cache[7].dirty_bitmap = (bitmap_t) 0b1010101010101010; + dmc->cache[7].data_bitmap = (bitmap_t) 0b1111111011111111; + + for (i = 0; i < 8; ++i) { + dirty_bitmap = dmc->cache[i].dirty_bitmap; + while (dirty_bitmap) { + quickflush_get_next_io_range(dmc->cache[i].data_bitmap, &dirty_bitmap, &offset, &size); + if (offset != result_offset[j] * SECTOR_PER_BIT + || size != result_size[j] * SECTOR_PER_BIT) { + fail = 1; + serr("io range test failed: i: %d j:%d offset: %lu size: %lu\n", i, j, offset, size); + } + j++; + if (j >= 15) { + serr("This should not happen\n"); + break; + } + } + } + + if (!fail) { + serr("io range test PASSED!!!\n"); + } else { + serr("io range test FAILED!!!\n"); + } + + kfree(dmc->cache); + kfree(dmc); +} + +// Note: This function how use the bitmap and cache in dmc directly +// Use in caution since it might messed up qf_bitmap and the index. +// Should change to use fake data and cache. +void +quickflush_test_bitmap_correctness(struct cache_c *dmc) +{ + int seg_idx = 0; + int unit_idx_in_seg = 0; + int nr_unit_per_seg = 0; + qf_unit_t *cur_unit = 0; + unsigned long long disk_blk_idx = 0; + unsigned long long disk_dirty_blk_idx = 0; + unsigned long long nr_bit_per_seg = QF_KB_TO_BIT(dmc->qf_bitmap_seg_size_kb); + unsigned long long nr_bit_per_unit = QF_BYTE_TO_BIT(sizeof(**dmc->qf_bitmap_segs)); + unsigned int right_most_bitval = 0; + unsigned long dirty_cnt = 0; + + quickflush_build_next_bitmap(dmc); + nr_unit_per_seg = compatible_div(QF_KB_TO_BYTE(dmc->qf_bitmap_seg_size_kb), sizeof(**dmc->qf_bitmap_segs)); + + while (1) { + while(seg_idx < dmc->qf_bitmap_seg_cnt) { + while (unit_idx_in_seg < nr_unit_per_seg) { + cur_unit = &dmc->qf_bitmap_segs[seg_idx][unit_idx_in_seg]; + while (*cur_unit) { + right_most_bitval = QF_R_MOST_BITVAL(*cur_unit); + disk_dirty_blk_idx = + dmc->qf_bitmap_start_blk_idx + + seg_idx * nr_bit_per_seg + + unit_idx_in_seg * nr_bit_per_unit + + ilog2(right_most_bitval); + *cur_unit &= ~right_most_bitval; + verify_is_dirty(dmc, disk_dirty_blk_idx); + dirty_cnt++; + } /* bits in a unit */ + ++unit_idx_in_seg; + disk_blk_idx = + dmc->qf_bitmap_start_blk_idx + + seg_idx * nr_bit_per_seg + + unit_idx_in_seg * nr_bit_per_unit; + if (disk_blk_idx >= dmc->disk_blk_cnt) { + goto out; + } + } /* units in segment */ + ++seg_idx; + unit_idx_in_seg = 0; + } /* segments in bitmap */ + seg_idx = 0; + quickflush_build_next_bitmap(dmc); + } /* bitmap in volume */ +out: + + printk(KERN_ERR "nr_dirty: %d dirty_cnt: %lu\n", dmc->nr_dirty, dirty_cnt); + if (dirty_cnt == dmc->nr_dirty) { + printk(KERN_ERR "Dirty Number Check Passed!"); + } else { + printk(KERN_ERR "Dirty Number Check Failed!"); + } +} diff --git a/drivers/syno/syno-mem-saving-driver/syno_unit_test.h b/drivers/syno/syno-mem-saving-driver/syno_unit_test.h new file mode 100644 index 000000000000..4d383c4e7cf3 --- /dev/null +++ b/drivers/syno/syno-mem-saving-driver/syno_unit_test.h @@ -0,0 +1,9 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. +#ifndef __SYNO_UNIT_TEST_H__ +#define __SYNO_UNIT_TEST_H__ + +void quickflush_test_io_count(void); +void quickflush_test_io_range(void); +void quickflush_test_bitmap_correctness(struct cache_c *dmc); + +#endif \ No newline at end of file diff --git a/drivers/syno/synobios/Makefile b/drivers/syno/synobios/Makefile new file mode 100644 index 000000000000..4152195d9e0f --- /dev/null +++ b/drivers/syno/synobios/Makefile @@ -0,0 +1,3 @@ +subdir-ccflags-y := -I$(src)/include +include $(src)/Makefile_vdsm.inc +obj-y += kvmx64v2/ diff --git a/drivers/syno/synobios/Makefile.inc b/drivers/syno/synobios/Makefile.inc new file mode 100644 index 000000000000..e6fae957c23f --- /dev/null +++ b/drivers/syno/synobios/Makefile.inc @@ -0,0 +1,133 @@ +include /env.mak + +ifeq ($(SYNO_PLATFORM),BROMOLOW) +export SUBDIR := bromolow +endif +ifeq ($(SYNO_PLATFORM),GRANTLEY) +export SUBDIR := grantley +endif +ifeq ($(SYNO_PLATFORM),CEDARVIEW) +export SUBDIR := cedarview +endif +ifeq ($(SYNO_PLATFORM),EVANSPORT) +export SUBDIR := evansport +endif +ifeq ($(SYNO_PLATFORM),AVOTON) +export SUBDIR := avoton +endif +ifeq ($(SYNO_PLATFORM),BRASWELL) +export SUBDIR := braswell +endif +ifeq ($(SYNO_PLATFORM),APOLLOLAKE) +export SUBDIR := apollolake +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADAXP) +export SUBDIR := armada +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADA370) +export SUBDIR := armada +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADA375) +export SUBDIR := armada +endif +ifeq ($(SYNO_PLATFORM),MINDSPEED_COMCERTO2K) +export SUBDIR := comcerto2k +endif +ifeq ($(SYNO_PLATFORM),ALPINE) +export SUBDIR := alpine +endif +ifeq ($(SYNO_PLATFORM),STM_MONACO) +export SUBDIR := monaco +endif +ifeq ($(SYNO_PLATFORM),KVMX64) +export SUBDIR := kvmx64 +include Makefile_vdsm.inc +endif +ifeq ($(SYNO_PLATFORM),KVMX64SOFS) +export SUBDIR := kvmx64sofs +include Makefile_vdsm.inc +endif +ifeq ($(SYNO_PLATFORM),KVMX64V2) +export SUBDIR := kvmx64v2 +include Makefile_vdsm.inc +endif +ifeq ($(SYNO_PLATFORM),BROADWELL) +export SUBDIR := broadwell +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADA38X) +export SUBDIR := armada38x +endif +ifeq ($(SYNO_PLATFORM),REALTEK_RTD1296) +export SUBDIR := rtd1296 +endif +ifeq ($(SYNO_PLATFORM),DENVERTON) +export SUBDIR := denverton +endif +ifeq ($(SYNO_PLATFORM),BROADWELLNK) +export SUBDIR := broadwellnk +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADA37XX) +export SUBDIR := armada37xx +endif +ifeq ($(SYNO_PLATFORM),PURLEY) +export SUBDIR := purley +endif +ifeq ($(SYNO_PLATFORM),COFFEELAKE) +export SUBDIR := coffeelake +endif +ifeq ($(SYNO_PLATFORM),BROADWELLNTB) +export SUBDIR := broadwellntb +endif +ifeq ($(SYNO_PLATFORM),NEXTKVMX64) +export SUBDIR := nextkvmx64 +include Makefile_vdsm.inc +endif +ifeq ($(SYNO_PLATFORM),GEMINILAKE) +export SUBDIR := geminilake +endif +ifeq ($(SYNO_PLATFORM),REALTEK_RTD1619) +export SUBDIR := rtd1619 +endif +ifeq ($(SYNO_PLATFORM),SKYLAKED) +export SUBDIR := skylaked +endif +ifeq ($(SYNO_PLATFORM),V1000) +export SUBDIR := v1000 +endif +ifeq ($(SYNO_PLATFORM),V1000SOFS) +export SUBDIR := v1000sofs +endif +ifeq ($(SYNO_PLATFORM),BROADWELLNTBAP) +export SUBDIR := broadwellntbap +endif +ifeq ($(SYNO_PLATFORM),KVMCLOUD) +export SUBDIR := kvmcloud +include Makefile_vdsm.inc +endif +ifeq ($(SYNO_PLATFORM),EPYC7002) +export SUBDIR := epyc7002 +endif +ifeq ($(SYNO_PLATFORM),EPYC7002SOFS) +export SUBDIR := epyc7002sofs +endif +ifeq ($(SYNO_PLATFORM),R1000) +export SUBDIR := r1000 +endif +ifeq ($(SYNO_PLATFORM),ICELAKED) +export SUBDIR := icelaked +endif +ifeq ($(SYNO_PLATFORM),REALTEK_RTD1619B) +export SUBDIR := rtd1619b +endif +ifeq ($(SYNO_PLATFORM),BROADWELLNKV2) +export SUBDIR := broadwellnkv2 +endif +ifeq ($(SYNO_PLATFORM),RYZEN5K) +export SUBDIR := ryzen5k +endif +ifeq ($(SYNO_PLATFORM),GEMINILAKEVS) +export SUBDIR := geminilakevs +endif +ifeq ($(SYNO_PLATFORM),EPYC7003NTB) +export SUBDIR := epyc7003ntb +endif diff --git a/drivers/syno/synobios/Makefile_vdsm.inc b/drivers/syno/synobios/Makefile_vdsm.inc new file mode 100644 index 000000000000..3fbef5a1178e --- /dev/null +++ b/drivers/syno/synobios/Makefile_vdsm.inc @@ -0,0 +1,9 @@ +vdsm-common-obj = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o +# 為了讓其他共用此變數的 makefile å¯ä»¥ä½¿ç”¨åˆ°æ­¤è®Šæ•¸ï¼Œéœ€è¦ export 出去 +export vdsm-common-obj diff --git a/drivers/syno/synobios/SynoBuildConf/build b/drivers/syno/synobios/SynoBuildConf/build new file mode 100644 index 000000000000..d69aa44dc425 --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/build @@ -0,0 +1,22 @@ +#!/bin/bash +# Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +. ${ScriptsDir}/include/exports + +case ${MakeClean} in + [Yy][Ee][Ss]) + make distclean ${MAKE_FLAGS} + ;; +esac + +case ${CleanOnly} in + [Yy][Ee][Ss]) + return + ;; +esac + +if checkPlatformFunction SYNO_FEA_ROUTER_COMMON; then + echo "#define SYNO_BUILD_YEAR 1"`date +%y` > include/gen.h +fi + +make $MAKE_FLAGS KSRC="$KSRC" diff --git a/drivers/syno/synobios/SynoBuildConf/build-virtual-headers b/drivers/syno/synobios/SynoBuildConf/build-virtual-headers new file mode 100644 index 000000000000..906813a87a8b --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/build-virtual-headers @@ -0,0 +1,2 @@ +#!/bin/bash +# Copyright (c) 2000-2022 Synology Inc. All rights reserved. diff --git a/drivers/syno/synobios/SynoBuildConf/conflict-virtual-headers b/drivers/syno/synobios/SynoBuildConf/conflict-virtual-headers new file mode 100644 index 000000000000..783a1c163690 --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/conflict-virtual-headers @@ -0,0 +1 @@ +synobios-virtual-headers="synobios" diff --git a/drivers/syno/synobios/SynoBuildConf/depends b/drivers/syno/synobios/SynoBuildConf/depends new file mode 100644 index 000000000000..3fcf5803c25d --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/depends @@ -0,0 +1,3 @@ +[BuildDependent-Tag] +${Kernel} + diff --git a/drivers/syno/synobios/SynoBuildConf/depends-virtual-headers b/drivers/syno/synobios/SynoBuildConf/depends-virtual-headers new file mode 100644 index 000000000000..aa35e615f483 --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/depends-virtual-headers @@ -0,0 +1,3 @@ +[BuildDependent-Tag] +${KernelHeaders} + diff --git a/drivers/syno/synobios/SynoBuildConf/install-dev b/drivers/syno/synobios/SynoBuildConf/install-dev new file mode 100644 index 000000000000..8f122ad712db --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/install-dev @@ -0,0 +1,230 @@ +#!/bin/bash +# Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +SDSCustomDir="${SourceDir}/sds-custom" + +case "$BUILD_TARGET" in + BROMOLOW) + subdir="bromolow" + platform="bromolow" + STRIP=${STRIP64} + ;; + GRANTLEY) + subdir="grantley" + platform="grantley" + STRIP=${STRIP64} + ;; + CEDARVIEW) + subdir="cedarview" + platform="cedarview" + STRIP=${STRIP64} + ;; + AVOTON) + subdir="avoton" + platform="avoton" + STRIP=${STRIP64} + ;; + BRASWELL) + subdir="braswell" + platform="braswell" + STRIP=${STRIP64} + ;; + APOLLOLAKE) + subdir="apollolake" + platform="apollolake" + STRIP=${STRIP64} + ;; + EVANSPORT) + subdir="evansport" + platform="evansport" + ;; + MARVELL_ARMADAXP) + subdir="armada" + platform="armadaxp" + ;; + MARVELL_ARMADA370) + subdir="armada" + platform="armada370" + ;; + MARVELL_ARMADA375) + subdir="armada" + platform="armada375" + ;; + MINDSPEED_COMCERTO2K) + subdir="comcerto2k" + platform="comcerto2k" + ;; + ALPINE) + subdir="alpine" + platform="${PLATFORM_ABBR}" + ;; + STM_MONACO) + subdir="monaco" + platform="monaco" + ;; + KVMX64) + subdir="kvmx64" + platform="kvmx64" + STRIP=${STRIP64} + ;; + KVMX64SOFS) + subdir="kvmx64sofs" + platform="kvmx64sofs" + STRIP=${STRIP64} + ;; + KVMX64V2) + subdir="kvmx64v2" + platform="kvmx64v2" + STRIP=${STRIP64} + ;; + BROADWELL) + subdir="broadwell" + platform="broadwell" + STRIP=${STRIP64} + ;; + MARVELL_ARMADA38X) + subdir="armada38x" + platform="armada38x" + ;; + REALTEK_RTD1296) + subdir="rtd1296" + platform="rtd1296" + ;; + DENVERTON) + subdir="denverton" + platform="denverton" + STRIP=${STRIP64} + ;; + BROADWELLNK) + subdir="broadwellnk" + platform="broadwellnk" + STRIP=${STRIP64} + ;; + PURLEY) + subdir="purley" + platform="purley" + STRIP=${STRIP64} + ;; + COFFEELAKE) + subdir="coffeelake" + platform="coffeelake" + STRIP=${STRIP64} + ;; + BROADWELLNTB) + subdir="broadwellntb" + platform="broadwellntb" + STRIP=${STRIP64} + ;; + NEXTKVMX64) + subdir="nextkvmx64" + platform="nextkvmx64" + STRIP=${STRIP64} + ;; + GEMINILAKE) + subdir="geminilake" + platform="geminilake" + STRIP=${STRIP64} + ;; + REALTEK_RTD1619) + subdir="rtd1619" + platform="rtd1619" + ;; + SKYLAKED) + subdir="skylaked" + platform="skylaked" + STRIP=${STRIP64} + ;; + V1000) + subdir="v1000" + platform="v1000" + STRIP=${STRIP64} + ;; + V1000SOFS) + subdir="v1000sofs" + platform="v1000sofs" + STRIP=${STRIP64} + ;; + BROADWELLNTBAP) + subdir="broadwellntbap" + platform="broadwellntbap" + STRIP=${STRIP64} + ;; + KVMCLOUD) + subdir="kvmcloud" + platform="kvmcloud" + STRIP=${STRIP64} + ;; + EPYC7002) + subdir="epyc7002" + platform="epyc7002" + STRIP=${STRIP64} + ;; + EPYC7002SOFS) + subdir="epyc7002sofs" + platform="epyc7002sofs" + STRIP=${STRIP64} + ;; + R1000) + subdir="r1000" + platform="r1000" + STRIP=${STRIP64} + ;; + ICELAKED) + subdir="icelaked" + platform="icelaked" + STRIP=${STRIP64} + ;; + REALTEK_RTD1619B) + subdir="rtd1619b" + platform="rtd1619b" + ;; + BROADWELLNKV2) + subdir="broadwellnkv2" + platform="broadwellnkv2" + STRIP=${STRIP64} + ;; + RYZEN5K) + subdir="ryzen5k" + platform="ryzen5k" + STRIP=${STRIP64} + ;; + GEMINILAKEVS) + subdir="geminilakevs" + platform="geminilakevs" + STRIP=${STRIP64} + ;; + EPYC7003NTB) + subdir="epyc7003ntb" + platform="epyc7003ntb" + STRIP=${STRIP64} + ;; + +esac + +ModuleExt="ko" + +ThermalCtrlKModule="thermal_ctrl.ko" + +# Copy customized kernel module to ${DebDevBuild} directory. +IPRF="${SDSCustomDir}/*_${platform}_*.iprf" +for ThisIPRF in $IPRF; +do + ThisModel=`/bin/grep -s ^model ${ThisIPRF} | awk -F \" '{print $2}'` + KModule=`${SDSCustomDir}/ServiceKeyCheck.py --get_value ${ThisModel} synobios | awk -F \" '{ print $2 }'` + KModule=`find ${subdir} -name $KModule-synobios.${ModuleExt}` + if [ -n "$KModule" -a -r "${KModule}" ]; then + echo "=======================================================" + echo "Copy customized kernel module to ${DebDevBuild}. ($ThisModel)" + echo "=======================================================" + mkdir -p ${DebDevBuild}/image/modules/synobios/${ThisModel}/ + cp -fv ${KModule} ${DebDevBuild}/image/modules/synobios/${ThisModel}/synobios.${ModuleExt} + ${STRIP_ORI} -d ${DebDevBuild}/image/modules/synobios/${ThisModel}/synobios.${ModuleExt} + /usr/syno/bin/sign ${DebDevBuild}/image/modules/synobios/${ThisModel}/synobios.${ModuleExt} + fi + + if [ ${ThisModel} == "synology_armada370_eds14" ] && [ -f ${subdir}/${ThermalCtrlKModule} ] ; then + cp -fv ${subdir}/${ThermalCtrlKModule} ${DebDevBuild}/image/modules/synobios/${ThisModel}/ + ${STRIP_ORI} -d ${DebDevBuild}/image/modules/synobios/${ThisModel}/${ThermalCtrlKModule} + fi +done +# end of Copy customized kernel module diff --git a/drivers/syno/synobios/SynoBuildConf/install-dev-virtual-headers b/drivers/syno/synobios/SynoBuildConf/install-dev-virtual-headers new file mode 100644 index 000000000000..39cfd030138b --- /dev/null +++ b/drivers/syno/synobios/SynoBuildConf/install-dev-virtual-headers @@ -0,0 +1,5 @@ +#!/bin/bash +# Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +install -Dm644 "include/synobios.h" "$DebDevDir/$SynoIncludeDir/synobios/synobios.h" +install -Dm644 "include/syno_ttyS.h" "$DebDevDir/$SynoIncludeDir/synobios/syno_ttyS.h" diff --git a/drivers/syno/synobios/alpine/Makefile b/drivers/syno/synobios/alpine/Makefile new file mode 100644 index 000000000000..d2d7ded69e43 --- /dev/null +++ b/drivers/syno/synobios/alpine/Makefile @@ -0,0 +1,35 @@ +ifeq ($(SYNO_PLATFORM),ALPINE) +obj-m += ds2015xs-synobios.o +obj-m += ds1515-synobios.o +obj-m += ds715-synobios.o +obj-m += ds215+-synobios.o +obj-m += ds416-synobios.o +obj-m += ds1817-synobios.o +obj-m += ds1517-synobios.o +obj-m += rs1219-synobios.o +endif + +common-obj += \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-ricoh-lib.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-ricoh.o \ + ../rtc/rtc-linux-seiko.o \ + ../mapping.o \ + alpine_common.o + +fan-pwm-obj += fan-pwm.o + +ds2015xs-synobios-objs = ds2015xs.o $(fan-pwm-obj) $(common-obj) +ds1515-synobios-objs = ds1515.o $(fan-pwm-obj) $(common-obj) +ds715-synobios-objs = ds715.o $(fan-pwm-obj) $(common-obj) +ds215+-synobios-objs = ds215+.o $(fan-pwm-obj) $(common-obj) +ds416-synobios-objs = ds416.o $(fan-pwm-obj) $(common-obj) +ds1817-synobios-objs = ds1817.o $(fan-pwm-obj) $(common-obj) +ds1517-synobios-objs = ds1517.o $(fan-pwm-obj) $(common-obj) +rs1219-synobios-objs = rs1219.o $(fan-pwm-obj) $(common-obj) diff --git a/drivers/syno/synobios/alpine/alpine_common.c b/drivers/syno/synobios/alpine/alpine_common.c new file mode 100644 index 000000000000..0660e18e6cbd --- /dev/null +++ b/drivers/syno/synobios/alpine/alpine_common.c @@ -0,0 +1,312 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "synobios.h" +#include +#include +#include "../mapping.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "alpine_common.h" + +/* all alpine models share same synobios_model_init/cleanup(), + each model must implement their own model_private_init/cleanup() */ +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); + +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static int Uninitialize(void); + +static SYNO_HWMON_SENSOR_TYPE hdd_backplane_status_detect = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_DETECT, + }} +}; +static struct hwmon_sensor_list hdd_detect_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &hdd_backplane_status_detect, +}; + +static SYNO_HWMON_SENSOR_TYPE hdd_backplane_status_enable = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_ENABLE, + }} +}; +static struct hwmon_sensor_list hdd_enable_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &hdd_backplane_status_enable, +}; + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for (i = 0; i < sizeof(gPWMSpeedMapping) / sizeof(PWM_FAN_SPEED_MAPPING); ++i) { + if (gPWMSpeedMapping[i].fanSpeed == speed) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int iRet = -1; + int temperature = 0; + + if (!pCPUTemp) + goto END; + if (syno_alpine_get_cpu_temperature(&temperature) != 0) + goto END; + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = temperature; + + iRet = 0; +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + while (HAVE_HDD_DETECT(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 1; + while (HAVE_HDD_ENABLE(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 0; + while (hdd_backplane->sensor_num > index) { + if (0 == strncmp(HWMON_HDD_BP_ENABLE, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%lu", hdd_enable); + } else if (0 == strncmp(HWMON_HDD_BP_DETECT, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_DETECT))){ + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%lu", hdd_detect); + } + index++; + } + + iRet = 0; +End: + return iRet; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetDiskLedStatusV2(int disknum, SYNO_DISK_LED status) +{ + static int diskLedEnabled = 0; + if (0 == diskLedEnabled) { + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +int GetBackPlaneStatus(BACKPLANE_STATUS *pStatus) +{ + return 0; +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + return 0; +} + +int GetMemByte(MEMORY_BYTE *pMemory) +{ + return 0; +} + +static int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return 0; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = SetPowerLedStatus, + .set_disk_led = NULL, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .set_alarm_led = SetAlarmLed, + .get_backplane_status = GetBackPlaneStatus, + .get_mem_byte = GetMemByte, + .get_buzzer_cleared = GetBuzzerCleared, + .set_phy_led = NULL, + .set_hdd_led = SetHDDActLed, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + + syno_gpio_init(); +#ifdef MY_DEF_HERE + printk("Synobios %s GPIO initialized\n", syno_get_hw_version()); +#endif /* MY_DEF_HERE */ + + switch (GetModel()) { + case MODEL_DS215p: + case MODEL_DS715: + case MODEL_DS416: + hwmon_sensor_list = &hdd_enable_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + break; + case MODEL_RS1219: + hwmon_sensor_list = &hdd_detect_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + break; + } + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + if( pSynoModule && RTC_SEIKO == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = rtc_seiko_get_time; + synobios_ops.set_rtc_time = rtc_seiko_set_time; + synobios_ops.get_auto_poweron = rtc_get_auto_poweron; + synobios_ops.set_auto_poweron = rtc_seiko_set_auto_poweron; + synobios_ops.init_auto_poweron = rtc_seiko_auto_poweron_init; + synobios_ops.uninit_auto_poweron = rtc_seiko_auto_poweron_uninit; + } + if( pSynoModule && RTC_MV == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = NULL; + synobios_ops.set_rtc_time = NULL; + synobios_ops.get_auto_poweron = NULL; + synobios_ops.set_auto_poweron = NULL; + synobios_ops.init_auto_poweron = NULL; + synobios_ops.uninit_auto_poweron = NULL; + } + + *ops = &synobios_ops; + switch (GetModel()) { + case MODEL_DS1817: + case MODEL_RS1219: + synobios_ops.set_disk_led = SetDiskLedStatusV2; + break; + default: + synobios_ops.set_disk_led = SetDiskLedStatus; + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + return 0; +} + +static int Uninitialize(void) +{ + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + model_addon_cleanup(*ops); + return 0; +} diff --git a/drivers/syno/synobios/alpine/alpine_common.h b/drivers/syno/synobios/alpine/alpine_common.h new file mode 100644 index 000000000000..9d9732c91251 --- /dev/null +++ b/drivers/syno/synobios/alpine/alpine_common.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include "../mapping.h" +#include "../common/common.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetPowerLedStatus(SYNO_LED status); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int PWMFanSpeedMapping(FAN_SPEED speed); +int InitModuleType(struct synobios_ops *ops); +int SetHDDActLed(SYNO_LED ledStatus); +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +extern int syno_alpine_get_cpu_temperature(int *temperature); +void syno_gpio_init(void); +void syno_gpio_cleanup(void); + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/alpine/ds1515.c b/drivers/syno/synobios/alpine/ds1515.c new file mode 100644 index 000000000000..babddfb76c19 --- /dev/null +++ b/drivers/syno/synobios/alpine/ds1515.c @@ -0,0 +1,154 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_DS1515; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_1515 = MODULE_T_DS1515; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS1515: + pType = &type_1515; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS1515 GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 1 In FAN 2 + * 5 Out High = Disk LED off + * 18 Out High = GPIO fan fail + * 10 Out High = HDD 1 activity + * 11 Out High = HDD 2 activity + * 22 Out High = HDD 3 activity + * 23 Out High = HDD 4 activity + * 24 Out High = HDD 5 activity + * 29 Out High = HDD 1 present + * 31 Out High = HDD 2 present + * 32 Out High = HDD 3 present + * 33 Out High = HDD 4 present + * 34 Out High = HDD 5 present + * 38 Out High = HDD 1 fault + * 39 Out High = HDD 2 fault + * 40 Out High = HDD 3 fault + * 41 Out High = HDD 4 fault + * 42 Out High = HDD 5 fault + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {0, 1}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 5, + .gpio_port = {38, 39, 40, 41, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 5, + .gpio_port = {29, 31, 32, 33, 34}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 5, + .gpio_port = {10, 11, 22, 23, 24}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {18}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(1); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/ds1517.c b/drivers/syno/synobios/alpine/ds1517.c new file mode 100644 index 000000000000..8deae29ab2ce --- /dev/null +++ b/drivers/syno/synobios/alpine/ds1517.c @@ -0,0 +1,154 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_DS1517; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1700); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_1517 = MODULE_T_DS1517; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS1517: + pType = &type_1517; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS1517 GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 1 In FAN 2 + * 5 Out High = Disk LED off + * 18 Out High = GPIO fan fail + * 10 Out High = HDD 1 activity + * 11 Out High = HDD 2 activity + * 22 Out High = HDD 3 activity + * 23 Out High = HDD 4 activity + * 24 Out High = HDD 5 activity + * 29 Out High = HDD 1 present + * 31 Out High = HDD 2 present + * 32 Out High = HDD 3 present + * 33 Out High = HDD 4 present + * 34 Out High = HDD 5 present + * 38 Out High = HDD 1 fault + * 39 Out High = HDD 2 fault + * 40 Out High = HDD 3 fault + * 41 Out High = HDD 4 fault + * 42 Out High = HDD 5 fault + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {0, 1}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 5, + .gpio_port = {38, 39, 40, 41, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 5, + .gpio_port = {29, 31, 32, 33, 34}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 5, + .gpio_port = {10, 11, 22, 23, 24}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {18}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(1); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/ds1817.c b/drivers/syno/synobios/alpine/ds1817.c new file mode 100644 index 000000000000..c508e0ae4aeb --- /dev/null +++ b/drivers/syno/synobios/alpine/ds1817.c @@ -0,0 +1,161 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_DS1817; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1700); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_1817 = MODULE_T_DS1817; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS1817: + pType = &type_1817; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS1817 GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 1 In FAN 2 + * 5 Out High = Disk LED off + * 10 Out High = HDD 1 activity + * 11 Out High = HDD 2 activity + * 22 Out High = HDD 3 activity + * 23 Out High = HDD 4 activity + * 24 Out High = HDD 5 activity + * 25 Out High = HDD 6 activity + * 26 Out High = HDD 7 activity + * 27 Out High = HDD 8 activity + * 29 Out High = HDD 1 present + * 31 Out High = HDD 2 present + * 32 Out High = HDD 3 present + * 33 Out High = HDD 4 present + * 34 Out High = HDD 5 present + * 35 Out High = HDD 6 present + * 36 Out High = HDD 7 present + * 37 Out High = HDD 8 present + * 38 Out High = HDD 1 fault + * 39 Out High = HDD 2 fault + * 40 Out High = HDD 3 fault + * 41 Out High = HDD 4 fault + * 42 Out High = HDD 5 fault + * 2 Out High = HDD 6 fault + * 3 Out High = HDD 7 fault + * 4 Out High = HDD 8 fault + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {0, 1}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 8, + .gpio_port = {38, 39, 40, 41, 42, 2, 3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 8, + .gpio_port = {29, 31, 32, 33, 34, 35, 36, 37}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 8, + .gpio_port = {10, 11, 22, 23, 24, 25, 26, 27}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {18}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/ds2015xs.c b/drivers/syno/synobios/alpine/ds2015xs.c new file mode 100644 index 000000000000..3ff5b8edc826 --- /dev/null +++ b/drivers/syno/synobios/alpine/ds2015xs.c @@ -0,0 +1,164 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_DS2015xs; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1700); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_2015xs = MODULE_T_DS2015xs; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS2015xs: + pType = &type_2015xs; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS2015xs GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 1 In FAN 2 + * 5 Out High = Disk LED off + * 18 Out High = Enable ESATA 1 power + * 19 Out High = Enable ESATA 2 power + * 10 Out High = HDD 1 activity + * 11 Out High = HDD 2 activity + * 22 Out High = HDD 3 activity + * 23 Out High = HDD 4 activity + * 24 Out High = HDD 5 activity + * 25 Out High = HDD 6 activity + * 26 Out High = HDD 7 activity + * 27 Out High = HDD 8 activity + * 29 Out High = HDD 1 present + * 31 Out High = HDD 2 present + * 32 Out High = HDD 3 present + * 33 Out High = HDD 4 present + * 34 Out High = HDD 5 present + * 35 Out High = HDD 6 present + * 36 Out High = HDD 7 present + * 37 Out High = HDD 8 present + * 38 Out High = HDD 1 fault + * 39 Out High = HDD 2 fault + * 40 Out High = HDD 3 fault + * 41 Out High = HDD 4 fault + * 42 Out High = HDD 5 fault + * 2 Out High = HDD 6 fault + * 3 Out High = HDD 7 fault + * 4 Out High = HDD 8 fault + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {0, 1}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 8, + .gpio_port = {38, 39, 40, 41, 42, 2, 3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 8, + .gpio_port = {29, 31, 32, 33, 34, 35, 36, 37}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 8, + .gpio_port = {10, 11, 22, 23, 24, 25, 26, 27}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {18}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(1); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/ds215+.c b/drivers/syno/synobios/alpine/ds215+.c new file mode 100644 index 000000000000..f85ae71760a8 --- /dev/null +++ b/drivers/syno/synobios/alpine/ds215+.c @@ -0,0 +1,157 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_DS215p; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_215p = MODULE_T_DS215p; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS215p: + pType = &type_215p; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS715/DS215+ GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 2 In HDD_PRZ_1 (Low = HDD insert; High = plug out) + * 3 In HDD_PRZ_1 (Low = HDD insert; High = plug out) + * 5 Out High = SATA LED off + * 34 Out High = LAN LED on + * 19 Out High = Enable ESATA 1 power + * 22 Out High = Enable HDD 1 power (for deep sleep) + * 23 Out High = Enable HDD 1 power (for deep sleep) + * 10 Out High = HDD 1 activity LED + * 11 Out High = HDD 2 activity LED + * 29 Out High = HDD 1 present LED + * 31 Out High = HDD 2 present LED + * 38 Out High = HDD 1 faulty LED + * 39 Out High = HDD 2 faulty LED + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {0}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {38, 39}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {29, 31}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 2, + .gpio_port = {10, 11}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {22, 23}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(1); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/ds416.c b/drivers/syno/synobios/alpine/ds416.c new file mode 100755 index 000000000000..9f69fd4b34fe --- /dev/null +++ b/drivers/syno/synobios/alpine/ds416.c @@ -0,0 +1,204 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" +#include "syno_ttyS.h" + +int GetModel(void) +{ + return MODEL_DS416; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_416 = MODULE_T_DS416; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS416: + pType = &type_416; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int i = 0; + int err = -1; + for (i = 1; i <= 4; ++i) { + switch(ledStatus) { + case SYNO_LED_OFF: + SetDiskLedStatus(i, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SetDiskLedStatus(i, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + } + err = 0; +ERR: + return err; +} + +/* + * DS416 GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 1 In FAN 2 + * 2 In HDD_PRZ_1 (Low = HDD insert; High = plug out) + * 3 In HDD_PRZ_2 (Low = HDD insert; High = plug out) + * 35 In HDD_PRZ_3 (Low = HDD insert; High = plug out) + * 36 In HDD_PRZ_4 (Low = HDD insert; High = plug out) + * 5 Out High = Disk LED off + * 19 Out High = Enable ESATA 1 power + * 10 Out High = HDD 1 activity + * 11 Out High = HDD 2 activity + * 22 Out High = HDD 3 activity + * 23 Out High = HDD 4 activity + * 24 Out High = Enable HDD 1 power (for deep sleep) + * 25 Out High = Enable HDD 2 power (for deep sleep) + * 26 Out High = Enable HDD 3 power (for deep sleep) + * 27 Out High = Enable HDD 4 power (for deep sleep) + * 29 Out High = HDD 1 present + * 31 Out High = HDD 2 present + * 32 Out High = HDD 3 present + * 33 Out High = HDD 4 present + * 38 Out High = HDD 1 fault + * 39 Out High = HDD 2 fault + * 40 Out High = HDD 3 fault + * 41 Out High = HDD 4 fault + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {0, 1}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {38, 39, 40, 41}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 4, + .gpio_port = {29, 31, 32, 33}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 4, + .gpio_port = {10, 11, 22, 23}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {24, 25, 26, 27}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(1); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/ds715.c b/drivers/syno/synobios/alpine/ds715.c new file mode 100644 index 000000000000..7abbdb80ccda --- /dev/null +++ b/drivers/syno/synobios/alpine/ds715.c @@ -0,0 +1,157 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_DS715; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_715 = MODULE_T_DS715; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS715: + pType = &type_715; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS715/DS215+ GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 2 In HDD_PRZ_1 (Low = HDD insert; High = plug out) + * 3 In HDD_PRZ_1 (Low = HDD insert; High = plug out) + * 5 Out High = SATA LED off + * 34 Out High = LAN LED on + * 19 Out High = Enable ESATA 1 power + * 22 Out High = Enable HDD 1 power (for deep sleep) + * 23 Out High = Enable HDD 1 power (for deep sleep) + * 10 Out High = HDD 1 activity LED + * 11 Out High = HDD 2 activity LED + * 29 Out High = HDD 1 present LED + * 31 Out High = HDD 2 present LED + * 38 Out High = HDD 1 faulty LED + * 39 Out High = HDD 2 faulty LED + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {0}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {38, 39}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {29, 31}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 2, + .gpio_port = {10, 11}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {22, 23}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(1); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/alpine/fan-pwm.c b/drivers/syno/synobios/alpine/fan-pwm.c new file mode 100755 index 000000000000..8ed60c87fc2c --- /dev/null +++ b/drivers/syno/synobios/alpine/fan-pwm.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include "synobios.h" +#include +#include "alpine_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + int iHz = -1; + char szUartCmd[5] = {0}; + + if (status == FAN_STATUS_STOP) { + speed = FAN_SPEED_STOP; + } + + if (FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + iHz = FAN_SPEED_SHIFT_HZ_GET((int)speed); + if (iHz > 0) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, iHz); + if(0 > synobios_lock_ttyS_write(szUartCmd)) { + goto END; + } + } + } else { + iFanDuty = PWMFanSpeedMapping(speed); + if (iFanDuty < 0) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if (0 > synobios_lock_ttyS_write(szUartCmd)) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/alpine/rs1219.c b/drivers/syno/synobios/alpine/rs1219.c new file mode 100644 index 000000000000..6abf9e033bec --- /dev/null +++ b/drivers/syno/synobios/alpine/rs1219.c @@ -0,0 +1,176 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "alpine_common.h" + +int GetModel(void) +{ + return MODEL_RS1219; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1700); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_rs1219 = MODULE_T_RS1219; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS1219: + pType = &type_rs1219; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +/* + * DS1219 GPIO config table + * (High=1) + * + * Pin In/Out Function + * 0 In FAN 1 + * 1 In FAN 2 + * 5 Out High = Disk LED off + * 10 Out High = HDD 1 activity + * 11 Out High = HDD 2 activity + * 22 Out High = HDD 3 activity + * 23 Out High = HDD 4 activity + * 24 Out High = HDD 5 activity + * 25 Out High = HDD 6 activity + * 26 Out High = HDD 7 activity + * 27 Out High = HDD 8 activity + * 29 Out High = HDD 1 present + * 31 Out High = HDD 2 present + * 32 Out High = HDD 3 present + * 33 Out High = HDD 4 present + * 34 Out High = HDD 5 present + * 35 Out High = HDD 6 present + * 36 Out High = HDD 7 present + * 37 Out High = HDD 8 present + * 38 Out High = HDD 1 fault + * 39 Out High = HDD 2 fault + * 40 Out High = HDD 3 fault + * 41 Out High = HDD 4 fault + * 42 Out High = HDD 5 fault + * 2 Out High = HDD 6 fault + * 3 Out High = HDD 7 fault + * 4 Out High = HDD 8 fault + * 43 Out VTT off + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {0, 1}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 8, + .gpio_port = {38, 39, 40, 41, 42, 2, 3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 8, + .gpio_port = {29, 31, 32, 33, 34, 35, 36, 37}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_act_led = { + .nr_gpio = 8, + .gpio_port = {10, 11, 22, 23, 24, 25, 26, 27}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {18}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 8, + .gpio_port = {63, 60, 58, 56, 62, 61, 59, 57}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = &hdd_act_led; + } else { + check_gpio_consistency(syno_gpio.hdd_act_led, &hdd_act_led); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_act_led == syno_gpio.hdd_act_led) { + syno_gpio.hdd_act_led = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/apollolake/Makefile b/drivers/syno/synobios/apollolake/Makefile new file mode 100644 index 000000000000..8659c61aa978 --- /dev/null +++ b/drivers/syno/synobios/apollolake/Makefile @@ -0,0 +1,29 @@ +include /env.mak + +obj-m += apollolake-synobios.o + +apollolake-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds918p.o \ + ds218p.o \ + ds718p.o \ + ds418play.o \ + ds419p.o \ + ds1019p.o \ + ds719p.o \ + ds620slim.o \ + rs419p.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + apollolake_common.o + +ifneq (,$(filter $(PLAT_SPEC_VAR), SYNO_FEA_PORT_MAPPING_V2)) + apollolake-synobios-objs += \ + ../led/led_trigger.o +endif diff --git a/drivers/syno/synobios/apollolake/apollolake_common.c b/drivers/syno/synobios/apollolake/apollolake_common.c new file mode 100755 index 000000000000..3b2cf4bb3cfd --- /dev/null +++ b/drivers/syno/synobios/apollolake/apollolake_common.c @@ -0,0 +1,774 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#include "../rtc/rtc.h" + +#include "apollolake_common.h" + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int giAlertGPIOPin = -1; + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strncmp(gszSynoHWVersion, HW_DS918p, strlen(HW_DS918p) ) ) { + model = MODEL_DS918p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS218p, strlen(HW_DS218p) ) ) { + model = MODEL_DS218p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS718p, strlen(HW_DS718p) ) ) { + model = MODEL_DS718p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS418play, strlen(HW_DS418play) ) ) { + model = MODEL_DS418play; + } else if ( !strncmp(gszSynoHWVersion, HW_DS419p, strlen(HW_DS419p) ) ) { + model = MODEL_DS419p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1019p, strlen(HW_DS1019p) ) ) { + model = MODEL_DS1019p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS719p, strlen(HW_DS719p) ) ) { + model = MODEL_DS719p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS620slim, strlen(HW_DS620slim) ) ) { + model = MODEL_DS620slim; + } else if ( !strncmp(gszSynoHWVersion, HW_RS419p, strlen(HW_RS419p) ) ) { + model = MODEL_RS419p; + } + + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_DS218p: + case MODEL_DS718p: + case MODEL_DS719p: + iInternalDiskNum = 2; + break; + case MODEL_DS418play: + case MODEL_DS918p: + case MODEL_DS419p: + iInternalDiskNum = 4; + break; + case MODEL_DS1019p: + iInternalDiskNum = 5; + break; + case MODEL_DS620slim: + iInternalDiskNum = 6; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +static +int SetDiskLedStatusByLedTrigger(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != iStatus) { + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if (0 >= iDiskNum || 8 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByLedTrigger(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByLedTrigger(iHostNum + 1, iStatus); +} + +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 8 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 8 * sizeof(int)); + memset(gpOrangeLedMap, -1, 8 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} +#endif // CONFIG_SYNO_LEDS_TRIGGER +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx = 0; + + if (NULL == pCpuTemp) { + goto END; + } +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface ) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] -= 5; + + if (40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } + +END: + return iRet; +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + /* Front LAN LEDs and RJ45 Phy LEDs are contoled by GPIO pin APOLLOLAKE_GPIO_LAN_LED_CTL */ + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + iError = 0; +ERR: + return iError; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ +if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskTriggerLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 8 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 8 * sizeof(int)); + memset(gpOrangeLedMap, -1, 8 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +/* + * For GPIO alert Led, there is no blinking + */ +static +int SetAlarmLedByGPIO(unsigned char type) +{ + GPIO_PIN pin; + int iRet = -1; + + if (0 > giAlertGPIOPin) { + goto END; + } + + if (type) { + pin.value = 1; + }else{ + pin.value = 0; + } + pin.pin = giAlertGPIOPin; + SetGpioPin(&pin); + + iRet = 0; + +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int iInternalDiskNum = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iInternalDiskNum = GetMaxInternalDiskNum(); + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_DETECT(index)) { + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index-1); + } + } + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_ENABLE(index)) { + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01) << (index-1); + } + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_DS918p: + model_ops = &ds918p_ops; + hwmon_sensor_list = &ds918p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif + break; + case MODEL_DS218p: + model_ops = &ds218p_ops; + hwmon_sensor_list = &ds218p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; + break; + + case MODEL_DS718p: + model_ops = &ds718p_ops; + hwmon_sensor_list = &ds718p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; + break; + case MODEL_DS418play: + model_ops = &ds418play_ops; + hwmon_sensor_list = &ds418play_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif + break; + case MODEL_DS419p: + model_ops = &ds419p_ops; + hwmon_sensor_list = &ds419p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif + break; + case MODEL_DS1019p: + model_ops = &ds1019p_ops; + hwmon_sensor_list = &ds1019p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[5]){0,2,4,6,8}, (int[5]){1,3,5,7,9}, 5); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(4, 1); +#endif + break; + case MODEL_DS719p: + model_ops = &ds719p_ops; + hwmon_sensor_list = &ds719p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + break; + case MODEL_DS620slim: + model_ops = &ds620slim_ops; + hwmon_sensor_list = &ds620slim_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; + giAlertGPIOPin = 16; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[6]){0,2,4,6,8,10}, (int[6]){1,3,5,7,9,11}, 6); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(4, 1); + syno_ahci_disk_led_enable(5, 1); +#endif + break; + case MODEL_RS419p: + model_ops = &rs419p_ops; + hwmon_sensor_list = &rs419p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif + break; + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/apollolake/apollolake_common.h b/drivers/syno/synobios/apollolake/apollolake_common.h new file mode 100755 index 000000000000..fbf4f793a93c --- /dev/null +++ b/drivers/syno/synobios/apollolake/apollolake_common.h @@ -0,0 +1,126 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include "../led/led_trigger.h" +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#include "../common/common.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds918p_ops; +extern struct model_ops ds218p_ops; +extern struct model_ops ds718p_ops; +extern struct model_ops ds418play_ops; +extern struct model_ops ds419p_ops; +extern struct model_ops ds1019p_ops; +extern struct model_ops ds719p_ops; +extern struct model_ops ds620slim_ops; +extern struct model_ops rs419p_ops; + +extern struct hwmon_sensor_list ds918p_sensor_list; +extern struct hwmon_sensor_list ds218p_sensor_list; +extern struct hwmon_sensor_list ds718p_sensor_list; +extern struct hwmon_sensor_list ds418play_sensor_list; +extern struct hwmon_sensor_list ds419p_sensor_list; +extern struct hwmon_sensor_list ds1019p_sensor_list; +extern struct hwmon_sensor_list ds719p_sensor_list; +extern struct hwmon_sensor_list ds620slim_sensor_list; +extern struct hwmon_sensor_list rs419p_sensor_list; +extern struct hwmon_sensor_list ds220p_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +/* Apollolake will use LP3943 as disk led controler */ +#if defined(CONFIG_SYNO_LEDS_TRIGGER) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY && ! CONFIG_SYNO_PORT_MAPPING_V2 */ + +/* + * Apollo Lake has 4 GPIO controllers with different number of pins which are loosely arranged. + * We hard-coded the base offsets of these controllers so the GPIO number can be determined at static time, + * and the ranges are asigned in the pinctrl driver. + * look up for the pin number in linux-4.4.x/drivers/pinctrl/intel/pinctrl-broxton.c + * The global gpio number ranges of each controller are listed below - + * North 0~77; + * NorthWest 78~154; + * West 155~201; + * SouthWest 202~244; + */ + +/* Fan Sense */ +#define APOLLOLAKE_GPIO_FAN1_SEN 17 // GPIO_17 +#define APOLLOLAKE_GPIO_FAN2_SEN 16 // GPIO_16 +/* LED/Button */ +#define APOLLOLAKE_GPIO_HDD_LED_CTL 14 // GPIO_14 +#define APOLLOLAKE_GPIO_LAN_LED_CTL 15 // GPIO_15 +#define APOLLOLAKE_GPIO_USB_COPY_BTN 174 // ISH_GPIO_3 +#define APOLLOLAKE_GPIO_FRONT_LED_CTL 12 // GPIO_12 +/* Disk Present */ +#define APOLLOLAKE_GPIO_HDD1_PRE 18 // GPIO_18 +#define APOLLOLAKE_GPIO_HDD2_PRE 179 // ISH_GPIO_8 +#define APOLLOLAKE_GPIO_HDD3_PRE 176 // ISH_GPIO_5 +#define APOLLOLAKE_GPIO_HDD4_PRE 175 // ISH_GPIO_4 +/* Disk Power Enable */ +#define APOLLOLAKE_GPIO_HDD1_PWR_EN 21 // GPIO_21 +#define APOLLOLAKE_GPIO_HDD2_PWR_EN 20 // GPIO_20 +#define APOLLOLAKE_GPIO_HDD3_PWR_EN 19 // GPIO_19 +#define APOLLOLAKE_GPIO_HDD4_PWR_EN 9 // GPIO_9 +/* USB Power Enable */ +#define APOLLOLAKE_GPIO_USB_0_PWR_EN 11 // GPIO_11 +#define APOLLOLAKE_GPIO_USB_1_PWR_EN 10 // GPIO_10 +#define APOLLOLAKE_GPIO_USB_FP_PWR_EN 13 // GPIO_13 + + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/apollolake/ds1019p.c b/drivers/syno/synobios/apollolake/ds1019p.c new file mode 100644 index 000000000000..f336841115a5 --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds1019p.c @@ -0,0 +1,158 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS1019pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +// 177: ISH_GPIO_6 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 5, + .gpio_port = {18,179,176,175,177}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +// 173: ISH_GPIO_2 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 5, + .gpio_port = {21, 20, 19, 9, 173}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds1019p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS1019pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS1019pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS1019pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1019p = MODULE_T_DS1019p; + module_t *pType = &type_1019p; + + module_type_set(pType); + return 0; +} + +static +int DS1019pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1019pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1019pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1019pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1019p_ops = { + .x86_init_module_type = DS1019pInitModuleType, + .x86_fan_speed_mapping = DS1019pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1019pGpioInit, + .x86_gpio_cleanup = DS1019pGpioCleanup, +}; + +struct hwmon_sensor_list ds1019p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds1019p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds218p.c b/drivers/syno/synobios/apollolake/ds218p.c new file mode 100644 index 000000000000..0c9b503ec32e --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds218p.c @@ -0,0 +1,156 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS218pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {18,179,176,175}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {21, 20, 19, 9}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds218p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS218pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS218pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS218pInitModuleType(struct synobios_ops *ops) +{ + module_t type_218p = MODULE_T_DS218p; + module_t *pType = &type_218p; + + module_type_set(pType); + return 0; +} + +static +int DS218pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS218pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS218pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS218pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds218p_ops = { + .x86_init_module_type = DS218pInitModuleType, + .x86_fan_speed_mapping = DS218pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS218pGpioInit, + .x86_gpio_cleanup = DS218pGpioCleanup, +}; + +struct hwmon_sensor_list ds218p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds218p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds418play.c b/drivers/syno/synobios/apollolake/ds418play.c new file mode 100644 index 000000000000..66601375569f --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds418play.c @@ -0,0 +1,165 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS418playSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {18,179,176,175}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {21, 20, 19, 9}, + .gpio_polarity = ACTIVE_HIGH, +}; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds418play_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS418playGpioInit(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS418playGpioCleanup(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS418playInitModuleType(struct synobios_ops *ops) +{ + module_t type_418play = MODULE_T_DS418play; + module_t *pType = &type_418play; + + module_type_set(pType); + return 0; +} + +static +int DS418playFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS418playSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS418playSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS418playSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds418play_ops = { + .x86_init_module_type = DS418playInitModuleType, + .x86_fan_speed_mapping = DS418playFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS418playGpioInit, + .x86_gpio_cleanup = DS418playGpioCleanup, +}; + +struct hwmon_sensor_list ds418play_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds418play_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds419p.c b/drivers/syno/synobios/apollolake/ds419p.c new file mode 100644 index 000000000000..ee27ee07c651 --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds419p.c @@ -0,0 +1,156 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS419pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {18,179,176,175}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {21, 20, 19, 9}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds419p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS419pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS419pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS419pInitModuleType(struct synobios_ops *ops) +{ + module_t type_419p = MODULE_T_DS419p; + module_t *pType = &type_419p; + + module_type_set(pType); + return 0; +} + +static +int DS419pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS419pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS419pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS419pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds419p_ops = { + .x86_init_module_type = DS419pInitModuleType, + .x86_fan_speed_mapping = DS419pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS419pGpioInit, + .x86_gpio_cleanup = DS419pGpioCleanup, +}; + +struct hwmon_sensor_list ds419p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds419p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds620slim.c b/drivers/syno/synobios/apollolake/ds620slim.c new file mode 100644 index 000000000000..55518c9bc1da --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds620slim.c @@ -0,0 +1,159 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS620slimSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +// 177: ISH_GPIO_6 +// 171: ISH_GPIO_0 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 6, + .gpio_port = {18,179,176,175,177,171}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +// 173: ISH_GPIO_2 +// 172: ISH_GPIO_1 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 6, + .gpio_port = {21, 20, 19, 9, 173, 172}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_27 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {27}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds620slim_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS620slimGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS620slimGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS620slimInitModuleType(struct synobios_ops *ops) +{ + module_t type_620slim = MODULE_T_DS620slim; + module_t *pType = &type_620slim; + + module_type_set(pType); + return 0; +} + +static +int DS620slimFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS620slimSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS620slimSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS620slimSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds620slim_ops = { + .x86_init_module_type = DS620slimInitModuleType, + .x86_fan_speed_mapping = DS620slimFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS620slimGpioInit, + .x86_gpio_cleanup = DS620slimGpioCleanup, +}; + +struct hwmon_sensor_list ds620slim_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds620slim_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds718p.c b/drivers/syno/synobios/apollolake/ds718p.c new file mode 100644 index 000000000000..1466329dd4d7 --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds718p.c @@ -0,0 +1,156 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS718pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {18,179,176,175}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {21, 20, 19, 9}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds718p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS718pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS718pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS718pInitModuleType(struct synobios_ops *ops) +{ + module_t type_718p = MODULE_T_DS718p; + module_t *pType = &type_718p; + + module_type_set(pType); + return 0; +} + +static +int DS718pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS718pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS718pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS718pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds718p_ops = { + .x86_init_module_type = DS718pInitModuleType, + .x86_fan_speed_mapping = DS718pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS718pGpioInit, + .x86_gpio_cleanup = DS718pGpioCleanup, +}; + +struct hwmon_sensor_list ds718p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds718p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds719p.c b/drivers/syno/synobios/apollolake/ds719p.c new file mode 100644 index 000000000000..5225e7716fea --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds719p.c @@ -0,0 +1,152 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS719pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 175: ISH_GPIO_4 +// 177: ISH_GPIO_6 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {175,177}, + .gpio_polarity = ACTIVE_LOW, +}; +// 9: GPIO_9 +// 173: ISH_GPIO_2 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {9, 173}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds719p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS719pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS719pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS719pInitModuleType(struct synobios_ops *ops) +{ + module_t type_719p = MODULE_T_DS719p; + module_t *pType = &type_719p; + + module_type_set(pType); + return 0; +} + +static +int DS719pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS719pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS719pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS719pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds719p_ops = { + .x86_init_module_type = DS719pInitModuleType, + .x86_fan_speed_mapping = DS719pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS719pGpioInit, + .x86_gpio_cleanup = DS719pGpioCleanup, +}; + +struct hwmon_sensor_list ds719p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds719p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/ds918p.c b/drivers/syno/synobios/apollolake/ds918p.c new file mode 100644 index 000000000000..4d4d52128873 --- /dev/null +++ b/drivers/syno/synobios/apollolake/ds918p.c @@ -0,0 +1,156 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gDS918pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {17, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {18,179,176,175}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {21, 20, 19, 9}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds918p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void DS918pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS918pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS918pInitModuleType(struct synobios_ops *ops) +{ + module_t type_918p = MODULE_T_DS918p; + module_t *pType = &type_918p; + + module_type_set(pType); + return 0; +} + +static +int DS918pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS918pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS918pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS918pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds918p_ops = { + .x86_init_module_type = DS918pInitModuleType, + .x86_fan_speed_mapping = DS918pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS918pGpioInit, + .x86_gpio_cleanup = DS918pGpioCleanup, +}; + +struct hwmon_sensor_list ds918p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds918p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/apollolake/rs419p.c b/drivers/syno/synobios/apollolake/rs419p.c new file mode 100644 index 000000000000..57d8d6e006b5 --- /dev/null +++ b/drivers/syno/synobios/apollolake/rs419p.c @@ -0,0 +1,170 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "apollolake_common.h" + +PWM_FAN_SPEED_MAPPING gRS419pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// 17: GPIO_17 +// 16: GPIO_16 +// 26: GPIO_26 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 3, + .gpio_port = {17, 16, 26}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 18: GPIO_18 +// 179: ISH_GPIO_8 +// 176: ISH_GPIO_5 +// 175: ISH_GPIO_4 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {18,179,176,175}, + .gpio_polarity = ACTIVE_LOW, +}; +// 21: GPIO_21 +// 20: GPIO_20 +// 19: GPIO_19 +// 9: GPIO_9 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {21, 20, 19, 9}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 12: GPIO_14 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {14}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 15: GPIO_15 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 174: ISH_GPIO_3 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {174}, + .gpio_polarity = ACTIVE_LOW, +}; +// 178: ISH_GPIO_7 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {178}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE rs419p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +void RS419pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS419pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS419pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs419p = MODULE_T_RS419p; + module_t *pType = &type_rs419p; + + module_type_set(pType); + return 0; +} + +static +int RS419pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS419pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS419pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS419pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int getBuzzerButtonStatus(unsigned char *pValue) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(pValue); +} + +struct model_ops rs419p_ops = { + .x86_init_module_type = RS419pInitModuleType, + .x86_fan_speed_mapping = RS419pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = getBuzzerButtonStatus, + .x86_gpio_init = RS419pGpioInit, + .x86_gpio_cleanup = RS419pGpioCleanup, +}; + +struct hwmon_sensor_list rs419p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &rs419p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/armada/Makefile b/drivers/syno/synobios/armada/Makefile new file mode 100644 index 000000000000..ee04e614e356 --- /dev/null +++ b/drivers/syno/synobios/armada/Makefile @@ -0,0 +1,54 @@ +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADA370) +obj-m += ds213j-synobios.o +obj-m += ds114-synobios.o +obj-m += rs214-synobios.o +obj-m += ds214se-synobios.o +obj-m += ds414slim-synobios.o +obj-m += ds115j-synobios.o +obj-m += ds216se-synobios.o +obj-m += thermal_ctrl.o +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADAXP) +obj-m += ds414-synobios.o +obj-m += ds214-synobios.o +obj-m += rs814-synobios.o +obj-m += ds214p-synobios.o +obj-m += rs815-synobios.o +endif +ifeq ($(SYNO_PLATFORM),MARVELL_ARMADA375) +obj-m += ds215j-synobios.o +obj-m += ds115-synobios.o +endif + +common-obj += \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-ricoh-lib.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-ricoh.o \ + ../rtc/rtc-linux-seiko.o \ + ../rtc/rtc-mv-builtin.o \ + ../mapping.o \ + armada_common.o \ + mv_level_button.o + +fan-pwm-obj += fan-pwm.o +fan-resister-obj += fan-resister.o + +ds213j-synobios-objs = ds213j.o $(fan-resister-obj) $(common-obj) +ds114-synobios-objs = ds114.o $(fan-resister-obj) $(common-obj) +rs214-synobios-objs = rs214.o $(fan-resister-obj) $(common-obj) +ds414-synobios-objs = ds414.o $(fan-pwm-obj) $(common-obj) +ds214-synobios-objs = ds214.o $(fan-pwm-obj) $(common-obj) +rs814-synobios-objs = rs814.o $(fan-pwm-obj) $(common-obj) +ds214se-synobios-objs = ds214se.o $(fan-resister-obj) $(common-obj) +ds214p-synobios-objs = ds214p.o $(fan-pwm-obj) $(common-obj) +ds115j-synobios-objs = ds115j.o $(fan-resister-obj) $(common-obj) +ds414slim-synobios-objs = ds414slim.o $(fan-resister-obj) $(common-obj) +ds215j-synobios-objs = ds215j.o $(fan-resister-obj) $(common-obj) +ds115-synobios-objs = ds115.o $(fan-resister-obj) $(common-obj) +rs815-synobios-objs = rs815.o $(fan-pwm-obj) $(common-obj) +ds216se-synobios-objs = ds216se.o $(fan-resister-obj) $(common-obj) diff --git a/drivers/syno/synobios/armada/armada_common.c b/drivers/syno/synobios/armada/armada_common.c new file mode 100755 index 000000000000..4c287038c79e --- /dev/null +++ b/drivers/syno/synobios/armada/armada_common.c @@ -0,0 +1,491 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "synobios.h" +#include +#include +#include "armada_common.h" +#include "../mapping.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "syno_ttyS.h" + +/* all armada370 models share same synobios_model_init/cleanup(), + each model must implement their own model_private_init/cleanup() */ +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); + +#define MAX_ENABLE_PIN_NUM 4 +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int *hdd_enable_gpio = NULL; + +int armada_hdd_enable_gpio[4] = {-1, -1, -1, -1}; + +SYNO_HWMON_SENSOR_TYPE armada_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +struct hwmon_sensor_list armada_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &armada_hdd_backplane_status, +}; + + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static int Uninitialize(void); + +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gPWMSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gPWMSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus) +{ + int FanStatus; + + if (1 > fanno || 3 < fanno) { + return -EINVAL; + } + + if (NULL == pStatus) { + return -EINVAL; + } + + SYNO_CTRL_FAN_STATUS_GET(fanno, &FanStatus); + if (FanStatus) { + *pStatus = FAN_STATUS_RUNNING; + } else { + *pStatus = FAN_STATUS_STOP; + } + + return 0; +} + +int GetFanStatusActivePulse(int fanno, FAN_STATUS *pStatus) +{ + int FanStatus; + int rgcVolt[2] = {0, 0}; + + if ( 1 > fanno || 3 < fanno) { + return -EINVAL; + } + + do { + SYNO_CTRL_FAN_STATUS_GET(fanno, &FanStatus); + rgcVolt[(int)FanStatus] ++; + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ( (rgcVolt[0] + rgcVolt[1]) < 200 ); + + if ((rgcVolt[0] == 0) || (rgcVolt[1] == 0) ) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + + return 0; +} + +static int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 0 != SYNO_ARMADA_GPIO_PIN((int)pPin->pin, (int*)&pPin->value, 1) ) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 0 != SYNO_ARMADA_GPIO_PIN((int)pPin->pin, (int*)&pPin->value, 0) ) { + goto End; + } + + ret = 0; +End: + return ret; +} + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +/*FIXME - Too brutal and directly, should separate into levels*/ +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + /*Scsi host in kernel is zero-based, disknum here is one-based, + *so we should minus 1 while calling the function + */ + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status){ + syno_sata_mv_gpio_write( 1, disknum - 1); + }else{ + syno_sata_mv_gpio_write( 0, disknum - 1); + } + + err = 0; +END: + return err; +} +#endif /* MY_DEF_HERE */ + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int value; + int model = GetModel(); + + if (model != MODEL_RS214) { + goto END; + } + + SYNO_CTRL_BUZZER_CLEARED_GET(&value); + if(value) { + *buzzer_cleared = 1; + } else { + *buzzer_cleared = 0; + } + +END: + return 0; +} + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int ret = -1; + + if (!pCPUTemp) { + goto END; + } + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = axptemp_read_temp() - 13; + + ret = 0; +END: + return ret; +} + +int EnablePhyLed(SYNO_LED ledStatus) +{ + int iPhyAddr; + unsigned short uiRegValue; + int err = -1; + + iPhyAddr = mvBoardPhyAddrGet(PHY_PORTNUM); + + if (-1 == iPhyAddr) { + goto ERR; + } + + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, 0x3); /*set to page 3*/ + mvEthPhyRegRead((unsigned int)iPhyAddr, 0x10, &uiRegValue); + + switch(ledStatus){ + /*Set Phy led[1] of led[1-2]*/ + case SYNO_LED_ON: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0001; + break; + case SYNO_LED_OFF: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0008; + break; + default: + goto ERR; + } + + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x10, uiRegValue); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, 0x0); /*set to page 0*/ + + err = 0; + +ERR: + return err; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int err = -1; + switch(ledStatus) { + case SYNO_LED_OFF: + SYNO_SOC_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_SOC_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_SOC_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + SYNO_SOC_HDD_LED_SET(2, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +int set_disk_led_one(SYNO_LED ledStatus) +{ + int err = -1; + switch(ledStatus) { + case SYNO_LED_OFF: + SYNO_SOC_HDD_LED_SET(1, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_SOC_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + GPIO_PIN pPin; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list || NULL == hdd_enable_gpio) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < MAX_ENABLE_PIN_NUM; index++){ + if (NULL != hdd_enable_gpio) { + if (-1 == hdd_enable_gpio[index]) { + break; + } + pPin.pin = hdd_enable_gpio[index]; + GetGpioPin(&pPin); + hdd_enable |= (pPin.value & 0x01) << index; + } + } + + if (NULL != hdd_enable_gpio) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; + +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = SetPowerLedStatus, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .set_alarm_led = NULL, + .get_backplane_status = NULL, + .get_mem_byte = NULL, + .get_buzzer_cleared = GetBuzzerCleared, + .set_phy_led = EnablePhyLed, + .set_hdd_led = SetHDDActLed, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + hwmon_sensor_list = &armada_sensor_list; + switch (GetModel()) { + case MODEL_DS114: + case MODEL_DS115: + case MODEL_DS115j: + case MODEL_DS213j: + case MODEL_DS214: + case MODEL_DS214p: + case MODEL_DS214se: + case MODEL_DS215j: + case MODEL_DS216se: + case MODEL_DS414: + case MODEL_RS214: + case MODEL_RS814: + case MODEL_RS815: + hdd_enable_gpio = armada_hdd_enable_gpio; + break; + default: + hwmon_sensor_list = NULL; + hdd_enable_gpio = NULL; + synobios_ops.hwmon_get_backplane_status = NULL; + break; + } + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + if( pSynoModule && RTC_SEIKO == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = rtc_seiko_get_time; + synobios_ops.set_rtc_time = rtc_seiko_set_time; + synobios_ops.get_auto_poweron = rtc_get_auto_poweron; + synobios_ops.set_auto_poweron = rtc_seiko_set_auto_poweron; + synobios_ops.init_auto_poweron = rtc_seiko_auto_poweron_init; + synobios_ops.uninit_auto_poweron = rtc_seiko_auto_poweron_uninit; + } + if( pSynoModule && RTC_MV == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = rtc_mv_get_time; + synobios_ops.set_rtc_time = rtc_mv_set_time; + switch(GetModel()) + { + case MODEL_DS414: + case MODEL_RS814: + case MODEL_DS215j: + case MODEL_DS115: + case MODEL_RS815: + synobios_ops.init_auto_poweron = rtc_mv_auto_poweron_clean; + synobios_ops.get_auto_poweron = rtc_get_auto_poweron; + synobios_ops.set_auto_poweron = rtc_mv_set_auto_poweron; + break; + default: + synobios_ops.init_auto_poweron = NULL; + synobios_ops.get_auto_poweron = NULL; + synobios_ops.set_auto_poweron = NULL; + break; + } + synobios_ops.uninit_auto_poweron = rtc_mv_auto_poweron_clean; + } + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + + return 0; +} + +static int Uninitialize(void) +{ + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + model_addon_cleanup(*ops); + + return 0; +} + diff --git a/drivers/syno/synobios/armada/armada_common.h b/drivers/syno/synobios/armada/armada_common.h new file mode 100755 index 000000000000..d8bf802a5860 --- /dev/null +++ b/drivers/syno/synobios/armada/armada_common.h @@ -0,0 +1,99 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include "../mapping.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#define PHY_PORTNUM 0 + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetUsbDiskLedStatus(SYNO_DISK_LED status); +int SetPowerLedStatus(SYNO_LED status); +int GetFanStatusActivePulse(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +int GetFanNum(int *pFanNum); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int GetFanSpeedBits(int start, int end, MEMORY_BYTE *pMemory); +int GetMemByte( MEMORY_BYTE *pMemory ); +int InitModuleType(struct synobios_ops *ops); +int FanStatusMappingRS409r1(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int PWMFanSpeedMapping(FAN_SPEED speed); +int SetPhyLed(SYNO_LED ledStatus); +int SetHDDActLed(SYNO_LED ledStatus); +int SYNO_ARMADA_GPIO_PIN(int pin, int *pValue, int isWrite); +int SYNO_ARMADA_GPIO_BLINK(int pin, int blink); +int SYNO_CTRL_FAN_STATUS_GET(int index, int *pValue); +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +extern int SYNO_CTRL_BUZZER_CLEARED_GET(int *pValue); +extern int SynoArmadaSetPhyLed(SYNO_LED); +#ifdef MY_DEF_HERE +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status); +#endif +extern int SYNO_CTRL_EXT_CHIP_HDD_LED_SET(int index, int status); +extern int SYNO_CTRL_FAN_PERSISTER(int index, int status, int isWrite); +extern int SYNO_SOC_HDD_LED_SET(int index, int status); +extern int set_disk_led_one(SYNO_LED ledStatus); + +extern int axptemp_read_temp(void); + +/* common method of armada platform by synology in synobios */ + +/* Referenced BSP methods */ +extern int mvBoardPhyAddrGet(unsigned int uiEthPortNum); +extern int mvEthPhyRegRead(unsigned int uiPhyAddr, unsigned int uiRegOffs, unsigned short *pData); +extern int mvEthPhyRegWrite(unsigned int uiPhyAddr, unsigned int uiRegOffs, unsigned short uiData); + +/* Referenced synology kernel method */ +extern int SYNO_ENABLE_HDD_LED(int enable); +extern int SYNO_ENABLE_PHY_LED(int enable); +int EnablePhyLed(SYNO_LED ledStatus); +int SetHDDActLed(SYNO_LED ledStatus); + +/****************************** + * Level button structure and functions + * link with mv_level_button.c + *******************************/ +typedef enum { + BTN_PRESSED, + BTN_RELEASED +} BTN_STAT; + +struct level_button { + char *name; + int irq; + int gpio; + int is_high_pressed; + int (*press_act)(void*); + int (*release_act)(void*); + BTN_STAT stat; +}; + +int level_button_init(struct level_button *btn); +int level_button_exit(struct level_button *btn); + +extern int armada_hdd_enable_gpio[4]; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; \ No newline at end of file diff --git a/drivers/syno/synobios/armada/ds114.c b/drivers/syno/synobios/armada/ds114.c new file mode 100755 index 000000000000..1917ad2ec894 --- /dev/null +++ b/drivers/syno/synobios/armada/ds114.c @@ -0,0 +1,67 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS114; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_114v1 = MODULE_T_DS114v1; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS114: + pType = &type_114v1; + armada_hdd_enable_gpio[0] = 37; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->set_hdd_led = set_disk_led_one; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds115.c b/drivers/syno/synobios/armada/ds115.c new file mode 100755 index 000000000000..9fc7804a5ca3 --- /dev/null +++ b/drivers/syno/synobios/armada/ds115.c @@ -0,0 +1,67 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS115; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_115 = MODULE_T_DS115; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS115: + pType = &type_115; + armada_hdd_enable_gpio[0] = 24; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->set_hdd_led = set_disk_led_one; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds115j.c b/drivers/syno/synobios/armada/ds115j.c new file mode 100755 index 000000000000..908243c92e27 --- /dev/null +++ b/drivers/syno/synobios/armada/ds115j.c @@ -0,0 +1,70 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + +extern int SYNO_ENABLE_USB_POWER(int enable); + +int GetModel(void) +{ + return MODEL_DS115j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_115j = MODULE_T_DS115j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS115j: + pType = &type_115j; + armada_hdd_enable_gpio[0] = 37; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + if (disknum > 1) + return 0; + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->set_hdd_led = set_disk_led_one; + SYNO_ENABLE_USB_POWER(TRUE); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds213j.c b/drivers/syno/synobios/armada/ds213j.c new file mode 100755 index 000000000000..3a5b1e55604c --- /dev/null +++ b/drivers/syno/synobios/armada/ds213j.c @@ -0,0 +1,66 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS213j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_213jv1 = MODULE_T_DS213jv1; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS213j: + pType = &type_213jv1; + armada_hdd_enable_gpio[0] = 37; + armada_hdd_enable_gpio[1] = 62; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds214.c b/drivers/syno/synobios/armada/ds214.c new file mode 100755 index 000000000000..6479c534dd80 --- /dev/null +++ b/drivers/syno/synobios/armada/ds214.c @@ -0,0 +1,151 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS214; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1066); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_214v1 = MODULE_T_DS214; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS214: + pType = &type_214v1; + armada_hdd_enable_gpio[0] = 37; + armada_hdd_enable_gpio[1] = 62; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +static int set_hdd_led_enabled(SYNO_LED ledStatus) +{ + int err = -1; + + switch(ledStatus) { + case SYNO_LED_OFF: + SYNO_SOC_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_SOC_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_SOC_HDD_LED_SET(1, DISK_LED_GREEN_SOLID); + SYNO_SOC_HDD_LED_SET(2, DISK_LED_GREEN_SOLID); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +#include +#define IRQ_AURORA_GBE0_FIC 8 +#define LINK_DELAY_MS 10 +int SetPhyLed(SYNO_LED ledStatus) +{ + int iPhyAddr; + unsigned short uiRegValue; + int err = -1; + + iPhyAddr = mvBoardPhyAddrGet(0); + + if (-1 == iPhyAddr) { + goto ERR; + } + + /* Eth phy mv1512 will link down/up when switch register page from/to 0, + and instand link up/down will cause link handle error in multi-core (ex. AXP). + Thus we disable GBE interrupt and wait a short period to make sure + eth link stat stable */ + disable_irq(IRQ_AURORA_GBE0_FIC); + + mdelay(LINK_DELAY_MS); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, 0x3); /*set to page 3*/ + mdelay(LINK_DELAY_MS); + mvEthPhyRegRead((unsigned int)iPhyAddr, 0x10, &uiRegValue); + mdelay(LINK_DELAY_MS); + + switch(ledStatus){ + /*Set Phy led[0] of led[0-2]*/ + case SYNO_LED_ON: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0001; + break; + case SYNO_LED_OFF: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0008; + break; + default: + goto ERR; + } + + mdelay(LINK_DELAY_MS); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x10, uiRegValue); + mdelay(LINK_DELAY_MS); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, 0x0); /*set to page 0*/ + mdelay(LINK_DELAY_MS); + + enable_irq(IRQ_AURORA_GBE0_FIC); + + err = 0; + +ERR: + return err; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* Tricky Fix! + Set disk led green to turn on MPP[24,25] sata preset function */ + SYNO_SOC_HDD_LED_SET(1, DISK_LED_GREEN_SOLID); + SYNO_SOC_HDD_LED_SET(2, DISK_LED_GREEN_SOLID); + + ops->set_hdd_led = set_hdd_led_enabled; + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds214p.c b/drivers/syno/synobios/armada/ds214p.c new file mode 100755 index 000000000000..3647cb1c1675 --- /dev/null +++ b/drivers/syno/synobios/armada/ds214p.c @@ -0,0 +1,77 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS214p; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1333); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_DS214p; + module_type_set(&type); + armada_hdd_enable_gpio[0] = 42; + armada_hdd_enable_gpio[1] = 44; + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + return SetDiskLedStatusBySataMvGPIO(disknum, status); +#else + return 0; +#endif +} + +static int set_disk_led_all(SYNO_LED status) +{ + return SYNO_ENABLE_HDD_LED((SYNO_LED_ON == status)? TRUE : FALSE); +} + +static int set_phy_led(SYNO_LED ledStatus) +{ + return SYNO_ENABLE_PHY_LED((SYNO_LED_ON == ledStatus)? TRUE : FALSE); +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(TRUE); + + ops->set_hdd_led = set_disk_led_all; + ops->set_phy_led = set_phy_led; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds214se.c b/drivers/syno/synobios/armada/ds214se.c new file mode 100755 index 000000000000..f0e06721933f --- /dev/null +++ b/drivers/syno/synobios/armada/ds214se.c @@ -0,0 +1,66 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS214se; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_214se = MODULE_T_DS214se; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS214se: + pType = &type_214se; + armada_hdd_enable_gpio[0] = 37; + armada_hdd_enable_gpio[1] = 62; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds215j.c b/drivers/syno/synobios/armada/ds215j.c new file mode 100755 index 000000000000..dc3b937f633b --- /dev/null +++ b/drivers/syno/synobios/armada/ds215j.c @@ -0,0 +1,66 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS215j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_215j = MODULE_T_DS215j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS215j: + pType = &type_215j; + armada_hdd_enable_gpio[0] = 24; + armada_hdd_enable_gpio[1] = 25; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds216se.c b/drivers/syno/synobios/armada/ds216se.c new file mode 100755 index 000000000000..5e4bd634c821 --- /dev/null +++ b/drivers/syno/synobios/armada/ds216se.c @@ -0,0 +1,66 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS216se; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_216se = MODULE_T_DS216se; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS216se: + pType = &type_216se; + armada_hdd_enable_gpio[0] = 37; + armada_hdd_enable_gpio[1] = 62; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds414.c b/drivers/syno/synobios/armada/ds414.c new file mode 100755 index 000000000000..5c1cc0344a28 --- /dev/null +++ b/drivers/syno/synobios/armada/ds414.c @@ -0,0 +1,85 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_DS414; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1333); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_414 = MODULE_T_DS414; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS414: + pType = &type_414; + armada_hdd_enable_gpio[0] = 42; + armada_hdd_enable_gpio[1] = 44; + armada_hdd_enable_gpio[2] = 45; + armada_hdd_enable_gpio[3] = 46; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + return SetDiskLedStatusBySataMvGPIO(disknum, status); +#else + return 0; +#endif +} + +static int set_disk_led_all(SYNO_LED status) +{ + return SYNO_ENABLE_HDD_LED((SYNO_LED_ON == status)? TRUE : FALSE); +} + +int model_addon_init(struct synobios_ops *ops) +{ + SYNO_ENABLE_HDD_LED(TRUE); + + ops->set_hdd_led = set_disk_led_all; + ops->set_phy_led = NULL; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/ds414slim.c b/drivers/syno/synobios/armada/ds414slim.c new file mode 100644 index 000000000000..38512bd6ee28 --- /dev/null +++ b/drivers/syno/synobios/armada/ds414slim.c @@ -0,0 +1,81 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +extern int SYNO_ENABLE_USB_POWER(int enable); +int GetModel(void) +{ + return MODEL_DS414slim; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_414slim = MODULE_T_DS414slim; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS414slim: + pType = &type_414slim; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + return SetDiskLedStatusBySataMvGPIO(disknum, status); +#else + return 0; +#endif +} + +static int set_disk_led_all(SYNO_LED status) +{ + return SYNO_ENABLE_HDD_LED((SYNO_LED_ON == status)? TRUE : FALSE); +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->get_fan_status = GetFanStatusActiveLow; + ops->set_hdd_led = set_disk_led_all; + SYNO_ENABLE_HDD_LED(TRUE); + SYNO_ENABLE_USB_POWER(TRUE); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/fan-pwm.c b/drivers/syno/synobios/armada/fan-pwm.c new file mode 100755 index 000000000000..9a41edb83ea9 --- /dev/null +++ b/drivers/syno/synobios/armada/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include "synobios.h" +#include +#include "armada_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/armada/fan-resister.c b/drivers/syno/synobios/armada/fan-resister.c new file mode 100644 index 000000000000..f287b2e6fbc0 --- /dev/null +++ b/drivers/syno/synobios/armada/fan-resister.c @@ -0,0 +1,106 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include "synobios.h" +#include +#include +#include + +#include "armada_common.h" + +int +FanStatusMappingRS409r1(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value) +{ + int ret = -1; + + if (status == FAN_STATUS_STOP) { + *pSpeed_value = CPLD_FAN_SPEED_0; + } else { + switch (speed) { + case FAN_SPEED_STOP: + *pSpeed_value = CPLD_FAN_SPEED_0; + break; + case FAN_SPEED_ULTRA_LOW: + case FAN_SPEED_VERY_LOW: + case FAN_SPEED_LOW: + case FAN_SPEED_TEST_1: + *pSpeed_value = CPLD_FAN_SPEED_2; + break; + case FAN_SPEED_MIDDLE: + case FAN_SPEED_TEST_2: + *pSpeed_value = CPLD_FAN_SPEED_4; + break; + case FAN_SPEED_HIGH: + case FAN_SPEED_VERY_HIGH: + case FAN_SPEED_ULTRA_HIGH: + case FAN_SPEED_FULL: + case FAN_SPEED_TEST_4: + *pSpeed_value = CPLD_FAN_SPEED_6; + break; + default: + printk("%s(%d) No such fan speed exists, speed=[%d].\n", + __FILE__, __LINE__, speed); + goto END; + } + } + + ret = 0; +END: + return ret; +} + +int +SetFanSpeedValue(char speed_value) +{ + int index = 0; + int ret = -1; + int status = 0; + + for (index=0; index<3; index++) { + if (0x01 & (speed_value>>index)) { + status = 1; + } else { + status = 0; + } + + if (SYNO_CTRL_FAN_PERSISTER(index+1, status, 1)) { + goto End; + } + } + + ret = 0; +End: + return ret; +} + +int +SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + case MODEL_RS812: + /* this is only for RS409r1, not RS409, RS409 not use FAN_MULTI_ALWAYS in mapping.h + * so it never go to this case even you use this function point */ + if (FanStatusMappingRS409r1(status, speed, &speed_value)) { + goto END; + } + break; + case MODEL_RS214: + if (FanStatusMappingType2(status, speed, &speed_value)) { + goto END; + } + break; + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (-1 == SetFanSpeedValue(speed_value)) { + goto END; + } + + res = 0; +END: + return res; +} diff --git a/drivers/syno/synobios/armada/mv_level_button.c b/drivers/syno/synobios/armada/mv_level_button.c new file mode 100644 index 000000000000..07e859b87059 --- /dev/null +++ b/drivers/syno/synobios/armada/mv_level_button.c @@ -0,0 +1,134 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include "armada_common.h" +#include + +#define GPIO_GROUP_0 0 +#define GPIO_GROUP_1 1 + +typedef int MV_STATUS; +typedef unsigned int MV_U32; +MV_STATUS mvGppPolaritySet(MV_U32 group, MV_U32 mask, MV_U32 value); +MV_U32 mvGppPolarityGet(MV_U32 group, MV_U32 mask); + +static inline +int get_group_and_mask(int gpio, MV_U32 *group, MV_U32 *mask) +{ + if (gpio < 32) { + *group = GPIO_GROUP_0; + *mask = 1U << gpio; + } else if (32 <= gpio && gpio < 64) { + *group = GPIO_GROUP_1; + *mask = 1U << (gpio - 32); + } else { + printk("Not supported button gpio %d\n", gpio); + BUG_ON(1); + return -1; + } + return 0; +} + +static +int get_status_and_invert_polarity(struct level_button *btn) +{ + MV_U32 gppPolarity; + MV_U32 gppGroup = 0; + MV_U32 gppMask = 0; + int invert_polarity; + + get_group_and_mask(btn->gpio, &gppGroup, &gppMask); + + /* get current polarity */ + gppPolarity = mvGppPolarityGet(gppGroup, gppMask); + invert_polarity = gppPolarity? 1 : 0; + + /* Revert polarity of gpp */ + gppPolarity ^= gppMask; + mvGppPolaritySet(gppGroup, gppMask, gppPolarity); + + /* GPIO interrupt is always high trigger. + * If polarity is inversed, incoming signal is low */ + if (invert_polarity) { + /* currently low on PCB */ + if (btn->is_high_pressed) { + return BTN_RELEASED; + } else { + return BTN_PRESSED; + } + } else { + /* currently high on PCB */ + if (btn->is_high_pressed) { + return BTN_PRESSED; + } else { + return BTN_RELEASED; + } + } +} + +static +irqreturn_t btn_isr_handler (int irq, void *dev_id) +{ + struct level_button *btn = (struct level_button *)dev_id; + BUG_ON(irq != btn->irq); + + btn->stat = get_status_and_invert_polarity(btn); + + if (!btn->press_act && !btn->release_act) { + return IRQ_HANDLED; + } + + return IRQ_WAKE_THREAD; +} + +static +irqreturn_t btn_dsr_handler(int irq, void *dev_id) +{ + struct level_button *btn = (struct level_button *)dev_id; + BUG_ON(irq != btn->irq); + + if (BTN_PRESSED == btn->stat) { + if (btn->press_act) { + btn->press_act(dev_id); + } + } else { + if (btn->release_act) { + btn->release_act(dev_id); + } + } + + return IRQ_HANDLED; +} + +int level_button_init(struct level_button *btn) +{ + MV_U32 gppPolarity; + MV_U32 gppGroup = 0; + MV_U32 gppMask = 0; + + /* set polarity */ + get_group_and_mask(btn->gpio, &gppGroup, &gppMask); + gppPolarity = btn->is_high_pressed? 0 : 0xffff; + mvGppPolaritySet(gppGroup, gppMask, gppPolarity); + + /* register ISR */ + if (request_threaded_irq(btn->irq, + btn_isr_handler, + btn_dsr_handler, + 0, btn->name, + btn)) + { + printk("Failed to register irq button: %s(%d,%d)\n", + btn->name, btn->irq, btn->gpio); + return -1; + } + + return 0; +} + +int level_button_exit(struct level_button *btn) +{ + free_irq(btn->irq, btn); + return 0; +} + diff --git a/drivers/syno/synobios/armada/rs214.c b/drivers/syno/synobios/armada/rs214.c new file mode 100755 index 000000000000..6ab09e558c26 --- /dev/null +++ b/drivers/syno/synobios/armada/rs214.c @@ -0,0 +1,66 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" + + +int GetModel(void) +{ + return MODEL_RS214; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_214v1 = MODULE_T_RS214v1; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS214: + pType = &type_214v1; + armada_hdd_enable_gpio[0] = 60; + armada_hdd_enable_gpio[1] = 48; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_SOC_HDD_LED_SET(disknum, status); +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada/rs814.c b/drivers/syno/synobios/armada/rs814.c new file mode 100755 index 000000000000..66bdfa5ca55c --- /dev/null +++ b/drivers/syno/synobios/armada/rs814.c @@ -0,0 +1,125 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" +#include + +#define GPIO_RS814_BUZZER 44 +#define IRQ_RS814_BUTTON_BUZZER (IRQ_AURORA_GPIO_START + GPIO_RS814_BUZZER) + +struct sd_softc { + int countEvents; + int idxPtr; + SYNOBIOSEVENT rgEvents[SYNOBIOS_NEVENTS]; + wait_queue_head_t wq_poll; +}; +int synobios_record_event(struct sd_softc *sc, u_int event_type); + +static +int send_buzzer_clear_event(void *pdata) +{ + printk("synobios: buzzer stop button pressed\n"); + synobios_record_event(NULL, SYNO_EVENT_BUTTON_BUZZER_CLEAR); + return 0; +} + +static +struct level_button buzzer_btn = { + .name = "rs814_button_buzzer", + .irq = IRQ_RS814_BUTTON_BUZZER, + .gpio = GPIO_RS814_BUZZER, + .is_high_pressed = 0, + .press_act = send_buzzer_clear_event, + .release_act = NULL +}; + + +int GetModel(void) +{ + return MODEL_RS814; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1333); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_814 = MODULE_T_RS814; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS814: + pType = &type_814; + armada_hdd_enable_gpio[0] = 42; + armada_hdd_enable_gpio[1] = 44; + armada_hdd_enable_gpio[2] = 45; + armada_hdd_enable_gpio[3] = 46; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + if (1 == disknum) + return SYNO_SOC_HDD_LED_SET(disknum, status); + else + return SetDiskLedStatusBySataMvGPIO(disknum, status); +#else + return 0; +#endif +} + +static int set_hdd_led_all(SYNO_LED status) +{ + return SYNO_ENABLE_HDD_LED((SYNO_LED_ON == status)? TRUE : FALSE); +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* init disk led */ + SYNO_ENABLE_HDD_LED(TRUE); + /* HDD1(ata5) not conctrl by mv7042 sata chip, so we default set led on*/ + SYNO_SOC_HDD_LED_SET(1, SYNO_LED_ON); + ops->set_hdd_led = set_hdd_led_all; + ops->set_phy_led = NULL; + + /* init buzzer clear button */ + level_button_init(&buzzer_btn); + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + level_button_exit(&buzzer_btn); + + return 0; +} diff --git a/drivers/syno/synobios/armada/rs815.c b/drivers/syno/synobios/armada/rs815.c new file mode 100755 index 000000000000..6e87bc4b0ad9 --- /dev/null +++ b/drivers/syno/synobios/armada/rs815.c @@ -0,0 +1,125 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" +#include + +#define GPIO_RS815_BUZZER 44 +#define IRQ_RS815_BUTTON_BUZZER (IRQ_AURORA_GPIO_START + GPIO_RS815_BUZZER) + +struct sd_softc { + int countEvents; + int idxPtr; + SYNOBIOSEVENT rgEvents[SYNOBIOS_NEVENTS]; + wait_queue_head_t wq_poll; +}; +int synobios_record_event(struct sd_softc *sc, u_int event_type); + +static +int send_buzzer_clear_event(void *pdata) +{ + printk("synobios: buzzer stop button pressed\n"); + synobios_record_event(NULL, SYNO_EVENT_BUTTON_BUZZER_CLEAR); + return 0; +} + +static +struct level_button buzzer_btn = { + .name = "rs815_button_buzzer", + .irq = IRQ_RS815_BUTTON_BUZZER, + .gpio = GPIO_RS815_BUZZER, + .is_high_pressed = 0, + .press_act = send_buzzer_clear_event, + .release_act = NULL +}; + + +int GetModel(void) +{ + return MODEL_RS815; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1333); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_815 = MODULE_T_RS815; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS815: + pType = &type_815; + armada_hdd_enable_gpio[0] = 42; + armada_hdd_enable_gpio[1] = 44; + armada_hdd_enable_gpio[2] = 45; + armada_hdd_enable_gpio[3] = 46; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + if (1 == disknum) + return SYNO_SOC_HDD_LED_SET(disknum, status); + else + return SetDiskLedStatusBySataMvGPIO(disknum, status); +#else + return 0; +#endif +} + +static int set_hdd_led_all(SYNO_LED status) +{ + return SYNO_ENABLE_HDD_LED((SYNO_LED_ON == status)? TRUE : FALSE); +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* init disk led */ + SYNO_ENABLE_HDD_LED(TRUE); + /* HDD1(ata5) not conctrl by mv7042 sata chip, so we default set led on*/ + SYNO_SOC_HDD_LED_SET(1, SYNO_LED_ON); + ops->set_hdd_led = set_hdd_led_all; + ops->set_phy_led = NULL; + + /* init buzzer clear button */ + level_button_init(&buzzer_btn); + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + level_button_exit(&buzzer_btn); + + return 0; +} diff --git a/drivers/syno/synobios/armada/thermal_ctrl.c b/drivers/syno/synobios/armada/thermal_ctrl.c new file mode 100644 index 000000000000..4a9fbbb30c6c --- /dev/null +++ b/drivers/syno/synobios/armada/thermal_ctrl.c @@ -0,0 +1,389 @@ +// Copyright (c) 2013 Synology Inc. All rights reserved. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef OUTPUT_DBG +#define DBG_MSG(fmt, arg...) printk("%s.%s.%d"fmt, __FILE__, __FUNCTION__, __LINE__, ##arg) +#else +#define DBG_MSG(fmt, arg...) +#endif + +#define THERMAL_STAGES 3 +#define DISABLE_IDLE_TIME_MS 1000 +#define MIN_IDLE_TIME_MS 5 +#define PRIORITY 99 +#define CHECK_PERIOD_MS 2000 +#define THERMAL_NODE "syno_thermal" + +#define GET_CPU_TEMP() (axptemp_read_temp()-13) + +#define GET_ARRAY_ENTRY(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0])) +#define GET_NS_TIME(_CPU_TIME_) do_div(_CPU_TIME_, 1000000000) +#define NS_TO_MS_TIME(_NS_TIME_) do_div(_NS_TIME_,1000) + +/****************************************************** + * External APIs from Kernel + *****************************************************/ +extern int axptemp_read_temp(void); +extern unsigned long long force_cpu_idle(void); +extern unsigned long long get_cpu_time(void); +extern int set_schedule(int policy,const struct sched_param *param); + +typedef enum { + MODE_DISABLE = 0, + MODE_ENABLE, + + MODE_END +} SYNO_THERMAL_Mode; + +typedef struct { + int StartTemp; + int StopTemp; + int TaskIdleTime; +} SYNO_STAGE_INFO; + +typedef struct { + struct proc_dir_entry* pProcFSEntry; + struct task_struct * pThremalThread; + struct task_struct * pThermalCtrlThread; + SYNO_STAGE_INFO ThermalTable[THERMAL_STAGES]; + SYNO_THERMAL_Mode Mode; + unsigned long long LogCPUIdleTime; + unsigned long long LogThermalStartTime; + unsigned long long LogThermalStopTime; + unsigned long ThermalIdleJS; + int Stage; + int CheckTempPeriodMS; // MS + unsigned int CPUTempTrend; +} SYNO_THREMAL_INFO; + +static +const SYNO_STAGE_INFO g_DftThermalTable[THERMAL_STAGES] = +{ + {0, 0, DISABLE_IDLE_TIME_MS}, + {87, 84, 50}, + {89, 87, 10} +}; + +static +const char *g_ModeString[MODE_END] = {"Disable" , "Enable"}; + +static +SYNO_THREMAL_INFO g_SynoInfo; + +static +void SetStageArgs(SYNO_THREMAL_INFO* pInfo, const char* pArg, const char* pStageString, int Index) +{ + int arg_len; + char* pend; + + SYNO_STAGE_INFO Entry = g_DftThermalTable[Index]; + + pArg = strstr(pArg, pStageString); + if (pArg) { + DBG_MSG("pArg=%s, atoi=%s\n", pArg, &pArg[arg_len]); + arg_len = strlen(pStageString); + Entry.StartTemp = simple_strtol(&pArg[arg_len], &pend, 0); + if (pend) { + pArg = strchr(pend, ','); + if (pArg) { + DBG_MSG("%s.%d: pend=%s, atoi=%s\n", pend, &pArg[1]); + Entry.StopTemp = simple_strtol(&pArg[1], &pend, 0); // ignore + } + if (pend) { + pArg = strchr(pend, ','); + if (pArg) { + DBG_MSG("pend=%s, pArg=%s\n", pend, &pArg[1]); + Entry.TaskIdleTime = simple_strtol(&pArg[1], &pend, 0); // ignore + } + } + } + } + + if (Entry.TaskIdleTime < MIN_IDLE_TIME_MS) { + Entry.TaskIdleTime = MIN_IDLE_TIME_MS; + } + + DBG_MSG("ThermalStartTemp=%d, ThermalStopTemp=%d, idle_time=%d\n", Entry.StartTemp, Entry.StopTemp, Entry.TaskIdleTime); + pInfo->ThermalTable[Index] = Entry; +} + + +static +int SynoThermalWrite(struct file *pFile, const char *pBuffer, + unsigned long Count, void *pData) +{ + if (!strncmp (pBuffer, "enable", strlen("enable"))) { + preempt_disable(); + SetStageArgs(&g_SynoInfo, pBuffer, "s1:", 1); + SetStageArgs(&g_SynoInfo, pBuffer, "s2:", 2); + g_SynoInfo.LogCPUIdleTime = 0; + g_SynoInfo.Stage = 0; + preempt_enable(); + g_SynoInfo.LogThermalStartTime = get_cpu_time(); + barrier(); + g_SynoInfo.Mode = MODE_ENABLE; + } else if (!strncmp (pBuffer, "disable", strlen("disable"))) { + g_SynoInfo.Mode = MODE_DISABLE; + g_SynoInfo.LogThermalStopTime = get_cpu_time(); + } + + return Count; +} + +static +int ShowUsage(char *pBuffer, int Len) +{ + int i; + Len += sprintf(&pBuffer[Len], "Usage:\n\t enable,[s1:start_tmp,stop_tmp,idle_time s2:start_tmp,stop_tmp,idle_time]: start thermal task...\n"); + Len += sprintf(&pBuffer[Len], "\t disable: stop thermal task\n"); + Len += sprintf(&pBuffer[Len], "\t Argaments within [] is optional\n"); + Len += sprintf(&pBuffer[Len], "\t Default cmd = enable,"); + + for (i = 1; i < THERMAL_STAGES; i++) { + Len += sprintf(&pBuffer[Len], "s%d:%d,%d,%d ", i, + g_DftThermalTable[i].StartTemp, + g_DftThermalTable[i].StopTemp, + g_DftThermalTable[i].TaskIdleTime); + } + Len += sprintf(&pBuffer[Len], "\n\t Example: echo enable > /proc/%s\n", THERMAL_NODE); + Len += sprintf(&pBuffer[Len], "\t Example: echo enable,s1:80,75,50 s2:85,82,10 > /proc/%s\n", THERMAL_NODE); + return Len; +} + +static +int ShowInfo(char *pBuffer, int Len, unsigned long long TotalTime) +{ + unsigned long long IdleTime; + unsigned long IdleTimeNS, TotalTimeNS; + unsigned long Percentage = 0; + int i, Stage, CPUTrendNum; + unsigned int CPUTempTrend; + char Buffer[64]; + + IdleTime = g_SynoInfo.LogCPUIdleTime; + Stage = g_SynoInfo.Stage; + + IdleTimeNS = GET_NS_TIME(IdleTime); + TotalTimeNS = GET_NS_TIME(TotalTime); + + NS_TO_MS_TIME(IdleTimeNS); + NS_TO_MS_TIME(TotalTimeNS); + + if (TotalTime) { + Percentage = (unsigned long)(IdleTime*100); + /* be careful, first argument of do_div will be modified */ + do_div(Percentage, (unsigned long)TotalTime); + } + + CPUTrendNum = sizeof(CPUTempTrend)*8; + CPUTempTrend = g_SynoInfo.CPUTempTrend; + for (i = 0; i < CPUTrendNum; i++) { + Buffer[i] = (char)(((CPUTempTrend >> i)& 0x01)|0x30); + } + Buffer[CPUTrendNum]='\0'; + + Len += sprintf(&pBuffer[Len], "Status:\n\t Mode: [%s]\n" + "\t Current stage[%d]: start temp: %2d, stop temp: %2d, idle time: %2d ms\n", + g_ModeString[g_SynoInfo.Mode], Stage, + g_SynoInfo.ThermalTable[Stage].StartTemp, + g_SynoInfo.ThermalTable[Stage].StopTemp, + g_SynoInfo.ThermalTable[Stage].TaskIdleTime); + + for (i = 1 ; i < THERMAL_STAGES; i++ ) { + Len += sprintf(&pBuffer[Len], "\t Stage[%d]: start temp: %2d, stop temp: %2d, idle time: %2d ms\n", i, + g_SynoInfo.ThermalTable[i].StartTemp, + g_SynoInfo.ThermalTable[i].StopTemp, + g_SynoInfo.ThermalTable[i].TaskIdleTime); + + } + + Len += sprintf(&pBuffer[Len], "\t CPU temp trend: %s [1: cpu temp was rising compared to last sample]\n" + "\t Idle time [%5lu.%06lu] \n" + "\t Total time [%5lu.%06lu] \n" + "\t Idle percentage: %2lu %%\n", + Buffer, + (unsigned long)IdleTime, IdleTimeNS, + (unsigned long)TotalTime, TotalTimeNS, + Percentage); + + Len += sprintf(&pBuffer[Len], "\t Current CPU temp = %d\n", GET_CPU_TEMP()); + + return Len; +} + +static +int SynoThermalRead(char *pOutBuffer, char **pBufferLocation, off_t Offset, + int BufferLength, int *pZero, void *pObj) +{ + unsigned long long TotalTime; + int Len = 0; + + if (Offset > 0) + return 0; + + if (g_SynoInfo.Mode >= MODE_END) { + DBG_MSG("Wrong Mode [%d]....\n", g_SynoInfo.Mode); + return -1; + } + + if (MODE_DISABLE == g_SynoInfo.Mode) { + TotalTime = g_SynoInfo.LogThermalStopTime - g_SynoInfo.LogThermalStartTime; + } else { + TotalTime = get_cpu_time() - g_SynoInfo.LogThermalStartTime; + } + + Len += ShowUsage(pOutBuffer, Len); + + return ShowInfo(pOutBuffer, Len, TotalTime); +} + + +static +void CreateProc(struct proc_dir_entry** pOutEntry) +{ + struct proc_dir_entry* pEntry; + + pEntry = create_proc_entry(THERMAL_NODE, 0666, NULL); + pEntry->read_proc = SynoThermalRead; + pEntry->write_proc = SynoThermalWrite; + pEntry->nlink = 1; + *pOutEntry = pEntry; +} + +static +void DeleteProc(struct proc_dir_entry** pEntry) +{ + if (pEntry && *pEntry) { + remove_proc_entry(THERMAL_NODE, NULL); + *pEntry = NULL; + } +} + +static +int SynoIdleThead(void* pObject) { + struct sched_param param; + + param.sched_priority = PRIORITY; + if (0 != set_schedule(SCHED_RR, ¶m)){ + printk("failed to set RR schedule\n"); + } + + while (!kthread_should_stop()) { + if (g_SynoInfo.Stage <= 0) { + msleep(DISABLE_IDLE_TIME_MS); + continue; + } + + g_SynoInfo.LogCPUIdleTime += force_cpu_idle(); + schedule_timeout_uninterruptible(g_SynoInfo.ThermalIdleJS); + } + + return 0; +} + +inline +void StageChange(SYNO_THREMAL_INFO* pSynoInfo, int NewStage, int CPUTemp) +{ + if (NewStage != pSynoInfo->Stage) { + pSynoInfo->ThermalIdleJS = msecs_to_jiffies(pSynoInfo->ThermalTable[NewStage].TaskIdleTime); + pSynoInfo->Stage = NewStage; + DBG_MSG("Enter Stage: %d, CPU=%d\n", NewStage, CPUTemp); + } +} + +static +int SynoThermalCtrlThread(void* pObject) +{ + int CPUTemp, LastCPUTemp = 0; + int NewStage; + + while (!kthread_should_stop()) { + if (g_SynoInfo.Mode == MODE_DISABLE) { + g_SynoInfo.Stage = 0; + msleep(DISABLE_IDLE_TIME_MS); + continue; + } + + CPUTemp = GET_CPU_TEMP(); + + if (CPUTemp > LastCPUTemp) { + g_SynoInfo.CPUTempTrend |= 1; + + NewStage = g_SynoInfo.Stage + 1; + if (NewStage >= THERMAL_STAGES) { + NewStage = THERMAL_STAGES - 1; + } + + if (CPUTemp >= g_SynoInfo.ThermalTable[NewStage].StartTemp) { + StageChange(&g_SynoInfo, NewStage, CPUTemp); + } + } else { + NewStage = g_SynoInfo.Stage; + if (CPUTemp <= g_SynoInfo.ThermalTable[NewStage].StopTemp) { + NewStage--; + if (NewStage < 0) { + NewStage = 0; + } + StageChange(&g_SynoInfo, NewStage, CPUTemp); + } + } + + LastCPUTemp = CPUTemp; + g_SynoInfo.CPUTempTrend <<= 1; + msleep(g_SynoInfo.CheckTempPeriodMS); + } + + return 0; +} + +static +int SynoThermalCtrlInit(void) +{ + memset(&g_SynoInfo, 0, sizeof(SYNO_THREMAL_INFO)); + memcpy(&g_SynoInfo.ThermalTable, g_DftThermalTable, sizeof(g_SynoInfo.ThermalTable)); + g_SynoInfo.CheckTempPeriodMS = CHECK_PERIOD_MS; + /* set default mode to enable */ + g_SynoInfo.Mode = MODE_ENABLE; + + CreateProc(&g_SynoInfo.pProcFSEntry); + g_SynoInfo.pThremalThread = kthread_run(SynoIdleThead, NULL, "thermal"); + g_SynoInfo.pThermalCtrlThread = kthread_run(SynoThermalCtrlThread, NULL, "thermal_ctrl"); + + return 0; +} + +static +void SynoThermalCtrlCleanup(void) +{ + DeleteProc(&g_SynoInfo.pProcFSEntry); + + if (g_SynoInfo.pThremalThread) { + kthread_stop(g_SynoInfo.pThremalThread); + g_SynoInfo.pThremalThread = NULL; + } + + if (g_SynoInfo.pThermalCtrlThread) { + kthread_stop(g_SynoInfo.pThermalCtrlThread); + g_SynoInfo.pThermalCtrlThread = NULL; + } +} + +module_init(SynoThermalCtrlInit); +module_exit(SynoThermalCtrlCleanup); + +MODULE_AUTHOR("King Huang"); +MODULE_DESCRIPTION("syno thermal control module\n") ; +MODULE_LICENSE("Synology Inc."); + diff --git a/drivers/syno/synobios/armada/us3.c b/drivers/syno/synobios/armada/us3.c new file mode 100644 index 000000000000..0f465a0f249a --- /dev/null +++ b/drivers/syno/synobios/armada/us3.c @@ -0,0 +1,354 @@ +/* Copyright (c) 2000-2016 Synology Inc. All rights reserved. */ + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "../i2c/i2c-linux.h" +#include "armada_common.h" +#include + +#define GPIO_US3_RESET 33 +#define GPIO_US3_EJECT 38 +#define GPIO_US3_STORAGE_LED 40 +#define GPIO_US3_PWR_LED 42 +#define GPIO_US3_SDFAIL_LED 43 +#define GPIO_US3_MEMTEST_LED 60 +#define GPIO_US3_SD_DETECT 62 +#define IRQ_US3_BUTTON_RESET (IRQ_AURORA_GPIO_START + GPIO_US3_RESET) +#define IRQ_US3_BUTTON_EJECT (IRQ_AURORA_GPIO_START + GPIO_US3_EJECT) +#define IRQ_US3_SD_DETECT (IRQ_AURORA_GPIO_START + GPIO_US3_SD_DETECT) + +struct sd_softc { + int countEvents; + int idxPtr; + SYNOBIOSEVENT rgEvents[SYNOBIOS_NEVENTS]; + wait_queue_head_t wq_poll; +}; +int synobios_record_event(struct sd_softc *sc, u_int event_type); + +static int doing_factory_default=0; + +static void send_reset_event(unsigned long data); +static void send_card_change_event(unsigned long data); +static DEFINE_TIMER(btn_reset_timer, send_reset_event, 0, 0); +static DEFINE_TIMER(card_detect_timer, send_card_change_event, 0, 0); + +static +int send_eject_event(void *pdata) +{ + printk("synobios: eject button pressed\n"); + synobios_record_event(NULL, + SYNO_EVENT_USBSTATION_EJECT); + return 0; +} + +static +void send_reset_event(unsigned long data) +{ + printk("synobios: reset button pressed\n"); + synobios_record_event(NULL, + SYNO_EVENT_BUTTON_RESET); +} + +static +int start_reset_timer(void *pdata) +{ + mod_timer(&btn_reset_timer, jiffies + 3 * HZ); + + return 0; +} + +static +int cancel_reset_timer(void *pdata) +{ + del_timer_sync(&btn_reset_timer); + return 0; +} + +static +void send_card_change_event(unsigned long data) +{ + synobios_record_event(NULL, SYNO_EVENT_DETECT_CARD_CHANGE); +} + +static +int detect_card_change(void *pdata) +{ + printk("synobios: SD card change detected\n"); + synobios_record_event(NULL, SYNO_EVENT_DETECT_CARD_CHANGE); + + /* US3 card reader may delay card init with different firmware + * Send additionl event to cover such delay */ + mod_timer(&card_detect_timer, jiffies + 2 * HZ); + + return 0; +} + + +int GetModel(void) +{ + return MODEL_US3; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + +static int US3SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + // dummy interface + return 0; +} + +static int US3GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + *pStatus = FAN_STATUS_RUNNING; + return 0; +} + + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_us3v1 = MODULE_T_US3v1; + module_t *pType = NULL; + + switch (model) { + case MODEL_US3: + pType = &type_us3v1; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return 0; +} + +static +int armada_gpio_set(int pin, int value) +{ + return SYNO_ARMADA_GPIO_PIN(pin, &value, 1); +} + +typedef struct { + int gpio; + int low_active; +} GPIO_LED; + +static +int set_led(GPIO_LED *led, SYNO_LED status) +{ + const int active = led->low_active? 0 : 1; + switch (status) { + case SYNO_LED_ON: + armada_gpio_set(led->gpio, active); + SYNO_ARMADA_GPIO_BLINK(led->gpio, 0); + break; + case SYNO_LED_BLINKING: + armada_gpio_set(led->gpio, !active); + SYNO_ARMADA_GPIO_BLINK(led->gpio, 1); + break; + case SYNO_LED_OFF: + armada_gpio_set(led->gpio, !active); + SYNO_ARMADA_GPIO_BLINK(led->gpio, 0); + break; + default: + printk("unknown led status: %d\n", status); + } + return 0; +} + +static GPIO_LED pwr_green_led = { + .gpio = GPIO_US3_PWR_LED, + .low_active = 1 +}; + +static GPIO_LED pwr_orange_led = { + .gpio = GPIO_US3_SDFAIL_LED, + .low_active = 1 +}; + +static GPIO_LED storage_led = { + .gpio = GPIO_US3_STORAGE_LED, + .low_active = 0 +}; + +static GPIO_LED memtest_led = { + .gpio = GPIO_US3_MEMTEST_LED, + .low_active = 1 +}; + +static +int us3_set_power_led(SYNO_LED status) +{ + /* we may add mutual control with sdfail led in the future */ + return set_led(&pwr_green_led, status); +} + +static +int us3_exdisplay_handler(struct _SynoMsgPkt *pMsgPkt) +{ + SYNO_LED *pLed; + + switch(pMsgPkt->usNum) { + case SYNO_LED_USBSTATION_MEMTEST_LED: + pLed = (SYNO_LED *)pMsgPkt->szMsg; + set_led(&memtest_led, *pLed); + break; + case SYNO_LED_USBSTATION_DISK_ORANGE: + pLed = (SYNO_LED *)pMsgPkt->szMsg; + set_led(&pwr_orange_led, *pLed); + break; + case SYNO_LED_USBSTATION_DISK_GREEN: + pLed = (SYNO_LED *)pMsgPkt->szMsg; + set_led(&storage_led, *pLed); + break; + case SYNO_LED_USBSTATION_POWER: + pLed = (SYNO_LED *)pMsgPkt->szMsg; + set_led(&pwr_green_led, *pLed); + break; + case SYNO_SYS_RUN: + /* RUN: power LED green steady */ + set_led(&pwr_green_led, SYNO_LED_ON); + set_led(&pwr_orange_led, SYNO_LED_OFF); + break; + case SYNO_SYS_SHUTDOWN: + if (doing_factory_default) { + /* factory default: orange blinking */ + set_led(&pwr_green_led, SYNO_LED_OFF); + set_led(&pwr_orange_led, SYNO_LED_BLINKING); + } else { + /* normal shutdown: green blinking */ + set_led(&pwr_green_led, SYNO_LED_BLINKING); + set_led(&pwr_orange_led, SYNO_LED_OFF); + } + break; + case SYNO_SYS_NO_SYSTEM: + /* NODISK: sd fail led orange blinking */ + set_led(&pwr_green_led, SYNO_LED_OFF); + set_led(&pwr_orange_led, SYNO_LED_BLINKING); + break; + case SYNO_SYS_WAIT_RESET: + /* press reset button 3 sec will trigger reset password + change power led to orange to indicate button pressed */ + set_led(&pwr_green_led, SYNO_LED_OFF); + set_led(&pwr_orange_led, SYNO_LED_ON); + break; + case SYNO_SYS_FACTORY_DEFAULT: + /* blink sd fail led to indicating factory default in processing */ + set_led(&pwr_green_led, SYNO_LED_OFF); + set_led(&pwr_orange_led, SYNO_LED_BLINKING); + /* leave message to switch shutdown led mode */ + doing_factory_default=1; + break; + case SYNO_BEEP_ON: + /* No buzzer. Dont care. */ + break; + case SYNO_LED_USB_EJECT_BLINK: + case SYNO_LED_HDD_AB: + case SYNO_LED_HDD_GS: + /* No harddisk. Dont care. */ + break; + default: + printk("Unhandled msg num %04lx\n", pMsgPkt->usNum); + break; + } + return 0; +} + +static struct level_button eject_btn = { + .name = "us3_eject_button", + .irq = IRQ_US3_BUTTON_EJECT, + .gpio = GPIO_US3_EJECT, + .is_high_pressed = 0, + .press_act = send_eject_event, + .release_act = NULL +}; + +static struct level_button reset_btn = { + .name = "us3_reset_button", + .irq = IRQ_US3_BUTTON_RESET, + .gpio = GPIO_US3_RESET, + .is_high_pressed = 0, + .press_act = start_reset_timer, + .release_act = cancel_reset_timer +}; + +extern int add_card_detect_proc(void); +extern int remove_card_detect_proc(void); +static struct level_button btn_sd_detect = { + .name = "sd_detect", + .irq = IRQ_US3_SD_DETECT, + .gpio = GPIO_US3_SD_DETECT, + .is_high_pressed = 0, + .press_act = detect_card_change, + .release_act = detect_card_change +}; + +int model_addon_init(struct synobios_ops *ops) +{ + /* init button timer */ + init_timer(&btn_reset_timer); + init_timer(&card_detect_timer); + + /* set specialized functions */ + ops->set_power_led = us3_set_power_led; + ops->exdisplay_handler = us3_exdisplay_handler; + + /* set GPIO init value for led */ + set_led(&pwr_green_led, SYNO_LED_BLINKING); // blinking when booting + set_led(&pwr_orange_led, SYNO_LED_OFF); + + /* init reset, eject button */ + level_button_init(&eject_btn); + level_button_init(&reset_btn); + + /* register irq for SD card detection + * also add proc entry to notify user space */ + level_button_init(&btn_sd_detect); + add_card_detect_proc(); // add proc entry to tell hotplugd don't poll + + /* disable HDD LED default function */ + ops->set_hdd_led = NULL; + ops->set_phy_led = NULL; + + /* set dummy fan control interface */ + ops->set_fan_status = US3SetFanStatus; + ops->get_fan_status = US3GetFanStatus; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + /* remove pending timer */ + del_timer_sync(&btn_reset_timer); + del_timer_sync(&card_detect_timer); + + remove_card_detect_proc(); + level_button_exit(&btn_sd_detect); + + level_button_exit(&eject_btn); + level_button_exit(&reset_btn); + + return 0; +} diff --git a/drivers/syno/synobios/armada37xx/Makefile b/drivers/syno/synobios/armada37xx/Makefile new file mode 100644 index 000000000000..ea0fa28c050e --- /dev/null +++ b/drivers/syno/synobios/armada37xx/Makefile @@ -0,0 +1,31 @@ +include /env.mak + +obj-m += ds219j-synobios.o +obj-m += ds219se-synobios.o +obj-m += ds119j-synobios.o +obj-m += ds120j-synobios.o + +common-obj += \ + ../common/common.o \ + ../i2c/i2c-linux.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + armada37xx_common.o + +fan-pwm-obj += fan-pwm.o +fan-resistor-obj += fan-resistor.o + +ifneq (,$(filter $(PLAT_SPEC_VAR), SYNO_FEA_PORT_MAPPING_V2)) + common-obj += \ + ../led/led_9170.o +endif + +ds219j-synobios-objs = ds219j.o $(fan-resistor-obj) $(common-obj) +ds219se-synobios-objs = ds219se.o $(fan-resistor-obj) $(common-obj) +ds119j-synobios-objs = ds119j.o $(fan-resistor-obj) $(common-obj) +ds120j-synobios-objs = ds120j.o $(fan-resistor-obj) $(common-obj) diff --git a/drivers/syno/synobios/armada37xx/armada37xx_common.c b/drivers/syno/synobios/armada37xx/armada37xx_common.c new file mode 100755 index 000000000000..43bf5bbe3325 --- /dev/null +++ b/drivers/syno/synobios/armada37xx/armada37xx_common.c @@ -0,0 +1,393 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2017 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include +#include +#include +#include "armada37xx_common.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" + +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); + +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +SYNO_HWMON_SENSOR_TYPE a37xx_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE a37xx_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "system", + }, +}; + +struct hwmon_sensor_list a37xx_sensor_list = { + .thermal_sensor = &a37xx_thermal_sensor, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &a37xx_hdd_backplane_status, +}; + +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef MY_DEF_HERE +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {56}, + .gpio_polarity = ACTIVE_HIGH, +}; + +int GetMaxInternalDiskNum(void) +#else +static int GetMaxInternalPCIE9xxxDiskNum(void) +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS219j: + case MODEL_DS219se: + iMaxInternalDiskNum = 2; + break; + case MODEL_DS119j: + iMaxInternalDiskNum = 1; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +static int ReadThermalData(int *Temperature) +{ + u16 data = 0; + + if (linuxI2CCharRead(0x48, (u8 *)&data, 2, -1)) { + return -1; + } + +#if defined (__LITTLE_ENDIAN) + data = __swab16(data); +#endif + /* The temperature data only 9 bits */ + data = data >> 7; + + if (data >> 8) { /* bit 9 is minus sign */ + *Temperature = -1 * (0x100 - ((u8 *)&data)[1]); + } else { + *Temperature = data; + } + (*Temperature) >>= 1; + + return 0; +} + +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + int iRet = -1; + int iTemp = 0; + + if (!pThermalTemp) + goto END; + + if (ReadThermalData(&iTemp) != 0) + goto END; + + if( 1 == pThermalTemp->blSurface ) { + iTemp += 18; + iTemp = (iTemp<40) ? 40 : iTemp ; + } + + pThermalTemp->temperature = iTemp; + + iRet = 0; +END: + return iRet; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9170GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9170_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9170GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9170GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + while(HAVE_HDD_DETECT(index)){ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index-1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 1; + + while(HAVE_HDD_ENABLE(index)){ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01 ) << (index-1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 0; + while (hdd_backplane->sensor_num > index) { + if (0 == strncmp(HWMON_HDD_BP_ENABLE, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%ld", hdd_enable); + } else if (0 == strncmp(HWMON_HDD_BP_DETECT, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_DETECT))){ + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%ld", hdd_detect); + } + index++; + } + + iRet = 0; + +End: + return iRet; +} + +static +int HWMONGetThermalSensor(struct _SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + struct _SynoThermalTemp ThermalTemp; + + if (NULL == SysThermal) { + return -ENODEV; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + if (0 != GetSysTemperature(&ThermalTemp)) { + goto End; + } + + snprintf(SysThermal->sensor[0].value, sizeof(SysThermal->sensor[0].value), "%d", ThermalTemp.temperature); + + iRet = 0; +End: + return iRet; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int err = -1; + switch (ledStatus) { + case SYNO_LED_OFF: + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + SYNO_HDD_LED_SET(2, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +int HddPhyLedPwrCtrl(SYNO_LED ledStatus) +{ + int ret = -1; + int pinValue; + + /* Custmized GPIO pin number of hdd & phy led power + * control for DS219j/se. We init it as 0(off) in uboot. + * 1: enable led power of hdd & phy(for system ready). + * 0: disable led power of hdd & phy(for hibernation/deep sleep). + */ + + switch (ledStatus) { + case SYNO_LED_OFF: + pinValue = 0; + break; + case SYNO_LED_ON: + pinValue = 1; + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + goto END; + } + SYNO_GPIO_WRITE(HDD_PHY_LED_PWR_GPIO, pinValue); + ret = 0; + +END: + return ret; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_fan_status = NULL, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = SetPowerLedStatus, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = NULL, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .set_alarm_led = NULL, + .get_backplane_status = NULL, + .get_mem_byte = NULL, + .get_buzzer_cleared = NULL, + .set_phy_led = HddPhyLedPwrCtrl, + .set_hdd_led = NULL, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + // for matching userspace usage, return 0 if button is pressed, else = 1 + .get_copy_button_status = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + + syno_gpio_init(); +#ifdef MY_DEF_HERE + printk("Synobios %s GPIO initialized\n", syno_get_hw_version()); +#endif /* MY_DEF_HERE */ + + switch (GetModel()) { + case MODEL_DS120j: + case MODEL_DS119j: + case MODEL_DS219j: + case MODEL_DS219se: + hwmon_sensor_list = &a37xx_sensor_list; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensor; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + break; + default: + hwmon_sensor_list = NULL; + synobios_ops.hwmon_get_sys_thermal = NULL; + synobios_ops.hwmon_get_backplane_status = NULL; + break; + } + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + + return 0; +} + +static int Uninitialize(void) +{ + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + model_addon_cleanup(*ops); + + return 0; +} diff --git a/drivers/syno/synobios/armada37xx/armada37xx_common.h b/drivers/syno/synobios/armada37xx/armada37xx_common.h new file mode 100755 index 000000000000..02c88164a338 --- /dev/null +++ b/drivers/syno/synobios/armada37xx/armada37xx_common.h @@ -0,0 +1,53 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2017 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include "../mapping.h" +#include "../common/common.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include "../led/led_9170.h" +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#define HDD_PHY_LED_PWR_GPIO 56 + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int InitModuleType(struct synobios_ops *ops); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int SetHDDActLed(SYNO_LED ledStatus); +int SetPowerLedStatus(SYNO_LED status); +int SYNO_GPIO_READ(int pin); +void SYNO_GPIO_WRITE(int pin, int pValue); + +#if defined(MY_DEF_HERE) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_mv_9170_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif /* MY_DEF_HERE && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +// for matching userspace usage, return 0 if button is pressed, else = 1 +int GetFanStatusMircopWithGPIOCommon(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +void VdimmPwrCtrl(SYNO_LED ledStatus); +void syno_gpio_init(void); +void syno_gpio_cleanup(void); +int HddPhyLedPwrCtrl(SYNO_LED ledStatus); + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/armada37xx/ds119j.c b/drivers/syno/synobios/armada37xx/ds119j.c new file mode 100755 index 000000000000..1e77ed507d5e --- /dev/null +++ b/drivers/syno/synobios/armada37xx/ds119j.c @@ -0,0 +1,203 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include "armada37xx_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS119j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_119j = MODULE_T_DS119j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS119j: + pType = &type_119j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != status) { + HddPhyLedPwrCtrl(SYNO_LED_ON); + diskLedEnabled = 1; + } + + iRet = SYNO_HDD_LED_SET(disknum, status); + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetHddLed(SYNO_LED ledStatus) +{ + int ret = -1; + SYNO_DISK_LED status; + switch (ledStatus) { + case SYNO_LED_OFF: + status = DISK_LED_OFF; + break; + case SYNO_LED_ON: + status = DISK_LED_GREEN_SOLID; + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + goto END; + } + SetDiskLedStatus(1, status); + ret = 0; +END: + return ret; +} + +/* + * DS119j GPIO config table + * + * Pin In/Out Function + + * 50 In Model ID 0 + * 51 In Model ID 1 + * 52 In Model ID 2 + * 45 In Fan 1 fail + * 56 Out hdd & phy LED power enable + * 57 Out USB3 ext. hub power enable + * 40 Out HDD 1 power enable + * 42 Out Fan High + * 43 Out Fan Mid + * 44 Out Fan Low + * 36 Out USB1 power enable + * 37 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {44, 43, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {13}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 1, + .gpio_port = {11}, + .gpio_polarity = ACTIVE_LOW, +}; +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 1, + .gpio_port = {40}, + .gpio_polarity = ACTIVE_HIGH, +}; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {50, 51, 52}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.model_id = &model_id; +} + +void syno_gpio_cleanup(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->set_hdd_led = SetHddLed; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada37xx/ds120j.c b/drivers/syno/synobios/armada37xx/ds120j.c new file mode 100755 index 000000000000..dc1d9bd10699 --- /dev/null +++ b/drivers/syno/synobios/armada37xx/ds120j.c @@ -0,0 +1,203 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include "armada37xx_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS120j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_120j = MODULE_T_DS120j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS120j: + pType = &type_120j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != status) { + HddPhyLedPwrCtrl(SYNO_LED_ON); + diskLedEnabled = 1; + } + + iRet = SYNO_HDD_LED_SET(disknum, status); + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetHddLed(SYNO_LED ledStatus) +{ + int ret = -1; + SYNO_DISK_LED status; + switch (ledStatus) { + case SYNO_LED_OFF: + status = DISK_LED_OFF; + break; + case SYNO_LED_ON: + status = DISK_LED_GREEN_SOLID; + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + goto END; + } + SetDiskLedStatus(1, status); + ret = 0; +END: + return ret; +} + +/* + * DS120j GPIO config table + * + * Pin In/Out Function + + * 50 In Model ID 0 + * 51 In Model ID 1 + * 52 In Model ID 2 + * 45 In Fan 1 fail + * 56 Out hdd & phy LED power enable + * 57 Out USB3 ext. hub power enable + * 40 Out HDD 1 power enable + * 42 Out Fan High + * 43 Out Fan Mid + * 44 Out Fan Low + * 36 Out USB1 power enable + * 37 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {44, 43, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {13}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 1, + .gpio_port = {11}, + .gpio_polarity = ACTIVE_LOW, +}; +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 1, + .gpio_port = {40}, + .gpio_polarity = ACTIVE_HIGH, +}; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {50, 51, 52}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.model_id = &model_id; +} + +void syno_gpio_cleanup(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->set_hdd_led = SetHddLed; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada37xx/ds219j.c b/drivers/syno/synobios/armada37xx/ds219j.c new file mode 100755 index 000000000000..26cac8500d74 --- /dev/null +++ b/drivers/syno/synobios/armada37xx/ds219j.c @@ -0,0 +1,166 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include "armada37xx_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS219j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_219j = MODULE_T_DS219j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS219j: + pType = &type_219j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != status) { + HddPhyLedPwrCtrl(SYNO_LED_ON); + diskLedEnabled = 1; + } +#ifdef MY_DEF_HERE + return SetDiskLedStatusBy9170GPIO(disknum, status); +#else + return 0; +#endif /* MY_DEF_HERE*/ +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS219j GPIO config table + * + * Pin In/Out Function + + * 50 In Model ID 0 + * 51 In Model ID 1 + * 52 In Model ID 2 + * 45 In Fan 1 fail + * 56 Out hdd & phy LED power enable + * 57 Out USB3 ext. hub power enable + * 40 Out HDD 1 power enable + * 41 Out HDD 2 power enable + * 42 Out Fan High + * 43 Out Fan Mid + * 44 Out Fan Low + * 36 Out USB1 power enable + * 37 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {44, 43, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {40, 41}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {50, 51, 52}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.model_id = &model_id; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada37xx/ds219se.c b/drivers/syno/synobios/armada37xx/ds219se.c new file mode 100755 index 000000000000..40b76f1e7e3d --- /dev/null +++ b/drivers/syno/synobios/armada37xx/ds219se.c @@ -0,0 +1,168 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include "armada37xx_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS219se; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 800); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_219se = MODULE_T_DS219se; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS219se: + pType = &type_219se; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != status) { + HddPhyLedPwrCtrl(SYNO_LED_ON); + diskLedEnabled = 1; + } +#ifdef MY_DEF_HERE + return SetDiskLedStatusBy9170GPIO(disknum, status); +#else + return 0; +#endif /* MY_DEF_HERE*/ +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS219se GPIO config table + * + * Pin In/Out Function + + * 50 In Model ID 0 + * 51 In Model ID 1 + * 52 In Model ID 2 + * 45 In Fan 1 fail + * 56 Out hdd & phy LED power enable + * 57 Out USB3 ext. hub power enable + * 40 Out HDD 1 power enable + * 41 Out HDD 2 power enable + * 42 Out Fan High + * 43 Out Fan Mid + * 44 Out Fan Low + * 36 Out USB1 power enable + * 37 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {44, 43, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {40, 41}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {50, 51, 52}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.model_id = &model_id; + + +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada37xx/fan-pwm.c b/drivers/syno/synobios/armada37xx/fan-pwm.c new file mode 100755 index 000000000000..3bdd5bcaf25a --- /dev/null +++ b/drivers/syno/synobios/armada37xx/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include "synobios.h" +#include +#include "armada_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/armada37xx/fan-resistor.c b/drivers/syno/synobios/armada37xx/fan-resistor.c new file mode 100644 index 000000000000..c59dfcfe6964 --- /dev/null +++ b/drivers/syno/synobios/armada37xx/fan-resistor.c @@ -0,0 +1,28 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include "synobios.h" +#include +#include +#include + +#include "armada37xx_common.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (SYNO_CTRL_FAN_RESISTOR(speed_value)) { + goto END; + } + + res = 0; +END: + return res; +} diff --git a/drivers/syno/synobios/armada38x/Makefile b/drivers/syno/synobios/armada38x/Makefile new file mode 100644 index 000000000000..6bd76bf74f97 --- /dev/null +++ b/drivers/syno/synobios/armada38x/Makefile @@ -0,0 +1,35 @@ +obj-m += ds416j-synobios.o +obj-m += ds216-synobios.o +obj-m += ds416slim-synobios.o +obj-m += ds216j-synobios.o +obj-m += rs816-synobios.o +obj-m += ds116-synobios.o +obj-m += rs217-synobios.o +obj-m += ds218j-synobios.o +obj-m += ds419slim-synobios.o + +common-obj += \ + ../common/common.o \ + ../i2c/i2c-linux.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-mvebu-builtin.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + armada38x_common.o + +fan-pwm-obj += fan-pwm.o +fan-resistor-obj += fan-resistor.o + +ds416j-synobios-objs = ds416j.o $(fan-resistor-obj) $(common-obj) +ds216-synobios-objs = ds216.o $(fan-resistor-obj) $(common-obj) +ds416slim-synobios-objs = ds416slim.o $(fan-resistor-obj) $(common-obj) +ds216j-synobios-objs = ds216j.o $(fan-resistor-obj) $(common-obj) +rs816-synobios-objs = rs816.o $(fan-resistor-obj) $(common-obj) +ds116-synobios-objs = ds116.o $(fan-resistor-obj) $(common-obj) +rs217-synobios-objs = rs217.o $(fan-resistor-obj) $(common-obj) +ds218j-synobios-objs = ds218j.o $(fan-resistor-obj) $(common-obj) +ds419slim-synobios-objs = ds419slim.o $(fan-resistor-obj) $(common-obj) diff --git a/drivers/syno/synobios/armada38x/armada38x_common.c b/drivers/syno/synobios/armada38x/armada38x_common.c new file mode 100755 index 000000000000..a3aa3aab02e8 --- /dev/null +++ b/drivers/syno/synobios/armada38x/armada38x_common.c @@ -0,0 +1,364 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2015 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc-mvebu-builtin.h" +#include "armada38x_common.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" + +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); + +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +SYNO_HWMON_SENSOR_TYPE a38x_hdd_backplane_status_detect_and_enable = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE a38x_hdd_backplane_status_only_detect = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, +}; + +SYNO_HWMON_SENSOR_TYPE a38x_hdd_backplane_status_only_enable = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +struct hwmon_sensor_list a38x_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; + +#ifdef MY_DEF_HERE +#ifdef MY_DEF_HERE +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); + +static int GetMaxInternalPCIE9xxxDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS416slim: + iMaxInternalDiskNum = 4; + break; + case MODEL_RS816: + iMaxInternalDiskNum = 4; + break; + case MODEL_RS217: + iMaxInternalDiskNum = 2; + break; + case MODEL_DS419slim: + iMaxInternalDiskNum = 4; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int iRet = -1; + int temperature = 0; + + if (!pCPUTemp) + goto END; + if (syno_armada_get_temperature(&temperature) != 0) + goto END; + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = temperature; + + iRet = 0; +END: + return iRet; +} + +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9235_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9235GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9235GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9170GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9170_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9170GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9170GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + while(HAVE_HDD_DETECT(index)){ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index-1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 1; + + while(HAVE_HDD_ENABLE(index)){ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01 ) << (index-1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 0; + while (hdd_backplane->sensor_num > index) { + if (0 == strncmp(HWMON_HDD_BP_ENABLE, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%ld", hdd_enable); + } else if (0 == strncmp(HWMON_HDD_BP_DETECT, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_DETECT))){ + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%ld", hdd_detect); + } + index++; + } + + iRet = 0; + +End: + return iRet; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int err = -1; + switch (ledStatus) { + case SYNO_LED_OFF: + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + SYNO_HDD_LED_SET(2, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_mvebu_get_time, + .set_rtc_time = rtc_mvebu_set_time, + .get_fan_status = NULL, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = NULL, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_mvebu_get_alarm, + .set_auto_poweron = rtc_mvebu_set_alarm, + .init_auto_poweron = rtc_mvebu_enable_alarm_irq, + .uninit_auto_poweron = rtc_mvebu_enable_alarm_irq, + .set_alarm_led = NULL, + .get_backplane_status = NULL, + .get_mem_byte = NULL, + .get_buzzer_cleared = NULL, + .set_phy_led = NULL, + .set_hdd_led = NULL, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + // for matching userspace usage, return 0 if button is pressed, else = 1 + .get_copy_button_status = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + + syno_gpio_init(); +#ifdef MY_DEF_HERE + printk("Synobios %s GPIO initialized\n", syno_get_hw_version()); +#endif /* MY_DEF_HERE */ + + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + hwmon_sensor_list = &a38x_sensor_list; + switch (GetModel()) { + case MODEL_DS116: + case MODEL_DS216j: + case MODEL_DS218j: + case MODEL_RS816: + hwmon_sensor_list->hdd_backplane = &a38x_hdd_backplane_status_only_enable; + break; + case MODEL_DS216: + case MODEL_DS416j: + case MODEL_DS416slim: + case MODEL_DS419slim: + hwmon_sensor_list->hdd_backplane = &a38x_hdd_backplane_status_detect_and_enable; + break; + case MODEL_RS217: + hwmon_sensor_list->hdd_backplane = &a38x_hdd_backplane_status_only_detect; + break; + default: + synobios_ops.hwmon_get_backplane_status = NULL; + hwmon_sensor_list = NULL; + } + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + + if( pSynoModule && RTC_SEIKO == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = rtc_seiko_get_time; + synobios_ops.set_rtc_time = rtc_seiko_set_time; + synobios_ops.get_auto_poweron = rtc_get_auto_poweron; + synobios_ops.set_auto_poweron = rtc_seiko_set_auto_poweron; + synobios_ops.init_auto_poweron = rtc_seiko_auto_poweron_init; + synobios_ops.uninit_auto_poweron = rtc_seiko_auto_poweron_uninit; + } + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + + return 0; +} + +static int Uninitialize(void) +{ + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + model_addon_cleanup(*ops); + + return 0; +} diff --git a/drivers/syno/synobios/armada38x/armada38x_common.h b/drivers/syno/synobios/armada38x/armada38x_common.h new file mode 100755 index 000000000000..d9d6517b2ee1 --- /dev/null +++ b/drivers/syno/synobios/armada38x/armada38x_common.h @@ -0,0 +1,50 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2015 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include "../mapping.h" +#include "../common/common.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int InitModuleType(struct synobios_ops *ops); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int SetHDDActLed(SYNO_LED ledStatus); +int SetPowerLedStatus(SYNO_LED status); +int SYNO_GPIO_READ(int pin); +void SYNO_GPIO_WRITE(int pin, int pValue); +#ifdef MY_DEF_HERE +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif +#ifdef MY_DEF_HERE +extern int syno_mv_9170_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +extern int syno_armada_get_temperature(int *temperature); +// for matching userspace usage, return 0 if button is pressed, else = 1 +int GetFanStatusMircopWithGPIOCommon(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +void VdimmPwrCtrl(SYNO_LED ledStatus); +void syno_gpio_init(void); +void syno_gpio_cleanup(void); + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; \ No newline at end of file diff --git a/drivers/syno/synobios/armada38x/ds116.c b/drivers/syno/synobios/armada38x/ds116.c new file mode 100755 index 000000000000..27130cf2c107 --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds116.c @@ -0,0 +1,314 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS116; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1800); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_116 = MODULE_T_DS116; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS116: + pType = &type_116; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +#define MAX_MPP_PIN 59 + +#define INTER_REGS_PHYS_BASE 0xf1000000 +#define MPP_CONTROL_REG_BASE 0x00018000 | INTER_REGS_PHYS_BASE +#define GPIO_0_31_OUT_ENABLE_CONTROL_REG 0x00018004 | INTER_REGS_PHYS_BASE +#define GPIO_32_59_OUT_ENABLE_CONTROL_REG 0x00018044 | INTER_REGS_PHYS_BASE + +#define MPP_MODE_GPIO 0x0 +#define MPP_MODE_SATA_PRESENT 0x4 + +#define REG_READ(base, mppGroup) \ + ioread32(base + (mppGroup << 2)) +#define REG_WRITE(val, base, mppGroup) \ + iowrite32(val, base + (mppGroup << 2)); + +int SYNOMppCtrlRegWrite(unsigned int mppPin, unsigned int mppVal) +{ + unsigned int origVal; + unsigned int mppGroup; + void *base_addr = ioremap(MPP_CONTROL_REG_BASE, 32); + + if (MAX_MPP_PIN < mppPin) + return -EINVAL; + + /* get the group the pin belongs to, for addressing */ + /* 32 bits per register, 4 bits per pin, 8 pins in a group */ + mppGroup = mppPin / 8; + mppVal &= 0x0F; + origVal = REG_READ(base_addr, mppGroup); + + /* get the corresponding bits */ + origVal &= ~(0xF << ((mppPin % 8) * 4)); + origVal |= mppVal << ((mppPin % 8) * 4); + + REG_WRITE(origVal, base_addr, mppGroup); + + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + if (HAVE_HDD_PRESENT_LED(disknum)) { + if (DISK_LED_ORANGE_SOLID == status || + DISK_LED_ORANGE_BLINK == status) + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(disknum), + MPP_MODE_GPIO); + else + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(disknum), + MPP_MODE_SATA_PRESENT); + } + + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetHddLed(SYNO_LED ledStatus) +{ + switch (ledStatus) { + case SYNO_LED_OFF: + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(1), + MPP_MODE_GPIO); + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(1), + MPP_MODE_SATA_PRESENT); + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + return -EINVAL; + } + + return 0; +} + +#define LINK_DELAY_MS 50 +#define IRQ_ETH0 193 + +typedef int MV_STATUS; +typedef unsigned int MV_U32; +typedef unsigned short MV_U16; + +MV_STATUS mvEthPhyRegWrite(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 data); +MV_STATUS mvEthPhyRegRead(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 *data); + +extern spinlock_t phy_smi_lock; + +int SetPhyLed(SYNO_LED ledStatus) +{ + u32 iPhyAddr; + u16 uiRegValue; + int err = -1; + u16 old_page = 0; + + spin_lock(&phy_smi_lock); + + /* Eth phy mv1514 will link down/up if switched register page. Besides, we + * should disable GBE interrupt and wait a short period to prevent race + * condition and make sure eth link stat stable */ + disable_irq(IRQ_ETH0); + + iPhyAddr = 1; /* boardEthSmiAddr */ + + mvEthPhyRegRead(iPhyAddr, 0x16, &old_page); + + mvEthPhyRegWrite(iPhyAddr, 0x16, 0x3); /* set to page 3 */ + mvEthPhyRegRead(iPhyAddr, 0x10, &uiRegValue); + + switch(ledStatus){ + /*Set Phy led[0] of led[0-2]*/ + case SYNO_LED_ON: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0001; + break; + case SYNO_LED_OFF: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0008; + break; + default: + goto ERR; + } + + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x10, uiRegValue); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, old_page); /* restore page */ + + mdelay(LINK_DELAY_MS); + enable_irq(IRQ_ETH0); + + spin_unlock(&phy_smi_lock); + + err = 0; + +ERR: + return err; +} + +/* + * DS116 GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 52 In Fan 1 fail + * 54 In USB1 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 15 Out HDD 1 power enable + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB1 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {52}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {13}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 1, + .gpio_port = {20}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 1, + .gpio_port = {15}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + /* enable to control LAN_LED */ + ops->set_phy_led = SetPhyLed; + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/ds216.c b/drivers/syno/synobios/armada38x/ds216.c new file mode 100755 index 000000000000..219b4f5a6172 --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds216.c @@ -0,0 +1,278 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS216; +} + +void VdimmPwrCtrl(SYNO_LED ledStatus) +{ + int gpio_number; + int pinValue; + + /* Custmized GPIO pin number of VdimmPWM control for DS216 */ + /* OFF: make all LED off, except breathing status led. */ + /* ON: enable all LED which can be switched on/off */ + gpio_number = 42; + + switch (ledStatus) { + case SYNO_LED_OFF: + pinValue = 0; + break; + case SYNO_LED_ON: + pinValue = 1; + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + return; + } + SYNO_GPIO_WRITE(gpio_number, pinValue); +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1333); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_216 = MODULE_T_DS216; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS216: + pType = &type_216; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + int ret = -1; + int gpio_number; + int pinValue; + + /* Custmized GPIO pin number of PHY LED for DS216 */ + gpio_number = 16; + + switch (ledStatus) { + case SYNO_LED_OFF: + pinValue = 0; + break; + case SYNO_LED_ON: + pinValue = 1; + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + ret = -EINVAL; + goto END; + } + SYNO_GPIO_WRITE(gpio_number, pinValue); + ret = 0; + +END: + return ret; +} + +int SetHddLed(SYNO_LED ledStatus) +{ + int ret = -1; + int gpio_number; + int pinValue; + + /* Custmized GPIO pin number of HDD LED for DS216 */ + gpio_number = 9; + + switch (ledStatus) { + case SYNO_LED_OFF: + pinValue = 0; + break; + case SYNO_LED_ON: + pinValue = 1; + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + ret = -EINVAL; + goto END; + } + SYNO_GPIO_WRITE(gpio_number, pinValue); + ret = 0; + +END: + return ret; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + VdimmPwrCtrl(SYNO_LED_ON); + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + VdimmPwrCtrl(SYNO_LED_OFF); + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +/* + * DS216 GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In USB3 overcurrent + * 42 In USB copy button press intterupt + * 43 In USB2 overcurrent + * 46 In SD card insert interrupt + * 6 Out COPY BUTTON + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 15 Out Fan High + * 37 Out Fan Mid + * 38 Out Fan Low + * 44 Out USB3 power enable + * 47 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {38, 37, 15}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {13, 14}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {39, 40}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {26, 27}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.copy_button_detect = ©_button_detect; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.copy_button_detect = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable all LED */ + VdimmPwrCtrl(SYNO_LED_ON); + /* enable to control LAN_LED */ + ops->set_phy_led = SetPhyLed; + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + /* pull high SATA_LED_CTRL pin, otherwise the hdd led will be off in junior mode*/ + ops->set_hdd_led(SYNO_LED_ON); + /* enable to read USBCOPY GPIO status. */ + /* for matching userspace usage, button pressed = 0, else = 1 */ + ops->get_copy_button_status = getCopyButtonStatus; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/ds216j.c b/drivers/syno/synobios/armada38x/ds216j.c new file mode 100755 index 000000000000..2a982c4ff84c --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds216j.c @@ -0,0 +1,321 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS216j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1000); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_216j = MODULE_T_DS216j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS216j: + pType = &type_216j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +#define MAX_MPP_PIN 59 + +#define INTER_REGS_PHYS_BASE 0xf1000000 +#define MPP_CONTROL_REG_BASE 0x00018000 | INTER_REGS_PHYS_BASE +#define GPIO_0_31_OUT_ENABLE_CONTROL_REG 0x00018004 | INTER_REGS_PHYS_BASE +#define GPIO_32_59_OUT_ENABLE_CONTROL_REG 0x00018044 | INTER_REGS_PHYS_BASE + +#define MPP_MODE_GPIO 0x0 +#define MPP_MODE_SATA_PRESENT 0x4 + +#define REG_READ(base, mppGroup) \ + ioread32(base + (mppGroup << 2)) +#define REG_WRITE(val, base, mppGroup) \ + iowrite32(val, base + (mppGroup << 2)); + +int SYNOMppCtrlRegWrite(unsigned int mppPin, unsigned int mppVal) +{ + unsigned int origVal; + unsigned int mppGroup; + void *base_addr = ioremap(MPP_CONTROL_REG_BASE, 32); + + if (MAX_MPP_PIN < mppPin) + return -EINVAL; + + /* get the group the pin belongs to, for addressing */ + /* 32 bits per register, 4 bits per pin, 8 pins in a group */ + mppGroup = mppPin / 8; + mppVal &= 0x0F; + origVal = REG_READ(base_addr, mppGroup); + + /* get the corresponding bits */ + origVal &= ~(0xF << ((mppPin % 8) * 4)); + origVal |= mppVal << ((mppPin % 8) * 4); + + REG_WRITE(origVal, base_addr, mppGroup); + + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + if (HAVE_HDD_PRESENT_LED(disknum)) { + if (DISK_LED_ORANGE_SOLID == status || + DISK_LED_ORANGE_BLINK == status) + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(disknum), + MPP_MODE_GPIO); + else + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(disknum), + MPP_MODE_SATA_PRESENT); + } + + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetHddLed(SYNO_LED ledStatus) +{ + switch (ledStatus) { + case SYNO_LED_OFF: + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(1), + MPP_MODE_GPIO); + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(2), + MPP_MODE_GPIO); + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(1), + MPP_MODE_SATA_PRESENT); + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(2), + MPP_MODE_SATA_PRESENT); + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + return -EINVAL; + } + + return 0; +} + +#define LINK_DELAY_MS 50 +#define IRQ_ETH0 193 + +typedef int MV_STATUS; +typedef unsigned int MV_U32; +typedef unsigned short MV_U16; + +MV_STATUS mvEthPhyRegWrite(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 data); +MV_STATUS mvEthPhyRegRead(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 *data); + +extern spinlock_t phy_smi_lock; + +int SetPhyLed(SYNO_LED ledStatus) +{ + u32 iPhyAddr; + u16 uiRegValue; + int err = -1; + u16 old_page = 0; + + spin_lock(&phy_smi_lock); + + /* Eth phy mv1514 will link down/up if switched register page. Besides, we + * should disable GBE interrupt and wait a short period to prevent race + * condition and make sure eth link stat stable */ + disable_irq(IRQ_ETH0); + + iPhyAddr = 1; /* boardEthSmiAddr */ + + mvEthPhyRegRead(iPhyAddr, 0x16, &old_page); + + mvEthPhyRegWrite(iPhyAddr, 0x16, 0x3); /* set to page 3 */ + mvEthPhyRegRead(iPhyAddr, 0x10, &uiRegValue); + + switch(ledStatus){ + /*Set Phy led[0] of led[0-2]*/ + case SYNO_LED_ON: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0001; + break; + case SYNO_LED_OFF: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0008; + break; + default: + goto ERR; + } + + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x10, uiRegValue); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, old_page); /* restore page */ + + mdelay(LINK_DELAY_MS); + enable_irq(IRQ_ETH0); + + spin_unlock(&phy_smi_lock); + + err = 0; + +ERR: + return err; +} + +/* + * DS216j GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 52 In Fan 1 fail + * 54 In USB1 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 15 Out HDD 1 power enable + * 16 Out HDD 2 power enable + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB1 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {52}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {13, 14}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {20, 19}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {15, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + /* enable to control LAN_LED */ + ops->set_phy_led = SetPhyLed; + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/ds218j.c b/drivers/syno/synobios/armada38x/ds218j.c new file mode 100755 index 000000000000..8bdfdbc05192 --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds218j.c @@ -0,0 +1,327 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS218j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1300); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_218j = MODULE_T_DS218j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS218j: + pType = &type_218j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +#define MAX_MPP_PIN 59 + +#define INTER_REGS_PHYS_BASE 0xf1000000 +#define MPP_CONTROL_REG_BASE 0x00018000 | INTER_REGS_PHYS_BASE +#define GPIO_0_31_OUT_ENABLE_CONTROL_REG 0x00018004 | INTER_REGS_PHYS_BASE +#define GPIO_32_59_OUT_ENABLE_CONTROL_REG 0x00018044 | INTER_REGS_PHYS_BASE + +#define MPP_MODE_GPIO 0x0 +#define MPP_MODE_SATA_PRESENT 0x4 + +#define REG_READ(base, mppGroup) \ + ioread32(base + (mppGroup << 2)) +#define REG_WRITE(val, base, mppGroup) \ + iowrite32(val, base + (mppGroup << 2)); + +int SYNOMppCtrlRegWrite(unsigned int mppPin, unsigned int mppVal) +{ + unsigned int origVal; + unsigned int mppGroup; + void *base_addr = ioremap(MPP_CONTROL_REG_BASE, 32); + + if (MAX_MPP_PIN < mppPin) + return -EINVAL; + + /* get the group the pin belongs to, for addressing */ + /* 32 bits per register, 4 bits per pin, 8 pins in a group */ + mppGroup = mppPin / 8; + mppVal &= 0x0F; + origVal = REG_READ(base_addr, mppGroup); + + /* get the corresponding bits */ + origVal &= ~(0xF << ((mppPin % 8) * 4)); + origVal |= mppVal << ((mppPin % 8) * 4); + + REG_WRITE(origVal, base_addr, mppGroup); + + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + if (HAVE_HDD_PRESENT_LED(disknum)) { + if (DISK_LED_ORANGE_SOLID == status || + DISK_LED_ORANGE_BLINK == status) + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(disknum), + MPP_MODE_GPIO); + else + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(disknum), + MPP_MODE_SATA_PRESENT); + } + + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetHddLed(SYNO_LED ledStatus) +{ + switch (ledStatus) { + case SYNO_LED_OFF: + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(1), + MPP_MODE_GPIO); + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(2), + MPP_MODE_GPIO); + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(1), + MPP_MODE_SATA_PRESENT); + SYNOMppCtrlRegWrite(HDD_PRESENT_LED_PIN(2), + MPP_MODE_SATA_PRESENT); + break; + default: + WARN(1 ,"invalid opration: %d\n", ledStatus); + return -EINVAL; + } + + return 0; +} + +#define LINK_DELAY_MS 50 +#define IRQ_ETH0 193 + +typedef int MV_STATUS; +typedef unsigned int MV_U32; +typedef unsigned short MV_U16; + +MV_STATUS mvEthPhyRegWrite(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 data); +MV_STATUS mvEthPhyRegRead(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 *data); + +extern spinlock_t phy_smi_lock; + +int SetPhyLed(SYNO_LED ledStatus) +{ + u32 iPhyAddr; + u16 uiRegValue; + int err = -1; + u16 old_page = 0; + static SYNO_LED ledNowStat = SYNO_LED_OFF; + + if (ledStatus == ledNowStat) { + err = 0; + goto ERR; + } + spin_lock(&phy_smi_lock); + + /* Eth phy mv1514 will link down/up if switched register page. Besides, we + * should disable GBE interrupt and wait a short period to prevent race + * condition and make sure eth link stat stable */ + disable_irq(IRQ_ETH0); + + iPhyAddr = 1; /* boardEthSmiAddr */ + + mvEthPhyRegRead(iPhyAddr, 0x16, &old_page); + + mvEthPhyRegWrite(iPhyAddr, 0x16, 0x3); /* set to page 3 */ + mvEthPhyRegRead(iPhyAddr, 0x10, &uiRegValue); + + switch(ledStatus){ + /*Set Phy led[0] of led[0-2]*/ + case SYNO_LED_ON: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0001; + break; + case SYNO_LED_OFF: + uiRegValue &= 0xFFF0; + uiRegValue |= 0x0008; + break; + default: + goto ERR; + } + + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x10, uiRegValue); + mvEthPhyRegWrite((unsigned int)iPhyAddr, 0x16, old_page); /* restore page */ + + mdelay(LINK_DELAY_MS); + enable_irq(IRQ_ETH0); + + spin_unlock(&phy_smi_lock); + + ledNowStat = ledStatus; + err = 0; + +ERR: + return err; +} + +/* + * DS218j GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 52 In Fan 1 fail + * 54 In USB1 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 15 Out HDD 1 power enable + * 16 Out HDD 2 power enable + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB1 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {52}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {13, 14}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {20, 19}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {15, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + /* enable to control LAN_LED */ + ops->set_phy_led = SetPhyLed; + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/ds416j.c b/drivers/syno/synobios/armada38x/ds416j.c new file mode 100755 index 000000000000..db82631a4aa3 --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds416j.c @@ -0,0 +1,198 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS416j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1333); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_416j = MODULE_T_DS416j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS416j: + pType = &type_416j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return SYNO_HDD_LED_SET(disknum, status); +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS416j GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In HDD 3 present + * 43 In HDD 4 present + * 52 In Fan 1 fail + * 53 In Fan 2 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 15 Out HDD 3 fault LED + * 16 Out HDD 4 fault LED + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 37 Out HDD 3 power enable + * 38 Out HDD 4 power enable + * 48 Out Fan Low + * 49 Out Fan Mid + * 50 Out Fan High + * 58 Out USB3 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {52, 53}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {13, 14, 15, 16}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {39, 40, 41, 43}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {26, 27, 37, 38}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/ds416slim.c b/drivers/syno/synobios/armada38x/ds416slim.c new file mode 100755 index 000000000000..9bb078e893b9 --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds416slim.c @@ -0,0 +1,193 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS416slim; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1000); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_416slim = MODULE_T_DS416slim; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS416slim: + pType = &type_416slim; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + return SetDiskLedStatusBy9235GPIO(disknum, status); +#else + return 0; +#endif +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS416slim GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In HDD 3 present + * 43 In HDD 4 present + * 52 In Fan 1 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 37 Out HDD 3 power enable + * 38 Out HDD 4 power enable + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB3 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {52}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {39, 40, 41, 43}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {26, 27, 37, 38}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/ds419slim.c b/drivers/syno/synobios/armada38x/ds419slim.c new file mode 100755 index 000000000000..4ff8ab86269c --- /dev/null +++ b/drivers/syno/synobios/armada38x/ds419slim.c @@ -0,0 +1,193 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS419slim; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1300); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_419slim = MODULE_T_DS419slim; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS419slim: + pType = &type_419slim; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + return SetDiskLedStatusBy9235GPIO(disknum, status); +#else + return 0; +#endif +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS419slim GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In HDD 3 present + * 43 In HDD 4 present + * 52 In Fan 1 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 37 Out HDD 3 power enable + * 38 Out HDD 4 power enable + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB3 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {52}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {39, 40, 41, 43}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {26, 27, 37, 38}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/fan-pwm.c b/drivers/syno/synobios/armada38x/fan-pwm.c new file mode 100755 index 000000000000..3bdd5bcaf25a --- /dev/null +++ b/drivers/syno/synobios/armada38x/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include "synobios.h" +#include +#include "armada_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/armada38x/fan-resistor.c b/drivers/syno/synobios/armada38x/fan-resistor.c new file mode 100644 index 000000000000..012d613b7eda --- /dev/null +++ b/drivers/syno/synobios/armada38x/fan-resistor.c @@ -0,0 +1,28 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include "synobios.h" +#include +#include +#include + +#include "armada38x_common.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (SYNO_CTRL_FAN_RESISTOR(speed_value)) { + goto END; + } + + res = 0; +END: + return res; +} diff --git a/drivers/syno/synobios/armada38x/rs217.c b/drivers/syno/synobios/armada38x/rs217.c new file mode 100755 index 000000000000..7bd6bb1bd8df --- /dev/null +++ b/drivers/syno/synobios/armada38x/rs217.c @@ -0,0 +1,187 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_RS217; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1800); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_217 = MODULE_T_RS217; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS217: + pType = &type_217; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + /* Disk1 is native sata, Disk2 are 9170 */ + if (1 == disknum) + return SYNO_HDD_LED_SET(disknum, status); + else + return SetDiskLedStatusBy9170GPIO(disknum, status); +#else + return 0; +#endif +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * RS217 GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 38 In Buzzer Mute GPI + * 39 In Present Pin + * 45 In Model ID 2 + * 46 In Fan 2 fail + * 52 In Fan 1 fail + * 53 In Fan 3 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED off + * 13 Out HDD1 fault LED + * 28 Out Buzzer Mute GPO + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB3 power enable + * 59 Out USB3 power enable + */ +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 3, + .gpio_port = {52, 46, 53}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {13}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 1, + .gpio_port = {39}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActivePulse; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/armada38x/rs816.c b/drivers/syno/synobios/armada38x/rs816.c new file mode 100755 index 000000000000..d41410672d1f --- /dev/null +++ b/drivers/syno/synobios/armada38x/rs816.c @@ -0,0 +1,230 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "armada38x_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_RS816; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1800); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_816 = MODULE_T_RS816; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS816: + pType = &type_816; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + if (1 == disknum) + return SYNO_HDD_LED_SET(disknum, status); + else + return SetDiskLedStatusBy9235GPIO(disknum, status); +#else + return 0; +#endif +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int getBuzzerButtonStatus(unsigned char *pValue) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(pValue); +} + +int setBuzzerMute (unsigned char buzzer_cleared) +{ + printk("Synobios: Buzzer is muted\n"); + return SYNO_CTRL_BUZZER_MUTE_SET(buzzer_cleared); +} + +/* + * RS816 GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 38 In Buzzer Mute GPI + * 39 In Present Pin + * 45 In Model ID 2 + * 46 In Fan 2 fail + * 52 In Fan 1 fail + * 53 In Fan 3 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED off + * 13 Out HDD1 fault LED + * 28 Out Buzzer Mute GPO + * 37 Out HDD 3 power enable + * 37 Out HDD 4 power enable + * 48 Out Fan High + * 49 Out Fan Mid + * 50 Out Fan Low + * 58 Out USB3 power enable + * 59 Out USB3 power enable + */ +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 3, + .gpio_port = {50, 49, 48}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 3, + .gpio_port = {52, 46, 53}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {13}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {39, 39, 39, 39}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {37, 37, 37, 37}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {38}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO buzzer_mute_ctrl = { + .nr_gpio = 1, + .gpio_port = {28}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.buzzer_mute_ctrl = &buzzer_mute_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.mute_button_detect = NULL; + syno_gpio.buzzer_mute_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActivePulse; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + ops->get_buzzer_cleared = getBuzzerButtonStatus; + ops->set_buzzer_clear = setBuzzerMute; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/avoton/Makefile b/drivers/syno/synobios/avoton/Makefile new file mode 100644 index 000000000000..393d928ee7cc --- /dev/null +++ b/drivers/syno/synobios/avoton/Makefile @@ -0,0 +1,27 @@ +include /env.mak + +obj-m += avoton-synobios.o + +avoton-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds2415+.o \ + ds415+.o \ + ds1815+.o \ + ds1515+.o \ + rs815+.o \ + rs815rp+.o \ + rs2416+.o \ + ds1616+.o \ + rs2416rp+.o \ + ds1517+.o \ + ds1817+.o \ + rs818+.o \ + rs818rp+.o \ + rs1219+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + avoton_common.o diff --git a/drivers/syno/synobios/avoton/avoton_common.c b/drivers/syno/synobios/avoton/avoton_common.c new file mode 100755 index 000000000000..9fa28036a14d --- /dev/null +++ b/drivers/syno/synobios/avoton/avoton_common.c @@ -0,0 +1,1018 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../rtc/rtc.h" + +#include "avoton_common.h" + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int giAlertGPIOPin = -1; +static int* hdd_detect_gpio = NULL; +static int* hdd_enable_gpio = NULL; + +#ifdef MY_DEF_HERE +extern void (*funcSynoNicLedCtrl)(int iEnable); +#endif //MY_DEF_HERE + +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS415p: + iMaxInternalDiskNum = 4; + break; + case MODEL_DS2415p: + case MODEL_RS2416p: + case MODEL_RS2416rpp: + iMaxInternalDiskNum = 12; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {11, 12, 18, 34}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + GPIO_PIN gPioPin; + int rgcVolt[2] = {0, 0}; + int iFanIndex = 0; + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + + /* RS818RP+ has only two fans, start from index 1 */ + if (MODEL_RS818rpp == GetModel()) { + iFanIndex = 1; + } + + gPioPin.pin = gpio_fan_map[fanno + iFanIndex - 1]; + + do { + GetGpioPin(&gPioPin); + if (!gPioPin.value) { + rgcVolt[0]++; + } else { + rgcVolt[1]++; + } + + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ((rgcVolt[0] + rgcVolt[1]) < 200); + + if (rgcVolt[0] == 0) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + return 0; +} + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_DS2415p; + + if ( !strncmp(gszSynoHWVersion, HW_DS2415p, strlen(HW_DS2415p) ) ) { + model = MODEL_DS2415p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS415p, strlen(HW_DS415p) ) ) { + model = MODEL_DS415p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1815p, strlen(HW_DS1815p) ) ) { + model = MODEL_DS1815p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1515p, strlen(HW_DS1515p) ) ) { + model = MODEL_DS1515p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS815p, strlen(HW_RS815p) ) ) { + model = MODEL_RS815p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS815rpp, strlen(HW_RS815rpp) ) ) { + model = MODEL_RS815rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2416p, strlen(HW_RS2416p) ) ) { + model = MODEL_RS2416p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2416rpp, strlen(HW_RS2416rpp) ) ) { + model = MODEL_RS2416rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1616p, strlen(HW_DS1616p) ) ) { + model = MODEL_DS1616p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1817p, strlen(HW_DS1817p) ) ) { + model = MODEL_DS1817p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1517p, strlen(HW_DS1517p) ) ) { + model = MODEL_DS1517p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS818p, strlen(HW_RS818p) ) ) { + model = MODEL_RS818p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS818rpp, strlen(HW_RS818rpp) ) ) { + model = MODEL_RS818rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS1219p, strlen(HW_RS1219p) ) ) { + model = MODEL_RS1219p; + } + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin(GPIO_PIN *pPin) +{ + int ret = -1; + + if (NULL == pPin) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin(GPIO_PIN *pPin) +{ + int ret = -1; + + if (NULL == pPin) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static int giAllLedController = -1; +/** + * For consistency of led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let ALL LED (exclude POWER LED) be able to light on + */ +static +void SetAllLedControl(int blEnable) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giAllLedController) { + return; + } + pin.pin = giAllLedController; + if (blEnable) { + pin.value = 1; + } else { + pin.value = 0; + } + SetGpioPin(&pin); +} + + +static int giDiskLedController = -1; +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void SetHDDLedControl(int blEnable) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + if (blEnable) { + pin.value = 1; + } else { + pin.value = 0; + } + SetGpioPin(&pin); +} + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +static +int SetDiskLedStatusByI2CLedDimmer(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + static int diskLedEnabled = 0; + + switch (GetModel()) { + case MODEL_DS1517p: + case MODEL_DS1817p: + case MODEL_RS818p: + case MODEL_RS818rpp: + case MODEL_RS1219p: + if (!diskLedEnabled) { + /* Above models gpio 49 control "ALL LED(exclude Power LED)" + * If no disk, DISK_LED_OFF would not enable gpio 49 */ + SetAllLedControl(1); + diskLedEnabled = 1; + } + break; + default: + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != iStatus) { + SetHDDLedControl(1); + diskLedEnabled = 1; + } + break; + } + + if (0 >= iDiskNum || 8 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByI2CLedDimmer(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByI2CLedDimmer(iHostNum + 1, iStatus); +} +#endif // CONFIG_SYNO_LEDS_TRIGGER + +#ifdef MY_DEF_HERE +static +int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + static int diskLedEnabled = 0; + int iWrite = -1; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != iStatus) { + SetHDDLedControl(1); + diskLedEnabled = 1; + } + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + return iRet; +} + +static +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9235GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9235GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} +#endif /* MY_DEF_HERE */ + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx = 0; + + if (NULL == pCpuTemp) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if(0 != iRet) { + goto END; + } + + /* + * Count the cpu surface termperature + * Coretemp is lower than heatsink about 9 celsius + * n += 9 + * n < 30 show 30 + */ + if (1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + if (MODEL_RS818rpp != GetModel() && MODEL_RS818p != GetModel() && MODEL_RS1219p != GetModel()) { + pCpuTemp->cpu_temp[iCPUIdx] += 9; + } + if (pCpuTemp->cpu_temp[iCPUIdx] < 30) { + pCpuTemp->cpu_temp[iCPUIdx] = 30; + } + } + } + +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int i = 0; + GPIO_PIN Pin; + unsigned long hdd_detect_status = 0; + unsigned long hdd_enable_status = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list || (NULL == hdd_enable_gpio && NULL == hdd_detect_gpio)) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (i = 0; i < GetMaxInternalDiskNum(); i++) { + Pin.pin = hdd_enable_gpio[i]; + if (0 > GetGpioPin(&Pin)) { + goto End; + } + hdd_enable_status |= (Pin.value & 0x01) << i; + + Pin.pin = hdd_detect_gpio[i]; + if (0 > GetGpioPin(&Pin)) { + goto End; + } + hdd_detect_status |= ((~Pin.value) & 0x01) << i; + } + + for (i = 0; i < hdd_backplane->sensor_num; i++) { + if (0 == strncmp(hdd_backplane->sensor[i].sensor_name, HWMON_HDD_BP_DETECT, strlen(HWMON_HDD_BP_DETECT))) { + snprintf(hdd_backplane->sensor[i].value, sizeof(hdd_backplane->sensor[i].value), "%ld", hdd_detect_status); + } else if (0 == strncmp(hdd_backplane->sensor[i].sensor_name, HWMON_HDD_BP_ENABLE, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[i].value, sizeof(hdd_backplane->sensor[i].value), "%ld", hdd_enable_status); + } + } + + iRet = 0; +End: + + return iRet; + +} + +/* + * For GPIO alert Led, there is no blinking + */ +static +int SetAlarmLedByGPIO(unsigned char type) +{ + GPIO_PIN pin; + int iRet = -1; + + if (0 > giAlertGPIOPin) { + goto END; + } + + if (type) { + pin.value = 1; + }else{ + pin.value = 0; + } + pin.pin = giAlertGPIOPin; + SetGpioPin(&pin); + + iRet = 0; + +END: + return iRet; +} + +int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = AVOTON_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus) { + case SYNO_LED_ON: + case SYNO_LED_OFF: +#ifdef MY_DEF_HERE + if (funcSynoNicLedCtrl) { + funcSynoNicLedCtrl(ledStatus); + } +#endif + break; + default: + goto ERR; + } + iError = 0; + +ERR: + return iError; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SetHDDLedControl(0); + } else { + SetHDDLedControl(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 8 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 8 * sizeof(int)); + memset(gpOrangeLedMap, -1, 8 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + +#define GPIO_POWER_GOOD 1 +int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + + if (0 != syno_pch_lpc_gpio_pin(AVOTON_POWER1_PIN , &power1_Value, 0)) { + goto FAIL; + } + + if (0 != syno_pch_lpc_gpio_pin(AVOTON_POWER2_PIN , &power2_Value, 0)) { + goto FAIL; + } + + if (power1_Value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + } else { + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + } else { + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = NULL, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + if (0 > syno_libata_disk_map_table_gen(giDiskMapTable)) { + gblDiskNumNeedTran = 0; + } else { + gblDiskNumNeedTran = 1; + } + + giDiskLedController = AVOTON_DISK_LED_ACTIVATE_PIN; + switch (GetModel()) { + case MODEL_DS2415p: + model_ops = &ds2415p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; + giAlertGPIOPin = 10; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS415p: + model_ops = &ds415p_ops; + hwmon_sensor_list = &ds415p_sensor_list; + hdd_detect_gpio = ds415p_hdd_detect_gpio; + hdd_enable_gpio = ds415p_hdd_enable_gpio; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + break; + case MODEL_DS1815p: + model_ops = &ds1815p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[8]){0,2,4,6,8,10,12,14}, (int[8]){1,3,5,7,9,11,13,15}, 8); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + giAlertGPIOPin = 10; +#ifdef MY_DEF_HERE + /* enable internal Sil3132 sw HDD activity led */ + syno_sil3132_disk_led_enable(6, 1); + syno_sil3132_disk_led_enable(7, 1); +#endif + break; + case MODEL_DS1515p: + model_ops = &ds1515p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[5]){0,2,4,6,8}, (int[5]){1,3,5,7,9}, 5); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + giAlertGPIOPin = 10; + break; + case MODEL_RS815p: + model_ops = &rs815p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + giAlertGPIOPin = 10; + break; + case MODEL_RS815rpp: + model_ops = &rs815rpp_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + giAlertGPIOPin = 10; + break; + case MODEL_RS2416p: + model_ops = &rs2416p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; + giAlertGPIOPin = 10; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + break; + case MODEL_RS2416rpp: + model_ops = &rs2416rpp_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; + giAlertGPIOPin = 10; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS1616p: + model_ops = &ds1616p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[6]){0,2,4,6,8,10}, (int[6]){1,3,5,7,9,11}, 6); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + giAlertGPIOPin = 10; + break; + case MODEL_DS1517p: + model_ops = &ds1517p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[5]){0,2,4,6,8}, (int[5]){1,3,5,7,9}, 5); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + giAlertGPIOPin = 10; + giAllLedController = 49; +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(3, 1); /* mv9235 slot 3 */ + syno_ahci_disk_led_enable_by_port(4, 1); /* mv9235 slot 4 */ + syno_ahci_disk_led_enable_by_port(5, 1); /* mv9170 slot 5 */ +#else + syno_ahci_disk_led_enable(3, 1); /* mv9235 slot 2 is host3 */ + syno_ahci_disk_led_enable(4, 1); /* mv9235 slot 3 is host4 */ + syno_ahci_disk_led_enable(6, 1); /* mv9170 slot 2 is host6 */ +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DS1817p: + model_ops = &ds1817p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[8]){0,2,4,6,8,10,12,14}, (int[8]){1,3,5,7,9,11,13,15}, 8); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + giAlertGPIOPin = 10; + giAllLedController = 49; +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(3, 1); /* mv9235-1 slot 3 */ + syno_ahci_disk_led_enable_by_port(4, 1); /* mv9235-1 slot 4 */ + syno_ahci_disk_led_enable_by_port(5, 1); /* mv9235-1 slot 5 */ + syno_ahci_disk_led_enable_by_port(6, 1); /* mv9235-2 slot 6 */ + syno_ahci_disk_led_enable_by_port(7, 1); /* mv9235-2 slot 7 */ + syno_ahci_disk_led_enable_by_port(8, 1); /* mv9235-2 slot 8 */ +#else + syno_ahci_disk_led_enable(3, 1); /* mv9235-1 slot 2 is host3 */ + syno_ahci_disk_led_enable(4, 1); /* mv9235-1 slot 3 is host4 */ + syno_ahci_disk_led_enable(5, 1); /* mv9235-1 slot 4 is host5 */ + syno_ahci_disk_led_enable(7, 1); /* mv9235-2 slot 2 is host7 */ + syno_ahci_disk_led_enable(8, 1); /* mv9235-2 slot 3 is host8 */ + syno_ahci_disk_led_enable(9, 1); /* mv9235-2 slot 4 is host9 */ +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS818p: + model_ops = &rs818p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + giAlertGPIOPin = 10; + giAllLedController = 49; +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(3, 1); /* mv9235-1 slot 1 is host3 */ + syno_ahci_disk_led_enable_by_port(4, 1); /* mv9235-2 slot 2 is host4 */ +#else + syno_ahci_disk_led_enable(3, 1); /* mv9235 slot 1 is host3 */ + syno_ahci_disk_led_enable(4, 1); /* mv9235 slot 2 is host4 */ +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS818rpp: + model_ops = &rs818rpp_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + giAlertGPIOPin = 10; + giAllLedController = 49; +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(3, 1); /* mv9235-1 slot 1 is host3 */ + syno_ahci_disk_led_enable_by_port(4, 1); /* mv9235-2 slot 2 is host4 */ +#else + syno_ahci_disk_led_enable(3, 1); /* mv9235 slot 1 is host3 */ + syno_ahci_disk_led_enable(4, 1); /* mv9235 slot 2 is host4 */ +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS1219p: + model_ops = &rs1219p_ops; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[8]){0,2,4,6,8,10,12,14}, (int[8]){1,3,5,7,9,11,13,15}, 8); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + giAlertGPIOPin = 10; + giAllLedController = 49; +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); /* mv9235-2 slot 2 */ + syno_ahci_disk_led_enable_by_port(2, 1); /* Internal */ + syno_ahci_disk_led_enable_by_port(3, 1); /* mv9235-1 slot 1 */ + syno_ahci_disk_led_enable_by_port(4, 1); /* mv9235-1 slot 3 */ + syno_ahci_disk_led_enable_by_port(5, 1); /* mv9235-2 slot 3 */ + syno_ahci_disk_led_enable_by_port(6, 1); /* mv9235-2 slot 4 */ + syno_ahci_disk_led_enable_by_port(7, 1); /* Internal */ + syno_ahci_disk_led_enable_by_port(8, 1); /* mv9235-1 slot 2 */ +#else + syno_ahci_disk_led_enable(1, 1); /* mv9235-2 slot 2 */ + syno_ahci_disk_led_enable(2, 1); /* Internal */ + syno_ahci_disk_led_enable(3, 1); /* mv9235-1 slot 1 */ + syno_ahci_disk_led_enable(4, 1); /* mv9235-1 slot 3 */ + syno_ahci_disk_led_enable(5, 1); /* mv9235-2 slot 3 */ + syno_ahci_disk_led_enable(6, 1); /* mv9235-2 slot 4 */ + syno_ahci_disk_led_enable(7, 1); /* Internal */ + syno_ahci_disk_led_enable(8, 1); /* mv9235-1 slot 2 */ +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + default : + break; + } + + if (synobios_ops.init_auto_poweron) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/avoton/avoton_common.h b/drivers/syno/synobios/avoton/avoton_common.h new file mode 100755 index 000000000000..22c1991a2d27 --- /dev/null +++ b/drivers/syno/synobios/avoton/avoton_common.h @@ -0,0 +1,109 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds2415p_ops; +extern struct model_ops ds415p_ops; +extern struct model_ops ds1815p_ops; +extern struct model_ops ds1515p_ops; +extern struct model_ops rs815p_ops; +extern struct model_ops rs815rpp_ops; +extern struct model_ops rs2416p_ops; +extern struct model_ops rs2416rpp_ops; +extern struct model_ops ds1616p_ops; +extern struct model_ops ds1817p_ops; +extern struct model_ops ds1517p_ops; +extern struct model_ops rs818p_ops; +extern struct model_ops rs818rpp_ops; +extern struct model_ops rs1219p_ops; + +extern struct hwmon_sensor_list ds415p_sensor_list; + +extern int ds415p_hdd_enable_gpio[4]; +extern int ds415p_hdd_detect_gpio[4]; + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +#endif + +#ifdef MY_DEF_HERE +extern int syno_sil3132_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif + +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +extern int syno_libata_disk_map_table_gen(int *iDiskMapTable); +#endif + +#ifdef MY_DEF_HERE +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +#endif + +#define AVOTON_POWER1_PIN 44 +#define AVOTON_POWER2_PIN 51 +#define AVOTON_BUZZER_OFF_PIN 58 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#define AVOTON_DISK_LED_ACTIVATE_PIN 49 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; \ No newline at end of file diff --git a/drivers/syno/synobios/avoton/ds1515+.c b/drivers/syno/synobios/avoton/ds1515+.c new file mode 100644 index 000000000000..95c9cdfaf625 --- /dev/null +++ b/drivers/syno/synobios/avoton/ds1515+.c @@ -0,0 +1,53 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +PWM_FAN_SPEED_MAPPING gDS1515pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1515pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1515p = MODULE_T_DS1515p; + module_t *pType = &type_ds1515p; + + module_type_set(pType); + return 0; +} + +static +int DS1515pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1515pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1515pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1515pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1515p_ops = { + .x86_init_module_type = DS1515pInitModuleType, + .x86_fan_speed_mapping = DS1515pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/avoton/ds1517+.c b/drivers/syno/synobios/avoton/ds1517+.c new file mode 100644 index 000000000000..79ecf1661a9b --- /dev/null +++ b/drivers/syno/synobios/avoton/ds1517+.c @@ -0,0 +1,53 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +PWM_FAN_SPEED_MAPPING gDS1517pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1517pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1517p = MODULE_T_DS1517p; + module_t *pType = &type_ds1517p; + + module_type_set(pType); + return 0; +} + +static +int DS1517pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1517pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1517pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1517pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1517p_ops = { + .x86_init_module_type = DS1517pInitModuleType, + .x86_fan_speed_mapping = DS1517pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/avoton/ds1616+.c b/drivers/syno/synobios/avoton/ds1616+.c new file mode 100644 index 000000000000..fdbc20525943 --- /dev/null +++ b/drivers/syno/synobios/avoton/ds1616+.c @@ -0,0 +1,56 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gDS1616pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1616pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1616p = MODULE_T_DS1616p; + module_t *pType = &type_ds1616p; + + module_type_set(pType); + return 0; +} + +static +int DS1616pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1616pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1616pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1616pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1616p_ops = { + .x86_init_module_type = DS1616pInitModuleType, + .x86_fan_speed_mapping = DS1616pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_power_status = NULL, +}; diff --git a/drivers/syno/synobios/avoton/ds1815+.c b/drivers/syno/synobios/avoton/ds1815+.c new file mode 100644 index 000000000000..14e388d1e754 --- /dev/null +++ b/drivers/syno/synobios/avoton/ds1815+.c @@ -0,0 +1,53 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +PWM_FAN_SPEED_MAPPING gDS1815pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1815pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1815p = MODULE_T_DS1815p; + module_t *pType = &type_ds1815p; + + module_type_set(pType); + return 0; +} + +static +int DS1815pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1815pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1815pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1815pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1815p_ops = { + .x86_init_module_type = DS1815pInitModuleType, + .x86_fan_speed_mapping = DS1815pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/avoton/ds1817+.c b/drivers/syno/synobios/avoton/ds1817+.c new file mode 100644 index 000000000000..8310de9b9dfe --- /dev/null +++ b/drivers/syno/synobios/avoton/ds1817+.c @@ -0,0 +1,53 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "avoton_common.h" + +PWM_FAN_SPEED_MAPPING gDS1817pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1817pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1817p = MODULE_T_DS1817p; + module_t *pType = &type_ds1817p; + + module_type_set(pType); + return 0; +} + +static +int DS1817pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1817pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1817pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1817pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1817p_ops = { + .x86_init_module_type = DS1817pInitModuleType, + .x86_fan_speed_mapping = DS1817pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/avoton/ds2415+.c b/drivers/syno/synobios/avoton/ds2415+.c new file mode 100644 index 000000000000..27c43c0b17b3 --- /dev/null +++ b/drivers/syno/synobios/avoton/ds2415+.c @@ -0,0 +1,53 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + + +PWM_FAN_SPEED_MAPPING gDS2415pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS2415pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds2415p = MODULE_T_DS2415p; + module_t *pType = &type_ds2415p; + module_type_set(pType); + return 0; +} + +static +int DS2415pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i = 0; + + for (i = 0; i < sizeof(gDS2415pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i) { + if (gDS2415pSpeedMapping[i].fanSpeed == speed) { + iDutyCycle = gDS2415pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds2415p_ops = { + .x86_init_module_type = DS2415pInitModuleType, + .x86_fan_speed_mapping = DS2415pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/avoton/ds415+.c b/drivers/syno/synobios/avoton/ds415+.c new file mode 100644 index 000000000000..f6a3c5837581 --- /dev/null +++ b/drivers/syno/synobios/avoton/ds415+.c @@ -0,0 +1,75 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +PWM_FAN_SPEED_MAPPING gDS415pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds415p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int ds415p_hdd_enable_gpio[] = {10, 15, 16, 17}; +int ds415p_hdd_detect_gpio[] = {18, 28, 34, 44}; + +static +int DS415pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds415p = MODULE_T_DS415p; + module_t *pType = &type_ds415p; + + module_type_set(pType); + return 0; +} + +static +int DS415pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS415pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS415pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS415pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds415p_ops = { + .x86_init_module_type = DS415pInitModuleType, + .x86_fan_speed_mapping = DS415pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; + +struct hwmon_sensor_list ds415p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds415p_hdd_backplane_status, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/avoton/rs1219+.c b/drivers/syno/synobios/avoton/rs1219+.c new file mode 100644 index 000000000000..59f33ccc9947 --- /dev/null +++ b/drivers/syno/synobios/avoton/rs1219+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS1219pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS1219pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs1219p = MODULE_T_RS1219p; + module_t *pType = &type_rs1219p; + + module_type_set(pType); + return 0; +} + +static +int RS1219pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS1219pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS1219pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS1219pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs1219p_ops = { + .x86_init_module_type = RS1219pInitModuleType, + .x86_fan_speed_mapping = RS1219pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = NULL, +}; diff --git a/drivers/syno/synobios/avoton/rs2416+.c b/drivers/syno/synobios/avoton/rs2416+.c new file mode 100644 index 000000000000..bb2efe4ae8ba --- /dev/null +++ b/drivers/syno/synobios/avoton/rs2416+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS2416pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2416pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2416p = MODULE_T_RS2416p; + module_t *pType = &type_rs2416p; + + module_type_set(pType); + return 0; +} + +static +int RS2416pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2416pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2416pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2416pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2416p_ops = { + .x86_init_module_type = RS2416pInitModuleType, + .x86_fan_speed_mapping = RS2416pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = NULL, +}; diff --git a/drivers/syno/synobios/avoton/rs2416rp+.c b/drivers/syno/synobios/avoton/rs2416rp+.c new file mode 100644 index 000000000000..45b5181f1e75 --- /dev/null +++ b/drivers/syno/synobios/avoton/rs2416rp+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS2416rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2416rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2416rpp = MODULE_T_RS2416rpp; + module_t *pType = &type_rs2416rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2416rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2416rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2416rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2416rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2416rpp_ops = { + .x86_init_module_type = RS2416rppInitModuleType, + .x86_fan_speed_mapping = RS2416rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = AvotonRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/avoton/rs815+.c b/drivers/syno/synobios/avoton/rs815+.c new file mode 100644 index 000000000000..9ae8d9a992ae --- /dev/null +++ b/drivers/syno/synobios/avoton/rs815+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS815pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS815pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs815p = MODULE_T_RS815p; + module_t *pType = &type_rs815p; + + module_type_set(pType); + return 0; +} + +static +int RS815pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS815pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS815pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS815pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs815p_ops = { + .x86_init_module_type = RS815pInitModuleType, + .x86_fan_speed_mapping = RS815pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = NULL, +}; diff --git a/drivers/syno/synobios/avoton/rs815rp+.c b/drivers/syno/synobios/avoton/rs815rp+.c new file mode 100644 index 000000000000..043c2be8b786 --- /dev/null +++ b/drivers/syno/synobios/avoton/rs815rp+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS815rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS815rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs815rpp = MODULE_T_RS815rpp; + module_t *pType = &type_rs815rpp; + + module_type_set(pType); + return 0; +} + +static +int RS815rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS815rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS815rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS815rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs815rpp_ops = { + .x86_init_module_type = RS815rppInitModuleType, + .x86_fan_speed_mapping = RS815rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = AvotonRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/avoton/rs818+.c b/drivers/syno/synobios/avoton/rs818+.c new file mode 100644 index 000000000000..36d29750fe40 --- /dev/null +++ b/drivers/syno/synobios/avoton/rs818+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS818pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS818pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs818p = MODULE_T_RS818p; + module_t *pType = &type_rs818p; + + module_type_set(pType); + return 0; +} + +static +int RS818pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS818pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS818pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS818pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs818p_ops = { + .x86_init_module_type = RS818pInitModuleType, + .x86_fan_speed_mapping = RS818pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = NULL, +}; diff --git a/drivers/syno/synobios/avoton/rs818rp+.c b/drivers/syno/synobios/avoton/rs818rp+.c new file mode 100644 index 000000000000..93d5221c461d --- /dev/null +++ b/drivers/syno/synobios/avoton/rs818rp+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "avoton_common.h" + +extern int AvotonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int AvotonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS818rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS818rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs818rpp = MODULE_T_RS818rpp; + module_t *pType = &type_rs818rpp; + + module_type_set(pType); + return 0; +} + +static +int RS818rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS818rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS818rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS818rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs818rpp_ops = { + .x86_init_module_type = RS818rppInitModuleType, + .x86_fan_speed_mapping = RS818rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = AvotonGetBuzzerCleared, + .x86_get_power_status = AvotonRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/braswell/Makefile b/drivers/syno/synobios/braswell/Makefile new file mode 100644 index 000000000000..c26d0e2c3a4e --- /dev/null +++ b/drivers/syno/synobios/braswell/Makefile @@ -0,0 +1,20 @@ +include /env.mak + +obj-m += braswell-synobios.o + +braswell-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds916p.o \ + ds716+.o \ + ds216+.o \ + ds216+II.o \ + ds416play.o \ + ds716+II.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + braswell_common.o diff --git a/drivers/syno/synobios/braswell/braswell_common.c b/drivers/syno/synobios/braswell/braswell_common.c new file mode 100644 index 000000000000..56ddd729968d --- /dev/null +++ b/drivers/syno/synobios/braswell/braswell_common.c @@ -0,0 +1,687 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../rtc/rtc.h" + +#include "braswell_common.h" + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +// 91: GP_CAMERASB02 North-community 35 +// 99: GP_CAMERASB07 North-community 43 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {91, 99}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 56: GPIO_DFX0 North-community 0 +// 59: GPIO_DFX1 North-community 3 +// 63: GPIO_DFX2 North-community 7 +// 57: GPIO_DFX3 North-community 1 +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {56, 59, 63, 57}, + .gpio_polarity = ACTIVE_LOW, +}; +// 61: GPIO_DFX4 North-community 5 +// 60: GPIO_DFX5 North-community 4 +// 71: GPIO_DFX6 North-community 15 +// 58: GPIO_DFX7 North-community 2 +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {61, 60, 71, 58}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 96: GP_CAMERASB03 North-community 40 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {96}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 101: GP_CAMERASB04 North-community 45 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {101}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 90: GP_CAMERASB05 North-community 34 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {90}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_DS916p; + + if ( !strncmp(gszSynoHWVersion, HW_DS916p, strlen(HW_DS916p) ) ) { + model = MODEL_DS916p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS716pII, strlen(HW_DS716pII) ) ) { + model = MODEL_DS716pII; + } else if ( !strncmp(gszSynoHWVersion, HW_DS716p, strlen(HW_DS716p) ) ) { + model = MODEL_DS716p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS216pII, strlen(HW_DS216pII) ) ) { + model = MODEL_DS216pII; + } else if ( !strncmp(gszSynoHWVersion, HW_DS216p, strlen(HW_DS216p) ) ) { + model = MODEL_DS216p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS416play, strlen(HW_DS416play) ) ) { + model = MODEL_DS416play; + } + + return model; +} + +static +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_DS216p: + case MODEL_DS216pII: + case MODEL_DS716p: + case MODEL_DS716pII: + iInternalDiskNum = 2; + break; + case MODEL_DS416play: + case MODEL_DS916p: + iInternalDiskNum = 4; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +static +int SetDiskLedStatusByLedTrigger(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != iStatus) { + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if (0 >= iDiskNum || 8 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByLedTrigger(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByLedTrigger(iHostNum + 1, iStatus); +} + +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 8 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 8 * sizeof(int)); + memset(gpOrangeLedMap, -1, 8 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} +#endif // CONFIG_SYNO_LEDS_TRIGGER + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if (NULL == pCpuTemp) { + goto END; + } +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + /* Front LAN LEDs and RJ45 Phy LEDs are contoled by GPIO pin BRASWELL_GPIO_LAN_LED_CTL */ + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + iError = 0; +ERR: + return iError; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ +if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskTriggerLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 8 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 8 * sizeof(int)); + memset(gpOrangeLedMap, -1, 8 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int iInternalDiskNum = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iInternalDiskNum = GetMaxInternalDiskNum(); + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_DETECT(index)) { + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index-1); + } + } + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_ENABLE(index)) { + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01) << (index-1); + } + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + syno_gpio_init(); + + switch(GetModel()) + { + case MODEL_DS916p: + model_ops = &ds916p_ops; + hwmon_sensor_list = &ds916p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif + break; + case MODEL_DS416play: + model_ops = &ds416play_ops; + hwmon_sensor_list = &ds416play_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif + break; + case MODEL_DS716p: + model_ops = &ds716p_ops; + hwmon_sensor_list = &ds716p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; + break; + case MODEL_DS216p: + model_ops = &ds216p_ops; + hwmon_sensor_list = &ds216p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; + break; + case MODEL_DS216pII: + model_ops = &ds216pII_ops; + hwmon_sensor_list = &ds216pII_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; + break; + case MODEL_DS716pII: + model_ops = &ds716pII_ops; + hwmon_sensor_list = &ds716pII_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); +#endif + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + return 0; +} diff --git a/drivers/syno/synobios/braswell/braswell_common.h b/drivers/syno/synobios/braswell/braswell_common.h new file mode 100644 index 000000000000..b2df6ba96247 --- /dev/null +++ b/drivers/syno/synobios/braswell/braswell_common.h @@ -0,0 +1,114 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif +#include "../common/common.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds916p_ops; +extern struct model_ops ds716p_ops; +extern struct model_ops ds716pII_ops; +extern struct model_ops ds216p_ops; +extern struct model_ops ds216pII_ops; +extern struct model_ops ds416play_ops; + +extern struct hwmon_sensor_list ds916p_sensor_list; +extern struct hwmon_sensor_list ds716p_sensor_list; +extern struct hwmon_sensor_list ds716pII_sensor_list; +extern struct hwmon_sensor_list ds216p_sensor_list; +extern struct hwmon_sensor_list ds216pII_sensor_list; +extern struct hwmon_sensor_list ds416play_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +/* Braswell will use LP3943 as disk led controler */ +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif + +/* + * Braswell has 4 GPIO controllers with different number of pins which are loosely arranged. + * We hard-coded the base offsets of these controllers so the GPIO number can be determined at static time, + * and the ranges are asigned in the pinctrl driver. + * The 'Pad Number Mapping' and info about the controller of which a pin is related to can be + * found in 'Intel Braswell SOC BIOS Writers Guide rev 0.9 (doc no.541233)' table 32-8. + * Both PRD and the document mentioned above are needed to look up for the pin number. + * The global gpio number ranges of each controller are listed below - + * SouthWest 0~55; + * North 56~114; + * Ease 115~138; + * SouthEast 139~193; + */ + +/* Fan Sense */ +#define BRASWELL_GPIO_FAN1_SEN 91 // GP_CAMERASB02 North-community 35 +#define BRASWELL_GPIO_FAN2_SEN 99 // GP_CAMERASB07 North-community 43 +/* LED/Button */ +#define BRASWELL_GPIO_HDD_LED_CTL 96 // GP_CAMERASB03 North-community 40 +#define BRASWELL_GPIO_LAN_LED_CTL 101 // GP_CAMERASB04 North-community 45 +#define BRASWELL_GPIO_USB_COPY_BTN 90 // GP_CAMERASB05 North-community 34 +#define BRASWELL_GPIO_FRONT_LED_CTL 94 // GP_CAMERASB06 North-community 38 +/* Disk Present */ +#define BRASWELL_GPIO_HDD1_PRE 56 // GPIO_DFX0 North-community 0 +#define BRASWELL_GPIO_HDD2_PRE 59 // GPIO_DFX1 North-community 3 +#define BRASWELL_GPIO_HDD3_PRE 63 // GPIO_DFX2 North-community 7 +#define BRASWELL_GPIO_HDD4_PRE 57 // GPIO_DFX3 North-community 1 +/* Disk Power Enable */ +#define BRASWELL_GPIO_HDD1_PWR_EN 61 // GPIO_DFX4 North-community 5 +#define BRASWELL_GPIO_HDD2_PWR_EN 60 // GPIO_DFX5 North-community 4 +#define BRASWELL_GPIO_HDD3_PWR_EN 71 // GPIO_DFX6 North-community 15 +#define BRASWELL_GPIO_HDD4_PWR_EN 58 // GPIO_DFX7 North-community 2 +/* USB Power Enable */ +#define BRASWELL_GPIO_USB_FP_PWR_EN 93 // GP_CAMERASB00 North-community 37 +#define BRASWELL_GPIO_USB_BP_PWR_EN 98 // GP_CAMERASB01 North-community 42 + + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/braswell/ds216+.c b/drivers/syno/synobios/braswell/ds216+.c new file mode 100644 index 000000000000..0d987d73454c --- /dev/null +++ b/drivers/syno/synobios/braswell/ds216+.c @@ -0,0 +1,73 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "braswell_common.h" + +PWM_FAN_SPEED_MAPPING gDS216pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds216p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + + +static +int DS216pInitModuleType(struct synobios_ops *ops) +{ + module_t type_216p = MODULE_T_DS216p; + module_t *pType = &type_216p; + + module_type_set(pType); + return 0; +} + +static +int DS216pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS216pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS216pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS216pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds216p_ops = { + .x86_init_module_type = DS216pInitModuleType, + .x86_fan_speed_mapping = DS216pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ +}; + +struct hwmon_sensor_list ds216p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds216p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/braswell/ds216+II.c b/drivers/syno/synobios/braswell/ds216+II.c new file mode 100644 index 000000000000..a125db02f812 --- /dev/null +++ b/drivers/syno/synobios/braswell/ds216+II.c @@ -0,0 +1,73 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "braswell_common.h" + +PWM_FAN_SPEED_MAPPING gDS216pIISpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds216pII_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + + +static +int DS216pIIInitModuleType(struct synobios_ops *ops) +{ + module_t type_216pII = MODULE_T_DS216pII; + module_t *pType = &type_216pII; + + module_type_set(pType); + return 0; +} + +static +int DS216pIIFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS216pIISpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS216pIISpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS216pIISpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds216pII_ops = { + .x86_init_module_type = DS216pIIInitModuleType, + .x86_fan_speed_mapping = DS216pIIFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ +}; + +struct hwmon_sensor_list ds216pII_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds216pII_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/braswell/ds416play.c b/drivers/syno/synobios/braswell/ds416play.c new file mode 100644 index 000000000000..98ca7669e844 --- /dev/null +++ b/drivers/syno/synobios/braswell/ds416play.c @@ -0,0 +1,73 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "braswell_common.h" + +PWM_FAN_SPEED_MAPPING gDS416playSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds416play_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + + +static +int DS416playInitModuleType(struct synobios_ops *ops) +{ + module_t type_416play = MODULE_T_DS416play; + module_t *pType = &type_416play; + + module_type_set(pType); + return 0; +} + +static +int DS416playFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS416playSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS416playSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS416playSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds416play_ops = { + .x86_init_module_type = DS416playInitModuleType, + .x86_fan_speed_mapping = DS416playFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ +}; + +struct hwmon_sensor_list ds416play_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds416play_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/braswell/ds716+.c b/drivers/syno/synobios/braswell/ds716+.c new file mode 100644 index 000000000000..23676c267f93 --- /dev/null +++ b/drivers/syno/synobios/braswell/ds716+.c @@ -0,0 +1,73 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "braswell_common.h" + +PWM_FAN_SPEED_MAPPING gDS716pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds716p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + + +static +int DS716pInitModuleType(struct synobios_ops *ops) +{ + module_t type_716p = MODULE_T_DS716p; + module_t *pType = &type_716p; + + module_type_set(pType); + return 0; +} + +static +int DS716pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS716pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS716pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS716pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds716p_ops = { + .x86_init_module_type = DS716pInitModuleType, + .x86_fan_speed_mapping = DS716pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ +}; + +struct hwmon_sensor_list ds716p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds716p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/braswell/ds716+II.c b/drivers/syno/synobios/braswell/ds716+II.c new file mode 100644 index 000000000000..49d975817d4d --- /dev/null +++ b/drivers/syno/synobios/braswell/ds716+II.c @@ -0,0 +1,73 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "braswell_common.h" + +PWM_FAN_SPEED_MAPPING gDS716pIISpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds716pII_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + + +static +int DS716pIIInitModuleType(struct synobios_ops *ops) +{ + module_t type_716pII = MODULE_T_DS716pII; + module_t *pType = &type_716pII; + + module_type_set(pType); + return 0; +} + +static +int DS716pIIFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS716pIISpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS716pIISpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS716pIISpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds716pII_ops = { + .x86_init_module_type = DS716pIIInitModuleType, + .x86_fan_speed_mapping = DS716pIIFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ +}; + +struct hwmon_sensor_list ds716pII_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds716pII_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/braswell/ds916p.c b/drivers/syno/synobios/braswell/ds916p.c new file mode 100644 index 000000000000..d1e5fd580db7 --- /dev/null +++ b/drivers/syno/synobios/braswell/ds916p.c @@ -0,0 +1,72 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "braswell_common.h" + +PWM_FAN_SPEED_MAPPING gDS916pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds916p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int DS916pInitModuleType(struct synobios_ops *ops) +{ + module_t type_916p = MODULE_T_DS916p; + module_t *pType = &type_916p; + + module_type_set(pType); + return 0; +} + +static +int DS916pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS916pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS916pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS916pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds916p_ops = { + .x86_init_module_type = DS916pInitModuleType, + .x86_fan_speed_mapping = DS916pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ +}; + +struct hwmon_sensor_list ds916p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds916p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwell/Makefile b/drivers/syno/synobios/broadwell/Makefile new file mode 100755 index 000000000000..57b13021b5e1 --- /dev/null +++ b/drivers/syno/synobios/broadwell/Makefile @@ -0,0 +1,25 @@ +include /env.mak + +obj-m += broadwell-synobios.o + +broadwell-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs4017xs+.o \ + rs18017xs+.o \ + rsd18016xs+.o \ + rs3618xs.o \ + rs3617rpxs.o \ + rs3617xs+.o \ + ds3617xs.o \ + fs2017.o \ + ds3017xs.o \ + fs3400.o \ + ds3617xsII.o \ + ds3622xs+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + broadwell_common.o diff --git a/drivers/syno/synobios/broadwell/broadwell_common.c b/drivers/syno/synobios/broadwell/broadwell_common.c new file mode 100755 index 000000000000..f9b92eeeadaa --- /dev/null +++ b/drivers/syno/synobios/broadwell/broadwell_common.c @@ -0,0 +1,1199 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "broadwell_common.h" +#include +#include + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ + +/** + * Set Max internal disk numbers + */ +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS3017xs: + iMaxInternalDiskNum = 6; + break; + case MODEL_RS3618xs: + case MODEL_RS3617rpxs: + case MODEL_RS3617xsp: + case MODEL_RSD18016xsp: + case MODEL_DS3617xs: + case MODEL_RS18017xsp: + case MODEL_DS3617xsII: + case MODEL_DS3622xsp: + iMaxInternalDiskNum = 12; + break; + case MODEL_RS4017xsp: + iMaxInternalDiskNum = 16; + break; + case MODEL_FS2017: + case MODEL_FS3400: + iMaxInternalDiskNum = 24; + break; + } + return iMaxInternalDiskNum; +} + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = BROADWELL_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELL_POWER1_PIN , &power1_Value, 0) ) { + goto FAIL; + } + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELL_POWER2_PIN , &power2_Value, 0) ) { + goto FAIL; + } + + if (power1_Value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + }else{ + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + }else{ + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static int giDiskLedController = -1; +static int giDiskLedControllerInit = 0; + +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void InitSynoDiskLed(void) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + pin.value = 0; + SetGpioPin(&pin); +} + +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL +/* Control disk led via 1475 SGPIO for user space */ +static +int DiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + // first time we tried to light on disk led + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + if (funcSYNOCtrlDiskLedBy1475) { + iRet = funcSYNOCtrlDiskLedBy1475(disknum, status); + } + return iRet; +} + +/* Control disk led via 1475 SGPIO for kernel */ +static +int SYNODiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + if (1 > disknum || GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if (funcSYNOCtrlDiskLedBy1475 != NULL) { +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) + if (!gblDiskNumNeedTran) { +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ + err = funcSYNOCtrlDiskLedBy1475(disknum - 1, status); +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) + } else { + err = funcSYNOCtrlDiskLedBy1475(giDiskMapTable[disknum - 1], status); + } +#endif /* CONFIG_SYNO_FIXED_DISK_NAME && CONFIG_SYNO_SATA_REMAP */ + } +END: + return err; +} +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {4, 31}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + GPIO_PIN gPioPin; + int rgcVolt[2] = {0, 0}; + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + + gPioPin.pin = gpio_fan_map[fanno-1]; + + do { + GetGpioPin(&gPioPin); + if (!gPioPin.value) { + rgcVolt[0]++; + } else { + rgcVolt[1]++; + } + + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ((rgcVolt[0] + rgcVolt[1]) < 200); + + if (rgcVolt[0] == 0) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + return 0; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int HWMONGetPMBUSStatus(SYNO_HWMON_SENSOR_TYPE* PsuStatus, int psu_no) +{ + int iRet = -1; + if (NULL == PsuStatus || 0 >= psu_no || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(PsuStatus, hwmon_sensor_list->psu_status, psu_no * sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_pmbus_status(PsuStatus, psu_no); + +END: + return iRet; +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_RSD18016xsp; + + if (!strncmp(gszSynoHWVersion, HW_RSD18016xsp, strlen(HW_RSD18016xsp))) { + model = MODEL_RSD18016xsp; + } else if (!strncmp(gszSynoHWVersion, HW_RS3617xsp, strlen(HW_RS3617xsp))) { + model = MODEL_RS3617xsp; + } else if (!strncmp(gszSynoHWVersion, HW_RS3618xs, strlen(HW_RS3618xs))) { + model = MODEL_RS3618xs; + } else if (!strncmp(gszSynoHWVersion, HW_RS3617rpxs, strlen(HW_RS3617rpxs))) { + model = MODEL_RS3617rpxs; + } else if (!strncmp(gszSynoHWVersion, HW_RS4017xsp, strlen(HW_RS4017xsp))) { + model = MODEL_RS4017xsp; + } else if (!strncmp(gszSynoHWVersion, HW_DS3617xs, strlen(HW_DS3617xs))) { + model = MODEL_DS3617xs; + } else if (!strncmp(gszSynoHWVersion, HW_RS18017xsp, strlen(HW_RS18017xsp))) { + model = MODEL_RS18017xsp; + } else if (!strncmp(gszSynoHWVersion, HW_FS2017, strlen(HW_FS2017))) { + model = MODEL_FS2017; + } else if (!strncmp(gszSynoHWVersion, HW_DS3017xs, strlen(HW_DS3017xs))) { + model = MODEL_DS3017xs; + } else if (!strncmp(gszSynoHWVersion, HW_FS3400, strlen(HW_FS3400))) { + model = MODEL_FS3400; + } else if (!strncmp(gszSynoHWVersion, HW_DS3617xsII, strlen(HW_DS3617xsII))) { + model = MODEL_DS3617xsII; + } else if (!strncmp(gszSynoHWVersion, HW_DS3622xsp, strlen(HW_DS3622xsp))) { + model = MODEL_DS3622xsp; + } + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = BROADWELL_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static +int SetDiskLedStatusByI2CLedDimmer(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + + if (0 >= iDiskNum || 6 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByI2CLedDimmer(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByI2CLedDimmer(iHostNum + 1, iStatus); +} + +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 6 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(6 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(6 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 6 * sizeof(int)); + memset(gpOrangeLedMap, -1, 6 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} + +static +int SetDiskLedStatusByAtmega(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + + if (0 >= iDiskNum || (giSynoAtmegaNum*12) < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByAtmega(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByAtmega(iHostNum + 1, iStatus); +} + +/* + * Setup the global Disk ATMEGA LED mapping for sata driver + */ +void SetupDiskAtmegaLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || (giSynoAtmegaNum*12) < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(iInternalDiskNum * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(iInternalDiskNum * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, iInternalDiskNum * sizeof(int)); + memset(gpOrangeLedMap, -1, iInternalDiskNum * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} + +int SetHddActLedByLedTrigger(SYNO_LED ledStatus, u16 addr) +{ + struct i2c_adapter *adapter = NULL; + union i2c_smbus_data data; + int iRet = -1; + + adapter = i2c_get_adapter(I2C_BUS_NO); + if (!adapter) { + printk("synobios: cannot get i2c adapter\n"); + goto END; + } + + data.byte = (SYNO_LED_OFF == ledStatus) ? ATMEGA1608_LED_MASKED : ATMEGA1608_LED_UNMASK; + iRet = i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, ATMEGA1608_MASK, I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk("synobios: fail to write i2c smbus\n"); + goto END; + } + +END: + return iRet; +} + +int SetHddAtmegaLed(SYNO_LED ledStatus) +{ + int i = 0, iRet = 0, iErr; + + for (i = 0; i < giSynoAtmegaNum; ++i) { + iErr = SetHddActLedByLedTrigger(ledStatus, gSynoAtmegaAddr[i]); + if (iErr < 0) { + iRet = iErr; + printk("fail to set HDD act LED on 0x%02x, err=%d", gSynoAtmegaAddr[i], iErr); + } + } + return iRet; +} + + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) + if (NULL == syno_disk_map_table_gen_mv14xx || + 0 > syno_disk_map_table_gen_mv14xx(giDiskMapTable, GetMaxInternalDiskNum())) { + gblDiskNumNeedTran = 0; + } else { + gblDiskNumNeedTran = 1; + } +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ + +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL + synobios_ops.set_disk_led = SYNODiskLedCtrlBy1475SGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = DiskLedCtrlBy1475SGPIO; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + giDiskLedController = BROADWELL_DISK_LED_ACTIVATE_PIN; + + switch(GetModel()) + { + case MODEL_RS3618xs: + model_ops = &rs3618xs_ops; + if (syno_is_hw_revision(HW_R1)) { + RS3618xsSMBusSwitchInit(); + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[12]){20,2,0,22,18,8,6,4,16,14,12,10}, + (int[12]){21,3,1,23,19,9,7,5,17,15,13,11}, + 12); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByAtmega; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); + syno_ahci_disk_led_enable(8, 1); + syno_ahci_disk_led_enable(11, 1); + syno_ahci_disk_led_enable(12, 1); + syno_ahci_disk_led_enable(13, 1); + syno_ahci_disk_led_enable(16, 1); + syno_ahci_disk_led_enable(17, 1); + syno_ahci_disk_led_enable(18, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + } else if (syno_is_hw_revision(HW_R2)) { + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[12]){20,2,0,22,18,8,6,4,16,14,12,10}, + (int[12]){21,3,1,23,19,9,7,5,17,15,13,11}, + 12); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByAtmega; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + } + hwmon_sensor_list = &rs3618xs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + if (syno_is_hw_revision(HW_R1) || + syno_is_hw_revision(HW_R2)) { + hwmon_sensor_list->hdd_backplane = &RS3618xs_hdd_backplane_status; +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + } + break; + case MODEL_RS3617rpxs: + model_ops = &rs3617rpxs_ops; + hwmon_sensor_list = &rs3617rpxs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS3617xsp: + model_ops = &rs3617xsp_ops; + hwmon_sensor_list = &rs3617xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RSD18016xsp: + model_ops = &rsd18016xsp_ops; + break; + case MODEL_RS4017xsp: + model_ops = &rs4017xsp_ops; + hwmon_sensor_list = &rs4017xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_DS3617xs: + model_ops = &ds3617xs_ops; + hwmon_sensor_list = &ds3617xs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS18017xsp: + model_ops = &rs18017xsp_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + hwmon_sensor_list = &rs18017xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_FS2017: + model_ops = &fs2017_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + hwmon_sensor_list = &fs2017_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_FS3400: + model_ops = &fs3400_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + hwmon_sensor_list = &fs3400_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_DS3017xs: + model_ops = &ds3017xs_ops; + synobios_ops.get_fan_status = GetFanStatusMircopWithGPIO; + synobios_ops.set_fan_status = SetFanStatusMircopWithGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[6]){0,2,4,6,8,10}, (int[6]){1,3,5,7,9,11}, 6); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(13, 1); + syno_ahci_disk_led_enable(14, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DS3617xsII: + model_ops = &ds3617xsII_ops; + hwmon_sensor_list = &ds3617xsII_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_DS3622xsp: + model_ops = &ds3622xsp_ops; + hwmon_sensor_list = &ds3622xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} + +/* FIXME: should not directly copy following function + * Modified from drivers/i2c/muxes/i2c-mux-pca954x.c */ +int SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val) +{ + int ret = -1; + struct i2c_adapter *adap = NULL; + + adap = i2c_get_adapter(bus_no); + if (!adap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, addr, + 0, I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } +END: + return ret; +} diff --git a/drivers/syno/synobios/broadwell/broadwell_common.h b/drivers/syno/synobios/broadwell/broadwell_common.h new file mode 100755 index 000000000000..6c36d69471a3 --- /dev/null +++ b/drivers/syno/synobios/broadwell/broadwell_common.h @@ -0,0 +1,129 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif +#include +#include "../i2c/i2c-linux.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops rsd18016xsp_ops; +extern struct model_ops rs3618xs_ops; +extern struct model_ops rs3617rpxs_ops; +extern struct model_ops rs3617xsp_ops; +extern struct model_ops rs4017xsp_ops; +extern struct model_ops ds3617xs_ops; +extern struct model_ops rs18017xsp_ops; +extern struct model_ops fs2017_ops; +extern struct model_ops ds3017xs_ops; +extern struct model_ops fs3400_ops; +extern struct model_ops ds3617xsII_ops; +extern struct model_ops ds3622xsp_ops; + +extern int SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val); +void RS3618xsSMBusSwitchInit(void); + +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +#ifdef CONFIG_SYNO_ATMEGA1608_PROBE_FIXED_BUS +extern int giSynoAtmegaNum; +extern long gSynoAtmegaAddr[SYNO_ATMEGA_NUM_MAX]; +#endif /* CONFIG_SYNO_ATMEGA1608_PROBE_FIXED_BUS */ + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list rs4017xsp_sensor_list; +extern struct hwmon_sensor_list rs3618xs_sensor_list; +extern struct hwmon_sensor_list rs3617rpxs_sensor_list; +extern struct hwmon_sensor_list rs3617xsp_sensor_list; +extern struct hwmon_sensor_list ds3617xs_sensor_list; +extern struct hwmon_sensor_list rs18017xsp_sensor_list; +extern struct hwmon_sensor_list fs2017_sensor_list; +extern struct hwmon_sensor_list fs3400_sensor_list; +extern struct hwmon_sensor_list ds3617xsII_sensor_list; +extern struct hwmon_sensor_list ds3622xsp_sensor_list; + +extern SYNO_HWMON_SENSOR_TYPE RS3618xs_hdd_backplane_status; + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + +#define BROADWELL_POWER1_PIN 50 +#define BROADWELL_POWER2_PIN 54 +#define BROADWELL_BUZZER_OFF_PIN 2 +#define BROADWELL_BUZZER_CTRL_PIN 3 +#define BROADWELL_ALARM_LED_PIN 28 +#define BROADWELL_DISK_LED_ACTIVATE_PIN 45 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +#define I2C_BUS_NO 0 + +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) +extern int (*syno_disk_map_table_gen_mv14xx)(int *iDiskMapTable, int iPortMax); +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL +extern int (*funcSYNOCtrlDiskLedBy1475)(unsigned short, unsigned short); +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/broadwell/ds3017xs.c b/drivers/syno/synobios/broadwell/ds3017xs.c new file mode 100644 index 000000000000..60ce630337d3 --- /dev/null +++ b/drivers/syno/synobios/broadwell/ds3017xs.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int DS3017xsInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3017xs = MODULE_T_DS3017xs; + module_t *pType = &type_ds3017xs; + + module_type_set(pType); + return 0; +} + +struct model_ops ds3017xs_ops = { + .x86_init_module_type = DS3017xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/ds3617xs.c b/drivers/syno/synobios/broadwell/ds3617xs.c new file mode 100644 index 000000000000..a70433b94ee1 --- /dev/null +++ b/drivers/syno/synobios/broadwell/ds3617xs.c @@ -0,0 +1,95 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern char *syno_get_cpu_model_name(void); + +SYNO_HWMON_SENSOR_TYPE DS3617xs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3617xs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3617xs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +static +int DS3617xsInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3617xs = MODULE_T_DS3617xs; + module_t *pType = &type_ds3617xs; + GPIO_PIN Pin; + + if ( strstr(syno_get_cpu_model_name(), "D-1528")) { + pType->cpu_arch_info = CPU_D_1528; + } else { + pType->cpu_arch_info = CPU_D_1527; + } + + module_type_set(pType); + return 0; +} + +struct model_ops ds3617xs_ops = { + .x86_init_module_type = DS3617xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; + +struct hwmon_sensor_list ds3617xs_sensor_list = { + .thermal_sensor = &DS3617xs_thermal_sensor, + .voltage_sensor = &DS3617xs_voltage_sensor, + .fan_speed_rpm = &DS3617xs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/ds3617xsII.c b/drivers/syno/synobios/broadwell/ds3617xsII.c new file mode 100644 index 000000000000..ccbd232d2411 --- /dev/null +++ b/drivers/syno/synobios/broadwell/ds3617xsII.c @@ -0,0 +1,95 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern char *syno_get_cpu_model_name(void); + +SYNO_HWMON_SENSOR_TYPE DS3617xsII_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3617xsII_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3617xsII_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +static +int DS3617xsIIInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3617xsII = MODULE_T_DS3617xsII; + module_t *pType = &type_ds3617xsII; + GPIO_PIN Pin; + + if ( strstr(syno_get_cpu_model_name(), "D-1528")) { + pType->cpu_arch_info = CPU_D_1528; + } else { + pType->cpu_arch_info = CPU_D_1527; + } + + module_type_set(pType); + return 0; +} + +struct model_ops ds3617xsII_ops = { + .x86_init_module_type = DS3617xsIIInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; + +struct hwmon_sensor_list ds3617xsII_sensor_list = { + .thermal_sensor = &DS3617xsII_thermal_sensor, + .voltage_sensor = &DS3617xsII_voltage_sensor, + .fan_speed_rpm = &DS3617xsII_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/ds3622xs+.c b/drivers/syno/synobios/broadwell/ds3622xs+.c new file mode 100755 index 000000000000..ca3c0ce77352 --- /dev/null +++ b/drivers/syno/synobios/broadwell/ds3622xs+.c @@ -0,0 +1,106 @@ +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern char *syno_get_cpu_model_name(void); + +SYNO_HWMON_SENSOR_TYPE DS3622xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3622xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3622xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds3622xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int DS3622xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3622xsp = MODULE_T_DS3622xsp; + module_t *pType = &type_ds3622xsp; + GPIO_PIN Pin; + + if ( strstr(syno_get_cpu_model_name(), "D-1528")) { + pType->cpu_arch_info = CPU_D_1528; + } else { + pType->cpu_arch_info = CPU_D_1527; + } + + module_type_set(pType); + return 0; +} + +struct model_ops ds3622xsp_ops = { + .x86_init_module_type = DS3622xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; + +struct hwmon_sensor_list ds3622xsp_sensor_list = { + .thermal_sensor = &DS3622xsp_thermal_sensor, + .voltage_sensor = &DS3622xsp_voltage_sensor, + .fan_speed_rpm = &DS3622xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &ds3622xsp_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwell/fs2017.c b/drivers/syno/synobios/broadwell/fs2017.c new file mode 100644 index 000000000000..07fb34b3a40e --- /dev/null +++ b/drivers/syno/synobios/broadwell/fs2017.c @@ -0,0 +1,102 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE FS2017_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2017_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2017_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +static +int FS2017InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs2017 = MODULE_T_FS2017; + module_t *pType = &type_fs2017; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops fs2017_ops = { + .x86_init_module_type = FS2017InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list fs2017_sensor_list = { + .thermal_sensor = &FS2017_thermal_sensor, + .voltage_sensor = &FS2017_voltage_sensor, + .fan_speed_rpm = &FS2017_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/fs3400.c b/drivers/syno/synobios/broadwell/fs3400.c new file mode 100644 index 000000000000..be37dbf6041b --- /dev/null +++ b/drivers/syno/synobios/broadwell/fs3400.c @@ -0,0 +1,102 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE FS3400_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3400_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3400_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +static +int FS3400InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs3400 = MODULE_T_FS3400; + module_t *pType = &type_fs3400; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops fs3400_ops = { + .x86_init_module_type = FS3400InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list fs3400_sensor_list = { + .thermal_sensor = &FS3400_thermal_sensor, + .voltage_sensor = &FS3400_voltage_sensor, + .fan_speed_rpm = &FS3400_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/rs18017xs+.c b/drivers/syno/synobios/broadwell/rs18017xs+.c new file mode 100644 index 000000000000..1f52e2179011 --- /dev/null +++ b/drivers/syno/synobios/broadwell/rs18017xs+.c @@ -0,0 +1,102 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE RS18017xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS18017xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS18017xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +static +int RS18017xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs18017xsp = MODULE_T_RS18017xsp; + module_t *pType = &type_rs18017xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs18017xsp_ops = { + .x86_init_module_type = RS18017xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs18017xsp_sensor_list = { + .thermal_sensor = &RS18017xsp_thermal_sensor, + .voltage_sensor = &RS18017xsp_voltage_sensor, + .fan_speed_rpm = &RS18017xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/rs3617rpxs.c b/drivers/syno/synobios/broadwell/rs3617rpxs.c new file mode 100644 index 000000000000..bf3dc9c59216 --- /dev/null +++ b/drivers/syno/synobios/broadwell/rs3617rpxs.c @@ -0,0 +1,102 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE RS3617rpxs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3617rpxs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3617rpxs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +static +int RS3617rpxsInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs3617rpxs = MODULE_T_RS3617rpxs; + module_t *pType = &type_rs3617rpxs; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3617rpxs_ops = { + .x86_init_module_type = RS3617rpxsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3617rpxs_sensor_list = { + .thermal_sensor = &RS3617rpxs_thermal_sensor, + .voltage_sensor = &RS3617rpxs_voltage_sensor, + .fan_speed_rpm = &RS3617rpxs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/rs3617xs+.c b/drivers/syno/synobios/broadwell/rs3617xs+.c new file mode 100644 index 000000000000..33331ab90e99 --- /dev/null +++ b/drivers/syno/synobios/broadwell/rs3617xs+.c @@ -0,0 +1,103 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from broadwell_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE RS3617xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3617xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3617xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, + +}; + +static +int RS3617xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs3617xsp = MODULE_T_RS3617xsp; + module_t *pType = &type_rs3617xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3617xsp_ops = { + .x86_init_module_type = RS3617xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3617xsp_sensor_list = { + .thermal_sensor = &RS3617xsp_thermal_sensor, + .voltage_sensor = &RS3617xsp_voltage_sensor, + .fan_speed_rpm = &RS3617xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/rs3618xs.c b/drivers/syno/synobios/broadwell/rs3618xs.c new file mode 100644 index 000000000000..35ad84626779 --- /dev/null +++ b/drivers/syno/synobios/broadwell/rs3618xs.c @@ -0,0 +1,120 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +#define I2C_SWITCH_ADDR 0x70 +#define I2C_SWITCH_VAL 0x04 + +// extern function from bromolow_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +void RS3618xsSMBusSwitchInit(void) { + SMBusSwitchRegWrite(I2C_BUS_NO, I2C_SWITCH_ADDR, I2C_SWITCH_VAL); +} + +SYNO_HWMON_SENSOR_TYPE RS3618xs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3618xs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3618xs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3618xs_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS3618xsInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs3618xs = MODULE_T_RS3618xs; + module_t *pType = &type_rs3618xs; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3618xs_ops = { + .x86_init_module_type = RS3618xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3618xs_sensor_list = { + .thermal_sensor = &RS3618xs_thermal_sensor, + .voltage_sensor = &RS3618xs_voltage_sensor, + .fan_speed_rpm = &RS3618xs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/rs4017xs+.c b/drivers/syno/synobios/broadwell/rs4017xs+.c new file mode 100644 index 000000000000..40394d32d9a6 --- /dev/null +++ b/drivers/syno/synobios/broadwell/rs4017xs+.c @@ -0,0 +1,171 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from broadwell_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE RS4017xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4017xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4017xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4017xsp_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + + +static +int RS4017xspI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +static +int RS4017xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs4017xsp = MODULE_T_RS4017xsp; + module_t *pType = &type_rs4017xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELL_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs4017xsp_ops = { + .x86_init_module_type = RS4017xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = RS4017xspI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs4017xsp_sensor_list = { + .thermal_sensor = &RS4017xsp_thermal_sensor, + .voltage_sensor = &RS4017xsp_voltage_sensor, + .fan_speed_rpm = &RS4017xsp_fan_speed_rpm, + .psu_status = RS4017xsp_psu_status, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwell/rsd18016xs+.c b/drivers/syno/synobios/broadwell/rsd18016xs+.c new file mode 100644 index 000000000000..f85bc17d1411 --- /dev/null +++ b/drivers/syno/synobios/broadwell/rsd18016xs+.c @@ -0,0 +1,45 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwell_common.h" + +// extern function from bromolow_common +extern int BroadwellRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +/* FIXME wait HW fix this GPIO pin */ +//extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int RSD18016xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rsd18016xsp = MODULE_T_RSD18016xsp; + module_t *pType = &type_rsd18016xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rsd18016xsp_ops = { + .x86_init_module_type = RSD18016xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, +// .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = BroadwellRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/broadwellnk/Makefile b/drivers/syno/synobios/broadwellnk/Makefile new file mode 100644 index 000000000000..28a5d28f03fc --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/Makefile @@ -0,0 +1,32 @@ +include /env.mak + +obj-m += broadwellnk-synobios.o + +broadwellnk-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds3018xs.o \ + fs1018.o \ + rs1619xs+.o \ + sa3400.o \ + sa3600.o \ + fs3600.o \ + hd3400.o \ + ds1621xs+.o \ + rs3621xs+.o \ + rs3621rpxs.o \ + rs4021xs+.o \ + ds3622xs+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + broadwellnk_common.o + +ifneq (,$(filter $(PLAT_SPEC_VAR), SYNO_FEA_PORT_MAPPING_V2)) + broadwellnk-synobios-objs += \ + ../led/led_9235.o \ + ../led/led_1475.o \ + ../led/led_trigger.o +endif diff --git a/drivers/syno/synobios/broadwellnk/broadwellnk_common.c b/drivers/syno/synobios/broadwellnk/broadwellnk_common.c new file mode 100755 index 000000000000..ab0782bd0fe9 --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/broadwellnk_common.c @@ -0,0 +1,1472 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "broadwellnk_common.h" +#include +#include + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int *hdd_enable_gpio = NULL; +static int *hdd_detect_gpio = NULL; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int (*GetMaxInternalHostNum)(void) = NULL; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +extern int syno_is_hw_revision(const char *hw_revision); +static int I2CGetPowerInfo(POWER_INFO *power_info); +/** + * Set Max internal disk numbers + */ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS3018xs: + case MODEL_DS1621xsp: + iMaxInternalDiskNum = 6; + break; + case MODEL_FS1018: + case MODEL_SA3400: + case MODEL_SA3600: + case MODEL_RS3621xsp: + case MODEL_RS3621rpxs: + case MODEL_DS3622xsp: + iMaxInternalDiskNum = 12; + break; + case MODEL_RS4021xsp: + iMaxInternalDiskNum = 16; + break; + case MODEL_RS1619xsp: + iMaxInternalDiskNum = 4; + break; + case MODEL_FS3600: + iMaxInternalDiskNum = 24; + break; + case MODEL_HD3400: + iMaxInternalDiskNum = 60; + break; + } + return iMaxInternalDiskNum; +} + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = BROADWELLNK_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELLNK_POWER1_PIN , &power1_Value, 0) ) { + goto FAIL; + } + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELLNK_POWER2_PIN , &power2_Value, 0) ) { + goto FAIL; + } + + if (power1_Value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + }else{ + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + }else{ + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static int giDiskLedController = -1; +static int giDiskLedControllerInit = 0; + +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void InitSynoDiskLed(void) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + pin.value = 0; + SetGpioPin(&pin); +} + +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL +/* Control disk led via 1475 SGPIO for user space */ +static +int DiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + // first time we tried to light on disk led + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + if (funcSYNOCtrlDiskLedBy1475) { + iRet = funcSYNOCtrlDiskLedBy1475(disknum, status); + } + return iRet; +} + +/* Control disk led via 1475 SGPIO for kernel */ +static +int SYNODiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + if (1 > disknum || GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if (funcSYNOCtrlDiskLedBy1475 != NULL) { +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) + if (!gblDiskNumNeedTran) { +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ + err = funcSYNOCtrlDiskLedBy1475(disknum - 1, status); +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) + } else { + err = funcSYNOCtrlDiskLedBy1475(giDiskMapTable[disknum - 1], status); + } +#endif /* CONFIG_SYNO_FIXED_DISK_NAME && CONFIG_SYNO_SATA_REMAP */ + } +END: + return err; +} +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {4, 31}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + GPIO_PIN gPioPin; + int rgcVolt[2] = {0, 0}; + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + + gPioPin.pin = gpio_fan_map[fanno-1]; + + do { + GetGpioPin(&gPioPin); + if (!gPioPin.value) { + rgcVolt[0]++; + } else { + rgcVolt[1]++; + } + + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ((rgcVolt[0] + rgcVolt[1]) < 200); + + if (rgcVolt[0] == 0) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + return 0; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + GPIO_PIN pPin; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list || (NULL == hdd_enable_gpio && NULL == hdd_detect_gpio)) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != hdd_enable_gpio) { + pPin.pin = hdd_enable_gpio[index]; + GetGpioPin(&pPin); + hdd_enable |= (pPin.value & 0x01) << index; + } + // hdd_detect_pin in broadwellnk are active low. So get the inverse value. + if (NULL != hdd_detect_gpio) { + pPin.pin = hdd_detect_gpio[index]; + GetGpioPin(&pPin); + hdd_detect |= ((~pPin.value) & 0x01) << index; + } + } + + if (NULL != hdd_enable_gpio) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + } + if (NULL != hdd_detect_gpio) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + iRet = 0; + +End: + return iRet; +} + +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_DS3018xs; + + if (!strncmp(gszSynoHWVersion, HW_DS3018xs, strlen(HW_DS3018xs))) { + model = MODEL_DS3018xs; + } else if (!strncmp(gszSynoHWVersion, HW_FS1018, strlen(HW_FS1018))) { + model = MODEL_FS1018; + } else if (!strncmp(gszSynoHWVersion, HW_RS1619xsp, strlen(HW_RS1619xsp))) { + model = MODEL_RS1619xsp; + } else if (!strncmp(gszSynoHWVersion, HW_SA3400, strlen(HW_SA3400))) { + model = MODEL_SA3400; + } else if (!strncmp(gszSynoHWVersion, HW_SA3600, strlen(HW_SA3600))) { + model = MODEL_SA3600; + } else if (!strncmp(gszSynoHWVersion, HW_FS3600, strlen(HW_FS3600))) { + model = MODEL_FS3600; + } else if (!strncmp(gszSynoHWVersion, HW_HD3400, strlen(HW_HD3400))) { + model = MODEL_HD3400; + } else if (!strncmp(gszSynoHWVersion, HW_DS1621xsp, strlen(HW_DS1621xsp))) { + model = MODEL_DS1621xsp; + } else if (!strncmp(gszSynoHWVersion, HW_RS3621xsp, strlen(HW_RS3621xsp))) { + model = MODEL_RS3621xsp; + } else if (!strncmp(gszSynoHWVersion, HW_RS3621rpxs, strlen(HW_RS3621rpxs))) { + model = MODEL_RS3621rpxs; + } else if (!strncmp(gszSynoHWVersion, HW_RS4021xsp, strlen(HW_RS4021xsp))) { + model = MODEL_RS4021xsp; + } else if (!strncmp(gszSynoHWVersion, HW_DS3622xsp, strlen(HW_DS3622xsp))) { + model = MODEL_DS3622xsp; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = BROADWELLNK_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static +int SetDiskLedStatusByI2CLedDimmer(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + + if (0 >= iDiskNum || 6 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByI2CLedDimmer(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByI2CLedDimmer(iHostNum + 1, iStatus); +} + +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 6 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(6 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(6 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 6 * sizeof(int)); + memset(gpOrangeLedMap, -1, 6 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} + +static +int SetDiskLedStatusByAtmega(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + + if (0 >= iDiskNum || (giSynoAtmegaNum*12) < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int SYNOSetDiskLedStatusByAtmega(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByAtmega(iHostNum + 1, iStatus); +} + +/* + * Setup the global Disk ATMEGA LED mapping for sata driver + */ +void SetupDiskAtmegaLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || (giSynoAtmegaNum*12) < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(iInternalDiskNum * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(iInternalDiskNum * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, iInternalDiskNum * sizeof(int)); + memset(gpOrangeLedMap, -1, iInternalDiskNum * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} + +int SetHddActLedByLedTrigger(SYNO_LED ledStatus, u16 addr) +{ + struct i2c_adapter *adapter = NULL; + union i2c_smbus_data data; + int iRet = -1; + + adapter = i2c_get_adapter(I2C_BUS_NO); + if (!adapter) { + printk("synobios: cannot get i2c adapter\n"); + goto END; + } + + data.byte = (SYNO_LED_OFF == ledStatus) ? ATMEGA1608_LED_MASKED : ATMEGA1608_LED_UNMASK; + iRet = i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, ATMEGA1608_MASK, I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk("synobios: fail to write i2c smbus\n"); + goto END; + } + +END: + return iRet; +} + +int SetHddAtmegaLed(SYNO_LED ledStatus) +{ + int i = 0, iRet = 0, iErr; + + for (i = 0; i < giSynoAtmegaNum; ++i) { + iErr = SetHddActLedByLedTrigger(ledStatus, gSynoAtmegaAddr[i]); + if (iErr < 0) { + iRet = iErr; + printk("fail to set HDD act LED on 0x%02x, err=%d", gSynoAtmegaAddr[i], iErr); + } + } + return iRet; +} + + + +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; +#else + giDiskLedController = BROADWELLNK_DISK_LED_ACTIVATE_PIN; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) + if (NULL == syno_disk_map_table_gen_mv14xx || + 0 > syno_disk_map_table_gen_mv14xx(giDiskMapTable, GetMaxInternalDiskNum())) { + gblDiskNumNeedTran = 0; + } else { + gblDiskNumNeedTran = 1; + } +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ + +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL + synobios_ops.set_disk_led = SYNODiskLedCtrlBy1475SGPIO; +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + funcSYNOSATADiskLedCtrl = SYNODiskLedCtrlBy1475SGPIO; +#else + funcSYNOSATADiskLedCtrl = DiskLedCtrlBy1475SGPIO; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + + switch(GetModel()) + { + case MODEL_DS3018xs: + model_ops = &ds3018xs_ops; + synobios_ops.get_fan_status = GetFanStatusMircopWithGPIO; + synobios_ops.set_fan_status = SetFanStatusMircopWithGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; +#else + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + SetupDiskLedMap((int[6]){0,2,4,6,8,10}, (int[6]){1,3,5,7,9,11}, 6); +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#else + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(12, 1); + syno_ahci_disk_led_enable(13, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_FS1018: + model_ops = &fs1018_ops; + synobios_ops.get_fan_status = GetFanStatusMircopWithGPIO; + synobios_ops.set_fan_status = SetFanStatusMircopWithGPIO; + break; + case MODEL_RS1619xsp: + model_ops = &rs1619xsp_ops; + hwmon_sensor_list = &rs1619xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + synobios_ops.get_fan_status = GetFanStatusMircopWithGPIO; + synobios_ops.set_fan_status = SetFanStatusMircopWithGPIO; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + hdd_enable_gpio = rs1619xsp_hdd_enable_gpio; + hdd_detect_gpio = rs1619xsp_hdd_detect_gpio; +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; +#else + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#else + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_SA3400: + model_ops = &sa3400_ops; + hwmon_sensor_list = &sa3400_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + break; + case MODEL_SA3600: + model_ops = &sa3600_ops; + hwmon_sensor_list = &sa3600_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + break; + case MODEL_FS3600: + model_ops = &fs3600_ops; + hwmon_sensor_list = &fs3600_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + break; + case MODEL_HD3400: + model_ops = &hd3400_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + break; + case MODEL_DS1621xsp: + model_ops = &ds1621xsp_ops; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[6]){0,2,4,6,8,10}, (int[6]){1,3,5,7,9,11}, 6); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(12, 1); + syno_ahci_disk_led_enable(13, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + hwmon_sensor_list = &ds1621xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; + break; + case MODEL_RS3621xsp: + model_ops = &rs3621xsp_ops; + if (syno_is_hw_revision(HW_R1)) { + model_ops->x86_get_power_status = I2CGetPowerInfo; + RS3621xspSMBusSwitchInit(); + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[12]){20,2,0,22,18,8,6,4,16,14,12,10}, + (int[12]){21,3,1,23,19,9,7,5,17,15,13,11}, + 12); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); + syno_ahci_disk_led_enable(8, 1); + syno_ahci_disk_led_enable(11, 1); + syno_ahci_disk_led_enable(12, 1); + syno_ahci_disk_led_enable(13, 1); + syno_ahci_disk_led_enable(16, 1); + syno_ahci_disk_led_enable(17, 1); + syno_ahci_disk_led_enable(18, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + } else if (syno_is_hw_revision(HW_R2)) { + model_ops->x86_get_power_status = I2CGetPowerInfo; + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[12]){20,2,0,22,18,8,6,4,16,14,12,10}, + (int[12]){21,3,1,23,19,9,7,5,17,15,13,11}, + 12); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + } + hwmon_sensor_list = &rs3621xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + if (syno_is_hw_revision(HW_R1) || + syno_is_hw_revision(HW_R2)) { + hwmon_sensor_list->hdd_backplane = &RS3621xsp_hdd_backplane_status; +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + } + break; + case MODEL_RS3621rpxs: + model_ops = &rs3621rpxs_ops; + if (syno_is_hw_revision(HW_R1)) { + model_ops->x86_get_power_status = I2CGetPowerInfo; + RS3621rpxsSMBusSwitchInit(); + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[12]){20,2,0,22,18,8,6,4,16,14,12,10}, + (int[12]){21,3,1,23,19,9,7,5,17,15,13,11}, + 12); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByAtmega; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); + syno_ahci_disk_led_enable(8, 1); + syno_ahci_disk_led_enable(11, 1); + syno_ahci_disk_led_enable(12, 1); + syno_ahci_disk_led_enable(13, 1); + syno_ahci_disk_led_enable(16, 1); + syno_ahci_disk_led_enable(17, 1); + syno_ahci_disk_led_enable(18, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + } else if (syno_is_hw_revision(HW_R2)) { + model_ops->x86_get_power_status = I2CGetPowerInfo; + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[12]){20,2,0,22,18,8,6,4,16,14,12,10}, + (int[12]){21,3,1,23,19,9,7,5,17,15,13,11}, + 12); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByAtmega; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + } + hwmon_sensor_list = &rs3621rpxs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + if (syno_is_hw_revision(HW_R1) || + syno_is_hw_revision(HW_R2)) { + hwmon_sensor_list->hdd_backplane = &RS3621rpxs_hdd_backplane_status; +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + } + break; + case MODEL_RS4021xsp: + model_ops = &rs4021xsp_ops; + if (syno_is_hw_revision(HW_R1)) { + RS4021xspSMBusSwitchInit(); + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[16]){40,26,16,2,38,28,14,4,36,30,12,6,34,32,10,8}, + (int[16]){41,27,17,3,39,29,15,5,37,31,13,7,35,33,11,9}, + 16); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByAtmega; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(5, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); + syno_ahci_disk_led_enable(8, 1); + syno_ahci_disk_led_enable(10, 1); + syno_ahci_disk_led_enable(11, 1); + syno_ahci_disk_led_enable(12, 1); + syno_ahci_disk_led_enable(13, 1); + syno_ahci_disk_led_enable(15, 1); + syno_ahci_disk_led_enable(16, 1); + syno_ahci_disk_led_enable(17, 1); + syno_ahci_disk_led_enable(18, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + } else if (syno_is_hw_revision(HW_R2)) { + synobios_ops.set_hdd_led = SetHddAtmegaLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByAtmega; + SetupDiskAtmegaLedMap( + (int[16]){40,26,16,2,38,28,14,4,36,30,12,6,34,32,10,8}, + (int[16]){41,27,17,3,39,29,15,5,37,31,13,7,35,33,11,9}, + 16); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByAtmega; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + } + hwmon_sensor_list = &rs4021xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + if (syno_is_hw_revision(HW_R1) || + syno_is_hw_revision(HW_R2)) { + hwmon_sensor_list->hdd_backplane = &RS4021xsp_hdd_backplane_status; +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + } + break; + case MODEL_DS3622xsp: + model_ops = &ds3622xsp_ops; + hwmon_sensor_list = &ds3622xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + break; + + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} + +static +int I2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +/* FIXME: should not directly copy following function + * Modified from drivers/i2c/muxes/i2c-mux-pca954x.c */ +int SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val) +{ + int ret = -1; + struct i2c_adapter *adap = NULL; + + adap = i2c_get_adapter(bus_no); + if (!adap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, addr, + 0, I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } +END: + return ret; +} diff --git a/drivers/syno/synobios/broadwellnk/broadwellnk_common.h b/drivers/syno/synobios/broadwellnk/broadwellnk_common.h new file mode 100755 index 000000000000..1a5f56c34b6f --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/broadwellnk_common.h @@ -0,0 +1,151 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include "../led/led_9235.h" +#include "../led/led_trigger.h" +#include "../led/led_1475.h" +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ +#include "../i2c/i2c-linux.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops ds3018xs_ops; +extern struct model_ops fs1018_ops; +extern struct model_ops rs1619xsp_ops; +extern struct model_ops sa3400_ops; +extern struct model_ops sa3600_ops; +extern struct model_ops fs3600_ops; +extern struct model_ops hd3400_ops; +extern struct model_ops ds1621xsp_ops; +extern struct model_ops rs3621xsp_ops; +extern struct model_ops rs3621rpxs_ops; +extern struct model_ops rs4021xsp_ops; +extern struct model_ops ds3622xsp_ops; + +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list fs3600_sensor_list; +extern struct hwmon_sensor_list sa3600_sensor_list; +extern struct hwmon_sensor_list sa3400_sensor_list; +extern struct hwmon_sensor_list rs1619xsp_sensor_list; +extern struct hwmon_sensor_list ds1621xsp_sensor_list; +extern struct hwmon_sensor_list rs3621xsp_sensor_list; +extern struct hwmon_sensor_list rs3621rpxs_sensor_list; +extern struct hwmon_sensor_list rs4021xsp_sensor_list; +extern struct hwmon_sensor_list ds3622xsp_sensor_list; +extern int rs1619xsp_hdd_enable_gpio[4]; +extern int rs1619xsp_hdd_detect_gpio[4]; +extern SYNO_HWMON_SENSOR_TYPE RS4021xsp_hdd_backplane_status; +extern SYNO_HWMON_SENSOR_TYPE RS3621xsp_hdd_backplane_status; +extern SYNO_HWMON_SENSOR_TYPE RS3621rpxs_hdd_backplane_status; + +extern int SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val); +void RS3621xspSMBusSwitchInit(void); +void RS3621rpxsSMBusSwitchInit(void); +void RS4021xspSMBusSwitchInit(void); + +#ifdef CONFIG_SYNO_ATMEGA1608_PROBE_FIXED_BUS +extern int giSynoAtmegaNum; +extern long gSynoAtmegaAddr[SYNO_ATMEGA_NUM_MAX]; +#endif /* CONFIG_SYNO_ATMEGA1608_PROBE_FIXED_BUS */ + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +#ifdef CONFIG_SYNO_SATA_REMAP +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(CONFIG_SYNO_LEDS_TRIGGER) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#define BROADWELLNK_POWER1_PIN 50 +#define BROADWELLNK_POWER2_PIN 54 +#define BROADWELLNK_BUZZER_OFF_PIN 2 +#define BROADWELLNK_BUZZER_CTRL_PIN 3 +#define BROADWELLNK_ALARM_LED_PIN 28 +#define BROADWELLNK_DISK_LED_ACTIVATE_PIN 45 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +#define I2C_BUS_NO 0 + +#if defined(CONFIG_SYNO_FIXED_DISK_NAME_MV14XX) && defined(CONFIG_SYNO_SATA_REMAP) +extern int (*syno_disk_map_table_gen_mv14xx)(int *iDiskMapTable, int iPortMax); +#endif /* CONFIG_SYNO_FIXED_DISK_NAME_MV14XX && CONFIG_SYNO_SATA_REMAP */ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL +extern int (*funcSYNOCtrlDiskLedBy1475)(unsigned short, unsigned short); +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); + +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/broadwellnk/ds1621xs+.c b/drivers/syno/synobios/broadwellnk/ds1621xs+.c new file mode 100644 index 000000000000..48884c68be0e --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/ds1621xs+.c @@ -0,0 +1,98 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE ds1621xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds1621xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds1621xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds1621xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int DS1621xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1621xsp = MODULE_T_DS1621xsp; + module_t *pType = &type_ds1621xsp; + + module_type_set(pType); + return 0; +} + +struct model_ops ds1621xsp_ops = { + .x86_init_module_type = DS1621xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; + +struct hwmon_sensor_list ds1621xsp_sensor_list = { + .thermal_sensor = &ds1621xsp_thermal_sensor, + .voltage_sensor = &ds1621xsp_voltage_sensor, + .fan_speed_rpm = &ds1621xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &ds1621xsp_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwellnk/ds3018xs.c b/drivers/syno/synobios/broadwellnk/ds3018xs.c new file mode 100644 index 000000000000..df0d39467596 --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/ds3018xs.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int DS3018xsInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3018xs = MODULE_T_DS3018xs; + module_t *pType = &type_ds3018xs; + + module_type_set(pType); + return 0; +} + +struct model_ops ds3018xs_ops = { + .x86_init_module_type = DS3018xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; diff --git a/drivers/syno/synobios/broadwellnk/ds3622xs+.c b/drivers/syno/synobios/broadwellnk/ds3622xs+.c new file mode 100755 index 000000000000..94205fa1454b --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/ds3622xs+.c @@ -0,0 +1,99 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern char *syno_get_cpu_model_name(void); + +SYNO_HWMON_SENSOR_TYPE DS3622xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3622xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3622xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds3622xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int DS3622xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3622xsp = MODULE_T_DS3622xsp; + module_t *pType = &type_ds3622xsp; + + module_type_set(pType); + return 0; +} + +struct model_ops ds3622xsp_ops = { + .x86_init_module_type = DS3622xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; + +struct hwmon_sensor_list ds3622xsp_sensor_list = { + .thermal_sensor = &DS3622xsp_thermal_sensor, + .voltage_sensor = &DS3622xsp_voltage_sensor, + .fan_speed_rpm = &DS3622xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &ds3622xsp_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwellnk/fs1018.c b/drivers/syno/synobios/broadwellnk/fs1018.c new file mode 100644 index 000000000000..8484fca62c1e --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/fs1018.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int FS1018InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs1018 = MODULE_T_FS1018; + module_t *pType = &type_fs1018; + + module_type_set(pType); + return 0; +} + +struct model_ops fs1018_ops = { + .x86_init_module_type = FS1018InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; diff --git a/drivers/syno/synobios/broadwellnk/fs3600.c b/drivers/syno/synobios/broadwellnk/fs3600.c new file mode 100644 index 000000000000..3dbd564d90cb --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/fs3600.c @@ -0,0 +1,103 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +SYNO_HWMON_SENSOR_TYPE FS3600_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3600_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3600_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +static +int FS3600InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs3600 = MODULE_T_FS3600; + module_t *pType = &type_fs3600; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops fs3600_ops = { + .x86_init_module_type = FS3600InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list fs3600_sensor_list = { + .thermal_sensor = &FS3600_thermal_sensor, + .voltage_sensor = &FS3600_voltage_sensor, + .fan_speed_rpm = &FS3600_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; + diff --git a/drivers/syno/synobios/broadwellnk/hd3400.c b/drivers/syno/synobios/broadwellnk/hd3400.c new file mode 100644 index 000000000000..3057383b2893 --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/hd3400.c @@ -0,0 +1,43 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int HD3400InitModuleType(struct synobios_ops *ops) +{ + module_t type_hd3400 = MODULE_T_HD3400; + module_t *pType = &type_hd3400; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops hd3400_ops = { + .x86_init_module_type = HD3400InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/broadwellnk/rs1619xs+.c b/drivers/syno/synobios/broadwellnk/rs1619xs+.c new file mode 100644 index 000000000000..054195e5d10b --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/rs1619xs+.c @@ -0,0 +1,111 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int RS1619xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs1619xsp = MODULE_T_RS1619xsp; + module_t *pType = &type_rs1619xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RS1619xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1619xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1619xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1619xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int rs1619xsp_hdd_enable_gpio[4] = {71, 70, 25, 27}; +int rs1619xsp_hdd_detect_gpio[4] = {69, 26, 35, 37}; + +struct model_ops rs1619xsp_ops = { + .x86_init_module_type = RS1619xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs1619xsp_sensor_list = { + .thermal_sensor = &RS1619xsp_thermal_sensor, + .voltage_sensor = &RS1619xsp_voltage_sensor, + .fan_speed_rpm = &RS1619xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &RS1619xsp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/broadwellnk/rs3621rpxs.c b/drivers/syno/synobios/broadwellnk/rs3621rpxs.c new file mode 100644 index 000000000000..e86e87dad3fa --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/rs3621rpxs.c @@ -0,0 +1,120 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +#define I2C_SWITCH_ADDR 0x70 +#define I2C_SWITCH_VAL 0x04 + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +void RS3621rpxsSMBusSwitchInit(void) { + SMBusSwitchRegWrite(I2C_BUS_NO, I2C_SWITCH_ADDR, I2C_SWITCH_VAL); +} + +SYNO_HWMON_SENSOR_TYPE RS3621rpxs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3621rpxs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3621rpxs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3621rpxs_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS3621rpxsInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs3621rpxs = MODULE_T_RS3621rpxs; + module_t *pType = &type_rs3621rpxs; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNK_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3621rpxs_ops = { + .x86_init_module_type = RS3621rpxsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3621rpxs_sensor_list = { + .thermal_sensor = &RS3621rpxs_thermal_sensor, + .voltage_sensor = &RS3621rpxs_voltage_sensor, + .fan_speed_rpm = &RS3621rpxs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwellnk/rs3621xs+.c b/drivers/syno/synobios/broadwellnk/rs3621xs+.c new file mode 100644 index 000000000000..917b4247cc85 --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/rs3621xs+.c @@ -0,0 +1,121 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +#define I2C_SWITCH_ADDR 0x70 +#define I2C_SWITCH_VAL 0x04 + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +void RS3621xspSMBusSwitchInit(void) { + SMBusSwitchRegWrite(I2C_BUS_NO, I2C_SWITCH_ADDR, I2C_SWITCH_VAL); +} + +SYNO_HWMON_SENSOR_TYPE RS3621xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3621xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3621xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, + +}; + +SYNO_HWMON_SENSOR_TYPE RS3621xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS3621xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs3621xsp = MODULE_T_RS3621xsp; + module_t *pType = &type_rs3621xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNK_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3621xsp_ops = { + .x86_init_module_type = RS3621xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3621xsp_sensor_list = { + .thermal_sensor = &RS3621xsp_thermal_sensor, + .voltage_sensor = &RS3621xsp_voltage_sensor, + .fan_speed_rpm = &RS3621xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwellnk/rs4021xs+.c b/drivers/syno/synobios/broadwellnk/rs4021xs+.c new file mode 100755 index 000000000000..20f7e220e3ed --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/rs4021xs+.c @@ -0,0 +1,185 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +#define I2C_SWITCH_ADDR 0x70 +#define I2C_SWITCH_VAL 0x04 + +// extern function from broadwellnk_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +void RS4021xspSMBusSwitchInit(void) { + SMBusSwitchRegWrite(I2C_BUS_NO, I2C_SWITCH_ADDR, I2C_SWITCH_VAL); +} + +SYNO_HWMON_SENSOR_TYPE RS4021xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4021xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4021xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4021xsp_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4021xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + + +static +int RS4021xspI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +static +int RS4021xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs4021xsp = MODULE_T_RS4021xsp; + module_t *pType = &type_rs4021xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNK_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs4021xsp_ops = { + .x86_init_module_type = RS4021xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = RS4021xspI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs4021xsp_sensor_list = { + .thermal_sensor = &RS4021xsp_thermal_sensor, + .voltage_sensor = &RS4021xsp_voltage_sensor, + .fan_speed_rpm = &RS4021xsp_fan_speed_rpm, + .psu_status = RS4021xsp_psu_status, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/broadwellnk/sa3400.c b/drivers/syno/synobios/broadwellnk/sa3400.c new file mode 100644 index 000000000000..f8453bdfc9c6 --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/sa3400.c @@ -0,0 +1,103 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int SA3400InitModuleType(struct synobios_ops *ops) +{ + module_t type_sa3400 = MODULE_T_SA3400; + module_t *pType = &type_sa3400; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE SA3400_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3400_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3400_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops sa3400_ops = { + .x86_init_module_type = SA3400InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list sa3400_sensor_list = { + .thermal_sensor = &SA3400_thermal_sensor, + .voltage_sensor = &SA3400_voltage_sensor, + .fan_speed_rpm = &SA3400_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; + diff --git a/drivers/syno/synobios/broadwellnk/sa3600.c b/drivers/syno/synobios/broadwellnk/sa3600.c new file mode 100644 index 000000000000..e3d4a02a1aaa --- /dev/null +++ b/drivers/syno/synobios/broadwellnk/sa3600.c @@ -0,0 +1,103 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnk_common.h" + +// extern function from broadwellnk_common +extern int BroadwellnkRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int SA3600InitModuleType(struct synobios_ops *ops) +{ + module_t type_sa3600 = MODULE_T_SA3600; + module_t *pType = &type_sa3600; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELL_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNK_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE SA3600_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3600_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3600_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops sa3600_ops = { + .x86_init_module_type = SA3600InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellnkRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list sa3600_sensor_list = { + .thermal_sensor = &SA3600_thermal_sensor, + .voltage_sensor = &SA3600_voltage_sensor, + .fan_speed_rpm = &SA3600_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; + diff --git a/drivers/syno/synobios/broadwellnkv2/Makefile b/drivers/syno/synobios/broadwellnkv2/Makefile new file mode 100644 index 000000000000..4d29f9b232af --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/Makefile @@ -0,0 +1,20 @@ +include /env.mak + +obj-m += broadwellnkv2-synobios.o + +broadwellnkv2-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs4022xs+.o \ + fs3410.o \ + sa3410.o \ + sa3610.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + ../led/led_trigger.o \ + broadwellnkv2_common.o \ + ../pmbus/pmbus.o diff --git a/drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.c b/drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.c new file mode 100755 index 000000000000..6bf04cff8c87 --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.c @@ -0,0 +1,742 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "../pmbus/pmbus.h" +#include "broadwellnkv2_common.h" + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +int (*GetMaxInternalHostNum)(void) = NULL; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + +#ifdef CONFIG_SYNO_ICH_GPIO_CTRL +int SetIchGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +int GetIchGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0)) { + goto End; + } + + ret = 0; +End: + return ret; +} +#endif /* CONFIG_SYNO_ICH_GPIO_CTRL */ +/** + * Set Max internal disk numbers + */ +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_RS4022xsp: + iMaxInternalDiskNum = 16; + break; + case MODEL_FS3410: + iMaxInternalDiskNum = 24; + break; + case MODEL_SA3410: + case MODEL_SA3610: + iMaxInternalDiskNum = 12; + break; + } + return iMaxInternalDiskNum; +} + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = BROADWELLNKV2_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetIchGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = BROADWELLNKV2_BUZZER_OFF_PIN; + if ( 0 > GetIchGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int Broadwellnkv2RedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELLNKV2_POWER1_PIN , &power1_Value, 0) ) { + goto FAIL; + } + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELLNKV2_POWER2_PIN , &power2_Value, 0) ) { + goto FAIL; + } + + if (power1_Value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + }else{ + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + }else{ + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_DS3018xs; + + if (!strncmp(gszSynoHWVersion, HW_RS4022xsp, strlen(HW_RS4022xsp))) { + model = MODEL_RS4022xsp; + }else if (!strncmp(gszSynoHWVersion, HW_FS3410, strlen(HW_FS3410))) { + model = MODEL_FS3410; + }else if (!strncmp(gszSynoHWVersion, HW_SA3410, strlen(HW_SA3410))) { + model = MODEL_SA3410; + }else if (!strncmp(gszSynoHWVersion, HW_SA3610, strlen(HW_SA3610))) { + model = MODEL_SA3610; + } + + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = BROADWELLNKV2_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetIchGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetIchGpioPin, + .set_gpio_pin = SetIchGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int Broadwellnkv2GetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + + if (NULL == hwmon_sensor_list) { + goto END; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + iRet = HWMONGetPSUStatusByI2C(psu_status, iPsuNumber); +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + int i, maxdisk = 0; + *ops = &synobios_ops; + + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; + + switch(GetModel()) + { + case MODEL_RS4022xsp: + model_ops = &rs4022xsp_ops; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + break; + case MODEL_FS3410: + model_ops = &fs3410_ops; + FS3410SMBusSwitchInit(); + hwmon_sensor_list = &fs3410_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = Broadwellnkv2GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + g_smbus_hdd_powerctl = 1; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + maxdisk = GetMaxInternalDiskNum(); + for (i = 1; i <= maxdisk; ++i) { + syno_ahci_disk_led_enable_by_port(i, 1); + } +#endif + break; + case MODEL_SA3410: + model_ops = &sa3410_ops; + hwmon_sensor_list = &sa3410_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = Broadwellnkv2GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + break; + case MODEL_SA3610: + model_ops = &sa3610_ops; + hwmon_sensor_list = &sa3610_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = Broadwellnkv2GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} + +#ifdef CONFIG_SYNO_HWMON_PMBUS +// Portmappingv2 method to get PSU status +int redundantPowerGetPowerStatusByI2C(POWER_INFO *power_info) +{ + int iRet = -1; + + if (NULL == power_info) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + if (0 > I2CPmbusReadPowerStatus(0, &(power_info->power_1))) { + goto END; + } + if (0 > I2CPmbusReadPowerStatus(1, &(power_info->power_2))) { + goto END; + } + + iRet = 0; + +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ diff --git a/drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.h b/drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.h new file mode 100755 index 000000000000..68f27c918000 --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/broadwellnkv2_common.h @@ -0,0 +1,91 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "../led/led_9235.h" +#include "../led/led_trigger.h" +#include "../led/led_1475.h" +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern char gszSynoHWVersion[]; +extern struct model_ops rs4022xsp_ops; +extern struct model_ops fs3410_ops; +extern struct model_ops sa3410_ops; +extern struct model_ops sa3610_ops; + +extern struct hwmon_sensor_list fs3410_sensor_list; +extern struct hwmon_sensor_list sa3410_sensor_list; +extern struct hwmon_sensor_list sa3610_sensor_list; + +#ifdef CONFIG_SYNO_SMBUS_HDD_POWERCTL +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +extern void FS3410SMBusSwitchInit(void); +extern void SA3410SMBusSwitchInit(void); +extern void SA3610SMBusSwitchInit(void); + +#define BROADWELLNKV2_POWER1_PIN 50 +#define BROADWELLNKV2_POWER2_PIN 54 +#define BROADWELLNKV2_BUZZER_OFF_PIN 2 +#define BROADWELLNKV2_BUZZER_CTRL_PIN 3 +#define BROADWELLNKV2_ALARM_LED_PIN 28 +#define BROADWELLNKV2_DISK_LED_ACTIVATE_PIN 45 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); + +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/broadwellnkv2/fs3410.c b/drivers/syno/synobios/broadwellnkv2/fs3410.c new file mode 100644 index 000000000000..c3494bf980bc --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/fs3410.c @@ -0,0 +1,236 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "broadwellnkv2_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from broadwellnkv2_common +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); + + +/* FIXME: should not directly copy following function + * Modified from drivers/i2c/muxes/i2c-mux-pca954x.c */ +int FS3410SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val) +{ + int ret = -1; + struct i2c_adapter *adap = NULL; + + adap = i2c_get_adapter(bus_no); + if (!adap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, addr, + 0, I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } +END: + return ret; +} + +void FS3410SMBusSwitchInit(void) { + FS3410SMBusSwitchRegWrite(0, 0x70, 0x8); +} + +SYNO_HWMON_SENSOR_TYPE FS3410_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3410_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3410_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3410_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS3410_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int FS3410InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs3410 = MODULE_T_FS3410; + module_t *pType = &type_fs3410; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNKV2_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNKV2_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + + +static +int FS3410I2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +struct model_ops fs3410_ops = { + .x86_init_module_type = FS3410InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = FS3410I2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list fs3410_sensor_list = { + .thermal_sensor = &FS3410_thermal_sensor, + .voltage_sensor = &FS3410_voltage_sensor, + .fan_speed_rpm = &FS3410_fan_speed_rpm, + .psu_status = FS3410_psu_status, + .hdd_backplane = &FS3410_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwellnkv2/rs4022xs+.c b/drivers/syno/synobios/broadwellnkv2/rs4022xs+.c new file mode 100644 index 000000000000..121717ca2adf --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/rs4022xs+.c @@ -0,0 +1,73 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellnkv2_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from broadwell_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int RS4022xspI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +static +int RS4022xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs4022xsp = MODULE_T_RS4022xsp; + module_t *pType = &type_rs4022xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNKV2_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNKV2_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs4022xsp_ops = { + .x86_init_module_type = RS4022xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = RS4022xspI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/broadwellnkv2/sa3410.c b/drivers/syno/synobios/broadwellnkv2/sa3410.c new file mode 100644 index 000000000000..eb68a62d60a9 --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/sa3410.c @@ -0,0 +1,214 @@ +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "broadwellnkv2_common.h" +#ifdef CONFIG_SYNO_HWMON_PMBUS +//#include +extern int redundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +// extern function from broadwellnkv2_common +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + + +/* FIXME: should not directly copy following function + * Modified from drivers/i2c/muxes/i2c-mux-pca954x.c */ +int SA3410SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val) +{ + int ret = -1; + struct i2c_adapter *adap = NULL; + + adap = i2c_get_adapter(bus_no); + if (!adap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, addr, + 0, I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } +END: + return ret; +} + +void SA3410SMBusSwitchInit(void) { + + // + // PCIe SMBus switch 0x70 write 0x4, to open the route to PCIe Slot#3) + // 1. SMBus topology : PCIe Slot#3 ---> SAS HBA card ---> HDD BP ---> PIC (slave addr 0x47) + // 2. PIC (slave addr 0x47) to control disk power-on delay (default no delay) and to read hdd present + // + SA3410SMBusSwitchRegWrite(0, 0x70, 0x4); +} + +SYNO_HWMON_SENSOR_TYPE SA3410_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3410_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3410_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3410_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3410_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int SA3410InitModuleType(struct synobios_ops *ops) +{ + module_t type_sa3410 = MODULE_T_SA3410; + module_t *pType = &type_sa3410; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNKV2_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNKV2_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops sa3410_ops = { + .x86_init_module_type = SA3410InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = redundantPowerGetPowerStatusByI2C, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list sa3410_sensor_list = { + .thermal_sensor = &SA3410_thermal_sensor, + .voltage_sensor = &SA3410_voltage_sensor, + .fan_speed_rpm = &SA3410_fan_speed_rpm, + .psu_status = SA3410_psu_status, + .hdd_backplane = &SA3410_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwellnkv2/sa3610.c b/drivers/syno/synobios/broadwellnkv2/sa3610.c new file mode 100644 index 000000000000..05e6f301e33d --- /dev/null +++ b/drivers/syno/synobios/broadwellnkv2/sa3610.c @@ -0,0 +1,214 @@ +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "broadwellnkv2_common.h" +#ifdef CONFIG_SYNO_HWMON_PMBUS +//#include +extern int redundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +// extern function from broadwellnkv2_common +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + + +/* FIXME: should not directly copy following function + * Modified from drivers/i2c/muxes/i2c-mux-pca954x.c */ +int SA3610SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val) +{ + int ret = -1; + struct i2c_adapter *adap = NULL; + + adap = i2c_get_adapter(bus_no); + if (!adap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, addr, + 0, I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } +END: + return ret; +} + +void SA3610SMBusSwitchInit(void) { + + // + // PCIe SMBus switch 0x70 write 0x4, to open the route to PCIe Slot#3) + // 1. SMBus topology : PCIe Slot#3 ---> SAS HBA card ---> HDD BP ---> PIC (slave addr 0x47) + // 2. PIC (slave addr 0x47) to control disk power-on delay (default no delay) and to read hdd present + // + SA3610SMBusSwitchRegWrite(0, 0x70, 0x4); +} + +SYNO_HWMON_SENSOR_TYPE SA3610_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3610_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3610_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3610_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3610_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int SA3610InitModuleType(struct synobios_ops *ops) +{ + module_t type_sa3610 = MODULE_T_SA3610; + module_t *pType = &type_sa3610; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio BROADWELLNKV2_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNKV2_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops sa3610_ops = { + .x86_init_module_type = SA3610InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = redundantPowerGetPowerStatusByI2C, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list sa3610_sensor_list = { + .thermal_sensor = &SA3610_thermal_sensor, + .voltage_sensor = &SA3610_voltage_sensor, + .fan_speed_rpm = &SA3610_fan_speed_rpm, + .psu_status = SA3610_psu_status, + .hdd_backplane = &SA3610_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/broadwellntb/Makefile b/drivers/syno/synobios/broadwellntb/Makefile new file mode 100644 index 000000000000..48a1fb95f5ea --- /dev/null +++ b/drivers/syno/synobios/broadwellntb/Makefile @@ -0,0 +1,14 @@ +include /env.mak + +obj-m += broadwellntb-synobios.o + +broadwellntb-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + taipei.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + broadwellntb_common.o diff --git a/drivers/syno/synobios/broadwellntb/broadwellntb_common.c b/drivers/syno/synobios/broadwellntb/broadwellntb_common.c new file mode 100644 index 000000000000..c1d64b9a1a8b --- /dev/null +++ b/drivers/syno/synobios/broadwellntb/broadwellntb_common.c @@ -0,0 +1,531 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "broadwellntb_common.h" +#include + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; + +static int gblOktoRemoveLedOn = false; +static struct delayed_work oktoremoveled_work; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + +/** + * Set Max internal disk numbers + */ +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_TAIPEI: + iMaxInternalDiskNum = 12; + break; + } + return iMaxInternalDiskNum; +} + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = BROADWELLNTB_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = BROADWELLNTB_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int BroadwellntbRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELLNTB_POWER1_PIN , &power1_Value, 0) ) { + goto FAIL; + } + + if ( 0 != syno_pch_lpc_gpio_pin(BROADWELLNTB_POWER2_PIN , &power2_Value, 0) ) { + goto FAIL; + } + + if (power1_Value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + }else{ + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + }else{ + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static int giDiskLedController = -1; +static int giDiskLedControllerInit = 0; + +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void InitSynoDiskLed(void) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + pin.value = 0; + SetGpioPin(&pin); +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_DS3018xs; + + if (!strncmp(gszSynoHWVersion, HW_TAIPEI, strlen(HW_TAIPEI))) { + model = MODEL_TAIPEI; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = BROADWELLNTB_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static void OkToRemoveLedWork(struct work_struct *work){ + GPIO_PIN Pin; + static unsigned char chGpioStatus = 0; + + Pin.pin = BROADWELLNTB_REMOTE_LED_GPIO_PIN; + + if (true == gblOktoRemoveLedOn) { + Pin.value = chGpioStatus; + if (0 == chGpioStatus) { + chGpioStatus = 1; + } else { + chGpioStatus = 0; + } + if (0 > SetGpioPin(&Pin)) { + printk("Fail to set ok to remove led gpio\n"); + } + schedule_delayed_work(&oktoremoveled_work, + msecs_to_jiffies(1000)); + } else { + Pin.value = 0; + if (0 > SetGpioPin(&Pin)) { + printk("Fail to set ok to remove led gpio\n"); + } + } + +} + +static +int SetOkToRemoveLeD(unsigned char ledON) +{ + /** + * 1 Means led on + * 0 Means led off + */ + static bool blInited = false; + + if (false == blInited) { + INIT_DELAYED_WORK(&oktoremoveled_work, OkToRemoveLedWork); + blInited = true; + } + + if (ledON) { + if (false == gblOktoRemoveLedOn) { + schedule_delayed_work(&oktoremoveled_work, + msecs_to_jiffies(1000)); + } + gblOktoRemoveLedOn = true; + } else { + gblOktoRemoveLedOn = false; + } + + return 0; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .set_ok_to_remove_led = NULL, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + + giDiskLedController = BROADWELLNTB_DISK_LED_ACTIVATE_PIN; + + switch(GetModel()) + { + case MODEL_TAIPEI: + model_ops = &taipei_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + synobios_ops.set_ok_to_remove_led = SetOkToRemoveLeD; + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + diff --git a/drivers/syno/synobios/broadwellntb/broadwellntb_common.h b/drivers/syno/synobios/broadwellntb/broadwellntb_common.h new file mode 100644 index 000000000000..2819e7b9a515 --- /dev/null +++ b/drivers/syno/synobios/broadwellntb/broadwellntb_common.h @@ -0,0 +1,60 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops taipei_ops; + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +extern int syno_ttys_write(const int index, const char* szBuf); +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + +#define BROADWELLNTB_POWER1_PIN 50 +#define BROADWELLNTB_POWER2_PIN 54 +#define BROADWELLNTB_BUZZER_OFF_PIN 2 +#define BROADWELLNTB_BUZZER_CTRL_PIN 3 +#define BROADWELLNTB_ALARM_LED_PIN 28 +#define BROADWELLNTB_DISK_LED_ACTIVATE_PIN 45 +#define BROADWELLNTB_REMOTE_LED_GPIO_PIN 32 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/broadwellntb/taipei.c b/drivers/syno/synobios/broadwellntb/taipei.c new file mode 100644 index 000000000000..09712e95e469 --- /dev/null +++ b/drivers/syno/synobios/broadwellntb/taipei.c @@ -0,0 +1,40 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellntb_common.h" + +// extern function from broadwellntb_common +extern int BroadwellntbRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int TAIPEIInitModuleType(struct synobios_ops *ops) +{ + module_t type_taipei = MODULE_T_TAIPEI; + module_t *pType = &type_taipei; + GPIO_PIN Pin; + + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNTB_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + module_type_set(pType); + return 0; +} + +struct model_ops taipei_ops = { + .x86_init_module_type = TAIPEIInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; diff --git a/drivers/syno/synobios/broadwellntbap/Makefile b/drivers/syno/synobios/broadwellntbap/Makefile new file mode 100644 index 000000000000..0ea2a99aba34 --- /dev/null +++ b/drivers/syno/synobios/broadwellntbap/Makefile @@ -0,0 +1,15 @@ +include /env.mak + +obj-m += broadwellntbap-synobios.o + +broadwellntbap-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + sa3200d.o \ + sa3400d.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + broadwellntbap_common.o diff --git a/drivers/syno/synobios/broadwellntbap/broadwellntbap_common.c b/drivers/syno/synobios/broadwellntbap/broadwellntbap_common.c new file mode 100644 index 000000000000..fbdc62731f30 --- /dev/null +++ b/drivers/syno/synobios/broadwellntbap/broadwellntbap_common.c @@ -0,0 +1,671 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "broadwellntbap_common.h" +#include + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static int gblOktoRemoveLedOn = false; +static struct delayed_work oktoremoveled_work; + + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + +/** + * Set Max internal disk numbers + */ +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_SA3200d: + case MODEL_SA3400d: + iMaxInternalDiskNum = 12; + break; + } + return iMaxInternalDiskNum; +} + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = BROADWELLNTBAP_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = BROADWELLNTBAP_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +int BroadwellntbapRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + u16 data = 0; + + err = linuxI2CSmbusRegRead(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, PSU_DELTA_800AB_I2C_REG, &data); + + if (0 != err) { + printk("%s:%d return error:%d!\n", __FILE__, __LINE__, err); + goto FAIL; + } + + power1_Value = data & 0x1; + power2_Value = data & 0x2; + + if (power1_Value) { + power_info->power_1 = POWER_STATUS_GOOD; + } else { + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value) { + power_info->power_2 = POWER_STATUS_GOOD; + } else { + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static int giDiskLedController = -1; +static int giDiskLedControllerInit = 0; + +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void InitSynoDiskLed(void) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + pin.value = 0; + SetGpioPin(&pin); +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_SA3200d; + + if (!strncmp(gszSynoHWVersion, HW_SA3200d, strlen(HW_SA3200d))) { + model = MODEL_SA3200d; + } + else if (!strncmp(gszSynoHWVersion, HW_SA3400d, strlen(HW_SA3400d))) { + model = MODEL_SA3400d; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( 75 < pPin->pin ) { + goto End; + } + + if (0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = BROADWELLNTBAP_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static void OkToRemoveLedWork(struct work_struct *work){ + GPIO_PIN Pin; + static unsigned char chGpioStatus = 0; + + Pin.pin = BROADWELLNTBAP_REMOTE_LED_GPIO_PIN; + + if (true == gblOktoRemoveLedOn) { + Pin.value = chGpioStatus; + if (0 == chGpioStatus) { + chGpioStatus = 1; + } else { + chGpioStatus = 0; + } + if (0 > SetGpioPin(&Pin)) { + printk("Fail to set ok to remove led gpio\n"); + } + } else { + if (0 == chGpioStatus) { + chGpioStatus = 1; + Pin.value = 0; + if (0 > SetGpioPin(&Pin)) { + printk("Fail to set ok to remove led gpio\n"); + } + } + } + + schedule_delayed_work(&oktoremoveled_work, + msecs_to_jiffies(1000)); +} + +static +int SetOkToRemoveLeD(unsigned char ledON) +{ + /** + * 1 Means led on + * 0 Means led off + */ + static unsigned long Inited = 0; + if (0 == test_and_set_bit(0, &Inited)) { + INIT_DELAYED_WORK(&oktoremoveled_work, OkToRemoveLedWork); + schedule_work(&oktoremoveled_work); + } + + if (ledON) { + gblOktoRemoveLedOn = true; + } else { + gblOktoRemoveLedOn = false; + } + + return 0; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int SynoSetSasAllLed(SYNO_LED ledStatus) { + static SYNO_LED CurrentLedStatus = -1; + int iRet = -1; + GPIO_PIN pin; + + pin.pin = BROADWELLNTBAP_DISK_LED_ACTIVATE_PIN; + pin.value = 0; + if (ledStatus != CurrentLedStatus) { + + if (SYNO_LED_OFF == ledStatus) { + pin.value = DISK_LED_CTRL_OFF; + } else if (SYNO_LED_ON == ledStatus) { + pin.value = DISK_LED_CTRL_ON; + } else { + goto END; + } + SetGpioPin(&pin); + + CurrentLedStatus = ledStatus; + } + iRet = syno_valid_lsi3008_led(ledStatus); + +END: + return iRet; +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +int BroadwellntbapGetPowerStatus(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + u16 data = 0; + + err = linuxI2CSmbusRegRead(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, PSU_DELTA_800AB_I2C_REG, &data); + + if (0 != err) { + printk("%s:%d return error:%d!\n", __FILE__, __LINE__, err); + goto FAIL; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + + // we have known sa3200d and sa3400d have two power supplies. + power1_Value = data & 0x1; + power2_Value = data & 0x2; + + if (power1_Value) { + snprintf(psu_status[0].sensor[0].value, MAX_SENSOR_VALUE, "%s", "psu good"); + } else { + snprintf(psu_status[0].sensor[0].value, MAX_SENSOR_VALUE, "%s", "psu off"); + } + + if (power2_Value) { + snprintf(psu_status[1].sensor[0].value, MAX_SENSOR_VALUE, "%s", "psu good"); + } else { + snprintf(psu_status[1].sensor[0].value, MAX_SENSOR_VALUE, "%s", "psu off"); + } + err = 0; + +FAIL: + return err; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .set_ok_to_remove_led = NULL, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + + giDiskLedController = BROADWELLNTBAP_DISK_LED_ACTIVATE_PIN; + + switch(GetModel()) + { + case MODEL_SA3200d: + model_ops = &sa3200d_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = SynoSetSasAllLed; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + synobios_ops.set_ok_to_remove_led = SetOkToRemoveLeD; + break; + case MODEL_SA3400d: + model_ops = &sa3400d_ops; + hwmon_sensor_list = &sa3400d_sensor_list; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led) { + synobios_ops.set_hdd_led = SynoSetSasAllLed; + } +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + synobios_ops.set_ok_to_remove_led = SetOkToRemoveLeD; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + synobios_ops.hwmon_get_psu_status = BroadwellntbapGetPowerStatus; + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + diff --git a/drivers/syno/synobios/broadwellntbap/broadwellntbap_common.h b/drivers/syno/synobios/broadwellntbap/broadwellntbap_common.h new file mode 100644 index 000000000000..a3267f53ba60 --- /dev/null +++ b/drivers/syno/synobios/broadwellntbap/broadwellntbap_common.h @@ -0,0 +1,83 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops sa3200d_ops; +extern struct model_ops sa3400d_ops; + +extern struct hwmon_sensor_list sa3400d_sensor_list; + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +extern int syno_ttys_write(const int index, const char* szBuf); +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + +#define BROADWELLNTBAP_POWER1_PIN 50 +#define BROADWELLNTBAP_POWER2_PIN 54 +#define BROADWELLNTBAP_BUZZER_OFF_PIN 2 +#define BROADWELLNTBAP_BUZZER_CTRL_PIN 3 +#define BROADWELLNTBAP_ALARM_LED_PIN 28 +#define BROADWELLNTBAP_DISK_LED_ACTIVATE_PIN 45 +#define BROADWELLNTBAP_REMOTE_LED_GPIO_PIN 32 + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x64 +#define PSU_DELTA_800AB_I2C_REG 0x20 + +#define DISK_LED_CTRL_ON 0 +#define DISK_LED_CTRL_OFF 1 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/broadwellntbap/sa3200d.c b/drivers/syno/synobios/broadwellntbap/sa3200d.c new file mode 100644 index 000000000000..e1d1409a8d3c --- /dev/null +++ b/drivers/syno/synobios/broadwellntbap/sa3200d.c @@ -0,0 +1,40 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellntbap_common.h" + +// extern function from broadwellntbap_common +extern int BroadwellntbapRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int SA3200dInitModuleType(struct synobios_ops *ops) +{ + module_t type_sa3200d = MODULE_T_SA3200d; + module_t *pType = &type_sa3200d; + GPIO_PIN Pin; + + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNTBAP_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + module_type_set(pType); + return 0; +} + +struct model_ops sa3200d_ops = { + .x86_init_module_type = SA3200dInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellntbapRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/broadwellntbap/sa3400d.c b/drivers/syno/synobios/broadwellntbap/sa3400d.c new file mode 100755 index 000000000000..bdb4522a810a --- /dev/null +++ b/drivers/syno/synobios/broadwellntbap/sa3400d.c @@ -0,0 +1,117 @@ +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "broadwellntbap_common.h" + +// extern function from broadwellntbap_common +extern int BroadwellntbapRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int SA3400dInitModuleType(struct synobios_ops *ops) +{ + module_t type_sa3400d = MODULE_T_SA3400d; + module_t *pType = &type_sa3400d; + GPIO_PIN Pin; + + if (ops && ops->set_gpio_pin) { + Pin.pin = BROADWELLNTBAP_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE SA3400d_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3400d_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3400d_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA3400d_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +struct model_ops sa3400d_ops = { + .x86_init_module_type = SA3400dInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BroadwellntbapRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list sa3400d_sensor_list = { + .thermal_sensor = &SA3400d_thermal_sensor, + .voltage_sensor = &SA3400d_voltage_sensor, + .fan_speed_rpm = &SA3400d_fan_speed_rpm, + .psu_status = SA3400d_psu_status, + // SA3400D does not support the backplane monitor + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/Makefile b/drivers/syno/synobios/bromolow/Makefile new file mode 100644 index 000000000000..106e245c1d68 --- /dev/null +++ b/drivers/syno/synobios/bromolow/Makefile @@ -0,0 +1,29 @@ +include /env.mak + +obj-m += bromolow-synobios.o + +bromolow-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs3412rpxs.o \ + rs3412xs.o \ + ds3612xs.o \ + ds3615xs.o \ + rs3411rpxs.o \ + rs3411xs.o \ + ds3611xs.o \ + rs10613xs+.o \ + rs3413xs+.o \ + rs3614xs.o \ + rs3614rpxs.o \ + rs3614xs+.o \ + ds2414xs.o \ + rs3415xs+.o \ + rc18015xs+.o \ + rs18016xs+.o \ + rs3617xs.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + bromolow_common.o diff --git a/drivers/syno/synobios/bromolow/bromolow_common.c b/drivers/syno/synobios/bromolow/bromolow_common.c new file mode 100755 index 000000000000..e25ec0a4ef4d --- /dev/null +++ b/drivers/syno/synobios/bromolow/bromolow_common.c @@ -0,0 +1,1226 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "bromolow_common.h" + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif +static int giHALedGreenPin = -1; +static int giHALedOrangePin = -1; +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +/** + * Set Max internal disk numbers + */ +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_RS3411rpxs: + case MODEL_RS3412rpxs: + case MODEL_RS3413xsp: /* RS3413xs is an RP model*/ + case MODEL_RS3415xsp: /* RS3415xs is an RP model*/ + iMaxInternalDiskNum = 10; + break; + case MODEL_RS3411xs: + case MODEL_RS3412xs: + iMaxInternalDiskNum = 10; + break; + case MODEL_DS3611xs: + case MODEL_DS3612xs: + case MODEL_DS3615xs: + case MODEL_RS3614xs: + case MODEL_RS3614rpxs: + case MODEL_RS3614xsp: + case MODEL_DS2414xs: + case MODEL_RS18016xsp: + case MODEL_RS3617xs: + iMaxInternalDiskNum = 12; + break; + case MODEL_RS10613xsp: + iMaxInternalDiskNum = 10; + break; + } + return iMaxInternalDiskNum; +} + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +// following functions are not chagned in any bromolow models, so we move them from model.o to here +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = BROMOLOW_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = BROMOLOW_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1_Value = 0, power2_Value = 0; + + if ( 0 != syno_pch_lpc_gpio_pin(BROMOLOW_POWER1_PIN , &power1_Value, 0) ) { + goto FAIL; + } + + if ( 0 != syno_pch_lpc_gpio_pin(BROMOLOW_POWER2_PIN , &power2_Value, 0) ) { + goto FAIL; + } + + if (power1_Value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + }else{ + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2_Value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + }else{ + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {1,6,7,68}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + GPIO_PIN gpiopin; + int rgcVolt[2] = {0, 0}; + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + + gpiopin.pin = gpio_fan_map[fanno-1]; + + do { + GetGpioPin(&gpiopin); + if (!gpiopin.value) { + rgcVolt[0]++; + } else { + rgcVolt[1]++; + } + + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ( (rgcVolt[0] + rgcVolt[1]) < 200 ); + + if (rgcVolt[0] == 0) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + return 0; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_CPUFAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( NULL == model_ops->x86_cpufan_speed_mapping ) { + goto END; + } else if( 0 > (iFanDuty = model_ops->x86_cpufan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_CPUFAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_RS3411rpxs; + + if ( !strncmp(gszSynoHWVersion, HW_RS3411rpxs, strlen(HW_RS3411rpxs) ) ) { + model = MODEL_RS3411rpxs; + }else if (!strncmp(gszSynoHWVersion, HW_RS3411xs, strlen(HW_RS3411xs) ) ) { + model = MODEL_RS3411xs; + }else if (!strncmp(gszSynoHWVersion, HW_DS3611xs, strlen(HW_DS3611xs) ) ) { + model = MODEL_DS3611xs; + } else if ( !strncmp(gszSynoHWVersion, HW_RS3412rpxs, strlen(HW_RS3412rpxs) ) ) { + model = MODEL_RS3412rpxs; + }else if (!strncmp(gszSynoHWVersion, HW_RS3412xs, strlen(HW_RS3412xs) ) ) { + model = MODEL_RS3412xs; + }else if (!strncmp(gszSynoHWVersion, HW_DS3612xs, strlen(HW_DS3612xs) ) ) { + model = MODEL_DS3612xs; + }else if (!strncmp(gszSynoHWVersion, HW_DS3615xs, strlen(HW_DS3615xs) ) ) { + model = MODEL_DS3615xs; + }else if (!strncmp(gszSynoHWVersion, HW_RS10613xsp, strlen(HW_RS10613xsp) ) ) { + model = MODEL_RS10613xsp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS3413xsp, strlen(HW_RS3413xsp) ) ) { + model = MODEL_RS3413xsp; + }else if (!strncmp(gszSynoHWVersion, HW_RS3614xsp, strlen(HW_RS3614xsp) ) ) { + model = MODEL_RS3614xsp; + }else if (!strncmp(gszSynoHWVersion, HW_RS3614xs, strlen(HW_RS3614xs) ) ) { + model = MODEL_RS3614xs; + }else if (!strncmp(gszSynoHWVersion, HW_RS3614rpxs, strlen(HW_RS3614rpxs) ) ) { + model = MODEL_RS3614rpxs; + }else if (!strncmp(gszSynoHWVersion, HW_DS2414xs, strlen(HW_DS2414xs) ) ) { + model = MODEL_DS2414xs; + }else if (!strncmp(gszSynoHWVersion, HW_RS3415xsp, strlen(HW_RS3415xsp) ) ) { + model = MODEL_RS3415xsp; + }else if (!strncmp(gszSynoHWVersion, HW_RC18015xsp, strlen(HW_RC18015xsp) ) ) { + model = MODEL_RC18015xsp; + }else if (!strncmp(gszSynoHWVersion, HW_RS18016xsp, strlen(HW_RS18016xsp) ) ) { + model = MODEL_RS18016xsp; + }else if (!strncmp(gszSynoHWVersion, HW_RS3617xs, strlen(HW_RS3617xs) ) ) { + model = MODEL_RS3617xs; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( pPin->pin < 100 ) { + if ( 0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1) ) { + goto End; + } + } else { +#ifdef MY_DEF_HERE + if ( 0 != syno_superio_gpio_pin((int)pPin->pin - 100, (int*)&pPin->value, 1) ) { + goto End; + } +#else /*MY_DEF_HERE*/ + goto End; +#endif /*MY_DEF_HERE*/ + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( pPin->pin < 100 ) { + if ( 0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0) ) { + goto End; + } + } else { +#ifdef MY_DEF_HERE + if ( 0 != syno_superio_gpio_pin((int)pPin->pin - 100, (int*)&pPin->value, 0) ) { + goto End; + } +#else /*MY_DEF_HERE*/ + goto End; +#endif /*MY_DEF_HERE*/ + } + + ret = 0; +End: + return ret; +} + +#ifdef MY_DEF_HERE +static +int SetSCSIHostLedStatusBySataMvGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int iWrite = -1; + int iRead = -1; + + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status) { + iWrite = 1; + } else { + iWrite = 0; + } + syno_sata_mv_gpio_write(iWrite, iHostNum); + + iRead = syno_sata_mv_gpio_read(iHostNum); +#ifdef MY_DEF_HERE + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } +#endif /* MY_DEF_HERE */ + + return 0; +} +/*FIXME - Too brutal and directly, should separate into levels*/ +static +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + if (GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if(!gblDiskNumNeedTran) { + /*Scsi host in kernel is zero-based, disknum here is one-based, + *so we should minus 1 while calling the function + */ + SetSCSIHostLedStatusBySataMvGPIO(disknum - 1, status); + }else{ + /* DS3611xs/DS3612xs and RS3411(rp)xs/RS3412(rp)xs have different disk sequences, + * when the cmd is performed on these two models, the disk numbers + * need to be transferred by the corresponding table. + */ + SetSCSIHostLedStatusBySataMvGPIO(giDiskMapTable[disknum - 1], status); + } + + err = 0; +END: + return err; +} +#endif /* MY_DEF_HERE */ + +static int giDiskLedController = -1; + +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void InitSynoDiskLed(void) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + pin.value = 0; + SetGpioPin(&pin); +} + +#ifdef MY_DEF_HERE +/** + * Set disk led via scsi host sysfs interface + */ +static +int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret; + static int diskLedEnabled = 0; + int iWrite = -1; + int iRead = -1; + + // first time we tried to light on disk led + if (!diskLedEnabled && status != DISK_LED_OFF) { + InitSynoDiskLed(); + diskLedEnabled = 1; + } + + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status) { + iWrite = 1; + } else { + iWrite = 0; + } + ret = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + iRead = syno_mv_9235_disk_led_get(iHostNum); + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } + + return ret; +} + +/* Set disk led via 9235 */ +static +int SetDiskLedStatusBy9235GPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + if (GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if(!gblDiskNumNeedTran) { + err = SetSCSIHostLedStatusBy9235GPIO(disknum - 1, status); + }else{ + err = SetSCSIHostLedStatusBy9235GPIO(giDiskMapTable[disknum - 1], status); + } +END: + return err; +} +#endif /* MY_DEF_HERE */ + +/** + * Control disk led via AHCI SGPIO + */ +static +int SetSCSIHostLedStatusByAHCIGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret = -1; + int iFault, iPresent; + + switch(status) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + iFault = 1; + iPresent = 0; + break; + case DISK_LED_GREEN_SOLID: + iFault = 0; + iPresent = 1; + break; + case DISK_LED_OFF: + iFault = 0; + iPresent = 0; + break; + default: + printk("Invalid LED status [%d]\n", status); + goto END; + } +#ifdef MY_DEF_HERE + sata_syno_ahci_diskled_set(iHostNum, iPresent, iFault); +#else + printk(KERN_ERR "SYNO ATA AHCI DISK LED control function is not defined!!"); +#endif /* MY_DEF_HERE */ + ret = 0; +END: + return ret; +} + +#ifdef MY_DEF_HERE +/** + * The RS3614xs, RS3614rpxs, RS3415xs+, DS3615xs control their disk led over ahci SGPIO + * The way of controlling SGPIO is the same as Cedarview + */ +static +int SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret; + int iWrite = -1, iRead = -1; + int iInternalHost =0; + static int diskLedEnabled = 0; + + // first time we tried to light on disk led + if (!diskLedEnabled && status != DISK_LED_OFF) { + InitSynoDiskLed(); + diskLedEnabled = 1; + } + + switch(GetModel()) + { + case MODEL_RS3614rpxs: + case MODEL_RS3614xs: + iInternalHost = 3; + break; + case MODEL_RS3415xsp: + iInternalHost = 2; + break; + case MODEL_DS3615xs: + iInternalHost = 6; + break; + default: + iInternalHost = 0; + break; + } + + if (iHostNum < iInternalHost) { + ret = SetSCSIHostLedStatusByAHCIGPIO(iHostNum, status);; + } else { + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status) { + iWrite = 1; + } else { + iWrite = 0; + } + ret = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + iRead = syno_mv_9235_disk_led_get(iHostNum); + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } + } + return ret; +} + +/** + * Set disk led status for RS3614rpxs, RS3614xs, RS3415xs+ and DS3615xs + */ +static +int SetDiskLedStatusBy9235GPIOandAHCISGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + if (GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if(!gblDiskNumNeedTran) { + err = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(disknum - 1, status); + }else{ + err = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(giDiskMapTable[disknum - 1], status); + } +END: + return err; +} + +#endif /* MY_DEF_HERE */ + +/** + * Set disk led for DS2414, the first 6 disks use internal ahci, the last 6 use sata mv + */ +static +int SetSCSIHostLedStatusBySataMvandAHCISGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret; + int iWrite = -1, iRead = -1; + static int diskLedEnabled = 0; + + // first time we tried to light on disk led + if (!diskLedEnabled && status != DISK_LED_OFF) { + InitSynoDiskLed(); + diskLedEnabled = 1; + } + + if (iHostNum < 6) { + ret = SetSCSIHostLedStatusByAHCIGPIO(iHostNum, status); + } else { + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status) { + iWrite = 1; + } else { + iWrite = 0; + } +#ifdef MY_DEF_HERE + syno_sata_mv_gpio_write(iWrite, iHostNum); + + iRead = syno_sata_mv_gpio_read(iHostNum); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } +#endif /*MY_DEF_HERE*/ + ret = 0; + } + return ret; +} + +/** + * Set disk led for DS2414, the first 6 disks use internal ahci, the last 6 use sata mv + */ +static +int SetDiskLedStatusBySataMvandAHCISGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + if (GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if(!gblDiskNumNeedTran) { + err = SetSCSIHostLedStatusBySataMvandAHCISGPIO(disknum - 1, status); + }else{ + err = SetSCSIHostLedStatusBySataMvandAHCISGPIO(giDiskMapTable[disknum - 1], status); + } +END: + return err; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int GetCpuTemperatureDenlowI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 10 - 264) / 10; // cpu temperature adjust -26.4 degree + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +/** + * Set HA active led via GPIO + * + * @param ops synobios operation set + * @param ledStatus type of led status + * @return 0 if succeed + * -1 if error + */ +static int SetHALedByGPIO(struct synobios_ops *ops, SYNO_AHA_LED ledStatus) +{ + GPIO_PIN greenLedPin, orangeLedPin; + + if (!ops || !ops->set_gpio_pin || -1 == giHALedGreenPin || -1 == giHALedOrangePin) { + return -1; + } + + greenLedPin.pin = giHALedGreenPin; + orangeLedPin.pin = giHALedOrangePin; + + switch (ledStatus) { + case AHA_LED_OFF: + greenLedPin.value = 0; + orangeLedPin.value = 0; + break; + case AHA_LED_GREEN_SOLID: + greenLedPin.value = 1; + orangeLedPin.value = 0; + break; + case AHA_LED_ORANGE_SOLID: + greenLedPin.value = 0; + orangeLedPin.value = 1; + break; + default: + printk("Unknown ha led type\n"); + break; + } + + ops->set_gpio_pin(&greenLedPin); + ops->set_gpio_pin(&orangeLedPin); + return 0; +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, +#ifdef MY_DEF_HERE + .set_disk_led = SetDiskLedStatusBySataMvGPIO, +#else + .set_disk_led = NULL, +#endif + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = CheckMicropId, + .set_microp_id = SetMicropId, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + if ( 0 > syno_libata_disk_map_table_gen(giDiskMapTable)) { + gblDiskNumNeedTran = 0; + } else { + gblDiskNumNeedTran = 1; + } +#endif + +#ifdef MY_DEF_HERE +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBySataMvGPIO; +#endif /* MY_DEF_HERE */ +#endif + switch(GetModel()) + { + case MODEL_RC18015xsp: + model_ops = &rc18015xsp_ops; + synobios_ops.set_disk_led = NULL; + giHALedGreenPin = 21; + giHALedOrangePin = 16; + synobios_ops.set_aha_led = SetHALedByGPIO; + hwmon_sensor_list = &rc18015xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS18016xsp: + model_ops = &rs18016xsp_ops; + // SAS model has different disk led control mechanism, it via SES service + // so we don't hook any function pointer here + synobios_ops.set_disk_led = NULL; + hwmon_sensor_list = &rs18016xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS3411rpxs: + model_ops = &rs3411rpxs_ops; + break; + case MODEL_RS3411xs: + model_ops = &rs3411xs_ops; + break; + case MODEL_DS3611xs: + model_ops = &ds3611xs_ops; + break; + case MODEL_RS3412rpxs: + model_ops = &rs3412rpxs_ops; + break; + case MODEL_RS3412xs: + model_ops = &rs3412xs_ops; + break; + case MODEL_DS3612xs: + model_ops = &ds3612xs_ops; + break; + case MODEL_DS3615xs: + model_ops = &ds3615xs_ops; + synobios_ops.get_fan_status = NULL; + synobios_ops.get_cpu_temperature = GetCpuTemperatureDenlowI3Transfer; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIOandAHCISGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO; +#endif // MY_DEF_HERE +#endif // MY_DEF_HERE + giDiskLedController = DENLOW_DISK_LED_ACTIVATE_PIN; + hwmon_sensor_list = &ds3615xs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS10613xsp: + model_ops = &rs10613xsp_ops; + // SAS model has different disk led control mechanism, it via SES service + // so we don't hook any function pointer here + synobios_ops.set_disk_led = NULL; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = NULL; +#endif + break; + case MODEL_RS3413xsp: + model_ops = &rs3413xsp_ops; + break; + case MODEL_RS3614xs: + model_ops = &rs3614xs_ops; + synobios_ops.get_fan_status = NULL; + synobios_ops.get_cpu_temperature = GetCpuTemperatureDenlowI3Transfer; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIOandAHCISGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + giDiskLedController = DENLOW_DISK_LED_ACTIVATE_PIN; + hwmon_sensor_list = &rs3614xs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS3614rpxs: + model_ops = &rs3614rpxs_ops; + synobios_ops.get_fan_status = NULL; + synobios_ops.get_cpu_temperature = GetCpuTemperatureDenlowI3Transfer; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIOandAHCISGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + giDiskLedController = DENLOW_DISK_LED_ACTIVATE_PIN; + hwmon_sensor_list = &rs3614rpxs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_RS3614xsp: + model_ops = &rs3614xsp_ops; + synobios_ops.get_fan_status = NULL; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + giDiskLedController = IVYBRIDGE_DISK_LED_ACTIVATE_PIN; + hwmon_sensor_list = &rs3614xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + case MODEL_DS2414xs: + model_ops = &ds2414xs_ops; + synobios_ops.set_disk_led = SetDiskLedStatusBySataMvandAHCISGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBySataMvandAHCISGPIO; +#endif /* MY_DEF_HERE */ + giDiskLedController = DENLOW_DISK_LED_ACTIVATE_PIN; + break; + case MODEL_RS3415xsp: + model_ops = &rs3415xsp_ops; + synobios_ops.get_fan_status = NULL; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + giDiskLedController = IVYBRIDGE_DISK_LED_ACTIVATE_PIN; + break; + case MODEL_RS3617xs: + model_ops = &rs3617xs_ops; + synobios_ops.get_fan_status = NULL; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + giDiskLedController = IVYBRIDGE_DISK_LED_ACTIVATE_PIN; + hwmon_sensor_list = &rs3617xs_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/bromolow/bromolow_common.h b/drivers/syno/synobios/bromolow/bromolow_common.h new file mode 100755 index 000000000000..9775c19a1811 --- /dev/null +++ b/drivers/syno/synobios/bromolow/bromolow_common.h @@ -0,0 +1,103 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops rs3411rpxs_ops; +extern struct model_ops rs3411xs_ops; +extern struct model_ops rs10613xsp_ops; +extern struct model_ops rc18015xsp_ops; +extern struct model_ops ds3611xs_ops; +extern struct model_ops rs3412rpxs_ops; +extern struct model_ops rs3412xs_ops; +extern struct model_ops ds3612xs_ops; +extern struct model_ops ds3615xs_ops; +extern struct model_ops rs3413xsp_ops; +extern struct model_ops rs3614xs_ops; +extern struct model_ops rs3614rpxs_ops; +extern struct model_ops rs3614xsp_ops; +extern struct model_ops ds2414xs_ops; +extern struct model_ops rs3415xsp_ops; +extern struct model_ops rs18016xsp_ops; +extern struct model_ops rs3617xs_ops; + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef MY_DEF_HERE +extern u32 syno_superio_gpio_pin(int pin, int *pValue, int isWrite); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list ds3615xs_sensor_list; +extern struct hwmon_sensor_list rc18015xsp_sensor_list; +extern struct hwmon_sensor_list rs18016xsp_sensor_list; +extern struct hwmon_sensor_list rs3614rpxs_sensor_list; +extern struct hwmon_sensor_list rs3614xsp_sensor_list; +extern struct hwmon_sensor_list rs3614xs_sensor_list; +extern struct hwmon_sensor_list rs3617xs_sensor_list; + +#define BROMOLOW_POWER1_PIN 2 +#define BROMOLOW_POWER2_PIN 3 +#define BROMOLOW_BUZZER_OFF_PIN 4 +#define BROMOLOW_BUZZER_CTRL_PIN 5 +#define IVYBRIDGE_DISK_LED_ACTIVATE_PIN 0 +#define DENLOW_DISK_LED_ACTIVATE_PIN 45 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +extern int syno_sata_mv_gpio_read(const unsigned short hostnum); + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +extern int syno_libata_disk_map_table_gen(int *iDiskMapTable); +#endif + +#endif +#ifdef MY_DEF_HERE +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +extern int syno_mv_9235_disk_led_get(const unsigned short hostnum); +#endif +#ifdef MY_DEF_HERE +extern void sata_syno_ahci_diskled_set(int iHostNum, int iPresent, int iFault); +#endif + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/bromolow/ds2414xs.c b/drivers/syno/synobios/bromolow/ds2414xs.c new file mode 100644 index 000000000000..b951865de873 --- /dev/null +++ b/drivers/syno/synobios/bromolow/ds2414xs.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int DS2414xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_DS2414xs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +struct model_ops ds2414xs_ops = { + .x86_init_module_type = DS2414xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/bromolow/ds3611xs.c b/drivers/syno/synobios/bromolow/ds3611xs.c new file mode 100644 index 000000000000..9d967076bff4 --- /dev/null +++ b/drivers/syno/synobios/bromolow/ds3611xs.c @@ -0,0 +1,32 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int DS3611xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_DS3611xs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +struct model_ops ds3611xs_ops = { + .x86_init_module_type = DS3611xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/bromolow/ds3612xs.c b/drivers/syno/synobios/bromolow/ds3612xs.c new file mode 100644 index 000000000000..674eb94bde84 --- /dev/null +++ b/drivers/syno/synobios/bromolow/ds3612xs.c @@ -0,0 +1,32 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int DS3612xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_DS3612xs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +struct model_ops ds3612xs_ops = { + .x86_init_module_type = DS3612xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/bromolow/ds3615xs.c b/drivers/syno/synobios/bromolow/ds3615xs.c new file mode 100644 index 000000000000..b27c83038bd3 --- /dev/null +++ b/drivers/syno/synobios/bromolow/ds3615xs.c @@ -0,0 +1,85 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int DS3615xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_DS3615xs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE DS3615xs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3615xs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS3615xs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +struct model_ops ds3615xs_ops = { + .x86_init_module_type = DS3615xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; + +struct hwmon_sensor_list ds3615xs_sensor_list = { + .thermal_sensor = &DS3615xs_thermal_sensor, + .voltage_sensor = &DS3615xs_voltage_sensor, + .fan_speed_rpm = &DS3615xs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/es3614xs+.c b/drivers/syno/synobios/bromolow/es3614xs+.c new file mode 100644 index 000000000000..ede7694e6191 --- /dev/null +++ b/drivers/syno/synobios/bromolow/es3614xs+.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int ES3614xspInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_ES3614xsp; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +struct model_ops es3614xsp_ops = { + .x86_init_module_type = ES3614xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/bromolow/rc18015xs+.c b/drivers/syno/synobios/bromolow/rc18015xs+.c new file mode 100644 index 000000000000..28584dfd655c --- /dev/null +++ b/drivers/syno/synobios/bromolow/rc18015xs+.c @@ -0,0 +1,114 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int RC18015xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rc18015xsp = MODULE_T_RC18015xsp; + module_t *pType = &type_rc18015xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RC18015xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "ADT1 Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, + .sensor[3] = { + .sensor_name = "ADT2 Local", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RC18015xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 6, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "ADT1 V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, + .sensor[5] = { + .sensor_name = "ADT2 V33", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RC18015xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 6, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, + .sensor[4] = { + .sensor_name = HWMON_SYS_FAN5_RPM, + }, + .sensor[5] = { + .sensor_name = HWMON_SYS_FAN6_RPM, + }, +}; + +struct model_ops rc18015xsp_ops = { + .x86_init_module_type = RC18015xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rc18015xsp_sensor_list = { + .thermal_sensor = &RC18015xsp_thermal_sensor, + .voltage_sensor = &RC18015xsp_voltage_sensor, + .fan_speed_rpm = &RC18015xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/rs10613xs+.c b/drivers/syno/synobios/bromolow/rs10613xs+.c new file mode 100644 index 000000000000..93e0dd7b04ca --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs10613xs+.c @@ -0,0 +1,43 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS10613xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs10613xsp = MODULE_T_RS10613xsp; + module_t *pType = &type_rs10613xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs10613xsp_ops = { + .x86_init_module_type = RS10613xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/bromolow/rs18016xs+.c b/drivers/syno/synobios/bromolow/rs18016xs+.c new file mode 100644 index 000000000000..a1df57ba9995 --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs18016xs+.c @@ -0,0 +1,102 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int RS18016xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs18016xsp = MODULE_T_RS18016xsp; + module_t *pType = &type_rs18016xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RS18016xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS18016xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS18016xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops rs18016xsp_ops = { + .x86_init_module_type = RS18016xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs18016xsp_sensor_list = { + .thermal_sensor = &RS18016xsp_thermal_sensor, + .voltage_sensor = &RS18016xsp_voltage_sensor, + .fan_speed_rpm = &RS18016xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/rs3411rpxs.c b/drivers/syno/synobios/bromolow/rs3411rpxs.c new file mode 100644 index 000000000000..c9dc13b3cc23 --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3411rpxs.c @@ -0,0 +1,41 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int RS3411rpxsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3411rpxs; + module_t *pType = &type; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3411rpxs_ops = { + .x86_init_module_type = RS3411rpxsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/bromolow/rs3411xs.c b/drivers/syno/synobios/bromolow/rs3411xs.c new file mode 100644 index 000000000000..fd3bbf1f0a8f --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3411xs.c @@ -0,0 +1,41 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int RS3411xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3411xs; + module_t *pType = &type; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3411xs_ops = { + .x86_init_module_type = RS3411xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/bromolow/rs3412rpxs.c b/drivers/syno/synobios/bromolow/rs3412rpxs.c new file mode 100644 index 000000000000..75f0957fa206 --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3412rpxs.c @@ -0,0 +1,41 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int RS3412rpxsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3412rpxs; + module_t *pType = &type; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3412rpxs_ops = { + .x86_init_module_type = RS3412rpxsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/bromolow/rs3412xs.c b/drivers/syno/synobios/bromolow/rs3412xs.c new file mode 100644 index 000000000000..3b165c52930e --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3412xs.c @@ -0,0 +1,41 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int RS3412xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3412xs; + module_t *pType = &type; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3412xs_ops = { + .x86_init_module_type = RS3412xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, +}; diff --git a/drivers/syno/synobios/bromolow/rs3413xs+.c b/drivers/syno/synobios/bromolow/rs3413xs+.c new file mode 100644 index 000000000000..de1babb18daf --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3413xs+.c @@ -0,0 +1,43 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS3413xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs3413xsp = MODULE_T_RS3413xsp; + module_t *pType = &type_rs3413xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power or lcd panel then poweron, + * It may cause gpio 5 set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = 5; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs3413xsp_ops = { + .x86_init_module_type = RS3413xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/bromolow/rs3415xs+.c b/drivers/syno/synobios/bromolow/rs3415xs+.c new file mode 100644 index 000000000000..2c133fda68eb --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3415xs+.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2014 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS3415xspInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3415xsp; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +struct model_ops rs3415xsp_ops = { + .x86_init_module_type = RS3415xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/bromolow/rs3614rpxs.c b/drivers/syno/synobios/bromolow/rs3614rpxs.c new file mode 100644 index 000000000000..9028cda7cb42 --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3614rpxs.c @@ -0,0 +1,93 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS3614rpxsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3614rpxs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RS3614rpxs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3614rpxs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3614rpxs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops rs3614rpxs_ops = { + .x86_init_module_type = RS3614rpxsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3614rpxs_sensor_list = { + .thermal_sensor = &RS3614rpxs_thermal_sensor, + .voltage_sensor = &RS3614rpxs_voltage_sensor, + .fan_speed_rpm = &RS3614rpxs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/rs3614xs+.c b/drivers/syno/synobios/bromolow/rs3614xs+.c new file mode 100644 index 000000000000..f741150ec234 --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3614xs+.c @@ -0,0 +1,93 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS3614xspInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3614xsp; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RS3614xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3614xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3614xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops rs3614xsp_ops = { + .x86_init_module_type = RS3614xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3614xsp_sensor_list = { + .thermal_sensor = &RS3614xsp_thermal_sensor, + .voltage_sensor = &RS3614xsp_voltage_sensor, + .fan_speed_rpm = &RS3614xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/rs3614xs.c b/drivers/syno/synobios/bromolow/rs3614xs.c new file mode 100644 index 000000000000..fc8d45d8246a --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3614xs.c @@ -0,0 +1,93 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS3614xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3614xs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RS3614xs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3614xs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3614xs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops rs3614xs_ops = { + .x86_init_module_type = RS3614xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3614xs_sensor_list = { + .thermal_sensor = &RS3614xs_thermal_sensor, + .voltage_sensor = &RS3614xs_voltage_sensor, + .fan_speed_rpm = &RS3614xs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/bromolow/rs3617xs.c b/drivers/syno/synobios/bromolow/rs3617xs.c new file mode 100644 index 000000000000..bea9c12d9258 --- /dev/null +++ b/drivers/syno/synobios/bromolow/rs3617xs.c @@ -0,0 +1,93 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "bromolow_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsFanSpeedMapping(FAN_SPEED speed); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); + +static +int RS3617xsInitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_RS3617xs; + module_t *pType = &type; + + module_type_set(pType); + return 0; +} + +SYNO_HWMON_SENSOR_TYPE RS3617xs_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3617xs_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS3617xs_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +struct model_ops rs3617xs_ops = { + .x86_init_module_type = RS3617xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list rs3617xs_sensor_list = { + .thermal_sensor = &RS3617xs_thermal_sensor, + .voltage_sensor = &RS3617xs_voltage_sensor, + .fan_speed_rpm = &RS3617xs_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/cedarview/Makefile b/drivers/syno/synobios/cedarview/Makefile new file mode 100644 index 000000000000..c07a66d5daa6 --- /dev/null +++ b/drivers/syno/synobios/cedarview/Makefile @@ -0,0 +1,28 @@ +include /env.mak + +obj-m += cedarview-synobios.o + +cedarview-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds1512+.o \ + ds1513+.o \ + ds412+.o \ + rs812+.o \ + rs812rp+.o \ + rs814+.o \ + rs814rp+.o \ + ds1812+.o \ + ds1813+.o \ + rs2212+.o \ + rs2212rp+.o \ + rs2414+.o \ + rs2414rp+.o \ + ds2413+.o \ + ds713+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + cedarview_common.o diff --git a/drivers/syno/synobios/cedarview/cedarview_common.c b/drivers/syno/synobios/cedarview/cedarview_common.c new file mode 100755 index 000000000000..ac4638d55696 --- /dev/null +++ b/drivers/syno/synobios/cedarview/cedarview_common.c @@ -0,0 +1,1340 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" + +#include "cedarview_common.h" + +#ifdef MY_DEF_HERE +extern void sata_syno_ahci_diskled_set(int iHostNum, int iPresent, int iFault); + +#ifdef SYNO_ATA_AHCI_LED_SWITCH +#ifndef SYNO_MAX_INTERNAL_DISK /* TODO XXX REMOVE MEEEEEEEEE */ +#define SYNO_MAX_INTERNAL_DISK 19 +#endif +extern int giSynoHddLedEnabled; +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +extern atomic_t ata_print_id; +#else /* SYNO_HAVE_KERNEL_VERSION(3,10,0) */ +extern unsigned int ata_print_id; +#endif /* SYNO_HAVE_KERNEL_VERSION(3,10,0) */ +SYNO_DISK_LED gDiskOrgStatus[SYNO_MAX_INTERNAL_DISK] = {0}; +#endif + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#define DS1812P_INTERNAL_DISK_NUM 8 +#define DS1813P_INTERNAL_DISK_NUM 8 +#define DS1513P_INTERNAL_DISK_NUM 5 +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +extern char gszSynoHWRevision[4]; +#endif + +#ifdef SYNO_E1000E_LED_SWITCH +extern void (*funcSynoNicLedCtrl)(int iEnable); +#endif + +#ifdef MY_DEF_HERE +extern int syno_superio_regist_read(u8 ldn, u8 reg, u8 *value); +extern int syno_superio_regist_write(u8 ldn, u8 reg, u8 value); +#endif /*MY_DEF_HERE*/ + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); + +#define GPIO_POWER_GOOD 1 +int CedarviewRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + int power1value = 0, power2value = 0; + int gpio_rp_map[] = {27, 28}; + + if ( 0 != syno_pch_lpc_gpio_pin(gpio_rp_map[0] , &power1value, 0) ) { + goto FAIL; + } + + if ( 0 != syno_pch_lpc_gpio_pin(gpio_rp_map[1] , &power2value, 0) ) { + goto FAIL; + } + + if (power1value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + }else{ + power_info->power_1 = POWER_STATUS_BAD; + } + + if (power2value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + }else{ + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +FAIL: + return err; +} + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int* hdd_detect_gpio = NULL; +static int* hdd_enable_gpio = NULL; + +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS713p: + iMaxInternalDiskNum = 2; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +int GetFanStatusMircopWithGPIOCommon(const int pin, FAN_STATUS *pStatus) +{ + GPIO_PIN gpiopin; + int rgcVolt[2] = {0, 0}; + + if (pStatus == NULL) { + return -EINVAL; + } + + gpiopin.pin = pin; + + do { + GetGpioPin(&gpiopin); + if (!gpiopin.value) { + rgcVolt[0]++; + } else { + rgcVolt[1]++; + } + + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ( (rgcVolt[0] + rgcVolt[1]) < 200 ); + + if (rgcVolt[0] == 0) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + return 0; +} + +/* + * This function is used by all cedarview model except RS812+ + * due to the gpio mapping, RS812+ use it's own gpio defination + */ +int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {37, 36, 18, 30}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + GetFanStatusMircopWithGPIOCommon(gpio_fan_map[fanno-1], pStatus); + + return 0; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_get_fan_status) { + iRet = model_ops->x86_get_fan_status(fanno, pStatus); + } + + return iRet; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int i = 0; + GPIO_PIN Pin; + unsigned long hdd_detect_status = 0; + unsigned long hdd_enable_status = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list || (NULL == hdd_enable_gpio && NULL == hdd_detect_gpio)) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (i = 0; i < GetMaxInternalDiskNum(); i++) { + Pin.pin = hdd_enable_gpio[i]; + if (0 > GetGpioPin(&Pin)) { + goto End; + } + hdd_enable_status |= (Pin.value & 0x01) << i; + + Pin.pin = hdd_detect_gpio[i]; + if (0 > GetGpioPin(&Pin)) { + goto End; + } + hdd_detect_status |= (Pin.value & 0x01) << i; + } + + for (i = 0; i < hdd_backplane->sensor_num; i++) { + if (0 == strncmp(hdd_backplane->sensor[i].sensor_name, HWMON_HDD_BP_DETECT, strlen(HWMON_HDD_BP_DETECT))) { + snprintf(hdd_backplane->sensor[i].value, sizeof(hdd_backplane->sensor[i].value), "%ld", hdd_detect_status); + } else if (0 == strncmp(hdd_backplane->sensor[i].sensor_name, HWMON_HDD_BP_ENABLE, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[i].value, sizeof(hdd_backplane->sensor[i].value), "%ld", hdd_enable_status); + } + } + + iRet = 0; +End: + + return iRet; + +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_CPUFAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( NULL == model_ops->x86_cpufan_speed_mapping ) { + goto END; + } else if( 0 > (iFanDuty = model_ops->x86_cpufan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_CPUFAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_DS1512p; + + if ( !strncmp(gszSynoHWVersion, HW_DS1512p, strlen(HW_DS1512p) ) ) { + model = MODEL_DS1512p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1513p, strlen(HW_DS1513p) ) ) { + model = MODEL_DS1513p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS412p, strlen(HW_DS412p) ) ) { + model = MODEL_DS412p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS713p, strlen(HW_DS713p) ) ) { + model = MODEL_DS713p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS812p, strlen(HW_RS812p) ) ) { + model = MODEL_RS812p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS812rpp, strlen(HW_RS812rpp) ) ) { + model = MODEL_RS812rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS814p, strlen(HW_RS814p) ) ) { + model = MODEL_RS814p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS814rpp, strlen(HW_RS814rpp) ) ) { + model = MODEL_RS814rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1812p, strlen(HW_DS1812p) ) ) { + model = MODEL_DS1812p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1813p, strlen(HW_DS1813p) ) ) { + model = MODEL_DS1813p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2212p, strlen(HW_RS2212p) ) ) { + model = MODEL_RS2212p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2212rpp, strlen(HW_RS2212rpp) ) ) { + model = MODEL_RS2212rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2414p, strlen(HW_RS2414p) ) ) { + model = MODEL_RS2414p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2414rpp, strlen(HW_RS2414rpp) ) ) { + model = MODEL_RS2414rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_DS2413p, strlen(HW_DS2413p) ) ) { + model = MODEL_DS2413p; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( pPin->pin < 100 ) { + if ( 0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 1) ) { + goto End; + } + } else { +#ifdef MY_DEF_HERE + if ( 0 != syno_superio_gpio_pin((int)pPin->pin - 100, (int*)&pPin->value, 1) ) { + goto End; + } +#else /*MY_DEF_HERE*/ + goto End; +#endif /*MY_DEF_HERE*/ + } + + ret = 0; +End: + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if ( NULL == pPin ) { + goto End; + } + + if ( pPin->pin < 100 ) { + if ( 0 != syno_pch_lpc_gpio_pin((int)pPin->pin, (int*)&pPin->value, 0) ) { + goto End; + } + } else { +#ifdef MY_DEF_HERE + if ( 0 != syno_superio_gpio_pin((int)pPin->pin - 100, (int*)&pPin->value, 0) ) { + goto End; + } +#else /*MY_DEF_HERE*/ + goto End; +#endif /*MY_DEF_HERE*/ + } + + ret = 0; +End: + return ret; +} + +#ifdef MY_DEF_HERE +/*FIXME - Too brutal and directly, should separate into levels*/ +static +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + int iWrite = -1; + int iRead = -1; + + if (1 > disknum) { + goto END; + } + + /*Scsi host in kernel is zero-based, disknum here is one-based, + *so we should minus 1 while calling the function + */ + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status){ + iWrite = 1; + }else{ + iWrite = 0; + } + syno_sata_mv_gpio_write(iWrite, disknum - 1); + + iRead = syno_sata_mv_gpio_read(disknum - 1); +#ifdef MY_DEF_HERE + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } +#endif /* MY_DEF_HERE */ + err = 0; +END: + return err; +} +#endif /* MY_DEF_HERE */ +/* refactor function to group disk led status setting together + * pin1 & pin2 must set and pass as sequence + */ +static +int SetDiskLedGPIOPinValue(SYNO_DISK_LED iStatus, GPIO_PIN *Pin1, GPIO_PIN *Pin2) +{ + int err = -1; + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + Pin1->value = 0; + Pin2->value = 1; + break; + case DISK_LED_GREEN_SOLID: + Pin1->value = 1; + Pin2->value = 0; + break; + case DISK_LED_OFF: + Pin1->value = 0; + Pin2->value = 0; + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + err = 0; +END: + return err; +} + +#ifdef MY_DEF_HERE +/* this function is created for SATA disks which use ahci as its controller + * the LED control function will be different from other GPIO controlled disks + * before using this function, the iDiskNum must be checked + */ +static +int SetDiskLedStatusBySGPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int err = -1; + int iFault, iPresent; + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + iFault = 1; + iPresent = 0; + break; + case DISK_LED_GREEN_SOLID: + iFault = 0; + iPresent = 1; + break; + case DISK_LED_OFF: + iFault = 0; + iPresent = 0; + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + /* disknum in kernel space and user space are both 1-based. */ + sata_syno_ahci_diskled_set(iDiskNum -1, iPresent, iFault); + mdelay(100); + err = 0; + +END: + return err; +} + +/* DS1812+ use ahci & sil3132 as its internal disk controller + */ +static +int SetDiskLedStatusBySGPIOandGPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int err = -1; + GPIO_PIN Pin1, Pin2; + + if (0 > SetDiskLedGPIOPinValue(iStatus, &Pin1, &Pin2)) { + goto END; + } + + switch(iDiskNum) { + case 1 ... 6: + SetDiskLedStatusBySGPIO(iDiskNum, iStatus); + goto SGPIO_END; + case 7: + /* Disk 7 are set via gpio */ + Pin1.pin = SYNO_GPP_HDD7_LED_0; + Pin2.pin = SYNO_GPP_HDD7_LED_1; + break; + case 8: + /* Disk 8 are set via gpio */ + Pin1.pin = SYNO_GPP_HDD8_LED_0; + Pin2.pin = SYNO_GPP_HDD8_LED_1; + break; + case 9 ... 16: + err = 0; + goto END; + default: + printk("Invalid HDD number [%d]\n", iDiskNum); + goto END; + } + SetGpioPin(&Pin1); + SetGpioPin(&Pin2); + +SGPIO_END: +#ifdef SYNO_ATA_AHCI_LED_SWITCH + gDiskOrgStatus[iDiskNum - 1] = iStatus; +#endif + err = 0; +END: + return err; +} + +/** + * This function is created for funcSYNOSATADiskLedCtrl to hook + */ +static +int SYNOSetDiskLedStatusBySGPIOandGPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusBySGPIOandGPIO(iHostNum + 1, iStatus); +} +#else + +static +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + GPIO_PIN Pin1, Pin2; + + if (0 > SetDiskLedGPIOPinValue(status, &Pin1, &Pin2)) { + goto END; + } + + switch (disknum) { + case 1: + Pin1.pin = SYNO_GPP_HDD1_LED_0; + Pin2.pin = SYNO_GPP_HDD1_LED_1; + break; + case 2: + Pin1.pin = SYNO_GPP_HDD2_LED_0; + Pin2.pin = SYNO_GPP_HDD2_LED_1; + break; + case 3: + Pin1.pin = SYNO_GPP_HDD3_LED_0; + Pin2.pin = SYNO_GPP_HDD3_LED_1; + break; + case 4: + Pin1.pin = SYNO_GPP_HDD4_LED_0; + Pin2.pin = SYNO_GPP_HDD4_LED_1; + break; + case 5: + Pin1.pin = SYNO_GPP_HDD5_LED_0; + Pin2.pin = SYNO_GPP_HDD5_LED_1; + break; + case 7: + /* The eSata disk is /dev/sdg on DS710+, + * so it is the 7th disk on this model. + * ( 'g' - 'a' + 1 = 7 ) + */ + if (model_ops && model_ops->x86_set_esata_led_status) { + model_ops->x86_set_esata_led_status(status); + } + goto ESATA_END; + case 6: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + //for esata + err = 0; + goto END; + default: + printk("Wrong HDD number [%d]\n", disknum); + goto END; + } + + SetGpioPin(&Pin1); + SetGpioPin(&Pin2); + +ESATA_END: + err = 0; +END: + return err; +} + +#endif /* MY_DEF_HERE */ + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + +/** + * This function is for #29300 + * In rs2212rp+ and rs2212+, the disks are hosted by different sata controllers + * The first 6 disks are hosted by ahci and the last 4 disks are hosted by mv7042 + * They control disk present LEDs in totally different ways. + * Ahci is controlled by gpio, but mv7042 is controlled directly by chipset itself. + * That means we can not control last 4 disk present leds. + * So if we enable gpio pin 24 to enable them in synobios_init, the last 4 disks will light on but the first 6 disks will keep off. + * And the first 6 disks will light on after scemd scan all disk ports and light them on 1 by 1. + * To sync disk led activities, we have to delay enabling gpio pin 24 to when scemd try to light on disk leds. + */ +static int SetDiskLedEnable(SYNO_DISK_LED iStatus) +{ + static int diskLedEnable = 0; + GPIO_PIN LedActivate; + + // At first time to set disk led to light on, we enable gpio pin 24. + if (0 == diskLedEnable && iStatus != DISK_LED_OFF) { + diskLedEnable = 1; + + //Signal to activate the leds. + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); + } + return diskLedEnable; +} + +static +int SetDiskLedStatusBySGPIOandMvGPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int err = -1; + + SetDiskLedEnable(iStatus); + switch(iDiskNum) { + case 1 ... 6: + SetDiskLedStatusBySGPIO(iDiskNum, iStatus); + goto SGPIO_END; + case 7 ... 10: + SetDiskLedStatusBySataMvGPIO(iDiskNum, iStatus); + goto SGPIO_END; + case 11 ... 16: + err = 0; + goto END; + default: + printk("Invalid HDD number [%d]\n", iDiskNum); + goto END; + } +SGPIO_END: + err = 0; +END: + return err; +} + +/** + * This function is created for funcSYNOSATADiskLedCtrl to hook + */ +static +int SYNOSetDiskLedStatusBySGPIOandMvGPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusBySGPIOandMvGPIO(iHostNum + 1, iStatus); +} + +static +int SetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int err = -1; + GPIO_PIN Pin1, Pin2; + + SetDiskLedEnable(iStatus); + + if (0 > SetDiskLedGPIOPinValue(iStatus, &Pin1, &Pin2)) { + goto END; + } + + switch(iDiskNum) { + case 1 ... 6: + SetDiskLedStatusBySGPIO(iDiskNum, iStatus); + goto SGPIO_END; + case 7 ... 10: + SetDiskLedStatusBySataMvGPIO(iDiskNum + 4, iStatus); + goto SGPIO_END; + case 11: + Pin1.pin = SYNO_GPP_HDD11_LED_0; + Pin2.pin = SYNO_GPP_HDD11_LED_1; + break; + case 12: + Pin1.pin = SYNO_GPP_HDD12_LED_0; + Pin2.pin = SYNO_GPP_HDD12_LED_1; + break; + case 13 ... 16: + err = 0; + goto END; + default: + printk("Invalid HDD number [%d]\n", iDiskNum); + goto END; + } + SetGpioPin(&Pin1); + SetGpioPin(&Pin2); + +SGPIO_END: + err = 0; +END: + return err; +} + +/** + * This function is created for funcSYNOSATADiskLedCtrl to hook + */ +static +int SYNOSetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO(iHostNum + 1, iStatus); +} + +static +int SetDiskLedStatusBySGPIOMvGPIOandGPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int err = -1; + GPIO_PIN Pin1, Pin2; + + SetDiskLedEnable(iStatus); + + if (0 > SetDiskLedGPIOPinValue(iStatus, &Pin1, &Pin2)) { + goto END; + } + + switch(iDiskNum) { + case 1 ... 6: + SetDiskLedStatusBySGPIO(iDiskNum, iStatus); + goto SGPIO_END; + case 7 ... 10: + SetDiskLedStatusBySataMvGPIO(iDiskNum, iStatus); + goto SGPIO_END; + case 11: + Pin1.pin = SYNO_GPP_HDD11_LED_0; + Pin2.pin = SYNO_GPP_HDD11_LED_1; + break; + case 12: + Pin1.pin = SYNO_GPP_HDD12_LED_0; + Pin2.pin = SYNO_GPP_HDD12_LED_1; + break; + case 13 ... 16: + err = 0; + goto END; + default: + printk("Invalid HDD number [%d]\n", iDiskNum); + goto END; + } + SetGpioPin(&Pin1); + SetGpioPin(&Pin2); + +SGPIO_END: + err = 0; +END: + return err; +} + +/** + * This function is created for funcSYNOSATADiskLedCtrl to hook + */ +static +int SYNOSetDiskLedStatusBySGPIOMvGPIOandGPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusBySGPIOMvGPIOandGPIO(iHostNum + 1, iStatus); +} +#endif /* MY_DEF_HERE && MY_DEF_HERE */ + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if (NULL == pCpuTemp) { + goto END; + } +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if(0 != iRet) { + goto END; + } + + /* + * Count the cpu surface termperature + * n > 30 show n - 8 + * 30 >= n >= 22: show 22 + * n < 22: show n + */ + if(1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + if (pCpuTemp->cpu_temp[iCPUIdx] > 30) { + pCpuTemp->cpu_temp[iCPUIdx] = pCpuTemp->cpu_temp[iCPUIdx] - 8; + } else if (pCpuTemp->cpu_temp[iCPUIdx] >= 22){ + pCpuTemp->cpu_temp[iCPUIdx] = 22; + } + } + } + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static void synobios_hw_function(void) +{ + char szbuf[8] = {0}; + char c; + ReadUart("R", "R", szbuf, sizeof(szbuf)); + c = szbuf[0]; + + switch (c) { + case 'E': + sprintf(gszSynoHWVersion, "%s", HW_DS412p); + break; + case 'F': + sprintf(gszSynoHWVersion, "%s", HW_DS1812p); + break; + case 'G': + sprintf(gszSynoHWVersion, "%s", HW_DS1512p); + break; + case 'H': + sprintf(gszSynoHWVersion, "%s", HW_RS812p); + break; + case 'I': + sprintf(gszSynoHWVersion, "%s", HW_RS812rpp); + break; + case 'J': + sprintf(gszSynoHWVersion, "%s", HW_RS2212p); + break; + case 'K': + sprintf(gszSynoHWVersion, "%s", HW_RS2212rpp); + break; + case 'L': + sprintf(gszSynoHWVersion, "%s", HW_DS2413p); + break; + case 'P': + sprintf(gszSynoHWVersion, "%s", HW_DS713p); + break; + case 'Q': + sprintf(gszSynoHWVersion, "%s", HW_DS1513p); + break; + case 'R': + sprintf(gszSynoHWVersion, "%s", HW_DS1813p); + break; + case 'S': + sprintf(gszSynoHWVersion, "%s", HW_RS2414p); + break; + case 'T': + sprintf(gszSynoHWVersion, "%s", HW_RS2414rpp); + break; + case 'U': + sprintf(gszSynoHWVersion, "%s", HW_RS814p); + break; + case 'V': + sprintf(gszSynoHWVersion, "%s", HW_RS814rpp); + break; + } +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ +#ifdef SYNO_ATA_AHCI_LED_SWITCH + int iError = -1; + int iDiskIdx; +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) + int iDiskIdxMax = atomic_read(&ata_print_id); +#endif /* SYNO_HAVE_KERNEL_VERSION(3,10,0) */ + + switch(ledStatus){ + case SYNO_LED_OFF: + giSynoHddLedEnabled = 0; + break; + case SYNO_LED_ON: + giSynoHddLedEnabled = ~0; + break; + default: + goto ERR; + } + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) + for (iDiskIdx = 1; iDiskIdx < iDiskIdxMax; iDiskIdx++) { +#else /* SYNO_HAVE_KERNEL_VERSION(3,10,0) */ + for (iDiskIdx = 1; iDiskIdx < ata_print_id; iDiskIdx++) { +#endif /* SYNO_HAVE_KERNEL_VERSION(3,10,0) */ + SetDiskLedStatusBySGPIOandGPIO (iDiskIdx, gDiskOrgStatus[iDiskIdx - 1]); + } + + iError = 0; +ERR: + return iError; +#else + return 0; +#endif +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + case SYNO_LED_OFF: +#ifdef SYNO_E1000E_LED_SWITCH + if (funcSynoNicLedCtrl) { + funcSynoNicLedCtrl(ledStatus); + } +#endif + break; + default: + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static int superio_read (SYNO_SUPERIO_PACKAGE* pSuperioPackage){ + int iRet = -1; + +#ifdef MY_DEF_HERE + if(syno_superio_regist_read(pSuperioPackage->ldn, pSuperioPackage->reg, &pSuperioPackage->value)){ + goto END; + } + + iRet = 0; +END: +#endif /*MY_DEF_HERE*/ + return iRet; +} + +static int superio_write (SYNO_SUPERIO_PACKAGE* pSuperioPackage){ + int iRet = -1; + +#ifdef MY_DEF_HERE + if(syno_superio_regist_write(pSuperioPackage->ldn, pSuperioPackage->reg, pSuperioPackage->value)){ + goto END; + } + + iRet = 0; +END: +#endif /*MY_DEF_HERE*/ + return iRet; +} +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, +#ifdef MY_DEF_HERE + .set_disk_led = SetDiskLedStatusBySGPIOandGPIO, +#else + .set_disk_led = SetDiskLedStatus, +#endif + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = CheckMicropId, + .set_microp_id = SetMicropId, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ +#ifdef MY_DEF_HERE + GPIO_PIN LedActivate; + int iDiskIdx; +#endif + GPIO_PIN UsbOverCurrent; + *ops = &synobios_ops; + + synobios_hw_function(); + +#ifdef MY_DEF_HERE +#ifdef MY_DEF_HERE + // the default function of .set_disk_led is SetDiskLedStatusBySGPIOandGPIO + // SYNOSetDiskLedStatusBySGPIOandGPIO is actually SetDiskLedStatusBySGPIOandGPIO + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusBySGPIOandGPIO; +#endif /* MY_DEF_HERE */ +#endif + switch(GetModel()) + { + case MODEL_DS1512p: + model_ops = &ds1512p_ops; + break; + case MODEL_DS1513p: + model_ops = &ds1513p_ops; + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; +#ifdef MY_DEF_HERE + //Set to off to avoid lighting up too early + for(iDiskIdx = 1; iDiskIdx <= DS1513P_INTERNAL_DISK_NUM; iDiskIdx++) { + SetDiskLedStatusBySGPIOandGPIO(iDiskIdx, DISK_LED_OFF); + } + + //Signal to activate the leds. + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS412p: + model_ops = &ds412p_ops; + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + if (0 == strcmp(gszSynoHWRevision,"r2")){ + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; + } + break; + case MODEL_DS713p: + model_ops = &ds713p_ops; + hwmon_sensor_list = &ds713p_sensor_list; + hdd_detect_gpio = ds713p_hdd_detect_gpio; + hdd_enable_gpio = ds713p_hdd_enable_gpio; + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + if (0 == strcmp(gszSynoHWRevision,"r2")){ + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; + } + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + break; + case MODEL_RS812p: + model_ops = &rs812p_ops; + break; + case MODEL_RS812rpp: + model_ops = &rs812rpp_ops; + break; + case MODEL_RS814p: + model_ops = &rs814p_ops; + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; + break; + case MODEL_RS814rpp: + model_ops = &rs814rpp_ops; + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; + break; + case MODEL_DS1812p: + model_ops = &ds1812p_ops; +#ifdef MY_DEF_HERE + //Set to off to avoid lighting up too early + for(iDiskIdx = 1; iDiskIdx <= DS1812P_INTERNAL_DISK_NUM; iDiskIdx++) { + SetDiskLedStatusBySGPIOandGPIO(iDiskIdx, DISK_LED_OFF); + } + + //Signal to activate the leds. + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS1813p: + model_ops = &ds1813p_ops; + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; +#ifdef MY_DEF_HERE + //Set to off to avoid lighting up too early + for(iDiskIdx = 1; iDiskIdx <= DS1813P_INTERNAL_DISK_NUM; iDiskIdx++) { + SetDiskLedStatusBySGPIOandGPIO(iDiskIdx, DISK_LED_OFF); + } + + //Signal to activate the leds. + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); +#endif /* MY_DEF_HERE */ + break; + case MODEL_RS2212p: + model_ops = &rs2212p_ops; +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + synobios_ops.set_disk_led = SetDiskLedStatusBySGPIOandMvGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusBySGPIOandMvGPIO; +#endif /* MY_DEF_HERE */ +#endif + break; + case MODEL_RS2212rpp: + model_ops = &rs2212rpp_ops; +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + synobios_ops.set_disk_led = SetDiskLedStatusBySGPIOandMvGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusBySGPIOandMvGPIO; +#endif /* MY_DEF_HERE */ +#endif + break; + case MODEL_RS2414p: + model_ops = &rs2414p_ops; + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + synobios_ops.set_disk_led = SetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO; +#endif /* MY_DEF_HERE */ +#endif + /* To avoid possible interference that makes kernel complain about USB over current */ + UsbOverCurrent.pin = 43; + UsbOverCurrent.value = 1; + SetGpioPin(&UsbOverCurrent); + + UsbOverCurrent.pin = 42; + UsbOverCurrent.value = 1; + SetGpioPin(&UsbOverCurrent); + + break; + case MODEL_RS2414rpp: + model_ops = &rs2414rpp_ops; + synobios_ops.get_superio = superio_read; + synobios_ops.set_superio = superio_write; +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + synobios_ops.set_disk_led = SetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusBySGPIOMvGPIOandAHCIGPIO; +#endif /* MY_DEF_HERE */ +#endif + /* To avoid possible interference that makes kernel complain about USB over current */ + UsbOverCurrent.pin = 43; + UsbOverCurrent.value = 1; + SetGpioPin(&UsbOverCurrent); + + UsbOverCurrent.pin = 42; + UsbOverCurrent.value = 1; + SetGpioPin(&UsbOverCurrent); + + break; + case MODEL_DS2413p: + model_ops = &ds2413p_ops; +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) + synobios_ops.set_disk_led = SetDiskLedStatusBySGPIOMvGPIOandGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusBySGPIOMvGPIOandGPIO; +#endif /* MY_DEF_HERE */ +#endif + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + GPIO_PIN LedActivate; + + if(MODEL_DS1812p == GetModel() || + MODEL_DS1813p == GetModel()) { + //Signal to deactivate the leds. + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 1; + + SetGpioPin(&LedActivate); + } + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/cedarview/cedarview_common.h b/drivers/syno/synobios/cedarview/cedarview_common.h new file mode 100755 index 000000000000..ea1efe115fbe --- /dev/null +++ b/drivers/syno/synobios/cedarview/cedarview_common.h @@ -0,0 +1,104 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds1512p_ops; +extern struct model_ops ds1513p_ops; +extern struct model_ops ds412p_ops; +extern struct model_ops ds713p_ops; +extern struct model_ops rs812p_ops; +extern struct model_ops rs812rpp_ops; +extern struct model_ops rs814p_ops; +extern struct model_ops rs814rpp_ops; +extern struct model_ops ds1812p_ops; +extern struct model_ops ds1813p_ops; +extern struct model_ops rs2212p_ops; +extern struct model_ops rs2212rpp_ops; +extern struct model_ops ds2413p_ops; +extern struct model_ops rs2414p_ops; +extern struct model_ops rs2414rpp_ops; + +extern struct hwmon_sensor_list ds713p_sensor_list; + +extern int ds713p_hdd_enable_gpio[2]; +extern int ds713p_hdd_detect_gpio[2]; + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef MY_DEF_HERE +extern u32 syno_superio_gpio_pin(int pin, int *pValue, int isWrite); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +extern int syno_sata_mv_gpio_read(const unsigned short hostnum); +#endif + +#define SYNO_GPP_HDD1_LED_0 16 +#define SYNO_GPP_HDD1_LED_1 18 +#define SYNO_GPP_HDD2_LED_0 20 +#define SYNO_GPP_HDD2_LED_1 32 +#define SYNO_GPP_HDD3_LED_0 33 +#define SYNO_GPP_HDD3_LED_1 34 +#define SYNO_GPP_HDD4_LED_0 49 +#define SYNO_GPP_HDD4_LED_1 55 +#define SYNO_GPP_RS_BUZZER_OFF 57 +#define SYNO_GPP_HDD5_LED_0 133 +#define SYNO_GPP_HDD5_LED_1 132 +#define SYNO_GPP_HDD7_LED_0 47 +#define SYNO_GPP_HDD7_LED_1 45 +#define SYNO_GPP_HDD8_LED_0 29 +#define SYNO_GPP_HDD8_LED_1 46 +#define SYNO_GPP_HDD11_LED_0 47 +#define SYNO_GPP_HDD11_LED_1 45 +#define SYNO_GPP_HDD12_LED_0 29 +#define SYNO_GPP_HDD12_LED_1 46 +#define SYNO_GPP_LEDS_ACTIVATE 24 + +#define CEDARVIEW_GPIO_MAX_PIN 95 +#define CEDARVIEW_GPIO_ACTIVE_LOW 1 +#define CEDARVIEW_GPIO_ACTIVE_HIGH 0 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; \ No newline at end of file diff --git a/drivers/syno/synobios/cedarview/ds1512+.c b/drivers/syno/synobios/cedarview/ds1512+.c new file mode 100644 index 000000000000..fcd0e5d0e95e --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds1512+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS1512pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1512pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1512p = MODULE_T_DS1512p; + module_t *pType = &type_1512p; + + module_type_set(pType); + return 0; +} + +static +int DS1512pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1512pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1512pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1512pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1512p_ops = { + .x86_init_module_type = DS1512pInitModuleType, + .x86_fan_speed_mapping = DS1512pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/ds1513+.c b/drivers/syno/synobios/cedarview/ds1513+.c new file mode 100644 index 000000000000..e3534a877f28 --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds1513+.c @@ -0,0 +1,57 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS1513pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1513pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1513p = MODULE_T_DS1513p; + module_t *pType = &type_1513p; + + module_type_set(pType); + return 0; +} + +static +int DS1513pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1513pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1513pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1513pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1513p_ops = { + .x86_init_module_type = DS1513pInitModuleType, + .x86_fan_speed_mapping = DS1513pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/ds1812+.c b/drivers/syno/synobios/cedarview/ds1812+.c new file mode 100644 index 000000000000..0173198f6db6 --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds1812+.c @@ -0,0 +1,85 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS1812pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gDS1812pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1812pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1812p = MODULE_T_DS1812p; + module_t *pType = &type_1812p; + + module_type_set(pType); + return 0; +} + +static +int DS1812pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1812pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1812pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1812pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int DS1812pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1812pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1812pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1812pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1812p_ops = { + .x86_init_module_type = DS1812pInitModuleType, + .x86_fan_speed_mapping = DS1812pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = DS1812pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/ds1813+.c b/drivers/syno/synobios/cedarview/ds1813+.c new file mode 100644 index 000000000000..a34a2958b998 --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds1813+.c @@ -0,0 +1,85 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS1813pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gDS1813pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1813pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1813p = MODULE_T_DS1813p; + module_t *pType = &type_1813p; + + module_type_set(pType); + return 0; +} + +static +int DS1813pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1813pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1813pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1813pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int DS1813pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1813pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1813pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1813pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1813p_ops = { + .x86_init_module_type = DS1813pInitModuleType, + .x86_fan_speed_mapping = DS1813pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = DS1813pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/ds2413+.c b/drivers/syno/synobios/cedarview/ds2413+.c new file mode 100644 index 000000000000..a7f8207810c6 --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds2413+.c @@ -0,0 +1,85 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS2413pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gDS2413pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS2413pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds2413p = MODULE_T_DS2413p; + module_t *pType = &type_ds2413p; + + module_type_set(pType); + return 0; +} + +static +int DS2413pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS2413pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS2413pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS2413pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int DS2413pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS2413pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS2413pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS2413pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds2413p_ops = { + .x86_init_module_type = DS2413pInitModuleType, + .x86_fan_speed_mapping = DS2413pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = DS2413pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/ds412+.c b/drivers/syno/synobios/cedarview/ds412+.c new file mode 100644 index 000000000000..859b1d8d56c8 --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds412+.c @@ -0,0 +1,85 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS412pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gDS412pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS412pInitModuleType(struct synobios_ops *ops) +{ + module_t type_412p = MODULE_T_DS412p; + module_t *pType = &type_412p; + + module_type_set(pType); + return 0; +} + +static +int DS412pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS412pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS412pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS412pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int DS412pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS412pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS412pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS412pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds412p_ops = { + .x86_init_module_type = DS412pInitModuleType, + .x86_fan_speed_mapping = DS412pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = DS412pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/ds713+.c b/drivers/syno/synobios/cedarview/ds713+.c new file mode 100644 index 000000000000..351167ca939f --- /dev/null +++ b/drivers/syno/synobios/cedarview/ds713+.c @@ -0,0 +1,107 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gDS713pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gDS713pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE ds713p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int ds713p_hdd_detect_gpio[] = {33, 35}; +int ds713p_hdd_enable_gpio[] = {16, 20}; + +static +int DS713pInitModuleType(struct synobios_ops *ops) +{ + module_t type_713p = MODULE_T_DS713p; + module_t *pType = &type_713p; + + module_type_set(pType); + return 0; +} + +static +int DS713pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS713pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS713pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS713pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int DS713pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS713pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS713pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS713pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds713p_ops = { + .x86_init_module_type = DS713pInitModuleType, + .x86_fan_speed_mapping = DS713pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = DS713pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; + +struct hwmon_sensor_list ds713p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds713p_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/cedarview/rs2212+.c b/drivers/syno/synobios/cedarview/rs2212+.c new file mode 100644 index 000000000000..eaffd220bd28 --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs2212+.c @@ -0,0 +1,111 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS2212pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS2212pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2212pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2212p = MODULE_T_RS2212p; + module_t *pType = &type_rs2212p; + + module_type_set(pType); + return 0; +} + +static +int RS2212pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2212pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2212pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2212pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS2212pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS2212pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2212pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2212pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2212pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2212p_ops = { + .x86_init_module_type = RS2212pInitModuleType, + .x86_fan_speed_mapping = RS2212pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS2212pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS2212pGetBuzzerCleared, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs2212rp+.c b/drivers/syno/synobios/cedarview/rs2212rp+.c new file mode 100644 index 000000000000..dd39f8e6b86d --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs2212rp+.c @@ -0,0 +1,113 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +// extern function from cedarview_common +extern int CedarviewRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS2212rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS2212rppCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2212rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2212rpp = MODULE_T_RS2212rpp; + module_t *pType = &type_rs2212rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2212rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2212rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2212rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2212rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS2212rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS2212rppCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2212rppCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2212rppCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2212rppCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2212rpp_ops = { + .x86_init_module_type = RS2212rppInitModuleType, + .x86_fan_speed_mapping = RS2212rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS2212rppCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS2212rppGetBuzzerCleared, + .x86_get_power_status = CedarviewRedundantPowerGetPowerStatus, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs2414+.c b/drivers/syno/synobios/cedarview/rs2414+.c new file mode 100644 index 000000000000..bc16244373dd --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs2414+.c @@ -0,0 +1,111 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS2414pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS2414pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2414pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2414p = MODULE_T_RS2414p; + module_t *pType = &type_rs2414p; + + module_type_set(pType); + return 0; +} + +static +int RS2414pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2414pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2414pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2414pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS2414pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS2414pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2414pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2414pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2414pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2414p_ops = { + .x86_init_module_type = RS2414pInitModuleType, + .x86_fan_speed_mapping = RS2414pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS2414pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS2414pGetBuzzerCleared, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs2414rp+.c b/drivers/syno/synobios/cedarview/rs2414rp+.c new file mode 100644 index 000000000000..9f23bd8a95ab --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs2414rp+.c @@ -0,0 +1,113 @@ +// Copyright (c) 2000-2013 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +//extern function from cedarview_common.c +extern int CedarviewRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS2414rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS2414rppCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2414rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2414rpp = MODULE_T_RS2414rpp; + module_t *pType = &type_rs2414rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2414rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2414rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2414rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2414rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS2414rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS2414rppCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2414rppCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2414rppCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2414rppCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2414rpp_ops = { + .x86_init_module_type = RS2414rppInitModuleType, + .x86_fan_speed_mapping = RS2414rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS2414rppCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS2414rppGetBuzzerCleared, + .x86_get_power_status = CedarviewRedundantPowerGetPowerStatus, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs812+.c b/drivers/syno/synobios/cedarview/rs812+.c new file mode 100644 index 000000000000..7850d2513395 --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs812+.c @@ -0,0 +1,129 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +// extern function from cedarview_common +extern int GetFanStatusMircopWithGPIOCommon(const int pin, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS812pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS812pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS812pInitModuleType(struct synobios_ops *ops) +{ + module_t type_812p = MODULE_T_RS812p; + module_t *pType = &type_812p; + + module_type_set(pType); + return 0; +} + +static +int RS812pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS812pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS812pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS812pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS812pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS812pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS812pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS812pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS812pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS812pGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {36, 18, 37, 30}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + GetFanStatusMircopWithGPIOCommon(gpio_fan_map[fanno-1], pStatus); + + return 0; +} + +struct model_ops rs812p_ops = { + .x86_init_module_type = RS812pInitModuleType, + .x86_fan_speed_mapping = RS812pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS812pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS812pGetBuzzerCleared, + .x86_get_fan_status = RS812pGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs812rp+.c b/drivers/syno/synobios/cedarview/rs812rp+.c new file mode 100644 index 000000000000..60a5c81d4044 --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs812rp+.c @@ -0,0 +1,113 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +// extern function from cedarview_common +extern int CedarviewRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS812rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS812rppCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS812rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_812p = MODULE_T_RS812rpp; + module_t *pType = &type_812p; + + module_type_set(pType); + return 0; +} + +static +int RS812rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS812rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS812rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS812rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS812rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS812rppCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS812rppCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS812rppCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS812rppCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs812rpp_ops = { + .x86_init_module_type = RS812rppInitModuleType, + .x86_fan_speed_mapping = RS812rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS812rppCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS812rppGetBuzzerCleared, + .x86_get_power_status = CedarviewRedundantPowerGetPowerStatus, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs814+.c b/drivers/syno/synobios/cedarview/rs814+.c new file mode 100644 index 000000000000..1370abc5471f --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs814+.c @@ -0,0 +1,112 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +// extern function from cedarview_common +extern int CedarviewRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS814pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS814pCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS814pInitModuleType(struct synobios_ops *ops) +{ + module_t type_814p = MODULE_T_RS814p; + module_t *pType = &type_814p; + + module_type_set(pType); + return 0; +} + +static +int RS814pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS814pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS814pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS814pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS814pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS814pCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS814pCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS814pCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS814pCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs814p_ops = { + .x86_init_module_type = RS814pInitModuleType, + .x86_fan_speed_mapping = RS814pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS814pCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS814pGetBuzzerCleared, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/cedarview/rs814rp+.c b/drivers/syno/synobios/cedarview/rs814rp+.c new file mode 100644 index 000000000000..b7283bf4aa94 --- /dev/null +++ b/drivers/syno/synobios/cedarview/rs814rp+.c @@ -0,0 +1,113 @@ +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "cedarview_common.h" + +// extern function from cedarview_common +extern int CedarviewRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int CedarviewGetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus); + +PWM_FAN_SPEED_MAPPING gRS814rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gRS814rppCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS814rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_814p = MODULE_T_RS814rpp; + module_t *pType = &type_814p; + + module_type_set(pType); + return 0; +} + +static +int RS814rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS814rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS814rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS814rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS814rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SYNO_GPP_RS_BUZZER_OFF; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +static +int RS814rppCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS814rppCPUFanSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS814rppCPUFanSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS814rppCPUFanSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs814rpp_ops = { + .x86_init_module_type = RS814rppInitModuleType, + .x86_fan_speed_mapping = RS814rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = RS814rppCPUFanSpeedMapping, + .x86_get_buzzer_cleared = RS814rppGetBuzzerCleared, + .x86_get_power_status = CedarviewRedundantPowerGetPowerStatus, + .x86_get_fan_status = CedarviewGetFanStatusMircopWithGPIO, +}; diff --git a/drivers/syno/synobios/coffeelake/Makefile b/drivers/syno/synobios/coffeelake/Makefile new file mode 100644 index 000000000000..146adc573f54 --- /dev/null +++ b/drivers/syno/synobios/coffeelake/Makefile @@ -0,0 +1,15 @@ +include /env.mak + +obj-m += coffeelake-synobios.o + +coffeelake-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds3619xs.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + ../common/common.o \ + coffeelake_common.o diff --git a/drivers/syno/synobios/coffeelake/coffeelake_common.c b/drivers/syno/synobios/coffeelake/coffeelake_common.c new file mode 100644 index 000000000000..ea48662cb2fe --- /dev/null +++ b/drivers/syno/synobios/coffeelake/coffeelake_common.c @@ -0,0 +1,459 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "coffeelake_common.h" + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL */ + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +/** + * Set Max internal disk numbers + */ +static int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS3619xs: + iMaxInternalDiskNum = 12; + break; + } + return iMaxInternalDiskNum; +} + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +static int giDiskLedController = -1; +static int giDiskLedControllerInit = 0; + +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void InitSynoDiskLed(void) +{ + GPIO_PIN pin; + + // the disk led enable controller is not assigned, just return + if (0 > giDiskLedController) { + return; + } + pin.pin = giDiskLedController; + pin.value = 0; + SetGpioPin(&pin); +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_DS3619xs; + + if (!strncmp(gszSynoHWVersion, HW_DS3619xs, strlen(HW_DS3619xs))) { + model = MODEL_DS3619xs; + } + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +/** + * Control disk led via AHCI SGPIO + */ +static +int SetSCSIHostLedStatusByAHCIGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret = -1; + int iFault, iPresent; + + switch(status) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + iFault = 1; + iPresent = 0; + break; + case DISK_LED_GREEN_SOLID: + iFault = 0; + iPresent = 1; + break; + case DISK_LED_OFF: + iFault = 0; + iPresent = 0; + break; + default: + printk("Invalid LED status [%d]\n", status); + goto END; + } +#ifdef MY_DEF_HERE + sata_syno_ahci_diskled_set(iHostNum, iPresent, iFault); +#else + printk(KERN_ERR "SYNO ATA AHCI DISK LED control function is not defined!!"); +#endif /* MY_DEF_HERE */ + ret = 0; +END: + return ret; +} + +#ifdef MY_DEF_HERE +/** + * Control disk led over ahci SGPIO + */ +static +int SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret; + int iWrite = -1, iRead = -1; + int iInternalHost =0; + + // first time we tried to light on disk led + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + + switch(GetModel()) + { + case MODEL_DS3619xs: + iInternalHost = 6; + break; + default: + iInternalHost = 0; + break; + } + + if (iHostNum < iInternalHost) { + ret = SetSCSIHostLedStatusByAHCIGPIO(iHostNum, status);; + } else { + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status) { + iWrite = 1; + } else { + iWrite = 0; + } + ret = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + iRead = syno_mv_9235_disk_led_get(iHostNum); + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } + } + return ret; +} + +static +int SetDiskLedStatusBy9235GPIOandAHCISGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + // first time we tried to light on disk led + if (0 == giDiskLedControllerInit) { + InitSynoDiskLed(); + giDiskLedControllerInit = 1; + } + + if (1 > disknum) { + goto END; + } + + if (GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if (!gblDiskNumNeedTran) { + err = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(disknum - 1, status); + } else { + err = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(giDiskMapTable[disknum - 1], status); + } +END: + return err; +} +#endif /* MY_DEF_HERE */ + + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = COFFEELAKE_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + giDiskLedController = COFFEELAKE_ALL_LED_ACTIVATE_PIN; + + if (0 > syno_libata_disk_map_table_gen(giDiskMapTable)) { + gblDiskNumNeedTran = 0; + } else { + gblDiskNumNeedTran = 1; + } + + switch(GetModel()) + { + case MODEL_DS3619xs: + model_ops = &ds3619xs_ops; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIOandAHCISGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/coffeelake/coffeelake_common.h b/drivers/syno/synobios/coffeelake/coffeelake_common.h new file mode 100644 index 000000000000..e6a0d415dfd0 --- /dev/null +++ b/drivers/syno/synobios/coffeelake/coffeelake_common.h @@ -0,0 +1,53 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "../common/common.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops ds3619xs_ops; + +extern u32 syno_pch_lpc_gpio_pin(int pin, int *pValue, int isWrite); +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +extern int syno_libata_disk_map_table_gen(int *iDiskMapTable); +#endif +#ifdef MY_DEF_HERE +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +extern int syno_mv_9235_disk_led_get(const unsigned short hostnum); +#endif +#ifdef MY_DEF_HERE +extern void sata_syno_ahci_diskled_set(int iHostNum, int iPresent, int iFault); +#endif + +/* USB Power */ +#define COFFEELAKE_GPIO_USB3A_PWR_EN1 65 // GPP_C_14 (UART1_RTSB_ISH_UART1_RTSB) +#define COFFEELAKE_GPIO_USB3A_PWR_EN2 66 // GPP_C_15 (UART1_CTSB_ISH_UART1_CTSB) +#define COFFEELAKE_GPIO_USB3C_PWR_EN1 67 // GPP_C_16 (I2C0_SDA) +/* LED control */ +#define COFFEELAKE_LAN_LED_ACTIVATE_PIN 198 // GPP_H_19 (ISH_I2C0_SDA) +#define COFFEELAKE_DISK_LED_ACTIVATE_PIN 199 // GPP_H_20 (ISH_I2C0_SCL) +#define COFFEELAKE_ALL_LED_ACTIVATE_PIN 200 // GPP_H_21 (ISH_I2C1_SDA) +#define COFFEELAKE_ALARM_LED_PIN 201 // GPP_H_22 (ISH_I2C1_SCL) + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/coffeelake/ds3619xs.c b/drivers/syno/synobios/coffeelake/ds3619xs.c new file mode 100644 index 000000000000..93b78c241c04 --- /dev/null +++ b/drivers/syno/synobios/coffeelake/ds3619xs.c @@ -0,0 +1,30 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "coffeelake_common.h" + +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int DS3619xsInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds3619xs = MODULE_T_DS3619xs; + module_t *pType = &type_ds3619xs; + + module_type_set(pType); + return 0; +} + +struct model_ops ds3619xs_ops = { + .x86_init_module_type = DS3619xsInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, + .x86_set_buzzer_clear = NULL, +}; diff --git a/drivers/syno/synobios/comcerto2k/Makefile b/drivers/syno/synobios/comcerto2k/Makefile new file mode 100644 index 000000000000..fc0de557f7da --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/Makefile @@ -0,0 +1,23 @@ +ifeq ($(SYNO_PLATFORM),MINDSPEED_COMCERTO2K) +obj-m += ds414j-synobios.o +obj-m += ds415j-synobios.o +endif + +common-obj += \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-ricoh-lib.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-ricoh.o \ + ../rtc/rtc-linux-seiko.o \ + ../mapping.o \ + comcerto2k_common.o + +fan-pwm-obj += fan-pwm.o +fan-resister-obj += fan-resister.o + +ds414j-synobios-objs = ds414j.o $(fan-resister-obj) $(common-obj) +ds415j-synobios-objs = ds415j.o $(fan-resister-obj) $(common-obj) diff --git a/drivers/syno/synobios/comcerto2k/comcerto2k_common.c b/drivers/syno/synobios/comcerto2k/comcerto2k_common.c new file mode 100755 index 000000000000..c07d588661a8 --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/comcerto2k_common.c @@ -0,0 +1,328 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "synobios.h" +#include +#include +#include "../mapping.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "comcerto2k_common.h" + +/* all armada370 models share same synobios_model_init/cleanup(), + each model must implement their own model_private_init/cleanup() */ +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); + +#define MAX_ENABLE_PIN_NUM 4 +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int *hdd_enable_gpio = NULL; +static int *hdd_detect_gpio = NULL; + + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static int Uninitialize(void); + +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gPWMSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gPWMSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + u16 data = 0; + + if (linuxI2CCharRead(0x48, (u8 *)&data, 2, 0)) { + return -1; + } + + /* The temperature data only 9 bits */ + data = data >> 7; + + if (data >> 8) { /* bit 9 is minus sign */ + pThermalTemp->temperature = -1 * (0x100 - ((u8 *)&data)[1]); + } else { + pThermalTemp->temperature = data; + } + (pThermalTemp->temperature) >>= 1; + + return 0; +} + +static int SetGpioPin(GPIO_PIN *pPin) +{ + int iRet = -1; + + if(NULL == pPin) { + goto END; + } + + if(0 != SYNO_COMCERTO2K_GPIO_PIN((int)pPin->pin, (int*)&pPin->value, 1)) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static int GetGpioPin( GPIO_PIN *pPin ) +{ + int iRet = -1; + + if(NULL == pPin) { + goto END; + } + + if(0 != SYNO_COMCERTO2K_GPIO_PIN((int)pPin->pin, (int*)&pPin->value, 0)) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + /*Scsi host in kernel is zero-based, disknum here is one-based, + *so we should minus 1 while calling the function + */ + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status){ + syno_sata_mv_gpio_write( 1, disknum - 1); + }else{ + syno_sata_mv_gpio_write( 0, disknum - 1); + } + + err = 0; +END: + return err; +} +#endif /* MY_DEF_HERE */ + + +int GetMemByte( MEMORY_BYTE *pMemory ) +{ + return 0; +} + +static int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return 0; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + GPIO_PIN pPin; + unsigned long hdd_enable = 0; + unsigned long hdd_detect = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list || (NULL == hdd_enable_gpio && NULL == hdd_detect_gpio)) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < MAX_ENABLE_PIN_NUM; index++){ + if (NULL != hdd_enable_gpio) { + if (-1 == hdd_enable_gpio[index]) { + break; + } + pPin.pin = hdd_enable_gpio[index]; + GetGpioPin(&pPin); + hdd_enable |= (pPin.value & 0x01) << index; + } + if (NULL != hdd_detect_gpio) { + if (-1 == hdd_detect_gpio[index]) { + break; + } + pPin.pin = hdd_detect_gpio[index]; + GetGpioPin(&pPin); + hdd_detect |= (pPin.value & 0x01) << index; + } + } + + if (NULL != hdd_detect_gpio) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + if (NULL != hdd_enable_gpio) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + } + + iRet = 0; + +End: + return iRet; +} + +static +int HWMONGetThermalSensor(struct _SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + struct _SynoThermalTemp ThermalTemp; + + if (NULL == SysThermal) { + return -ENODEV; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + if (0 != GetSysTemperature(&ThermalTemp)) { + goto End; + } + + snprintf(SysThermal->sensor[0].value, sizeof(SysThermal->sensor[0].value), "%d", ThermalTemp.temperature); + + iRet = 0; +End: + return iRet; +} + + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = SetPowerLedStatus, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = NULL, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .set_alarm_led = SetAlarmLed, + .get_backplane_status = GetBackPlaneStatus, + .get_mem_byte = GetMemByte, + .get_buzzer_cleared = GetBuzzerCleared, + .set_phy_led = NULL, + .set_hdd_led = SetHDDActLed, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + if( pSynoModule && RTC_SEIKO == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = rtc_seiko_get_time; + synobios_ops.set_rtc_time = rtc_seiko_set_time; + synobios_ops.get_auto_poweron = rtc_get_auto_poweron; + synobios_ops.set_auto_poweron = rtc_seiko_set_auto_poweron; + synobios_ops.init_auto_poweron = rtc_seiko_auto_poweron_init; + synobios_ops.uninit_auto_poweron = rtc_seiko_auto_poweron_uninit; + } + if( pSynoModule && RTC_MV == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = NULL; + synobios_ops.set_rtc_time = NULL; + synobios_ops.get_auto_poweron = NULL; + synobios_ops.set_auto_poweron = NULL; + synobios_ops.init_auto_poweron = NULL; + synobios_ops.uninit_auto_poweron = NULL; + } + + switch (GetModel()) { + case MODEL_DS414j: + hwmon_sensor_list = &ds414j_sensor_list; + hdd_enable_gpio = ds414j_hdd_enable_gpio; + hdd_detect_gpio = ds414j_hdd_detect_gpio; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensor; + break; + default: + hwmon_sensor_list = NULL; + hdd_enable_gpio = NULL; + hdd_detect_gpio = NULL; + synobios_ops.hwmon_get_backplane_status = NULL; + break; + } + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + return 0; +} + +static int Uninitialize(void) +{ + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + model_addon_cleanup(*ops); + return 0; +} diff --git a/drivers/syno/synobios/comcerto2k/comcerto2k_common.h b/drivers/syno/synobios/comcerto2k/comcerto2k_common.h new file mode 100755 index 000000000000..e064ed942690 --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/comcerto2k_common.h @@ -0,0 +1,67 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include "../mapping.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetUsbDiskLedStatus(SYNO_DISK_LED status); +int SetPowerLedStatus(SYNO_LED status); +int GetFanStatus(int fanno, FAN_STATUS *pStatus); +int GetFanNum(int *pFanNum); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp); +int SetAlarmLed(unsigned char type); +int GetBackPlaneStatus(BACKPLANE_STATUS *pStatus); +int GetFanSpeedBits(int start, int end, MEMORY_BYTE *pMemory); +int GetMemByte( MEMORY_BYTE *pMemory ); +int InitModuleType(struct synobios_ops *ops); +int FanStatusMappingRS409r1(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int PWMFanSpeedMapping(FAN_SPEED speed); +int SetPhyLed(SYNO_LED ledStatus); +int SetHDDActLed(SYNO_LED ledStatus); +int SYNO_COMCERTO2K_GPIO_PIN(int pin, int *pValue, int isWrite); +int SYNO_COMCERTO2K_GPIO_BLINK(int pin, int blink); +int SYNO_CTRL_FAN_STATUS_GET(int index, int *pValue); +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +extern int SYNO_CTRL_BUZZER_CLEARED_GET(int *pValue); +extern int SynoArmadaSetPhyLed(SYNO_LED); +#ifdef MY_DEF_HERE +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status); +#endif +extern int SYNO_CTRL_EXT_CHIP_HDD_LED_SET(int index, int status); +extern int SYNO_CTRL_FAN_PERSISTER(int index, int status, int isWrite); +extern int SYNO_CTRL_INTERNAL_HDD_LED_SET(int index, int status); +extern int SYNO_SOC_HDD_LED_SET(int index, int status); +extern int axptemp_read_temp(void); +extern void SYNO_GPIO_SET_FALLING_EDGE(int gpio); +extern void SYNO_GPIO_SET_RISING_EDGE(int gpio); +#ifdef MY_DEF_HERE +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +extern int syno_mv_9235_disk_led_get(const unsigned short hostnum); +#endif + +extern struct hwmon_sensor_list ds414j_sensor_list; + +extern int ds414j_hdd_detect_gpio[4]; +extern int ds414j_hdd_enable_gpio[4]; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; \ No newline at end of file diff --git a/drivers/syno/synobios/comcerto2k/ds414j.c b/drivers/syno/synobios/comcerto2k/ds414j.c new file mode 100755 index 000000000000..ae54de8e0a0a --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/ds414j.c @@ -0,0 +1,148 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2010 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "../i2c/i2c-linux.h" +#include "comcerto2k_common.h" + +int GetModel(void) +{ + return MODEL_DS414j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + + +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + int FanStatus; + + if ( 1 > fanno || 3 < fanno) { + return -EINVAL; + } + + SYNO_CTRL_FAN_STATUS_GET(fanno, &FanStatus); + + if (0 == FanStatus) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + + return 0; +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_414j = MODULE_T_DS414jv10; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS414j: + pType = &type_414j; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ +#ifdef MY_DEF_HERE + return SetDiskLedStatusBySataMvGPIO(disknum, status); +#else + return 0; +#endif +} + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} +int SetAlarmLed(unsigned char type) +{ + return 0; +} + +int GetBackPlaneStatus(BACKPLANE_STATUS *pStatus) +{ + return 0; +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + return 0; +} + +int model_addon_init(struct synobios_ops *ops) +{ + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + + return 0; +} + +int ds414j_hdd_detect_gpio[4] = {39, 38, 37, 36}; +int ds414j_hdd_enable_gpio[4] = {5, 4, 3, 2}; + +SYNO_HWMON_SENSOR_TYPE ds414j_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "system", + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds414j_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +struct hwmon_sensor_list ds414j_sensor_list = { + .thermal_sensor = &ds414j_thermal_sensor, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds414j_hdd_backplane_status, +}; + + diff --git a/drivers/syno/synobios/comcerto2k/ds415j.c b/drivers/syno/synobios/comcerto2k/ds415j.c new file mode 100755 index 000000000000..4137859ad3fb --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/ds415j.c @@ -0,0 +1,205 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2010 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "../i2c/i2c-linux.h" +#include "comcerto2k_common.h" +#include "syno_ttyS.h" + +extern void SYNO_MASK_HDD_LED(int blEnable); +int GetModel(void) +{ + return MODEL_DS415j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1200); +} + + +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + int FanStatus; + int rgcVolt[2] = {0, 0}; + + if ( 1 > fanno || 3 < fanno) { + return -EINVAL; + } + + do { + SYNO_CTRL_FAN_STATUS_GET(fanno, &FanStatus); + rgcVolt[(int)FanStatus] ++; + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ( (rgcVolt[0] + rgcVolt[1]) < 200 ); + + if ((rgcVolt[0] == 0) || (rgcVolt[1] == 0) ) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + + return 0; +} + +int +InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = ops->get_model(); + module_t type_415j = MODULE_T_DS415jv10; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS415j: + pType = &type_415j; + break; + default: + break; + } + + module_type_set(pType); + + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return 0; +} + +int SetAlarmLed(unsigned char type) +{ + return 0; +} + +int GetBackPlaneStatus(BACKPLANE_STATUS *pStatus) +{ + return 0; +} + +extern void syno_genphy_ledcontrol(const int); +int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + case SYNO_LED_OFF: + syno_genphy_ledcontrol(ledStatus); + break; + default: + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + SYNO_MASK_HDD_LED(ledStatus); + return 0; +} + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +static +int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + return iRet; +} + +static +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || 4 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + iRet = SetSCSIHostLedStatusBy9235GPIO(iDiskNum - 1, iStatus); +END: + return iRet; + +} +#endif /* MY_DEF_HERE */ +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} +int model_addon_init(struct synobios_ops *ops) +{ + + SYNO_MASK_HDD_LED(1); +#ifdef MY_DEF_HERE + ops->set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + + ops->set_phy_led = NULL; + return 0; +} diff --git a/drivers/syno/synobios/comcerto2k/fan-pwm.c b/drivers/syno/synobios/comcerto2k/fan-pwm.c new file mode 100755 index 000000000000..606d0f0ebe2c --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include "synobios.h" +#include +#include "comcerto2k_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/comcerto2k/fan-resister.c b/drivers/syno/synobios/comcerto2k/fan-resister.c new file mode 100644 index 000000000000..464f7f06d0d8 --- /dev/null +++ b/drivers/syno/synobios/comcerto2k/fan-resister.c @@ -0,0 +1,60 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include "synobios.h" +#include +#include +#include + +#include "comcerto2k_common.h" + +int +SetFanSpeedValue(char speed_value) +{ + int index = 0; + int ret = -1; + int status = 0; + + for (index=0; index<3; index++) { + if (0x01 & (speed_value>>index)) { + status = 1; + } else { + status = 0; + } + + if (SYNO_CTRL_FAN_PERSISTER(index+1, status, 1)) { + goto End; + } + } + + ret = 0; +End: + return ret; +} + +int +SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + case MODEL_DS414j: + case MODEL_DS415j: + if (FanStatusMappingType2(status, speed, &speed_value)) { + goto END; + } + break; + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (-1 == SetFanSpeedValue(speed_value)) { + goto END; + } + + res = 0; +END: + return res; + +} diff --git a/drivers/syno/synobios/common/common.c b/drivers/syno/synobios/common/common.c new file mode 100644 index 000000000000..7cb3b30b61b7 --- /dev/null +++ b/drivers/syno/synobios/common/common.c @@ -0,0 +1,376 @@ +/* Copyright (c) 2009-2015 Synology Inc. All rights reserved. */ +#include "synobios.h" +#include +#include "common.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +#ifdef CONFIG_SYNO_GPIO +void check_gpio_consistency (SYNO_GPIO_INFO* pGpio1, SYNO_GPIO_INFO* pGpio2) +{ + int i; + + if (!pGpio1 || !pGpio2) { + printk("%s: Error Parameter\n", __FUNCTION__); + return; + } + + if ((pGpio1->nr_gpio != pGpio2->nr_gpio) || + (pGpio1->gpio_polarity != pGpio2->gpio_polarity)) { + goto WARN; + } + + for (i = 0; i < pGpio1->nr_gpio; i++) { + if (pGpio1->gpio_port[i] != pGpio2->gpio_port[i]) { + goto WARN; + } + } + return ; +WARN: + printk("WARNING: inconsistent syno gpio info"); + if (pGpio1->name) { + printk(", %s", pGpio1->name); + } + printk("\n"); +} + +int SYNO_CTRL_FAN_RESISTOR(char speed_value) +{ + int i = 0; + int status = 0; + + for (i = 0; i < syno_gpio.fan_ctrl->nr_gpio; i++) { + // 3 LSBs represent fan speed. + // bit[0]: max, bit[1]: mid, bit[2]: min + // 5 LSBs + // bit[0]: full, bit[1]: vol, bit[2]: high, bit[3]: mid, bit[4]: low + if (0x01 & (speed_value >> i)) { + status = 1; + } else { + status = 0; + } + if (!HAVE_FAN_CTRL(i + 1)) { // HAVE_FAN_CTRL is 1-based + printk("No such fan ctrl pin. Index: %d\n", i + 1); + WARN_ON(1); + return -EINVAL; + } + SYNO_GPIO_WRITE(FAN_CTRL_PIN(i+1), status); + } + return 0; +} + +/* SYNO_CTRL_FAN_STATUS_GET + * Query Fan status . + * output: 1 - not fail, 0 - fail. + */ +int SYNO_CTRL_FAN_STATUS_GET(int index, int *pValue) +{ + int failed = 0; + + if (!HAVE_FAN_FAIL(index)) { // index is 1-based + printk("No such fan fail pin. Index: %d\n", index); + WARN_ON(1); + return -EINVAL; + } + + failed = SYNO_GPIO_READ(FAN_FAIL_PIN(index)); + + if (failed) + *pValue = 0; + else + *pValue = 1; + + return 0; +} + +/** + * For those fans output constant 0 or 1 when active or stopped + * + * @param fanno [IN] Represent which fan + * @param pStatus [OUT] The fan status + * + * @return 0: sucessful + * -EINVAL: error parameter + * +*/ +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus) +{ + int FanStatus = 0; + int iRet = -EINVAL; + + if (!(1 <= fanno && fanno <= 3) || NULL == pStatus) { + goto END; + } + + if (0 != SYNO_CTRL_FAN_STATUS_GET(fanno, &FanStatus)) { + goto END; + } + if (FanStatus) { + *pStatus = FAN_STATUS_RUNNING; + } else { + *pStatus = FAN_STATUS_STOP; + } + iRet = 0; + +END: + return iRet; +} + +/** + * For those fans output constant 1 or 0 when stopped and output + * periodically 0 and 1 by truns when active. + * + * @param fanno [IN] Represent which fan + * @param pStatus [OUT] The fan status + * + * @return 0: sucessful + * -EINVAL: error parameter + * +*/ +int GetFanStatusActivePulse(int fanno, FAN_STATUS *pStatus) +{ + int FanStatus = 0; + int rgcVolt[2] = {0, 0}; + int iRet = -EINVAL; + + if (pStatus == NULL || !HAVE_FAN_FAIL(fanno)) { + goto END; + } + + do { + if (0 != SYNO_CTRL_FAN_STATUS_GET(fanno, &FanStatus)) { + goto END; + } + rgcVolt[FanStatus]++; + if (rgcVolt[0] && rgcVolt[1]) { + break; + } + udelay(300); + } while ((rgcVolt[0] + rgcVolt[1]) < 200); + + if (rgcVolt[1] == 0) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + + iRet = 0; +END: + return iRet; +} + +int SYNO_CTRL_ALARM_LED_SET(int status) +{ + if (!HAVE_ALARM_LED()) { + WARN_ON(1); + return -EINVAL; + } + + SYNO_GPIO_WRITE(ALARM_LED_PIN(), status); + return 0; +} + +#if defined(CONFIG_SYNO_ATA_PWR_CTRL) || defined(CONFIG_SYNO_SATA_PWR_CTRL) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +#define HDD_FAIL_LED_POLARITY(index) HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, index) +#define HDD_PRESENT_LED_POLARITY(index) HDD_FAIL_LED_POLARITY_BY_SLOT(DT_INTERNAL_SLOT, index) +#define HDD_PRESENT_LED_PIN(index) HDD_PRESENT_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, index) +#define HAVE_HDD_PRESENT_LED(index) HDD_PRESENT_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, index) +#define HAVE_HDD_FAIL_LED(index) HDD_PRESENT_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, index) +#define HDD_FAIL_LED_PIN(index) HDD_FAIL_LED_PIN_BY_SLOT(DT_INTERNAL_SLOT, index) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +int SYNO_HDD_LED_SET(int index, int status) +{ + int fail_value, present_value; + + if (!HAVE_HDD_FAIL_LED(index)) { // index is 1-based + printk("No such hdd fail led pin. Index: %d\n", index); + WARN_ON(1); + return -EINVAL; + } + + if (0 == SYNO_CHECK_HDD_DETECT(index)) { + status = DISK_LED_OFF; + } + + /* Since faulty led and present led are combined, + we need to disable present led when light on faulty's */ + if (DISK_LED_ORANGE_SOLID == status || DISK_LED_ORANGE_BLINK == status) { + fail_value = 1; + present_value = 0; + } else if (DISK_LED_GREEN_SOLID == status || DISK_LED_GREEN_BLINK == status) { + fail_value = 0; + present_value = 1; + } else if (DISK_LED_OFF == status) { + fail_value = 0; + present_value = 0; + } else { + printk("Wrong HDD led status [%d]\n", status); + return -EINVAL; + } + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + if (ACTIVE_LOW == HDD_FAIL_LED_POLARITY(index)) +#else + if (ACTIVE_LOW == HDD_FAIL_LED_POLARITY()) +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + fail_value = !fail_value; + SYNO_GPIO_WRITE(HDD_FAIL_LED_PIN(index),fail_value); + + /* armada38x and monaco have no hdd detect pin so it can be ignored */ + if (HAVE_HDD_PRESENT_LED(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + if (ACTIVE_LOW == HDD_PRESENT_LED_POLARITY(index)) +#else + if (ACTIVE_LOW == HDD_PRESENT_LED_POLARITY()) +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + present_value = !present_value; + SYNO_GPIO_WRITE(HDD_PRESENT_LED_PIN(index), present_value); + } + + return 0; +} +#endif /* defined(CONFIG_SYNO_ATA_PWR_CTRL) || defined(CONFIG_SYNO_SATA_PWR_CTRL) */ + +// for matching userspace usage, return 0 if button is pressed, else = 1 +int SYNO_COPY_BUTTON_GPIO_GET(void) +{ + int ret; + + if (!HAVE_COPY_BUTTON_DETECT()) { + printk("No copy button detect pin\n"); + WARN_ON(1); + return 1; + } + ret = SYNO_GPIO_READ(COPY_BUTTON_DETECT_PIN()); + if (ACTIVE_LOW == COPY_BUTTON_DETECT_POLARITY()){ + return ret; + } + return !ret; +} + +unsigned int SynoModelIDGet(SYNO_GPIO *pGpio) +{ + int value; + unsigned int ret = 0; + + value = SYNO_GPIO_READ(pGpio->model_id->gpio_port[0]); + ret |= (value ? 1 : 0) << 2; + value = SYNO_GPIO_READ(pGpio->model_id->gpio_port[1]); + ret |= (value ? 1 : 0) << 1; + value = SYNO_GPIO_READ(pGpio->model_id->gpio_port[2]); + ret |= (value ? 1 : 0) << 0; + + return ret; +} + +void SYNO_ENABLE_HDD_LED(int blEnable) +{ + if (!HAVE_DISK_LED_CTRL()) { + printk("No disk led ctrl pin\n"); + WARN_ON(1); + return; + } + + if (ACTIVE_LOW == DISK_LED_CTRL_POLARITY()) { + blEnable = !blEnable; + } + SYNO_GPIO_WRITE(DISK_LED_CTRL_PIN(), blEnable); +} + +void SYNO_ENABLE_PHY_LED(int blEnable) +{ + if (!HAVE_PHY_LED_CTRL()) { + printk("No phy led ctrl pin\n"); + WARN_ON(1); + return; + } + + if (ACTIVE_LOW == PHY_LED_CTRL_POLARITY()) { + blEnable = !blEnable; + } + SYNO_GPIO_WRITE(PHY_LED_CTRL_PIN(), blEnable); +} + +int SYNO_BUZZER_BUTTON_GPIO_GET(unsigned char *pValue) +{ + int tempVal = 0; + + if (!HAVE_MUTE_BUTTON_DETECT()) { + printk("No buzzer mute detect pin\n"); + WARN_ON(1); + return -EINVAL; + } + + tempVal = SYNO_GPIO_READ(MUTE_BUTTON_DETECT_PIN()); + if (ACTIVE_LOW == MUTE_BUTTON_DETECT_POLARITY()) { + *pValue = !tempVal; + } + else { + *pValue = tempVal; + } + + return 0; +} + +int SYNO_CTRL_BUZZER_MUTE_SET(unsigned char pValue) +{ + if (!HAVE_BUZZER_MUTE_CTRL()) { + printk("No buzzer mute ctrl pin\n"); + WARN_ON(1); + return -EINVAL; + } + + SYNO_GPIO_WRITE(BUZZER_MUTE_CTRL_PIN(), pValue); + return 0; +} + +int SYNO_CTRL_RP_FAN(int status) +{ + if (!HAVE_RP_FAN_CTRL()) { + WARN_ON(1); + return -EINVAL; + } + + SYNO_GPIO_WRITE(RP_FAN_CTRL_PIN(), status); + return 0; +} + +/* Set GPIO pin value */ +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if (NULL == pPin) { + goto End; + } + + SYNO_GPIO_WRITE(pPin->pin, pPin->value); + + ret = 0; +End: + return ret; +} + +/* Get GPIO pin value */ +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + if (NULL == pPin) { + goto End; + } + + pPin->value = SYNO_GPIO_READ(pPin->pin); + + ret = 0; +End: + return ret; +} +#endif /* CONFIG_SYNO_GPIO */ + +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} diff --git a/drivers/syno/synobios/common/common.h b/drivers/syno/synobios/common/common.h new file mode 100644 index 000000000000..de8e1a9a8168 --- /dev/null +++ b/drivers/syno/synobios/common/common.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2009-2015 Synology Inc. All rights reserved. */ +#ifndef ARM_COMMON_H +#define ARM_COMMON_H + +#include "synobios.h" +#include +#include +#include "../mapping.h" + +#define GPIO_UNDEF 0xFF + +unsigned int SynoModelIDGet(SYNO_GPIO *pGpio); +int SYNO_CTRL_FAN_RESISTOR(char speed_value); +int SYNO_CTRL_FAN_STATUS_GET(int index, int *pValue); +int SYNO_CTRL_ALARM_LED_SET(int status); +int SYNO_BUZZER_BUTTON_GPIO_GET(unsigned char *pValue); +int SYNO_CTRL_BUZZER_MUTE_SET(unsigned char pValue); +int SYNO_HDD_LED_SET(int index, int status); +int SYNO_COPY_BUTTON_GPIO_GET(void); +void SYNO_ENABLE_HDD_LED(int blEnable); +void SYNO_ENABLE_PHY_LED(int blEnable); +int SYNO_CTRL_RP_FAN(int status); +char* syno_get_hw_version(void); +void check_gpio_consistency(SYNO_GPIO_INFO* pGpio1, SYNO_GPIO_INFO* pGpio2); +int GetBrand(void); +int SetGpioPin( GPIO_PIN *pPin ); +int GetGpioPin( GPIO_PIN *pPin ); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActivePulse(int fanno, FAN_STATUS *pStatus); +/* Implemented on Kernel */ +extern SYNO_GPIO syno_gpio; +int SYNO_GPIO_READ(int pin); +void SYNO_GPIO_WRITE(int pin, int pValue); +int SYNO_CHECK_HDD_DETECT(int index); +#endif /* ARM_COMMON_H */ diff --git a/drivers/syno/synobios/denverton/Makefile b/drivers/syno/synobios/denverton/Makefile new file mode 100644 index 000000000000..bc4c419e7879 --- /dev/null +++ b/drivers/syno/synobios/denverton/Makefile @@ -0,0 +1,33 @@ +include /env.mak + +obj-m += denverton-synobios.o + +denverton-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs2418+.o \ + rs2418rp+.o \ + ds1618+.o \ + rs2818rp+.o \ + ds2419+.o \ + ds1819+.o \ + dva3219.o \ + rs820+.o \ + rs820rp+.o \ + rs1220+.o \ + rs1220rp+.o \ + dva3221.o \ + ds2419+II.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + denverton_common.o + +ifneq (,$(filter $(PLAT_SPEC_VAR), SYNO_FEA_PORT_MAPPING_V2)) +denverton-synobios-objs += \ + ../led/led_trigger.o \ + ../led/led_9235.o +endif diff --git a/drivers/syno/synobios/denverton/denverton_common.c b/drivers/syno/synobios/denverton/denverton_common.c new file mode 100755 index 000000000000..f9b1f038f85a --- /dev/null +++ b/drivers/syno/synobios/denverton/denverton_common.c @@ -0,0 +1,1007 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" + +#include "denverton_common.h" + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif + +static int diskLedEnabled = 0; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +// 14: GPIO_28 (NCSI_RXD0) +// 15: GPIO_29 (NCSI_CLK_IN) +// 16: GPIO_30 (NCSI_RXD1) +// 17: GPIO_31 (NCSI_CRS_DV) +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 4, + .gpio_port = {14, 15, 16, 17}, + .gpio_polarity = ACTIVE_HIGH, +}; +// 98: GPIO_8 (GPIO_8) +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {98}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_32 (NCSI_ARB_IN) +// GPIO_33 (NCSI_TX_EN) +static SYNO_GPIO_INFO redundant_power_detect = { + .nr_gpio = 2, + .gpio_port = {18, 19}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.redundant_power_detect = &redundant_power_detect; +} + +void syno_gpio_cleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.redundant_power_detect = NULL; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int (*GetMaxInternalHostNum)(void) = NULL; +#else +static +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DVA3219: + case MODEL_RS820p: + case MODEL_RS820rpp: + case MODEL_DVA3221: + iMaxInternalDiskNum = 4; + break; + case MODEL_DS1618p: + iMaxInternalDiskNum = 6; + break; + case MODEL_DS1819p: + case MODEL_RS1220p: + case MODEL_RS1220rpp: + iMaxInternalDiskNum = 8; + break; + case MODEL_RS2418p: + case MODEL_RS2418rpp: + case MODEL_DS2419p: + case MODEL_DS2419pII: + iMaxInternalDiskNum = 12; + break; + case MODEL_RS2818rpp: + iMaxInternalDiskNum = 16; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strncmp(gszSynoHWVersion, HW_RS2418rpp, strlen(HW_RS2418rpp) ) ) { + model = MODEL_RS2418rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2418p, strlen(HW_RS2418p) ) ) { + model = MODEL_RS2418p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1618p, strlen(HW_DS1618p) ) ) { + model = MODEL_DS1618p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS2818rpp, strlen(HW_RS2818rpp) ) ) { + model = MODEL_RS2818rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_DS2419p, strlen(HW_DS2419p) ) ) { + model = MODEL_DS2419p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1819p, strlen(HW_DS1819p) ) ) { + model = MODEL_DS1819p; + } else if ( !strncmp(gszSynoHWVersion, HW_DVA3219, strlen(HW_DVA3219) ) ) { + model = MODEL_DVA3219; + } else if ( !strncmp(gszSynoHWVersion, HW_RS820p, strlen(HW_RS820p) ) ) { + model = MODEL_RS820p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS820rpp, strlen(HW_RS820rpp) ) ) { + model = MODEL_RS820rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_RS1220p, strlen(HW_RS1220p) ) ) { + model = MODEL_RS1220p; + } else if ( !strncmp(gszSynoHWVersion, HW_RS1220rpp, strlen(HW_RS1220rpp) ) ) { + model = MODEL_RS1220rpp; + } else if ( !strncmp(gszSynoHWVersion, HW_DVA3221, strlen(HW_DVA3221) ) ) { + model = MODEL_DVA3221; + } else if ( !strncmp(gszSynoHWVersion, HW_DS2419pII, strlen(HW_DS2419pII) ) ) { + model = MODEL_DS2419pII; + } + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +/** + * For consistency of lighting disk led, we need a gpio pin to control cpld behavior + * Which means pull a gpio to let disk led be able to light on + */ +static +void SetHDDLedControl(int blEnable) +{ + GPIO_PIN pin; + + pin.pin = DENVERTON_DISK_LED_ACTIVATE_PIN; + if (blEnable) { + pin.value = 1; + } else { + pin.value = 0; + } + SetGpioPin(&pin); +} + +#ifdef CONFIG_SYNO_LEDS_TRIGGER +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || LP3943_NUM_MAX < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(LP3943_NUM_MAX * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(LP3943_NUM_MAX * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, LP3943_NUM_MAX * sizeof(int)); + memset(gpOrangeLedMap, -1, LP3943_NUM_MAX * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); +} + +static int SetDiskLedStatusByI2CLedDimmer(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (!diskLedEnabled) { + SetHDDLedControl(1); + diskLedEnabled = 1; + } + + if (0 >= iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +#ifdef MY_DEF_HERE +static int SYNOSetDiskLedStatusByI2CLedDimmer(int iHostNum, SYNO_DISK_LED iStatus) +{ + return SetDiskLedStatusByI2CLedDimmer(iHostNum + 1, iStatus); +} +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER + +#ifdef MY_DEF_HERE +static +int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != iStatus) { + SetHDDLedControl(1); + diskLedEnabled = 1; + } + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + return iRet; +} + +static +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (!diskLedEnabled) { + SetHDDLedControl(1); + diskLedEnabled = 1; + } + + if (1 > iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9235GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9235GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx = 0; + + if (NULL == pCpuTemp) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if(0 != iRet) { + goto END; + } + +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int i = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + + + while(HAVE_HDD_DETECT(index)){ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index-1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + index = 1; + + while(HAVE_HDD_ENABLE(index)){ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01 ) << (index-1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + index++; + } + + for (i = 0; i < hdd_backplane->sensor_num; i++) { + if (0 == strncmp(hdd_backplane->sensor[i].sensor_name, HWMON_HDD_BP_DETECT, strlen(HWMON_HDD_BP_DETECT))) { + snprintf(hdd_backplane->sensor[i].value, sizeof(hdd_backplane->sensor[i].value), "%ld", hdd_detect); + } else if (0 == strncmp(hdd_backplane->sensor[i].sensor_name, HWMON_HDD_BP_ENABLE, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[i].value, sizeof(hdd_backplane->sensor[i].value), "%ld", hdd_enable); + } + } + + iRet = 0; + +End: + return iRet; +} + +/* + * For GPIO alert Led, there is no blinking + */ +static +int SetAlarmLedByGPIO(unsigned char type) +{ + GPIO_PIN pin; + int iRet = -1; + + if (type) { + pin.value = 1; + }else{ + pin.value = 0; + } + pin.pin = DENVERTON_ALERT_PIN; + SetGpioPin(&pin); + + iRet = 0; + return iRet; +} + +int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = DENVERTON_BUZZER_OFF_BUTTON_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + } + + ret = 0; +End: + return ret; +} + +int SetRPBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = DENVERTON_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + ret = 0; +End: + return ret; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + /* cpufreq will get wrong value while booting for DNV platform + ,so use cpu_khz which got value from CPU MSR dirctley*/ + unsigned int freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +#define GPIO_POWER_GOOD 1 +int DenvertonRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + GPIO_PIN pinPower1; + GPIO_PIN pinPower2; + int err = -1; + + pinPower1.pin = syno_gpio.redundant_power_detect->gpio_port[0]; + pinPower2.pin = syno_gpio.redundant_power_detect->gpio_port[1]; + if (0 > GetGpioPin(&pinPower1) || 0 > GetGpioPin(&pinPower2)) { + goto END; + } + + + if (pinPower1.value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + } else { + power_info->power_1 = POWER_STATUS_BAD; + } + + if (pinPower2.value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + } else { + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +END: + return err; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLedByGPIO, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .set_buzzer_clear = SetBuzzerClear, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_hdd_led = SetHddActLed, + .set_aha_led = NULL, + .set_power_led = SetPowerLedStatus, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; +#endif + syno_gpio_init(); +#ifdef MY_DEF_HERE + if (0 > syno_libata_disk_map_table_gen(giDiskMapTable)) { + gblDiskNumNeedTran = 0; + } else { + gblDiskNumNeedTran = 1; + } +#endif /* MY_DEF_HERE */ + + switch (GetModel()) { + case MODEL_RS2418rpp: + model_ops = &rs2418rpp_ops; + hwmon_sensor_list = &rs2418rpp_sensor_list; + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ + break; + case MODEL_RS2418p: + model_ops = &rs2418p_ops; + hwmon_sensor_list = &rs2418p_sensor_list; + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS1618p: + model_ops = &ds1618p_ops; + hwmon_sensor_list = &ds1618p_sensor_list; + syno_gpio.fan_fail->nr_gpio = 2; + syno_gpio.fan_fail->gpio_port[0] = 16; + syno_gpio.fan_fail->gpio_port[1] = 14; +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; +#else + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + SetupDiskLedMap((int[6]){0,2,4,6,8,10}, (int[6]){1,3,5,7,9,11}, 6); +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#else + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(4, 1); + syno_ahci_disk_led_enable(5, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS2818rpp: + model_ops = &rs2818rpp_ops; + hwmon_sensor_list = &rs2818rpp_sensor_list; + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS2419p: + model_ops = &ds2419p_ops; + hwmon_sensor_list = &ds2419p_sensor_list; + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ + break; + case MODEL_DS1819p: + model_ops = &ds1819p_ops; + hwmon_sensor_list = &ds1819p_sensor_list; + syno_gpio.fan_fail->nr_gpio = 2; + syno_gpio.fan_fail->gpio_port[0] = 14; + syno_gpio.fan_fail->gpio_port[1] = 16; +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; +#else + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + SetupDiskLedMap((int[8]){0,2,4,6,8,10,12,14}, (int[8]){1,3,5,7,9,11,13,15}, 8); +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#else + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(4, 1); + syno_ahci_disk_led_enable(5, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DVA3219: + model_ops = &dva3219_ops; + hwmon_sensor_list = &dva3219_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + syno_gpio.fan_fail->nr_gpio = 1; + syno_gpio.fan_fail->gpio_port[0] = 14; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS820p: + model_ops = &rs820p_ops; + hwmon_sensor_list = &rs820p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + syno_gpio.fan_fail->nr_gpio = 3; + syno_gpio.fan_fail->gpio_port[0] = 14; + syno_gpio.fan_fail->gpio_port[1] = 16; + syno_gpio.fan_fail->gpio_port[2] = 15; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS820rpp: + model_ops = &rs820rpp_ops; + hwmon_sensor_list = &rs820rpp_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + syno_gpio.fan_fail->nr_gpio = 2; + syno_gpio.fan_fail->gpio_port[0] = 16; + syno_gpio.fan_fail->gpio_port[1] = 15; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS1220p: + model_ops = &rs1220p_ops; + syno_gpio.fan_fail->nr_gpio = 2; + syno_gpio.fan_fail->gpio_port[0] = 14; + syno_gpio.fan_fail->gpio_port[1] = 16; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[8]){0,2,4,6,8,10,12,14}, (int[8]){1,3,5,7,9,11,13,15}, 8); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(4, 1); + syno_ahci_disk_led_enable(5, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS1220rpp: + model_ops = &rs1220rpp_ops; + syno_gpio.fan_fail->nr_gpio = 2; + syno_gpio.fan_fail->gpio_port[0] = 16; + syno_gpio.fan_fail->gpio_port[1] = 14; + syno_gpio.redundant_power_detect->gpio_port[0] = 87; + syno_gpio.redundant_power_detect->gpio_port[1] = 140; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[8]){0,2,4,6,8,10,12,14}, (int[8]){1,3,5,7,9,11,13,15}, 8); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); + syno_ahci_disk_led_enable(4, 1); + syno_ahci_disk_led_enable(5, 1); + syno_ahci_disk_led_enable(6, 1); + syno_ahci_disk_led_enable(7, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DVA3221: + model_ops = &dva3221_ops; + hwmon_sensor_list = &dva3221_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + syno_gpio.fan_fail->nr_gpio = 1; + syno_gpio.fan_fail->gpio_port[0] = 14; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[4]){0,2,4,6}, (int[4]){1,3,5,7}, 4); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByI2CLedDimmer; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY +#ifdef CONFIG_SYNO_SATA_REMAP + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#else + syno_ahci_disk_led_enable(0, 1); + syno_ahci_disk_led_enable(1, 1); + syno_ahci_disk_led_enable(2, 1); + syno_ahci_disk_led_enable(3, 1); +#endif /* CONFIG_SYNO_SATA_REMAP */ +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DS2419pII: + model_ops = &ds2419pII_ops; + hwmon_sensor_list = &ds2419pII_sensor_list; + synobios_ops.set_disk_led = SetDiskLedStatusBy9235GPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SetSCSIHostLedStatusBy9235GPIO; +#endif /* MY_DEF_HERE */ + break; + default : + break; + } + + if (synobios_ops.init_auto_poweron) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/denverton/denverton_common.h b/drivers/syno/synobios/denverton/denverton_common.h new file mode 100755 index 000000000000..9630677a10f9 --- /dev/null +++ b/drivers/syno/synobios/denverton/denverton_common.h @@ -0,0 +1,123 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include "../led/led_9235.h" +#include "../led/led_trigger.h" +#else +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include +#include +#endif +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#include "../common/common.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops rs2418p_ops; +extern struct model_ops rs2418rpp_ops; +extern struct model_ops ds1618p_ops; +extern struct model_ops rs2818rpp_ops; +extern struct model_ops ds2419p_ops; +extern struct model_ops ds1819p_ops; +extern struct model_ops dva3219_ops; +extern struct model_ops rs820p_ops; +extern struct model_ops rs820rpp_ops; +extern struct model_ops rs1220p_ops; +extern struct model_ops rs1220rpp_ops; +extern struct model_ops dva3221_ops; +extern struct model_ops ds2419pII_ops; + +extern struct hwmon_sensor_list rs2418p_sensor_list; +extern struct hwmon_sensor_list rs2418rpp_sensor_list; +extern struct hwmon_sensor_list ds1618p_sensor_list; +extern struct hwmon_sensor_list rs2818rpp_sensor_list; +extern struct hwmon_sensor_list ds2419p_sensor_list; +extern struct hwmon_sensor_list ds1819p_sensor_list; +extern struct hwmon_sensor_list dva3219_sensor_list; +extern struct hwmon_sensor_list rs820p_sensor_list; +extern struct hwmon_sensor_list rs820rpp_sensor_list; +extern struct hwmon_sensor_list dva3221_sensor_list; +extern struct hwmon_sensor_list ds2419pII_sensor_list; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ + +#if defined(MY_DEF_HERE) && defined(MY_DEF_HERE) +extern int syno_libata_disk_map_table_gen(int *iDiskMapTable); +#endif + +#if defined(MY_DEF_HERE) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +#endif /* MY_DEF_HERE && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +#ifdef CONFIG_SYNO_SATA_REMAP +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(CONFIG_SYNO_LEDS_TRIGGER) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#endif /* CONFIG_SYNO_LEDS_TRIGGER && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +/* Fan Sense */ +#define DENVERTON_GPIO_FAN1_SEN 14 // GPIO_28 (NCSI_RXD0) +#define DENVERTON_GPIO_FAN2_SEN 15 // GPIO_29 (NCSI_CLK_IN) +#define DENVERTON_GPIO_FAN3_SEN 16 // GPIO_30 (NCSI_RXD1) +#define DENVERTON_GPIO_FAN4_SEN 17 // GPIO_31 (NCSI_CRS_DV) + +#define DENVERTON_BUZZER_CTRL_PIN 88 // GPIO_6 (GPIO_6) +#define DENVERTON_BUZZER_OFF_BUTTON_PIN 89 // GPIO_7 (GPIO_7) +#define DENVERTON_DISK_LED_ACTIVATE_PIN 98 // GPIO_8 (GPIO_8) +#define DENVERTON_ALERT_PIN 22 // GPIO_36 (NCSI_ARB_OUT) + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/denverton/ds1618+.c b/drivers/syno/synobios/denverton/ds1618+.c new file mode 100644 index 000000000000..c3e085374d3e --- /dev/null +++ b/drivers/syno/synobios/denverton/ds1618+.c @@ -0,0 +1,61 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "denverton_common.h" + +PWM_FAN_SPEED_MAPPING gDS1618pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1618pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1618p = MODULE_T_DS1618p; + module_t *pType = &type_ds1618p; + + module_type_set(pType); + return 0; +} + +static +int DS1618pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1618pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1618pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1618pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1618p_ops = { + .x86_init_module_type = DS1618pInitModuleType, + .x86_fan_speed_mapping = DS1618pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; + +struct hwmon_sensor_list ds1618p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/ds1819+.c b/drivers/syno/synobios/denverton/ds1819+.c new file mode 100644 index 000000000000..36a7b55358af --- /dev/null +++ b/drivers/syno/synobios/denverton/ds1819+.c @@ -0,0 +1,61 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "denverton_common.h" + +PWM_FAN_SPEED_MAPPING gDS1819pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS1819pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds1819p = MODULE_T_DS1819p; + module_t *pType = &type_ds1819p; + + module_type_set(pType); + return 0; +} + +static +int DS1819pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1819pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1819pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1819pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1819p_ops = { + .x86_init_module_type = DS1819pInitModuleType, + .x86_fan_speed_mapping = DS1819pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; + +struct hwmon_sensor_list ds1819p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/ds2419+.c b/drivers/syno/synobios/denverton/ds2419+.c new file mode 100644 index 000000000000..ad4b0b31f72e --- /dev/null +++ b/drivers/syno/synobios/denverton/ds2419+.c @@ -0,0 +1,63 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + + +PWM_FAN_SPEED_MAPPING gDS2419pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS2419pInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds2419p = MODULE_T_DS2419p; + module_t *pType = &type_ds2419p; + + module_type_set(pType); + return 0; +} + +static +int DS2419pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS2419pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS2419pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS2419pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds2419p_ops = { + .x86_init_module_type = DS2419pInitModuleType, + .x86_fan_speed_mapping = DS2419pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, +}; + +struct hwmon_sensor_list ds2419p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/ds2419+II.c b/drivers/syno/synobios/denverton/ds2419+II.c new file mode 100644 index 000000000000..15cd0b080cb5 --- /dev/null +++ b/drivers/syno/synobios/denverton/ds2419+II.c @@ -0,0 +1,63 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + + +PWM_FAN_SPEED_MAPPING gDS2419pIISpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS2419pIIInitModuleType(struct synobios_ops *ops) +{ + module_t type_ds2419pII = MODULE_T_DS2419pII; + module_t *pType = &type_ds2419pII; + + module_type_set(pType); + return 0; +} + +static +int DS2419pIIFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS2419pIISpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS2419pIISpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS2419pIISpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds2419pII_ops = { + .x86_init_module_type = DS2419pIIInitModuleType, + .x86_fan_speed_mapping = DS2419pIIFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, + .x86_get_power_status = NULL, +}; + +struct hwmon_sensor_list ds2419pII_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/denverton/dva3219.c b/drivers/syno/synobios/denverton/dva3219.c new file mode 100644 index 000000000000..2d0de257965d --- /dev/null +++ b/drivers/syno/synobios/denverton/dva3219.c @@ -0,0 +1,95 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "denverton_common.h" + +PWM_FAN_SPEED_MAPPING gDVA3219SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {89,87,16,21}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE dva3219_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, +}; + +static +int DVA3219InitModuleType(struct synobios_ops *ops) +{ + module_t type_dva3219 = MODULE_T_DVA3219; + module_t *pType = &type_dva3219; + + module_type_set(pType); + return 0; +} + +static +int DVA3219FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDVA3219SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDVA3219SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDVA3219SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +void DVA3219GpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } +} + +static +void DVA3219GpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } +} + +struct model_ops dva3219_ops = { + .x86_init_module_type = DVA3219InitModuleType, + .x86_fan_speed_mapping = DVA3219FanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, + .x86_gpio_init = DVA3219GpioInit, + .x86_gpio_cleanup = DVA3219GpioCleanup, +}; + +struct hwmon_sensor_list dva3219_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &dva3219_hdd_backplane_status, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/dva3221.c b/drivers/syno/synobios/denverton/dva3221.c new file mode 100644 index 000000000000..43e9ec186b20 --- /dev/null +++ b/drivers/syno/synobios/denverton/dva3221.c @@ -0,0 +1,95 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "denverton_common.h" + +PWM_FAN_SPEED_MAPPING gDVA3221SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {89,87,16,21}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE dva3221_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, +}; + +static +int DVA3221InitModuleType(struct synobios_ops *ops) +{ + module_t type_dva3221 = MODULE_T_DVA3221; + module_t *pType = &type_dva3221; + + module_type_set(pType); + return 0; +} + +static +int DVA3221FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDVA3221SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDVA3221SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDVA3221SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +void DVA3221GpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } +} + +static +void DVA3221GpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } +} + +struct model_ops dva3221_ops = { + .x86_init_module_type = DVA3221InitModuleType, + .x86_fan_speed_mapping = DVA3221FanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, + .x86_gpio_init = DVA3221GpioInit, + .x86_gpio_cleanup = DVA3221GpioCleanup, +}; + +struct hwmon_sensor_list dva3221_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &dva3221_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/denverton/rs1220+.c b/drivers/syno/synobios/denverton/rs1220+.c new file mode 100644 index 000000000000..c8da8fe274d5 --- /dev/null +++ b/drivers/syno/synobios/denverton/rs1220+.c @@ -0,0 +1,56 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS1220pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS1220pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs1220p = MODULE_T_RS1220p; + module_t *pType = &type_rs1220p; + + module_type_set(pType); + return 0; +} + +static +int RS1220pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS1220pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS1220pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS1220pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs1220p_ops = { + .x86_init_module_type = RS1220pInitModuleType, + .x86_fan_speed_mapping = RS1220pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = NULL, +}; diff --git a/drivers/syno/synobios/denverton/rs1220rp+.c b/drivers/syno/synobios/denverton/rs1220rp+.c new file mode 100644 index 000000000000..8f62de115112 --- /dev/null +++ b/drivers/syno/synobios/denverton/rs1220rp+.c @@ -0,0 +1,59 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int SetRPBuzzerClear(unsigned char buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS1220rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS1220rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs1220rpp = MODULE_T_RS1220rpp; + module_t *pType = &type_rs1220rpp; + + module_type_set(pType); + return 0; +} + +static +int RS1220rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS1220rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS1220rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS1220rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs1220rpp_ops = { + .x86_init_module_type = RS1220rppInitModuleType, + .x86_fan_speed_mapping = RS1220rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = DenvertonRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = NULL, +}; diff --git a/drivers/syno/synobios/denverton/rs2418+.c b/drivers/syno/synobios/denverton/rs2418+.c new file mode 100644 index 000000000000..61297897f7a8 --- /dev/null +++ b/drivers/syno/synobios/denverton/rs2418+.c @@ -0,0 +1,64 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS2418pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2418pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2418p = MODULE_T_RS2418p; + module_t *pType = &type_rs2418p; + + module_type_set(pType); + return 0; +} + +static +int RS2418pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2418pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2418pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2418pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2418p_ops = { + .x86_init_module_type = RS2418pInitModuleType, + .x86_fan_speed_mapping = RS2418pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = NULL, +}; + +struct hwmon_sensor_list rs2418p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/rs2418rp+.c b/drivers/syno/synobios/denverton/rs2418rp+.c new file mode 100644 index 000000000000..a84e3d0f02f3 --- /dev/null +++ b/drivers/syno/synobios/denverton/rs2418rp+.c @@ -0,0 +1,67 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int SetRPBuzzerClear(unsigned char buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS2418rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2418rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2418rpp = MODULE_T_RS2418rpp; + module_t *pType = &type_rs2418rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2418rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2418rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2418rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2418rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2418rpp_ops = { + .x86_init_module_type = RS2418rppInitModuleType, + .x86_fan_speed_mapping = RS2418rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = DenvertonRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = SetRPBuzzerClear, +}; + +struct hwmon_sensor_list rs2418rpp_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/rs2818rp+.c b/drivers/syno/synobios/denverton/rs2818rp+.c new file mode 100644 index 000000000000..7f51de9bd4d6 --- /dev/null +++ b/drivers/syno/synobios/denverton/rs2818rp+.c @@ -0,0 +1,67 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int SetRPBuzzerClear(unsigned char buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS2818rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int RS2818rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2818rpp = MODULE_T_RS2818rpp; + module_t *pType = &type_rs2818rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2818rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2818rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2818rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2818rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2818rpp_ops = { + .x86_init_module_type = RS2818rppInitModuleType, + .x86_fan_speed_mapping = RS2818rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = DenvertonRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = SetRPBuzzerClear, +}; + +struct hwmon_sensor_list rs2818rpp_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = NULL, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/denverton/rs820+.c b/drivers/syno/synobios/denverton/rs820+.c new file mode 100644 index 000000000000..690895c3c29e --- /dev/null +++ b/drivers/syno/synobios/denverton/rs820+.c @@ -0,0 +1,118 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS820pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {86,87,88,0}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {140,2,17,90}, + .gpio_polarity = ACTIVE_HIGH, +}; + +SYNO_HWMON_SENSOR_TYPE rs820p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS820pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs820p = MODULE_T_RS820p; + module_t *pType = &type_rs820p; + + module_type_set(pType); + return 0; +} + +static +int RS820pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS820pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS820pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS820pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +void RS820pGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +} + +static +void RS820pGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +} + +struct model_ops rs820p_ops = { + .x86_init_module_type = RS820pInitModuleType, + .x86_fan_speed_mapping = RS820pFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = NULL, + .x86_gpio_init = RS820pGpioInit, + .x86_gpio_cleanup = RS820pGpioCleanup, +}; + +struct hwmon_sensor_list rs820p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &rs820p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/denverton/rs820rp+.c b/drivers/syno/synobios/denverton/rs820rp+.c new file mode 100644 index 000000000000..6cd10eddf63c --- /dev/null +++ b/drivers/syno/synobios/denverton/rs820rp+.c @@ -0,0 +1,120 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "denverton_common.h" + +extern int DenvertonRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int DenvertonGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int SetRPBuzzerClear(unsigned char buzzer_cleared); + +PWM_FAN_SPEED_MAPPING gRS820rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {86,87,88,0}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {140,2,17,90}, + .gpio_polarity = ACTIVE_HIGH, +}; + +SYNO_HWMON_SENSOR_TYPE rs820rpp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS820rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs820rpp = MODULE_T_RS820rpp; + module_t *pType = &type_rs820rpp; + + module_type_set(pType); + return 0; +} + +static +int RS820rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS820rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS820rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS820rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +void RS820rppGpioInit(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +} + +static +void RS820rppGpioCleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +} + +struct model_ops rs820rpp_ops = { + .x86_init_module_type = RS820rppInitModuleType, + .x86_fan_speed_mapping = RS820rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = DenvertonGetBuzzerCleared, + .x86_get_power_status = DenvertonRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = NULL, + .x86_gpio_init = RS820rppGpioInit, + .x86_gpio_cleanup = RS820rppGpioCleanup, +}; + +struct hwmon_sensor_list rs820rpp_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &rs820rpp_hdd_backplane_status, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/epyc7002/Makefile b/drivers/syno/synobios/epyc7002/Makefile new file mode 100644 index 000000000000..b8661c75c4fa --- /dev/null +++ b/drivers/syno/synobios/epyc7002/Makefile @@ -0,0 +1,21 @@ +ccflags-y := -DSYNO_PLATFORM=\"EPYC7002\" +obj-$(CONFIG_SYNO_SYNOBIOS) += synobios.o + +synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + ../led/led_trigger.o \ + ../pmbus/pmbus.o \ + epyc7002_common.o \ + fs6400n.o \ + fs6410.o \ + sa6400.o \ + sa6200.o \ + sc6200.o diff --git a/drivers/syno/synobios/epyc7002/epyc7002_common.c b/drivers/syno/synobios/epyc7002/epyc7002_common.c new file mode 100755 index 000000000000..692e25e585bc --- /dev/null +++ b/drivers/syno/synobios/epyc7002/epyc7002_common.c @@ -0,0 +1,642 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_HWMON_PMBUS +#include +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "../pmbus/pmbus.h" + +#include "epyc7002_common.h" + +#define GPIO_POWER_GOOD 1 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strcmp(gszSynoHWVersion, HW_FS6400N) ) { + model = MODEL_FS6400N; + } else if ( !strcmp(gszSynoHWVersion, HW_FS6410) ) { + model = MODEL_FS6410; + } else if ( !strcmp(gszSynoHWVersion, HW_SA6400) ) { + model = MODEL_SA6400; + } else if ( !strcmp(gszSynoHWVersion, HW_SA6200) ) { + model = MODEL_SA6200; + } else if ( !strcmp(gszSynoHWVersion, HW_SC6200) ) { + model = MODEL_SC6200; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_FS6400N: + case MODEL_FS6410: + iInternalDiskNum = 24; + break; + case MODEL_SA6400: + case MODEL_SA6200: + case MODEL_SC6200: + iInternalDiskNum = 12; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) + iRet = syno_k10cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +END: + return iRet; +} + + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +#if defined(CONFIG_SYNO_HWMON_PMBUS) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +int EPYC7002RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info) +{ + int iRet = -1; + + if (NULL == power_info) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + if (0 > I2CPmbusReadPowerStatus(0, &(power_info->power_1))) { + goto END; + } + if (0 > I2CPmbusReadPowerStatus(1, &(power_info->power_2))) { + goto END; + } + + iRet = 0; + +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int EPYC7002GetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + + if (NULL == hwmon_sensor_list) { + goto END; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + iRet = HWMONGetPSUStatusByI2C(psu_status, iPsuNumber); +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + DISKLEDSTATUS diskLedStatus; + const char* abbrName[] = {"internal", "sys"}; + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_FS6400N: + model_ops = &fs6400n_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs6400n_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + break; + + case MODEL_FS6410: + model_ops = &fs6410_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs6410_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); + syno_ahci_disk_led_enable_by_port(13, 1); + syno_ahci_disk_led_enable_by_port(14, 1); + syno_ahci_disk_led_enable_by_port(15, 1); + syno_ahci_disk_led_enable_by_port(16, 1); + syno_ahci_disk_led_enable_by_port(17, 1); + syno_ahci_disk_led_enable_by_port(18, 1); + syno_ahci_disk_led_enable_by_port(19, 1); + syno_ahci_disk_led_enable_by_port(20, 1); + syno_ahci_disk_led_enable_by_port(21, 1); + syno_ahci_disk_led_enable_by_port(22, 1); + syno_ahci_disk_led_enable_by_port(23, 1); + syno_ahci_disk_led_enable_by_port(24, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SA6400: + model_ops = &sa6400_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sa6400_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SA6200: + model_ops = &sa6200_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sa6200_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SC6200: + model_ops = &sc6200_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sc6200_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/epyc7002/epyc7002_common.h b/drivers/syno/synobios/epyc7002/epyc7002_common.h new file mode 100755 index 000000000000..23971ad5b88c --- /dev/null +++ b/drivers/syno/synobios/epyc7002/epyc7002_common.h @@ -0,0 +1,79 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern char gszSynoHWVersion[]; +extern struct model_ops fs6400n_ops; +extern struct model_ops fs6410_ops; +extern struct model_ops sa6400_ops; +extern struct model_ops sa6200_ops; +extern struct model_ops sc6200_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list fs6400n_sensor_list; +extern struct hwmon_sensor_list fs6410_sensor_list; +extern struct hwmon_sensor_list sa6400_sensor_list; +extern struct hwmon_sensor_list sa6200_sensor_list; +extern struct hwmon_sensor_list sc6200_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) +extern int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/epyc7002/fs6400n.c b/drivers/syno/synobios/epyc7002/fs6400n.c new file mode 100644 index 000000000000..e433fe30ccb0 --- /dev/null +++ b/drivers/syno/synobios/epyc7002/fs6400n.c @@ -0,0 +1,191 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gFS6400NSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int FS6400NGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void FS6400NGpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void FS6400NGpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; +} + +static +int FS6400NInitModuleType(struct synobios_ops *ops) +{ + module_t type_FS6400N = MODULE_T_FS6400N; + module_t *pType = &type_FS6400N; + + module_type_set(pType); + return 0; +} + +static +int FS6400NFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS6400NSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS6400NSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS6400NSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs6400n_ops = { + .x86_init_module_type = FS6400NInitModuleType, + .x86_fan_speed_mapping = FS6400NFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = FS6400NGetBuzzerCleared, + .x86_gpio_init = FS6400NGpioInit, + .x86_gpio_cleanup = FS6400NGpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002RedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list fs6400n_sensor_list = { + .thermal_sensor = &FS6400N_thermal_sensor, + .voltage_sensor = &FS6400N_voltage_sensor, + .fan_speed_rpm = &FS6400N_fan_speed_rpm, + .psu_status = FS6400N_psu_status, + .hdd_backplane = &FS6400N_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002/fs6410.c b/drivers/syno/synobios/epyc7002/fs6410.c new file mode 100644 index 000000000000..5bca278f6a1b --- /dev/null +++ b/drivers/syno/synobios/epyc7002/fs6410.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gFS6410SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int FS6410GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void FS6410GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void FS6410GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int FS6410InitModuleType(struct synobios_ops *ops) +{ + module_t type_FS6410 = MODULE_T_FS6410; + module_t *pType = &type_FS6410; + + module_type_set(pType); + return 0; +} + +static +int FS6410FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS6410SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS6410SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS6410SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs6410_ops = { + .x86_init_module_type = FS6410InitModuleType, + .x86_fan_speed_mapping = FS6410FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = FS6410GetBuzzerCleared, + .x86_gpio_init = FS6410GpioInit, + .x86_gpio_cleanup = FS6410GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002RedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list fs6410_sensor_list = { + .thermal_sensor = &FS6410_thermal_sensor, + .voltage_sensor = &FS6410_voltage_sensor, + .fan_speed_rpm = &FS6410_fan_speed_rpm, + .psu_status = FS6410_psu_status, + .hdd_backplane = &FS6410_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002/sa6200.c b/drivers/syno/synobios/epyc7002/sa6200.c new file mode 100644 index 000000000000..e04b44a1632f --- /dev/null +++ b/drivers/syno/synobios/epyc7002/sa6200.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif + +PWM_FAN_SPEED_MAPPING gSA6200SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SA6200GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void SA6200GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void SA6200GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int SA6200InitModuleType(struct synobios_ops *ops) +{ + module_t type_SA6200 = MODULE_T_SA6200; + module_t *pType = &type_SA6200; + + module_type_set(pType); + return 0; +} + +static +int SA6200FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSA6200SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSA6200SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSA6200SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sa6200_ops = { + .x86_init_module_type = SA6200InitModuleType, + .x86_fan_speed_mapping = SA6200FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SA6200GetBuzzerCleared, + .x86_gpio_init = SA6200GpioInit, + .x86_gpio_cleanup = SA6200GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002RedundantPowerGetPowerStatusByI2C, +#endif +}; + +struct hwmon_sensor_list sa6200_sensor_list = { + .thermal_sensor = &SA6200_thermal_sensor, + .voltage_sensor = &SA6200_voltage_sensor, + .fan_speed_rpm = &SA6200_fan_speed_rpm, + .psu_status = SA6200_psu_status, + .hdd_backplane = &SA6200_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002/sa6400.c b/drivers/syno/synobios/epyc7002/sa6400.c new file mode 100644 index 000000000000..4846e56be528 --- /dev/null +++ b/drivers/syno/synobios/epyc7002/sa6400.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif + +PWM_FAN_SPEED_MAPPING gSA6400SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SA6400GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void SA6400GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void SA6400GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int SA6400InitModuleType(struct synobios_ops *ops) +{ + module_t type_SA6400 = MODULE_T_SA6400; + module_t *pType = &type_SA6400; + + module_type_set(pType); + return 0; +} + +static +int SA6400FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSA6400SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSA6400SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSA6400SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sa6400_ops = { + .x86_init_module_type = SA6400InitModuleType, + .x86_fan_speed_mapping = SA6400FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SA6400GetBuzzerCleared, + .x86_gpio_init = SA6400GpioInit, + .x86_gpio_cleanup = SA6400GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002RedundantPowerGetPowerStatusByI2C, +#endif +}; + +struct hwmon_sensor_list sa6400_sensor_list = { + .thermal_sensor = &SA6400_thermal_sensor, + .voltage_sensor = &SA6400_voltage_sensor, + .fan_speed_rpm = &SA6400_fan_speed_rpm, + .psu_status = SA6400_psu_status, + .hdd_backplane = &SA6400_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002/sc6200.c b/drivers/syno/synobios/epyc7002/sc6200.c new file mode 100644 index 000000000000..3e61ae9761b7 --- /dev/null +++ b/drivers/syno/synobios/epyc7002/sc6200.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif + +PWM_FAN_SPEED_MAPPING gSC6200SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SC6200GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void SC6200GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void SC6200GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int SC6200InitModuleType(struct synobios_ops *ops) +{ + module_t type_SC6200 = MODULE_T_SC6200; + module_t *pType = &type_SC6200; + + module_type_set(pType); + return 0; +} + +static +int SC6200FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSC6200SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSC6200SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSC6200SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sc6200_ops = { + .x86_init_module_type = SC6200InitModuleType, + .x86_fan_speed_mapping = SC6200FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SC6200GetBuzzerCleared, + .x86_gpio_init = SC6200GpioInit, + .x86_gpio_cleanup = SC6200GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002RedundantPowerGetPowerStatusByI2C, +#endif +}; + +struct hwmon_sensor_list sc6200_sensor_list = { + .thermal_sensor = &SC6200_thermal_sensor, + .voltage_sensor = &SC6200_voltage_sensor, + .fan_speed_rpm = &SC6200_fan_speed_rpm, + .psu_status = SC6200_psu_status, + .hdd_backplane = &SC6200_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002sofs/Makefile b/drivers/syno/synobios/epyc7002sofs/Makefile new file mode 100644 index 000000000000..324de1fef731 --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/Makefile @@ -0,0 +1,22 @@ +include /env.mak + +obj-m += epyc7002sofs-synobios.o + +epyc7002sofs-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + ../led/led_trigger.o \ + ../pmbus/pmbus.o \ + epyc7002sofs_common.o \ + fs6400n.o \ + fs6410.o \ + sa6400.o \ + sa6200.o \ + sc6200.o diff --git a/drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.c b/drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.c new file mode 100755 index 000000000000..c96e64e8ebe9 --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.c @@ -0,0 +1,642 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_HWMON_PMBUS +#include +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "../pmbus/pmbus.h" + +#include "epyc7002sofs_common.h" + +#define GPIO_POWER_GOOD 1 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strcmp(gszSynoHWVersion, HW_FS6400N) ) { + model = MODEL_FS6400N; + } else if ( !strcmp(gszSynoHWVersion, HW_FS6410) ) { + model = MODEL_FS6410; + } else if ( !strcmp(gszSynoHWVersion, HW_SA6400) ) { + model = MODEL_SA6400; + } else if ( !strcmp(gszSynoHWVersion, HW_SA6200) ) { + model = MODEL_SA6200; + } else if ( !strcmp(gszSynoHWVersion, HW_SC6200) ) { + model = MODEL_SC6200; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_FS6400N: + case MODEL_FS6410: + iInternalDiskNum = 24; + break; + case MODEL_SA6400: + case MODEL_SA6200: + case MODEL_SC6200: + iInternalDiskNum = 12; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) + iRet = syno_k10cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +END: + return iRet; +} + + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +#if defined(CONFIG_SYNO_HWMON_PMBUS) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +int EPYC7002SOFSRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info) +{ + int iRet = -1; + + if (NULL == power_info) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + if (0 > I2CPmbusReadPowerStatus(0, &(power_info->power_1))) { + goto END; + } + if (0 > I2CPmbusReadPowerStatus(1, &(power_info->power_2))) { + goto END; + } + + iRet = 0; + +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int EPYC7002SOFSGetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + + if (NULL == hwmon_sensor_list) { + goto END; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + iRet = HWMONGetPSUStatusByI2C(psu_status, iPsuNumber); +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + DISKLEDSTATUS diskLedStatus; + const char* abbrName[] = {"internal", "sys"}; + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_FS6400N: + model_ops = &fs6400n_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs6400n_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + break; + + case MODEL_FS6410: + model_ops = &fs6410_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs6410_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002SOFSGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); + syno_ahci_disk_led_enable_by_port(13, 1); + syno_ahci_disk_led_enable_by_port(14, 1); + syno_ahci_disk_led_enable_by_port(15, 1); + syno_ahci_disk_led_enable_by_port(16, 1); + syno_ahci_disk_led_enable_by_port(17, 1); + syno_ahci_disk_led_enable_by_port(18, 1); + syno_ahci_disk_led_enable_by_port(19, 1); + syno_ahci_disk_led_enable_by_port(20, 1); + syno_ahci_disk_led_enable_by_port(21, 1); + syno_ahci_disk_led_enable_by_port(22, 1); + syno_ahci_disk_led_enable_by_port(23, 1); + syno_ahci_disk_led_enable_by_port(24, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SA6400: + model_ops = &sa6400_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sa6400_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002SOFSGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SA6200: + model_ops = &sa6200_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sa6200_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002SOFSGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SC6200: + model_ops = &sc6200_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sc6200_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = EPYC7002SOFSGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); + syno_ahci_disk_led_enable_by_port(9, 1); + syno_ahci_disk_led_enable_by_port(10, 1); + syno_ahci_disk_led_enable_by_port(11, 1); + syno_ahci_disk_led_enable_by_port(12, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.h b/drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.h new file mode 100755 index 000000000000..23971ad5b88c --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/epyc7002sofs_common.h @@ -0,0 +1,79 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern char gszSynoHWVersion[]; +extern struct model_ops fs6400n_ops; +extern struct model_ops fs6410_ops; +extern struct model_ops sa6400_ops; +extern struct model_ops sa6200_ops; +extern struct model_ops sc6200_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list fs6400n_sensor_list; +extern struct hwmon_sensor_list fs6410_sensor_list; +extern struct hwmon_sensor_list sa6400_sensor_list; +extern struct hwmon_sensor_list sa6200_sensor_list; +extern struct hwmon_sensor_list sc6200_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) +extern int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/epyc7002sofs/fs6400n.c b/drivers/syno/synobios/epyc7002sofs/fs6400n.c new file mode 100644 index 000000000000..658522cef682 --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/fs6400n.c @@ -0,0 +1,191 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002sofs_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002SOFSRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gFS6400NSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400N_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int FS6400NGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void FS6400NGpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void FS6400NGpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; +} + +static +int FS6400NInitModuleType(struct synobios_ops *ops) +{ + module_t type_FS6400N = MODULE_T_FS6400N; + module_t *pType = &type_FS6400N; + + module_type_set(pType); + return 0; +} + +static +int FS6400NFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS6400NSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS6400NSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS6400NSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs6400n_ops = { + .x86_init_module_type = FS6400NInitModuleType, + .x86_fan_speed_mapping = FS6400NFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = FS6400NGetBuzzerCleared, + .x86_gpio_init = FS6400NGpioInit, + .x86_gpio_cleanup = FS6400NGpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002SOFSRedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list fs6400n_sensor_list = { + .thermal_sensor = &FS6400N_thermal_sensor, + .voltage_sensor = &FS6400N_voltage_sensor, + .fan_speed_rpm = &FS6400N_fan_speed_rpm, + .psu_status = FS6400N_psu_status, + .hdd_backplane = &FS6400N_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002sofs/fs6410.c b/drivers/syno/synobios/epyc7002sofs/fs6410.c new file mode 100644 index 000000000000..c3f59f0940bd --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/fs6410.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002sofs_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002SOFSRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gFS6410SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6410_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int FS6410GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void FS6410GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void FS6410GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int FS6410InitModuleType(struct synobios_ops *ops) +{ + module_t type_FS6410 = MODULE_T_FS6410; + module_t *pType = &type_FS6410; + + module_type_set(pType); + return 0; +} + +static +int FS6410FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS6410SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS6410SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS6410SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs6410_ops = { + .x86_init_module_type = FS6410InitModuleType, + .x86_fan_speed_mapping = FS6410FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = FS6410GetBuzzerCleared, + .x86_gpio_init = FS6410GpioInit, + .x86_gpio_cleanup = FS6410GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002SOFSRedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list fs6410_sensor_list = { + .thermal_sensor = &FS6410_thermal_sensor, + .voltage_sensor = &FS6410_voltage_sensor, + .fan_speed_rpm = &FS6410_fan_speed_rpm, + .psu_status = FS6410_psu_status, + .hdd_backplane = &FS6410_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002sofs/sa6200.c b/drivers/syno/synobios/epyc7002sofs/sa6200.c new file mode 100644 index 000000000000..1462413d45e1 --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/sa6200.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002sofs_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002SOFSRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif + +PWM_FAN_SPEED_MAPPING gSA6200SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6200_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SA6200GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void SA6200GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void SA6200GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int SA6200InitModuleType(struct synobios_ops *ops) +{ + module_t type_SA6200 = MODULE_T_SA6200; + module_t *pType = &type_SA6200; + + module_type_set(pType); + return 0; +} + +static +int SA6200FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSA6200SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSA6200SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSA6200SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sa6200_ops = { + .x86_init_module_type = SA6200InitModuleType, + .x86_fan_speed_mapping = SA6200FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SA6200GetBuzzerCleared, + .x86_gpio_init = SA6200GpioInit, + .x86_gpio_cleanup = SA6200GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002SOFSRedundantPowerGetPowerStatusByI2C, +#endif +}; + +struct hwmon_sensor_list sa6200_sensor_list = { + .thermal_sensor = &SA6200_thermal_sensor, + .voltage_sensor = &SA6200_voltage_sensor, + .fan_speed_rpm = &SA6200_fan_speed_rpm, + .psu_status = SA6200_psu_status, + .hdd_backplane = &SA6200_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002sofs/sa6400.c b/drivers/syno/synobios/epyc7002sofs/sa6400.c new file mode 100644 index 000000000000..3bbd9656314b --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/sa6400.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002sofs_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002SOFSRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif + +PWM_FAN_SPEED_MAPPING gSA6400SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6400_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SA6400GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void SA6400GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void SA6400GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int SA6400InitModuleType(struct synobios_ops *ops) +{ + module_t type_SA6400 = MODULE_T_SA6400; + module_t *pType = &type_SA6400; + + module_type_set(pType); + return 0; +} + +static +int SA6400FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSA6400SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSA6400SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSA6400SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sa6400_ops = { + .x86_init_module_type = SA6400InitModuleType, + .x86_fan_speed_mapping = SA6400FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SA6400GetBuzzerCleared, + .x86_gpio_init = SA6400GpioInit, + .x86_gpio_cleanup = SA6400GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002SOFSRedundantPowerGetPowerStatusByI2C, +#endif +}; + +struct hwmon_sensor_list sa6400_sensor_list = { + .thermal_sensor = &SA6400_thermal_sensor, + .voltage_sensor = &SA6400_voltage_sensor, + .fan_speed_rpm = &SA6400_fan_speed_rpm, + .psu_status = SA6400_psu_status, + .hdd_backplane = &SA6400_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7002sofs/sc6200.c b/drivers/syno/synobios/epyc7002sofs/sc6200.c new file mode 100644 index 000000000000..25fc58d4c46c --- /dev/null +++ b/drivers/syno/synobios/epyc7002sofs/sc6200.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7002sofs_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7002SOFSRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif + +PWM_FAN_SPEED_MAPPING gSC6200SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC6200_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SC6200GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void SC6200GpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void SC6200GpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int SC6200InitModuleType(struct synobios_ops *ops) +{ + module_t type_SC6200 = MODULE_T_SC6200; + module_t *pType = &type_SC6200; + + module_type_set(pType); + return 0; +} + +static +int SC6200FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSC6200SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSC6200SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSC6200SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sc6200_ops = { + .x86_init_module_type = SC6200InitModuleType, + .x86_fan_speed_mapping = SC6200FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SC6200GetBuzzerCleared, + .x86_gpio_init = SC6200GpioInit, + .x86_gpio_cleanup = SC6200GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7002SOFSRedundantPowerGetPowerStatusByI2C, +#endif +}; + +struct hwmon_sensor_list sc6200_sensor_list = { + .thermal_sensor = &SC6200_thermal_sensor, + .voltage_sensor = &SC6200_voltage_sensor, + .fan_speed_rpm = &SC6200_fan_speed_rpm, + .psu_status = SC6200_psu_status, + .hdd_backplane = &SC6200_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/epyc7003ntb/Makefile b/drivers/syno/synobios/epyc7003ntb/Makefile new file mode 100644 index 000000000000..08848de7b50c --- /dev/null +++ b/drivers/syno/synobios/epyc7003ntb/Makefile @@ -0,0 +1,18 @@ +include /env.mak + +obj-m += epyc7003ntb-synobios.o + +epyc7003ntb-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + ../led/led_trigger.o \ + ../pmbus/pmbus.o \ + epyc7003ntb_common.o \ + fs6600dn.o \ diff --git a/drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.c b/drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.c new file mode 100755 index 000000000000..6463b0feddbf --- /dev/null +++ b/drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.c @@ -0,0 +1,445 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_HWMON_PMBUS +#include +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "../pmbus/pmbus.h" + +#include "epyc7003ntb_common.h" + +#define GPIO_POWER_GOOD 1 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strcmp(gszSynoHWVersion, HW_FS6600DN) ) { + model = MODEL_FS6600DN; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_FS6600DN: + iInternalDiskNum = 48; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) + iRet = syno_k10cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +END: + return iRet; +} + + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +#if defined(CONFIG_SYNO_HWMON_PMBUS) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +int EPYC7003NTBRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info) +{ + int iRet = -1; + + if (NULL == power_info) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + if (0 > I2CPmbusReadPowerStatus(0, &(power_info->power_1))) { + goto END; + } + if (0 > I2CPmbusReadPowerStatus(1, &(power_info->power_2))) { + goto END; + } + + iRet = 0; + +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int EPYC7003NTBGetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + + if (NULL == hwmon_sensor_list) { + goto END; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + iRet = HWMONGetPSUStatusByI2C(psu_status, iPsuNumber); +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + DISKLEDSTATUS diskLedStatus; + const char* abbrName[] = {"internal", "sys"}; + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_FS6600DN: + model_ops = &fs6600dn_ops; + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs6600dn_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; + synobios_ops.hwmon_get_psu_status = EPYC7003NTBGetPSUStatusByI2C; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.h b/drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.h new file mode 100755 index 000000000000..377d51f016dd --- /dev/null +++ b/drivers/syno/synobios/epyc7003ntb/epyc7003ntb_common.h @@ -0,0 +1,71 @@ +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern char gszSynoHWVersion[]; +extern struct model_ops fs6600dn_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list fs6600dn_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) +extern int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/epyc7003ntb/fs6600dn.c b/drivers/syno/synobios/epyc7003ntb/fs6600dn.c new file mode 100644 index 000000000000..fc0dc25cd922 --- /dev/null +++ b/drivers/syno/synobios/epyc7003ntb/fs6600dn.c @@ -0,0 +1,202 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "epyc7003ntb_common.h" +#include "../i2c/i2c-linux.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int EPYC7003NTBRedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gFS6600DNSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600DN_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600DN_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600DN_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600DN_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600DN_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int FS6600DNGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_31 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {31}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {137}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void FS6600DNGpioInit(void) +{ + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.alarm_led = &alarm_led; +} + +static +void FS6600DNGpioCleanup(void) +{ + syno_gpio.mute_button_detect = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int FS6600DNInitModuleType(struct synobios_ops *ops) +{ + module_t type_FS6600DN = MODULE_T_FS6600DN; + module_t *pType = &type_FS6600DN; + + module_type_set(pType); + return 0; +} + +static +int FS6600DNFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS6600DNSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS6600DNSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS6600DNSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs6600dn_ops = { + .x86_init_module_type = FS6600DNInitModuleType, + .x86_fan_speed_mapping = FS6600DNFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = FS6600DNGetBuzzerCleared, + .x86_gpio_init = FS6600DNGpioInit, + .x86_gpio_cleanup = FS6600DNGpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = EPYC7003NTBRedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list fs6600dn_sensor_list = { + .thermal_sensor = &FS6600DN_thermal_sensor, + .voltage_sensor = &FS6600DN_voltage_sensor, + .fan_speed_rpm = &FS6600DN_fan_speed_rpm, + .psu_status = FS6600DN_psu_status, + .hdd_backplane = &FS6600DN_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/evansport/Makefile b/drivers/syno/synobios/evansport/Makefile new file mode 100644 index 000000000000..361f63861d7f --- /dev/null +++ b/drivers/syno/synobios/evansport/Makefile @@ -0,0 +1,16 @@ +obj-m += evansport-synobios.o + +evansport-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds214play.o \ + ds415play.o \ + ds114+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + evansport_common.o diff --git a/drivers/syno/synobios/evansport/ds114+.c b/drivers/syno/synobios/evansport/ds114+.c new file mode 100644 index 000000000000..442cc8091d30 --- /dev/null +++ b/drivers/syno/synobios/evansport/ds114+.c @@ -0,0 +1,79 @@ +// Copyright (c) 2000-2011 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include "evansport_common.h" + +PWM_FAN_SPEED_MAPPING gDS114pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS114pInitModuleType(struct synobios_ops *ops) +{ + module_t type_114p = MODULE_T_DS114pv1; + module_t *pType = &type_114p; + + module_type_set(pType); + return 0; +} + +static +int DS114pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS114pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS114pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS114pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +#define SZ_CMD_LED_ESATA_ON "LE1" +#define SZ_CMD_LED_ESATA_BLINK "LE2" +#define SZ_CMD_LED_ESATA_OFF "LE3" +static +int DS114pSetEsataLedStatus(SYNO_DISK_LED status) +{ + int iRet = -1; + + switch ( status ) { + case DISK_LED_OFF: + SetUart(SZ_CMD_LED_ESATA_OFF); + break; + case DISK_LED_GREEN_SOLID: + SetUart(SZ_CMD_LED_ESATA_ON); + break; + default: + printk("%s:%d No such eSata LED operation.", __FILE__, __LINE__); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +struct model_ops ds114p_ops = { + .x86_init_module_type = DS114pInitModuleType, + .x86_fan_speed_mapping = DS114pFanSpeedMapping, + .x86_set_esata_led_status = DS114pSetEsataLedStatus, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/evansport/ds214play.c b/drivers/syno/synobios/evansport/ds214play.c new file mode 100644 index 000000000000..55ffb497e995 --- /dev/null +++ b/drivers/syno/synobios/evansport/ds214play.c @@ -0,0 +1,79 @@ +// Copyright (c) 2000-2011 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include "evansport_common.h" + +PWM_FAN_SPEED_MAPPING gDS214playSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS214playInitModuleType(struct synobios_ops *ops) +{ + module_t type_214play = MODULE_T_DS214playv1; + module_t *pType = &type_214play; + + module_type_set(pType); + return 0; +} + +static +int DS214playFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS214playSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS214playSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS214playSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +#define SZ_CMD_LED_ESATA_ON "LE1" +#define SZ_CMD_LED_ESATA_BLINK "LE2" +#define SZ_CMD_LED_ESATA_OFF "LE3" +static +int DS214playSetEsataLedStatus(SYNO_DISK_LED status) +{ + int iRet = -1; + + switch ( status ) { + case DISK_LED_OFF: + SetUart(SZ_CMD_LED_ESATA_OFF); + break; + case DISK_LED_GREEN_SOLID: + SetUart(SZ_CMD_LED_ESATA_ON); + break; + default: + printk("%s:%d No such eSata LED operation.", __FILE__, __LINE__); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +struct model_ops ds214play_ops = { + .x86_init_module_type = DS214playInitModuleType, + .x86_fan_speed_mapping = DS214playFanSpeedMapping, + .x86_set_esata_led_status = DS214playSetEsataLedStatus, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/evansport/ds415play.c b/drivers/syno/synobios/evansport/ds415play.c new file mode 100644 index 000000000000..6875e3449c53 --- /dev/null +++ b/drivers/syno/synobios/evansport/ds415play.c @@ -0,0 +1,54 @@ +// Copyright (c) 2000-2011 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include "evansport_common.h" + +PWM_FAN_SPEED_MAPPING gDS415playSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +int DS415playInitModuleType(struct synobios_ops *ops) +{ + module_t type_415play = MODULE_T_DS415play; + module_t *pType = &type_415play; + + module_type_set(pType); + return 0; +} + +static +int DS415playFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS415playSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS415playSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS415playSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds415play_ops = { + .x86_init_module_type = DS415playInitModuleType, + .x86_fan_speed_mapping = DS415playFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = NULL, + .x86_get_buzzer_cleared = NULL, +}; diff --git a/drivers/syno/synobios/evansport/evansport_common.c b/drivers/syno/synobios/evansport/evansport_common.c new file mode 100755 index 000000000000..cb7d29f08d49 --- /dev/null +++ b/drivers/syno/synobios/evansport/evansport_common.c @@ -0,0 +1,541 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include +#include "../rtc/rtc.h" +#include "evansport_common.h" +#include "syno_ttyS.h" +#ifdef MY_DEF_HERE +#include +#endif + +#ifdef MY_DEF_HERE +extern void sata_syno_ahci_diskled_set(int iHostNum, int iPresent, int iFault); +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +extern void e1000_syno_led_switch(int iEnable); +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); + +static struct model_ops *model_ops = NULL; + +static int SetGpioPin( GPIO_PIN *pPin ) +{ + int iRet = -1; + + if ( NULL == pPin ) { + goto END; + } + + if ( 0 != SYNO_EVANSPORT_GPIO_PIN((int)pPin->pin, (int*)&pPin->value, 1) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static int GetGpioPin( GPIO_PIN *pPin ) +{ + int iRet = -1; + + if ( NULL == pPin ) { + goto END; + } + + if ( 0 != SYNO_EVANSPORT_GPIO_PIN((int)pPin->pin, (int*)&pPin->value, 0) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static +int GetFanStatusMircopWithPWMGPIO(int fanno, FAN_STATUS *pStatus) +{ + int gpio_fan_map[] = {16, 100}; + int fanNum = sizeof(gpio_fan_map)/sizeof(gpio_fan_map[0]); + GPIO_PIN gpiopin; + int rgcStat[2] = {0, 0}; + + if (pStatus == NULL) { + return -EINVAL; + } + + if (fanno > fanNum) { + return -EINVAL; + } + + do { + gpiopin.pin = gpio_fan_map[fanno-1]; + GetGpioPin(&gpiopin); + rgcStat[gpiopin.value] ++; + udelay(300); + } while (200 > rgcStat[0] + rgcStat[1]); + + if ((rgcStat[0] == 0) || (rgcStat[1] == 0)) { + *pStatus = FAN_STATUS_STOP; + } else { + *pStatus = FAN_STATUS_RUNNING; + } + + return 0; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return 0; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_CPUFAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( NULL == model_ops->x86_cpufan_speed_mapping ) { + goto END; + } else if( 0 > (iFanDuty = model_ops->x86_cpufan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_CPUFAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_DS214play; + + if ( !strncmp(gszSynoHWVersion, HW_DS214play, strlen(HW_DS214play) ) ) { + model = MODEL_DS214play; + }else if ( !strncmp(gszSynoHWVersion, HW_DS114p, strlen(HW_DS114p) ) ) { + model = MODEL_DS114p; + }else if ( !strncmp(gszSynoHWVersion, HW_DS415play, strlen(HW_DS415play) ) ) { + model = MODEL_DS415play; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +#ifdef MY_DEF_HERE +/*FIXME - Too brutal and directly, should separate into levels*/ +static +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + /*Scsi host in kernel is zero-based, disknum here is one-based, + *so we should minus 1 while calling the function + */ + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status){ + syno_sata_mv_gpio_write( 1, disknum - 1); + }else{ + syno_sata_mv_gpio_write( 0, disknum - 1); + } + + err = 0; +END: + return err; +} +#endif /* MY_DEF_HERE */ + +static +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + GPIO_PIN PinAct, PinFaulty; + + if ( status == DISK_LED_ORANGE_BLINK ) { + status = DISK_LED_ORANGE_SOLID; + } + + if ( status == DISK_LED_GREEN_SOLID ) { + PinAct.value = 0; + PinFaulty.value = 1; + } else if ( status == DISK_LED_ORANGE_SOLID ) { + PinAct.value = 1; + PinFaulty.value = 0; + } else if ( status == DISK_LED_OFF ) { + PinAct.value = 1; + PinFaulty.value = 1; + } + + switch (disknum) { + case 1: + PinAct.pin = SYNO_GPP_HDD1_LED_ACT; + PinFaulty.pin = SYNO_GPP_HDD1_LED_FAULTY; + break; + case 2: + PinAct.pin = SYNO_GPP_HDD2_LED_ACT; + PinFaulty.pin = SYNO_GPP_HDD2_LED_FAULTY; + break; + case 3: + if (model_ops && model_ops->x86_set_esata_led_status) { + model_ops->x86_set_esata_led_status(status); + } + goto ESATA_END; + case 4 ... 16: + err = 0; + goto END; + default: + printk("Wrong HDD number [%d]\n", disknum); + goto END; + } + + SetGpioPin(&PinAct); + SetGpioPin(&PinFaulty); + +ESATA_END: + err = 0; +END: + return err; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + int iError = -1; + GPIO_PIN LedActivate; + + switch(ledStatus){ + case SYNO_LED_OFF: + LedActivate.value = 1; + break; + case SYNO_LED_ON: + LedActivate.value = 0; + break; + default: + goto ERR; + } + + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + + SetGpioPin(&LedActivate); + + iError = 0; +ERR: + return iError; +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + case SYNO_LED_OFF: +#ifdef MY_DEF_HERE + e1000_syno_led_switch(ledStatus); +#endif + break; + default: + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + return 0; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + +END: + return iRet; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithPWMGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = SetDiskLedStatus, + .set_hdd_led = SetHddActLed, + .set_alarm_led = NULL, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .set_power_led = SetPowerLedStatus, + .set_phy_led = SetPhyLed, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + GPIO_PIN LedActivate; + GPIO_PIN USBPower; + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_DS214play: + model_ops = &ds214play_ops; + + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); + break; + case MODEL_DS114p: + model_ops = &ds114p_ops; + + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); + break; + case MODEL_DS415play: + model_ops = &ds415play_ops; +#ifdef MY_DEF_HERE + synobios_ops.set_disk_led = SetDiskLedStatusBySataMvGPIO; +#endif + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 0; + + SetGpioPin(&LedActivate); + + USBPower.pin = SYNO_GPP_USB_POWER; + USBPower.value = 1; + + SetGpioPin(&USBPower); + + break; + default: + break; + } + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + GPIO_PIN LedActivate; + + //Signal to deactivate the leds. + LedActivate.pin = SYNO_GPP_LEDS_ACTIVATE; + LedActivate.value = 1; + + SetGpioPin(&LedActivate); + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} diff --git a/drivers/syno/synobios/evansport/evansport_common.h b/drivers/syno/synobios/evansport/evansport_common.h new file mode 100755 index 000000000000..a01efecdc006 --- /dev/null +++ b/drivers/syno/synobios/evansport/evansport_common.h @@ -0,0 +1,53 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int SYNO_EVANSPORT_GPIO_PIN(int pin, int *pValue, int isWrite); + +extern int SetUart(const char* cmd); +extern struct model_ops ds214play_ops; +extern struct model_ops ds114p_ops; +extern struct model_ops ds415play_ops; + +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +#endif + +#define SYNO_GPP_HDD1_LED_ACT 13 +#define SYNO_GPP_HDD1_LED_FAULTY 11 +#define SYNO_GPP_HDD2_LED_ACT 15 +#define SYNO_GPP_HDD2_LED_FAULTY 12 +#define SYNO_GPP_LEDS_ACTIVATE 34 +#define SYNO_GPP_USB_POWER 43 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); +}; diff --git a/drivers/syno/synobios/geminilake/Makefile b/drivers/syno/synobios/geminilake/Makefile new file mode 100644 index 000000000000..f3733b1f2a13 --- /dev/null +++ b/drivers/syno/synobios/geminilake/Makefile @@ -0,0 +1,24 @@ +include /env.mak + +obj-m += geminilake-synobios.o + +geminilake-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds420p.o \ + ds720p.o \ + ds1520p.o \ + ds220p.o \ + ds920p.o \ + dva1622.o \ + ds423p.o \ + ds224p.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + geminilake_common.o \ + ../led/led_trigger.o diff --git a/drivers/syno/synobios/geminilake/ds1520p.c b/drivers/syno/synobios/geminilake/ds1520p.c new file mode 100644 index 000000000000..2818a714e622 --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds1520p.c @@ -0,0 +1,114 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS1520pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {39, 40}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1520pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS1520pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds1520p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds1520p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS1520pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1520p = MODULE_T_DS1520p; + module_t *pType = &type_1520p; + + module_type_set(pType); + return 0; +} + +static +int DS1520pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1520pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1520pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1520pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1520p_ops = { + .x86_init_module_type = DS1520pInitModuleType, + .x86_fan_speed_mapping = DS1520pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1520pGpioInit, + .x86_gpio_cleanup = DS1520pGpioCleanup, +}; + +struct hwmon_sensor_list ds1520p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds1520p_hdd_backplane_status, + .current_sensor = &ds1520p_current_status, +}; diff --git a/drivers/syno/synobios/geminilake/ds220p.c b/drivers/syno/synobios/geminilake/ds220p.c new file mode 100644 index 000000000000..b30a4be03924 --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds220p.c @@ -0,0 +1,138 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS220pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {39}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_146 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {150}, + .gpio_polarity = ACTIVE_HIGH, +}; +//GPIO_22 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {22}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds220p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds220p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +void DS220pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS220pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS220pInitModuleType(struct synobios_ops *ops) +{ + module_t type_220p = MODULE_T_DS220p; + module_t *pType = &type_220p; + + module_type_set(pType); + return 0; +} + +static +int DS220pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS220pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS220pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS220pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds220p_ops = { + .x86_init_module_type = DS220pInitModuleType, + .x86_fan_speed_mapping = DS220pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS220pGpioInit, + .x86_gpio_cleanup = DS220pGpioCleanup, +}; + +struct hwmon_sensor_list ds220p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds220p_hdd_backplane_status, + .current_sensor = &ds220p_current_status, +}; + +#if defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) +static void DS220pLedDisable(void) +{ + /* When WOL is set, CPLD will light on phy led as boot if this pin is high, before BIOS initialization. */ + SYNO_GPIO_WRITE(PHY_LED_CTRL_PIN(), 0); +} +SYNO_SHUTDOWN_HOOK ds220p_shutdown_hook = { + .shutdown = DS220pLedDisable, +}; +#endif /* defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) */ + diff --git a/drivers/syno/synobios/geminilake/ds224p.c b/drivers/syno/synobios/geminilake/ds224p.c new file mode 100644 index 000000000000..202279821194 --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds224p.c @@ -0,0 +1,138 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS224pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {39}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_146 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {150}, + .gpio_polarity = ACTIVE_HIGH, +}; +//GPIO_22 +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {22}, + .gpio_polarity = ACTIVE_LOW, +}; + +SYNO_HWMON_SENSOR_TYPE ds224p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds224p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +void DS224pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; +} + +static +void DS224pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +int DS224pInitModuleType(struct synobios_ops *ops) +{ + module_t type_224p = MODULE_T_DS224p; + module_t *pType = &type_224p; + + module_type_set(pType); + return 0; +} + +static +int DS224pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS224pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS224pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS224pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds224p_ops = { + .x86_init_module_type = DS224pInitModuleType, + .x86_fan_speed_mapping = DS224pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS224pGpioInit, + .x86_gpio_cleanup = DS224pGpioCleanup, +}; + +struct hwmon_sensor_list ds224p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds224p_hdd_backplane_status, + .current_sensor = &ds224p_current_status, +}; + +#if defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) +static void DS224pLedDisable(void) +{ + /* When WOL is set, CPLD will light on phy led as boot if this pin is high, before BIOS initialization. */ + SYNO_GPIO_WRITE(PHY_LED_CTRL_PIN(), 0); +} +SYNO_SHUTDOWN_HOOK ds224p_shutdown_hook = { + .shutdown = DS224pLedDisable, +}; +#endif /* defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) */ + diff --git a/drivers/syno/synobios/geminilake/ds420p.c b/drivers/syno/synobios/geminilake/ds420p.c new file mode 100644 index 000000000000..74bbafaa0939 --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds420p.c @@ -0,0 +1,115 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS420pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +// GPIO_40 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {39, 40}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS420pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS420pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds420p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds420p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS420pInitModuleType(struct synobios_ops *ops) +{ + module_t type_420p = MODULE_T_DS420p; + module_t *pType = &type_420p; + + module_type_set(pType); + return 0; +} + +static +int DS420pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS420pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS420pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS420pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds420p_ops = { + .x86_init_module_type = DS420pInitModuleType, + .x86_fan_speed_mapping = DS420pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS420pGpioInit, + .x86_gpio_cleanup = DS420pGpioCleanup, +}; + +struct hwmon_sensor_list ds420p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds420p_hdd_backplane_status, + .current_sensor = &ds420p_current_status, +}; diff --git a/drivers/syno/synobios/geminilake/ds423p.c b/drivers/syno/synobios/geminilake/ds423p.c new file mode 100644 index 000000000000..5f5d4e6dbada --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds423p.c @@ -0,0 +1,115 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS423pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +// GPIO_40 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {39, 40}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS423pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS423pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds423p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds423p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS423pInitModuleType(struct synobios_ops *ops) +{ + module_t type_423p = MODULE_T_DS423p; + module_t *pType = &type_423p; + + module_type_set(pType); + return 0; +} + +static +int DS423pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS423pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS423pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS423pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds423p_ops = { + .x86_init_module_type = DS423pInitModuleType, + .x86_fan_speed_mapping = DS423pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS423pGpioInit, + .x86_gpio_cleanup = DS423pGpioCleanup, +}; + +struct hwmon_sensor_list ds423p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds423p_hdd_backplane_status, + .current_sensor = &ds423p_current_status, +}; diff --git a/drivers/syno/synobios/geminilake/ds720p.c b/drivers/syno/synobios/geminilake/ds720p.c new file mode 100644 index 000000000000..adba607075a1 --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds720p.c @@ -0,0 +1,127 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS720pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {39}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_40 for DS720+r1 +static SYNO_GPIO_INFO fan_fail_r1 = { + .nr_gpio = 1, + .gpio_port = {40}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS720pGpioInit(void) +{ + if (syno_is_hw_revision(HW_R1)) { + syno_gpio.fan_fail = &fan_fail_r1; + } else { + syno_gpio.fan_fail = &fan_fail; + } + + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS720pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds720p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds720p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS720pInitModuleType(struct synobios_ops *ops) +{ + module_t type_720p = MODULE_T_DS720p; + module_t *pType = &type_720p; + + module_type_set(pType); + return 0; +} + +static +int DS720pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS720pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS720pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS720pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds720p_ops = { + .x86_init_module_type = DS720pInitModuleType, + .x86_fan_speed_mapping = DS720pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS720pGpioInit, + .x86_gpio_cleanup = DS720pGpioCleanup, +}; + +struct hwmon_sensor_list ds720p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds720p_hdd_backplane_status, + .current_sensor = &ds720p_current_status, +}; diff --git a/drivers/syno/synobios/geminilake/ds920p.c b/drivers/syno/synobios/geminilake/ds920p.c new file mode 100644 index 000000000000..8deb1fdcb0ae --- /dev/null +++ b/drivers/syno/synobios/geminilake/ds920p.c @@ -0,0 +1,115 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDS920pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +// GPIO_40 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {39, 40}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS920pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS920pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds920p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds920p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS920pInitModuleType(struct synobios_ops *ops) +{ + module_t type_920p = MODULE_T_DS920p; + module_t *pType = &type_920p; + + module_type_set(pType); + return 0; +} + +static +int DS920pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS920pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS920pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS920pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds920p_ops = { + .x86_init_module_type = DS920pInitModuleType, + .x86_fan_speed_mapping = DS920pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS920pGpioInit, + .x86_gpio_cleanup = DS920pGpioCleanup, +}; + +struct hwmon_sensor_list ds920p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds920p_hdd_backplane_status, + .current_sensor = &ds920p_current_status, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/geminilake/dva1622.c b/drivers/syno/synobios/geminilake/dva1622.c new file mode 100644 index 000000000000..81316528e334 --- /dev/null +++ b/drivers/syno/synobios/geminilake/dva1622.c @@ -0,0 +1,115 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilake_common.h" + +PWM_FAN_SPEED_MAPPING gDVA1622SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_40 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 1, + .gpio_port = {40}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DVA1622GpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DVA1622GpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE dva1622_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE dva1622_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DVA1622InitModuleType(struct synobios_ops *ops) +{ + module_t type_dva1622 = MODULE_T_DVA1622; + module_t *pType = &type_dva1622; + + module_type_set(pType); + return 0; +} + +static +int DVA1622FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDVA1622SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDVA1622SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDVA1622SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops dva1622_ops = { + .x86_init_module_type = DVA1622InitModuleType, + .x86_fan_speed_mapping = DVA1622FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DVA1622GpioInit, + .x86_gpio_cleanup = DVA1622GpioCleanup, +}; + +struct hwmon_sensor_list dva1622_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &dva1622_hdd_backplane_status, + .current_sensor = &dva1622_current_status, +}; diff --git a/drivers/syno/synobios/geminilake/geminilake_common.c b/drivers/syno/synobios/geminilake/geminilake_common.c new file mode 100755 index 000000000000..7201ca961a97 --- /dev/null +++ b/drivers/syno/synobios/geminilake/geminilake_common.c @@ -0,0 +1,709 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include +#include "../rtc/rtc.h" + +#include "geminilake_common.h" +#include "syno_ttyS.h" + +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int giAlertGPIOPin = -1; + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) +extern int (*syno_get_current)(unsigned char, struct tty_struct *); +extern int save_current_data_from_uart(unsigned char ch, struct tty_struct *tty); +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ +extern int synobios_lock_ttyS_current(char *szCommand, char *szBuf); + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strncmp(gszSynoHWVersion, HW_DS420p, strlen(HW_DS420p) ) ) { + model = MODEL_DS420p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS720p, strlen(HW_DS720p) ) ) { + model = MODEL_DS720p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS1520p, strlen(HW_DS1520p) ) ) { + model = MODEL_DS1520p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS220p, strlen(HW_DS220p) ) ) { + model = MODEL_DS220p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS920p, strlen(HW_DS920p) ) ) { + model = MODEL_DS920p; + } else if ( !strncmp(gszSynoHWVersion, HW_DVA1622, strlen(HW_DVA1622) ) ) { + model = MODEL_DVA1622; + } else if ( !strncmp(gszSynoHWVersion, HW_DS423p, strlen(HW_DS423p) ) ) { + model = MODEL_DS423p; + } else if ( !strncmp(gszSynoHWVersion, HW_DS224p, strlen(HW_DS224p) ) ) { + model = MODEL_DS224p; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_DS420p: + case MODEL_DS920p: + case MODEL_DS423p: + iInternalDiskNum = 4; + break; + case MODEL_DS720p: + case MODEL_DS220p: + case MODEL_DVA1622: + case MODEL_DS224p: + iInternalDiskNum = 2; + break; + case MODEL_DS1520p: + iInternalDiskNum = 5; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx = 0; + + if (NULL == pCpuTemp) { + goto END; + } +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + /* Front LAN LEDs and RJ45 Phy LEDs are contoled by GPIO pin APOLLOLAKE_GPIO_LAN_LED_CTL */ + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + iError = 0; +ERR: + return iError; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ +if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +/* + * For GPIO alert Led, there is no blinking + */ +static +int SetAlarmLedByGPIO(unsigned char type) +{ + GPIO_PIN pin; + int iRet = -1; + + if (0 > giAlertGPIOPin) { + goto END; + } + + if (type) { + pin.value = 1; + }else{ + pin.value = 0; + } + pin.pin = giAlertGPIOPin; + SetGpioPin(&pin); + + iRet = 0; + +END: + return iRet; +} + +static +int SYNOIOGetCurrentStatusByMicroP(unsigned long* pulSysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szTTYCur[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulTTYCur = 0; + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szTTYCur, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szTTYCur, 10, &ulTTYCur); + if (0 > iRet) { + goto End; + } + // microP return value * 16.13 = System current (mA) (reference : uP #130) + *pulSysCurrent = (ulTTYCur * 16) + (ulTTYCur * 13 / 100); + + iRet = 0; +End: + return iRet; +} +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int iInternalDiskNum = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iInternalDiskNum = GetMaxInternalDiskNum(); + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_DETECT(index)) { + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); + } + } + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_ENABLE(index)) { + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); + } + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +static +int HWMONGetCurrentStatusByMicroP(struct _SYNO_HWMON_SENSOR_TYPE *SysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szCurrent[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulCurrent = 0; + + if (NULL == SysCurrent || NULL == hwmon_sensor_list) { + printk("SysCurrent null\n"); + goto End; + } + + memcpy(SysCurrent, hwmon_sensor_list->current_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szCurrent, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szCurrent, 10, &ulCurrent); + if (0 > iRet) { + goto End; + } + snprintf(SysCurrent->sensor[0].value, sizeof(SysCurrent->sensor[0].value), "%ld", (ulCurrent * 16) + (ulCurrent * 13 / 100)); + + iRet = 0; +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, + .hwmon_get_sys_current = NULL, + .get_sys_current = SYNOIOGetCurrentStatusByMicroP, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_DS420p: + model_ops = &ds420p_ops; + hwmon_sensor_list = &ds420p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + case MODEL_DS720p: + model_ops = &ds720p_ops; + hwmon_sensor_list = &ds720p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + case MODEL_DS1520p: + model_ops = &ds1520p_ops; + hwmon_sensor_list = &ds1520p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + case MODEL_DS220p: + model_ops = &ds220p_ops; + hwmon_sensor_list = &ds220p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; +#if defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) + syno_append_shutdown_hook(&ds220p_shutdown_hook); +#endif /* defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) */ + break; + case MODEL_DS920p: + model_ops = &ds920p_ops; + hwmon_sensor_list = &ds920p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + case MODEL_DVA1622: + model_ops = &dva1622_ops; + hwmon_sensor_list = &dva1622_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + + case MODEL_DS423p: + model_ops = &ds423p_ops; + hwmon_sensor_list = &ds423p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + + case MODEL_DS224p: + model_ops = &ds224p_ops; + hwmon_sensor_list = &ds224p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + // for matching userspace usage, button pressed = 0, else = 1 + synobios_ops.get_copy_button_status = getCopyButtonStatus; +#if defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) + syno_append_shutdown_hook(&ds224p_shutdown_hook); +#endif /* defined(CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK) && defined(CONFIG_SYNO_GPIO) */ + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/geminilake/geminilake_common.h b/drivers/syno/synobios/geminilake/geminilake_common.h new file mode 100755 index 000000000000..6d9880797455 --- /dev/null +++ b/drivers/syno/synobios/geminilake/geminilake_common.h @@ -0,0 +1,82 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "syno_ttyS.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK +#include "syno_shutdown_hook.h" +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds420p_ops; +extern struct model_ops ds720p_ops; +extern struct model_ops ds1520p_ops; +extern struct model_ops ds220p_ops; +extern struct model_ops ds920p_ops; +extern struct model_ops dva1622_ops; +extern struct model_ops ds423p_ops; +extern struct model_ops ds224p_ops; + +extern struct hwmon_sensor_list ds420p_sensor_list; +extern struct hwmon_sensor_list ds720p_sensor_list; +extern struct hwmon_sensor_list ds1520p_sensor_list; +extern struct hwmon_sensor_list ds220p_sensor_list; +extern struct hwmon_sensor_list ds920p_sensor_list; +extern struct hwmon_sensor_list dva1622_sensor_list; +extern struct hwmon_sensor_list ds423p_sensor_list; +extern struct hwmon_sensor_list ds224p_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK +extern void syno_append_shutdown_hook(SYNO_SHUTDOWN_HOOK *ops); +extern SYNO_SHUTDOWN_HOOK ds220p_shutdown_hook; +extern SYNO_SHUTDOWN_HOOK ds224p_shutdown_hook; +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; + SYNO_HWMON_SENSOR_TYPE *current_sensor; +}; diff --git a/drivers/syno/synobios/geminilakevs/Makefile b/drivers/syno/synobios/geminilakevs/Makefile new file mode 100644 index 000000000000..ae23fa40f998 --- /dev/null +++ b/drivers/syno/synobios/geminilakevs/Makefile @@ -0,0 +1,17 @@ +include /env.mak + +obj-m += geminilakevs-synobios.o + +geminilakevs-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + vs750hd.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + geminilakevs_common.o \ + ../led/led_trigger.o diff --git a/drivers/syno/synobios/geminilakevs/geminilakevs_common.c b/drivers/syno/synobios/geminilakevs/geminilakevs_common.c new file mode 100755 index 000000000000..6867feeb1441 --- /dev/null +++ b/drivers/syno/synobios/geminilakevs/geminilakevs_common.c @@ -0,0 +1,468 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include +#include "../rtc/rtc.h" + +#include "geminilakevs_common.h" +#include "syno_ttyS.h" + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int giAlertGPIOPin = -1; + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) +extern int (*syno_get_current)(unsigned char, struct tty_struct *); +extern int save_current_data_from_uart(unsigned char ch, struct tty_struct *tty); +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ +extern int synobios_lock_ttyS_current(char *szCommand, char *szBuf); + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strncmp(gszSynoHWVersion, HW_VS750hd, strlen(HW_VS750hd) ) ) { + model = MODEL_VS750hd; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_VS750hd: + iInternalDiskNum = 1; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx = 0; + + if (NULL == pCpuTemp) { + goto END; + } +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + /* Front LAN LEDs and RJ45 Phy LEDs are contoled by GPIO pin APOLLOLAKE_GPIO_LAN_LED_CTL */ + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + iError = 0; +ERR: + return iError; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ +if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +/* + * For GPIO alert Led, there is no blinking + */ +static +int SetAlarmLedByGPIO(unsigned char type) +{ + GPIO_PIN pin; + int iRet = -1; + + if (0 > giAlertGPIOPin) { + goto END; + } + + if (type) { + pin.value = 1; + }else{ + pin.value = 0; + } + pin.pin = giAlertGPIOPin; + SetGpioPin(&pin); + + iRet = 0; + +END: + return iRet; +} + +static +int SYNOIOGetCurrentStatusByMicroP(unsigned long* pulSysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szTTYCur[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulTTYCur = 0; + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szTTYCur, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szTTYCur, 10, &ulTTYCur); + if (0 > iRet) { + goto End; + } + // microP return value * 16.13 = System current (mA) (reference : uP #130) + *pulSysCurrent = (ulTTYCur * 16) + (ulTTYCur * 13 / 100); + + iRet = 0; +End: + return iRet; +} +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int iInternalDiskNum = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iInternalDiskNum = GetMaxInternalDiskNum(); + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_DETECT(index)) { + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); + } + } + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_ENABLE(index)) { + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); + } + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +static +int HWMONGetCurrentStatusByMicroP(struct _SYNO_HWMON_SENSOR_TYPE *SysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szCurrent[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulCurrent = 0; + + if (NULL == SysCurrent || NULL == hwmon_sensor_list) { + printk("SysCurrent null\n"); + goto End; + } + + memcpy(SysCurrent, hwmon_sensor_list->current_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szCurrent, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szCurrent, 10, &ulCurrent); + if (0 > iRet) { + goto End; + } + snprintf(SysCurrent->sensor[0].value, sizeof(SysCurrent->sensor[0].value), "%ld", (ulCurrent * 16) + (ulCurrent * 13 / 100)); + + iRet = 0; +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, + .hwmon_get_sys_current = NULL, + .get_sys_current = SYNOIOGetCurrentStatusByMicroP, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_VS750hd: + model_ops = &vs750hd_ops; + hwmon_sensor_list = &vs750hd_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_phy_led = SetPhyLed; + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/geminilakevs/geminilakevs_common.h b/drivers/syno/synobios/geminilakevs/geminilakevs_common.h new file mode 100755 index 000000000000..b2fb50bf3c6a --- /dev/null +++ b/drivers/syno/synobios/geminilakevs/geminilakevs_common.h @@ -0,0 +1,66 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "syno_ttyS.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK +#include "syno_shutdown_hook.h" +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops vs750hd_ops; + +extern struct hwmon_sensor_list vs750hd_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK +extern void syno_append_shutdown_hook(SYNO_SHUTDOWN_HOOK *ops); +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; + SYNO_HWMON_SENSOR_TYPE *current_sensor; +}; diff --git a/drivers/syno/synobios/geminilakevs/vs750hd.c b/drivers/syno/synobios/geminilakevs/vs750hd.c new file mode 100644 index 000000000000..d6c2bcd9ff93 --- /dev/null +++ b/drivers/syno/synobios/geminilakevs/vs750hd.c @@ -0,0 +1,122 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "geminilakevs_common.h" + +PWM_FAN_SPEED_MAPPING gVS750hdSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +// GPIO_39 +// GPIO_40 +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {39, 40}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_17 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_146 +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {150}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void VS750hdGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = NULL; +} + +static +void VS750hdGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE vs750hd_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE vs750hd_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int VS750hdInitModuleType(struct synobios_ops *ops) +{ + module_t type_750hd = MODULE_T_VS750hd; + module_t *pType = &type_750hd; + + module_type_set(pType); + return 0; +} + +static +int VS750hdFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gVS750hdSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gVS750hdSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gVS750hdSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops vs750hd_ops = { + .x86_init_module_type = VS750hdInitModuleType, + .x86_fan_speed_mapping = VS750hdFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = VS750hdGpioInit, + .x86_gpio_cleanup = VS750hdGpioCleanup, +}; + +struct hwmon_sensor_list vs750hd_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &vs750hd_hdd_backplane_status, + .current_sensor = &vs750hd_current_status, +}; diff --git a/drivers/syno/synobios/grantley/Makefile b/drivers/syno/synobios/grantley/Makefile new file mode 100644 index 000000000000..6bb80d42ef01 --- /dev/null +++ b/drivers/syno/synobios/grantley/Makefile @@ -0,0 +1,14 @@ +include /env.mak + +obj-m += grantley-synobios.o + +grantley-synobios-objs = \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs18016dxs+.o \ + fs3017.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + grantley_common.o diff --git a/drivers/syno/synobios/grantley/fs3017.c b/drivers/syno/synobios/grantley/fs3017.c new file mode 100644 index 000000000000..00c2f8f162d9 --- /dev/null +++ b/drivers/syno/synobios/grantley/fs3017.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "grantley_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int FS3017InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs3017 = MODULE_T_FS3017; + module_t *pType = &type_fs3017; + + module_type_set(pType); + return 0; +} + +struct model_ops fs3017_ops = { + .x86_init_module_type = FS3017InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/grantley/grantley_common.c b/drivers/syno/synobios/grantley/grantley_common.c new file mode 100755 index 000000000000..5c414c67e575 --- /dev/null +++ b/drivers/syno/synobios/grantley/grantley_common.c @@ -0,0 +1,362 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "grantley_common.h" + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +// following functions are not chagned in any bromolow models, so we move them from model.o to here +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = -1; + + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = -1; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL + *buzzer_cleared = gSynoBuzzerMutePressed; + gSynoBuzzerMutePressed = 0; + ret = 0; +#endif + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_FS3017; + + if (!strncmp(gszSynoHWVersion, HW_FS3017, strlen(HW_FS3017))) { + model = MODEL_FS3017; + } else if (!strncmp(gszSynoHWVersion, HW_RS18016Dxsp, strlen(HW_RS18016Dxsp))) { + model = MODEL_RS18016Dxsp; + } + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + int iProcNum = 0; + int iCpuCore = 0; + int iCpuNum = 0; + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + memset(cpu->cpucore, 0, CONFIG_SYNO_MULTI_CPU_NUM * sizeof(unsigned int)); + for_each_online_cpu(iProcNum) { + if(iCpuNum < cpu_data(iProcNum).phys_proc_id + 1) { + cpu->cpucore[iCpuNum] = cpu_data(iProcNum).booted_cores; + iCpuNum++; + iCpuCore += cpu_data(iProcNum).booted_cores; + } + } + cpu->core = iCpuCore; + return ; + +} + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /*CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL*/ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_RS18016Dxsp: + model_ops = &rs18016dxsp_ops; + break; + case MODEL_FS3017: + model_ops = &fs3017_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led){ + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /*config_syno_sas_host_disk_led_ctrl*/ + break; + /* TODO */ + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/grantley/grantley_common.h b/drivers/syno/synobios/grantley/grantley_common.h new file mode 100755 index 000000000000..effd23c6620c --- /dev/null +++ b/drivers/syno/synobios/grantley/grantley_common.h @@ -0,0 +1,41 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops rs18016dxsp_ops; +extern struct model_ops fs3017_ops; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "@" +#define SZ_UART_ALARM_LED_BLINKING "A" +#define SZ_UART_ALARM_LED_OFF "B" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/grantley/rs18016dxs+.c b/drivers/syno/synobios/grantley/rs18016dxs+.c new file mode 100644 index 000000000000..4f4131fbe1ff --- /dev/null +++ b/drivers/syno/synobios/grantley/rs18016dxs+.c @@ -0,0 +1,34 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "grantley_common.h" + +// extern function from bromolow_common +extern int BromolowRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int RS18016DxspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs18016dxsp = MODULE_T_RS18016Dxsp; + module_t *pType = &type_rs18016dxsp; + + module_type_set(pType); + return 0; +} + +struct model_ops rs18016dxsp_ops = { + .x86_init_module_type = RS18016DxspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = BromolowRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/i2c/i2c-linux.c b/drivers/syno/synobios/i2c/i2c-linux.c new file mode 100644 index 000000000000..42df8d996a6e --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-linux.c @@ -0,0 +1,169 @@ +#include +#include "i2c-linux.h" + +#ifndef CONFIG_SYNO_HI3535_VS +#include "../rtc/rtc.h" +#endif + +#include +#include +#if defined(CONFIG_SYNO_TI_816X) || defined(CONFIG_SYNO_RTD1619) || defined(CONFIG_SYNO_RTD1619B)|| defined(CONFIG_SYNO_V1000) || defined(CONFIG_SYNO_V1000SOFS) || defined(CONFIG_SYNO_R1000) +#define I2C_BUS_NO 1 +#elif defined(CONFIG_ARCH_GEN3) +#define I2C_BUS_NO 2 +#elif defined(CONFIG_SYNO_EPYC7002) || defined(CONFIG_SYNO_EPYC7002SOFS) +#define I2C_BUS_NO 3 +#else +#define I2C_BUS_NO 0 +#endif + +static int i2c_bus_no = I2C_BUS_NO; + +void I2cBusChange(int new_bus) +{ + i2c_bus_no = new_bus; +} + +int linuxI2CCharWrite(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap = NULL; + struct i2c_msg msg = {0}; + int ret = -1; + int buf_len = 0; + u8 *pDataBuf = NULL; + + pAdap = i2c_get_adapter(i2c_bus_no); + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + + if (-1 == offset) { + buf_len = length; + } else { + buf_len = length + 1; + } + + if (NULL == (pDataBuf = kzalloc(buf_len, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = 0; + msg.len = buf_len; + msg.buf = pDataBuf; + + if (-1 == offset) { + memcpy(pDataBuf, data, length); + } else { + pDataBuf[0] = offset << 4; + memcpy(pDataBuf + 1, data, length); + } + + if (1 != i2c_transfer(pAdap, &msg, 1)) { + goto END; + } + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + if (pDataBuf) + kfree(pDataBuf); + + return ret; +} + +int linuxI2CCharRead(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap; + struct i2c_msg msg; + int ret = -1; + char *pDataBuf = NULL; + int real_length; + + pAdap = i2c_get_adapter(i2c_bus_no); + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + + if (-1 == offset) { + real_length = length; + } else { + real_length = 17; + } + + if (NULL == (pDataBuf = kzalloc(real_length, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = I2C_M_RD; + msg.buf = pDataBuf; + msg.len = real_length; + + if (1 != i2c_transfer(pAdap, &msg, 1)) + goto END; + + if (-1 != offset) { + memcpy(data, pDataBuf + 1 + offset, length); + } else { + memcpy(data, pDataBuf, length); + } + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + if (pDataBuf) + kfree(pDataBuf); + + return ret; +} + +int linuxI2CSmbusRegRead(int bus_no, u16 addr, u8 reg, u16 *data) +{ + int ret = -1; + int err = -1; + struct i2c_adapter *pAdap = NULL; + u16 flags = 0; + union i2c_smbus_data smbus_data; + static u16 uLostAddr = 0; + + if (NULL == data) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + pAdap = i2c_get_adapter(bus_no); + if (!pAdap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + err = i2c_smbus_xfer(pAdap, addr, flags, I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, &smbus_data); + if (0 > err) { + if (uLostAddr != addr) { + uLostAddr = addr; + printk("i2c_smbus_xfer return error!\n"); + } + goto END; + } + if (uLostAddr == addr) { + uLostAddr = 0; + } + + *data = smbus_data.word; + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + return ret; +} diff --git a/drivers/syno/synobios/i2c/i2c-linux.h b/drivers/syno/synobios/i2c/i2c-linux.h new file mode 100644 index 000000000000..984f95ed1db3 --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-linux.h @@ -0,0 +1,4 @@ +int linuxI2CCharRead(int target, u8 *data, int length, int offset); +int linuxI2CCharWrite(int target, u8 *data, int length, int offset); +int linuxI2CSmbusRegRead(int bus_no, u16 addr, u8 reg, u16 *data); +void I2cBusChange(int new_bus); diff --git a/drivers/syno/synobios/i2c/i2c-mv.c b/drivers/syno/synobios/i2c/i2c-mv.c new file mode 100644 index 000000000000..0836f3fc0d35 --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-mv.c @@ -0,0 +1,191 @@ +#include +#include "i2c-mv.h" +#include "../rtc/rtc.h" + +#ifdef CONFIG_MACH_SYNOLOGY_6281 +#include + +int mvI2CCharWrite(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap = NULL; + struct i2c_msg msg = {0}; + int ret = -1; + int buf_len = 0; + u8 *pDataBuf = NULL; + + pAdap = i2c_get_adapter(0); + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + + if (-1 == offset) { + buf_len = length; + } else { + buf_len = length + 1; + } + + if (NULL == (pDataBuf = kzalloc(buf_len, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = 0; + msg.len = buf_len; + msg.buf = pDataBuf; + + if (-1 == offset) { + memcpy(pDataBuf, data, length); + } else { + pDataBuf[0] = offset << 4; + memcpy(pDataBuf + 1, data, length); + } + + if (1 != i2c_transfer(pAdap, &msg, 1)) { + goto END; + } + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + if (pDataBuf) + kfree(pDataBuf); + + return ret; +} + +int mvI2CCharRead(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap; + struct i2c_msg msg; + int ret = -1; + u8 offset_u8 = offset; + char *pDataBuf = NULL; + int real_length; + + pAdap = i2c_get_adapter(0); + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + + if (-1 == offset) { + offset_u8 = 0; + } + + if (-1 == offset) { + real_length = length; + } else { + real_length = 17; + } + + if (NULL == (pDataBuf = kzalloc(real_length, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = I2C_M_RD; + msg.buf = pDataBuf; + msg.len = real_length; + + if (1 != i2c_transfer(pAdap, &msg, 1)) + goto END; + + if (-1 != offset) { + memcpy(data, pDataBuf + 1 + offset, length); + } else { + memcpy(data, pDataBuf, length); + } + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + if (pDataBuf) + kfree(pDataBuf); + + return ret; +} +#else +/* The TWSI interface supports both 7-bit and 10-bit addressing. + * This enumerator describes addressing type. + */ +typedef enum _mvTwsiAddrType +{ + ADDR7_BIT, /* 7 bit address */ + ADDR10_BIT /* 10 bit address */ +}MV_TWSI_ADDR_TYPE; + +/* This structure describes TWSI address. */ +typedef struct _mvTwsiAddr +{ + u32 address; /* address */ + MV_TWSI_ADDR_TYPE type; /* Address type */ +}MV_TWSI_ADDR; + +/* This structure describes a TWSI slave. */ +typedef struct _mvTwsiSlave +{ + MV_TWSI_ADDR slaveAddr; + int validOffset; /* whether the slave has offset (i.e. Eeprom etc.) */ + u32 offset; /* offset in the slave. */ + int moreThen256; /* whether the ofset is bigger then 256 */ +}MV_TWSI_SLAVE; + +/****************************************************************************** + * Marvell 88F5182 i2c control * + * * + * Those structures are copied from arch/arm/mach-mv88fxx81/Soc/twsi/mvTwsi.h * + * ***************************************************************************/ + +/******************************************************************************** + * Marvell 88F6281 i2c control * + * * + * Those structures are copied from arch/arm/plat-feroceon/mv_hal/twsi/mvTwsi.h * + * *****************************************************************************/ + +#ifdef CONFIG_SYNO_MV88F5x8x +extern int mvTwsiRead (MV_TWSI_SLAVE *twsiSlave, u8 *pBlock, u32 blockSize); +extern int mvTwsiWrite(MV_TWSI_SLAVE *twsiSlave, u8 *pBlock, u32 blockSize); +#else +extern int mvTwsiRead (char chanNum, MV_TWSI_SLAVE *twsiSlave, u8 *pBlock, u32 blockSize); +extern int mvTwsiWrite(char chanNum, MV_TWSI_SLAVE *twsiSlave, u8 *pBlock, u32 blockSize); +#endif + +int mvI2CCharRead(int target, u8 *data, int length, int offset) +{ + MV_TWSI_SLAVE twsiSlave; + + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.slaveAddr.address = target; + twsiSlave.validOffset = (offset >= 0) ? 1 : 0; + twsiSlave.offset = (offset<<4); + twsiSlave.moreThen256 = 0; +#ifdef CONFIG_SYNO_MV88F5x8x + return mvTwsiRead (&twsiSlave, data, length); +#elif CONFIG_SYNO_MV88F6281 + return mvTwsiRead (0, &twsiSlave, data, length); +#endif +} + +int mvI2CCharWrite(int target, u8 *data, int length, int offset) +{ + MV_TWSI_SLAVE twsiSlave; + + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.slaveAddr.address = target; + twsiSlave.validOffset = (offset >= 0) ? 1 : 0; + twsiSlave.offset = (offset<<4); + twsiSlave.moreThen256 = 0; +#ifdef CONFIG_SYNO_MV88F5x8x + return mvTwsiWrite(&twsiSlave, data, length); +#elif CONFIG_SYNO_MV88F6281 + return mvTwsiWrite(0, &twsiSlave, data, length); +#endif +} +#endif diff --git a/drivers/syno/synobios/i2c/i2c-mv.h b/drivers/syno/synobios/i2c/i2c-mv.h new file mode 100644 index 000000000000..0c4aa0b0f75d --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-mv.h @@ -0,0 +1,2 @@ +int mvI2CCharRead(int target, u8 *data, int length, int offset); +int mvI2CCharWrite(int target, u8 *data, int length, int offset); diff --git a/drivers/syno/synobios/i2c/i2c-plx.c b/drivers/syno/synobios/i2c/i2c-plx.c new file mode 100644 index 000000000000..5e29d7979722 --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-plx.c @@ -0,0 +1,111 @@ +#include +#include "i2c-plx.h" +#include "../rtc/rtc.h" +#include + +int plxI2CCharWrite(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap = NULL; + struct i2c_msg msg = {0}; + int ret = -1; + int buf_len = 0; + u8 *pDataBuf = NULL; + + pAdap = i2c_get_adapter(0); + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + + if (-1 == offset) { + buf_len = length; + } else { + buf_len = length + 1; + } + + if (NULL == (pDataBuf = kzalloc(buf_len, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = 0; + msg.len = buf_len; + msg.buf = pDataBuf; + + if (-1 == offset) { + memcpy(pDataBuf, data, length); + } else { + pDataBuf[0] = offset << 4; + memcpy(pDataBuf + 1, data, length); + } + + if (1 != i2c_transfer(pAdap, &msg, 1)) { + goto END; + } + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + if (pDataBuf) + kfree(pDataBuf); + + return ret; +} + +int plxI2CCharRead(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap; + struct i2c_msg msg; + int ret = -1; + u8 offset_u8 = offset; + char *pDataBuf = NULL; + int real_length; + + pAdap = i2c_get_adapter(0); + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + + if (-1 == offset) { + offset_u8 = 0; + } + + if (-1 == offset) { + real_length = length; + } else { + real_length = 17; + } + + if (NULL == (pDataBuf = kzalloc(real_length, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = I2C_M_RD; + msg.buf = pDataBuf; + msg.len = real_length; + + if (1 != i2c_transfer(pAdap, &msg, 1)) + goto END; + + if (-1 != offset) { + memcpy(data, pDataBuf + 1 + offset, length); + } else { + memcpy(data, pDataBuf, length); + } + + ret = 0; +END: + if (pAdap) + i2c_put_adapter(pAdap); + + if (pDataBuf) + kfree(pDataBuf); + + return ret; +} diff --git a/drivers/syno/synobios/i2c/i2c-plx.h b/drivers/syno/synobios/i2c/i2c-plx.h new file mode 100644 index 000000000000..082d3ca07701 --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-plx.h @@ -0,0 +1,2 @@ +int plxI2CCharRead(int target, u8 *data, int length, int offset); +int plxI2CCharWrite(int target, u8 *data, int length, int offset); diff --git a/drivers/syno/synobios/i2c/i2c-ppc.c b/drivers/syno/synobios/i2c/i2c-ppc.c new file mode 100644 index 000000000000..e2a9101862d6 --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-ppc.c @@ -0,0 +1,263 @@ +// Copyright (c) 2000-2008 Synology Inc. All rights reserved. + +#ifdef CONFIG_SYNO_MPC85XX_COMMON +#include +#include +#include +#include +extern phys_addr_t get_immrbase(void); +#define SYNO_POWERPC_EUMB_BASE get_immrbase() +#else +#include +#include +#include +#include +#define MPC10X_MAPB_EUMB_BASE 0xfc000000 +#define SYNO_POWERPC_EUMB_BASE MPC10X_MAPB_EUMB_BASE +#endif +#define SYNO_POWERPC_I2C_OFFSET 0x3000 + +#define MPC_I2C_ADDR 0x00 +#define MPC_I2C_FDR 0x04 +#define MPC_I2C_CR 0x08 +#define MPC_I2C_SR 0x0c +#define MPC_I2C_DR 0x10 +#define MPC_I2C_DFSRR 0x14 +#define MPC_I2C_REGION 0x20 + +#define CCR_MEN 0x80 +#define CCR_MIEN 0x40 +#define CCR_MSTA 0x20 +#define CCR_MTX 0x10 +#define CCR_TXAK 0x08 +#define CCR_RSTA 0x04 + +#define CSR_MCF 0x80 +#define CSR_MAAS 0x40 +#define CSR_MBB 0x20 +#define CSR_MAL 0x10 +#define CSR_SRW 0x04 +#define CSR_MIF 0x02 +#define CSR_RXAK 0x01 + +#define MPC8245_CFG_EUMBBAR 0x78 +#define MPC8245_VENDOR_ID 0x1057 +#define MPC8245_EUMB_I2C_SIZE 0x20 + +char *i2c_base; +struct semaphore gsemI2c; +//************************************************************************* +// I2C control for MPC8245 +//************************************************************************* + + +static void writeccr(u32 x) +{ + writel(x, i2c_base + MPC_I2C_CR); +} + +static int mpc_i2c_wait(unsigned timeout, int writing) +{ + unsigned long orig_jiffies = jiffies; + u32 x; + while (((x = readl(i2c_base + MPC_I2C_SR)) & (CSR_MCF | CSR_MIF)) != (CSR_MCF | CSR_MIF)) { + schedule(); + if (signal_pending(current)) { + printk("I2C: Interrupted\n"); + return -EINTR; + } + if(time_after(jiffies, orig_jiffies + timeout)){ + printk("I2C: timeout\n"); + return -EIO; + } + } + + if (x & CSR_MAL) { + printk("I2C: MAL\n"); + return -EIO; + } + + if (writing && (x & CSR_RXAK)) { + printk("I2C: No RXAK\n"); + /* generate stop */ + writeccr(CCR_MEN); + return -EIO; + } + writel(0, i2c_base + MPC_I2C_SR); + return 0; +} + +static void mpc_i2c_stop(void) +{ + writeccr(CCR_MEN); +} + +int mpc_i2c_wait_bus_idle(unsigned int timeout) +{ + unsigned long orig_jiffies = jiffies; + u32 x; + + while (((x = readl(i2c_base + MPC_I2C_SR)) & CSR_MBB) != 0) { + schedule(); + if (signal_pending(current)) { + printk("I2C: Interrupted\n"); + return -EINTR; + } + if (time_after(jiffies, orig_jiffies + timeout)) { + printk("I2C: timeout\n"); + return -EIO; + } + } + return 0; +} + +int mpc_i2c_write(int target, const u8 *data, int length, int restart, int offset) +{ + int i; + unsigned timeout = HZ; + u32 flags = restart ? CCR_RSTA : 0; + int err = -1; + + down(&gsemI2c); + if (mpc_i2c_wait_bus_idle(timeout)) { + goto ABORT; + } + + /* Start with MEN */ + if (! restart) + writeccr(CCR_MEN); + /* Start as master */ + writeccr(CCR_MEN | CCR_MSTA | CCR_MTX | flags); + /* Write target byte */ + writel((target << 1), i2c_base + MPC_I2C_DR); + + if (mpc_i2c_wait(timeout, 1) < 0) { + printk("%s(%s)(%d) write target %x time out\n", __FILE__, __FUNCTION__, __LINE__, target); + goto END; + } + + if( offset >= 0 ) { + u8 slave_addr = ((u8)offset) << 4; + writel(slave_addr, i2c_base + MPC_I2C_DR); + if (mpc_i2c_wait(timeout, 1) < 0) { + printk("%s(%s)(%d) write offset %x time out\n", __FILE__, __FUNCTION__, __LINE__, slave_addr); + goto END; + } + } + + for(i = 0; i < length; i++) { + /* Write data byte */ + writel(data[i], i2c_base + MPC_I2C_DR); + + if (mpc_i2c_wait(timeout, 1) < 0) { + printk("%s(%s)(%d) write byte %d value %x time out\n", __FILE__, __FUNCTION__, __LINE__, i, data[i]); + goto END; + } + } + + err = 0; +END: + mpc_i2c_stop(); +ABORT: + up(&gsemI2c); + return err; +} + +int mpc_i2c_read(int target, u8 *data, int length, int restart, int offset) +{ + unsigned timeout = HZ; + int i; + u32 flags = restart ? CCR_RSTA : 0; + u32 temp = 0; + int err = -1; + + down(&gsemI2c); + if (mpc_i2c_wait_bus_idle(timeout)) { + goto ABORT; + } + + /* Start with MEN */ + if (! restart) + writeccr(CCR_MEN); + /* Start as master */ + writeccr(CCR_MEN | CCR_MSTA | CCR_MTX | flags); + /* Write target byte */ + writel((target << 1), i2c_base + MPC_I2C_DR); + + if (mpc_i2c_wait(timeout, 1) < 0) { + printk("%s(%s)(%d) write target %x timeout\n", __FILE__, __FUNCTION__, __LINE__, target); + goto END; + } + + if( offset >= 0 ) { + u8 slave_addr = ((u8)offset) << 4; + writel(slave_addr, i2c_base + MPC_I2C_DR); + if (mpc_i2c_wait(timeout, 1) < 0) { + printk("%s(%s)(%d) write offset %x timeout\n", __FILE__, __FUNCTION__, __LINE__, slave_addr); + goto END; + } + } + + /* Switch to read - restart */ + writeccr(CCR_MEN | CCR_MSTA | CCR_MTX | CCR_RSTA); + /* Write target byte - this time with the read flag set */ + writel((target<<1) | 1, i2c_base + MPC_I2C_DR); + + if (mpc_i2c_wait(timeout, 0) < 0) { + printk("%s(%s)(%d) write target %x timeout\n", __FILE__, __FUNCTION__, __LINE__, target); + goto END; + } + + if (length == 1) + writeccr(CCR_MEN | CCR_MSTA | CCR_TXAK); + else + writeccr(CCR_MEN | CCR_MSTA); + /* Dummy read */ + readl(i2c_base + MPC_I2C_DR); + + for(i = 0; i < length; i++) { + if (mpc_i2c_wait(timeout, 0) < 0) { + printk("%s(%s)(%d) read byte %d timeout\n", __FILE__, __FUNCTION__, __LINE__, i); + goto END; + } + + /* Generate stop on last byte */ + if (i == length - 1) + writeccr(CCR_MEN | CCR_TXAK); + //data[i] = readl(i2c_base + MPC_I2C_DR); + temp = readl(i2c_base + MPC_I2C_DR); + data[i] = (u8)temp; + } + err = 0; +END: + mpc_i2c_stop(); +ABORT: + up(&gsemI2c); + return length; +} + +int mpc_i2c_init(void) +{ +#ifdef CONFIG_SYNO_MPC85XX_COMMON + u32 x; +#endif + + i2c_base = (unsigned char __iomem *)(SYNO_POWERPC_EUMB_BASE + SYNO_POWERPC_I2C_OFFSET); + sema_init(&gsemI2c, 1); + +#ifdef CONFIG_SYNO_MPC85XX_COMMON +#ifdef CONFIG_SYNO_MPC854X + // ((CCB/2)/1920) ~= 100 KHz (CPU_MPC8548ERM.pdf p.531) + // initialize i2c frequency by set register I2CFDR + x = 0x0B; +#elif CONFIG_SYNO_MPC8533 + // ((CCB/3)/1152) = (400/3)/1152 ~= 100 KHz (MPC8533ERM.pdf p.11-7) + x = 0x08; +#endif + writel(x, i2c_base + MPC_I2C_FDR); +#endif + + return 0; +} + + diff --git a/drivers/syno/synobios/i2c/i2c-ppc.h b/drivers/syno/synobios/i2c/i2c-ppc.h new file mode 100644 index 000000000000..79e1c5ac0dae --- /dev/null +++ b/drivers/syno/synobios/i2c/i2c-ppc.h @@ -0,0 +1,3 @@ +int mpc_i2c_write(int target, const unsigned char *data, int length, int restart, int offset); +int mpc_i2c_read(int target, unsigned char *data, int length, int restart, int offset); +int mpc_i2c_init(void); diff --git a/drivers/syno/synobios/icelaked/Makefile b/drivers/syno/synobios/icelaked/Makefile new file mode 100644 index 000000000000..25f3ad1cb00a --- /dev/null +++ b/drivers/syno/synobios/icelaked/Makefile @@ -0,0 +1,17 @@ +include /env.mak + +obj-m += icelaked-synobios.o + +icelaked-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs4023xs+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-pericom-lib.o \ + ../rtc/rtc-linux-pericom.o \ + ../i2c/i2c-linux.o \ + icelaked_common.o \ + ../led/led_trigger.o diff --git a/drivers/syno/synobios/icelaked/icelaked_common.c b/drivers/syno/synobios/icelaked/icelaked_common.c new file mode 100755 index 000000000000..3dce0f25c0c1 --- /dev/null +++ b/drivers/syno/synobios/icelaked/icelaked_common.c @@ -0,0 +1,566 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "icelaked_common.h" + +static int Uninitialize(void); + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static int Uninitialize(void); + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_RS4023xsp: + iMaxInternalDiskNum = 16; + break; + } + return iMaxInternalDiskNum; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = ICELAKED_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = ICELAKED_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_RS4023xsp; + + if (!strncmp(gszSynoHWVersion, HW_RS4023xsp, strlen(HW_RS4023xsp))) { + model = MODEL_RS4023xsp; + } + + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_pericom_get_time, + .set_rtc_time = rtc_pericom_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_pericom_set_auto_poweron, + .init_auto_poweron = rtc_pericom_auto_poweron_init, + .uninit_auto_poweron = rtc_pericom_auto_poweron_uninit, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + int i = 0; + int maxdisk = 0; +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_RS4023xsp: + model_ops = &rs4023xsp_ops; + RS4023xspSMBusSwitchInit(); + synobios_ops.set_power_led = SetPowerLedStatus; + hwmon_sensor_list = &rs4023xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + maxdisk = GetMaxInternalDiskNum(); + for (i = 1; i <= maxdisk; ++i) { + syno_ahci_disk_led_enable_by_port(i, 1); + } +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + break; + default: + break; + } + + return 0; +} + +static int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if (synobios_ops.get_rtc_time) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} + +void SMBusSwitchRegWrite(u8 command, u8 length, u8 *data) +{ + struct device_node *np = NULL; + struct i2c_client *client = NULL; + + while ((np = of_find_compatible_node(np, NULL, "nxp,pca9546"))) { + if (of_property_read_bool(np, "led_enable")) { + client = of_find_i2c_device_by_node(np); + + if (NULL == client || 0 > i2c_smbus_write_i2c_block_data(client, command, length, data)) { + printk("i2c_smbus_write_i2c_block_data failed\n"); + } + } + of_node_put(np); + } +} diff --git a/drivers/syno/synobios/icelaked/icelaked_common.h b/drivers/syno/synobios/icelaked/icelaked_common.h new file mode 100755 index 000000000000..607b18a2be24 --- /dev/null +++ b/drivers/syno/synobios/icelaked/icelaked_common.h @@ -0,0 +1,81 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "../led/led_9235.h" +#include "../led/led_trigger.h" +#include "../led/led_1475.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +#define I2C_BUS_NO 0 +extern void RS4023xspSMBusSwitchInit(void); +extern void SMBusSwitchRegWrite(u8 command, u8 length, u8 *data); + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern char gszSynoHWVersion[]; +extern struct model_ops rs4023xsp_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list rs4023xsp_sensor_list; + +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define ICELAKED_BUZZER_OFF_PIN 53 +#define ICELAKED_BUZZER_CTRL_PIN 52 +#define ICELAKED_DISK_LED_ACTIVATE_PIN 45 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/icelaked/rs4023xs+.c b/drivers/syno/synobios/icelaked/rs4023xs+.c new file mode 100755 index 000000000000..c91b554dbf18 --- /dev/null +++ b/drivers/syno/synobios/icelaked/rs4023xs+.c @@ -0,0 +1,211 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "icelaked_common.h" + +#define I2C_SWITCH_VAL 0x9 + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from icelaked_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +void RS4023xspSMBusSwitchInit(void) { + u8 data = I2C_SWITCH_VAL; + SMBusSwitchRegWrite(0, 1, &data); +} + +SYNO_HWMON_SENSOR_TYPE RS4023xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4023xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4023xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4023xsp_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4023xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS4023xspI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {57}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void RS4023xspGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; +} + +static +void RS4023xspGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; +} + +static +int RS4023xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs4023xsp = MODULE_T_RS4023xsp; + module_t *pType = &type_rs4023xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio ICELAKED_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = ICELAKED_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs4023xsp_ops = { + .x86_init_module_type = RS4023xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = RS4023xspI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, + .x86_gpio_init = RS4023xspGpioInit, + .x86_gpio_cleanup = RS4023xspGpioCleanup, +}; + +struct hwmon_sensor_list rs4023xsp_sensor_list = { + .thermal_sensor = &RS4023xsp_thermal_sensor, + .voltage_sensor = &RS4023xsp_voltage_sensor, + .fan_speed_rpm = &RS4023xsp_fan_speed_rpm, + .psu_status = RS4023xsp_psu_status, + .hdd_backplane = &RS4023xsp_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/include/syno_shutdown_hook.h b/drivers/syno/synobios/include/syno_shutdown_hook.h new file mode 100644 index 000000000000..1e1d2173a6cd --- /dev/null +++ b/drivers/syno/synobios/include/syno_shutdown_hook.h @@ -0,0 +1,16 @@ +#ifndef SYNO_SHUTDOWN_HOOK_H +#define SYNO_SHUTDOWN_HOOK_H + +#include +typedef struct __tag_SYNO_SHUTDOWN_HOOK { + struct list_head node; + void (*shutdown)(void); + void (*restart)(void); +} SYNO_SHUTDOWN_HOOK; + +typedef struct _tag_SYNO_SHUTDOWN_HOOK_LIST { + struct list_head hookList; + struct mutex hookLock; +} SYNO_SHUTDOWN_HOOK_LIST; + +#endif /* SYNO_SHUTDOWN_HOOK_H */ diff --git a/drivers/syno/synobios/include/syno_ttyS.h b/drivers/syno/synobios/include/syno_ttyS.h new file mode 100755 index 000000000000..225c4d94269e --- /dev/null +++ b/drivers/syno/synobios/include/syno_ttyS.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2017 Synology Inc. All rights reserved.*/ +#ifndef SYNO_TTYS_H +#define SYNO_TTYS_H + + +#define UP_DELAY 250 +#define UART_BUF_SIZE 8 +typedef struct _UART2_BUFFER { + char szBuf[UART_BUF_SIZE]; + int size; +} UART2_BUFFER; + +/** + * init open microP device in synobios. + * default open /dev/ttyS1. + * should call once when insert synobios module. + * + * @return -1: Failed + * 0: Success + * @example + *
+ * if (0 > syno_ttyS_open()) return -1;
+ * 
+ * + * @see syno_ttyS_open + **/ +int syno_ttyS_open(void); + +/** + * read data from microP device in synobios. + * should open before read. + * if read fail will return -1 else return data length. + * + * @param [OUT] szBuf Store read data + * @param [IN] size Max size of szBuf + * + * @return -1: Failed + * else: data length + * @example + *
+ * len = synobios_lock_ttyS_read(szBuf, size);
+ * if (0 > len) return -1;
+ * 
+ * + **/ +int synobios_lock_ttyS_read(char *szBuf, int size); + +/** + * write commad to microP device in synobios. + * should open before write. + * if write fail will return -1. + * + * @param [IN] szCmd The command will be written to microP + * + * @return -1: Failed + * else: Length of being written command + * @example + *
+ * len = syno_ttyS_write(szCmd)
+ * if (0 > len) return -1;
+ * 
+ * + * @see syno_ttyS_write + **/ +int synobios_lock_ttyS_write(const char *szBuf); + +/** + * close microP device in synobios. + * should call when will not read, write microP in synobios anymore. + * will be called in unload synobios module + * + * + * @example + *
+ * syno_ttyS_close;
+ * 
+ * + * @see syno_ttyS_close + **/ +void syno_ttyS_close(void); + +int synobios_lock_ttyS_write_and_read(char *szBuf, int size); + +void try_wakeup_waiting_microp(void); + +void set_log_switch(int logSwitch); + +#define TTY_BUF_SIZE 24 +#define CURRENT_DATA_LEN 4 +#define PREFIX_CH '+' +#define TTY_PROTECT_CMD_SIZE 17 +#define SZ_UART_CURRENT_PREFIX 'D' +#define SZ_UART_CURRENT_SUFFIX 'X' +#define SZ_UART_CURRENT_ZERO_SUBSTITUE '*' +#define SZ_UART_CURRENT_ZERO '0' +#define TTY_NAME "ttyS1" + +#define SZ_UART_CMD_CURRENT_GET "D" + +#endif /* SYNO_TTYS_H */ diff --git a/drivers/syno/synobios/include/synobios.h b/drivers/syno/synobios/include/synobios.h new file mode 100755 index 000000000000..2472260d98be --- /dev/null +++ b/drivers/syno/synobios/include/synobios.h @@ -0,0 +1,1608 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. +#ifndef __SYNOBIOS_OEM_H_ +#define __SYNOBIOS_OEM_H_ + +#include + +#ifndef SYNO_HI_3535 +#include +#endif + +#include "syno_ttyS.h" + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_HW_VERSION) +#include +#include +extern char gszSynoHWVersion[]; +#endif /* MY_DEF_HERE || CONFIG_SYNO_HW_VERSION */ + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif +#ifndef BCD2BIN +#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10) +#endif +#ifndef BIN2BCD +#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10) +#endif + +#define SYNOBIOS_MAJOR 201 +#define SYNOBIOS_NEVENTS 128 + +int GetHWMONSupport(SYNO_HWMON_SUPPORT *hwmon_support); + +/* + * SynoBios Hardware status structure is as following + * ThermalStage: 0~3: Normal, Warm, Hot, Critical, four stages + * MemEccCount: 0~X: the count of Memory ECC + * ButtonStatus: each bit presents a button status pressed(1) or not(0) + * HardDiskStatus: each bit presents a HD status removed(1) or not(0) + * AcPowerStatus: a boolean value, 0:AC Power failed; 1:AC Power on-line + */ +/*#define LCD_STR_LEN 40 +typedef struct _Synohw { + unsigned long AcPowerStatus; + unsigned long ThermalStage; + unsigned long MemEccCount; + unsigned long ButtonStatus; + unsigned long HardDiskStatus; + unsigned long FanFaultStatus; + unsigned long PowerSupplyFault; + unsigned long PowerSupplyPresent; + unsigned long BatteryStatus; + unsigned long BatteryFault; + char szLcdStr[LCD_STR_LEN]; +} SYNOHW; + +typedef struct _Synohw_custom { + unsigned long obj_1; + unsigned long obj_2; + unsigned long obj_3; + unsigned long obj_4; + unsigned long obj_5; + unsigned long obj_6; + unsigned long obj_7; + unsigned long obj_8; + unsigned long obj_9; + unsigned long obj_10; + unsigned long obj_11; + unsigned long obj_12; + unsigned long obj_13; + unsigned long obj_14; + unsigned long obj_15; + unsigned long obj_16; + unsigned long obj_17; + unsigned long obj_18; + unsigned long obj_19; + unsigned long obj_20; + unsigned long obj_21; + unsigned long obj_22; + unsigned long obj_23; + unsigned long obj_24; + unsigned long obj_25; + unsigned long obj_26; + unsigned long obj_27; + unsigned long obj_28; + unsigned long obj_29; + unsigned long obj_30; + unsigned long obj_31; + unsigned long obj_32; +} SYNOHW_CUSTOM; +*/ + +extern struct proc_dir_entry *proc_synobios_root; + +typedef struct _SynoMsgPkt { + long usNum; + long usLen; + char szMsg[128]; +} SYNOMSGPKT; + +#define BIOS_STR_LEN_MAX 32 + +/*typedef struct __bvs { + int addr; + char szBStr[BIOS_STR_LEN_MAX]; +} BVS; + +#define valueLongPointer(a) (*((unsigned long *) a)) +#define FIELD_SIZE 4 +#define LEN_SIZE 4 + +#define APM_SUCCESS 0 +#define APM_FAILURE 1 +#define APM_NOT_PRESENT -1 + +#define USE_BY_CONSOLE 1 +#define USE_BY_UPS 0 +*/ + +/* + * SYNOBIOS Events (status change of SynoBIOS) + */ +#define SYNO_EVENT_CPU_THERMAL_NORMAL 0x0100 +#define SYNO_EVENT_CPU_THERMAL_WARM 0x0101 +#define SYNO_EVENT_CPU_THERMAL_HEAT 0x0102 +#define SYNO_EVENT_CPU_THERMAL_CRITICAL 0x0103 + +#define SYNO_EVENT_BUTTON_0 0x0200 +#define SYNO_EVENT_BUTTON_MANUTIL 0x0200 +#define SYNO_EVENT_BUTTON_NORMAL 0x0201 + +#define SYNO_EVENT_BUTTON_1 0x0210 +#define SYNO_EVENT_BUTTON_2 0x0220 + +#define SYNO_EVENT_BUTTON_SHUTDOWN_PUSHED 0x0221 +#define SYNO_EVENT_BUTTON_SHUTDOWN_RELEASED 0x0222 +#define SYNO_EVENT_BUTTON_SHUTDOWN 0x0223 +#define SYNO_EVENT_BUTTON_BUZZER_CLEAR 0x0224 + +#define SYNO_EVENT_BUTTON_3 0x0230 +#define SYNO_EVENT_BUTTON_RESET 0x0230 + +#define SYNO_EVENT_BUTTON_4 0x0240 +#define SYNO_EVENT_USBCOPY_START 0x0240 + +#define SYNO_EVENT_BUTTON_5 0x0250 +#define SYNO_EVENT_BUTTON_6 0x0260 +#define SYNO_EVENT_BUTTON_7 0x0270 + +#define SYNO_EVENT_RM_HD0 0x0300 +#define SYNO_EVENT_PLUG_HD0 0x0400 +#define SYNO_EVENT_MEM_ECC_1 0x0501 +#define SYNO_EVENT_MEM_ECC_2_OR_MORE 0x0502 + +#define SYNO_EVENT_ACPOWER_FAIL 0x0600 +/*#define SYNO_EVENT_IOERR_HD0 0x0700*/ + +#define SYNO_EVENT_FAN_FAIL 0x0900 +#define SYNO_EVENT_POWERSUPPLY_FAIL 0x0a00 +#define SYNO_EVENT_RM_BATTERY 0x0b00 +#define SYNO_EVENT_BATTERY_FAULT 0x0c00 + +#define SYNO_EVENT_FAN_RECOVER 0x0d00 +#define SYNO_EVENT_BATTERY_RECOVER 0x0e00 +#define SYNO_EVENT_INSERT_BATTERY 0x0f00 +#define SYNO_EVENT_POWERSUPPLY_RECOVER 0x1000 + +#define SYNO_EVENT_NETCARD_ATTACH 0x1100 +#define SYNO_EVENT_NETCARD_DETACH 0x1200 + +#define SYNO_EVENT_RM_SCSI0 0x1300 +#define SYNO_EVENT_PLUG_SCSI0 0x1400 + +#define SYNO_EVENT_HDFAIL_HD0 0x1500 +#define SYNO_EVENT_HDRESUME_HD0 0x1600 + +#define SYNO_EVENT_IOERR_HD0 0x1700 + +#define SYNO_EVENT_DETECT_CARD_CHANGE 0x1800 + +#define SYNO_EVENT_RAID 0x1900 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) +#define SYNO_EVENT_RAID_SYNC 0x1a00 +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) */ + + +#define SYNO_EVENT_SHUTDOWN_LOG 0x2200 +#define SYNO_EVENT_EBOX_REFRESH 0x2300 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_ECC_NOTIFICATION) +#define SYNO_EVENT_ECC_NOTIFICATION 0x2400 +#endif /* MY_DEF_HERE || CONFIG_SYNO_ECC_NOTIFICATION */ + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) +#define SYNO_EVENT_RAID_REMAP_RECORD 0x2500 +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) */ + + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_EXT4_ERROR_REPORT) +#define SYNO_EVENT_ERROR_FS 0x2900 +#endif /* MY_DEF_HERE || CONFIG_SYNO_EXT4_ERROR_REPORT */ + + + + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_BTRFS_DATA_CORRECTION) +#define SYNO_EVENT_ERROR_FS_BTRFS 0x2d00 +#define SYNO_EVENT_ERROR_BTRFS_META_CORRUPTED 0x2d01 +#endif /* MY_DEF_HERE || CONFIG_SYNO_BTRFS_DATA_CORRECTION */ + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_OOM_NOTIFICATION) +#define SYNO_EVENT_ERROR_OOM 0x2f00 +#endif /* (MY_DEF_HERE) || (CONFIG_SYNO_OOM_NOTIFICATION) */ + +#ifdef CONFIG_SYNO_SYNOBIOS_EVENT +/* SYNO_SYNOBIOS_EVENT moves event define to linux_kernel_version/include/uapi/linux/synobios.h */ +#else /* CONFIG_SYNO_SYNOBIOS_EVENT */ +#define SYNO_EVENT_USB_PROHIBIT 0x1b00 +#define SYNO_EVENT_CONSOLE_PROHIBIT 0x1c00 +#define SYNO_EVENT_MICROP_GET 0x1d00 +#define SYNO_EVENT_DISK_PWR_RESET 0x2700 +#define SYNO_EVENT_DISK_PORT_DISABLED 0x2800 +#define SYNO_EVENT_SATA_ERROR_REPORT 0x2a00 +#define SYNO_EVENT_WAKE_FROM_DEEP_SLEEP 0x2b00 +#define SYNO_EVENT_DISK_RETRY_REPORT 0x2c00 +#define SYNO_EVENT_DSIK_POWER_SHORT_BREAK 0x2e00 +#define SYNO_EVENT_DISK_TIMEOUT_REPORT 0x3000 +#define SYNO_EVENT_DISK_RESET_FAIL_REPORT 0x3100 +#define SYNO_EVENT_DISK_PORT_LOST 0x3200 +#define SYNO_EVENT_SCSI_ERROR 0x3300 +#define SYNO_EVENT_EBOX_RESET 0x3400 +#endif /* CONFIG_SYNO_SYNOBIOS_EVENT */ + + +#define SYNO_EVENT_BACK_TEMP_CRITICAL 0x4004 +#define SYNO_EVENT_BACK_TEMP_HIGH 0x4003 +#define SYNO_EVENT_BACK_TEMP_HEAT 0x4002 +#define SYNO_EVENT_BACK_TEMP_WARM 0x4001 +#define SYNO_EVENT_CASE_TEMP_CRITICAL 0x4104 +#define SYNO_EVENT_CASE_TEMP_HIGH 0x4103 +#define SYNO_EVENT_CASE_TEMP_HEAT 0x4102 +#define SYNO_EVENT_CASE_TEMP_WARM 0x4101 +#define SYNO_EVENT_VOLPIN0_ABNORMAL 0x4200 +#define SYNO_EVENT_VOLPIN1_ABNORMAL 0x4201 +#define SYNO_EVENT_VOLPIN2_ABNORMAL 0x4202 +#define SYNO_EVENT_VOLPIN3_ABNORMAL 0x4203 +#define SYNO_EVENT_VOLPIN4_ABNORMAL 0x4204 +#define SYNO_EVENT_VOLPIN5_ABNORMAL 0x4205 +#define SYNO_EVENT_VOLPIN6_ABNORMAL 0x4206 +#define SYNO_EVENT_VOLPIN7_ABNORMAL 0x4207 +#define SYNO_EVENT_VOLPIN8_ABNORMAL 0x4208 +#define SYNO_EVENT_VOLPIN9_ABNORMAL 0x4209 + +#define SYNO_EVENT_USBSTATION_RESET 0x5000 +#define SYNO_EVENT_USBSTATION_EJECT 0x5001 + +#define SYNO_EVENT_WIFIWPS 0x6000 +#define DRIVER_CLASS_FXP 0x00 +#define DRIVER_CLASS_EM 0x10 +#define DRIVER_CLASS_RL 0x20 + + +/************************************************************************* + * Ioctl definitions + ************************************************************************/ +/*MUST mentain the order in RTC structure*/ + +typedef struct _SynoRtcControlPkt { + char ControlR_1; + char ControlR_2; +} SYNORTCCONTROLPKT; + +typedef struct _SynoRtcTimePkt { + unsigned char sec; + unsigned char min; + unsigned char hour; + unsigned char weekday; + unsigned char day; + unsigned char month; + // Value starts from 1900 (in dec) + unsigned char year; +} SYNORTCTIMEPKT; + +typedef struct _tag_SYNO_MEM_ACCESS { + unsigned int addr; + unsigned int value; +} SYNO_MEM_ACCESS; + +/* for auto poweron functions */ +#define I2C_RTC_ADDR 0x32 +#define I2C_RTC_TIMER_OFFSET 0x00 +#define I2C_RTC_TIME_TRIM_OFFSET 0x07 +#define I2C_RTC_ALARMA_OFFSET 0x08 +#define I2C_RTC_ALARMB_OFFSET 0x0B +#define I2C_RTC_CONTROL1_OFFSET 0x0E +#define I2C_RTC_CONTROL2_OFFSET 0x0F + +#define I2C_RTC_ALARMA_ENABLE 0x80 +#define I2C_RTC_ALARMB_ENABLE 0x40 +#define I2C_RTC_ALARMAB_SL 0x20 + +#define I2C_RTC_ALARMA_24HOUR 0x20 + +#define I2C_TEMPERATURE_ADDR 0x48 + +typedef enum { + AUTO_POWERON_SUN = 0x01, + AUTO_POWERON_MON = 0x02, + AUTO_POWERON_TUE = 0x04, + AUTO_POWERON_WED = 0x08, + AUTO_POWERON_THU = 0x10, + AUTO_POWERON_FRI = 0x20, + AUTO_POWERON_SAT = 0x40, +} AUTO_POWERON_WEEKDAY; +#define AUTO_POWERON_WEEKDAY_MASK ( AUTO_POWERON_SUN | \ + AUTO_POWERON_MON | \ + AUTO_POWERON_TUE | \ + AUTO_POWERON_WED | \ + AUTO_POWERON_THU | \ + AUTO_POWERON_FRI | \ + AUTO_POWERON_SAT ) + +typedef enum { + SYNO_AUTO_POWERON_DISABLE = 0, + SYNO_AUTO_POWERON_ENABLE = 1, +} SYNO_AUTO_POWERON_EN; + +typedef struct _SynoRtcAlarmPkt { + unsigned char min; // BCD formatted 24-hour: 17 --> 0x23, we can call DEC2BCD() to convert this field. + unsigned char hour; // BCD formatted 24-hour: 17 --> 0x23, we can call DEC2BCD() to convert this field. + unsigned char weekdays; // 7-bit day of week: [SUN][MON][TUE][WED][THU][FRI][SAT] +} SYNORTCALARMPKT; + +#define MAX_POWER_SCHEDULE_TASKS 100 + +typedef struct _SynoAutoPowerOn { + int num; + SYNO_AUTO_POWERON_EN enabled; + SYNORTCALARMPKT RtcAlarmPkt[MAX_POWER_SCHEDULE_TASKS]; +} SYNO_AUTO_POWERON; + +/*for test only*/ +typedef struct _SynoRtcPkt { + char rg[16]; +} SYNORTCPKT; + +typedef struct _SynoPWMCTL { + int blSetPWM; + int hz; + int duty_cycle; + int rpm; +} SynoPWMCTL; + +#define SYNOBIOS_EVENTDATA_NUM_MAX 8 +typedef struct _tag_SynobiosEvent { + unsigned int event; + unsigned long long data[SYNOBIOS_EVENTDATA_NUM_MAX]; +} SYNOBIOSEVENT; + +typedef enum { + DISK_WAKE_UP = 0, +} SYNO_DISK_HIBERNATION_EVENT; + +typedef struct _tag_DiskLedStatus { + int diskno; + SYNO_DISK_LED status; + int iNodeNameLen; /* length of szNodeName */ + const char* szNodeName; +} DISKLEDSTATUS; + +typedef enum { + AHA_LED_OFF = 0, + AHA_LED_GREEN_SOLID, + AHA_LED_ORANGE_SOLID, +} SYNO_AHA_LED; + +typedef enum { + FAN_STATUS_UNKNOWN_UART_BUSY = -2, + FAN_STATUS_UNKNOWN = -1, + FAN_STATUS_STOP = 0, + FAN_STATUS_RUNNING = 1, +} FAN_STATUS; + +typedef enum { + BACKPLANE_STATUS_UNKNOWN = -1, + BACKPLANE_STATUS_ERROR = 0, + BACKPLANE_STATUS_NORMAL = 1, +} BACKPLANE_STATUS; + +typedef enum { + TEMPERATURE_OVER_NORMAL = -7, +} SYNO_SHUTDOWN_LOG; + +/* When you add a new FAN_SPEED. Please modify the parsing in libsynosdk/external/?match.c */ +typedef enum { + /* The FAN_SPEED_* is ordered from low to high speed. + * Note, the FAN_SPEED_UNKNOWN = 0, must not move, we will init FAN_SPEED value to FAN_SPEED_UNKNOWN + * and will use it to compare with other speeds. So it must at the lowest order */ + FAN_SPEED_UNKNOWN = 0, + FAN_SPEED_STOP, + FAN_SPEED_ULTRA_LOW, + FAN_SPEED_VERY_LOW, + FAN_SPEED_LOW, + FAN_SPEED_MIDDLE, + FAN_SPEED_HIGH, + FAN_SPEED_VERY_HIGH, + FAN_SPEED_ULTRA_HIGH, + FAN_SPEED_FULL, + /* FAN_SPEED_TEST_X is used inside manutild for fan testing*/ + FAN_SPEED_TEST_0, + FAN_SPEED_TEST_1, + FAN_SPEED_TEST_2, + FAN_SPEED_TEST_3, + FAN_SPEED_TEST_4, + FAN_SPEED_TEST_5, + FAN_SPEED_TEST_6, + FAN_SPEED_TEST_7, + FAN_SPEED_TEST_8, + FAN_SPEED_TEST_9, + FAN_SPEED_TEST_10, + FAN_SPEED_TEST_11, + FAN_SPEED_TEST_12, + FAN_SPEED_TEST_13, + FAN_SPEED_TEST_14, + FAN_SPEED_TEST_15, + FAN_SPEED_TEST_16, + FAN_SPEED_TEST_17, + /* PWM format is only for bandon and QC test */ + FAN_SPEED_PWM_FORMAT_SHIFT = 1000, +} FAN_SPEED; + +/* Mapping FAN_SPEED to duty cycle */ +typedef struct _tag_PWM_FAN_SPEED_MAPPING_ { + FAN_SPEED fanSpeed; + int iDutyCycle; // Range [0, 99] +} PWM_FAN_SPEED_MAPPING; + +typedef struct _tag_FanStatus { + int fanno; // CS406 ==>1, RS406 ==> 1,2,3 + FAN_STATUS status; // 1 ==> stop, 0 ==> running + FAN_SPEED speed; // 1 ==> high, 0 ==> low +} FANSTATUS; + +/* shift 8bit and set hz value in it */ +#define FAN_SPEED_SHIFT_SET(duty_cycle, hz) ((duty_cycle) + ((hz) << 8) + FAN_SPEED_PWM_FORMAT_SHIFT) +#define FAN_SPEED_SHIFT_HZ_GET(speed) (((speed) - FAN_SPEED_PWM_FORMAT_SHIFT) >> 8) /* shift 8bit and get hz value */ +#define FAN_SPEED_SHIFT_DUTY_GET(speed) (((speed) - FAN_SPEED_PWM_FORMAT_SHIFT) & 0xFF) /* duty cycle is set in the first 8bit, so get it in first 8bit */ + +/* if curspeed is stop and nxtspeed is lower than "high", return true. else return false*/ +#define IS_FAN_NEED_TO_SPIN_FASTER_FIRST(NxtSpeed, CurSpeed) (((NxtSpeed) < FAN_SPEED_PWM_FORMAT_SHIFT) ? ( (FAN_SPEED_HIGH > (NxtSpeed) && FAN_SPEED_STOP == (CurSpeed) ) || (FAN_SPEED_TEST_5 > (NxtSpeed) && FAN_SPEED_TEST_0 == (CurSpeed) ) ) : (65 > FAN_SPEED_SHIFT_DUTY_GET(NxtSpeed) && (0 == FAN_SPEED_SHIFT_DUTY_GET(CurSpeed) || IS_FAN_SET_TO_STOP(CurSpeed)))) + +#define IS_FAN_SET_TO_STOP(CurSpeed) ((FAN_SPEED_STOP == CurSpeed) || (FAN_SPEED_TEST_0 == CurSpeed)) + +// Synology Disk Station Brand +enum { + BRAND_SYNOLOGY = 0x00, + BRAND_LOGITEC = 0x01, + BRAND_SYNOLOGY_USA = 0x02, +}; + +// for hardware capabilities +#define MAX_CAPABILITY 4 + +typedef enum { + POWER_STATUS_BAD = 0, + POWER_STATUS_GOOD, +} SYNO_POWER_STATUS; + +// FIXME: only 4 bits, and at most 16 kinds of type fan_t, so please be careful +typedef enum { + FAN_UNKNOWN, + FAN_CPLD_SPEED_1LEVEL, + FAN_CPLD_SPEED_2LEVEL, + FAN_MULTI_EXCEPT_SLEEP, + FAN_MICROP_ALERT_FIRM, + FAN_MICROP_ALERT_SOFT, + FAN_MICROP_PWM, + FAN_MULTI_ALWAYS, + FAN_MICROP_PWM_WITH_CPUFAN, + FAN_MICROP_PWM_WITH_GPIO, + FAN_MICROP_PWM_WITH_CPUFAN_AND_GPIO, + FAN_ADT, + FAN_ADT_FANFAIL_WITH_MICROP, + FAN_BMC, +} FAN_T; + +typedef enum { + LED_UNKNOWN, + LED_DISKS, + LED_DISK_ESATA, + LED_DISKS_ALARM, +} LED_T; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) +typedef enum { + RAID_SYNC_NONE = 0, + RAID_SYNC_RESYNC, + RAID_SYNC_REQUESTED_RESYNC, + RAID_SYNC_CHECK, + RAID_SYNC_RECOVERY, + RAID_SYNC_RESHAPE +} RAID_SYNC_TYPE; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) */ + +typedef enum { + THERMAL_UNKNOWN, + THERMAL_YES, + THERMAL_NO, +} THERMAL_T; + +//Support get CPU temperature or not +typedef enum { + CPUTMP_UNKNOWN, + CPUTMP_YES, + CPUTMP_NO, +} CPUTMP_T; + +typedef enum { + DISK_LED_CTRL_UNKNOWN, + DISK_LED_CTRL_SW, + DISK_LED_CTRL_HW, +} DISK_LED_CTRL_T; + +typedef enum { + AUTO_POWERON_UNKNOWN, + AUTO_POWERON_YES, + AUTO_POWERON_NO, +} AUTO_POWERON_T; + +typedef enum { + POWER_UNKNOWN, + POWER_SINGLE, + POWER_DUAL, +} DUAL_POWER_T; + +typedef enum { + USBCOPY_NO = 0, + USBCOPY_MICROP, + USBCOPY_GPIO, +} USBCOPY_T; + +typedef enum { + FAN_NUMBER_X = 0, + FAN_NUMBER_1 = 1, + FAN_NUMBER_2 = 2, + FAN_NUMBER_3 = 3, + FAN_NUMBER_4 = 4, + FAN_NUMBER_5 = 5, + FAN_NUMBER_6 = 6, +} FAN_NUMBER_T; + +typedef enum _tag_POWER_IN_SEQ { + POWER_IN_SEQ_OFF, + POWER_IN_SEQ_2, + POWER_IN_SEQ_4, +} POWER_IN_SEQ; + +typedef enum _tag_RTC_TYPE { + RTC_UNKNOWN, + RTC_RICOH, + RTC_SEIKO, + RTC_BANDON, + RTC_MV, + RTC_DIODES, +} RTC_TYPE; + +typedef enum { + FAN_RPM_RPT_UNKNOWN, + FAN_RPM_RPT_YES, + FAN_RPM_RPT_NO, +} FAN_RPM_RPT_T; + +typedef enum { + LCM_UNKNOWN, + LCM_YES, + LCM_NO +} LCM_T; + +typedef enum { + WIFI_WPS_NO = 0xFE, + WIFI_WPS_UNKNOWN = 0xFF +} WIFI_WPS_T; + +typedef enum { + CPU_FREQ_ADJUST_UNKNOWN, + CPU_FREQ_ADJUST_YES, + CPU_FREQ_ADJUST_NO, +} CPUFREQ_ADJUST_T; + +typedef enum { + CARDREADER_UNKNOWN, + CARDREADER_YES, + CARDREADER_NO, +} CARDREADER_T; + +typedef enum { + MICROP_PWM_UNKNOWN, + MICROP_PWM_YES, + MICROP_PWM_NO, +} MICROP_PWM_T; + +typedef enum { + HIBER_LED_UNKNOWN, + HIBER_LED_STATUS_OFF, /* status led off, others don't care */ + HIBER_LED_STATUS_BREATH, /* status led breathing */ + HIBER_LED_POWER_ONLY, /* power led on, others off */ + HIBER_LED_STANDARD_BEHAVIOR, /* hibernation status off, deep sleep disk off */ +} HIBERNATE_LED_T; + +//For backward compatibility +#define HIBER_LED_NORMAL HIBER_LED_STATUS_OFF +#define HIBER_LED_ALLOUT HIBER_LED_STATUS_BREATH +#define HIBER_LED_EXCEPTPWR HIBER_LED_POWER_ONLY + +typedef enum { + RTC_NOT_NEED_TO_CORRECT = 0x00, + RTC_SEIKO_CORR_DEFAULT = 0x03, /* -5.62 sec/day */ + RTC_SEIKO_CORR_106B1 = 0x57, + RTC_RICOH_CORR_DEFAULT = 0x0F, +} RTC_CORRECTION_T; + +typedef enum { + MICROP_ID_710p = 0x31, /* '1' */ + MICROP_ID_411p = 0x33, /* '3' 411+II is the same*/ + MICROP_ID_1010p = 0x32, /* '2' */ + MICROP_ID_1511p = 0x36, /* '6' */ + MICROP_ID_810p = 0x35, /* '5' */ + MICROP_ID_810rp = 0x34, /* '4' */ + MICROP_ID_2211p = 0x37, /* '7' */ + MICROP_ID_2211rp = 0x38, /* '8' */ + MICROP_ID_2411p = 0x39, /* '9' */ + MICROP_ID_3411xs = 0x43, /* 'C' 3412xs is the same */ + MICROP_ID_3411rpxs = 0x41, /* 'A' 3412rpxs is the same */ + MICROP_ID_3611xs = 0x42, /* 'B' 3612xs is the same*/ + MICROP_ID_712p = 0x44, /* 'D' */ + MICROP_ID_412p = 0x45, /* 'E' */ + MICROP_ID_1512p = 0x47, /* 'G' */ + MICROP_ID_1812p = 0x46, /* 'F' */ + MICROP_ID_812p = 0x48, /* 'H' */ + MICROP_ID_812rp = 0x49, /* 'I' */ + MICROP_ID_2212p = 0x4A, /* 'J' */ + MICROP_ID_2212rp = 0x4B, /* 'K' */ + MICROP_ID_2413p = 0x4C, /* 'L' */ + MICROP_ID_10613xsp = 0x4d, /* 'M' */ + MICROP_ID_3413xsp = 0x4e, /* 'N' */ + MICROP_ID_713p = 0x50, /* 'P' */ + MICROP_ID_1513p = 0x51, /* 'Q' */ + MICROP_ID_1813p = 0x52, /* 'R' */ + MICROP_ID_RS2414p = 0x53, /* 'S' */ + MICROP_ID_RS2414rpp = 0x54, /* 'T' */ + MICROP_ID_RS814p = 0x55, /* 'U' */ + MICROP_ID_RS814rpp = 0x56, /* 'V' */ + MICROP_ID_RS3614xsp = 0x57, /* 'W' RS3614xsp */ + MICROP_ID_RS3617xs = 0x57, /* 'W' RS3617xs */ + MICROP_ID_ES3614xsp = 0x57, /* 'W' ES3614xsp */ + MICROP_ID_RS3614xs = 0x5B, /* 'W' RS3614xs */ + MICROP_ID_RS3614rpxs = 0x5C, /* 'W' RS3614rpxs */ + MICROP_ID_RC18015xsp = 0x4d, /* 'M' Temporarily using the same microp ID as 10613 */ + MICROP_ID_RS18016xsp = 0x4d, /* 'M' */ + MICROP_ID_RS18016Dxsp = 0x4d, /* 'M' */ + MICROP_ID_FS3017 = 0x4d, /* 'M' */ + MICROP_ID_DS2414xs = 0x57, /* 'W' DS2414xs */ + MICROP_ID_RS3415xsp = 0x60, /* '`' RS3415xs+ cheese cake*/ + MICROP_ID_3615xs = 0x5D, /* ']' DS3615xs*/ + MICROP_ID_RS3614xsR1 = 0x64, /* 'd' RS3614xs R1 */ + MICROP_ID_RS3614rpxsR1 = 0x65, /* 'e' RS3614rpxs R1 */ + MICROP_ID_UNKNOW = 0xFF, +} SYNO_MICROP_ID; + +#define MICROP_LOG_OFF 0 +#define MICROP_LOG_ON 1 + +/* This is for grpup wake setting + * [7-4]: how many disks are in one group + * [3-0]: the deno of 7s, it means how + * many seconds between each groups + * ex. 0x47 means 4 disks in one gorup, + * and delay 7/7 = 1s between each waking groups + **/ +typedef enum { + ONE_DISK_DENO_ONE = 0x11, /* this is default settings */ + FOUR_DISK_DENO_SEVEN = 0x47, /* if the model is >=8bay, you must use this */ + FIVE_DISK_DENO_ONE = 0x51, /* for 5bay, wakeup simultaneously, but insert command before wakeup */ + UNKNOW_DISK_DENO = 0x00, +} GROUP_WAKE_CONFIG_T; + +typedef enum { + CPU_UNKNOWN, + CPU_E5_2620v3, + CPU_E5_2609v3, + CPU_E3_1230v2, + CPU_D_1508, + CPU_D_1521, + CPU_D_1527, + CPU_D_1528, + CPU_D_1531, + CPU_D_1541, + CPU_D_1567, + CPU_I3_2100, + CPU_I3_4130, + CPU_D410, + CPU_D425, + CPU_D510, + CPU_D525, + CPU_D2700, + CPU_CE5335, + CPU_88F6281, + CPU_88F6282, + CPU_88F6702, + CPU_88F6707, + CPU_88F6720, + CPU_88F6820, + CPU_88F6828, + CPU_88F3710, + CPU_88F3720, + CPU_MV78230, + CPU_8241, + CPU_8533e, + CPU_P1022, + CPU_C2000, + CPU_LS1024, + CPU_AL212, + CPU_AL314, + CPU_AL514, + CPU_C2538, + CPU_BCM58622, + CPU_J1800, + CPU_J3355, + CPU_J3455, + CPU_J4005, + CPU_J4025, + CPU_J4105, + CPU_J4125, + CPU_J4205, + CPU_HI3535, + CPU_H412, + CPU_N3000, + CPU_N3050, + CPU_N3150, + CPU_N3700, + CPU_NVR, + CPU_N3010, + CPU_N3060, + CPU_N3160, + CPU_N3710, + CPU_HI3536, + CPU_RTD1296, + CPU_RTD1293, + CPU_C3538, + CPU_SILVER_4110, + CPU_RTD1619, + CPU_D_2143IT, + CPU_V1500B, + CPU_SILVER_4210R, + CPU_SILVER_4214R, + CPU_V1780B, + CPU_EPYC7272, + CPU_R1600, + CPU_D_5566, + CPU_RTD1619B, + CPU_EPYC7232P, + CPU_5800E, + CPU_EPYC7443P +} CPU_ARCH_INFO_T; + +typedef enum { + CRYPTO_HW_NONE, + CRYPTO_A370, + CRYPTO_A375, + CRYPTO_A38X, + CRYPTO_AXP, + CRYPTO_COMCERTO2K, + CRYPTO_ALPINE, + CRYPTO_QORIQ, + CRYPTO_853X, + CRYPTO_628X, + CRYPTO_RTD129X, + CRYPTO_RTD1619, + CRYPTO_RTD1619B +} CRYPTO_HW_INFO_T; + +/** + * This structure is used to store types of each module + * in different DS models, including module fan type, + * module raid type, ... + */ +typedef struct { + FAN_T fan_type :4; + LED_T led_type :4; + THERMAL_T thermal_type :2; + DISK_LED_CTRL_T diskled_ctrl_type:2; + AUTO_POWERON_T auto_poweron_type :2; + DUAL_POWER_T dual_power_type :2; + USBCOPY_T usbcopy_type :2; + FAN_NUMBER_T fan_number :4; + EUNIT_PWRON_TYPE eunit_pwron_type:4; + POWER_IN_SEQ pis_type :4; + RTC_TYPE rtc_type :4; + CPUTMP_T cputmp_type :2; + FAN_RPM_RPT_T fan_rpm_rpt_type :2; + LCM_T lcm_type :2; + WIFI_WPS_T wifi_wps_type :8; + CPUFREQ_ADJUST_T cpu_freq_adjust :2; + CARDREADER_T has_cardreader :2; + HIBERNATE_LED_T hibernate_led :4; + RTC_CORRECTION_T rtc_corr_value :8; + SYNO_MICROP_ID microp_id :8; + GROUP_WAKE_CONFIG_T group_wake_config :8; + CPU_ARCH_INFO_T cpu_arch_info :8; + CRYPTO_HW_INFO_T crypto_hw_info :8; +} __attribute__((packed)) module_t; + +typedef struct _tag_HwCapability { + char* szHwVersion; + CAPABILITY capability[MAX_CAPABILITY]; +} HwCapability; + +// Synology Disk Station model +typedef enum { + MODEL_RS3411rpxs = 0x00, + MODEL_RS3411xs = 0x01, + MODEL_RS10613xsp = 0x02, + MODEL_DS3611xs, + MODEL_RS3412rpxs, + MODEL_RS3412xs, + MODEL_DS3612xs, + MODEL_RS3413xsp, + MODEL_RS3614xs, + MODEL_RS3614rpxs, + MODEL_RS3614xsp, //10 + MODEL_ES3614xsp, + MODEL_DS2414xs, + MODEL_DS412p, + MODEL_DS713p, + MODEL_RS812p, + MODEL_RS812rpp, + MODEL_DS1812p, + MODEL_RS2212p, + MODEL_RS2212rpp, + MODEL_RS2414p, //20 + MODEL_RS2414rpp, + MODEL_DS2413p, + MODEL_RS812, + MODEL_DS1512p, + MODEL_DS112slim, + MODEL_DS414j, + MODEL_DS415j, + MODEL_DS213, + MODEL_RS214, //30 + MODEL_DS1513p, + MODEL_DS1813p, + MODEL_DS213j, + MODEL_DS114, + MODEL_DS214, + MODEL_DS214p, + MODEL_DS414, + MODEL_RS814, + MODEL_DS114p, + MODEL_RC18015xsp, //40 + MODEL_RS814p, + MODEL_RS814rpp, + MODEL_DS214se, + MODEL_DS214play, + MODEL_DS2415p, + MODEL_DS414slim, + MODEL_DS415play, + MODEL_DS2015xs, + MODEL_DS115j, + MODEL_RS3415xsp, //50 + MODEL_DS415p, + MODEL_DS3615xs, + MODEL_DS1815p, + MODEL_DS1515p, + MODEL_DS215j, + MODEL_RS815p, + MODEL_RS815rpp, + MODEL_DS715, + MODEL_DS115, //60 + MODEL_RS815, + MODEL_RS18016xsp, + MODEL_VS360hd, + MODEL_DS1515, + MODEL_DS215p, + MODEL_DS416, + MODEL_RR36015xsppp, + MODEL_VirtualDSM, + MODEL_RS18016Dxsp, + MODEL_RS2416p, //70 + MODEL_RS2416rpp, + MODEL_DS216play, + MODEL_DS216se, + MODEL_DS916p, + MODEL_RSD18016xsp, + MODEL_DS1616p, + MODEL_DS716p, + MODEL_RS3618xs, + MODEL_RS3617rpxs, + MODEL_RS3617xsp, //80 + MODEL_DS416j, + MODEL_DS216, + MODEL_DS416slim, + MODEL_DS216p, + MODEL_DS216j, + MODEL_RS816, + MODEL_DS116, + MODEL_DS416play, + MODEL_DS216pII, + MODEL_DS716pII, //90 + MODEL_RS217, + MODEL_FS3017, + MODEL_RS3617xs, + MODEL_RS2418p, + MODEL_RS2418rpp, + MODEL_DS918p, + MODEL_RS4017xsp, + MODEL_DS3617xs, + MODEL_RS18017xsp, + MODEL_DS218p, //100 + MODEL_DS1618p, + MODEL_C2DSM, + MODEL_DS1517p, + MODEL_DS1817p, + MODEL_DS718p, + MODEL_FS2017, + MODEL_DS418j, + MODEL_DS418, + MODEL_DS218play, + MODEL_DS118, //110 + MODEL_DS218, + MODEL_EDS19, + MODEL_RS819, + MODEL_DS220j, + MODEL_DS420j, + MODEL_DS1817, + MODEL_DS1517, + MODEL_DS3017xs, + MODEL_DS3018xs, + MODEL_FS1018, //120 + MODEL_DS219j, + MODEL_FS6400, + MODEL_RS818p, + MODEL_RS818rpp, + MODEL_DS418play, + MODEL_RS2818rpp, + MODEL_DS219se, + MODEL_NVR1218, + MODEL_DS218j, + MODEL_DS3619xs, //130 + MODEL_DS119j, + MODEL_RS1619xsp, + MODEL_TAIPEI, + MODEL_RS1219p, + MODEL_DS2419p, + MODEL_DS419p, + MODEL_DS1019p, + MODEL_DS719p, + MODEL_DS1819p, + MODEL_DS620slim, //140 + MODEL_RS419p, + MODEL_DS419slim, + MODEL_RS1219, + MODEL_DVA3219, + MODEL_SA3400, + MODEL_DS420p, + MODEL_DS720p, + MODEL_DS220p, + MODEL_RS820p, + MODEL_RS820rpp, //150 + MODEL_FS3400, + MODEL_SA3600, + MODEL_FS3600, + MODEL_HD3400, + MODEL_DS220play, + MODEL_DS220, + MODEL_DS120j, + MODEL_DS1520p, + MODEL_RS1220p, + MODEL_RS1220rpp, + MODEL_DS1621xsp, + MODEL_DS920p, + MODEL_SA6500, + MODEL_DS1621p, + MODEL_HD6500, + MODEL_SA3200d, + MODEL_DVA3221, + MODEL_AliDSM, + MODEL_RS1221p, + MODEL_RS1221rpp, + MODEL_DS1821p, + MODEL_DS2422p, + MODEL_RS2421p, + MODEL_RS2421rpp, + MODEL_RS2821rpp, + MODEL_FS6600N, + MODEL_RS3621xsp, + MODEL_RS3621rpxs, + MODEL_RS4021xsp, + MODEL_FS6500, + MODEL_DS3617xsII, + MODEL_DS3622xsp, + MODEL_DS2419pII, + MODEL_FS2500, + MODEL_FS2500T, + MODEL_FS6400N, + MODEL_DS723p, + MODEL_DS923p, + MODEL_RS422p, + MODEL_DVA1622, + MODEL_RS4023xsp, + MODEL_DS223j, + MODEL_DS1522p, + MODEL_RS4022xsp, + MODEL_FS3410, + MODEL_DS423, + MODEL_FS6410, + MODEL_SA6400, + MODEL_SA6200, + MODEL_SC6200, + MODEL_DS223, + MODEL_RS822p, + MODEL_RS822rpp, + MODEL_RS2423p, + MODEL_RS2423rpp, + MODEL_DS1823xsp, + MODEL_RS1623xsp, + MODEL_DS423p, + MODEL_SA3410, + MODEL_SA3610, + MODEL_DS124, + MODEL_VS750hd, + MODEL_SA3400d, + MODEL_DS224p, + MODEL_RS4024xsp, + MODEL_FS6600DN, + MODEL_DS1623p, + MODEL_DS1823p, + MODEL_SC2500, + MODEL_INVALID +} PRODUCT_MODEL; + +typedef struct _tag_SYNO_MODEL_NAME { + PRODUCT_MODEL model; + char* szHwVersion; +} SYNO_MODEL_NAME; + + +typedef struct _tag_CPLDReg { + unsigned char diskledctrl; + unsigned char diskpowerstate; + unsigned char modelnumber; + unsigned char fanstatus; +} CPLDREG; + +typedef struct _tag_MEMORY_BYTE { + unsigned char offset; + unsigned char value; +} MEMORY_BYTE; + +typedef struct _tag_GPIO_PIN { + int pin; + int value; +} GPIO_PIN; + +typedef struct _tag_POWER_INFO { + SYNO_POWER_STATUS power_1; + SYNO_POWER_STATUS power_2; +} POWER_INFO; + +typedef enum { + NET_LINK = 0, + NET_NOLINK, +} SYNO_NET_LINK_EVENT; + + +/** + * from first 0 bit to 6th bit is signature + * 7th bit indicate component status, true is compoent fail + * the others bits are id + */ +typedef unsigned int sys_comp_stat_t; +#define COMP_STAT_BITS sizeof(sys_comp_stat_t)*8 + +#define SYS_STAT_SIGNATURE_MASK 0x7F +#define SYS_STAT_COMPONENT_MASK 0x80 +#define SYS_STAT_ID_MASK ~(0xFF) + +#define SYS_STAT_COMPONENT_SHIFT 7 +#define SYS_STAT_IDX_SHIFT 8 + +#define DEFINE_COMP_STAT(x) sys_comp_stat_t x = 0 + +#define ID_LIST_GET(sys_comp_stat_t) (sys_comp_stat_t & SYS_STAT_ID_MASK) +#define ID_LIST_ENCODE(idx) ((1 << idx) << SYS_STAT_IDX_SHIFT) +#define ID_LIST_DECODE(sys_comp_stat_t) (sys_comp_stat_t >> SYS_STAT_IDX_SHIFT) +#define ID_LIST_EMPTY(sys_comp_stat_t) (0 == ID_LIST_DECODE(sys_comp_stat_t)) +#define SIGNATURE_GET(sig) (sig & SYS_STAT_SIGNATURE_MASK) +#define SIGNATURE_INCLUDE(sys_comp_stat_t) (sys_comp_stat_t & SYS_STAT_SIGNATURE_MASK) +#define COMP_STAT_ENCODE(boolean) (boolean << SYS_STAT_COMPONENT_SHIFT) +#define COMP_FAIL(sys_comp_stat_t) (sys_comp_stat_t & SYS_STAT_COMPONENT_MASK) + +/** + * This is the primaty key for look up SYNO_SYS_STATUS. + * When we want add a new component status. You must add a new + * signature too + */ +typedef enum { + SIGNATURE_FAN_FAIL = 0x1, + SIGNATURE_VOLUME_DEGRADE = 0x2, + SIGNATURE_VOLUME_CRASHED = 0x3, + SIGNATURE_POWER_FAIL = 0x4, + SIGNATURE_EBOX_FAN_FAIL = 0x5, + SIGNATURE_CPU_FAN_FAIL = 0x6, +} SYNO_SYS_STAT_SIGNATURE; + +/** + * These are system components stat, we don't use array here. + * Because it still need hard code signature in synobios.c + */ +typedef struct _tag_SYNO_SYS_STATUS { + sys_comp_stat_t fan_fail; + sys_comp_stat_t volume_degrade; + sys_comp_stat_t volume_crashed; + sys_comp_stat_t power_fail; + sys_comp_stat_t ebox_fan_fail; + sys_comp_stat_t cpu_fan_fail; +} SYNO_SYS_STATUS; + +typedef struct _tag_SYNO_CPU_INFO { + unsigned int core; + char clock[16]; +#if defined(CONFIG_SYNO_GRANTLEY) || defined(CONFIG_SYNO_PURLEY) + unsigned int cpucore[CONFIG_SYNO_MULTI_CPU_NUM]; +#endif +} SYNO_CPU_INFO; + +#define MAX_DISK_PER_INTF 64 +#define MAX_DISK_INTF_LEN 32 +typedef struct _tag_SYNO_DISK_INTF { + unsigned char disk_list[MAX_DISK_PER_INTF]; + char intf_name[MAX_DISK_INTF_LEN]; +} SYNO_DISK_INTF; +#define MAX_DISK_INTF 2 // for SAS/SATA or U.2 NVMe +typedef struct _tag_SYNO_DISK_INTF_INFO { + int intf_num; + SYNO_DISK_INTF disk_intf[MAX_DISK_INTF]; +} SYNO_DISK_INTF_INFO; + +#define SYNOIO_EXDISPLAY _IOWR(SYNOBIOS_IOC_MAGIC, 1, struct _SynoMsgPkt) +#define SYNOIO_NEXTEVENT _IOWR(SYNOBIOS_IOC_MAGIC, 2, u_int) + +#define SYNOIO_RTC_CONTROL_READ _IOWR(SYNOBIOS_IOC_MAGIC, 3, struct _SynoRtcControlPkt) +#define SYNOIO_RTC_CONTROL_WRITE _IOWR(SYNOBIOS_IOC_MAGIC, 4, struct _SynoRtcControlPkt) +#define SYNOIO_RTC_TIME_READ _IOWR(SYNOBIOS_IOC_MAGIC, 5, struct _SynoRtcTimePkt) +#define SYNOIO_RTC_TIME_WRITE _IOWR(SYNOBIOS_IOC_MAGIC, 6, struct _SynoRtcTimePkt) + +#define SYNOIO_BUTTON_POWER _IOWR(SYNOBIOS_IOC_MAGIC, 7, int) +#define SYNOIO_BUTTON_RESET _IOWR(SYNOBIOS_IOC_MAGIC, 8, int) +#define SYNOIO_BUTTON_USB _IOWR(SYNOBIOS_IOC_MAGIC, 9, int) + +#define SYNOIO_SET_DISK_LED _IOWR(SYNOBIOS_IOC_MAGIC, 10, DISKLEDSTATUS) +#define SYNOIO_GET_FAN_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 11, FANSTATUS) +#define SYNOIO_SET_FAN_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 12, FANSTATUS) +#define SYNOIO_GET_DS_MODEL _IOWR(SYNOBIOS_IOC_MAGIC, 13, int) +#define SYNOIO_GET_DS_BRAND _IOWR(SYNOBIOS_IOC_MAGIC, 14, int) +#define SYNOIO_GET_CPLD_VERSION _IOWR(SYNOBIOS_IOC_MAGIC, 15, int) +#define SYNOIO_GET_TEMPERATURE _IOWR(SYNOBIOS_IOC_MAGIC, 16, int) +#define SYNOIO_GET_CPLD_REG _IOWR(SYNOBIOS_IOC_MAGIC, 17, CPLDREG) +#define SYNOIO_GET_AUTO_POWERON _IOWR(SYNOBIOS_IOC_MAGIC, 18, SYNO_AUTO_POWERON) +#define SYNOIO_SET_AUTO_POWERON _IOWR(SYNOBIOS_IOC_MAGIC, 19, SYNO_AUTO_POWERON) +#define SYNOIO_GET_MEM_BYTE _IOWR(SYNOBIOS_IOC_MAGIC, 20, MEMORY_BYTE) +#define SYNOIO_SET_MEM_BYTE _IOWR(SYNOBIOS_IOC_MAGIC, 21, MEMORY_BYTE) +#define SYNOIO_SET_ALARM_LED _IOWR(SYNOBIOS_IOC_MAGIC, 22, unsigned char) +#define SYNOIO_GET_HW_CAPABILITY _IOWR(SYNOBIOS_IOC_MAGIC, 23, CAPABILITY) +#define SYNOIO_GET_FAN_NUM _IOWR(SYNOBIOS_IOC_MAGIC, 24, int) +#define SYNOIO_GET_POWER_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 25, POWER_INFO) +#define SYNOIO_SHUTDOWN_LOG _IOWR(SYNOBIOS_IOC_MAGIC, 26, SYNO_SHUTDOWN_LOG) +#define SYNOIO_UNINITIALIZE _IOWR(SYNOBIOS_IOC_MAGIC, 27, int) +#define SYNOIO_GET_SYS_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 28, SYNO_SYS_STATUS) +#define SYNOIO_SET_SYS_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 29, sys_comp_stat_t) +#define SYNOIO_GET_MODULE_TYPE _IOWR(SYNOBIOS_IOC_MAGIC, 30, module_t) +#define SYNOIO_GET_BUZZER_CLEARED _IOWR(SYNOBIOS_IOC_MAGIC, 31, unsigned char) +#define SYNOIO_GET_BACKPLANE_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 32, BACKPLANE_STATUS) +#define SYNOIO_SET_UART2 _IOWR(SYNOBIOS_IOC_MAGIC, 33, unsigned char) +#define SYNOIO_GET_CPU_TEMPERATURE _IOWR(SYNOBIOS_IOC_MAGIC, 34, SYNOCPUTEMP) +#define SYNOIO_SET_CPU_FAN_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 35, FANSTATUS) +#define SYNOIO_SET_PHY_LED _IOWR(SYNOBIOS_IOC_MAGIC, 36, SYNO_LED) +#define SYNOIO_SET_HDD_LED _IOWR(SYNOBIOS_IOC_MAGIC, 37, SYNO_LED) +#define SYNOIO_SET_PWR_LED _IOWR(SYNOBIOS_IOC_MAGIC, 38, SYNO_LED) +#define SYNOIO_PWM_CTL _IOWR(SYNOBIOS_IOC_MAGIC, 39, SynoPWMCTL) +#define SYNOIO_CHECK_MICROP_ID _IO(SYNOBIOS_IOC_MAGIC, 40) +//#define SYNOIO_GET_EUNIT_TYPE _IOR(SYNOBIOS_IOC_MAGIC, 41, EUNIT_PWRON_TYPE) // Move into kernel +#define SYNOIO_SET_BUZZER_CLEAR _IOWR(SYNOBIOS_IOC_MAGIC, 42, unsigned char) +#define SYNOIO_WRITE_MEM _IOWR(SYNOBIOS_IOC_MAGIC, 43, SYNO_MEM_ACCESS) +#define SYNOIO_READ_MEM _IOWR(SYNOBIOS_IOC_MAGIC, 44, SYNO_MEM_ACCESS) +#define SYNOIO_SET_AHA_LED _IOWR(SYNOBIOS_IOC_MAGIC, 45, SYNO_AHA_LED) +#define SYNOIO_GET_COPY_BUTTON _IOWR(SYNOBIOS_IOC_MAGIC, 46, int) // for matching userspace usage, button pressed = 0, else = 1 +#define SYNOIO_SET_AND_GET_UART2 _IOWR(SYNOBIOS_IOC_MAGIC, 47, unsigned char) +#define SYNOIO_GET_UART2 _IOWR(SYNOBIOS_IOC_MAGIC, 48, unsigned char) +#define SYNOIO_UART_DEBUG_CONTROL _IOWR(SYNOBIOS_IOC_MAGIC, 49, unsigned char) +#define SYNOIO_GET_SYS_CURRENT _IOWR(SYNOBIOS_IOC_MAGIC, 50, unsigned long) +#define SYNOIO_SET_RP_FAN _IOWR(SYNOBIOS_IOC_MAGIC, 51, unsigned char) + +#define SYNOIO_POWER_OFF _IOWR(SYNOBIOS_IOC_MAGIC, 65, int) + +#define SYNOIO_MANUTIL_MODE _IOWR(SYNOBIOS_IOC_MAGIC, 128, int) +#define SYNOIO_RECORD_EVENT _IOWR(SYNOBIOS_IOC_MAGIC, 129, int) + +#ifdef SYNO_HI_3535 +#define SYNOIO_GPIO_PIN_READ _IOWR(SYNOBIOS_IOC_MAGIC, 205, GPIO_PIN) +#define SYNOIO_GPIO_PIN_WRITE _IOWR(SYNOBIOS_IOC_MAGIC, 206, GPIO_PIN) +#else +#define SYNOIO_GPIO_PIN_READ _IOWR(SYNOBIOS_IOC_MAGIC, 205, int) +#define SYNOIO_GPIO_PIN_WRITE _IOWR(SYNOBIOS_IOC_MAGIC, 206, int) +#endif + +#define SYNOIO_RTC_READ _IOWR(SYNOBIOS_IOC_MAGIC, 208, struct _SynoRtcPkt) +#define SYNOIO_RTC_READ_3 _IOWR(SYNOBIOS_IOC_MAGIC, 209, struct _SynoRtcPkt) +#define SYNOIO_SDA_SDL_READ _IOWR(SYNOBIOS_IOC_MAGIC, 210, int) + + +#ifdef SYNO_BAD_SECTOR_DISK_DEBUG +#define DISK_BADSECTOR_ON _IOWR(SYNOBIOS_IOC_MAGIC, 211, int) +#define DISK_BADSECTOR_OFF _IOWR(SYNOBIOS_IOC_MAGIC, 212, int) +#define DISK_BADSECTOR_SET _IOWR(SYNOBIOS_IOC_MAGIC, 213, struct disk_bs_map_ctlcmd) +#define DISK_BADSECTOR_GET _IOWR(SYNOBIOS_IOC_MAGIC, 214, struct disk_bs_map_ctlcmd) +#define DISK_BADSECTOR_RESET _IOWR(SYNOBIOS_IOC_MAGIC, 215, int) +#endif + +#define HWMON_GET_SUPPORT _IOWR(SYNOBIOS_IOC_MAGIC, 301, SYNO_HWMON_SUPPORT) +#define HWMON_GET_CPU_TEMPERATURE _IOWR(SYNOBIOS_IOC_MAGIC, 302, SYNO_HWMON_SENSOR_TYPE) +#define HWMON_GET_FAN_SPEED_RPM _IOWR(SYNOBIOS_IOC_MAGIC, 303, SYNO_HWMON_SENSOR_TYPE) +#define HWMON_GET_PSU_STATUS _IOWR(SYNOBIOS_IOC_MAGIC, 304, SYNO_HWMON_SENSOR_TYPE) +#define HWMON_GET_SYS_VOLTAGE _IOWR(SYNOBIOS_IOC_MAGIC, 305, SYNO_HWMON_SENSOR_TYPE) +#define HWMON_GET_SYS_THERMAL _IOWR(SYNOBIOS_IOC_MAGIC, 306, SYNO_HWMON_SENSOR_TYPE) +#define HWMON_GET_HDD_BACKPLANE _IOWR(SYNOBIOS_IOC_MAGIC, 307, SYNO_HWMON_SENSOR_TYPE) +#define HWMON_GET_SYS_CURRENT _IOWR(SYNOBIOS_IOC_MAGIC, 308, SYNO_HWMON_SENSOR_TYPE) + +/* Move into kernel +#define SYNOIO_SUPERIO_READ _IOWR(SYNOBIOS_IOC_MAGIC, 216, SYNO_SUPERIO_PACKAGE) +#define SYNOIO_SUPERIO_WRITE _IOWR(SYNOBIOS_IOC_MAGIC, 217, SYNO_SUPERIO_PACKAGE) +#define SYNOIO_IS_FULLY_SUPPORT_EUP _IOWR(SYNOBIOS_IOC_MAGIC, 218, SYNO_EUP_SUPPORT) +*/ + +#define SYNOIO_SET_OK_TO_REMOVE_LED _IOWR(SYNOBIOS_IOC_MAGIC, 219, unsigned char) +#define SYNOIO_CHECK_DISK_INTF _IOWR(SYNOBIOS_IOC_MAGIC, 220, SYNO_DISK_INTF_INFO) + +/* +#define SYNOIO_HWSTATUS _IOR('A', 102, struct _Synohw) +#define SYNOIO_TESTING _IOW('P', 104, int) +#define SYNOIO_SERIAL _IOR('A', 105, int) +#define SYNOIO_HDBACK _IOW('P', 106, int) +#define SYNOIO_SYNOVER _IOR('A', 107, unsigned long) +#define SYNOIO_GETSERIALNUM _IOR('A', 108, off_t) +#define SYNOIO_SETHWSTATUS _IOW('P', 109, HWBLOCK) +#define SYNOIO_HWHDSUPPORT _IOR('A', 110, int) +#define SYNOIO_HWTHERMALSUPPORT _IOR('A', 111, int) +#define SYNOIO_POWEROFF _IO('A', 114) +#define SYNOIO_SETHWSTATUS_INIT _IOW('P', 111, HWBLOCK) +#define SYNOIO_HWSTATUS_CUSTOM _IOR('A', 112, struct _Synohw_custom) +#define SYNOIO_SET_EVENT _IOW('P', 113, u_int) +#define SYNOIO_BIOSVER _IOWR('P', 115, BVS) +*/ +#define SCEM_IOC_TESTING_DISABLE_TEST 0x00 +#define SCEM_IOC_TESTING_ENABLE_TEST 0x01 + +#define SCEM_IOC_TESTING_ACPOWER_ON 0x10 +#define SCEM_IOC_TESTING_ACPOWER_OFF 0x11 + +#define SCEM_IOC_TESTING_SET_OVERHEATING_0 0x20 +#define SCEM_IOC_TESTING_SET_OVERHEATING_1 0x21 +#define SCEM_IOC_TESTING_SET_OVERHEATING_2 0x22 +#define SCEM_IOC_TESTING_SET_OVERHEATING_3 0x23 + +#define SCEM_IOC_TESTING_SET_MEMORY_ECC_0 0x30 +#define SCEM_IOC_TESTING_SET_MEMORY_ECC_1 0x31 +#define SCEM_IOC_TESTING_SET_MEMORY_ECC_2 0x32 + +#define SCEM_IOC_TESTING_SET_BUTTON_0 0x40 +#define SCEM_IOC_TESTING_SET_BUTTON_1 0x41 +#define SCEM_IOC_TESTING_SET_BUTTON_2 0x42 +#define SCEM_IOC_TESTING_SET_BUTTON_3 0x43 +#define SCEM_IOC_TESTING_SET_BUTTON_4 0x44 +#define SCEM_IOC_TESTING_SET_BUTTON_5 0x45 +#define SCEM_IOC_TESTING_SET_BUTTON_6 0x46 +#define SCEM_IOC_TESTING_SET_BUTTON_7 0x47 +#define SCEM_IOC_TESTING_SET_BUTTON_8 0x48 + +#define SCEM_IOC_TESTING_RM_HDA 0x51 +#define SCEM_IOC_TESTING_RM_HDB 0x52 +#define SCEM_IOC_TESTING_RM_HDC 0x53 +#define SCEM_IOC_TESTING_RM_HDD 0x54 +#define SCEM_IOC_TESTING_RM_HDE 0x55 +#define SCEM_IOC_TESTING_RM_HDF 0x56 +#define SCEM_IOC_TESTING_RM_HDG 0x57 +#define SCEM_IOC_TESTING_RM_HDH 0x58 + +#define SCEM_IOC_TESTING_PLUG_HDA 0x61 +#define SCEM_IOC_TESTING_PLUG_HDB 0x62 +#define SCEM_IOC_TESTING_PLUG_HDC 0x63 +#define SCEM_IOC_TESTING_PLUG_HDD 0x64 +#define SCEM_IOC_TESTING_PLUG_HDE 0x65 +#define SCEM_IOC_TESTING_PLUG_HDF 0x66 +#define SCEM_IOC_TESTING_PLUG_HDG 0x67 +#define SCEM_IOC_TESTING_PLUG_HDH 0x68 + +#define ACPOWER_FAILURE 1 + +#define THERMAL_NORMAL 0 +#define THERMAL_WARM 1 +#define THERMAL_HEAT 2 +#define THERMAL_CRITICAL 3 + +#define NO_MEM_ECC 0 +#define MEM_ECC_ONCE 1 +#define MEM_ECC_TWICE_OR_MORE 2 + +#define THERMAL_STAGE(a) \ + ((a >= iThermal3) ? THERMAL_CRITICAL : \ + ((a >= iThermal2) ? THERMAL_HEAT : \ + ((a >= iThermal1) ? THERMAL_WARM : THERMAL_NORMAL))) + +#define F_GET_ACPOWER(a) (a->AcPowerStatus) +#define F_GET_THERMAL(a) (a->ThermalStage) +#define F_GET_BUTTON(a) (a->ButtonStatus) +#define F_GET_MEMORY(a) (a->MemEccCount) + +#define F_GET_1_BUTTON(a) ((a->ButtonStatus)&0x0001) +#define F_GET_IPBUTTON(a) ((a->ButtonStatus)&0x0001) +#define F_GET_2_BUTTON(a) ((a->ButtonStatus)&0x0002) +#define F_GET_BACKUP_BUTTON(a) ((a->ButtonStatus)&0x0002) +#define F_GET_3_BUTTON(a) ((a->ButtonStatus)&0x0004) +#define F_GET_4_BUTTON(a) ((a->ButtonStatus)&0x0008) +#define F_GET_5_BUTTON(a) ((a->ButtonStatus)&0x0010) +#define F_GET_6_BUTTON(a) ((a->ButtonStatus)&0x0020) +#define F_GET_7_BUTTON(a) ((a->ButtonStatus)&0x0040) +#define F_GET_8_BUTTON(a) ((a->ButtonStatus)&0x0080) + +#define EQ_ACPOWER_STATUS(a,b) ((a->AcPowerStatus)==(b->AcPowerStatus)) +#define EQ_THERMAL_STATUS(a,b) (THERMAL_STAGE(a->ThermalStage)==THERMAL_STAGE(b->ThermalStage)) +#define EQ_MEMORY_STATUS(a,b) ((a->MemEccCount)==(b->MemEccCount)) +#define EQ_BUTTON_STATUS(a,b) ((a->ButtonStatus)==(b->ButtonStatus)) +#define EQ_HD_STATUS(a, b) ((a->HardDiskStatus) == (b->HardDiskStatus)) +#define EQ_FAN_STATUS(a, b) ((a->FanFaultStatus) == (b->FanFaultStatus)) + +#define EQ_BUTTON_1_4(a, b) ((a->ButtonStatus&0x000f)==(b->ButtonStatus&0x000f)) +#define EQ_BUTTON_1_2(a, b) ((a->ButtonStatus&0x0003)==(b->ButtonStatus&0x0003)) +#define EQ_BUTTON_3_4(a, b) ((a->ButtonStatus&0x000c)==(b->ButtonStatus&0x000c)) +#define EQ_BUTTON_5_8(a, b) ((a->ButtonStatus&0x00f0)==(b->ButtonStatus&0x00f0)) +#define EQ_BUTTON_5_6(a, b) ((a->ButtonStatus&0x0030)==(b->ButtonStatus&0x0030)) +#define EQ_BUTTON_7_8(a, b) ((a->ButtonStatus&0x00c0)==(b->ButtonStatus&0x00c0)) +#define EQ_BUTTON_1(a, b) ((a->ButtonStatus&0x0001)==(b->ButtonStatus&0x0001)) +#define EQ_BUTTON_2(a, b) ((a->ButtonStatus&0x0002)==(b->ButtonStatus&0x0002)) +#define EQ_BUTTON_3(a, b) ((a->ButtonStatus&0x0004)==(b->ButtonStatus&0x0004)) +#define EQ_BUTTON_4(a, b) ((a->ButtonStatus&0x0008)==(b->ButtonStatus&0x0008)) +#define EQ_BUTTON_5(a, b) ((a->ButtonStatus&0x0010)==(b->ButtonStatus&0x0010)) +#define EQ_BUTTON_6(a, b) ((a->ButtonStatus&0x0020)==(b->ButtonStatus&0x0020)) +#define EQ_BUTTON_7(a, b) ((a->ButtonStatus&0x0040)==(b->ButtonStatus&0x0040)) +#define EQ_BUTTON_8(a, b) ((a->ButtonStatus&0x0080)==(b->ButtonStatus&0x0080)) + +#define F_GET_HD_STATUS_A(a) ((a->HardDiskStatus&0x0001)) +#define F_GET_HD_STATUS_B(a) ((a->HardDiskStatus&0x0002)) +#define F_GET_HD_STATUS_C(a) ((a->HardDiskStatus&0x0004)) +#define F_GET_HD_STATUS_D(a) ((a->HardDiskStatus&0x0008)) +#define F_GET_HD_STATUS_E(a) ((a->HardDiskStatus&0x0010)) +#define F_GET_HD_STATUS_F(a) ((a->HardDiskStatus&0x0020)) +#define F_GET_HD_STATUS_G(a) ((a->HardDiskStatus&0x0040)) +#define F_GET_HD_STATUS_H(a) ((a->HardDiskStatus&0x0080)) + +#define EQ_HD_STATUS_A_D(a,b) ((a->HardDiskStatus&0x000f)==(b->HardDiskStatus&0x000f)) +#define EQ_HD_STATUS_E_H(a,b) ((a->HardDiskStatus&0x00f0)==(b->HardDiskStatus&0x00f0)) +#define EQ_HD_STATUS_A_B(a,b) ((a->HardDiskStatus&0x0003)==(b->HardDiskStatus&0x0003)) +#define EQ_HD_STATUS_C_D(a,b) ((a->HardDiskStatus&0x000c)==(b->HardDiskStatus&0x000c)) +#define EQ_HD_STATUS_E_F(a,b) ((a->HardDiskStatus&0x0030)==(b->HardDiskStatus&0x0030)) +#define EQ_HD_STATUS_G_H(a,b) ((a->HardDiskStatus&0x00c0)==(b->HardDiskStatus&0x00c0)) +#define EQ_HD_STATUS_A(a,b) ((a->HardDiskStatus&0x0001)==(b->HardDiskStatus&0x0001)) +#define EQ_HD_STATUS_B(a,b) ((a->HardDiskStatus&0x0002)==(b->HardDiskStatus&0x0002)) +#define EQ_HD_STATUS_C(a,b) ((a->HardDiskStatus&0x0004)==(b->HardDiskStatus&0x0004)) +#define EQ_HD_STATUS_D(a,b) ((a->HardDiskStatus&0x0008)==(b->HardDiskStatus&0x0008)) +#define EQ_HD_STATUS_E(a,b) ((a->HardDiskStatus&0x0010)==(b->HardDiskStatus&0x0010)) +#define EQ_HD_STATUS_F(a,b) ((a->HardDiskStatus&0x0020)==(b->HardDiskStatus&0x0020)) +#define EQ_HD_STATUS_G(a,b) ((a->HardDiskStatus&0x0040)==(b->HardDiskStatus&0x0040)) +#define EQ_HD_STATUS_H(a,b) ((a->HardDiskStatus&0x0080)==(b->HardDiskStatus&0x0080)) + +#define PMEV_SYNO_EVENT0 0x0200 +#define PMEV_SYNO_EVENT1 0x0201 +#define PMEV_SYNO_EVENT2 0x0202 +#define PMEV_SYNO_EVENT3 0x0203 +#define PMEV_SYNO_EVENT4 0x0204 +#define PMEV_SYNO_EVENT5 0x0205 +#define PMEV_SYNO_EVENT6 0x0206 +#define PMEV_SYNO_EVENT7 0x0207 +#define PMEV_SYNO_EVENT8 0x0208 +#define PMEV_SYNO_EVENT9 0x0209 + +#define VMAX 32 +#define MAX_HD_NUM 16 +#define HD_NUM_MAX 16 +#define FAN_NUM_MAX 16 +#define POWER_NUM_MAX 16 +#define BATTERY_NUM_MAX 16 +#define LP3943_NUM_MAX 8 + + +/************************************************************************* + * SYNOHWWxternalControl message Id + ************************************************************************/ + +#define SYNO_PURE_MESSAGE 0x0000 +#define SYNO_DISABLE_CRITICAL 0x0100 +#define SYNO_ENABLE_CRITICAL 0x0101 +#define SYNO_E_MAIL_SUCCESS 0x0102 +#define SYNO_E_MAIL_FAILED 0x0103 +#define SYNO_DISABLE_IDENTIFY 0x0200 +#define SYNO_ENABLE_IDENTIFY 0x0300 +#define SYNO_BEEPER_MUTE 0x0400 +#define SYNO_BEEPER_BEEPBEEP 0x0500 +#define SYNO_CANCEL_DISK_FULL 0x0800 +#define SYNO_DISK_FULL 0x0900 +#define SYNO_CANCEL_VOLUME_FULL 0x8000 +#define SYNO_VOLUME_FULL 0x9000 +#define SYNO_DISK_NORMAL 0x1000 +#define SYNO_DISK_FAILURE 0x1100 +#define SYNO_DISK_REBUILD 0x1200 +#define SYNO_DISK_ABSENT 0x1300 +#define SYNO_DISK_INITIAL 0x1400 +#define SYNO_DISK_EMPTY 0x1500 +#define SYNO_DISK_BAD_SECTOR 0x1600 +#define SYNO_DISK_BAD_SYS 0x1700 +#define SYNO_DISK_BAD_SYSNSEC 0x1800 +#define SYNO_CPU_OVERHEAT 0x2101 +#define SYNO_CPU_NORMAL 0x2001 +#define SYNO_MEM_ECC 0x2104 +#define SYNO_FAN_FAULT 0x3000 +#define SYNO_POWER_FAULT 0x3100 +#define SYNO_BATTERY_FAILURE 0x3200 +#define SYNO_BATTERY_REMOVED 0x3300 +#define SYNO_FAN_RECOVERY 0x3400 +#define SYNO_POWER_RECOVERY 0x3500 +#define SYNO_NOP_SUCCESS 0x3600 +#define SYNO_NOP_FAILURE 0x3700 +#define SYNO_VOL_NORMAL 0x3800 +#define SYNO_VOL_BUILT 0x3900 +#define SYNO_VOL_FAILED 0x3a00 +#define SYNO_VOL_CREATE 0x3b00 +#define SYNO_VOL_REMOVE 0x3c00 +#define SYNO_SYS_MSG 0x4000 +#define SYNO_SYS_BOOT 0x4001 +#define SYNO_SYS_RUN 0x4002 +#define SYNO_SYS_SHUTDOWN 0x4003 +#define SYNO_SYS_NO_SYSTEM 0x4004 +#define SYNO_SYS_NODISK SYNO_SYS_NO_SYSTEM // NODISK is alias of NO_SYSTEM +#define SYNO_SYS_WAIT_RESET 0x4005 +#define SYNO_SYS_FACTORY_DEFAULT 0x4006 +#define SYNO_LED_USB_COPY_NONE 0x5100 +#define SYNO_LED_USB_COPY_STEADY 0x5101 +#define SYNO_LED_USB_COPY_BLINK 0x5102 +#define SYNO_LED_USB_EJECT_BLINK 0x5103 +#define SYNO_LED_HDD_GS 0x5200 +#define SYNO_LED_HDD_AS 0x5201 +#define SYNO_LED_HDD_AB 0x5202 +#define SYNO_LED_HDD_OFF 0x5203 +#define SYNO_LED_HDD_GB 0x5204 +#define SYNO_LED_ALARM_ON 0x5205 +#define SYNO_LED_ALARM_BLINKING 0x5206 +#define SYNO_LED_ALARM_OFF 0x5207 +#define SYNO_BEEP_OFF 0x5300 +#define SYNO_BEEP_ON 0x5301 +#define SYNO_BEEP_200MS 0x5302 +#define SYNO_POWER_OFF 0x5400 +#define SYNO_RCPOWER_ON 0x5500 +#define SYNO_RCPOWER_OFF 0x5600 +#define SYNO_AUTO_POWERON_ON 0x5700 +#define SYNO_AUTO_POWERON_OFF 0x5701 +#define SYNO_UART2_FANCHEK_ON 0x5800 +#define SYNO_UART2_FANCHEK_OFF 0x5801 +#define SYNO_LED_USBSTATION_DISK_GREEN 0x5900 +#define SYNO_LED_USBSTATION_DISK_ORANGE 0x5901 +#define SYNO_LED_USBSTATION_POWER 0x5902 +#define SYNO_LED_USBSTATION_MEMTEST_LED 0x5903 + +/*add by chchou : moved from synobios.c*/ +/*int SYNOBiosSetEvent(u_int event_type); +int ErrSYNOHardwareConfigure __P((int , int *)); +*/ +/**/ +/* Eval pin value considering polarity, output HIGH or LOW + P V (!P == !V) + 0 0 1 + 1 0 0 + 0 1 0 + 1 1 1 */ +#define EVAL_PIN_VAL(polarity, value) (!(polarity) == !(value)) + +struct synobios_ops { + struct module *owner; + int (*get_brand)(void); + int (*get_model)(void); + int (*get_cpld_version)(void); + int (*get_rtc_time)(struct _SynoRtcTimePkt *); + int (*set_rtc_time)(struct _SynoRtcTimePkt *); + int (*get_fan_status)(int, FAN_STATUS *); + int (*set_fan_status)(FAN_STATUS, FAN_SPEED); + int (*get_sys_temperature)(struct _SynoThermalTemp *); + int (*get_cpu_temperature)(struct _SynoCpuTemp *); + #if defined(CONFIG_SYNO_PORT_MAPPING_V2) + int (*set_disk_led)(DISKLEDSTATUS*); + #else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + int (*set_disk_led)(int, SYNO_DISK_LED); + #endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + int (*set_power_led)(SYNO_LED); + int (*get_cpld_reg)(CPLDREG *); + int (*set_mem_byte)(MEMORY_BYTE *); + int (*get_mem_byte)(MEMORY_BYTE *); + int (*set_gpio_pin)(GPIO_PIN *); + int (*get_gpio_pin)(GPIO_PIN *); + int (*set_gpio_blink)(GPIO_PIN *); + int (*set_auto_poweron)(SYNO_AUTO_POWERON *); + int (*get_auto_poweron)(SYNO_AUTO_POWERON *); + int (*init_auto_poweron)(void); + int (*uninit_auto_poweron)(void); + int (*set_alarm_led)(unsigned char); + int (*get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*set_buzzer_clear)(unsigned char buzzer_clear); + int (*get_power_status)(POWER_INFO *); + int (*get_backplane_status)(BACKPLANE_STATUS *); + int (*module_type_init)(struct synobios_ops *); + int (*uninitialize)(void); + int (*set_cpu_fan_status)(FAN_STATUS, FAN_SPEED); + int (*set_phy_led)(SYNO_LED); + int (*set_hdd_led)(SYNO_LED); + int (*pwm_ctl)(SynoPWMCTL *); + int (*check_microp_id)(const struct synobios_ops *); + int (*set_microp_id)(void); + int (*get_superio)(SYNO_SUPERIO_PACKAGE *); + int (*set_superio)(SYNO_SUPERIO_PACKAGE *); + int (*exdisplay_handler)(struct _SynoMsgPkt *); + int (*read_memory)(SYNO_MEM_ACCESS*); + int (*write_memory)(SYNO_MEM_ACCESS*); + void (*get_cpu_info)(SYNO_CPU_INFO*, const unsigned int); + int (*set_aha_led)(struct synobios_ops *, SYNO_AHA_LED); + int (*get_copy_button_status)(void); // for matching userspace usage, button pressed = 0, else = 1 + int (*hwmon_get_fan_speed_rpm)(SYNO_HWMON_SENSOR_TYPE *); + int (*hwmon_get_psu_status)(SYNO_HWMON_SENSOR_TYPE *, int); + int (*hwmon_get_sys_voltage)(SYNO_HWMON_SENSOR_TYPE *); + int (*hwmon_get_backplane_status)(SYNO_HWMON_SENSOR_TYPE *); + int (*hwmon_get_sys_thermal)(SYNO_HWMON_SENSOR_TYPE *); + int (*hwmon_get_sys_current)(SYNO_HWMON_SENSOR_TYPE *); + int (*set_ok_to_remove_led)(unsigned char ledON); + int (*get_sys_current)(unsigned long*); + int (*get_disk_intf)(SYNO_DISK_INTF_INFO *); + int (*set_rp_fan)(unsigned char); +}; + +/**************************/ +#define IXP425 + +PRODUCT_MODEL synobios_getmodel(void); + +#define PCI_VENDOR_SYNOLOGY 0x7053 + +#define PCI_DEVICE_E10G18T1 0x1001 +#define PCI_DEVICE_E10G18T2 0x1002 +#define PCI_DEVICE_E10G21F2 0x1003 +#define PCI_DEVICE_E25G21F2 0x1004 +#define PCI_DEVICE_E10G30T1 0x1005 +#define PCI_DEVICE_E10G22T1_MINI 0x1006 +#define PCI_DEVICE_E10G30T2_BROADCOM 0x1008 +#define PCI_DEVICE_E10G22T1_MINI_AQC107 0x1009 +#define PCI_DEVICE_E10G30T2_QLOGIC 0x100a +#define PCI_DEVICE_E10G30F2 0x100b +#define PCI_DEVICE_E25G30F2 0x100c +#define PCI_DEVICE_E10G30T1_AQC113 0x100d +#define PCI_DEVICE_E10G22T1_MINI_AQC113 0x100e +#define PCI_DEVICE_E10M20T1 0x2002 + +#define SZ_SYNOLOGY_M2D17 "M2D17" +#define SZ_SYNOLOGY_M2D18 "M2D18" +#define SZ_SYNOLOGY_M2D20 "M2D20" +#define SZ_SYNOLOGY_E10G18T1 "E10G18-T1" +#define SZ_SYNOLOGY_E10G18T2 "E10G18-T2" +#define SZ_SYNOLOGY_E10G21F2 "E10G21-F2" +#define SZ_SYNOLOGY_E25G21F2 "E25G21-F2" +#define SZ_SYNOLOGY_E10G30T1 "E10G30-T1" +#define SZ_SYNOLOGY_E10G30T2 "E10G30-T2" +#define SZ_SYNOLOGY_E10G30F2 "E10G30-F2" +#define SZ_SYNOLOGY_E25G30F2 "E25G30-F2" +#define SZ_SYNOLOGY_E10G22T1_MINI "E10G22-T1-Mini" +#define SZ_SYNOLOGY_E10M20T1 "E10M20-T1" +#define SZ_SYNOLOGY_FX2422N "FX2422N" + +#define __SYNOEVENTCALL_PARM1(parms) parms[0] +#define __SYNOEVENTCALL_PARM2(parms) \ + __SYNOEVENTCALL_PARM1(parms), parms[1] +#define __SYNOEVENTCALL_PARM3(parms) \ + __SYNOEVENTCALL_PARM2(parms), parms[2] +#define __SYNOEVENTCALL_PARM4(parms) \ + __SYNOEVENTCALL_PARM3(parms), parms[3] +#define __SYNOEVENTCALL_PARM5(parms) \ + __SYNOEVENTCALL_PARM4(parms), parms[4] + +#endif /* __SYNOBIOS_OEM_H_ */ diff --git a/drivers/syno/synobios/kvmcloud/Makefile b/drivers/syno/synobios/kvmcloud/Makefile new file mode 100644 index 000000000000..2e73a933fe31 --- /dev/null +++ b/drivers/syno/synobios/kvmcloud/Makefile @@ -0,0 +1,8 @@ +include /env.mak + +obj-m += kvmcloud-synobios.o + +kvmcloud-synobios-objs = \ + $(vdsm-common-obj) \ + alidsm.o \ + kvmcloud_common.o diff --git a/drivers/syno/synobios/kvmcloud/alidsm.c b/drivers/syno/synobios/kvmcloud/alidsm.c new file mode 100644 index 000000000000..75a860ffbdbf --- /dev/null +++ b/drivers/syno/synobios/kvmcloud/alidsm.c @@ -0,0 +1,32 @@ +// Copyright (c) 2017 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "kvmcloud_common.h" + +// extern function from bromolow_common +extern int KvmcloudRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int AliDSMInitModuleType(struct synobios_ops *ops) +{ + module_t type_alidsm = MODULE_T_AliDSM; + module_t *pType = &type_alidsm; + + module_type_set(pType); + return 0; +} + +struct model_ops alidsm_ops = { + .x86_init_module_type = AliDSMInitModuleType, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = KvmcloudRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/kvmcloud/kvmcloud_common.c b/drivers/syno/synobios/kvmcloud/kvmcloud_common.c new file mode 100755 index 000000000000..b690a24418fa --- /dev/null +++ b/drivers/syno/synobios/kvmcloud/kvmcloud_common.c @@ -0,0 +1,286 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "kvmcloud_common.h" + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = -1; + + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = -1; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL + *buzzer_cleared = gSynoBuzzerMutePressed; + gSynoBuzzerMutePressed = 0; + ret = 0; +#endif + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int KvmcloudRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if (!strncmp(gszSynoHWVersion, HW_AliDSM, strlen(HW_AliDSM))) { + model = MODEL_AliDSM; + } + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_AliDSM: + model_ops = &alidsm_ops; + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/kvmcloud/kvmcloud_common.h b/drivers/syno/synobios/kvmcloud/kvmcloud_common.h new file mode 100755 index 000000000000..f751b5111670 --- /dev/null +++ b/drivers/syno/synobios/kvmcloud/kvmcloud_common.h @@ -0,0 +1,40 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops alidsm_ops; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/kvmx64/Makefile b/drivers/syno/synobios/kvmx64/Makefile new file mode 100644 index 000000000000..82930cbf9f02 --- /dev/null +++ b/drivers/syno/synobios/kvmx64/Makefile @@ -0,0 +1,9 @@ +include /env.mak + +obj-m += kvmx64-synobios.o + +kvmx64-synobios-objs = \ + $(vdsm-common-obj) \ + virtualdsm.o \ + c2dsm.o \ + kvmx64_common.o diff --git a/drivers/syno/synobios/kvmx64/c2dsm.c b/drivers/syno/synobios/kvmx64/c2dsm.c new file mode 100644 index 000000000000..ce8c3fc858f3 --- /dev/null +++ b/drivers/syno/synobios/kvmx64/c2dsm.c @@ -0,0 +1,32 @@ +// Copyright (c) 2016 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "kvmx64_common.h" + +// extern function from bromolow_common +extern int Kvmx64RedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int C2DSMInitModuleType(struct synobios_ops *ops) +{ + module_t type_c2dsm = MODULE_T_C2DSM; + module_t *pType = &type_c2dsm; + + module_type_set(pType); + return 0; +} + +struct model_ops c2dsm_ops = { + .x86_init_module_type = C2DSMInitModuleType, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = Kvmx64RedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/kvmx64/kvmx64_common.c b/drivers/syno/synobios/kvmx64/kvmx64_common.c new file mode 100755 index 000000000000..08f9c9536c7d --- /dev/null +++ b/drivers/syno/synobios/kvmx64/kvmx64_common.c @@ -0,0 +1,289 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "kvmx64_common.h" + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = -1; + + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = -1; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL + *buzzer_cleared = gSynoBuzzerMutePressed; + gSynoBuzzerMutePressed = 0; + ret = 0; +#endif + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int Kvmx64RedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_VirtualDSM; + + if (!strncmp(gszSynoHWVersion, HW_C2DSM, strlen(HW_C2DSM))) { + model = MODEL_C2DSM; + } + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_VirtualDSM: + model_ops = &virtualdsm_ops; + break; + case MODEL_C2DSM: + model_ops = &c2dsm_ops; + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/kvmx64/kvmx64_common.h b/drivers/syno/synobios/kvmx64/kvmx64_common.h new file mode 100755 index 000000000000..5c46d10cc7a5 --- /dev/null +++ b/drivers/syno/synobios/kvmx64/kvmx64_common.h @@ -0,0 +1,41 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops virtualdsm_ops; +extern struct model_ops c2dsm_ops; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/kvmx64/virtualdsm.c b/drivers/syno/synobios/kvmx64/virtualdsm.c new file mode 100644 index 000000000000..a6473a434816 --- /dev/null +++ b/drivers/syno/synobios/kvmx64/virtualdsm.c @@ -0,0 +1,32 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "kvmx64_common.h" + +// extern function from bromolow_common +extern int Kvmx64RedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int VirtualDSMInitModuleType(struct synobios_ops *ops) +{ + module_t type_virtualdsm = MODULE_T_VirtualDSM; + module_t *pType = &type_virtualdsm; + + module_type_set(pType); + return 0; +} + +struct model_ops virtualdsm_ops = { + .x86_init_module_type = VirtualDSMInitModuleType, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = Kvmx64RedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/kvmx64sofs/Makefile b/drivers/syno/synobios/kvmx64sofs/Makefile new file mode 100644 index 000000000000..2e659c3490ad --- /dev/null +++ b/drivers/syno/synobios/kvmx64sofs/Makefile @@ -0,0 +1,8 @@ +include /env.mak + +obj-m += kvmx64sofs-synobios.o + +kvmx64sofs-synobios-objs = \ + $(vdsm-common-obj) \ + virtualdsm.o \ + kvmx64sofs_common.o diff --git a/drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.c b/drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.c new file mode 100755 index 000000000000..cd0132094008 --- /dev/null +++ b/drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.c @@ -0,0 +1,283 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "kvmx64sofs_common.h" + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = -1; + + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = -1; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL + *buzzer_cleared = gSynoBuzzerMutePressed; + gSynoBuzzerMutePressed = 0; + ret = 0; +#endif + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int Kvmx64sofsRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_VirtualDSM; + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_VirtualDSM: + model_ops = &virtualdsm_ops; + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.h b/drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.h new file mode 100755 index 000000000000..6322e01dcc41 --- /dev/null +++ b/drivers/syno/synobios/kvmx64sofs/kvmx64sofs_common.h @@ -0,0 +1,40 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops virtualdsm_ops; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/kvmx64sofs/virtualdsm.c b/drivers/syno/synobios/kvmx64sofs/virtualdsm.c new file mode 100644 index 000000000000..40c83826c7c0 --- /dev/null +++ b/drivers/syno/synobios/kvmx64sofs/virtualdsm.c @@ -0,0 +1,32 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "kvmx64sofs_common.h" + +// extern function from bromolow_common +extern int Kvmx64sofsRedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int VirtualDSMInitModuleType(struct synobios_ops *ops) +{ + module_t type_virtualdsm = MODULE_T_VirtualDSM; + module_t *pType = &type_virtualdsm; + + module_type_set(pType); + return 0; +} + +struct model_ops virtualdsm_ops = { + .x86_init_module_type = VirtualDSMInitModuleType, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = Kvmx64sofsRedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/kvmx64v2/Makefile b/drivers/syno/synobios/kvmx64v2/Makefile new file mode 100644 index 000000000000..60fb57779f5a --- /dev/null +++ b/drivers/syno/synobios/kvmx64v2/Makefile @@ -0,0 +1,8 @@ +ccflags-y := -DSYNO_PLATFORM=\"KVMX64V2\" + +obj-$(CONFIG_SYNO_SYNOBIOS) += synobios.o + +synobios-objs = \ + $(vdsm-common-obj) \ + virtualdsm.o \ + kvmx64v2_common.o diff --git a/drivers/syno/synobios/kvmx64v2/kvmx64v2_common.c b/drivers/syno/synobios/kvmx64v2/kvmx64v2_common.c new file mode 100755 index 000000000000..02123363f0e2 --- /dev/null +++ b/drivers/syno/synobios/kvmx64v2/kvmx64v2_common.c @@ -0,0 +1,283 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "kvmx64v2_common.h" + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = -1; + + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = -1; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL + *buzzer_cleared = gSynoBuzzerMutePressed; + gSynoBuzzerMutePressed = 0; + ret = 0; +#endif + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int Kvmx64v2RedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_VirtualDSM; + + return model; +} + +static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_VirtualDSM: + model_ops = &virtualdsm_ops; + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/kvmx64v2/kvmx64v2_common.h b/drivers/syno/synobios/kvmx64v2/kvmx64v2_common.h new file mode 100755 index 000000000000..6322e01dcc41 --- /dev/null +++ b/drivers/syno/synobios/kvmx64v2/kvmx64v2_common.h @@ -0,0 +1,40 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops virtualdsm_ops; + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/kvmx64v2/virtualdsm.c b/drivers/syno/synobios/kvmx64v2/virtualdsm.c new file mode 100644 index 000000000000..9a2d5ce1faa8 --- /dev/null +++ b/drivers/syno/synobios/kvmx64v2/virtualdsm.c @@ -0,0 +1,32 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "kvmx64v2_common.h" + +// extern function from bromolow_common +extern int Kvmx64v2RedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + +static +int VirtualDSMInitModuleType(struct synobios_ops *ops) +{ + module_t type_virtualdsm = MODULE_T_VirtualDSM; + module_t *pType = &type_virtualdsm; + + module_type_set(pType); + return 0; +} + +struct model_ops virtualdsm_ops = { + .x86_init_module_type = VirtualDSMInitModuleType, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = Kvmx64v2RedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/led/led_1475.c b/drivers/syno/synobios/led/led_1475.c new file mode 100755 index 000000000000..2fb431c0c1a4 --- /dev/null +++ b/drivers/syno/synobios/led/led_1475.c @@ -0,0 +1,35 @@ +#include +#include "led_1475.h" +int GetMaxInternalDiskNum(void); + +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) +int SYNODiskLedCtrlBy1475SGPIO(DISKLEDSTATUS* diskLedStatus) +{ + int err = -1; + + if (1 > diskLedStatus->diskno || GetMaxInternalDiskNum() < diskLedStatus->diskno) { + goto END; + } + if (NULL != funcSYNOCtrlDiskLedBy1475) { + err = funcSYNOCtrlDiskLedBy1475(diskLedStatus->diskno, diskLedStatus->status); + } +END: + return err; +} +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ +/* Control disk led via 1475 SGPIO for kernel */ +int SYNODiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum || GetMaxInternalDiskNum() < disknum) { + goto END; + } + + if (funcSYNOCtrlDiskLedBy1475 != NULL) { + err = funcSYNOCtrlDiskLedBy1475(disknum, status); + } +END: + return err; +} +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ diff --git a/drivers/syno/synobios/led/led_1475.h b/drivers/syno/synobios/led/led_1475.h new file mode 100644 index 000000000000..6dfe6759c8a3 --- /dev/null +++ b/drivers/syno/synobios/led/led_1475.h @@ -0,0 +1,10 @@ +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL +#include "led_common.h" +int DiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status); +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) +int SYNODiskLedCtrlBy1475SGPIO(DISKLEDSTATUS* diskLedStatus); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ +int SYNODiskLedCtrlBy1475SGPIO(int disknum, SYNO_DISK_LED status); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +extern int (*funcSYNOCtrlDiskLedBy1475)(unsigned short, unsigned short); +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ diff --git a/drivers/syno/synobios/led/led_9170.c b/drivers/syno/synobios/led/led_9170.c new file mode 100755 index 000000000000..ffe7ff5b7c05 --- /dev/null +++ b/drivers/syno/synobios/led/led_9170.c @@ -0,0 +1,35 @@ +#include +#include "led_9170.h" +int GetMaxInternalDiskNum(void); + +/** + * SetDiskLedStatusBy9170GPIO - control 9170 led by slot + * @iDiskPort: the slot number of disk + * @iStatus: led status + * + * return 0: success + * -1: fail + * -EINVAL: fail + */ +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + int iWrite = -1; + + if (1 > iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9170_disk_led_set_by_port(iDiskNum, iWrite); + +END: + return iRet; + +} diff --git a/drivers/syno/synobios/led/led_9170.h b/drivers/syno/synobios/led/led_9170.h new file mode 100644 index 000000000000..de526103a09a --- /dev/null +++ b/drivers/syno/synobios/led/led_9170.h @@ -0,0 +1,11 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL) +#include "led_common.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +extern int syno_mv_9170_disk_led_set_by_port(int iDiskNum, int iValue); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +extern int syno_mv_9170_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif /* MY_DEF_HERE || SYNO_SATA_MV92XX_GPIO_CTRL*/ diff --git a/drivers/syno/synobios/led/led_9235.c b/drivers/syno/synobios/led/led_9235.c new file mode 100755 index 000000000000..8dcf4e6cf107 --- /dev/null +++ b/drivers/syno/synobios/led/led_9235.c @@ -0,0 +1,213 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include "led_9235.h" + +int GetMaxInternalDiskNum(void); + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +inline int SYNO_LED_ORANGE_STATUS_SET(SYNO_DISK_LED iStatus) +{ + return (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) ? 1 : 0; +} + +/** + * SetSCSIHostLedStatusByAHCIGPIO - control led light of input slot by ahci gpio + * @iHostNum: the scsi host of disk + * + * return 0: success + -1: fail + */ +int SetSCSIHostLedStatusByAHCIGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret = -1; + int iFault, iPresent; + + switch(status) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + iFault = 1; + iPresent = 0; + break; + case DISK_LED_GREEN_SOLID: + iFault = 0; + iPresent = 1; + break; + case DISK_LED_OFF: + iFault = 0; + iPresent = 0; + break; + default: + printk("Invalid LED status [%d]\n", status); + goto END; + } +#ifdef MY_DEF_HERE + sata_syno_ahci_diskled_set(iHostNum, iPresent, iFault); +#else + printk(KERN_ERR "SYNO ATA AHCI DISK LED control function is not defined!!"); +#endif /* MY_DEF_HERE */ + ret = 0; +END: + return ret; +} + +int SetDiskLedStatusByAHCIGPIO(int iDiskPort, SYNO_DISK_LED status) +{ + int ret = -1; + int iFault, iPresent; + + switch(status) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + iFault = 1; + iPresent = 0; + break; + case DISK_LED_GREEN_SOLID: + iFault = 0; + iPresent = 1; + break; + case DISK_LED_OFF: + iFault = 0; + iPresent = 0; + break; + default: + printk("Invalid LED status [%d]\n", status); + goto END; + } +#ifdef MY_DEF_HERE + sata_syno_ahci_diskled_set_by_port(iDiskPort, iPresent, iFault); +#else + printk(KERN_ERR "SYNO ATA AHCI DISK LED control function is not defined!!"); +#endif /* MY_DEF_HERE */ + ret = 0; +END: + return ret; +} + +/** + * SetDiskLedStatusBy9235GPIOByPort - control light of slot number on 9235 + * @iDiskPort: the slot number of disk + * @iStatus: light status + * + * return 0: success + * -EINVAL: fail + */ +int SetDiskLedStatusBy9235GPIOByPort(int iDiskPort, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + iWrite = SYNO_LED_ORANGE_STATUS_SET(iStatus); + iRet = syno_mv_9235_disk_led_set_by_port(iDiskPort, iWrite); + return iRet; +} + +/** + * SetSCSIHostLedStatusBy9235GPIO - control light of scsi host number on 9235 + * @iDiskPort: the scsi host number of disk + * @iStatus: light status + * + * return 0: success + * -EINVAL: fail + */ +int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + iWrite = SYNO_LED_ORANGE_STATUS_SET(iStatus); + iRet = syno_mv_9235_disk_led_set(iHostNum, iWrite); + return iRet; +} + +/** + * SetDiskLedStatusBy9235GPIO - control light of slot number on 9235 + * @iDiskPort: the slot number of disk + * @iStatus: light status + * + * return 0: success + * -EINVAL: fail + */ +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + iRet = SetDiskLedStatusBy9235GPIOByPort(iDiskNum, iStatus); +END: + return iRet; +} + +/** + * SetDiskLedStatusBy9235GPIOandAHCISGPIObyPort - control mix ahci and 9235 led of slot + * @iDiskPort: the slot number of disk + * @iStatus: light status + * + * return 0: success + * -EINVAL: fail + */ +int SetDiskLedStatusBy9235GPIOandAHCISGPIObyPort(int iDiskPort, SYNO_DISK_LED status) +{ + int ret; + int iWrite = -1, iRead = -1; + + if (GetMaxInternalHostNum && iDiskPort < GetMaxInternalHostNum()) { + ret = SetDiskLedStatusByAHCIGPIO(iDiskPort, status);; + } else { + iWrite = SYNO_LED_ORANGE_STATUS_SET(status); + ret = syno_mv_9235_disk_led_set_by_port(iDiskPort, iWrite); + + iRead = syno_mv_9235_disk_led_get_by_port(iDiskPort); + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } + } + return ret; +} + +int SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(int iHostNum, SYNO_DISK_LED status) +{ + int ret; + int iWrite = -1, iRead = -1; + + if (GetMaxInternalHostNum && iHostNum < GetMaxInternalHostNum()) { + ret = SetSCSIHostLedStatusByAHCIGPIO(iHostNum, status);; + } else { + iWrite = SYNO_LED_ORANGE_STATUS_SET(status); + ret = syno_mv_9235_disk_led_set(iHostNum, iWrite); + + iRead = syno_mv_9235_disk_led_get(iHostNum); + if (-1 == iRead || iRead != iWrite) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + } + } + return ret; +} + +int SetDiskLedStatusBy9235GPIOandAHCISGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + if (1 > disknum) { + goto END; + } + + if (GetMaxInternalDiskNum() < disknum) { + goto END; + } + err = SetDiskLedStatusBy9235GPIOandAHCISGPIObyPort(disknum, status); + +END: + return err; +} diff --git a/drivers/syno/synobios/led/led_9235.h b/drivers/syno/synobios/led/led_9235.h new file mode 100644 index 000000000000..9bf638ddfe19 --- /dev/null +++ b/drivers/syno/synobios/led/led_9235.h @@ -0,0 +1,19 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL) +#include "led_common.h" +extern int (*GetMaxInternalHostNum)(void); +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +extern int syno_mv_9235_disk_led_get_by_port(int iDiskPort); +extern int syno_mv_9235_disk_led_set_by_port(const unsigned short iDiskPort, int iValue); +extern void sata_syno_ahci_diskled_set_by_port(int iDiskPort, int iPresent, int iFault); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +extern int syno_mv_9235_disk_led_get(const unsigned short hostnum); +extern void sata_syno_ahci_diskled_set(int iHostNum, int iPresent, int iFault); +int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus); +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +int SetDiskLedStatusBy9235GPIOandAHCISGPIO(int disknum, SYNO_DISK_LED status); +int SetSCSIHostLedStatusBy9235GPIOandAHCISGPIO(int iHostNum, SYNO_DISK_LED status); +#endif /* MY_DEF_HERE || SYNO_SATA_MV92XX_GPIO_CTRL */ diff --git a/drivers/syno/synobios/led/led_asm116x.c b/drivers/syno/synobios/led/led_asm116x.c new file mode 100644 index 000000000000..5cdc8aff842d --- /dev/null +++ b/drivers/syno/synobios/led/led_asm116x.c @@ -0,0 +1,45 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#if defined(CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL) +#include +#include "led_asm116x.h" +#include +#include + +extern int GetMaxInternalDiskNum(void); + +/** + * SetDiskLedStatusByASM116XGPIOByPort - control light of slot number on ASM116X + * + * return 0: success + * -EINVAL: fail + */ +int SetDiskLedStatusByASM116XGPIOByPort(DISKLEDSTATUS *pLedStatus) +{ + int iRet = -1; + int iWrite = -1; + int iDiskPort = pLedStatus->diskno; + + if (1 > iDiskPort || GetMaxInternalDiskNum() < iDiskPort) { + printk("Invalid disk Number [%d]\n", iDiskPort); + goto END; + } + iWrite = (DISK_LED_ORANGE_BLINK == pLedStatus->status || DISK_LED_ORANGE_SOLID == pLedStatus->status) ? 1 : 0; + iRet = syno_asmedia_116x_disk_led_set(iDiskPort, iWrite); +END: + return iRet; +} +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +int SYNOSetDiskLedStatusByASM116XGPIOByPort(int iHostNum, SYNO_DISK_LED iStatus) +{ + DISKLEDSTATUS ledStatus = { + .diskno = iHostNum + 1, + .status = iStatus, + .iNodeNameLen = sizeof(DT_INTERNAL_SLOT), + .szNodeName = DT_INTERNAL_SLOT + }; + return SetDiskLedStatusByASM116XGPIOByPort(&ledStatus); +} +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL || CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL */ diff --git a/drivers/syno/synobios/led/led_asm116x.h b/drivers/syno/synobios/led/led_asm116x.h new file mode 100644 index 000000000000..7697f35c7b73 --- /dev/null +++ b/drivers/syno/synobios/led/led_asm116x.h @@ -0,0 +1,9 @@ +#if defined(CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL) +#include "led_common.h" +extern int (*GetMaxInternalHostNum)(void); + +int SetDiskLedStatusByASM116XGPIOByPort(DISKLEDSTATUS *pLedStatus); +int SYNOSetDiskLedStatusByASM116XGPIOByPort(int iHostNum, SYNO_DISK_LED iStatus); +extern int syno_asmedia_116x_disk_led_set(const int iDiskPort, const int iValue); + +#endif /* CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL || CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL */ diff --git a/drivers/syno/synobios/led/led_common.h b/drivers/syno/synobios/led/led_common.h new file mode 100644 index 000000000000..69519a6a44cb --- /dev/null +++ b/drivers/syno/synobios/led/led_common.h @@ -0,0 +1,8 @@ +#include +#include "synobios.h" +#include +extern void SYNO_ENABLE_HDD_LED(int blEnable); +#include "../common/common.h" +extern int syno_ahci_disk_led_enable(const unsigned short hostnum, const int iValue); +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +extern SYNO_GPIO syno_gpio; diff --git a/drivers/syno/synobios/led/led_gpio.c b/drivers/syno/synobios/led/led_gpio.c new file mode 100644 index 000000000000..73d28ca2716e --- /dev/null +++ b/drivers/syno/synobios/led/led_gpio.c @@ -0,0 +1,48 @@ +#include "led_gpio.h" + +int synoDiskLedControlByGpio(DISKLEDSTATUS *cmd) +{ + int iRet = -1; + u8 state = PIN_BITMAP_OFF; + u32 pin = 0; + u32 val = 0; + + switch (cmd->status) { + case DISK_LED_OFF: + state = PIN_BITMAP_OFF; + break; + case DISK_LED_GREEN_SOLID: + state = PIN_BITMAP_GREEN; + break; + case DISK_LED_ORANGE_SOLID: + state = PIN_BITMAP_ORANGE; + break; + case DISK_LED_GREEN_BLINK: + state = PIN_BITMAP_GREEN | PIN_BITMAP_BLINK; + break; + case DISK_LED_ORANGE_BLINK: + /* No such combination */ + default: + goto FAIL; + } + + if (HAVE_HDD_PRESENT_LED_BY_SLOT(cmd->szNodeName, cmd->diskno)) { + pin = HDD_PRESENT_LED_PIN_BY_SLOT(cmd->szNodeName, cmd->diskno); + val = EVAL_PIN_VAL(HDD_PRESENT_LED_POLARITY_BY_SLOT(cmd->szNodeName, cmd->diskno), state & PIN_BITMAP_GREEN); + SYNO_GPIO_WRITE(pin, val); + } + if (HAVE_HDD_FAIL_LED_BY_SLOT(cmd->szNodeName, cmd->diskno)) { + pin = HDD_FAIL_LED_PIN_BY_SLOT(cmd->szNodeName, cmd->diskno); + val = EVAL_PIN_VAL(HDD_FAIL_LED_POLARITY_BY_SLOT(cmd->szNodeName, cmd->diskno), state & PIN_BITMAP_ORANGE); + SYNO_GPIO_WRITE(pin, val); + } + if (HAVE_HDD_ACT_LED_BY_SLOT(cmd->szNodeName, cmd->diskno)) { + pin = HDD_ACT_LED_PIN_BY_SLOT(cmd->szNodeName, cmd->diskno); + val = EVAL_PIN_VAL(HDD_ACT_LED_POLARITY_BY_SLOT(cmd->szNodeName, cmd->diskno), state & PIN_BITMAP_BLINK); + SYNO_GPIO_WRITE(pin, val); + } + + iRet = 0; +FAIL: + return iRet; +} diff --git a/drivers/syno/synobios/led/led_gpio.h b/drivers/syno/synobios/led/led_gpio.h new file mode 100644 index 000000000000..70f03e7cc3a0 --- /dev/null +++ b/drivers/syno/synobios/led/led_gpio.h @@ -0,0 +1,10 @@ +#include +#include +#include + +#define PIN_BITMAP_OFF (0x00) +#define PIN_BITMAP_GREEN (0x01) +#define PIN_BITMAP_ORANGE (0x02) +#define PIN_BITMAP_BLINK (0x04) + +int synoDiskLedControlByGpio(DISKLEDSTATUS *cmd); diff --git a/drivers/syno/synobios/led/led_jmb585.c b/drivers/syno/synobios/led/led_jmb585.c new file mode 100644 index 000000000000..bc7243356e45 --- /dev/null +++ b/drivers/syno/synobios/led/led_jmb585.c @@ -0,0 +1,46 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#if defined(CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL) +#include +#include "led_jmb585.h" +#include +#include + +extern int GetMaxInternalDiskNum(void); + +/** + * SetDiskLedStatusByJMB585GPIOByPort - control light of slot number on JMB585 + * + * return 0: success + * -EINVAL: fail + */ +int SetDiskLedStatusByJMB585GPIOByPort(DISKLEDSTATUS *pLedStatus) +{ + int iRet = -1; + int iWrite = -1; + int iDiskPort = pLedStatus->diskno; + + if (1 > iDiskPort || GetMaxInternalDiskNum() < iDiskPort) { + printk("Invalid disk Number [%d]\n", iDiskPort); + goto END; + } + iWrite = (DISK_LED_ORANGE_BLINK == pLedStatus->status || DISK_LED_ORANGE_SOLID == pLedStatus->status) ? 1 : 0; + iRet = syno_jmb585_disk_led_set(iDiskPort, iWrite); +END: + return iRet; +} + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +int SYNOSetDiskLedStatusByJMB585GPIOByPort(int iHostNum, SYNO_DISK_LED iStatus) +{ + DISKLEDSTATUS ledStatus = { + .diskno = iHostNum + 1, + .status = iStatus, + .iNodeNameLen = sizeof(DT_INTERNAL_SLOT), + .szNodeName = DT_INTERNAL_SLOT + }; + return SetDiskLedStatusByJMB585GPIOByPort(&ledStatus); +} +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL || CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL */ diff --git a/drivers/syno/synobios/led/led_jmb585.h b/drivers/syno/synobios/led/led_jmb585.h new file mode 100644 index 000000000000..ca2b42b64259 --- /dev/null +++ b/drivers/syno/synobios/led/led_jmb585.h @@ -0,0 +1,10 @@ +#if defined(CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL) +#include "led_common.h" +extern int (*GetMaxInternalHostNum)(void); + +int SetDiskLedStatusByJMB585GPIOByPort(DISKLEDSTATUS *pLedStatus); +int SYNOSetDiskLedStatusByJMB585GPIOByPort(int iHostNum, SYNO_DISK_LED iStatus); +extern int syno_jmb585_disk_led_set(const int iDiskPort, int iValue); +extern void syno_jmb585_led_wait(void); + +#endif /* CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL || CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL */ diff --git a/drivers/syno/synobios/led/led_trigger.c b/drivers/syno/synobios/led/led_trigger.c new file mode 100755 index 000000000000..597a9443e784 --- /dev/null +++ b/drivers/syno/synobios/led/led_trigger.c @@ -0,0 +1,192 @@ +#include +#include +#include +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) +#include +#include +#include +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#include "led_trigger.h" +int GetMaxInternalDiskNum(void); + +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) +#define SZ_DT_DISK_LED_TYPE_LP3943 "lp3943" +#define SZ_DT_DISK_LED_TYPE_ATMEGA1608 "atmega1608" + +int SetDiskLedStatusByLedTrigger(DISKLEDSTATUS *pLedStatus) +{ + int iDiskNum = pLedStatus->diskno; + SYNO_DISK_LED iStatus = pLedStatus->status; +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ +int SetDiskLedStatusByLedTrigger(int iDiskNum, SYNO_DISK_LED iStatus) +{ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (0 >= iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL +int SYNOSetDiskLedStatusByLedTrigger(int iHostNum, SYNO_DISK_LED iStatus) +{ +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) + DISKLEDSTATUS ledStatus = { + .diskno = iHostNum + 1, + .status = iStatus, + .iNodeNameLen = sizeof(DT_INTERNAL_SLOT), + .szNodeName = DT_INTERNAL_SLOT + }; + return SetDiskLedStatusByLedTrigger(&ledStatus); +#else + return SetDiskLedStatusByLedTrigger(iHostNum + 1, iStatus); +#endif +} +#endif //CONFIG_SYNO_SATA_DISK_LED_CONTROL + +/* + * Setup the global Disk LED mapping for sata driver + */ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int SetHddActLedByLedTrigger(SYNO_LED ledStatus) +{ + struct device_node *pBusNode = NULL; + struct device_node *pDevNode = NULL; + struct i2c_adapter *adapter = NULL; + union i2c_smbus_data data; + u16 addr = 0x0; + char *szDevName = NULL; + char *szDevAddr = NULL; + int iRet = -1; + + for_each_child_of_node(of_root, pBusNode) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + if (NULL != pBusNode->full_name && 0 == strncmp(pBusNode->full_name, DT_I2C_BUS, strlen(DT_I2C_BUS))) { +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */ + if (NULL != pBusNode->full_name && 0 == strncmp(pBusNode->full_name, "/"DT_I2C_BUS, strlen("/"DT_I2C_BUS))) { +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */ + for_each_child_of_node(pBusNode, pDevNode) { + if (NULL != pDevNode->name && 0 == strncmp(pDevNode->name, DT_I2C_DEVICE, strlen(DT_I2C_DEVICE))) { + szDevName = (char *)of_get_property(pDevNode, DT_I2C_DEVICE_NAME, NULL); + if (0 == strcmp(szDevName, SZ_DT_DISK_LED_TYPE_ATMEGA1608)) { + //get i2c adapter + if (NULL == (adapter = syno_i2c_adapter_get_by_node(pBusNode))) { + printk("synobios: cannot get i2c adapter\n"); + goto END; + } + //get i2c address + szDevAddr = (char *)of_get_property(pDevNode, DT_I2C_ADDRESS, NULL); + if (NULL == szDevAddr || 0 != kstrtou16(szDevAddr, 16, &addr)) { + printk("synobios: cannot parse i2c address\n"); + goto END; + } + + data.byte = (SYNO_LED_OFF == ledStatus) ? ATMEGA1608_LED_MASKED : ATMEGA1608_LED_UNMASK; + iRet = i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, ATMEGA1608_MASK, I2C_SMBUS_BYTE_DATA, &data); + if (0 > iRet) { + printk("synobios: fail to write i2c smbus\n"); + goto END; + } + + } // add new i2c device here + } + } + } + } +END: + return iRet; +} + +void SetupDiskLedMap() +{ + int i = 0, iLedId = -1; + char szLedName[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {0}; + char szLedType[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {0}; + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = kmalloc(GetMaxInternalDiskNum() * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = kmalloc(GetMaxInternalDiskNum() * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, GetMaxInternalDiskNum() * sizeof(int)); + memset(gpOrangeLedMap, -1, GetMaxInternalDiskNum() * sizeof(int)); + + for (i = 0; i < GetMaxInternalDiskNum(); i++){ + if (0 > syno_led_type_get(DT_INTERNAL_SLOT, i + 1, szLedType, sizeof(szLedType))) { + printk("Fail to get disk %d led type\n", i + 1); + continue; + } + if (0 != strcmp(szLedType, SZ_DT_DISK_LED_TYPE_LP3943) && 0 != strcmp(szLedType, SZ_DT_DISK_LED_TYPE_ATMEGA1608)) { + continue; + } + if (0 > HDD_PRESENT_LED_NAME_BY_SLOT(DT_INTERNAL_SLOT, i + 1, szLedName, sizeof(szLedName))) { + printk("Fail to get disk %d green led name\n", i + 1); + continue; + } + sscanf(szLedName, "syno_led%d", &iLedId); + gpGreenLedMap[i] = iLedId; + if (0 > HDD_FAIL_LED_NAME_BY_SLOT(DT_INTERNAL_SLOT, i + 1, szLedName, sizeof(szLedName))) { + printk("Fail to get disk %d orange led name\n", i + 1); + continue; + } + sscanf(szLedName, "syno_led%d", &iLedId); + gpOrangeLedMap[i] = iLedId; + } +} +#else +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if (NULL == pGreenLed || NULL == pOrangeLed || GetMaxInternalDiskNum() < iInternalDiskNum) { + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = kmalloc(GetMaxInternalDiskNum() * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = kmalloc(GetMaxInternalDiskNum() * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, GetMaxInternalDiskNum() * sizeof(int)); + memset(gpOrangeLedMap, -1, GetMaxInternalDiskNum() * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); +} +#endif diff --git a/drivers/syno/synobios/led/led_trigger.h b/drivers/syno/synobios/led/led_trigger.h new file mode 100644 index 000000000000..f66a750d941f --- /dev/null +++ b/drivers/syno/synobios/led/led_trigger.h @@ -0,0 +1,22 @@ +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "led_common.h" +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern struct i2c_adapter* syno_i2c_adapter_get_by_node(struct device_node *pI2CBusNode); +extern int syno_led_name_get(const char* szSlotName, const int diskPort, const char *szLedType, char *szSynoLedName, unsigned int cbSynoLedName); +#endif + +int SYNOSetDiskLedStatusByLedTrigger(int iHostNum, SYNO_DISK_LED iStatus); +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) +int SetDiskLedStatusByLedTrigger(DISKLEDSTATUS* status); +void SetupDiskLedMap(void); +int SetHddActLedByLedTrigger(SYNO_LED ledStatus); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ +int SetDiskLedStatusByLedTrigger(int iDiskNum, SYNO_DISK_LED iStatus); +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ diff --git a/drivers/syno/synobios/led/led_trigger_disk.c b/drivers/syno/synobios/led/led_trigger_disk.c new file mode 100755 index 000000000000..da3a24ef8726 --- /dev/null +++ b/drivers/syno/synobios/led/led_trigger_disk.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include "led_trigger_disk.h" + +int GetMaxInternalDiskNum(void); + +struct led_classdev **gpGreenLedDevMap, **gpOrangeLedDevMap; + +int SetDiskLedStatusByTrigDiskSyno(DISKLEDSTATUS *pLedStatus) +{ + int iDiskNum = pLedStatus->diskno; + SYNO_DISK_LED iStatus = pLedStatus->status; + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + + if (0 >= iDiskNum || GetMaxInternalDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedDevMap || NULL == gpOrangeLedDevMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_ON; + LEDGreen = LED_OFF; + break; + case DISK_LED_GREEN_BLINK: + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_ON; + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + ledtrig_syno_disk_led_on(gpGreenLedDevMap[iDiskNum-1], LEDGreen); + ledtrig_syno_disk_led_on(gpOrangeLedDevMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +#ifdef CONFIG_SYNO_SATA_DISK_LED_CONTROL +int SYNOSetDiskLedStatusByTrigDiskSynoint (int iHostNum, SYNO_DISK_LED iStatus) +{ + DISKLEDSTATUS ledStatus = { + .diskno = iHostNum + 1, + .status = iStatus, + .iNodeNameLen = sizeof(DT_INTERNAL_SLOT), + .szNodeName = DT_INTERNAL_SLOT + }; + return SetDiskLedStatusByTrigDiskSyno(&ledStatus); +} +#endif //CONFIG_SYNO_SATA_DISK_LED_CONTROL + +void SetupLedTrigDiskMap(void) +{ + int i = 0; + char szLedType[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {0}; + + /* allocate and initialize disk led mapping*/ + gpGreenLedDevMap = kmalloc(GetMaxInternalDiskNum() * sizeof(struct led_classdev *), GFP_KERNEL); + gpOrangeLedDevMap = kmalloc(GetMaxInternalDiskNum() * sizeof(struct led_classdev *), GFP_KERNEL); + memset(gpGreenLedDevMap, 0, GetMaxInternalDiskNum() * sizeof(struct led_classdev *)); + memset(gpOrangeLedDevMap, 0, GetMaxInternalDiskNum() * sizeof(struct led_classdev *)); + + for (i = 0; i < GetMaxInternalDiskNum(); i++){ + if (0 > syno_led_type_get(DT_INTERNAL_SLOT, i + 1, szLedType, sizeof(szLedType))) { + printk("Fail to get disk %d led type\n", i + 1); + continue; + } + if (0 != strcmp(szLedType, DT_HDD_LED_TYPE_TRIG_DISK_SYNO)) { + continue; + } + + // green + gpGreenLedDevMap[i] = syno_led_dev_get(DT_INTERNAL_SLOT, i + 1, DT_HDD_GREEN_LED); + // orange + gpOrangeLedDevMap[i] = syno_led_dev_get(DT_INTERNAL_SLOT, i + 1, DT_HDD_ORANGE_LED); + } +} diff --git a/drivers/syno/synobios/led/led_trigger_disk.h b/drivers/syno/synobios/led/led_trigger_disk.h new file mode 100644 index 000000000000..29cb63c2fa74 --- /dev/null +++ b/drivers/syno/synobios/led/led_trigger_disk.h @@ -0,0 +1,11 @@ +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK +#include "led_common.h" +#define LED_NORMAL 0 +#define LED_FAULTY 1 +extern void ledtrig_syno_disk_led_on(struct led_classdev *led_cdev, bool active); +extern struct led_classdev* syno_led_dev_get(const char* szSlotName, const int diskPort, const char* szledName); + +int SYNOSetDiskLedStatusByTrigDiskSyno(int iHostNum, SYNO_DISK_LED iStatus); +int SetDiskLedStatusByTrigDiskSyno(DISKLEDSTATUS* status); +void SetupLedTrigDiskMap(void); +#endif /*CONFIG_SYNO_LEDS_TRIGGER_DISK */ diff --git a/drivers/syno/synobios/mapping.c b/drivers/syno/synobios/mapping.c new file mode 100755 index 000000000000..02ec9da7be5a --- /dev/null +++ b/drivers/syno/synobios/mapping.c @@ -0,0 +1,411 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. +#ifdef CONFIG_SYNO_RTD1619B +#else /* CONFIG_SYNO_RTD1619B */ +#include +#endif /* CONFIG_SYNO_RTD1619B */ +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include "mapping.h" + +#define TTY_MAX_RETRY 10 + +#if 0 +#define DBGMESG(x...) printk(x) +#else +#define DBGMESG(x...) +#endif + +#ifdef MY_DEF_HERE +extern unsigned int guiWakeupDisksNum; +extern unsigned int giDenoOfTimeInterval; +#endif + +module_t syno_module = MODULE_T_UNKNOWN; + +extern int synobios_lock_ttyS_write(const char *szBuf); +extern int synobios_lock_ttyS_read(char *szBuf, int size); +void +module_type_set(module_t *pModule) +{ + if (NULL == pModule) { +#if defined(WARN_ON) + WARN_ON(1); +#endif + printk("Module type init error\n"); + goto End; + } + + syno_module = *pModule; +End: + return; +} + +module_t * +module_type_get(void) +{ + return &syno_module; +} + +int +GetFanNum(int *pFanNum) +{ + int iRet = -1; + + *pFanNum = syno_module.fan_number; + + iRet = 0; + return iRet; +} + +#ifdef MY_DEF_HERE +/** + * Set the group wakeup config + * + * @return 0: success, others: fail + */ +int SetGroupWakeConfig(void) +{ + int iRet = -1; + + if (UNKNOW_DISK_DENO == syno_module.group_wake_config) { + goto END; + } + + guiWakeupDisksNum = (unsigned int)(syno_module.group_wake_config >> 4); + giDenoOfTimeInterval = (unsigned int)(syno_module.group_wake_config & 0x0F); + + if (ONE_DISK_DENO_ONE == syno_module.group_wake_config) { + printk("This is default settings: "); + } + printk("set group disks wakeup number to %d, spinup time deno %d\n", + guiWakeupDisksNum, giDenoOfTimeInterval); + + iRet = 0; + +END: + return iRet; +} +#endif + +#if defined(CONFIG_SYNO_X86) || defined(CONFIG_SYNO_X64) +int SetUart(const char* cmd) +{ + int err = -1; + int writeRet = -1; + char cmdbuf[16] = {0}; + + if (NULL == cmd) { + goto ERR; + } + snprintf(cmdbuf, sizeof(cmdbuf), "%s", cmd); + + writeRet = synobios_lock_ttyS_write(cmdbuf); + err = 0; +ERR: + return err; +} + +/* + * Set Uart command and read command result + * @return: -1 means error, 0 means success + */ +int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng) +{ + int err = -1; + int iCount = 0; + + if (SetUart(szGoCmd)) { + goto ERR; + } + // wait for ttyS1 input + msleep(500); + iCount = synobios_lock_ttyS_read(szResult, leng); + + if (SetUart(szStopCmd)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetMicropId(void) +{ + static SYNO_MICROP_ID MpId = MICROP_ID_UNKNOW; + int iRet = -1; + char szbuf[8] = {'\0'}; + + if (MICROP_ID_UNKNOW == syno_module.microp_id) { + printk("get microp fail\n"); + goto END; + } + + /* if unknow means the MpId not matched or not init before */ + if (MICROP_ID_UNKNOW == MpId) { + /* check_if the model and microp was matched */ + if (ReadUart(MICROP_CMD_READID, MICROP_CMD_READID, szbuf, sizeof(szbuf))) { + goto END; + } + + MpId = (SYNO_MICROP_ID)szbuf[0]; + /* FIXME: we not check microp id now, if got successfully we treat it ok */ + /* FIXME: RS3614(RP)xs have two different MicroP ID. If the check need to be + re-open, please remember to handle this special case */ +#if 0 + if (MpId != syno_module.microp_id) { + /* not matched, say Thank you to user, and reset MpId to unknow */ + printk("!!! Thank you, please purchase Synology products !!!\n"); + MpId = MICROP_ID_UNKNOW; + goto END; + } +#endif + } + + iRet = 0; + +END: + return iRet; +} + +int +CheckMicropId(const struct synobios_ops *pSynobiosOps) +{ + int iRet = -1; + int iTries = 0; + + if (!pSynobiosOps || !pSynobiosOps->set_microp_id) { + printk("no ops\n"); + goto END; + } + + if (MICROP_ID_UNKNOW == syno_module.microp_id) { + printk("get microp fail\n"); + goto END; + } + + /* if fail re-try 3 times */ + for (iTries = 0; iTries < 3 && iRet; ++iTries) { + if ((iRet = pSynobiosOps->set_microp_id())) { + msleep(500); + } + } + +END: + return iRet; +} +#endif + +int +GetHwCapability(CAPABILITY *pCapability) +{ + int iRet = -1; + + if ( NULL == pCapability ) { + iRet = -EINVAL; + goto End; + } + + pCapability->support = 0; + + switch (pCapability->id) { + case CAPABILITY_DISK_LED_CTRL: + if (DISK_LED_CTRL_SW == syno_module.diskled_ctrl_type) { + pCapability->support = 1; + } + break; + case CAPABILITY_THERMAL: + if (THERMAL_YES == syno_module.thermal_type) { + pCapability->support = 1; + } + break; + case CAPABILITY_AUTO_POWERON: + if (AUTO_POWERON_YES == syno_module.auto_poweron_type) { + pCapability->support = 1; + } + break; + case CAPABILITY_CPU_TEMP: + if (CPUTMP_YES == syno_module.cputmp_type) { + pCapability->support = 1; + } + break; + case CAPABILITY_S_LED_BREATH: + if (HIBER_LED_STATUS_BREATH == syno_module.hibernate_led) { + pCapability->support = 1; + } + break; + case CAPABILITY_FAN_RPM_RPT: + if (FAN_RPM_RPT_YES == syno_module.fan_rpm_rpt_type) { + pCapability->support = 1; + } + break; + case CAPABILITY_MICROP_PWM: + if(FAN_MICROP_PWM == syno_module.fan_type || + FAN_MICROP_PWM_WITH_CPUFAN == syno_module.fan_type || + FAN_MICROP_PWM_WITH_GPIO == syno_module.fan_type || + FAN_MICROP_PWM_WITH_CPUFAN_AND_GPIO == syno_module.fan_type){ + pCapability->support = 1; + } + break; + case CAPABILITY_CARDREADER: + if(CARDREADER_YES == syno_module.has_cardreader){ + pCapability->support = 1; + } + break; + default: + iRet = -EINVAL; + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int +FanStatusMappingType1(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value) +{ + int ret = -1; + + if (status == FAN_STATUS_STOP) { + *pSpeed_value = CPLD_FAN_SPEED_0; + } else { + switch (speed) { + case FAN_SPEED_STOP: + case FAN_SPEED_TEST_0: + *pSpeed_value = CPLD_FAN_SPEED_0; + break; + case FAN_SPEED_ULTRA_LOW: + case FAN_SPEED_TEST_1: + *pSpeed_value = CPLD_FAN_SPEED_1; + break; + case FAN_SPEED_VERY_LOW: + case FAN_SPEED_TEST_2: + *pSpeed_value = CPLD_FAN_SPEED_2; + break; + /* by spec. The fan speed of 3/4 is inverted. + * Because the last resistance is smaller than the sum of the others. + */ + case FAN_SPEED_MIDDLE: + case FAN_SPEED_TEST_3: + *pSpeed_value = CPLD_FAN_SPEED_3; + break; + case FAN_SPEED_LOW: + case FAN_SPEED_TEST_4: + *pSpeed_value = CPLD_FAN_SPEED_4; + break; + case FAN_SPEED_HIGH: + case FAN_SPEED_TEST_5: + *pSpeed_value = CPLD_FAN_SPEED_5; + break; + case FAN_SPEED_VERY_HIGH: + case FAN_SPEED_TEST_6: + *pSpeed_value = CPLD_FAN_SPEED_6; + break; + case FAN_SPEED_ULTRA_HIGH: + case FAN_SPEED_FULL: + case FAN_SPEED_TEST_7: + *pSpeed_value = CPLD_FAN_SPEED_7; + break; + case FAN_SPEED_TEST_8: + *pSpeed_value = CPLD_FAN_SPEED_8; + break; + case FAN_SPEED_TEST_9: + *pSpeed_value = CPLD_FAN_SPEED_9; + break; + case FAN_SPEED_TEST_10: + *pSpeed_value = CPLD_FAN_SPEED_10; + break; + case FAN_SPEED_TEST_11: + *pSpeed_value = CPLD_FAN_SPEED_11; + break; + case FAN_SPEED_TEST_12: + *pSpeed_value = CPLD_FAN_SPEED_12; + break; + case FAN_SPEED_TEST_13: + *pSpeed_value = CPLD_FAN_SPEED_13; + break; + case FAN_SPEED_TEST_14: + *pSpeed_value = CPLD_FAN_SPEED_14; + break; + case FAN_SPEED_TEST_15: + *pSpeed_value = CPLD_FAN_SPEED_15; + break; + case FAN_SPEED_TEST_16: + *pSpeed_value = CPLD_FAN_SPEED_16; + break; + case FAN_SPEED_TEST_17: + *pSpeed_value = CPLD_FAN_SPEED_17; + break; + default: + goto END; + } + } + + ret = 0; +END: + return ret; +} + +int +FanStatusMappingType2(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value) +{ + int ret = -1; + + if (status == FAN_STATUS_STOP) { + *pSpeed_value = CPLD_FAN_SPEED_0; + } else { + switch (speed) { + case FAN_SPEED_STOP: + case FAN_SPEED_TEST_0: + *pSpeed_value = CPLD_FAN_SPEED_0; + break; + case FAN_SPEED_ULTRA_LOW: + case FAN_SPEED_TEST_1: + *pSpeed_value = CPLD_FAN_SPEED_1; + break; + case FAN_SPEED_VERY_LOW: + case FAN_SPEED_TEST_2: + *pSpeed_value = CPLD_FAN_SPEED_2; + break; + case FAN_SPEED_LOW: + case FAN_SPEED_TEST_3: + *pSpeed_value = CPLD_FAN_SPEED_3; + break; + case FAN_SPEED_MIDDLE: + case FAN_SPEED_TEST_4: + *pSpeed_value = CPLD_FAN_SPEED_4; + break; + case FAN_SPEED_HIGH: + case FAN_SPEED_TEST_5: + *pSpeed_value = CPLD_FAN_SPEED_5; + break; + case FAN_SPEED_VERY_HIGH: + case FAN_SPEED_TEST_6: + *pSpeed_value = CPLD_FAN_SPEED_6; + break; + case FAN_SPEED_ULTRA_HIGH: + case FAN_SPEED_FULL: + case FAN_SPEED_TEST_7: + *pSpeed_value = CPLD_FAN_SPEED_7; + break; + default: + goto END; + } + } + + ret = 0; +END: + return ret; +} + +EUNIT_PWRON_TYPE GetEUnitType(void) +{ + return syno_module.eunit_pwron_type; +} diff --git a/drivers/syno/synobios/mapping.h b/drivers/syno/synobios/mapping.h new file mode 100755 index 000000000000..3096a12f60aa --- /dev/null +++ b/drivers/syno/synobios/mapping.h @@ -0,0 +1,542 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include "synobios.h" + +#define CPLD_FAN_SPEED_0 0x0 +#define CPLD_FAN_SPEED_1 0x1 +#define CPLD_FAN_SPEED_2 0x2 +#define CPLD_FAN_SPEED_3 0x3 +#define CPLD_FAN_SPEED_4 0x4 +#define CPLD_FAN_SPEED_5 0x5 +#define CPLD_FAN_SPEED_6 0x6 +#define CPLD_FAN_SPEED_7 0x7 +#define CPLD_FAN_SPEED_8 0x8 +#define CPLD_FAN_SPEED_9 0x9 +#define CPLD_FAN_SPEED_10 0xa +#define CPLD_FAN_SPEED_11 0xb +#define CPLD_FAN_SPEED_12 0xc +#define CPLD_FAN_SPEED_13 0xd +#define CPLD_FAN_SPEED_14 0xe +#define CPLD_FAN_SPEED_15 0xf +#define CPLD_FAN_SPEED_16 0x10 +#define CPLD_FAN_SPEED_17 0x18 + +// DS2.0 #8126 +// These two definitions are for 3-bit fan speed adjust +// The unit for this duration is milli-seconds, ex: 500ms. +#define FAN_ACTIVATION_SPEED CPLD_FAN_SPEED_6 +#define FAN_ACTIVATION_DURATION 500 + +/** + * if you want to add a field to module_t, remember to modify + * this macro + */ +#define MODULE_T_DECLARE(FAN_T, \ + LED_T, \ + THERMAL_T, \ + DISK_LED_CTRL_T, \ + AUTO_POWERON_T, \ + DUAL_POWER_T, \ + USBCOPY_T, \ + FAN_NUMBER_T, \ + EUNIT_PWRON_TYPE, \ + POWER_IN_SEQ, \ + RTC_TYPE, \ + CPUTMP_T, \ + FAN_RPM_RPT_T, \ + LCM_T, \ + WIFI_WPS_T, \ + CPUFREQ_ADJUST_T, \ + CARDREADER_T, \ + HIBERNATE_LED_T, \ + RTC_CORRECTION_T, \ + SYNO_MICROP_ID, \ + GROUP_WAKE_CONFIG_T, \ + CPU_ARCH_INFO_T, \ + CRYPTO_HW_INFO_T) \ + \ + { \ + fan_type: FAN_T, \ + led_type: LED_T, \ + thermal_type: THERMAL_T, \ + diskled_ctrl_type: DISK_LED_CTRL_T,\ + auto_poweron_type: AUTO_POWERON_T, \ + dual_power_type: DUAL_POWER_T, \ + usbcopy_type: USBCOPY_T, \ + fan_number: FAN_NUMBER_T, \ + eunit_pwron_type: EUNIT_PWRON_TYPE, \ + pis_type: POWER_IN_SEQ, \ + rtc_type: RTC_TYPE, \ + cputmp_type: CPUTMP_T, \ + fan_rpm_rpt_type: FAN_RPM_RPT_T, \ + lcm_type: LCM_T, \ + wifi_wps_type: WIFI_WPS_T, \ + cpu_freq_adjust: CPUFREQ_ADJUST_T, \ + has_cardreader: CARDREADER_T, \ + hibernate_led: HIBERNATE_LED_T, \ + rtc_corr_value: RTC_CORRECTION_T, \ + microp_id: SYNO_MICROP_ID, \ + group_wake_config: GROUP_WAKE_CONFIG_T,\ + cpu_arch_info: CPU_ARCH_INFO_T, \ + crypto_hw_info: CRYPTO_HW_INFO_T \ + } + +/** + * Add a model must also add a define on this. And add the + * assign on your own module_type_init in dsxxx.c + */ + +#define MODULE_T_RS3411rpxs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_CPUFAN_AND_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3411rpxs, FOUR_DISK_DENO_SEVEN, CPU_I3_2100, CRYPTO_HW_NONE) //{MODEL_RS3411rpxs, HW_RS3411rpxs} + +#define MODULE_T_RS3411xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_CPUFAN_AND_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3411xs, FOUR_DISK_DENO_SEVEN, CPU_I3_2100, CRYPTO_HW_NONE) //{MODEL_RS3411xs, HW_RS3411xs} + +// redefine the meanning of ebox, SAS model doesn't support ebox, but leave enclosure as a part of eunit +#define MODULE_T_RS10613xsp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_YES, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_10613xsp, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RS10613xsp, HW_RS10613xsp} + +#define MODULE_T_RS3412rpxs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3411rpxs, FOUR_DISK_DENO_SEVEN, CPU_I3_2100, CRYPTO_HW_NONE) //{MODEL_RS3412rpxs, HW_RS3412rpxs} + +#define MODULE_T_RS3412xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3411xs, FOUR_DISK_DENO_SEVEN, CPU_I3_2100, CRYPTO_HW_NONE) //{MODEL_RS3412xs, HW_RS3412xs} + +#define MODULE_T_DS3611xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_CPUFAN_AND_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3611xs, FOUR_DISK_DENO_SEVEN, CPU_I3_2100, CRYPTO_HW_NONE) //{MODEL_DS3611xs, HW_DS3611xs} + +#define MODULE_T_DS3612xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3611xs, FOUR_DISK_DENO_SEVEN, CPU_I3_2100, CRYPTO_HW_NONE) //{MODEL_DS3612xs, HW_DS3612xs} + +#define MODULE_T_DS3615xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3615xs, FOUR_DISK_DENO_SEVEN, CPU_I3_4130, CRYPTO_HW_NONE) //{MODEL_DS3615xs, HW_DS3615xs} + +#define MODULE_T_RS3413xsp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_YES, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_3413xsp, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RS3413xsp, HW_RS3413xsp} + +#define MODULE_T_RS3614xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS3614xs, FOUR_DISK_DENO_SEVEN, CPU_I3_4130, CRYPTO_HW_NONE) //{MODEL_RS3614xs, HW_RS3614xs} + +#define MODULE_T_RS3614rpxs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS3614rpxs, FOUR_DISK_DENO_SEVEN, CPU_I3_4130, CRYPTO_HW_NONE) //{MODEL_RS3614rpxs, HW_RS3614rpxs} + +#define MODULE_T_RS3614xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS3614xsp, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RS3614xsp, HW_RS3614xsp} + +#define MODULE_T_DS2414xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_DS2414xs, FOUR_DISK_DENO_SEVEN, CPU_I3_4130, CRYPTO_HW_NONE) //{MODEL_DS2414xs, HW_DS2414xs} + +#define MODULE_T_DS412p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_4, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_BREATH, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_412p, ONE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS412p, HW_DS412p} + +#define MODULE_T_RS812p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_812p, ONE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS812p, HW_RS812p} + +#define MODULE_T_DS713p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_MICROP, FAN_NUMBER_1, EUNIT_PWRON_GPIO, POWER_IN_SEQ_2, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_713p, ONE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS713p, HW_DS713p} + +#define MODULE_T_RS812rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_812rp, ONE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS812p, HW_RS812p} + +#define MODULE_T_RS814p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS814p, ONE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS814p, HW_RS814p} + +#define MODULE_T_RS814rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS814rpp, ONE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS814rpp, HW_RS814rpp} + +#define MODULE_T_DS1812p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_1812p, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS1812p, HW_DS1812p} + +#define MODULE_T_DS1813p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_1813p, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS1813p, HW_DS1813p} + +#define MODULE_T_RS2212p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_2212p, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS2212p, HW_RS2212p} + +#define MODULE_T_RS2212rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_2212rp, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS2212rpp, HW_RS2212rpp} + +#define MODULE_T_RS2414p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS2414p, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS2414p, HW_RS2414p} + +#define MODULE_T_RS2414rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS2414rpp, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_RS2414rpp, HW_RS2414rpp} + +#define MODULE_T_DS2413p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_2413p, FOUR_DISK_DENO_SEVEN, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS2413p, HW_DS2413p} + +#define MODULE_T_DS2415p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS2415p, HW_DS2415p} + +#define MODULE_T_RS812 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_RICOH, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_RICOH_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6282, CRYPTO_628X) //{MODEL_RS812, HW_RS812} + +#define MODULE_T_DS1512p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_1512p, FIVE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS1512p, HW_DS1512p} + +#define MODULE_T_DS1513p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_1513p, FIVE_DISK_DENO_ONE, CPU_D2700, CRYPTO_HW_NONE) //{MODEL_DS1513p, HW_DS1513p} + +#define MODULE_T_DS414jv10 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2000, CRYPTO_COMCERTO2K) //{MODEL_DS414j, HW_DS414jv10} + + +#define MODULE_T_DS415jv10 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2000, CRYPTO_COMCERTO2K) //{MODEL_DS415j, HW_DS415jv10} + +#define MODULE_T_DS213 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_MICROP, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_RICOH, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_YES, HIBER_LED_STATUS_BREATH, RTC_RICOH_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6282, CRYPTO_628X) //{MODEL_DS213, HW_DS213} + +#define MODULE_T_DS213jv1 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_DS213jv10, HW_DS213jv10} + +#define MODULE_T_DS114v1 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_DS114v10, HW_DS114v10} + +#define MODULE_T_RS214v1 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_RS214v10, HW_RS214v1} + +#define MODULE_T_DS214p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_MICROP, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_MV78230, CRYPTO_AXP) //{MODEL_DS214p, HW_DS214p} + +#define MODULE_T_DS214 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_MICROP, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_BREATH, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_MV78230, CRYPTO_AXP) //{MODEL_DS214, HW_DS214} + +#define MODULE_T_DS214se MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_DS214se, HW_DS214se} + +#define MODULE_T_DS114pv1 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_MICROP, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_DS114p, HW_DS114p} + +#define MODULE_T_DS414 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_BREATH, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_MV78230, CRYPTO_AXP) //{MODEL_DS414, HW_DS414} + +#define MODULE_T_RS814 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_MV78230, CRYPTO_AXP) //{MODEL_RS814, HW_RS814} + +#define MODULE_T_DS214playv1 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_MICROP, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_YES, HIBER_LED_STATUS_BREATH, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_CE5335, CRYPTO_HW_NONE) //{MODEL_DS214play, HW_DS214play} + +#define MODULE_T_DS415play MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_SEIKO_CORR_DEFAULT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_CE5335, CRYPTO_HW_NONE) //{MODEL_DS415play, HW_DS415play} + +#define MODULE_T_DS916p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_N3710, CRYPTO_HW_NONE) //{MODEL_DS916p, HW_DS916p} + +#define MODULE_T_DS716p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_N3150, CRYPTO_HW_NONE) //{MODEL_DS716p, HW_DS716p} + +#define MODULE_T_DS716pII MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_N3160, CRYPTO_HW_NONE) //{MODEL_DS716pII, HW_DS716pII} + +#define MODULE_T_DS414slim MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_DS414slim, HW_DS414slim} + +#define MODULE_T_RC18015xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_6, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_NORMAL, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RC18015xsp, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RC18015xsp, HW_RC18015xsp} + +#define MODULE_T_RS18016xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS18016xsp, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RS18016xsp, HW_RS18016xsp} + +#define MODULE_T_RS18016Dxsp MODULE_T_DECLARE(FAN_BMC, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS18016Dxsp, FOUR_DISK_DENO_SEVEN, CPU_E5_2609v3, CRYPTO_HW_NONE) //{MODEL_RS18016Dxsp, HW_RS18016Dxsp} + +#define MODULE_T_FS3017 MODULE_T_DECLARE(FAN_BMC, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_FS3017, FOUR_DISK_DENO_SEVEN, CPU_E5_2620v3, CRYPTO_HW_NONE) //{MODEL_FS3017, HW_FS3017} + +#define MODULE_T_RS3415xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS3415xsp, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RS3415xsp, HW_RS3415xsp} + +#define MODULE_T_DS2015xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_AL514, CRYPTO_ALPINE) //{MODEL_DS2015xs, HW_DS2015xs} + +#define MODULE_T_DS115j MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_DS115j, HW_DS115j} + +#define MODULE_T_DS415p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_4, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS415p, HW_DS415p} + +#define MODULE_T_DS1815p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS1815p, HW_DS1815p} + +#define MODULE_T_DS1515p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS1515p, HW_DS1515p} + +#define MODULE_T_DS215j MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6720, CRYPTO_A375) //{MODEL_DS215j, HW_DS215j} + +#define MODULE_T_DS115 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6720, CRYPTO_A375) //{MODEL_DS115, HW_DS115} + +#define MODULE_T_RS815p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS815p, HW_RS815p} + +#define MODULE_T_RS815rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS815rpp, HW_RS815rpp} + + +#define MODULE_T_RS815 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_MV78230, CRYPTO_AXP) + +#define MODULE_T_DS1515 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_AL314, CRYPTO_ALPINE) //{MODEL_DS1515, HW_DS1515} + +#define MODULE_T_DS715 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_AL314, CRYPTO_ALPINE) //{MODEL_DS715, HW_DS715} + +#define MODULE_T_DS215p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_AL212, CRYPTO_ALPINE) //{MODEL_DS215p, HW_DS215p} + +#define MODULE_T_DS416 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_AL212, CRYPTO_ALPINE) //{MODEL_DS416, HW_DS416} + +#define MODULE_T_RS2416p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS2416p, HW_RS2416p} + +#define MODULE_T_RS2416rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS2416rpp, HW_RS2416rpp} + +#define MODULE_T_DS216play MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_H412, CRYPTO_HW_NONE) //{MODEL_DS216play, HW_DS216play} + +#define MODULE_T_DS216se MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6707, CRYPTO_A370) //{MODEL_DS216se, HW_DS216se} + +#define MODULE_T_RSD18016xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_NORMAL, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_RSD18016xsp, HW_RSD18016xsp} + +#define MODULE_T_DS416j MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6828, CRYPTO_A38X) //{MODEL_DS416j, HW_DS416j} + +#define MODULE_T_DS216 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_DS216, HW_DS216} + +#define MODULE_T_DS416slim MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_DS416slim, HW_DS416slim} + +#define MODULE_T_DS1616p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS1616p, HW_DS1616p} + +#define MODULE_T_VirtualDSM MODULE_T_DECLARE(FAN_UNKNOWN, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_VirtualDSM, HW_VirtualDSM} + +#define MODULE_T_RS3618xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1521, CRYPTO_HW_NONE) //{MODEL_RS3618xs, HW_RS3618xs} + +#define MODULE_T_RS3617rpxs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1521, CRYPTO_HW_NONE) //{MODEL_RS3617rpxs, HW_RS3617rpxs} + +#define MODULE_T_RS3617xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1531, CRYPTO_HW_NONE) //{MODEL_RS3617xsp, HW_RS3617xsp} + +#define MODULE_T_DS216p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_N3050, CRYPTO_HW_NONE) //{MODEL_DS216p, HW_DS216p} + +#define MODULE_T_DS216pII MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_N3060, CRYPTO_HW_NONE) //{MODEL_DS216pII, HW_DS216pII} + +#define MODULE_T_DS216j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_DS216j, HW_DS216j} + +#define MODULE_T_RS816 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_RS816, HW_RS816} + +#define MODULE_T_DS116 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_DS116, HW_DS116} + +#define MODULE_T_DS416play MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_N3060, CRYPTO_HW_NONE) //{MODEL_DS416play, HW_DS416play} + +#define MODULE_T_RS217 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_RS217, HW_RS217} + +#define MODULE_T_RS3617xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_RS3617xs, FOUR_DISK_DENO_SEVEN, CPU_E3_1230v2, CRYPTO_HW_NONE) //{MODEL_RS3617xs, HW_RS3617xs} + +#define MODULE_T_RS2418p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS2418p, HW_RS2418p} + +#define MODULE_T_RS2418rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS2418rpp, HW_RS2418rpp} + +#define MODULE_T_DS918p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3455, CRYPTO_HW_NONE) //{MODEL_DS918p, HW_DS918p} + +#define MODULE_T_RS4017xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_RS4017xsp, HW_RS4017xsp} + +#define MODULE_T_DS3617xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1528, CRYPTO_HW_NONE) //{MODEL_DS3617xs, HW_DS3617xs} + +#define MODULE_T_RS18017xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1531, CRYPTO_HW_NONE) //{MODEL_RS18017xsp, HW_RS18017xsp} + +#define MODULE_T_DS218p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3355, CRYPTO_HW_NONE) //{MODEL_DS218p, HW_DS218p} + +#define MODULE_T_DS1618p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_DS1618p, HW_DS1618p} + +#define MODULE_T_DS1517p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS1517p, HW_DS1517p} + +#define MODULE_T_DS1817p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_DS1817p, HW_DS1817p} + +#define MODULE_T_C2DSM MODULE_T_DECLARE(FAN_UNKNOWN, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_C2DSM, HW_C2DSM} + +#define MODULE_T_DS718p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3455, CRYPTO_HW_NONE) //{MODEL_DS718p, HW_DS718p} + +#define MODULE_T_FS2017 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_FS2017, HW_FS2017} + +#define MODULE_T_DS418j MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1293, CRYPTO_RTD129X) //{MODEL_DS418j, HW_DS418j} + +#define MODULE_T_DS418 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_DS418, HW_DS418} + +#define MODULE_T_DS218play MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_DS218play, HW_DS218play} + +#define MODULE_T_DS118 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_DS118, HW_DS118} + +#define MODULE_T_DS218 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_DS218, HW_DS218} + +#define MODULE_T_DS1817 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_AL314, CRYPTO_ALPINE) //{MODEL_DS1817, HW_DS1817} + +#define MODULE_T_EDS19 MODULE_T_DECLARE(FAN_UNKNOWN, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_NO, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_X, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_YES, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_EDS19, HW_EDS19} + +#define MODULE_T_RS819 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_RS819, HW_RS819} + +#define MODULE_T_DS220j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_DS220j, HW_DS220j} + +#define MODULE_T_DS420j MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE,CPU_RTD1296, CRYPTO_RTD129X) //{MODEL_DS420j, HW_DS420j} + +#define MODULE_T_DS1517 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_AL314, CRYPTO_ALPINE) //{MODEL_DS1517, HW_DS1517} + +#define MODULE_T_DS3017xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_D_1508, CRYPTO_HW_NONE) //{MODEL_DS3017xs, HW_DS3017xs} + +#define MODULE_T_DS3018xs MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_D_1508, CRYPTO_HW_NONE) //{MODEL_DS3018xs, HW_DS3018xs} + +#define MODULE_T_FS1018 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_D_1508, CRYPTO_HW_NONE) //{MODEL_FS1018, HW_FS1018} + +#define MODULE_T_DS219j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_MV, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F3720, CRYPTO_HW_NONE) //{MODEL_DS219j, HW_DS219j} + +#define MODULE_T_FS6400 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_SILVER_4110, CRYPTO_HW_NONE) //{MODEL_FS6400, HW_FS6400} + +#define MODULE_T_RS818p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS818p, HW_RS818p} + +#define MODULE_T_RS818rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_GPIO, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS818rpp, HW_RS818rpp} + +#define MODULE_T_DS418play MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3355, CRYPTO_HW_NONE) //{MODEL_DS418play, HW_DS418play} + +#define MODULE_T_RS2818rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS2818rpp, HW_RS2818rpp} + +#define MODULE_T_DS219se MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_MV, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F3720, CRYPTO_HW_NONE) //{MODEL_DS219se, HW_DS219se} + +#define MODULE_T_NVR1218 MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_GPIO, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_NVR, CRYPTO_HW_NONE) //{MODEL_NVR, HW_NVR1218} + +#define MODULE_T_DS218j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_MV, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_DS218j, HW_DS218j} + +#define MODULE_T_DS3619xs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_DS3619xs, HW_DS3619xs} + +#define MODULE_T_DS119j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F3720, CRYPTO_HW_NONE) //{MODEL_DS119j, HW_DS119j} + +#define MODULE_T_DS120j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_YES, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_MV, CPUTMP_NO, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F3720, CRYPTO_HW_NONE) //{MODEL_DS120j, HW_DS120j} + +#define MODULE_T_TAIPEI MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1521, CRYPTO_HW_NONE) //{MODEL_TAIPEI, HW_TAIPEI} + +#define MODULE_T_RS1619xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_D_1527, CRYPTO_HW_NONE) //{MODEL_RS1619xsp, HW_RS1619xsp} + +#define MODULE_T_RS1219p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C2538, CRYPTO_HW_NONE) //{MODEL_RS1219p, HW_RS1219p} + +#define MODULE_T_DS2419p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_DS2419p, HW_DS2419p} + + +#define MODULE_T_DS419p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3455, CRYPTO_HW_NONE) //{MODEL_DS419p, HW_DS419p} + +#define MODULE_T_DS1019p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3455, CRYPTO_HW_NONE) //{MODEL_DS1019p, HW_DS1019p} + +#define MODULE_T_DS719p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3455, CRYPTO_HW_NONE) //{MODEL_DS719p, HW_DS719p} + +#define MODULE_T_DS1819p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_DS1819p, HW_DS1819p} + +#define MODULE_T_DS620slim MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3355, CRYPTO_HW_NONE) //{MODEL_DS620slim, HW_DS620slim} + +#define MODULE_T_RS419p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J3455, CRYPTO_HW_NONE) //{MODEL_RS419p, HW_RS419p} + +#define MODULE_T_DS419slim MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_88F6820, CRYPTO_A38X) //{MODEL_DS419slim, HW_DS419slim} + +#define MODULE_T_RS1219 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_AL314, CRYPTO_ALPINE) //{MODEL_RS1219, HW_RS1219} + +#define MODULE_T_DVA3219 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_DVA3219, HW_DVA3219} + +#define MODULE_T_SA3400 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_SA3400, HW_SA3400} + +#define MODULE_T_DS420p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4025, CRYPTO_HW_NONE) //{MODEL_DS420p, HW_DS420p} + +#define MODULE_T_DS720p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_DS720p, HW_DS720p} + +#define MODULE_T_RS820p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS820p, HW_RS820p} + +#define MODULE_T_RS820rpp MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS820rpp, HW_RS820rpp} + +#define MODULE_T_DS220p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4025, CRYPTO_HW_NONE) //{MODEL_DS220p, HW_DS220p} + +#define MODULE_T_FS3400 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_FS3400, HW_FS3400} + +#define MODULE_T_SA3600 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1567, CRYPTO_HW_NONE) //{MODEL_SA3600, HW_SA3600} + +#define MODULE_T_FS3600 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1567, CRYPTO_HW_NONE) //{MODEL_FS3600, HW_FS3600} + +#define MODULE_T_HD3400 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_HD3400, HW_HD3400} + +#define MODULE_T_DS220play MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1619, CRYPTO_RTD1619) //{MODEL_DS220play, HW_DS220play} + +#define MODULE_T_DS220 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1619, CRYPTO_RTD1619) //{MODEL_DS220, HW_DS220} + +#define MODULE_T_DS1520p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_DS1520p, HW_DS1520p} + +#define MODULE_T_RS1220p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS1220p, HW_RS1220p} + +#define MODULE_T_RS1220rpp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_RS1220rpp, HW_RS1220rpp} + +#define MODULE_T_DS1621xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FIVE_DISK_DENO_ONE, CPU_D_1527, CRYPTO_HW_NONE) //{MODEL_DS1621xsp, HW_DS1621xsp} + +#define MODULE_T_DS920p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_DS920p, HW_DS920p} + +#define MODULE_T_SA6500 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_SILVER_4210R, CRYPTO_HW_NONE) //{MODEL_SA6500, HW_SA6500} + +#define MODULE_T_DS1621p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_DS1621p, HW_DS1621p} + +#define MODULE_T_HD6500 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_SILVER_4210R, CRYPTO_HW_NONE) //{MODEL_HD6500, HW_HD6500} + +#define MODULE_T_SA3200d MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1521, CRYPTO_HW_NONE) //{MODEL_SA3200d, HW_XA3200d} + +#define MODULE_T_SA3400d MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_SA3400d, HW_XA3200d} + +#define MODULE_T_DVA3221 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_DVA3221, HW_DVA3221} +#define MODULE_T_AliDSM MODULE_T_DECLARE(FAN_UNKNOWN, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_AliDSM, HW_AliDSM} + +#define MODULE_T_RS1221p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS1221p, HW_RS1221p} + +#define MODULE_T_RS1221rpp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS1221rpp, HW_RS1221rpp} + +#define MODULE_T_DS1821p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_DS1821p, HW_DS1821p} + +#define MODULE_T_DS2422p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_DS2422p, HW_DS2422p} + +#define MODULE_T_RS2421p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS2421p, HW_RS2421p} + +#define MODULE_T_RS2421rpp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS2421rpp, HW_RS2421rpp} + +#define MODULE_T_RS2821rpp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS2821rpp, HW_RS2821rpp} + +#define MODULE_T_FS6600N MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_SILVER_4214R, CRYPTO_HW_NONE) //{MODEL_FS6600N, HW_FS6600N} + +#define MODULE_T_RS3621xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_RS3621xsp, HW_RS3621xsp} + +#define MODULE_T_RS3621rpxs MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1531, CRYPTO_HW_NONE) //{MODEL_RS3621rpxs, HW_RS3621rpxs} + +#define MODULE_T_RS4021xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_RS4021xsp, HW_RS4021xsp} + +#define MODULE_T_FS6500 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_SILVER_4210R, CRYPTO_HW_NONE) //{MODEL_FS6500, HW_FS6500} + +#define MODULE_T_DS3617xsII MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STATUS_OFF, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1528, CRYPTO_HW_NONE) //{MODEL_DS3617xsII, HW_DS3617xsII} + +#define MODULE_T_DS3622xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1531, CRYPTO_HW_NONE) //{MODEL_DS3622xsp, HW_DS3622xsp} + +#define MODULE_T_DS2419pII MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_C3538, CRYPTO_HW_NONE) //{MODEL_DS2419pII, HW_DS2419pII} + +#define MODULE_T_FS2500 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_FS2500, HW_FS2500} + +#define MODULE_T_FS2500T MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_FS2500T, HW_FS2500T} + +#define MODULE_T_FS6400N MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_EPYC7272, CRYPTO_HW_NONE) //{MODEL_FS6400N, HW_FS6400N} + +#define MODULE_T_DS723p MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_R1600, CRYPTO_HW_NONE) //{MODEL_DS723p, HW_DS723p} + +#define MODULE_T_DS923p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_R1600, CRYPTO_HW_NONE) //{MODEL_DS923p, HW_DS923p} + +#define MODULE_T_RS422p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_R1600, CRYPTO_HW_NONE) //{MODEL_RS422p, HW_RS422p} + +#define MODULE_T_DVA1622 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_DVA1622, HW_DVA1622} + +#define MODULE_T_RS4023xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_DIODES, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_5566, CRYPTO_HW_NONE) //{MODEL_RS4023xsp, HW_RS4023xsp} + +#define MODULE_T_DS223j MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_DIODES, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1619B, CRYPTO_RTD1619B) //{MODEL_DS223j, HW_DS223j} + +#define MODULE_T_DS1522p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_R1600, CRYPTO_HW_NONE) //{MODEL_DS1522p, HW_DS1522p} + +#define MODULE_T_RS4022xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_RS4022xsp, HW_RS4022xsp} + +#define MODULE_T_FS3410 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_FS3410, HW_FS3410} + +#define MODULE_T_DS423 MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_4, RTC_DIODES, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1619B, CRYPTO_RTD1619B) //{MODEL_DS423, HW_DS423} + +#define MODULE_T_FS6410 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_EPYC7272, CRYPTO_HW_NONE) //{MODEL_FS6410, HW_FS6410} + +#define MODULE_T_SA6400 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_EPYC7272, CRYPTO_HW_NONE) //{MODEL_SA6400, HW_SA6400} + +#define MODULE_T_SA6200 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_EPYC7232P, CRYPTO_HW_NONE) //{MODEL_SA6200, HW_SA6200} + +#define MODULE_T_SC6200 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_EPYC7232P, CRYPTO_HW_NONE) //{MODEL_SC6200, HW_SC6200} + +#define MODULE_T_DS223 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_DIODES, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1619B, CRYPTO_RTD1619B) //{MODEL_DS223, HW_DS223} + +#define MODULE_T_RS822p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS822p, HW_RS822p} + +#define MODULE_T_RS822rpp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_RS822rpp, HW_RS822rpp} + +#define MODULE_T_RS2423p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_RS2423p, HW_RS2423p} + +#define MODULE_T_RS2423rpp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_RS2423rpp, HW_RS2423rpp} + +#define MODULE_T_DS1823xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_DS1823xsp, HW_DS1823xsp} + +#define MODULE_T_RS1623xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_DS1823xsp, HW_DS1823xsp} + +#define MODULE_T_DS423p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_4, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_DS423p, HW_DS423p} + +#define MODULE_T_SA3410 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1541, CRYPTO_HW_NONE) //{MODEL_SA3410, HW_SA3410} + +#define MODULE_T_SA3610 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_4, EUNIT_SAS_NO_PWRON, POWER_IN_SEQ_OFF, RTC_BANDON, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_D_1567, CRYPTO_HW_NONE) //{MODEL_SA3610, HW_SA3610} +#define MODULE_T_DS124 MODULE_T_DECLARE(FAN_MICROP_PWM, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_DIODES, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_RTD1619B, CRYPTO_RTD1619B) //{MODEL_DS124, HW_DS124} + +#define MODULE_T_DS224p MODULE_T_DECLARE(FAN_MICROP_PWM_WITH_GPIO, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_GPIO, FAN_NUMBER_1, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_2, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_DS224p, HW_DS224p} + +#define MODULE_T_RS4024xsp MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_DIODES, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_5800E, CRYPTO_HW_NONE) //{MODEL_RS4024xsp, HW_RS4024xsp} + +#define MODULE_T_VS750hd MODULE_T_DECLARE(FAN_MULTI_ALWAYS, LED_DISKS, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_NO, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_X, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_UNKNOWN, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_NO, CARDREADER_NO, HIBER_LED_POWER_ONLY, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_J4125, CRYPTO_HW_NONE) //{MODEL_VS750hd, HW_VS750hd}}) + +#define MODULE_T_FS6600DN MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD , POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_YES, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, FOUR_DISK_DENO_SEVEN, CPU_EPYC7443P, CRYPTO_HW_NONE) //{MODEL_FS6600DN, HW_FS6600DN} + +#define MODULE_T_DS1623p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_DS1623p, HW_DS1623p} + +#define MODULE_T_DS1823p MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_SINGLE, USBCOPY_NO, FAN_NUMBER_2, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1500B, CRYPTO_HW_NONE) // {MODEL_DS1823p, HW_DS1823p} + +#define MODULE_T_SC2500 MODULE_T_DECLARE(FAN_ADT, LED_DISKS_ALARM, THERMAL_NO, DISK_LED_CTRL_SW, AUTO_POWERON_YES, POWER_DUAL, USBCOPY_NO, FAN_NUMBER_3, EUNIT_PWRON_ATACMD, POWER_IN_SEQ_OFF, RTC_SEIKO, CPUTMP_YES, FAN_RPM_RPT_NO, LCM_NO, WIFI_WPS_NO, CPU_FREQ_ADJUST_YES, CARDREADER_NO, HIBER_LED_STANDARD_BEHAVIOR, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, ONE_DISK_DENO_ONE, CPU_V1780B, CRYPTO_HW_NONE) // {MODEL_SC2500, HW_SC2500} + +#define MODULE_T_UNKNOWN MODULE_T_DECLARE(FAN_UNKNOWN, LED_UNKNOWN, THERMAL_UNKNOWN, DISK_LED_CTRL_UNKNOWN, AUTO_POWERON_UNKNOWN, POWER_UNKNOWN, USBCOPY_NO, FAN_NUMBER_X, EUNIT_NOT_SUPPORT, POWER_IN_SEQ_OFF, RTC_UNKNOWN, CPUTMP_UNKNOWN, FAN_RPM_RPT_UNKNOWN, LCM_NO, WIFI_WPS_UNKNOWN, CPU_FREQ_ADJUST_UNKNOWN, CARDREADER_UNKNOWN, HIBER_LED_UNKNOWN, RTC_NOT_NEED_TO_CORRECT, MICROP_ID_UNKNOW, UNKNOW_DISK_DENO, CPU_UNKNOWN, CRYPTO_HW_NONE) //{MODEL_INVALID, NULL} + + +void module_type_set(module_t *pModule); +module_t *module_type_get(void); + +int GetFanNum(int *pFanNum); +#ifdef MY_DEF_HERE +int SetGroupWakeConfig(void); +#endif +#if defined(CONFIG_SYNO_X86) || defined(CONFIG_SYNO_X64) +int CheckMicropId(const struct synobios_ops *); +int SetMicropId(void); +int SetUart(const char* cmd); +int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +#endif +int GetHwCapability(CAPABILITY *pCapability); +EUNIT_PWRON_TYPE GetEUnitType(void); +int FanStatusMappingType1(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value); +int FanStatusMappingType2(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value); + +#define SYNO_MICROP_TTYSDEV "/dev/ttyS1" +#define MICROP_CMD_READID "R" diff --git a/drivers/syno/synobios/mesh/mesh.c b/drivers/syno/synobios/mesh/mesh.c new file mode 100644 index 000000000000..83b19e0ed260 --- /dev/null +++ b/drivers/syno/synobios/mesh/mesh.c @@ -0,0 +1,277 @@ + +#include "../mapping.h" +#include "mesh.h" +extern int router_exdisplay_handler(struct _SynoMsgPkt *pMsgPkt); +bool gMeshHeartBeatAlive = false; +bool gMeshIsRE = false; +bool gMeshIsJoining = false; +int gMeshSingalQuality = 0; +SYNO_MESH_BACKHAUL_TYPE gMeshBackhaulType = MESH_BACKHAUL_TYPE_NONE; +int syno_mesh_signal_quality_read_command(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", gMeshSingalQuality); + return 0; +} + +int syno_mesh_signal_quality_write_command(struct file *filp,const char *buf,size_t count,loff_t *offp) +{ + int val = -1; + struct _SynoMsgPkt msgPkt; + + sscanf(buf, "%d", &val); + + if (0 > val || 100 < val) { + goto END; + } + + gMeshSingalQuality = val; + + msgPkt.usNum = SYNO_MESH_SIGNAL_QUALITY; + msgPkt.usLen = 0; + msgPkt.szMsg[0] = 0; + + router_exdisplay_handler(&msgPkt); +END: + return count; +} + +static int synobios_proc_mesh_signal_quality_open(struct inode *inode, struct file *file) +{ + return single_open(file, syno_mesh_signal_quality_read_command, NULL); +} + +static const struct file_operations synobios_proc_mesh_signal_quality_fops = { + .owner = THIS_MODULE, + .open = synobios_proc_mesh_signal_quality_open, + .write = syno_mesh_signal_quality_write_command, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int syno_mesh_is_joining_read_command(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", gMeshIsJoining); + return 0; +} + +int syno_mesh_is_joining_write_command(struct file *filp,const char *buf,size_t count,loff_t *offp) +{ + int val = -1; + struct _SynoMsgPkt msgPkt; + module_t* pSynoModule = NULL; + + sscanf(buf, "%d", &val); + + if (0 > val || 1 < val) { + goto END; + } + + if (val) { + gMeshIsJoining = true; + msgPkt.usNum = SYNO_LED_NETWORK_SETTING; + } else { + gMeshIsJoining = false; + msgPkt.usNum = SYNO_LED_NETWORK_SETTING_END; + } + pSynoModule = module_type_get(); + if (LED_RT == pSynoModule->led_type) { + snprintf(msgPkt.szMsg, sizeof(msgPkt.szMsg), "findme"); + msgPkt.usLen = strlen(msgPkt.szMsg); + + router_exdisplay_handler(&msgPkt); + } +END: + return count; +} + +static int synobios_proc_mesh_is_joining_open(struct inode *inode, struct file *file) +{ + return single_open(file, syno_mesh_is_joining_read_command, NULL); +} + +static const struct file_operations synobios_proc_mesh_is_joining_fops = { + .owner = THIS_MODULE, + .open = synobios_proc_mesh_is_joining_open, + .write = syno_mesh_is_joining_write_command, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int syno_mesh_is_re_read_command(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", gMeshIsRE); + return 0; +} + +int syno_mesh_is_re_write_command(struct file *filp,const char *buf,size_t count,loff_t *offp) +{ + int val = -1; + module_t* pSynoModule = NULL; + struct _SynoMsgPkt msgPkt; + + sscanf(buf, "%d", &val); + + if (0 > val || 1 < val) { + goto END; + } + + if (!val) { + gMeshIsRE = false; + } else { + gMeshIsRE = true; + if (gMeshHeartBeatAlive) { + msgPkt.usNum = SYNO_LED_CONNECT; + } else { + msgPkt.usNum = SYNO_LED_DISCONNECT; + } + msgPkt.usLen = 0; + msgPkt.szMsg[0] = 0; + + pSynoModule = module_type_get(); + if (LED_RT == pSynoModule->led_type) { + router_exdisplay_handler(&msgPkt); + + } + } +END: + return count; +} + +static int synobios_proc_mesh_is_re_open(struct inode *inode, struct file *file) +{ + return single_open(file, syno_mesh_is_re_read_command, NULL); +} + +static const struct file_operations synobios_proc_mesh_is_re_fops = { + .owner = THIS_MODULE, + .open = synobios_proc_mesh_is_re_open, + .write = syno_mesh_is_re_write_command, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int syno_mesh_heartbeat_alive_read_command(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", gMeshHeartBeatAlive); + return 0; +} + +int syno_mesh_heartbeat_alive_write_command(struct file *filp,const char *buf,size_t count,loff_t *offp) +{ + int val = -1; + module_t* pSynoModule = NULL; + struct _SynoMsgPkt msgPkt; + + sscanf(buf, "%d", &val); + + if (0 > val || 1 < val) { + goto END; + } + + if (0 == val) { + gMeshHeartBeatAlive = false; + msgPkt.usNum = SYNO_LED_DISCONNECT; + } else { + gMeshHeartBeatAlive = true; + msgPkt.usNum = SYNO_LED_CONNECT; + } + msgPkt.usLen = 0; + msgPkt.szMsg[0] = 0; + + pSynoModule = module_type_get(); + if (LED_RT == pSynoModule->led_type) { + router_exdisplay_handler(&msgPkt); + + } +END: + return count; +} + +static int synobios_read_proc_mesh_heartbeat_alive_open(struct inode *inode, struct file *file) +{ + return single_open(file, syno_mesh_heartbeat_alive_read_command, NULL); +} + +static const struct file_operations synobios_read_proc_mesh_heartbeat_alive_fops = { + .owner = THIS_MODULE, + .open = synobios_read_proc_mesh_heartbeat_alive_open, + .write = syno_mesh_heartbeat_alive_write_command, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int syno_mesh_eth_backhaul_type_read_command(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", gMeshBackhaulType); + return 0; +} + +int syno_mesh_backhaul_type_write_command(struct file *filp,const char *buf,size_t count,loff_t *offp) +{ + int val = -1; + struct _SynoMsgPkt msgPkt; + + sscanf(buf, "%d", &val); + + if (0 > val || 2 < val) { + goto END; + } + + gMeshBackhaulType = val; + + msgPkt.usNum = SYNO_MESH_BACKHAUL_IFACE; + msgPkt.usLen = 0; + msgPkt.szMsg[0] = 0; + + router_exdisplay_handler(&msgPkt); +END: + return count; +} + +static int synobios_read_proc_mesh_backhaul_type_open(struct inode *inode, struct file *file) +{ + return single_open(file, syno_mesh_eth_backhaul_type_read_command, NULL); +} + +static const struct file_operations synobios_proc_mesh_backhaul_type_fops = { + .owner = THIS_MODULE, + .open = synobios_read_proc_mesh_backhaul_type_open, + .write = syno_mesh_backhaul_type_write_command, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int start_syno_mesh_proc(void) +{ + static struct proc_dir_entry *syno_mesh_is_re; + syno_mesh_is_re = proc_create_data(SZ_MESH_IS_RE_NAME, 0600, proc_synobios_root, + &synobios_proc_mesh_is_re_fops, NULL); + static struct proc_dir_entry *syno_mesh_is_joining; + syno_mesh_is_joining = proc_create_data(SZ_MESH_IS_JOINING_NAME, 0600, proc_synobios_root, + &synobios_proc_mesh_is_joining_fops, NULL); + static struct proc_dir_entry *syno_mesh_signal_quality; + syno_mesh_signal_quality = proc_create_data(SZ_MESH_SIGNAL_QUALITY_NAME, 0600, proc_synobios_root, + &synobios_proc_mesh_signal_quality_fops, NULL); + static struct proc_dir_entry *syno_mesh_heartbeat_alive; + syno_mesh_heartbeat_alive = proc_create_data(SZ_MESH_HEARTBEAT_ALIVE_NAME, 0600, proc_synobios_root, + &synobios_read_proc_mesh_heartbeat_alive_fops, NULL); + static struct proc_dir_entry *syno_mesh_backhaul_type; + syno_mesh_backhaul_type = proc_create_data(SZ_MESH_BACKHAUL_TYPE_NAME, 0600, proc_synobios_root, + &synobios_proc_mesh_backhaul_type_fops, NULL); + return 0; +} + +int remove_syno_mesh_proc(void) +{ + remove_proc_entry(SZ_MESH_BACKHAUL_TYPE_NAME, proc_synobios_root); + remove_proc_entry(SZ_MESH_HEARTBEAT_ALIVE_NAME, proc_synobios_root); + remove_proc_entry(SZ_MESH_SIGNAL_QUALITY_NAME, proc_synobios_root); + remove_proc_entry(SZ_MESH_IS_JOINING_NAME, proc_synobios_root); + remove_proc_entry(SZ_MESH_IS_RE_NAME, proc_synobios_root); + return 0; +} diff --git a/drivers/syno/synobios/mesh/mesh.h b/drivers/syno/synobios/mesh/mesh.h new file mode 100644 index 000000000000..cf4c3bb5854b --- /dev/null +++ b/drivers/syno/synobios/mesh/mesh.h @@ -0,0 +1,21 @@ +#ifndef _MESH_SYSTEM_H +#define _MESH_SYSTEM_H +#include +#include +#include +#include /* printk() */ +#include +#define SZ_MESH_IS_RE_NAME "syno_mesh_is_re" +#define SZ_MESH_IS_JOINING_NAME "syno_mesh_is_joining" +#define SZ_MESH_SIGNAL_QUALITY_NAME "syno_mesh_signal_quality" +#define SZ_MESH_HEARTBEAT_ALIVE_NAME "syno_mesh_heartbeat_alive" +#define SZ_MESH_BACKHAUL_TYPE_NAME "syno_mesh_backhaul_type" +int start_syno_mesh_proc(void); +int remove_syno_mesh_proc(void); +typedef enum { + MESH_BACKHAUL_TYPE_NONE, + MESH_BACKHAUL_TYPE_WIRED, + MESH_BACKHAUL_TYPE_WIRELESS, +} SYNO_MESH_BACKHAUL_TYPE; + +#endif /* _MESH_SYSTEM_H */ diff --git a/drivers/syno/synobios/monaco/Makefile b/drivers/syno/synobios/monaco/Makefile new file mode 100644 index 000000000000..293521188476 --- /dev/null +++ b/drivers/syno/synobios/monaco/Makefile @@ -0,0 +1,22 @@ +ifeq ($(SYNO_PLATFORM),STM_MONACO) +obj-m += ds216play-synobios.o +endif + +common-obj += \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-ricoh-lib.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-ricoh.o \ + ../rtc/rtc-linux-seiko.o \ + ../mapping.o \ + monaco_common.o + +fan-pwm-obj += fan-pwm.o +fan-resistor-obj += fan-resistor.o + +ds216play-synobios-objs = ds216play.o $(fan-resistor-obj) $(common-obj) diff --git a/drivers/syno/synobios/monaco/ds216play.c b/drivers/syno/synobios/monaco/ds216play.c new file mode 100755 index 000000000000..a88598f36efb --- /dev/null +++ b/drivers/syno/synobios/monaco/ds216play.c @@ -0,0 +1,102 @@ +/* Copyright (c) 2000-2016 Synology Inc. All rights reserved. */ + +#include /* printk() */ +#include /* error codes */ +#include +#include "../i2c/i2c-linux.h" +#include "monaco_common.h" + +void SYNO_ENABLE_HDD_LED(int blEnable); +void SYNO_ENABLE_PHY_LED(int blEnable); + +int GetModel(void) +{ + return MODEL_DS216play; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + cpu->core = 2; + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1500); +} + +int +InitModuleType(struct synobios_ops *ops) +{ + module_t type = MODULE_T_DS216play; + module_t *pType = NULL; + + pType = &type; + + module_type_set(pType); + + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + return 0; +} + +int SetAlarmLed(unsigned char type) +{ + return 0; +} + +int GetBackPlaneStatus(BACKPLANE_STATUS *pStatus) +{ + return 0; +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + switch(ledStatus) { + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + default: + printk("Invalid PHY LED status [%d]\n", ledStatus); + return -EFAULT; + } + return 0; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + SYNO_ENABLE_HDD_LED((SYNO_LED_ON == ledStatus)? ENABLE : DISABLE); + return 0; +} + +int model_addon_init(struct synobios_ops *ops) +{ + ops->set_phy_led = SetPhyLed; + ops->set_disk_led = SetDiskLedStatusByI2CLedDimmer; + SetupDiskLedMap((int[2]){0,2}, (int[2]){1,3}, 2); + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} + +int ds216play_hdd_enable_gpio[2] = {112, 115}; + +SYNO_HWMON_SENSOR_TYPE ds216play_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +struct hwmon_sensor_list ds216play_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds216play_hdd_backplane_status, +}; \ No newline at end of file diff --git a/drivers/syno/synobios/monaco/fan-pwm.c b/drivers/syno/synobios/monaco/fan-pwm.c new file mode 100755 index 000000000000..e03595855ef8 --- /dev/null +++ b/drivers/syno/synobios/monaco/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include "synobios.h" +#include +#include "monaco_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/monaco/fan-resistor.c b/drivers/syno/synobios/monaco/fan-resistor.c new file mode 100644 index 000000000000..e15e113afbce --- /dev/null +++ b/drivers/syno/synobios/monaco/fan-resistor.c @@ -0,0 +1,36 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include "synobios.h" +#include +#include +#include + +#include "monaco_common.h" + +int +SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + case MODEL_DS414j: + case MODEL_DS415j: + if (FanStatusMappingType2(status, speed, &speed_value)) { + goto END; + } + break; + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (SYNO_CTRL_FAN_RESISTOR(speed_value)) { + goto END; + } + + res = 0; +END: + return res; + +} diff --git a/drivers/syno/synobios/monaco/monaco_common.c b/drivers/syno/synobios/monaco/monaco_common.c new file mode 100755 index 000000000000..68b10dde3724 --- /dev/null +++ b/drivers/syno/synobios/monaco/monaco_common.c @@ -0,0 +1,334 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "synobios.h" +#include +#include +#include "../mapping.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "monaco_common.h" + +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); +unsigned long int syno_get_temperature(void); +void SYNO_ENABLE_HDD_LED(int enable); + +#define MAX_ENABLE_PIN_NUM 2 +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static int *hdd_enable_gpio = NULL; + + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static int Uninitialize(void); + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gPWMSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gPWMSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int ret = -1; + unsigned long int temperature = 0; + int cpu_temperature = 0; + + if (!pCPUTemp) { + goto END; + } + + temperature = syno_get_temperature(); + do_div(temperature, 1000); + cpu_temperature = (int) temperature; + + if (cpu_temperature < 0) + cpu_temperature = 0; + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = cpu_temperature - 5; + + ret = 0; +END: + return ret; +} + +#ifdef MY_DEF_HERE +extern void syno_sata_mv_gpio_write(u8 blFaulty, const unsigned short hostnum); +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status) +{ + int err = -1; + + if (1 > disknum) { + goto END; + } + + /*Scsi host in kernel is zero-based, disknum here is one-based, + *so we should minus 1 while calling the function + */ + if (DISK_LED_ORANGE_BLINK == status || DISK_LED_ORANGE_SOLID == status){ + syno_sata_mv_gpio_write( 1, disknum - 1); + }else{ + syno_sata_mv_gpio_write( 0, disknum - 1); + } + + err = 0; +END: + return err; +} +#endif /* MY_DEF_HERE */ + +int SetPowerLedStatus(SYNO_LED status) +{ + return 0; +} + +int GetMemByte( MEMORY_BYTE *pMemory ) +{ + return 0; +} + +static int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return 0; +} + +/* + * Setup the global Disk LED mapping for sata driver + */ +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum) +{ + if(NULL == pGreenLed || NULL == pOrangeLed || 8 < iInternalDiskNum){ + return; + } + + /* allocate and initialize disk led mapping*/ + gpGreenLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + gpOrangeLedMap = (int*)kmalloc(8 * sizeof(int), GFP_KERNEL); + memset(gpGreenLedMap, -1, 8 * sizeof(int)); + memset(gpOrangeLedMap, -1, 8 * sizeof(int)); + + memcpy(gpGreenLedMap, pGreenLed, iInternalDiskNum * sizeof(int)); + memcpy(gpOrangeLedMap, pOrangeLed, iInternalDiskNum * sizeof(int)); + +} +int SetDiskLedStatusByI2CLedDimmer(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + enum led_brightness LEDGreen, LEDOrange; + static int diskLedEnabled = 0; + + /* first time we tried to light on disk led */ + if (!diskLedEnabled && DISK_LED_OFF != iStatus) { + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if (0 >= iDiskNum || 8 < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (NULL == gpGreenLedMap || NULL == gpOrangeLedMap){ + printk("Disk LED not mapped\n"); + goto END; + } + + switch(iStatus) { + case DISK_LED_ORANGE_BLINK: + case DISK_LED_ORANGE_SOLID: + LEDOrange = LED_FULL; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_FAULTY); //disable the disk activity led trigger + break; + case DISK_LED_GREEN_BLINK: + LEDOrange = LED_OFF; + LEDGreen = LED_HALF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_GREEN_SOLID: + LEDOrange = LED_OFF; + LEDGreen = LED_FULL; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + case DISK_LED_OFF: + LEDOrange = LED_OFF; + LEDGreen = LED_OFF; + syno_ledtrig_faulty_set(gpGreenLedMap[iDiskNum-1], LED_NORMAL); + break; + default: + printk("Invalid LED status [%d]\n", iStatus); + goto END; + } + + syno_ledtrig_set(gpGreenLedMap[iDiskNum-1], LEDGreen); + syno_ledtrig_set(gpOrangeLedMap[iDiskNum-1], LEDOrange); + + iRet = 0; +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + GPIO_PIN pPin; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list || NULL == hdd_enable_gpio) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < MAX_ENABLE_PIN_NUM; index++){ + if (NULL != hdd_enable_gpio) { + if (-1 == hdd_enable_gpio[index]) { + break; + } + pPin.pin = hdd_enable_gpio[index]; + GetGpioPin(&pPin); + hdd_enable |= (pPin.value & 0x01) << index; + } + } + + if (NULL != hdd_enable_gpio) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; + +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = SetPowerLedStatus, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .set_alarm_led = SetAlarmLed, + .get_backplane_status = GetBackPlaneStatus, + .get_mem_byte = GetMemByte, + .get_buzzer_cleared = GetBuzzerCleared, + .set_phy_led = NULL, + .set_hdd_led = SetHDDActLed, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +/* Unlike a38x and alpine, monaco init its gpio in kernel */ +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + if( pSynoModule && RTC_SEIKO == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = rtc_seiko_get_time; + synobios_ops.set_rtc_time = rtc_seiko_set_time; + synobios_ops.get_auto_poweron = rtc_get_auto_poweron; + synobios_ops.set_auto_poweron = rtc_seiko_set_auto_poweron; + synobios_ops.init_auto_poweron = rtc_seiko_auto_poweron_init; + synobios_ops.uninit_auto_poweron = rtc_seiko_auto_poweron_uninit; + } + if( pSynoModule && RTC_MV == pSynoModule->rtc_type ) { + synobios_ops.get_rtc_time = NULL; + synobios_ops.set_rtc_time = NULL; + synobios_ops.get_auto_poweron = NULL; + synobios_ops.set_auto_poweron = NULL; + synobios_ops.init_auto_poweron = NULL; + synobios_ops.uninit_auto_poweron = NULL; + } + + switch (GetModel()) { + case MODEL_DS216play: + hwmon_sensor_list = &ds216play_sensor_list; + hdd_enable_gpio = ds216play_hdd_enable_gpio; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + break; + default: + hwmon_sensor_list = NULL; + hdd_enable_gpio = NULL; + synobios_ops.hwmon_get_backplane_status = NULL; + break; + } + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + return 0; +} + +static int Uninitialize(void) +{ + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + model_addon_cleanup(*ops); + return 0; +} diff --git a/drivers/syno/synobios/monaco/monaco_common.h b/drivers/syno/synobios/monaco/monaco_common.h new file mode 100755 index 000000000000..e79275fbcf6d --- /dev/null +++ b/drivers/syno/synobios/monaco/monaco_common.h @@ -0,0 +1,71 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include "../mapping.h" +#include +#include +#include "../common/common.h" + +#define LED_NORMAL 0 +#define LED_FAULTY 1 +#define ENABLE 1 +#define DISABLE 0 + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetUsbDiskLedStatus(SYNO_DISK_LED status); +int SetPowerLedStatus(SYNO_LED status); +int GetFanStatus(int fanno, FAN_STATUS *pStatus); +int GetFanNum(int *pFanNum); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int SetAlarmLed(unsigned char type); +int GetBackPlaneStatus(BACKPLANE_STATUS *pStatus); +int GetFanSpeedBits(int start, int end, MEMORY_BYTE *pMemory); +int GetMemByte( MEMORY_BYTE *pMemory ); +int InitModuleType(struct synobios_ops *ops); +int FanStatusMappingRS409r1(FAN_STATUS status, FAN_SPEED speed, char *pSpeed_value); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int PWMFanSpeedMapping(FAN_SPEED speed); +int SetPhyLed(SYNO_LED ledStatus); +int SetHDDActLed(SYNO_LED ledStatus); +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +extern int SynoArmadaSetPhyLed(SYNO_LED); +#ifdef MY_DEF_HERE +int SetDiskLedStatusBySataMvGPIO(int disknum, SYNO_DISK_LED status); +#endif +extern int axptemp_read_temp(void); +extern void SYNO_GPIO_SET_FALLING_EDGE(int gpio); +extern void SYNO_GPIO_SET_RISING_EDGE(int gpio); +#ifdef MY_DEF_HERE +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +extern int syno_mv_9235_disk_led_get(const unsigned short hostnum); +#endif +extern void syno_ledtrig_set(int iLedNum, enum led_brightness brightness); +extern void syno_ledtrig_faulty_set(int iLedNum, int iFaulty); +extern int *gpGreenLedMap, *gpOrangeLedMap; +int SetDiskLedStatusByI2CLedDimmer(int iDiskNum, SYNO_DISK_LED iStatus); +int SYNOSetDiskLedStatusByI2CLedDimmer(int iHostNum, SYNO_DISK_LED iStatus); +void SetupDiskLedMap(const int *pGreenLed, const int *pOrangeLed, unsigned int iInternalDiskNum); + +extern struct hwmon_sensor_list ds216play_sensor_list; + +extern int ds216play_hdd_enable_gpio[2]; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; \ No newline at end of file diff --git a/drivers/syno/synobios/nextkvmx64/Makefile b/drivers/syno/synobios/nextkvmx64/Makefile new file mode 100644 index 000000000000..75d4ae93a1af --- /dev/null +++ b/drivers/syno/synobios/nextkvmx64/Makefile @@ -0,0 +1,8 @@ +include /env.mak + +obj-m += nextkvmx64-synobios.o + +nextkvmx64-synobios-objs = \ + $(vdsm-common-obj) \ + nextvirtualdsm.o \ + nextkvmx64_common.o diff --git a/drivers/syno/synobios/nextkvmx64/nextkvmx64_common.c b/drivers/syno/synobios/nextkvmx64/nextkvmx64_common.c new file mode 100755 index 000000000000..955d42c91f0d --- /dev/null +++ b/drivers/syno/synobios/nextkvmx64/nextkvmx64_common.c @@ -0,0 +1,286 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../rtc/rtc.h" +#include "nextkvmx64_common.h" + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = -1; + + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = -1; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL + *buzzer_cleared = gSynoBuzzerMutePressed; + gSynoBuzzerMutePressed = 0; + ret = 0; +#endif + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int Nextkvmx64RedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + + static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + + static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + + static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_VirtualDSM; + + if (!strncmp(gszSynoHWVersion, HW_C2DSM, strlen(HW_C2DSM))) { + model = MODEL_C2DSM; + } + return model; +} + + static +int GetBrand(void) +{ + return BRAND_SYNOLOGY; +} + + static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +int SetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + +int GetGpioPin( GPIO_PIN *pPin ) +{ + int ret = -1; + + return ret; +} + + static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + + static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) + iRet = syno_cpu_temperature(pCpuTemp); +#endif /*MY_DEF_HERE*/ + + if( 0 != iRet) { + goto END; + } + + if( 1 == pCpuTemp->blSurface) { + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = (pCpuTemp->cpu_temp[iCPUIdx] * 1000 - 19682) / 1000; + + if(40 > pCpuTemp->cpu_temp[iCPUIdx]) { + pCpuTemp->cpu_temp[iCPUIdx] = 40; + } + } + } +END: + return iRet; +} + + static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + + static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + + static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatusMircopWithGPIO, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_VirtualDSM: + model_ops = &virtualdsm_ops; + break; + /* TODO */ + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/nextkvmx64/nextkvmx64_common.h b/drivers/syno/synobios/nextkvmx64/nextkvmx64_common.h new file mode 100755 index 000000000000..7c8b88758794 --- /dev/null +++ b/drivers/syno/synobios/nextkvmx64/nextkvmx64_common.h @@ -0,0 +1,43 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops virtualdsm_ops; + +extern int syno_ttys_write(const int index, const char* szBuf); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_X86_CORETEMP) +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /*MY_DEF_HERE*/ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +#define UART_TTYS_INDEX 1 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/nextkvmx64/nextvirtualdsm.c b/drivers/syno/synobios/nextkvmx64/nextvirtualdsm.c new file mode 100644 index 000000000000..e4828291ecb0 --- /dev/null +++ b/drivers/syno/synobios/nextkvmx64/nextvirtualdsm.c @@ -0,0 +1,32 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "nextkvmx64_common.h" + +// extern function from bromolow_common +extern int Nextkvmx64RedundantPowerGetPowerStatus(POWER_INFO *power_info); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); + + static +int VirtualDSMInitModuleType(struct synobios_ops *ops) +{ + module_t type_virtualdsm = MODULE_T_VirtualDSM; + module_t *pType = &type_virtualdsm; + + module_type_set(pType); + return 0; +} + +struct model_ops virtualdsm_ops = { + .x86_init_module_type = VirtualDSMInitModuleType, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = Nextkvmx64RedundantPowerGetPowerStatus, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/pmbus/pmbus.c b/drivers/syno/synobios/pmbus/pmbus.c new file mode 100644 index 000000000000..1b6ef673c665 --- /dev/null +++ b/drivers/syno/synobios/pmbus/pmbus.c @@ -0,0 +1,181 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#ifdef CONFIG_SYNO_HWMON_PMBUS +#include +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#include +#include "pmbus.h" +#include "../i2c/i2c-linux.h" + +int HWMONReadPmbusStatusReg(unsigned int adapter, unsigned int addr, unsigned int reg, char *SensorValue, int cValueSize) +{ + int iRet = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + err = linuxI2CSmbusRegRead(adapter, addr, reg, &data); + if (0 != err) { + if (uLostAddr != addr) { + uLostAddr = addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + iRet = 0; + goto END; + } + + if (uLostAddr == addr) { + uLostAddr = 0; + } + + //Pmbus use linear data format + // X = Y x 2^N + //– X is the real world value + //– Y = data[10:0], The mantissa is the variable components that changes as the sensor value changes. + // Y is a signed 11 bit 2’s complement integer + //– N = data[15:11], exponent is a signed 5 bit 2’s complement integer + // The exponents are fixed for each power supply and define the resolution for each sensor. + snprintf(SensorValue, cValueSize, "%04x", data); + + iRet = 0; + +END: + return iRet; +} + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int I2CPmbusReadPowerStatus(int index, SYNO_POWER_STATUS* status) +{ + int iRet = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + unsigned int uiPmbusAdapter = 0; + unsigned int uiPmbusAddress = 0; + unsigned int uiPmbusStatusReg = 0; + unsigned int uiPmbusPSUOffBit = 0; + unsigned int uiPmbusPSUPresentBit = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + // get pmbus properties from fdt + if (0 > syno_pmbus_property_get(&uiPmbusAdapter, DT_SYNO_PMBUS_ADAPTER, index)) { + printk("Failed to get PMBus Adapter %d from fdt\n", index); + goto END; + } + if (0 > syno_pmbus_property_get(&uiPmbusAddress, DT_SYNO_PMBUS_ADDRESS, index)) { + printk("Failed to get PMBus Address %d from fdt\n", index); + goto END; + } + if (0 > syno_pmbus_property_get(&uiPmbusStatusReg, DT_SYNO_PMBUS_STATUS_REG, index)) { + printk("Failed to get PMBus Status Register %d from fdt\n", index); + goto END; + } + if (0 > syno_pmbus_property_get(&uiPmbusPSUOffBit, DT_SYNO_PMBUS_PSU_OFF_BIT, index)) { + printk("Failed to get PMBus Power Good bit %d from fdt\n", index); + goto END; + } + if (0 > syno_pmbus_property_get(&uiPmbusPSUPresentBit, DT_SYNO_PMBUS_PSU_PRESENT_BIT, index)) { + printk("Failed to get PMBus Power Present bit %d from fdt\n", index); + goto END; + } + + err = linuxI2CSmbusRegRead(uiPmbusAdapter, uiPmbusAddress, uiPmbusStatusReg, &data); + if (0 != err) { + if (uLostAddr != uiPmbusAddress) { + uLostAddr = uiPmbusAddress; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + iRet = 0; + goto END; + } + if (uLostAddr == uiPmbusAddress) { + uLostAddr = 0; + } + + if ((data & uiPmbusPSUOffBit) || (uiPmbusPSUPresentBit && !(data & uiPmbusPSUPresentBit))) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + iRet = 0; + +END: + return iRet; +} + +int HWMONGetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + int i = 0, j = 0; + unsigned int uiPmbusAdapter = UINT_MAX; + unsigned int uiPmbusAddress = UINT_MAX; + unsigned int uiPmbusRegister = UINT_MAX; + SYNO_POWER_STATUS PowerStatus = POWER_STATUS_BAD; + char szPsuType[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {0}; + + if (NULL == psu_status || 0 >= iPsuNumber) { + goto END; + } + + for (i = 0; i < iPsuNumber; i++) { + // get pmbus properties from fdt + if (0 > syno_pmbus_property_get(&uiPmbusAdapter, DT_SYNO_PMBUS_ADAPTER, i) || UINT_MAX == uiPmbusAdapter) { + printk("Failed to get PMBus Adapter %d from fdt\n", i); + goto END; + } + if (0 > syno_pmbus_property_get(&uiPmbusAddress, DT_SYNO_PMBUS_ADDRESS, i) || UINT_MAX == uiPmbusAddress) { + printk("Failed to get PMBus Address %d from fdt\n", i); + goto END; + } + for (j = 0; j < psu_status[i].sensor_num; j++) { + if (0 == strcmp(HWMON_PSU_SENSOR_STATUS, psu_status[i].sensor[j].sensor_name)) { + if (0 > I2CPmbusReadPowerStatus(i, &PowerStatus)) { + printk("Failed to get PMBus %d power status\n", i); + continue; + } + snprintf(psu_status[i].sensor[j].value, MAX_SENSOR_VALUE, "%s", (POWER_STATUS_BAD == PowerStatus)?"psu off":"psu good"); + } else { + if (0 == strcmp(HWMON_PSU_SENSOR_PIN, psu_status[i].sensor[j].sensor_name)) { + snprintf(szPsuType, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s", DT_SYNO_PMBUS_PIN_REG); + } else if (0 == strcmp(HWMON_PSU_SENSOR_POUT, psu_status[i].sensor[j].sensor_name)) { + snprintf(szPsuType, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s", DT_SYNO_PMBUS_POUT_REG); + } else if (0 == strcmp(HWMON_PSU_SENSOR_TEMP1, psu_status[i].sensor[j].sensor_name)) { + snprintf(szPsuType, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s", DT_SYNO_PMBUS_TEMP1_REG); + } else if (0 == strcmp(HWMON_PSU_SENSOR_TEMP2, psu_status[i].sensor[j].sensor_name)) { + snprintf(szPsuType, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s", DT_SYNO_PMBUS_TEMP2_REG); + } else if (0 == strcmp(HWMON_PSU_SENSOR_TEMP3, psu_status[i].sensor[j].sensor_name)) { + snprintf(szPsuType, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s", DT_SYNO_PMBUS_TEMP3_REG); + } else if (0 == strcmp(HWMON_PSU_SENSOR_FAN, psu_status[i].sensor[j].sensor_name) || + 0 == strcmp(HWMON_PSU_SENSOR_FAN_VOLT, psu_status[i].sensor[j].sensor_name)) { + snprintf(szPsuType, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s", DT_SYNO_PMBUS_FAN_REG); + } else { + printk("Failed to match PMBus %d sensor name : %s\n", i, psu_status[i].sensor[j].sensor_name); + continue; + } + if (0 > syno_pmbus_property_get(&uiPmbusRegister, szPsuType, i) || UINT_MAX == uiPmbusRegister) { + printk("Failed to get PMBus %d Register %s from fdt\n", i, szPsuType); + continue; + } + if (0 > HWMONReadPmbusStatusReg(uiPmbusAdapter, uiPmbusAddress, uiPmbusRegister, psu_status[i].sensor[j].value, MAX_SENSOR_VALUE)) { + printk("Failed to read PMBus Status Register 0x%x\n", uiPmbusRegister); + continue; + } + } + } + } + + iRet = 0; +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ diff --git a/drivers/syno/synobios/pmbus/pmbus.h b/drivers/syno/synobios/pmbus/pmbus.h new file mode 100644 index 000000000000..1c8407b4f6e4 --- /dev/null +++ b/drivers/syno/synobios/pmbus/pmbus.h @@ -0,0 +1,6 @@ +#include "synobios.h" +int HWMONReadPmbusStatusReg(unsigned int adapter, unsigned int addr, unsigned int reg, char *SensorValue, int cValueSize); +#ifdef CONFIG_SYNO_HWMON_PMBUS +int I2CPmbusReadPowerStatus(int index, SYNO_POWER_STATUS* status); +int HWMONGetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ diff --git a/drivers/syno/synobios/purley/Makefile b/drivers/syno/synobios/purley/Makefile new file mode 100644 index 000000000000..c7ee947b2b04 --- /dev/null +++ b/drivers/syno/synobios/purley/Makefile @@ -0,0 +1,23 @@ +include /env.mak + +obj-m += purley-synobios.o + +purley-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + fs6400.o \ + fs6500.o \ + sa6500.o \ + hd6500.o \ + fs6600n.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + purley_common.o \ + ../led/led_trigger.o \ + ../i2c/i2c-linux.o \ + ../led/led_gpio.o \ + ../switchtec/switchtec.o \ + ../pmbus/pmbus.o diff --git a/drivers/syno/synobios/purley/fs6400.c b/drivers/syno/synobios/purley/fs6400.c new file mode 100644 index 000000000000..f34f5ea295ad --- /dev/null +++ b/drivers/syno/synobios/purley/fs6400.c @@ -0,0 +1,122 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "purley_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from purley_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int FS6400I2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +SYNO_HWMON_SENSOR_TYPE FS6400_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6400_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +int FS6400InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs6400 = MODULE_T_FS6400; + module_t *pType = &type_fs6400; + + module_type_set(pType); + return 0; +} + +struct model_ops fs6400_ops = { + .x86_init_module_type = FS6400InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = FS6400I2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +struct hwmon_sensor_list fs6400_sensor_list = { + .thermal_sensor = &FS6400_thermal_sensor, + .voltage_sensor = &FS6400_voltage_sensor, + .fan_speed_rpm = &FS6400_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/purley/fs6500.c b/drivers/syno/synobios/purley/fs6500.c new file mode 100755 index 000000000000..c14eb0a5ffa9 --- /dev/null +++ b/drivers/syno/synobios/purley/fs6500.c @@ -0,0 +1,123 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "purley_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from purley_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int FS6500I2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + + +int FS6500InitModuleType(struct synobios_ops *ops) +{ + module_t type_fs6500 = MODULE_T_FS6500; + module_t *pType = &type_fs6500; + + module_type_set(pType); + return 0; +} + +struct model_ops fs6500_ops = { + .x86_init_module_type = FS6500InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = FS6500I2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; +SYNO_HWMON_SENSOR_TYPE FS6500_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6500_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6500_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + + +struct hwmon_sensor_list fs6500_sensor_list = { + .thermal_sensor = &FS6500_thermal_sensor, + .voltage_sensor = &FS6500_voltage_sensor, + .fan_speed_rpm = &FS6500_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/purley/fs6600n.c b/drivers/syno/synobios/purley/fs6600n.c new file mode 100644 index 000000000000..ed9b6fa4e748 --- /dev/null +++ b/drivers/syno/synobios/purley/fs6600n.c @@ -0,0 +1,177 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "purley_common.h" +#include "../i2c/i2c-linux.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from purley_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int FS6600NI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +int FS6600NInitModuleType(struct synobios_ops *ops) +{ + module_t type_fs6600n = MODULE_T_FS6600N; + module_t *pType = &type_fs6600n; + + module_type_set(pType); + return 0; +} + +struct model_ops fs6600n_ops = { + .x86_init_module_type = FS6600NInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = FS6600NI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600N_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600N_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600N_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS6600N_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2 + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3 + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2 + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3 + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +struct hwmon_sensor_list fs6600n_sensor_list = { + .thermal_sensor = &FS6600N_thermal_sensor, + .voltage_sensor = &FS6600N_voltage_sensor, + .fan_speed_rpm = &FS6600N_fan_speed_rpm, + .psu_status = FS6600N_psu_status, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/purley/hd6500.c b/drivers/syno/synobios/purley/hd6500.c new file mode 100755 index 000000000000..04f36e6b3114 --- /dev/null +++ b/drivers/syno/synobios/purley/hd6500.c @@ -0,0 +1,195 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "purley_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x59 +#define PSU_BTM_I2C_ADDR 0x58 + +// extern function from purley_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static +int HD6500I2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +// GPP_H1 CPLD_LED_CTRL_N (No.216) for SystemDisk HDD LED mask & Pront Panel Status LED mask +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {PURLEY_CPLD_LED_CTRL_N}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void HD6500GpioInit(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void HD6500GpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +int HD6500InitModuleType(struct synobios_ops *ops) +{ + module_t type_hd6500 = MODULE_T_HD6500; + module_t *pType = &type_hd6500; + + module_type_set(pType); + return 0; +} + +struct model_ops hd6500_ops = { + .x86_init_module_type = HD6500InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = HD6500I2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, + .x86_gpio_init = HD6500GpioInit, + .x86_gpio_cleanup = HD6500GpioCleanup, +}; + +SYNO_HWMON_SENSOR_TYPE HD6500_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE HD6500_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE HD6500_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE HD6500_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 6, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2 + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 6, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2 + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; +struct hwmon_sensor_list hd6500_sensor_list = { + .thermal_sensor = &HD6500_thermal_sensor, + .voltage_sensor = &HD6500_voltage_sensor, + .fan_speed_rpm = &HD6500_fan_speed_rpm, + .psu_status = HD6500_psu_status, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/purley/purley_common.c b/drivers/syno/synobios/purley/purley_common.c new file mode 100755 index 000000000000..2c08513ac2d7 --- /dev/null +++ b/drivers/syno/synobios/purley/purley_common.c @@ -0,0 +1,651 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2009 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "purley_common.h" +#include "../led/led_gpio.h" +#include "../pmbus/pmbus.h" + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; + +#ifdef CONFIG_SYNO_XR17V35X_SERIAL +extern int gSynoBuzzerMutePressed; +#endif + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ +extern int SA6500GetDiskIntf(SYNO_DISK_INTF_INFO *input); + +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +// following functions are not chagned in any bromolow models, so we move them from model.o to here +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = PURLEY_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = PURLEY_BUZZER_OFF_BUTTON_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; + +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_FS6400: + case MODEL_FS6600N: + case MODEL_FS6500: + iInternalDiskNum = 24; + break; + case MODEL_SA6500: + iInternalDiskNum = 20; + break; + case MODEL_HD6500: + iInternalDiskNum = 60; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int PurleyRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +#ifdef CONFIG_SYNO_ADT7490_FEATURES +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + +static struct synobios_ops synobios_ops; +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + + switch(GetModel()) + { + case MODEL_FS6600N: + if (synobios_ops.set_hdd_led) { + synobios_ops.set_hdd_led (SYNO_LED_OFF); + } + break; + default: + break; + } + + return 0; +} + +int GetModel(void) +{ + int model = MODEL_FS6400; + + if (!strncmp(gszSynoHWVersion, HW_FS6400, strlen(HW_FS6400))) { + model = MODEL_FS6400; + } else if (!strncmp(gszSynoHWVersion, HW_FS6500, strlen(HW_FS6500))) { + model = MODEL_FS6500; + } else if (!strncmp(gszSynoHWVersion, HW_SA6500, strlen(HW_SA6500))) { + model = MODEL_SA6500; + } else if (!strncmp(gszSynoHWVersion, HW_HD6500, strlen(HW_HD6500))) { + model = MODEL_HD6500; + } else if (!strncmp(gszSynoHWVersion, HW_FS6600N, strlen(HW_FS6600N))) { + model = MODEL_FS6600N; + } + + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } +#ifdef CONFIG_SYNO_ADT7490_FEATURES + iRet = syno_get_adt_peci(pCpuTemp); +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + + if( 0 != iRet) { + goto END; + } + + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = pCpuTemp->cpu_temp[iCPUIdx] / 1000; + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = PURLEY_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + int iProcNum = 0; + int iCpuCore = 0; + int iCpuNum = 0; + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + memset(cpu->cpucore, 0, CONFIG_SYNO_MULTI_CPU_NUM * sizeof(unsigned int)); + for_each_online_cpu(iProcNum) { + if(iCpuNum < cpu_data(iProcNum).phys_proc_id + 1) { + cpu->cpucore[iCpuNum] = cpu_data(iProcNum).booted_cores; + iCpuNum++; + iCpuCore += cpu_data(iProcNum).booted_cores; + } + } + cpu->core = iCpuCore; + return ; + +} + +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +extern int (*syno_valid_lsi3008_led)(SYNO_LED ledStatus); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +extern int (*syno_valid_lsi3008_led)(u8 cmd); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +#endif /*CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL*/ + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int PurleyGetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + + if (NULL == hwmon_sensor_list) { + goto END; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + iRet = HWMONGetPSUStatusByI2C(psu_status, iPsuNumber); +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_FS6400: + model_ops = &fs6400_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led){ + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /*config_syno_sas_host_disk_led_ctrl*/ + hwmon_sensor_list = &fs6400_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + break; + case MODEL_FS6500: + model_ops = &fs6500_ops; +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led){ + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /*config_syno_sas_host_disk_led_ctrl*/ + hwmon_sensor_list = &fs6500_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + break; + case MODEL_SA6500: + model_ops = &sa6500_ops; + SA6500SMBusSwitchInit(); +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + if (NULL != syno_valid_lsi3008_led){ + synobios_ops.set_hdd_led = syno_valid_lsi3008_led; + } +#endif /*config_syno_sas_host_disk_led_ctrl*/ +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ + hwmon_sensor_list = &sa6500_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = PurleyGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.get_disk_intf = SA6500GetDiskIntf; + break; + case MODEL_HD6500: + model_ops = &hd6500_ops; + synobios_ops.set_disk_led = synoDiskLedControlByGpio; + hwmon_sensor_list = &hd6500_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = PurleyGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + if (model_ops->x86_gpio_init) { + model_ops->x86_gpio_init(); + } + synobios_ops.set_hdd_led = SetHddActLed; + break; + case MODEL_FS6600N: + model_ops = &fs6600n_ops; + hwmon_sensor_list = &fs6600n_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = PurleyGetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + if (0 == switchtec_init()) { + synobios_ops.set_hdd_led = switchtec_led_set; + synobios_ops.set_disk_led = switchtec_set_disk_led; + } + break; + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + switch(GetModel()) + { + case MODEL_FS6600N: + switchtec_deinit(); + break; + default: + break; + } + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} diff --git a/drivers/syno/synobios/purley/purley_common.h b/drivers/syno/synobios/purley/purley_common.h new file mode 100644 index 000000000000..f3426336550a --- /dev/null +++ b/drivers/syno/synobios/purley/purley_common.h @@ -0,0 +1,82 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#include "../common/common.h" +#include "../switchtec/switchtec.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops fs6400_ops; +extern struct model_ops fs6500_ops; +extern struct model_ops sa6500_ops; +extern struct model_ops hd6500_ops; +extern struct model_ops fs6600n_ops; + +#ifdef CONFIG_SYNO_ADT7490_FEATURES +extern int syno_get_adt_peci(struct _SynoCpuTemp *); +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ +extern void SA6500SMBusSwitchInit(void); +extern int SetDiskLedStatus(DISKLEDSTATUS*); +extern int SA6500GetHDDBackPlaneStatus(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane); + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list fs6400_sensor_list; +extern struct hwmon_sensor_list fs6500_sensor_list; +extern struct hwmon_sensor_list sa6500_sensor_list; +extern struct hwmon_sensor_list hd6500_sensor_list; +extern struct hwmon_sensor_list fs6600n_sensor_list; + +#define PURLEY_BUZZER_CTRL_PIN 113 //GPP_D17 (BUZZER_MUTE_BOT_PCH_GPO) +#define PURLEY_BUZZER_OFF_BUTTON_PIN 114 //GPP_D18 (BUZZER_MUTE signal from PSU to PCH) +#define PURLEY_ALARM_LED_PIN 223 //GPP_H8 (SYNO_ALERT_LED_CTRL_N) +#define PURLEY_CPLD_LED_CTRL_N 216 //GPP_H1 (No.216) for SystemDisk HDD LED mask & Pront Panel Status LED mask + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/purley/sa6500.c b/drivers/syno/synobios/purley/sa6500.c new file mode 100644 index 000000000000..8f8a05a86f58 --- /dev/null +++ b/drivers/syno/synobios/purley/sa6500.c @@ -0,0 +1,391 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "synobios.h" +#include "purley_common.h" +#include "../i2c/i2c-linux.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 +// there two types of interface in SA6500 (U.2 NVMe, SAS/SATA) +#define SA6500_INTF_NUM 2 +#define SA6500_U2_BOARD_UP_BUS 0 +#define SA6500_U2_BOARD_UP_I2C_ADDR 0x47 +#define INTF_ERR 1 + +// extern function from purley_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +/* FIXME: should not directly copy following function + * Modified from drivers/i2c/muxes/i2c-mux-pca954x.c */ +int SA6500SMBusSwitchRegWrite(int bus_no, u16 addr, u8 val) +{ + int ret = -1; + struct i2c_adapter *adap = NULL; + + adap = i2c_get_adapter(bus_no); + if (!adap) { + printk("Cannot get i2c adapter!\n"); + goto END; + } + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, addr, + 0, I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } +END: + return ret; +} + +void SA6500SMBusSwitchInit(void) { + SA6500SMBusSwitchRegWrite(0, 0x71, 4); + SA6500SMBusSwitchRegWrite(0, 0x72, 1); +} + +static +int SA6500I2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +int SA6500InitModuleType(struct synobios_ops *ops) +{ + module_t type_sa6500 = MODULE_T_SA6500; + module_t *pType = &type_sa6500; + + module_type_set(pType); + return 0; +} + +typedef enum { + SYNO_U2_NVME, + SYNO_SAS_SATA, + SYNO_NO_DISK, +} SYNO_DISK_INTF_ENUM; + +/* DevPresent: 0 disk present, 1 no disk present + * IntfDetect: 0 SAS/SATA, 1, U.2 NVMe */ +static int ToDiskIntf(u8 InfDet, u8 DevPre) +{ + int ret = SYNO_NO_DISK; + + if (DevPre) { + goto END; + } + + ret = (InfDet) ? SYNO_U2_NVME : SYNO_SAS_SATA; +END: + return ret; +} +static char* ToDiskIntfStr[3] = {"U.2 NVMe", "SAS/SATA", "nodisk"}; + +#if defined(CONFIG_SYNO_LP3943_FEATURES) || defined(CONFIG_SYNO_LEDS_LP3943_FEATURES) +extern void SYNOLP3943I2CMutex (bool lock); +#endif /* CONFIG_SYNO_LP3943_FEATURES || CONFIG_SYNO_LEDS_LP3943_FEATURES */ + +static int SA6500GetDiskStatus(u8* IntfDetect, u8* DevPresent, u8* DevEnabled) +{ + int ret = -1; + u16 data = 0xffff; + + /* According to HW spec + * 0x0A, 0x0B, 0x0C is port 8-1, 16-9, 24-17 interface detect + * 0x0D, 0x0E, 0x0F is port 8-1, 16-9, 24-17 device present + * 0x1D, 0x1E, 0x1F is port 8-1, 16-9, 24-17 device enabled + * */ + +#if defined(CONFIG_SYNO_LP3943_FEATURES) || defined(CONFIG_SYNO_LEDS_LP3943_FEATURES) + SYNOLP3943I2CMutex (true); +#endif /* CONFIG_SYNO_LP3943_FEATURES || CONFIG_SYNO_LEDS_LP3943_FEATURES */ + SA6500SMBusSwitchRegWrite(0, 0x72, 3); + if (0 != linuxI2CSmbusRegRead(SA6500_U2_BOARD_UP_BUS, SA6500_U2_BOARD_UP_I2C_ADDR, 0xa, &data)) { + printk("%s: linuxI2CSmbusRegRead 0xA return error!\n", __FILE__); + goto END; + } + + IntfDetect[0] = data & 0xff; + IntfDetect[1] = (data & 0xff00) >> 8; + + if (0 != linuxI2CSmbusRegRead(SA6500_U2_BOARD_UP_BUS, SA6500_U2_BOARD_UP_I2C_ADDR, 0xc, &data)) { + printk("%s: linuxI2CSmbusRegRead 0xC return error!\n", __FILE__); + goto END; + } + + IntfDetect[2] = data & 0xf; + DevPresent[0] = (data & 0xff00) >> 8; + + if (0 != linuxI2CSmbusRegRead(SA6500_U2_BOARD_UP_BUS, SA6500_U2_BOARD_UP_I2C_ADDR, 0xe, &data)) { + printk("%s: linuxI2CSmbusRegRead 0xE return error!\n", __FILE__); + goto END; + } + + DevPresent[1] = data & 0xff; + DevPresent[2] = (data & 0xf00) >> 8; + + if (NULL == DevEnabled) { + ret = 0; + goto END; + } + + if (0 != linuxI2CSmbusRegRead(SA6500_U2_BOARD_UP_BUS, SA6500_U2_BOARD_UP_I2C_ADDR, 0x1d, &data)) { + printk("%s: linuxI2CSmbusRegRead 0x1D return error!\n", __FILE__); + goto END; + } + + DevEnabled[0] = data & 0xff; + DevEnabled[1] = (data & 0xff00) >> 8; + + if (0 != linuxI2CSmbusRegRead(SA6500_U2_BOARD_UP_BUS, SA6500_U2_BOARD_UP_I2C_ADDR, 0x1f, &data)) { + printk("%s: linuxI2CSmbusRegRead 0x1F return error!\n", __FILE__); + goto END; + } + + DevEnabled[2] = data & 0xf; + + ret = 0; +END: + SA6500SMBusSwitchRegWrite(0, 0x72, 1); +#if defined(CONFIG_SYNO_LP3943_FEATURES) || defined(CONFIG_SYNO_LEDS_LP3943_FEATURES) + SYNOLP3943I2CMutex (false); +#endif /* CONFIG_SYNO_LP3943_FEATURES || CONFIG_SYNO_LEDS_LP3943_FEATURES */ + return ret; +} + +int SA6500GetDiskIntf(SYNO_DISK_INTF_INFO *input) +{ + int i; + int ret = -1; + u8 IntfDetect[3], DevPresent[3]; + // helper array to convert number 0-7 to corresponding bit + static u8 mask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; + + if (0 != SA6500GetDiskStatus(IntfDetect, DevPresent, NULL)) { + printk("%s: SA6500GetDiskStatus return error!\n", __FILE__); + goto END; + } + + // zero out input + memset(input, 0, sizeof(SYNO_DISK_INTF_INFO)); + + input->intf_num = SA6500_INTF_NUM; + + // copy the interface string to return structure + snprintf(input->disk_intf[SYNO_U2_NVME].intf_name, MAX_DISK_INTF_LEN, "%s", ToDiskIntfStr[SYNO_U2_NVME]); + snprintf(input->disk_intf[SYNO_SAS_SATA].intf_name, MAX_DISK_INTF_LEN, "%s", ToDiskIntfStr[SYNO_SAS_SATA]); + + /* slot 1-4 is U.2 NVMe and located in bit 16-19 + first four bit in IntfDetect[2], DevPresent[2] */ + for (i = 0; i < 4; ++i) { + int disk_intf = ToDiskIntf(IntfDetect[2]&mask[i], DevPresent[2]&mask[i]); + /* interface is correct or there is no disk, no need to do anything */ + if (disk_intf == SYNO_U2_NVME || disk_intf == SYNO_NO_DISK) { + continue; + } + input->disk_intf[SYNO_U2_NVME].disk_list[i] = INTF_ERR; + } + + /* slot 5-20 is SAS/SATA and located in bit 0-15 + IntfDetect[0, 1], DevPresent[0, 1] */ + for (i = 0; i < 16; ++i) { + int disk_intf = ToDiskIntf(IntfDetect[i/8]&mask[i%8], DevPresent[i/8]&mask[i%8]); + /* interface is correct or there is no disk, no need to do anything */ + if (disk_intf == SYNO_SAS_SATA || disk_intf == SYNO_NO_DISK) { + continue; + } + input->disk_intf[SYNO_SAS_SATA].disk_list[i+4] = INTF_ERR; + } + ret = 0; +END: + return ret; +} + +int SA6500GetHDDBackPlaneStatus(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + unsigned long hdd_intf = 0; + u8 DevEnabled[3], DevPresent[3], IntfDetect[3]; + struct hwmon_sensor_list *hwmon_sensor_list = &sa6500_sensor_list; + + if (NULL == hdd_backplane) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + if (0 != SA6500GetDiskStatus(IntfDetect, DevPresent, DevEnabled)) { + printk("%s: SA6500GetDiskStatus return error!\n", __FILE__); + goto End; + } + + hdd_detect = (DevPresent[1] << 12) | (DevPresent[0] << 4) | DevPresent[2]; + hdd_enable = (DevEnabled[1] << 12) | (DevEnabled[0] << 4) | DevEnabled[2]; + hdd_intf = (IntfDetect[1] << 12) | (IntfDetect[0] << 4) | IntfDetect[2]; + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%05x", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%05x", hdd_enable); + snprintf(hdd_backplane->sensor[2].value, sizeof(hdd_backplane->sensor[2].value), "%05x", hdd_intf); + + iRet = 0; + +End: + return iRet; +} + +struct model_ops sa6500_ops = { + .x86_init_module_type = SA6500InitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = SA6500I2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; + +SYNO_HWMON_SENSOR_TYPE SA6500_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6500_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6500_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SA6500_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 6, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2 + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 6, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2 + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +struct hwmon_sensor_list sa6500_sensor_list = { + .thermal_sensor = &SA6500_thermal_sensor, + .voltage_sensor = &SA6500_voltage_sensor, + .fan_speed_rpm = &SA6500_fan_speed_rpm, + .psu_status = SA6500_psu_status, + .hdd_backplane = NULL, +}; diff --git a/drivers/syno/synobios/r1000/Makefile b/drivers/syno/synobios/r1000/Makefile new file mode 100644 index 000000000000..a88170e2839b --- /dev/null +++ b/drivers/syno/synobios/r1000/Makefile @@ -0,0 +1,20 @@ +include /env.mak + +obj-m += r1000-synobios.o + +r1000-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds723p.o \ + ds923p.o \ + rs422p.o \ + ds1522p.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + r1000_common.o \ + ../led/led_trigger.o diff --git a/drivers/syno/synobios/r1000/ds1522p.c b/drivers/syno/synobios/r1000/ds1522p.c new file mode 100644 index 000000000000..b91c25937b55 --- /dev/null +++ b/drivers/syno/synobios/r1000/ds1522p.c @@ -0,0 +1,107 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "r1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS1522pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {68, 69}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1522pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS1522pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds1522p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds1522p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS1522pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1522p = MODULE_T_DS1522p; + module_t *pType = &type_1522p; + + module_type_set(pType); + return 0; +} + +static +int DS1522pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1522pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1522pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1522pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1522p_ops = { + .x86_init_module_type = DS1522pInitModuleType, + .x86_fan_speed_mapping = DS1522pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1522pGpioInit, + .x86_gpio_cleanup = DS1522pGpioCleanup, +}; + +struct hwmon_sensor_list ds1522p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds1522p_hdd_backplane_status, + .current_sensor = &ds1522p_current_status, +}; diff --git a/drivers/syno/synobios/r1000/ds723p.c b/drivers/syno/synobios/r1000/ds723p.c new file mode 100644 index 000000000000..9f2e37602f11 --- /dev/null +++ b/drivers/syno/synobios/r1000/ds723p.c @@ -0,0 +1,101 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "r1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS723pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static +void DS723pGpioInit(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS723pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds723p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds723p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS723pInitModuleType(struct synobios_ops *ops) +{ + module_t type_723p = MODULE_T_DS723p; + module_t *pType = &type_723p; + + module_type_set(pType); + return 0; +} + +static +int DS723pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS723pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS723pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS723pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds723p_ops = { + .x86_init_module_type = DS723pInitModuleType, + .x86_fan_speed_mapping = DS723pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS723pGpioInit, + .x86_gpio_cleanup = DS723pGpioCleanup, +}; + +struct hwmon_sensor_list ds723p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds723p_hdd_backplane_status, + .current_sensor = &ds723p_current_status, +}; diff --git a/drivers/syno/synobios/r1000/ds923p.c b/drivers/syno/synobios/r1000/ds923p.c new file mode 100644 index 000000000000..86bc2096b252 --- /dev/null +++ b/drivers/syno/synobios/r1000/ds923p.c @@ -0,0 +1,107 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "r1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS923pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {68, 69}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS923pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void DS923pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE ds923p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE ds923p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int DS923pInitModuleType(struct synobios_ops *ops) +{ + module_t type_923p = MODULE_T_DS923p; + module_t *pType = &type_923p; + + module_type_set(pType); + return 0; +} + +static +int DS923pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS923pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS923pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS923pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds923p_ops = { + .x86_init_module_type = DS923pInitModuleType, + .x86_fan_speed_mapping = DS923pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS923pGpioInit, + .x86_gpio_cleanup = DS923pGpioCleanup, +}; + +struct hwmon_sensor_list ds923p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &ds923p_hdd_backplane_status, + .current_sensor = &ds923p_current_status, +}; diff --git a/drivers/syno/synobios/r1000/r1000_common.c b/drivers/syno/synobios/r1000/r1000_common.c new file mode 100755 index 000000000000..09155cfb5301 --- /dev/null +++ b/drivers/syno/synobios/r1000/r1000_common.c @@ -0,0 +1,529 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include +#include "../rtc/rtc.h" + +#include "r1000_common.h" +#include "syno_ttyS.h" + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_TTY_RECEIVE +extern int (*syno_get_current)(unsigned char, struct tty_struct *); +extern int save_current_data_from_uart(unsigned char ch, struct tty_struct *tty); +#endif /* CONFIG_SYNO_TTY_RECEIVE */ +extern int synobios_lock_ttyS_current(char *szCommand, char *szBuf); + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strncmp(gszSynoHWVersion, HW_DS723p, strlen(HW_DS723p) ) ) { + model = MODEL_DS723p; + } else if (!strncmp(gszSynoHWVersion, HW_DS923p, strlen(HW_DS923p))){ + model = MODEL_DS923p; + } else if (!strncmp(gszSynoHWVersion, HW_RS422p, strlen(HW_RS422p))){ + model = MODEL_RS422p; + } else if (!strncmp(gszSynoHWVersion, HW_DS1522p, strlen(HW_DS1522p))){ + model = MODEL_DS1522p; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_DS723p: + iInternalDiskNum = 2; + break; + case MODEL_DS923p: + case MODEL_RS422p: + iInternalDiskNum = 4; + break; + case MODEL_DS1522p: + iInternalDiskNum = 5; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_K10TEMP + iRet = syno_k10cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP */ + +END: + return iRet; +} + +static +int SetAlarmLedByGPIO(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int SetAlarmLed(unsigned char type) +{ + const char* cmd = NULL; + + if (type) { + cmd = SZ_UART_ALARM_LED_BLINKING; + }else{ + cmd = SZ_UART_ALARM_LED_OFF; + } + + return SetUart(cmd); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +static +int SYNOIOGetCurrentStatusByMicroP(unsigned long* pulSysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szTTYCur[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulTTYCur = 0; + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szTTYCur, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szTTYCur, 10, &ulTTYCur); + if (0 > iRet) { + goto End; + } + // microP return value * 16.13 = System current (mA) (reference : uP #130) + *pulSysCurrent = (ulTTYCur * 16) + (ulTTYCur * 13 / 100); + + iRet = 0; +End: + return iRet; +} + +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int iInternalDiskNum = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iInternalDiskNum = GetMaxInternalDiskNum(); + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_DETECT(index)) { + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); + } + } + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_ENABLE(index)) { + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); + } + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +static +int HWMONGetCurrentStatusByMicroP(struct _SYNO_HWMON_SENSOR_TYPE *SysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szCurrent[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulCurrent = 0; + + if (NULL == SysCurrent || NULL == hwmon_sensor_list) { + printk("SysCurrent null\n"); + goto End; + } + + memcpy(SysCurrent, hwmon_sensor_list->current_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szCurrent, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szCurrent, 10, &ulCurrent); + if (0 > iRet) { + goto End; + } + snprintf(SysCurrent->sensor[0].value, sizeof(SysCurrent->sensor[0].value), "%ld", (ulCurrent * 16) + (ulCurrent * 13 / 100)); + + iRet = 0; +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = NULL, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, + .hwmon_get_sys_current = NULL, + .get_sys_current = SYNOIOGetCurrentStatusByMicroP, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_DS723p: + model_ops = &ds723p_ops; + hwmon_sensor_list = &ds723p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif +#ifdef CONFIG_SYNO_TTY_RECEIVE + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE */ + break; + case MODEL_DS923p: + model_ops = &ds923p_ops; + hwmon_sensor_list = &ds923p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif +#ifdef CONFIG_SYNO_TTY_RECEIVE + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE */ + break; + case MODEL_RS422p: + model_ops = &rs422p_ops; + hwmon_sensor_list = &rs422p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLedByGPIO; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif +#ifdef CONFIG_SYNO_TTY_RECEIVE + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE */ + break; + case MODEL_DS1522p: + model_ops = &ds1522p_ops; + hwmon_sensor_list = &ds1522p_sensor_list; + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_alarm_led = SetAlarmLed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); +#endif +#ifdef CONFIG_SYNO_TTY_RECEIVE + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_RECEIVE */ + break; + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/r1000/r1000_common.h b/drivers/syno/synobios/r1000/r1000_common.h new file mode 100755 index 000000000000..9389c806b27e --- /dev/null +++ b/drivers/syno/synobios/r1000/r1000_common.h @@ -0,0 +1,65 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "syno_ttyS.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern char gszSynoHWVersion[]; +extern struct model_ops ds723p_ops; +extern struct model_ops ds923p_ops; +extern struct model_ops rs422p_ops; +extern struct model_ops ds1522p_ops; + +extern struct hwmon_sensor_list ds723p_sensor_list; +extern struct hwmon_sensor_list ds923p_sensor_list; +extern struct hwmon_sensor_list rs422p_sensor_list; +extern struct hwmon_sensor_list ds1522p_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#ifdef CONFIG_SYNO_K10TEMP +extern int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; + SYNO_HWMON_SENSOR_TYPE *current_sensor; +}; diff --git a/drivers/syno/synobios/r1000/rs422p.c b/drivers/syno/synobios/r1000/rs422p.c new file mode 100644 index 000000000000..60798f23bd58 --- /dev/null +++ b/drivers/syno/synobios/r1000/rs422p.c @@ -0,0 +1,129 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "r1000_common.h" + +PWM_FAN_SPEED_MAPPING gRS422pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 3, + .gpio_port = {68, 69, 40}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {3}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS422pGpioInit(void) +{ + syno_gpio.fan_fail = &fan_fail; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +static +void RS422pGpioCleanup(void) +{ + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +SYNO_HWMON_SENSOR_TYPE rs422p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE rs422p_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static +int RS422pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs422p = MODULE_T_RS422p; + module_t *pType = &type_rs422p; + + module_type_set(pType); + return 0; +} + +static +int RS422pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS422pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS422pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS422pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +static +int RS422pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +struct model_ops rs422p_ops = { + .x86_init_module_type = RS422pInitModuleType, + .x86_fan_speed_mapping = RS422pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS422pGetBuzzerCleared, + .x86_gpio_init = RS422pGpioInit, + .x86_gpio_cleanup = RS422pGpioCleanup, +}; + +struct hwmon_sensor_list rs422p_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &rs422p_hdd_backplane_status, + .current_sensor = &rs422p_current_status, +}; diff --git a/drivers/syno/synobios/rtc/alarmtime.c b/drivers/syno/synobios/rtc/alarmtime.c new file mode 100644 index 000000000000..875a04d01e8e --- /dev/null +++ b/drivers/syno/synobios/rtc/alarmtime.c @@ -0,0 +1,159 @@ +#include "synobios.h" +#include +#include "localtime.h" + +extern SYNO_AUTO_POWERON gPwSched; + +unsigned char rtc_get_next_weekday(const unsigned char weekdays, const unsigned char cur_wday) +{ + unsigned char u8Nextday = 0xFF; + unsigned int mask = 1 << cur_wday; + unsigned int weekdays_masked = weekdays & AUTO_POWERON_WEEKDAY_MASK; + + if( weekdays_masked == 0 || mask == 0 ) { // no days set in weekday bitsmask + goto End; + } + + u8Nextday = cur_wday; + weekdays_masked |= weekdays_masked << 7; // duplicate days into next week + + while( !(mask & weekdays_masked) ) { + mask <<= 1; + u8Nextday++; + } + u8Nextday %= 7; + +End: + return u8Nextday; +} + +void rtc_get_days_later(const SYNORTCTIMEPKT *pRtcTime, const int daysLater, struct xtm *tagetTime) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + time64_t t; +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + time_t t; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + t = mktime64(pRtcTime->year+1900, pRtcTime->month+1, pRtcTime->day, pRtcTime->hour, pRtcTime->min, pRtcTime->sec); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + t = mktime(pRtcTime->year+1900, pRtcTime->month+1, pRtcTime->day, pRtcTime->hour, pRtcTime->min, pRtcTime->sec); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + t += 86400 * daysLater; + localtime_1(tagetTime, t); + localtime_2(tagetTime, t); + localtime_3(tagetTime, t); + +} + +static +unsigned char rtc_get_next_mday(const SYNORTCTIMEPKT *pRtcTime, const int daysLater) +{ + struct xtm tagetTime; + + rtc_get_days_later(pRtcTime, daysLater, &tagetTime); + return (unsigned char)tagetTime.monthday; +} + +int rtc_later_equal_than_int(unsigned char rtcHour, const unsigned char rtcMin, + unsigned char intHour, const unsigned char intMin) +{ + if( rtcHour > intHour || (rtcHour == intHour && rtcMin >= intMin) ) { + return 1; + } + + return 0; +} + +unsigned char rtc_get_alarm_time(SYNORTCALARMPKT *pAlarmTime, const SYNORTCTIMEPKT *pRtcTime) +{ + int iLoop = 0; + unsigned char next_wday; + unsigned char wdays, mday, hrs, min; + unsigned char wdays_result = 0; + unsigned char mday_result = 0; + unsigned char hrs_result = 0; + unsigned char min_result = 0; + int min_day_offset = 0; + + if (NULL == pAlarmTime || NULL == pRtcTime) { + goto End; + } + + for (iLoop = 0; iLoop < gPwSched.num; iLoop++) { + int over_cur_time = 0; + int day_offset = 0; + int blSwitch = 0; + + wdays = gPwSched.RtcAlarmPkt[iLoop].weekdays; + next_wday = rtc_get_next_weekday(gPwSched.RtcAlarmPkt[iLoop].weekdays, pRtcTime->weekday); + over_cur_time = rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, + gPwSched.RtcAlarmPkt[iLoop].hour, + gPwSched.RtcAlarmPkt[iLoop].min); + + if( next_wday == pRtcTime->weekday && over_cur_time ) + { + next_wday = rtc_get_next_weekday(gPwSched.RtcAlarmPkt[iLoop].weekdays, (pRtcTime->weekday+1)%7); + } + + // only bandon use mday now + if ((next_wday == pRtcTime->weekday) && over_cur_time) { + day_offset = 7; + mday = rtc_get_next_mday(pRtcTime, day_offset); + } else if ( next_wday >= pRtcTime->weekday ) { + day_offset = next_wday - pRtcTime->weekday; + mday = rtc_get_next_mday(pRtcTime, day_offset); + } else { + day_offset = 7 - pRtcTime->weekday + next_wday; + mday = rtc_get_next_mday(pRtcTime, day_offset); + } + + hrs = gPwSched.RtcAlarmPkt[iLoop].hour; + min = gPwSched.RtcAlarmPkt[iLoop].min; + + if (0 == iLoop) { + blSwitch = 1; + }else{ + if ( day_offset < min_day_offset ) { + blSwitch = 1; + }else if ( day_offset == min_day_offset ) { + if ( hrs < hrs_result ) { + blSwitch = 1; + }else if ( hrs == hrs_result ) { + if ( min < min_result ) { + blSwitch = 1; + } + } + } + } + + if (blSwitch) { + min_day_offset = day_offset; + wdays_result = wdays; + hrs_result = hrs; + min_result = min; + mday_result = mday; + } + } + + pAlarmTime->weekdays = wdays_result; + pAlarmTime->hour = hrs_result; + pAlarmTime->min = min_result; +End: + return mday_result; +} + +int rtc_get_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn) +{ + int iRet = -1; + + if( NULL == pAutoPowerOn ) { + goto End; + } + + memcpy(pAutoPowerOn, &gPwSched, sizeof(SYNO_AUTO_POWERON)); + iRet = 0; +End: + return iRet; +} diff --git a/drivers/syno/synobios/rtc/localtime.c b/drivers/syno/synobios/rtc/localtime.c new file mode 100644 index 000000000000..049dcd9b0f42 --- /dev/null +++ b/drivers/syno/synobios/rtc/localtime.c @@ -0,0 +1,133 @@ +#include "localtime.h" + +static const u_int16_t days_since_year[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, +}; + +static const u_int16_t days_since_leapyear[] = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, +}; + +/* + * Since time progresses forward, it is best to organize this array in reverse, + * to minimize lookup time. + */ +enum { + DSE_FIRST = 2039, +}; +static const u_int16_t days_since_epoch[] = { + /* 2039 - 2030 */ + 25202, 24837, 24472, 24106, 23741, 23376, 23011, 22645, 22280, 21915, + /* 2029 - 2020 */ + 21550, 21184, 20819, 20454, 20089, 19723, 19358, 18993, 18628, 18262, + /* 2019 - 2010 */ + 17897, 17532, 17167, 16801, 16436, 16071, 15706, 15340, 14975, 14610, + /* 2009 - 2000 */ + 14245, 13879, 13514, 13149, 12784, 12418, 12053, 11688, 11323, 10957, + /* 1999 - 1990 */ + 10592, 10227, 9862, 9496, 9131, 8766, 8401, 8035, 7670, 7305, + /* 1989 - 1980 */ + 6940, 6574, 6209, 5844, 5479, 5113, 4748, 4383, 4018, 3652, + /* 1979 - 1970 */ + 3287, 2922, 2557, 2191, 1826, 1461, 1096, 730, 365, 0, +}; + +static inline int is_leap(unsigned int y) +{ + return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); +} + +/* + * Each network packet has a (nano)seconds-since-the-epoch (SSTE) timestamp. + * Since we match against days and daytime, the SSTE value needs to be + * computed back into human-readable dates. + * + * This is done in three separate functions so that the most expensive + * calculations are done last, in case a "simple match" can be found earlier. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +unsigned int localtime_1(struct xtm *r, time64_t time) +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +unsigned int localtime_1(struct xtm *r, time_t time) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +{ + unsigned int v, w; + + /* Each day has 86400s, so finding the hour/minute is actually easy. */ + v = time % 86400; + r->second = v % 60; + w = v / 60; + r->minute = w % 60; + r->hour = w / 60; + return v; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +void localtime_2(struct xtm *r, time64_t time) +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +void localtime_2(struct xtm *r, time_t time) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +{ + /* + * Here comes the rest (weekday, monthday). First, divide the SSTE + * by seconds-per-day to get the number of _days_ since the epoch. + */ + r->dse = time / 86400; + + /* 1970-01-01 (w=0) was a Thursday (4). */ + r->weekday = (4 + r->dse) % 7; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +void localtime_3(struct xtm *r, time64_t time) +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +void localtime_3(struct xtm *r, time_t time) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +{ + unsigned int year, i, w = r->dse; + + /* + * In each year, a certain number of days-since-the-epoch have passed. + * Find the year that is closest to said days. + * + * Consider, for example, w=21612 (2029-03-04). Loop will abort on + * dse[i] <= w, which happens when dse[i] == 21550. This implies + * year == 2009. w will then be 62. + */ + for (i = 0, year = DSE_FIRST; days_since_epoch[i] > w; + ++i, --year) + /* just loop */; + + w -= days_since_epoch[i]; + + /* + * By now we have the current year, and the day of the year. + * r->yearday = w; + * + * On to finding the month (like above). In each month, a certain + * number of days-since-New Year have passed, and find the closest + * one. + * + * Consider w=62 (in a non-leap year). Loop will abort on + * dsy[i] < w, which happens when dsy[i] == 31+28 (i == 2). + * Concludes i == 2, i.e. 3rd month => March. + * + * (A different approach to use would be to subtract a monthlength + * from w repeatedly while counting.) + */ + if (is_leap(year)) { + for (i = ARRAY_SIZE(days_since_leapyear) - 1; + i > 0 && days_since_leapyear[i] > w; --i) + /* just loop */; + r->month = i + 1; + r->monthday = w - days_since_leapyear[i] + 1; + } else { + for (i = ARRAY_SIZE(days_since_year) - 1; + i > 0 && days_since_year[i] > w; --i) + /* just loop */; + r->month = i + 1; + r->monthday = w - days_since_year[i] + 1; + } + + return; +} diff --git a/drivers/syno/synobios/rtc/localtime.h b/drivers/syno/synobios/rtc/localtime.h new file mode 100644 index 000000000000..9f51b5cb26a2 --- /dev/null +++ b/drivers/syno/synobios/rtc/localtime.h @@ -0,0 +1,29 @@ + +#ifndef __SYNOBIOS_LOCALTIME__ +#define __SYNOBIOS_LOCALTIME__ +#include +#include +#include +#include +#include + +struct xtm { + u_int8_t month; /* (1-12) */ + u_int8_t monthday; /* (1-31) */ + u_int8_t weekday; /* (1-7) */ + u_int8_t hour; /* (0-23) */ + u_int8_t minute; /* (0-59) */ + u_int8_t second; /* (0-59) */ + unsigned int dse; +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +unsigned int localtime_1(struct xtm *r, time64_t time); +void localtime_2(struct xtm *r, time64_t time); +void localtime_3(struct xtm *r, time64_t time); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +unsigned int localtime_1(struct xtm *r, time_t time); +void localtime_2(struct xtm *r, time_t time); +void localtime_3(struct xtm *r, time_t time); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +#endif /* __SYNOBIOS_LOCALTIME__*/ diff --git a/drivers/syno/synobios/rtc/rtc-linux-pericom.c b/drivers/syno/synobios/rtc/rtc-linux-pericom.c new file mode 100644 index 000000000000..41d217077720 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-linux-pericom.c @@ -0,0 +1,366 @@ +#include +#include +#include +#include +#include +#include "synobios.h" +#include "../i2c/i2c-linux.h" +#include "rtc.h" +#include "../mapping.h" +#include + +#if defined(CONFIG_SYNO_RTD1619B) +#define I2C_BUS_NO 1 +#else +#define I2C_BUS_NO 0 +#endif + +static int pericomCharReadByI2c(struct i2c_adapter *pAdap, int target, u8 *data, int length, int offset) +{ + unsigned char *msgbuf0 = NULL; + unsigned char *msgbuf1 = NULL; + int ret = -1; + struct i2c_msg msg[2] = { + { + .addr = target, + .flags = 0, + .len = 1, + }, { + .addr = target, + .flags = I2C_M_RD, + .len = length, + }, + }; + + if (NULL ==pAdap) { + printk("Adpater NULL\n"); + goto END; + } + + if (NULL == (msgbuf0 = kzalloc(1, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg[0].buf = msgbuf0; + msgbuf0[0] = offset; + + if (NULL == (msgbuf1 = kzalloc(length, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg[1].buf = msgbuf1; + + if (2 != i2c_transfer(pAdap, msg, 2)) + goto END; + + memcpy(data, msg[1].buf, length); + + ret = 0; +END: + return ret; +} + +static int pericomCharReadBySmbus(u8 *data, int length, int offset) +{ + int iRet = -1; + struct device_node *np = of_find_compatible_node(NULL, NULL, "pericom,pt7c4337"); + struct i2c_client *client = NULL; + + if (np == NULL) { + printk("find pericom rtc failed\n"); + goto END; + } + + client = of_find_i2c_device_by_node(np); + + if (NULL == client) { + printk("get i2c client failed\n"); + goto END; + } + + if (0 >= i2c_smbus_read_i2c_block_data(client, offset, length, data)) { + printk("i2c_smbus_read_i2c_block_data failed\n"); + goto END; + } + iRet = 0; + +END: + of_node_put(np); + return iRet; +} + +static int pericomI2CCharRead(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap = i2c_get_adapter(I2C_BUS_NO); + int iRet = -1; + + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + if (pAdap->algo->master_xfer) { // i2c protocol + if (0 > pericomCharReadByI2c(pAdap, target, data, length, offset)) { + goto END; + } + } else if (pAdap->algo->smbus_xfer) { // SMBus protocol + if (0 > pericomCharReadBySmbus(data, length, offset)) { + goto END; + } + } else { // No protocol is specified + printk("No usable i2c protocol\n"); + goto END; + } + iRet = 0; + +END: + if (pAdap) + i2c_put_adapter(pAdap); + return iRet; +} + +static int pericomCharWriteByI2c(struct i2c_adapter *pAdap, int target, u8 *data, int length, int offset) +{ + struct i2c_msg msg = {0}; + int ret = -1; + int buf_len = 0; + u8 *pDataBuf = NULL; + + if (NULL ==pAdap) { + printk("Adpater NULL\n"); + goto END; + } + + buf_len = length + 1; + + if (NULL == (pDataBuf = kzalloc(buf_len, GFP_KERNEL))){ + printk("error malloc\n"); + goto END; + } + + msg.addr = target; + msg.flags = 0; + msg.len = buf_len; + msg.buf = pDataBuf; + + pDataBuf[0] = offset; + + memcpy(pDataBuf + 1, data, length); + + if (1 != i2c_transfer(pAdap, &msg, 1)) { + goto END; + } + + ret = 0; +END: + if (pDataBuf) + kfree(pDataBuf); + + return ret; + +} + +static int pericomCharWriteBySmbus(u8 *data, int length, int offset) +{ + int iRet = -1; + struct device_node *np = of_find_compatible_node(NULL, NULL, "pericom,pt7c4337"); + struct i2c_client *client = NULL; + + if (np == NULL) { + printk("find pericom rtc failed\n"); + goto END; + } + + if (NULL == (client = of_find_i2c_device_by_node(np))) { + printk("get i2c client failed\n"); + goto END; + } + + if (0 > i2c_smbus_write_i2c_block_data(client, offset, length, data)) { + printk("i2c_smbus_read_i2c_block_data failed\n"); + goto END; + } + iRet = 0; + +END: + of_node_put(np); + return iRet; +} + +static int pericomI2CCharWrite(int target, u8 *data, int length, int offset) +{ + struct i2c_adapter *pAdap = i2c_get_adapter(I2C_BUS_NO); + int iRet = -1; + + if (!pAdap) { + printk("Cannot get i2c adapter\n"); + goto END; + } + if (pAdap->algo->master_xfer) { // i2c protocol + if (0 > pericomCharWriteByI2c(pAdap, target, data, length, offset)) { + goto END; + } + } else if (pAdap->algo->smbus_xfer) { // SMBus protocol + if (0 > pericomCharWriteBySmbus(data, length, offset)) { + goto END; + } + } else { // No protocol is specified + printk("No usable i2c protocol\n"); + goto END; + } + iRet = 0; + +END: + if (pAdap) + i2c_put_adapter(pAdap); + return iRet; +} + + +int rtc_pericom_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int ret = -1; + u8 csr = 0; + u8 str = 0; + unsigned char nextWday = 0; + SYNORTCALARMPKT alarmTime = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + if ( 0 > (ret = pericomI2CCharRead(PERICOM_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), PERICOM_RTC_CONTROL_OFFSET)) ) { + goto End; + } + + if ( 0 > (ret = pericomI2CCharRead(PERICOM_RTC_ADDR, (u8 *)&str, sizeof(str)/sizeof(u8), PERICOM_RTC_STATUS_OFFSET)) ) { + goto End; + } + + // clear alarm interrupt bit + csr &= ~(PERICOM_RTC_A1IE_BIT | PERICOM_RTC_A2IE_BIT | PERICOM_RTC_INTCN_BIT); + + // clear status bit + str = 0; + + rtc_get_alarm_time(&alarmTime, pRtcTime); + + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday+1)%7); + } + + alarmTime.hour = Hour_to_Pericom(alarmTime.hour); + BIN_TO_BCD(alarmTime.hour); + BIN_TO_BCD(alarmTime.min); + + if ( SYNO_AUTO_POWERON_ENABLE == pAutoPowerOn->enabled ) { + + // enable alarm interrupt + csr |= PERICOM_RTC_A2IE_BIT; + + if( 0x7F == alarmTime.weekdays) { + alarmTime.weekdays |= PERICOM_RTC_DAY_MASK_BIT; + } else { + // pericom use 01 to 07 to present weekdays + if (nextWday == 0) { + nextWday = 7; + } + alarmTime.weekdays = nextWday | PERICOM_RTC_DAY_DATE_SWITCH; // BIT6 for date / day + } + } + + // set alarm data + if( 0 > (ret = pericomI2CCharWrite(PERICOM_RTC_ADDR, (u8 *)&alarmTime, + sizeof(SYNORTCALARMPKT)/sizeof(u8), PERICOM_RTC_ALARM2_OFFSET)) ) { + goto End; + } + + // set alarm interrupt + if ( 0 > (ret = pericomI2CCharWrite(PERICOM_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), PERICOM_RTC_CONTROL_OFFSET)) ) { + goto End; + } + + // clear status + if ( 0 > (ret = pericomI2CCharWrite(PERICOM_RTC_ADDR, (u8 *)&str, sizeof(str)/sizeof(u8), PERICOM_RTC_STATUS_OFFSET)) ) { + goto End; + } + + ret = 0; +End: + return ret; + +} + +int rtc_pericom_get_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7] = {0}; + unsigned char hrs = 0; + SYNO_AUTO_POWERON schedule; + + if( 0 != (ret = pericomI2CCharRead(PERICOM_RTC_ADDR, (u8 *)rgRtcTimeTemp, 7, 0))) { + goto END; + } + + pRtcTimePkt->sec = BCD2BIN(rgRtcTimeTemp[0]); + pRtcTimePkt->min = BCD2BIN(rgRtcTimeTemp[1]); + hrs = BCD2BIN(rgRtcTimeTemp[2]); + pRtcTimePkt->hour = Pericom_to_Hour(hrs); + pRtcTimePkt->weekday = BCD2BIN(rgRtcTimeTemp[3]); + pRtcTimePkt->day = BCD2BIN(rgRtcTimeTemp[4]); + pRtcTimePkt->month = BCD2BIN(rgRtcTimeTemp[5]); + pRtcTimePkt->year = BCD2BIN(rgRtcTimeTemp[6]); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_pericom_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +END: + return ret; +} + + +int rtc_pericom_set_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int ret = 0; + unsigned char year = 0, mon = 0, hrs = 0; + unsigned char rgRtcTimeTemp[7] = {0}; + SYNO_AUTO_POWERON schedule; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[6] = BIN2BCD(year); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[5] = BIN2BCD(mon); + rgRtcTimeTemp[4] = BIN2BCD(pRtcTimePkt->day); + // pericom use 01 to 07 to present weekdays + if (pRtcTimePkt->weekday == 0) { + pRtcTimePkt->weekday = 7; + } + rgRtcTimeTemp[3] = BIN2BCD(pRtcTimePkt->weekday); + hrs = Hour_to_Pericom(pRtcTimePkt->hour); + rgRtcTimeTemp[2] = BIN2BCD(hrs); + rgRtcTimeTemp[1] = BIN2BCD(pRtcTimePkt->min); + rgRtcTimeTemp[0] = BIN2BCD(pRtcTimePkt->sec); + + if ( 0 != (ret = pericomI2CCharWrite(PERICOM_RTC_ADDR, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + } + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_pericom_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return ret; + +} + + +int rtc_pericom_auto_poweron_init(void) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtc/rtc-linux-ricoh.c b/drivers/syno/synobios/rtc/rtc-linux-ricoh.c new file mode 100644 index 000000000000..9cf70ef86e75 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-linux-ricoh.c @@ -0,0 +1,164 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include "synobios.h" +#include "rtc.h" +#include "../i2c/i2c-linux.h" + +int rtc_ricoh_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int ret = -1; + u8 csr = 0; + SYNORTCALARMPKT alarmTime = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + // get Alarm enable bit + if ( 0 > (ret = linuxI2CCharRead(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + if ( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + // disable Alarm enable bit + csr &= ~I2C_RTC_ALARMA_ENABLE; + if ( 0 > (ret = linuxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + alarmTime.hour = Hour_to_Ricoh(alarmTime.hour); + BIN_TO_BCD(alarmTime.hour); + BIN_TO_BCD(alarmTime.min); + + // enable Alarm + csr |= I2C_RTC_ALARMAB_SL; + csr |= I2C_RTC_ALARMA_ENABLE; + + if ( 0 > (ret = linuxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + csr = 0; + if ( 0 > (ret = linuxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + + // set Alarm data + if( 0 > (ret = linuxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&alarmTime, + sizeof(SYNORTCALARMPKT)/sizeof(u8), I2C_RTC_ALARMA_OFFSET)) ) { + goto End; + } + } + + ret = 0; +End: + return ret; +} + +int rtc_ricoh_get_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + unsigned char hrs; + SYNO_AUTO_POWERON schedule; + + if ( 0 != (ret = linuxI2CCharRead(0x32, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + goto END; + } + + pRtcTimePkt->sec = BCD2BIN(rgRtcTimeTemp[0]); + pRtcTimePkt->min = BCD2BIN(rgRtcTimeTemp[1]); + hrs = BCD2BIN(rgRtcTimeTemp[2]); + pRtcTimePkt->hour = Ricoh_to_Hour(hrs); + pRtcTimePkt->weekday = BCD2BIN(rgRtcTimeTemp[3]); + pRtcTimePkt->day = BCD2BIN(rgRtcTimeTemp[4]); + pRtcTimePkt->month = BCD2BIN(rgRtcTimeTemp[5]); + pRtcTimePkt->year = BCD2BIN(rgRtcTimeTemp[6]); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +END: + return ret; +} + +int rtc_ricoh_set_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[6] = BIN2BCD(year); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[5] = BIN2BCD(mon); + rgRtcTimeTemp[4] = BIN2BCD(pRtcTimePkt->day); + rgRtcTimeTemp[3] = BIN2BCD(pRtcTimePkt->weekday); + hrs = Hour_to_Ricoh(pRtcTimePkt->hour); + rgRtcTimeTemp[2] = BIN2BCD(hrs); + rgRtcTimeTemp[1] = BIN2BCD(pRtcTimePkt->min); + rgRtcTimeTemp[0] = BIN2BCD(pRtcTimePkt->sec); + + if ( 0 != (ret = linuxI2CCharWrite(0x32, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + } + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return ret; +} + +void rtc_ricoh_time_correction_set(void) +{ + unsigned char correction = 0x0f; + linuxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&correction, 1, I2C_RTC_TIME_TRIM_OFFSET); +} + +void rtc_ricoh_time_correction_get(void) +{ + unsigned char correction = 0; + linuxI2CCharRead(I2C_RTC_ADDR, &correction, 1, I2C_RTC_TIME_TRIM_OFFSET); + printk("correction with 0x%02x\n", correction); +} + +int rtc_ricoh_auto_poweron_init(void) +{ + int err = -1; + u8 csr = 0; + + // disable matched bit + // this will cause #4457 so we mark it + //csr = I2C_RTC_ALARMA_24HOUR; + if ( 0 > (err = linuxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + +#ifdef MY_DEF_HERE + if ( strncmp(gszSynoHWVersion, HW_DS209, strlen(HW_DS209) ) && + strncmp(gszSynoHWVersion, HW_DS409slim, strlen(HW_DS409slim) ) ) + { + rtc_ricoh_time_correction_set(); + rtc_ricoh_time_correction_get(); + } +#endif + + err = 0; + +End: + return err; +} diff --git a/drivers/syno/synobios/rtc/rtc-linux-seiko.c b/drivers/syno/synobios/rtc/rtc-linux-seiko.c new file mode 100644 index 000000000000..7485c4ffc037 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-linux-seiko.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include "synobios.h" +#include "../i2c/i2c-linux.h" +#include "rtc.h" +#include "../mapping.h" + +/* + * Reset interrupt mode in Status2 register. It'll clear interrupts from RTC. + */ +int rtc_seiko_reset_interrupt_mode(void) +{ + int iRet = -1; + u8 csr = 0x00; + + iRet = linuxI2CCharWrite(SEIKO_RTC_STATUS2_ADDR, (u8 *)&csr, 1, -1); + + // enable interrupt mode for auto poweron + // [INT1FE, INT1ME, INT1AE, 32kE, INT2FE, INT2ME, INT2AE, TEST] = [0, 0, 1, 0, 0, 0, 1, 0] + csr = 0x22; + iRet = linuxI2CCharWrite(SEIKO_RTC_STATUS2_ADDR, (u8 *)&csr, 1, -1); + + return iRet; +} + +/* + * Write interrupt register on RTC for auto power-on + * + * @param intAddr: SEIKO_RTC_INT1_ADDR or SEIKO_RTC_INT2_ADDR + * @param data: [weekday, hour, min] (Hour: Richo RTC Format) + * @param enable: 0 is disable, otherwise enable + */ +static +int rtc_set_interrupt(const unsigned char intAddr, const unsigned char data[3], const int enable) +{ + int iRet = -1; + unsigned char rgIntReg[3] = {0, 0, 0}; + + if( intAddr != SEIKO_RTC_INT1_ADDR && intAddr != SEIKO_RTC_INT2_ADDR ) { + goto End; + } + + rgIntReg[2] = RB(data[2]); + rgIntReg[1] = RB(data[1]); + rgIntReg[0] = RB(data[0]); + + if( enable ) { + rgIntReg[2] |= 0x01; + rgIntReg[1] |= 0x01; + rgIntReg[0] |= 0x01; + } + + rtc_seiko_reset_interrupt_mode(); + + if( (iRet = linuxI2CCharWrite(intAddr, (u8 *)rgIntReg, 3, -1) ) < 0 ) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + SYNORTCALARMPKT alarmTime = {0}; + const unsigned char rgEmptyData[3] = {0, 0, 0}; + unsigned char rgIntReg[3] = {0, 0, 0}; + unsigned char nextWday = 0; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + if( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + rtc_set_interrupt(SEIKO_RTC_INT1_ADDR, rgEmptyData, 0); + rtc_set_interrupt(SEIKO_RTC_INT2_ADDR, rgEmptyData, 0); + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + // RTC have only one weekday saved in a interrupt register + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday+1)%7); + } + rgIntReg[0] = nextWday; + rgIntReg[1] = BIN2BCD(Hour_to_Seiko(alarmTime.hour)); + rgIntReg[2] = BIN2BCD(alarmTime.min); + rtc_set_interrupt(SEIKO_RTC_INT1_ADDR, rgIntReg, 1); + rtc_set_interrupt(SEIKO_RTC_INT2_ADDR, rgEmptyData, 0); + } + + // set *weekdays* to Free register + BIN_TO_BCD(alarmTime.weekdays); + if( (iRet = linuxI2CCharWrite(SEIKO_RTC_FREE_ADDR, (u8*)&(alarmTime.weekdays), + sizeof(unsigned char)/sizeof(u8), -1) ) < 0 ) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_get_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + if( (ret = linuxI2CCharRead(SEIKO_RTC_REALTIME1_ADDR, (u8 *)rgRtcTimeTemp, + sizeof(rgRtcTimeTemp)/sizeof(unsigned char), -1) < 0) ) { + goto End; + } + + pRtcTimePkt->sec = BCD2BIN(RB(rgRtcTimeTemp[6])); + pRtcTimePkt->min = BCD2BIN(RB(rgRtcTimeTemp[5])); + pRtcTimePkt->hour = Seiko_to_Hour(BCD2BIN(RB(rgRtcTimeTemp[4]))); + pRtcTimePkt->weekday = BCD2BIN(RB(rgRtcTimeTemp[3])); + pRtcTimePkt->day = BCD2BIN(RB(rgRtcTimeTemp[2])); + pRtcTimePkt->month = BCD2BIN(RB(rgRtcTimeTemp[1])); + pRtcTimePkt->year = BCD2BIN(RB(rgRtcTimeTemp[0])); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + /* + * reset the same data to toggle weekday rotation in interrupt registers. + * scemd syncs system time with RTC every 1 hour, so it'll also do rotation. + */ + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_seiko_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +End: + return ret; +} + +int rtc_seiko_set_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int iRet = -1; + SYNO_AUTO_POWERON schedule; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[0] = RB(BIN2BCD(year)); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[1] = RB(BIN2BCD(mon)); + rgRtcTimeTemp[2] = RB(BIN2BCD(pRtcTimePkt->day)); + rgRtcTimeTemp[3] = RB(BIN2BCD(pRtcTimePkt->weekday)); + hrs = Hour_to_Seiko(pRtcTimePkt->hour); + rgRtcTimeTemp[4] = RB(BIN2BCD(hrs)); + rgRtcTimeTemp[5] = RB(BIN2BCD(pRtcTimePkt->min)); + rgRtcTimeTemp[6] = RB(BIN2BCD(pRtcTimePkt->sec)); + + if( (iRet = linuxI2CCharWrite(SEIKO_RTC_REALTIME1_ADDR, (u8 *)rgRtcTimeTemp, + sizeof(rgRtcTimeTemp)/sizeof(unsigned char), -1) < 0) ) { + goto End; + } + + /* + * reset the same data to toggle weekday rotation in interrupt registers. + */ + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_seiko_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +End: + return iRet; +} + +void rtc_seiko_time_correction_set(void) +{ + unsigned char correction = module_type_get()->rtc_corr_value; + linuxI2CCharWrite(SEIKO_RTC_CORRECT_ADDR, &correction, 1, -1); +} + +void rtc_seiko_time_correction_get(void) +{ + unsigned char correction = 0; + linuxI2CCharRead(SEIKO_RTC_CORRECT_ADDR, &correction, 1, -1); + printk("correction with 0x%02x\n", correction); +} + +int rtc_seiko_auto_poweron_init(void) +{ + rtc_seiko_time_correction_set(); + rtc_seiko_time_correction_get(); + return rtc_seiko_reset_interrupt_mode(); +} diff --git a/drivers/syno/synobios/rtc/rtc-mv-builtin.c b/drivers/syno/synobios/rtc/rtc-mv-builtin.c new file mode 100755 index 000000000000..4aa59d13425d --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-mv-builtin.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include "synobios.h" +#include "localtime.h" +#include "rtc.h" + +#define DEC2BCD(dec) (((dec/10)*16)+(dec%10)) +#define BCD2DEC(val) ((val)=((val)&15) + ((val)>>4)*10) + +typedef unsigned char MV_U8; +typedef void MV_VOID; + +#if defined(CONFIG_SYNO_ARMADA) || defined(CONFIG_SYNO_ARMADA_V2) +typedef unsigned int MV_U32; +extern SYNO_AUTO_POWERON gPwSched; +#endif +typedef struct _tag_MV_RTC_TIME +{ + MV_U8 seconds; + MV_U8 minutes; + MV_U8 hours; + MV_U8 day; + MV_U8 date; + MV_U8 month; + MV_U8 century; + MV_U8 year; +} MV_RTC_TIME; + +MV_VOID mvRtcTimeSet(MV_RTC_TIME* time); +MV_VOID mvRtcTimeGet(MV_RTC_TIME* time); +#if defined(CONFIG_SYNO_ARMADA) || defined(CONFIG_SYNO_ARMADA_V2) +MV_VOID SYNOmvRtcExtAlarmSet(MV_U32 time); +MV_VOID SYNOmvRtcExtAlarmClean(void); + +static MV_U32 rtc_mv_calculate_config_value(unsigned char alarmYear, const struct xtm *nextAlarmTime) +{ + const MV_U32 NSM[12] = {0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600}; + MV_U32 configValue = 0; + + // RTC counts year from 2000. _SynoRtcTimePkt starts from 1900. + if (100 < alarmYear) { + alarmYear = alarmYear - 100; + } + + // use years, month, monthday, hours, minutes,seconds to calculate configValue and set it to register + configValue = alarmYear * 31536000 + (alarmYear/4) * 86400 + NSM[nextAlarmTime->month-1] + (nextAlarmTime->monthday-1) * 86400 + nextAlarmTime->hour * 3600 + nextAlarmTime->minute * 60 + nextAlarmTime->second; + + // in Functional Specification 29.2.4.3 + // ceil(YY/4) * 86400 = (alarmYear/4) * 86400 + (0 != alarmYear % 4)? 86400:0; + // (alarmYear/4) * 86400 is in above part, and others in below part + // (YY%4==0) * (MM>2) * 86400 represent to (0 == alarmYear % 4 && nextAlarmTime->month > 2) + if (0 != alarmYear % 4 || (0 == alarmYear % 4 && nextAlarmTime->month > 2)) { + configValue = configValue + 86400; + } + + return configValue; +} +int rtc_mv_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int ret = -1; + SYNORTCALARMPKT alarmTime = {0}; + unsigned char nextWday = 0; + int daysLater = 0; + struct xtm nextAlarmTime; + unsigned char alarmYear = 0; + SYNORTCTIMEPKT rtcNow = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + if ( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + SYNOmvRtcExtAlarmSet(0); + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + // RTC have only one weekday saved in a interrupt register + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday+1)%7); + } + + // generate Alarm time: years, Month, monthday, hours, minutes, seconds + daysLater = (nextWday - pRtcTime->weekday + 7) % 7; + rtc_mv_get_time(&rtcNow); + if (0 == daysLater && (60 * alarmTime.hour + alarmTime.min) <= (60 * rtcNow.hour + rtcNow.min)) { + daysLater = 7; + } + rtc_get_days_later(pRtcTime, daysLater, &nextAlarmTime); + + alarmYear = pRtcTime->year; + // pRtcTime->month is 0-based, pRtcTime->day is 1-based + if (11 == pRtcTime->month && 31 < daysLater + pRtcTime->day) { + alarmYear = alarmYear + 1; + } + nextAlarmTime.hour = alarmTime.hour; + nextAlarmTime.minute = alarmTime.min; + nextAlarmTime.second = 0; + + SYNOmvRtcExtAlarmSet(rtc_mv_calculate_config_value(alarmYear, &nextAlarmTime)); + + } + + ret = 0; +End: + return ret; +} + +int rtc_mv_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if( NULL == pAutoPowerOn || pAutoPowerOn->num < 0 ) { + printk("Parameter Error.\n"); + goto End; + } + + if( 0 > rtc_mv_get_time(&rtcTime) ) { + printk("Failed to get time from rtc.\n"); + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if ( 0 != rtc_mv_rotate_auto_poweron(pAutoPowerOn, &rtcTime) ) { + printk("Failed to set alarm data.\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_mv_auto_poweron_clean(void) +{ + // disable Alarm interrupt + SYNOmvRtcExtAlarmClean(); + return 0; +} +#endif + +int rtc_mv_get_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + MV_RTC_TIME mvTime; + + if (NULL == pRtcTimePkt) { + return -1; + } + + mvRtcTimeGet(&mvTime); + + pRtcTimePkt->sec = mvTime.seconds; + pRtcTimePkt->min = mvTime.minutes; + pRtcTimePkt->hour = mvTime.hours; + pRtcTimePkt->weekday = mvTime.day; + pRtcTimePkt->day = mvTime.date; + pRtcTimePkt->month = mvTime.month - 1; + pRtcTimePkt->year = mvTime.year + 100; + + return 0; +} + +int rtc_mv_set_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + MV_RTC_TIME mvTime; + + if (NULL == pRtcTimePkt) { + return -1; + } + + mvTime.seconds = pRtcTimePkt->sec; + mvTime.minutes = pRtcTimePkt->min; + mvTime.hours = pRtcTimePkt->hour; + mvTime.day = pRtcTimePkt->weekday; + mvTime.date = pRtcTimePkt->day; + /* Month: Kirkwood RTC is 1-based and _SynoRtcTimePkt is 0-based. */ + mvTime.month = pRtcTimePkt->month + 1; + /* + * Kirkwood RTC counts year from 2000. _SynoRtcTimePkt starts from 1900. + * Check range and fallback to 0 (year 2000). + */ + if (100 <= pRtcTimePkt->year) { + mvTime.year = pRtcTimePkt->year - 100; + } else { + mvTime.year = 0; + } + + mvRtcTimeSet(&mvTime); + + return 0; +} diff --git a/drivers/syno/synobios/rtc/rtc-mv-ricoh.c b/drivers/syno/synobios/rtc/rtc-mv-ricoh.c new file mode 100644 index 000000000000..178444bb56fd --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-mv-ricoh.c @@ -0,0 +1,165 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include "synobios.h" +#include "rtc.h" +#include "../i2c/i2c-mv.h" +#include "../mapping.h" + +int rtc_ricoh_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int ret = -1; + u8 csr = 0; + SYNORTCALARMPKT alarmTime = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + // get Alarm enable bit + if ( 0 > (ret = mvI2CCharRead(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + if ( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + // disable Alarm enable bit + csr &= ~I2C_RTC_ALARMA_ENABLE; + if ( 0 > (ret = mvI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + alarmTime.hour = Hour_to_Ricoh(alarmTime.hour); + BIN_TO_BCD(alarmTime.hour); + BIN_TO_BCD(alarmTime.min); + + // enable Alarm + csr |= I2C_RTC_ALARMAB_SL; + csr |= I2C_RTC_ALARMA_ENABLE; + + if ( 0 > (ret = mvI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + csr = 0; + if ( 0 > (ret = mvI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + + // set Alarm data + if( 0 > (ret = mvI2CCharWrite(I2C_RTC_ADDR, (u8 *)&alarmTime, + sizeof(SYNORTCALARMPKT)/sizeof(u8), I2C_RTC_ALARMA_OFFSET)) ) { + goto End; + } + } + + ret = 0; +End: + return ret; +} + +int rtc_ricoh_get_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + unsigned char hrs; + SYNO_AUTO_POWERON schedule; + + if ( 0 != (ret = mvI2CCharRead(0x32, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + goto END; + } + + pRtcTimePkt->sec = BCD2BIN(rgRtcTimeTemp[0]); + pRtcTimePkt->min = BCD2BIN(rgRtcTimeTemp[1]); + hrs = BCD2BIN(rgRtcTimeTemp[2]); + pRtcTimePkt->hour = Ricoh_to_Hour(hrs); + pRtcTimePkt->weekday = BCD2BIN(rgRtcTimeTemp[3]); + pRtcTimePkt->day = BCD2BIN(rgRtcTimeTemp[4]); + pRtcTimePkt->month = BCD2BIN(rgRtcTimeTemp[5]); + pRtcTimePkt->year = BCD2BIN(rgRtcTimeTemp[6]); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +END: + return ret; +} + +int rtc_ricoh_set_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[6] = BIN2BCD(year); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[5] = BIN2BCD(mon); + rgRtcTimeTemp[4] = BIN2BCD(pRtcTimePkt->day); + rgRtcTimeTemp[3] = BIN2BCD(pRtcTimePkt->weekday); + hrs = Hour_to_Ricoh(pRtcTimePkt->hour); + rgRtcTimeTemp[2] = BIN2BCD(hrs); + rgRtcTimeTemp[1] = BIN2BCD(pRtcTimePkt->min); + rgRtcTimeTemp[0] = BIN2BCD(pRtcTimePkt->sec); + + if ( 0 != (ret = mvI2CCharWrite(0x32, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + } + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return ret; +} + +void rtc_ricoh_time_correction_set(void) +{ + unsigned char correction = module_type_get()->rtc_corr_value; + mvI2CCharWrite(I2C_RTC_ADDR, (u8 *)&correction, 1, I2C_RTC_TIME_TRIM_OFFSET); +} + +void rtc_ricoh_time_correction_get(void) +{ + unsigned char correction = 0; + mvI2CCharRead(I2C_RTC_ADDR, &correction, 1, I2C_RTC_TIME_TRIM_OFFSET); + printk("correction with 0x%02x\n", correction); +} + +int rtc_ricoh_auto_poweron_init(void) +{ + int err = -1; + u8 csr = 0; + + // disable matched bit + // this will cause #4457 so we mark it + //csr = I2C_RTC_ALARMA_24HOUR; + if ( 0 > (err = mvI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + +#ifdef MY_DEF_HERE + if ( strncmp(gszSynoHWVersion, HW_DS209, strlen(HW_DS209) ) && + strncmp(gszSynoHWVersion, HW_DS409slim, strlen(HW_DS409slim) ) ) + { + rtc_ricoh_time_correction_set(); + rtc_ricoh_time_correction_get(); + } +#endif + + err = 0; + +End: + return err; +} diff --git a/drivers/syno/synobios/rtc/rtc-mv-seiko.c b/drivers/syno/synobios/rtc/rtc-mv-seiko.c new file mode 100644 index 000000000000..986df700bb25 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-mv-seiko.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include "synobios.h" +#include "../i2c/i2c-mv.h" +#include "rtc.h" +#include "../mapping.h" + +/* + * Reset interrupt mode in Status2 register. It'll clear interrupts from RTC. + */ +int rtc_seiko_reset_interrupt_mode(void) +{ + int iRet = -1; + u8 csr = 0x00; + + iRet = mvI2CCharWrite(SEIKO_RTC_STATUS2_ADDR, (u8 *)&csr, 1, -1); + + // enable interrupt mode for auto poweron + // [INT1FE, INT1ME, INT1AE, 32kE, INT2FE, INT2ME, INT2AE, TEST] = [0, 0, 1, 0, 0, 0, 1, 0] + csr = 0x22; + iRet = mvI2CCharWrite(SEIKO_RTC_STATUS2_ADDR, (u8 *)&csr, 1, -1); + + return iRet; +} + +/* + * Write interrupt register on RTC for auto power-on + * + * @param intAddr: SEIKO_RTC_INT1_ADDR or SEIKO_RTC_INT2_ADDR + * @param data: [weekday, hour, min] (Hour: Richo RTC Format) + * @param enable: 0 is disable, otherwise enable + */ +static +int rtc_set_interrupt(const unsigned char intAddr, const unsigned char data[3], const int enable) +{ + int iRet = -1; + unsigned char rgIntReg[3] = {0, 0, 0}; + + if( intAddr != SEIKO_RTC_INT1_ADDR && intAddr != SEIKO_RTC_INT2_ADDR ) { + goto End; + } + + rgIntReg[2] = RB(data[2]); + rgIntReg[1] = RB(data[1]); + rgIntReg[0] = RB(data[0]); + + if( enable ) { + rgIntReg[2] |= 0x01; + rgIntReg[1] |= 0x01; + rgIntReg[0] |= 0x01; + } + + rtc_seiko_reset_interrupt_mode(); + + if( (iRet = mvI2CCharWrite(intAddr, (u8 *)rgIntReg, 3, -1) ) < 0 ) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + SYNORTCALARMPKT alarmTime = {0}; + const unsigned char rgEmptyData[3] = {0, 0, 0}; + unsigned char rgIntReg[3] = {0, 0, 0}; + unsigned char nextWday = 0; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + if( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + rtc_set_interrupt(SEIKO_RTC_INT1_ADDR, rgEmptyData, 0); + rtc_set_interrupt(SEIKO_RTC_INT2_ADDR, rgEmptyData, 0); + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + // RTC have only one weekday saved in a interrupt register + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday+1)%7); + } + rgIntReg[0] = nextWday; + rgIntReg[1] = BIN2BCD(Hour_to_Seiko(alarmTime.hour)); + rgIntReg[2] = BIN2BCD(alarmTime.min); + rtc_set_interrupt(SEIKO_RTC_INT1_ADDR, rgIntReg, 1); + rtc_set_interrupt(SEIKO_RTC_INT2_ADDR, rgEmptyData, 0); + } + + // set *weekdays* to Free register + BIN_TO_BCD(alarmTime.weekdays); + if( (iRet = mvI2CCharWrite(SEIKO_RTC_FREE_ADDR, (u8*)&(alarmTime.weekdays), + sizeof(unsigned char)/sizeof(u8), -1) ) < 0 ) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_get_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + if( (ret = mvI2CCharRead(SEIKO_RTC_REALTIME1_ADDR, (u8 *)rgRtcTimeTemp, + sizeof(rgRtcTimeTemp)/sizeof(unsigned char), -1) < 0) ) { + goto End; + } + + pRtcTimePkt->sec = BCD2BIN(RB(rgRtcTimeTemp[6])); + pRtcTimePkt->min = BCD2BIN(RB(rgRtcTimeTemp[5])); + pRtcTimePkt->hour = Seiko_to_Hour(BCD2BIN(RB(rgRtcTimeTemp[4]))); + pRtcTimePkt->weekday = BCD2BIN(RB(rgRtcTimeTemp[3])); + pRtcTimePkt->day = BCD2BIN(RB(rgRtcTimeTemp[2])); + pRtcTimePkt->month = BCD2BIN(RB(rgRtcTimeTemp[1])); + pRtcTimePkt->year = BCD2BIN(RB(rgRtcTimeTemp[0])); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + /* + * reset the same data to toggle weekday rotation in interrupt registers. + * scemd syncs system time with RTC every 1 hour, so it'll also do rotation. + */ + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_seiko_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +End: + return ret; +} + +int rtc_seiko_set_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int iRet = -1; + SYNO_AUTO_POWERON schedule; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[0] = RB(BIN2BCD(year)); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[1] = RB(BIN2BCD(mon)); + rgRtcTimeTemp[2] = RB(BIN2BCD(pRtcTimePkt->day)); + rgRtcTimeTemp[3] = RB(BIN2BCD(pRtcTimePkt->weekday)); + hrs = Hour_to_Seiko(pRtcTimePkt->hour); + rgRtcTimeTemp[4] = RB(BIN2BCD(hrs)); + rgRtcTimeTemp[5] = RB(BIN2BCD(pRtcTimePkt->min)); + rgRtcTimeTemp[6] = RB(BIN2BCD(pRtcTimePkt->sec)); + + if( (iRet = mvI2CCharWrite(SEIKO_RTC_REALTIME1_ADDR, (u8 *)rgRtcTimeTemp, + sizeof(rgRtcTimeTemp)/sizeof(unsigned char), -1) < 0) ) { + goto End; + } + + /* + * reset the same data to toggle weekday rotation in interrupt registers. + */ + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_seiko_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +End: + return iRet; +} + +void rtc_seiko_time_correction_set(void) +{ + unsigned char correction = module_type_get()->rtc_corr_value; + mvI2CCharWrite(SEIKO_RTC_CORRECT_ADDR, &correction, 1, -1); +} + +void rtc_seiko_time_correction_get(void) +{ + unsigned char correction = 0; + mvI2CCharRead(SEIKO_RTC_CORRECT_ADDR, &correction, 1, -1); + printk("correction with 0x%02x\n", correction); +} + +int rtc_seiko_auto_poweron_init(void) +{ + rtc_seiko_time_correction_set(); + rtc_seiko_time_correction_get(); + return rtc_seiko_reset_interrupt_mode(); +} diff --git a/drivers/syno/synobios/rtc/rtc-mvebu-builtin.c b/drivers/syno/synobios/rtc/rtc-mvebu-builtin.c new file mode 100755 index 000000000000..2606d229f95d --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-mvebu-builtin.c @@ -0,0 +1,214 @@ +#include +#include "rtc.h" + +#define SYNO_RTC_MVEBU_DEVICE "rtc0" + +extern SYNO_AUTO_POWERON gPwSched; + +int rtc_mvebu_set_time(SYNORTCTIMEPKT* pRtcTimePkt) +{ + int iRet = -1; + struct rtc_time tm = {0}; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_MVEBU_DEVICE); + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_MVEBU_DEVICE); + goto End; + } + + tm.tm_sec = pRtcTimePkt->sec; + tm.tm_min = pRtcTimePkt->min; + tm.tm_hour = pRtcTimePkt->hour; + tm.tm_mday = pRtcTimePkt->day; + tm.tm_mon = pRtcTimePkt->month; + tm.tm_year = pRtcTimePkt->year; + tm.tm_wday = pRtcTimePkt->weekday; + + iRet = rtc_set_time(rtc, &tm); + if (iRet) { + printk("synobios: unable to set the hardware clock\n"); + goto End; + } +End: + return iRet; +} + +int rtc_mvebu_get_time(SYNORTCTIMEPKT* pRtcTimePkt) +{ + int iRet = -1; + struct rtc_time tm = {0}; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_MVEBU_DEVICE); + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_MVEBU_DEVICE); + goto End; + } + + if (0 != rtc_read_time(rtc, &tm)) { + printk("synobios: unable to read the hardware clock\n"); + rtc_class_close(rtc); + goto End; + } + + if (0 != rtc_valid_tm(&tm)) { + printk("synobios: invalid date/time read from rtc device\n"); + rtc_class_close(rtc); + goto End; + } + + pRtcTimePkt->sec = tm.tm_sec; + pRtcTimePkt->min = tm.tm_min; + pRtcTimePkt->hour = tm.tm_hour; + pRtcTimePkt->day = tm.tm_mday; + pRtcTimePkt->month = tm.tm_mon; + pRtcTimePkt->year = tm.tm_year; + pRtcTimePkt->weekday = tm.tm_wday; + + iRet = 0; +End: + return iRet; +} + +static int rtc_mvebu_set_alarm_irq_enabled(int enabled) +{ + int iRet = -1; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_MVEBU_DEVICE); + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_MVEBU_DEVICE); + goto End; + } + rtc_alarm_irq_enable(rtc, enabled); + iRet = 0; +End: + return iRet; +} + +int rtc_mvebu_enable_alarm_irq(void) +{ + return rtc_mvebu_set_alarm_irq_enabled(1); +} + +static unsigned long alarm_unix_time_since_1970(unsigned char alarmYear, const struct xtm *nextAlarmTime) +{ + const unsigned long NSM[12] = {0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600}; + const unsigned long OFFSET_1970 = 946684800; // seconds between 1970/01/01 00:00:00 ~ 2000/01/01 00:00:00 + unsigned long seconds = 0; // seconds since 2000/01/01 00:00:00 + + // RTC counts year from 2000. _SynoRtcTimePkt starts from 1900. + if (100 < alarmYear) { + alarmYear = alarmYear - 100; + } + + seconds = alarmYear * 31536000 + (alarmYear / 4) * 86400 + NSM[nextAlarmTime->month - 1] + (nextAlarmTime->monthday - 1) * 86400 + nextAlarmTime->hour * 3600 + nextAlarmTime->minute * 60 + nextAlarmTime->second; + + if (0 != alarmYear % 4 || (0 == alarmYear % 4 && nextAlarmTime->month > 2)) { + seconds += 86400; + } + + return seconds + OFFSET_1970; +} + +static unsigned long convert_next_alarm_time_to_unix_time(const SYNORTCTIMEPKT *pRtcTime) +{ + SYNORTCALARMPKT alarmTime = {0}; + unsigned char nextWday = 0; + int daysLater = 0; + struct xtm nextAlarmTime = {0}; + unsigned char alarmYear = 0; + SYNORTCTIMEPKT rtcNow = {0}; + + rtc_get_alarm_time(&alarmTime, pRtcTime); + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday + 1) % 7); + } + + daysLater = (nextWday - pRtcTime->weekday + 7) % 7; + rtc_mvebu_get_time(&rtcNow); + if (0 == daysLater && (60 * alarmTime.hour + alarmTime.min) <= (60 * rtcNow.hour + rtcNow.min)) { + daysLater = 7; + } + rtc_get_days_later(pRtcTime, daysLater, &nextAlarmTime); + + alarmYear = pRtcTime->year; + // pRtcTime->month is 0-based, pRtcTime->day is 1-based + if (11 == pRtcTime->month && 31 < daysLater + pRtcTime->day) { + alarmYear = alarmYear + 1; + } + nextAlarmTime.hour = alarmTime.hour; + nextAlarmTime.minute = alarmTime.min; + nextAlarmTime.second = 0; + + return alarm_unix_time_since_1970(alarmYear, &nextAlarmTime); +} + +static int rtc_mvebu_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + struct rtc_wkalrm alarm = {0}; + struct rtc_time time= {0}; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_MVEBU_DEVICE);; + + if (NULL == pAutoPowerOn || NULL == pRtcTime) { + goto End; + } + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_MVEBU_DEVICE); + iRet = -1; + goto End; + } + + if (SYNO_AUTO_POWERON_ENABLE == pAutoPowerOn->enabled) { + rtc_time_to_tm(convert_next_alarm_time_to_unix_time(pRtcTime), &time); + alarm.time = time; + alarm.enabled = 1; + rtc_set_alarm(rtc, &alarm); + } + rtc_alarm_irq_enable(rtc, pAutoPowerOn->enabled); + + iRet = 0; +End: + return iRet; +} + +int rtc_mvebu_set_alarm(SYNO_AUTO_POWERON *pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if (NULL == pAutoPowerOn || pAutoPowerOn->num < 0) { + printk("synobios: RTC set alarm parameter error\n"); + goto End; + } + + if (0 != rtc_mvebu_get_time(&rtcTime)) { + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if (0 != rtc_mvebu_rotate_auto_poweron(pAutoPowerOn, &rtcTime)) { + printk("synobios: Failed to set alarm data\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_mvebu_get_alarm(SYNO_AUTO_POWERON* pAutoPowerOn) +{ + int iRet = -1; + + if (NULL == pAutoPowerOn) { + goto End; + } + + memcpy(pAutoPowerOn, &gPwSched, sizeof(SYNO_AUTO_POWERON)); + iRet = 0; +End: + return iRet; +} diff --git a/drivers/syno/synobios/rtc/rtc-mvebu-builtin.h b/drivers/syno/synobios/rtc/rtc-mvebu-builtin.h new file mode 100644 index 000000000000..7b1205b517f2 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-mvebu-builtin.h @@ -0,0 +1,7 @@ +#include "synobios.h" + +int rtc_mvebu_set_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_mvebu_get_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_mvebu_set_alarm(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_mvebu_get_alarm(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_mvebu_enable_alarm_irq(void); diff --git a/drivers/syno/synobios/rtc/rtc-pericom-lib.c b/drivers/syno/synobios/rtc/rtc-pericom-lib.c new file mode 100644 index 000000000000..f10b2644d894 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-pericom-lib.c @@ -0,0 +1,89 @@ +#include "synobios.h" +#include +#include +#include "rtc.h" + +extern SYNO_AUTO_POWERON gPwSched; + +/* + * Time Display Digit Table (in BCD encoding) + * Ricoh: old RTC + * Seiko: new RTC + * + * struct _SynoRtcTimePkt is designed for Ricoh RTC, so we need to + * transform its format from Seiko RTC to Ricoh RTC. + * + * @see: lnxscemd-2.0/modules/rtc.c :: ScemRTCTimeGet() + * @todo: transform struct _SynoRtcTimePkt to traditional 24hr format + * + * +----+-------+-------+---------++----+-------+-------+---------+ + * |24hr| Ricoh | Seiko | Pericom ||24hr| Ricoh | Seiko | Pericom | + * +----+-------+-------+---------++----+-------+-------+---------+ + * |(AM)| | | 12/24 ||(PM)| | 12/24 | 12/24 | + * +----+-------+-------+---------++----+-------+-------+---------+ + * | 00 | 12 | 00 | 52/00 || 12 | 32 | 40/52 | 72/12 | + * | 01 | 01 | 01 | 41/01 || 13 | 21 | 41/53 | 61/13 | + * | 02 | 02 | 02 | 42/02 || 14 | 22 | 42/54 | 62/14 | + * | 03 | 03 | 03 | 43/03 || 15 | 23 | 43/55 | 63/15 | + * | 04 | 04 | 04 | 44/04 || 16 | 24 | 44/56 | 64/16 | + * | 05 | 05 | 05 | 45/05 || 17 | 25 | 45/57 | 65/17 | + * | 06 | 06 | 06 | 46/06 || 18 | 26 | 46/58 | 66/18 | + * | 07 | 07 | 07 | 47/07 || 19 | 27 | 47/59 | 67/19 | + * | 08 | 08 | 08 | 48/08 || 20 | 28 | 48/60 | 68/20 | + * | 09 | 09 | 09 | 49/09 || 21 | 29 | 49/61 | 69/21 | + * | 10 | 10 | 10 | 50/10 || 22 | 30 | 50/62 | 70/22 | + * | 11 | 11 | 11 | 51/11 || 23 | 31 | 51/63 | 71/23 | + * +----+-------+-------+---------++----+-------+-------+---------+ + */ +unsigned char Hour_to_Pericom(const unsigned char hour) +{ + return hour; +} + +unsigned char Pericom_to_Hour(const unsigned char hour) +{ + if( hour == 72 ) { + return 12; + }else if( hour >= 61 ) { + return hour - 48; + }else if( hour == 52 ) { + return 0; + }else if( hour >= 41 ) { + return hour - 40; + } + return hour; +} + +int rtc_pericom_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if( NULL == pAutoPowerOn || pAutoPowerOn->num < 0 ) { + printk("Parameter Error.\n"); + goto End; + } + + if( 0 > rtc_pericom_get_time(&rtcTime) ) { + printk("Failed to get time from rtc.\n"); + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if ( 0 != rtc_pericom_rotate_auto_poweron(pAutoPowerOn, &rtcTime) ) { + printk("Failed to set alarm data.\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_pericom_auto_poweron_uninit(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_pericom_get_time(&rtc_time_pkt); + return rtc_pericom_auto_poweron_init(); +} diff --git a/drivers/syno/synobios/rtc/rtc-plx-ricoh.c b/drivers/syno/synobios/rtc/rtc-plx-ricoh.c new file mode 100644 index 000000000000..4f9eb1c8f5f0 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-plx-ricoh.c @@ -0,0 +1,164 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include "synobios.h" +#include "rtc.h" +#include "../i2c/i2c-plx.h" + +int rtc_ricoh_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int ret = -1; + u8 csr = 0; + SYNORTCALARMPKT alarmTime = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + // get Alarm enable bit + if ( 0 > (ret = plxI2CCharRead(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + if ( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + // disable Alarm enable bit + csr &= ~I2C_RTC_ALARMA_ENABLE; + if ( 0 > (ret = plxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + alarmTime.hour = Hour_to_Ricoh(alarmTime.hour); + BIN_TO_BCD(alarmTime.hour); + BIN_TO_BCD(alarmTime.min); + + // enable Alarm + csr |= I2C_RTC_ALARMAB_SL; + csr |= I2C_RTC_ALARMA_ENABLE; + + if ( 0 > (ret = plxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + csr = 0; + if ( 0 > (ret = plxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + + // set Alarm data + if( 0 > (ret = plxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&alarmTime, + sizeof(SYNORTCALARMPKT)/sizeof(u8), I2C_RTC_ALARMA_OFFSET)) ) { + goto End; + } + } + + ret = 0; +End: + return ret; +} + +int rtc_ricoh_get_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + unsigned char hrs; + SYNO_AUTO_POWERON schedule; + + if ( 0 != (ret = plxI2CCharRead(0x32, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + goto END; + } + + pRtcTimePkt->sec = BCD2BIN(rgRtcTimeTemp[0]); + pRtcTimePkt->min = BCD2BIN(rgRtcTimeTemp[1]); + hrs = BCD2BIN(rgRtcTimeTemp[2]); + pRtcTimePkt->hour = Ricoh_to_Hour(hrs); + pRtcTimePkt->weekday = BCD2BIN(rgRtcTimeTemp[3]); + pRtcTimePkt->day = BCD2BIN(rgRtcTimeTemp[4]); + pRtcTimePkt->month = BCD2BIN(rgRtcTimeTemp[5]); + pRtcTimePkt->year = BCD2BIN(rgRtcTimeTemp[6]); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +END: + return ret; +} + +int rtc_ricoh_set_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[6] = BIN2BCD(year); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[5] = BIN2BCD(mon); + rgRtcTimeTemp[4] = BIN2BCD(pRtcTimePkt->day); + rgRtcTimeTemp[3] = BIN2BCD(pRtcTimePkt->weekday); + hrs = Hour_to_Ricoh(pRtcTimePkt->hour); + rgRtcTimeTemp[2] = BIN2BCD(hrs); + rgRtcTimeTemp[1] = BIN2BCD(pRtcTimePkt->min); + rgRtcTimeTemp[0] = BIN2BCD(pRtcTimePkt->sec); + + if ( 0 != (ret = plxI2CCharWrite(0x32, (u8 *)rgRtcTimeTemp, 7, 0)) ) { + ret = -1; + } + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return ret; +} + +void rtc_ricoh_time_correction_set(void) +{ + unsigned char correction = 0x0f; + plxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&correction, 1, I2C_RTC_TIME_TRIM_OFFSET); +} + +void rtc_ricoh_time_correction_get(void) +{ + unsigned char correction = 0; + plxI2CCharRead(I2C_RTC_ADDR, &correction, 1, I2C_RTC_TIME_TRIM_OFFSET); + printk("correction with 0x%02x\n", correction); +} + +int rtc_ricoh_auto_poweron_init(void) +{ + int err = -1; + u8 csr = 0; + + // disable matched bit + // this will cause #4457 so we mark it + //csr = I2C_RTC_ALARMA_24HOUR; + if ( 0 > (err = plxI2CCharWrite(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + +#ifdef MY_DEF_HERE + if ( strncmp(gszSynoHWVersion, HW_DS209, strlen(HW_DS209) ) && + strncmp(gszSynoHWVersion, HW_DS409slim, strlen(HW_DS409slim) ) ) + { + rtc_ricoh_time_correction_set(); + rtc_ricoh_time_correction_get(); + } +#endif + + err = 0; + +End: + return err; +} diff --git a/drivers/syno/synobios/rtc/rtc-plx-seiko.c b/drivers/syno/synobios/rtc/rtc-plx-seiko.c new file mode 100644 index 000000000000..c61113f91fb1 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-plx-seiko.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include "synobios.h" +#include "../i2c/i2c-plx.h" +#include "rtc.h" + +/* + * Reset interrupt mode in Status2 register. It'll clear interrupts from RTC. + */ +int rtc_seiko_reset_interrupt_mode(void) +{ + int iRet = -1; + u8 csr = 0x00; + + iRet = plxI2CCharWrite(SEIKO_RTC_STATUS2_ADDR, (u8 *)&csr, 1, -1); + + // enable interrupt mode for auto poweron + // [INT1FE, INT1ME, INT1AE, 32kE, INT2FE, INT2ME, INT2AE, TEST] = [0, 0, 1, 0, 0, 0, 1, 0] + csr = 0x22; + iRet = plxI2CCharWrite(SEIKO_RTC_STATUS2_ADDR, (u8 *)&csr, 1, -1); + + return iRet; +} + +/* + * Write interrupt register on RTC for auto power-on + * + * @param intAddr: SEIKO_RTC_INT1_ADDR or SEIKO_RTC_INT2_ADDR + * @param data: [weekday, hour, min] (Hour: Richo RTC Format) + * @param enable: 0 is disable, otherwise enable + */ +static +int rtc_set_interrupt(const unsigned char intAddr, const unsigned char data[3], const int enable) +{ + int iRet = -1; + unsigned char rgIntReg[3] = {0, 0, 0}; + + if( intAddr != SEIKO_RTC_INT1_ADDR && intAddr != SEIKO_RTC_INT2_ADDR ) { + goto End; + } + + rgIntReg[2] = RB(data[2]); + rgIntReg[1] = RB(data[1]); + rgIntReg[0] = RB(data[0]); + + if( enable ) { + rgIntReg[2] |= 0x01; + rgIntReg[1] |= 0x01; + rgIntReg[0] |= 0x01; + } + + rtc_seiko_reset_interrupt_mode(); + + if( (iRet = plxI2CCharWrite(intAddr, (u8 *)rgIntReg, 3, -1) ) < 0 ) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + SYNORTCALARMPKT alarmTime = {0}; + const unsigned char rgEmptyData[3] = {0, 0, 0}; + unsigned char rgIntReg[3] = {0, 0, 0}; + unsigned char nextWday = 0; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + if( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + rtc_set_interrupt(SEIKO_RTC_INT1_ADDR, rgEmptyData, 0); + rtc_set_interrupt(SEIKO_RTC_INT2_ADDR, rgEmptyData, 0); + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + // RTC have only one weekday saved in a interrupt register + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday+1)%7); + } + rgIntReg[0] = nextWday; + rgIntReg[1] = BIN2BCD(Hour_to_Seiko(alarmTime.hour)); + rgIntReg[2] = BIN2BCD(alarmTime.min); + rtc_set_interrupt(SEIKO_RTC_INT1_ADDR, rgIntReg, 1); + rtc_set_interrupt(SEIKO_RTC_INT2_ADDR, rgEmptyData, 0); + } + + // set *weekdays* to Free register + BIN_TO_BCD(alarmTime.weekdays); + if( (iRet = plxI2CCharWrite(SEIKO_RTC_FREE_ADDR, (u8*)&(alarmTime.weekdays), + sizeof(unsigned char)/sizeof(u8), -1) ) < 0 ) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_get_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + if( (ret = plxI2CCharRead(SEIKO_RTC_REALTIME1_ADDR, (u8 *)rgRtcTimeTemp, + sizeof(rgRtcTimeTemp)/sizeof(unsigned char), -1) < 0) ) { + goto End; + } + + pRtcTimePkt->sec = BCD2BIN(RB(rgRtcTimeTemp[6])); + pRtcTimePkt->min = BCD2BIN(RB(rgRtcTimeTemp[5])); + pRtcTimePkt->hour = Seiko_to_Hour(BCD2BIN(RB(rgRtcTimeTemp[4]))); + pRtcTimePkt->weekday = BCD2BIN(RB(rgRtcTimeTemp[3])); + pRtcTimePkt->day = BCD2BIN(RB(rgRtcTimeTemp[2])); + pRtcTimePkt->month = BCD2BIN(RB(rgRtcTimeTemp[1])); + pRtcTimePkt->year = BCD2BIN(RB(rgRtcTimeTemp[0])); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + /* + * reset the same data to toggle weekday rotation in interrupt registers. + * scemd syncs system time with RTC every 1 hour, so it'll also do rotation. + */ + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_seiko_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +End: + return ret; +} + +int rtc_seiko_set_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + int iRet = -1; + SYNO_AUTO_POWERON schedule; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[0] = RB(BIN2BCD(year)); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[1] = RB(BIN2BCD(mon)); + rgRtcTimeTemp[2] = RB(BIN2BCD(pRtcTimePkt->day)); + rgRtcTimeTemp[3] = RB(BIN2BCD(pRtcTimePkt->weekday)); + hrs = Hour_to_Seiko(pRtcTimePkt->hour); + rgRtcTimeTemp[4] = RB(BIN2BCD(hrs)); + rgRtcTimeTemp[5] = RB(BIN2BCD(pRtcTimePkt->min)); + rgRtcTimeTemp[6] = RB(BIN2BCD(pRtcTimePkt->sec)); + + if( (iRet = plxI2CCharWrite(SEIKO_RTC_REALTIME1_ADDR, (u8 *)rgRtcTimeTemp, + sizeof(rgRtcTimeTemp)/sizeof(unsigned char), -1) < 0) ) { + goto End; + } + + /* + * reset the same data to toggle weekday rotation in interrupt registers. + */ + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_seiko_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +End: + return iRet; +} + +void rtc_seiko_time_correction_set(void) +{ + unsigned char correction = 3; /* -5.62 sec/day */ + plxI2CCharWrite(SEIKO_RTC_CORRECT_ADDR, &correction, 1, -1); +} + +void rtc_seiko_time_correction_get(void) +{ + unsigned char correction = 0; + plxI2CCharRead(SEIKO_RTC_CORRECT_ADDR, &correction, 1, -1); + printk("correction with 0x%02x\n", correction); +} + +int rtc_seiko_auto_poweron_init(void) +{ + rtc_seiko_time_correction_set(); + rtc_seiko_time_correction_get(); + return rtc_seiko_reset_interrupt_mode(); +} diff --git a/drivers/syno/synobios/rtc/rtc-ppc-ricoh.c b/drivers/syno/synobios/rtc/rtc-ppc-ricoh.c new file mode 100644 index 000000000000..b056e66a5b74 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-ppc-ricoh.c @@ -0,0 +1,158 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include "synobios.h" +#include "rtc.h" +#include "../i2c/i2c-ppc.h" + +int rtc_ricoh_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + u8 csr = 0; + SYNORTCALARMPKT alarmTime = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + // get Alarm enable bit + if ( 0 > (iRet = mpc_i2c_read(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), 0, I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + if ( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + // disable Alarm enable bit + csr &= ~I2C_RTC_ALARMA_ENABLE; + if ( 0 > (iRet = mpc_i2c_write(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), 0, I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + } else { + rtc_get_alarm_time(&alarmTime, pRtcTime); + alarmTime.hour = Hour_to_Ricoh(alarmTime.hour); + BIN_TO_BCD(alarmTime.hour); + BIN_TO_BCD(alarmTime.min); + + // enable Alarm + csr |= I2C_RTC_ALARMAB_SL; + csr |= I2C_RTC_ALARMA_ENABLE; + if ( 0 > (iRet = mpc_i2c_write(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), 0, I2C_RTC_CONTROL1_OFFSET)) ) { + goto End; + } + + csr = 0; + if ( 0 > (iRet = mpc_i2c_write(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), 0, I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + + // set Alarm data + if ( 0 > (iRet = mpc_i2c_write(I2C_RTC_ADDR, (u8 *)&alarmTime, sizeof(SYNORTCALARMPKT)/sizeof(u8), 0, I2C_RTC_ALARMA_OFFSET)) ) { + goto End; + } + } + + iRet = 0; +End: + return iRet; +} + +int rtc_ricoh_get_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char rgRtcTimeTemp[7]; + unsigned char hrs; + SYNO_AUTO_POWERON schedule; + + ret = mpc_i2c_read(0x32, (u8 *)rgRtcTimeTemp, 7, 0, 0); + if (0 > ret){ + goto END; + } + + pRtcTimePkt->sec = BCD2BIN(rgRtcTimeTemp[0]); + pRtcTimePkt->min = BCD2BIN(rgRtcTimeTemp[1]); + hrs = BCD2BIN(rgRtcTimeTemp[2]); + pRtcTimePkt->hour = Ricoh_to_Hour(hrs); + pRtcTimePkt->weekday = BCD2BIN(rgRtcTimeTemp[3]); + pRtcTimePkt->day = BCD2BIN(rgRtcTimeTemp[4]); + pRtcTimePkt->month = BCD2BIN(rgRtcTimeTemp[5]); + pRtcTimePkt->year = BCD2BIN(rgRtcTimeTemp[6]); + + pRtcTimePkt->year += 100; + pRtcTimePkt->month -= 1; + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + +END: + return ret; +} + +int rtc_ricoh_set_time(struct _SynoRtcTimePkt *pRtcTimePkt) +{ + int ret = 0; + unsigned char year, mon, hrs; + unsigned char rgRtcTimeTemp[7]; + SYNO_AUTO_POWERON schedule; + + year = ((pRtcTimePkt->year + 1900 > 2000) ? (pRtcTimePkt->year - 100) : 0); + rgRtcTimeTemp[6] = BIN2BCD(year); + mon = pRtcTimePkt->month + 1; + rgRtcTimeTemp[5] = BIN2BCD(mon); + rgRtcTimeTemp[4] = BIN2BCD(pRtcTimePkt->day); + rgRtcTimeTemp[3] = BIN2BCD(pRtcTimePkt->weekday); + hrs = Hour_to_Ricoh(pRtcTimePkt->hour); + rgRtcTimeTemp[2] = BIN2BCD(hrs); + rgRtcTimeTemp[1] = BIN2BCD(pRtcTimePkt->min); + rgRtcTimeTemp[0] = BIN2BCD(pRtcTimePkt->sec); + + ret = mpc_i2c_write(0x32, (u8 *)rgRtcTimeTemp, 7, 0, 0); + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_ricoh_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return ret; +} + +void rtc_ricoh_time_correction_set(void) +{ + unsigned char correction = 0x0f; + mpc_i2c_write(I2C_RTC_ADDR, (u8 *)&correction, 1, 0, I2C_RTC_TIME_TRIM_OFFSET); +} + +void rtc_ricoh_time_correction_get(void) +{ + unsigned char correction = 0; + mpc_i2c_read(I2C_RTC_ADDR, (u8 *)&correction, 1, 0, I2C_RTC_TIME_TRIM_OFFSET); + printk("correction with 0x%02x\n", correction); +} + +int rtc_ricoh_auto_poweron_init(void) +{ + int err = -1; + u8 csr = 0; + + // disable matched bit + if ( 0 > (err = mpc_i2c_write(I2C_RTC_ADDR, (u8 *)&csr, sizeof(csr)/sizeof(u8), 0, I2C_RTC_CONTROL2_OFFSET)) ) { + goto End; + } + +#ifdef MY_DEF_HERE + if ( strncmp(gszSynoHWVersion, HW_DS409p, strlen(HW_DS409p) ) && + strncmp(gszSynoHWVersion, HW_DS410, strlen(HW_DS410) ) ) + { + rtc_ricoh_time_correction_set(); + rtc_ricoh_time_correction_get(); + } +#endif + + err = 0; + +End: + return err; +} diff --git a/drivers/syno/synobios/rtc/rtc-ricoh-lib.c b/drivers/syno/synobios/rtc/rtc-ricoh-lib.c new file mode 100644 index 000000000000..05904c03fd7a --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-ricoh-lib.c @@ -0,0 +1,93 @@ +#include "synobios.h" +#include +#include +#include "rtc.h" + +extern SYNO_AUTO_POWERON gPwSched; + +/* + * Time Display Digit Table (in BCD encoding) + * Ricoh: old RTC + * Seiko: new RTC + * + * struct _SynoRtcTimePkt is designed for Ricoh RTC, so we need to + * transform its format from Seiko RTC to Ricoh RTC. + * + * @see: lnxscemd-2.0/modules/rtc.c :: ScemRTCTimeGet() + * @todo: transform struct _SynoRtcTimePkt to traditional 24hr format + * + * +----+-------+-------+ +----+-------+--------+ + * |24hr| Ricoh | Seiko | |24hr| Ricoh | Seiko | + * +----+-------+-------+ +----+-------+--------+ + * |(AM)| | | |(PM)| | 12/24 | + * | 00 | 12 | 00 | | 12 | 32 | 40/52 | + * | 01 | 01 | 01 | | 13 | 21 | 41/53 | + * | 02 | 02 | 02 | | 14 | 22 | 42/54 | + * | 03 | 03 | 03 | | 15 | 23 | 43/55 | + * | 04 | 04 | 04 | | 16 | 24 | 44/56 | + * | 05 | 05 | 05 | | 17 | 25 | 45/57 | + * | 06 | 06 | 06 | | 18 | 26 | 46/58 | + * | 07 | 07 | 07 | | 19 | 27 | 47/59 | + * | 08 | 08 | 08 | | 20 | 28 | 48/60 | + * | 09 | 09 | 09 | | 21 | 29 | 49/61 | + * | 10 | 10 | 10 | | 22 | 30 | 50/62 | + * | 11 | 11 | 11 | | 23 | 31 | 51/63 | + * +----+-------+-------+ +----+-------+--------+ + */ +unsigned char Hour_to_Ricoh(const unsigned char hour) +{ + if ( hour == 0 ) { + return 12; + }else if( hour == 12 ) { + return 32; + }else if( hour > 12 ) { + return hour + 8; + } + return hour; +} + +unsigned char Ricoh_to_Hour(const unsigned char hour) +{ + if( hour == 12 ) { + return 0; + }else if( hour == 32 ) { + return 12; + }else if( hour >= 21 ) { + return hour - 8; + } + return hour; +} + +int rtc_ricoh_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if( NULL == pAutoPowerOn || pAutoPowerOn->num < 0 ) { + printk("Parameter Error.\n"); + goto End; + } + + if( 0 > rtc_ricoh_get_time(&rtcTime) ) { + printk("Failed to get time from rtc.\n"); + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if ( 0 != rtc_ricoh_rotate_auto_poweron(pAutoPowerOn, &rtcTime) ) { + printk("Failed to set alarm data.\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_ricoh_auto_poweron_uninit(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_ricoh_get_time(&rtc_time_pkt); + return rtc_ricoh_auto_poweron_init(); +} diff --git a/drivers/syno/synobios/rtc/rtc-rtk-builtin.c b/drivers/syno/synobios/rtc/rtc-rtk-builtin.c new file mode 100755 index 000000000000..057d0e2a2f4f --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-rtk-builtin.c @@ -0,0 +1,214 @@ +#include +#include "rtc.h" + +#define SYNO_RTC_RTK_DEVICE "rtc0" + +extern SYNO_AUTO_POWERON gPwSched; + +int rtc_rtk_set_time(SYNORTCTIMEPKT* pRtcTimePkt) +{ + int iRet = -1; + struct rtc_time tm = {0}; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_RTK_DEVICE); + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_RTK_DEVICE); + goto End; + } + + tm.tm_sec = pRtcTimePkt->sec; + tm.tm_min = pRtcTimePkt->min; + tm.tm_hour = pRtcTimePkt->hour; + tm.tm_mday = pRtcTimePkt->day; + tm.tm_mon = pRtcTimePkt->month; + tm.tm_year = pRtcTimePkt->year; + tm.tm_wday = pRtcTimePkt->weekday; + + iRet = rtc_set_time(rtc, &tm); + if (iRet) { + printk("synobios: unable to set the hardware clock\n"); + goto End; + } +End: + return iRet; +} + +int rtc_rtk_get_time(SYNORTCTIMEPKT* pRtcTimePkt) +{ + int iRet = -1; + struct rtc_time tm = {0}; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_RTK_DEVICE); + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_RTK_DEVICE); + goto End; + } + + if (0 != rtc_read_time(rtc, &tm)) { + printk("synobios: unable to read the hardware clock\n"); + rtc_class_close(rtc); + goto End; + } + + if (0 != rtc_valid_tm(&tm)) { + printk("synobios: invalid date/time read from rtc device\n"); + rtc_class_close(rtc); + goto End; + } + + pRtcTimePkt->sec = tm.tm_sec; + pRtcTimePkt->min = tm.tm_min; + pRtcTimePkt->hour = tm.tm_hour; + pRtcTimePkt->day = tm.tm_mday; + pRtcTimePkt->month = tm.tm_mon; + pRtcTimePkt->year = tm.tm_year; + pRtcTimePkt->weekday = tm.tm_wday; + + iRet = 0; +End: + return iRet; +} + +static int rtc_rtk_set_alarm_irq_enabled(int enabled) +{ + int iRet = -1; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_RTK_DEVICE); + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_RTK_DEVICE); + goto End; + } + rtc_alarm_irq_enable(rtc, enabled); + iRet = 0; +End: + return iRet; +} + +int rtc_rtk_enable_alarm_irq(void) +{ + return rtc_rtk_set_alarm_irq_enabled(1); +} + +static unsigned long alarm_unix_time_since_1970(unsigned char alarmYear, const struct xtm *nextAlarmTime) +{ + const unsigned long NSM[12] = {0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600}; + const unsigned long OFFSET_1970 = 946684800; // seconds between 1970/01/01 00:00:00 ~ 2000/01/01 00:00:00 + unsigned long seconds = 0; // seconds since 2000/01/01 00:00:00 + + // RTC counts year from 2000. _SynoRtcTimePkt starts from 1900. + if (100 < alarmYear) { + alarmYear = alarmYear - 100; + } + + seconds = alarmYear * 31536000 + (alarmYear / 4) * 86400 + NSM[nextAlarmTime->month - 1] + (nextAlarmTime->monthday - 1) * 86400 + nextAlarmTime->hour * 3600 + nextAlarmTime->minute * 60 + nextAlarmTime->second; + + if (0 != alarmYear % 4 || (0 == alarmYear % 4 && nextAlarmTime->month > 2)) { + seconds += 86400; + } + + return seconds + OFFSET_1970; +} + +static unsigned long convert_next_alarm_time_to_unix_time(const SYNORTCTIMEPKT *pRtcTime) +{ + SYNORTCALARMPKT alarmTime = {0}; + unsigned char nextWday = 0; + int daysLater = 0; + struct xtm nextAlarmTime = {0}; + unsigned char alarmYear = 0; + SYNORTCTIMEPKT rtcNow = {0}; + + rtc_get_alarm_time(&alarmTime, pRtcTime); + nextWday = rtc_get_next_weekday(alarmTime.weekdays, pRtcTime->weekday); + if (rtc_later_equal_than_int(pRtcTime->hour, pRtcTime->min, alarmTime.hour, alarmTime.min)) { + nextWday = rtc_get_next_weekday(alarmTime.weekdays, (pRtcTime->weekday + 1) % 7); + } + + daysLater = (nextWday - pRtcTime->weekday + 7) % 7; + rtc_rtk_get_time(&rtcNow); + if (0 == daysLater && (60 * alarmTime.hour + alarmTime.min) <= (60 * rtcNow.hour + rtcNow.min)) { + daysLater = 7; + } + rtc_get_days_later(pRtcTime, daysLater, &nextAlarmTime); + + alarmYear = pRtcTime->year; + // pRtcTime->month is 0-based, pRtcTime->day is 1-based + if (11 == pRtcTime->month && 31 < daysLater + pRtcTime->day) { + alarmYear = alarmYear + 1; + } + nextAlarmTime.hour = alarmTime.hour; + nextAlarmTime.minute = alarmTime.min; + nextAlarmTime.second = 0; + + return alarm_unix_time_since_1970(alarmYear, &nextAlarmTime); +} + +static int rtc_rtk_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + struct rtc_wkalrm alarm = {0}; + struct rtc_time time= {0}; + struct rtc_device *rtc = rtc_class_open(SYNO_RTC_RTK_DEVICE);; + + if (NULL == pAutoPowerOn || NULL == pRtcTime) { + goto End; + } + + if (rtc == NULL) { + printk("synobios: unable to open rtc device (%s)\n", SYNO_RTC_RTK_DEVICE); + iRet = -1; + goto End; + } + + if (SYNO_AUTO_POWERON_ENABLE == pAutoPowerOn->enabled) { + rtc_time_to_tm(convert_next_alarm_time_to_unix_time(pRtcTime), &time); + alarm.time = time; + alarm.enabled = 1; + rtc_set_alarm(rtc, &alarm); + } + rtc_alarm_irq_enable(rtc, pAutoPowerOn->enabled); + + iRet = 0; +End: + return iRet; +} + +int rtc_rtk_set_alarm(SYNO_AUTO_POWERON *pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if (NULL == pAutoPowerOn || pAutoPowerOn->num < 0) { + printk("synobios: RTC set alarm parameter error\n"); + goto End; + } + + if (0 != rtc_rtk_get_time(&rtcTime)) { + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if (0 != rtc_rtk_rotate_auto_poweron(pAutoPowerOn, &rtcTime)) { + printk("synobios: Failed to set alarm data\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_rtk_get_alarm(SYNO_AUTO_POWERON* pAutoPowerOn) +{ + int iRet = -1; + + if (NULL == pAutoPowerOn) { + goto End; + } + + memcpy(pAutoPowerOn, &gPwSched, sizeof(SYNO_AUTO_POWERON)); + iRet = 0; +End: + return iRet; +} diff --git a/drivers/syno/synobios/rtc/rtc-rtk-builtin.h b/drivers/syno/synobios/rtc/rtc-rtk-builtin.h new file mode 100644 index 000000000000..d1894e6412c4 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-rtk-builtin.h @@ -0,0 +1,7 @@ +#include + +int rtc_rtk_set_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_rtk_get_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_rtk_set_alarm(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_rtk_get_alarm(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_rtk_enable_alarm_irq(void); diff --git a/drivers/syno/synobios/rtc/rtc-seiko-lib.c b/drivers/syno/synobios/rtc/rtc-seiko-lib.c new file mode 100644 index 000000000000..5b63f32198ef --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-seiko-lib.c @@ -0,0 +1,102 @@ +#include "synobios.h" +#include +#include +#include "rtc.h" + +extern SYNO_AUTO_POWERON gPwSched; + +#define CHAR_BIT 8 +unsigned char reverse_bits(unsigned char v) { + unsigned char r = v; // r will be reversed bits of v; first get LSB of v + int s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end + + for( v >>= 1; v; v >>= 1 ) { + r <<= 1; + r |= v & 1; + s--; + } + return r <<= s; // shift when v's highest bits are zero +} + +/* + * Time Display Digit Table (in BCD encoding) + * Ricoh: old RTC + * Seiko: new RTC + * + * struct _SynoRtcTimePkt is designed for Ricoh RTC, so we need to + * transform its format from Seiko RTC to Ricoh RTC. + * + * @see: lnxscemd-2.0/modules/rtc.c :: ScemRTCTimeGet() + * @todo: transform struct _SynoRtcTimePkt to traditional 24hr format + * + * +----+-------+-------+ +----+-------+--------+ + * |24hr| Ricoh | Seiko | |24hr| Ricoh | Seiko | + * +----+-------+-------+ +----+-------+--------+ + * |(AM)| | | |(PM)| | 12/24 | + * | 00 | 12 | 00 | | 12 | 32 | 40/52 | + * | 01 | 01 | 01 | | 13 | 21 | 41/53 | + * | 02 | 02 | 02 | | 14 | 22 | 42/54 | + * | 03 | 03 | 03 | | 15 | 23 | 43/55 | + * | 04 | 04 | 04 | | 16 | 24 | 44/56 | + * | 05 | 05 | 05 | | 17 | 25 | 45/57 | + * | 06 | 06 | 06 | | 18 | 26 | 46/58 | + * | 07 | 07 | 07 | | 19 | 27 | 47/59 | + * | 08 | 08 | 08 | | 20 | 28 | 48/60 | + * | 09 | 09 | 09 | | 21 | 29 | 49/61 | + * | 10 | 10 | 10 | | 22 | 30 | 50/62 | + * | 11 | 11 | 11 | | 23 | 31 | 51/63 | + * +----+-------+-------+ +----+-------+--------+ + */ +unsigned char Hour_to_Seiko(const unsigned char hour) +{ + if( hour > 11 ) { + return hour + 28; + } + return hour; +} + +unsigned char Seiko_to_Hour(const unsigned char hour) +{ + if( hour >= 52 ) { + return hour - 40; + } else if( hour >= 40 ) { + return hour - 28; + } + return hour; +} + +int rtc_seiko_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if( NULL == pAutoPowerOn || pAutoPowerOn->num < 0 ) { + printk("Parameter Error.\n"); + goto End; + } + + if( 0 > rtc_seiko_get_time(&rtcTime) ) { + printk("Failed to get time from rtc.\n"); + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if ( 0 != rtc_seiko_rotate_auto_poweron(pAutoPowerOn, &rtcTime) ) { + printk("Failed to set alarm data.\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int rtc_seiko_auto_poweron_uninit(void) +{ + // fetch rtc time to reset the same data to toggle weekday rotation in interrupt registers. + SYNORTCTIMEPKT rtc_time_pkt; + rtc_seiko_get_time(&rtc_time_pkt); + + return rtc_seiko_reset_interrupt_mode(); +} diff --git a/drivers/syno/synobios/rtc/rtc-x86.c b/drivers/syno/synobios/rtc/rtc-x86.c new file mode 100755 index 000000000000..983a0e3708f6 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc-x86.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include + +#include "synobios.h" +#include "localtime.h" +#include "rtc.h" + +#ifdef CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE +#include +#endif /* CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE */ + +#define RTC_IRQMASK (RTC_PF | RTC_AF | RTC_UF) +#define RTC_MDAY_ALARM_MASK 0x3F + +extern SYNO_AUTO_POWERON gPwSched; +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +#if 0 +static +void rtc_bandon_dump(void) +{ + spin_lock_irq(&rtc_lock); + printk("##################################\n"); + printk("CMOS_READ(RTC_YEAR) =%02d\n", BCD2BIN(CMOS_READ(RTC_YEAR))); + printk("CMOS_READ(RTC_MONTH) =%02d\n", BCD2BIN(CMOS_READ(RTC_MONTH))); + printk("CMOS_READ(RTC_DAY_OF_MONTH) =%02d\n", BCD2BIN(CMOS_READ(RTC_DAY_OF_MONTH))); + printk("CMOS_READ(RTC_DAY_OF_WEEK) =%02d\n", CMOS_READ(RTC_DAY_OF_WEEK)); + printk("CMOS_READ(RTC_HOURS) =%02d\n", BCD2BIN(CMOS_READ(RTC_HOURS))); + printk("CMOS_READ(RTC_MINUTES) =%02d\n", BCD2BIN(CMOS_READ(RTC_MINUTES))); + printk("CMOS_READ(RTC_SECONDS) =%02d\n", BCD2BIN(CMOS_READ(RTC_SECONDS))); + printk("CMOS_READ(RTC_HOURS_ALARM) =%02d\n", BCD2BIN(CMOS_READ(RTC_HOURS_ALARM))); + printk("CMOS_READ(RTC_MINUTES_ALARM)=%02d\n", BCD2BIN(CMOS_READ(RTC_MINUTES_ALARM))); + printk("CMOS_READ(RTC_SECONDS_ALARM)=%02d\n", BCD2BIN(CMOS_READ(RTC_SECONDS_ALARM))); + printk("CMOS_READ(RTC_VALID) =0x%02x\n", CMOS_READ(RTC_VALID)); + printk("CMOS_READ(RTC_CONTROL) =0x%02x\n", CMOS_READ(RTC_CONTROL)); + printk("CMOS_READ(RTC_INTR_FLAGS) =0x%02x\n", CMOS_READ(RTC_INTR_FLAGS)); + spin_unlock_irq(&rtc_lock); +} +#endif + +static +int rtc_correct_wday(SYNORTCTIMEPKT *pRtcTime) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + time64_t t; +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + time_t t; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + + struct xtm taget_time; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + t = mktime64(pRtcTime->year+1900, pRtcTime->month+1, pRtcTime->day, pRtcTime->hour, pRtcTime->min, pRtcTime->sec); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + t = mktime(pRtcTime->year+1900, pRtcTime->month+1, pRtcTime->day, pRtcTime->hour, pRtcTime->min, pRtcTime->sec); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + localtime_1(&taget_time, t); + localtime_2(&taget_time, t); + localtime_3(&taget_time, t); + + //correct weekday + if ( taget_time.weekday != pRtcTime->weekday ) { + pRtcTime->weekday = taget_time.weekday; + + spin_lock_irq(&rtc_lock); + CMOS_WRITE(pRtcTime->weekday, RTC_DAY_OF_WEEK); + spin_unlock_irq(&rtc_lock); + } + + return pRtcTime->weekday; +} + +int rtc_bandon_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime) +{ + int iRet = -1; + unsigned char mday_result = 0; + unsigned char hrs_result = 0; + unsigned char min_result = 0; + unsigned char sec_result = 0; + unsigned char rtc_control, rtc_valid; + SYNORTCALARMPKT alarmTime = {0}; + + if( NULL == pAutoPowerOn || NULL == pRtcTime ) { + goto End; + } + + if ( SYNO_AUTO_POWERON_DISABLE == pAutoPowerOn->enabled ) { + mday_result = BIN2BCD(32); + hrs_result = BIN2BCD(25); + min_result = BIN2BCD(61); + sec_result = BIN2BCD(61); + } else { + mday_result = rtc_get_alarm_time(&alarmTime, pRtcTime); + BIN_TO_BCD(mday_result); + hrs_result = BIN2BCD(alarmTime.hour); + min_result = BIN2BCD(alarmTime.min); + } + sec_result = 0; + + spin_lock_irq(&rtc_lock); +#ifdef CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE + acpi_disable_event(ACPI_EVENT_RTC, 0); +#endif /* CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE */ + rtc_control = CMOS_READ(RTC_CONTROL); + rtc_control &= ~RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + rtc_valid = pAutoPowerOn->enabled ? ((CMOS_READ(RTC_VALID) & ~RTC_MDAY_ALARM_MASK) | mday_result) : 0; + + CMOS_WRITE(rtc_valid, RTC_VALID); + CMOS_WRITE(hrs_result, RTC_HOURS_ALARM); + CMOS_WRITE(min_result, RTC_MINUTES_ALARM); + CMOS_WRITE(sec_result, RTC_SECONDS_ALARM); + + if (pAutoPowerOn->enabled) { +#ifdef CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE + acpi_enable_event(ACPI_EVENT_RTC, 0); +#endif /* CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE */ + rtc_control |= RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + } + spin_unlock_irq(&rtc_lock); + + iRet = 0; +End: + return iRet; +} + +int rtc_bandon_set_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn) +{ + int iRet = -1; + SYNORTCTIMEPKT rtcTime; + + if( NULL == pAutoPowerOn || pAutoPowerOn->num < 0 ) { + printk("Parameter Error.\n"); + goto End; + } + + if( 0 > rtc_bandon_get_time(&rtcTime) ) { + printk("Failed to get time from rtc.\n"); + goto End; + } + + memcpy(&gPwSched, pAutoPowerOn, sizeof(SYNO_AUTO_POWERON)); + + if ( 0 != rtc_bandon_rotate_auto_poweron(pAutoPowerOn, &rtcTime) ) { + printk("Failed to set alarm data.\n"); + goto End; + } + + iRet = 0; +End: + return iRet; +} + +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char rtc_is_updating(void) +{ + unsigned char uip; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + +int rtc_bandon_get_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + unsigned long flags; + unsigned char ctrl; + SYNO_AUTO_POWERON schedule; + + /* + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + if (rtc_is_updating()) + mdelay(20); + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Note that while the + * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is + * only updated by the RTC when initially set to a non-zero value. + */ + spin_lock_irqsave(&rtc_lock, flags); + ctrl = CMOS_READ(RTC_CONTROL); + pRtcTimePkt->sec = CMOS_READ(RTC_SECONDS); + pRtcTimePkt->min = CMOS_READ(RTC_MINUTES); + pRtcTimePkt->hour = CMOS_READ(RTC_HOURS); + pRtcTimePkt->day = CMOS_READ(RTC_DAY_OF_MONTH); + pRtcTimePkt->month = CMOS_READ(RTC_MONTH); + pRtcTimePkt->weekday = CMOS_READ(RTC_DAY_OF_WEEK); + pRtcTimePkt->year = CMOS_READ(RTC_YEAR); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(pRtcTimePkt->sec); + BCD_TO_BIN(pRtcTimePkt->min); + BCD_TO_BIN(pRtcTimePkt->hour); + BCD_TO_BIN(pRtcTimePkt->day); + BCD_TO_BIN(pRtcTimePkt->month); + BCD_TO_BIN(pRtcTimePkt->year); + } + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((pRtcTimePkt->year += (epoch - 1900)) <= 69) + pRtcTimePkt->year += 100; + + pRtcTimePkt->month--; + + //Note: rtc_correct_wday will self adding y+1900 and m+1 + rtc_correct_wday(pRtcTimePkt); + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_bandon_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return 0; +} + +int rtc_bandon_set_time(struct _SynoRtcTimePkt* pRtcTimePkt) +{ + unsigned char save_control, save_freq_select; + unsigned char mon, day, hrs, min, sec, leap_yr, wday; + unsigned int yrs; + SYNO_AUTO_POWERON schedule; + + if (!capable(CAP_SYS_TIME)) { + return -EACCES; + } + + //Note: rtc_correct_wday will self adding y+1900 and m+1 + wday = rtc_correct_wday(pRtcTimePkt); + yrs = pRtcTimePkt->year + 1900; + mon = pRtcTimePkt->month + 1; /* tm_mon starts at zero */ + day = pRtcTimePkt->day; + hrs = pRtcTimePkt->hour; + min = pRtcTimePkt->min; + sec = pRtcTimePkt->sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + spin_lock_irq(&rtc_lock); + + /* These limits and adjustments are independent of + * whether the chip is in binary mode or not. + */ + if (yrs > 169) { + spin_unlock_irq(&rtc_lock); + return -EINVAL; + } + if (yrs >= 100) + yrs -= 100; + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(wday, RTC_DAY_OF_WEEK); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock_irq(&rtc_lock); + + if( 0 == rtc_get_auto_poweron(&schedule) ) { + rtc_bandon_rotate_auto_poweron(&schedule, pRtcTimePkt); + } + + return 0; +} + +int rtc_bandon_auto_poweron_init(void) +{ + return 0; +} + +int rtc_bandon_auto_poweron_uninit(void) +{ + SYNORTCTIMEPKT rtcTime; + rtc_bandon_get_time(&rtcTime); + + return 0; +} diff --git a/drivers/syno/synobios/rtc/rtc.h b/drivers/syno/synobios/rtc/rtc.h new file mode 100644 index 000000000000..e2260abfda26 --- /dev/null +++ b/drivers/syno/synobios/rtc/rtc.h @@ -0,0 +1,76 @@ +#include "synobios.h" +#include "localtime.h" + +#define SEIKO_RTC_STATUS1_ADDR 0x30 +#define SEIKO_RTC_STATUS2_ADDR 0x31 +#define SEIKO_RTC_REALTIME1_ADDR 0x32 +#define SEIKO_RTC_REALTIME2_ADDR 0x33 +#define SEIKO_RTC_INT1_ADDR 0x34 +#define SEIKO_RTC_INT2_ADDR 0x35 +#define SEIKO_RTC_CORRECT_ADDR 0x36 +#define SEIKO_RTC_FREE_ADDR 0x37 + +#define PERICOM_RTC_ADDR 0x68 +#define PERICOM_RTC_ALARM2_OFFSET 0x0B +#define PERICOM_RTC_CONTROL_OFFSET 0x0E +#define PERICOM_RTC_STATUS_OFFSET 0x0F +#define PERICOM_RTC_A1IE_BIT 0x01 +#define PERICOM_RTC_A2IE_BIT 0x02 +#define PERICOM_RTC_INTCN_BIT 0x03 +#define PERICOM_RTC_DAY_DATE_SWITCH 0x40 +#define PERICOM_RTC_DAY_MASK_BIT 0x80 + + +int rtc_ricoh_get_time(struct _SynoRtcTimePkt *pRtcTimePkt); +int rtc_ricoh_set_time(struct _SynoRtcTimePkt *pRtcTimePkt); +int rtc_ricoh_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_ricoh_auto_poweron_init(void); +int rtc_ricoh_auto_poweron_uninit(void); +int rtc_ricoh_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime); +unsigned char Hour_to_Ricoh(const unsigned char hour); +unsigned char Ricoh_to_Hour(const unsigned char hour); + +int rtc_seiko_get_time(struct _SynoRtcTimePkt *pRtcTimePkt); +int rtc_seiko_set_time(struct _SynoRtcTimePkt *pRtcTimePkt); +int rtc_seiko_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_seiko_auto_poweron_init(void); +int rtc_seiko_auto_poweron_uninit(void); +int rtc_seiko_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime); +int rtc_seiko_reset_interrupt_mode(void); +unsigned char Hour_to_Seiko(const unsigned char hour); +unsigned char Seiko_to_Hour(const unsigned char hour); + +int rtc_pericom_get_time(struct _SynoRtcTimePkt *pRtcTimePkt); +int rtc_pericom_set_time(struct _SynoRtcTimePkt *pRtcTimePkt); +int rtc_pericom_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_pericom_auto_poweron_init(void); +int rtc_pericom_auto_poweron_uninit(void); +int rtc_pericom_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime); +unsigned char Hour_to_Pericom(const unsigned char hour); +unsigned char Pericom_to_Hour(const unsigned char hour); + +/* + * Reverse the bits in a byte (unsigned char) + */ +#define RB(v) (reverse_bits(v)) + +int rtc_bandon_get_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_bandon_set_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_bandon_set_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn); +int rtc_bandon_auto_poweron_uninit(void); +int rtc_bandon_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime); + +int rtc_mv_get_time(struct _SynoRtcTimePkt* pRtcTimePkt); +int rtc_mv_set_time(struct _SynoRtcTimePkt* pRtcTimePkt); +#if defined(CONFIG_SYNO_ARMADA) || defined(CONFIG_SYNO_ARMADA_V2) +int rtc_mv_rotate_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn, const SYNORTCTIMEPKT *pRtcTime); +int rtc_mv_set_auto_poweron(SYNO_AUTO_POWERON *pAutoPowerOn); +int rtc_mv_auto_poweron_clean(void); +#endif + +unsigned char rtc_get_alarm_time(SYNORTCALARMPKT *pAlarmTime, const SYNORTCTIMEPKT *pRtcTime); +unsigned char reverse_bits(unsigned char v); +unsigned char rtc_get_next_weekday(const unsigned char weekdays, const unsigned char cur_wday); +void rtc_get_days_later(const SYNORTCTIMEPKT *pRtcTime, const int daysLater, struct xtm *tagetTime); +int rtc_get_auto_poweron(SYNO_AUTO_POWERON* pAutoPowerOn); +int rtc_later_equal_than_int(unsigned char rtcHour, const unsigned char rtcMin, unsigned char intHour, const unsigned char intMin); diff --git a/drivers/syno/synobios/rtd1296/Makefile b/drivers/syno/synobios/rtd1296/Makefile new file mode 100644 index 000000000000..2ccf68297a26 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/Makefile @@ -0,0 +1,35 @@ +obj-m += ds418j-synobios.o +obj-m += ds418-synobios.o +obj-m += ds218play-synobios.o +obj-m += ds118-synobios.o +obj-m += ds218-synobios.o +obj-m += eds19-synobios.o +obj-m += rs819-synobios.o +obj-m += ds220j-synobios.o +obj-m += ds420j-synobios.o + +common-obj += \ + ../common/common.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-rtk-builtin.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + rtd1296_common.o + +fan-pwm-obj += fan-pwm.o +fan-resistor-obj += fan-resistor.o + +syno_power_outage-obj += ../syno_power_outage/syno_power_outage.o + +ds418j-synobios-objs = ds418j.o $(fan-pwm-obj) $(common-obj) +ds418-synobios-objs = ds418.o $(fan-pwm-obj) $(common-obj) +ds218play-synobios-objs = ds218play.o $(fan-pwm-obj) $(common-obj) +ds118-synobios-objs = ds118.o $(fan-pwm-obj) $(common-obj) +ds218-synobios-objs = ds218.o $(fan-pwm-obj) $(common-obj) +eds19-synobios-objs = eds19.o $(common-obj) $(syno_power_outage-obj) +rs819-synobios-objs = rs819.o $(fan-pwm-obj) $(common-obj) +ds220j-synobios-objs = ds220j.o $(fan-pwm-obj) $(common-obj) +ds420j-synobios-objs = ds420j.o $(fan-pwm-obj) $(common-obj) diff --git a/drivers/syno/synobios/rtd1296/ds118.c b/drivers/syno/synobios/rtd1296/ds118.c new file mode 100755 index 000000000000..ace2a1572c04 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds118.c @@ -0,0 +1,200 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS118; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_118 = MODULE_T_DS118; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS118: + pType = &type_118; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status){ + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS118 GPIO config table + * + * Pin In/Out Function + * + * 16 In Reset button + * 11 Out Control front panel LED + * 21 Out Status green LED + * 22 Out USB3.0 port1 power + * 23 Out USB3.0 port0 power + * 25 Out Status red LED + * 18 Out HDD 1 green LED + * 85 Out HDD 1 power enable + * 87 Out Control HDD LED + * 98 Out HDD 1 orange LED + * 128 Out LAN LED + * + */ + +/* + * DS118 other control + * + * Fan fail MicroP + * HDD green LED Realtek driver (ahci.c, rtd-1296-synology-ds118.dts) + * Lan LED Realtek driver (r8169.c, rtd-1296-synology-ds118.dts) + * + */ + +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {98}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 1, + .gpio_port = {85}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.hdd_fail_led = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLedR8169NoCtrlPin; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/ds218.c b/drivers/syno/synobios/rtd1296/ds218.c new file mode 100755 index 000000000000..aaaa9b4ab3b9 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds218.c @@ -0,0 +1,247 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS218; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; + +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_218 = MODULE_T_DS218; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS218: + pType = &type_218; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status){ + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +/* + * DS218 GPIO config table + * + * Pin In/Out Function + * + * 13 In USB Copy + * 4 Out HDD 1 present + * 5 Out HDD 2 present + * 11 Out Control front panel LED + * 17 Out Control front panel USB2.0 power + * 18 Out HDD 1 green LED + * 19 Out HDD 2 green LED + * 22 Out USB3.0 port1 power + * 23 Out USB3.0 port0 power + * 85 Out HDD 1 power enable + * 86 Out HDD 2 power enable + * 87 Out Control HDD LED + * 88 Out Control LAN LED + * 97 Out HDD 2 orange LED + * 98 Out HDD 1 orange LED + * 128 Out LAN LED + * + */ + +/* + * DS218 other control + * + * Fan fail MicroP + * HDD green LED Realtek driver (ahci.c, rtd-1296-synology-ds218.dts) + * Lan LED Realtek driver (r8169.c, rtd-1296-synology-ds218.dts) + * + */ + +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {4, 5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {85, 86}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {88}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {13}, + .gpio_polarity = ACTIVE_LOW, +}; + + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; + + syno_gpio_direction_input(copy_button_detect.gpio_port[0]); +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.hdd_fail_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to read USBCOPY GPIO status. */ + /* for matching userspace usage, button pressed = 0, else = 1 */ + ops->get_copy_button_status = getCopyButtonStatus; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/ds218play.c b/drivers/syno/synobios/rtd1296/ds218play.c new file mode 100755 index 000000000000..05fac2700707 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds218play.c @@ -0,0 +1,211 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS218play; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_218play = MODULE_T_DS218play; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS218play: + pType = &type_218play; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS218play GPIO config table + * + * Pin In/Out Function + * + * 16 In Reset button + * 10 Out I2C_SCA, control dimmer + * 11 Out Control front panel LED + * 21 Out Status green LED + * 22 Out USB3.0 port1 power + * 23 Out USB3.0 port0 power + * 25 Out Status red LED + * 26 Out I2C_SCL, control dimmer + * 18 Out HDD 1 green LED + * 19 Out HDD 2 green LED + * 85 Out HDD 1 power enable + * 86 Out HDD 2 power enable + * 87 Out Control HDD LED + * 97 Out HDD 2 orange LED + * 98 Out HDD 1 orange LED + * 128 Out LAN LED + * + */ + +/* + * DS218play other control + * + * Fan fail MicroP + * HDD green LED Realtek driver (ahci.c, rtd-1296-synology-ds218play.dts) + * Lan LED Realtek driver (r8169.c, rtd-1296-synology-ds218play.dts) + * + */ + +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {85, 86}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO power_led = { + .nr_gpio = 1, + .gpio_port = {122}, // 21 + 101 + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.power_led = &power_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.hdd_fail_led = NULL; + syno_gpio.power_led = NULL; + syno_gpio.disk_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLedR8169NoCtrlPin; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/ds220j.c b/drivers/syno/synobios/rtd1296/ds220j.c new file mode 100644 index 000000000000..90658f4c31a9 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds220j.c @@ -0,0 +1,226 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS220j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds220j = MODULE_T_DS220j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS220j: + pType = &type_ds220j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS220j GPIO config table + * + * Pin In/Out Function + * + * 4 Out HDD 1 detect + * 5 Out HDD 2 detect + * 10 Out I2C_SCA, control dimmer + * 11 Out Control front panel LED + * 18 Out HDD 1 green LED + * 19 Out HDD 2 green LED + * 22 Out USB3.0 port1 power + * 23 Out USB3.0 port0 power + * 26 Out I2C_SCL, control dimmer + * 85 Out HDD 1 power enable + * 86 Out HDD 2 power enable + * 87 Out Control HDD LED + * 88 Out Control LAN LED + * 97 Out HDD 2 orange LED + * 98 Out HDD 1 orange LED + * 128 Out LAN LED + * + */ + +/* + * DS220j other control + * + * Fan fail MicroP + * HDD green LED Realtek driver (ahci.c, rtd-1296-synology-ds220j.dts) + * Lan LED Realtek driver (r8169.c, rtd-1296-synology-ds220j.dts) + * + */ + +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {4, 5}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {85, 86}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {88}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.hdd_fail_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/ds418.c b/drivers/syno/synobios/rtd1296/ds418.c new file mode 100755 index 000000000000..9f97fcf356b8 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds418.c @@ -0,0 +1,259 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS418; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_418 = MODULE_T_DS418; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS418: + pType = &type_418; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(disknum > 2) { + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status){ + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS418 GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In HDD 3 present + * 43 In HDD 4 present + * 52 In Fan 1 fail + * 53 In Fan 2 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 15 Out HDD 3 fault LED + * 16 Out HDD 4 fault LED + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 37 Out HDD 3 power enable + * 38 Out HDD 4 power enable + * 48 Out Fan Low + * 49 Out Fan Mid + * 50 Out Fan High + * 58 Out USB3 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {24, 12}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {100, 99, 98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +/* + * For Asmedia sata disk led, we use GPIO 54 and 63 + * For Realtek internal sata disk led, we use GPIO 18 and 19 + * GPIO 18 and 19 blink and enable are controlled by driver/ata/ahci_rtk.c driver + * Therefore, synobios don't control GPIO 18 and 19 to prevent conflict + */ +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {54, 63}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {4, 5, 6, 7}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {85, 86, 82, 81}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {88}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/ds418j.c b/drivers/syno/synobios/rtd1296/ds418j.c new file mode 100755 index 000000000000..e4a6a17c65c8 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds418j.c @@ -0,0 +1,269 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS418j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_418j = MODULE_T_DS418j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS418j: + pType = &type_418j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(disknum > 2) { + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status){ + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + + +/* + * DS418j GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In HDD 3 present + * 43 In HDD 4 present + * 52 In Fan 1 fail + * 53 In Fan 2 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 15 Out HDD 3 fault LED + * 16 Out HDD 4 fault LED + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 37 Out HDD 3 power enable + * 38 Out HDD 4 power enable + * 48 Out Fan Low + * 49 Out Fan Mid + * 50 Out Fan High + * 58 Out USB3 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {24, 134}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {100, 99, 98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +/* + * For Asmedia sata disk led, we use GPIO 54 and 63 + * For Realtek internal sata disk led, we use GPIO 18 and 19 + * GPIO 18 and 19 blink and enable are controlled by driver/ata/ahci_rtk.c driver + * Therefore, synobios don't control GPIO 18 and 19 to prevent conflict + */ +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {54, 63}, + .gpio_polarity = ACTIVE_HIGH, +}; +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {4, 5, 6, 7}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {85, 86, 82, 81}, + .gpio_polarity = ACTIVE_HIGH, +}; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {88}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/ds420j.c b/drivers/syno/synobios/rtd1296/ds420j.c new file mode 100644 index 000000000000..a398f76fef28 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/ds420j.c @@ -0,0 +1,269 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS420j; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_420j = MODULE_T_DS420j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS420j: + pType = &type_420j; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + if(disknum > 2) { + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status){ + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + + +/* + * DS420j GPIO config table + * + * Pin In/Out Function + + * 12 In Model ID 0 + * 21 In Model ID 1 + * 45 In Model ID 2 + * 39 In HDD 1 present + * 40 In HDD 2 present + * 41 In HDD 3 present + * 43 In HDD 4 present + * 52 In Fan 1 fail + * 53 In Fan 2 fail + * 54 In USB3 overcurrent + * 55 In USB2 overcurrent + * 6 Out LED on + * 13 Out HDD 1 fault LED + * 14 Out HDD 2 fault LED + * 15 Out HDD 3 fault LED + * 16 Out HDD 4 fault LED + * 26 Out HDD 1 power enable + * 27 Out HDD 2 power enable + * 37 Out HDD 3 power enable + * 38 Out HDD 4 power enable + * 48 Out Fan Low + * 49 Out Fan Mid + * 50 Out Fan High + * 58 Out USB3 power enable + * 59 Out USB2 power enable + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {24, 134}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {100, 99, 98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +/* + * For Asmedia sata disk led, we use GPIO 54 and 63 + * For Realtek internal sata disk led, we use GPIO 18 and 19 + * GPIO 18 and 19 blink and enable are controlled by driver/ata/ahci_rtk.c driver + * Therefore, synobios don't control GPIO 18 and 19 to prevent conflict + */ +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {54, 63}, + .gpio_polarity = ACTIVE_HIGH, +}; +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {4, 5, 6, 7}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {85, 86, 82, 81}, + .gpio_polarity = ACTIVE_HIGH, +}; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +static SYNO_GPIO_INFO model_id = { + .nr_gpio = 3, + .gpio_port = {12, 21, 45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {88}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.model_id = &model_id; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; +} + +void syno_gpio_cleanup(void) +{ +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + syno_gpio.fan_ctrl = NULL; + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.model_id = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/eds19.c b/drivers/syno/synobios/rtd1296/eds19.c new file mode 100755 index 000000000000..0d061de9cb11 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/eds19.c @@ -0,0 +1,230 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" +#include "../syno_power_outage/syno_power_outage.h" + + +int GetModel(void) +{ + return MODEL_EDS19; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; + +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1000); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_eds19 = MODULE_T_EDS19; + module_t *pType = NULL; + + switch (model) { + case MODEL_EDS19: + pType = &type_eds19; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + + if(status == DISK_LED_ORANGE_SOLID || status == DISK_LED_ORANGE_BLINK || status == DISK_LED_OFF) { + syno_ahci_disk_green_led(disknum - 1, 0); + } + else { + syno_ahci_disk_green_led(disknum - 1, 1); + } + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + /* eds19 doesn't need set fan status */ + return 0; +} + +/* + * EDS19 GPIO config table + * + * Pin In/Out Function + * + * *** General *** + * 6 In HDD 1 present + * 18 Out HDD 1 green LED + * 11 Out lan + disk led control + * 22 Out USB3.0 port1 power + * 23 Out USB3.0 port0 power + * 60 In USB3.0 port1 over current + * 61 In USB3.0 port2 over current + * 98 Out HDD 1 orange LED + * 128 Out LAN 1G Link/Activity LED + * 129 Out LAN 10/100 Link/Activity LED + * 130 Out PCIE1 reset + * + * *** Power *** + * 4 In Super Cap BP present + * 5 In PoE BP present + * 7 In Super Cap BP PFOn + * (Power loss and the power source change to Super Cap BP) + * 26 In Power Adapter Present + * 97 In Super Cap power good + * + * *** SD card *** + * 81 Out SD command(CMD) + * 82 Out SD clock(CLK) + * 83 In SD write protest(WP) + * 84 In SD card detect(CD) + * 85 Bi SD data 0(D0) + * 86 Bi SD data 1(D1) + * 87 Bi SD data 2(D2) + * 88 Bi SD data 3(D3) + * + * 99 Out SD card power enable + * 100 In SD eject button + */ + +/* + * EDS19 other control + * + * HDD green LED Realtek driver (ahci-rtk.c, rtd-1296-synology-eds19.dts) + * Lan LED Realtek driver (r8169.c, rtd-1296-synology-eds19.dts) + * + */ + +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {98}, + .gpio_polarity = ACTIVE_LOW, +}; + +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 1, + .gpio_port = {6}, + .gpio_polarity = ACTIVE_LOW, +}; + +/* GPIO 11 is lan + disk led control + * We need it mask only at poweron and phy_led_ctrl behavior is fit our needs. */ +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {11}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// high: not using super cap, low: using super cap +SYNO_GPIO_INFO power_outage_gpio = { + .nr_gpio = 1, + .gpio_port = {7}, + .gpio_polarity = ACTIVE_LOW, +}; + +// high: power adapter present, low: no power adapter +static SYNO_GPIO_INFO power_adapter_present = { + .nr_gpio = 1, + .gpio_port = {26}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// high: super cap percentage more than 92%, low: less than 92% +static SYNO_GPIO_INFO super_cap_good = { + .nr_gpio = 1, + .gpio_port = {97}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + + // gpio direction input + syno_gpio_direction_input(power_adapter_present.gpio_port[0]); + syno_gpio_direction_input(super_cap_good.gpio_port[0]); + + syno_power_outage_init(); +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + syno_gpio.hdd_fail_led = NULL; + syno_gpio.phy_led_ctrl = NULL; + + syno_power_outage_remove(); +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/fan-pwm.c b/drivers/syno/synobios/rtd1296/fan-pwm.c new file mode 100755 index 000000000000..105457a63e00 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/rtd1296/fan-resistor.c b/drivers/syno/synobios/rtd1296/fan-resistor.c new file mode 100644 index 000000000000..34ce77e90def --- /dev/null +++ b/drivers/syno/synobios/rtd1296/fan-resistor.c @@ -0,0 +1,28 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include +#include +#include +#include + +#include "rtd1296_common.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (SYNO_CTRL_FAN_RESISTOR(speed_value)) { + goto END; + } + + res = 0; +END: + return res; +} diff --git a/drivers/syno/synobios/rtd1296/rs819.c b/drivers/syno/synobios/rtd1296/rs819.c new file mode 100755 index 000000000000..39e2476afd9d --- /dev/null +++ b/drivers/syno/synobios/rtd1296/rs819.c @@ -0,0 +1,248 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1296_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_RS819; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1400); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_rs819 = MODULE_T_RS819; + module_t *pType = NULL; + + switch (model) { + case MODEL_RS819: + pType = &type_rs819; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status) +{ + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status){ + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +int getBuzzerButtonStatus(unsigned char *pValue) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(pValue); +} + +/* + * RS819 GPIO config table + * + * Pin In/Out Function + + * 4 In HDD 1 present + * 5 In HDD 2 present + * 6 In HDD 3 present + * 7 In HDD 4 present + * 12 In FAN 2 fail + * 17 In Buzzer mute Button + * 18 Out HDD 1 green LED + * 20 In FAN 3 fail + * 22 Out USB 3.0 lower power + * 23 Out USB 3.0 upper power + * 24 In FAN 1 fail + * 55 Out HDD 1 power + * 81 Out HDD 4 power + * 82 Out HDD 3 power + * 87 Out Control HDD LED + * 88 Out Control LAN LED + * 97 Out HDD 4 orange LED + * 98 Out HDD 3 orange LED + * 99 Out HDD 2 orange LED + * 100 Out HDD 1 orange LED + * 128 Out LAN 1G status LED + * 129 Out LAN active LED + */ + +/* + * For RS819 rtk internal sata disk led, we use GPIO 18 + * GPIO 18 blink and enable are controlled by driver/ata/ahci_rtk.c driver + * Therefore, synobios don't control GPIO 18 to prevent conflict + * RS819 other 3 disk are using MV9215 and don't need to control their led. + */ + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 3, + .gpio_port = {24, 12, 20}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {100, 99, 98, 97}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {4, 5, 6, 7}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {55, 86, 82, 81}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {87}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {88}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {17}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_fail = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.mute_button_detect = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* attach get_fan_status handler*/ + ops->get_fan_status = GetFanStatusActiveLow; + + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable for mute buzzer button */ + ops->get_buzzer_cleared = getBuzzerButtonStatus; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1296/rtd1296_common.c b/drivers/syno/synobios/rtd1296/rtd1296_common.c new file mode 100644 index 000000000000..95f2541f21b0 --- /dev/null +++ b/drivers/syno/synobios/rtd1296/rtd1296_common.c @@ -0,0 +1,480 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2016 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include +#include +#include "../rtc/rtc-rtk-builtin.h" +#include "rtd1296_common.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" + +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); +int syno_rtd_get_temperature(void); +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef MY_DEF_HERE +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif /* MY_DEF_HERE */ + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; +static int Uninitialize(void); + +static SYNO_HWMON_SENSOR_TYPE hdd_backplane_status_detect_enable = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_DETECT, + }, { + .sensor_name = HWMON_HDD_BP_ENABLE, + }} +}; +static struct hwmon_sensor_list hdd_detect_enable_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &hdd_backplane_status_detect_enable, +}; +static SYNO_HWMON_SENSOR_TYPE hdd_backplane_status_detect = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_DETECT, + }} +}; +static struct hwmon_sensor_list hdd_detect_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &hdd_backplane_status_detect, +}; +static SYNO_HWMON_SENSOR_TYPE hdd_backplane_status_enable = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 1, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_ENABLE, + }} +}; +static struct hwmon_sensor_list hdd_enable_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &hdd_backplane_status_enable, +}; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int (*GetMaxInternalHostNum)(void) = NULL; + +int GetMaxInternalDiskNum(void) +#else +static int GetMaxInternalPCIE9xxxDiskNum(void) +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS418: + iMaxInternalDiskNum = 4; + break; + case MODEL_DS418j: + iMaxInternalDiskNum = 4; + break; + case MODEL_DS218play: + iMaxInternalDiskNum = 2; + break; + case MODEL_DS118: + iMaxInternalDiskNum = 1; + break; + case MODEL_DS218: + iMaxInternalDiskNum = 2; + break; + case MODEL_EDS19: + iMaxInternalDiskNum = 1; + break; + case MODEL_RS819: + iMaxInternalDiskNum = 4; + break; + case MODEL_DS220j: + iMaxInternalDiskNum = 2; + break; + case MODEL_DS420j: + iMaxInternalDiskNum = 4; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int iRet = -1; + int iTemp = 0; + + if (!pCPUTemp) + goto END; + + iTemp = syno_rtd_get_temperature(); + + if( 1 == pCPUTemp->blSurface ) { + iTemp = (iTemp - 20) < 40 ? 40 : (iTemp - 20); + } + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = iTemp; + + iRet = 0; +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + while (HAVE_HDD_DETECT(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + index++; + } + + index = 1; + while (HAVE_HDD_ENABLE(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + if (MODEL_RS819 == GetModel() && 2 == index) { + // rs819 HDD 2 is always power on and power pin is fake. + hdd_enable |= 0x01 << (index - 1); + } + + index++; + } + + index = 0; + while (hdd_backplane->sensor_num > index) { + if (0 == strncmp(HWMON_HDD_BP_ENABLE, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_ENABLE))) { + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%lu", hdd_enable); + } else if (0 == strncmp(HWMON_HDD_BP_DETECT, hdd_backplane->sensor[index].sensor_name, strlen(HWMON_HDD_BP_DETECT))){ + snprintf(hdd_backplane->sensor[index].value, sizeof(hdd_backplane->sensor[index].value), "%lu", hdd_detect); + } + index++; + } + + iRet = 0; + +End: + return iRet; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9235_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9235GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9235GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9170GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9170_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9170GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9170GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int err = -1; + switch (ledStatus) { + case SYNO_LED_OFF: + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + SYNO_HDD_LED_SET(2, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +int SetPhyLedR8169NoCtrlPin(SYNO_LED status) +{ + int err = -1; + int val = 1; + struct net_device *dev; + struct ethtool_drvinfo info; + + switch(status) { + case SYNO_LED_ON: + val = 1; + break; + case SYNO_LED_OFF: + val = 0; + break; + default: + goto ERR; + } + + read_lock(&dev_base_lock); + for_each_netdev(&init_net, dev) { + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { + dev->ethtool_ops->get_drvinfo(dev, &info); + if (!strcmp(info.driver, "r8169")) { + syno_rtd129x_rtl8169_lan_led_control(dev, val); + err = 0; + break; + } + } + } + read_unlock(&dev_base_lock); + +ERR: + return err; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_rtk_get_time, + .set_rtc_time = rtc_rtk_set_time, + .get_fan_status = NULL, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = NULL, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_rtk_get_alarm, + .set_auto_poweron = rtc_rtk_set_alarm, + .init_auto_poweron = rtc_rtk_enable_alarm_irq, + .uninit_auto_poweron = rtc_rtk_enable_alarm_irq, + .set_alarm_led = NULL, + .get_backplane_status = NULL, + .get_mem_byte = NULL, + .get_buzzer_cleared = NULL, + .set_phy_led = NULL, + .set_hdd_led = NULL, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + // for matching userspace usage, return 0 if button is pressed, else = 1 + .get_copy_button_status = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + syno_gpio_init(); +#ifdef MY_DEF_HERE + printk("Synobios %s GPIO initialized\n", syno_get_hw_version()); +#endif /* MY_DEF_HERE */ + + switch (GetModel()) { + case MODEL_DS418j: + case MODEL_DS418: + case MODEL_DS218: + case MODEL_RS819: + case MODEL_DS220j: + case MODEL_DS420j: + hwmon_sensor_list = &hdd_detect_enable_sensor_list; + break; + case MODEL_EDS19: + hwmon_sensor_list = &hdd_detect_sensor_list; + break; + case MODEL_DS118: + case MODEL_DS218play: + hwmon_sensor_list = &hdd_enable_sensor_list; + break; + } + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + + return 0; +} + +static int Uninitialize(void) +{ + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + model_addon_cleanup(*ops); + + return 0; +} + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gPWMSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gPWMSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} diff --git a/drivers/syno/synobios/rtd1296/rtd1296_common.h b/drivers/syno/synobios/rtd1296/rtd1296_common.h new file mode 100755 index 000000000000..8dc6c20bf54f --- /dev/null +++ b/drivers/syno/synobios/rtd1296/rtd1296_common.h @@ -0,0 +1,58 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2015 Synology Inc. All rights reserved. */ + +#include +#include +#include "../mapping.h" +#include "../common/common.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetDiskLedStatus(int disknum, SYNO_DISK_LED status); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int InitModuleType(struct synobios_ops *ops); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int SetHDDActLed(SYNO_LED ledStatus); +int SetPowerLedStatus(SYNO_LED status); +int SYNO_GPIO_READ(int pin); +void SYNO_GPIO_WRITE(int pin, int pValue); + +#if defined(MY_DEF_HERE) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif /* MY_DEF_HERE && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(MY_DEF_HERE) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_mv_9170_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif /* MY_DEF_HERE && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +extern int syno_ahci_disk_green_led(const unsigned short hostnum, const int iValue); +//extern int syno_armada_get_temperature(int *temperature); +// for matching userspace usage, return 0 if button is pressed, else = 1 +int GetFanStatusMircopWithGPIOCommon(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +void VdimmPwrCtrl(SYNO_LED ledStatus); +void syno_gpio_init(void); +void syno_gpio_cleanup(void); +int PWMFanSpeedMapping(FAN_SPEED speed); +int SetPhyLed(SYNO_LED ledStatus); +int SetPhyLedR8169NoCtrlPin(SYNO_LED status); + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/rtd1619/Makefile b/drivers/syno/synobios/rtd1619/Makefile new file mode 100644 index 000000000000..770e4b7cbddf --- /dev/null +++ b/drivers/syno/synobios/rtd1619/Makefile @@ -0,0 +1,22 @@ +obj-m += ds220play-synobios.o +obj-m += ds220-synobios.o + +common-obj += \ + ../common/common.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + rtd1619_common.o + +fan-pwm-obj += fan-pwm.o +fan-resistor-obj += fan-resistor.o + +syno_power_outage-obj += ../syno_power_outage/syno_power_outage.o + +ds220play-synobios-objs = ds220play.o $(fan-resistor-obj) $(common-obj) +ds220-synobios-objs = ds220.o $(fan-resistor-obj) $(common-obj) diff --git a/drivers/syno/synobios/rtd1619/ds220.c b/drivers/syno/synobios/rtd1619/ds220.c new file mode 100644 index 000000000000..3c4488d0b158 --- /dev/null +++ b/drivers/syno/synobios/rtd1619/ds220.c @@ -0,0 +1,262 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1619_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS220; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1300); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds220 = MODULE_T_DS220; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS220: + pType = &type_ds220; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(DISKLEDSTATUS *pLedStatus) +{ + int disknum = pLedStatus->diskno; + SYNO_DISK_LED status = pLedStatus->status; + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +/* + * DS220 GPIO config table + * + * Pin In/Out Function + * + * 3 Out HDD green LED 1 + * 4 Out HDD green LED 2 + * 18 Out HDD orange LED 1 + * 19 Out HDD orange LED 2 + * 22 Out Front Panel LED Control + * 34 Out HDD LED Control + * 35 Out LAN LED Control + * 41 In HDD Detect 1 + * 42 In HDD Detect 2 + * 51 Out LAN LED + * 57 Out Fan control full + * 59 Out Fan control high + * 60 Out Fan control middle + * 61 Out Fan control low + * 62 Out HDD Power Enable 2 + * 67 Out HDD Power Enable 1 + * 68 Out Fan control voltage + * 70 Out USB3 Power Enable 1 + * 71 In USB3 OC 1 + * 72 Out USB3 Power Enable 2 + * 73 In USB3 OC 2 + * + */ + +/* + * DS220 other control + * + * Fan fail MicroP + * LAN LED Realtek driver (r8169soc_1619.c, rtd-1619-synology-ds220.dts) + * + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 5, + .gpio_port = {61, 60, 59, 68, 57}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {18, 19}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {41, 42}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {67, 62}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {34}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {35}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {30}, + .gpio_polarity = ACTIVE_LOW, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to read USBCOPY GPIO status. */ + /* for matching userspace usage, button pressed = 0, else = 1 */ + ops->get_copy_button_status = getCopyButtonStatus; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1619/ds220play.c b/drivers/syno/synobios/rtd1619/ds220play.c new file mode 100644 index 000000000000..b6f166915dac --- /dev/null +++ b/drivers/syno/synobios/rtd1619/ds220play.c @@ -0,0 +1,245 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1619_common.h" +#include "syno_ttyS.h" + + +int GetModel(void) +{ + return MODEL_DS220play; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ +#if defined(CONFIG_SMP) + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } +#else /* CONFIG_SMP */ + cpu->core = 1; +#endif + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1300); +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds220play = MODULE_T_DS220play; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS220play: + pType = &type_ds220play; + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetDiskLedStatus(DISKLEDSTATUS *pLedStatus) +{ + int disknum = pLedStatus->diskno; + SYNO_DISK_LED status = pLedStatus->status; + int iRet = -1; + static int diskLedEnabled = 0; + + if (0 == diskLedEnabled && DISK_LED_OFF != status) { + /* enable disk LED */ + SYNO_ENABLE_HDD_LED(1); + diskLedEnabled = 1; + } + + iRet = SYNO_HDD_LED_SET(disknum, status); + if (0 != iRet) { + goto END; + } +END: + return iRet; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS220play GPIO config table + * + * Pin In/Out Function + * + * 3 Out HDD green LED 1 + * 4 Out HDD green LED 2 + * 18 Out HDD orange LED 1 + * 19 Out HDD orange LED 2 + * 22 Out Front Panel LED Control + * 34 Out HDD LED Control + * 35 Out LAN LED Control + * 41 In HDD Detect 1 + * 42 In HDD Detect 2 + * 51 Out LAN LED + * 57 Out Fan control full + * 59 Out Fan control high + * 60 Out Fan control middle + * 61 Out Fan control low + * 62 Out HDD Power Enable 2 + * 67 Out HDD Power Enable 1 + * 68 Out Fan control voltage + * 70 Out USB3 Power Enable 1 + * 71 In USB3 OC 1 + * 72 Out USB3 Power Enable 2 + * 73 In USB3 OC 2 + * + */ + +/* + * DS220play other control + * + * Fan fail MicroP + * LAN LED Realtek driver (r8169soc_1619.c, rtd-1619-synology-ds220play.dts) + * + */ + +static SYNO_GPIO_INFO fan_ctrl = { + .nr_gpio = 5, + .gpio_port = {61, 60, 59, 68, 57}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {18, 19}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {41, 42}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {67, 62}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {34}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {35}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_ctrl = &fan_ctrl; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1619/fan-pwm.c b/drivers/syno/synobios/rtd1619/fan-pwm.c new file mode 100644 index 000000000000..0fe136b7a3f9 --- /dev/null +++ b/drivers/syno/synobios/rtd1619/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include +#include +#include "rtd1619_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/rtd1619/fan-resistor.c b/drivers/syno/synobios/rtd1619/fan-resistor.c new file mode 100644 index 000000000000..8f0d030af6b9 --- /dev/null +++ b/drivers/syno/synobios/rtd1619/fan-resistor.c @@ -0,0 +1,28 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include +#include +#include +#include + +#include "rtd1619_common.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (SYNO_CTRL_FAN_RESISTOR(speed_value)) { + goto END; + } + + res = 0; +END: + return res; +} diff --git a/drivers/syno/synobios/rtd1619/rtd1619_common.c b/drivers/syno/synobios/rtd1619/rtd1619_common.c new file mode 100644 index 000000000000..24f3c800cacc --- /dev/null +++ b/drivers/syno/synobios/rtd1619/rtd1619_common.c @@ -0,0 +1,364 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2016 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include +#include "rtd1619_common.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); +int syno_rtd_get_temperature(void); +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef MY_DEF_HERE +static int giDiskMapTable[32] = {0}; +static char gblDiskNumNeedTran = 0; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif /* MY_DEF_HERE */ + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; +static int Uninitialize(void); + +static SYNO_HWMON_SENSOR_TYPE rtd1619_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_DETECT, + }, { + .sensor_name = HWMON_HDD_BP_ENABLE, + }} +}; +static struct hwmon_sensor_list rtd1619_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &rtd1619_hdd_backplane_status, +}; +static struct hwmon_sensor_list *hwmon_sensor_list = &rtd1619_sensor_list; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int (*GetMaxInternalHostNum)(void) = NULL; + +int GetMaxInternalDiskNum(void) +#else +static int GetMaxInternalPCIE9xxxDiskNum(void) +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS220play: + iMaxInternalDiskNum = 2; + break; + case MODEL_DS220: + iMaxInternalDiskNum = 2; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int iRet = -1; + int iTemp = 0; + + if (!pCPUTemp) + goto END; + + iTemp = syno_rtd_get_temperature(); + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = iTemp; + + iRet = 0; +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + while (HAVE_HDD_DETECT(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + index++; + } + + index = 1; + while (HAVE_HDD_ENABLE(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + index++; + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%lu", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%lu", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#else +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9235GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9235_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9235GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9235GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +static int SetSCSIHostLedStatusBy9170GPIO(int iHostNum, SYNO_DISK_LED iStatus) +{ + int iRet = 0; + int iWrite = -1; + + if (DISK_LED_ORANGE_BLINK == iStatus || DISK_LED_ORANGE_SOLID == iStatus) { + iWrite = 1; + } else { + iWrite = 0; + } + + iRet = syno_mv_9170_disk_led_set((unsigned short)iHostNum, iWrite); + + return iRet; +} + +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus) +{ + int iRet = -1; + + if (1 > iDiskNum || GetMaxInternalPCIE9xxxDiskNum() < iDiskNum) { + printk("Invalid disk Number [%d]\n", iDiskNum); + goto END; + } + + if (!gblDiskNumNeedTran) { + iRet = SetSCSIHostLedStatusBy9170GPIO(iDiskNum - 1, iStatus); + } else { + iRet = SetSCSIHostLedStatusBy9170GPIO(giDiskMapTable[iDiskNum - 1], iStatus); + } +END: + return iRet; + +} + +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int err = -1; + switch (ledStatus) { + case SYNO_LED_OFF: + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + SYNO_HDD_LED_SET(2, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_fan_status = NULL, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = NULL, + .set_disk_led = SetDiskLedStatus, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .set_alarm_led = NULL, + .get_backplane_status = NULL, + .get_mem_byte = NULL, + .get_buzzer_cleared = NULL, + .set_phy_led = NULL, + .set_hdd_led = NULL, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + // for matching userspace usage, return 0 if button is pressed, else = 1 + .get_copy_button_status = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + syno_gpio_init(); +#ifdef MY_DEF_HERE + printk("Synobios %s GPIO initialized\n", syno_get_hw_version()); +#endif /* MY_DEF_HERE */ + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + model_addon_init(*ops); + + return 0; +} + +static int Uninitialize(void) +{ + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + model_addon_cleanup(*ops); + + return 0; +} + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gPWMSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gPWMSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} diff --git a/drivers/syno/synobios/rtd1619/rtd1619_common.h b/drivers/syno/synobios/rtd1619/rtd1619_common.h new file mode 100755 index 000000000000..debd244b9112 --- /dev/null +++ b/drivers/syno/synobios/rtd1619/rtd1619_common.h @@ -0,0 +1,58 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2015 Synology Inc. All rights reserved. */ + +#include +#include +#include "../mapping.h" +#include "../common/common.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetDiskLedStatus(DISKLEDSTATUS *pLedStatus); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int InitModuleType(struct synobios_ops *ops); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int SetHDDActLed(SYNO_LED ledStatus); +int SetPowerLedStatus(SYNO_LED status); +int SYNO_GPIO_READ(int pin); +void SYNO_GPIO_WRITE(int pin, int pValue); + +#if defined(MY_DEF_HERE) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_mv_9235_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9235GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif /* MY_DEF_HERE && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(MY_DEF_HERE) && !defined(CONFIG_SYNO_PORT_MAPPING_V2) +extern int syno_mv_9170_disk_led_set(const unsigned short hostnum, int iValue); +int SetDiskLedStatusBy9170GPIO(int iDiskNum, SYNO_DISK_LED iStatus); +#endif /* MY_DEF_HERE && !CONFIG_SYNO_PORT_MAPPING_V2 */ + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +// for matching userspace usage, return 0 if button is pressed, else = 1 +int GetFanStatusMircopWithGPIOCommon(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +void VdimmPwrCtrl(SYNO_LED ledStatus); +void syno_gpio_init(void); +void syno_gpio_cleanup(void); +int PWMFanSpeedMapping(FAN_SPEED speed); +int SetPhyLed(SYNO_LED ledStatus); +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; diff --git a/drivers/syno/synobios/rtd1619b/Makefile b/drivers/syno/synobios/rtd1619b/Makefile new file mode 100644 index 000000000000..67675e7aad29 --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/Makefile @@ -0,0 +1,21 @@ +obj-m += ds223j-synobios.o ds423-synobios.o ds223-synobios.o ds124-synobios.o + +common-obj += \ + ../common/common.o \ + ../i2c/i2c-linux.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + ../rtc/rtc-pericom-lib.o \ + ../rtc/rtc-linux-pericom.o \ + ../led/led_trigger_disk.o \ + rtd1619b_common.o + +fan-pwm-obj += fan-pwm.o + +ds223j-synobios-objs = ds223j.o $(fan-pwm-obj) $(common-obj) +ds423-synobios-objs = ds423.o $(fan-pwm-obj) $(common-obj) +ds223-synobios-objs = ds223.o $(fan-pwm-obj) $(common-obj) +ds124-synobios-objs = ds124.o $(fan-pwm-obj) $(common-obj) diff --git a/drivers/syno/synobios/rtd1619b/ds124.c b/drivers/syno/synobios/rtd1619b/ds124.c new file mode 100644 index 000000000000..cb44a2fc27aa --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/ds124.c @@ -0,0 +1,209 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1619b_common.h" +#include "syno_ttyS.h" + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK +#include "../led/led_trigger_disk.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + +int GetModel(void) +{ + return MODEL_DS124; +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds124 = MODULE_T_DS124; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS124: + pType = &type_ds124; + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK + SetupLedTrigDiskMap(); +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS124 GPIO config table + * + * Pin In/Out Function + * + * 3 Out HDD green LED 1 + * 4 Out HDD green LED 2 + * 18 Out HDD orange LED 1 + * 19 Out HDD orange LED 2 + * 22 Out Front Panel LED Control + * 34 Out HDD LED Control + * 35 Out LAN LED Control + * 41 In HDD Detect 1 + * 42 In HDD Detect 2 + * 51 Out LAN LED + * 57 Out Fan control full + * 59 Out Fan control high + * 60 Out Fan control middle + * 61 Out Fan control low + * 62 Out HDD Power Enable 2 + * 67 Out HDD Power Enable 1 + * 68 Out Fan control voltage + * 70 Out USB3 Power Enable 1 + * 71 In USB3 OC 1 + * 72 Out USB3 Power Enable 2 + * 73 In USB3 OC 2 + * + */ + +/* + * DS124 other control + * + * Fan fail MicroP + * LAN LED Realtek driver (r8169soc_1619.c, rtd-1619b-synology-ds124.dts) + * + */ + +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 1, + .gpio_port = {65}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 1, + .gpio_port = {73}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 1, + .gpio_port = {3}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {53}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) + syno_ahci_disk_led_enable_by_port(1, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1619b/ds223.c b/drivers/syno/synobios/rtd1619b/ds223.c new file mode 100644 index 000000000000..02af0fd581ec --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/ds223.c @@ -0,0 +1,227 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1619b_common.h" +#include "syno_ttyS.h" + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK +#include "../led/led_trigger_disk.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + +int GetModel(void) +{ + return MODEL_DS223; +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds223 = MODULE_T_DS223; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS223: + pType = &type_ds223; + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK + SetupLedTrigDiskMap(); +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS223 GPIO config table + * + * Pin In/Out Function + * + * 3 Out HDD green LED 1 + * 4 Out HDD green LED 2 + * 18 Out HDD orange LED 1 + * 19 Out HDD orange LED 2 + * 22 Out Front Panel LED Control + * 34 Out HDD LED Control + * 35 Out LAN LED Control + * 41 In HDD Detect 1 + * 42 In HDD Detect 2 + * 51 Out LAN LED + * 57 Out Fan control full + * 59 Out Fan control high + * 60 Out Fan control middle + * 61 Out Fan control low + * 62 Out HDD Power Enable 2 + * 67 Out HDD Power Enable 1 + * 68 Out Fan control voltage + * 70 Out USB3 Power Enable 1 + * 71 In USB3 OC 1 + * 72 Out USB3 Power Enable 2 + * 73 In USB3 OC 2 + * + */ + +/* + * DS223 other control + * + * Fan fail MicroP + * LAN LED Realtek driver (r8169soc_1619.c, rtd-1619b-synology-ds223.dts) + * + */ + +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {65, 66}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {69, 70}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {73, 74}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {53}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO copy_button_detect = { + .nr_gpio = 1, + .gpio_port = {44}, + .gpio_polarity = ACTIVE_LOW, +}; + +static int getCopyButtonStatus(void) +{ + // for matching userspace usage, button pressed = 0, else = 1 + return SYNO_COPY_BUTTON_GPIO_GET(); +} + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + syno_gpio.copy_button_detect = ©_button_detect; + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + /* enable to read USBCOPY GPIO status. */ + /* for matching userspace usage, button pressed = 0, else = 1 */ + ops->get_copy_button_status = getCopyButtonStatus; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1619b/ds223j.c b/drivers/syno/synobios/rtd1619b/ds223j.c new file mode 100644 index 000000000000..c07653e32d7b --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/ds223j.c @@ -0,0 +1,210 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1619b_common.h" +#include "syno_ttyS.h" + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK +#include "../led/led_trigger_disk.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + +int GetModel(void) +{ + return MODEL_DS223j; +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds223j = MODULE_T_DS223j; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS223j: + pType = &type_ds223j; + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK + SetupLedTrigDiskMap(); +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS223j GPIO config table + * + * Pin In/Out Function + * + * 3 Out HDD green LED 1 + * 4 Out HDD green LED 2 + * 18 Out HDD orange LED 1 + * 19 Out HDD orange LED 2 + * 22 Out Front Panel LED Control + * 34 Out HDD LED Control + * 35 Out LAN LED Control + * 41 In HDD Detect 1 + * 42 In HDD Detect 2 + * 51 Out LAN LED + * 57 Out Fan control full + * 59 Out Fan control high + * 60 Out Fan control middle + * 61 Out Fan control low + * 62 Out HDD Power Enable 2 + * 67 Out HDD Power Enable 1 + * 68 Out Fan control voltage + * 70 Out USB3 Power Enable 1 + * 71 In USB3 OC 1 + * 72 Out USB3 Power Enable 2 + * 73 In USB3 OC 2 + * + */ + +/* + * DS223j other control + * + * Fan fail MicroP + * LAN LED Realtek driver (r8169soc_1619.c, rtd-1619b-synology-ds223j.dts) + * + */ + +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 2, + .gpio_port = {65, 66}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 2, + .gpio_port = {69, 70}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 2, + .gpio_port = {73, 74}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 2, + .gpio_port = {3, 4}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {53}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1619b/ds423.c b/drivers/syno/synobios/rtd1619b/ds423.c new file mode 100644 index 000000000000..3bdd5a817c93 --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/ds423.c @@ -0,0 +1,219 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include +#include "rtd1619b_common.h" +#include "syno_ttyS.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK +#include "../led/led_trigger_disk.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + +int GetModel(void) +{ + return MODEL_DS423; +} + +int InitModuleType(struct synobios_ops *ops) +{ + PRODUCT_MODEL model = GetModel(); + module_t type_ds423 = MODULE_T_DS423; + module_t *pType = NULL; + + switch (model) { + case MODEL_DS423: + pType = &type_ds423; + +#ifdef CONFIG_SYNO_LEDS_TRIGGER_DISK + SetupLedTrigDiskMap(); +#endif /* CONFIG_SYNO_LEDS_TRIGGER_DISK */ + break; + default: + break; + } + + module_type_set(pType); + return 0; +} + +int SetPowerLedStatus(SYNO_LED status) +{ + char szCommand[5] = {0}; + int err = -1; + + switch(status){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > synobios_lock_ttyS_write(szCommand)) { + goto ERR; + } + + err = 0; +ERR: + return err; +} + +static int SetHddLed(SYNO_LED status) +{ + int err = -1; + + switch(status) { + case SYNO_LED_ON: + SYNO_ENABLE_HDD_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_HDD_LED(0); + break; + default: + goto ERR; + } + + err = 0; +ERR: + return err; +} + +/* + * DS423 GPIO config table + * + * Pin In/Out Function + * + * 3 Out HDD green LED 1 + * 4 Out HDD green LED 2 + * 18 Out HDD orange LED 1 + * 19 Out HDD orange LED 2 + * 22 Out Front Panel LED Control + * 34 Out HDD LED Control + * 35 Out LAN LED Control + * 41 In HDD Detect 1 + * 42 In HDD Detect 2 + * 51 Out LAN LED + * 57 Out Fan control full + * 59 Out Fan control high + * 60 Out Fan control middle + * 61 Out Fan control low + * 62 Out HDD Power Enable 2 + * 67 Out HDD Power Enable 1 + * 68 Out Fan control voltage + * 70 Out USB3 Power Enable 1 + * 71 In USB3 OC 1 + * 72 Out USB3 Power Enable 2 + * 73 In USB3 OC 2 + * + */ + +/* + * DS423 other control + * + * Fan fail MicroP + * LAN LED Realtek driver (r8169soc_1619.c, rtd-1619b-synology-ds423.dts) + * + */ + +static SYNO_GPIO_INFO hdd_present_led = { + .nr_gpio = 4, + .gpio_port = {65, 66, 67, 68}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_fail_led = { + .nr_gpio = 4, + .gpio_port = {69, 70, 71, 72}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_detect = { + .nr_gpio = 4, + .gpio_port = {73, 74, 75, 76}, + .gpio_polarity = ACTIVE_LOW, +}; +static SYNO_GPIO_INFO hdd_enable = { + .nr_gpio = 4, + .gpio_port = {3, 4, 5, 6}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {45}, + .gpio_polarity = ACTIVE_HIGH, +}; +static SYNO_GPIO_INFO phy_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {53}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static SYNO_GPIO_INFO fan_fail = { + .nr_gpio = 2, + .gpio_port = {41, 42}, + .gpio_polarity = ACTIVE_HIGH, +}; + +void syno_gpio_init(void) +{ + if (!syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = &hdd_detect; + } else { + check_gpio_consistency(syno_gpio.hdd_detect, &hdd_detect); + } + + if (!syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = &hdd_enable; + } else { + check_gpio_consistency(syno_gpio.hdd_enable, &hdd_enable); + } + + syno_gpio.fan_fail = &fan_fail; + syno_gpio.hdd_fail_led = &hdd_fail_led; + syno_gpio.hdd_present_led = &hdd_present_led; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = &phy_led_ctrl; + +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ +} + +void syno_gpio_cleanup(void) +{ + if (&hdd_detect == syno_gpio.hdd_detect) { + syno_gpio.hdd_detect = NULL; + } + + if (&hdd_enable == syno_gpio.hdd_enable) { + syno_gpio.hdd_enable = NULL; + } + + syno_gpio.fan_ctrl = NULL; + syno_gpio.hdd_fail_led = NULL; + syno_gpio.hdd_present_led = NULL; + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.phy_led_ctrl = NULL; +} + +int model_addon_init(struct synobios_ops *ops) +{ + /* enable to control PWR_LED */ + ops->set_power_led = SetPowerLedStatus; + + /* enable to control HDD_LED */ + ops->set_hdd_led = SetHddLed; + + /* enable to control PHY_LED */ + ops->set_phy_led = SetPhyLed; + + ops->get_fan_status = GetFanStatusActivePulse; + return 0; +} + +int model_addon_cleanup(struct synobios_ops *ops) +{ + return 0; +} diff --git a/drivers/syno/synobios/rtd1619b/fan-pwm.c b/drivers/syno/synobios/rtd1619b/fan-pwm.c new file mode 100644 index 000000000000..1850de1167db --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/fan-pwm.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2000-2012 Synology Inc. All rights reserved. */ +#include +#include +#include +#include "rtd1619b_common.h" +#include "syno_ttyS.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = PWMFanSpeedMapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > synobios_lock_ttyS_write(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} diff --git a/drivers/syno/synobios/rtd1619b/fan-resistor.c b/drivers/syno/synobios/rtd1619b/fan-resistor.c new file mode 100644 index 000000000000..a335190f115c --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/fan-resistor.c @@ -0,0 +1,28 @@ +// Copyright (c) 2000-2012 Synology Inc. All rights reserved. +#include +#include +#include +#include + +#include "rtd1619b_common.h" + +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + char speed_value; + int res = -EINVAL; + int model = GetModel(); + + switch (model) { + default: + if (FanStatusMappingType1(status, speed, &speed_value)) { + goto END; + } + } + if (SYNO_CTRL_FAN_RESISTOR(speed_value)) { + goto END; + } + + res = 0; +END: + return res; +} diff --git a/drivers/syno/synobios/rtd1619b/rtd1619b_common.c b/drivers/syno/synobios/rtd1619b/rtd1619b_common.c new file mode 100644 index 000000000000..cd065f837d6d --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/rtd1619b_common.c @@ -0,0 +1,372 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2016 Synology Inc. All rights reserved. */ + +#include "synobios.h" +#include +#include "rtd1619b_common.h" +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "../rtc/rtc-rtk-builtin.h" +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +#include +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#include "../led/led_trigger_disk.h" +#include "syno_ttyS.h" + +#if defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) +extern int (*syno_get_current)(unsigned char, struct tty_struct *); +extern int save_current_data_from_uart(unsigned char ch, struct tty_struct *tty); +extern int synobios_lock_ttyS_current(char *szCommand, char *szBuf); +#endif /* CONFIG_SYNO_TTY_MICROP_FUNCTIONS */ + +int model_addon_init(struct synobios_ops *ops); +int model_addon_cleanup(struct synobios_ops *ops); +int syno_rtd_get_temperature(void); + +static PWM_FAN_SPEED_MAPPING gPWMSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 30 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 40 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 50 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 80 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 99 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; +static int Uninitialize(void); + +static SYNO_HWMON_SENSOR_TYPE rtd1619b_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor = {{ + .sensor_name = HWMON_HDD_BP_DETECT, + }, { + .sensor_name = HWMON_HDD_BP_ENABLE, + }} +}; + +static SYNO_HWMON_SENSOR_TYPE rtd1619b_current_status = { + .type_name = HWMON_SYS_CURRENT_NAME, + .sensor_num = 1, + .sensor[0] = { + .sensor_name = "ADC", + }, +}; + +static struct hwmon_sensor_list rtd1619b_sensor_list = { + .thermal_sensor = NULL, + .voltage_sensor = NULL, + .fan_speed_rpm = NULL, + .psu_status = NULL, + .hdd_backplane = &rtd1619b_hdd_backplane_status, + .current_sensor = &rtd1619b_current_status, +}; +static struct hwmon_sensor_list *hwmon_sensor_list = &rtd1619b_sensor_list; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int (*GetMaxInternalHostNum)(void) = NULL; + +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_DS124: + iMaxInternalDiskNum = 1; + break; + case MODEL_DS223j: + case MODEL_DS223: + iMaxInternalDiskNum = 2; + break; + case MODEL_DS423: + iMaxInternalDiskNum = 4; + break; + default: + iMaxInternalDiskNum = 0; + break; + } + return iMaxInternalDiskNum; +} +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +int GetCPUTemperature(struct _SynoCpuTemp *pCPUTemp) +{ + int iRet = -1; + int iTemp = 0; + + if (!pCPUTemp) + goto END; + + iTemp = syno_rtd_get_temperature(); + + pCPUTemp->cpu_num = 1; + pCPUTemp->cpu_temp[0] = iTemp; + + iRet = 0; +END: + return iRet; +} + +static +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + while (HAVE_HDD_DETECT(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + index++; + } + + index = 1; + while (HAVE_HDD_ENABLE(index)) { +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index - 1); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY()) & 0x01) << (index - 1); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + + index++; + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%lu", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%lu", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +int SetHDDActLed(SYNO_LED ledStatus) +{ + int err = -1; + switch (ledStatus) { + case SYNO_LED_OFF: + SYNO_HDD_LED_SET(1, DISK_LED_OFF); + SYNO_HDD_LED_SET(2, DISK_LED_OFF); + break; + case SYNO_LED_ON: + SYNO_HDD_LED_SET(1, DISK_LED_GREEN_BLINK); + SYNO_HDD_LED_SET(2, DISK_LED_GREEN_BLINK); + break; + default: + goto ERR; + } + err = 0; +ERR: + return err; +} + +int SetPhyLed(SYNO_LED ledStatus) +{ + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + SYNO_ENABLE_PHY_LED(1); + break; + case SYNO_LED_OFF: + SYNO_ENABLE_PHY_LED(0); + break; + default: + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +extern unsigned int cpufreq_quick_get(unsigned int cpu); +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + int i; + + cpu->core = 0; + for_each_online_cpu(i) { + cpu->core++; + } + + snprintf(cpu->clock, sizeof(char) * maxLength, "%d", 1700); +} + +static +int SYNOIOGetCurrentStatusByMicroP(unsigned long* pulSysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szTTYCur[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulTTYCur = 0; + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szTTYCur, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szTTYCur, 10, &ulTTYCur); + if (0 > iRet) { + goto End; + } + // microP return value * 16.13 = System current (mA) (reference : uP #130) + *pulSysCurrent = (ulTTYCur * 16) + (ulTTYCur * 13 / 100); + + iRet = 0; +End: + return iRet; +} + +static +int HWMONGetCurrentStatusByMicroP(struct _SYNO_HWMON_SENSOR_TYPE *SysCurrent) +{ + int iRet = -1; + int len = 0; + unsigned char szTTYResult[TTY_BUF_SIZE] = {'\0'}; + unsigned char szCurrent[CURRENT_DATA_LEN+1] = {'\0'}; + unsigned long ulCurrent = 0; + + if (NULL == SysCurrent || NULL == hwmon_sensor_list) { + printk("SysCurrent null\n"); + goto End; + } + + memcpy(SysCurrent, hwmon_sensor_list->current_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + len = synobios_lock_ttyS_current(SZ_UART_CMD_CURRENT_GET, szTTYResult); + if (len < CURRENT_DATA_LEN) { + goto End; + } + memcpy(szCurrent, szTTYResult + len - CURRENT_DATA_LEN, CURRENT_DATA_LEN); + iRet = kstrtoul(szCurrent, 10, &ulCurrent); + if (0 > iRet) { + goto End; + } + snprintf(SysCurrent->sensor[0].value, sizeof(SysCurrent->sensor[0].value), "%ld", (ulCurrent * 16) + (ulCurrent * 13 / 100)); + + iRet = 0; +End: + return iRet; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_pericom_get_time, + .set_rtc_time = rtc_pericom_set_time, + .get_fan_status = NULL, + .set_fan_status = SetFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_power_led = NULL, + .set_disk_led = SetDiskLedStatusByTrigDiskSyno, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCPUTemperature, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_pericom_set_auto_poweron, + .init_auto_poweron = rtc_pericom_auto_poweron_init, + .uninit_auto_poweron = rtc_pericom_auto_poweron_uninit, + .set_alarm_led = NULL, + .get_backplane_status = NULL, + .get_mem_byte = NULL, + .get_buzzer_cleared = NULL, + .set_phy_led = NULL, + .set_hdd_led = NULL, + .module_type_init = InitModuleType, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + // for matching userspace usage, return 0 if button is pressed, else = 1 + .get_copy_button_status = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO, + .hwmon_get_sys_current = HWMONGetCurrentStatusByMicroP, + .get_sys_current = SYNOIOGetCurrentStatusByMicroP, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + module_t* pSynoModule = NULL; + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + syno_gpio_init(); +#ifdef MY_DEF_HERE + printk("Synobios %s GPIO initialized\n", syno_get_hw_version()); +#endif /* MY_DEF_HERE */ + + if (synobios_ops.module_type_init) { + synobios_ops.module_type_init(&synobios_ops); + } + + pSynoModule = module_type_get(); + + *ops = &synobios_ops; + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } +#if defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + syno_get_current = save_current_data_from_uart; +#endif /* CONFIG_SYNO_TTY_MICROP_FUNCTIONS */ + + model_addon_init(*ops); + + return 0; +} + +static int Uninitialize(void) +{ + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + syno_gpio_cleanup(); + model_addon_cleanup(*ops); + + return 0; +} + +int PWMFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gPWMSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gPWMSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gPWMSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} diff --git a/drivers/syno/synobios/rtd1619b/rtd1619b_common.h b/drivers/syno/synobios/rtd1619b/rtd1619b_common.h new file mode 100755 index 000000000000..a2e5e9946549 --- /dev/null +++ b/drivers/syno/synobios/rtd1619b/rtd1619b_common.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2000-2015 Synology Inc. All rights reserved. */ + +#include +#include +#include "../mapping.h" +#include "../common/common.h" + +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +int GetModel(void); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int InitModuleType(struct synobios_ops *ops); +int SetFanSpeedValue(char speed_value); +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed); +int SetHDDActLed(SYNO_LED ledStatus); +int SetPowerLedStatus(SYNO_LED status); +int SYNO_GPIO_READ(int pin); +void SYNO_GPIO_WRITE(int pin, int pValue); + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength); +// for matching userspace usage, return 0 if button is pressed, else = 1 +int GetFanStatusMircopWithGPIOCommon(int fanno, FAN_STATUS *pStatus); +int GetFanStatusActiveLow(int fanno, FAN_STATUS *pStatus); +void VdimmPwrCtrl(SYNO_LED ledStatus); +void syno_gpio_init(void); +void syno_gpio_cleanup(void); +int PWMFanSpeedMapping(FAN_SPEED speed); +int SetPhyLed(SYNO_LED ledStatus); +#if defined(CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY) || defined(CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK) +extern int syno_ahci_disk_led_enable_by_port(const unsigned short diskPort, const int iValue); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY || CONFIG_SYNO_AHCI_GPIO_SOFTWARE_PRESENT_BLINK */ + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; + SYNO_HWMON_SENSOR_TYPE *current_sensor; +}; diff --git a/drivers/syno/synobios/ryzen5k/Makefile b/drivers/syno/synobios/ryzen5k/Makefile new file mode 100644 index 000000000000..46db7b794d2d --- /dev/null +++ b/drivers/syno/synobios/ryzen5k/Makefile @@ -0,0 +1,17 @@ +include /env.mak + +obj-m += ryzen5k-synobios.o + +ryzen5k-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + rs4024xs+.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-pericom-lib.o \ + ../rtc/rtc-linux-pericom.o \ + ../i2c/i2c-linux.o \ + ryzen5k_common.o \ + ../led/led_trigger.o diff --git a/drivers/syno/synobios/ryzen5k/rs4024xs+.c b/drivers/syno/synobios/ryzen5k/rs4024xs+.c new file mode 100755 index 000000000000..74bd170ebcb6 --- /dev/null +++ b/drivers/syno/synobios/ryzen5k/rs4024xs+.c @@ -0,0 +1,211 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "ryzen5k_common.h" + +#define I2C_SWITCH_VAL 0x9 + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from ryzen5k_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +void RS4024xspSMBusSwitchInit(void) { + u8 data = I2C_SWITCH_VAL; + SMBusSwitchRegWrite(0, 1, &data); +} + +SYNO_HWMON_SENSOR_TYPE RS4024xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4024xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4024xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4024xsp_psu_status[2] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS4024xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +static +int RS4024xspI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {57}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void RS4024xspGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; +} + +static +void RS4024xspGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; +} + +static +int RS4024xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs4024xsp = MODULE_T_RS4024xsp; + module_t *pType = &type_rs4024xsp; + GPIO_PIN Pin; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio RYZEN5K_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = RYZEN5K_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs4024xsp_ops = { + .x86_init_module_type = RS4024xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = RS4024xspI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, + .x86_gpio_init = RS4024xspGpioInit, + .x86_gpio_cleanup = RS4024xspGpioCleanup, +}; + +struct hwmon_sensor_list rs4024xsp_sensor_list = { + .thermal_sensor = &RS4024xsp_thermal_sensor, + .voltage_sensor = &RS4024xsp_voltage_sensor, + .fan_speed_rpm = &RS4024xsp_fan_speed_rpm, + .psu_status = RS4024xsp_psu_status, + .hdd_backplane = &RS4024xsp_hdd_backplane_status, +}; diff --git a/drivers/syno/synobios/ryzen5k/ryzen5k_common.c b/drivers/syno/synobios/ryzen5k/ryzen5k_common.c new file mode 100755 index 000000000000..429f2c87f7c5 --- /dev/null +++ b/drivers/syno/synobios/ryzen5k/ryzen5k_common.c @@ -0,0 +1,566 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "ryzen5k_common.h" + +static int Uninitialize(void); + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; + +static int Uninitialize(void); + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_RS4024xsp: + iMaxInternalDiskNum = 16; + break; + } + return iMaxInternalDiskNum; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = RYZEN5K_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = RYZEN5K_BUZZER_OFF_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + + +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_RS4024xsp; + + if (!strncmp(gszSynoHWVersion, HW_RS4024xsp, strlen(HW_RS4024xsp))) { + model = MODEL_RS4024xsp; + } + + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + +#ifdef MY_DEF_HERE + syno_sys_temperature(pThermalTemp); +#endif /*MY_DEF_HERE*/ + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } + +#ifdef CONFIG_SYNO_X86_CORETEMP + iRet = syno_cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_pericom_get_time, + .set_rtc_time = rtc_pericom_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_pericom_set_auto_poweron, + .init_auto_poweron = rtc_pericom_auto_poweron_init, + .uninit_auto_poweron = rtc_pericom_auto_poweron_uninit, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + int i = 0; + int maxdisk = 0; +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_RS4024xsp: + model_ops = &rs4024xsp_ops; + RS4024xspSMBusSwitchInit(); + synobios_ops.set_power_led = SetPowerLedStatus; + hwmon_sensor_list = &rs4024xsp_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + maxdisk = GetMaxInternalDiskNum(); + for (i = 1; i <= maxdisk; ++i) { + syno_ahci_disk_led_enable_by_port(i, 1); + } +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + break; + default: + break; + } + + return 0; +} + +static int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if (synobios_ops.get_rtc_time) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if (synobios_ops.uninit_auto_poweron) { + synobios_ops.uninit_auto_poweron(); + } + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} + +void SMBusSwitchRegWrite(u8 command, u8 length, u8 *data) +{ + struct device_node *np = NULL; + struct i2c_client *client = NULL; + + while ((np = of_find_compatible_node(np, NULL, "nxp,pca9546"))) { + if (of_property_read_bool(np, "led_enable")) { + client = of_find_i2c_device_by_node(np); + + if (NULL == client || 0 > i2c_smbus_write_i2c_block_data(client, command, length, data)) { + printk("i2c_smbus_write_i2c_block_data failed\n"); + } + } + of_node_put(np); + } +} diff --git a/drivers/syno/synobios/ryzen5k/ryzen5k_common.h b/drivers/syno/synobios/ryzen5k/ryzen5k_common.h new file mode 100755 index 000000000000..686ed79d9ec9 --- /dev/null +++ b/drivers/syno/synobios/ryzen5k/ryzen5k_common.h @@ -0,0 +1,81 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "../led/led_9235.h" +#include "../led/led_trigger.h" +#include "../led/led_1475.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +#define I2C_BUS_NO 0 +extern void RS4024xspSMBusSwitchInit(void); +extern void SMBusSwitchRegWrite(u8 command, u8 length, u8 *data); + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern char gszSynoHWVersion[]; +extern struct model_ops rs4024xsp_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_pmbus_status(SYNO_HWMON_SENSOR_TYPE* , int); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern struct hwmon_sensor_list rs4024xsp_sensor_list; + +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ +#ifdef MY_DEF_HERE +extern int syno_sys_temperature(struct _SynoThermalTemp *pThermalTemp); +#endif /*MY_DEF_HERE*/ + +#define RYZEN5K_BUZZER_OFF_PIN 53 +#define RYZEN5K_BUZZER_CTRL_PIN 52 +#define RYZEN5K_DISK_LED_ACTIVATE_PIN 45 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/skylaked/Makefile b/drivers/syno/synobios/skylaked/Makefile new file mode 100644 index 000000000000..aaff4123e30e --- /dev/null +++ b/drivers/syno/synobios/skylaked/Makefile @@ -0,0 +1,15 @@ +include /env.mak + +obj-m += skylaked-synobios.o + +skylaked-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-x86.o \ + ../i2c/i2c-linux.o \ + skylaked_common.o \ + ../led/led_1475.o diff --git a/drivers/syno/synobios/skylaked/rs4021xsp.c b/drivers/syno/synobios/skylaked/rs4021xsp.c new file mode 100644 index 000000000000..df89538d7035 --- /dev/null +++ b/drivers/syno/synobios/skylaked/rs4021xsp.c @@ -0,0 +1,84 @@ +// Copyright (c) 2000-2015 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include "skylaked_common.h" + +#define PSU_I2C_BUS 0 +#define PSU_TOP_I2C_ADDR 0x58 +#define PSU_BTM_I2C_ADDR 0x59 + +// extern function from broadwell_common +extern int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status); +extern int xsSetBuzzerClear(unsigned char buzzer_cleared); +extern int xsGetBuzzerCleared(unsigned char *buzzer_cleared); +extern int xsCPUFanSpeedMapping(FAN_SPEED speed); +extern int xsFanSpeedMapping(FAN_SPEED speed); + +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {60}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +int RS4021xspI2CGetPowerInfo(POWER_INFO *power_info) +{ + int ret = -1; + int err = -1; + + if (NULL == power_info) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_TOP_I2C_ADDR, &(power_info->power_1)); + if (0 != err) { + goto FAIL; + } + + err = I2CSmbusReadPowerStatus(PSU_I2C_BUS, PSU_BTM_I2C_ADDR, &(power_info->power_2)); + if (0 != err) { + goto FAIL; + } + + ret = 0; + +FAIL: + return ret; +} + +static +int RS4021xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs4021xsp = MODULE_T_RS4021xsp; + module_t *pType = &type_rs4021xsp; + GPIO_PIN Pin; + + syno_gpio.fan_fail = NULL; + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.phy_led_ctrl = NULL; + syno_gpio.copy_button_detect = NULL; + + /* If user put "buzzer off" of redundant power then poweron, + * It may cause gpio SKYLAKED_BUZZER_CTRL_PIN set to low, it will casue unwanted buzzer off event*/ + if (ops && ops->set_gpio_pin) { + Pin.pin = SKYLAKED_BUZZER_CTRL_PIN; + Pin.value = 1; + ops->set_gpio_pin(&Pin); + } + + module_type_set(pType); + return 0; +} + +struct model_ops rs4021xsp_ops = { + .x86_init_module_type = RS4021xspInitModuleType, + .x86_fan_speed_mapping = xsFanSpeedMapping, + .x86_set_esata_led_status = NULL, + .x86_cpufan_speed_mapping = xsCPUFanSpeedMapping, + .x86_get_buzzer_cleared = xsGetBuzzerCleared, + .x86_get_power_status = RS4021xspI2CGetPowerInfo, + .x86_set_buzzer_clear = xsSetBuzzerClear, +}; diff --git a/drivers/syno/synobios/skylaked/skylaked_common.c b/drivers/syno/synobios/skylaked/skylaked_common.c new file mode 100755 index 000000000000..95e50f6c4349 --- /dev/null +++ b/drivers/syno/synobios/skylaked/skylaked_common.c @@ -0,0 +1,441 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#include "../i2c/i2c-linux.h" +#include "../rtc/rtc.h" +#include "skylaked_common.h" + +#ifdef MY_DEF_HERE +extern int giDenoOfTimeInterval; +#endif /* MY_DEF_HERE */ + +static struct model_ops *model_ops = NULL; + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +int (*GetMaxInternalHostNum)(void) = NULL; +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +/** + * Set Max internal disk numbers + */ +int GetMaxInternalDiskNum(void) +{ + int iMaxInternalDiskNum = 0; + + switch(GetModel()) { + case MODEL_RS4021xsp: + iMaxInternalDiskNum = 16; + break; + } + return iMaxInternalDiskNum; +} + +// If there is any necessary to modify these function on any other model, please rewrite another function to replace it +PWM_FAN_SPEED_MAPPING gxsSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +PWM_FAN_SPEED_MAPPING gxsCPUFanSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +int xsFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gxsSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gxsSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gxsSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +/* + * On RS10613xsp, and RS3413xsp we have no buzzer clear button anymore, so we need another way to stop redundant power buzzer + */ +int xsSetBuzzerClear(unsigned char buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + Pin.pin = SKYLAKED_BUZZER_CTRL_PIN; + Pin.value = buzzer_cleared; + if (0 > SetGpioPin(&Pin)) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + ret = 0; +End: + return ret; +} + +int xsGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + GPIO_PIN Pin; + int ret = -1; + + if ( NULL == buzzer_cleared ) { + goto End; + } + + *buzzer_cleared = 0; + + Pin.pin = SKYLAKED_BUZZER_OFF_BUTTON_PIN; + if ( 0 > GetGpioPin( &Pin ) ) { +#ifdef MY_DEF_HERE + giDenoOfTimeInterval = -1; +#endif /* MY_DEF_HERE */ + goto End; + } + + Pin.value = 1; + + if ( 0 == Pin.value ) { + *buzzer_cleared = 1; + // after read buzzer cleared, pull it back to high + // an workaround for #48623, because gpio 4 & 5 are jointed together + if (model_ops && model_ops->x86_set_buzzer_clear) { + model_ops->x86_set_buzzer_clear(1); + } + } + + ret = 0; +End: + return ret; + +} + +int xsCPUFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + + return iDutyCycle; +} + +#define GPIO_POWER_GOOD 1 +int SkylakedRedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + int err = -1; + + return err; +} + +static +int GetFanStatusMircopWithGPIO(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int GetFanStatus(int fanno, FAN_STATUS *pStatus) +{ + return -1; +} + +static +int SetFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int SetCpuFanStatus(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + + return iRet; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + rtc_bandon_get_time(&rtc_time_pkt); + return 0; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if (!strncmp(gszSynoHWVersion, HW_RS4021xsp, strlen(HW_RS4021xsp))) { + model = MODEL_RS4021xsp; + } + + return model; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetSysTemperature(struct _SynoThermalTemp *pThermalTemp) +{ + if (!pThermalTemp) { + return -1; + } + + + return 0; +} + +static +int GetCpuTemperatureI3Transfer(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + int iCPUIdx; + + if ( NULL == pCpuTemp ) { + goto END; + } +#ifdef CONFIG_SYNO_ADT7490_FEATURES + iRet = syno_get_adt_peci(pCpuTemp); +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + + if( 0 != iRet) { + goto END; + } + + for(iCPUIdx = 0; iCPUIdx < pCpuTemp->cpu_num; iCPUIdx++) { + pCpuTemp->cpu_temp[iCPUIdx] = pCpuTemp->cpu_temp[iCPUIdx] / 1000; + } +END: + return iRet; +} + +static +int SetAlarmLed(unsigned char ledON) +{ + GPIO_PIN Pin; + int iRet = -1; + + Pin.pin = SKYLAKED_ALARM_LED_PIN; + /** + * Attetion!! + * 0 Means alarm on + * 1 Means alarm off + * need to reverse + */ + if (ledON) { + Pin.value = 0; + } else { + Pin.value = 1; + } + + if (0 > SetGpioPin(&Pin)) { + goto End; + } + + iRet = 0; +End: + return iRet; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static +int SetBuzzerClear(unsigned char buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_set_buzzer_clear) { + ret = model_ops->x86_set_buzzer_clear(buzzer_cleared); + } + + return ret; +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_bandon_get_time, + .set_rtc_time = rtc_bandon_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_bandon_set_auto_poweron, + .get_fan_status = GetFanStatus, + .set_fan_status = SetFanStatus, + .get_sys_temperature = GetSysTemperature, + .get_cpu_temperature = GetCpuTemperatureI3Transfer, + .set_cpu_fan_status = SetCpuFanStatus, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .check_microp_id = NULL, + .set_microp_id = NULL, + .set_buzzer_clear = SetBuzzerClear, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + *ops = &synobios_ops; + + // for those model that have mix ahci and 9xxx internal disk, please implement GetMaxInternalHostNum + GetMaxInternalHostNum = NULL; + + + switch(GetModel()) + { + case MODEL_RS4021xsp: + model_ops = &rs4021xsp_ops; + synobios_ops.set_hdd_led = SetHddActLed; +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL + synobios_ops.set_disk_led = SYNODiskLedCtrlBy1475SGPIO; +#ifdef MY_DEF_HERE + funcSYNOSATADiskLedCtrl = funcSYNOCtrlDiskLedBy1475; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + break; + + default: + break; + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + return 0; +} + +int I2CSmbusReadPowerStatus(int i2c_bus_no, u16 i2c_addr, SYNO_POWER_STATUS* status) +{ + int ret = -1; + int err = -1; + u16 data = 0xffff; + static u16 uLostAddr = 0; + + if (NULL == status) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto FAIL; + } + + err = linuxI2CSmbusRegRead(i2c_bus_no, i2c_addr, PSU_DELTA_AC139_I2C_REG, &data); + if (0 != err) { + if (uLostAddr != i2c_addr) { + uLostAddr = i2c_addr; + printk("%s:%d return error!\n", __FILE__, __LINE__); + } + // i2c will read failed when 800W power is not inserted + // report bad power status with success return to avoid repeated log + *status = POWER_STATUS_BAD; + ret = 0; + goto FAIL; + } + if (uLostAddr == i2c_addr) { + uLostAddr = 0; + } + + if (data & PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT) { + *status = POWER_STATUS_BAD; + } else { + *status = POWER_STATUS_GOOD; + } + + ret = 0; + +FAIL: + return ret; +} diff --git a/drivers/syno/synobios/skylaked/skylaked_common.h b/drivers/syno/synobios/skylaked/skylaked_common.h new file mode 100755 index 000000000000..308d2fee5aa5 --- /dev/null +++ b/drivers/syno/synobios/skylaked/skylaked_common.h @@ -0,0 +1,46 @@ +// Copyright (c) 2000-2017 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#include "../led/led_1475.h" + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern struct model_ops rs4021xsp_ops; + +#ifdef CONFIG_SYNO_ADT7490_FEATURES +extern int syno_get_adt_peci(struct _SynoCpuTemp *); +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + +#ifdef CONFIG_SYNO_X86_CORETEMP +extern int syno_cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_X86_CORETEMP */ + +#define SKYLAKED_BUZZER_OFF_BUTTON_PIN 114 +#define SKYLAKED_BUZZER_CTRL_PIN 113 +#define SKYLAKED_ALARM_LED_PIN 223 + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" + +#define PSU_DELTA_AC139_I2C_REG 0x79 +#define PSU_DELTA_AC139_I2C_REG_ABNORMAL_STATUS_BIT 0x0800 + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_set_buzzer_clear)(unsigned char buzzer_cleared); +}; diff --git a/drivers/syno/synobios/switchtec/switchtec.c b/drivers/syno/synobios/switchtec/switchtec.c new file mode 100644 index 000000000000..f76442ff17d2 --- /dev/null +++ b/drivers/syno/synobios/switchtec/switchtec.c @@ -0,0 +1,183 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include +#include +#include +#include +#include "switchtec.h" +#include "../led/led_gpio.h" + +#define SWITCHTEC_MRPC_REGION_SIZE 0x1000 +#define SWITCHTEC_NUM_MAX 8 + +static int g_switch_num = 0; +// Memory-based Remote Procedure Calls +static void __iomem *g_mrpc[SWITCHTEC_NUM_MAX]; +static unsigned int g_led_off_gpio[SWITCHTEC_NUM_MAX]; +static struct pci_dev *g_pdev[SWITCHTEC_NUM_MAX]; + +int switchtec_init(void) +{ + unsigned int bus, dev, fun; + int idx, switch_num = 0; + int rc = -1; + struct device_node *pDeviceNode = NULL; + char *szProperty = NULL; + resource_size_t res_start; + + memset (g_mrpc, 0, sizeof(g_mrpc)); + memset (g_led_off_gpio, 0, sizeof(g_led_off_gpio)); + memset (g_pdev, 0, sizeof(g_pdev)); + + for_each_child_of_node(of_root, pDeviceNode) { + if (pDeviceNode->full_name == NULL) { + continue; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + if(0 != strncmp(pDeviceNode->full_name, DT_SWITCHTEC, strlen(DT_SWITCHTEC))) { +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if(0 != strncmp(pDeviceNode->full_name, "/"DT_SWITCHTEC, strlen("/"DT_SWITCHTEC))) { +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + continue; + } + ++switch_num; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + if (1 != sscanf(pDeviceNode->full_name, DT_SWITCHTEC"@%d", &idx)) { +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if (1 != sscanf(pDeviceNode->full_name, "/"DT_SWITCHTEC"@%d", &idx)) { +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + printk("synobios: cannot parse switchtec index\n"); + goto END; + } + if (0 > idx || SWITCHTEC_NUM_MAX <= idx) { + printk("synobios: invalid switchtec index (%d)\n", idx); + goto END; + } + szProperty = (char *)of_get_property(pDeviceNode, DT_PCIE_ROOT, NULL); + if(3 != sscanf(szProperty, "%x:%x.%x", &bus, &dev, &fun)) { + printk("synobios: cannot parse switchtec%d %s from dts\n", idx, DT_PCIE_ROOT); + goto END; + } + g_pdev[idx] = pci_get_domain_bus_and_slot(0, bus, PCI_DEVFN(dev, fun)); + + if (NULL == g_pdev[idx]) { + printk("synobios: swtichtec%d pci %02x:%02x.%d dev not found\n", + idx, bus, dev, fun); + goto END; + } + + res_start = pci_resource_start(g_pdev[idx], 0); + g_mrpc[idx] = devm_ioremap_wc(&g_pdev[idx]->dev, res_start, + SWITCHTEC_MRPC_REGION_SIZE); + if (NULL == g_mrpc[idx]) { + printk("synobios: switchtec%d devm_ioremap_wc failed\n", idx); + goto END; + } + + szProperty = (char *)of_get_property(pDeviceNode, DT_LED_OFF_GPIO, NULL); + if (1 != sscanf(szProperty, "%x", &g_led_off_gpio[idx])) { + printk("synobios: cannot parse switchtec%d %s from dts\n", idx, DT_LED_OFF_GPIO); + goto END; + } + } + g_switch_num = switch_num; + rc = 0; +END: + if (rc) { + switchtec_deinit(); + } + return rc; +} + +void switchtec_deinit(void) +{ + int i; + + for (i = 0; i < SWITCHTEC_NUM_MAX; ++i) { + if (NULL == g_mrpc[i]) { + continue; + } + devm_iounmap(&g_pdev[i]->dev, g_mrpc[i]); + } + memset (g_mrpc, 0, sizeof(g_mrpc)); + memset (g_led_off_gpio, 0, sizeof(g_led_off_gpio)); + memset (g_pdev, 0, sizeof(g_pdev)); + g_switch_num = 0; +} + +int switchtec_gpio_config(int switch_no, unsigned int gpio, unsigned int level) +{ + int rc = -1; + uint64_t val; + if (switch_no < 0 || switch_no >= g_switch_num) { + printk("synobios: invalid switch_no (%d)\n", switch_no); + goto END; + } + if (NULL == g_mrpc[switch_no]) { + printk("synobios: mrpc[%d] is null\n", switch_no); + goto END; + } +// Reference Microsemi Global Address Space and Management through MRPC +// BITS NAME HEX DEC DECODE +// [7:0] Sub Command = 0x3 3 Set GPIO Pin +// [15:8] Reserved = 0x0 0 +// [23:16] Logical Index 0 = 0xa1 161 GPIO # +// [31:24] Logical Index 1 = 0x0 0 +// [39:32] GPIO Data = 0x1 1 The Signal is High +// [63:40] Reserved = 0x0 0 + val = 0x3ull | (gpio << 16); + if (level) { + val |= 0x100000000ull; + } + writeq(val, g_mrpc[switch_no]); + writel(0x10002, g_mrpc[switch_no]+0x800); + rc = 0; +END: + return rc; +} + +int switchtec_led_set(SYNO_LED ledStatus) +{ + int i, rc = 0; + + for (i = 0; i < g_switch_num; ++i) { + if (switchtec_gpio_config(i, g_led_off_gpio[i], (SYNO_LED_OFF == ledStatus))) { + printk("synobios: switchtec_gpio_config switchtec%d failed\n", i); + rc = -1; + } + } + + return rc; +} + +int switchtec_set_disk_led(DISKLEDSTATUS *cmd) +{ + u8 state = PIN_BITMAP_OFF; + u32 pin = 0, val = 0; + int ret = -1; + + switch (cmd->status) { + case DISK_LED_ORANGE_SOLID: + state = PIN_BITMAP_ORANGE; + break; + case DISK_LED_OFF: + case DISK_LED_GREEN_SOLID: + case DISK_LED_GREEN_BLINK: + case DISK_LED_ORANGE_BLINK: + // only support set faulty LED now + state = PIN_BITMAP_OFF; + break; + default: + goto END; + } + + if (HAVE_HDD_FAIL_LED_BY_SLOT(cmd->szNodeName, cmd->diskno)) { + pin = HDD_FAIL_LED_PIN_BY_SLOT(cmd->szNodeName, cmd->diskno); + val = EVAL_PIN_VAL(HDD_FAIL_LED_POLARITY_BY_SLOT(cmd->szNodeName, cmd->diskno), state & PIN_BITMAP_ORANGE); + switchtec_gpio_config(HDD_SWITCH_NO(cmd->diskno), pin, val); + } + ret = 0; +END: + return ret; +} diff --git a/drivers/syno/synobios/switchtec/switchtec.h b/drivers/syno/synobios/switchtec/switchtec.h new file mode 100644 index 000000000000..39d59488ffc9 --- /dev/null +++ b/drivers/syno/synobios/switchtec/switchtec.h @@ -0,0 +1,6 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. +#include "synobios.h" +int switchtec_init(void); +void switchtec_deinit(void); +int switchtec_led_set(SYNO_LED ledStatus); +int switchtec_set_disk_led(DISKLEDSTATUS *cmd); diff --git a/drivers/syno/synobios/syno_power_outage/syno_power_outage.c b/drivers/syno/synobios/syno_power_outage/syno_power_outage.c new file mode 100644 index 000000000000..4183da1895a3 --- /dev/null +++ b/drivers/syno/synobios/syno_power_outage/syno_power_outage.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include "../common/common.h" + +extern SYNO_GPIO_INFO power_outage_gpio; +static int power_outage_gpio_pin = 7; + +static DEFINE_MUTEX(power_outage_mutex); +static LIST_HEAD(power_outage_list); + +struct power_outage_node { + atomic_t event; + wait_queue_head_t poll; + struct list_head list; +}; + +static int power_outage_open(struct inode *inode, struct file *file) +{ + int ret = -1; + struct power_outage_node *pon = NULL; + + pon = kmalloc(sizeof(struct power_outage_node), GFP_KERNEL); + if (!pon) { + ret = -ENOMEM; + goto END; + } + + atomic_set(&pon->event, 0); + init_waitqueue_head(&pon->poll); + INIT_LIST_HEAD(&pon->list); + + mutex_lock(&power_outage_mutex); + list_add(&pon->list, &power_outage_list); + mutex_unlock(&power_outage_mutex); + + file->private_data = pon; + ret = 0; +END: + return ret; +} + +static ssize_t power_outage_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) +{ + char po_buf[2] = {0}; + int po_status = SYNO_GPIO_READ(power_outage_gpio_pin); + ssize_t ret = 0; + + size = snprintf(po_buf, 2, "%d", po_status); + if (copy_to_user(buf, po_buf, size)) { + ret = -EFAULT; + goto END; + } + + ret = size; +END: + return ret; +} + +static unsigned int power_outage_poll(struct file *file, struct poll_table_struct *wait) +{ + struct power_outage_node *pon = file->private_data; + unsigned int mask = 0; + + poll_wait(file, &pon->poll, wait); + if (atomic_read(&pon->event)) { + mask |= POLLIN | POLLRDNORM; + atomic_set(&pon->event, 0); + } + + return mask; +} + +static int power_outage_release(struct inode *inode, struct file *file) +{ + struct power_outage_node *pon = file->private_data; + + mutex_lock(&power_outage_mutex); + list_del(&pon->list); + mutex_unlock(&power_outage_mutex); + + kfree(pon); + return 0; +} + +static const struct file_operations power_outage_fops = { + .owner = THIS_MODULE, + .open = power_outage_open, + .read = power_outage_read, + .poll = power_outage_poll, + .release = power_outage_release, +}; + +static void power_outage_notify(struct work_struct *work) +{ + struct list_head *p = NULL; + struct power_outage_node *pon = NULL; + + mutex_lock(&power_outage_mutex); + list_for_each(p, &power_outage_list) { + pon = list_entry(p, struct power_outage_node, list); + atomic_set(&pon->event, 1); + wake_up_interruptible(&pon->poll); + } + mutex_unlock(&power_outage_mutex); +} +DECLARE_WORK(power_outage_work, power_outage_notify); + +static irqreturn_t power_outage_handler(int irq, void *dev_id) +{ + schedule_work(&power_outage_work); + + return IRQ_HANDLED; +} + +int syno_power_outage_init(void) +{ + struct proc_dir_entry *syno_power_outage_entry; + + power_outage_gpio_pin = power_outage_gpio.gpio_port[0]; + + syno_power_outage_entry = proc_create_data("syno_power_outage", 0444, NULL, + &power_outage_fops, NULL); + if (!syno_power_outage_entry) { + printk(KERN_ERR "synobios create syno_power_outage entry fail\n"); + return -EFAULT; + } + + if (request_irq(syno_gpio_to_irq(power_outage_gpio_pin), + power_outage_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "power_outage_handler", NULL)) { + printk(KERN_ERR "synobios failed to request power outage IRQ\n"); + } + + printk(KERN_INFO "synobios syno_power_outage entry initialized\n"); + + return 0; +} + +void syno_power_outage_remove(void) +{ + free_irq(syno_gpio_to_irq(power_outage_gpio_pin), NULL); + remove_proc_entry("syno_power_outage", NULL); + return ; +} diff --git a/drivers/syno/synobios/syno_power_outage/syno_power_outage.h b/drivers/syno/synobios/syno_power_outage/syno_power_outage.h new file mode 100644 index 000000000000..1a54c7ff8d71 --- /dev/null +++ b/drivers/syno/synobios/syno_power_outage/syno_power_outage.h @@ -0,0 +1,8 @@ +/* Copyright (c) 2000-2017 Synology Inc. All rights reserved.*/ +#ifndef SYNO_POWER_OUTAGE_H +#define SYNO_POWER_OUTAGE_H + +int syno_power_outage_init(void); +void syno_power_outage_remove(void); + +#endif /* SYNO_POWER_OUTAGE_H */ diff --git a/drivers/syno/synobios/syno_ttyS/syno_ttyS.c b/drivers/syno/synobios/syno_ttyS/syno_ttyS.c new file mode 100755 index 000000000000..69872357b63e --- /dev/null +++ b/drivers/syno/synobios/syno_ttyS/syno_ttyS.c @@ -0,0 +1,592 @@ +#include +#include +#include +#include +#include +#include +#include "syno_ttyS.h" +#include + +#ifdef DEBUG +#define DBG(fmt, args...) printk(KERN_DEBUG "synotty: " fmt "\n", ##args) +#else +#define DBG(fmt, args...) do { } while(0) +#endif /* #ifdef DEBUG */ + +typedef struct _tag_MICROPREADLIST { + struct list_head readList; + struct mutex readListLock; + struct completion event; + struct completion writing_event; +} MICROPREADLIST; + +typedef struct syno_tty_buf { + unsigned char data[TTY_BUF_SIZE]; + int widx; + int ridx; + spinlock_t lock; + struct completion event; +} SYNOTTYBUF; + +SYNOTTYBUF tty_buf; +SYNOTTYBUF current_tty_buf; + +MICROPREADLIST micropReadList; + +#define SYNO_TTYS_PATH "/dev/ttyS" +#define SYNO_UART_TTYS_INDEX "1" +/* default syno uart ttys path is /dev/ttyS1 */ +#define SYNO_TTY_MAX_RETRY 5 +#define SYNO_UART_TTYS_PATH SYNO_TTYS_PATH SYNO_UART_TTYS_INDEX +#define SYNO_TTY_COMPLETION_TIMEOUT (UP_DELAY*SYNO_TTY_MAX_RETRY*4) + +struct file *tty_filp = NULL; +static int micropLogSwitch = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int syno_tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) +{ + struct ktermios old_termios; + int iRet = -1; + + if (NULL == tty || NULL == new_termios) { + goto ERR; + } + + down_write(&tty->termios_rwsem); + old_termios = tty->termios; + tty->termios = *new_termios; + + if (tty && tty->ops && tty->ops->set_termios) { + tty->ops->set_termios(tty, &old_termios); + } + + if (tty->ldisc && tty->ldisc->ops && tty->ldisc->ops->set_termios) { + tty->ldisc->ops->set_termios(tty, &old_termios); + } + + up_write(&tty->termios_rwsem); + iRet = 0; +ERR: + return iRet; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + +int syno_ttyS_set_termios(void) +{ + int ret = -1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + struct ktermios new_termios; + struct tty_struct *tty = NULL; +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + struct termios new_termios; + mm_segment_t fs; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + + if (!tty_filp) { + printk(KERN_ERR "synobios need open %s before set termios\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + tty = ((struct tty_file_private *)tty_filp->private_data)->tty; + memcpy(&new_termios, &tty->termios, sizeof(struct ktermios)); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if (!tty_filp->f_op) { + printk(KERN_ERR "synobios %s file->f_op struct error\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + if (!tty_filp->f_op->unlocked_ioctl) { + printk(KERN_ERR "synobios %s file->f_op->unlocked_ioctl error\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + fs = get_fs(); + set_fs(KERNEL_DS); + + ret = tty_filp->f_op->unlocked_ioctl(tty_filp, TCGETS, (unsigned long)&new_termios); + if (ret < 0) { + printk(KERN_ERR "synobios ioctl TCGETS %s failed\n", SYNO_UART_TTYS_PATH); + goto END; + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + + /* syno microP termios setting */ + new_termios.c_cflag &= ~(CBAUD | CBAUDEX); + new_termios.c_cflag |= B9600; + new_termios.c_cflag |= (CLOCAL | CREAD); + new_termios.c_cflag &= ~PARENB; + new_termios.c_cflag &= ~CSTOPB; + new_termios.c_cflag &= ~CSIZE; + new_termios.c_cflag |= CS8; + new_termios.c_cflag &= ~CRTSCTS; + new_termios.c_lflag = 0; + new_termios.c_oflag &= ~OPOST; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + ret = syno_tty_set_termios(tty, &new_termios); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + ret = tty_filp->f_op->unlocked_ioctl(tty_filp, TCSETS, (unsigned long)&new_termios); + if (ret < 0) { + printk(KERN_ERR "synobios ioctl TCSETS %s failed\n", SYNO_UART_TTYS_PATH); + goto END; + } + ret = 0; +END: + set_fs(fs); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +ERR: + return ret; +} + +int save_char_from_uart(unsigned char ch, struct tty_struct *tty) +{ + static int save_bytes = 0; + static int state = 0; + int save_char_flag = 0; + + if (0 != strcmp(tty->name, TTY_NAME)) { + goto END; + } + + switch (state) { + case 0: + if (ch == PREFIX_CH) { + DBG("state 0 : get prefix"); + state = 1; + save_char_flag = 1; + } else { + DBG("state 0 : not prefix %x (%c)", ch, ch); + } + break; + case 1: + save_bytes = ch - '0'; + state = 2; + save_char_flag = 1; + DBG("state 1 : save %d bytes (%x)", save_bytes, ch); + break; + case 2: + if (save_bytes) { + spin_lock(&tty_buf.lock); + tty_buf.data[tty_buf.widx] = ch; + DBG("state 2 : [%d] = 0x%x, get_ch = 0x%x", tty_buf.widx, tty_buf.data[tty_buf.widx], ch); + tty_buf.widx = (tty_buf.widx+1) % TTY_BUF_SIZE; + spin_unlock(&tty_buf.lock); + save_bytes -= 1; + save_char_flag = 1; + if (!save_bytes) + state = 0; + } + break; + default: + DBG("state %d : ERROR", state); + } +END: + return save_char_flag; +} +EXPORT_SYMBOL(save_char_from_uart); + +int save_current_data_from_uart(unsigned char ch, struct tty_struct *tty) +{ + static int state = 0; + int save_char_flag = 0; + + if (0 != strcmp(tty->name, TTY_NAME)) { + goto END; + } + + switch (state) { + case 0: + if (ch == SZ_UART_CURRENT_PREFIX) { + DBG("state 0 : get ADC current prefix"); + state = 1; + save_char_flag = 1; + } else { + DBG("state 0 : not prefix %x (%c)", ch, ch); + } + break; + case 1: + if (SZ_UART_CURRENT_SUFFIX == ch) { + state = 0; + complete(¤t_tty_buf.event); + } else { + spin_lock(¤t_tty_buf.lock); + /* To prevent uP '0' results in DSM poweroff, uP change 0 to * for current output. + * Therefore, we replace * with 0 to get reasonable current value. + */ + if (SZ_UART_CURRENT_ZERO_SUBSTITUE == ch) { + current_tty_buf.data[current_tty_buf.widx] = SZ_UART_CURRENT_ZERO; + } else { + current_tty_buf.data[current_tty_buf.widx] = ch; + } + DBG("state 2 : [%d] = 0x%x, get_ch = 0x%x", current_tty_buf.widx, current_tty_buf.data[current_tty_buf.widx], ch); + current_tty_buf.widx = (current_tty_buf.widx+1) % TTY_BUF_SIZE; + spin_unlock(¤t_tty_buf.lock); + } + save_char_flag = 1; + break; + default: + DBG("state %d : ERROR", state); + } +END: + return save_char_flag; +} +EXPORT_SYMBOL(save_current_data_from_uart); + +int syno_ttyS_open(void) +{ + int ret = -1; + + if (tty_filp) { + printk(KERN_INFO "%s have been opened in synobios\n", SYNO_UART_TTYS_PATH); + goto END; + } + + mutex_init(µpReadList.readListLock); + INIT_LIST_HEAD(µpReadList.readList); + init_completion(µpReadList.event); + init_completion(µpReadList.writing_event); + complete(µpReadList.writing_event); + memset(&tty_buf, 0x0, sizeof(SYNOTTYBUF)); + spin_lock_init(&tty_buf.lock); + memset(¤t_tty_buf, 0x0, sizeof(SYNOTTYBUF)); + init_completion(¤t_tty_buf.event); + spin_lock_init(¤t_tty_buf.lock); + + tty_filp = filp_open(SYNO_UART_TTYS_PATH, O_RDWR | O_NOCTTY | O_NONBLOCK , 0); + if (IS_ERR(tty_filp)) { + printk(KERN_ERR "synobios unable to open %s\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + if (syno_ttyS_set_termios()) { + printk(KERN_ERR "synobios unable to set termios of %s\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + printk(KERN_INFO "synobios open %s success\n", SYNO_UART_TTYS_PATH); +END: + ret = 0; +ERR: + return ret; +} + +/** + * read data from microP device in synobios. + * should open before read. + * if read fail will return -1 else return data length. + * + * @param [OUT] szBuf Store read data + * @param [IN] size Max size of szBuf + * @param [IN] micropReadWaitingNode: waiting node for queuing request of reading microp, + * waiting node must be added to waiting queue before calling this function, + * usually this is done with writing command to microp. + * NULL for none waiting call + * @return -1: Failed + * else: data length + **/ + +static int syno_ttyS_read(char *szBuf, int size) +{ + int ret = -1, errorKernelRead = 0; + int len = -1, recvLength = 0, i = 0; + char *rgTmp = NULL; + if (NULL == szBuf) { + printk(KERN_ERR "synobios can't store to empty buffer from %s\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + if (1 >= size) { + printk(KERN_ERR "synobios can't store to Null-terminated string with size <= 1\n"); + goto ERR; + } + if(0 != szBuf[0] && micropLogSwitch) { + printk(KERN_INFO "%s: read microP command [%s] called by %s\n", __func__, szBuf, current->comm); + } + + memset(szBuf, 0, size); + size -= 1; + + rgTmp = kmalloc(size, GFP_KERNEL); + if (!rgTmp) { + goto ERR; + } + if (!tty_filp) { + printk(KERN_ERR "synobios need open %s before read\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + // retry to fillup szBuf + for (i = 0; i < SYNO_TTY_MAX_RETRY; i++) { + memset(rgTmp, 0, size); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + len = kernel_read(tty_filp, rgTmp, size - recvLength, &tty_filp->f_pos); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + len = kernel_read(tty_filp, tty_filp->f_pos, rgTmp, size - recvLength); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if (0 > len) { + errorKernelRead = len; + msleep(UP_DELAY); + continue; + } + memcpy(szBuf + recvLength, rgTmp, len); + recvLength += len; + if (recvLength >= size) { + break; + } + msleep(UP_DELAY); + } + if (0 == recvLength && -EAGAIN != errorKernelRead) { + goto ERR; + } + + ret = recvLength; +ERR: + if (rgTmp) { + kfree(rgTmp); + } + return ret; +} + +static int syno_ttyS_write(const char* szCmd) +{ + int ret = -1; + int len = -1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + mm_segment_t fs; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */ + + if (!tty_filp) { + printk(KERN_ERR "synobios need open %s before write\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + if (!szCmd) { + printk(KERN_ERR "synobios can't write empty command to %s\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + if(micropLogSwitch) { + printk(KERN_INFO "%s: wirte microP command [%s] called by %s\n", __func__, szCmd, current->comm); + } + + /* If all platform kernel version >= 3.10, can use kernel_write instead of vfs_write */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + len = kernel_write(tty_filp, szCmd, strlen(szCmd), &tty_filp->f_pos); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + fs = get_fs(); + set_fs(KERNEL_DS); + len = vfs_write(tty_filp, (__force const char __user *)szCmd, strlen(szCmd), &tty_filp->f_pos); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if (len < 0) { + printk(KERN_ERR "synobios write %s to %s failed\n", szCmd, SYNO_UART_TTYS_PATH); + goto END; + } + + ret = len; +END: +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + set_fs(fs); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */ +ERR: + return ret; +} + +int syno_ttyS_write_with_length(const char* szCmd, const int cbCmd) +{ + int ret = -1; + int len = -1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + mm_segment_t fs; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */ + + if (!tty_filp) { + printk(KERN_ERR "synobios need open %s before write\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + + if (!szCmd || 0 == cbCmd) { + printk(KERN_ERR "synobios can't write empty command to %s\n", SYNO_UART_TTYS_PATH); + goto ERR; + } + if(micropLogSwitch) { + printk(KERN_INFO "%s: write microP command [%s] called by %s\n", __func__, szCmd, current->comm); + } + + /* If all platform kernel version >= 3.10, can use kernel_write instead of vfs_write */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + len = kernel_write(tty_filp, szCmd, cbCmd, &tty_filp->f_pos); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + fs = get_fs(); + set_fs(KERNEL_DS); + len = vfs_write(tty_filp, (__force const char __user *)szCmd, cbCmd, &tty_filp->f_pos); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if (len < 0) { + printk(KERN_ERR "synobios write %s to %s failed\n", szCmd, SYNO_UART_TTYS_PATH); + goto END; + } + + ret = len; +END: +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + set_fs(fs); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) */ +ERR: + return ret; +} + +int synobios_lock_ttyS_write(const char *szBuf) +{ + int ret = -1; + mutex_lock(µpReadList.readListLock); + ret = syno_ttyS_write(szBuf); + mutex_unlock(µpReadList.readListLock); + return ret; +} + +int synobios_lock_ttyS_read(char *szBuf, int size) +{ + int ret = -1; + LIST_HEAD(microp_reading_node); + mutex_lock(µpReadList.readListLock); + if (!list_empty(µpReadList.readList) || !completion_done(&(micropReadList.writing_event))) { + ret = -EBUSY; + mutex_unlock(µpReadList.readListLock); + goto END; + } + list_add_tail(µp_reading_node, µpReadList.readList); + mutex_unlock(µpReadList.readListLock); + + ret = syno_ttyS_read(szBuf, size); + + mutex_lock(µpReadList.readListLock); + list_del(µp_reading_node); + mutex_unlock(µpReadList.readListLock); + if (!completion_done(&(micropReadList.writing_event))) { + complete(µpReadList.writing_event); + } +END: + return ret; +} + +int synobios_lock_ttyS_write_and_read(char *szBuf, int size) +{ + int ret = -1; + LIST_HEAD(micropReadNode); + + mutex_lock(µpReadList.readListLock); + list_add_tail(µpReadNode, µpReadList.readList); + mutex_unlock(µpReadList.readListLock); + + if (0 == wait_for_completion_timeout(µpReadList.writing_event, SYNO_TTY_COMPLETION_TIMEOUT) || + 0 > synobios_lock_ttyS_write(szBuf)) { + ret = -EFAULT; + goto END; + } + + wait_for_completion_timeout(µpReadList.event, UP_DELAY); + ret = syno_ttyS_read(szBuf, size); + +END: + mutex_lock(µpReadList.readListLock); + list_del(µpReadNode); + mutex_unlock(µpReadList.readListLock); + if (!completion_done(&(micropReadList.writing_event))) { + complete(µpReadList.writing_event); + } + + return ret; +} + +int synobios_lock_ttyS_protection(char *szCommand, char *szBuf) { + int ret = -1, len = 0, index = 0; + if (NULL == szCommand || NULL == szBuf) { + goto END; + } + + + mutex_lock(µpReadList.readListLock); + syno_ttyS_write_with_length(szCommand, TTY_PROTECT_CMD_SIZE); + mdelay(UP_DELAY); + + while (tty_buf.ridx != tty_buf.widx) { + spin_lock_irq(&tty_buf.lock); + len += sprintf(szBuf+index*2, "%.2x", tty_buf.data[tty_buf.ridx]); + tty_buf.ridx = (tty_buf.ridx+1) % TTY_BUF_SIZE; + index++; + spin_unlock_irq(&tty_buf.lock); + } + mutex_unlock(µpReadList.readListLock); + ret = len; +END: + return ret; +} +EXPORT_SYMBOL(synobios_lock_ttyS_protection); + +int synobios_lock_ttyS_current(char *szCommand, char *szBuf) { + int ret = -1, len = 0, index = 0; + LIST_HEAD(microp_waiting_read); + + if (NULL == szCommand || NULL == szBuf) { + goto END; + } + + mutex_lock(µpReadList.readListLock); + list_add_tail(µp_waiting_read, µpReadList.readList); + mutex_unlock(µpReadList.readListLock); + + if (0 == wait_for_completion_timeout(µpReadList.writing_event, SYNO_TTY_COMPLETION_TIMEOUT) || + 0 > synobios_lock_ttyS_write(szCommand)) { + ret = -EFAULT; + goto END; + } + + wait_for_completion_timeout(¤t_tty_buf.event, UP_DELAY); + + spin_lock_irq(¤t_tty_buf.lock); + while (current_tty_buf.ridx != current_tty_buf.widx) { + len += sprintf(szBuf+index, "%c", current_tty_buf.data[current_tty_buf.ridx]); + current_tty_buf.ridx = (current_tty_buf.ridx+1) % TTY_BUF_SIZE; + index++; + } + spin_unlock_irq(¤t_tty_buf.lock); + if (0 == len) { + printk(KERN_ERR "synobios get empty ttyS current\n"); + goto END; + } + ret = len; +END: + + mutex_lock(µpReadList.readListLock); + list_del(µp_waiting_read); + mutex_unlock(µpReadList.readListLock); + if (!completion_done(&(micropReadList.writing_event))) { + complete(µpReadList.writing_event); + } + + return ret; +} +EXPORT_SYMBOL(synobios_lock_ttyS_current); + +void syno_ttyS_close(void) +{ + if (!tty_filp) { + printk(KERN_INFO "%s wasn't opened in synobios", SYNO_UART_TTYS_PATH); + goto ERR; + } + + filp_close(tty_filp, NULL); + tty_filp = NULL; +ERR: + return; +} + +void try_wakeup_waiting_microp(void) { + if (!completion_done(&(micropReadList.event))) { + complete(µpReadList.event); + } +} +EXPORT_SYMBOL(try_wakeup_waiting_microp); + +void set_log_switch(int logSwitch){ + micropLogSwitch = logSwitch; +} diff --git a/drivers/syno/synobios/syno_ttyS/syno_ttyS_srm.c b/drivers/syno/synobios/syno_ttyS/syno_ttyS_srm.c new file mode 100755 index 000000000000..e87669dbcd44 --- /dev/null +++ b/drivers/syno/synobios/syno_ttyS/syno_ttyS_srm.c @@ -0,0 +1,65 @@ + +#include +int syno_ttyS_set_termios(void) +{ + return 0; +} + +int save_char_from_uart(unsigned char ch, struct tty_struct *tty) +{ + return 0; +} +EXPORT_SYMBOL(save_char_from_uart); + +int save_current_data_from_uart(unsigned char ch, struct tty_struct *tty) +{ + return 0; +} +EXPORT_SYMBOL(save_current_data_from_uart); + +int syno_ttyS_open(void) +{ + return 0; +} + + + +static int syno_ttyS_write(const char* szCmd) +{ + return 0; +} + +int syno_ttyS_write_with_length(const char* szCmd, const int cbCmd) +{ + return 0; +} + +int synobios_lock_ttyS_write(const char *szBuf) +{ + return 0; +} + +int synobios_lock_ttyS_read(char *szBuf, int size) +{ + return 0; +} + +int synobios_lock_ttyS_write_and_read(char *szBuf, int size) +{ + return 0; +} + +int synobios_lock_ttyS_protection(char *szCommand, char *szBuf) { + return 0; +} +EXPORT_SYMBOL(synobios_lock_ttyS_protection); + +int synobios_lock_ttyS_current(char *szCommand, char *szBuf) { + return 0; +} +EXPORT_SYMBOL(synobios_lock_ttyS_current); + +void syno_ttyS_close(void) +{ + return; +} diff --git a/drivers/syno/synobios/synobios.c b/drivers/syno/synobios/synobios.c new file mode 100755 index 000000000000..938e79101c75 --- /dev/null +++ b/drivers/syno/synobios/synobios.c @@ -0,0 +1,3231 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include + +#include +#include /* printk() */ +#include /* error codes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +#include +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK +#include "syno_shutdown_hook.h" +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + +#include "synobios.h" +#include +#include "mapping.h" +#include "rtc/rtc.h" +#include // readl(), writel() +#include +#ifdef MY_DEF_HERE +#include +#endif +#ifdef CONFIG_MD +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) +extern int (*funcSYNOSendRaidEvent)(unsigned int type, unsigned int raidno, unsigned int diskno, unsigned long long sector); +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) */ +#endif /* CONFIG_MD */ +#if defined(CONFIG_SYNO_TTY_EXPORT) || defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) +#include "syno_ttyS.h" +extern int (*syno_get_current)(unsigned char, struct tty_struct *); +#ifdef CONFIG_SYNO_SYNOBIOS_EVENT +#else /* CONFIG_SYNO_SYNOBIOS_EVENT */ +extern int (*funcSYNOMicropGetEvent)(struct tty_struct *); +#endif /* CONFIG_SYNO_SYNOBIOS_EVENT */ +#endif /* SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ +#endif /* MY_DEF_HERE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + +#ifdef MY_DEF_HERE +extern int (*funcSYNOSendScsiErrorEvent)(SYNOBIOS_EVENT_PARM parms); +#endif /* MY_DEF_HERE */ + +#if defined(CONFIG_SYNO_SATA_PM_DEVICE_I2C) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) +extern int (*funcSYNOSendEunitResetEvent)(SYNOBIOS_EVENT_PARM parms); +#endif /* defined(CONFIG_SYNO_SATA_PM_DEVICE_I2C) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) */ + +#if 0 +#define DBGMESG(x...) printk(x) +#else +#ifndef MY_DEF_HERE +#define DBGMESG(x...) +#endif +#endif + +static DEFINE_MUTEX(sys_status_lock); + +static DEFINE_RWLOCK(LedSetLock); + +SYNO_AUTO_POWERON gPwSched; +static int check_fan = 1; +module_param(check_fan, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(check_fan, "seconds to delay before using a new device"); + +static int system_mode = 0; +module_param(system_mode, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(system_mode, "Distinguish in junior mode or system mode"); + + +static struct synobios_ops *synobios_ops; +/* Each platform or model should implement their own init/cleanup function */ +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops); +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops); + +struct sd_softc { + int countEvents; + int idxPtr; + SYNOBIOSEVENT rgEvents[SYNOBIOS_NEVENTS]; + wait_queue_head_t wq_poll; + spinlock_t lock; +}; +static struct sd_softc scSynoBios; +static SYNO_SYS_STATUS *pgSysStatus = NULL; + +#define SZ_PROC_SYNOBIOS_ROOT "synobios" +struct proc_dir_entry *proc_synobios_root = NULL; + +#if (defined(CONFIG_ATA) || defined(CONFIG_SCSI_SATA)) +#ifdef MY_DEF_HERE +extern int (*funcSYNOSendDiskResetPwrEvent)(unsigned int type, unsigned int diskno); +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE +extern int (*funcSYNOSendDiskPortDisEvent)(unsigned int type, unsigned int diskno, unsigned int shostno); +#ifdef MY_DEF_HERE +extern int (*funcSYNOSendDiskPortLostEvent)(unsigned int diskno, + unsigned int errorType); +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ +#if (defined(MY_DEF_HERE) || defined(SYNO_HAS_SDCARDREADER)) +extern int (*funcSYNOGetHwCapability)(CAPABILITY *); +#ifdef MY_DEF_HERE +extern EUNIT_PWRON_TYPE (*funcSynoEunitPowerctlType)(void); +#endif +#endif +#ifdef MY_DEF_HERE +extern int (*funcSYNOSendEboxRefreshEvent)(int portIndex); +#endif +#ifdef MY_DEF_HERE +extern int (*funcSYNOSataErrorReport)(SYNOBIOS_EVENT_PARM parms); +extern int (*funcSYNODiskRetryReport)(unsigned int uiSlotIndex, unsigned int uiPmpLinks); +extern int (*funcSYNODiskTimeoutReport)(SYNOBIOS_EVENT_PARM parms); +extern int (*funcSYNODiskResetFailReport)(SYNOBIOS_EVENT_PARM parms); +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE +extern int (*funcSYNODeepSleepEvent)(unsigned int uiSlotIndex, unsigned int uiPmpLinks); +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +extern int (*funcSYNODiskPowerShortBreakReport)(unsigned int uiDiskType, unsigned int uiSlotIndex, unsigned int uiSlotEMID, unsigned int uiPmpPortNumber); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ +extern int (*funcSYNODiskPowerShortBreakReport)(unsigned int uiSlotIndex, unsigned int uiPmpLinks); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_ATA */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_ECC_NOTIFICATION) +extern int (*funcSYNOECCNotification)(unsigned int type, unsigned int syndrome, u64 memAddr); +#endif /* MY_DEF_HERE || CONFIG_SYNO_ECC_NOTIFICATION */ +#ifdef CONFIG_SYNO_BUZZER_MUTE_IRQ +extern void (*funcSYNOBuzzerMuteIRQ)(void); +#endif/* CONFIG_SYNO_BUZZER_MUTE_IRQ */ +#ifdef CONFIG_SYNO_DISPLAY_CPUINFO +extern unsigned int gSynoCPUInfoCore; +#if defined(CONFIG_SYNO_GRANTLEY) || defined(CONFIG_SYNO_PURLEY) +extern int gSynoMultiCPUInfoCore[CONFIG_SYNO_MULTI_CPU_NUM]; +#endif +extern char gSynoCPUInfoClock[16]; +#endif/* CONFIG_SYNO_DISPLAY_CPUINFO */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ +#ifdef CONFIG_SYNO_IE_SOFT_POWER_OFF +extern int (*funcSYNOSendPowerButtonEvent)(void); +#endif /* CONFIG_SYNO_IE_SOFT_POWER_OFF */ + +#if defined(CONFIG_SYNO_USB_FORBID) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) +extern void (*funcSYNOUsbProhibitEvent)(void); +#endif /* CONFIG_SYNO_USB_FORBID && ! CONFIG_SYNO_SYNOBIOS_EVENT */ + +#if defined(CONFIG_SYNO_SERIAL_CONSOLE_FORBID) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) +extern void (*funcSYNOConsoleProhibitEvent)(void); +#endif /* CONFIG_SYNO_SERIAL_CONSOLE_FORBID && ! CONFIG_SYNO_SYNOBIOS_EVENT */ + +static int synobios_record_event_new(struct sd_softc *sc, SYNOBIOSEVENT *pEvent) +{ + unsigned long flags; + + if (scSynoBios.countEvents == SYNOBIOS_NEVENTS) { + return 1; + } + + spin_lock_irqsave(&scSynoBios.lock, flags); + scSynoBios.countEvents++; + scSynoBios.rgEvents[scSynoBios.idxPtr] = *pEvent; + scSynoBios.idxPtr++; + scSynoBios.idxPtr %= SYNOBIOS_NEVENTS; + spin_unlock_irqrestore(&scSynoBios.lock, flags); + + wake_up_interruptible(&(scSynoBios.wq_poll)); + + return 0; +} + +int synobios_record_event(struct sd_softc *sc, u_int event_type) +{ + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = event_type; + return synobios_record_event_new(sc, &event); +} + +static int synobios_record_shutdown_event(unsigned int type, SYNO_SHUTDOWN_LOG shutdown_event) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_SHUTDOWN_LOG; + event.data[0] = shutdown_event; + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} + +static int my_atoi(const char *name) +{ + int val = 0; + + for (;; name++) { + switch (*name) { + case '0' ... '9': + val = 10*val+(*name-'0'); + break; + default: + return val; + } + } +} + +#ifdef CONFIG_MD +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) +static int synobios_record_raid_event(unsigned int type, unsigned int raidno, unsigned int diskno, unsigned long long sector) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_RAID; + event.data[0] = type; + event.data[1] = raidno; + event.data[2] = diskno + 1; // scemd record disk1,2,3,4, + // raid driver use disk0,1,2,3 + event.data[3] = sector; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) */ + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) +extern int (*funcSYNOSendAutoRemapRaidEvent)(unsigned int, unsigned long long, unsigned int); + + +static int synobios_autoremap_raid_event(unsigned int raidno, unsigned long long sector, unsigned int diskno) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_RAID_REMAP_RECORD; + event.data[0] = diskno + 1; + event.data[1] = raidno; + event.data[2] = sector; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) +extern int (*funcSYNOSendRaidSyncEvent)(const char *szSyncType, int isSyncFinish, int isSyncInterrupt, int md_minor); + +static unsigned int raid_sync_type_get(const char *szSyncType) +{ + if (NULL == szSyncType) { + return RAID_SYNC_NONE; + } + + if (0 == strcmp("resync", szSyncType)) { + return RAID_SYNC_RESYNC; + } else if (0 == strcmp("requested-resync", szSyncType)) { + return RAID_SYNC_REQUESTED_RESYNC; + } else if (0 == strcmp("data-check", szSyncType)) { + return RAID_SYNC_CHECK; + } else if (0 == strcmp("recovery", szSyncType)) { + return RAID_SYNC_RECOVERY; + } else if (0 == strcmp("reshape", szSyncType)) { + return RAID_SYNC_RESHAPE; + } else { + return RAID_SYNC_NONE; + } +} + +static int synobios_raid_sync_event(const char *szSyncType, int isSyncFinish, int isSyncInterrupt, int md_minor) +{ + int ret = 0; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_RAID_SYNC; + event.data[0] = raid_sync_type_get(szSyncType); + event.data[1] = isSyncFinish; + event.data[2] = isSyncInterrupt; + event.data[3] = md_minor; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) */ +#endif /* CONFIG_MD */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_EXT4_ERROR_REPORT) +extern int (*funcSYNOSendErrorFsEvent)(const unsigned char*, const unsigned int); + +static int synobios_error_fs_event(const unsigned char* szDsmVersion, const unsigned int iErrorCount) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_ERROR_FS; + event.data[0] = my_atoi(szDsmVersion); + event.data[1] = iErrorCount; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* MY_DEF_HERE || CONFIG_SYNO_EXT4_ERROR_REPORT */ + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_BTRFS_DATA_CORRECTION) +extern int (*funcSYNOSendErrorFsBtrfsEvent)(const u8*); + +static int synobios_error_fs_btrfs_event(const u8* fsid) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_ERROR_FS_BTRFS; + event.data[0] = *((unsigned long long *)fsid); + event.data[1] = *((unsigned long long *)fsid + 1); + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} + +extern int (*funcSYNOMetaCorruptedEvent)(const u8*, u64); + +static int synobios_error_btrfs_meta_corrupted_event(const u8* fsid, u64 lba) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_ERROR_BTRFS_META_CORRUPTED; + event.data[0] = *((unsigned long long *)fsid); + event.data[1] = *((unsigned long long *)fsid + 1); + event.data[2] = (unsigned long long)lba; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* MY_DEF_HERE || CONFIG_SYNO_BTRFS_DATA_CORRECTION */ + +#ifdef MY_DEF_HERE +static int synobios_record_ebox_refresh_event(int portIndex) +{ + int ret = 0; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_EBOX_REFRESH; + event.data[0] = portIndex; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif + +static int synobios_record_disk_pwr_reset_event(unsigned int type, unsigned int diskno) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DISK_PWR_RESET; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} + +static int synobios_record_disk_port_disabled_event(unsigned int type, unsigned int diskno, unsigned int shostno) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DISK_PORT_DISABLED; + event.data[0] = type; + event.data[1] = diskno; + event.data[2] = shostno; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} + +static int synobios_disk_port_lost_report(unsigned int diskno, + unsigned int errorType) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DISK_PORT_LOST; + event.data[0] = diskno; // get by syno_libata_index_get, see DeviceNameGet for usage. + event.data[1] = errorType; // lost error type, reference to kernel include/linux/libata.h or libhwcontrol. + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} + +static int synobios_sata_error_report(SYNOBIOS_EVENT_PARM parms) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_SATA_ERROR_REPORT; + event.data[0] = parms.data[0]; //get by syno_libata_index_get, see DeviceNameGet for usage. + event.data[1] = parms.data[1] ? parms.data[2] + 1 : 0; //ex. ata5.02, pmp index is 3 + event.data[2] = parms.data[3]; + event.data[3] = parms.data[4]; + event.data[4] = parms.data[5]; + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} + +static int synobios_disk_retry_report(unsigned int uiSlotIndex, unsigned int uiPmpLinks) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DISK_RETRY_REPORT; + event.data[0] = uiSlotIndex; //get by syno_libata_index_get, see DeviceNameGet for usage. + event.data[1] = 0 == uiPmpLinks ? 0 : 1; //0 if it's internal port, 1 if it's pmp port. + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} + +static int synobios_disk_timeout_report(SYNOBIOS_EVENT_PARM parms) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DISK_TIMEOUT_REPORT; + event.data[0] = parms.data[0]; //get by syno_libata_index_get, see DeviceNameGet for usage. + event.data[1] = parms.data[1] ? parms.data[2] + 1 : 0; //ex. ata5.02, pmp index is 3 + event.data[2] = parms.data[3]; + event.data[3] = parms.data[4]; + event.data[4] = parms.data[5]; + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} + +static int synobios_disk_reset_fail_report(SYNOBIOS_EVENT_PARM parms) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DISK_RESET_FAIL_REPORT; + event.data[0] = parms.data[0]; //get by syno_libata_index_get, see DeviceNameGet for usage. + event.data[1] = parms.data[1] ? parms.data[2] + 1 : 0; //ex. ata5.02, pmp index is 3 + event.data[2] = parms.data[3]; + event.data[3] = parms.data[4]; + event.data[4] = parms.data[5]; + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_ECC_NOTIFICATION) +static int synobios_event_ecc_notification(unsigned int type, unsigned int syndrome, u64 memAddr) +{ + int ret = 0; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_ECC_NOTIFICATION; + event.data[0] = type; + event.data[1] = syndrome; + event.data[2] = memAddr; + + printk("synobios: ECC notification event."); + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* MY_DEF_HERE || CONFIG_SYNO_ECC_NOTIFICATION */ + +static int synobios_wake_from_deep_sleep(unsigned int uiSlotIndex, unsigned int uiPmpLinks) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_WAKE_FROM_DEEP_SLEEP; + event.data[0] = uiSlotIndex; //get by syno_libata_index_get, see DeviceNameGet for usage. + event.data[1] = uiPmpLinks; //ex. pmp link number. if it is internal disk, uiPmpLinks = 0. + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} + +#ifdef CONFIG_SYNO_MPC824X +extern int (*funcSYNORtcSetTime)(struct _SynoRtcTimePkt *pRtcTimePkt); +#endif /* CONFIG_SYNO_MPC824X */ + +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 +static int synobios_disk_power_short_break_report (unsigned int uiDiskType, unsigned int uiSlotIndex, unsigned int uiSlotEMID, unsigned int uiPmpPortNumber) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DSIK_POWER_SHORT_BREAK; + event.data[0] = uiDiskType; + event.data[1] = uiSlotIndex; + event.data[2] = uiSlotEMID; + event.data[3] = uiPmpPortNumber; //ex. pmp link number. + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ +static int synobios_disk_power_short_break_report (unsigned int uiSlotIndex, unsigned int uiPmpPortNumber) +{ + int iRet; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_DSIK_POWER_SHORT_BREAK; + event.data[0] = uiSlotIndex; // ata port number + event.data[1] = uiPmpPortNumber; //ex. pmp link number. + + iRet = synobios_record_event_new(&scSynoBios, &event); + + return iRet; +} +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_OOM_NOTIFICATION) +extern int (*funcSYNOSendErrorOOMEvent)(const char * process_name); + +static void my_prcoesstodata(const char * proc, SYNOBIOSEVENT *event) +{ + int i; + unsigned long long *data; + int size = strlen(proc); + for (i = 0; i < size; i++) { + if (i < 8) + data = &event->data[0]; + else if (i >= 8 && i < 16) + data = &event->data[1]; + else if (i >= 16 && i < 24) + data = &event->data[2]; + else if (i >= 24 && i < 32) + data = &event->data[3]; + *data = (*data) + (((unsigned long long)proc[i]) << (8 * (i % 8))); + } +} + +static int synobios_error_oom_event(const char * process_name) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_ERROR_OOM; + my_prcoesstodata(process_name, &event); + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} +#endif /* (MY_DEF_HERE) || (CONFIG_SYNO_OOM_NOTIFICATION) */ + +void synobios_rtc_init(void) +{ + int ret; + struct _SynoRtcTimePkt RtcTimePkt; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + struct timespec64 tv; +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + struct timespec tv; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + module_t* pSynoModule = NULL; + + memset(&RtcTimePkt, 0, sizeof(struct _SynoRtcTimePkt)); + pSynoModule = module_type_get(); + + if (RTC_UNKNOWN == pSynoModule->rtc_type) { + goto END; + } + + /* 1. read time from rtc. */ + if (synobios_ops->get_rtc_time) { + ret = synobios_ops->get_rtc_time(&RtcTimePkt); + }else{ + ret = -1; + } + + if (ret < 0) { + printk("%s(%d) read RTC error\n", __FILE__, __LINE__); + } + //printk("%s(%d) XX YYYY/MM/DD hh:mm:ss %04x/%02x/%02x %02x:%02x:%02x\n", __FILE__, __LINE__, RtcTimePkt.year, RtcTimePkt.month, RtcTimePkt.day, RtcTimePkt.hour, RtcTimePkt.min, RtcTimePkt.sec); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + tv.tv_sec = mktime64(RtcTimePkt.year + 1900, RtcTimePkt.month + 1, RtcTimePkt.day, RtcTimePkt.hour, RtcTimePkt.min, RtcTimePkt.sec); + tv.tv_nsec = 0; + do_settimeofday64(&tv); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + tv.tv_sec = mktime(RtcTimePkt.year + 1900, RtcTimePkt.month + 1, RtcTimePkt.day, RtcTimePkt.hour, RtcTimePkt.min, RtcTimePkt.sec); + tv.tv_nsec = 0; + do_settimeofday(&tv); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + printk("%d-%d-%d %d:%d:%d UTC\n", RtcTimePkt.year + 1900, RtcTimePkt.month + 1, RtcTimePkt.day, \ + RtcTimePkt.hour, RtcTimePkt.min, RtcTimePkt.sec); + +END: + return; + +} + +int update_comp_stat(SYNO_SYS_STATUS *pSysStatus, sys_comp_stat_t com_stat) +{ + int res = 0; + int comp_num = sizeof(SYNO_SYS_STATUS)/sizeof(sys_comp_stat_t); + SYNO_SYS_STAT_SIGNATURE signature = SIGNATURE_GET(com_stat); + int idx; + sys_comp_stat_t *pCom_stat; + + pCom_stat = (sys_comp_stat_t *)pSysStatus; + for (idx = 0; idx < comp_num; idx++, pCom_stat++) { + SYNO_SYS_STAT_SIGNATURE comp_signature = SIGNATURE_GET((*pCom_stat)); + if (signature == comp_signature) { + *pCom_stat = com_stat; + break; + } + } + + if (idx == comp_num) { + res = -1; + } + + return res; +} + +#ifdef CONFIG_SYNO_DISPLAY_CPUINFO +static void syno_display_cpu_info(void) +{ + SYNO_CPU_INFO cpu; + memset(&cpu, 0, sizeof(SYNO_CPU_INFO)); + + if (synobios_ops->get_cpu_info) { + synobios_ops->get_cpu_info(&cpu, sizeof(gSynoCPUInfoClock)); + } + gSynoCPUInfoCore = cpu.core; + snprintf(gSynoCPUInfoClock, sizeof(gSynoCPUInfoClock), cpu.clock); +#if defined(CONFIG_SYNO_GRANTLEY) || defined(CONFIG_SYNO_PURLEY) + memset(gSynoMultiCPUInfoCore, 0, CONFIG_SYNO_MULTI_CPU_NUM * sizeof(int)); + memcpy(gSynoMultiCPUInfoCore, cpu.cpucore, CONFIG_SYNO_MULTI_CPU_NUM * sizeof(int)); +#endif +} +#endif + +static void syno_buzzer_cleared_event(void) +{ + static unsigned long last_jiffies = INITIAL_JIFFIES; + static unsigned int buzzer_press_count = 0; + if (time_after(jiffies, last_jiffies + msecs_to_jiffies(500))) { + buzzer_press_count = 0; + } else { + buzzer_press_count++; + } + if (buzzer_press_count < 3) { + synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_BUZZER_CLEAR); + printk(KERN_INFO "synobios: buzzer stop button pressed\n"); + last_jiffies = jiffies; + } +} + +#ifdef CONFIG_SYNO_IE_SOFT_POWER_OFF +static void syno_power_button_event(void) +{ + synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_SHUTDOWN); + printk("synobios: IE soft power off\n"); +} +#endif /* CONFIG_SYNO_IE_SOFT_POWER_OFF */ + +static void syno_usb_prohibit_event(void) +{ + synobios_record_event(&scSynoBios, SYNO_EVENT_USB_PROHIBIT); +} + +static void syno_console_prohibit_event(void) +{ + synobios_record_event(&scSynoBios, SYNO_EVENT_CONSOLE_PROHIBIT); +} + +static int syno_microp_get_event(struct tty_struct *tty) +{ + if (0 != strcmp(tty->name, TTY_NAME)) { + goto END; + } + + synobios_record_event(&scSynoBios, SYNO_EVENT_MICROP_GET); +END: + return 0; +} + +static int synobios_record_ebox_reset_event(SYNOBIOS_EVENT_PARM parms) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_EBOX_RESET; + event.data[0] = parms.data[0]; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} + +static int +synobios_record_scsi_error_event(SYNOBIOS_EVENT_PARM parms) +{ + int ret; + SYNOBIOSEVENT event; + + memset(&event, 0, sizeof(SYNOBIOSEVENT)); + event.event = SYNO_EVENT_SCSI_ERROR; + event.data[0] = parms.data[0]; + event.data[1] = parms.data[1] + 1; // scemd record disk1,2,3,4, + // scsi driver use disk0,1,2,3 + event.data[2] = parms.data[2]; + event.data[3] = parms.data[3]; + + ret = synobios_record_event_new(&scSynoBios, &event); + + return ret; +} + +static unsigned int synobios_poll(struct file *pfile, struct poll_table_struct *ppolltable) +{ + int revents = 0; + + if(synobios_ops->get_buzzer_cleared) { + unsigned char buzzer_cleared = 0; + if ( 0 == synobios_ops->get_buzzer_cleared(&buzzer_cleared) ) { + if ( buzzer_cleared ) { + syno_buzzer_cleared_event(); + } + } + } + + if (scSynoBios.countEvents) { + revents |= (POLLIN | POLLRDNORM); + } else { + poll_wait(pfile, &(scSynoBios.wq_poll), ppolltable); + } + return (revents); +} + +static long synobios_ioctl (struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct _SynoRtcTimePkt rtcPkt; + struct _SynoRtcTimePkt *pRtcTimePkt = &rtcPkt; + int ret = 0; + int i; + unsigned long flags; + + if (_IOC_TYPE(cmd) != SYNOBIOS_IOC_MAGIC) { + ret = -ENOTTY; + goto END; + } + + switch (cmd) { + case SYNOIO_EXDISPLAY: +#ifdef CONFIG_SYNO_MV88F6281_USBSTATION +#define USBSTATION_GPP_LED_DISK_ORANGE 40 +#define USBSTATION_GPP_LED_DISK_GREEN 36 +#define USBSTATION_GPP_LED_POWER 37 + { + struct _SynoMsgPkt msgPkt; + struct _SynoMsgPkt *pMsgPkt = &msgPkt; + GPIO_PIN pin; + SYNO_LED *pLed; + SYNO_LED LedBlink = SYNO_LED_BLINKING; + SYNO_LED LedOn = SYNO_LED_ON; + int act_high = 0; + + /* Check fp availability */ + if (NULL == synobios_ops->set_gpio_pin || + NULL == synobios_ops->set_gpio_blink) { + ret = -EFAULT; + break; + } + if (copy_from_user((void *)pMsgPkt, (const void __user *)arg, sizeof(struct _SynoMsgPkt))) { + ret = -EFAULT; + break; + } + pLed = (SYNO_LED *)pMsgPkt->szMsg; + /* Determine which GPIO pin to use */ + switch(pMsgPkt->usNum) { + case SYNO_LED_USBSTATION_DISK_ORANGE: + act_high = 1; + pin.pin = USBSTATION_GPP_LED_DISK_ORANGE; + break; + case SYNO_LED_USBSTATION_DISK_GREEN: + act_high = 1; + pin.pin = USBSTATION_GPP_LED_DISK_GREEN; + break; + case SYNO_LED_USBSTATION_POWER: + pin.pin = USBSTATION_GPP_LED_POWER; + break; + case SYNO_SYS_RUN: + /* RUN means to steady power/status LED */ + pin.pin = USBSTATION_GPP_LED_POWER; + pLed = &LedOn; + break; + case SYNO_SYS_SHUTDOWN: + /* SHUTDOWN means to flash power/status LED */ + pin.pin = USBSTATION_GPP_LED_POWER; + pLed = &LedBlink; + break; + case SYNO_BEEP_ON: + /* No buzzer. Dont care. */ + pin.pin = -1; + break; + default: + pin.pin = -1; + printk("Unhandled msg num %08lx\n", pMsgPkt->usNum); + break; + } + if (pin.pin < 0) { + ret = -EFAULT; + break; + } + /* Manipulate GPIO pin */ + switch(*pLed) { + case SYNO_LED_OFF: + pin.value = act_high ? 0 : 1; + ret = synobios_ops->set_gpio_pin(&pin); + pin.value = 0; + synobios_ops->set_gpio_blink(&pin); + break; + case SYNO_LED_ON: + pin.value = act_high ? 1 : 0; + ret = synobios_ops->set_gpio_pin(&pin); + pin.value = 0; + synobios_ops->set_gpio_blink(&pin); + break; + case SYNO_LED_BLINKING: + pin.value = act_high ? 1 : 0; + ret = synobios_ops->set_gpio_pin(&pin); + pin.value = 1; + synobios_ops->set_gpio_blink(&pin); + break; + default: + printk("Unknown LED state %d for %08lx\n", + *pLed, pMsgPkt->usNum); + ret = -EFAULT; + break; + } + } + break; +#else + { + struct _SynoMsgPkt msgPkt; + struct _SynoMsgPkt *pMsgPkt = &msgPkt; + + if (synobios_ops->exdisplay_handler) { + //printk("private handle for SYNOIO_EXDISPLAY, cmd 0x%04lx\n", pMsgPkt->usNum); + if (copy_from_user((void *)pMsgPkt, (const void __user *)arg, sizeof(struct _SynoMsgPkt))) { + ret = -EFAULT; + break; + } + synobios_ops->exdisplay_handler(pMsgPkt); + } else { + printk("exdisplay_handler not implemented\n"); + ret = -EFAULT; + } + } + break; +#endif + case SYNOIO_NEXTEVENT: + { + SYNOBIOSEVENT event; + int isSucceed = 0; + + spin_lock_irqsave(&scSynoBios.lock, flags); + if (scSynoBios.countEvents < 0) { + ret = -EINVAL; + } else if (scSynoBios.countEvents == 0) { + ret = -EAGAIN; + } else { + i = scSynoBios.idxPtr + SYNOBIOS_NEVENTS - scSynoBios.countEvents; + i %= SYNOBIOS_NEVENTS; + memcpy(&event, &scSynoBios.rgEvents[i], sizeof(SYNOBIOSEVENT)); + isSucceed = 1; + scSynoBios.countEvents--; + } + spin_unlock_irqrestore(&scSynoBios.lock, flags); + + if (isSucceed) { + if (copy_to_user((void __user *)arg, &event, sizeof(SYNOBIOSEVENT))) { + ret = -EFAULT; + } + } + } + break; + case SYNOIO_RTC_TIME_READ: + if (copy_from_user((void *)pRtcTimePkt, (const void __user *)arg, sizeof(struct _SynoRtcTimePkt))) { + ret = -EFAULT; + break; + } + if (synobios_ops->get_rtc_time) { + ret = synobios_ops->get_rtc_time(pRtcTimePkt); + }else{ + ret = -1; + } + if (ret < 0) { + printk("%s: Failed to get rtc time.\n", __FUNCTION__); + } + DBGMESG("(0h, %x) (1h, %x) (2h, %x) (3h, %x) (4h, %x) (5h, %x) (6h, %x)\n", (unsigned int)pRtcTimePkt->sec, (unsigned int)pRtcTimePkt->min, (unsigned int)pRtcTimePkt->hour, (unsigned int)pRtcTimePkt->weekday, (unsigned int)pRtcTimePkt->day, (unsigned int)pRtcTimePkt->month, (unsigned int)pRtcTimePkt->year); + if (copy_to_user((void __user *)arg, pRtcTimePkt, sizeof(struct _SynoRtcTimePkt))) { + ret=-EFAULT; + } + break; + case SYNOIO_RTC_TIME_WRITE: + if (copy_from_user((void *)pRtcTimePkt, (const void __user *)arg, sizeof(struct _SynoRtcTimePkt))) { + ret = -EFAULT; + break; + } + DBGMESG("synobios_ioctl: SYNOIO_RTC_TIME_WRITE\n"); + if (pRtcTimePkt->year < 105) { + printk("%s: Failed to set rtc time before 2005/01/01\n",__FUNCTION__); + ret = -1; + break; + } + + if (synobios_ops->set_rtc_time) { + ret = synobios_ops->set_rtc_time(pRtcTimePkt); + }else{ + ret=-1; + } + if (ret < 0) { + printk("%s: Failed to set rtc time\n", __FUNCTION__); + } + DBGMESG("(0h, %x) (1h, %x) (2h, %x) (3h, %x) (4h, %x) (5h, %x) (6h, %x)\n", (unsigned int)pRtcTimePkt->sec, (unsigned int)pRtcTimePkt->min, (unsigned int)pRtcTimePkt->hour, (unsigned int)pRtcTimePkt->weekday, (unsigned int)pRtcTimePkt->day, (unsigned int)pRtcTimePkt->month, (unsigned int)pRtcTimePkt->year); + if (copy_to_user((void __user *)arg, pRtcTimePkt, sizeof(struct _SynoRtcTimePkt))) { + ret=-EFAULT; + } + break; + + case SYNOIO_MANUTIL_MODE: + if (copy_from_user((int *)&i, (const void __user *)arg, sizeof(int))) { + ret = -EFAULT; + break; + } + + if (i != 0) { + /*for manutil test, send manutil mode swich event*/ + printk(KERN_INFO "synobios_ioctl: MANUTIL BUTTON MODE\n"); + ret = synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_MANUTIL); + } else { + printk(KERN_INFO"synobios_ioctl: NORMAL BUTTON MODE\n"); + ret = synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_NORMAL); + } + break; + case SYNOIO_RECORD_EVENT: + /*for event test, generate event from user space*/ + printk(KERN_INFO "synobios_ioctl: SYNOIO_RECORD_EVENT, event id %x\n", *((u_int *) arg)); + ret = synobios_record_event(&scSynoBios, *(u_int *)arg); + break; + + case SYNOIO_BUTTON_RESET: + ret = synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_RESET); + printk("synobios: reset button pressed, ret = %d\n", ret); + break; + case SYNOIO_BUTTON_POWER: + ret = synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_SHUTDOWN); + printk("synobios: power button pressed, ret = %d\n", ret); + break; + case SYNOIO_POWER_OFF: + ret = synobios_record_event(&scSynoBios, SYNO_EVENT_BUTTON_SHUTDOWN); + break; + case SYNOIO_BUTTON_USB: + ret = synobios_record_event(&scSynoBios, SYNO_EVENT_USBCOPY_START); + printk("synobios: usb button pressed, ret = %d\n", ret); + break; + case SYNOIO_SET_DISK_LED: + { +#if defined(CONFIG_SYNO_PORT_MAPPING_V2) + DISKLEDSTATUS diskLedStatus; + char szNodeName[MAX_NODENAME_LEN] = {0}; + + if (copy_from_user((void *)&diskLedStatus, (const void __user *)arg, sizeof(DISKLEDSTATUS))) { + ret = -EFAULT; + break; + } + if (diskLedStatus.iNodeNameLen >= MAX_NODENAME_LEN) { + ret = -EINVAL; + break; + } + if (copy_from_user((void *)szNodeName, (const void __user*)(diskLedStatus.szNodeName), diskLedStatus.iNodeNameLen)) { + ret = -EFAULT; + break; + } + diskLedStatus.szNodeName = szNodeName; + if (synobios_ops->set_disk_led) { + write_lock(&LedSetLock); + ret = synobios_ops->set_disk_led(&diskLedStatus); + write_unlock(&LedSetLock); + } else { + ret = -EPERM; + } +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + DISKLEDSTATUS diskLedStatus; + if (copy_from_user((void *)&diskLedStatus, (const void __user *)arg, sizeof(DISKLEDSTATUS))) { + ret = -EFAULT; + break; + } + if (synobios_ops->set_disk_led) { +#ifdef CONFIG_SYNO_RTD129X + /* rtd1296 control gpio by gpio_requst and gpio_direction_output, + * so rtd1296 needn't apply lock again */ + ret = synobios_ops->set_disk_led(diskLedStatus.diskno, diskLedStatus.status); +#else /* CONFIG_SYNO_RTD129X */ + write_lock(&LedSetLock); + ret = synobios_ops->set_disk_led(diskLedStatus.diskno, diskLedStatus.status); + write_unlock(&LedSetLock); +#endif /* CONFIG_SYNO_RTD129X */ + }else{ + ret=-1; + } +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + break; + } + case SYNOIO_GET_FAN_STATUS: + { + FANSTATUS FanStatus; + if (copy_from_user((void *)&FanStatus, (const void __user *)arg, sizeof(FANSTATUS))) { + ret = -EFAULT; + break; + } + if (check_fan == 0) { + FanStatus.status = FAN_STATUS_RUNNING; + return 0; + } + if (synobios_ops->get_fan_status) { + ret = synobios_ops->get_fan_status(FanStatus.fanno, &(FanStatus.status)); + }else{ + ret=-1; + } + if (copy_to_user((void __user *)arg, &FanStatus, sizeof(FANSTATUS))) { + ret=-EFAULT; + } + + break; + } + case SYNOIO_SET_FAN_STATUS: + { + FANSTATUS FanStatus; + if (copy_from_user((void *)&FanStatus, (const void __user *)arg, sizeof(FANSTATUS))) { + ret = -EFAULT; + break; + } + if (synobios_ops->set_fan_status) { + ret = synobios_ops->set_fan_status(FanStatus.status, FanStatus.speed); + }else{ + ret = -1; + } + + break; + } + case SYNOIO_GET_FAN_NUM: + { + int fanNum = 0; + ret = GetFanNum(&fanNum); + if (copy_to_user((void __user *)arg, &fanNum, sizeof(int))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_DS_BRAND: + { + int brand = 0; + + if (synobios_ops->get_brand) { + brand = synobios_ops->get_brand(); + } + + if (brand != BRAND_SYNOLOGY && brand != BRAND_LOGITEC && brand != BRAND_SYNOLOGY_USA) { + ret = -EINVAL; + } + if (copy_to_user((void __user *)arg, &brand, sizeof(int))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_DS_MODEL: + { + int model = 0; + + if (synobios_ops->get_model) { + model = synobios_ops->get_model(); + } + if (copy_to_user((void __user *)arg, &model, sizeof(int))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_CPLD_VERSION: + { + int version = 0; + + if (synobios_ops->get_cpld_version) { + version = synobios_ops->get_cpld_version(); + } + if (copy_to_user((void __user *)arg, &version, sizeof(int))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_TEMPERATURE: + { + struct _SynoThermalTemp thermalTemp; + + if (copy_from_user((void *)&thermalTemp, (const void __user *)arg, sizeof(struct _SynoThermalTemp))) { + ret = -EFAULT; + break; + } + if (synobios_ops->get_sys_temperature) { + ret = synobios_ops->get_sys_temperature(&thermalTemp); + }else{ + ret=-1; + } + if (copy_to_user((void __user *)arg, &thermalTemp, sizeof(struct _SynoThermalTemp))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_CPLD_REG: + { + CPLDREG cpld; + + memset(&cpld, 0, sizeof(CPLDREG)); + if (synobios_ops->get_cpld_reg) { + ret = synobios_ops->get_cpld_reg(&cpld); + }else{ + ret=-1; + } + if (copy_to_user((void __user *)arg, &cpld, sizeof(cpld))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_MEM_BYTE: + { + MEMORY_BYTE memory; + if (copy_from_user((void *)&memory, (const void __user *)arg, sizeof(MEMORY_BYTE))) { + ret = -EFAULT; + break; + } + + if (synobios_ops->set_mem_byte) { + ret = synobios_ops->set_mem_byte(&memory); + }else{ + ret=-1; + } + break; + } + case SYNOIO_GET_MEM_BYTE: + { + MEMORY_BYTE memory; + + memset(&memory, 0, sizeof(MEMORY_BYTE)); + if (synobios_ops->get_mem_byte) { + ret = synobios_ops->get_mem_byte(&memory); + }else{ + ret=-1; + } + if (copy_to_user((void __user *)arg, &memory, sizeof(MEMORY_BYTE))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GPIO_PIN_WRITE: + { + GPIO_PIN gpin;; + if (copy_from_user((void *)&gpin, (const void __user *)arg, sizeof(GPIO_PIN))) { + ret = -EFAULT; + break; + } + if (synobios_ops->set_gpio_pin) { + ret = synobios_ops->set_gpio_pin(&gpin); + }else{ + ret=-1; + } + break; + } + case SYNOIO_GPIO_PIN_READ: + { + GPIO_PIN gpin; + if (copy_from_user((void *)&gpin, (const void __user *)arg, sizeof(GPIO_PIN))) { + ret = -EFAULT; + break; + } + if (synobios_ops->get_gpio_pin) { + ret = synobios_ops->get_gpio_pin(&gpin); + }else{ + ret=-1; + } + if (copy_to_user((void __user *)arg, &gpin, sizeof(GPIO_PIN))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_AUTO_POWERON: + { + SYNO_AUTO_POWERON autoPowerOn; + memset(&autoPowerOn, 0, sizeof(SYNO_AUTO_POWERON)); + + if (synobios_ops->get_auto_poweron) { + ret = synobios_ops->get_auto_poweron(&autoPowerOn); + }else{ + ret=-1; + } + if (copy_to_user((void __user *)arg, &autoPowerOn, sizeof(SYNO_AUTO_POWERON))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_AUTO_POWERON: + { + SYNO_AUTO_POWERON autoPowerOn; + + if (copy_from_user((void *)&autoPowerOn, (const void __user *)arg, sizeof(SYNO_AUTO_POWERON))) { + ret = -EFAULT; + break; + } + if (synobios_ops->set_auto_poweron) { + ret = synobios_ops->set_auto_poweron(&autoPowerOn); + }else{ + ret=-1; + } + break; + } + case SYNOIO_GET_HW_CAPABILITY: + { + CAPABILITY capability; + if (copy_from_user((void *)&capability, (const void __user *)arg, sizeof(CAPABILITY))) { + ret = -EFAULT; + break; + } + ret = GetHwCapability(&capability); + if (copy_to_user((void __user *)arg, &capability, sizeof(CAPABILITY))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_ALARM_LED: + { + if(synobios_ops->set_alarm_led) { + ret = synobios_ops->set_alarm_led((unsigned char)arg); + }else{ + ret = -1; + } + break; + } + case SYNOIO_SET_OK_TO_REMOVE_LED: + { + if(synobios_ops->set_ok_to_remove_led) { + ret = synobios_ops->set_ok_to_remove_led((unsigned char)arg); + } else { + ret = -1; + } + break; + } + case SYNOIO_GET_BUZZER_CLEARED: + { + //for manutil + unsigned char ucBuzzer_cleared = 0; + if(synobios_ops->get_buzzer_cleared) { + ret = synobios_ops->get_buzzer_cleared(&ucBuzzer_cleared); + if ( ucBuzzer_cleared ) { + printk(KERN_INFO "synobios: buzzer stop button pressed, ret = %d\n", ret); + } + }else{ + ret = -1; + } + if (copy_to_user((void __user *)arg, &ucBuzzer_cleared, sizeof(char))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_BUZZER_CLEAR: + { + if(synobios_ops->set_buzzer_clear) { + ret = synobios_ops->set_buzzer_clear((unsigned char)arg); + }else{ + ret = -1; + } + break; + } + case SYNOIO_GET_POWER_STATUS: + { + POWER_INFO powerinfo; + + memset(&powerinfo, 0, sizeof(POWER_INFO)); + if(synobios_ops->get_power_status) { + ret = synobios_ops->get_power_status(&powerinfo); + }else{ + ret = -1; + } + if (copy_to_user((void __user *)arg, &powerinfo, sizeof(POWER_INFO))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SHUTDOWN_LOG: + { + int event = (SYNO_SHUTDOWN_LOG)arg; + ret = synobios_record_shutdown_event(SYNO_EVENT_SHUTDOWN_LOG, event); + break; + } + case SYNOIO_UNINITIALIZE: + { + if(synobios_ops->uninitialize) { + ret = synobios_ops->uninitialize(); + }else{ + ret = -1; + } + break; + } + case SYNOIO_GET_SYS_STATUS: + { + SYNO_SYS_STATUS *pUSysStat = (SYNO_SYS_STATUS *)arg; + if (NULL != pUSysStat){ + mutex_lock(&sys_status_lock); + if (copy_to_user(pUSysStat, + pgSysStatus, + sizeof(SYNO_SYS_STATUS))) { + ret = -EFAULT; + } + mutex_unlock(&sys_status_lock); + } else{ + ret = -1; + } + break; + } + case SYNOIO_SET_SYS_STATUS: + { + sys_comp_stat_t uSysStat = (sys_comp_stat_t)arg; + mutex_lock(&sys_status_lock); + ret = update_comp_stat(pgSysStatus, uSysStat); + mutex_unlock(&sys_status_lock); + break; + } + case SYNOIO_GET_MODULE_TYPE: + { + if (copy_to_user((void __user *)arg, + module_type_get(), + sizeof(module_t))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_BACKPLANE_STATUS: + { + BACKPLANE_STATUS backSt; + memset(&backSt, 0, sizeof(BACKPLANE_STATUS)); + if (synobios_ops->get_backplane_status) { + ret = synobios_ops->get_backplane_status(&backSt); + }else{ + ret = -1; + } + if (copy_to_user((void __user *)arg, &backSt, sizeof(BACKPLANE_STATUS))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_UART2: + { +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_CTRL) + char szBuf[17] = {'\0'}; + int retVal = -1; +#if defined(CONFIG_SYNO_PWM_CONTROL_LED) + struct _SynoMsgPkt MsgPkt; +#endif /* defined(CONFIG_SYNO_PWM_CONTROL_LED) */ + + if (copy_from_user((char *)&szBuf, (const void __user *)arg, sizeof(szBuf) - sizeof(char))) { + ret = -EFAULT; + break; + } + szBuf[16] = '\0'; +#if defined(CONFIG_SYNO_PWM_CONTROL_LED) + if (synobios_ops->exdisplay_handler) { + memset(&MsgPkt, 0, sizeof(struct _SynoMsgPkt)); + MsgPkt.usNum = SYNO_PURE_MESSAGE; + MsgPkt.usLen = sizeof(szBuf); + strncpy(MsgPkt.szMsg, szBuf, sizeof(szBuf)); + retVal = synobios_ops->exdisplay_handler(&MsgPkt); + if (0 == retVal) { + break; + } + } +#endif /* defined(CONFIG_SYNO_PWM_CONTROL_LED) */ + retVal = synobios_lock_ttyS_write(szBuf); + if (0 > retVal) { + ret = -1; + } +#else /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_CTRL) */ + ret = -1; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_CTRL) */ + break; + } + case SYNOIO_SET_AND_GET_UART2: + { +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_CTRL) + UART2_BUFFER Buffer; + if (copy_from_user((void *)&Buffer, (const void __user *)arg, sizeof(UART2_BUFFER))) { + ret = -EFAULT; + break; + } + Buffer.szBuf[UART_BUF_SIZE - 1] = '\0'; + Buffer.size = (UART_BUF_SIZE > Buffer.size + 1) ? Buffer.size + 1: UART_BUF_SIZE; + ret = synobios_lock_ttyS_write_and_read(Buffer.szBuf, Buffer.size); + if (0 <= ret && copy_to_user((void __user *)arg, &Buffer, sizeof(UART2_BUFFER))) { + ret = -EFAULT; + } +#else /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_CTRL) */ + ret = -1; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_CTRL) */ + break; + } + case SYNOIO_GET_UART2: + { + UART2_BUFFER Buffer; + if (copy_from_user((void *)&Buffer, (const void __user *)arg, sizeof(UART2_BUFFER))) { + ret = -EFAULT; + break; + } + if (Buffer.size <= 0) { + ret = -EFAULT; + break; + } + memset(Buffer.szBuf, 0, UART_BUF_SIZE); + ret = synobios_lock_ttyS_read(Buffer.szBuf, (UART_BUF_SIZE > Buffer.size + 1) ? Buffer.size + 1 : UART_BUF_SIZE); + if (0 <= ret && copy_to_user((void __user *)arg, &Buffer, sizeof(UART2_BUFFER))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_UART_DEBUG_CONTROL: + { + int micropLogControl = 0; + if (copy_from_user((void *)µpLogControl, (const void __user *)arg, sizeof(int))) { + ret = -EFAULT; + break; + } + if ((MICROP_LOG_OFF != micropLogControl) + && (MICROP_LOG_ON != micropLogControl)) { + printk(KERN_ERR "Error microp log level, should be MICROP_LOG_ON or MICROP_LOG_OFF\n"); + ret = -EFAULT; + break; + } + set_log_switch(micropLogControl); + break; + } + case SYNOIO_GET_CPU_TEMPERATURE: + { + struct _SynoCpuTemp cpuTmp; + + if (copy_from_user((void *)&cpuTmp, (const void __user *)arg, sizeof(struct _SynoCpuTemp))) { + ret = -EFAULT; + break; + } + if (synobios_ops->get_cpu_temperature) { + ret = synobios_ops->get_cpu_temperature(&cpuTmp); + } else { + ret = -1; + } + if (copy_to_user((void __user *)arg, &cpuTmp, sizeof(struct _SynoCpuTemp))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_CPU_FAN_STATUS: + { + FANSTATUS FanStatus; + + if (copy_from_user((void *)&FanStatus, (const void __user *)arg, sizeof(FANSTATUS))) { + ret = -EFAULT; + break; + } + if (synobios_ops->set_cpu_fan_status) { + ret = synobios_ops->set_cpu_fan_status(FanStatus.status, FanStatus.speed); + }else{ + ret = -1; + } + + break; + } + case SYNOIO_SET_PHY_LED: + { + if (synobios_ops->set_phy_led) { + ret = synobios_ops->set_phy_led((SYNO_LED)arg); + }else{ + ret = -1; + } + break; + } + case SYNOIO_SET_HDD_LED: + { + if (synobios_ops->set_hdd_led) { + ret = synobios_ops->set_hdd_led((SYNO_LED)arg); + }else{ +#ifdef CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL + ret = 0; +#else + ret = -1; +#endif /*CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL*/ + } + break; + } + case SYNOIO_SET_PWR_LED: + { + if (synobios_ops->set_power_led) { + synobios_ops->set_power_led((SYNO_LED)arg); + }else{ + ret = -1; + } + break; + } + case SYNOIO_PWM_CTL: + { + struct _SynoPWMCTL pwmctl; + if (copy_from_user((void *)&pwmctl, (const void __user *)arg, sizeof(struct _SynoPWMCTL))) { + ret = -EFAULT; + break; + } + if (synobios_ops->pwm_ctl) { + ret = synobios_ops->pwm_ctl(&pwmctl); + }else{ + ret = -1; + } + if (copy_to_user((void __user *)arg, &pwmctl, sizeof(struct _SynoPWMCTL))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_CHECK_MICROP_ID: + { + if (synobios_ops->check_microp_id) { + ret = synobios_ops->check_microp_id(synobios_ops); + } else { + ret = 0; + } + break; + } + case SYNOIO_GET_EUNIT_TYPE: + { + EUNIT_PWRON_TYPE pwronType = GetEUnitType(); + if (copy_to_user((void __user *)arg, + &pwronType, + sizeof(EUNIT_PWRON_TYPE))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SUPERIO_READ: + { + if (synobios_ops->get_superio){ + synobios_ops->get_superio((SYNO_SUPERIO_PACKAGE *)arg); + } + ret = 0; + break; + } + case SYNOIO_SUPERIO_WRITE: + { + if(synobios_ops->set_superio){ + synobios_ops->set_superio((SYNO_SUPERIO_PACKAGE *)arg); + } + ret = 0; + break; + } + case SYNOIO_IS_FULLY_SUPPORT_EUP: + { +#ifdef CONFIG_SYNO_CEDARVIEW + if (synobios_ops->set_superio) { + if (synobios_ops->get_rtc_time != rtc_bandon_get_time) { + /* there's an external RTC */ + ret = EUP_FULLY_SUPPORT; + } else { + ret = EUP_NOT_FULLY_SUPPORT; + } + } else { + ret = EUP_NOT_SUPPORT; + } + break; +#else + ret = EUP_NOT_SUPPORT; + break; +#endif + } +#define MEM_READ(a) readl(a) +#define MEM_WRITE(a,v) writel(v,a) + case SYNOIO_WRITE_MEM: + { + SYNO_MEM_ACCESS mem_access; + + if (copy_from_user((void *)&mem_access, (void __user *)arg, sizeof(SYNO_MEM_ACCESS))) { + ret = -EFAULT; + break; + } + + if (synobios_ops->write_memory) { + ret = synobios_ops->write_memory(&mem_access); + } else { + MEM_WRITE((void *)(uintptr_t)mem_access.addr, mem_access.value); + ret = 0; + } + break; + } + case SYNOIO_READ_MEM: + { + SYNO_MEM_ACCESS mem_access; + + if (copy_from_user((void *)&mem_access, (const void __user *)arg, sizeof(SYNO_MEM_ACCESS))) { + ret = -EFAULT; + break; + } + + if (synobios_ops->read_memory) { + ret = synobios_ops->read_memory(&mem_access); + } else { + mem_access.value = MEM_READ((void *)(uintptr_t)mem_access.addr); + ret = 0; + } + + if (0 == ret && + 0 != (ret = copy_to_user((void __user *)arg, &mem_access, sizeof(SYNO_MEM_ACCESS)))) + { + ret = -EFAULT; + } + + break; + } + case SYNOIO_SET_AHA_LED: + { + if (synobios_ops->set_aha_led) { + synobios_ops->set_aha_led(synobios_ops, (SYNO_AHA_LED)arg); + } else { + ret = -1; + } + break; + } + case SYNOIO_GET_COPY_BUTTON: + { + int button_status; + if(synobios_ops->get_copy_button_status) { + // for matching userspace usage, return button_status = 0 if pressed, else = 1 + button_status = synobios_ops->get_copy_button_status(); + } else { + ret = -ENOSYS; + break; + } + if (copy_to_user((void __user *)arg, &button_status, sizeof(int))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_SUPPORT: + { + SYNO_HWMON_SUPPORT hwmon_support; + if (copy_from_user((void *)&hwmon_support, (const void __user *)arg, sizeof(SYNO_HWMON_SUPPORT))) { + ret = -EFAULT; + break; + } + ret = GetHWMONSupport(&hwmon_support); + if (copy_to_user((void __user *)arg, &hwmon_support, sizeof(SYNO_HWMON_SUPPORT))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_CPU_TEMPERATURE: + { + SYNO_HWMON_SENSOR_TYPE cpu_temp; + SYNOCPUTEMP cpuTmp; + int index = 0; + + if (copy_from_user((void *)&cpu_temp, (const void __user *)arg, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + break; + } + + cpuTmp.blSurface = 1; + if (synobios_ops->get_cpu_temperature) { + ret = synobios_ops->get_cpu_temperature(&cpuTmp); + cpu_temp.sensor_num = cpuTmp.cpu_num; + for (index = 0 ; index < cpu_temp.sensor_num ; index++) { + snprintf(cpu_temp.sensor[index].value, sizeof(cpu_temp.sensor[index].value), "%d", cpuTmp.cpu_temp[index]); + } + } else { + ret = -1; + break; + } + + if (copy_to_user((void __user *)arg, &cpu_temp, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_FAN_SPEED_RPM: + { + SYNO_HWMON_SENSOR_TYPE fan_rpm; + if (copy_from_user((void *)&fan_rpm, (const void __user *)arg, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + break; + } + if (synobios_ops->hwmon_get_fan_speed_rpm) { + ret = synobios_ops->hwmon_get_fan_speed_rpm(&fan_rpm); + } else{ + ret = -1; + break; + } + if (copy_to_user((void __user *)arg, &fan_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_PSU_STATUS: + { + SYNO_HWMON_SUPPORT psu_support; + SYNO_HWMON_SENSOR_TYPE *psusts = NULL; + + memset(&psu_support, 0, sizeof(SYNO_HWMON_SUPPORT)); + psu_support.id = HWMON_PSU_STATUS; + if ( 0 > (ret = GetHWMONSupport(&psu_support))) { + ret = -EFAULT; + break; + } + + if (NULL == (psusts = kmalloc(psu_support.support * sizeof(SYNO_HWMON_SENSOR_TYPE), GFP_KERNEL))) { + ret = -EFAULT; + break; + } + + if (copy_from_user((void *)psusts, (const void __user *)arg, psu_support.support * sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + if (psusts) { + kfree(psusts); + } + break; + } + if (synobios_ops->hwmon_get_psu_status) { + ret = synobios_ops->hwmon_get_psu_status(psusts, psu_support.support); + } else{ + ret = -1; + if (psusts) { + kfree(psusts); + } + break; + } + if (copy_to_user((void __user *)arg, psusts, psu_support.support *sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + if (psusts) { + kfree(psusts); + } + break; + } + case HWMON_GET_SYS_VOLTAGE: + { + SYNO_HWMON_SENSOR_TYPE sysvol; + if (copy_from_user((void *)&sysvol, (const void __user *)arg, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + break; + } + if (synobios_ops->hwmon_get_sys_voltage) { + ret = synobios_ops->hwmon_get_sys_voltage(&sysvol); + } else{ + ret = -1; + break; + } + if (copy_to_user((void __user *)arg, &sysvol, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_SYS_THERMAL: + { + SYNO_HWMON_SENSOR_TYPE systhermal; + + if (copy_from_user((void *)&systhermal, (const void __user *)arg, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + break; + } + if (synobios_ops->hwmon_get_sys_thermal) { + ret = synobios_ops->hwmon_get_sys_thermal(&systhermal); + } else{ + ret = -1; + break; + } + if (copy_to_user((void __user *)arg, &systhermal, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_HDD_BACKPLANE: + { + SYNO_HWMON_SENSOR_TYPE hddbp; + if (copy_from_user((void *)&hddbp, (const void __user *)arg, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + break; + } + if (synobios_ops->hwmon_get_backplane_status) { + ret = synobios_ops->hwmon_get_backplane_status(&hddbp); + } else{ + ret = -1; + break; + } + if (copy_to_user((void __user *)arg, &hddbp, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + break; + } + case HWMON_GET_SYS_CURRENT: + { + SYNO_HWMON_SENSOR_TYPE syscurrent; + if (copy_from_user((void *)&syscurrent, (const void __user *)arg, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + break; + } + if (synobios_ops->hwmon_get_sys_current) { + ret = synobios_ops->hwmon_get_sys_current(&syscurrent); + } else{ + ret = -1; + break; + } + if (copy_to_user((void __user *)arg, &syscurrent, sizeof(SYNO_HWMON_SENSOR_TYPE))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_GET_SYS_CURRENT: + { + unsigned long ulSysCurrent = 0; + + if(synobios_ops->get_sys_current) { + ret = synobios_ops->get_sys_current(&ulSysCurrent); + } else { + ret = -ENOSYS; + break; + } + if (copy_to_user((void __user *)arg, &ulSysCurrent, sizeof(unsigned long))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_CHECK_DISK_INTF: + { + SYNO_DISK_INTF_INFO model; + + if (synobios_ops->get_disk_intf) { + ret = synobios_ops->get_disk_intf(&model); + } else { + ret = -1; + break; + } + + if (copy_to_user((void __user *)arg, &model, sizeof(SYNO_DISK_INTF_INFO))) { + ret = -EFAULT; + } + break; + } + case SYNOIO_SET_RP_FAN: + { + if(synobios_ops->set_rp_fan) { + ret = synobios_ops->set_rp_fan((unsigned char)arg); + } + break; + } + default: + ret=-ENOSYS; + //printk(KERN_INFO "synobios_ioctl: un-defined ioctl number %x\n", cmd); + break; + } +END: + return ret; +} + +typedef struct _tag_SYNO_CPU_MAPPING { + CPU_ARCH_INFO_T id; + char *cpu_number; +} SYNO_CPU_MAPPING; + +static SYNO_CPU_MAPPING gSynoCPUMapping[] = { + {CPU_E5_2620v3, "INTEL, Xeon, E5-2620 v3, 12"}, + {CPU_E5_2609v3, "INTEL, Xeon, E5-2609 v3, 12"}, + {CPU_E3_1230v2, "INTEL, Xeon, E3-1230 v2, 4"}, + {CPU_D_1508, "INTEL, Pentium, D1508, 2"}, + {CPU_D_1521, "INTEL, Xeon, D-1521, 4"}, + {CPU_D_1527, "INTEL, Xeon, D-1527, 4"}, + {CPU_D_1528, "INTEL, Xeon, D-1528, 6"}, + {CPU_D_1531, "INTEL, Xeon, D-1531, 6"}, + {CPU_D_1541, "INTEL, Xeon, D-1541, 8"}, + {CPU_D_1567, "INTEL, Xeon, D-1567, 12"}, + {CPU_I3_2100, "INTEL, Core, i3-2100, 2"}, + {CPU_I3_4130, "INTEL, Core, i3-4130, 2"}, + {CPU_D410, "INTEL, Atom, D410, 1"}, + {CPU_D425, "INTEL, Atom, D425, 1"}, + {CPU_D510, "INTEL, Atom, D510, 2"}, + {CPU_D525, "INTEL, Atom, D525, 2"}, + {CPU_D2700, "INTEL, Atom, D2700, 2"}, + {CPU_CE5335, "INTEL, Atom, CE5335, 2"}, + {CPU_88F6281, "MARVELL, Kirkwood, 88F6281, 1"}, + {CPU_88F6282, "MARVELL, Kirkwood, 88F6282, 1"}, + {CPU_88F6702, "MARVELL, Kirkwood, 88F6702, 1"}, + {CPU_88F6707, "MARVELL, Armada 370, 88F6707, 1"}, + {CPU_88F6720, "MARVELL, Armada 375, 88F6720, 2"}, + {CPU_88F6820, "MARVELL, Armada 385, 88F6820, 2"}, + {CPU_88F6828, "MARVELL, Armada 388, 88F6828, 2"}, + {CPU_88F3710, "MARVELL, Armada 3710, 88F3710, 1"}, + {CPU_88F3720, "MARVELL, Armada 3720, 88F3720, 2"}, + {CPU_MV78230, "MARVELL, Armada XP, MV78230, 2"}, + {CPU_8241, "FREESCALE, PowerQUICC II, 8241, 1"}, + {CPU_8533e, "FREESCALE, PowerQUICC III, 8533e, 1"}, + {CPU_P1022, "FREESCALE, QorIQ, P1022, 2"}, + {CPU_C2000, "MINDSPEED, Comcerto, C2000, 2"}, + {CPU_LS1024, "Freescale, QorIQ series, LS1024, 2"}, + {CPU_AL212, "ANNAPURNALABS, Alpine, AL212, 2"}, + {CPU_AL314, "ANNAPURNALABS, Alpine, AL314, 4"}, + {CPU_AL514, "ANNAPURNALABS, Alpine, AL514, 4"}, + {CPU_C2538, "INTEL, Atom, C2538, 4"}, + {CPU_J1800, "INTEL, Celeron, J1800, 2"}, + {CPU_J3355, "INTEL, Celeron, J3355, 2"}, + {CPU_J3455, "INTEL, Celeron, J3455, 4"}, + {CPU_J4005, "INTEL, Celeron, J4005, 2"}, + {CPU_J4025, "INTEL, Celeron, J4025, 2"}, + {CPU_J4105, "INTEL, Celeron, J4105, 4"}, + {CPU_J4125, "INTEL, Celeron, J4125, 4"}, + {CPU_J4205, "INTEL, Pentium, J4205, 4"}, + {CPU_H412, "STM, Monaco, STiH412, 2"}, + {CPU_HI3535, "Hisillicon, Hi3535, V100, 2"}, + {CPU_N3000, "INTEL, Celeron, N3000, 2"}, + {CPU_N3050, "INTEL, Celeron, N3050, 2"}, + {CPU_N3150, "INTEL, Celeron, N3150, 4"}, + {CPU_N3700, "INTEL, Pentium, N3700, 4"}, + {CPU_NVR, "Embedded, NVR, Soc, 2"}, + {CPU_N3010, "INTEL, Celeron, N3010, 2"}, + {CPU_N3060, "INTEL, Celeron, N3060, 2"}, + {CPU_N3160, "INTEL, Celeron, N3160, 4"}, + {CPU_N3710, "INTEL, Pentium, N3710, 4"}, + {CPU_HI3536, "Hisilicon, Hi3536, , 4"}, + {CPU_RTD1296, "Realtek, RTD1296, SoC, 4"}, + {CPU_RTD1293, "Realtek, RTD1293, SoC, 2"}, + {CPU_C3538, "INTEL, Atom, C3538, 4"}, + {CPU_SILVER_4110, "INTEL, Xeon, Silver 4110, 16"}, + {CPU_RTD1619, "Realtek, RTD1619, SoC, 6"}, + {CPU_D_2143IT, "INTEL, Xeon, D-2143IT, 8"}, + {CPU_V1500B, "AMD, Ryzen, V1500B, 4"}, + {CPU_SILVER_4210R, "INTEL, Xeon, Silver 4210R, 20"}, + {CPU_SILVER_4214R, "INTEL, Xeon, Silver 4214R, 24"}, + {CPU_V1780B, "AMD, Ryzen, V1780B, 4"}, + {CPU_EPYC7272, "AMD, EPYC, 7272, 12"}, + {CPU_R1600, "AMD, Ryzen, R1600, 2"}, + {CPU_RTD1619B, "Realtek, RTD1619B, SoC, 4"}, + {CPU_EPYC7232P, "AMD, EPYC, 7232P, 8"}, + {CPU_EPYC7443P, "AMD, EPYC, 7443P, 24"}, + {CPU_UNKNOWN, "unknown, unknown, unknown, unknown"} +}; + +typedef struct _tag_SYNO_CRYPTO_MAPPING { + CRYPTO_HW_INFO_T hw_name; + char *crypto_capabilities; +} SYNO_CRYPTO_MAPPING; + +/* this is a hint for userspace to utilize crypto engine */ +static SYNO_CRYPTO_MAPPING gSynoCRYPTOMapping[] = { + {CRYPTO_A370, "AES_CBC, DES_CBC, 3DES_CBC, MD5, MD5_HMAC, SHA1, SHA1_HMAC"}, + {CRYPTO_A375, "AES_CBC, DES_CBC, 3DES_CBC, MD5, MD5_HMAC, SHA1, SHA1_HMAC"}, + {CRYPTO_A38X, "AES_CBC, DES_CBC, 3DES_CBC, MD5, MD5_HMAC, SHA1, SHA1_HMAC"}, + {CRYPTO_RTD129X, "AES_CBC, DES_CBC, 3DES_CBC, MD5, MD5_HMAC, SHA1, SHA1_HMAC"}, + {CRYPTO_AXP, "AES_CBC, DES_CBC, 3DES_CBC, MD5, MD5_HMAC, SHA1, SHA1_HMAC"}, + {CRYPTO_COMCERTO2K, "DES_CBC, 3DES_CBC, MD5, MD5_HMAC, SHA1, SHA1_HMAC, SHA2_256_HMAC"}, + {CRYPTO_ALPINE, "AES_CBC, AES_ECB, AES_CTR, DES_CBC, DEC_ECB, 3DES_ECB, 3DES_CBC, SHA1_HMAC, SHA2_256_HMAC, SHA2_384_HMAC, SHA2_512_HMAC"}, + {CRYPTO_QORIQ, "none"}, //removed cryptodev, for more info please refer to DSM #39064 + {CRYPTO_853X, "none"}, //removed cryptodev, same reason as QORIQ + {CRYPTO_628X, "AES_CBC"}, + {CRYPTO_HW_NONE, "none"} +}; + +#define CPU_MODEL_SZ 80 +static char cpu_model_synofmt[CPU_MODEL_SZ] = ""; + +static bool string_ends_with(const char *str, const char *suffix) +{ + size_t str_len, suffix_len; + + if (!str || !suffix) { + return false; + } + + str_len = strlen(str); + suffix_len = strlen(suffix); + + if (str_len < suffix_len) { + return false; + } + + return strcmp(str + str_len - suffix_len, suffix) == 0; +} + +static void synobios_detect_cpu_model(void) +{ + char *p, *cpu_model, *cpu_model_orig; + int part = 0, written = 0; + + cpu_model_orig = cpu_model = + kstrdup(boot_cpu_data.x86_model_id, GFP_KERNEL); + if (unlikely(!cpu_model)) + return; + + pr_info("%s: model name: %s, nr_cpu_ids: %d\n", __func__, cpu_model, + nr_cpu_ids); + + while ((p = strsep(&cpu_model, " "))) { + if (!*p) + continue; + + if (*p == '@' || *p == '-' || strcmp(p, "with") == 0 || + strcmp(p, "w/") == 0) + break; + if (strcmp(p, "CPU") == 0 || strcmp(p, "Genuine") == 0 || + strcmp(p, "Processor") == 0 || + strcmp(p, "processor") == 0 || strcmp(p, "Gen") == 0 || + string_ends_with(p, "th") || strstr(p, "-Core") != NULL) + continue; + + if (part > 0) { + if (part < 3) + written += + scnprintf(cpu_model_synofmt + written, + CPU_MODEL_SZ - written, ","); + written += scnprintf(cpu_model_synofmt + written, + CPU_MODEL_SZ - written, " "); + } + written += scnprintf(cpu_model_synofmt + written, + CPU_MODEL_SZ - written, "%s", p); + ++part; + } + while (++part < 4) + written += scnprintf(cpu_model_synofmt + written, + CPU_MODEL_SZ - written, ", Processor"); + written += scnprintf(cpu_model_synofmt + written, + CPU_MODEL_SZ - written, ", %u", nr_cpu_ids); + + kfree(cpu_model_orig); +} + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +static int synobios_read_proc_cpu_arch(struct seq_file *m, void *v) +#else /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +static int synobios_read_proc_cpu_arch(char *page, char **start, off_t off, + int count, int *eof, void *data) +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +{ + int len = 0; + SYNO_CPU_MAPPING *p_cpu_mapping = NULL; + static SYNO_CPU_MAPPING cpu_mapping = { .cpu_number = + cpu_model_synofmt }; + module_t *syno_module = module_type_get(); + if (!syno_module) { + printk("get cpu arch information failed\n"); + goto END; + } + + p_cpu_mapping = gSynoCPUMapping; + while (CPU_UNKNOWN != p_cpu_mapping->id) { + if (p_cpu_mapping->id == syno_module->cpu_arch_info) + break; + p_cpu_mapping++; + } + + if (CPU_UNKNOWN == p_cpu_mapping->id && *cpu_model_synofmt) + p_cpu_mapping = &cpu_mapping; + +#if SYNO_HAVE_KERNEL_VERSION(4,4,0) + seq_printf(m, "%s\n", p_cpu_mapping->cpu_number); +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) + len = seq_printf(m, "%s\n", p_cpu_mapping->cpu_number); +#else /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + len = sprintf(page, "%s\n", p_cpu_mapping->cpu_number); +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +END: + return len; +} + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +static int synobios_read_proc_cpu_arch_open(struct inode *inode, struct file *file) +{ + return single_open(file, synobios_read_proc_cpu_arch, NULL); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) +static const struct proc_ops synobios_read_proc_cpu_arch_ops = { + .proc_open = synobios_read_proc_cpu_arch_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +#else +static const struct file_operations synobios_read_proc_cpu_arch_fops = { + .owner = THIS_MODULE, + .open = synobios_read_proc_cpu_arch_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + +static int synobios_add_proc_cpu_arch(void) +{ + struct proc_dir_entry *synobios_proc_entry; + + if (boot_cpu_data.x86_model_id[0]) + synobios_detect_cpu_model(); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) + synobios_proc_entry = proc_create_data("syno_cpu_arch", 0444, NULL, + &synobios_read_proc_cpu_arch_ops, NULL); +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) + synobios_proc_entry = proc_create_data("syno_cpu_arch", 0444, NULL, + &synobios_read_proc_cpu_arch_fops, NULL); +#else + synobios_proc_entry = create_proc_read_entry("syno_cpu_arch", 0444, NULL, + synobios_read_proc_cpu_arch, NULL); +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + + if (!synobios_proc_entry) { + printk("create cpu_arch proc entry fail\n"); + return -EFAULT; + } + + printk(KERN_INFO"synobios cpu_arch proc entry initialized\n"); + + return 0; +} + +static int synobios_remove_proc_cpu_arch(void) +{ + remove_proc_entry("syno_cpu_arch", NULL); + return 0; +} + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +static int synobios_read_proc_crypto_hw(struct seq_file *m, void *v) +#else /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +static int synobios_read_proc_crypto_hw(char *page, char **start, off_t off, + int count, int *eof, void *data) +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +{ + int len = 0; + SYNO_CRYPTO_MAPPING *p_crypto_mapping = NULL; + module_t *syno_module = module_type_get(); + if (!syno_module) { + printk("get crypto hw information failed\n"); + goto END; + } + + p_crypto_mapping = gSynoCRYPTOMapping; + while (CRYPTO_HW_NONE != p_crypto_mapping->hw_name) { + if (p_crypto_mapping->hw_name == syno_module->crypto_hw_info) + break; + p_crypto_mapping++; + } +#if SYNO_HAVE_KERNEL_VERSION(4,4,0) + seq_printf(m, "%s\n", p_crypto_mapping->crypto_capabilities); +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) + len = seq_printf(m, "%s\n", p_crypto_mapping->crypto_capabilities); +#else /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + len = sprintf(page, "%s\n", p_crypto_mapping->crypto_capabilities); +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +END: + return len; +} + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +static int synobios_read_proc_crypto_hw_open(struct inode *inode, struct file *file) +{ + return single_open(file, synobios_read_proc_crypto_hw, NULL); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) +static const struct proc_ops synobios_read_proc_crypto_hw_ops = { + .proc_open = synobios_read_proc_crypto_hw_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +#else +static const struct file_operations synobios_read_proc_crypto_hw_fops = { + .owner = THIS_MODULE, + .open = synobios_read_proc_crypto_hw_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + +/* this is a hint for userspace to utilize crypto engine */ +static int synobios_add_proc_crypto_hw(void) +{ + struct proc_dir_entry *synobios_proc_entry; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) + synobios_proc_entry = proc_create_data("syno_crypto_hw", 0400, proc_synobios_root, + &synobios_read_proc_crypto_hw_ops, NULL); +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) + synobios_proc_entry = proc_create_data("syno_crypto_hw", 0400, proc_synobios_root, + &synobios_read_proc_crypto_hw_fops, NULL); +#else + synobios_proc_entry = create_proc_read_entry("syno_crypto_hw", 0400, proc_synobios_root, synobios_read_proc_crypto_hw, NULL); +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + + if (!synobios_proc_entry) { + printk("create crypto hw proc entry fail\n"); + return -EFAULT; + } + + printk(KERN_INFO"synobios crypto_hw proc entry initialized\n"); + + return 0; +} + +static int synobios_remove_proc_crypto_hw(void) +{ + remove_proc_entry("syno_crypto_hw", proc_synobios_root); + return 0; +} + +#if SYNO_HAVE_KERNEL_VERSION(3,10,0) +static int synobios_read_proc_platform_name(struct seq_file *m, void *v) +{ +#if SYNO_HAVE_KERNEL_VERSION(4,4,0) + seq_printf(m, "%s\n", SYNO_PLATFORM); + return 0; +#else + return seq_printf(m, "%s\n", SYNO_PLATFORM); +#endif /* SYNO_HAVE_KERNEL_VERSION(4,4,0) */ +} + +static int synobios_read_proc_platform_open(struct inode *inode, struct file *file) +{ + return single_open(file, synobios_read_proc_platform_name, NULL); +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) +static const struct proc_ops synobios_read_proc_platform_ops = { + .proc_open = synobios_read_proc_platform_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +#else +static const struct file_operations synobios_read_proc_platform_fops = { + .owner = THIS_MODULE, + .open = synobios_read_proc_platform_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif +#else /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ +static int synobios_read_proc_platform_name(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return sprintf(page, "%s\n", SYNO_PLATFORM); +} +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + +static int synobios_add_proc_platform_name(void) +{ + struct proc_dir_entry *synobios_proc_entry; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) + synobios_proc_entry = proc_create_data("syno_platform", 0444, NULL, + &synobios_read_proc_platform_ops, NULL); +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) + synobios_proc_entry = proc_create_data("syno_platform", 0444, NULL, + &synobios_read_proc_platform_fops, NULL); +#else + synobios_proc_entry = create_proc_read_entry("syno_platform", 0444, NULL, synobios_read_proc_platform_name, NULL); +#endif /* SYNO_HAVE_KERNEL_VERSION(3,10,0) */ + if (!synobios_proc_entry) { + printk("create syno_platform proc entry fail\n"); + return -EFAULT; + } + + printk(KERN_INFO"synobios syno_platform proc entry initialized\n"); + + return 0; +} + +static int synobios_remove_proc_platform_name(void) +{ + remove_proc_entry("syno_platform", NULL); + return 0; +} + +int synobios_open(struct inode *inode, struct file *filp) +{ + return 0; +} + + +int synobios_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +/***** + * Helper function to notify user space + * HW has capability to detect SD card change + *****/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) +static const struct proc_ops card_detect_proc_ops; +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) +static const struct file_operations card_detect_proc_fops; +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + +#define SD_DETECT_PROC_ENTRY "syno_card_detect" +int add_card_detect_proc(void) +{ + struct proc_dir_entry *proc_entry; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) + proc_entry = proc_create(SD_DETECT_PROC_ENTRY, 0400, proc_synobios_root, &card_detect_proc_ops); +#elif SYNO_HAVE_KERNEL_VERSION(3,10,0) + proc_entry = proc_create(SD_DETECT_PROC_ENTRY, 0400, proc_synobios_root, &card_detect_proc_fops); +#else + proc_entry = create_proc_entry(SD_DETECT_PROC_ENTRY, 0400, proc_synobios_root); +#endif /*SYNO_HAVE_KERNEL_VERSION(3,10,0)*/ + if (!proc_entry) { + printk("create card detect proc entry fail\n"); + return -EFAULT; + } + + printk(KERN_INFO"add card detect proc entry\n"); + + return 0; +} +int remove_card_detect_proc(void) +{ + remove_proc_entry(SD_DETECT_PROC_ENTRY, proc_synobios_root); + return 0; +} + +struct file_operations synobios_fops = { + /*llseek:*/ + /*read:*/ + /*write:*/ + /*readdir:*/ + poll: synobios_poll, + unlocked_ioctl: synobios_ioctl, + compat_ioctl: synobios_ioctl, +/* int (*mmap) (struct file *, struct vm_area_struct *);*/ + open: synobios_open, +/* int (*flush) (struct file *);*/ + release: synobios_release, +/* int (*fsync) (struct file *, struct dentry *, int datasync);*/ +/* int (*fasync) (int, struct file *, int);*/ +/* int (*lock) (struct file *, int, struct file_lock *);*/ +/* ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);*/ +/* ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);*/ +/* ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);*/ +/* unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);*/ +}; + +typedef struct _tag_SYNO_MODEL_MAPPING { + PRODUCT_MODEL model; + char *szModelName; +} SYNO_MODEL_MAPPING; + +static SYNO_MODEL_MAPPING gSynoModelMapping[] = { + {MODEL_RS3411rpxs, "RS-3411rpxs"}, + {MODEL_RS3411xs, "RS-3411xs"}, + {MODEL_RS10613xsp, "RS-10613xs+"}, + {MODEL_DS3611xs, "DS-3611xs"}, + {MODEL_DS412p, "DS-412+"}, + {MODEL_DS713p, "DS-713+"}, + {MODEL_RS812p, "RS-812+"}, + {MODEL_RS812rpp, "RS-812rp+"}, + {MODEL_DS1812p, "DS-1812+"}, + {MODEL_RS2212p, "RS-2212+"}, + {MODEL_RS2414p, "RS-2414+"}, + {MODEL_RS2414rpp, "RS-2414rp+"}, + {MODEL_RS2212rpp, "RS-2212rp+"}, + {MODEL_DS2413p, "DS-2413+"}, + {MODEL_DS2415p, "DS-2415+"}, + {MODEL_RS812, "RS-812"}, + {MODEL_DS1512p, "DS-1512+"}, + {MODEL_RS3412rpxs, "RS-3412rpxs"}, + {MODEL_RS3412xs, "RS-3412xs"}, + {MODEL_DS3612xs, "DS-3612xs"}, + {MODEL_RS3413xsp, "RS-3413xs+"}, + {MODEL_RS3614xs, "RS-3614xs"}, + {MODEL_RS3614rpxs, "RS-3614rpxs"}, + {MODEL_RS3614xsp, "RS-3614xs+"}, + {MODEL_DS2414xs, "DS-2414xs"}, + {MODEL_DS414j, "DS-414j"}, + {MODEL_DS415j, "DS-415j"}, + {MODEL_DS213, "DS-213"}, + {MODEL_DS1513p, "DS-1513+"}, + {MODEL_DS1813p, "DS-1813+"}, + {MODEL_DS213j, "DS-213j"}, + {MODEL_DS114, "DS-114"}, + {MODEL_RS214, "RS-214"}, + {MODEL_DS214, "DS-214"}, + {MODEL_DS214p, "DS-214+"}, + {MODEL_DS214se, "DS-214se"}, + {MODEL_DS114p, "DS-114+"}, + {MODEL_DS414, "DS-414"}, + {MODEL_RS814, "RS-814"}, + {MODEL_RC18015xsp, "RC-18015xs+"}, + {MODEL_RS814p, "RS-814+"}, + {MODEL_RS814rpp, "RS-814rp+"}, + {MODEL_DS214play, "DS-214play"}, + {MODEL_DS414slim, "DS-414slim"}, + {MODEL_DS415play, "DS-415play"}, + {MODEL_DS2015xs, "DS-2015xs"}, + {MODEL_DS115j, "DS-115j"}, + {MODEL_RS3415xsp, "RS-3415xs+"}, + {MODEL_DS415p, "DS-415+"}, + {MODEL_DS3615xs, "DS-3615xs"}, + {MODEL_DS1815p, "DS-1815+"}, + {MODEL_DS1515p, "DS-1515+"}, + {MODEL_DS215j, "DS-215j"}, + {MODEL_DS115, "DS-115"}, + {MODEL_RS815p, "RS-815+"}, + {MODEL_RS815rpp, "RS-815rp+"}, + {MODEL_DS715, "DS-715"}, + {MODEL_RS815, "RS-815"}, + {MODEL_RS18016xsp, "RS-18016xs+"}, + {MODEL_RS18016Dxsp, "RS-18016Dxs+"}, + {MODEL_DS1515, "DS-1515"}, + {MODEL_DS215p, "DS-215+"}, + {MODEL_VirtualDSM, "VirtualDSM"}, + {MODEL_DS416, "DS-416"}, + {MODEL_RS2416p, "RS-2416+"}, + {MODEL_RS2416rpp, "RS-2416rp+"}, + {MODEL_DS216play, "DS-216play"}, + {MODEL_DS216se, "DS-216se"}, + {MODEL_RSD18016xsp, "RSD-18016xs+"}, + {MODEL_DS916p, "DS-916+"}, + {MODEL_DS1616p, "DS-1616+"}, + {MODEL_DS716p, "DS-716+"}, + {MODEL_RS3618xs, "RS-3618xs"}, + {MODEL_RS3617rpxs, "RS-3617rpxs"}, + {MODEL_RS3617xsp, "RS-3617xs+"}, + {MODEL_DS416j, "DS-416j"}, + {MODEL_DS216, "DS-216"}, + {MODEL_DS416slim, "DS-416slim"}, + {MODEL_DS216p, "DS-216+"}, + {MODEL_DS216j, "DS-216j"}, + {MODEL_RS816, "RS-816"}, + {MODEL_DS116, "DS-116"}, + {MODEL_DS416play, "DS-416play"}, + {MODEL_DS216pII, "DS-216+II"}, + {MODEL_DS716pII, "DS-716+II"}, + {MODEL_RS217, "RS-217"}, + {MODEL_FS3017, "FS-3017"}, + {MODEL_RS3617xs, "RS-3617xs"}, + {MODEL_RS2418p, "RS-2418+"}, + {MODEL_RS2418rpp, "RS-2418rp+"}, + {MODEL_DS918p, "DS-918+"}, + {MODEL_RS4017xsp, "RS-4017xs+"}, + {MODEL_DS3617xs, "DS-3617xs"}, + {MODEL_RS18017xsp, "RS-18017xs+"}, + {MODEL_DS218p, "DS-218+"}, + {MODEL_DS1618p, "DS-1618+"}, + {MODEL_C2DSM, "C2DSM"}, + {MODEL_DS1517p, "DS-1517+"}, + {MODEL_DS1817p, "DS-1817+"}, + {MODEL_DS718p, "DS-718+"}, + {MODEL_FS2017, "FS-2017"}, + {MODEL_DS418, "DS-418"}, + {MODEL_DS418j, "DS-418j"}, + {MODEL_DS218play, "DS-218play"}, + {MODEL_DS118, "DS-118"}, + {MODEL_DS218, "DS-218"}, + {MODEL_EDS19, "EDS-19"}, + {MODEL_RS819, "RS-819"}, + {MODEL_DS220j, "DS-220j"}, + {MODEL_DS420j, "DS-420j"}, + {MODEL_DS1817, "DS-1817"}, + {MODEL_DS1517, "DS-1517"}, + {MODEL_DS3017xs, "DS-3017xs"}, + {MODEL_DS3018xs, "DS-3018xs"}, + {MODEL_FS1018, "FS-1018"}, + {MODEL_DS219j, "DS-219j"}, + {MODEL_FS6400, "FS-6400"}, + {MODEL_RS818p, "RS-818+"}, + {MODEL_RS818rpp, "RS-818rp+"}, + {MODEL_DS418play, "DS-418play"}, + {MODEL_RS2818rpp, "RS-2818rp+"}, + {MODEL_DS219se, "DS-219se"}, + {MODEL_NVR1218, "NVR1218"}, + {MODEL_DS218j, "DS-218j"}, + {MODEL_DS3619xs, "DS-3619xs"}, + {MODEL_DS119j, "DS-119j"}, + {MODEL_TAIPEI, "TAIPEI"}, + {MODEL_RS1619xsp, "RS-1619xs+"}, + {MODEL_RS1219p, "RS-1219+"}, + {MODEL_DS2419p, "DS-2419+"}, + {MODEL_DS419p, "DS-419+"}, + {MODEL_DS1019p, "DS-1019+"}, + {MODEL_DS719p, "DS-719+"}, + {MODEL_DS1819p, "DS-1819+"}, + {MODEL_DS620slim, "DS-620slim"}, + {MODEL_RS419p, "RS-419+"}, + {MODEL_DS419slim, "DS-419slim"}, + {MODEL_RS1219, "RS-1219"}, + {MODEL_DVA3219, "DVA-3219"}, + {MODEL_SA3400, "SA-3400"}, + {MODEL_DS420p, "DS-420+"}, + {MODEL_DS720p, "DS-720+"}, + {MODEL_DS220p, "DS-220+"}, + {MODEL_RS820p, "RS-820+"}, + {MODEL_RS820rpp, "RS-820rp+"}, + {MODEL_FS3400, "FS-3400"}, + {MODEL_SA3600, "SA-3600"}, + {MODEL_FS3600, "FS-3600"}, + {MODEL_HD3400, "HD-3400"}, + {MODEL_DS220play, "DS-220play"}, + {MODEL_DS220, "DS-220"}, + {MODEL_DS120j, "DS-120j"}, + {MODEL_DS1520p, "DS-1520+"}, + {MODEL_RS1220p, "RS-1220+"}, + {MODEL_RS1220rpp, "RS-1220rp+"}, + {MODEL_DS920p, "DS-920+"}, + {MODEL_SA6500, "SA-6500"}, + {MODEL_DS1621p, "DS-1621+"}, + {MODEL_HD6500, "HD-6500"}, + {MODEL_SA3200d, "SA-3200d"}, + {MODEL_SA3400d, "SA-3400d"}, + {MODEL_DVA3221, "DVA-3221"}, + {MODEL_AliDSM, "AliDSM"}, + {MODEL_RS1221p, "RS-1221+"}, + {MODEL_RS1221rpp, "RS-1221rp+"}, + {MODEL_DS1821p, "DS-1821+"}, + {MODEL_DS2422p, "DS-2422+"}, + {MODEL_RS2421p, "RS-2421+"}, + {MODEL_RS2421rpp, "RS-2421rp+"}, + {MODEL_RS2821rpp, "RS-2821rp+"}, + {MODEL_FS6600N, "FS-6600N"}, + {MODEL_RS3621xsp, "RS-3621xs+"}, + {MODEL_RS3621rpxs, "RS-3621rpxs"}, + {MODEL_RS4021xsp, "RS-4021xs+"}, + {MODEL_FS6500, "FS-6500"}, + {MODEL_DS3617xsII, "DS-3617xsII"}, + {MODEL_DS3622xsp, "DS-3622xs+"}, + {MODEL_DS2419pII, "DS-2419+II"}, + {MODEL_FS2500, "FS2500"}, + {MODEL_FS2500T, "FS2500T"}, + {MODEL_DVA1622, "DVA-1622"}, + {MODEL_RS4023xsp, "RS-4023xs+"}, + {MODEL_RS4022xsp, "RS-4022xs+"}, + {MODEL_FS3410, "FS-3410"}, + {MODEL_DS223j, "DS-223j"}, + {MODEL_DS423, "DS-423"}, + {MODEL_DS223, "DS-223"}, + {MODEL_DS723p, "DS-723+"}, + {MODEL_DS923p, "DS-923+"}, + {MODEL_RS422p, "RS-422+"}, + {MODEL_DS1522p, "DS-1522+"}, + {MODEL_RS822p, "RS-822+"}, + {MODEL_RS822rpp, "RS-822rp+"}, + {MODEL_RS2423p, "RS-2423+"}, + {MODEL_RS2423rpp, "RS-2423rp+"}, + {MODEL_DS1823xsp, "DS-1823xs+"}, + {MODEL_RS1623xsp, "RS-1623xs+"}, + {MODEL_FS6410, "FS-6410"}, + {MODEL_SA6400, "SA-6400"}, + {MODEL_SA6200, "SA-6200"}, + {MODEL_SC6200, "SC-6200"}, + {MODEL_DS423p, "DS-423+"}, + {MODEL_SA3410, "SA-3410"}, + {MODEL_SA3610, "SA-3610"}, + {MODEL_DS124, "DS-124"}, + {MODEL_DS224p, "DS-224+"}, + {MODEL_RS4024xsp, "RS-4024xs+"}, + {MODEL_VS750hd, "VS-750hd"}, + {MODEL_DS1623p, "DS-1623+"}, + {MODEL_DS1823p, "DS-1823+"}, + {MODEL_SC2500, "SC-2500"}, + {MODEL_INVALID, "Unknown"}, +}; + +static void synobios_print_model(void) +{ + int brand, model; + SYNO_MODEL_MAPPING *pModelMapping; + + if (synobios_ops->get_brand) { + brand = synobios_ops->get_brand(); + switch (brand) { + case BRAND_SYNOLOGY: + printk("Brand: Synology\n"); + break; + case BRAND_LOGITEC: + printk("Brand: Logitec\n"); + break; + default: + printk("Brand: Unknown brand\n"); + } + } else { + printk("Get brand function not defined.\n"); + } + if (synobios_ops->get_model) { + model = synobios_ops->get_model(); + pModelMapping = gSynoModelMapping; + while (pModelMapping->model != MODEL_INVALID) { + if (pModelMapping->model == model) { + break; + } + pModelMapping++; + } + printk("Model: %s\n", pModelMapping->szModelName); + } else { + printk("Get model function not defined.\n"); + } + + return; +} + +static void synobios_schedule_poweron_init(void) +{ + gPwSched.num = 0; + gPwSched.enabled = SYNO_AUTO_POWERON_DISABLE; + memset(gPwSched.RtcAlarmPkt, 0, sizeof(SYNORTCALARMPKT)*MAX_POWER_SCHEDULE_TASKS); + + return; +} + +int +GetHWMONSupport(SYNO_HWMON_SUPPORT *hwmon_support) +{ + int iRet = -1; + module_t *syno_module = module_type_get(); + + if (NULL == hwmon_support) { + iRet = -EINVAL; + goto End; + } + + hwmon_support->support = 0; + + switch (hwmon_support->id) { + case HWMON_CPU_TEMP: + if (CPUTMP_YES == syno_module->cputmp_type) { + hwmon_support->support = 1; + } + break; + case HWMON_SYS_THERMAL: + if (synobios_ops->hwmon_get_sys_thermal) { + hwmon_support->support = 1; + } + break; + case HWMON_SYS_VOLTAGE: + if (synobios_ops->hwmon_get_sys_voltage) { + hwmon_support->support = 1; + } + break; + case HWMON_FAN_SPEED_RPM: + if (synobios_ops->hwmon_get_fan_speed_rpm) { + hwmon_support->support = 1; + } + break; + case HWMON_HDD_BACKPLANE: + if (synobios_ops->hwmon_get_backplane_status) { + hwmon_support->support = 1; + } + break; + case HWMON_PSU_STATUS: + if (synobios_ops->hwmon_get_psu_status) { + if (POWER_DUAL == syno_module->dual_power_type) { + hwmon_support->support = 2; + } + else { + hwmon_support->support = 1; + } + } + break; + case HWMON_SYS_CURRENT: + if (synobios_ops->hwmon_get_sys_current) { + hwmon_support->support = 1; + } + break; + default: + iRet = -EINVAL; + goto End; + } + + iRet = 0; +End: + return iRet; +} + +int synobios_event_handler(unsigned long long synobios_event_type, ...) +{ + int args_num = 0, i = 0, ret = -EPERM; + unsigned long long parms[SYNOBIOS_EVENTDATA_NUM_MAX] = {0}; + va_list args; + struct tty_struct tty; + SYNOBIOS_EVENT_PARM event_parms; + memset(&event_parms, 0, sizeof(SYNOBIOS_EVENT_PARM)); + + va_start(args, synobios_event_type); + + args_num = va_arg(args, unsigned long long); + if (SYNOBIOS_EVENTDATA_NUM_MAX < args_num) { + pr_warn("args number %d from kernel exceeds synobios expected max %d.\n", args_num, SYNOBIOS_EVENTDATA_NUM_MAX); + ret = -EINVAL; + va_end(args); + goto END; + } + for (i = 0; i < args_num && i < SYNOBIOS_EVENTDATA_NUM_MAX; i++) { + parms[i] = va_arg(args, unsigned long long); + event_parms.data[i] = parms[i]; + } + va_end(args); + + switch (synobios_event_type) { + case SYNO_EVENT_DSIK_POWER_SHORT_BREAK: +#ifdef CONFIG_SYNO_PORT_MAPPING_V2 + synobios_disk_power_short_break_report(__SYNOEVENTCALL_PARM4(parms)); +#else /* CONFIG_SYNO_PORT_MAPPING_V2 */ + synobios_disk_power_short_break_report(__SYNOEVENTCALL_PARM2(parms)); +#endif /* CONFIG_SYNO_PORT_MAPPING_V2 */ + break; + case SYNO_EVENT_DISK_PWR_RESET: + synobios_record_disk_pwr_reset_event(__SYNOEVENTCALL_PARM2(parms)); + break; + case SYNO_EVENT_DISK_PORT_DISABLED: + synobios_record_disk_port_disabled_event(__SYNOEVENTCALL_PARM3(parms)); + break; + case SYNO_EVENT_WAKE_FROM_DEEP_SLEEP: + synobios_wake_from_deep_sleep(__SYNOEVENTCALL_PARM2(parms)); + break; + case SYNO_EVENT_DISK_PORT_LOST: + synobios_disk_port_lost_report(__SYNOEVENTCALL_PARM2(parms)); + break; + case SYNO_EVENT_DISK_RESET_FAIL_REPORT: + synobios_disk_reset_fail_report(event_parms); + break; + case SYNO_EVENT_DISK_TIMEOUT_REPORT: + synobios_disk_timeout_report(event_parms); + break; + case SYNO_EVENT_SATA_ERROR_REPORT: + synobios_sata_error_report(event_parms); + break; + case SYNO_EVENT_DISK_RETRY_REPORT: + synobios_disk_retry_report(__SYNOEVENTCALL_PARM2(parms)); + break; + case SYNO_EVENT_USB_PROHIBIT: + syno_usb_prohibit_event(); + break; + case SYNO_EVENT_CONSOLE_PROHIBIT: + syno_console_prohibit_event(); + break; + case SYNO_EVENT_MICROP_GET: + /* FIXME: Remove tty struct and refine syno_microp_get_event parms + * when kernel previous 4.4 does not use this synobios. + * The tty struct is for compatibility for 4.4 version synobios. + * In 4.4 synobios the tty name check is in synobios, + * but we move tty name check to kernel in 5.10 version. + */ + try_wakeup_waiting_microp(); + memset(&tty, 0, sizeof(struct tty_struct)); + snprintf(tty.name, 64, "%s", TTY_NAME); + syno_microp_get_event(&tty); + break; + case SYNO_EVENT_SCSI_ERROR: + synobios_record_scsi_error_event(event_parms); + break; + case SYNO_EVENT_EBOX_RESET: + synobios_record_ebox_reset_event(event_parms); + break; + default: + pr_warn("Unknown synobios event type.\n"); + ret = -EINVAL; + goto END; + } + + ret = 0; +END: + return ret; +} + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_ERROR_REPORT) +extern struct list_head gSynoBiosEventHead; +extern spinlock_t syno_sata_error_lock; +void process_synobios_event_list(void) +{ + SYNOBIOS_EVENT_ACTION_LIST *synobios_action = NULL; + SYNOBIOS_EVENT_ACTION_LIST *nex_synobios_action = NULL; + unsigned long syno_sata_error_lock_flags; + + spin_lock_irqsave(&syno_sata_error_lock, syno_sata_error_lock_flags); + list_for_each_entry_safe(synobios_action, nex_synobios_action, &gSynoBiosEventHead, list) { + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + synobios_event_handler(synobios_action->synobios_event_type, 5, synobios_action->parms.data[0], + synobios_action->parms.data[1], synobios_action->parms.data[2], synobios_action->parms.data[3], synobios_action->parms.data[4]); +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + if (NULL != synobios_action->funcSynobiosEvent && NULL != *(synobios_action->funcSynobiosEvent)) { + (*(synobios_action->funcSynobiosEvent))(synobios_action->parms); + } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ + list_del(&synobios_action->list); + kfree(synobios_action); + } + spin_unlock_irqrestore(&syno_sata_error_lock, syno_sata_error_lock_flags); +} +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_ERROR_REPORT */ + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK +extern int (*funcSYNOShutdownHook)(void); +SYNO_SHUTDOWN_HOOK_LIST synoShutdownHooks; + +static int syno_shutdown_hooks(void) +{ + SYNO_SHUTDOWN_HOOK *ops; + + mutex_lock(&synoShutdownHooks.hookLock); + list_for_each_entry(ops, &synoShutdownHooks.hookList, node) { + if (system_state == SYSTEM_POWER_OFF && ops->shutdown) { + ops->shutdown(); + }else if (system_state == SYSTEM_RESTART && ops->restart) { + ops->restart(); + } + } + mutex_unlock(&synoShutdownHooks.hookLock); + + return 0; +} + +static void syno_init_shutdown_hooks(void) +{ + mutex_init(&synoShutdownHooks.hookLock); + INIT_LIST_HEAD(&synoShutdownHooks.hookList); + + funcSYNOShutdownHook = syno_shutdown_hooks; +} + +static void syno_uninit_shutdown_hooks(void) +{ + mutex_destroy(&synoShutdownHooks.hookLock); + + funcSYNOShutdownHook = NULL; +} + +void syno_append_shutdown_hook(SYNO_SHUTDOWN_HOOK *ops) +{ + if (NULL == ops) { + return; + } + + mutex_lock(&synoShutdownHooks.hookLock); + list_add_tail(&ops->node, &synoShutdownHooks.hookList); + mutex_unlock(&synoShutdownHooks.hookLock); +} +EXPORT_SYMBOL(syno_append_shutdown_hook); +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + +int synobios_init(void) +{ + int iRet = -1; + + scSynoBios.countEvents = 0; + scSynoBios.idxPtr = 0; + spin_lock_init(&scSynoBios.lock); + + /*initialize wait queues*/ + init_waitqueue_head(&(scSynoBios.wq_poll)); + + /* create procfs root entry */ + proc_synobios_root = proc_mkdir(SZ_PROC_SYNOBIOS_ROOT, NULL); + if (!proc_synobios_root) { + printk("synobios: create procfs root entry fail\n"); + } + + syno_ttyS_open(); + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK + /* Initialize Shutdown Hook functions: + * + * How to add customized shutdown function + * syno_append_shutdown_hook(SYNO_SHUTDOWN_HOOK *ops) + * + * Note: the execution order of SHUTDOWN_HOOK will be same as the + * order of appending. + */ + syno_init_shutdown_hooks(); +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + + synobios_model_init(&synobios_fops, &synobios_ops); + + if (synobios_ops->module_type_init) { + synobios_ops->module_type_init(synobios_ops); + } else { + module_type_set(NULL); + } + + synobios_rtc_init(); + + if (NULL == (pgSysStatus = kzalloc(sizeof(SYNO_SYS_STATUS), GFP_KERNEL))) { + printk("malloc SYNO_SYS_STATUS fail\n"); + iRet = 0; + goto END; + } + + pgSysStatus->fan_fail |= SIGNATURE_FAN_FAIL; + pgSysStatus->volume_degrade |= SIGNATURE_VOLUME_DEGRADE; + pgSysStatus->volume_crashed |= SIGNATURE_VOLUME_CRASHED; + pgSysStatus->power_fail |= SIGNATURE_POWER_FAIL; + pgSysStatus->ebox_fan_fail |= SIGNATURE_EBOX_FAN_FAIL; + pgSysStatus->cpu_fan_fail |= SIGNATURE_CPU_FAN_FAIL; + +/* + * Defined in drivers/md/libmd-report.c: + * funcSYNOSendRaidEvent + */ +#ifdef CONFIG_MD +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) + funcSYNOSendRaidEvent = synobios_record_raid_event; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) + funcSYNOSendAutoRemapRaidEvent = synobios_autoremap_raid_event; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) + funcSYNOSendRaidSyncEvent = synobios_raid_sync_event; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) */ +#endif /* CONFIG_MD */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_EXT4_ERROR_REPORT) + funcSYNOSendErrorFsEvent = synobios_error_fs_event; +#endif /* MY_DEF_HERE || CONFIG_SYNO_EXT4_ERROR_REPORT */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_BTRFS_DATA_CORRECTION) + funcSYNOSendErrorFsBtrfsEvent = synobios_error_fs_btrfs_event; + funcSYNOMetaCorruptedEvent = synobios_error_btrfs_meta_corrupted_event; +#endif /* MY_DEF_HERE || CONFIG_SYNO_BTRFS_DATA_CORRECTION */ +/* + * Defined in drivers/ata/libata-core.c: + * funcSYNOGetHwCapability + * funcSYNOSendEboxRefreshEvent + */ +#if (defined(CONFIG_ATA) || defined(CONFIG_SCSI_SATA)) +#ifdef MY_DEF_HERE + funcSYNOSendDiskResetPwrEvent = synobios_record_disk_pwr_reset_event; +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + funcSYNOSendDiskPortDisEvent = synobios_record_disk_port_disabled_event; +#ifdef MY_DEF_HERE + funcSYNOSendDiskPortLostEvent = synobios_disk_port_lost_report; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ +#if (defined(MY_DEF_HERE) || defined(SYNO_HAS_SDCARDREADER)) + funcSYNOGetHwCapability = GetHwCapability; +#ifdef MY_DEF_HERE + funcSynoEunitPowerctlType = GetEUnitType; +#endif +#endif +#ifdef MY_DEF_HERE + funcSYNOSendEboxRefreshEvent = synobios_record_ebox_refresh_event; +#endif +#ifdef MY_DEF_HERE + funcSYNOSataErrorReport = synobios_sata_error_report; + funcSYNODiskRetryReport = synobios_disk_retry_report; + funcSYNODiskTimeoutReport = synobios_disk_timeout_report; + funcSYNODiskResetFailReport = synobios_disk_reset_fail_report; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_ATA */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_ECC_NOTIFICATION) + funcSYNOECCNotification = synobios_event_ecc_notification; +#endif /* MY_DEF_HERE || CONFIG_SYNO_ECC_NOTIFICATION */ +#ifdef MY_DEF_HERE + funcSYNODeepSleepEvent = synobios_wake_from_deep_sleep; +#endif /* MY_DEF_HERE */ +#if defined(MY_DEF_HERE) + funcSYNODiskPowerShortBreakReport = synobios_disk_power_short_break_report; +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_MPC824X + if( synobios_ops->set_rtc_time ) { + funcSYNORtcSetTime = synobios_ops->set_rtc_time; + } +#endif /*CONFIG_SYNO_MPC824X*/ +#ifdef CONFIG_SYNO_BUZZER_MUTE_IRQ + funcSYNOBuzzerMuteIRQ = syno_buzzer_cleared_event; +#endif/* CONFIG_SYNO_BUZZER_MUTE_IRQ */ +#ifdef CONFIG_SYNO_DISPLAY_CPUINFO + syno_display_cpu_info(); +#endif/* CONFIG_SYNO_DISPLAY_CPUINFO */ +#ifdef CONFIG_SYNO_IE_SOFT_POWER_OFF + funcSYNOSendPowerButtonEvent = syno_power_button_event; +#endif /* CONFIG_SYNO_IE_SOFT_POWER_OFF */ + +#if defined(CONFIG_SYNO_USB_FORBID) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) + funcSYNOUsbProhibitEvent = syno_usb_prohibit_event; +#endif /* CONFIG_SYNO_USB_FORBID && ! CONFIG_SYNO_SYNOBIOS_EVENT */ + +#if defined(CONFIG_SYNO_SERIAL_CONSOLE_FORBID) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) + funcSYNOConsoleProhibitEvent = syno_console_prohibit_event; +#endif /* CONFIG_SYNO_SERIAL_CONSOLE_FORBID && ! CONFIG_SYNO_SYNOBIOS_EVENT */ + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_OOM_NOTIFICATION) + funcSYNOSendErrorOOMEvent = synobios_error_oom_event; +#endif /* (MY_DEF_HERE) || (CONFIG_SYNO_OOM_NOTIFICATION) */ + +#if defined(CONFIG_SYNO_TTY_EXPORT) || defined(MY_DEF_HERE) +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(SYNO_TTY_RECEIVE) + funcSYNOMicropGetEvent = syno_microp_get_event; +#endif /* SYNO_TTY_RECEIVE */ +#endif /* MY_DEF_HERE */ + +/* + * Defined in drivers/scsi/libsyno_report.c + */ +#if defined(MY_DEF_HERE) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) + funcSYNOSendScsiErrorEvent = synobios_record_scsi_error_event; +#endif /* MY_DEF_HERE && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) */ + +#if defined(CONFIG_SYNO_SATA_PM_DEVICE_I2C) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) + funcSYNOSendEunitResetEvent = synobios_record_ebox_reset_event; +#endif /* defined(CONFIG_SYNO_SATA_PM_DEVICE_I2C) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) ))*/ + +#ifdef CONFIG_SYNO_SYNOBIOS_EVENT + func_synobios_event_handler = synobios_event_handler; +#endif /* CONFIG_SYNO_SYNOBIOS_EVENT */ + printk(KERN_INFO "synobios: load, major number %d\n", SYNOBIOS_MAJOR); + iRet = register_chrdev(SYNOBIOS_MAJOR, "synobios", &synobios_fops); + if (iRet < 0) { + printk(KERN_INFO "synobios: can't set major number\n"); + goto END; + } + synobios_print_model(); + synobios_schedule_poweron_init(); +#ifdef MY_DEF_HERE + SetGroupWakeConfig(); +#endif + + if (synobios_ops->set_microp_id) { + synobios_ops->set_microp_id(); + } + + synobios_add_proc_cpu_arch(); + synobios_add_proc_crypto_hw(); + synobios_add_proc_platform_name(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_ERROR_REPORT) + if (1 == system_mode) { + process_synobios_event_list(); + } +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_ERROR_REPORT */ + iRet = 0; + +END: + return iRet; +} + +void synobios_cleanup(void) +{ +#ifdef CONFIG_MD +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT) + funcSYNOSendRaidEvent = NULL; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SECTOR_STATUS_REPORT)*/ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) + funcSYNOSendAutoRemapRaidEvent = NULL; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_AUTO_REMAP_REPORT) */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) + funcSYNOSendRaidSyncEvent = NULL; +#endif /* defined(MY_DEF_HERE) || defined(CONFIG_SYNO_MD_SYNC_STATUS_REPORT) */ +#endif /* CONFIG_MD */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_EXT4_ERROR_REPORT) + funcSYNOSendErrorFsEvent = NULL; +#endif /* MY_DEF_HERE || CONFIG_SYNO_EXT4_ERROR_REPORT */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_BTRFS_DATA_CORRECTION) + funcSYNOSendErrorFsBtrfsEvent = NULL; +#endif /* MY_DEF_HERE || CONFIG_SYNO_BTRFS_DATA_CORRECTION */ +#if (defined(CONFIG_ATA) || defined(CONFIG_SCSI_SATA)) +#ifdef MY_DEF_HERE + funcSYNOSendDiskResetPwrEvent = NULL; +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + funcSYNOSendDiskPortDisEvent = NULL; +#ifdef MY_DEF_HERE + funcSYNOSendDiskPortLostEvent = NULL; +#endif /* MY_DEF_HERE */ +#endif /* MY_DEF_HERE */ +#if (defined(MY_DEF_HERE) || defined(SYNO_HAS_SDCARDREADER)) + funcSYNOGetHwCapability = NULL; +#ifdef MY_DEF_HERE + funcSynoEunitPowerctlType = NULL; +#endif +#endif +#ifdef MY_DEF_HERE + funcSYNOSendEboxRefreshEvent = NULL; +#endif +#ifdef MY_DEF_HERE + funcSYNOSataErrorReport = NULL; + funcSYNODiskRetryReport = NULL; + funcSYNODiskTimeoutReport = NULL; + funcSYNODiskResetFailReport = NULL; +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + funcSYNODeepSleepEvent = NULL; +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + funcSYNODiskPowerShortBreakReport = NULL; +#endif /* MY_DEF_HERE */ +#endif /* CONFIG_ATA */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_ECC_NOTIFICATION) + funcSYNOECCNotification = NULL; +#endif /* MY_DEF_HERE || CONFIG_SYNO_ECC_NOTIFICATION */ +#ifdef CONFIG_SYNO_MPC824X + funcSYNORtcSetTime = NULL; +#endif /* CONFIG_SYNO_MPC824X */ +#ifdef CONFIG_SYNO_BUZZER_MUTE_IRQ + funcSYNOBuzzerMuteIRQ = NULL; +#endif /* CONFIG_SYNO_BUZZER_MUTE_IRQ */ +#ifdef CONFIG_SYNO_IE_SOFT_POWER_OFF + funcSYNOSendPowerButtonEvent = NULL; +#endif /* CONFIG_SYNO_IE_SOFT_POWER_OFF */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = NULL; +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_OOM_NOTIFICATION) + funcSYNOSendErrorOOMEvent = NULL; +#endif /* (MY_DEF_HERE) || (CONFIG_SYNO_OOM_NOTIFICATION) */ + +#if defined(CONFIG_SYNO_USB_FORBID) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) + funcSYNOUsbProhibitEvent = NULL; +#endif /* CONFIG_SYNO_USB_FORBID && ! CONFIG_SYNO_SYNOBIOS_EVENT */ + +#if defined(CONFIG_SYNO_SERIAL_CONSOLE_FORBID) && ! defined(CONFIG_SYNO_SYNOBIOS_EVENT) + funcSYNOConsoleProhibitEvent = NULL; +#endif /* CONFIG_SYNO_SERIAL_CONSOLE_FORBID && ! CONFIG_SYNO_SYNOBIOS_EVENT */ + +#ifdef MY_DEF_HERE + funcSYNOSendScsiErrorEvent = NULL; +#endif /* MY_DEF_HERE */ + +#ifdef CONFIG_SYNO_SYNOBIOS_EVENT + func_synobios_event_handler = NULL; +#endif /* CONFIG_SYNO_SYNOBIOS_EVENT */ + + if (pgSysStatus) { + kfree(pgSysStatus); + } + synobios_remove_proc_cpu_arch(); + synobios_remove_proc_crypto_hw(); + synobios_remove_proc_platform_name(); + + syno_ttyS_close(); + synobios_model_cleanup(&synobios_fops, &synobios_ops); + + /* remove procfs root entry */ + if (proc_synobios_root) { + remove_proc_entry(SZ_PROC_SYNOBIOS_ROOT, NULL); + } + +#if defined(CONFIG_SYNO_TTY_EXPORT) || defined(MY_DEF_HERE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) +#if defined(CONFIG_SYNO_TTY_RECEIVE) || defined(SYNO_TTY_RECEIVE) || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) + if (syno_get_current) { + syno_get_current = NULL; + } + +#ifdef CONFIG_SYNO_SYNOBIOS_EVENT +#else /* CONFIG_SYNO_SYNOBIOS_EVENT */ + funcSYNOMicropGetEvent = NULL; +#endif /* CONFIG_SYNO_SYNOBIOS_EVENT */ +#endif /* SYNO_TTY_RECEIVE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ +#endif /* MY_DEF_HERE || defined(CONFIG_SYNO_TTY_MICROP_FUNCTIONS) */ + +#ifdef CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK + syno_uninit_shutdown_hooks(); +#endif /* CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK */ + + printk("synobios: unload\n"); + unregister_chrdev(SYNOBIOS_MAJOR, "synobios"); +} + +MODULE_AUTHOR("Alex Wang"); +MODULE_DESCRIPTION("synobios\n") ; +MODULE_LICENSE("GPL"); + +module_init(synobios_init); +module_exit(synobios_cleanup); + diff --git a/drivers/syno/synobios/v1000/Makefile b/drivers/syno/synobios/v1000/Makefile new file mode 100644 index 000000000000..a91f5f614c71 --- /dev/null +++ b/drivers/syno/synobios/v1000/Makefile @@ -0,0 +1,39 @@ +include /env.mak + +obj-m += v1000-synobios.o + +v1000-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds1621p.o \ + rs1221p.o \ + rs1221rp+.o \ + ds1821p.o \ + ds2422p.o \ + rs2421p.o \ + rs2421rpp.o \ + rs2821rpp.o \ + fs2500.o \ + fs2500t.o \ + rs822p.o \ + rs822rpp.o \ + rs2423p.o \ + rs2423rpp.o \ + ds1823xsp.o \ + rs1623xsp.o \ + ds1623p.o \ + ds1823p.o \ + sc2500.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + v1000_common.o \ + ../led/led_trigger.o \ + ../led/led_jmb585.o \ + ../led/led_asm116x.o \ + ../led/led_1475.o \ + ../pmbus/pmbus.o diff --git a/drivers/syno/synobios/v1000/ds1621p.c b/drivers/syno/synobios/v1000/ds1621p.c new file mode 100644 index 000000000000..2ccc2d79bb90 --- /dev/null +++ b/drivers/syno/synobios/v1000/ds1621p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS1621pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1621pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1621pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1621pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1621p = MODULE_T_DS1621p; + module_t *pType = &type_1621p; + + module_type_set(pType); + return 0; +} + +static +int DS1621pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1621pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1621pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1621pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1621p_ops = { + .x86_init_module_type = DS1621pInitModuleType, + .x86_fan_speed_mapping = DS1621pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1621pGpioInit, + .x86_gpio_cleanup = DS1621pGpioCleanup, +}; + +struct hwmon_sensor_list ds1621p_sensor_list = { + .thermal_sensor = &DS1621p_thermal_sensor, + .voltage_sensor = &DS1621p_voltage_sensor, + .fan_speed_rpm = &DS1621p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1621p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/ds1623p.c b/drivers/syno/synobios/v1000/ds1623p.c new file mode 100644 index 000000000000..0f3d0581fb82 --- /dev/null +++ b/drivers/syno/synobios/v1000/ds1623p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS1623pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1623p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1623p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1623p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1623p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1623pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1623pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1623pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1623p = MODULE_T_DS1623p; + module_t *pType = &type_1623p; + + module_type_set(pType); + return 0; +} + +static +int DS1623pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1623pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1623pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1623pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1623p_ops = { + .x86_init_module_type = DS1623pInitModuleType, + .x86_fan_speed_mapping = DS1623pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1623pGpioInit, + .x86_gpio_cleanup = DS1623pGpioCleanup, +}; + +struct hwmon_sensor_list ds1623p_sensor_list = { + .thermal_sensor = &DS1623p_thermal_sensor, + .voltage_sensor = &DS1623p_voltage_sensor, + .fan_speed_rpm = &DS1623p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1623p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/ds1821p.c b/drivers/syno/synobios/v1000/ds1821p.c new file mode 100644 index 000000000000..ee1d87f0ebb7 --- /dev/null +++ b/drivers/syno/synobios/v1000/ds1821p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS1821pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1821pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1821pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1821pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1821p = MODULE_T_DS1821p; + module_t *pType = &type_1821p; + + module_type_set(pType); + return 0; +} + +static +int DS1821pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1821pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1821pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1821pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1821p_ops = { + .x86_init_module_type = DS1821pInitModuleType, + .x86_fan_speed_mapping = DS1821pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1821pGpioInit, + .x86_gpio_cleanup = DS1821pGpioCleanup, +}; + +struct hwmon_sensor_list ds1821p_sensor_list = { + .thermal_sensor = &DS1821p_thermal_sensor, + .voltage_sensor = &DS1821p_voltage_sensor, + .fan_speed_rpm = &DS1821p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1821p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/ds1823p.c b/drivers/syno/synobios/v1000/ds1823p.c new file mode 100644 index 000000000000..63ae0c002c54 --- /dev/null +++ b/drivers/syno/synobios/v1000/ds1823p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS1823pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1823pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1823pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1823pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1823p = MODULE_T_DS1823p; + module_t *pType = &type_1823p; + + module_type_set(pType); + return 0; +} + +static +int DS1823pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1823pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1823pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1823pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1823p_ops = { + .x86_init_module_type = DS1823pInitModuleType, + .x86_fan_speed_mapping = DS1823pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1823pGpioInit, + .x86_gpio_cleanup = DS1823pGpioCleanup, +}; + +struct hwmon_sensor_list ds1823p_sensor_list = { + .thermal_sensor = &DS1823p_thermal_sensor, + .voltage_sensor = &DS1823p_voltage_sensor, + .fan_speed_rpm = &DS1823p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1823p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/ds1823xsp.c b/drivers/syno/synobios/v1000/ds1823xsp.c new file mode 100644 index 000000000000..d50f60d9be91 --- /dev/null +++ b/drivers/syno/synobios/v1000/ds1823xsp.c @@ -0,0 +1,148 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS1823xspSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1823xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1823xspGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1823xspGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1823xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_1823xsp = MODULE_T_DS1823xsp; + module_t *pType = &type_1823xsp; + + module_type_set(pType); + return 0; +} + +static +int DS1823xspFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1823xspSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1823xspSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1823xspSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1823xsp_ops = { + .x86_init_module_type = DS1823xspInitModuleType, + .x86_fan_speed_mapping = DS1823xspFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1823xspGpioInit, + .x86_gpio_cleanup = DS1823xspGpioCleanup, +}; + +struct hwmon_sensor_list ds1823xsp_sensor_list = { + .thermal_sensor = &DS1823xsp_thermal_sensor, + .voltage_sensor = &DS1823xsp_voltage_sensor, + .fan_speed_rpm = &DS1823xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1823xsp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/ds2422p.c b/drivers/syno/synobios/v1000/ds2422p.c new file mode 100644 index 000000000000..d20fbe339627 --- /dev/null +++ b/drivers/syno/synobios/v1000/ds2422p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gDS2422pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS2422p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS2422p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS2422p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS2422p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS2422pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS2422pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS2422pInitModuleType(struct synobios_ops *ops) +{ + module_t type_2422p = MODULE_T_DS2422p; + module_t *pType = &type_2422p; + + module_type_set(pType); + return 0; +} + +static +int DS2422pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS2422pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS2422pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS2422pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds2422p_ops = { + .x86_init_module_type = DS2422pInitModuleType, + .x86_fan_speed_mapping = DS2422pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS2422pGpioInit, + .x86_gpio_cleanup = DS2422pGpioCleanup, +}; + +struct hwmon_sensor_list ds2422p_sensor_list = { + .thermal_sensor = &DS2422p_thermal_sensor, + .voltage_sensor = &DS2422p_voltage_sensor, + .fan_speed_rpm = &DS2422p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS2422p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/fs2500.c b/drivers/syno/synobios/v1000/fs2500.c new file mode 100644 index 000000000000..91e515e5628c --- /dev/null +++ b/drivers/syno/synobios/v1000/fs2500.c @@ -0,0 +1,179 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +extern int V1000RedundantPowerGetPowerStatus(POWER_INFO *power_info); + +PWM_FAN_SPEED_MAPPING gFS2500SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, + .sensor[3] = { + .sensor_name = HWMON_SYS_FAN4_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int FS2500GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +// GPIO_84, GPIO_85 +static SYNO_GPIO_INFO redundant_power_detect = { + .nr_gpio = 2, + .gpio_port = {84, 85}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void FS2500GpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.redundant_power_detect = &redundant_power_detect; +} + +static +void FS2500GpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; + syno_gpio.redundant_power_detect = NULL; +} + +static +int FS2500InitModuleType(struct synobios_ops *ops) +{ + module_t type_FS2500 = MODULE_T_FS2500; + module_t *pType = &type_FS2500; + + module_type_set(pType); + return 0; +} + +static +int FS2500FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS2500SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS2500SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS2500SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs2500_ops = { + .x86_init_module_type = FS2500InitModuleType, + .x86_fan_speed_mapping = FS2500FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = FS2500GetBuzzerCleared, + .x86_gpio_init = FS2500GpioInit, + .x86_gpio_cleanup = FS2500GpioCleanup, + .x86_get_power_status = V1000RedundantPowerGetPowerStatus, +}; + +struct hwmon_sensor_list fs2500_sensor_list = { + .thermal_sensor = &FS2500_thermal_sensor, + .voltage_sensor = &FS2500_voltage_sensor, + .fan_speed_rpm = &FS2500_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &FS2500_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/fs2500t.c b/drivers/syno/synobios/v1000/fs2500t.c new file mode 100644 index 000000000000..cc219f4beb5d --- /dev/null +++ b/drivers/syno/synobios/v1000/fs2500t.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gFS2500TSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500T_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500T_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500T_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE FS2500T_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void FS2500TGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void FS2500TGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int FS2500TInitModuleType(struct synobios_ops *ops) +{ + module_t type_FS2500T = MODULE_T_FS2500T; + module_t *pType = &type_FS2500T; + + module_type_set(pType); + return 0; +} + +static +int FS2500TFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gFS2500TSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gFS2500TSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gFS2500TSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops fs2500t_ops = { + .x86_init_module_type = FS2500TInitModuleType, + .x86_fan_speed_mapping = FS2500TFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, + .x86_gpio_init = FS2500TGpioInit, + .x86_gpio_cleanup = FS2500TGpioCleanup, +}; + +struct hwmon_sensor_list fs2500t_sensor_list = { + .thermal_sensor = &FS2500T_thermal_sensor, + .voltage_sensor = &FS2500T_voltage_sensor, + .fan_speed_rpm = &FS2500T_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &FS2500T_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs1221p.c b/drivers/syno/synobios/v1000/rs1221p.c new file mode 100644 index 000000000000..ed00052e9acd --- /dev/null +++ b/drivers/syno/synobios/v1000/rs1221p.c @@ -0,0 +1,161 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gRS1221pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS1221pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS1221pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS1221pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect =NULL; +} + +static +int RS1221pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs1221p = MODULE_T_RS1221p; + module_t *pType = &type_rs1221p; + + module_type_set(pType); + return 0; +} + +static +int RS1221pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS1221pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS1221pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS1221pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs1221p_ops = { + .x86_init_module_type = RS1221pInitModuleType, + .x86_fan_speed_mapping = RS1221pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS1221pGetBuzzerCleared, + .x86_gpio_init = RS1221pGpioInit, + .x86_gpio_cleanup = RS1221pGpioCleanup, +}; + +struct hwmon_sensor_list rs1221p_sensor_list = { + .thermal_sensor = &RS1221p_thermal_sensor, + .voltage_sensor = &RS1221p_voltage_sensor, + .fan_speed_rpm = &RS1221p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &RS1221p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs1221rp+.c b/drivers/syno/synobios/v1000/rs1221rp+.c new file mode 100644 index 000000000000..a039e37a5678 --- /dev/null +++ b/drivers/syno/synobios/v1000/rs1221rp+.c @@ -0,0 +1,174 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +extern int V1000RedundantPowerGetPowerStatus(POWER_INFO *power_info); + +PWM_FAN_SPEED_MAPPING gRS1221rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221rpp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221rpp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221rpp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1221rpp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS1221rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + + +// GPIO_84, GPIO_85 +static SYNO_GPIO_INFO redundant_power_detect = { + .nr_gpio = 2, + .gpio_port = {84, 85}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void RS1221rppGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.redundant_power_detect = &redundant_power_detect; +} + +static +void RS1221rppGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; + syno_gpio.redundant_power_detect = NULL; +} + +static +int RS1221rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_RS1221rpp = MODULE_T_RS1221rpp; + module_t *pType = &type_RS1221rpp; + + module_type_set(pType); + return 0; +} + +static +int RS1221rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS1221rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS1221rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS1221rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs1221rpp_ops = { + .x86_init_module_type = RS1221rppInitModuleType, + .x86_fan_speed_mapping = RS1221rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS1221rppGetBuzzerCleared, + .x86_gpio_init = RS1221rppGpioInit, + .x86_gpio_cleanup = RS1221rppGpioCleanup, + .x86_get_power_status = V1000RedundantPowerGetPowerStatus, +}; + +struct hwmon_sensor_list rs1221rpp_sensor_list = { + .thermal_sensor = &RS1221rpp_thermal_sensor, + .voltage_sensor = &RS1221rpp_voltage_sensor, + .fan_speed_rpm = &RS1221rpp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &RS1221rpp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs1623xsp.c b/drivers/syno/synobios/v1000/rs1623xsp.c new file mode 100644 index 000000000000..26f5bf8c236e --- /dev/null +++ b/drivers/syno/synobios/v1000/rs1623xsp.c @@ -0,0 +1,165 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +extern int V1000RedundantPowerGetPowerStatus(POWER_INFO *power_info); + +PWM_FAN_SPEED_MAPPING gRS1623xspSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1623xsp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1623xsp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1623xsp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS1623xsp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS1623xspGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_84, GPIO_85 +static SYNO_GPIO_INFO redundant_power_detect = { + .nr_gpio = 2, + .gpio_port = {84, 85}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS1623xspGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; + syno_gpio.redundant_power_detect = &redundant_power_detect; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS1623xspGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; + syno_gpio.redundant_power_detect = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS1623xspInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs1623xsp = MODULE_T_RS1623xsp; + module_t *pType = &type_rs1623xsp; + + module_type_set(pType); + return 0; +} + +static +int RS1623xspFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS1623xspSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS1623xspSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS1623xspSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs1623xsp_ops = { + .x86_init_module_type = RS1623xspInitModuleType, + .x86_fan_speed_mapping = RS1623xspFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS1623xspGetBuzzerCleared, + .x86_gpio_init = RS1623xspGpioInit, + .x86_gpio_cleanup = RS1623xspGpioCleanup, + .x86_get_power_status = V1000RedundantPowerGetPowerStatus, +}; + +struct hwmon_sensor_list rs1623xsp_sensor_list = { + .thermal_sensor = &RS1623xsp_thermal_sensor, + .voltage_sensor = &RS1623xsp_voltage_sensor, + .fan_speed_rpm = &RS1623xsp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &RS1623xsp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs2421p.c b/drivers/syno/synobios/v1000/rs2421p.c new file mode 100644 index 000000000000..47c66b76efbd --- /dev/null +++ b/drivers/syno/synobios/v1000/rs2421p.c @@ -0,0 +1,164 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gRS2421pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS2421pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS2421pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS2421pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect =NULL; +} + +static +int RS2421pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2421p = MODULE_T_RS2421p; + module_t *pType = &type_rs2421p; + + module_type_set(pType); + return 0; +} + +static +int RS2421pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2421pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2421pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2421pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2421p_ops = { + .x86_init_module_type = RS2421pInitModuleType, + .x86_fan_speed_mapping = RS2421pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS2421pGetBuzzerCleared, + .x86_gpio_init = RS2421pGpioInit, + .x86_gpio_cleanup = RS2421pGpioCleanup, +}; + +struct hwmon_sensor_list rs2421p_sensor_list = { + .thermal_sensor = &RS2421p_thermal_sensor, + .voltage_sensor = &RS2421p_voltage_sensor, + .fan_speed_rpm = &RS2421p_fan_speed_rpm, + .psu_status = NULL, //FIXME: should support psu + .hdd_backplane = &RS2421p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs2421rpp.c b/drivers/syno/synobios/v1000/rs2421rpp.c new file mode 100644 index 000000000000..7a36867b7d19 --- /dev/null +++ b/drivers/syno/synobios/v1000/rs2421rpp.c @@ -0,0 +1,206 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int V1000RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gRS2421rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421rpp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421rpp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421rpp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421rpp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2421rpp_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int RS2421rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS2421rppGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS2421rppGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS2421rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_RS2421rpp = MODULE_T_RS2421rpp; + module_t *pType = &type_RS2421rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2421rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2421rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2421rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2421rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2421rpp_ops = { + .x86_init_module_type = RS2421rppInitModuleType, + .x86_fan_speed_mapping = RS2421rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS2421rppGetBuzzerCleared, + .x86_gpio_init = RS2421rppGpioInit, + .x86_gpio_cleanup = RS2421rppGpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = V1000RedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list rs2421rpp_sensor_list = { + .thermal_sensor = &RS2421rpp_thermal_sensor, + .voltage_sensor = &RS2421rpp_voltage_sensor, + .fan_speed_rpm = &RS2421rpp_fan_speed_rpm, + .psu_status = RS2421rpp_psu_status, + .hdd_backplane = &RS2421rpp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs2423p.c b/drivers/syno/synobios/v1000/rs2423p.c new file mode 100644 index 000000000000..896977f40918 --- /dev/null +++ b/drivers/syno/synobios/v1000/rs2423p.c @@ -0,0 +1,156 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gRS2423pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS2423pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS2423pGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS2423pGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS2423pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs2423p = MODULE_T_RS2423p; + module_t *pType = &type_rs2423p; + + module_type_set(pType); + return 0; +} + +static +int RS2423pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2423pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2423pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2423pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2423p_ops = { + .x86_init_module_type = RS2423pInitModuleType, + .x86_fan_speed_mapping = RS2423pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS2423pGetBuzzerCleared, + .x86_gpio_init = RS2423pGpioInit, + .x86_gpio_cleanup = RS2423pGpioCleanup, +}; + +struct hwmon_sensor_list rs2423p_sensor_list = { + .thermal_sensor = &RS2423p_thermal_sensor, + .voltage_sensor = &RS2423p_voltage_sensor, + .fan_speed_rpm = &RS2423p_fan_speed_rpm, + .psu_status = NULL, //FIXME: should support psu + .hdd_backplane = &RS2423p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs2423rpp.c b/drivers/syno/synobios/v1000/rs2423rpp.c new file mode 100644 index 000000000000..a330f6d25daa --- /dev/null +++ b/drivers/syno/synobios/v1000/rs2423rpp.c @@ -0,0 +1,198 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int V1000RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gRS2423rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423rpp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423rpp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423rpp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423rpp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2423rpp_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int RS2423rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS2423rppGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS2423rppGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS2423rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_RS2423rpp = MODULE_T_RS2423rpp; + module_t *pType = &type_RS2423rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2423rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2423rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2423rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2423rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2423rpp_ops = { + .x86_init_module_type = RS2423rppInitModuleType, + .x86_fan_speed_mapping = RS2423rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS2423rppGetBuzzerCleared, + .x86_gpio_init = RS2423rppGpioInit, + .x86_gpio_cleanup = RS2423rppGpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = V1000RedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list rs2423rpp_sensor_list = { + .thermal_sensor = &RS2423rpp_thermal_sensor, + .voltage_sensor = &RS2423rpp_voltage_sensor, + .fan_speed_rpm = &RS2423rpp_fan_speed_rpm, + .psu_status = RS2423rpp_psu_status, + .hdd_backplane = &RS2423rpp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs2821rpp.c b/drivers/syno/synobios/v1000/rs2821rpp.c new file mode 100644 index 000000000000..9d2c0840816a --- /dev/null +++ b/drivers/syno/synobios/v1000/rs2821rpp.c @@ -0,0 +1,224 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int V1000RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gRS2821rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2821rpp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2821rpp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2821rpp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2821rpp_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 7, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_PIN, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP2, + }, + .sensor[4] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP3, + }, + .sensor[5] = { + .sensor_name = HWMON_PSU_SENSOR_FAN, + }, + .sensor[6] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS2821rpp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS2821rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS2821rppGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS2821rppGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS2821rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_RS2821rpp = MODULE_T_RS2821rpp; + module_t *pType = &type_RS2821rpp; + + module_type_set(pType); + return 0; +} + +static +int RS2821rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS2821rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS2821rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS2821rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs2821rpp_ops = { + .x86_init_module_type = RS2821rppInitModuleType, + .x86_fan_speed_mapping = RS2821rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS2821rppGetBuzzerCleared, + .x86_gpio_init = RS2821rppGpioInit, + .x86_gpio_cleanup = RS2821rppGpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = V1000RedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list rs2821rpp_sensor_list = { + .thermal_sensor = &RS2821rpp_thermal_sensor, + .voltage_sensor = &RS2821rpp_voltage_sensor, + .fan_speed_rpm = &RS2821rpp_fan_speed_rpm, + .psu_status = RS2821rpp_psu_status, + .hdd_backplane = &RS2821rpp_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs822p.c b/drivers/syno/synobios/v1000/rs822p.c new file mode 100644 index 000000000000..84e125f84d75 --- /dev/null +++ b/drivers/syno/synobios/v1000/rs822p.c @@ -0,0 +1,156 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +PWM_FAN_SPEED_MAPPING gRS822pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS822pGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_3 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {3}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void RS822pGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void RS822pGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int RS822pInitModuleType(struct synobios_ops *ops) +{ + module_t type_rs822p = MODULE_T_RS822p; + module_t *pType = &type_rs822p; + + module_type_set(pType); + return 0; +} + +static +int RS822pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS822pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS822pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS822pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs822p_ops = { + .x86_init_module_type = RS822pInitModuleType, + .x86_fan_speed_mapping = RS822pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS822pGetBuzzerCleared, + .x86_gpio_init = RS822pGpioInit, + .x86_gpio_cleanup = RS822pGpioCleanup, +}; + +struct hwmon_sensor_list rs822p_sensor_list = { + .thermal_sensor = &RS822p_thermal_sensor, + .voltage_sensor = &RS822p_voltage_sensor, + .fan_speed_rpm = &RS822p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &RS822p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/rs822rpp.c b/drivers/syno/synobios/v1000/rs822rpp.c new file mode 100644 index 000000000000..cd0c207f29fa --- /dev/null +++ b/drivers/syno/synobios/v1000/rs822rpp.c @@ -0,0 +1,183 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +extern int V1000RedundantPowerGetPowerStatus(POWER_INFO *power_info); + +#define FAN_NUM 2 + +PWM_FAN_SPEED_MAPPING gRS822rppSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822rpp_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822rpp_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE RS822rpp_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = FAN_NUM, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_FAN_ORDER rs822rpp_fan_order_list = { + .fan_num = FAN_NUM, + .fan_order_list = {1,2}, +}; + +SYNO_HWMON_SENSOR_TYPE RS822rpp_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +int RS822rppGetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_3 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {3}, + .gpio_polarity = ACTIVE_LOW, +}; + + +// GPIO_91, GPIO_68 +static SYNO_GPIO_INFO redundant_power_detect = { + .nr_gpio = 2, + .gpio_port = {91, 68}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_86 +static SYNO_GPIO_INFO redundant_power_fan_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void RS822rppGpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; + syno_gpio.redundant_power_detect = &redundant_power_detect; + syno_gpio.redundant_power_fan_ctrl = &redundant_power_fan_ctrl; +} + +static +void RS822rppGpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; + syno_gpio.redundant_power_detect = NULL; + syno_gpio.redundant_power_fan_ctrl = NULL; +} + +static +int RS822rppInitModuleType(struct synobios_ops *ops) +{ + module_t type_RS822rpp = MODULE_T_RS822rpp; + module_t *pType = &type_RS822rpp; + + module_type_set(pType); + return 0; +} + +static +int RS822rppFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gRS822rppSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gRS822rppSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gRS822rppSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops rs822rpp_ops = { + .x86_init_module_type = RS822rppInitModuleType, + .x86_fan_speed_mapping = RS822rppFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = RS822rppGetBuzzerCleared, + .x86_gpio_init = RS822rppGpioInit, + .x86_gpio_cleanup = RS822rppGpioCleanup, + .x86_get_power_status = V1000RedundantPowerGetPowerStatus, +}; + +struct hwmon_sensor_list rs822rpp_sensor_list = { + .thermal_sensor = &RS822rpp_thermal_sensor, + .voltage_sensor = &RS822rpp_voltage_sensor, + .fan_speed_rpm = &RS822rpp_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &RS822rpp_hdd_backplane_status, +}; + + diff --git a/drivers/syno/synobios/v1000/sc2500.c b/drivers/syno/synobios/v1000/sc2500.c new file mode 100644 index 000000000000..f83d9e80a249 --- /dev/null +++ b/drivers/syno/synobios/v1000/sc2500.c @@ -0,0 +1,198 @@ +// Copyright (c) 2000-2021 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000_common.h" + +#ifdef CONFIG_SYNO_HWMON_PMBUS +extern int V1000RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info); +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +PWM_FAN_SPEED_MAPPING gSC2500SpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE SC2500_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC2500_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC2500_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, + .sensor[2] = { + .sensor_name = HWMON_SYS_FAN3_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC2500_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +SYNO_HWMON_SENSOR_TYPE SC2500_psu_status[] = { + { + .type_name = HWMON_PSU1_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1 + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, + { + .type_name = HWMON_PSU2_STATUS_NAME, + .sensor_num = 4, + .sensor[0] = { + .sensor_name = HWMON_PSU_SENSOR_POUT, + }, + .sensor[1] = { + .sensor_name = HWMON_PSU_SENSOR_TEMP1, + }, + .sensor[2] = { + .sensor_name = HWMON_PSU_SENSOR_FAN_VOLT, + }, + .sensor[3] = { + .sensor_name = HWMON_PSU_SENSOR_STATUS, + }, + }, +}; + +int SC2500GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + return SYNO_BUZZER_BUTTON_GPIO_GET(buzzer_cleared); +} + +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +// GPIO_69 +static SYNO_GPIO_INFO mute_button_detect = { + .nr_gpio = 1, + .gpio_port = {69}, + .gpio_polarity = ACTIVE_LOW, +}; + +static +void SC2500GpioInit(void) +{ + syno_gpio.alarm_led = &alarm_led; + syno_gpio.mute_button_detect = &mute_button_detect; +} + +static +void SC2500GpioCleanup(void) +{ + syno_gpio.alarm_led = NULL; + syno_gpio.mute_button_detect = NULL; +} + +static +int SC2500InitModuleType(struct synobios_ops *ops) +{ + module_t type_SC2500 = MODULE_T_SC2500; + module_t *pType = &type_SC2500; + + module_type_set(pType); + return 0; +} + +static +int SC2500FanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gSC2500SpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gSC2500SpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gSC2500SpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops sc2500_ops = { + .x86_init_module_type = SC2500InitModuleType, + .x86_fan_speed_mapping = SC2500FanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = SC2500GetBuzzerCleared, + .x86_gpio_init = SC2500GpioInit, + .x86_gpio_cleanup = SC2500GpioCleanup, +#ifdef CONFIG_SYNO_HWMON_PMBUS + .x86_get_power_status = V1000RedundantPowerGetPowerStatusByI2C, +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +}; + +struct hwmon_sensor_list sc2500_sensor_list = { + .thermal_sensor = &SC2500_thermal_sensor, + .voltage_sensor = &SC2500_voltage_sensor, + .fan_speed_rpm = &SC2500_fan_speed_rpm, + .psu_status = SC2500_psu_status, + .hdd_backplane = &SC2500_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000/v1000_common.c b/drivers/syno/synobios/v1000/v1000_common.c new file mode 100755 index 000000000000..4250eedb86a7 --- /dev/null +++ b/drivers/syno/synobios/v1000/v1000_common.c @@ -0,0 +1,1216 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_HWMON_PMBUS +#include +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "../pmbus/pmbus.h" + +#include "v1000_common.h" + +#define GPIO_POWER_GOOD 1 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static SYNO_HWMON_FAN_ORDER *hwmon_fan_order_list = NULL; +//static int *hdd_enable = NULL; +//static int *hdd_detect = NULL; + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strcmp(gszSynoHWVersion, HW_DS1621p) ) { + model = MODEL_DS1621p; + } else if ( !strcmp(gszSynoHWVersion, HW_RS1221p) ) { + model = MODEL_RS1221p; + } else if ( !strcmp(gszSynoHWVersion, HW_RS1221rpp) ) { + model = MODEL_RS1221rpp; + } else if ( !strcmp(gszSynoHWVersion, HW_DS1821p) ) { + model = MODEL_DS1821p; + } else if ( !strcmp(gszSynoHWVersion, HW_DS2422p) ) { + model = MODEL_DS2422p; + } else if ( !strcmp(gszSynoHWVersion, HW_RS2421p) ) { + model = MODEL_RS2421p; + } else if ( !strcmp(gszSynoHWVersion, HW_RS2421rpp) ) { + model = MODEL_RS2421rpp; + } else if ( !strcmp(gszSynoHWVersion, HW_RS2821rpp) ) { + model = MODEL_RS2821rpp; + } else if ( !strcmp(gszSynoHWVersion, HW_FS2500) ) { + model = MODEL_FS2500; + } else if ( !strcmp(gszSynoHWVersion, HW_FS2500T) ) { + model = MODEL_FS2500T; + } else if ( !strcmp(gszSynoHWVersion, HW_RS822p) ) { + model = MODEL_RS822p; + } else if ( !strcmp(gszSynoHWVersion, HW_RS822rpp) ) { + model = MODEL_RS822rpp; + } else if ( !strcmp(gszSynoHWVersion, HW_RS2423p) ) { + model = MODEL_RS2423p; + } else if ( !strcmp(gszSynoHWVersion, HW_RS2423rpp) ) { + model = MODEL_RS2423rpp; + } else if ( !strcmp(gszSynoHWVersion, HW_DS1823xsp) ) { + model = MODEL_DS1823xsp; + } else if ( !strcmp(gszSynoHWVersion, HW_RS1623xsp) ) { + model = MODEL_RS1623xsp; + } else if ( !strcmp(gszSynoHWVersion, HW_DS1623p) ) { + model = MODEL_DS1623p; + } else if ( !strcmp(gszSynoHWVersion, HW_DS1823p) ) { + model = MODEL_DS1823p; + } else if ( !strcmp(gszSynoHWVersion, HW_SC2500) ) { + model = MODEL_SC2500; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_DS1621p: + case MODEL_DS1623p: + iInternalDiskNum = 6; + break; + case MODEL_RS1221p: + case MODEL_RS1221rpp: + case MODEL_DS1821p: + case MODEL_DS1823xsp: + case MODEL_DS1823p: + iInternalDiskNum = 8; + break; + case MODEL_DS2422p: + case MODEL_RS2421p: + case MODEL_RS2421rpp: + case MODEL_FS2500: + case MODEL_FS2500T: + case MODEL_RS2423p: + case MODEL_RS2423rpp: + case MODEL_SC2500: + iInternalDiskNum = 12; + break; + case MODEL_RS2821rpp: + iInternalDiskNum = 16; + break; + case MODEL_RS822p: + case MODEL_RS822rpp: + case MODEL_RS1623xsp: + iInternalDiskNum = 4; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) + iRet = syno_k10cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +END: + return iRet; +} + + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +static int SetHddActLedBoth(SYNO_LED ledStatus) +{ + // set GPIO + SetHddActLed(ledStatus); + + // set led trigger through i2c + return SetHddActLedByLedTrigger(ledStatus); +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +static +int SetRedundantPowerFanFullSpeed(unsigned char type) +{ + int iFullSpeed = 0; + + if (type) { + iFullSpeed = 1; + } + return SYNO_CTRL_RP_FAN(iFullSpeed); +} + +#ifdef CONFIG_SYNO_ADT7490_FEATURES +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADTByOrder(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list || NULL == hwmon_fan_order_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm_by_order(FanSpeedRpm, hwmon_fan_order_list); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +int HWMONGetHDDBackPlaneStatusByGPIO(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 1; + int iInternalDiskNum = -1; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iInternalDiskNum = GetMaxInternalDiskNum(); + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_DETECT(index)) { + hdd_detect |= ((SYNO_GPIO_READ(HDD_DETECT_PIN(index)) ^ HDD_DETECT_POLARITY(index)) & 0x01) << (index-1); + } + } + + for (index = 1; index <= iInternalDiskNum; index++) { + if (HAVE_HDD_ENABLE(index)) { + hdd_enable |= ((SYNO_GPIO_READ(HDD_ENABLE_PIN(index)) ^ HDD_ENABLE_POLARITY(index)) & 0x01) << (index-1); + } + } + + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[1].value), "%ld", hdd_enable); + + iRet = 0; + +End: + return iRet; +} + +int V1000RedundantPowerGetPowerStatus(POWER_INFO *power_info) +{ + GPIO_PIN pinPower1; + GPIO_PIN pinPower2; + int err = -1; + + pinPower1.pin = syno_gpio.redundant_power_detect->gpio_port[0]; + pinPower2.pin = syno_gpio.redundant_power_detect->gpio_port[1]; + if (0 > GetGpioPin(&pinPower1) || 0 > GetGpioPin(&pinPower2)) { + goto END; + } + + + if (pinPower1.value == GPIO_POWER_GOOD) { + power_info->power_1 = POWER_STATUS_GOOD; + } else { + power_info->power_1 = POWER_STATUS_BAD; + } + + if (pinPower2.value == GPIO_POWER_GOOD) { + power_info->power_2 = POWER_STATUS_GOOD; + } else { + power_info->power_2 = POWER_STATUS_BAD; + } + + err = 0; + +END: + return err; +} + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int V1000RedundantPowerGetPowerStatusByI2C(POWER_INFO *power_info) +{ + int iRet = -1; + + if (NULL == power_info) { + printk("%s:%d in %s: parameters error!\n", __FILE__, __LINE__, __FUNCTION__); + goto END; + } + + if (0 > I2CPmbusReadPowerStatus(0, &(power_info->power_1))) { + goto END; + } + if (0 > I2CPmbusReadPowerStatus(1, &(power_info->power_2))) { + goto END; + } + + iRet = 0; + +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, + .set_rp_fan = NULL, +}; + +#ifdef CONFIG_SYNO_HWMON_PMBUS +int V1000GetPSUStatusByI2C(SYNO_HWMON_SENSOR_TYPE *psu_status, int iPsuNumber) +{ + int iRet = -1; + + if (NULL == hwmon_sensor_list) { + goto END; + } + memcpy(psu_status, hwmon_sensor_list->psu_status, + iPsuNumber * sizeof(SYNO_HWMON_SENSOR_TYPE)); + iRet = HWMONGetPSUStatusByI2C(psu_status, iPsuNumber); +END: + return iRet; +} +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + int i = 0; + DISKLEDSTATUS diskLedStatus; + const char* abbrName[] = {"internal", "sys"}; + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_DS1621p: + model_ops = &ds1621p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1621p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS1221p: + model_ops = &rs1221p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs1221p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS1221rpp: + model_ops = &rs1221rpp_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs1221rpp_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DS1821p: + model_ops = &ds1821p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1821p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DS2422p: + model_ops = &ds2422p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds2422p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#if defined(CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL) + //wait jmb585 initialization then close orange light of all disks + syno_jmb585_led_wait(); + synobios_ops.set_disk_led = SetDiskLedStatusByJMB585GPIOByPort; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + for (i = 1; i <= 12; i++) { + diskLedStatus.diskno = i; + SetDiskLedStatusByJMB585GPIOByPort(&diskLedStatus); + } +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByJMB585GPIOByPort; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL || CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL */ + break; + case MODEL_RS2421p: + model_ops = &rs2421p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs2421p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#if defined (CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL) + synobios_ops.set_disk_led = SetDiskLedStatusByASM116XGPIOByPort; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + for (i = 1; i <= 12; i++) { + diskLedStatus.diskno = i; + SetDiskLedStatusByASM116XGPIOByPort(&diskLedStatus); + } +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByASM116XGPIOByPort; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL || CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL */ + break; + case MODEL_RS2421rpp: + model_ops = &rs2421rpp_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs2421rpp_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = V1000GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#if defined (CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL) + synobios_ops.set_disk_led = SetDiskLedStatusByASM116XGPIOByPort; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + for (i = 1; i <= 12; i++) { + diskLedStatus.diskno = i; + SetDiskLedStatusByASM116XGPIOByPort(&diskLedStatus); + } +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByASM116XGPIOByPort; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_ASM_116X_GPIO_LED_CTRL || CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL */ + break; + case MODEL_RS2821rpp: + model_ops = &rs2821rpp_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs2821rpp_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = V1000GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#if defined(CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL) || defined(CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL) + //wait jmb585 initialization then close orange light of all disks + syno_jmb585_led_wait(); + synobios_ops.set_disk_led = SetDiskLedStatusByJMB585GPIOByPort; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; + for (i = 1; i <= 16; i++) { + diskLedStatus.diskno = i; + SetDiskLedStatusByJMB585GPIOByPort(&diskLedStatus); + } +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByJMB585GPIOByPort; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif /* CONFIG_SYNO_JMICRON_585_GPIO_LED_CTRL || CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL */ + break; + case MODEL_FS2500: + model_ops = &fs2500_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs2500_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL + synobios_ops.set_disk_led = SYNODiskLedCtrlBy1475SGPIO; +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + break; + case MODEL_FS2500T: + model_ops = &fs2500t_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &fs2500t_sensor_list; + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; + diskLedStatus.szNodeName = abbrName[0]; + diskLedStatus.iNodeNameLen = strlen("internal"); + diskLedStatus.status = 0; +#ifdef CONFIG_SYNO_MV1475_SGPIO_LED_CTRL + synobios_ops.set_disk_led = SYNODiskLedCtrlBy1475SGPIO; +#endif /* CONFIG_SYNO_MV1475_SGPIO_LED_CTRL */ + break; + case MODEL_RS822p: + model_ops = &rs822p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs822p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS822rpp: + model_ops = &rs822rpp_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs822rpp_sensor_list; + hwmon_fan_order_list = &rs822rpp_fan_order_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADTByOrder; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; + synobios_ops.set_rp_fan = SetRedundantPowerFanFullSpeed; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS2423p: + model_ops = &rs2423p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs2423p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + for (i = 1; i <= 12; i++) { + syno_ahci_disk_led_enable_by_port(i, 1); + } +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_RS2423rpp: + model_ops = &rs2423rpp_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs2423rpp_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = V1000GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + for (i = 1; i <= 12; i++) { + syno_ahci_disk_led_enable_by_port(i, 1); + } +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_DS1823xsp: + model_ops = &ds1823xsp_ops; + + I2cBusChange(0); + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1823xsp_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLedBoth; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_RS1623xsp: + model_ops = &rs1623xsp_ops; + + I2cBusChange(0); + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &rs1623xsp_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusByGPIO; + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_DS1623p: + model_ops = &ds1623p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1623p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLedBoth; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_DS1823p: + model_ops = &ds1823p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1823p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLedBoth; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + case MODEL_SC2500: + model_ops = &sc2500_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &sc2500_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ +#ifdef CONFIG_SYNO_HWMON_PMBUS + synobios_ops.hwmon_get_psu_status = V1000GetPSUStatusByI2C; +#endif /* CONFIG_SYNO_HWMON_PMBUS */ + synobios_ops.set_hdd_led = SetHddActLedByLedTrigger; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + for (i = 1; i <= 12; i++) { + syno_ahci_disk_led_enable_by_port(i, 1); + } +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/v1000/v1000_common.h b/drivers/syno/synobios/v1000/v1000_common.h new file mode 100755 index 000000000000..b1cb7b412094 --- /dev/null +++ b/drivers/syno/synobios/v1000/v1000_common.h @@ -0,0 +1,112 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" +#include "../led/led_jmb585.h" +#include "../led/led_asm116x.h" +#include "../led/led_1475.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds1621p_ops; +extern struct model_ops rs1221p_ops; +extern struct model_ops rs1221rpp_ops; +extern struct model_ops ds1821p_ops; +extern struct model_ops ds2422p_ops; +extern struct model_ops rs2421p_ops; +extern struct model_ops rs2421rpp_ops; +extern struct model_ops rs2821rpp_ops; +extern struct model_ops fs2500_ops; +extern struct model_ops fs2500t_ops; +extern struct model_ops rs822p_ops; +extern struct model_ops rs822rpp_ops; +extern struct model_ops rs2423p_ops; +extern struct model_ops rs2423rpp_ops; +extern struct model_ops ds1823xsp_ops; +extern struct model_ops rs1623xsp_ops; +extern struct model_ops ds1623p_ops; +extern struct model_ops ds1823p_ops; +extern struct model_ops sc2500_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_fan_speed_rpm_by_order(SYNO_HWMON_SENSOR_TYPE *, SYNO_HWMON_FAN_ORDER *); +extern struct hwmon_sensor_list ds1621p_sensor_list; +extern struct hwmon_sensor_list rs1221p_sensor_list; +extern struct hwmon_sensor_list rs1221rpp_sensor_list; +extern struct hwmon_sensor_list ds1821p_sensor_list; +extern struct hwmon_sensor_list ds2422p_sensor_list; +extern struct hwmon_sensor_list rs2421p_sensor_list; +extern struct hwmon_sensor_list rs2421rpp_sensor_list; +extern struct hwmon_sensor_list rs2821rpp_sensor_list; +extern struct hwmon_sensor_list fs2500_sensor_list; +extern struct hwmon_sensor_list fs2500t_sensor_list; +extern struct hwmon_sensor_list rs822p_sensor_list; +extern struct hwmon_sensor_list rs822rpp_sensor_list; +extern struct hwmon_sensor_list rs2423p_sensor_list; +extern struct hwmon_sensor_list rs2423rpp_sensor_list; +extern struct hwmon_sensor_list ds1823xsp_sensor_list; +extern struct hwmon_sensor_list rs1623xsp_sensor_list; +extern struct hwmon_sensor_list ds1623p_sensor_list; +extern struct hwmon_sensor_list ds1823p_sensor_list; +extern struct hwmon_sensor_list sc2500_sensor_list; + +extern SYNO_HWMON_FAN_ORDER rs822rpp_fan_order_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) +extern int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/syno/synobios/v1000sofs/Makefile b/drivers/syno/synobios/v1000sofs/Makefile new file mode 100644 index 000000000000..2132bb125f4f --- /dev/null +++ b/drivers/syno/synobios/v1000sofs/Makefile @@ -0,0 +1,22 @@ +include /env.mak + +obj-m += v1000sofs-synobios.o + +v1000sofs-synobios-objs = \ + ../common/common.o \ + ../syno_ttyS/syno_ttyS.o \ + ../synobios.o \ + ds1621p.o \ + ds1821p.o \ + ../mapping.o \ + ../rtc/localtime.o \ + ../rtc/alarmtime.o \ + ../rtc/rtc-seiko-lib.o \ + ../rtc/rtc-linux-seiko.o \ + ../i2c/i2c-linux.o \ + v1000sofs_common.o \ + ../led/led_trigger.o \ + ../led/led_jmb585.o \ + ../led/led_asm116x.o \ + ../led/led_1475.o \ + ../pmbus/pmbus.o diff --git a/drivers/syno/synobios/v1000sofs/ds1621p.c b/drivers/syno/synobios/v1000sofs/ds1621p.c new file mode 100644 index 000000000000..aa222c166024 --- /dev/null +++ b/drivers/syno/synobios/v1000sofs/ds1621p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000sofs_common.h" + +PWM_FAN_SPEED_MAPPING gDS1621pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1621p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1621pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1621pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1621pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1621p = MODULE_T_DS1621p; + module_t *pType = &type_1621p; + + module_type_set(pType); + return 0; +} + +static +int DS1621pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1621pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1621pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1621pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1621p_ops = { + .x86_init_module_type = DS1621pInitModuleType, + .x86_fan_speed_mapping = DS1621pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1621pGpioInit, + .x86_gpio_cleanup = DS1621pGpioCleanup, +}; + +struct hwmon_sensor_list ds1621p_sensor_list = { + .thermal_sensor = &DS1621p_thermal_sensor, + .voltage_sensor = &DS1621p_voltage_sensor, + .fan_speed_rpm = &DS1621p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1621p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000sofs/ds1821p.c b/drivers/syno/synobios/v1000sofs/ds1821p.c new file mode 100644 index 000000000000..ff6839de56a7 --- /dev/null +++ b/drivers/syno/synobios/v1000sofs/ds1821p.c @@ -0,0 +1,147 @@ +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +#include /* printk() */ +#include /* error codes */ +#include +#include +#include "v1000sofs_common.h" + +PWM_FAN_SPEED_MAPPING gDS1821pSpeedMapping[] = { + { .fanSpeed = FAN_SPEED_STOP, .iDutyCycle = 0 }, + { .fanSpeed = FAN_SPEED_ULTRA_LOW, .iDutyCycle = 15 }, + { .fanSpeed = FAN_SPEED_VERY_LOW, .iDutyCycle = 20 }, + { .fanSpeed = FAN_SPEED_LOW, .iDutyCycle = 25 }, + { .fanSpeed = FAN_SPEED_MIDDLE, .iDutyCycle = 35 }, + { .fanSpeed = FAN_SPEED_HIGH, .iDutyCycle = 45 }, + { .fanSpeed = FAN_SPEED_VERY_HIGH, .iDutyCycle = 55 }, + { .fanSpeed = FAN_SPEED_ULTRA_HIGH, .iDutyCycle = 65 }, + { .fanSpeed = FAN_SPEED_FULL, .iDutyCycle = 99 }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_thermal_sensor = { + .type_name = HWMON_SYS_THERMAL_NAME, + .sensor_num = 3, + .sensor[0] = { + .sensor_name = "Remote1", + }, + .sensor[1] = { + .sensor_name = "Local", + }, + .sensor[2] = { + .sensor_name = "Remote2", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_voltage_sensor = { + .type_name = HWMON_SYS_VOLTAGE_NAME, + .sensor_num = 5, + .sensor[0] = { + .sensor_name = "VCC", + }, + .sensor[1] = { + .sensor_name = "VPP", + }, + .sensor[2] = { + .sensor_name = "V33", + }, + .sensor[3] = { + .sensor_name = "V5", + }, + .sensor[4] = { + .sensor_name = "V12", + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_fan_speed_rpm = { + .type_name = HWMON_SYS_FAN_RPM_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_SYS_FAN1_RPM, + }, + .sensor[1] = { + .sensor_name = HWMON_SYS_FAN2_RPM, + }, +}; + +SYNO_HWMON_SENSOR_TYPE DS1821p_hdd_backplane_status = { + .type_name = HWMON_HDD_BP_STATUS_NAME, + .sensor_num = 2, + .sensor[0] = { + .sensor_name = HWMON_HDD_BP_DETECT, + }, + .sensor[1] = { + .sensor_name = HWMON_HDD_BP_ENABLE, + }, +}; + +// GPIO_86 +static SYNO_GPIO_INFO disk_led_ctrl = { + .nr_gpio = 1, + .gpio_port = {86}, + .gpio_polarity = ACTIVE_HIGH, +}; +// GPIO_89 +static SYNO_GPIO_INFO alarm_led = { + .nr_gpio = 1, + .gpio_port = {89}, + .gpio_polarity = ACTIVE_HIGH, +}; + +static +void DS1821pGpioInit(void) +{ + syno_gpio.disk_led_ctrl = &disk_led_ctrl; + syno_gpio.alarm_led = &alarm_led; +} + +static +void DS1821pGpioCleanup(void) +{ + syno_gpio.disk_led_ctrl = NULL; + syno_gpio.alarm_led = NULL; +} + +static +int DS1821pInitModuleType(struct synobios_ops *ops) +{ + module_t type_1821p = MODULE_T_DS1821p; + module_t *pType = &type_1821p; + + module_type_set(pType); + return 0; +} + +static +int DS1821pFanSpeedMapping(FAN_SPEED speed) +{ + int iDutyCycle = -1; + size_t i; + + for( i = 0; i < sizeof(gDS1821pSpeedMapping)/sizeof(PWM_FAN_SPEED_MAPPING); ++i ) { + if( gDS1821pSpeedMapping[i].fanSpeed == speed ) { + iDutyCycle = gDS1821pSpeedMapping[i].iDutyCycle; + break; + } + } + + return iDutyCycle; +} + +struct model_ops ds1821p_ops = { + .x86_init_module_type = DS1821pInitModuleType, + .x86_fan_speed_mapping = DS1821pFanSpeedMapping, + .x86_set_esata_led_status = NULL, /* no esata led */ + .x86_cpufan_speed_mapping = NULL, /* no cpu fan */ + .x86_get_buzzer_cleared = NULL, /* no mute button */ + .x86_gpio_init = DS1821pGpioInit, + .x86_gpio_cleanup = DS1821pGpioCleanup, +}; + +struct hwmon_sensor_list ds1821p_sensor_list = { + .thermal_sensor = &DS1821p_thermal_sensor, + .voltage_sensor = &DS1821p_voltage_sensor, + .fan_speed_rpm = &DS1821p_fan_speed_rpm, + .psu_status = NULL, + .hdd_backplane = &DS1821p_hdd_backplane_status, +}; + diff --git a/drivers/syno/synobios/v1000sofs/v1000sofs_common.c b/drivers/syno/synobios/v1000sofs/v1000sofs_common.c new file mode 100755 index 000000000000..84069afb58c0 --- /dev/null +++ b/drivers/syno/synobios/v1000sofs/v1000sofs_common.c @@ -0,0 +1,468 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2019 Synology Inc. All rights reserved. + +#include +#include +#include /* printk() */ +#include /* error codes */ +#include +#include "synobios.h" +#include +#include +#include +#ifdef CONFIG_SYNO_HWMON_PMBUS +#include +#endif /* CONFIG_SYNO_HWMON_PMBUS */ +#include "../rtc/rtc.h" +#include "../i2c/i2c-linux.h" +#include "../pmbus/pmbus.h" + +#include "v1000sofs_common.h" + +#define GPIO_POWER_GOOD 1 + +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) +extern int (*funcSYNOSATADiskLedCtrl)(int iHostNum, SYNO_DISK_LED diskLed); +#endif /* MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL */ + +static int Uninitialize(void); +static struct model_ops *model_ops = NULL; +static struct hwmon_sensor_list *hwmon_sensor_list = NULL; +static SYNO_HWMON_FAN_ORDER *hwmon_fan_order_list = NULL; +//static int *hdd_enable = NULL; +//static int *hdd_detect = NULL; + +static +int SetFanStatusMircopWithGPIO(FAN_STATUS status, FAN_SPEED speed) +{ + int iRet = -1; + int iFanDuty = -1; + char szUartCmd[5] = {0}; + + if( status == FAN_STATUS_STOP ) { + speed = FAN_SPEED_STOP; + } + + if( FAN_SPEED_PWM_FORMAT_SHIFT <= (int)speed ) { + /* PWM format is only for bandon and QC test */ + iFanDuty = FAN_SPEED_SHIFT_DUTY_GET((int)speed); + /* set fan speed hz */ + if(0 < FAN_SPEED_SHIFT_HZ_GET((int)speed)) { + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_FREQUENCY, FAN_SPEED_SHIFT_HZ_GET((int)speed)); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + } + } else { + if( 0 > (iFanDuty = model_ops->x86_fan_speed_mapping(speed)) ) { + printk("No matched fan speed!\n"); + goto END; + } + } + + /* set fan speed duty cycle */ + snprintf(szUartCmd, sizeof(szUartCmd), "%s%02d", SZ_UART_FAN_DUTY_CYCLE, iFanDuty); + if( 0 > SetUart(szUartCmd) ) { + goto END; + } + + iRet = 0; +END: + return iRet; +} + +int GetModel(void) +{ + int model = MODEL_INVALID; + + if ( !strcmp(gszSynoHWVersion, HW_DS1621p) ) { + model = MODEL_DS1621p; + } else if ( !strcmp(gszSynoHWVersion, HW_DS1821p) ) { + model = MODEL_DS1821p; + } + + return model; +} + +int GetMaxInternalDiskNum(void) +{ + int iInternalDiskNum = -1; + switch(GetModel()) { + case MODEL_DS1621p: + iInternalDiskNum = 6; + break; + case MODEL_DS1821p: + iInternalDiskNum = 8; + break; + default: + printk(KERN_INFO "synobios cannot find internal disk number.\n"); + break; + } + return iInternalDiskNum; +} + +static +int InitModuleType(struct synobios_ops *ops) +{ + int iRet = -1; + + if (model_ops && model_ops->x86_init_module_type) { + iRet = model_ops->x86_init_module_type(ops); + } + + return iRet; +} + +static +int GetCpuTemperature(struct _SynoCpuTemp *pCpuTemp) +{ + int iRet = -1; + + if (NULL == pCpuTemp) { + goto END; + } +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) + iRet = syno_k10cpu_temperature(pCpuTemp); +#endif /* CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +END: + return iRet; +} + + +static +int SetAlarmLed(unsigned char type) +{ + int iBlinking = 0; + + if (type) { + iBlinking = 1; + } + return SYNO_CTRL_ALARM_LED_SET(iBlinking); +} + +static +int GetBuzzerCleared(unsigned char *buzzer_cleared) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_buzzer_cleared) { + ret = model_ops->x86_get_buzzer_cleared(buzzer_cleared); + } + + return ret; +} + +static int GetPowerStatus(POWER_INFO *power_info) +{ + int ret = 0; + + if (model_ops && model_ops->x86_get_power_status) { + ret = model_ops->x86_get_power_status(power_info); + }else{ + ret = -1; + } + + return ret; +} + +static int SetHddActLed(SYNO_LED ledStatus) +{ + if (SYNO_LED_OFF == ledStatus) { + SYNO_ENABLE_HDD_LED(0); + } else { + SYNO_ENABLE_HDD_LED(1); + } + + return 0; +} + +static int SetPowerLedStatus(SYNO_LED ledStatus) +{ + char szCommand[5] = {0}; + int iError = -1; + + switch(ledStatus){ + case SYNO_LED_ON: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_ON); + break; + case SYNO_LED_OFF: + snprintf(szCommand, sizeof(szCommand), "%s", SZ_UART_PWR_LED_OFF); + break; + default: + goto ERR; + } + + if (0 > SetUart(szCommand)) { + goto ERR; + } + + iError = 0; +ERR: + return iError; +} + +void GetCPUInfo(SYNO_CPU_INFO *cpu, const unsigned int maxLength) +{ + unsigned int freq = cpufreq_quick_get(0); + + if (!freq) + freq = cpu_khz; + + snprintf(cpu->clock, sizeof(char) * maxLength, "%u.%3u", freq / 1000, freq % 1000); + + cpu->core = cpu_data(0).booted_cores; + +} + +#ifdef CONFIG_SYNO_ADT7490_FEATURES +static +int HWMONGetThermalSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int iRet = -1; + + if (NULL == SysThermal || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysThermal, hwmon_sensor_list->thermal_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_thermal_sensor(SysThermal); + +END: + return iRet; +} + +static +int HWMONGetFanSpeedRPMFromADT(SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int iRet = -1; + + if (NULL == FanSpeedRpm || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(FanSpeedRpm, hwmon_sensor_list->fan_speed_rpm, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_fan_speed_rpm(FanSpeedRpm); + +END: + return iRet; +} + +static +int HWMONGetVoltageSensorFromADT(SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int iRet = -1; + + if (NULL == SysVoltage || NULL == hwmon_sensor_list) { + goto END; + } + + memcpy(SysVoltage, hwmon_sensor_list->voltage_sensor, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + iRet = syno_get_adt_voltage_sensor(SysVoltage); + +END: + return iRet; +} +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern void syno_smbus_hdd_powerctl_init(void); +static +int HWMONGetHDDBackPlaneStatusBySMBUS(struct _SYNO_HWMON_SENSOR_TYPE *hdd_backplane) +{ + int iRet = -1; + int index = 0; + int val = 0; + unsigned long hdd_detect = 0; + unsigned long hdd_enable = 0; + + if (NULL == hdd_backplane || NULL == hwmon_sensor_list) { + printk("hdd_backplane null\n"); + goto End; + } + if (0 >= g_smbus_hdd_powerctl) { + goto End; + } + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + memcpy(hdd_backplane, hwmon_sensor_list->hdd_backplane, sizeof(SYNO_HWMON_SENSOR_TYPE)); + + for (index = 0; index < GetMaxInternalDiskNum(); index++){ + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_detect |= (val & 0x01) << index; + } + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + val = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index+1); + hdd_enable |= (val & 0x01) << index; + } + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + snprintf(hdd_backplane->sensor[0].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_detect); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + snprintf(hdd_backplane->sensor[1].value, sizeof(hdd_backplane->sensor[0].value), "%ld", hdd_enable); + } + + iRet = 0; +End: + return iRet; +} +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +static struct synobios_ops synobios_ops = { + .owner = THIS_MODULE, + .get_brand = GetBrand, + .get_model = GetModel, + .get_rtc_time = rtc_seiko_get_time, + .set_rtc_time = rtc_seiko_set_time, + .get_auto_poweron = rtc_get_auto_poweron, + .set_auto_poweron = rtc_seiko_set_auto_poweron, + .init_auto_poweron = rtc_seiko_auto_poweron_init, + .uninit_auto_poweron = rtc_seiko_auto_poweron_uninit, + .get_fan_status = GetFanStatusActivePulse, + .set_fan_status = SetFanStatusMircopWithGPIO, + .get_sys_temperature = NULL, + .get_cpu_temperature = GetCpuTemperature, + .set_cpu_fan_status = NULL, + .get_gpio_pin = GetGpioPin, + .set_gpio_pin = SetGpioPin, + .set_disk_led = NULL, + .set_alarm_led = SetAlarmLed, + .module_type_init = InitModuleType, + .get_buzzer_cleared = GetBuzzerCleared, + .get_power_status = GetPowerStatus, + .uninitialize = Uninitialize, + .get_cpu_info = GetCPUInfo, + .set_aha_led = NULL, + .get_copy_button_status = NULL, // for matching userspace usage, button pressed = 0, else = 1 + .hwmon_get_fan_speed_rpm = NULL, + .hwmon_get_sys_thermal = NULL, + .hwmon_get_sys_voltage = NULL, + .hwmon_get_psu_status = NULL, + .hwmon_get_backplane_status = NULL, + .set_rp_fan = NULL, +}; + +int synobios_model_init(struct file_operations *fops, struct synobios_ops **ops) +{ + int i = 0; + DISKLEDSTATUS diskLedStatus; + const char* abbrName[] = {"internal", "sys"}; + *ops = &synobios_ops; + + switch(GetModel()) + { + case MODEL_DS1621p: + model_ops = &ds1621p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1621p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + case MODEL_DS1821p: + model_ops = &ds1821p_ops; + + if ( model_ops->x86_gpio_init ) { + model_ops->x86_gpio_init(); + } + hwmon_sensor_list = &ds1821p_sensor_list; +#ifdef CONFIG_SYNO_ADT7490_FEATURES + synobios_ops.hwmon_get_fan_speed_rpm = HWMONGetFanSpeedRPMFromADT; + synobios_ops.hwmon_get_sys_voltage = HWMONGetVoltageSensorFromADT; + synobios_ops.hwmon_get_sys_thermal = HWMONGetThermalSensorFromADT; +#endif /* CONFIG_SYNO_ADT7490_FEATURES */ +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) + synobios_ops.hwmon_get_backplane_status = HWMONGetHDDBackPlaneStatusBySMBUS; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + synobios_ops.set_hdd_led = SetHddActLed; + synobios_ops.set_power_led = SetPowerLedStatus; +#ifdef CONFIG_SYNO_LEDS_TRIGGER + synobios_ops.set_disk_led = SetDiskLedStatusByLedTrigger; + SetupDiskLedMap(); +#if defined(MY_DEF_HERE) || defined(CONFIG_SYNO_SATA_DISK_LED_CONTROL) + funcSYNOSATADiskLedCtrl = SYNOSetDiskLedStatusByLedTrigger; +#endif // MY_DEF_HERE || CONFIG_SYNO_SATA_DISK_LED_CONTROL +#endif // CONFIG_SYNO_LEDS_TRIGGER +#ifdef CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY + syno_ahci_disk_led_enable_by_port(1, 1); + syno_ahci_disk_led_enable_by_port(2, 1); + syno_ahci_disk_led_enable_by_port(3, 1); + syno_ahci_disk_led_enable_by_port(4, 1); + syno_ahci_disk_led_enable_by_port(5, 1); + syno_ahci_disk_led_enable_by_port(6, 1); + syno_ahci_disk_led_enable_by_port(7, 1); + syno_ahci_disk_led_enable_by_port(8, 1); +#endif /* CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY */ + break; + + default : + break; + } + + if( synobios_ops.init_auto_poweron ) { + synobios_ops.init_auto_poweron(); + } + + return 0; +} + +static +int Uninitialize(void) +{ + SYNORTCTIMEPKT rtc_time_pkt; + + if( synobios_ops.get_rtc_time ) { + synobios_ops.get_rtc_time(&rtc_time_pkt); + } + + if( synobios_ops.uninit_auto_poweron ) { + synobios_ops.uninit_auto_poweron(); + } + + return 0; +} + +int synobios_model_cleanup(struct file_operations *fops, struct synobios_ops **ops) +{ + if ( model_ops->x86_gpio_cleanup ) { + model_ops->x86_gpio_cleanup(); + } + + return 0; +} diff --git a/drivers/syno/synobios/v1000sofs/v1000sofs_common.h b/drivers/syno/synobios/v1000sofs/v1000sofs_common.h new file mode 100755 index 000000000000..42a804a715f6 --- /dev/null +++ b/drivers/syno/synobios/v1000sofs/v1000sofs_common.h @@ -0,0 +1,76 @@ +// Copyright (c) 2000-2018 Synology Inc. All rights reserved. + +#include "synobios.h" +#include "../mapping.h" +#ifdef CONFIG_SYNO_LEDS_TRIGGER +#include "../led/led_trigger.h" +#endif /* CONFIG_SYNO_LEDS_TRIGGER */ +#include "../common/common.h" +#include "../led/led_jmb585.h" +#include "../led/led_asm116x.h" +#include "../led/led_1475.h" +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +#include +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +int GetModel(void); +int GetGpioPin(GPIO_PIN *pPin); +int SetGpioPin(GPIO_PIN *pPin); + +extern int SetUart(const char* cmd); +extern int ReadUart(const char *szGoCmd, const char *szStopCmd, char *szResult, size_t leng); +extern struct model_ops ds1621p_ops; +extern struct model_ops ds1821p_ops; + +#if defined(CONFIG_SYNO_SMBUS_HDD_POWERCTL) || defined(CONFIG_SYNO_SATA_PWR_CTRL_SMBUS) +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; +#endif /* CONFIG_SYNO_SMBUS_HDD_POWERCTL || CONFIG_SYNO_SATA_PWR_CTRL_SMBUS */ + +extern int syno_get_adt_fan_speed_rpm(SYNO_HWMON_SENSOR_TYPE *); +extern int syno_get_adt_thermal_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_voltage_sensor(SYNO_HWMON_SENSOR_TYPE*); +extern int syno_get_adt_fan_speed_rpm_by_order(SYNO_HWMON_SENSOR_TYPE *, SYNO_HWMON_FAN_ORDER *); +extern struct hwmon_sensor_list ds1621p_sensor_list; +extern struct hwmon_sensor_list ds1821p_sensor_list; + +#ifdef CONFIG_SYNO_X86_PINCTRL_GPIO +#include +#endif /* CONFIG_SYNO_X86_PINCTRL_GPIO */ +#if defined(CONFIG_SYNO_K10TEMP) || defined(CONFIG_SYNO_HWMON_AMD_K10TEMP) +extern int syno_k10cpu_temperature(struct _SynoCpuTemp *pCpuTemp); +#endif /* CONFIG_SYNO_K10TEMP || CONFIG_SYNO_HWMON_AMD_K10TEMP */ + +#define SZ_UART_CMD_PREFIX "-" +#define SZ_UART_ALARM_LED_ON "LA1" +#define SZ_UART_ALARM_LED_BLINKING "LA2" +#define SZ_UART_ALARM_LED_OFF "LA3" +#define SZ_UART_FAN_DUTY_CYCLE "V" +#define SZ_UART_FAN_FREQUENCY "W" +#define SZ_UART_CPUFAN_DUTY_CYCLE "X" +#define SZ_UART_CPUFAN_FREQUENCY "Y" +#define SZ_UART_PWR_LED_ON "4" +#define SZ_UART_PWR_LED_OFF "6" + +struct model_ops { + int (*x86_init_module_type)(struct synobios_ops *ops); + int (*x86_fan_speed_mapping)(FAN_SPEED speed); + int (*x86_set_esata_led_status)(SYNO_DISK_LED status); + int (*x86_cpufan_speed_mapping)(FAN_SPEED speed); + int (*x86_get_buzzer_cleared)(unsigned char *buzzer_cleared); + int (*x86_get_power_status)(POWER_INFO *power_info); + int (*x86_get_fan_status)(int fanno, FAN_STATUS *pStatus); + void (*x86_gpio_init)(void); + void (*x86_gpio_cleanup)(void); +}; + +struct hwmon_sensor_list { + SYNO_HWMON_SENSOR_TYPE *thermal_sensor; + SYNO_HWMON_SENSOR_TYPE *voltage_sensor; + SYNO_HWMON_SENSOR_TYPE *fan_speed_rpm; + SYNO_HWMON_SENSOR_TYPE *psu_status; + SYNO_HWMON_SENSOR_TYPE *hdd_backplane; +}; + diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 68da044afbfa..47bb350cf7c1 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -1,7 +1,17 @@ # SPDX-License-Identifier: GPL-2.0 +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) + +ccflags-y += -I$(srctree)/drivers/soc/realtek/common/mem_allocator/rtk/inc + +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_TEE) += tee.o tee-objs += tee_core.o tee-objs += tee_shm.o tee-objs += tee_shm_pool.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +ifeq ($(CONFIG_ION_RTK_DHC_HEAP),y) +obj-$(CONFIG_OPTEE) += tee_mem_api.o +endif +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_OPTEE) += optee/ obj-$(CONFIG_AMDTEE) += amdtee/ diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 63542c1cc291..572b760477dd 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015, Linaro Limited @@ -733,7 +736,16 @@ static struct platform_driver optee_driver = { .of_match_table = optee_dt_match, }, }; +#if defined(MY_DEF_HERE) + +static int __init optee_init(void) +{ + return platform_driver_register(&optee_driver); +} +subsys_initcall(optee_init); +#else /* MY_DEF_HERE */ module_platform_driver(optee_driver); +#endif /* MY_DEF_HERE */ MODULE_AUTHOR("Linaro"); MODULE_DESCRIPTION("OP-TEE driver"); diff --git a/drivers/tee/tee_client_api.h b/drivers/tee/tee_client_api.h new file mode 100644 index 000000000000..591bf261a22b --- /dev/null +++ b/drivers/tee/tee_client_api.h @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2014, STMicroelectronics International N.V. + * All rights reserved. + * Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef TEE_CLIENT_API_H +#define TEE_CLIENT_API_H + +//#include +//#include + +/* + * Defines the number of available memory references in an open session or + * invoke command operation payload. + */ +#define TEEC_CONFIG_PAYLOAD_REF_COUNT 4 + + +/** + * Defines the maximum size of a single shared memory block, in bytes, of both + * API allocated and API registered memory. The size is currently set to + * 512 * kB (512 * 1024). + */ +#define TEEC_CONFIG_SHAREDMEM_MAX_SIZE 0x8000 + +/** + * Flag constants indicating the type of parameters encoded inside the + * operation payload (TEEC_Operation), Type is uint32_t. + * + * TEEC_NONE The Parameter is not used + * + * TEEC_VALUE_INPUT The Parameter is a TEEC_Value tagged as input. + * + * TEEC_VALUE_OUTPUT The Parameter is a TEEC_Value tagged as output. + * + * TEEC_VALUE_INOUT The Parameter is a TEEC_Value tagged as both as + * input and output, i.e., for which both the + * behaviors of TEEC_VALUE_INPUT and + * TEEC_VALUE_OUTPUT apply. + * + * TEEC_MEMREF_TEMP_INPUT The Parameter is a TEEC_TempMemoryReference + * describing a region of memory which needs to be + * temporarily registered for the duration of the + * Operation and is tagged as input. + * + * TEEC_MEMREF_TEMP_OUTPUT Same as TEEC_MEMREF_TEMP_INPUT, but the Memory + * Reference is tagged as output. The + * Implementation may update the size field to + * reflect the required output size in some use + * cases. + * + * TEEC_MEMREF_TEMP_INOUT A Temporary Memory Reference tagged as both + * input and output, i.e., for which both the + * behaviors of TEEC_MEMREF_TEMP_INPUT and + * TEEC_MEMREF_TEMP_OUTPUT apply. + * + * TEEC_MEMREF_WHOLE The Parameter is a Registered Memory Reference + * that refers to the entirety of its parent Shared + * Memory block. The parameter structure is a + * TEEC_MemoryReference. In this structure, the + * Implementation MUST read only the parent field + * and MAY update the size field when the operation + * completes. + * + * TEEC_MEMREF_PARTIAL_INPUT A Registered Memory Reference structure that + * refers to a partial region of its parent Shared + * Memory block and is tagged as input. + * + * TEEC_MEMREF_PARTIAL_OUTPUT Registered Memory Reference structure that + * refers to a partial region of its parent Shared + * Memory block and is tagged as output. + * + * TEEC_MEMREF_PARTIAL_INOUT The Registered Memory Reference structure that + * refers to a partial region of its parent Shared + * Memory block and is tagged as both input and + * output, i.e., for which both the behaviors of + * TEEC_MEMREF_PARTIAL_INPUT and + * TEEC_MEMREF_PARTIAL_OUTPUT apply. + */ +#define TEEC_NONE 0x00000000 +#define TEEC_VALUE_INPUT 0x00000001 +#define TEEC_VALUE_OUTPUT 0x00000002 +#define TEEC_VALUE_INOUT 0x00000003 +#define TEEC_MEMREF_TEMP_INPUT 0x00000005 +#define TEEC_MEMREF_TEMP_OUTPUT 0x00000006 +#define TEEC_MEMREF_TEMP_INOUT 0x00000007 +#define TEEC_MEMREF_WHOLE 0x0000000C +#define TEEC_MEMREF_PARTIAL_INPUT 0x0000000D +#define TEEC_MEMREF_PARTIAL_OUTPUT 0x0000000E +#define TEEC_MEMREF_PARTIAL_INOUT 0x0000000F + +/** + * Flag constants indicating the data transfer direction of memory in + * TEEC_Parameter. TEEC_MEM_INPUT signifies data transfer direction from the + * client application to the TEE. TEEC_MEM_OUTPUT signifies data transfer + * direction from the TEE to the client application. Type is uint32_t. + * + * TEEC_MEM_INPUT The Shared Memory can carry data from the client + * application to the Trusted Application. + * TEEC_MEM_OUTPUT The Shared Memory can carry data from the Trusted + * Application to the client application. + */ +#define TEEC_MEM_INPUT 0x00000001 +#define TEEC_MEM_OUTPUT 0x00000002 + +/** + * Return values. Type is TEEC_Result + * + * TEEC_SUCCESS The operation was successful. + * TEEC_ERROR_GENERIC Non-specific cause. + * TEEC_ERROR_ACCESS_DENIED Access privileges are not sufficient. + * TEEC_ERROR_CANCEL The operation was canceled. + * TEEC_ERROR_ACCESS_CONFLICT Concurrent accesses caused conflict. + * TEEC_ERROR_EXCESS_DATA Too much data for the requested operation was + * passed. + * TEEC_ERROR_BAD_FORMAT Input data was of invalid format. + * TEEC_ERROR_BAD_PARAMETERS Input parameters were invalid. + * TEEC_ERROR_BAD_STATE Operation is not valid in the current state. + * TEEC_ERROR_ITEM_NOT_FOUND The requested data item is not found. + * TEEC_ERROR_NOT_IMPLEMENTED The requested operation should exist but is not + * yet implemented. + * TEEC_ERROR_NOT_SUPPORTED The requested operation is valid but is not + * supported in this implementation. + * TEEC_ERROR_NO_DATA Expected data was missing. + * TEEC_ERROR_OUT_OF_MEMORY System ran out of resources. + * TEEC_ERROR_BUSY The system is busy working on something else. + * TEEC_ERROR_COMMUNICATION Communication with a remote party failed. + * TEEC_ERROR_SECURITY A security fault was detected. + * TEEC_ERROR_SHORT_BUFFER The supplied buffer is too short for the + * generated output. + * TEEC_ERROR_TARGET_DEAD Trusted Application has panicked + * during the operation. + */ + +/** + * Standard defined error codes. + */ +#define TEEC_SUCCESS 0x00000000 +#define TEEC_ERROR_GENERIC 0xFFFF0000 +#define TEEC_ERROR_ACCESS_DENIED 0xFFFF0001 +#define TEEC_ERROR_CANCEL 0xFFFF0002 +#define TEEC_ERROR_ACCESS_CONFLICT 0xFFFF0003 +#define TEEC_ERROR_EXCESS_DATA 0xFFFF0004 +#define TEEC_ERROR_BAD_FORMAT 0xFFFF0005 +#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEEC_ERROR_BAD_STATE 0xFFFF0007 +#define TEEC_ERROR_ITEM_NOT_FOUND 0xFFFF0008 +#define TEEC_ERROR_NOT_IMPLEMENTED 0xFFFF0009 +#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A +#define TEEC_ERROR_NO_DATA 0xFFFF000B +#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C +#define TEEC_ERROR_BUSY 0xFFFF000D +#define TEEC_ERROR_COMMUNICATION 0xFFFF000E +#define TEEC_ERROR_SECURITY 0xFFFF000F +#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010 +#define TEEC_ERROR_EXTERNAL_CANCEL 0xFFFF0011 +#define TEEC_ERROR_TARGET_DEAD 0xFFFF3024 + +/** + * Function error origins, of type TEEC_ErrorOrigin. These indicate where in + * the software stack a particular return value originates from. + * + * TEEC_ORIGIN_API The error originated within the TEE Client API + * implementation. + * TEEC_ORIGIN_COMMS The error originated within the underlying + * communications stack linking the rich OS with + * the TEE. + * TEEC_ORIGIN_TEE The error originated within the common TEE code. + * TEEC_ORIGIN_TRUSTED_APP The error originated within the Trusted Application + * code. + */ +#define TEEC_ORIGIN_API 0x00000001 +#define TEEC_ORIGIN_COMMS 0x00000002 +#define TEEC_ORIGIN_TEE 0x00000003 +#define TEEC_ORIGIN_TRUSTED_APP 0x00000004 + +/** + * Session login methods, for use in TEEC_OpenSession() as parameter + * connectionMethod. Type is uint32_t. + * + * TEEC_LOGIN_PUBLIC No login data is provided. + * TEEC_LOGIN_USER Login data about the user running the Client + * Application process is provided. + * TEEC_LOGIN_GROUP Login data about the group running the Client + * Application process is provided. + * TEEC_LOGIN_APPLICATION Login data about the running Client Application + * itself is provided. + */ +#define TEEC_LOGIN_PUBLIC 0x00000000 +#define TEEC_LOGIN_USER 0x00000001 +#define TEEC_LOGIN_GROUP 0x00000002 +#define TEEC_LOGIN_APPLICATION 0x00000004 + +/** + * Encode the paramTypes according to the supplied types. + * + * @param p0 The first param type. + * @param p1 The second param type. + * @param p2 The third param type. + * @param p3 The fourth param type. + */ +#define TEEC_PARAM_TYPES(p0, p1, p2, p3) \ + ((p0) | ((p1) << 4) | ((p2) << 8) | ((p3) << 12)) + +/** + * Get the i_th param type from the paramType. + * + * @param p The paramType. + * @param i The i-th parameter to get the type for. + */ +#define TEEC_PARAM_TYPE_GET(p, i) (((p) >> (i * 4)) & 0xF) + +typedef uint32_t TEEC_Result; + +/** + * struct TEEC_Context - Represents a connection between a client application + * and a TEE. + */ +typedef struct { + /* Implementation defined */ + int fd; +} TEEC_Context; + +/** + * This type contains a Universally Unique Resource Identifier (UUID) type as + * defined in RFC4122. These UUID values are used to identify Trusted + * Applications. + */ +typedef struct { + uint32_t timeLow; + uint16_t timeMid; + uint16_t timeHiAndVersion; + uint8_t clockSeqAndNode[8]; +} TEEC_UUID; + +/** + * struct TEEC_SharedMemory - Memory to transfer data between a client + * application and trusted code. + * + * @param buffer The memory buffer which is to be, or has been, shared + * with the TEE. + * @param size The size, in bytes, of the memory buffer. + * @param flags Bit-vector which holds properties of buffer. + * The bit-vector can contain either or both of the + * TEEC_MEM_INPUT and TEEC_MEM_OUTPUT flags. + * + * A shared memory block is a region of memory allocated in the context of the + * client application memory space that can be used to transfer data between + * that client application and a trusted application. The user of this struct + * is responsible to populate the buffer pointer. + */ +typedef struct { + void *buffer; + size_t size; + uint32_t flags; + /* + * Implementation-Defined + */ + int id; + size_t alloced_size; + void *shadow_buffer; +} TEEC_SharedMemory; + +/** + * struct TEEC_TempMemoryReference - Temporary memory to transfer data between + * a client application and trusted code, only used for the duration of the + * operation. + * + * @param buffer The memory buffer which is to be, or has been shared with + * the TEE. + * @param size The size, in bytes, of the memory buffer. + * + * A memory buffer that is registered temporarily for the duration of the + * operation to be called. + */ +typedef struct { + void *buffer; + size_t size; +} TEEC_TempMemoryReference; + +/** + * struct TEEC_RegisteredMemoryReference - use a pre-registered or + * pre-allocated shared memory block of memory to transfer data between + * a client application and trusted code. + * + * @param parent Points to a shared memory structure. The memory reference + * may utilize the whole shared memory or only a part of it. + * Must not be NULL + * + * @param size The size, in bytes, of the memory buffer. + * + * @param offset The offset, in bytes, of the referenced memory region from + * the start of the shared memory block. + * + */ +typedef struct { + TEEC_SharedMemory *parent; + size_t size; + size_t offset; +} TEEC_RegisteredMemoryReference; + +/** + * struct TEEC_Value - Small raw data container + * + * Instead of allocating a shared memory buffer this structure can be used + * to pass small raw data between a client application and trusted code. + * + * @param a The first integer value. + * + * @param b The second second value. + */ +typedef struct { + uint32_t a; + uint32_t b; +} TEEC_Value; + +/** + * union TEEC_Parameter - Memory container to be used when passing data between + * client application and trusted code. + * + * Either the client uses a shared memory reference, parts of it or a small raw + * data container. + * + * @param tmpref A temporary memory reference only valid for the duration + * of the operation. + * + * @param memref The entire shared memory or parts of it. + * + * @param value The small raw data container to use + */ +typedef union { + TEEC_TempMemoryReference tmpref; + TEEC_RegisteredMemoryReference memref; + TEEC_Value value; +} TEEC_Parameter; + +/** + * struct TEEC_Session - Represents a connection between a client application + * and a trusted application. + */ +typedef struct { + /* Implementation defined */ + TEEC_Context *ctx; + uint32_t session_id; +} TEEC_Session; + +/** + * struct TEEC_Operation - Holds information and memory references used in + * TEEC_InvokeCommand(). + * + * @param started Client must initialize to zero if it needs to cancel + * an operation about to be performed. + * @param paramTypes Type of data passed. Use TEEC_PARAMS_TYPE macro to + * create the correct flags. + * 0 means TEEC_NONE is passed for all params. + * @param params Array of parameters of type TEEC_Parameter. + * @param session Internal pointer to the last session used by + * TEEC_InvokeCommand with this operation. + * + */ +typedef struct { + uint32_t started; + uint32_t paramTypes; + TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT]; + /* Implementation-Defined */ + TEEC_Session *session; +} TEEC_Operation; + +/** + * TEEC_InitializeContext() - Initializes a context holding connection + * information on the specific TEE, designated by the name string. + + * @param name A zero-terminated string identifying the TEE to connect to. + * If name is set to NULL, the default TEE is connected to. NULL + * is the only supported value in this version of the API + * implementation. + * + * @param context The context structure which is to be initialized. + * + * @return TEEC_SUCCESS The initialization was successful. + * @return TEEC_Result Something failed. + */ +TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context); + +/** + * TEEC_FinalizeContext() - Destroys a context holding connection information + * on the specific TEE. + * + * This function destroys an initialized TEE context, closing the connection + * between the client application and the TEE. This function must only be + * called when all sessions related to this TEE context have been closed and + * all shared memory blocks have been released. + * + * @param context The context to be destroyed. + */ +void TEEC_FinalizeContext(TEEC_Context *context); + +/** + * TEEC_OpenSession() - Opens a new session with the specified trusted + * application. + * + * @param context The initialized TEE context structure in which + * scope to open the session. + * @param session The session to initialize. + * @param destination A structure identifying the trusted application + * with which to open a session. + * + * @param connectionMethod The connection method to use. + * @param connectionData Any data necessary to connect with the chosen + * connection method. Not supported, should be set to + * NULL. + * @param operation An operation structure to use in the session. May + * be set to NULL to signify no operation structure + * needed. + * + * @param returnOrigin A parameter which will hold the error origin if + * this function returns any value other than + * TEEC_SUCCESS. + * + * @return TEEC_SUCCESS OpenSession successfully opened a new session. + * @return TEEC_Result Something failed. + * + */ +TEEC_Result TEEC_OpenSession(TEEC_Context *context, + TEEC_Session *session, + const TEEC_UUID *destination, + uint32_t connectionMethod, + const void *connectionData, + TEEC_Operation *operation, + uint32_t *returnOrigin); + +/** + * TEEC_CloseSession() - Closes the session which has been opened with the + * specific trusted application. + * + * @param session The opened session to close. + */ +void TEEC_CloseSession(TEEC_Session *session); + +/** + * TEEC_InvokeCommand() - Executes a command in the specified trusted + * application. + * + * @param session A handle to an open connection to the trusted + * application. + * @param commandID Identifier of the command in the trusted application + * to invoke. + * @param operation An operation structure to use in the invoke command. + * May be set to NULL to signify no operation structure + * needed. + * @param returnOrigin A parameter which will hold the error origin if this + * function returns any value other than TEEC_SUCCESS. + * + * @return TEEC_SUCCESS OpenSession successfully opened a new session. + * @return TEEC_Result Something failed. + */ +TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, + uint32_t commandID, + TEEC_Operation *operation, + uint32_t *returnOrigin); + +/** + * TEEC_RegisterSharedMemory() - Register a block of existing memory as a + * shared block within the scope of the specified context. + * + * @param context The initialized TEE context structure in which scope to + * open the session. + * @param sharedMem pointer to the shared memory structure to register. + * + * @return TEEC_SUCCESS The registration was successful. + * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. + * @return TEEC_Result Something failed. + */ +TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context, + TEEC_SharedMemory *sharedMem); + +/** + * TEEC_AllocateSharedMemory() - Allocate shared memory for TEE. + * + * @param context The initialized TEE context structure in which scope to + * open the session. + * @param sharedMem Pointer to the allocated shared memory. + * + * @return TEEC_SUCCESS The registration was successful. + * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion. + * @return TEEC_Result Something failed. + */ +TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context, + TEEC_SharedMemory *sharedMem); + +/** + * TEEC_ReleaseSharedMemory() - Free or deregister the shared memory. + * + * @param sharedMem Pointer to the shared memory to be freed. + */ +void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory); + +/** + * TEEC_RequestCancellation() - Request the cancellation of a pending open + * session or command invocation. + * + * @param operation Pointer to an operation previously passed to open session + * or invoke. + */ +void TEEC_RequestCancellation(TEEC_Operation *operation); + +#endif diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 6ade4a5c4840..e80ec1223082 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2016, Linaro Limited @@ -42,6 +45,9 @@ static DEFINE_SPINLOCK(driver_lock); static struct class *tee_class; static dev_t tee_devt; +#if defined(MY_DEF_HERE) +static u64 dma_mask;//for DMA operation +#endif /* MY_DEF_HERE */ static struct tee_context *teedev_open(struct tee_device *teedev) { @@ -352,6 +358,44 @@ tee_ioctl_shm_register(struct tee_context *ctx, return ret; } +#if defined(MY_DEF_HERE) +static int tee_ioctl_shm_register_fd(struct tee_context *ctx, + struct tee_ioctl_shm_register_fd_data __user *udata) +{ + struct tee_ioctl_shm_register_fd_data data; + struct tee_shm *shm; + long ret; + + if (copy_from_user(&data, udata, sizeof(data))) + return -EFAULT; + + /* Currently no input flags are supported */ + if (data.flags) + return -EINVAL; + + shm = tee_shm_register_fd(ctx, data.fd); + if (IS_ERR_OR_NULL(shm)) + return -EINVAL; + + data.id = shm->id; + data.flags = shm->flags; + data.size = shm->size; + + if (copy_to_user(udata, &data, sizeof(data))) + ret = -EFAULT; + else + ret = tee_shm_get_fd(shm); + + /* + * When user space closes the file descriptor the shared memory + * should be freed or if tee_shm_get_fd() failed then it will + * be freed immediately. + */ + tee_shm_put(shm); + return ret; +} + +#endif /* MY_DEF_HERE */ static int params_from_user(struct tee_context *ctx, struct tee_param *params, size_t num_params, struct tee_ioctl_param __user *uparams) @@ -825,6 +869,10 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return tee_ioctl_shm_alloc(ctx, uarg); case TEE_IOC_SHM_REGISTER: return tee_ioctl_shm_register(ctx, uarg); +#if defined(MY_DEF_HERE) + case TEE_IOC_SHM_REGISTER_FD: + return tee_ioctl_shm_register_fd(ctx, uarg); +#endif /* MY_DEF_HERE */ case TEE_IOC_OPEN_SESSION: return tee_ioctl_open_session(ctx, uarg); case TEE_IOC_INVOKE: @@ -920,6 +968,11 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, teedev->dev.class = tee_class; teedev->dev.release = tee_release_device; teedev->dev.parent = dev; +#if defined(MY_DEF_HERE) + //for DMA operation + dma_mask = 0xffffffff; + teedev->dev.dma_mask = &dma_mask; +#endif /* MY_DEF_HERE */ teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id); diff --git a/drivers/tee/tee_mem_api.c b/drivers/tee/tee_mem_api.c new file mode 100644 index 000000000000..228ad0211767 --- /dev/null +++ b/drivers/tee/tee_mem_api.c @@ -0,0 +1,708 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tee_private.h" +#include "tee_client_api.h" +#include "ion_rtk_protected_notifier.h" + +static const uuid_t pta_mem_uuid = UUID_INIT(0xb8b220fc, 0x3851, 0x4d5a, + 0xa6, 0x7e, 0x9d, 0x45, 0xed, 0xdf, 0xc5, 0x32); +static const uuid_t ta_mem_uuid = UUID_INIT(0x7aaaf200, 0x2450, 0x11e4, + 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b); + +#define TEE_MEM_TAG "TEE_MEM : " + +//#define TEE_MEM_EMPTY_FUNCTION // FOR TEST + +enum tee_mem_cmd_for_ta { + TA_TEE_MEM_PROTECTED_DESTROY_SSID = 24, + TA_TEE_MEM_PROTECTED_CREATE_SSID = 26, + TA_TEE_MEM_PROTECTED_CHANGE = 27, + TA_TEE_MEM_PROTECTED_EXT_SET_SSID = 28, + TA_TEE_MEM_PROTECTED_EXT_UNSET_SSID = 29, +}; + +struct tee_mem_region { + unsigned int type; + unsigned long long base; + unsigned long long size; +}; + +struct tee_mem_ext_region { + unsigned int ext; + unsigned long long base; + unsigned long long size; + long long parent_ssid; +}; + +struct tee_mem_protected_create_ssid { + struct tee_mem_region mem; + long long ssid; +}; + +struct tee_mem_protected_destroy_ssid { + long long ssid; +}; + +struct tee_mem_protected_change_ssid { + struct tee_mem_region mem; + long long ssid; +}; + +struct tee_mem_protected_ext_set_ssid { + struct tee_mem_ext_region mem; + long long ssid; +}; + +struct tee_mem_protected_ext_unset_ssid { + long long ssid; +}; + +struct tee_mem_protected_slot { + struct list_head list; + struct tee_mem_region mem; + long long ssid; +}; + +struct tee_mem_protected_ext_slot { + struct list_head list; + struct tee_mem_ext_region mem; + long long ssid; +}; + +struct tee_mem_api_module { + struct tee_context * tee_context; + unsigned int tee_session; + struct mutex protected_lock; + struct list_head protected_list; + struct list_head protected_ext_list; + struct notifier_block protected_notifier; + bool bReady; +}; + +static int protected_handler(struct notifier_block *self, unsigned long val, void *data); + +static void tee_mem_protected_slot_init (struct tee_mem_protected_slot * slot, + unsigned long long base, unsigned long long size, long long ssid, unsigned int type) +{ + memset((void *) slot, 0, sizeof(struct tee_mem_protected_slot)); + INIT_LIST_HEAD(&slot->list); + slot->mem.base = base; + slot->mem.size = size; + slot->mem.type = type; + slot->ssid = ssid; +} + +static void tee_mem_protected_ext_slot_init(struct tee_mem_protected_ext_slot *slot, + unsigned long long base, + unsigned long long size, long long ssid, + unsigned int ext, struct tee_mem_protected_slot * parent) +{ + memset((void *)slot, 0, sizeof(struct tee_mem_protected_ext_slot)); + INIT_LIST_HEAD(&slot->list); + slot->mem.base = base; + slot->mem.size = size; + slot->mem.ext = ext; + slot->mem.parent_ssid = parent->ssid; + slot->ssid = ssid; +} + +static __maybe_unused int mem_optee_match(struct tee_ioctl_version_data *data, + const void *vers) +{ + return 1; +} + +static struct tee_mem_protected_slot * tee_mem_protected_create (struct tee_mem_api_module * module, unsigned long base, size_t size, unsigned int type) +{ + struct tee_mem_protected_slot * ret = NULL; + do { +#ifndef TEE_MEM_EMPTY_FUNCTION + struct tee_param *invoke_param = NULL; + struct tee_ioctl_invoke_arg tee_arg; + struct tee_shm * tee_shm; + struct tee_mem_protected_create_ssid * create_info; +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + struct tee_mem_protected_slot * slot; + + slot = (struct tee_mem_protected_slot *) kzalloc(sizeof(struct tee_mem_protected_slot), GFP_KERNEL); + if (!slot) + break; + +#ifndef TEE_MEM_EMPTY_FUNCTION + tee_shm = tee_shm_alloc(module->tee_context, sizeof (struct tee_mem_protected_create_ssid), TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(tee_shm)) { + kfree(slot); + break; + } + + create_info = (struct tee_mem_protected_create_ssid *) tee_shm->kaddr; + create_info->mem.base = base; + create_info->mem.size = size; + create_info->mem.type = type; + + invoke_param = kcalloc(TEEC_CONFIG_PAYLOAD_REF_COUNT, + sizeof(struct tee_param), GFP_KERNEL); + + if (!invoke_param) + return ret; + + invoke_param[0].u.memref.size = sizeof(struct tee_mem_protected_create_ssid); + invoke_param[0].u.memref.shm = tee_shm; + + invoke_param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; + invoke_param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + memset(&tee_arg, 0, sizeof(struct tee_ioctl_invoke_arg)); + tee_arg.func = TA_TEE_MEM_PROTECTED_CREATE_SSID; + tee_arg.session = module->tee_session; + tee_arg.num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; + + tee_client_invoke_func(module->tee_context, &tee_arg, invoke_param); + if (tee_arg.ret != 0) { + pr_info("%s%s : %d ==== tee_arg.ret:%08x ====\n", TEE_MEM_TAG, __func__, __LINE__, tee_arg.ret); + tee_shm_free(tee_shm); + kfree(invoke_param); + kfree(slot); + break; + } + + pr_info("%s%s : %d ssid:%x\n", TEE_MEM_TAG, __func__, __LINE__, create_info->ssid); + tee_mem_protected_slot_init(slot, base, size, create_info->ssid, type); + tee_shm_free(tee_shm); + kfree(invoke_param); +#else /* else of TEE_MEM_EMPTY_FUNCTION */ + tee_mem_protected_slot_init(slot, base, size, 0, 0); +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + + mutex_lock(&module->protected_lock); + list_add(&slot->list, &module->protected_list); + mutex_unlock(&module->protected_lock); + + ret = slot; + break; + } while(0); + + return ret; +} + +static int tee_mem_protected_destroy (struct tee_mem_api_module * module, struct tee_mem_protected_slot * slot) +{ + int ret = -1; + do { +#ifndef TEE_MEM_EMPTY_FUNCTION + struct tee_param *invoke_param = NULL; + struct tee_ioctl_invoke_arg tee_arg; + struct tee_shm * tee_shm; + struct tee_mem_protected_destroy_ssid * destroy_info; + + tee_shm = tee_shm_alloc(module->tee_context, sizeof (struct tee_mem_protected_destroy_ssid), TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(tee_shm)) { + break; + } + + destroy_info = (struct tee_mem_protected_destroy_ssid *) tee_shm->kaddr; + destroy_info->ssid = slot->ssid; + + invoke_param = kcalloc(TEEC_CONFIG_PAYLOAD_REF_COUNT, + sizeof(struct tee_param), GFP_KERNEL); + + if (!invoke_param) + return ret; + + invoke_param[0].u.memref.size = sizeof(struct tee_mem_protected_destroy_ssid); + invoke_param[0].u.memref.shm = tee_shm; + + invoke_param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + invoke_param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + memset(&tee_arg, 0, sizeof(struct tee_ioctl_invoke_arg)); + tee_arg.func = TA_TEE_MEM_PROTECTED_DESTROY_SSID; + tee_arg.session = module->tee_session; + tee_arg.num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; + + tee_client_invoke_func(module->tee_context, &tee_arg, invoke_param); + if (tee_arg.ret != 0) { + pr_info("%s%s : %d ==== tee_arg.ret:%08x ====\n", TEE_MEM_TAG, __func__, __LINE__, tee_arg.ret); + tee_shm_free(tee_shm); + kfree(invoke_param); + break; + } + + pr_info("%s%s : %d ssid:%x\n", TEE_MEM_TAG, __func__, __LINE__, destroy_info->ssid); + tee_shm_free(tee_shm); + kfree(invoke_param); +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + + mutex_lock(&module->protected_lock); + list_del(&slot->list); + mutex_unlock(&module->protected_lock); + + + kfree(slot); + + ret = 0; + break; + } while(0); + return ret; +} + +static int tee_mem_protected_change (struct tee_mem_api_module * module, struct tee_mem_protected_slot * slot, + unsigned long long base, unsigned long long size, unsigned int type) +{ + int ret = -1; + do { +#ifndef TEE_MEM_EMPTY_FUNCTION + struct tee_param *invoke_param = NULL; + struct tee_ioctl_invoke_arg tee_arg; + struct tee_shm * tee_shm; + struct tee_mem_protected_change_ssid * change_info; + + tee_shm = tee_shm_alloc(module->tee_context, sizeof (struct tee_mem_protected_change_ssid), TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(tee_shm)) { + break; + } + + change_info = (struct tee_mem_protected_change_ssid *) tee_shm->kaddr; + change_info->ssid = slot->ssid; + change_info->mem.base = base; + change_info->mem.size = size; + change_info->mem.type = type; + + invoke_param = kcalloc(TEEC_CONFIG_PAYLOAD_REF_COUNT, + sizeof(struct tee_param), GFP_KERNEL); + + if (!invoke_param) + return ret; + + invoke_param[0].u.memref.size = sizeof(struct tee_mem_protected_change_ssid); + invoke_param[0].u.memref.shm = tee_shm; + + invoke_param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + invoke_param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + memset(&tee_arg, 0, sizeof(struct tee_ioctl_invoke_arg)); + tee_arg.func = TA_TEE_MEM_PROTECTED_CHANGE; + tee_arg.session = module->tee_session; + tee_arg.num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; + + tee_client_invoke_func(module->tee_context, &tee_arg, invoke_param); + + if (tee_arg.ret != 0) { + pr_info("%s%s : %d ==== tee_arg.ret:%08x ====\n", TEE_MEM_TAG, __func__, __LINE__, tee_arg.ret); + tee_shm_free(tee_shm); + kfree(invoke_param); + break; + } + + pr_info("%s%s : %d ssid:%x\n", TEE_MEM_TAG, __func__, __LINE__, change_info->ssid); + tee_shm_free(tee_shm); + kfree(invoke_param); +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + + slot->mem.base = base; + slot->mem.size = size; + + + ret = 0; + break; + } while(0); + return ret; +} + +static struct tee_mem_protected_ext_slot *tee_mem_protected_ext_create(struct tee_mem_api_module *module, + unsigned long base, + size_t size, + unsigned int ext, struct tee_mem_protected_slot * parent) +{ + struct tee_mem_protected_ext_slot *ret = NULL; + + do { +#ifndef TEE_MEM_EMPTY_FUNCTION + struct tee_param *invoke_param = NULL; + struct tee_ioctl_invoke_arg tee_arg; + struct tee_shm *tee_shm; + struct tee_mem_protected_ext_set_ssid *create_info; +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + struct tee_mem_protected_ext_slot *slot; + + slot = + (struct tee_mem_protected_ext_slot *) + kzalloc(sizeof(struct tee_mem_protected_ext_slot), GFP_KERNEL); + if (!slot) + break; + +#ifndef TEE_MEM_EMPTY_FUNCTION + tee_shm = + tee_shm_alloc(module->tee_context, + sizeof(struct tee_mem_protected_ext_set_ssid), + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(tee_shm)) { + kfree(slot); + break; + } + + create_info = + (struct tee_mem_protected_ext_set_ssid *)tee_shm->kaddr; + create_info->mem.base = base; + create_info->mem.size = size; + create_info->mem.ext = ext; + create_info->mem.parent_ssid = parent->ssid; + + invoke_param = kcalloc(TEEC_CONFIG_PAYLOAD_REF_COUNT, + sizeof(struct tee_param), GFP_KERNEL); + + if (!invoke_param) + return NULL; + + invoke_param[0].u.memref.size = + sizeof(struct tee_mem_protected_ext_set_ssid); + invoke_param[0].u.memref.shm = tee_shm; + + invoke_param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; + invoke_param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + memset(&tee_arg, 0, sizeof(struct tee_ioctl_invoke_arg)); + tee_arg.func = TA_TEE_MEM_PROTECTED_EXT_SET_SSID; + tee_arg.session = module->tee_session; + tee_arg.num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; + + tee_client_invoke_func(module->tee_context, &tee_arg, + invoke_param); + if (tee_arg.ret != 0) { + pr_info("%s%s : %d ==== tee_arg.ret:%08x ====\n", + TEE_MEM_TAG, __func__, __LINE__, tee_arg.ret); + tee_shm_free(tee_shm); + kfree(invoke_param); + kfree(slot); + break; + } + + pr_info("%s%s : %d ssid:%x\n", TEE_MEM_TAG, __func__, __LINE__, + create_info->ssid); + tee_mem_protected_ext_slot_init(slot, base, size, create_info->ssid, + ext, parent); + tee_shm_free(tee_shm); + kfree(invoke_param); +#else /* else of TEE_MEM_EMPTY_FUNCTION */ + tee_mem_protected_ext_slot_init(slot, base, size, 0, 0, parent); +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + + mutex_lock(&module->protected_lock); + list_add(&slot->list, &module->protected_ext_list); + mutex_unlock(&module->protected_lock); + + ret = slot; + break; + } while (0); + + return ret; +} + +static int tee_mem_protected_ext_destroy(struct tee_mem_api_module *module, + struct tee_mem_protected_ext_slot *slot) +{ + int ret = -1; + + do { +#ifndef TEE_MEM_EMPTY_FUNCTION + struct tee_param *invoke_param = NULL; + struct tee_ioctl_invoke_arg tee_arg; + struct tee_shm *tee_shm; + struct tee_mem_protected_ext_unset_ssid *destroy_info; + + tee_shm = + tee_shm_alloc(module->tee_context, + sizeof(struct tee_mem_protected_ext_unset_ssid), + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); + if (IS_ERR(tee_shm)) + break; + + destroy_info = + (struct tee_mem_protected_ext_unset_ssid *)tee_shm->kaddr; + destroy_info->ssid = slot->ssid; + + invoke_param = kcalloc(TEEC_CONFIG_PAYLOAD_REF_COUNT, + sizeof(struct tee_param), GFP_KERNEL); + + if (!invoke_param) + return -1; + + invoke_param[0].u.memref.size = + sizeof(struct tee_mem_protected_ext_unset_ssid); + invoke_param[0].u.memref.shm = tee_shm; + + invoke_param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; + invoke_param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + invoke_param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + memset(&tee_arg, 0, sizeof(struct tee_ioctl_invoke_arg)); + tee_arg.func = TA_TEE_MEM_PROTECTED_EXT_UNSET_SSID; + tee_arg.session = module->tee_session; + tee_arg.num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; + + tee_client_invoke_func(module->tee_context, &tee_arg, + invoke_param); + if (tee_arg.ret != 0) { + pr_info("%s%s : %d ==== tee_arg.ret:%08x ====\n", + TEE_MEM_TAG, __func__, __LINE__, tee_arg.ret); + tee_shm_free(tee_shm); + kfree(invoke_param); + break; + } + + pr_info("%s%s : %d ssid:%x\n", TEE_MEM_TAG, __func__, __LINE__, + destroy_info->ssid); + tee_shm_free(tee_shm); + kfree(invoke_param); +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + + mutex_lock(&module->protected_lock); + list_del(&slot->list); + mutex_unlock(&module->protected_lock); + + kfree(slot); + + ret = 0; + break; + } while (0); + return ret; +} + +struct tee_mem_api_module * gModule = NULL; +static int __init tee_mem_api_module_init(void) +{ + int ret = -1; + pr_info("%s%s init\n", TEE_MEM_TAG, __func__); + do { + struct tee_mem_api_module * module; + if (gModule) { + ret = 0; + break; + } + + gModule = kzalloc(sizeof(struct tee_mem_api_module), GFP_KERNEL); + if (!gModule) + break; + + module = gModule; + + pr_info("%s%s : %d\n", TEE_MEM_TAG, __func__, __LINE__); + module->protected_notifier.notifier_call = protected_handler; + INIT_LIST_HEAD(&module->protected_list); + INIT_LIST_HEAD(&module->protected_ext_list); + mutex_init(&module->protected_lock); + +#ifndef TEE_MEM_EMPTY_FUNCTION + { + struct tee_ioctl_open_session_arg arg; + struct tee_param param[TEEC_CONFIG_PAYLOAD_REF_COUNT]; + + struct tee_ioctl_version_data vers = { + .impl_id = TEE_OPTEE_CAP_TZ, + .impl_caps = TEE_IMPL_ID_OPTEE, + .gen_caps = TEE_GEN_CAP_GP, + }; + + pr_info("%s%s : %d Use PTA_MEM_UUID", TEE_MEM_TAG, __func__, __LINE__); + + pr_info("%s%s : %d\n", TEE_MEM_TAG, __func__, __LINE__); + module->tee_context = tee_client_open_context(NULL, mem_optee_match, NULL, &vers); + pr_info("%s%s : %d\n", TEE_MEM_TAG, __func__, __LINE__); + + if (IS_ERR(module->tee_context)) { + pr_err("%s%s tee_client_open_context fail\n", TEE_MEM_TAG, __func__); +#if 0 + kfree(module); + gModule = NULL; +#else + gModule->bReady = false; + ret = 0; +#endif + break; + } + + memcpy(arg.uuid, pta_mem_uuid.b, TEE_IOCTL_UUID_LEN); + arg.clnt_login = TEEC_LOGIN_PUBLIC; + arg.num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; + { + size_t n; + for (n=0; ntee_context, &arg, param); + pr_info("%s%s : %d\n", TEE_MEM_TAG, __func__, __LINE__); + + if (IS_ERR(module->tee_context)) { + pr_err("%s%s tee_client_open_session fail\n", TEE_MEM_TAG, __func__); +#if 0 + kfree(module); + gModule = NULL; +#else + gModule->bReady = false; + ret = 0; +#endif + break; + } + + module->tee_session = arg.session; + } +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + + pr_info("%s%s : %d\n", TEE_MEM_TAG, __func__, __LINE__); + ion_rtk_protected_notifier_register(&module->protected_notifier); + pr_info("%s%s : %d\n", TEE_MEM_TAG, __func__, __LINE__); + + gModule->bReady = true; + ret = 0; + } while (0); + pr_info("%s%s (%d) module:%p\n", TEE_MEM_TAG, __func__, ret, gModule); + return ret; +} + +static void __exit tee_mem_api_module_exit (void) +{ + if (gModule) { + struct tee_mem_api_module * module = gModule; + ion_rtk_protected_notifier_unregister(&module->protected_notifier); + { + struct tee_mem_protected_slot * slot, * tmp_slot; + list_for_each_entry_safe(slot, tmp_slot, &module->protected_list, list) { + tee_mem_protected_destroy(module, slot); + } + } +#ifndef TEE_MEM_EMPTY_FUNCTION + tee_client_close_session(module->tee_context, module->tee_session); + tee_client_close_context(module->tee_context); +#endif /* end of TEE_MEM_EMPTY_FUNCTION */ + kfree(module); + gModule = NULL; + } + pr_info("%s%s\n", TEE_MEM_TAG, __func__); +} + +#ifdef CONFIG_ION_RTK_DHC_HEAP +subsys_initcall_sync(tee_mem_api_module_init); +#else +module_init(tee_mem_api_module_init); +#endif +module_exit(tee_mem_api_module_exit); + +static int protected_handler(struct notifier_block *self, + unsigned long val, + void *data) +{ + struct tee_mem_api_module * module = container_of(self, struct tee_mem_api_module, protected_notifier); + if (!module->bReady) + return NOTIFY_BAD; + switch (val) { + case PROTECTED_REGION_CREATE: + { + struct ion_rtk_protected_create_info * create_info = (struct ion_rtk_protected_create_info *) data; + struct tee_mem_protected_slot * slot = tee_mem_protected_create (module, + create_info->mem.base, + create_info->mem.size, create_info->mem.type); + if (!slot) { + pr_err("%stee_mem_protected_create failed!\n", TEE_MEM_TAG); + return NOTIFY_BAD; + } + + pr_info("%sPROTECTED_REGION_CREATE: %p (0x%08llx ~ 0x%08llx)\n", TEE_MEM_TAG, + slot, slot->mem.base, slot->mem.base + slot->mem.size); + + create_info->priv_virt = (void *) slot; + } + break; + case PROTECTED_REGION_CHANGE: + { + struct ion_rtk_protected_change_info * change_info = (struct ion_rtk_protected_change_info *) data; + struct tee_mem_protected_slot * slot = (struct tee_mem_protected_slot *) change_info->priv_virt; + if (tee_mem_protected_change(module, slot, change_info->mem.base, change_info->mem.size, change_info->mem.type)) { + pr_err("%stee_mem_protected_change failed! %p\n", TEE_MEM_TAG, slot); + return NOTIFY_BAD; + } + + pr_info("%sPROTECTED_REGION_CHANGE: %p (0x%08llx ~ 0x%08llx)\n", TEE_MEM_TAG, + slot, slot->mem.base, slot->mem.base + slot->mem.size); + } + break; + case PROTECTED_REGION_DESTROY: + { + struct ion_rtk_protected_destroy_info * destroy_info = (struct ion_rtk_protected_destroy_info *) data; + struct tee_mem_protected_slot * slot = (struct tee_mem_protected_slot *) destroy_info->priv_virt; + if (tee_mem_protected_destroy(module, slot)) { + pr_err("%stee_mem_protected_destroy failed! %p\n", TEE_MEM_TAG, slot); + return NOTIFY_BAD; + } + + pr_info("%sPROTECTED_REGION_DESTROY: %p\n", TEE_MEM_TAG, slot); + } + break; + case PROTECTED_REGION_EXTENSION_SET: + { + struct ion_rtk_protected_ext_set *create_info = + (struct ion_rtk_protected_ext_set *)data; + struct tee_mem_protected_ext_slot *slot = + tee_mem_protected_ext_create(module, + create_info->mem.base, + create_info->mem.size, + create_info->mem.ext, + (struct tee_mem_protected_slot *) create_info->mem.parent_priv); + if (!slot) { + pr_err("%stee_mem_protected_ext_create failed!\n", + TEE_MEM_TAG); + return NOTIFY_BAD; + } + + pr_info + ("%sPROTECTED_REGION_EXTENSION_SET: %p (0x%08llx ~ 0x%08llx)\n", + TEE_MEM_TAG, slot, slot->mem.base, + slot->mem.base + slot->mem.size); + + create_info->priv_virt = (void *)slot; + } + break; + case PROTECTED_REGION_EXTENSION_UNSET: + { + struct ion_rtk_protected_ext_unset *destroy_info = + (struct ion_rtk_protected_ext_unset *)data; + struct tee_mem_protected_ext_slot *slot = + (struct tee_mem_protected_ext_slot *)destroy_info->priv_virt; + + if (tee_mem_protected_ext_destroy(module, slot)) { + pr_err + ("%stee_mem_protected_ext_destroy failed! %p\n", + TEE_MEM_TAG, slot); + return NOTIFY_BAD; + } + + pr_info("%sPROTECTED_REGION_EXTENSION_UNSET: %p\n", TEE_MEM_TAG, + slot); + } + break; + default: + return NOTIFY_BAD; + } + return NOTIFY_OK; +} + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); + diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 00472f5ce22e..12b8f1df24d3 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2016, Linaro Limited @@ -12,6 +15,16 @@ #include #include "tee_private.h" +#if defined(MY_DEF_HERE) +/* extra references appended to shm object for registered shared memory */ +struct tee_shm_dmabuf_ref { + struct tee_shm shm; + struct dma_buf *dmabuf; + struct dma_buf_attachment *attach; + struct sg_table *sgt; +}; + +#endif /* MY_DEF_HERE */ static void release_registered_pages(struct tee_shm *shm) { if (shm->pages) { @@ -38,7 +51,19 @@ static void tee_shm_release(struct tee_shm *shm) mutex_unlock(&teedev->mutex); } +#if defined(MY_DEF_HERE) + if (shm->flags & TEE_SHM_EXT_DMA_BUF) { + struct tee_shm_dmabuf_ref *ref; + + ref = container_of(shm, struct tee_shm_dmabuf_ref, shm); + dma_buf_unmap_attachment(ref->attach, ref->sgt, + DMA_BIDIRECTIONAL); + dma_buf_detach(ref->dmabuf, ref->attach); + dma_buf_put(ref->dmabuf); + } else if (shm->flags & TEE_SHM_POOL) { +#else /* MY_DEF_HERE */ if (shm->flags & TEE_SHM_POOL) { +#endif /* MY_DEF_HERE */ struct tee_shm_pool_mgr *poolm; if (shm->flags & TEE_SHM_DMA_BUF) @@ -318,6 +343,100 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, } EXPORT_SYMBOL_GPL(tee_shm_register); +#if defined(MY_DEF_HERE) +struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd) +{ + struct tee_shm_dmabuf_ref *ref; + void *rc; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + if (!tee_device_get(ctx->teedev)) + return ERR_PTR(-EINVAL); + + teedev_ctx_get(ctx); + + ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) { + rc = ERR_PTR(-ENOMEM); + goto err; + } + + ref->shm.ctx = ctx; + ref->shm.id = -1; + + ref->dmabuf = dma_buf_get(fd); + if (!ref->dmabuf) { + rc = ERR_PTR(-EINVAL); + goto err; + } + + ref->attach = dma_buf_attach(ref->dmabuf, &ref->shm.ctx->teedev->dev); + if (IS_ERR_OR_NULL(ref->attach)) { + rc = ERR_PTR(-EINVAL); + goto err; + } + + ref->sgt = dma_buf_map_attachment(ref->attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(ref->sgt)) { + rc = ERR_PTR(-EINVAL); + goto err; + } + + if (sg_nents(ref->sgt->sgl) != 1) { + rc = ERR_PTR(-EINVAL); + goto err; + } + + ref->shm.paddr = sg_dma_address(ref->sgt->sgl); + ref->shm.size = sg_dma_len(ref->sgt->sgl); + ref->shm.flags = TEE_SHM_DMA_BUF | TEE_SHM_EXT_DMA_BUF; + + mutex_lock(&ref->shm.ctx->teedev->mutex); + ref->shm.id = idr_alloc(&ref->shm.ctx->teedev->idr, &ref->shm, + 1, 0, GFP_KERNEL); + mutex_unlock(&ref->shm.ctx->teedev->mutex); + if (ref->shm.id < 0) { + rc = ERR_PTR(ref->shm.id); + goto err; + } + + /* export a dmabuf to later get a userland ref */ + exp_info.ops = &tee_shm_dma_buf_ops; + exp_info.size = ref->shm.size; + exp_info.flags = O_RDWR; + exp_info.priv = &ref->shm; + + ref->shm.dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(ref->shm.dmabuf)) { + rc = ERR_PTR(-EINVAL); + goto err; + } + + return &ref->shm; + +err: + if (ref) { + if (ref->shm.id >= 0) { + mutex_lock(&ctx->teedev->mutex); + idr_remove(&ctx->teedev->idr, ref->shm.id); + mutex_unlock(&ctx->teedev->mutex); + } + if (ref->sgt) + dma_buf_unmap_attachment(ref->attach, ref->sgt, + DMA_BIDIRECTIONAL); + if (ref->attach) + dma_buf_detach(ref->dmabuf, ref->attach); + if (ref->dmabuf) + dma_buf_put(ref->dmabuf); + } + kfree(ref); + teedev_ctx_put(ctx); + tee_device_put(ctx->teedev); + return rc; +} +EXPORT_SYMBOL_GPL(tee_shm_register_fd); + +#endif /* MY_DEF_HERE */ /** * tee_shm_get_fd() - Increase reference count and return file descriptor * @shm: Shared memory handle @@ -434,8 +553,10 @@ EXPORT_SYMBOL_GPL(tee_shm_get_va); */ int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa) { +#if defined(MY_DEF_HERE) if (offs >= shm->size) return -EINVAL; +#endif /* MY_DEF_HERE */ if (pa) *pa = shm->paddr + offs; return 0; diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 7edc8dc6bbab..451e40aee6a3 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -510,4 +510,8 @@ config KHADAS_MCU_FAN_THERMAL If you say yes here you get support for the FAN controlled by the Microcontroller found on the Khadas VIM boards. +if SYNO_LSP_RTD1619B +source "drivers/thermal/realtek/Kconfig" + +endif # SYNO_LSP_RTD1619B endif diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index b64dd50a6629..64bdfd4f8f14 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -62,3 +62,6 @@ obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTK_THERMAL) += realtek/ +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/thermal/realtek/Kconfig b/drivers/thermal/realtek/Kconfig new file mode 100644 index 000000000000..7f420a03f3b6 --- /dev/null +++ b/drivers/thermal/realtek/Kconfig @@ -0,0 +1,18 @@ +config RTK_THERMAL + bool "Realtek thermal management" + depends on OF && THERMAL_OF + depends on ARCH_REALTEK || COMPILE_TEST + default y + help + Enable thermal management with a generic thermal + sensor driver on Realtek SoCs. + + If you want this support, you should say Y here. + +config RTK_THERMAL_CPU_CORE_COOLING + bool "Realtek CPU core cooling device" + select RTK_CPUHP_QOS + help + This enable Realtek CPU core cooling device drvier + + If not sure, say N diff --git a/drivers/thermal/realtek/Makefile b/drivers/thermal/realtek/Makefile new file mode 100644 index 000000000000..13006dd1ccf6 --- /dev/null +++ b/drivers/thermal/realtek/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_RTK_THERMAL) += rtk-thermal.o + +rtk-thermal-y += sensor.o +rtk-thermal-y += sensor-rtd119x.o +rtk-thermal-y += sensor-rtd129x.o +rtk-thermal-y += sensor-rtd161x.o + +obj-$(CONFIG_RTK_THERMAL_CPU_CORE_COOLING) += cpu_core_cooling.o diff --git a/drivers/thermal/realtek/cpu_core_cooling.c b/drivers/thermal/realtek/cpu_core_cooling.c new file mode 100644 index 000000000000..1ffd8a747408 --- /dev/null +++ b/drivers/thermal/realtek/cpu_core_cooling.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017,2020 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct c3dev { + struct device *dev; + struct thermal_cooling_device *cdev; + unsigned long max_state; + unsigned long cur_state; + struct rtk_cpuhp_qos_request req; +}; + +static int c3dev_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct c3dev *c = cdev->devdata; + + *state = c->max_state; + return 0; +} + +static int c3dev_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct c3dev *c = cdev->devdata; + + *state = c->cur_state; + return 0; +} + +static int c3dev_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct c3dev *c = cdev->devdata; + + rtk_cpuhp_qos_update_request(&c->req, (int)state); + return 0; +} + +static struct thermal_cooling_device_ops c3dev_cooling_ops = { + .get_max_state = c3dev_get_max_state, + .get_cur_state = c3dev_get_cur_state, + .set_cur_state = c3dev_set_cur_state, +}; + +static int c3dev_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct c3dev *c; + int ret; + + c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + c->dev = dev; + c->max_state = num_possible_cpus() - 1; + c->cur_state = 0; + rtk_cpuhp_qos_add_request(&c->req, 0); + + c->cdev = thermal_of_cooling_device_register(np, "thermal-cpu-core", + c, &c3dev_cooling_ops); + if (IS_ERR(c->cdev)) { + ret = PTR_ERR(c->cdev); + dev_err(dev, "failed to register cooling device: %d\n", ret); + rtk_cpuhp_qos_remove_request(&c->req); + return ret; + } + + return 0; +} + +static int c3dev_remove(struct platform_device *pdev) +{ + struct c3dev *c = platform_get_drvdata(pdev); + + thermal_cooling_device_unregister(c->cdev); + rtk_cpuhp_qos_remove_request(&c->req); + return 0; +} + +static const struct of_device_id c3dev_ids[] = { + { .compatible = "realtek,cpu-core-cooling" }, + {} +}; + +static struct platform_driver c3dev_driver = { + .probe = c3dev_probe, + .remove = c3dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rtk-cpu-core-cooling", + .of_match_table = c3dev_ids, + }, +}; +module_platform_driver(c3dev_driver); diff --git a/drivers/thermal/realtek/sensor-rtd119x.c b/drivers/thermal/realtek/sensor-rtd119x.c new file mode 100644 index 000000000000..6700a64ffa84 --- /dev/null +++ b/drivers/thermal/realtek/sensor-rtd119x.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include "sensor.h" + +struct sensor_data { + int calibration_data; +}; + +static int get_calibration_data(struct thermal_sensor_device *tdev, int index, + int *cal) +{ + struct device *dev = tdev->dev; + char cell_name[20]; + struct nvmem_cell *cell; + unsigned char *buf; + size_t buf_size; + + *cal = 0; + + sprintf(cell_name, "calibration%d", index); + cell = nvmem_cell_get(dev, cell_name); + if (IS_ERR(cell)) { + dev_warn(dev, "nvmem_cell_get() returns %ld\n", PTR_ERR(cell)); + goto done; + } + buf = nvmem_cell_read(cell, &buf_size); + nvmem_cell_put(cell); + dev_info(dev, "sensor%d: calibration=%d\n", index, (int)buf[0]); + *cal = (int)buf[0] * 1000; + kfree(buf); +done: + return 0; +} + +static int rtd119x_sensor_init(struct thermal_sensor_device *tdev) +{ + struct sensor_data *data; + + data = kcalloc(2, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + get_calibration_data(tdev, 0, &data[0].calibration_data); + get_calibration_data(tdev, 1, &data[1].calibration_data); + tdev->priv_data = data; + return 0; +} + +static void rtd119x_sensor_exit(struct thermal_sensor_device *tdev) +{ + kfree(tdev->priv_data); +} + +static void rtd119x_sensor_get_temp_index(struct thermal_sensor_device *tdev, + int index, int *temp) +{ + int i; + u64 t; + u32 val, cmp_data; + u32 off = index ? 0x4 : 0x0; + struct sensor_data *data = tdev->priv_data; + u32 cal = data[index].calibration_data; + + /* enable */ + thermal_sensor_device_reg_write(tdev, off, 0x0000c80c); + usleep_range(15, 25); + + /* thermal detect */ + for (i = 6; i >= 0; i--) { + thermal_sensor_device_reg_read(tdev, off, &val); + cmp_data = BIT(i + 5); + thermal_sensor_device_reg_write(tdev, off, cmp_data); + usleep_range(15, 25); + + thermal_sensor_device_reg_read(tdev, off, &val); + if ((val & BIT(16)) == 0) + thermal_sensor_device_reg_write(tdev, off, ~cmp_data & val); + } + + /* get temperture */ + thermal_sensor_device_reg_read(tdev, off, &val); + t = (val >> 5) & 0x7f; + t *= 1000; + t -= cal; + t = (t * 165) / 128; + if (cal) + t += 25 * 1000; + else + t -= 47 * 1000; + + dev_dbg(tdev->dev, "sensor%d: reg=%05x, t=%lld, calibration_data=%d\n", + index, val, t, cal); + *temp = (int)t; +} + +static +int rtd119x_sensor_get_temp(struct thermal_sensor_device *tdev, int *temp) +{ + int t0, t1; + + rtd119x_sensor_get_temp_index(tdev, 0, &t0); + rtd119x_sensor_get_temp_index(tdev, 1, &t1); + + *temp = t0 > t1 ? t0 : t1; + return 0; +} + +static const struct thermal_sensor_hw_ops rtd119x_hw_ops = { + .get_temp = rtd119x_sensor_get_temp, + .init = rtd119x_sensor_init, + .exit = rtd119x_sensor_exit, +}; + +const struct thermal_sensor_desc rtd119x_sensor_desc = { + .hw_ops = &rtd119x_hw_ops, +}; diff --git a/drivers/thermal/realtek/sensor-rtd129x.c b/drivers/thermal/realtek/sensor-rtd129x.c new file mode 100644 index 000000000000..dbaa19d4f960 --- /dev/null +++ b/drivers/thermal/realtek/sensor-rtd129x.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include "sensor.h" + +/* + * Thermal sensor offset + */ +#define TM_SENSOR_CTRL0 0x00 +#define TM_SENSOR_CTRL1 0x04 +#define TM_SENSOR_CTRL2 0x08 +#define TM_SENSOR_CTRL3 0x0C +#define TM_SENSOR_CTRL4 0x10 +#define TM_SENSOR_CTRL5 0x14 +#define TM_SENSOR_STATUS1 0x18 +#define TM_SENSOR_STATUS2 0x1C + +static void rtd129x_sensor_reset(struct thermal_sensor_device *tdev) +{ + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x01904001); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x01924001); +} + +static int rtd129x_sensor_init(struct thermal_sensor_device *tdev) +{ + rtd129x_sensor_reset(tdev); + return 0; +} + +static inline int rtd129x_sensor_get_temp(struct thermal_sensor_device *tdev, + int *temp) +{ + unsigned int val = 0; + + thermal_sensor_device_reg_read(tdev, TM_SENSOR_STATUS1, &val); + *temp = __signext(18, val) * 1000 / 1024; + return 0; +} + +static void rtd139x_sensor_reset(struct thermal_sensor_device *tdev) +{ + + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x11904000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x11924000); +} + +static int rtd139x_sensor_init(struct thermal_sensor_device *tdev) +{ + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL0, 0x081fc000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL1, 0x05772000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x11824000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x11924000); + return 0; +} + +static const struct thermal_sensor_hw_ops rtd129x_hw_ops = { + .get_temp = rtd129x_sensor_get_temp, + .reset = rtd129x_sensor_reset, + .init = rtd129x_sensor_init, +}; + +const struct thermal_sensor_desc rtd129x_sensor_desc = { + .hw_ops = &rtd129x_hw_ops, + .reset_time_ms = 25, + .status_ofs = TM_SENSOR_STATUS1, + .status_cnt = 2, +}; + +static const struct thermal_sensor_hw_ops rtd139x_sensor_hw_ops = { + .get_temp = rtd129x_sensor_get_temp, + .reset = rtd139x_sensor_reset, + .init = rtd139x_sensor_init, +}; + +const struct thermal_sensor_desc rtd139x_sensor_desc = { + .hw_ops = &rtd139x_sensor_hw_ops, + .reset_time_ms = 25, + .status_ofs = TM_SENSOR_STATUS1, + .status_cnt = 2, +}; diff --git a/drivers/thermal/realtek/sensor-rtd161x.c b/drivers/thermal/realtek/sensor-rtd161x.c new file mode 100644 index 000000000000..dd6a1008e82d --- /dev/null +++ b/drivers/thermal/realtek/sensor-rtd161x.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include "sensor.h" + +/* + * thermal sensor offset + */ +#define TM_SENSOR_CTRL0 0x00 +#define TM_SENSOR_CTRL1 0x04 +#define TM_SENSOR_CTRL2 0x08 +#define TM_SENSOR_STATUS0 0x40 +#define TM_SENSOR_STATUS1 0x44 + +/* external control reg offset */ +#define TM2_SENSOR_CTRL3 0x604 + +static void rtd1619_sensor_reset(struct thermal_sensor_device *tdev) +{ + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL0, 0x07ce7ae1); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL1, 0x00378228); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00011114); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00031114); +} + +static void sc_wrap_disable_sensor_latch(struct thermal_sensor_device *tdev) +{ + regmap_write(tdev->regmap, TM2_SENSOR_CTRL3, 0xfffffffe); +} + +static void rtd1319_sensor_reset(struct thermal_sensor_device *tdev) +{ + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL0, 0x08130000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL1, 0x003723ff); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00011114); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00031114); + + sc_wrap_disable_sensor_latch(tdev); +} + +static void rtd1619b_sensor_reset(struct thermal_sensor_device *tdev) +{ + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL0, 0x09000000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL1, 0x00364400); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00011194); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00031194); + + sc_wrap_disable_sensor_latch(tdev); +} + +static void rtd1312c_sensor_reset(struct thermal_sensor_device *tdev) +{ + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL0, 0x080A0000); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL1, 0x00372732); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00011114); + thermal_sensor_device_reg_write(tdev, TM_SENSOR_CTRL2, 0x00031114); + + sc_wrap_disable_sensor_latch(tdev); +} + +static int rtd1619_sensor_init(struct thermal_sensor_device *tdev) +{ + tdev->desc->hw_ops->reset(tdev); + return 0; +} + +static inline int rtd1619_sensor_get_temp(struct thermal_sensor_device *tdev, + int *temp) +{ + unsigned int val = 0; + + thermal_sensor_device_reg_read(tdev, TM_SENSOR_STATUS0, &val); + *temp = __signext(18, val) * 1000 / 1024; + return 0; +} + +static const struct thermal_sensor_hw_ops rtd1619_sensor_hw_ops = { + .get_temp = rtd1619_sensor_get_temp, + .reset = rtd1619_sensor_reset, + .init = rtd1619_sensor_init, +}; + +const struct thermal_sensor_desc rtd1619_sensor_desc = { + .hw_ops = &rtd1619_sensor_hw_ops, + .reset_time_ms = 12, + .status_ofs = TM_SENSOR_STATUS0, + .status_cnt = 2, +}; + +static const struct thermal_sensor_hw_ops rtd1319_sensor_hw_ops = { + .get_temp = rtd1619_sensor_get_temp, + .reset = rtd1319_sensor_reset, + .init = rtd1619_sensor_init, +}; + +const struct thermal_sensor_desc rtd1319_sensor_desc = { + .hw_ops = &rtd1319_sensor_hw_ops, + .reset_time_ms = 12, + .status_ofs = TM_SENSOR_STATUS0, + .status_cnt = 2, +}; + +static const struct thermal_sensor_hw_ops rtd1619b_sensor_hw_ops = { + .get_temp = rtd1619_sensor_get_temp, + .reset = rtd1619b_sensor_reset, + .init = rtd1619_sensor_init, +}; + +const struct thermal_sensor_desc rtd1619b_sensor_desc = { + .hw_ops = &rtd1619b_sensor_hw_ops, + .reset_time_ms = 12, + .status_ofs = TM_SENSOR_STATUS0, + .status_cnt = 2, +}; + +static const struct thermal_sensor_hw_ops rtd1312c_sensor_hw_ops = { + .get_temp = rtd1619_sensor_get_temp, + .reset = rtd1312c_sensor_reset, + .init = rtd1619_sensor_init, +}; + +const struct thermal_sensor_desc rtd1312c_sensor_desc = { + .hw_ops = &rtd1312c_sensor_hw_ops, + .reset_time_ms = 12, + .status_ofs = TM_SENSOR_STATUS0, + .status_cnt = 2, +}; diff --git a/drivers/thermal/realtek/sensor.c b/drivers/thermal/realtek/sensor.c new file mode 100644 index 000000000000..3bfe8f60ada4 --- /dev/null +++ b/drivers/thermal/realtek/sensor.c @@ -0,0 +1,320 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-only +/* + * sensor.c - Realtek generic thermal sensor driver + * + * Copyright (C) 2017-2018,2020 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../thermal_core.h" +#include "sensor.h" + +#if defined(MY_DEF_HERE) +static struct thermal_sensor_device* g_syno_tdev = NULL; +#endif /* MY_DEF_HERE */ + +static inline int thermal_sensor_hw_init(struct thermal_sensor_device *tdev) +{ + const struct thermal_sensor_desc *desc = tdev->desc; + int ret; + + if (!desc->hw_ops->init) + return 0; + + ret = desc->hw_ops->init(tdev); + tdev->last_reset_time = ktime_get(); + return ret; +} + +static inline void thermal_sensor_hw_exit(struct thermal_sensor_device *tdev) +{ + const struct thermal_sensor_desc *desc = tdev->desc; + + if (!desc->hw_ops->exit) + return; + + desc->hw_ops->exit(tdev); +} + +static inline void thermal_sensor_hw_reset(struct thermal_sensor_device *tdev) +{ + const struct thermal_sensor_desc *desc = tdev->desc; + + if (!desc->hw_ops->reset) + return; + + desc->hw_ops->reset(tdev); + tdev->last_reset_time = ktime_get(); +} + +static inline int thermal_sensor_hw_get_temp(struct thermal_sensor_device *tdev, + int *temp) +{ + const struct thermal_sensor_desc *desc = tdev->desc; + + if (!desc->hw_ops->get_temp) + return -EINVAL; + + if (desc->reset_time_ms) { + s64 t; + + t = ktime_ms_delta(ktime_add_ms(tdev->last_reset_time, desc->reset_time_ms), + ktime_get()); + if (t > 0) { + dev_info(tdev->dev, "wait %lldms to be ready\n", t); + msleep(t); + } + } + + return desc->hw_ops->get_temp(tdev, temp); +} + +static inline +void thermal_sensor_hw_dump_status(struct thermal_sensor_device *tdev) +{ + const struct thermal_sensor_desc *desc = tdev->desc; + unsigned int val; + int ret; + int i; + + if (!desc->status_cnt) + return; + + for (i = 0; i < desc->status_cnt; i++) { + ret = thermal_sensor_device_reg_read(tdev, desc->status_ofs + i * 4, &val); + dev_warn(tdev->dev, "status%d, ofs=%04x, val=%08x, ret=%d\n", + i, desc->status_ofs + i * 4, val, ret); + } +} + +static const struct thermal_zone_of_device_ops thermal_sensor_ops; +static const struct of_device_id thermal_sensor_of_match[]; + +static int thermal_sensor_device_add(struct device *dev, + struct thermal_sensor_device *tdev, + const struct thermal_sensor_desc *desc) +{ + int ret; + + tdev->dev = dev; + tdev->desc = desc; + + ret = thermal_sensor_hw_init(tdev); + if (ret) + return ret; + + tdev->tz = thermal_zone_of_sensor_register(dev, 0, tdev, + &thermal_sensor_ops); + if (IS_ERR(tdev->tz)) { + thermal_sensor_hw_exit(tdev); + return PTR_ERR(tdev->tz); + } +#if defined(MY_DEF_HERE) + g_syno_tdev = tdev; +#endif /* MY_DEF_HERE */ + + return 0; +} + +static void thermal_sensor_device_remove(struct thermal_sensor_device *tdev) +{ + thermal_zone_of_sensor_unregister(tdev->dev, tdev->tz); + thermal_sensor_hw_exit(tdev); +} + +static int thermal_sensor_get_temp(void *data, int *temp) +{ + struct thermal_sensor_device *tdev = data; + int ret; + + ret = thermal_sensor_hw_get_temp(tdev, temp); + + if (ret || !is_vaild_temp(*temp)) { + dev_warn(tdev->dev, "invalid temp=%d\n", *temp); + thermal_sensor_hw_dump_status(tdev); + + thermal_sensor_hw_reset(tdev); + + ret = thermal_sensor_hw_get_temp(tdev, temp); + } + + dev_dbg(tdev->dev, "temp=%d\n", *temp); + return ret; +} + +#if defined(MY_DEF_HERE) +int syno_rtd_get_temperature(void) +{ + int ret = -1; + int temp = 0; + + if (NULL == g_syno_tdev) { + printk(KERN_ERR "syno: thermal device not found\n"); + goto out; + } + + // rtk thermal will return degree * 1000, we need to change unit + thermal_sensor_hw_get_temp(g_syno_tdev, &temp); + ret = temp/1000; + +out: + return ret; +} +EXPORT_SYMBOL(syno_rtd_get_temperature); +#endif /* MY_DEF_HERE */ + +static int thermal_sensor_get_trend(void *data, int i, + enum thermal_trend *trend) +{ + struct thermal_sensor_device *tdev = data; + struct thermal_zone_device *tz = tdev->tz; + const struct thermal_trip *trip; + int delta; + + /* .get_trend will be called at thermal_zone_register. */ + if (!tz || !of_thermal_is_trip_valid(tz, i)) + return -EINVAL; + + trip = of_thermal_get_trip_points(tz) + i; + delta = tz->temperature - trip->temperature; + + if (-500 < delta && delta < 500) + *trend = THERMAL_TREND_STABLE; + else if (delta > 5000) + *trend = THERMAL_TREND_RAISE_FULL; + else if (delta > 0) + *trend = THERMAL_TREND_RAISING; + else + *trend = THERMAL_TREND_DROPPING; + + dev_dbg(tdev->dev, "trip%d, delta=%d, trend=%d\n", i, + delta, *trend); + + return 0; +} + +static const struct thermal_zone_of_device_ops thermal_sensor_ops = { + .get_temp = thermal_sensor_get_temp, + .get_trend = thermal_sensor_get_trend, +}; + +static int thermal_sensor_resume(struct device *dev) +{ + struct thermal_sensor_device *tdev = dev_get_drvdata(dev); + + dev_info(dev, "enter %s\n", __func__); + thermal_sensor_hw_reset(tdev); + dev_info(dev, "exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops thermal_sensor_pm_ops = { + .resume = thermal_sensor_resume, +}; + +static int thermal_sensor_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct thermal_sensor_device *tdev; + int ret = 0; + struct resource res; + const struct thermal_sensor_desc *desc; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + tdev = devm_kzalloc(dev, sizeof(*tdev), GFP_KERNEL); + if (!tdev) + return -ENOMEM; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + tdev->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!tdev->base) + return -ENOMEM; + + if (of_find_property(np, "realtek,scpu-wrapper", NULL)) { + tdev->regmap = syscon_regmap_lookup_by_phandle(np, + "realtek,scpu-wrapper"); + if (IS_ERR(tdev->regmap)) + return PTR_ERR(tdev->regmap); + } + + ret = thermal_sensor_device_add(dev, tdev, desc); + if (ret) + dev_err(dev, "failed to add thermal sensor: %d\n", ret); + platform_set_drvdata(pdev, tdev); + return 0; +} + +static int thermal_sensor_remove(struct platform_device *pdev) +{ + struct thermal_sensor_device *tdev = platform_get_drvdata(pdev); + + thermal_sensor_device_remove(tdev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static const struct of_device_id thermal_sensor_of_match[] = { + { + .compatible = "realtek,rtd119x-thermal-sensor", + .data = &rtd119x_sensor_desc, + }, + { + .compatible = "realtek,rtd129x-thermal-sensor", + .data = &rtd129x_sensor_desc, + }, + { + .compatible = "realtek,rtd139x-thermal-sensor", + .data = &rtd139x_sensor_desc, + }, + { + .compatible = "realtek,rtd161x-thermal-sensor", + .data = &rtd1619_sensor_desc, + }, + { + .compatible = "realtek,rtd131x-thermal-sensor", + .data = &rtd1319_sensor_desc, + }, + { + .compatible = "realtek,rtd1619b-thermal-sensor", + .data = &rtd1619b_sensor_desc, + }, + { .compatible = "realtek,rtd1312c-thermal-sensor", .data = &rtd1312c_sensor_desc, }, + {} +}; +MODULE_DEVICE_TABLE(of, thermal_sensor_of_match); + +static struct platform_driver thermal_sensor_drv = { + .driver = { + .name = "rtk-thermal-sensor", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(thermal_sensor_of_match), + .pm = &thermal_sensor_pm_ops, + }, + .probe = thermal_sensor_probe, + .remove = thermal_sensor_remove, +}; +module_platform_driver(thermal_sensor_drv); + +MODULE_DESCRIPTION("Realtek Thermal Sensor Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Cheng-Yu Lee "); diff --git a/drivers/thermal/realtek/sensor.h b/drivers/thermal/realtek/sensor.h new file mode 100644 index 000000000000..5ec65045f2d6 --- /dev/null +++ b/drivers/thermal/realtek/sensor.h @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2018 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __REALTEK_THERMAL_H +#define __REALTEK_THERMAL_H + +#include +#include +#include +#include +#include +#include +#include + +struct thermal_sensor_device; +struct thermal_cooling_device; + +struct thermal_sensor_hw_ops { + int (*init)(struct thermal_sensor_device *); + void (*exit)(struct thermal_sensor_device *); + void (*reset)(struct thermal_sensor_device *); + int (*get_temp)(struct thermal_sensor_device *, int *); +}; + +struct thermal_sensor_desc { + const struct thermal_sensor_hw_ops *hw_ops; + int reset_time_ms; + int status_ofs; + int status_cnt; +}; + +struct thermal_sensor_device { + struct device *dev; + const struct thermal_zone_of_device_ops *ops; + struct thermal_zone_device *tz; + void *base; + struct regmap *regmap; + + const struct thermal_sensor_desc *desc; + struct thermal_sensor *sensors; + + void *priv_data; + ktime_t last_reset_time; +}; + +static inline +int thermal_sensor_device_reg_read(struct thermal_sensor_device *tdev, + int offset, unsigned int *val) +{ + *val = readl(tdev->base + offset); + return 0; +} + +static inline +int thermal_sensor_device_reg_write(struct thermal_sensor_device *tdev, + int offset, unsigned int val) +{ + writel(val, tdev->base + offset); + return 0; +} + + +extern const struct thermal_sensor_desc rtd119x_sensor_desc; +extern const struct thermal_sensor_desc rtd129x_sensor_desc; +extern const struct thermal_sensor_desc rtd139x_sensor_desc; +extern const struct thermal_sensor_desc rtd1619_sensor_desc; +extern const struct thermal_sensor_desc rtd1319_sensor_desc; +extern const struct thermal_sensor_desc rtd1619b_sensor_desc; +extern const struct thermal_sensor_desc rtd1312c_sensor_desc; + +/* helper function */ +static inline int __signext(int signb, unsigned int v) +{ + int x = 31 - signb; + + return ((int)(v << x)) >> x; +} + +static inline int is_vaild_temp(int temp) +{ + if (temp < -3000 || temp > 150000) + return 0; + return 1; +} + +static inline bool cdev_is_cpufreq(struct thermal_cooling_device *cdev) +{ + return !strncmp("thermal-cpufreq-0", cdev->type, THERMAL_NAME_LENGTH); +} + +#endif diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index e4f4b2186bce..9e965a51469a 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-1.0+ /* * n_tty.c --- implements the N_TTY line discipline. @@ -50,6 +53,11 @@ #include #include +#ifdef MY_ABC_HERE +#include +extern int gSynoForbidConsole; +#endif /* MY_ABC_HERE */ + /* * Until this number of characters is queued in the xmit buffer, select will * return "we have room for writes". @@ -1696,6 +1704,19 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, { struct n_tty_data *ldata = tty->disc_data; int room, n, rcvd = 0, overflow; +#ifdef MY_ABC_HERE + static unsigned long last_jiffies = INITIAL_JIFFIES; + + if (1 == gSynoForbidConsole && !strcmp(tty->name, "ttyS0")) { + if (time_after(jiffies, last_jiffies + msecs_to_jiffies(3000))) { + if (NULL != func_synobios_event_handler) { + func_synobios_event_handler(SYNO_EVENT_CONSOLE_PROHIBIT, 0); + } + last_jiffies = jiffies; + } + return count; + } +#endif /* MY_ABC_HERE */ down_read(&tty->termios_rwsem); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index cae61d1ebec5..9ddd8d234406 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Universal/legacy driver for 8250/16550-type serial ports @@ -42,6 +45,21 @@ #include "8250.h" +#ifdef MY_ABC_HERE +#include +#include +#include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +extern char gszSynoTtyS0[50]; +extern char gszSynoTtyS1[50]; +extern char gszSynoTtyS2[50]; + +static unsigned long syno_parse_ttys_port(char* s); +#endif /* MY_ABC_HERE */ + /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option @@ -538,8 +556,42 @@ static void __init serial8250_isa_init_ports(void) i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++, up++) { struct uart_port *port = &up->port; - +#ifdef MY_ABC_HERE + //If ttyS is serial we have to replace the port here, cause there is no + //additional driver will fill the serial8250_ports. + char *str; + if ((0 == i) && (!strncmp(gszSynoTtyS0, "serial", 6))) { + str = &gszSynoTtyS0[6]; + if (syno_parse_ttys_port(str)) { + port->iobase = syno_parse_ttys_port(str); + } else { + port->iobase = old_serial_port[i].port; + } + } else if ((1 == i) && (!strncmp(gszSynoTtyS1, "serial", 6))) { + str = &gszSynoTtyS1[6]; + if (syno_parse_ttys_port(str)) { + port->iobase = syno_parse_ttys_port(str); + } else { + port->iobase = old_serial_port[i].port; + } + } else if ((1 == i) && (!strncmp(gszSynoTtyS2, "serial", 6))) { + str = &gszSynoTtyS2[6]; + if (syno_parse_ttys_port(str)) { + port->iobase = syno_parse_ttys_port(str); + } else { + port->iobase = old_serial_port[i].port; + } + } else if ((2 == i) && (!strncmp(gszSynoTtyS2, "serial", 6))) { + str = &gszSynoTtyS2[6]; + if (syno_parse_ttys_port(str)) { + port->iobase = syno_parse_ttys_port(str); + } else { + port->iobase = old_serial_port[i].port; + } + } +#else /* MY_ABC_HERE */ port->iobase = old_serial_port[i].port; +#endif /* MY_ABC_HERE */ port->irq = irq_canonicalize(old_serial_port[i].irq); port->irqflags = 0; port->uartclk = old_serial_port[i].baud_base * 16; @@ -576,6 +628,20 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) } } +#ifdef MY_ABC_HERE +void syno_uart_write(struct tty_port *port, char *buf, int size) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + int i = 0; + + for (i = 0; i < size; i++) { + serial_port_out(uport, UART_TX, *(buf + i)); + } +} +EXPORT_SYMBOL(syno_uart_write); +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_SERIAL_8250_CONSOLE static void univ8250_console_write(struct console *co, const char *s, @@ -681,11 +747,35 @@ static struct console univ8250_console = { .data = &serial8250_reg, }; +#ifdef MY_ABC_HERE +struct console kt_console = { + .name = "ttyS", + .write = univ8250_console_write, + .device = uart_console_device, + .setup = univ8250_console_setup, + .exit = univ8250_console_exit, + .match = univ8250_console_match, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, + .index = SYNO_OOB_TTY, + .data = &serial8250_reg, +}; + +void kt_console_init(void) +{ + register_console(&kt_console); + univ8250_console_setup(&kt_console, NULL); +} +#endif /* MY_ABC_HERE */ + static int __init univ8250_console_init(void) { if (nr_uarts == 0) return -ENODEV; +#ifdef MY_ABC_HERE + return -ENODEV; +#endif /* MY_ABC_HERE */ + serial8250_isa_init_ports(); register_console(&univ8250_console); return 0; @@ -915,28 +1005,424 @@ static struct platform_device *serial8250_isa_devs; */ static DEFINE_MUTEX(serial_mutex); +#ifdef MY_ABC_HERE +static unsigned long syno_parse_ttys_port(char* s) +{ + unsigned long Ret = 0; + char *e; + + if (*s == ',') + ++s; + + if (!strncmp(s, "0x", 2)) { + Ret = simple_strtoul(s, &e, 16); + } + + return Ret; +} + +static unsigned long syno_parse_ttys_pci(char *s) +{ + unsigned long Ret = 0; + u8 bus, slot, func; + u32 bar0; + char *e; + + if (*s == ',') + ++s; + + if (*s == 0) + goto End; + + bus = (u8)simple_strtoul(s, &e, 16); + s = e; + + if (*s != ':') + goto End; + + ++s; + slot = (u8)simple_strtoul(s, &e, 16); + s = e; + + if (*s != '.') + goto End; + + ++s; + func = (u8)simple_strtoul(s, &e, 16); + s = e; + + /* A baud might be following */ + if (*s == ',') + s++; + + bar0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); + + if (bar0 & 0x01) { + /* pci is IO mapped and port is also IO mapped */ + Ret = bar0 & 0xfffffffc; + } else if (!(bar0 & 0x01)) { + /* pci is IO mapped and port is also IO mapped */ + Ret = bar0 & 0xfffffff0; + } + +End: + return Ret; +} + +static bool syno_compare_tty_pci(char *str1, char *str2) +{ + bool bRet = false; + u8 bus, slot, func; + u8 bus2, slot2, func2; + char *e; + + //,0x0:0x1a.0x0,115200 + if (*str1 == ',') + ++str1; + bus = (u8)simple_strtoul(str1, &e, 16); + str1 = e; + + if (*str1 != ':') + goto End; + ++str1; + slot = (u8)simple_strtoul(str1, &e, 16); + + str1 = e; + if (*str1 != '.') + goto End; + ++str1; + func = (u8)simple_strtoul(str1, &e, 16); + + //0000:02:00.1 + str2+=5; + bus2 = (u8)simple_strtoul(str2, &e, 16); + str2 = e; + + if (*str2 != ':') + goto End; + ++str2; + slot2 = (u8)simple_strtoul(str2, &e, 16); + + str2 = e; + if (*str2 != '.') + goto End; + ++str2; + func2 = (u8)simple_strtoul(str2, &e, 16); + + if(bus == bus2 && slot == slot2 && func == func2) { + bRet = true; + } +End: + return bRet; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +#define DT_TTY_NODE "ttyS" +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size); +extern int syno_compare_dts_pciepath(const struct pci_dev *pdev, const struct device_node *pDeviceNode); + +/** + * lookup_internal_slot - lookup device tree to find corresponding internal slot of the ata_port + * @ap [IN]: query ata_port + * + * return 1: match + * 0: slot not found + */ +int pcipath_uart_port_match(char* str, const struct uart_port *port) +{ + int ret = 0; + char sztemp[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (NULL == str || NULL == port) { + goto END; + } + + if (*str == ',') + ++str; + + if (-1 == syno_pciepath_dts_pattern_get(to_pci_dev(port->dev), sztemp, sizeof(sztemp))) { + goto END; + } + + if (0 == strncmp(str, sztemp, strlen(sztemp))) { + ret = 1; + } + +END: + return ret; +} + +bool dts_uart_port_match(struct uart_port *port, const int uart_index) +{ + bool ret = false; + int index = -1; + struct device_node *pSlotNode = NULL; + const char *addr_type = NULL; + int err = 0; + u32 base_addr = 0; + + if (NULL == of_root) { + goto END; + } + for_each_child_of_node(of_root, pSlotNode) { + // get index number of tty, e.g. /ttyS@2 --> 2 + if (!pSlotNode->full_name || 1 != sscanf(pSlotNode->full_name, DT_TTY_NODE"@%d", &index)) { + continue; + } + if (uart_index == index) { + break; + } + } + + if (NULL == pSlotNode) { + goto END; + } + + err = of_property_read_string(pSlotNode, "addr_type", &addr_type); + if (err < 0) { + of_node_put(pSlotNode); + goto END; + } + + if (!strcmp(addr_type, "pcie")) { + if (dev_is_pci(port->dev)) { + ret = (0 == syno_compare_dts_pciepath(to_pci_dev(port->dev), pSlotNode) ? true : false); + } else { + ret = false; + } + } else if (!strcmp(addr_type, "io")){ + of_property_read_u32(pSlotNode, "base", &base_addr); + ret = (port->iobase == base_addr? true : false); + } else if (!strcmp(addr_type, "mmio")){ + of_property_read_u32(pSlotNode, "base", &base_addr); + ret = ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == base_addr? true : false); + } else { + // unknown type + ret = false; + } + + // + // TODO: Uart port is found + // Set uart configs if there are some settings in dts. + // + //if (ret) { + // Set configs + //} + + of_node_put(pSlotNode); + +END: + return ret; +} +#endif /* MY_ABC_HERE */ + static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) { int i; +#ifdef MY_ABC_HERE + char *str; + struct pci_dev *pdev = NULL; + char *root_port = NULL; + int iTtyCount = 0; + + if (0 != strcmp(gszSynoTtyS0, "")) { + iTtyCount++; + } + if (0 != strcmp(gszSynoTtyS1, "")) { + iTtyCount++; + } + if (0 != strcmp(gszSynoTtyS2, "")) { + iTtyCount++; + } + + switch (port->iotype) { + case UPIO_PORT: + case UPIO_HUB6: + if (!strncmp(gszSynoTtyS0, "serial", 6)) { + str = &gszSynoTtyS0[6]; + if (port->iobase == syno_parse_ttys_port(str)) { + return &serial8250_ports[0]; + } + } + + if (!strncmp(gszSynoTtyS1, "serial", 6)){ + str = &gszSynoTtyS1[6]; + if (port->iobase == syno_parse_ttys_port(str)) { + return &serial8250_ports[1]; + } + } + + if (!strncmp(gszSynoTtyS2, "serial", 6)){ + str = &gszSynoTtyS2[6]; + if (port->iobase == syno_parse_ttys_port(str)) { + return &serial8250_ports[2]; + } + } + +#ifdef MY_ABC_HERE + if (!strcmp(gszSynoTtyS0, "")) { + if (dts_uart_port_match(port, 0)) { + iTtyCount++; + return &serial8250_ports[0]; + } + } + + if (!strcmp(gszSynoTtyS1, "")) { + if (dts_uart_port_match(port, 1)) { + iTtyCount++; + return &serial8250_ports[1]; + } + } + + if (!strcmp(gszSynoTtyS2, "")) { + if (dts_uart_port_match(port, 2)) { + iTtyCount++; + return &serial8250_ports[2]; + } + } +#endif /* MY_ABC_HERE */ + + /* fall through */ + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_AU: + case UPIO_TSI: + if (port->dev->bus && !strncmp("pci", port->dev->bus->name, 3)) { + pdev = to_pci_dev(port->dev); + if (pdev && pdev->bus->self) { + root_port = (char*)(dev_name(&(pdev->bus->self->dev))); + } + } + if (!strncmp(gszSynoTtyS0, "pciserial", 9)) { + str = &gszSynoTtyS0[9]; + if (syno_compare_tty_pci(str, (char*)dev_name(port->dev)) || + (root_port && syno_compare_tty_pci(str, root_port)) || + ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == syno_parse_ttys_pci(str))) { + return &serial8250_ports[0]; + } + } + if (!strncmp(gszSynoTtyS1, "pciserial", 9)) { + str = &gszSynoTtyS1[9]; + if (syno_compare_tty_pci(str, (char*)dev_name(port->dev)) || + (root_port && syno_compare_tty_pci(str, root_port)) || + ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == syno_parse_ttys_pci(str))) { + return &serial8250_ports[1]; + } + } + if (!strncmp(gszSynoTtyS2, "pciserial", 9)) { + str = &gszSynoTtyS2[9]; + if (syno_compare_tty_pci(str, (char*)dev_name(port->dev)) || + (root_port && syno_compare_tty_pci(str, root_port)) || + ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == syno_parse_ttys_pci(str))) { + return &serial8250_ports[2]; + } + } + if (!strncmp(gszSynoTtyS0, "mmio", 4)) { + str = &gszSynoTtyS0[4]; + if ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == syno_parse_ttys_port(str)) { + return &serial8250_ports[0]; + } + } + + if (!strncmp(gszSynoTtyS1, "mmio", 4)) { + str = &gszSynoTtyS1[4]; + if ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == syno_parse_ttys_port(str)) { + return &serial8250_ports[1]; + } + } + + if (!strncmp(gszSynoTtyS2, "mmio", 4)) { + str = &gszSynoTtyS2[4]; + if ((virt_to_phys((volatile void *)port->mapbase) & 0xffffffff) == syno_parse_ttys_port(str)) { + return &serial8250_ports[2]; + } + } + +#ifdef MY_ABC_HERE + if (!strncmp(gszSynoTtyS0, "pcifull", 7)) { + str = &gszSynoTtyS0[7]; + if (1 == pcipath_uart_port_match(str, port)) { + return &serial8250_ports[0]; + } + } + + if (!strncmp(gszSynoTtyS1, "pcifull", 7)) { + str = &gszSynoTtyS1[7]; + if (1 == pcipath_uart_port_match(str, port)) { + return &serial8250_ports[1]; + } + } + + if (!strncmp(gszSynoTtyS2, "pcifull", 7)) { + str = &gszSynoTtyS2[7]; + if (1 == pcipath_uart_port_match(str, port)) { + return &serial8250_ports[2]; + } + } + + if (!strcmp(gszSynoTtyS0, "")) { + if (dts_uart_port_match(port, 0)) { + iTtyCount++; + return &serial8250_ports[0]; + } + } + + if (!strcmp(gszSynoTtyS1, "")) { + if (dts_uart_port_match(port, 1)) { + iTtyCount++; + return &serial8250_ports[1]; + } + } + + if (!strcmp(gszSynoTtyS2, "")) { + if (dts_uart_port_match(port, 2)) { + iTtyCount++; + return &serial8250_ports[2]; + } + } +#endif /* MY_ABC_HERE */ + break; + default: + break; + } +#endif /* MY_ABC_HERE */ + /* * First, find a port entry which matches. */ + +#ifdef MY_ABC_HERE + for (i = iTtyCount; i < nr_uarts; i++) +#else /* MY_ABC_HERE */ for (i = 0; i < nr_uarts; i++) +#endif /* MY_ABC_HERE */ if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; /* try line number first if still available */ i = port->line; if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN && - serial8250_ports[i].port.iobase == 0) + serial8250_ports[i].port.iobase == 0 +#ifdef MY_ABC_HERE + && i > (iTtyCount - 1) +#endif /* MY_ABC_HERE */ + ) + return &serial8250_ports[i]; /* * We didn't find a matching entry, so look for the first * free entry. We look for one which hasn't been previously * used (indicated by zero iobase). */ +#ifdef MY_ABC_HERE + for (i = iTtyCount; i < nr_uarts; i++) +#else /* MY_ABC_HERE */ for (i = 0; i < nr_uarts; i++) +#endif /* MY_ABC_HERE */ if (serial8250_ports[i].port.type == PORT_UNKNOWN && serial8250_ports[i].port.iobase == 0) return &serial8250_ports[i]; @@ -945,7 +1431,11 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * That also failed. Last resort is to find any entry which * doesn't have a real port associated with it. */ +#ifdef MY_ABC_HERE + for (i = iTtyCount; i < nr_uarts; i++) +#else /* MY_ABC_HERE */ for (i = 0; i < nr_uarts; i++) +#endif /* MY_ABC_HERE */ if (serial8250_ports[i].port.type == PORT_UNKNOWN) return &serial8250_ports[i]; @@ -1019,6 +1509,9 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->rs485_start_tx = up->rs485_start_tx; uart->rs485_stop_tx = up->rs485_stop_tx; uart->dma = up->dma; +#ifdef MY_ABC_HERE + uart->blXmitrCheck = true; +#endif /* MY_ABC_HERE */ /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 13929ab64dce..24874706730b 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Probe module for 8250/16550-type PCI serial ports. @@ -1942,7 +1945,6 @@ pci_moxa_setup(struct serial_private *priv, #define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM 0x10E9 #define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8 - #define PCI_DEVICE_ID_MOXA_CP102E 0x1024 #define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 #define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 @@ -3910,7 +3912,9 @@ serial_pci_matches(const struct pciserial_board *board, board->reg_shift == guessed->reg_shift && board->first_offset == guessed->first_offset; } - +#ifdef MY_ABC_HERE +extern void kt_console_init(void); +#endif /* MY_ABC_HERE */ struct serial_private * pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) { @@ -3996,6 +4000,14 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) break; } } + +#ifdef MY_ABC_HERE + if (PCI_VENDOR_ID_REALTEK == dev->vendor && + 0x816a == dev->device) { + kt_console_init(); + } +#endif /* MY_ABC_HERE */ + priv->nr = i; priv->board = board; return priv; @@ -5642,9 +5654,12 @@ static const struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_1_115200 }, +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ { PCI_VENDOR_ID_REALTEK, 0x816b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_1_115200 }, +#endif /* MY_ABC_HERE */ /* Fintek PCI serial cards */ { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 6d9c494bed7d..d7967b205a09 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Base port operations for 8250/16550-type serial ports @@ -52,6 +55,15 @@ #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) +#ifdef MY_ABC_HERE +extern int (*syno_test_list)(unsigned char, struct tty_struct *); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +extern int (*syno_get_current)(unsigned char, struct tty_struct *); +#endif /* MY_ABC_HERE */ + /* * Here we define the default xmit fifo size used for each type of UART. */ @@ -1765,6 +1777,20 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) if (uart_prepare_sysrq_char(port, ch)) return; +#ifdef MY_ABC_HERE + if (NULL != syno_test_list && syno_test_list(ch, port->state->port.tty)) { + return; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (NULL != syno_get_current && syno_get_current(ch, port->state->port.tty)) { + return; + } else if (NULL != func_synobios_event_handler && !strcmp(port->state->port.tty->name, SYNO_MICROP_TTY_NAME)) { + func_synobios_event_handler(SYNO_EVENT_MICROP_GET, 0); + } +#endif /* MY_ABC_HERE */ + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); } EXPORT_SYMBOL_GPL(serial8250_read_char); @@ -2061,6 +2087,78 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) serial8250_rpm_put(up); } +/* + * Wait for transmitter & holding register to empty + */ +#ifdef MY_ABC_HERE +static void syno_kt_wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int status, tmout = 10000; + static int iCtsTimeoutCt = 0; + static int iTransTimeoutCt = 0; + static int iTransCt = 0; + struct console *con = NULL; + + if (false == up->blXmitrCheck) { + return; + } + /* Wait up to 10ms for the character(s) to be sent. */ + iTransCt++; + for (;;) { + status = serial_in(up, UART_LSR); + + up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + + if ((status & bits) == bits) + break; + if (--tmout == 0) { + iTransTimeoutCt++; + break; + } + udelay(1); + } + if (SYNO_TX_CHECK_COUNT <= iTransCt) { + if (SYNO_TX_CHECK_THRESHOLD <= iTransTimeoutCt) { + for_each_console(con) { + if (SYNO_OOB_TTY == con->index) { + con->flags &= ~CON_ENABLED; + up->blXmitrCheck = false; + } + } + } + iTransCt = 0; + iTransTimeoutCt = 0; + } + + /* Wait up to 1s for flow control if necessary */ + { + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + udelay(1); + touch_nmi_watchdog(); + } + if (unlikely(0 == tmout)) { + iCtsTimeoutCt++; + } else { + iCtsTimeoutCt = 0; + } + // stuck more than 10s, disable CTS check + if (SYNO_CTS_CHECK_COUNT <= iCtsTimeoutCt) { + for_each_console(con) { + if (SYNO_OOB_TTY == con->index) { + con->flags &= ~CON_ENABLED; + up->blXmitrCheck = false; + } + } + iCtsTimeoutCt = 0; + } + } +} +#endif /* MY_ABC_HERE */ + /* * Wait for transmitter & holding register to empty */ @@ -3117,8 +3215,70 @@ static ssize_t rx_trig_bytes_store(struct device *dev, static DEVICE_ATTR_RW(rx_trig_bytes); +#ifdef MY_ABC_HERE +static ssize_t serial8250_get_attr_console_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + + return snprintf(buf, PAGE_SIZE, "%d\n", up->blXmitrCheck); +} + +static ssize_t serial8250_set_attr_console_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + unsigned char enable; + struct console *con = NULL; + unsigned long flags; + int ret; + + if (!count) + return -EINVAL; + + if (SYNO_OOB_TTY != up->port.line) { + return count; + } + + ret = kstrtou8(buf, 10, &enable); + if (ret < 0) + return ret; + + for_each_console(con) { + if (SYNO_OOB_TTY == con->index) { + spin_lock_irqsave(&uport->lock, flags); + if (1 == enable) { + con->flags |= CON_ENABLED; + up->blXmitrCheck = true; + } else if (0 == enable) { + con->flags &= ~CON_ENABLED; + up->blXmitrCheck = false; + } + spin_unlock_irqrestore(&uport->lock, flags); + } + } + + return count; +} + +static DEVICE_ATTR(console_enable, S_IRUSR | S_IWUSR | S_IRGRP, + serial8250_get_attr_console_enable, + serial8250_set_attr_console_enable); +#endif /* MY_ABC_HERE */ + static struct attribute *serial8250_dev_attrs[] = { &dev_attr_rx_trig_bytes.attr, +#ifdef MY_ABC_HERE + &dev_attr_console_enable.attr, +#endif /* MY_ABC_HERE */ NULL }; @@ -3266,7 +3426,15 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) { struct uart_8250_port *up = up_to_u8250p(port); +#ifdef MY_ABC_HERE + if (SYNO_OOB_TTY == up->port.line) { + syno_kt_wait_for_xmitr(up, UART_LSR_THRE); + } else { +#endif /* MY_ABC_HERE */ wait_for_xmitr(up, UART_LSR_THRE); +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ serial_port_out(port, UART_TX, ch); } @@ -3385,7 +3553,11 @@ static unsigned int probe_baud(struct uart_port *port) int serial8250_console_setup(struct uart_port *port, char *options, bool probe) { +#ifdef MY_ABC_HERE + int baud = 115200; +#else /* MY_ABC_HERE */ int baud = 9600; +#endif /* MY_ABC_HERE */ int bits = 8; int parity = 'n'; int flow = 'n'; diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index a8bfb654d490..13e6ec447e95 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -11,6 +11,18 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o 8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o +ifeq ($(CONFIG_SYNO_ICELAKED), y) +obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o +endif # CONFIG_SYNO_ICELAKED +ifeq ($(CONFIG_SYNO_EPYC7002), y) +obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o +else ifeq ($(CONFIG_SYNO_EPYC7002SOFS), y) +obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o +else ifeq ($(CONFIG_SYNO_V1000), y) +obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o +else ifeq ($(CONFIG_SYNO_EPYC7003NTB), y) +obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o +endif # CONFIG_SYNO_EPYC7002 || CONFIG_SYNO_EPYC7002SOFS || CONFIG_SYNO_V1000 || CONFIG_SYNO_EPYC7003NTB obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o @@ -26,7 +38,12 @@ obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o +ifeq ($(CONFIG_SYNO_EPYC7002), y) +else ifeq ($(CONFIG_SYNO_EPYC7002SOFS), y) +else ifeq ($(CONFIG_SYNO_V1000), y) +else obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o +endif # CONFIG_SYNO_EPYC7002 || CONFIG_SYNO_EPYC7002SOFS || CONFIG_SYNO_V1000 obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o @@ -35,7 +52,9 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o +ifneq ($(CONFIG_SYNO_ICELAKED), y) obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o +endif # CONFIG_SYNO_ICELAKED obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 68a0ff605476..203ef47e8b63 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Driver core for serial ports @@ -29,10 +32,24 @@ #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ + + /* * This is used to lock changes in serial line configuration. */ static DEFINE_MUTEX(port_mutex); +#ifdef MY_ABC_HERE +static DEFINE_SPINLOCK(ttyS1_lock); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +extern int gSynoForbidConsole; +#endif /* MY_ABC_HERE */ /* * lockdep: port->lock is initialized in two places, but we @@ -582,6 +599,15 @@ static int uart_write(struct tty_struct *tty, unsigned long flags; int c, ret = 0; +#ifdef MY_ABC_HERE + /* We need to delay 150 ms avoid micro p buffer queue overflow */ + if (!strcmp(tty->name, "ttyS1")) { + spin_lock(&ttyS1_lock); + mdelay(150); + spin_unlock(&ttyS1_lock); + } +#endif /* MY_ABC_HERE */ + /* * This means you called this function _after_ the port was * closed. No cookie for you. @@ -598,6 +624,13 @@ static int uart_write(struct tty_struct *tty, return 0; } +#ifdef MY_ABC_HERE + if (1 == gSynoForbidConsole && !strcmp(tty->name, "ttyS0")) { + uart_port_unlock(port, flags); + return count; + } +#endif /* MY_ABC_HERE */ + while (port) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) @@ -1942,6 +1975,12 @@ void uart_console_write(struct uart_port *port, const char *s, { unsigned int i; +#ifdef MY_ABC_HERE + if (1 == gSynoForbidConsole) { + return; + } +#endif /* MY_ABC_HERE */ + for (i = 0; i < count; i++, s++) { if (*s == '\n') putchar(port, '\r'); @@ -2375,7 +2414,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, if (port->type != PORT_UNKNOWN) { unsigned long flags; +#ifdef MY_DEF_HERE +#else uart_report_port(drv, port); +#endif /* Power up port for set_mctrl() */ uart_change_pm(state, UART_PM_STATE_ON); @@ -2403,6 +2445,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, */ if (!uart_console(port)) uart_change_pm(state, UART_PM_STATE_OFF); +#ifdef MY_DEF_HERE + uart_report_port(drv, port); +#endif } } @@ -2811,6 +2856,56 @@ static ssize_t console_store(struct device *dev, return ret < 0 ? ret : count; } +#ifdef MY_ABC_HERE +#define UART_MSR 0x6 +static ssize_t msr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + unsigned int msr = 0; + + msr = uport->serial_in(uport, UART_MSR); + return snprintf(buf, PAGE_SIZE, "%x\n", msr); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size); +static void syno_pciepath_enum(struct device *dev, char *buf) { + struct pci_dev *pdev = NULL; + char sztemp[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (NULL == buf || NULL == dev) { + return; + } + pdev = to_pci_dev(dev); + + if (-1 == syno_pciepath_dts_pattern_get(pdev, sztemp, sizeof(sztemp))) { + return; + } + + snprintf(buf, 512, "%spciepath=%s", buf, sztemp); +} + +static ssize_t syno_pcipath_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + char szPciePath[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (dev_is_pci(uport->dev)) { + syno_pciepath_enum(uport->dev, szPciePath); + } + + return sprintf(buf, "%s\n", szPciePath); +} +#endif /* MY_ABC_HERE */ + static DEVICE_ATTR_RO(uartclk); static DEVICE_ATTR_RO(type); static DEVICE_ATTR_RO(line); @@ -2825,6 +2920,12 @@ static DEVICE_ATTR_RO(io_type); static DEVICE_ATTR_RO(iomem_base); static DEVICE_ATTR_RO(iomem_reg_shift); static DEVICE_ATTR_RW(console); +#ifdef MY_ABC_HERE +static DEVICE_ATTR_RO(msr); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static DEVICE_ATTR_RO(syno_pcipath); +#endif /* MY_ABC_HERE */ static struct attribute *tty_dev_attrs[] = { &dev_attr_uartclk.attr, @@ -2841,6 +2942,12 @@ static struct attribute *tty_dev_attrs[] = { &dev_attr_iomem_base.attr, &dev_attr_iomem_reg_shift.attr, &dev_attr_console.attr, +#ifdef MY_ABC_HERE + &dev_attr_msr.attr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &dev_attr_syno_pcipath.attr, +#endif /* MY_ABC_HERE */ NULL }; @@ -3273,5 +3380,15 @@ int uart_get_rs485_mode(struct uart_port *port) } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); +#ifdef MY_ABC_HERE +int (*syno_test_list)(unsigned char, struct tty_struct *) = NULL; +EXPORT_SYMBOL(syno_test_list); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int (*syno_get_current)(unsigned char, struct tty_struct *) = NULL; +EXPORT_SYMBOL(syno_get_current); +#endif /* MY_ABC_HERE */ + MODULE_DESCRIPTION("Serial driver core"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 959f9e121cc6..9ae0275dcf5c 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Linux Magic System Request Key Hacks @@ -175,6 +178,23 @@ static const struct sysrq_key_op sysrq_reboot_op = { const struct sysrq_key_op *__sysrq_reboot_op = &sysrq_reboot_op; +#ifdef MY_ABC_HERE +static void sysrq_handle_cf9_reboot(int key) +{ + lockdep_off(); + local_irq_enable(); + reboot_type = BOOT_CF9_FORCE; + reboot_mode = REBOOT_COLD; + emergency_restart(); +} +static struct sysrq_key_op sysrq_cf9_reboot_op = { + .handler = sysrq_handle_cf9_reboot, + .help_msg = "cf9 reboot(g)", + .action_msg = "CF9 Resetting", + .enable_mask = SYSRQ_ENABLE_BOOT, +}; +#endif /* MY_ABC_HERE */ + static void sysrq_handle_sync(int key) { emergency_sync(); @@ -464,7 +484,11 @@ static const struct sysrq_key_op *sysrq_key_table[62] = { &sysrq_term_op, /* e */ &sysrq_moom_op, /* f */ /* g: May be registered for the kernel debugger */ +#ifdef MY_ABC_HERE + &sysrq_cf9_reboot_op, /* g */ +#else /* MY_ABC_HERE */ NULL, /* g */ +#endif /* MY_ABC_HERE */ NULL, /* h - reserved for help */ &sysrq_kill_op, /* i */ #ifdef CONFIG_BLOCK diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bc5314092aa4..8eaa89b6f55d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991, 1992 Linus Torvalds @@ -1115,7 +1118,42 @@ static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_ if (!ld->ops->write) ret = -EIO; else +#ifdef MY_ABC_HERE + { + if (0 == strcmp(tty->name, "ttyS1")) { + char *prefix = "-"; + struct kvec iov = { + .iov_base = (void *)prefix, + .iov_len = 1, + }; + struct iov_iter iter; +#ifdef MY_ABC_HERE + char first_char = '\0'; + + if (copy_from_iter(&first_char, 1, from) != 1) + printk(KERN_ERR "error attempted to copy_from_iter\n"); + else + iov_iter_revert(from, 1); + + if ('+' == first_char) { + goto skip_uP_prefix; + } +#endif /* MY_ABC_HERE */ + iov_iter_kvec(&iter, WRITE, &iov, 1, iov.iov_len); + ret = do_tty_write(ld->ops->write, tty, file, &iter); + if (0 > ret) { + printk(KERN_ERR "Write uP control prefix fail!\n"); + } + } + +#ifdef MY_ABC_HERE +skip_uP_prefix: +#endif /* MY_ABC_HERE */ ret = do_tty_write(ld->ops->write, tty, file, from); + } +#else /* MY_ABC_HERE */ + ret = do_tty_write(ld->ops->write, tty, file, from); +#endif /* MY_ABC_HERE */ tty_ldisc_deref(ld); return ret; } @@ -3124,6 +3162,63 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch) } EXPORT_SYMBOL_GPL(tty_put_char); +#ifdef MY_ABC_HERE +int syno_ttys_write(const int index, const char* szBuf) +{ + int err = -1; + struct tty_driver *drv = NULL; + struct tty_struct *tty = NULL; + char *szX64Buf = NULL; + size_t cbX64Buf = strlen(szBuf) + 2; + + szX64Buf = kmalloc(cbX64Buf, GFP_KERNEL); + if (!szX64Buf) { + err = -ENOMEM; + goto Error; + } + + mutex_lock(&tty_mutex); + list_for_each_entry(drv, &tty_drivers, tty_drivers) { + if (strcmp(drv->name, "ttyS")) { + continue; + } + if (index < 0 || index >= drv->num) { + continue; + } + if (NULL == drv->ttys || NULL == drv->ttys[index]) { + continue; + } + tty = drv->ttys[index]; + } + if (!IS_ERR(tty)) + tty_kref_get(tty); + else + tty = NULL; + mutex_unlock(&tty_mutex); + + if (!tty) { + err = -ENODEV; + goto Error; + } + + memset(szX64Buf, 0, cbX64Buf); + snprintf(szX64Buf, cbX64Buf, "%c%s", '-', szBuf); + + syno_uart_write(tty->port, szX64Buf, strlen(szX64Buf)); + + mutex_lock(&tty_mutex); + tty_kref_put(tty); + mutex_unlock(&tty_mutex); + + err = 0; +Error: + if (szX64Buf) + kfree(szX64Buf); + return err; +} +EXPORT_SYMBOL(syno_ttys_write); +#endif /* MY_ABC_HERE */ + struct class *tty_class; static int tty_cdev_add(struct tty_driver *driver, dev_t dev, diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 06757b1d4aec..bbf348c3d2c1 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991, 1992 Linus Torvalds @@ -3030,6 +3033,12 @@ int vt_kmsg_redirect(int new) return kmsg_con; } +#ifdef MY_ABC_HERE +/* + * virtual terminal is not actvated in our implementation, + * so the related functions is not needed. + */ +#else /* MY_ABC_HERE */ /* * Console on virtual terminal * @@ -3125,6 +3134,7 @@ static struct console vt_console_driver = { .flags = CON_PRINTBUFFER, .index = -1, }; +#endif /* MY_ABC_HERE */ #endif /* @@ -3510,7 +3520,14 @@ static int __init con_init(void) console_unlock(); #ifdef CONFIG_VT_CONSOLE +#ifdef MY_ABC_HERE +/* + * virtual terminal is not actvated in our implementation, + * so the related functions is not needed. + */ +#else /* MY_ABC_HERE */ register_console(&vt_console_driver); +#endif /* MY_ABC_HERE */ #endif return 0; } diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 09b8d02acd99..90e4fcd3dc39 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -246,6 +246,8 @@ int vt_waitactive(int n) * * XXX It should at least call into the driver, fbdev's definitely need to * restore their engine state. --BenH + * + * Called with the console lock held. */ static int vt_kdsetmode(struct vc_data *vc, unsigned long mode) { @@ -262,7 +264,6 @@ static int vt_kdsetmode(struct vc_data *vc, unsigned long mode) return -EINVAL; } - /* FIXME: this needs the console lock extending */ if (vc->vc_mode == mode) return 0; @@ -271,12 +272,10 @@ static int vt_kdsetmode(struct vc_data *vc, unsigned long mode) return 0; /* explicitly blank/unblank the screen if switching modes */ - console_lock(); if (mode == KD_TEXT) do_unblank_screen(1); else do_blank_screen(1); - console_unlock(); return 0; } @@ -378,7 +377,10 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd, if (!perm) return -EPERM; - return vt_kdsetmode(vc, arg); + console_lock(); + ret = vt_kdsetmode(vc, arg); + console_unlock(); + return ret; case KDGETMODE: return put_user(vc->vc_mode, (int __user *)arg); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 26475b409b53..3c7b34dec1c8 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -164,6 +164,12 @@ source "drivers/usb/misc/Kconfig" source "drivers/usb/atm/Kconfig" +if SYNO_LSP_RTD1619B +config USB_PATCH_ON_RTK + bool + default y if USB_OHCI_RTK || USB_EHCI_RTK || USB_DWC3_RTK + +endif # SYNO_LSP_RTD1619B endif # USB source "drivers/usb/phy/Kconfig" diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 8aef5eb769a0..a6bfb976bf22 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * @@ -128,6 +131,12 @@ struct acm { u8 bInterval; struct usb_anchor delayed; /* writes queued for a device about to be woken */ unsigned long quirks; +#ifdef MY_DEF_HERE + rwlock_t status_lock; /* prevent reading and updating expstatus at same time */ + char **cached_expstatus; /* for key-value table of each eunit status */ + char **latest_expstatus; /* saves new fetch status in this table, then updates to expstatus */ + struct list_head syno_device_list; /* for disk name in an eunit controlled by this acm microP */ +#endif /* MY_DEF_HERE */ }; /* constants describing various quirks and errors */ diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 351ede4b5de2..2677f42f54f8 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -116,3 +116,12 @@ config USB_AUTOSUSPEND_DELAY The default value Linux has always had is 2 seconds. Change this value if you want a different delay and cannot modify the command line or module parameter. +if SYNO_LSP_RTD1619B + +config USB_RTK_HCD_TEST_MODE + bool "RTK Host CTS test mode" + default n + help + Enable RTK USB Host CTS testing mode. + +endif # SYNO_LSP_RTD1619B diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 1ef2de6e375a..f25e8705f8c8 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * devices.c @@ -47,6 +50,11 @@ #include "usb.h" +#ifdef MY_DEF_HERE +#include +#include +#endif /* MY_DEF_HERE */ + /* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */ #define ALLOW_SERIAL_NUMBER @@ -437,6 +445,62 @@ static char *usb_dump_string(char *start, char *end, } #endif /* PROC_EXTRA */ +/* return value : + * 0 : a usbdev is not a usb copy port + * 1 : the usbdev is a usb copy port + * -ENODEV : error no of_root or no usbdev + */ +#ifdef MY_DEF_HERE +static int usb_copy_support(struct usb_device *usbdev) +{ + int ret = -ENODEV; + const char* dt_usb_copy = NULL; + struct device_node *usb_slot = NULL, *usb_port = NULL; + + if (NULL == of_root || NULL == usbdev) { + goto END; + } + + for_each_child_of_node(of_root, usb_slot) { + if (!usb_slot->full_name || strncmp(usb_slot->full_name, DT_USB_SLOT, strlen(DT_USB_SLOT))) { + continue; + } + + if (0 > of_property_read_string(usb_slot, DT_USB_COPY, &dt_usb_copy) || + 0 != strncmp(dt_usb_copy, "true", strlen("true"))) { + continue; + } + + usb_port = of_get_child_by_name(usb_slot, DT_USB2); + if (0 == of_property_read_string(usb_port, DT_USB_PORT, &dt_usb_copy) && + 0 == strncmp(dt_usb_copy, dev_name(&usbdev->dev), strlen(dt_usb_copy))) { + ret = 1; + goto END; + } + of_node_put(usb_port); + usb_port = NULL; + + usb_port = of_get_child_by_name(usb_slot, DT_USB3); + if (0 == of_property_read_string(usb_port, DT_USB_PORT, &dt_usb_copy) && + 0 == strncmp(dt_usb_copy, dev_name(&usbdev->dev), strlen(dt_usb_copy))) { + ret = 1; + goto END; + } + of_node_put(usb_port); + usb_port = NULL; + } + + ret = 0; +END: + if (usb_slot) { + of_node_put(usb_slot); + } + if (usb_port) { + of_node_put(usb_port); + } + return ret; +} +#endif /* MY_DEF_HERE */ /*****************************************************************/ @@ -494,6 +558,16 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, default: speed = "??"; } + +#if defined(MY_DEF_HERE) + if(0 < usb_copy_support(usbdev)) + // Port=99 in /sys/kernel/debug/usb/devices + data_end = pages_start + sprintf(pages_start, format_topo, + bus->busnum, level, parent_devnum, + USBCOPY_PORT_LOCATION, count, usbdev->devnum, + speed, usbdev->maxchild); + else +#endif /* defined(MY_DEF_HERE) */ data_end = pages_start + sprintf(pages_start, format_topo, bus->busnum, level, parent_devnum, index, count, usbdev->devnum, diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 4dfa44d6cc3c..5700b6f2a266 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/driver.c - most of the driver model stuff for usb @@ -34,6 +37,9 @@ #include "usb.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ /* * Adds a new dynamic USBdevice ID to this driver, @@ -299,6 +305,20 @@ static int usb_probe_device(struct device *dev) return error; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +int RTK_usb_probe_device(struct device *dev) +{ + int ret = 0; + ret = usb_probe_device(dev); + return ret; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(RTK_usb_probe_device); +#endif /* MY_DEF_HERE */ +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* called from driver core with dev locked */ static int usb_unbind_device(struct device *dev) { @@ -314,6 +334,20 @@ static int usb_unbind_device(struct device *dev) return 0; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +int RTK_usb_unbind_device(struct device *dev) +{ + int ret = 0; + ret = usb_unbind_device(dev); + return ret; +} +#if defined(MY_DEF_HERE) +EXPORT_SYMBOL(RTK_usb_unbind_device); +#endif /* MY_DEF_HERE */ +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* called from driver core with dev locked */ static int usb_probe_interface(struct device *dev) { @@ -857,11 +891,38 @@ bool usb_driver_applicable(struct usb_device *udev, static int usb_device_match(struct device *dev, struct device_driver *drv) { +#ifdef MY_ABC_HERE + extern int gSynoForbidUsb; + u16 vendor_id = 0, product_id = 0; + static unsigned long last_jiffies = INITIAL_JIFFIES; +#endif /* MY_ABC_HERE */ + /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { struct usb_device *udev; struct usb_device_driver *udrv; +#ifdef MY_ABC_HERE + if (gSynoForbidUsb) { + udev = to_usb_device(dev); + vendor_id = le16_to_cpu(udev->descriptor.idVendor); + product_id = le16_to_cpu(udev->descriptor.idProduct); + if (udev->parent && USB_CLASS_HUB != udev->descriptor.bDeviceClass && !IS_SYNO_FLASH(vendor_id, product_id)) { + dev_err(&udev->dev, "USB device idVendor=%04x idProduct=%04x manufacturer=%s product=%s is prohibited!\n", + vendor_id, product_id, udev->manufacturer, udev->product); + if (time_after(jiffies, last_jiffies + msecs_to_jiffies(3000))) { + if (NULL == func_synobios_event_handler) { + dev_err(&udev->dev, "%s: Can't reference to function 'func_synobios_event_handler'\n",__func__); + } else { + func_synobios_event_handler(SYNO_EVENT_USB_PROHIBIT, 0); + } + last_jiffies = jiffies; + } + return 0; + } + } +#endif /* MY_ABC_HERE */ + /* interface drivers never match devices */ if (!is_usb_device_driver(drv)) return 0; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ec0d6c50610c..62f38167940a 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright David Brownell 2000-2002 @@ -194,7 +197,17 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, * make sure irq setup is not touched for xhci in generic hcd code */ if ((driver->flags & HCD_MASK) < HCD_USB3) { +#ifdef MY_ABC_HERE + // 8111EP EHCI controller don't support MSI, so force it on legacy mode + if (0x10EC == dev->vendor && 0x816D == dev->device) { + retval = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); + } else { +#else /* MY_ABC_HERE */ retval = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSI); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ if (retval < 0) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 95a9bae72f13..3b1f46b4d0c1 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * USB hub driver. @@ -25,10 +28,16 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include @@ -45,10 +54,23 @@ #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 #define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02 +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_USB_CTRL_MANAGER +extern int RTK_usb_reprobe_usb_storage(struct usb_device *udev); +extern bool RTK_usb_disable_hub_autosuspend(void); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ #define USB_TP_TRANSMISSION_DELAY 40 /* ns */ #define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ #define USB_PING_RESPONSE_TIME 400 /* ns */ +#if defined(MY_DEF_HERE) +#define SYNO_SERIAL_EXT_HUB "syno.ext.hub" +#endif /* MY_DEF_HERE */ + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -108,6 +130,11 @@ MODULE_PARM_DESC(use_both_schemes, DECLARE_RWSEM(ehci_cf_port_reset_rwsem); EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); +#ifdef MY_ABC_HERE +#define SERIAL_LEN 33 +DEFINE_MUTEX(hub_init_mutex); +#endif /* MY_ABC_HERE */ + #define HUB_DEBOUNCE_TIMEOUT 2000 #define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STABLE 100 @@ -411,6 +438,28 @@ static int get_hub_descriptor(struct usb_device *hdev, return -EINVAL; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_RTK_HCD_TEST_MODE +int get_hub_descriptor_port(struct usb_device *hdev, void *data, int size, int port1) +{ + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_device *dev = hub->ports[port1 - 1]->child; + + if (dev) { + memset(data, 0, size); + + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_DEVICE << 8), 0, data, size, + USB_CTRL_GET_TIMEOUT); + + } else + return 0; +} +EXPORT_SYMBOL_GPL(get_hub_descriptor_port); +#endif //CONFIG_USB_RTK_HCD_TEST_MODE + +#endif /* MY_DEF_HERE */ /* * USB 2.0 spec Section 11.24.2.1 */ @@ -956,6 +1005,239 @@ static int hub_set_port_link_state(struct usb_hub *hub, int port1, USB_PORT_FEAT_LINK_STATE); } +#ifdef MY_ABC_HERE +#define IS_XHCI(hcd) (hcd->driver->flags & HCD_USB3) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct device_node *syno_usb_hub_node_get(const struct usb_device *hdev, const int portnum); +static inline int get_vbus_gpio(struct usb_hub *hub, int port) { +#ifdef MY_ABC_HERE + struct usb_port *port_dev = hub->ports[port - 1]; + + if (0 <= port_dev->syno_vbus_gpp) { + return port_dev->syno_vbus_gpp; + } +#else /* MY_ABC_HERE */ + struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); + + /* A38x only has 1 port per host controller */ + if (0 <= hcd->vbus_gpio_pin) { + return hcd->vbus_gpio_pin; + } +#endif /* MY_ABC_HERE */ + return -EINVAL; +} + +static inline int +syno_usb_set_power(struct usb_hub *hub, int enable, int port) { + int usb_vbus_gpio = get_vbus_gpio(hub, port); + int ret = -EINVAL; + + if (NULL == syno_usb_hub_node_get(hub->hdev, port)) { + dev_dbg(hub->intfdev, "for port %d is not a syno usb port\n", port); + goto END; + } + + if (0 > usb_vbus_gpio) { + dev_err(hub->intfdev, + "cannot find VBUS gpio for port %d\n", port); + goto END; + } + + /* + * Truth Table for setting gpio with polarity: + * enable Polarity !(enable ^ Polarity) + * 0 0 1 + * 1 0 0 + * 0 1 0 + * 1 1 1 + */ + enable = !(enable ^ hub->ports[port-1]->syno_vbus_gpp_pol); + SYNO_GPIO_WRITE(usb_vbus_gpio, enable); + ret = 0; +END: + return ret; +} + +/*PORTING: + * Measure the power-off time (5V -> 0V) to make sure our delay time is enough. + * Some devices may need more delay time after we turn off the power, so + * we add SYNO_HUB_POWER_CYCLE_EXTRA_DELAY_TIME as an extra delay time + */ +static inline unsigned int +syno_get_power_off_time_ms(void) { + unsigned int power_off_time = CONFIG_SYNO_USB_POWER_OFF_TIME; + return power_off_time; +} +static inline unsigned int +syno_get_power_on_time_ms(void) { + return CONFIG_SYNO_USB_POWER_ON_TIME; +} + +#if defined(MY_DEF_HERE) +extern struct device_node *syno_hub_node_get(const struct usb_device *hdev, const int portnum); +static int is_syno_ext_hub(struct usb_device *udev) +{ + int ret = -1; + if (!udev) { + goto END; + } + + if (syno_hub_node_get(udev->parent, udev->portnum)) { + ret = 0; + } + +END: + return ret; +} + +static int is_syno_ext_hub_by_parent_port(const struct usb_device *hdev, const int portnum) +{ + int ret = -1; + if (!hdev || 1 > portnum) { + goto END; + } + + if (syno_hub_node_get(hdev, portnum)) { + ret = 0; + } + +END: + return ret; +} + +static int syno_usb_power_set_children(struct usb_hub *hub, const int port, const int enable) +{ + int ret = -EINVAL; + struct usb_hub *child_hub = NULL; + int ports = 0; + + if (NULL == hub || 1 > port || NULL == hub->ports[port-1]) { + pr_info("%s parameter check failed\n", __func__); + goto END; + } + + if (enable) { + if (0 == syno_usb_set_power(hub, enable, port)) { + dev_info(hub->intfdev, + "[%u/%u] Enabling USB power vbus#%d for port %d\n", + hub->ports[port - 1]->power_cycle_counter, + SYNO_POWER_CYCLE_TRIES, + hub->ports[port-1]->syno_vbus_gpp, + port); + } + + // if power on a hub, delay waiting for hub ready + if (0 == is_syno_ext_hub_by_parent_port(hub->hdev, port)) { + dev_info(hub->intfdev, + "waiting %u ms for syno external usb hub at port %d\n", + syno_get_power_off_time_ms(), port); + msleep(syno_get_power_on_time_ms()); + } + } + + if (0 == is_syno_ext_hub_by_parent_port(hub->hdev, port)) { + child_hub = usb_hub_to_struct_hub(hub->ports[port - 1]->child); + if (child_hub) { + for (ports = 1; ports <= child_hub->hdev->maxchild; ports++) { + syno_usb_power_set_children(child_hub, ports, enable); + } + } + } + + if (0 == enable) { + if (0 == syno_usb_set_power(hub, enable, port)) { + dev_info(hub->intfdev, + "[%u/%u] Disabling USB power vbus#%d for port %d\n", + hub->ports[port - 1]->power_cycle_counter, + SYNO_POWER_CYCLE_TRIES, + hub->ports[port-1]->syno_vbus_gpp, + port); + } + } + + ret = 0; +END: + return ret; +} +#endif /* MY_DEF_HERE */ + +static int +__syno_usb_power_cycle(struct usb_hub *hub, int port) { + unsigned int power_cycle_delay_time; + int ret; + if (0 >= hub->ports[port - 1]->power_cycle_counter) { + dev_info(hub->intfdev, + "Stop power cycle handling for port %d\n", port); + /* Reset power_cycle_counter to default value */ + hub->ports[port - 1]->power_cycle_counter = SYNO_POWER_CYCLE_TRIES; + return -EINVAL; + } + /* power off */ + power_cycle_delay_time = syno_get_power_off_time_ms(); + dev_info(hub->intfdev, + "[%u/%u] Disabling USB power and waiting %u ms for port %d\n", + hub->ports[port - 1]->power_cycle_counter, + SYNO_POWER_CYCLE_TRIES, + power_cycle_delay_time, port); + +#if defined(MY_DEF_HERE) + ret = syno_usb_power_set_children(hub, port, 0); +#else /* MY_DEF_HERE */ + ret = syno_usb_set_power(hub, 0, port); +#endif /* MY_DEF_HERE */ + if (0 > ret) + return -EINVAL; + msleep(power_cycle_delay_time); + + /* power on + * Add delay time to avoid continuous calling of this function + */ + power_cycle_delay_time = syno_get_power_on_time_ms(); + dev_info(hub->intfdev, + "[%u/%u] Enabling USB power and waiting %u ms for port %d\n", + hub->ports[port - 1]->power_cycle_counter, + SYNO_POWER_CYCLE_TRIES, + power_cycle_delay_time, port); +#if defined(MY_DEF_HERE) + ret = syno_usb_power_set_children(hub, port, 1); +#else /* MY_DEF_HERE */ + ret = syno_usb_set_power(hub, 1, port); +#endif /* MY_DEF_HERE */ + if (0 > ret) + return -EINVAL; + + msleep(power_cycle_delay_time); + hub->ports[port - 1]->power_cycle_counter--; + return 0; +} + +int +syno_usb_power_cycle(struct usb_hub *hub, int port, int status) { + struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); +#if defined (MY_DEF_HERE) + if (hdev->parent && 0 != is_syno_ext_hub(hdev)) +#else /* defined (MY_DEF_HERE) */ + /* Ignore external hub */ + if (hdev->parent) +#endif /* defined (MY_DEF_HERE) */ + return -EINVAL; + + if ((status == -ENODEV) || (status == -ENOTCONN) || (status == -ENOTSUPP)) + return -EINVAL; + + if (hcd->power_control_support) { + return __syno_usb_power_cycle(hub, port); + } else { + printk("This model does not support power control\n"); + return -ENOSYS; /* Function not implemented */ + } +} +#endif /* MY_ABC_HERE */ + /* * Disable a port and mark a logical connect-change event, so that some * time later hub_wq will disconnect() any existing usb_device on the port @@ -963,7 +1245,12 @@ static int hub_set_port_link_state(struct usb_hub *hub, int port1, */ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) { +#ifdef MY_ABC_HERE + dev_info(&hub->ports[port1 - 1]->dev, "logical disconnect on port" + " %d [%s]\n", port1, current->comm); +#else /* MY_ABC_HERE */ dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n"); +#endif /* MY_ABC_HERE */ hub_port_disable(hub, port1, 1); /* FIXME let caller ask to power down the port: @@ -1381,6 +1668,10 @@ static int hub_configure(struct usb_hub *hub, unsigned full_load; unsigned maxchild; +#ifdef MY_ABC_HERE + mutex_lock(&hub_init_mutex); +#endif /* MY_ABC_HERE */ + hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); if (!hub->buffer) { ret = -ENOMEM; @@ -1681,6 +1972,10 @@ static int hub_configure(struct usb_hub *hub, } } +#ifdef MY_ABC_HERE + mutex_unlock(&hub_init_mutex); +#endif /* MY_ABC_HERE */ + usb_hub_adjust_deviceremovable(hdev, hub->descriptor); hub_activate(hub, HUB_INIT); @@ -1690,6 +1985,11 @@ static int hub_configure(struct usb_hub *hub, dev_err(hub_dev, "config failed, %s (err %d)\n", message, ret); /* hub_disconnect() frees urb and descriptor */ + +#ifdef MY_ABC_HERE + mutex_unlock(&hub_init_mutex); +#endif /* MY_ABC_HERE */ + return ret; } @@ -1715,6 +2015,9 @@ static void hub_disconnect(struct usb_interface *intf) * will not try to remove any pending work item. */ hub->disconnected = 1; +#ifdef MY_ABC_HERE + del_timer_sync(&hub->ups_discon_flt_timer); +#endif /* MY_ABC_HERE */ /* Disconnect all children and quiesce the hub */ hub->error = 0; @@ -1770,6 +2073,16 @@ static bool hub_descriptor_is_sane(struct usb_host_interface *desc) return true; } +#ifdef MY_ABC_HERE +static void ups_discon_flt_work(struct timer_list *t) +{ + struct usb_hub *hub = from_timer(hub, t, ups_discon_flt_timer); + set_bit(hub->ups_discon_flt_port, hub->change_bits); + hub->ups_discon_flt_status = SYNO_UPS_DISCON_FLT_STATUS_TIMEOUT; + kick_hub_wq(hub); +} +#endif /* MY_ABC_HERE */ + static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_host_interface *desc; @@ -1827,6 +2140,16 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) */ if (hdev->parent) { /* normal device */ usb_enable_autosuspend(hdev); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_USB_CTRL_MANAGER + if (RTK_usb_disable_hub_autosuspend()) { + dev_warn(&intf->dev, "disable hub autosuspend\n"); + usb_disable_autosuspend(hdev); + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ } else { /* root hub */ const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver; @@ -1885,6 +2208,12 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_autopm_get_interface_no_resume(intf); } +#ifdef MY_ABC_HERE + timer_setup(&hub->ups_discon_flt_timer, ups_discon_flt_work, 0); + hub->ups_discon_flt_last = jiffies - 16 * HZ; + hub->ups_discon_flt_status = SYNO_UPS_DISCON_FLT_STATUS_NONE; +#endif /* MY_ABC_HERE */ + if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) return 0; @@ -2404,6 +2733,25 @@ static int usb_enumerate_device(struct usb_device *udev) udev->manufacturer = usb_cache_string(udev, udev->descriptor.iManufacturer); udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); +#ifdef MY_ABC_HERE + /* Make the backup serial pointer points to the formal udev->serial. + * If we are going to change its serial string, we will make syno_old_serial + * keep the original serial(even it is NULL). + */ + udev->syno_old_serial = udev->serial; + +#if defined (MY_DEF_HERE) + // for syno external hub, + // we need to fix serial name as SYNO_SERIAL_EXT_HUB for user space recognization + if (0 == is_syno_ext_hub(udev)) { + udev->serial = kmalloc(SERIAL_LEN, GFP_KERNEL); + if (NULL != udev->serial) { + snprintf(udev->serial, SERIAL_LEN, "%s", SYNO_SERIAL_EXT_HUB); + printk("Set serial number \"%s\" for Synology External hub.\n",udev->serial); + } + } +#endif /* MY_DEF_HERE */ +#endif /* MY_ABC_HERE */ err = usb_enumerate_device_otg(udev); if (err < 0) @@ -2428,6 +2776,37 @@ static int usb_enumerate_device(struct usb_device *udev) return 0; } +#ifdef MY_ABC_HERE +/* Return 1 if found the same serial in other usb device. Otherwizs, return 0. */ +static int device_serial_match(struct usb_device *dev, struct usb_device *udev_search) +{ + int child, match = 0; + struct usb_device *childdev; + + /* look through all of the children of this device */ + usb_hub_for_each_child(dev, child, childdev) { + if (childdev && childdev != udev_search && childdev->serial) { + + /* Can't down() here. Because when using hub, it will be lock by someone else */ + if (childdev->serial[0] && +#if defined(MY_DEF_HERE) + 0 != is_syno_ext_hub(childdev) && +#endif /* MY_DEF_HERE */ + strcmp(childdev->serial, udev_search->serial) == 0) { + match++; + } else { + match = device_serial_match(childdev, udev_search); + } + + if (match) { + break; + } + } + } + return match; +} +#endif /* MY_ABC_HERE*/ + static void set_usb_port_removable(struct usb_device *udev) { struct usb_device *hdev = udev->parent; @@ -2536,6 +2915,84 @@ int usb_new_device(struct usb_device *udev) udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); +#ifdef MY_ABC_HERE + /* Make a fake serial number from product name */ + if ( NULL == udev->product ) { + udev->product = kmalloc(16, GFP_KERNEL); + if (NULL != udev->product) { + snprintf(udev->product, 16, "USBDevice"); + } + } + + if (NULL == udev->serial && NULL != udev->product) { + int i; + char seed = 0xb4; /* pick a random number */ + + udev->serial = kmalloc(SERIAL_LEN, GFP_KERNEL); + if (NULL != udev->serial) { + const int cProductLen = strlen(udev->product); + printk("Got empty serial number. " + "Generate serial number from product.\n"); + /* TODO: generated sn using signed char causes a lot of 0xffffff shown in sn. + * Warning: If you modify generated sn format, user's devices sn will change and lost user defined configurations. */ + udev->serial[0] = '\0'; + for(i = 0; (i < cProductLen) && (i < (SERIAL_LEN-1)/2); i++) { + snprintf(udev->serial + strlen(udev->serial), + SERIAL_LEN - strlen(udev->serial), + "%02x", (seed ^= udev->product[cProductLen-i-1])); + } + udev->serial[SERIAL_LEN-1] = '\0'; + } + } + + if (udev->parent && udev->serial) { + int match, counter = 0; + int entered = 0; + + struct usb_bus *bus; + int id; + +RETRY: + match = 0; + idr_for_each_entry(&usb_bus_idr, bus, id) { + if (!bus->root_hub) + continue; + + mutex_lock(&hub_init_mutex); + match = device_serial_match(bus->root_hub, udev); + mutex_unlock(&hub_init_mutex); + + if (match) { + break; + } + } + if (match) { + int Len = strlen(udev->serial); + + if (Len == 0) { + printk("USB serial length is 0!\n"); + } else if (counter > 9) { + printk("There are to many same devices (%d)\n", counter); + } else { + if (NULL != udev->syno_old_serial && !entered) { + /* backup old serial for checking if firmware changed after usb reset. + * if the original serial is empty, keep it empty. */ + udev->syno_old_serial = kmalloc(Len, GFP_KERNEL); + memcpy(udev->syno_old_serial, udev->serial, Len); + entered = 1; + } + udev->serial[Len - 1] = counter + '0'; + udev->serial[Len] = '\0'; + printk("%s (%d) Same device found. Change serial to %s \n", + __FILE__, __LINE__, udev->serial); + + counter++; + goto RETRY; + } + } + } +#endif /* MY_ABC_HERE */ + /* Tell the world! */ announce_device(udev); @@ -2730,8 +3187,22 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define HUB_SHORT_RESET_TIME 10 #define HUB_BH_RESET_TIME 50 #define HUB_LONG_RESET_TIME 200 +#ifdef MY_ABC_HERE +#define HUB_SYNO_RESET_TIMEOUT 3000 +#endif /* MY_ABC_HERE */ #define HUB_RESET_TIMEOUT 800 +#ifdef MY_ABC_HERE +#define SYNO_HUB_SPEED_MORPH_RESET_TRIES (3) +#define SYNO_HUB_SPEED_MORPH_TRIES (5) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +// wait device reset, some devices are slow, then set address will fail +// ex. WD passport, Fujitsu, HP. +#define HUB_SYNO_ROOT_RESET_TIME 1000 +#endif /* MY_ABC_HERE */ + static bool use_new_scheme(struct usb_device *udev, int retry, struct usb_port *port_dev) { @@ -2786,8 +3257,19 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, u16 portchange; u32 ext_portstatus = 0; +#ifdef MY_ABC_HERE + // this sleep is waiting for status change to clear (reset/bh_reset/link_state), + // but sometimes it will take longer time to change the status, + // so prolong the waiting time. + msleep(20); +#endif /* MY_ABC_HERE */ + for (delay_time = 0; +#ifdef MY_ABC_HERE + delay_time < HUB_SYNO_RESET_TIMEOUT; +#else delay_time < HUB_RESET_TIMEOUT; +#endif /* MY_ABC_HERE */ delay_time += delay) { /* wait to give the device a chance to reset */ msleep(delay); @@ -2815,6 +3297,14 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, (portstatus & USB_PORT_STAT_CONNECTION)) break; +#ifdef MY_ABC_HERE + /* HUB_RESET_TIMEOUT is replaced by HUB_SYNO_RESET_TIMEOUT and + * delay time is changed to 1000 ms after HUB_RESET_TIMEOUT. + */ + if (delay_time >= HUB_RESET_TIMEOUT) + delay = HUB_SYNO_ROOT_RESET_TIME; + else +#endif /* MY_ABC_HERE */ /* switch to the long delay after two short delay failures */ if (delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; @@ -2824,8 +3314,17 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, warm ? "warm " : "", delay); } +#ifdef MY_ABC_HERE + /* Broadwell-DE USB host controller will keep USB_PORT_STAT_RESET bit, + * even if device went away, which will cause unnecessary retrial. + */ + if ((portstatus & USB_PORT_STAT_CONNECTION) && + (portstatus & USB_PORT_STAT_RESET)) + return -EBUSY; +#else /* MY_ABC_HERE */ if ((portstatus & USB_PORT_STAT_RESET)) return -EBUSY; +#endif /* MY_ABC_HERE */ if (hub_port_warm_reset_required(hub, port1, portstatus)) return -ENOTCONN; @@ -2842,7 +3341,14 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, (portchange & USB_PORT_STAT_C_CONNECTION)) { usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); +#ifdef MY_ABC_HERE + if (portchange & USB_PORT_STAT_C_ENABLE) + usb_clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_ENABLE); + return -SYNO_CONNECT_BOUNCE; +#else /* MY_ABC_HERE */ return -EAGAIN; +#endif /* MY_ABC_HERE */ } if (!(portstatus & USB_PORT_STAT_ENABLE)) @@ -2929,6 +3435,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1, /* Check for disconnect or reset */ if (status == 0 || status == -ENOTCONN || status == -ENODEV) { +#ifdef MY_ABC_HERE + if (-SYNO_CONNECT_BOUNCE != status) { +#endif /* MY_ABC_HERE */ usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_RESET); @@ -2965,6 +3474,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "hot reset failed, warm reset\n"); warm = true; } +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ } dev_dbg(&port_dev->dev, @@ -3623,6 +4135,42 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + /* [DEV_FIX] Disconnect usb port at resume. + * commit 1a50dacafca108bd258f28755e2f4ad9ba4bc8d4 + * [BUG_FIX]: ID 46792 [ROOT_CAUSE]: can't recognize usb hub + * commit cd7a079f0a82876abcdbe3e6a0b9409441c94294 + * [DEV_FIX]check udev reset_resume flag to disconnect + * the device while resume back . + * commit 8185a91ad51e2fe115d8d7a60d8b1ed4b8eb6c9f + * [DEV_FIX]cant recognize hub after unplug/plug & suspend/resume + * commit 3bbc65af52a4b27ac41114a998ad942aa613c078 + * [DEV_FIX]2. force CONFIG_USB_HUB_DISCONNECT_AT_RESUME + * commit 3e6a470b06ea6e37edded163aa814c8c24f04ced + */ + if (udev->reset_resume) { + int i; + if (udev->descriptor.bDeviceClass == USB_CLASS_MASS_STORAGE) + status = -1; + else + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_host_config *config = udev->actconfig; + struct usb_interface *intf = config->interface[i]; + struct usb_interface_descriptor *desc; + desc = &intf->cur_altsetting->desc; + + dev_notice(&udev->dev , "%s bInterfaceClass = %d \n", __func__, desc->bInterfaceClass);//hcy test + if (desc->bInterfaceClass == USB_CLASS_MASS_STORAGE){ + status = -1; + break; + } + } + } +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ if (status == 0) status = finish_port_resume(udev); if (status < 0) { @@ -4548,6 +5096,39 @@ static int hub_set_address(struct usb_device *udev, int devnum) return retval; } +#if defined (MY_ABC_HERE) +static int check_superspeed(struct usb_hub *hub, struct usb_device *udev) +{ + struct usb_device *hdev = hub->hdev; + int retval = -EINVAL; +#if defined (MY_DEF_HERE) + /* The usb3.0 hub instance won't have chance to do reset, + * because the upstream port's usb2.0 pins have been given + * to usb2.0 hub instance. + * the usb2.0 hub instance will enter check_highspeed + * if its speed is downgraded. + */ + if (0 == is_syno_ext_hub(udev)) { + dev_info(&udev->dev, "This is Synology external hub. Skip %s\n", __func__); + return retval; + } + + /* Only the parent is root hub or syno external hub + * can do speed downgrade recovery. + */ + if ((!hdev->parent || 0 == is_syno_ext_hub(hdev)) && +#else /* MY_DEF_HERE */ + if (!hdev->parent && +#endif /* MY_DEF_HERE */ + !hub_is_superspeed(hdev) && + 0x0210 <= le16_to_cpu(udev->descriptor.bcdUSB)) { + dev_info(&udev->dev, "not running at top speed\n"); + retval = 0; + } + return retval; +} +#endif /* MY_ABC_HERE */ + /* * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM * when they're plugged into a USB 2.0 port, but they don't work when LPM is @@ -4613,6 +5194,10 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, int devnum = udev->devnum; const char *driver_name; bool do_new_scheme; +#ifdef MY_ABC_HERE + int reset_retry = 1; + int speed_morph_count = 0; +#endif /* MY_ABC_HERE */ /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -4630,9 +5215,21 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, mutex_lock(hcd->address0_mutex); +#if defined (MY_ABC_HERE) +port_speed_morph: + do { + /* Reset the device; full speed may morph to high speed */ + /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ + retval = hub_port_reset(hub, port1, udev, delay, false); + if (retval < 0) + break; + } while (--reset_retry); +#else /* MY_ABC_HERE */ /* Reset the device; full speed may morph to high speed */ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ retval = hub_port_reset(hub, port1, udev, delay, false); +#endif /* MY_ABC_HERE */ + if (retval < 0) /* error or disconnect */ goto fail; /* success, speed is known */ @@ -4698,6 +5295,29 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, (udev->config) ? "reset" : "new", speed, devnum, driver_name); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (udev->speed < USB_SPEED_SUPER) + dev_notice(&udev->dev, + "%s %s USB device number %d using %s (%s)\n", + (udev->config) ? "reset" : "new", speed, + devnum, driver_name, + dev_name(udev->bus->controller->parent)); + + /* add for debug reset*/ + if (udev->speed < USB_SPEED_SUPER && udev->config) { + dev_dbg(&udev->dev, + "Start print dump_stack for %s %s USB device number %d " + "using %s (%s)\n", + (udev->config) ? "reset" : "new", speed, + devnum, driver_name, + dev_name(udev->bus->controller->parent)); + dev_dbg(&udev->dev, "End print dump_stack for USB dev number %d", + ({dump_stack(); devnum;})); + } +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* Set up TT records, if needed */ if (hdev->tt) { udev->tt = hdev->tt; @@ -4834,6 +5454,32 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, (udev->rx_lanes == 2 && udev->tx_lanes == 2) ? "x2" : "", devnum, driver_name); +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + dev_notice(&udev->dev, + "%s SuperSpeed%s USB device number %d using %s at %s\n", + (udev->config) ? "To reset" : "Get new", + (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "", + devnum, driver_name, + dev_name(udev->bus->controller->parent)); + + /* add for debug reset*/ + if (udev->config) { + dev_dbg(&udev->dev, + "Start print dump_stack for %s SuperSpeed%s " + "USB device number %d " + "using %s (%s)\n", + (udev->config) ? "reset" : "new", + (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "", + devnum, driver_name, + dev_name(udev->bus->controller->parent)); + dev_dbg(&udev->dev, + "End print dump_stack for USB dev number %d", + ({dump_stack(); devnum;})); + } +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ } /* cope with hardware quirkiness: @@ -4922,6 +5568,23 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, usb_detect_quirks(udev); +#if defined (MY_ABC_HERE) + if (IS_XHCI(hcd) +#ifdef MY_DEF_HERE + && !(SYNO_USB_PORT_CASTRATED_XHC & hub->ports[port1 - 1]->flag) +#endif /* MY_DEF_HERE */ + ) { + retval = check_superspeed(hub, udev); + if (!retval && speed_morph_count < SYNO_HUB_SPEED_MORPH_TRIES) { + speed_morph_count++; + reset_retry = SYNO_HUB_SPEED_MORPH_RESET_TRIES; + hub_port_disable(hub, port1, 0); + oldspeed = USB_SPEED_UNKNOWN; + goto port_speed_morph; + } + } +#endif /* MY_ABC_HERE */ + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { retval = usb_get_bos_descriptor(udev); if (!retval) { @@ -4931,6 +5594,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, } retval = 0; +#ifdef MY_ABC_HERE + hub->ports[port1 - 1]->power_cycle_counter = SYNO_POWER_CYCLE_TRIES; +#endif /* MY_ABC_HERE */ /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); @@ -5052,8 +5718,19 @@ static int descriptors_changed(struct usb_device *udev, * But the SerialNumber string could be different (e.g., a * different flash card of the same brand). */ + +#ifdef MY_ABC_HERE + /* For bug #295: + * when calling usb_reset_device, compare the length of serial number + * with the original one. If we didn't change the serial, the + * udev->syno_old_serial will still point to udev->serial. + */ + if (udev->syno_old_serial) + serial_len = strlen(udev->syno_old_serial) + 1; +#else /* MY_ABC_HERE */ if (udev->serial) serial_len = strlen(udev->serial) + 1; +#endif /* MY_ABC_HERE */ len = serial_len; for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { @@ -5094,7 +5771,16 @@ static int descriptors_changed(struct usb_device *udev, dev_dbg(&udev->dev, "serial string error %d\n", length); changed = 1; +#ifdef MY_ABC_HERE + /* For bug #295 , when calling usb_reset_device, + * compare the serial number with the original one. + * If we had changed its serial, the syno_old_serial will still keep the original one; + * Otherwise it will point to whatever udev->serial points. + */ + } else if (memcmp(buf, udev->syno_old_serial, length) != 0) { +#else /* MY_ABC_HERE */ } else if (memcmp(buf, udev->serial, length) != 0) { +#endif /* MY_ABC_HERE */ dev_dbg(&udev->dev, "serial string changed\n"); changed = 1; } @@ -5118,6 +5804,65 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, /* Disconnect any existing devices under this port */ if (udev) { +#ifdef MY_ABC_HERE + /* Defer disconnect for UPS devices */ + if (unlikely(udev->syno_quirks & + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER)) { + if (portstatus & USB_PORT_STAT_CONNECTION) { + /* for the case that the device is connected again after + * disconnected, cancel the disconnection and reset it. + */ + int ret; + del_timer_sync(&hub->ups_discon_flt_timer); + hub->ups_discon_flt_status = + SYNO_UPS_DISCON_FLT_STATUS_NONE; + hub->ups_discon_flt_last = jiffies; + hub_port_debounce_be_stable(hub, port1); + usb_lock_device(udev); + ret = usb_reset_device(udev); + usb_unlock_device(udev); + if (0 > ret) { + hub_port_status(hub, port1, &portstatus, &portchange); + dev_err(&port_dev->dev, "deferred disconnect failed, " + "on port %d reset (ret: %d), status: %04x, " + "change: %04x\n", port1, ret, portstatus, + portchange); + } else + return; + } else if (portchange & USB_PORT_STAT_C_CONNECTION) { + /* for the case that the device is disconnected, defer it. */ + if (unlikely((udev->syno_quirks & + SYNO_USB_QUIRK_LIMITED_UPS_DISCONNECT_FILTERING) + && time_after(hub->ups_discon_flt_last + 15 * HZ, + jiffies))) + /* For the buggy UPS which disconnects very frequently + * before a UPS driver (usually in userspace) links the UPS. + * Because the condition that the buggy UPS isn't stable + * initally and UPS driver can't also link it before the + * driver stops trying, so we should actually disconnect and + * re-connect to notify and restart the UPS driver. + */ + ; + else { + if (!timer_pending(&hub->ups_discon_flt_timer)) { + hub->ups_discon_flt_status = + SYNO_UPS_DISCON_FLT_STATUS_DEFERRED; + hub->ups_discon_flt_port = port1; + hub->ups_discon_flt_timer.expires = jiffies + 3 * HZ; + add_timer(&hub->ups_discon_flt_timer); + } + return; + } + } else { + /* for the case that defer disconnection timeout, disconnect it + * actually. + */ + del_timer_sync(&hub->ups_discon_flt_timer); + hub->ups_discon_flt_status = + SYNO_UPS_DISCON_FLT_STATUS_NONE; + } + } +#endif /* MY_ABC_HERE */ if (hcd->usb_phy && !hdev->parent) usb_phy_notify_disconnect(hcd->usb_phy, udev->speed); usb_disconnect(&port_dev->child); @@ -5134,6 +5879,9 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, USB_PORT_STAT_C_ENABLE)) { status = hub_port_debounce_be_stable(hub, port1); if (status < 0) { +#ifdef MY_ABC_HERE + syno_usb_power_cycle(hub, port1, status); +#endif /* MY_ABC_HERE */ if (status != -ENODEV && port1 != unreliable_port && printk_ratelimit()) @@ -5270,6 +6018,14 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, /* Run it through the hoops (find a driver, etc) */ if (!status) { status = usb_new_device(udev); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_USB_CTRL_MANAGER + if (!status) + RTK_usb_reprobe_usb_storage(udev); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ if (status) { mutex_lock(&usb_port_peer_mutex); spin_lock_irq(&device_state_lock); @@ -5319,6 +6075,15 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, "unable to enumerate USB device\n"); } +#ifdef MY_ABC_HERE + /* TODO + * Check if we should put syno_usb_power_cycle below the label "done", + * because it would be better we do syno_usb_power_cycle after + * hub_port_disable. (Refer to hub_port_logical_disconnect) + */ + syno_usb_power_cycle(hub, port1, status); +#endif /* MY_ABC_HERE */ + done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) { @@ -5345,6 +6110,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, int status = -ENODEV; int retval; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + dev_notice(&port_dev->dev, "port %d, status %04x, change %04x, %s\n", + port1, portstatus, portchange, portspeed(hub, portstatus)); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, portchange, portspeed(hub, portstatus)); @@ -5386,6 +6158,16 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, udev->descriptor = descriptor; } else { status = 0; /* Nothing to do */ +#ifdef MY_ABC_HERE + if (unlikely((udev->syno_quirks & + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER) && + (hub->ups_discon_flt_status != + SYNO_UPS_DISCON_FLT_STATUS_NONE))) { + dev_warn(&port_dev->dev, "UPS disconnect filter: re-connected but " + "port %d still enabled, status: %04x, change: %04x\n", + port1, portstatus, portchange); + } +#endif /* MY_ABC_HERE */ } } #ifdef CONFIG_PM @@ -5484,7 +6266,22 @@ static void port_event(struct usb_hub *hub, int port1) */ if (!(portstatus & USB_PORT_STAT_ENABLE) && !connect_change && udev) { +#ifdef MY_ABC_HERE + int ret = 1; +#endif /* MY_ABC_HERE */ dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n"); +#ifdef MY_ABC_HERE + /* re-enable for UPS's EMI without disconnect */ + if (udev->syno_quirks & + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER) { + usb_unlock_port(port_dev); + usb_lock_device(udev); + ret = usb_reset_device(udev); + usb_unlock_device(udev); + usb_lock_port(port_dev); + } + if (ret) +#endif /* MY_ABC_HERE */ connect_change = 1; } } @@ -5567,6 +6364,12 @@ static void hub_event(struct work_struct *work) u16 hubstatus; u16 hubchange; int i, ret; +#ifdef MY_ABC_HERE + u16 portstatus; + u16 portchange; + int ups_discon_flt; + int connect_change; +#endif /* MY_ABC_HERE */ hub = container_of(work, struct usb_hub, events); hdev = hub->hdev; @@ -5618,8 +6421,53 @@ static void hub_event(struct work_struct *work) hub->error = 0; } +#ifdef MY_ABC_HERE + ups_discon_flt = 0; + + /* Serialize hub events among a deferred disconnection of a UPS and + * others within the same instance of hub, by deferring hub events to + * behind the deferred disconnection of a UPS. + */ + if (SYNO_UPS_DISCON_FLT_STATUS_NONE != hub->ups_discon_flt_status) { + connect_change = 0; + i = hub->ups_discon_flt_port; + /* for the case of ups_discon_flt_timer timeout */ + connect_change = test_bit(i, hub->change_bits); + + ret = hub_port_status(hub, i, + &portstatus, &portchange); + + /* for the case of re-connection of a UPS */ + if (0 >= ret && + portchange & USB_PORT_STAT_C_CONNECTION) + connect_change = 1; + + if (connect_change) + /* we must ensure that the target port of UPS-disconnect filter + * (i.e. ups_discon_flt_port) can be dealt with before others by + * the following for-loop. + */ + ups_discon_flt = 1; + else + /* all hub events coming from the ports that are not the target + * of UPS-disconnect filter (i.e. ups_discon_flt_port) will be + * discarded (or pending, actually) if there is a pending UPS- + * disconnection within the same instance of hub. Because a + * pending UPS-disconnection must generate a hub event, so the + * discarded ones will be also dealt with by the following for- + * loop later. + */ + goto out_hdev_lock; + } +#endif /* MY_ABC_HERE */ /* deal with port status changes */ +#ifdef MY_ABC_HERE + for (i = ups_discon_flt? hub->ups_discon_flt_port: 1; + i <= hdev->maxchild; + i = ups_discon_flt? 1: i + 1, ups_discon_flt = 0) { +#else for (i = 1; i <= hdev->maxchild; i++) { +#endif /* MY_ABC_HERE */ struct usb_port *port_dev = hub->ports[i - 1]; if (test_bit(i, hub->event_bits) diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 22ea1f4f2d66..375f1b342a05 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * usb hub driver head file @@ -16,6 +19,11 @@ #include #include "usb.h" +#ifdef MY_ABC_HERE +/* SYNO USB Error Code */ +#define SYNO_CONNECT_BOUNCE 0x400 +#endif /* MY_ABC_HERE */ + struct usb_hub { struct device *intfdev; /* the "interface" device */ struct usb_device *hdev; @@ -73,6 +81,16 @@ struct usb_hub { spinlock_t irq_urb_lock; struct timer_list irq_urb_retry; struct usb_port **ports; + +#ifdef MY_ABC_HERE + struct timer_list ups_discon_flt_timer; + int ups_discon_flt_port; + unsigned long ups_discon_flt_last; /* last filtered time */ +#define SYNO_UPS_DISCON_FLT_STATUS_NONE 0 +#define SYNO_UPS_DISCON_FLT_STATUS_DEFERRED 1 +#define SYNO_UPS_DISCON_FLT_STATUS_TIMEOUT 2 + unsigned int ups_discon_flt_status; +#endif /* MY_ABC_HERE */ }; /** @@ -103,10 +121,25 @@ struct usb_port { u8 portnum; u32 quirks; unsigned int is_superspeed:1; +#ifdef MY_ABC_HERE + unsigned int power_cycle_counter; +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE +#define SYNO_USB_PORT_CASTRATED_XHC 0x01 + unsigned int flag; +#endif /* MY_DEF_HERE */ unsigned int usb3_lpm_u1_permit:1; unsigned int usb3_lpm_u2_permit:1; +#ifdef MY_ABC_HERE + int syno_vbus_gpp; + int syno_vbus_gpp_pol; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +#define SYNO_POWER_CYCLE_TRIES (3) +#endif /* MY_ABC_HERE */ + #define to_usb_port(_dev) \ container_of(_dev, struct usb_port, dev) diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 235a7c645503..237e90a62de4 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * usb port device code @@ -9,6 +12,9 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "hub.h" @@ -528,11 +534,146 @@ static void find_and_link_peer(struct usb_hub *hub, int port1) link_peers_report(port_dev, peer); } +#ifdef MY_ABC_HERE +/** + * syno_usb_hub_node_get - return usb or hub slot index by usb 2 or 3 bus and port + * @hdev [IN]: usb device + * @portnum [IN]: port number + * @prefix [IN]: node name in dts + * + * return >0: slot number + * -1: slot not found + */ +static struct device_node *__syno_usb_hub_node_get(const struct usb_device *hdev, const int portnum, const char *szNodeName) +{ + int size = 0; + struct device_node *pUsbSlotNode = NULL, *pUsbNode = NULL; + char *szUsbNodeBusPort = NULL; + char szUsbBusPort[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (NULL == hdev || NULL == szNodeName || 0 > portnum) { + goto END; + } + + if (0 == strncmp(dev_name(&hdev->dev), "usb", strlen("usb"))) { + snprintf(szUsbBusPort, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s-%d", dev_name(&hdev->dev), portnum); + sscanf(szUsbBusPort, "usb%s", szUsbBusPort); + } else { + snprintf(szUsbBusPort, SYNO_DTS_PROPERTY_CONTENT_LENGTH, "%s.%d", dev_name(&hdev->dev), portnum); + } + + for_each_child_of_node(of_root, pUsbSlotNode) { + if (pUsbSlotNode->name && (strlen(pUsbSlotNode->name) == strlen(szNodeName)) + && 0 == (of_node_cmp(pUsbSlotNode->name, szNodeName))) { + + pUsbNode = of_get_child_by_name(pUsbSlotNode, DT_USB2); + szUsbNodeBusPort = (char *)of_get_property(pUsbNode, DT_USB_PORT, &size); + if (szUsbNodeBusPort && (strlen(szUsbNodeBusPort) == strlen(szUsbBusPort)) + && 0 == strcmp(szUsbNodeBusPort, szUsbBusPort)) { + goto END; + } + of_node_put(pUsbNode); + + pUsbNode = of_get_child_by_name(pUsbSlotNode, DT_USB3); + szUsbNodeBusPort = (char *)of_get_property(pUsbNode, DT_USB_PORT, &size); + if (szUsbNodeBusPort && (strlen(szUsbNodeBusPort) == strlen(szUsbBusPort)) + && 0 == strcmp(szUsbNodeBusPort, szUsbBusPort)) { + goto END; + } + of_node_put(pUsbNode); + } + } +END: + return pUsbSlotNode; +} + +#if defined(MY_DEF_HERE) +/** + * syno_hub_node_get - return hub slot index by usb 2 or 3 bus and port + * @hdev [IN]: usb device + * @portnum [IN]: port number + * + * return >0: slot number + * -1: slot not found + */ +struct device_node *syno_hub_node_get(const struct usb_device *hdev, const int portnum) +{ + struct device_node *pDeviceNode = NULL; + if (NULL == hdev || 1 > portnum) { + goto END; + } + pDeviceNode = __syno_usb_hub_node_get(hdev, portnum, DT_HUB_SLOT); +END: + return pDeviceNode; +} +EXPORT_SYMBOL(syno_hub_node_get); +#endif /* MY_DEF_HERE */ + +/** + * syno_usb_hub_node_get - return usb or hub slot index by usb 2 or 3 bus and port + * @hdev [IN]: usb device + * @portnum [IN]: port number + * + * return >0: slot number + * -1: slot not found + */ +struct device_node *syno_usb_hub_node_get(const struct usb_device *hdev, const int portnum) +{ + struct device_node *pDeviceNode = NULL; + if (NULL == hdev || 0 > portnum) { + goto END; + } + pDeviceNode = __syno_usb_hub_node_get(hdev, portnum, DT_USB_SLOT); + if (NULL != pDeviceNode) { + goto END; + } + pDeviceNode = __syno_usb_hub_node_get(hdev, portnum, DT_HUB_SLOT); +END: + return pDeviceNode; +} +EXPORT_SYMBOL(syno_usb_hub_node_get); + +/** + * syno_vbus_gpio_set - set vbus gpio + * @vbus_gpio_pin [IN]: vbus gpio pin + * @vbus_gpio_polarity [IN]: polarity of the pin + * @port1 [IN]: usb port + * + * return void + */ +void syno_vbus_gpio_set(const char *vbus_host_addr, const unsigned vbus_gpio_pin, const unsigned vbus_gpio_polarity, const int port1) +{ + if (UINT_MAX == vbus_gpio_pin || UINT_MAX == vbus_gpio_polarity || 0 > port1) { + return; + } + + if (vbus_gpio_polarity != SYNO_GPIO_READ(vbus_gpio_pin)) { + SYNO_GPIO_WRITE(vbus_gpio_pin, vbus_gpio_polarity); + printk(KERN_INFO " port%d is going to power up Vbus by " + "GPIO#%d(%s)\n", port1, vbus_gpio_pin, + vbus_gpio_polarity ? "ACTIVE_HIGH" : "ACTIVE_LOW"); + + mdelay(100); + } + return; +} +#endif /* MY_ABC_HERE */ + int usb_hub_create_port_device(struct usb_hub *hub, int port1) { struct usb_port *port_dev; struct usb_device *hdev = hub->hdev; int retval; +#ifdef MY_DEF_HERE + extern char gSynoCastratedXhcAddr[CONFIG_SYNO_USB_NUM_CASTRATED_XHC][32]; + extern unsigned gSynoCastratedXhcPortBitmap[CONFIG_SYNO_USB_NUM_CASTRATED_XHC]; + int i = 0; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + u32 vbusGpioPin = U32_MAX, vbusGpioPolarity = 0; + char *szGpioShared = NULL; + struct device_node *pVbusNode = NULL, *pUSBNode = NULL; +#endif /* MY_ABC_HERE */ port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); if (!port_dev) @@ -560,6 +701,75 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) port_dev->is_superspeed = 1; dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev), port1); + +#ifdef MY_ABC_HERE + port_dev->power_cycle_counter = SYNO_POWER_CYCLE_TRIES; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + if (hdev && hdev->serial) { + for (i = 0; i < CONFIG_SYNO_USB_NUM_CASTRATED_XHC; i++) { + if (0 == strcmp(gSynoCastratedXhcAddr[i], hdev->serial) && + gSynoCastratedXhcPortBitmap[i] & (0x01 << (port1 - 1))) { + /* Castrated xHC-port is an outer USB-port which is serviced by + * a xHCI and without physical links of USB3 (i.e. without USB3 + * capability. + */ + port_dev->flag |= SYNO_USB_PORT_CASTRATED_XHC; + if (hub_is_superspeed(hdev)) + dev_info (&port_dev->dev, "is a castrated xHC-port\n"); + } + } + } +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE + port_dev->syno_vbus_gpp = -1; + port_dev->syno_vbus_gpp_pol = -1; + if (hdev && hdev->serial) { + pUSBNode = syno_usb_hub_node_get(hdev, port1); + if (NULL == pUSBNode) { + goto PUT_NODE; + } + + pVbusNode = of_get_child_by_name(pUSBNode, DT_VBUS); + if (NULL == pVbusNode) { + goto PUT_NODE; + } + + if (0 != of_property_read_u32_index(pVbusNode, DT_SYNO_GPIO, SYNO_GPIO_PIN, &vbusGpioPin)) { + printk(KERN_ERR "%s reading vbus vbusGpioPin failed.\n", __func__); + goto PUT_NODE; + } + + if (0 != of_property_read_u32_index(pVbusNode, DT_SYNO_GPIO, SYNO_POLARITY_PIN, &vbusGpioPolarity)) { + printk(KERN_ERR "%s reading vbus vbusGpioPolarity failed.\n", __func__); + goto PUT_NODE; + } + + syno_vbus_gpio_set(NULL, vbusGpioPin, vbusGpioPolarity, port1); + + szGpioShared = (char *)of_get_property(pUSBNode, DT_SHARED, NULL); + + if (szGpioShared && 0 == strncmp(szGpioShared, "true", strlen("true"))) { + goto PUT_NODE; + } + + port_dev->syno_vbus_gpp = vbusGpioPin; + port_dev->syno_vbus_gpp_pol = vbusGpioPolarity; + printk(KERN_INFO "host %s port %d has Vbus GPIO#%d with polarity " + "%s\n",hdev->serial, port1, port_dev->syno_vbus_gpp, + port_dev->syno_vbus_gpp_pol ? "ACTIVE_HIGH" : "ACTIVE_LOW"); +PUT_NODE: + if (pUSBNode) { + of_node_put(pUSBNode); + } + if (pVbusNode) { + of_node_put(pVbusNode); + } + } +#endif /* MY_ABC_HERE */ + mutex_init(&port_dev->status_lock); retval = device_register(&port_dev->dev); if (retval) { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index a54a735b6384..25e38a71c33e 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * USB device quirk handling logic and table @@ -9,6 +12,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include "usb.h" @@ -217,6 +223,12 @@ static const struct usb_device_id usb_quirk_list[] = { /* Microsoft LifeCam-VX700 v2.0 */ { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Microsoft Wireless Mouse 5000 */ + { USB_DEVICE(0x045e, 0x0745), .driver_info = USB_QUIRK_RESET }, +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */ { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM }, @@ -264,6 +276,13 @@ static const struct usb_device_id usb_quirk_list[] = { /* Logitech Harmony 700-series */ { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Logitech Wireless Mouse M705 */ + { USB_DEVICE(0x046d, 0xc52b), .driver_info = USB_QUIRK_RESET }, +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -488,6 +507,19 @@ static const struct usb_device_id usb_quirk_list[] = { /* Blackmagic Design UltraStudio SDI */ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Kingston DataTraveler 3.0 G4 */ + { USB_DEVICE_VER(0x0951, 0x1666, 0, 0x1100), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Kingston DataTraveler 3.0 G4 no support lpm */ + { USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM }, + + /* Toshiba no support lpm */ + { USB_DEVICE(0x0930, 0x6545), .driver_info = USB_QUIRK_NO_LPM }, +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* Hauppauge HVR-950q */ { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -532,6 +564,48 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = { { } /* terminating entry must be last */ }; +#ifdef MY_ABC_HERE +/* + * List of quirky USB devices which should be applied with Synology USB quirks + */ +static const struct usb_device_id syno_usb_quirk_list[] = { + /* Cyper Power UPSes */ + { USB_DEVICE(0x0764, 0x0005), .driver_info = + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER }, + + /* Cyper Power UPSes, e.g. CP1500 AVR UPS */ + { USB_DEVICE(0x0764, 0x0501), .driver_info = + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER }, + + /* Cyper Power UPSes, e.g. PR1500LCDRT2U UPS */ + { USB_DEVICE(0x0764, 0x0601), .driver_info = + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER }, + + /* MGE UPSes, e.g. EATON Ellipse PRO 650 IEC */ + { USB_DEVICE(0x0463, 0xffff), .driver_info = + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER }, + + /* UPSes, e.g. FT-BS 500VA */ + { USB_DEVICE(0x0665, 0x5161), .driver_info = + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER | + SYNO_USB_QUIRK_LIMITED_UPS_DISCONNECT_FILTERING }, + + /* APC UPSes, e.g. APC BR550GI */ + { USB_DEVICE(0x051d, 0x0002), .driver_info = + SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER }, + + /* iStorage Pro series */ + { USB_DEVICE(0x0984, 0x1403), .driver_info = + SYNO_USB_QUIRK_SYNCHRONIZE_CACHE_FILTER }, + + /* EPSON C1100 */ + { USB_DEVICE(0x04b8, 0x0007), .driver_info = + SYNO_USB_QUIRK_HC_MORE_TRANSACTION_TRIES }, + + { } /* terminating entry must be last */ +}; +#endif /* MY_ABC_HERE */ + /* * Entries for endpoints that should be ignored when parsing configuration * descriptors. @@ -651,6 +725,9 @@ static u32 usb_detect_dynamic_quirks(struct usb_device *udev) void usb_detect_quirks(struct usb_device *udev) { udev->quirks = usb_detect_static_quirks(udev, usb_quirk_list); +#ifdef MY_ABC_HERE + udev->syno_quirks = usb_detect_static_quirks(udev, syno_usb_quirk_list); +#endif /* MY_ABC_HERE */ /* * Pixart-based mice would trigger remote wakeup issue on AMD diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 8d134193fa0c..d846b880452c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/core/sysfs.c @@ -48,6 +51,11 @@ static ssize_t field##_show(struct device *dev, \ usb_actconfig_attr(bNumInterfaces, "%2d\n"); usb_actconfig_attr(bmAttributes, "%2x\n"); +#ifdef MY_ABC_HERE +extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev); +extern int syno_usb_power_cycle(struct usb_hub *hub, int port, int status); +#endif /* MY_ABC_HERE */ + static ssize_t bMaxPower_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -258,6 +266,34 @@ static ssize_t quirks_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(quirks); +#ifdef MY_ABC_HERE +static ssize_t +syno_quirks_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "0x%x\n", udev->syno_quirks); +} + +static ssize_t +syno_quirks_store(struct device *dev, struct device_attribute *attr, + const char * buf, size_t count) +{ + struct usb_device *udev; + unsigned int val; + + if (0 > kstrtouint(buf, 16, &val)) + return -EINVAL; + + udev = to_usb_device(dev); + udev->syno_quirks = val; + + return count; +} +static DEVICE_ATTR_RW(syno_quirks); +#endif /* MY_ABC_HERE */ + static ssize_t avoid_reset_quirk_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -330,6 +366,33 @@ static ssize_t ltm_capable_show(struct device *dev, } static DEVICE_ATTR_RO(ltm_capable); +#ifdef MY_ABC_HERE +static ssize_t +syno_vbus_reset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->maxchild); +} +static ssize_t +syno_vbus_reset_store(struct device *dev, struct device_attribute *attr, + const char * buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + struct usb_hub *hub = usb_hub_to_struct_hub(udev); + unsigned int port1; + + if (0 > kstrtouint(buf, 10, &port1)) + return -EINVAL; + + if (port1 > udev->maxchild || 0 >= port1) + return -EINVAL; + + syno_usb_power_cycle(hub, port1, 0); + return count; +} +static DEVICE_ATTR_RW(syno_vbus_reset); +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_PM static ssize_t persist_show(struct device *dev, struct device_attribute *attr, @@ -795,6 +858,196 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_RTK_HCD_TEST_MODE +#include +#include +#include + +extern int get_hub_descriptor_port(struct usb_device *hdev, void *data, int size, int port1); + +// copy from hub.c and rename +/* + * USB 2.0 spec Section 11.24.2.2 + */ +static int hub_clear_port_feature(struct usb_device *hdev, int port1, int feature) +{ + return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, 1000); +} + +/* + * USB 2.0 spec Section 11.24.2.13 + */ +static int hub_set_port_feature(struct usb_device *hdev, int port1, int feature) +{ + return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, 1000); +} + +/* use a short timeout for hub/port status fetches */ +#define USB_STS_TIMEOUT 1000 +#define USB_STS_RETRIES 5 + +static int get_port_status(struct usb_device *hdev, int port1, + struct usb_port_status *data) +{ + int i, status = -ETIMEDOUT; + + for (i = 0; i < USB_STS_RETRIES && + (status == -ETIMEDOUT || status == -EPIPE); i++) { + printk("get_port_status at port %d ...\n", port1); + status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1, + data, sizeof(*data), USB_STS_TIMEOUT); + } + return status; +} + +enum { + TEST_RESET = 0, + TEST_TEST_J, + TEST_TEST_K, + TEST_TEST_SE0_NAK, + TEST_TEST_PACKET, + TEST_TEST_FORCE_ENABLE, + TEST_SUSPEND_RESUME, + TEST_SINGLE_STEP_GET_DEVICE_DESCRIPTOR, + TEST_PORT_RESET, + MAX_CTS_TEST_CASE, +}; + +static ssize_t show_runTestMode (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = udev = to_usb_device (dev); + + if(udev->descriptor.bDeviceClass != USB_CLASS_HUB) + return sprintf (buf, "This node is not a HUB\n"); + + return sprintf (buf, "%s to runTestMode\n" + "echo \"1 %d\" to run port1 HC_RESET command\n" + "echo \"1 %d\" to run port1 TEST_J command\n" + "echo \"1 %d\" ro run port1 TEST_K command\n" + "echo \"1 %d\" to run port1 TEST_SE0_NAK command\n" + "echo \"1 %d\" to run port1 TEST_PACKET command\n" + "echo \"1 %d\" to run port1 TEST_FORCE_ENABLE command\n" + "echo \"1 %d\" to run port1 SUSPEND/RESUME command\n" + "echo \"1 %d\" to run port1 " + "SINGLE_STEP_GET_DEVICE_DESCRIPTOR command\n" + "echo \"1 %d\" to run port1 PORT_RESET command\n", + dev_name(dev), + TEST_RESET, TEST_TEST_J, TEST_TEST_K, TEST_TEST_SE0_NAK, + TEST_TEST_PACKET, + TEST_TEST_FORCE_ENABLE, TEST_SUSPEND_RESUME, + TEST_SINGLE_STEP_GET_DEVICE_DESCRIPTOR, + TEST_PORT_RESET); + + return 0; +} + +static ssize_t +set_runTestMode (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_device *udev = udev = to_usb_device (dev); + int value, test_case; + unsigned int port1 = 1; + + if ((value = sscanf (buf, "%u", &port1)) != 1) + return -EINVAL; + + buf += 2; + + if ((value = sscanf (buf, "%u", &test_case)) != 1) + return -EINVAL; + + if(udev->descriptor.bDeviceClass != USB_CLASS_HUB) + return value; + + switch (test_case) { + case TEST_RESET: + printk("run HC_RESET (%d) to port %d ...\n", test_case, port1); + if (udev->bus != NULL) { + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + int ret; + if (hcd != NULL && hcd->driver != NULL && hcd->driver->reset) + ret = hcd->driver->reset(hcd); + if (ret) + printk("run HC_RESET fail ...\n"); + } + + break; + case TEST_TEST_J: + case TEST_TEST_K: + case TEST_TEST_SE0_NAK: + case TEST_TEST_PACKET: + case TEST_TEST_FORCE_ENABLE: + usb_autoresume_device(udev); + printk("run USB_PORT_FEAT_TEST mode %d to port %d ...\n", test_case, port1); + hub_set_port_feature(udev,(test_case << 8) | port1, USB_PORT_FEAT_TEST); + + break; + case TEST_SUSPEND_RESUME: + printk("run TEST_SUSPEND_RESUME to the port %d of the hub ...\n", port1); + msleep(15000); + printk("set USB_PORT_FEAT_SUSPEND to the port %d of the hub ...\n", port1); + hub_set_port_feature(udev, port1, USB_PORT_FEAT_SUSPEND); + printk("set OK !!!\n"); + msleep(15000); + printk("clear USB_PORT_FEAT_SUSPEND to the port %d of the hub ...\n", port1); + hub_clear_port_feature(udev, port1, USB_PORT_FEAT_SUSPEND); + printk("clear OK !!!\n"); + { + struct usb_port_status data; + + printk("get_port_status port %d of the hub ...\n", port1); + msleep(USB_RESUME_TIMEOUT); + get_port_status(udev, port1, &data); + } + break; + case TEST_SINGLE_STEP_GET_DEVICE_DESCRIPTOR: + { + int i, size = 0x12; + unsigned char *data; + + printk("run SINGLE_STEP_GET_DEVICE_DESCRIPTOR to the port %d of the hub ...\n", port1); + data = (unsigned char*)kmalloc(size, GFP_KERNEL); + if (!data) + return -ENOMEM; + memset (data, 0, size); + get_hub_descriptor_port(udev, data, size, port1); + + printk(" get device descriptor\n"); + for( i = 0; i < size; i++) + { + printk(" %.2x", data[i]); + if((i % 15) == 0 && (i != 0)) + printk("\n<1>"); + } + printk("\n"); + + kfree(data); + } + break; + case TEST_PORT_RESET: + printk("run PORT_RESET (%d) to port %d ...\n", test_case, port1); + hub_clear_port_feature(udev, port1, USB_PORT_FEAT_POWER); + msleep(1000); + hub_set_port_feature(udev, port1, USB_PORT_FEAT_POWER); + + break; + default: + printk("error test_case %d !!!\n", test_case); + break; + } + + return (value < 0) ? value : count; +} +static DEVICE_ATTR(runTestMode, S_IRUGO | S_IWUSR, + show_runTestMode, set_runTestMode); +#endif /* CONFIG_USB_RTK_HCD_TEST_MODE */ +#endif /* MY_DEF_HERE */ static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -822,14 +1075,25 @@ static struct attribute *dev_attrs[] = { &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, +#ifdef MY_ABC_HERE + &dev_attr_syno_quirks.attr, +#endif /* MY_ABC_HERE */ &dev_attr_avoid_reset_quirk.attr, &dev_attr_authorized.attr, &dev_attr_remove.attr, &dev_attr_removable.attr, &dev_attr_ltm_capable.attr, +#ifdef MY_ABC_HERE + &dev_attr_syno_vbus_reset.attr, +#endif /* MY_ABC_HERE */ #ifdef CONFIG_OF &dev_attr_devspec.attr, #endif +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_RTK_HCD_TEST_MODE + &dev_attr_runTestMode.attr, +#endif // CONFIG_USB_RTK_HCD_TEST_MODE +#endif /* MY_DEF_HERE */ NULL, }; static struct attribute_group dev_attr_grp = { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index db4de5367737..9cc811b17e4f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/core/usb.c @@ -39,6 +42,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include @@ -420,6 +426,10 @@ static void usb_release_dev(struct device *dev) usb_put_hcd(hcd); kfree(udev->product); kfree(udev->manufacturer); +#ifdef MY_ABC_HERE + if (udev->syno_old_serial != udev->serial) + kfree(udev->syno_old_serial); +#endif /* MY_ABC_HERE */ kfree(udev->serial); kfree(udev); } @@ -983,16 +993,32 @@ static struct notifier_block usb_bus_nb = { }; static struct dentry *usb_devices_root; +#ifdef MY_ABC_HERE +static struct proc_dir_entry *usbdir = NULL; +#endif /* MY_ABC_HERE */ static void usb_debugfs_init(void) { usb_devices_root = debugfs_create_file("devices", 0444, usb_debug_root, NULL, &usbfs_devices_fops); + +#ifdef MY_ABC_HERE + /* create mount point for /proc/bus/usb */ + usbdir = proc_mkdir("bus/usb", NULL); + if (!usbdir) { + printk(KERN_ERR "Fail to create /proc/bus/usb\n"); + } +#endif /* MY_ABC_HERE */ + } static void usb_debugfs_cleanup(void) { debugfs_remove(usb_devices_root); +#ifdef MY_ABC_HERE + if (usbdir) + remove_proc_entry("bus/usb", NULL); +#endif /* MY_ABC_HERE */ } /* diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 7a2304565a73..1fe0a9c732a8 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -53,6 +53,40 @@ endchoice comment "Platform Glue Driver Support" +if SYNO_LSP_RTD1619B +config USB_DWC3_RTK + tristate "Realtek DWC3 Platform Driver" + default USB_DWC3 + select RTK_USB2PHY + select RTK_USB3PHY + select USB_RTK_CTRL_MANAGER + help + RTK SoCs with DesignWare Core USB3 IP inside, + say 'Y' or 'M' if you have such device. + +config USB_DWC3_RTK_DUAL_ROLE + tristate "Realtek DWC3 Platform Dual Role Driver" + default USB_DWC3_RTK if (USB_DWC3_DUAL_ROLE) + depends on USB_DWC3_DUAL_ROLE + help + RTK SoCs with DesignWare Core USB3 IP to suport drd mode, + Support Realtek dwc3 drd mode to dynamical host/device switch. + say 'Y' or 'M' if you have such device. + +config USB_DWC3_RTK_TYPE_C + bool "RTK DWC3 Type C Driver (dynamical host/device mode switch)" + default USB_DWC3_RTK if (USB_DWC3_DUAL_ROLE) + depends on USB_DWC3_DUAL_ROLE + help + Support Realtek dwc3 drd type c port + +config USB_TYPE_C_RTK_RTS5400 + bool "RTK Type C Controller RTS5400" + depends on USB_RTK_DWC3_DRD_MODE + help + Support Realtek type c controller via RTS5400 + +endif # SYNO_LSP_RTD1619B config USB_DWC3_OMAP tristate "Texas Instruments OMAP5 and similar Platforms" depends on ARCH_OMAP2PLUS || COMPILE_TEST diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index ae86da0dc5bd..9157702eaec0 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -51,3 +51,29 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +ifeq ($(CONFIG_SYNO_RTD1619B), y) +obj-$(CONFIG_USB_DWC3_RTK) += dwc3_rtk.o +dwc3_rtk-y := dwc3-rtk.o + +ifneq ($(CONFIG_TRACING),) + CFLAGS_trace-rtk.o := -I$(src) + dwc3_rtk-y += trace-rtk.o +endif + +ifneq ($(CONFIG_DEBUG_FS),) + dwc3_rtk-y += dwc3-rtk-debugfs.o +endif + +ifneq ($(CONFIG_USB_DWC3_RTK_DUAL_ROLE),) + dwc3_rtk-y += dwc3-rtk-drd.o +endif + +else # CONFIG_SYNO_RTD1619B +obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o +obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk-debugfs.o +obj-$(CONFIG_USB_DWC3_RTK_DUAL_ROLE) += dwc3-rtk-drd.o +endif # CONFIG_SYNO_RTD1619B +obj-$(CONFIG_USB_DWC3_RTK_TYPE_C) += dwc3-rtk-type_c.o +obj-$(CONFIG_USB_TYPE_C_RTK_RTS5400) += rtk-rts5400.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index bfb72902f3a6..ee3649abf529 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * core.c - DesignWare USB3 DRD Controller Core file @@ -32,6 +35,12 @@ #include #include +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#include +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ #include "core.h" #include "gadget.h" #include "io.h" @@ -114,7 +123,11 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } +#if defined(MY_DEF_HERE) +int dwc3_core_soft_reset(struct dwc3 *dwc); +#else /* MY_DEF_HERE */ static int dwc3_core_soft_reset(struct dwc3 *dwc); +#endif /* MY_DEF_HERE */ static void __dwc3_set_mode(struct work_struct *work) { @@ -260,7 +273,15 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK +int dwc3_core_soft_reset(struct dwc3 *dwc) +#else static int dwc3_core_soft_reset(struct dwc3 *dwc) +#endif // USB_PATCH_BY_RTK +#else /* MY_DEF_HERE */ +static int dwc3_core_soft_reset(struct dwc3 *dwc) +#endif /* MY_DEF_HERE */ { u32 reg; int retries = 1000; @@ -620,6 +641,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) reg |= DWC3_GUSB3PIPECTL_SUSPHY; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (dwc->revision > DWC3_REVISION_194A) { + unsigned int hw_mode; + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + /* + * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after + * power-on reset, and it can be set after core initialization, which is + * after device soft-reset during initialization. + */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + } +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#else /* MY_DEF_HERE */ /* * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after * power-on reset, and it can be set after core initialization, which is @@ -627,6 +665,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) */ if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; +#endif /* MY_DEF_HERE */ if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; @@ -710,6 +749,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) reg |= DWC3_GUSB2PHYCFG_SUSPHY; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (dwc->revision > DWC3_REVISION_194A) { + unsigned int hw_mode; + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + /* + * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after + * power-on reset, and it can be set after core initialization, which is + * after device soft-reset during initialization. + */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + } +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#else /* MY_DEF_HERE */ /* * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after * power-on reset, and it can be set after core initialization, which is @@ -717,6 +773,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) */ if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; +#endif /* MY_DEF_HERE */ if (dwc->dis_u2_susphy_quirk) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; @@ -979,10 +1036,23 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc->phys_ready = true; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + dwc3_writel(dwc->regs, DWC3_GCTL, reg | DWC3_GCTL_DSBLCLKGTNG); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ ret = dwc3_core_soft_reset(dwc); if (ret) goto err0a; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + dwc3_writel(dwc->regs, DWC3_GCTL, reg); +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { if (!dwc->dis_u3_susphy_quirk) { @@ -998,6 +1068,30 @@ static int dwc3_core_init(struct dwc3 *dwc) } } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (dwc->revision > DWC3_REVISION_194A) { + unsigned int hw_mode; + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && + !dwc->dis_u3_susphy_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + } + + if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && + !dwc->dis_u2_susphy_quirk) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + } +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ + dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); @@ -1026,6 +1120,26 @@ static int dwc3_core_init(struct dwc3 *dwc) goto err4; } +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK + /* base on commit id 00af62330c39a6c88615a08e7f9d068944e4af69 */ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); + break; + case USB_DR_MODE_HOST: + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); + break; + case USB_DR_MODE_OTG: + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); + break; + default: + dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode); + break; + } +#endif // USB_PATCH_BY_RTK + +#endif /* MY_DEF_HERE */ /* * ENDXFER polling is available on version 3.10a and later of * the DWC_usb3 controller. It is NOT available in the @@ -1056,6 +1170,16 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK + if (dwc->dev_force_20_clk_for_30_clk) + dwc3_writel(dwc->regs, DWC3_GUCTL1, + dwc3_readl(dwc->regs, DWC3_GUCTL1) | + DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK); +#endif // USB_PATCH_BY_RTK + + +#endif /* MY_DEF_HERE */ if (dwc->dr_mode == USB_DR_MODE_HOST || dwc->dr_mode == USB_DR_MODE_OTG) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL); @@ -1366,6 +1490,12 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-u2-freeclk-exists-quirk"); dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev, "snps,dis-del-phy-power-chg-quirk"); +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK + dwc->dev_force_20_clk_for_30_clk = device_property_read_bool(dev, + "snps,dev_force_20_clk_for_30_clk"); +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev, "snps,dis-tx-ipgap-linecheck-quirk"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, @@ -1509,6 +1639,23 @@ static int dwc3_probe(struct platform_device *pdev) dwc_res = *res; dwc_res.start += DWC3_GLOBALS_REGS_START; +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK + /* For some dwc3 controller, the dwc3 global register start address is + * not at DWC3_GLOBALS_REGS_START (0xc100). + */ + device_property_read_u32(dev, "snps,fixed_dwc3_globals_regs_start", + &dwc->fixed_dwc3_globals_regs_start); + if (dwc->fixed_dwc3_globals_regs_start) { + dwc_res.start -= DWC3_GLOBALS_REGS_START; + dwc_res.start += dwc->fixed_dwc3_globals_regs_start; + dev_info(dev, + "fixed dwc3 globals register start address from 0x%x to end 0x%x\n", + (int)dwc_res.start, (int)dwc_res.end); + } +#endif + +#endif /* MY_DEF_HERE */ regs = devm_ioremap_resource(dev, &dwc_res); if (IS_ERR(regs)) return PTR_ERR(regs); @@ -1894,25 +2041,89 @@ static int dwc3_runtime_idle(struct device *dev) #endif /* CONFIG_PM */ #ifdef CONFIG_PM_SLEEP +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK +/* [DEV_FIX]implement New USB reset mechanism with CRT reset + * to workaround any HW or IP issues + * commit 319ff9f5c298b94517a10d4ced59812b54994347 + */ +static int dwc3_suspend(struct device *dev); +int RTK_dwc3_suspend(struct device *dev) +{ + return dwc3_suspend(dev); +} +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ static int dwc3_suspend(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); int ret; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + dev_info(dev, "[USB] Enter %s", __func__); + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + return 0; + } + //For suspend mode + dev_info(dev, "[USB] %s Suspend mode\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; pinctrl_pm_select_sleep_state(dev); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + dev_info(dev, "[USB] Exit %s", __func__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ return 0; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +/* [DEV_FIX]implement New USB reset mechanism with CRT reset + * to workaround any HW or IP issues + * commit 319ff9f5c298b94517a10d4ced59812b54994347 + */ +static int dwc3_resume(struct device *dev); +int RTK_dwc3_resume(struct device *dev) +{ + return dwc3_resume(dev); +} +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ static int dwc3_resume(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); int ret; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + dev_info(dev, "[USB] Enter %s", __func__); + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + return 0; + } + //For suspend mode + dev_info(dev, "[USB] %s Suspend mode\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ pinctrl_pm_select_default_state(dev); ret = dwc3_resume_common(dwc, PMSG_RESUME); @@ -1923,6 +2134,16 @@ static int dwc3_resume(struct device *dev) pm_runtime_set_active(dev); pm_runtime_enable(dev); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ +out: +#endif /* MY_DEF_HERE */ + dev_info(dev, "[USB] Exit %s", __func__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ return 0; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 79e1b82e5e05..530121d0007e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * core.h - DesignWare USB3 DRD Core Header @@ -200,6 +203,15 @@ #define DWC3_EVENTQ 7 #define DWC3_AUXEVENTQ 8 +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK +/* Global TX Threshold Configuration Register */ +#define DWC3_GTXTHRCFG_MAXTXBURSTSIZE(n) (((n) & 0xff) << 16) +#define DWC3_GTXTHRCFG_TXPKTCNT(n) (((n) & 0xf) << 24) +#define DWC3_GTXTHRCFG_PKTCNTSEL BIT(29) +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ + /* Global RX Threshold Configuration Register */ #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19) #define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24) @@ -255,6 +267,11 @@ /* Global User Control 1 Register */ #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK +#define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) /* Global Status Register */ @@ -306,6 +323,7 @@ #define DWC3_GUSB3PIPECTL_SUSPHY BIT(17) #define DWC3_GUSB3PIPECTL_LFPSFILT BIT(9) #define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8) + #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) @@ -554,6 +572,12 @@ #define DWC3_DEV_IMOD_INTERVAL_SHIFT 0 #define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0) +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK +#define DWC3_DEVICE_IMODI(n) ((0xffff & (n))) +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ + /* OTG Configuration Register */ #define DWC3_OCFG_DISPWRCUTTOFF BIT(5) #define DWC3_OCFG_HIBDISMASK BIT(4) @@ -1064,6 +1088,9 @@ struct dwc3_scratchpad_array { * @dis_split_quirk: set to disable split boundary. * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. +#if defined(MY_DEF_HERE) + * @fixed_dwc3_globals_regs_start: fix the dwc3 global register start address. +#endif // MY_DEF_HERE */ struct dwc3 { struct work_struct drd_work; @@ -1252,6 +1279,11 @@ struct dwc3 { unsigned dis_u2_freeclk_exists_quirk:1; unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK + unsigned dev_force_20_clk_for_30_clk:1; +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ unsigned parkmode_disable_ss_quirk:1; unsigned tx_de_emphasis_quirk:1; @@ -1262,6 +1294,12 @@ struct dwc3 { unsigned dis_split_quirk:1; u16 imod_interval; + +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK + u32 fixed_dwc3_globals_regs_start; +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ }; #define INCRX_BURST_MODE 0 @@ -1430,6 +1468,12 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode); void dwc3_set_mode(struct dwc3 *dwc, u32 mode); u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); +#if defined(MY_DEF_HERE) +#if 1 // USB_PATCH_BY_RTK +int dwc3_core_soft_reset(struct dwc3 *dwc); +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ + #define DWC3_IP_IS(_ip) \ (dwc->ip == _ip##_IP) diff --git a/drivers/usb/dwc3/dwc3-rtk-debugfs.c b/drivers/usb/dwc3/dwc3-rtk-debugfs.c new file mode 100644 index 000000000000..f227b0bd75ba --- /dev/null +++ b/drivers/usb/dwc3/dwc3-rtk-debugfs.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * dwc3-rtk-debugfs.c - Reltek DesignWare USB3 DRD Controller DebugFS file + * + * Copyright (C) 2020 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include + +#include "dwc3-rtk.h" +#include "core.h" +#include "io.h" + +#ifdef CONFIG_DEBUG_FS + +struct rtk_debugfs_reg32 { + char *name; + unsigned long offset; + int default_val; +}; + +#define dump_register(nm) \ +{ \ + .name = __stringify(nm) " [" __stringify(DWC3_ ##nm) "]", \ + .offset = DWC3_ ##nm, \ +} + +#define dump_ep_register_set_DEPCMDPAR2(n) \ + { \ + .name = "DEPCMDPAR2("__stringify(n)") [" \ + __stringify(DWC3_DEP_BASE(n)) " + " \ + __stringify(DWC3_DEPCMDPAR2) "]", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMDPAR2, \ + }, +#define dump_ep_register_set_DEPCMDPAR1(n) \ + { \ + .name = "DEPCMDPAR1("__stringify(n)" [" \ + __stringify(DWC3_DEP_BASE(n)) " + " \ + __stringify(DWC3_DEPCMDPAR1) "]", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMDPAR1, \ + }, +#define dump_ep_register_set_DEPCMDPAR0(n) \ + { \ + .name = "DEPCMDPAR0("__stringify(n)") [" \ + __stringify(DWC3_DEP_BASE(n)) " + " \ + __stringify(DWC3_DEPCMDPAR0) "]", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMDPAR0, \ + }, +#define dump_ep_register_set_CMD(n) \ + { \ + .name = "DEPCMD("__stringify(n)") [" \ + __stringify(DWC3_DEP_BASE(n)) " + " \ + __stringify(DWC3_DEPCMD) "]", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMD, \ + } + +#define dump_ep_register_set(n) \ + dump_ep_register_set_DEPCMDPAR2(n) \ + dump_ep_register_set_DEPCMDPAR1(n) \ + dump_ep_register_set_DEPCMDPAR0(n) \ + dump_ep_register_set_CMD(n) \ + +static const struct rtk_debugfs_reg32 dwc3_regs[] = { + dump_register(GSBUSCFG0), + dump_register(GSBUSCFG1), + dump_register(GTXTHRCFG), + dump_register(GRXTHRCFG), + dump_register(GCTL), + dump_register(GEVTEN), + dump_register(GSTS), + dump_register(GUCTL1), + dump_register(GSNPSID), + dump_register(GGPIO), + dump_register(GUID), + dump_register(GUCTL), + dump_register(GBUSERRADDR0), + dump_register(GBUSERRADDR1), + dump_register(GPRTBIMAP0), + dump_register(GPRTBIMAP1), + dump_register(GHWPARAMS0), + dump_register(GHWPARAMS1), + dump_register(GHWPARAMS2), + dump_register(GHWPARAMS3), + dump_register(GHWPARAMS4), + dump_register(GHWPARAMS5), + dump_register(GHWPARAMS6), + dump_register(GHWPARAMS7), + dump_register(GDBGFIFOSPACE), + dump_register(GDBGLTSSM), + dump_register(GPRTBIMAP_HS0), + dump_register(GPRTBIMAP_HS1), + dump_register(GPRTBIMAP_FS0), + dump_register(GPRTBIMAP_FS1), + + dump_register(GUSB2PHYCFG(0)), + dump_register(GUSB2PHYCFG(1)), + dump_register(GUSB2PHYCFG(2)), + dump_register(GUSB2PHYCFG(3)), + dump_register(GUSB2PHYCFG(4)), + dump_register(GUSB2PHYCFG(5)), + dump_register(GUSB2PHYCFG(6)), + dump_register(GUSB2PHYCFG(7)), + dump_register(GUSB2PHYCFG(8)), + dump_register(GUSB2PHYCFG(9)), + dump_register(GUSB2PHYCFG(10)), + dump_register(GUSB2PHYCFG(11)), + dump_register(GUSB2PHYCFG(12)), + dump_register(GUSB2PHYCFG(13)), + dump_register(GUSB2PHYCFG(14)), + dump_register(GUSB2PHYCFG(15)), + + dump_register(GUSB2I2CCTL(0)), + dump_register(GUSB2I2CCTL(1)), + dump_register(GUSB2I2CCTL(2)), + dump_register(GUSB2I2CCTL(3)), + dump_register(GUSB2I2CCTL(4)), + dump_register(GUSB2I2CCTL(5)), + dump_register(GUSB2I2CCTL(6)), + dump_register(GUSB2I2CCTL(7)), + dump_register(GUSB2I2CCTL(8)), + dump_register(GUSB2I2CCTL(9)), + dump_register(GUSB2I2CCTL(10)), + dump_register(GUSB2I2CCTL(11)), + dump_register(GUSB2I2CCTL(12)), + dump_register(GUSB2I2CCTL(13)), + dump_register(GUSB2I2CCTL(14)), + dump_register(GUSB2I2CCTL(15)), + + dump_register(GUSB2PHYACC(0)), + dump_register(GUSB2PHYACC(1)), + dump_register(GUSB2PHYACC(2)), + dump_register(GUSB2PHYACC(3)), + dump_register(GUSB2PHYACC(4)), + dump_register(GUSB2PHYACC(5)), + dump_register(GUSB2PHYACC(6)), + dump_register(GUSB2PHYACC(7)), + dump_register(GUSB2PHYACC(8)), + dump_register(GUSB2PHYACC(9)), + dump_register(GUSB2PHYACC(10)), + dump_register(GUSB2PHYACC(11)), + dump_register(GUSB2PHYACC(12)), + dump_register(GUSB2PHYACC(13)), + dump_register(GUSB2PHYACC(14)), + dump_register(GUSB2PHYACC(15)), + + dump_register(GUSB3PIPECTL(0)), + dump_register(GUSB3PIPECTL(1)), + dump_register(GUSB3PIPECTL(2)), + dump_register(GUSB3PIPECTL(3)), + dump_register(GUSB3PIPECTL(4)), + dump_register(GUSB3PIPECTL(5)), + dump_register(GUSB3PIPECTL(6)), + dump_register(GUSB3PIPECTL(7)), + dump_register(GUSB3PIPECTL(8)), + dump_register(GUSB3PIPECTL(9)), + dump_register(GUSB3PIPECTL(10)), + dump_register(GUSB3PIPECTL(11)), + dump_register(GUSB3PIPECTL(12)), + dump_register(GUSB3PIPECTL(13)), + dump_register(GUSB3PIPECTL(14)), + dump_register(GUSB3PIPECTL(15)), + + dump_register(GTXFIFOSIZ(0)), + dump_register(GTXFIFOSIZ(1)), + dump_register(GTXFIFOSIZ(2)), + dump_register(GTXFIFOSIZ(3)), + dump_register(GTXFIFOSIZ(4)), + dump_register(GTXFIFOSIZ(5)), + dump_register(GTXFIFOSIZ(6)), + dump_register(GTXFIFOSIZ(7)), + dump_register(GTXFIFOSIZ(8)), + dump_register(GTXFIFOSIZ(9)), + dump_register(GTXFIFOSIZ(10)), + dump_register(GTXFIFOSIZ(11)), + dump_register(GTXFIFOSIZ(12)), + dump_register(GTXFIFOSIZ(13)), + dump_register(GTXFIFOSIZ(14)), + dump_register(GTXFIFOSIZ(15)), + dump_register(GTXFIFOSIZ(16)), + dump_register(GTXFIFOSIZ(17)), + dump_register(GTXFIFOSIZ(18)), + dump_register(GTXFIFOSIZ(19)), + dump_register(GTXFIFOSIZ(20)), + dump_register(GTXFIFOSIZ(21)), + dump_register(GTXFIFOSIZ(22)), + dump_register(GTXFIFOSIZ(23)), + dump_register(GTXFIFOSIZ(24)), + dump_register(GTXFIFOSIZ(25)), + dump_register(GTXFIFOSIZ(26)), + dump_register(GTXFIFOSIZ(27)), + dump_register(GTXFIFOSIZ(28)), + dump_register(GTXFIFOSIZ(29)), + dump_register(GTXFIFOSIZ(30)), + dump_register(GTXFIFOSIZ(31)), + + dump_register(GRXFIFOSIZ(0)), + dump_register(GRXFIFOSIZ(1)), + dump_register(GRXFIFOSIZ(2)), + dump_register(GRXFIFOSIZ(3)), + dump_register(GRXFIFOSIZ(4)), + dump_register(GRXFIFOSIZ(5)), + dump_register(GRXFIFOSIZ(6)), + dump_register(GRXFIFOSIZ(7)), + dump_register(GRXFIFOSIZ(8)), + dump_register(GRXFIFOSIZ(9)), + dump_register(GRXFIFOSIZ(10)), + dump_register(GRXFIFOSIZ(11)), + dump_register(GRXFIFOSIZ(12)), + dump_register(GRXFIFOSIZ(13)), + dump_register(GRXFIFOSIZ(14)), + dump_register(GRXFIFOSIZ(15)), + dump_register(GRXFIFOSIZ(16)), + dump_register(GRXFIFOSIZ(17)), + dump_register(GRXFIFOSIZ(18)), + dump_register(GRXFIFOSIZ(19)), + dump_register(GRXFIFOSIZ(20)), + dump_register(GRXFIFOSIZ(21)), + dump_register(GRXFIFOSIZ(22)), + dump_register(GRXFIFOSIZ(23)), + dump_register(GRXFIFOSIZ(24)), + dump_register(GRXFIFOSIZ(25)), + dump_register(GRXFIFOSIZ(26)), + dump_register(GRXFIFOSIZ(27)), + dump_register(GRXFIFOSIZ(28)), + dump_register(GRXFIFOSIZ(29)), + dump_register(GRXFIFOSIZ(30)), + dump_register(GRXFIFOSIZ(31)), + + dump_register(GEVNTADRLO(0)), + dump_register(GEVNTADRHI(0)), + dump_register(GEVNTSIZ(0)), + dump_register(GEVNTCOUNT(0)), + + dump_register(GHWPARAMS8), + dump_register(DCFG), + dump_register(DCTL), + dump_register(DEVTEN), + dump_register(DSTS), + dump_register(DGCMDPAR), + dump_register(DGCMD), + dump_register(DALEPENA), + + dump_ep_register_set(0), + dump_ep_register_set(1), + dump_ep_register_set(2), + dump_ep_register_set(3), + dump_ep_register_set(4), + dump_ep_register_set(5), + dump_ep_register_set(6), + dump_ep_register_set(7), + dump_ep_register_set(8), + dump_ep_register_set(9), + dump_ep_register_set(10), + dump_ep_register_set(11), + dump_ep_register_set(12), + dump_ep_register_set(13), + dump_ep_register_set(14), + dump_ep_register_set(15), + dump_ep_register_set(16), + dump_ep_register_set(17), + dump_ep_register_set(18), + dump_ep_register_set(19), + dump_ep_register_set(20), + dump_ep_register_set(21), + dump_ep_register_set(22), + dump_ep_register_set(23), + dump_ep_register_set(24), + dump_ep_register_set(25), + dump_ep_register_set(26), + dump_ep_register_set(27), + dump_ep_register_set(28), + dump_ep_register_set(29), + dump_ep_register_set(30), + dump_ep_register_set(31), + + dump_register(OCFG), + dump_register(OCTL), + dump_register(OEVT), + dump_register(OEVTEN), + dump_register(OSTS), +}; + +#define dump_wrap_register(nm) \ +{ \ + .name = __stringify(nm) " [" __stringify(WRAP_ ##nm) "]", \ + .offset = WRAP_ ##nm, \ +} + +static const struct rtk_debugfs_reg32 wrap_regs[] = { + dump_wrap_register(CTR_reg), + dump_wrap_register(USB_HMAC_CTR0_reg), + dump_wrap_register(USB2_PHY_reg), +}; + +static int dwc3_rtk_dwc_regdump_show(struct seq_file *s, void *unused) +{ + struct dwc3_rtk *dwc3_rtk = s->private; + struct dwc3 *dwc; + unsigned long flags; + struct rtk_debugfs_reg32 *regs = + (struct rtk_debugfs_reg32 *)(dwc3_rtk->dwc3_regs_dump); + u32 nregs = ARRAY_SIZE(dwc3_regs); + int i; + + dwc = dwc3_rtk->dwc; + + spin_lock_irqsave(&dwc->lock, flags); + + for (i = 0; i < nregs; i++, regs++) { + u32 val = dwc3_readl(dwc->regs, regs->offset); + + seq_printf(s, "%s = 0x%08x -> 0x%08x (diff=0x%08x)\n", + regs->name, + regs->default_val, val, regs->default_val ^ val); + if (seq_has_overflowed(s)) + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rtk_dwc_regdump_open(struct inode *inode, struct file *file) +{ + return single_open(file, dwc3_rtk_dwc_regdump_show, inode->i_private); +} + +static const struct file_operations dwc3_rtk_dwc_regdump_fops = { + .open = dwc3_rtk_dwc_regdump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dwc3_rtk_wrap_regdump_show(struct seq_file *s, void *unused) +{ + struct dwc3_rtk *dwc3_rtk = s->private; + struct rtk_debugfs_reg32 *regs = + (struct rtk_debugfs_reg32 *)(dwc3_rtk->wrap_regs_dump); + u32 nregs = ARRAY_SIZE(wrap_regs); + int i; + + for (i = 0; i < nregs; i++, regs++) { + u32 val = readl(dwc3_rtk->regs + regs->offset); + + seq_printf(s, "%s = 0x%08x -> 0x%08x (diff=0x%08x)\n", + regs->name, + regs->default_val, val, regs->default_val ^ val); + if (seq_has_overflowed(s)) + break; + } + + return 0; +} + +static int dwc3_rtk_wrap_regdump_open(struct inode *inode, struct file *file) +{ + return single_open(file, dwc3_rtk_wrap_regdump_show, inode->i_private); +} + +static const struct file_operations dwc3_rtk_wrap_regdump_fops = { + .open = dwc3_rtk_wrap_regdump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void dwc3_rtk_regdump_init(struct dwc3_rtk *dwc3_rtk) +{ + struct device *dev; + struct device_node *node; + struct device_node *dwc3_node; + + if (!dwc3_rtk) { + pr_err("%s: No device for dwc3_rtk!\n", __func__); + return; + } + + dev = dwc3_rtk->dev; + if (!dev) { + pr_err("%s: No device for dwc3_rtk!\n", __func__); + return; + } + + node = dev->of_node; + if (!node) { + pr_err("%s: No device node for dwc3_rtk!\n", __func__); + return; + } + + dwc3_node = of_get_compatible_child(node, "synopsys,dwc3"); + if (!dwc3_node) { + dev_info(dev, "%s: Get dwc3_node at first child node\n", + __func__); + dwc3_node = of_get_next_child(node, NULL); + } + if (dwc3_node) { + const __be32 *addrp; + u64 addr; + u64 size; + unsigned int flags; + u32 fixed_dwc3_globals_regs_start; + struct rtk_debugfs_reg32 *regs; + size_t regs_size = ARRAY_SIZE(dwc3_regs); + void __iomem *base; + int i; + + dwc3_rtk->dwc3_regs_dump = kzalloc( + sizeof(struct rtk_debugfs_reg32) * regs_size, + GFP_KERNEL); + regs = (struct rtk_debugfs_reg32 *)(dwc3_rtk->dwc3_regs_dump); + memcpy(regs, dwc3_regs, + sizeof(struct rtk_debugfs_reg32) * regs_size); + + addrp = of_get_address(dwc3_node, 0, &size, &flags); + if (addrp == NULL) { + dev_err(dev, "%s: Error! Can't get dwc3 reg address!\n", + __func__); + return; + } + addr = of_translate_address(dwc3_node, addrp); + + of_property_read_u32(dwc3_node, + "snps,fixed_dwc3_globals_regs_start", + &fixed_dwc3_globals_regs_start); + if (fixed_dwc3_globals_regs_start) { + addr += fixed_dwc3_globals_regs_start; + size -= fixed_dwc3_globals_regs_start; + } + dev_dbg(dev, "dwc3 register start address to 0x%x (size=%x)\n", + (u32)addr, (u32)size); + + base = ioremap(addr, size); + + for (i = 0; i < regs_size; i++, regs++) + regs->default_val = dwc3_readl(base, regs->offset); + + iounmap(base); + } + + if (dwc3_rtk) { + struct rtk_debugfs_reg32 *regs; + size_t regs_size = ARRAY_SIZE(wrap_regs); + int i; + + dwc3_rtk->wrap_regs_dump = kzalloc( + sizeof(struct rtk_debugfs_reg32) * regs_size, + GFP_KERNEL); + regs = (struct rtk_debugfs_reg32 *)(dwc3_rtk->wrap_regs_dump); + memcpy(regs, wrap_regs, + sizeof(struct rtk_debugfs_reg32) * regs_size); + + for (i = 0; i < regs_size; i++, regs++) + regs->default_val = readl(dwc3_rtk->regs + + regs->offset); + } +} + +void dwc3_rtk_debugfs_init(struct dwc3_rtk *dwc3_rtk) +{ + struct dentry *debug_dir; + struct dentry *file; + struct device *dev; + + if (!dwc3_rtk) { + pr_err("%s: No device for dwc3_rtk!\n", __func__); + return; + } + + dev = dwc3_rtk->dev; + if (!dev) { + pr_err("%s: No device for dwc3_rtk!\n", __func__); + return; + } + + dwc3_rtk_regdump_init(dwc3_rtk); + + debug_dir = debugfs_create_dir(dev_name(dev), usb_debug_root); + if (!debug_dir) { + dev_err(dev, "%s: Can't create debugfs dir\n", __func__); + return; + } + dwc3_rtk->debug_dir = debug_dir; + + file = debugfs_create_file("dwc3_regdump", S_IRUGO, + debug_dir, dwc3_rtk, &dwc3_rtk_dwc_regdump_fops); + if (!file) + dev_err(dev, "%s: Can't create debugfs regdump\n", __func__); + + file = debugfs_create_file("wrap_regdump", S_IRUGO, + debug_dir, dwc3_rtk, &dwc3_rtk_wrap_regdump_fops); + if (!file) + dev_err(dev, "%s: Can't create debugfs regdump\n", __func__); +} + +void dwc3_rtk_debugfs_exit(struct dwc3_rtk *dwc3_rtk) +{ + debugfs_remove_recursive(dwc3_rtk->debug_dir); + + kfree(dwc3_rtk->dwc3_regs_dump); + kfree(dwc3_rtk->wrap_regs_dump); +} + +#else +void dwc3_rtk_debugfs_init(struct dwc3_rtk *dwc3_rtk) +{ + +} + +void dwc3_rtk_debugfs_exit(struct dwc3_rtk *dwc3_rtk) +{ + +} +#endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/usb/dwc3/dwc3-rtk-drd.c b/drivers/usb/dwc3/dwc3-rtk-drd.c new file mode 100644 index 000000000000..c9b4b0243793 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-rtk-drd.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * dwc3-rtk-drd.c - Realtek DWC3 Specific Glue layer + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include "core.h" +#include "gadget.h" +#include "io.h" + +static int dwc3_check_drd_mode(struct dwc3 *dwc) +{ + int mode = USB_DR_MODE_UNKNOWN; + + if (dwc->xhci) { + mode = USB_DR_MODE_HOST; + dev_dbg(dwc->dev, "%s Now is host\n", __func__); + } else if (dwc->gadget && dwc->gadget->udc) { + mode = USB_DR_MODE_PERIPHERAL; + dev_dbg(dwc->dev, "%s Now is gadget\n", __func__); + } + + return mode; +} + +static int rtk_dwc3_drd_core_soft_reset(struct dwc3 *dwc) +{ + int ret; + unsigned long timeout; + u32 reg_gctl, reg_u2phy, reg_u3phy; + + reg_gctl = dwc3_readl(dwc->regs, DWC3_GCTL); + dwc3_writel(dwc->regs, DWC3_GCTL, reg_gctl | DWC3_GCTL_DSBLCLKGTNG); + + reg_u3phy = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), + reg_u3phy & ~DWC3_GUSB3PIPECTL_SUSPHY); + + reg_u2phy = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), + reg_u2phy & ~DWC3_GUSB2PHYCFG_SUSPHY); + + /* issue device SoftReset too */ + timeout = jiffies + msecs_to_jiffies(500); + dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); + do { + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (!(reg & DWC3_DCTL_CSFTRST)) + break; + + if (time_after(jiffies, timeout)) { + dev_err(dwc->dev, "Reset Timed Out\n"); + ret = -ETIMEDOUT; + goto err0; + } + + cpu_relax(); + } while (true); + + ret = dwc3_core_soft_reset(dwc); + +err0: + + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg_u2phy); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg_u3phy); + dwc3_writel(dwc->regs, DWC3_GCTL, reg_gctl); + + return ret; +} + +static int rtk_dwc3_drd_event_buffers_setup(struct dwc3 *dwc) +{ + struct dwc3_event_buffer *evt; + + evt = dwc->ev_buf; + evt->lpos = 0; + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), + lower_32_bits(evt->dma)); + dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), + upper_32_bits(evt->dma)); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_SIZE(evt->length)); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); + + return 0; +} + +static void rtk_dwc3_set_mode(struct dwc3 *dwc, u32 mode) +{ + dwc3_set_prtcap(dwc, mode); +} + +int dwc3_drd_to_host(struct dwc3 *dwc) +{ + int ret; + + dev_info(dwc->dev, "%s START....", __func__); + if (dwc3_check_drd_mode(dwc) == USB_DR_MODE_PERIPHERAL) { + dwc3_gadget_exit(dwc); + } + /* Do wmb */ + wmb(); + + if (dwc3_check_drd_mode(dwc) == USB_DR_MODE_HOST) { + dev_info(dwc->dev, "%s Now is host", __func__); + return 0; + } + + dev_info(dwc->dev, "%s: call dwc3_core_soft_reset\n", __func__); + + ret = rtk_dwc3_drd_core_soft_reset(dwc); + if (ret) { + dev_err(dwc->dev, "soft reset failed\n"); + goto err0; + } + + ret = rtk_dwc3_drd_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto err0; + } + + rtk_dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + + ret = dwc3_host_init(dwc); + if (ret) + dev_err(dwc->dev, "failed to init host\n"); + +err0: + dev_info(dwc->dev, "%s END....", __func__); + return ret; +} + +int dwc3_drd_to_device(struct dwc3 *dwc) +{ + int ret; + unsigned long flags = 0; + + dev_info(dwc->dev, "%s START....", __func__); + + if (dwc3_check_drd_mode(dwc) == USB_DR_MODE_HOST) { + dev_info(dwc->dev, "%s dwc3_host_exit", __func__); + dwc3_host_exit(dwc); + } + /* Do wmb */ + wmb(); + + if (dwc3_check_drd_mode(dwc) == USB_DR_MODE_PERIPHERAL) { + dev_info(dwc->dev, "%s Now is gadget", __func__); + return 0; + } + + dev_info(dwc->dev, "%s: call dwc3_core_soft_reset\n", __func__); + ret = rtk_dwc3_drd_core_soft_reset(dwc); + if (ret) { + dev_err(dwc->dev, "soft reset failed\n"); + goto err0; + } + + spin_lock_irqsave(&dwc->lock, flags); + + ret = rtk_dwc3_drd_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + spin_unlock_irqrestore(&dwc->lock, flags); + goto err0; + } + + rtk_dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + + spin_unlock_irqrestore(&dwc->lock, flags); + + ret = dwc3_gadget_init(dwc); + if (ret) + dev_err(dwc->dev, "failed to init gadget\n"); + +err0: + dev_info(dwc->dev, "%s END....", __func__); + return ret; +} + +int dwc3_drd_to_stop_all(struct dwc3 *dwc) +{ + int ret = 0; + + dev_info(dwc->dev, "%s START....", __func__); + if (dwc3_check_drd_mode(dwc) == USB_DR_MODE_HOST) + dwc3_host_exit(dwc); + if (dwc3_check_drd_mode(dwc) == USB_DR_MODE_PERIPHERAL) + dwc3_gadget_exit(dwc); + + /* Do wmb */ + wmb(); + dev_info(dwc->dev, "%s END....", __func__); + return ret; +} diff --git a/drivers/usb/dwc3/dwc3-rtk-drd.h b/drivers/usb/dwc3/dwc3-rtk-drd.h new file mode 100644 index 000000000000..997d5c3fc301 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-rtk-drd.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * dwc3-rtk-drd.h - Realtek DWC3 Specific Glue layer + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#ifndef __DRIVERS_USB_DWC3_RTK_DRD_H +#define __DRIVERS_USB_DWC3_RTK_DRD_H + +struct dwc3; + +int dwc3_drd_to_host(struct dwc3 *dwc); +int dwc3_drd_to_device(struct dwc3 *dwc); +int dwc3_drd_to_stop_all(struct dwc3 *dwc); + +struct dwc3_rtk; + +int dwc3_rtk_get_dr_mode(struct dwc3_rtk *rtk); +int dwc3_rtk_set_dr_mode(struct dwc3_rtk *rtk, int dr_mode); +bool dwc3_rtk_is_connected_on_device_mode(struct dwc3_rtk *dwc3_rtk); +bool dwc3_rtk_is_support_drd_mode(struct dwc3_rtk *dwc3_rtk); + +#endif /* __DRIVERS_USB_DWC3_RTK_CORE_H */ + diff --git a/drivers/usb/dwc3/dwc3-rtk-type_c.c b/drivers/usb/dwc3/dwc3-rtk-type_c.c new file mode 100644 index 000000000000..016fc4db9eae --- /dev/null +++ b/drivers/usb/dwc3/dwc3-rtk-type_c.c @@ -0,0 +1,2801 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * * dwc3-rtk-type_c.c - Realtek DWC3 Type C driver + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TYPEC +#include +#endif + +#include "dwc3-rtk-drd.h" + +#ifdef CONFIG_DUAL_ROLE_USB_INTF +#include +#endif + +#ifdef CONFIG_USB_TYPE_C_RTK_RTS5400 +extern bool rtk_rts5400_is_UFP_attached(void); +extern bool rtk_rts5400_is_enabled(void); +extern int rtk_rts5400_set_type_c_soft_reset(void); +#endif + +static const struct soc_device_attribute rtk_soc_kylin[] = { + { + .family = "Realtek Kylin", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_hercules[] = { + { + .family = "Realtek Hercules", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_typc_parameter_v0[] = { + { + .family = "Realtek Kylin", + }, + { + .family = "Realtek Hercules", + }, + { + .family = "Realtek Thor", + }, + { + .family = "Realtek Hank", + }, + { + /* empty */ + } +}; + +struct dwc3_rtk; + +struct type_c_data { + void __iomem *type_c_reg_base; + struct device *dev; + + u32 irq; + + int chip_revision; + + /* rd control GPIO only for rtd129x*/ + unsigned int rd_ctrl_gpio; + + /* Parameters */ + int para_ver; /* Parameter version */ + u32 cc1_rp; + u32 cc1_rp_code; + u32 cc1_rd_code; + u32 cc1_vref_ufp; + u32 cc1_vref_dfp_usb; + u32 cc1_vref_dfp_1_5; + u32 cc1_vref_dfp_3_0; + u32 cc2_rp; + u32 cc2_rp_code; + u32 cc2_rd_code; + u32 cc2_vref_ufp; + u32 cc2_vref_dfp_usb; + u32 cc2_vref_dfp_1_5; + u32 cc2_vref_dfp_3_0; + u32 debounce_val; /* 1b,1us 7f,4.7us */ + int cc_dfp_mode; + + bool use_defalut_parameter; + + /* Host/Device mode status */ + struct dwc3_rtk *dwc3_rtk; + int dr_mode; /* current mode in type c cc status */ + + /* type_c state */ + int connect_change; +#define CONNECT_CHANGE 1 +#define CONNECT_NO_CHANGE 0 + int cc_mode; /* cc is host or device */ +#define IN_HOST_MODE 1 +#define IN_DEVICE_MODE 0 + int is_attach; +#define IN_ATTACH 1 +#define TO_ATTACH 1 +#define IN_DETACH 0 +#define TO_DETACH 0 + int at_cc1; +#define AT_CC1 1 +#define AT_CC2 0 + bool is_role_swap; /* if in role swap */ +#define ROLE_SWAP 1 +#define NO_ROLE_SWAP 0 +#define TO_SWAP_ROLE 1 +#define TO_RESTORE_ROLE 0 + + u32 int_status; + u32 cc_status; + spinlock_t lock; + struct delayed_work delayed_work; + + struct work_struct start_work; + + /* boot time check device mode transfer to host mode*/ + bool check_at_boot; + int boot_check_time; + struct delayed_work boot_check_work; + + bool rd_en_at_first; + + /* A sw debounce to filter cc signal */ + bool filter_config_channel_signal; + + bool debug; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debug_dir; +#endif + +#ifdef CONFIG_DUAL_ROLE_USB_INTF + struct dual_role_phy_instance *drp; +#endif +#ifdef CONFIG_TYPEC + struct typec_port *port; +#endif /* CONFIG_TYPEC */ +}; + +/* Type C register offset */ +#define USB_TYPEC_CTRL_CC1_0 0x0 +#define USB_TYPEC_CTRL_CC1_1 0x4 +#define USB_TYPEC_CTRL_CC2_0 0x8 +#define USB_TYPEC_CTRL_CC2_1 0xC +#define USB_TYPEC_STS 0x10 +#define USB_TYPEC_CTRL 0x14 +#define USB_DBUS_PWR_CTRL 0x18 + +#define enable_cc1 0x1 +#define enable_cc2 0x2 +#define disable_cc 0x0 + +/* Bit mapping USB_TYPEC_CTRL_CC1_0 and USB_TYPEC_CTRL_CC2_0 */ +#define PLR_EN BIT(29) +#define rp4pk_code(val) ((0x1f & val) << 22) +#define code_rp4pk(val) ((val >> 22) & 0x1f) +#define rp36k_code(val) ((0x1f & val) << 17) +#define code_rp36k(val) ((val >> 17) & 0x1f) +#define rp12k_code(val) ((0x1f & val) << 12) +#define code_rp12k(val) ((val >> 12) & 0x1f) +#define rd_code(val) ((0x1f & val) << 7) +#define code_rd(val) ((val >> 7) & 0x1f) +#define cc_mode(val) ((0x3 & val) << 5) +#define En_rp4p7k BIT(4) +#define En_rp36k BIT(3) +#define En_rp12k BIT(2) +#define En_rd BIT(1) +#define En_cc_det BIT(0) + +#define CC_MODE_UFP 0x0 +#define CC_MODE_DFP_USB 0x1 +#define CC_MODE_DFP_1_5 0x2 +#define CC_MODE_DFP_3_0 0x3 + +/* Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */ +#define V0_vref_2p6v(val) ((0x7 & val) << 26) +#define V0_vref_1p23v(val) ((0xf & val) << 22) +#define V0_vref_0p8v(val) ((0xf & val) << 18) +#define V0_vref_0p66v(val) ((0xf & val) << 14) +#define V0_vref_0p4v(val) ((0x7 & val) << 11) +#define V0_vref_0p2v(val) ((0x7 & val) << 8) +#define V0_vref_1_1p6v(val) ((0xf & val) << 4) +#define V0_vref_0_1p6v(val) ((0xf & val) << 0) + +#define V0_decode_2p6v(val) ((val >> 26) & 0x7) +#define V0_decode_1p23v(val) ((val >> 22) & 0xf) +#define V0_decode_0p8v(val) ((val >> 18) & 0xf) +#define V0_decode_0p66v(val) ((val >> 14) & 0xf) +#define V0_decode_0p4v(val) ((val >> 11) & 0x7) +#define V0_decode_0p2v(val) ((val >> 8) & 0x7) +#define V0_decode_1_1p6v(val) ((val >> 4) & 0xf) +#define V0_decode_0_1p6v(val) ((val >> 0) & 0xf) + +/* new Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */ +#define V1_vref_2p6v(val) ((0xf & val) << 28) +#define V1_vref_1p23v(val) ((0xf & val) << 24) +#define V1_vref_0p8v(val) ((0xf & val) << 20) +#define V1_vref_0p66v(val) ((0xf & val) << 16) +#define V1_vref_0p4v(val) ((0xf & val) << 12) +#define V1_vref_0p2v(val) ((0xf & val) << 8) +#define V1_vref_1_1p6v(val) ((0xf & val) << 4) +#define V1_vref_0_1p6v(val) ((0xf & val) << 0) + +#define V1_decode_2p6v(val) ((val >> 28) & 0xf) +#define V1_decode_1p23v(val) ((val >> 24) & 0xf) +#define V1_decode_0p8v(val) ((val >> 20) & 0xf) +#define V1_decode_0p66v(val) ((val >> 16) & 0xf) +#define V1_decode_0p4v(val) ((val >> 12) & 0xf) +#define V1_decode_0p2v(val) ((val >> 8) & 0xf) +#define V1_decode_1_1p6v(val) ((val >> 4) & 0xf) +#define V1_decode_0_1p6v(val) ((val >> 0) & 0xf) + +/* Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */ +#define vref_2p6v(val) (type_c->para_ver?V1_vref_2p6v(val):V0_vref_2p6v(val)) +#define vref_1p23v(val) (type_c->para_ver?V1_vref_1p23v(val):V0_vref_1p23v(val)) +#define vref_0p8v(val) (type_c->para_ver?V1_vref_0p8v(val):V0_vref_0p8v(val)) +#define vref_0p66v(val) (type_c->para_ver?V1_vref_0p66v(val):V0_vref_0p66v(val)) +#define vref_0p4v(val) (type_c->para_ver?V1_vref_0p4v(val):V0_vref_0p4v(val)) +#define vref_0p2v(val) (type_c->para_ver?V1_vref_0p2v(val):V0_vref_0p2v(val)) +#define vref_1_1p6v(val) (type_c->para_ver?V1_vref_1_1p6v(val):V0_vref_1_1p6v(val)) +#define vref_0_1p6v(val) (type_c->para_ver?V1_vref_0_1p6v(val):V0_vref_0_1p6v(val)) + +#define decode_2p6v(val) (type_c->para_ver?V1_decode_2p6v(val):V0_decode_2p6v(val)) +#define decode_1p23v(val) (type_c->para_ver?V1_decode_1p23v(val):V0_decode_1p23v(val)) +#define decode_0p8v(val) (type_c->para_ver?V1_decode_0p8v(val):V0_decode_0p8v(val)) +#define decode_0p66v(val) (type_c->para_ver?V1_decode_0p66v(val):V0_decode_0p66v(val)) +#define decode_0p4v(val) (type_c->para_ver?V1_decode_0p4v(val):V0_decode_0p4v(val)) +#define decode_0p2v(val) (type_c->para_ver?V1_decode_0p2v(val):V0_decode_0p2v(val)) +#define decode_1_1p6v(val) (type_c->para_ver?V1_decode_1_1p6v(val):V0_decode_1_1p6v(val)) +#define decode_0_1p6v(val) (type_c->para_ver?V1_decode_0_1p6v(val):V0_decode_0_1p6v(val)) + +/* Bit mapping USB_TYPEC_STS */ +#define det_sts 0x7 +#define cc1_det_sts (det_sts) +#define cc2_det_sts (det_sts << 3) +#define det_sts_ra 0x1 +#define det_sts_rd 0x3 +#define det_sts_rp 0x1 +#define cc1_det_sts_ra (det_sts_ra) +#define cc1_det_sts_rd (det_sts_rd) +#define cc1_det_sts_rp (det_sts_rp) +#define cc2_det_sts_ra (det_sts_ra << 3) +#define cc2_det_sts_rd (det_sts_rd << 3) +#define cc2_det_sts_rp (det_sts_rp << 3) + +/* Bit mapping USB_TYPEC_CTRL */ +#define cc2_int_en BIT(11) +#define cc1_int_en BIT(10) +#define cc2_int_sts BIT(9) +#define cc1_int_sts BIT(8) +#define debounce_time_MASK 0xff +#define ENABLE_TYPE_C_DETECT (cc1_int_en | cc2_int_en) +#define all_cc_int_sts (cc1_int_sts | cc2_int_sts) + +/* Parameter */ +#define DETECT_TIME 50 /* ms */ + +static void enable_writel(int value, void __iomem *addr) +{ + writel(value | readl(addr), addr); +} + +static void disable_writel(int value, void __iomem *addr) +{ + writel(~value & readl(addr), addr); +} + +static inline int rtk_type_c_init(struct type_c_data *type_c) +{ + dev_info(type_c->dev, "%s\n", __func__); + + rtk_usb_type_c_init(type_c->dev); + + return 0; +} + +static int rtd129x_switch_type_c_plug_config(struct type_c_data *type_c, + int dr_mode, int cc) +{ + void __iomem *usb_typec_ctrl_cc1_0; + int val_cc; + +#define TYPE_C_EN_SWITCH BIT(29) +#define TYPE_C_TxRX_sel (BIT(28) | BIT(27)) +#define TYPE_C_SWITCH_MASK (TYPE_C_EN_SWITCH | TYPE_C_TxRX_sel) +#define TYPE_C_enable_cc1 TYPE_C_EN_SWITCH +#define TYPE_C_enable_cc2 (TYPE_C_EN_SWITCH | TYPE_C_TxRX_sel) +#define TYPE_C_disable_cc ~TYPE_C_SWITCH_MASK + + usb_typec_ctrl_cc1_0 = type_c->type_c_reg_base + USB_TYPEC_CTRL_CC1_0; + val_cc = readl(usb_typec_ctrl_cc1_0); + val_cc &= ~TYPE_C_SWITCH_MASK; + + if (cc == disable_cc) { + val_cc &= TYPE_C_disable_cc; + } else if (cc == enable_cc1) { + val_cc |= TYPE_C_enable_cc1; + } else if (cc == enable_cc2) { + val_cc |= TYPE_C_enable_cc2; + } else { + pr_err("%s: Error cc setting cc=0x%x\n", __func__, cc); + return -1; + } + writel(val_cc, usb_typec_ctrl_cc1_0); + + mdelay(1); + + pr_info("%s: cc=0x%x val_cc=0x%x usb_typec_ctrl_cc1_0=0x%x\n", + __func__, cc, val_cc, readl(usb_typec_ctrl_cc1_0)); + + return 0; +} + +static inline void switch_type_c_plug_config(struct type_c_data *type_c, + int dr_mode, int cc) +{ + int ret = 0; + + dev_info(type_c->dev, "%s dr_mode=%d cc=0x%x\n", __func__, dr_mode, cc); + + if (soc_device_match(rtk_soc_kylin)) + ret = rtd129x_switch_type_c_plug_config(type_c, dr_mode, cc); + + if (ret < 0) + dev_err(type_c->dev, "%s: Error set type c plug config\n", + __func__); + + rtk_usb_type_c_plug_config(type_c->dev, dr_mode, cc); +} + +static void switch_type_c_dr_mode(struct type_c_data *type_c, + int dr_mode, int cc) +{ + dev_dbg(type_c->dev, "%s START....", __func__); + + switch_type_c_plug_config(type_c, dr_mode, cc); + if (cc == disable_cc) + msleep(1000); + + type_c->dr_mode = dwc3_rtk_set_dr_mode(type_c->dwc3_rtk, dr_mode); + +#ifdef CONFIG_TYPEC + if (type_c->port) { + switch (dr_mode) { + case USB_DR_MODE_HOST: + typec_set_data_role(type_c->port, TYPEC_HOST); + typec_set_pwr_role(type_c->port, TYPEC_SOURCE); + break; + case USB_DR_MODE_PERIPHERAL: + typec_set_data_role(type_c->port, + TYPEC_DEVICE); + typec_set_pwr_role(type_c->port, TYPEC_SINK); + break; + default: + dev_dbg(type_c->dev, "%s unknown dr_mode=%d\n", + __func__, dr_mode); + break; + } + } +#endif + + dev_dbg(type_c->dev, "%s END....", __func__); +} + +/* device attached/detached */ +static int device_attached(struct type_c_data *type_c, u32 enable_cc) +{ + struct device *dev = type_c->dev; + void __iomem *type_c_reg_base = type_c->type_c_reg_base; + + dev_info(dev, "%s: a device attach\n", __func__); + + cancel_delayed_work(&type_c->delayed_work); + + switch_type_c_dr_mode(type_c, USB_DR_MODE_HOST, enable_cc); + + enable_writel(ENABLE_TYPE_C_DETECT, type_c_reg_base + USB_TYPEC_CTRL); + return 0; +} + +static int device_detached(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + void __iomem *type_c_reg_base = type_c->type_c_reg_base; + + dev_info(dev, "%s: a device detach\n", __func__); + + disable_writel(ENABLE_TYPE_C_DETECT, type_c_reg_base + USB_TYPEC_CTRL); + + switch_type_c_dr_mode(type_c, 0, disable_cc); + + schedule_delayed_work(&type_c->delayed_work, + msecs_to_jiffies(DETECT_TIME)); + + return 0; +} + +/* host connect/disconnect*/ +static int host_connected(struct type_c_data *type_c, u32 enable_cc) +{ + struct device *dev = type_c->dev; + void __iomem *type_c_reg_base = type_c->type_c_reg_base; + + dev_info(dev, "%s: a Host connect\n", __func__); + + cancel_delayed_work(&type_c->delayed_work); + + switch_type_c_dr_mode(type_c, USB_DR_MODE_PERIPHERAL, enable_cc); + + enable_writel(ENABLE_TYPE_C_DETECT, type_c_reg_base + USB_TYPEC_CTRL); + return 0; +} + +static int host_disconnected(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + void __iomem *type_c_reg_base = type_c->type_c_reg_base; + + dev_info(dev, "%s: a Host disconnect\n", __func__); + + disable_writel(ENABLE_TYPE_C_DETECT, type_c_reg_base + USB_TYPEC_CTRL); + + switch_type_c_dr_mode(type_c, 0, disable_cc); + + schedule_delayed_work(&type_c->delayed_work, + msecs_to_jiffies(DETECT_TIME)); + + return 0; +} + +/* detect host device switch */ +static int detect_device(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + void __iomem *type_c_reg_base = type_c->type_c_reg_base; + unsigned int gpio = type_c->rd_ctrl_gpio; + u32 cc1_config, cc2_config, default_ctrl; + int cc_mode_sel = type_c->cc_dfp_mode; + + /* For kylin to disable external rd control gpio */ + if (soc_device_match(rtk_soc_kylin)) { + if (gpio != -1 && gpio_is_valid(gpio)) { + if (gpio_direction_output(gpio, 1)) + dev_err(dev, "%s ERROR rd_ctrl_gpio=1 fail\n", + __func__); + } + } + + default_ctrl = readl(type_c_reg_base + USB_TYPEC_CTRL) & + debounce_time_MASK; + writel(default_ctrl, type_c_reg_base + USB_TYPEC_CTRL); + + disable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC1_0); + disable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC2_0); + + switch (cc_mode_sel) { + case CC_MODE_DFP_USB: + writel(type_c->cc1_vref_dfp_usb, + type_c_reg_base + USB_TYPEC_CTRL_CC1_1); + writel(type_c->cc2_vref_dfp_usb, + type_c_reg_base + USB_TYPEC_CTRL_CC2_1); + break; + case CC_MODE_DFP_1_5: + writel(type_c->cc1_vref_dfp_1_5, + type_c_reg_base + USB_TYPEC_CTRL_CC1_1); + writel(type_c->cc2_vref_dfp_1_5, + type_c_reg_base + USB_TYPEC_CTRL_CC2_1); + break; + case CC_MODE_DFP_3_0: + writel(type_c->cc1_vref_dfp_3_0, + type_c_reg_base + USB_TYPEC_CTRL_CC1_1); + writel(type_c->cc2_vref_dfp_3_0, + type_c_reg_base + USB_TYPEC_CTRL_CC2_1); + break; + default: + dev_err(dev, "%s ERROR cc_mode_sel=%d\n", + __func__, cc_mode_sel); + break; + } + cc1_config = type_c->cc1_rp | type_c->cc1_rp_code | + cc_mode(cc_mode_sel); + cc2_config = type_c->cc2_rp | type_c->cc2_rp_code | + cc_mode(cc_mode_sel); + + writel(cc1_config, type_c_reg_base + USB_TYPEC_CTRL_CC1_0); + writel(cc2_config, type_c_reg_base + USB_TYPEC_CTRL_CC2_0); + + /* Do wmb */ + wmb(); + + enable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC1_0); + enable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC2_0); + + return 0; +} + +static int detect_host(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + void __iomem *type_c_reg_base = type_c->type_c_reg_base; + unsigned int gpio = type_c->rd_ctrl_gpio; + u32 cc1_config, cc2_config, default_ctrl; + u32 cc_rd = En_rd; + + if (type_c->rd_en_at_first) { + if (soc_device_match(rtk_soc_kylin)) { + cc_rd = 0; + /* use external Rd */ + if (gpio != -1 && gpio_is_valid(gpio)) { + if (gpio_direction_output(gpio, 0)) + dev_err(dev, "%s ERROR rd_ctrl_gpio=0 fail\n", + __func__); + } + } else { + dev_info(dev, "%s set PLR_EN on rd_en_at_first\n", + __func__); + cc_rd = PLR_EN; + } + type_c->rd_en_at_first = false; + } else { + /* For kylin to disable external rd control gpio */ + if (soc_device_match(rtk_soc_kylin)) { + /* use internal Rd */ + if (gpio != -1 && gpio_is_valid(gpio)) { + if (gpio_direction_output(gpio, 1)) + dev_err(dev, "%s ERROR rd_ctrl_gpio=1 fail\n", + __func__); + } + } + } + + default_ctrl = readl(type_c_reg_base + USB_TYPEC_CTRL) & + debounce_time_MASK; + writel(default_ctrl, type_c_reg_base + USB_TYPEC_CTRL); + + disable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC1_0); + disable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC2_0); + + writel(type_c->cc1_vref_ufp, type_c_reg_base + USB_TYPEC_CTRL_CC1_1); + writel(type_c->cc2_vref_ufp, type_c_reg_base + USB_TYPEC_CTRL_CC2_1); + + cc1_config = cc_rd | type_c->cc1_rd_code | cc_mode(CC_MODE_UFP); + cc2_config = cc_rd | type_c->cc2_rd_code | cc_mode(CC_MODE_UFP); + + writel(cc1_config, type_c_reg_base + USB_TYPEC_CTRL_CC1_0); + writel(cc2_config, type_c_reg_base + USB_TYPEC_CTRL_CC2_0); + + /* Do wmb */ + wmb(); + + enable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC1_0); + enable_writel(En_cc_det, type_c_reg_base + USB_TYPEC_CTRL_CC2_0); + + return 0; +} + +static int host_device_switch_detection(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + int ret = 0; + + if (type_c->debug) + dev_dbg(dev, "ENTER %s", __func__); + if (type_c->cc_mode) { + type_c->cc_mode = IN_DEVICE_MODE; + detect_host(type_c); + if (type_c->debug) + dev_dbg(dev, "Now device mode $$$$"); + } else { + type_c->cc_mode = IN_HOST_MODE; + detect_device(type_c); + if (type_c->debug) + dev_dbg(dev, "Now host mode ####"); + } + + return ret; +} + +static int detect_type_c_state(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + u32 int_status, cc_status, cc_status_check; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + int_status = readl(type_c->type_c_reg_base + USB_TYPEC_CTRL); + cc_status = readl(type_c->type_c_reg_base + USB_TYPEC_STS); + + type_c->connect_change = CONNECT_NO_CHANGE; + + switch (type_c->cc_mode) { + case IN_HOST_MODE: + switch (type_c->is_attach) { + case IN_ATTACH: + if (((cc_status & cc1_det_sts) == cc1_det_sts) && + (type_c->at_cc1 == AT_CC1)) { + dev_dbg(dev, "IN host mode and cc1 device detach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } else if (((cc_status & cc2_det_sts) == cc2_det_sts) && + (type_c->at_cc1 == AT_CC2)) { + dev_dbg(dev, "IN host mode and cc2 device detach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } + break; + case IN_DETACH: + cc_status_check = readl( + type_c->type_c_reg_base + USB_TYPEC_STS); + if (cc_status_check != (cc1_det_sts | cc2_det_sts)) { + if (in_interrupt()) { + mdelay(300); + } else { + spin_unlock_irqrestore(&type_c->lock, + flags); + msleep(300); + spin_lock_irqsave(&type_c->lock, flags); + } + cc_status_check = readl( + type_c->type_c_reg_base + + USB_TYPEC_STS); + } + if (cc_status != cc_status_check) { + dev_warn(dev, "IN_HOST_MODE: cc_status (0x%x) != cc_status_check (0x%x)\n", + cc_status, cc_status_check); + cc_status = readl(type_c->type_c_reg_base + + USB_TYPEC_STS); + } + + if ((cc_status & cc1_det_sts) == cc1_det_sts_rd) { + dev_dbg(dev, "IN host mode and cc1 device attach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_ATTACH; + type_c->at_cc1 = AT_CC1; + type_c->connect_change = CONNECT_CHANGE; + } else if ((cc_status & cc2_det_sts) == + cc2_det_sts_rd) { + dev_dbg(dev, "In host mode and cc2 device attach (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_ATTACH; + type_c->at_cc1 = AT_CC2; + type_c->connect_change = CONNECT_CHANGE; + } + break; + default: + dev_err(dev, "IN host_mode and error attach state (is_attach=%d)", + type_c->is_attach); + } + break; + case IN_DEVICE_MODE: + switch (type_c->is_attach) { + case IN_ATTACH: + if (type_c->filter_config_channel_signal && + ((cc_status & cc1_det_sts) < + cc1_det_sts_rp || + (cc_status & cc2_det_sts) < + cc2_det_sts_rp)) { + /* Add a sw debounce to filter cc signal sent + * from apple pd adapter + */ + if (in_interrupt()) { + mdelay(5); + } else { + spin_unlock_irqrestore( + &type_c->lock, flags); + msleep(5); + spin_lock_irqsave(&type_c->lock, flags); + } + cc_status_check = readl( + type_c->type_c_reg_base + + USB_TYPEC_STS); + + if (cc_status != cc_status_check) { + dev_dbg(dev, "IN_DEVICE_MODE: cc_status (0x%x) != cc_status_check (0x%x) maybe use a pd adapter\n", + cc_status, cc_status_check); + cc_status = cc_status_check; + } + } + + if ((cc_status & cc1_det_sts) < cc1_det_sts_rp && + type_c->at_cc1 == AT_CC1) { + dev_dbg(dev, "IN device mode and cc1 host disconnect (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } else if ((cc_status & cc2_det_sts) < cc2_det_sts_rp && + type_c->at_cc1 == AT_CC2) { + dev_dbg(dev, "IN device mode and cc2 host disconnect (cc_status=0x%x)", + cc_status); + type_c->is_attach = TO_DETACH; + type_c->connect_change = CONNECT_CHANGE; + } + break; + case IN_DETACH: + cc_status_check = readl(type_c->type_c_reg_base + + USB_TYPEC_STS); + if (cc_status_check != 0x0) { + if (in_interrupt()) { + mdelay(300); + } else { + spin_unlock_irqrestore(&type_c->lock, + flags); + msleep(300); + spin_lock_irqsave(&type_c->lock, flags); + } + cc_status_check = readl( + type_c->type_c_reg_base + + USB_TYPEC_STS); + } + if (cc_status != cc_status_check) { + dev_warn(dev, "IN_DEVICE_MODE: cc_status (0x%x) != cc_status_check (0x%x)\n", + cc_status, cc_status_check); + cc_status = readl(type_c->type_c_reg_base + + USB_TYPEC_STS); + } + + if ((cc_status & cc1_det_sts) >= cc1_det_sts_rp) { + dev_dbg(dev, "IN device mode and cc1 host connect (cc_status=0x%x)", + cc_status); + type_c->at_cc1 = AT_CC1; + type_c->is_attach = TO_ATTACH; + type_c->connect_change = CONNECT_CHANGE; + } else if ((cc_status & cc2_det_sts) >= + cc2_det_sts_rp) { + dev_dbg(dev, "IN device mode and cc2 host connect (cc_status=0x%x)", + cc_status); + type_c->at_cc1 = AT_CC2; + type_c->is_attach = TO_ATTACH; + type_c->connect_change = CONNECT_CHANGE; + } + break; + default: + dev_err(dev, "IN device_mode and error attach state (is_attach=%d)", + type_c->is_attach); + } + break; + default: + dev_err(dev, "error host or device mode (cc_mode=%d)", + type_c->cc_mode); + } + + type_c->int_status = int_status; + type_c->cc_status = cc_status; + + spin_unlock_irqrestore(&type_c->lock, flags); + return 0; +} + +static void host_device_switch(struct work_struct *work) +{ + struct type_c_data *type_c = container_of(work, + struct type_c_data, delayed_work.work); + struct device *dev = type_c->dev; + unsigned long flags; + int connect_change = 0; + int cc_mode = 0; + int is_attach = 0; + int at_cc1 = 0; + + if (type_c->debug) + dev_dbg(type_c->dev, "ENTER %s", __func__); + + spin_lock_irqsave(&type_c->lock, flags); + if (type_c->connect_change) + connect_change = type_c->connect_change; + spin_unlock_irqrestore(&type_c->lock, flags); + + if (!connect_change) + detect_type_c_state(type_c); + + spin_lock_irqsave(&type_c->lock, flags); + if (type_c->connect_change) { + connect_change = type_c->connect_change; + cc_mode = type_c->cc_mode; + is_attach = type_c->is_attach; + at_cc1 = type_c->at_cc1; + type_c->connect_change = CONNECT_NO_CHANGE; + type_c->is_role_swap = NO_ROLE_SWAP; + } else { + host_device_switch_detection(type_c); + + schedule_delayed_work(&type_c->delayed_work, + msecs_to_jiffies(DETECT_TIME)); + } + spin_unlock_irqrestore(&type_c->lock, flags); + + if (connect_change) { + dev_info(dev, "%s: usb cable connection change\n", __func__); +#ifdef CONFIG_USB_TYPE_C_RTK_RTS5400 + if (type_c->check_at_boot + && rtk_rts5400_is_enabled() + && rtk_rts5400_is_UFP_attached()) { + u32 enable_cc = at_cc1?enable_cc1:enable_cc2; + + dev_info(dev, "%s: In Device mode, role swap to Host mode\n", + __func__); + switch_type_c_dr_mode(type_c, USB_DR_MODE_HOST, + enable_cc); + + rtk_rts5400_set_type_c_soft_reset(); + + type_c->check_at_boot = false; + } else +#endif //CONFIG_USB_TYPE_C_RTK_RTS5400 + if (cc_mode) { + if (is_attach && at_cc1) + device_attached(type_c, enable_cc1); + else if (is_attach && !at_cc1) + device_attached(type_c, enable_cc2); + else + device_detached(type_c); + } else { + if (is_attach && at_cc1) + host_connected(type_c, enable_cc1); + else if (is_attach && !at_cc1) + host_connected(type_c, enable_cc2); + else + host_disconnected(type_c); + } + dev_err(dev, "Connection change OK: IN %s mode to %s %s at %s (cc_status=0x%x)\n", + cc_mode?"host":"device", + cc_mode ? + (is_attach?"attach":"detach") : + (is_attach?"connect":"disconnect"), + cc_mode?"device":"host", + at_cc1?"cc1":"cc2", type_c->cc_status); + + } + + /* For special case, some boards use type c power and + * need use host mode. + * After 30s, We switch to host mode if in device mode + * but no host connect. + */ + if (type_c->check_at_boot) { + if (connect_change && + (cc_mode == IN_DEVICE_MODE) && + is_attach) { + dev_info(dev, "%s: In Device mode check connection at boot time\n", + __func__); + schedule_delayed_work(&type_c->boot_check_work, + msecs_to_jiffies(type_c->boot_check_time)); + } + type_c->check_at_boot = false; + } +} + +static int host_device_role_swap(struct type_c_data *type_c, bool swap_role) +{ + int ret = 0; + int swap_to_xx_mode = USB_DR_MODE_UNKNOWN; + int at_cc1, cc_mode, is_attach; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + at_cc1 = type_c->at_cc1; + cc_mode = type_c->cc_mode; + is_attach = type_c->is_attach; + + spin_unlock_irqrestore(&type_c->lock, flags); + + if (!is_attach) { + dev_warn(type_c->dev, "Can not swap role!! It is Not attach\n"); + return -1; + } + + dev_info(type_c->dev, "%s: In %s Mode and now is%s role swap ", + __func__, + cc_mode == IN_HOST_MODE?"Host":"Device", + type_c->is_role_swap == ROLE_SWAP?"":" Not"); + + if (swap_role == TO_RESTORE_ROLE && + type_c->is_role_swap == ROLE_SWAP) + /* Restore Role */ + if (cc_mode == IN_DEVICE_MODE) + swap_to_xx_mode = USB_DR_MODE_PERIPHERAL; + else + swap_to_xx_mode = USB_DR_MODE_HOST; + else if (swap_role == TO_SWAP_ROLE && + type_c->is_role_swap == NO_ROLE_SWAP) + /* Swap Role */ + if (cc_mode == IN_DEVICE_MODE) + swap_to_xx_mode = USB_DR_MODE_HOST; + else + swap_to_xx_mode = USB_DR_MODE_PERIPHERAL; + else + dev_info(type_c->dev, "%s: Other Case swap_role=%x is_role_swap=%x\n", + __func__, swap_role, type_c->is_role_swap); + + if (swap_to_xx_mode != USB_DR_MODE_UNKNOWN) { + u32 enable_cc = at_cc1?enable_cc1:enable_cc2; + + dev_info(type_c->dev, "%s: now is%s role swap ==> to %s role (swap_to_xx_mode=%s\n", + __func__, + type_c->is_role_swap == ROLE_SWAP?"":" No", + swap_role == TO_SWAP_ROLE?"swap":"restore", + ({ char *tmp; + switch (swap_to_xx_mode) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; })); + + switch_type_c_plug_config(type_c, 0, disable_cc); + mdelay(100); + switch_type_c_dr_mode(type_c, swap_to_xx_mode, enable_cc); + + type_c->is_role_swap = (swap_role == TO_SWAP_ROLE ? + ROLE_SWAP : NO_ROLE_SWAP); + } else { + dev_info(type_c->dev, "%s: No swap and No restore\n", __func__); + } + + return ret; +} + +static void boot_time_check(struct work_struct *work) +{ + struct type_c_data *type_c = container_of(work, + struct type_c_data, boot_check_work.work); + struct device *dev = type_c->dev; + int at_cc1, cc_mode, is_attach; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + at_cc1 = type_c->at_cc1; + cc_mode = type_c->cc_mode; + is_attach = type_c->is_attach; + + spin_unlock_irqrestore(&type_c->lock, flags); + + if ((cc_mode == IN_DEVICE_MODE) && is_attach) { + + if (!dwc3_rtk_is_connected_on_device_mode( + type_c->dwc3_rtk)) { + dev_info(dev, "%s: In Device mode, NO host connect at boot time (After %dms), switch to Host mode\n", + __func__, type_c->boot_check_time); + + host_device_role_swap(type_c, TO_SWAP_ROLE); + } + } +} + +irqreturn_t type_c_detect_irq(int irq, void *__data) +{ + struct type_c_data *type_c = (struct type_c_data *) __data; + struct device *dev = type_c->dev; + unsigned long flags; + + detect_type_c_state(type_c); + + spin_lock_irqsave(&type_c->lock, flags); + + if (type_c->connect_change) { + dev_info(dev, "%s: IN %s mode to %s %s (at %s interrupt) int_status=0x%x, cc_status=0x%x", + __func__, + type_c->cc_mode?"host":"device", + type_c->cc_mode ? + (type_c->is_attach?"attach":"detach") : + (type_c->is_attach?"connect":"disconnect"), + type_c->cc_mode?"device":"host", + type_c->at_cc1?"cc1":"cc2", + type_c->int_status, type_c->cc_status); + + /* clear interrupt status */ + disable_writel(all_cc_int_sts, + type_c->type_c_reg_base + USB_TYPEC_CTRL); + + cancel_delayed_work(&type_c->delayed_work); + schedule_delayed_work(&type_c->delayed_work, + msecs_to_jiffies(0)); +#ifdef CONFIG_DUAL_ROLE_USB_INTF + if (type_c->drp) + dual_role_instance_changed(type_c->drp); +#endif + } else { + static int local_count; + + if (local_count++ > 10) { + /* clear interrupt status */ + disable_writel(all_cc_int_sts, + type_c->type_c_reg_base + USB_TYPEC_CTRL); + local_count = 0; + } + if (type_c->debug) + dev_dbg(dev, "%s: ###NO change### Status: IN %s mode %s %s (at %s interrupt)\n", + __func__, + type_c->cc_mode?"host":"device", + type_c->cc_mode ? + (type_c->is_attach?"attach":"detach") : + (type_c->is_attach?"connect":"disconnect"), + type_c->cc_mode?"device":"host", + type_c->at_cc1?"cc1":"cc2"); + dev_dbg(dev, "%s: int_status=0x%x, cc_status=0x%x\n", + __func__, + type_c->int_status, type_c->cc_status); + } + + spin_unlock_irqrestore(&type_c->lock, flags); + + return IRQ_HANDLED; +} + +static ssize_t role_swap_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now cc_mode is %s and cur_mode is %s ==> Now is%s role swap\n", + ({ char *tmp; + switch (type_c->cc_mode) { + case IN_DEVICE_MODE: + tmp = "IN_DEVICE_MODE"; break; + case IN_HOST_MODE: + tmp = "IN_HOST_MODE"; break; + default: + tmp = "UNKNOWN"; break; + } tmp; }), + ({ char *tmp; + switch (type_c->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; }), + type_c->is_role_swap == ROLE_SWAP?"":" not"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "write 1 to swap role, ex: echo 1 > role_swap\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "write 0 to restore role, ex: echo 0 > role_swap\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t role_swap_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + + if (!strncmp(buf, "1", 1)) + host_device_role_swap(type_c, TO_SWAP_ROLE); + else if (!strncmp(buf, "0", 1)) + host_device_role_swap(type_c, TO_RESTORE_ROLE); + + return count; +} +static DEVICE_ATTR_RW(role_swap); + +static ssize_t force_set_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now cc_mode is %s and type c dr_mode is %s (dwc3_rtk dr_mode=%s)\n", + ({ char *tmp; + switch (type_c->cc_mode) { + case IN_DEVICE_MODE: + tmp = "IN_DEVICE_MODE"; break; + case IN_HOST_MODE: + tmp = "IN_HOST_MODE"; break; + default: + tmp = "UNKNOWN"; break; + } tmp; }), + ({ char *tmp; + switch (type_c->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; }), + ({ char *tmp; + switch (dwc3_rtk_get_dr_mode(type_c->dwc3_rtk)) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; })); + + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "write host -> switch to Host mode\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "write device -> switch to Device mode\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t force_set_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + unsigned long flags; + u32 enable_cc; + + spin_lock_irqsave(&type_c->lock, flags); + enable_cc = type_c->at_cc1?enable_cc1:enable_cc2; + spin_unlock_irqrestore(&type_c->lock, flags); + + + if (!strncmp(buf, "host", 4)) { + switch_type_c_dr_mode(type_c, USB_DR_MODE_HOST, enable_cc); + } else if (!strncmp(buf, "device", 6)) { + switch_type_c_dr_mode(type_c, USB_DR_MODE_PERIPHERAL, + enable_cc); + } else { + switch_type_c_dr_mode(type_c, 0, disable_cc); + } + return count; +} +static DEVICE_ATTR_RW(force_set_mode); + +#ifdef CONFIG_DEBUG_FS +static int type_c_parameter_show(struct seq_file *s, void *unused) +{ + struct type_c_data *type_c = s->private; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + seq_printf(s, "cc_dfp_mode %s\n", + ({ char *tmp; + switch (type_c->cc_dfp_mode) { + case CC_MODE_DFP_USB: + tmp = "CC_MODE_DFP_USB"; break; + case CC_MODE_DFP_1_5: + tmp = "CC_MODE_DFP_1_5"; break; + case CC_MODE_DFP_3_0: + tmp = "CC_MODE_DFP_3_0"; break; + default: + tmp = "?"; break; + } tmp; })); + seq_printf(s, "cc1_rp 0x%x\n", type_c->cc1_rp); + seq_printf(s, "cc1_rp_code 0x%x\n", + ({ int tmp; + switch (type_c->cc_dfp_mode) { + case CC_MODE_DFP_USB: + tmp = code_rp12k(type_c->cc1_rp_code); break; + case CC_MODE_DFP_1_5: + tmp = code_rp36k(type_c->cc1_rp_code); break; + case CC_MODE_DFP_3_0: + tmp = code_rp4pk(type_c->cc1_rp_code); break; + default: + tmp = -1; break; + } tmp; })); + seq_printf(s, "cc1_rd_code 0x%x\n", + code_rd(type_c->cc1_rd_code)); + seq_printf(s, "cc1_vref_ufp vref_1p23v 0x%x vref_0p66v 0x%x vref_0p2v 0x%x\n", + decode_1p23v(type_c->cc1_vref_ufp), + decode_0p66v(type_c->cc1_vref_ufp), + decode_0p2v(type_c->cc1_vref_ufp)); + seq_printf(s, "cc1_vref_dfp_usb vref_0_1p6v 0x%x vref_0p2v 0x%x\n", + decode_0_1p6v(type_c->cc1_vref_dfp_usb), + decode_0p2v(type_c->cc1_vref_dfp_usb)); + seq_printf(s, "cc1_vref_dfp_1_5 vref_1_1p6v 0x%x vref_0p4v 0x%x vref_0p2v 0x%x\n", + decode_1_1p6v(type_c->cc1_vref_dfp_1_5), + decode_0p4v(type_c->cc1_vref_dfp_1_5), + decode_0p2v(type_c->cc1_vref_dfp_1_5)); + seq_printf(s, "cc1_vref_dfp_3_0 vref_2p6v 0x%x vref_0p8v 0x%x vref_0p2v 0x%x\n", + decode_2p6v(type_c->cc1_vref_dfp_3_0), + decode_0p8v(type_c->cc1_vref_dfp_3_0), + decode_0p2v(type_c->cc1_vref_dfp_3_0)); + seq_printf(s, "cc2_rp 0x%x\n", type_c->cc2_rp); + seq_printf(s, "cc2_rp_code 0x%x\n", + ({ int tmp; + switch (type_c->cc_dfp_mode) { + case CC_MODE_DFP_USB: + tmp = code_rp12k(type_c->cc2_rp_code); break; + case CC_MODE_DFP_1_5: + tmp = code_rp36k(type_c->cc2_rp_code); break; + case CC_MODE_DFP_3_0: + tmp = code_rp4pk(type_c->cc2_rp_code); break; + default: + tmp = -1; break; + } tmp; })); + seq_printf(s, "cc2_rd_code 0x%x\n", + code_rd(type_c->cc2_rd_code)); + seq_printf(s, "cc2_vref_ufp vref_1p23v 0x%x vref_0p66v 0x%x vref_0p2v 0x%x\n", + decode_1p23v(type_c->cc2_vref_ufp), + decode_0p66v(type_c->cc2_vref_ufp), + decode_0p2v(type_c->cc2_vref_ufp)); + seq_printf(s, "cc2_vref_dfp_usb vref_0_1p6v 0x%x vref_0p2v 0x%x\n", + decode_0_1p6v(type_c->cc2_vref_dfp_usb), + decode_0p2v(type_c->cc2_vref_dfp_usb)); + seq_printf(s, "cc2_vref_dfp_1_5 vref_1_1p6v 0x%x vref_0p4v 0x%x vref_0p2v 0x%x\n", + decode_1_1p6v(type_c->cc2_vref_dfp_1_5), + decode_0p4v(type_c->cc2_vref_dfp_1_5), + decode_0p2v(type_c->cc2_vref_dfp_1_5)); + seq_printf(s, "cc2_vref_dfp_3_0 vref_2p6v 0x%x vref_0p8v 0x%x vref_0p2v 0x%x\n", + decode_2p6v(type_c->cc2_vref_dfp_3_0), + decode_0p8v(type_c->cc2_vref_dfp_3_0), + decode_0p2v(type_c->cc2_vref_dfp_3_0)); + seq_printf(s, "debounce_val 0x%x\n", type_c->debounce_val); + seq_puts(s, "\n"); + + spin_unlock_irqrestore(&type_c->lock, flags); + + return 0; +} + +static int type_c_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, type_c_parameter_show, inode->i_private); +} + +static const struct file_operations type_c_parameter_fops = { + .open = type_c_parameter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int type_c_set_parameter_show(struct seq_file *s, void *unused) +{ + seq_puts(s, "cc_dfp_mode [CC_MODE_DFP_USB|CC_MODE_DFP_1_5|CC_MODE_DFP_3_0]\n"); + seq_puts(s, "cc1_rp_code 0x_value\n"); + seq_puts(s, "cc1_rd_code 0x_value\n"); + seq_puts(s, "cc1_vref_ufp_vref_1p23v 0x_value\n"); + seq_puts(s, "cc1_vref_ufp_vref_0p66v 0x_value\n"); + seq_puts(s, "cc1_vref_ufp_vref_0p2v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_usb_vref_1p6v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_usb_vref_0p2v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_1_5_vref_1p6v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_1_5_vref_0p4v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_1_5_vref_0p2v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_3_0_vref_2p6v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_3_0_vref_0p8v 0x_value\n"); + seq_puts(s, "cc1_vref_dfp_3_0_vref_0p2v 0x_value\n"); + seq_puts(s, "cc2_rp_code 0x_value\n"); + seq_puts(s, "cc2_rd_code 0x_value\n"); + seq_puts(s, "cc2_vref_ufp_vref_1p23v 0x_value\n"); + seq_puts(s, "cc2_vref_ufp_vref_0p66v 0x_value\n"); + seq_puts(s, "cc2_vref_ufp_vref_0p2v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_usb_vref_1p6v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_usb_vref_0p2v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_1_5_vref_1p6v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_1_5_vref_0p4v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_1_5_vref_0p2v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_3_0_vref_2p6v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_3_0_vref_0p8v 0x_value\n"); + seq_puts(s, "cc2_vref_dfp_3_0_vref_0p2v 0x_value\n"); + seq_puts(s, "debounce_val value\n"); + + return 0; +} + +static int type_c_set_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, type_c_set_parameter_show, inode->i_private); +} + +static ssize_t type_c_set_parameter_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct type_c_data *type_c = s->private; + unsigned long flags; + char buffer[40]; + char *buf = buffer; + u32 value; + int ret = 0; + + if (copy_from_user(&buffer, ubuf, + min_t(size_t, sizeof(buffer) - 1, count))) + return -EFAULT; + + spin_lock_irqsave(&type_c->lock, flags); + if (!strncmp(buf, "cc_dfp_mode", 11)) { + buf = buf + 11; + buf = skip_spaces(buf); + if (!strncmp(buf, "CC_MODE_DFP_USB", 15)) { + type_c->cc_dfp_mode = CC_MODE_DFP_USB; + type_c->cc1_rp = En_rp12k; + type_c->cc2_rp = En_rp12k; + } else if (!strncmp(buf, "CC_MODE_DFP_1_5", 15)) { + type_c->cc_dfp_mode = CC_MODE_DFP_1_5; + type_c->cc1_rp = En_rp36k; + type_c->cc2_rp = En_rp36k; + } else if (!strncmp(buf, "CC_MODE_DFP_3_0", 15)) { + type_c->cc_dfp_mode = CC_MODE_DFP_3_0; + type_c->cc1_rp = En_rp4p7k; + type_c->cc2_rp = En_rp4p7k; + } else { + dev_err(type_c->dev, "cc_dfp_mode UNKNOWN (%s)", buf); + } + } else if (!strncmp(buf, "cc1_rp_code", 11)) { + buf = buf + 11; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + if (type_c->cc_dfp_mode == CC_MODE_DFP_USB) + type_c->cc1_rp_code = rp12k_code(value); + else if (type_c->cc_dfp_mode == CC_MODE_DFP_1_5) + type_c->cc1_rp_code = rp36k_code(value); + else if (type_c->cc_dfp_mode == CC_MODE_DFP_3_0) + type_c->cc1_rp_code = rp4pk_code(value); + } else if (!strncmp(buf, "cc1_rd_code", 11)) { + buf = buf + 11; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_rd_code = rd_code(value); + } else if (!strncmp(buf, "cc1_vref_ufp_vref_1p23v", 23)) { + buf = buf + 23; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_ufp = (type_c->cc1_vref_ufp & + (~vref_1p23v(0xf))) | + vref_1p23v(value); + } else if (!strncmp(buf, "cc1_vref_ufp_vref_0p66v", 23)) { + buf = buf + 23; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_ufp = (type_c->cc1_vref_ufp & + (~vref_0p66v(0xf))) | + vref_0p66v(value); + } else if (!strncmp(buf, "cc1_vref_ufp_vref_0p2v", 22)) { + buf = buf + 22; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_ufp = (type_c->cc1_vref_ufp & + (~vref_0p2v(0x7))) | + vref_0p2v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_usb_vref_1p6v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_usb = (type_c->cc1_vref_dfp_usb & + (~vref_0_1p6v(0xf))) | vref_0_1p6v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_usb_vref_0p2v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_usb = (type_c->cc1_vref_dfp_usb & + (~vref_0p2v(0x7))) | vref_0p2v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_1_5_vref_1p6v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_1_5 = (type_c->cc1_vref_dfp_1_5 & + (~vref_1_1p6v(0xf))) | vref_1_1p6v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_1_5_vref_0p4v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_1_5 = (type_c->cc1_vref_dfp_1_5 & + (~vref_0p4v(0x7))) | vref_0p4v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_1_5_vref_0p2v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_1_5 = (type_c->cc1_vref_dfp_1_5 & + (~vref_0p2v(0x7))) | vref_0p2v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_3_0_vref_2p6v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_ufp = (type_c->cc1_vref_dfp_1_5 & + (~vref_2p6v(0x7))) | + vref_2p6v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_3_0_vref_0p8v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_3_0 = (type_c->cc1_vref_dfp_3_0 & + (~vref_0p8v(0xf))) | vref_0p8v(value); + } else if (!strncmp(buf, "cc1_vref_dfp_3_0_vref_0p2v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc1_vref_dfp_3_0 = (type_c->cc1_vref_dfp_3_0 & + (~vref_0p2v(0x7))) | vref_0p2v(value); + } else if (!strncmp(buf, "cc2_rp_code", 11)) { + buf = buf + 11; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + if (type_c->cc_dfp_mode == CC_MODE_DFP_USB) + type_c->cc2_rp_code = rp12k_code(value); + else if (type_c->cc_dfp_mode == CC_MODE_DFP_1_5) + type_c->cc2_rp_code = rp36k_code(value); + else if (type_c->cc_dfp_mode == CC_MODE_DFP_3_0) + type_c->cc2_rp_code = rp4pk_code(value); + } else if (!strncmp(buf, "cc2_rd_code", 11)) { + buf = buf + 11; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_rd_code = rd_code(value); + } else if (!strncmp(buf, "cc2_vref_ufp_vref_1p23v", 23)) { + buf = buf + 23; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_ufp = (type_c->cc2_vref_ufp & + (~vref_1p23v(0xf))) | + vref_1p23v(value); + } else if (!strncmp(buf, "cc2_vref_ufp_vref_0p66v", 23)) { + buf = buf + 23; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_ufp = (type_c->cc2_vref_ufp & + (~vref_0p66v(0xf))) | + vref_0p66v(value); + } else if (!strncmp(buf, "cc2_vref_ufp_vref_0p2v", 22)) { + buf = buf + 22; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_ufp = (type_c->cc2_vref_ufp & + (~vref_0p2v(0x7))) | + vref_0p2v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_usb_vref_1p6v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_usb = (type_c->cc2_vref_dfp_usb & + (~vref_0_1p6v(0xf))) | vref_0_1p6v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_usb_vref_0p2v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_usb = (type_c->cc2_vref_dfp_usb & + (~vref_0p2v(0x7))) | vref_0p2v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_1_5_vref_1p6v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_1_5 = (type_c->cc2_vref_dfp_1_5 & + (~vref_1_1p6v(0xf))) | vref_1_1p6v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_1_5_vref_0p4v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_1_5 = (type_c->cc2_vref_dfp_1_5 & + (~vref_0p4v(0x7))) | vref_0p4v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_1_5_vref_0p2v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_1_5 = (type_c->cc2_vref_dfp_1_5 & + (~vref_0p2v(0x7))) | vref_0p2v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_3_0_vref_2p6v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_3_0 = (type_c->cc2_vref_dfp_3_0 & + (~vref_2p6v(0x7))) | vref_2p6v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_3_0_vref_0p8v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_3_0 = (type_c->cc2_vref_dfp_3_0 & + (~vref_0p8v(0xf))) | vref_0p8v(value); + } else if (!strncmp(buf, "cc2_vref_dfp_3_0_vref_0p2v", 26)) { + buf = buf + 26; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->cc2_vref_dfp_3_0 = (type_c->cc2_vref_dfp_3_0 & + (~vref_0p2v(0x7))) | vref_0p2v(value); + } else if (!strncmp(buf, "debounce_val", 12)) { + buf = buf + 12; + buf = skip_spaces(buf); + ret = kstrtoint(buf, 0, &value); + if (ret < 0) { + dev_err(type_c->dev, "kstrtoint ret error (%d)", ret); + return -EFAULT; + } + type_c->debounce_val = value; + } else + dev_err(type_c->dev, "UNKNOWN input (%s)", buf); + + spin_unlock_irqrestore(&type_c->lock, flags); + return count; +} + +static const struct file_operations type_c_set_parameter_fops = { + .open = type_c_set_parameter_open, + .write = type_c_set_parameter_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int type_c_status_show(struct seq_file *s, void *unused) +{ + struct type_c_data *type_c = s->private; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + + seq_printf(s, "Now dr_mode is %s (Is%s role swap)\n", + ({ char *tmp; + switch (type_c->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; }), type_c->is_role_swap == ROLE_SWAP?"":" not"); + + seq_printf(s, "In %s mode %s %s at %s (cc_status=0x%x)\n", + type_c->cc_mode?"host":"device", + type_c->cc_mode ? + (type_c->is_attach?"attach":"detach") : + (type_c->is_attach?"connect":"disconnect"), + type_c->cc_mode?"device":"host", + type_c->at_cc1?"cc1":"cc2", type_c->cc_status); + + seq_printf(s, "Read Register (type_c_ctrl_cc1_0=0x%x)\n", + readl(type_c->type_c_reg_base + 0x0)); + seq_printf(s, "Read Register (type_c_ctrl_cc1_1=0x%x)\n", + readl(type_c->type_c_reg_base + 0x4)); + seq_printf(s, "Read Register (type_c_ctrl_cc2_0=0x%x)\n", + readl(type_c->type_c_reg_base + 0x8)); + seq_printf(s, "Read Register (type_c_ctrl_cc2_1=0x%x)\n", + readl(type_c->type_c_reg_base + 0xc)); + seq_printf(s, "Read Register (type_c_status=0x%x)\n", + readl(type_c->type_c_reg_base + 0x10)); + seq_printf(s, "Read Register (type_c_ctrl=0x%x)\n", + readl(type_c->type_c_reg_base + 0x14)); + + spin_unlock_irqrestore(&type_c->lock, flags); + + return 0; +} + +static int type_c_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, type_c_status_show, inode->i_private); +} + +static const struct file_operations type_c_status_fops = { + .open = type_c_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int type_c_debug_show(struct seq_file *s, void *unused) +{ + struct type_c_data *type_c = s->private; + + seq_printf(s, "Debug: %s\n", + type_c->debug?"Enable":"disable"); + + return 0; +} + +static int type_c_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, type_c_debug_show, inode->i_private); +} + +static ssize_t type_c_debug_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct type_c_data *type_c = s->private; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "enable", 6)) + type_c->debug = true; + else if (!strncmp(buf, "disable", 7)) + type_c->debug = false; + + return count; +} + +static const struct file_operations type_c_debug_fops = { + .open = type_c_debug_open, + .write = type_c_debug_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void create_debug_files(struct type_c_data *type_c) +{ + dev_err(type_c->dev, "%s", __func__); + + type_c->debug_dir = debugfs_create_dir("type_c", usb_debug_root); + if (!type_c->debug_dir) { + dev_err(type_c->dev, "%s Error debug_dir is NULL", __func__); + return; + } + + if (!debugfs_create_file("parameter", 0444, type_c->debug_dir, type_c, + &type_c_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("set_parameter", 0644, + type_c->debug_dir, type_c, + &type_c_set_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("status", 0444, type_c->debug_dir, type_c, + &type_c_status_fops)) + goto file_error; + + if (!debugfs_create_file("debug", 0644, + type_c->debug_dir, type_c, + &type_c_debug_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(type_c->debug_dir); +} +#endif //CONFIG_DEBUG_FS + +static void get_default_type_c_parameter(struct type_c_data *type_c, + struct device *dev) +{ + void *reg; + int val; + + if (soc_device_match(rtk_soc_typc_parameter_v0)) + type_c->para_ver = 0; + else + type_c->para_ver = 1; + + type_c->debounce_val = 0x7f;/* 1b,1us 7f,4.7us */ + type_c->cc_dfp_mode = CC_MODE_DFP_3_0; + type_c->cc1_rp = En_rp4p7k; + type_c->cc2_rp = En_rp4p7k; + + reg = type_c->type_c_reg_base + USB_TYPEC_CTRL_CC1_0; + val = readl(reg); + type_c->cc1_rp_code = rp4pk_code(code_rp4pk(val)) | + rp36k_code(code_rp36k(val)) | + rp12k_code(code_rp12k(val)); + type_c->cc1_rd_code = rd_code(code_rd(val)); + dev_dbg(dev, "%s: cc1_0=0x%x, cc1_rp_code=0x%x, cc1_rd_code=0x%x\n", + __func__, val, type_c->cc1_rp_code, type_c->cc1_rd_code); + + if (val & PLR_EN) + type_c->rd_en_at_first = true; + else + type_c->rd_en_at_first = false; + + /* Add a workaround to disable rd_en for stark */ + if (!soc_device_match(rtk_soc_typc_parameter_v0)) + type_c->rd_en_at_first = false; + + reg = type_c->type_c_reg_base + USB_TYPEC_CTRL_CC2_0; + val = readl(reg); + type_c->cc2_rp_code = rp4pk_code(code_rp4pk(val)) | + rp36k_code(code_rp36k(val)) | + rp12k_code(code_rp12k(val)); + type_c->cc2_rd_code = rd_code(code_rd(val)); + dev_dbg(dev, "%s: cc2_0=0x%x, cc2_rp_code=0x%x, cc2_rd_code=0x%x\n", + __func__, val, type_c->cc2_rp_code, type_c->cc2_rd_code); + + reg = type_c->type_c_reg_base + USB_TYPEC_CTRL_CC1_1; + val = readl(reg); + type_c->cc1_vref_ufp = vref_1p23v(decode_1p23v(val)) | + vref_0p66v(decode_0p66v(val)) | + vref_0p2v(decode_0p2v(val)); + type_c->cc1_vref_dfp_usb = vref_0_1p6v(decode_0_1p6v(val)) | + vref_0p2v(decode_0p2v(val)); + type_c->cc1_vref_dfp_1_5 = vref_1_1p6v(decode_1_1p6v(val)) | + vref_0p4v(decode_0p4v(val)) | + vref_0p2v(decode_0p2v(val)); + type_c->cc1_vref_dfp_3_0 = vref_2p6v(decode_2p6v(val)) | + vref_0p8v(decode_0p8v(val)) | vref_0p2v(decode_0p2v(val)); + dev_dbg(dev, "%s: cc1_1=0x%x, cc1_vref_ufp=0x%x, cc1_vref_dfp_usb=0x%x" + " cc1_vref_dfp_1_5=0x%x, cc1_vref_dfp_3_0=0x%x\n", + __func__, val, type_c->cc1_vref_ufp, + type_c->cc1_vref_dfp_usb, type_c->cc1_vref_dfp_1_5, + type_c->cc1_vref_dfp_3_0); + + reg = type_c->type_c_reg_base + USB_TYPEC_CTRL_CC2_1; + val = readl(reg); + type_c->cc2_vref_ufp = vref_1p23v(decode_1p23v(val)) | + vref_0p66v(decode_0p66v(val)) | + vref_0p2v(decode_0p2v(val)); + type_c->cc2_vref_dfp_usb = vref_0_1p6v(decode_0_1p6v(val)) | + vref_0p2v(decode_0p2v(val)); + type_c->cc2_vref_dfp_1_5 = vref_1_1p6v(decode_1_1p6v(val)) | + vref_0p4v(decode_0p4v(val)) | + vref_0p2v(decode_0p2v(val)); + type_c->cc2_vref_dfp_3_0 = vref_2p6v(decode_2p6v(val)) | + vref_0p8v(decode_0p8v(val)) | vref_0p2v(decode_0p2v(val)); + dev_dbg(dev, "%s: cc2_1=0x%x, cc2_vref_ufp=0x%x, cc2_vref_dfp_usb=0x%x" + " cc1_vref_dfp_1_5=0x%x, cc1_vref_dfp_3_0=0x%x\n", + __func__, val, type_c->cc2_vref_ufp, + type_c->cc2_vref_dfp_usb, type_c->cc2_vref_dfp_1_5, + type_c->cc2_vref_dfp_3_0); +} + +static int set_type_c_parameter(struct type_c_data *type_c, struct device *dev) +{ + struct device_node *node = dev->of_node; + const char *str; + u32 val, default_val; + struct device_node *sub_node; + u8 array_vals[3]; + u32 u32_vals[3]; + u32 default_revision; + char revision[4] = {0}; + int ret; + + if (!node) { + dev_err(dev, "%s: No device node!\n", __func__); + return -ENODEV; + } else if (!of_device_is_available(node)) { + dev_err(dev, "%s: device node is unavailable!\n", __func__); + return -ENODEV; + } + + if (of_property_read_bool(node, "use_defalut_parameter")) { + type_c->use_defalut_parameter = true; + } else { + type_c->use_defalut_parameter = false; + } + + get_default_type_c_parameter(type_c, dev); + + if (type_c->use_defalut_parameter) { + dev_info(dev, "%s: Use default type c parameter\n", __func__); + return 0; + } + + ret = of_property_read_u32(node, "default_revision", + &default_revision); + if (ret) { + default_revision = 0xA00; + dev_info(dev, "%s: No set default_revision (use %x)\n", + __func__, default_revision); + } + + if (!type_c->chip_revision || + type_c->chip_revision > default_revision) + snprintf(revision, 4, "%X", default_revision); + else + snprintf(revision, 4, "%X", type_c->chip_revision); + dev_info(dev, "Chip revision is %x (support revision %x) to load %s parameter\n", + type_c->chip_revision, + default_revision, revision); + sub_node = of_get_child_by_name(node, revision); + + ret = of_property_read_string(sub_node, "cc_dfp_mode", &str); + if (ret) { + dev_err(dev, "%s: cc_dfp_mode error(%d)\n", + __func__, ret); + } + if (!strcmp(str, "dfp_usb")) { + type_c->cc_dfp_mode = CC_MODE_DFP_USB; + type_c->cc1_rp = En_rp12k; + type_c->cc2_rp = En_rp12k; + } else if (!strcmp(str, "dfp_1_5")) { + type_c->cc_dfp_mode = CC_MODE_DFP_1_5; + type_c->cc1_rp = En_rp36k; + type_c->cc2_rp = En_rp36k; + } else if (!strcmp(str, "dfp_3_0")) { + type_c->cc_dfp_mode = CC_MODE_DFP_3_0; + type_c->cc1_rp = En_rp4p7k; + type_c->cc2_rp = En_rp4p7k; + } else { + dev_err(dev, "%s: unknown cc_dfp_mode %s\n", + __func__, str); + } + + //cc1 parameters + ret = of_property_read_u32(sub_node, "cc1_rp_4p7k_code", + &u32_vals[0]); + if (ret) { + dev_err(dev, "%s: cc1_rp_4p7k_code error(%d)\n", + __func__, u32_vals[0]); + } + ret = of_property_read_u32(sub_node, "cc1_rp_36k_code", + &u32_vals[1]); + if (ret) { + dev_err(dev, "%s: cc1_rp_36k_code error(%d)\n", + __func__, + u32_vals[1]); + } + ret = of_property_read_u32(sub_node, "cc1_rp_12k_code", + &u32_vals[2]); + if (ret) { + dev_err(dev, "%s: cc1_rp_12k_code error(%d)\n", + __func__, u32_vals[2]); + } + default_val = type_c->cc1_rp_code; + type_c->cc1_rp_code = rp4pk_code(u32_vals[0]) + | rp36k_code(u32_vals[1]) + | rp12k_code(u32_vals[2]); + if (default_val ^ type_c->cc1_rp_code) + dev_dbg(dev, "Set cc1_rp_code 0x%x --> 0x%x\n", + default_val, type_c->cc1_rp_code); + + ret = of_property_read_u32(sub_node, "cc1_rd_code", &val); + if (ret) { + dev_err(dev, "%s: cc1_rd_code error(%d)\n", + __func__, ret); + } + default_val = type_c->cc1_rd_code; + type_c->cc1_rd_code = rd_code(val); + if (default_val ^ type_c->cc1_rd_code) + dev_dbg(dev, "Set cc1_rd_code 0x%x --> 0x%x\n", + default_val, type_c->cc1_rd_code); + + ret = of_property_read_u8_array(sub_node, "cc1_vref_ufp", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc1_vref_ufp error(%d)\n", + __func__, ret); + } + default_val = type_c->cc1_vref_ufp; + type_c->cc1_vref_ufp = vref_1p23v(array_vals[0]) | + vref_0p66v(array_vals[1]) | + vref_0p2v(array_vals[2]); + if (default_val ^ type_c->cc1_vref_ufp) + dev_dbg(dev, "Set cc1_vref_ufp 0x%x --> 0x%x\n", + default_val, type_c->cc1_vref_ufp); + + ret = of_property_read_u8_array(sub_node, "cc1_vref_dfp_usb", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc1_vref_dfp_usb error(%d)\n", + __func__, ret); + } + default_val = type_c->cc1_vref_dfp_usb; + type_c->cc1_vref_dfp_usb = vref_0_1p6v(array_vals[0]) | + vref_0p2v(array_vals[1]); + if (default_val ^ type_c->cc1_vref_dfp_usb) + dev_dbg(dev, "Set cc1_vref_dfp_usb 0x%x --> 0x%x\n", + default_val, type_c->cc1_vref_dfp_usb); + + ret = of_property_read_u8_array(sub_node, "cc1_vref_dfp_1_5", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc1_vref_dfp_1_5 error(%d)\n", + __func__, ret); + } + default_val = type_c->cc1_vref_dfp_1_5; + type_c->cc1_vref_dfp_1_5 = vref_1_1p6v(array_vals[0]) | + vref_0p4v(array_vals[1]) | + vref_0p2v(array_vals[2]); + if (default_val ^ type_c->cc1_vref_dfp_1_5) + dev_dbg(dev, "Set cc1_vref_dfp_1_5 0x%x --> 0x%x\n", + default_val, type_c->cc1_vref_dfp_1_5); + + ret = of_property_read_u8_array(sub_node, "cc1_vref_dfp_3_0", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc1_vref_dfp_3_0 error(%d)\n", + __func__, ret); + } + default_val = type_c->cc1_vref_dfp_3_0; + type_c->cc1_vref_dfp_3_0 = vref_2p6v(array_vals[0]) | + vref_0p8v(array_vals[1]) | vref_0p2v(array_vals[2]); + if (default_val ^ type_c->cc1_vref_dfp_3_0) + dev_dbg(dev, "Set cc1_vref_dfp_3_0 0x%x --> 0x%x\n", + default_val, type_c->cc1_vref_dfp_3_0); + + //cc2 parameters + ret = of_property_read_u32(sub_node, "cc2_rp_4p7k_code", + &u32_vals[0]); + if (ret) { + dev_err(dev, "%s: cc2_rp_4p7k_code error(%d)\n", + __func__, ret); + } + ret = of_property_read_u32(sub_node, "cc2_rp_36k_code", + &u32_vals[1]); + if (ret) { + dev_err(dev, "%s: cc2_rp_36k_code error(%d)\n", + __func__, ret); + } + ret = of_property_read_u32(sub_node, "cc2_rp_12k_code", + &u32_vals[2]); + if (ret) { + dev_err(dev, "%s: cc2_rp_12k_code error(%d)\n", + __func__, ret); + } + default_val = type_c->cc2_rp_code; + type_c->cc2_rp_code = rp4pk_code(u32_vals[0]) + | rp36k_code(u32_vals[1]) + | rp12k_code(u32_vals[2]); + if (default_val ^ type_c->cc2_rp_code) + dev_dbg(dev, "Set cc2_rp_code 0x%x --> 0x%x\n", + default_val, type_c->cc2_rp_code); + + ret = of_property_read_u32(sub_node, "cc2_rd_code", &val); + if (ret) { + dev_err(dev, "%s: cc2_rd_code error(%d)\n", + __func__, ret); + } + default_val = type_c->cc2_rd_code; + type_c->cc2_rd_code = rd_code(val); + if (default_val ^ type_c->cc2_rd_code) + dev_dbg(dev, "Set cc2_rd_code 0x%x --> 0x%x\n", + default_val, type_c->cc2_rd_code); + + ret = of_property_read_u8_array(sub_node, "cc2_vref_ufp", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc2_vref_ufp error(%d)\n", + __func__, ret); + } + default_val = type_c->cc2_vref_ufp; + type_c->cc2_vref_ufp = vref_1p23v(array_vals[0]) | + vref_0p66v(array_vals[1]) | + vref_0p2v(array_vals[2]); + if (default_val ^ type_c->cc2_vref_ufp) + dev_dbg(dev, "Set cc2_vref_ufp 0x%x --> 0x%x\n", + default_val, type_c->cc2_vref_ufp); + + ret = of_property_read_u8_array(sub_node, "cc2_vref_dfp_usb", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc2_vref_dfp_usb error(%d)\n", + __func__, ret); + } + default_val = type_c->cc2_vref_dfp_usb; + type_c->cc2_vref_dfp_usb = vref_0_1p6v(array_vals[0]) | + vref_0p2v(array_vals[1]); + if (default_val ^ type_c->cc2_vref_dfp_usb) + dev_dbg(dev, "Set cc2_vref_dfp_usb 0x%x --> 0x%x\n", + default_val, type_c->cc2_vref_dfp_usb); + + ret = of_property_read_u8_array(sub_node, "cc2_vref_dfp_1_5", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc2_vref_dfp_1_5 error(%d)\n", + __func__, ret); + } + default_val = type_c->cc2_vref_dfp_1_5; + type_c->cc2_vref_dfp_1_5 = vref_1_1p6v(array_vals[0]) | + vref_0p4v(array_vals[1]) | vref_0p2v(array_vals[2]); + if (default_val ^ type_c->cc2_vref_dfp_1_5) + dev_dbg(dev, "Set cc2_vref_dfp_1_5 0x%x --> 0x%x\n", + default_val, type_c->cc2_vref_dfp_1_5); + + ret = of_property_read_u8_array(sub_node, "cc2_vref_dfp_3_0", + array_vals, 3); + if (ret) { + dev_err(dev, "%s: cc2_vref_dfp_3_0 error(%d)\n", + __func__, ret); + } + default_val = type_c->cc2_vref_dfp_3_0; + type_c->cc2_vref_dfp_3_0 = vref_2p6v(array_vals[0]) | + vref_0p8v(array_vals[1]) | vref_0p2v(array_vals[2]); + if (default_val ^ type_c->cc2_vref_dfp_3_0) + dev_dbg(dev, "Set cc2_vref_dfp_3_0 0x%x --> 0x%x\n", + default_val, type_c->cc2_vref_dfp_3_0); + + type_c->debounce_val = 0x7f;/* 1b,1us 7f,4.7us */ + + return 0; +} + +#ifdef CONFIG_DUAL_ROLE_USB_INTF +static enum dual_role_property fusb_drp_properties[] = { + DUAL_ROLE_PROP_MODE, + DUAL_ROLE_PROP_PR, + DUAL_ROLE_PROP_DR, +}; + +static int dual_role_get_local_prop(struct dual_role_phy_instance *drp, + enum dual_role_property prop, + unsigned int *val) +{ + struct type_c_data *type_c = dual_role_get_drvdata(drp); + + if (!type_c) { + pr_err("driver data not ready\n"); + return -1; + } + + if (type_c->dr_mode == USB_DR_MODE_PERIPHERAL) { + if (prop == DUAL_ROLE_PROP_MODE) + *val = DUAL_ROLE_PROP_MODE_UFP; + else if (prop == DUAL_ROLE_PROP_PR) + *val = DUAL_ROLE_PROP_PR_SNK; + else if (prop == DUAL_ROLE_PROP_DR) + *val = DUAL_ROLE_PROP_DR_DEVICE; + else + return -EINVAL; + } else if (type_c->dr_mode == USB_DR_MODE_HOST) { + if (prop == DUAL_ROLE_PROP_MODE) + *val = DUAL_ROLE_PROP_MODE_DFP; + else if (prop == DUAL_ROLE_PROP_PR) + *val = DUAL_ROLE_PROP_PR_SRC; + else if (prop == DUAL_ROLE_PROP_DR) + *val = DUAL_ROLE_PROP_DR_HOST; + else + return -EINVAL; + } else { + if (prop == DUAL_ROLE_PROP_MODE) + *val = DUAL_ROLE_PROP_MODE_NONE; + else if (prop == DUAL_ROLE_PROP_PR) + *val = DUAL_ROLE_PROP_PR_NONE; + else if (prop == DUAL_ROLE_PROP_DR) + *val = DUAL_ROLE_PROP_DR_NONE; + else + return -EINVAL; + } + + return 0; +} + +static int dual_role_is_writeable(struct dual_role_phy_instance *drp, + enum dual_role_property prop) +{ + if (prop == DUAL_ROLE_PROP_MODE) + return 1; + else + return 0; +} + +#if 0 +static int dual_role_set_mode_prop(struct dual_role_phy_instance *drp, + enum dual_role_property prop, + const unsigned int *val) +{ + pr_err("%s\n", __func__); + return 0; +} + +static int dual_role_set_prop(struct dual_role_phy_instance *drp, + enum dual_role_property prop, + const unsigned int *val) +{ + if (prop == DUAL_ROLE_PROP_MODE) + return dual_role_set_mode_prop(drp, prop, val); + else + return -EINVAL; +} +#endif +#endif + +#ifdef CONFIG_TYPEC +static int type_c_port_dr_set(struct typec_port *port, + enum typec_data_role role) +{ + struct type_c_data *type_c = typec_get_drvdata(port); + int ret = 0; + u32 enable_cc; + unsigned long flags; + + spin_lock_irqsave(&type_c->lock, flags); + enable_cc = type_c->at_cc1?enable_cc1:enable_cc2; + spin_unlock_irqrestore(&type_c->lock, flags); + + if (role == TYPEC_HOST) { + switch_type_c_dr_mode(type_c, USB_DR_MODE_HOST, enable_cc); + } else if (role == TYPEC_DEVICE) { + switch_type_c_dr_mode(type_c, USB_DR_MODE_PERIPHERAL, + enable_cc); + } else { + switch_type_c_dr_mode(type_c, 0, disable_cc); + } + + return ret < 0 ? ret : 0; +} + +static const struct typec_operations type_c_port_ops = { + .dr_set = type_c_port_dr_set, +}; +#endif /* CONFIG_TYPEC */ + +#define DEFAULT_CHIP_REVISION 0xA00 +#define MAX_CHIP_REVISION 0xC00 + +static int __get_chip_revision(void) +{ + int chip_revision = 0xFFF; + char revision[] = "FFF"; + struct soc_device_attribute soc_att[] = {{.revision = revision}, {}}; + struct soc_device_attribute *soc_att_match = NULL; + + while (soc_att_match == NULL) { + chip_revision--; + + if (chip_revision <= DEFAULT_CHIP_REVISION) + break; + if (chip_revision > MAX_CHIP_REVISION) + chip_revision = MAX_CHIP_REVISION; + else if ((chip_revision & 0xFF) > 0xF) + chip_revision = (chip_revision & 0xF00) + 0xF; + + snprintf(revision, 4, "%X", chip_revision); + + soc_att_match = (struct soc_device_attribute *) + soc_device_match(soc_att); + } + + if (soc_att_match) { + pr_debug("%s get chip_revision %x\n", __func__, chip_revision); + return chip_revision; + } + + pr_debug("%s usb DEFAULT chip_revision %X\n", __func__, + DEFAULT_CHIP_REVISION); + return DEFAULT_CHIP_REVISION; +} + +/* Init and probe */ +static int dwc3_rtk_type_c_init(struct type_c_data *type_c) +{ + struct device *dev = type_c->dev; + u32 debounce_val = type_c->debounce_val;// 1b,1us 7f,4.7us + unsigned long flags; +#ifdef CONFIG_DUAL_ROLE_USB_INTF + struct dual_role_phy_desc *desc; + struct dual_role_phy_instance *dual_role; +#endif + + enable_writel(debounce_val<<1, + type_c->type_c_reg_base + USB_TYPEC_CTRL); + dev_info(dev, "%s set debounce = 0x%x (check--> 0x%x)\n", + __func__, debounce_val, + readl(type_c->type_c_reg_base + USB_TYPEC_CTRL)); + + if ((type_c->rd_ctrl_gpio != -1) && + gpio_request(type_c->rd_ctrl_gpio, dev->of_node->name)) + dev_err(dev, "%s ERROR Request rd_ctrl_gpio (id=%d) fail\n", + __func__, type_c->rd_ctrl_gpio); + + rtk_type_c_init(type_c); + + switch_type_c_dr_mode(type_c, 0, disable_cc); + + spin_lock_irqsave(&type_c->lock, flags); + + dev_info(dev, "First check USB_DR_MODE_PERIPHERAL"); + type_c->cc_mode = IN_DEVICE_MODE; + type_c->is_attach = IN_DETACH; + type_c->connect_change = CONNECT_NO_CHANGE; + if (type_c->boot_check_time < 0) + type_c->check_at_boot = false; + else + type_c->check_at_boot = true; + dev_info(dev, "First time device mode check is %s", + type_c->check_at_boot?"Enable":"Diable"); + + detect_host(type_c); + + spin_unlock_irqrestore(&type_c->lock, flags); + + schedule_delayed_work(&type_c->delayed_work, + msecs_to_jiffies(0)); + +#ifdef CONFIG_DUAL_ROLE_USB_INTF + if (type_c->drp == NULL) { + desc = devm_kzalloc(dev, sizeof(struct dual_role_phy_desc), + GFP_KERNEL); + if (!desc) + return 0; + + desc->name = "dwc3_otg"; + desc->supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP; + desc->get_property = dual_role_get_local_prop; +// desc->set_property = dual_role_set_prop; + desc->properties = fusb_drp_properties; + desc->num_properties = ARRAY_SIZE(fusb_drp_properties); + desc->property_is_writeable = dual_role_is_writeable; + dual_role = devm_dual_role_instance_register(dev, desc); + dual_role->drv_data = type_c; + type_c->drp = dual_role; + } +#endif + +#ifdef CONFIG_TYPEC + if (type_c->port == NULL) { + struct typec_capability typec_cap = { }; + + typec_cap.revision = USB_TYPEC_REV_1_0; + typec_cap.pd_revision = 0x200; + typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + typec_cap.driver_data = type_c; + typec_cap.ops = &type_c_port_ops; + + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_DRD; + + type_c->port = typec_register_port(type_c->dev, &typec_cap); + if (IS_ERR(type_c->port)) + return PTR_ERR(type_c->port); + } +#endif /* CONFIG_TYPEC */ + return 0; +} + +static void dwc3_rtk_type_c_probe_work(struct work_struct *work) +{ + struct type_c_data *type_c = container_of(work, + struct type_c_data, start_work); + struct device *dev = type_c->dev; + int ret = 0; + + unsigned long probe_time = jiffies; + + dev_info(dev, "%s Start ...\n", __func__); + + ret = dwc3_rtk_type_c_init(type_c); + + if (ret) + dev_err(dev, "%s failed to init type_c\n", __func__); + + dev_info(dev, "%s End ... ok! (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); +} + +static int dwc3_rtk_type_c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct type_c_data *type_c; + unsigned int gpio; + int ret = 0; + unsigned long probe_time = jiffies; + + dev_info(dev, "ENTER %s", __func__); + type_c = devm_kzalloc(dev, sizeof(*type_c), GFP_KERNEL); + if (!type_c) + return -ENOMEM; + + type_c->type_c_reg_base = of_iomap(pdev->dev.of_node, 0); + if (type_c->type_c_reg_base == NULL) { + dev_err(&pdev->dev, "error mapping memory for reg_base\n"); + ret = -EFAULT; + goto err1; + } + + type_c->dev = dev; + + type_c->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (type_c->irq <= 0) { + dev_err(&pdev->dev, + "Type C driver with no IRQ. Check %s setup!\n", + dev_name(&pdev->dev)); + ret = -ENODEV; + goto err1; + } + + ret = request_irq(type_c->irq, type_c_detect_irq, + IRQF_SHARED, "type_c_detect", type_c); + + spin_lock_init(&type_c->lock); + type_c->chip_revision = __get_chip_revision(); + + type_c->rd_ctrl_gpio = -1; + if (node && of_device_is_available(node) && + soc_device_match(rtk_soc_kylin)) { + gpio = of_get_named_gpio(node, "realtek,rd_ctrl-gpio", 0); + if (gpio_is_valid(gpio)) { + type_c->rd_ctrl_gpio = gpio; + dev_info(dev, "%s get rd_ctrl-gpio (id=%d) OK\n", + __func__, gpio); + } else { + dev_err(dev, "Error rd_ctrl-gpio no found"); + } + } + + if (node && of_device_is_available(node)) { + ret = of_property_read_u32(node, "boot_check_time", + &type_c->boot_check_time); + if (ret) + type_c->boot_check_time = -1; + + dev_info(dev, + "Set device mode boot_check_time %d ms ==> (%s to check)\n", + type_c->boot_check_time, + type_c->boot_check_time < 0?"Disable":"Enable"); + + if (of_property_read_bool(node, "filter_config_channel_signal")) + type_c->filter_config_channel_signal = true; + else + type_c->filter_config_channel_signal = false; + dev_info(dev, "Set filter_config_channel_signal is %s\n", + type_c->filter_config_channel_signal ? + "True":"False"); + + } + + if (set_type_c_parameter(type_c, dev)) { + dev_err(dev, "ERROR: %s to set type c parameter!!", __func__); + } + + if (node) { + struct device_node *parent_node; + + parent_node = of_parse_phandle(dev->of_node, "dwc3_rtk", 0); + if (!parent_node) + parent_node = of_get_parent(node); + if (parent_node) { + type_c->dwc3_rtk = platform_get_drvdata( + of_find_device_by_node(parent_node)); + } else { + dev_err(dev, "%s No find dwc3_rtk", __func__); + ret = -ENODEV; + goto err1; + } + } + + type_c->is_attach = IN_DETACH; + type_c->is_role_swap = NO_ROLE_SWAP; + + if (of_property_read_bool(node, "debug")) { + dev_info(&pdev->dev, "%s device tree set debug flag\n", + __func__); + type_c->debug = true; + } else { + type_c->debug = false; + } + + INIT_DELAYED_WORK(&type_c->delayed_work, host_device_switch); + INIT_DELAYED_WORK(&type_c->boot_check_work, boot_time_check); + + if (node) { + if (of_property_read_bool(node, "delay_probe_work")) { + INIT_WORK(&type_c->start_work, + dwc3_rtk_type_c_probe_work); + + if (of_property_read_bool(node, "ordered_probe")) + rtk_usb_manager_schedule_work(dev, + &type_c->start_work); + else + schedule_work(&type_c->start_work); + } else { + ret = dwc3_rtk_type_c_init(type_c); + if (ret) { + dev_err(dev, "%s failed to init type_c\n", + __func__); + goto err1; + } + } + } else { + dev_err(dev, "no device node, failed to init type_c\n"); + ret = -ENODEV; + goto err1; + } + + platform_set_drvdata(pdev, type_c); + + device_create_file(type_c->dev, &dev_attr_role_swap); + device_create_file(type_c->dev, &dev_attr_force_set_mode); + +#ifdef CONFIG_DEBUG_FS + create_debug_files(type_c); +#endif + + dev_info(&pdev->dev, "Exit %s OK (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); + return 0; + +err1: + dev_err(&pdev->dev, "%s: Probe fail, %d\n", __func__, ret); + + return ret; +} + +static int dwc3_rtk_type_c_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct type_c_data *type_c = dev_get_drvdata(dev); + u32 default_ctrl; + unsigned long flags; + + dev_info(dev, "[USB] Enter %s", __func__); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(type_c->debug_dir); +#endif + +#ifdef CONFIG_TYPEC + if (type_c->port) { + typec_unregister_port(type_c->port); + type_c->port = NULL; + } +#endif + + device_remove_file(type_c->dev, &dev_attr_role_swap); + device_remove_file(type_c->dev, &dev_attr_force_set_mode); + + cancel_delayed_work_sync(&type_c->delayed_work); + flush_delayed_work(&type_c->delayed_work); + BUG_ON(delayed_work_pending(&type_c->delayed_work)); + + cancel_delayed_work_sync(&type_c->boot_check_work); + flush_delayed_work(&type_c->boot_check_work); + BUG_ON(delayed_work_pending(&type_c->boot_check_work)); + + spin_lock_irqsave(&type_c->lock, flags); + /* disable interrupt */ + default_ctrl = readl(type_c->type_c_reg_base + USB_TYPEC_CTRL) & + debounce_time_MASK; + writel(default_ctrl, type_c->type_c_reg_base + USB_TYPEC_CTRL); + + spin_unlock_irqrestore(&type_c->lock, flags); + + free_irq(type_c->irq, type_c); + + dev_info(&pdev->dev, "[USB] Exit %s\n", __func__); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rtk_dwc3_type_c_match[] = { + { .compatible = "realtek,dwc3-type_c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtk_dwc3_type_c_match); +#endif + +#ifdef CONFIG_PM_SLEEP +static int dwc3_rtk_type_c_prepare(struct device *dev) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + u32 default_ctrl; + unsigned long flags; + int ret = 0; + + dev_info(dev, "[USB] Enter %s\n", __func__); + + if (!type_c) { + dev_err(dev, "[USB] %s type_c_data is NULL\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto common; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + dev_info(dev, "[USB] %s Suspend mode\n", __func__); + +#ifdef CONFIG_USB_PATCH_ON_RTK +common: +#endif // CONFIG_USB_PATCH_ON_RTK + + cancel_delayed_work_sync(&type_c->delayed_work); + flush_delayed_work(&type_c->delayed_work); + BUG_ON(delayed_work_pending(&type_c->delayed_work)); + + cancel_delayed_work_sync(&type_c->boot_check_work); + flush_delayed_work(&type_c->boot_check_work); + BUG_ON(delayed_work_pending(&type_c->boot_check_work)); + + spin_lock_irqsave(&type_c->lock, flags); + /* disable interrupt */ + default_ctrl = readl(type_c->type_c_reg_base + USB_TYPEC_CTRL) & + debounce_time_MASK; + writel(default_ctrl, type_c->type_c_reg_base + USB_TYPEC_CTRL); + + spin_unlock_irqrestore(&type_c->lock, flags); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return ret; +} + +static void dwc3_rtk_type_c_complete(struct device *dev) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + + dev_info(dev, "[USB] Enter %s\n", __func__); + + if (!type_c) { + dev_err(dev, "[USB] %s type_c_data is NULL\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + unsigned long flags; + + //For idle mode + dev_info(dev, "[USB] %s S1 (Standby mode)\n", __func__); + + spin_lock_irqsave(&type_c->lock, flags); + //enable interrupt + if (type_c->is_attach == IN_ATTACH) + enable_writel(ENABLE_TYPE_C_DETECT, + type_c->type_c_reg_base + USB_TYPEC_CTRL); + + schedule_delayed_work(&type_c->delayed_work, + msecs_to_jiffies(1)); + spin_unlock_irqrestore(&type_c->lock, flags); + + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + dev_info(dev, "[USB] %s S3 (Suspend-to-RAM mode)\n", __func__); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); +} + +static int dwc3_rtk_type_c_suspend(struct device *dev) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + + dev_info(dev, "[USB] Enter %s", __func__); + + if (!type_c) { + dev_err(dev, "[USB] %s type_c_data is NULL\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + //For suspend mode + dev_info(dev, "[USB] %s Suspend mode\n", __func__); + + if (type_c->rd_ctrl_gpio != -1) + gpio_free(type_c->rd_ctrl_gpio); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return 0; +} + +static int dwc3_rtk_type_c_resume(struct device *dev) +{ + struct type_c_data *type_c = dev_get_drvdata(dev); + unsigned long flags; + bool reinit = false; + + dev_info(dev, "[USB] Enter %s", __func__); + + if (!type_c) { + dev_err(dev, "[USB] %s type_c_data is NULL\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + //For suspend mode + dev_info(dev, "[USB] %s Suspend mode\n", __func__); + + if (rtk_usb_manager_is_iso_mode(type_c->dev)) { + spin_lock_irqsave(&type_c->lock, flags); + //enable interrupt + if (type_c->is_attach == IN_ATTACH) + enable_writel(ENABLE_TYPE_C_DETECT, + type_c->type_c_reg_base + USB_TYPEC_CTRL); + else + reinit = true; + spin_unlock_irqrestore(&type_c->lock, flags); + } else { + dev_info(dev, "[USB] %s reinit dwc3_rtk_type_c_init (Not iso mode\n)", + __func__); + + if (type_c->is_attach == IN_ATTACH) { + u32 enable_cc; + + rtk_type_c_init(type_c); + enable_writel(ENABLE_TYPE_C_DETECT, + type_c->type_c_reg_base + USB_TYPEC_CTRL); + enable_cc = type_c->at_cc1?enable_cc1:enable_cc2; + switch_type_c_plug_config(type_c, + type_c->dr_mode, enable_cc); + } else { + reinit = true; + } + } + + if (reinit) + dwc3_rtk_type_c_init(type_c); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops dwc3_rtk_type_c_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS( + dwc3_rtk_type_c_suspend, dwc3_rtk_type_c_resume) + .prepare = dwc3_rtk_type_c_prepare, + .complete = dwc3_rtk_type_c_complete, +}; + +#define DEV_PM_OPS (&dwc3_rtk_type_c_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static struct platform_driver dwc3_rtk_type_c_driver = { + .probe = dwc3_rtk_type_c_probe, + .remove = dwc3_rtk_type_c_remove, + .driver = { + .name = "rtk-dwc3-type_c", + .of_match_table = of_match_ptr(rtk_dwc3_type_c_match), + .pm = DEV_PM_OPS, + }, +}; + +static int __init dwc3_rtk_type_c_driver_init(void) +{ + return platform_driver_register(&(dwc3_rtk_type_c_driver)); +} +module_init(dwc3_rtk_type_c_driver_init); + +static void __exit dwc3_rtk_type_c_driver_exit(void) +{ + platform_driver_unregister(&(dwc3_rtk_type_c_driver)); +} +module_exit(dwc3_rtk_type_c_driver_exit); + +MODULE_ALIAS("platform:rtk-dwc3-type_c"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/dwc3/dwc3-rtk.c b/drivers/usb/dwc3/dwc3-rtk.c new file mode 100644 index 000000000000..82f1e5552837 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-rtk.c @@ -0,0 +1,829 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0 +/** + * dwc3-rtk.c - Realtek DWC3 Specific Glue layer + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dwc3-rtk.h" +#include "dwc3-rtk-drd.h" +#include "core.h" +#include "io.h" + +static const struct soc_device_attribute rtk_soc_phoenix[] = { + { + .family = "Realtek Phoenix", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_kylin[] = { + { + .family = "Realtek Kylin", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_kylin_a00[] = { + { + .family = "Realtek Kylin", + .revision = "A00", + }, + { + /* empty */ + } +}; + +static const struct soc_device_attribute rtk_soc_hercules[] = { + { + .family = "Realtek Hercules", + }, + { + /* empty */ + } +}; + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_USB3PHY +extern void rtk_usb3_phy_toggle(struct usb_phy *usb3_phy, bool isConnect, + int port); +#endif + +void RTK_dwc3_usb3_phy_toggle(struct device *hcd_dev, bool isConnect, int port) +{ + struct device *dwc3_dev = NULL; + struct dwc3 *dwc = NULL; + + if (hcd_dev == NULL) + return; + + dwc3_dev = hcd_dev->parent; + if (dwc3_dev == NULL) + return; + + dwc = dev_get_drvdata(dwc3_dev); +#ifdef CONFIG_RTK_USB3PHY + dev_dbg(dwc3_dev, "%s port=%d\n", __func__, port); + if (dwc != NULL) + rtk_usb3_phy_toggle(dwc->usb3_phy, isConnect, port); +#endif +} + +#ifdef CONFIG_RTK_USB2PHY +extern void rtk_usb2_phy_toggle(struct usb_phy *usb3_phy, bool isConnect, + int port); +#endif + +int RTK_dwc3_usb2_phy_toggle(struct device *hcd_dev, bool isConnect, int port) +{ + struct device *dwc3_dev = NULL; + struct dwc3 *dwc = NULL; + + if (hcd_dev == NULL) + return -1; + + dwc3_dev = hcd_dev->parent; + if (dwc3_dev == NULL) + return -1; + + dwc = dev_get_drvdata(dwc3_dev); + if (dwc == NULL) + return -1; + +#ifdef CONFIG_RTK_USB2PHY + dev_dbg(dwc3_dev, "%s port=%d\n", __func__, port); + rtk_usb2_phy_toggle(dwc->usb2_phy, isConnect, port); +#endif + return 0; +} +#endif // CONFIG_USB_PATCH_ON_RTK + +bool dwc3_rtk_is_support_drd_mode(struct dwc3_rtk *dwc3_rtk) +{ + if (!dwc3_rtk) { + pr_err("%s: ERROR: dwc3_rtk is NULL!", __func__); + return false; + } + + return dwc3_rtk->support_drd_mode; +} + +bool dwc3_rtk_is_connected_on_device_mode(struct dwc3_rtk *dwc3_rtk) +{ + bool connected = true; + int no_host_connect = 0; + int no_run_gadget = 0; + u32 dsts, dctl; + + if (!dwc3_rtk) { + pr_err("%s: ERROR: dwc3_rtk is NULL!", __func__); + return connected; + } + if (dwc3_rtk->cur_dr_mode != USB_DR_MODE_PERIPHERAL) { + dev_info(dwc3_rtk->dev, + "%s: Error: not in device mode (cur_dr_mode=%x)\n", + __func__, dwc3_rtk->cur_dr_mode); + return connected; + } + + dsts = dwc3_readl(dwc3_rtk->dwc->regs, DWC3_DSTS); + dctl = dwc3_readl(dwc3_rtk->dwc->regs, DWC3_DCTL); + + dev_info(dwc3_rtk->dev, "%s: Device mode check DSTS=%x DCTL=%x\n", + __func__, + dsts, dctl); + no_host_connect = DWC3_DSTS_USBLNKST(dsts) >= DWC3_LINK_STATE_SS_DIS; + no_host_connect = no_host_connect | ((dsts & 0x0003FFF8) == BIT(17)); + no_run_gadget = (dctl & BIT(31)) == 0x0; + if (no_host_connect || no_run_gadget) + connected = false; + + return connected; +} + +static void switch_u2_dr_mode(struct dwc3_rtk *rtk, int dr_mode) +{ + switch (dr_mode) { + case USB_DR_MODE_PERIPHERAL: + writel(USB2_PHY_SWITCH_DEVICE | + (~USB2_PHY_SWITCH_MASK & + readl(rtk->regs + WRAP_USB2_PHY_reg)), + rtk->regs + WRAP_USB2_PHY_reg); + break; + case USB_DR_MODE_HOST: + writel(USB2_PHY_SWITCH_HOST | + (~USB2_PHY_SWITCH_MASK & + readl(rtk->regs + WRAP_USB2_PHY_reg)), + rtk->regs + WRAP_USB2_PHY_reg); + break; + case USB_DR_MODE_OTG: + //writel(BIT(11) , rtk->regs + WRAP_USB2_PHY_reg); + dev_info(rtk->dev, "%s: USB_DR_MODE_OTG\n", __func__); + break; + } +} + +static void switch_dwc3_dr_mode(struct dwc3_rtk *rtk, int dr_mode) +{ +#ifdef CONFIG_USB_DWC3_RTK_DUAL_ROLE + switch (dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dev_info(rtk->dev, "%s dr_mode=USB_DR_MODE_PERIPHERAL\n", + __func__); + dwc3_drd_to_device(rtk->dwc); + break; + case USB_DR_MODE_HOST: + dev_info(rtk->dev, "%s dr_mode=USB_DR_MODE_HOST\n", + __func__); + dwc3_drd_to_host(rtk->dwc); + break; + default: + dev_info(rtk->dev, "%s dr_mode=%d\n", __func__, dr_mode); + dwc3_drd_to_stop_all(rtk->dwc); + } +#else + dev_info(rtk->dev, "Not support CONFIG_USB_DWC3_RTK_DUAL_ROLE\n"); +#endif /* CONFIG_USB_DWC3_RTK_DUAL_ROLE */ +} + +int dwc3_rtk_get_dr_mode(struct dwc3_rtk *rtk) +{ + return rtk->cur_dr_mode; +} + +int dwc3_rtk_set_dr_mode(struct dwc3_rtk *rtk, int dr_mode) +{ + if (!rtk->support_drd_mode) + return rtk->cur_dr_mode; + + if (!rtk->dwc) { + dev_err(rtk->dev, "%s Error! dwc3 is NULL", __func__); + return rtk->cur_dr_mode; + } + + dev_dbg(rtk->dev, "%s START....", __func__); + + rtk->cur_dr_mode = dr_mode; + rtk->dwc->dr_mode = dr_mode; + + if (dr_mode != USB_DR_MODE_HOST) { + dev_info(rtk->dev, "%s: To disable power\n", __func__); + rtk_usb_port_power_on_off(rtk->dev, false); + } + + switch_dwc3_dr_mode(rtk, dr_mode); + mdelay(10); + switch_u2_dr_mode(rtk, dr_mode); + + if (dr_mode == USB_DR_MODE_HOST) { + dev_info(rtk->dev, "%s: To enable power\n", __func__); + rtk_usb_port_power_on_off(rtk->dev, true); + } + + dev_dbg(rtk->dev, "%s END....", __func__); + + return rtk->cur_dr_mode; +} + +static ssize_t set_dr_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dwc3_rtk *rtk = dev_get_drvdata(dev); + char *ptr = buf; + int count = PAGE_SIZE; + int n; + + n = scnprintf(ptr, count, + "Now cur_dr_mode is %s (default dwc3 dr_mode is %s)\n", + ({ char *tmp; + switch (rtk->cur_dr_mode) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; }), + ({ char *tmp; + switch (rtk->default_dwc3_dr_mode) { + case USB_DR_MODE_PERIPHERAL: + tmp = "USB_DR_MODE_PERIPHERAL"; break; + case USB_DR_MODE_HOST: + tmp = "USB_DR_MODE_HOST"; break; + default: + tmp = "USB_DR_MODE_UNKNOWN"; break; + } tmp; })); + + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "write host -> switch to Host mode\n"); + ptr += n; + count -= n; + + n = scnprintf(ptr, count, + "write device -> switch to Device mode\n"); + ptr += n; + count -= n; + + return ptr - buf; +} + +static ssize_t set_dr_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dwc3_rtk *rtk = dev_get_drvdata(dev); + + if (!strncmp(buf, "host", 4)) + dwc3_rtk_set_dr_mode(rtk, USB_DR_MODE_HOST); + else if (!strncmp(buf, "device", 6)) + dwc3_rtk_set_dr_mode(rtk, USB_DR_MODE_PERIPHERAL); + else + dwc3_rtk_set_dr_mode(rtk, 0); + + return count; +} +static DEVICE_ATTR_RW(set_dr_mode); + +#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH) +static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, enum usb_role role) +{ + struct dwc3_rtk *rtk = usb_role_switch_get_drvdata(sw); + + if (!rtk) { + pr_err("ERROR: %s dwc3_rtk is NULL!", __func__); + return role; + } + + switch (role) { + case USB_ROLE_HOST: + dwc3_rtk_set_dr_mode(rtk, USB_DR_MODE_HOST); + break; + case USB_ROLE_DEVICE: + dwc3_rtk_set_dr_mode(rtk, USB_DR_MODE_PERIPHERAL); + break; + default: + dwc3_rtk_set_dr_mode(rtk, 0); + } + + return 0; +} + +static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw) +{ + struct dwc3_rtk *rtk = usb_role_switch_get_drvdata(sw); + enum usb_role role = USB_ROLE_NONE; + int dr_mode; + + if (!rtk) { + pr_err("ERROR: %s dwc3_rtk is NULL!", __func__); + return role; + } + + dr_mode = dwc3_rtk_get_dr_mode(rtk); + switch (dr_mode) { + case USB_DR_MODE_HOST: + role = USB_ROLE_HOST; + break; + case USB_DR_MODE_PERIPHERAL: + role = USB_ROLE_DEVICE; + break; + default: + dev_info(rtk->dev, "%s dr_mode=%d", __func__, dr_mode); + break; + } + return role; +} + +static int dwc3_rtk_setup_role_switch(struct dwc3_rtk *rtk) +{ + struct usb_role_switch_desc dwc3_role_switch = {NULL}; + + dwc3_role_switch.driver_data = rtk; + dwc3_role_switch.allow_userspace_control = true; + dwc3_role_switch.fwnode = dev_fwnode(rtk->dev); + dwc3_role_switch.set = dwc3_usb_role_switch_set; + dwc3_role_switch.get = dwc3_usb_role_switch_get; + rtk->role_switch = usb_role_switch_register(rtk->dev, &dwc3_role_switch); + if (IS_ERR(rtk->role_switch)) + return PTR_ERR(rtk->role_switch); + + return 0; +} + +static int dwc3_rtk_remove_role_switch(struct dwc3_rtk *rtk) +{ + if (rtk->role_switch) + usb_role_switch_unregister(rtk->role_switch); + + rtk->role_switch = NULL; + + return 0; +} +#else +#if defined(MY_DEF_HERE) +#define dwc3_rtk_setup_role_switch(x) +#define dwc3_rtk_remove_role_switch(x) +#else /* MY_DEF_HERE */ +#define dwc3_rtk_setup_role_switch(x) 0 +#define dwc3_rtk_remove_role_switch(x) 0 +#endif /* MY_DEF_HERE */ +#endif + +static int dwc3_rtk_init(struct dwc3_rtk *rtk) +{ + struct device *dev = rtk->dev; + void __iomem *regs = rtk->regs; + + if (soc_device_match(rtk_soc_kylin_a00)) { + writel(DISABLE_MULTI_REQ | readl(regs + WRAP_CTR_reg), + regs + WRAP_CTR_reg); + dev_info(dev, "[bug fixed] 1295/1296 A00: add workaround to disable multiple request for D-Bus"); + } + + if (soc_device_match(rtk_soc_hercules)) { + writel(USB2_PHY_EN_PHY_PLL_PORT1 | + readl(regs + WRAP_USB2_PHY_reg), + regs + WRAP_USB2_PHY_reg); + dev_info(dev, "[bug fixed] 1395 add workaround to disable usb2 port 2 suspend!"); + + } + + if (rtk->dis_u3_port) { + void __iomem *reg; + int val; + + reg = rtk->regs + WRAP_USB_HMAC_CTR0_reg; + val = U3PORT_DIS | readl(reg); + writel(val, reg); + + dev_info(rtk->dev, "%s: only set dis_u3_port\n", + __func__); + } + + if (rtk->disable_usb3) { + void __iomem *reg; + int val; + + reg = rtk->regs + WRAP_CTR_reg; + val = FORCE_PIPE3_PHY_STATUS_TO_0 | readl(reg); + writel(val, reg); + + reg = rtk->regs + WRAP_PHY_PIPE_reg; + val = ~CLOCk_ENABLE_FOR_PIPE3_PCLK & readl(reg); + val |= RESET_DISABLE_PIPE3_P0; + writel(val, reg); + + reg = rtk->regs + WRAP_USB_HMAC_CTR0_reg; + val = U3PORT_DIS | readl(reg); + writel(val, reg); + + reg = rtk->regs + WRAP_APHY_reg; + val = ~USB3_MBIAS_ENABLE & readl(reg); + writel(val, reg); + + dev_info(rtk->dev, "%s: disable usb 3.0 phy\n", + __func__); + } + + return 0; +} + +static int dwc3_rtk_initiated(struct dwc3_rtk *rtk) +{ + struct device *dev; + struct dwc3 *dwc; + + if (!rtk) { + pr_err("ERROR! rtk is NULL\n"); + return -1; + } + + dev = rtk->dev; + dwc = rtk->dwc; + if (!dwc) { + dev_err(dev, "ERROR! dwc3 is NULL\n"); + return -1; + } + + dev_info(dev, "%s\n", __func__); + + /* workaround: to avoid transaction error and cause port reset + * we enable threshold control for TX/RX + * [Dev_Fix] Enable DWC3 threshold control for USB compatibility issue + * commit 77f116ba77cc089ee2a6ceca1d2aa496b39c98ba + * [Dev_Fix] change RX threshold packet count from 1 to 3, + * it will get better performance + * commit fe8905c2112f899f9ec3ddbfd83e0f183d3fbf7d + * [DEV_FIX] In case there may have transaction error once + * system bus busy + * commit b36294740c5cf66932c0fec429f4c5399e26f591 + */ + if (soc_device_match(rtk_soc_phoenix) || + soc_device_match(rtk_soc_kylin) || + soc_device_match(rtk_soc_hercules)) { + dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, + DWC3_GTXTHRCFG_TXPKTCNT(1) | + DWC3_GTXTHRCFG_MAXTXBURSTSIZE(1)); + dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, + DWC3_GRXTHRCFG_PKTCNTSEL | + DWC3_GRXTHRCFG_RXPKTCNT(3) | + DWC3_GRXTHRCFG_MAXRXBURSTSIZE(3)); + + /* enable auto retry */ + dwc3_writel(dwc->regs, DWC3_GUCTL, + dwc3_readl(dwc->regs, DWC3_GUCTL) | + DWC3_GUCTL_HSTINAUTORETRY); + } + + if (dwc->revision >= DWC3_REVISION_300A) + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), + dwc3_readl(dwc->regs, DWC3_DEV_IMOD(0)) | + DWC3_DEVICE_IMODI(0x1)); + + return 0; +} + +static int dwc3_rtk_probe_dwc3core(struct dwc3_rtk *rtk) +{ + struct device *dev = rtk->dev; + struct device_node *node = dev->of_node; + struct device_node *dwc3_node; + int ret = 0; + + dwc3_rtk_init(rtk); + + if (node) { + ret = of_platform_populate(node, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to add dwc3 core\n"); + return ret; + } + + dwc3_node = of_get_compatible_child(node, "synopsys,dwc3"); + if (!dwc3_node) { + dev_info(dev, "Get dwc3_node at first child node\n"); + dwc3_node = of_get_next_child(node, NULL); + } + if (dwc3_node != NULL) { + struct device *dwc3_dev; + struct platform_device *dwc3_pdev; + int dr_mode; + + dwc3_pdev = of_find_device_by_node(dwc3_node); + dwc3_dev = &dwc3_pdev->dev; + rtk->dwc = platform_get_drvdata(dwc3_pdev); + + dr_mode = usb_get_dr_mode(dwc3_dev); + if (dr_mode != rtk->dwc->dr_mode) { + dev_info(dev, "dts set dr_mode=%d, but dwc3 set dr_mode=%d\n", + dr_mode, rtk->dwc->dr_mode); + + dr_mode = rtk->dwc->dr_mode; + } + + rtk->default_dwc3_dr_mode = dr_mode; + rtk->cur_dr_mode = dr_mode; + + switch_u2_dr_mode(rtk, dr_mode); + + } else { + dev_err(dev, "dwc3 node is NULL\n"); + } + } else { + dev_err(dev, "dwc3_rtk node is NULL\n"); + } + + ret = dwc3_rtk_initiated(rtk); + + if (rtk->cur_dr_mode == USB_DR_MODE_HOST) + rtk_usb_init_port_power_on_off(rtk->dev, true); + else + rtk_usb_init_port_power_on_off(rtk->dev, false); + + if (rtk->support_drd_mode) { + device_create_file(dev, &dev_attr_set_dr_mode); + + dwc3_rtk_setup_role_switch(rtk); + } + + return ret; +} + +static void dwc3_rtk_probe_work(struct work_struct *work) +{ + struct dwc3_rtk *rtk = container_of(work, struct dwc3_rtk, work); + struct device *dev = rtk->dev; + int ret = 0; + + unsigned long probe_time = jiffies; + + dev_info(dev, "%s Start ...\n", __func__); + + ret = dwc3_rtk_probe_dwc3core(rtk); + + if (ret) + dev_err(dev, "%s failed to add dwc3 core\n", __func__); + + dev_info(dev, "%s End ... ok! (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); +} + +static int dwc3_rtk_probe(struct platform_device *pdev) +{ + struct dwc3_rtk *rtk; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + + struct resource *res; + void __iomem *regs; + + int ret = -ENOMEM; + unsigned long probe_time = jiffies; + + dev_info(&pdev->dev, "Probe Realtek-SoC USB DWC3 Host Controller\n"); + + rtk = devm_kzalloc(dev, sizeof(*rtk), GFP_KERNEL); + if (!rtk) + goto err1; + + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we move to full device tree support this will vanish off. + */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + platform_set_drvdata(pdev, rtk); + + rtk->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + ret = -ENODEV; + goto err1; + } + + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto err1; + } + + rtk->regs = regs; + rtk->regs_size = resource_size(res); + + dwc3_rtk_debugfs_init(rtk); + + if (node) { + + rtk->dis_u3_port = false; + if (of_property_read_bool(node, "dis_u3_port")) + rtk->dis_u3_port = true; + + rtk->disable_usb3 = false; + if (of_property_read_bool(node, "disable_usb3")) + rtk->disable_usb3 = true; + + rtk->support_drd_mode = false; + if (of_property_read_bool(node, "drd_mode")) { + dev_info(rtk->dev, "%s: support drd_mode\n", __func__); + rtk->support_drd_mode = true; + } + } + + if (node) { + if (of_property_read_bool(node, "delay_probe_work")) { + INIT_WORK(&rtk->work, dwc3_rtk_probe_work); + if (of_property_read_bool(node, "ordered_probe")) + rtk_usb_manager_schedule_work(dev, &rtk->work); + else + schedule_work(&rtk->work); + } else { + ret = dwc3_rtk_probe_dwc3core(rtk); + if (ret) { + dev_err(dev, "%s failed to add dwc3 core\n", + __func__); + goto err1; + } + } + } else { + dev_err(dev, "no device node, failed to add dwc3 core\n"); + ret = -ENODEV; + goto err1; + } + + dev_info(dev, "%s ok! (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); + + return 0; + +err1: + return ret; +} + +static int dwc3_rtk_remove(struct platform_device *pdev) +{ + struct dwc3_rtk *rtk = platform_get_drvdata(pdev); + + rtk->dwc = NULL; + + if (rtk->support_drd_mode) { + device_remove_file(rtk->dev, &dev_attr_set_dr_mode); + + dwc3_rtk_remove_role_switch(rtk); + } + + dwc3_rtk_debugfs_exit(rtk); + + of_platform_depopulate(rtk->dev); + + rtk_usb_remove_port_power_on_off(rtk->dev, false); + return 0; +} + +static void dwc3_rtk_shutdown(struct platform_device *pdev) +{ +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ + struct dwc3_rtk *rtk = platform_get_drvdata(pdev); +#endif /* MY_DEF_HERE */ + struct device *dev = &pdev->dev; + + dev_info(dev, "%s start ...\n", __func__); + + dev_info(dev, "%s ok!\n", __func__); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtk_dwc3_match[] = { + { .compatible = "realtek,dwc3" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtk_dwc3_match); +#endif + +#ifdef CONFIG_PM_SLEEP +static int dwc3_rtk_suspend(struct device *dev) +{ + struct dwc3_rtk *rtk = dev_get_drvdata(dev); + + dev_info(dev, "[USB] Enter %s\n", __func__); + + if (!rtk) { + dev_err(dev, "[USB] %s dwc3_rtk is NULL\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + //For suspend mode + dev_info(dev, "[USB] %s Suspend mode\n", __func__); + +out: + dev_info(dev, "[USB] Exit %s", __func__); + return 0; +} + +static int dwc3_rtk_resume(struct device *dev) +{ + struct dwc3_rtk *rtk = dev_get_drvdata(dev); + struct dwc3 *dwc = rtk->dwc; + + dev_info(dev, "[USB] Enter %s", __func__); + + if (!rtk) { + dev_err(dev, "[USB] %s dwc3_rtk is NULL\n", __func__); + goto out; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + //For suspend mode + dev_info(dev, "[USB] %s Suspend mode\n", __func__); + + dwc3_rtk_init(rtk); + + switch_u2_dr_mode(rtk, dwc->dr_mode); + + dwc3_rtk_initiated(rtk); + + /* runtime set active to reflect active state. */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + +out: + dev_info(dev, "[USB] Exit %s\n", __func__); + return 0; +} + +static const struct dev_pm_ops dwc3_rtk_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_rtk_suspend, dwc3_rtk_resume) +}; + +#define DEV_PM_OPS (&dwc3_rtk_dev_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static struct platform_driver dwc3_rtk_driver = { + .probe = dwc3_rtk_probe, + .remove = dwc3_rtk_remove, + .driver = { + .name = "rtk-dwc3", + .of_match_table = of_match_ptr(rtk_dwc3_match), + .pm = DEV_PM_OPS, + }, + .shutdown = dwc3_rtk_shutdown, +}; + +module_platform_driver(dwc3_rtk_driver); + +MODULE_ALIAS("platform:rtk-dwc3"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/dwc3/dwc3-rtk.h b/drivers/usb/dwc3/dwc3-rtk.h new file mode 100644 index 000000000000..6badd49d611a --- /dev/null +++ b/drivers/usb/dwc3/dwc3-rtk.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * dwc3-rtk.h - Realtek DWC3 Specific Glue layer + * + * Copyright (C) 2020 Realtek Semiconductor Corporation + * + */ + +#ifndef __DRIVERS_USB_DWC3_RTK_H +#define __DRIVERS_USB_DWC3_RTK_H + +#define WRAP_CTR_reg 0x0 +#define DISABLE_MULTI_REQ BIT(1) +#define FORCE_PIPE3_PHY_STATUS_TO_0 BIT(13) + +#define WRAP_PHY_PIPE_reg 0xC +#define RESET_DISABLE_PIPE3_P0 BIT(0) +#define CLOCk_ENABLE_FOR_PIPE3_PCLK BIT(1) + +#define WRAP_USB_HMAC_CTR0_reg 0x60 +#define U3PORT_DIS BIT(8) + +#define WRAP_APHY_reg 0x128 +#define USB3_MBIAS_ENABLE BIT(1) + +#define WRAP_USB2_PHY_reg 0x70 +#define USB2_PHY_EN_PHY_PLL_PORT0 BIT(12) +#define USB2_PHY_EN_PHY_PLL_PORT1 BIT(13) +#define USB2_PHY_SWITCH_MASK 0x707 +#define USB2_PHY_SWITCH_DEVICE 0x0 +#define USB2_PHY_SWITCH_HOST 0x606 + +struct dwc3_rtk { + struct device *dev; + + void __iomem *regs; + size_t regs_size; + + struct dwc3 *dwc; + + struct work_struct work; + + int default_dwc3_dr_mode; /* define by dwc3 driver, and it is fixed */ + int cur_dr_mode; /* current dr mode */ + bool support_drd_mode; /* if support Host/device switch */ + struct usb_role_switch *role_switch; + + bool dis_u3_port; + bool disable_usb3; + + /* For debugfs */ + struct dentry *debug_dir; + + void *dwc3_regs_dump; + void *wrap_regs_dump; +}; + +void dwc3_rtk_debugfs_init(struct dwc3_rtk *dwc3_rtk); +void dwc3_rtk_debugfs_exit(struct dwc3_rtk *dwc3_rtk); + +#endif /* __DRIVERS_USB_DWC3_RTK_H */ diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 14a7c05abfe8..70180615e8b8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link @@ -2361,6 +2364,13 @@ static int dwc3_gadget_start(struct usb_gadget *g, } dwc->gadget_driver = driver; +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + dwc->link_state = 0; +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ spin_unlock_irqrestore(&dwc->lock, flags); return 0; @@ -2387,6 +2397,13 @@ static int dwc3_gadget_stop(struct usb_gadget *g) spin_lock_irqsave(&dwc->lock, flags); dwc->gadget_driver = NULL; +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + dwc->link_state = 0; +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ spin_unlock_irqrestore(&dwc->lock, flags); free_irq(dwc->irq_gadget, dwc->ev_buf); @@ -3969,6 +3986,13 @@ void dwc3_gadget_exit(struct dwc3 *dwc) kfree(dwc->setup_buf); dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); +#if defined(MY_DEF_HERE) + +#if 1 // USB_PATCH_BY_RTK + dwc->gadget->udc = NULL; + dwc->gadget = NULL; +#endif // USB_PATCH_BY_RTK +#endif /* MY_DEF_HERE */ } int dwc3_gadget_suspend(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index e195176580de..23e130002361 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * host.c - DesignWare USB3 DRD Controller Host Glue @@ -130,4 +133,12 @@ int dwc3_host_init(struct dwc3 *dwc) void dwc3_host_exit(struct dwc3 *dwc) { platform_device_unregister(dwc->xhci); +#if defined(MY_DEF_HERE) + +#if 1 // USB_PATCH_BY_RTK + dwc->xhci = NULL; +#endif + + +#endif /* MY_DEF_HERE */ } diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 76b73b116862..12f0ba5ea820 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /** * io.h - DesignWare USB3 DRD IO Header @@ -16,10 +19,25 @@ #include "debug.h" #include "core.h" +#if defined(MY_DEF_HERE) +#if 0//def CONFIG_USB_PATCH_ON_RTK +/* Add global lock for emmc issue*/ +#include +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ static inline u32 dwc3_readl(void __iomem *base, u32 offset) { u32 value; +#if defined(MY_DEF_HERE) +#if 0//def CONFIG_USB_PATCH_ON_RTK + /* Add global lock for emmc issue*/ + unsigned long flags; + rtk_lockapi_lock(flags, __FUNCTION__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* * We requested the mem region starting from the Globals address * space, see dwc3_probe in core.c. @@ -27,6 +45,13 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset) */ value = readl(base + offset - DWC3_GLOBALS_REGS_START); +#if defined(MY_DEF_HERE) +#if 0//def CONFIG_USB_PATCH_ON_RTK + /* Add global lock for emmc issue*/ + rtk_lockapi_unlock(flags,__FUNCTION__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* * When tracing we want to make it easy to find the correct address on * documentation, so we revert it back to the proper addresses, the @@ -39,6 +64,12 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset) static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) { +#if defined(MY_DEF_HERE) +#if 0//def CONFIG_USB_PATCH_ON_RTK + unsigned long flags; + rtk_lockapi_lock(flags, __FUNCTION__); +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ /* * We requested the mem region starting from the Globals address * space, see dwc3_probe in core.c. @@ -46,6 +77,12 @@ static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) */ writel(value, base + offset - DWC3_GLOBALS_REGS_START); +#if defined(MY_DEF_HERE) +#if 0//def CONFIG_USB_PATCH_ON_RTK + rtk_lockapi_unlock(flags,__FUNCTION__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* * When tracing we want to make it easy to find the correct address on * documentation, so we revert it back to the proper addresses, the diff --git a/drivers/usb/dwc3/rtk-rts5400.c b/drivers/usb/dwc3/rtk-rts5400.c new file mode 100644 index 000000000000..473a9dce492d --- /dev/null +++ b/drivers/usb/dwc3/rtk-rts5400.c @@ -0,0 +1,729 @@ +/** + * rtk-rts5400.c - Realtek RTS5400 Type C driver + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + * 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 + +#include +#include + +#define RTS5400_MAX_WRITE_DATA_LEN 32 + +static struct tcpm_command { + u8 cmd; + u8 wr_data_len; + u8 data[RTS5400_MAX_WRITE_DATA_LEN]; +} __packed; + +#define PING_STATUS_CMD_STATUS(n) (n & 0x3) +#define PING_STATUS_DATA_LEN(n) ((n & 0xFC) >> 2) + +static struct tcpm_command_status { + u8 cmd_status:2; +#define PING_STATUS_IN_PORCESS 0x0 +#define PING_STATUS_COMPLETE 0x1 +#define PING_STATUS_DEFERRED 0x2 +#define PING_STATUS_ERROR 0x3 + u8 data_len:6; +} __packed; + +static struct pd_ic_status { + u8 reservrd1; + u8 reservrd2; + u8 reservrd3; + u8 main_ver; + u8 sub_ver; + u8 sub_ver2; + u8 reservrd4; + u8 reservrd5; + u8 pd_tc; +#define IC_STATUS_PD_READY(n) (n & 0x1) +#define IC_STATUS_TC_CONNECT(n) ((n >> 3) & 0x1) + uint32_t reservrd6; + u8 sm_ready; +#define IC_STATUS_SMB_READY(n) (n & 0x1) + u8 reservrd7; + u8 reservrd8; + uint32_t reservrd9; +} __packed; + +static struct pd_status_change {//TODO + uint32_t reservrd; +} __packed; + +static struct pd_status_info { + struct pd_status_change status_change; /* bit 0-31 */ + u8 supply:1; +#define PD_STATUS_INFO_NO_SUPPULY 0x0 +#define PD_STATUS_INFO_SUPPULY 0x1 + u8 port_op_mode:3; +#define PD_STATUS_INFO_NO_CONSUMER 0x0 +#define PD_STATUS_INFO_USB_DEFAULT 0x1 +#define PD_STATUS_INFO_BC 0x2 +#define PD_STATUS_INFO_PD 0x3 +#define PD_STATUS_INFO_USB_1_5A 0x4 +#define PD_STATUS_INFO_USB_3_0A 0x5 + u8 insertion_detect:1; +#define PD_STATUS_INFO_NO_CABLE 0x0 +#define PD_STATUS_INFO_CABLE_DETECT 0x1 + u8 pd_capable_cable:1; +#define PD_STATUS_INFO_NO_PD_CABLE 0x0 +#define PD_STATUS_INFO_PD_CABLE 0x1 + u8 power_direction:1; +#define PD_STATUS_INFO_CONSUMER 0x0 +#define PD_STATUS_INFO_PROVIDER 0x1 + u8 connect_status:1; +#define PD_STATUS_INFO_UNATTACHED 0x0 +#define PD_STATUS_INFO_ATTACHED 0x1 + u8 port_partner_flag; /* bit 40-47 */ +#define PD_STATUS_INFO_PARTNER_USB 0x0 +#define PD_STATUS_INFO_PARTNER_ALT 0x1 + uint32_t request_data_obj; /* bit 48-79 */ + u8 port_partner_type:3; /* bit 80-82 */ +#define PD_STATUS_INFO_PARTNER_DFP 0x1 +#define PD_STATUS_INFO_PARTNER_UFP 0x2 +#define PD_STATUS_INFO_PARTNER_PC 0x3 +#define PD_STATUS_INFO_PARTNER_PC_UFP 0x4 +#define PD_STATUS_INFO_PARTNER_DA 0x5 +#define PD_STATUS_INFO_PARTNER_AAA 0x6 + u8 battery_charging_status:2; + u8 pd_sourcing_Vconn:1; + u8 pd_responsible_for_Vconn:1; + u8 pd_ams:1; + u8 last_ams:4; /* bit 88-91 */ + u8 port_partner_not_support_pd:1; + u8 plug_direction:1; + u8 dp_role:1; +#define PD_STATUS_INFO_DP_SINK 0x0 +#define PD_STATUS_INFO_DP_SOURCE 0x1 + u8 pd_connect:1; +#define PD_STATUS_INFO_PD_NOT_EXCHANGE 0x0 +#define PD_STATUS_INFO_PD_EXCHANGE 0x1 + u8 reservrd1; + u8 alt_mode_status:3; + u8 reservrd2:5; +} __packed; + +#define PDO_TYPE(n) (n&0x1) +#define PDO_TYPE_SINK 0x0 +#define PDO_TYPE_SOURCE 0x1 +#define PDO_TCPM(n) ((n&0x1) << 1) +#define PDO_TCPM_TCPM 0x0 +#define PDO_TCPM_PARTNER 0x1 +#define PDO_OFFEST(n) ((n&0x7) << 2) +#define PDO_NUM(n) ((n&0x7) << 5) + +static struct source_fix_pdo { + u16 max_current:10; + u16 valtage:10; + u8 peak_current:2; + u8 reservrd:3; + u8 data_role_swap:1; + u8 usb_comm_capable:1; + u8 external_power:1; + u8 usb_suspend:1; + u8 dual_role_power:1; + u8 power_type:2; +} __packed; + +static struct source_var_pdo { + u16 max_current:10; + u16 min_valtage:10; + u16 max_valtage:10; + u8 power_type:2; +} __packed; + +static struct source_bat_pdo { + u16 max_current:10; + u16 min_valtage:10; + u16 max_valtage:10; + u8 power_type:2; +} __packed; + +static struct sink_fix_pdo { + u16 op_current:10; + u16 valtage:10; + u8 peak_current:2; + u8 reservrd:3; + u8 data_role_swap:1; + u8 usb_comm_capable:1; + u8 external_power:1; + u8 higher_capability:1; + u8 dual_role_power:1; + u8 power_type:2; +} __packed; + +static struct sink_var_pdo { + u16 op_current:10; + u16 min_valtage:10; + u16 max_valtage:10; + u8 power_type:2; +} __packed; + +static struct sink_bat_pdo { + u16 op_current:10; + u16 min_valtage:10; + u16 max_valtage:10; + u8 power_type:2; +} __packed; + +static struct common_pdo { + uint32_t reservrd:30; + u8 power_type:2; +#define PDO_INFO_POWER_TYPE_FIX 0x0 +#define PDO_INFO_POWER_TYPE_BAT 0x1 +#define PDO_INFO_POWER_TYPE_VAR 0x2 +} __packed; + +union pdo_info { + struct source_fix_pdo so_f; + struct source_var_pdo so_v; + struct source_bat_pdo so_b; + struct sink_fix_pdo si_f; + struct sink_var_pdo si_v; + struct sink_bat_pdo si_b; + struct common_pdo com; +}; + +static struct rdo_info { + uint32_t reservrd_todo:28; //TODO + uint32_t obj_pos:3; + uint32_t reservrd:1; +} __packed; + +#define PD_AMS_PR_SWAP 0x01 +#define PD_AMS_DR_SWAP 0x02 +#define PD_AMS_VCONN_SWAP 0x03 +#define PD_AMS_SOURCE_CAP 0x04 +#define PD_AMS_REQUEST 0x05 +#define PD_AMS_SOFT_RESET 0x06 +#define PD_AMS_HARD_RESET 0x07 +#define PD_AMS_GOTO_MIN 0x08 +#define PD_AMS_GET_SNK_CAP 0x09 +#define PD_AMS_GET_SRC_CAP 0x0A + +static struct rts5400_dev { + struct i2c_client *client; + struct device *dev; + bool no_device; + + struct pd_ic_status ic_status; + struct pd_status_info status_info; + + unsigned int pow_gpio; +} g_rts5400; + +/* I2C transfer */ +static struct tcpm_command_status __rts5400_get_ping_status( + const struct i2c_client *client) +{ + int ret; + struct tcpm_command_status status; + status.cmd_status = 0; + status.data_len = 0; + + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_err(&client->dev, "%s get error %d\n", __func__, ret); + return status; + } + status.cmd_status = PING_STATUS_CMD_STATUS(ret); + status.data_len = PING_STATUS_DATA_LEN(ret); + return status; +} + +static int __rts5400_block_read(const struct i2c_client *client, + struct tcpm_command *command) +{ + int ret; + int data_len = command->wr_data_len + 1; + u8 *buffer; + + buffer = kzalloc(data_len, GFP_KERNEL); + + ret = i2c_smbus_read_i2c_block_data(client, command->cmd, + data_len, buffer); + + if (ret < 0) + dev_err(&client->dev, "block read failed\n"); + else { + memcpy(&command->data, buffer + 1, command->wr_data_len); + ret = buffer[0]; + } + + kfree(buffer); + + return ret; +} + +static int __rts5400_block_write(struct i2c_client *client, + struct tcpm_command *command) +{ + int ret; + + ret = i2c_smbus_write_block_data(client, command->cmd, + command->wr_data_len, (u8)&command->data); + return ret; +} + +static int __rts5400_transfer(const struct rts5400_dev *rts5400, + struct tcpm_command *w_cmd, struct tcpm_command *r_cmd) +{ + struct device *dev = rts5400->dev; + struct i2c_client *client = rts5400->client; + struct tcpm_command_status status; + int retry = 100; + int ret = -ENODEV; + + if (rts5400->no_device) { + dev_dbg(dev, "%s Error! NO rts5400\n", __func__); + return ret; + } + dev_dbg(dev, "%s start write command 0x%x,wr_data_len %d, sub_command 0x%x\n", + __func__, w_cmd->cmd, w_cmd->wr_data_len, w_cmd->data[0]); + + ret = __rts5400_block_write(client, w_cmd); + + if (ret < 0) { + dev_err(dev, "%s block write error %d", __func__, ret); + return ret; + } + + while (--retry) { + mdelay(1); + status = __rts5400_get_ping_status(client); + if (status.cmd_status == PING_STATUS_COMPLETE) { + break; + } else if (status.cmd_status == PING_STATUS_ERROR) { + dev_err(dev, "%s get ping status error %d\n", __func__, status.cmd_status); + break; + } + } + if (!retry) { + dev_err(dev, "%s get ping status TIMEOUT\n", __func__); + return -ETIMEDOUT; + } else + dev_dbg(dev, "%s get ping status 0x%x, data_len %d\n", + __func__, status.cmd_status, status.data_len); + + if (r_cmd->wr_data_len == 0xff) + r_cmd->wr_data_len = status.data_len; + + if (r_cmd->wr_data_len > 0) { + dev_dbg(dev, "%s start read command 0x%x,wr_data_len %d\n", + __func__, r_cmd->cmd, r_cmd->wr_data_len); + + ret = __rts5400_block_read(client, r_cmd); + if (ret < 0) + dev_err(dev, "%s block read error %d\n", __func__, ret); + } + if (status.cmd_status == PING_STATUS_ERROR) + return -3; + else + return ret; +} + +int rtk_rts5400_get_IC_status(void) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + int ret, i; + struct tcpm_command w_cmd, r_cmd; + struct pd_ic_status *ic_status = &rts5400->ic_status; + + w_cmd.cmd = 0x3A; + w_cmd.wr_data_len = 0x1; + w_cmd.data[0] = 0x14; + r_cmd.cmd = 0x80; + r_cmd.wr_data_len = 0x14; + memset(&r_cmd.data, 0, RTS5400_MAX_WRITE_DATA_LEN); + + dev_dbg(rts5400->dev, "Enter %s\n", __func__); + + ret = __rts5400_transfer(rts5400, &w_cmd, &r_cmd); + + if (ret < 0) { + dev_err(rts5400->dev, "%s I2C transfer fails\n", __func__); + return ret; + } + + //for (i = 0; i < r_cmd.wr_data_len; i++) { + // dev_dbg(rts5400->dev, "Data#%d : 0x%x\n", i, r_cmd.data[i]); + //} + memcpy(ic_status, &r_cmd.data, r_cmd.wr_data_len); + + dev_info(rts5400->dev, "RTS5400 Main_version %d Sub_version %d Sub_version_2 %d\n", + ic_status->main_ver, ic_status->sub_ver, ic_status->sub_ver2); + + dev_info(rts5400->dev, "SMBus %sready, PD %sready, TypeC %sconnect\n", + IC_STATUS_SMB_READY(ic_status->sm_ready)?"":"NOT ", + IC_STATUS_PD_READY(ic_status->pd_tc)?"":"NOT ", + IC_STATUS_TC_CONNECT(ic_status->pd_tc)?"":"NOT "); + + dev_dbg(rts5400->dev, "Exit %s return cmd %x, wr_data_len %d\n", __func__, + r_cmd.cmd, r_cmd.wr_data_len); + + ret = IC_STATUS_SMB_READY(ic_status->sm_ready) + & IC_STATUS_PD_READY(ic_status->pd_tc) + & IC_STATUS_TC_CONNECT(ic_status->pd_tc); + + return ret; +} + +int rtk_rts5400_get_status(void) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + int ret, i; + struct tcpm_command w_cmd, r_cmd; + struct pd_status_info *status_info = &rts5400->status_info; + + w_cmd.cmd = 0x9; + w_cmd.wr_data_len = 0x3; + w_cmd.data[0] = 0x0; + w_cmd.data[1] = 0; + w_cmd.data[2] = 0x0D; + r_cmd.cmd = 0x80; + r_cmd.wr_data_len = 0xff; + memset(&r_cmd.data, 0, RTS5400_MAX_WRITE_DATA_LEN); + + dev_dbg(rts5400->dev, "Enter %s\n", __func__); + + ret = __rts5400_transfer(rts5400, &w_cmd, &r_cmd); + + if (ret < 0) { + dev_err(rts5400->dev, "%s I2C transfer fails\n", __func__); + return ret; + } + + //for (i = 0; i < r_cmd.wr_data_len; i++) { + // dev_dbg(rts5400->dev, "Data#%d : 0x%x\n", i, r_cmd.data[i]); + //} + + memcpy(status_info, &r_cmd.data, r_cmd.wr_data_len); + + dev_info(rts5400->dev, "[Status Info] Externally Powered supply %d, Port OP mode %d, Insertion Detect %d\n", + status_info->supply, status_info->port_op_mode, status_info->insertion_detect); + dev_info(rts5400->dev, "[Status Info] PD Capable Cable %d, Power Direction %d\n", + status_info->pd_capable_cable, status_info->power_direction); + dev_info(rts5400->dev, "[Status Info] Connect Status %d, Port Partner Flags %d\n", + status_info->connect_status, status_info->port_partner_flag); + dev_info(rts5400->dev, "[Status Info] Request Data Object 0x%x\n", status_info->request_data_obj); + dev_info(rts5400->dev, "[Status Info] Port Partner Type %d\n", status_info->port_partner_type); + dev_info(rts5400->dev, "[Status Info] Battery Charging Status %d\n", status_info->battery_charging_status); + dev_info(rts5400->dev, "[Status Info] PD Sourcing Vconn %d\n", status_info->pd_sourcing_Vconn); + dev_info(rts5400->dev, "[Status Info] PD AMS is %s\n", status_info->pd_ams?"in progress":"ready"); + dev_info(rts5400->dev, "[Status Info] DP Role: %s\n", status_info->dp_role?"Sink":"Source"); + dev_info(rts5400->dev, "[Status Info] PD %sexchanged pd message and goodcrc\n", status_info->pd_connect?"":"NOT "); + dev_info(rts5400->dev, "[Status Info] Alt mode status 0x%x\n", status_info->alt_mode_status); + + dev_dbg(rts5400->dev, "Exit %s return cmd %x, wr_data_len %d\n", __func__, + r_cmd.cmd, r_cmd.wr_data_len); + + return ret; +} + +int rtk_rts5400_get_PDO(int pdo_type, int pdo, int offset, + int num, u8 *value) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + int ret, i; + struct tcpm_command w_cmd, r_cmd; + union pdo_info *pdo_inf; + + w_cmd.cmd = 0x8; + w_cmd.wr_data_len = 0x3; + w_cmd.data[0] = 0x83; + w_cmd.data[1] = 0; + w_cmd.data[2] = PDO_TYPE(pdo_type) | PDO_TCPM(pdo) | PDO_OFFEST(offset) | PDO_NUM(num); + r_cmd.cmd = 0x80; + r_cmd.wr_data_len = 0xff; + memset(&r_cmd.data, 0, RTS5400_MAX_WRITE_DATA_LEN); + + dev_dbg(rts5400->dev, "Enter %s\n", __func__); + + ret = __rts5400_transfer(rts5400, &w_cmd, &r_cmd); + + if (ret < 0) { + dev_err(rts5400->dev, "%s I2C transfer fails\n", __func__); + return ret; + } + + dev_dbg(rts5400->dev, "[PDO status] %s %s PDO, offset %d, num %d\n", + pdo?"Partner":"TCPM", pdo_type?"Source":"Sink", offset, num); + + //for (i = 0; i < r_cmd.wr_data_len; i++) { + // dev_dbg(rts5400->dev, "Data#%d : 0x%x\n", i, r_cmd.data[i]); + //} + + for (i = 0; i < r_cmd.wr_data_len; i = i + 4) { + pdo_inf = (union pdo_info *)&r_cmd.data[i]; + + if (pdo == PDO_TYPE_SOURCE && pdo_inf->com.power_type == PDO_INFO_POWER_TYPE_FIX) { + dev_info(rts5400->dev, "[PDO status] %s Fix PDO, valtage %d mV\n", + pdo_type?"Source":"Sink", (pdo_inf->so_f.valtage) * 50); + } else if (pdo == PDO_TYPE_SOURCE && pdo_inf->com.power_type == PDO_INFO_POWER_TYPE_VAR) { + dev_info(rts5400->dev, "[PDO status] %s Var PDO\n", pdo_type?"Source":"Sink"); + } else if (pdo == PDO_TYPE_SOURCE && pdo_inf->com.power_type == PDO_INFO_POWER_TYPE_BAT) { + dev_info(rts5400->dev, "[PDO status] %s Bat PDO\n", pdo_type?"Source":"Sink"); + } else if (pdo == PDO_TYPE_SINK && pdo_inf->com.power_type == PDO_INFO_POWER_TYPE_FIX) { + dev_info(rts5400->dev, "[PDO status] %s Fix PDO, valtage %d mV\n", + pdo_type?"Source":"Sink", (pdo_inf->si_f.valtage) * 50); + } else if (pdo == PDO_TYPE_SINK && pdo_inf->com.power_type == PDO_INFO_POWER_TYPE_VAR) { + dev_info(rts5400->dev, "[PDO status] %s Var PDO\n", pdo_type?"Source":"Sink"); + } else if (pdo == PDO_TYPE_SINK && pdo_inf->com.power_type == PDO_INFO_POWER_TYPE_BAT) { + dev_info(rts5400->dev, "[PDO status] %s Var PDO\n", pdo_type?"Source":"Sink"); + } + } + dev_dbg(rts5400->dev, "Exit %s return cmd %x, wr_data_len %d\n", __func__, + r_cmd.cmd, r_cmd.wr_data_len); + + if (ret > 0) { + if (value != NULL) { + memcpy(value, &r_cmd.data, r_cmd.wr_data_len); + } + return r_cmd.wr_data_len; + } + return ret; +} + +int rtk_rts5400_init_pd_ams(u8 pd_ams) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + int ret, i; + struct tcpm_command w_cmd, r_cmd; + + w_cmd.cmd = 0x8; + w_cmd.wr_data_len = 0x3; + w_cmd.data[0] = 0x20; + w_cmd.data[1] = 0; + w_cmd.data[2] = pd_ams; + r_cmd.cmd = 0x80; + r_cmd.wr_data_len = 0x0; + memset(&r_cmd.data, 0, RTS5400_MAX_WRITE_DATA_LEN); + + dev_dbg(rts5400->dev, "Enter %s pd_ams=%x\n", __func__, pd_ams); + + ret = __rts5400_transfer(rts5400, &w_cmd, &r_cmd); + + if (ret < 0) { + dev_err(rts5400->dev, "%s I2C transfer fails\n", __func__); + return ret; + } + + dev_dbg(rts5400->dev, "Exit %s\n", __func__); + + return ret; +} + +/* Type C */ +bool rtk_rts5400_is_enabled(void) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + struct device *dev = rts5400->dev; + + return !rts5400->no_device; +} + +bool rtk_rts5400_is_UFP_attached(void) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + struct device *dev = rts5400->dev; + struct pd_status_info *status_info = &rts5400->status_info; + + return status_info->port_partner_type == PD_STATUS_INFO_PARTNER_UFP; +} + +int rtk_rts5400_set_type_c_soft_reset(void) +{ + int ret = 0; + + ret = rtk_rts5400_init_pd_ams(PD_AMS_SOFT_RESET); + + return ret; +} + +int rtk_rts5400_get_current_pdo_voltage(void) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + struct device *dev = rts5400->dev; + struct pd_status_info *status_info = &rts5400->status_info; + struct rdo_info *rdo = NULL; + union pdo_info *pdo = NULL; + int offest; + int ret = -1; + u8 *buffer; + + dev_dbg(dev, "Enter %s\n", __func__); + if (status_info->request_data_obj == 0x0) { + dev_err(dev, "%s NO request_data_obj", __func__); + return ret; + } else + rdo = (struct rdo_info *)&status_info->request_data_obj; + + offest = (rdo->obj_pos - 1) * 4; + + dev_dbg(dev, "%s rdo->obj_pos=%d, offest=%d", __func__, + rdo->obj_pos, offest); + + if (offest < 0) { + dev_err(dev, "%s Error! rdo->obj_pos=%d, offest=%d", + __func__, rdo->obj_pos, offest); + return ret; + } + + buffer = kzalloc(7*4, GFP_KERNEL); + + ret = rtk_rts5400_get_PDO(PDO_TYPE_SOURCE, PDO_TCPM_PARTNER, 0, 7, buffer); + + if (ret < 0) { + dev_err(dev, "%s rtk_rts5400_get_PDO fail(ret=%d)", __func__, ret); + kfree(buffer); + return ret; + } + pdo = (union pdo_info *)buffer + offest; + + if (pdo != NULL && pdo->com.power_type == PDO_INFO_POWER_TYPE_FIX) { + dev_info(rts5400->dev, "Current Partner Source Fix PDO, " + "valtage %d mV\n", (pdo->so_f.valtage) * 50); + ret = pdo->so_f.valtage * 50; + } + + kfree(buffer); + dev_dbg(dev, "Exit %s\n", __func__); + return ret; +} + +/* init and probe */ +static int rtk_rts5400_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rts5400_dev *rts5400 = &g_rts5400; + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; + unsigned int gpio, power_on_12v = 0; + + int i, ret; + u8 val; + dev_dbg(dev, "Enter %s\n", __func__); + + memset(rts5400, 0, sizeof(rts5400)); + + rts5400->client = client; + rts5400->dev = dev; + + i2c_set_clientdata(client, rts5400); + + ret = rtk_rts5400_get_IC_status(); + if (ret < 0) { + dev_err(dev, "[RTS5400] rtk_rts5400_get_IC_status fail (ret=%d)\n", ret); + rts5400->no_device = true; + } else { + ret = rtk_rts5400_get_status(); + if (ret < 0) + dev_err(dev, "[RTS5400] rtk_rts5400_get_status fail (ret=%d)\n", ret); + ret = rtk_rts5400_get_PDO(PDO_TYPE_SOURCE, PDO_TCPM_TCPM, 0, 7, NULL); + if (ret < 0) + dev_err(dev, "[RTS5400] rtk_rts5400_get_PDO " + "(PDO_TYPE_SOURCE, PDO_TCPM_TCPM) fail (ret=%d)\n", ret); + ret = rtk_rts5400_get_PDO(PDO_TYPE_SOURCE, PDO_TCPM_PARTNER, 0, 7, NULL); + if (ret < 0) + dev_err(dev, "[RTS5400] rtk_rts5400_get_PDO " + "PDO_TYPE_SOURCE, PDO_TCPM_PARTNER) fail (ret=%d)\n", ret); + ret = rtk_rts5400_get_PDO(PDO_TYPE_SINK, PDO_TCPM_TCPM, 0, 7, NULL); + if (ret < 0) + dev_err(dev, "[RTS5400] rtk_rts5400_get_PDO " + "(PDO_TYPE_SINK, PDO_TCPM_TCPM) fail (ret=%d)\n", ret); + ret = rtk_rts5400_get_PDO(PDO_TYPE_SINK, PDO_TCPM_PARTNER, 0, 7, NULL); + if (ret < 0) + dev_err(dev, "[RTS5400] rtk_rts5400_get_PDO " + "(PDO_TYPE_SINK, PDO_TCPM_PARTNER) fail (ret=%d)\n", ret); + + ret = rtk_rts5400_get_current_pdo_voltage(); + + if (ret >= 12000) + power_on_12v = 1; + + gpio = of_get_named_gpio(node, "realtek,12v-power-gpio", 0); + + if (gpio_is_valid(gpio)) { + rts5400->pow_gpio = gpio; + dev_info(dev, "%s get 12V power-gpio (id=%d) OK\n", __func__, gpio); + if (gpio_direction_output(gpio, power_on_12v)) + dev_err(dev, "%s ERROR set 12v power (= 0) fail\n", __func__); + else + dev_info(dev, "%s Power %s 12v\n", __func__, power_on_12v?"on":"off"); + } else { + dev_err(dev, "Error 12V-power-gpio no found"); + rts5400->pow_gpio = -1; + } + } + + dev_dbg(dev, "Exit %s\n", __func__); + + return 0; +} + +#ifdef CONFIG_SUSPEND +static int rtk_rts5400_suspend(struct device *dev) +{ + dev_dbg(dev, "Enter %s\n", __func__); + + dev_dbg(dev, "Exit %s\n", __func__); + return 0; +} + +static int rtk_rts5400_resume(struct device *dev) +{ + dev_dbg(dev, "Enter %s\n", __func__); + + dev_dbg(dev, "Exit %s\n", __func__); + return 0; +} +#else + +#define rtk_rts5400_suspend NULL +#define rtk_rts5400_resume NULL + +#endif + +static const struct dev_pm_ops rtk_rts5400_pm_ops = { + .suspend = rtk_rts5400_suspend, + .resume = rtk_rts5400_resume, +}; + +static const struct i2c_device_id rtk_rts5400_ids[] = { + {"rtk-rts5400", 0}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, rtk_rts5400_ids); + +static struct i2c_driver rtk_rts5400_driver = { + .driver = { + .name = "rtk_rts5400", + .owner = THIS_MODULE, + .pm = &rtk_rts5400_pm_ops, + }, + .probe = rtk_rts5400_probe, + .id_table = rtk_rts5400_ids, +}; + +module_i2c_driver(rtk_rts5400_driver); + +MODULE_DESCRIPTION("RTS5400 Type C Port Manager Driver"); +MODULE_AUTHOR("Stanley Chang"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/dwc3/trace-rtk.c b/drivers/usb/dwc3/trace-rtk.c new file mode 100644 index 000000000000..5db28636c2b4 --- /dev/null +++ b/drivers/usb/dwc3/trace-rtk.c @@ -0,0 +1,3 @@ +#define DRIVERS_USB_DWC3_RTK_TRACE +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 97f4f1125a41..c3fba50b2670 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /** * trace.h - DesignWare USB3 DRD Controller Trace Support @@ -8,7 +11,11 @@ */ #undef TRACE_SYSTEM +#if defined(MY_DEF_HERE) && defined(DRIVERS_USB_DWC3_RTK_TRACE) +#define TRACE_SYSTEM dwc3_rtk +#else /* define(MY_DEF_HERE) && defined(DRIVERS_USB_DWC3_RTK_TRACE) */ #define TRACE_SYSTEM dwc3 +#endif /* define(MY_DEF_HERE) && defined(DRIVERS_USB_DWC3_RTK_TRACE) */ #if !defined(__DWC3_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) #define __DWC3_TRACE_H diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2d152571a7de..0afc0efafe5e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -216,6 +216,13 @@ config USB_F_PRINTER config USB_F_TCM tristate +if SYNO_LSP_RTD1619B +config USB_F_MTP + tristate + +config USB_F_PTP + tristate +endif # SYNO_LSP_RTD1619B # this first set of drivers all depend on bulk-capable hardware. config USB_CONFIGFS @@ -371,6 +378,21 @@ config USB_CONFIGFS_F_FS implemented in kernel space (for instance Ethernet, serial or mass storage) and other are implemented in user space. +if SYNO_LSP_RTD1619B +config USB_CONFIGFS_F_MTP + bool "MTP gadget" + depends on USB_CONFIGFS + select USB_F_MTP + help + USB gadget MTP support + +config USB_CONFIGFS_F_PTP + bool "PTP gadget" + depends on USB_CONFIGFS && USB_CONFIGFS_F_MTP + select USB_F_PTP + help + USB gadget PTP support +endif # SYNO_LSP_RTD1619B config USB_CONFIGFS_F_UAC1 bool "Audio Class 1.0" depends on USB_CONFIGFS diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1a556a628971..15054c67cea7 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * composite.c - infrastructure for Composite USB Gadgets @@ -346,6 +349,16 @@ int usb_add_function(struct usb_configuration *config, if (value) DBG(config->cdev, "adding '%s'/%p --> %d\n", function->name, function, value); +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + /* add to print log*/ + pr_notice("adding '%s'/%p to config '%s'/%p --> %s (ret=%d)\n", + function->name, function, + config->label, config, value?"Fail":"Ok", value); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ return value; } EXPORT_SYMBOL_GPL(usb_add_function); diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 5d3a6cf02218..023074bbda12 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -50,3 +50,9 @@ usb_f_printer-y := f_printer.o obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o usb_f_tcm-y := f_tcm.o obj-$(CONFIG_USB_F_TCM) += usb_f_tcm.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +usb_f_mtp-y := f_mtp.o +obj-$(CONFIG_USB_F_MTP) += usb_f_mtp.o +usb_f_ptp-y := f_ptp.o +obj-$(CONFIG_USB_F_PTP) += usb_f_ptp.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 725e35167837..fcc1a94dc8af 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * f_fs.c -- user mode file system API for USB composite function controllers @@ -3363,7 +3366,14 @@ static int ffs_func_setup(struct usb_function *f, __ffs_event_add(ffs, FUNCTIONFS_SETUP); spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Fix adnroid adb push big file fail */ + return 0; +#else +#endif /* MY_DEF_HERE */ return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0; +#endif /* MY_DEF_HERE */ } static bool ffs_func_req_match(struct usb_function *f, diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c new file mode 100644 index 000000000000..bd5261d1b44c --- /dev/null +++ b/drivers/usb/gadget/function/f_mtp.c @@ -0,0 +1,1714 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Gadget Function Driver for MTP + * + * Copyright (C) 2010 Google, Inc. + * Author: Mike Lockwood + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "configfs.h" + +#define MTP_BULK_BUFFER_SIZE 16384 +#define INTR_BUFFER_SIZE 28 +#define MAX_INST_NAME_LEN 40 +#define MTP_MAX_FILE_SIZE 0xFFFFFFFFL + +/* String IDs */ +#define INTERFACE_STRING_INDEX 0 + +/* values for mtp_dev.state */ +#define STATE_OFFLINE 0 /* initial state, disconnected */ +#define STATE_READY 1 /* ready for userspace calls */ +#define STATE_BUSY 2 /* processing userspace calls */ +#define STATE_CANCELED 3 /* transaction canceled by host */ +#define STATE_ERROR 4 /* error from completion routine */ + +/* number of tx and rx requests to allocate */ +#define TX_REQ_MAX 4 +#define RX_REQ_MAX 2 +#define INTR_REQ_MAX 5 + +/* ID for Microsoft MTP OS String */ +#define MTP_OS_STRING_ID 0xEE + +/* MTP class reqeusts */ +#define MTP_REQ_CANCEL 0x64 +#define MTP_REQ_GET_EXT_EVENT_DATA 0x65 +#define MTP_REQ_RESET 0x66 +#define MTP_REQ_GET_DEVICE_STATUS 0x67 + +/* constants for device status */ +#define MTP_RESPONSE_OK 0x2001 +#define MTP_RESPONSE_DEVICE_BUSY 0x2019 +#define DRIVER_NAME "mtp" + +#ifdef CONFIG_USB_PATCH_ON_RTK +#define IOCNR_MTP_SEND_FILE 0 +#define IOCNR_MTP_RECEIVE_FILE 1 +#define IOCNR_MTP_SEND_EVENT 3 +#define IOCNR_MTP_SEND_FILE_WITH_HEADER 4 + +struct mtp_event_32 { + int32_t length; + int32_t data; +}; +#endif + +static const char mtp_shortname[] = DRIVER_NAME "_usb"; + +struct mtp_dev { + struct usb_function function; + struct usb_composite_dev *cdev; + spinlock_t lock; + + struct usb_ep *ep_in; + struct usb_ep *ep_out; + struct usb_ep *ep_intr; + + int state; + + /* synchronize access to our device file */ + atomic_t open_excl; + /* to enforce only one ioctl at a time */ + atomic_t ioctl_excl; + + struct list_head tx_idle; + struct list_head intr_idle; + + wait_queue_head_t read_wq; + wait_queue_head_t write_wq; + wait_queue_head_t intr_wq; + struct usb_request *rx_req[RX_REQ_MAX]; + int rx_done; + + /* for processing MTP_SEND_FILE, MTP_RECEIVE_FILE and + * MTP_SEND_FILE_WITH_HEADER ioctls on a work queue + */ + struct workqueue_struct *wq; + struct work_struct send_file_work; + struct work_struct receive_file_work; + struct file *xfer_file; + loff_t xfer_file_offset; + int64_t xfer_file_length; + unsigned xfer_send_header; + uint16_t xfer_command; + uint32_t xfer_transaction_id; + int xfer_result; +}; + +static struct usb_interface_descriptor mtp_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 3, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, + .bInterfaceProtocol = 0, +}; + +static struct usb_interface_descriptor ptp_interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 3, + .bInterfaceClass = USB_CLASS_STILL_IMAGE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, +}; + +static struct usb_endpoint_descriptor mtp_ss_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor mtp_ss_in_comp_desc = { + .bLength = sizeof(mtp_ss_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = DYNAMIC, */ +}; + +static struct usb_endpoint_descriptor mtp_ss_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor mtp_ss_out_comp_desc = { + .bLength = sizeof(mtp_ss_out_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = DYNAMIC, */ +}; + +static struct usb_endpoint_descriptor mtp_highspeed_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor mtp_fullspeed_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor mtp_intr_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(INTR_BUFFER_SIZE), + .bInterval = 6, +}; + +static struct usb_ss_ep_comp_descriptor mtp_intr_ss_comp_desc = { + .bLength = sizeof(mtp_intr_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .wBytesPerInterval = cpu_to_le16(INTR_BUFFER_SIZE), +}; + +static struct usb_descriptor_header *fs_mtp_descs[] = { + (struct usb_descriptor_header *) &mtp_interface_desc, + (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, + (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, + (struct usb_descriptor_header *) &mtp_intr_desc, + NULL, +}; + +static struct usb_descriptor_header *hs_mtp_descs[] = { + (struct usb_descriptor_header *) &mtp_interface_desc, + (struct usb_descriptor_header *) &mtp_highspeed_in_desc, + (struct usb_descriptor_header *) &mtp_highspeed_out_desc, + (struct usb_descriptor_header *) &mtp_intr_desc, + NULL, +}; + +static struct usb_descriptor_header *ss_mtp_descs[] = { + (struct usb_descriptor_header *) &mtp_interface_desc, + (struct usb_descriptor_header *) &mtp_ss_in_desc, + (struct usb_descriptor_header *) &mtp_ss_in_comp_desc, + (struct usb_descriptor_header *) &mtp_ss_out_desc, + (struct usb_descriptor_header *) &mtp_ss_out_comp_desc, + (struct usb_descriptor_header *) &mtp_intr_desc, + (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc, + NULL, +}; + +static struct usb_descriptor_header *fs_ptp_descs[] = { + (struct usb_descriptor_header *) &ptp_interface_desc, + (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, + (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, + (struct usb_descriptor_header *) &mtp_intr_desc, + NULL, +}; + +static struct usb_descriptor_header *hs_ptp_descs[] = { + (struct usb_descriptor_header *) &ptp_interface_desc, + (struct usb_descriptor_header *) &mtp_highspeed_in_desc, + (struct usb_descriptor_header *) &mtp_highspeed_out_desc, + (struct usb_descriptor_header *) &mtp_intr_desc, + NULL, +}; + +static struct usb_descriptor_header *ss_ptp_descs[] = { + (struct usb_descriptor_header *) &ptp_interface_desc, + (struct usb_descriptor_header *) &mtp_ss_in_desc, + (struct usb_descriptor_header *) &mtp_ss_in_comp_desc, + (struct usb_descriptor_header *) &mtp_ss_out_desc, + (struct usb_descriptor_header *) &mtp_ss_out_comp_desc, + (struct usb_descriptor_header *) &mtp_intr_desc, + (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc, + NULL, +}; + +static struct usb_string mtp_string_defs[] = { + /* Naming interface "MTP" so libmtp will recognize us */ + [INTERFACE_STRING_INDEX].s = "MTP", + { }, /* end of list */ +}; + +static struct usb_gadget_strings mtp_string_table = { + .language = 0x0409, /* en-US */ + .strings = mtp_string_defs, +}; + +static struct usb_gadget_strings *mtp_strings[] = { + &mtp_string_table, + NULL, +}; + +/* Microsoft MTP OS String */ +static u8 mtp_os_string[] = { + 18, /* sizeof(mtp_os_string) */ + USB_DT_STRING, + /* Signature field: "MSFT100" */ + 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, + /* vendor code */ + 1, + /* padding */ + 0 +}; + +/* Microsoft Extended Configuration Descriptor Header Section */ +struct mtp_ext_config_desc_header { + __le32 dwLength; + __u16 bcdVersion; + __le16 wIndex; + __u8 bCount; + __u8 reserved[7]; +}; + +/* Microsoft Extended Configuration Descriptor Function Section */ +struct mtp_ext_config_desc_function { + __u8 bFirstInterfaceNumber; + __u8 bInterfaceCount; + __u8 compatibleID[8]; + __u8 subCompatibleID[8]; + __u8 reserved[6]; +}; + +/* MTP Extended Configuration Descriptor */ +struct { + struct mtp_ext_config_desc_header header; + struct mtp_ext_config_desc_function function; +} mtp_ext_config_desc = { + .header = { + .dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)), + .bcdVersion = __constant_cpu_to_le16(0x0100), + .wIndex = __constant_cpu_to_le16(4), + .bCount = 1, + }, + .function = { + .bFirstInterfaceNumber = 0, + .bInterfaceCount = 1, + .compatibleID = { 'M', 'T', 'P' }, + }, +}; + +struct mtp_device_status { + __le16 wLength; + __le16 wCode; +}; + +struct mtp_data_header { + /* length of packet, including this header */ + __le32 length; + /* container type (2 for data packet) */ + __le16 type; + /* MTP command code */ + __le16 command; + /* MTP transaction ID */ + __le32 transaction_id; +}; + +struct mtp_instance { + struct usb_function_instance func_inst; + const char *name; + struct mtp_dev *dev; + char mtp_ext_compat_id[16]; + struct usb_os_desc mtp_os_desc; +}; + +/* temporary variable used between mtp_open() and mtp_gadget_bind() */ +static struct mtp_dev *_mtp_dev; + +static inline struct mtp_dev *func_to_mtp(struct usb_function *f) +{ + return container_of(f, struct mtp_dev, function); +} + +static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) +{ + struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); + + if (!req) + return NULL; + + /* now allocate buffers for the requests */ + req->buf = kmalloc(buffer_size, GFP_KERNEL); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + + return req; +} + +static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) +{ + if (req) { + kfree(req->buf); + usb_ep_free_request(ep, req); + } +} + +static inline int mtp_lock(atomic_t *excl) +{ + if (atomic_inc_return(excl) == 1) { + return 0; + } else { + atomic_dec(excl); + return -1; + } +} + +static inline void mtp_unlock(atomic_t *excl) +{ + atomic_dec(excl); +} + +/* add a request to the tail of a list */ +static void mtp_req_put(struct mtp_dev *dev, struct list_head *head, + struct usb_request *req) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + list_add_tail(&req->list, head); + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* remove a request from the head of a list */ +static struct usb_request +*mtp_req_get(struct mtp_dev *dev, struct list_head *head) +{ + unsigned long flags; + struct usb_request *req; + + spin_lock_irqsave(&dev->lock, flags); + if (list_empty(head)) { + req = 0; + } else { + req = list_first_entry(head, struct usb_request, list); + list_del(&req->list); + } + spin_unlock_irqrestore(&dev->lock, flags); + return req; +} + +static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) +{ + struct mtp_dev *dev = _mtp_dev; + + if (req->status != 0) + dev->state = STATE_ERROR; + + mtp_req_put(dev, &dev->tx_idle, req); + + wake_up(&dev->write_wq); +} + +static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) +{ + struct mtp_dev *dev = _mtp_dev; + + dev->rx_done = 1; + if (req->status != 0) + dev->state = STATE_ERROR; + + wake_up(&dev->read_wq); +} + +static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) +{ + struct mtp_dev *dev = _mtp_dev; + + if (req->status != 0) + dev->state = STATE_ERROR; + + mtp_req_put(dev, &dev->intr_idle, req); + + wake_up(&dev->intr_wq); +} + +static int mtp_create_bulk_endpoints(struct mtp_dev *dev, + struct usb_endpoint_descriptor *in_desc, + struct usb_endpoint_descriptor *out_desc, + struct usb_endpoint_descriptor *intr_desc) +{ + struct usb_composite_dev *cdev = dev->cdev; + struct usb_request *req; + struct usb_ep *ep; + int i; + + DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); + + ep = usb_ep_autoconfig(cdev->gadget, in_desc); + if (!ep) { + DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); + return -ENODEV; + } + DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); + ep->driver_data = dev; /* claim the endpoint */ + dev->ep_in = ep; + + ep = usb_ep_autoconfig(cdev->gadget, out_desc); + if (!ep) { + DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); + return -ENODEV; + } + DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); + ep->driver_data = dev; /* claim the endpoint */ + dev->ep_out = ep; + + ep = usb_ep_autoconfig(cdev->gadget, intr_desc); + if (!ep) { + DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n"); + return -ENODEV; + } + DBG(cdev, "usb_ep_autoconfig for mtp ep_intr got %s\n", ep->name); + ep->driver_data = dev; /* claim the endpoint */ + dev->ep_intr = ep; + + /* now allocate requests for our endpoints */ + for (i = 0; i < TX_REQ_MAX; i++) { + req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE); + if (!req) + goto fail; + req->complete = mtp_complete_in; + mtp_req_put(dev, &dev->tx_idle, req); + } + for (i = 0; i < RX_REQ_MAX; i++) { + req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE); + if (!req) + goto fail; + req->complete = mtp_complete_out; + dev->rx_req[i] = req; + } + for (i = 0; i < INTR_REQ_MAX; i++) { + req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE); + if (!req) + goto fail; + req->complete = mtp_complete_intr; + mtp_req_put(dev, &dev->intr_idle, req); + } + + return 0; + +fail: + pr_err("mtp_bind() could not allocate requests\n"); + return -1; +} + +static ssize_t mtp_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + struct mtp_dev *dev = fp->private_data; + struct usb_composite_dev *cdev = dev->cdev; + struct usb_request *req; + ssize_t r = count; + unsigned xfer; + int ret = 0; + size_t len = 0; + + DBG(cdev, "mtp_read(%zu)\n", count); + + /* we will block until we're online */ + DBG(cdev, "mtp_read: waiting for online state\n"); + ret = wait_event_interruptible(dev->read_wq, + dev->state != STATE_OFFLINE); + if (ret < 0) { + r = ret; + goto done; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Add a workaround due to we dynamical switch gadget driver */ + if (cdev == NULL) { + pr_info("%s cdev is NULL! We get cdev again. dev->cdev=%p\n", + __func__, dev->cdev); + cdev = dev->cdev; + } +#endif // CONFIG_USB_PATCH_ON_RTK + + spin_lock_irq(&dev->lock); + if (dev->ep_out->desc) { + len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count); + if (len > MTP_BULK_BUFFER_SIZE) { + spin_unlock_irq(&dev->lock); + return -EINVAL; + } + } + + if (dev->state == STATE_CANCELED) { + /* report cancelation to userspace */ + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + return -ECANCELED; + } + dev->state = STATE_BUSY; + spin_unlock_irq(&dev->lock); + +requeue_req: + /* queue a request */ + req = dev->rx_req[0]; + req->length = len; + dev->rx_done = 0; +#ifdef CONFIG_USB_PATCH_ON_RTK + // add workaround to fix Rx for bMaxPacketSize0 + if (count == 512) { + struct usb_gadget *gadget = cdev->gadget; + if (gadget->speed == USB_SPEED_SUPER) { + req->length = 1024; + DBG(cdev, "mtp_read(%zu) for super speed fixed length to 1024\n", count); + } + } +#endif + ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); + if (ret < 0) { + r = -EIO; + goto done; + } else { + DBG(cdev, "rx %p queue\n", req); + } + + /* wait for a request to complete */ + ret = wait_event_interruptible(dev->read_wq, dev->rx_done); + if (ret < 0) { + r = ret; + usb_ep_dequeue(dev->ep_out, req); + goto done; + } + if (dev->state == STATE_BUSY) { + /* If we got a 0-len packet, throw it back and try again. */ + if (req->actual == 0) + goto requeue_req; + + DBG(cdev, "rx %p %d\n", req, req->actual); + xfer = (req->actual < count) ? req->actual : count; + r = xfer; + if (copy_to_user(buf, req->buf, xfer)) + r = -EFAULT; + } else + r = -EIO; + +done: + spin_lock_irq(&dev->lock); + if (dev->state == STATE_CANCELED) + r = -ECANCELED; + else if (dev->state != STATE_OFFLINE) + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + + DBG(cdev, "mtp_read returning %zd\n", r); + + return r; +} + +static ssize_t mtp_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct mtp_dev *dev = fp->private_data; + struct usb_composite_dev *cdev = dev->cdev; + struct usb_request *req = 0; + ssize_t r = count; + unsigned xfer; + int sendZLP = 0; + int ret; + + DBG(cdev, "mtp_write(%zu)\n", count); + + spin_lock_irq(&dev->lock); + if (dev->state == STATE_CANCELED) { + /* report cancelation to userspace */ + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + return -ECANCELED; + } + if (dev->state == STATE_OFFLINE) { + spin_unlock_irq(&dev->lock); + return -ENODEV; + } + dev->state = STATE_BUSY; + spin_unlock_irq(&dev->lock); + + /* we need to send a zero length packet to signal the end of transfer + * if the transfer size is aligned to a packet boundary. + */ + if ((count & (dev->ep_in->maxpacket - 1)) == 0) + sendZLP = 1; + + while (count > 0 || sendZLP) { + /* so we exit after sending ZLP */ + if (count == 0) + sendZLP = 0; + + if (dev->state != STATE_BUSY) { + DBG(cdev, "mtp_write dev->error\n"); + r = -EIO; + break; + } + + /* get an idle tx request to use */ + req = 0; + ret = wait_event_interruptible(dev->write_wq, + ((req = mtp_req_get(dev, &dev->tx_idle)) + || dev->state != STATE_BUSY)); + if (!req) { + r = ret; + break; + } + + if (count > MTP_BULK_BUFFER_SIZE) + xfer = MTP_BULK_BUFFER_SIZE; + else + xfer = count; + if (xfer && copy_from_user(req->buf, buf, xfer)) { + r = -EFAULT; + break; + } + + req->length = xfer; + ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); + if (ret < 0) { + DBG(cdev, "mtp_write: xfer error %d\n", ret); + r = -EIO; + break; + } + + buf += xfer; + count -= xfer; + + /* zero this so we don't try to free it on error exit */ + req = 0; + } + + if (req) + mtp_req_put(dev, &dev->tx_idle, req); + + spin_lock_irq(&dev->lock); + if (dev->state == STATE_CANCELED) + r = -ECANCELED; + else if (dev->state != STATE_OFFLINE) + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + + DBG(cdev, "mtp_write returning %zd\n", r); + return r; +} + +/* read from a local file and write to USB */ +static void send_file_work(struct work_struct *data) +{ + struct mtp_dev *dev = container_of(data, struct mtp_dev, + send_file_work); + struct usb_composite_dev *cdev = dev->cdev; + struct usb_request *req = 0; + struct mtp_data_header *header; + struct file *filp; + loff_t offset; + int64_t count; + int xfer, ret, hdr_size; + int r = 0; + int sendZLP = 0; + + /* read our parameters */ + smp_rmb(); + filp = dev->xfer_file; + offset = dev->xfer_file_offset; + count = dev->xfer_file_length; + + DBG(cdev, "send_file_work(%lld %lld)\n", offset, count); + + if (dev->xfer_send_header) { + hdr_size = sizeof(struct mtp_data_header); + count += hdr_size; + } else { + hdr_size = 0; + } + + /* we need to send a zero length packet to signal the end of transfer + * if the transfer size is aligned to a packet boundary. + */ + if ((count & (dev->ep_in->maxpacket - 1)) == 0) + sendZLP = 1; + + while (count > 0 || sendZLP) { + /* so we exit after sending ZLP */ + if (count == 0) + sendZLP = 0; + + /* get an idle tx request to use */ + req = 0; + ret = wait_event_interruptible(dev->write_wq, + (req = mtp_req_get(dev, &dev->tx_idle)) + || dev->state != STATE_BUSY); + if (dev->state == STATE_CANCELED) { + r = -ECANCELED; + break; + } + if (!req) { + r = ret; + break; + } + + if (count > MTP_BULK_BUFFER_SIZE) + xfer = MTP_BULK_BUFFER_SIZE; + else + xfer = count; + + if (hdr_size) { + /* prepend MTP data header */ + header = (struct mtp_data_header *)req->buf; + /* + * set file size with header according to + * MTP Specification v1.0 + */ + header->length = (count > MTP_MAX_FILE_SIZE) ? + MTP_MAX_FILE_SIZE : __cpu_to_le32(count); + header->type = __cpu_to_le16(2); /* data packet */ + header->command = __cpu_to_le16(dev->xfer_command); + header->transaction_id = + __cpu_to_le32(dev->xfer_transaction_id); + } + + ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size, + &offset); + if (ret < 0) { + r = ret; + break; + } + xfer = ret + hdr_size; + hdr_size = 0; + + req->length = xfer; + ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); + if (ret < 0) { + DBG(cdev, "send_file_work: xfer error %d\n", ret); + dev->state = STATE_ERROR; + r = -EIO; + break; + } + + count -= xfer; + + /* zero this so we don't try to free it on error exit */ + req = 0; + } + + if (req) + mtp_req_put(dev, &dev->tx_idle, req); + + DBG(cdev, "send_file_work returning %d\n", r); + /* write the result */ + dev->xfer_result = r; + smp_wmb(); +} + +/* read from USB and write to a local file */ +static void receive_file_work(struct work_struct *data) +{ + struct mtp_dev *dev = container_of(data, struct mtp_dev, + receive_file_work); + struct usb_composite_dev *cdev = dev->cdev; + struct usb_request *read_req = NULL, *write_req = NULL; + struct file *filp; + loff_t offset; + int64_t count, len; + int ret, cur_buf = 0; + int r = 0; + + /* read our parameters */ + smp_rmb(); + filp = dev->xfer_file; + offset = dev->xfer_file_offset; + count = dev->xfer_file_length; +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Fixed last transfer can't complete */ + if (count != 0xFFFFFFFF) + count = count + offset; + DBG(cdev, "receive_file_work(%lld %lld)\n", offset, count); +#endif + + DBG(cdev, "receive_file_work(%lld)\n", count); + + while (count > 0 || write_req) { + if (count > 0) { + /* queue a request */ + read_req = dev->rx_req[cur_buf]; + cur_buf = (cur_buf + 1) % RX_REQ_MAX; + + len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count); + if (len > MTP_BULK_BUFFER_SIZE) + len = MTP_BULK_BUFFER_SIZE; + read_req->length = len; + dev->rx_done = 0; + ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); + if (ret < 0) { + r = -EIO; + dev->state = STATE_ERROR; + break; + } + } + + if (write_req) { + DBG(cdev, "rx %p %d\n", write_req, write_req->actual); + ret = vfs_write(filp, write_req->buf, write_req->actual, + &offset); + DBG(cdev, "vfs_write %d\n", ret); + if (ret != write_req->actual) { + r = -EIO; + dev->state = STATE_ERROR; + break; + } + write_req = NULL; + } + + if (read_req) { + /* wait for our last read to complete */ + ret = wait_event_interruptible(dev->read_wq, + dev->rx_done || dev->state != STATE_BUSY); + if (dev->state == STATE_CANCELED) { + r = -ECANCELED; + if (!dev->rx_done) + usb_ep_dequeue(dev->ep_out, read_req); + break; + } + if (read_req->status) { + r = read_req->status; + break; + } + /* if xfer_file_length is 0xFFFFFFFF, then we read until + * we get a zero length packet + */ + if (count != 0xFFFFFFFF) + count -= read_req->actual; + if (read_req->actual < read_req->length) { + /* + * short packet is used to signal EOF for + * sizes > 4 gig + */ + DBG(cdev, "got short packet\n"); + count = 0; + } + + write_req = read_req; + read_req = NULL; + } + } + + DBG(cdev, "receive_file_work returning %d\n", r); + /* write the result */ + dev->xfer_result = r; + smp_wmb(); +} + +static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) +{ + struct usb_request *req = NULL; + int ret; + int length = event->length; + + DBG(dev->cdev, "mtp_send_event(%zu)\n", event->length); + + if (length < 0 || length > INTR_BUFFER_SIZE) + return -EINVAL; + if (dev->state == STATE_OFFLINE) + return -ENODEV; + + ret = wait_event_interruptible_timeout(dev->intr_wq, + (req = mtp_req_get(dev, &dev->intr_idle)), + msecs_to_jiffies(1000)); + if (!req) + return -ETIME; + + if (copy_from_user(req->buf, (void __user *)event->data, length)) { + mtp_req_put(dev, &dev->intr_idle, req); + return -EFAULT; + } + req->length = length; + ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL); + if (ret) + mtp_req_put(dev, &dev->intr_idle, req); + + return ret; +} + +static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) +{ + struct mtp_dev *dev = fp->private_data; + struct file *filp = NULL; + int ret = -EINVAL; + + if (mtp_lock(&dev->ioctl_excl)) + return -EBUSY; +#ifdef CONFIG_USB_PATCH_ON_RTK + DBG(dev->cdev, "%s\n", __func__); + + DBG(dev->cdev, + "mtp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", code, + _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code), _IOC_DIR(code)); + + if ((_IOC_TYPE(code) != 'M') && (_IOC_DIR(code) != _IOC_WRITE)) { + ERROR(dev->cdev, + "mtp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", code, + _IOC_TYPE(code), _IOC_NR(code), _IOC_SIZE(code), _IOC_DIR(code)); + goto out; + } + + switch (_IOC_NR(code)) { + case IOCNR_MTP_SEND_FILE: + case IOCNR_MTP_RECEIVE_FILE: + case IOCNR_MTP_SEND_FILE_WITH_HEADER: + { + struct mtp_file_range mfr; + struct work_struct *work; + + spin_lock_irq(&dev->lock); + if (dev->state == STATE_CANCELED) { + /* report cancelation to userspace */ + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + ret = -ECANCELED; + goto out; + } + if (dev->state == STATE_OFFLINE) { + spin_unlock_irq(&dev->lock); + ret = -ENODEV; + goto out; + } + dev->state = STATE_BUSY; + spin_unlock_irq(&dev->lock); + + if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { + ret = -EFAULT; + goto fail; + } + /* hold a reference to the file while we are working with it */ + filp = fget(mfr.fd); + if (!filp) { + ret = -EBADF; + goto fail; + } + + /* write the parameters */ + dev->xfer_file = filp; + dev->xfer_file_offset = mfr.offset; + dev->xfer_file_length = mfr.length; + smp_wmb(); + + if (_IOC_NR(code) == IOCNR_MTP_SEND_FILE_WITH_HEADER) { + work = &dev->send_file_work; + dev->xfer_send_header = 1; + dev->xfer_command = mfr.command; + dev->xfer_transaction_id = mfr.transaction_id; + } else if (_IOC_NR(code) == IOCNR_MTP_SEND_FILE) { + work = &dev->send_file_work; + dev->xfer_send_header = 0; + } else { + work = &dev->receive_file_work; + } + + /* We do the file transfer on a work queue so it will run + * in kernel context, which is necessary for vfs_read and + * vfs_write to use our buffers in the kernel address space. + */ + queue_work(dev->wq, work); + /* wait for operation to complete */ + flush_workqueue(dev->wq); + fput(filp); + + /* read the result */ + smp_rmb(); + ret = dev->xfer_result; + break; + } + case IOCNR_MTP_SEND_EVENT: + { + struct mtp_event_32 event32; + struct mtp_event event; + /* return here so we don't change dev->state below, + * which would interfere with bulk transfer state. + */ + if (_IOC_SIZE(code) == sizeof(struct mtp_event)) { + if (copy_from_user(&event, (void __user *)value, sizeof(struct mtp_event))) + ret = -EFAULT; + else + ret = mtp_send_event(dev, &event); + } else if (_IOC_SIZE(code) == sizeof(struct mtp_event_32)) { + if (copy_from_user(&event32, (void __user *)value, _IOC_SIZE(code))) + ret = -EFAULT; + else { + event.length = event32.length; +#if defined(CONFIG_CPU_V7) + event.data = event32.data; +#else + event.data = compat_ptr(event32.data); +#endif /* CONFIG_CPU_V7 */ + DBG(dev->cdev, "%s: data %x data32 %x\n",__func__, event.data, event32.data); + ret = mtp_send_event(dev, &event); + } + } + goto out; + } + } +#else + switch (code) { + case MTP_SEND_FILE: + case MTP_RECEIVE_FILE: + case MTP_SEND_FILE_WITH_HEADER: + { + struct mtp_file_range mfr; + struct work_struct *work; + + spin_lock_irq(&dev->lock); + if (dev->state == STATE_CANCELED) { + /* report cancelation to userspace */ + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); + ret = -ECANCELED; + goto out; + } + if (dev->state == STATE_OFFLINE) { + spin_unlock_irq(&dev->lock); + ret = -ENODEV; + goto out; + } + dev->state = STATE_BUSY; + spin_unlock_irq(&dev->lock); + + if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { + ret = -EFAULT; + goto fail; + } + /* hold a reference to the file while we are working with it */ + filp = fget(mfr.fd); + if (!filp) { + ret = -EBADF; + goto fail; + } + + /* write the parameters */ + dev->xfer_file = filp; + dev->xfer_file_offset = mfr.offset; + dev->xfer_file_length = mfr.length; + smp_wmb(); + + if (code == MTP_SEND_FILE_WITH_HEADER) { + work = &dev->send_file_work; + dev->xfer_send_header = 1; + dev->xfer_command = mfr.command; + dev->xfer_transaction_id = mfr.transaction_id; + } else if (code == MTP_SEND_FILE) { + work = &dev->send_file_work; + dev->xfer_send_header = 0; + } else { + work = &dev->receive_file_work; + } + + /* We do the file transfer on a work queue so it will run + * in kernel context, which is necessary for vfs_read and + * vfs_write to use our buffers in the kernel address space. + */ + queue_work(dev->wq, work); + /* wait for operation to complete */ + flush_workqueue(dev->wq); + fput(filp); + + /* read the result */ + smp_rmb(); + ret = dev->xfer_result; + break; + } + case MTP_SEND_EVENT: + { + struct mtp_event event; + /* return here so we don't change dev->state below, + * which would interfere with bulk transfer state. + */ + if (copy_from_user(&event, (void __user *)value, sizeof(event))) + ret = -EFAULT; + else + ret = mtp_send_event(dev, &event); + goto out; + } + } +#endif + +fail: + spin_lock_irq(&dev->lock); + if (dev->state == STATE_CANCELED) + ret = -ECANCELED; + else if (dev->state != STATE_OFFLINE) + dev->state = STATE_READY; + spin_unlock_irq(&dev->lock); +out: + mtp_unlock(&dev->ioctl_excl); + DBG(dev->cdev, "ioctl returning %d\n", ret); + return ret; +} + +#ifdef CONFIG_COMPAT +static long mtp_compat_ioctl(struct file *fp, unsigned code, unsigned long value) +{ + struct mtp_dev *dev = fp->private_data; + int ret; + DBG(dev->cdev, "%s\n", __func__); +#if defined(CONFIG_CPU_V7) + ret = mtp_ioctl(fp, code, value); +#else + ret = mtp_ioctl(fp, code, compat_ptr(value)); +#endif /* CONFIG_CPU_V7 */ + return ret; +} +#endif + +static int mtp_open(struct inode *ip, struct file *fp) +{ + printk(KERN_INFO "mtp_open\n"); + if (mtp_lock(&_mtp_dev->open_excl)) + return -EBUSY; + + /* clear any error condition */ + if (_mtp_dev->state != STATE_OFFLINE) + _mtp_dev->state = STATE_READY; + + fp->private_data = _mtp_dev; + return 0; +} + +static int mtp_release(struct inode *ip, struct file *fp) +{ + printk(KERN_INFO "mtp_release\n"); + + mtp_unlock(&_mtp_dev->open_excl); + return 0; +} + +/* file operations for /dev/mtp_usb */ +static const struct file_operations mtp_fops = { + .owner = THIS_MODULE, + .read = mtp_read, + .write = mtp_write, + .unlocked_ioctl = mtp_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mtp_compat_ioctl, +#endif + .open = mtp_open, + .release = mtp_release, +}; + +static struct miscdevice mtp_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = mtp_shortname, + .fops = &mtp_fops, +}; + +static int mtp_ctrlrequest(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl) +{ + struct mtp_dev *dev = _mtp_dev; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + unsigned long flags; + + VDBG(cdev, "mtp_ctrlrequest " + "%02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + + /* Handle MTP OS string */ + if (ctrl->bRequestType == + (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) + && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR + && (w_value >> 8) == USB_DT_STRING + && (w_value & 0xFF) == MTP_OS_STRING_ID) { + value = (w_length < sizeof(mtp_os_string) + ? w_length : sizeof(mtp_os_string)); + memcpy(cdev->req->buf, mtp_os_string, value); + } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { + /* Handle MTP OS descriptor */ + DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n", + ctrl->bRequest, w_index, w_value, w_length); + + if (ctrl->bRequest == 1 + && (ctrl->bRequestType & USB_DIR_IN) + && (w_index == 4 || w_index == 5)) { + value = (w_length < sizeof(mtp_ext_config_desc) ? + w_length : sizeof(mtp_ext_config_desc)); + memcpy(cdev->req->buf, &mtp_ext_config_desc, value); + } + } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { + DBG(cdev, "class request: %d index: %d value: %d length: %d\n", + ctrl->bRequest, w_index, w_value, w_length); + + if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0 + && w_value == 0) { + DBG(cdev, "MTP_REQ_CANCEL\n"); + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state == STATE_BUSY) { + dev->state = STATE_CANCELED; + wake_up(&dev->read_wq); + wake_up(&dev->write_wq); + } + spin_unlock_irqrestore(&dev->lock, flags); + + /* We need to queue a request to read the remaining + * bytes, but we don't actually need to look at + * the contents. + */ + value = w_length; + } else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS + && w_index == 0 && w_value == 0) { + struct mtp_device_status *status = cdev->req->buf; + + status->wLength = + __constant_cpu_to_le16(sizeof(*status)); + + DBG(cdev, "MTP_REQ_GET_DEVICE_STATUS\n"); + spin_lock_irqsave(&dev->lock, flags); + /* device status is "busy" until we report + * the cancelation to userspace + */ + if (dev->state == STATE_CANCELED) + status->wCode = + __cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY); + else + status->wCode = + __cpu_to_le16(MTP_RESPONSE_OK); + spin_unlock_irqrestore(&dev->lock, flags); + value = sizeof(*status); + } + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + int rc; + + cdev->req->zero = value < w_length; + cdev->req->length = value; + rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); + if (rc < 0) + ERROR(cdev, "%s: response queue error\n", __func__); + } + return value; +} + +static int +mtp_function_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct mtp_dev *dev = func_to_mtp(f); + int id; + int ret; + struct mtp_instance *fi_mtp; + + dev->cdev = cdev; + DBG(cdev, "mtp_function_bind dev: %p\n", dev); + + /* allocate interface ID(s) */ + id = usb_interface_id(c, f); + if (id < 0) + return id; + mtp_interface_desc.bInterfaceNumber = id; + + if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) { + ret = usb_string_id(c->cdev); + if (ret < 0) + return ret; + mtp_string_defs[INTERFACE_STRING_INDEX].id = ret; + mtp_interface_desc.iInterface = ret; + } + + fi_mtp = container_of(f->fi, struct mtp_instance, func_inst); + + if (cdev->use_os_string) { + f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), + GFP_KERNEL); + if (!f->os_desc_table) + return -ENOMEM; + f->os_desc_n = 1; + f->os_desc_table[0].os_desc = &fi_mtp->mtp_os_desc; + } + + /* allocate endpoints */ + ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, + &mtp_fullspeed_out_desc, &mtp_intr_desc); + if (ret) + return ret; + + /* support high speed hardware */ + if (gadget_is_dualspeed(c->cdev->gadget)) { + mtp_highspeed_in_desc.bEndpointAddress = + mtp_fullspeed_in_desc.bEndpointAddress; + mtp_highspeed_out_desc.bEndpointAddress = + mtp_fullspeed_out_desc.bEndpointAddress; + } + /* support super speed hardware */ + if (gadget_is_superspeed(c->cdev->gadget)) { + unsigned max_burst; + + /* Calculate bMaxBurst, we know packet size is 1024 */ + max_burst = min_t(unsigned, MTP_BULK_BUFFER_SIZE / 1024, 15); + mtp_ss_in_desc.bEndpointAddress = + mtp_fullspeed_in_desc.bEndpointAddress; + mtp_ss_in_comp_desc.bMaxBurst = max_burst; + mtp_ss_out_desc.bEndpointAddress = + mtp_fullspeed_out_desc.bEndpointAddress; + mtp_ss_out_comp_desc.bMaxBurst = max_burst; + } + + DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : + (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"), + f->name, dev->ep_in->name, dev->ep_out->name); + return 0; +} + +static void +mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct mtp_dev *dev = func_to_mtp(f); + struct usb_request *req; + int i; + + mtp_string_defs[INTERFACE_STRING_INDEX].id = 0; + while ((req = mtp_req_get(dev, &dev->tx_idle))) + mtp_request_free(req, dev->ep_in); + for (i = 0; i < RX_REQ_MAX; i++) + mtp_request_free(dev->rx_req[i], dev->ep_out); + while ((req = mtp_req_get(dev, &dev->intr_idle))) + mtp_request_free(req, dev->ep_intr); + dev->state = STATE_OFFLINE; + kfree(f->os_desc_table); + f->os_desc_n = 0; +} + +static int mtp_function_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct mtp_dev *dev = func_to_mtp(f); + struct usb_composite_dev *cdev = f->config->cdev; + int ret; + + DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt); + + ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); + if (ret) + return ret; + + ret = usb_ep_enable(dev->ep_in); + if (ret) + return ret; + + ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); + if (ret) + return ret; + + ret = usb_ep_enable(dev->ep_out); + if (ret) { + usb_ep_disable(dev->ep_in); + return ret; + } + + ret = config_ep_by_speed(cdev->gadget, f, dev->ep_intr); + if (ret) + return ret; + + ret = usb_ep_enable(dev->ep_intr); + if (ret) { + usb_ep_disable(dev->ep_out); + usb_ep_disable(dev->ep_in); + return ret; + } + dev->state = STATE_READY; + + /* readers may be blocked waiting for us to go online */ + wake_up(&dev->read_wq); + return 0; +} + +static void mtp_function_disable(struct usb_function *f) +{ + struct mtp_dev *dev = func_to_mtp(f); + struct usb_composite_dev *cdev = dev->cdev; + + DBG(cdev, "mtp_function_disable\n"); + dev->state = STATE_OFFLINE; + usb_ep_disable(dev->ep_in); + usb_ep_disable(dev->ep_out); + usb_ep_disable(dev->ep_intr); + + /* readers may be blocked waiting for us to go online */ + wake_up(&dev->read_wq); + + VDBG(cdev, "%s disabled\n", dev->function.name); +} + +static int __mtp_setup(struct mtp_instance *fi_mtp) +{ + struct mtp_dev *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + + if (fi_mtp != NULL) + fi_mtp->dev = dev; + + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->lock); + init_waitqueue_head(&dev->read_wq); + init_waitqueue_head(&dev->write_wq); + init_waitqueue_head(&dev->intr_wq); + atomic_set(&dev->open_excl, 0); + atomic_set(&dev->ioctl_excl, 0); + INIT_LIST_HEAD(&dev->tx_idle); + INIT_LIST_HEAD(&dev->intr_idle); + + dev->wq = create_singlethread_workqueue("f_mtp"); + if (!dev->wq) { + ret = -ENOMEM; + goto err1; + } + INIT_WORK(&dev->send_file_work, send_file_work); + INIT_WORK(&dev->receive_file_work, receive_file_work); + + _mtp_dev = dev; + + ret = misc_register(&mtp_device); + if (ret) + goto err2; + + return 0; + +err2: + destroy_workqueue(dev->wq); +err1: + _mtp_dev = NULL; + kfree(dev); + printk(KERN_ERR "mtp gadget driver failed to initialize\n"); + return ret; +} + +static int mtp_setup_configfs(struct mtp_instance *fi_mtp) +{ + return __mtp_setup(fi_mtp); +} + + +static void mtp_cleanup(void) +{ + struct mtp_dev *dev = _mtp_dev; + + if (!dev) + return; + + misc_deregister(&mtp_device); + destroy_workqueue(dev->wq); + _mtp_dev = NULL; + kfree(dev); +} + +static struct mtp_instance *to_mtp_instance(struct config_item *item) +{ + return container_of(to_config_group(item), struct mtp_instance, + func_inst.group); +} + +static void mtp_attr_release(struct config_item *item) +{ + struct mtp_instance *fi_mtp = to_mtp_instance(item); + + usb_put_function_instance(&fi_mtp->func_inst); +} + +static struct configfs_item_operations mtp_item_ops = { + .release = mtp_attr_release, +}; + +static struct config_item_type mtp_func_type = { + .ct_item_ops = &mtp_item_ops, + .ct_owner = THIS_MODULE, +}; + + +static struct mtp_instance *to_fi_mtp(struct usb_function_instance *fi) +{ + return container_of(fi, struct mtp_instance, func_inst); +} + +static int mtp_set_inst_name(struct usb_function_instance *fi, const char *name) +{ + struct mtp_instance *fi_mtp; + char *ptr; + int name_len; + + name_len = strlen(name) + 1; + if (name_len > MAX_INST_NAME_LEN) + return -ENAMETOOLONG; + + ptr = kstrndup(name, name_len, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + fi_mtp = to_fi_mtp(fi); + fi_mtp->name = ptr; + + return 0; +} + +static void mtp_free_inst(struct usb_function_instance *fi) +{ + struct mtp_instance *fi_mtp; + + fi_mtp = to_fi_mtp(fi); + kfree(fi_mtp->name); + mtp_cleanup(); + kfree(fi_mtp); +} + +struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config) +{ + struct mtp_instance *fi_mtp; + int ret = 0; + struct usb_os_desc *descs[1]; + char *names[1]; + + fi_mtp = kzalloc(sizeof(*fi_mtp), GFP_KERNEL); + if (!fi_mtp) + return ERR_PTR(-ENOMEM); + fi_mtp->func_inst.set_inst_name = mtp_set_inst_name; + fi_mtp->func_inst.free_func_inst = mtp_free_inst; + + fi_mtp->mtp_os_desc.ext_compat_id = fi_mtp->mtp_ext_compat_id; + INIT_LIST_HEAD(&fi_mtp->mtp_os_desc.ext_prop); + descs[0] = &fi_mtp->mtp_os_desc; + names[0] = "MTP"; + + if (mtp_config) { + ret = mtp_setup_configfs(fi_mtp); + if (ret) { + kfree(fi_mtp); + pr_err("Error setting MTP\n"); + return ERR_PTR(ret); + } + } else + fi_mtp->dev = _mtp_dev; + + config_group_init_type_name(&fi_mtp->func_inst.group, + "", &mtp_func_type); + usb_os_desc_prepare_interf_dir(&fi_mtp->func_inst.group, 1, + descs, names, THIS_MODULE); + + return &fi_mtp->func_inst; +} +EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp); + +static struct usb_function_instance *mtp_alloc_inst(void) +{ + return alloc_inst_mtp_ptp(true); +} + +static int mtp_ctrlreq_configfs(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + return mtp_ctrlrequest(f->config->cdev, ctrl); +} + +static void mtp_free(struct usb_function *f) +{ + /*NO-OP: no function specific resource allocation in mtp_alloc*/ +} + +struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, + bool mtp_config) +{ + struct mtp_instance *fi_mtp = to_fi_mtp(fi); + struct mtp_dev *dev; + + /* + * PTP piggybacks on MTP function so make sure we have + * created MTP function before we associate this PTP + * function with a gadget configuration. + */ + if (fi_mtp->dev == NULL) { + pr_err("Error: Create MTP function before linking" + " PTP function with a gadget configuration\n"); + pr_err("\t1: Delete existing PTP function if any\n"); + pr_err("\t2: Create MTP function\n"); + pr_err("\t3: Create and symlink PTP function" + " with a gadget configuration\n"); + return ERR_PTR(-EINVAL); /* Invalid Configuration */ + } + + dev = fi_mtp->dev; + dev->function.name = DRIVER_NAME; + dev->function.strings = mtp_strings; + if (mtp_config) { + dev->function.fs_descriptors = fs_mtp_descs; + dev->function.hs_descriptors = hs_mtp_descs; + dev->function.ss_descriptors = ss_mtp_descs; + } else { + dev->function.fs_descriptors = fs_ptp_descs; + dev->function.hs_descriptors = hs_ptp_descs; + dev->function.ss_descriptors = ss_ptp_descs; + } + dev->function.bind = mtp_function_bind; + dev->function.unbind = mtp_function_unbind; + dev->function.set_alt = mtp_function_set_alt; + dev->function.disable = mtp_function_disable; + dev->function.setup = mtp_ctrlreq_configfs; + dev->function.free_func = mtp_free; + + return &dev->function; +} +EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp); + +static struct usb_function *mtp_alloc(struct usb_function_instance *fi) +{ + return function_alloc_mtp_ptp(fi, true); +} + +DECLARE_USB_FUNCTION_INIT(mtp, mtp_alloc_inst, mtp_alloc); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/function/f_mtp.h b/drivers/usb/gadget/function/f_mtp.h new file mode 100644 index 000000000000..dd21447df601 --- /dev/null +++ b/drivers/usb/gadget/function/f_mtp.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Badhri Jagan Sridharan + * + */ + +extern struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config); +extern struct usb_function *function_alloc_mtp_ptp( + struct usb_function_instance *fi, bool mtp_config); diff --git a/drivers/usb/gadget/function/f_ptp.c b/drivers/usb/gadget/function/f_ptp.c new file mode 100644 index 000000000000..750aac8e0bf8 --- /dev/null +++ b/drivers/usb/gadget/function/f_ptp.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Gadget Function Driver for PTP + * + * Copyright (C) 2014 Google, Inc. + * Author: Badhri Jagan Sridharan + * + */ + +#include +#include + +#include +#include + +#include "f_mtp.h" + +static struct usb_function_instance *ptp_alloc_inst(void) +{ + return alloc_inst_mtp_ptp(false); +} + +static struct usb_function *ptp_alloc(struct usb_function_instance *fi) +{ + return function_alloc_mtp_ptp(fi, false); +} + +DECLARE_USB_FUNCTION_INIT(ptp, ptp_alloc_inst, ptp_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Badhri Jagan Sridharan"); diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 282737e4609c..ece613041fdb 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * f_sourcesink.c - USB peripheral source/sink configuration driver @@ -48,6 +51,11 @@ struct f_sourcesink { unsigned buflen; unsigned bulk_qlen; unsigned iso_qlen; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + unsigned bulk_maxburst; +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ }; static inline struct f_sourcesink *func_to_ss(struct usb_function *f) @@ -430,6 +438,16 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) (ss->isoc_mult + 1) * (ss->isoc_maxburst + 1); ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (ss->bulk_maxburst > 15) + ss->bulk_maxburst = 15; + + ss_source_comp_desc.bMaxBurst = ss->bulk_maxburst; + ss_sink_comp_desc.bMaxBurst = ss->bulk_maxburst; +#endif /* CONFIG_USB_PATCH_ON_RTK */ + +#endif /* MY_DEF_HERE */ ret = usb_assign_descriptors(f, fs_source_sink_descs, hs_source_sink_descs, ss_source_sink_descs, ss_source_sink_descs); @@ -855,6 +873,11 @@ static struct usb_function *source_sink_alloc_func( ss->buflen = ss_opts->bulk_buflen; ss->bulk_qlen = ss_opts->bulk_qlen; ss->iso_qlen = ss_opts->iso_qlen; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + ss->bulk_maxburst = ss_opts->bulk_maxburst; +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ ss->function.name = "source/sink"; ss->function.bind = sourcesink_bind; @@ -1215,6 +1238,53 @@ static ssize_t f_ss_opts_iso_qlen_store(struct config_item *item, CONFIGFS_ATTR(f_ss_opts_, iso_qlen); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +static ssize_t f_ss_opts_bulk_maxburst_show(struct config_item *item, char *page) +{ + struct f_ss_opts *opts = to_f_ss_opts(item); + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%u\n", opts->bulk_maxburst); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_bulk_maxburst_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_ss_opts *opts = to_f_ss_opts(item); + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + if (num > 15) { + ret = -EINVAL; + goto end; + } + + opts->bulk_maxburst = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +CONFIGFS_ATTR(f_ss_opts_, bulk_maxburst); +#endif /* CONFIG_USB_PATCH_ON_RTK */ + +#endif /* MY_DEF_HERE */ static struct configfs_attribute *ss_attrs[] = { &f_ss_opts_attr_pattern, &f_ss_opts_attr_isoc_interval, @@ -1224,6 +1294,11 @@ static struct configfs_attribute *ss_attrs[] = { &f_ss_opts_attr_bulk_buflen, &f_ss_opts_attr_bulk_qlen, &f_ss_opts_attr_iso_qlen, +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + &f_ss_opts_attr_bulk_maxburst, +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ NULL, }; diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h index 98b8462ad538..ddc1a60f99ad 100644 --- a/drivers/usb/gadget/function/g_zero.h +++ b/drivers/usb/gadget/function/g_zero.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * This header declares the utility functions used by "Gadget Zero", plus @@ -36,6 +39,11 @@ struct f_ss_opts { unsigned bulk_buflen; unsigned bulk_qlen; unsigned iso_qlen; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + unsigned bulk_maxburst; +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ /* * Read/write access to configfs attributes is handled by configfs. diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 1a12aab208b4..8ccd483ff079 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -258,6 +258,21 @@ config USB_MV_U3D MARVELL PXA2128 Processor series include a super speed USB3.0 device controller, which support super speed USB peripheral. +if SYNO_LSP_RTD1619B +config USB_RTK_UDC + tristate "RTK USB2.0 Device Controller" + depends on ARCH_RTD129x + help + RTD129x Soc include a high speed USB2.0 OTG controller, which can be + configured as high speed or full speed USB peripheral. + +config USB_RTK_UDC_OTG_SWITCH + tristate "RTK USB2.0 HOST/Device switch by sysfs" + depends on USB_RTK_UDC && ARCH_RTD129x + help + Use sysfs to switch RTK 129x SOC USB2.0 OTG controller. + +endif # SYNO_LSP_RTD1619B config USB_SNP_CORE depends on (USB_AMD5536UDC || USB_SNP_UDC_PLAT) depends on HAS_DMA diff --git a/drivers/usb/gadget/udc/rtk-hsotg.c b/drivers/usb/gadget/udc/rtk-hsotg.c new file mode 100644 index 000000000000..5646b59d3b45 --- /dev/null +++ b/drivers/usb/gadget/udc/rtk-hsotg.c @@ -0,0 +1,4077 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * rtk-hsotg.c + * + * RTK USB2.0 High-speed / OtG driver + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#include +#include +#include +#include + +#include "rtk-hsotg.h" + +#ifdef CONFIG_USB_PATCH_ON_RTK +#include + +static inline unsigned int otg_readl(void __iomem *reg) +{ + unsigned long flags; + u32 value; + + rtk_lockapi_lock(flags, __FUNCTION__); /* Add global lock for emmc issue*/ + + value = readl_relaxed(reg); + __iormb(); + + rtk_lockapi_unlock(flags,__FUNCTION__); /* Add global lock for emmc issue*/ + + return value; +} + +static inline void otg_writel(const unsigned int val, void __iomem *reg) +{ + unsigned long flags; + + rtk_lockapi_lock(flags, __FUNCTION__); /* Add global lock for emmc issue*/ + + writel_relaxed(val, reg); + __iormb(); + + rtk_lockapi_unlock(flags,__FUNCTION__); /* Add global lock for emmc issue*/ +} + +#undef readl +#define readl(addr) otg_readl(addr) +#undef writel +#define writel(val, addr) otg_writel(val, addr) + +#endif // CONFIG_USB_PATCH_ON_RTK + + +struct platform_device; +enum rtk_hsotg_dmamode { + RTK_HSOTG_DMA_NONE, /* do not use DMA at-all */ + RTK_HSOTG_DMA_ONLY, /* always use DMA */ + RTK_HSOTG_DMA_DRV, /* DMA is chosen by driver */ +}; + +/** + * struct rtk_hsotg_plat - platform data for high-speed otg/udc + * @dma: Whether to use DMA or not. + * @is_osc: The clock source is an oscillator, not a crystal + */ +struct rtk_hsotg_plat { + enum rtk_hsotg_dmamode dma; + unsigned int is_osc:1; + int phy_type; + + int (*phy_init)(struct platform_device *pdev, int type); + int (*phy_exit)(struct platform_device *pdev, int type); +}; + +extern void rtk_hsotg_set_platdata(struct rtk_hsotg_plat *pd); + +static const char * const rtk_hsotg_supply_names[] = { + "vusb_d", /* digital USB supply, 1.2V */ + "vusb_a", /* analog USB supply, 1.1V */ +}; + +/* + * EP0_MPS_LIMIT + * + * Unfortunately there seems to be a limit of the amount of data that can + * be transferred by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practically means 1 packet and 63 bytes of data) when the + * MPS is set to 64. + * + * This means if we are wanting to move >127 bytes of data, we need to + * split the transactions up, but just doing one packet at a time does + * not work (this may be an implicit DATA0 PID on first packet of the + * transaction) and doing 2 packets is outside the controller's limits. + * + * If we try to lower the MPS size for EP0, then no transfers work properly + * for EP0, and the system will fail basic enumeration. As no cause for this + * has currently been found, we cannot support any large IN transfers for + * EP0. + */ +#define EP0_MPS_LIMIT 64 + +struct rtk_hsotg; +struct rtk_hsotg_req; + +/** + * struct rtk_hsotg_ep - driver endpoint definition. + * @ep: The gadget layer representation of the endpoint. + * @name: The driver generated name for the endpoint. + * @queue: Queue of requests for this endpoint. + * @parent: Reference back to the parent device structure. + * @req: The current request that the endpoint is processing. This is + * used to indicate an request has been loaded onto the endpoint + * and has yet to be completed (maybe due to data move, or simply + * awaiting an ack from the core all the data has been completed). + * @debugfs: File entry for debugfs file for this endpoint. + * @lock: State lock to protect contents of endpoint. + * @dir_in: Set to true if this endpoint is of the IN direction, which + * means that it is sending data to the Host. + * @index: The index for the endpoint registers. + * @mc: Multi Count - number of transactions per microframe + * @interval - Interval for periodic endpoints + * @name: The name array passed to the USB core. + * @halted: Set if the endpoint has been halted. + * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep + * @sent_zlp: Set if we've sent a zero-length packet. + * @total_data: The total number of data bytes done. + * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_load: The amount of data loaded into the FIFO (periodic IN) + * @last_load: The offset of data for the last start of request. + * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * + * This is the driver's state for each registered enpoint, allowing it + * to keep track of transactions that need doing. Each endpoint has a + * lock to protect the state, to try and avoid using an overall lock + * for the host controller as much as possible. + * + * For periodic IN endpoints, we have fifo_size and fifo_load to try + * and keep track of the amount of data in the periodic FIFO for each + * of these as we don't have a status register that tells us how much + * is in each of them. (note, this may actually be useless information + * as in shared-fifo mode periodic in acts like a single-frame packet + * buffer than a fifo) + */ +struct rtk_hsotg_ep { + struct usb_ep ep; + struct list_head queue; + struct rtk_hsotg *parent; + struct rtk_hsotg_req *req; + struct dentry *debugfs; + + + unsigned long total_data; + unsigned int size_loaded; + unsigned int last_load; + unsigned int fifo_load; + unsigned short fifo_size; + + unsigned char dir_in; + unsigned char index; + unsigned char mc; + unsigned char interval; + + unsigned int halted:1; + unsigned int periodic:1; + unsigned int isochronous:1; + unsigned int sent_zlp:1; + + char name[10]; +}; + +/** + * struct rtk_hsotg - driver state. + * @dev: The parent device supplied to the probe function + * @driver: USB gadget driver + * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. + * @regs: The memory area mapped for accessing registers. + * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies + * @phyif: PHY interface width + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) + * @debug_root: root directrory for debugfs. + * @debug_file: main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset + * @eps: The endpoints being supplied to the gadget framework + */ +struct rtk_hsotg { + struct device *dev; + struct usb_gadget_driver *driver; + struct phy *phy; + struct usb_phy *uphy; + struct rtk_hsotg_plat *plat; + + spinlock_t lock; + + void __iomem *regs; + void __iomem *phyregs; + int irq; + struct clk *clk; + + struct regulator_bulk_data supplies[ARRAY_SIZE(rtk_hsotg_supply_names)]; + + u32 phyif; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; + + struct dentry *debug_root; + struct dentry *debug_file; + struct dentry *debug_fifo; + + struct usb_request *ep0_reply; + struct usb_request *ctrl_req; + u8 ep0_buff[8]; + u8 ctrl_buff[8]; + + struct usb_gadget gadget; + unsigned int setup; + unsigned long last_rst; + struct rtk_hsotg_ep *eps; + +#ifdef CONFIG_USB_RTK_UDC_OTG_SWITCH + int otg_type; +#define RTK_HOST_MODE 0 +#define RTK_DEVICE_MODE 1 +#endif //CONFIG_USB_RTK_UDC_OTG_SWITCH +}; + +/** + * struct rtk_hsotg_req - data transfer request + * @req: The USB gadget request + * @queue: The list of requests for the endpoint this is queued for. + * @in_progress: Has already had size/packets written to core + * @mapped: DMA buffer for this request has been mapped via dma_map_single(). + */ +struct rtk_hsotg_req { + struct usb_request req; + struct list_head queue; + unsigned char in_progress; + unsigned char mapped; +}; + +/* conversion functions */ +static inline struct rtk_hsotg_req *our_req(struct usb_request *req) +{ + return container_of(req, struct rtk_hsotg_req, req); +} + +static inline struct rtk_hsotg_ep *our_ep(struct usb_ep *ep) +{ + return container_of(ep, struct rtk_hsotg_ep, ep); +} + +static inline struct rtk_hsotg *to_hsotg(struct usb_gadget *gadget) +{ + return container_of(gadget, struct rtk_hsotg, gadget); +} + +static inline void __orr32(void __iomem *ptr, u32 val) +{ + writel(readl(ptr) | val, ptr); +} + +static inline void __bic32(void __iomem *ptr, u32 val) +{ + writel(readl(ptr) & ~val, ptr); +} + +/* forward decleration of functions */ +static void rtk_hsotg_dump(struct rtk_hsotg *hsotg); + +/** + * using_dma - return the DMA status of the driver. + * @hsotg: The driver state. + * + * Return true if we're using DMA. + * + * Currently, we have the DMA support code worked into everywhere + * that needs it, but the AMBA DMA implementation in the hardware can + * only DMA from 32bit aligned addresses. This means that gadgets such + * as the CDC Ethernet cannot work as they often pass packets which are + * not 32bit aligned. + * + * Unfortunately the choice to use DMA or not is global to the controller + * and seems to be only settable when the controller is being put through + * a core reset. This means we either need to fix the gadgets to take + * account of DMA alignment, or add bounce buffers (yuerk). + * + * Until this issue is sorted out, we always return 'false'. + */ +static inline bool using_dma(struct rtk_hsotg *hsotg) +{ + return false; /* support is not complete */ +} + +/** + * rtk_hsotg_en_gsint - enable one or more of the general interrupt + * @hsotg: The device state + * @ints: A bitmask of the interrupts to enable + */ +static void rtk_hsotg_en_gsint(struct rtk_hsotg *hsotg, u32 ints) +{ + u32 gsintmsk = readl(hsotg->regs + GINTMSK); + u32 new_gsintmsk; + + new_gsintmsk = gsintmsk | ints; + + if (new_gsintmsk != gsintmsk) { + dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); + writel(new_gsintmsk, hsotg->regs + GINTMSK); + } +} + +/** + * rtk_hsotg_disable_gsint - disable one or more of the general interrupt + * @hsotg: The device state + * @ints: A bitmask of the interrupts to enable + */ +static void rtk_hsotg_disable_gsint(struct rtk_hsotg *hsotg, u32 ints) +{ + u32 gsintmsk = readl(hsotg->regs + GINTMSK); + u32 new_gsintmsk; + + new_gsintmsk = gsintmsk & ~ints; + + if (new_gsintmsk != gsintmsk) + writel(new_gsintmsk, hsotg->regs + GINTMSK); +} + +/** + * rtk_hsotg_ctrl_epint - enable/disable an endpoint irq + * @hsotg: The device state + * @ep: The endpoint index + * @dir_in: True if direction is in. + * @en: The enable value, true to enable + * + * Set or clear the mask for an individual endpoint's interrupt + * request. + */ +static void rtk_hsotg_ctrl_epint(struct rtk_hsotg *hsotg, + unsigned int ep, unsigned int dir_in, + unsigned int en) +{ + unsigned long flags; + u32 bit = 1 << ep; + u32 daint; + + if (!dir_in) + bit <<= 16; + + local_irq_save(flags); + daint = readl(hsotg->regs + DAINTMSK); + if (en) + daint |= bit; + else + daint &= ~bit; + writel(daint, hsotg->regs + DAINTMSK); + local_irq_restore(flags); +} + +/** + * rtk_hsotg_init_fifo - initialise non-periodic FIFOs + * @hsotg: The device instance. + */ +static void rtk_hsotg_init_fifo(struct rtk_hsotg *hsotg) +{ + unsigned int ep; + unsigned int addr; + unsigned int size; + int timeout; + u32 val; + +#define FIFO_SZ 512 //2048 +#define FIFO_DEPTH 256 //1024 + /* set FIFO sizes to 512/256 2048/1024 */ + + writel(FIFO_SZ, hsotg->regs + GRXFSIZ); + writel(GNPTXFSIZ_NPTxFStAddr(FIFO_SZ) | + GNPTXFSIZ_NPTxFDep(FIFO_DEPTH), + hsotg->regs + GNPTXFSIZ); + + /* + * arange all the rest of the TX FIFOs, as some versions of this + * block have overlapping default addresses. This also ensures + * that if the settings have been changed, then they are set to + * known values. + */ + + /* start at the end of the GNPTXFSIZ, rounded up */ + addr = FIFO_SZ + FIFO_DEPTH; + size = 768; + + /* + * currently we allocate TX FIFOs for all possible endpoints, + * and assume that they are all the same size. + */ + + for (ep = 1; ep <= 15; ep++) { + val = addr; + val |= size << DPTXFSIZn_DPTxFSize_SHIFT; + addr += size; + + writel(val, hsotg->regs + DPTXFSIZn(ep)); + } + + /* + * according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing + */ + + writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh | + GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL); + + /* wait until the fifos are both flushed */ + timeout = 100; + while (1) { + val = readl(hsotg->regs + GRSTCTL); + + if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) + break; + + if (--timeout == 0) { + dev_err(hsotg->dev, + "%s: timeout flushing fifos (GRSTCTL=%08x)\n", + __func__, val); + } + + udelay(1); + } + + dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); +} + +/** + * @ep: USB endpoint to allocate request for. + * @flags: Allocation flags + * + * Allocate a new USB request structure appropriate for the specified endpoint + */ +static struct usb_request *rtk_hsotg_ep_alloc_request(struct usb_ep *ep, + gfp_t flags) +{ + struct rtk_hsotg_req *req; + + req = kzalloc(sizeof(struct rtk_hsotg_req), flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +/** + * is_ep_periodic - return true if the endpoint is in periodic mode. + * @hs_ep: The endpoint to query. + * + * Returns true if the endpoint is in periodic mode, meaning it is being + * used for an Interrupt or ISO transfer. + */ +static inline int is_ep_periodic(struct rtk_hsotg_ep *hs_ep) +{ + return hs_ep->periodic; +} + +/** + * rtk_hsotg_unmap_dma - unmap the DMA memory being used for the request + * @hsotg: The device state. + * @hs_ep: The endpoint for the request + * @hs_req: The request being processed. + * + * This is the reverse of rtk_hsotg_map_dma(), called for the completion + * of a request to ensure the buffer is ready for access by the caller. + */ +static void rtk_hsotg_unmap_dma(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep, + struct rtk_hsotg_req *hs_req) +{ + struct usb_request *req = &hs_req->req; + + /* ignore this if we're not moving any data */ + if (hs_req->req.length == 0) + return; + + usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); +} + +/** + * rtk_hsotg_write_fifo - write packet Data to the TxFIFO + * @hsotg: The controller state. + * @hs_ep: The endpoint we're going to write for. + * @hs_req: The request to write data for. + * + * This is called when the TxFIFO has some space in it to hold a new + * transmission and we have something to give it. The actual setup of + * the data size is done elsewhere, so all we have to do is to actually + * write the data. + * + * The return value is zero if there is more space (or nothing was done) + * otherwise -ENOSPC is returned if the FIFO space was used up. + * + * This routine is only needed for PIO + */ +static int rtk_hsotg_write_fifo(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep, + struct rtk_hsotg_req *hs_req) +{ + bool periodic = is_ep_periodic(hs_ep); + u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); + int buf_pos = hs_req->req.actual; + int to_write = hs_ep->size_loaded; + void *data; + int can_write; + int pkt_round; + int max_transfer; + + to_write -= (buf_pos - hs_ep->last_load); + + /* if there's nothing to write, get out early */ + if (to_write == 0) + return 0; + + if (periodic && !hsotg->dedicated_fifos) { + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); + int size_left; + int size_done; + + /* + * work out how much data was loaded so we can calculate + * how much data is left in the fifo. + */ + + size_left = DxEPTSIZ_XferSize_GET(epsize); + + /* + * if shared fifo, we cannot write anything until the + * previous data has been completely sent. + */ + if (hs_ep->fifo_load != 0) { + rtk_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); + return -ENOSPC; + } + + dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", + __func__, size_left, + hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); + + /* how much of the data has moved */ + size_done = hs_ep->size_loaded - size_left; + + /* how much data is left in the fifo */ + can_write = hs_ep->fifo_load - size_done; + dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", + __func__, can_write); + + can_write = hs_ep->fifo_size - can_write; + dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", + __func__, can_write); + + if (can_write <= 0) { + rtk_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); + return -ENOSPC; + } + } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { + can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); + + can_write &= 0xffff; + can_write *= 4; + } else { + if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { + dev_dbg(hsotg->dev, + "%s: no queue slots available (0x%08x)\n", + __func__, gnptxsts); + + rtk_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); + return -ENOSPC; + } + + can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); + can_write *= 4; /* fifo size is in 32bit quantities. */ + } + + max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; + + dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", + __func__, gnptxsts, can_write, to_write, max_transfer); + + /* + * limit to 512 bytes of data, it seems at least on the non-periodic + * FIFO, requests of >512 cause the endpoint to get stuck with a + * fragment of the end of the transfer in it. + */ + if (can_write > 512 && !periodic) + can_write = 512; + + /* + * limit the write to one max-packet size worth of data, but allow + * the transfer to return that it did not run out of fifo space + * doing it. + */ + if (to_write > max_transfer) { + to_write = max_transfer; + + /* it's needed only when we do not use dedicated fifos */ + if (!hsotg->dedicated_fifos) + rtk_hsotg_en_gsint(hsotg, + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); + } + + /* see if we can write data */ + + if (to_write > can_write) { + to_write = can_write; + pkt_round = to_write % max_transfer; + + /* + * Round the write down to an + * exact number of packets. + * + * Note, we do not currently check to see if we can ever + * write a full packet or not to the FIFO. + */ + + if (pkt_round) + to_write -= pkt_round; + + /* + * enable correct FIFO interrupt to alert us when there + * is more room left. + */ + + /* it's needed only when we do not use dedicated fifos */ + if (!hsotg->dedicated_fifos) + rtk_hsotg_en_gsint(hsotg, + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); + } + + dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", + to_write, hs_req->req.length, can_write, buf_pos); + + if (to_write <= 0) + return -ENOSPC; + + hs_req->req.actual = buf_pos + to_write; + hs_ep->total_data += to_write; + + if (periodic) + hs_ep->fifo_load += to_write; + + to_write = DIV_ROUND_UP(to_write, 4); + data = hs_req->req.buf + buf_pos; + + iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); + + return (to_write >= can_write) ? -ENOSPC : 0; +} + +/** + * get_ep_limit - get the maximum data legnth for this endpoint + * @hs_ep: The endpoint + * + * Return the maximum data that can be queued in one go on a given endpoint + * so that transfers that are too long can be split. + */ +static unsigned get_ep_limit(struct rtk_hsotg_ep *hs_ep) +{ + int index = hs_ep->index; + unsigned maxsize; + unsigned maxpkt; + + if (index != 0) { + maxsize = DxEPTSIZ_XferSize_LIMIT + 1; + maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; + } else { + maxsize = 64+64; + if (hs_ep->dir_in) + maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; + else + maxpkt = 2; + } + + /* we made the constant loading easier above by using +1 */ + maxpkt--; + maxsize--; + + /* + * constrain by packet count if maxpkts*pktsize is greater + * than the length register size. + */ + + if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) + maxsize = maxpkt * hs_ep->ep.maxpacket; + + return maxsize; +} + +/** + * rtk_hsotg_start_req - start a USB request from an endpoint's queue + * @hsotg: The controller state. + * @hs_ep: The endpoint to process a request for + * @hs_req: The request to start. + * @continuing: True if we are doing more for the current request. + * + * Start the given request running by setting the endpoint registers + * appropriately, and writing any data to the FIFOs. + */ +static void rtk_hsotg_start_req(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep, + struct rtk_hsotg_req *hs_req, + bool continuing) +{ + struct usb_request *ureq = &hs_req->req; + int index = hs_ep->index; + int dir_in = hs_ep->dir_in; + u32 epctrl_reg; + u32 epsize_reg; + u32 epsize; + u32 ctrl; + unsigned length; + unsigned packets; + unsigned maxreq; + + if (index != 0) { + if (hs_ep->req && !continuing) { + dev_err(hsotg->dev, "%s: active request\n", __func__); + WARN_ON(1); + return; + } else if (hs_ep->req != hs_req && continuing) { + dev_err(hsotg->dev, + "%s: continue different req\n", __func__); + WARN_ON(1); + return; + } + } + + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", + __func__, readl(hsotg->regs + epctrl_reg), index, + hs_ep->dir_in ? "in" : "out"); + + /* If endpoint is stalled, we will restart request later */ + ctrl = readl(hsotg->regs + epctrl_reg); + + if (ctrl & DxEPCTL_Stall) { + dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); + return; + } + + length = ureq->length - ureq->actual; + dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", + ureq->length, ureq->actual); + if (0) + dev_dbg(hsotg->dev, + "REQ buf %p len %d dma 0x%pad noi=%d zp=%d snok=%d\n", + ureq->buf, length, &ureq->dma, + ureq->no_interrupt, ureq->zero, ureq->short_not_ok); + + maxreq = get_ep_limit(hs_ep); + if (length > maxreq) { + int round = maxreq % hs_ep->ep.maxpacket; + + dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", + __func__, length, maxreq, round); + + /* round down to multiple of packets */ + if (round) + maxreq -= round; + + length = maxreq; + } + + if (length) + packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); + else + packets = 1; /* send one packet if length is zero. */ + + if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { + dev_err(hsotg->dev, "req length > maxpacket*mc\n"); + return; + } + + if (dir_in && index != 0) + if (hs_ep->isochronous) + epsize = DxEPTSIZ_MC(packets); + else + epsize = DxEPTSIZ_MC(1); + else + epsize = 0; + + if (index != 0 && ureq->zero) { + /* + * test for the packets being exactly right for the + * transfer + */ + + if (length == (packets * hs_ep->ep.maxpacket)) + packets++; + } + + epsize |= DxEPTSIZ_PktCnt(packets); + epsize |= DxEPTSIZ_XferSize(length); + + dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", + __func__, packets, length, ureq->length, epsize, epsize_reg); + + /* store the request as the current one we're doing */ + hs_ep->req = hs_req; + + /* write size / packets */ + writel(epsize, hsotg->regs + epsize_reg); + + if (using_dma(hsotg) && !continuing) { + unsigned int dma_reg; + + /* + * write DMA address to control register, buffer already + * synced by rtk_hsotg_ep_queue(). + */ + + dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); + writel(ureq->dma, hsotg->regs + dma_reg); + + dev_dbg(hsotg->dev, "%s: 0x%pad => 0x%08x\n", + __func__, &ureq->dma, dma_reg); + } + + ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= DxEPCTL_USBActEp; + + dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); + + /* For Setup request do not clear NAK */ +#if 0 //barry + if (hsotg->setup && index == 0) + hsotg->setup = 0; + else +#endif + ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); + writel(ctrl, hsotg->regs + epctrl_reg); + + /* + * set these, it seems that DMA support increments past the end + * of the packet buffer so we need to calculate the length from + * this information. + */ + hs_ep->size_loaded = length; + hs_ep->last_load = ureq->actual; + + if (dir_in && !using_dma(hsotg)) { + /* set these anyway, we may need them for non-periodic in */ + hs_ep->fifo_load = 0; + + rtk_hsotg_write_fifo(hsotg, hs_ep, hs_req); + } + + /* + * clear the INTknTXFEmpMsk when we start request, more as a aide + * to debugging to see what is going on. + */ + if (dir_in) + writel(DIEPMSK_INTknTXFEmpMsk, + hsotg->regs + DIEPINT(index)); + + /* check ep is enabled */ + if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) + dev_warn(hsotg->dev, + "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", + index, readl(hsotg->regs + epctrl_reg)); + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", + __func__, readl(hsotg->regs + epctrl_reg)); + + /* enable ep interrupts */ + rtk_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); +} + +/** + * rtk_hsotg_map_dma - map the DMA memory being used for the request + * @hsotg: The device state. + * @hs_ep: The endpoint the request is on. + * @req: The request being processed. + * + * We've been asked to queue a request, so ensure that the memory buffer + * is correctly setup for DMA. If we've been passed an extant DMA address + * then ensure the buffer has been synced to memory. If our buffer has no + * DMA memory, then we map the memory and mark our request to allow us to + * cleanup on completion. + */ +static int rtk_hsotg_map_dma(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep, + struct usb_request *req) +{ + struct rtk_hsotg_req *hs_req = our_req(req); + int ret; + + /* if the length is zero, ignore the DMA data */ + if (hs_req->req.length == 0) + return 0; + + ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); + if (ret) + goto dma_error; + + return 0; + +dma_error: + dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", + __func__, req->buf, req->length); + + return -EIO; +} + +static int rtk_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags) +{ + struct rtk_hsotg_req *hs_req = our_req(req); + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hs = hs_ep->parent; + bool first; + + dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", + ep->name, req, req->length, req->buf, req->no_interrupt, + req->zero, req->short_not_ok); + + /* initialise status of the request */ + INIT_LIST_HEAD(&hs_req->queue); + req->actual = 0; + req->status = -EINPROGRESS; + + /* if we're using DMA, sync the buffers as necessary */ + if (using_dma(hs)) { + int ret = rtk_hsotg_map_dma(hs, hs_ep, req); + if (ret) + return ret; + } + + first = list_empty(&hs_ep->queue); + list_add_tail(&hs_req->queue, &hs_ep->queue); + + if (first) + rtk_hsotg_start_req(hs, hs_ep, hs_req, false); + + return 0; +} + +static int rtk_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hs = hs_ep->parent; + unsigned long flags = 0; + int ret = 0; + + spin_lock_irqsave(&hs->lock, flags); + ret = rtk_hsotg_ep_queue(ep, req, gfp_flags); + spin_unlock_irqrestore(&hs->lock, flags); + + return ret; +} + +static void rtk_hsotg_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + struct rtk_hsotg_req *hs_req = our_req(req); + + kfree(hs_req); +} + +/** + * rtk_hsotg_complete_oursetup - setup completion callback + * @ep: The endpoint the request was on. + * @req: The request completed. + * + * Called on completion of any requests the driver itself + * submitted that need cleaning up. + */ +static void rtk_hsotg_complete_oursetup(struct usb_ep *ep, + struct usb_request *req) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hsotg = hs_ep->parent; + + dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); + + rtk_hsotg_ep_free_request(ep, req); +} + +/** + * ep_from_windex - convert control wIndex value to endpoint + * @hsotg: The driver state. + * @windex: The control request wIndex field (in host order). + * + * Convert the given wIndex into a pointer to an driver endpoint + * structure, or return NULL if it is not a valid endpoint. + */ +static struct rtk_hsotg_ep *ep_from_windex(struct rtk_hsotg *hsotg, + u32 windex) +{ + struct rtk_hsotg_ep *ep = &hsotg->eps[windex & 0x7F]; + int dir = (windex & USB_DIR_IN) ? 1 : 0; + int idx = windex & 0x7F; + + if (windex >= 0x100) + return NULL; + + if (idx > hsotg->num_of_eps) + return NULL; + + if (idx && ep->dir_in != dir) + return NULL; + + return ep; +} + +/** + * rtk_hsotg_send_reply - send reply to control request + * @hsotg: The device state + * @ep: Endpoint 0 + * @buff: Buffer for request + * @length: Length of reply. + * + * Create a request and queue it on the given endpoint. This is useful as + * an internal method of sending replies to certain control requests, etc. + */ +static int rtk_hsotg_send_reply(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *ep, + void *buff, + int length) +{ + struct usb_request *req; + int ret; + + dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); + + req = rtk_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); + hsotg->ep0_reply = req; + if (!req) { + dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); + return -ENOMEM; + } + + req->buf = hsotg->ep0_buff; + req->length = length; + req->zero = 1; /* always do zero-length final transfer */ + req->complete = rtk_hsotg_complete_oursetup; + + if (length) + memcpy(req->buf, buff, length); + else + ep->sent_zlp = 1; + + ret = rtk_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); + if (ret) { + dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); + return ret; + } + + return 0; +} + +/** + * rtk_hsotg_process_req_status - process request GET_STATUS + * @hsotg: The device state + * @ctrl: USB control request + */ +static int rtk_hsotg_process_req_status(struct rtk_hsotg *hsotg, + struct usb_ctrlrequest *ctrl) +{ + struct rtk_hsotg_ep *ep0 = &hsotg->eps[0]; + struct rtk_hsotg_ep *ep; + __le16 reply; + int ret; + + dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); + + if (!ep0->dir_in) { + dev_warn(hsotg->dev, "%s: direction out?\n", __func__); + return -EINVAL; + } + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + reply = cpu_to_le16(0); /* bit 0 => self powered, + * bit 1 => remote wakeup */ + break; + + case USB_RECIP_INTERFACE: + /* currently, the data result should be zero */ + reply = cpu_to_le16(0); + break; + + case USB_RECIP_ENDPOINT: + ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); + if (!ep) + return -ENOENT; + + reply = cpu_to_le16(ep->halted ? 1 : 0); + break; + + default: + return 0; + } + + if (le16_to_cpu(ctrl->wLength) != 2) + return -EINVAL; + + ret = rtk_hsotg_send_reply(hsotg, ep0, &reply, 2); + if (ret) { + dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); + return ret; + } + + return 1; +} + +static int rtk_hsotg_ep_sethalt(struct usb_ep *ep, int value); + +/** + * get_ep_head - return the first request on the endpoint + * @hs_ep: The controller endpoint to get + * + * Get the first request on the endpoint. + */ +static struct rtk_hsotg_req *get_ep_head(struct rtk_hsotg_ep *hs_ep) +{ + if (list_empty(&hs_ep->queue)) + return NULL; + + return list_first_entry(&hs_ep->queue, struct rtk_hsotg_req, queue); +} + +/** + * rtk_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE + * @hsotg: The device state + * @ctrl: USB control request + */ +static int rtk_hsotg_process_req_feature(struct rtk_hsotg *hsotg, + struct usb_ctrlrequest *ctrl) +{ + struct rtk_hsotg_ep *ep0 = &hsotg->eps[0]; + struct rtk_hsotg_req *hs_req; + bool restart; + bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); + struct rtk_hsotg_ep *ep; + int ret; + bool halted; + + dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", + __func__, set ? "SET" : "CLEAR"); + + if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { + ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); + if (!ep) { + dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", + __func__, le16_to_cpu(ctrl->wIndex)); + return -ENOENT; + } + + switch (le16_to_cpu(ctrl->wValue)) { + case USB_ENDPOINT_HALT: + halted = ep->halted; + + rtk_hsotg_ep_sethalt(&ep->ep, set); + + ret = rtk_hsotg_send_reply(hsotg, ep0, NULL, 0); + if (ret) { + dev_err(hsotg->dev, + "%s: failed to send reply\n", __func__); + return ret; + } + + /* + * we have to complete all requests for ep if it was + * halted, and the halt was cleared by CLEAR_FEATURE + */ + + if (!set && halted) { + /* + * If we have request in progress, + * then complete it + */ + if (ep->req) { + hs_req = ep->req; + ep->req = NULL; + list_del_init(&hs_req->queue); + hs_req->req.complete(&ep->ep, + &hs_req->req); + } + + /* If we have pending request, then start it */ + restart = !list_empty(&ep->queue); + if (restart) { + hs_req = get_ep_head(ep); + rtk_hsotg_start_req(hsotg, ep, + hs_req, false); + } + } + + break; + + default: + return -ENOENT; + } + } else + return -ENOENT; /* currently only deal with endpoint */ + + return 1; +} + +static void rtk_hsotg_enqueue_setup(struct rtk_hsotg *hsotg); +static void rtk_hsotg_disconnect(struct rtk_hsotg *hsotg); + +/** + * rtk_hsotg_stall_ep0 - stall ep0 + * @hsotg: The device state + * + * Set stall for ep0 as response for setup request. + */ +static void rtk_hsotg_stall_ep0(struct rtk_hsotg *hsotg) { + struct rtk_hsotg_ep *ep0 = &hsotg->eps[0]; + u32 reg; + u32 ctrl; + + dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); + reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; + + /* + * DxEPCTL_Stall will be cleared by EP once it has + * taken effect, so no need to clear later. + */ + + ctrl = readl(hsotg->regs + reg); + ctrl |= DxEPCTL_Stall; + ctrl |= DxEPCTL_CNAK; + writel(ctrl, hsotg->regs + reg); + + dev_dbg(hsotg->dev, + "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", + ctrl, reg, readl(hsotg->regs + reg)); + + /* + * complete won't be called, so we enqueue + * setup request here + */ + rtk_hsotg_enqueue_setup(hsotg); +} + +/** + * rtk_hsotg_process_control - process a control request + * @hsotg: The device state + * @ctrl: The control request received + * + * The controller has received the SETUP phase of a control request, and + * needs to work out what to do next (and whether to pass it on to the + * gadget driver). + */ +static void rtk_hsotg_process_control(struct rtk_hsotg *hsotg, + struct usb_ctrlrequest *ctrl) +{ + struct rtk_hsotg_ep *ep0 = &hsotg->eps[0]; + int ret = 0; + u32 dcfg; + + ep0->sent_zlp = 0; + + dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n", + ctrl->bRequest, ctrl->bRequestType, + ctrl->wValue, ctrl->wLength); + + /* + * record the direction of the request, for later use when enquing + * packets onto EP0. + */ + + ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; + dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); + + /* + * if we've no data with this request, then the last part of the + * transaction is going to implicitly be IN. + */ + if (ctrl->wLength == 0) + ep0->dir_in = 1; + + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (ctrl->bRequest) { + case USB_REQ_SET_ADDRESS: + rtk_hsotg_disconnect(hsotg); + dcfg = readl(hsotg->regs + DCFG); + dcfg &= ~DCFG_DevAddr_MASK; + dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; + writel(dcfg, hsotg->regs + DCFG); + + dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); + + ret = rtk_hsotg_send_reply(hsotg, ep0, NULL, 0); + return; + + case USB_REQ_GET_STATUS: + ret = rtk_hsotg_process_req_status(hsotg, ctrl); + break; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + ret = rtk_hsotg_process_req_feature(hsotg, ctrl); + break; + } + } + + /* as a fallback, try delivering it to the driver to deal with */ + + if (ret == 0 && hsotg->driver) { + spin_unlock(&hsotg->lock); + ret = hsotg->driver->setup(&hsotg->gadget, ctrl); + spin_lock(&hsotg->lock); + if (ret < 0) + dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); + } + + /* + * the request is either unhandlable, or is not formatted correctly + * so respond with a STALL for the status stage to indicate failure. + */ + + if (ret < 0) + rtk_hsotg_stall_ep0(hsotg); +} + +/** + * rtk_hsotg_complete_setup - completion of a setup transfer + * @ep: The endpoint the request was on. + * @req: The request completed. + * + * Called on completion of any requests the driver itself submitted for + * EP0 setup packets + */ +static void rtk_hsotg_complete_setup(struct usb_ep *ep, + struct usb_request *req) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hsotg = hs_ep->parent; + + if (req->status < 0) { + dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); + return; + } + + spin_lock(&hsotg->lock); + if (req->actual == 0) + rtk_hsotg_enqueue_setup(hsotg); + else + rtk_hsotg_process_control(hsotg, req->buf); + spin_unlock(&hsotg->lock); +} + +/** + * rtk_hsotg_enqueue_setup - start a request for EP0 packets + * @hsotg: The device state. + * + * Enqueue a request on EP0 if necessary to received any SETUP packets + * received from the host. + */ +static void rtk_hsotg_enqueue_setup(struct rtk_hsotg *hsotg) +{ + struct usb_request *req = hsotg->ctrl_req; + struct rtk_hsotg_req *hs_req = our_req(req); + int ret; + + dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); + + req->zero = 0; + req->length = 8; + req->buf = hsotg->ctrl_buff; + req->complete = rtk_hsotg_complete_setup; + + if (!list_empty(&hs_req->queue)) { + dev_dbg(hsotg->dev, "%s already queued???\n", __func__); + return; + } + + hsotg->eps[0].dir_in = 0; + + ret = rtk_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); + if (ret < 0) { + dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); + /* + * Don't think there's much we can do other than watch the + * driver fail. + */ + } +} + +/** + * rtk_hsotg_complete_request - complete a request given to us + * @hsotg: The device state. + * @hs_ep: The endpoint the request was on. + * @hs_req: The request to complete. + * @result: The result code (0 => Ok, otherwise errno) + * + * The given request has finished, so call the necessary completion + * if it has one and then look to see if we can start a new request + * on the endpoint. + * + * Note, expects the ep to already be locked as appropriate. + */ +static void rtk_hsotg_complete_request(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep, + struct rtk_hsotg_req *hs_req, + int result) +{ + bool restart; + + if (!hs_req) { + dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); + return; + } + + dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", + hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); + + /* + * only replace the status if we've not already set an error + * from a previous transaction + */ + + if (hs_req->req.status == -EINPROGRESS) + hs_req->req.status = result; + + hs_ep->req = NULL; + list_del_init(&hs_req->queue); + + if (using_dma(hsotg)) + rtk_hsotg_unmap_dma(hsotg, hs_ep, hs_req); + + /* + * call the complete request with the locks off, just in case the + * request tries to queue more work for this endpoint. + */ + + if (hs_req->req.complete) { + spin_unlock(&hsotg->lock); + hs_req->req.complete(&hs_ep->ep, &hs_req->req); + spin_lock(&hsotg->lock); + } + + /* + * Look to see if there is anything else to do. Note, the completion + * of the previous request may have caused a new request to be started + * so be careful when doing this. + */ + + if (!hs_ep->req && result >= 0) { + restart = !list_empty(&hs_ep->queue); + if (restart) { + hs_req = get_ep_head(hs_ep); + rtk_hsotg_start_req(hsotg, hs_ep, hs_req, false); + } + } +} + +/** + * rtk_hsotg_rx_data - receive data from the FIFO for an endpoint + * @hsotg: The device state. + * @ep_idx: The endpoint index for the data + * @size: The size of data in the fifo, in bytes + * + * The FIFO status shows there is data to read from the FIFO for a given + * endpoint, so sort out whether we need to read the data into a request + * that has been made for that endpoint. + */ +static void rtk_hsotg_rx_data(struct rtk_hsotg *hsotg, int ep_idx, int size) +{ + struct rtk_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; + struct rtk_hsotg_req *hs_req = hs_ep->req; + void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); + int to_read; + int max_req; + int read_ptr; + + + if (!hs_req) { + u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); + int ptr; + + dev_warn(hsotg->dev, + "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", + __func__, size, ep_idx, epctl); + + /* dump the data from the FIFO, we've nothing we can do */ + for (ptr = 0; ptr < size; ptr += 4) + (void)readl(fifo); + + return; + } + + to_read = size; + read_ptr = hs_req->req.actual; + max_req = hs_req->req.length - read_ptr; + + dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", + __func__, to_read, max_req, read_ptr, hs_req->req.length); + + if (to_read > max_req) { + /* + * more data appeared than we where willing + * to deal with in this request. + */ + + /* currently we don't deal this */ + WARN_ON_ONCE(1); + } + + hs_ep->total_data += to_read; + hs_req->req.actual += to_read; + to_read = DIV_ROUND_UP(to_read, 4); + + /* + * note, we might over-write the buffer end by 3 bytes depending on + * alignment of the data. + */ + ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); +} + +/** + * rtk_hsotg_send_zlp - send zero-length packet on control endpoint + * @hsotg: The device instance + * @req: The request currently on this endpoint + * + * Generate a zero-length IN packet request for terminating a SETUP + * transaction. + * + * Note, since we don't write any data to the TxFIFO, then it is + * currently believed that we do not need to wait for any space in + * the TxFIFO. + */ +static void rtk_hsotg_send_zlp(struct rtk_hsotg *hsotg, + struct rtk_hsotg_req *req) +{ + u32 ctrl; + + if (!req) { + dev_warn(hsotg->dev, "%s: no request?\n", __func__); + return; + } + + if (req->req.length == 0) { + hsotg->eps[0].sent_zlp = 1; + rtk_hsotg_enqueue_setup(hsotg); + return; + } + + hsotg->eps[0].dir_in = 1; + hsotg->eps[0].sent_zlp = 1; + + dev_dbg(hsotg->dev, "sending zero-length packet\n"); + + /* issue a zero-sized packet to terminate this */ + writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | + DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); + + ctrl = readl(hsotg->regs + DIEPCTL0); + ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= DxEPCTL_USBActEp; + writel(ctrl, hsotg->regs + DIEPCTL0); +} + +/** + * rtk_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO + * @hsotg: The device instance + * @epnum: The endpoint received from + * @was_setup: Set if processing a SetupDone event. + * + * The RXFIFO has delivered an OutDone event, which means that the data + * transfer for an OUT endpoint has been completed, either by a short + * packet or by the finish of a transfer. + */ +static void rtk_hsotg_handle_outdone(struct rtk_hsotg *hsotg, + int epnum, bool was_setup) +{ + u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); + struct rtk_hsotg_ep *hs_ep = &hsotg->eps[epnum]; + struct rtk_hsotg_req *hs_req = hs_ep->req; + struct usb_request *req = &hs_req->req; + unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); + int result = 0; + + if (!hs_req) { + dev_dbg(hsotg->dev, "%s: no request active\n", __func__); + return; + } + + if (using_dma(hsotg)) { + unsigned size_done; + + /* + * Calculate the size of the transfer by checking how much + * is left in the endpoint size register and then working it + * out from the amount we loaded for the transfer. + * + * We need to do this as DMA pointers are always 32bit aligned + * so may overshoot/undershoot the transfer. + */ + + size_done = hs_ep->size_loaded - size_left; + size_done += hs_ep->last_load; + + req->actual = size_done; + } + + /* if there is more request to do, schedule new transfer */ + if (req->actual < req->length && size_left == 0) { + rtk_hsotg_start_req(hsotg, hs_ep, hs_req, true); + return; + } else if (epnum == 0) { + /* + * After was_setup = 1 => + * set CNAK for non Setup requests + */ + hsotg->setup = was_setup ? 0 : 1; + } + + if (req->actual < req->length && req->short_not_ok) { + dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", + __func__, req->actual, req->length); + + /* + * todo - what should we return here? there's no one else + * even bothering to check the status. + */ + } + + if (epnum == 0) { + /* + * Condition req->complete != rtk_hsotg_complete_setup says: + * send ZLP when we have an asynchronous request from gadget + */ + if (!was_setup && req->complete != rtk_hsotg_complete_setup) + rtk_hsotg_send_zlp(hsotg, hs_req); + } + + rtk_hsotg_complete_request(hsotg, hs_ep, hs_req, result); +} + +/** + * rtk_hsotg_read_frameno - read current frame number + * @hsotg: The device instance + * + * Return the current frame number + */ +static u32 rtk_hsotg_read_frameno(struct rtk_hsotg *hsotg) +{ + u32 dsts; + + dsts = readl(hsotg->regs + DSTS); + dsts &= DSTS_SOFFN_MASK; + dsts >>= DSTS_SOFFN_SHIFT; + + return dsts; +} + +/** + * rtk_hsotg_handle_rx - RX FIFO has data + * @hsotg: The device instance + * + * The IRQ handler has detected that the RX FIFO has some data in it + * that requires processing, so find out what is in there and do the + * appropriate read. + * + * The RXFIFO is a true FIFO, the packets coming out are still in packet + * chunks, so if you have x packets received on an endpoint you'll get x + * FIFO events delivered, each with a packet's worth of data in it. + * + * When using DMA, we should not be processing events from the RXFIFO + * as the actual data should be sent to the memory directly and we turn + * on the completion interrupts to get notifications of transfer completion. + */ +static void rtk_hsotg_handle_rx(struct rtk_hsotg *hsotg) +{ + u32 grxstsr = readl(hsotg->regs + GRXSTSP); + u32 epnum, status, size; + + WARN_ON(using_dma(hsotg)); + + epnum = grxstsr & GRXSTS_EPNum_MASK; + status = grxstsr & GRXSTS_PktSts_MASK; + + size = grxstsr & GRXSTS_ByteCnt_MASK; + size >>= GRXSTS_ByteCnt_SHIFT; + + if (1) + dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", + __func__, grxstsr, size, epnum); + +#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) + + switch (status >> GRXSTS_PktSts_SHIFT) { + case __status(GRXSTS_PktSts_GlobalOutNAK): + dev_dbg(hsotg->dev, "GlobalOutNAK\n"); + break; + + case __status(GRXSTS_PktSts_OutDone): + dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", + rtk_hsotg_read_frameno(hsotg)); + + if (!using_dma(hsotg)) + rtk_hsotg_handle_outdone(hsotg, epnum, false); + break; + + case __status(GRXSTS_PktSts_SetupDone): + dev_dbg(hsotg->dev, + "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", + rtk_hsotg_read_frameno(hsotg), + readl(hsotg->regs + DOEPCTL(0))); + + rtk_hsotg_handle_outdone(hsotg, epnum, true); + break; + + case __status(GRXSTS_PktSts_OutRX): + rtk_hsotg_rx_data(hsotg, epnum, size); + break; + + case __status(GRXSTS_PktSts_SetupRX): + dev_dbg(hsotg->dev, + "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", + rtk_hsotg_read_frameno(hsotg), + readl(hsotg->regs + DOEPCTL(0))); + + rtk_hsotg_rx_data(hsotg, epnum, size); + break; + + default: + dev_warn(hsotg->dev, "%s: unknown status %08x\n", + __func__, grxstsr); + + rtk_hsotg_dump(hsotg); + break; + } +} + +/** + * rtk_hsotg_ep0_mps - turn max packet size into register setting + * @mps: The maximum packet size in bytes. + */ +static u32 rtk_hsotg_ep0_mps(unsigned int mps) +{ + switch (mps) { + case 64: + return D0EPCTL_MPS_64; + case 32: + return D0EPCTL_MPS_32; + case 16: + return D0EPCTL_MPS_16; + case 8: + return D0EPCTL_MPS_8; + } + + /* bad max packet size, warn and return invalid result */ + WARN_ON(1); + return (u32)-1; +} + +/** + * rtk_hsotg_set_ep_maxpacket - set endpoint's max-packet field + * @hsotg: The driver state. + * @ep: The index number of the endpoint + * @mps: The maximum packet size in bytes + * + * Configure the maximum packet size for the given endpoint, updating + * the hardware control registers to reflect this. + */ +static void rtk_hsotg_set_ep_maxpacket(struct rtk_hsotg *hsotg, + unsigned int ep, unsigned int mps) +{ + struct rtk_hsotg_ep *hs_ep = &hsotg->eps[ep]; + void __iomem *regs = hsotg->regs; + u32 mpsval; + u32 mcval; + u32 reg; + + if (ep == 0) { + /* EP0 is a special case */ + mpsval = rtk_hsotg_ep0_mps(mps); + if (mpsval > 3) + goto bad_mps; + hs_ep->ep.maxpacket = mps; + hs_ep->mc = 1; + } else { + mpsval = mps & DxEPCTL_MPS_MASK; + if (mpsval > 1024) + goto bad_mps; + mcval = ((mps >> 11) & 0x3) + 1; + hs_ep->mc = mcval; + if (mcval > 3) + goto bad_mps; + hs_ep->ep.maxpacket = mpsval; + } + + /* + * update both the in and out endpoint controldir_ registers, even + * if one of the directions may not be in use. + */ + + reg = readl(regs + DIEPCTL(ep)); + reg &= ~DxEPCTL_MPS_MASK; + reg |= mpsval; + writel(reg, regs + DIEPCTL(ep)); + + if (ep) { + reg = readl(regs + DOEPCTL(ep)); + reg &= ~DxEPCTL_MPS_MASK; + reg |= mpsval; + writel(reg, regs + DOEPCTL(ep)); + } + + return; + +bad_mps: + dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); +} + +/** + * rtk_hsotg_txfifo_flush - flush Tx FIFO + * @hsotg: The driver state + * @idx: The index for the endpoint (0..15) + */ +static void rtk_hsotg_txfifo_flush(struct rtk_hsotg *hsotg, unsigned int idx) +{ + int timeout; + int val; + + writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, + hsotg->regs + GRSTCTL); + + /* wait until the fifo is flushed */ + timeout = 100; + + while (1) { + val = readl(hsotg->regs + GRSTCTL); + + if ((val & (GRSTCTL_TxFFlsh)) == 0) + break; + + if (--timeout == 0) { + dev_err(hsotg->dev, + "%s: timeout flushing fifo (GRSTCTL=%08x)\n", + __func__, val); + } + + udelay(1); + } +} + +/** + * rtk_hsotg_trytx - check to see if anything needs transmitting + * @hsotg: The driver state + * @hs_ep: The driver endpoint to check. + * + * Check to see if there is a request that has data to send, and if so + * make an attempt to write data into the FIFO. + */ +static int rtk_hsotg_trytx(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep) +{ + struct rtk_hsotg_req *hs_req = hs_ep->req; + + if (!hs_ep->dir_in || !hs_req) { + /** + * if request is not enqueued, we disable interrupts + * for endpoints, excepting ep0 + */ + if (hs_ep->index != 0) + rtk_hsotg_ctrl_epint(hsotg, hs_ep->index, + hs_ep->dir_in, 0); + return 0; + } + + if (hs_req->req.actual < hs_req->req.length) { + dev_dbg(hsotg->dev, "trying to write more for ep%d\n", + hs_ep->index); + return rtk_hsotg_write_fifo(hsotg, hs_ep, hs_req); + } + + return 0; +} + +/** + * rtk_hsotg_complete_in - complete IN transfer + * @hsotg: The device state. + * @hs_ep: The endpoint that has just completed. + * + * An IN transfer has been completed, update the transfer's state and then + * call the relevant completion routines. + */ +static void rtk_hsotg_complete_in(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep) +{ + struct rtk_hsotg_req *hs_req = hs_ep->req; + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); + int size_left, size_done; + + if (!hs_req) { + dev_dbg(hsotg->dev, "XferCompl but no req\n"); + return; + } + + /* Finish ZLP handling for IN EP0 transactions */ + if (hsotg->eps[0].sent_zlp) { + dev_dbg(hsotg->dev, "zlp packet received\n"); + rtk_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); + return; + } + + /* + * Calculate the size of the transfer by checking how much is left + * in the endpoint size register and then working it out from + * the amount we loaded for the transfer. + * + * We do this even for DMA, as the transfer may have incremented + * past the end of the buffer (DMA transfers are always 32bit + * aligned). + */ + + size_left = DxEPTSIZ_XferSize_GET(epsize); + + size_done = hs_ep->size_loaded - size_left; + size_done += hs_ep->last_load; + + if (hs_req->req.actual != size_done) + dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", + __func__, hs_req->req.actual, size_done); + + hs_req->req.actual = size_done; + dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", + hs_req->req.length, hs_req->req.actual, hs_req->req.zero); + + /* + * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0 + * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B + * ,256B ... ), after last MPS sized packet send IN ZLP packet to + * inform the host that no more data is available. + * The state of req.zero member is checked to be sure that the value to + * send is smaller than wValue expected from host. + * Check req.length to NOT send another ZLP when the current one is + * under completion (the one for which this completion has been called). + */ + if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero && + hs_req->req.length == hs_req->req.actual && + !(hs_req->req.length % hs_ep->ep.maxpacket)) { + + dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n"); + rtk_hsotg_send_zlp(hsotg, hs_req); + + return; + } + + if (!size_left && hs_req->req.actual < hs_req->req.length) { + dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); + rtk_hsotg_start_req(hsotg, hs_ep, hs_req, true); + } else + rtk_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); +} + +/** + * rtk_hsotg_epint - handle an in/out endpoint interrupt + * @hsotg: The driver state + * @idx: The index for the endpoint (0..15) + * @dir_in: Set if this is an IN endpoint + * + * Process and clear any interrupt pending for an individual endpoint + */ +static void rtk_hsotg_epint(struct rtk_hsotg *hsotg, unsigned int idx, + int dir_in) +{ + struct rtk_hsotg_ep *hs_ep = &hsotg->eps[idx]; + u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); + u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); + u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); + u32 ints; + u32 ctrl; + + ints = readl(hsotg->regs + epint_reg); + ctrl = readl(hsotg->regs + epctl_reg); + + /* Clear endpoint interrupts */ + writel(ints, hsotg->regs + epint_reg); + + dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", + __func__, idx, dir_in ? "in" : "out", ints); + + if (ints & DxEPINT_XferCompl) { + if (hs_ep->isochronous && hs_ep->interval == 1) { + if (ctrl & DxEPCTL_EOFrNum) + ctrl |= DxEPCTL_SetEvenFr; + else + ctrl |= DxEPCTL_SetOddFr; + writel(ctrl, hsotg->regs + epctl_reg); + } + + dev_dbg(hsotg->dev, + "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", + __func__, readl(hsotg->regs + epctl_reg), + readl(hsotg->regs + epsiz_reg)); + + /* + * we get OutDone from the FIFO, so we only need to look + * at completing IN requests here + */ + if (dir_in) { + rtk_hsotg_complete_in(hsotg, hs_ep); + + if (idx == 0 && !hs_ep->req) + rtk_hsotg_enqueue_setup(hsotg); + } else if (using_dma(hsotg)) { + /* + * We're using DMA, we need to fire an OutDone here + * as we ignore the RXFIFO. + */ + + rtk_hsotg_handle_outdone(hsotg, idx, false); + } + } + + if (ints & DxEPINT_EPDisbld) { + dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); + + if (dir_in) { + int epctl = readl(hsotg->regs + epctl_reg); + + rtk_hsotg_txfifo_flush(hsotg, idx); + + if ((epctl & DxEPCTL_Stall) && + (epctl & DxEPCTL_EPType_Bulk)) { + int dctl = readl(hsotg->regs + DCTL); + + dctl |= DCTL_CGNPInNAK; + writel(dctl, hsotg->regs + DCTL); + } + } + } + + if (ints & DxEPINT_AHBErr) + dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); + + if (ints & DxEPINT_Setup) { /* Setup or Timeout */ + dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); + + if (using_dma(hsotg) && idx == 0) { + /* + * this is the notification we've received a + * setup packet. In non-DMA mode we'd get this + * from the RXFIFO, instead we need to process + * the setup here. + */ + + if (dir_in) + WARN_ON_ONCE(1); + else + rtk_hsotg_handle_outdone(hsotg, 0, true); + } + } + + if (ints & DxEPINT_Back2BackSetup) + dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); + + if (dir_in && !hs_ep->isochronous) { + /* not sure if this is important, but we'll clear it anyway */ + if (ints & DIEPMSK_INTknTXFEmpMsk) { + dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", + __func__, idx); + } + + /* this probably means something bad is happening */ + if (ints & DIEPMSK_INTknEPMisMsk) { + dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", + __func__, idx); + } + + /* FIFO has space or is empty (see GAHBCFG) */ + if (hsotg->dedicated_fifos && + ints & DIEPMSK_TxFIFOEmpty) { + dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", + __func__, idx); + if (!using_dma(hsotg)) + rtk_hsotg_trytx(hsotg, hs_ep); + } + } +} + +/** + * rtk_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) + * @hsotg: The device state. + * + * Handle updating the device settings after the enumeration phase has + * been completed. + */ +static void rtk_hsotg_irq_enumdone(struct rtk_hsotg *hsotg) +{ + u32 dsts = readl(hsotg->regs + DSTS); + int ep0_mps = 0, ep_mps; + + /* + * This should signal the finish of the enumeration phase + * of the USB handshaking, so we should now know what rate + * we connected at. + */ + + dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); + + /* + * note, since we're limited by the size of transfer on EP0, and + * it seems IN transfers must be a even number of packets we do + * not advertise a 64byte MPS on EP0. + */ + + /* catch both EnumSpd_FS and EnumSpd_FS48 */ + switch (dsts & DSTS_EnumSpd_MASK) { + case DSTS_EnumSpd_FS: + case DSTS_EnumSpd_FS48: + hsotg->gadget.speed = USB_SPEED_FULL; + ep0_mps = EP0_MPS_LIMIT; + ep_mps = 1023; + // ep_mps = 64; //barry + break; + + case DSTS_EnumSpd_HS: + hsotg->gadget.speed = USB_SPEED_HIGH; + ep0_mps = EP0_MPS_LIMIT; + ep_mps = 1024; + // ep_mps = 512; //barry + break; + + case DSTS_EnumSpd_LS: + hsotg->gadget.speed = USB_SPEED_LOW; + /* + * note, we don't actually support LS in this driver at the + * moment, and the documentation seems to imply that it isn't + * supported by the PHYs on some of the devices. + */ + break; + } + dev_info(hsotg->dev, "new device is %s\n", + usb_speed_string(hsotg->gadget.speed)); + + /* + * we should now know the maximum packet size for an + * endpoint, so set the endpoints to a default value. + */ + + if (ep0_mps) { + int i; + rtk_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); + for (i = 1; i < hsotg->num_of_eps; i++) + rtk_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); + } + + /* ensure after enumeration our EP0 is active */ + + rtk_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); +} + +/** + * kill_all_requests - remove all requests from the endpoint's queue + * @hsotg: The device state. + * @ep: The endpoint the requests may be on. + * @result: The result code to use. + * @force: Force removal of any current requests + * + * Go through the requests on the given endpoint and mark them + * completed with the given result code. + */ +static void kill_all_requests(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *ep, + int result, bool force) +{ + struct rtk_hsotg_req *req, *treq; + + list_for_each_entry_safe(req, treq, &ep->queue, queue) { + /* + * currently, we can't do much about an already + * running request on an in endpoint + */ + + if (ep->req == req && ep->dir_in && !force) + continue; + + rtk_hsotg_complete_request(hsotg, ep, req, + result); + } + if(hsotg->dedicated_fifos) + if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072) + rtk_hsotg_txfifo_flush(hsotg, ep->index); +} + +#define call_gadget(_hs, _entry) \ +do { \ + if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ + (_hs)->driver && (_hs)->driver->_entry) { \ + spin_unlock(&_hs->lock); \ + (_hs)->driver->_entry(&(_hs)->gadget); \ + spin_lock(&_hs->lock); \ + } \ +} while (0) + +/** + * rtk_hsotg_disconnect - disconnect service + * @hsotg: The device state. + * + * The device has been disconnected. Remove all current + * transactions and signal the gadget driver that this + * has happened. + */ +static void rtk_hsotg_disconnect(struct rtk_hsotg *hsotg) +{ + unsigned ep; + + for (ep = 0; ep < hsotg->num_of_eps; ep++) + kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); + + call_gadget(hsotg, disconnect); +} + +/** + * rtk_hsotg_irq_fifoempty - TX FIFO empty interrupt handler + * @hsotg: The device state: + * @periodic: True if this is a periodic FIFO interrupt + */ +static void rtk_hsotg_irq_fifoempty(struct rtk_hsotg *hsotg, bool periodic) +{ + struct rtk_hsotg_ep *ep; + int epno, ret; + + /* look through for any more data to transmit */ + + for (epno = 0; epno < hsotg->num_of_eps; epno++) { + ep = &hsotg->eps[epno]; + + if (!ep->dir_in) + continue; + + if ((periodic && !ep->periodic) || + (!periodic && ep->periodic)) + continue; + + ret = rtk_hsotg_trytx(hsotg, ep); + if (ret < 0) + break; + } +} + +/* IRQ flags which will trigger a retry around the IRQ loop */ +#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ + GINTSTS_PTxFEmp | \ + GINTSTS_RxFLvl) + +/** + * rtk_hsotg_corereset - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. + */ +static int rtk_hsotg_corereset(struct rtk_hsotg *hsotg) +{ + int timeout; + u32 grstctl; + + dev_dbg(hsotg->dev, "resetting core\n"); + + /* issue soft reset */ + writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); + + timeout = 10000; + do { + grstctl = readl(hsotg->regs + GRSTCTL); + } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); + + if (grstctl & GRSTCTL_CSftRst) { + dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); + return -EINVAL; + } + + timeout = 10000; + + while (1) { + u32 grstctl = readl(hsotg->regs + GRSTCTL); + + if (timeout-- < 0) { + dev_info(hsotg->dev, + "%s: reset failed, GRSTCTL=%08x\n", + __func__, grstctl); + return -ETIMEDOUT; + } + + if (!(grstctl & GRSTCTL_AHBIdle)) + continue; + + break; /* reset done */ + } + + dev_dbg(hsotg->dev, "reset successful\n"); + return 0; +} + +/** + * rtk_hsotg_core_init - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. + */ +static void rtk_hsotg_core_init(struct rtk_hsotg *hsotg) +{ + rtk_hsotg_corereset(hsotg); + + /* + * we must now enable ep0 ready for host detection and then + * set configuration. + */ + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(hsotg->phyif | GUSBCFG_TOutCal(7) | + (0x5 << 10), hsotg->regs + GUSBCFG); + mdelay(100); + + rtk_hsotg_init_fifo(hsotg); + + __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + + writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG); + + /* Clear any pending OTG interrupts */ + writel(0xffffffff, hsotg->regs + GOTGINT); + + /* Clear any pending interrupts */ + writel(0xffffffff, hsotg->regs + GINTSTS); + + writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt | + GINTSTS_GOUTNakEff | GINTSTS_GINNakEff | + GINTSTS_ConIDStsChng | GINTSTS_USBRst | + GINTSTS_EnumDone | GINTSTS_OTGInt | + GINTSTS_USBSusp | GINTSTS_WkUpInt, + hsotg->regs + GINTMSK); + + if (using_dma(hsotg)) + writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | + GAHBCFG_HBstLen_Incr4, + hsotg->regs + GAHBCFG); + else + writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NPTxFEmpLvl | + GAHBCFG_PTxFEmpLvl) : 0) | + GAHBCFG_GlblIntrEn, + hsotg->regs + GAHBCFG); + + /* + * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts + * when we have no data to transfer. Otherwise we get being flooded by + * interrupts. + */ + + writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty | + DIEPMSK_INTknTXFEmpMsk : 0) | + DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | + DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | + DIEPMSK_INTknEPMisMsk, + hsotg->regs + DIEPMSK); + + /* + * don't need XferCompl, we get that from RXFIFO in slave mode. In + * DMA mode we may need this. + */ + writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk | + DIEPMSK_TimeOUTMsk) : 0) | + DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk | + DOEPMSK_SetupMsk, + hsotg->regs + DOEPMSK); + + writel(0, hsotg->regs + DAINTMSK); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); + + /* enable in and out endpoint interrupts */ + rtk_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); + + /* + * Enable the RXFIFO when in slave mode, as this is how we collect + * the data. In DMA mode, we get events from the FIFO but also + * things we cannot process, so do not use it. + */ + if (!using_dma(hsotg)) + rtk_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl); + + /* Enable interrupts for EP0 in and out */ + rtk_hsotg_ctrl_epint(hsotg, 0, 0, 1); + rtk_hsotg_ctrl_epint(hsotg, 0, 1, 1); + + __orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + udelay(10); /* see openiboot */ + __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + + dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); + + /* + * DxEPCTL_USBActEp says RO in manual, but seems to be set by + * writing to the EPCTL register.. + */ + + /* set to read 1 8byte packet */ + writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | + DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); + + writel(rtk_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + DxEPCTL_CNAK | DxEPCTL_EPEna | + DxEPCTL_USBActEp, + hsotg->regs + DOEPCTL0); + + /* enable, but don't activate EP0in */ + writel(rtk_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); + + rtk_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); + + /* clear global NAKs */ + writel(DCTL_CGOUTNak | DCTL_CGNPInNAK, + hsotg->regs + DCTL); + + /* must be at-least 3ms to allow bus to see disconnect */ + mdelay(3); + + /* remove the soft-disconnect and let's go */ + __bic32(hsotg->regs + DCTL, DCTL_SftDiscon); +} + +/** + * rtk_hsotg_irq - handle device interrupt + * @irq: The IRQ number triggered + * @pw: The pw value when registered the handler. + */ +static irqreturn_t rtk_hsotg_irq(int irq, void *pw) +{ + struct rtk_hsotg *hsotg = pw; + int retry_count = 8; + u32 gintsts; + u32 gintmsk; + + spin_lock(&hsotg->lock); +irq_retry: + gintsts = readl(hsotg->regs + GINTSTS); + gintmsk = readl(hsotg->regs + GINTMSK); + + dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", + __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); + + gintsts &= gintmsk; + + if (gintsts & GINTSTS_OTGInt) { + u32 otgint = readl(hsotg->regs + GOTGINT); + + dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); + + writel(otgint, hsotg->regs + GOTGINT); + } + + if (gintsts & GINTSTS_SessReqInt) { + dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); + writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); + } + + if (gintsts & GINTSTS_EnumDone) { + writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); + + rtk_hsotg_irq_enumdone(hsotg); + } + + if (gintsts & GINTSTS_ConIDStsChng) { + dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", + readl(hsotg->regs + DSTS), + readl(hsotg->regs + GOTGCTL)); + + writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); + } + + if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { + u32 daint = readl(hsotg->regs + DAINT); + u32 daintmsk = readl(hsotg->regs + DAINTMSK); + u32 daint_out, daint_in; + int ep; + + daint &= daintmsk; + daint_out = daint >> DAINT_OutEP_SHIFT; + daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); + + dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); + + for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { + if (daint_out & 1) + rtk_hsotg_epint(hsotg, ep, 0); + } + + for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { + if (daint_in & 1) + rtk_hsotg_epint(hsotg, ep, 1); + } + } + + if (gintsts & GINTSTS_USBRst) { + + u32 usb_status = readl(hsotg->regs + GOTGCTL); + + dev_info(hsotg->dev, "%s: USBRst\n", __func__); + dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", + readl(hsotg->regs + GNPTXSTS)); + + writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); + + if (usb_status & GOTGCTL_BSESVLD) { + if (time_after(jiffies, hsotg->last_rst + + msecs_to_jiffies(200))) { + + kill_all_requests(hsotg, &hsotg->eps[0], + -ECONNRESET, true); + + rtk_hsotg_core_init(hsotg); + hsotg->last_rst = jiffies; + } + } + } + + /* check both FIFOs */ + + if (gintsts & GINTSTS_NPTxFEmp) { + dev_dbg(hsotg->dev, "NPTxFEmp\n"); + + /* + * Disable the interrupt to stop it happening again + * unless one of these endpoint routines decides that + * it needs re-enabling + */ + + rtk_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); + rtk_hsotg_irq_fifoempty(hsotg, false); + } + + if (gintsts & GINTSTS_PTxFEmp) { + dev_dbg(hsotg->dev, "PTxFEmp\n"); + + /* See note in GINTSTS_NPTxFEmp */ + + rtk_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); + rtk_hsotg_irq_fifoempty(hsotg, true); + } + + if (gintsts & GINTSTS_RxFLvl) { + /* + * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, + * we need to retry rtk_hsotg_handle_rx if this is still + * set. + */ + + rtk_hsotg_handle_rx(hsotg); + } + + if (gintsts & GINTSTS_ModeMis) { + dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); + writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); + } + + if (gintsts & GINTSTS_USBSusp) { + dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); + writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); + + call_gadget(hsotg, suspend); + } + + if (gintsts & GINTSTS_WkUpInt) { + dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); + writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); + + call_gadget(hsotg, resume); + } + + if (gintsts & GINTSTS_ErlySusp) { + dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); + writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); + } + + /* + * these next two seem to crop-up occasionally causing the core + * to shutdown the USB transfer, so try clearing them and logging + * the occurrence. + */ + + if (gintsts & GINTSTS_GOUTNakEff) { + dev_info(hsotg->dev, "GOUTNakEff triggered\n"); + + writel(DCTL_CGOUTNak, hsotg->regs + DCTL); + + rtk_hsotg_dump(hsotg); + } + + if (gintsts & GINTSTS_GINNakEff) { + dev_info(hsotg->dev, "GINNakEff triggered\n"); + + writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); + + rtk_hsotg_dump(hsotg); + } + + /* + * if we've had fifo events, we should try and go around the + * loop again to see if there's any point in returning yet. + */ + + if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) + goto irq_retry; + + spin_unlock(&hsotg->lock); + + return IRQ_HANDLED; +} + +/** + * rtk_hsotg_ep_enable - enable the given endpoint + * @ep: The USB endpint to configure + * @desc: The USB endpoint descriptor to configure with. + * + * This is called from the USB gadget code's usb_ep_enable(). + */ +static int rtk_hsotg_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hsotg = hs_ep->parent; + unsigned long flags; + int index = hs_ep->index; + u32 epctrl_reg; + u32 epctrl; + u32 mps; + int dir_in; + int ret = 0; + + dev_dbg(hsotg->dev, + "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", + __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, + desc->wMaxPacketSize, desc->bInterval); + + /* not to be called for EP0 */ + WARN_ON(index == 0); + + dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; + if (dir_in != hs_ep->dir_in) { + dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); + return -EINVAL; + } + + mps = usb_endpoint_maxp(desc); + + /* note, we handle this here instead of rtk_hsotg_set_ep_maxpacket */ + + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + epctrl = readl(hsotg->regs + epctrl_reg); + + dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", + __func__, epctrl, epctrl_reg); + + spin_lock_irqsave(&hsotg->lock, flags); + + epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK); + epctrl |= DxEPCTL_MPS(mps); + + /* + * mark the endpoint as active, otherwise the core may ignore + * transactions entirely for this endpoint + */ + epctrl |= DxEPCTL_USBActEp; + + /* + * set the NAK status on the endpoint, otherwise we might try and + * do something with data that we've yet got a request to process + * since the RXFIFO will take data for an endpoint even if the + * size register hasn't been set. + */ + + epctrl |= DxEPCTL_SNAK; + + /* update the endpoint state */ + rtk_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps); + + /* default, set to non-periodic */ + hs_ep->isochronous = 0; + hs_ep->periodic = 0; + hs_ep->halted = 0; + hs_ep->interval = desc->bInterval; + + if (hs_ep->interval > 1 && hs_ep->mc > 1) + dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_ISOC: + epctrl |= DxEPCTL_EPType_Iso; + epctrl |= DxEPCTL_SetEvenFr; + hs_ep->isochronous = 1; + if (dir_in) + hs_ep->periodic = 1; + break; + + case USB_ENDPOINT_XFER_BULK: + epctrl |= DxEPCTL_EPType_Bulk; + break; + + case USB_ENDPOINT_XFER_INT: + if (dir_in) { + /* + * Allocate our TxFNum by simply using the index + * of the endpoint for the moment. We could do + * something better if the host indicates how + * many FIFOs we are expecting to use. + */ + + hs_ep->periodic = 1; + epctrl |= DxEPCTL_TxFNum(index); + } + + epctrl |= DxEPCTL_EPType_Intterupt; + break; + + case USB_ENDPOINT_XFER_CONTROL: + epctrl |= DxEPCTL_EPType_Control; + break; + } + + /* + * if the hardware has dedicated fifos, we must give each IN EP + * a unique tx-fifo even if it is non-periodic. + */ + if (dir_in && hsotg->dedicated_fifos) + epctrl |= DxEPCTL_TxFNum(index); + + /* for non control endpoints, set PID to D0 */ + if (index) + epctrl |= DxEPCTL_SetD0PID; + + dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", + __func__, epctrl); + + writel(epctrl, hsotg->regs + epctrl_reg); + dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", + __func__, readl(hsotg->regs + epctrl_reg)); + + /* enable the endpoint interrupt */ + rtk_hsotg_ctrl_epint(hsotg, index, dir_in, 1); + + spin_unlock_irqrestore(&hsotg->lock, flags); + return ret; +} + +/** + * rtk_hsotg_ep_disable - disable given endpoint + * @ep: The endpoint to disable. + */ +static int rtk_hsotg_ep_disable(struct usb_ep *ep) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hsotg = hs_ep->parent; + int dir_in = hs_ep->dir_in; + int index = hs_ep->index; + unsigned long flags; + u32 epctrl_reg; + u32 ctrl; + + dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep); + + if (ep == &hsotg->eps[0].ep) { + dev_err(hsotg->dev, "%s: called for ep0\n", __func__); + return -EINVAL; + } + + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + + spin_lock_irqsave(&hsotg->lock, flags); + /* terminate all requests with shutdown */ + kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); + + + ctrl = readl(hsotg->regs + epctrl_reg); + ctrl &= ~DxEPCTL_EPEna; + ctrl &= ~DxEPCTL_USBActEp; + ctrl |= DxEPCTL_SNAK; + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); + writel(ctrl, hsotg->regs + epctrl_reg); + + /* disable endpoint interrupts */ + rtk_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); + + spin_unlock_irqrestore(&hsotg->lock, flags); + return 0; +} + +/** + * on_list - check request is on the given endpoint + * @ep: The endpoint to check. + * @test: The request to test if it is on the endpoint. + */ +static bool on_list(struct rtk_hsotg_ep *ep, struct rtk_hsotg_req *test) +{ + struct rtk_hsotg_req *req, *treq; + + list_for_each_entry_safe(req, treq, &ep->queue, queue) { + if (req == test) + return true; + } + + return false; +} + +/** + * rtk_hsotg_ep_dequeue - dequeue given endpoint + * @ep: The endpoint to dequeue. + * @req: The request to be removed from a queue. + */ +static int rtk_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + struct rtk_hsotg_req *hs_req = our_req(req); + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hs = hs_ep->parent; + unsigned long flags; + + dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); + + spin_lock_irqsave(&hs->lock, flags); + + if (!on_list(hs_ep, hs_req)) { + spin_unlock_irqrestore(&hs->lock, flags); + return -EINVAL; + } + + rtk_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); + spin_unlock_irqrestore(&hs->lock, flags); + + return 0; +} + +/** + * rtk_hsotg_ep_sethalt - set halt on a given endpoint + * @ep: The endpoint to set halt. + * @value: Set or unset the halt. + */ +static int rtk_hsotg_ep_sethalt(struct usb_ep *ep, int value) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hs = hs_ep->parent; + int index = hs_ep->index; + u32 epreg; + u32 epctl; + u32 xfertype; + + dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); + + if (index == 0) { + if (value) + rtk_hsotg_stall_ep0(hs); + else + dev_warn(hs->dev, + "%s: can't clear halt on ep0\n", __func__); + return 0; + } + + /* write both IN and OUT control registers */ + + epreg = DIEPCTL(index); + epctl = readl(hs->regs + epreg); + + if (value) { + epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; + if (epctl & DxEPCTL_EPEna) + epctl |= DxEPCTL_EPDis; + } else { + epctl &= ~DxEPCTL_Stall; + xfertype = epctl & DxEPCTL_EPType_MASK; + if (xfertype == DxEPCTL_EPType_Bulk || + xfertype == DxEPCTL_EPType_Intterupt) + epctl |= DxEPCTL_SetD0PID; + } + + writel(epctl, hs->regs + epreg); + + epreg = DOEPCTL(index); + epctl = readl(hs->regs + epreg); + + if (value) + epctl |= DxEPCTL_Stall; + else { + epctl &= ~DxEPCTL_Stall; + xfertype = epctl & DxEPCTL_EPType_MASK; + if (xfertype == DxEPCTL_EPType_Bulk || + xfertype == DxEPCTL_EPType_Intterupt) + epctl |= DxEPCTL_SetD0PID; + } + + writel(epctl, hs->regs + epreg); + + hs_ep->halted = value; + + return 0; +} + +/** + * rtk_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held + * @ep: The endpoint to set halt. + * @value: Set or unset the halt. + */ +static int rtk_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) +{ + struct rtk_hsotg_ep *hs_ep = our_ep(ep); + struct rtk_hsotg *hs = hs_ep->parent; + unsigned long flags = 0; + int ret = 0; + + spin_lock_irqsave(&hs->lock, flags); + ret = rtk_hsotg_ep_sethalt(ep, value); + spin_unlock_irqrestore(&hs->lock, flags); + + return ret; +} + +static struct usb_ep_ops rtk_hsotg_ep_ops = { + .enable = rtk_hsotg_ep_enable, + .disable = rtk_hsotg_ep_disable, + .alloc_request = rtk_hsotg_ep_alloc_request, + .free_request = rtk_hsotg_ep_free_request, + .queue = rtk_hsotg_ep_queue_lock, + .dequeue = rtk_hsotg_ep_dequeue, + .set_halt = rtk_hsotg_ep_sethalt_lock, + /* note, don't believe we have any call for the fifo routines */ +}; + +/** + * rtk_hsotg_phy_enable - enable platform phy dev + * @hsotg: The driver state + * + * A wrapper for platform code responsible for controlling + * low-level USB code + */ +static void rtk_hsotg_phy_enable(struct rtk_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); + + if(hsotg->phyregs) { + writel(readl(hsotg->phyregs+0xc)|BIT(0), hsotg->phyregs+0xc); + mdelay(100); + writel(readl(hsotg->phyregs+0x2c)|BIT(0), hsotg->phyregs+0x2c); + mdelay(100); + writel(readl(hsotg->phyregs+0x40)|BIT(0), hsotg->phyregs+0x40); + writel(readl(hsotg->phyregs+0x44)|0x180, hsotg->phyregs+0x44); + mdelay(100); + } +} + +/** + * rtk_hsotg_phy_disable - disable platform phy dev + * @hsotg: The driver state + * + * A wrapper for platform code responsible for controlling + * low-level USB code + */ +static void rtk_hsotg_phy_disable(struct rtk_hsotg *hsotg) +{ +#if 0 //barry + struct platform_device *pdev = to_platform_device(hsotg->dev); + + if (hsotg->phy) { + phy_power_off(hsotg->phy); + phy_exit(hsotg->phy); + } else if (hsotg->uphy) + usb_phy_shutdown(hsotg->uphy); + else if (hsotg->plat->phy_exit) + hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); +#endif +#ifdef CONFIG_USB_OTG + if(hsotg->phyregs) + writel(readl(hsotg->phyregs+0x40)&~BIT(0), hsotg->phyregs+0x40); +#endif +} + +/** + * rtk_hsotg_init - initalize the usb core + * @hsotg: The driver state + */ +static void rtk_hsotg_init(struct rtk_hsotg *hsotg) +{ + /* unmask subset of endpoint interrupts */ + + writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | + DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, + hsotg->regs + DIEPMSK); + + writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | + DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, + hsotg->regs + DOEPMSK); + + writel(0, hsotg->regs + DAINTMSK); + + /* Be in disconnected state until gadget is registered */ + __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + + if (0) { + /* post global nak until we're ready */ + writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, + hsotg->regs + DCTL); + } + + /* setup fifos */ + + dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", + readl(hsotg->regs + GRXFSIZ), + readl(hsotg->regs + GNPTXFSIZ)); + + rtk_hsotg_init_fifo(hsotg); + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10), + hsotg->regs + GUSBCFG); +// writel(hsotg->phyif | GUSBCFG_TOutCal(7) | (0x5 << 10), //barry +// hsotg->regs + GUSBCFG); + mdelay(100); + + writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, + hsotg->regs + GAHBCFG); +} + +/** + * rtk_hsotg_udc_start - prepare the udc for work + * @gadget: The usb gadget state + * @driver: The usb gadget driver + * + * Perform initialization to prepare udc device and driver + * to work. + */ +static int rtk_hsotg_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct rtk_hsotg *hsotg = to_hsotg(gadget); + int ret; + + if (!hsotg) { + pr_err("%s: called with no device\n", __func__); + return -ENODEV; + } + + if (!driver) { + dev_err(hsotg->dev, "%s: no driver\n", __func__); + return -EINVAL; + } + + if (driver->max_speed < USB_SPEED_FULL) + dev_err(hsotg->dev, "%s: bad speed\n", __func__); + + if (!driver->setup) { + dev_err(hsotg->dev, "%s: missing entry points\n", __func__); + return -EINVAL; + } + + WARN_ON(hsotg->driver); + + driver->driver.bus = NULL; + hsotg->driver = driver; + hsotg->gadget.dev.of_node = hsotg->dev->of_node; + hsotg->gadget.speed = USB_SPEED_UNKNOWN; +#if 0 + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); + goto err; + } +#endif + hsotg->last_rst = jiffies; + dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); + return 0; + +//err: + hsotg->driver = NULL; + return ret; +} + +/** + * rtk_hsotg_udc_stop - stop the udc + * @gadget: The usb gadget state + * @driver: The usb gadget driver + * + * Stop udc hw block and stay tunned for future transmissions + */ +static int rtk_hsotg_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct rtk_hsotg *hsotg = to_hsotg(gadget); + unsigned long flags = 0; + int ep; + + if (!hsotg) + return -ENODEV; + + /* all endpoints should be shutdown */ + for (ep = 0; ep < hsotg->num_of_eps; ep++) + rtk_hsotg_ep_disable(&hsotg->eps[ep].ep); + + spin_lock_irqsave(&hsotg->lock, flags); + + rtk_hsotg_phy_disable(hsotg); + + if (!driver) + hsotg->driver = NULL; + + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + + spin_unlock_irqrestore(&hsotg->lock, flags); +#if 0 + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); +#endif + return 0; +} + +/** + * rtk_hsotg_gadget_getframe - read the frame number + * @gadget: The usb gadget state + * + * Read the {micro} frame number + */ +static int rtk_hsotg_gadget_getframe(struct usb_gadget *gadget) +{ + return rtk_hsotg_read_frameno(to_hsotg(gadget)); +} + +/** + * rtk_hsotg_pullup - connect/disconnect the USB PHY + * @gadget: The usb gadget state + * @is_on: Current state of the USB PHY + * + * Connect/Disconnect the USB PHY pullup + */ +static int rtk_hsotg_pullup(struct usb_gadget *gadget, int is_on) +{ + struct rtk_hsotg *hsotg = to_hsotg(gadget); + unsigned long flags = 0; + + dev_dbg(hsotg->dev, "%s: is_in: %d\n", __func__, is_on); + + spin_lock_irqsave(&hsotg->lock, flags); + if (is_on) { + rtk_hsotg_phy_enable(hsotg); + rtk_hsotg_core_init(hsotg); + } else { + rtk_hsotg_disconnect(hsotg); + rtk_hsotg_phy_disable(hsotg); + } + + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); + + return 0; +} + +static const struct usb_gadget_ops rtk_hsotg_gadget_ops = { + .get_frame = rtk_hsotg_gadget_getframe, + .udc_start = rtk_hsotg_udc_start, + .udc_stop = rtk_hsotg_udc_stop, + .pullup = rtk_hsotg_pullup, +}; + +/** + * rtk_hsotg_initep - initialise a single endpoint + * @hsotg: The device state. + * @hs_ep: The endpoint to be initialised. + * @epnum: The endpoint number + * + * Initialise the given endpoint (as part of the probe and device state + * creation) to give to the gadget driver. Setup the endpoint name, any + * direction information and other state that may be required. + */ +static void rtk_hsotg_initep(struct rtk_hsotg *hsotg, + struct rtk_hsotg_ep *hs_ep, + int epnum) +{ + u32 ptxfifo; + char *dir; + + if (epnum == 0) + dir = ""; + else if ((epnum % 2) == 0) { + dir = "out"; + } else { + dir = "in"; + hs_ep->dir_in = 1; + } + + hs_ep->index = epnum; + + snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); + + INIT_LIST_HEAD(&hs_ep->queue); + INIT_LIST_HEAD(&hs_ep->ep.ep_list); + + /* add to the list of endpoints known by the gadget driver */ + if (epnum) + list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); + + hs_ep->parent = hsotg; + hs_ep->ep.name = hs_ep->name; + usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); + hs_ep->ep.ops = &rtk_hsotg_ep_ops; + + /* + * Read the FIFO size for the Periodic TX FIFO, even if we're + * an OUT endpoint, we may as well do this if in future the + * code is changed to make each endpoint's direction changeable. + */ + + ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); + hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; + + /* + * if we're using dma, we need to set the next-endpoint pointer + * to be something valid. + */ + + if (using_dma(hsotg)) { + u32 next = DxEPCTL_NextEp((epnum + 1) % 15); + writel(next, hsotg->regs + DIEPCTL(epnum)); + writel(next, hsotg->regs + DOEPCTL(epnum)); + } +} + +/** + * rtk_hsotg_hw_cfg - read HW configuration registers + * @param: The device state + * + * Read the USB core HW configuration registers + */ +static void rtk_hsotg_hw_cfg(struct rtk_hsotg *hsotg) +{ + u32 cfg2, cfg4; + /* check hardware configuration */ + +#ifdef CONFIG_USB_OTG + hsotg->num_of_eps = 5; + hsotg->dedicated_fifos = 0; +#else + cfg2 = readl(hsotg->regs + 0x48); + hsotg->num_of_eps = (cfg2 >> 10) & 0xF; + + dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps); + + cfg4 = readl(hsotg->regs + 0x50); + hsotg->dedicated_fifos = (cfg4 >> 25) & 1; +#endif + dev_info(hsotg->dev, "%s fifos\n", + hsotg->dedicated_fifos ? "dedicated" : "shared"); +} + +/** + * rtk_hsotg_dump - dump state of the udc + * @param: The device state + */ +static void rtk_hsotg_dump(struct rtk_hsotg *hsotg) +{ +#ifdef DEBUG + struct device *dev = hsotg->dev; + void __iomem *regs = hsotg->regs; + u32 val; + int idx; + + dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", + readl(regs + DCFG), readl(regs + DCTL), + readl(regs + DIEPMSK)); + + dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", + readl(regs + GAHBCFG), readl(regs + 0x44)); + + dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", + readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ)); + + /* show periodic fifo settings */ + + for (idx = 1; idx <= 15; idx++) { + val = readl(regs + DPTXFSIZn(idx)); + dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, + val >> DPTXFSIZn_DPTxFSize_SHIFT, + val & DPTXFSIZn_DPTxFStAddr_MASK); + } + + for (idx = 0; idx < 15; idx++) { + dev_info(dev, + "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, + readl(regs + DIEPCTL(idx)), + readl(regs + DIEPTSIZ(idx)), + readl(regs + DIEPDMA(idx))); + + val = readl(regs + DOEPCTL(idx)); + dev_info(dev, + "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", + idx, readl(regs + DOEPCTL(idx)), + readl(regs + DOEPTSIZ(idx)), + readl(regs + DOEPDMA(idx))); + + } + + dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", + readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE)); +#endif +} + +/** + * state_show - debugfs: show overall driver and device state. + * @seq: The seq file to write to. + * @v: Unused parameter. + * + * This debugfs entry shows the overall state of the hardware and + * some general information about each of the endpoints available + * to the system. + */ +static int state_show(struct seq_file *seq, void *v) +{ + struct rtk_hsotg *hsotg = seq->private; + void __iomem *regs = hsotg->regs; + int idx; + + seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", + readl(regs + DCFG), + readl(regs + DCTL), + readl(regs + DSTS)); + + seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", + readl(regs + DIEPMSK), readl(regs + DOEPMSK)); + + seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", + readl(regs + GINTMSK), + readl(regs + GINTSTS)); + + seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", + readl(regs + DAINTMSK), + readl(regs + DAINT)); + + seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", + readl(regs + GNPTXSTS), + readl(regs + GRXSTSR)); + + seq_puts(seq, "\nEndpoint status:\n"); + + for (idx = 0; idx < 15; idx++) { + u32 in, out; + + in = readl(regs + DIEPCTL(idx)); + out = readl(regs + DOEPCTL(idx)); + + seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", + idx, in, out); + + in = readl(regs + DIEPTSIZ(idx)); + out = readl(regs + DOEPTSIZ(idx)); + + seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", + in, out); + + seq_puts(seq, "\n"); + } + + return 0; +} + +static int state_open(struct inode *inode, struct file *file) +{ + return single_open(file, state_show, inode->i_private); +} + +static const struct file_operations state_fops = { + .owner = THIS_MODULE, + .open = state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * fifo_show - debugfs: show the fifo information + * @seq: The seq_file to write data to. + * @v: Unused parameter. + * + * Show the FIFO information for the overall fifo and all the + * periodic transmission FIFOs. + */ +static int fifo_show(struct seq_file *seq, void *v) +{ + struct rtk_hsotg *hsotg = seq->private; + void __iomem *regs = hsotg->regs; + u32 val; + int idx; + + seq_puts(seq, "Non-periodic FIFOs:\n"); + seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); + + val = readl(regs + GNPTXFSIZ); + seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", + val >> GNPTXFSIZ_NPTxFDep_SHIFT, + val & GNPTXFSIZ_NPTxFStAddr_MASK); + + seq_puts(seq, "\nPeriodic TXFIFOs:\n"); + + for (idx = 1; idx <= 15; idx++) { + val = readl(regs + DPTXFSIZn(idx)); + + seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, + val >> DPTXFSIZn_DPTxFSize_SHIFT, + val & DPTXFSIZn_DPTxFStAddr_MASK); + } + + return 0; +} + +static int fifo_open(struct inode *inode, struct file *file) +{ + return single_open(file, fifo_show, inode->i_private); +} + +static const struct file_operations fifo_fops = { + .owner = THIS_MODULE, + .open = fifo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + +static const char *decode_direction(int is_in) +{ + return is_in ? "in" : "out"; +} + +/** + * ep_show - debugfs: show the state of an endpoint. + * @seq: The seq_file to write data to. + * @v: Unused parameter. + * + * This debugfs entry shows the state of the given endpoint (one is + * registered for each available). + */ +static int ep_show(struct seq_file *seq, void *v) +{ + struct rtk_hsotg_ep *ep = seq->private; + struct rtk_hsotg *hsotg = ep->parent; + struct rtk_hsotg_req *req; + void __iomem *regs = hsotg->regs; + int index = ep->index; + int show_limit = 15; + unsigned long flags; + + seq_printf(seq, "Endpoint index %d, named %s, dir %s:\n", + ep->index, ep->ep.name, decode_direction(ep->dir_in)); + + /* first show the register state */ + + seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", + readl(regs + DIEPCTL(index)), + readl(regs + DOEPCTL(index))); + + seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", + readl(regs + DIEPDMA(index)), + readl(regs + DOEPDMA(index))); + + seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", + readl(regs + DIEPINT(index)), + readl(regs + DOEPINT(index))); + + seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", + readl(regs + DIEPTSIZ(index)), + readl(regs + DOEPTSIZ(index))); + + seq_puts(seq, "\n"); + seq_printf(seq, "mps %d\n", ep->ep.maxpacket); + seq_printf(seq, "total_data=%ld\n", ep->total_data); + + seq_printf(seq, "request list (%p,%p):\n", + ep->queue.next, ep->queue.prev); + + spin_lock_irqsave(&hsotg->lock, flags); + + list_for_each_entry(req, &ep->queue, queue) { + if (--show_limit < 0) { + seq_puts(seq, "not showing more requests...\n"); + break; + } + + seq_printf(seq, "%c req %p: %d bytes @%p, ", + req == ep->req ? '*' : ' ', + req, req->req.length, req->req.buf); + seq_printf(seq, "%d done, res %d\n", + req->req.actual, req->req.status); + } + + spin_unlock_irqrestore(&hsotg->lock, flags); + + return 0; +} + +static int ep_open(struct inode *inode, struct file *file) +{ + return single_open(file, ep_show, inode->i_private); +} + +static const struct file_operations ep_fops = { + .owner = THIS_MODULE, + .open = ep_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * rtk_hsotg_create_debug - create debugfs directory and files + * @hsotg: The driver state + * + * Create the debugfs files to allow the user to get information + * about the state of the system. The directory name is created + * with the same name as the device itself, in case we end up + * with multiple blocks in future systems. + */ +static void rtk_hsotg_create_debug(struct rtk_hsotg *hsotg) +{ + struct dentry *root; + unsigned epidx; + + root = debugfs_create_dir(dev_name(hsotg->dev), NULL); + hsotg->debug_root = root; + if (IS_ERR(root)) { + dev_err(hsotg->dev, "cannot create debug root\n"); + return; + } + + /* create general state file */ + + hsotg->debug_file = debugfs_create_file("state", 0444, root, + hsotg, &state_fops); + + if (IS_ERR(hsotg->debug_file)) + dev_err(hsotg->dev, "%s: failed to create state\n", __func__); + + hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, + hsotg, &fifo_fops); + + if (IS_ERR(hsotg->debug_fifo)) + dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); + + /* create one file for each endpoint */ + + for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { + struct rtk_hsotg_ep *ep = &hsotg->eps[epidx]; + + ep->debugfs = debugfs_create_file(ep->name, 0444, + root, ep, &ep_fops); + + if (IS_ERR(ep->debugfs)) + dev_err(hsotg->dev, "failed to create %s debug file\n", + ep->name); + } +} + +/** + * rtk_hsotg_delete_debug - cleanup debugfs entries + * @hsotg: The driver state + * + * Cleanup (remove) the debugfs files for use on module exit. + */ +static void rtk_hsotg_delete_debug(struct rtk_hsotg *hsotg) +{ + unsigned epidx; + + for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { + struct rtk_hsotg_ep *ep = &hsotg->eps[epidx]; + debugfs_remove(ep->debugfs); + } + + debugfs_remove(hsotg->debug_file); + debugfs_remove(hsotg->debug_fifo); + debugfs_remove(hsotg->debug_root); +} + +#ifdef CONFIG_USB_RTK_UDC_OTG_SWITCH +static int rtk_hsotg_gadget_suspend(struct platform_device *pdev) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + unsigned long flags; + int ret = 0; + + if (hsotg->driver) + dev_info(hsotg->dev, "suspending usb gadget %s\n", + hsotg->driver->driver.name); + + spin_lock_irqsave(&hsotg->lock, flags); + rtk_hsotg_disconnect(hsotg); + rtk_hsotg_phy_disable(hsotg); + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); + + if (hsotg->driver) { + int ep; + for (ep = 0; ep < hsotg->num_of_eps; ep++) + rtk_hsotg_ep_disable(&hsotg->eps[ep].ep); + } + + return ret; +} + +static int rtk_hsotg_gadget_resume(struct platform_device *pdev) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + unsigned long flags; + int ret = 0; + + if (hsotg->driver) { + dev_info(hsotg->dev, "resuming usb gadget %s\n", + hsotg->driver->driver.name); + } + + spin_lock_irqsave(&hsotg->lock, flags); + hsotg->last_rst = jiffies; + rtk_hsotg_phy_enable(hsotg); + rtk_hsotg_core_init(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + + return ret; +} + +static int switch_to_device_mode(struct rtk_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); + return rtk_hsotg_gadget_resume(pdev); +} + +static int switch_to_host_mode(struct rtk_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); + int ret; + + ret = rtk_hsotg_gadget_suspend(pdev); + + if(hsotg->phyregs) { + writel(readl(hsotg->phyregs+0xc)|BIT(0), hsotg->phyregs+0xc); + mdelay(100); + writel(readl(hsotg->phyregs+0x2c)|BIT(0), hsotg->phyregs+0x2c); + mdelay(100); + writel(readl(hsotg->phyregs+0x40) & ~BIT(0), hsotg->phyregs+0x40); + writel(readl(hsotg->phyregs+0x44) & ~0x180, hsotg->phyregs+0x44); + mdelay(100); + } + return ret; +} + +static ssize_t switch_mode_show(struct device *dev, struct device_attribute *attr, char *buffer) +{ + struct rtk_hsotg *hsotg = dev_get_drvdata(dev); + + return sprintf(buffer, "%s\n", hsotg->otg_type?"In device mode":"In host mode"); +} + +static ssize_t switch_mode_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t size) +{ + struct rtk_hsotg *hsotg = dev_get_drvdata(dev); + int ret; + char str[8]; + + ret = sscanf(buffer, "%7s", str); + if (ret != 1) + return -EINVAL; + + if (!strcmp(str, "device")) { + hsotg->otg_type = RTK_DEVICE_MODE; + dev_info(hsotg->dev, "switch to device mode\n"); + switch_to_device_mode(hsotg); + } else if (!strcmp(str, "host")) { + hsotg->otg_type = RTK_HOST_MODE; + dev_info(hsotg->dev, "switch to host mode\n"); + switch_to_host_mode(hsotg); + } else { + dev_err(hsotg->dev, "ERROR switch to %s mode\n", str); + } + return size; +} + +static DEVICE_ATTR(switch_mode, 0644, switch_mode_show, switch_mode_store); + +static const struct attribute *switch_mode_attrs[] = { + &dev_attr_switch_mode.attr, + NULL +}; + +static int rtk_hsotg_create_sysfs_by_otg(struct rtk_hsotg *hsotg) +{ + struct device *dev = hsotg->dev; + int retval; + + hsotg->otg_type = RTK_DEVICE_MODE; + + retval = sysfs_create_files(&dev->kobj, + (const struct attribute **)switch_mode_attrs); + + return retval; +} +#endif // CONFIG_USB_RTK_UDC_OTG_SWITCH + +/** + * rtk_hsotg_probe - probe function for hsotg driver + * @pdev: The platform information for the driver + */ +static int rtk_hsotg_probe(struct platform_device *pdev) +{ + struct rtk_hsotg_plat *plat = dev_get_platdata(&pdev->dev); +// struct phy *phy; + struct usb_phy *uphy; + struct device *dev = &pdev->dev; + struct rtk_hsotg_ep *eps; + struct rtk_hsotg *hsotg; + struct resource *res; + int epnum; + int ret; +// int i; + + hsotg = devm_kzalloc(&pdev->dev, sizeof(struct rtk_hsotg), GFP_KERNEL); + if (!hsotg) { + dev_err(dev, "cannot get memory\n"); + return -ENOMEM; + } + + /* + * Attempt to find a generic PHY, then look for an old style + * USB PHY, finally fall back to pdata + */ + uphy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); + if (IS_ERR(uphy)) { + /* Fallback for pdata */ + plat = dev_get_platdata(&pdev->dev); + if (!plat) { + dev_err(&pdev->dev, "no platform data or transceiver defined\n"); + return -EPROBE_DEFER; + } + hsotg->plat = plat; + } else { + hsotg->uphy = uphy; + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + hsotg->phyregs = devm_ioremap_nocache(dev, res->start, resource_size(res)); + } + + hsotg->dev = dev; +#if 0 //barry + hsotg->clk = devm_clk_get(&pdev->dev, "otg"); + if (IS_ERR(hsotg->clk)) { + dev_err(dev, "cannot get otg clock\n"); + return PTR_ERR(hsotg->clk); + } +#endif + platform_set_drvdata(pdev, hsotg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + hsotg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); + //hsotg->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hsotg->regs)) { + ret = PTR_ERR(hsotg->regs); + goto err_clk; + } + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "cannot find IRQ\n"); + goto err_clk; + } + + spin_lock_init(&hsotg->lock); + + hsotg->irq = ret; + + ret = devm_request_irq(&pdev->dev, hsotg->irq, rtk_hsotg_irq, IRQF_SHARED, + dev_name(dev), hsotg); + if (ret < 0) { + dev_err(dev, "cannot claim IRQ\n"); + goto err_clk; + } + + dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); + + hsotg->gadget.max_speed = USB_SPEED_HIGH; + hsotg->gadget.ops = &rtk_hsotg_gadget_ops; + hsotg->gadget.name = dev_name(dev); + + /* reset the system */ +#if 0 //barry + clk_prepare_enable(hsotg->clk); + + /* regulators */ + + for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) + hsotg->supplies[i].supply = rtk_hsotg_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(dev, "failed to request supplies: %d\n", ret); + goto err_clk; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + + if (ret) { + dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); + goto err_supplies; + } +#endif + /* Set default UTMI width */ + //hsotg->phyif = GUSBCFG_PHYIf16; + hsotg->phyif = GUSBCFG_PHYIf16|GUSBCFG_FORCEDEVMODE; + //hsotg->phyif = GUSBCFG_PHYIf8|GUSBCFG_FORCEDEVMODE; + + /* usb phy enable */ + // rtk_usb_phy_init(); + rtk_hsotg_phy_enable(hsotg); + rtk_hsotg_corereset(hsotg); + rtk_hsotg_init(hsotg); + rtk_hsotg_hw_cfg(hsotg); + + /* hsotg->num_of_eps holds number of EPs other than ep0 */ + + if (hsotg->num_of_eps == 0) { + dev_err(dev, "wrong number of EPs (zero)\n"); + ret = -EINVAL; + goto err_supplies; + } + + eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct rtk_hsotg_ep), + GFP_KERNEL); + if (!eps) { + dev_err(dev, "cannot get memory\n"); + ret = -ENOMEM; + goto err_supplies; + } + + hsotg->eps = eps; + + /* setup endpoint information */ + + INIT_LIST_HEAD(&hsotg->gadget.ep_list); + hsotg->gadget.ep0 = &hsotg->eps[0].ep; + + /* allocate EP0 request */ + + hsotg->ctrl_req = rtk_hsotg_ep_alloc_request(&hsotg->eps[0].ep, + GFP_KERNEL); + if (!hsotg->ctrl_req) { + dev_err(dev, "failed to allocate ctrl req\n"); + ret = -ENOMEM; + goto err_ep_mem; + } + + /* initialise the endpoints now the core has been initialised */ + for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) + rtk_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); + + /* disable power and clock */ +#if 0 + ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret); + goto err_ep_mem; + } +#endif + rtk_hsotg_phy_disable(hsotg); + + ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); + if (ret) + goto err_ep_mem; + + rtk_hsotg_create_debug(hsotg); + +#ifdef CONFIG_USB_RTK_UDC_OTG_SWITCH + rtk_hsotg_create_sysfs_by_otg(hsotg); +#endif // CONFIG_USB_RTK_UDC_OTG_SWITCH + + rtk_hsotg_dump(hsotg); + +#ifdef CONFIG_USB_OTG + otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); +#endif + return 0; + +err_ep_mem: + kfree(eps); +err_supplies: + rtk_hsotg_phy_disable(hsotg); +err_clk: + clk_disable_unprepare(hsotg->clk); + + return ret; +} + +/** + * rtk_hsotg_remove - remove function for hsotg driver + * @pdev: The platform information for the driver + */ +static int rtk_hsotg_remove(struct platform_device *pdev) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + + usb_del_gadget_udc(&hsotg->gadget); + + rtk_hsotg_delete_debug(hsotg); + + if (hsotg->driver) { + /* should have been done already by driver model core */ + usb_gadget_unregister_driver(hsotg->driver); + } + + rtk_hsotg_phy_disable(hsotg); +#if 0 //barry + if (hsotg->phy) + phy_exit(hsotg->phy); + clk_disable_unprepare(hsotg->clk); +#endif + return 0; +} + +#if 0 //barry +static int rtk_hsotg_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + unsigned long flags; + int ret = 0; + + if (hsotg->driver) + dev_info(hsotg->dev, "suspending usb gadget %s\n", + hsotg->driver->driver.name); + + spin_lock_irqsave(&hsotg->lock, flags); + rtk_hsotg_disconnect(hsotg); + rtk_hsotg_phy_disable(hsotg); + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); + + if (hsotg->driver) { + int ep; + for (ep = 0; ep < hsotg->num_of_eps; ep++) + rtk_hsotg_ep_disable(&hsotg->eps[ep].ep); + + ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + } + + return ret; +} + +static int rtk_hsotg_resume(struct platform_device *pdev) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + unsigned long flags; + int ret = 0; + + if (hsotg->driver) { + dev_info(hsotg->dev, "resuming usb gadget %s\n", + hsotg->driver->driver.name); + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + } + + spin_lock_irqsave(&hsotg->lock, flags); + hsotg->last_rst = jiffies; + rtk_hsotg_phy_enable(hsotg); + rtk_hsotg_core_init(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + + return ret; +} +#else +#define rtk_hsotg_suspend NULL +#define rtk_hsotg_resume NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id rtk_hsotg_of_ids[] = { + { .compatible = "realtek,rtd129x-usb2-udc" }, + { .compatible = "snps,dwc2", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtk_hsotg_of_ids); +#endif + +#ifdef CONFIG_USB_OTG +static int rtk_hsotg_otg_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + rtk_hsotg_phy_disable(hsotg); + return 0; +} +static int rtk_hsotg_otg_resume(struct platform_device *pdev) +{ + struct rtk_hsotg *hsotg = platform_get_drvdata(pdev); + rtk_hsotg_phy_enable(hsotg); +// rtk_hsotg_core_init(hsotg); + return 0; +} +#else +#define rtk_hsotg_otg_suspend NULL +#define rtk_hsotg_otg_resume NULL +#endif + +static struct platform_driver rtk_hsotg_driver = { + .driver = { + .name = "rtk-hsotg", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtk_hsotg_of_ids), +#ifdef CONFIG_USB_OTG + .suspend = rtk_hsotg_otg_suspend, + .resume = rtk_hsotg_otg_resume, +#endif + }, + .probe = rtk_hsotg_probe, + .remove = rtk_hsotg_remove, + .suspend = rtk_hsotg_suspend, + .resume = rtk_hsotg_resume, +}; + +module_platform_driver(rtk_hsotg_driver); + +MODULE_DESCRIPTION("Realtek USB High-speed/OtG device"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtk-hsotg"); diff --git a/drivers/usb/gadget/udc/rtk-hsotg.h b/drivers/usb/gadget/udc/rtk-hsotg.h new file mode 100644 index 000000000000..5b910888cee9 --- /dev/null +++ b/drivers/usb/gadget/udc/rtk-hsotg.h @@ -0,0 +1,379 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* drivers/usb/gadget/rtk-hsotg.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers + * +*/ + +#ifndef __REGS_USB_HSOTG_H +#define __REGS_USB_HSOTG_H __FILE__ + +#define HSOTG_REG(x) (x) + +#define GOTGCTL HSOTG_REG(0x000) +#define GOTGCTL_BSESVLD (1 << 19) +#define GOTGCTL_ASESVLD (1 << 18) +#define GOTGCTL_DBNC_SHORT (1 << 17) +#define GOTGCTL_CONID_B (1 << 16) +#define GOTGCTL_DEVHNPEN (1 << 11) +#define GOTGCTL_HSSETHNPEN (1 << 10) +#define GOTGCTL_HNPREQ (1 << 9) +#define GOTGCTL_HSTNEGSCS (1 << 8) +#define GOTGCTL_SESREQ (1 << 1) +#define GOTGCTL_SESREQSCS (1 << 0) + +#define GOTGINT HSOTG_REG(0x004) +#define GOTGINT_DbnceDone (1 << 19) +#define GOTGINT_ADevTOUTChg (1 << 18) +#define GOTGINT_HstNegDet (1 << 17) +#define GOTGINT_HstnegSucStsChng (1 << 9) +#define GOTGINT_SesReqSucStsChng (1 << 8) +#define GOTGINT_SesEndDet (1 << 2) + +#define GAHBCFG HSOTG_REG(0x008) +#define GAHBCFG_PTxFEmpLvl (1 << 8) +#define GAHBCFG_NPTxFEmpLvl (1 << 7) +#define GAHBCFG_DMAEn (1 << 5) +#define GAHBCFG_HBstLen_MASK (0xf << 1) +#define GAHBCFG_HBstLen_SHIFT (1) +#define GAHBCFG_HBstLen_Single (0x0 << 1) +#define GAHBCFG_HBstLen_Incr (0x1 << 1) +#define GAHBCFG_HBstLen_Incr4 (0x3 << 1) +#define GAHBCFG_HBstLen_Incr8 (0x5 << 1) +#define GAHBCFG_HBstLen_Incr16 (0x7 << 1) +#define GAHBCFG_GlblIntrEn (1 << 0) + +#define GUSBCFG HSOTG_REG(0x00C) +#define GUSBCFG_FORCEDEVMODE (1 << 30) +#define GUSBCFG_FORCEHOSTMODE (1 << 29) +#define GUSBCFG_PHYLPClkSel (1 << 15) +#define GUSBCFG_HNPCap (1 << 9) +#define GUSBCFG_SRPCap (1 << 8) +#define GUSBCFG_PHYIf16 (1 << 3) +#define GUSBCFG_PHYIf8 (0 << 3) +#define GUSBCFG_TOutCal_MASK (0x7 << 0) +#define GUSBCFG_TOutCal_SHIFT (0) +#define GUSBCFG_TOutCal_LIMIT (0x7) +#define GUSBCFG_TOutCal(_x) ((_x) << 0) + +#define GRSTCTL HSOTG_REG(0x010) + +#define GRSTCTL_AHBIdle (1 << 31) +#define GRSTCTL_DMAReq (1 << 30) +#define GRSTCTL_TxFNum_MASK (0x1f << 6) +#define GRSTCTL_TxFNum_SHIFT (6) +#define GRSTCTL_TxFNum_LIMIT (0x1f) +#define GRSTCTL_TxFNum(_x) ((_x) << 6) +#define GRSTCTL_TxFFlsh (1 << 5) +#define GRSTCTL_RxFFlsh (1 << 4) +#define GRSTCTL_INTknQFlsh (1 << 3) +#define GRSTCTL_FrmCntrRst (1 << 2) +#define GRSTCTL_HSftRst (1 << 1) +#define GRSTCTL_CSftRst (1 << 0) + +#define GINTSTS HSOTG_REG(0x014) +#define GINTMSK HSOTG_REG(0x018) + +#define GINTSTS_WkUpInt (1 << 31) +#define GINTSTS_SessReqInt (1 << 30) +#define GINTSTS_DisconnInt (1 << 29) +#define GINTSTS_ConIDStsChng (1 << 28) +#define GINTSTS_PTxFEmp (1 << 26) +#define GINTSTS_HChInt (1 << 25) +#define GINTSTS_PrtInt (1 << 24) +#define GINTSTS_FetSusp (1 << 22) +#define GINTSTS_incompIP (1 << 21) +#define GINTSTS_IncomplSOIN (1 << 20) +#define GINTSTS_OEPInt (1 << 19) +#define GINTSTS_IEPInt (1 << 18) +#define GINTSTS_EPMis (1 << 17) +#define GINTSTS_EOPF (1 << 15) +#define GINTSTS_ISOutDrop (1 << 14) +#define GINTSTS_EnumDone (1 << 13) +#define GINTSTS_USBRst (1 << 12) +#define GINTSTS_USBSusp (1 << 11) +#define GINTSTS_ErlySusp (1 << 10) +#define GINTSTS_GOUTNakEff (1 << 7) +#define GINTSTS_GINNakEff (1 << 6) +#define GINTSTS_NPTxFEmp (1 << 5) +#define GINTSTS_RxFLvl (1 << 4) +#define GINTSTS_SOF (1 << 3) +#define GINTSTS_OTGInt (1 << 2) +#define GINTSTS_ModeMis (1 << 1) +#define GINTSTS_CurMod_Host (1 << 0) + +#define GRXSTSR HSOTG_REG(0x01C) +#define GRXSTSP HSOTG_REG(0x020) + +#define GRXSTS_FN_MASK (0x7f << 25) +#define GRXSTS_FN_SHIFT (25) + +#define GRXSTS_PktSts_MASK (0xf << 17) +#define GRXSTS_PktSts_SHIFT (17) +#define GRXSTS_PktSts_GlobalOutNAK (0x1 << 17) +#define GRXSTS_PktSts_OutRX (0x2 << 17) +#define GRXSTS_PktSts_OutDone (0x3 << 17) +#define GRXSTS_PktSts_SetupDone (0x4 << 17) +#define GRXSTS_PktSts_SetupRX (0x6 << 17) + +#define GRXSTS_DPID_MASK (0x3 << 15) +#define GRXSTS_DPID_SHIFT (15) +#define GRXSTS_ByteCnt_MASK (0x7ff << 4) +#define GRXSTS_ByteCnt_SHIFT (4) +#define GRXSTS_EPNum_MASK (0xf << 0) +#define GRXSTS_EPNum_SHIFT (0) + +#define GRXFSIZ HSOTG_REG(0x024) + +#define GNPTXFSIZ HSOTG_REG(0x028) + +#define GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16) +#define GNPTXFSIZ_NPTxFDep_SHIFT (16) +#define GNPTXFSIZ_NPTxFDep_LIMIT (0xffff) +#define GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16) +#define GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0) +#define GNPTXFSIZ_NPTxFStAddr_SHIFT (0) +#define GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff) +#define GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0) + +#define GNPTXSTS HSOTG_REG(0x02C) + +#define GNPTXSTS_NPtxQTop_MASK (0x7f << 24) +#define GNPTXSTS_NPtxQTop_SHIFT (24) + +#define GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16) +#define GNPTXSTS_NPTxQSpcAvail_SHIFT (16) +#define GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff) + +#define GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0) +#define GNPTXSTS_NPTxFSpcAvail_SHIFT (0) +#define GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff) + + +#define HPTXFSIZ HSOTG_REG(0x100) + +#define DPTXFSIZn(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) + +#define DPTXFSIZn_DPTxFSize_MASK (0xffff << 16) +#define DPTXFSIZn_DPTxFSize_SHIFT (16) +#define DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff) +#define DPTXFSIZn_DPTxFSize_LIMIT (0xffff) +#define DPTXFSIZn_DPTxFSize(_x) ((_x) << 16) + +#define DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0) +#define DPTXFSIZn_DPTxFStAddr_SHIFT (0) + +/* Device mode registers */ +#define DCFG HSOTG_REG(0x800) + +#define DCFG_EPMisCnt_MASK (0x1f << 18) +#define DCFG_EPMisCnt_SHIFT (18) +#define DCFG_EPMisCnt_LIMIT (0x1f) +#define DCFG_EPMisCnt(_x) ((_x) << 18) + +#define DCFG_PerFrInt_MASK (0x3 << 11) +#define DCFG_PerFrInt_SHIFT (11) +#define DCFG_PerFrInt_LIMIT (0x3) +#define DCFG_PerFrInt(_x) ((_x) << 11) + +#define DCFG_DevAddr_MASK (0x7f << 4) +#define DCFG_DevAddr_SHIFT (4) +#define DCFG_DevAddr_LIMIT (0x7f) +#define DCFG_DevAddr(_x) ((_x) << 4) + +#define DCFG_NZStsOUTHShk (1 << 2) + +#define DCFG_DevSpd_MASK (0x3 << 0) +#define DCFG_DevSpd_SHIFT (0) +#define DCFG_DevSpd_HS (0x0 << 0) +#define DCFG_DevSpd_FS (0x1 << 0) +#define DCFG_DevSpd_LS (0x2 << 0) +#define DCFG_DevSpd_FS48 (0x3 << 0) + +#define DCTL HSOTG_REG(0x804) + +#define DCTL_PWROnPrgDone (1 << 11) +#define DCTL_CGOUTNak (1 << 10) +#define DCTL_SGOUTNak (1 << 9) +#define DCTL_CGNPInNAK (1 << 8) +#define DCTL_SGNPInNAK (1 << 7) +#define DCTL_TstCtl_MASK (0x7 << 4) +#define DCTL_TstCtl_SHIFT (4) +#define DCTL_GOUTNakSts (1 << 3) +#define DCTL_GNPINNakSts (1 << 2) +#define DCTL_SftDiscon (1 << 1) +#define DCTL_RmtWkUpSig (1 << 0) + +#define DSTS HSOTG_REG(0x808) + +#define DSTS_SOFFN_MASK (0x3fff << 8) +#define DSTS_SOFFN_SHIFT (8) +#define DSTS_SOFFN_LIMIT (0x3fff) +#define DSTS_SOFFN(_x) ((_x) << 8) +#define DSTS_ErraticErr (1 << 3) +#define DSTS_EnumSpd_MASK (0x3 << 1) +#define DSTS_EnumSpd_SHIFT (1) +#define DSTS_EnumSpd_HS (0x0 << 1) +#define DSTS_EnumSpd_FS (0x1 << 1) +#define DSTS_EnumSpd_LS (0x2 << 1) +#define DSTS_EnumSpd_FS48 (0x3 << 1) + +#define DSTS_SuspSts (1 << 0) + +#define DIEPMSK HSOTG_REG(0x810) + +#define DIEPMSK_TxFIFOEmpty (1 << 7) +#define DIEPMSK_INEPNakEffMsk (1 << 6) +#define DIEPMSK_INTknEPMisMsk (1 << 5) +#define DIEPMSK_INTknTXFEmpMsk (1 << 4) +#define DIEPMSK_TimeOUTMsk (1 << 3) +#define DIEPMSK_AHBErrMsk (1 << 2) +#define DIEPMSK_EPDisbldMsk (1 << 1) +#define DIEPMSK_XferComplMsk (1 << 0) + +#define DOEPMSK HSOTG_REG(0x814) + +#define DOEPMSK_Back2BackSetup (1 << 6) +#define DOEPMSK_OUTTknEPdisMsk (1 << 4) +#define DOEPMSK_SetupMsk (1 << 3) +#define DOEPMSK_AHBErrMsk (1 << 2) +#define DOEPMSK_EPDisbldMsk (1 << 1) +#define DOEPMSK_XferComplMsk (1 << 0) + +#define DAINT HSOTG_REG(0x818) +#define DAINTMSK HSOTG_REG(0x81C) + +#define DAINT_OutEP_SHIFT (16) +#define DAINT_OutEP(x) (1 << ((x) + 16)) +#define DAINT_InEP(x) (1 << (x)) + +#define DTKNQR1 HSOTG_REG(0x820) +#define DTKNQR2 HSOTG_REG(0x824) +#define DTKNQR3 HSOTG_REG(0x830) +#define DTKNQR4 HSOTG_REG(0x834) + +#define DVBUSDIS HSOTG_REG(0x828) +#define DVBUSPULSE HSOTG_REG(0x82C) + +#define DIEPCTL0 HSOTG_REG(0x900) +#define DOEPCTL0 HSOTG_REG(0xB00) +#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) +#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) + +/* EP0 specialness: + * bits[29..28] - reserved (no SetD0PID, SetD1PID) + * bits[25..22] - should always be zero, this isn't a periodic endpoint + * bits[10..0] - MPS setting differenct for EP0 + */ +#define D0EPCTL_MPS_MASK (0x3 << 0) +#define D0EPCTL_MPS_SHIFT (0) +#define D0EPCTL_MPS_64 (0x0 << 0) +#define D0EPCTL_MPS_32 (0x1 << 0) +#define D0EPCTL_MPS_16 (0x2 << 0) +#define D0EPCTL_MPS_8 (0x3 << 0) + +#define DxEPCTL_EPEna (1 << 31) +#define DxEPCTL_EPDis (1 << 30) +#define DxEPCTL_SetD1PID (1 << 29) +#define DxEPCTL_SetOddFr (1 << 29) +#define DxEPCTL_SetD0PID (1 << 28) +#define DxEPCTL_SetEvenFr (1 << 28) +#define DxEPCTL_SNAK (1 << 27) +#define DxEPCTL_CNAK (1 << 26) +#define DxEPCTL_TxFNum_MASK (0xf << 22) +#define DxEPCTL_TxFNum_SHIFT (22) +#define DxEPCTL_TxFNum_LIMIT (0xf) +#define DxEPCTL_TxFNum(_x) ((_x) << 22) + +#define DxEPCTL_Stall (1 << 21) +#define DxEPCTL_Snp (1 << 20) +#define DxEPCTL_EPType_MASK (0x3 << 18) +#define DxEPCTL_EPType_SHIFT (18) +#define DxEPCTL_EPType_Control (0x0 << 18) +#define DxEPCTL_EPType_Iso (0x1 << 18) +#define DxEPCTL_EPType_Bulk (0x2 << 18) +#define DxEPCTL_EPType_Intterupt (0x3 << 18) + +#define DxEPCTL_NAKsts (1 << 17) +#define DxEPCTL_DPID (1 << 16) +#define DxEPCTL_EOFrNum (1 << 16) +#define DxEPCTL_USBActEp (1 << 15) +#define DxEPCTL_NextEp_MASK (0xf << 11) +#define DxEPCTL_NextEp_SHIFT (11) +#define DxEPCTL_NextEp_LIMIT (0xf) +#define DxEPCTL_NextEp(_x) ((_x) << 11) + +#define DxEPCTL_MPS_MASK (0x7ff << 0) +#define DxEPCTL_MPS_SHIFT (0) +#define DxEPCTL_MPS_LIMIT (0x7ff) +#define DxEPCTL_MPS(_x) ((_x) << 0) + +#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) +#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) + +#define DxEPINT_INEPNakEff (1 << 6) +#define DxEPINT_Back2BackSetup (1 << 6) +#define DxEPINT_INTknEPMis (1 << 5) +#define DxEPINT_INTknTXFEmp (1 << 4) +#define DxEPINT_OUTTknEPdis (1 << 4) +#define DxEPINT_Timeout (1 << 3) +#define DxEPINT_Setup (1 << 3) +#define DxEPINT_AHBErr (1 << 2) +#define DxEPINT_EPDisbld (1 << 1) +#define DxEPINT_XferCompl (1 << 0) + +#define DIEPTSIZ0 HSOTG_REG(0x910) + +#define DIEPTSIZ0_PktCnt_MASK (0x3 << 19) +#define DIEPTSIZ0_PktCnt_SHIFT (19) +#define DIEPTSIZ0_PktCnt_LIMIT (0x3) +#define DIEPTSIZ0_PktCnt(_x) ((_x) << 19) + +#define DIEPTSIZ0_XferSize_MASK (0x7f << 0) +#define DIEPTSIZ0_XferSize_SHIFT (0) +#define DIEPTSIZ0_XferSize_LIMIT (0x7f) +#define DIEPTSIZ0_XferSize(_x) ((_x) << 0) + +#define DOEPTSIZ0 HSOTG_REG(0xB10) +#define DOEPTSIZ0_SUPCnt_MASK (0x3 << 29) +#define DOEPTSIZ0_SUPCnt_SHIFT (29) +#define DOEPTSIZ0_SUPCnt_LIMIT (0x3) +#define DOEPTSIZ0_SUPCnt(_x) ((_x) << 29) + +#define DOEPTSIZ0_PktCnt (1 << 19) +#define DOEPTSIZ0_XferSize_MASK (0x7f << 0) +#define DOEPTSIZ0_XferSize_SHIFT (0) + +#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) +#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) + +#define DxEPTSIZ_MC_MASK (0x3 << 29) +#define DxEPTSIZ_MC_SHIFT (29) +#define DxEPTSIZ_MC_LIMIT (0x3) +#define DxEPTSIZ_MC(_x) ((_x) << 29) + +#define DxEPTSIZ_PktCnt_MASK (0x3ff << 19) +#define DxEPTSIZ_PktCnt_SHIFT (19) +#define DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff) +#define DxEPTSIZ_PktCnt_LIMIT (0x3ff) +#define DxEPTSIZ_PktCnt(_x) ((_x) << 19) + +#define DxEPTSIZ_XferSize_MASK (0x7ffff << 0) +#define DxEPTSIZ_XferSize_SHIFT (0) +#define DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff) +#define DxEPTSIZ_XferSize_LIMIT (0x7ffff) +#define DxEPTSIZ_XferSize(_x) ((_x) << 0) + +#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) +#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) +#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) + +#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) + +#endif /* __REGS_USB_HSOTG_H */ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ab12c4bf0ef1..bf14bb52c4fc 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -160,6 +160,18 @@ config USB_EHCI_ROOT_HUB_TT This supports the EHCI implementation that's originally from ARC, and has since changed hands a few times. +if SYNO_LSP_RTD1619B +config USB_EHCI_RTK + tristate "Support for RTK on-chip EHCI USB controller" + depends on USB_EHCI_HCD + select RTK_USB_RLE0599_PHY + help + The Realtek chips are dual-role host/peripheral USB controllers. + + Enable this option to support this chip in host controller mode. + If unsure, say N. + +endif # SYNO_LSP_RTD1619B config USB_EHCI_TT_NEWSCHED bool "Improved Transaction Translator scheduling" depends on USB_EHCI_HCD @@ -429,6 +441,18 @@ config USB_OHCI_HCD if USB_OHCI_HCD +if SYNO_LSP_RTD1619B +config USB_OHCI_RTK + bool "Support for RTK on-chip OHCI USB controller" + depends on USB_OHCI_HCD + select RTK_USB_RLE0599_PHY + help + The Realtek chips are dual-role host/peripheral USB controllers. + + Enable this option to support this chip in host controller mode. + If unsure, say N. + +endif # SYNO_LSP_RTD1619B config USB_OHCI_HCD_OMAP1 tristate "OHCI support for OMAP1/2 chips" depends on ARCH_OMAP1 diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index bc731332fed9..96a695a9ecc1 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -50,6 +50,9 @@ obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o obj-$(CONFIG_USB_EHCI_BRCMSTB) += ehci-brcm.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_USB_EHCI_RTK) += ehci-rtk.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 0b7f1edd9eec..60d59ad3a221 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2002 by David Brownell @@ -867,6 +870,30 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) size -= temp; next += temp; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + temp = scnprintf (next, size, "CTRLDSSEGMENT %08x\n", + ehci_readl(ehci, &ehci->regs->segment)); + size -= temp; + next += temp; + + temp = scnprintf (next, size, "PERIODIC_LIST_BASE %08x\n", + ehci_readl(ehci, &ehci->regs->frame_list)); + size -= temp; + next += temp; + + temp = scnprintf (next, size, "ASYNC_LIST_ADDR %08x\n", + ehci_readl(ehci, &ehci->regs->async_next)); + size -= temp; + next += temp; + + temp = scnprintf (next, size, "CONFIG_FLAG %08x\n", + ehci_readl(ehci, &ehci->regs->configured_flag)); + size -= temp; + next += temp; +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ for (i = 1; i <= HCS_N_PORTS(ehci->hcs_params); i++) { temp = dbg_port_buf(scratch, sizeof(scratch), label, i, ehci_readl(ehci, diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index a319b1df3011..0cde846f771e 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * drivers/usb/host/ehci-orion.c @@ -215,6 +218,10 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) int irq, err; enum orion_ehci_phy_ver phy_version; struct orion_ehci_hcd *priv; +#ifdef MY_ABC_HERE + struct device_node *node = pdev->dev.of_node; + u32 vbus_gpio_pin = 0; +#endif /* MY_ABC_HERE */ if (usb_disabled()) return -ENODEV; @@ -250,6 +257,27 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) goto err; } +#ifdef MY_ABC_HERE + if (node) { + if (of_property_read_bool(node, "power-control-capable")) { + hcd->power_control_support = 1; + } else { + hcd->power_control_support = 0; + } + if (of_property_read_bool(node, "vbus-gpio")) { + of_property_read_u32(node, "vbus-gpio", &vbus_gpio_pin); + /* hcd->vbus_gpio_pin' is an integer, but vbus_gpio_pin is + * an unsigned integer. It should be safe because it's enough + * for gpio number. + */ + hcd->vbus_gpio_pin = vbus_gpio_pin; + } else { + hcd->vbus_gpio_pin = -1; + dev_warn(&pdev->dev, "failed to get Vbus gpio\n"); + } + } +#endif /* MY_ABC_HERE */ + hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = regs; @@ -301,6 +329,12 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "USB phy version isn't supported.\n"); } +#ifdef MY_ABC_HERE + dev_info(&pdev->dev, "USB2 Vbus gpio %d\n", hcd->vbus_gpio_pin); + dev_info(&pdev->dev, "power control %s\n", hcd->power_control_support ? + "enabled" : "disabled"); +#endif /* MY_ABC_HERE */ + err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_dis_clk; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 71ec3025686f..381d8144665a 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * EHCI HCD (Host Controller Driver) PCI Bus Glue. @@ -39,6 +42,10 @@ static const struct pci_device_id bypass_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), }, +#ifdef MY_DEF_HERE + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8c26), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8c2d), }, +#endif /* MY_DEF_HERE */ {} }; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a826715ae9bd..6311d3d82810 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2001-2004 by David Brownell @@ -33,6 +36,35 @@ /* fill a qtd, returning how much of the buffer we were able to queue up */ +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +extern int RTK_ohci_force_suspend(const char *func); + +/* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ +int check_and_restore_async_list(struct ehci_hcd *ehci, const char *func, int line) { + + int retry = 0; + if (ehci->fixed_async_list_addr_bug) { + for (retry = 0; retry < 5; retry++) { + u32 async_next = ehci_readl(ehci, &ehci->regs->async_next); + if (async_next == 0) { + ehci_err(ehci, "%s:%d #%d async_next is NULL ==> fixed async_next to HEAD=%x\n", + func, line, retry, (unsigned int) ehci->async->qh_dma); + ehci_writel(ehci, (u32) ehci->async->qh_dma, + &ehci->regs->async_next); + wmb(); + mdelay(2); + } else { + break; + } + } + } + return 0; +} +#endif // CONFIG_USB_PATCH_ON_RTK + + +#endif /* MY_DEF_HERE */ static int qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token, int maxpacket) @@ -952,6 +984,13 @@ qh_make ( static void enable_async(struct ehci_hcd *ehci) { +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + check_and_restore_async_list(ehci, __func__, __LINE__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ if (ehci->async_count++) return; @@ -965,6 +1004,13 @@ static void enable_async(struct ehci_hcd *ehci) static void disable_async(struct ehci_hcd *ehci) { +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + check_and_restore_async_list(ehci, __func__, __LINE__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ if (--ehci->async_count) return; @@ -983,6 +1029,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) __hc32 dma = QH_NEXT(ehci, qh->qh_dma); struct ehci_qh *head; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + /* When EHCI schedule actived, force suspend OHCI*/ + check_and_restore_async_list(ehci, __func__, __LINE__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* Don't link a QH if there's a Clear-TT-Buffer pending */ if (unlikely(qh->clearing_tt)) return; @@ -1111,6 +1165,14 @@ submit_async ( int rc; epnum = urb->ep->desc.bEndpointAddress; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_USB_OHCI_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + RTK_ohci_force_suspend(__func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ #ifdef EHCI_URB_TRACE { @@ -1271,6 +1333,13 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) prev->qh_next = qh->qh_next; if (ehci->qh_scan_next == qh) ehci->qh_scan_next = qh->qh_next.qh; +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + check_and_restore_async_list(ehci, __func__, __LINE__); +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ } static void start_iaa_cycle(struct ehci_hcd *ehci) @@ -1300,6 +1369,13 @@ static void end_iaa_cycle(struct ehci_hcd *ehci) ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + check_and_restore_async_list(ehci, __func__, __LINE__); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* The current IAA cycle has ended */ ehci->iaa_in_progress = false; diff --git a/drivers/usb/host/ehci-rtk.c b/drivers/usb/host/ehci-rtk.c new file mode 100644 index 000000000000..fb285bf1e373 --- /dev/null +++ b/drivers/usb/host/ehci-rtk.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * ehic-rtk.c RTK EHCI HCD (Host Controller Driver) + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ehci.h" + +#define DRIVER_DESC "EHCI realtek driver" + +static const char hcd_name[] = "ehci-rtk"; + +static struct hc_driver __read_mostly ehci_rtk_hc_driver; + +static struct ehci_rtk { + struct device *dev; + struct usb_phy *phy; + struct ehci_hcd *ehci; + int irq; + + struct work_struct work; +}; + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_USB_RLE0599_PHY +extern void rtk_rle0599_phy_toggle(struct usb_phy *usb2_phy, bool isConnect); +#endif + +int RTK_ehci_usb2_phy_toggle(struct device *hcd_dev, bool isConnect) +{ + struct usb_phy *phy = NULL; + + if (hcd_dev == NULL) + return -ENODEV; + + phy = devm_usb_get_phy_by_phandle(hcd_dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(hcd_dev, "No usb phy found\n"); + return -ENODEV; + } + + dev_dbg(hcd_dev, "%s\n", __func__); +#ifdef CONFIG_RTK_USB_RLE0599_PHY + if (phy != NULL) + rtk_rle0599_phy_toggle(phy, isConnect); +#endif + return 0; +} +#endif // CONFIG_USB_PATCH_ON_RTK + +static void ehci_rtk_probe_work(struct work_struct *work) +{ + struct ehci_rtk *rtk = container_of(work, struct ehci_rtk, work); + struct device *dev = rtk->dev; + struct usb_hcd *hcd = ehci_to_hcd(rtk->ehci); + struct usb_phy *phy = rtk->phy; + + int irq = rtk->irq; + int ret = 0; + + unsigned long probe_time = jiffies; + + dev_info(dev, "%s Start ...\n", __func__); + + usb_phy_init(phy); + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(dev, "%s: error add hcd\n", __func__); + usb_put_hcd(hcd); + } + + rtk_usb_init_port_power_on(dev); + + dev_info(dev, "%s End ... ok! (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); +} + +static int ehci_rtk_drv_probe(struct platform_device *pdev) +{ + struct resource res; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + void __iomem *regs; + int irq, err = 0; + struct usb_phy *phy; + unsigned long probe_time = jiffies; + + if (usb_disabled()) + return -ENODEV; + + dev_info(&pdev->dev, "Probe Realtek-SoC USB EHCI Host Controller\n"); + + //phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "No usb phy found\n"); + return -ENODEV; + } + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (irq <= 0) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(&pdev->dev)); + err = -ENODEV; + goto err1; + } + + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(&pdev->dev)); + err = -ENODEV; + goto err1; + } + + /* + * Right now device-tree probed devices don't get dma_mask + * set. Since shared usb code relies on it, set it here for + * now. Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + regs = of_iomap(pdev->dev.of_node, 0); + if (regs == NULL) { + dev_err(&pdev->dev, "error mapping memory\n"); + err = -EFAULT; + goto err3; + } + + if (readl(regs) == 0xdeadbeef) { + dev_err(&pdev->dev, "%s error read ehci registers\n", __func__); + err = -ENODEV; + goto err3; + } + + hcd = usb_create_hcd(&ehci_rtk_hc_driver, + &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + err = -ENOMEM; + goto err3; + } + + hcd->rsrc_start = res.start; + hcd->rsrc_len = resource_size(&res); + hcd->regs = regs; + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs; + +#ifdef CONFIG_USB_PATCH_ON_RTK + if (of_property_read_bool(pdev->dev.of_node, + "fixed_async_list_addr_bug")) { + dev_info(&pdev->dev, "%s Enable fixed_async_list_addr_bug\n", + __func__); + ehci->fixed_async_list_addr_bug = 1; + } +#endif // CONFIG_USB_PATCH_ON_RTK + + if (of_property_read_bool(pdev->dev.of_node, "delay_probe_work")) { + struct ehci_rtk *rtk; + + rtk = devm_kzalloc(&pdev->dev, sizeof(*rtk), GFP_KERNEL); + if (!rtk) { + err = -ENOMEM; + goto err4; + } + rtk->dev = &pdev->dev; + rtk->ehci = ehci; + rtk->irq = irq; + rtk->phy = phy; + INIT_WORK(&rtk->work, ehci_rtk_probe_work); + if (of_property_read_bool(pdev->dev.of_node, "ordered_probe")) + rtk_usb_manager_schedule_work(&pdev->dev, &rtk->work); + else + schedule_work(&rtk->work); + } else { + usb_phy_init(phy); + + err = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (err) { + dev_err(&pdev->dev, "error add hcd\n"); + goto err4; + } + } + + dev_info(&pdev->dev, "%s OK (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); + return 0; + +err4: + usb_put_hcd(hcd); +err3: + irq_dispose_mapping(irq); +err1: + dev_err(&pdev->dev, "%s: Probe %s fail, %d\n", __func__, + dev_name(&pdev->dev), err); + + return err; + +} + +static int ehci_rtk_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + dev_set_drvdata(&pdev->dev, NULL); + + usb_remove_hcd(hcd); + irq_dispose_mapping(hcd->irq); + usb_put_hcd(hcd); + + return 0; +} + +#ifdef CONFIG_USB_PATCH_ON_RTK +/* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ +bool RTK_ehci_check_schedule_actived(const char *func) +{ + static struct ehci_hcd *ehci; + struct device_node *node = NULL; + struct platform_device *pdev = NULL; + struct usb_hcd *hcd = NULL; + bool connected = false; + u32 status; + + if (ehci == NULL) { + node = of_find_compatible_node(NULL, NULL, + "realtek,rtd129x-ehci"); + if (node != NULL) + pdev = of_find_device_by_node(node); + if (pdev != NULL) { + hcd = platform_get_drvdata(pdev); + ehci = hcd_to_ehci(hcd); + } + } + if (ehci == NULL) { + pr_debug("%s NO EHCI\n", __func__); + return false; + } + status = ehci_readl(ehci, &ehci->regs->status); + if (status & (STS_PSS | STS_ASS)) + connected = true; + return connected; +} +#endif // CONFIG_USB_PATCH_ON_RTK + +#ifdef CONFIG_SUSPEND +#ifdef CONFIG_USB_PATCH_ON_RTK +static int rtk_ehci_suspend(struct device *dev); +int RTK_rtk_ehci_suspend(struct device *dev) +{ + return rtk_ehci_suspend(dev); +} +#endif // CONFIG_USB_PATCH_ON_RTK + +static int rtk_ehci_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct usb_phy *phy; + bool do_wakeup = device_may_wakeup(dev); + int rc = 0; + + dev_info(dev, "[USB] Enter %s", __func__); + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } + dev_info(dev, "[USB] %s Suspend mode\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + rc = ehci_suspend(hcd, do_wakeup); + + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "No usb phy found\n"); + return -ENODEV; + } + + usb_phy_shutdown(phy); + +out: + dev_info(dev, "[USB] Exit %s", __func__); + return rc; +} + +#ifdef CONFIG_USB_PATCH_ON_RTK +static int rtk_ehci_resume(struct device *dev); +int RTK_rtk_ehci_resume(struct device *dev) +{ + return rtk_ehci_resume(dev); +} +#endif // CONFIG_USB_PATCH_ON_RTK + +static int rtk_ehci_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct usb_phy *phy; + + dev_info(dev, "[USB] Enter %s", __func__); + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } + dev_info(dev, "[USB] %s Suspend mode\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "No usb phy found\n"); + return -ENODEV; + } + + usb_phy_init(phy); + + ehci_resume(hcd, false); + +out: + dev_info(dev, "[USB] Exit %s", __func__); + return 0; +} + +#else +#define rtk_ehci_suspend NULL +#define rtk_ehci_resume NULL +#endif + +static const struct dev_pm_ops rtk_ehci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rtk_ehci_suspend, rtk_ehci_resume) + //SET_LATE_SYSTEM_SLEEP_PM_OPS(rtk_ehci_suspend, rtk_ehci_resume) +}; + +static const struct of_device_id ehci_rtk_dt_ids[] = { + { .compatible = "realtek,rtk119x-ehci", }, + { .compatible = "realtek,rtd129x-ehci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ehci_rtk_dt_ids); + +static struct platform_driver ehci_rtk_driver = { + .probe = ehci_rtk_drv_probe, + .remove = ehci_rtk_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "rtk-ehci", + .owner = THIS_MODULE, + .pm = &rtk_ehci_pm_ops, + .of_match_table = of_match_ptr(ehci_rtk_dt_ids), + }, +}; + +static int __init ehci_rtk_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC " init\n", hcd_name); + + ehci_init_driver(&ehci_rtk_hc_driver, NULL); + return platform_driver_register(&ehci_rtk_driver); +} +module_init(ehci_rtk_init); +//late_initcall_sync(ehci_rtk_init); + +static void __exit ehci_rtk_cleanup(void) +{ + platform_driver_unregister(&ehci_rtk_driver); +} +module_exit(ehci_rtk_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:rtk-ehci"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 6dfb242f9a4b..c34b843ae66c 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2004 by David Brownell @@ -6,6 +9,13 @@ /* this file is part of ehci-hcd.c */ +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +/* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ +extern int RTK_ohci_force_suspend(const char *func); +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /*-------------------------------------------------------------------------*/ /* @@ -909,6 +919,16 @@ static int intr_submit( /* get endpoint and transfer/schedule data */ epnum = urb->ep->desc.bEndpointAddress; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_USB_OHCI_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + /* When EHCI schedule actived, force suspend OHCI*/ + RTK_ohci_force_suspend(__func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ spin_lock_irqsave(&ehci->lock, flags); if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index eabf22a78eae..9a966c2ea653 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (c) 2001-2002 by David Brownell @@ -219,6 +222,12 @@ struct ehci_hcd { /* one per controller */ unsigned need_oc_pp_cycle:1; /* MPC834X port power */ unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + unsigned fixed_async_list_addr_bug:1; +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) #define OHCI_USB_OPER (2 << 6) diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 44504c1751e0..6e0ec1701f6d 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-1.0+ /* * OHCI HCD (Host Controller Driver) for USB. @@ -43,6 +46,15 @@ static void update_done_list(struct ohci_hcd *); static void ohci_work(struct ohci_hcd *); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_USB_EHCI_RTK +/* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ +extern bool RTK_ehci_check_schedule_actived(const char *func); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ #ifdef CONFIG_PM static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) __releases(ohci->lock) @@ -155,6 +167,22 @@ __acquires(ohci->lock) int status = -EINPROGRESS; int autostopped = ohci->autostop; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_USB_EHCI_RTK + /* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ + /* When EHCI schedule actived, don't resume OHCI*/ + if (RTK_ehci_check_schedule_actived(__func__)) { + ohci_info (ohci, "[Workaround] %s EHCI schedule actived, skip resume OHCI\n", __func__); + return 0; + } else { + ohci->resuming = 1; + init_completion(&ohci->resuming_done); + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ ohci->autostop = 0; ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); @@ -295,6 +323,14 @@ __acquires(ohci->lock) } ohci->rh_state = OHCI_RH_RUNNING; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (ohci->resuming) { + complete(&ohci->resuming_done); + ohci->resuming = 0; + } +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ return 0; } @@ -521,6 +557,19 @@ int ohci_hub_status_data(struct usb_hcd *hcd, char *buf) else clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + /* add to check OHCI register deadbeef */ + if (true) { + u32 status = roothub_portstatus (ohci, 0); + if (status == 0xdeadbeef) { + ohci_err(ohci, "OHCI register is 0x%x" + " to clear HCD_FLAG_POLL_RH", status); + clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); + } + } +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ done: spin_unlock_irqrestore (&ohci->lock, flags); diff --git a/drivers/usb/host/ohci-rtk.c b/drivers/usb/host/ohci-rtk.c new file mode 100644 index 000000000000..dee44a6a07ba --- /dev/null +++ b/drivers/usb/host/ohci-rtk.c @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * ohic-rtk.c RTK OHCI HCD (Host Controller Driver) + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTK_OHCI_HCD_NAME "rtk-ohci" + +extern int usb_disabled(void); + +static int ohci_rtk_setup(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ohci_dbg(ohci, "%s, ohci:%p", __func__, ohci); + + ret = ohci_init(ohci); + if (ret < 0) + return ret; + return 0; +} + +static int ohci_rtk_dmp_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ohci_dbg(ohci, "%s, ohci:%p", __func__, ohci); + + ret = ohci_run(ohci); + if (ret < 0) { + pr_err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_rtk_dmp_hc_driver = { + .description = hcd_name, + .product_desc = "Rtk Dmp OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ohci_rtk_setup, + .start = ohci_rtk_dmp_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +struct ohci_rtk { + struct device *dev; + struct ohci_hcd *ohci; + struct usb_phy *phy; + int irq; + + struct work_struct work; +}; + +static void ohci_rtk_probe_work(struct work_struct *work) +{ + struct ohci_rtk *rtk = container_of(work, struct ohci_rtk, work); + struct device *dev = rtk->dev; + struct usb_hcd *hcd = ohci_to_hcd(rtk->ohci); + struct usb_phy *phy = rtk->phy; + int irq = rtk->irq; + int ret = 0; + + unsigned long probe_time = jiffies; + + dev_info(dev, "%s Start ...\n", __func__); + + usb_phy_init(phy); + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(dev, "%s: error add hcd\n", __func__); + usb_put_hcd(hcd); + } + + rtk_usb_init_port_power_on(dev); + + dev_info(dev, "%s End ... ok! (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); +} + +static int ohci_rtk_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + void *reg_base; + struct resource res; + int irq; + int ret; + struct usb_phy *phy; + unsigned long probe_time = jiffies; + + if (usb_disabled()) + return -ENODEV; + + dev_info(&pdev->dev, "Probe Realtek-SoC USB OHCI Host Controller\n"); + + //phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "No usb phy found\n"); + return -ENODEV; + } + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (irq <= 0) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + /* + * Right now device-tree probed devices don't get dma_mask + * set. Since shared usb code relies on it, set it here for + * now. Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + hcd = usb_create_hcd(&ohci_rtk_dmp_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res.start; + hcd->rsrc_len = resource_size(&res); + + reg_base = of_iomap(pdev->dev.of_node, 0); + if (!reg_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + if (readl(reg_base) == 0xdeadbeef) { + dev_err(&pdev->dev, "%s error read ohci registers\n", __func__); + ret = -ENODEV; + goto err2; + } + + hcd->regs = reg_base; + + ohci = hcd_to_ohci(hcd); + + ohci_hcd_init(ohci); + +#ifdef CONFIG_USB_PATCH_ON_RTK + if (pdev->dev.of_node) { + u32 wrap_reg = 0; + + of_property_read_u32(pdev->dev.of_node, "wrap_reg", &wrap_reg); + if (wrap_reg) + ohci->wrap_reg = ioremap(wrap_reg, 0x4); + else + ohci->wrap_reg = NULL; + } +#endif // CONFIG_USB_PATCH_ON_RTK + + if (of_property_read_bool(pdev->dev.of_node, "delay_probe_work")) { + struct ohci_rtk *rtk; + + rtk = devm_kzalloc(&pdev->dev, sizeof(*rtk), GFP_KERNEL); + if (!rtk) { + ret = -ENOMEM; + goto err2; + } + rtk->dev = &pdev->dev; + rtk->ohci = ohci; + rtk->phy = phy; + rtk->irq = irq; + INIT_WORK(&rtk->work, ohci_rtk_probe_work); + if (of_property_read_bool(pdev->dev.of_node, "ordered_probe")) + rtk_usb_manager_schedule_work(&pdev->dev, &rtk->work); + else + schedule_work(&rtk->work); + } else { + usb_phy_init(phy); + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(&pdev->dev, "failed to add hcd with err %d\n", + ret); + goto err2; + } + } + + platform_set_drvdata(pdev, hcd); + + dev_info(&pdev->dev, "%s OK (take %d ms)\n", __func__, + jiffies_to_msecs(jiffies - probe_time)); + return 0; + +err2: + irq_dispose_mapping(irq); +//err1: + usb_put_hcd(hcd); + return ret; +} + +static int ohci_rtk_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + + iounmap(hcd->regs); + +#ifdef CONFIG_USB_PATCH_ON_RTK + if (hcd) { + struct ohci_hcd *ohci; + + ohci = hcd_to_ohci(hcd); + if (ohci->wrap_reg) + __iounmap(ohci->wrap_reg); + } +#endif // CONFIG_USB_PATCH_ON_RTK + + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_USB_PATCH_ON_RTK +extern int usb_runtime_suspend(struct device *dev); + +/* Add Workaround to fixed EHCI/OHCI Wrapper can't work simultaneously */ +int RTK_ohci_force_suspend(const char *func) +{ + static struct ohci_hcd *s_ohci; + struct device_node *node = NULL; + struct platform_device *pdev = NULL; + struct usb_hcd *hcd = NULL; + struct ohci_hcd *ohci = NULL; + unsigned long flags; + + if (s_ohci == NULL) { + node = of_find_compatible_node(NULL, NULL, + "realtek,rtd129x-ohci"); + if (node != NULL) + pdev = of_find_device_by_node(node); + if (pdev != NULL) { + hcd = platform_get_drvdata(pdev); + s_ohci = hcd_to_ohci(hcd); + } + } else + ohci = s_ohci; + + if (ohci) { + u32 hc_control; + int resuming; + + spin_lock_irqsave(&ohci->lock, flags); + resuming = ohci->resuming; + spin_unlock_irqrestore(&ohci->lock, flags); + + if (resuming) { + ohci_dbg(ohci, "%s wait for resuming done !!\n", + __func__); + if (!wait_for_completion_timeout(&ohci->resuming_done, + msecs_to_jiffies(1000))) { + ohci_info(ohci, + "%s timed out on wait resuming_done\n", + __func__); + } + } + + spin_lock_irqsave(&ohci->lock, flags); + hc_control = ohci_readl(ohci, &ohci->regs->control); + if ((hc_control&OHCI_CTRL_HCFS) == OHCI_USB_OPER) { +#ifdef CONFIG_PM + ohci_info(ohci, "%s force suspend by %s\n", + __func__, func); + ohci_rh_suspend(ohci, 1); +#else + ohci_err(ohci, "%s NO build config CONFIG_PM!!\n", + __func__); +#endif + } + spin_unlock_irqrestore(&ohci->lock, flags); + + } else + pr_debug("%s NO OHCI !!!\n", __func__); + return 0; +} +#endif // CONFIG_USB_PATCH_ON_RTK + +#ifdef CONFIG_PM +static int rtk_ohci_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct usb_phy *phy; + bool do_wakeup = device_may_wakeup(dev); + int rc = 0; + + dev_info(dev, "[USB] Enter %s", __func__); + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } + dev_info(dev, "[USB] %s Suspend mode\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + rc = ohci_suspend(hcd, do_wakeup); + + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "No usb phy found\n"); + return -ENODEV; + } + + usb_phy_shutdown(phy); + +out: + dev_info(dev, "[USB] Exit %s", __func__); + return rc; +} + +static int rtk_ohci_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct usb_phy *phy; + + dev_info(dev, "[USB] Enter %s", __func__); + +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + //For idle mode + dev_info(dev, "[USB] %s Idle mode\n", __func__); + goto out; + } + dev_info(dev, "[USB] %s Suspend mode\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "No usb phy found\n"); + return -ENODEV; + } + + usb_phy_init(phy); + + ohci_resume(hcd, false); +out: + dev_info(dev, "[USB] Exit %s", __func__); + return 0; +} +#else +#define rtk_ohci_suspend NULL +#define rtk_ohci_resume NULL +#endif + +static const struct dev_pm_ops rtk_ohci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rtk_ohci_suspend, rtk_ohci_resume) + //SET_LATE_SYSTEM_SLEEP_PM_OPS(rtk_ohci_suspend, rtk_ohci_resume) +}; + +static const struct of_device_id ohci_rtk_dt_ids[] = { + { .compatible = "realtek,rtk119x-ohci", }, + { .compatible = "realtek,rtd129x-ohci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ohci_rtk_dt_ids); + +static struct platform_driver ohci_rtk_driver = { + .probe = ohci_rtk_drv_probe, + .remove = ohci_rtk_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = RTK_OHCI_HCD_NAME, + .owner = THIS_MODULE, + .pm = &rtk_ohci_pm_ops, + .of_match_table = of_match_ptr(ohci_rtk_dt_ids), + }, +}; + +MODULE_ALIAS("platform:" RTK_OHCI_HCD_NAME); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index aac6285b37f8..1276ab6ed9e5 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-1.0+ */ /* * OHCI HCD (Host Controller Driver) for USB. @@ -8,6 +11,12 @@ * This file is licenced under the GPL. */ +#if defined(MY_DEF_HERE) +#if 0//def CONFIG_USB_PATCH_ON_RTK +#include +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to * __leXX (normally) or __beXX (given OHCI_BIG_ENDIAN), depending on the @@ -362,6 +371,12 @@ enum ohci_rh_state { struct ohci_hcd { spinlock_t lock; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + void __iomem *wrap_reg; +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* * I/O memory used to communicate with the HC (dma-consistent) */ @@ -399,6 +414,12 @@ struct ohci_hcd { * driver state */ enum ohci_rh_state rh_state; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + int resuming; + struct completion resuming_done; +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ int num_ports; int load [NUM_INTS]; u32 hc_control; /* copy of hc control reg */ @@ -561,6 +582,20 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs) { +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + //unsigned long flags; + //rtk_lockapi_lock(flags, __FUNCTION__); /* Add global lock for emmc issue*/ + if (ohci->wrap_reg && readl(ohci->wrap_reg) == 0x0) { + ohci_err(ohci, "%s [USB Workaround] fixed force to enable " + "ohci clock \n", __func__); + writel(0x40, ohci->wrap_reg); + mdelay(1); + } + //rtk_lockapi_unlock(flags,__FUNCTION__); /* Add global lock for emmc issue*/ +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO return big_endian_mmio(ohci) ? readl_be (regs) : @@ -573,6 +608,19 @@ static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, static inline void _ohci_writel (const struct ohci_hcd *ohci, const unsigned int val, __hc32 __iomem *regs) { +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + //unsigned long flags; + //rtk_lockapi_lock(flags, __FUNCTION__); /* Add global lock for emmc issue*/ + if (ohci->wrap_reg && readl(ohci->wrap_reg) == 0x0) { + ohci_err(ohci, "%s [USB Workaround] fixed force to enable ohci clock \n", __func__); + writel(0x40, ohci->wrap_reg); + mdelay(1); + } + //rtk_lockapi_unlock(flags,__FUNCTION__); /* Add global lock for emmc issue*/ +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO big_endian_mmio(ohci) ? writel_be (val, regs) : diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 8466527eb246..f7d195fe5bdd 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * xHCI host controller driver @@ -1087,6 +1090,54 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, return status; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_USB_DWC3_RTK +extern void RTK_dwc3_usb3_phy_toggle(struct device *dwc3_dev, bool isConnect, int port); +extern int RTK_dwc3_usb2_phy_toggle(struct device *dwc3_dev, bool isConnect, int port); +#endif + +static void RTK_phy_toggle(struct usb_hcd *hcd, u16 wValue, u16 wIndex, + u32 temp) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (wValue == USB_PORT_FEAT_C_CONNECTION) { + + unsigned long flags; + struct xhci_bus_state *bus_state; + struct xhci_hub *rhub; + int port; + u32 status; + bool isConnect; + + port = wIndex; + rhub = xhci_get_rhub(hcd); + bus_state = &rhub->bus_state; + status = xhci_get_port_status(hcd, bus_state, wIndex, temp, + &flags); + isConnect = (status & PORT_CONNECT)?true:false; + +#ifdef CONFIG_USB_DWC3_RTK + if (hcd->speed >= HCD_USB3) { + xhci_info(xhci, "%s to call RTK_dwc3_usb3_phy_toggle (wValue=%x " + "port=%d status=%x)\n", + __func__, wValue, port, status); + RTK_dwc3_usb3_phy_toggle(hcd->self.controller, isConnect, port); + } else { + xhci_info(xhci, "%s to call RTK_dwc3_usb2_phy_toggle (wValue=%x " + "port=%d status=%x)\n", + __func__, wValue, port, status); + RTK_dwc3_usb2_phy_toggle(hcd->self.controller, isConnect, port); + } +#else + xhci_info(xhci, "%s NO build CONFIG_USB_DWC3_RTK\n", __func__); +#endif + } +} +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -1488,6 +1539,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_BH_PORT_RESET: case USB_PORT_FEAT_C_CONNECTION: +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + RTK_phy_toggle(hcd, wValue, wIndex, temp); +#if defined(MY_DEF_HERE) + xhci_clear_port_change_bit(xhci, wValue, wIndex, + ports[wIndex]->addr, temp); + break; +#endif /* MY_DEF_HERE */ +#endif // CONFIG_USB_PATCH_ON_RTK +#endif /* MY_DEF_HERE */ case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_PORT_LINK_STATE: diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ed380ee58ab5..72271d1ec02d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * xHCI host controller driver @@ -1057,6 +1060,73 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, virt_dev = xhci->devs[udev->slot_id]; ep0_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, 0); ep_ring = virt_dev->eps[0].ring; +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK +#if 1 + /* [DEV_FIX]xhci control tranfer will error occasionally (1/45) + * commit 0d2ae2abc867c1a31b7d280dc6429d18ba3770c5 + */ + { + int i = 0; + struct xhci_ring *ring = ep_ring; + union xhci_trb *next; + union xhci_trb *trb; + + ring->enq_seg = ring->first_seg; + ring->enqueue = ring->first_seg->trbs; + next = ring->enqueue; + wmb(); + for (i = 0; i < (TRBS_PER_SEGMENT); i++) { + trb = &ring->first_seg->trbs[i]; + trb->generic.field[3] &= cpu_to_le32(~TRB_CYCLE); + } + for (i = 0; i < (TRBS_PER_SEGMENT); i++) { + trb = &ring->first_seg->next->trbs[i]; + trb->generic.field[3] &= cpu_to_le32(~TRB_CYCLE); + } + ring->cycle_state = 1; + wmb(); + } +#else + /* [DEV_FIx]set address fail after warm/hot reset + * commit e7afd2f2d0093553379a9e2d6874ef11897a394f + */ + /* Fixed : USB reset issue, which will cause set address fail. + * by Ted. + */ + { + int i = 0; + struct xhci_ring *ring = ep_ring; + union xhci_trb *next; + union xhci_trb *trb; + ring->enq_seg = ring->first_seg; + ring->enqueue = ring->first_seg->trbs; + next = ring->enqueue; + wmb(); + for (i = 0; i < (TRBS_PER_SEGMENT -1); ++i) { + trb = &ring->first_seg->trbs[i]; + trb->generic.field[0] = 0x0; + trb->generic.field[1] = 0x0; + trb->generic.field[2] = 0x0; + trb->generic.field[3] = 0x0; + } + wmb(); + + for (i = 0; i < (TRBS_PER_SEGMENT -1); ++i) { + trb = &ring->first_seg->next->trbs[i]; + trb->generic.field[0] = 0x0; + trb->generic.field[1] = 0x0; + trb->generic.field[2] = 0x0; + trb->generic.field[3] = 0x0; + } + ring->cycle_state = 1; + wmb(); + } +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ /* * FIXME we don't keep track of the dequeue pointer very well after a * Set TR dequeue pointer, so we're setting the dequeue pointer of the @@ -2221,9 +2291,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, if ((xhci->hci_version >= 0x100) && (major_revision != 0x03) && (temp & XHCI_HLC)) { +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xHCI 1.0: support USB2 hardware lpm"); xhci->hw_lpm_support = 1; +#endif /* MY_ABC_HERE */ } port_offset--; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 119d1a8fbb19..0d619d23b74b 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * xHCI host controller driver PCI Bus Glue. @@ -183,7 +186,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_U2_DISABLE_WAKE; if (pdev->vendor == PCI_VENDOR_ID_INTEL) { +#ifdef MY_ABC_HERE + xhci->quirks &= ~XHCI_LPM_SUPPORT; +#else /* MY_ABC_HERE */ xhci->quirks |= XHCI_LPM_SUPPORT; +#endif /* MY_ABC_HERE */ xhci->quirks |= XHCI_INTEL_HOST; xhci->quirks |= XHCI_AVOID_BEI; } @@ -347,6 +354,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd) if (retval) return retval; +#ifdef MY_ABC_HERE + hcd->power_control_support = 1; +#endif /* MY_ABC_HERE */ + if (!usb_hcd_is_primary_hcd(hcd)) return 0; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index c1edcc9b13ce..e100fd4b3f3a 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * xhci-plat.c - xHCI host controller driver platform Bus Glue. @@ -186,6 +189,12 @@ MODULE_DEVICE_TABLE(of, usb_xhci_of_match); static int xhci_plat_probe(struct platform_device *pdev) { +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ + u32 vbus_gpio_pin = 0; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ const struct xhci_plat_priv *priv_match; const struct hc_driver *driver; struct device *sysdev, *tmpdev; @@ -339,6 +348,36 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_usb3_hcd; } +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + hcd->power_control_support = 1; + dev_info(&pdev->dev, "power control %s\n", hcd->power_control_support ? + "enabled" : "disabled"); +#else /* MY_ABC_HERE */ + if (node) { + if (of_property_read_bool(node, "power-control-capable")) { + hcd->power_control_support = 1; + } else { + hcd->power_control_support = 0; + } + if (of_property_read_bool(node, "vbus-gpio")) { + of_property_read_u32(node, "vbus-gpio", &vbus_gpio_pin); + /* hcd->vbus_gpio_pin' is an integer, but vbus_gpio_pin is + * an unsigned integer. It should be safe because it's enough + * for gpio number. + */ + hcd->vbus_gpio_pin = vbus_gpio_pin; + } else { + hcd->vbus_gpio_pin = -1; + dev_warn(&pdev->dev, "failed to get Vbus gpio\n"); + } + } + dev_info(&pdev->dev, "USB2 Vbus gpio %d\n", hcd->vbus_gpio_pin); + dev_info(&pdev->dev, "power control %s\n", hcd->power_control_support ? + "enabled" : "disabled"); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); xhci->shared_hcd->tpl_support = hcd->tpl_support; @@ -358,6 +397,21 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + xhci->shared_hcd->power_control_support = hcd->power_control_support; + dev_info(&pdev->dev, "power control %s\n", hcd->power_control_support ? + "enabled" : "disabled"); +#else /* MY_ABC_HERE */ + xhci->shared_hcd->vbus_gpio_pin = hcd->vbus_gpio_pin; + xhci->shared_hcd->power_control_support = hcd->power_control_support; + dev_info(&pdev->dev, "USB3 Vbus gpio %d\n", + xhci->shared_hcd->vbus_gpio_pin); + dev_info(&pdev->dev, "power control %s\n", hcd->power_control_support ? + "enabled" : "disabled"); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; @@ -431,12 +485,39 @@ static int xhci_plat_remove(struct platform_device *dev) return 0; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +/* [DEV_FIX]implement New USB reset mechanism with CRT reset to workaround any HW or IP issues + * commit 319ff9f5c298b94517a10d4ced59812b54994347 + */ +static int xhci_plat_suspend(struct device *dev); +int RTK_xhci_plat_suspend(struct device *dev) { + return xhci_plat_suspend(dev); +} +#endif // CONFIG_USB_PATCH_ON_RTK + + +#endif /* MY_DEF_HERE */ static int __maybe_unused xhci_plat_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); int ret; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + dev_info(dev, "[USB] %s Idle mode\n", __func__); + return 0; + } else + xhci_info(xhci, "[USB] %s Suspend mode --> xhci_suspend (do_wakeup=%s)", + __func__, device_may_wakeup(dev)? "true":"false"); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + + +#endif /* MY_DEF_HERE */ ret = xhci_priv_suspend_quirk(hcd); if (ret) return ret; @@ -447,12 +528,37 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) return xhci_suspend(xhci, device_may_wakeup(dev)); } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +/* [DEV_FIX]implement New USB reset mechanism with CRT reset to workaround any HW or IP issues + * commit 319ff9f5c298b94517a10d4ced59812b54994347 + */ +static int xhci_plat_resume(struct device *dev); +int RTK_xhci_plat_resume(struct device *dev) +{ + return xhci_plat_resume(dev); +} +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ static int __maybe_unused xhci_plat_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); int ret; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +#ifdef CONFIG_RTK_PLATFORM + if (RTK_PM_STATE == PM_SUSPEND_STANDBY) { + dev_info(dev, "[USB] %s Idle mode\n", __func__); + return 0; + } else + dev_info(dev, "[USB] %s Suspend mode --> xhci_resume\n", __func__); +#endif +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ ret = xhci_priv_resume_quirk(hcd); if (ret) return ret; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 53059ee957ad..2ac94a881e21 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * xHCI host controller driver @@ -702,6 +705,71 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, usb_hcd_giveback_urb(hcd, urb, status); } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +static void xhci_unmap_td_cache_buf(struct xhci_hcd *xhci, + struct xhci_ring *ring, struct xhci_td *td) +{ + struct device *dev = xhci_to_hcd(xhci)->self.controller; + struct urb *urb = td->urb; + size_t len; + struct xhci_cache_buf *cache_buf, *tmp; + + if (usb_urb_dir_out(urb)) { + list_for_each_entry_safe(cache_buf, tmp, &td->cache_buf_list, + list) { + if (!cache_buf) + continue; + + list_del_init(&cache_buf->list); + + if (!cache_buf->buf) { + xhci_err(xhci, "%s cache_buf buf is NULL\n", + __func__); + kfree(cache_buf); + continue; + } + + dma_unmap_single(dev, cache_buf->dma, cache_buf->len, + DMA_TO_DEVICE); + + kfree(cache_buf->buf); + kfree(cache_buf); + } + return; + } + + list_for_each_entry_safe(cache_buf, tmp, &td->cache_buf_list, + list) { + if (!cache_buf) + continue; + + list_del_init(&cache_buf->list); + + if (!cache_buf->buf) { + xhci_err(xhci, "%s cache_buf buf is NULL\n", __func__); + kfree(cache_buf); + continue; + } + + dma_unmap_single(dev, cache_buf->dma, cache_buf->len, + DMA_FROM_DEVICE); + /* for in tranfers we need to copy the data from cache to sg */ + len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, + cache_buf->buf, + cache_buf->len, cache_buf->offs); + if (len != cache_buf->len) + xhci_warn(xhci, "WARN Wrong cache buffer read length: %zu != %d\n", + len, cache_buf->len); + + kfree(cache_buf->buf); + kfree(cache_buf); + } +} +#endif + + +#endif /* MY_DEF_HERE */ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_ring *ring, struct xhci_td *td) { @@ -710,6 +778,12 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct urb *urb = td->urb; size_t len; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + xhci_unmap_td_cache_buf(xhci, ring, td); +#endif /* CONFIG_USB_PATCH_ON_RTK */ + +#endif /* MY_DEF_HERE */ if (!ring || !seg || !urb) return; @@ -1576,6 +1650,32 @@ static void handle_vendor_event(struct xhci_hcd *xhci, handle_cmd_completion(xhci, &event->event_cmd); } +#ifdef MY_DEF_HERE +static void xhci_giveback_error_urb(struct xhci_hcd *xhci, + int slot_id) +{ + struct xhci_virt_device *virt_dev; + int i; + + virt_dev = xhci->devs[slot_id]; + for (i = LAST_EP_INDEX; i > 0; i--) { + struct xhci_virt_ep *ep = &virt_dev->eps[i]; + struct xhci_ring *ring = ep->ring; + if (!ring) + continue; + if (!list_empty(&ring->td_list)) { + struct xhci_td *cur_td = list_first_entry(&ring->td_list, + struct xhci_td, + td_list); + list_del_init(&cur_td->td_list); + if (!list_empty(&cur_td->cancelled_td_list)) + list_del_init(&cur_td->cancelled_td_list); + xhci_giveback_urb_in_irq(xhci, cur_td, -EPROTO); + } + } +} +#endif /* MY_DEF_HERE */ + static void handle_device_notification(struct xhci_hcd *xhci, union xhci_trb *event) { @@ -1690,6 +1790,24 @@ static void handle_port_status(struct xhci_hcd *xhci, xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR; } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE && + (portsc & PORT_PLC)) { + bus_state->port_remote_wakeup |= (1 << hcd_portnum); + xhci_dbg(xhci, "Get port link state XDEV_INACTIVE and port link change " + "to set port_remote_wakeup (port_status=0x%x)\n", portsc); + if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) { + bus_state->port_remote_wakeup &= + ~(1 << hcd_portnum); + xhci_test_and_clear_bit(xhci, port, PORT_PLC); + usb_wakeup_notification(hcd->self.root_hub, + hcd_portnum + 1); + } + } +#endif // CONFIG_USB_PATCH_ON_RTK + +#endif /* MY_DEF_HERE */ if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { xhci_dbg(xhci, "port resume event for port %d\n", port_id); @@ -1731,6 +1849,19 @@ static void handle_port_status(struct xhci_hcd *xhci, } } +#ifdef MY_DEF_HERE + if (!(portsc & PORT_CONNECT) && + (portsc & PORT_WRC)) { + slot_id = xhci_find_slot_id_by_port(hcd, xhci, + hcd_portnum + 1); + if (slot_id && xhci->devs[slot_id]) { + xhci_warn(xhci, "device is plugged out, empty URBs\n"); + xhci->devs[slot_id]->disconnected = true; + xhci_giveback_error_urb(xhci, slot_id); + } + } +#endif /* MY_DEF_HERE */ + if ((portsc & PORT_PLC) && DEV_SUPERSPEED_ANY(portsc) && ((portsc & PORT_PLS_MASK) == XDEV_U0 || @@ -3091,6 +3222,11 @@ static int prepare_transfer(struct xhci_hcd *xhci, INIT_LIST_HEAD(&td->td_list); INIT_LIST_HEAD(&td->cancelled_td_list); +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + INIT_LIST_HEAD(&td->cache_buf_list); +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ if (td_index == 0) { ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb); @@ -3274,6 +3410,65 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, return (total_packet_count - ((transferred + trb_buff_len) / maxp)); } +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +static u64 xhci_align_cache_buf(struct xhci_hcd *xhci, + struct urb *urb, u32 enqd_len, u32 hw_limit_buf_len, + u32 *trb_buff_len, struct xhci_td *td) +{ + struct device *dev = xhci_to_hcd(xhci)->self.controller; + struct xhci_cache_buf *cache_buf; + unsigned int max_pkt; + u32 new_buff_len; + size_t len; + + max_pkt = usb_endpoint_maxp(&urb->ep->desc); + + cache_buf = kzalloc(sizeof(struct xhci_cache_buf), GFP_KERNEL); + if (!cache_buf) + return -ENOMEM; + list_add(&cache_buf->list, &td->cache_buf_list); + + cache_buf->buf = kzalloc(max_pkt, GFP_DMA | GFP_ATOMIC); + if (!cache_buf->buf) + return -ENOMEM; + + new_buff_len = max_pkt - (enqd_len % max_pkt); + + if (new_buff_len > (urb->transfer_buffer_length - enqd_len)) + new_buff_len = (urb->transfer_buffer_length - enqd_len); + + /* create a max max_pkt sized cache buffer pointed to by last trb */ + if (usb_urb_dir_out(urb)) { + len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs, + cache_buf->buf, new_buff_len, enqd_len); + if (len != new_buff_len) + xhci_warn(xhci, + "WARN Wrong cache buffer write length: %zu != %d\n", + len, new_buff_len); + cache_buf->dma = dma_map_single(dev, cache_buf->buf, + max_pkt, DMA_TO_DEVICE); + } else { + cache_buf->dma = dma_map_single(dev, cache_buf->buf, + max_pkt, DMA_FROM_DEVICE); + } + + if (dma_mapping_error(dev, cache_buf->dma)) { + /* try without aligning. Some host controllers survive */ + xhci_warn(xhci, "Failed mapping cache buffer, not aligning\n"); + return 0; + } + *trb_buff_len = new_buff_len; + + cache_buf->len = new_buff_len; + cache_buf->offs = enqd_len; + + xhci_dbg(xhci, "cache buf align, new buff len %d\n", *trb_buff_len); + + return cache_buf->dma; +} +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, u32 *trb_buff_len, struct xhci_segment *seg) @@ -3362,6 +3557,18 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int sent_len, ret; u32 field, length_field, remainder; u64 addr, send_addr; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + int max_hw_limit_num_trbs, hw_limit_num_trbs = 0; + int max_hw_limit_buf_len, hw_limit_buf_len = 0; + + max_hw_limit_buf_len = usb_endpoint_maxp(&urb->ep->desc); + if (urb->dev->speed >= USB_SPEED_SUPER) + max_hw_limit_num_trbs = 13; + else + max_hw_limit_num_trbs = 7; +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ ring = xhci_urb_to_transfer_ring(xhci, urb); if (!ring) @@ -3428,6 +3635,30 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ if (enqd_len + trb_buff_len < full_len) { field |= TRB_CHAIN; +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + hw_limit_num_trbs++; + hw_limit_buf_len += trb_buff_len; + + if (hw_limit_buf_len >= max_hw_limit_buf_len) { + hw_limit_buf_len = (enqd_len + trb_buff_len) % + max_hw_limit_buf_len; + hw_limit_num_trbs = 0; + } else if (hw_limit_num_trbs >= max_hw_limit_num_trbs) { + send_addr = xhci_align_cache_buf(xhci, urb, + enqd_len, hw_limit_buf_len, + &trb_buff_len, td); + if (send_addr <= 0) + return send_addr; + + hw_limit_buf_len = (enqd_len + trb_buff_len) % + max_hw_limit_buf_len; + hw_limit_num_trbs = 0; + } +#endif /* CONFIG_USB_PATCH_ON_RTK */ + +#endif /* MY_DEF_HERE */ if (trb_is_link(ring->enqueue + 1)) { if (xhci_align_td(xhci, urb, enqd_len, &trb_buff_len, @@ -3435,6 +3666,14 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, send_addr = ring->enq_seg->bounce_dma; /* assuming TD won't span 2 segs */ td->bounce_seg = ring->enq_seg; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK + hw_limit_buf_len = (enqd_len + + trb_buff_len) % + max_hw_limit_buf_len; + hw_limit_num_trbs = 0; +#endif +#endif /* MY_DEF_HERE */ } } } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a8d97e23f601..2bcc31e1927f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * xHCI host controller driver @@ -186,6 +189,10 @@ int xhci_reset(struct xhci_hcd *xhci) command |= CMD_RESET; writel(command, &xhci->op_regs->command); +#ifdef MY_DEF_HERE + mdelay(100); +#endif /* MY_DEF_HERE */ + /* Existing Intel xHCI controllers require a delay of 1 mS, * after setting the CMD_RESET bit, and before accessing any * HC registers. This allows the HC to complete the @@ -206,6 +213,11 @@ int xhci_reset(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Wait for controller to be ready for doorbell rings"); + +#ifdef MY_DEF_HERE + mdelay(100); +#endif /* MY_DEF_HERE */ + /* * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. @@ -1553,6 +1565,15 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag goto free_priv; } +#ifdef MY_DEF_HERE + if (xhci->devs[slot_id]->disconnected) { + xhci_warn(xhci, "Ignore URB enqueuing while device " + "is disconnecting\n"); + ret = -ENOTCONN; + goto free_priv; + } +#endif /* MY_DEF_HERE */ + switch (usb_endpoint_type(&urb->ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c1865a121100..b3f232967f90 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* @@ -1026,6 +1029,9 @@ struct xhci_virt_device { u16 current_mel; /* Used for the debugfs interfaces. */ void *debugfs_private; +#ifdef MY_DEF_HERE + bool disconnected; +#endif /* MY_DEF_HERE */ }; /* @@ -1532,6 +1538,19 @@ struct xhci_segment { unsigned int bounce_len; }; +#if defined(MY_DEF_HERE) +#ifdef CONFIG_USB_PATCH_ON_RTK +struct xhci_cache_buf { + dma_addr_t dma; + void *buf; + unsigned int offs; + unsigned int len; + + struct list_head list; +}; +#endif /* CONFIG_USB_PATCH_ON_RTK */ + +#endif /* MY_DEF_HERE */ struct xhci_td { struct list_head td_list; struct list_head cancelled_td_list; @@ -1542,6 +1561,12 @@ struct xhci_td { struct xhci_segment *bounce_seg; /* actual_length of the URB has already been set */ bool urb_length_set; +#if defined(MY_DEF_HERE) + +#ifdef CONFIG_USB_PATCH_ON_RTK + struct list_head cache_buf_list; +#endif /* CONFIG_USB_PATCH_ON_RTK */ +#endif /* MY_DEF_HERE */ }; /* xHCI command default timeout value */ diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index ef4787cd3d37..914cd1461bef 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -192,4 +192,24 @@ config JZ4770_PHY This driver provides PHY support for the USB controller found on the JZ-series and X-series SoCs from Ingenic. +if SYNO_LSP_RTD1619B +config RTK_USB_RLE0599_PHY + tristate "Realtek USB RLE0599 PHY Controller Driver" + select USB_PHY + help + Enable this to support Realtek RLE0599 phy controller SoC. + +config RTK_USB2PHY + tristate "Realtek USB2 PHY Controller Driver" + select USB_PHY + help + Enable this to support Realtek USB2 phy controller SoC. + +config RTK_USB3PHY + tristate "Realtek USB3 PHY Controller Driver" + select USB_PHY + help + Enable this to support Realtek USB3 phy controller SoC. + +endif # SYNO_LSP_RTD1619B endmenu diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index b352bdbe8712..a6966accc12f 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -25,3 +25,8 @@ obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o obj-$(CONFIG_JZ4770_PHY) += phy-jz4770.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTK_USB2PHY) += phy-rtk-usb2.o +obj-$(CONFIG_RTK_USB3PHY) += phy-rtk-usb3.o +obj-$(CONFIG_RTK_USB_RLE0599_PHY) += phy-rtk-rle0599.o +endif # CONFIG_SYNO_LSP_RTD1619B diff --git a/drivers/usb/phy/phy-rtk-rle0599.c b/drivers/usb/phy/phy-rtk-rle0599.c new file mode 100644 index 000000000000..65b78d115a36 --- /dev/null +++ b/drivers/usb/phy/phy-rtk-rle0599.c @@ -0,0 +1,740 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-rtk-rle0599.c RTK rle0599 usb2.0 phy driver + * + * copyright (c) 2017 realtek semiconductor corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-rtk-usb.h" +#ifdef CONFIG_USB_PATCH_ON_RTK +/* Add global lock for emmc issue*/ +//#include +#endif // CONFIG_USB_PATCH_ON_RTK + + +#define RTK_USB_RLE0599_PHY_NAME "rtk-usb-phy-rle0599" + +struct reg_addr { + void __iomem *REG_WRAP_VStatusOut2; + void __iomem *REG_EHCI_INSNREG05; +}; + +struct phy_data { + int page0_size; + struct rtk_usb_phy_data_s *page0; + int page1_size; + struct rtk_usb_phy_data_s *page1; + + bool do_toggle; + bool use_default_parameter; +}; + +#define WAIT_VBUSY_RETRY 3 + +#define OFFEST_PHY_READ 0x20 + +#define USB_ST_BUSY BIT(17) + +static DEFINE_SPINLOCK(rtk_phy_lock); + +static char rtk_usb_phy_read(struct rtk_usb_phy_s *rtk_phy, char addr) +{ + volatile unsigned int regVal; + struct reg_addr *regAddr = rtk_phy->reg_addr; + void __iomem *REG_EHCI_INSNREG05 = regAddr->REG_EHCI_INSNREG05; + + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = low nibble of addr, VLoadM = 1 + regVal = (1 << 13) | /* Port num */ + (1 << 12) | // vload + ((addr & 0x0f) << 8); // vcontrol + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = low nibble of addr, VLoadM = 0 + regVal &= ~(1 << 12); + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = high nibble of addr, VLoadM = 1 + regVal = (1 << 13) | /* Port num */ + (1 << 12) | // vload + ((addr & 0xf0) << 4); // vcontrol + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = high nibble of addr, VLoadM = 0 + regVal &= ~(1 << 12); + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + /* do smp_rmb */ + smp_rmb(); + regVal = phy_read(REG_EHCI_INSNREG05); + + return (char) (regVal & 0xff); +} + +static int rtk_usb_phy_write(struct rtk_usb_phy_s *rtk_phy, + char addr, char data) +{ + volatile unsigned int regVal; + struct reg_addr *regAddr = rtk_phy->reg_addr; + void __iomem *REG_WRAP_VStatusOut2 = regAddr->REG_WRAP_VStatusOut2; + void __iomem *REG_EHCI_INSNREG05 = regAddr->REG_EHCI_INSNREG05; + +#if 0//def CONFIG_USB_PATCH_ON_RTK + /* Add global lock for emmc issue*/ + unsigned long flags; + + rtk_lockapi_lock(flags, __func__); +#endif // CONFIG_USB_PATCH_ON_RTK + //write data to VStatusOut2 (data output to phy) + phy_write(REG_WRAP_VStatusOut2, (u32) data); +#if 0//def CONFIG_USB_PATCH_ON_RTK + /* Add global lock for emmc issue*/ + rtk_lockapi_unlock(flags, __func__); +#endif // CONFIG_USB_PATCH_ON_RTK + + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = low nibble of addr, VLoadM = 1 + regVal = (1 << 13) | /* Port num */ + (1 << 12) | // vload + ((addr & 0x0f) << 8); // vcontrol + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = low nibble of addr, VLoadM = 0 + regVal &= ~(1 << 12); + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = high nibble of addr, VLoadM = 1 + regVal = (1 << 13) | /* Port num */ + (1 << 12) | // vload + ((addr & 0xf0) << 4); // vcontrol + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + // VCtrl = high nibble of addr, VLoadM = 0 + regVal &= ~(1 << 12); + phy_write(REG_EHCI_INSNREG05, regVal); + utmi_wait_register(REG_EHCI_INSNREG05, USB_ST_BUSY, 0); + + return 0; +} + +static int rtk_usb_phy_set_page(struct rtk_usb_phy_s *rtk_phy, int page) +{ + return rtk_usb_phy_write(rtk_phy, 0xf4, page == 0 ? 0x9b : 0xbb); +} + +static int initialized; +void rtk_usb_phy_shutdown(struct usb_phy *phy) +{ + /* Todo */ + initialized = 0; +} + +void rtk_rle0599_phy_toggle(struct usb_phy *usb2_phy, bool isConnect); + +int rtk_usb_phy_init(struct usb_phy *phy) +{ + int i; + int ret = 0; + unsigned long flags; + struct rtk_usb_phy_s *rtk_phy = (struct rtk_usb_phy_s *)phy; + //struct reg_addr *regAddr = rtk_phy->reg_addr; + struct phy_data *phy_data = rtk_phy->phy_data; + struct rtk_usb_phy_data_s *phy_page0_default_setting = phy_data->page0; + struct rtk_usb_phy_data_s *phy_page1_default_setting = phy_data->page1; + + spin_lock_irqsave(&rtk_phy_lock, flags); + + if (initialized) + goto out; + + if (phy_data->use_default_parameter) { + dev_info(phy->dev, "%s phy use default parameter\n", + __func__); + goto do_toggle; + } + + dev_info(phy->dev, "Init RTK USB phy-rle0599\n"); + + /* Set page 0 */ + //printk("[%s:%d], Set page 0\n", __func__, __LINE__); + rtk_usb_phy_set_page(rtk_phy, 0); + + for (i = 0; i < phy_data->page0_size; i++) { + if (rtk_usb_phy_write(rtk_phy, + (phy_page0_default_setting + i)->addr, + (phy_page0_default_setting + i)->data)) { + dev_err(phy->dev, "[%s:%d], page0 Error : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + (phy_page0_default_setting + i)->addr, + (phy_page0_default_setting + i)->data); + ret = -1; + goto out; + } else { + dev_dbg(phy->dev, "[%s:%d], page0 Good : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + (phy_page0_default_setting + i)->addr, + rtk_usb_phy_read(rtk_phy, + (phy_page0_default_setting + i)->addr - + OFFEST_PHY_READ)); + } + } + + /* Set page 1 */ + //printk("[%s:%d], Set page 1\n", __func__, __LINE__); + rtk_usb_phy_set_page(rtk_phy, 1); + + for (i = 0; i < phy_data->page1_size; i++) { + if (rtk_usb_phy_write(rtk_phy, + (phy_page1_default_setting + i)->addr, + (phy_page1_default_setting + i)->data)) { + dev_err(phy->dev, "[%s:%d], page1 Error : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + (phy_page1_default_setting + i)->addr, + (phy_page1_default_setting + i)->data); + ret = -1; + goto out; + } else { + dev_dbg(phy->dev, "[%s:%d], page1 Good : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + (phy_page1_default_setting + i)->addr, + rtk_usb_phy_read(rtk_phy, + (phy_page1_default_setting + i)->addr - + OFFEST_PHY_READ)); + } + } + +do_toggle: + rtk_rle0599_phy_toggle(phy, false); + + initialized = 1; + + dev_info(phy->dev, "%s Initialized RTK USB PHY rle0599\n", __FILE__); +out: + spin_unlock_irqrestore(&rtk_phy_lock, flags); + return ret; +} + +void rtk_rle0599_phy_toggle(struct usb_phy *usb2_phy, bool isConnect) +{ + struct rtk_usb_phy_s *rtk_phy = NULL; + struct phy_data *phy_data = NULL; + int i; + struct rtk_usb_phy_data_s *phy_page0_default_setting; + struct rtk_usb_phy_data_s *phy_page1_default_setting; + + if (usb2_phy != NULL && usb2_phy->dev != NULL) + rtk_phy = dev_get_drvdata(usb2_phy->dev); + + if (rtk_phy == NULL) { + pr_err("%s %s ERROR! NO this device", __FILE__, __func__); + return; + } + + phy_data = rtk_phy->phy_data; + + if (!phy_data) { + pr_err("%s %s ERROR! phy_data is NULL", __FILE__, __func__); + return; + } + + if (!phy_data->do_toggle) + return; + + phy_page0_default_setting = phy_data->page0; + phy_page1_default_setting = phy_data->page1; + /* Set page 0 */ + rtk_usb_phy_set_page(rtk_phy, 0); + for (i = 0; i < phy_data->page0_size; i++) { + if ((phy_page0_default_setting + i)->addr == 0xE7) { + if (isConnect) { + rtk_usb_phy_write(rtk_phy, + (phy_page0_default_setting + i)->addr, + (phy_page0_default_setting + i)->data & + (~(BIT(4) | BIT(5) | BIT(6)))); + } else { + rtk_usb_phy_write(rtk_phy, + (phy_page0_default_setting + i)->addr, + (phy_page0_default_setting + i)->data | + (BIT(4) | BIT(5) | BIT(6))); + } + dev_dbg(rtk_phy->dev, "%s %sconnect to set Page0 0xE7 = %x\n", + __func__, + isConnect?"":"dis", + rtk_usb_phy_read(rtk_phy, + (phy_page0_default_setting + i)->addr)); + } + } + + /* Set page 1 */ + rtk_usb_phy_set_page(rtk_phy, 1); + + for (i = 0; i < phy_data->page1_size; i++) { + if ((phy_page1_default_setting + i)->addr == 0xe0) { + dev_info(rtk_phy->dev, "%s ########## to toggle Page1 addr 0xe0 BIT(2)\n", + __func__); + rtk_usb_phy_write(rtk_phy, + (phy_page1_default_setting + i)->addr, + ((phy_page1_default_setting + i)->data) & + (~BIT(2))); + mdelay(1); + rtk_usb_phy_write(rtk_phy, + (phy_page1_default_setting + i)->addr, + (phy_page1_default_setting + i)->data); + } + } +} +EXPORT_SYMBOL(rtk_rle0599_phy_toggle); + +#ifdef CONFIG_DEBUG_FS +static struct dentry *create_phy_debug_root(void) +{ + struct dentry *phy_debug_root; + + phy_debug_root = debugfs_lookup("phy", usb_debug_root); + if (!phy_debug_root) { + phy_debug_root = debugfs_create_dir("phy", usb_debug_root); + if (!phy_debug_root) + pr_err("%s Error phy_debug_root is NULL\n", __func__); + else + pr_info("%s Create phy_debug_root folder\n", __func__); + } + + return phy_debug_root; +} + +static int rtk_rle0599_parameter_show(struct seq_file *s, void *unused) +{ + struct rtk_usb_phy_s *rtk_phy = s->private; + struct phy_data *phy_data = rtk_phy->phy_data; + struct rtk_usb_phy_data_s *phy_page0_default_setting = phy_data->page0; + struct rtk_usb_phy_data_s *phy_page1_default_setting = phy_data->page1; + int i; + unsigned long flags; + + seq_puts(s, "Page 0:\n"); + spin_lock_irqsave(&rtk_phy_lock, flags); + /* Set page 0 */ + rtk_usb_phy_set_page(rtk_phy, 0); + + for (i = 0; i < phy_data->page0_size; i++) { + seq_printf(s, "Page 0: addr = 0x%x, value = 0x%x\n", + (phy_page0_default_setting + i)->addr, + rtk_usb_phy_read(rtk_phy, + (phy_page0_default_setting + i)->addr - + OFFEST_PHY_READ)); + } + + seq_puts(s, "Page 1:\n"); + /* Set page 1 */ + rtk_usb_phy_set_page(rtk_phy, 1); + + for (i = 0; i < phy_data->page1_size; i++) { + seq_printf(s, "Page 1: addr = 0x%x, value = 0x%x\n", + (phy_page1_default_setting + i)->addr, + rtk_usb_phy_read(rtk_phy, + (phy_page1_default_setting + i)->addr - + OFFEST_PHY_READ)); + } + + spin_unlock_irqrestore(&rtk_phy_lock, flags); + + return 0; +} + +static int rtk_rle0599_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_rle0599_parameter_show, inode->i_private); +} + +static const struct file_operations rtk_rle0599_parameter_fops = { + .open = rtk_rle0599_parameter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rtk_rle0599_set_parameter_show(struct seq_file *s, void *unused) +{ + //struct rtk_usb_phy_s *rtk_phy = s->private; + + seq_puts(s, "Set Phy parameter by following command\n"); + seq_puts(s, "echo \"page addr value\" > set_parameter\n"); + seq_puts(s, "echo \"page0 0xE1 0x30\" > set_parameter\n"); + seq_puts(s, "echo \"page1 0xE1 0xEF\" > set_parameter\n"); + + return 0; +} + +static int rtk_rle0599_set_parameter_open(struct inode *inode, + struct file *file) +{ + return single_open(file, rtk_rle0599_set_parameter_show, + inode->i_private); +} + +static ssize_t rtk_rle0599_set_parameter_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct rtk_usb_phy_s *rtk_phy = s->private; + struct phy_data *phy_data = rtk_phy->phy_data; + struct rtk_usb_phy_data_s *phy_page0_default_setting = phy_data->page0; + struct rtk_usb_phy_data_s *phy_page1_default_setting = phy_data->page1; + unsigned long flags; + char buffer[40]; + char *buf = buffer; + int i; + u32 addr; + u32 value; + + if (copy_from_user(&buffer, ubuf, + min_t(size_t, sizeof(buffer) - 1, count))) + return -EFAULT; + + spin_lock_irqsave(&rtk_phy_lock, flags); + if (!strncmp(buf, "page0", 5)) { + buf = buf + 5; + buf = skip_spaces(buf); + sscanf(buf, "%x %x", &addr, &value); + + rtk_usb_phy_set_page(rtk_phy, 0); + for (i = 0; i < phy_data->page0_size; i++) { + if ((phy_page0_default_setting + i)->addr == addr) { + int ret; + + (phy_page0_default_setting + i)->data = value; + ret = rtk_usb_phy_write(rtk_phy, + addr, value); + if (ret) + dev_err(rtk_phy->dev, "[%s:%d], page0 Error : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + addr, value); + else + dev_dbg(rtk_phy->dev, "[%s:%d], page0 Good : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + addr, + rtk_usb_phy_read(rtk_phy, + addr - OFFEST_PHY_READ)); + } + } + } else if (!strncmp(buf, "page1", 5)) { + buf = buf + 5; + buf = skip_spaces(buf); + sscanf(buf, "%x %x", &addr, &value); + + rtk_usb_phy_set_page(rtk_phy, 1); + for (i = 0; i < phy_data->page1_size; i++) { + if ((phy_page1_default_setting + i)->addr == addr) { + int ret; + + (phy_page1_default_setting + i)->data = value; + ret = rtk_usb_phy_write(rtk_phy, + addr, value); + if (ret) + dev_err(rtk_phy->dev, "[%s:%d], page1 Error : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + addr, value); + else + dev_dbg(rtk_phy->dev, "[%s:%d], page1 Good : addr = 0x%x, value = 0x%x\n", + __func__, __LINE__, + addr, + rtk_usb_phy_read(rtk_phy, + addr - OFFEST_PHY_READ)); + } + } + } else + dev_err(rtk_phy->dev, "UNKNOWN input (%s)", buf); + + spin_unlock_irqrestore(&rtk_phy_lock, flags); + return count; +} + +static const struct file_operations rtk_rle0599_set_parameter_fops = { + .open = rtk_rle0599_set_parameter_open, + .write = rtk_rle0599_set_parameter_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rtk_rle0599_toggle_show(struct seq_file *s, void *unused) +{ + //struct rtk_usb_phy_s *rtk_phy = s->private; + + seq_puts(s, "ehco 1 to toggle Page1 addr 0xe0 BIT(2)\n"); + + return 0; +} + +static int rtk_rle0599_toggle_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_rle0599_toggle_show, inode->i_private); +} + +static ssize_t rtk_rle0599_toggle_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct rtk_usb_phy_s *rtk_phy = s->private; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1)) + rtk_rle0599_phy_toggle(&rtk_phy->phy, false); + + return count; +} + +static const struct file_operations rtk_rle0599_toggle_fops = { + .open = rtk_rle0599_toggle_open, + .write = rtk_rle0599_toggle_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void create_debug_files(struct rtk_usb_phy_s *rtk_phy) +{ + struct dentry *phy_debug_root = NULL; + + dev_dbg(rtk_phy->dev, "%s", __func__); + + phy_debug_root = create_phy_debug_root(); + + if (!phy_debug_root) { + dev_err(rtk_phy->dev, "%s Error phy_debug_root is NULL", + __func__); + return; + } + + rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), + phy_debug_root); + if (!rtk_phy->debug_dir) { + dev_err(rtk_phy->dev, "%s Error debug_dir is NULL", __func__); + return; + } + + if (!debugfs_create_file("parameter", S_IRUGO, + rtk_phy->debug_dir, rtk_phy, + &rtk_rle0599_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("set_parameter", S_IRUGO | S_IWUSR, + rtk_phy->debug_dir, rtk_phy, + &rtk_rle0599_set_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("toggle", S_IRUGO | S_IWUSR, + rtk_phy->debug_dir, rtk_phy, + &rtk_rle0599_toggle_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(rtk_phy->debug_dir); +} +#endif //CONFIG_DEBUG_FS + +static int rtk_usb_rle0599_phy_probe(struct platform_device *pdev) +{ + struct rtk_usb_phy_s *rtk_usb_phy; + struct device *dev = &pdev->dev; + int ret = 0; + struct reg_addr *addr; + struct phy_data *phy_data; + int phy_data_page0_size, phy_data_page1_size; + + rtk_usb_phy = devm_kzalloc(dev, sizeof(*rtk_usb_phy), GFP_KERNEL); + if (!rtk_usb_phy) + return -ENOMEM; + + rtk_usb_phy->dev = &pdev->dev; + rtk_usb_phy->phy.dev = rtk_usb_phy->dev; + rtk_usb_phy->phy.label = RTK_USB_RLE0599_PHY_NAME; + rtk_usb_phy->phy.init = rtk_usb_phy_init; + rtk_usb_phy->phy.shutdown = rtk_usb_phy_shutdown; + + if (dev->of_node) { + ret = of_property_read_u32_index(dev->of_node, "phyN", 0, + &rtk_usb_phy->phyN); + if (ret) + goto err; + dev_dbg(dev, "%s %s phyN=%d\n", __FILE__, __func__, + rtk_usb_phy->phyN); + addr = devm_kzalloc(dev, sizeof(*addr), GFP_KERNEL); + if (!addr) + return -ENOMEM; + + addr->REG_WRAP_VStatusOut2 = of_iomap(dev->of_node, 0); + addr->REG_EHCI_INSNREG05 = of_iomap(dev->of_node, 1); + + rtk_usb_phy->reg_addr = addr; + + dev_dbg(dev, "%s %s REG_WRAP_VStatusOut2=%p\n", __FILE__, + __func__, addr->REG_WRAP_VStatusOut2); + dev_dbg(dev, "%s %s REG_EHCI_INSNREG05=%p\n", __FILE__, + __func__, addr->REG_EHCI_INSNREG05); + ret = of_property_read_u32_index(dev->of_node, + "phy_data_page0_size", 0, &phy_data_page0_size); + if (ret) + goto err; + ret = of_property_read_u32_index(dev->of_node, + "phy_data_page1_size", 0, &phy_data_page1_size); + if (ret) + goto err; + + dev_dbg(dev, "%s %s phy_data_page0_size=%d, phy_data_page1_size=%d\n", + __FILE__, __func__, + phy_data_page0_size, phy_data_page1_size); + } + + phy_data = devm_kzalloc(dev, sizeof(*phy_data), GFP_KERNEL); + if (!phy_data) + return -ENOMEM; + phy_data->page0_size = phy_data_page0_size; + phy_data->page0 = devm_kzalloc(dev, + sizeof(struct rtk_usb_phy_data_s)*phy_data_page0_size, + GFP_KERNEL); + if (!phy_data->page0) + return -ENOMEM; + phy_data->page1_size = phy_data_page1_size; + phy_data->page1 = devm_kzalloc(dev, + sizeof(struct rtk_usb_phy_data_s)*phy_data_page1_size, + GFP_KERNEL); + if (!phy_data->page1) + return -ENOMEM; + + if (dev->of_node) { + int i = 0; + char *tmp_addr = NULL; + char *tmp_data = NULL; + + tmp_addr = kzalloc(sizeof(char) * phy_data_page0_size, GFP_KERNEL); + tmp_data = kzalloc(sizeof(char) * phy_data_page0_size, GFP_KERNEL); + + ret = of_property_read_u8_array(dev->of_node, + "phy_data_page0_addr", tmp_addr, + phy_data_page0_size); + if (ret) + goto err; + ret = of_property_read_u8_array(dev->of_node, + "phy_data_page0_data", tmp_data, + phy_data_page0_size); + if (ret) + goto err; + for (i = 0; i < phy_data_page0_size; i++) { + struct rtk_usb_phy_data_s *phy_data_page0 = + (phy_data->page0 + i); + + phy_data_page0->addr = tmp_addr[i]; + phy_data_page0->data = tmp_data[i]; + } + ret = of_property_read_u8_array(dev->of_node, + "phy_data_page1_addr", tmp_addr, + phy_data_page1_size); + if (ret) + goto err; + ret = of_property_read_u8_array(dev->of_node, + "phy_data_page1_data", tmp_data, + phy_data_page1_size); + if (ret) + goto err; + for (i = 0; i < phy_data_page1_size; i++) { + struct rtk_usb_phy_data_s *phy_data_page1 = + (phy_data->page1 + i); + + phy_data_page1->addr = tmp_addr[i]; + phy_data_page1->data = tmp_data[i]; + } + rtk_usb_phy->phy_data = phy_data; + + if (of_property_read_bool(dev->of_node, "do_toggle")) + phy_data->do_toggle = true; + else + phy_data->do_toggle = false; + + if (of_property_read_bool(dev->of_node, + "use_default_parameter")) + phy_data->use_default_parameter = true; + else + phy_data->use_default_parameter = false; + + kfree(tmp_addr); + kfree(tmp_data); + } + + ret = usb_add_phy_dev(&rtk_usb_phy->phy); + if (ret) + goto err; + + platform_set_drvdata(pdev, rtk_usb_phy); + +#ifdef CONFIG_DEBUG_FS + create_debug_files(rtk_usb_phy); +#endif + + dev_info(&pdev->dev, "Probe RTK USB 2.0 RLE0599 PHY\n"); + +err: + return ret; +} + +static int rtk_usb_rle0599_phy_remove(struct platform_device *pdev) +{ + struct rtk_usb_phy_s *rtk_usb_phy = platform_get_drvdata(pdev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(rtk_usb_phy->debug_dir); +#endif + + usb_remove_phy(&rtk_usb_phy->phy); + + return 0; +} + +static const struct of_device_id usb_phy_rle0599_rtk_dt_ids[] = { + { .compatible = "realtek,rtd119x-usb_phy_rle0599", }, + { .compatible = "realtek,rtd129x-usb_phy_rle0599", }, + {}, +}; +MODULE_DEVICE_TABLE(of, usb_phy_rle0599_rtk_dt_ids); + +static struct platform_driver rtk_usb_rle0599_phy_driver = { + .probe = rtk_usb_rle0599_phy_probe, + .remove = rtk_usb_rle0599_phy_remove, + .driver = { + .name = RTK_USB_RLE0599_PHY_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(usb_phy_rle0599_rtk_dt_ids), + }, +}; + +module_platform_driver(rtk_usb_rle0599_phy_driver); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" RTK_USB_RLE0599_PHY_NAME); diff --git a/drivers/usb/phy/phy-rtk-usb.h b/drivers/usb/phy/phy-rtk-usb.h new file mode 100644 index 000000000000..90150f583995 --- /dev/null +++ b/drivers/usb/phy/phy-rtk-usb.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * phy-rtk-usb.h RTK usb phy header file + * + * copyright (c) 2017 realtek semiconductor corporation + * + */ + +#ifndef __PHY_RTK_USB_H__ +#define __PHY_RTK_USB_H__ + +struct rtk_usb_phy_s { + struct usb_phy phy; + struct device *dev; + + int port_index; + int phyN; + void *reg_addr; + void *phy_data; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debug_dir; +#endif +}; + +struct rtk_usb_phy_data_s { + char addr; + char data; +}; + +#define phy_read(addr) __raw_readl(addr) +#define phy_write(addr, val) do { \ + /* Do smp_wmb */ \ + smp_wmb(); __raw_writel(val, addr); \ +} while (0) +#define PHY_IO_TIMEOUT_MSEC (50) + +static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(PHY_IO_TIMEOUT_MSEC); + + while (time_before(jiffies, timeout)) { + /* Do smp_rmb */ + smp_rmb(); + if ((phy_read(reg) & mask) == result) + return 0; + udelay(100); + } + pr_err("\033[0;32;31m can't program USB phy \033[m\n"); + return -ETIMEDOUT; +} + +#endif /* __PHY_RTK_USB_H__ */ diff --git a/drivers/usb/phy/phy-rtk-usb2.c b/drivers/usb/phy/phy-rtk-usb2.c new file mode 100644 index 000000000000..7f493853941c --- /dev/null +++ b/drivers/usb/phy/phy-rtk-usb2.c @@ -0,0 +1,1586 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-rtk-usb2.c RTK usb2.0 PHY driver + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-rtk-usb.h" + +#define RTK_USB2PHY_NAME "rtk-usb2phy" + +#define OFFEST_PHY_READ 0x20 + +#define USB_ST_BUSY BIT(23) +#define MAX_PHY_DATA_SIZE 20 + +#define EFUS_USB_DC_CAL_RATE 2 +#define EFUS_USB_DC_CAL_MAX 7 +#define USB_DC_CAL_MASK 0x1F + +#define PAGE_START 0xE0 +#define PAGE0_0xE4 0xE4 +#define PAGE0_0xE7 0xE7 +#define PAGE1_0xE0 0xE0 +/* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */ +#define PAGE_ADDR_MAP_ARRAY_INDEX(addr) \ + (((addr - PAGE_START)&0x7) + \ + (((addr - PAGE_START)&0x10)>>1)) +#define ARRAY_INDEX_MAP_PAGE_ADDR(index) \ + (((index + PAGE_START)&0x7) + \ + (((index&0x8)<<1) + PAGE_START)) + +struct reg_addr { + void __iomem *REG_WRAP_VStatusOut2; + void __iomem *REG_GUSB2PHYACC0; + int vstatus_index; +}; + +struct phy_parameter { + u8 addr; + u8 data; +}; + +struct phy_data { + int page0_size; + struct phy_parameter *page0; + int page1_size; + struct phy_parameter *page1; + int page2_size; + struct phy_parameter *page2; + + bool check_efuse; + int8_t efuse_usb_dc_cal; + int efuse_usb_dc_cal_rate; + int usb_dc_cal_mask; + bool do_toggle; + bool use_default_parameter; + bool is_double_sensitivity_mode; + bool ldo_force_enable; + bool ldo_enable; + s32 ldo_page0_e4_compensate; +}; + +static char rtk_usb_phy_read(struct reg_addr *regAddr, char addr) +{ + unsigned int regVal; + void __iomem *REG_GUSB2PHYACC0 = regAddr->REG_GUSB2PHYACC0; + int ret = 0; + + addr -= OFFEST_PHY_READ; + + // polling until VBusy == 0 + ret = utmi_wait_register(REG_GUSB2PHYACC0, USB_ST_BUSY, 0); + if (ret) + return (char)ret; + + // VCtrl = low nibble of addr, VLoadM = 1 + regVal = BIT(25) | // vload + ((addr & 0x0f) << 8); // vcontrol + phy_write(REG_GUSB2PHYACC0, regVal); + ret = utmi_wait_register(REG_GUSB2PHYACC0, USB_ST_BUSY, 0); + if (ret) + return (char)ret; + + // VCtrl = high nibble of addr, VLoadM = 1 + regVal = BIT(25) | // vload + ((addr & 0xf0) << 4); // vcontrol + phy_write(REG_GUSB2PHYACC0, regVal); + ret = utmi_wait_register(REG_GUSB2PHYACC0, USB_ST_BUSY, 0); + if (ret) + return (char)ret; + + /* rmb for reg read */ + smp_rmb(); + regVal = phy_read(REG_GUSB2PHYACC0); + + return (char) (regVal & 0xff); +} + +static int rtk_usb_phy_write(struct reg_addr *regAddr, char addr, char data) +{ + unsigned int regVal; + void __iomem *REG_WRAP_VStatusOut2 = regAddr->REG_WRAP_VStatusOut2; + void __iomem *REG_GUSB2PHYACC0 = regAddr->REG_GUSB2PHYACC0; + int shift_bits = regAddr->vstatus_index * 8; + int ret = 0; + + //write data to VStatusOut2 (data output to phy) + phy_write(REG_WRAP_VStatusOut2, (u32)data<REG_GUSB2PHYACC0; + u8 addr = 0xF4; + u8 read_addr = addr - OFFEST_PHY_READ; + int use_ldo = 0; + volatile unsigned int val; + void __iomem *reg_usb_ctrl = ioremap(USB_CTRL, 0x4); + + if (!reg_usb_ctrl) { + pr_err("%s USB_CTRL ioremap fail\n", __func__); + return use_ldo; + } + + val = readl(reg_usb_ctrl); + if ((val & ISO_USB_U2PHY_REG_LDO_PW) == ISO_USB_U2PHY_REG_LDO_PW) { + pr_notice("%s phy use ldo power! (USB_CTRL val=0x%x)\n", + __func__, val); + use_ldo = 1; + goto out; + } + + // VCtrl = low nibble of addr, VLoadM = 1 + regVal = BIT(25) | // vload + ((read_addr & 0x0f) << 8); // vcontrol + phy_write(REG_GUSB2PHYACC0, regVal); + mdelay(1); + + // VCtrl = high nibble of addr, VLoadM = 1 + regVal = BIT(25) | // vload + ((read_addr & 0xf0) << 4); // vcontrol + phy_write(REG_GUSB2PHYACC0, regVal); + mdelay(1); + + /* rmb for reg read */ + smp_rmb(); + regVal = phy_read(REG_GUSB2PHYACC0); + + if ((regVal & 0xf) == 0x0 || phy_data->ldo_force_enable) { + val = readl(reg_usb_ctrl); + val |= ISO_USB_U2PHY_REG_LDO_PW; + writel(val, reg_usb_ctrl); + use_ldo = 1; + + mdelay(1); + phy_write(REG_GUSB2PHYACC0, BIT(25)); + + pr_notice("%s phy %s then turn on ldo! USB_CTRL val=0x%x\n", + __func__, + phy_data->ldo_force_enable? + " ldo_force_enable":"no power", + val); + pr_notice("check phy regVal=0x%x ==> regVal=0x%x\n", + regVal & 0xf, rtk_usb_phy_read(regAddr, addr)); + } + +out: + iounmap(reg_usb_ctrl); + return use_ldo; +} +#endif // CONFIG_USB_PATCH_ON_RTK + +static void rtk_usb2_phy_shutdown(struct usb_phy *phy) +{ + /* Todo */ +} + +static int __get_phy_parameter_by_efuse(struct rtk_usb_phy_s *rtk_phy, + struct phy_data *phy_data, int index) +{ + u8 value = 0; + struct nvmem_cell *cell; + int dc_cal_rate = phy_data->efuse_usb_dc_cal_rate; + + cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-cal"); + if (IS_ERR(cell)) { + dev_warn(rtk_phy->dev, "%s failed to get usb-dc-cal: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; + + buf = nvmem_cell_read(cell, &buf_size); + + value = buf[0] & phy_data->usb_dc_cal_mask; + + dev_dbg(rtk_phy->dev, + "buf=0x%x buf_size=%d value=0x%x\n", + buf[0], (int)buf_size, value); + + kfree(buf); + nvmem_cell_put(cell); + } + + if (value <= EFUS_USB_DC_CAL_MAX) + phy_data->efuse_usb_dc_cal = (int8_t)(value * dc_cal_rate); + else + phy_data->efuse_usb_dc_cal = -(int8_t)( + (EFUS_USB_DC_CAL_MAX & value) * dc_cal_rate); + + dev_info(rtk_phy->dev, "Get Efuse usb_dc_cal=%d for index=%d value=%x\n", + phy_data->efuse_usb_dc_cal, index, value); + + return 0; +} + +u8 __updated_page0_0xe4_parameter(struct phy_data *phy_data, u8 data) +{ + u8 val; + s32 __val; + s32 ldo_page0_e4_compensate = 0; + s32 usb_dc_cal_mask = phy_data->usb_dc_cal_mask; + + if (phy_data->ldo_enable) + ldo_page0_e4_compensate = phy_data->ldo_page0_e4_compensate; + + __val = (s32)(data & usb_dc_cal_mask) + ldo_page0_e4_compensate + + phy_data->efuse_usb_dc_cal; + + if (__val > usb_dc_cal_mask) + __val = usb_dc_cal_mask; + else if (__val < 0) + __val = 0; + + val = (data & (~usb_dc_cal_mask)) | (__val & usb_dc_cal_mask); + + return val; +} + +static void do_rtk_usb2_phy_toggle(struct rtk_usb_phy_s *rtk_phy, + int index, bool isConnect); + +static int do_rtk_usb2_phy_init(struct usb_phy *phy, int index) +{ + int i; + struct rtk_usb_phy_s *rtk_phy = (struct rtk_usb_phy_s *) phy; + struct reg_addr *regAddr; + struct phy_data *phy_data; + struct phy_parameter *phy_page_setting; + + if (!rtk_phy) { + pr_err("%s, rtk_phy is NULL\n", __func__); + return -EINVAL; + } + + dev_info(phy->dev, "%s Init RTK USB 2.0 PHY phy#%d\n", + __func__, index); + + regAddr = &((struct reg_addr *)rtk_phy->reg_addr)[index]; + phy_data = &((struct phy_data *)rtk_phy->phy_data)[index]; + + if (!phy_data) { + pr_err("%s, phy_data is NULL\n", __func__); + return -EINVAL; + } + +#ifdef CONFIG_USB_PATCH_ON_RTK + if (check_phy_power(phy_data, regAddr)) { + phy_data->ldo_enable = true; + dev_info(phy->dev, "%s USB phy use ldo power compensate phy parameter (%d)\n", + __func__, phy_data->ldo_page0_e4_compensate); + } +#endif // CONFIG_USB_PATCH_ON_RTK + + if (phy_data->use_default_parameter) { + dev_info(phy->dev, "%s phy#%d use default parameter\n", + __func__, index); + goto do_toggle; + } + + /* Get PAGE0_0xE4 default value */ + if (phy_data->efuse_usb_dc_cal || phy_data->ldo_page0_e4_compensate) { + phy_page_setting = phy_data->page0; + rtk_usb_phy_set_page(regAddr, 0); + + i = PAGE_ADDR_MAP_ARRAY_INDEX(PAGE0_0xE4); + if (i < phy_data->page0_size) { + u8 addr = (phy_page_setting + i)->addr; + u8 data = (phy_page_setting + i)->data; + + if (!addr) { + addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + data = rtk_usb_phy_read(regAddr, addr); + + (phy_page_setting + i)->addr = addr; + (phy_page_setting + i)->data = data; + dev_info(rtk_phy->dev, + "Get default addr %x value %x\n", + (phy_page_setting + i)->addr, + (phy_page_setting + i)->data); + } + } + } + + /* Set page 0 */ + phy_page_setting = phy_data->page0; + rtk_usb_phy_set_page(regAddr, 0); + + for (i = 0; i < phy_data->page0_size; i++) { + u8 addr = (phy_page_setting + i)->addr; + u8 data = (phy_page_setting + i)->data; + + if (!addr) + continue; + + if (addr == PAGE0_0xE4) + data = __updated_page0_0xe4_parameter(phy_data, data); + + if (rtk_usb_phy_write(regAddr, addr, data)) { + dev_err(phy->dev, + "[%s:%d] Error page0 addr=0x%x value=0x%x\n", + __func__, __LINE__, addr, data); + return -1; + } + dev_dbg(phy->dev, "[%s:%d] Good page0 addr=0x%x value=0x%x\n", + __func__, __LINE__, addr, + rtk_usb_phy_read(regAddr, addr)); + } + + /* Set page 1 */ + phy_page_setting = phy_data->page1; + rtk_usb_phy_set_page(regAddr, 1); + + for (i = 0; i < phy_data->page1_size; i++) { + u8 addr = (phy_page_setting + i)->addr; + u8 data = (phy_page_setting + i)->data; + + if (!addr) + continue; + + if (rtk_usb_phy_write(regAddr, addr, data)) { + dev_err(phy->dev, + "[%s:%d] Error page1 addr=0x%x value=0x%x\n", + __func__, __LINE__, + addr, data); + return -1; + } + dev_dbg(phy->dev, "[%s:%d] Good page1 addr=0x%x value=0x%x\n", + __func__, __LINE__, addr, + rtk_usb_phy_read(regAddr, addr)); + } + + if (phy_data->page2_size == 0) + goto do_toggle; + + /* Set page 2 */ + phy_page_setting = phy_data->page2; + rtk_usb_phy_set_page(regAddr, 2); + + for (i = 0; i < phy_data->page2_size; i++) { + u8 addr = (phy_page_setting + i)->addr; + u8 data = (phy_page_setting + i)->data; + + if (!addr) + continue; + + if (rtk_usb_phy_write(regAddr, addr, data)) { + dev_err(phy->dev, + "[%s:%d] Error page2 addr=0x%x value=0x%x\n", + __func__, __LINE__, addr, data); + return -1; + } + dev_dbg(phy->dev, "[%s:%d] Good page2 addr=0x%x value=0x%x\n", + __func__, __LINE__, + (phy_page_setting + i)->addr, + rtk_usb_phy_read(regAddr, + (phy_page_setting + i)->addr)); + } + +do_toggle: + do_rtk_usb2_phy_toggle(rtk_phy, index, false); + + return 0; +} + +static int rtk_usb2_phy_init(struct usb_phy *phy) +{ + struct rtk_usb_phy_s *rtk_phy = (struct rtk_usb_phy_s *) phy; + int i, ret = 0; + unsigned long phy_init_time = jiffies; + + dev_info(phy->dev, "%s Init RTK USB 2.0 PHY\n", __func__); + for (i = 0; i < rtk_phy->phyN; i++) + ret = do_rtk_usb2_phy_init(phy, i); + + dev_info(phy->dev, "%s Initialized RTK USB 2.0 PHY (take %dms)\n", + __func__, + jiffies_to_msecs(jiffies - phy_init_time)); + return ret; +} + +static void do_rtk_usb2_phy_toggle(struct rtk_usb_phy_s *rtk_phy, + int index, bool isConnect) +{ + struct reg_addr *regAddr; + struct phy_data *phy_data; + struct phy_parameter *phy_page_setting; + int i; + + if (!rtk_phy) { + pr_err("%s phy_data is NULL\n", __func__); + return; + } + + regAddr = &((struct reg_addr *)rtk_phy->reg_addr)[index]; + phy_data = &((struct phy_data *)rtk_phy->phy_data)[index]; + + if (!phy_data) { + dev_err(rtk_phy->dev, "%s phy_data is NULL\n", __func__); + return; + } + + if (!phy_data->do_toggle) + return; + + /* Set page 1 */ + phy_page_setting = phy_data->page1; + rtk_usb_phy_set_page(regAddr, 1); + + i = PAGE_ADDR_MAP_ARRAY_INDEX(PAGE1_0xE0); + + if (i < phy_data->page1_size) { + u8 addr = (phy_page_setting + i)->addr; + u8 data = (phy_page_setting + i)->data; + + if (!addr) { + addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + data = rtk_usb_phy_read(regAddr, addr); + + (phy_page_setting + i)->addr = addr; + (phy_page_setting + i)->data = data; + dev_dbg(rtk_phy->dev, + "Get default addr %x value %x\n", + (phy_page_setting + i)->addr, + (phy_page_setting + i)->data); + } + + dev_info(rtk_phy->dev, + "%s ########## to toggle PAGE1_0xE0 BIT(2)\n", + __func__); + rtk_usb_phy_write(regAddr, addr, data & (~BIT(2))); + mdelay(1); + rtk_usb_phy_write(regAddr, addr, data | (BIT(2))); + } else { + dev_err(rtk_phy->dev, + "ERROR: %s %d index=%d addr Not PAGE1_0xE0\n", + __func__, __LINE__, i); + } + + if (phy_data->is_double_sensitivity_mode) + return; + + /* Set page 0 */ + phy_page_setting = phy_data->page0; + rtk_usb_phy_set_page(regAddr, 0); + + i = PAGE_ADDR_MAP_ARRAY_INDEX(PAGE0_0xE7); + + if (i < phy_data->page0_size) { + u8 addr = (phy_page_setting + i)->addr; + u8 data = (phy_page_setting + i)->data; + + if (!addr) { + addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + data = rtk_usb_phy_read(regAddr, addr); + + (phy_page_setting + i)->addr = addr; + (phy_page_setting + i)->data = data; + dev_dbg(rtk_phy->dev, + "Get default addr %x value %x\n", + (phy_page_setting + i)->addr, + (phy_page_setting + i)->data); + } + + if (isConnect) { + rtk_usb_phy_write(regAddr, addr, data & + (~(BIT(4) | BIT(5) | BIT(6)))); + } else { + rtk_usb_phy_write(regAddr, addr, data | + (BIT(4) | BIT(5) | BIT(6))); + } + dev_info(rtk_phy->dev, + "%s %sconnect to set Page0 0xE7=%x\n", + __func__, + isConnect?"":"dis", + rtk_usb_phy_read(regAddr, addr)); + } else { + dev_err(rtk_phy->dev, + "ERROR: %s %d index=%d addr Not PAGE0_0xE4\n", + __func__, __LINE__, i); + } +} + +void rtk_usb2_phy_toggle(struct usb_phy *usb2_phy, bool isConnect, int port) +{ + int index = port; + struct rtk_usb_phy_s *rtk_phy = NULL; + + if (usb2_phy != NULL && usb2_phy->dev != NULL) + rtk_phy = dev_get_drvdata(usb2_phy->dev); + + if (rtk_phy == NULL) { + pr_err("%s %d ERROR! NO this device\n", __func__, __LINE__); + return; + } + if (index > rtk_phy->phyN) { + pr_err("%s %d ERROR! port=%d > phyN=%d\n", + __func__, __LINE__, index, rtk_phy->phyN); + return; + } + + do_rtk_usb2_phy_toggle(rtk_phy, index, isConnect); + +} +EXPORT_SYMBOL(rtk_usb2_phy_toggle); + +#ifdef CONFIG_DEBUG_FS +static struct dentry *create_phy_debug_root(void) +{ + struct dentry *phy_debug_root; + + phy_debug_root = debugfs_lookup("phy", usb_debug_root); + if (!phy_debug_root) { + phy_debug_root = debugfs_create_dir("phy", usb_debug_root); + if (!phy_debug_root) + pr_err("%s Error phy_debug_root is NULL\n", __func__); + else + pr_info("%s Create phy_debug_root folder\n", __func__); + } + + return phy_debug_root; +} + +static int rtk_usb2_parameter_show(struct seq_file *s, void *unused) +{ + struct rtk_usb_phy_s *rtk_phy = s->private; + int i, index; + + for (index = 0; index < rtk_phy->phyN; index++) { + struct reg_addr *regAddr = + &((struct reg_addr *)rtk_phy->reg_addr)[index]; + struct phy_data *phy_data = + &((struct phy_data *)rtk_phy->phy_data)[index]; + struct phy_parameter *phy_page_setting; + + seq_printf(s, "PHY %d:\n", index); + + seq_puts(s, "Page 0:\n"); + /* Set page 0 */ + phy_page_setting = phy_data->page0; + rtk_usb_phy_set_page(regAddr, 0); + + for (i = 0; i < phy_data->page0_size; i++) { + u8 addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + u8 data = (phy_page_setting + i)->data; + u8 value = rtk_usb_phy_read(regAddr, addr); + + if ((phy_page_setting + i)->addr) + seq_printf(s, "Page 0: addr=0x%x data=0x%02x ==> read value=0x%02x\n", + addr, data, value); + else + seq_printf(s, "Page 0: addr=0x%x data=none ==> read value=0x%02x\n", + addr, value); + } + + seq_puts(s, "Page 1:\n"); + /* Set page 1 */ + phy_page_setting = phy_data->page1; + rtk_usb_phy_set_page(regAddr, 1); + + for (i = 0; i < phy_data->page1_size; i++) { + u8 addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + u8 data = (phy_page_setting + i)->data; + u8 value = rtk_usb_phy_read(regAddr, addr); + + if ((phy_page_setting + i)->addr) + seq_printf(s, "Page 1: addr=0x%x data=0x%02x ==> read value=0x%02x\n", + addr, data, value); + else + seq_printf(s, "Page 1: addr=0x%x data=none ==> read value=0x%02x\n", + addr, value); + } + + if (phy_data->page2_size == 0) + goto out; + + seq_puts(s, "Page 2:\n"); + /* Set page 2 */ + phy_page_setting = phy_data->page2; + rtk_usb_phy_set_page(regAddr, 2); + + for (i = 0; i < phy_data->page2_size; i++) { + u8 addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + u8 data = (phy_page_setting + i)->data; + u8 value = rtk_usb_phy_read(regAddr, addr); + + if ((phy_page_setting + i)->addr) + seq_printf(s, "Page 2: addr=0x%x data=0x%02x ==> read value=0x%02x\n", + addr, data, value); + else + seq_printf(s, "Page 2: addr=0x%x data=none ==> read value=0x%02x\n", + addr, value); + } + seq_printf(s, "Property:\n"); + seq_printf(s, "check_efuse: %s\n", + phy_data->check_efuse?"Enable":"Disable"); + seq_printf(s, "efuse_usb_dc_cal: %d\n", + (int)phy_data->efuse_usb_dc_cal); + seq_printf(s, "efuse_usb_dc_cal_rate: %d\n", + phy_data->efuse_usb_dc_cal_rate); + seq_printf(s, "usb_dc_cal_mask: 0x%x\n", + phy_data->usb_dc_cal_mask); + seq_printf(s, "do_toggle: %s\n", + phy_data->do_toggle?"Enable":"Disable"); + seq_printf(s, "use_default_parameter: %s\n", + phy_data->use_default_parameter?"Enable":"Disable"); + seq_printf(s, "is_double_sensitivity_mode: %s\n", + phy_data->is_double_sensitivity_mode?"Enable":"Disable"); + seq_printf(s, "ldo_force_enable: %s\n", + phy_data->ldo_force_enable?"Enable":"Disable"); + seq_printf(s, "ldo_enable: %s\n", + phy_data->ldo_enable?"Enable":"Disable"); + seq_printf(s, "ldo_page0_e4_compensate: %d\n", + phy_data->ldo_page0_e4_compensate); + } + +out: + return 0; +} + +static int rtk_usb2_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb2_parameter_show, inode->i_private); +} + +static const struct file_operations rtk_usb2_parameter_fops = { + .open = rtk_usb2_parameter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rtk_usb2_set_parameter_show(struct seq_file *s, void *unused) +{ + //struct rtk_usb_phy_s *rtk_phy = s->private; + + seq_puts(s, "Set Phy parameter by following command\n"); + seq_puts(s, "echo \"phy_num page addr value\" > set_parameter\n"); + seq_puts(s, "echo \"0 page0 0xE1 0x30\" > set_parameter\n"); + seq_puts(s, "echo \"0 page1 0xE1 0xEF\" > set_parameter\n"); + + return 0; +} + +static int rtk_usb2_set_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb2_set_parameter_show, inode->i_private); +} + +static ssize_t rtk_usb2_set_parameter_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct rtk_usb_phy_s *rtk_phy = s->private; + struct reg_addr *regAddr; + struct phy_data *phy_data; + struct phy_parameter *phy_page_setting; + int page_size = 0; + int ret = 0; + char buffer[40]; + char *buf = buffer; + int i, index; + u32 addr; + u32 value; + + if (copy_from_user(&buffer, ubuf, + min_t(size_t, sizeof(buffer) - 1, count))) + return -EFAULT; + + ret = kstrtoint(buf, 0, &index); + if (ret < 0) + return -EFAULT; + + buf = buf + 2; + regAddr = &((struct reg_addr *)rtk_phy->reg_addr)[index]; + phy_data = &((struct phy_data *)rtk_phy->phy_data)[index]; + + if (!strncmp(buf, "page0", 5)) { + buf = buf + 5; + buf = skip_spaces(buf); + ret = sscanf(buf, "%x %x", &addr, &value); + if (ret < 0) + return -EFAULT; + + phy_page_setting = phy_data->page0; + page_size = phy_data->page0_size; + rtk_usb_phy_set_page(regAddr, 0); + dev_dbg(rtk_phy->dev, "%s page0 addr = 0x%x, value = 0x%x\n", + __func__, addr, value); + + } else if (!strncmp(buf, "page1", 5)) { + buf = buf + 5; + buf = skip_spaces(buf); + ret = sscanf(buf, "%x %x", &addr, &value); + if (ret < 0) + return -EFAULT; + + phy_page_setting = phy_data->page1; + page_size = phy_data->page1_size; + rtk_usb_phy_set_page(regAddr, 1); + dev_dbg(rtk_phy->dev, "%s page1 addr = 0x%x, value = 0x%x\n", + __func__, addr, value); + } else if (!strncmp(buf, "page2", 5)) { + buf = buf + 5; + buf = skip_spaces(buf); + ret = sscanf(buf, "%x %x", &addr, &value); + if (ret < 0) + return -EFAULT; + + phy_page_setting = phy_data->page2; + page_size = phy_data->page2_size; + rtk_usb_phy_set_page(regAddr, 2); + dev_dbg(rtk_phy->dev, "%s page2 addr = 0x%x, value = 0x%x\n", + __func__, addr, value); + } else { + dev_err(rtk_phy->dev, "UNKNOWN input (%s)", buf); + } + + for (i = 0; i < page_size; i++) { + u8 i2addr = ARRAY_INDEX_MAP_PAGE_ADDR(i); + + if (i2addr == addr) { + (phy_page_setting + i)->addr = addr; + (phy_page_setting + i)->data = value; + if (rtk_usb_phy_write(regAddr, addr, value)) + dev_err(rtk_phy->dev, + "[%s:%d] Error: addr=0x%x value=0x%x\n", + __func__, __LINE__, addr, value); + else + dev_dbg(rtk_phy->dev, + "[%s:%d] Good: addr=0x%x value=0x%x\n", + __func__, __LINE__, addr, + rtk_usb_phy_read(regAddr, addr)); + } + } + + return count; +} + +static const struct file_operations rtk_usb2_set_parameter_fops = { + .open = rtk_usb2_set_parameter_open, + .write = rtk_usb2_set_parameter_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rtk_usb2_toggle_show(struct seq_file *s, void *unused) +{ + struct rtk_usb_phy_s *rtk_phy = s->private; + struct phy_data *phy_data; + int i; + + for (i = 0; i < rtk_phy->phyN; i++) { + phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + seq_printf(s, "Now phy#%d do_toggle is %s.\n", + i, phy_data->do_toggle?"Enable":"Disable"); + } + seq_puts(s, "ehco 1 to enable toggle phy parameter.\n"); + + return 0; +} + +static int rtk_usb2_toggle_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb2_toggle_show, inode->i_private); +} + +static ssize_t rtk_usb2_toggle_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct rtk_usb_phy_s *rtk_phy = s->private; + char buf[32]; + struct phy_data *phy_data; + bool enable = false; + int i; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1)) + enable = true; + + for (i = 0; i < rtk_phy->phyN; i++) { + phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + phy_data->do_toggle = enable; + dev_info(rtk_phy->dev, "Set phy#%d do_toggle is %s.\n", + i, phy_data->do_toggle?"Enable":"Disable"); + } + + return count; +} + +static const struct file_operations rtk_usb2_toggle_fops = { + .open = rtk_usb2_toggle_open, + .write = rtk_usb2_toggle_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void create_debug_files(struct rtk_usb_phy_s *rtk_phy) +{ + struct dentry *phy_debug_root = NULL; + + dev_dbg(rtk_phy->dev, "%s", __func__); + + phy_debug_root = create_phy_debug_root(); + + if (!phy_debug_root) { + dev_err(rtk_phy->dev, "%s Error phy_debug_root is NULL", + __func__); + return; + } + + rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), + phy_debug_root); + if (!rtk_phy->debug_dir) { + dev_err(rtk_phy->dev, "%s Error debug_dir is NULL", __func__); + return; + } + + if (!debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy, + &rtk_usb2_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("set_parameter", 0644, + rtk_phy->debug_dir, rtk_phy, &rtk_usb2_set_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("toggle", 0644, + rtk_phy->debug_dir, rtk_phy, &rtk_usb2_toggle_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(rtk_phy->debug_dir); +} +#endif //CONFIG_DEBUG_FS + +#define DEFAULT_CHIP_REVISION 0xA00 +#define MAX_CHIP_REVISION 0xC00 + +static int __get_chip_revision(void) +{ + int chip_revision = 0xFFF; + char revision[] = "FFF"; + struct soc_device_attribute soc_att[] = {{.revision = revision}, {}}; + struct soc_device_attribute *soc_att_match = NULL; + + while (soc_att_match == NULL) { + chip_revision--; + + if (chip_revision <= DEFAULT_CHIP_REVISION) + break; + if (chip_revision > MAX_CHIP_REVISION) + chip_revision = MAX_CHIP_REVISION; + else if ((chip_revision & 0xFF) > 0xF) + chip_revision = (chip_revision & 0xF00) + 0xF; + + snprintf(revision, 4, "%X", chip_revision); + + soc_att_match = (struct soc_device_attribute *) + soc_device_match(soc_att); + } + + if (soc_att_match) { + pr_debug("%s get chip_revision %x\n", __func__, chip_revision); + return chip_revision; + } + + pr_debug("%s: Use default chip_revision %x\n", __func__, + DEFAULT_CHIP_REVISION); + return DEFAULT_CHIP_REVISION; +} + +static int __get_phy_parameter_v1(struct device *dev, struct phy_data *phy_data, + struct device_node *sub_node) +{ + int phy_data_page0_size, phy_data_page1_size; + int phy_data_page2_size; + char tmp_addr[MAX_PHY_DATA_SIZE]; + char tmp_data[MAX_PHY_DATA_SIZE]; + int i, chip_revision, revision, ret = 0; + + chip_revision = __get_chip_revision(); + + dev_dbg(dev, "%s: Chip revision is %x\n", __func__, chip_revision); + + ret = of_property_read_u32_index(sub_node, + "phy_data_page0_size", 0, &phy_data_page0_size); + if (ret) + goto err; + + ret = of_property_read_u32_index(sub_node, + "phy_data_page1_size", 0, &phy_data_page1_size); + if (ret) + goto err; + + dev_dbg(dev, "%s %d phy_data_page0_size=%d, phy_data_page1_size=%d\n", + __func__, __LINE__, + phy_data_page0_size, phy_data_page1_size); + + if (phy_data_page0_size > MAX_PHY_DATA_SIZE || + phy_data_page1_size > MAX_PHY_DATA_SIZE) { + dev_err(dev, "%s phy_data size > MAX_PHY_DATA_SIZE\n", + __func__); + goto err; + } + + ret = of_property_read_u32_index(sub_node, + "phy_data_page2_size", 0, &phy_data_page2_size); + if (ret) + phy_data_page2_size = 0; + dev_dbg(dev, "%s %d phy_data_page2_size=%d\n", + __func__, __LINE__, + phy_data_page2_size); + + if (phy_data_page2_size > MAX_PHY_DATA_SIZE) { + dev_err(dev, "%s page2 phy_data size=%d > MAX_PHY_DATA_SIZE\n", + __func__, phy_data_page2_size); + goto err; + } + + phy_data->page0_size = phy_data_page0_size; + phy_data->page0 = devm_kzalloc(dev, + sizeof(struct phy_parameter) * + phy_data_page0_size, + GFP_KERNEL); + if (!phy_data->page0) { + ret = -ENOMEM; + goto err; + } + + phy_data->page1_size = phy_data_page1_size; + phy_data->page1 = devm_kzalloc(dev, + sizeof(struct phy_parameter) * + phy_data_page1_size, + GFP_KERNEL); + if (!phy_data->page1) { + ret = -ENOMEM; + goto err; + } + + phy_data->page2_size = phy_data_page2_size; + if (phy_data->page2_size > 0) { + phy_data->page2 = devm_kzalloc(dev, + sizeof(struct phy_parameter) * + phy_data->page2_size, + GFP_KERNEL); + if (!phy_data->page2) { + ret = -ENOMEM; + goto err; + } + } + + ret = of_property_read_u8_array(sub_node, "phy_data_page0_addr", + tmp_addr, phy_data_page0_size); + if (ret) + goto err; + + revision = chip_revision; + while (revision >= DEFAULT_CHIP_REVISION) { + char phy_data_revision[20] = {0}; + + snprintf(phy_data_revision, 19, "phy_data_page0_%X", revision); + + ret = of_property_read_u8_array(sub_node, phy_data_revision, + tmp_data, phy_data_page0_size); + if (!ret) { + dev_dbg(dev, "%s load %s parameter\n", + __func__, phy_data_revision); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + } + + /* For old device tree */ + if (ret) { + ret = of_property_read_u8_array(sub_node, "phy_data_page0_data", + tmp_data, phy_data_page0_size); + if (ret) + goto err; + else + dev_info(dev, "%s load page0 parameter\n", + __func__); + } + + for (i = 0; i < phy_data_page0_size; i++) { + struct phy_parameter *phy_data_page0 = + (phy_data->page0 + i); + + phy_data_page0->addr = tmp_addr[i]; + phy_data_page0->data = tmp_data[i]; + } + + ret = of_property_read_u8_array(sub_node, "phy_data_page1_addr", + tmp_addr, phy_data_page1_size); + if (ret) + goto err; + + revision = chip_revision; + while (revision >= DEFAULT_CHIP_REVISION) { + char phy_data_revision[20] = {0}; + + snprintf(phy_data_revision, 19, "phy_data_page1_%X", revision); + + ret = of_property_read_u8_array(sub_node, phy_data_revision, + tmp_data, phy_data_page1_size); + if (!ret) { + dev_dbg(dev, "%s load %s parameter\n", + __func__, phy_data_revision); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + } + + /* For old device tree */ + if (ret) { + ret = of_property_read_u8_array(sub_node, "phy_data_page1_data", + tmp_data, phy_data_page1_size); + if (ret) + goto err; + else + dev_info(dev, "%s load page1 parameter\n", + __func__); + } + + for (i = 0; i < phy_data_page1_size; i++) { + struct phy_parameter *phy_data_page1 = + (phy_data->page1 + i); + + phy_data_page1->addr = tmp_addr[i]; + phy_data_page1->data = tmp_data[i]; + } + + if (phy_data->page2_size > 0) { + ret = of_property_read_u8_array(sub_node, + "phy_data_page2_addr", + tmp_addr, phy_data->page2_size); + if (ret) + goto err; + + revision = chip_revision; + while (revision >= DEFAULT_CHIP_REVISION) { + char phy_data_revision[20] = {0}; + + snprintf(phy_data_revision, 19, "phy_data_page2_%X", + revision); + + ret = of_property_read_u8_array(sub_node, + phy_data_revision, + tmp_data, phy_data_page2_size); + if (!ret) { + dev_dbg(dev, "%s load %s parameter\n", + __func__, phy_data_revision); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + } + + /* For old device tree */ + if (ret) { + ret = of_property_read_u8_array(sub_node, + "phy_data_page2_data", + tmp_data, phy_data->page2_size); + if (ret) + goto err; + else + dev_info(dev, "%s load page2 parameter\n", + __func__); + } + for (i = 0; i < phy_data->page2_size; i++) { + struct phy_parameter *phy_data_page2 = + (phy_data->page2 + i); + phy_data_page2->addr = tmp_addr[i]; + phy_data_page2->data = tmp_data[i]; + } + } + +err: + return ret; +} + +static int __get_phy_parameter_v2(struct device *dev, struct phy_data *phy_data, + struct device_node *sub_node) +{ + u32 page_size = 0; + u32 num_cells = 2; /*< addr value > */ + u32 data_size; + int i, offset, chip_revision, revision, ret = 0; + char phy_data_revision[15] = {0}; + + chip_revision = __get_chip_revision(); + + /* Page 0 */ + ret = of_property_read_u32_index(sub_node, "page0_size", 0, &page_size); + if (ret) { + dev_err(dev, "%s No page0_size\n", __func__); + goto parse_page1; + } + + phy_data->page0_size = page_size; + phy_data->page0 = devm_kzalloc(dev, + sizeof(struct phy_parameter) * page_size, GFP_KERNEL); + if (!phy_data->page0) { + ret = -ENOMEM; + goto out; + } + + revision = chip_revision; + while (revision >= DEFAULT_CHIP_REVISION) { + snprintf(phy_data_revision, 15, "page0_data_%X", revision); + + if (of_get_property(sub_node, phy_data_revision, &data_size)) { + dev_dbg(dev, "%s load %s parameter (data_size=%d)\n", + __func__, phy_data_revision, data_size); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + + data_size = 0; + ret = 0; + } + data_size = data_size / (sizeof(u32) * num_cells); + + for (i = 0; i < data_size; i++) { + struct phy_parameter *phy_data_page; + u32 addr, data; + int index; + + offset = i * num_cells; + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset, &addr); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, addr); + break; + } + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset + 1, &data); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, data); + break; + } + + index = PAGE_ADDR_MAP_ARRAY_INDEX(addr); + phy_data_page = (phy_data->page0 + index); + phy_data_page->addr = (char)addr; + phy_data_page->data = (char)data; + + dev_dbg(dev, "%s index=%d addr=0x%x data=0x%x\n", + phy_data_revision, index, + phy_data_page->addr, phy_data_page->data); + } + +parse_page1: + /* Page 1 */ + ret = of_property_read_u32_index(sub_node, "page1_size", 0, &page_size); + if (ret) { + dev_err(dev, "%s No page0_size\n", __func__); + goto parse_page2; + } + + phy_data->page1_size = page_size; + phy_data->page1 = devm_kzalloc(dev, + sizeof(struct rtk_usb_phy_data_s) * page_size, GFP_KERNEL); + if (!phy_data->page1) { + ret = -ENOMEM; + goto out; + } + + revision = chip_revision; + while (revision >= DEFAULT_CHIP_REVISION) { + snprintf(phy_data_revision, 15, "page1_data_%X", revision); + + if (of_get_property(sub_node, phy_data_revision, &data_size)) { + dev_dbg(dev, "%s load %s parameter (data_size=%d)\n", + __func__, phy_data_revision, data_size); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + + data_size = 0; + ret = 0; + } + data_size = data_size / (sizeof(u32) * num_cells); + + for (i = 0; i < data_size; i++) { + struct phy_parameter *phy_data_page; + u32 addr, data; + int index; + + offset = i * num_cells; + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset, &addr); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, addr); + break; + } + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset + 1, &data); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, data); + break; + } + + index = PAGE_ADDR_MAP_ARRAY_INDEX(addr); + phy_data_page = phy_data->page1 + index; + phy_data_page->addr = (char)addr; + phy_data_page->data = (char)data; + + dev_dbg(dev, "%s index=%d addr=0x%x data=0x%x\n", + phy_data_revision, index, + phy_data_page->addr, phy_data_page->data); + } + +parse_page2: + /* Page 2 */ + ret = of_property_read_u32_index(sub_node, "page2_size", 0, &page_size); + if (ret) { + dev_dbg(dev, "%s No page2_size\n", __func__); + goto out; + } + + phy_data->page2_size = page_size; + phy_data->page2 = devm_kzalloc(dev, + sizeof(struct rtk_usb_phy_data_s) * page_size, GFP_KERNEL); + if (!phy_data->page2) { + ret = -ENOMEM; + goto out; + } + + revision = chip_revision; + while (revision >= DEFAULT_CHIP_REVISION) { + snprintf(phy_data_revision, 15, "page2_data_%X", revision); + + if (of_get_property(sub_node, phy_data_revision, &data_size)) { + dev_dbg(dev, "%s load %s parameter (data_size=%d)\n", + __func__, phy_data_revision, data_size); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + + data_size = 0; + ret = 0; + } + data_size = data_size / (sizeof(u32) * num_cells); + + for (i = 0; i < data_size; i++) { + struct phy_parameter *phy_data_page; + u32 addr, data; + int index; + + offset = i * num_cells; + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset, &addr); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, addr); + break; + } + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset + 1, &data); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, data); + break; + } + + index = PAGE_ADDR_MAP_ARRAY_INDEX(addr); + phy_data_page = phy_data->page2 + index; + phy_data_page->addr = (char)addr; + phy_data_page->data = (char)data; + + dev_dbg(dev, "%s index=%d addr=0x%x data=0x%x\n", + phy_data_revision, index, + phy_data_page->addr, phy_data_page->data); + } + +out: + return ret; +} + +static int __get_phy_parameter(struct rtk_usb_phy_s *rtk_usb_phy, int index) +{ + struct device *dev = rtk_usb_phy->dev; + struct reg_addr *addr = + &((struct reg_addr *)rtk_usb_phy->reg_addr)[index]; + struct phy_data *phy_data = + &((struct phy_data *)rtk_usb_phy->phy_data)[index]; + char phy_name[5], phy_name_v2[10]; + struct device_node *sub_node; + int ret = 0; + + addr->REG_WRAP_VStatusOut2 = of_iomap(dev->of_node, 0); + addr->REG_GUSB2PHYACC0 = of_iomap(dev->of_node, index + 1); + addr->vstatus_index = index; + dev_dbg(dev, "%s %d #%d REG_WRAP_VStatusOut2=%p\n", + __func__, __LINE__, + index, addr->REG_WRAP_VStatusOut2); + dev_dbg(dev, "%s %d #%d REG_GUSB2PHYACC0=%p\n", + __func__, __LINE__, + index, addr->REG_GUSB2PHYACC0); + + snprintf(phy_name, 5, "phy%d", index); + + sub_node = of_get_child_by_name(dev->of_node, phy_name); + if (sub_node) { + dev_info(dev, "%s %d: #%d Get phy data v1 sub_node for %s\n", + __func__, __LINE__, index, phy_name); + ret = __get_phy_parameter_v1(dev, phy_data, sub_node); + if (ret) + goto err; + } else { + snprintf(phy_name_v2, 10, "phy%d_data", index); + sub_node = of_get_child_by_name(dev->of_node, phy_name_v2); + if (sub_node) { + dev_info(dev, "%s %d: #%d Get phy data v2 sub_node for %s\n", + __func__, __LINE__, index, phy_name_v2); + ret = __get_phy_parameter_v2(dev, phy_data, sub_node); + if (ret) + goto err; + } + } + + if (!sub_node) + goto err; + + if (of_property_read_bool(sub_node, "do_toggle")) + phy_data->do_toggle = true; + else + phy_data->do_toggle = false; + + if (of_property_read_bool(sub_node, "check_efuse")) + phy_data->check_efuse = true; + else + phy_data->check_efuse = false; + + if (of_property_read_bool(sub_node, "use_default_parameter")) + phy_data->use_default_parameter = true; + else + phy_data->use_default_parameter = false; + + if (of_property_read_bool(sub_node, + "is_double_sensitivity_mode")) + phy_data->is_double_sensitivity_mode = true; + else + phy_data->is_double_sensitivity_mode = false; + + if (of_property_read_bool(sub_node, + "ldo_force_enable")) + phy_data->ldo_force_enable = true; + else + phy_data->ldo_force_enable = false; + + if (of_property_read_s32(sub_node, + "ldo_page0_e4_compensate", &phy_data->ldo_page0_e4_compensate)) + phy_data->ldo_page0_e4_compensate = 0; + + phy_data->efuse_usb_dc_cal_rate = EFUS_USB_DC_CAL_RATE; + + if (of_property_read_s32(sub_node, + "usb_dc_cal_mask", &phy_data->usb_dc_cal_mask)) + phy_data->usb_dc_cal_mask = USB_DC_CAL_MASK; + + if (phy_data->check_efuse) + __get_phy_parameter_by_efuse(rtk_usb_phy, phy_data, index); + +err: + return ret; +} + +static int rtk_usb2phy_probe(struct platform_device *pdev) +{ + struct rtk_usb_phy_s *rtk_usb_phy; + struct device *dev = &pdev->dev; + int index, ret = 0; + int port_index, phyN; + + rtk_usb_phy = devm_kzalloc(dev, sizeof(*rtk_usb_phy), GFP_KERNEL); + if (!rtk_usb_phy) + return -ENOMEM; + + rtk_usb_phy->dev = &pdev->dev; + rtk_usb_phy->phy.dev = rtk_usb_phy->dev; + rtk_usb_phy->phy.label = RTK_USB2PHY_NAME; + rtk_usb_phy->phy.init = rtk_usb2_phy_init; + rtk_usb_phy->phy.shutdown = rtk_usb2_phy_shutdown; + + if (!dev->of_node) { + dev_err(dev, "%s %d No device node\n", __func__, __LINE__); + goto err; + } + + ret = of_property_read_u32_index(dev->of_node, "port_index", 0, + &port_index); + if (ret) + port_index = -1; + + ret = of_property_read_u32_index(dev->of_node, "phyN", 0, + &phyN); + if (ret) + goto err; + + dev_dbg(dev, "%s %d port_index=%d phyN=%d\n", + __func__, __LINE__, port_index, phyN); + + rtk_usb_phy->port_index = port_index; + rtk_usb_phy->phyN = phyN; + rtk_usb_phy->reg_addr = devm_kzalloc(dev, + sizeof(struct reg_addr) * phyN, GFP_KERNEL); + if (!rtk_usb_phy->reg_addr) + return -ENOMEM; + + rtk_usb_phy->phy_data = devm_kzalloc(dev, + sizeof(struct phy_data) * phyN, + GFP_KERNEL); + + if (!rtk_usb_phy->phy_data) + return -ENOMEM; + + for (index = 0; index < phyN; index++) { + ret = __get_phy_parameter(rtk_usb_phy, index); + if (ret) { + dev_err(dev, "%s %d: __get_phy_parameter fail ret=%d\n", + __func__, __LINE__, ret); + goto err; + } + } + + platform_set_drvdata(pdev, rtk_usb_phy); + + ret = usb_add_phy_dev(&rtk_usb_phy->phy); + if (ret) + goto err; + +#ifdef CONFIG_DEBUG_FS + create_debug_files(rtk_usb_phy); +#endif + + dev_info(&pdev->dev, "%s Probe RTK USB 2.0 PHY\n", __FILE__); +err: + return ret; +} + +static int rtk_usb2phy_remove(struct platform_device *pdev) +{ + struct rtk_usb_phy_s *rtk_usb_phy = platform_get_drvdata(pdev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(rtk_usb_phy->debug_dir); +#endif + + usb_remove_phy(&rtk_usb_phy->phy); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id usbphy_rtk_dt_match[] = { + { .compatible = "realtek,usb2phy", }, + {}, +}; +MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); +#endif + +static struct platform_driver rtk_usb2phy_driver = { + .probe = rtk_usb2phy_probe, + .remove = rtk_usb2phy_remove, + .driver = { + .name = RTK_USB2PHY_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(usbphy_rtk_dt_match), + }, +}; + +module_platform_driver(rtk_usb2phy_driver); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" RTK_USB2PHY_NAME); diff --git a/drivers/usb/phy/phy-rtk-usb3.c b/drivers/usb/phy/phy-rtk-usb3.c new file mode 100644 index 000000000000..4031f286642a --- /dev/null +++ b/drivers/usb/phy/phy-rtk-usb3.c @@ -0,0 +1,912 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-rtk-usb3.c RTK usb3.0 phy driver + * + * copyright (c) 2017 realtek semiconductor corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-rtk-usb.h" + +#define RTK_USB3PHY_NAME "rtk-usb3phy" + +#define USB_ST_BUSY BIT(7) +#define PHY_ADDR_0x09 0x09 +#define PHY_ADDR_0x1F 0x1F +#define PHY_ADDR_0x20 0x20 +#define PHY_ADDR_0x30 0x30 + +#define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4 +#define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xF + +#define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr) +#define ARRAY_INDEX_MAP_PHY_ADDR(index) (index) + +struct reg_addr { + void __iomem *REG_MDIO_CTL; +}; + +struct phy_parameter { + u8 addr; + u16 data; +}; + +struct phy_data { + int size; + struct phy_parameter *parameter; + + u16 saved_trim_value;//=0xFFFF; + u8 connected;//=0; + + bool check_efuse; + u8 efuse_usb_u3_tx_lfps_swing_trim; + bool do_toggle; + bool do_toggle_once; + bool use_default_parameter; +}; + +static int rtk_usb_phy3_wait_vbusy(struct reg_addr *regAddr) +{ + return utmi_wait_register(regAddr->REG_MDIO_CTL, USB_ST_BUSY, 0); +} + +static u16 rtk_usb_phy_read(struct reg_addr *regAddr, char addr) +{ + unsigned int regVal; + u32 value; + + regVal = (addr << 8); + + writel(regVal, regAddr->REG_MDIO_CTL); + + rtk_usb_phy3_wait_vbusy(regAddr); + + value = readl(regAddr->REG_MDIO_CTL); + value = value >> 16; + + return (u16)value; +} + +static int rtk_usb_phy_write(struct reg_addr *regAddr, char addr, u16 data) +{ + unsigned int regVal; + + regVal = BIT(0) | + (addr << 8) | + (data << 16); + + writel(regVal, regAddr->REG_MDIO_CTL); + + rtk_usb_phy3_wait_vbusy(regAddr); + + return 0; +} + +static void rtk_usb_phy_shutdown(struct usb_phy *phy) +{ + /* Todo */ +} + +static int __get_phy_parameter_by_efuse(struct rtk_usb_phy_s *rtk_phy, + struct phy_data *phy_data, int index) +{ + u8 value = 0; + struct nvmem_cell *cell; + + cell = nvmem_cell_get(rtk_phy->dev, "usb_u3_tx_lfps_swing_trim"); + if (IS_ERR(cell)) { + dev_warn(rtk_phy->dev, + "%s failed to get usb_u3_tx_lfps_swing_trim: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; +#if defined(MY_DEF_HERE) +#else /* MY_DEF_HERE */ + int value_size = 4; +#endif /* MY_DEF_HERE */ + + buf = nvmem_cell_read(cell, &buf_size); + + value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK; + + dev_info(rtk_phy->dev, + "phy index=%d buf=0x%x buf_size=%d value=0x%x\n", + index, buf[0], (int)buf_size, value); + kfree(buf); + nvmem_cell_put(cell); + } + + if (value < 0x8) + phy_data->efuse_usb_u3_tx_lfps_swing_trim = 0x8; + else + phy_data->efuse_usb_u3_tx_lfps_swing_trim = (u8)value; + + dev_info(rtk_phy->dev, "Get Efuse usb_u3_tx_lfps_swing_trim=0x%x (value=0x%x)\n", + phy_data->efuse_usb_u3_tx_lfps_swing_trim, value); + + return 0; +} + +static void do_rtk_usb3_phy_toggle(struct rtk_usb_phy_s *rtk_phy, + int index, bool isConnect); + +static int do_rtk_usb_phy_init(struct usb_phy *phy, int phy_index) +{ + struct rtk_usb_phy_s *rtk_phy = (struct rtk_usb_phy_s *) phy; + struct reg_addr *regAddr = + &((struct reg_addr *)rtk_phy->reg_addr)[phy_index]; + struct phy_data *phy_data = + &((struct phy_data *)rtk_phy->phy_data)[phy_index]; + int index = 0; + struct phy_parameter *phy_parameter = phy_data->parameter; + + + dev_info(phy->dev, "%s Init RTK USB 3.0 PHY phy#%d\n", + __func__, phy_index); + + if (phy_data->use_default_parameter) { + dev_info(phy->dev, "%s phy#%d use default parameter\n", + __func__, phy_index); + goto do_toggle; + } + + for (index = 0; index < phy_data->size; index++) { + u8 addr = (phy_parameter + index)->addr; + u16 data = (phy_parameter + index)->data; + + if (addr == 0xFF) + continue; + + if (addr == PHY_ADDR_0x20) { + u8 efuse_val = phy_data->efuse_usb_u3_tx_lfps_swing_trim; + u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK; + int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT; + + if (efuse_val) { + data &= ~(val_mask << val_shift); + data |= ((efuse_val & val_mask) << val_shift); + } + } + + rtk_usb_phy_write(regAddr, addr, data); + } + + for (index = 0; index < phy_data->size; index++) { + u8 addr = (phy_parameter + index)->addr; + u16 data = (phy_parameter + index)->data; + + if (addr == 0xFF) + continue; + + dev_dbg(phy->dev, "[USB3_PHY], addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n", + addr, data, + rtk_usb_phy_read(regAddr, addr)); + } + +do_toggle: + if (phy_data->do_toggle_once) + phy_data->do_toggle = true; + + do_rtk_usb3_phy_toggle(rtk_phy, phy_index, false); + + if (phy_data->do_toggle_once) { + u16 check_value = 0; + int count = 10; + + check_value = rtk_usb_phy_read(regAddr, PHY_ADDR_0x30); + + while (!(check_value & BIT(15))) { + check_value = rtk_usb_phy_read(regAddr, PHY_ADDR_0x30); + mdelay(1); + if (count-- < 0) + break; + } + + if (!(check_value & BIT(15))) + dev_info(phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n", + PHY_ADDR_0x30, check_value); + else + dev_info(phy->dev, "toggle okay addr=0x%02x, data=0x%04x\n", + PHY_ADDR_0x30, check_value); + + phy_data->do_toggle = false; + } + + return 0; +} + +static int rtk_usb_phy_init(struct usb_phy *phy) +{ + struct rtk_usb_phy_s *rtk_phy = (struct rtk_usb_phy_s *) phy; + int ret = 0; + int i; + unsigned long phy_init_time = jiffies; + + if (!rtk_phy) { + pr_err("%s rtk_phy is NULL!\n", __func__); + return -1; + } + + dev_info(phy->dev, "%s Init RTK USB 3.0 PHY\n", __func__); + for (i = 0; i < rtk_phy->phyN; i++) + ret = do_rtk_usb_phy_init(phy, i); + + dev_info(phy->dev, "%s Initialized RTK USB 3.0 PHY (take %dms)\n", + __func__, + jiffies_to_msecs(jiffies - phy_init_time)); + return ret; +} + +static void do_rtk_usb3_phy_toggle(struct rtk_usb_phy_s *rtk_phy, int i, + bool isConnect) +{ + struct reg_addr *regAddr = &((struct reg_addr *)rtk_phy->reg_addr)[i]; + struct phy_data *phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + struct phy_parameter *phy_parameter; + size_t index; + + if (!rtk_phy) { + pr_err("%s rtk_phy is NULL!\n", __func__); + return; + } + + regAddr = &((struct reg_addr *)rtk_phy->reg_addr)[i]; + phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + + if (!phy_data) { + dev_err(rtk_phy->dev, "%s phy_data is NULL!\n", __func__); + return; + } + + if (!phy_data->do_toggle) + return; + + phy_parameter = phy_data->parameter; + + index = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0x09); + + if (index < phy_data->size) { + u8 addr = (phy_parameter + index)->addr; + u16 data = (phy_parameter + index)->data; + + if (addr == 0xFF) { + addr = ARRAY_INDEX_MAP_PHY_ADDR(index); + data = rtk_usb_phy_read(regAddr, addr); + (phy_parameter + index)->addr = addr; + (phy_parameter + index)->data = data; + } + mdelay(1); + dev_info(rtk_phy->dev, + "%s ########## to toggle PHY addr 0x09 BIT(9)\n", + __func__); + rtk_usb_phy_write(regAddr, addr, data&(~BIT(9))); + mdelay(1); + rtk_usb_phy_write(regAddr, addr, data); + } + dev_info(rtk_phy->dev, "%s ########## PHY addr 0x1f = 0x%04x\n", + __func__, rtk_usb_phy_read(regAddr, PHY_ADDR_0x1F)); +} + +void rtk_usb3_phy_toggle(struct usb_phy *usb3_phy, bool isConnect, int port) +{ + int index = port; + struct rtk_usb_phy_s *rtk_phy = NULL; + + if (usb3_phy != NULL && usb3_phy->dev != NULL) + rtk_phy = dev_get_drvdata(usb3_phy->dev); + + if (rtk_phy == NULL) { + pr_err("%s ERROR! NO this device\n", __func__); + return; + } + + if (index > rtk_phy->phyN) { + pr_err("%s %d ERROR! port=%d > phyN=%d\n", + __func__, __LINE__, index, rtk_phy->phyN); + return; + } + + do_rtk_usb3_phy_toggle(rtk_phy, index, isConnect); +} +EXPORT_SYMBOL(rtk_usb3_phy_toggle); + +#ifdef CONFIG_DEBUG_FS +static struct dentry *create_phy_debug_root(void) +{ + struct dentry *phy_debug_root; + + phy_debug_root = debugfs_lookup("phy", usb_debug_root); + if (!phy_debug_root) { + phy_debug_root = debugfs_create_dir("phy", usb_debug_root); + if (!phy_debug_root) + pr_err("%s Error phy_debug_root is NULL\n", __func__); + else + pr_info("%s Create phy_debug_root folder\n", __func__); + } + + return phy_debug_root; +} + +static int rtk_usb3_parameter_show(struct seq_file *s, void *unused) +{ + struct rtk_usb_phy_s *rtk_phy = s->private; + int i, index; + + for (i = 0; i < rtk_phy->phyN; i++) { + struct reg_addr *regAddr = + &((struct reg_addr *)rtk_phy->reg_addr)[i]; + struct phy_data *phy_data = + &((struct phy_data *)rtk_phy->phy_data)[i]; + struct phy_parameter *phy_parameter; + + phy_parameter = phy_data->parameter; + + seq_printf(s, "[USB3_PHY] PHY %d\n", i); + + for (index = 0; index < phy_data->size; index++) { + u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(index); + u16 data = (phy_parameter + index)->data; + + if ((phy_parameter + index)->addr == 0xFF) + seq_printf(s, "[USB3_PHY], addr = 0x%02x, data = none ==> read value = 0x%04x\n", + addr, + rtk_usb_phy_read(regAddr, addr)); + else + seq_printf(s, "[USB3_PHY], addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n", + addr, data, + rtk_usb_phy_read(regAddr, addr)); + } + } + return 0; +} + +static int rtk_usb3_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb3_parameter_show, inode->i_private); +} + +static const struct file_operations rtk_usb3_parameter_fops = { + .open = rtk_usb3_parameter_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rtk_usb3_set_parameter_show(struct seq_file *s, void *unused) +{ + //struct rtk_usb_phy_s *rtk_phy = s->private; + + seq_puts(s, "Set Phy parameter by following command\n"); + seq_puts(s, "echo \"phy_num addr value\" > set_parameter\n"); + seq_puts(s, "echo \"0 0x00 0x4008\" > set_parameter\n"); + seq_puts(s, "echo \"0 0x21 0x88AA\" > set_parameter\n"); + + return 0; +} + +static int rtk_usb3_set_parameter_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb3_set_parameter_show, inode->i_private); +} + +static ssize_t rtk_usb3_set_parameter_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct rtk_usb_phy_s *rtk_phy = s->private; + struct reg_addr *regAddr; + struct phy_data *phy_data; + struct phy_parameter *phy_parameter; + int index, i, ret = 0; + char buffer[40]; + char *buf = buffer; + u32 addr; + u32 value; + + if (copy_from_user(&buffer, ubuf, + min_t(size_t, sizeof(buffer) - 1, count))) + return -EFAULT; + + ret = kstrtoint(buf, 0, &i); + if (ret < 0) + return -EFAULT; + + buf = buf + 1; + + regAddr = &((struct reg_addr *)rtk_phy->reg_addr)[i]; + phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + phy_parameter = phy_data->parameter; + + buf = skip_spaces(buf); + ret = sscanf(buf, "%x %x", &addr, &value); + if (ret < 0) + return -EFAULT; + + index = PHY_ADDR_MAP_ARRAY_INDEX(addr); + + if (index < phy_data->size) { + (phy_parameter + index)->addr = addr; + (phy_parameter + index)->data = value; + rtk_usb_phy_write(regAddr, addr, value); + } + + return count; +} + +static const struct file_operations rtk_usb3_set_parameter_fops = { + .open = rtk_usb3_set_parameter_open, + .write = rtk_usb3_set_parameter_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rtk_usb3_toggle_show(struct seq_file *s, void *unused) +{ + struct rtk_usb_phy_s *rtk_phy = s->private; + struct phy_data *phy_data; + int i; + + for (i = 0; i < rtk_phy->phyN; i++) { + phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + seq_printf(s, "Now phy#%d do_toggle is %s.\n", + i, phy_data->do_toggle?"Enable":"Disable"); + } + seq_puts(s, "ehco 1 to enable toggle phy parameter.\n"); + + return 0; +} + +static int rtk_usb3_toggle_open(struct inode *inode, struct file *file) +{ + return single_open(file, rtk_usb3_toggle_show, inode->i_private); +} + +static ssize_t rtk_usb3_toggle_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct rtk_usb_phy_s *rtk_phy = s->private; + char buf[32]; + struct phy_data *phy_data; + bool enable = false; + int i; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1)) + enable = true; + + for (i = 0; i < rtk_phy->phyN; i++) { + phy_data = &((struct phy_data *)rtk_phy->phy_data)[i]; + phy_data->do_toggle = enable; + dev_info(rtk_phy->dev, "Set phy#%d do_toggle is %s.\n", + i, phy_data->do_toggle?"Enable":"Disable"); + } + + return count; +} + +static const struct file_operations rtk_usb3_toggle_fops = { + .open = rtk_usb3_toggle_open, + .write = rtk_usb3_toggle_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void create_debug_files(struct rtk_usb_phy_s *rtk_phy) +{ + struct dentry *phy_debug_root = NULL; + + dev_dbg(rtk_phy->dev, "%s", __func__); + + phy_debug_root = create_phy_debug_root(); + + if (!phy_debug_root) { + dev_err(rtk_phy->dev, "%s Error phy_debug_root is NULL", + __func__); + return; + } + rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), + phy_debug_root); + if (!rtk_phy->debug_dir) { + dev_err(rtk_phy->dev, "%s Error debug_dir is NULL", __func__); + return; + } + + if (!debugfs_create_file("parameter", 0444, + rtk_phy->debug_dir, rtk_phy, + &rtk_usb3_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("set_parameter", 0644, + rtk_phy->debug_dir, rtk_phy, + &rtk_usb3_set_parameter_fops)) + goto file_error; + + if (!debugfs_create_file("toggle", 0644, rtk_phy->debug_dir, rtk_phy, + &rtk_usb3_toggle_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(rtk_phy->debug_dir); +} +#endif //CONFIG_DEBUG_FS + +#define DEFAULT_CHIP_REVISION 0xA00 +#define MAX_CHIP_REVISION 0xC00 + +static int __get_chip_revision(void) +{ + int chip_revision = 0xFFF; + char revision[] = "FFF"; + struct soc_device_attribute soc_att[] = {{.revision = revision}, {}}; + struct soc_device_attribute *soc_att_match = NULL; + + while (soc_att_match == NULL) { + chip_revision--; + + if (chip_revision <= DEFAULT_CHIP_REVISION) + break; + if (chip_revision > MAX_CHIP_REVISION) + chip_revision = MAX_CHIP_REVISION; + else if ((chip_revision & 0xFF) > 0xF) + chip_revision = (chip_revision & 0xF00) + 0xF; + + snprintf(revision, 4, "%X", chip_revision); + + soc_att_match = (struct soc_device_attribute *) + soc_device_match(soc_att); + } + + if (soc_att_match) { + pr_debug("%s get chip_revision %x\n", __func__, chip_revision); + return chip_revision; + } + + pr_debug("%s: Use default chip_revision %x\n", __func__, + DEFAULT_CHIP_REVISION); + return DEFAULT_CHIP_REVISION; +} + +static int __get_phy_parameter_v1(struct device *dev, struct phy_data *phy_data, + struct device_node *sub_node) +{ + struct phy_parameter *phy_parameter; + int revision, i, ret = 0; + u8 *addr; + u16 *data; + + ret = of_property_read_u32_index(sub_node, "phy_data_size", 0, + &phy_data->size); + if (ret) + goto out; + + phy_data->parameter = devm_kzalloc(dev, + sizeof(struct phy_parameter) * phy_data->size, + GFP_KERNEL); + if (!phy_data->parameter) + return -ENOMEM; + + addr = kzalloc(sizeof(u8) * phy_data->size, + GFP_KERNEL); + if (!addr) { + kfree(phy_data->parameter); + phy_data->parameter = NULL; + return -ENOMEM; + } + + data = kzalloc(sizeof(u16) * phy_data->size, + GFP_KERNEL); + if (!data) { + kfree(phy_data->parameter); + kfree(addr); + phy_data->parameter = NULL; + return -ENOMEM; + } + ret = of_property_read_u8_array(sub_node, "phy_data_addr", + addr, phy_data->size); + if (ret) + goto out; + + revision = __get_chip_revision(); + dev_dbg(dev, "%s: Chip revision is %x\n", __func__, revision); + + while (revision >= DEFAULT_CHIP_REVISION) { + char phy_data_revision[14] = {0}; + + snprintf(phy_data_revision, 13, "phy_data_%X", + revision); + ret = of_property_read_u16_array(sub_node, + phy_data_revision, + data, phy_data->size); + if (!ret) { + dev_dbg(dev, "%s load %s parameter\n", + __func__, phy_data_revision); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + } + + /* For old device tree */ + if (ret) { + ret = of_property_read_u16_array(sub_node, + "phy_data_revA", + data, phy_data->size); + if (ret) + goto out; + else + dev_info(dev, "%s load parameter\n", __func__); + } + + phy_parameter = phy_data->parameter; + + for (i = 0; i < phy_data->size; i++) { + (phy_parameter + i)->addr = *(addr + i); + (phy_parameter + i)->data = *(data + i); + dev_dbg(dev, "%s i=%d addr=0x%x data=0x%x\n", + __func__, i, (phy_parameter + i)->addr, + (phy_parameter + i)->data); + } + +out: + kfree(addr); + kfree(data); + + return ret; +} + +static int __get_phy_parameter_v2(struct device *dev, struct phy_data *phy_data, + struct device_node *sub_node) +{ + struct phy_parameter *phy_parameter; + int revision, i, ret = 0; + int data_size , num_cells = 2; + char phy_data_revision[14] = {0}; + + ret = of_property_read_u32_index(sub_node, "phy_data_size", 0, + &phy_data->size); + if (ret) + goto out; + + phy_data->parameter = devm_kzalloc(dev, + sizeof(struct phy_parameter) * phy_data->size, + GFP_KERNEL); + if (!phy_data->parameter) + return -ENOMEM; + + revision = __get_chip_revision(); + dev_dbg(dev, "%s: Chip revision is %x\n", __func__, revision); + + while (revision >= DEFAULT_CHIP_REVISION) { + snprintf(phy_data_revision, 13, "phy_data_%X", + revision); + if (of_get_property(sub_node, phy_data_revision, &data_size)) { + dev_dbg(dev, "%s load %s parameter (data_size=%d)\n", + __func__, phy_data_revision, data_size); + break; + } + revision--; + if ((revision & 0xFF) > 0xF) + revision = (revision & 0xF00) + 0xF; + + data_size = 0; + ret = 0; + } + + phy_parameter = phy_data->parameter; + for (i = 0; i < phy_data->size; i++) + (phy_parameter + i)->addr = 0xFF; + + data_size = data_size / (sizeof(u32) * num_cells); + for (i = 0; i < data_size; i++) { + struct phy_parameter *parameter; + u32 addr, data; + int offset, index; + + offset = i * num_cells; + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset, &addr); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, addr); + break; + } + + ret = of_property_read_u32_index(sub_node, phy_data_revision, + offset + 1, &data); + if (ret) { + dev_err(dev, "ERROR: To get %s i=%d addr=0x%x\n", + phy_data_revision, i, data); + break; + } + + index = PHY_ADDR_MAP_ARRAY_INDEX(addr); + parameter = (phy_parameter + index); + parameter->addr = (u8)addr; + parameter->data = (u16)data; + + dev_dbg(dev, "%s index=%d addr=0x%x data=0x%x\n", + phy_data_revision, index, + parameter->addr, parameter->data); + } + +out: + return ret; +} + +static int rtk_usb3phy_probe(struct platform_device *pdev) +{ + struct rtk_usb_phy_s *rtk_usb_phy; + struct device *dev = &pdev->dev; + int i, ret, phyN; + + rtk_usb_phy = devm_kzalloc(dev, sizeof(*rtk_usb_phy), GFP_KERNEL); + if (!rtk_usb_phy) + return -ENOMEM; + + rtk_usb_phy->dev = &pdev->dev; + rtk_usb_phy->phy.dev = rtk_usb_phy->dev; + rtk_usb_phy->phy.label = RTK_USB3PHY_NAME; + rtk_usb_phy->phy.init = rtk_usb_phy_init; + rtk_usb_phy->phy.shutdown = rtk_usb_phy_shutdown; + + if (!dev->of_node) { + dev_err(dev, "%s %d No device node\n", __func__, __LINE__); + goto err; + } + + ret = of_property_read_u32_index(dev->of_node, "phyN", 0, + &phyN); + if (ret) + goto err; + + rtk_usb_phy->phyN = phyN; + + rtk_usb_phy->reg_addr = devm_kzalloc(dev, + sizeof(struct reg_addr) * phyN, GFP_KERNEL); + if (!rtk_usb_phy->reg_addr) + return -ENOMEM; + rtk_usb_phy->phy_data = devm_kzalloc(dev, + sizeof(struct phy_data) * phyN, GFP_KERNEL); + if (!rtk_usb_phy->phy_data) + return -ENOMEM; + + for (i = 0; i < phyN; i++) { + struct reg_addr *addr = + &((struct reg_addr *)rtk_usb_phy->reg_addr)[i]; + struct phy_data *phy_data = + &((struct phy_data *)rtk_usb_phy->phy_data)[i]; + + char phy_name[5], phy_name_v2[10]; + struct device_node *sub_node; + + addr->REG_MDIO_CTL = of_iomap(dev->of_node, i); + dev_dbg(dev, "%s %d #%d REG_MDIO_CTL=%p\n", + __func__, __LINE__, i, addr->REG_MDIO_CTL); + + snprintf(phy_name, 5, "phy%d", i); + + sub_node = of_get_child_by_name(dev->of_node, phy_name); + if (sub_node) { + dev_info(dev, "%s %d: #%d Get phy data v1 sub_node for %s\n", + __func__, __LINE__, i, phy_name); + ret = __get_phy_parameter_v1(dev, phy_data, sub_node); + if (ret) + goto err; + } else { + snprintf(phy_name_v2, 10, "phy%d_data", i); + sub_node = of_get_child_by_name(dev->of_node, phy_name_v2); + if (sub_node) { + dev_info(dev, "%s %d: #%d Get phy data v2 sub_node for %s\n", + __func__, __LINE__, i, phy_name_v2); + ret = __get_phy_parameter_v2(dev, phy_data, sub_node); + if (ret) + goto err; + } + } + + if (!sub_node) { + dev_err(dev, "%s %d No device sub node for %s\n", + __func__, __LINE__, phy_name); + goto err; + } + + phy_data->saved_trim_value = 0xFFFF; + phy_data->connected = 0; + + if (of_property_read_bool(sub_node, "do_toggle_once")) + phy_data->do_toggle_once = true; + else + phy_data->do_toggle_once = false; + + if (of_property_read_bool(sub_node, "do_toggle")) + phy_data->do_toggle = true; + else + phy_data->do_toggle = false; + + if (of_property_read_bool(sub_node, "use_default_parameter")) + phy_data->use_default_parameter = true; + else + phy_data->use_default_parameter = false; + + if (of_property_read_bool(sub_node, "check_efuse")) + phy_data->check_efuse = true; + else + phy_data->check_efuse = false; + + if (phy_data->check_efuse) + __get_phy_parameter_by_efuse(rtk_usb_phy, phy_data, i); + } + + platform_set_drvdata(pdev, rtk_usb_phy); + + ret = usb_add_phy_dev(&rtk_usb_phy->phy); + if (ret) + goto err; + +#ifdef CONFIG_DEBUG_FS + create_debug_files(rtk_usb_phy); +#endif + + dev_info(&pdev->dev, "%s Probe RTK USB 3.0 PHY\n", __FILE__); +err: + return ret; +} + +static int rtk_usb3phy_remove(struct platform_device *pdev) +{ + struct rtk_usb_phy_s *rtk_usb_phy = platform_get_drvdata(pdev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(rtk_usb_phy->debug_dir); +#endif + + usb_remove_phy(&rtk_usb_phy->phy); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id usbphy_rtk_dt_match[] = { + { .compatible = "realtek,usb3phy", }, + {}, +}; +MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); +#endif + +static struct platform_driver rtk_usb3phy_driver = { + .probe = rtk_usb3phy_probe, + .remove = rtk_usb3phy_remove, + .driver = { + .name = RTK_USB3PHY_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(usbphy_rtk_dt_match), + }, +}; + +module_platform_driver(rtk_usb3phy_driver); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" RTK_USB3PHY_NAME); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e5a971b83e3f..fe270c10eedf 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Driver for USB Mass Storage compliant devices @@ -41,6 +44,9 @@ #include "usb.h" #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "scsiglue.h" #include "debug.h" #include "transport.h" @@ -593,6 +599,34 @@ static struct device_attribute *sysfs_device_attr_list[] = { NULL, }; +#ifdef MY_ABC_HERE +static void syno_usb_info_enum(struct scsi_device *sdev) { + struct us_data *usdata = NULL; + struct uas_dev_info *uasdevinfo = NULL; + struct usb_device *udev = NULL; + + if (NULL == sdev || NULL == sdev->host) { + return; + } + + if (strncmp(sdev->host->hostt->name, "usb-storage", 11) == 0) { + usdata = host_to_us(sdev->host); + if (NULL == usdata || NULL == usdata->pusb_intf){ + return; + } + udev = usdata->pusb_dev; + } else if (strncmp(sdev->host->hostt->name, "uas", 3) == 0) { + uasdevinfo = (struct uas_dev_info *)sdev->host->hostdata; + if (NULL == uasdevinfo || NULL == uasdevinfo->intf){ + return; + } + udev = uasdevinfo->udev; + } + + snprintf(sdev->syno_block_info, BLOCK_INFO_SIZE, "%susb_path=%s\n", sdev->syno_block_info, dev_name(&udev->dev)); +} +#endif /* MY_ABC_HERE */ + /* * this defines our host template, with which we'll allocate hosts */ @@ -655,6 +689,11 @@ static const struct scsi_host_template usb_stor_host_template = { /* sysfs device attributes */ .sdev_attrs = sysfs_device_attr_list, +#ifdef MY_ABC_HERE + .syno_port_type = SYNO_PORT_TYPE_USB, + .syno_sdev_info_enum = syno_usb_info_enum, +#endif /* MY_ABC_HERE */ + /* module management */ .module = THIS_MODULE }; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 7cc8813f5d8c..a78bdb80e990 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Driver for USB Mass Storage compliant devices @@ -49,6 +52,14 @@ #include "../../scsi/sd.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + /*********************************************************************** * Data transfer routines ***********************************************************************/ @@ -601,6 +612,16 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) int need_auto_sense; int result; +#ifdef MY_ABC_HERE + if (unlikely((us->pusb_dev->syno_quirks & + SYNO_USB_QUIRK_SYNCHRONIZE_CACHE_FILTER) && + SYNCHRONIZE_CACHE == srb->cmnd[0])) { + srb->result = SAM_STAT_GOOD; + msleep(3000); + return; + } +#endif /* MY_ABC_HERE */ + /* send the command to the transport layer */ scsi_set_resid(srb, 0); result = us->transport(srb, us); @@ -1107,6 +1128,29 @@ int usb_stor_Bulk_max_lun(struct us_data *us) return 0; } +#ifdef MY_ABC_HERE +int extra_delay = 0; +module_param(extra_delay, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +int extra_delay_time = 0; +module_param(extra_delay_time, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +static inline void usb_stor_delay(struct us_data *us) +{ + /* 0 : no delay + * 1 : for customized + * others : for original delay mechanism (just for Jmicron, Samsung, Lacie, + * Freecom, Iomega, SimpleTech, Icybox) + */ + if (likely(extra_delay == 0)) + return; + + if (1 == extra_delay && 0 < extra_delay_time) { + udelay(extra_delay_time); + return; + } +} +#endif /* MY_ABC_HERE */ + int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; @@ -1147,6 +1191,9 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) bcb->Length); result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL); +#ifdef MY_ABC_HERE + usb_stor_delay(us); +#endif /* MY_ABC_HERE */ usb_stor_dbg(us, "Bulk command transfer result=%d\n", result); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -1166,6 +1213,9 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_srb(us, pipe, srb); +#ifdef MY_ABC_HERE + usb_stor_delay(us); +#endif /* MY_ABC_HERE */ usb_stor_dbg(us, "Bulk data transfer result 0x%x\n", result); if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; @@ -1215,7 +1265,9 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) usb_stor_dbg(us, "Attempting to get CSW...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); - +#ifdef MY_ABC_HERE + usb_stor_delay(us); +#endif /* MY_ABC_HERE */ /* * Some broken devices add unnecessary zero-length packets to the * end of their data transfers. Such packets show up as 0-length @@ -1225,6 +1277,9 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) usb_stor_dbg(us, "Received 0-length CSW; retrying...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); +#ifdef MY_ABC_HERE + usb_stor_delay(us); +#endif /* MY_ABC_HERE */ } /* did the attempt to read the CSW fail? */ @@ -1234,6 +1289,9 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); +#ifdef MY_ABC_HERE + usb_stor_delay(us); +#endif /* MY_ABC_HERE */ } /* if we still have a failure at this point, we're in trouble */ diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index ff6f41e7e068..631b3dfbd7d6 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * USB Attached SCSI @@ -29,6 +32,8 @@ #include "uas-detect.h" #include "scsiglue.h" +#ifdef MY_ABC_HERE +#else #define MAX_CMNDS 256 struct uas_dev_info { @@ -47,6 +52,7 @@ struct uas_dev_info { struct work_struct work; struct work_struct scan_work; /* for async scanning */ }; +#endif enum { SUBMIT_STATUS_URB = BIT(1), @@ -912,6 +918,9 @@ static struct scsi_host_template uas_host_template = { .this_id = -1, .skip_settle_delay = 1, .dma_boundary = PAGE_SIZE - 1, +#ifdef MY_ABC_HERE + .syno_port_type = SYNO_PORT_TYPE_USB, +#endif /* MY_ABC_HERE */ }; #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 90aa9c12ffac..0854dbda1dd2 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Driver for USB Mass Storage compliant devices @@ -57,6 +60,7 @@ #include "option_ms.h" #if IS_ENABLED(CONFIG_USB_UAS) +#include #include "uas-detect.h" #endif @@ -75,6 +79,9 @@ static char quirks[128]; module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR); MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); +#ifdef MY_ABC_HERE +extern int syno_all_usb_uas_enabled; +#endif /* MY_ABC_HERE */ /* * The entries in this table correspond, line for line, @@ -860,6 +867,12 @@ static void quiesce_and_remove_host(struct us_data *us) if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags)) usb_autopm_put_interface_no_suspend(us->pusb_intf); +#ifdef MY_ABC_HERE + scsi_lock(host); + usb_stor_stop_transport(us); + scsi_unlock(host); +#endif /* MY_ABC_HERE */ + /* * Removing the host will perform an orderly shutdown: caches * synchronized, disks spun down, etc. @@ -1102,8 +1115,22 @@ static int storage_probe(struct usb_interface *intf, /* If uas is enabled and this device can do uas then ignore it. */ #if IS_ENABLED(CONFIG_USB_UAS) +#ifdef MY_ABC_HERE + /* + * If service key support_uasp equals to "yes", then syno_all_usb_uas_enabled will be 1 + * and usb device will use uas driver. + * + * If service key support_uasp equals to "no", then syno_all_usb_uas_enabled will be 0 + * and usb device will use usb-storage driver. + */ + if (0 < syno_all_usb_uas_enabled) + if (uas_use_uas_driver(intf, id, NULL)) + return -ENXIO; +#else /* MY_ABC_HERE */ if (uas_use_uas_driver(intf, id, NULL)) return -ENXIO; + +#endif /* MY_ABC_HERE */ #endif /* diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index c8784dfafdd7..fa55a54adec0 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -642,8 +642,6 @@ static bool tx_can_batch(struct vhost_virtqueue *vq, size_t total_len) !vhost_vq_avail_empty(vq->dev, vq); } -#define SKB_FRAG_PAGE_ORDER get_order(32768) - static bool vhost_net_page_frag_refill(struct vhost_net *net, unsigned int sz, struct page_frag *pfrag, gfp_t gfp) { diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 222d630c41fc..d8860e74b742 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -254,7 +254,7 @@ void vp_del_vqs(struct virtio_device *vdev) if (vp_dev->msix_affinity_masks) { for (i = 0; i < vp_dev->msix_vectors; i++) - if (vp_dev->msix_affinity_masks[i]) + if (cpumask_available(vp_dev->msix_affinity_masks[i])) free_cpumask_var(vp_dev->msix_affinity_masks[i]); } diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index db935d6b10c2..584e4007fae1 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -105,6 +105,16 @@ config WATCHDOG_PRETIMEOUT_GOV_PANIC Panic watchdog pretimeout governor, on watchdog pretimeout event put the kernel into panic. +if SYNO_LSP_RTD1619B +config WATCHDOG_PRETIMEOUT_GOV_DUMP + tristate "Dump watchdog pretimeout governor" + depends on WATCHDOG_CORE + default WATCHDOG_CORE + help + Dump watchdog pretimeout governor, on watchdog pretimeout + event, dump infortmation form sysrq and reboot. + +endif # SYNO_LSP_RTD1619B choice prompt "Default Watchdog Pretimeout Governor" default WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC @@ -939,6 +949,14 @@ config ASPEED_WATCHDOG To compile this driver as a module, choose M here: the module will be called aspeed_wdt. +if SYNO_LSP_RTD1619B +config RTK_WATCHDOG + tristate "Realtek watchdog support" + depends on ARCH_REALTEK + select WATCHDOG_CORE + help + Realtek watchdog support. +endif # SYNO_LSP_RTD1619B config ZX2967_WATCHDOG tristate "ZTE zx2967 SoCs watchdog support" depends on ARCH_ZX diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 071a2e50be98..d2756f685d1f 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -12,6 +12,9 @@ watchdog-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV) += watchdog_pretimeout.o obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP) += pretimeout_noop.o obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC) += pretimeout_panic.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_DUMP) += pretimeout_dump.o +endif # CONFIG_SYNO_LSP_RTD1619B # Only one watchdog can succeed. We probe the ISA/PCI/USB based # watchdog-cards first, then the architecture specific watchdog @@ -92,6 +95,9 @@ obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o obj-$(CONFIG_RTD119X_WATCHDOG) += rtd119x_wdt.o +ifeq ($(CONFIG_SYNO_LSP_RTD1619B), y) +obj-$(CONFIG_RTK_WATCHDOG) += rtk_wdt.o +endif # CONFIG_SYNO_LSP_RTD1619B obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o diff --git a/drivers/watchdog/pretimeout_dump.c b/drivers/watchdog/pretimeout_dump.c new file mode 100644 index 000000000000..e959edfd5001 --- /dev/null +++ b/drivers/watchdog/pretimeout_dump.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Realtek Semiconductor Corp. + * Author: Cheng-Yu Lee + */ + +#include +#include +#include +#include +#include + +#include "watchdog_pretimeout.h" + +static void pretimeout_dump(struct watchdog_device *wdd) +{ + if (wdd->ops->stop) + wdd->ops->stop(wdd); + dev_err(wdd->parent, "%s: start dump\n", __func__); + + handle_sysrq('9'); + dump_stack(); + handle_sysrq('w'); + handle_sysrq('l'); + /* dump memory stats */ + handle_sysrq('m'); + handle_sysrq('p'); + handle_sysrq('q'); + /* dump scheduler state */ + handle_sysrq('t'); + handle_sysrq('z'); + + machine_restart("watchdog"); +} + +static struct watchdog_governor watchdog_gov_dump = { + .name = "dump", + .pretimeout = pretimeout_dump, +}; + +static int __init watchdog_gov_dump_register(void) +{ + return watchdog_register_governor(&watchdog_gov_dump); +} + +static void __exit watchdog_gov_dump_unregister(void) +{ + watchdog_unregister_governor(&watchdog_gov_dump); +} +module_init(watchdog_gov_dump_register); +module_exit(watchdog_gov_dump_unregister); + +MODULE_AUTHOR("Cheng-Yu Lee "); +MODULE_DESCRIPTION("Realtek dump watchdog pretimeout governor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/rtk_wdt.c b/drivers/watchdog/rtk_wdt.c new file mode 100644 index 000000000000..5cb2e40b8229 --- /dev/null +++ b/drivers/watchdog/rtk_wdt.c @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rtk_wdt.c - Realtek watchdog driver + * Copyright (c) 2018-2021 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WDT_OFFSET_TCWCR 0x0 +#define WDT_OFFSET_TCWTR 0x4 +#define WDT_OFFSET_TCWNMI 0x8 +#define WDT_OFFSET_TCWOV 0xc + +#define WDT_CNT_VAL_1SEC (27000000) +#define WDT_CTN_VAL_1MS (27000) + +#define WDT_OVRSTB_OFFSET_CNT 0x0 +#define WDT_OVRSTB_OFFSET_PAD 0x4 + +#define WDT_OVRSTB_OE_INVALID (-1) + +struct rtk_wdt { + struct device *dev; + struct watchdog_device wdd; + void __iomem *wdt_base; + int irq; + + void __iomem *ov_rstb_base; + struct notifier_block reboot_nb; + int ov_rstb_oe; + int ov_rstb_oe_init; +}; + +static int rtk_wdt_ov_rstb_oe_vaild(int val) +{ + return val == 1 || val == 0; +} + +static void rtk_wdt_enable(struct rtk_wdt *wdt) +{ + u32 val = readl(wdt->wdt_base + WDT_OFFSET_TCWCR); + + val &= ~0xff; + val |= 0xff; + writel(val, wdt->wdt_base + WDT_OFFSET_TCWCR); +} + +static void rtk_wdt_disable(struct rtk_wdt *wdt) +{ + u32 val = readl(wdt->wdt_base + WDT_OFFSET_TCWCR); + + val &= ~0xff; + val |= 0xa5; + writel(val, wdt->wdt_base + WDT_OFFSET_TCWCR); +} + +static void rtk_wdt_enable_int(struct rtk_wdt *wdt) +{ + u32 val = readl(wdt->wdt_base + WDT_OFFSET_TCWCR); + + val &= ~0x80000000; + val |= 0x80000000; + writel(val, wdt->wdt_base + WDT_OFFSET_TCWCR); +} + +static void rtk_wdt_disable_int(struct rtk_wdt *wdt) +{ + u32 val = readl(wdt->wdt_base + WDT_OFFSET_TCWCR); + + val &= ~0x80000000; + writel(val, wdt->wdt_base + WDT_OFFSET_TCWCR); +} + +static void rtk_wdt_clear_cnt(struct rtk_wdt *wdt) +{ + writel(0x1, wdt->wdt_base + WDT_OFFSET_TCWTR); +} + +static void rtk_wdt_set_nmi(struct rtk_wdt *wdt, u32 val) +{ + writel(val, wdt->wdt_base + WDT_OFFSET_TCWNMI); +} + +static void rtk_wdt_set_ov(struct rtk_wdt *wdt, u32 val) +{ + writel(val, wdt->wdt_base + WDT_OFFSET_TCWOV); +} + +static void rtk_wdt_set_ov_rstb_oe(struct rtk_wdt *wdt, int oe) +{ + u32 val; + + val = readl(wdt->ov_rstb_base + WDT_OVRSTB_OFFSET_PAD); + val &= ~0x1; + val |= oe & 0x1; + writel(val, wdt->ov_rstb_base + WDT_OVRSTB_OFFSET_PAD); +} + +static int rtk_wdt_set_ov_rstb_cnt(struct rtk_wdt *wdt, u32 cnt) +{ + writel(cnt, wdt->ov_rstb_base + WDT_OVRSTB_OFFSET_CNT); + return 0; +} + +static inline int sec_to_cnt(unsigned int sec) +{ + return sec * WDT_CNT_VAL_1SEC; +} + +static int rtk_wdt_start(struct watchdog_device *wdd) +{ + struct rtk_wdt *wdt = watchdog_get_drvdata(wdd); + unsigned int delta; + + rtk_wdt_set_ov(wdt, sec_to_cnt(wdd->timeout)); + rtk_wdt_enable(wdt); + rtk_wdt_clear_cnt(wdt); + + if (!wdd->pretimeout || wdd->pretimeout > wdd->timeout) + delta = 0; + else + delta = wdd->timeout - wdd->pretimeout; + rtk_wdt_set_nmi(wdt, sec_to_cnt(delta)); + if (delta) + rtk_wdt_enable_int(wdt); + else + rtk_wdt_disable_int(wdt); + + return 0; +} + +static int rtk_wdt_stop(struct watchdog_device *wdd) +{ + struct rtk_wdt *wdt = watchdog_get_drvdata(wdd); + + rtk_wdt_disable(wdt); + rtk_wdt_disable_int(wdt); + + return 0; +} + +static int rtk_wdt_ping(struct watchdog_device *wdd) +{ + struct rtk_wdt *wdt = watchdog_get_drvdata(wdd); + + rtk_wdt_clear_cnt(wdt); + return 0; +} + + +static int rtk_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + wdd->timeout = timeout; + return rtk_wdt_start(wdd); +} + +static int rtk_wdt_set_pretimeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + wdd->pretimeout = timeout; + return rtk_wdt_start(wdd); +} + +static int rtk_wdt_restart(struct watchdog_device *wdd, unsigned long action, + void *data) +{ + struct rtk_wdt *wdt = watchdog_get_drvdata(wdd); + + dev_emerg(wdd->parent, "Restarting...\n"); + + rtk_wdt_disable(wdt); + rtk_wdt_disable_int(wdt); + rtk_wdt_clear_cnt(wdt); + + rtk_wdt_set_ov(wdt, 0x00800000); + rtk_wdt_enable(wdt); + + mdelay(10000); + dev_emerg(wdd->parent, "Unable to restart system\n"); + + return NOTIFY_OK; +} + +static irqreturn_t rtk_wdt_irq_handler(int irq, void *devid) +{ + struct rtk_wdt *wdt = devid; + + watchdog_notify_pretimeout(&wdt->wdd); + return IRQ_HANDLED; +} + +static void rtk_wdt_shutdown(struct platform_device *pdev) +{ + struct rtk_wdt *wdt = platform_get_drvdata(pdev); + struct device *dev = wdt->wdd.parent; + + dev_info(dev, "%s\n", __func__); + rtk_wdt_stop(&wdt->wdd); +} + +static const struct watchdog_info rtk_wdt_info = { + .identity = "Realtek watchdog", + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | + WDIOF_PRETIMEOUT, +}; + +static const struct watchdog_ops rtk_wdt_ops = { + .owner = THIS_MODULE, + .start = rtk_wdt_start, + .stop = rtk_wdt_stop, + .ping = rtk_wdt_ping, + .set_timeout = rtk_wdt_set_timeout, + .set_pretimeout = rtk_wdt_set_pretimeout, + .restart = rtk_wdt_restart, +}; + +static int rtk_wdt_reboot_notify(struct notifier_block *nb, unsigned long mode, void *cmd) +{ + struct rtk_wdt *wdt = container_of(nb, struct rtk_wdt, reboot_nb); + + if (!rtk_wdt_ov_rstb_oe_vaild(wdt->ov_rstb_oe)) + return NOTIFY_DONE; + + dev_info(wdt->dev, "set oe to %d\n", wdt->ov_rstb_oe); + rtk_wdt_set_ov_rstb_oe(wdt, wdt->ov_rstb_oe); + rtk_wdt_set_ov_rstb_cnt(wdt, 0x00800000); + return NOTIFY_OK; +} + +static void rtk_wdt_fini_ov_rstb(void *data) +{ + struct rtk_wdt *wdt = data; + + unregister_reboot_notifier(&wdt->reboot_nb); +} + +static int rtk_wdt_init_ov_rstb(struct rtk_wdt *wdt) +{ + struct device_node *np = wdt->dev->of_node; + + wdt->ov_rstb_oe_init = WDT_OVRSTB_OE_INVALID; + of_property_read_u32(np, "ov-rstb-oe-init", &wdt->ov_rstb_oe_init); + + wdt->ov_rstb_oe = WDT_OVRSTB_OE_INVALID; + of_property_read_u32(np, "ov-rstb-oe", &wdt->ov_rstb_oe); + + wdt->reboot_nb.notifier_call = rtk_wdt_reboot_notify; + register_reboot_notifier(&wdt->reboot_nb); + + return devm_add_action_or_reset(wdt->dev, rtk_wdt_fini_ov_rstb, wdt); +} + +static int rtk_wdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtk_wdt *wdt; + struct resource *res; + int ret = 0; + int restart_priority; + + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + wdt->dev = dev; + wdt->wdt_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!wdt->wdt_base) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + wdt->ov_rstb_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!wdt->ov_rstb_base) { + dev_err(dev, "failed to map rstb\n"); + return -ENOMEM; + } + + ret = rtk_wdt_init_ov_rstb(wdt); + if (ret) + dev_warn(dev, "failed to init rstb: %d\n", ret); + + if (rtk_wdt_ov_rstb_oe_vaild(wdt->ov_rstb_oe_init)) + rtk_wdt_set_ov_rstb_oe(wdt, wdt->ov_rstb_oe_init); + } + + wdt->irq = platform_get_irq(pdev, 0); + if (wdt->irq < 0) { + dev_err(dev, "no irq specified: %d\n", wdt->irq); + return wdt->irq; + } + + /* ARM does not support NMI interrupt directly so software can configure + * the GIC to come up a non-maskable interrupt. + */ + ret = devm_request_irq(dev, wdt->irq, rtk_wdt_irq_handler, 0, + dev_name(dev), wdt); + if (ret) { + dev_err(dev, "failed to request irq: %d\n", ret); + return ret; + } + + + wdt->wdd.parent = dev; + wdt->wdd.info = &rtk_wdt_info; + wdt->wdd.ops = &rtk_wdt_ops; + wdt->wdd.min_timeout = 1; + wdt->wdd.max_timeout = UINT_MAX / WDT_CNT_VAL_1SEC; + watchdog_set_drvdata(&wdt->wdd, wdt); + watchdog_init_timeout(&wdt->wdd, 0, dev); + + if (of_property_read_u32(dev->of_node, "restart_priority", &restart_priority)) + restart_priority = -1; + watchdog_set_restart_priority(&wdt->wdd, restart_priority); + + rtk_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout); + rtk_wdt_set_pretimeout(&wdt->wdd, 8); + rtk_wdt_stop(&wdt->wdd); + + ret = watchdog_register_device(&wdt->wdd); + if (ret) { + dev_err(dev, "cannot register watchdog device: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, wdt); + + return 0; +} + +static int rtk_wdt_remove(struct platform_device *pdev) +{ + struct rtk_wdt *wdt = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + watchdog_unregister_device(&wdt->wdd); + return 0; +} + +static const struct of_device_id rtk_wdt_of_table[] = { + { .compatible = "realtek,watchdog", }, + {} +}; +MODULE_DEVICE_TABLE(of, rtk_wdt_of_table); + +static struct platform_driver rtk_watchdog_driver = { + .probe = rtk_wdt_probe, + .remove = rtk_wdt_remove, + .shutdown = rtk_wdt_shutdown, + .driver = { + .name = "rtk-wdt", + .of_match_table = rtk_wdt_of_table, + }, +}; +module_platform_driver(rtk_watchdog_driver); + +MODULE_DESCRIPTION("Realtek Watchdog Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/fs/Kconfig b/fs/Kconfig index da524c4d7b7e..7fa4edd58273 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -122,6 +122,7 @@ source "fs/quota/Kconfig" source "fs/autofs/Kconfig" source "fs/fuse/Kconfig" source "fs/overlayfs/Kconfig" +source "fs/aufs/Kconfig" menu "Caches" diff --git a/fs/Makefile b/fs/Makefile index 999d1a23f036..6bc18c01bad6 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o +obj-$(CONFIG_SYNO_FS_WINACL) += syno_acl.o syno_acl_api.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_COREDUMP) += coredump.o obj-$(CONFIG_SYSCTL) += drop_caches.o @@ -112,6 +113,7 @@ obj-$(CONFIG_AUTOFS_FS) += autofs/ obj-$(CONFIG_ADFS_FS) += adfs/ obj-$(CONFIG_FUSE_FS) += fuse/ obj-$(CONFIG_OVERLAY_FS) += overlayfs/ +obj-$(CONFIG_AUFS_FS) += aufs/ obj-$(CONFIG_ORANGEFS_FS) += orangefs/ obj-$(CONFIG_UDF_FS) += udf/ obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ diff --git a/fs/aio.c b/fs/aio.c index 6a21d8919409..2a9dfa58ec3a 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -182,8 +182,9 @@ struct poll_iocb { struct file *file; struct wait_queue_head *head; __poll_t events; - bool done; bool cancelled; + bool work_scheduled; + bool work_need_resched; struct wait_queue_entry wait; struct work_struct work; }; @@ -1621,6 +1622,51 @@ static void aio_poll_put_work(struct work_struct *work) iocb_put(iocb); } +/* + * Safely lock the waitqueue which the request is on, synchronizing with the + * case where the ->poll() provider decides to free its waitqueue early. + * + * Returns true on success, meaning that req->head->lock was locked, req->wait + * is on req->head, and an RCU read lock was taken. Returns false if the + * request was already removed from its waitqueue (which might no longer exist). + */ +static bool poll_iocb_lock_wq(struct poll_iocb *req) +{ + wait_queue_head_t *head; + + /* + * While we hold the waitqueue lock and the waitqueue is nonempty, + * wake_up_pollfree() will wait for us. However, taking the waitqueue + * lock in the first place can race with the waitqueue being freed. + * + * We solve this as eventpoll does: by taking advantage of the fact that + * all users of wake_up_pollfree() will RCU-delay the actual free. If + * we enter rcu_read_lock() and see that the pointer to the queue is + * non-NULL, we can then lock it without the memory being freed out from + * under us, then check whether the request is still on the queue. + * + * Keep holding rcu_read_lock() as long as we hold the queue lock, in + * case the caller deletes the entry from the queue, leaving it empty. + * In that case, only RCU prevents the queue memory from being freed. + */ + rcu_read_lock(); + head = smp_load_acquire(&req->head); + if (head) { + spin_lock(&head->lock); + if (!list_empty(&req->wait.entry)) + return true; + spin_unlock(&head->lock); + } + rcu_read_unlock(); + return false; +} + +static void poll_iocb_unlock_wq(struct poll_iocb *req) +{ + spin_unlock(&req->head->lock); + rcu_read_unlock(); +} + static void aio_poll_complete_work(struct work_struct *work) { struct poll_iocb *req = container_of(work, struct poll_iocb, work); @@ -1640,14 +1686,27 @@ static void aio_poll_complete_work(struct work_struct *work) * avoid further branches in the fast path. */ spin_lock_irq(&ctx->ctx_lock); - if (!mask && !READ_ONCE(req->cancelled)) { - add_wait_queue(req->head, &req->wait); - spin_unlock_irq(&ctx->ctx_lock); - return; - } + if (poll_iocb_lock_wq(req)) { + if (!mask && !READ_ONCE(req->cancelled)) { + /* + * The request isn't actually ready to be completed yet. + * Reschedule completion if another wakeup came in. + */ + if (req->work_need_resched) { + schedule_work(&req->work); + req->work_need_resched = false; + } else { + req->work_scheduled = false; + } + poll_iocb_unlock_wq(req); + spin_unlock_irq(&ctx->ctx_lock); + return; + } + list_del_init(&req->wait.entry); + poll_iocb_unlock_wq(req); + } /* else, POLLFREE has freed the waitqueue, so we must complete */ list_del_init(&iocb->ki_list); iocb->ki_res.res = mangle_poll(mask); - req->done = true; spin_unlock_irq(&ctx->ctx_lock); iocb_put(iocb); @@ -1659,13 +1718,14 @@ static int aio_poll_cancel(struct kiocb *iocb) struct aio_kiocb *aiocb = container_of(iocb, struct aio_kiocb, rw); struct poll_iocb *req = &aiocb->poll; - spin_lock(&req->head->lock); - WRITE_ONCE(req->cancelled, true); - if (!list_empty(&req->wait.entry)) { - list_del_init(&req->wait.entry); - schedule_work(&aiocb->poll.work); - } - spin_unlock(&req->head->lock); + if (poll_iocb_lock_wq(req)) { + WRITE_ONCE(req->cancelled, true); + if (!req->work_scheduled) { + schedule_work(&aiocb->poll.work); + req->work_scheduled = true; + } + poll_iocb_unlock_wq(req); + } /* else, the request was force-cancelled by POLLFREE already */ return 0; } @@ -1682,20 +1742,26 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, if (mask && !(mask & req->events)) return 0; - list_del_init(&req->wait.entry); - - if (mask && spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) { + /* + * Complete the request inline if possible. This requires that three + * conditions be met: + * 1. An event mask must have been passed. If a plain wakeup was done + * instead, then mask == 0 and we have to call vfs_poll() to get + * the events, so inline completion isn't possible. + * 2. The completion work must not have already been scheduled. + * 3. ctx_lock must not be busy. We have to use trylock because we + * already hold the waitqueue lock, so this inverts the normal + * locking order. Use irqsave/irqrestore because not all + * filesystems (e.g. fuse) call this function with IRQs disabled, + * yet IRQs have to be disabled before ctx_lock is obtained. + */ + if (mask && !req->work_scheduled && + spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) { struct kioctx *ctx = iocb->ki_ctx; - /* - * Try to complete the iocb inline if we can. Use - * irqsave/irqrestore because not all filesystems (e.g. fuse) - * call this function with IRQs disabled and because IRQs - * have to be disabled before ctx_lock is obtained. - */ + list_del_init(&req->wait.entry); list_del(&iocb->ki_list); iocb->ki_res.res = mangle_poll(mask); - req->done = true; if (iocb->ki_eventfd && eventfd_signal_count()) { iocb = NULL; INIT_WORK(&req->work, aio_poll_put_work); @@ -1705,7 +1771,43 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, if (iocb) iocb_put(iocb); } else { - schedule_work(&req->work); + /* + * Schedule the completion work if needed. If it was already + * scheduled, record that another wakeup came in. + * + * Don't remove the request from the waitqueue here, as it might + * not actually be complete yet (we won't know until vfs_poll() + * is called), and we must not miss any wakeups. POLLFREE is an + * exception to this; see below. + */ + if (req->work_scheduled) { + req->work_need_resched = true; + } else { + schedule_work(&req->work); + req->work_scheduled = true; + } + + /* + * If the waitqueue is being freed early but we can't complete + * the request inline, we have to tear down the request as best + * we can. That means immediately removing the request from its + * waitqueue and preventing all further accesses to the + * waitqueue via the request. We also need to schedule the + * completion work (done above). Also mark the request as + * cancelled, to potentially skip an unneeded call to ->poll(). + */ + if (mask & POLLFREE) { + WRITE_ONCE(req->cancelled, true); + list_del_init(&req->wait.entry); + + /* + * Careful: this *must* be the last step, since as soon + * as req->head is NULL'ed out, the request can be + * completed and freed, since aio_poll_complete_work() + * will no longer need to take the waitqueue lock. + */ + smp_store_release(&req->head, NULL); + } } return 1; } @@ -1713,6 +1815,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, struct aio_poll_table { struct poll_table_struct pt; struct aio_kiocb *iocb; + bool queued; int error; }; @@ -1723,11 +1826,12 @@ aio_poll_queue_proc(struct file *file, struct wait_queue_head *head, struct aio_poll_table *pt = container_of(p, struct aio_poll_table, pt); /* multiple wait queues per file are not supported */ - if (unlikely(pt->iocb->poll.head)) { + if (unlikely(pt->queued)) { pt->error = -EINVAL; return; } + pt->queued = true; pt->error = 0; pt->iocb->poll.head = head; add_wait_queue(head, &pt->iocb->poll.wait); @@ -1752,12 +1856,14 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb) req->events = demangle_poll(iocb->aio_buf) | EPOLLERR | EPOLLHUP; req->head = NULL; - req->done = false; req->cancelled = false; + req->work_scheduled = false; + req->work_need_resched = false; apt.pt._qproc = aio_poll_queue_proc; apt.pt._key = req->events; apt.iocb = aiocb; + apt.queued = false; apt.error = -EINVAL; /* same as no support for IOCB_CMD_POLL */ /* initialized the list so that we can do list_empty checks */ @@ -1766,23 +1872,35 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb) mask = vfs_poll(req->file, &apt.pt) & req->events; spin_lock_irq(&ctx->ctx_lock); - if (likely(req->head)) { - spin_lock(&req->head->lock); - if (unlikely(list_empty(&req->wait.entry))) { - if (apt.error) + if (likely(apt.queued)) { + bool on_queue = poll_iocb_lock_wq(req); + + if (!on_queue || req->work_scheduled) { + /* + * aio_poll_wake() already either scheduled the async + * completion work, or completed the request inline. + */ + if (apt.error) /* unsupported case: multiple queues */ cancel = true; apt.error = 0; mask = 0; } if (mask || apt.error) { + /* Steal to complete synchronously. */ list_del_init(&req->wait.entry); } else if (cancel) { + /* Cancel if possible (may be too late though). */ WRITE_ONCE(req->cancelled, true); - } else if (!req->done) { /* actually waiting for an event */ + } else if (on_queue) { + /* + * Actually waiting for an event, so add the request to + * active_reqs so that it can be cancelled if needed. + */ list_add_tail(&aiocb->ki_list, &ctx->active_reqs); aiocb->ki_cancel = aio_poll_cancel; } - spin_unlock(&req->head->lock); + if (on_queue) + poll_iocb_unlock_wq(req); } if (mask) { /* no async, we'd stolen it */ aiocb->ki_res.res = mangle_poll(mask); diff --git a/fs/attr.c b/fs/attr.c index b4bbdbd4c8ca..b7b770374e74 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/attr.c @@ -18,6 +21,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + static bool chown_ok(const struct inode *inode, kuid_t uid) { if (uid_eq(current_fsuid(), inode->i_uid) && @@ -243,6 +250,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de if (IS_IMMUTABLE(inode)) return -EPERM; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + error = synoacl_op_permission(dentry, MAY_WRITE_ATTR | MAY_WRITE_EXT_ATTR); + if (error) + return error; + } else +#endif /* MY_ABC_HERE */ if (!inode_owner_or_capable(inode)) { error = inode_permission(inode, MAY_WRITE); if (error) @@ -332,12 +346,23 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de if (error) return error; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + error = synoacl_op_setattr_prepare(dentry, attr); + if (error) + return error; + } +#endif /* MY_ABC_HERE */ if (inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); else error = simple_setattr(dentry, attr); if (!error) { +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) + synoacl_op_setattr_post(dentry, attr); +#endif /* MY_ABC_HERE */ fsnotify_change(dentry, ia_valid); ima_inode_post_setattr(dentry); evm_inode_post_setattr(dentry, ia_valid); diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig new file mode 100644 index 000000000000..9f436425716a --- /dev/null +++ b/fs/aufs/Kconfig @@ -0,0 +1,199 @@ +# SPDX-License-Identifier: GPL-2.0 +config AUFS_FS + tristate "Aufs (Advanced multi layered unification filesystem) support" + help + Aufs is a stackable unification filesystem such as Unionfs, + which unifies several directories and provides a merged single + directory. + In the early days, aufs was entirely re-designed and + re-implemented Unionfs Version 1.x series. Introducing many + original ideas, approaches and improvements, it becomes totally + different from Unionfs while keeping the basic features. + +if AUFS_FS +choice + prompt "Maximum number of branches" + default AUFS_BRANCH_MAX_127 + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_127 + bool "127" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_511 + bool "511" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_1023 + bool "1023" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +config AUFS_BRANCH_MAX_32767 + bool "32767" + help + Specifies the maximum number of branches (or member directories) + in a single aufs. The larger value consumes more system + resources and has a minor impact to performance. +endchoice + +config AUFS_SBILIST + bool + depends on AUFS_MAGIC_SYSRQ || PROC_FS + default y + help + Automatic configuration for internal use. + When aufs supports Magic SysRq or /proc, enabled automatically. + +config AUFS_HNOTIFY + bool "Detect direct branch access (bypassing aufs)" + help + If you want to modify files on branches directly, eg. bypassing aufs, + and want aufs to detect the changes of them fully, then enable this + option and use 'udba=notify' mount option. + Currently there is only one available configuration, "fsnotify". + It will have a negative impact to the performance. + See detail in aufs.5. + +choice + prompt "method" if AUFS_HNOTIFY + default AUFS_HFSNOTIFY +config AUFS_HFSNOTIFY + bool "fsnotify" + select FSNOTIFY +endchoice + +config AUFS_EXPORT + bool "NFS-exportable aufs" + depends on EXPORTFS + help + If you want to export your mounted aufs via NFS, then enable this + option. There are several requirements for this configuration. + See detail in aufs.5. + +config AUFS_INO_T_64 + bool + depends on AUFS_EXPORT + depends on 64BIT && !(ALPHA || S390) + default y + help + Automatic configuration for internal use. + /* typedef unsigned long/int __kernel_ino_t */ + /* alpha and s390x are int */ + +config AUFS_XATTR + bool "support for XATTR/EA (including Security Labels)" + help + If your branch fs supports XATTR/EA and you want to make them + available in aufs too, then enable this opsion and specify the + branch attributes for EA. + See detail in aufs.5. + +config AUFS_FHSM + bool "File-based Hierarchical Storage Management" + help + Hierarchical Storage Management (or HSM) is a well-known feature + in the storage world. Aufs provides this feature as file-based. + with multiple branches. + These multiple branches are prioritized, ie. the topmost one + should be the fastest drive and be used heavily. + +config AUFS_RDU + bool "Readdir in userspace" + help + Aufs has two methods to provide a merged view for a directory, + by a user-space library and by kernel-space natively. The latter + is always enabled but sometimes large and slow. + If you enable this option, install the library in aufs2-util + package, and set some environment variables for your readdir(3), + then the work will be handled in user-space which generally + shows better performance in most cases. + See detail in aufs.5. + +config AUFS_DIRREN + bool "Workaround for rename(2)-ing a directory" + help + By default, aufs returns EXDEV error in renameing a dir who has + his child on the lower branch, since it is a bad idea to issue + rename(2) internally for every lower branch. But user may not + accept this behaviour. So here is a workaround to allow such + rename(2) and store some extra infromation on the writable + branch. Obviously this costs high (and I don't like it). + To use this feature, you need to enable this configuration AND + to specify the mount option `dirren.' + See details in aufs.5 and the design documents. + +config AUFS_SHWH + bool "Show whiteouts" + help + If you want to make the whiteouts in aufs visible, then enable + this option and specify 'shwh' mount option. Although it may + sounds like philosophy or something, but in technically it + simply shows the name of whiteout with keeping its behaviour. + +config AUFS_BR_RAMFS + bool "Ramfs (initramfs/rootfs) as an aufs branch" + help + If you want to use ramfs as an aufs branch fs, then enable this + option. Generally tmpfs is recommended. + Aufs prohibited them to be a branch fs by default, because + initramfs becomes unusable after switch_root or something + generally. If you sets initramfs as an aufs branch and boot your + system by switch_root, you will meet a problem easily since the + files in initramfs may be inaccessible. + Unless you are going to use ramfs as an aufs branch fs without + switch_root or something, leave it N. + +config AUFS_BR_FUSE + bool "Fuse fs as an aufs branch" + depends on FUSE_FS + select AUFS_POLL + help + If you want to use fuse-based userspace filesystem as an aufs + branch fs, then enable this option. + It implements the internal poll(2) operation which is + implemented by fuse only (curretnly). + +config AUFS_POLL + bool + help + Automatic configuration for internal use. + +config AUFS_BR_HFSPLUS + bool "Hfsplus as an aufs branch" + depends on HFSPLUS_FS + default y + help + If you want to use hfsplus fs as an aufs branch fs, then enable + this option. This option introduces a small overhead at + copying-up a file on hfsplus. + +config AUFS_BDEV_LOOP + bool + depends on BLK_DEV_LOOP + default y + help + Automatic configuration for internal use. + Convert =[ym] into =y. + +config AUFS_DEBUG + bool "Debug aufs" + help + Enable this to compile aufs internal debug code. + It will have a negative impact to the performance. + +config AUFS_MAGIC_SYSRQ + bool + depends on AUFS_DEBUG && MAGIC_SYSRQ + default y + help + Automatic configuration for internal use. + When aufs supports Magic SysRq, enabled automatically. +endif diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile new file mode 100644 index 000000000000..e41dcf8d05d6 --- /dev/null +++ b/fs/aufs/Makefile @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0 + +include ${srctree}/${src}/magic.mk +#ifeq (${CONFIG_AUFS_FS},m) +#include ${srctree}/${src}/conf.mk +#endif +-include ${srctree}/${src}/priv_def.mk + +# cf. include/linux/kernel.h +# enable pr_debug +ccflags-y += -DDEBUG +# sparse requires the full pathname +ifdef M +ccflags-y += -include ${M}/../../include/uapi/linux/aufs_type.h +else +ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h +endif + +obj-$(CONFIG_AUFS_FS) += aufs.o +aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ + wkq.o vfsub.o dcsub.o \ + cpup.o whout.o wbr_policy.o \ + dinfo.o dentry.o \ + dynop.o \ + finfo.o file.o f_op.o \ + dir.o vdir.o \ + iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ + mvdown.o ioctl.o + +# all are boolean +aufs-$(CONFIG_PROC_FS) += procfs.o plink.o +aufs-$(CONFIG_SYSFS) += sysfs.o +aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o +aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o +aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o +aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o +aufs-$(CONFIG_AUFS_EXPORT) += export.o +aufs-$(CONFIG_AUFS_XATTR) += xattr.o +aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o +aufs-$(CONFIG_AUFS_DIRREN) += dirren.o +aufs-$(CONFIG_AUFS_FHSM) += fhsm.o +aufs-$(CONFIG_AUFS_POLL) += poll.o +aufs-$(CONFIG_AUFS_RDU) += rdu.o +aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o +aufs-$(CONFIG_AUFS_DEBUG) += debug.o +aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h new file mode 100644 index 000000000000..a62a85211b88 --- /dev/null +++ b/fs/aufs/aufs.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * all header files + */ + +#ifndef __AUFS_H__ +#define __AUFS_H__ + +#ifdef __KERNEL__ + +#define AuStub(type, name, body, ...) \ + static inline type name(__VA_ARGS__) { body; } + +#define AuStubVoid(name, ...) \ + AuStub(void, name, , __VA_ARGS__) +#define AuStubInt0(name, ...) \ + AuStub(int, name, return 0, __VA_ARGS__) + +#include "debug.h" + +#include "branch.h" +#include "cpup.h" +#include "dcsub.h" +#include "dbgaufs.h" +#include "dentry.h" +#include "dir.h" +#include "dirren.h" +#include "dynop.h" +#include "file.h" +#include "fstype.h" +#include "hbl.h" +#include "inode.h" +#include "lcnt.h" +#include "loop.h" +#include "module.h" +#include "opts.h" +#include "rwsem.h" +#include "super.h" +#include "sysaufs.h" +#include "vfsub.h" +#include "whout.h" +#include "wkq.h" + +#endif /* __KERNEL__ */ +#endif /* __AUFS_H__ */ diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c new file mode 100644 index 000000000000..356790acb758 --- /dev/null +++ b/fs/aufs/branch.c @@ -0,0 +1,1427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * branch management + */ + +#include +#include +#include "aufs.h" + +/* + * free a single branch + */ +static void au_br_do_free(struct au_branch *br) +{ + int i; + struct au_wbr *wbr; + struct au_dykey **key; + + au_hnotify_fin_br(br); + /* always, regardless the mount option */ + au_dr_hino_free(&br->br_dirren); + au_xino_put(br); + + AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); + au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); + AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); + au_lcnt_fin(&br->br_count, /*do_sync*/0); + + wbr = br->br_wbr; + if (wbr) { + for (i = 0; i < AuBrWh_Last; i++) + dput(wbr->wbr_wh[i]); + AuDebugOn(atomic_read(&wbr->wbr_wh_running)); + AuRwDestroy(&wbr->wbr_wh_rwsem); + } + + if (br->br_fhsm) { + au_br_fhsm_fin(br->br_fhsm); + au_kfree_try_rcu(br->br_fhsm); + } + + key = br->br_dykey; + for (i = 0; i < AuBrDynOp; i++, key++) + if (*key) + au_dy_put(*key); + else + break; + + /* recursive lock, s_umount of branch's */ + /* synchronize_rcu(); */ /* why? */ + lockdep_off(); + path_put(&br->br_path); + lockdep_on(); + au_kfree_rcu(wbr); + au_lcnt_wait_for_fin(&br->br_nfiles); + au_lcnt_wait_for_fin(&br->br_count); + /* I don't know why, but percpu_refcount requires this */ + /* synchronize_rcu(); */ + au_kfree_rcu(br); +} + +/* + * frees all branches + */ +void au_br_free(struct au_sbinfo *sbinfo) +{ + aufs_bindex_t bmax; + struct au_branch **br; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + bmax = sbinfo->si_bbot + 1; + br = sbinfo->si_branch; + while (bmax--) + au_br_do_free(*br++); +} + +/* + * find the index of a branch which is specified by @br_id. + */ +int au_br_index(struct super_block *sb, aufs_bindex_t br_id) +{ + aufs_bindex_t bindex, bbot; + + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) + if (au_sbr_id(sb, bindex) == br_id) + return bindex; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* + * add a branch + */ + +static int test_overlap(struct super_block *sb, struct dentry *h_adding, + struct dentry *h_root) +{ + if (unlikely(h_adding == h_root + || au_test_loopback_overlap(sb, h_adding))) + return 1; + if (h_adding->d_sb != h_root->d_sb) + return 0; + return au_test_subdir(h_adding, h_root) + || au_test_subdir(h_root, h_adding); +} + +/* + * returns a newly allocated branch. @new_nbranch is a number of branches + * after adding a branch. + */ +static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, + int perm) +{ + struct au_branch *add_branch; + struct dentry *root; + struct inode *inode; + int err; + + err = -ENOMEM; + add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); + if (unlikely(!add_branch)) + goto out; + add_branch->br_xino = au_xino_alloc(/*nfile*/1); + if (unlikely(!add_branch->br_xino)) + goto out_br; + err = au_hnotify_init_br(add_branch, perm); + if (unlikely(err)) + goto out_xino; + + if (au_br_writable(perm)) { + /* may be freed separately at changing the branch permission */ + add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), + GFP_NOFS); + if (unlikely(!add_branch->br_wbr)) + goto out_hnotify; + } + + if (au_br_fhsm(perm)) { + err = au_fhsm_br_alloc(add_branch); + if (unlikely(err)) + goto out_wbr; + } + + root = sb->s_root; + err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); + if (!err) + err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); + if (!err) { + inode = d_inode(root); + err = au_hinode_realloc(au_ii(inode), new_nbranch, + /*may_shrink*/0); + } + if (!err) + return add_branch; /* success */ + +out_wbr: + au_kfree_rcu(add_branch->br_wbr); +out_hnotify: + au_hnotify_fin_br(add_branch); +out_xino: + au_xino_put(add_branch); +out_br: + au_kfree_rcu(add_branch); +out: + return ERR_PTR(err); +} + +/* + * test if the branch permission is legal or not. + */ +static int test_br(struct inode *inode, int brperm, char *path) +{ + int err; + + err = (au_br_writable(brperm) && IS_RDONLY(inode)); + if (!err) + goto out; + + err = -EINVAL; + pr_err("write permission for readonly mount or inode, %s\n", path); + +out: + return err; +} + +/* + * returns: + * 0: success, the caller will add it + * plus: success, it is already unified, the caller should ignore it + * minus: error + */ +static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) +{ + int err; + aufs_bindex_t bbot, bindex; + struct dentry *root, *h_dentry; + struct inode *inode, *h_inode; + + root = sb->s_root; + bbot = au_sbbot(sb); + if (unlikely(bbot >= 0 + && au_find_dbindex(root, add->path.dentry) >= 0)) { + err = 1; + if (!remount) { + err = -EINVAL; + pr_err("%s duplicated\n", add->pathname); + } + goto out; + } + + err = -ENOSPC; /* -E2BIG; */ + if (unlikely(AUFS_BRANCH_MAX <= add->bindex + || AUFS_BRANCH_MAX - 1 <= bbot)) { + pr_err("number of branches exceeded %s\n", add->pathname); + goto out; + } + + err = -EDOM; + if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { + pr_err("bad index %d\n", add->bindex); + goto out; + } + + inode = d_inode(add->path.dentry); + err = -ENOENT; + if (unlikely(!inode->i_nlink)) { + pr_err("no existence %s\n", add->pathname); + goto out; + } + + err = -EINVAL; + if (unlikely(inode->i_sb == sb)) { + pr_err("%s must be outside\n", add->pathname); + goto out; + } + + if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { + pr_err("unsupported filesystem, %s (%s)\n", + add->pathname, au_sbtype(inode->i_sb)); + goto out; + } + + if (unlikely(inode->i_sb->s_stack_depth)) { + pr_err("already stacked, %s (%s)\n", + add->pathname, au_sbtype(inode->i_sb)); + goto out; + } + + err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); + if (unlikely(err)) + goto out; + + if (bbot < 0) + return 0; /* success */ + + err = -EINVAL; + for (bindex = 0; bindex <= bbot; bindex++) + if (unlikely(test_overlap(sb, add->path.dentry, + au_h_dptr(root, bindex)))) { + pr_err("%s is overlapped\n", add->pathname); + goto out; + } + + err = 0; + if (au_opt_test(au_mntflags(sb), WARN_PERM)) { + h_dentry = au_h_dptr(root, 0); + h_inode = d_inode(h_dentry); + if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) + || !uid_eq(h_inode->i_uid, inode->i_uid) + || !gid_eq(h_inode->i_gid, inode->i_gid)) + pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", + add->pathname, + i_uid_read(inode), i_gid_read(inode), + (inode->i_mode & S_IALLUGO), + i_uid_read(h_inode), i_gid_read(h_inode), + (h_inode->i_mode & S_IALLUGO)); + } + +out: + return err; +} + +/* + * initialize or clean the whiteouts for an adding branch + */ +static int au_br_init_wh(struct super_block *sb, struct au_branch *br, + int new_perm) +{ + int err, old_perm; + aufs_bindex_t bindex; + struct inode *h_inode; + struct au_wbr *wbr; + struct au_hinode *hdir; + struct dentry *h_dentry; + + err = vfsub_mnt_want_write(au_br_mnt(br)); + if (unlikely(err)) + goto out; + + wbr = br->br_wbr; + old_perm = br->br_perm; + br->br_perm = new_perm; + hdir = NULL; + h_inode = NULL; + bindex = au_br_index(sb, br->br_id); + if (0 <= bindex) { + hdir = au_hi(d_inode(sb->s_root), bindex); + au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); + } else { + h_dentry = au_br_dentry(br); + h_inode = d_inode(h_dentry); + inode_lock_nested(h_inode, AuLsc_I_PARENT); + } + if (!wbr) + err = au_wh_init(br, sb); + else { + wbr_wh_write_lock(wbr); + err = au_wh_init(br, sb); + wbr_wh_write_unlock(wbr); + } + if (hdir) + au_hn_inode_unlock(hdir); + else + inode_unlock(h_inode); + vfsub_mnt_drop_write(au_br_mnt(br)); + br->br_perm = old_perm; + + if (!err && wbr && !au_br_writable(new_perm)) { + au_kfree_rcu(wbr); + br->br_wbr = NULL; + } + +out: + return err; +} + +static int au_wbr_init(struct au_branch *br, struct super_block *sb, + int perm) +{ + int err; + struct kstatfs kst; + struct au_wbr *wbr; + + wbr = br->br_wbr; + au_rw_init(&wbr->wbr_wh_rwsem); + atomic_set(&wbr->wbr_wh_running, 0); + + /* + * a limit for rmdir/rename a dir + * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h + */ + err = vfs_statfs(&br->br_path, &kst); + if (unlikely(err)) + goto out; + err = -EINVAL; + if (kst.f_namelen >= NAME_MAX) + err = au_br_init_wh(sb, br, perm); + else + pr_err("%pd(%s), unsupported namelen %ld\n", + au_br_dentry(br), + au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); + +out: + return err; +} + +/* initialize a new branch */ +static int au_br_init(struct au_branch *br, struct super_block *sb, + struct au_opt_add *add) +{ + int err; + struct au_branch *brbase; + struct file *xf; + struct inode *h_inode; + + err = 0; + br->br_perm = add->perm; + br->br_path = add->path; /* set first, path_get() later */ + spin_lock_init(&br->br_dykey_lock); + au_lcnt_init(&br->br_nfiles, /*release*/NULL); + au_lcnt_init(&br->br_count, /*release*/NULL); + br->br_id = au_new_br_id(sb); + AuDebugOn(br->br_id < 0); + + /* always, regardless the given option */ + err = au_dr_br_init(sb, br, &add->path); + if (unlikely(err)) + goto out_err; + + if (au_br_writable(add->perm)) { + err = au_wbr_init(br, sb, add->perm); + if (unlikely(err)) + goto out_err; + } + + if (au_opt_test(au_mntflags(sb), XINO)) { + brbase = au_sbr(sb, 0); + xf = au_xino_file(brbase->br_xino, /*idx*/-1); + AuDebugOn(!xf); + h_inode = d_inode(add->path.dentry); + err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); + if (unlikely(err)) { + AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); + goto out_err; + } + } + + sysaufs_br_init(br); + path_get(&br->br_path); + goto out; /* success */ + +out_err: + memset(&br->br_path, 0, sizeof(br->br_path)); +out: + return err; +} + +static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, + struct au_branch *br, aufs_bindex_t bbot, + aufs_bindex_t amount) +{ + struct au_branch **brp; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + brp = sbinfo->si_branch + bindex; + memmove(brp + 1, brp, sizeof(*brp) * amount); + *brp = br; + sbinfo->si_bbot++; + if (unlikely(bbot < 0)) + sbinfo->si_bbot = 0; +} + +static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, + aufs_bindex_t bbot, aufs_bindex_t amount) +{ + struct au_hdentry *hdp; + + AuRwMustWriteLock(&dinfo->di_rwsem); + + hdp = au_hdentry(dinfo, bindex); + memmove(hdp + 1, hdp, sizeof(*hdp) * amount); + au_h_dentry_init(hdp); + dinfo->di_bbot++; + if (unlikely(bbot < 0)) + dinfo->di_btop = 0; +} + +static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, + aufs_bindex_t bbot, aufs_bindex_t amount) +{ + struct au_hinode *hip; + + AuRwMustWriteLock(&iinfo->ii_rwsem); + + hip = au_hinode(iinfo, bindex); + memmove(hip + 1, hip, sizeof(*hip) * amount); + au_hinode_init(hip); + iinfo->ii_bbot++; + if (unlikely(bbot < 0)) + iinfo->ii_btop = 0; +} + +static void au_br_do_add(struct super_block *sb, struct au_branch *br, + aufs_bindex_t bindex) +{ + struct dentry *root, *h_dentry; + struct inode *root_inode, *h_inode; + aufs_bindex_t bbot, amount; + + root = sb->s_root; + root_inode = d_inode(root); + bbot = au_sbbot(sb); + amount = bbot + 1 - bindex; + h_dentry = au_br_dentry(br); + au_sbilist_lock(); + au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); + au_br_do_add_hdp(au_di(root), bindex, bbot, amount); + au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); + au_set_h_dptr(root, bindex, dget(h_dentry)); + h_inode = d_inode(h_dentry); + au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); + au_sbilist_unlock(); +} + +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) +{ + int err; + aufs_bindex_t bbot, add_bindex; + struct dentry *root, *h_dentry; + struct inode *root_inode; + struct au_branch *add_branch; + + root = sb->s_root; + root_inode = d_inode(root); + IMustLock(root_inode); + IiMustWriteLock(root_inode); + err = test_add(sb, add, remount); + if (unlikely(err < 0)) + goto out; + if (err) { + err = 0; + goto out; /* success */ + } + + bbot = au_sbbot(sb); + add_branch = au_br_alloc(sb, bbot + 2, add->perm); + err = PTR_ERR(add_branch); + if (IS_ERR(add_branch)) + goto out; + + err = au_br_init(add_branch, sb, add); + if (unlikely(err)) { + au_br_do_free(add_branch); + goto out; + } + + add_bindex = add->bindex; + sysaufs_brs_del(sb, add_bindex); /* remove successors */ + au_br_do_add(sb, add_branch, add_bindex); + sysaufs_brs_add(sb, add_bindex); /* append successors */ + dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ + + h_dentry = add->path.dentry; + if (!add_bindex) { + au_cpup_attr_all(root_inode, /*force*/1); + sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; + } else + au_add_nlink(root_inode, d_inode(h_dentry)); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +static unsigned long long au_farray_cb(struct super_block *sb, void *a, + unsigned long long max __maybe_unused, + void *arg) +{ + unsigned long long n; + struct file **p, *f; + struct hlist_bl_head *files; + struct hlist_bl_node *pos; + struct au_finfo *finfo; + + n = 0; + p = a; + files = &au_sbi(sb)->si_files; + hlist_bl_lock(files); + hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { + f = finfo->fi_file; + if (file_count(f) + && !special_file(file_inode(f)->i_mode)) { + get_file(f); + *p++ = f; + n++; + AuDebugOn(n > max); + } + } + hlist_bl_unlock(files); + + return n; +} + +static struct file **au_farray_alloc(struct super_block *sb, + unsigned long long *max) +{ + struct au_sbinfo *sbi; + + sbi = au_sbi(sb); + *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); + return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); +} + +static void au_farray_free(struct file **a, unsigned long long max) +{ + unsigned long long ull; + + for (ull = 0; ull < max; ull++) + if (a[ull]) + fput(a[ull]); + kvfree(a); +} + +/* ---------------------------------------------------------------------- */ + +/* + * delete a branch + */ + +/* to show the line number, do not make it inlined function */ +#define AuVerbose(do_info, fmt, ...) do { \ + if (do_info) \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + +static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, + aufs_bindex_t bbot) +{ + return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; +} + +static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, + aufs_bindex_t bbot) +{ + return au_test_ibusy(d_inode(dentry), btop, bbot); +} + +/* + * test if the branch is deletable or not. + */ +static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, + unsigned int sigen, const unsigned int verbose) +{ + int err, i, j, ndentry; + aufs_bindex_t btop, bbot; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry *d; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, root, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + for (i = 0; !err && i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = 0; !err && j < ndentry; j++) { + d = dpage->dentries[j]; + AuDebugOn(au_dcount(d) <= 0); + if (!au_digen_test(d, sigen)) { + di_read_lock_child(d, AuLock_IR); + if (unlikely(au_dbrange_test(d))) { + di_read_unlock(d, AuLock_IR); + continue; + } + } else { + di_write_lock_child(d); + if (unlikely(au_dbrange_test(d))) { + di_write_unlock(d); + continue; + } + err = au_reval_dpath(d, sigen); + if (!err) + di_downgrade_lock(d, AuLock_IR); + else { + di_write_unlock(d); + break; + } + } + + /* AuDbgDentry(d); */ + btop = au_dbtop(d); + bbot = au_dbbot(d); + if (btop <= bindex + && bindex <= bbot + && au_h_dptr(d, bindex) + && au_test_dbusy(d, btop, bbot)) { + err = -EBUSY; + AuVerbose(verbose, "busy %pd\n", d); + AuDbgDentry(d); + } + di_read_unlock(d, AuLock_IR); + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, + unsigned int sigen, const unsigned int verbose) +{ + int err; + unsigned long long max, ull; + struct inode *i, **array; + aufs_bindex_t btop, bbot; + + array = au_iarray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + err = 0; + AuDbg("b%d\n", bindex); + for (ull = 0; !err && ull < max; ull++) { + i = array[ull]; + if (unlikely(!i)) + break; + if (i->i_ino == AUFS_ROOT_INO) + continue; + + /* AuDbgInode(i); */ + if (au_iigen(i, NULL) == sigen) + ii_read_lock_child(i); + else { + ii_write_lock_child(i); + err = au_refresh_hinode_self(i); + au_iigen_dec(i); + if (!err) + ii_downgrade_lock(i); + else { + ii_write_unlock(i); + break; + } + } + + btop = au_ibtop(i); + bbot = au_ibbot(i); + if (btop <= bindex + && bindex <= bbot + && au_h_iptr(i, bindex) + && au_test_ibusy(i, btop, bbot)) { + err = -EBUSY; + AuVerbose(verbose, "busy i%lu\n", i->i_ino); + AuDbgInode(i); + } + ii_read_unlock(i); + } + au_iarray_free(array, max); + +out: + return err; +} + +static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, + const unsigned int verbose) +{ + int err; + unsigned int sigen; + + sigen = au_sigen(root->d_sb); + DiMustNoWaiters(root); + IiMustNoWaiters(d_inode(root)); + di_write_unlock(root); + err = test_dentry_busy(root, bindex, sigen, verbose); + if (!err) + err = test_inode_busy(root->d_sb, bindex, sigen, verbose); + di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ + + return err; +} + +static int test_dir_busy(struct file *file, aufs_bindex_t br_id, + struct file **to_free, int *idx) +{ + int err; + unsigned char matched, root; + aufs_bindex_t bindex, bbot; + struct au_fidir *fidir; + struct au_hfile *hfile; + + err = 0; + root = IS_ROOT(file->f_path.dentry); + if (root) { + get_file(file); + to_free[*idx] = file; + (*idx)++; + goto out; + } + + matched = 0; + fidir = au_fi(file)->fi_hdir; + AuDebugOn(!fidir); + bbot = au_fbbot_dir(file); + for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { + hfile = fidir->fd_hfile + bindex; + if (!hfile->hf_file) + continue; + + if (hfile->hf_br->br_id == br_id) { + matched = 1; + break; + } + } + if (matched) + err = -EBUSY; + +out: + return err; +} + +static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, + struct file **to_free, int opened) +{ + int err, idx; + unsigned long long ull, max; + aufs_bindex_t btop; + struct file *file, **array; + struct dentry *root; + struct au_hfile *hfile; + + array = au_farray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + err = 0; + idx = 0; + root = sb->s_root; + di_write_unlock(root); + for (ull = 0; ull < max; ull++) { + file = array[ull]; + if (unlikely(!file)) + break; + + /* AuDbg("%pD\n", file); */ + fi_read_lock(file); + btop = au_fbtop(file); + if (!d_is_dir(file->f_path.dentry)) { + hfile = &au_fi(file)->fi_htop; + if (hfile->hf_br->br_id == br_id) + err = -EBUSY; + } else + err = test_dir_busy(file, br_id, to_free, &idx); + fi_read_unlock(file); + if (unlikely(err)) + break; + } + di_write_lock_child(root); + au_farray_free(array, max); + AuDebugOn(idx > opened); + +out: + return err; +} + +static void br_del_file(struct file **to_free, unsigned long long opened, + aufs_bindex_t br_id) +{ + unsigned long long ull; + aufs_bindex_t bindex, btop, bbot, bfound; + struct file *file; + struct au_fidir *fidir; + struct au_hfile *hfile; + + for (ull = 0; ull < opened; ull++) { + file = to_free[ull]; + if (unlikely(!file)) + break; + + /* AuDbg("%pD\n", file); */ + AuDebugOn(!d_is_dir(file->f_path.dentry)); + bfound = -1; + fidir = au_fi(file)->fi_hdir; + AuDebugOn(!fidir); + fi_write_lock(file); + btop = au_fbtop(file); + bbot = au_fbbot_dir(file); + for (bindex = btop; bindex <= bbot; bindex++) { + hfile = fidir->fd_hfile + bindex; + if (!hfile->hf_file) + continue; + + if (hfile->hf_br->br_id == br_id) { + bfound = bindex; + break; + } + } + AuDebugOn(bfound < 0); + au_set_h_fptr(file, bfound, NULL); + if (bfound == btop) { + for (btop++; btop <= bbot; btop++) + if (au_hf_dir(file, btop)) { + au_set_fbtop(file, btop); + break; + } + } + fi_write_unlock(file); + } +} + +static void au_br_do_del_brp(struct au_sbinfo *sbinfo, + const aufs_bindex_t bindex, + const aufs_bindex_t bbot) +{ + struct au_branch **brp, **p; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + brp = sbinfo->si_branch + bindex; + if (bindex < bbot) + memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); + sbinfo->si_branch[0 + bbot] = NULL; + sbinfo->si_bbot--; + + p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, + /*may_shrink*/1); + if (p) + sbinfo->si_branch = p; + /* harmless error */ +} + +static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, + const aufs_bindex_t bbot) +{ + struct au_hdentry *hdp, *p; + + AuRwMustWriteLock(&dinfo->di_rwsem); + + hdp = au_hdentry(dinfo, bindex); + if (bindex < bbot) + memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); + /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ + dinfo->di_bbot--; + + p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, + /*may_shrink*/1); + if (p) + dinfo->di_hdentry = p; + /* harmless error */ +} + +static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, + const aufs_bindex_t bbot) +{ + struct au_hinode *hip, *p; + + AuRwMustWriteLock(&iinfo->ii_rwsem); + + hip = au_hinode(iinfo, bindex); + if (bindex < bbot) + memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); + /* au_hinode_init(au_hinode(iinfo, bbot)); */ + iinfo->ii_bbot--; + + p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, + /*may_shrink*/1); + if (p) + iinfo->ii_hinode = p; + /* harmless error */ +} + +static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, + struct au_branch *br) +{ + aufs_bindex_t bbot; + struct au_sbinfo *sbinfo; + struct dentry *root, *h_root; + struct inode *inode, *h_inode; + struct au_hinode *hinode; + + SiMustWriteLock(sb); + + root = sb->s_root; + inode = d_inode(root); + sbinfo = au_sbi(sb); + bbot = sbinfo->si_bbot; + + h_root = au_h_dptr(root, bindex); + hinode = au_hi(inode, bindex); + h_inode = au_igrab(hinode->hi_inode); + au_hiput(hinode); + + au_sbilist_lock(); + au_br_do_del_brp(sbinfo, bindex, bbot); + au_br_do_del_hdp(au_di(root), bindex, bbot); + au_br_do_del_hip(au_ii(inode), bindex, bbot); + au_sbilist_unlock(); + + /* ignore an error */ + au_dr_br_fin(sb, br); /* always, regardless the mount option */ + + dput(h_root); + iput(h_inode); + au_br_do_free(br); +} + +static unsigned long long empty_cb(struct super_block *sb, void *array, + unsigned long long max, void *arg) +{ + return max; +} + +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) +{ + int err, rerr, i; + unsigned long long opened; + unsigned int mnt_flags; + aufs_bindex_t bindex, bbot, br_id; + unsigned char do_wh, verbose; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *root; + struct file **to_free; + + err = 0; + opened = 0; + to_free = NULL; + root = sb->s_root; + bindex = au_find_dbindex(root, del->h_path.dentry); + if (bindex < 0) { + if (remount) + goto out; /* success */ + err = -ENOENT; + pr_err("%s no such branch\n", del->pathname); + goto out; + } + AuDbg("bindex b%d\n", bindex); + + err = -EBUSY; + mnt_flags = au_mntflags(sb); + verbose = !!au_opt_test(mnt_flags, VERBOSE); + bbot = au_sbbot(sb); + if (unlikely(!bbot)) { + AuVerbose(verbose, "no more branches left\n"); + goto out; + } + + br = au_sbr(sb, bindex); + AuDebugOn(!path_equal(&br->br_path, &del->h_path)); + if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { + AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); + goto out; + } + + br_id = br->br_id; + opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); + if (unlikely(opened)) { + to_free = au_array_alloc(&opened, empty_cb, sb, NULL); + err = PTR_ERR(to_free); + if (IS_ERR(to_free)) + goto out; + + err = test_file_busy(sb, br_id, to_free, opened); + if (unlikely(err)) { + AuVerbose(verbose, "%llu file(s) opened\n", opened); + goto out; + } + } + + wbr = br->br_wbr; + do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); + if (do_wh) { + /* instead of WbrWhMustWriteLock(wbr) */ + SiMustWriteLock(sb); + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } + } + + err = test_children_busy(root, bindex, verbose); + if (unlikely(err)) { + if (do_wh) + goto out_wh; + goto out; + } + + err = 0; + if (to_free) { + /* + * now we confirmed the branch is deletable. + * let's free the remaining opened dirs on the branch. + */ + di_write_unlock(root); + br_del_file(to_free, opened, br_id); + di_write_lock_child(root); + } + + sysaufs_brs_del(sb, bindex); /* remove successors */ + dbgaufs_xino_del(br); /* remove one */ + au_br_do_del(sb, bindex, br); + sysaufs_brs_add(sb, bindex); /* append successors */ + dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ + + if (!bindex) { + au_cpup_attr_all(d_inode(root), /*force*/1); + sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; + } else + au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); + if (au_opt_test(mnt_flags, PLINK)) + au_plink_half_refresh(sb, br_id); + + goto out; /* success */ + +out_wh: + /* revert */ + rerr = au_br_init_wh(sb, br, br->br_perm); + if (rerr) + pr_warn("failed re-creating base whiteout, %s. (%d)\n", + del->pathname, rerr); +out: + if (to_free) + au_farray_free(to_free, opened); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) +{ + int err; + aufs_bindex_t btop, bbot; + struct aufs_ibusy ibusy; + struct inode *inode, *h_inode; + + err = -EPERM; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + err = copy_from_user(&ibusy, arg, sizeof(ibusy)); + if (!err) + /* VERIFY_WRITE */ + err = !access_ok(&arg->h_ino, sizeof(arg->h_ino)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + + err = -EINVAL; + si_read_lock(sb, AuLock_FLUSH); + if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) + goto out_unlock; + + err = 0; + ibusy.h_ino = 0; /* invalid */ + inode = ilookup(sb, ibusy.ino); + if (!inode + || inode->i_ino == AUFS_ROOT_INO + || au_is_bad_inode(inode)) + goto out_unlock; + + ii_read_lock_child(inode); + btop = au_ibtop(inode); + bbot = au_ibbot(inode); + if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { + h_inode = au_h_iptr(inode, ibusy.bindex); + if (h_inode && au_test_ibusy(inode, btop, bbot)) + ibusy.h_ino = h_inode->i_ino; + } + ii_read_unlock(inode); + iput(inode); + +out_unlock: + si_read_unlock(sb); + if (!err) { + err = __put_user(ibusy.h_ino, &arg->h_ino); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + } + } +out: + return err; +} + +long au_ibusy_ioctl(struct file *file, unsigned long arg) +{ + return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); +} + +#ifdef CONFIG_COMPAT +long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) +{ + return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); +} +#endif + +/* ---------------------------------------------------------------------- */ + +/* + * change a branch permission + */ + +static void au_warn_ima(void) +{ +#ifdef CONFIG_IMA + /* since it doesn't support mark_files_ro() */ + AuWarn1("RW -> RO makes IMA to produce wrong message\n"); +#endif +} + +static int do_need_sigen_inc(int a, int b) +{ + return au_br_whable(a) && !au_br_whable(b); +} + +static int need_sigen_inc(int old, int new) +{ + return do_need_sigen_inc(old, new) + || do_need_sigen_inc(new, old); +} + +static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) +{ + int err, do_warn; + unsigned int mnt_flags; + unsigned long long ull, max; + aufs_bindex_t br_id; + unsigned char verbose, writer; + struct file *file, *hf, **array; + struct au_hfile *hfile; + struct inode *h_inode; + + mnt_flags = au_mntflags(sb); + verbose = !!au_opt_test(mnt_flags, VERBOSE); + + array = au_farray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + do_warn = 0; + br_id = au_sbr_id(sb, bindex); + for (ull = 0; ull < max; ull++) { + file = array[ull]; + if (unlikely(!file)) + break; + + /* AuDbg("%pD\n", file); */ + fi_read_lock(file); + if (unlikely(au_test_mmapped(file))) { + err = -EBUSY; + AuVerbose(verbose, "mmapped %pD\n", file); + AuDbgFile(file); + FiMustNoWaiters(file); + fi_read_unlock(file); + goto out_array; + } + + hfile = &au_fi(file)->fi_htop; + hf = hfile->hf_file; + if (!d_is_reg(file->f_path.dentry) + || !(file->f_mode & FMODE_WRITE) + || hfile->hf_br->br_id != br_id + || !(hf->f_mode & FMODE_WRITE)) + array[ull] = NULL; + else { + do_warn = 1; + get_file(file); + } + + FiMustNoWaiters(file); + fi_read_unlock(file); + fput(file); + } + + err = 0; + if (do_warn) + au_warn_ima(); + + for (ull = 0; ull < max; ull++) { + file = array[ull]; + if (!file) + continue; + + /* todo: already flushed? */ + /* + * fs/super.c:mark_files_ro() is gone, but aufs keeps its + * approach which resets f_mode and calls mnt_drop_write() and + * file_release_write() for each file, because the branch + * attribute in aufs world is totally different from the native + * fs rw/ro mode. + */ + /* fi_read_lock(file); */ + hfile = &au_fi(file)->fi_htop; + hf = hfile->hf_file; + /* fi_read_unlock(file); */ + spin_lock(&hf->f_lock); + writer = !!(hf->f_mode & FMODE_WRITER); + hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); + spin_unlock(&hf->f_lock); + if (writer) { + h_inode = file_inode(hf); + if (hf->f_mode & FMODE_READ) + i_readcount_inc(h_inode); + put_write_access(h_inode); + __mnt_drop_write(hf->f_path.mnt); + } + } + +out_array: + au_farray_free(array, max); +out: + AuTraceErr(err); + return err; +} + +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_refresh) +{ + int err, rerr; + aufs_bindex_t bindex; + struct dentry *root; + struct au_branch *br; + struct au_br_fhsm *bf; + + root = sb->s_root; + bindex = au_find_dbindex(root, mod->h_root); + if (bindex < 0) { + if (remount) + return 0; /* success */ + err = -ENOENT; + pr_err("%s no such branch\n", mod->path); + goto out; + } + AuDbg("bindex b%d\n", bindex); + + err = test_br(d_inode(mod->h_root), mod->perm, mod->path); + if (unlikely(err)) + goto out; + + br = au_sbr(sb, bindex); + AuDebugOn(mod->h_root != au_br_dentry(br)); + if (br->br_perm == mod->perm) + return 0; /* success */ + + /* pre-allocate for non-fhsm --> fhsm */ + bf = NULL; + if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { + err = au_fhsm_br_alloc(br); + if (unlikely(err)) + goto out; + bf = br->br_fhsm; + br->br_fhsm = NULL; + } + + if (au_br_writable(br->br_perm)) { + /* remove whiteout base */ + err = au_br_init_wh(sb, br, mod->perm); + if (unlikely(err)) + goto out_bf; + + if (!au_br_writable(mod->perm)) { + /* rw --> ro, file might be mmapped */ + DiMustNoWaiters(root); + IiMustNoWaiters(d_inode(root)); + di_write_unlock(root); + err = au_br_mod_files_ro(sb, bindex); + /* aufs_write_lock() calls ..._child() */ + di_write_lock_child(root); + + if (unlikely(err)) { + rerr = -ENOMEM; + br->br_wbr = kzalloc(sizeof(*br->br_wbr), + GFP_NOFS); + if (br->br_wbr) + rerr = au_wbr_init(br, sb, br->br_perm); + if (unlikely(rerr)) { + AuIOErr("nested error %d (%d)\n", + rerr, err); + br->br_perm = mod->perm; + } + } + } + } else if (au_br_writable(mod->perm)) { + /* ro --> rw */ + err = -ENOMEM; + br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); + if (br->br_wbr) { + err = au_wbr_init(br, sb, mod->perm); + if (unlikely(err)) { + au_kfree_rcu(br->br_wbr); + br->br_wbr = NULL; + } + } + } + if (unlikely(err)) + goto out_bf; + + if (au_br_fhsm(br->br_perm)) { + if (!au_br_fhsm(mod->perm)) { + /* fhsm --> non-fhsm */ + au_br_fhsm_fin(br->br_fhsm); + au_kfree_rcu(br->br_fhsm); + br->br_fhsm = NULL; + } + } else if (au_br_fhsm(mod->perm)) + /* non-fhsm --> fhsm */ + br->br_fhsm = bf; + + *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); + br->br_perm = mod->perm; + goto out; /* success */ + +out_bf: + au_kfree_try_rcu(bf); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) +{ + int err; + struct kstatfs kstfs; + + err = vfs_statfs(&br->br_path, &kstfs); + if (!err) { + stfs->f_blocks = kstfs.f_blocks; + stfs->f_bavail = kstfs.f_bavail; + stfs->f_files = kstfs.f_files; + stfs->f_ffree = kstfs.f_ffree; + } + + return err; +} diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h new file mode 100644 index 000000000000..2d4973af8698 --- /dev/null +++ b/fs/aufs/branch.h @@ -0,0 +1,364 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * branch filesystems and xino for them + */ + +#ifndef __AUFS_BRANCH_H__ +#define __AUFS_BRANCH_H__ + +#ifdef __KERNEL__ + +#include +#include "dirren.h" +#include "dynop.h" +#include "lcnt.h" +#include "rwsem.h" +#include "super.h" + +/* ---------------------------------------------------------------------- */ + +/* a xino file */ +struct au_xino { + struct file **xi_file; + unsigned int xi_nfile; + + struct { + spinlock_t spin; + ino_t *array; + int total; + /* reserved for future use */ + /* unsigned long *bitmap; */ + wait_queue_head_t wqh; + } xi_nondir; + + struct mutex xi_mtx; /* protects xi_file array */ + struct hlist_bl_head xi_writing; + + atomic_t xi_truncating; + + struct kref xi_kref; +}; + +/* File-based Hierarchical Storage Management */ +struct au_br_fhsm { +#ifdef CONFIG_AUFS_FHSM + struct mutex bf_lock; + unsigned long bf_jiffy; + struct aufs_stfs bf_stfs; + int bf_readable; +#endif +}; + +/* members for writable branch only */ +enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; +struct au_wbr { + struct au_rwsem wbr_wh_rwsem; + struct dentry *wbr_wh[AuBrWh_Last]; + atomic_t wbr_wh_running; +#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ +#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ +#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ + + /* mfs mode */ + unsigned long long wbr_bytes; +}; + +/* ext2 has 3 types of operations at least, ext3 has 4 */ +#define AuBrDynOp (AuDyLast * 4) + +#ifdef CONFIG_AUFS_HFSNOTIFY +/* support for asynchronous destruction */ +struct au_br_hfsnotify { + struct fsnotify_group *hfsn_group; +}; +#endif + +/* sysfs entries */ +struct au_brsysfs { + char name[16]; + struct attribute attr; +}; + +enum { + AuBrSysfs_BR, + AuBrSysfs_BRID, + AuBrSysfs_Last +}; + +/* protected by superblock rwsem */ +struct au_branch { + struct au_xino *br_xino; + + aufs_bindex_t br_id; + + int br_perm; + struct path br_path; + spinlock_t br_dykey_lock; + struct au_dykey *br_dykey[AuBrDynOp]; + au_lcnt_t br_nfiles; /* opened files */ + au_lcnt_t br_count; /* in-use for other */ + + struct au_wbr *br_wbr; + struct au_br_fhsm *br_fhsm; + +#ifdef CONFIG_AUFS_HFSNOTIFY + struct au_br_hfsnotify *br_hfsn; +#endif + +#ifdef CONFIG_SYSFS + /* entries under sysfs per mount-point */ + struct au_brsysfs br_sysfs[AuBrSysfs_Last]; +#endif + +#ifdef CONFIG_DEBUG_FS + struct dentry *br_dbgaufs; /* xino */ +#endif + + struct au_dr_br br_dirren; +}; + +/* ---------------------------------------------------------------------- */ + +static inline struct vfsmount *au_br_mnt(struct au_branch *br) +{ + return br->br_path.mnt; +} + +static inline struct dentry *au_br_dentry(struct au_branch *br) +{ + return br->br_path.dentry; +} + +static inline struct super_block *au_br_sb(struct au_branch *br) +{ + return au_br_mnt(br)->mnt_sb; +} + +static inline int au_br_rdonly(struct au_branch *br) +{ + return (sb_rdonly(au_br_sb(br)) + || !au_br_writable(br->br_perm)) + ? -EROFS : 0; +} + +static inline int au_br_hnotifyable(int brperm __maybe_unused) +{ +#ifdef CONFIG_AUFS_HNOTIFY + return !(brperm & AuBrPerm_RR); +#else + return 0; +#endif +} + +static inline int au_br_test_oflag(int oflag, struct au_branch *br) +{ + int err, exec_flag; + + err = 0; + exec_flag = oflag & __FMODE_EXEC; + if (unlikely(exec_flag && path_noexec(&br->br_path))) + err = -EACCES; + + return err; +} + +static inline void au_xino_get(struct au_branch *br) +{ + struct au_xino *xi; + + xi = br->br_xino; + if (xi) + kref_get(&xi->xi_kref); +} + +static inline int au_xino_count(struct au_branch *br) +{ + int v; + struct au_xino *xi; + + v = 0; + xi = br->br_xino; + if (xi) + v = kref_read(&xi->xi_kref); + + return v; +} + +/* ---------------------------------------------------------------------- */ + +/* branch.c */ +struct au_sbinfo; +void au_br_free(struct au_sbinfo *sinfo); +int au_br_index(struct super_block *sb, aufs_bindex_t br_id); +struct au_opt_add; +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); +struct au_opt_del; +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); +long au_ibusy_ioctl(struct file *file, unsigned long arg); +#ifdef CONFIG_COMPAT +long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); +#endif +struct au_opt_mod; +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_refresh); +struct aufs_stfs; +int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); + +/* xino.c */ +static const loff_t au_loff_max = LLONG_MAX; + +aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); +struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, + int wbrtop); +struct file *au_xino_create2(struct super_block *sb, struct path *base, + struct file *copy_src); +struct au_xi_new { + struct au_xino *xi; /* switch between xino and xigen */ + int idx; + struct path *base; + struct file *copy_src; +}; +struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); + +int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t *ino); +int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t ino); +ssize_t xino_fread(struct file *file, void *buf, size_t size, loff_t *pos); +ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos); + +int au_xib_trunc(struct super_block *sb); +int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin); + +struct au_xino *au_xino_alloc(unsigned int nfile); +int au_xino_put(struct au_branch *br); +struct file *au_xino_file1(struct au_xino *xi); + +struct au_opt_xino; +void au_xino_clr(struct super_block *sb); +int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount); +struct file *au_xino_def(struct super_block *sb); +int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t hino, + struct path *base); + +ino_t au_xino_new_ino(struct super_block *sb); +void au_xino_delete_inode(struct inode *inode, const int unlinked); + +void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, + ino_t h_ino, int idx); +int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + int *idx); + +int au_xino_path(struct seq_file *seq, struct file *file); + +/* ---------------------------------------------------------------------- */ + +/* @idx is signed to accept -1 meaning the first file */ +static inline struct file *au_xino_file(struct au_xino *xi, int idx) +{ + struct file *file; + + file = NULL; + if (!xi) + goto out; + + if (idx >= 0) { + if (idx < xi->xi_nfile) + file = xi->xi_file[idx]; + } else + file = au_xino_file1(xi); + +out: + return file; +} + +/* ---------------------------------------------------------------------- */ + +/* Superblock to branch */ +static inline +aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_id; +} + +static inline +struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_mnt(au_sbr(sb, bindex)); +} + +static inline +struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_sb(au_sbr(sb, bindex)); +} + +static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_perm; +} + +static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_whable(au_sbr_perm(sb, bindex)); +} + +/* ---------------------------------------------------------------------- */ + +#define wbr_wh_read_lock(wbr) au_rw_read_lock(&(wbr)->wbr_wh_rwsem) +#define wbr_wh_write_lock(wbr) au_rw_write_lock(&(wbr)->wbr_wh_rwsem) +#define wbr_wh_read_trylock(wbr) au_rw_read_trylock(&(wbr)->wbr_wh_rwsem) +#define wbr_wh_write_trylock(wbr) au_rw_write_trylock(&(wbr)->wbr_wh_rwsem) +/* +#define wbr_wh_read_trylock_nested(wbr) \ + au_rw_read_trylock_nested(&(wbr)->wbr_wh_rwsem) +#define wbr_wh_write_trylock_nested(wbr) \ + au_rw_write_trylock_nested(&(wbr)->wbr_wh_rwsem) +*/ + +#define wbr_wh_read_unlock(wbr) au_rw_read_unlock(&(wbr)->wbr_wh_rwsem) +#define wbr_wh_write_unlock(wbr) au_rw_write_unlock(&(wbr)->wbr_wh_rwsem) +#define wbr_wh_downgrade_lock(wbr) au_rw_dgrade_lock(&(wbr)->wbr_wh_rwsem) + +#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&(wbr)->wbr_wh_rwsem) +#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&(wbr)->wbr_wh_rwsem) +#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&(wbr)->wbr_wh_rwsem) + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_FHSM +static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) +{ + mutex_init(&brfhsm->bf_lock); + brfhsm->bf_jiffy = 0; + brfhsm->bf_readable = 0; +} + +static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) +{ + mutex_destroy(&brfhsm->bf_lock); +} +#else +AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) +AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_BRANCH_H__ */ diff --git a/fs/aufs/conf.mk b/fs/aufs/conf.mk new file mode 100644 index 000000000000..12782f8e0f38 --- /dev/null +++ b/fs/aufs/conf.mk @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0 + +AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} + +define AuConf +ifdef ${1} +AuConfStr += ${1}=${${1}} +endif +endef + +AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ + SBILIST \ + HNOTIFY HFSNOTIFY \ + EXPORT INO_T_64 \ + XATTR \ + FHSM \ + RDU \ + DIRREN \ + SHWH \ + BR_RAMFS \ + BR_FUSE POLL \ + BR_HFSPLUS \ + BDEV_LOOP \ + DEBUG MAGIC_SYSRQ +$(foreach i, ${AuConfAll}, \ + $(eval $(call AuConf,CONFIG_AUFS_${i}))) + +AuConfName = ${obj}/conf.str +${AuConfName}.tmp: FORCE + @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ +${AuConfName}: ${AuConfName}.tmp + @diff -q $< $@ > /dev/null 2>&1 || { \ + echo ' GEN ' $@; \ + cp -p $< $@; \ + } +FORCE: +clean-files += ${AuConfName} ${AuConfName}.tmp +${obj}/sysfs.o: ${AuConfName} + +-include ${srctree}/${src}/conf_priv.mk diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c new file mode 100644 index 000000000000..6962c5486d26 --- /dev/null +++ b/fs/aufs/cpup.c @@ -0,0 +1,1445 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * copy-up functions, see wbr_policy.c for copy-down + */ + +#include +#include +#include +#include "aufs.h" + +void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) +{ + const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE + | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; + + BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); + + dst->i_flags |= iflags & ~mask; + if (au_test_fs_notime(dst->i_sb)) + dst->i_flags |= S_NOATIME | S_NOCMTIME; +} + +void au_cpup_attr_timesizes(struct inode *inode) +{ + struct inode *h_inode; + + h_inode = au_h_iptr(inode, au_ibtop(inode)); + fsstack_copy_attr_times(inode, h_inode); + fsstack_copy_inode_size(inode, h_inode); +} + +void au_cpup_attr_nlink(struct inode *inode, int force) +{ + struct inode *h_inode; + struct super_block *sb; + aufs_bindex_t bindex, bbot; + + sb = inode->i_sb; + bindex = au_ibtop(inode); + h_inode = au_h_iptr(inode, bindex); + if (!force + && !S_ISDIR(h_inode->i_mode) + && au_opt_test(au_mntflags(sb), PLINK) + && au_plink_test(inode)) + return; + + /* + * 0 can happen in revalidating. + * h_inode->i_mutex may not be held here, but it is harmless since once + * i_nlink reaches 0, it will never become positive except O_TMPFILE + * case. + * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause + * the incorrect link count. + */ + set_nlink(inode, h_inode->i_nlink); + + /* + * fewer nlink makes find(1) noisy, but larger nlink doesn't. + * it may includes whplink directory. + */ + if (S_ISDIR(h_inode->i_mode)) { + bbot = au_ibbot(inode); + for (bindex++; bindex <= bbot; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (h_inode) + au_add_nlink(inode, h_inode); + } + } +} + +void au_cpup_attr_changeable(struct inode *inode) +{ + struct inode *h_inode; + + h_inode = au_h_iptr(inode, au_ibtop(inode)); + inode->i_mode = h_inode->i_mode; + inode->i_uid = h_inode->i_uid; + inode->i_gid = h_inode->i_gid; + au_cpup_attr_timesizes(inode); + au_cpup_attr_flags(inode, h_inode->i_flags); +} + +void au_cpup_igen(struct inode *inode, struct inode *h_inode) +{ + struct au_iinfo *iinfo = au_ii(inode); + + IiMustWriteLock(inode); + + iinfo->ii_higen = h_inode->i_generation; + iinfo->ii_hsb1 = h_inode->i_sb; +} + +void au_cpup_attr_all(struct inode *inode, int force) +{ + struct inode *h_inode; + + h_inode = au_h_iptr(inode, au_ibtop(inode)); + au_cpup_attr_changeable(inode); + if (inode->i_nlink > 0) + au_cpup_attr_nlink(inode, force); + inode->i_rdev = h_inode->i_rdev; + inode->i_blkbits = h_inode->i_blkbits; + au_cpup_igen(inode, h_inode); +} + +/* ---------------------------------------------------------------------- */ + +/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ + +/* keep the timestamps of the parent dir when cpup */ +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct path *h_path) +{ + struct inode *h_inode; + + dt->dt_dentry = dentry; + dt->dt_h_path = *h_path; + h_inode = d_inode(h_path->dentry); + dt->dt_atime = h_inode->i_atime; + dt->dt_mtime = h_inode->i_mtime; + /* smp_mb(); */ +} + +void au_dtime_revert(struct au_dtime *dt) +{ + struct iattr attr; + int err; + + attr.ia_atime = dt->dt_atime; + attr.ia_mtime = dt->dt_mtime; + attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET + | ATTR_ATIME | ATTR_ATIME_SET; + + /* no delegation since this is a directory */ + err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); + if (unlikely(err)) + pr_warn("restoring timestamps failed(%d). ignored\n", err); +} + +/* ---------------------------------------------------------------------- */ + +/* internal use only */ +struct au_cpup_reg_attr { + int valid; + struct kstat st; + unsigned int iflags; /* inode->i_flags */ +}; + +static noinline_for_stack +int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, + struct au_cpup_reg_attr *h_src_attr) +{ + int err, sbits, icex; + unsigned int mnt_flags; + unsigned char verbose; + struct iattr ia; + struct path h_path; + struct inode *h_isrc, *h_idst; + struct kstat *h_st; + struct au_branch *br; + + h_path.dentry = au_h_dptr(dst, bindex); + h_idst = d_inode(h_path.dentry); + br = au_sbr(dst->d_sb, bindex); + h_path.mnt = au_br_mnt(br); + h_isrc = d_inode(h_src); + ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID + | ATTR_ATIME | ATTR_MTIME + | ATTR_ATIME_SET | ATTR_MTIME_SET; + if (h_src_attr && h_src_attr->valid) { + h_st = &h_src_attr->st; + ia.ia_uid = h_st->uid; + ia.ia_gid = h_st->gid; + ia.ia_atime = h_st->atime; + ia.ia_mtime = h_st->mtime; + if (h_idst->i_mode != h_st->mode + && !S_ISLNK(h_idst->i_mode)) { + ia.ia_valid |= ATTR_MODE; + ia.ia_mode = h_st->mode; + } + sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); + au_cpup_attr_flags(h_idst, h_src_attr->iflags); + } else { + ia.ia_uid = h_isrc->i_uid; + ia.ia_gid = h_isrc->i_gid; + ia.ia_atime = h_isrc->i_atime; + ia.ia_mtime = h_isrc->i_mtime; + if (h_idst->i_mode != h_isrc->i_mode + && !S_ISLNK(h_idst->i_mode)) { + ia.ia_valid |= ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + } + sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); + au_cpup_attr_flags(h_idst, h_isrc->i_flags); + } + /* no delegation since it is just created */ + err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); + + /* is this nfs only? */ + if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { + ia.ia_valid = ATTR_FORCE | ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); + } + + icex = br->br_perm & AuBrAttr_ICEX; + if (!err) { + mnt_flags = au_mntflags(dst->d_sb); + verbose = !!au_opt_test(mnt_flags, VERBOSE); + err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, + char *buf, unsigned long blksize) +{ + int err; + size_t sz, rbytes, wbytes; + unsigned char all_zero; + char *p, *zp; + struct inode *h_inode; + /* reduce stack usage */ + struct iattr *ia; + + zp = page_address(ZERO_PAGE(0)); + if (unlikely(!zp)) + return -ENOMEM; /* possible? */ + + err = 0; + all_zero = 0; + while (len) { + AuDbg("len %lld\n", len); + sz = blksize; + if (len < blksize) + sz = len; + + rbytes = 0; + /* todo: signal_pending? */ + while (!rbytes || err == -EAGAIN || err == -EINTR) { + rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); + err = rbytes; + } + if (unlikely(err < 0)) + break; + + all_zero = 0; + if (len >= rbytes && rbytes == blksize) + all_zero = !memcmp(buf, zp, rbytes); + if (!all_zero) { + wbytes = rbytes; + p = buf; + while (wbytes) { + size_t b; + + b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); + err = b; + /* todo: signal_pending? */ + if (unlikely(err == -EAGAIN || err == -EINTR)) + continue; + if (unlikely(err < 0)) + break; + wbytes -= b; + p += b; + } + if (unlikely(err < 0)) + break; + } else { + loff_t res; + + AuLabel(hole); + res = vfsub_llseek(dst, rbytes, SEEK_CUR); + err = res; + if (unlikely(res < 0)) + break; + } + len -= rbytes; + err = 0; + } + + /* the last block may be a hole */ + if (!err && all_zero) { + AuLabel(last hole); + + err = 1; + if (au_test_nfs(dst->f_path.dentry->d_sb)) { + /* nfs requires this step to make last hole */ + /* is this only nfs? */ + do { + /* todo: signal_pending? */ + err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); + } while (err == -EAGAIN || err == -EINTR); + if (err == 1) + dst->f_pos--; + } + + if (err == 1) { + ia = (void *)buf; + ia->ia_size = dst->f_pos; + ia->ia_valid = ATTR_SIZE | ATTR_FILE; + ia->ia_file = dst; + h_inode = file_inode(dst); + inode_lock_nested(h_inode, AuLsc_I_CHILD2); + /* no delegation since it is just created */ + err = vfsub_notify_change(&dst->f_path, ia, + /*delegated*/NULL); + inode_unlock(h_inode); + } + } + + return err; +} + +int au_copy_file(struct file *dst, struct file *src, loff_t len) +{ + int err; + unsigned long blksize; + unsigned char do_kfree; + char *buf; + struct super_block *h_sb; + + err = -ENOMEM; + h_sb = file_inode(dst)->i_sb; + blksize = h_sb->s_blocksize; + if (!blksize || PAGE_SIZE < blksize) + blksize = PAGE_SIZE; + AuDbg("blksize %lu\n", blksize); + do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); + if (do_kfree) + buf = kmalloc(blksize, GFP_NOFS); + else + buf = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!buf)) + goto out; + + if (len > (1 << 22)) + AuDbg("copying a large file %lld\n", (long long)len); + + src->f_pos = 0; + dst->f_pos = 0; + err = au_do_copy_file(dst, src, len, buf, blksize); + if (do_kfree) { + AuDebugOn(!au_kfree_do_sz_test(blksize)); + au_kfree_do_rcu(buf); + } else + free_page((unsigned long)buf); + +out: + return err; +} + +static int au_do_copy(struct file *dst, struct file *src, loff_t len) +{ + int err; + struct super_block *h_src_sb; + struct inode *h_src_inode; + + h_src_inode = file_inode(src); + h_src_sb = h_src_inode->i_sb; + + /* XFS acquires inode_lock */ + if (!au_test_xfs(h_src_sb)) + err = au_copy_file(dst, src, len); + else { + inode_unlock_shared(h_src_inode); + err = au_copy_file(dst, src, len); + inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); + } + + return err; +} + +static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) +{ + int err; + loff_t lo; + struct super_block *h_src_sb; + struct inode *h_src_inode; + + h_src_inode = file_inode(src); + h_src_sb = h_src_inode->i_sb; + if (h_src_sb != file_inode(dst)->i_sb + || !dst->f_op->remap_file_range) { + err = au_do_copy(dst, src, len); + goto out; + } + + if (!au_test_nfs(h_src_sb)) { + inode_unlock_shared(h_src_inode); + lo = vfsub_clone_file_range(src, dst, len); + inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); + } else + lo = vfsub_clone_file_range(src, dst, len); + if (lo == len) { + err = 0; + goto out; /* success */ + } else if (lo >= 0) + /* todo: possible? */ + /* paritially succeeded */ + AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); + else if (lo != -EOPNOTSUPP) { + /* older XFS has a condition in cloning */ + err = lo; + goto out; + } + + /* the backend fs on NFS may not support cloning */ + err = au_do_copy(dst, src, len); + +out: + AuTraceErr(err); + return err; +} + +/* + * to support a sparse file which is opened with O_APPEND, + * we need to close the file. + */ +static int au_cp_regular(struct au_cp_generic *cpg) +{ + int err, i; + enum { SRC, DST }; + struct { + aufs_bindex_t bindex; + unsigned int flags; + struct dentry *dentry; + int force_wr; + struct file *file; + } *f, file[] = { + { + .bindex = cpg->bsrc, + .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, + }, + { + .bindex = cpg->bdst, + .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, + .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), + } + }; + struct au_branch *br; + struct super_block *sb, *h_src_sb; + struct inode *h_src_inode; + struct task_struct *tsk = current; + + /* bsrc branch can be ro/rw. */ + sb = cpg->dentry->d_sb; + f = file; + for (i = 0; i < 2; i++, f++) { + f->dentry = au_h_dptr(cpg->dentry, f->bindex); + f->file = au_h_open(cpg->dentry, f->bindex, f->flags, + /*file*/NULL, f->force_wr); + if (IS_ERR(f->file)) { + err = PTR_ERR(f->file); + if (i == SRC) + goto out; + else + goto out_src; + } + } + + /* try stopping to update while we copyup */ + h_src_inode = d_inode(file[SRC].dentry); + h_src_sb = h_src_inode->i_sb; + if (!au_test_nfs(h_src_sb)) + IMustLock(h_src_inode); + err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); + + /* i wonder if we had O_NO_DELAY_FPUT flag */ + if (tsk->flags & PF_KTHREAD) + __fput_sync(file[DST].file); + else { + /* it happened actually */ + fput(file[DST].file); + /* + * too bad. + * we have to call both since we don't know which place the file + * was added to. + */ + task_work_run(); + flush_delayed_fput(); + } + br = au_sbr(sb, file[DST].bindex); + au_lcnt_dec(&br->br_nfiles); + +out_src: + fput(file[SRC].file); + br = au_sbr(sb, file[SRC].bindex); + au_lcnt_dec(&br->br_nfiles); +out: + return err; +} + +static int au_do_cpup_regular(struct au_cp_generic *cpg, + struct au_cpup_reg_attr *h_src_attr) +{ + int err, rerr; + loff_t l; + struct path h_path; + struct inode *h_src_inode, *h_dst_inode; + + err = 0; + h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); + l = i_size_read(h_src_inode); + if (cpg->len == -1 || l < cpg->len) + cpg->len = l; + if (cpg->len) { + /* try stopping to update while we are referencing */ + inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); + au_pin_hdir_unlock(cpg->pin); + + h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); + h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); + h_src_attr->iflags = h_src_inode->i_flags; + if (!au_test_nfs(h_src_inode->i_sb)) + err = vfsub_getattr(&h_path, &h_src_attr->st); + else { + inode_unlock_shared(h_src_inode); + err = vfsub_getattr(&h_path, &h_src_attr->st); + inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); + } + if (unlikely(err)) { + inode_unlock_shared(h_src_inode); + goto out; + } + h_src_attr->valid = 1; + if (!au_test_nfs(h_src_inode->i_sb)) { + err = au_cp_regular(cpg); + inode_unlock_shared(h_src_inode); + } else { + inode_unlock_shared(h_src_inode); + err = au_cp_regular(cpg); + } + rerr = au_pin_hdir_relock(cpg->pin); + if (!err && rerr) + err = rerr; + } + if (!err && (h_src_inode->i_state & I_LINKABLE)) { + h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); + h_dst_inode = d_inode(h_path.dentry); + spin_lock(&h_dst_inode->i_lock); + h_dst_inode->i_state |= I_LINKABLE; + spin_unlock(&h_dst_inode->i_lock); + } + +out: + return err; +} + +static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, + struct inode *h_dir) +{ + int err; + DEFINE_DELAYED_CALL(done); + const char *sym; + + sym = vfs_get_link(h_src, &done); + err = PTR_ERR(sym); + if (IS_ERR(sym)) + goto out; + + err = vfsub_symlink(h_dir, h_path, sym); + +out: + do_delayed_call(&done); + return err; +} + +/* + * regardless 'acl' option, reset all ACL. + * All ACL will be copied up later from the original entry on the lower branch. + */ +static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) +{ + int err; + struct dentry *h_dentry; + struct inode *h_inode; + + h_dentry = h_path->dentry; + h_inode = d_inode(h_dentry); + /* forget_all_cached_acls(h_inode)); */ + err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); + AuTraceErr(err); + if (err == -EOPNOTSUPP) + err = 0; + if (!err) + err = vfsub_acl_chmod(h_inode, mode); + + AuTraceErr(err); + return err; +} + +static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, + struct inode *h_dir, struct path *h_path) +{ + int err; + struct inode *dir, *inode; + + err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT); + AuTraceErr(err); + if (err == -EOPNOTSUPP) + err = 0; + if (unlikely(err)) + goto out; + + /* + * strange behaviour from the users view, + * particularly setattr case + */ + dir = d_inode(dst_parent); + if (au_ibtop(dir) == cpg->bdst) + au_cpup_attr_nlink(dir, /*force*/1); + inode = d_inode(cpg->dentry); + au_cpup_attr_nlink(inode, /*force*/1); + +out: + return err; +} + +static noinline_for_stack +int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, + struct au_cpup_reg_attr *h_src_attr) +{ + int err; + umode_t mode; + unsigned int mnt_flags; + unsigned char isdir, isreg, force; + const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); + struct au_dtime dt; + struct path h_path; + struct dentry *h_src, *h_dst, *h_parent; + struct inode *h_inode, *h_dir; + struct super_block *sb; + + /* bsrc branch can be ro/rw. */ + h_src = au_h_dptr(cpg->dentry, cpg->bsrc); + h_inode = d_inode(h_src); + AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); + + /* try stopping to be referenced while we are creating */ + h_dst = au_h_dptr(cpg->dentry, cpg->bdst); + if (au_ftest_cpup(cpg->flags, RENAME)) + AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, + AUFS_WH_PFX_LEN)); + h_parent = h_dst->d_parent; /* dir inode is locked */ + h_dir = d_inode(h_parent); + IMustLock(h_dir); + AuDebugOn(h_parent != h_dst->d_parent); + + sb = cpg->dentry->d_sb; + h_path.mnt = au_sbr_mnt(sb, cpg->bdst); + if (do_dt) { + h_path.dentry = h_parent; + au_dtime_store(&dt, dst_parent, &h_path); + } + h_path.dentry = h_dst; + + isreg = 0; + isdir = 0; + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: + isreg = 1; + err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); + if (!err) + err = au_do_cpup_regular(cpg, h_src_attr); + break; + case S_IFDIR: + isdir = 1; + err = vfsub_mkdir(h_dir, &h_path, mode); + if (!err) + err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); + break; + case S_IFLNK: + err = au_do_cpup_symlink(&h_path, h_src, h_dir); + break; + case S_IFCHR: + case S_IFBLK: + AuDebugOn(!capable(CAP_MKNOD)); + fallthrough; + case S_IFIFO: + case S_IFSOCK: + err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); + break; + default: + AuIOErr("Unknown inode type 0%o\n", mode); + err = -EIO; + } + if (!err) + err = au_reset_acl(h_dir, &h_path, mode); + + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, UDBA_NONE) + && !isdir + && au_opt_test(mnt_flags, XINO) + && (h_inode->i_nlink == 1 + || (h_inode->i_state & I_LINKABLE)) + /* todo: unnecessary? */ + /* && d_inode(cpg->dentry)->i_nlink == 1 */ + && cpg->bdst < cpg->bsrc + && !au_ftest_cpup(cpg->flags, KEEPLINO)) + au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); + /* ignore this error */ + + if (!err) { + force = 0; + if (isreg) { + force = !!cpg->len; + if (cpg->len == -1) + force = !!i_size_read(h_inode); + } + au_fhsm_wrote(sb, cpg->bdst, force); + } + + if (do_dt) + au_dtime_revert(&dt); + return err; +} + +static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) +{ + int err; + struct dentry *dentry, *h_dentry, *h_parent, *parent; + struct inode *h_dir; + aufs_bindex_t bdst; + + dentry = cpg->dentry; + bdst = cpg->bdst; + h_dentry = au_h_dptr(dentry, bdst); + if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { + dget(h_dentry); + au_set_h_dptr(dentry, bdst, NULL); + err = au_lkup_neg(dentry, bdst, /*wh*/0); + if (!err) + h_path->dentry = dget(au_h_dptr(dentry, bdst)); + au_set_h_dptr(dentry, bdst, h_dentry); + } else { + err = 0; + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + dput(parent); + h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); + if (IS_ERR(h_path->dentry)) + err = PTR_ERR(h_path->dentry); + } + if (unlikely(err)) + goto out; + + h_parent = h_dentry->d_parent; /* dir inode is locked */ + h_dir = d_inode(h_parent); + IMustLock(h_dir); + AuDbg("%pd %pd\n", h_dentry, h_path->dentry); + /* no delegation since it is just created */ + err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, + /*flags*/0); + dput(h_path->dentry); + +out: + return err; +} + +/* + * copyup the @dentry from @bsrc to @bdst. + * the caller must set the both of lower dentries. + * @len is for truncating when it is -1 copyup the entire file. + * in link/rename cases, @dst_parent may be different from the real one. + * basic->bsrc can be larger than basic->bdst. + * aufs doesn't touch the credential so + * security_inode_copy_up{,_xattr}() are unnecessary. + */ +static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) +{ + int err, rerr; + aufs_bindex_t old_ibtop; + unsigned char isdir, plink; + struct dentry *h_src, *h_dst, *h_parent; + struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; + struct super_block *sb; + struct au_branch *br; + /* to reduce stack size */ + struct { + struct au_dtime dt; + struct path h_path; + struct au_cpup_reg_attr h_src_attr; + } *a; + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + a->h_src_attr.valid = 0; + + sb = cpg->dentry->d_sb; + br = au_sbr(sb, cpg->bdst); + a->h_path.mnt = au_br_mnt(br); + h_dst = au_h_dptr(cpg->dentry, cpg->bdst); + h_parent = h_dst->d_parent; /* dir inode is locked */ + h_dir = d_inode(h_parent); + IMustLock(h_dir); + + h_src = au_h_dptr(cpg->dentry, cpg->bsrc); + inode = d_inode(cpg->dentry); + + if (!dst_parent) + dst_parent = dget_parent(cpg->dentry); + else + dget(dst_parent); + + plink = !!au_opt_test(au_mntflags(sb), PLINK); + dst_inode = au_h_iptr(inode, cpg->bdst); + if (dst_inode) { + if (unlikely(!plink)) { + err = -EIO; + AuIOErr("hi%lu(i%lu) exists on b%d " + "but plink is disabled\n", + dst_inode->i_ino, inode->i_ino, cpg->bdst); + goto out_parent; + } + + if (dst_inode->i_nlink) { + const int do_dt = au_ftest_cpup(cpg->flags, DTIME); + + h_src = au_plink_lkup(inode, cpg->bdst); + err = PTR_ERR(h_src); + if (IS_ERR(h_src)) + goto out_parent; + if (unlikely(d_is_negative(h_src))) { + err = -EIO; + AuIOErr("i%lu exists on b%d " + "but not pseudo-linked\n", + inode->i_ino, cpg->bdst); + dput(h_src); + goto out_parent; + } + + if (do_dt) { + a->h_path.dentry = h_parent; + au_dtime_store(&a->dt, dst_parent, &a->h_path); + } + + a->h_path.dentry = h_dst; + delegated = NULL; + err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); + if (!err && au_ftest_cpup(cpg->flags, RENAME)) + err = au_do_ren_after_cpup(cpg, &a->h_path); + if (do_dt) + au_dtime_revert(&a->dt); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + dput(h_src); + goto out_parent; + } else + /* todo: cpup_wh_file? */ + /* udba work */ + au_update_ibrange(inode, /*do_put_zero*/1); + } + + isdir = S_ISDIR(inode->i_mode); + old_ibtop = au_ibtop(inode); + err = cpup_entry(cpg, dst_parent, &a->h_src_attr); + if (unlikely(err)) + goto out_rev; + dst_inode = d_inode(h_dst); + inode_lock_nested(dst_inode, AuLsc_I_CHILD2); + /* todo: necessary? */ + /* au_pin_hdir_unlock(cpg->pin); */ + + err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); + if (unlikely(err)) { + /* todo: necessary? */ + /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ + inode_unlock(dst_inode); + goto out_rev; + } + + if (cpg->bdst < old_ibtop) { + if (S_ISREG(inode->i_mode)) { + err = au_dy_iaop(inode, cpg->bdst, dst_inode); + if (unlikely(err)) { + /* ignore an error */ + /* au_pin_hdir_relock(cpg->pin); */ + inode_unlock(dst_inode); + goto out_rev; + } + } + au_set_ibtop(inode, cpg->bdst); + } else + au_set_ibbot(inode, cpg->bdst); + au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), + au_hi_flags(inode, isdir)); + + /* todo: necessary? */ + /* err = au_pin_hdir_relock(cpg->pin); */ + inode_unlock(dst_inode); + if (unlikely(err)) + goto out_rev; + + src_inode = d_inode(h_src); + if (!isdir + && (src_inode->i_nlink > 1 + || src_inode->i_state & I_LINKABLE) + && plink) + au_plink_append(inode, cpg->bdst, h_dst); + + if (au_ftest_cpup(cpg->flags, RENAME)) { + a->h_path.dentry = h_dst; + err = au_do_ren_after_cpup(cpg, &a->h_path); + } + if (!err) + goto out_parent; /* success */ + + /* revert */ +out_rev: + a->h_path.dentry = h_parent; + au_dtime_store(&a->dt, dst_parent, &a->h_path); + a->h_path.dentry = h_dst; + rerr = 0; + if (d_is_positive(h_dst)) { + if (!isdir) { + /* no delegation since it is just created */ + rerr = vfsub_unlink(h_dir, &a->h_path, + /*delegated*/NULL, /*force*/0); + } else + rerr = vfsub_rmdir(h_dir, &a->h_path); + } + au_dtime_revert(&a->dt); + if (rerr) { + AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); + err = -EIO; + } +out_parent: + dput(dst_parent); + au_kfree_rcu(a); +out: + return err; +} + +#if 0 /* reserved */ +struct au_cpup_single_args { + int *errp; + struct au_cp_generic *cpg; + struct dentry *dst_parent; +}; + +static void au_call_cpup_single(void *args) +{ + struct au_cpup_single_args *a = args; + + au_pin_hdir_acquire_nest(a->cpg->pin); + *a->errp = au_cpup_single(a->cpg, a->dst_parent); + au_pin_hdir_release(a->cpg->pin); +} +#endif + +/* + * prevent SIGXFSZ in copy-up. + * testing CAP_MKNOD is for generic fs, + * but CAP_FSETID is for xfs only, currently. + */ +static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) +{ + int do_sio; + struct super_block *sb; + struct inode *h_dir; + + do_sio = 0; + sb = au_pinned_parent(pin)->d_sb; + if (!au_wkq_test() + && (!au_sbi(sb)->si_plink_maint_pid + || au_plink_maint(sb, AuLock_NOPLM))) { + switch (mode & S_IFMT) { + case S_IFREG: + /* no condition about RLIMIT_FSIZE and the file size */ + do_sio = 1; + break; + case S_IFCHR: + case S_IFBLK: + do_sio = !capable(CAP_MKNOD); + break; + } + if (!do_sio) + do_sio = ((mode & (S_ISUID | S_ISGID)) + && !capable(CAP_FSETID)); + /* this workaround may be removed in the future */ + if (!do_sio) { + h_dir = au_pinned_h_dir(pin); + do_sio = h_dir->i_mode & S_ISVTX; + } + } + + return do_sio; +} + +#if 0 /* reserved */ +int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) +{ + int err, wkq_err; + struct dentry *h_dentry; + + h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); + if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) + err = au_cpup_single(cpg, dst_parent); + else { + struct au_cpup_single_args args = { + .errp = &err, + .cpg = cpg, + .dst_parent = dst_parent + }; + wkq_err = au_wkq_wait(au_call_cpup_single, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} +#endif + +/* + * copyup the @dentry from the first active lower branch to @bdst, + * using au_cpup_single(). + */ +static int au_cpup_simple(struct au_cp_generic *cpg) +{ + int err; + unsigned int flags_orig; + struct dentry *dentry; + + AuDebugOn(cpg->bsrc < 0); + + dentry = cpg->dentry; + DiMustWriteLock(dentry); + + err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); + if (!err) { + flags_orig = cpg->flags; + au_fset_cpup(cpg->flags, RENAME); + err = au_cpup_single(cpg, NULL); + cpg->flags = flags_orig; + if (!err) + return 0; /* success */ + + /* revert */ + au_set_h_dptr(dentry, cpg->bdst, NULL); + au_set_dbtop(dentry, cpg->bsrc); + } + + return err; +} + +struct au_cpup_simple_args { + int *errp; + struct au_cp_generic *cpg; +}; + +static void au_call_cpup_simple(void *args) +{ + struct au_cpup_simple_args *a = args; + + au_pin_hdir_acquire_nest(a->cpg->pin); + *a->errp = au_cpup_simple(a->cpg); + au_pin_hdir_release(a->cpg->pin); +} + +static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) +{ + int err, wkq_err; + struct dentry *dentry, *parent; + struct file *h_file; + struct inode *h_dir; + + dentry = cpg->dentry; + h_file = NULL; + if (au_ftest_cpup(cpg->flags, HOPEN)) { + AuDebugOn(cpg->bsrc < 0); + h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + } + + parent = dget_parent(dentry); + h_dir = au_h_iptr(d_inode(parent), cpg->bdst); + if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) + && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) + err = au_cpup_simple(cpg); + else { + struct au_cpup_simple_args args = { + .errp = &err, + .cpg = cpg + }; + wkq_err = au_wkq_wait(au_call_cpup_simple, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + dput(parent); + if (h_file) + au_h_open_post(dentry, cpg->bsrc, h_file); + +out: + return err; +} + +int au_sio_cpup_simple(struct au_cp_generic *cpg) +{ + aufs_bindex_t bsrc, bbot; + struct dentry *dentry, *h_dentry; + + if (cpg->bsrc < 0) { + dentry = cpg->dentry; + bbot = au_dbbot(dentry); + for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { + h_dentry = au_h_dptr(dentry, bsrc); + if (h_dentry) { + AuDebugOn(d_is_negative(h_dentry)); + break; + } + } + AuDebugOn(bsrc > bbot); + cpg->bsrc = bsrc; + } + AuDebugOn(cpg->bsrc <= cpg->bdst); + return au_do_sio_cpup_simple(cpg); +} + +int au_sio_cpdown_simple(struct au_cp_generic *cpg) +{ + AuDebugOn(cpg->bdst <= cpg->bsrc); + return au_do_sio_cpup_simple(cpg); +} + +/* ---------------------------------------------------------------------- */ + +/* + * copyup the deleted file for writing. + */ +static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, + struct file *file) +{ + int err; + unsigned int flags_orig; + aufs_bindex_t bsrc_orig; + struct au_dinfo *dinfo; + struct { + struct au_hdentry *hd; + struct dentry *h_dentry; + } hdst, hsrc; + + dinfo = au_di(cpg->dentry); + AuRwMustWriteLock(&dinfo->di_rwsem); + + bsrc_orig = cpg->bsrc; + cpg->bsrc = dinfo->di_btop; + hdst.hd = au_hdentry(dinfo, cpg->bdst); + hdst.h_dentry = hdst.hd->hd_dentry; + hdst.hd->hd_dentry = wh_dentry; + dinfo->di_btop = cpg->bdst; + + hsrc.h_dentry = NULL; + if (file) { + hsrc.hd = au_hdentry(dinfo, cpg->bsrc); + hsrc.h_dentry = hsrc.hd->hd_dentry; + hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; + } + flags_orig = cpg->flags; + cpg->flags = !AuCpup_DTIME; + err = au_cpup_single(cpg, /*h_parent*/NULL); + cpg->flags = flags_orig; + if (file) { + if (!err) + err = au_reopen_nondir(file); + hsrc.hd->hd_dentry = hsrc.h_dentry; + } + hdst.hd->hd_dentry = hdst.h_dentry; + dinfo->di_btop = cpg->bsrc; + cpg->bsrc = bsrc_orig; + + return err; +} + +static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) +{ + int err; + aufs_bindex_t bdst; + struct au_dtime dt; + struct dentry *dentry, *parent, *h_parent, *wh_dentry; + struct au_branch *br; + struct path h_path; + + dentry = cpg->dentry; + bdst = cpg->bdst; + br = au_sbr(dentry->d_sb, bdst); + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + h_path.dentry = h_parent; + h_path.mnt = au_br_mnt(br); + au_dtime_store(&dt, parent, &h_path); + err = au_do_cpup_wh(cpg, wh_dentry, file); + if (unlikely(err)) + goto out_wh; + + dget(wh_dentry); + h_path.dentry = wh_dentry; + if (!d_is_dir(wh_dentry)) { + /* no delegation since it is just created */ + err = vfsub_unlink(d_inode(h_parent), &h_path, + /*delegated*/NULL, /*force*/0); + } else + err = vfsub_rmdir(d_inode(h_parent), &h_path); + if (unlikely(err)) { + AuIOErr("failed remove copied-up tmp file %pd(%d)\n", + wh_dentry, err); + err = -EIO; + } + au_dtime_revert(&dt); + au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); + +out_wh: + dput(wh_dentry); +out: + dput(parent); + return err; +} + +struct au_cpup_wh_args { + int *errp; + struct au_cp_generic *cpg; + struct file *file; +}; + +static void au_call_cpup_wh(void *args) +{ + struct au_cpup_wh_args *a = args; + + au_pin_hdir_acquire_nest(a->cpg->pin); + *a->errp = au_cpup_wh(a->cpg, a->file); + au_pin_hdir_release(a->cpg->pin); +} + +int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) +{ + int err, wkq_err; + aufs_bindex_t bdst; + struct dentry *dentry, *parent, *h_orph, *h_parent; + struct inode *dir, *h_dir, *h_tmpdir; + struct au_wbr *wbr; + struct au_pin wh_pin, *pin_orig; + + dentry = cpg->dentry; + bdst = cpg->bdst; + parent = dget_parent(dentry); + dir = d_inode(parent); + h_orph = NULL; + h_parent = NULL; + h_dir = au_igrab(au_h_iptr(dir, bdst)); + h_tmpdir = h_dir; + pin_orig = NULL; + if (!h_dir->i_nlink) { + wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; + h_orph = wbr->wbr_orph; + + h_parent = dget(au_h_dptr(parent, bdst)); + au_set_h_dptr(parent, bdst, dget(h_orph)); + h_tmpdir = d_inode(h_orph); + au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); + + inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); + /* todo: au_h_open_pre()? */ + + pin_orig = cpg->pin; + au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, + AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); + cpg->pin = &wh_pin; + } + + if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) + && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) + err = au_cpup_wh(cpg, file); + else { + struct au_cpup_wh_args args = { + .errp = &err, + .cpg = cpg, + .file = file + }; + wkq_err = au_wkq_wait(au_call_cpup_wh, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + if (h_orph) { + inode_unlock(h_tmpdir); + /* todo: au_h_open_post()? */ + au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); + au_set_h_dptr(parent, bdst, h_parent); + AuDebugOn(!pin_orig); + cpg->pin = pin_orig; + } + iput(h_dir); + dput(parent); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * generic routine for both of copy-up and copy-down. + */ +/* cf. revalidate function in file.c */ +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, + int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent, void *arg), + void *arg) +{ + int err; + struct au_pin pin; + struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; + + err = 0; + parent = dget_parent(dentry); + if (IS_ROOT(parent)) + goto out; + + au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, + au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); + + /* do not use au_dpage */ + real_parent = parent; + while (1) { + dput(parent); + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + if (h_parent) + goto out; /* success */ + + /* find top dir which is necessary to cpup */ + do { + d = parent; + dput(parent); + parent = dget_parent(d); + di_read_lock_parent3(parent, !AuLock_IR); + h_parent = au_h_dptr(parent, bdst); + di_read_unlock(parent, !AuLock_IR); + } while (!h_parent); + + if (d != real_parent) + di_write_lock_child3(d); + + /* somebody else might create while we were sleeping */ + h_dentry = au_h_dptr(d, bdst); + if (!h_dentry || d_is_negative(h_dentry)) { + if (h_dentry) + au_update_dbtop(d); + + au_pin_set_dentry(&pin, d); + err = au_do_pin(&pin); + if (!err) { + err = cp(d, bdst, &pin, h_parent, arg); + au_unpin(&pin); + } + } + + if (d != real_parent) + di_write_unlock(d); + if (unlikely(err)) + break; + } + +out: + dput(parent); + return err; +} + +static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent __maybe_unused, + void *arg __maybe_unused) +{ + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = bdst, + .bsrc = -1, + .len = 0, + .pin = pin, + .flags = AuCpup_DTIME + }; + return au_sio_cpup_simple(&cpg); +} + +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); +} + +int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + struct dentry *parent; + struct inode *dir; + + parent = dget_parent(dentry); + dir = d_inode(parent); + err = 0; + if (au_h_iptr(dir, bdst)) + goto out; + + di_read_unlock(parent, AuLock_IR); + di_write_lock_parent(parent); + /* someone else might change our inode while we were sleeping */ + if (!au_h_iptr(dir, bdst)) + err = au_cpup_dirs(dentry, bdst); + di_downgrade_lock(parent, AuLock_IR); + +out: + dput(parent); + return err; +} diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h new file mode 100644 index 000000000000..abcbfbc55a5c --- /dev/null +++ b/fs/aufs/cpup.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * copy-up/down functions + */ + +#ifndef __AUFS_CPUP_H__ +#define __AUFS_CPUP_H__ + +#ifdef __KERNEL__ + +#include + +struct inode; +struct file; +struct au_pin; + +void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); +void au_cpup_attr_timesizes(struct inode *inode); +void au_cpup_attr_nlink(struct inode *inode, int force); +void au_cpup_attr_changeable(struct inode *inode); +void au_cpup_igen(struct inode *inode, struct inode *h_inode); +void au_cpup_attr_all(struct inode *inode, int force); + +/* ---------------------------------------------------------------------- */ + +struct au_cp_generic { + struct dentry *dentry; + aufs_bindex_t bdst, bsrc; + loff_t len; + struct au_pin *pin; + unsigned int flags; +}; + +/* cpup flags */ +#define AuCpup_DTIME 1 /* do dtime_store/revert */ +#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, + for link(2) */ +#define AuCpup_RENAME (1 << 2) /* rename after cpup */ +#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in + cpup */ +#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the + existing entry */ +#define AuCpup_RWDST (1 << 5) /* force write target even if + the branch is marked as RO */ + +#ifndef CONFIG_AUFS_BR_HFSPLUS +#undef AuCpup_HOPEN +#define AuCpup_HOPEN 0 +#endif + +#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) +#define au_fset_cpup(flags, name) \ + do { (flags) |= AuCpup_##name; } while (0) +#define au_fclr_cpup(flags, name) \ + do { (flags) &= ~AuCpup_##name; } while (0) + +int au_copy_file(struct file *dst, struct file *src, loff_t len); +int au_sio_cpup_simple(struct au_cp_generic *cpg); +int au_sio_cpdown_simple(struct au_cp_generic *cpg); +int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); + +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, + int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent, void *arg), + void *arg); +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); +int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); + +/* ---------------------------------------------------------------------- */ + +/* keep timestamps when copyup */ +struct au_dtime { + struct dentry *dt_dentry; + struct path dt_h_path; + struct timespec64 dt_atime, dt_mtime; +}; +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct path *h_path); +void au_dtime_revert(struct au_dtime *dt); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_CPUP_H__ */ diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c new file mode 100644 index 000000000000..e32d91d1f638 --- /dev/null +++ b/fs/aufs/dbgaufs.c @@ -0,0 +1,526 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debugfs interface + */ + +#include +#include "aufs.h" + +#ifndef CONFIG_SYSFS +#error DEBUG_FS depends upon SYSFS +#endif + +static struct dentry *dbgaufs; +static const mode_t dbgaufs_mode = 0444; + +/* 20 is max digits length of ulong 64 */ +struct dbgaufs_arg { + int n; + char a[20 * 4]; +}; + +/* + * common function for all XINO files + */ +static int dbgaufs_xi_release(struct inode *inode __maybe_unused, + struct file *file) +{ + void *p; + + p = file->private_data; + if (p) { + /* this is struct dbgaufs_arg */ + AuDebugOn(!au_kfree_sz_test(p)); + au_kfree_do_rcu(p); + } + return 0; +} + +static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, + int cnt) +{ + int err; + struct kstat st; + struct dbgaufs_arg *p; + + err = -ENOMEM; + p = kmalloc(sizeof(*p), GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = 0; + p->n = 0; + file->private_data = p; + if (!xf) + goto out; + + err = vfsub_getattr(&xf->f_path, &st); + if (!err) { + if (do_fcnt) + p->n = snprintf + (p->a, sizeof(p->a), "%d, %llux%u %lld\n", + cnt, st.blocks, st.blksize, + (long long)st.size); + else + p->n = snprintf(p->a, sizeof(p->a), "%llux%u %lld\n", + st.blocks, st.blksize, + (long long)st.size); + AuDebugOn(p->n >= sizeof(p->a)); + } else { + p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); + err = 0; + } + +out: + return err; +} + +static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dbgaufs_arg *p; + + p = file->private_data; + return simple_read_from_buffer(buf, count, ppos, p->a, p->n); +} + +/* ---------------------------------------------------------------------- */ + +struct dbgaufs_plink_arg { + int n; + char a[]; +}; + +static int dbgaufs_plink_release(struct inode *inode __maybe_unused, + struct file *file) +{ + free_page((unsigned long)file->private_data); + return 0; +} + +static int dbgaufs_plink_open(struct inode *inode, struct file *file) +{ + int err, i, limit; + unsigned long n, sum; + struct dbgaufs_plink_arg *p; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct hlist_bl_head *hbl; + + err = -ENOMEM; + p = (void *)get_zeroed_page(GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = -EFBIG; + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + if (au_opt_test(au_mntflags(sb), PLINK)) { + limit = PAGE_SIZE - sizeof(p->n); + + /* the number of buckets */ + n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); + p->n += n; + limit -= n; + + sum = 0; + for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; + i++, hbl++) { + n = au_hbl_count(hbl); + sum += n; + + n = snprintf(p->a + p->n, limit, "%lu ", n); + p->n += n; + limit -= n; + if (unlikely(limit <= 0)) + goto out_free; + } + p->a[p->n - 1] = '\n'; + + /* the sum of plinks */ + n = snprintf(p->a + p->n, limit, "%lu\n", sum); + p->n += n; + limit -= n; + if (unlikely(limit <= 0)) + goto out_free; + } else { +#define str "1\n0\n0\n" + p->n = sizeof(str) - 1; + strcpy(p->a, str); +#undef str + } + si_read_unlock(sb); + + err = 0; + file->private_data = p; + goto out; /* success */ + +out_free: + free_page((unsigned long)p); +out: + return err; +} + +static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dbgaufs_plink_arg *p; + + p = file->private_data; + return simple_read_from_buffer(buf, count, ppos, p->a, p->n); +} + +static const struct file_operations dbgaufs_plink_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_plink_open, + .release = dbgaufs_plink_release, + .read = dbgaufs_plink_read +}; + +/* ---------------------------------------------------------------------- */ + +static int dbgaufs_xib_open(struct inode *inode, struct file *file) +{ + int err; + struct au_sbinfo *sbinfo; + struct super_block *sb; + + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); + si_read_unlock(sb); + return err; +} + +static const struct file_operations dbgaufs_xib_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_xib_open, + .release = dbgaufs_xi_release, + .read = dbgaufs_xi_read +}; + +/* ---------------------------------------------------------------------- */ + +#define DbgaufsXi_PREFIX "xi" + +static int dbgaufs_xino_open(struct inode *inode, struct file *file) +{ + int err, idx; + long l; + aufs_bindex_t bindex; + char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct au_xino *xi; + struct file *xf; + struct qstr *name; + struct au_branch *br; + + err = -ENOENT; + name = &file->f_path.dentry->d_name; + if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) + || memcmp(name->name, DbgaufsXi_PREFIX, + sizeof(DbgaufsXi_PREFIX) - 1))) + goto out; + + AuDebugOn(name->len >= sizeof(a)); + memcpy(a, name->name, name->len); + a[name->len] = '\0'; + p = strchr(a, '-'); + if (p) + *p = '\0'; + err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); + if (unlikely(err)) + goto out; + bindex = l; + idx = 0; + if (p) { + err = kstrtol(p + 1, 10, &l); + if (unlikely(err)) + goto out; + idx = l; + } + + err = -ENOENT; + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) + goto out_si; + br = au_sbr(sb, bindex); + xi = br->br_xino; + if (unlikely(idx >= xi->xi_nfile)) + goto out_si; + xf = au_xino_file(xi, idx); + if (xf) + err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, + au_xino_count(br)); + +out_si: + si_read_unlock(sb); +out: + AuTraceErr(err); + return err; +} + +static const struct file_operations dbgaufs_xino_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_xino_open, + .release = dbgaufs_xi_release, + .read = dbgaufs_xi_read +}; + +void dbgaufs_xino_del(struct au_branch *br) +{ + struct dentry *dbgaufs; + + dbgaufs = br->br_dbgaufs; + if (!dbgaufs) + return; + + br->br_dbgaufs = NULL; + /* debugfs acquires the parent i_mutex */ + lockdep_off(); + debugfs_remove(dbgaufs); + lockdep_on(); +} + +void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + aufs_bindex_t bbot; + struct au_branch *br; + + if (!au_sbi(sb)->si_dbgaufs) + return; + + bbot = au_sbbot(sb); + for (; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + dbgaufs_xino_del(br); + } +} + +static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, + unsigned int idx, struct dentry *parent, + struct au_sbinfo *sbinfo) +{ + struct au_branch *br; + struct dentry *d; + /* "xi" bindex(5) "-" idx(2) NULL */ + char name[sizeof(DbgaufsXi_PREFIX) + 8]; + + if (!idx) + snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); + else + snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", + bindex, idx); + br = au_sbr(sb, bindex); + if (br->br_dbgaufs) { + struct qstr qstr = QSTR_INIT(name, strlen(name)); + + if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { + /* debugfs acquires the parent i_mutex */ + lockdep_off(); + d = debugfs_rename(parent, br->br_dbgaufs, parent, + name); + lockdep_on(); + if (unlikely(!d)) + pr_warn("failed renaming %pd/%s, ignored.\n", + parent, name); + } + } else { + lockdep_off(); + br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, + sbinfo, &dbgaufs_xino_fop); + lockdep_on(); + if (unlikely(!br->br_dbgaufs)) + pr_warn("failed creating %pd/%s, ignored.\n", + parent, name); + } +} + +static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, + struct dentry *parent, struct au_sbinfo *sbinfo) +{ + struct au_branch *br; + struct au_xino *xi; + unsigned int u; + + br = au_sbr(sb, bindex); + xi = br->br_xino; + for (u = 0; u < xi->xi_nfile; u++) + dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); +} + +void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) +{ + struct au_sbinfo *sbinfo; + struct dentry *parent; + aufs_bindex_t bbot; + + if (!au_opt_test(au_mntflags(sb), XINO)) + return; + + sbinfo = au_sbi(sb); + parent = sbinfo->si_dbgaufs; + if (!parent) + return; + + bbot = au_sbbot(sb); + if (topdown) + for (; bindex <= bbot; bindex++) + dbgaufs_br_add(sb, bindex, parent, sbinfo); + else + for (; bbot >= bindex; bbot--) + dbgaufs_br_add(sb, bbot, parent, sbinfo); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_EXPORT +static int dbgaufs_xigen_open(struct inode *inode, struct file *file) +{ + int err; + struct au_sbinfo *sbinfo; + struct super_block *sb; + + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); + si_read_unlock(sb); + return err; +} + +static const struct file_operations dbgaufs_xigen_fop = { + .owner = THIS_MODULE, + .open = dbgaufs_xigen_open, + .release = dbgaufs_xi_release, + .read = dbgaufs_xi_read +}; + +static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) +{ + int err; + + /* + * This function is a dynamic '__init' function actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ + + err = -EIO; + sbinfo->si_dbgaufs_xigen = debugfs_create_file + ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_xigen_fop); + if (sbinfo->si_dbgaufs_xigen) + err = 0; + + return err; +} +#else +static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) +{ + return 0; +} +#endif /* CONFIG_AUFS_EXPORT */ + +/* ---------------------------------------------------------------------- */ + +void dbgaufs_si_fin(struct au_sbinfo *sbinfo) +{ + /* + * This function is a dynamic '__fin' function actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ + + debugfs_remove_recursive(sbinfo->si_dbgaufs); + sbinfo->si_dbgaufs = NULL; +} + +int dbgaufs_si_init(struct au_sbinfo *sbinfo) +{ + int err; + char name[SysaufsSiNameLen]; + + /* + * This function is a dynamic '__init' function actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ + + err = -ENOENT; + if (!dbgaufs) { + AuErr1("/debug/aufs is uninitialized\n"); + goto out; + } + + err = -EIO; + sysaufs_name(sbinfo, name); + sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); + if (unlikely(!sbinfo->si_dbgaufs)) + goto out; + + /* regardless plink/noplink option */ + sbinfo->si_dbgaufs_plink = debugfs_create_file + ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_plink_fop); + if (unlikely(!sbinfo->si_dbgaufs_plink)) + goto out_dir; + + /* regardless xino/noxino option */ + sbinfo->si_dbgaufs_xib = debugfs_create_file + ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_xib_fop); + if (unlikely(!sbinfo->si_dbgaufs_xib)) + goto out_dir; + + err = dbgaufs_xigen_init(sbinfo); + if (!err) + goto out; /* success */ + +out_dir: + dbgaufs_si_fin(sbinfo); +out: + if (unlikely(err)) + pr_err("debugfs/aufs failed\n"); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void dbgaufs_fin(void) +{ + debugfs_remove(dbgaufs); +} + +int __init dbgaufs_init(void) +{ + int err; + + err = -EIO; + dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); + if (dbgaufs) + err = 0; + return err; +} diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h new file mode 100644 index 000000000000..1ea241bf0234 --- /dev/null +++ b/fs/aufs/dbgaufs.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debugfs interface + */ + +#ifndef __DBGAUFS_H__ +#define __DBGAUFS_H__ + +#ifdef __KERNEL__ + +struct super_block; +struct au_sbinfo; +struct au_branch; + +#ifdef CONFIG_DEBUG_FS +/* dbgaufs.c */ +void dbgaufs_xino_del(struct au_branch *br); +void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); +void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown); +void dbgaufs_si_fin(struct au_sbinfo *sbinfo); +int dbgaufs_si_init(struct au_sbinfo *sbinfo); +void dbgaufs_fin(void); +int __init dbgaufs_init(void); +#else +AuStubVoid(dbgaufs_xino_del, struct au_branch *br) +AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) +AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex, + int topdown) +AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) +AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) +AuStubVoid(dbgaufs_fin, void) +AuStubInt0(__init dbgaufs_init, void) +#endif /* CONFIG_DEBUG_FS */ + +#endif /* __KERNEL__ */ +#endif /* __DBGAUFS_H__ */ diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c new file mode 100644 index 000000000000..0b9122307667 --- /dev/null +++ b/fs/aufs/dcsub.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for dentry cache + */ + +#include "aufs.h" + +static void au_dpage_free(struct au_dpage *dpage) +{ + int i; + struct dentry **p; + + p = dpage->dentries; + for (i = 0; i < dpage->ndentry; i++) + dput(*p++); + free_page((unsigned long)dpage->dentries); +} + +int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) +{ + int err; + void *p; + + err = -ENOMEM; + dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); + if (unlikely(!dpages->dpages)) + goto out; + + p = (void *)__get_free_page(gfp); + if (unlikely(!p)) + goto out_dpages; + + dpages->dpages[0].ndentry = 0; + dpages->dpages[0].dentries = p; + dpages->ndpage = 1; + return 0; /* success */ + +out_dpages: + au_kfree_try_rcu(dpages->dpages); +out: + return err; +} + +void au_dpages_free(struct au_dcsub_pages *dpages) +{ + int i; + struct au_dpage *p; + + p = dpages->dpages; + for (i = 0; i < dpages->ndpage; i++) + au_dpage_free(p++); + au_kfree_try_rcu(dpages->dpages); +} + +static int au_dpages_append(struct au_dcsub_pages *dpages, + struct dentry *dentry, gfp_t gfp) +{ + int err, sz; + struct au_dpage *dpage; + void *p; + + dpage = dpages->dpages + dpages->ndpage - 1; + sz = PAGE_SIZE / sizeof(dentry); + if (unlikely(dpage->ndentry >= sz)) { + AuLabel(new dpage); + err = -ENOMEM; + sz = dpages->ndpage * sizeof(*dpages->dpages); + p = au_kzrealloc(dpages->dpages, sz, + sz + sizeof(*dpages->dpages), gfp, + /*may_shrink*/0); + if (unlikely(!p)) + goto out; + + dpages->dpages = p; + dpage = dpages->dpages + dpages->ndpage; + p = (void *)__get_free_page(gfp); + if (unlikely(!p)) + goto out; + + dpage->ndentry = 0; + dpage->dentries = p; + dpages->ndpage++; + } + + AuDebugOn(au_dcount(dentry) <= 0); + dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); + return 0; /* success */ + +out: + return err; +} + +/* todo: BAD approach */ +/* copied from linux/fs/dcache.c */ +enum d_walk_ret { + D_WALK_CONTINUE, + D_WALK_QUIT, + D_WALK_NORETRY, + D_WALK_SKIP, +}; + +extern void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *)); + +struct ac_dpages_arg { + int err; + struct au_dcsub_pages *dpages; + struct super_block *sb; + au_dpages_test test; + void *arg; +}; + +static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) +{ + enum d_walk_ret ret; + struct ac_dpages_arg *arg = _arg; + + ret = D_WALK_CONTINUE; + if (dentry->d_sb == arg->sb + && !IS_ROOT(dentry) + && au_dcount(dentry) > 0 + && au_di(dentry) + && (!arg->test || arg->test(dentry, arg->arg))) { + arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); + if (unlikely(arg->err)) + ret = D_WALK_QUIT; + } + + return ret; +} + +int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, + au_dpages_test test, void *arg) +{ + struct ac_dpages_arg args = { + .err = 0, + .dpages = dpages, + .sb = root->d_sb, + .test = test, + .arg = arg + }; + + d_walk(root, &args, au_call_dpages_append); + + return args.err; +} + +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, + int do_include, au_dpages_test test, void *arg) +{ + int err; + + err = 0; + write_seqlock(&rename_lock); + spin_lock(&dentry->d_lock); + if (do_include + && au_dcount(dentry) > 0 + && (!test || test(dentry, arg))) + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + spin_unlock(&dentry->d_lock); + if (unlikely(err)) + goto out; + + /* + * RCU for vfsmount is unnecessary since this is a traverse in a single + * mount + */ + while (!IS_ROOT(dentry)) { + dentry = dentry->d_parent; /* rename_lock is locked */ + spin_lock(&dentry->d_lock); + if (au_dcount(dentry) > 0 + && (!test || test(dentry, arg))) + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + spin_unlock(&dentry->d_lock); + if (unlikely(err)) + break; + } + +out: + write_sequnlock(&rename_lock); + return err; +} + +static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) +{ + return au_di(dentry) && dentry->d_sb == arg; +} + +int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, + struct dentry *dentry, int do_include) +{ + return au_dcsub_pages_rev(dpages, dentry, do_include, + au_dcsub_dpages_aufs, dentry->d_sb); +} + +int au_test_subdir(struct dentry *d1, struct dentry *d2) +{ + struct path path[2] = { + { + .dentry = d1 + }, + { + .dentry = d2 + } + }; + + return path_is_under(path + 0, path + 1); +} diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h new file mode 100644 index 000000000000..5e578995c256 --- /dev/null +++ b/fs/aufs/dcsub.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for dentry cache + */ + +#ifndef __AUFS_DCSUB_H__ +#define __AUFS_DCSUB_H__ + +#ifdef __KERNEL__ + +#include +#include + +struct au_dpage { + int ndentry; + struct dentry **dentries; +}; + +struct au_dcsub_pages { + int ndpage; + struct au_dpage *dpages; +}; + +/* ---------------------------------------------------------------------- */ + +/* dcsub.c */ +int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); +void au_dpages_free(struct au_dcsub_pages *dpages); +typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); +int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, + au_dpages_test test, void *arg); +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, + int do_include, au_dpages_test test, void *arg); +int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, + struct dentry *dentry, int do_include); +int au_test_subdir(struct dentry *d1, struct dentry *d2); + +/* ---------------------------------------------------------------------- */ + +/* + * todo: in linux-3.13, several similar (but faster) helpers are added to + * include/linux/dcache.h. Try them (in the future). + */ + +static inline int au_d_hashed_positive(struct dentry *d) +{ + int err; + struct inode *inode = d_inode(d); + + err = 0; + if (unlikely(d_unhashed(d) + || d_is_negative(d) + || !inode->i_nlink)) + err = -ENOENT; + return err; +} + +static inline int au_d_linkable(struct dentry *d) +{ + int err; + struct inode *inode = d_inode(d); + + err = au_d_hashed_positive(d); + if (err + && d_is_positive(d) + && (inode->i_state & I_LINKABLE)) + err = 0; + return err; +} + +static inline int au_d_alive(struct dentry *d) +{ + int err; + struct inode *inode; + + err = 0; + if (!IS_ROOT(d)) + err = au_d_hashed_positive(d); + else { + inode = d_inode(d); + if (unlikely(d_unlinked(d) + || d_is_negative(d) + || !inode->i_nlink)) + err = -ENOENT; + } + return err; +} + +static inline int au_alive_dir(struct dentry *d) +{ + int err; + + err = au_d_alive(d); + if (unlikely(err || IS_DEADDIR(d_inode(d)))) + err = -ENOENT; + return err; +} + +static inline int au_qstreq(struct qstr *a, struct qstr *b) +{ + return a->len == b->len + && !memcmp(a->name, b->name, a->len); +} + +/* + * by the commit + * 360f547 2015-01-25 dcache: let the dentry count go down to zero without + * taking d_lock + * the type of d_lockref.count became int, but the inlined function d_count() + * still returns unsigned int. + * I don't know why. Maybe it is for every d_count() users? + * Anyway au_dcount() lives on. + */ +static inline int au_dcount(struct dentry *d) +{ + return (int)d_count(d); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DCSUB_H__ */ diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c new file mode 100644 index 000000000000..b93bb4f565bf --- /dev/null +++ b/fs/aufs/debug.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debug print functions + */ + +#include +#include "aufs.h" + +/* Returns 0, or -errno. arg is in kp->arg. */ +static int param_atomic_t_set(const char *val, const struct kernel_param *kp) +{ + int err, n; + + err = kstrtoint(val, 0, &n); + if (!err) { + if (n > 0) + au_debug_on(); + else + au_debug_off(); + } + return err; +} + +/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ +static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) +{ + atomic_t *a; + + a = kp->arg; + return sprintf(buffer, "%d", atomic_read(a)); +} + +static struct kernel_param_ops param_ops_atomic_t = { + .set = param_atomic_t_set, + .get = param_atomic_t_get + /* void (*free)(void *arg) */ +}; + +atomic_t aufs_debug = ATOMIC_INIT(0); +MODULE_PARM_DESC(debug, "debug print"); +module_param_named(debug, aufs_debug, atomic_t, 0664); + +DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ +char *au_plevel = KERN_DEBUG; +#define dpri(fmt, ...) do { \ + if ((au_plevel \ + && strcmp(au_plevel, KERN_DEBUG)) \ + || au_debug_test()) \ + printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ +} while (0) + +/* ---------------------------------------------------------------------- */ + +void au_dpri_whlist(struct au_nhash *whlist) +{ + unsigned long ul, n; + struct hlist_head *head; + struct au_vdir_wh *pos; + + n = whlist->nh_num; + head = whlist->nh_head; + for (ul = 0; ul < n; ul++) { + hlist_for_each_entry(pos, head, wh_hash) + dpri("b%d, %.*s, %d\n", + pos->wh_bindex, + pos->wh_str.len, pos->wh_str.name, + pos->wh_str.len); + head++; + } +} + +void au_dpri_vdir(struct au_vdir *vdir) +{ + unsigned long ul; + union au_vdir_deblk_p p; + unsigned char *o; + + if (!vdir || IS_ERR(vdir)) { + dpri("err %ld\n", PTR_ERR(vdir)); + return; + } + + dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %llu\n", + vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, + vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); + for (ul = 0; ul < vdir->vd_nblk; ul++) { + p.deblk = vdir->vd_deblk[ul]; + o = p.deblk; + dpri("[%lu]: %p\n", ul, o); + } +} + +static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, + struct dentry *wh) +{ + char *n = NULL; + int l = 0; + + if (!inode || IS_ERR(inode)) { + dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); + return -1; + } + + /* the type of i_blocks depends upon CONFIG_LBDAF */ + BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) + && sizeof(inode->i_blocks) != sizeof(u64)); + if (wh) { + n = (void *)wh->d_name.name; + l = wh->d_name.len; + } + + dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," + " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", + bindex, inode, + inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", + atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, + i_size_read(inode), (unsigned long long)inode->i_blocks, + hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, + inode->i_mapping ? inode->i_mapping->nrpages : 0, + inode->i_state, inode->i_flags, inode_peek_iversion(inode), + inode->i_generation, + l ? ", wh " : "", l, n); + return 0; +} + +void au_dpri_inode(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct au_hinode *hi; + aufs_bindex_t bindex; + int err, hn; + + err = do_pri_inode(-1, inode, -1, NULL); + if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) + return; + + iinfo = au_ii(inode); + dpri("i-1: btop %d, bbot %d, gen %d\n", + iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); + if (iinfo->ii_btop < 0) + return; + hn = 0; + for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { + hi = au_hinode(iinfo, bindex); + hn = !!au_hn(hi); + do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); + } +} + +void au_dpri_dalias(struct inode *inode) +{ + struct dentry *d; + + spin_lock(&inode->i_lock); + hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) + au_dpri_dentry(d); + spin_unlock(&inode->i_lock); +} + +static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) +{ + struct dentry *wh = NULL; + int hn; + struct inode *inode; + struct au_iinfo *iinfo; + struct au_hinode *hi; + + if (!dentry || IS_ERR(dentry)) { + dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); + return -1; + } + /* do not call dget_parent() here */ + /* note: access d_xxx without d_lock */ + dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", + bindex, dentry, dentry, + dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", + au_dcount(dentry), dentry->d_flags, + d_unhashed(dentry) ? "un" : ""); + hn = -1; + inode = NULL; + if (d_is_positive(dentry)) + inode = d_inode(dentry); + if (inode + && au_test_aufs(dentry->d_sb) + && bindex >= 0 + && !au_is_bad_inode(inode)) { + iinfo = au_ii(inode); + hi = au_hinode(iinfo, bindex); + hn = !!au_hn(hi); + wh = hi->hi_whdentry; + } + do_pri_inode(bindex, inode, hn, wh); + return 0; +} + +void au_dpri_dentry(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + aufs_bindex_t bindex; + int err; + + err = do_pri_dentry(-1, dentry); + if (err || !au_test_aufs(dentry->d_sb)) + return; + + dinfo = au_di(dentry); + if (!dinfo) + return; + dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", + dinfo->di_btop, dinfo->di_bbot, + dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), + dinfo->di_tmpfile); + if (dinfo->di_btop < 0) + return; + for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) + do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); +} + +static int do_pri_file(aufs_bindex_t bindex, struct file *file) +{ + char a[32]; + + if (!file || IS_ERR(file)) { + dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); + return -1; + } + a[0] = 0; + if (bindex < 0 + && !IS_ERR_OR_NULL(file->f_path.dentry) + && au_test_aufs(file->f_path.dentry->d_sb) + && au_fi(file)) + snprintf(a, sizeof(a), ", gen %d, mmapped %d", + au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); + dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", + bindex, file->f_mode, file->f_flags, (long)file_count(file), + file->f_version, file->f_pos, a); + if (!IS_ERR_OR_NULL(file->f_path.dentry)) + do_pri_dentry(bindex, file->f_path.dentry); + return 0; +} + +void au_dpri_file(struct file *file) +{ + struct au_finfo *finfo; + struct au_fidir *fidir; + struct au_hfile *hfile; + aufs_bindex_t bindex; + int err; + + err = do_pri_file(-1, file); + if (err + || IS_ERR_OR_NULL(file->f_path.dentry) + || !au_test_aufs(file->f_path.dentry->d_sb)) + return; + + finfo = au_fi(file); + if (!finfo) + return; + if (finfo->fi_btop < 0) + return; + fidir = finfo->fi_hdir; + if (!fidir) + do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); + else + for (bindex = finfo->fi_btop; + bindex >= 0 && bindex <= fidir->fd_bbot; + bindex++) { + hfile = fidir->fd_hfile + bindex; + do_pri_file(bindex, hfile ? hfile->hf_file : NULL); + } +} + +static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) +{ + struct vfsmount *mnt; + struct super_block *sb; + + if (!br || IS_ERR(br)) + goto out; + mnt = au_br_mnt(br); + if (!mnt || IS_ERR(mnt)) + goto out; + sb = mnt->mnt_sb; + if (!sb || IS_ERR(sb)) + goto out; + + dpri("s%d: {perm 0x%x, id %d, wbr %p}, " + "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " + "xino %d\n", + bindex, br->br_perm, br->br_id, br->br_wbr, + au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), + sb->s_flags, sb->s_count, + atomic_read(&sb->s_active), + !!au_xino_file(br->br_xino, /*idx*/-1)); + return 0; + +out: + dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); + return -1; +} + +void au_dpri_sb(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + aufs_bindex_t bindex; + int err; + /* to reduce stack size */ + struct { + struct vfsmount mnt; + struct au_branch fake; + } *a; + + /* this function can be called from magic sysrq */ + a = kzalloc(sizeof(*a), GFP_ATOMIC); + if (unlikely(!a)) { + dpri("no memory\n"); + return; + } + + a->mnt.mnt_sb = sb; + a->fake.br_path.mnt = &a->mnt; + err = do_pri_br(-1, &a->fake); + au_kfree_rcu(a); + dpri("dev 0x%x\n", sb->s_dev); + if (err || !au_test_aufs(sb)) + return; + + sbinfo = au_sbi(sb); + if (!sbinfo) + return; + dpri("nw %d, gen %u, kobj %d\n", + atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, + kref_read(&sbinfo->si_kobj.kref)); + for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) + do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); +} + +/* ---------------------------------------------------------------------- */ + +void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) +{ + struct inode *h_inode, *inode = d_inode(dentry); + struct dentry *h_dentry; + aufs_bindex_t bindex, bbot, bi; + + if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) + return; + + bbot = au_dbbot(dentry); + bi = au_ibbot(inode); + if (bi < bbot) + bbot = bi; + bindex = au_dbtop(dentry); + bi = au_ibtop(inode); + if (bi > bindex) + bindex = bi; + + for (; bindex <= bbot; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + h_inode = au_h_iptr(inode, bindex); + if (unlikely(h_inode != d_inode(h_dentry))) { + au_debug_on(); + AuDbg("b%d, %s:%d\n", bindex, func, line); + AuDbgDentry(dentry); + AuDbgInode(inode); + au_debug_off(); + BUG(); + } + } +} + +void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) +{ + int err, i, j; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + + err = au_dpages_init(&dpages, GFP_NOFS); + AuDebugOn(err); + err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); + AuDebugOn(err); + for (i = dpages.ndpage - 1; !err && i >= 0; i--) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + for (j = dpage->ndentry - 1; !err && j >= 0; j--) + AuDebugOn(au_digen_test(dentries[j], sigen)); + } + au_dpages_free(&dpages); +} + +void au_dbg_verify_kthread(void) +{ + if (au_wkq_test()) { + au_dbg_blocked(); + /* + * It may be recursive, but udba=notify between two aufs mounts, + * where a single ro branch is shared, is not a problem. + */ + /* WARN_ON(1); */ + } +} + +/* ---------------------------------------------------------------------- */ + +int __init au_debug_init(void) +{ + aufs_bindex_t bindex; + struct au_vdir_destr destr; + + bindex = -1; + AuDebugOn(bindex >= 0); + + destr.len = -1; + AuDebugOn(destr.len < NAME_MAX); + +#ifdef CONFIG_4KSTACKS + pr_warn("CONFIG_4KSTACKS is defined.\n"); +#endif + + return 0; +} diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h new file mode 100644 index 000000000000..9c52470a61fb --- /dev/null +++ b/fs/aufs/debug.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * debug print functions + */ + +#ifndef __AUFS_DEBUG_H__ +#define __AUFS_DEBUG_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#ifdef CONFIG_AUFS_DEBUG +#define AuDebugOn(a) BUG_ON(a) + +/* module parameter */ +extern atomic_t aufs_debug; +static inline void au_debug_on(void) +{ + atomic_inc(&aufs_debug); +} +static inline void au_debug_off(void) +{ + atomic_dec_if_positive(&aufs_debug); +} + +static inline int au_debug_test(void) +{ + return atomic_read(&aufs_debug) > 0; +} +#else +#define AuDebugOn(a) do {} while (0) +AuStubVoid(au_debug_on, void) +AuStubVoid(au_debug_off, void) +AuStubInt0(au_debug_test, void) +#endif /* CONFIG_AUFS_DEBUG */ + +#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) + +/* ---------------------------------------------------------------------- */ + +/* debug print */ + +#define AuDbg(fmt, ...) do { \ + if (au_debug_test()) \ + pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ +} while (0) +#define AuLabel(l) AuDbg(#l "\n") +#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) +#define AuWarn1(fmt, ...) do { \ + static unsigned char _c; \ + if (!_c++) \ + pr_warn(fmt, ##__VA_ARGS__); \ +} while (0) + +#define AuErr1(fmt, ...) do { \ + static unsigned char _c; \ + if (!_c++) \ + pr_err(fmt, ##__VA_ARGS__); \ +} while (0) + +#define AuIOErr1(fmt, ...) do { \ + static unsigned char _c; \ + if (!_c++) \ + AuIOErr(fmt, ##__VA_ARGS__); \ +} while (0) + +#define AuUnsupportMsg "This operation is not supported." \ + " Please report this application to aufs-users ML." +#define AuUnsupport(fmt, ...) do { \ + pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ + dump_stack(); \ +} while (0) + +#define AuTraceErr(e) do { \ + if (unlikely((e) < 0)) \ + AuDbg("err %d\n", (int)(e)); \ +} while (0) + +#define AuTraceErrPtr(p) do { \ + if (IS_ERR(p)) \ + AuDbg("err %ld\n", PTR_ERR(p)); \ +} while (0) + +/* dirty macros for debug print, use with "%.*s" and caution */ +#define AuLNPair(qstr) (qstr)->len, (qstr)->name + +/* ---------------------------------------------------------------------- */ + +struct dentry; +#ifdef CONFIG_AUFS_DEBUG +extern struct mutex au_dbg_mtx; +extern char *au_plevel; +struct au_nhash; +void au_dpri_whlist(struct au_nhash *whlist); +struct au_vdir; +void au_dpri_vdir(struct au_vdir *vdir); +struct inode; +void au_dpri_inode(struct inode *inode); +void au_dpri_dalias(struct inode *inode); +void au_dpri_dentry(struct dentry *dentry); +struct file; +void au_dpri_file(struct file *filp); +struct super_block; +void au_dpri_sb(struct super_block *sb); + +#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) +void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); +void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); +void au_dbg_verify_kthread(void); + +int __init au_debug_init(void); + +#define AuDbgWhlist(w) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#w "\n"); \ + au_dpri_whlist(w); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgVdir(v) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#v "\n"); \ + au_dpri_vdir(v); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgInode(i) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#i "\n"); \ + au_dpri_inode(i); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgDAlias(i) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#i "\n"); \ + au_dpri_dalias(i); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgDentry(d) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#d "\n"); \ + au_dpri_dentry(d); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgFile(f) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#f "\n"); \ + au_dpri_file(f); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgSb(sb) do { \ + mutex_lock(&au_dbg_mtx); \ + AuDbg(#sb "\n"); \ + au_dpri_sb(sb); \ + mutex_unlock(&au_dbg_mtx); \ +} while (0) + +#define AuDbgSym(addr) do { \ + char sym[KSYM_SYMBOL_LEN]; \ + sprint_symbol(sym, (unsigned long)addr); \ + AuDbg("%s\n", sym); \ +} while (0) +#else +AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) +AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) +AuStubVoid(au_dbg_verify_kthread, void) +AuStubInt0(__init au_debug_init, void) + +#define AuDbgWhlist(w) do {} while (0) +#define AuDbgVdir(v) do {} while (0) +#define AuDbgInode(i) do {} while (0) +#define AuDbgDAlias(i) do {} while (0) +#define AuDbgDentry(d) do {} while (0) +#define AuDbgFile(f) do {} while (0) +#define AuDbgSb(sb) do {} while (0) +#define AuDbgSym(addr) do {} while (0) +#endif /* CONFIG_AUFS_DEBUG */ + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_MAGIC_SYSRQ +int __init au_sysrq_init(void); +void au_sysrq_fin(void); + +#ifdef CONFIG_HW_CONSOLE +#define au_dbg_blocked() do { \ + WARN_ON(1); \ + handle_sysrq('w'); \ +} while (0) +#else +AuStubVoid(au_dbg_blocked, void) +#endif + +#else +AuStubInt0(__init au_sysrq_init, void) +AuStubVoid(au_sysrq_fin, void) +AuStubVoid(au_dbg_blocked, void) +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DEBUG_H__ */ diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c new file mode 100644 index 000000000000..faf664508e64 --- /dev/null +++ b/fs/aufs/dentry.c @@ -0,0 +1,1154 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * lookup and dentry operations + */ + +#include +#include +#include "aufs.h" + +/* + * returns positive/negative dentry, NULL or an error. + * NULL means whiteout-ed or not-found. + */ +static struct dentry* +au_do_lookup(struct dentry *h_parent, struct dentry *dentry, + aufs_bindex_t bindex, struct au_do_lookup_args *args) +{ + struct dentry *h_dentry; + struct inode *h_inode; + struct au_branch *br; + int wh_found, opq; + unsigned char wh_able; + const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); + const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, + IGNORE_PERM); + + wh_found = 0; + br = au_sbr(dentry->d_sb, bindex); + wh_able = !!au_br_whable(br->br_perm); + if (wh_able) + wh_found = au_wh_test(h_parent, &args->whname, ignore_perm); + h_dentry = ERR_PTR(wh_found); + if (!wh_found) + goto real_lookup; + if (unlikely(wh_found < 0)) + goto out; + + /* We found a whiteout */ + /* au_set_dbbot(dentry, bindex); */ + au_set_dbwh(dentry, bindex); + if (!allow_neg) + return NULL; /* success */ + +real_lookup: + if (!ignore_perm) + h_dentry = vfsub_lkup_one(args->name, h_parent); + else + h_dentry = au_sio_lkup_one(args->name, h_parent); + if (IS_ERR(h_dentry)) { + if (PTR_ERR(h_dentry) == -ENAMETOOLONG + && !allow_neg) + h_dentry = NULL; + goto out; + } + + h_inode = d_inode(h_dentry); + if (d_is_negative(h_dentry)) { + if (!allow_neg) + goto out_neg; + } else if (wh_found + || (args->type && args->type != (h_inode->i_mode & S_IFMT))) + goto out_neg; + else if (au_ftest_lkup(args->flags, DIRREN) + /* && h_inode */ + && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { + AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, + (unsigned long long)h_inode->i_ino); + goto out_neg; + } + + if (au_dbbot(dentry) <= bindex) + au_set_dbbot(dentry, bindex); + if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) + au_set_dbtop(dentry, bindex); + au_set_h_dptr(dentry, bindex, h_dentry); + + if (!d_is_dir(h_dentry) + || !wh_able + || (d_really_is_positive(dentry) && !d_is_dir(dentry))) + goto out; /* success */ + + inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); + opq = au_diropq_test(h_dentry); + inode_unlock_shared(h_inode); + if (opq > 0) + au_set_dbdiropq(dentry, bindex); + else if (unlikely(opq < 0)) { + au_set_h_dptr(dentry, bindex, NULL); + h_dentry = ERR_PTR(opq); + } + goto out; + +out_neg: + dput(h_dentry); + h_dentry = NULL; +out: + return h_dentry; +} + +static int au_test_shwh(struct super_block *sb, const struct qstr *name) +{ + if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) + && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) + return -EPERM; + return 0; +} + +/* + * returns the number of lower positive dentries, + * otherwise an error. + * can be called at unlinking with @type is zero. + */ +int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, + unsigned int flags) +{ + int npositive, err; + aufs_bindex_t bindex, btail, bdiropq; + unsigned char isdir, dirperm1, dirren; + struct au_do_lookup_args args = { + .flags = flags, + .name = &dentry->d_name + }; + struct dentry *parent; + struct super_block *sb; + + sb = dentry->d_sb; + err = au_test_shwh(sb, args.name); + if (unlikely(err)) + goto out; + + err = au_wh_name_alloc(&args.whname, args.name); + if (unlikely(err)) + goto out; + + isdir = !!d_is_dir(dentry); + dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); + dirren = !!au_opt_test(au_mntflags(sb), DIRREN); + if (dirren) + au_fset_lkup(args.flags, DIRREN); + + npositive = 0; + parent = dget_parent(dentry); + btail = au_dbtaildir(parent); + for (bindex = btop; bindex <= btail; bindex++) { + struct dentry *h_parent, *h_dentry; + struct inode *h_inode, *h_dir; + struct au_branch *br; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry) { + if (d_is_positive(h_dentry)) + npositive++; + break; + } + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || !d_is_dir(h_parent)) + continue; + + if (dirren) { + /* if the inum matches, then use the prepared name */ + err = au_dr_lkup_name(&args, bindex); + if (unlikely(err)) + goto out_parent; + } + + h_dir = d_inode(h_parent); + inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); + h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); + inode_unlock_shared(h_dir); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out_parent; + if (h_dentry) + au_fclr_lkup(args.flags, ALLOW_NEG); + if (dirperm1) + au_fset_lkup(args.flags, IGNORE_PERM); + + if (au_dbwh(dentry) == bindex) + break; + if (!h_dentry) + continue; + if (d_is_negative(h_dentry)) + continue; + h_inode = d_inode(h_dentry); + npositive++; + if (!args.type) + args.type = h_inode->i_mode & S_IFMT; + if (args.type != S_IFDIR) + break; + else if (isdir) { + /* the type of lower may be different */ + bdiropq = au_dbdiropq(dentry); + if (bdiropq >= 0 && bdiropq <= bindex) + break; + } + br = au_sbr(sb, bindex); + if (dirren + && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, + /*add_ent*/NULL)) { + /* prepare next name to lookup */ + err = au_dr_lkup(&args, dentry, bindex); + if (unlikely(err)) + goto out_parent; + } + } + + if (npositive) { + AuLabel(positive); + au_update_dbtop(dentry); + } + err = npositive; + if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) + && au_dbtop(dentry) < 0)) { + err = -EIO; + AuIOErr("both of real entry and whiteout found, %pd, err %d\n", + dentry, err); + } + +out_parent: + dput(parent); + au_kfree_try_rcu(args.whname.name); + if (dirren) + au_dr_lkup_fin(&args); +out: + return err; +} + +struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) +{ + struct dentry *dentry; + int wkq_err; + + if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC)) + dentry = vfsub_lkup_one(name, parent); + else { + struct vfsub_lkup_one_args args = { + .errp = &dentry, + .name = name, + .parent = parent + }; + + wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); + if (unlikely(wkq_err)) + dentry = ERR_PTR(wkq_err); + } + + return dentry; +} + +/* + * lookup @dentry on @bindex which should be negative. + */ +int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) +{ + int err; + struct dentry *parent, *h_parent, *h_dentry; + struct au_branch *br; + + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bindex); + br = au_sbr(dentry->d_sb, bindex); + if (wh) + h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); + else + h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out; + if (unlikely(d_is_positive(h_dentry))) { + err = -EIO; + AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); + dput(h_dentry); + goto out; + } + + err = 0; + if (bindex < au_dbtop(dentry)) + au_set_dbtop(dentry, bindex); + if (au_dbbot(dentry) < bindex) + au_set_dbbot(dentry, bindex); + au_set_h_dptr(dentry, bindex, h_dentry); + +out: + dput(parent); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* subset of struct inode */ +struct au_iattr { + unsigned long i_ino; + /* unsigned int i_nlink; */ + kuid_t i_uid; + kgid_t i_gid; + u64 i_version; +/* + loff_t i_size; + blkcnt_t i_blocks; +*/ + umode_t i_mode; +}; + +static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) +{ + ia->i_ino = h_inode->i_ino; + /* ia->i_nlink = h_inode->i_nlink; */ + ia->i_uid = h_inode->i_uid; + ia->i_gid = h_inode->i_gid; + ia->i_version = inode_query_iversion(h_inode); +/* + ia->i_size = h_inode->i_size; + ia->i_blocks = h_inode->i_blocks; +*/ + ia->i_mode = (h_inode->i_mode & S_IFMT); +} + +static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) +{ + return ia->i_ino != h_inode->i_ino + /* || ia->i_nlink != h_inode->i_nlink */ + || !uid_eq(ia->i_uid, h_inode->i_uid) + || !gid_eq(ia->i_gid, h_inode->i_gid) + || !inode_eq_iversion(h_inode, ia->i_version) +/* + || ia->i_size != h_inode->i_size + || ia->i_blocks != h_inode->i_blocks +*/ + || ia->i_mode != (h_inode->i_mode & S_IFMT); +} + +static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, + struct au_branch *br) +{ + int err; + struct au_iattr ia; + struct inode *h_inode; + struct dentry *h_d; + struct super_block *h_sb; + + err = 0; + memset(&ia, -1, sizeof(ia)); + h_sb = h_dentry->d_sb; + h_inode = NULL; + if (d_is_positive(h_dentry)) { + h_inode = d_inode(h_dentry); + au_iattr_save(&ia, h_inode); + } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) + /* nfs d_revalidate may return 0 for negative dentry */ + /* fuse d_revalidate always return 0 for negative dentry */ + goto out; + + /* main purpose is namei.c:cached_lookup() and d_revalidate */ + h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); + err = PTR_ERR(h_d); + if (IS_ERR(h_d)) + goto out; + + err = 0; + if (unlikely(h_d != h_dentry + || d_inode(h_d) != h_inode + || (h_inode && au_iattr_test(&ia, h_inode)))) + err = au_busy_or_stale(); + dput(h_d); + +out: + AuTraceErr(err); + return err; +} + +int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, + struct dentry *h_parent, struct au_branch *br) +{ + int err; + + err = 0; + if (udba == AuOpt_UDBA_REVAL + && !au_test_fs_remote(h_dentry->d_sb)) { + IMustLock(h_dir); + err = (d_inode(h_dentry->d_parent) != h_dir); + } else if (udba != AuOpt_UDBA_NONE) + err = au_h_verify_dentry(h_dentry, h_parent, br); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) +{ + int err; + aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; + struct au_hdentry tmp, *p, *q; + struct au_dinfo *dinfo; + struct super_block *sb; + + DiMustWriteLock(dentry); + + sb = dentry->d_sb; + dinfo = au_di(dentry); + bbot = dinfo->di_bbot; + bwh = dinfo->di_bwh; + bdiropq = dinfo->di_bdiropq; + bindex = dinfo->di_btop; + p = au_hdentry(dinfo, bindex); + for (; bindex <= bbot; bindex++, p++) { + if (!p->hd_dentry) + continue; + + new_bindex = au_br_index(sb, p->hd_id); + if (new_bindex == bindex) + continue; + + if (dinfo->di_bwh == bindex) + bwh = new_bindex; + if (dinfo->di_bdiropq == bindex) + bdiropq = new_bindex; + if (new_bindex < 0) { + au_hdput(p); + p->hd_dentry = NULL; + continue; + } + + /* swap two lower dentries, and loop again */ + q = au_hdentry(dinfo, new_bindex); + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hd_dentry) { + bindex--; + p--; + } + } + + dinfo->di_bwh = -1; + if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) + dinfo->di_bwh = bwh; + + dinfo->di_bdiropq = -1; + if (bdiropq >= 0 + && bdiropq <= au_sbbot(sb) + && au_sbr_whable(sb, bdiropq)) + dinfo->di_bdiropq = bdiropq; + + err = -EIO; + dinfo->di_btop = -1; + dinfo->di_bbot = -1; + bbot = au_dbbot(parent); + bindex = 0; + p = au_hdentry(dinfo, bindex); + for (; bindex <= bbot; bindex++, p++) + if (p->hd_dentry) { + dinfo->di_btop = bindex; + break; + } + + if (dinfo->di_btop >= 0) { + bindex = bbot; + p = au_hdentry(dinfo, bindex); + for (; bindex >= 0; bindex--, p--) + if (p->hd_dentry) { + dinfo->di_bbot = bindex; + err = 0; + break; + } + } + + return err; +} + +static void au_do_hide(struct dentry *dentry) +{ + struct inode *inode; + + if (d_really_is_positive(dentry)) { + inode = d_inode(dentry); + if (!d_is_dir(dentry)) { + if (inode->i_nlink && !d_unhashed(dentry)) + drop_nlink(inode); + } else { + clear_nlink(inode); + /* stop next lookup */ + inode->i_flags |= S_DEAD; + } + smp_mb(); /* necessary? */ + } + d_drop(dentry); +} + +static int au_hide_children(struct dentry *parent) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry *dentry; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, parent, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + /* in reverse order */ + for (i = dpages.ndpage - 1; i >= 0; i--) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = ndentry - 1; j >= 0; j--) { + dentry = dpage->dentries[j]; + if (dentry != parent) + au_do_hide(dentry); + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +static void au_hide(struct dentry *dentry) +{ + int err; + + AuDbgDentry(dentry); + if (d_is_dir(dentry)) { + /* shrink_dcache_parent(dentry); */ + err = au_hide_children(dentry); + if (unlikely(err)) + AuIOErr("%pd, failed hiding children, ignored %d\n", + dentry, err); + } + au_do_hide(dentry); +} + +/* + * By adding a dirty branch, a cached dentry may be affected in various ways. + * + * a dirty branch is added + * - on the top of layers + * - in the middle of layers + * - to the bottom of layers + * + * on the added branch there exists + * - a whiteout + * - a diropq + * - a same named entry + * + exist + * * negative --> positive + * * positive --> positive + * - type is unchanged + * - type is changed + * + doesn't exist + * * negative --> negative + * * positive --> negative (rejected by au_br_del() for non-dir case) + * - none + */ +static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, + struct au_dinfo *tmp) +{ + int err; + aufs_bindex_t bindex, bbot; + struct { + struct dentry *dentry; + struct inode *inode; + mode_t mode; + } orig_h, tmp_h = { + .dentry = NULL + }; + struct au_hdentry *hd; + struct inode *inode, *h_inode; + struct dentry *h_dentry; + + err = 0; + AuDebugOn(dinfo->di_btop < 0); + orig_h.mode = 0; + orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; + orig_h.inode = NULL; + if (d_is_positive(orig_h.dentry)) { + orig_h.inode = d_inode(orig_h.dentry); + orig_h.mode = orig_h.inode->i_mode & S_IFMT; + } + if (tmp->di_btop >= 0) { + tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; + if (d_is_positive(tmp_h.dentry)) { + tmp_h.inode = d_inode(tmp_h.dentry); + tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; + } + } + + inode = NULL; + if (d_really_is_positive(dentry)) + inode = d_inode(dentry); + if (!orig_h.inode) { + AuDbg("negative originally\n"); + if (inode) { + au_hide(dentry); + goto out; + } + AuDebugOn(inode); + AuDebugOn(dinfo->di_btop != dinfo->di_bbot); + AuDebugOn(dinfo->di_bdiropq != -1); + + if (!tmp_h.inode) { + AuDbg("negative --> negative\n"); + /* should have only one negative lower */ + if (tmp->di_btop >= 0 + && tmp->di_btop < dinfo->di_btop) { + AuDebugOn(tmp->di_btop != tmp->di_bbot); + AuDebugOn(dinfo->di_btop != dinfo->di_bbot); + au_set_h_dptr(dentry, dinfo->di_btop, NULL); + au_di_cp(dinfo, tmp); + hd = au_hdentry(tmp, tmp->di_btop); + au_set_h_dptr(dentry, tmp->di_btop, + dget(hd->hd_dentry)); + } + au_dbg_verify_dinode(dentry); + } else { + AuDbg("negative --> positive\n"); + /* + * similar to the behaviour of creating with bypassing + * aufs. + * unhash it in order to force an error in the + * succeeding create operation. + * we should not set S_DEAD here. + */ + d_drop(dentry); + /* au_di_swap(tmp, dinfo); */ + au_dbg_verify_dinode(dentry); + } + } else { + AuDbg("positive originally\n"); + /* inode may be NULL */ + AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); + if (!tmp_h.inode) { + AuDbg("positive --> negative\n"); + /* or bypassing aufs */ + au_hide(dentry); + if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) + dinfo->di_bwh = tmp->di_bwh; + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + } else if (orig_h.mode == tmp_h.mode) { + AuDbg("positive --> positive, same type\n"); + if (!S_ISDIR(orig_h.mode) + && dinfo->di_btop > tmp->di_btop) { + /* + * similar to the behaviour of removing and + * creating. + */ + au_hide(dentry); + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + } else { + /* fill empty slots */ + if (dinfo->di_btop > tmp->di_btop) + dinfo->di_btop = tmp->di_btop; + if (dinfo->di_bbot < tmp->di_bbot) + dinfo->di_bbot = tmp->di_bbot; + dinfo->di_bwh = tmp->di_bwh; + dinfo->di_bdiropq = tmp->di_bdiropq; + bbot = dinfo->di_bbot; + bindex = tmp->di_btop; + hd = au_hdentry(tmp, bindex); + for (; bindex <= bbot; bindex++, hd++) { + if (au_h_dptr(dentry, bindex)) + continue; + h_dentry = hd->hd_dentry; + if (!h_dentry) + continue; + AuDebugOn(d_is_negative(h_dentry)); + h_inode = d_inode(h_dentry); + AuDebugOn(orig_h.mode + != (h_inode->i_mode + & S_IFMT)); + au_set_h_dptr(dentry, bindex, + dget(h_dentry)); + } + if (inode) + err = au_refresh_hinode(inode, dentry); + au_dbg_verify_dinode(dentry); + } + } else { + AuDbg("positive --> positive, different type\n"); + /* similar to the behaviour of removing and creating */ + au_hide(dentry); + if (inode) + err = au_refresh_hinode_self(inode); + au_dbg_verify_dinode(dentry); + } + } + +out: + return err; +} + +void au_refresh_dop(struct dentry *dentry, int force_reval) +{ + const struct dentry_operations *dop + = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; + static const unsigned int mask + = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; + + BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); + + if (dentry->d_op == dop) + return; + + AuDbg("%pd\n", dentry); + spin_lock(&dentry->d_lock); + if (dop == &aufs_dop) + dentry->d_flags |= mask; + else + dentry->d_flags &= ~mask; + dentry->d_op = dop; + spin_unlock(&dentry->d_lock); +} + +int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) +{ + int err, ebrange, nbr; + unsigned int sigen; + struct au_dinfo *dinfo, *tmp; + struct super_block *sb; + struct inode *inode; + + DiMustWriteLock(dentry); + AuDebugOn(IS_ROOT(dentry)); + AuDebugOn(d_really_is_negative(parent)); + + sb = dentry->d_sb; + sigen = au_sigen(sb); + err = au_digen_test(parent, sigen); + if (unlikely(err)) + goto out; + + nbr = au_sbbot(sb) + 1; + dinfo = au_di(dentry); + err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); + if (unlikely(err)) + goto out; + ebrange = au_dbrange_test(dentry); + if (!ebrange) + ebrange = au_do_refresh_hdentry(dentry, parent); + + if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { + AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); + if (d_really_is_positive(dentry)) { + inode = d_inode(dentry); + err = au_refresh_hinode_self(inode); + } + au_dbg_verify_dinode(dentry); + if (!err) + goto out_dgen; /* success */ + goto out; + } + + /* temporary dinfo */ + AuDbgDentry(dentry); + err = -ENOMEM; + tmp = au_di_alloc(sb, AuLsc_DI_TMP); + if (unlikely(!tmp)) + goto out; + au_di_swap(tmp, dinfo); + /* returns the number of positive dentries */ + /* + * if current working dir is removed, it returns an error. + * but the dentry is legal. + */ + err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); + AuDbgDentry(dentry); + au_di_swap(tmp, dinfo); + if (err == -ENOENT) + err = 0; + if (err >= 0) { + /* compare/refresh by dinfo */ + AuDbgDentry(dentry); + err = au_refresh_by_dinfo(dentry, dinfo, tmp); + au_dbg_verify_dinode(dentry); + AuTraceErr(err); + } + au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */ + au_rw_write_unlock(&tmp->di_rwsem); + au_di_free(tmp); + if (unlikely(err)) + goto out; + +out_dgen: + au_update_digen(dentry); +out: + if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { + AuIOErr("failed refreshing %pd, %d\n", dentry, err); + AuDbgDentry(dentry); + } + AuTraceErr(err); + return err; +} + +static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, + struct dentry *dentry, aufs_bindex_t bindex) +{ + int err, valid; + + err = 0; + if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) + goto out; + + AuDbg("b%d\n", bindex); + /* + * gave up supporting LOOKUP_CREATE/OPEN for lower fs, + * due to whiteout and branch permission. + */ + flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE + | LOOKUP_FOLLOW | LOOKUP_EXCL); + /* it may return tri-state */ + valid = h_dentry->d_op->d_revalidate(h_dentry, flags); + + if (unlikely(valid < 0)) + err = valid; + else if (!valid) + err = -EINVAL; + +out: + AuTraceErr(err); + return err; +} + +/* todo: remove this */ +static int h_d_revalidate(struct dentry *dentry, struct inode *inode, + unsigned int flags, int do_udba, int dirren) +{ + int err; + umode_t mode, h_mode; + aufs_bindex_t bindex, btail, btop, ibs, ibe; + unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; + struct inode *h_inode, *h_cached_inode; + struct dentry *h_dentry; + struct qstr *name, *h_name; + + err = 0; + plus = 0; + mode = 0; + ibs = -1; + ibe = -1; + unhashed = !!d_unhashed(dentry); + is_root = !!IS_ROOT(dentry); + name = &dentry->d_name; + tmpfile = au_di(dentry)->di_tmpfile; + + /* + * Theoretically, REVAL test should be unnecessary in case of + * {FS,I}NOTIFY. + * But {fs,i}notify doesn't fire some necessary events, + * IN_ATTRIB for atime/nlink/pageio + * Let's do REVAL test too. + */ + if (do_udba && inode) { + mode = (inode->i_mode & S_IFMT); + plus = (inode->i_nlink > 0); + ibs = au_ibtop(inode); + ibe = au_ibbot(inode); + } + + btop = au_dbtop(dentry); + btail = btop; + if (inode && S_ISDIR(inode->i_mode)) + btail = au_dbtaildir(dentry); + for (bindex = btop; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + + AuDbg("b%d, %pd\n", bindex, h_dentry); + h_nfs = !!au_test_nfs(h_dentry->d_sb); + spin_lock(&h_dentry->d_lock); + h_name = &h_dentry->d_name; + if (unlikely(do_udba + && !is_root + && ((!h_nfs + && (unhashed != !!d_unhashed(h_dentry) + || (!tmpfile && !dirren + && !au_qstreq(name, h_name)) + )) + || (h_nfs + && !(flags & LOOKUP_OPEN) + && (h_dentry->d_flags + & DCACHE_NFSFS_RENAMED))) + )) { + int h_unhashed; + + h_unhashed = d_unhashed(h_dentry); + spin_unlock(&h_dentry->d_lock); + AuDbg("unhash 0x%x 0x%x, %pd %pd\n", + unhashed, h_unhashed, dentry, h_dentry); + goto err; + } + spin_unlock(&h_dentry->d_lock); + + err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); + if (unlikely(err)) + /* do not goto err, to keep the errno */ + break; + + /* todo: plink too? */ + if (!do_udba) + continue; + + /* UDBA tests */ + if (unlikely(!!inode != d_is_positive(h_dentry))) + goto err; + + h_inode = NULL; + if (d_is_positive(h_dentry)) + h_inode = d_inode(h_dentry); + h_plus = plus; + h_mode = mode; + h_cached_inode = h_inode; + if (h_inode) { + h_mode = (h_inode->i_mode & S_IFMT); + h_plus = (h_inode->i_nlink > 0); + } + if (inode && ibs <= bindex && bindex <= ibe) + h_cached_inode = au_h_iptr(inode, bindex); + + if (!h_nfs) { + if (unlikely(plus != h_plus && !tmpfile)) + goto err; + } else { + if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) + && !is_root + && !IS_ROOT(h_dentry) + && unhashed != d_unhashed(h_dentry))) + goto err; + } + if (unlikely(mode != h_mode + || h_cached_inode != h_inode)) + goto err; + continue; + +err: + err = -EINVAL; + break; + } + + AuTraceErr(err); + return err; +} + +/* todo: consolidate with do_refresh() and au_reval_for_attr() */ +static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) +{ + int err; + struct dentry *parent; + + if (!au_digen_test(dentry, sigen)) + return 0; + + parent = dget_parent(dentry); + di_read_lock_parent(parent, AuLock_IR); + AuDebugOn(au_digen_test(parent, sigen)); + au_dbg_verify_gen(parent, sigen); + err = au_refresh_dentry(dentry, parent); + di_read_unlock(parent, AuLock_IR); + dput(parent); + AuTraceErr(err); + return err; +} + +int au_reval_dpath(struct dentry *dentry, unsigned int sigen) +{ + int err; + struct dentry *d, *parent; + + if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) + return simple_reval_dpath(dentry, sigen); + + /* slow loop, keep it simple and stupid */ + /* cf: au_cpup_dirs() */ + err = 0; + parent = NULL; + while (au_digen_test(dentry, sigen)) { + d = dentry; + while (1) { + dput(parent); + parent = dget_parent(d); + if (!au_digen_test(parent, sigen)) + break; + d = parent; + } + + if (d != dentry) + di_write_lock_child2(d); + + /* someone might update our dentry while we were sleeping */ + if (au_digen_test(d, sigen)) { + /* + * todo: consolidate with simple_reval_dpath(), + * do_refresh() and au_reval_for_attr(). + */ + di_read_lock_parent(parent, AuLock_IR); + err = au_refresh_dentry(d, parent); + di_read_unlock(parent, AuLock_IR); + } + + if (d != dentry) + di_write_unlock(d); + dput(parent); + if (unlikely(err)) + break; + } + + return err; +} + +/* + * if valid returns 1, otherwise 0. + */ +static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + int valid, err; + unsigned int sigen; + unsigned char do_udba, dirren; + struct super_block *sb; + struct inode *inode; + + /* todo: support rcu-walk? */ + if (flags & LOOKUP_RCU) + return -ECHILD; + + valid = 0; + if (unlikely(!au_di(dentry))) + goto out; + + valid = 1; + sb = dentry->d_sb; + /* + * todo: very ugly + * i_mutex of parent dir may be held, + * but we should not return 'invalid' due to busy. + */ + err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); + if (unlikely(err)) { + valid = err; + AuTraceErr(err); + goto out; + } + inode = NULL; + if (d_really_is_positive(dentry)) + inode = d_inode(dentry); + if (unlikely(inode && au_is_bad_inode(inode))) { + err = -EINVAL; + AuTraceErr(err); + goto out_dgrade; + } + if (unlikely(au_dbrange_test(dentry))) { + err = -EINVAL; + AuTraceErr(err); + goto out_dgrade; + } + + sigen = au_sigen(sb); + if (au_digen_test(dentry, sigen)) { + AuDebugOn(IS_ROOT(dentry)); + err = au_reval_dpath(dentry, sigen); + if (unlikely(err)) { + AuTraceErr(err); + goto out_dgrade; + } + } + di_downgrade_lock(dentry, AuLock_IR); + + err = -EINVAL; + if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) + && inode + && !(inode->i_state && I_LINKABLE) + && (IS_DEADDIR(inode) || !inode->i_nlink)) { + AuTraceErr(err); + goto out_inval; + } + + do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); + if (do_udba && inode) { + aufs_bindex_t btop = au_ibtop(inode); + struct inode *h_inode; + + if (btop >= 0) { + h_inode = au_h_iptr(inode, btop); + if (h_inode && au_test_higen(inode, h_inode)) { + AuTraceErr(err); + goto out_inval; + } + } + } + + dirren = !!au_opt_test(au_mntflags(sb), DIRREN); + err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); + if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { + err = -EIO; + AuDbg("both of real entry and whiteout found, %p, err %d\n", + dentry, err); + } + goto out_inval; + +out_dgrade: + di_downgrade_lock(dentry, AuLock_IR); +out_inval: + aufs_read_unlock(dentry, AuLock_IR); + AuTraceErr(err); + valid = !err; +out: + if (!valid) { + AuDbg("%pd invalid, %d\n", dentry, valid); + d_drop(dentry); + } + return valid; +} + +static void aufs_d_release(struct dentry *dentry) +{ + if (au_di(dentry)) { + au_di_fin(dentry); + au_hn_di_reinit(dentry); + } +} + +const struct dentry_operations aufs_dop = { + .d_revalidate = aufs_d_revalidate, + .d_weak_revalidate = aufs_d_revalidate, + .d_release = aufs_d_release +}; + +/* aufs_dop without d_revalidate */ +const struct dentry_operations aufs_dop_noreval = { + .d_release = aufs_d_release +}; diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h new file mode 100644 index 000000000000..3b443fc7eef0 --- /dev/null +++ b/fs/aufs/dentry.h @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * lookup and dentry operations + */ + +#ifndef __AUFS_DENTRY_H__ +#define __AUFS_DENTRY_H__ + +#ifdef __KERNEL__ + +#include +#include "dirren.h" +#include "rwsem.h" + +struct au_hdentry { + struct dentry *hd_dentry; + aufs_bindex_t hd_id; +}; + +struct au_dinfo { + atomic_t di_generation; + + struct au_rwsem di_rwsem; + aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; + unsigned char di_tmpfile; /* to allow the different name */ + struct au_hdentry *di_hdentry; + struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ + +/* flags for au_lkup_dentry() */ +#define AuLkup_ALLOW_NEG 1 +#define AuLkup_IGNORE_PERM (1 << 1) +#define AuLkup_DIRREN (1 << 2) +#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) +#define au_fset_lkup(flags, name) \ + do { (flags) |= AuLkup_##name; } while (0) +#define au_fclr_lkup(flags, name) \ + do { (flags) &= ~AuLkup_##name; } while (0) + +#ifndef CONFIG_AUFS_DIRREN +#undef AuLkup_DIRREN +#define AuLkup_DIRREN 0 +#endif + +struct au_do_lookup_args { + unsigned int flags; + mode_t type; + struct qstr whname, *name; + struct au_dr_lookup dirren; +}; + +/* ---------------------------------------------------------------------- */ + +/* dentry.c */ +extern const struct dentry_operations aufs_dop, aufs_dop_noreval; +struct au_branch; +struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); +int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, + struct dentry *h_parent, struct au_branch *br); + +int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, + unsigned int flags); +int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); +int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); +int au_reval_dpath(struct dentry *dentry, unsigned int sigen); +void au_refresh_dop(struct dentry *dentry, int force_reval); + +/* dinfo.c */ +void au_di_init_once(void *_di); +struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); +void au_di_free(struct au_dinfo *dinfo); +void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); +void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); +int au_di_init(struct dentry *dentry); +void au_di_fin(struct dentry *dentry); +int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink); + +void di_read_lock(struct dentry *d, int flags, unsigned int lsc); +void di_read_unlock(struct dentry *d, int flags); +void di_downgrade_lock(struct dentry *d, int flags); +void di_write_lock(struct dentry *d, unsigned int lsc); +void di_write_unlock(struct dentry *d); +void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); +void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); +void di_write_unlock2(struct dentry *d1, struct dentry *d2); + +struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); +struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); +aufs_bindex_t au_dbtail(struct dentry *dentry); +aufs_bindex_t au_dbtaildir(struct dentry *dentry); + +void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_dentry); +int au_digen_test(struct dentry *dentry, unsigned int sigen); +int au_dbrange_test(struct dentry *dentry); +void au_update_digen(struct dentry *dentry); +void au_update_dbrange(struct dentry *dentry, int do_put_zero); +void au_update_dbtop(struct dentry *dentry); +void au_update_dbbot(struct dentry *dentry); +int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); + +/* ---------------------------------------------------------------------- */ + +static inline struct au_dinfo *au_di(struct dentry *dentry) +{ + return dentry->d_fsdata; +} + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for dinfo */ +enum { + AuLsc_DI_CHILD, /* child first */ + AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ + AuLsc_DI_CHILD3, /* copyup dirs */ + AuLsc_DI_PARENT, + AuLsc_DI_PARENT2, + AuLsc_DI_PARENT3, + AuLsc_DI_TMP /* temp for replacing dinfo */ +}; + +/* + * di_read_lock_child, di_write_lock_child, + * di_read_lock_child2, di_write_lock_child2, + * di_read_lock_child3, di_write_lock_child3, + * di_read_lock_parent, di_write_lock_parent, + * di_read_lock_parent2, di_write_lock_parent2, + * di_read_lock_parent3, di_write_lock_parent3, + */ +#define AuReadLockFunc(name, lsc) \ +static inline void di_read_lock_##name(struct dentry *d, int flags) \ +{ di_read_lock(d, flags, AuLsc_DI_##lsc); } + +#define AuWriteLockFunc(name, lsc) \ +static inline void di_write_lock_##name(struct dentry *d) \ +{ di_write_lock(d, AuLsc_DI_##lsc); } + +#define AuRWLockFuncs(name, lsc) \ + AuReadLockFunc(name, lsc) \ + AuWriteLockFunc(name, lsc) + +AuRWLockFuncs(child, CHILD); +AuRWLockFuncs(child2, CHILD2); +AuRWLockFuncs(child3, CHILD3); +AuRWLockFuncs(parent, PARENT); +AuRWLockFuncs(parent2, PARENT2); +AuRWLockFuncs(parent3, PARENT3); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) +#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) +#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) + +/* ---------------------------------------------------------------------- */ + +/* todo: memory barrier? */ +static inline unsigned int au_digen(struct dentry *d) +{ + return atomic_read(&au_di(d)->di_generation); +} + +static inline void au_h_dentry_init(struct au_hdentry *hdentry) +{ + hdentry->hd_dentry = NULL; +} + +static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, + aufs_bindex_t bindex) +{ + return di->di_hdentry + bindex; +} + +static inline void au_hdput(struct au_hdentry *hd) +{ + if (hd) + dput(hd->hd_dentry); +} + +static inline aufs_bindex_t au_dbtop(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_btop; +} + +static inline aufs_bindex_t au_dbbot(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bbot; +} + +static inline aufs_bindex_t au_dbwh(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bwh; +} + +static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bdiropq; +} + +/* todo: hard/soft set? */ +static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + au_di(dentry)->di_btop = bindex; +} + +static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + au_di(dentry)->di_bbot = bindex; +} + +static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + /* dbwh can be outside of btop - bbot range */ + au_di(dentry)->di_bwh = bindex; +} + +static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + au_di(dentry)->di_bdiropq = bindex; +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_HNOTIFY +static inline void au_digen_dec(struct dentry *d) +{ + atomic_dec(&au_di(d)->di_generation); +} + +static inline void au_hn_di_reinit(struct dentry *dentry) +{ + dentry->d_fsdata = NULL; +} +#else +AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) +#endif /* CONFIG_AUFS_HNOTIFY */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DENTRY_H__ */ diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c new file mode 100644 index 000000000000..86140548f046 --- /dev/null +++ b/fs/aufs/dinfo.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * dentry private data + */ + +#include "aufs.h" + +void au_di_init_once(void *_dinfo) +{ + struct au_dinfo *dinfo = _dinfo; + + au_rw_init(&dinfo->di_rwsem); +} + +struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) +{ + struct au_dinfo *dinfo; + int nbr, i; + + dinfo = au_cache_alloc_dinfo(); + if (unlikely(!dinfo)) + goto out; + + nbr = au_sbbot(sb) + 1; + if (nbr <= 0) + nbr = 1; + dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); + if (dinfo->di_hdentry) { + au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); + dinfo->di_btop = -1; + dinfo->di_bbot = -1; + dinfo->di_bwh = -1; + dinfo->di_bdiropq = -1; + dinfo->di_tmpfile = 0; + for (i = 0; i < nbr; i++) + dinfo->di_hdentry[i].hd_id = -1; + goto out; + } + + au_cache_free_dinfo(dinfo); + dinfo = NULL; + +out: + return dinfo; +} + +void au_di_free(struct au_dinfo *dinfo) +{ + struct au_hdentry *p; + aufs_bindex_t bbot, bindex; + + /* dentry may not be revalidated */ + bindex = dinfo->di_btop; + if (bindex >= 0) { + bbot = dinfo->di_bbot; + p = au_hdentry(dinfo, bindex); + while (bindex++ <= bbot) + au_hdput(p++); + } + au_kfree_try_rcu(dinfo->di_hdentry); + au_cache_free_dinfo(dinfo); +} + +void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) +{ + struct au_hdentry *p; + aufs_bindex_t bi; + + AuRwMustWriteLock(&a->di_rwsem); + AuRwMustWriteLock(&b->di_rwsem); + +#define DiSwap(v, name) \ + do { \ + v = a->di_##name; \ + a->di_##name = b->di_##name; \ + b->di_##name = v; \ + } while (0) + + DiSwap(p, hdentry); + DiSwap(bi, btop); + DiSwap(bi, bbot); + DiSwap(bi, bwh); + DiSwap(bi, bdiropq); + /* smp_mb(); */ + +#undef DiSwap +} + +void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) +{ + AuRwMustWriteLock(&dst->di_rwsem); + AuRwMustWriteLock(&src->di_rwsem); + + dst->di_btop = src->di_btop; + dst->di_bbot = src->di_bbot; + dst->di_bwh = src->di_bwh; + dst->di_bdiropq = src->di_bdiropq; + /* smp_mb(); */ +} + +int au_di_init(struct dentry *dentry) +{ + int err; + struct super_block *sb; + struct au_dinfo *dinfo; + + err = 0; + sb = dentry->d_sb; + dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); + if (dinfo) { + atomic_set(&dinfo->di_generation, au_sigen(sb)); + /* smp_mb(); */ /* atomic_set */ + dentry->d_fsdata = dinfo; + } else + err = -ENOMEM; + + return err; +} + +void au_di_fin(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + + dinfo = au_di(dentry); + AuRwDestroy(&dinfo->di_rwsem); + au_di_free(dinfo); +} + +int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) +{ + int err, sz; + struct au_hdentry *hdp; + + AuRwMustWriteLock(&dinfo->di_rwsem); + + err = -ENOMEM; + sz = sizeof(*hdp) * (dinfo->di_bbot + 1); + if (!sz) + sz = sizeof(*hdp); + hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, + may_shrink); + if (hdp) { + dinfo->di_hdentry = hdp; + err = 0; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void do_ii_write_lock(struct inode *inode, unsigned int lsc) +{ + switch (lsc) { + case AuLsc_DI_CHILD: + ii_write_lock_child(inode); + break; + case AuLsc_DI_CHILD2: + ii_write_lock_child2(inode); + break; + case AuLsc_DI_CHILD3: + ii_write_lock_child3(inode); + break; + case AuLsc_DI_PARENT: + ii_write_lock_parent(inode); + break; + case AuLsc_DI_PARENT2: + ii_write_lock_parent2(inode); + break; + case AuLsc_DI_PARENT3: + ii_write_lock_parent3(inode); + break; + default: + BUG(); + } +} + +static void do_ii_read_lock(struct inode *inode, unsigned int lsc) +{ + switch (lsc) { + case AuLsc_DI_CHILD: + ii_read_lock_child(inode); + break; + case AuLsc_DI_CHILD2: + ii_read_lock_child2(inode); + break; + case AuLsc_DI_CHILD3: + ii_read_lock_child3(inode); + break; + case AuLsc_DI_PARENT: + ii_read_lock_parent(inode); + break; + case AuLsc_DI_PARENT2: + ii_read_lock_parent2(inode); + break; + case AuLsc_DI_PARENT3: + ii_read_lock_parent3(inode); + break; + default: + BUG(); + } +} + +void di_read_lock(struct dentry *d, int flags, unsigned int lsc) +{ + struct inode *inode; + + au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); + if (d_really_is_positive(d)) { + inode = d_inode(d); + if (au_ftest_lock(flags, IW)) + do_ii_write_lock(inode, lsc); + else if (au_ftest_lock(flags, IR)) + do_ii_read_lock(inode, lsc); + } +} + +void di_read_unlock(struct dentry *d, int flags) +{ + struct inode *inode; + + if (d_really_is_positive(d)) { + inode = d_inode(d); + if (au_ftest_lock(flags, IW)) { + au_dbg_verify_dinode(d); + ii_write_unlock(inode); + } else if (au_ftest_lock(flags, IR)) { + au_dbg_verify_dinode(d); + ii_read_unlock(inode); + } + } + au_rw_read_unlock(&au_di(d)->di_rwsem); +} + +void di_downgrade_lock(struct dentry *d, int flags) +{ + if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) + ii_downgrade_lock(d_inode(d)); + au_rw_dgrade_lock(&au_di(d)->di_rwsem); +} + +void di_write_lock(struct dentry *d, unsigned int lsc) +{ + au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); + if (d_really_is_positive(d)) + do_ii_write_lock(d_inode(d), lsc); +} + +void di_write_unlock(struct dentry *d) +{ + au_dbg_verify_dinode(d); + if (d_really_is_positive(d)) + ii_write_unlock(d_inode(d)); + au_rw_write_unlock(&au_di(d)->di_rwsem); +} + +void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) +{ + AuDebugOn(d1 == d2 + || d_inode(d1) == d_inode(d2) + || d1->d_sb != d2->d_sb); + + if ((isdir && au_test_subdir(d1, d2)) + || d1 < d2) { + di_write_lock_child(d1); + di_write_lock_child2(d2); + } else { + di_write_lock_child(d2); + di_write_lock_child2(d1); + } +} + +void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) +{ + AuDebugOn(d1 == d2 + || d_inode(d1) == d_inode(d2) + || d1->d_sb != d2->d_sb); + + if ((isdir && au_test_subdir(d1, d2)) + || d1 < d2) { + di_write_lock_parent(d1); + di_write_lock_parent2(d2); + } else { + di_write_lock_parent(d2); + di_write_lock_parent2(d1); + } +} + +void di_write_unlock2(struct dentry *d1, struct dentry *d2) +{ + di_write_unlock(d1); + if (d_inode(d1) == d_inode(d2)) + au_rw_write_unlock(&au_di(d2)->di_rwsem); + else + di_write_unlock(d2); +} + +/* ---------------------------------------------------------------------- */ + +struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) +{ + struct dentry *d; + + DiMustAnyLock(dentry); + + if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) + return NULL; + AuDebugOn(bindex < 0); + d = au_hdentry(au_di(dentry), bindex)->hd_dentry; + AuDebugOn(d && au_dcount(d) <= 0); + return d; +} + +/* + * extended version of au_h_dptr(). + * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or + * error. + */ +struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) +{ + struct dentry *h_dentry; + struct inode *inode, *h_inode; + + AuDebugOn(d_really_is_negative(dentry)); + + h_dentry = NULL; + if (au_dbtop(dentry) <= bindex + && bindex <= au_dbbot(dentry)) + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && !au_d_linkable(h_dentry)) { + dget(h_dentry); + goto out; /* success */ + } + + inode = d_inode(dentry); + AuDebugOn(bindex < au_ibtop(inode)); + AuDebugOn(au_ibbot(inode) < bindex); + h_inode = au_h_iptr(inode, bindex); + h_dentry = d_find_alias(h_inode); + if (h_dentry) { + if (!IS_ERR(h_dentry)) { + if (!au_d_linkable(h_dentry)) + goto out; /* success */ + dput(h_dentry); + } else + goto out; + } + + if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { + h_dentry = au_plink_lkup(inode, bindex); + AuDebugOn(!h_dentry); + if (!IS_ERR(h_dentry)) { + if (!au_d_hashed_positive(h_dentry)) + goto out; /* success */ + dput(h_dentry); + h_dentry = NULL; + } + } + +out: + AuDbgDentry(h_dentry); + return h_dentry; +} + +aufs_bindex_t au_dbtail(struct dentry *dentry) +{ + aufs_bindex_t bbot, bwh; + + bbot = au_dbbot(dentry); + if (0 <= bbot) { + bwh = au_dbwh(dentry); + if (!bwh) + return bwh; + if (0 < bwh && bwh < bbot) + return bwh - 1; + } + return bbot; +} + +aufs_bindex_t au_dbtaildir(struct dentry *dentry) +{ + aufs_bindex_t bbot, bopq; + + bbot = au_dbtail(dentry); + if (0 <= bbot) { + bopq = au_dbdiropq(dentry); + if (0 <= bopq && bopq < bbot) + bbot = bopq; + } + return bbot; +} + +/* ---------------------------------------------------------------------- */ + +void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_dentry) +{ + struct au_dinfo *dinfo; + struct au_hdentry *hd; + struct au_branch *br; + + DiMustWriteLock(dentry); + + dinfo = au_di(dentry); + hd = au_hdentry(dinfo, bindex); + au_hdput(hd); + hd->hd_dentry = h_dentry; + if (h_dentry) { + br = au_sbr(dentry->d_sb, bindex); + hd->hd_id = br->br_id; + } +} + +int au_dbrange_test(struct dentry *dentry) +{ + int err; + aufs_bindex_t btop, bbot; + + err = 0; + btop = au_dbtop(dentry); + bbot = au_dbbot(dentry); + if (btop >= 0) + AuDebugOn(bbot < 0 && btop > bbot); + else { + err = -EIO; + AuDebugOn(bbot >= 0); + } + + return err; +} + +int au_digen_test(struct dentry *dentry, unsigned int sigen) +{ + int err; + + err = 0; + if (unlikely(au_digen(dentry) != sigen + || au_iigen_test(d_inode(dentry), sigen))) + err = -EIO; + + return err; +} + +void au_update_digen(struct dentry *dentry) +{ + atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); + /* smp_mb(); */ /* atomic_set */ +} + +void au_update_dbrange(struct dentry *dentry, int do_put_zero) +{ + struct au_dinfo *dinfo; + struct dentry *h_d; + struct au_hdentry *hdp; + aufs_bindex_t bindex, bbot; + + DiMustWriteLock(dentry); + + dinfo = au_di(dentry); + if (!dinfo || dinfo->di_btop < 0) + return; + + if (do_put_zero) { + bbot = dinfo->di_bbot; + bindex = dinfo->di_btop; + hdp = au_hdentry(dinfo, bindex); + for (; bindex <= bbot; bindex++, hdp++) { + h_d = hdp->hd_dentry; + if (h_d && d_is_negative(h_d)) + au_set_h_dptr(dentry, bindex, NULL); + } + } + + dinfo->di_btop = 0; + hdp = au_hdentry(dinfo, dinfo->di_btop); + for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) + if (hdp->hd_dentry) + break; + if (dinfo->di_btop > dinfo->di_bbot) { + dinfo->di_btop = -1; + dinfo->di_bbot = -1; + return; + } + + hdp = au_hdentry(dinfo, dinfo->di_bbot); + for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) + if (hdp->hd_dentry) + break; + AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); +} + +void au_update_dbtop(struct dentry *dentry) +{ + aufs_bindex_t bindex, bbot; + struct dentry *h_dentry; + + bbot = au_dbbot(dentry); + for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + if (d_is_positive(h_dentry)) { + au_set_dbtop(dentry, bindex); + return; + } + au_set_h_dptr(dentry, bindex, NULL); + } +} + +void au_update_dbbot(struct dentry *dentry) +{ + aufs_bindex_t bindex, btop; + struct dentry *h_dentry; + + btop = au_dbtop(dentry); + for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + if (d_is_positive(h_dentry)) { + au_set_dbbot(dentry, bindex); + return; + } + au_set_h_dptr(dentry, bindex, NULL); + } +} + +int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) +{ + aufs_bindex_t bindex, bbot; + + bbot = au_dbbot(dentry); + for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) + if (au_h_dptr(dentry, bindex) == h_dentry) + return bindex; + return -1; +} diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c new file mode 100644 index 000000000000..68e87d6f287e --- /dev/null +++ b/fs/aufs/dir.c @@ -0,0 +1,763 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * directory operations + */ + +#include +#include +#include "aufs.h" + +void au_add_nlink(struct inode *dir, struct inode *h_dir) +{ + unsigned int nlink; + + AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); + + nlink = dir->i_nlink; + nlink += h_dir->i_nlink - 2; + if (h_dir->i_nlink < 2) + nlink += 2; + smp_mb(); /* for i_nlink */ + /* 0 can happen in revaliding */ + set_nlink(dir, nlink); +} + +void au_sub_nlink(struct inode *dir, struct inode *h_dir) +{ + unsigned int nlink; + + AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); + + nlink = dir->i_nlink; + nlink -= h_dir->i_nlink - 2; + if (h_dir->i_nlink < 2) + nlink -= 2; + smp_mb(); /* for i_nlink */ + /* nlink == 0 means the branch-fs is broken */ + set_nlink(dir, nlink); +} + +loff_t au_dir_size(struct file *file, struct dentry *dentry) +{ + loff_t sz; + aufs_bindex_t bindex, bbot; + struct file *h_file; + struct dentry *h_dentry; + + sz = 0; + if (file) { + AuDebugOn(!d_is_dir(file->f_path.dentry)); + + bbot = au_fbbot_dir(file); + for (bindex = au_fbtop(file); + bindex <= bbot && sz < KMALLOC_MAX_SIZE; + bindex++) { + h_file = au_hf_dir(file, bindex); + if (h_file && file_inode(h_file)) + sz += vfsub_f_size_read(h_file); + } + } else { + AuDebugOn(!dentry); + AuDebugOn(!d_is_dir(dentry)); + + bbot = au_dbtaildir(dentry); + for (bindex = au_dbtop(dentry); + bindex <= bbot && sz < KMALLOC_MAX_SIZE; + bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && d_is_positive(h_dentry)) + sz += i_size_read(d_inode(h_dentry)); + } + } + if (sz < KMALLOC_MAX_SIZE) + sz = roundup_pow_of_two(sz); + if (sz > KMALLOC_MAX_SIZE) + sz = KMALLOC_MAX_SIZE; + else if (sz < NAME_MAX) { + BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); + sz = AUFS_RDBLK_DEF; + } + return sz; +} + +struct au_dir_ts_arg { + struct dentry *dentry; + aufs_bindex_t brid; +}; + +static void au_do_dir_ts(void *arg) +{ + struct au_dir_ts_arg *a = arg; + struct au_dtime dt; + struct path h_path; + struct inode *dir, *h_dir; + struct super_block *sb; + struct au_branch *br; + struct au_hinode *hdir; + int err; + aufs_bindex_t btop, bindex; + + sb = a->dentry->d_sb; + if (d_really_is_negative(a->dentry)) + goto out; + /* no dir->i_mutex lock */ + aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ + + dir = d_inode(a->dentry); + btop = au_ibtop(dir); + bindex = au_br_index(sb, a->brid); + if (bindex < btop) + goto out_unlock; + + br = au_sbr(sb, bindex); + h_path.dentry = au_h_dptr(a->dentry, bindex); + if (!h_path.dentry) + goto out_unlock; + h_path.mnt = au_br_mnt(br); + au_dtime_store(&dt, a->dentry, &h_path); + + br = au_sbr(sb, btop); + if (!au_br_writable(br->br_perm)) + goto out_unlock; + h_path.dentry = au_h_dptr(a->dentry, btop); + h_path.mnt = au_br_mnt(br); + err = vfsub_mnt_want_write(h_path.mnt); + if (err) + goto out_unlock; + hdir = au_hi(dir, btop); + au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); + h_dir = au_h_iptr(dir, btop); + if (h_dir->i_nlink + && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { + dt.dt_h_path = h_path; + au_dtime_revert(&dt); + } + au_hn_inode_unlock(hdir); + vfsub_mnt_drop_write(h_path.mnt); + au_cpup_attr_timesizes(dir); + +out_unlock: + aufs_read_unlock(a->dentry, AuLock_DW); +out: + dput(a->dentry); + au_nwt_done(&au_sbi(sb)->si_nowait); + au_kfree_try_rcu(arg); +} + +void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) +{ + int perm, wkq_err; + aufs_bindex_t btop; + struct au_dir_ts_arg *arg; + struct dentry *dentry; + struct super_block *sb; + + IMustLock(dir); + + dentry = d_find_any_alias(dir); + AuDebugOn(!dentry); + sb = dentry->d_sb; + btop = au_ibtop(dir); + if (btop == bindex) { + au_cpup_attr_timesizes(dir); + goto out; + } + + perm = au_sbr_perm(sb, btop); + if (!au_br_writable(perm)) + goto out; + + arg = kmalloc(sizeof(*arg), GFP_NOFS); + if (!arg) + goto out; + + arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ + arg->brid = au_sbr_id(sb, bindex); + wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); + if (unlikely(wkq_err)) { + pr_err("wkq %d\n", wkq_err); + dput(dentry); + au_kfree_try_rcu(arg); + } + +out: + dput(dentry); +} + +/* ---------------------------------------------------------------------- */ + +static int reopen_dir(struct file *file) +{ + int err; + unsigned int flags; + aufs_bindex_t bindex, btail, btop; + struct dentry *dentry, *h_dentry; + struct file *h_file; + + /* open all lower dirs */ + dentry = file->f_path.dentry; + btop = au_dbtop(dentry); + for (bindex = au_fbtop(file); bindex < btop; bindex++) + au_set_h_fptr(file, bindex, NULL); + au_set_fbtop(file, btop); + + btail = au_dbtaildir(dentry); + for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) + au_set_h_fptr(file, bindex, NULL); + au_set_fbbot_dir(file, btail); + + flags = vfsub_file_flags(file); + for (bindex = btop; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + h_file = au_hf_dir(file, bindex); + if (h_file) + continue; + + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; /* close all? */ + au_set_h_fptr(file, bindex, h_file); + } + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + err = 0; + +out: + return err; +} + +static int do_open_dir(struct file *file, int flags, struct file *h_file) +{ + int err; + aufs_bindex_t bindex, btail; + struct dentry *dentry, *h_dentry; + struct vfsmount *mnt; + + FiMustWriteLock(file); + AuDebugOn(h_file); + + err = 0; + mnt = file->f_path.mnt; + dentry = file->f_path.dentry; + file->f_version = inode_query_iversion(d_inode(dentry)); + bindex = au_dbtop(dentry); + au_set_fbtop(file, bindex); + btail = au_dbtaildir(dentry); + au_set_fbbot_dir(file, btail); + for (; !err && bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + + err = vfsub_test_mntns(mnt, h_dentry->d_sb); + if (unlikely(err)) + break; + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); + if (IS_ERR(h_file)) { + err = PTR_ERR(h_file); + break; + } + au_set_h_fptr(file, bindex, h_file); + } + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + if (!err) + return 0; /* success */ + + /* close all */ + for (bindex = au_fbtop(file); bindex <= btail; bindex++) + au_set_h_fptr(file, bindex, NULL); + au_set_fbtop(file, -1); + au_set_fbbot_dir(file, -1); + + return err; +} + +static int aufs_open_dir(struct inode *inode __maybe_unused, + struct file *file) +{ + int err; + struct super_block *sb; + struct au_fidir *fidir; + + err = -ENOMEM; + sb = file->f_path.dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + fidir = au_fidir_alloc(sb); + if (fidir) { + struct au_do_open_args args = { + .open = do_open_dir, + .fidir = fidir + }; + err = au_do_open(file, &args); + if (unlikely(err)) + au_kfree_rcu(fidir); + } + si_read_unlock(sb); + return err; +} + +static int aufs_release_dir(struct inode *inode __maybe_unused, + struct file *file) +{ + struct au_vdir *vdir_cache; + struct au_finfo *finfo; + struct au_fidir *fidir; + struct au_hfile *hf; + aufs_bindex_t bindex, bbot; + + finfo = au_fi(file); + fidir = finfo->fi_hdir; + if (fidir) { + au_hbl_del(&finfo->fi_hlist, + &au_sbi(file->f_path.dentry->d_sb)->si_files); + vdir_cache = fidir->fd_vdir_cache; /* lock-free */ + if (vdir_cache) + au_vdir_free(vdir_cache); + + bindex = finfo->fi_btop; + if (bindex >= 0) { + hf = fidir->fd_hfile + bindex; + /* + * calls fput() instead of filp_close(), + * since no dnotify or lock for the lower file. + */ + bbot = fidir->fd_bbot; + for (; bindex <= bbot; bindex++, hf++) + if (hf->hf_file) + au_hfput(hf, /*execed*/0); + } + au_kfree_rcu(fidir); + finfo->fi_hdir = NULL; + } + au_finfo_fin(file); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_flush_dir(struct file *file, fl_owner_t id) +{ + int err; + aufs_bindex_t bindex, bbot; + struct file *h_file; + + err = 0; + bbot = au_fbbot_dir(file); + for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { + h_file = au_hf_dir(file, bindex); + if (h_file) + err = vfsub_flush(h_file, id); + } + return err; +} + +static int aufs_flush_dir(struct file *file, fl_owner_t id) +{ + return au_do_flush(file, id, au_do_flush_dir); +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) +{ + int err; + aufs_bindex_t bbot, bindex; + struct inode *inode; + struct super_block *sb; + + err = 0; + sb = dentry->d_sb; + inode = d_inode(dentry); + IMustLock(inode); + bbot = au_dbbot(dentry); + for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { + struct path h_path; + + if (au_test_ro(sb, bindex, inode)) + continue; + h_path.dentry = au_h_dptr(dentry, bindex); + if (!h_path.dentry) + continue; + + h_path.mnt = au_sbr_mnt(sb, bindex); + err = vfsub_fsync(NULL, &h_path, datasync); + } + + return err; +} + +static int au_do_fsync_dir(struct file *file, int datasync) +{ + int err; + aufs_bindex_t bbot, bindex; + struct file *h_file; + struct super_block *sb; + struct inode *inode; + + err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); + if (unlikely(err)) + goto out; + + inode = file_inode(file); + sb = inode->i_sb; + bbot = au_fbbot_dir(file); + for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { + h_file = au_hf_dir(file, bindex); + if (!h_file || au_test_ro(sb, bindex, inode)) + continue; + + err = vfsub_fsync(h_file, &h_file->f_path, datasync); + } + +out: + return err; +} + +/* + * @file may be NULL + */ +static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, + int datasync) +{ + int err; + struct dentry *dentry; + struct inode *inode; + struct super_block *sb; + + err = 0; + dentry = file->f_path.dentry; + inode = d_inode(dentry); + inode_lock(inode); + sb = dentry->d_sb; + si_noflush_read_lock(sb); + if (file) + err = au_do_fsync_dir(file, datasync); + else { + di_write_lock_child(dentry); + err = au_do_fsync_dir_no_file(dentry, datasync); + } + au_cpup_attr_timesizes(inode); + di_write_unlock(dentry); + if (file) + fi_write_unlock(file); + + si_read_unlock(sb); + inode_unlock(inode); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) +{ + int err; + struct dentry *dentry; + struct inode *inode, *h_inode; + struct super_block *sb; + + AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); + + dentry = file->f_path.dentry; + inode = d_inode(dentry); + IMustLock(inode); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); + if (unlikely(err)) + goto out; + err = au_alive_dir(dentry); + if (!err) + err = au_vdir_init(file); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + + h_inode = au_h_iptr(inode, au_ibtop(inode)); + if (!au_test_nfsd()) { + err = au_vdir_fill_de(file, ctx); + fsstack_copy_attr_atime(inode, h_inode); + } else { + /* + * nfsd filldir may call lookup_one_len(), vfs_getattr(), + * encode_fh() and others. + */ + atomic_inc(&h_inode->i_count); + di_read_unlock(dentry, AuLock_IR); + si_read_unlock(sb); + err = au_vdir_fill_de(file, ctx); + fsstack_copy_attr_atime(inode, h_inode); + fi_write_unlock(file); + iput(h_inode); + + AuTraceErr(err); + return err; + } + +out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +#define AuTestEmpty_WHONLY 1 +#define AuTestEmpty_CALLED (1 << 1) +#define AuTestEmpty_SHWH (1 << 2) +#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) +#define au_fset_testempty(flags, name) \ + do { (flags) |= AuTestEmpty_##name; } while (0) +#define au_fclr_testempty(flags, name) \ + do { (flags) &= ~AuTestEmpty_##name; } while (0) + +#ifndef CONFIG_AUFS_SHWH +#undef AuTestEmpty_SHWH +#define AuTestEmpty_SHWH 0 +#endif + +struct test_empty_arg { + struct dir_context ctx; + struct au_nhash *whlist; + unsigned int flags; + int err; + aufs_bindex_t bindex; +}; + +static int test_empty_cb(struct dir_context *ctx, const char *__name, + int namelen, loff_t offset __maybe_unused, u64 ino, + unsigned int d_type) +{ + struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, + ctx); + char *name = (void *)__name; + + arg->err = 0; + au_fset_testempty(arg->flags, CALLED); + /* smp_mb(); */ + if (name[0] == '.' + && (namelen == 1 || (name[1] == '.' && namelen == 2))) + goto out; /* success */ + + if (namelen <= AUFS_WH_PFX_LEN + || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + if (au_ftest_testempty(arg->flags, WHONLY) + && !au_nhash_test_known_wh(arg->whlist, name, namelen)) + arg->err = -ENOTEMPTY; + goto out; + } + + name += AUFS_WH_PFX_LEN; + namelen -= AUFS_WH_PFX_LEN; + if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) + arg->err = au_nhash_append_wh + (arg->whlist, name, namelen, ino, d_type, arg->bindex, + au_ftest_testempty(arg->flags, SHWH)); + +out: + /* smp_mb(); */ + AuTraceErr(arg->err); + return arg->err; +} + +static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +{ + int err; + struct file *h_file; + struct au_branch *br; + + h_file = au_h_open(dentry, arg->bindex, + O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, + /*file*/NULL, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + err = 0; + if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) + && !file_inode(h_file)->i_nlink) + goto out_put; + + do { + arg->err = 0; + au_fclr_testempty(arg->flags, CALLED); + /* smp_mb(); */ + err = vfsub_iterate_dir(h_file, &arg->ctx); + if (err >= 0) + err = arg->err; + } while (!err && au_ftest_testempty(arg->flags, CALLED)); + +out_put: + fput(h_file); + br = au_sbr(dentry->d_sb, arg->bindex); + au_lcnt_dec(&br->br_nfiles); +out: + return err; +} + +struct do_test_empty_args { + int *errp; + struct dentry *dentry; + struct test_empty_arg *arg; +}; + +static void call_do_test_empty(void *args) +{ + struct do_test_empty_args *a = args; + *a->errp = do_test_empty(a->dentry, a->arg); +} + +static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +{ + int err, wkq_err; + struct dentry *h_dentry; + struct inode *h_inode; + + h_dentry = au_h_dptr(dentry, arg->bindex); + h_inode = d_inode(h_dentry); + /* todo: i_mode changes anytime? */ + inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); + err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); + inode_unlock_shared(h_inode); + if (!err) + err = do_test_empty(dentry, arg); + else { + struct do_test_empty_args args = { + .errp = &err, + .dentry = dentry, + .arg = arg + }; + unsigned int flags = arg->flags; + + wkq_err = au_wkq_wait(call_do_test_empty, &args); + if (unlikely(wkq_err)) + err = wkq_err; + arg->flags = flags; + } + + return err; +} + +int au_test_empty_lower(struct dentry *dentry) +{ + int err; + unsigned int rdhash; + aufs_bindex_t bindex, btop, btail; + struct au_nhash whlist; + struct test_empty_arg arg = { + .ctx = { + .actor = test_empty_cb + } + }; + int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); + + SiMustAnyLock(dentry->d_sb); + + rdhash = au_sbi(dentry->d_sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); + err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + + arg.flags = 0; + arg.whlist = &whlist; + btop = au_dbtop(dentry); + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) + au_fset_testempty(arg.flags, SHWH); + test_empty = do_test_empty; + if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) + test_empty = sio_test_empty; + arg.bindex = btop; + err = test_empty(dentry, &arg); + if (unlikely(err)) + goto out_whlist; + + au_fset_testempty(arg.flags, WHONLY); + btail = au_dbtaildir(dentry); + for (bindex = btop + 1; !err && bindex <= btail; bindex++) { + struct dentry *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && d_is_positive(h_dentry)) { + arg.bindex = bindex; + err = test_empty(dentry, &arg); + } + } + +out_whlist: + au_nhash_wh_free(&whlist); +out: + return err; +} + +int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) +{ + int err; + struct test_empty_arg arg = { + .ctx = { + .actor = test_empty_cb + } + }; + aufs_bindex_t bindex, btail; + + err = 0; + arg.whlist = whlist; + arg.flags = AuTestEmpty_WHONLY; + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) + au_fset_testempty(arg.flags, SHWH); + btail = au_dbtaildir(dentry); + for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { + struct dentry *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && d_is_positive(h_dentry)) { + arg.bindex = bindex; + err = sio_test_empty(dentry, &arg); + } + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +const struct file_operations aufs_dir_fop = { + .owner = THIS_MODULE, + .llseek = default_llseek, + .read = generic_read_dir, + .iterate_shared = aufs_iterate_shared, + .unlocked_ioctl = aufs_ioctl_dir, +#ifdef CONFIG_COMPAT + .compat_ioctl = aufs_compat_ioctl_dir, +#endif + .open = aufs_open_dir, + .release = aufs_release_dir, + .flush = aufs_flush_dir, + .fsync = aufs_fsync_dir +}; diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h new file mode 100644 index 000000000000..a23b3818f065 --- /dev/null +++ b/fs/aufs/dir.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * directory operations + */ + +#ifndef __AUFS_DIR_H__ +#define __AUFS_DIR_H__ + +#ifdef __KERNEL__ + +#include + +/* ---------------------------------------------------------------------- */ + +/* need to be faster and smaller */ + +struct au_nhash { + unsigned int nh_num; + struct hlist_head *nh_head; +}; + +struct au_vdir_destr { + unsigned char len; + unsigned char name[]; +} __packed; + +struct au_vdir_dehstr { + struct hlist_node hash; + struct au_vdir_destr *str; + struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +struct au_vdir_de { + ino_t de_ino; + unsigned char de_type; + /* caution: packed */ + struct au_vdir_destr de_str; +} __packed; + +struct au_vdir_wh { + struct hlist_node wh_hash; +#ifdef CONFIG_AUFS_SHWH + ino_t wh_ino; + aufs_bindex_t wh_bindex; + unsigned char wh_type; +#else + aufs_bindex_t wh_bindex; +#endif + /* caution: packed */ + struct au_vdir_destr wh_str; +} __packed; + +union au_vdir_deblk_p { + unsigned char *deblk; + struct au_vdir_de *de; +}; + +struct au_vdir { + unsigned char **vd_deblk; + unsigned long vd_nblk; + struct { + unsigned long ul; + union au_vdir_deblk_p p; + } vd_last; + + u64 vd_version; + unsigned int vd_deblk_sz; + unsigned long vd_jiffy; + struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ + +/* dir.c */ +extern const struct file_operations aufs_dir_fop; +void au_add_nlink(struct inode *dir, struct inode *h_dir); +void au_sub_nlink(struct inode *dir, struct inode *h_dir); +loff_t au_dir_size(struct file *file, struct dentry *dentry); +void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); +int au_test_empty_lower(struct dentry *dentry); +int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); + +/* vdir.c */ +unsigned int au_rdhash_est(loff_t sz); +int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); +void au_nhash_wh_free(struct au_nhash *whlist); +int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, + int limit); +int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); +int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, + unsigned int d_type, aufs_bindex_t bindex, + unsigned char shwh); +void au_vdir_free(struct au_vdir *vdir); +int au_vdir_init(struct file *file); +int au_vdir_fill_de(struct file *file, struct dir_context *ctx); + +/* ioctl.c */ +long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); + +#ifdef CONFIG_AUFS_RDU +/* rdu.c */ +long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +#endif +#else +AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, + unsigned int cmd, unsigned long arg) +#ifdef CONFIG_COMPAT +AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, + unsigned int cmd, unsigned long arg) +#endif +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIR_H__ */ diff --git a/fs/aufs/dirren.c b/fs/aufs/dirren.c new file mode 100644 index 000000000000..2e4f423003a1 --- /dev/null +++ b/fs/aufs/dirren.c @@ -0,0 +1,1316 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * special handling in renaming a directory + * in order to support looking-up the before-renamed name on the lower readonly + * branches + */ + +#include +#include "aufs.h" + +static void au_dr_hino_del(struct au_dr_br *dr, struct au_dr_hino *ent) +{ + int idx; + + idx = au_dr_ihash(ent->dr_h_ino); + au_hbl_del(&ent->dr_hnode, dr->dr_h_ino + idx); +} + +static int au_dr_hino_test_empty(struct au_dr_br *dr) +{ + int ret, i; + struct hlist_bl_head *hbl; + + ret = 1; + for (i = 0; ret && i < AuDirren_NHASH; i++) { + hbl = dr->dr_h_ino + i; + hlist_bl_lock(hbl); + ret &= hlist_bl_empty(hbl); + hlist_bl_unlock(hbl); + } + + return ret; +} + +static struct au_dr_hino *au_dr_hino_find(struct au_dr_br *dr, ino_t ino) +{ + struct au_dr_hino *found, *ent; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + int idx; + + found = NULL; + idx = au_dr_ihash(ino); + hbl = dr->dr_h_ino + idx; + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) + if (ent->dr_h_ino == ino) { + found = ent; + break; + } + hlist_bl_unlock(hbl); + + return found; +} + +int au_dr_hino_test_add(struct au_dr_br *dr, ino_t ino, + struct au_dr_hino *add_ent) +{ + int found, idx; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + struct au_dr_hino *ent; + + found = 0; + idx = au_dr_ihash(ino); + hbl = dr->dr_h_ino + idx; +#if 0 /* debug print */ + { + struct hlist_bl_node *tmp; + + hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) + AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); + } +#endif + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) + if (ent->dr_h_ino == ino) { + found = 1; + break; + } + if (!found && add_ent) + hlist_bl_add_head(&add_ent->dr_hnode, hbl); + hlist_bl_unlock(hbl); + + if (!found && add_ent) + AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); + + return found; +} + +void au_dr_hino_free(struct au_dr_br *dr) +{ + int i; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos, *tmp; + struct au_dr_hino *ent; + + /* SiMustWriteLock(sb); */ + + for (i = 0; i < AuDirren_NHASH; i++) { + hbl = dr->dr_h_ino + i; + /* no spinlock since sbinfo must be write-locked */ + hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) + au_kfree_rcu(ent); + INIT_HLIST_BL_HEAD(hbl); + } +} + +/* returns the number of inodes or an error */ +static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, + struct file *hinofile) +{ + int err, i; + ssize_t ssz; + loff_t pos, oldsize; + __be64 u64; + struct inode *hinoinode; + struct hlist_bl_head *hbl; + struct hlist_bl_node *n1, *n2; + struct au_dr_hino *ent; + + SiMustWriteLock(sb); + AuDebugOn(!au_br_writable(br->br_perm)); + + hinoinode = file_inode(hinofile); + oldsize = i_size_read(hinoinode); + + err = 0; + pos = 0; + hbl = br->br_dirren.dr_h_ino; + for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { + /* no bit-lock since sbinfo must be write-locked */ + hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { + AuDbg("hi%llu, %pD2\n", + (unsigned long long)ent->dr_h_ino, hinofile); + u64 = cpu_to_be64(ent->dr_h_ino); + ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); + if (ssz == sizeof(u64)) + continue; + + /* write error */ + pr_err("ssz %zd, %pD2\n", ssz, hinofile); + err = -ENOSPC; + if (ssz < 0) + err = ssz; + break; + } + } + /* regardless the error */ + if (pos < oldsize) { + err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); + AuTraceErr(err); + } + + AuTraceErr(err); + return err; +} + +static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) +{ + int err, hidx; + ssize_t ssz; + size_t sz, n; + loff_t pos; + uint64_t u64; + struct au_dr_hino *ent; + struct inode *hinoinode; + struct hlist_bl_head *hbl; + + err = 0; + pos = 0; + hbl = dr->dr_h_ino; + hinoinode = file_inode(hinofile); + sz = i_size_read(hinoinode); + AuDebugOn(sz % sizeof(u64)); + n = sz / sizeof(u64); + while (n--) { + ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); + if (unlikely(ssz != sizeof(u64))) { + pr_err("ssz %zd, %pD2\n", ssz, hinofile); + err = -EINVAL; + if (ssz < 0) + err = ssz; + goto out_free; + } + + ent = kmalloc(sizeof(*ent), GFP_NOFS); + if (!ent) { + err = -ENOMEM; + AuTraceErr(err); + goto out_free; + } + ent->dr_h_ino = be64_to_cpu((__force __be64)u64); + AuDbg("hi%llu, %pD2\n", + (unsigned long long)ent->dr_h_ino, hinofile); + hidx = au_dr_ihash(ent->dr_h_ino); + au_hbl_add(&ent->dr_hnode, hbl + hidx); + } + goto out; /* success */ + +out_free: + au_dr_hino_free(dr); +out: + AuTraceErr(err); + return err; +} + +/* + * @bindex/@br is a switch to distinguish whether suspending hnotify or not. + * @path is a switch to distinguish load and store. + */ +static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, + struct au_branch *br, const struct path *path) +{ + int err, flags; + unsigned char load, suspend; + struct file *hinofile; + struct au_hinode *hdir; + struct inode *dir, *delegated; + struct path hinopath; + struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, + sizeof(AUFS_WH_DR_BRHINO) - 1); + + AuDebugOn(bindex < 0 && !br); + AuDebugOn(bindex >= 0 && br); + + err = -EINVAL; + suspend = !br; + if (suspend) + br = au_sbr(sb, bindex); + load = !!path; + if (!load) { + path = &br->br_path; + AuDebugOn(!au_br_writable(br->br_perm)); + if (unlikely(!au_br_writable(br->br_perm))) + goto out; + } + + hdir = NULL; + if (suspend) { + dir = d_inode(sb->s_root); + hdir = au_hinode(au_ii(dir), bindex); + dir = hdir->hi_inode; + au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); + } else { + dir = d_inode(path->dentry); + inode_lock_nested(dir, AuLsc_I_CHILD); + } + hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry); + err = PTR_ERR(hinopath.dentry); + if (IS_ERR(hinopath.dentry)) + goto out_unlock; + + err = 0; + flags = O_RDONLY; + if (load) { + if (d_is_negative(hinopath.dentry)) + goto out_dput; /* success */ + } else { + if (au_dr_hino_test_empty(&br->br_dirren)) { + if (d_is_positive(hinopath.dentry)) { + delegated = NULL; + err = vfsub_unlink(dir, &hinopath, &delegated, + /*force*/0); + AuTraceErr(err); + if (unlikely(err)) + pr_err("ignored err %d, %pd2\n", + err, hinopath.dentry); + if (unlikely(err == -EWOULDBLOCK)) + iput(delegated); + err = 0; + } + goto out_dput; + } else if (!d_is_positive(hinopath.dentry)) { + err = vfsub_create(dir, &hinopath, 0600, + /*want_excl*/false); + AuTraceErr(err); + if (unlikely(err)) + goto out_dput; + } + flags = O_WRONLY; + } + hinopath.mnt = path->mnt; + hinofile = vfsub_dentry_open(&hinopath, flags); + if (suspend) + au_hn_inode_unlock(hdir); + else + inode_unlock(dir); + dput(hinopath.dentry); + AuTraceErrPtr(hinofile); + if (IS_ERR(hinofile)) { + err = PTR_ERR(hinofile); + goto out; + } + + if (load) + err = au_dr_hino_load(&br->br_dirren, hinofile); + else + err = au_dr_hino_store(sb, br, hinofile); + fput(hinofile); + goto out; + +out_dput: + dput(hinopath.dentry); +out_unlock: + if (suspend) + au_hn_inode_unlock(hdir); + else + inode_unlock(dir); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) +{ + int err; + struct kstatfs kstfs; + dev_t dev; + struct dentry *dentry; + struct super_block *sb; + + err = vfs_statfs((void *)path, &kstfs); + AuTraceErr(err); + if (unlikely(err)) + goto out; + + /* todo: support for UUID */ + + if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { + brid->type = AuBrid_FSID; + brid->fsid = kstfs.f_fsid; + } else { + dentry = path->dentry; + sb = dentry->d_sb; + dev = sb->s_dev; + if (dev) { + brid->type = AuBrid_DEV; + brid->dev = dev; + } + } + +out: + return err; +} + +int au_dr_br_init(struct super_block *sb, struct au_branch *br, + const struct path *path) +{ + int err, i; + struct au_dr_br *dr; + struct hlist_bl_head *hbl; + + dr = &br->br_dirren; + hbl = dr->dr_h_ino; + for (i = 0; i < AuDirren_NHASH; i++, hbl++) + INIT_HLIST_BL_HEAD(hbl); + + err = au_dr_brid_init(&dr->dr_brid, path); + if (unlikely(err)) + goto out; + + if (au_opt_test(au_mntflags(sb), DIRREN)) + err = au_dr_hino(sb, /*bindex*/-1, br, path); + +out: + AuTraceErr(err); + return err; +} + +int au_dr_br_fin(struct super_block *sb, struct au_branch *br) +{ + int err; + + err = 0; + if (au_br_writable(br->br_perm)) + err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); + if (!err) + au_dr_hino_free(&br->br_dirren); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, + char *buf, size_t sz) +{ + int err; + unsigned int major, minor; + char *p; + + p = buf; + err = snprintf(p, sz, "%d_", brid->type); + AuDebugOn(err > sz); + p += err; + sz -= err; + switch (brid->type) { + case AuBrid_Unset: + return -EINVAL; + case AuBrid_UUID: + err = snprintf(p, sz, "%pU", brid->uuid.b); + break; + case AuBrid_FSID: + err = snprintf(p, sz, "%08x-%08x", + brid->fsid.val[0], brid->fsid.val[1]); + break; + case AuBrid_DEV: + major = MAJOR(brid->dev); + minor = MINOR(brid->dev); + if (major <= 0xff && minor <= 0xff) + err = snprintf(p, sz, "%02x%02x", major, minor); + else + err = snprintf(p, sz, "%03x:%05x", major, minor); + break; + } + AuDebugOn(err > sz); + p += err; + sz -= err; + err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); + AuDebugOn(err > sz); + p += err; + sz -= err; + + return p - buf; +} + +static int au_drinfo_name(struct au_branch *br, char *name, int len) +{ + int rlen; + struct dentry *br_dentry; + struct inode *br_inode; + + br_dentry = au_br_dentry(br); + br_inode = d_inode(br_dentry); + rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); + AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); + AuDebugOn(rlen > len); + + return rlen; +} + +/* ---------------------------------------------------------------------- */ + +/* + * from the given @h_dentry, construct drinfo at @*fdata. + * when the size of @*fdata is not enough, reallocate and return new @fdata and + * @allocated. + */ +static int au_drinfo_construct(struct au_drinfo_fdata **fdata, + struct dentry *h_dentry, + unsigned char *allocated) +{ + int err, v; + struct au_drinfo_fdata *f, *p; + struct au_drinfo *drinfo; + struct inode *h_inode; + struct qstr *qname; + + err = 0; + f = *fdata; + h_inode = d_inode(h_dentry); + qname = &h_dentry->d_name; + drinfo = &f->drinfo; + drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); + drinfo->oldnamelen = qname->len; + if (*allocated < sizeof(*f) + qname->len) { + v = roundup_pow_of_two(*allocated + qname->len); + p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); + if (unlikely(!p)) { + err = -ENOMEM; + AuTraceErr(err); + goto out; + } + f = p; + *fdata = f; + *allocated = v; + drinfo = &f->drinfo; + } + memcpy(drinfo->oldname, qname->name, qname->len); + AuDbg("i%llu, %.*s\n", + be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, + drinfo->oldname); + +out: + AuTraceErr(err); + return err; +} + +/* callers have to free the return value */ +static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) +{ + struct au_drinfo *ret, *drinfo; + struct au_drinfo_fdata fdata; + int len; + loff_t pos; + ssize_t ssz; + + ret = ERR_PTR(-EIO); + pos = 0; + ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); + if (unlikely(ssz != sizeof(fdata))) { + AuIOErr("ssz %zd, %u, %pD2\n", + ssz, (unsigned int)sizeof(fdata), file); + goto out; + } + + fdata.magic = ntohl((__force __be32)fdata.magic); + switch (fdata.magic) { + case AUFS_DRINFO_MAGIC_V1: + break; + default: + AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", + fdata.magic, AUFS_DRINFO_MAGIC_V1, file); + goto out; + } + + drinfo = &fdata.drinfo; + len = drinfo->oldnamelen; + if (!len) { + AuIOErr("broken drinfo %pD2\n", file); + goto out; + } + + ret = NULL; + drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); + if (unlikely(h_ino && drinfo->ino != h_ino)) { + AuDbg("ignored i%llu, i%llu, %pD2\n", + (unsigned long long)drinfo->ino, + (unsigned long long)h_ino, file); + goto out; /* success */ + } + + ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); + if (unlikely(!ret)) { + ret = ERR_PTR(-ENOMEM); + AuTraceErrPtr(ret); + goto out; + } + + *ret = *drinfo; + ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); + if (unlikely(ssz != len)) { + au_kfree_rcu(ret); + ret = ERR_PTR(-EIO); + AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); + goto out; + } + + AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); + +out: + return ret; +} + +/* ---------------------------------------------------------------------- */ + +/* in order to be revertible */ +struct au_drinfo_rev_elm { + int created; + struct dentry *info_dentry; + struct au_drinfo *info_last; +}; + +struct au_drinfo_rev { + unsigned char already; + aufs_bindex_t nelm; + struct au_drinfo_rev_elm elm[]; +}; + +/* todo: isn't it too large? */ +struct au_drinfo_store { + struct path h_ppath; + struct dentry *h_dentry; + struct au_drinfo_fdata *fdata; + char *infoname; /* inside of whname, just after PFX */ + char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; + aufs_bindex_t btgt, btail; + unsigned char no_sio, + allocated, /* current size of *fdata */ + infonamelen, /* room size for p */ + whnamelen, /* length of the generated name */ + renameback; /* renamed back */ +}; + +/* on rename(2) error, the caller should revert it using @elm */ +static int au_drinfo_do_store(struct au_drinfo_store *w, + struct au_drinfo_rev_elm *elm) +{ + int err, len; + ssize_t ssz; + loff_t pos; + struct path infopath = { + .mnt = w->h_ppath.mnt + }; + struct inode *h_dir, *h_inode, *delegated; + struct file *infofile; + struct qstr *qname; + + AuDebugOn(elm + && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); + + infopath.dentry = vfsub_lookup_one_len(w->whname, w->h_ppath.dentry, + w->whnamelen); + AuTraceErrPtr(infopath.dentry); + if (IS_ERR(infopath.dentry)) { + err = PTR_ERR(infopath.dentry); + goto out; + } + + err = 0; + h_dir = d_inode(w->h_ppath.dentry); + if (elm && d_is_negative(infopath.dentry)) { + err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); + AuTraceErr(err); + if (unlikely(err)) + goto out_dput; + elm->created = 1; + elm->info_dentry = dget(infopath.dentry); + } + + infofile = vfsub_dentry_open(&infopath, O_RDWR); + AuTraceErrPtr(infofile); + if (IS_ERR(infofile)) { + err = PTR_ERR(infofile); + goto out_dput; + } + + h_inode = d_inode(infopath.dentry); + if (elm && i_size_read(h_inode)) { + h_inode = d_inode(w->h_dentry); + elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); + AuTraceErrPtr(elm->info_last); + if (IS_ERR(elm->info_last)) { + err = PTR_ERR(elm->info_last); + elm->info_last = NULL; + AuDebugOn(elm->info_dentry); + goto out_fput; + } + } + + if (elm && w->renameback) { + delegated = NULL; + err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); + AuTraceErr(err); + if (unlikely(err == -EWOULDBLOCK)) + iput(delegated); + goto out_fput; + } + + pos = 0; + qname = &w->h_dentry->d_name; + len = sizeof(*w->fdata) + qname->len; + if (!elm) + len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; + ssz = vfsub_write_k(infofile, w->fdata, len, &pos); + if (ssz == len) { + AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, + w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); + goto out_fput; /* success */ + } else { + err = -EIO; + if (ssz < 0) + err = ssz; + /* the caller should revert it using @elm */ + } + +out_fput: + fput(infofile); +out_dput: + dput(infopath.dentry); +out: + AuTraceErr(err); + return err; +} + +struct au_call_drinfo_do_store_args { + int *errp; + struct au_drinfo_store *w; + struct au_drinfo_rev_elm *elm; +}; + +static void au_call_drinfo_do_store(void *args) +{ + struct au_call_drinfo_do_store_args *a = args; + + *a->errp = au_drinfo_do_store(a->w, a->elm); +} + +static int au_drinfo_store_sio(struct au_drinfo_store *w, + struct au_drinfo_rev_elm *elm) +{ + int err, wkq_err; + + if (w->no_sio) + err = au_drinfo_do_store(w, elm); + else { + struct au_call_drinfo_do_store_args a = { + .errp = &err, + .w = w, + .elm = elm + }; + wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); + if (unlikely(wkq_err)) + err = wkq_err; + } + AuTraceErr(err); + + return err; +} + +static int au_drinfo_store_work_init(struct au_drinfo_store *w, + aufs_bindex_t btgt) +{ + int err; + + memset(w, 0, sizeof(*w)); + w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); + strcpy(w->whname, AUFS_WH_DR_INFO_PFX); + w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; + w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); + w->btgt = btgt; + w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); + + err = -ENOMEM; + w->fdata = kcalloc(1, w->allocated, GFP_NOFS); + if (unlikely(!w->fdata)) { + AuTraceErr(err); + goto out; + } + w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); + err = 0; + +out: + return err; +} + +static void au_drinfo_store_work_fin(struct au_drinfo_store *w) +{ + au_kfree_rcu(w->fdata); +} + +static void au_drinfo_store_rev(struct au_drinfo_rev *rev, + struct au_drinfo_store *w) +{ + struct au_drinfo_rev_elm *elm; + struct inode *h_dir, *delegated; + int err, nelm; + struct path infopath = { + .mnt = w->h_ppath.mnt + }; + + h_dir = d_inode(w->h_ppath.dentry); + IMustLock(h_dir); + + err = 0; + elm = rev->elm; + for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { + AuDebugOn(elm->created && elm->info_last); + if (elm->created) { + AuDbg("here\n"); + delegated = NULL; + infopath.dentry = elm->info_dentry; + err = vfsub_unlink(h_dir, &infopath, &delegated, + !w->no_sio); + AuTraceErr(err); + if (unlikely(err == -EWOULDBLOCK)) + iput(delegated); + dput(elm->info_dentry); + } else if (elm->info_last) { + AuDbg("here\n"); + w->fdata->drinfo = *elm->info_last; + memcpy(w->fdata->drinfo.oldname, + elm->info_last->oldname, + elm->info_last->oldnamelen); + err = au_drinfo_store_sio(w, /*elm*/NULL); + au_kfree_rcu(elm->info_last); + } + if (unlikely(err)) + AuIOErr("%d, %s\n", err, w->whname); + /* go on even if err */ + } +} + +/* caller has to call au_dr_rename_fin() later */ +static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, + struct qstr *dst_name, void *_rev) +{ + int err, sz, nelm; + aufs_bindex_t bindex, btail; + struct au_drinfo_store work; + struct au_drinfo_rev *rev, **p; + struct au_drinfo_rev_elm *elm; + struct super_block *sb; + struct au_branch *br; + struct au_hinode *hdir; + + err = au_drinfo_store_work_init(&work, btgt); + AuTraceErr(err); + if (unlikely(err)) + goto out; + + err = -ENOMEM; + btail = au_dbtaildir(dentry); + nelm = btail - btgt; + sz = sizeof(*rev) + sizeof(*elm) * nelm; + rev = kcalloc(1, sz, GFP_NOFS); + if (unlikely(!rev)) { + AuTraceErr(err); + goto out_args; + } + rev->nelm = nelm; + elm = rev->elm; + p = _rev; + *p = rev; + + err = 0; + sb = dentry->d_sb; + work.h_ppath.dentry = au_h_dptr(dentry, btgt); + work.h_ppath.mnt = au_sbr_mnt(sb, btgt); + hdir = au_hi(d_inode(dentry), btgt); + au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); + for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { + work.h_dentry = au_h_dptr(dentry, bindex); + if (!work.h_dentry) + continue; + + err = au_drinfo_construct(&work.fdata, work.h_dentry, + &work.allocated); + AuTraceErr(err); + if (unlikely(err)) + break; + + work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); + br = au_sbr(sb, bindex); + work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; + work.whnamelen += au_drinfo_name(br, work.infoname, + work.infonamelen); + AuDbg("whname %.*s, i%llu, %.*s\n", + work.whnamelen, work.whname, + be64_to_cpu((__force __be64)work.fdata->drinfo.ino), + work.fdata->drinfo.oldnamelen, + work.fdata->drinfo.oldname); + + err = au_drinfo_store_sio(&work, elm); + AuTraceErr(err); + if (unlikely(err)) + break; + } + if (unlikely(err)) { + /* revert all drinfo */ + au_drinfo_store_rev(rev, &work); + au_kfree_try_rcu(rev); + *p = NULL; + } + au_hn_inode_unlock(hdir); + +out_args: + au_drinfo_store_work_fin(&work); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, + struct qstr *dst_name, void *_rev) +{ + int err, already; + ino_t ino; + struct super_block *sb; + struct au_branch *br; + struct au_dr_br *dr; + struct dentry *h_dentry; + struct inode *h_inode; + struct au_dr_hino *ent; + struct au_drinfo_rev *rev, **p; + + AuDbg("bindex %d\n", bindex); + + err = -ENOMEM; + ent = kmalloc(sizeof(*ent), GFP_NOFS); + if (unlikely(!ent)) + goto out; + + sb = src->d_sb; + br = au_sbr(sb, bindex); + dr = &br->br_dirren; + h_dentry = au_h_dptr(src, bindex); + h_inode = d_inode(h_dentry); + ino = h_inode->i_ino; + ent->dr_h_ino = ino; + already = au_dr_hino_test_add(dr, ino, ent); + AuDbg("b%d, hi%llu, already %d\n", + bindex, (unsigned long long)ino, already); + + err = au_drinfo_store(src, bindex, dst_name, _rev); + AuTraceErr(err); + if (!err) { + p = _rev; + rev = *p; + rev->already = already; + goto out; /* success */ + } + + /* revert */ + if (!already) + au_dr_hino_del(dr, ent); + au_kfree_rcu(ent); + +out: + AuTraceErr(err); + return err; +} + +void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) +{ + struct au_drinfo_rev *rev; + struct au_drinfo_rev_elm *elm; + int nelm; + + rev = _rev; + elm = rev->elm; + for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { + dput(elm->info_dentry); + au_kfree_rcu(elm->info_last); + } + au_kfree_try_rcu(rev); +} + +void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) +{ + int err; + struct au_drinfo_store work; + struct au_drinfo_rev *rev = _rev; + struct super_block *sb; + struct au_branch *br; + struct inode *h_inode; + struct au_dr_br *dr; + struct au_dr_hino *ent; + + err = au_drinfo_store_work_init(&work, btgt); + if (unlikely(err)) + goto out; + + sb = src->d_sb; + br = au_sbr(sb, btgt); + work.h_ppath.dentry = au_h_dptr(src, btgt); + work.h_ppath.mnt = au_br_mnt(br); + au_drinfo_store_rev(rev, &work); + au_drinfo_store_work_fin(&work); + if (rev->already) + goto out; + + dr = &br->br_dirren; + h_inode = d_inode(work.h_ppath.dentry); + ent = au_dr_hino_find(dr, h_inode->i_ino); + BUG_ON(!ent); + au_dr_hino_del(dr, ent); + au_kfree_rcu(ent); + +out: + au_kfree_try_rcu(rev); + if (unlikely(err)) + pr_err("failed to remove dirren info\n"); +} + +/* ---------------------------------------------------------------------- */ + +static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, + char *whname, int whnamelen, + struct dentry **info_dentry) +{ + struct au_drinfo *drinfo; + struct file *f; + struct inode *h_dir; + struct path infopath; + int unlocked; + + AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); + + *info_dentry = NULL; + drinfo = NULL; + unlocked = 0; + h_dir = d_inode(h_ppath->dentry); + inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); + infopath.dentry = vfsub_lookup_one_len(whname, h_ppath->dentry, + whnamelen); + if (IS_ERR(infopath.dentry)) { + drinfo = (void *)infopath.dentry; + goto out; + } + + if (d_is_negative(infopath.dentry)) + goto out_dput; /* success */ + + infopath.mnt = h_ppath->mnt; + f = vfsub_dentry_open(&infopath, O_RDONLY); + inode_unlock_shared(h_dir); + unlocked = 1; + if (IS_ERR(f)) { + drinfo = (void *)f; + goto out_dput; + } + + drinfo = au_drinfo_read_k(f, /*h_ino*/0); + if (IS_ERR_OR_NULL(drinfo)) + goto out_fput; + + AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); + *info_dentry = dget(infopath.dentry); /* keep it alive */ + +out_fput: + fput(f); +out_dput: + dput(infopath.dentry); +out: + if (!unlocked) + inode_unlock_shared(h_dir); + AuTraceErrPtr(drinfo); + return drinfo; +} + +struct au_drinfo_do_load_args { + struct au_drinfo **drinfop; + struct path *h_ppath; + char *whname; + int whnamelen; + struct dentry **info_dentry; +}; + +static void au_call_drinfo_do_load(void *args) +{ + struct au_drinfo_do_load_args *a = args; + + *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, + a->info_dentry); +} + +struct au_drinfo_load { + struct path h_ppath; + struct qstr *qname; + unsigned char no_sio; + + aufs_bindex_t ninfo; + struct au_drinfo **drinfo; +}; + +static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, + struct au_branch *br) +{ + int err, wkq_err, whnamelen, e; + char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] + = AUFS_WH_DR_INFO_PFX; + struct au_drinfo *drinfo; + struct qstr oldname; + struct inode *h_dir, *delegated; + struct dentry *info_dentry; + struct path infopath; + + whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; + whnamelen += au_drinfo_name(br, whname + whnamelen, + sizeof(whname) - whnamelen); + if (w->no_sio) + drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, + &info_dentry); + else { + struct au_drinfo_do_load_args args = { + .drinfop = &drinfo, + .h_ppath = &w->h_ppath, + .whname = whname, + .whnamelen = whnamelen, + .info_dentry = &info_dentry + }; + wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); + if (unlikely(wkq_err)) + drinfo = ERR_PTR(wkq_err); + } + err = PTR_ERR(drinfo); + if (IS_ERR_OR_NULL(drinfo)) + goto out; + + err = 0; + oldname.len = drinfo->oldnamelen; + oldname.name = drinfo->oldname; + if (au_qstreq(w->qname, &oldname)) { + /* the name is renamed back */ + au_kfree_rcu(drinfo); + drinfo = NULL; + + infopath.dentry = info_dentry; + infopath.mnt = w->h_ppath.mnt; + h_dir = d_inode(w->h_ppath.dentry); + delegated = NULL; + inode_lock_nested(h_dir, AuLsc_I_PARENT); + e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); + inode_unlock(h_dir); + if (unlikely(e)) + AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); + if (unlikely(e == -EWOULDBLOCK)) + iput(delegated); + } + au_kfree_rcu(w->drinfo[bindex]); + w->drinfo[bindex] = drinfo; + dput(info_dentry); + +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) +{ + struct au_drinfo **p = drinfo; + + while (n-- > 0) + au_kfree_rcu(*drinfo++); + au_kfree_try_rcu(p); +} + +int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, + aufs_bindex_t btgt) +{ + int err, ninfo; + struct au_drinfo_load w; + aufs_bindex_t bindex, bbot; + struct au_branch *br; + struct inode *h_dir; + struct au_dr_hino *ent; + struct super_block *sb; + + AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", + AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), + AuLNPair(&lkup->whname), btgt); + + sb = dentry->d_sb; + bbot = au_sbbot(sb); + w.ninfo = bbot + 1; + if (!lkup->dirren.drinfo) { + lkup->dirren.drinfo = kcalloc(w.ninfo, + sizeof(*lkup->dirren.drinfo), + GFP_NOFS); + if (unlikely(!lkup->dirren.drinfo)) { + err = -ENOMEM; + goto out; + } + lkup->dirren.ninfo = w.ninfo; + } + w.drinfo = lkup->dirren.drinfo; + w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); + w.h_ppath.dentry = au_h_dptr(dentry, btgt); + AuDebugOn(!w.h_ppath.dentry); + w.h_ppath.mnt = au_sbr_mnt(sb, btgt); + w.qname = &dentry->d_name; + + ninfo = 0; + for (bindex = btgt + 1; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + err = au_drinfo_load(&w, bindex, br); + if (unlikely(err)) + goto out_free; + if (w.drinfo[bindex]) + ninfo++; + } + if (!ninfo) { + br = au_sbr(sb, btgt); + h_dir = d_inode(w.h_ppath.dentry); + ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); + AuDebugOn(!ent); + au_dr_hino_del(&br->br_dirren, ent); + au_kfree_rcu(ent); + } + goto out; /* success */ + +out_free: + au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); + lkup->dirren.ninfo = 0; + lkup->dirren.drinfo = NULL; +out: + AuTraceErr(err); + return err; +} + +void au_dr_lkup_fin(struct au_do_lookup_args *lkup) +{ + au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); +} + +int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) +{ + int err; + struct au_drinfo *drinfo; + + err = 0; + if (!lkup->dirren.drinfo) + goto out; + AuDebugOn(lkup->dirren.ninfo <= btgt); + drinfo = lkup->dirren.drinfo[btgt]; + if (!drinfo) + goto out; + + au_kfree_try_rcu(lkup->whname.name); + lkup->whname.name = NULL; + lkup->dirren.dr_name.len = drinfo->oldnamelen; + lkup->dirren.dr_name.name = drinfo->oldname; + lkup->name = &lkup->dirren.dr_name; + err = au_wh_name_alloc(&lkup->whname, lkup->name); + if (!err) + AuDbg("name %.*s, whname %.*s, b%d\n", + AuLNPair(lkup->name), AuLNPair(&lkup->whname), + btgt); + +out: + AuTraceErr(err); + return err; +} + +int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, + ino_t h_ino) +{ + int match; + struct au_drinfo *drinfo; + + match = 1; + if (!lkup->dirren.drinfo) + goto out; + AuDebugOn(lkup->dirren.ninfo <= bindex); + drinfo = lkup->dirren.drinfo[bindex]; + if (!drinfo) + goto out; + + match = (drinfo->ino == h_ino); + AuDbg("match %d\n", match); + +out: + return match; +} + +/* ---------------------------------------------------------------------- */ + +int au_dr_opt_set(struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bbot; + struct au_branch *br; + + err = 0; + bbot = au_sbbot(sb); + for (bindex = 0; !err && bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + err = au_dr_hino(sb, bindex, /*br*/NULL, &br->br_path); + } + + return err; +} + +int au_dr_opt_flush(struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bbot; + struct au_branch *br; + + err = 0; + bbot = au_sbbot(sb); + for (bindex = 0; !err && bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_writable(br->br_perm)) + err = au_dr_hino(sb, bindex, /*br*/NULL, /*path*/NULL); + } + + return err; +} + +int au_dr_opt_clr(struct super_block *sb, int no_flush) +{ + int err; + aufs_bindex_t bindex, bbot; + struct au_branch *br; + + err = 0; + if (!no_flush) { + err = au_dr_opt_flush(sb); + if (unlikely(err)) + goto out; + } + + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + au_dr_hino_free(&br->br_dirren); + } + +out: + return err; +} diff --git a/fs/aufs/dirren.h b/fs/aufs/dirren.h new file mode 100644 index 000000000000..a986736462c3 --- /dev/null +++ b/fs/aufs/dirren.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * renamed dir info + */ + +#ifndef __AUFS_DIRREN_H__ +#define __AUFS_DIRREN_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include "hbl.h" + +#define AuDirren_NHASH 100 + +#ifdef CONFIG_AUFS_DIRREN +enum au_brid_type { + AuBrid_Unset, + AuBrid_UUID, + AuBrid_FSID, + AuBrid_DEV +}; + +struct au_dr_brid { + enum au_brid_type type; + union { + uuid_t uuid; /* unimplemented yet */ + fsid_t fsid; + dev_t dev; + }; +}; + +/* 20 is the max digits length of ulong 64 */ +/* brid-type "_" uuid "_" inum */ +#define AUFS_DIRREN_FNAME_SZ (1 + 1 + UUID_STRING_LEN + 20) +#define AUFS_DIRREN_ENV_VAL_SZ (AUFS_DIRREN_FNAME_SZ + 1 + 20) + +struct au_dr_hino { + struct hlist_bl_node dr_hnode; + ino_t dr_h_ino; +}; + +struct au_dr_br { + struct hlist_bl_head dr_h_ino[AuDirren_NHASH]; + struct au_dr_brid dr_brid; +}; + +struct au_dr_lookup { + /* dr_name is pointed by struct au_do_lookup_args.name */ + struct qstr dr_name; /* subset of dr_info */ + aufs_bindex_t ninfo; + struct au_drinfo **drinfo; +}; +#else +struct au_dr_hino; +/* empty */ +struct au_dr_br { }; +struct au_dr_lookup { }; +#endif + +/* ---------------------------------------------------------------------- */ + +struct au_branch; +struct au_do_lookup_args; +struct au_hinode; +#ifdef CONFIG_AUFS_DIRREN +int au_dr_hino_test_add(struct au_dr_br *dr, ino_t h_ino, + struct au_dr_hino *add_ent); +void au_dr_hino_free(struct au_dr_br *dr); +int au_dr_br_init(struct super_block *sb, struct au_branch *br, + const struct path *path); +int au_dr_br_fin(struct super_block *sb, struct au_branch *br); +int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, + struct qstr *dst_name, void *_rev); +void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *rev); +void au_dr_rename_rev(struct dentry *src, aufs_bindex_t bindex, void *rev); +int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, + aufs_bindex_t bindex); +int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt); +int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, + ino_t h_ino); +void au_dr_lkup_fin(struct au_do_lookup_args *lkup); +int au_dr_opt_set(struct super_block *sb); +int au_dr_opt_flush(struct super_block *sb); +int au_dr_opt_clr(struct super_block *sb, int no_flush); +#else +AuStubInt0(au_dr_hino_test_add, struct au_dr_br *dr, ino_t h_ino, + struct au_dr_hino *add_ent); +AuStubVoid(au_dr_hino_free, struct au_dr_br *dr); +AuStubInt0(au_dr_br_init, struct super_block *sb, struct au_branch *br, + const struct path *path); +AuStubInt0(au_dr_br_fin, struct super_block *sb, struct au_branch *br); +AuStubInt0(au_dr_rename, struct dentry *src, aufs_bindex_t bindex, + struct qstr *dst_name, void *_rev); +AuStubVoid(au_dr_rename_fin, struct dentry *src, aufs_bindex_t btgt, void *rev); +AuStubVoid(au_dr_rename_rev, struct dentry *src, aufs_bindex_t bindex, + void *rev); +AuStubInt0(au_dr_lkup, struct au_do_lookup_args *lkup, struct dentry *dentry, + aufs_bindex_t bindex); +AuStubInt0(au_dr_lkup_name, struct au_do_lookup_args *lkup, aufs_bindex_t btgt); +AuStubInt0(au_dr_lkup_h_ino, struct au_do_lookup_args *lkup, + aufs_bindex_t bindex, ino_t h_ino); +AuStubVoid(au_dr_lkup_fin, struct au_do_lookup_args *lkup); +AuStubInt0(au_dr_opt_set, struct super_block *sb); +AuStubInt0(au_dr_opt_flush, struct super_block *sb); +AuStubInt0(au_dr_opt_clr, struct super_block *sb, int no_flush); +#endif + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_DIRREN +static inline int au_dr_ihash(ino_t h_ino) +{ + return h_ino % AuDirren_NHASH; +} +#else +AuStubInt0(au_dr_ihash, ino_t h_ino); +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIRREN_H__ */ diff --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c new file mode 100644 index 000000000000..9253c1edb06c --- /dev/null +++ b/fs/aufs/dynop.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2010-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * dynamically customizable operations for regular files + */ + +#include "aufs.h" + +#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) + +/* + * How large will these lists be? + * Usually just a few elements, 20-30 at most for each, I guess. + */ +static struct hlist_bl_head dynop[AuDyLast]; + +static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, + const void *h_op) +{ + struct au_dykey *key, *tmp; + struct hlist_bl_node *pos; + + key = NULL; + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) + if (tmp->dk_op.dy_hop == h_op) { + if (kref_get_unless_zero(&tmp->dk_kref)) + key = tmp; + break; + } + hlist_bl_unlock(hbl); + + return key; +} + +static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) +{ + struct au_dykey **k, *found; + const void *h_op = key->dk_op.dy_hop; + int i; + + found = NULL; + k = br->br_dykey; + for (i = 0; i < AuBrDynOp; i++) + if (k[i]) { + if (k[i]->dk_op.dy_hop == h_op) { + found = k[i]; + break; + } + } else + break; + if (!found) { + spin_lock(&br->br_dykey_lock); + for (; i < AuBrDynOp; i++) + if (k[i]) { + if (k[i]->dk_op.dy_hop == h_op) { + found = k[i]; + break; + } + } else { + k[i] = key; + break; + } + spin_unlock(&br->br_dykey_lock); + BUG_ON(i == AuBrDynOp); /* expand the array */ + } + + return found; +} + +/* kref_get() if @key is already added */ +static struct au_dykey *dy_gadd(struct hlist_bl_head *hbl, struct au_dykey *key) +{ + struct au_dykey *tmp, *found; + struct hlist_bl_node *pos; + const void *h_op = key->dk_op.dy_hop; + + found = NULL; + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) + if (tmp->dk_op.dy_hop == h_op) { + if (kref_get_unless_zero(&tmp->dk_kref)) + found = tmp; + break; + } + if (!found) + hlist_bl_add_head(&key->dk_hnode, hbl); + hlist_bl_unlock(hbl); + + if (!found) + DyPrSym(key); + return found; +} + +static void dy_free_rcu(struct rcu_head *rcu) +{ + struct au_dykey *key; + + key = container_of(rcu, struct au_dykey, dk_rcu); + DyPrSym(key); + kfree(key); +} + +static void dy_free(struct kref *kref) +{ + struct au_dykey *key; + struct hlist_bl_head *hbl; + + key = container_of(kref, struct au_dykey, dk_kref); + hbl = dynop + key->dk_op.dy_type; + au_hbl_del(&key->dk_hnode, hbl); + call_rcu(&key->dk_rcu, dy_free_rcu); +} + +void au_dy_put(struct au_dykey *key) +{ + kref_put(&key->dk_kref, dy_free); +} + +/* ---------------------------------------------------------------------- */ + +#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) + +#ifdef CONFIG_AUFS_DEBUG +#define DyDbgDeclare(cnt) unsigned int cnt = 0 +#define DyDbgInc(cnt) do { cnt++; } while (0) +#else +#define DyDbgDeclare(cnt) do {} while (0) +#define DyDbgInc(cnt) do {} while (0) +#endif + +#define DySet(func, dst, src, h_op, h_sb) do { \ + DyDbgInc(cnt); \ + if (h_op->func) { \ + if (src.func) \ + dst.func = src.func; \ + else \ + AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ + } \ +} while (0) + +#define DySetForce(func, dst, src) do { \ + AuDebugOn(!src.func); \ + DyDbgInc(cnt); \ + dst.func = src.func; \ +} while (0) + +#define DySetAop(func) \ + DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) +#define DySetAopForce(func) \ + DySetForce(func, dyaop->da_op, aufs_aop) + +static void dy_aop(struct au_dykey *key, const void *h_op, + struct super_block *h_sb __maybe_unused) +{ + struct au_dyaop *dyaop = (void *)key; + const struct address_space_operations *h_aop = h_op; + DyDbgDeclare(cnt); + + AuDbg("%s\n", au_sbtype(h_sb)); + + DySetAop(writepage); + DySetAopForce(readpage); /* force */ + DySetAop(writepages); + DySetAop(set_page_dirty); + DySetAop(readpages); + DySetAop(readahead); + DySetAop(write_begin); + DySetAop(write_end); + DySetAop(bmap); + DySetAop(invalidatepage); + DySetAop(releasepage); + DySetAop(freepage); + /* this one will be changed according to an aufs mount option */ + DySetAop(direct_IO); + DySetAop(migratepage); + DySetAop(isolate_page); + DySetAop(putback_page); + DySetAop(launder_page); + DySetAop(is_partially_uptodate); + DySetAop(is_dirty_writeback); + DySetAop(error_remove_page); + DySetAop(swap_activate); + DySetAop(swap_deactivate); + + DyDbgSize(cnt, *h_aop); +} + +/* ---------------------------------------------------------------------- */ + +static void dy_bug(struct kref *kref) +{ + BUG(); +} + +static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) +{ + struct au_dykey *key, *old; + struct hlist_bl_head *hbl; + struct op { + unsigned int sz; + void (*set)(struct au_dykey *key, const void *h_op, + struct super_block *h_sb __maybe_unused); + }; + static const struct op a[] = { + [AuDy_AOP] = { + .sz = sizeof(struct au_dyaop), + .set = dy_aop + } + }; + const struct op *p; + + hbl = dynop + op->dy_type; + key = dy_gfind_get(hbl, op->dy_hop); + if (key) + goto out_add; /* success */ + + p = a + op->dy_type; + key = kzalloc(p->sz, GFP_NOFS); + if (unlikely(!key)) { + key = ERR_PTR(-ENOMEM); + goto out; + } + + key->dk_op.dy_hop = op->dy_hop; + kref_init(&key->dk_kref); + p->set(key, op->dy_hop, au_br_sb(br)); + old = dy_gadd(hbl, key); + if (old) { + au_kfree_rcu(key); + key = old; + } + +out_add: + old = dy_bradd(br, key); + if (old) + /* its ref-count should never be zero here */ + kref_put(&key->dk_kref, dy_bug); +out: + return key; +} + +/* ---------------------------------------------------------------------- */ +/* + * Aufs prohibits O_DIRECT by default even if the branch supports it. + * This behaviour is necessary to return an error from open(O_DIRECT) instead + * of the succeeding I/O. The dio mount option enables O_DIRECT and makes + * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. + * See the aufs manual in detail. + */ +static void dy_adx(struct au_dyaop *dyaop, int do_dx) +{ + if (!do_dx) + dyaop->da_op.direct_IO = NULL; + else + dyaop->da_op.direct_IO = aufs_aop.direct_IO; +} + +static struct au_dyaop *dy_aget(struct au_branch *br, + const struct address_space_operations *h_aop, + int do_dx) +{ + struct au_dyaop *dyaop; + struct au_dynop op; + + op.dy_type = AuDy_AOP; + op.dy_haop = h_aop; + dyaop = (void *)dy_get(&op, br); + if (IS_ERR(dyaop)) + goto out; + dy_adx(dyaop, do_dx); + +out: + return dyaop; +} + +int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode) +{ + int err, do_dx; + struct super_block *sb; + struct au_branch *br; + struct au_dyaop *dyaop; + + AuDebugOn(!S_ISREG(h_inode->i_mode)); + IiMustWriteLock(inode); + + sb = inode->i_sb; + br = au_sbr(sb, bindex); + do_dx = !!au_opt_test(au_mntflags(sb), DIO); + dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); + err = PTR_ERR(dyaop); + if (IS_ERR(dyaop)) + /* unnecessary to call dy_fput() */ + goto out; + + err = 0; + inode->i_mapping->a_ops = &dyaop->da_op; + +out: + return err; +} + +/* + * Is it safe to replace a_ops during the inode/file is in operation? + * Yes, I hope so. + */ +int au_dy_irefresh(struct inode *inode) +{ + int err; + aufs_bindex_t btop; + struct inode *h_inode; + + err = 0; + if (S_ISREG(inode->i_mode)) { + btop = au_ibtop(inode); + h_inode = au_h_iptr(inode, btop); + err = au_dy_iaop(inode, btop, h_inode); + } + return err; +} + +void au_dy_arefresh(int do_dx) +{ + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + struct au_dykey *key; + + hbl = dynop + AuDy_AOP; + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) + dy_adx((void *)key, do_dx); + hlist_bl_unlock(hbl); +} + +/* ---------------------------------------------------------------------- */ + +void __init au_dy_init(void) +{ + int i; + + for (i = 0; i < AuDyLast; i++) + INIT_HLIST_BL_HEAD(dynop + i); +} + +void au_dy_fin(void) +{ + int i; + + for (i = 0; i < AuDyLast; i++) + WARN_ON(!hlist_bl_empty(dynop + i)); +} diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h new file mode 100644 index 000000000000..5d0b36559425 --- /dev/null +++ b/fs/aufs/dynop.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2010-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * dynamically customizable operations (for regular files only) + */ + +#ifndef __AUFS_DYNOP_H__ +#define __AUFS_DYNOP_H__ + +#ifdef __KERNEL__ + +#include +#include + +enum {AuDy_AOP, AuDyLast}; + +struct au_dynop { + int dy_type; + union { + const void *dy_hop; + const struct address_space_operations *dy_haop; + }; +}; + +struct au_dykey { + union { + struct hlist_bl_node dk_hnode; + struct rcu_head dk_rcu; + }; + struct au_dynop dk_op; + + /* + * during I am in the branch local array, kref is gotten. when the + * branch is removed, kref is put. + */ + struct kref dk_kref; +}; + +/* stop unioning since their sizes are very different from each other */ +struct au_dyaop { + struct au_dykey da_key; + struct address_space_operations da_op; /* not const */ +}; +/* make sure that 'struct au_dykey *' can be any type */ +static_assert(!offsetof(struct au_dyaop, da_key)); + +/* ---------------------------------------------------------------------- */ + +/* dynop.c */ +struct au_branch; +void au_dy_put(struct au_dykey *key); +int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode); +int au_dy_irefresh(struct inode *inode); +void au_dy_arefresh(int do_dio); + +void __init au_dy_init(void); +void au_dy_fin(void); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DYNOP_H__ */ diff --git a/fs/aufs/export.c b/fs/aufs/export.c new file mode 100644 index 000000000000..bf22024d68b7 --- /dev/null +++ b/fs/aufs/export.c @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * export via nfs + */ + +#include +#include +#include +#include +#include +#include +#include "aufs.h" + +union conv { +#ifdef CONFIG_AUFS_INO_T_64 + __u32 a[2]; +#else + __u32 a[1]; +#endif + ino_t ino; +}; + +static ino_t decode_ino(__u32 *a) +{ + union conv u; + + BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); + u.a[0] = a[0]; +#ifdef CONFIG_AUFS_INO_T_64 + u.a[1] = a[1]; +#endif + return u.ino; +} + +static void encode_ino(__u32 *a, ino_t ino) +{ + union conv u; + + u.ino = ino; + a[0] = u.a[0]; +#ifdef CONFIG_AUFS_INO_T_64 + a[1] = u.a[1]; +#endif +} + +/* NFS file handle */ +enum { + Fh_br_id, + Fh_sigen, +#ifdef CONFIG_AUFS_INO_T_64 + /* support 64bit inode number */ + Fh_ino1, + Fh_ino2, + Fh_dir_ino1, + Fh_dir_ino2, +#else + Fh_ino1, + Fh_dir_ino1, +#endif + Fh_igen, + Fh_h_type, + Fh_tail, + + Fh_ino = Fh_ino1, + Fh_dir_ino = Fh_dir_ino1 +}; + +static int au_test_anon(struct dentry *dentry) +{ + /* note: read d_flags without d_lock */ + return !!(dentry->d_flags & DCACHE_DISCONNECTED); +} + +int au_test_nfsd(void) +{ + int ret; + struct task_struct *tsk = current; + char comm[sizeof(tsk->comm)]; + + ret = 0; + if (tsk->flags & PF_KTHREAD) { + get_task_comm(comm, tsk); + ret = !strcmp(comm, "nfsd"); + } + + return ret; +} + +/* ---------------------------------------------------------------------- */ +/* inode generation external table */ + +void au_xigen_inc(struct inode *inode) +{ + loff_t pos; + ssize_t sz; + __u32 igen; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + sb = inode->i_sb; + AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); + + sbinfo = au_sbi(sb); + pos = inode->i_ino; + pos *= sizeof(igen); + igen = inode->i_generation + 1; + sz = xino_fwrite(sbinfo->si_xigen, &igen, sizeof(igen), &pos); + if (sz == sizeof(igen)) + return; /* success */ + + if (unlikely(sz >= 0)) + AuIOErr("xigen error (%zd)\n", sz); +} + +int au_xigen_new(struct inode *inode) +{ + int err; + loff_t pos; + ssize_t sz; + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct file *file; + + err = 0; + /* todo: dirty, at mount time */ + if (inode->i_ino == AUFS_ROOT_INO) + goto out; + sb = inode->i_sb; + SiMustAnyLock(sb); + if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) + goto out; + + err = -EFBIG; + pos = inode->i_ino; + if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { + AuIOErr1("too large i%lld\n", pos); + goto out; + } + pos *= sizeof(inode->i_generation); + + err = 0; + sbinfo = au_sbi(sb); + file = sbinfo->si_xigen; + BUG_ON(!file); + + if (vfsub_f_size_read(file) + < pos + sizeof(inode->i_generation)) { + inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); + sz = xino_fwrite(file, &inode->i_generation, + sizeof(inode->i_generation), &pos); + } else + sz = xino_fread(file, &inode->i_generation, + sizeof(inode->i_generation), &pos); + if (sz == sizeof(inode->i_generation)) + goto out; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xigen error (%zd)\n", sz); + } + +out: + return err; +} + +int au_xigen_set(struct super_block *sb, struct path *path) +{ + int err; + struct au_sbinfo *sbinfo; + struct file *file; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + file = au_xino_create2(sb, path, sbinfo->si_xigen); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + err = 0; + if (sbinfo->si_xigen) + fput(sbinfo->si_xigen); + sbinfo->si_xigen = file; + +out: + AuTraceErr(err); + return err; +} + +void au_xigen_clr(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + if (sbinfo->si_xigen) { + fput(sbinfo->si_xigen); + sbinfo->si_xigen = NULL; + } +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, + ino_t dir_ino) +{ + struct dentry *dentry, *d; + struct inode *inode; + unsigned int sigen; + + dentry = NULL; + inode = ilookup(sb, ino); + if (!inode) + goto out; + + dentry = ERR_PTR(-ESTALE); + sigen = au_sigen(sb); + if (unlikely(au_is_bad_inode(inode) + || IS_DEADDIR(inode) + || sigen != au_iigen(inode, NULL))) + goto out_iput; + + dentry = NULL; + if (!dir_ino || S_ISDIR(inode->i_mode)) + dentry = d_find_alias(inode); + else { + spin_lock(&inode->i_lock); + hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { + spin_lock(&d->d_lock); + if (!au_test_anon(d) + && d_inode(d->d_parent)->i_ino == dir_ino) { + dentry = dget_dlock(d); + spin_unlock(&d->d_lock); + break; + } + spin_unlock(&d->d_lock); + } + spin_unlock(&inode->i_lock); + } + if (unlikely(dentry && au_digen_test(dentry, sigen))) { + /* need to refresh */ + dput(dentry); + dentry = NULL; + } + +out_iput: + iput(inode); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +/* todo: dirty? */ +/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ + +struct au_compare_mnt_args { + /* input */ + struct super_block *sb; + + /* output */ + struct vfsmount *mnt; +}; + +static int au_compare_mnt(struct vfsmount *mnt, void *arg) +{ + struct au_compare_mnt_args *a = arg; + + if (mnt->mnt_sb != a->sb) + return 0; + a->mnt = mntget(mnt); + return 1; +} + +static struct vfsmount *au_mnt_get(struct super_block *sb) +{ + int err; + struct path root; + struct au_compare_mnt_args args = { + .sb = sb + }; + + get_fs_root(current->fs, &root); + rcu_read_lock(); + err = iterate_mounts(au_compare_mnt, &args, root.mnt); + rcu_read_unlock(); + path_put(&root); + AuDebugOn(!err); + AuDebugOn(!args.mnt); + return args.mnt; +} + +struct au_nfsd_si_lock { + unsigned int sigen; + aufs_bindex_t bindex, br_id; + unsigned char force_lock; +}; + +static int si_nfsd_read_lock(struct super_block *sb, + struct au_nfsd_si_lock *nsi_lock) +{ + int err; + aufs_bindex_t bindex; + + si_read_lock(sb, AuLock_FLUSH); + + /* branch id may be wrapped around */ + err = 0; + bindex = au_br_index(sb, nsi_lock->br_id); + if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) + goto out; /* success */ + + err = -ESTALE; + bindex = -1; + if (!nsi_lock->force_lock) + si_read_unlock(sb); + +out: + nsi_lock->bindex = bindex; + return err; +} + +struct find_name_by_ino { + struct dir_context ctx; + int called, found; + ino_t ino; + char *name; + int namelen; +}; + +static int +find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, + ctx); + + a->called++; + if (a->ino != ino) + return 0; + + memcpy(a->name, name, namelen); + a->namelen = namelen; + a->found = 1; + return 1; +} + +static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, + struct au_nfsd_si_lock *nsi_lock) +{ + struct dentry *dentry, *parent; + struct file *file; + struct inode *dir; + struct find_name_by_ino arg = { + .ctx = { + .actor = find_name_by_ino + } + }; + int err; + + parent = path->dentry; + if (nsi_lock) + si_read_unlock(parent->d_sb); + file = vfsub_dentry_open(path, au_dir_roflags); + dentry = (void *)file; + if (IS_ERR(file)) + goto out; + + dentry = ERR_PTR(-ENOMEM); + arg.name = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!arg.name)) + goto out_file; + arg.ino = ino; + arg.found = 0; + do { + arg.called = 0; + /* smp_mb(); */ + err = vfsub_iterate_dir(file, &arg.ctx); + } while (!err && !arg.found && arg.called); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_name; + /* instead of ENOENT */ + dentry = ERR_PTR(-ESTALE); + if (!arg.found) + goto out_name; + + /* do not call vfsub_lkup_one() */ + dir = d_inode(parent); + dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen); + AuTraceErrPtr(dentry); + if (IS_ERR(dentry)) + goto out_name; + AuDebugOn(au_test_anon(dentry)); + if (unlikely(d_really_is_negative(dentry))) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } + +out_name: + free_page((unsigned long)arg.name); +out_file: + fput(file); +out: + if (unlikely(nsi_lock + && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) + if (!IS_ERR(dentry)) { + dput(dentry); + dentry = ERR_PTR(-ESTALE); + } + AuTraceErrPtr(dentry); + return dentry; +} + +static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, + ino_t dir_ino, + struct au_nfsd_si_lock *nsi_lock) +{ + struct dentry *dentry; + struct path path; + + if (dir_ino != AUFS_ROOT_INO) { + path.dentry = decode_by_ino(sb, dir_ino, 0); + dentry = path.dentry; + if (!path.dentry || IS_ERR(path.dentry)) + goto out; + AuDebugOn(au_test_anon(path.dentry)); + } else + path.dentry = dget(sb->s_root); + + path.mnt = au_mnt_get(sb); + dentry = au_lkup_by_ino(&path, ino, nsi_lock); + path_put(&path); + +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +static int h_acceptable(void *expv, struct dentry *dentry) +{ + return 1; +} + +static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, + char *buf, int len, struct super_block *sb) +{ + char *p; + int n; + struct path path; + + p = d_path(h_rootpath, buf, len); + if (IS_ERR(p)) + goto out; + n = strlen(p); + + path.mnt = h_rootpath->mnt; + path.dentry = h_parent; + p = d_path(&path, buf, len); + if (IS_ERR(p)) + goto out; + if (n != 1) + p += n; + + path.mnt = au_mnt_get(sb); + path.dentry = sb->s_root; + p = d_path(&path, buf, len - strlen(p)); + mntput(path.mnt); + if (IS_ERR(p)) + goto out; + if (n != 1) + p[strlen(p)] = '/'; + +out: + AuTraceErrPtr(p); + return p; +} + +static +struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, + int fh_len, struct au_nfsd_si_lock *nsi_lock) +{ + struct dentry *dentry, *h_parent, *root; + struct super_block *h_sb; + char *pathname, *p; + struct vfsmount *h_mnt; + struct au_branch *br; + int err; + struct path path; + + br = au_sbr(sb, nsi_lock->bindex); + h_mnt = au_br_mnt(br); + h_sb = h_mnt->mnt_sb; + /* todo: call lower fh_to_dentry()? fh_to_parent()? */ + lockdep_off(); + h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), + fh_len - Fh_tail, fh[Fh_h_type], + h_acceptable, /*context*/NULL); + lockdep_on(); + dentry = h_parent; + if (unlikely(!h_parent || IS_ERR(h_parent))) { + AuWarn1("%s decode_fh failed, %ld\n", + au_sbtype(h_sb), PTR_ERR(h_parent)); + goto out; + } + dentry = NULL; + if (unlikely(au_test_anon(h_parent))) { + AuWarn1("%s decode_fh returned a disconnected dentry\n", + au_sbtype(h_sb)); + goto out_h_parent; + } + + dentry = ERR_PTR(-ENOMEM); + pathname = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!pathname)) + goto out_h_parent; + + root = sb->s_root; + path.mnt = h_mnt; + di_read_lock_parent(root, !AuLock_IR); + path.dentry = au_h_dptr(root, nsi_lock->bindex); + di_read_unlock(root, !AuLock_IR); + p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); + dentry = (void *)p; + if (IS_ERR(p)) + goto out_pathname; + + si_read_unlock(sb); + err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_relock; + + dentry = ERR_PTR(-ENOENT); + AuDebugOn(au_test_anon(path.dentry)); + if (unlikely(d_really_is_negative(path.dentry))) + goto out_path; + + if (ino != d_inode(path.dentry)->i_ino) + dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); + else + dentry = dget(path.dentry); + +out_path: + path_put(&path); +out_relock: + if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) + if (!IS_ERR(dentry)) { + dput(dentry); + dentry = ERR_PTR(-ESTALE); + } +out_pathname: + free_page((unsigned long)pathname); +out_h_parent: + dput(h_parent); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry * +aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, + int fh_type) +{ + struct dentry *dentry; + __u32 *fh = fid->raw; + struct au_branch *br; + ino_t ino, dir_ino; + struct au_nfsd_si_lock nsi_lock = { + .force_lock = 0 + }; + + dentry = ERR_PTR(-ESTALE); + /* it should never happen, but the file handle is unreliable */ + if (unlikely(fh_len < Fh_tail)) + goto out; + nsi_lock.sigen = fh[Fh_sigen]; + nsi_lock.br_id = fh[Fh_br_id]; + + /* branch id may be wrapped around */ + br = NULL; + if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) + goto out; + nsi_lock.force_lock = 1; + + /* is this inode still cached? */ + ino = decode_ino(fh + Fh_ino); + /* it should never happen */ + if (unlikely(ino == AUFS_ROOT_INO)) + goto out_unlock; + + dir_ino = decode_ino(fh + Fh_dir_ino); + dentry = decode_by_ino(sb, ino, dir_ino); + if (IS_ERR(dentry)) + goto out_unlock; + if (dentry) + goto accept; + + /* is the parent dir cached? */ + br = au_sbr(sb, nsi_lock.bindex); + au_lcnt_inc(&br->br_nfiles); + dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); + if (IS_ERR(dentry)) + goto out_unlock; + if (dentry) + goto accept; + + /* lookup path */ + dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); + if (IS_ERR(dentry)) + goto out_unlock; + if (unlikely(!dentry)) + /* todo?: make it ESTALE */ + goto out_unlock; + +accept: + if (!au_digen_test(dentry, au_sigen(sb)) + && d_inode(dentry)->i_generation == fh[Fh_igen]) + goto out_unlock; /* success */ + + dput(dentry); + dentry = ERR_PTR(-ESTALE); +out_unlock: + if (br) + au_lcnt_dec(&br->br_nfiles); + si_read_unlock(sb); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +#if 0 /* reserved for future use */ +/* support subtreecheck option */ +static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + struct dentry *parent; + __u32 *fh = fid->raw; + ino_t dir_ino; + + dir_ino = decode_ino(fh + Fh_dir_ino); + parent = decode_by_ino(sb, dir_ino, 0); + if (IS_ERR(parent)) + goto out; + if (!parent) + parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), + dir_ino, fh, fh_len); + +out: + AuTraceErrPtr(parent); + return parent; +} +#endif + +/* ---------------------------------------------------------------------- */ + +static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, + struct inode *dir) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb, *h_sb; + struct dentry *dentry, *parent, *h_parent; + struct inode *h_dir; + struct au_branch *br; + + err = -ENOSPC; + if (unlikely(*max_len <= Fh_tail)) { + AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); + goto out; + } + + err = FILEID_ROOT; + if (inode->i_ino == AUFS_ROOT_INO) { + AuDebugOn(inode->i_ino != AUFS_ROOT_INO); + goto out; + } + + h_parent = NULL; + sb = inode->i_sb; + err = si_read_lock(sb, AuLock_FLUSH); + if (unlikely(err)) + goto out; + +#ifdef CONFIG_AUFS_DEBUG + if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) + AuWarn1("NFS-exporting requires xino\n"); +#endif + err = -EIO; + parent = NULL; + ii_read_lock_child(inode); + bindex = au_ibtop(inode); + if (!dir) { + dentry = d_find_any_alias(inode); + if (unlikely(!dentry)) + goto out_unlock; + AuDebugOn(au_test_anon(dentry)); + parent = dget_parent(dentry); + dput(dentry); + if (unlikely(!parent)) + goto out_unlock; + if (d_really_is_positive(parent)) + dir = d_inode(parent); + } + + ii_read_lock_parent(dir); + h_dir = au_h_iptr(dir, bindex); + ii_read_unlock(dir); + if (unlikely(!h_dir)) + goto out_parent; + h_parent = d_find_any_alias(h_dir); + if (unlikely(!h_parent)) + goto out_hparent; + + err = -EPERM; + br = au_sbr(sb, bindex); + h_sb = au_br_sb(br); + if (unlikely(!h_sb->s_export_op)) { + AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); + goto out_hparent; + } + + fh[Fh_br_id] = br->br_id; + fh[Fh_sigen] = au_sigen(sb); + encode_ino(fh + Fh_ino, inode->i_ino); + encode_ino(fh + Fh_dir_ino, dir->i_ino); + fh[Fh_igen] = inode->i_generation; + + *max_len -= Fh_tail; + fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), + max_len, + /*connectable or subtreecheck*/0); + err = fh[Fh_h_type]; + *max_len += Fh_tail; + /* todo: macros? */ + if (err != FILEID_INVALID) + err = 99; + else + AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); + +out_hparent: + dput(h_parent); +out_parent: + dput(parent); +out_unlock: + ii_read_unlock(inode); + si_read_unlock(sb); +out: + if (unlikely(err < 0)) + err = FILEID_INVALID; + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_commit_metadata(struct inode *inode) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb; + struct inode *h_inode; + int (*f)(struct inode *inode); + + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + ii_write_lock_child(inode); + bindex = au_ibtop(inode); + AuDebugOn(bindex < 0); + h_inode = au_h_iptr(inode, bindex); + + f = h_inode->i_sb->s_export_op->commit_metadata; + if (f) + err = f(h_inode); + else { + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0 /* metadata only */ + }; + + err = sync_inode(h_inode, &wbc); + } + + au_cpup_attr_timesizes(inode); + ii_write_unlock(inode); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct export_operations aufs_export_op = { + .fh_to_dentry = aufs_fh_to_dentry, + /* .fh_to_parent = aufs_fh_to_parent, */ + .encode_fh = aufs_encode_fh, + .commit_metadata = aufs_commit_metadata +}; + +void au_export_init(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + __u32 u; + + BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) + && IS_MODULE(CONFIG_EXPORTFS), + AUFS_NAME ": unsupported configuration " + "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); + + sb->s_export_op = &aufs_export_op; + sbinfo = au_sbi(sb); + sbinfo->si_xigen = NULL; + get_random_bytes(&u, sizeof(u)); + BUILD_BUG_ON(sizeof(u) != sizeof(int)); + atomic_set(&sbinfo->si_xigen_next, u); +} diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c new file mode 100644 index 000000000000..a050957eed4e --- /dev/null +++ b/fs/aufs/f_op.c @@ -0,0 +1,771 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file and vm operations + */ + +#include +#include +#include +#include +#include "aufs.h" + +int au_do_open_nondir(struct file *file, int flags, struct file *h_file) +{ + int err; + aufs_bindex_t bindex; + struct dentry *dentry, *h_dentry; + struct au_finfo *finfo; + struct inode *h_inode; + + FiMustWriteLock(file); + + err = 0; + dentry = file->f_path.dentry; + AuDebugOn(IS_ERR_OR_NULL(dentry)); + finfo = au_fi(file); + memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); + atomic_set(&finfo->fi_mmapped, 0); + bindex = au_dbtop(dentry); + if (!h_file) { + h_dentry = au_h_dptr(dentry, bindex); + err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); + if (unlikely(err)) + goto out; + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); + if (IS_ERR(h_file)) { + err = PTR_ERR(h_file); + goto out; + } + } else { + h_dentry = h_file->f_path.dentry; + err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); + if (unlikely(err)) + goto out; + /* br ref is already inc-ed */ + } + + if ((flags & __O_TMPFILE) + && !(flags & O_EXCL)) { + h_inode = file_inode(h_file); + spin_lock(&h_inode->i_lock); + h_inode->i_state |= I_LINKABLE; + spin_unlock(&h_inode->i_lock); + } + au_set_fbtop(file, bindex); + au_set_h_fptr(file, bindex, h_file); + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + +out: + return err; +} + +static int aufs_open_nondir(struct inode *inode __maybe_unused, + struct file *file) +{ + int err; + struct super_block *sb; + struct au_do_open_args args = { + .open = au_do_open_nondir + }; + + AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", + file, vfsub_file_flags(file), file->f_mode); + + sb = file->f_path.dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_do_open(file, &args); + si_read_unlock(sb); + return err; +} + +int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) +{ + struct au_finfo *finfo; + aufs_bindex_t bindex; + + finfo = au_fi(file); + au_hbl_del(&finfo->fi_hlist, + &au_sbi(file->f_path.dentry->d_sb)->si_files); + bindex = finfo->fi_btop; + if (bindex >= 0) + au_set_h_fptr(file, bindex, NULL); + + au_finfo_fin(file); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_flush_nondir(struct file *file, fl_owner_t id) +{ + int err; + struct file *h_file; + + err = 0; + h_file = au_hf_top(file); + if (h_file) + err = vfsub_flush(h_file, id); + return err; +} + +static int aufs_flush_nondir(struct file *file, fl_owner_t id) +{ + return au_do_flush(file, id, au_do_flush_nondir); +} + +/* ---------------------------------------------------------------------- */ +/* + * read and write functions acquire [fdi]_rwsem once, but release before + * mmap_sem. This is because to stop a race condition between mmap(2). + * Releasing these aufs-rwsem should be safe, no branch-management (by keeping + * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in + * read functions after [fdi]_rwsem are released, but it should be harmless. + */ + +/* Callers should call au_read_post() or fput() in the end */ +struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc) +{ + struct file *h_file; + int err; + + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, lsc); + if (!err) { + di_read_unlock(file->f_path.dentry, AuLock_IR); + h_file = au_hf_top(file); + get_file(h_file); + if (!keep_fi) + fi_read_unlock(file); + } else + h_file = ERR_PTR(err); + + return h_file; +} + +static void au_read_post(struct inode *inode, struct file *h_file) +{ + /* update without lock, I don't think it a problem */ + fsstack_copy_attr_atime(inode, file_inode(h_file)); + fput(h_file); +} + +struct au_write_pre { + /* input */ + unsigned int lsc; + + /* output */ + blkcnt_t blks; + aufs_bindex_t btop; +}; + +/* + * return with iinfo is write-locked + * callers should call au_write_post() or iinfo_write_unlock() + fput() in the + * end + */ +static struct file *au_write_pre(struct file *file, int do_ready, + struct au_write_pre *wpre) +{ + struct file *h_file; + struct dentry *dentry; + int err; + unsigned int lsc; + struct au_pin pin; + + lsc = 0; + if (wpre) + lsc = wpre->lsc; + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, lsc); + h_file = ERR_PTR(err); + if (unlikely(err)) + goto out; + + dentry = file->f_path.dentry; + if (do_ready) { + err = au_ready_to_write(file, -1, &pin); + if (unlikely(err)) { + h_file = ERR_PTR(err); + di_write_unlock(dentry); + goto out_fi; + } + } + + di_downgrade_lock(dentry, /*flags*/0); + if (wpre) + wpre->btop = au_fbtop(file); + h_file = au_hf_top(file); + get_file(h_file); + if (wpre) + wpre->blks = file_inode(h_file)->i_blocks; + if (do_ready) + au_unpin(&pin); + di_read_unlock(dentry, /*flags*/0); + +out_fi: + fi_write_unlock(file); +out: + return h_file; +} + +static void au_write_post(struct inode *inode, struct file *h_file, + struct au_write_pre *wpre, ssize_t written) +{ + struct inode *h_inode; + + au_cpup_attr_timesizes(inode); + AuDebugOn(au_ibtop(inode) != wpre->btop); + h_inode = file_inode(h_file); + inode->i_mode = h_inode->i_mode; + ii_write_unlock(inode); + /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ + if (written > 0) + au_fhsm_wrote(inode->i_sb, wpre->btop, + /*force*/h_inode->i_blocks > wpre->blks); + fput(h_file); +} + +/* + * todo: very ugly + * it locks both of i_mutex and si_rwsem for read in safe. + * if the plink maintenance mode continues forever (that is the problem), + * may loop forever. + */ +static void au_mtx_and_read_lock(struct inode *inode) +{ + int err; + struct super_block *sb = inode->i_sb; + + while (1) { + inode_lock(inode); + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (!err) + break; + inode_unlock(inode); + si_read_lock(sb, AuLock_NOPLMW); + si_read_unlock(sb); + } +} + +static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, + struct iov_iter *iov_iter) +{ + ssize_t err; + struct file *file; + ssize_t (*iter)(struct kiocb *, struct iov_iter *); + + err = security_file_permission(h_file, rw); + if (unlikely(err)) + goto out; + + err = -ENOSYS; /* the branch doesn't have its ->(read|write)_iter() */ + iter = NULL; + if (rw == MAY_READ) + iter = h_file->f_op->read_iter; + else if (rw == MAY_WRITE) + iter = h_file->f_op->write_iter; + + file = kio->ki_filp; + kio->ki_filp = h_file; + if (iter) { + lockdep_off(); + err = iter(kio, iov_iter); + lockdep_on(); + } else + /* currently there is no such fs */ + WARN_ON_ONCE(1); + kio->ki_filp = file; + +out: + return err; +} + +static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) +{ + ssize_t err; + struct file *file, *h_file; + struct inode *inode; + struct super_block *sb; + + file = kio->ki_filp; + inode = file_inode(file); + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + + h_file = au_read_pre(file, /*keep_fi*/1, /*lsc*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + if (au_test_loopback_kthread()) { + au_warn_loopback(h_file->f_path.dentry->d_sb); + if (file->f_mapping != h_file->f_mapping) { + file->f_mapping = h_file->f_mapping; + smp_mb(); /* unnecessary? */ + } + } + fi_read_unlock(file); + + err = au_do_iter(h_file, MAY_READ, kio, iov_iter); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + au_read_post(inode, h_file); + +out: + si_read_unlock(sb); + return err; +} + +static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) +{ + ssize_t err; + struct au_write_pre wpre; + struct inode *inode; + struct file *file, *h_file; + + file = kio->ki_filp; + inode = file_inode(file); + au_mtx_and_read_lock(inode); + + wpre.lsc = 0; + h_file = au_write_pre(file, /*do_ready*/1, &wpre); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); + au_write_post(inode, h_file, &wpre, err); + +out: + si_read_unlock(inode->i_sb); + inode_unlock(inode); + return err; +} + +/* + * We may be able to remove aufs_splice_{read,write}() since almost all FSes + * don't have their own .splice_{read,write} implimentations, and they use + * generic_file_splice_read() and iter_file_splice_write() who can act like the + * simple converters to f_op->iter_read() and ->iter_write(). + * But we keep our own implementations because some non-mainlined FSes may have + * their own .splice_{read,write} implimentations and aufs doesn't want to take + * away an opportunity to co-work with aufs from them. + */ +static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + ssize_t err; + struct file *h_file; + struct inode *inode; + struct super_block *sb; + + inode = file_inode(file); + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + + h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + err = vfsub_splice_to(h_file, ppos, pipe, len, flags); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + au_read_post(inode, h_file); + +out: + si_read_unlock(sb); + return err; +} + +static ssize_t +aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, + size_t len, unsigned int flags) +{ + ssize_t err; + struct au_write_pre wpre; + struct inode *inode; + struct file *h_file; + + inode = file_inode(file); + au_mtx_and_read_lock(inode); + + wpre.lsc = 0; + h_file = au_write_pre(file, /*do_ready*/1, &wpre); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + err = vfsub_splice_from(pipe, h_file, ppos, len, flags); + au_write_post(inode, h_file, &wpre, err); + +out: + si_read_unlock(inode->i_sb); + inode_unlock(inode); + return err; +} + +static long aufs_fallocate(struct file *file, int mode, loff_t offset, + loff_t len) +{ + long err; + struct au_write_pre wpre; + struct inode *inode; + struct file *h_file; + + inode = file_inode(file); + au_mtx_and_read_lock(inode); + + wpre.lsc = 0; + h_file = au_write_pre(file, /*do_ready*/1, &wpre); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + lockdep_off(); + err = vfs_fallocate(h_file, mode, offset, len); + lockdep_on(); + au_write_post(inode, h_file, &wpre, /*written*/1); + +out: + si_read_unlock(inode->i_sb); + inode_unlock(inode); + return err; +} + +static ssize_t aufs_copy_file_range(struct file *src, loff_t src_pos, + struct file *dst, loff_t dst_pos, + size_t len, unsigned int flags) +{ + ssize_t err; + struct au_write_pre wpre; + enum { SRC, DST }; + struct { + struct inode *inode; + struct file *h_file; + struct super_block *h_sb; + } a[2]; +#define a_src a[SRC] +#define a_dst a[DST] + + err = -EINVAL; + a_src.inode = file_inode(src); + if (unlikely(!S_ISREG(a_src.inode->i_mode))) + goto out; + a_dst.inode = file_inode(dst); + if (unlikely(!S_ISREG(a_dst.inode->i_mode))) + goto out; + + au_mtx_and_read_lock(a_dst.inode); + /* + * in order to match the order in di_write_lock2_{child,parent}(), + * use f_path.dentry for this comparison. + */ + if (src->f_path.dentry < dst->f_path.dentry) { + a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); + err = PTR_ERR(a_src.h_file); + if (IS_ERR(a_src.h_file)) + goto out_si; + + wpre.lsc = AuLsc_FI_2; + a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); + err = PTR_ERR(a_dst.h_file); + if (IS_ERR(a_dst.h_file)) { + au_read_post(a_src.inode, a_src.h_file); + goto out_si; + } + } else { + wpre.lsc = AuLsc_FI_1; + a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); + err = PTR_ERR(a_dst.h_file); + if (IS_ERR(a_dst.h_file)) + goto out_si; + + a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_2); + err = PTR_ERR(a_src.h_file); + if (IS_ERR(a_src.h_file)) { + au_write_post(a_dst.inode, a_dst.h_file, &wpre, + /*written*/0); + goto out_si; + } + } + + err = -EXDEV; + a_src.h_sb = file_inode(a_src.h_file)->i_sb; + a_dst.h_sb = file_inode(a_dst.h_file)->i_sb; + if (unlikely(a_src.h_sb != a_dst.h_sb)) { + AuDbgFile(src); + AuDbgFile(dst); + goto out_file; + } + + err = vfsub_copy_file_range(a_src.h_file, src_pos, a_dst.h_file, + dst_pos, len, flags); + +out_file: + au_write_post(a_dst.inode, a_dst.h_file, &wpre, err); + fi_read_unlock(src); + au_read_post(a_src.inode, a_src.h_file); +out_si: + si_read_unlock(a_dst.inode->i_sb); + inode_unlock(a_dst.inode); +out: + return err; +#undef a_src +#undef a_dst +} + +/* ---------------------------------------------------------------------- */ + +/* + * The locking order around current->mmap_sem. + * - in most and regular cases + * file I/O syscall -- aufs_read() or something + * -- si_rwsem for read -- mmap_sem + * (Note that [fdi]i_rwsem are released before mmap_sem). + * - in mmap case + * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem + * This AB-BA order is definitely bad, but is not a problem since "si_rwsem for + * read" allows multiple processes to acquire it and [fdi]i_rwsem are not held + * in file I/O. Aufs needs to stop lockdep in aufs_mmap() though. + * It means that when aufs acquires si_rwsem for write, the process should never + * acquire mmap_sem. + * + * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a + * problem either since any directory is not able to be mmap-ed. + * The similar scenario is applied to aufs_readlink() too. + */ + +#if 0 /* stop calling security_file_mmap() */ +/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ +#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) + +static unsigned long au_arch_prot_conv(unsigned long flags) +{ + /* currently ppc64 only */ +#ifdef CONFIG_PPC64 + /* cf. linux/arch/powerpc/include/asm/mman.h */ + AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); + return AuConv_VM_PROT(flags, SAO); +#else + AuDebugOn(arch_calc_vm_prot_bits(-1)); + return 0; +#endif +} + +static unsigned long au_prot_conv(unsigned long flags) +{ + return AuConv_VM_PROT(flags, READ) + | AuConv_VM_PROT(flags, WRITE) + | AuConv_VM_PROT(flags, EXEC) + | au_arch_prot_conv(flags); +} + +/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ +#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) + +static unsigned long au_flag_conv(unsigned long flags) +{ + return AuConv_VM_MAP(flags, GROWSDOWN) + | AuConv_VM_MAP(flags, DENYWRITE) + | AuConv_VM_MAP(flags, LOCKED); +} +#endif + +static int aufs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err; + const unsigned char wlock + = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); + struct super_block *sb; + struct file *h_file; + struct inode *inode; + + AuDbgVmRegion(file, vma); + + inode = file_inode(file); + sb = inode->i_sb; + lockdep_off(); + si_read_lock(sb, AuLock_NOPLMW); + + h_file = au_write_pre(file, wlock, /*wpre*/NULL); + lockdep_on(); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + err = 0; + au_set_mmapped(file); + au_vm_file_reset(vma, h_file); + /* + * we cannot call security_mmap_file() here since it may acquire + * mmap_sem or i_mutex. + * + * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), + * au_flag_conv(vma->vm_flags)); + */ + if (!err) + err = call_mmap(h_file, vma); + if (!err) { + au_vm_prfile_set(vma, file); + fsstack_copy_attr_atime(inode, file_inode(h_file)); + goto out_fput; /* success */ + } + au_unset_mmapped(file); + au_vm_file_reset(vma, file); + +out_fput: + lockdep_off(); + ii_write_unlock(inode); + lockdep_on(); + fput(h_file); +out: + lockdep_off(); + si_read_unlock(sb); + lockdep_on(); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, + int datasync) +{ + int err; + struct au_write_pre wpre; + struct inode *inode; + struct file *h_file; + + err = 0; /* -EBADF; */ /* posix? */ + if (unlikely(!(file->f_mode & FMODE_WRITE))) + goto out; + + inode = file_inode(file); + au_mtx_and_read_lock(inode); + + wpre.lsc = 0; + h_file = au_write_pre(file, /*do_ready*/1, &wpre); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out_unlock; + + err = vfsub_fsync(h_file, &h_file->f_path, datasync); + au_write_post(inode, h_file, &wpre, /*written*/0); + +out_unlock: + si_read_unlock(inode->i_sb); + inode_unlock(inode); +out: + return err; +} + +static int aufs_fasync(int fd, struct file *file, int flag) +{ + int err; + struct file *h_file; + struct super_block *sb; + + sb = file->f_path.dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + + h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + if (h_file->f_op->fasync) + err = h_file->f_op->fasync(fd, h_file, flag); + fput(h_file); /* instead of au_read_post() */ + +out: + si_read_unlock(sb); + return err; +} + +static int aufs_setfl(struct file *file, unsigned long arg) +{ + int err; + struct file *h_file; + struct super_block *sb; + + sb = file->f_path.dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + + h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + + /* stop calling h_file->fasync */ + arg |= vfsub_file_flags(file) & FASYNC; + err = setfl(/*unused fd*/-1, h_file, arg); + fput(h_file); /* instead of au_read_post() */ + +out: + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* no one supports this operation, currently */ +#if 0 /* reserved for future use */ +static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, + size_t len, loff_t *pos, int more) +{ +} +#endif + +/* ---------------------------------------------------------------------- */ + +const struct file_operations aufs_file_fop = { + .owner = THIS_MODULE, + + .llseek = default_llseek, + + .read_iter = aufs_read_iter, + .write_iter = aufs_write_iter, + +#ifdef CONFIG_AUFS_POLL + .poll = aufs_poll, +#endif + .unlocked_ioctl = aufs_ioctl_nondir, +#ifdef CONFIG_COMPAT + .compat_ioctl = aufs_compat_ioctl_nondir, +#endif + .mmap = aufs_mmap, + .open = aufs_open_nondir, + .flush = aufs_flush_nondir, + .release = aufs_release_nondir, + .fsync = aufs_fsync_nondir, + .fasync = aufs_fasync, + /* .sendpage = aufs_sendpage, */ + .setfl = aufs_setfl, + .splice_write = aufs_splice_write, + .splice_read = aufs_splice_read, +#if 0 /* reserved for future use */ + .aio_splice_write = aufs_aio_splice_write, + .aio_splice_read = aufs_aio_splice_read, +#endif + .fallocate = aufs_fallocate, + .copy_file_range = aufs_copy_file_range +}; diff --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c new file mode 100644 index 000000000000..f86a4c24fb26 --- /dev/null +++ b/fs/aufs/fhsm.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2011-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * File-based Hierarchy Storage Management + */ + +#include +#include +#include +#include +#include "aufs.h" + +static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + fhsm = &sbinfo->si_fhsm; + AuDebugOn(!fhsm); + return fhsm->fhsm_bottom; +} + +void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) +{ + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + fhsm = &sbinfo->si_fhsm; + AuDebugOn(!fhsm); + fhsm->fhsm_bottom = bindex; +} + +/* ---------------------------------------------------------------------- */ + +static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) +{ + struct au_br_fhsm *bf; + + bf = br->br_fhsm; + MtxMustLock(&bf->bf_lock); + + return !bf->bf_readable + || time_after(jiffies, + bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); +} + +/* ---------------------------------------------------------------------- */ + +static void au_fhsm_notify(struct super_block *sb, int val) +{ + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + fhsm = &sbinfo->si_fhsm; + if (au_fhsm_pid(fhsm) + && atomic_read(&fhsm->fhsm_readable) != -1) { + atomic_set(&fhsm->fhsm_readable, val); + if (val) + wake_up(&fhsm->fhsm_wqh); + } +} + +static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, + struct aufs_stfs *rstfs, int do_lock, int do_notify) +{ + int err; + struct au_branch *br; + struct au_br_fhsm *bf; + + br = au_sbr(sb, bindex); + AuDebugOn(au_br_rdonly(br)); + bf = br->br_fhsm; + AuDebugOn(!bf); + + if (do_lock) + mutex_lock(&bf->bf_lock); + else + MtxMustLock(&bf->bf_lock); + + /* sb->s_root for NFS is unreliable */ + err = au_br_stfs(br, &bf->bf_stfs); + if (unlikely(err)) { + AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); + goto out; + } + + bf->bf_jiffy = jiffies; + bf->bf_readable = 1; + if (do_notify) + au_fhsm_notify(sb, /*val*/1); + if (rstfs) + *rstfs = bf->bf_stfs; + +out: + if (do_lock) + mutex_unlock(&bf->bf_lock); + au_fhsm_notify(sb, /*val*/1); + + return err; +} + +void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) +{ + int err; + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + struct au_branch *br; + struct au_br_fhsm *bf; + + AuDbg("b%d, force %d\n", bindex, force); + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + fhsm = &sbinfo->si_fhsm; + if (!au_ftest_si(sbinfo, FHSM) + || fhsm->fhsm_bottom == bindex) + return; + + br = au_sbr(sb, bindex); + bf = br->br_fhsm; + AuDebugOn(!bf); + mutex_lock(&bf->bf_lock); + if (force + || au_fhsm_pid(fhsm) + || au_fhsm_test_jiffy(sbinfo, br)) + err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, + /*do_notify*/1); + mutex_unlock(&bf->bf_lock); +} + +void au_fhsm_wrote_all(struct super_block *sb, int force) +{ + aufs_bindex_t bindex, bbot; + struct au_branch *br; + + /* exclude the bottom */ + bbot = au_fhsm_bottom(sb); + for (bindex = 0; bindex < bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_fhsm(br->br_perm)) + au_fhsm_wrote(sb, bindex, force); + } +} + +/* ---------------------------------------------------------------------- */ + +static __poll_t au_fhsm_poll(struct file *file, struct poll_table_struct *wait) +{ + __poll_t mask; + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + + mask = 0; + sbinfo = file->private_data; + fhsm = &sbinfo->si_fhsm; + poll_wait(file, &fhsm->fhsm_wqh, wait); + if (atomic_read(&fhsm->fhsm_readable)) + mask = EPOLLIN /* | EPOLLRDNORM */; + + if (!mask) + AuDbg("mask 0x%x\n", mask); + return mask; +} + +static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, + struct aufs_stfs *stfs, __s16 brid) +{ + int err; + + err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); + if (!err) + err = __put_user(brid, &stbr->brid); + if (unlikely(err)) + err = -EFAULT; + + return err; +} + +static ssize_t au_fhsm_do_read(struct super_block *sb, + struct aufs_stbr __user *stbr, size_t count) +{ + ssize_t err; + int nstbr; + aufs_bindex_t bindex, bbot; + struct au_branch *br; + struct au_br_fhsm *bf; + + /* except the bottom branch */ + err = 0; + nstbr = 0; + bbot = au_fhsm_bottom(sb); + for (bindex = 0; !err && bindex < bbot; bindex++) { + br = au_sbr(sb, bindex); + if (!au_br_fhsm(br->br_perm)) + continue; + + bf = br->br_fhsm; + mutex_lock(&bf->bf_lock); + if (bf->bf_readable) { + err = -EFAULT; + if (count >= sizeof(*stbr)) + err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, + br->br_id); + if (!err) { + bf->bf_readable = 0; + count -= sizeof(*stbr); + nstbr++; + } + } + mutex_unlock(&bf->bf_lock); + } + if (!err) + err = sizeof(*stbr) * nstbr; + + return err; +} + +static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, + loff_t *pos) +{ + ssize_t err; + int readable; + aufs_bindex_t nfhsm, bindex, bbot; + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + struct au_branch *br; + struct super_block *sb; + + err = 0; + sbinfo = file->private_data; + fhsm = &sbinfo->si_fhsm; +need_data: + spin_lock_irq(&fhsm->fhsm_wqh.lock); + if (!atomic_read(&fhsm->fhsm_readable)) { + if (vfsub_file_flags(file) & O_NONBLOCK) + err = -EAGAIN; + else + err = wait_event_interruptible_locked_irq + (fhsm->fhsm_wqh, + atomic_read(&fhsm->fhsm_readable)); + } + spin_unlock_irq(&fhsm->fhsm_wqh.lock); + if (unlikely(err)) + goto out; + + /* sb may already be dead */ + au_rw_read_lock(&sbinfo->si_rwsem); + readable = atomic_read(&fhsm->fhsm_readable); + if (readable > 0) { + sb = sbinfo->si_sb; + AuDebugOn(!sb); + /* exclude the bottom branch */ + nfhsm = 0; + bbot = au_fhsm_bottom(sb); + for (bindex = 0; bindex < bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_fhsm(br->br_perm)) + nfhsm++; + } + err = -EMSGSIZE; + if (nfhsm * sizeof(struct aufs_stbr) <= count) { + atomic_set(&fhsm->fhsm_readable, 0); + err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, + count); + } + } + au_rw_read_unlock(&sbinfo->si_rwsem); + if (!readable) + goto need_data; + +out: + return err; +} + +static int au_fhsm_release(struct inode *inode, struct file *file) +{ + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + + /* sb may already be dead */ + sbinfo = file->private_data; + fhsm = &sbinfo->si_fhsm; + spin_lock(&fhsm->fhsm_spin); + fhsm->fhsm_pid = 0; + spin_unlock(&fhsm->fhsm_spin); + kobject_put(&sbinfo->si_kobj); + + return 0; +} + +static const struct file_operations au_fhsm_fops = { + .owner = THIS_MODULE, + .llseek = noop_llseek, + .read = au_fhsm_read, + .poll = au_fhsm_poll, + .release = au_fhsm_release +}; + +int au_fhsm_fd(struct super_block *sb, int oflags) +{ + int err, fd; + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + + err = -EPERM; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + err = -EINVAL; + if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) + goto out; + + err = 0; + sbinfo = au_sbi(sb); + fhsm = &sbinfo->si_fhsm; + spin_lock(&fhsm->fhsm_spin); + if (!fhsm->fhsm_pid) + fhsm->fhsm_pid = current->pid; + else + err = -EBUSY; + spin_unlock(&fhsm->fhsm_spin); + if (unlikely(err)) + goto out; + + oflags |= O_RDONLY; + /* oflags |= FMODE_NONOTIFY; */ + fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); + err = fd; + if (unlikely(fd < 0)) + goto out_pid; + + /* succeed regardless 'fhsm' status */ + kobject_get(&sbinfo->si_kobj); + si_noflush_read_lock(sb); + if (au_ftest_si(sbinfo, FHSM)) + au_fhsm_wrote_all(sb, /*force*/0); + si_read_unlock(sb); + goto out; /* success */ + +out_pid: + spin_lock(&fhsm->fhsm_spin); + fhsm->fhsm_pid = 0; + spin_unlock(&fhsm->fhsm_spin); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_fhsm_br_alloc(struct au_branch *br) +{ + int err; + + err = 0; + br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); + if (br->br_fhsm) + au_br_fhsm_init(br->br_fhsm); + else + err = -ENOMEM; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_fhsm_fin(struct super_block *sb) +{ + au_fhsm_notify(sb, /*val*/-1); +} + +void au_fhsm_init(struct au_sbinfo *sbinfo) +{ + struct au_fhsm *fhsm; + + fhsm = &sbinfo->si_fhsm; + spin_lock_init(&fhsm->fhsm_spin); + init_waitqueue_head(&fhsm->fhsm_wqh); + atomic_set(&fhsm->fhsm_readable, 0); + fhsm->fhsm_expire + = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); + fhsm->fhsm_bottom = -1; +} + +void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) +{ + sbinfo->si_fhsm.fhsm_expire + = msecs_to_jiffies(sec * MSEC_PER_SEC); +} + +void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) +{ + unsigned int u; + + if (!au_ftest_si(sbinfo, FHSM)) + return; + + u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; + if (u != AUFS_FHSM_CACHE_DEF_SEC) + seq_printf(seq, ",fhsm_sec=%u", u); +} diff --git a/fs/aufs/file.c b/fs/aufs/file.c new file mode 100644 index 000000000000..dbb33855d226 --- /dev/null +++ b/fs/aufs/file.c @@ -0,0 +1,863 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * handling file/dir, and address_space operation + */ + +#ifdef CONFIG_AUFS_DEBUG +#include +#endif +#include +#include "aufs.h" + +/* drop flags for writing */ +unsigned int au_file_roflags(unsigned int flags) +{ + flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); + flags |= O_RDONLY | O_NOATIME; + return flags; +} + +/* common functions to regular file and dir */ +struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, + struct file *file, int force_wr) +{ + struct file *h_file; + struct dentry *h_dentry; + struct inode *h_inode; + struct super_block *sb; + struct au_branch *br; + struct path h_path; + int err; + + /* a race condition can happen between open and unlink/rmdir */ + h_file = ERR_PTR(-ENOENT); + h_dentry = au_h_dptr(dentry, bindex); + if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry))) + goto out; + h_inode = d_inode(h_dentry); + spin_lock(&h_dentry->d_lock); + err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) + /* || !d_inode(dentry)->i_nlink */ + ; + spin_unlock(&h_dentry->d_lock); + if (unlikely(err)) + goto out; + + sb = dentry->d_sb; + br = au_sbr(sb, bindex); + err = au_br_test_oflag(flags, br); + h_file = ERR_PTR(err); + if (unlikely(err)) + goto out; + + /* drop flags for writing */ + if (au_test_ro(sb, bindex, d_inode(dentry))) { + if (force_wr && !(flags & O_WRONLY)) + force_wr = 0; + flags = au_file_roflags(flags); + if (force_wr) { + h_file = ERR_PTR(-EROFS); + flags = au_file_roflags(flags); + if (unlikely(vfsub_native_ro(h_inode) + || IS_APPEND(h_inode))) + goto out; + flags &= ~O_ACCMODE; + flags |= O_WRONLY; + } + } + flags &= ~O_CREAT; + au_lcnt_inc(&br->br_nfiles); + h_path.dentry = h_dentry; + h_path.mnt = au_br_mnt(br); + h_file = vfsub_dentry_open(&h_path, flags); + if (IS_ERR(h_file)) + goto out_br; + + if (flags & __FMODE_EXEC) { + err = deny_write_access(h_file); + if (unlikely(err)) { + fput(h_file); + h_file = ERR_PTR(err); + goto out_br; + } + } + fsnotify_open(h_file); + goto out; /* success */ + +out_br: + au_lcnt_dec(&br->br_nfiles); +out: + return h_file; +} + +static int au_cmoo(struct dentry *dentry) +{ + int err, cmoo, matched; + unsigned int udba; + struct path h_path; + struct au_pin pin; + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = -1, + .bsrc = -1, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + struct inode *delegated; + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct au_fhsm *fhsm; + pid_t pid; + struct au_branch *br; + struct dentry *parent; + struct au_hinode *hdir; + + DiMustWriteLock(dentry); + IiMustWriteLock(d_inode(dentry)); + + err = 0; + if (IS_ROOT(dentry)) + goto out; + cpg.bsrc = au_dbtop(dentry); + if (!cpg.bsrc) + goto out; + + sb = dentry->d_sb; + sbinfo = au_sbi(sb); + fhsm = &sbinfo->si_fhsm; + pid = au_fhsm_pid(fhsm); + rcu_read_lock(); + matched = (pid + && (current->pid == pid + || rcu_dereference(current->real_parent)->pid == pid)); + rcu_read_unlock(); + if (matched) + goto out; + + br = au_sbr(sb, cpg.bsrc); + cmoo = au_br_cmoo(br->br_perm); + if (!cmoo) + goto out; + if (!d_is_reg(dentry)) + cmoo &= AuBrAttr_COO_ALL; + if (!cmoo) + goto out; + + parent = dget_parent(dentry); + di_write_lock_parent(parent); + err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); + cpg.bdst = err; + if (unlikely(err < 0)) { + err = 0; /* there is no upper writable branch */ + goto out_dgrade; + } + AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); + + /* do not respect the coo attrib for the target branch */ + err = au_cpup_dirs(dentry, cpg.bdst); + if (unlikely(err)) + goto out_dgrade; + + di_downgrade_lock(parent, AuLock_IR); + udba = au_opt_udba(sb); + err = au_pin(&pin, dentry, cpg.bdst, udba, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out_parent; + + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + if (unlikely(err)) + goto out_parent; + if (!(cmoo & AuBrWAttr_MOO)) + goto out_parent; /* success */ + + err = au_pin(&pin, dentry, cpg.bsrc, udba, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out_parent; + + h_path.mnt = au_br_mnt(br); + h_path.dentry = au_h_dptr(dentry, cpg.bsrc); + hdir = au_hi(d_inode(parent), cpg.bsrc); + delegated = NULL; + err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); + au_unpin(&pin); + /* todo: keep h_dentry or not? */ + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) { + pr_err("unlink %pd after coo failed (%d), ignored\n", + dentry, err); + err = 0; + } + goto out_parent; /* success */ + +out_dgrade: + di_downgrade_lock(parent, AuLock_IR); +out_parent: + di_read_unlock(parent, AuLock_IR); + dput(parent); +out: + AuTraceErr(err); + return err; +} + +int au_do_open(struct file *file, struct au_do_open_args *args) +{ + int err, aopen = args->aopen; + struct dentry *dentry; + struct au_finfo *finfo; + + if (!aopen) + err = au_finfo_init(file, args->fidir); + else { + lockdep_off(); + err = au_finfo_init(file, args->fidir); + lockdep_on(); + } + if (unlikely(err)) + goto out; + + dentry = file->f_path.dentry; + AuDebugOn(IS_ERR_OR_NULL(dentry)); + di_write_lock_child(dentry); + err = au_cmoo(dentry); + di_downgrade_lock(dentry, AuLock_IR); + if (!err) { + if (!aopen) + err = args->open(file, vfsub_file_flags(file), NULL); + else { + lockdep_off(); + err = args->open(file, vfsub_file_flags(file), + args->h_file); + lockdep_on(); + } + } + di_read_unlock(dentry, AuLock_IR); + + finfo = au_fi(file); + if (!err) { + finfo->fi_file = file; + au_hbl_add(&finfo->fi_hlist, + &au_sbi(file->f_path.dentry->d_sb)->si_files); + } + if (!aopen) + fi_write_unlock(file); + else { + lockdep_off(); + fi_write_unlock(file); + lockdep_on(); + } + if (unlikely(err)) { + finfo->fi_hdir = NULL; + au_finfo_fin(file); + } + +out: + AuTraceErr(err); + return err; +} + +int au_reopen_nondir(struct file *file) +{ + int err; + aufs_bindex_t btop; + struct dentry *dentry; + struct au_branch *br; + struct file *h_file, *h_file_tmp; + + dentry = file->f_path.dentry; + btop = au_dbtop(dentry); + br = au_sbr(dentry->d_sb, btop); + h_file_tmp = NULL; + if (au_fbtop(file) == btop) { + h_file = au_hf_top(file); + if (file->f_mode == h_file->f_mode) + return 0; /* success */ + h_file_tmp = h_file; + get_file(h_file_tmp); + au_lcnt_inc(&br->br_nfiles); + au_set_h_fptr(file, btop, NULL); + } + AuDebugOn(au_fi(file)->fi_hdir); + /* + * it can happen + * file exists on both of rw and ro + * open --> dbtop and fbtop are both 0 + * prepend a branch as rw, "rw" become ro + * remove rw/file + * delete the top branch, "rw" becomes rw again + * --> dbtop is 1, fbtop is still 0 + * write --> fbtop is 0 but dbtop is 1 + */ + /* AuDebugOn(au_fbtop(file) < btop); */ + + h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, + file, /*force_wr*/0); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) { + if (h_file_tmp) { + /* revert */ + au_set_h_fptr(file, btop, h_file_tmp); + h_file_tmp = NULL; + } + goto out; /* todo: close all? */ + } + + err = 0; + au_set_fbtop(file, btop); + au_set_h_fptr(file, btop, h_file); + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + +out: + if (h_file_tmp) { + fput(h_file_tmp); + au_lcnt_dec(&br->br_nfiles); + } + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, + struct dentry *hi_wh) +{ + int err; + aufs_bindex_t btop; + struct au_dinfo *dinfo; + struct dentry *h_dentry; + struct au_hdentry *hdp; + + dinfo = au_di(file->f_path.dentry); + AuRwMustWriteLock(&dinfo->di_rwsem); + + btop = dinfo->di_btop; + dinfo->di_btop = btgt; + hdp = au_hdentry(dinfo, btgt); + h_dentry = hdp->hd_dentry; + hdp->hd_dentry = hi_wh; + err = au_reopen_nondir(file); + hdp->hd_dentry = h_dentry; + dinfo->di_btop = btop; + + return err; +} + +static int au_ready_to_write_wh(struct file *file, loff_t len, + aufs_bindex_t bcpup, struct au_pin *pin) +{ + int err; + struct inode *inode, *h_inode; + struct dentry *h_dentry, *hi_wh; + struct au_cp_generic cpg = { + .dentry = file->f_path.dentry, + .bdst = bcpup, + .bsrc = -1, + .len = len, + .pin = pin + }; + + au_update_dbtop(cpg.dentry); + inode = d_inode(cpg.dentry); + h_inode = NULL; + if (au_dbtop(cpg.dentry) <= bcpup + && au_dbbot(cpg.dentry) >= bcpup) { + h_dentry = au_h_dptr(cpg.dentry, bcpup); + if (h_dentry && d_is_positive(h_dentry)) + h_inode = d_inode(h_dentry); + } + hi_wh = au_hi_wh(inode, bcpup); + if (!hi_wh && !h_inode) + err = au_sio_cpup_wh(&cpg, file); + else + /* already copied-up after unlink */ + err = au_reopen_wh(file, bcpup, hi_wh); + + if (!err + && (inode->i_nlink > 1 + || (inode->i_state & I_LINKABLE)) + && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) + au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); + + return err; +} + +/* + * prepare the @file for writing. + */ +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) +{ + int err; + aufs_bindex_t dbtop; + struct dentry *parent; + struct inode *inode; + struct super_block *sb; + struct file *h_file; + struct au_cp_generic cpg = { + .dentry = file->f_path.dentry, + .bdst = -1, + .bsrc = -1, + .len = len, + .pin = pin, + .flags = AuCpup_DTIME + }; + + sb = cpg.dentry->d_sb; + inode = d_inode(cpg.dentry); + cpg.bsrc = au_fbtop(file); + err = au_test_ro(sb, cpg.bsrc, inode); + if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { + err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, + /*flags*/0); + goto out; + } + + /* need to cpup or reopen */ + parent = dget_parent(cpg.dentry); + di_write_lock_parent(parent); + err = AuWbrCopyup(au_sbi(sb), cpg.dentry); + cpg.bdst = err; + if (unlikely(err < 0)) + goto out_dgrade; + err = 0; + + if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { + err = au_cpup_dirs(cpg.dentry, cpg.bdst); + if (unlikely(err)) + goto out_dgrade; + } + + err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out_dgrade; + + dbtop = au_dbtop(cpg.dentry); + if (dbtop <= cpg.bdst) + cpg.bsrc = cpg.bdst; + + if (dbtop <= cpg.bdst /* just reopen */ + || !d_unhashed(cpg.dentry) /* copyup and reopen */ + ) { + h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); + if (IS_ERR(h_file)) + err = PTR_ERR(h_file); + else { + di_downgrade_lock(parent, AuLock_IR); + if (dbtop > cpg.bdst) + err = au_sio_cpup_simple(&cpg); + if (!err) + err = au_reopen_nondir(file); + au_h_open_post(cpg.dentry, cpg.bsrc, h_file); + } + } else { /* copyup as wh and reopen */ + /* + * since writable hfsplus branch is not supported, + * h_open_pre/post() are unnecessary. + */ + err = au_ready_to_write_wh(file, len, cpg.bdst, pin); + di_downgrade_lock(parent, AuLock_IR); + } + + if (!err) { + au_pin_set_parent_lflag(pin, /*lflag*/0); + goto out_dput; /* success */ + } + au_unpin(pin); + goto out_unlock; + +out_dgrade: + di_downgrade_lock(parent, AuLock_IR); +out_unlock: + di_read_unlock(parent, AuLock_IR); +out_dput: + dput(parent); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_do_flush(struct file *file, fl_owner_t id, + int (*flush)(struct file *file, fl_owner_t id)) +{ + int err; + struct super_block *sb; + struct inode *inode; + + inode = file_inode(file); + sb = inode->i_sb; + si_noflush_read_lock(sb); + fi_read_lock(file); + ii_read_lock_child(inode); + + err = flush(file, id); + au_cpup_attr_timesizes(inode); + + ii_read_unlock(inode); + fi_read_unlock(file); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_file_refresh_by_inode(struct file *file, int *need_reopen) +{ + int err; + struct au_pin pin; + struct au_finfo *finfo; + struct dentry *parent, *hi_wh; + struct inode *inode; + struct super_block *sb; + struct au_cp_generic cpg = { + .dentry = file->f_path.dentry, + .bdst = -1, + .bsrc = -1, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME + }; + + FiMustWriteLock(file); + + err = 0; + finfo = au_fi(file); + sb = cpg.dentry->d_sb; + inode = d_inode(cpg.dentry); + cpg.bdst = au_ibtop(inode); + if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) + goto out; + + parent = dget_parent(cpg.dentry); + if (au_test_ro(sb, cpg.bdst, inode)) { + di_read_lock_parent(parent, !AuLock_IR); + err = AuWbrCopyup(au_sbi(sb), cpg.dentry); + cpg.bdst = err; + di_read_unlock(parent, !AuLock_IR); + if (unlikely(err < 0)) + goto out_parent; + err = 0; + } + + di_read_lock_parent(parent, AuLock_IR); + hi_wh = au_hi_wh(inode, cpg.bdst); + if (!S_ISDIR(inode->i_mode) + && au_opt_test(au_mntflags(sb), PLINK) + && au_plink_test(inode) + && !d_unhashed(cpg.dentry) + && cpg.bdst < au_dbtop(cpg.dentry)) { + err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); + if (unlikely(err)) + goto out_unlock; + + /* always superio. */ + err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (!err) { + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + } + } else if (hi_wh) { + /* already copied-up after unlink */ + err = au_reopen_wh(file, cpg.bdst, hi_wh); + *need_reopen = 0; + } + +out_unlock: + di_read_unlock(parent, AuLock_IR); +out_parent: + dput(parent); +out: + return err; +} + +static void au_do_refresh_dir(struct file *file) +{ + aufs_bindex_t bindex, bbot, new_bindex, brid; + struct au_hfile *p, tmp, *q; + struct au_finfo *finfo; + struct super_block *sb; + struct au_fidir *fidir; + + FiMustWriteLock(file); + + sb = file->f_path.dentry->d_sb; + finfo = au_fi(file); + fidir = finfo->fi_hdir; + AuDebugOn(!fidir); + p = fidir->fd_hfile + finfo->fi_btop; + brid = p->hf_br->br_id; + bbot = fidir->fd_bbot; + for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) { + if (!p->hf_file) + continue; + + new_bindex = au_br_index(sb, p->hf_br->br_id); + if (new_bindex == bindex) + continue; + if (new_bindex < 0) { + au_set_h_fptr(file, bindex, NULL); + continue; + } + + /* swap two lower inode, and loop again */ + q = fidir->fd_hfile + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hf_file) { + bindex--; + p--; + } + } + + p = fidir->fd_hfile; + if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) { + bbot = au_sbbot(sb); + for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; + finfo->fi_btop++, p++) + if (p->hf_file) { + if (file_inode(p->hf_file)) + break; + au_hfput(p, /*execed*/0); + } + } else { + bbot = au_br_index(sb, brid); + for (finfo->fi_btop = 0; finfo->fi_btop < bbot; + finfo->fi_btop++, p++) + if (p->hf_file) + au_hfput(p, /*execed*/0); + bbot = au_sbbot(sb); + } + + p = fidir->fd_hfile + bbot; + for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; + fidir->fd_bbot--, p--) + if (p->hf_file) { + if (file_inode(p->hf_file)) + break; + au_hfput(p, /*execed*/0); + } + AuDebugOn(fidir->fd_bbot < finfo->fi_btop); +} + +/* + * after branch manipulating, refresh the file. + */ +static int refresh_file(struct file *file, int (*reopen)(struct file *file)) +{ + int err, need_reopen, nbr; + aufs_bindex_t bbot, bindex; + struct dentry *dentry; + struct super_block *sb; + struct au_finfo *finfo; + struct au_hfile *hfile; + + dentry = file->f_path.dentry; + sb = dentry->d_sb; + nbr = au_sbbot(sb) + 1; + finfo = au_fi(file); + if (!finfo->fi_hdir) { + hfile = &finfo->fi_htop; + AuDebugOn(!hfile->hf_file); + bindex = au_br_index(sb, hfile->hf_br->br_id); + AuDebugOn(bindex < 0); + if (bindex != finfo->fi_btop) + au_set_fbtop(file, bindex); + } else { + err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0); + if (unlikely(err)) + goto out; + au_do_refresh_dir(file); + } + + err = 0; + need_reopen = 1; + if (!au_test_mmapped(file)) + err = au_file_refresh_by_inode(file, &need_reopen); + if (finfo->fi_hdir) + /* harmless if err */ + au_fidir_realloc(finfo, nbr, /*may_shrink*/1); + if (!err && need_reopen && !d_unlinked(dentry)) + err = reopen(file); + if (!err) { + au_update_figen(file); + goto out; /* success */ + } + + /* error, close all lower files */ + if (finfo->fi_hdir) { + bbot = au_fbbot_dir(file); + for (bindex = au_fbtop(file); bindex <= bbot; bindex++) + au_set_h_fptr(file, bindex, NULL); + } + +out: + return err; +} + +/* common function to regular file and dir */ +int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), + int wlock, unsigned int fi_lsc) +{ + int err; + unsigned int sigen, figen; + aufs_bindex_t btop; + unsigned char pseudo_link; + struct dentry *dentry; + struct inode *inode; + + err = 0; + dentry = file->f_path.dentry; + inode = d_inode(dentry); + sigen = au_sigen(dentry->d_sb); + fi_write_lock_nested(file, fi_lsc); + figen = au_figen(file); + if (!fi_lsc) + di_write_lock_child(dentry); + else + di_write_lock_child2(dentry); + btop = au_dbtop(dentry); + pseudo_link = (btop != au_ibtop(inode)); + if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { + if (!wlock) { + di_downgrade_lock(dentry, AuLock_IR); + fi_downgrade_lock(file); + } + goto out; /* success */ + } + + AuDbg("sigen %d, figen %d\n", sigen, figen); + if (au_digen_test(dentry, sigen)) { + err = au_reval_dpath(dentry, sigen); + AuDebugOn(!err && au_digen_test(dentry, sigen)); + } + + if (!err) + err = refresh_file(file, reopen); + if (!err) { + if (!wlock) { + di_downgrade_lock(dentry, AuLock_IR); + fi_downgrade_lock(file); + } + } else { + di_write_unlock(dentry); + fi_write_unlock(file); + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* cf. aufs_nopage() */ +/* for madvise(2) */ +static int aufs_readpage(struct file *file __maybe_unused, struct page *page) +{ + unlock_page(page); + return 0; +} + +/* it will never be called, but necessary to support O_DIRECT */ +static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +{ BUG(); return 0; } + +/* they will never be called. */ +#ifdef CONFIG_AUFS_DEBUG +static int aufs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ AuUnsupport(); return 0; } +static int aufs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ AuUnsupport(); return 0; } +static int aufs_writepage(struct page *page, struct writeback_control *wbc) +{ AuUnsupport(); return 0; } + +static int aufs_set_page_dirty(struct page *page) +{ AuUnsupport(); return 0; } +static void aufs_invalidatepage(struct page *page, unsigned int offset, + unsigned int length) +{ AuUnsupport(); } +static int aufs_releasepage(struct page *page, gfp_t gfp) +{ AuUnsupport(); return 0; } +#if 0 /* called by memory compaction regardless file */ +static int aufs_migratepage(struct address_space *mapping, struct page *newpage, + struct page *page, enum migrate_mode mode) +{ AuUnsupport(); return 0; } +#endif +static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) +{ AuUnsupport(); return true; } +static void aufs_putback_page(struct page *page) +{ AuUnsupport(); } +static int aufs_launder_page(struct page *page) +{ AuUnsupport(); return 0; } +static int aufs_is_partially_uptodate(struct page *page, + unsigned long from, + unsigned long count) +{ AuUnsupport(); return 0; } +static void aufs_is_dirty_writeback(struct page *page, bool *dirty, + bool *writeback) +{ AuUnsupport(); } +static int aufs_error_remove_page(struct address_space *mapping, + struct page *page) +{ AuUnsupport(); return 0; } +static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, + sector_t *span) +{ AuUnsupport(); return 0; } +static void aufs_swap_deactivate(struct file *file) +{ AuUnsupport(); } +#endif /* CONFIG_AUFS_DEBUG */ + +const struct address_space_operations aufs_aop = { + .readpage = aufs_readpage, + .direct_IO = aufs_direct_IO, +#ifdef CONFIG_AUFS_DEBUG + .writepage = aufs_writepage, + /* no writepages, because of writepage */ + .set_page_dirty = aufs_set_page_dirty, + /* no readpages, because of readpage */ + .write_begin = aufs_write_begin, + .write_end = aufs_write_end, + /* no bmap, no block device */ + .invalidatepage = aufs_invalidatepage, + .releasepage = aufs_releasepage, + /* is fallback_migrate_page ok? */ + /* .migratepage = aufs_migratepage, */ + .isolate_page = aufs_isolate_page, + .putback_page = aufs_putback_page, + .launder_page = aufs_launder_page, + .is_partially_uptodate = aufs_is_partially_uptodate, + .is_dirty_writeback = aufs_is_dirty_writeback, + .error_remove_page = aufs_error_remove_page, + .swap_activate = aufs_swap_activate, + .swap_deactivate = aufs_swap_deactivate +#endif /* CONFIG_AUFS_DEBUG */ +}; diff --git a/fs/aufs/file.h b/fs/aufs/file.h new file mode 100644 index 000000000000..c679a19df528 --- /dev/null +++ b/fs/aufs/file.h @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file operations + */ + +#ifndef __AUFS_FILE_H__ +#define __AUFS_FILE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include "rwsem.h" + +struct au_branch; +struct au_hfile { + struct file *hf_file; + struct au_branch *hf_br; +}; + +struct au_vdir; +struct au_fidir { + aufs_bindex_t fd_bbot; + aufs_bindex_t fd_nent; + struct au_vdir *fd_vdir_cache; + struct au_hfile fd_hfile[]; +}; + +static inline int au_fidir_sz(int nent) +{ + AuDebugOn(nent < 0); + return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; +} + +struct au_finfo { + atomic_t fi_generation; + + struct au_rwsem fi_rwsem; + aufs_bindex_t fi_btop; + + /* do not union them */ + struct { /* for non-dir */ + struct au_hfile fi_htop; + atomic_t fi_mmapped; + }; + struct au_fidir *fi_hdir; /* for dir only */ + + struct hlist_bl_node fi_hlist; + struct file *fi_file; /* very ugly */ + struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ + +/* file.c */ +extern const struct address_space_operations aufs_aop; +unsigned int au_file_roflags(unsigned int flags); +struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, + struct file *file, int force_wr); +struct au_do_open_args { + int aopen; + int (*open)(struct file *file, int flags, + struct file *h_file); + struct au_fidir *fidir; + struct file *h_file; +}; +int au_do_open(struct file *file, struct au_do_open_args *args); +int au_reopen_nondir(struct file *file); +struct au_pin; +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); +int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), + int wlock, unsigned int fi_lsc); +int au_do_flush(struct file *file, fl_owner_t id, + int (*flush)(struct file *file, fl_owner_t id)); + +/* poll.c */ +#ifdef CONFIG_AUFS_POLL +__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); +#endif + +#ifdef CONFIG_AUFS_BR_HFSPLUS +/* hfsplus.c */ +struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, + int force_wr); +void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file); +#else +AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, + aufs_bindex_t bindex, int force_wr) +AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file); +#endif + +/* f_op.c */ +extern const struct file_operations aufs_file_fop; +int au_do_open_nondir(struct file *file, int flags, struct file *h_file); +int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); +struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); + +/* finfo.c */ +void au_hfput(struct au_hfile *hf, int execed); +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, + struct file *h_file); + +void au_update_figen(struct file *file); +struct au_fidir *au_fidir_alloc(struct super_block *sb); +int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); + +void au_fi_init_once(void *_fi); +void au_finfo_fin(struct file *file); +int au_finfo_init(struct file *file, struct au_fidir *fidir); + +/* ioctl.c */ +long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, + unsigned long arg); +long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, + unsigned long arg); +#endif + +/* ---------------------------------------------------------------------- */ + +static inline struct au_finfo *au_fi(struct file *file) +{ + return file->private_data; +} + +/* ---------------------------------------------------------------------- */ + +#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) +#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) +#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) +#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) +/* +#define fi_read_trylock_nested(f) \ + au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) +#define fi_write_trylock_nested(f) \ + au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) +*/ + +#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) +#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) +#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) + +/* lock subclass for finfo */ +enum { + AuLsc_FI_1, + AuLsc_FI_2 +}; + +static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) +{ + au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); +} + +static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) +{ + au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); +} + +/* + * fi_read_lock_1, fi_write_lock_1, + * fi_read_lock_2, fi_write_lock_2 + */ +#define AuReadLockFunc(name) \ +static inline void fi_read_lock_##name(struct file *f) \ +{ fi_read_lock_nested(f, AuLsc_FI_##name); } + +#define AuWriteLockFunc(name) \ +static inline void fi_write_lock_##name(struct file *f) \ +{ fi_write_lock_nested(f, AuLsc_FI_##name); } + +#define AuRWLockFuncs(name) \ + AuReadLockFunc(name) \ + AuWriteLockFunc(name) + +AuRWLockFuncs(1); +AuRWLockFuncs(2); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) +#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) +#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) + +/* ---------------------------------------------------------------------- */ + +/* todo: hard/soft set? */ +static inline aufs_bindex_t au_fbtop(struct file *file) +{ + FiMustAnyLock(file); + return au_fi(file)->fi_btop; +} + +static inline aufs_bindex_t au_fbbot_dir(struct file *file) +{ + FiMustAnyLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + return au_fi(file)->fi_hdir->fd_bbot; +} + +static inline struct au_vdir *au_fvdir_cache(struct file *file) +{ + FiMustAnyLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + return au_fi(file)->fi_hdir->fd_vdir_cache; +} + +static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) +{ + FiMustWriteLock(file); + au_fi(file)->fi_btop = bindex; +} + +static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) +{ + FiMustWriteLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + au_fi(file)->fi_hdir->fd_bbot = bindex; +} + +static inline void au_set_fvdir_cache(struct file *file, + struct au_vdir *vdir_cache) +{ + FiMustWriteLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; +} + +static inline struct file *au_hf_top(struct file *file) +{ + FiMustAnyLock(file); + AuDebugOn(au_fi(file)->fi_hdir); + return au_fi(file)->fi_htop.hf_file; +} + +static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) +{ + FiMustAnyLock(file); + AuDebugOn(!au_fi(file)->fi_hdir); + return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; +} + +/* todo: memory barrier? */ +static inline unsigned int au_figen(struct file *f) +{ + return atomic_read(&au_fi(f)->fi_generation); +} + +static inline void au_set_mmapped(struct file *f) +{ + if (atomic_inc_return(&au_fi(f)->fi_mmapped)) + return; + pr_warn("fi_mmapped wrapped around\n"); + while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) + ; +} + +static inline void au_unset_mmapped(struct file *f) +{ + atomic_dec(&au_fi(f)->fi_mmapped); +} + +static inline int au_test_mmapped(struct file *f) +{ + return atomic_read(&au_fi(f)->fi_mmapped); +} + +/* customize vma->vm_file */ + +static inline void au_do_vm_file_reset(struct vm_area_struct *vma, + struct file *file) +{ + struct file *f; + + f = vma->vm_file; + get_file(file); + vma->vm_file = file; + fput(f); +} + +#ifdef CONFIG_MMU +#define AuDbgVmRegion(file, vma) do {} while (0) + +static inline void au_vm_file_reset(struct vm_area_struct *vma, + struct file *file) +{ + au_do_vm_file_reset(vma, file); +} +#else +#define AuDbgVmRegion(file, vma) \ + AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) + +static inline void au_vm_file_reset(struct vm_area_struct *vma, + struct file *file) +{ + struct file *f; + + au_do_vm_file_reset(vma, file); + f = vma->vm_region->vm_file; + get_file(file); + vma->vm_region->vm_file = file; + fput(f); +} +#endif /* CONFIG_MMU */ + +/* handle vma->vm_prfile */ +static inline void au_vm_prfile_set(struct vm_area_struct *vma, + struct file *file) +{ + get_file(file); + vma->vm_prfile = file; +#ifndef CONFIG_MMU + get_file(file); + vma->vm_region->vm_prfile = file; +#endif +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FILE_H__ */ diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c new file mode 100644 index 000000000000..448c5e9cd85d --- /dev/null +++ b/fs/aufs/finfo.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * file private data + */ + +#include "aufs.h" + +void au_hfput(struct au_hfile *hf, int execed) +{ + if (execed) + allow_write_access(hf->hf_file); + fput(hf->hf_file); + hf->hf_file = NULL; + au_lcnt_dec(&hf->hf_br->br_nfiles); + hf->hf_br = NULL; +} + +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) +{ + struct au_finfo *finfo = au_fi(file); + struct au_hfile *hf; + struct au_fidir *fidir; + + fidir = finfo->fi_hdir; + if (!fidir) { + AuDebugOn(finfo->fi_btop != bindex); + hf = &finfo->fi_htop; + } else + hf = fidir->fd_hfile + bindex; + + if (hf && hf->hf_file) + au_hfput(hf, vfsub_file_execed(file)); + if (val) { + FiMustWriteLock(file); + AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); + hf->hf_file = val; + hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); + } +} + +void au_update_figen(struct file *file) +{ + atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); + /* smp_mb(); */ /* atomic_set */ +} + +/* ---------------------------------------------------------------------- */ + +struct au_fidir *au_fidir_alloc(struct super_block *sb) +{ + struct au_fidir *fidir; + int nbr; + + nbr = au_sbbot(sb) + 1; + if (nbr < 2) + nbr = 2; /* initial allocate for 2 branches */ + fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); + if (fidir) { + fidir->fd_bbot = -1; + fidir->fd_nent = nbr; + } + + return fidir; +} + +int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink) +{ + int err; + struct au_fidir *fidir, *p; + + AuRwMustWriteLock(&finfo->fi_rwsem); + fidir = finfo->fi_hdir; + AuDebugOn(!fidir); + + err = -ENOMEM; + p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), + GFP_NOFS, may_shrink); + if (p) { + p->fd_nent = nbr; + finfo->fi_hdir = p; + err = 0; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_finfo_fin(struct file *file) +{ + struct au_finfo *finfo; + + au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); + + finfo = au_fi(file); + AuDebugOn(finfo->fi_hdir); + AuRwDestroy(&finfo->fi_rwsem); + au_cache_free_finfo(finfo); +} + +void au_fi_init_once(void *_finfo) +{ + struct au_finfo *finfo = _finfo; + + au_rw_init(&finfo->fi_rwsem); +} + +int au_finfo_init(struct file *file, struct au_fidir *fidir) +{ + int err; + struct au_finfo *finfo; + struct dentry *dentry; + + err = -ENOMEM; + dentry = file->f_path.dentry; + finfo = au_cache_alloc_finfo(); + if (unlikely(!finfo)) + goto out; + + err = 0; + au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles); + au_rw_write_lock(&finfo->fi_rwsem); + finfo->fi_btop = -1; + finfo->fi_hdir = fidir; + atomic_set(&finfo->fi_generation, au_digen(dentry)); + /* smp_mb(); */ /* atomic_set */ + + file->private_data = finfo; + +out: + return err; +} diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h new file mode 100644 index 000000000000..510bd87e9404 --- /dev/null +++ b/fs/aufs/fstype.h @@ -0,0 +1,401 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * judging filesystem type + */ + +#ifndef __AUFS_FSTYPE_H__ +#define __AUFS_FSTYPE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +static inline int au_test_aufs(struct super_block *sb) +{ + return sb->s_magic == AUFS_SUPER_MAGIC; +} + +static inline const char *au_sbtype(struct super_block *sb) +{ + return sb->s_type->name; +} + +static inline int au_test_iso9660(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_ISO9660_FS) + return sb->s_magic == ISOFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_romfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_ROMFS_FS) + return sb->s_magic == ROMFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_cramfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_CRAMFS) + return sb->s_magic == CRAMFS_MAGIC; +#endif + return 0; +} + +static inline int au_test_nfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_NFS_FS) + return sb->s_magic == NFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_fuse(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_FUSE_FS) + return sb->s_magic == FUSE_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_xfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_XFS_FS) + return sb->s_magic == XFS_SB_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_TMPFS + return sb->s_magic == TMPFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_ECRYPT_FS) + return !strcmp(au_sbtype(sb), "ecryptfs"); +#else + return 0; +#endif +} + +static inline int au_test_ramfs(struct super_block *sb) +{ + return sb->s_magic == RAMFS_MAGIC; +} + +static inline int au_test_ubifs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_UBIFS_FS) + return sb->s_magic == UBIFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_procfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_PROC_FS + return sb->s_magic == PROC_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_sysfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_SYSFS + return sb->s_magic == SYSFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_configfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_CONFIGFS_FS) + return sb->s_magic == CONFIGFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_minix(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_MINIX_FS) + return sb->s_magic == MINIX3_SUPER_MAGIC + || sb->s_magic == MINIX2_SUPER_MAGIC + || sb->s_magic == MINIX2_SUPER_MAGIC2 + || sb->s_magic == MINIX_SUPER_MAGIC + || sb->s_magic == MINIX_SUPER_MAGIC2; +#else + return 0; +#endif +} + +static inline int au_test_fat(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_FAT_FS) + return sb->s_magic == MSDOS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_msdos(struct super_block *sb) +{ + return au_test_fat(sb); +} + +static inline int au_test_vfat(struct super_block *sb) +{ + return au_test_fat(sb); +} + +static inline int au_test_securityfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_SECURITYFS + return sb->s_magic == SECURITYFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_squashfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_SQUASHFS) + return sb->s_magic == SQUASHFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_btrfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_BTRFS_FS) + return sb->s_magic == BTRFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_xenfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_XENFS) + return sb->s_magic == XENFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_debugfs(struct super_block *sb __maybe_unused) +{ +#ifdef CONFIG_DEBUG_FS + return sb->s_magic == DEBUGFS_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_nilfs(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_NILFS) + return sb->s_magic == NILFS_SUPER_MAGIC; +#else + return 0; +#endif +} + +static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) +{ +#if IS_ENABLED(CONFIG_HFSPLUS_FS) + return sb->s_magic == HFSPLUS_SUPER_MAGIC; +#else + return 0; +#endif +} + +/* ---------------------------------------------------------------------- */ +/* + * they can't be an aufs branch. + */ +static inline int au_test_fs_unsuppoted(struct super_block *sb) +{ + return +#ifndef CONFIG_AUFS_BR_RAMFS + au_test_ramfs(sb) || +#endif + au_test_procfs(sb) + || au_test_sysfs(sb) + || au_test_configfs(sb) + || au_test_debugfs(sb) + || au_test_securityfs(sb) + || au_test_xenfs(sb) + || au_test_ecryptfs(sb) + /* || !strcmp(au_sbtype(sb), "unionfs") */ + || au_test_aufs(sb); /* will be supported in next version */ +} + +static inline int au_test_fs_remote(struct super_block *sb) +{ + return !au_test_tmpfs(sb) +#ifdef CONFIG_AUFS_BR_RAMFS + && !au_test_ramfs(sb) +#endif + && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); +} + +/* ---------------------------------------------------------------------- */ + +/* + * Note: these functions (below) are created after reading ->getattr() in all + * filesystems under linux/fs. it means we have to do so in every update... + */ + +/* + * some filesystems require getattr to refresh the inode attributes before + * referencing. + * in most cases, we can rely on the inode attribute in NFS (or every remote fs) + * and leave the work for d_revalidate() + */ +static inline int au_test_fs_refresh_iattr(struct super_block *sb) +{ + return au_test_nfs(sb) + || au_test_fuse(sb) + /* || au_test_btrfs(sb) */ /* untested */ + ; +} + +/* + * filesystems which don't maintain i_size or i_blocks. + */ +static inline int au_test_fs_bad_iattr_size(struct super_block *sb) +{ + return au_test_xfs(sb) + || au_test_btrfs(sb) + || au_test_ubifs(sb) + || au_test_hfsplus(sb) /* maintained, but incorrect */ + /* || au_test_minix(sb) */ /* untested */ + ; +} + +/* + * filesystems which don't store the correct value in some of their inode + * attributes. + */ +static inline int au_test_fs_bad_iattr(struct super_block *sb) +{ + return au_test_fs_bad_iattr_size(sb) + || au_test_fat(sb) + || au_test_msdos(sb) + || au_test_vfat(sb); +} + +/* they don't check i_nlink in link(2) */ +static inline int au_test_fs_no_limit_nlink(struct super_block *sb) +{ + return au_test_tmpfs(sb) +#ifdef CONFIG_AUFS_BR_RAMFS + || au_test_ramfs(sb) +#endif + || au_test_ubifs(sb) + || au_test_hfsplus(sb); +} + +/* + * filesystems which sets S_NOATIME and S_NOCMTIME. + */ +static inline int au_test_fs_notime(struct super_block *sb) +{ + return au_test_nfs(sb) + || au_test_fuse(sb) + || au_test_ubifs(sb) + ; +} + +/* temporary support for i#1 in cramfs */ +static inline int au_test_fs_unique_ino(struct inode *inode) +{ + if (au_test_cramfs(inode->i_sb)) + return inode->i_ino != 1; + return 1; +} + +/* ---------------------------------------------------------------------- */ + +/* + * the filesystem where the xino files placed must support i/o after unlink and + * maintain i_size and i_blocks. + */ +static inline int au_test_fs_bad_xino(struct super_block *sb) +{ + return au_test_fs_remote(sb) + || au_test_fs_bad_iattr_size(sb) + /* don't want unnecessary work for xino */ + || au_test_aufs(sb) + || au_test_ecryptfs(sb) + || au_test_nilfs(sb); +} + +static inline int au_test_fs_trunc_xino(struct super_block *sb) +{ + return au_test_tmpfs(sb) + || au_test_ramfs(sb); +} + +/* + * test if the @sb is real-readonly. + */ +static inline int au_test_fs_rr(struct super_block *sb) +{ + return au_test_squashfs(sb) + || au_test_iso9660(sb) + || au_test_cramfs(sb) + || au_test_romfs(sb); +} + +/* + * test if the @inode is nfs with 'noacl' option + * NFS always sets SB_POSIXACL regardless its mount option 'noacl.' + */ +static inline int au_test_nfs_noacl(struct inode *inode) +{ + return au_test_nfs(inode->i_sb) + /* && IS_POSIXACL(inode) */ + && !nfs_server_capable(inode, NFS_CAP_ACLS); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FSTYPE_H__ */ diff --git a/fs/aufs/hbl.h b/fs/aufs/hbl.h new file mode 100644 index 000000000000..6db65b16b08a --- /dev/null +++ b/fs/aufs/hbl.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * helpers for hlist_bl.h + */ + +#ifndef __AUFS_HBL_H__ +#define __AUFS_HBL_H__ + +#ifdef __KERNEL__ + +#include + +static inline void au_hbl_add(struct hlist_bl_node *node, + struct hlist_bl_head *hbl) +{ + hlist_bl_lock(hbl); + hlist_bl_add_head(node, hbl); + hlist_bl_unlock(hbl); +} + +static inline void au_hbl_del(struct hlist_bl_node *node, + struct hlist_bl_head *hbl) +{ + hlist_bl_lock(hbl); + hlist_bl_del(node); + hlist_bl_unlock(hbl); +} + +#define au_hbl_for_each(pos, head) \ + for (pos = hlist_bl_first(head); \ + pos; \ + pos = pos->next) + +static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl) +{ + unsigned long cnt; + struct hlist_bl_node *pos; + + cnt = 0; + hlist_bl_lock(hbl); + au_hbl_for_each(pos, hbl) + cnt++; + hlist_bl_unlock(hbl); + return cnt; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_HBL_H__ */ diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c new file mode 100644 index 000000000000..6a330a41c08c --- /dev/null +++ b/fs/aufs/hfsnotify.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * fsnotify for the lower directories + */ + +#include "aufs.h" + +/* FS_IN_IGNORED is unnecessary */ +static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE + | FS_CREATE | FS_EVENT_ON_CHILD); +static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); +static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); + +static void au_hfsn_free_mark(struct fsnotify_mark *mark) +{ + struct au_hnotify *hn = container_of(mark, struct au_hnotify, + hn_mark); + /* AuDbg("here\n"); */ + au_cache_free_hnotify(hn); + smp_mb__before_atomic(); /* for atomic64_dec */ + if (atomic64_dec_and_test(&au_hfsn_ifree)) + wake_up(&au_hfsn_wq); +} + +static int au_hfsn_alloc(struct au_hinode *hinode) +{ + int err; + struct au_hnotify *hn; + struct super_block *sb; + struct au_branch *br; + struct fsnotify_mark *mark; + aufs_bindex_t bindex; + + hn = hinode->hi_notify; + sb = hn->hn_aufs_inode->i_sb; + bindex = au_br_index(sb, hinode->hi_id); + br = au_sbr(sb, bindex); + AuDebugOn(!br->br_hfsn); + + mark = &hn->hn_mark; + fsnotify_init_mark(mark, br->br_hfsn->hfsn_group); + mark->mask = AuHfsnMask; + /* + * by udba rename or rmdir, aufs assign a new inode to the known + * h_inode, so specify 1 to allow dups. + */ + lockdep_off(); + err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); + lockdep_on(); + + return err; +} + +static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) +{ + struct fsnotify_mark *mark; + unsigned long long ull; + struct fsnotify_group *group; + + ull = atomic64_inc_return(&au_hfsn_ifree); + BUG_ON(!ull); + + mark = &hn->hn_mark; + spin_lock(&mark->lock); + group = mark->group; + fsnotify_get_group(group); + spin_unlock(&mark->lock); + lockdep_off(); + fsnotify_destroy_mark(mark, group); + fsnotify_put_mark(mark); + fsnotify_put_group(group); + lockdep_on(); + + /* free hn by myself */ + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) +{ + struct fsnotify_mark *mark; + + mark = &hinode->hi_notify->hn_mark; + spin_lock(&mark->lock); + if (do_set) { + AuDebugOn(mark->mask & AuHfsnMask); + mark->mask |= AuHfsnMask; + } else { + AuDebugOn(!(mark->mask & AuHfsnMask)); + mark->mask &= ~AuHfsnMask; + } + spin_unlock(&mark->lock); + /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ +} + +/* ---------------------------------------------------------------------- */ + +/* #define AuDbgHnotify */ +#ifdef AuDbgHnotify +static char *au_hfsn_name(u32 mask) +{ +#ifdef CONFIG_AUFS_DEBUG +#define test_ret(flag) \ + do { \ + if (mask & flag) \ + return #flag; \ + } while (0) + test_ret(FS_ACCESS); + test_ret(FS_MODIFY); + test_ret(FS_ATTRIB); + test_ret(FS_CLOSE_WRITE); + test_ret(FS_CLOSE_NOWRITE); + test_ret(FS_OPEN); + test_ret(FS_MOVED_FROM); + test_ret(FS_MOVED_TO); + test_ret(FS_CREATE); + test_ret(FS_DELETE); + test_ret(FS_DELETE_SELF); + test_ret(FS_MOVE_SELF); + test_ret(FS_UNMOUNT); + test_ret(FS_Q_OVERFLOW); + test_ret(FS_IN_IGNORED); + test_ret(FS_ISDIR); + test_ret(FS_IN_ONESHOT); + test_ret(FS_EVENT_ON_CHILD); + return ""; +#undef test_ret +#else + return "??"; +#endif +} +#endif + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_free_group(struct fsnotify_group *group) +{ + struct au_br_hfsnotify *hfsn = group->private; + + /* AuDbg("here\n"); */ + au_kfree_try_rcu(hfsn); +} + +static int au_hfsn_handle_event(struct fsnotify_group *group, + u32 mask, const void *data, int data_type, + struct inode *dir, + const struct qstr *file_name, u32 cookie, + struct fsnotify_iter_info *iter_info) +{ + int err; + struct au_hnotify *hnotify; + struct inode *h_dir, *h_inode; + struct fsnotify_mark *inode_mark; + + AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); + + err = 0; + /* if FS_UNMOUNT happens, there must be another bug */ + AuDebugOn(mask & FS_UNMOUNT); + if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) + goto out; + + h_dir = dir; + h_inode = NULL; +#ifdef AuDbgHnotify + au_debug_on(); + if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 + || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { + AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", + h_dir->i_ino, mask, au_hfsn_name(mask), + AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); + /* WARN_ON(1); */ + } + au_debug_off(); +#endif + + inode_mark = fsnotify_iter_inode_mark(iter_info); + AuDebugOn(!inode_mark); + hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); + err = au_hnotify(h_dir, hnotify, mask, file_name, h_inode); + +out: + return err; +} + +static struct fsnotify_ops au_hfsn_ops = { + .handle_event = au_hfsn_handle_event, + .free_group_priv = au_hfsn_free_group, + .free_mark = au_hfsn_free_mark +}; + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_fin_br(struct au_branch *br) +{ + struct au_br_hfsnotify *hfsn; + + hfsn = br->br_hfsn; + if (hfsn) { + lockdep_off(); + fsnotify_put_group(hfsn->hfsn_group); + lockdep_on(); + } +} + +static int au_hfsn_init_br(struct au_branch *br, int perm) +{ + int err; + struct fsnotify_group *group; + struct au_br_hfsnotify *hfsn; + + err = 0; + br->br_hfsn = NULL; + if (!au_br_hnotifyable(perm)) + goto out; + + err = -ENOMEM; + hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); + if (unlikely(!hfsn)) + goto out; + + err = 0; + group = fsnotify_alloc_group(&au_hfsn_ops); + if (IS_ERR(group)) { + err = PTR_ERR(group); + pr_err("fsnotify_alloc_group() failed, %d\n", err); + goto out_hfsn; + } + + group->private = hfsn; + hfsn->hfsn_group = group; + br->br_hfsn = hfsn; + goto out; /* success */ + +out_hfsn: + au_kfree_try_rcu(hfsn); +out: + return err; +} + +static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) +{ + int err; + + err = 0; + if (!br->br_hfsn) + err = au_hfsn_init_br(br, perm); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_fin(void) +{ + AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); + wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); +} + +const struct au_hnotify_op au_hnotify_op = { + .ctl = au_hfsn_ctl, + .alloc = au_hfsn_alloc, + .free = au_hfsn_free, + + .fin = au_hfsn_fin, + + .reset_br = au_hfsn_reset_br, + .fin_br = au_hfsn_fin_br, + .init_br = au_hfsn_init_br +}; diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c new file mode 100644 index 000000000000..3bd869a69c8f --- /dev/null +++ b/fs/aufs/hfsplus.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2010-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * special support for filesystems which acquires an inode mutex + * at final closing a file, eg, hfsplus. + * + * This trick is very simple and stupid, just to open the file before really + * necessary open to tell hfsplus that this is not the final closing. + * The caller should call au_h_open_pre() after acquiring the inode mutex, + * and au_h_open_post() after releasing it. + */ + +#include "aufs.h" + +struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, + int force_wr) +{ + struct file *h_file; + struct dentry *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + AuDebugOn(!h_dentry); + AuDebugOn(d_is_negative(h_dentry)); + + h_file = NULL; + if (au_test_hfsplus(h_dentry->d_sb) + && d_is_reg(h_dentry)) + h_file = au_h_open(dentry, bindex, + O_RDONLY | O_NOATIME | O_LARGEFILE, + /*file*/NULL, force_wr); + return h_file; +} + +void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file) +{ + struct au_branch *br; + + if (h_file) { + fput(h_file); + br = au_sbr(dentry->d_sb, bindex); + au_lcnt_dec(&br->br_nfiles); + } +} diff --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c new file mode 100644 index 000000000000..dc861c81dbde --- /dev/null +++ b/fs/aufs/hnotify.c @@ -0,0 +1,715 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * abstraction to notify the direct changes on lower directories + */ + +/* #include */ +#include "aufs.h" + +int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) +{ + int err; + struct au_hnotify *hn; + + err = -ENOMEM; + hn = au_cache_alloc_hnotify(); + if (hn) { + hn->hn_aufs_inode = inode; + hinode->hi_notify = hn; + err = au_hnotify_op.alloc(hinode); + AuTraceErr(err); + if (unlikely(err)) { + hinode->hi_notify = NULL; + au_cache_free_hnotify(hn); + /* + * The upper dir was removed by udba, but the same named + * dir left. In this case, aufs assigns a new inode + * number and set the monitor again. + * For the lower dir, the old monitor is still left. + */ + if (err == -EEXIST) + err = 0; + } + } + + AuTraceErr(err); + return err; +} + +void au_hn_free(struct au_hinode *hinode) +{ + struct au_hnotify *hn; + + hn = hinode->hi_notify; + if (hn) { + hinode->hi_notify = NULL; + if (au_hnotify_op.free(hinode, hn)) + au_cache_free_hnotify(hn); + } +} + +/* ---------------------------------------------------------------------- */ + +void au_hn_ctl(struct au_hinode *hinode, int do_set) +{ + if (hinode->hi_notify) + au_hnotify_op.ctl(hinode, do_set); +} + +void au_hn_reset(struct inode *inode, unsigned int flags) +{ + aufs_bindex_t bindex, bbot; + struct inode *hi; + struct dentry *iwhdentry; + + bbot = au_ibbot(inode); + for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { + hi = au_h_iptr(inode, bindex); + if (!hi) + continue; + + /* inode_lock_nested(hi, AuLsc_I_CHILD); */ + iwhdentry = au_hi_wh(inode, bindex); + if (iwhdentry) + dget(iwhdentry); + au_igrab(hi); + au_set_h_iptr(inode, bindex, NULL, 0); + au_set_h_iptr(inode, bindex, au_igrab(hi), + flags & ~AuHi_XINO); + iput(hi); + dput(iwhdentry); + /* inode_unlock(hi); */ + } +} + +/* ---------------------------------------------------------------------- */ + +static int hn_xino(struct inode *inode, struct inode *h_inode) +{ + int err; + aufs_bindex_t bindex, bbot, bfound, btop; + struct inode *h_i; + + err = 0; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + pr_warn("branch root dir was changed\n"); + goto out; + } + + bfound = -1; + bbot = au_ibbot(inode); + btop = au_ibtop(inode); +#if 0 /* reserved for future use */ + if (bindex == bbot) { + /* keep this ino in rename case */ + goto out; + } +#endif + for (bindex = btop; bindex <= bbot; bindex++) + if (au_h_iptr(inode, bindex) == h_inode) { + bfound = bindex; + break; + } + if (bfound < 0) + goto out; + + for (bindex = btop; bindex <= bbot; bindex++) { + h_i = au_h_iptr(inode, bindex); + if (!h_i) + continue; + + err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); + /* ignore this error */ + /* bad action? */ + } + + /* children inode number will be broken */ + +out: + AuTraceErr(err); + return err; +} + +static int hn_gen_tree(struct dentry *dentry) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, dentry, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + struct dentry *d; + + d = dentries[j]; + if (IS_ROOT(d)) + continue; + + au_digen_dec(d); + if (d_really_is_positive(d)) + /* todo: reset children xino? + cached children only? */ + au_iigen_dec(d_inode(d)); + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +/* + * return 0 if processed. + */ +static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, + const unsigned int isdir) +{ + int err; + struct dentry *d; + struct qstr *dname; + + err = 1; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + pr_warn("branch root dir was changed\n"); + err = 0; + goto out; + } + + if (!isdir) { + AuDebugOn(!name); + au_iigen_dec(inode); + spin_lock(&inode->i_lock); + hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { + spin_lock(&d->d_lock); + dname = &d->d_name; + if (dname->len != nlen + && memcmp(dname->name, name, nlen)) { + spin_unlock(&d->d_lock); + continue; + } + err = 0; + au_digen_dec(d); + spin_unlock(&d->d_lock); + break; + } + spin_unlock(&inode->i_lock); + } else { + au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); + d = d_find_any_alias(inode); + if (!d) { + au_iigen_dec(inode); + goto out; + } + + spin_lock(&d->d_lock); + dname = &d->d_name; + if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { + spin_unlock(&d->d_lock); + err = hn_gen_tree(d); + spin_lock(&d->d_lock); + } + spin_unlock(&d->d_lock); + dput(d); + } + +out: + AuTraceErr(err); + return err; +} + +static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) +{ + int err; + + if (IS_ROOT(dentry)) { + pr_warn("branch root dir was changed\n"); + return 0; + } + + err = 0; + if (!isdir) { + au_digen_dec(dentry); + if (d_really_is_positive(dentry)) + au_iigen_dec(d_inode(dentry)); + } else { + au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); + if (d_really_is_positive(dentry)) + err = hn_gen_tree(dentry); + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* hnotify job flags */ +#define AuHnJob_XINO0 1 +#define AuHnJob_GEN (1 << 1) +#define AuHnJob_DIRENT (1 << 2) +#define AuHnJob_ISDIR (1 << 3) +#define AuHnJob_TRYXINO0 (1 << 4) +#define AuHnJob_MNTPNT (1 << 5) +#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) +#define au_fset_hnjob(flags, name) \ + do { (flags) |= AuHnJob_##name; } while (0) +#define au_fclr_hnjob(flags, name) \ + do { (flags) &= ~AuHnJob_##name; } while (0) + +enum { + AuHn_CHILD, + AuHn_PARENT, + AuHnLast +}; + +struct au_hnotify_args { + struct inode *h_dir, *dir, *h_child_inode; + u32 mask; + unsigned int flags[AuHnLast]; + unsigned int h_child_nlen; + char h_child_name[]; +}; + +struct hn_job_args { + unsigned int flags; + struct inode *inode, *h_inode, *dir, *h_dir; + struct dentry *dentry; + char *h_name; + int h_nlen; +}; + +static int hn_job(struct hn_job_args *a) +{ + const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); + int e; + + /* reset xino */ + if (au_ftest_hnjob(a->flags, XINO0) && a->inode) + hn_xino(a->inode, a->h_inode); /* ignore this error */ + + if (au_ftest_hnjob(a->flags, TRYXINO0) + && a->inode + && a->h_inode) { + inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); + if (!a->h_inode->i_nlink + && !(a->h_inode->i_state & I_LINKABLE)) + hn_xino(a->inode, a->h_inode); /* ignore this error */ + inode_unlock_shared(a->h_inode); + } + + /* make the generation obsolete */ + if (au_ftest_hnjob(a->flags, GEN)) { + e = -1; + if (a->inode) + e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, + isdir); + if (e && a->dentry) + hn_gen_by_name(a->dentry, isdir); + /* ignore this error */ + } + + /* make dir entries obsolete */ + if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { + struct au_vdir *vdir; + + vdir = au_ivdir(a->inode); + if (vdir) + vdir->vd_jiffy = 0; + /* IMustLock(a->inode); */ + /* inode_inc_iversion(a->inode); */ + } + + /* can do nothing but warn */ + if (au_ftest_hnjob(a->flags, MNTPNT) + && a->dentry + && d_mountpoint(a->dentry)) + pr_warn("mount-point %pd is removed or renamed\n", a->dentry); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, + struct inode *dir) +{ + struct dentry *dentry, *d, *parent; + struct qstr *dname; + + parent = d_find_any_alias(dir); + if (!parent) + return NULL; + + dentry = NULL; + spin_lock(&parent->d_lock); + list_for_each_entry(d, &parent->d_subdirs, d_child) { + /* AuDbg("%pd\n", d); */ + spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); + dname = &d->d_name; + if (dname->len != nlen || memcmp(dname->name, name, nlen)) + goto cont_unlock; + if (au_di(d)) + au_digen_dec(d); + else + goto cont_unlock; + if (au_dcount(d) > 0) { + dentry = dget_dlock(d); + spin_unlock(&d->d_lock); + break; + } + +cont_unlock: + spin_unlock(&d->d_lock); + } + spin_unlock(&parent->d_lock); + dput(parent); + + if (dentry) + di_write_lock_child(dentry); + + return dentry; +} + +static struct inode *lookup_wlock_by_ino(struct super_block *sb, + aufs_bindex_t bindex, ino_t h_ino) +{ + struct inode *inode; + ino_t ino; + int err; + + inode = NULL; + err = au_xino_read(sb, bindex, h_ino, &ino); + if (!err && ino) + inode = ilookup(sb, ino); + if (!inode) + goto out; + + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + pr_warn("wrong root branch\n"); + iput(inode); + inode = NULL; + goto out; + } + + ii_write_lock_child(inode); + +out: + return inode; +} + +static void au_hn_bh(void *_args) +{ + struct au_hnotify_args *a = _args; + struct super_block *sb; + aufs_bindex_t bindex, bbot, bfound; + unsigned char xino, try_iput; + int err; + struct inode *inode; + ino_t h_ino; + struct hn_job_args args; + struct dentry *dentry; + struct au_sbinfo *sbinfo; + + AuDebugOn(!_args); + AuDebugOn(!a->h_dir); + AuDebugOn(!a->dir); + AuDebugOn(!a->mask); + AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", + a->mask, a->dir->i_ino, a->h_dir->i_ino, + a->h_child_inode ? a->h_child_inode->i_ino : 0); + + inode = NULL; + dentry = NULL; + /* + * do not lock a->dir->i_mutex here + * because of d_revalidate() may cause a deadlock. + */ + sb = a->dir->i_sb; + AuDebugOn(!sb); + sbinfo = au_sbi(sb); + AuDebugOn(!sbinfo); + si_write_lock(sb, AuLock_NOPLMW); + + if (au_opt_test(sbinfo->si_mntflags, DIRREN)) + switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { + case FS_MOVED_FROM: + case FS_MOVED_TO: + AuWarn1("DIRREN with UDBA may not work correctly " + "for the direct rename(2)\n"); + } + + ii_read_lock_parent(a->dir); + bfound = -1; + bbot = au_ibbot(a->dir); + for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) + if (au_h_iptr(a->dir, bindex) == a->h_dir) { + bfound = bindex; + break; + } + ii_read_unlock(a->dir); + if (unlikely(bfound < 0)) + goto out; + + xino = !!au_opt_test(au_mntflags(sb), XINO); + h_ino = 0; + if (a->h_child_inode) + h_ino = a->h_child_inode->i_ino; + + if (a->h_child_nlen + && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) + || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) + dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, + a->dir); + try_iput = 0; + if (dentry && d_really_is_positive(dentry)) + inode = d_inode(dentry); + if (xino && !inode && h_ino + && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) + || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) + || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { + inode = lookup_wlock_by_ino(sb, bfound, h_ino); + try_iput = 1; + } + + args.flags = a->flags[AuHn_CHILD]; + args.dentry = dentry; + args.inode = inode; + args.h_inode = a->h_child_inode; + args.dir = a->dir; + args.h_dir = a->h_dir; + args.h_name = a->h_child_name; + args.h_nlen = a->h_child_nlen; + err = hn_job(&args); + if (dentry) { + if (au_di(dentry)) + di_write_unlock(dentry); + dput(dentry); + } + if (inode && try_iput) { + ii_write_unlock(inode); + iput(inode); + } + + ii_write_lock_parent(a->dir); + args.flags = a->flags[AuHn_PARENT]; + args.dentry = NULL; + args.inode = a->dir; + args.h_inode = a->h_dir; + args.dir = NULL; + args.h_dir = NULL; + args.h_name = NULL; + args.h_nlen = 0; + err = hn_job(&args); + ii_write_unlock(a->dir); + +out: + iput(a->h_child_inode); + iput(a->h_dir); + iput(a->dir); + si_write_unlock(sb); + au_nwt_done(&sbinfo->si_nowait); + au_kfree_rcu(a); +} + +/* ---------------------------------------------------------------------- */ + +int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, + const struct qstr *h_child_qstr, struct inode *h_child_inode) +{ + int err, len; + unsigned int flags[AuHnLast], f; + unsigned char isdir, isroot, wh; + struct inode *dir; + struct au_hnotify_args *args; + char *p, *h_child_name; + + err = 0; + AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); + dir = igrab(hnotify->hn_aufs_inode); + if (!dir) + goto out; + + isroot = (dir->i_ino == AUFS_ROOT_INO); + wh = 0; + h_child_name = (void *)h_child_qstr->name; + len = h_child_qstr->len; + if (h_child_name) { + if (len > AUFS_WH_PFX_LEN + && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + h_child_name += AUFS_WH_PFX_LEN; + len -= AUFS_WH_PFX_LEN; + wh = 1; + } + } + + isdir = 0; + if (h_child_inode) + isdir = !!S_ISDIR(h_child_inode->i_mode); + flags[AuHn_PARENT] = AuHnJob_ISDIR; + flags[AuHn_CHILD] = 0; + if (isdir) + flags[AuHn_CHILD] = AuHnJob_ISDIR; + au_fset_hnjob(flags[AuHn_PARENT], DIRENT); + au_fset_hnjob(flags[AuHn_CHILD], GEN); + switch (mask & ALL_FSNOTIFY_DIRENT_EVENTS) { + case FS_MOVED_FROM: + case FS_MOVED_TO: + au_fset_hnjob(flags[AuHn_CHILD], XINO0); + au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); + fallthrough; + case FS_CREATE: + AuDebugOn(!h_child_name); + break; + + case FS_DELETE: + /* + * aufs never be able to get this child inode. + * revalidation should be in d_revalidate() + * by checking i_nlink, i_generation or d_unhashed(). + */ + AuDebugOn(!h_child_name); + au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); + au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); + break; + + default: + AuDebugOn(1); + } + + if (wh) + h_child_inode = NULL; + + err = -ENOMEM; + /* iput() and kfree() will be called in au_hnotify() */ + args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); + if (unlikely(!args)) { + AuErr1("no memory\n"); + iput(dir); + goto out; + } + args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; + args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; + args->mask = mask; + args->dir = dir; + args->h_dir = igrab(h_dir); + if (h_child_inode) + h_child_inode = igrab(h_child_inode); /* can be NULL */ + args->h_child_inode = h_child_inode; + args->h_child_nlen = len; + if (len) { + p = (void *)args; + p += sizeof(*args); + memcpy(p, h_child_name, len); + p[len] = 0; + } + + /* NFS fires the event for silly-renamed one from kworker */ + f = 0; + if (!dir->i_nlink + || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) + f = AuWkq_NEST; + err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); + if (unlikely(err)) { + pr_err("wkq %d\n", err); + iput(args->h_child_inode); + iput(args->h_dir); + iput(args->dir); + au_kfree_rcu(args); + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) +{ + int err; + + AuDebugOn(!(udba & AuOptMask_UDBA)); + + err = 0; + if (au_hnotify_op.reset_br) + err = au_hnotify_op.reset_br(udba, br, perm); + + return err; +} + +int au_hnotify_init_br(struct au_branch *br, int perm) +{ + int err; + + err = 0; + if (au_hnotify_op.init_br) + err = au_hnotify_op.init_br(br, perm); + + return err; +} + +void au_hnotify_fin_br(struct au_branch *br) +{ + if (au_hnotify_op.fin_br) + au_hnotify_op.fin_br(br); +} + +static void au_hn_destroy_cache(void) +{ + kmem_cache_destroy(au_cache[AuCache_HNOTIFY]); + au_cache[AuCache_HNOTIFY] = NULL; +} + +int __init au_hnotify_init(void) +{ + int err; + + err = -ENOMEM; + au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); + if (au_cache[AuCache_HNOTIFY]) { + err = 0; + if (au_hnotify_op.init) + err = au_hnotify_op.init(); + if (unlikely(err)) + au_hn_destroy_cache(); + } + AuTraceErr(err); + return err; +} + +void au_hnotify_fin(void) +{ + if (au_hnotify_op.fin) + au_hnotify_op.fin(); + + /* cf. au_cache_fin() */ + if (au_cache[AuCache_HNOTIFY]) + au_hn_destroy_cache(); +} diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c new file mode 100644 index 000000000000..b1cc965c8cb5 --- /dev/null +++ b/fs/aufs/i_op.c @@ -0,0 +1,1502 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations (except add/del/rename) + */ + +#include +#include +#include +#include +#include +#include "aufs.h" + +static int h_permission(struct inode *h_inode, int mask, + struct path *h_path, int brperm) +{ + int err; + const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); + + err = -EPERM; + if (write_mask && IS_IMMUTABLE(h_inode)) + goto out; + + err = -EACCES; + if (((mask & MAY_EXEC) + && S_ISREG(h_inode->i_mode) + && (path_noexec(h_path) + || !(h_inode->i_mode & 0111)))) + goto out; + + /* + * - skip the lower fs test in the case of write to ro branch. + * - nfs dir permission write check is optimized, but a policy for + * link/rename requires a real check. + * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' + * in this case, generic_permission() returns -EOPNOTSUPP. + */ + if ((write_mask && !au_br_writable(brperm)) + || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) + && write_mask && !(mask & MAY_READ)) + || !h_inode->i_op->permission) { + /* AuLabel(generic_permission); */ + /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ + err = generic_permission(h_inode, mask); + if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) + err = h_inode->i_op->permission(h_inode, mask); + AuTraceErr(err); + } else { + /* AuLabel(h_inode->permission); */ + err = h_inode->i_op->permission(h_inode, mask); + AuTraceErr(err); + } + + if (!err) + err = devcgroup_inode_permission(h_inode, mask); + if (!err) + err = security_inode_permission(h_inode, mask); + +out: + return err; +} + +static int aufs_permission(struct inode *inode, int mask) +{ + int err; + aufs_bindex_t bindex, bbot; + const unsigned char isdir = !!S_ISDIR(inode->i_mode), + write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); + struct inode *h_inode; + struct super_block *sb; + struct au_branch *br; + + /* todo: support rcu-walk? */ + if (mask & MAY_NOT_BLOCK) + return -ECHILD; + + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH); + ii_read_lock_child(inode); +#if 0 /* reserved for future use */ + /* + * This test may be rather 'too much' since the test is essentially done + * in the aufs_lookup(). Theoretically it is possible that the inode + * generation doesn't match to the superblock's here. But it isn't a + * big deal I suppose. + */ + err = au_iigen_test(inode, au_sigen(sb)); + if (unlikely(err)) + goto out; +#endif + + if (!isdir + || write_mask + || au_opt_test(au_mntflags(sb), DIRPERM1)) { + err = au_busy_or_stale(); + h_inode = au_h_iptr(inode, au_ibtop(inode)); + if (unlikely(!h_inode + || (h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT))) + goto out; + + err = 0; + bindex = au_ibtop(inode); + br = au_sbr(sb, bindex); + err = h_permission(h_inode, mask, &br->br_path, br->br_perm); + if (write_mask + && !err + && !special_file(h_inode->i_mode)) { + /* test whether the upper writable branch exists */ + err = -EROFS; + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = 0; + break; + } + } + goto out; + } + + /* non-write to dir */ + err = 0; + bbot = au_ibbot(inode); + for (bindex = au_ibtop(inode); !err && bindex <= bbot; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (h_inode) { + err = au_busy_or_stale(); + if (unlikely(!S_ISDIR(h_inode->i_mode))) + break; + + br = au_sbr(sb, bindex); + err = h_permission(h_inode, mask, &br->br_path, + br->br_perm); + } + } + +out: + ii_read_unlock(inode); + si_read_unlock(sb); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + struct dentry *ret, *parent; + struct inode *inode; + struct super_block *sb; + int err, npositive; + + IMustLock(dir); + + /* todo: support rcu-walk? */ + ret = ERR_PTR(-ECHILD); + if (flags & LOOKUP_RCU) + goto out; + + ret = ERR_PTR(-ENAMETOOLONG); + if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) + goto out; + + sb = dir->i_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + ret = ERR_PTR(err); + if (unlikely(err)) + goto out; + + err = au_di_init(dentry); + ret = ERR_PTR(err); + if (unlikely(err)) + goto out_si; + + inode = NULL; + npositive = 0; /* suppress a warning */ + parent = dentry->d_parent; /* dir inode is locked */ + di_read_lock_parent(parent, AuLock_IR); + err = au_alive_dir(parent); + if (!err) + err = au_digen_test(parent, au_sigen(sb)); + if (!err) { + /* regardless LOOKUP_CREATE, always ALLOW_NEG */ + npositive = au_lkup_dentry(dentry, au_dbtop(parent), + AuLkup_ALLOW_NEG); + err = npositive; + } + di_read_unlock(parent, AuLock_IR); + ret = ERR_PTR(err); + if (unlikely(err < 0)) + goto out_unlock; + + if (npositive) { + inode = au_new_inode(dentry, /*must_new*/0); + if (IS_ERR(inode)) { + ret = (void *)inode; + inode = NULL; + goto out_unlock; + } + } + + if (inode) + atomic_inc(&inode->i_count); + ret = d_splice_alias(inode, dentry); +#if 0 /* reserved for future use */ + if (unlikely(d_need_lookup(dentry))) { + spin_lock(&dentry->d_lock); + dentry->d_flags &= ~DCACHE_NEED_LOOKUP; + spin_unlock(&dentry->d_lock); + } else +#endif + if (inode) { + if (!IS_ERR(ret)) { + iput(inode); + if (ret && ret != dentry) + ii_write_unlock(inode); + } else { + ii_write_unlock(inode); + iput(inode); + inode = NULL; + } + } + +out_unlock: + di_write_unlock(dentry); +out_si: + si_read_unlock(sb); +out: + return ret; +} + +/* ---------------------------------------------------------------------- */ + +/* + * very dirty and complicated aufs ->atomic_open(). + * aufs_atomic_open() + * + au_aopen_or_create() + * + add_simple() + * + vfsub_atomic_open() + * + branch fs ->atomic_open() + * may call the actual 'open' for h_file + * + inc br_nfiles only if opened + * + au_aopen_no_open() or au_aopen_do_open() + * + * au_aopen_do_open() + * + finish_open() + * + au_do_aopen() + * + au_do_open() the body of all 'open' + * + au_do_open_nondir() + * set the passed h_file + * + * au_aopen_no_open() + * + finish_no_open() + */ + +struct aopen_node { + struct hlist_bl_node hblist; + struct file *file, *h_file; +}; + +static int au_do_aopen(struct inode *inode, struct file *file) +{ + struct hlist_bl_head *aopen; + struct hlist_bl_node *pos; + struct aopen_node *node; + struct au_do_open_args args = { + .aopen = 1, + .open = au_do_open_nondir + }; + + aopen = &au_sbi(inode->i_sb)->si_aopen; + hlist_bl_lock(aopen); + hlist_bl_for_each_entry(node, pos, aopen, hblist) + if (node->file == file) { + args.h_file = node->h_file; + break; + } + hlist_bl_unlock(aopen); + /* AuDebugOn(!args.h_file); */ + + return au_do_open(file, &args); +} + +static int au_aopen_do_open(struct file *file, struct dentry *dentry, + struct aopen_node *aopen_node) +{ + int err; + struct hlist_bl_head *aopen; + + AuLabel(here); + aopen = &au_sbi(dentry->d_sb)->si_aopen; + au_hbl_add(&aopen_node->hblist, aopen); + err = finish_open(file, dentry, au_do_aopen); + au_hbl_del(&aopen_node->hblist, aopen); + /* AuDbgFile(file); */ + AuDbg("%pd%s%s\n", dentry, + (file->f_mode & FMODE_CREATED) ? " created" : "", + (file->f_mode & FMODE_OPENED) ? " opened" : ""); + + AuTraceErr(err); + return err; +} + +static int au_aopen_no_open(struct file *file, struct dentry *dentry) +{ + int err; + + AuLabel(here); + dget(dentry); + err = finish_no_open(file, dentry); + + AuTraceErr(err); + return err; +} + +static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, + struct file *file, unsigned int open_flag, + umode_t create_mode) +{ + int err, did_open; + unsigned int lkup_flags; + aufs_bindex_t bindex; + struct super_block *sb; + struct dentry *parent, *d; + struct vfsub_aopen_args args = { + .open_flag = open_flag, + .create_mode = create_mode + }; + struct aopen_node aopen_node = { + .file = file + }; + + IMustLock(dir); + AuDbg("open_flag 0%o\n", open_flag); + AuDbgDentry(dentry); + + err = 0; + if (!au_di(dentry)) { + lkup_flags = LOOKUP_OPEN; + if (open_flag & O_CREAT) + lkup_flags |= LOOKUP_CREATE; + d = aufs_lookup(dir, dentry, lkup_flags); + if (IS_ERR(d)) { + err = PTR_ERR(d); + AuTraceErr(err); + goto out; + } else if (d) { + /* + * obsoleted dentry found. + * another error will be returned later. + */ + d_drop(d); + AuDbgDentry(d); + dput(d); + } + AuDbgDentry(dentry); + } + + if (d_is_positive(dentry) + || d_unhashed(dentry) + || d_unlinked(dentry) + || !(open_flag & O_CREAT)) { + err = au_aopen_no_open(file, dentry); + goto out; /* success */ + } + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); + if (unlikely(err)) + goto out; + + sb = dentry->d_sb; + parent = dentry->d_parent; /* dir is locked */ + di_write_lock_parent(parent); + err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); + if (unlikely(err < 0)) + goto out_parent; + + AuDbgDentry(dentry); + if (d_is_positive(dentry)) { + err = au_aopen_no_open(file, dentry); + goto out_parent; /* success */ + } + + args.file = alloc_empty_file(file->f_flags, current_cred()); + err = PTR_ERR(args.file); + if (IS_ERR(args.file)) + goto out_parent; + + bindex = au_dbtop(dentry); + err = au_aopen_or_create(dir, dentry, &args); + AuTraceErr(err); + AuDbgFile(args.file); + file->f_mode = args.file->f_mode & ~FMODE_OPENED; + did_open = !!(args.file->f_mode & FMODE_OPENED); + if (!did_open) { + fput(args.file); + args.file = NULL; + } + di_write_unlock(parent); + di_write_unlock(dentry); + if (unlikely(err < 0)) { + if (args.file) + fput(args.file); + goto out_sb; + } + + if (!did_open) + err = au_aopen_no_open(file, dentry); + else { + aopen_node.h_file = args.file; + err = au_aopen_do_open(file, dentry, &aopen_node); + } + if (unlikely(err < 0)) { + if (args.file) + fput(args.file); + if (did_open) + au_lcnt_dec(&args.br->br_nfiles); + } + goto out_sb; /* success */ + +out_parent: + di_write_unlock(parent); + di_write_unlock(dentry); +out_sb: + si_read_unlock(sb); +out: + AuTraceErr(err); + AuDbgFile(file); + return err; +} + + +/* ---------------------------------------------------------------------- */ + +static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, + const unsigned char add_entry, aufs_bindex_t bcpup, + aufs_bindex_t btop) +{ + int err; + struct dentry *h_parent; + struct inode *h_dir; + + if (add_entry) + IMustLock(d_inode(parent)); + else + di_write_lock_parent(parent); + + err = 0; + if (!au_h_dptr(parent, bcpup)) { + if (btop > bcpup) + err = au_cpup_dirs(dentry, bcpup); + else if (btop < bcpup) + err = au_cpdown_dirs(dentry, bcpup); + else + BUG(); + } + if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { + h_parent = au_h_dptr(parent, bcpup); + h_dir = d_inode(h_parent); + inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); + err = au_lkup_neg(dentry, bcpup, /*wh*/0); + /* todo: no unlock here */ + inode_unlock_shared(h_dir); + + AuDbg("bcpup %d\n", bcpup); + if (!err) { + if (d_really_is_negative(dentry)) + au_set_h_dptr(dentry, btop, NULL); + au_update_dbrange(dentry, /*do_put_zero*/0); + } + } + + if (!add_entry) + di_write_unlock(parent); + if (!err) + err = bcpup; /* success */ + + AuTraceErr(err); + return err; +} + +/* + * decide the branch and the parent dir where we will create a new entry. + * returns new bindex or an error. + * copyup the parent dir if needed. + */ +int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, + struct au_wr_dir_args *args) +{ + int err; + unsigned int flags; + aufs_bindex_t bcpup, btop, src_btop; + const unsigned char add_entry + = au_ftest_wrdir(args->flags, ADD_ENTRY) + | au_ftest_wrdir(args->flags, TMPFILE); + struct super_block *sb; + struct dentry *parent; + struct au_sbinfo *sbinfo; + + sb = dentry->d_sb; + sbinfo = au_sbi(sb); + parent = dget_parent(dentry); + btop = au_dbtop(dentry); + bcpup = btop; + if (args->force_btgt < 0) { + if (src_dentry) { + src_btop = au_dbtop(src_dentry); + if (src_btop < btop) + bcpup = src_btop; + } else if (add_entry) { + flags = 0; + if (au_ftest_wrdir(args->flags, ISDIR)) + au_fset_wbr(flags, DIR); + err = AuWbrCreate(sbinfo, dentry, flags); + bcpup = err; + } + + if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { + if (add_entry) + err = AuWbrCopyup(sbinfo, dentry); + else { + if (!IS_ROOT(dentry)) { + di_read_lock_parent(parent, !AuLock_IR); + err = AuWbrCopyup(sbinfo, dentry); + di_read_unlock(parent, !AuLock_IR); + } else + err = AuWbrCopyup(sbinfo, dentry); + } + bcpup = err; + if (unlikely(err < 0)) + goto out; + } + } else { + bcpup = args->force_btgt; + AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); + } + + AuDbg("btop %d, bcpup %d\n", btop, bcpup); + err = bcpup; + if (bcpup == btop) + goto out; /* success */ + + /* copyup the new parent into the branch we process */ + err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); + if (err >= 0) { + if (d_really_is_negative(dentry)) { + au_set_h_dptr(dentry, btop, NULL); + au_set_dbtop(dentry, bcpup); + au_set_dbbot(dentry, bcpup); + } + AuDebugOn(add_entry + && !au_ftest_wrdir(args->flags, TMPFILE) + && !au_h_dptr(dentry, bcpup)); + } + +out: + dput(parent); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_pin_hdir_unlock(struct au_pin *p) +{ + if (p->hdir) + au_hn_inode_unlock(p->hdir); +} + +int au_pin_hdir_lock(struct au_pin *p) +{ + int err; + + err = 0; + if (!p->hdir) + goto out; + + /* even if an error happens later, keep this lock */ + au_hn_inode_lock_nested(p->hdir, p->lsc_hi); + + err = -EBUSY; + if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) + goto out; + + err = 0; + if (p->h_dentry) + err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, + p->h_parent, p->br); + +out: + return err; +} + +int au_pin_hdir_relock(struct au_pin *p) +{ + int err, i; + struct inode *h_i; + struct dentry *h_d[] = { + p->h_dentry, + p->h_parent + }; + + err = au_pin_hdir_lock(p); + if (unlikely(err)) + goto out; + + for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { + if (!h_d[i]) + continue; + if (d_is_positive(h_d[i])) { + h_i = d_inode(h_d[i]); + err = !h_i->i_nlink; + } + } + +out: + return err; +} + +static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) +{ + atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); +} + +void au_pin_hdir_acquire_nest(struct au_pin *p) +{ + if (p->hdir) { + rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, + p->lsc_hi, 0, NULL, _RET_IP_); + au_pin_hdir_set_owner(p, current); + } +} + +void au_pin_hdir_release(struct au_pin *p) +{ + if (p->hdir) { + au_pin_hdir_set_owner(p, p->task); + rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, _RET_IP_); + } +} + +struct dentry *au_pinned_h_parent(struct au_pin *pin) +{ + if (pin && pin->parent) + return au_h_dptr(pin->parent, pin->bindex); + return NULL; +} + +void au_unpin(struct au_pin *p) +{ + if (p->hdir) + au_pin_hdir_unlock(p); + if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) + vfsub_mnt_drop_write(p->h_mnt); + if (!p->hdir) + return; + + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_unlock(p->parent, AuLock_IR); + iput(p->hdir->hi_inode); + dput(p->parent); + p->parent = NULL; + p->hdir = NULL; + p->h_mnt = NULL; + /* do not clear p->task */ +} + +int au_do_pin(struct au_pin *p) +{ + int err; + struct super_block *sb; + struct inode *h_dir; + + err = 0; + sb = p->dentry->d_sb; + p->br = au_sbr(sb, p->bindex); + if (IS_ROOT(p->dentry)) { + if (au_ftest_pin(p->flags, MNT_WRITE)) { + p->h_mnt = au_br_mnt(p->br); + err = vfsub_mnt_want_write(p->h_mnt); + if (unlikely(err)) { + au_fclr_pin(p->flags, MNT_WRITE); + goto out_err; + } + } + goto out; + } + + p->h_dentry = NULL; + if (p->bindex <= au_dbbot(p->dentry)) + p->h_dentry = au_h_dptr(p->dentry, p->bindex); + + p->parent = dget_parent(p->dentry); + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_lock(p->parent, AuLock_IR, p->lsc_di); + + h_dir = NULL; + p->h_parent = au_h_dptr(p->parent, p->bindex); + p->hdir = au_hi(d_inode(p->parent), p->bindex); + if (p->hdir) + h_dir = p->hdir->hi_inode; + + /* + * udba case, or + * if DI_LOCKED is not set, then p->parent may be different + * and h_parent can be NULL. + */ + if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { + err = -EBUSY; + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_unlock(p->parent, AuLock_IR); + dput(p->parent); + p->parent = NULL; + goto out_err; + } + + if (au_ftest_pin(p->flags, MNT_WRITE)) { + p->h_mnt = au_br_mnt(p->br); + err = vfsub_mnt_want_write(p->h_mnt); + if (unlikely(err)) { + au_fclr_pin(p->flags, MNT_WRITE); + if (!au_ftest_pin(p->flags, DI_LOCKED)) + di_read_unlock(p->parent, AuLock_IR); + dput(p->parent); + p->parent = NULL; + goto out_err; + } + } + + au_igrab(h_dir); + err = au_pin_hdir_lock(p); + if (!err) + goto out; /* success */ + + au_unpin(p); + +out_err: + pr_err("err %d\n", err); + err = au_busy_or_stale(); +out: + return err; +} + +void au_pin_init(struct au_pin *p, struct dentry *dentry, + aufs_bindex_t bindex, int lsc_di, int lsc_hi, + unsigned int udba, unsigned char flags) +{ + p->dentry = dentry; + p->udba = udba; + p->lsc_di = lsc_di; + p->lsc_hi = lsc_hi; + p->flags = flags; + p->bindex = bindex; + + p->parent = NULL; + p->hdir = NULL; + p->h_mnt = NULL; + + p->h_dentry = NULL; + p->h_parent = NULL; + p->br = NULL; + p->task = current; +} + +int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, + unsigned int udba, unsigned char flags) +{ + au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, + udba, flags); + return au_do_pin(pin); +} + +/* ---------------------------------------------------------------------- */ + +/* + * ->setattr() and ->getattr() are called in various cases. + * chmod, stat: dentry is revalidated. + * fchmod, fstat: file and dentry are not revalidated, additionally they may be + * unhashed. + * for ->setattr(), ia->ia_file is passed from ftruncate only. + */ +/* todo: consolidate with do_refresh() and simple_reval_dpath() */ +int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) +{ + int err; + struct dentry *parent; + + err = 0; + if (au_digen_test(dentry, sigen)) { + parent = dget_parent(dentry); + di_read_lock_parent(parent, AuLock_IR); + err = au_refresh_dentry(dentry, parent); + di_read_unlock(parent, AuLock_IR); + dput(parent); + } + + AuTraceErr(err); + return err; +} + +int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, + struct au_icpup_args *a) +{ + int err; + loff_t sz; + aufs_bindex_t btop, ibtop; + struct dentry *hi_wh, *parent; + struct inode *inode; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = 0 + }; + + if (d_is_dir(dentry)) + au_fset_wrdir(wr_dir_args.flags, ISDIR); + /* plink or hi_wh() case */ + btop = au_dbtop(dentry); + inode = d_inode(dentry); + ibtop = au_ibtop(inode); + if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) + wr_dir_args.force_btgt = ibtop; + err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); + if (unlikely(err < 0)) + goto out; + a->btgt = err; + if (err != btop) + au_fset_icpup(a->flags, DID_CPUP); + + err = 0; + a->pin_flags = AuPin_MNT_WRITE; + parent = NULL; + if (!IS_ROOT(dentry)) { + au_fset_pin(a->pin_flags, DI_LOCKED); + parent = dget_parent(dentry); + di_write_lock_parent(parent); + } + + err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); + if (unlikely(err)) + goto out_parent; + + sz = -1; + a->h_path.dentry = au_h_dptr(dentry, btop); + a->h_inode = d_inode(a->h_path.dentry); + if (ia && (ia->ia_valid & ATTR_SIZE)) { + inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); + if (ia->ia_size < i_size_read(a->h_inode)) + sz = ia->ia_size; + inode_unlock_shared(a->h_inode); + } + + hi_wh = NULL; + if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { + hi_wh = au_hi_wh(inode, a->btgt); + if (!hi_wh) { + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = a->btgt, + .bsrc = -1, + .len = sz, + .pin = &a->pin + }; + err = au_sio_cpup_wh(&cpg, /*file*/NULL); + if (unlikely(err)) + goto out_unlock; + hi_wh = au_hi_wh(inode, a->btgt); + /* todo: revalidate hi_wh? */ + } + } + + if (parent) { + au_pin_set_parent_lflag(&a->pin, /*lflag*/0); + di_downgrade_lock(parent, AuLock_IR); + dput(parent); + parent = NULL; + } + if (!au_ftest_icpup(a->flags, DID_CPUP)) + goto out; /* success */ + + if (!d_unhashed(dentry)) { + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = a->btgt, + .bsrc = btop, + .len = sz, + .pin = &a->pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + err = au_sio_cpup_simple(&cpg); + if (!err) + a->h_path.dentry = au_h_dptr(dentry, a->btgt); + } else if (!hi_wh) + a->h_path.dentry = au_h_dptr(dentry, a->btgt); + else + a->h_path.dentry = hi_wh; /* do not dget here */ + +out_unlock: + a->h_inode = d_inode(a->h_path.dentry); + if (!err) + goto out; /* success */ + au_unpin(&a->pin); +out_parent: + if (parent) { + di_write_unlock(parent); + dput(parent); + } +out: + if (!err) + inode_lock_nested(a->h_inode, AuLsc_I_CHILD); + return err; +} + +static int aufs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err; + struct inode *inode, *delegated; + struct super_block *sb; + struct file *file; + struct au_icpup_args *a; + + inode = d_inode(dentry); + IMustLock(inode); + + err = setattr_prepare(dentry, ia); + if (unlikely(err)) + goto out; + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + ia->ia_valid &= ~ATTR_MODE; + + file = NULL; + sb = dentry->d_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_kfree; + + if (ia->ia_valid & ATTR_FILE) { + /* currently ftruncate(2) only */ + AuDebugOn(!d_is_reg(dentry)); + file = ia->ia_file; + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, + /*fi_lsc*/0); + if (unlikely(err)) + goto out_si; + ia->ia_file = au_hf_top(file); + a->udba = AuOpt_UDBA_NONE; + } else { + /* fchmod() doesn't pass ia_file */ + a->udba = au_opt_udba(sb); + di_write_lock_child(dentry); + /* no d_unlinked(), to set UDBA_NONE for root */ + if (d_unhashed(dentry)) + a->udba = AuOpt_UDBA_NONE; + if (a->udba != AuOpt_UDBA_NONE) { + AuDebugOn(IS_ROOT(dentry)); + err = au_reval_for_attr(dentry, au_sigen(sb)); + if (unlikely(err)) + goto out_dentry; + } + } + + err = au_pin_and_icpup(dentry, ia, a); + if (unlikely(err < 0)) + goto out_dentry; + if (au_ftest_icpup(a->flags, DID_CPUP)) { + ia->ia_file = NULL; + ia->ia_valid &= ~ATTR_FILE; + } + + a->h_path.mnt = au_sbr_mnt(sb, a->btgt); + if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) + == (ATTR_MODE | ATTR_CTIME)) { + err = security_path_chmod(&a->h_path, ia->ia_mode); + if (unlikely(err)) + goto out_unlock; + } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) + && (ia->ia_valid & ATTR_CTIME)) { + err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); + if (unlikely(err)) + goto out_unlock; + } + + if (ia->ia_valid & ATTR_SIZE) { + struct file *f; + + if (ia->ia_size < i_size_read(inode)) + /* unmap only */ + truncate_setsize(inode, ia->ia_size); + + f = NULL; + if (ia->ia_valid & ATTR_FILE) + f = ia->ia_file; + inode_unlock(a->h_inode); + err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); + inode_lock_nested(a->h_inode, AuLsc_I_CHILD); + } else { + delegated = NULL; + while (1) { + err = vfsub_notify_change(&a->h_path, ia, &delegated); + if (delegated) { + err = break_deleg_wait(&delegated); + if (!err) + continue; + } + break; + } + } + /* + * regardless aufs 'acl' option setting. + * why don't all acl-aware fs call this func from their ->setattr()? + */ + if (!err && (ia->ia_valid & ATTR_MODE)) + err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); + if (!err) + au_cpup_attr_changeable(inode); + +out_unlock: + inode_unlock(a->h_inode); + au_unpin(&a->pin); + if (unlikely(err)) + au_update_dbtop(dentry); +out_dentry: + di_write_unlock(dentry); + if (file) { + fi_write_unlock(file); + ia->ia_file = file; + ia->ia_valid |= ATTR_FILE; + } +out_si: + si_read_unlock(sb); +out_kfree: + au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} + +#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) +static int au_h_path_to_set_attr(struct dentry *dentry, + struct au_icpup_args *a, struct path *h_path) +{ + int err; + struct super_block *sb; + + sb = dentry->d_sb; + a->udba = au_opt_udba(sb); + /* no d_unlinked(), to set UDBA_NONE for root */ + if (d_unhashed(dentry)) + a->udba = AuOpt_UDBA_NONE; + if (a->udba != AuOpt_UDBA_NONE) { + AuDebugOn(IS_ROOT(dentry)); + err = au_reval_for_attr(dentry, au_sigen(sb)); + if (unlikely(err)) + goto out; + } + err = au_pin_and_icpup(dentry, /*ia*/NULL, a); + if (unlikely(err < 0)) + goto out; + + h_path->dentry = a->h_path.dentry; + h_path->mnt = au_sbr_mnt(sb, a->btgt); + +out: + return err; +} + +ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, + struct au_sxattr *arg) +{ + int err; + struct path h_path; + struct super_block *sb; + struct au_icpup_args *a; + struct inode *h_inode; + + IMustLock(inode); + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + sb = dentry->d_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_kfree; + + h_path.dentry = NULL; /* silence gcc */ + di_write_lock_child(dentry); + err = au_h_path_to_set_attr(dentry, a, &h_path); + if (unlikely(err)) + goto out_di; + + inode_unlock(a->h_inode); + switch (arg->type) { + case AU_XATTR_SET: + AuDebugOn(d_is_negative(h_path.dentry)); + err = vfsub_setxattr(h_path.dentry, + arg->u.set.name, arg->u.set.value, + arg->u.set.size, arg->u.set.flags); + break; + case AU_ACL_SET: + err = -EOPNOTSUPP; + h_inode = d_inode(h_path.dentry); + if (h_inode->i_op->set_acl) + /* this will call posix_acl_update_mode */ + err = h_inode->i_op->set_acl(h_inode, + arg->u.acl_set.acl, + arg->u.acl_set.type); + break; + } + if (!err) + au_cpup_attr_timesizes(inode); + + au_unpin(&a->pin); + if (unlikely(err)) + au_update_dbtop(dentry); + +out_di: + di_write_unlock(dentry); + si_read_unlock(sb); +out_kfree: + au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} +#endif + +static void au_refresh_iattr(struct inode *inode, struct kstat *st, + unsigned int nlink) +{ + unsigned int n; + + inode->i_mode = st->mode; + /* don't i_[ug]id_write() here */ + inode->i_uid = st->uid; + inode->i_gid = st->gid; + inode->i_atime = st->atime; + inode->i_mtime = st->mtime; + inode->i_ctime = st->ctime; + + au_cpup_attr_nlink(inode, /*force*/0); + if (S_ISDIR(inode->i_mode)) { + n = inode->i_nlink; + n -= nlink; + n += st->nlink; + smp_mb(); /* for i_nlink */ + /* 0 can happen */ + set_nlink(inode, n); + } + + spin_lock(&inode->i_lock); + inode->i_blocks = st->blocks; + i_size_write(inode, st->size); + spin_unlock(&inode->i_lock); +} + +/* + * common routine for aufs_getattr() and au_getxattr(). + * returns zero or negative (an error). + * @dentry will be read-locked in success. + */ +int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, + struct path *h_path, int locked) +{ + int err; + unsigned int mnt_flags, sigen; + unsigned char udba_none; + aufs_bindex_t bindex; + struct super_block *sb, *h_sb; + + h_path->mnt = NULL; + h_path->dentry = NULL; + + err = 0; + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); + + if (unlikely(locked)) + goto body; /* skip locking dinfo */ + + /* support fstat(2) */ + if (!d_unlinked(dentry) && !udba_none) { + sigen = au_sigen(sb); + err = au_digen_test(dentry, sigen); + if (!err) { + di_read_lock_child(dentry, AuLock_IR); + err = au_dbrange_test(dentry); + if (unlikely(err)) { + di_read_unlock(dentry, AuLock_IR); + goto out; + } + } else { + AuDebugOn(IS_ROOT(dentry)); + di_write_lock_child(dentry); + err = au_dbrange_test(dentry); + if (!err) + err = au_reval_for_attr(dentry, sigen); + if (!err) + di_downgrade_lock(dentry, AuLock_IR); + else { + di_write_unlock(dentry); + goto out; + } + } + } else + di_read_lock_child(dentry, AuLock_IR); + +body: + if (!inode) { + inode = d_inode(dentry); + if (unlikely(!inode)) + goto out; + } + bindex = au_ibtop(inode); + h_path->mnt = au_sbr_mnt(sb, bindex); + h_sb = h_path->mnt->mnt_sb; + if (!force + && !au_test_fs_bad_iattr(h_sb) + && udba_none) + goto out; /* success */ + + if (au_dbtop(dentry) == bindex) + h_path->dentry = au_h_dptr(dentry, bindex); + else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { + h_path->dentry = au_plink_lkup(inode, bindex); + if (IS_ERR(h_path->dentry)) + /* pretending success */ + h_path->dentry = NULL; + else + dput(h_path->dentry); + } + +out: + return err; +} + +static int aufs_getattr(const struct path *path, struct kstat *st, + u32 request, unsigned int query) +{ + int err; + unsigned char positive; + struct path h_path; + struct dentry *dentry; + struct inode *inode; + struct super_block *sb; + + dentry = path->dentry; + inode = d_inode(dentry); + sb = dentry->d_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out; + err = au_h_path_getattr(dentry, /*inode*/NULL, /*force*/0, &h_path, + /*locked*/0); + if (unlikely(err)) + goto out_si; + if (unlikely(!h_path.dentry)) + /* illegally overlapped or something */ + goto out_fill; /* pretending success */ + + positive = d_is_positive(h_path.dentry); + if (positive) + /* no vfsub version */ + err = vfs_getattr(&h_path, st, request, query); + if (!err) { + if (positive) + au_refresh_iattr(inode, st, + d_inode(h_path.dentry)->i_nlink); + goto out_fill; /* success */ + } + AuTraceErr(err); + goto out_di; + +out_fill: + generic_fillattr(inode, st); +out_di: + di_read_unlock(dentry, AuLock_IR); +out_si: + si_read_unlock(sb); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, + struct delayed_call *done) +{ + const char *ret; + struct dentry *h_dentry; + struct inode *h_inode; + int err; + aufs_bindex_t bindex; + + ret = NULL; /* suppress a warning */ + err = -ECHILD; + if (!dentry) + goto out; + + err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); + if (unlikely(err)) + goto out; + + err = au_d_hashed_positive(dentry); + if (unlikely(err)) + goto out_unlock; + + err = -EINVAL; + inode = d_inode(dentry); + bindex = au_ibtop(inode); + h_inode = au_h_iptr(inode, bindex); + if (unlikely(!h_inode->i_op->get_link)) + goto out_unlock; + + err = -EBUSY; + h_dentry = NULL; + if (au_dbtop(dentry) <= bindex) { + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry) + dget(h_dentry); + } + if (!h_dentry) { + h_dentry = d_find_any_alias(h_inode); + if (IS_ERR(h_dentry)) { + err = PTR_ERR(h_dentry); + goto out_unlock; + } + } + if (unlikely(!h_dentry)) + goto out_unlock; + + err = 0; + AuDbg("%ps\n", h_inode->i_op->get_link); + AuDbgDentry(h_dentry); + ret = vfs_get_link(h_dentry, done); + dput(h_dentry); + if (IS_ERR(ret)) + err = PTR_ERR(ret); + +out_unlock: + aufs_read_unlock(dentry, AuLock_IR); +out: + if (unlikely(err)) + ret = ERR_PTR(err); + AuTraceErrPtr(ret); + return ret; +} + +/* ---------------------------------------------------------------------- */ + +static int au_is_special(struct inode *inode) +{ + return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); +} + +static int aufs_update_time(struct inode *inode, struct timespec64 *ts, + int flags) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb; + struct inode *h_inode; + struct vfsmount *h_mnt; + + sb = inode->i_sb; + WARN_ONCE((flags & S_ATIME) && !IS_NOATIME(inode), + "unexpected s_flags 0x%lx", sb->s_flags); + + /* mmap_sem might be acquired already, cf. aufs_mmap() */ + lockdep_off(); + si_read_lock(sb, AuLock_FLUSH); + ii_write_lock_child(inode); + + err = 0; + bindex = au_ibtop(inode); + h_inode = au_h_iptr(inode, bindex); + if (!au_test_ro(sb, bindex, inode)) { + h_mnt = au_sbr_mnt(sb, bindex); + err = vfsub_mnt_want_write(h_mnt); + if (!err) { + err = vfsub_update_time(h_inode, ts, flags); + vfsub_mnt_drop_write(h_mnt); + } + } else if (au_is_special(h_inode)) { + /* + * Never copy-up here. + * These special files may already be opened and used for + * communicating. If we copied it up, then the communication + * would be corrupted. + */ + AuWarn1("timestamps for i%lu are ignored " + "since it is on readonly branch (hi%lu).\n", + inode->i_ino, h_inode->i_ino); + } else if (flags & ~S_ATIME) { + err = -EIO; + AuIOErr1("unexpected flags 0x%x\n", flags); + AuDebugOn(1); + } + + if (!err) + au_cpup_attr_timesizes(inode); + ii_write_unlock(inode); + si_read_unlock(sb); + lockdep_on(); + + if (!err && (flags & S_VERSION)) + inode_inc_iversion(inode); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* no getattr version will be set by module.c:aufs_init() */ +struct inode_operations aufs_iop_nogetattr[AuIop_Last], + aufs_iop[] = { + [AuIop_SYMLINK] = { + .permission = aufs_permission, +#ifdef CONFIG_FS_POSIX_ACL + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, /* unsupport for symlink? */ +#endif + + .setattr = aufs_setattr, + .getattr = aufs_getattr, + +#ifdef CONFIG_AUFS_XATTR + .listxattr = aufs_listxattr, +#endif + + .get_link = aufs_get_link, + + /* .update_time = aufs_update_time */ + }, + [AuIop_DIR] = { + .create = aufs_create, + .lookup = aufs_lookup, + .link = aufs_link, + .unlink = aufs_unlink, + .symlink = aufs_symlink, + .mkdir = aufs_mkdir, + .rmdir = aufs_rmdir, + .mknod = aufs_mknod, + .rename = aufs_rename, + + .permission = aufs_permission, +#ifdef CONFIG_FS_POSIX_ACL + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, +#endif + + .setattr = aufs_setattr, + .getattr = aufs_getattr, + +#ifdef CONFIG_AUFS_XATTR + .listxattr = aufs_listxattr, +#endif + + .update_time = aufs_update_time, + .atomic_open = aufs_atomic_open, + .tmpfile = aufs_tmpfile + }, + [AuIop_OTHER] = { + .permission = aufs_permission, +#ifdef CONFIG_FS_POSIX_ACL + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, +#endif + + .setattr = aufs_setattr, + .getattr = aufs_getattr, + +#ifdef CONFIG_AUFS_XATTR + .listxattr = aufs_listxattr, +#endif + + .update_time = aufs_update_time + } +}; diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c new file mode 100644 index 000000000000..af6893e61066 --- /dev/null +++ b/fs/aufs/i_op_add.c @@ -0,0 +1,936 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations (add entry) + */ + +#include +#include "aufs.h" + +/* + * final procedure of adding a new entry, except link(2). + * remove whiteout, instantiate, copyup the parent dir's times and size + * and update version. + * if it failed, re-create the removed whiteout. + */ +static int epilog(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct dentry *dentry) +{ + int err, rerr; + aufs_bindex_t bwh; + struct path h_path; + struct super_block *sb; + struct inode *inode, *h_dir; + struct dentry *wh; + + bwh = -1; + sb = dir->i_sb; + if (wh_dentry) { + h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ + IMustLock(h_dir); + AuDebugOn(au_h_iptr(dir, bindex) != h_dir); + bwh = au_dbwh(dentry); + h_path.dentry = wh_dentry; + h_path.mnt = au_sbr_mnt(sb, bindex); + err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, + dentry); + if (unlikely(err)) + goto out; + } + + inode = au_new_inode(dentry, /*must_new*/1); + if (!IS_ERR(inode)) { + d_instantiate(dentry, inode); + dir = d_inode(dentry->d_parent); /* dir inode is locked */ + IMustLock(dir); + au_dir_ts(dir, bindex); + inode_inc_iversion(dir); + au_fhsm_wrote(sb, bindex, /*force*/0); + return 0; /* success */ + } + + err = PTR_ERR(inode); + if (!wh_dentry) + goto out; + + /* revert */ + /* dir inode is locked */ + wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); + rerr = PTR_ERR(wh); + if (IS_ERR(wh)) { + AuIOErr("%pd reverting whiteout failed(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } else + dput(wh); + +out: + return err; +} + +static int au_d_may_add(struct dentry *dentry) +{ + int err; + + err = 0; + if (unlikely(d_unhashed(dentry))) + err = -ENOENT; + if (unlikely(d_really_is_positive(dentry))) + err = -EEXIST; + return err; +} + +/* + * simple tests for the adding inode operations. + * following the checks in vfs, plus the parent-child relationship. + */ +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir) +{ + int err; + umode_t h_mode; + struct dentry *h_dentry; + struct inode *h_inode; + + err = -ENAMETOOLONG; + if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) + goto out; + + h_dentry = au_h_dptr(dentry, bindex); + if (d_really_is_negative(dentry)) { + err = -EEXIST; + if (unlikely(d_is_positive(h_dentry))) + goto out; + } else { + /* rename(2) case */ + err = -EIO; + if (unlikely(d_is_negative(h_dentry))) + goto out; + h_inode = d_inode(h_dentry); + if (unlikely(!h_inode->i_nlink)) + goto out; + + h_mode = h_inode->i_mode; + if (!isdir) { + err = -EISDIR; + if (unlikely(S_ISDIR(h_mode))) + goto out; + } else if (unlikely(!S_ISDIR(h_mode))) { + err = -ENOTDIR; + goto out; + } + } + + err = 0; + /* expected parent dir is locked */ + if (unlikely(h_parent != h_dentry->d_parent)) + err = -EIO; + +out: + AuTraceErr(err); + return err; +} + +/* + * initial procedure of adding a new entry. + * prepare writable branch and the parent dir, lock it, + * and lookup whiteout for the new entry. + */ +static struct dentry* +lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, + struct dentry *src_dentry, struct au_pin *pin, + struct au_wr_dir_args *wr_dir_args) +{ + struct dentry *wh_dentry, *h_parent; + struct super_block *sb; + struct au_branch *br; + int err; + unsigned int udba; + aufs_bindex_t bcpup; + + AuDbg("%pd\n", dentry); + + err = au_wr_dir(dentry, src_dentry, wr_dir_args); + bcpup = err; + wh_dentry = ERR_PTR(err); + if (unlikely(err < 0)) + goto out; + + sb = dentry->d_sb; + udba = au_opt_udba(sb); + err = au_pin(pin, dentry, bcpup, udba, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out; + + h_parent = au_pinned_h_parent(pin); + if (udba != AuOpt_UDBA_NONE + && au_dbtop(dentry) == bcpup) + err = au_may_add(dentry, bcpup, h_parent, + au_ftest_wrdir(wr_dir_args->flags, ISDIR)); + else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) + err = -ENAMETOOLONG; + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_unpin; + + br = au_sbr(sb, bcpup); + if (dt) { + struct path tmp = { + .dentry = h_parent, + .mnt = au_br_mnt(br) + }; + au_dtime_store(dt, au_pinned_parent(pin), &tmp); + } + + wh_dentry = NULL; + if (bcpup != au_dbwh(dentry)) + goto out; /* success */ + + /* + * ENAMETOOLONG here means that if we allowed create such name, then it + * would not be able to removed in the future. So we don't allow such + * name here and we don't handle ENAMETOOLONG differently here. + */ + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); + +out_unpin: + if (IS_ERR(wh_dentry)) + au_unpin(pin); +out: + return wh_dentry; +} + +/* ---------------------------------------------------------------------- */ + +enum { Mknod, Symlink, Creat }; +struct simple_arg { + int type; + union { + struct { + umode_t mode; + bool want_excl; + bool try_aopen; + struct vfsub_aopen_args *aopen; + } c; + struct { + const char *symname; + } s; + struct { + umode_t mode; + dev_t dev; + } m; + } u; +}; + +static int add_simple(struct inode *dir, struct dentry *dentry, + struct simple_arg *arg) +{ + int err, rerr; + aufs_bindex_t btop; + unsigned char created; + const unsigned char try_aopen + = (arg->type == Creat && arg->u.c.try_aopen); + struct vfsub_aopen_args *aopen = arg->u.c.aopen; + struct dentry *wh_dentry, *parent; + struct inode *h_dir; + struct super_block *sb; + struct au_branch *br; + /* to reduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; + struct path h_path; + struct au_wr_dir_args wr_dir_args; + } *a; + + AuDbg("%pd\n", dentry); + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + a->wr_dir_args.force_btgt = -1; + a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; + + parent = dentry->d_parent; /* dir inode is locked */ + if (!try_aopen) { + err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); + if (unlikely(err)) + goto out_free; + } + err = au_d_may_add(dentry); + if (unlikely(err)) + goto out_unlock; + if (!try_aopen) + di_write_lock_parent(parent); + wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, + &a->pin, &a->wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + btop = au_dbtop(dentry); + sb = dentry->d_sb; + br = au_sbr(sb, btop); + a->h_path.dentry = au_h_dptr(dentry, btop); + a->h_path.mnt = au_br_mnt(br); + h_dir = au_pinned_h_dir(&a->pin); + switch (arg->type) { + case Creat: + if (!try_aopen || !h_dir->i_op->atomic_open) { + err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, + arg->u.c.want_excl); + created = !err; + if (!err && try_aopen) + aopen->file->f_mode |= FMODE_CREATED; + } else { + aopen->br = br; + err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); + AuDbg("err %d\n", err); + AuDbgFile(aopen->file); + created = err >= 0 + && !!(aopen->file->f_mode & FMODE_CREATED); + } + break; + case Symlink: + err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); + created = !err; + break; + case Mknod: + err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, + arg->u.m.dev); + created = !err; + break; + default: + BUG(); + } + if (unlikely(err < 0)) + goto out_unpin; + + err = epilog(dir, btop, wh_dentry, dentry); + if (!err) + goto out_unpin; /* success */ + + /* revert */ + if (created /* && d_is_positive(a->h_path.dentry) */) { + /* no delegation since it is just created */ + rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, + /*force*/0); + if (rerr) { + AuIOErr("%pd revert failure(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } + au_dtime_revert(&a->dt); + } + if (try_aopen && h_dir->i_op->atomic_open + && (aopen->file->f_mode & FMODE_OPENED)) + /* aopen->file is still opened */ + au_lcnt_dec(&aopen->br->br_nfiles); + +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); +out_parent: + if (!try_aopen) + di_write_unlock(parent); +out_unlock: + if (unlikely(err)) { + au_update_dbtop(dentry); + d_drop(dentry); + } + if (!try_aopen) + aufs_read_unlock(dentry, AuLock_DW); +out_free: + au_kfree_rcu(a); +out: + return err; +} + +int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t dev) +{ + struct simple_arg arg = { + .type = Mknod, + .u.m = { + .mode = mode, + .dev = dev + } + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + struct simple_arg arg = { + .type = Symlink, + .u.s.symname = symname + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool want_excl) +{ + struct simple_arg arg = { + .type = Creat, + .u.c = { + .mode = mode, + .want_excl = want_excl + } + }; + return add_simple(dir, dentry, &arg); +} + +int au_aopen_or_create(struct inode *dir, struct dentry *dentry, + struct vfsub_aopen_args *aopen_args) +{ + struct simple_arg arg = { + .type = Creat, + .u.c = { + .mode = aopen_args->create_mode, + .want_excl = aopen_args->open_flag & O_EXCL, + .try_aopen = true, + .aopen = aopen_args + } + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb; + struct dentry *parent, *h_parent, *h_dentry; + struct inode *h_dir, *inode; + struct vfsmount *h_mnt; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = AuWrDir_TMPFILE + }; + + /* copy-up may happen */ + inode_lock(dir); + + sb = dir->i_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out; + + err = au_di_init(dentry); + if (unlikely(err)) + goto out_si; + + err = -EBUSY; + parent = d_find_any_alias(dir); + AuDebugOn(!parent); + di_write_lock_parent(parent); + if (unlikely(d_inode(parent) != dir)) + goto out_parent; + + err = au_digen_test(parent, au_sigen(sb)); + if (unlikely(err)) + goto out_parent; + + bindex = au_dbtop(parent); + au_set_dbtop(dentry, bindex); + au_set_dbbot(dentry, bindex); + err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); + bindex = err; + if (unlikely(err < 0)) + goto out_parent; + + err = -EOPNOTSUPP; + h_dir = au_h_iptr(dir, bindex); + if (unlikely(!h_dir->i_op->tmpfile)) + goto out_parent; + + h_mnt = au_sbr_mnt(sb, bindex); + err = vfsub_mnt_want_write(h_mnt); + if (unlikely(err)) + goto out_parent; + + h_parent = au_h_dptr(parent, bindex); + h_dentry = vfs_tmpfile(h_parent, mode, /*open_flag*/0); + if (IS_ERR(h_dentry)) { + err = PTR_ERR(h_dentry); + goto out_mnt; + } + + au_set_dbtop(dentry, bindex); + au_set_dbbot(dentry, bindex); + au_set_h_dptr(dentry, bindex, dget(h_dentry)); + inode = au_new_inode(dentry, /*must_new*/1); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + au_set_h_dptr(dentry, bindex, NULL); + au_set_dbtop(dentry, -1); + au_set_dbbot(dentry, -1); + } else { + if (!inode->i_nlink) + set_nlink(inode, 1); + d_tmpfile(dentry, inode); + au_di(dentry)->di_tmpfile = 1; + + /* update without i_mutex */ + if (au_ibtop(dir) == au_dbtop(dentry)) + au_cpup_attr_timesizes(dir); + } + dput(h_dentry); + +out_mnt: + vfsub_mnt_drop_write(h_mnt); +out_parent: + di_write_unlock(parent); + dput(parent); + di_write_unlock(dentry); + if (unlikely(err)) { + au_di_fin(dentry); + dentry->d_fsdata = NULL; + } +out_si: + si_read_unlock(sb); +out: + inode_unlock(dir); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_link_args { + aufs_bindex_t bdst, bsrc; + struct au_pin pin; + struct path h_path; + struct dentry *src_parent, *parent; +}; + +static int au_cpup_before_link(struct dentry *src_dentry, + struct au_link_args *a) +{ + int err; + struct dentry *h_src_dentry; + struct au_cp_generic cpg = { + .dentry = src_dentry, + .bdst = a->bdst, + .bsrc = a->bsrc, + .len = -1, + .pin = &a->pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ + }; + + di_read_lock_parent(a->src_parent, AuLock_IR); + err = au_test_and_cpup_dirs(src_dentry, a->bdst); + if (unlikely(err)) + goto out; + + h_src_dentry = au_h_dptr(src_dentry, a->bsrc); + err = au_pin(&a->pin, src_dentry, a->bdst, + au_opt_udba(src_dentry->d_sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out; + + err = au_sio_cpup_simple(&cpg); + au_unpin(&a->pin); + +out: + di_read_unlock(a->src_parent, AuLock_IR); + return err; +} + +static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, + struct au_link_args *a) +{ + int err; + unsigned char plink; + aufs_bindex_t bbot; + struct dentry *h_src_dentry; + struct inode *h_inode, *inode, *delegated; + struct super_block *sb; + struct file *h_file; + + plink = 0; + h_inode = NULL; + sb = src_dentry->d_sb; + inode = d_inode(src_dentry); + if (au_ibtop(inode) <= a->bdst) + h_inode = au_h_iptr(inode, a->bdst); + if (!h_inode || !h_inode->i_nlink) { + /* copyup src_dentry as the name of dentry. */ + bbot = au_dbbot(dentry); + if (bbot < a->bsrc) + au_set_dbbot(dentry, a->bsrc); + au_set_h_dptr(dentry, a->bsrc, + dget(au_h_dptr(src_dentry, a->bsrc))); + dget(a->h_path.dentry); + au_set_h_dptr(dentry, a->bdst, NULL); + AuDbg("temporary d_inode...\n"); + spin_lock(&dentry->d_lock); + dentry->d_inode = d_inode(src_dentry); /* tmp */ + spin_unlock(&dentry->d_lock); + h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); + if (IS_ERR(h_file)) + err = PTR_ERR(h_file); + else { + struct au_cp_generic cpg = { + .dentry = dentry, + .bdst = a->bdst, + .bsrc = -1, + .len = -1, + .pin = &a->pin, + .flags = AuCpup_KEEPLINO + }; + err = au_sio_cpup_simple(&cpg); + au_h_open_post(dentry, a->bsrc, h_file); + if (!err) { + dput(a->h_path.dentry); + a->h_path.dentry = au_h_dptr(dentry, a->bdst); + } else + au_set_h_dptr(dentry, a->bdst, + a->h_path.dentry); + } + spin_lock(&dentry->d_lock); + dentry->d_inode = NULL; /* restore */ + spin_unlock(&dentry->d_lock); + AuDbg("temporary d_inode...done\n"); + au_set_h_dptr(dentry, a->bsrc, NULL); + au_set_dbbot(dentry, bbot); + } else { + /* the inode of src_dentry already exists on a.bdst branch */ + h_src_dentry = d_find_alias(h_inode); + if (!h_src_dentry && au_plink_test(inode)) { + plink = 1; + h_src_dentry = au_plink_lkup(inode, a->bdst); + err = PTR_ERR(h_src_dentry); + if (IS_ERR(h_src_dentry)) + goto out; + + if (unlikely(d_is_negative(h_src_dentry))) { + dput(h_src_dentry); + h_src_dentry = NULL; + } + + } + if (h_src_dentry) { + delegated = NULL; + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + dput(h_src_dentry); + } else { + AuIOErr("no dentry found for hi%lu on b%d\n", + h_inode->i_ino, a->bdst); + err = -EIO; + } + } + + if (!err && !plink) + au_plink_append(inode, a->bdst, a->h_path.dentry); + +out: + AuTraceErr(err); + return err; +} + +int aufs_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry) +{ + int err, rerr; + struct au_dtime dt; + struct au_link_args *a; + struct dentry *wh_dentry, *h_src_dentry; + struct inode *inode, *delegated; + struct super_block *sb; + struct au_wr_dir_args wr_dir_args = { + /* .force_btgt = -1, */ + .flags = AuWrDir_ADD_ENTRY + }; + + IMustLock(dir); + inode = d_inode(src_dentry); + IMustLock(inode); + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + a->parent = dentry->d_parent; /* dir inode is locked */ + err = aufs_read_and_write_lock2(dentry, src_dentry, + AuLock_NOPLM | AuLock_GEN); + if (unlikely(err)) + goto out_kfree; + err = au_d_linkable(src_dentry); + if (unlikely(err)) + goto out_unlock; + err = au_d_may_add(dentry); + if (unlikely(err)) + goto out_unlock; + + a->src_parent = dget_parent(src_dentry); + wr_dir_args.force_btgt = au_ibtop(inode); + + di_write_lock_parent(a->parent); + wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); + wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, + &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + err = 0; + sb = dentry->d_sb; + a->bdst = au_dbtop(dentry); + a->h_path.dentry = au_h_dptr(dentry, a->bdst); + a->h_path.mnt = au_sbr_mnt(sb, a->bdst); + a->bsrc = au_ibtop(inode); + h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); + if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) + h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); + if (!h_src_dentry) { + a->bsrc = au_dbtop(src_dentry); + h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); + AuDebugOn(!h_src_dentry); + } else if (IS_ERR(h_src_dentry)) { + err = PTR_ERR(h_src_dentry); + goto out_parent; + } + + /* + * aufs doesn't touch the credential so + * security_dentry_create_files_as() is unnecessary. + */ + if (au_opt_test(au_mntflags(sb), PLINK)) { + if (a->bdst < a->bsrc + /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) + err = au_cpup_or_link(src_dentry, dentry, a); + else { + delegated = NULL; + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + } + dput(h_src_dentry); + } else { + /* + * copyup src_dentry to the branch we process, + * and then link(2) to it. + */ + dput(h_src_dentry); + if (a->bdst < a->bsrc + /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { + au_unpin(&a->pin); + di_write_unlock(a->parent); + err = au_cpup_before_link(src_dentry, a); + di_write_lock_parent(a->parent); + if (!err) + err = au_pin(&a->pin, dentry, a->bdst, + au_opt_udba(sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (unlikely(err)) + goto out_wh; + } + if (!err) { + h_src_dentry = au_h_dptr(src_dentry, a->bdst); + err = -ENOENT; + if (h_src_dentry && d_is_positive(h_src_dentry)) { + delegated = NULL; + err = vfsub_link(h_src_dentry, + au_pinned_h_dir(&a->pin), + &a->h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry" + " for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + } + } + } + if (unlikely(err)) + goto out_unpin; + + if (wh_dentry) { + a->h_path.dentry = wh_dentry; + err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, + dentry); + if (unlikely(err)) + goto out_revert; + } + + au_dir_ts(dir, a->bdst); + inode_inc_iversion(dir); + inc_nlink(inode); + inode->i_ctime = dir->i_ctime; + d_instantiate(dentry, au_igrab(inode)); + if (d_unhashed(a->h_path.dentry)) + /* some filesystem calls d_drop() */ + d_drop(dentry); + /* some filesystems consume an inode even hardlink */ + au_fhsm_wrote(sb, a->bdst, /*force*/0); + goto out_unpin; /* success */ + +out_revert: + /* no delegation since it is just created */ + rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, + /*delegated*/NULL, /*force*/0); + if (unlikely(rerr)) { + AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); + err = -EIO; + } + au_dtime_revert(&dt); +out_unpin: + au_unpin(&a->pin); +out_wh: + dput(wh_dentry); +out_parent: + di_write_unlock(a->parent); + dput(a->src_parent); +out_unlock: + if (unlikely(err)) { + au_update_dbtop(dentry); + d_drop(dentry); + } + aufs_read_and_write_unlock2(dentry, src_dentry); +out_kfree: + au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} + +int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + int err, rerr; + aufs_bindex_t bindex; + unsigned char diropq; + struct path h_path; + struct dentry *wh_dentry, *parent, *opq_dentry; + struct inode *h_inode; + struct super_block *sb; + struct { + struct au_pin pin; + struct au_dtime dt; + } *a; /* reduce the stack usage */ + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR + }; + + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_d_may_add(dentry); + if (unlikely(err)) + goto out_unlock; + + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, + &a->pin, &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + sb = dentry->d_sb; + bindex = au_dbtop(dentry); + h_path.dentry = au_h_dptr(dentry, bindex); + h_path.mnt = au_sbr_mnt(sb, bindex); + err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); + if (unlikely(err)) + goto out_unpin; + + /* make the dir opaque */ + diropq = 0; + h_inode = d_inode(h_path.dentry); + if (wh_dentry + || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { + inode_lock_nested(h_inode, AuLsc_I_CHILD); + opq_dentry = au_diropq_create(dentry, bindex); + inode_unlock(h_inode); + err = PTR_ERR(opq_dentry); + if (IS_ERR(opq_dentry)) + goto out_dir; + dput(opq_dentry); + diropq = 1; + } + + err = epilog(dir, bindex, wh_dentry, dentry); + if (!err) { + inc_nlink(dir); + goto out_unpin; /* success */ + } + + /* revert */ + if (diropq) { + AuLabel(revert opq); + inode_lock_nested(h_inode, AuLsc_I_CHILD); + rerr = au_diropq_remove(dentry, bindex); + inode_unlock(h_inode); + if (rerr) { + AuIOErr("%pd reverting diropq failed(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } + } + +out_dir: + AuLabel(revert dir); + rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); + if (rerr) { + AuIOErr("%pd reverting dir failed(%d, %d)\n", + dentry, err, rerr); + err = -EIO; + } + au_dtime_revert(&a->dt); +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); +out_parent: + di_write_unlock(parent); +out_unlock: + if (unlikely(err)) { + au_update_dbtop(dentry); + d_drop(dentry); + } + aufs_read_unlock(dentry, AuLock_DW); +out_free: + au_kfree_rcu(a); +out: + return err; +} diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c new file mode 100644 index 000000000000..1c459dbea5db --- /dev/null +++ b/fs/aufs/i_op_del.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations (del entry) + */ + +#include +#include "aufs.h" + +/* + * decide if a new whiteout for @dentry is necessary or not. + * when it is necessary, prepare the parent dir for the upper branch whose + * branch index is @bcpup for creation. the actual creation of the whiteout will + * be done by caller. + * return value: + * 0: wh is unnecessary + * plus: wh is necessary + * minus: error + */ +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) +{ + int need_wh, err; + aufs_bindex_t btop; + struct super_block *sb; + + sb = dentry->d_sb; + btop = au_dbtop(dentry); + if (*bcpup < 0) { + *bcpup = btop; + if (au_test_ro(sb, btop, d_inode(dentry))) { + err = AuWbrCopyup(au_sbi(sb), dentry); + *bcpup = err; + if (unlikely(err < 0)) + goto out; + } + } else + AuDebugOn(btop < *bcpup + || au_test_ro(sb, *bcpup, d_inode(dentry))); + AuDbg("bcpup %d, btop %d\n", *bcpup, btop); + + if (*bcpup != btop) { + err = au_cpup_dirs(dentry, *bcpup); + if (unlikely(err)) + goto out; + need_wh = 1; + } else { + struct au_dinfo *dinfo, *tmp; + + need_wh = -ENOMEM; + dinfo = au_di(dentry); + tmp = au_di_alloc(sb, AuLsc_DI_TMP); + if (tmp) { + au_di_cp(tmp, dinfo); + au_di_swap(tmp, dinfo); + /* returns the number of positive dentries */ + need_wh = au_lkup_dentry(dentry, btop + 1, + /* AuLkup_IGNORE_PERM */ 0); + au_di_swap(tmp, dinfo); + au_rw_write_unlock(&tmp->di_rwsem); + au_di_free(tmp); + } + } + AuDbg("need_wh %d\n", need_wh); + err = need_wh; + +out: + return err; +} + +/* + * simple tests for the del-entry operations. + * following the checks in vfs, plus the parent-child relationship. + */ +int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir) +{ + int err; + umode_t h_mode; + struct dentry *h_dentry, *h_latest; + struct inode *h_inode; + + h_dentry = au_h_dptr(dentry, bindex); + if (d_really_is_positive(dentry)) { + err = -ENOENT; + if (unlikely(d_is_negative(h_dentry))) + goto out; + h_inode = d_inode(h_dentry); + if (unlikely(!h_inode->i_nlink)) + goto out; + + h_mode = h_inode->i_mode; + if (!isdir) { + err = -EISDIR; + if (unlikely(S_ISDIR(h_mode))) + goto out; + } else if (unlikely(!S_ISDIR(h_mode))) { + err = -ENOTDIR; + goto out; + } + } else { + /* rename(2) case */ + err = -EIO; + if (unlikely(d_is_positive(h_dentry))) + goto out; + } + + err = -ENOENT; + /* expected parent dir is locked */ + if (unlikely(h_parent != h_dentry->d_parent)) + goto out; + err = 0; + + /* + * rmdir a dir may break the consistency on some filesystem. + * let's try heavy test. + */ + err = -EACCES; + if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) + && au_test_h_perm(d_inode(h_parent), + MAY_EXEC | MAY_WRITE))) + goto out; + + h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); + err = -EIO; + if (IS_ERR(h_latest)) + goto out; + if (h_latest == h_dentry) + err = 0; + dput(h_latest); + +out: + return err; +} + +/* + * decide the branch where we operate for @dentry. the branch index will be set + * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent + * dir for reverting. + * when a new whiteout is necessary, create it. + */ +static struct dentry* +lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, + struct au_dtime *dt, struct au_pin *pin) +{ + struct dentry *wh_dentry; + struct super_block *sb; + struct path h_path; + int err, need_wh; + unsigned int udba; + aufs_bindex_t bcpup; + + need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); + wh_dentry = ERR_PTR(need_wh); + if (unlikely(need_wh < 0)) + goto out; + + sb = dentry->d_sb; + udba = au_opt_udba(sb); + bcpup = *rbcpup; + err = au_pin(pin, dentry, bcpup, udba, + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out; + + h_path.dentry = au_pinned_h_parent(pin); + if (udba != AuOpt_UDBA_NONE + && au_dbtop(dentry) == bcpup) { + err = au_may_del(dentry, bcpup, h_path.dentry, isdir); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_unpin; + } + + h_path.mnt = au_sbr_mnt(sb, bcpup); + au_dtime_store(dt, au_pinned_parent(pin), &h_path); + wh_dentry = NULL; + if (!need_wh) + goto out; /* success, no need to create whiteout */ + + wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); + if (IS_ERR(wh_dentry)) + goto out_unpin; + + /* returns with the parent is locked and wh_dentry is dget-ed */ + goto out; /* success */ + +out_unpin: + au_unpin(pin); +out: + return wh_dentry; +} + +/* + * when removing a dir, rename it to a unique temporary whiteout-ed name first + * in order to be revertible and save time for removing many child whiteouts + * under the dir. + * returns 1 when there are too many child whiteout and caller should remove + * them asynchronously. returns 0 when the number of children is enough small to + * remove now or the branch fs is a remote fs. + * otherwise return an error. + */ +static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, + struct au_nhash *whlist, struct inode *dir) +{ + int rmdir_later, err, dirwh; + struct dentry *h_dentry; + struct super_block *sb; + struct inode *inode; + + sb = dentry->d_sb; + SiMustAnyLock(sb); + h_dentry = au_h_dptr(dentry, bindex); + err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); + if (unlikely(err)) + goto out; + + /* stop monitoring */ + inode = d_inode(dentry); + au_hn_free(au_hi(inode, bindex)); + + if (!au_test_fs_remote(h_dentry->d_sb)) { + dirwh = au_sbi(sb)->si_dirwh; + rmdir_later = (dirwh <= 1); + if (!rmdir_later) + rmdir_later = au_nhash_test_longer_wh(whlist, bindex, + dirwh); + if (rmdir_later) + return rmdir_later; + } + + err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); + if (unlikely(err)) { + AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", + h_dentry, bindex, err); + err = 0; + } + +out: + AuTraceErr(err); + return err; +} + +/* + * final procedure for deleting a entry. + * maintain dentry and iattr. + */ +static void epilog(struct inode *dir, struct dentry *dentry, + aufs_bindex_t bindex) +{ + struct inode *inode; + + inode = d_inode(dentry); + d_drop(dentry); + inode->i_ctime = dir->i_ctime; + + au_dir_ts(dir, bindex); + inode_inc_iversion(dir); +} + +/* + * when an error happened, remove the created whiteout and revert everything. + */ +static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, + aufs_bindex_t bwh, struct dentry *wh_dentry, + struct dentry *dentry, struct au_dtime *dt) +{ + int rerr; + struct path h_path = { + .dentry = wh_dentry, + .mnt = au_sbr_mnt(dir->i_sb, bindex) + }; + + rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); + if (!rerr) { + au_set_dbwh(dentry, bwh); + au_dtime_revert(dt); + return 0; + } + + AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); + return -EIO; +} + +/* ---------------------------------------------------------------------- */ + +int aufs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + aufs_bindex_t bwh, bindex, btop; + struct inode *inode, *h_dir, *delegated; + struct dentry *parent, *wh_dentry; + /* to reduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; + struct path h_path; + } *a; + + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_d_hashed_positive(dentry); + if (unlikely(err)) + goto out_unlock; + inode = d_inode(dentry); + IMustLock(inode); + err = -EISDIR; + if (unlikely(d_is_dir(dentry))) + goto out_unlock; /* possible? */ + + btop = au_dbtop(dentry); + bwh = au_dbwh(dentry); + bindex = -1; + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, + &a->pin); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); + a->h_path.dentry = au_h_dptr(dentry, btop); + dget(a->h_path.dentry); + if (bindex == btop) { + h_dir = au_pinned_h_dir(&a->pin); + delegated = NULL; + err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + } else { + /* dir inode is locked */ + h_dir = d_inode(wh_dentry->d_parent); + IMustLock(h_dir); + err = 0; + } + + if (!err) { + vfsub_drop_nlink(inode); + epilog(dir, dentry, bindex); + + /* update target timestamps */ + if (bindex == btop) { + vfsub_update_h_iattr(&a->h_path, /*did*/NULL); + /*ignore*/ + inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; + } else + /* todo: this timestamp may be reverted later */ + inode->i_ctime = h_dir->i_ctime; + goto out_unpin; /* success */ + } + + /* revert */ + if (wh_dentry) { + int rerr; + + rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, + &a->dt); + if (rerr) + err = rerr; + } + +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); + dput(a->h_path.dentry); +out_parent: + di_write_unlock(parent); +out_unlock: + aufs_read_unlock(dentry, AuLock_DW); +out_free: + au_kfree_rcu(a); +out: + return err; +} + +int aufs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err, rmdir_later; + aufs_bindex_t bwh, bindex, btop; + struct inode *inode; + struct dentry *parent, *wh_dentry, *h_dentry; + struct au_whtmp_rmdir *args; + /* to reduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; + } *a; + + IMustLock(dir); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); + if (unlikely(err)) + goto out_free; + err = au_alive_dir(dentry); + if (unlikely(err)) + goto out_unlock; + inode = d_inode(dentry); + IMustLock(inode); + err = -ENOTDIR; + if (unlikely(!d_is_dir(dentry))) + goto out_unlock; /* possible? */ + + err = -ENOMEM; + args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); + if (unlikely(!args)) + goto out_unlock; + + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + err = au_test_empty(dentry, &args->whlist); + if (unlikely(err)) + goto out_parent; + + btop = au_dbtop(dentry); + bwh = au_dbwh(dentry); + bindex = -1; + wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, + &a->pin); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_parent; + + h_dentry = au_h_dptr(dentry, btop); + dget(h_dentry); + rmdir_later = 0; + if (bindex == btop) { + err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); + if (err > 0) { + rmdir_later = err; + err = 0; + } + } else { + /* stop monitoring */ + au_hn_free(au_hi(inode, btop)); + + /* dir inode is locked */ + IMustLock(d_inode(wh_dentry->d_parent)); + err = 0; + } + + if (!err) { + vfsub_dead_dir(inode); + au_set_dbdiropq(dentry, -1); + epilog(dir, dentry, bindex); + + if (rmdir_later) { + au_whtmp_kick_rmdir(dir, btop, h_dentry, args); + args = NULL; + } + + goto out_unpin; /* success */ + } + + /* revert */ + AuLabel(revert); + if (wh_dentry) { + int rerr; + + rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, + &a->dt); + if (rerr) + err = rerr; + } + +out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); + dput(h_dentry); +out_parent: + di_write_unlock(parent); + if (args) + au_whtmp_rmdir_free(args); +out_unlock: + aufs_read_unlock(dentry, AuLock_DW); +out_free: + au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c new file mode 100644 index 000000000000..d0fa03976273 --- /dev/null +++ b/fs/aufs/i_op_ren.c @@ -0,0 +1,1250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operation (rename entry) + * todo: this is crazy monster + */ + +#include +#include "aufs.h" + +enum { AuSRC, AuDST, AuSrcDst }; +enum { AuPARENT, AuCHILD, AuParentChild }; + +#define AuRen_ISDIR_SRC 1 +#define AuRen_ISDIR_DST (1 << 1) +#define AuRen_ISSAMEDIR (1 << 2) +#define AuRen_WHSRC (1 << 3) +#define AuRen_WHDST (1 << 4) +#define AuRen_MNT_WRITE (1 << 5) +#define AuRen_DT_DSTDIR (1 << 6) +#define AuRen_DIROPQ_SRC (1 << 7) +#define AuRen_DIROPQ_DST (1 << 8) +#define AuRen_DIRREN (1 << 9) +#define AuRen_DROPPED_SRC (1 << 10) +#define AuRen_DROPPED_DST (1 << 11) +#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) +#define au_fset_ren(flags, name) \ + do { (flags) |= AuRen_##name; } while (0) +#define au_fclr_ren(flags, name) \ + do { (flags) &= ~AuRen_##name; } while (0) + +#ifndef CONFIG_AUFS_DIRREN +#undef AuRen_DIRREN +#define AuRen_DIRREN 0 +#endif + +struct au_ren_args { + struct { + struct dentry *dentry, *h_dentry, *parent, *h_parent, + *wh_dentry; + struct inode *dir, *inode; + struct au_hinode *hdir, *hinode; + struct au_dtime dt[AuParentChild]; + aufs_bindex_t btop, bdiropq; + } sd[AuSrcDst]; + +#define src_dentry sd[AuSRC].dentry +#define src_dir sd[AuSRC].dir +#define src_inode sd[AuSRC].inode +#define src_h_dentry sd[AuSRC].h_dentry +#define src_parent sd[AuSRC].parent +#define src_h_parent sd[AuSRC].h_parent +#define src_wh_dentry sd[AuSRC].wh_dentry +#define src_hdir sd[AuSRC].hdir +#define src_hinode sd[AuSRC].hinode +#define src_h_dir sd[AuSRC].hdir->hi_inode +#define src_dt sd[AuSRC].dt +#define src_btop sd[AuSRC].btop +#define src_bdiropq sd[AuSRC].bdiropq + +#define dst_dentry sd[AuDST].dentry +#define dst_dir sd[AuDST].dir +#define dst_inode sd[AuDST].inode +#define dst_h_dentry sd[AuDST].h_dentry +#define dst_parent sd[AuDST].parent +#define dst_h_parent sd[AuDST].h_parent +#define dst_wh_dentry sd[AuDST].wh_dentry +#define dst_hdir sd[AuDST].hdir +#define dst_hinode sd[AuDST].hinode +#define dst_h_dir sd[AuDST].hdir->hi_inode +#define dst_dt sd[AuDST].dt +#define dst_btop sd[AuDST].btop +#define dst_bdiropq sd[AuDST].bdiropq + + struct dentry *h_trap; + struct au_branch *br; + struct path h_path; + struct au_nhash whlist; + aufs_bindex_t btgt, src_bwh; + + struct { + unsigned short auren_flags; + unsigned char flags; /* syscall parameter */ + unsigned char exchange; + } __packed; + + struct au_whtmp_rmdir *thargs; + struct dentry *h_dst; + struct au_hinode *h_root; +}; + +/* ---------------------------------------------------------------------- */ + +/* + * functions for reverting. + * when an error happened in a single rename systemcall, we should revert + * everything as if nothing happened. + * we don't need to revert the copied-up/down the parent dir since they are + * harmless. + */ + +#define RevertFailure(fmt, ...) do { \ + AuIOErr("revert failure: " fmt " (%d, %d)\n", \ + ##__VA_ARGS__, err, rerr); \ + err = -EIO; \ +} while (0) + +static void au_ren_do_rev_diropq(int err, struct au_ren_args *a, int idx) +{ + int rerr; + struct dentry *d; +#define src_or_dst(member) a->sd[idx].member + + d = src_or_dst(dentry); /* {src,dst}_dentry */ + au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); + rerr = au_diropq_remove(d, a->btgt); + au_hn_inode_unlock(src_or_dst(hinode)); + au_set_dbdiropq(d, src_or_dst(bdiropq)); + if (rerr) + RevertFailure("remove diropq %pd", d); + +#undef src_or_dst_ +} + +static void au_ren_rev_diropq(int err, struct au_ren_args *a) +{ + if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) + au_ren_do_rev_diropq(err, a, AuSRC); + if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) + au_ren_do_rev_diropq(err, a, AuDST); +} + +static void au_ren_rev_rename(int err, struct au_ren_args *a) +{ + int rerr; + struct inode *delegated; + + a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, + a->src_h_parent); + rerr = PTR_ERR(a->h_path.dentry); + if (IS_ERR(a->h_path.dentry)) { + RevertFailure("lkup one %pd", a->src_dentry); + return; + } + + delegated = NULL; + rerr = vfsub_rename(a->dst_h_dir, + au_h_dptr(a->src_dentry, a->btgt), + a->src_h_dir, &a->h_path, &delegated, a->flags); + if (unlikely(rerr == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + d_drop(a->h_path.dentry); + dput(a->h_path.dentry); + /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ + if (rerr) + RevertFailure("rename %pd", a->src_dentry); +} + +static void au_ren_rev_whtmp(int err, struct au_ren_args *a) +{ + int rerr; + struct inode *delegated; + + a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, + a->dst_h_parent); + rerr = PTR_ERR(a->h_path.dentry); + if (IS_ERR(a->h_path.dentry)) { + RevertFailure("lkup one %pd", a->dst_dentry); + return; + } + if (d_is_positive(a->h_path.dentry)) { + d_drop(a->h_path.dentry); + dput(a->h_path.dentry); + return; + } + + delegated = NULL; + rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, + &delegated, a->flags); + if (unlikely(rerr == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + d_drop(a->h_path.dentry); + dput(a->h_path.dentry); + if (!rerr) + au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); + else + RevertFailure("rename %pd", a->h_dst); +} + +static void au_ren_rev_whsrc(int err, struct au_ren_args *a) +{ + int rerr; + + a->h_path.dentry = a->src_wh_dentry; + rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); + au_set_dbwh(a->src_dentry, a->src_bwh); + if (rerr) + RevertFailure("unlink %pd", a->src_wh_dentry); +} +#undef RevertFailure + +/* ---------------------------------------------------------------------- */ + +/* + * when we have to copyup the renaming entry, do it with the rename-target name + * in order to minimize the cost (the later actual rename is unnecessary). + * otherwise rename it on the target branch. + */ +static int au_ren_or_cpup(struct au_ren_args *a) +{ + int err; + struct dentry *d; + struct inode *delegated; + + d = a->src_dentry; + if (au_dbtop(d) == a->btgt) { + a->h_path.dentry = a->dst_h_dentry; + AuDebugOn(au_dbtop(d) != a->btgt); + delegated = NULL; + err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), + a->dst_h_dir, &a->h_path, &delegated, + a->flags); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + } else + BUG(); + + if (!err && a->h_dst) + /* it will be set to dinfo later */ + dget(a->h_dst); + + return err; +} + +/* cf. aufs_rmdir() */ +static int au_ren_del_whtmp(struct au_ren_args *a) +{ + int err; + struct inode *dir; + + dir = a->dst_dir; + SiMustAnyLock(dir->i_sb); + if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, + au_sbi(dir->i_sb)->si_dirwh) + || au_test_fs_remote(a->h_dst->d_sb)) { + err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); + if (unlikely(err)) + pr_warn("failed removing whtmp dir %pd (%d), " + "ignored.\n", a->h_dst, err); + } else { + au_nhash_wh_free(&a->thargs->whlist); + a->thargs->whlist = a->whlist; + a->whlist.nh_num = 0; + au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); + dput(a->h_dst); + a->thargs = NULL; + } + + return 0; +} + +/* make it 'opaque' dir. */ +static int au_ren_do_diropq(struct au_ren_args *a, int idx) +{ + int err; + struct dentry *d, *diropq; +#define src_or_dst(member) a->sd[idx].member + + err = 0; + d = src_or_dst(dentry); /* {src,dst}_dentry */ + src_or_dst(bdiropq) = au_dbdiropq(d); + src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); + au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); + diropq = au_diropq_create(d, a->btgt); + au_hn_inode_unlock(src_or_dst(hinode)); + if (IS_ERR(diropq)) + err = PTR_ERR(diropq); + else + dput(diropq); + +#undef src_or_dst_ + return err; +} + +static int au_ren_diropq(struct au_ren_args *a) +{ + int err; + unsigned char always; + struct dentry *d; + + err = 0; + d = a->dst_dentry; /* already renamed on the branch */ + always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); + if (au_ftest_ren(a->auren_flags, ISDIR_SRC) + && !au_ftest_ren(a->auren_flags, DIRREN) + && a->btgt != au_dbdiropq(a->src_dentry) + && (a->dst_wh_dentry + || a->btgt <= au_dbdiropq(d) + /* hide the lower to keep xino */ + /* the lowers may not be a dir, but we hide them anyway */ + || a->btgt < au_dbbot(d) + || always)) { + AuDbg("here\n"); + err = au_ren_do_diropq(a, AuSRC); + if (unlikely(err)) + goto out; + au_fset_ren(a->auren_flags, DIROPQ_SRC); + } + if (!a->exchange) + goto out; /* success */ + + d = a->src_dentry; /* already renamed on the branch */ + if (au_ftest_ren(a->auren_flags, ISDIR_DST) + && a->btgt != au_dbdiropq(a->dst_dentry) + && (a->btgt < au_dbdiropq(d) + || a->btgt < au_dbbot(d) + || always)) { + AuDbgDentry(a->src_dentry); + AuDbgDentry(a->dst_dentry); + err = au_ren_do_diropq(a, AuDST); + if (unlikely(err)) + goto out_rev_src; + au_fset_ren(a->auren_flags, DIROPQ_DST); + } + goto out; /* success */ + +out_rev_src: + AuDbg("err %d, reverting src\n", err); + au_ren_rev_diropq(err, a); +out: + return err; +} + +static int do_rename(struct au_ren_args *a) +{ + int err; + struct dentry *d, *h_d; + + if (!a->exchange) { + /* prepare workqueue args for asynchronous rmdir */ + h_d = a->dst_h_dentry; + if (au_ftest_ren(a->auren_flags, ISDIR_DST) + /* && !au_ftest_ren(a->auren_flags, DIRREN) */ + && d_is_positive(h_d)) { + err = -ENOMEM; + a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, + GFP_NOFS); + if (unlikely(!a->thargs)) + goto out; + a->h_dst = dget(h_d); + } + + /* create whiteout for src_dentry */ + if (au_ftest_ren(a->auren_flags, WHSRC)) { + a->src_bwh = au_dbwh(a->src_dentry); + AuDebugOn(a->src_bwh >= 0); + a->src_wh_dentry = au_wh_create(a->src_dentry, a->btgt, + a->src_h_parent); + err = PTR_ERR(a->src_wh_dentry); + if (IS_ERR(a->src_wh_dentry)) + goto out_thargs; + } + + /* lookup whiteout for dentry */ + if (au_ftest_ren(a->auren_flags, WHDST)) { + h_d = au_wh_lkup(a->dst_h_parent, + &a->dst_dentry->d_name, a->br); + err = PTR_ERR(h_d); + if (IS_ERR(h_d)) + goto out_whsrc; + if (d_is_negative(h_d)) + dput(h_d); + else + a->dst_wh_dentry = h_d; + } + + /* rename dentry to tmpwh */ + if (a->thargs) { + err = au_whtmp_ren(a->dst_h_dentry, a->br); + if (unlikely(err)) + goto out_whdst; + + d = a->dst_dentry; + au_set_h_dptr(d, a->btgt, NULL); + err = au_lkup_neg(d, a->btgt, /*wh*/0); + if (unlikely(err)) + goto out_whtmp; + a->dst_h_dentry = au_h_dptr(d, a->btgt); + } + } + + BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); +#if 0 /* debugging */ + BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) + && d_is_positive(a->dst_h_dentry) + && a->src_btop != a->btgt); +#endif + + /* rename by vfs_rename or cpup */ + err = au_ren_or_cpup(a); + if (unlikely(err)) + /* leave the copied-up one */ + goto out_whtmp; + + /* make dir opaque */ + err = au_ren_diropq(a); + if (unlikely(err)) + goto out_rename; + + /* update target timestamps */ + if (a->exchange) { + AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); + a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); + vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ + a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; + } + AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); + a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); + vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ + a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; + + if (!a->exchange) { + /* remove whiteout for dentry */ + if (a->dst_wh_dentry) { + a->h_path.dentry = a->dst_wh_dentry; + err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, + a->dst_dentry); + if (unlikely(err)) + goto out_diropq; + } + + /* remove whtmp */ + if (a->thargs) + au_ren_del_whtmp(a); /* ignore this error */ + + au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); + } + err = 0; + goto out_success; + +out_diropq: + au_ren_rev_diropq(err, a); +out_rename: + au_ren_rev_rename(err, a); + dput(a->h_dst); +out_whtmp: + if (a->thargs) + au_ren_rev_whtmp(err, a); +out_whdst: + dput(a->dst_wh_dentry); + a->dst_wh_dentry = NULL; +out_whsrc: + if (a->src_wh_dentry) + au_ren_rev_whsrc(err, a); +out_success: + dput(a->src_wh_dentry); + dput(a->dst_wh_dentry); +out_thargs: + if (a->thargs) { + dput(a->h_dst); + au_whtmp_rmdir_free(a->thargs); + a->thargs = NULL; + } +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * test if @dentry dir can be rename destination or not. + * success means, it is a logically empty dir. + */ +static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) +{ + return au_test_empty(dentry, whlist); +} + +/* + * test if @a->src_dentry dir can be rename source or not. + * if it can, return 0. + * success means, + * - it is a logically empty dir. + * - or, it exists on writable branch and has no children including whiteouts + * on the lower branch unless DIRREN is on. + */ +static int may_rename_srcdir(struct au_ren_args *a) +{ + int err; + unsigned int rdhash; + aufs_bindex_t btop, btgt; + struct dentry *dentry; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + dentry = a->src_dentry; + sb = dentry->d_sb; + sbinfo = au_sbi(sb); + if (au_opt_test(sbinfo->si_mntflags, DIRREN)) + au_fset_ren(a->auren_flags, DIRREN); + + btgt = a->btgt; + btop = au_dbtop(dentry); + if (btop != btgt) { + struct au_nhash whlist; + + SiMustAnyLock(sb); + rdhash = sbinfo->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, + dentry)); + err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_test_empty(dentry, &whlist); + au_nhash_wh_free(&whlist); + goto out; + } + + if (btop == au_dbtaildir(dentry)) + return 0; /* success */ + + err = au_test_empty_lower(dentry); + +out: + if (err == -ENOTEMPTY) { + if (au_ftest_ren(a->auren_flags, DIRREN)) { + err = 0; + } else { + AuWarn1("renaming dir who has child(ren) on multiple " + "branches, is not supported\n"); + err = -EXDEV; + } + } + return err; +} + +/* side effect: sets whlist and h_dentry */ +static int au_ren_may_dir(struct au_ren_args *a) +{ + int err; + unsigned int rdhash; + struct dentry *d; + + d = a->dst_dentry; + SiMustAnyLock(d->d_sb); + + err = 0; + if (au_ftest_ren(a->auren_flags, ISDIR_DST) && a->dst_inode) { + rdhash = au_sbi(d->d_sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); + err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + + if (!a->exchange) { + au_set_dbtop(d, a->dst_btop); + err = may_rename_dstdir(d, &a->whlist); + au_set_dbtop(d, a->btgt); + } else + err = may_rename_srcdir(a); + } + a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); + if (unlikely(err)) + goto out; + + d = a->src_dentry; + a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); + if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { + err = may_rename_srcdir(a); + if (unlikely(err)) { + au_nhash_wh_free(&a->whlist); + a->whlist.nh_num = 0; + } + } +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * simple tests for rename. + * following the checks in vfs, plus the parent-child relationship. + */ +static int au_may_ren(struct au_ren_args *a) +{ + int err, isdir; + struct inode *h_inode; + + if (a->src_btop == a->btgt) { + err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, + au_ftest_ren(a->auren_flags, ISDIR_SRC)); + if (unlikely(err)) + goto out; + err = -EINVAL; + if (unlikely(a->src_h_dentry == a->h_trap)) + goto out; + } + + err = 0; + if (a->dst_btop != a->btgt) + goto out; + + err = -ENOTEMPTY; + if (unlikely(a->dst_h_dentry == a->h_trap)) + goto out; + + err = -EIO; + isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); + if (d_really_is_negative(a->dst_dentry)) { + if (d_is_negative(a->dst_h_dentry)) + err = au_may_add(a->dst_dentry, a->btgt, + a->dst_h_parent, isdir); + } else { + if (unlikely(d_is_negative(a->dst_h_dentry))) + goto out; + h_inode = d_inode(a->dst_h_dentry); + if (h_inode->i_nlink) + err = au_may_del(a->dst_dentry, a->btgt, + a->dst_h_parent, isdir); + } + +out: + if (unlikely(err == -ENOENT || err == -EEXIST)) + err = -EIO; + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * locking order + * (VFS) + * - src_dir and dir by lock_rename() + * - inode if exists + * (aufs) + * - lock all + * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, + * + si_read_lock + * + di_write_lock2_child() + * + di_write_lock_child() + * + ii_write_lock_child() + * + di_write_lock_child2() + * + ii_write_lock_child2() + * + src_parent and parent + * + di_write_lock_parent() + * + ii_write_lock_parent() + * + di_write_lock_parent2() + * + ii_write_lock_parent2() + * + lower src_dir and dir by vfsub_lock_rename() + * + verify the every relationships between child and parent. if any + * of them failed, unlock all and return -EBUSY. + */ +static void au_ren_unlock(struct au_ren_args *a) +{ + vfsub_unlock_rename(a->src_h_parent, a->src_hdir, + a->dst_h_parent, a->dst_hdir); + if (au_ftest_ren(a->auren_flags, DIRREN) + && a->h_root) + au_hn_inode_unlock(a->h_root); + if (au_ftest_ren(a->auren_flags, MNT_WRITE)) + vfsub_mnt_drop_write(au_br_mnt(a->br)); +} + +static int au_ren_lock(struct au_ren_args *a) +{ + int err; + unsigned int udba; + + err = 0; + a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); + a->src_hdir = au_hi(a->src_dir, a->btgt); + a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); + a->dst_hdir = au_hi(a->dst_dir, a->btgt); + + err = vfsub_mnt_want_write(au_br_mnt(a->br)); + if (unlikely(err)) + goto out; + au_fset_ren(a->auren_flags, MNT_WRITE); + if (au_ftest_ren(a->auren_flags, DIRREN)) { + struct dentry *root; + struct inode *dir; + + /* + * sbinfo is already locked, so this ii_read_lock is + * unnecessary. but our debugging feature checks it. + */ + root = a->src_inode->i_sb->s_root; + if (root != a->src_parent && root != a->dst_parent) { + dir = d_inode(root); + ii_read_lock_parent3(dir); + a->h_root = au_hi(dir, a->btgt); + ii_read_unlock(dir); + au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); + } + } + a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, + a->dst_h_parent, a->dst_hdir); + udba = au_opt_udba(a->src_dentry->d_sb); + if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) + || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) + err = au_busy_or_stale(); + if (!err && au_dbtop(a->src_dentry) == a->btgt) + err = au_h_verify(a->src_h_dentry, udba, + d_inode(a->src_h_parent), a->src_h_parent, + a->br); + if (!err && au_dbtop(a->dst_dentry) == a->btgt) + err = au_h_verify(a->dst_h_dentry, udba, + d_inode(a->dst_h_parent), a->dst_h_parent, + a->br); + if (!err) + goto out; /* success */ + + err = au_busy_or_stale(); + au_ren_unlock(a); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void au_ren_refresh_dir(struct au_ren_args *a) +{ + struct inode *dir; + + dir = a->dst_dir; + inode_inc_iversion(dir); + if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { + /* is this updating defined in POSIX? */ + au_cpup_attr_timesizes(a->src_inode); + au_cpup_attr_nlink(dir, /*force*/1); + } + au_dir_ts(dir, a->btgt); + + if (a->exchange) { + dir = a->src_dir; + inode_inc_iversion(dir); + if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { + /* is this updating defined in POSIX? */ + au_cpup_attr_timesizes(a->dst_inode); + au_cpup_attr_nlink(dir, /*force*/1); + } + au_dir_ts(dir, a->btgt); + } + + if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) + return; + + dir = a->src_dir; + inode_inc_iversion(dir); + if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) + au_cpup_attr_nlink(dir, /*force*/1); + au_dir_ts(dir, a->btgt); +} + +static void au_ren_refresh(struct au_ren_args *a) +{ + aufs_bindex_t bbot, bindex; + struct dentry *d, *h_d; + struct inode *i, *h_i; + struct super_block *sb; + + d = a->dst_dentry; + d_drop(d); + if (a->h_dst) + /* already dget-ed by au_ren_or_cpup() */ + au_set_h_dptr(d, a->btgt, a->h_dst); + + i = a->dst_inode; + if (i) { + if (!a->exchange) { + if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) + vfsub_drop_nlink(i); + else { + vfsub_dead_dir(i); + au_cpup_attr_timesizes(i); + } + au_update_dbrange(d, /*do_put_zero*/1); + } else + au_cpup_attr_nlink(i, /*force*/1); + } else { + bbot = a->btgt; + for (bindex = au_dbtop(d); bindex < bbot; bindex++) + au_set_h_dptr(d, bindex, NULL); + bbot = au_dbbot(d); + for (bindex = a->btgt + 1; bindex <= bbot; bindex++) + au_set_h_dptr(d, bindex, NULL); + au_update_dbrange(d, /*do_put_zero*/0); + } + + if (a->exchange + || au_ftest_ren(a->auren_flags, DIRREN)) { + d_drop(a->src_dentry); + if (au_ftest_ren(a->auren_flags, DIRREN)) + au_set_dbwh(a->src_dentry, -1); + return; + } + + d = a->src_dentry; + au_set_dbwh(d, -1); + bbot = au_dbbot(d); + for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { + h_d = au_h_dptr(d, bindex); + if (h_d) + au_set_h_dptr(d, bindex, NULL); + } + au_set_dbbot(d, a->btgt); + + sb = d->d_sb; + i = a->src_inode; + if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) + return; /* success */ + + bbot = au_ibbot(i); + for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { + h_i = au_h_iptr(i, bindex); + if (h_i) { + au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); + /* ignore this error */ + au_set_h_iptr(i, bindex, NULL, 0); + } + } + au_set_ibbot(i, a->btgt); +} + +/* ---------------------------------------------------------------------- */ + +/* mainly for link(2) and rename(2) */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) +{ + aufs_bindex_t bdiropq, bwh; + struct dentry *parent; + struct au_branch *br; + + parent = dentry->d_parent; + IMustLock(d_inode(parent)); /* dir is locked */ + + bdiropq = au_dbdiropq(parent); + bwh = au_dbwh(dentry); + br = au_sbr(dentry->d_sb, btgt); + if (au_br_rdonly(br) + || (0 <= bdiropq && bdiropq < btgt) + || (0 <= bwh && bwh < btgt)) + btgt = -1; + + AuDbg("btgt %d\n", btgt); + return btgt; +} + +/* sets src_btop, dst_btop and btgt */ +static int au_ren_wbr(struct au_ren_args *a) +{ + int err; + struct au_wr_dir_args wr_dir_args = { + /* .force_btgt = -1, */ + .flags = AuWrDir_ADD_ENTRY + }; + + a->src_btop = au_dbtop(a->src_dentry); + a->dst_btop = au_dbtop(a->dst_dentry); + if (au_ftest_ren(a->auren_flags, ISDIR_SRC) + || au_ftest_ren(a->auren_flags, ISDIR_DST)) + au_fset_wrdir(wr_dir_args.flags, ISDIR); + wr_dir_args.force_btgt = a->src_btop; + if (a->dst_inode && a->dst_btop < a->src_btop) + wr_dir_args.force_btgt = a->dst_btop; + wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); + err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); + a->btgt = err; + if (a->exchange) + au_update_dbtop(a->dst_dentry); + + return err; +} + +static void au_ren_dt(struct au_ren_args *a) +{ + a->h_path.dentry = a->src_h_parent; + au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); + if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) { + a->h_path.dentry = a->dst_h_parent; + au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); + } + + au_fclr_ren(a->auren_flags, DT_DSTDIR); + if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) + && !a->exchange) + return; + + a->h_path.dentry = a->src_h_dentry; + au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); + if (d_is_positive(a->dst_h_dentry)) { + au_fset_ren(a->auren_flags, DT_DSTDIR); + a->h_path.dentry = a->dst_h_dentry; + au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); + } +} + +static void au_ren_rev_dt(int err, struct au_ren_args *a) +{ + struct dentry *h_d; + struct inode *h_inode; + + au_dtime_revert(a->src_dt + AuPARENT); + if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) + au_dtime_revert(a->dst_dt + AuPARENT); + + if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { + h_d = a->src_dt[AuCHILD].dt_h_path.dentry; + h_inode = d_inode(h_d); + inode_lock_nested(h_inode, AuLsc_I_CHILD); + au_dtime_revert(a->src_dt + AuCHILD); + inode_unlock(h_inode); + + if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { + h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; + h_inode = d_inode(h_d); + inode_lock_nested(h_inode, AuLsc_I_CHILD); + au_dtime_revert(a->dst_dt + AuCHILD); + inode_unlock(h_inode); + } + } +} + +/* ---------------------------------------------------------------------- */ + +int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, + struct inode *_dst_dir, struct dentry *_dst_dentry, + unsigned int _flags) +{ + int err, lock_flags; + void *rev; + /* reduce stack space */ + struct au_ren_args *a; + struct au_pin pin; + + AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); + IMustLock(_src_dir); + IMustLock(_dst_dir); + + err = -EINVAL; + if (unlikely(_flags & RENAME_WHITEOUT)) + goto out; + + err = -ENOMEM; + BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + a->flags = _flags; + BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) + && RENAME_EXCHANGE > U8_MAX); + a->exchange = _flags & RENAME_EXCHANGE; + a->src_dir = _src_dir; + a->src_dentry = _src_dentry; + a->src_inode = NULL; + if (d_really_is_positive(a->src_dentry)) + a->src_inode = d_inode(a->src_dentry); + a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ + a->dst_dir = _dst_dir; + a->dst_dentry = _dst_dentry; + a->dst_inode = NULL; + if (d_really_is_positive(a->dst_dentry)) + a->dst_inode = d_inode(a->dst_dentry); + a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ + if (a->dst_inode) { + /* + * if EXCHANGE && src is non-dir && dst is dir, + * dst is not locked. + */ + /* IMustLock(a->dst_inode); */ + au_igrab(a->dst_inode); + } + + err = -ENOTDIR; + lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; + if (d_is_dir(a->src_dentry)) { + au_fset_ren(a->auren_flags, ISDIR_SRC); + if (unlikely(!a->exchange + && d_really_is_positive(a->dst_dentry) + && !d_is_dir(a->dst_dentry))) + goto out_free; + lock_flags |= AuLock_DIRS; + } + if (a->dst_inode && d_is_dir(a->dst_dentry)) { + au_fset_ren(a->auren_flags, ISDIR_DST); + if (unlikely(!a->exchange + && d_really_is_positive(a->src_dentry) + && !d_is_dir(a->src_dentry))) + goto out_free; + lock_flags |= AuLock_DIRS; + } + err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, + lock_flags); + if (unlikely(err)) + goto out_free; + + err = au_d_hashed_positive(a->src_dentry); + if (unlikely(err)) + goto out_unlock; + err = -ENOENT; + if (a->dst_inode) { + /* + * If it is a dir, VFS unhash it before this + * function. It means we cannot rely upon d_unhashed(). + */ + if (unlikely(!a->dst_inode->i_nlink)) + goto out_unlock; + if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { + err = au_d_hashed_positive(a->dst_dentry); + if (unlikely(err && !a->exchange)) + goto out_unlock; + } else if (unlikely(IS_DEADDIR(a->dst_inode))) + goto out_unlock; + } else if (unlikely(d_unhashed(a->dst_dentry))) + goto out_unlock; + + /* + * is it possible? + * yes, it happened (in linux-3.3-rcN) but I don't know why. + * there may exist a problem somewhere else. + */ + err = -EINVAL; + if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) + goto out_unlock; + + au_fset_ren(a->auren_flags, ISSAMEDIR); /* temporary */ + di_write_lock_parent(a->dst_parent); + + /* which branch we process */ + err = au_ren_wbr(a); + if (unlikely(err < 0)) + goto out_parent; + a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); + a->h_path.mnt = au_br_mnt(a->br); + + /* are they available to be renamed */ + err = au_ren_may_dir(a); + if (unlikely(err)) + goto out_children; + + /* prepare the writable parent dir on the same branch */ + if (a->dst_btop == a->btgt) { + au_fset_ren(a->auren_flags, WHDST); + } else { + err = au_cpup_dirs(a->dst_dentry, a->btgt); + if (unlikely(err)) + goto out_children; + } + + err = 0; + if (!a->exchange) { + if (a->src_dir != a->dst_dir) { + /* + * this temporary unlock is safe, + * because both dir->i_mutex are locked. + */ + di_write_unlock(a->dst_parent); + di_write_lock_parent(a->src_parent); + err = au_wr_dir_need_wh(a->src_dentry, + au_ftest_ren(a->auren_flags, + ISDIR_SRC), + &a->btgt); + di_write_unlock(a->src_parent); + di_write_lock2_parent(a->src_parent, a->dst_parent, + /*isdir*/1); + au_fclr_ren(a->auren_flags, ISSAMEDIR); + } else + err = au_wr_dir_need_wh(a->src_dentry, + au_ftest_ren(a->auren_flags, + ISDIR_SRC), + &a->btgt); + } + if (unlikely(err < 0)) + goto out_children; + if (err) + au_fset_ren(a->auren_flags, WHSRC); + + /* cpup src */ + if (a->src_btop != a->btgt) { + err = au_pin(&pin, a->src_dentry, a->btgt, + au_opt_udba(a->src_dentry->d_sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (!err) { + struct au_cp_generic cpg = { + .dentry = a->src_dentry, + .bdst = a->btgt, + .bsrc = a->src_btop, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + } + if (unlikely(err)) + goto out_children; + a->src_btop = a->btgt; + a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); + if (!a->exchange) + au_fset_ren(a->auren_flags, WHSRC); + } + + /* cpup dst */ + if (a->exchange && a->dst_inode + && a->dst_btop != a->btgt) { + err = au_pin(&pin, a->dst_dentry, a->btgt, + au_opt_udba(a->dst_dentry->d_sb), + AuPin_DI_LOCKED | AuPin_MNT_WRITE); + if (!err) { + struct au_cp_generic cpg = { + .dentry = a->dst_dentry, + .bdst = a->btgt, + .bsrc = a->dst_btop, + .len = -1, + .pin = &pin, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + err = au_sio_cpup_simple(&cpg); + au_unpin(&pin); + } + if (unlikely(err)) + goto out_children; + a->dst_btop = a->btgt; + a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); + } + + /* lock them all */ + err = au_ren_lock(a); + if (unlikely(err)) + /* leave the copied-up one */ + goto out_children; + + if (!a->exchange) { + if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) + err = au_may_ren(a); + else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) + err = -ENAMETOOLONG; + if (unlikely(err)) + goto out_hdir; + } + + /* store timestamps to be revertible */ + au_ren_dt(a); + + /* store dirren info */ + if (au_ftest_ren(a->auren_flags, DIRREN)) { + err = au_dr_rename(a->src_dentry, a->btgt, + &a->dst_dentry->d_name, &rev); + AuTraceErr(err); + if (unlikely(err)) + goto out_dt; + } + + /* here we go */ + err = do_rename(a); + if (unlikely(err)) + goto out_dirren; + + if (au_ftest_ren(a->auren_flags, DIRREN)) + au_dr_rename_fin(a->src_dentry, a->btgt, rev); + + /* update dir attributes */ + au_ren_refresh_dir(a); + + /* dput/iput all lower dentries */ + au_ren_refresh(a); + + goto out_hdir; /* success */ + +out_dirren: + if (au_ftest_ren(a->auren_flags, DIRREN)) + au_dr_rename_rev(a->src_dentry, a->btgt, rev); +out_dt: + au_ren_rev_dt(err, a); +out_hdir: + au_ren_unlock(a); +out_children: + au_nhash_wh_free(&a->whlist); + if (err && a->dst_inode && a->dst_btop != a->btgt) { + AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); + au_set_h_dptr(a->dst_dentry, a->btgt, NULL); + au_set_dbtop(a->dst_dentry, a->dst_btop); + } +out_parent: + if (!err) { + if (d_unhashed(a->src_dentry)) + au_fset_ren(a->auren_flags, DROPPED_SRC); + if (d_unhashed(a->dst_dentry)) + au_fset_ren(a->auren_flags, DROPPED_DST); + if (!a->exchange) + d_move(a->src_dentry, a->dst_dentry); + else { + d_exchange(a->src_dentry, a->dst_dentry); + if (au_ftest_ren(a->auren_flags, DROPPED_DST)) + d_drop(a->dst_dentry); + } + if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) + d_drop(a->src_dentry); + } else { + au_update_dbtop(a->dst_dentry); + if (!a->dst_inode) + d_drop(a->dst_dentry); + } + if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) + di_write_unlock(a->dst_parent); + else + di_write_unlock2(a->src_parent, a->dst_parent); +out_unlock: + aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); +out_free: + iput(a->dst_inode); + if (a->thargs) + au_whtmp_rmdir_free(a->thargs); + au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c new file mode 100644 index 000000000000..098fd115052a --- /dev/null +++ b/fs/aufs/iinfo.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode private data + */ + +#include "aufs.h" + +struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) +{ + struct inode *h_inode; + struct au_hinode *hinode; + + IiMustAnyLock(inode); + + hinode = au_hinode(au_ii(inode), bindex); + h_inode = hinode->hi_inode; + AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); + return h_inode; +} + +/* todo: hard/soft set? */ +void au_hiput(struct au_hinode *hinode) +{ + au_hn_free(hinode); + dput(hinode->hi_whdentry); + iput(hinode->hi_inode); +} + +unsigned int au_hi_flags(struct inode *inode, int isdir) +{ + unsigned int flags; + const unsigned int mnt_flags = au_mntflags(inode->i_sb); + + flags = 0; + if (au_opt_test(mnt_flags, XINO)) + au_fset_hi(flags, XINO); + if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) + au_fset_hi(flags, HNOTIFY); + return flags; +} + +void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode, unsigned int flags) +{ + struct au_hinode *hinode; + struct inode *hi; + struct au_iinfo *iinfo = au_ii(inode); + + IiMustWriteLock(inode); + + hinode = au_hinode(iinfo, bindex); + hi = hinode->hi_inode; + AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); + + if (hi) + au_hiput(hinode); + hinode->hi_inode = h_inode; + if (h_inode) { + int err; + struct super_block *sb = inode->i_sb; + struct au_branch *br; + + AuDebugOn(inode->i_mode + && (h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT)); + if (bindex == iinfo->ii_btop) + au_cpup_igen(inode, h_inode); + br = au_sbr(sb, bindex); + hinode->hi_id = br->br_id; + if (au_ftest_hi(flags, XINO)) { + err = au_xino_write(sb, bindex, h_inode->i_ino, + inode->i_ino); + if (unlikely(err)) + AuIOErr1("failed au_xino_write() %d\n", err); + } + + if (au_ftest_hi(flags, HNOTIFY) + && au_br_hnotifyable(br->br_perm)) { + err = au_hn_alloc(hinode, inode); + if (unlikely(err)) + AuIOErr1("au_hn_alloc() %d\n", err); + } + } +} + +void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_wh) +{ + struct au_hinode *hinode; + + IiMustWriteLock(inode); + + hinode = au_hinode(au_ii(inode), bindex); + AuDebugOn(hinode->hi_whdentry); + hinode->hi_whdentry = h_wh; +} + +void au_update_iigen(struct inode *inode, int half) +{ + struct au_iinfo *iinfo; + struct au_iigen *iigen; + unsigned int sigen; + + sigen = au_sigen(inode->i_sb); + iinfo = au_ii(inode); + iigen = &iinfo->ii_generation; + spin_lock(&iigen->ig_spin); + iigen->ig_generation = sigen; + if (half) + au_ig_fset(iigen->ig_flags, HALF_REFRESHED); + else + au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); + spin_unlock(&iigen->ig_spin); +} + +/* it may be called at remount time, too */ +void au_update_ibrange(struct inode *inode, int do_put_zero) +{ + struct au_iinfo *iinfo; + aufs_bindex_t bindex, bbot; + + AuDebugOn(au_is_bad_inode(inode)); + IiMustWriteLock(inode); + + iinfo = au_ii(inode); + if (do_put_zero && iinfo->ii_btop >= 0) { + for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; + bindex++) { + struct inode *h_i; + + h_i = au_hinode(iinfo, bindex)->hi_inode; + if (h_i + && !h_i->i_nlink + && !(h_i->i_state & I_LINKABLE)) + au_set_h_iptr(inode, bindex, NULL, 0); + } + } + + iinfo->ii_btop = -1; + iinfo->ii_bbot = -1; + bbot = au_sbbot(inode->i_sb); + for (bindex = 0; bindex <= bbot; bindex++) + if (au_hinode(iinfo, bindex)->hi_inode) { + iinfo->ii_btop = bindex; + break; + } + if (iinfo->ii_btop >= 0) + for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) + if (au_hinode(iinfo, bindex)->hi_inode) { + iinfo->ii_bbot = bindex; + break; + } + AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); +} + +/* ---------------------------------------------------------------------- */ + +void au_icntnr_init_once(void *_c) +{ + struct au_icntnr *c = _c; + struct au_iinfo *iinfo = &c->iinfo; + + spin_lock_init(&iinfo->ii_generation.ig_spin); + au_rw_init(&iinfo->ii_rwsem); + inode_init_once(&c->vfs_inode); +} + +void au_hinode_init(struct au_hinode *hinode) +{ + hinode->hi_inode = NULL; + hinode->hi_id = -1; + au_hn_init(hinode); + hinode->hi_whdentry = NULL; +} + +int au_iinfo_init(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct super_block *sb; + struct au_hinode *hi; + int nbr, i; + + sb = inode->i_sb; + iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); + nbr = au_sbbot(sb) + 1; + if (unlikely(nbr <= 0)) + nbr = 1; + hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); + if (hi) { + au_lcnt_inc(&au_sbi(sb)->si_ninodes); + + iinfo->ii_hinode = hi; + for (i = 0; i < nbr; i++, hi++) + au_hinode_init(hi); + + iinfo->ii_generation.ig_generation = au_sigen(sb); + iinfo->ii_btop = -1; + iinfo->ii_bbot = -1; + iinfo->ii_vdir = NULL; + return 0; + } + return -ENOMEM; +} + +int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) +{ + int err, i; + struct au_hinode *hip; + + AuRwMustWriteLock(&iinfo->ii_rwsem); + + err = -ENOMEM; + hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, + may_shrink); + if (hip) { + iinfo->ii_hinode = hip; + i = iinfo->ii_bbot + 1; + hip += i; + for (; i < nbr; i++, hip++) + au_hinode_init(hip); + err = 0; + } + + return err; +} + +void au_iinfo_fin(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct au_hinode *hi; + struct super_block *sb; + aufs_bindex_t bindex, bbot; + const unsigned char unlinked = !inode->i_nlink; + + AuDebugOn(au_is_bad_inode(inode)); + + sb = inode->i_sb; + au_lcnt_dec(&au_sbi(sb)->si_ninodes); + if (si_pid_test(sb)) + au_xino_delete_inode(inode, unlinked); + else { + /* + * it is safe to hide the dependency between sbinfo and + * sb->s_umount. + */ + lockdep_off(); + si_noflush_read_lock(sb); + au_xino_delete_inode(inode, unlinked); + si_read_unlock(sb); + lockdep_on(); + } + + iinfo = au_ii(inode); + if (iinfo->ii_vdir) + au_vdir_free(iinfo->ii_vdir); + + bindex = iinfo->ii_btop; + if (bindex >= 0) { + hi = au_hinode(iinfo, bindex); + bbot = iinfo->ii_bbot; + while (bindex++ <= bbot) { + if (hi->hi_inode) + au_hiput(hi); + hi++; + } + } + au_kfree_rcu(iinfo->ii_hinode); + AuRwDestroy(&iinfo->ii_rwsem); +} diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c new file mode 100644 index 000000000000..8d53cd08b8fb --- /dev/null +++ b/fs/aufs/inode.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode functions + */ + +#include +#include "aufs.h" + +struct inode *au_igrab(struct inode *inode) +{ + if (inode) { + AuDebugOn(!atomic_read(&inode->i_count)); + ihold(inode); + } + return inode; +} + +static void au_refresh_hinode_attr(struct inode *inode, int do_version) +{ + au_cpup_attr_all(inode, /*force*/0); + au_update_iigen(inode, /*half*/1); + if (do_version) + inode_inc_iversion(inode); +} + +static int au_ii_refresh(struct inode *inode, int *update) +{ + int err, e, nbr; + umode_t type; + aufs_bindex_t bindex, new_bindex; + struct super_block *sb; + struct au_iinfo *iinfo; + struct au_hinode *p, *q, tmp; + + AuDebugOn(au_is_bad_inode(inode)); + IiMustWriteLock(inode); + + *update = 0; + sb = inode->i_sb; + nbr = au_sbbot(sb) + 1; + type = inode->i_mode & S_IFMT; + iinfo = au_ii(inode); + err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); + if (unlikely(err)) + goto out; + + AuDebugOn(iinfo->ii_btop < 0); + p = au_hinode(iinfo, iinfo->ii_btop); + for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; + bindex++, p++) { + if (!p->hi_inode) + continue; + + AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); + new_bindex = au_br_index(sb, p->hi_id); + if (new_bindex == bindex) + continue; + + if (new_bindex < 0) { + *update = 1; + au_hiput(p); + p->hi_inode = NULL; + continue; + } + + if (new_bindex < iinfo->ii_btop) + iinfo->ii_btop = new_bindex; + if (iinfo->ii_bbot < new_bindex) + iinfo->ii_bbot = new_bindex; + /* swap two lower inode, and loop again */ + q = au_hinode(iinfo, new_bindex); + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hi_inode) { + bindex--; + p--; + } + } + au_update_ibrange(inode, /*do_put_zero*/0); + au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ + e = au_dy_irefresh(inode); + if (unlikely(e && !err)) + err = e; + +out: + AuTraceErr(err); + return err; +} + +void au_refresh_iop(struct inode *inode, int force_getattr) +{ + int type; + struct au_sbinfo *sbi = au_sbi(inode->i_sb); + const struct inode_operations *iop + = force_getattr ? aufs_iop : sbi->si_iop_array; + + if (inode->i_op == iop) + return; + + switch (inode->i_mode & S_IFMT) { + case S_IFDIR: + type = AuIop_DIR; + break; + case S_IFLNK: + type = AuIop_SYMLINK; + break; + default: + type = AuIop_OTHER; + break; + } + + inode->i_op = iop + type; + /* unnecessary smp_wmb() */ +} + +int au_refresh_hinode_self(struct inode *inode) +{ + int err, update; + + err = au_ii_refresh(inode, &update); + if (!err) + au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); + + AuTraceErr(err); + return err; +} + +int au_refresh_hinode(struct inode *inode, struct dentry *dentry) +{ + int err, e, update; + unsigned int flags; + umode_t mode; + aufs_bindex_t bindex, bbot; + unsigned char isdir; + struct au_hinode *p; + struct au_iinfo *iinfo; + + err = au_ii_refresh(inode, &update); + if (unlikely(err)) + goto out; + + update = 0; + iinfo = au_ii(inode); + p = au_hinode(iinfo, iinfo->ii_btop); + mode = (inode->i_mode & S_IFMT); + isdir = S_ISDIR(mode); + flags = au_hi_flags(inode, isdir); + bbot = au_dbbot(dentry); + for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { + struct inode *h_i, *h_inode; + struct dentry *h_d; + + h_d = au_h_dptr(dentry, bindex); + if (!h_d || d_is_negative(h_d)) + continue; + + h_inode = d_inode(h_d); + AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); + if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { + h_i = au_h_iptr(inode, bindex); + if (h_i) { + if (h_i == h_inode) + continue; + err = -EIO; + break; + } + } + if (bindex < iinfo->ii_btop) + iinfo->ii_btop = bindex; + if (iinfo->ii_bbot < bindex) + iinfo->ii_bbot = bindex; + au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); + update = 1; + } + au_update_ibrange(inode, /*do_put_zero*/0); + e = au_dy_irefresh(inode); + if (unlikely(e && !err)) + err = e; + if (!err) + au_refresh_hinode_attr(inode, update && isdir); + +out: + AuTraceErr(err); + return err; +} + +static int set_inode(struct inode *inode, struct dentry *dentry) +{ + int err; + unsigned int flags; + umode_t mode; + aufs_bindex_t bindex, btop, btail; + unsigned char isdir; + struct dentry *h_dentry; + struct inode *h_inode; + struct au_iinfo *iinfo; + const struct inode_operations *iop; + + IiMustWriteLock(inode); + + err = 0; + isdir = 0; + iop = au_sbi(inode->i_sb)->si_iop_array; + btop = au_dbtop(dentry); + h_dentry = au_h_dptr(dentry, btop); + h_inode = d_inode(h_dentry); + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: + btail = au_dbtail(dentry); + inode->i_op = iop + AuIop_OTHER; + inode->i_fop = &aufs_file_fop; + err = au_dy_iaop(inode, btop, h_inode); + if (unlikely(err)) + goto out; + break; + case S_IFDIR: + isdir = 1; + btail = au_dbtaildir(dentry); + inode->i_op = iop + AuIop_DIR; + inode->i_fop = &aufs_dir_fop; + break; + case S_IFLNK: + btail = au_dbtail(dentry); + inode->i_op = iop + AuIop_SYMLINK; + break; + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + case S_IFSOCK: + btail = au_dbtail(dentry); + inode->i_op = iop + AuIop_OTHER; + init_special_inode(inode, mode, h_inode->i_rdev); + break; + default: + AuIOErr("Unknown file type 0%o\n", mode); + err = -EIO; + goto out; + } + + /* do not set hnotify for whiteouted dirs (SHWH mode) */ + flags = au_hi_flags(inode, isdir); + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) + && au_ftest_hi(flags, HNOTIFY) + && dentry->d_name.len > AUFS_WH_PFX_LEN + && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) + au_fclr_hi(flags, HNOTIFY); + iinfo = au_ii(inode); + iinfo->ii_btop = btop; + iinfo->ii_bbot = btail; + for (bindex = btop; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry) + au_set_h_iptr(inode, bindex, + au_igrab(d_inode(h_dentry)), flags); + } + au_cpup_attr_all(inode, /*force*/1); + /* + * to force calling aufs_get_acl() every time, + * do not call cache_no_acl() for aufs inode. + */ + +out: + return err; +} + +/* + * successful returns with iinfo write_locked + * minus: errno + * zero: success, matched + * plus: no error, but unmatched + */ +static int reval_inode(struct inode *inode, struct dentry *dentry) +{ + int err; + unsigned int gen, igflags; + aufs_bindex_t bindex, bbot; + struct inode *h_inode, *h_dinode; + struct dentry *h_dentry; + + /* + * before this function, if aufs got any iinfo lock, it must be only + * one, the parent dir. + * it can happen by UDBA and the obsoleted inode number. + */ + err = -EIO; + if (unlikely(inode->i_ino == parent_ino(dentry))) + goto out; + + err = 1; + ii_write_lock_new_child(inode); + h_dentry = au_h_dptr(dentry, au_dbtop(dentry)); + h_dinode = d_inode(h_dentry); + bbot = au_ibbot(inode); + for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (!h_inode || h_inode != h_dinode) + continue; + + err = 0; + gen = au_iigen(inode, &igflags); + if (gen == au_digen(dentry) + && !au_ig_ftest(igflags, HALF_REFRESHED)) + break; + + /* fully refresh inode using dentry */ + err = au_refresh_hinode(inode, dentry); + if (!err) + au_update_iigen(inode, /*half*/0); + break; + } + + if (unlikely(err)) + ii_write_unlock(inode); +out: + return err; +} + +int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + unsigned int d_type, ino_t *ino) +{ + int err, idx; + const int isnondir = d_type != DT_DIR; + + /* prevent hardlinked inode number from race condition */ + if (isnondir) { + err = au_xinondir_enter(sb, bindex, h_ino, &idx); + if (unlikely(err)) + goto out; + } + + err = au_xino_read(sb, bindex, h_ino, ino); + if (unlikely(err)) + goto out_xinondir; + + if (!*ino) { + err = -EIO; + *ino = au_xino_new_ino(sb); + if (unlikely(!*ino)) + goto out_xinondir; + err = au_xino_write(sb, bindex, h_ino, *ino); + if (unlikely(err)) + goto out_xinondir; + } + +out_xinondir: + if (isnondir && idx >= 0) + au_xinondir_leave(sb, bindex, h_ino, idx); +out: + return err; +} + +/* successful returns with iinfo write_locked */ +/* todo: return with unlocked? */ +struct inode *au_new_inode(struct dentry *dentry, int must_new) +{ + struct inode *inode, *h_inode; + struct dentry *h_dentry; + struct super_block *sb; + ino_t h_ino, ino; + int err, idx, hlinked; + aufs_bindex_t btop; + + sb = dentry->d_sb; + btop = au_dbtop(dentry); + h_dentry = au_h_dptr(dentry, btop); + h_inode = d_inode(h_dentry); + h_ino = h_inode->i_ino; + hlinked = !d_is_dir(h_dentry) && h_inode->i_nlink > 1; + +new_ino: + /* + * stop 'race'-ing between hardlinks under different + * parents. + */ + if (hlinked) { + err = au_xinondir_enter(sb, btop, h_ino, &idx); + inode = ERR_PTR(err); + if (unlikely(err)) + goto out; + } + + err = au_xino_read(sb, btop, h_ino, &ino); + inode = ERR_PTR(err); + if (unlikely(err)) + goto out_xinondir; + + if (!ino) { + ino = au_xino_new_ino(sb); + if (unlikely(!ino)) { + inode = ERR_PTR(-EIO); + goto out_xinondir; + } + } + + AuDbg("i%lu\n", (unsigned long)ino); + inode = au_iget_locked(sb, ino); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_xinondir; + + AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); + if (inode->i_state & I_NEW) { + ii_write_lock_new_child(inode); + err = set_inode(inode, dentry); + if (!err) { + unlock_new_inode(inode); + goto out_xinondir; /* success */ + } + + /* + * iget_failed() calls iput(), but we need to call + * ii_write_unlock() after iget_failed(). so dirty hack for + * i_count. + */ + atomic_inc(&inode->i_count); + iget_failed(inode); + ii_write_unlock(inode); + au_xino_write(sb, btop, h_ino, /*ino*/0); + /* ignore this error */ + goto out_iput; + } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { + /* + * horrible race condition between lookup, readdir and copyup + * (or something). + */ + if (hlinked && idx >= 0) + au_xinondir_leave(sb, btop, h_ino, idx); + err = reval_inode(inode, dentry); + if (unlikely(err < 0)) { + hlinked = 0; + goto out_iput; + } + if (!err) + goto out; /* success */ + else if (hlinked && idx >= 0) { + err = au_xinondir_enter(sb, btop, h_ino, &idx); + if (unlikely(err)) { + iput(inode); + inode = ERR_PTR(err); + goto out; + } + } + } + + if (unlikely(au_test_fs_unique_ino(h_inode))) + AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," + " b%d, %s, %pd, hi%lu, i%lu.\n", + btop, au_sbtype(h_dentry->d_sb), dentry, + (unsigned long)h_ino, (unsigned long)ino); + ino = 0; + err = au_xino_write(sb, btop, h_ino, /*ino*/0); + if (!err) { + iput(inode); + if (hlinked && idx >= 0) + au_xinondir_leave(sb, btop, h_ino, idx); + goto new_ino; + } + +out_iput: + iput(inode); + inode = ERR_PTR(err); +out_xinondir: + if (hlinked && idx >= 0) + au_xinondir_leave(sb, btop, h_ino, idx); +out: + return inode; +} + +/* ---------------------------------------------------------------------- */ + +int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode) +{ + int err; + struct inode *hi; + + err = au_br_rdonly(au_sbr(sb, bindex)); + + /* pseudo-link after flushed may happen out of bounds */ + if (!err + && inode + && au_ibtop(inode) <= bindex + && bindex <= au_ibbot(inode)) { + /* + * permission check is unnecessary since vfsub routine + * will be called later + */ + hi = au_h_iptr(inode, bindex); + if (hi) + err = IS_IMMUTABLE(hi) ? -EROFS : 0; + } + + return err; +} + +int au_test_h_perm(struct inode *h_inode, int mask) +{ + if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) + return 0; + return inode_permission(h_inode, mask); +} + +int au_test_h_perm_sio(struct inode *h_inode, int mask) +{ + if (au_test_nfs(h_inode->i_sb) + && (mask & MAY_WRITE) + && S_ISDIR(h_inode->i_mode)) + mask |= MAY_READ; /* force permission check */ + return au_test_h_perm(h_inode, mask); +} diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h new file mode 100644 index 000000000000..2fc7674d4369 --- /dev/null +++ b/fs/aufs/inode.h @@ -0,0 +1,698 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * inode operations + */ + +#ifndef __AUFS_INODE_H__ +#define __AUFS_INODE_H__ + +#ifdef __KERNEL__ + +#include +#include "rwsem.h" + +struct vfsmount; + +struct au_hnotify { +#ifdef CONFIG_AUFS_HNOTIFY +#ifdef CONFIG_AUFS_HFSNOTIFY + /* never use fsnotify_add_vfsmount_mark() */ + struct fsnotify_mark hn_mark; +#endif + struct inode *hn_aufs_inode; /* no get/put */ + struct rcu_head rcu; +#endif +} ____cacheline_aligned_in_smp; + +struct au_hinode { + struct inode *hi_inode; + aufs_bindex_t hi_id; +#ifdef CONFIG_AUFS_HNOTIFY + struct au_hnotify *hi_notify; +#endif + + /* reference to the copied-up whiteout with get/put */ + struct dentry *hi_whdentry; +}; + +/* ig_flags */ +#define AuIG_HALF_REFRESHED 1 +#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) +#define au_ig_fset(flags, name) \ + do { (flags) |= AuIG_##name; } while (0) +#define au_ig_fclr(flags, name) \ + do { (flags) &= ~AuIG_##name; } while (0) + +struct au_iigen { + spinlock_t ig_spin; + __u32 ig_generation, ig_flags; +}; + +struct au_vdir; +struct au_iinfo { + struct au_iigen ii_generation; + struct super_block *ii_hsb1; /* no get/put */ + + struct au_rwsem ii_rwsem; + aufs_bindex_t ii_btop, ii_bbot; + __u32 ii_higen; + struct au_hinode *ii_hinode; + struct au_vdir *ii_vdir; +}; + +struct au_icntnr { + struct au_iinfo iinfo; + struct inode vfs_inode; + struct hlist_bl_node plink; + struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* au_pin flags */ +#define AuPin_DI_LOCKED 1 +#define AuPin_MNT_WRITE (1 << 1) +#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) +#define au_fset_pin(flags, name) \ + do { (flags) |= AuPin_##name; } while (0) +#define au_fclr_pin(flags, name) \ + do { (flags) &= ~AuPin_##name; } while (0) + +struct au_pin { + /* input */ + struct dentry *dentry; + unsigned int udba; + unsigned char lsc_di, lsc_hi, flags; + aufs_bindex_t bindex; + + /* output */ + struct dentry *parent; + struct au_hinode *hdir; + struct vfsmount *h_mnt; + + /* temporary unlock/relock for copyup */ + struct dentry *h_dentry, *h_parent; + struct au_branch *br; + struct task_struct *task; +}; + +void au_pin_hdir_unlock(struct au_pin *p); +int au_pin_hdir_lock(struct au_pin *p); +int au_pin_hdir_relock(struct au_pin *p); +void au_pin_hdir_acquire_nest(struct au_pin *p); +void au_pin_hdir_release(struct au_pin *p); + +/* ---------------------------------------------------------------------- */ + +static inline struct au_iinfo *au_ii(struct inode *inode) +{ + BUG_ON(is_bad_inode(inode)); + return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); +} + +/* ---------------------------------------------------------------------- */ + +/* inode.c */ +struct inode *au_igrab(struct inode *inode); +void au_refresh_iop(struct inode *inode, int force_getattr); +int au_refresh_hinode_self(struct inode *inode); +int au_refresh_hinode(struct inode *inode, struct dentry *dentry); +int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + unsigned int d_type, ino_t *ino); +struct inode *au_new_inode(struct dentry *dentry, int must_new); +int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode); +int au_test_h_perm(struct inode *h_inode, int mask); +int au_test_h_perm_sio(struct inode *h_inode, int mask); + +static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, + ino_t h_ino, unsigned int d_type, ino_t *ino) +{ +#ifdef CONFIG_AUFS_SHWH + return au_ino(sb, bindex, h_ino, d_type, ino); +#else + return 0; +#endif +} + +/* i_op.c */ +enum { + AuIop_SYMLINK, + AuIop_DIR, + AuIop_OTHER, + AuIop_Last +}; +extern struct inode_operations aufs_iop[AuIop_Last], /* not const */ + aufs_iop_nogetattr[AuIop_Last]; + +/* au_wr_dir flags */ +#define AuWrDir_ADD_ENTRY 1 +#define AuWrDir_ISDIR (1 << 1) +#define AuWrDir_TMPFILE (1 << 2) +#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) +#define au_fset_wrdir(flags, name) \ + do { (flags) |= AuWrDir_##name; } while (0) +#define au_fclr_wrdir(flags, name) \ + do { (flags) &= ~AuWrDir_##name; } while (0) + +struct au_wr_dir_args { + aufs_bindex_t force_btgt; + unsigned char flags; +}; +int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, + struct au_wr_dir_args *args); + +struct dentry *au_pinned_h_parent(struct au_pin *pin); +void au_pin_init(struct au_pin *pin, struct dentry *dentry, + aufs_bindex_t bindex, int lsc_di, int lsc_hi, + unsigned int udba, unsigned char flags); +int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, + unsigned int udba, unsigned char flags) __must_check; +int au_do_pin(struct au_pin *pin) __must_check; +void au_unpin(struct au_pin *pin); +int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); + +#define AuIcpup_DID_CPUP 1 +#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) +#define au_fset_icpup(flags, name) \ + do { (flags) |= AuIcpup_##name; } while (0) +#define au_fclr_icpup(flags, name) \ + do { (flags) &= ~AuIcpup_##name; } while (0) + +struct au_icpup_args { + unsigned char flags; + unsigned char pin_flags; + aufs_bindex_t btgt; + unsigned int udba; + struct au_pin pin; + struct path h_path; + struct inode *h_inode; +}; + +int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, + struct au_icpup_args *a); + +int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, + struct path *h_path, int locked); + +/* i_op_add.c */ +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir); +int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t dev); +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); +int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool want_excl); +struct vfsub_aopen_args; +int au_aopen_or_create(struct inode *dir, struct dentry *dentry, + struct vfsub_aopen_args *args); +int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode); +int aufs_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry); +int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); + +/* i_op_del.c */ +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); +int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir); +int aufs_unlink(struct inode *dir, struct dentry *dentry); +int aufs_rmdir(struct inode *dir, struct dentry *dentry); + +/* i_op_ren.c */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); +int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry, + unsigned int flags); + +/* iinfo.c */ +struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); +void au_hiput(struct au_hinode *hinode); +void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_wh); +unsigned int au_hi_flags(struct inode *inode, int isdir); + +/* hinode flags */ +#define AuHi_XINO 1 +#define AuHi_HNOTIFY (1 << 1) +#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) +#define au_fset_hi(flags, name) \ + do { (flags) |= AuHi_##name; } while (0) +#define au_fclr_hi(flags, name) \ + do { (flags) &= ~AuHi_##name; } while (0) + +#ifndef CONFIG_AUFS_HNOTIFY +#undef AuHi_HNOTIFY +#define AuHi_HNOTIFY 0 +#endif + +void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode, unsigned int flags); + +void au_update_iigen(struct inode *inode, int half); +void au_update_ibrange(struct inode *inode, int do_put_zero); + +void au_icntnr_init_once(void *_c); +void au_hinode_init(struct au_hinode *hinode); +int au_iinfo_init(struct inode *inode); +void au_iinfo_fin(struct inode *inode); +int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink); + +#ifdef CONFIG_PROC_FS +/* plink.c */ +int au_plink_maint(struct super_block *sb, int flags); +struct au_sbinfo; +void au_plink_maint_leave(struct au_sbinfo *sbinfo); +int au_plink_maint_enter(struct super_block *sb); +#ifdef CONFIG_AUFS_DEBUG +void au_plink_list(struct super_block *sb); +#else +AuStubVoid(au_plink_list, struct super_block *sb) +#endif +int au_plink_test(struct inode *inode); +struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); +void au_plink_append(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_dentry); +void au_plink_put(struct super_block *sb, int verbose); +void au_plink_clean(struct super_block *sb, int verbose); +void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); +#else +AuStubInt0(au_plink_maint, struct super_block *sb, int flags); +AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); +AuStubInt0(au_plink_maint_enter, struct super_block *sb); +AuStubVoid(au_plink_list, struct super_block *sb); +AuStubInt0(au_plink_test, struct inode *inode); +AuStub(struct dentry *, au_plink_lkup, return NULL, + struct inode *inode, aufs_bindex_t bindex); +AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_dentry); +AuStubVoid(au_plink_put, struct super_block *sb, int verbose); +AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); +AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); +#endif /* CONFIG_PROC_FS */ + +#ifdef CONFIG_AUFS_XATTR +/* xattr.c */ +int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, + unsigned int verbose); +ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); +void au_xattr_init(struct super_block *sb); +#else +AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src, + int ignore_flags, unsigned int verbose); +AuStubVoid(au_xattr_init, struct super_block *sb); +#endif + +#ifdef CONFIG_FS_POSIX_ACL +struct posix_acl *aufs_get_acl(struct inode *inode, int type); +int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type); +#endif + +#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) +enum { + AU_XATTR_SET, + AU_ACL_SET +}; + +struct au_sxattr { + int type; + union { + struct { + const char *name; + const void *value; + size_t size; + int flags; + } set; + struct { + struct posix_acl *acl; + int type; + } acl_set; + } u; +}; +ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, + struct au_sxattr *arg); +#endif + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for iinfo */ +enum { + AuLsc_II_CHILD, /* child first */ + AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ + AuLsc_II_CHILD3, /* copyup dirs */ + AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ + AuLsc_II_PARENT2, + AuLsc_II_PARENT3, /* copyup dirs */ + AuLsc_II_NEW_CHILD +}; + +/* + * ii_read_lock_child, ii_write_lock_child, + * ii_read_lock_child2, ii_write_lock_child2, + * ii_read_lock_child3, ii_write_lock_child3, + * ii_read_lock_parent, ii_write_lock_parent, + * ii_read_lock_parent2, ii_write_lock_parent2, + * ii_read_lock_parent3, ii_write_lock_parent3, + * ii_read_lock_new_child, ii_write_lock_new_child, + */ +#define AuReadLockFunc(name, lsc) \ +static inline void ii_read_lock_##name(struct inode *i) \ +{ \ + au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ +} + +#define AuWriteLockFunc(name, lsc) \ +static inline void ii_write_lock_##name(struct inode *i) \ +{ \ + au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ +} + +#define AuRWLockFuncs(name, lsc) \ + AuReadLockFunc(name, lsc) \ + AuWriteLockFunc(name, lsc) + +AuRWLockFuncs(child, CHILD); +AuRWLockFuncs(child2, CHILD2); +AuRWLockFuncs(child3, CHILD3); +AuRWLockFuncs(parent, PARENT); +AuRWLockFuncs(parent2, PARENT2); +AuRWLockFuncs(parent3, PARENT3); +AuRWLockFuncs(new_child, NEW_CHILD); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +#define ii_read_unlock(i) au_rw_read_unlock(&au_ii(i)->ii_rwsem) +#define ii_write_unlock(i) au_rw_write_unlock(&au_ii(i)->ii_rwsem) +#define ii_downgrade_lock(i) au_rw_dgrade_lock(&au_ii(i)->ii_rwsem) + +#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) +#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) +#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) + +/* ---------------------------------------------------------------------- */ + +static inline void au_icntnr_init(struct au_icntnr *c) +{ +#ifdef CONFIG_AUFS_DEBUG + c->vfs_inode.i_mode = 0; +#endif +} + +static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) +{ + unsigned int gen; + struct au_iinfo *iinfo; + struct au_iigen *iigen; + + iinfo = au_ii(inode); + iigen = &iinfo->ii_generation; + spin_lock(&iigen->ig_spin); + if (igflags) + *igflags = iigen->ig_flags; + gen = iigen->ig_generation; + spin_unlock(&iigen->ig_spin); + + return gen; +} + +/* tiny test for inode number */ +/* tmpfs generation is too rough */ +static inline int au_test_higen(struct inode *inode, struct inode *h_inode) +{ + struct au_iinfo *iinfo; + + iinfo = au_ii(inode); + AuRwMustAnyLock(&iinfo->ii_rwsem); + return !(iinfo->ii_hsb1 == h_inode->i_sb + && iinfo->ii_higen == h_inode->i_generation); +} + +static inline void au_iigen_dec(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct au_iigen *iigen; + + iinfo = au_ii(inode); + iigen = &iinfo->ii_generation; + spin_lock(&iigen->ig_spin); + iigen->ig_generation--; + spin_unlock(&iigen->ig_spin); +} + +static inline int au_iigen_test(struct inode *inode, unsigned int sigen) +{ + int err; + + err = 0; + if (unlikely(inode && au_iigen(inode, NULL) != sigen)) + err = -EIO; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static inline struct au_hinode *au_hinode(struct au_iinfo *iinfo, + aufs_bindex_t bindex) +{ + return iinfo->ii_hinode + bindex; +} + +static inline int au_is_bad_inode(struct inode *inode) +{ + return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); +} + +static inline aufs_bindex_t au_ii_br_id(struct inode *inode, + aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + return au_hinode(au_ii(inode), bindex)->hi_id; +} + +static inline aufs_bindex_t au_ibtop(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_btop; +} + +static inline aufs_bindex_t au_ibbot(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_bbot; +} + +static inline struct au_vdir *au_ivdir(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_vdir; +} + +static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + return au_hinode(au_ii(inode), bindex)->hi_whdentry; +} + +static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustWriteLock(inode); + au_ii(inode)->ii_btop = bindex; +} + +static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustWriteLock(inode); + au_ii(inode)->ii_bbot = bindex; +} + +static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) +{ + IiMustWriteLock(inode); + au_ii(inode)->ii_vdir = vdir; +} + +static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + return au_hinode(au_ii(inode), bindex); +} + +/* ---------------------------------------------------------------------- */ + +static inline struct dentry *au_pinned_parent(struct au_pin *pin) +{ + if (pin) + return pin->parent; + return NULL; +} + +static inline struct inode *au_pinned_h_dir(struct au_pin *pin) +{ + if (pin && pin->hdir) + return pin->hdir->hi_inode; + return NULL; +} + +static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) +{ + if (pin) + return pin->hdir; + return NULL; +} + +static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) +{ + if (pin) + pin->dentry = dentry; +} + +static inline void au_pin_set_parent_lflag(struct au_pin *pin, + unsigned char lflag) +{ + if (pin) { + if (lflag) + au_fset_pin(pin->flags, DI_LOCKED); + else + au_fclr_pin(pin->flags, DI_LOCKED); + } +} + +#if 0 /* reserved */ +static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) +{ + if (pin) { + dput(pin->parent); + pin->parent = dget(parent); + } +} +#endif + +/* ---------------------------------------------------------------------- */ + +struct au_branch; +#ifdef CONFIG_AUFS_HNOTIFY +struct au_hnotify_op { + void (*ctl)(struct au_hinode *hinode, int do_set); + int (*alloc)(struct au_hinode *hinode); + + /* + * if it returns true, the caller should free hinode->hi_notify, + * otherwise ->free() frees it. + */ + int (*free)(struct au_hinode *hinode, + struct au_hnotify *hn) __must_check; + + void (*fin)(void); + int (*init)(void); + + int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); + void (*fin_br)(struct au_branch *br); + int (*init_br)(struct au_branch *br, int perm); +}; + +/* hnotify.c */ +int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); +void au_hn_free(struct au_hinode *hinode); +void au_hn_ctl(struct au_hinode *hinode, int do_set); +void au_hn_reset(struct inode *inode, unsigned int flags); +int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, + const struct qstr *h_child_qstr, struct inode *h_child_inode); +int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); +int au_hnotify_init_br(struct au_branch *br, int perm); +void au_hnotify_fin_br(struct au_branch *br); +int __init au_hnotify_init(void); +void au_hnotify_fin(void); + +/* hfsnotify.c */ +extern const struct au_hnotify_op au_hnotify_op; + +static inline +void au_hn_init(struct au_hinode *hinode) +{ + hinode->hi_notify = NULL; +} + +static inline struct au_hnotify *au_hn(struct au_hinode *hinode) +{ + return hinode->hi_notify; +} + +#else +AuStub(int, au_hn_alloc, return -EOPNOTSUPP, + struct au_hinode *hinode __maybe_unused, + struct inode *inode __maybe_unused) +AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) +AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) +AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, + int do_set __maybe_unused) +AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, + unsigned int flags __maybe_unused) +AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, + struct au_branch *br __maybe_unused, + int perm __maybe_unused) +AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, + int perm __maybe_unused) +AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) +AuStubInt0(__init au_hnotify_init, void) +AuStubVoid(au_hnotify_fin, void) +AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) +#endif /* CONFIG_AUFS_HNOTIFY */ + +static inline void au_hn_suspend(struct au_hinode *hdir) +{ + au_hn_ctl(hdir, /*do_set*/0); +} + +static inline void au_hn_resume(struct au_hinode *hdir) +{ + au_hn_ctl(hdir, /*do_set*/1); +} + +static inline void au_hn_inode_lock(struct au_hinode *hdir) +{ + inode_lock(hdir->hi_inode); + au_hn_suspend(hdir); +} + +static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, + unsigned int sc __maybe_unused) +{ + inode_lock_nested(hdir->hi_inode, sc); + au_hn_suspend(hdir); +} + +#if 0 /* unused */ +#include "vfsub.h" +static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, + unsigned int sc) +{ + inode_lock_shared_nested(hdir->hi_inode, sc); + au_hn_suspend(hdir); +} +#endif + +static inline void au_hn_inode_unlock(struct au_hinode *hdir) +{ + au_hn_resume(hdir); + inode_unlock(hdir->hi_inode); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_INODE_H__ */ diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c new file mode 100644 index 000000000000..fb2fb758283e --- /dev/null +++ b/fs/aufs/ioctl.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * ioctl + * plink-management and readdir in userspace. + * assist the pathconf(3) wrapper library. + * move-down + * File-based Hierarchical Storage Management. + */ + +#include +#include +#include "aufs.h" + +static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) +{ + int err, fd; + aufs_bindex_t wbi, bindex, bbot; + struct file *h_file; + struct super_block *sb; + struct dentry *root; + struct au_branch *br; + struct aufs_wbr_fd wbrfd = { + .oflags = au_dir_roflags, + .brid = -1 + }; + const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY + | O_NOATIME | O_CLOEXEC; + + AuDebugOn(wbrfd.oflags & ~valid); + + if (arg) { + err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); + if (unlikely(err)) { + err = -EFAULT; + goto out; + } + + err = -EINVAL; + AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); + wbrfd.oflags |= au_dir_roflags; + AuDbg("0%o\n", wbrfd.oflags); + if (unlikely(wbrfd.oflags & ~valid)) + goto out; + } + + fd = get_unused_fd_flags(0); + err = fd; + if (unlikely(fd < 0)) + goto out; + + h_file = ERR_PTR(-EINVAL); + wbi = 0; + br = NULL; + sb = path->dentry->d_sb; + root = sb->s_root; + aufs_read_lock(root, AuLock_IR); + bbot = au_sbbot(sb); + if (wbrfd.brid >= 0) { + wbi = au_br_index(sb, wbrfd.brid); + if (unlikely(wbi < 0 || wbi > bbot)) + goto out_unlock; + } + + h_file = ERR_PTR(-ENOENT); + br = au_sbr(sb, wbi); + if (!au_br_writable(br->br_perm)) { + if (arg) + goto out_unlock; + + bindex = wbi + 1; + wbi = -1; + for (; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_writable(br->br_perm)) { + wbi = bindex; + br = au_sbr(sb, wbi); + break; + } + } + } + AuDbg("wbi %d\n", wbi); + if (wbi >= 0) + h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, + /*force_wr*/0); + +out_unlock: + aufs_read_unlock(root, AuLock_IR); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out_fd; + + au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */ + fd_install(fd, h_file); + err = fd; + goto out; /* success */ + +out_fd: + put_unused_fd(fd); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err; + struct dentry *dentry; + + switch (cmd) { + case AUFS_CTL_RDU: + case AUFS_CTL_RDU_INO: + err = au_rdu_ioctl(file, cmd, arg); + break; + + case AUFS_CTL_WBR_FD: + err = au_wbr_fd(&file->f_path, (void __user *)arg); + break; + + case AUFS_CTL_IBUSY: + err = au_ibusy_ioctl(file, arg); + break; + + case AUFS_CTL_BRINFO: + err = au_brinfo_ioctl(file, arg); + break; + + case AUFS_CTL_FHSM_FD: + dentry = file->f_path.dentry; + if (IS_ROOT(dentry)) + err = au_fhsm_fd(dentry->d_sb, arg); + else + err = -ENOTTY; + break; + + default: + /* do not call the lower */ + AuDbg("0x%x\n", cmd); + err = -ENOTTY; + } + + AuTraceErr(err); + return err; +} + +long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err; + + switch (cmd) { + case AUFS_CTL_MVDOWN: + err = au_mvdown(file->f_path.dentry, (void __user *)arg); + break; + + case AUFS_CTL_WBR_FD: + err = au_wbr_fd(&file->f_path, (void __user *)arg); + break; + + default: + /* do not call the lower */ + AuDbg("0x%x\n", cmd); + err = -ENOTTY; + } + + AuTraceErr(err); + return err; +} + +#ifdef CONFIG_COMPAT +long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long err; + + switch (cmd) { + case AUFS_CTL_RDU: + case AUFS_CTL_RDU_INO: + err = au_rdu_compat_ioctl(file, cmd, arg); + break; + + case AUFS_CTL_IBUSY: + err = au_ibusy_compat_ioctl(file, arg); + break; + + case AUFS_CTL_BRINFO: + err = au_brinfo_compat_ioctl(file, arg); + break; + + default: + err = aufs_ioctl_dir(file, cmd, arg); + } + + AuTraceErr(err); + return err; +} + +long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif diff --git a/fs/aufs/lcnt.h b/fs/aufs/lcnt.h new file mode 100644 index 000000000000..d8508f875f28 --- /dev/null +++ b/fs/aufs/lcnt.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * simple long counter wrapper + */ + +#ifndef __AUFS_LCNT_H__ +#define __AUFS_LCNT_H__ + +#ifdef __KERNEL__ + +#include "debug.h" + +#define AuLCntATOMIC 1 +#define AuLCntPCPUCNT 2 +/* + * why does percpu_refcount require extra synchronize_rcu()s in + * au_br_do_free() + */ +#define AuLCntPCPUREF 3 + +/* #define AuLCntChosen AuLCntATOMIC */ +#define AuLCntChosen AuLCntPCPUCNT +/* #define AuLCntChosen AuLCntPCPUREF */ + +#if AuLCntChosen == AuLCntATOMIC +#include + +typedef atomic_long_t au_lcnt_t; + +static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) +{ + atomic_long_set(cnt, 0); + return 0; +} + +static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) +{ + /* empty */ +} + +static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused, + int do_sync __maybe_unused) +{ + /* empty */ +} + +static inline void au_lcnt_inc(au_lcnt_t *cnt) +{ + atomic_long_inc(cnt); +} + +static inline void au_lcnt_dec(au_lcnt_t *cnt) +{ + atomic_long_dec(cnt); +} + +static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) +{ + return atomic_long_read(cnt); +} +#endif + +#if AuLCntChosen == AuLCntPCPUCNT +#include + +typedef struct percpu_counter au_lcnt_t; + +static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) +{ + return percpu_counter_init(cnt, 0, GFP_NOFS); +} + +static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) +{ + /* empty */ +} + +static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused) +{ + percpu_counter_destroy(cnt); +} + +static inline void au_lcnt_inc(au_lcnt_t *cnt) +{ + percpu_counter_inc(cnt); +} + +static inline void au_lcnt_dec(au_lcnt_t *cnt) +{ + percpu_counter_dec(cnt); +} + +static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) +{ + s64 n; + + n = percpu_counter_sum(cnt); + BUG_ON(n < 0); + if (LONG_MAX != LLONG_MAX + && n > LONG_MAX) + AuWarn1("%s\n", "wrap-around"); + + return n; +} +#endif + +#if AuLCntChosen == AuLCntPCPUREF +#include + +typedef struct percpu_ref au_lcnt_t; + +static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release) +{ + if (!release) + release = percpu_ref_exit; + return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS); +} + +static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) +{ + synchronize_rcu(); +} + +static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync) +{ + percpu_ref_kill(cnt); + if (do_sync) + au_lcnt_wait_for_fin(cnt); +} + +static inline void au_lcnt_inc(au_lcnt_t *cnt) +{ + percpu_ref_get(cnt); +} + +static inline void au_lcnt_dec(au_lcnt_t *cnt) +{ + percpu_ref_put(cnt); +} + +/* + * avoid calling this func as possible. + */ +static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev) +{ + long l; + + percpu_ref_switch_to_atomic_sync(cnt); + l = atomic_long_read(&cnt->count); + if (do_rev) + percpu_ref_switch_to_percpu(cnt); + + /* percpu_ref is initialized by 1 instead of 0 */ + return l - 1; +} +#endif + +#ifdef CONFIG_AUFS_DEBUG +#define AuLCntZero(val) do { \ + long l = val; \ + if (l) \ + AuDbg("%s = %ld\n", #val, l); \ +} while (0) +#else +#define AuLCntZero(val) do {} while (0) +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_LCNT_H__ */ diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c new file mode 100644 index 000000000000..bfcb9f994c2d --- /dev/null +++ b/fs/aufs/loop.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * support for loopback block device as a branch + */ + +#include "aufs.h" + +/* added into drivers/block/loop.c */ +static struct file *(*backing_file_func)(struct super_block *sb); + +/* + * test if two lower dentries have overlapping branches. + */ +int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) +{ + struct super_block *h_sb; + struct file *backing_file; + + if (unlikely(!backing_file_func)) { + /* don't load "loop" module here */ + backing_file_func = symbol_get(loop_backing_file); + if (unlikely(!backing_file_func)) + /* "loop" module is not loaded */ + return 0; + } + + h_sb = h_adding->d_sb; + backing_file = backing_file_func(h_sb); + if (!backing_file) + return 0; + + h_adding = backing_file->f_path.dentry; + /* + * h_adding can be local NFS. + * in this case aufs cannot detect the loop. + */ + if (unlikely(h_adding->d_sb == sb)) + return 1; + return !!au_test_subdir(h_adding, sb->s_root); +} + +/* true if a kernel thread named 'loop[0-9].*' accesses a file */ +int au_test_loopback_kthread(void) +{ + int ret; + struct task_struct *tsk = current; + char c, comm[sizeof(tsk->comm)]; + + ret = 0; + if (tsk->flags & PF_KTHREAD) { + get_task_comm(comm, tsk); + c = comm[4]; + ret = ('0' <= c && c <= '9' + && !strncmp(comm, "loop", 4)); + } + + return ret; +} + +/* ---------------------------------------------------------------------- */ + +#define au_warn_loopback_step 16 +static int au_warn_loopback_nelem = au_warn_loopback_step; +static unsigned long *au_warn_loopback_array; + +void au_warn_loopback(struct super_block *h_sb) +{ + int i, new_nelem; + unsigned long *a, magic; + static DEFINE_SPINLOCK(spin); + + magic = h_sb->s_magic; + spin_lock(&spin); + a = au_warn_loopback_array; + for (i = 0; i < au_warn_loopback_nelem && *a; i++) + if (a[i] == magic) { + spin_unlock(&spin); + return; + } + + /* h_sb is new to us, print it */ + if (i < au_warn_loopback_nelem) { + a[i] = magic; + goto pr; + } + + /* expand the array */ + new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; + a = au_kzrealloc(au_warn_loopback_array, + au_warn_loopback_nelem * sizeof(unsigned long), + new_nelem * sizeof(unsigned long), GFP_ATOMIC, + /*may_shrink*/0); + if (a) { + au_warn_loopback_nelem = new_nelem; + au_warn_loopback_array = a; + a[i] = magic; + goto pr; + } + + spin_unlock(&spin); + AuWarn1("realloc failed, ignored\n"); + return; + +pr: + spin_unlock(&spin); + pr_warn("you may want to try another patch for loopback file " + "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); +} + +int au_loopback_init(void) +{ + int err; + struct super_block *sb __maybe_unused; + + BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); + + err = 0; + au_warn_loopback_array = kcalloc(au_warn_loopback_step, + sizeof(unsigned long), GFP_NOFS); + if (unlikely(!au_warn_loopback_array)) + err = -ENOMEM; + + return err; +} + +void au_loopback_fin(void) +{ + if (backing_file_func) + symbol_put(loop_backing_file); + au_kfree_try_rcu(au_warn_loopback_array); +} diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h new file mode 100644 index 000000000000..7fc394e72d75 --- /dev/null +++ b/fs/aufs/loop.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * support for loopback mount as a branch + */ + +#ifndef __AUFS_LOOP_H__ +#define __AUFS_LOOP_H__ + +#ifdef __KERNEL__ + +struct dentry; +struct super_block; + +#ifdef CONFIG_AUFS_BDEV_LOOP +/* drivers/block/loop.c */ +struct file *loop_backing_file(struct super_block *sb); + +/* loop.c */ +int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); +int au_test_loopback_kthread(void); +void au_warn_loopback(struct super_block *h_sb); + +int au_loopback_init(void); +void au_loopback_fin(void); +#else +AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) + +AuStubInt0(au_test_loopback_overlap, struct super_block *sb, + struct dentry *h_adding) +AuStubInt0(au_test_loopback_kthread, void) +AuStubVoid(au_warn_loopback, struct super_block *h_sb) + +AuStubInt0(au_loopback_init, void) +AuStubVoid(au_loopback_fin, void) +#endif /* BLK_DEV_LOOP */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_LOOP_H__ */ diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk new file mode 100644 index 000000000000..7bc9eef3ffec --- /dev/null +++ b/fs/aufs/magic.mk @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0 + +# defined in ${srctree}/fs/fuse/inode.c +# tristate +ifdef CONFIG_FUSE_FS +ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 +endif + +# defined in ${srctree}/fs/xfs/xfs_sb.h +# tristate +ifdef CONFIG_XFS_FS +ccflags-y += -DXFS_SB_MAGIC=0x58465342 +endif + +# defined in ${srctree}/fs/configfs/mount.c +# tristate +ifdef CONFIG_CONFIGFS_FS +ccflags-y += -DCONFIGFS_MAGIC=0x62656570 +endif + +# defined in ${srctree}/fs/ubifs/ubifs.h +# tristate +ifdef CONFIG_UBIFS_FS +ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 +endif + +# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h +# tristate +ifdef CONFIG_HFSPLUS_FS +ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b +endif diff --git a/fs/aufs/module.c b/fs/aufs/module.c new file mode 100644 index 000000000000..295736adfc3c --- /dev/null +++ b/fs/aufs/module.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * module global variables and operations + */ + +#include +#include +#include "aufs.h" + +/* shrinkable realloc */ +void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) +{ + size_t sz; + int diff; + + sz = 0; + diff = -1; + if (p) { +#if 0 /* unused */ + if (!new_sz) { + au_kfree_rcu(p); + p = NULL; + goto out; + } +#else + AuDebugOn(!new_sz); +#endif + sz = ksize(p); + diff = au_kmidx_sub(sz, new_sz); + } + if (sz && !diff) + goto out; + + if (sz < new_sz) + /* expand or SLOB */ + p = krealloc(p, new_sz, gfp); + else if (new_sz < sz && may_shrink) { + /* shrink */ + void *q; + + q = kmalloc(new_sz, gfp); + if (q) { + if (p) { + memcpy(q, p, new_sz); + au_kfree_try_rcu(p); + } + p = q; + } else + p = NULL; + } + +out: + return p; +} + +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, + int may_shrink) +{ + p = au_krealloc(p, new_sz, gfp, may_shrink); + if (p && new_sz > nused) + memset(p + nused, 0, new_sz - nused); + return p; +} + +/* ---------------------------------------------------------------------- */ +/* + * aufs caches + */ +struct kmem_cache *au_cache[AuCache_Last]; + +static void au_cache_fin(void) +{ + int i; + + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); + + /* excluding AuCache_HNOTIFY */ + BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); + for (i = 0; i < AuCache_HNOTIFY; i++) { + kmem_cache_destroy(au_cache[i]); + au_cache[i] = NULL; + } +} + +static int __init au_cache_init(void) +{ + au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); + if (au_cache[AuCache_DINFO]) + /* SLAB_DESTROY_BY_RCU */ + au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, + au_icntnr_init_once); + if (au_cache[AuCache_ICNTNR]) + au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, + au_fi_init_once); + if (au_cache[AuCache_FINFO]) + au_cache[AuCache_VDIR] = AuCache(au_vdir); + if (au_cache[AuCache_VDIR]) + au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); + if (au_cache[AuCache_DEHSTR]) + return 0; + + au_cache_fin(); + return -ENOMEM; +} + +/* ---------------------------------------------------------------------- */ + +int au_dir_roflags; + +#ifdef CONFIG_AUFS_SBILIST +/* + * iterate_supers_type() doesn't protect us from + * remounting (branch management) + */ +struct hlist_bl_head au_sbilist; +#endif + +/* + * functions for module interface. + */ +MODULE_LICENSE("GPL"); +/* MODULE_LICENSE("GPL v2"); */ +MODULE_AUTHOR("Junjiro R. Okajima "); +MODULE_DESCRIPTION(AUFS_NAME + " -- Advanced multi layered unification filesystem"); +MODULE_VERSION(AUFS_VERSION); +MODULE_ALIAS_FS(AUFS_NAME); + +/* this module parameter has no meaning when SYSFS is disabled */ +int sysaufs_brs = 1; +MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); +module_param_named(brs, sysaufs_brs, int, 0444); + +/* this module parameter has no meaning when USER_NS is disabled */ +bool au_userns; +MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); +module_param_named(allow_userns, au_userns, bool, 0444); + +/* ---------------------------------------------------------------------- */ + +static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ + +int au_seq_path(struct seq_file *seq, struct path *path) +{ + int err; + + err = seq_path(seq, path, au_esc_chars); + if (err >= 0) + err = 0; + else + err = -ENOMEM; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int __init aufs_init(void) +{ + int err, i; + char *p; + + p = au_esc_chars; + for (i = 1; i <= ' '; i++) + *p++ = i; + *p++ = '\\'; + *p++ = '\x7f'; + *p = 0; + + au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); + + memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); + for (i = 0; i < AuIop_Last; i++) + aufs_iop_nogetattr[i].getattr = NULL; + + memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ + + au_sbilist_init(); + sysaufs_brs_init(); + au_debug_init(); + au_dy_init(); + err = sysaufs_init(); + if (unlikely(err)) + goto out; + err = dbgaufs_init(); + if (unlikely(err)) + goto out_sysaufs; + err = au_procfs_init(); + if (unlikely(err)) + goto out_dbgaufs; + err = au_wkq_init(); + if (unlikely(err)) + goto out_procfs; + err = au_loopback_init(); + if (unlikely(err)) + goto out_wkq; + err = au_hnotify_init(); + if (unlikely(err)) + goto out_loopback; + err = au_sysrq_init(); + if (unlikely(err)) + goto out_hin; + err = au_cache_init(); + if (unlikely(err)) + goto out_sysrq; + + aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; + err = register_filesystem(&aufs_fs_type); + if (unlikely(err)) + goto out_cache; + + /* since we define pr_fmt, call printk directly */ + printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); + goto out; /* success */ + +out_cache: + au_cache_fin(); +out_sysrq: + au_sysrq_fin(); +out_hin: + au_hnotify_fin(); +out_loopback: + au_loopback_fin(); +out_wkq: + au_wkq_fin(); +out_procfs: + au_procfs_fin(); +out_dbgaufs: + dbgaufs_fin(); +out_sysaufs: + sysaufs_fin(); + au_dy_fin(); +out: + return err; +} + +static void __exit aufs_exit(void) +{ + unregister_filesystem(&aufs_fs_type); + au_cache_fin(); + au_sysrq_fin(); + au_hnotify_fin(); + au_loopback_fin(); + au_wkq_fin(); + au_procfs_fin(); + dbgaufs_fin(); + sysaufs_fin(); + au_dy_fin(); +} + +module_init(aufs_init); +module_exit(aufs_exit); diff --git a/fs/aufs/module.h b/fs/aufs/module.h new file mode 100644 index 000000000000..3036754b90d0 --- /dev/null +++ b/fs/aufs/module.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * module initialization and module-global + */ + +#ifndef __AUFS_MODULE_H__ +#define __AUFS_MODULE_H__ + +#ifdef __KERNEL__ + +#include +#include "debug.h" +#include "dentry.h" +#include "dir.h" +#include "file.h" +#include "inode.h" + +struct path; +struct seq_file; + +/* module parameters */ +extern int sysaufs_brs; +extern bool au_userns; + +/* ---------------------------------------------------------------------- */ + +extern int au_dir_roflags; + +void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, + int may_shrink); + +/* + * Comparing the size of the object with sizeof(struct rcu_head) + * case 1: object is always larger + * --> au_kfree_rcu() or au_kfree_do_rcu() + * case 2: object is always smaller + * --> au_kfree_small() + * case 3: object can be any size + * --> au_kfree_try_rcu() + */ + +static inline void au_kfree_do_rcu(const void *p) +{ + struct { + struct rcu_head rcu; + } *a = (void *)p; + + kfree_rcu(a, rcu); +} + +#define au_kfree_rcu(_p) do { \ + typeof(_p) p = (_p); \ + BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ + if (p) \ + au_kfree_do_rcu(p); \ + } while (0) + +#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) +#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) + +static inline void au_kfree_try_rcu(const void *p) +{ + if (!p) + return; + if (au_kfree_sz_test(p)) + au_kfree_do_rcu(p); + else + kfree(p); +} + +static inline void au_kfree_small(const void *p) +{ + if (!p) + return; + AuDebugOn(au_kfree_sz_test(p)); + kfree(p); +} + +static inline int au_kmidx_sub(size_t sz, size_t new_sz) +{ +#ifndef CONFIG_SLOB + return kmalloc_index(sz) - kmalloc_index(new_sz); +#else + return -1; /* SLOB is untested */ +#endif +} + +int au_seq_path(struct seq_file *seq, struct path *path); + +#ifdef CONFIG_PROC_FS +/* procfs.c */ +int __init au_procfs_init(void); +void au_procfs_fin(void); +#else +AuStubInt0(au_procfs_init, void); +AuStubVoid(au_procfs_fin, void); +#endif + +/* ---------------------------------------------------------------------- */ + +/* kmem cache */ +enum { + AuCache_DINFO, + AuCache_ICNTNR, + AuCache_FINFO, + AuCache_VDIR, + AuCache_DEHSTR, + AuCache_HNOTIFY, /* must be last */ + AuCache_Last +}; + +extern struct kmem_cache *au_cache[AuCache_Last]; + +#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) +#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) +#define AuCacheCtor(type, ctor) \ + kmem_cache_create(#type, sizeof(struct type), \ + __alignof__(struct type), AuCacheFlags, ctor) + +#define AuCacheFuncs(name, index) \ + static inline struct au_##name *au_cache_alloc_##name(void) \ + { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ + static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ + { kmem_cache_free(au_cache[AuCache_##index], p); } \ + \ + static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ + { void *p = rcu; \ + p -= offsetof(struct au_##name, rcu); \ + kmem_cache_free(au_cache[AuCache_##index], p); } \ + static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ + { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ + call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ + \ + static inline void au_cache_free_##name(struct au_##name *p) \ + { /* au_cache_free_##name##_norcu(p); */ \ + au_cache_free_##name##_rcu(p); } + +AuCacheFuncs(dinfo, DINFO); +AuCacheFuncs(icntnr, ICNTNR); +AuCacheFuncs(finfo, FINFO); +AuCacheFuncs(vdir, VDIR); +AuCacheFuncs(vdir_dehstr, DEHSTR); +#ifdef CONFIG_AUFS_HNOTIFY +AuCacheFuncs(hnotify, HNOTIFY); +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_MODULE_H__ */ diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c new file mode 100644 index 000000000000..cbac849ead31 --- /dev/null +++ b/fs/aufs/mvdown.c @@ -0,0 +1,706 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2011-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * move-down, opposite of copy-up + */ + +#include "aufs.h" + +struct au_mvd_args { + struct { + struct super_block *h_sb; + struct dentry *h_parent; + struct au_hinode *hdir; + struct inode *h_dir, *h_inode; + struct au_pin pin; + } info[AUFS_MVDOWN_NARRAY]; + + struct aufs_mvdown mvdown; + struct dentry *dentry, *parent; + struct inode *inode, *dir; + struct super_block *sb; + aufs_bindex_t bopq, bwh, bfound; + unsigned char rename_lock; +}; + +#define mvd_errno mvdown.au_errno +#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex +#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid +#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex +#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid + +#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb +#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent +#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir +#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir +#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode +#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin + +#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb +#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent +#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir +#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir +#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode +#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin + +#define AU_MVD_PR(flag, ...) do { \ + if (flag) \ + pr_err(__VA_ARGS__); \ + } while (0) + +static int find_lower_writable(struct au_mvd_args *a) +{ + struct super_block *sb; + aufs_bindex_t bindex, bbot; + struct au_branch *br; + + sb = a->sb; + bindex = a->mvd_bsrc; + bbot = au_sbbot(sb); + if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) + for (bindex++; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_fhsm(br->br_perm) + && !sb_rdonly(au_br_sb(br))) + return bindex; + } + else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) + for (bindex++; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (!au_br_rdonly(br)) + return bindex; + } + else + for (bindex++; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (!sb_rdonly(au_br_sb(br))) { + if (au_br_rdonly(br)) + a->mvdown.flags + |= AUFS_MVDOWN_ROLOWER_R; + return bindex; + } + } + + return -1; +} + +/* make the parent dir on bdst */ +static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + + err = 0; + a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); + a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); + a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); + a->mvd_h_dst_parent = NULL; + if (au_dbbot(a->parent) >= a->mvd_bdst) + a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); + if (!a->mvd_h_dst_parent) { + err = au_cpdown_dirs(a->dentry, a->mvd_bdst); + if (unlikely(err)) { + AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); + goto out; + } + a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); + } + +out: + AuTraceErr(err); + return err; +} + +/* lock them all */ +static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct dentry *h_trap; + + a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); + a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); + err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, + au_opt_udba(a->sb), + AuPin_MNT_WRITE | AuPin_DI_LOCKED); + AuTraceErr(err); + if (unlikely(err)) { + AU_MVD_PR(dmsg, "pin_dst failed\n"); + goto out; + } + + if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { + a->rename_lock = 0; + au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, + AuLsc_DI_PARENT, AuLsc_I_PARENT3, + au_opt_udba(a->sb), + AuPin_MNT_WRITE | AuPin_DI_LOCKED); + err = au_do_pin(&a->mvd_pin_src); + AuTraceErr(err); + a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); + if (unlikely(err)) { + AU_MVD_PR(dmsg, "pin_src failed\n"); + goto out_dst; + } + goto out; /* success */ + } + + a->rename_lock = 1; + au_pin_hdir_unlock(&a->mvd_pin_dst); + err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, + au_opt_udba(a->sb), + AuPin_MNT_WRITE | AuPin_DI_LOCKED); + AuTraceErr(err); + a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); + if (unlikely(err)) { + AU_MVD_PR(dmsg, "pin_src failed\n"); + au_pin_hdir_lock(&a->mvd_pin_dst); + goto out_dst; + } + au_pin_hdir_unlock(&a->mvd_pin_src); + h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, + a->mvd_h_dst_parent, a->mvd_hdir_dst); + if (h_trap) { + err = (h_trap != a->mvd_h_src_parent); + if (err) + err = (h_trap != a->mvd_h_dst_parent); + } + BUG_ON(err); /* it should never happen */ + if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { + err = -EBUSY; + AuTraceErr(err); + vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, + a->mvd_h_dst_parent, a->mvd_hdir_dst); + au_pin_hdir_lock(&a->mvd_pin_src); + au_unpin(&a->mvd_pin_src); + au_pin_hdir_lock(&a->mvd_pin_dst); + goto out_dst; + } + goto out; /* success */ + +out_dst: + au_unpin(&a->mvd_pin_dst); +out: + AuTraceErr(err); + return err; +} + +static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) +{ + if (!a->rename_lock) + au_unpin(&a->mvd_pin_src); + else { + vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, + a->mvd_h_dst_parent, a->mvd_hdir_dst); + au_pin_hdir_lock(&a->mvd_pin_src); + au_unpin(&a->mvd_pin_src); + au_pin_hdir_lock(&a->mvd_pin_dst); + } + au_unpin(&a->mvd_pin_dst); +} + +/* copy-down the file */ +static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct au_cp_generic cpg = { + .dentry = a->dentry, + .bdst = a->mvd_bdst, + .bsrc = a->mvd_bsrc, + .len = -1, + .pin = &a->mvd_pin_dst, + .flags = AuCpup_DTIME | AuCpup_HOPEN + }; + + AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); + if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) + au_fset_cpup(cpg.flags, OVERWRITE); + if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) + au_fset_cpup(cpg.flags, RWDST); + err = au_sio_cpdown_simple(&cpg); + if (unlikely(err)) + AU_MVD_PR(dmsg, "cpdown failed\n"); + + AuTraceErr(err); + return err; +} + +/* + * unlink the whiteout on bdst if exist which may be created by UDBA while we + * were sleeping + */ +static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct path h_path; + struct au_branch *br; + struct inode *delegated; + + br = au_sbr(a->sb, a->mvd_bdst); + h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) { + AU_MVD_PR(dmsg, "wh_lkup failed\n"); + goto out; + } + + err = 0; + if (d_is_positive(h_path.dentry)) { + h_path.mnt = au_br_mnt(br); + delegated = NULL; + err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, + &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) + AU_MVD_PR(dmsg, "wh_unlink failed\n"); + } + dput(h_path.dentry); + +out: + AuTraceErr(err); + return err; +} + +/* + * unlink the topmost h_dentry + */ +static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct path h_path; + struct inode *delegated; + + h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); + h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); + delegated = NULL; + err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) + AU_MVD_PR(dmsg, "unlink failed\n"); + + AuTraceErr(err); + return err; +} + +/* Since mvdown succeeded, we ignore an error of this function */ +static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct au_branch *br; + + a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; + br = au_sbr(a->sb, a->mvd_bsrc); + err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); + if (!err) { + br = au_sbr(a->sb, a->mvd_bdst); + a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; + err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); + } + if (!err) + a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; + else + AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); +} + +/* + * copy-down the file and unlink the bsrc file. + * - unlink the bdst whout if exist + * - copy-down the file (with whtmp name and rename) + * - unlink the bsrc file + */ +static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + + err = au_do_mkdir(dmsg, a); + if (!err) + err = au_do_lock(dmsg, a); + if (unlikely(err)) + goto out; + + /* + * do not revert the activities we made on bdst since they should be + * harmless in aufs. + */ + + err = au_do_cpdown(dmsg, a); + if (!err) + err = au_do_unlink_wh(dmsg, a); + if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) + err = au_do_unlink(dmsg, a); + if (unlikely(err)) + goto out_unlock; + + AuDbg("%pd2, 0x%x, %d --> %d\n", + a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); + if (find_lower_writable(a) < 0) + a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; + + if (a->mvdown.flags & AUFS_MVDOWN_STFS) + au_do_stfs(dmsg, a); + + /* maintain internal array */ + if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { + au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); + au_set_dbtop(a->dentry, a->mvd_bdst); + au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); + au_set_ibtop(a->inode, a->mvd_bdst); + } else { + /* hide the lower */ + au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); + au_set_dbbot(a->dentry, a->mvd_bsrc); + au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); + au_set_ibbot(a->inode, a->mvd_bsrc); + } + if (au_dbbot(a->dentry) < a->mvd_bdst) + au_set_dbbot(a->dentry, a->mvd_bdst); + if (au_ibbot(a->inode) < a->mvd_bdst) + au_set_ibbot(a->inode, a->mvd_bdst); + +out_unlock: + au_do_unlock(dmsg, a); +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* make sure the file is idle */ +static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err, plinked; + + err = 0; + plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); + if (au_dbtop(a->dentry) == a->mvd_bsrc + && au_dcount(a->dentry) == 1 + && atomic_read(&a->inode->i_count) == 1 + /* && a->mvd_h_src_inode->i_nlink == 1 */ + && (!plinked || !au_plink_test(a->inode)) + && a->inode->i_nlink == 1) + goto out; + + err = -EBUSY; + AU_MVD_PR(dmsg, + "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", + a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), + atomic_read(&a->inode->i_count), a->inode->i_nlink, + a->mvd_h_src_inode->i_nlink, + plinked, plinked ? au_plink_test(a->inode) : 0); + +out: + AuTraceErr(err); + return err; +} + +/* make sure the parent dir is fine */ +static int au_mvd_args_parent(const unsigned char dmsg, + struct au_mvd_args *a) +{ + int err; + aufs_bindex_t bindex; + + err = 0; + if (unlikely(au_alive_dir(a->parent))) { + err = -ENOENT; + AU_MVD_PR(dmsg, "parent dir is dead\n"); + goto out; + } + + a->bopq = au_dbdiropq(a->parent); + bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); + AuDbg("b%d\n", bindex); + if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) + || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { + err = -EINVAL; + a->mvd_errno = EAU_MVDOWN_OPAQUE; + AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", + a->bopq, a->mvd_bdst); + } + +out: + AuTraceErr(err); + return err; +} + +static int au_mvd_args_intermediate(const unsigned char dmsg, + struct au_mvd_args *a) +{ + int err; + struct au_dinfo *dinfo, *tmp; + + /* lookup the next lower positive entry */ + err = -ENOMEM; + tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); + if (unlikely(!tmp)) + goto out; + + a->bfound = -1; + a->bwh = -1; + dinfo = au_di(a->dentry); + au_di_cp(tmp, dinfo); + au_di_swap(tmp, dinfo); + + /* returns the number of positive dentries */ + err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, + /* AuLkup_IGNORE_PERM */ 0); + if (!err) + a->bwh = au_dbwh(a->dentry); + else if (err > 0) + a->bfound = au_dbtop(a->dentry); + + au_di_swap(tmp, dinfo); + au_rw_write_unlock(&tmp->di_rwsem); + au_di_free(tmp); + if (unlikely(err < 0)) + AU_MVD_PR(dmsg, "failed look-up lower\n"); + + /* + * here, we have these cases. + * bfound == -1 + * no positive dentry under bsrc. there are more sub-cases. + * bwh < 0 + * there no whiteout, we can safely move-down. + * bwh <= bsrc + * impossible + * bsrc < bwh && bwh < bdst + * there is a whiteout on RO branch. cannot proceed. + * bwh == bdst + * there is a whiteout on the RW target branch. it should + * be removed. + * bdst < bwh + * there is a whiteout somewhere unrelated branch. + * -1 < bfound && bfound <= bsrc + * impossible. + * bfound < bdst + * found, but it is on RO branch between bsrc and bdst. cannot + * proceed. + * bfound == bdst + * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return + * error. + * bdst < bfound + * found, after we create the file on bdst, it will be hidden. + */ + + AuDebugOn(a->bfound == -1 + && a->bwh != -1 + && a->bwh <= a->mvd_bsrc); + AuDebugOn(-1 < a->bfound + && a->bfound <= a->mvd_bsrc); + + err = -EINVAL; + if (a->bfound == -1 + && a->mvd_bsrc < a->bwh + && a->bwh != -1 + && a->bwh < a->mvd_bdst) { + a->mvd_errno = EAU_MVDOWN_WHITEOUT; + AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", + a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); + goto out; + } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { + a->mvd_errno = EAU_MVDOWN_UPPER; + AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", + a->mvd_bdst, a->bfound); + goto out; + } + + err = 0; /* success */ + +out: + AuTraceErr(err); + return err; +} + +static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + + err = 0; + if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) + && a->bfound == a->mvd_bdst) + err = -EEXIST; + AuTraceErr(err); + return err; +} + +static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) +{ + int err; + struct au_branch *br; + + err = -EISDIR; + if (unlikely(S_ISDIR(a->inode->i_mode))) + goto out; + + err = -EINVAL; + if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) + a->mvd_bsrc = au_ibtop(a->inode); + else { + a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); + if (unlikely(a->mvd_bsrc < 0 + || (a->mvd_bsrc < au_dbtop(a->dentry) + || au_dbbot(a->dentry) < a->mvd_bsrc + || !au_h_dptr(a->dentry, a->mvd_bsrc)) + || (a->mvd_bsrc < au_ibtop(a->inode) + || au_ibbot(a->inode) < a->mvd_bsrc + || !au_h_iptr(a->inode, a->mvd_bsrc)))) { + a->mvd_errno = EAU_MVDOWN_NOUPPER; + AU_MVD_PR(dmsg, "no upper\n"); + goto out; + } + } + if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { + a->mvd_errno = EAU_MVDOWN_BOTTOM; + AU_MVD_PR(dmsg, "on the bottom\n"); + goto out; + } + a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); + br = au_sbr(a->sb, a->mvd_bsrc); + err = au_br_rdonly(br); + if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { + if (unlikely(err)) + goto out; + } else if (!(vfsub_native_ro(a->mvd_h_src_inode) + || IS_APPEND(a->mvd_h_src_inode))) { + if (err) + a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; + /* go on */ + } else + goto out; + + err = -EINVAL; + if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { + a->mvd_bdst = find_lower_writable(a); + if (unlikely(a->mvd_bdst < 0)) { + a->mvd_errno = EAU_MVDOWN_BOTTOM; + AU_MVD_PR(dmsg, "no writable lower branch\n"); + goto out; + } + } else { + a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); + if (unlikely(a->mvd_bdst < 0 + || au_sbbot(a->sb) < a->mvd_bdst)) { + a->mvd_errno = EAU_MVDOWN_NOLOWERBR; + AU_MVD_PR(dmsg, "no lower brid\n"); + goto out; + } + } + + err = au_mvd_args_busy(dmsg, a); + if (!err) + err = au_mvd_args_parent(dmsg, a); + if (!err) + err = au_mvd_args_intermediate(dmsg, a); + if (!err) + err = au_mvd_args_exist(dmsg, a); + if (!err) + AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); + +out: + AuTraceErr(err); + return err; +} + +int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) +{ + int err, e; + unsigned char dmsg; + struct au_mvd_args *args; + struct inode *inode; + + inode = d_inode(dentry); + err = -EPERM; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + err = -ENOMEM; + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) + goto out; + + err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); + if (!err) + /* VERIFY_WRITE */ + err = !access_ok(uarg, sizeof(*uarg)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out_free; + } + AuDbg("flags 0x%x\n", args->mvdown.flags); + args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); + args->mvdown.au_errno = 0; + args->dentry = dentry; + args->inode = inode; + args->sb = dentry->d_sb; + + err = -ENOENT; + dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); + args->parent = dget_parent(dentry); + args->dir = d_inode(args->parent); + inode_lock_nested(args->dir, I_MUTEX_PARENT); + dput(args->parent); + if (unlikely(args->parent != dentry->d_parent)) { + AU_MVD_PR(dmsg, "parent dir is moved\n"); + goto out_dir; + } + + inode_lock_nested(inode, I_MUTEX_CHILD); + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); + if (unlikely(err)) + goto out_inode; + + di_write_lock_parent(args->parent); + err = au_mvd_args(dmsg, args); + if (unlikely(err)) + goto out_parent; + + err = au_do_mvdown(dmsg, args); + if (unlikely(err)) + goto out_parent; + + au_cpup_attr_timesizes(args->dir); + au_cpup_attr_timesizes(inode); + if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) + au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); + /* au_digen_dec(dentry); */ + +out_parent: + di_write_unlock(args->parent); + aufs_read_unlock(dentry, AuLock_DW); +out_inode: + inode_unlock(inode); +out_dir: + inode_unlock(args->dir); +out_free: + e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); + if (unlikely(e)) + err = -EFAULT; + au_kfree_rcu(args); +out: + AuTraceErr(err); + return err; +} diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c new file mode 100644 index 000000000000..954afe04d5ba --- /dev/null +++ b/fs/aufs/opts.c @@ -0,0 +1,1880 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * mount options/flags + */ + +#include +#include /* a distribution requires */ +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +enum { + Opt_br, + Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, + Opt_idel, Opt_imod, + Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, + Opt_rdblk_def, Opt_rdhash_def, + Opt_xino, Opt_noxino, + Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, + Opt_trunc_xino_path, Opt_itrunc_xino, + Opt_trunc_xib, Opt_notrunc_xib, + Opt_shwh, Opt_noshwh, + Opt_plink, Opt_noplink, Opt_list_plink, + Opt_udba, + Opt_dio, Opt_nodio, + Opt_diropq_a, Opt_diropq_w, + Opt_warn_perm, Opt_nowarn_perm, + Opt_wbr_copyup, Opt_wbr_create, + Opt_fhsm_sec, + Opt_verbose, Opt_noverbose, + Opt_sum, Opt_nosum, Opt_wsum, + Opt_dirperm1, Opt_nodirperm1, + Opt_dirren, Opt_nodirren, + Opt_acl, Opt_noacl, + Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err +}; + +static match_table_t options = { + {Opt_br, "br=%s"}, + {Opt_br, "br:%s"}, + + {Opt_add, "add=%d:%s"}, + {Opt_add, "add:%d:%s"}, + {Opt_add, "ins=%d:%s"}, + {Opt_add, "ins:%d:%s"}, + {Opt_append, "append=%s"}, + {Opt_append, "append:%s"}, + {Opt_prepend, "prepend=%s"}, + {Opt_prepend, "prepend:%s"}, + + {Opt_del, "del=%s"}, + {Opt_del, "del:%s"}, + /* {Opt_idel, "idel:%d"}, */ + {Opt_mod, "mod=%s"}, + {Opt_mod, "mod:%s"}, + /* {Opt_imod, "imod:%d:%s"}, */ + + {Opt_dirwh, "dirwh=%d"}, + + {Opt_xino, "xino=%s"}, + {Opt_noxino, "noxino"}, + {Opt_trunc_xino, "trunc_xino"}, + {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, + {Opt_notrunc_xino, "notrunc_xino"}, + {Opt_trunc_xino_path, "trunc_xino=%s"}, + {Opt_itrunc_xino, "itrunc_xino=%d"}, + /* {Opt_zxino, "zxino=%s"}, */ + {Opt_trunc_xib, "trunc_xib"}, + {Opt_notrunc_xib, "notrunc_xib"}, + +#ifdef CONFIG_PROC_FS + {Opt_plink, "plink"}, +#else + {Opt_ignore_silent, "plink"}, +#endif + + {Opt_noplink, "noplink"}, + +#ifdef CONFIG_AUFS_DEBUG + {Opt_list_plink, "list_plink"}, +#endif + + {Opt_udba, "udba=%s"}, + + {Opt_dio, "dio"}, + {Opt_nodio, "nodio"}, + +#ifdef CONFIG_AUFS_DIRREN + {Opt_dirren, "dirren"}, + {Opt_nodirren, "nodirren"}, +#else + {Opt_ignore, "dirren"}, + {Opt_ignore_silent, "nodirren"}, +#endif + +#ifdef CONFIG_AUFS_FHSM + {Opt_fhsm_sec, "fhsm_sec=%d"}, +#else + {Opt_ignore, "fhsm_sec=%d"}, +#endif + + {Opt_diropq_a, "diropq=always"}, + {Opt_diropq_a, "diropq=a"}, + {Opt_diropq_w, "diropq=whiteouted"}, + {Opt_diropq_w, "diropq=w"}, + + {Opt_warn_perm, "warn_perm"}, + {Opt_nowarn_perm, "nowarn_perm"}, + + /* keep them temporary */ + {Opt_ignore_silent, "nodlgt"}, + {Opt_ignore, "clean_plink"}, + +#ifdef CONFIG_AUFS_SHWH + {Opt_shwh, "shwh"}, +#endif + {Opt_noshwh, "noshwh"}, + + {Opt_dirperm1, "dirperm1"}, + {Opt_nodirperm1, "nodirperm1"}, + + {Opt_verbose, "verbose"}, + {Opt_verbose, "v"}, + {Opt_noverbose, "noverbose"}, + {Opt_noverbose, "quiet"}, + {Opt_noverbose, "q"}, + {Opt_noverbose, "silent"}, + + {Opt_sum, "sum"}, + {Opt_nosum, "nosum"}, + {Opt_wsum, "wsum"}, + + {Opt_rdcache, "rdcache=%d"}, + {Opt_rdblk, "rdblk=%d"}, + {Opt_rdblk_def, "rdblk=def"}, + {Opt_rdhash, "rdhash=%d"}, + {Opt_rdhash_def, "rdhash=def"}, + + {Opt_wbr_create, "create=%s"}, + {Opt_wbr_create, "create_policy=%s"}, + {Opt_wbr_copyup, "cpup=%s"}, + {Opt_wbr_copyup, "copyup=%s"}, + {Opt_wbr_copyup, "copyup_policy=%s"}, + + /* generic VFS flag */ +#ifdef CONFIG_FS_POSIX_ACL + {Opt_acl, "acl"}, + {Opt_noacl, "noacl"}, +#else + {Opt_ignore, "acl"}, + {Opt_ignore_silent, "noacl"}, +#endif + + /* internal use for the scripts */ + {Opt_ignore_silent, "si=%s"}, + + {Opt_br, "dirs=%s"}, + {Opt_ignore, "debug=%d"}, + {Opt_ignore, "delete=whiteout"}, + {Opt_ignore, "delete=all"}, + {Opt_ignore, "imap=%s"}, + + /* temporary workaround, due to old mount(8)? */ + {Opt_ignore_silent, "relatime"}, + + {Opt_err, NULL} +}; + +/* ---------------------------------------------------------------------- */ + +static const char *au_parser_pattern(int val, match_table_t tbl) +{ + struct match_token *p; + + p = tbl; + while (p->pattern) { + if (p->token == val) + return p->pattern; + p++; + } + BUG(); + return "??"; +} + +static const char *au_optstr(int *val, match_table_t tbl) +{ + struct match_token *p; + int v; + + v = *val; + if (!v) + goto out; + p = tbl; + while (p->pattern) { + if (p->token + && (v & p->token) == p->token) { + *val &= ~p->token; + return p->pattern; + } + p++; + } + +out: + return NULL; +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t brperm = { + {AuBrPerm_RO, AUFS_BRPERM_RO}, + {AuBrPerm_RR, AUFS_BRPERM_RR}, + {AuBrPerm_RW, AUFS_BRPERM_RW}, + {0, NULL} +}; + +static match_table_t brattr = { + /* general */ + {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, + {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, + /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ + {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, +#ifdef CONFIG_AUFS_FHSM + {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, +#endif +#ifdef CONFIG_AUFS_XATTR + {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, + {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, + {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, + {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, + {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, + {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, +#endif + + /* ro/rr branch */ + {AuBrRAttr_WH, AUFS_BRRATTR_WH}, + + /* rw branch */ + {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, + {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, + + {0, NULL} +}; + +static int br_attr_val(char *str, match_table_t table, substring_t args[]) +{ + int attr, v; + char *p; + + attr = 0; + do { + p = strchr(str, '+'); + if (p) + *p = 0; + v = match_token(str, table, args); + if (v) { + if (v & AuBrAttr_CMOO_Mask) + attr &= ~AuBrAttr_CMOO_Mask; + attr |= v; + } else { + if (p) + *p = '+'; + pr_warn("ignored branch attribute %s\n", str); + break; + } + if (p) + str = p + 1; + } while (p); + + return attr; +} + +static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) +{ + int sz; + const char *p; + char *q; + + q = str->a; + *q = 0; + p = au_optstr(&perm, brattr); + if (p) { + sz = strlen(p); + memcpy(q, p, sz + 1); + q += sz; + } else + goto out; + + do { + p = au_optstr(&perm, brattr); + if (p) { + *q++ = '+'; + sz = strlen(p); + memcpy(q, p, sz + 1); + q += sz; + } + } while (p); + +out: + return q - str->a; +} + +static int noinline_for_stack br_perm_val(char *perm) +{ + int val, bad, sz; + char *p; + substring_t args[MAX_OPT_ARGS]; + au_br_perm_str_t attr; + + p = strchr(perm, '+'); + if (p) + *p = 0; + val = match_token(perm, brperm, args); + if (!val) { + if (p) + *p = '+'; + pr_warn("ignored branch permission %s\n", perm); + val = AuBrPerm_RO; + goto out; + } + if (!p) + goto out; + + val |= br_attr_val(p + 1, brattr, args); + + bad = 0; + switch (val & AuBrPerm_Mask) { + case AuBrPerm_RO: + case AuBrPerm_RR: + bad = val & AuBrWAttr_Mask; + val &= ~AuBrWAttr_Mask; + break; + case AuBrPerm_RW: + bad = val & AuBrRAttr_Mask; + val &= ~AuBrRAttr_Mask; + break; + } + + /* + * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs + * does not treat it as an error, just warning. + * this is a tiny guard for the user operation. + */ + if (val & AuBrAttr_UNPIN) { + bad |= AuBrAttr_UNPIN; + val &= ~AuBrAttr_UNPIN; + } + + if (unlikely(bad)) { + sz = au_do_optstr_br_attr(&attr, bad); + AuDebugOn(!sz); + pr_warn("ignored branch attribute %s\n", attr.a); + } + +out: + return val; +} + +void au_optstr_br_perm(au_br_perm_str_t *str, int perm) +{ + au_br_perm_str_t attr; + const char *p; + char *q; + int sz; + + q = str->a; + p = au_optstr(&perm, brperm); + AuDebugOn(!p || !*p); + sz = strlen(p); + memcpy(q, p, sz + 1); + q += sz; + + sz = au_do_optstr_br_attr(&attr, perm); + if (sz) { + *q++ = '+'; + memcpy(q, attr.a, sz + 1); + } + + AuDebugOn(strlen(str->a) >= sizeof(str->a)); +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t udbalevel = { + {AuOpt_UDBA_REVAL, "reval"}, + {AuOpt_UDBA_NONE, "none"}, +#ifdef CONFIG_AUFS_HNOTIFY + {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ +#ifdef CONFIG_AUFS_HFSNOTIFY + {AuOpt_UDBA_HNOTIFY, "fsnotify"}, +#endif +#endif + {-1, NULL} +}; + +static int noinline_for_stack udba_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + + return match_token(str, udbalevel, args); +} + +const char *au_optstr_udba(int udba) +{ + return au_parser_pattern(udba, udbalevel); +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t au_wbr_create_policy = { + {AuWbrCreate_TDP, "tdp"}, + {AuWbrCreate_TDP, "top-down-parent"}, + {AuWbrCreate_RR, "rr"}, + {AuWbrCreate_RR, "round-robin"}, + {AuWbrCreate_MFS, "mfs"}, + {AuWbrCreate_MFS, "most-free-space"}, + {AuWbrCreate_MFSV, "mfs:%d"}, + {AuWbrCreate_MFSV, "most-free-space:%d"}, + + /* top-down regardless the parent, and then mfs */ + {AuWbrCreate_TDMFS, "tdmfs:%d"}, + {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, + + {AuWbrCreate_MFSRR, "mfsrr:%d"}, + {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, + {AuWbrCreate_PMFS, "pmfs"}, + {AuWbrCreate_PMFSV, "pmfs:%d"}, + {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, + {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, + + {-1, NULL} +}; + +static int au_wbr_mfs_wmark(substring_t *arg, char *str, + struct au_opt_wbr_create *create) +{ + int err; + unsigned long long ull; + + err = 0; + if (!match_u64(arg, &ull)) + create->mfsrr_watermark = ull; + else { + pr_err("bad integer in %s\n", str); + err = -EINVAL; + } + + return err; +} + +static int au_wbr_mfs_sec(substring_t *arg, char *str, + struct au_opt_wbr_create *create) +{ + int n, err; + + err = 0; + if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) + create->mfs_second = n; + else { + pr_err("bad integer in %s\n", str); + err = -EINVAL; + } + + return err; +} + +static int noinline_for_stack +au_wbr_create_val(char *str, struct au_opt_wbr_create *create) +{ + int err, e; + substring_t args[MAX_OPT_ARGS]; + + err = match_token(str, au_wbr_create_policy, args); + create->wbr_create = err; + switch (err) { + case AuWbrCreate_MFSRRV: + case AuWbrCreate_TDMFSV: + case AuWbrCreate_PMFSRRV: + e = au_wbr_mfs_wmark(&args[0], str, create); + if (!e) + e = au_wbr_mfs_sec(&args[1], str, create); + if (unlikely(e)) + err = e; + break; + case AuWbrCreate_MFSRR: + case AuWbrCreate_TDMFS: + case AuWbrCreate_PMFSRR: + e = au_wbr_mfs_wmark(&args[0], str, create); + if (unlikely(e)) { + err = e; + break; + } + fallthrough; + case AuWbrCreate_MFS: + case AuWbrCreate_PMFS: + create->mfs_second = AUFS_MFS_DEF_SEC; + break; + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + e = au_wbr_mfs_sec(&args[0], str, create); + if (unlikely(e)) + err = e; + break; + } + + return err; +} + +const char *au_optstr_wbr_create(int wbr_create) +{ + return au_parser_pattern(wbr_create, au_wbr_create_policy); +} + +static match_table_t au_wbr_copyup_policy = { + {AuWbrCopyup_TDP, "tdp"}, + {AuWbrCopyup_TDP, "top-down-parent"}, + {AuWbrCopyup_BUP, "bup"}, + {AuWbrCopyup_BUP, "bottom-up-parent"}, + {AuWbrCopyup_BU, "bu"}, + {AuWbrCopyup_BU, "bottom-up"}, + {-1, NULL} +}; + +static int noinline_for_stack au_wbr_copyup_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + + return match_token(str, au_wbr_copyup_policy, args); +} + +const char *au_optstr_wbr_copyup(int wbr_copyup) +{ + return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); +} + +/* ---------------------------------------------------------------------- */ + +static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; + +static void dump_opts(struct au_opts *opts) +{ +#ifdef CONFIG_AUFS_DEBUG + /* reduce stack space */ + union { + struct au_opt_add *add; + struct au_opt_del *del; + struct au_opt_mod *mod; + struct au_opt_xino *xino; + struct au_opt_xino_itrunc *xino_itrunc; + struct au_opt_wbr_create *create; + } u; + struct au_opt *opt; + + opt = opts->opt; + while (opt->type != Opt_tail) { + switch (opt->type) { + case Opt_add: + u.add = &opt->add; + AuDbg("add {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->pathname, u.add->perm, + u.add->path.dentry); + break; + case Opt_del: + case Opt_idel: + u.del = &opt->del; + AuDbg("del {%s, %p}\n", + u.del->pathname, u.del->h_path.dentry); + break; + case Opt_mod: + case Opt_imod: + u.mod = &opt->mod; + AuDbg("mod {%s, 0x%x, %p}\n", + u.mod->path, u.mod->perm, u.mod->h_root); + break; + case Opt_append: + u.add = &opt->add; + AuDbg("append {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->pathname, u.add->perm, + u.add->path.dentry); + break; + case Opt_prepend: + u.add = &opt->add; + AuDbg("prepend {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->pathname, u.add->perm, + u.add->path.dentry); + break; + case Opt_dirwh: + AuDbg("dirwh %d\n", opt->dirwh); + break; + case Opt_rdcache: + AuDbg("rdcache %d\n", opt->rdcache); + break; + case Opt_rdblk: + AuDbg("rdblk %u\n", opt->rdblk); + break; + case Opt_rdblk_def: + AuDbg("rdblk_def\n"); + break; + case Opt_rdhash: + AuDbg("rdhash %u\n", opt->rdhash); + break; + case Opt_rdhash_def: + AuDbg("rdhash_def\n"); + break; + case Opt_xino: + u.xino = &opt->xino; + AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); + break; + case Opt_trunc_xino: + AuLabel(trunc_xino); + break; + case Opt_notrunc_xino: + AuLabel(notrunc_xino); + break; + case Opt_trunc_xino_path: + case Opt_itrunc_xino: + u.xino_itrunc = &opt->xino_itrunc; + AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); + break; + case Opt_noxino: + AuLabel(noxino); + break; + case Opt_trunc_xib: + AuLabel(trunc_xib); + break; + case Opt_notrunc_xib: + AuLabel(notrunc_xib); + break; + case Opt_shwh: + AuLabel(shwh); + break; + case Opt_noshwh: + AuLabel(noshwh); + break; + case Opt_dirperm1: + AuLabel(dirperm1); + break; + case Opt_nodirperm1: + AuLabel(nodirperm1); + break; + case Opt_plink: + AuLabel(plink); + break; + case Opt_noplink: + AuLabel(noplink); + break; + case Opt_list_plink: + AuLabel(list_plink); + break; + case Opt_udba: + AuDbg("udba %d, %s\n", + opt->udba, au_optstr_udba(opt->udba)); + break; + case Opt_dio: + AuLabel(dio); + break; + case Opt_nodio: + AuLabel(nodio); + break; + case Opt_diropq_a: + AuLabel(diropq_a); + break; + case Opt_diropq_w: + AuLabel(diropq_w); + break; + case Opt_warn_perm: + AuLabel(warn_perm); + break; + case Opt_nowarn_perm: + AuLabel(nowarn_perm); + break; + case Opt_verbose: + AuLabel(verbose); + break; + case Opt_noverbose: + AuLabel(noverbose); + break; + case Opt_sum: + AuLabel(sum); + break; + case Opt_nosum: + AuLabel(nosum); + break; + case Opt_wsum: + AuLabel(wsum); + break; + case Opt_wbr_create: + u.create = &opt->wbr_create; + AuDbg("create %d, %s\n", u.create->wbr_create, + au_optstr_wbr_create(u.create->wbr_create)); + switch (u.create->wbr_create) { + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + AuDbg("%d sec\n", u.create->mfs_second); + break; + case AuWbrCreate_MFSRR: + case AuWbrCreate_TDMFS: + AuDbg("%llu watermark\n", + u.create->mfsrr_watermark); + break; + case AuWbrCreate_MFSRRV: + case AuWbrCreate_TDMFSV: + case AuWbrCreate_PMFSRRV: + AuDbg("%llu watermark, %d sec\n", + u.create->mfsrr_watermark, + u.create->mfs_second); + break; + } + break; + case Opt_wbr_copyup: + AuDbg("copyup %d, %s\n", opt->wbr_copyup, + au_optstr_wbr_copyup(opt->wbr_copyup)); + break; + case Opt_fhsm_sec: + AuDbg("fhsm_sec %u\n", opt->fhsm_second); + break; + case Opt_dirren: + AuLabel(dirren); + break; + case Opt_nodirren: + AuLabel(nodirren); + break; + case Opt_acl: + AuLabel(acl); + break; + case Opt_noacl: + AuLabel(noacl); + break; + default: + BUG(); + } + opt++; + } +#endif +} + +void au_opts_free(struct au_opts *opts) +{ + struct au_opt *opt; + + opt = opts->opt; + while (opt->type != Opt_tail) { + switch (opt->type) { + case Opt_add: + case Opt_append: + case Opt_prepend: + path_put(&opt->add.path); + break; + case Opt_del: + case Opt_idel: + path_put(&opt->del.h_path); + break; + case Opt_mod: + case Opt_imod: + dput(opt->mod.h_root); + break; + case Opt_xino: + fput(opt->xino.file); + break; + } + opt++; + } +} + +static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, + aufs_bindex_t bindex) +{ + int err; + struct au_opt_add *add = &opt->add; + char *p; + + add->bindex = bindex; + add->perm = AuBrPerm_RO; + add->pathname = opt_str; + p = strchr(opt_str, '='); + if (p) { + *p++ = 0; + if (*p) + add->perm = br_perm_val(p); + } + + err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); + if (!err) { + if (!p) { + add->perm = AuBrPerm_RO; + if (au_test_fs_rr(add->path.dentry->d_sb)) + add->perm = AuBrPerm_RR; + else if (!bindex && !(sb_flags & SB_RDONLY)) + add->perm = AuBrPerm_RW; + } + opt->type = Opt_add; + goto out; + } + pr_err("lookup failed %s (%d)\n", add->pathname, err); + err = -EINVAL; + +out: + return err; +} + +static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) +{ + int err; + + del->pathname = args[0].from; + AuDbg("del path %s\n", del->pathname); + + err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); + if (unlikely(err)) + pr_err("lookup failed %s (%d)\n", del->pathname, err); + + return err; +} + +#if 0 /* reserved for future use */ +static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, + struct au_opt_del *del, substring_t args[]) +{ + int err; + struct dentry *root; + + err = -EINVAL; + root = sb->s_root; + aufs_read_lock(root, AuLock_FLUSH); + if (bindex < 0 || au_sbbot(sb) < bindex) { + pr_err("out of bounds, %d\n", bindex); + goto out; + } + + err = 0; + del->h_path.dentry = dget(au_h_dptr(root, bindex)); + del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); + +out: + aufs_read_unlock(root, !AuLock_IR); + return err; +} +#endif + +static int noinline_for_stack +au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) +{ + int err; + struct path path; + char *p; + + err = -EINVAL; + mod->path = args[0].from; + p = strchr(mod->path, '='); + if (unlikely(!p)) { + pr_err("no permission %s\n", args[0].from); + goto out; + } + + *p++ = 0; + err = vfsub_kern_path(mod->path, lkup_dirflags, &path); + if (unlikely(err)) { + pr_err("lookup failed %s (%d)\n", mod->path, err); + goto out; + } + + mod->perm = br_perm_val(p); + AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); + mod->h_root = dget(path.dentry); + path_put(&path); + +out: + return err; +} + +#if 0 /* reserved for future use */ +static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, + struct au_opt_mod *mod, substring_t args[]) +{ + int err; + struct dentry *root; + + err = -EINVAL; + root = sb->s_root; + aufs_read_lock(root, AuLock_FLUSH); + if (bindex < 0 || au_sbbot(sb) < bindex) { + pr_err("out of bounds, %d\n", bindex); + goto out; + } + + err = 0; + mod->perm = br_perm_val(args[1].from); + AuDbg("mod path %s, perm 0x%x, %s\n", + mod->path, mod->perm, args[1].from); + mod->h_root = dget(au_h_dptr(root, bindex)); + +out: + aufs_read_unlock(root, !AuLock_IR); + return err; +} +#endif + +static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, + substring_t args[]) +{ + int err; + struct file *file; + + file = au_xino_create(sb, args[0].from, /*silent*/0, /*wbrtop*/0); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + + err = -EINVAL; + if (unlikely(file->f_path.dentry->d_sb == sb)) { + fput(file); + pr_err("%s must be outside\n", args[0].from); + goto out; + } + + err = 0; + xino->file = file; + xino->path = args[0].from; + +out: + return err; +} + +static int noinline_for_stack +au_opts_parse_xino_itrunc_path(struct super_block *sb, + struct au_opt_xino_itrunc *xino_itrunc, + substring_t args[]) +{ + int err; + aufs_bindex_t bbot, bindex; + struct path path; + struct dentry *root; + + err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); + if (unlikely(err)) { + pr_err("lookup failed %s (%d)\n", args[0].from, err); + goto out; + } + + xino_itrunc->bindex = -1; + root = sb->s_root; + aufs_read_lock(root, AuLock_FLUSH); + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + if (au_h_dptr(root, bindex) == path.dentry) { + xino_itrunc->bindex = bindex; + break; + } + } + aufs_read_unlock(root, !AuLock_IR); + path_put(&path); + + if (unlikely(xino_itrunc->bindex < 0)) { + pr_err("no such branch %s\n", args[0].from); + err = -EINVAL; + } + +out: + return err; +} + +/* called without aufs lock */ +int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) +{ + int err, n, token; + aufs_bindex_t bindex; + unsigned char skipped; + struct dentry *root; + struct au_opt *opt, *opt_tail; + char *opt_str; + /* reduce the stack space */ + union { + struct au_opt_xino_itrunc *xino_itrunc; + struct au_opt_wbr_create *create; + } u; + struct { + substring_t args[MAX_OPT_ARGS]; + } *a; + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + root = sb->s_root; + err = 0; + bindex = 0; + opt = opts->opt; + opt_tail = opt + opts->max_opt - 1; + opt->type = Opt_tail; + while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { + err = -EINVAL; + skipped = 0; + token = match_token(opt_str, options, a->args); + switch (token) { + case Opt_br: + err = 0; + while (!err && (opt_str = strsep(&a->args[0].from, ":")) + && *opt_str) { + err = opt_add(opt, opt_str, opts->sb_flags, + bindex++); + if (unlikely(!err && ++opt > opt_tail)) { + err = -E2BIG; + break; + } + opt->type = Opt_tail; + skipped = 1; + } + break; + case Opt_add: + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + bindex = n; + err = opt_add(opt, a->args[1].from, opts->sb_flags, + bindex); + if (!err) + opt->type = token; + break; + case Opt_append: + err = opt_add(opt, a->args[0].from, opts->sb_flags, + /*dummy bindex*/1); + if (!err) + opt->type = token; + break; + case Opt_prepend: + err = opt_add(opt, a->args[0].from, opts->sb_flags, + /*bindex*/0); + if (!err) + opt->type = token; + break; + case Opt_del: + err = au_opts_parse_del(&opt->del, a->args); + if (!err) + opt->type = token; + break; +#if 0 /* reserved for future use */ + case Opt_idel: + del->pathname = "(indexed)"; + if (unlikely(match_int(&args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + err = au_opts_parse_idel(sb, n, &opt->del, a->args); + if (!err) + opt->type = token; + break; +#endif + case Opt_mod: + err = au_opts_parse_mod(&opt->mod, a->args); + if (!err) + opt->type = token; + break; +#ifdef IMOD /* reserved for future use */ + case Opt_imod: + u.mod->path = "(indexed)"; + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + err = au_opts_parse_imod(sb, n, &opt->mod, a->args); + if (!err) + opt->type = token; + break; +#endif + case Opt_xino: + err = au_opts_parse_xino(sb, &opt->xino, a->args); + if (!err) + opt->type = token; + break; + + case Opt_trunc_xino_path: + err = au_opts_parse_xino_itrunc_path + (sb, &opt->xino_itrunc, a->args); + if (!err) + opt->type = token; + break; + + case Opt_itrunc_xino: + u.xino_itrunc = &opt->xino_itrunc; + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + u.xino_itrunc->bindex = n; + aufs_read_lock(root, AuLock_FLUSH); + if (n < 0 || au_sbbot(sb) < n) { + pr_err("out of bounds, %d\n", n); + aufs_read_unlock(root, !AuLock_IR); + break; + } + aufs_read_unlock(root, !AuLock_IR); + err = 0; + opt->type = token; + break; + + case Opt_dirwh: + if (unlikely(match_int(&a->args[0], &opt->dirwh))) + break; + err = 0; + opt->type = token; + break; + + case Opt_rdcache: + if (unlikely(match_int(&a->args[0], &n))) { + pr_err("bad integer in %s\n", opt_str); + break; + } + if (unlikely(n > AUFS_RDCACHE_MAX)) { + pr_err("rdcache must be smaller than %d\n", + AUFS_RDCACHE_MAX); + break; + } + opt->rdcache = n; + err = 0; + opt->type = token; + break; + case Opt_rdblk: + if (unlikely(match_int(&a->args[0], &n) + || n < 0 + || n > KMALLOC_MAX_SIZE)) { + pr_err("bad integer in %s\n", opt_str); + break; + } + if (unlikely(n && n < NAME_MAX)) { + pr_err("rdblk must be larger than %d\n", + NAME_MAX); + break; + } + opt->rdblk = n; + err = 0; + opt->type = token; + break; + case Opt_rdhash: + if (unlikely(match_int(&a->args[0], &n) + || n < 0 + || n * sizeof(struct hlist_head) + > KMALLOC_MAX_SIZE)) { + pr_err("bad integer in %s\n", opt_str); + break; + } + opt->rdhash = n; + err = 0; + opt->type = token; + break; + + case Opt_trunc_xino: + case Opt_notrunc_xino: + case Opt_noxino: + case Opt_trunc_xib: + case Opt_notrunc_xib: + case Opt_shwh: + case Opt_noshwh: + case Opt_dirperm1: + case Opt_nodirperm1: + case Opt_plink: + case Opt_noplink: + case Opt_list_plink: + case Opt_dio: + case Opt_nodio: + case Opt_diropq_a: + case Opt_diropq_w: + case Opt_warn_perm: + case Opt_nowarn_perm: + case Opt_verbose: + case Opt_noverbose: + case Opt_sum: + case Opt_nosum: + case Opt_wsum: + case Opt_rdblk_def: + case Opt_rdhash_def: + case Opt_dirren: + case Opt_nodirren: + case Opt_acl: + case Opt_noacl: + err = 0; + opt->type = token; + break; + + case Opt_udba: + opt->udba = udba_val(a->args[0].from); + if (opt->udba >= 0) { + err = 0; + opt->type = token; + } else + pr_err("wrong value, %s\n", opt_str); + break; + + case Opt_wbr_create: + u.create = &opt->wbr_create; + u.create->wbr_create + = au_wbr_create_val(a->args[0].from, u.create); + if (u.create->wbr_create >= 0) { + err = 0; + opt->type = token; + } else + pr_err("wrong value, %s\n", opt_str); + break; + case Opt_wbr_copyup: + opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); + if (opt->wbr_copyup >= 0) { + err = 0; + opt->type = token; + } else + pr_err("wrong value, %s\n", opt_str); + break; + + case Opt_fhsm_sec: + if (unlikely(match_int(&a->args[0], &n) + || n < 0)) { + pr_err("bad integer in %s\n", opt_str); + break; + } + if (sysaufs_brs) { + opt->fhsm_second = n; + opt->type = token; + } else + pr_warn("ignored %s\n", opt_str); + err = 0; + break; + + case Opt_ignore: + pr_warn("ignored %s\n", opt_str); + fallthrough; + case Opt_ignore_silent: + skipped = 1; + err = 0; + break; + case Opt_err: + pr_err("unknown option %s\n", opt_str); + break; + } + + if (!err && !skipped) { + if (unlikely(++opt > opt_tail)) { + err = -E2BIG; + opt--; + opt->type = Opt_tail; + break; + } + opt->type = Opt_tail; + } + } + + au_kfree_rcu(a); + dump_opts(opts); + if (unlikely(err)) + au_opts_free(opts); + +out: + return err; +} + +static int au_opt_wbr_create(struct super_block *sb, + struct au_opt_wbr_create *create) +{ + int err; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + err = 1; /* handled */ + sbinfo = au_sbi(sb); + if (sbinfo->si_wbr_create_ops->fin) { + err = sbinfo->si_wbr_create_ops->fin(sb); + if (!err) + err = 1; + } + + sbinfo->si_wbr_create = create->wbr_create; + sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; + switch (create->wbr_create) { + case AuWbrCreate_MFSRRV: + case AuWbrCreate_MFSRR: + case AuWbrCreate_TDMFS: + case AuWbrCreate_TDMFSV: + case AuWbrCreate_PMFSRR: + case AuWbrCreate_PMFSRRV: + sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; + fallthrough; + case AuWbrCreate_MFS: + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFS: + case AuWbrCreate_PMFSV: + sbinfo->si_wbr_mfs.mfs_expire + = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); + break; + } + + if (sbinfo->si_wbr_create_ops->init) + sbinfo->si_wbr_create_ops->init(sb); /* ignore */ + + return err; +} + +/* + * returns, + * plus: processed without an error + * zero: unprocessed + */ +static int au_opt_simple(struct super_block *sb, struct au_opt *opt, + struct au_opts *opts) +{ + int err; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + err = 1; /* handled */ + sbinfo = au_sbi(sb); + switch (opt->type) { + case Opt_udba: + sbinfo->si_mntflags &= ~AuOptMask_UDBA; + sbinfo->si_mntflags |= opt->udba; + opts->given_udba |= opt->udba; + break; + + case Opt_plink: + au_opt_set(sbinfo->si_mntflags, PLINK); + break; + case Opt_noplink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_put(sb, /*verbose*/1); + au_opt_clr(sbinfo->si_mntflags, PLINK); + break; + case Opt_list_plink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_list(sb); + break; + + case Opt_dio: + au_opt_set(sbinfo->si_mntflags, DIO); + au_fset_opts(opts->flags, REFRESH_DYAOP); + break; + case Opt_nodio: + au_opt_clr(sbinfo->si_mntflags, DIO); + au_fset_opts(opts->flags, REFRESH_DYAOP); + break; + + case Opt_fhsm_sec: + au_fhsm_set(sbinfo, opt->fhsm_second); + break; + + case Opt_diropq_a: + au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; + case Opt_diropq_w: + au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; + + case Opt_warn_perm: + au_opt_set(sbinfo->si_mntflags, WARN_PERM); + break; + case Opt_nowarn_perm: + au_opt_clr(sbinfo->si_mntflags, WARN_PERM); + break; + + case Opt_verbose: + au_opt_set(sbinfo->si_mntflags, VERBOSE); + break; + case Opt_noverbose: + au_opt_clr(sbinfo->si_mntflags, VERBOSE); + break; + + case Opt_sum: + au_opt_set(sbinfo->si_mntflags, SUM); + break; + case Opt_wsum: + au_opt_clr(sbinfo->si_mntflags, SUM); + au_opt_set(sbinfo->si_mntflags, SUM_W); + break; + case Opt_nosum: + au_opt_clr(sbinfo->si_mntflags, SUM); + au_opt_clr(sbinfo->si_mntflags, SUM_W); + break; + + case Opt_wbr_create: + err = au_opt_wbr_create(sb, &opt->wbr_create); + break; + case Opt_wbr_copyup: + sbinfo->si_wbr_copyup = opt->wbr_copyup; + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; + break; + + case Opt_dirwh: + sbinfo->si_dirwh = opt->dirwh; + break; + + case Opt_rdcache: + sbinfo->si_rdcache + = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); + break; + case Opt_rdblk: + sbinfo->si_rdblk = opt->rdblk; + break; + case Opt_rdblk_def: + sbinfo->si_rdblk = AUFS_RDBLK_DEF; + break; + case Opt_rdhash: + sbinfo->si_rdhash = opt->rdhash; + break; + case Opt_rdhash_def: + sbinfo->si_rdhash = AUFS_RDHASH_DEF; + break; + + case Opt_shwh: + au_opt_set(sbinfo->si_mntflags, SHWH); + break; + case Opt_noshwh: + au_opt_clr(sbinfo->si_mntflags, SHWH); + break; + + case Opt_dirperm1: + au_opt_set(sbinfo->si_mntflags, DIRPERM1); + break; + case Opt_nodirperm1: + au_opt_clr(sbinfo->si_mntflags, DIRPERM1); + break; + + case Opt_trunc_xino: + au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); + break; + case Opt_notrunc_xino: + au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); + break; + + case Opt_trunc_xino_path: + case Opt_itrunc_xino: + err = au_xino_trunc(sb, opt->xino_itrunc.bindex, + /*idx_begin*/0); + if (!err) + err = 1; + break; + + case Opt_trunc_xib: + au_fset_opts(opts->flags, TRUNC_XIB); + break; + case Opt_notrunc_xib: + au_fclr_opts(opts->flags, TRUNC_XIB); + break; + + case Opt_dirren: + err = 1; + if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { + err = au_dr_opt_set(sb); + if (!err) + err = 1; + } + if (err == 1) + au_opt_set(sbinfo->si_mntflags, DIRREN); + break; + case Opt_nodirren: + err = 1; + if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { + err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, + DR_FLUSHED)); + if (!err) + err = 1; + } + if (err == 1) + au_opt_clr(sbinfo->si_mntflags, DIRREN); + break; + + case Opt_acl: + sb->s_flags |= SB_POSIXACL; + break; + case Opt_noacl: + sb->s_flags &= ~SB_POSIXACL; + break; + + default: + err = 0; + break; + } + + return err; +} + +/* + * returns tri-state. + * plus: processed without an error + * zero: unprocessed + * minus: error + */ +static int au_opt_br(struct super_block *sb, struct au_opt *opt, + struct au_opts *opts) +{ + int err, do_refresh; + + err = 0; + switch (opt->type) { + case Opt_append: + opt->add.bindex = au_sbbot(sb) + 1; + if (opt->add.bindex < 0) + opt->add.bindex = 0; + goto add; + /* Always goto add, not fallthrough */ + case Opt_prepend: + opt->add.bindex = 0; + fallthrough; + add: /* indented label */ + case Opt_add: + err = au_br_add(sb, &opt->add, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { + err = 1; + au_fset_opts(opts->flags, REFRESH); + } + break; + + case Opt_del: + case Opt_idel: + err = au_br_del(sb, &opt->del, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { + err = 1; + au_fset_opts(opts->flags, TRUNC_XIB); + au_fset_opts(opts->flags, REFRESH); + } + break; + + case Opt_mod: + case Opt_imod: + err = au_br_mod(sb, &opt->mod, + au_ftest_opts(opts->flags, REMOUNT), + &do_refresh); + if (!err) { + err = 1; + if (do_refresh) + au_fset_opts(opts->flags, REFRESH); + } + break; + } + return err; +} + +static int au_opt_xino(struct super_block *sb, struct au_opt *opt, + struct au_opt_xino **opt_xino, + struct au_opts *opts) +{ + int err; + + err = 0; + switch (opt->type) { + case Opt_xino: + err = au_xino_set(sb, &opt->xino, + !!au_ftest_opts(opts->flags, REMOUNT)); + if (unlikely(err)) + break; + + *opt_xino = &opt->xino; + break; + + case Opt_noxino: + au_xino_clr(sb); + *opt_xino = (void *)-1; + break; + } + + return err; +} + +int au_opts_verify(struct super_block *sb, unsigned long sb_flags, + unsigned int pending) +{ + int err, fhsm; + aufs_bindex_t bindex, bbot; + unsigned char do_plink, skip, do_free, can_no_dreval; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *root, *dentry; + struct inode *dir, *h_dir; + struct au_sbinfo *sbinfo; + struct au_hinode *hdir; + + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); + + if (!(sb_flags & SB_RDONLY)) { + if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) + pr_warn("first branch should be rw\n"); + if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) + pr_warn_once("shwh should be used with ro\n"); + } + + if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) + && !au_opt_test(sbinfo->si_mntflags, XINO)) + pr_warn_once("udba=*notify requires xino\n"); + + if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) + pr_warn_once("dirperm1 breaks the protection" + " by the permission bits on the lower branch\n"); + + err = 0; + fhsm = 0; + root = sb->s_root; + dir = d_inode(root); + do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); + can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), + UDBA_NONE); + bbot = au_sbbot(sb); + for (bindex = 0; !err && bindex <= bbot; bindex++) { + skip = 0; + h_dir = au_h_iptr(dir, bindex); + br = au_sbr(sb, bindex); + + if ((br->br_perm & AuBrAttr_ICEX) + && !h_dir->i_op->listxattr) + br->br_perm &= ~AuBrAttr_ICEX; +#if 0 /* untested */ + if ((br->br_perm & AuBrAttr_ICEX_SEC) + && (au_br_sb(br)->s_flags & SB_NOSEC)) + br->br_perm &= ~AuBrAttr_ICEX_SEC; +#endif + + do_free = 0; + wbr = br->br_wbr; + if (wbr) + wbr_wh_read_lock(wbr); + + if (!au_br_writable(br->br_perm)) { + do_free = !!wbr; + skip = (!wbr + || (!wbr->wbr_whbase + && !wbr->wbr_plink + && !wbr->wbr_orph)); + } else if (!au_br_wh_linkable(br->br_perm)) { + /* skip = (!br->br_whbase && !br->br_orph); */ + skip = (!wbr || !wbr->wbr_whbase); + if (skip && wbr) { + if (do_plink) + skip = !!wbr->wbr_plink; + else + skip = !wbr->wbr_plink; + } + } else { + /* skip = (br->br_whbase && br->br_ohph); */ + skip = (wbr && wbr->wbr_whbase); + if (skip) { + if (do_plink) + skip = !!wbr->wbr_plink; + else + skip = !wbr->wbr_plink; + } + } + if (wbr) + wbr_wh_read_unlock(wbr); + + if (can_no_dreval) { + dentry = br->br_path.dentry; + spin_lock(&dentry->d_lock); + if (dentry->d_flags & + (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) + can_no_dreval = 0; + spin_unlock(&dentry->d_lock); + } + + if (au_br_fhsm(br->br_perm)) { + fhsm++; + AuDebugOn(!br->br_fhsm); + } + + if (skip) + continue; + + hdir = au_hi(dir, bindex); + au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); + if (wbr) + wbr_wh_write_lock(wbr); + err = au_wh_init(br, sb); + if (wbr) + wbr_wh_write_unlock(wbr); + au_hn_inode_unlock(hdir); + + if (!err && do_free) { + au_kfree_rcu(wbr); + br->br_wbr = NULL; + } + } + + if (can_no_dreval) + au_fset_si(sbinfo, NO_DREVAL); + else + au_fclr_si(sbinfo, NO_DREVAL); + + if (fhsm >= 2) { + au_fset_si(sbinfo, FHSM); + for (bindex = bbot; bindex >= 0; bindex--) { + br = au_sbr(sb, bindex); + if (au_br_fhsm(br->br_perm)) { + au_fhsm_set_bottom(sb, bindex); + break; + } + } + } else { + au_fclr_si(sbinfo, FHSM); + au_fhsm_set_bottom(sb, -1); + } + + return err; +} + +int au_opts_mount(struct super_block *sb, struct au_opts *opts) +{ + int err; + unsigned int tmp; + aufs_bindex_t bindex, bbot; + struct au_opt *opt; + struct au_opt_xino *opt_xino, xino; + struct au_sbinfo *sbinfo; + struct au_branch *br; + struct inode *dir; + + SiMustWriteLock(sb); + + err = 0; + opt_xino = NULL; + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) + err = au_opt_simple(sb, opt++, opts); + if (err > 0) + err = 0; + else if (unlikely(err < 0)) + goto out; + + /* disable xino and udba temporary */ + sbinfo = au_sbi(sb); + tmp = sbinfo->si_mntflags; + au_opt_clr(sbinfo->si_mntflags, XINO); + au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); + + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) + err = au_opt_br(sb, opt++, opts); + if (err > 0) + err = 0; + else if (unlikely(err < 0)) + goto out; + + bbot = au_sbbot(sb); + if (unlikely(bbot < 0)) { + err = -EINVAL; + pr_err("no branches\n"); + goto out; + } + + if (au_opt_test(tmp, XINO)) + au_opt_set(sbinfo->si_mntflags, XINO); + opt = opts->opt; + while (!err && opt->type != Opt_tail) + err = au_opt_xino(sb, opt++, &opt_xino, opts); + if (unlikely(err)) + goto out; + + err = au_opts_verify(sb, sb->s_flags, tmp); + if (unlikely(err)) + goto out; + + /* restore xino */ + if (au_opt_test(tmp, XINO) && !opt_xino) { + xino.file = au_xino_def(sb); + err = PTR_ERR(xino.file); + if (IS_ERR(xino.file)) + goto out; + + err = au_xino_set(sb, &xino, /*remount*/0); + fput(xino.file); + if (unlikely(err)) + goto out; + } + + /* restore udba */ + tmp &= AuOptMask_UDBA; + sbinfo->si_mntflags &= ~AuOptMask_UDBA; + sbinfo->si_mntflags |= tmp; + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + err = au_hnotify_reset_br(tmp, br, br->br_perm); + if (unlikely(err)) + AuIOErr("hnotify failed on br %d, %d, ignored\n", + bindex, err); + /* go on even if err */ + } + if (au_opt_test(tmp, UDBA_HNOTIFY)) { + dir = d_inode(sb->s_root); + au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); + } + +out: + return err; +} + +int au_opts_remount(struct super_block *sb, struct au_opts *opts) +{ + int err, rerr; + unsigned char no_dreval; + struct inode *dir; + struct au_opt_xino *opt_xino; + struct au_opt *opt; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + err = au_dr_opt_flush(sb); + if (unlikely(err)) + goto out; + au_fset_opts(opts->flags, DR_FLUSHED); + + dir = d_inode(sb->s_root); + sbinfo = au_sbi(sb); + opt_xino = NULL; + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) { + err = au_opt_simple(sb, opt, opts); + if (!err) + err = au_opt_br(sb, opt, opts); + if (!err) + err = au_opt_xino(sb, opt, &opt_xino, opts); + opt++; + } + if (err > 0) + err = 0; + AuTraceErr(err); + /* go on even err */ + + no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); + rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); + if (unlikely(rerr && !err)) + err = rerr; + + if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) + au_fset_opts(opts->flags, REFRESH_IDOP); + + if (au_ftest_opts(opts->flags, TRUNC_XIB)) { + rerr = au_xib_trunc(sb); + if (unlikely(rerr && !err)) + err = rerr; + } + + /* will be handled by the caller */ + if (!au_ftest_opts(opts->flags, REFRESH) + && (opts->given_udba + || au_opt_test(sbinfo->si_mntflags, XINO) + || au_ftest_opts(opts->flags, REFRESH_IDOP) + )) + au_fset_opts(opts->flags, REFRESH); + + AuDbg("status 0x%x\n", opts->flags); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +unsigned int au_opt_udba(struct super_block *sb) +{ + return au_mntflags(sb) & AuOptMask_UDBA; +} diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h new file mode 100644 index 000000000000..6326b54340c7 --- /dev/null +++ b/fs/aufs/opts.h @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * mount options/flags + */ + +#ifndef __AUFS_OPTS_H__ +#define __AUFS_OPTS_H__ + +#ifdef __KERNEL__ + +#include + +struct file; + +/* ---------------------------------------------------------------------- */ + +/* mount flags */ +#define AuOpt_XINO 1 /* external inode number bitmap + and translation table */ +#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ +#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ +#define AuOpt_UDBA_REVAL (1 << 3) +#define AuOpt_UDBA_HNOTIFY (1 << 4) +#define AuOpt_SHWH (1 << 5) /* show whiteout */ +#define AuOpt_PLINK (1 << 6) /* pseudo-link */ +#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm + bits */ +#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ +#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ +#define AuOpt_SUM_W (1 << 11) /* unimplemented */ +#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ +#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */ +#define AuOpt_DIO (1 << 14) /* direct io */ +#define AuOpt_DIRREN (1 << 15) /* directory rename */ + +#ifndef CONFIG_AUFS_HNOTIFY +#undef AuOpt_UDBA_HNOTIFY +#define AuOpt_UDBA_HNOTIFY 0 +#endif +#ifndef CONFIG_AUFS_DIRREN +#undef AuOpt_DIRREN +#define AuOpt_DIRREN 0 +#endif +#ifndef CONFIG_AUFS_SHWH +#undef AuOpt_SHWH +#define AuOpt_SHWH 0 +#endif + +#define AuOpt_Def (AuOpt_XINO \ + | AuOpt_UDBA_REVAL \ + | AuOpt_PLINK \ + /* | AuOpt_DIRPERM1 */ \ + | AuOpt_WARN_PERM) +#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ + | AuOpt_UDBA_REVAL \ + | AuOpt_UDBA_HNOTIFY) + +#define au_opt_test(flags, name) (flags & AuOpt_##name) +#define au_opt_set(flags, name) do { \ + BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ + ((flags) |= AuOpt_##name); \ +} while (0) +#define au_opt_set_udba(flags, name) do { \ + (flags) &= ~AuOptMask_UDBA; \ + ((flags) |= AuOpt_##name); \ +} while (0) +#define au_opt_clr(flags, name) do { \ + ((flags) &= ~AuOpt_##name); \ +} while (0) + +static inline unsigned int au_opts_plink(unsigned int mntflags) +{ +#ifdef CONFIG_PROC_FS + return mntflags; +#else + return mntflags & ~AuOpt_PLINK; +#endif +} + +/* ---------------------------------------------------------------------- */ + +/* policies to select one among multiple writable branches */ +enum { + AuWbrCreate_TDP, /* top down parent */ + AuWbrCreate_RR, /* round robin */ + AuWbrCreate_MFS, /* most free space */ + AuWbrCreate_MFSV, /* mfs with seconds */ + AuWbrCreate_MFSRR, /* mfs then rr */ + AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ + AuWbrCreate_TDMFS, /* top down regardless parent and mfs */ + AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ + AuWbrCreate_PMFS, /* parent and mfs */ + AuWbrCreate_PMFSV, /* parent and mfs with seconds */ + AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ + AuWbrCreate_PMFSRRV, /* plus seconds */ + + AuWbrCreate_Def = AuWbrCreate_TDP +}; + +enum { + AuWbrCopyup_TDP, /* top down parent */ + AuWbrCopyup_BUP, /* bottom up parent */ + AuWbrCopyup_BU, /* bottom up */ + + AuWbrCopyup_Def = AuWbrCopyup_TDP +}; + +/* ---------------------------------------------------------------------- */ + +struct au_opt_add { + aufs_bindex_t bindex; + char *pathname; + int perm; + struct path path; +}; + +struct au_opt_del { + char *pathname; + struct path h_path; +}; + +struct au_opt_mod { + char *path; + int perm; + struct dentry *h_root; +}; + +struct au_opt_xino { + char *path; + struct file *file; +}; + +struct au_opt_xino_itrunc { + aufs_bindex_t bindex; +}; + +struct au_opt_wbr_create { + int wbr_create; + int mfs_second; + unsigned long long mfsrr_watermark; +}; + +struct au_opt { + int type; + union { + struct au_opt_xino xino; + struct au_opt_xino_itrunc xino_itrunc; + struct au_opt_add add; + struct au_opt_del del; + struct au_opt_mod mod; + int dirwh; + int rdcache; + unsigned int rdblk; + unsigned int rdhash; + int udba; + struct au_opt_wbr_create wbr_create; + int wbr_copyup; + unsigned int fhsm_second; + }; +}; + +/* opts flags */ +#define AuOpts_REMOUNT 1 +#define AuOpts_REFRESH (1 << 1) +#define AuOpts_TRUNC_XIB (1 << 2) +#define AuOpts_REFRESH_DYAOP (1 << 3) +#define AuOpts_REFRESH_IDOP (1 << 4) +#define AuOpts_DR_FLUSHED (1 << 5) +#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) +#define au_fset_opts(flags, name) \ + do { (flags) |= AuOpts_##name; } while (0) +#define au_fclr_opts(flags, name) \ + do { (flags) &= ~AuOpts_##name; } while (0) + +#ifndef CONFIG_AUFS_DIRREN +#undef AuOpts_DR_FLUSHED +#define AuOpts_DR_FLUSHED 0 +#endif + +struct au_opts { + struct au_opt *opt; + int max_opt; + + unsigned int given_udba; + unsigned int flags; + unsigned long sb_flags; +}; + +/* ---------------------------------------------------------------------- */ + +/* opts.c */ +void au_optstr_br_perm(au_br_perm_str_t *str, int perm); +const char *au_optstr_udba(int udba); +const char *au_optstr_wbr_copyup(int wbr_copyup); +const char *au_optstr_wbr_create(int wbr_create); + +void au_opts_free(struct au_opts *opts); +struct super_block; +int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); +int au_opts_verify(struct super_block *sb, unsigned long sb_flags, + unsigned int pending); +int au_opts_mount(struct super_block *sb, struct au_opts *opts); +int au_opts_remount(struct super_block *sb, struct au_opts *opts); + +unsigned int au_opt_udba(struct super_block *sb); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_OPTS_H__ */ diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c new file mode 100644 index 000000000000..718edb8827a3 --- /dev/null +++ b/fs/aufs/plink.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * pseudo-link + */ + +#include "aufs.h" + +/* + * the pseudo-link maintenance mode. + * during a user process maintains the pseudo-links, + * prohibit adding a new plink and branch manipulation. + * + * Flags + * NOPLM: + * For entry functions which will handle plink, and i_mutex is already held + * in VFS. + * They cannot wait and should return an error at once. + * Callers has to check the error. + * NOPLMW: + * For entry functions which will handle plink, but i_mutex is not held + * in VFS. + * They can wait the plink maintenance mode to finish. + * + * They behave like F_SETLK and F_SETLKW. + * If the caller never handle plink, then both flags are unnecessary. + */ + +int au_plink_maint(struct super_block *sb, int flags) +{ + int err; + pid_t pid, ppid; + struct task_struct *parent, *prev; + struct au_sbinfo *sbi; + + SiMustAnyLock(sb); + + err = 0; + if (!au_opt_test(au_mntflags(sb), PLINK)) + goto out; + + sbi = au_sbi(sb); + pid = sbi->si_plink_maint_pid; + if (!pid || pid == current->pid) + goto out; + + /* todo: it highly depends upon /sbin/mount.aufs */ + prev = NULL; + parent = current; + ppid = 0; + rcu_read_lock(); + while (1) { + parent = rcu_dereference(parent->real_parent); + if (parent == prev) + break; + ppid = task_pid_vnr(parent); + if (pid == ppid) { + rcu_read_unlock(); + goto out; + } + prev = parent; + } + rcu_read_unlock(); + + if (au_ftest_lock(flags, NOPLMW)) { + /* if there is no i_mutex lock in VFS, we don't need to wait */ + /* AuDebugOn(!lockdep_depth(current)); */ + while (sbi->si_plink_maint_pid) { + si_read_unlock(sb); + /* gave up wake_up_bit() */ + wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); + + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&sbi->si_nowait); + si_noflush_read_lock(sb); + } + } else if (au_ftest_lock(flags, NOPLM)) { + AuDbg("ppid %d, pid %d\n", ppid, pid); + err = -EAGAIN; + } + +out: + return err; +} + +void au_plink_maint_leave(struct au_sbinfo *sbinfo) +{ + spin_lock(&sbinfo->si_plink_maint_lock); + sbinfo->si_plink_maint_pid = 0; + spin_unlock(&sbinfo->si_plink_maint_lock); + wake_up_all(&sbinfo->si_plink_wq); +} + +int au_plink_maint_enter(struct super_block *sb) +{ + int err; + struct au_sbinfo *sbinfo; + + err = 0; + sbinfo = au_sbi(sb); + /* make sure i am the only one in this fs */ + si_write_lock(sb, AuLock_FLUSH); + if (au_opt_test(au_mntflags(sb), PLINK)) { + spin_lock(&sbinfo->si_plink_maint_lock); + if (!sbinfo->si_plink_maint_pid) + sbinfo->si_plink_maint_pid = current->pid; + else + err = -EBUSY; + spin_unlock(&sbinfo->si_plink_maint_lock); + } + si_write_unlock(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_DEBUG +void au_plink_list(struct super_block *sb) +{ + int i; + struct au_sbinfo *sbinfo; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + struct au_icntnr *icntnr; + + SiMustAnyLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + for (i = 0; i < AuPlink_NHASH; i++) { + hbl = sbinfo->si_plink + i; + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(icntnr, pos, hbl, plink) + AuDbg("%lu\n", icntnr->vfs_inode.i_ino); + hlist_bl_unlock(hbl); + } +} +#endif + +/* is the inode pseudo-linked? */ +int au_plink_test(struct inode *inode) +{ + int found, i; + struct au_sbinfo *sbinfo; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + struct au_icntnr *icntnr; + + sbinfo = au_sbi(inode->i_sb); + AuRwMustAnyLock(&sbinfo->si_rwsem); + AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); + AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); + + found = 0; + i = au_plink_hash(inode->i_ino); + hbl = sbinfo->si_plink + i; + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(icntnr, pos, hbl, plink) + if (&icntnr->vfs_inode == inode) { + found = 1; + break; + } + hlist_bl_unlock(hbl); + return found; +} + +/* ---------------------------------------------------------------------- */ + +/* + * generate a name for plink. + * the file will be stored under AUFS_WH_PLINKDIR. + */ +/* 20 is max digits length of ulong 64 */ +#define PLINK_NAME_LEN ((20 + 1) * 2) + +static int plink_name(char *name, int len, struct inode *inode, + aufs_bindex_t bindex) +{ + int rlen; + struct inode *h_inode; + + h_inode = au_h_iptr(inode, bindex); + rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); + return rlen; +} + +struct au_do_plink_lkup_args { + struct dentry **errp; + struct qstr *tgtname; + struct dentry *h_parent; + struct au_branch *br; +}; + +static struct dentry *au_do_plink_lkup(struct qstr *tgtname, + struct dentry *h_parent, + struct au_branch *br) +{ + struct dentry *h_dentry; + struct inode *h_inode; + + h_inode = d_inode(h_parent); + inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); + h_dentry = vfsub_lkup_one(tgtname, h_parent); + inode_unlock_shared(h_inode); + return h_dentry; +} + +static void au_call_do_plink_lkup(void *args) +{ + struct au_do_plink_lkup_args *a = args; + *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br); +} + +/* lookup the plink-ed @inode under the branch at @bindex */ +struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) +{ + struct dentry *h_dentry, *h_parent; + struct au_branch *br; + int wkq_err; + char a[PLINK_NAME_LEN]; + struct qstr tgtname = QSTR_INIT(a, 0); + + AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); + + br = au_sbr(inode->i_sb, bindex); + h_parent = br->br_wbr->wbr_plink; + tgtname.len = plink_name(a, sizeof(a), inode, bindex); + + if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { + struct au_do_plink_lkup_args args = { + .errp = &h_dentry, + .tgtname = &tgtname, + .h_parent = h_parent, + .br = br + }; + + wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); + if (unlikely(wkq_err)) + h_dentry = ERR_PTR(wkq_err); + } else + h_dentry = au_do_plink_lkup(&tgtname, h_parent, br); + + return h_dentry; +} + +/* create a pseudo-link */ +static int do_whplink(struct qstr *tgt, struct dentry *h_parent, + struct dentry *h_dentry, struct au_branch *br) +{ + int err; + struct path h_path = { + .mnt = au_br_mnt(br) + }; + struct inode *h_dir, *delegated; + + h_dir = d_inode(h_parent); + inode_lock_nested(h_dir, AuLsc_I_CHILD2); +again: + h_path.dentry = vfsub_lkup_one(tgt, h_parent); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) + goto out; + + err = 0; + /* wh.plink dir is not monitored */ + /* todo: is it really safe? */ + if (d_is_positive(h_path.dentry) + && d_inode(h_path.dentry) != d_inode(h_dentry)) { + delegated = NULL; + err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + dput(h_path.dentry); + h_path.dentry = NULL; + if (!err) + goto again; + } + if (!err && d_is_negative(h_path.dentry)) { + delegated = NULL; + err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + } + dput(h_path.dentry); + +out: + inode_unlock(h_dir); + return err; +} + +struct do_whplink_args { + int *errp; + struct qstr *tgt; + struct dentry *h_parent; + struct dentry *h_dentry; + struct au_branch *br; +}; + +static void call_do_whplink(void *args) +{ + struct do_whplink_args *a = args; + *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); +} + +static int whplink(struct dentry *h_dentry, struct inode *inode, + aufs_bindex_t bindex, struct au_branch *br) +{ + int err, wkq_err; + struct au_wbr *wbr; + struct dentry *h_parent; + char a[PLINK_NAME_LEN]; + struct qstr tgtname = QSTR_INIT(a, 0); + + wbr = au_sbr(inode->i_sb, bindex)->br_wbr; + h_parent = wbr->wbr_plink; + tgtname.len = plink_name(a, sizeof(a), inode, bindex); + + /* always superio. */ + if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { + struct do_whplink_args args = { + .errp = &err, + .tgt = &tgtname, + .h_parent = h_parent, + .h_dentry = h_dentry, + .br = br + }; + wkq_err = au_wkq_wait(call_do_whplink, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } else + err = do_whplink(&tgtname, h_parent, h_dentry, br); + + return err; +} + +/* + * create a new pseudo-link for @h_dentry on @bindex. + * the linked inode is held in aufs @inode. + */ +void au_plink_append(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_dentry) +{ + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + struct au_icntnr *icntnr; + int found, err, cnt, i; + + sb = inode->i_sb; + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + found = au_plink_test(inode); + if (found) + return; + + i = au_plink_hash(inode->i_ino); + hbl = sbinfo->si_plink + i; + au_igrab(inode); + + hlist_bl_lock(hbl); + hlist_bl_for_each_entry(icntnr, pos, hbl, plink) { + if (&icntnr->vfs_inode == inode) { + found = 1; + break; + } + } + if (!found) { + icntnr = container_of(inode, struct au_icntnr, vfs_inode); + hlist_bl_add_head(&icntnr->plink, hbl); + } + hlist_bl_unlock(hbl); + if (!found) { + cnt = au_hbl_count(hbl); +#define msg "unexpectedly unbalanced or too many pseudo-links" + if (cnt > AUFS_PLINK_WARN) + AuWarn1(msg ", %d\n", cnt); +#undef msg + err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); + if (unlikely(err)) { + pr_warn("err %d, damaged pseudo link.\n", err); + au_hbl_del(&icntnr->plink, hbl); + iput(&icntnr->vfs_inode); + } + } else + iput(&icntnr->vfs_inode); +} + +/* free all plinks */ +void au_plink_put(struct super_block *sb, int verbose) +{ + int i, warned; + struct au_sbinfo *sbinfo; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos, *tmp; + struct au_icntnr *icntnr; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + /* no spin_lock since sbinfo is write-locked */ + warned = 0; + for (i = 0; i < AuPlink_NHASH; i++) { + hbl = sbinfo->si_plink + i; + if (!warned && verbose && !hlist_bl_empty(hbl)) { + pr_warn("pseudo-link is not flushed"); + warned = 1; + } + hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) + iput(&icntnr->vfs_inode); + INIT_HLIST_BL_HEAD(hbl); + } +} + +void au_plink_clean(struct super_block *sb, int verbose) +{ + struct dentry *root; + + root = sb->s_root; + aufs_write_lock(root); + if (au_opt_test(au_mntflags(sb), PLINK)) + au_plink_put(sb, verbose); + aufs_write_unlock(root); +} + +static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) +{ + int do_put; + aufs_bindex_t btop, bbot, bindex; + + do_put = 0; + btop = au_ibtop(inode); + bbot = au_ibbot(inode); + if (btop >= 0) { + for (bindex = btop; bindex <= bbot; bindex++) { + if (!au_h_iptr(inode, bindex) + || au_ii_br_id(inode, bindex) != br_id) + continue; + au_set_h_iptr(inode, bindex, NULL, 0); + do_put = 1; + break; + } + if (do_put) + for (bindex = btop; bindex <= bbot; bindex++) + if (au_h_iptr(inode, bindex)) { + do_put = 0; + break; + } + } else + do_put = 1; + + return do_put; +} + +/* free the plinks on a branch specified by @br_id */ +void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) +{ + struct au_sbinfo *sbinfo; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos, *tmp; + struct au_icntnr *icntnr; + struct inode *inode; + int i, do_put; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); + + /* no bit_lock since sbinfo is write-locked */ + for (i = 0; i < AuPlink_NHASH; i++) { + hbl = sbinfo->si_plink + i; + hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) { + inode = au_igrab(&icntnr->vfs_inode); + ii_write_lock_child(inode); + do_put = au_plink_do_half_refresh(inode, br_id); + if (do_put) { + hlist_bl_del(&icntnr->plink); + iput(inode); + } + ii_write_unlock(inode); + iput(inode); + } + } +} diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c new file mode 100644 index 000000000000..c48c6cb6491f --- /dev/null +++ b/fs/aufs/poll.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * poll operation + * There is only one filesystem which implements ->poll operation, currently. + */ + +#include "aufs.h" + +__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) +{ + __poll_t mask; + struct file *h_file; + struct super_block *sb; + + /* We should pretend an error happened. */ + mask = EPOLLERR /* | EPOLLIN | EPOLLOUT */; + sb = file->f_path.dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + + h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); + if (IS_ERR(h_file)) { + AuDbg("h_file %ld\n", PTR_ERR(h_file)); + goto out; + } + + mask = vfs_poll(h_file, pt); + fput(h_file); /* instead of au_read_post() */ + +out: + si_read_unlock(sb); + if (mask & EPOLLERR) + AuDbg("mask 0x%x\n", mask); + return mask; +} diff --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c new file mode 100644 index 000000000000..3c8f9a222ed8 --- /dev/null +++ b/fs/aufs/posix_acl.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2014-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * posix acl operations + */ + +#include +#include "aufs.h" + +struct posix_acl *aufs_get_acl(struct inode *inode, int type) +{ + struct posix_acl *acl; + int err; + aufs_bindex_t bindex; + struct inode *h_inode; + struct super_block *sb; + + acl = NULL; + sb = inode->i_sb; + si_read_lock(sb, AuLock_FLUSH); + ii_read_lock_child(inode); + if (!(sb->s_flags & SB_POSIXACL)) + goto out; + + bindex = au_ibtop(inode); + h_inode = au_h_iptr(inode, bindex); + if (unlikely(!h_inode + || ((h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT)))) { + err = au_busy_or_stale(); + acl = ERR_PTR(err); + goto out; + } + + /* always topmost only */ + acl = get_acl(h_inode, type); + if (IS_ERR(acl)) + forget_cached_acl(inode, type); + else + set_cached_acl(inode, type, acl); + +out: + ii_read_unlock(inode); + si_read_unlock(sb); + + AuTraceErrPtr(acl); + return acl; +} + +int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type) +{ + int err; + ssize_t ssz; + struct dentry *dentry; + struct au_sxattr arg = { + .type = AU_ACL_SET, + .u.acl_set = { + .acl = acl, + .type = type + }, + }; + + IMustLock(inode); + + if (inode->i_ino == AUFS_ROOT_INO) + dentry = dget(inode->i_sb->s_root); + else { + dentry = d_find_alias(inode); + if (!dentry) + dentry = d_find_any_alias(inode); + if (!dentry) { + pr_warn("cannot handle this inode, " + "please report to aufs-users ML\n"); + err = -ENOENT; + goto out; + } + } + + ssz = au_sxattr(dentry, inode, &arg); + /* forget even it if succeeds since the branch might set differently */ + forget_cached_acl(inode, type); + dput(dentry); + err = ssz; + if (ssz >= 0) + err = 0; + +out: + return err; +} diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c new file mode 100644 index 000000000000..eeb4c357bd79 --- /dev/null +++ b/fs/aufs/procfs.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2010-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * procfs interfaces + */ + +#include +#include "aufs.h" + +static int au_procfs_plm_release(struct inode *inode, struct file *file) +{ + struct au_sbinfo *sbinfo; + + sbinfo = file->private_data; + if (sbinfo) { + au_plink_maint_leave(sbinfo); + kobject_put(&sbinfo->si_kobj); + } + + return 0; +} + +static void au_procfs_plm_write_clean(struct file *file) +{ + struct au_sbinfo *sbinfo; + + sbinfo = file->private_data; + if (sbinfo) + au_plink_clean(sbinfo->si_sb, /*verbose*/0); +} + +static int au_procfs_plm_write_si(struct file *file, unsigned long id) +{ + int err; + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct hlist_bl_node *pos; + + err = -EBUSY; + if (unlikely(file->private_data)) + goto out; + + sb = NULL; + /* don't use au_sbilist_lock() here */ + hlist_bl_lock(&au_sbilist); + hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) + if (id == sysaufs_si_id(sbinfo)) { + if (kobject_get_unless_zero(&sbinfo->si_kobj)) + sb = sbinfo->si_sb; + break; + } + hlist_bl_unlock(&au_sbilist); + + err = -EINVAL; + if (unlikely(!sb)) + goto out; + + err = au_plink_maint_enter(sb); + if (!err) + /* keep kobject_get() */ + file->private_data = sbinfo; + else + kobject_put(&sbinfo->si_kobj); +out: + return err; +} + +/* + * Accept a valid "si=xxxx" only. + * Once it is accepted successfully, accept "clean" too. + */ +static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t err; + unsigned long id; + /* last newline is allowed */ + char buf[3 + sizeof(unsigned long) * 2 + 1]; + + err = -EACCES; + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + + err = -EINVAL; + if (unlikely(count > sizeof(buf))) + goto out; + + err = copy_from_user(buf, ubuf, count); + if (unlikely(err)) { + err = -EFAULT; + goto out; + } + buf[count] = 0; + + err = -EINVAL; + if (!strcmp("clean", buf)) { + au_procfs_plm_write_clean(file); + goto out_success; + } else if (unlikely(strncmp("si=", buf, 3))) + goto out; + + err = kstrtoul(buf + 3, 16, &id); + if (unlikely(err)) + goto out; + + err = au_procfs_plm_write_si(file, id); + if (unlikely(err)) + goto out; + +out_success: + err = count; /* success */ +out: + return err; +} + +static const struct proc_ops au_procfs_plm_op = { + .proc_write = au_procfs_plm_write, + .proc_release = au_procfs_plm_release +}; + +/* ---------------------------------------------------------------------- */ + +static struct proc_dir_entry *au_procfs_dir; + +void au_procfs_fin(void) +{ + remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); + remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); +} + +int __init au_procfs_init(void) +{ + int err; + struct proc_dir_entry *entry; + + err = -ENOMEM; + au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); + if (unlikely(!au_procfs_dir)) + goto out; + + entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | 0200, + au_procfs_dir, &au_procfs_plm_op); + if (unlikely(!entry)) + goto out_dir; + + err = 0; + goto out; /* success */ + + +out_dir: + remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); +out: + return err; +} diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c new file mode 100644 index 000000000000..3805e79627eb --- /dev/null +++ b/fs/aufs/rdu.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * readdir in userspace. + */ + +#include +#include +#include +#include "aufs.h" + +/* bits for struct aufs_rdu.flags */ +#define AuRdu_CALLED 1 +#define AuRdu_CONT (1 << 1) +#define AuRdu_FULL (1 << 2) +#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) +#define au_fset_rdu(flags, name) \ + do { (flags) |= AuRdu_##name; } while (0) +#define au_fclr_rdu(flags, name) \ + do { (flags) &= ~AuRdu_##name; } while (0) + +struct au_rdu_arg { + struct dir_context ctx; + struct aufs_rdu *rdu; + union au_rdu_ent_ul ent; + unsigned long end; + + struct super_block *sb; + int err; +}; + +static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, + loff_t offset, u64 h_ino, unsigned int d_type) +{ + int err, len; + struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); + struct aufs_rdu *rdu = arg->rdu; + struct au_rdu_ent ent; + + err = 0; + arg->err = 0; + au_fset_rdu(rdu->cookie.flags, CALLED); + len = au_rdu_len(nlen); + if (arg->ent.ul + len < arg->end) { + ent.ino = h_ino; + ent.bindex = rdu->cookie.bindex; + ent.type = d_type; + ent.nlen = nlen; + if (unlikely(nlen > AUFS_MAX_NAMELEN)) + ent.type = DT_UNKNOWN; + + /* unnecessary to support mmap_sem since this is a dir */ + err = -EFAULT; + if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) + goto out; + if (copy_to_user(arg->ent.e->name, name, nlen)) + goto out; + /* the terminating NULL */ + if (__put_user(0, arg->ent.e->name + nlen)) + goto out; + err = 0; + /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ + arg->ent.ul += len; + rdu->rent++; + } else { + err = -EFAULT; + au_fset_rdu(rdu->cookie.flags, FULL); + rdu->full = 1; + rdu->tail = arg->ent; + } + +out: + /* AuTraceErr(err); */ + return err; +} + +static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) +{ + int err; + loff_t offset; + struct au_rdu_cookie *cookie = &arg->rdu->cookie; + + /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ + offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); + err = offset; + if (unlikely(offset != cookie->h_pos)) + goto out; + + err = 0; + do { + arg->err = 0; + au_fclr_rdu(cookie->flags, CALLED); + /* smp_mb(); */ + err = vfsub_iterate_dir(h_file, &arg->ctx); + if (err >= 0) + err = arg->err; + } while (!err + && au_ftest_rdu(cookie->flags, CALLED) + && !au_ftest_rdu(cookie->flags, FULL)); + cookie->h_pos = h_file->f_pos; + +out: + AuTraceErr(err); + return err; +} + +static int au_rdu(struct file *file, struct aufs_rdu *rdu) +{ + int err; + aufs_bindex_t bbot; + struct au_rdu_arg arg = { + .ctx = { + .actor = au_rdu_fill + } + }; + struct dentry *dentry; + struct inode *inode; + struct file *h_file; + struct au_rdu_cookie *cookie = &rdu->cookie; + + /* VERIFY_WRITE */ + err = !access_ok(rdu->ent.e, rdu->sz); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + rdu->rent = 0; + rdu->tail = rdu->ent; + rdu->full = 0; + arg.rdu = rdu; + arg.ent = rdu->ent; + arg.end = arg.ent.ul; + arg.end += rdu->sz; + + err = -ENOTDIR; + if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) + goto out; + + err = security_file_permission(file, MAY_READ); + AuTraceErr(err); + if (unlikely(err)) + goto out; + + dentry = file->f_path.dentry; + inode = d_inode(dentry); + inode_lock_shared(inode); + + arg.sb = inode->i_sb; + err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_mtx; + err = au_alive_dir(dentry); + if (unlikely(err)) + goto out_si; + /* todo: reval? */ + fi_read_lock(file); + + err = -EAGAIN; + if (unlikely(au_ftest_rdu(cookie->flags, CONT) + && cookie->generation != au_figen(file))) + goto out_unlock; + + err = 0; + if (!rdu->blk) { + rdu->blk = au_sbi(arg.sb)->si_rdblk; + if (!rdu->blk) + rdu->blk = au_dir_size(file, /*dentry*/NULL); + } + bbot = au_fbtop(file); + if (cookie->bindex < bbot) + cookie->bindex = bbot; + bbot = au_fbbot_dir(file); + /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ + for (; !err && cookie->bindex <= bbot; + cookie->bindex++, cookie->h_pos = 0) { + h_file = au_hf_dir(file, cookie->bindex); + if (!h_file) + continue; + + au_fclr_rdu(cookie->flags, FULL); + err = au_rdu_do(h_file, &arg); + AuTraceErr(err); + if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) + break; + } + AuDbg("rent %llu\n", rdu->rent); + + if (!err && !au_ftest_rdu(cookie->flags, CONT)) { + rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); + au_fset_rdu(cookie->flags, CONT); + cookie->generation = au_figen(file); + } + + ii_read_lock_child(inode); + fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); + ii_read_unlock(inode); + +out_unlock: + fi_read_unlock(file); +out_si: + si_read_unlock(arg.sb); +out_mtx: + inode_unlock_shared(inode); +out: + AuTraceErr(err); + return err; +} + +static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) +{ + int err; + ino_t ino; + unsigned long long nent; + union au_rdu_ent_ul *u; + struct au_rdu_ent ent; + struct super_block *sb; + + err = 0; + nent = rdu->nent; + u = &rdu->ent; + sb = file->f_path.dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + while (nent-- > 0) { + /* unnecessary to support mmap_sem since this is a dir */ + err = copy_from_user(&ent, u->e, sizeof(ent)); + if (!err) + /* VERIFY_WRITE */ + err = !access_ok(&u->e->ino, sizeof(ino)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + break; + } + + /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ + if (!ent.wh) + err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); + else + err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, + &ino); + if (unlikely(err)) { + AuTraceErr(err); + break; + } + + err = __put_user(ino, &u->e->ino); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + break; + } + u->ul += au_rdu_len(ent.nlen); + } + si_read_unlock(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_rdu_verify(struct aufs_rdu *rdu) +{ + AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " + "%llu, b%d, 0x%x, g%u}\n", + rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], + rdu->blk, + rdu->rent, rdu->shwh, rdu->full, + rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, + rdu->cookie.generation); + + if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) + return 0; + + AuDbg("%u:%u\n", + rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); + return -EINVAL; +} + +long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err, e; + struct aufs_rdu rdu; + void __user *p = (void __user *)arg; + + err = copy_from_user(&rdu, p, sizeof(rdu)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + err = au_rdu_verify(&rdu); + if (unlikely(err)) + goto out; + + switch (cmd) { + case AUFS_CTL_RDU: + err = au_rdu(file, &rdu); + if (unlikely(err)) + break; + + e = copy_to_user(p, &rdu, sizeof(rdu)); + if (unlikely(e)) { + err = -EFAULT; + AuTraceErr(err); + } + break; + case AUFS_CTL_RDU_INO: + err = au_rdu_ino(file, &rdu); + break; + + default: + /* err = -ENOTTY; */ + err = -EINVAL; + } + +out: + AuTraceErr(err); + return err; +} + +#ifdef CONFIG_COMPAT +long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err, e; + struct aufs_rdu rdu; + void __user *p = compat_ptr(arg); + + /* todo: get_user()? */ + err = copy_from_user(&rdu, p, sizeof(rdu)); + if (unlikely(err)) { + err = -EFAULT; + AuTraceErr(err); + goto out; + } + rdu.ent.e = compat_ptr(rdu.ent.ul); + err = au_rdu_verify(&rdu); + if (unlikely(err)) + goto out; + + switch (cmd) { + case AUFS_CTL_RDU: + err = au_rdu(file, &rdu); + if (unlikely(err)) + break; + + rdu.ent.ul = ptr_to_compat(rdu.ent.e); + rdu.tail.ul = ptr_to_compat(rdu.tail.e); + e = copy_to_user(p, &rdu, sizeof(rdu)); + if (unlikely(e)) { + err = -EFAULT; + AuTraceErr(err); + } + break; + case AUFS_CTL_RDU_INO: + err = au_rdu_ino(file, &rdu); + break; + + default: + /* err = -ENOTTY; */ + err = -EINVAL; + } + +out: + AuTraceErr(err); + return err; +} +#endif diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h new file mode 100644 index 000000000000..4264dfd9fba1 --- /dev/null +++ b/fs/aufs/rwsem.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * simple read-write semaphore wrappers + */ + +#ifndef __AUFS_RWSEM_H__ +#define __AUFS_RWSEM_H__ + +#ifdef __KERNEL__ + +#include "debug.h" + +/* in the future, the name 'au_rwsem' will be totally gone */ +#define au_rwsem rw_semaphore + +/* to debug easier, do not make them inlined functions */ +#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) +/* rwsem_is_locked() is unusable */ +#define AuRwMustReadLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ + && !lockdep_recursing(current) \ + && debug_locks \ + && !lockdep_is_held_type(rw, 1)) +#define AuRwMustWriteLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ + && !lockdep_recursing(current) \ + && debug_locks \ + && !lockdep_is_held_type(rw, 0)) +#define AuRwMustAnyLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ + && !lockdep_recursing(current) \ + && debug_locks \ + && !lockdep_is_held(rw)) +#define AuRwDestroy(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ + && !lockdep_recursing(current) \ + && debug_locks \ + && lockdep_is_held(rw)) + +#define au_rw_init(rw) init_rwsem(rw) + +#define au_rw_init_wlock(rw) do { \ + au_rw_init(rw); \ + down_write(rw); \ + } while (0) + +#define au_rw_init_wlock_nested(rw, lsc) do { \ + au_rw_init(rw); \ + down_write_nested(rw, lsc); \ + } while (0) + +#define au_rw_read_lock(rw) down_read(rw) +#define au_rw_read_lock_nested(rw, lsc) down_read_nested(rw, lsc) +#define au_rw_read_unlock(rw) up_read(rw) +#define au_rw_dgrade_lock(rw) downgrade_write(rw) +#define au_rw_write_lock(rw) down_write(rw) +#define au_rw_write_lock_nested(rw, lsc) down_write_nested(rw, lsc) +#define au_rw_write_unlock(rw) up_write(rw) +/* why is not _nested version defined? */ +#define au_rw_read_trylock(rw) down_read_trylock(rw) +#define au_rw_write_trylock(rw) down_write_trylock(rw) + +#endif /* __KERNEL__ */ +#endif /* __AUFS_RWSEM_H__ */ diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c new file mode 100644 index 000000000000..500a920b4ea1 --- /dev/null +++ b/fs/aufs/sbinfo.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * superblock private data + */ + +#include +#include "aufs.h" + +/* + * they are necessary regardless sysfs is disabled. + */ +void au_si_free(struct kobject *kobj) +{ + int i; + struct au_sbinfo *sbinfo; + char *locked __maybe_unused; /* debug only */ + + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + for (i = 0; i < AuPlink_NHASH; i++) + AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); + AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); + + AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); + au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); + AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); + au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); + + dbgaufs_si_fin(sbinfo); + au_rw_write_lock(&sbinfo->si_rwsem); + au_br_free(sbinfo); + au_rw_write_unlock(&sbinfo->si_rwsem); + + au_kfree_try_rcu(sbinfo->si_branch); + mutex_destroy(&sbinfo->si_xib_mtx); + AuRwDestroy(&sbinfo->si_rwsem); + + au_lcnt_wait_for_fin(&sbinfo->si_ninodes); + /* si_nfiles is waited too */ + au_kfree_rcu(sbinfo); +} + +int au_si_alloc(struct super_block *sb) +{ + int err, i; + struct au_sbinfo *sbinfo; + + err = -ENOMEM; + sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); + if (unlikely(!sbinfo)) + goto out; + + /* will be reallocated separately */ + sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); + if (unlikely(!sbinfo->si_branch)) + goto out_sbinfo; + + err = sysaufs_si_init(sbinfo); + if (!err) { + dbgaufs_si_null(sbinfo); + err = dbgaufs_si_init(sbinfo); + if (unlikely(err)) + kobject_put(&sbinfo->si_kobj); + } + if (unlikely(err)) + goto out_br; + + au_nwt_init(&sbinfo->si_nowait); + au_rw_init_wlock(&sbinfo->si_rwsem); + + au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); + au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); + + sbinfo->si_bbot = -1; + sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; + + sbinfo->si_wbr_copyup = AuWbrCopyup_Def; + sbinfo->si_wbr_create = AuWbrCreate_Def; + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; + sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; + + au_fhsm_init(sbinfo); + + sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); + + sbinfo->si_xino_jiffy = jiffies; + sbinfo->si_xino_expire + = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); + mutex_init(&sbinfo->si_xib_mtx); + /* leave si_xib_last_pindex and si_xib_next_bit */ + + INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); + + sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); + sbinfo->si_rdblk = AUFS_RDBLK_DEF; + sbinfo->si_rdhash = AUFS_RDHASH_DEF; + sbinfo->si_dirwh = AUFS_DIRWH_DEF; + + for (i = 0; i < AuPlink_NHASH; i++) + INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); + init_waitqueue_head(&sbinfo->si_plink_wq); + spin_lock_init(&sbinfo->si_plink_maint_lock); + + INIT_HLIST_BL_HEAD(&sbinfo->si_files); + + /* with getattr by default */ + sbinfo->si_iop_array = aufs_iop; + + /* leave other members for sysaufs and si_mnt. */ + sbinfo->si_sb = sb; + sb->s_fs_info = sbinfo; + si_pid_set(sb); + return 0; /* success */ + +out_br: + au_kfree_try_rcu(sbinfo->si_branch); +out_sbinfo: + au_kfree_rcu(sbinfo); +out: + return err; +} + +int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) +{ + int err, sz; + struct au_branch **brp; + + AuRwMustWriteLock(&sbinfo->si_rwsem); + + err = -ENOMEM; + sz = sizeof(*brp) * (sbinfo->si_bbot + 1); + if (unlikely(!sz)) + sz = sizeof(*brp); + brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, + may_shrink); + if (brp) { + sbinfo->si_branch = brp; + err = 0; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +unsigned int au_sigen_inc(struct super_block *sb) +{ + unsigned int gen; + struct inode *inode; + + SiMustWriteLock(sb); + + gen = ++au_sbi(sb)->si_generation; + au_update_digen(sb->s_root); + inode = d_inode(sb->s_root); + au_update_iigen(inode, /*half*/0); + inode_inc_iversion(inode); + return gen; +} + +aufs_bindex_t au_new_br_id(struct super_block *sb) +{ + aufs_bindex_t br_id; + int i; + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + for (i = 0; i <= AUFS_BRANCH_MAX; i++) { + br_id = ++sbinfo->si_last_br_id; + AuDebugOn(br_id < 0); + if (br_id && au_br_index(sb, br_id) < 0) + return br_id; + } + + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* it is ok that new 'nwt' tasks are appended while we are sleeping */ +int si_read_lock(struct super_block *sb, int flags) +{ + int err; + + err = 0; + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + + si_noflush_read_lock(sb); + err = au_plink_maint(sb, flags); + if (unlikely(err)) + si_read_unlock(sb); + + return err; +} + +int si_write_lock(struct super_block *sb, int flags) +{ + int err; + + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + + si_noflush_write_lock(sb); + err = au_plink_maint(sb, flags); + if (unlikely(err)) + si_write_unlock(sb); + + return err; +} + +/* dentry and super_block lock. call at entry point */ +int aufs_read_lock(struct dentry *dentry, int flags) +{ + int err; + struct super_block *sb; + + sb = dentry->d_sb; + err = si_read_lock(sb, flags); + if (unlikely(err)) + goto out; + + if (au_ftest_lock(flags, DW)) + di_write_lock_child(dentry); + else + di_read_lock_child(dentry, flags); + + if (au_ftest_lock(flags, GEN)) { + err = au_digen_test(dentry, au_sigen(sb)); + if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) + AuDebugOn(!err && au_dbrange_test(dentry)); + else if (!err) + err = au_dbrange_test(dentry); + if (unlikely(err)) + aufs_read_unlock(dentry, flags); + } + +out: + return err; +} + +void aufs_read_unlock(struct dentry *dentry, int flags) +{ + if (au_ftest_lock(flags, DW)) + di_write_unlock(dentry); + else + di_read_unlock(dentry, flags); + si_read_unlock(dentry->d_sb); +} + +void aufs_write_lock(struct dentry *dentry) +{ + si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); + di_write_lock_child(dentry); +} + +void aufs_write_unlock(struct dentry *dentry) +{ + di_write_unlock(dentry); + si_write_unlock(dentry->d_sb); +} + +int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) +{ + int err; + unsigned int sigen; + struct super_block *sb; + + sb = d1->d_sb; + err = si_read_lock(sb, flags); + if (unlikely(err)) + goto out; + + di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); + + if (au_ftest_lock(flags, GEN)) { + sigen = au_sigen(sb); + err = au_digen_test(d1, sigen); + AuDebugOn(!err && au_dbrange_test(d1)); + if (!err) { + err = au_digen_test(d2, sigen); + AuDebugOn(!err && au_dbrange_test(d2)); + } + if (unlikely(err)) + aufs_read_and_write_unlock2(d1, d2); + } + +out: + return err; +} + +void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) +{ + di_write_unlock2(d1, d2); + si_read_unlock(d1->d_sb); +} diff --git a/fs/aufs/super.c b/fs/aufs/super.c new file mode 100644 index 000000000000..dce010d656df --- /dev/null +++ b/fs/aufs/super.c @@ -0,0 +1,1047 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * mount and super_block operations + */ + +#include +#include +#include +#include +#include +#include "aufs.h" + +/* + * super_operations + */ +static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) +{ + struct au_icntnr *c; + + c = au_cache_alloc_icntnr(); + if (c) { + au_icntnr_init(c); + inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ + c->iinfo.ii_hinode = NULL; + return &c->vfs_inode; + } + return NULL; +} + +static void aufs_destroy_inode(struct inode *inode) +{ + if (!au_is_bad_inode(inode)) + au_iinfo_fin(inode); +} + +static void aufs_free_inode(struct inode *inode) +{ + au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); +} + +struct inode *au_iget_locked(struct super_block *sb, ino_t ino) +{ + struct inode *inode; + int err; + + inode = iget_locked(sb, ino); + if (unlikely(!inode)) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + if (!(inode->i_state & I_NEW)) + goto out; + + err = au_xigen_new(inode); + if (!err) + err = au_iinfo_init(inode); + if (!err) + inode_inc_iversion(inode); + else { + iget_failed(inode); + inode = ERR_PTR(err); + } + +out: + /* never return NULL */ + AuDebugOn(!inode); + AuTraceErrPtr(inode); + return inode; +} + +/* lock free root dinfo */ +static int au_show_brs(struct seq_file *seq, struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bbot; + struct path path; + struct au_hdentry *hdp; + struct au_branch *br; + au_br_perm_str_t perm; + + err = 0; + bbot = au_sbbot(sb); + bindex = 0; + hdp = au_hdentry(au_di(sb->s_root), bindex); + for (; !err && bindex <= bbot; bindex++, hdp++) { + br = au_sbr(sb, bindex); + path.mnt = au_br_mnt(br); + path.dentry = hdp->hd_dentry; + err = au_seq_path(seq, &path); + if (!err) { + au_optstr_br_perm(&perm, br->br_perm); + seq_printf(seq, "=%s", perm.a); + if (bindex != bbot) + seq_putc(seq, ':'); + } + } + if (unlikely(err || seq_has_overflowed(seq))) + err = -E2BIG; + + return err; +} + +static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, + const char *append) +{ + char *p; + + p = fmt; + while (*pat != ':') + *p++ = *pat++; + *p++ = *pat++; + strcpy(p, append); + AuDebugOn(strlen(fmt) >= len); +} + +static void au_show_wbr_create(struct seq_file *m, int v, + struct au_sbinfo *sbinfo) +{ + const char *pat; + char fmt[32]; + struct au_wbr_mfs *mfs; + + AuRwMustAnyLock(&sbinfo->si_rwsem); + + seq_puts(m, ",create="); + pat = au_optstr_wbr_create(v); + mfs = &sbinfo->si_wbr_mfs; + switch (v) { + case AuWbrCreate_TDP: + case AuWbrCreate_RR: + case AuWbrCreate_MFS: + case AuWbrCreate_PMFS: + seq_puts(m, pat); + break; + case AuWbrCreate_MFSRR: + case AuWbrCreate_TDMFS: + case AuWbrCreate_PMFSRR: + au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); + seq_printf(m, fmt, mfs->mfsrr_watermark); + break; + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); + seq_printf(m, fmt, + jiffies_to_msecs(mfs->mfs_expire) + / MSEC_PER_SEC); + break; + case AuWbrCreate_MFSRRV: + case AuWbrCreate_TDMFSV: + case AuWbrCreate_PMFSRRV: + au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); + seq_printf(m, fmt, mfs->mfsrr_watermark, + jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); + break; + default: + BUG(); + } +} + +static int au_show_xino(struct seq_file *seq, struct super_block *sb) +{ +#ifdef CONFIG_SYSFS + return 0; +#else + int err; + const int len = sizeof(AUFS_XINO_FNAME) - 1; + aufs_bindex_t bindex, brid; + struct qstr *name; + struct file *f; + struct dentry *d, *h_root; + struct au_branch *br; + + AuRwMustAnyLock(&sbinfo->si_rwsem); + + err = 0; + f = au_sbi(sb)->si_xib; + if (!f) + goto out; + + /* stop printing the default xino path on the first writable branch */ + h_root = NULL; + bindex = au_xi_root(sb, f->f_path.dentry); + if (bindex >= 0) { + br = au_sbr_sb(sb, bindex); + h_root = au_br_dentry(br); + } + + d = f->f_path.dentry; + name = &d->d_name; + /* safe ->d_parent because the file is unlinked */ + if (d->d_parent == h_root + && name->len == len + && !memcmp(name->name, AUFS_XINO_FNAME, len)) + goto out; + + seq_puts(seq, ",xino="); + err = au_xino_path(seq, f); + +out: + return err; +#endif +} + +/* seq_file will re-call me in case of too long string */ +static int aufs_show_options(struct seq_file *m, struct dentry *dentry) +{ + int err; + unsigned int mnt_flags, v; + struct super_block *sb; + struct au_sbinfo *sbinfo; + +#define AuBool(name, str) do { \ + v = au_opt_test(mnt_flags, name); \ + if (v != au_opt_test(AuOpt_Def, name)) \ + seq_printf(m, ",%s" #str, v ? "" : "no"); \ +} while (0) + +#define AuStr(name, str) do { \ + v = mnt_flags & AuOptMask_##name; \ + if (v != (AuOpt_Def & AuOptMask_##name)) \ + seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ +} while (0) + +#define AuUInt(name, str, val) do { \ + if (val != AUFS_##name##_DEF) \ + seq_printf(m, "," #str "=%u", val); \ +} while (0) + + sb = dentry->d_sb; + if (sb->s_flags & SB_POSIXACL) + seq_puts(m, ",acl"); +#if 0 /* reserved for future use */ + if (sb->s_flags & SB_I_VERSION) + seq_puts(m, ",i_version"); +#endif + + /* lock free root dinfo */ + si_noflush_read_lock(sb); + sbinfo = au_sbi(sb); + seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); + + mnt_flags = au_mntflags(sb); + if (au_opt_test(mnt_flags, XINO)) { + err = au_show_xino(m, sb); + if (unlikely(err)) + goto out; + } else + seq_puts(m, ",noxino"); + + AuBool(TRUNC_XINO, trunc_xino); + AuStr(UDBA, udba); + AuBool(SHWH, shwh); + AuBool(PLINK, plink); + AuBool(DIO, dio); + AuBool(DIRPERM1, dirperm1); + + v = sbinfo->si_wbr_create; + if (v != AuWbrCreate_Def) + au_show_wbr_create(m, v, sbinfo); + + v = sbinfo->si_wbr_copyup; + if (v != AuWbrCopyup_Def) + seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); + + v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); + if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) + seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); + + AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); + + v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; + AuUInt(RDCACHE, rdcache, v); + + AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); + AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); + + au_fhsm_show(m, sbinfo); + + AuBool(DIRREN, dirren); + AuBool(SUM, sum); + /* AuBool(SUM_W, wsum); */ + AuBool(WARN_PERM, warn_perm); + AuBool(VERBOSE, verbose); + +out: + /* be sure to print "br:" last */ + if (!sysaufs_brs) { + seq_puts(m, ",br:"); + au_show_brs(m, sb); + } + si_read_unlock(sb); + return 0; + +#undef AuBool +#undef AuStr +#undef AuUInt +} + +/* ---------------------------------------------------------------------- */ + +/* sum mode which returns the summation for statfs(2) */ + +static u64 au_add_till_max(u64 a, u64 b) +{ + u64 old; + + old = a; + a += b; + if (old <= a) + return a; + return ULLONG_MAX; +} + +static u64 au_mul_till_max(u64 a, long mul) +{ + u64 old; + + old = a; + a *= mul; + if (old <= a) + return a; + return ULLONG_MAX; +} + +static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) +{ + int err; + long bsize, factor; + u64 blocks, bfree, bavail, files, ffree; + aufs_bindex_t bbot, bindex, i; + unsigned char shared; + struct path h_path; + struct super_block *h_sb; + + err = 0; + bsize = LONG_MAX; + files = 0; + ffree = 0; + blocks = 0; + bfree = 0; + bavail = 0; + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + h_path.mnt = au_sbr_mnt(sb, bindex); + h_sb = h_path.mnt->mnt_sb; + shared = 0; + for (i = 0; !shared && i < bindex; i++) + shared = (au_sbr_sb(sb, i) == h_sb); + if (shared) + continue; + + /* sb->s_root for NFS is unreliable */ + h_path.dentry = h_path.mnt->mnt_root; + err = vfs_statfs(&h_path, buf); + if (unlikely(err)) + goto out; + + if (bsize > buf->f_bsize) { + /* + * we will reduce bsize, so we have to expand blocks + * etc. to match them again + */ + factor = (bsize / buf->f_bsize); + blocks = au_mul_till_max(blocks, factor); + bfree = au_mul_till_max(bfree, factor); + bavail = au_mul_till_max(bavail, factor); + bsize = buf->f_bsize; + } + + factor = (buf->f_bsize / bsize); + blocks = au_add_till_max(blocks, + au_mul_till_max(buf->f_blocks, factor)); + bfree = au_add_till_max(bfree, + au_mul_till_max(buf->f_bfree, factor)); + bavail = au_add_till_max(bavail, + au_mul_till_max(buf->f_bavail, factor)); + files = au_add_till_max(files, buf->f_files); + ffree = au_add_till_max(ffree, buf->f_ffree); + } + + buf->f_bsize = bsize; + buf->f_blocks = blocks; + buf->f_bfree = bfree; + buf->f_bavail = bavail; + buf->f_files = files; + buf->f_ffree = ffree; + buf->f_frsize = 0; + +out: + return err; +} + +static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + int err; + struct path h_path; + struct super_block *sb; + + /* lock free root dinfo */ + sb = dentry->d_sb; + si_noflush_read_lock(sb); + if (!au_opt_test(au_mntflags(sb), SUM)) { + /* sb->s_root for NFS is unreliable */ + h_path.mnt = au_sbr_mnt(sb, 0); + h_path.dentry = h_path.mnt->mnt_root; + err = vfs_statfs(&h_path, buf); + } else + err = au_statfs_sum(sb, buf); + si_read_unlock(sb); + + if (!err) { + buf->f_type = AUFS_SUPER_MAGIC; + buf->f_namelen = AUFS_MAX_NAMELEN; + memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); + } + /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_sync_fs(struct super_block *sb, int wait) +{ + int err, e; + aufs_bindex_t bbot, bindex; + struct au_branch *br; + struct super_block *h_sb; + + err = 0; + si_noflush_read_lock(sb); + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (!au_br_writable(br->br_perm)) + continue; + + h_sb = au_sbr_sb(sb, bindex); + e = vfsub_sync_filesystem(h_sb, wait); + if (unlikely(e && !err)) + err = e; + /* go on even if an error happens */ + } + si_read_unlock(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* final actions when unmounting a file system */ +static void aufs_put_super(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + sbinfo = au_sbi(sb); + if (sbinfo) + kobject_put(&sbinfo->si_kobj); +} + +/* ---------------------------------------------------------------------- */ + +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, + struct super_block *sb, void *arg) +{ + void *array; + unsigned long long n, sz; + + array = NULL; + n = 0; + if (!*hint) + goto out; + + if (*hint > ULLONG_MAX / sizeof(array)) { + array = ERR_PTR(-EMFILE); + pr_err("hint %llu\n", *hint); + goto out; + } + + sz = sizeof(array) * *hint; + array = kzalloc(sz, GFP_NOFS); + if (unlikely(!array)) + array = vzalloc(sz); + if (unlikely(!array)) { + array = ERR_PTR(-ENOMEM); + goto out; + } + + n = cb(sb, array, *hint, arg); + AuDebugOn(n > *hint); + +out: + *hint = n; + return array; +} + +static unsigned long long au_iarray_cb(struct super_block *sb, void *a, + unsigned long long max __maybe_unused, + void *arg) +{ + unsigned long long n; + struct inode **p, *inode; + struct list_head *head; + + n = 0; + p = a; + head = arg; + spin_lock(&sb->s_inode_list_lock); + list_for_each_entry(inode, head, i_sb_list) { + if (!au_is_bad_inode(inode) + && au_ii(inode)->ii_btop >= 0) { + spin_lock(&inode->i_lock); + if (atomic_read(&inode->i_count)) { + au_igrab(inode); + *p++ = inode; + n++; + AuDebugOn(n > max); + } + spin_unlock(&inode->i_lock); + } + } + spin_unlock(&sb->s_inode_list_lock); + + return n; +} + +struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) +{ + struct au_sbinfo *sbi; + + sbi = au_sbi(sb); + *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); + return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); +} + +void au_iarray_free(struct inode **a, unsigned long long max) +{ + unsigned long long ull; + + for (ull = 0; ull < max; ull++) + iput(a[ull]); + kvfree(a); +} + +/* ---------------------------------------------------------------------- */ + +/* + * refresh dentry and inode at remount time. + */ +/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ +static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, + struct dentry *parent) +{ + int err; + + di_write_lock_child(dentry); + di_read_lock_parent(parent, AuLock_IR); + err = au_refresh_dentry(dentry, parent); + if (!err && dir_flags) + au_hn_reset(d_inode(dentry), dir_flags); + di_read_unlock(parent, AuLock_IR); + di_write_unlock(dentry); + + return err; +} + +static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, + struct au_sbinfo *sbinfo, + const unsigned int dir_flags, unsigned int do_idop) +{ + int err; + struct dentry *parent; + + err = 0; + parent = dget_parent(dentry); + if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { + if (d_really_is_positive(dentry)) { + if (!d_is_dir(dentry)) + err = au_do_refresh(dentry, /*dir_flags*/0, + parent); + else { + err = au_do_refresh(dentry, dir_flags, parent); + if (unlikely(err)) + au_fset_si(sbinfo, FAILED_REFRESH_DIR); + } + } else + err = au_do_refresh(dentry, /*dir_flags*/0, parent); + AuDbgDentry(dentry); + } + dput(parent); + + if (!err) { + if (do_idop) + au_refresh_dop(dentry, /*force_reval*/0); + } else + au_refresh_dop(dentry, /*force_reval*/1); + + AuTraceErr(err); + return err; +} + +static int au_refresh_d(struct super_block *sb, unsigned int do_idop) +{ + int err, i, j, ndentry, e; + unsigned int sigen; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries, *d; + struct au_sbinfo *sbinfo; + struct dentry *root = sb->s_root; + const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); + + if (do_idop) + au_refresh_dop(root, /*force_reval*/0); + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, root, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + sigen = au_sigen(sb); + sbinfo = au_sbi(sb); + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + d = dentries[j]; + e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, + do_idop); + if (unlikely(e && !err)) + err = e; + /* go on even err */ + } + } + +out_dpages: + au_dpages_free(&dpages); +out: + return err; +} + +static int au_refresh_i(struct super_block *sb, unsigned int do_idop) +{ + int err, e; + unsigned int sigen; + unsigned long long max, ull; + struct inode *inode, **array; + + array = au_iarray_alloc(sb, &max); + err = PTR_ERR(array); + if (IS_ERR(array)) + goto out; + + err = 0; + sigen = au_sigen(sb); + for (ull = 0; ull < max; ull++) { + inode = array[ull]; + if (unlikely(!inode)) + break; + + e = 0; + ii_write_lock_child(inode); + if (au_iigen(inode, NULL) != sigen) { + e = au_refresh_hinode_self(inode); + if (unlikely(e)) { + au_refresh_iop(inode, /*force_getattr*/1); + pr_err("error %d, i%lu\n", e, inode->i_ino); + if (!err) + err = e; + /* go on even if err */ + } + } + if (!e && do_idop) + au_refresh_iop(inode, /*force_getattr*/0); + ii_write_unlock(inode); + } + + au_iarray_free(array, max); + +out: + return err; +} + +static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) +{ + int err, e; + unsigned int udba; + aufs_bindex_t bindex, bbot; + struct dentry *root; + struct inode *inode; + struct au_branch *br; + struct au_sbinfo *sbi; + + au_sigen_inc(sb); + sbi = au_sbi(sb); + au_fclr_si(sbi, FAILED_REFRESH_DIR); + + root = sb->s_root; + DiMustNoWaiters(root); + inode = d_inode(root); + IiMustNoWaiters(inode); + + udba = au_opt_udba(sb); + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + err = au_hnotify_reset_br(udba, br, br->br_perm); + if (unlikely(err)) + AuIOErr("hnotify failed on br %d, %d, ignored\n", + bindex, err); + /* go on even if err */ + } + au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); + + if (do_idop) { + if (au_ftest_si(sbi, NO_DREVAL)) { + AuDebugOn(sb->s_d_op == &aufs_dop_noreval); + sb->s_d_op = &aufs_dop_noreval; + AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); + sbi->si_iop_array = aufs_iop_nogetattr; + } else { + AuDebugOn(sb->s_d_op == &aufs_dop); + sb->s_d_op = &aufs_dop; + AuDebugOn(sbi->si_iop_array == aufs_iop); + sbi->si_iop_array = aufs_iop; + } + pr_info("reset to %ps and %ps\n", + sb->s_d_op, sbi->si_iop_array); + } + + di_write_unlock(root); + err = au_refresh_d(sb, do_idop); + e = au_refresh_i(sb, do_idop); + if (unlikely(e && !err)) + err = e; + /* aufs_write_lock() calls ..._child() */ + di_write_lock_child(root); + + au_cpup_attr_all(inode, /*force*/1); + + if (unlikely(err)) + AuIOErr("refresh failed, ignored, %d\n", err); +} + +/* stop extra interpretation of errno in mount(8), and strange error messages */ +static int cvt_err(int err) +{ + AuTraceErr(err); + + switch (err) { + case -ENOENT: + case -ENOTDIR: + case -EEXIST: + case -EIO: + err = -EINVAL; + } + return err; +} + +static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + int err, do_dx; + unsigned int mntflags; + struct au_opts opts = { + .opt = NULL + }; + struct dentry *root; + struct inode *inode; + struct au_sbinfo *sbinfo; + + err = 0; + root = sb->s_root; + if (!data || !*data) { + err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (!err) { + di_write_lock_child(root); + err = au_opts_verify(sb, *flags, /*pending*/0); + aufs_write_unlock(root); + } + goto out; + } + + err = -ENOMEM; + opts.opt = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!opts.opt)) + goto out; + opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); + opts.flags = AuOpts_REMOUNT; + opts.sb_flags = *flags; + + /* parse it before aufs lock */ + err = au_opts_parse(sb, data, &opts); + if (unlikely(err)) + goto out_opts; + + sbinfo = au_sbi(sb); + inode = d_inode(root); + inode_lock(inode); + err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out_mtx; + di_write_lock_child(root); + + /* au_opts_remount() may return an error */ + err = au_opts_remount(sb, &opts); + au_opts_free(&opts); + + if (au_ftest_opts(opts.flags, REFRESH)) + au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); + + if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { + mntflags = au_mntflags(sb); + do_dx = !!au_opt_test(mntflags, DIO); + au_dy_arefresh(do_dx); + } + + au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ + aufs_write_unlock(root); + +out_mtx: + inode_unlock(inode); +out_opts: + free_page((unsigned long)opts.opt); +out: + err = cvt_err(err); + AuTraceErr(err); + return err; +} + +static const struct super_operations aufs_sop = { + .alloc_inode = aufs_alloc_inode, + .destroy_inode = aufs_destroy_inode, + .free_inode = aufs_free_inode, + /* always deleting, no clearing */ + .drop_inode = generic_delete_inode, + .show_options = aufs_show_options, + .statfs = aufs_statfs, + .put_super = aufs_put_super, + .sync_fs = aufs_sync_fs, + .remount_fs = aufs_remount_fs +}; + +/* ---------------------------------------------------------------------- */ + +static int alloc_root(struct super_block *sb) +{ + int err; + struct inode *inode; + struct dentry *root; + + err = -ENOMEM; + inode = au_iget_locked(sb, AUFS_ROOT_INO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out; + + inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ + inode->i_fop = &aufs_dir_fop; + inode->i_mode = S_IFDIR; + set_nlink(inode, 2); + unlock_new_inode(inode); + + root = d_make_root(inode); + if (unlikely(!root)) + goto out; + err = PTR_ERR(root); + if (IS_ERR(root)) + goto out; + + err = au_di_init(root); + if (!err) { + sb->s_root = root; + return 0; /* success */ + } + dput(root); + +out: + return err; +} + +static int aufs_fill_super(struct super_block *sb, void *raw_data, + int silent __maybe_unused) +{ + int err; + struct au_opts opts = { + .opt = NULL + }; + struct au_sbinfo *sbinfo; + struct dentry *root; + struct inode *inode; + char *arg = raw_data; + + if (unlikely(!arg || !*arg)) { + err = -EINVAL; + pr_err("no arg\n"); + goto out; + } + + err = -ENOMEM; + opts.opt = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!opts.opt)) + goto out; + opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); + opts.sb_flags = sb->s_flags; + + err = au_si_alloc(sb); + if (unlikely(err)) + goto out_opts; + sbinfo = au_sbi(sb); + + /* all timestamps always follow the ones on the branch */ + sb->s_flags |= SB_NOATIME | SB_NODIRATIME; + sb->s_flags |= SB_I_VERSION; /* do we really need this? */ + sb->s_op = &aufs_sop; + sb->s_d_op = &aufs_dop; + sb->s_magic = AUFS_SUPER_MAGIC; + sb->s_maxbytes = 0; + sb->s_stack_depth = 1; + au_export_init(sb); + au_xattr_init(sb); + + err = alloc_root(sb); + if (unlikely(err)) { + si_write_unlock(sb); + goto out_info; + } + root = sb->s_root; + inode = d_inode(root); + + /* + * actually we can parse options regardless aufs lock here. + * but at remount time, parsing must be done before aufs lock. + * so we follow the same rule. + */ + ii_write_lock_parent(inode); + aufs_write_unlock(root); + err = au_opts_parse(sb, arg, &opts); + if (unlikely(err)) + goto out_root; + + /* lock vfs_inode first, then aufs. */ + inode_lock(inode); + aufs_write_lock(root); + err = au_opts_mount(sb, &opts); + au_opts_free(&opts); + if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { + sb->s_d_op = &aufs_dop_noreval; + pr_info("%ps\n", sb->s_d_op); + au_refresh_dop(root, /*force_reval*/0); + sbinfo->si_iop_array = aufs_iop_nogetattr; + au_refresh_iop(inode, /*force_getattr*/0); + } + aufs_write_unlock(root); + inode_unlock(inode); + if (!err) + goto out_opts; /* success */ + +out_root: + dput(root); + sb->s_root = NULL; +out_info: + kobject_put(&sbinfo->si_kobj); + sb->s_fs_info = NULL; +out_opts: + free_page((unsigned long)opts.opt); +out: + AuTraceErr(err); + err = cvt_err(err); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name __maybe_unused, + void *raw_data) +{ + struct dentry *root; + + /* all timestamps always follow the ones on the branch */ + /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ + root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); + if (IS_ERR(root)) + goto out; + + au_sbilist_add(root->d_sb); + +out: + return root; +} + +static void aufs_kill_sb(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + sbinfo = au_sbi(sb); + if (sbinfo) { + au_sbilist_del(sb); + aufs_write_lock(sb->s_root); + au_fhsm_fin(sb); + if (sbinfo->si_wbr_create_ops->fin) + sbinfo->si_wbr_create_ops->fin(sb); + if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { + au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); + au_remount_refresh(sb, /*do_idop*/0); + } + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_put(sb, /*verbose*/1); + au_xino_clr(sb); + au_dr_opt_flush(sb); + sbinfo->si_sb = NULL; + aufs_write_unlock(sb->s_root); + au_nwt_flush(&sbinfo->si_nowait); + } + kill_anon_super(sb); +} + +struct file_system_type aufs_fs_type = { + .name = AUFS_FSTYPE, + /* a race between rename and others */ + .fs_flags = FS_RENAME_DOES_D_MOVE, + .mount = aufs_mount, + .kill_sb = aufs_kill_sb, + /* no need to __module_get() and module_put(). */ + .owner = THIS_MODULE, +}; diff --git a/fs/aufs/super.h b/fs/aufs/super.h new file mode 100644 index 000000000000..6a5de1f0d047 --- /dev/null +++ b/fs/aufs/super.h @@ -0,0 +1,587 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * super_block operations + */ + +#ifndef __AUFS_SUPER_H__ +#define __AUFS_SUPER_H__ + +#ifdef __KERNEL__ + +#include +#include +#include "hbl.h" +#include "lcnt.h" +#include "rwsem.h" +#include "wkq.h" + +/* policies to select one among multiple writable branches */ +struct au_wbr_copyup_operations { + int (*copyup)(struct dentry *dentry); +}; + +#define AuWbr_DIR 1 /* target is a dir */ +#define AuWbr_PARENT (1 << 1) /* always require a parent */ + +#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) +#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } +#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } + +struct au_wbr_create_operations { + int (*create)(struct dentry *dentry, unsigned int flags); + int (*init)(struct super_block *sb); + int (*fin)(struct super_block *sb); +}; + +struct au_wbr_mfs { + struct mutex mfs_lock; /* protect this structure */ + unsigned long mfs_jiffy; + unsigned long mfs_expire; + aufs_bindex_t mfs_bindex; + + unsigned long long mfsrr_bytes; + unsigned long long mfsrr_watermark; +}; + +#define AuPlink_NHASH 100 +static inline int au_plink_hash(ino_t ino) +{ + return ino % AuPlink_NHASH; +} + +/* File-based Hierarchical Storage Management */ +struct au_fhsm { +#ifdef CONFIG_AUFS_FHSM + /* allow only one process who can receive the notification */ + spinlock_t fhsm_spin; + pid_t fhsm_pid; + wait_queue_head_t fhsm_wqh; + atomic_t fhsm_readable; + + /* these are protected by si_rwsem */ + unsigned long fhsm_expire; + aufs_bindex_t fhsm_bottom; +#endif +}; + +struct au_branch; +struct au_sbinfo { + /* nowait tasks in the system-wide workqueue */ + struct au_nowait_tasks si_nowait; + + /* + * tried sb->s_umount, but failed due to the dependency between i_mutex. + * rwsem for au_sbinfo is necessary. + */ + struct au_rwsem si_rwsem; + + /* + * dirty approach to protect sb->sb_inodes and ->s_files (gone) from + * remount. + */ + au_lcnt_t si_ninodes, si_nfiles; + + /* branch management */ + unsigned int si_generation; + + /* see AuSi_ flags */ + unsigned char au_si_status; + + aufs_bindex_t si_bbot; + + /* dirty trick to keep br_id plus */ + unsigned int si_last_br_id : + sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; + struct au_branch **si_branch; + + /* policy to select a writable branch */ + unsigned char si_wbr_copyup; + unsigned char si_wbr_create; + struct au_wbr_copyup_operations *si_wbr_copyup_ops; + struct au_wbr_create_operations *si_wbr_create_ops; + + /* round robin */ + atomic_t si_wbr_rr_next; + + /* most free space */ + struct au_wbr_mfs si_wbr_mfs; + + /* File-based Hierarchical Storage Management */ + struct au_fhsm si_fhsm; + + /* mount flags */ + /* include/asm-ia64/siginfo.h defines a macro named si_flags */ + unsigned int si_mntflags; + + /* external inode number (bitmap and translation table) */ + loff_t si_ximaxent; /* max entries in a xino */ + + struct file *si_xib; + struct mutex si_xib_mtx; /* protect xib members */ + unsigned long *si_xib_buf; + unsigned long si_xib_last_pindex; + int si_xib_next_bit; + + unsigned long si_xino_jiffy; + unsigned long si_xino_expire; + /* reserved for future use */ + /* unsigned long long si_xib_limit; */ /* Max xib file size */ + +#ifdef CONFIG_AUFS_EXPORT + /* i_generation */ + /* todo: make xigen file an array to support many inode numbers */ + struct file *si_xigen; + atomic_t si_xigen_next; +#endif + + /* dirty trick to support atomic_open */ + struct hlist_bl_head si_aopen; + + /* vdir parameters */ + unsigned long si_rdcache; /* max cache time in jiffies */ + unsigned int si_rdblk; /* deblk size */ + unsigned int si_rdhash; /* hash size */ + + /* + * If the number of whiteouts are larger than si_dirwh, leave all of + * them after au_whtmp_ren to reduce the cost of rmdir(2). + * future fsck.aufs or kernel thread will remove them later. + * Otherwise, remove all whiteouts and the dir in rmdir(2). + */ + unsigned int si_dirwh; + + /* pseudo_link list */ + struct hlist_bl_head si_plink[AuPlink_NHASH]; + wait_queue_head_t si_plink_wq; + spinlock_t si_plink_maint_lock; + pid_t si_plink_maint_pid; + + /* file list */ + struct hlist_bl_head si_files; + + /* with/without getattr, brother of sb->s_d_op */ + const struct inode_operations *si_iop_array; + + /* + * sysfs and lifetime management. + * this is not a small structure and it may be a waste of memory in case + * of sysfs is disabled, particularly when many aufs-es are mounted. + * but using sysfs is majority. + */ + struct kobject si_kobj; +#ifdef CONFIG_DEBUG_FS + struct dentry *si_dbgaufs; + struct dentry *si_dbgaufs_plink; + struct dentry *si_dbgaufs_xib; +#ifdef CONFIG_AUFS_EXPORT + struct dentry *si_dbgaufs_xigen; +#endif +#endif + +#ifdef CONFIG_AUFS_SBILIST + struct hlist_bl_node si_list; +#endif + + /* dirty, necessary for unmounting, sysfs and sysrq */ + struct super_block *si_sb; +}; + +/* sbinfo status flags */ +/* + * set true when refresh_dirs() failed at remount time. + * then try refreshing dirs at access time again. + * if it is false, refreshing dirs at access time is unnecessary + */ +#define AuSi_FAILED_REFRESH_DIR 1 +#define AuSi_FHSM (1 << 1) /* fhsm is active now */ +#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ + +#ifndef CONFIG_AUFS_FHSM +#undef AuSi_FHSM +#define AuSi_FHSM 0 +#endif + +static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, + unsigned int flag) +{ + AuRwMustAnyLock(&sbi->si_rwsem); + return sbi->au_si_status & flag; +} +#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) +#define au_fset_si(sbinfo, name) do { \ + AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ + (sbinfo)->au_si_status |= AuSi_##name; \ +} while (0) +#define au_fclr_si(sbinfo, name) do { \ + AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ + (sbinfo)->au_si_status &= ~AuSi_##name; \ +} while (0) + +/* ---------------------------------------------------------------------- */ + +/* policy to select one among writable branches */ +#define AuWbrCopyup(sbinfo, ...) \ + ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) +#define AuWbrCreate(sbinfo, ...) \ + ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) + +/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ +#define AuLock_DW 1 /* write-lock dentry */ +#define AuLock_IR (1 << 1) /* read-lock inode */ +#define AuLock_IW (1 << 2) /* write-lock inode */ +#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ +#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ + /* except RENAME_EXCHANGE */ +#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ +#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ +#define AuLock_GEN (1 << 7) /* test digen/iigen */ +#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) +#define au_fset_lock(flags, name) \ + do { (flags) |= AuLock_##name; } while (0) +#define au_fclr_lock(flags, name) \ + do { (flags) &= ~AuLock_##name; } while (0) + +/* ---------------------------------------------------------------------- */ + +/* super.c */ +extern struct file_system_type aufs_fs_type; +struct inode *au_iget_locked(struct super_block *sb, ino_t ino); +typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, + unsigned long long max, void *arg); +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, + struct super_block *sb, void *arg); +struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); +void au_iarray_free(struct inode **a, unsigned long long max); + +/* sbinfo.c */ +void au_si_free(struct kobject *kobj); +int au_si_alloc(struct super_block *sb); +int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink); + +unsigned int au_sigen_inc(struct super_block *sb); +aufs_bindex_t au_new_br_id(struct super_block *sb); + +int si_read_lock(struct super_block *sb, int flags); +int si_write_lock(struct super_block *sb, int flags); +int aufs_read_lock(struct dentry *dentry, int flags); +void aufs_read_unlock(struct dentry *dentry, int flags); +void aufs_write_lock(struct dentry *dentry); +void aufs_write_unlock(struct dentry *dentry); +int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); +void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); + +/* wbr_policy.c */ +extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; +extern struct au_wbr_create_operations au_wbr_create_ops[]; +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); +int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); +int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); + +/* mvdown.c */ +int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); + +#ifdef CONFIG_AUFS_FHSM +/* fhsm.c */ + +static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) +{ + pid_t pid; + + spin_lock(&fhsm->fhsm_spin); + pid = fhsm->fhsm_pid; + spin_unlock(&fhsm->fhsm_spin); + + return pid; +} + +void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); +void au_fhsm_wrote_all(struct super_block *sb, int force); +int au_fhsm_fd(struct super_block *sb, int oflags); +int au_fhsm_br_alloc(struct au_branch *br); +void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); +void au_fhsm_fin(struct super_block *sb); +void au_fhsm_init(struct au_sbinfo *sbinfo); +void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); +void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); +#else +AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, + int force) +AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) +AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) +AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) +AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) +AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) +AuStubVoid(au_fhsm_fin, struct super_block *sb) +AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) +AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) +AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) +#endif + +/* ---------------------------------------------------------------------- */ + +static inline struct au_sbinfo *au_sbi(struct super_block *sb) +{ + return sb->s_fs_info; +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_EXPORT +int au_test_nfsd(void); +void au_export_init(struct super_block *sb); +void au_xigen_inc(struct inode *inode); +int au_xigen_new(struct inode *inode); +int au_xigen_set(struct super_block *sb, struct path *path); +void au_xigen_clr(struct super_block *sb); + +static inline int au_busy_or_stale(void) +{ + if (!au_test_nfsd()) + return -EBUSY; + return -ESTALE; +} +#else +AuStubInt0(au_test_nfsd, void) +AuStubVoid(au_export_init, struct super_block *sb) +AuStubVoid(au_xigen_inc, struct inode *inode) +AuStubInt0(au_xigen_new, struct inode *inode) +AuStubInt0(au_xigen_set, struct super_block *sb, struct path *path) +AuStubVoid(au_xigen_clr, struct super_block *sb) +AuStub(int, au_busy_or_stale, return -EBUSY, void) +#endif /* CONFIG_AUFS_EXPORT */ + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_SBILIST +/* module.c */ +extern struct hlist_bl_head au_sbilist; + +static inline void au_sbilist_init(void) +{ + INIT_HLIST_BL_HEAD(&au_sbilist); +} + +static inline void au_sbilist_add(struct super_block *sb) +{ + au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); +} + +static inline void au_sbilist_del(struct super_block *sb) +{ + au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); +} + +#ifdef CONFIG_AUFS_MAGIC_SYSRQ +static inline void au_sbilist_lock(void) +{ + hlist_bl_lock(&au_sbilist); +} + +static inline void au_sbilist_unlock(void) +{ + hlist_bl_unlock(&au_sbilist); +} +#define AuGFP_SBILIST GFP_ATOMIC +#else +AuStubVoid(au_sbilist_lock, void) +AuStubVoid(au_sbilist_unlock, void) +#define AuGFP_SBILIST GFP_NOFS +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ +#else +AuStubVoid(au_sbilist_init, void) +AuStubVoid(au_sbilist_add, struct super_block *sb) +AuStubVoid(au_sbilist_del, struct super_block *sb) +AuStubVoid(au_sbilist_lock, void) +AuStubVoid(au_sbilist_unlock, void) +#define AuGFP_SBILIST GFP_NOFS +#endif + +/* ---------------------------------------------------------------------- */ + +static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) +{ + /* + * This function is a dynamic '__init' function actually, + * so the tiny check for si_rwsem is unnecessary. + */ + /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ +#ifdef CONFIG_DEBUG_FS + sbinfo->si_dbgaufs = NULL; + sbinfo->si_dbgaufs_plink = NULL; + sbinfo->si_dbgaufs_xib = NULL; +#ifdef CONFIG_AUFS_EXPORT + sbinfo->si_dbgaufs_xigen = NULL; +#endif +#endif +} + +/* ---------------------------------------------------------------------- */ + +/* current->atomic_flags */ +/* this value should never corrupt the ones defined in linux/sched.h */ +#define PFA_AUFS 0x10 + +TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ +TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ +TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ + +static inline int si_pid_test(struct super_block *sb) +{ + return !!task_test_aufs(current); +} + +static inline void si_pid_clr(struct super_block *sb) +{ + AuDebugOn(!task_test_aufs(current)); + task_clear_aufs(current); +} + +static inline void si_pid_set(struct super_block *sb) +{ + AuDebugOn(task_test_aufs(current)); + task_set_aufs(current); +} + +/* ---------------------------------------------------------------------- */ + +/* lock superblock. mainly for entry point functions */ +#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) +#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) +#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) +#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) +/* +#define __si_read_trylock_nested(sb) \ + au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) +#define __si_write_trylock_nested(sb) \ + au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) +*/ + +#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) +#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) +#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&au_sbi(sb)->si_rwsem) + +#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) +#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) +#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) + +static inline void si_noflush_read_lock(struct super_block *sb) +{ + __si_read_lock(sb); + si_pid_set(sb); +} + +static inline int si_noflush_read_trylock(struct super_block *sb) +{ + int locked; + + locked = __si_read_trylock(sb); + if (locked) + si_pid_set(sb); + return locked; +} + +static inline void si_noflush_write_lock(struct super_block *sb) +{ + __si_write_lock(sb); + si_pid_set(sb); +} + +static inline int si_noflush_write_trylock(struct super_block *sb) +{ + int locked; + + locked = __si_write_trylock(sb); + if (locked) + si_pid_set(sb); + return locked; +} + +#if 0 /* reserved */ +static inline int si_read_trylock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + return si_noflush_read_trylock(sb); +} +#endif + +static inline void si_read_unlock(struct super_block *sb) +{ + si_pid_clr(sb); + __si_read_unlock(sb); +} + +#if 0 /* reserved */ +static inline int si_write_trylock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + return si_noflush_write_trylock(sb); +} +#endif + +static inline void si_write_unlock(struct super_block *sb) +{ + si_pid_clr(sb); + __si_write_unlock(sb); +} + +#if 0 /* reserved */ +static inline void si_downgrade_lock(struct super_block *sb) +{ + __si_downgrade_lock(sb); +} +#endif + +/* ---------------------------------------------------------------------- */ + +static inline aufs_bindex_t au_sbbot(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_bbot; +} + +static inline unsigned int au_mntflags(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_mntflags; +} + +static inline unsigned int au_sigen(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_generation; +} + +static inline struct au_branch *au_sbr(struct super_block *sb, + aufs_bindex_t bindex) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_branch[0 + bindex]; +} + +static inline loff_t au_xi_maxent(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_ximaxent; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SUPER_H__ */ diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c new file mode 100644 index 000000000000..32a0811c54de --- /dev/null +++ b/fs/aufs/sysaufs.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sysfs interface and lifetime management + * they are necessary regardless sysfs is disabled. + */ + +#include +#include "aufs.h" + +unsigned long sysaufs_si_mask; +struct kset *sysaufs_kset; + +#define AuSiAttr(_name) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = sysaufs_si_##_name, \ +} + +static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); +struct attribute *sysaufs_si_attrs[] = { + &sysaufs_si_attr_xi_path.attr, + NULL, +}; + +static const struct sysfs_ops au_sbi_ops = { + .show = sysaufs_si_show +}; + +static struct kobj_type au_sbi_ktype = { + .release = au_si_free, + .sysfs_ops = &au_sbi_ops, + .default_attrs = sysaufs_si_attrs +}; + +/* ---------------------------------------------------------------------- */ + +int sysaufs_si_init(struct au_sbinfo *sbinfo) +{ + int err; + + sbinfo->si_kobj.kset = sysaufs_kset; + /* cf. sysaufs_name() */ + err = kobject_init_and_add + (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, + SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); + + return err; +} + +void sysaufs_fin(void) +{ + sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); + kset_unregister(sysaufs_kset); +} + +int __init sysaufs_init(void) +{ + int err; + + do { + get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); + } while (!sysaufs_si_mask); + + err = -EINVAL; + sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); + if (unlikely(!sysaufs_kset)) + goto out; + err = PTR_ERR(sysaufs_kset); + if (IS_ERR(sysaufs_kset)) + goto out; + err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); + if (unlikely(err)) + kset_unregister(sysaufs_kset); + +out: + return err; +} diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h new file mode 100644 index 000000000000..195fe279b820 --- /dev/null +++ b/fs/aufs/sysaufs.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sysfs interface and mount lifetime management + */ + +#ifndef __SYSAUFS_H__ +#define __SYSAUFS_H__ + +#ifdef __KERNEL__ + +#include +#include "module.h" + +struct super_block; +struct au_sbinfo; + +struct sysaufs_si_attr { + struct attribute attr; + int (*show)(struct seq_file *seq, struct super_block *sb); +}; + +/* ---------------------------------------------------------------------- */ + +/* sysaufs.c */ +extern unsigned long sysaufs_si_mask; +extern struct kset *sysaufs_kset; +extern struct attribute *sysaufs_si_attrs[]; +int sysaufs_si_init(struct au_sbinfo *sbinfo); +int __init sysaufs_init(void); +void sysaufs_fin(void); + +/* ---------------------------------------------------------------------- */ + +/* some people doesn't like to show a pointer in kernel */ +static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) +{ + return sysaufs_si_mask ^ (unsigned long)sbinfo; +} + +#define SysaufsSiNamePrefix "si_" +#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) +static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) +{ + snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", + sysaufs_si_id(sbinfo)); +} + +struct au_branch; +#ifdef CONFIG_SYSFS +/* sysfs.c */ +extern struct attribute_group *sysaufs_attr_group; + +int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); +ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, + char *buf); +long au_brinfo_ioctl(struct file *file, unsigned long arg); +#ifdef CONFIG_COMPAT +long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); +#endif + +void sysaufs_br_init(struct au_branch *br); +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); +void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); + +#define sysaufs_brs_init() do {} while (0) + +#else +#define sysaufs_attr_group NULL + +AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) +AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, + struct attribute *attr, char *buf) +AuStubVoid(sysaufs_br_init, struct au_branch *br) +AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) +AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) + +static inline void sysaufs_brs_init(void) +{ + sysaufs_brs = 0; +} + +#endif /* CONFIG_SYSFS */ + +#endif /* __KERNEL__ */ +#endif /* __SYSAUFS_H__ */ diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c new file mode 100644 index 000000000000..098281b51a1a --- /dev/null +++ b/fs/aufs/sysfs.c @@ -0,0 +1,381 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sysfs interface + */ + +#include +#include +#include "aufs.h" + +#ifdef CONFIG_AUFS_FS_MODULE +/* this entry violates the "one line per file" policy of sysfs */ +static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + ssize_t err; + static char *conf = +#ifdef MY_ABC_HERE + "" +#else +/* this file is generated at compiling */ +#include "conf.str" +#endif /* MY_ABC_HERE */ + ; + + err = snprintf(buf, PAGE_SIZE, conf); + if (unlikely(err >= PAGE_SIZE)) + err = -EFBIG; + return err; +} + +static struct kobj_attribute au_config_attr = __ATTR_RO(config); +#endif + +static struct attribute *au_attr[] = { +#ifdef CONFIG_AUFS_FS_MODULE + &au_config_attr.attr, +#endif + NULL, /* need to NULL terminate the list of attributes */ +}; + +static struct attribute_group sysaufs_attr_group_body = { + .attrs = au_attr +}; + +struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; + +/* ---------------------------------------------------------------------- */ + +int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) +{ + int err; + + SiMustAnyLock(sb); + + err = 0; + if (au_opt_test(au_mntflags(sb), XINO)) { + err = au_xino_path(seq, au_sbi(sb)->si_xib); + seq_putc(seq, '\n'); + } + return err; +} + +/* + * the lifetime of branch is independent from the entry under sysfs. + * sysfs handles the lifetime of the entry, and never call ->show() after it is + * unlinked. + */ +static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, + aufs_bindex_t bindex, int idx) +{ + int err; + struct path path; + struct dentry *root; + struct au_branch *br; + au_br_perm_str_t perm; + + AuDbg("b%d\n", bindex); + + err = 0; + root = sb->s_root; + di_read_lock_parent(root, !AuLock_IR); + br = au_sbr(sb, bindex); + + switch (idx) { + case AuBrSysfs_BR: + path.mnt = au_br_mnt(br); + path.dentry = au_h_dptr(root, bindex); + err = au_seq_path(seq, &path); + if (!err) { + au_optstr_br_perm(&perm, br->br_perm); + seq_printf(seq, "=%s\n", perm.a); + } + break; + case AuBrSysfs_BRID: + seq_printf(seq, "%d\n", br->br_id); + break; + } + di_read_unlock(root, !AuLock_IR); + if (unlikely(err || seq_has_overflowed(seq))) + err = -E2BIG; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct seq_file *au_seq(char *p, ssize_t len) +{ + struct seq_file *seq; + + seq = kzalloc(sizeof(*seq), GFP_NOFS); + if (seq) { + /* mutex_init(&seq.lock); */ + seq->buf = p; + seq->size = len; + return seq; /* success */ + } + + seq = ERR_PTR(-ENOMEM); + return seq; +} + +#define SysaufsBr_PREFIX "br" +#define SysaufsBrid_PREFIX "brid" + +/* todo: file size may exceed PAGE_SIZE */ +ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + ssize_t err; + int idx; + long l; + aufs_bindex_t bbot; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct seq_file *seq; + char *name; + struct attribute **cattr; + + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + sb = sbinfo->si_sb; + + /* + * prevent a race condition between sysfs and aufs. + * for instance, sysfs_file_read() calls sysfs_get_active_two() which + * prohibits maintaining the sysfs entries. + * hew we acquire read lock after sysfs_get_active_two(). + * on the other hand, the remount process may maintain the sysfs/aufs + * entries after acquiring write lock. + * it can cause a deadlock. + * simply we gave up processing read here. + */ + err = -EBUSY; + if (unlikely(!si_noflush_read_trylock(sb))) + goto out; + + seq = au_seq(buf, PAGE_SIZE); + err = PTR_ERR(seq); + if (IS_ERR(seq)) + goto out_unlock; + + name = (void *)attr->name; + cattr = sysaufs_si_attrs; + while (*cattr) { + if (!strcmp(name, (*cattr)->name)) { + err = container_of(*cattr, struct sysaufs_si_attr, attr) + ->show(seq, sb); + goto out_seq; + } + cattr++; + } + + if (!strncmp(name, SysaufsBrid_PREFIX, + sizeof(SysaufsBrid_PREFIX) - 1)) { + idx = AuBrSysfs_BRID; + name += sizeof(SysaufsBrid_PREFIX) - 1; + } else if (!strncmp(name, SysaufsBr_PREFIX, + sizeof(SysaufsBr_PREFIX) - 1)) { + idx = AuBrSysfs_BR; + name += sizeof(SysaufsBr_PREFIX) - 1; + } else + BUG(); + + err = kstrtol(name, 10, &l); + if (!err) { + bbot = au_sbbot(sb); + if (l <= bbot) + err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); + else + err = -ENOENT; + } + +out_seq: + if (!err) { + err = seq->count; + /* sysfs limit */ + if (unlikely(err == PAGE_SIZE)) + err = -EFBIG; + } + au_kfree_rcu(seq); +out_unlock: + si_read_unlock(sb); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) +{ + int err; + int16_t brid; + aufs_bindex_t bindex, bbot; + size_t sz; + char *buf; + struct seq_file *seq; + struct au_branch *br; + + si_read_lock(sb, AuLock_FLUSH); + bbot = au_sbbot(sb); + err = bbot + 1; + if (!arg) + goto out; + + err = -ENOMEM; + buf = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!buf)) + goto out; + + seq = au_seq(buf, PAGE_SIZE); + err = PTR_ERR(seq); + if (IS_ERR(seq)) + goto out_buf; + + sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); + for (bindex = 0; bindex <= bbot; bindex++, arg++) { + /* VERIFY_WRITE */ + err = !access_ok(arg, sizeof(*arg)); + if (unlikely(err)) + break; + + br = au_sbr(sb, bindex); + brid = br->br_id; + BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); + err = __put_user(brid, &arg->id); + if (unlikely(err)) + break; + + BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); + err = __put_user(br->br_perm, &arg->perm); + if (unlikely(err)) + break; + + err = au_seq_path(seq, &br->br_path); + if (unlikely(err)) + break; + seq_putc(seq, '\0'); + if (!seq_has_overflowed(seq)) { + err = copy_to_user(arg->path, seq->buf, seq->count); + seq->count = 0; + if (unlikely(err)) + break; + } else { + err = -E2BIG; + goto out_seq; + } + } + if (unlikely(err)) + err = -EFAULT; + +out_seq: + au_kfree_rcu(seq); +out_buf: + free_page((unsigned long)buf); +out: + si_read_unlock(sb); + return err; +} + +long au_brinfo_ioctl(struct file *file, unsigned long arg) +{ + return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); +} + +#ifdef CONFIG_COMPAT +long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) +{ + return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); +} +#endif + +/* ---------------------------------------------------------------------- */ + +void sysaufs_br_init(struct au_branch *br) +{ + int i; + struct au_brsysfs *br_sysfs; + struct attribute *attr; + + br_sysfs = br->br_sysfs; + for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { + attr = &br_sysfs->attr; + sysfs_attr_init(attr); + attr->name = br_sysfs->name; + attr->mode = 0444; + br_sysfs++; + } +} + +void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + struct au_branch *br; + struct kobject *kobj; + struct au_brsysfs *br_sysfs; + int i; + aufs_bindex_t bbot; + + if (!sysaufs_brs) + return; + + kobj = &au_sbi(sb)->si_kobj; + bbot = au_sbbot(sb); + for (; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + br_sysfs = br->br_sysfs; + for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { + sysfs_remove_file(kobj, &br_sysfs->attr); + br_sysfs++; + } + } +} + +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +{ + int err, i; + aufs_bindex_t bbot; + struct kobject *kobj; + struct au_branch *br; + struct au_brsysfs *br_sysfs; + + if (!sysaufs_brs) + return; + + kobj = &au_sbi(sb)->si_kobj; + bbot = au_sbbot(sb); + for (; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + br_sysfs = br->br_sysfs; + snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), + SysaufsBr_PREFIX "%d", bindex); + snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), + SysaufsBrid_PREFIX "%d", bindex); + for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { + err = sysfs_create_file(kobj, &br_sysfs->attr); + if (unlikely(err)) + pr_warn("failed %s under sysfs(%d)\n", + br_sysfs->name, err); + br_sysfs++; + } + } +} diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c new file mode 100644 index 000000000000..0a4d7f41bf1b --- /dev/null +++ b/fs/aufs/sysrq.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * magic sysrq handler + */ + +/* #include */ +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +static void sysrq_sb(struct super_block *sb) +{ + char *plevel; + struct au_sbinfo *sbinfo; + struct file *file; + struct hlist_bl_head *files; + struct hlist_bl_node *pos; + struct au_finfo *finfo; + struct inode *i; + + plevel = au_plevel; + au_plevel = KERN_WARNING; + + /* since we define pr_fmt, call printk directly */ +#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) + + sbinfo = au_sbi(sb); + printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); + pr("superblock\n"); + au_dpri_sb(sb); + +#if 0 /* reserved */ + do { + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + + err = au_dpages_init(&dpages, GFP_ATOMIC); + if (unlikely(err)) + break; + err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); + if (!err) + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) + au_dpri_dentry(dpage->dentries[j]); + } + au_dpages_free(&dpages); + } while (0); +#endif + + pr("isolated inode\n"); + spin_lock(&sb->s_inode_list_lock); + list_for_each_entry(i, &sb->s_inodes, i_sb_list) { + spin_lock(&i->i_lock); + if (hlist_empty(&i->i_dentry)) + au_dpri_inode(i); + spin_unlock(&i->i_lock); + } + spin_unlock(&sb->s_inode_list_lock); + + pr("files\n"); + files = &au_sbi(sb)->si_files; + hlist_bl_lock(files); + hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { + umode_t mode; + + file = finfo->fi_file; + mode = file_inode(file)->i_mode; + if (!special_file(mode)) + au_dpri_file(file); + } + hlist_bl_unlock(files); + pr("done\n"); + +#undef pr + au_plevel = plevel; +} + +/* ---------------------------------------------------------------------- */ + +/* module parameter */ +static char *aufs_sysrq_key = "a"; +module_param_named(sysrq, aufs_sysrq_key, charp, 0444); +MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); + +static void au_sysrq(int key __maybe_unused) +{ + struct au_sbinfo *sbinfo; + struct hlist_bl_node *pos; + + lockdep_off(); + au_sbilist_lock(); + hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) + sysrq_sb(sbinfo->si_sb); + au_sbilist_unlock(); + lockdep_on(); +} + +static struct sysrq_key_op au_sysrq_op = { + .handler = au_sysrq, + .help_msg = "Aufs", + .action_msg = "Aufs", + .enable_mask = SYSRQ_ENABLE_DUMP +}; + +/* ---------------------------------------------------------------------- */ + +int __init au_sysrq_init(void) +{ + int err; + char key; + + err = -1; + key = *aufs_sysrq_key; + if ('a' <= key && key <= 'z') + err = register_sysrq_key(key, &au_sysrq_op); + if (unlikely(err)) + pr_err("err %d, sysrq=%c\n", err, key); + return err; +} + +void au_sysrq_fin(void) +{ + int err; + + err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); + if (unlikely(err)) + pr_err("err %d (ignored)\n", err); +} diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c new file mode 100644 index 000000000000..9ba22894165d --- /dev/null +++ b/fs/aufs/vdir.c @@ -0,0 +1,896 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * virtual or vertical directory + */ + +#include +#include "aufs.h" + +static unsigned int calc_size(int nlen) +{ + return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); +} + +static int set_deblk_end(union au_vdir_deblk_p *p, + union au_vdir_deblk_p *deblk_end) +{ + if (calc_size(0) <= deblk_end->deblk - p->deblk) { + p->de->de_str.len = 0; + /* smp_mb(); */ + return 0; + } + return -1; /* error */ +} + +/* returns true or false */ +static int is_deblk_end(union au_vdir_deblk_p *p, + union au_vdir_deblk_p *deblk_end) +{ + if (calc_size(0) <= deblk_end->deblk - p->deblk) + return !p->de->de_str.len; + return 1; +} + +static unsigned char *last_deblk(struct au_vdir *vdir) +{ + return vdir->vd_deblk[vdir->vd_nblk - 1]; +} + +/* ---------------------------------------------------------------------- */ + +/* estimate the appropriate size for name hash table */ +unsigned int au_rdhash_est(loff_t sz) +{ + unsigned int n; + + n = UINT_MAX; + sz >>= 10; + if (sz < n) + n = sz; + if (sz < AUFS_RDHASH_DEF) + n = AUFS_RDHASH_DEF; + /* pr_info("n %u\n", n); */ + return n; +} + +/* + * the allocated memory has to be freed by + * au_nhash_wh_free() or au_nhash_de_free(). + */ +int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) +{ + struct hlist_head *head; + unsigned int u; + size_t sz; + + sz = sizeof(*nhash->nh_head) * num_hash; + head = kmalloc(sz, gfp); + if (head) { + nhash->nh_num = num_hash; + nhash->nh_head = head; + for (u = 0; u < num_hash; u++) + INIT_HLIST_HEAD(head++); + return 0; /* success */ + } + + return -ENOMEM; +} + +static void nhash_count(struct hlist_head *head) +{ +#if 0 /* debugging */ + unsigned long n; + struct hlist_node *pos; + + n = 0; + hlist_for_each(pos, head) + n++; + pr_info("%lu\n", n); +#endif +} + +static void au_nhash_wh_do_free(struct hlist_head *head) +{ + struct au_vdir_wh *pos; + struct hlist_node *node; + + hlist_for_each_entry_safe(pos, node, head, wh_hash) + au_kfree_rcu(pos); +} + +static void au_nhash_de_do_free(struct hlist_head *head) +{ + struct au_vdir_dehstr *pos; + struct hlist_node *node; + + hlist_for_each_entry_safe(pos, node, head, hash) + au_cache_free_vdir_dehstr(pos); +} + +static void au_nhash_do_free(struct au_nhash *nhash, + void (*free)(struct hlist_head *head)) +{ + unsigned int n; + struct hlist_head *head; + + n = nhash->nh_num; + if (!n) + return; + + head = nhash->nh_head; + while (n-- > 0) { + nhash_count(head); + free(head++); + } + au_kfree_try_rcu(nhash->nh_head); +} + +void au_nhash_wh_free(struct au_nhash *whlist) +{ + au_nhash_do_free(whlist, au_nhash_wh_do_free); +} + +static void au_nhash_de_free(struct au_nhash *delist) +{ + au_nhash_do_free(delist, au_nhash_de_do_free); +} + +/* ---------------------------------------------------------------------- */ + +int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, + int limit) +{ + int num; + unsigned int u, n; + struct hlist_head *head; + struct au_vdir_wh *pos; + + num = 0; + n = whlist->nh_num; + head = whlist->nh_head; + for (u = 0; u < n; u++, head++) + hlist_for_each_entry(pos, head, wh_hash) + if (pos->wh_bindex == btgt && ++num > limit) + return 1; + return 0; +} + +static struct hlist_head *au_name_hash(struct au_nhash *nhash, + unsigned char *name, + unsigned int len) +{ + unsigned int v; + /* const unsigned int magic_bit = 12; */ + + AuDebugOn(!nhash->nh_num || !nhash->nh_head); + + v = 0; + if (len > 8) + len = 8; + while (len--) + v += *name++; + /* v = hash_long(v, magic_bit); */ + v %= nhash->nh_num; + return nhash->nh_head + v; +} + +static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, + int nlen) +{ + return str->len == nlen && !memcmp(str->name, name, nlen); +} + +/* returns found or not */ +int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) +{ + struct hlist_head *head; + struct au_vdir_wh *pos; + struct au_vdir_destr *str; + + head = au_name_hash(whlist, name, nlen); + hlist_for_each_entry(pos, head, wh_hash) { + str = &pos->wh_str; + AuDbg("%.*s\n", str->len, str->name); + if (au_nhash_test_name(str, name, nlen)) + return 1; + } + return 0; +} + +/* returns found(true) or not */ +static int test_known(struct au_nhash *delist, char *name, int nlen) +{ + struct hlist_head *head; + struct au_vdir_dehstr *pos; + struct au_vdir_destr *str; + + head = au_name_hash(delist, name, nlen); + hlist_for_each_entry(pos, head, hash) { + str = pos->str; + AuDbg("%.*s\n", str->len, str->name); + if (au_nhash_test_name(str, name, nlen)) + return 1; + } + return 0; +} + +static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, + unsigned char d_type) +{ +#ifdef CONFIG_AUFS_SHWH + wh->wh_ino = ino; + wh->wh_type = d_type; +#endif +} + +/* ---------------------------------------------------------------------- */ + +int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, + unsigned int d_type, aufs_bindex_t bindex, + unsigned char shwh) +{ + int err; + struct au_vdir_destr *str; + struct au_vdir_wh *wh; + + AuDbg("%.*s\n", nlen, name); + AuDebugOn(!whlist->nh_num || !whlist->nh_head); + + err = -ENOMEM; + wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); + if (unlikely(!wh)) + goto out; + + err = 0; + wh->wh_bindex = bindex; + if (shwh) + au_shwh_init_wh(wh, ino, d_type); + str = &wh->wh_str; + str->len = nlen; + memcpy(str->name, name, nlen); + hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); + /* smp_mb(); */ + +out: + return err; +} + +static int append_deblk(struct au_vdir *vdir) +{ + int err; + unsigned long ul; + const unsigned int deblk_sz = vdir->vd_deblk_sz; + union au_vdir_deblk_p p, deblk_end; + unsigned char **o; + + err = -ENOMEM; + o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), + GFP_NOFS, /*may_shrink*/0); + if (unlikely(!o)) + goto out; + + vdir->vd_deblk = o; + p.deblk = kmalloc(deblk_sz, GFP_NOFS); + if (p.deblk) { + ul = vdir->vd_nblk++; + vdir->vd_deblk[ul] = p.deblk; + vdir->vd_last.ul = ul; + vdir->vd_last.p.deblk = p.deblk; + deblk_end.deblk = p.deblk + deblk_sz; + err = set_deblk_end(&p, &deblk_end); + } + +out: + return err; +} + +static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, + unsigned int d_type, struct au_nhash *delist) +{ + int err; + unsigned int sz; + const unsigned int deblk_sz = vdir->vd_deblk_sz; + union au_vdir_deblk_p p, *room, deblk_end; + struct au_vdir_dehstr *dehstr; + + p.deblk = last_deblk(vdir); + deblk_end.deblk = p.deblk + deblk_sz; + room = &vdir->vd_last.p; + AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk + || !is_deblk_end(room, &deblk_end)); + + sz = calc_size(nlen); + if (unlikely(sz > deblk_end.deblk - room->deblk)) { + err = append_deblk(vdir); + if (unlikely(err)) + goto out; + + p.deblk = last_deblk(vdir); + deblk_end.deblk = p.deblk + deblk_sz; + /* smp_mb(); */ + AuDebugOn(room->deblk != p.deblk); + } + + err = -ENOMEM; + dehstr = au_cache_alloc_vdir_dehstr(); + if (unlikely(!dehstr)) + goto out; + + dehstr->str = &room->de->de_str; + hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); + room->de->de_ino = ino; + room->de->de_type = d_type; + room->de->de_str.len = nlen; + memcpy(room->de->de_str.name, name, nlen); + + err = 0; + room->deblk += sz; + if (unlikely(set_deblk_end(room, &deblk_end))) + err = append_deblk(vdir); + /* smp_mb(); */ + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_vdir_free(struct au_vdir *vdir) +{ + unsigned char **deblk; + + deblk = vdir->vd_deblk; + while (vdir->vd_nblk--) + au_kfree_try_rcu(*deblk++); + au_kfree_try_rcu(vdir->vd_deblk); + au_cache_free_vdir(vdir); +} + +static struct au_vdir *alloc_vdir(struct file *file) +{ + struct au_vdir *vdir; + struct super_block *sb; + int err; + + sb = file->f_path.dentry->d_sb; + SiMustAnyLock(sb); + + err = -ENOMEM; + vdir = au_cache_alloc_vdir(); + if (unlikely(!vdir)) + goto out; + + vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); + if (unlikely(!vdir->vd_deblk)) + goto out_free; + + vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; + if (!vdir->vd_deblk_sz) { + /* estimate the appropriate size for deblk */ + vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); + /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ + } + vdir->vd_nblk = 0; + vdir->vd_version = 0; + vdir->vd_jiffy = 0; + err = append_deblk(vdir); + if (!err) + return vdir; /* success */ + + au_kfree_try_rcu(vdir->vd_deblk); + +out_free: + au_cache_free_vdir(vdir); +out: + vdir = ERR_PTR(err); + return vdir; +} + +static int reinit_vdir(struct au_vdir *vdir) +{ + int err; + union au_vdir_deblk_p p, deblk_end; + + while (vdir->vd_nblk > 1) { + au_kfree_try_rcu(vdir->vd_deblk[vdir->vd_nblk - 1]); + /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ + vdir->vd_nblk--; + } + p.deblk = vdir->vd_deblk[0]; + deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; + err = set_deblk_end(&p, &deblk_end); + /* keep vd_dblk_sz */ + vdir->vd_last.ul = 0; + vdir->vd_last.p.deblk = vdir->vd_deblk[0]; + vdir->vd_version = 0; + vdir->vd_jiffy = 0; + /* smp_mb(); */ + return err; +} + +/* ---------------------------------------------------------------------- */ + +#define AuFillVdir_CALLED 1 +#define AuFillVdir_WHABLE (1 << 1) +#define AuFillVdir_SHWH (1 << 2) +#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) +#define au_fset_fillvdir(flags, name) \ + do { (flags) |= AuFillVdir_##name; } while (0) +#define au_fclr_fillvdir(flags, name) \ + do { (flags) &= ~AuFillVdir_##name; } while (0) + +#ifndef CONFIG_AUFS_SHWH +#undef AuFillVdir_SHWH +#define AuFillVdir_SHWH 0 +#endif + +struct fillvdir_arg { + struct dir_context ctx; + struct file *file; + struct au_vdir *vdir; + struct au_nhash delist; + struct au_nhash whlist; + aufs_bindex_t bindex; + unsigned int flags; + int err; +}; + +static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, + loff_t offset __maybe_unused, u64 h_ino, + unsigned int d_type) +{ + struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); + char *name = (void *)__name; + struct super_block *sb; + ino_t ino; + const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); + + arg->err = 0; + sb = arg->file->f_path.dentry->d_sb; + au_fset_fillvdir(arg->flags, CALLED); + /* smp_mb(); */ + if (nlen <= AUFS_WH_PFX_LEN + || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + if (test_known(&arg->delist, name, nlen) + || au_nhash_test_known_wh(&arg->whlist, name, nlen)) + goto out; /* already exists or whiteouted */ + + arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); + if (!arg->err) { + if (unlikely(nlen > AUFS_MAX_NAMELEN)) + d_type = DT_UNKNOWN; + arg->err = append_de(arg->vdir, name, nlen, ino, + d_type, &arg->delist); + } + } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { + name += AUFS_WH_PFX_LEN; + nlen -= AUFS_WH_PFX_LEN; + if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) + goto out; /* already whiteouted */ + + ino = 0; /* just to suppress a warning */ + if (shwh) + arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, + &ino); + if (!arg->err) { + if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) + d_type = DT_UNKNOWN; + arg->err = au_nhash_append_wh + (&arg->whlist, name, nlen, ino, d_type, + arg->bindex, shwh); + } + } + +out: + if (!arg->err) + arg->vdir->vd_jiffy = jiffies; + /* smp_mb(); */ + AuTraceErr(arg->err); + return arg->err; +} + +static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, + struct au_nhash *whlist, struct au_nhash *delist) +{ +#ifdef CONFIG_AUFS_SHWH + int err; + unsigned int nh, u; + struct hlist_head *head; + struct au_vdir_wh *pos; + struct hlist_node *n; + char *p, *o; + struct au_vdir_destr *destr; + + AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); + + err = -ENOMEM; + o = p = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = 0; + nh = whlist->nh_num; + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + p += AUFS_WH_PFX_LEN; + for (u = 0; u < nh; u++) { + head = whlist->nh_head + u; + hlist_for_each_entry_safe(pos, n, head, wh_hash) { + destr = &pos->wh_str; + memcpy(p, destr->name, destr->len); + err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, + pos->wh_ino, pos->wh_type, delist); + if (unlikely(err)) + break; + } + } + + free_page((unsigned long)o); + +out: + AuTraceErr(err); + return err; +#else + return 0; +#endif +} + +static int au_do_read_vdir(struct fillvdir_arg *arg) +{ + int err; + unsigned int rdhash; + loff_t offset; + aufs_bindex_t bbot, bindex, btop; + unsigned char shwh; + struct file *hf, *file; + struct super_block *sb; + + file = arg->file; + sb = file->f_path.dentry->d_sb; + SiMustAnyLock(sb); + + rdhash = au_sbi(sb)->si_rdhash; + if (!rdhash) + rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); + err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); + if (unlikely(err)) + goto out_delist; + + err = 0; + arg->flags = 0; + shwh = 0; + if (au_opt_test(au_mntflags(sb), SHWH)) { + shwh = 1; + au_fset_fillvdir(arg->flags, SHWH); + } + btop = au_fbtop(file); + bbot = au_fbbot_dir(file); + for (bindex = btop; !err && bindex <= bbot; bindex++) { + hf = au_hf_dir(file, bindex); + if (!hf) + continue; + + offset = vfsub_llseek(hf, 0, SEEK_SET); + err = offset; + if (unlikely(offset)) + break; + + arg->bindex = bindex; + au_fclr_fillvdir(arg->flags, WHABLE); + if (shwh + || (bindex != bbot + && au_br_whable(au_sbr_perm(sb, bindex)))) + au_fset_fillvdir(arg->flags, WHABLE); + do { + arg->err = 0; + au_fclr_fillvdir(arg->flags, CALLED); + /* smp_mb(); */ + err = vfsub_iterate_dir(hf, &arg->ctx); + if (err >= 0) + err = arg->err; + } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); + + /* + * dir_relax() may be good for concurrency, but aufs should not + * use it since it will cause a lockdep problem. + */ + } + + if (!err && shwh) + err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); + + au_nhash_wh_free(&arg->whlist); + +out_delist: + au_nhash_de_free(&arg->delist); +out: + return err; +} + +static int read_vdir(struct file *file, int may_read) +{ + int err; + unsigned long expire; + unsigned char do_read; + struct fillvdir_arg arg = { + .ctx = { + .actor = fillvdir + } + }; + struct inode *inode; + struct au_vdir *vdir, *allocated; + + err = 0; + inode = file_inode(file); + IMustLock(inode); + IiMustWriteLock(inode); + SiMustAnyLock(inode->i_sb); + + allocated = NULL; + do_read = 0; + expire = au_sbi(inode->i_sb)->si_rdcache; + vdir = au_ivdir(inode); + if (!vdir) { + do_read = 1; + vdir = alloc_vdir(file); + err = PTR_ERR(vdir); + if (IS_ERR(vdir)) + goto out; + err = 0; + allocated = vdir; + } else if (may_read + && (!inode_eq_iversion(inode, vdir->vd_version) + || time_after(jiffies, vdir->vd_jiffy + expire))) { + do_read = 1; + err = reinit_vdir(vdir); + if (unlikely(err)) + goto out; + } + + if (!do_read) + return 0; /* success */ + + arg.file = file; + arg.vdir = vdir; + err = au_do_read_vdir(&arg); + if (!err) { + /* file->f_pos = 0; */ /* todo: ctx->pos? */ + vdir->vd_version = inode_query_iversion(inode); + vdir->vd_last.ul = 0; + vdir->vd_last.p.deblk = vdir->vd_deblk[0]; + if (allocated) + au_set_ivdir(inode, allocated); + } else if (allocated) + au_vdir_free(allocated); + +out: + return err; +} + +static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) +{ + int err, rerr; + unsigned long ul, n; + const unsigned int deblk_sz = src->vd_deblk_sz; + + AuDebugOn(tgt->vd_nblk != 1); + + err = -ENOMEM; + if (tgt->vd_nblk < src->vd_nblk) { + unsigned char **p; + + p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, + GFP_NOFS, /*may_shrink*/0); + if (unlikely(!p)) + goto out; + tgt->vd_deblk = p; + } + + if (tgt->vd_deblk_sz != deblk_sz) { + unsigned char *p; + + tgt->vd_deblk_sz = deblk_sz; + p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, + /*may_shrink*/1); + if (unlikely(!p)) + goto out; + tgt->vd_deblk[0] = p; + } + memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); + tgt->vd_version = src->vd_version; + tgt->vd_jiffy = src->vd_jiffy; + + n = src->vd_nblk; + for (ul = 1; ul < n; ul++) { + tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, + GFP_NOFS); + if (unlikely(!tgt->vd_deblk[ul])) + goto out; + tgt->vd_nblk++; + } + tgt->vd_nblk = n; + tgt->vd_last.ul = tgt->vd_last.ul; + tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; + tgt->vd_last.p.deblk += src->vd_last.p.deblk + - src->vd_deblk[src->vd_last.ul]; + /* smp_mb(); */ + return 0; /* success */ + +out: + rerr = reinit_vdir(tgt); + BUG_ON(rerr); + return err; +} + +int au_vdir_init(struct file *file) +{ + int err; + struct inode *inode; + struct au_vdir *vdir_cache, *allocated; + + /* test file->f_pos here instead of ctx->pos */ + err = read_vdir(file, !file->f_pos); + if (unlikely(err)) + goto out; + + allocated = NULL; + vdir_cache = au_fvdir_cache(file); + if (!vdir_cache) { + vdir_cache = alloc_vdir(file); + err = PTR_ERR(vdir_cache); + if (IS_ERR(vdir_cache)) + goto out; + allocated = vdir_cache; + } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { + /* test file->f_pos here instead of ctx->pos */ + err = reinit_vdir(vdir_cache); + if (unlikely(err)) + goto out; + } else + return 0; /* success */ + + inode = file_inode(file); + err = copy_vdir(vdir_cache, au_ivdir(inode)); + if (!err) { + file->f_version = inode_query_iversion(inode); + if (allocated) + au_set_fvdir_cache(file, allocated); + } else if (allocated) + au_vdir_free(allocated); + +out: + return err; +} + +static loff_t calc_offset(struct au_vdir *vdir) +{ + loff_t offset; + union au_vdir_deblk_p p; + + p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; + offset = vdir->vd_last.p.deblk - p.deblk; + offset += vdir->vd_deblk_sz * vdir->vd_last.ul; + return offset; +} + +/* returns true or false */ +static int seek_vdir(struct file *file, struct dir_context *ctx) +{ + int valid; + unsigned int deblk_sz; + unsigned long ul, n; + loff_t offset; + union au_vdir_deblk_p p, deblk_end; + struct au_vdir *vdir_cache; + + valid = 1; + vdir_cache = au_fvdir_cache(file); + offset = calc_offset(vdir_cache); + AuDbg("offset %lld\n", offset); + if (ctx->pos == offset) + goto out; + + vdir_cache->vd_last.ul = 0; + vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; + if (!ctx->pos) + goto out; + + valid = 0; + deblk_sz = vdir_cache->vd_deblk_sz; + ul = div64_u64(ctx->pos, deblk_sz); + AuDbg("ul %lu\n", ul); + if (ul >= vdir_cache->vd_nblk) + goto out; + + n = vdir_cache->vd_nblk; + for (; ul < n; ul++) { + p.deblk = vdir_cache->vd_deblk[ul]; + deblk_end.deblk = p.deblk + deblk_sz; + offset = ul; + offset *= deblk_sz; + while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { + unsigned int l; + + l = calc_size(p.de->de_str.len); + offset += l; + p.deblk += l; + } + if (!is_deblk_end(&p, &deblk_end)) { + valid = 1; + vdir_cache->vd_last.ul = ul; + vdir_cache->vd_last.p = p; + break; + } + } + +out: + /* smp_mb(); */ + if (!valid) + AuDbg("valid %d\n", !valid); + return valid; +} + +int au_vdir_fill_de(struct file *file, struct dir_context *ctx) +{ + unsigned int l, deblk_sz; + union au_vdir_deblk_p deblk_end; + struct au_vdir *vdir_cache; + struct au_vdir_de *de; + + if (!seek_vdir(file, ctx)) + return 0; + + vdir_cache = au_fvdir_cache(file); + deblk_sz = vdir_cache->vd_deblk_sz; + while (1) { + deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; + deblk_end.deblk += deblk_sz; + while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { + de = vdir_cache->vd_last.p.de; + AuDbg("%.*s, off%lld, i%lu, dt%d\n", + de->de_str.len, de->de_str.name, ctx->pos, + (unsigned long)de->de_ino, de->de_type); + if (unlikely(!dir_emit(ctx, de->de_str.name, + de->de_str.len, de->de_ino, + de->de_type))) { + /* todo: ignore the error caused by udba? */ + /* return err; */ + return 0; + } + + l = calc_size(de->de_str.len); + vdir_cache->vd_last.p.deblk += l; + ctx->pos += l; + } + if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { + vdir_cache->vd_last.ul++; + vdir_cache->vd_last.p.deblk + = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; + ctx->pos = deblk_sz * vdir_cache->vd_last.ul; + continue; + } + break; + } + + /* smp_mb(); */ + return 0; +} diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c new file mode 100644 index 000000000000..2e09b0e689e1 --- /dev/null +++ b/fs/aufs/vfsub.c @@ -0,0 +1,885 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for VFS + */ + +#include +#include +#include +#include +#include +#include "aufs.h" + +#ifdef CONFIG_AUFS_BR_FUSE +int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) +{ + if (!au_test_fuse(h_sb) || !au_userns) + return 0; + + return is_current_mnt_ns(mnt) ? 0 : -EACCES; +} +#endif + +int vfsub_sync_filesystem(struct super_block *h_sb, int wait) +{ + int err; + + lockdep_off(); + down_read(&h_sb->s_umount); + err = __sync_filesystem(h_sb, wait); + up_read(&h_sb->s_umount); + lockdep_on(); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +int vfsub_update_h_iattr(struct path *h_path, int *did) +{ + int err; + struct kstat st; + struct super_block *h_sb; + + /* for remote fs, leave work for its getattr or d_revalidate */ + /* for bad i_attr fs, handle them in aufs_getattr() */ + /* still some fs may acquire i_mutex. we need to skip them */ + err = 0; + if (!did) + did = &err; + h_sb = h_path->dentry->d_sb; + *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); + if (*did) + err = vfsub_getattr(h_path, &st); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct file *vfsub_dentry_open(struct path *path, int flags) +{ + return dentry_open(path, flags /* | __FMODE_NONOTIFY */, + current_cred()); +} + +struct file *vfsub_filp_open(const char *path, int oflags, int mode) +{ + struct file *file; + + lockdep_off(); + file = filp_open(path, + oflags /* | __FMODE_NONOTIFY */, + mode); + lockdep_on(); + if (IS_ERR(file)) + goto out; + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + +out: + return file; +} + +/* + * Ideally this function should call VFS:do_last() in order to keep all its + * checkings. But it is very hard for aufs to regenerate several VFS internal + * structure such as nameidata. This is a second (or third) best approach. + * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). + */ +int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, + struct vfsub_aopen_args *args) +{ + int err; + struct au_branch *br = args->br; + struct file *file = args->file; + /* copied from linux/fs/namei.c:atomic_open() */ + struct dentry *const DENTRY_NOT_SET = (void *)-1UL; + + IMustLock(dir); + AuDebugOn(!dir->i_op->atomic_open); + + err = au_br_test_oflag(args->open_flag, br); + if (unlikely(err)) + goto out; + + au_lcnt_inc(&br->br_nfiles); + file->f_path.dentry = DENTRY_NOT_SET; + file->f_path.mnt = au_br_mnt(br); + AuDbg("%ps\n", dir->i_op->atomic_open); + err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, + args->create_mode); + if (unlikely(err < 0)) { + au_lcnt_dec(&br->br_nfiles); + goto out; + } + + /* temporary workaround for nfsv4 branch */ + if (au_test_nfs(dir->i_sb)) + nfs_mark_for_revalidate(dir); + + if (file->f_mode & FMODE_CREATED) + fsnotify_create(dir, dentry); + if (!(file->f_mode & FMODE_OPENED)) { + au_lcnt_dec(&br->br_nfiles); + goto out; + } + + /* todo: call VFS:may_open() here */ + /* todo: ima_file_check() too? */ + if (!err && (args->open_flag & __FMODE_EXEC)) + err = deny_write_access(file); + if (!err) + fsnotify_open(file); + else + au_lcnt_dec(&br->br_nfiles); + /* note that the file is created and still opened */ + +out: + return err; +} + +int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) +{ + int err; + + err = kern_path(name, flags, path); + if (!err && d_is_positive(path->dentry)) + vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ + return err; +} + +struct dentry *vfsub_lookup_one_len_unlocked(const char *name, + struct dentry *parent, int len) +{ + struct path path = { + .mnt = NULL + }; + + path.dentry = lookup_one_len_unlocked(name, parent, len); + if (IS_ERR(path.dentry)) + goto out; + if (d_is_positive(path.dentry)) + vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ + +out: + AuTraceErrPtr(path.dentry); + return path.dentry; +} + +struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, + int len) +{ + struct path path = { + .mnt = NULL + }; + + /* VFS checks it too, but by WARN_ON_ONCE() */ + IMustLock(d_inode(parent)); + + path.dentry = lookup_one_len(name, parent, len); + if (IS_ERR(path.dentry)) + goto out; + if (d_is_positive(path.dentry)) + vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ + +out: + AuTraceErrPtr(path.dentry); + return path.dentry; +} + +void vfsub_call_lkup_one(void *args) +{ + struct vfsub_lkup_one_args *a = args; + *a->errp = vfsub_lkup_one(a->name, a->parent); +} + +/* ---------------------------------------------------------------------- */ + +struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2) +{ + struct dentry *d; + + lockdep_off(); + d = lock_rename(d1, d2); + lockdep_on(); + au_hn_suspend(hdir1); + if (hdir1 != hdir2) + au_hn_suspend(hdir2); + + return d; +} + +void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2) +{ + au_hn_resume(hdir1); + if (hdir1 != hdir2) + au_hn_resume(hdir2); + lockdep_off(); + unlock_rename(d1, d2); + lockdep_on(); +} + +/* ---------------------------------------------------------------------- */ + +int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_mknod(path, d, mode, 0); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_create(dir, path->dentry, mode, want_excl); + lockdep_on(); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_symlink(path, d, symname); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_symlink(dir, path->dentry, symname); + lockdep_on(); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_mknod(path, d, mode, new_encode_dev(dev)); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_mknod(dir, path->dentry, mode, dev); + lockdep_on(); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +static int au_test_nlink(struct inode *inode) +{ + const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ + + if (!au_test_fs_no_limit_nlink(inode->i_sb) + || inode->i_nlink < link_max) + return 0; + return -EMLINK; +} + +int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, + struct inode **delegated_inode) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + err = au_test_nlink(d_inode(src_dentry)); + if (unlikely(err)) + return err; + + /* we don't call may_linkat() */ + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_link(src_dentry, path, d); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_link(src_dentry, dir, path->dentry, delegated_inode); + lockdep_on(); + if (!err) { + struct path tmp = *path; + int did; + + /* fuse has different memory inode for the same inumber */ + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + tmp.dentry = src_dentry; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct path *path, + struct inode **delegated_inode, unsigned int flags) +{ + int err; + struct path tmp = { + .mnt = path->mnt + }; + struct dentry *d; + + IMustLock(dir); + IMustLock(src_dir); + + d = path->dentry; + path->dentry = d->d_parent; + tmp.dentry = src_dentry->d_parent; + err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_rename(src_dir, src_dentry, dir, path->dentry, + delegated_inode, flags); + lockdep_on(); + if (!err) { + int did; + + tmp.dentry = d->d_parent; + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = src_dentry; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + tmp.dentry = src_dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_mkdir(struct inode *dir, struct path *path, int mode) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_mkdir(path, d, mode); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_mkdir(dir, path->dentry, mode); + lockdep_on(); + if (!err) { + struct path tmp = *path; + int did; + + vfsub_update_h_iattr(&tmp, &did); + if (did) { + tmp.dentry = path->dentry->d_parent; + vfsub_update_h_iattr(&tmp, /*did*/NULL); + } + /*ignore*/ + } + +out: + return err; +} + +int vfsub_rmdir(struct inode *dir, struct path *path) +{ + int err; + struct dentry *d; + + IMustLock(dir); + + d = path->dentry; + path->dentry = d->d_parent; + err = security_path_rmdir(path, d); + path->dentry = d; + if (unlikely(err)) + goto out; + + lockdep_off(); + err = vfs_rmdir(dir, path->dentry); + lockdep_on(); + if (!err) { + struct path tmp = { + .dentry = path->dentry->d_parent, + .mnt = path->mnt + }; + + vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ + } + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* todo: support mmap_sem? */ +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + + lockdep_off(); + err = vfs_read(file, ubuf, count, ppos); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + + lockdep_off(); + err = kernel_read(file, kbuf, count, ppos); + lockdep_on(); + AuTraceErr(err); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + + lockdep_off(); + err = vfs_write(file, ubuf, count, ppos); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) +{ + ssize_t err; + + lockdep_off(); + err = kernel_write(file, kbuf, count, ppos); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +int vfsub_flush(struct file *file, fl_owner_t id) +{ + int err; + + err = 0; + if (file->f_op->flush) { + if (!au_test_nfs(file->f_path.dentry->d_sb)) + err = file->f_op->flush(file, id); + else { + lockdep_off(); + err = file->f_op->flush(file, id); + lockdep_on(); + } + if (!err) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); + /*ignore*/ + } + return err; +} + +int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) +{ + int err; + + AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); + + lockdep_off(); + err = iterate_dir(file, ctx); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ + + return err; +} + +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + long err; + + lockdep_off(); + err = do_splice_to(in, ppos, pipe, len, flags); + lockdep_on(); + file_accessed(in); + if (err >= 0) + vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + long err; + + lockdep_off(); + err = do_splice_from(pipe, out, ppos, len, flags); + lockdep_on(); + if (err >= 0) + vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ + return err; +} + +int vfsub_fsync(struct file *file, struct path *path, int datasync) +{ + int err; + + /* file can be NULL */ + lockdep_off(); + err = vfs_fsync(file, datasync); + lockdep_on(); + if (!err) { + if (!path) { + AuDebugOn(!file); + path = &file->f_path; + } + vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ + } + return err; +} + +/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ +int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, + struct file *h_file) +{ + int err; + struct inode *h_inode; + struct super_block *h_sb; + + if (!h_file) { + err = vfsub_truncate(h_path, length); + goto out; + } + + h_inode = d_inode(h_path->dentry); + h_sb = h_inode->i_sb; + lockdep_off(); + sb_start_write(h_sb); + lockdep_on(); + err = locks_verify_truncate(h_inode, h_file, length); + if (!err) + err = security_path_truncate(h_path); + if (!err) { + lockdep_off(); + err = do_truncate(h_path->dentry, length, attr, h_file); + lockdep_on(); + } + lockdep_off(); + sb_end_write(h_sb); + lockdep_on(); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_vfsub_mkdir_args { + int *errp; + struct inode *dir; + struct path *path; + int mode; +}; + +static void au_call_vfsub_mkdir(void *args) +{ + struct au_vfsub_mkdir_args *a = args; + *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); +} + +int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) +{ + int err, do_sio, wkq_err; + + do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); + if (!do_sio) { + lockdep_off(); + err = vfsub_mkdir(dir, path, mode); + lockdep_on(); + } else { + struct au_vfsub_mkdir_args args = { + .errp = &err, + .dir = dir, + .path = path, + .mode = mode + }; + wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} + +struct au_vfsub_rmdir_args { + int *errp; + struct inode *dir; + struct path *path; +}; + +static void au_call_vfsub_rmdir(void *args) +{ + struct au_vfsub_rmdir_args *a = args; + *a->errp = vfsub_rmdir(a->dir, a->path); +} + +int vfsub_sio_rmdir(struct inode *dir, struct path *path) +{ + int err, do_sio, wkq_err; + + do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); + if (!do_sio) { + lockdep_off(); + err = vfsub_rmdir(dir, path); + lockdep_on(); + } else { + struct au_vfsub_rmdir_args args = { + .errp = &err, + .dir = dir, + .path = path + }; + wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct notify_change_args { + int *errp; + struct path *path; + struct iattr *ia; + struct inode **delegated_inode; +}; + +static void call_notify_change(void *args) +{ + struct notify_change_args *a = args; + struct inode *h_inode; + + h_inode = d_inode(a->path->dentry); + IMustLock(h_inode); + + *a->errp = -EPERM; + if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { + lockdep_off(); + *a->errp = notify_change(a->path->dentry, a->ia, + a->delegated_inode); + lockdep_on(); + if (!*a->errp) + vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ + } + AuTraceErr(*a->errp); +} + +int vfsub_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode) +{ + int err; + struct notify_change_args args = { + .errp = &err, + .path = path, + .ia = ia, + .delegated_inode = delegated_inode + }; + + call_notify_change(&args); + + return err; +} + +int vfsub_sio_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode) +{ + int err, wkq_err; + struct notify_change_args args = { + .errp = &err, + .path = path, + .ia = ia, + .delegated_inode = delegated_inode + }; + + wkq_err = au_wkq_wait(call_notify_change, &args); + if (unlikely(wkq_err)) + err = wkq_err; + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct unlink_args { + int *errp; + struct inode *dir; + struct path *path; + struct inode **delegated_inode; +}; + +static void call_unlink(void *args) +{ + struct unlink_args *a = args; + struct dentry *d = a->path->dentry; + struct inode *h_inode; + const int stop_sillyrename = (au_test_nfs(d->d_sb) + && au_dcount(d) == 1); + + IMustLock(a->dir); + + a->path->dentry = d->d_parent; + *a->errp = security_path_unlink(a->path, d); + a->path->dentry = d; + if (unlikely(*a->errp)) + return; + + if (!stop_sillyrename) + dget(d); + h_inode = NULL; + if (d_is_positive(d)) { + h_inode = d_inode(d); + ihold(h_inode); + } + + lockdep_off(); + *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); + lockdep_on(); + if (!*a->errp) { + struct path tmp = { + .dentry = d->d_parent, + .mnt = a->path->mnt + }; + vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ + } + + if (!stop_sillyrename) + dput(d); + if (h_inode) + iput(h_inode); + + AuTraceErr(*a->errp); +} + +/* + * @dir: must be locked. + * @dentry: target dentry. + */ +int vfsub_unlink(struct inode *dir, struct path *path, + struct inode **delegated_inode, int force) +{ + int err; + struct unlink_args args = { + .errp = &err, + .dir = dir, + .path = path, + .delegated_inode = delegated_inode + }; + + if (!force) + call_unlink(&args); + else { + int wkq_err; + + wkq_err = au_wkq_wait(call_unlink, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h new file mode 100644 index 000000000000..51e677c7f6b7 --- /dev/null +++ b/fs/aufs/vfsub.h @@ -0,0 +1,354 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * sub-routines for VFS + */ + +#ifndef __AUFS_VFSUB_H__ +#define __AUFS_VFSUB_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include "debug.h" + +/* copied from linux/fs/internal.h */ +/* todo: BAD approach!! */ +extern void __mnt_drop_write(struct vfsmount *); +extern struct file *alloc_empty_file(int, const struct cred *); + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for lower inode */ +/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ +/* reduce? gave up. */ +enum { + AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ + AuLsc_I_PARENT, /* lower inode, parent first */ + AuLsc_I_PARENT2, /* copyup dirs */ + AuLsc_I_PARENT3, /* copyup wh */ + AuLsc_I_CHILD, + AuLsc_I_CHILD2, + AuLsc_I_End +}; + +/* to debug easier, do not make them inlined functions */ +#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) +#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) + +/* ---------------------------------------------------------------------- */ + +static inline void vfsub_drop_nlink(struct inode *inode) +{ + AuDebugOn(!inode->i_nlink); + drop_nlink(inode); +} + +static inline void vfsub_dead_dir(struct inode *inode) +{ + AuDebugOn(!S_ISDIR(inode->i_mode)); + inode->i_flags |= S_DEAD; + clear_nlink(inode); +} + +static inline int vfsub_native_ro(struct inode *inode) +{ + return sb_rdonly(inode->i_sb) + || IS_RDONLY(inode) + /* || IS_APPEND(inode) */ + || IS_IMMUTABLE(inode); +} + +#ifdef CONFIG_AUFS_BR_FUSE +int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); +#else +AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); +#endif + +int vfsub_sync_filesystem(struct super_block *h_sb, int wait); + +/* ---------------------------------------------------------------------- */ + +int vfsub_update_h_iattr(struct path *h_path, int *did); +struct file *vfsub_dentry_open(struct path *path, int flags); +struct file *vfsub_filp_open(const char *path, int oflags, int mode); +struct au_branch; +struct vfsub_aopen_args { + struct file *file; + unsigned int open_flag; + umode_t create_mode; + struct au_branch *br; +}; +int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, + struct vfsub_aopen_args *args); +int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); + +struct dentry *vfsub_lookup_one_len_unlocked(const char *name, + struct dentry *parent, int len); +struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, + int len); + +struct vfsub_lkup_one_args { + struct dentry **errp; + struct qstr *name; + struct dentry *parent; +}; + +static inline struct dentry *vfsub_lkup_one(struct qstr *name, + struct dentry *parent) +{ + return vfsub_lookup_one_len(name->name, parent, name->len); +} + +void vfsub_call_lkup_one(void *args); + +/* ---------------------------------------------------------------------- */ + +static inline int vfsub_mnt_want_write(struct vfsmount *mnt) +{ + int err; + + lockdep_off(); + err = mnt_want_write(mnt); + lockdep_on(); + return err; +} + +static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) +{ + lockdep_off(); + mnt_drop_write(mnt); + lockdep_on(); +} + +#if 0 /* reserved */ +static inline void vfsub_mnt_drop_write_file(struct file *file) +{ + lockdep_off(); + mnt_drop_write_file(file); + lockdep_on(); +} +#endif + +/* ---------------------------------------------------------------------- */ + +struct au_hinode; +struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2); +void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, + struct dentry *d2, struct au_hinode *hdir2); + +int vfsub_create(struct inode *dir, struct path *path, int mode, + bool want_excl); +int vfsub_symlink(struct inode *dir, struct path *path, + const char *symname); +int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); +int vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct path *path, struct inode **delegated_inode); +int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, + struct inode *hdir, struct path *path, + struct inode **delegated_inode, unsigned int flags); +int vfsub_mkdir(struct inode *dir, struct path *path, int mode); +int vfsub_rmdir(struct inode *dir, struct path *path); + +/* ---------------------------------------------------------------------- */ + +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos); +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos); +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos); +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos); +int vfsub_flush(struct file *file, fl_owner_t id); +int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); + +static inline loff_t vfsub_f_size_read(struct file *file) +{ + return i_size_read(file_inode(file)); +} + +static inline unsigned int vfsub_file_flags(struct file *file) +{ + unsigned int flags; + + spin_lock(&file->f_lock); + flags = file->f_flags; + spin_unlock(&file->f_lock); + + return flags; +} + +static inline int vfsub_file_execed(struct file *file) +{ + /* todo: direct access f_flags */ + return !!(vfsub_file_flags(file) & __FMODE_EXEC); +} + +#if 0 /* reserved */ +static inline void vfsub_file_accessed(struct file *h_file) +{ + file_accessed(h_file); + vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ +} +#endif + +#if 0 /* reserved */ +static inline void vfsub_touch_atime(struct vfsmount *h_mnt, + struct dentry *h_dentry) +{ + struct path h_path = { + .dentry = h_dentry, + .mnt = h_mnt + }; + touch_atime(&h_path); + vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ +} +#endif + +static inline int vfsub_update_time(struct inode *h_inode, + struct timespec64 *ts, int flags) +{ + return update_time(h_inode, ts, flags); + /* no vfsub_update_h_iattr() since we don't have struct path */ +} + +#ifdef CONFIG_FS_POSIX_ACL +static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) +{ + int err; + + err = posix_acl_chmod(h_inode, h_mode); + if (err == -EOPNOTSUPP) + err = 0; + return err; +} +#else +AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode); +#endif + +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); + +static inline long vfsub_truncate(struct path *path, loff_t length) +{ + long err; + + lockdep_off(); + err = vfs_truncate(path, length); + lockdep_on(); + return err; +} + +int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, + struct file *h_file); +int vfsub_fsync(struct file *file, struct path *path, int datasync); + +/* + * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such + * ioctl. + */ +static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, + loff_t len) +{ + loff_t err; + + lockdep_off(); + err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); + lockdep_on(); + + return err; +} + +/* copy_file_range(2) is a systemcall */ +static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, + struct file *dst, loff_t dst_pos, + size_t len, unsigned int flags) +{ + ssize_t ssz; + + lockdep_off(); + ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); + lockdep_on(); + + return ssz; +} + +/* ---------------------------------------------------------------------- */ + +static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t err; + + lockdep_off(); + err = vfs_llseek(file, offset, origin); + lockdep_on(); + return err; +} + +/* ---------------------------------------------------------------------- */ + +int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); +int vfsub_sio_rmdir(struct inode *dir, struct path *path); +int vfsub_sio_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode); +int vfsub_notify_change(struct path *path, struct iattr *ia, + struct inode **delegated_inode); +int vfsub_unlink(struct inode *dir, struct path *path, + struct inode **delegated_inode, int force); + +static inline int vfsub_getattr(const struct path *path, struct kstat *st) +{ + return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); +} + +/* ---------------------------------------------------------------------- */ + +static inline int vfsub_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + int err; + + lockdep_off(); + err = vfs_setxattr(dentry, name, value, size, flags); + lockdep_on(); + + return err; +} + +static inline int vfsub_removexattr(struct dentry *dentry, const char *name) +{ + int err; + + lockdep_off(); + err = vfs_removexattr(dentry, name); + lockdep_on(); + + return err; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_VFSUB_H__ */ diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c new file mode 100644 index 000000000000..64954145c0ec --- /dev/null +++ b/fs/aufs/wbr_policy.c @@ -0,0 +1,830 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * policies for selecting one among multiple writable branches + */ + +#include +#include "aufs.h" + +/* subset of cpup_attr() */ +static noinline_for_stack +int au_cpdown_attr(struct path *h_path, struct dentry *h_src) +{ + int err, sbits; + struct iattr ia; + struct inode *h_isrc; + + h_isrc = d_inode(h_src); + ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; + ia.ia_mode = h_isrc->i_mode; + ia.ia_uid = h_isrc->i_uid; + ia.ia_gid = h_isrc->i_gid; + sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); + au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); + /* no delegation since it is just created */ + err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); + + /* is this nfs only? */ + if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { + ia.ia_valid = ATTR_FORCE | ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); + } + + return err; +} + +#define AuCpdown_PARENT_OPQ 1 +#define AuCpdown_WHED (1 << 1) +#define AuCpdown_MADE_DIR (1 << 2) +#define AuCpdown_DIROPQ (1 << 3) +#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) +#define au_fset_cpdown(flags, name) \ + do { (flags) |= AuCpdown_##name; } while (0) +#define au_fclr_cpdown(flags, name) \ + do { (flags) &= ~AuCpdown_##name; } while (0) + +static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, + unsigned int *flags) +{ + int err; + struct dentry *opq_dentry; + + opq_dentry = au_diropq_create(dentry, bdst); + err = PTR_ERR(opq_dentry); + if (IS_ERR(opq_dentry)) + goto out; + dput(opq_dentry); + au_fset_cpdown(*flags, DIROPQ); + +out: + return err; +} + +static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, + struct inode *dir, aufs_bindex_t bdst) +{ + int err; + struct path h_path; + struct au_branch *br; + + br = au_sbr(dentry->d_sb, bdst); + h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) + goto out; + + err = 0; + if (d_is_positive(h_path.dentry)) { + h_path.mnt = au_br_mnt(br); + err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, + dentry); + } + dput(h_path.dentry); + +out: + return err; +} + +static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, + struct au_pin *pin, + struct dentry *h_parent, void *arg) +{ + int err, rerr; + aufs_bindex_t bopq, btop; + struct path h_path; + struct dentry *parent; + struct inode *h_dir, *h_inode, *inode, *dir; + unsigned int *flags = arg; + + btop = au_dbtop(dentry); + /* dentry is di-locked */ + parent = dget_parent(dentry); + dir = d_inode(parent); + h_dir = d_inode(h_parent); + AuDebugOn(h_dir != au_h_iptr(dir, bdst)); + IMustLock(h_dir); + + err = au_lkup_neg(dentry, bdst, /*wh*/0); + if (unlikely(err < 0)) + goto out; + h_path.dentry = au_h_dptr(dentry, bdst); + h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); + err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, 0755); + if (unlikely(err)) + goto out_put; + au_fset_cpdown(*flags, MADE_DIR); + + bopq = au_dbdiropq(dentry); + au_fclr_cpdown(*flags, WHED); + au_fclr_cpdown(*flags, DIROPQ); + if (au_dbwh(dentry) == bdst) + au_fset_cpdown(*flags, WHED); + if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) + au_fset_cpdown(*flags, PARENT_OPQ); + h_inode = d_inode(h_path.dentry); + inode_lock_nested(h_inode, AuLsc_I_CHILD); + if (au_ftest_cpdown(*flags, WHED)) { + err = au_cpdown_dir_opq(dentry, bdst, flags); + if (unlikely(err)) { + inode_unlock(h_inode); + goto out_dir; + } + } + + err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); + inode_unlock(h_inode); + if (unlikely(err)) + goto out_opq; + + if (au_ftest_cpdown(*flags, WHED)) { + err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); + if (unlikely(err)) + goto out_opq; + } + + inode = d_inode(dentry); + if (au_ibbot(inode) < bdst) + au_set_ibbot(inode, bdst); + au_set_h_iptr(inode, bdst, au_igrab(h_inode), + au_hi_flags(inode, /*isdir*/1)); + au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); + goto out; /* success */ + + /* revert */ +out_opq: + if (au_ftest_cpdown(*flags, DIROPQ)) { + inode_lock_nested(h_inode, AuLsc_I_CHILD); + rerr = au_diropq_remove(dentry, bdst); + inode_unlock(h_inode); + if (unlikely(rerr)) { + AuIOErr("failed removing diropq for %pd b%d (%d)\n", + dentry, bdst, rerr); + err = -EIO; + goto out; + } + } +out_dir: + if (au_ftest_cpdown(*flags, MADE_DIR)) { + rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); + if (unlikely(rerr)) { + AuIOErr("failed removing %pd b%d (%d)\n", + dentry, bdst, rerr); + err = -EIO; + } + } +out_put: + au_set_h_dptr(dentry, bdst, NULL); + if (au_dbbot(dentry) == bdst) + au_update_dbbot(dentry); +out: + dput(parent); + return err; +} + +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + unsigned int flags; + + flags = 0; + err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* policies for create */ + +int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) +{ + int err, i, j, ndentry; + aufs_bindex_t bopq; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries, *parent, *d; + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + parent = dget_parent(dentry); + err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); + if (unlikely(err)) + goto out_free; + + err = bindex; + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + d = dentries[j]; + di_read_lock_parent2(d, !AuLock_IR); + bopq = au_dbdiropq(d); + di_read_unlock(d, !AuLock_IR); + if (bopq >= 0 && bopq < err) + err = bopq; + } + } + +out_free: + dput(parent); + au_dpages_free(&dpages); +out: + return err; +} + +static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) +{ + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) + return bindex; + return -EROFS; +} + +/* top down parent */ +static int au_wbr_create_tdp(struct dentry *dentry, + unsigned int flags __maybe_unused) +{ + int err; + aufs_bindex_t btop, bindex; + struct super_block *sb; + struct dentry *parent, *h_parent; + + sb = dentry->d_sb; + btop = au_dbtop(dentry); + err = btop; + if (!au_br_rdonly(au_sbr(sb, btop))) + goto out; + + err = -EROFS; + parent = dget_parent(dentry); + for (bindex = au_dbtop(parent); bindex < btop; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || d_is_negative(h_parent)) + continue; + + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = bindex; + break; + } + } + dput(parent); + + /* bottom up here */ + if (unlikely(err < 0)) { + err = au_wbr_bu(sb, btop - 1); + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + } + +out: + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* an exception for the policy other than tdp */ +static int au_wbr_create_exp(struct dentry *dentry) +{ + int err; + aufs_bindex_t bwh, bdiropq; + struct dentry *parent; + + err = -1; + bwh = au_dbwh(dentry); + parent = dget_parent(dentry); + bdiropq = au_dbdiropq(parent); + if (bwh >= 0) { + if (bdiropq >= 0) + err = min(bdiropq, bwh); + else + err = bwh; + AuDbg("%d\n", err); + } else if (bdiropq >= 0) { + err = bdiropq; + AuDbg("%d\n", err); + } + dput(parent); + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + + if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) + err = -1; + + AuDbg("%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* round robin */ +static int au_wbr_create_init_rr(struct super_block *sb) +{ + int err; + + err = au_wbr_bu(sb, au_sbbot(sb)); + atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ + /* smp_mb(); */ + + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) +{ + int err, nbr; + unsigned int u; + aufs_bindex_t bindex, bbot; + struct super_block *sb; + atomic_t *next; + + err = au_wbr_create_exp(dentry); + if (err >= 0) + goto out; + + sb = dentry->d_sb; + next = &au_sbi(sb)->si_wbr_rr_next; + bbot = au_sbbot(sb); + nbr = bbot + 1; + for (bindex = 0; bindex <= bbot; bindex++) { + if (!au_ftest_wbr(flags, DIR)) { + err = atomic_dec_return(next) + 1; + /* modulo for 0 is meaningless */ + if (unlikely(!err)) + err = atomic_dec_return(next) + 1; + } else + err = atomic_read(next); + AuDbg("%d\n", err); + u = err; + err = u % nbr; + AuDbg("%d\n", err); + if (!au_br_rdonly(au_sbr(sb, err))) + break; + err = -EROFS; + } + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + +out: + AuDbg("%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* most free space */ +static void au_mfs(struct dentry *dentry, struct dentry *parent) +{ + struct super_block *sb; + struct au_branch *br; + struct au_wbr_mfs *mfs; + struct dentry *h_parent; + aufs_bindex_t bindex, bbot; + int err; + unsigned long long b, bavail; + struct path h_path; + /* reduce the stack usage */ + struct kstatfs *st; + + st = kmalloc(sizeof(*st), GFP_NOFS); + if (unlikely(!st)) { + AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); + return; + } + + bavail = 0; + sb = dentry->d_sb; + mfs = &au_sbi(sb)->si_wbr_mfs; + MtxMustLock(&mfs->mfs_lock); + mfs->mfs_bindex = -EROFS; + mfs->mfsrr_bytes = 0; + if (!parent) { + bindex = 0; + bbot = au_sbbot(sb); + } else { + bindex = au_dbtop(parent); + bbot = au_dbtaildir(parent); + } + + for (; bindex <= bbot; bindex++) { + if (parent) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || d_is_negative(h_parent)) + continue; + } + br = au_sbr(sb, bindex); + if (au_br_rdonly(br)) + continue; + + /* sb->s_root for NFS is unreliable */ + h_path.mnt = au_br_mnt(br); + h_path.dentry = h_path.mnt->mnt_root; + err = vfs_statfs(&h_path, st); + if (unlikely(err)) { + AuWarn1("failed statfs, b%d, %d\n", bindex, err); + continue; + } + + /* when the available size is equal, select the lower one */ + BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) + || sizeof(b) < sizeof(st->f_bsize)); + b = st->f_bavail * st->f_bsize; + br->br_wbr->wbr_bytes = b; + if (b >= bavail) { + bavail = b; + mfs->mfs_bindex = bindex; + mfs->mfs_jiffy = jiffies; + } + } + + mfs->mfsrr_bytes = bavail; + AuDbg("b%d\n", mfs->mfs_bindex); + au_kfree_rcu(st); +} + +static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) +{ + int err; + struct dentry *parent; + struct super_block *sb; + struct au_wbr_mfs *mfs; + + err = au_wbr_create_exp(dentry); + if (err >= 0) + goto out; + + sb = dentry->d_sb; + parent = NULL; + if (au_ftest_wbr(flags, PARENT)) + parent = dget_parent(dentry); + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) + || mfs->mfs_bindex < 0 + || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) + au_mfs(dentry, parent); + mutex_unlock(&mfs->mfs_lock); + err = mfs->mfs_bindex; + dput(parent); + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + +out: + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_create_init_mfs(struct super_block *sb) +{ + struct au_wbr_mfs *mfs; + + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_init(&mfs->mfs_lock); + mfs->mfs_jiffy = 0; + mfs->mfs_bindex = -EROFS; + + return 0; +} + +static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) +{ + mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +/* top down regardless parent, and then mfs */ +static int au_wbr_create_tdmfs(struct dentry *dentry, + unsigned int flags __maybe_unused) +{ + int err; + aufs_bindex_t bwh, btail, bindex, bfound, bmfs; + unsigned long long watermark; + struct super_block *sb; + struct au_wbr_mfs *mfs; + struct au_branch *br; + struct dentry *parent; + + sb = dentry->d_sb; + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) + || mfs->mfs_bindex < 0) + au_mfs(dentry, /*parent*/NULL); + watermark = mfs->mfsrr_watermark; + bmfs = mfs->mfs_bindex; + mutex_unlock(&mfs->mfs_lock); + + /* another style of au_wbr_create_exp() */ + bwh = au_dbwh(dentry); + parent = dget_parent(dentry); + btail = au_dbtaildir(parent); + if (bwh >= 0 && bwh < btail) + btail = bwh; + + err = au_wbr_nonopq(dentry, btail); + if (unlikely(err < 0)) + goto out; + btail = err; + bfound = -1; + for (bindex = 0; bindex <= btail; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_rdonly(br)) + continue; + if (br->br_wbr->wbr_bytes > watermark) { + bfound = bindex; + break; + } + } + err = bfound; + if (err < 0) + err = bmfs; + +out: + dput(parent); + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* most free space and then round robin */ +static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) +{ + int err; + struct au_wbr_mfs *mfs; + + err = au_wbr_create_mfs(dentry, flags); + if (err >= 0) { + mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) + err = au_wbr_create_rr(dentry, flags); + mutex_unlock(&mfs->mfs_lock); + } + + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_create_init_mfsrr(struct super_block *sb) +{ + int err; + + au_wbr_create_init_mfs(sb); /* ignore */ + err = au_wbr_create_init_rr(sb); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* top down parent and most free space */ +static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) +{ + int err, e2; + unsigned long long b; + aufs_bindex_t bindex, btop, bbot; + struct super_block *sb; + struct dentry *parent, *h_parent; + struct au_branch *br; + + err = au_wbr_create_tdp(dentry, flags); + if (unlikely(err < 0)) + goto out; + parent = dget_parent(dentry); + btop = au_dbtop(parent); + bbot = au_dbtaildir(parent); + if (btop == bbot) + goto out_parent; /* success */ + + e2 = au_wbr_create_mfs(dentry, flags); + if (e2 < 0) + goto out_parent; /* success */ + + /* when the available size is equal, select upper one */ + sb = dentry->d_sb; + br = au_sbr(sb, err); + b = br->br_wbr->wbr_bytes; + AuDbg("b%d, %llu\n", err, b); + + for (bindex = btop; bindex <= bbot; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || d_is_negative(h_parent)) + continue; + + br = au_sbr(sb, bindex); + if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { + b = br->br_wbr->wbr_bytes; + err = bindex; + AuDbg("b%d, %llu\n", err, b); + } + } + + if (err >= 0) + err = au_wbr_nonopq(dentry, err); + +out_parent: + dput(parent); +out: + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * - top down parent + * - most free space with parent + * - most free space round-robin regardless parent + */ +static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) +{ + int err; + unsigned long long watermark; + struct super_block *sb; + struct au_branch *br; + struct au_wbr_mfs *mfs; + + err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); + if (unlikely(err < 0)) + goto out; + + sb = dentry->d_sb; + br = au_sbr(sb, err); + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + watermark = mfs->mfsrr_watermark; + mutex_unlock(&mfs->mfs_lock); + if (br->br_wbr->wbr_bytes < watermark) + /* regardless the parent dir */ + err = au_wbr_create_mfsrr(dentry, flags); + +out: + AuDbg("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* policies for copyup */ + +/* top down parent */ +static int au_wbr_copyup_tdp(struct dentry *dentry) +{ + return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); +} + +/* bottom up parent */ +static int au_wbr_copyup_bup(struct dentry *dentry) +{ + int err; + aufs_bindex_t bindex, btop; + struct dentry *parent, *h_parent; + struct super_block *sb; + + err = -EROFS; + sb = dentry->d_sb; + parent = dget_parent(dentry); + btop = au_dbtop(parent); + for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || d_is_negative(h_parent)) + continue; + + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = bindex; + break; + } + } + dput(parent); + + /* bottom up here */ + if (unlikely(err < 0)) + err = au_wbr_bu(sb, btop - 1); + + AuDbg("b%d\n", err); + return err; +} + +/* bottom up */ +int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) +{ + int err; + + err = au_wbr_bu(dentry->d_sb, btop); + AuDbg("b%d\n", err); + if (err > btop) + err = au_wbr_nonopq(dentry, err); + + AuDbg("b%d\n", err); + return err; +} + +static int au_wbr_copyup_bu(struct dentry *dentry) +{ + int err; + aufs_bindex_t btop; + + btop = au_dbtop(dentry); + err = au_wbr_do_copyup_bu(dentry, btop); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { + [AuWbrCopyup_TDP] = { + .copyup = au_wbr_copyup_tdp + }, + [AuWbrCopyup_BUP] = { + .copyup = au_wbr_copyup_bup + }, + [AuWbrCopyup_BU] = { + .copyup = au_wbr_copyup_bu + } +}; + +struct au_wbr_create_operations au_wbr_create_ops[] = { + [AuWbrCreate_TDP] = { + .create = au_wbr_create_tdp + }, + [AuWbrCreate_RR] = { + .create = au_wbr_create_rr, + .init = au_wbr_create_init_rr + }, + [AuWbrCreate_MFS] = { + .create = au_wbr_create_mfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSV] = { + .create = au_wbr_create_mfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSRR] = { + .create = au_wbr_create_mfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSRRV] = { + .create = au_wbr_create_mfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_TDMFS] = { + .create = au_wbr_create_tdmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_TDMFSV] = { + .create = au_wbr_create_tdmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFS] = { + .create = au_wbr_create_pmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSV] = { + .create = au_wbr_create_pmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSRR] = { + .create = au_wbr_create_pmfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSRRV] = { + .create = au_wbr_create_pmfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + } +}; diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c new file mode 100644 index 000000000000..5afb430b0b08 --- /dev/null +++ b/fs/aufs/whout.c @@ -0,0 +1,1062 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * whiteout for logical deletion and opaque directory + */ + +#include "aufs.h" + +#define WH_MASK 0444 + +/* + * If a directory contains this file, then it is opaque. We start with the + * .wh. flag so that it is blocked by lookup. + */ +static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, + sizeof(AUFS_WH_DIROPQ) - 1); + +/* + * generate whiteout name, which is NOT terminated by NULL. + * @name: original d_name.name + * @len: original d_name.len + * @wh: whiteout qstr + * returns zero when succeeds, otherwise error. + * succeeded value as wh->name should be freed by kfree(). + */ +int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) +{ + char *p; + + if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) + return -ENAMETOOLONG; + + wh->len = name->len + AUFS_WH_PFX_LEN; + p = kmalloc(wh->len, GFP_NOFS); + wh->name = p; + if (p) { + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); + /* smp_mb(); */ + return 0; + } + return -ENOMEM; +} + +/* ---------------------------------------------------------------------- */ + +/* + * test if the @wh_name exists under @h_parent. + * @try_sio specifies the necessary of super-io. + */ +int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) +{ + int err; + struct dentry *wh_dentry; + + if (!try_sio) + wh_dentry = vfsub_lkup_one(wh_name, h_parent); + else + wh_dentry = au_sio_lkup_one(wh_name, h_parent); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) { + if (err == -ENAMETOOLONG) + err = 0; + goto out; + } + + err = 0; + if (d_is_negative(wh_dentry)) + goto out_wh; /* success */ + + err = 1; + if (d_is_reg(wh_dentry)) + goto out_wh; /* success */ + + err = -EIO; + AuIOErr("%pd Invalid whiteout entry type 0%o.\n", + wh_dentry, d_inode(wh_dentry)->i_mode); + +out_wh: + dput(wh_dentry); +out: + return err; +} + +/* + * test if the @h_dentry sets opaque or not. + */ +int au_diropq_test(struct dentry *h_dentry) +{ + int err; + struct inode *h_dir; + + h_dir = d_inode(h_dentry); + err = au_wh_test(h_dentry, &diropq_name, + au_test_h_perm_sio(h_dir, MAY_EXEC)); + return err; +} + +/* + * returns a negative dentry whose name is unique and temporary. + */ +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, + struct qstr *prefix) +{ + struct dentry *dentry; + int i; + char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], + *name, *p; + /* strict atomic_t is unnecessary here */ + static unsigned short cnt; + struct qstr qs; + + BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); + + name = defname; + qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; + if (unlikely(prefix->len > DNAME_INLINE_LEN)) { + dentry = ERR_PTR(-ENAMETOOLONG); + if (unlikely(qs.len > NAME_MAX)) + goto out; + dentry = ERR_PTR(-ENOMEM); + name = kmalloc(qs.len + 1, GFP_NOFS); + if (unlikely(!name)) + goto out; + } + + /* doubly whiteout-ed */ + memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); + p = name + AUFS_WH_PFX_LEN * 2; + memcpy(p, prefix->name, prefix->len); + p += prefix->len; + *p++ = '.'; + AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); + + qs.name = name; + for (i = 0; i < 3; i++) { + sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); + dentry = au_sio_lkup_one(&qs, h_parent); + if (IS_ERR(dentry) || d_is_negative(dentry)) + goto out_name; + dput(dentry); + } + /* pr_warn("could not get random name\n"); */ + dentry = ERR_PTR(-EEXIST); + AuDbg("%.*s\n", AuLNPair(&qs)); + BUG(); + +out_name: + if (name != defname) + au_kfree_try_rcu(name); +out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* + * rename the @h_dentry on @br to the whiteouted temporary name. + */ +int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) +{ + int err; + struct path h_path = { + .mnt = au_br_mnt(br) + }; + struct inode *h_dir, *delegated; + struct dentry *h_parent; + + h_parent = h_dentry->d_parent; /* dir inode is locked */ + h_dir = d_inode(h_parent); + IMustLock(h_dir); + + h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); + err = PTR_ERR(h_path.dentry); + if (IS_ERR(h_path.dentry)) + goto out; + + /* under the same dir, no need to lock_rename() */ + delegated = NULL; + err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, + /*flags*/0); + AuTraceErr(err); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal rename\n"); + iput(delegated); + } + dput(h_path.dentry); + +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ +/* + * functions for removing a whiteout + */ + +static int do_unlink_wh(struct inode *h_dir, struct path *h_path) +{ + int err, force; + struct inode *delegated; + + /* + * forces superio when the dir has a sticky bit. + * this may be a violation of unix fs semantics. + */ + force = (h_dir->i_mode & S_ISVTX) + && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); + delegated = NULL; + err = vfsub_unlink(h_dir, h_path, &delegated, force); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + return err; +} + +int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, + struct dentry *dentry) +{ + int err; + + err = do_unlink_wh(h_dir, h_path); + if (!err && dentry) + au_set_dbwh(dentry, -1); + + return err; +} + +static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, + struct au_branch *br) +{ + int err; + struct path h_path = { + .mnt = au_br_mnt(br) + }; + + err = 0; + h_path.dentry = vfsub_lkup_one(wh, h_parent); + if (IS_ERR(h_path.dentry)) + err = PTR_ERR(h_path.dentry); + else { + if (d_is_reg(h_path.dentry)) + err = do_unlink_wh(d_inode(h_parent), &h_path); + dput(h_path.dentry); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ +/* + * initialize/clean whiteout for a branch + */ + +static void au_wh_clean(struct inode *h_dir, struct path *whpath, + const int isdir) +{ + int err; + struct inode *delegated; + + if (d_is_negative(whpath->dentry)) + return; + + if (isdir) + err = vfsub_rmdir(h_dir, whpath); + else { + delegated = NULL; + err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + } + if (unlikely(err)) + pr_warn("failed removing %pd (%d), ignored.\n", + whpath->dentry, err); +} + +static int test_linkable(struct dentry *h_root) +{ + struct inode *h_dir = d_inode(h_root); + + if (h_dir->i_op->link) + return 0; + + pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", + h_root, au_sbtype(h_root->d_sb)); + return -ENOSYS; /* the branch doesn't have its ->link() */ +} + +/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ +static int au_whdir(struct inode *h_dir, struct path *path) +{ + int err; + + err = -EEXIST; + if (d_is_negative(path->dentry)) { + int mode = 0700; + + if (au_test_nfs(path->dentry->d_sb)) + mode |= 0111; + err = vfsub_mkdir(h_dir, path, mode); + } else if (d_is_dir(path->dentry)) + err = 0; + else + pr_err("unknown %pd exists\n", path->dentry); + + return err; +} + +struct au_wh_base { + const struct qstr *name; + struct dentry *dentry; +}; + +static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], + struct path *h_path) +{ + h_path->dentry = base[AuBrWh_BASE].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/0); + h_path->dentry = base[AuBrWh_PLINK].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/1); + h_path->dentry = base[AuBrWh_ORPH].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/1); +} + +/* + * returns tri-state, + * minus: error, caller should print the message + * zero: success + * plus: error, caller should NOT print the message + */ +static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, + int do_plink, struct au_wh_base base[], + struct path *h_path) +{ + int err; + struct inode *h_dir; + + h_dir = d_inode(h_root); + h_path->dentry = base[AuBrWh_BASE].dentry; + au_wh_clean(h_dir, h_path, /*isdir*/0); + h_path->dentry = base[AuBrWh_PLINK].dentry; + if (do_plink) { + err = test_linkable(h_root); + if (unlikely(err)) { + err = 1; + goto out; + } + + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); + } else + au_wh_clean(h_dir, h_path, /*isdir*/1); + h_path->dentry = base[AuBrWh_ORPH].dentry; + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); + +out: + return err; +} + +/* + * for the moment, aufs supports the branch filesystem which does not support + * link(2). testing on FAT which does not support i_op->setattr() fully either, + * copyup failed. finally, such filesystem will not be used as the writable + * branch. + * + * returns tri-state, see above. + */ +static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, + int do_plink, struct au_wh_base base[], + struct path *h_path) +{ + int err; + struct inode *h_dir; + + WbrWhMustWriteLock(wbr); + + err = test_linkable(h_root); + if (unlikely(err)) { + err = 1; + goto out; + } + + /* + * todo: should this create be done in /sbin/mount.aufs helper? + */ + err = -EEXIST; + h_dir = d_inode(h_root); + if (d_is_negative(base[AuBrWh_BASE].dentry)) { + h_path->dentry = base[AuBrWh_BASE].dentry; + err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); + } else if (d_is_reg(base[AuBrWh_BASE].dentry)) + err = 0; + else + pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); + if (unlikely(err)) + goto out; + + h_path->dentry = base[AuBrWh_PLINK].dentry; + if (do_plink) { + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); + } else + au_wh_clean(h_dir, h_path, /*isdir*/1); + wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); + + h_path->dentry = base[AuBrWh_ORPH].dentry; + err = au_whdir(h_dir, h_path); + if (unlikely(err)) + goto out; + wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); + +out: + return err; +} + +/* + * initialize the whiteout base file/dir for @br. + */ +int au_wh_init(struct au_branch *br, struct super_block *sb) +{ + int err, i; + const unsigned char do_plink + = !!au_opt_test(au_mntflags(sb), PLINK); + struct inode *h_dir; + struct path path = br->br_path; + struct dentry *h_root = path.dentry; + struct au_wbr *wbr = br->br_wbr; + static const struct qstr base_name[] = { + [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, + sizeof(AUFS_BASE_NAME) - 1), + [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, + sizeof(AUFS_PLINKDIR_NAME) - 1), + [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, + sizeof(AUFS_ORPHDIR_NAME) - 1) + }; + struct au_wh_base base[] = { + [AuBrWh_BASE] = { + .name = base_name + AuBrWh_BASE, + .dentry = NULL + }, + [AuBrWh_PLINK] = { + .name = base_name + AuBrWh_PLINK, + .dentry = NULL + }, + [AuBrWh_ORPH] = { + .name = base_name + AuBrWh_ORPH, + .dentry = NULL + } + }; + + if (wbr) + WbrWhMustWriteLock(wbr); + + for (i = 0; i < AuBrWh_Last; i++) { + /* doubly whiteouted */ + struct dentry *d; + + d = au_wh_lkup(h_root, (void *)base[i].name, br); + err = PTR_ERR(d); + if (IS_ERR(d)) + goto out; + + base[i].dentry = d; + AuDebugOn(wbr + && wbr->wbr_wh[i] + && wbr->wbr_wh[i] != base[i].dentry); + } + + if (wbr) + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } + + err = 0; + if (!au_br_writable(br->br_perm)) { + h_dir = d_inode(h_root); + au_wh_init_ro(h_dir, base, &path); + } else if (!au_br_wh_linkable(br->br_perm)) { + err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); + if (err > 0) + goto out; + else if (err) + goto out_err; + } else { + err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); + if (err > 0) + goto out; + else if (err) + goto out_err; + } + goto out; /* success */ + +out_err: + pr_err("an error(%d) on the writable branch %pd(%s)\n", + err, h_root, au_sbtype(h_root->d_sb)); +out: + for (i = 0; i < AuBrWh_Last; i++) + dput(base[i].dentry); + return err; +} + +/* ---------------------------------------------------------------------- */ +/* + * whiteouts are all hard-linked usually. + * when its link count reaches a ceiling, we create a new whiteout base + * asynchronously. + */ + +struct reinit_br_wh { + struct super_block *sb; + struct au_branch *br; +}; + +static void reinit_br_wh(void *arg) +{ + int err; + aufs_bindex_t bindex; + struct path h_path; + struct reinit_br_wh *a = arg; + struct au_wbr *wbr; + struct inode *dir, *delegated; + struct dentry *h_root; + struct au_hinode *hdir; + + err = 0; + wbr = a->br->br_wbr; + /* big aufs lock */ + si_noflush_write_lock(a->sb); + if (!au_br_writable(a->br->br_perm)) + goto out; + bindex = au_br_index(a->sb, a->br->br_id); + if (unlikely(bindex < 0)) + goto out; + + di_read_lock_parent(a->sb->s_root, AuLock_IR); + dir = d_inode(a->sb->s_root); + hdir = au_hi(dir, bindex); + h_root = au_h_dptr(a->sb->s_root, bindex); + AuDebugOn(h_root != au_br_dentry(a->br)); + + au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); + wbr_wh_write_lock(wbr); + err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, + h_root, a->br); + if (!err) { + h_path.dentry = wbr->wbr_whbase; + h_path.mnt = au_br_mnt(a->br); + delegated = NULL; + err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, + /*force*/0); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + } else { + pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); + err = 0; + } + dput(wbr->wbr_whbase); + wbr->wbr_whbase = NULL; + if (!err) + err = au_wh_init(a->br, a->sb); + wbr_wh_write_unlock(wbr); + au_hn_inode_unlock(hdir); + di_read_unlock(a->sb->s_root, AuLock_IR); + if (!err) + au_fhsm_wrote(a->sb, bindex, /*force*/0); + +out: + if (wbr) + atomic_dec(&wbr->wbr_wh_running); + au_lcnt_dec(&a->br->br_count); + si_write_unlock(a->sb); + au_nwt_done(&au_sbi(a->sb)->si_nowait); + au_kfree_rcu(a); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} + +static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) +{ + int do_dec, wkq_err; + struct reinit_br_wh *arg; + + do_dec = 1; + if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) + goto out; + + /* ignore ENOMEM */ + arg = kmalloc(sizeof(*arg), GFP_NOFS); + if (arg) { + /* + * dec(wh_running), kfree(arg) and dec(br_count) + * in reinit function + */ + arg->sb = sb; + arg->br = br; + au_lcnt_inc(&br->br_count); + wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); + if (unlikely(wkq_err)) { + atomic_dec(&br->br_wbr->wbr_wh_running); + au_lcnt_dec(&br->br_count); + au_kfree_rcu(arg); + } + do_dec = 0; + } + +out: + if (do_dec) + atomic_dec(&br->br_wbr->wbr_wh_running); +} + +/* ---------------------------------------------------------------------- */ + +/* + * create the whiteout @wh. + */ +static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, + struct dentry *wh) +{ + int err; + struct path h_path = { + .dentry = wh + }; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *h_parent; + struct inode *h_dir, *delegated; + + h_parent = wh->d_parent; /* dir inode is locked */ + h_dir = d_inode(h_parent); + IMustLock(h_dir); + + br = au_sbr(sb, bindex); + h_path.mnt = au_br_mnt(br); + wbr = br->br_wbr; + wbr_wh_read_lock(wbr); + if (wbr->wbr_whbase) { + delegated = NULL; + err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal link\n"); + iput(delegated); + } + if (!err || err != -EMLINK) + goto out; + + /* link count full. re-initialize br_whbase. */ + kick_reinit_br_wh(sb, br); + } + + /* return this error in this context */ + err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); + if (!err) + au_fhsm_wrote(sb, bindex, /*force*/0); + +out: + wbr_wh_read_unlock(wbr); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * create or remove the diropq. + */ +static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags) +{ + struct dentry *opq_dentry, *h_dentry; + struct super_block *sb; + struct au_branch *br; + int err; + + sb = dentry->d_sb; + br = au_sbr(sb, bindex); + h_dentry = au_h_dptr(dentry, bindex); + opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); + if (IS_ERR(opq_dentry)) + goto out; + + if (au_ftest_diropq(flags, CREATE)) { + err = link_or_create_wh(sb, bindex, opq_dentry); + if (!err) { + au_set_dbdiropq(dentry, bindex); + goto out; /* success */ + } + } else { + struct path tmp = { + .dentry = opq_dentry, + .mnt = au_br_mnt(br) + }; + err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &tmp); + if (!err) + au_set_dbdiropq(dentry, -1); + } + dput(opq_dentry); + opq_dentry = ERR_PTR(err); + +out: + return opq_dentry; +} + +struct do_diropq_args { + struct dentry **errp; + struct dentry *dentry; + aufs_bindex_t bindex; + unsigned int flags; +}; + +static void call_do_diropq(void *args) +{ + struct do_diropq_args *a = args; + *a->errp = do_diropq(a->dentry, a->bindex, a->flags); +} + +struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags) +{ + struct dentry *diropq, *h_dentry; + + h_dentry = au_h_dptr(dentry, bindex); + if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE)) + diropq = do_diropq(dentry, bindex, flags); + else { + int wkq_err; + struct do_diropq_args args = { + .errp = &diropq, + .dentry = dentry, + .bindex = bindex, + .flags = flags + }; + + wkq_err = au_wkq_wait(call_do_diropq, &args); + if (unlikely(wkq_err)) + diropq = ERR_PTR(wkq_err); + } + + return diropq; +} + +/* ---------------------------------------------------------------------- */ + +/* + * lookup whiteout dentry. + * @h_parent: lower parent dentry which must exist and be locked + * @base_name: name of dentry which will be whiteouted + * returns dentry for whiteout. + */ +struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, + struct au_branch *br) +{ + int err; + struct qstr wh_name; + struct dentry *wh_dentry; + + err = au_wh_name_alloc(&wh_name, base_name); + wh_dentry = ERR_PTR(err); + if (!err) { + wh_dentry = vfsub_lkup_one(&wh_name, h_parent); + au_kfree_try_rcu(wh_name.name); + } + return wh_dentry; +} + +/* + * link/create a whiteout for @dentry on @bindex. + */ +struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent) +{ + struct dentry *wh_dentry; + struct super_block *sb; + int err; + + sb = dentry->d_sb; + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); + if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { + err = link_or_create_wh(sb, bindex, wh_dentry); + if (!err) { + au_set_dbwh(dentry, bindex); + au_fhsm_wrote(sb, bindex, /*force*/0); + } else { + dput(wh_dentry); + wh_dentry = ERR_PTR(err); + } + } + + return wh_dentry; +} + +/* ---------------------------------------------------------------------- */ + +/* Delete all whiteouts in this directory on branch bindex. */ +static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, + aufs_bindex_t bindex, struct au_branch *br) +{ + int err; + unsigned long ul, n; + struct qstr wh_name; + char *p; + struct hlist_head *head; + struct au_vdir_wh *pos; + struct au_vdir_destr *str; + + err = -ENOMEM; + p = (void *)__get_free_page(GFP_NOFS); + wh_name.name = p; + if (unlikely(!wh_name.name)) + goto out; + + err = 0; + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + p += AUFS_WH_PFX_LEN; + n = whlist->nh_num; + head = whlist->nh_head; + for (ul = 0; !err && ul < n; ul++, head++) { + hlist_for_each_entry(pos, head, wh_hash) { + if (pos->wh_bindex != bindex) + continue; + + str = &pos->wh_str; + if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { + memcpy(p, str->name, str->len); + wh_name.len = AUFS_WH_PFX_LEN + str->len; + err = unlink_wh_name(h_dentry, &wh_name, br); + if (!err) + continue; + break; + } + AuIOErr("whiteout name too long %.*s\n", + str->len, str->name); + err = -EIO; + break; + } + } + free_page((unsigned long)wh_name.name); + +out: + return err; +} + +struct del_wh_children_args { + int *errp; + struct dentry *h_dentry; + struct au_nhash *whlist; + aufs_bindex_t bindex; + struct au_branch *br; +}; + +static void call_del_wh_children(void *args) +{ + struct del_wh_children_args *a = args; + *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); +} + +/* ---------------------------------------------------------------------- */ + +struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) +{ + struct au_whtmp_rmdir *whtmp; + int err; + unsigned int rdhash; + + SiMustAnyLock(sb); + + whtmp = kzalloc(sizeof(*whtmp), gfp); + if (unlikely(!whtmp)) { + whtmp = ERR_PTR(-ENOMEM); + goto out; + } + + /* no estimation for dir size */ + rdhash = au_sbi(sb)->si_rdhash; + if (!rdhash) + rdhash = AUFS_RDHASH_DEF; + err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); + if (unlikely(err)) { + au_kfree_rcu(whtmp); + whtmp = ERR_PTR(err); + } + +out: + return whtmp; +} + +void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) +{ + if (whtmp->br) + au_lcnt_dec(&whtmp->br->br_count); + dput(whtmp->wh_dentry); + iput(whtmp->dir); + au_nhash_wh_free(&whtmp->whlist); + au_kfree_rcu(whtmp); +} + +/* + * rmdir the whiteouted temporary named dir @h_dentry. + * @whlist: whiteouted children. + */ +int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist) +{ + int err; + unsigned int h_nlink; + struct path h_tmp; + struct inode *wh_inode, *h_dir; + struct au_branch *br; + + h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ + IMustLock(h_dir); + + br = au_sbr(dir->i_sb, bindex); + wh_inode = d_inode(wh_dentry); + inode_lock_nested(wh_inode, AuLsc_I_CHILD); + + /* + * someone else might change some whiteouts while we were sleeping. + * it means this whlist may have an obsoleted entry. + */ + if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) + err = del_wh_children(wh_dentry, whlist, bindex, br); + else { + int wkq_err; + struct del_wh_children_args args = { + .errp = &err, + .h_dentry = wh_dentry, + .whlist = whlist, + .bindex = bindex, + .br = br + }; + + wkq_err = au_wkq_wait(call_del_wh_children, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } + inode_unlock(wh_inode); + + if (!err) { + h_tmp.dentry = wh_dentry; + h_tmp.mnt = au_br_mnt(br); + h_nlink = h_dir->i_nlink; + err = vfsub_rmdir(h_dir, &h_tmp); + /* some fs doesn't change the parent nlink in some cases */ + h_nlink -= h_dir->i_nlink; + } + + if (!err) { + if (au_ibtop(dir) == bindex) { + /* todo: dir->i_mutex is necessary */ + au_cpup_attr_timesizes(dir); + if (h_nlink) + vfsub_drop_nlink(dir); + } + return 0; /* success */ + } + + pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); + return err; +} + +static void call_rmdir_whtmp(void *args) +{ + int err; + aufs_bindex_t bindex; + struct au_whtmp_rmdir *a = args; + struct super_block *sb; + struct dentry *h_parent; + struct inode *h_dir; + struct au_hinode *hdir; + + /* rmdir by nfsd may cause deadlock with this i_mutex */ + /* inode_lock(a->dir); */ + err = -EROFS; + sb = a->dir->i_sb; + si_read_lock(sb, !AuLock_FLUSH); + if (!au_br_writable(a->br->br_perm)) + goto out; + bindex = au_br_index(sb, a->br->br_id); + if (unlikely(bindex < 0)) + goto out; + + err = -EIO; + ii_write_lock_parent(a->dir); + h_parent = dget_parent(a->wh_dentry); + h_dir = d_inode(h_parent); + hdir = au_hi(a->dir, bindex); + err = vfsub_mnt_want_write(au_br_mnt(a->br)); + if (unlikely(err)) + goto out_mnt; + au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); + err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, + a->br); + if (!err) + err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); + au_hn_inode_unlock(hdir); + vfsub_mnt_drop_write(au_br_mnt(a->br)); + +out_mnt: + dput(h_parent); + ii_write_unlock(a->dir); +out: + /* inode_unlock(a->dir); */ + au_whtmp_rmdir_free(a); + si_read_unlock(sb); + au_nwt_done(&au_sbi(sb)->si_nowait); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} + +void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_whtmp_rmdir *args) +{ + int wkq_err; + struct super_block *sb; + + IMustLock(dir); + + /* all post-process will be done in do_rmdir_whtmp(). */ + sb = dir->i_sb; + args->dir = au_igrab(dir); + args->br = au_sbr(sb, bindex); + au_lcnt_inc(&args->br->br_count); + args->wh_dentry = dget(wh_dentry); + wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); + if (unlikely(wkq_err)) { + pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); + au_whtmp_rmdir_free(args); + } +} diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h new file mode 100644 index 000000000000..06f69b24e5c1 --- /dev/null +++ b/fs/aufs/whout.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * whiteout for logical deletion and opaque directory + */ + +#ifndef __AUFS_WHOUT_H__ +#define __AUFS_WHOUT_H__ + +#ifdef __KERNEL__ + +#include "dir.h" + +/* whout.c */ +int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); +int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio); +int au_diropq_test(struct dentry *h_dentry); +struct au_branch; +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, + struct qstr *prefix); +int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); +int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, + struct dentry *dentry); +int au_wh_init(struct au_branch *br, struct super_block *sb); + +/* diropq flags */ +#define AuDiropq_CREATE 1 +#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) +#define au_fset_diropq(flags, name) \ + do { (flags) |= AuDiropq_##name; } while (0) +#define au_fclr_diropq(flags, name) \ + do { (flags) &= ~AuDiropq_##name; } while (0) + +struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags); +struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, + struct au_branch *br); +struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent); + +/* real rmdir for the whiteout-ed dir */ +struct au_whtmp_rmdir { + struct inode *dir; + struct au_branch *br; + struct dentry *wh_dentry; + struct au_nhash whlist; +}; + +struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); +void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); +int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist); +void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_whtmp_rmdir *args); + +/* ---------------------------------------------------------------------- */ + +static inline struct dentry *au_diropq_create(struct dentry *dentry, + aufs_bindex_t bindex) +{ + return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); +} + +static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) +{ + return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WHOUT_H__ */ diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c new file mode 100644 index 000000000000..22eb3f802760 --- /dev/null +++ b/fs/aufs/wkq.c @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * workqueue for asynchronous/super-io operations + * todo: try new credential scheme + */ + +#include +#include "aufs.h" + +/* internal workqueue named AUFS_WKQ_NAME */ + +static struct workqueue_struct *au_wkq; + +struct au_wkinfo { + struct work_struct wk; + struct kobject *kobj; + + unsigned int flags; /* see wkq.h */ + + au_wkq_func_t func; + void *args; + +#ifdef CONFIG_LOCKDEP + int dont_check; + struct held_lock **hlock; +#endif + + struct completion *comp; +}; + +/* ---------------------------------------------------------------------- */ +/* + * Aufs passes some operations to the workqueue such as the internal copyup. + * This scheme looks rather unnatural for LOCKDEP debugging feature, since the + * job run by workqueue depends upon the locks acquired in the other task. + * Delegating a small operation to the workqueue, aufs passes its lockdep + * information too. And the job in the workqueue restores the info in order to + * pretend as if it acquired those locks. This is just to make LOCKDEP work + * correctly and expectedly. + */ + +#ifndef CONFIG_LOCKDEP +AuStubInt0(au_wkq_lockdep_alloc, struct au_wkinfo *wkinfo); +AuStubVoid(au_wkq_lockdep_free, struct au_wkinfo *wkinfo); +AuStubVoid(au_wkq_lockdep_pre, struct au_wkinfo *wkinfo); +AuStubVoid(au_wkq_lockdep_post, struct au_wkinfo *wkinfo); +AuStubVoid(au_wkq_lockdep_init, struct au_wkinfo *wkinfo); +#else +static void au_wkq_lockdep_init(struct au_wkinfo *wkinfo) +{ + wkinfo->hlock = NULL; + wkinfo->dont_check = 0; +} + +/* + * 1: matched + * 0: unmatched + */ +static int au_wkq_lockdep_test(struct lock_class_key *key, const char *name) +{ + static DEFINE_SPINLOCK(spin); + static struct { + char *name; + struct lock_class_key *key; + } a[] = { + { .name = "&sbinfo->si_rwsem" }, + { .name = "&finfo->fi_rwsem" }, + { .name = "&dinfo->di_rwsem" }, + { .name = "&iinfo->ii_rwsem" } + }; + static int set; + int i; + + /* lockless read from 'set.' see below */ + if (set == ARRAY_SIZE(a)) { + for (i = 0; i < ARRAY_SIZE(a); i++) + if (a[i].key == key) + goto match; + goto unmatch; + } + + spin_lock(&spin); + if (set) + for (i = 0; i < ARRAY_SIZE(a); i++) + if (a[i].key == key) { + spin_unlock(&spin); + goto match; + } + for (i = 0; i < ARRAY_SIZE(a); i++) { + if (a[i].key) { + if (unlikely(a[i].key == key)) { /* rare but possible */ + spin_unlock(&spin); + goto match; + } else + continue; + } + if (strstr(a[i].name, name)) { + /* + * the order of these three lines is important for the + * lockless read above. + */ + a[i].key = key; + spin_unlock(&spin); + set++; + /* AuDbg("%d, %s\n", set, name); */ + goto match; + } + } + spin_unlock(&spin); + goto unmatch; + +match: + return 1; +unmatch: + return 0; +} + +static int au_wkq_lockdep_alloc(struct au_wkinfo *wkinfo) +{ + int err, n; + struct task_struct *curr; + struct held_lock **hl, *held_locks, *p; + + err = 0; + curr = current; + wkinfo->dont_check = lockdep_recursing(curr); + if (wkinfo->dont_check) + goto out; + n = curr->lockdep_depth; + if (!n) + goto out; + + err = -ENOMEM; + wkinfo->hlock = kmalloc_array(n + 1, sizeof(*wkinfo->hlock), GFP_NOFS); + if (unlikely(!wkinfo->hlock)) + goto out; + + err = 0; +#if 0 /* left for debugging */ + if (0 && au_debug_test()) + lockdep_print_held_locks(curr); +#endif + held_locks = curr->held_locks; + hl = wkinfo->hlock; + while (n--) { + p = held_locks++; + if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) + *hl++ = p; + } + *hl = NULL; + +out: + return err; +} + +static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) +{ + au_kfree_try_rcu(wkinfo->hlock); +} + +static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) +{ + struct held_lock *p, **hl = wkinfo->hlock; + int subclass; + + if (wkinfo->dont_check) + lockdep_off(); + if (!hl) + return; + while ((p = *hl++)) { /* assignment */ + subclass = lockdep_hlock_class(p)->subclass; + /* AuDbg("%s, %d\n", p->instance->name, subclass); */ + if (p->read) + rwsem_acquire_read(p->instance, subclass, 0, + /*p->acquire_ip*/_RET_IP_); + else + rwsem_acquire(p->instance, subclass, 0, + /*p->acquire_ip*/_RET_IP_); + } +} + +static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) +{ + struct held_lock *p, **hl = wkinfo->hlock; + + if (wkinfo->dont_check) + lockdep_on(); + if (!hl) + return; + while ((p = *hl++)) /* assignment */ + rwsem_release(p->instance, /*p->acquire_ip*/_RET_IP_); +} +#endif + +static void wkq_func(struct work_struct *wk) +{ + struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); + + AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); + AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); + + au_wkq_lockdep_pre(wkinfo); + wkinfo->func(wkinfo->args); + au_wkq_lockdep_post(wkinfo); + if (au_ftest_wkq(wkinfo->flags, WAIT)) + complete(wkinfo->comp); + else { + kobject_put(wkinfo->kobj); + module_put(THIS_MODULE); /* todo: ?? */ + au_kfree_rcu(wkinfo); + } +} + +/* + * Since struct completion is large, try allocating it dynamically. + */ +#define AuWkqCompDeclare(name) struct completion *comp = NULL + +static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +{ + *comp = kmalloc(sizeof(**comp), GFP_NOFS); + if (*comp) { + init_completion(*comp); + wkinfo->comp = *comp; + return 0; + } + return -ENOMEM; +} + +static void au_wkq_comp_free(struct completion *comp) +{ + au_kfree_rcu(comp); +} + +static void au_wkq_run(struct au_wkinfo *wkinfo) +{ + if (au_ftest_wkq(wkinfo->flags, NEST)) { + if (au_wkq_test()) { + AuWarn1("wkq from wkq, unless silly-rename on NFS," + " due to a dead dir by UDBA," + " or async xino write?\n"); + AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); + } + } else + au_dbg_verify_kthread(); + + if (au_ftest_wkq(wkinfo->flags, WAIT)) { + INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); + queue_work(au_wkq, &wkinfo->wk); + } else { + INIT_WORK(&wkinfo->wk, wkq_func); + schedule_work(&wkinfo->wk); + } +} + +/* + * Be careful. It is easy to make deadlock happen. + * processA: lock, wkq and wait + * processB: wkq and wait, lock in wkq + * --> deadlock + */ +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) +{ + int err; + AuWkqCompDeclare(comp); + struct au_wkinfo wkinfo = { + .flags = flags, + .func = func, + .args = args + }; + + err = au_wkq_comp_alloc(&wkinfo, &comp); + if (unlikely(err)) + goto out; + err = au_wkq_lockdep_alloc(&wkinfo); + if (unlikely(err)) + goto out_comp; + if (!err) { + au_wkq_run(&wkinfo); + /* no timeout, no interrupt */ + wait_for_completion(wkinfo.comp); + } + au_wkq_lockdep_free(&wkinfo); + +out_comp: + au_wkq_comp_free(comp); +out: + destroy_work_on_stack(&wkinfo.wk); + return err; +} + +/* + * Note: dget/dput() in func for aufs dentries are not supported. It will be a + * problem in a concurrent umounting. + */ +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, + unsigned int flags) +{ + int err; + struct au_wkinfo *wkinfo; + + atomic_inc(&au_sbi(sb)->si_nowait.nw_len); + + /* + * wkq_func() must free this wkinfo. + * it highly depends upon the implementation of workqueue. + */ + err = 0; + wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); + if (wkinfo) { + wkinfo->kobj = &au_sbi(sb)->si_kobj; + wkinfo->flags = flags & ~AuWkq_WAIT; + wkinfo->func = func; + wkinfo->args = args; + wkinfo->comp = NULL; + au_wkq_lockdep_init(wkinfo); + kobject_get(wkinfo->kobj); + __module_get(THIS_MODULE); /* todo: ?? */ + + au_wkq_run(wkinfo); + } else { + err = -ENOMEM; + au_nwt_done(&au_sbi(sb)->si_nowait); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_nwt_init(struct au_nowait_tasks *nwt) +{ + atomic_set(&nwt->nw_len, 0); + /* smp_mb(); */ /* atomic_set */ + init_waitqueue_head(&nwt->nw_wq); +} + +void au_wkq_fin(void) +{ + destroy_workqueue(au_wkq); +} + +int __init au_wkq_init(void) +{ + int err; + + err = 0; + au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); + if (IS_ERR(au_wkq)) + err = PTR_ERR(au_wkq); + else if (!au_wkq) + err = -ENOMEM; + + return err; +} diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h new file mode 100644 index 000000000000..235370d91693 --- /dev/null +++ b/fs/aufs/wkq.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * workqueue for asynchronous/super-io operations + * todo: try new credentials management scheme + */ + +#ifndef __AUFS_WKQ_H__ +#define __AUFS_WKQ_H__ + +#ifdef __KERNEL__ + +#include + +struct super_block; + +/* ---------------------------------------------------------------------- */ + +/* + * in the next operation, wait for the 'nowait' tasks in system-wide workqueue + */ +struct au_nowait_tasks { + atomic_t nw_len; + wait_queue_head_t nw_wq; +}; + +/* ---------------------------------------------------------------------- */ + +typedef void (*au_wkq_func_t)(void *args); + +/* wkq flags */ +#define AuWkq_WAIT 1 +#define AuWkq_NEST (1 << 1) +#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) +#define au_fset_wkq(flags, name) \ + do { (flags) |= AuWkq_##name; } while (0) +#define au_fclr_wkq(flags, name) \ + do { (flags) &= ~AuWkq_##name; } while (0) + +/* wkq.c */ +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, + unsigned int flags); +void au_nwt_init(struct au_nowait_tasks *nwt); +int __init au_wkq_init(void); +void au_wkq_fin(void); + +/* ---------------------------------------------------------------------- */ + +static inline int au_wkq_test(void) +{ + return current->flags & PF_WQ_WORKER; +} + +static inline int au_wkq_wait(au_wkq_func_t func, void *args) +{ + return au_wkq_do_wait(AuWkq_WAIT, func, args); +} + +static inline void au_nwt_done(struct au_nowait_tasks *nwt) +{ + if (atomic_dec_and_test(&nwt->nw_len)) + wake_up_all(&nwt->nw_wq); +} + +static inline int au_nwt_flush(struct au_nowait_tasks *nwt) +{ + wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); + return 0; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WKQ_H__ */ diff --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c new file mode 100644 index 000000000000..38a1819e2473 --- /dev/null +++ b/fs/aufs/xattr.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2014-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * handling xattr functions + */ + +#include +#include +#include +#include "aufs.h" + +static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) +{ + if (!ignore_flags) + goto out; + switch (err) { + case -ENOMEM: + case -EDQUOT: + goto out; + } + + if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { + err = 0; + goto out; + } + +#define cmp(brattr, prefix) do { \ + if (!strncmp(name, XATTR_##prefix##_PREFIX, \ + XATTR_##prefix##_PREFIX_LEN)) { \ + if (ignore_flags & AuBrAttr_ICEX_##brattr) \ + err = 0; \ + goto out; \ + } \ + } while (0) + + cmp(SEC, SECURITY); + cmp(SYS, SYSTEM); + cmp(TR, TRUSTED); + cmp(USR, USER); +#undef cmp + + if (ignore_flags & AuBrAttr_ICEX_OTH) + err = 0; + +out: + return err; +} + +static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; + +static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, + char *name, char **buf, unsigned int ignore_flags, + unsigned int verbose) +{ + int err; + ssize_t ssz; + struct inode *h_idst; + + ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS); + err = ssz; + if (unlikely(err <= 0)) { + if (err == -ENODATA + || (err == -EOPNOTSUPP + && ((ignore_flags & au_xattr_out_of_list) + || (au_test_nfs_noacl(d_inode(h_src)) + && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) + || !strcmp(name, + XATTR_NAME_POSIX_ACL_DEFAULT)))) + )) + err = 0; + if (err && (verbose || au_debug_test())) + pr_err("%s, err %d\n", name, err); + goto out; + } + + /* unlock it temporary */ + h_idst = d_inode(h_dst); + inode_unlock(h_idst); + err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0); + inode_lock_nested(h_idst, AuLsc_I_CHILD2); + if (unlikely(err)) { + if (verbose || au_debug_test()) + pr_err("%s, err %d\n", name, err); + err = au_xattr_ignore(err, name, ignore_flags); + } + +out: + return err; +} + +int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, + unsigned int verbose) +{ + int err, unlocked, acl_access, acl_default; + ssize_t ssz; + struct inode *h_isrc, *h_idst; + char *value, *p, *o, *e; + + /* try stopping to update the source inode while we are referencing */ + /* there should not be the parent-child relationship between them */ + h_isrc = d_inode(h_src); + h_idst = d_inode(h_dst); + inode_unlock(h_idst); + inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); + inode_lock_nested(h_idst, AuLsc_I_CHILD2); + unlocked = 0; + + /* some filesystems don't list POSIX ACL, for example tmpfs */ + ssz = vfs_listxattr(h_src, NULL, 0); + err = ssz; + if (unlikely(err < 0)) { + AuTraceErr(err); + if (err == -ENODATA + || err == -EOPNOTSUPP) + err = 0; /* ignore */ + goto out; + } + + err = 0; + p = NULL; + o = NULL; + if (ssz) { + err = -ENOMEM; + p = kmalloc(ssz, GFP_NOFS); + o = p; + if (unlikely(!p)) + goto out; + err = vfs_listxattr(h_src, p, ssz); + } + inode_unlock_shared(h_isrc); + unlocked = 1; + AuDbg("err %d, ssz %zd\n", err, ssz); + if (unlikely(err < 0)) + goto out_free; + + err = 0; + e = p + ssz; + value = NULL; + acl_access = 0; + acl_default = 0; + while (!err && p < e) { + acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, + sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); + acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, + sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) + - 1); + err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, + verbose); + p += strlen(p) + 1; + } + AuTraceErr(err); + ignore_flags |= au_xattr_out_of_list; + if (!err && !acl_access) { + err = au_do_cpup_xattr(h_dst, h_src, + XATTR_NAME_POSIX_ACL_ACCESS, &value, + ignore_flags, verbose); + AuTraceErr(err); + } + if (!err && !acl_default) { + err = au_do_cpup_xattr(h_dst, h_src, + XATTR_NAME_POSIX_ACL_DEFAULT, &value, + ignore_flags, verbose); + AuTraceErr(err); + } + + au_kfree_try_rcu(value); + +out_free: + au_kfree_try_rcu(o); +out: + if (!unlocked) + inode_unlock_shared(h_isrc); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_smack_reentering(struct super_block *sb) +{ +#if IS_ENABLED(CONFIG_SECURITY_SMACK) || IS_ENABLED(CONFIG_SECURITY_SELINUX) + /* + * as a part of lookup, smack_d_instantiate() is called, and it calls + * i_op->getxattr(). ouch. + */ + return si_pid_test(sb); +#else + return 0; +#endif +} + +enum { + AU_XATTR_LIST, + AU_XATTR_GET +}; + +struct au_lgxattr { + int type; + union { + struct { + char *list; + size_t size; + } list; + struct { + const char *name; + void *value; + size_t size; + } get; + } u; +}; + +static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode, + struct au_lgxattr *arg) +{ + ssize_t err; + int reenter; + struct path h_path; + struct super_block *sb; + + sb = dentry->d_sb; + reenter = au_smack_reentering(sb); + if (!reenter) { + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out; + } + err = au_h_path_getattr(dentry, inode, /*force*/1, &h_path, reenter); + if (unlikely(err)) + goto out_si; + if (unlikely(!h_path.dentry)) + /* illegally overlapped or something */ + goto out_di; /* pretending success */ + + /* always topmost entry only */ + switch (arg->type) { + case AU_XATTR_LIST: + err = vfs_listxattr(h_path.dentry, + arg->u.list.list, arg->u.list.size); + break; + case AU_XATTR_GET: + AuDebugOn(d_is_negative(h_path.dentry)); + err = vfs_getxattr(h_path.dentry, + arg->u.get.name, arg->u.get.value, + arg->u.get.size); + break; + } + +out_di: + if (!reenter) + di_read_unlock(dentry, AuLock_IR); +out_si: + if (!reenter) + si_read_unlock(sb); +out: + AuTraceErr(err); + return err; +} + +ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) +{ + struct au_lgxattr arg = { + .type = AU_XATTR_LIST, + .u.list = { + .list = list, + .size = size + }, + }; + + return au_lgxattr(dentry, /*inode*/NULL, &arg); +} + +static ssize_t au_getxattr(struct dentry *dentry, struct inode *inode, + const char *name, void *value, size_t size) +{ + struct au_lgxattr arg = { + .type = AU_XATTR_GET, + .u.get = { + .name = name, + .value = value, + .size = size + }, + }; + + return au_lgxattr(dentry, inode, &arg); +} + +static int au_setxattr(struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, + int flags) +{ + struct au_sxattr arg = { + .type = AU_XATTR_SET, + .u.set = { + .name = name, + .value = value, + .size = size, + .flags = flags + }, + }; + + return au_sxattr(dentry, inode, &arg); +} + +/* ---------------------------------------------------------------------- */ + +static int au_xattr_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *buffer, size_t size) +{ + return au_getxattr(dentry, inode, name, buffer, size); +} + +static int au_xattr_set(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, + int flags) +{ + return au_setxattr(dentry, inode, name, value, size, flags); +} + +static const struct xattr_handler au_xattr_handler = { + .name = "", + .prefix = "", + .get = au_xattr_get, + .set = au_xattr_set +}; + +static const struct xattr_handler *au_xattr_handlers[] = { +#ifdef CONFIG_FS_POSIX_ACL + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, +#endif + &au_xattr_handler, /* must be last */ + NULL +}; + +void au_xattr_init(struct super_block *sb) +{ + sb->s_xattr = au_xattr_handlers; +} diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c new file mode 100644 index 000000000000..aa558f806625 --- /dev/null +++ b/fs/aufs/xino.c @@ -0,0 +1,1925 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * external inode number translation table and bitmap + * + * things to consider + * - the lifetime + * + au_xino object + * + XINO files (xino, xib, xigen) + * + dynamic debugfs entries (xiN) + * + static debugfs entries (xib, xigen) + * + static sysfs entry (xi_path) + * - several entry points to handle them. + * + mount(2) without xino option (default) + * + mount(2) with xino option + * + mount(2) with noxino option + * + umount(2) + * + remount with add/del branches + * + remount with xino/noxino options + */ + +#include +#include +#include "aufs.h" + +static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, + aufs_bindex_t bbot, + struct super_block *h_sb) +{ + /* todo: try binary-search if the branches are many */ + for (; btop <= bbot; btop++) + if (h_sb == au_sbr_sb(sb, btop)) + return btop; + return -1; +} + +/* + * find another branch who is on the same filesystem of the specified + * branch{@btgt}. search until @bbot. + */ +static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, + aufs_bindex_t bbot) +{ + aufs_bindex_t bindex; + struct super_block *tgt_sb; + + tgt_sb = au_sbr_sb(sb, btgt); + bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); + if (bindex < 0) + bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); + + return bindex; +} + +/* ---------------------------------------------------------------------- */ + +/* + * stop unnecessary notify events at creating xino files + */ + +aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) +{ + aufs_bindex_t bfound, bindex, bbot; + struct dentry *parent; + struct au_branch *br; + + bfound = -1; + parent = dentry->d_parent; /* safe d_parent access */ + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_dentry(br) == parent) { + bfound = bindex; + break; + } + } + + AuDbg("bfound b%d\n", bfound); + return bfound; +} + +struct au_xino_lock_dir { + struct au_hinode *hdir; + struct dentry *parent; + struct inode *dir; +}; + +static struct dentry *au_dget_parent_lock(struct dentry *dentry, + unsigned int lsc) +{ + struct dentry *parent; + struct inode *dir; + + parent = dget_parent(dentry); + dir = d_inode(parent); + inode_lock_nested(dir, lsc); +#if 0 /* it should not happen */ + spin_lock(&dentry->d_lock); + if (unlikely(dentry->d_parent != parent)) { + spin_unlock(&dentry->d_lock); + inode_unlock(dir); + dput(parent); + parent = NULL; + goto out; + } + spin_unlock(&dentry->d_lock); + +out: +#endif + return parent; +} + +static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, + struct au_xino_lock_dir *ldir) +{ + aufs_bindex_t bindex; + + ldir->hdir = NULL; + bindex = au_xi_root(sb, xipath->dentry); + if (bindex >= 0) { + /* rw branch root */ + ldir->hdir = au_hi(d_inode(sb->s_root), bindex); + au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); + } else { + /* other */ + ldir->parent = au_dget_parent_lock(xipath->dentry, + AuLsc_I_PARENT); + ldir->dir = d_inode(ldir->parent); + } +} + +static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) +{ + if (ldir->hdir) + au_hn_inode_unlock(ldir->hdir); + else { + inode_unlock(ldir->dir); + dput(ldir->parent); + } +} + +/* ---------------------------------------------------------------------- */ + +/* + * create and set a new xino file + */ +struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, + int wbrtop) +{ + struct file *file; + struct dentry *h_parent, *d; + struct inode *h_dir, *inode; + int err; + static DEFINE_MUTEX(mtx); + + /* + * at mount-time, and the xino file is the default path, + * hnotify is disabled so we have no notify events to ignore. + * when a user specified the xino, we cannot get au_hdir to be ignored. + */ + if (!wbrtop) + mutex_lock(&mtx); + file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE + /* | __FMODE_NONOTIFY */, + 0666); + if (IS_ERR(file)) { + if (!wbrtop) + mutex_unlock(&mtx); + if (!silent) + pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); + return file; + } + + /* keep file count */ + err = 0; + d = file->f_path.dentry; + h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); + if (!wbrtop) + mutex_unlock(&mtx); + /* mnt_want_write() is unnecessary here */ + h_dir = d_inode(h_parent); + inode = file_inode(file); + /* no delegation since it is just created */ + if (inode->i_nlink) + err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, + /*force*/0); + inode_unlock(h_dir); + dput(h_parent); + if (unlikely(err)) { + if (!silent) + pr_err("unlink %s(%d)\n", fpath, err); + goto out; + } + + err = -EINVAL; + if (unlikely(sb == d->d_sb)) { + if (!silent) + pr_err("%s must be outside\n", fpath); + goto out; + } + if (unlikely(au_test_fs_bad_xino(d->d_sb))) { + if (!silent) + pr_err("xino doesn't support %s(%s)\n", + fpath, au_sbtype(d->d_sb)); + goto out; + } + return file; /* success */ + +out: + fput(file); + file = ERR_PTR(err); + return file; +} + +/* + * create a new xinofile at the same place/path as @base. + */ +struct file *au_xino_create2(struct super_block *sb, struct path *base, + struct file *copy_src) +{ + struct file *file; + struct dentry *dentry, *parent; + struct inode *dir, *delegated; + struct qstr *name; + struct path path; + int err, do_unlock; + struct au_xino_lock_dir ldir; + + do_unlock = 1; + au_xino_lock_dir(sb, base, &ldir); + dentry = base->dentry; + parent = dentry->d_parent; /* dir inode is locked */ + dir = d_inode(parent); + IMustLock(dir); + + name = &dentry->d_name; + path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); + if (IS_ERR(path.dentry)) { + file = (void *)path.dentry; + pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); + goto out; + } + + /* no need to mnt_want_write() since we call dentry_open() later */ + err = vfs_create(dir, path.dentry, 0666, NULL); + if (unlikely(err)) { + file = ERR_PTR(err); + pr_err("%pd create err %d\n", dentry, err); + goto out_dput; + } + + path.mnt = base->mnt; + file = vfsub_dentry_open(&path, + O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE + /* | __FMODE_NONOTIFY */); + if (IS_ERR(file)) { + pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); + goto out_dput; + } + + delegated = NULL; + err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); + au_xino_unlock_dir(&ldir); + do_unlock = 0; + if (unlikely(err == -EWOULDBLOCK)) { + pr_warn("cannot retry for NFSv4 delegation" + " for an internal unlink\n"); + iput(delegated); + } + if (unlikely(err)) { + pr_err("%pd unlink err %d\n", dentry, err); + goto out_fput; + } + + if (copy_src) { + /* no one can touch copy_src xino */ + err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); + if (unlikely(err)) { + pr_err("%pd copy err %d\n", dentry, err); + goto out_fput; + } + } + goto out_dput; /* success */ + +out_fput: + fput(file); + file = ERR_PTR(err); +out_dput: + dput(path.dentry); +out: + if (do_unlock) + au_xino_unlock_dir(&ldir); + return file; +} + +struct file *au_xino_file1(struct au_xino *xi) +{ + struct file *file; + unsigned int u, nfile; + + file = NULL; + nfile = xi->xi_nfile; + for (u = 0; u < nfile; u++) { + file = xi->xi_file[u]; + if (file) + break; + } + + return file; +} + +static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) +{ + int err; + struct file *f; + void *p; + + if (file) + get_file(file); + + err = 0; + f = NULL; + if (idx < xi->xi_nfile) { + f = xi->xi_file[idx]; + if (f) + fput(f); + } else { + p = au_kzrealloc(xi->xi_file, + sizeof(*xi->xi_file) * xi->xi_nfile, + sizeof(*xi->xi_file) * (idx + 1), + GFP_NOFS, /*may_shrink*/0); + if (p) { + MtxMustLock(&xi->xi_mtx); + xi->xi_file = p; + xi->xi_nfile = idx + 1; + } else { + err = -ENOMEM; + if (file) + fput(file); + goto out; + } + } + xi->xi_file[idx] = file; + +out: + return err; +} + +/* + * if @xinew->xi is not set, then create new xigen file. + */ +struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) +{ + struct file *file; + int err; + + SiMustAnyLock(sb); + + file = au_xino_create2(sb, xinew->base, xinew->copy_src); + if (IS_ERR(file)) { + err = PTR_ERR(file); + pr_err("%s[%d], err %d\n", + xinew->xi ? "xino" : "xigen", + xinew->idx, err); + goto out; + } + + if (xinew->xi) + err = au_xino_file_set(xinew->xi, xinew->idx, file); + else { + BUG(); + /* todo: make xigen file an array */ + /* err = au_xigen_file_set(sb, xinew->idx, file); */ + } + fput(file); + if (unlikely(err)) + file = ERR_PTR(err); + +out: + return file; +} + +/* ---------------------------------------------------------------------- */ + +/* + * truncate xino files + */ +static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, + int idx, struct kstatfs *st) +{ + int err; + blkcnt_t blocks; + struct file *file, *new_xino; + struct au_xi_new xinew = { + .idx = idx + }; + + err = 0; + xinew.xi = au_sbr(sb, bindex)->br_xino; + file = au_xino_file(xinew.xi, idx); + if (!file) + goto out; + + xinew.base = &file->f_path; + err = vfs_statfs(xinew.base, st); + if (unlikely(err)) { + AuErr1("statfs err %d, ignored\n", err); + err = 0; + goto out; + } + + blocks = file_inode(file)->i_blocks; + pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", + bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); + + xinew.copy_src = file; + new_xino = au_xi_new(sb, &xinew); + if (IS_ERR(new_xino)) { + err = PTR_ERR(new_xino); + pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); + goto out; + } + + err = vfs_statfs(&new_xino->f_path, st); + if (!err) + pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", + bindex, idx, (u64)file_inode(new_xino)->i_blocks, + st->f_bfree, st->f_blocks); + else { + AuErr1("statfs err %d, ignored\n", err); + err = 0; + } + +out: + return err; +} + +int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) +{ + int err, i; + unsigned long jiffy; + aufs_bindex_t bbot; + struct kstatfs *st; + struct au_branch *br; + struct au_xino *xi; + + err = -ENOMEM; + st = kmalloc(sizeof(*st), GFP_NOFS); + if (unlikely(!st)) + goto out; + + err = -EINVAL; + bbot = au_sbbot(sb); + if (unlikely(bindex < 0 || bbot < bindex)) + goto out_st; + + err = 0; + jiffy = jiffies; + br = au_sbr(sb, bindex); + xi = br->br_xino; + for (i = idx_begin; !err && i < xi->xi_nfile; i++) + err = au_xino_do_trunc(sb, bindex, i, st); + if (!err) + au_sbi(sb)->si_xino_jiffy = jiffy; + +out_st: + au_kfree_rcu(st); +out: + return err; +} + +struct xino_do_trunc_args { + struct super_block *sb; + struct au_branch *br; + int idx; +}; + +static void xino_do_trunc(void *_args) +{ + struct xino_do_trunc_args *args = _args; + struct super_block *sb; + struct au_branch *br; + struct inode *dir; + int err, idx; + aufs_bindex_t bindex; + + err = 0; + sb = args->sb; + dir = d_inode(sb->s_root); + br = args->br; + idx = args->idx; + + si_noflush_write_lock(sb); + ii_read_lock_parent(dir); + bindex = au_br_index(sb, br->br_id); + err = au_xino_trunc(sb, bindex, idx); + ii_read_unlock(dir); + if (unlikely(err)) + pr_warn("err b%d, (%d)\n", bindex, err); + atomic_dec(&br->br_xino->xi_truncating); + au_lcnt_dec(&br->br_count); + si_write_unlock(sb); + au_nwt_done(&au_sbi(sb)->si_nowait); + au_kfree_rcu(args); +} + +/* + * returns the index in the xi_file array whose corresponding file is necessary + * to truncate, or -1 which means no need to truncate. + */ +static int xino_trunc_test(struct super_block *sb, struct au_branch *br) +{ + int err; + unsigned int u; + struct kstatfs st; + struct au_sbinfo *sbinfo; + struct au_xino *xi; + struct file *file; + + /* todo: si_xino_expire and the ratio should be customizable */ + sbinfo = au_sbi(sb); + if (time_before(jiffies, + sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) + return -1; + + /* truncation border */ + xi = br->br_xino; + for (u = 0; u < xi->xi_nfile; u++) { + file = au_xino_file(xi, u); + if (!file) + continue; + + err = vfs_statfs(&file->f_path, &st); + if (unlikely(err)) { + AuErr1("statfs err %d, ignored\n", err); + return -1; + } + if (div64_u64(st.f_bfree * 100, st.f_blocks) + >= AUFS_XINO_DEF_TRUNC) + return u; + } + + return -1; +} + +static void xino_try_trunc(struct super_block *sb, struct au_branch *br) +{ + int idx; + struct xino_do_trunc_args *args; + int wkq_err; + + idx = xino_trunc_test(sb, br); + if (idx < 0) + return; + + if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) + goto out; + + /* lock and kfree() will be called in trunc_xino() */ + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) { + AuErr1("no memory\n"); + goto out; + } + + au_lcnt_inc(&br->br_count); + args->sb = sb; + args->br = br; + args->idx = idx; + wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); + if (!wkq_err) + return; /* success */ + + pr_err("wkq %d\n", wkq_err); + au_lcnt_dec(&br->br_count); + au_kfree_rcu(args); + +out: + atomic_dec(&br->br_xino->xi_truncating); +} + +/* ---------------------------------------------------------------------- */ + +struct au_xi_calc { + int idx; + loff_t pos; +}; + +static void au_xi_calc(struct super_block *sb, ino_t h_ino, + struct au_xi_calc *calc) +{ + loff_t maxent; + + maxent = au_xi_maxent(sb); + calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); + calc->pos *= sizeof(ino_t); +} + +static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, + struct au_xi_calc *calc) +{ + int err; + struct file *file; + struct au_xino *xi = br->br_xino; + struct au_xi_new xinew = { + .xi = xi + }; + + SiMustAnyLock(sb); + + err = 0; + if (!xi) + goto out; + + mutex_lock(&xi->xi_mtx); + file = au_xino_file(xi, calc->idx); + if (file) + goto out_mtx; + + file = au_xino_file(xi, /*idx*/-1); + AuDebugOn(!file); + xinew.idx = calc->idx; + xinew.base = &file->f_path; + /* xinew.copy_src = NULL; */ + file = au_xi_new(sb, &xinew); + if (IS_ERR(file)) + err = PTR_ERR(file); + +out_mtx: + mutex_unlock(&xi->xi_mtx); +out: + return err; +} + +struct au_xino_do_new_async_args { + struct super_block *sb; + struct au_branch *br; + struct au_xi_calc calc; + ino_t ino; +}; + +struct au_xi_writing { + struct hlist_bl_node node; + ino_t h_ino, ino; +}; + +static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, + ino_t ino); + +static void au_xino_call_do_new_async(void *args) +{ + struct au_xino_do_new_async_args *a = args; + struct au_branch *br; + struct super_block *sb; + struct au_sbinfo *sbi; + struct inode *root; + struct file *file; + struct au_xi_writing *del, *p; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + int err; + + br = a->br; + sb = a->sb; + sbi = au_sbi(sb); + si_noflush_read_lock(sb); + root = d_inode(sb->s_root); + ii_read_lock_child(root); + err = au_xino_do_new_async(sb, br, &a->calc); + if (unlikely(err)) { + AuIOErr("err %d\n", err); + goto out; + } + + file = au_xino_file(br->br_xino, a->calc.idx); + AuDebugOn(!file); + err = au_xino_do_write(file, &a->calc, a->ino); + if (unlikely(err)) { + AuIOErr("err %d\n", err); + goto out; + } + + del = NULL; + hbl = &br->br_xino->xi_writing; + hlist_bl_lock(hbl); + au_hbl_for_each(pos, hbl) { + p = container_of(pos, struct au_xi_writing, node); + if (p->ino == a->ino) { + del = p; + hlist_bl_del(&p->node); + break; + } + } + hlist_bl_unlock(hbl); + au_kfree_rcu(del); + +out: + au_lcnt_dec(&br->br_count); + ii_read_unlock(root); + si_read_unlock(sb); + au_nwt_done(&sbi->si_nowait); + au_kfree_rcu(a); +} + +/* + * create a new xino file asynchronously + */ +static int au_xino_new_async(struct super_block *sb, struct au_branch *br, + struct au_xi_calc *calc, ino_t ino) +{ + int err; + struct au_xino_do_new_async_args *arg; + + err = -ENOMEM; + arg = kmalloc(sizeof(*arg), GFP_NOFS); + if (unlikely(!arg)) + goto out; + + arg->sb = sb; + arg->br = br; + arg->calc = *calc; + arg->ino = ino; + au_lcnt_inc(&br->br_count); + err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); + if (unlikely(err)) { + pr_err("wkq %d\n", err); + au_lcnt_dec(&br->br_count); + au_kfree_rcu(arg); + } + +out: + return err; +} + +/* + * read @ino from xinofile for the specified branch{@sb, @bindex} + * at the position of @h_ino. + */ +int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t *ino) +{ + int err; + ssize_t sz; + struct au_xi_calc calc; + struct au_sbinfo *sbinfo; + struct file *file; + struct au_xino *xi; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos; + struct au_xi_writing *p; + + *ino = 0; + if (!au_opt_test(au_mntflags(sb), XINO)) + return 0; /* no xino */ + + err = 0; + au_xi_calc(sb, h_ino, &calc); + xi = au_sbr(sb, bindex)->br_xino; + file = au_xino_file(xi, calc.idx); + if (!file) { + hbl = &xi->xi_writing; + hlist_bl_lock(hbl); + au_hbl_for_each(pos, hbl) { + p = container_of(pos, struct au_xi_writing, node); + if (p->h_ino == h_ino) { + AuDbg("hi%llu, i%llu, found\n", + (u64)p->h_ino, (u64)p->ino); + *ino = p->ino; + break; + } + } + hlist_bl_unlock(hbl); + return 0; + } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) + return 0; /* no xino */ + + sbinfo = au_sbi(sb); + sz = xino_fread(file, ino, sizeof(*ino), &calc.pos); + if (sz == sizeof(*ino)) + return 0; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xino read error (%zd)\n", sz); + } + return err; +} + +static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, + ino_t ino) +{ + ssize_t sz; + + sz = xino_fwrite(file, &ino, sizeof(ino), &calc->pos); + if (sz == sizeof(ino)) + return 0; /* success */ + + AuIOErr("write failed (%zd)\n", sz); + return -EIO; +} + +/* + * write @ino to the xinofile for the specified branch{@sb, @bindex} + * at the position of @h_ino. + * even if @ino is zero, it is written to the xinofile and means no entry. + * if the size of the xino file on a specific filesystem exceeds the watermark, + * try truncating it. + */ +int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t ino) +{ + int err; + unsigned int mnt_flags; + struct au_xi_calc calc; + struct file *file; + struct au_branch *br; + struct au_xino *xi; + struct au_xi_writing *p; + + SiMustAnyLock(sb); + + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, XINO)) + return 0; + + au_xi_calc(sb, h_ino, &calc); + br = au_sbr(sb, bindex); + xi = br->br_xino; + file = au_xino_file(xi, calc.idx); + if (!file) { + /* store the inum pair into the list */ + p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); + p->h_ino = h_ino; + p->ino = ino; + au_hbl_add(&p->node, &xi->xi_writing); + + /* create and write a new xino file asynchronously */ + err = au_xino_new_async(sb, br, &calc, ino); + if (!err) + return 0; /* success */ + goto out; + } + + err = au_xino_do_write(file, &calc, ino); + if (!err) { + br = au_sbr(sb, bindex); + if (au_opt_test(mnt_flags, TRUNC_XINO) + && au_test_fs_trunc_xino(au_br_sb(br))) + xino_try_trunc(sb, br); + return 0; /* success */ + } + +out: + AuIOErr("write failed (%d)\n", err); + return -EIO; +} + +static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, + loff_t *pos); + +/* todo: unnecessary to support mmap_sem since kernel-space? */ +ssize_t xino_fread(struct file *file, void *kbuf, size_t size, loff_t *pos) +{ + ssize_t err; + int i; + const int prevent_endless = 10; + + i = 0; + do { + err = vfsub_read_k(file, kbuf, size, pos); + if (err == -EINTR + && !au_wkq_test() + && fatal_signal_pending(current)) { + err = xino_fread_wkq(file, kbuf, size, pos); + BUG_ON(err == -EINTR); + } + } while (i++ < prevent_endless + && (err == -EAGAIN || err == -EINTR)); + +#if 0 /* reserved for future use */ + if (err > 0) + fsnotify_access(file->f_path.dentry); +#endif + + return err; +} + +struct xino_fread_args { + ssize_t *errp; + struct file *file; + void *buf; + size_t size; + loff_t *pos; +}; + +static void call_xino_fread(void *args) +{ + struct xino_fread_args *a = args; + *a->errp = xino_fread(a->file, a->buf, a->size, a->pos); +} + +static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, + loff_t *pos) +{ + ssize_t err; + int wkq_err; + struct xino_fread_args args = { + .errp = &err, + .file = file, + .buf = buf, + .size = size, + .pos = pos + }; + + wkq_err = au_wkq_wait(call_xino_fread, &args); + if (unlikely(wkq_err)) + err = wkq_err; + + return err; +} + +static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, + loff_t *pos); + +static ssize_t do_xino_fwrite(struct file *file, void *kbuf, size_t size, + loff_t *pos) +{ + ssize_t err; + int i; + const int prevent_endless = 10; + + i = 0; + do { + err = vfsub_write_k(file, kbuf, size, pos); + if (err == -EINTR + && !au_wkq_test() + && fatal_signal_pending(current)) { + err = xino_fwrite_wkq(file, kbuf, size, pos); + BUG_ON(err == -EINTR); + } + } while (i++ < prevent_endless + && (err == -EAGAIN || err == -EINTR)); + +#if 0 /* reserved for future use */ + if (err > 0) + fsnotify_modify(file->f_path.dentry); +#endif + + return err; +} + +struct do_xino_fwrite_args { + ssize_t *errp; + struct file *file; + void *buf; + size_t size; + loff_t *pos; +}; + +static void call_do_xino_fwrite(void *args) +{ + struct do_xino_fwrite_args *a = args; + *a->errp = do_xino_fwrite(a->file, a->buf, a->size, a->pos); +} + +static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, + loff_t *pos) +{ + ssize_t err; + int wkq_err; + struct do_xino_fwrite_args args = { + .errp = &err, + .file = file, + .buf = buf, + .size = size, + .pos = pos + }; + + /* + * it breaks RLIMIT_FSIZE and normal user's limit, + * users should care about quota and real 'filesystem full.' + */ + wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); + if (unlikely(wkq_err)) + err = wkq_err; + + return err; +} + +ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos) +{ + ssize_t err; + + if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { + lockdep_off(); + err = do_xino_fwrite(file, buf, size, pos); + lockdep_on(); + } else { + lockdep_off(); + err = xino_fwrite_wkq(file, buf, size, pos); + lockdep_on(); + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * inode number bitmap + */ +static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; +static ino_t xib_calc_ino(unsigned long pindex, int bit) +{ + ino_t ino; + + AuDebugOn(bit < 0 || page_bits <= bit); + ino = AUFS_FIRST_INO + pindex * page_bits + bit; + return ino; +} + +static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) +{ + AuDebugOn(ino < AUFS_FIRST_INO); + ino -= AUFS_FIRST_INO; + *pindex = ino / page_bits; + *bit = ino % page_bits; +} + +static int xib_pindex(struct super_block *sb, unsigned long pindex) +{ + int err; + loff_t pos; + ssize_t sz; + struct au_sbinfo *sbinfo; + struct file *xib; + unsigned long *p; + + sbinfo = au_sbi(sb); + MtxMustLock(&sbinfo->si_xib_mtx); + AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE + || !au_opt_test(sbinfo->si_mntflags, XINO)); + + if (pindex == sbinfo->si_xib_last_pindex) + return 0; + + xib = sbinfo->si_xib; + p = sbinfo->si_xib_buf; + pos = sbinfo->si_xib_last_pindex; + pos *= PAGE_SIZE; + sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); + if (unlikely(sz != PAGE_SIZE)) + goto out; + + pos = pindex; + pos *= PAGE_SIZE; + if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) + sz = xino_fread(xib, p, PAGE_SIZE, &pos); + else { + memset(p, 0, PAGE_SIZE); + sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); + } + if (sz == PAGE_SIZE) { + sbinfo->si_xib_last_pindex = pindex; + return 0; /* success */ + } + +out: + AuIOErr1("write failed (%zd)\n", sz); + err = sz; + if (sz >= 0) + err = -EIO; + return err; +} + +static void au_xib_clear_bit(struct inode *inode) +{ + int err, bit; + unsigned long pindex; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + AuDebugOn(inode->i_nlink); + + sb = inode->i_sb; + xib_calc_bit(inode->i_ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + sbinfo = au_sbi(sb); + mutex_lock(&sbinfo->si_xib_mtx); + err = xib_pindex(sb, pindex); + if (!err) { + clear_bit(bit, sbinfo->si_xib_buf); + sbinfo->si_xib_next_bit = bit; + } + mutex_unlock(&sbinfo->si_xib_mtx); +} + +/* ---------------------------------------------------------------------- */ + +/* + * truncate a xino bitmap file + */ + +/* todo: slow */ +static int do_xib_restore(struct super_block *sb, struct file *file, void *page) +{ + int err, bit; + ssize_t sz; + unsigned long pindex; + loff_t pos, pend; + struct au_sbinfo *sbinfo; + ino_t *ino; + unsigned long *p; + + err = 0; + sbinfo = au_sbi(sb); + MtxMustLock(&sbinfo->si_xib_mtx); + p = sbinfo->si_xib_buf; + pend = vfsub_f_size_read(file); + pos = 0; + while (pos < pend) { + sz = xino_fread(file, page, PAGE_SIZE, &pos); + err = sz; + if (unlikely(sz <= 0)) + goto out; + + err = 0; + for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { + if (unlikely(*ino < AUFS_FIRST_INO)) + continue; + + xib_calc_bit(*ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + err = xib_pindex(sb, pindex); + if (!err) + set_bit(bit, p); + else + goto out; + } + } + +out: + return err; +} + +static int xib_restore(struct super_block *sb) +{ + int err, i; + unsigned int nfile; + aufs_bindex_t bindex, bbot; + void *page; + struct au_branch *br; + struct au_xino *xi; + struct file *file; + + err = -ENOMEM; + page = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!page)) + goto out; + + err = 0; + bbot = au_sbbot(sb); + for (bindex = 0; !err && bindex <= bbot; bindex++) + if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) { + br = au_sbr(sb, bindex); + xi = br->br_xino; + nfile = xi->xi_nfile; + for (i = 0; i < nfile; i++) { + file = au_xino_file(xi, i); + if (file) + err = do_xib_restore(sb, file, page); + } + } else + AuDbg("skip shared b%d\n", bindex); + free_page((unsigned long)page); + +out: + return err; +} + +int au_xib_trunc(struct super_block *sb) +{ + int err; + ssize_t sz; + loff_t pos; + struct au_sbinfo *sbinfo; + unsigned long *p; + struct file *file; + + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); + if (!au_opt_test(sbinfo->si_mntflags, XINO)) + goto out; + + file = sbinfo->si_xib; + if (vfsub_f_size_read(file) <= PAGE_SIZE) + goto out; + + file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + fput(sbinfo->si_xib); + sbinfo->si_xib = file; + + p = sbinfo->si_xib_buf; + memset(p, 0, PAGE_SIZE); + pos = 0; + sz = xino_fwrite(sbinfo->si_xib, p, PAGE_SIZE, &pos); + if (unlikely(sz != PAGE_SIZE)) { + err = sz; + AuIOErr("err %d\n", err); + if (sz >= 0) + err = -EIO; + goto out; + } + + mutex_lock(&sbinfo->si_xib_mtx); + /* mnt_want_write() is unnecessary here */ + err = xib_restore(sb); + mutex_unlock(&sbinfo->si_xib_mtx); + +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_xino *au_xino_alloc(unsigned int nfile) +{ + struct au_xino *xi; + + xi = kzalloc(sizeof(*xi), GFP_NOFS); + if (unlikely(!xi)) + goto out; + xi->xi_nfile = nfile; + xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); + if (unlikely(!xi->xi_file)) + goto out_free; + + xi->xi_nondir.total = 8; /* initial size */ + xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), + GFP_NOFS); + if (unlikely(!xi->xi_nondir.array)) + goto out_file; + + spin_lock_init(&xi->xi_nondir.spin); + init_waitqueue_head(&xi->xi_nondir.wqh); + mutex_init(&xi->xi_mtx); + INIT_HLIST_BL_HEAD(&xi->xi_writing); + atomic_set(&xi->xi_truncating, 0); + kref_init(&xi->xi_kref); + goto out; /* success */ + +out_file: + au_kfree_try_rcu(xi->xi_file); +out_free: + au_kfree_rcu(xi); + xi = NULL; +out: + return xi; +} + +static int au_xino_init(struct au_branch *br, int idx, struct file *file) +{ + int err; + struct au_xino *xi; + + err = 0; + xi = au_xino_alloc(idx + 1); + if (unlikely(!xi)) { + err = -ENOMEM; + goto out; + } + + if (file) + get_file(file); + xi->xi_file[idx] = file; + AuDebugOn(br->br_xino); + br->br_xino = xi; + +out: + return err; +} + +static void au_xino_release(struct kref *kref) +{ + struct au_xino *xi; + int i; + unsigned long ul; + struct hlist_bl_head *hbl; + struct hlist_bl_node *pos, *n; + struct au_xi_writing *p; + + xi = container_of(kref, struct au_xino, xi_kref); + for (i = 0; i < xi->xi_nfile; i++) + if (xi->xi_file[i]) + fput(xi->xi_file[i]); + for (i = xi->xi_nondir.total - 1; i >= 0; i--) + AuDebugOn(xi->xi_nondir.array[i]); + mutex_destroy(&xi->xi_mtx); + hbl = &xi->xi_writing; + ul = au_hbl_count(hbl); + if (unlikely(ul)) { + pr_warn("xi_writing %lu\n", ul); + hlist_bl_lock(hbl); + hlist_bl_for_each_entry_safe(p, pos, n, hbl, node) { + hlist_bl_del(&p->node); + /* kmemleak reported au_kfree_rcu() doesn't free it */ + kfree(p); + } + hlist_bl_unlock(hbl); + } + au_kfree_try_rcu(xi->xi_file); + au_kfree_try_rcu(xi->xi_nondir.array); + au_kfree_rcu(xi); +} + +int au_xino_put(struct au_branch *br) +{ + int ret; + struct au_xino *xi; + + ret = 0; + xi = br->br_xino; + if (xi) { + br->br_xino = NULL; + ret = kref_put(&xi->xi_kref, au_xino_release); + } + + return ret; +} + +/* ---------------------------------------------------------------------- */ + +/* + * xino mount option handlers + */ + +/* xino bitmap */ +static void xino_clear_xib(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; + if (sbinfo->si_xib_buf) + free_page((unsigned long)sbinfo->si_xib_buf); + sbinfo->si_xib_buf = NULL; +} + +static int au_xino_set_xib(struct super_block *sb, struct path *path) +{ + int err; + loff_t pos; + struct au_sbinfo *sbinfo; + struct file *file; + struct super_block *xi_sb; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + file = au_xino_create2(sb, path, sbinfo->si_xib); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = file; + xi_sb = file_inode(file)->i_sb; + sbinfo->si_ximaxent = xi_sb->s_maxbytes; + if (unlikely(sbinfo->si_ximaxent < PAGE_SIZE)) { + err = -EIO; + pr_err("s_maxbytes(%llu) on %s is too small\n", + (u64)sbinfo->si_ximaxent, au_sbtype(xi_sb)); + goto out_unset; + } + sbinfo->si_ximaxent /= sizeof(ino_t); + + err = -ENOMEM; + if (!sbinfo->si_xib_buf) + sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); + if (unlikely(!sbinfo->si_xib_buf)) + goto out_unset; + + sbinfo->si_xib_last_pindex = 0; + sbinfo->si_xib_next_bit = 0; + if (vfsub_f_size_read(file) < PAGE_SIZE) { + pos = 0; + err = xino_fwrite(file, sbinfo->si_xib_buf, PAGE_SIZE, &pos); + if (unlikely(err != PAGE_SIZE)) + goto out_free; + } + err = 0; + goto out; /* success */ + +out_free: + if (sbinfo->si_xib_buf) + free_page((unsigned long)sbinfo->si_xib_buf); + sbinfo->si_xib_buf = NULL; + if (err >= 0) + err = -EIO; +out_unset: + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; +out: + AuTraceErr(err); + return err; +} + +/* xino for each branch */ +static void xino_clear_br(struct super_block *sb) +{ + aufs_bindex_t bindex, bbot; + struct au_branch *br; + + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + AuDebugOn(!br); + au_xino_put(br); + } +} + +static void au_xino_set_br_shared(struct super_block *sb, struct au_branch *br, + aufs_bindex_t bshared) +{ + struct au_branch *brshared; + + brshared = au_sbr(sb, bshared); + AuDebugOn(!brshared->br_xino); + AuDebugOn(!brshared->br_xino->xi_file); + if (br->br_xino != brshared->br_xino) { + au_xino_get(brshared); + au_xino_put(br); + br->br_xino = brshared->br_xino; + } +} + +struct au_xino_do_set_br { + struct au_branch *br; + ino_t h_ino; + aufs_bindex_t bshared; +}; + +static int au_xino_do_set_br(struct super_block *sb, struct path *path, + struct au_xino_do_set_br *args) +{ + int err; + struct au_xi_calc calc; + struct file *file; + struct au_branch *br; + struct au_xi_new xinew = { + .base = path + }; + + br = args->br; + xinew.xi = br->br_xino; + au_xi_calc(sb, args->h_ino, &calc); + xinew.copy_src = au_xino_file(xinew.xi, calc.idx); + if (args->bshared >= 0) + /* shared xino */ + au_xino_set_br_shared(sb, br, args->bshared); + else if (!xinew.xi) { + /* new xino */ + err = au_xino_init(br, calc.idx, xinew.copy_src); + if (unlikely(err)) + goto out; + } + + /* force re-creating */ + xinew.xi = br->br_xino; + xinew.idx = calc.idx; + mutex_lock(&xinew.xi->xi_mtx); + file = au_xi_new(sb, &xinew); + mutex_unlock(&xinew.xi->xi_mtx); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + AuDebugOn(!file); + + err = au_xino_do_write(file, &calc, AUFS_ROOT_INO); + if (unlikely(err)) + au_xino_put(br); + +out: + AuTraceErr(err); + return err; +} + +static int au_xino_set_br(struct super_block *sb, struct path *path) +{ + int err; + aufs_bindex_t bindex, bbot; + struct au_xino_do_set_br args; + struct inode *inode; + + SiMustWriteLock(sb); + + bbot = au_sbbot(sb); + inode = d_inode(sb->s_root); + for (bindex = 0; bindex <= bbot; bindex++) { + args.h_ino = au_h_iptr(inode, bindex)->i_ino; + args.br = au_sbr(sb, bindex); + args.bshared = is_sb_shared(sb, bindex, bindex - 1); + err = au_xino_do_set_br(sb, path, &args); + if (unlikely(err)) + break; + } + + AuTraceErr(err); + return err; +} + +void au_xino_clr(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + au_xigen_clr(sb); + xino_clear_xib(sb); + xino_clear_br(sb); + dbgaufs_brs_del(sb, 0); + sbinfo = au_sbi(sb); + /* lvalue, do not call au_mntflags() */ + au_opt_clr(sbinfo->si_mntflags, XINO); +} + +int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount) +{ + int err, skip; + struct dentry *dentry, *parent, *cur_dentry, *cur_parent; + struct qstr *dname, *cur_name; + struct file *cur_xino; + struct au_sbinfo *sbinfo; + struct path *path, *cur_path; + + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); + path = &xiopt->file->f_path; + dentry = path->dentry; + parent = dget_parent(dentry); + if (remount) { + skip = 0; + cur_xino = sbinfo->si_xib; + if (cur_xino) { + cur_path = &cur_xino->f_path; + cur_dentry = cur_path->dentry; + cur_parent = dget_parent(cur_dentry); + cur_name = &cur_dentry->d_name; + dname = &dentry->d_name; + skip = (cur_parent == parent + && au_qstreq(dname, cur_name)); + dput(cur_parent); + } + if (skip) + goto out; + } + + au_opt_set(sbinfo->si_mntflags, XINO); + err = au_xino_set_xib(sb, path); + /* si_x{read,write} are set */ + if (!err) + err = au_xigen_set(sb, path); + if (!err) + err = au_xino_set_br(sb, path); + if (!err) { + dbgaufs_brs_add(sb, 0, /*topdown*/1); + goto out; /* success */ + } + + /* reset all */ + AuIOErr("failed setting xino(%d).\n", err); + au_xino_clr(sb); + +out: + dput(parent); + return err; +} + +/* + * create a xinofile at the default place/path. + */ +struct file *au_xino_def(struct super_block *sb) +{ + struct file *file; + char *page, *p; + struct au_branch *br; + struct super_block *h_sb; + struct path path; + aufs_bindex_t bbot, bindex, bwr; + + br = NULL; + bbot = au_sbbot(sb); + bwr = -1; + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_writable(br->br_perm) + && !au_test_fs_bad_xino(au_br_sb(br))) { + bwr = bindex; + break; + } + } + + if (bwr >= 0) { + file = ERR_PTR(-ENOMEM); + page = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!page)) + goto out; + path.mnt = au_br_mnt(br); + path.dentry = au_h_dptr(sb->s_root, bwr); + p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); + file = (void *)p; + if (!IS_ERR(p)) { + strcat(p, "/" AUFS_XINO_FNAME); + AuDbg("%s\n", p); + file = au_xino_create(sb, p, /*silent*/0, /*wbrtop*/1); + } + free_page((unsigned long)page); + } else { + file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, + /*wbrtop*/0); + if (IS_ERR(file)) + goto out; + h_sb = file->f_path.dentry->d_sb; + if (unlikely(au_test_fs_bad_xino(h_sb))) { + pr_err("xino doesn't support %s(%s)\n", + AUFS_XINO_DEFPATH, au_sbtype(h_sb)); + fput(file); + file = ERR_PTR(-EINVAL); + } + } + +out: + return file; +} + +/* ---------------------------------------------------------------------- */ + +/* + * initialize the xinofile for the specified branch @br + * at the place/path where @base_file indicates. + * test whether another branch is on the same filesystem or not, + * if found then share the xinofile with another branch. + */ +int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, + struct path *base) +{ + int err; + struct au_xino_do_set_br args = { + .h_ino = h_ino, + .br = br + }; + + args.bshared = sbr_find_shared(sb, /*btop*/0, au_sbbot(sb), + au_br_sb(br)); + err = au_xino_do_set_br(sb, base, &args); + if (unlikely(err)) + au_xino_put(br); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * get an unused inode number from bitmap + */ +ino_t au_xino_new_ino(struct super_block *sb) +{ + ino_t ino; + unsigned long *p, pindex, ul, pend; + struct au_sbinfo *sbinfo; + struct file *file; + int free_bit, err; + + if (!au_opt_test(au_mntflags(sb), XINO)) + return iunique(sb, AUFS_FIRST_INO); + + sbinfo = au_sbi(sb); + mutex_lock(&sbinfo->si_xib_mtx); + p = sbinfo->si_xib_buf; + free_bit = sbinfo->si_xib_next_bit; + if (free_bit < page_bits && !test_bit(free_bit, p)) + goto out; /* success */ + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + + pindex = sbinfo->si_xib_last_pindex; + for (ul = pindex - 1; ul < ULONG_MAX; ul--) { + err = xib_pindex(sb, ul); + if (unlikely(err)) + goto out_err; + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + } + + file = sbinfo->si_xib; + pend = vfsub_f_size_read(file) / PAGE_SIZE; + for (ul = pindex + 1; ul <= pend; ul++) { + err = xib_pindex(sb, ul); + if (unlikely(err)) + goto out_err; + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + } + BUG(); + +out: + set_bit(free_bit, p); + sbinfo->si_xib_next_bit = free_bit + 1; + pindex = sbinfo->si_xib_last_pindex; + mutex_unlock(&sbinfo->si_xib_mtx); + ino = xib_calc_ino(pindex, free_bit); + AuDbg("i%lu\n", (unsigned long)ino); + return ino; +out_err: + mutex_unlock(&sbinfo->si_xib_mtx); + AuDbg("i0\n"); + return 0; +} + +/* for s_op->delete_inode() */ +void au_xino_delete_inode(struct inode *inode, const int unlinked) +{ + int err; + unsigned int mnt_flags; + aufs_bindex_t bindex, bbot, bi; + unsigned char try_trunc; + struct au_iinfo *iinfo; + struct super_block *sb; + struct au_hinode *hi; + struct inode *h_inode; + struct au_branch *br; + struct au_xi_calc calc; + struct file *file; + + AuDebugOn(au_is_bad_inode(inode)); + + sb = inode->i_sb; + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, XINO) + || inode->i_ino == AUFS_ROOT_INO) + return; + + if (unlinked) { + au_xigen_inc(inode); + au_xib_clear_bit(inode); + } + + iinfo = au_ii(inode); + bindex = iinfo->ii_btop; + if (bindex < 0) + return; + + try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); + hi = au_hinode(iinfo, bindex); + bbot = iinfo->ii_bbot; + for (; bindex <= bbot; bindex++, hi++) { + h_inode = hi->hi_inode; + if (!h_inode + || (!unlinked && h_inode->i_nlink)) + continue; + + /* inode may not be revalidated */ + bi = au_br_index(sb, hi->hi_id); + if (bi < 0) + continue; + + br = au_sbr(sb, bi); + au_xi_calc(sb, h_inode->i_ino, &calc); + file = au_xino_file(br->br_xino, calc.idx); + if (IS_ERR_OR_NULL(file)) + continue; + + err = au_xino_do_write(file, &calc, /*ino*/0); + if (!err && try_trunc + && au_test_fs_trunc_xino(au_br_sb(br))) + xino_try_trunc(sb, br); + } +} + +/* ---------------------------------------------------------------------- */ + +static int au_xinondir_find(struct au_xino *xi, ino_t h_ino) +{ + int found, total, i; + + found = -1; + total = xi->xi_nondir.total; + for (i = 0; i < total; i++) { + if (xi->xi_nondir.array[i] != h_ino) + continue; + found = i; + break; + } + + return found; +} + +static int au_xinondir_expand(struct au_xino *xi) +{ + int err, sz; + ino_t *p; + + BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); + + err = -ENOMEM; + sz = xi->xi_nondir.total * sizeof(ino_t); + if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) + goto out; + p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, + /*may_shrink*/0); + if (p) { + xi->xi_nondir.array = p; + xi->xi_nondir.total <<= 1; + AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); + err = 0; + } + +out: + return err; +} + +void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, + ino_t h_ino, int idx) +{ + struct au_xino *xi; + + AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); + xi = au_sbr(sb, bindex)->br_xino; + AuDebugOn(idx < 0 || xi->xi_nondir.total <= idx); + + spin_lock(&xi->xi_nondir.spin); + AuDebugOn(xi->xi_nondir.array[idx] != h_ino); + xi->xi_nondir.array[idx] = 0; + spin_unlock(&xi->xi_nondir.spin); + wake_up_all(&xi->xi_nondir.wqh); +} + +int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + int *idx) +{ + int err, found, empty; + struct au_xino *xi; + + err = 0; + *idx = -1; + if (!au_opt_test(au_mntflags(sb), XINO)) + goto out; /* no xino */ + + xi = au_sbr(sb, bindex)->br_xino; + +again: + spin_lock(&xi->xi_nondir.spin); + found = au_xinondir_find(xi, h_ino); + if (found == -1) { + empty = au_xinondir_find(xi, /*h_ino*/0); + if (empty == -1) { + empty = xi->xi_nondir.total; + err = au_xinondir_expand(xi); + if (unlikely(err)) + goto out_unlock; + } + xi->xi_nondir.array[empty] = h_ino; + *idx = empty; + } else { + spin_unlock(&xi->xi_nondir.spin); + wait_event(xi->xi_nondir.wqh, + xi->xi_nondir.array[found] != h_ino); + goto again; + } + +out_unlock: + spin_unlock(&xi->xi_nondir.spin); +out: + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_xino_path(struct seq_file *seq, struct file *file) +{ + int err; + + err = au_seq_path(seq, &file->f_path); + if (unlikely(err)) + goto out; + +#define Deleted "\\040(deleted)" + seq->count -= sizeof(Deleted) - 1; + AuDebugOn(memcmp(seq->buf + seq->count, Deleted, + sizeof(Deleted) - 1)); +#undef Deleted + +out: + return err; +} diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index e738f6206ea5..cd78781d6e17 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -14,10 +14,20 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ block-rsv.o delalloc-space.o block-group.o discard.o reflink.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o +btrfs-$(CONFIG_SYNO_BTRFS_WINACL) += syno_acl.o btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o btrfs-$(CONFIG_BTRFS_FS_REF_VERIFY) += ref-verify.o +btrfs-$(CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE) += free-space-analyze.o +btrfs-$(CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION) += snapshot-size-query.o +btrfs-$(CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE) += syno-extent-usage.o +btrfs-$(CONFIG_SYNO_BTRFS_SYNO_QUOTA) += usrquota.o +btrfs-$(CONFIG_SYNO_BTRFS_LOCKER) += syno-locker.o + btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ tests/extent-buffer-tests.o tests/btrfs-tests.o \ tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o \ tests/free-space-tree-tests.o tests/extent-map-tests.o + +btrfs-$(CONFIG_SYNO_BTRFS_FEATURE_TREE) += syno-feat-tree.o +btrfs-$(CONFIG_SYNO_BTRFS_RBD_META) += syno-rbd-meta.o diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 309516e6a968..ce2f81511acb 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -157,6 +160,25 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, return ret; } +#ifdef MY_ABC_HERE +struct btrfs_workqueue *btrfs_alloc_workqueue_with_sysfs( + struct btrfs_fs_info *fs_info, + const char *name, + unsigned int flags, + int limit_active, + int thresh) +{ + /* 32 for sid, 12 for prefix and postfix in __btrfs_alloc_workqueue */ + char trimmed_name[21] = {0}; + char name_sid[WQ_NAME_LEN] = {0}; + BUILD_BUG_ON((WQ_NAME_LEN - 44) < 20); + + snprintf(trimmed_name, sizeof(trimmed_name), "%s", name); + snprintf(name_sid, sizeof(name_sid), "%s-%s", trimmed_name, fs_info->sb->s_id); + return btrfs_alloc_workqueue(fs_info, name_sid, flags | WQ_SYSFS, limit_active, thresh); +} +#endif /* MY_ABC_HERE */ + /* * Hook for threshold which will be called in btrfs_queue_work. * This hook WILL be called in IRQ handler context, diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 3204daa51b95..7a7e39f8ecc3 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -34,6 +37,15 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, unsigned int flags, int limit_active, int thresh); +#ifdef MY_ABC_HERE +struct btrfs_workqueue *btrfs_alloc_workqueue_with_sysfs( + struct btrfs_fs_info *fs_info, + const char *name, + unsigned int flags, + int limit_active, + int thresh); +#endif /* MY_ABC_HERE */ + void btrfs_init_work(struct btrfs_work *work, btrfs_func_t func, btrfs_func_t ordered_func, btrfs_func_t ordered_free); void btrfs_queue_work(struct btrfs_workqueue *wq, diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 6e447bdaf9ec..eb33378ee061 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2011 STRATO. All rights reserved. @@ -17,10 +20,21 @@ /* Just an arbitrary number so we can be sure this happened */ #define BACKREF_FOUND_SHARED 6 +#ifdef MY_ABC_HERE +#define BACKREF_NEXT_ITEM 253 +#define BACKREF_FOUND_SHARED_ROOT 254 +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BACKREF_FOUND_ROOT_INO 255 +#endif /* MY_ABC_HERE */ struct extent_inode_elem { u64 inum; u64 offset; +#ifdef MY_ABC_HERE + int extent_type; +#endif /* MY_ABC_HERE */ struct extent_inode_elem *next; }; @@ -57,6 +71,9 @@ static int check_extent_in_eb(const struct btrfs_key *key, e->next = *eie; e->inum = key->objectid; e->offset = key->offset + offset; +#ifdef MY_ABC_HERE + e->extent_type = btrfs_file_extent_type(eb, fi); +#endif /* MY_ABC_HERE */ *eie = e; return 0; @@ -112,6 +129,54 @@ static int find_extent_in_eb(const struct extent_buffer *eb, return 0; } +#ifdef MY_ABC_HERE +// Copied from find_extent_in_eb(). +static int find_ino_extent_in_eb(struct extent_buffer *eb, + u64 wanted_disk_byte, u64 ino, u64 offset) +{ + u64 disk_byte; + struct btrfs_key key; + struct btrfs_file_extent_item *fi; + int slot; + int nritems; + int extent_type; + + /* + * from the shared data ref, we only have the leaf but we need + * the key. thus, we must look into all items and see that we + * find one (some) with a reference to our extent item. + */ + nritems = btrfs_header_nritems(eb); + for (slot = 0; slot < nritems; ++slot) { + btrfs_item_key_to_cpu(eb, &key, slot); + if (key.objectid > ino) + break; + if (key.type != BTRFS_EXTENT_DATA_KEY) + continue; + fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(eb, fi); + if (extent_type == BTRFS_FILE_EXTENT_INLINE) + continue; + /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */ + disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); + if (disk_byte != wanted_disk_byte) + continue; + + if (key.objectid == ino) { + if (key.offset >= offset) + return 0; + /* + * For offset != (u64)-1, ulist could avoid calling check for + * same extent multiple times. + */ + return 1; + } + } + + return 0; +} +#endif /* MY_ABC_HERE */ + struct preftree { struct rb_root_cached root; unsigned int count; @@ -125,6 +190,18 @@ struct preftrees { struct preftree indirect_missing_keys; }; +#ifdef MY_ABC_HERE +enum share_check_mode { + SC_FIND_SHARED, + SC_FIND_SHARED_ROOT, +}; + +enum found_state_bits { + DIRECT, + INDIRECT, +}; +#endif /* MY_ABC_HERE */ + /* * Checks for a shared extent during backref search. * @@ -137,10 +214,77 @@ struct share_check { u64 root_objectid; u64 inum; int share_count; +#ifdef MY_ABC_HERE + enum share_check_mode mode; + unsigned long found_state; + struct ulist *shared_roots; + u64 direct_backref_lowest_bytenr; + u64 indirect_backref_highest_rootid; + u64 indirect_backref_lowest_inum; + u64 indirect_backref_lowest_offset; + u64 parent_bytenr; + u64 offset; + u64 datao; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static inline void +share_check_update_direct_if_need(struct share_check *sc, u64 offset) +{ + WARN_ON_ONCE(!sc || sc->mode != SC_FIND_SHARED_ROOT); + + if (!test_and_set_bit(DIRECT, &sc->found_state) || + offset < sc->direct_backref_lowest_bytenr) + sc->direct_backref_lowest_bytenr = offset; +} + +static inline void +share_check_update_indirect_if_need(struct share_check *sc, + u64 root, struct btrfs_key *key) +{ + WARN_ON_ONCE(!sc || sc->mode != SC_FIND_SHARED_ROOT); + + if (!test_and_set_bit(INDIRECT, &sc->found_state) || + root > sc->indirect_backref_highest_rootid || + (root == sc->indirect_backref_highest_rootid && + key->objectid < sc->indirect_backref_lowest_inum) || + (root == sc->indirect_backref_highest_rootid && + key->objectid == sc->indirect_backref_lowest_inum && + key->offset < sc->indirect_backref_lowest_offset)) { + sc->indirect_backref_highest_rootid = root; + sc->indirect_backref_lowest_inum = key->objectid; + sc->indirect_backref_lowest_offset = key->offset; + } +} + +/* + * Only called by find_parent_nodes_shared_root() + * , aka sc->mode == SC_FIND_SHARED_ROOT + */ +static inline bool backref_check_shared_not_in_sc(struct share_check *sc) +{ + WARN_ON_ONCE(!sc || sc->mode != SC_FIND_SHARED_ROOT); + + if (test_bit(DIRECT, &sc->found_state) && + sc->direct_backref_lowest_bytenr != sc->parent_bytenr) + return true; + else if (test_bit(INDIRECT, &sc->found_state) && + (sc->indirect_backref_highest_rootid != sc->root_objectid || + sc->indirect_backref_lowest_inum != sc->inum || + sc->indirect_backref_lowest_offset != sc->offset - + sc->datao)) + return true; + + return false; +} +#endif /* MY_ABC_HERE */ + static inline int extent_is_shared(struct share_check *sc) { +#ifdef MY_ABC_HERE + WARN_ON_ONCE(sc && sc->mode != SC_FIND_SHARED); +#endif /* MY_ABC_HERE */ return (sc && sc->share_count > 1) ? BACKREF_FOUND_SHARED : 0; } @@ -359,7 +503,13 @@ static int add_prelim_ref(const struct btrfs_fs_info *fs_info, ref->parent = parent; ref->wanted_disk_byte = wanted_disk_byte; prelim_ref_insert(fs_info, preftree, ref, sc); +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED) + return extent_is_shared(sc); + return 0; +#else /* MY_ABC_HERE */ return extent_is_shared(sc); +#endif /* MY_ABC_HERE */ } /* direct refs use root == 0, key == NULL */ @@ -416,7 +566,15 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, struct ulist *parents, struct preftrees *preftrees, struct prelim_ref *ref, int level, u64 time_seq, const u64 *extent_item_pos, - bool ignore_offset) + bool ignore_offset +#ifdef MY_ABC_HERE + , struct share_check *sc +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) + { int ret = 0; int slot; @@ -429,6 +587,10 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, u64 wanted_disk_byte = ref->wanted_disk_byte; u64 count = 0; u64 data_offset; +#ifdef MY_ABC_HERE + u64 datao; + u64 ram_bytes = SZ_256M; +#endif /* MY_ABC_HERE */ if (level != 0) { eb = path->nodes[level]; @@ -486,6 +648,12 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); data_offset = btrfs_file_extent_offset(eb, fi); +#ifdef MY_ABC_HERE + if (key_for_search->type == BTRFS_EXTENT_DATA_KEY && + key.offset >= key_for_search->offset + ram_bytes) + break; +#endif /* MY_ABC_HERE */ + if (disk_byte == wanted_disk_byte) { eie = NULL; old = NULL; @@ -493,6 +661,33 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, count++; else goto next; +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT && + ref->level == 0 && + ref->root_id == sc->root_objectid && + ref->key_for_search.objectid == sc->inum && + ref->key_for_search.offset == sc->offset - + sc->datao && key.offset < sc->offset) { + /* + * goto out, the return value will be set to + * 0, so return it directly, the caller can + * handle it. + */ + return BACKREF_NEXT_ITEM; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ram_bytes = btrfs_file_extent_ram_bytes(eb, fi); + if (qc) { + datao = key.offset - btrfs_file_extent_offset(eb, fi); + if (datao != key_for_search->offset) + goto next; + if (key.offset >= qc->offset) + break; + } +#endif /* MY_ABC_HERE */ + if (extent_item_pos) { ret = check_extent_in_eb(&key, eb, fi, *extent_item_pos, @@ -535,7 +730,14 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 time_seq, struct preftrees *preftrees, struct prelim_ref *ref, struct ulist *parents, - const u64 *extent_item_pos, bool ignore_offset) + const u64 *extent_item_pos, bool ignore_offset +#ifdef MY_ABC_HERE + , struct share_check *sc +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { struct btrfs_root *root; struct extent_buffer *eb; @@ -629,7 +831,14 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info, } ret = add_all_parents(root, path, parents, preftrees, ref, level, - time_seq, extent_item_pos, ignore_offset); + time_seq, extent_item_pos, ignore_offset +#ifdef MY_ABC_HERE + , sc +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); out: btrfs_put_root(root); out_free: @@ -666,7 +875,11 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 time_seq, struct preftrees *preftrees, const u64 *extent_item_pos, - struct share_check *sc, bool ignore_offset) + struct share_check *sc, bool ignore_offset +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { int err; int ret = 0; @@ -704,6 +917,9 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, } if (sc && sc->root_objectid && +#ifdef MY_ABC_HERE + sc->mode == SC_FIND_SHARED && +#endif /* MY_ABC_HERE */ ref->root_id != sc->root_objectid) { free_pref(ref); ret = BACKREF_FOUND_SHARED; @@ -711,7 +927,14 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, } err = resolve_indirect_ref(fs_info, path, time_seq, preftrees, ref, parents, extent_item_pos, - ignore_offset); + ignore_offset +#ifdef MY_ABC_HERE + , sc +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); /* * we can only tolerate ENOENT,otherwise,we should catch error * and return directly. @@ -814,7 +1037,11 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info, */ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head *head, u64 seq, - struct preftrees *preftrees, struct share_check *sc) + struct preftrees *preftrees, struct share_check *sc +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { struct btrfs_delayed_ref_node *node; struct btrfs_delayed_extent_op *extent_op = head->extent_op; @@ -880,15 +1107,43 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, key.type = BTRFS_EXTENT_DATA_KEY; key.offset = ref->offset; +#ifdef MY_ABC_HERE + if (qc) { + WARN_ON(!qc->ino || !qc->root_objectid); + if (key.objectid != qc->ino) + break; + if (key.offset < LLONG_MAX && key.offset >= qc->offset) + break; + + /* + * Only when we check if an inode has reference to extent_item, + * could we break now. Otherwise, we need to run into the + * leaf block. + */ + if (qc->offset == (u64)-1 && ref->root == qc->root_objectid) { + ret = BACKREF_FOUND_ROOT_INO; + break; + } + goto add_ref; + } +#endif /* MY_ABC_HERE */ + /* * Found a inum that doesn't match our known inum, we * know it's shared. */ - if (sc && sc->inum && ref->objectid != sc->inum) { + if (sc && sc->inum && ref->objectid != sc->inum +#ifdef MY_ABC_HERE + && sc->mode == SC_FIND_SHARED +#endif /* MY_ABC_HERE */ + ) { ret = BACKREF_FOUND_SHARED; goto out; } +#ifdef MY_ABC_HERE +add_ref: +#endif /* MY_ABC_HERE */ ret = add_indirect_ref(fs_info, preftrees, ref->root, &key, 0, node->bytenr, count, sc, GFP_ATOMIC); @@ -915,7 +1170,11 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, if (ret && (ret != BACKREF_FOUND_SHARED)) break; } - if (!ret) + if (!ret +#ifdef MY_ABC_HERE + && sc && sc->mode == SC_FIND_SHARED +#endif /* MY_ABC_HERE */ + ) ret = extent_is_shared(sc); out: spin_unlock(&head->lock); @@ -930,7 +1189,11 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, static int add_inline_refs(const struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, int *info_level, struct preftrees *preftrees, - struct share_check *sc) + struct share_check *sc +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { int ret = 0; int slot; @@ -996,6 +1259,10 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, struct btrfs_shared_data_ref *sdref; int count; +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT) + share_check_update_direct_if_need(sc, offset); +#endif /* MY_ABC_HERE */ sdref = (struct btrfs_shared_data_ref *)(iref + 1); count = btrfs_shared_data_ref_count(leaf, sdref); @@ -1004,6 +1271,13 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, break; } case BTRFS_TREE_BLOCK_REF_KEY: +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT && + !ulist_search(sc->shared_roots, offset)) { + ret = BACKREF_FOUND_SHARED_ROOT; + break; + } +#endif /* MY_ABC_HERE */ ret = add_indirect_ref(fs_info, preftrees, offset, NULL, *info_level + 1, bytenr, 1, NULL, GFP_NOFS); @@ -1020,13 +1294,47 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, key.type = BTRFS_EXTENT_DATA_KEY; key.offset = btrfs_extent_data_ref_offset(leaf, dref); - if (sc && sc->inum && key.objectid != sc->inum) { + if (sc && sc->inum && key.objectid != sc->inum +#ifdef MY_ABC_HERE + && sc->mode == SC_FIND_SHARED +#endif /* MY_ABC_HERE */ + ) { ret = BACKREF_FOUND_SHARED; break; } root = btrfs_extent_data_ref_root(leaf, dref); +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT) { + if (!ulist_search(sc->shared_roots, root)) { + ret = BACKREF_FOUND_SHARED_ROOT; + break; + } + share_check_update_indirect_if_need(sc, root, + &key); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (qc) { + WARN_ON(!qc->ino || !qc->root_objectid); + if (key.objectid != qc->ino) + break; + if (key.offset < LLONG_MAX && key.offset >= qc->offset) + break; + /* + * Only when we check if an inode has reference to extent_item, + * could we break now. Otherwise, we need to run into the + * leaf block. + */ + if (qc->offset == (u64)-1 && root == qc->root_objectid) { + ret = BACKREF_FOUND_ROOT_INO; + break; + } + } +#endif /* MY_ABC_HERE */ + ret = add_indirect_ref(fs_info, preftrees, root, &key, 0, bytenr, count, sc, GFP_NOFS); @@ -1051,7 +1359,11 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, static int add_keyed_refs(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, int info_level, struct preftrees *preftrees, - struct share_check *sc) + struct share_check *sc +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { struct btrfs_root *extent_root = fs_info->extent_root; int ret; @@ -1091,6 +1403,11 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, struct btrfs_shared_data_ref *sdref; int count; +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT) + share_check_update_direct_if_need(sc, + key.offset); +#endif /* MY_ABC_HERE */ sdref = btrfs_item_ptr(leaf, slot, struct btrfs_shared_data_ref); count = btrfs_shared_data_ref_count(leaf, sdref); @@ -1100,6 +1417,13 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, break; } case BTRFS_TREE_BLOCK_REF_KEY: +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT && + !ulist_search(sc->shared_roots, key.offset)) { + ret = BACKREF_FOUND_SHARED_ROOT; + break; + } +#endif /* MY_ABC_HERE */ /* NORMAL INDIRECT METADATA backref */ ret = add_indirect_ref(fs_info, preftrees, key.offset, NULL, info_level + 1, bytenr, @@ -1119,12 +1443,47 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, key.type = BTRFS_EXTENT_DATA_KEY; key.offset = btrfs_extent_data_ref_offset(leaf, dref); - if (sc && sc->inum && key.objectid != sc->inum) { + if (sc && sc->inum && key.objectid != sc->inum +#ifdef MY_ABC_HERE + && sc->mode == SC_FIND_SHARED +#endif /* MY_ABC_HERE */ + ) { ret = BACKREF_FOUND_SHARED; break; } root = btrfs_extent_data_ref_root(leaf, dref); + +#ifdef MY_ABC_HERE + if (sc && sc->mode == SC_FIND_SHARED_ROOT) { + if (!ulist_search(sc->shared_roots, root)) { + ret = BACKREF_FOUND_SHARED_ROOT; + break; + } + share_check_update_indirect_if_need(sc, root, + &key); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (qc) { + WARN_ON(!qc->ino || !qc->root_objectid); + if (key.objectid != qc->ino) + break; + if (key.offset < LLONG_MAX && key.offset >= qc->offset) + break; + /* + * Only when we check if an inode has reference to extent_item, + * could we break now. Otherwise, we need to run into the + * leaf block. + */ + if (qc->offset == (u64)-1 && root == qc->root_objectid) { + ret = BACKREF_FOUND_ROOT_INO; + break; + } + } +#endif /* MY_ABC_HERE */ + ret = add_indirect_ref(fs_info, preftrees, root, &key, 0, bytenr, count, sc, GFP_NOFS); @@ -1167,7 +1526,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 bytenr, u64 time_seq, struct ulist *refs, struct ulist *roots, const u64 *extent_item_pos, - struct share_check *sc, bool ignore_offset) + struct share_check *sc, bool ignore_offset +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { struct btrfs_key key; struct btrfs_path *path; @@ -1183,6 +1546,9 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, .indirect = PREFTREE_INIT, .indirect_missing_keys = PREFTREE_INIT }; +#ifdef MY_ABC_HERE + bool in_run_delayed = (qc)? qc->in_run_delayed : false; +#endif /* MY_ABC_HERE */ key.objectid = bytenr; key.offset = (u64)-1; @@ -1229,7 +1595,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, spin_lock(&delayed_refs->lock); head = btrfs_find_delayed_ref_head(delayed_refs, bytenr); if (head) { +#ifdef MY_ABC_HERE + if (!in_run_delayed && !mutex_trylock(&head->mutex)) { +#else if (!mutex_trylock(&head->mutex)) { +#endif /* MY_ABC_HERE */ refcount_inc(&head->refs); spin_unlock(&delayed_refs->lock); @@ -1246,8 +1616,15 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, } spin_unlock(&delayed_refs->lock); ret = add_delayed_refs(fs_info, head, time_seq, - &preftrees, sc); - mutex_unlock(&head->mutex); + &preftrees, sc +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (!in_run_delayed) +#endif /* MY_ABC_HERE */ + mutex_unlock(&head->mutex); if (ret) goto out; } else { @@ -1267,11 +1644,19 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, (key.type == BTRFS_EXTENT_ITEM_KEY || key.type == BTRFS_METADATA_ITEM_KEY)) { ret = add_inline_refs(fs_info, path, bytenr, - &info_level, &preftrees, sc); + &info_level, &preftrees, sc +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; ret = add_keyed_refs(fs_info, path, bytenr, info_level, - &preftrees, sc); + &preftrees, sc +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; } @@ -1286,7 +1671,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root.rb_root)); ret = resolve_indirect_refs(fs_info, path, time_seq, &preftrees, - extent_item_pos, sc, ignore_offset); + extent_item_pos, sc, ignore_offset +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; @@ -1314,7 +1703,21 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, * and would retain their original ref->count < 0. */ if (roots && ref->count && ref->root_id && ref->parent == 0) { +#ifdef MY_ABC_HERE + if (qc) { + WARN_ON(!qc->root_objectid); + if (ref->root_id == qc->root_objectid) { + ret = BACKREF_FOUND_ROOT_INO; + goto out; + } + goto shortcut; + } +#endif /* MY_ABC_HERE */ + if (sc && sc->root_objectid && +#ifdef MY_ABC_HERE + sc->mode == SC_FIND_SHARED && +#endif /* MY_ABC_HERE */ ref->root_id != sc->root_objectid) { ret = BACKREF_FOUND_SHARED; goto out; @@ -1325,6 +1728,10 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, if (ret < 0) goto out; } +#ifdef MY_ABC_HERE +shortcut: +#endif /* MY_ABC_HERE */ + if (ref->count && ref->parent) { if (extent_item_pos && !ref->inode_list && ref->level == 0) { @@ -1354,6 +1761,33 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, goto out; ref->inode_list = eie; } +#ifdef MY_ABC_HERE + if (qc && ref->level == 0 && ref->key_for_search.type == 0) { + struct extent_buffer *eb; + eb = read_tree_block(fs_info, ref->parent, 0, + ref->level, NULL); + if (IS_ERR(eb)) { + ret = PTR_ERR(eb); + goto out; + } else if (!extent_buffer_uptodate(eb)) { + free_extent_buffer(eb); + ret = -EIO; + goto out; + } + + if (!path->skip_locking) { + btrfs_tree_read_lock(eb); + btrfs_set_lock_blocking_read(eb); + } + ret = find_ino_extent_in_eb(eb, bytenr, qc->ino, qc->offset); + + if (!path->skip_locking) + btrfs_tree_read_unlock_blocking(eb); + free_extent_buffer(eb); + if (!ret) + goto next; + } +#endif /* MY_ABC_HERE */ ret = ulist_add_merge_ptr(refs, ref->parent, ref->inode_list, (void **)&eie, GFP_NOFS); @@ -1371,6 +1805,9 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, } eie = NULL; } +#ifdef MY_ABC_HERE +next: +#endif /* MY_ABC_HERE */ cond_resched(); } @@ -1386,6 +1823,255 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +static int check_first_ref(struct extent_buffer *eb, u64 bytenr, + u64 inum, u64 file_offset) +{ + u64 disk_byte; + struct btrfs_key key; + struct btrfs_file_extent_item *fi; + int slot; + int nritems; + int extent_type; + + /* + * from the shared data ref, we only have the leaf but we need + * the key. thus, we must look into all items and see that we + * find one (some) with a reference to our extent item. + */ + nritems = btrfs_header_nritems(eb); + for (slot = 0; slot < nritems; ++slot) { + btrfs_item_key_to_cpu(eb, &key, slot); + if (key.type != BTRFS_EXTENT_DATA_KEY) + continue; + fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(eb, fi); + if (extent_type == BTRFS_FILE_EXTENT_INLINE) + continue; + /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */ + disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); + if (disk_byte != bytenr) + continue; + + if (key.objectid < inum || + (key.objectid == inum && key.offset < file_offset)) + return 0; + } + + return 1; +} + +/* + * Copy from find_parent_nodes + */ +static int find_parent_nodes_shared_root(struct btrfs_fs_info *fs_info, + u64 root_objectid, u64 inum, + u64 offset, u64 datao, u64 bytenr, + struct ulist *roots, + u64 parent_bytenr, u64 *counted_root, + struct ulist *refs) +{ + struct btrfs_key key; + struct btrfs_path *path; + int info_level = 0; + int ret; + struct prelim_ref *ref; + struct rb_node *node; + struct preftrees preftrees = { + .direct = PREFTREE_INIT, + .indirect = PREFTREE_INIT, + .indirect_missing_keys = PREFTREE_INIT + }; + /* + * We record the following record: + * 1. smallest full backref bytenr (direct backref) + * 2. smallest offset of smallest inode number in largest root + * (indirect backref) + * + * If both records are available, we use smallest full backref bytenr. + * This is used to make sure we only account EXTENT once. + * We only take this extent into account if this path contains the + * record. + * + * The reason why we use largest rootid but smallest inode number + * and offset is we want to use cumulative accounting. Therefore, + * larget root id is needed. Using smallest offset is + * to make resolve indirect reference work faster. In resolving + * indirect ref, we always start from smaller offset of inode number. + * If the behavior of root id changes(e.g. from largest to smallest), + * make sure to change the function snap_entry_insert in ctree.c + */ + struct share_check sc = { + .mode = SC_FIND_SHARED_ROOT, + .root_objectid = root_objectid, + .inum = inum, + .shared_roots = roots, + .parent_bytenr = parent_bytenr, + .offset = offset, + .datao = datao, + .share_count = 0, + .found_state = 0, + }; + + key.objectid = bytenr; + key.offset = (u64)-1; + if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) + key.type = BTRFS_METADATA_ITEM_KEY; + else + key.type = BTRFS_EXTENT_ITEM_KEY; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + path->search_commit_root = 1; + path->skip_locking = 1; + + ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); + if (ret < 0) + goto out; + BUG_ON(ret == 0); + + if (path->slots[0]) { + struct extent_buffer *leaf; + int slot; + + path->slots[0]--; + leaf = path->nodes[0]; + slot = path->slots[0]; + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid == bytenr && + (key.type == BTRFS_EXTENT_ITEM_KEY || + key.type == BTRFS_METADATA_ITEM_KEY)) { + ret = add_inline_refs(fs_info, path, bytenr, + &info_level, &preftrees, &sc +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); + if (ret) + goto out; + ret = add_keyed_refs(fs_info, path, bytenr, + info_level, &preftrees, &sc +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); + if (ret) + goto out; + if (key.type == BTRFS_EXTENT_ITEM_KEY && + sc.mode == SC_FIND_SHARED_ROOT && + backref_check_shared_not_in_sc(&sc)) { + ret = BACKREF_NEXT_ITEM; + goto out; + } + } + } + btrfs_release_path(path); + + ret = add_missing_keys(fs_info, &preftrees, path->skip_locking == 0); + if (ret) + goto out; + WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root.rb_root)); + + ret = resolve_indirect_refs(fs_info, path, 0, &preftrees, NULL, &sc, + false +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); + if (ret) + goto out; + WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect.root.rb_root)); + + /* + * This walks the tree of merged and resolved refs. Tree blocks are + * read in as needed. Unique entries are added to the ulist, and + * the list of found roots is updated. + * + * We release the entire tree in one go before returning. + */ + node = rb_first_cached(&preftrees.direct.root); + while (node) { + ref = rb_entry(node, struct prelim_ref, rbnode); + node = rb_next(&ref->rbnode); + + if (roots && ref->count && ref->root_id && ref->parent == 0) { + if (!ulist_search(roots, ref->root_id)) { + ret = BACKREF_FOUND_SHARED_ROOT; + goto out; + } + if (counted_root && ref->root_id > *counted_root) + *counted_root = ref->root_id; + } + if (ref->count && ref->parent) { + if (ref->level == 0 && + ref->key_for_search.type == 0 && + ref->parent == parent_bytenr) { + /* + * The reason to add parent_bytenr == + * ref->parent condition here: + * If the parent bytenr is the smallest bytenr + * among all the full backrefs, and this leaf + * contains four EXTENT_DATA pointing to this + * EXTENT_ITEM. We will go into this check + * shared four times, so only check this + * EXTENT_ITEM for the first time pointing to + * the EXTENT_ITEM in this leaf. Otherwise + * we'll account four times here. + */ + struct extent_buffer *eb; + + eb = read_tree_block(fs_info, ref->parent, 0, + ref->level, NULL); + if (IS_ERR(eb)) { + ret = PTR_ERR(eb); + goto out; + } else if (!extent_buffer_uptodate(eb)) { + free_extent_buffer(eb); + ret = -EIO; + goto out; + } + btrfs_tree_read_lock(eb); + btrfs_set_lock_blocking_read(eb); + ret = check_first_ref(eb, bytenr, inum, + offset); + btrfs_tree_read_unlock_blocking(eb); + free_extent_buffer(eb); + if (!ret) { + ret = BACKREF_NEXT_ITEM; + goto out; + } + } + /* + * When dealing with an EXTENT_ITEM, we only account + * data that is referenced from the lowest block + * bytenr(or smallest offset of smallest inode in the + * largest root id if there's no full backref) to + * avoid counting one extent more than once. + * Therefore, we need to go through check_first_ref + * for every EXTENT_DATA. After passing that, we can + * safely check parent bytenr to skip checking backref + * on parent, which we know is not shared. + */ + if (!parent_bytenr || ref->parent != parent_bytenr) { + ret = ulist_add(refs, ref->parent, 0, + GFP_NOFS); + if (ret < 0) + goto out; + } + } + cond_resched(); + } + +out: + btrfs_free_path(path); + prelim_release(&preftrees.direct); + prelim_release(&preftrees.indirect); + prelim_release(&preftrees.indirect_missing_keys); + return ret; +} +#endif /* MY_ABC_HERE */ + static void free_leaf_list(struct ulist *blocks) { struct ulist_node *node = NULL; @@ -1424,7 +2110,11 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, return -ENOMEM; ret = find_parent_nodes(trans, fs_info, bytenr, time_seq, - *leafs, NULL, extent_item_pos, NULL, ignore_offset); + *leafs, NULL, extent_item_pos, NULL, ignore_offset +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret < 0 && ret != -ENOENT) { free_leaf_list(*leafs); return ret; @@ -1449,7 +2139,11 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 bytenr, u64 time_seq, struct ulist **roots, - bool ignore_offset) + bool ignore_offset +#ifdef MY_ABC_HERE + , struct quota_check *qc +#endif /* MY_ABC_HERE */ + ) { struct ulist *tmp; struct ulist_node *node = NULL; @@ -1468,7 +2162,20 @@ static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans, ULIST_ITER_INIT(&uiter); while (1) { ret = find_parent_nodes(trans, fs_info, bytenr, time_seq, - tmp, *roots, NULL, NULL, ignore_offset); + tmp, *roots, NULL, NULL, ignore_offset +#ifdef MY_ABC_HERE + , qc +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (qc && ret == BACKREF_FOUND_ROOT_INO) { + ulist_free(tmp); + ulist_free(*roots); + *roots = NULL; + return ret; + } +#endif /* MY_ABC_HERE */ + if (ret < 0 && ret != -ENOENT) { ulist_free(tmp); ulist_free(*roots); @@ -1496,12 +2203,78 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, if (!trans) down_read(&fs_info->commit_root_sem); ret = btrfs_find_all_roots_safe(trans, fs_info, bytenr, - time_seq, roots, ignore_offset); + time_seq, roots, ignore_offset +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (!trans) up_read(&fs_info->commit_root_sem); return ret; } +#ifdef MY_ABC_HERE +static int btrfs_find_root_inode(struct btrfs_trans_handle *trans, + u64 time_seq, struct quota_check *qc) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct ulist *leafs = NULL; + struct ulist *roots = NULL; + struct ulist_node *ref_node = NULL; + struct ulist_iterator ref_uiter; + int ret; + + leafs = ulist_alloc(GFP_NOFS); + if (!leafs) + return -ENOMEM; + + ret = find_parent_nodes(trans, fs_info, qc->bytenr, time_seq, + leafs, NULL, NULL, + NULL, true, qc); + if (ret) + goto out; + + ULIST_ITER_INIT(&ref_uiter); + while (!ret && (ref_node = ulist_next(leafs, &ref_uiter))) { + ret = btrfs_find_all_roots_safe(trans, fs_info, ref_node->val, + time_seq, &roots, true, qc); + if (ret >= 0) { + ulist_free(roots); + roots = NULL; + } + } +out: + if (ret > 0 && ret != BACKREF_FOUND_ROOT_INO) { + /* + * find_parent_nodes might set ret to 1, it's not what + * we want. + */ + WARN_ON(ret == BACKREF_FOUND_SHARED); + ret = 0; + } + ulist_free(leafs); + return ret; +} + +int check_root_inode_ref(struct btrfs_trans_handle *trans, + struct quota_check *qc) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); + int ret; + + btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); + ret = btrfs_find_root_inode(trans, tree_mod_seq_elem.seq, qc); + btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); + + if (ret > 0) { + ret = 1; + } + + return ret; +} +#endif /* MY_ABC_HERE */ + /** * btrfs_check_shared - tell us whether an extent is shared * @@ -1526,6 +2299,9 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr, struct seq_list elem = SEQ_LIST_INIT(elem); int ret = 0; struct share_check shared = { +#ifdef MY_ABC_HERE + .mode = SC_FIND_SHARED, +#endif /* MY_ABC_HERE */ .root_objectid = root->root_key.objectid, .inum = inum, .share_count = 0, @@ -1549,7 +2325,11 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr, ULIST_ITER_INIT(&uiter); while (1) { ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp, - roots, NULL, &shared, false); + roots, NULL, &shared, false +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret == BACKREF_FOUND_SHARED) { /* this is the only condition under which we return 1 */ ret = 1; @@ -1578,6 +2358,72 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr, return ret; } +#ifdef MY_ABC_HERE +static int __btrfs_check_shared_inlist(struct btrfs_fs_info *fs_info, + u64 root_objectid, u64 inum, + u64 file_offset, u64 datao, u64 bytenr, + struct ulist *shared_roots, + u64 parent_bytenr, u64 *owner_id) +{ + struct ulist *tmp; + struct ulist_node *node = NULL; + struct ulist_iterator uiter; + int ret = 0; + + tmp = ulist_alloc(GFP_NOFS); + if (!tmp) + return -ENOMEM; + + ULIST_ITER_INIT(&uiter); + while (1) { + ret = find_parent_nodes_shared_root(fs_info, root_objectid, + inum, file_offset, datao, + bytenr, shared_roots, + parent_bytenr, owner_id, + tmp); + if (ret == BACKREF_NEXT_ITEM || + ret == BACKREF_FOUND_SHARED_ROOT) { + ulist_free(tmp); + return ret; + } + if (ret < 0 && ret != -ENOENT) { + ulist_free(tmp); + return ret; + } + + node = ulist_next(tmp, &uiter); + if (!node) + break; + bytenr = node->val; + cond_resched(); + } + + ulist_free(tmp); + return 0; +} + +int btrfs_check_shared_inlist(struct btrfs_fs_info *fs_info, + u64 root_objectid, u64 inum, u64 file_offset, + u64 datao, u64 bytenr, + struct ulist *shared_roots, u64 parent_bytenr, + u64 *owner_id) +{ + int ret; + + down_read(&fs_info->commit_root_sem); + ret = __btrfs_check_shared_inlist(fs_info, root_objectid, inum, + file_offset, datao, bytenr, + shared_roots, parent_bytenr, + owner_id); + up_read(&fs_info->commit_root_sem); + + WARN_ON(ret > 0 && ret != BACKREF_NEXT_ITEM && + ret != BACKREF_FOUND_SHARED_ROOT); + + return ret; +} +#endif /* MY_ABC_HERE */ + int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, u64 start_off, struct btrfs_path *path, struct btrfs_inode_extref **ret_extref, @@ -1925,7 +2771,11 @@ static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, "ref for %llu resolved, key (%llu EXTEND_DATA %llu), root %llu", extent_item_objectid, eie->inum, eie->offset, root); - ret = iterate(eie->inum, eie->offset, root, ctx); + ret = iterate(eie->inum, eie->offset, root, ctx +#ifdef MY_ABC_HERE + , eie->extent_type +#endif /* MY_ABC_HERE */ + ); if (ret) { btrfs_debug(fs_info, "stopping iteration for %llu due to ret=%d", @@ -1986,7 +2836,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { ret = btrfs_find_all_roots_safe(trans, fs_info, ref_node->val, tree_mod_seq_elem.seq, &roots, - ignore_offset); + ignore_offset +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret) break; ULIST_ITER_INIT(&root_uiter); diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h index 17abde7f794c..1ba8fc893a57 100644 --- a/fs/btrfs/backref.h +++ b/fs/btrfs/backref.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2011 STRATO. All rights reserved. @@ -17,8 +20,33 @@ struct inode_fs_paths { struct btrfs_data_container *fspath; }; +#ifdef MY_ABC_HERE +/* + * This mode will check whether EXTENT_ITEM is referenced prior to + * an offset in an inode of a desiganted subvolume. + * If offset is provided with (u64)-1, all the file is checked. + * This mode is currently used by quota accounting for + * 1. clone range + * 2. remove extents + * 3. usrquota chown. + * The offset of file should be passed to check_root_inode_ref for usrquota + * chown or (u64)-1 for the other two cases. + */ +struct quota_check { + u64 bytenr; + u64 root_objectid; + u64 ino; + u64 offset; + bool in_run_delayed; +}; +#endif /* MY_ABC_HERE */ + typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root, - void *ctx); + void *ctx +#ifdef MY_ABC_HERE + , int extent_type +#endif /* MY_ABC_HERE */ + ); int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, struct btrfs_path *path, struct btrfs_key *found_key, @@ -48,6 +76,9 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, int btrfs_find_all_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 bytenr, u64 time_seq, struct ulist **roots, bool ignore_offset); +#ifdef MY_ABC_HERE +int check_root_inode_ref(struct btrfs_trans_handle *trans, struct quota_check *qc); +#endif /* MY_ABC_HERE */ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, u32 name_len, unsigned long name_off, struct extent_buffer *eb_in, u64 parent, @@ -64,6 +95,13 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, u64 *found_off); int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr, struct ulist *roots, struct ulist *tmp_ulist); +#ifdef MY_ABC_HERE +int btrfs_check_shared_inlist(struct btrfs_fs_info *fs_info, + u64 root_objectid, u64 inum, u64 file_offset, + u64 datao, u64 bytenr, + struct ulist *shared_roots, u64 parent_bytenr, + u64 *owner_id); +#endif /* MY_ABC_HERE */ int __init btrfs_prelim_ref_init(void); void __cold btrfs_prelim_ref_exit(void); diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index c99e293b50f5..4501391ac28a 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include "misc.h" @@ -142,6 +145,15 @@ void btrfs_put_block_group(struct btrfs_block_group *cache) * No better way to resolve, but only to warn. */ WARN_ON(!RB_EMPTY_ROOT(&cache->full_stripe_locks_root.root)); +#ifdef MY_ABC_HERE + atomic64_dec(&cache->fs_info->block_group_cnt); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + WARN_ON_ONCE(!RB_EMPTY_NODE(&cache->syno_allocator.bytes_index)); + WARN_ON_ONCE(!RB_EMPTY_NODE(&cache->syno_allocator.max_length_index)); + WARN_ON_ONCE(!RB_EMPTY_NODE(&cache->syno_allocator.max_length_with_extent_index)); + WARN_ON_ONCE(!RB_EMPTY_NODE(&cache->syno_allocator.preload_index)); +#endif /* MY_ABC_HERE */ kfree(cache->free_space_ctl); kfree(cache); } @@ -408,18 +420,22 @@ void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache, btrfs_put_caching_control(caching_ctl); } -int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache) +static int btrfs_caching_ctl_wait_done(struct btrfs_block_group *cache, + struct btrfs_caching_control *caching_ctl) +{ + wait_event(caching_ctl->wait, btrfs_block_group_done(cache)); + return cache->cached == BTRFS_CACHE_ERROR ? -EIO : 0; +} + +static int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache) { struct btrfs_caching_control *caching_ctl; - int ret = 0; + int ret; caching_ctl = btrfs_get_caching_control(cache); if (!caching_ctl) return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0; - - wait_event(caching_ctl->wait, btrfs_block_group_done(cache)); - if (cache->cached == BTRFS_CACHE_ERROR) - ret = -EIO; + ret = btrfs_caching_ctl_wait_done(cache, caching_ctl); btrfs_put_caching_control(caching_ctl); return ret; } @@ -556,8 +572,6 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) if (need_resched() || rwsem_is_contended(&fs_info->commit_root_sem)) { - if (wakeup) - caching_ctl->progress = last; btrfs_release_path(path); up_read(&fs_info->commit_root_sem); mutex_unlock(&caching_ctl->mutex); @@ -581,9 +595,6 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) key.objectid = last; key.offset = 0; key.type = BTRFS_EXTENT_ITEM_KEY; - - if (wakeup) - caching_ctl->progress = last; btrfs_release_path(path); goto next; } @@ -618,7 +629,6 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) total_found += add_new_free_space(block_group, last, block_group->start + block_group->length); - caching_ctl->progress = (u64)-1; out: btrfs_free_path(path); @@ -631,6 +641,9 @@ static noinline void caching_thread(struct btrfs_work *work) struct btrfs_fs_info *fs_info; struct btrfs_caching_control *caching_ctl; int ret; +#ifdef MY_ABC_HERE + struct btrfs_space_info *sinfo; +#endif /* MY_ABC_HERE */ caching_ctl = container_of(work, struct btrfs_caching_control, work); block_group = caching_ctl->block_group; @@ -639,6 +652,23 @@ static noinline void caching_thread(struct btrfs_work *work) mutex_lock(&caching_ctl->mutex); down_read(&fs_info->commit_root_sem); + if (btrfs_test_opt(fs_info, SPACE_CACHE)) { + ret = load_free_space_cache(block_group); + if (ret == 1) { + ret = 0; + goto done; + } + + /* + * We failed to load the space cache, set ourselves to + * CACHE_STARTED and carry on. + */ + spin_lock(&block_group->lock); + block_group->cached = BTRFS_CACHE_STARTED; + spin_unlock(&block_group->lock); + wake_up(&caching_ctl->wait); + } + /* * If we are in the transaction that populated the free space tree we * can't actually cache from the free space tree as our commit root and @@ -651,12 +681,28 @@ static noinline void caching_thread(struct btrfs_work *work) ret = load_free_space_tree(caching_ctl); else ret = load_extent_tree_free(caching_ctl); - +done: spin_lock(&block_group->lock); block_group->caching_ctl = NULL; block_group->cached = ret ? BTRFS_CACHE_ERROR : BTRFS_CACHE_FINISHED; spin_unlock(&block_group->lock); +#ifdef MY_ABC_HERE + sinfo = block_group->syno_allocator.space_info; + spin_lock(&sinfo->syno_allocator.lock); + if (!RB_EMPTY_NODE(&block_group->syno_allocator.preload_index)) { + rb_erase_cached(&block_group->syno_allocator.preload_index, &sinfo->syno_allocator.preload); + RB_CLEAR_NODE(&block_group->syno_allocator.preload_index); + } + spin_unlock(&sinfo->syno_allocator.lock); + /* + * If an error occurs, we should relink block_group to the + * corresponding position. + */ + if (ret) + btrfs_syno_allocator_relink_block_group(block_group); +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_BTRFS_DEBUG if (btrfs_should_fragment_free_space(block_group)) { u64 bytes_used; @@ -671,8 +717,6 @@ static noinline void caching_thread(struct btrfs_work *work) } #endif - caching_ctl->progress = (u64)-1; - up_read(&fs_info->commit_root_sem); btrfs_free_excluded_extents(block_group); mutex_unlock(&caching_ctl->mutex); @@ -683,11 +727,10 @@ static noinline void caching_thread(struct btrfs_work *work) btrfs_put_block_group(block_group); } -int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only) +int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait) { - DEFINE_WAIT(wait); struct btrfs_fs_info *fs_info = cache->fs_info; - struct btrfs_caching_control *caching_ctl; + struct btrfs_caching_control *caching_ctl = NULL; int ret = 0; caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS); @@ -698,120 +741,45 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, int load_cache_only mutex_init(&caching_ctl->mutex); init_waitqueue_head(&caching_ctl->wait); caching_ctl->block_group = cache; - caching_ctl->progress = cache->start; - refcount_set(&caching_ctl->count, 1); + refcount_set(&caching_ctl->count, 2); btrfs_init_work(&caching_ctl->work, caching_thread, NULL, NULL); spin_lock(&cache->lock); - /* - * This should be a rare occasion, but this could happen I think in the - * case where one thread starts to load the space cache info, and then - * some other thread starts a transaction commit which tries to do an - * allocation while the other thread is still loading the space cache - * info. The previous loop should have kept us from choosing this block - * group, but if we've moved to the state where we will wait on caching - * block groups we need to first check if we're doing a fast load here, - * so we can wait for it to finish, otherwise we could end up allocating - * from a block group who's cache gets evicted for one reason or - * another. - */ - while (cache->cached == BTRFS_CACHE_FAST) { - struct btrfs_caching_control *ctl; - - ctl = cache->caching_ctl; - refcount_inc(&ctl->count); - prepare_to_wait(&ctl->wait, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&cache->lock); - - schedule(); - - finish_wait(&ctl->wait, &wait); - btrfs_put_caching_control(ctl); - spin_lock(&cache->lock); - } - if (cache->cached != BTRFS_CACHE_NO) { - spin_unlock(&cache->lock); kfree(caching_ctl); - return 0; + + caching_ctl = cache->caching_ctl; + if (caching_ctl) + refcount_inc(&caching_ctl->count); + spin_unlock(&cache->lock); + goto out; } WARN_ON(cache->caching_ctl); cache->caching_ctl = caching_ctl; - cache->cached = BTRFS_CACHE_FAST; + cache->cached = BTRFS_CACHE_STARTED; + cache->has_caching_ctl = 1; spin_unlock(&cache->lock); - if (btrfs_test_opt(fs_info, SPACE_CACHE)) { - mutex_lock(&caching_ctl->mutex); - ret = load_free_space_cache(cache); - - spin_lock(&cache->lock); - if (ret == 1) { - cache->caching_ctl = NULL; - cache->cached = BTRFS_CACHE_FINISHED; - cache->last_byte_to_unpin = (u64)-1; - caching_ctl->progress = (u64)-1; - } else { - if (load_cache_only) { - cache->caching_ctl = NULL; - cache->cached = BTRFS_CACHE_NO; - } else { - cache->cached = BTRFS_CACHE_STARTED; - cache->has_caching_ctl = 1; - } - } - spin_unlock(&cache->lock); -#ifdef CONFIG_BTRFS_DEBUG - if (ret == 1 && - btrfs_should_fragment_free_space(cache)) { - u64 bytes_used; - - spin_lock(&cache->space_info->lock); - spin_lock(&cache->lock); - bytes_used = cache->length - cache->used; - cache->space_info->bytes_used += bytes_used >> 1; - spin_unlock(&cache->lock); - spin_unlock(&cache->space_info->lock); - fragment_free_space(cache); - } -#endif - mutex_unlock(&caching_ctl->mutex); - - wake_up(&caching_ctl->wait); - if (ret == 1) { - btrfs_put_caching_control(caching_ctl); - btrfs_free_excluded_extents(cache); - return 0; - } - } else { - /* - * We're either using the free space tree or no caching at all. - * Set cached to the appropriate value and wakeup any waiters. - */ - spin_lock(&cache->lock); - if (load_cache_only) { - cache->caching_ctl = NULL; - cache->cached = BTRFS_CACHE_NO; - } else { - cache->cached = BTRFS_CACHE_STARTED; - cache->has_caching_ctl = 1; - } - spin_unlock(&cache->lock); - wake_up(&caching_ctl->wait); - } - - if (load_cache_only) { - btrfs_put_caching_control(caching_ctl); - return 0; - } - - down_write(&fs_info->commit_root_sem); + spin_lock(&fs_info->block_group_cache_lock); refcount_inc(&caching_ctl->count); list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups); - up_write(&fs_info->commit_root_sem); + spin_unlock(&fs_info->block_group_cache_lock); btrfs_get_block_group(cache); +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, SYNO_ALLOCATOR)) + btrfs_queue_work(fs_info->syno_allocator.caching_workers, &caching_ctl->work); + else + btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work); +#else /* MY_ABC_HERE */ btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work); +#endif /* MY_ABC_HERE */ +out: + if (wait && caching_ctl) + ret = btrfs_caching_ctl_wait_done(cache, caching_ctl); + if (caching_ctl) + btrfs_put_caching_control(caching_ctl); return ret; } @@ -877,12 +845,44 @@ static int remove_block_group_item(struct btrfs_trans_handle *trans, struct btrfs_root *root; struct btrfs_key key; int ret; +#ifdef MY_ABC_HERE + int err; +#endif /* MY_ABC_HERE */ root = fs_info->extent_root; key.objectid = block_group->start; key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; key.offset = block_group->length; +#ifdef MY_ABC_HERE + if (fs_info->block_group_hint_root) { + err = btrfs_search_slot(trans, fs_info->block_group_hint_root, &key, path, -1, 1); + if (!err) + btrfs_del_item(trans, fs_info->block_group_hint_root, path); + btrfs_release_path(path); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_syno_block_group_cache_tree_enabled(fs_info)) { + ret = btrfs_search_slot(trans, fs_info->block_group_cache_root, &key, path, -1, 1); + if (ret > 0) + ret = -ENOENT; + if (ret < 0) { + btrfs_err(fs_info, "Failed to search block group item %llu-%llu from cache tree, err = %d", + key.objectid, key.offset, ret); + return ret; + } + ret = btrfs_del_item(trans, fs_info->block_group_cache_root, path); + if (ret) { + btrfs_err(fs_info, "Failed to remove block group item %llu-%llu from cache tree, err = %d", + key.objectid, key.offset, ret); + return ret; + } + btrfs_release_path(path); + } +#endif /* MY_ABC_HERE */ + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) ret = -ENOENT; @@ -900,8 +900,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_path *path; struct btrfs_block_group *block_group; struct btrfs_free_cluster *cluster; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_key key; struct inode *inode; struct kobject *kobj = NULL; int ret; @@ -910,12 +908,20 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_caching_control *caching_ctl = NULL; bool remove_em; bool remove_rsv = false; +#ifdef MY_ABC_HERE + bool has_metadata_group = false; +#endif /* MY_ABC_HERE */ block_group = btrfs_lookup_block_group(fs_info, group_start); BUG_ON(!block_group); BUG_ON(!block_group->ro); trace_btrfs_remove_block_group(block_group); + +#ifdef MY_ABC_HERE + if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) + has_metadata_group = true; +#endif /* MY_ABC_HERE */ /* * Free the reserved super bytes from this block group before * remove it. @@ -942,6 +948,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, btrfs_return_cluster_to_free_space(block_group, cluster); spin_unlock(&cluster->refill_lock); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_release_cache_block_group(block_group); + btrfs_syno_allocator_remove_block_group(block_group); +#endif /* MY_ABC_HERE */ + path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; @@ -979,42 +990,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, spin_unlock(&trans->transaction->dirty_bgs_lock); mutex_unlock(&trans->transaction->cache_write_mutex); - if (!IS_ERR(inode)) { - ret = btrfs_orphan_add(trans, BTRFS_I(inode)); - if (ret) { - btrfs_add_delayed_iput(inode); - goto out; - } - clear_nlink(inode); - /* One for the block groups ref */ - spin_lock(&block_group->lock); - if (block_group->iref) { - block_group->iref = 0; - block_group->inode = NULL; - spin_unlock(&block_group->lock); - iput(inode); - } else { - spin_unlock(&block_group->lock); - } - /* One for our lookup ref */ - btrfs_add_delayed_iput(inode); - } - - key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.type = 0; - key.offset = block_group->start; - - ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); - if (ret < 0) + ret = btrfs_remove_free_space_inode(trans, inode, block_group); + if (ret) goto out; - if (ret > 0) - btrfs_release_path(path); - if (ret == 0) { - ret = btrfs_del_item(trans, tree_root, path); - if (ret) - goto out; - btrfs_release_path(path); - } spin_lock(&fs_info->block_group_cache_lock); rb_erase(&block_group->cache_node, @@ -1051,7 +1029,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, if (block_group->cached == BTRFS_CACHE_STARTED) btrfs_wait_block_group_cache_done(block_group); if (block_group->has_caching_ctl) { - down_write(&fs_info->commit_root_sem); + spin_lock(&fs_info->block_group_cache_lock); if (!caching_ctl) { struct btrfs_caching_control *ctl; @@ -1065,7 +1043,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, } if (caching_ctl) list_del_init(&caching_ctl->list); - up_write(&fs_info->commit_root_sem); + spin_unlock(&fs_info->block_group_cache_lock); if (caching_ctl) { /* Once for the caching bgs list and once for us. */ btrfs_put_caching_control(caching_ctl); @@ -1164,6 +1142,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, if (remove_rsv) btrfs_delayed_refs_rsv_release(fs_info, 1); btrfs_free_path(path); + +#ifdef MY_ABC_HERE + if (!ret && has_metadata_group && fs_info->metadata_cache_enable) + atomic_inc(&fs_info->syno_metadata_block_group_update_count); +#endif /* MY_ABC_HERE */ return ret; } @@ -1226,6 +1209,10 @@ static int inc_block_group_ro(struct btrfs_block_group *cache, int force) u64 num_bytes; int ret = -ENOSPC; +#ifdef MY_ABC_HERE + down_write(&sinfo->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ + spin_lock(&sinfo->lock); spin_lock(&cache->lock); @@ -1283,6 +1270,15 @@ static int inc_block_group_ro(struct btrfs_block_group *cache, int force) "unable to make block group %llu ro", cache->start); btrfs_dump_space_info(cache->fs_info, cache->space_info, 0, 0); } +#ifdef MY_ABC_HERE + /* + * If the block_group is successfully switched to ro, + * we should relink block_group to the corresponding position. + */ + if (!ret) + btrfs_syno_allocator_relink_block_group(cache); + up_write(&sinfo->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ return ret; } @@ -1368,6 +1364,14 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) mutex_lock(&fs_info->delete_unused_bgs_mutex); /* Don't want to race with allocators so take the groups_sem */ +#ifdef MY_ABC_HERE + /* + * Avoid race with syno_allocation. + * Because in syno_allocation, we may release groups_sem when + * do chunk allocation, but we are still using the block_group. + * So we add checking syno_allocator.refs to avoid the above race. + */ +#endif /* MY_ABC_HERE */ down_write(&space_info->groups_sem); /* @@ -1388,7 +1392,15 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) spin_lock(&block_group->lock); if (block_group->reserved || block_group->pinned || block_group->used || block_group->ro || - list_is_singular(&block_group->list)) { + list_is_singular(&block_group->list) +#ifdef MY_ABC_HERE + // Do not release reserve block. + || block_group->start == fs_info->log_tree_rsv_start +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + || atomic_read(&block_group->syno_allocator.refs) +#endif /* MY_ABC_HERE */ + ) { /* * We want to bail if we made new allocations or have * outstanding allocations in this block group. We do @@ -1524,10 +1536,115 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) btrfs_discard_punt_unused_bgs_list(fs_info); } +#ifdef MY_ABC_HERE +#define READA_BLOCK_GROUP_THREAD_MAX 10 +static void reada_root(struct btrfs_root *root) +{ + struct extent_buffer *node; + int level; + u64 search; + u32 nr = 0; + u32 nritems; + + node = btrfs_root_node(root); + level = btrfs_header_level(node); + if (level == 0) + goto out; + + nritems = btrfs_header_nritems(node); + while (nr < nritems) { + search = btrfs_node_blockptr(node, nr); + readahead_tree_block(root->fs_info, search); + nr++; + } + +out: + free_extent_buffer(node); +} + +struct btrfs_bg_reada_work { + struct btrfs_root *root; + struct btrfs_key key; + struct btrfs_work work; +}; + +static void btrfs_run_bg_reada_work(struct btrfs_work *work) +{ + struct btrfs_bg_reada_work *reada_work; + struct btrfs_path *path; + struct btrfs_fs_info *fs_info; + + reada_work = container_of(work, struct btrfs_bg_reada_work, work); + fs_info = reada_work->root->fs_info; + path = btrfs_alloc_path(); + if (!path) + goto out; + + btrfs_search_slot(NULL, reada_work->root, &reada_work->key, path, 0, 0); + btrfs_free_path(path); + +out: + kfree(reada_work); + atomic_dec(&fs_info->reada_block_group_threads); +} + +/* + * Iteratively use hint_path to search next block group item in hint tree to do readahead. + * It will release hint_path if no block group item with greater key in hint tree can be found, + * so caller knows he can stop doing readahead. But caller still need to free hint_path itself + * to avoid leaking. + */ +static void btrfs_reada_block_group_item(struct btrfs_fs_info *fs_info, struct btrfs_path *hint_path) +{ + struct btrfs_bg_reada_work *reada_work; + struct extent_buffer *leaf; + int slot; + int i; + + // We have search all block group items in hint tree. + if (!hint_path->nodes[0]) + return; + + for (i = 0; i < READA_BLOCK_GROUP_THREAD_MAX; i++) { + if (atomic_read(&fs_info->reada_block_group_threads) >= READA_BLOCK_GROUP_THREAD_MAX) + break; + + slot = hint_path->slots[0]; + leaf = hint_path->nodes[0]; + + reada_work = kmalloc(sizeof(*reada_work), GFP_NOFS); + if (!reada_work) + goto stop_readahead; + + reada_work->root = fs_info->extent_root; + btrfs_item_key_to_cpu(leaf, &reada_work->key, slot); + + btrfs_init_work(&reada_work->work, btrfs_run_bg_reada_work, NULL, NULL); + btrfs_queue_work(fs_info->bg_reada_workers, &reada_work->work); + atomic_inc(&fs_info->reada_block_group_threads); + + if (slot + 1 < btrfs_header_nritems(leaf)) + hint_path->slots[0]++; + else if (btrfs_next_leaf(fs_info->block_group_hint_root, hint_path)) + goto stop_readahead; + } + return; + +stop_readahead: + btrfs_release_path(hint_path); + return; +} +#endif /* MY_ABC_HERE */ + void btrfs_mark_bg_unused(struct btrfs_block_group *bg) { struct btrfs_fs_info *fs_info = bg->fs_info; +#ifdef MY_ABC_HERE + if (bg->start == fs_info->log_tree_rsv_start) + return; +#endif /* MY_ABC_HERE */ + spin_lock(&fs_info->unused_bgs_lock); if (list_empty(&bg->bg_list)) { btrfs_get_block_group(bg); @@ -1590,7 +1707,11 @@ static int read_bg_from_eb(struct btrfs_fs_info *fs_info, struct btrfs_key *key, static int find_first_block_group(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - struct btrfs_key *key) + struct btrfs_key *key +#ifdef MY_ABC_HERE + , struct btrfs_root *block_group_cache_root +#endif /* MY_ABC_HERE */ + ) { struct btrfs_root *root = fs_info->extent_root; int ret; @@ -1598,6 +1719,11 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf; int slot; +#ifdef MY_ABC_HERE + if (block_group_cache_root) + root = block_group_cache_root; +#endif /* MY_ABC_HERE */ + ret = btrfs_search_slot(NULL, root, key, path, 0, 0); if (ret < 0) return ret; @@ -1781,6 +1907,11 @@ static void link_block_group(struct btrfs_block_group *cache) down_write(&space_info->groups_sem); list_add_tail(&cache->list, &space_info->block_groups[index]); up_write(&space_info->groups_sem); +#ifdef MY_ABC_HERE + spin_lock(&cache->lock); + cache->syno_allocator.initialized = true; + spin_unlock(&cache->lock); +#endif /* MY_ABC_HERE */ } static struct btrfs_block_group *btrfs_create_block_group_cache( @@ -1802,6 +1933,9 @@ static struct btrfs_block_group *btrfs_create_block_group_cache( cache->start = start; cache->fs_info = fs_info; +#ifdef MY_ABC_HERE + atomic64_inc(&cache->fs_info->block_group_cnt); +#endif /* MY_ABC_HERE */ cache->full_stripe_len = btrfs_full_stripe_len(fs_info, start); cache->discard_index = BTRFS_DISCARD_INDEX_UNUSED; @@ -1816,10 +1950,26 @@ static struct btrfs_block_group *btrfs_create_block_group_cache( INIT_LIST_HEAD(&cache->discard_list); INIT_LIST_HEAD(&cache->dirty_list); INIT_LIST_HEAD(&cache->io_list); - btrfs_init_free_space_ctl(cache); + btrfs_init_free_space_ctl(cache, cache->free_space_ctl); atomic_set(&cache->frozen, 0); mutex_init(&cache->free_space_lock); btrfs_init_full_stripe_locks_tree(&cache->full_stripe_locks_root); +#ifdef MY_ABC_HERE + cache->syno_allocator.space_info = NULL; + RB_CLEAR_NODE(&cache->syno_allocator.bytes_index); + RB_CLEAR_NODE(&cache->syno_allocator.max_length_index); + RB_CLEAR_NODE(&cache->syno_allocator.max_length_with_extent_index); + RB_CLEAR_NODE(&cache->syno_allocator.preload_index); + cache->syno_allocator.last_bytes = 0; + cache->syno_allocator.last_max_length = 0; + cache->syno_allocator.last_max_length_with_extent = 0; + cache->syno_allocator.preload_free_space = 0; + cache->syno_allocator.ro = false; + cache->syno_allocator.cache_error = false; + cache->syno_allocator.removed = false; + cache->syno_allocator.initialized = false; + atomic_set(&cache->syno_allocator.refs, 0); +#endif /* MY_ABC_HERE */ return cache; } @@ -1937,6 +2087,17 @@ static int read_one_block_group(struct btrfs_fs_info *info, goto error; } +#ifdef MY_ABC_HERE + cache->syno_allocator.space_info = btrfs_find_space_info(info, cache->flags); + if (!cache->syno_allocator.space_info) { + btrfs_err(info, "No space info for %llu", cache->flags); + ret = -EINVAL; + goto error; + } + /* avoid null pointer when syno_allocation->btrfs_add_reserved_bytes */ + cache->space_info = cache->syno_allocator.space_info; +#endif /* MY_ABC_HERE */ + /* * We need to exclude the super stripes now so that the space info has * super bytes accounted for, otherwise we'll think we have more space @@ -1949,6 +2110,11 @@ static int read_one_block_group(struct btrfs_fs_info *info, goto error; } +#ifdef MY_ABC_HERE + btrfs_syno_allocator_preload_block_group(cache, cache->length - cache->used); + btrfs_syno_allocator_relink_block_group(cache); +#endif /* MY_ABC_HERE */ + /* * Check for two cases, either we are full, and therefore don't need * to bother with the caching work since we won't find any space, or we @@ -1956,11 +2122,9 @@ static int read_one_block_group(struct btrfs_fs_info *info, * This saves us _a_lot_ of time, particularly in the full case. */ if (cache->length == cache->used) { - cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; btrfs_free_excluded_extents(cache); } else if (cache->used == 0) { - cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; add_new_free_space(cache, cache->start, cache->start + cache->length); @@ -1981,6 +2145,12 @@ static int read_one_block_group(struct btrfs_fs_info *info, link_block_group(cache); set_avail_alloc_bits(info, cache->flags); + +#ifdef MY_ABC_HERE + if (cache->start == info->log_tree_rsv_start) + info->log_tree_rsv_size = cache->length; +#endif /* MY_ABC_HERE*/ + if (btrfs_chunk_readonly(info, cache->start)) { inc_block_group_ro(cache, 1); } else if (cache->used == 0) { @@ -2005,6 +2175,13 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) struct btrfs_key key; int need_clear = 0; u64 cache_gen; +#ifdef MY_ABC_HERE + struct btrfs_path *hint_path; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool use_cache_tree; + struct btrfs_root *block_group_cache_root = NULL; +#endif /* MY_ABC_HERE */ key.objectid = 0; key.offset = 0; @@ -2012,6 +2189,40 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) path = btrfs_alloc_path(); if (!path) return -ENOMEM; +#ifdef MY_ABC_HERE + hint_path = btrfs_alloc_path(); + if (!hint_path) { + ret = -ENOMEM; + goto error; + } + hint_path->reada = READA_FORWARD_ALWAYS; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + use_cache_tree = btrfs_syno_block_group_cache_tree_enabled(info); + if (use_cache_tree) { + block_group_cache_root = info->block_group_cache_root; + path->reada = READA_FORWARD_ALWAYS; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, BLOCK_GROUP_HINT_TREE) +#ifdef MY_ABC_HERE + && !use_cache_tree +#endif /* MY_ABC_HERE */ + ) { + info->bg_reada_workers = btrfs_alloc_workqueue(info, "bg-reada", WQ_FREEZABLE | WQ_UNBOUND, info->thread_pool_size, 2); + + reada_root(info->extent_root); + if (info->block_group_hint_root) { + reada_root(info->block_group_hint_root); + ret = btrfs_search_slot(NULL, info->block_group_hint_root, &key, hint_path, 0, 0); + if (ret < 0) + btrfs_release_path(hint_path); + } + } +#endif /* MY_ABC_HERE */ cache_gen = btrfs_super_cache_generation(info->super_copy); if (btrfs_test_opt(info, SPACE_CACHE) && @@ -2021,7 +2232,21 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) need_clear = 1; while (1) { - ret = find_first_block_group(info, path, &key); +#ifdef MY_ABC_HERE + if (info->block_group_hint_root && + info->bg_reada_workers +#ifdef MY_ABC_HERE + && !use_cache_tree +#endif /* MY_ABC_HERE */ + ) + btrfs_reada_block_group_item(info, hint_path); +#endif /* MY_ABC_HERE */ + + ret = find_first_block_group(info, path, &key +#ifdef MY_ABC_HERE + , block_group_cache_root +#endif /* MY_ABC_HERE */ + ); if (ret > 0) break; if (ret != 0) @@ -2072,6 +2297,11 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) btrfs_init_global_block_rsv(info); ret = check_chunk_block_group_mappings(info); error: +#ifdef MY_ABC_HERE + btrfs_destroy_workqueue(info->bg_reada_workers); + info->bg_reada_workers = NULL; + btrfs_free_path(hint_path); +#endif /* MY_ABC_HERE */ btrfs_free_path(path); return ret; } @@ -2083,6 +2313,12 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans, struct btrfs_block_group_item bgi; struct btrfs_root *root; struct btrfs_key key; +#ifdef MY_ABC_HERE + int err; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int ret; +#endif /* MY_ABC_HERE */ spin_lock(&block_group->lock); btrfs_set_stack_block_group_used(&bgi, block_group->used); @@ -2094,6 +2330,26 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans, key.offset = block_group->length; spin_unlock(&block_group->lock); +#ifdef MY_ABC_HERE + if (fs_info->block_group_hint_root) { + err = btrfs_insert_item(trans, fs_info->block_group_hint_root, &key, &bgi, sizeof(bgi)); + if (err) + btrfs_warn(fs_info, "Failed to insert block group item %llu-%llu into hint tree, err = %d", + key.objectid, key.offset, err); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_syno_block_group_cache_tree_enabled(fs_info)) { + ret = btrfs_insert_item(trans, fs_info->block_group_cache_root, &key, &bgi, sizeof(bgi)); + if (ret) { + btrfs_err(fs_info, "Failed to insert block group item %llu-%llu into cache tree, err = %d", + key.objectid, key.offset, ret); + return ret; + } + } +#endif /* MY_ABC_HERE */ + root = fs_info->extent_root; return btrfs_insert_item(trans, root, &key, &bgi, sizeof(bgi)); } @@ -2103,10 +2359,32 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans) struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_block_group *block_group; int ret = 0; +#ifdef MY_ABC_HERE + struct btrfs_root *block_group_hint_root; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool has_metadata_group = false; +#endif /* MY_ABC_HERE */ if (!trans->can_flush_pending_bgs) return; +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, BLOCK_GROUP_HINT_TREE) && !fs_info->block_group_hint_root) { + mutex_lock(&fs_info->block_group_hint_tree_mutex); + if (!fs_info->block_group_hint_root) { + block_group_hint_root = btrfs_create_tree(trans, BTRFS_BLOCK_GROUP_HINT_TREE_OBJECTID); + if (!IS_ERR(block_group_hint_root)) { + fs_info->block_group_hint_root = block_group_hint_root; + } else { + btrfs_clear_opt(fs_info->mount_opt, BLOCK_GROUP_HINT_TREE); + btrfs_warn(fs_info, "Failed to create block group hint tree"); + } + } + mutex_unlock(&fs_info->block_group_hint_tree_mutex); + } +#endif /* MY_ABC_HERE */ + while (!list_empty(&trans->new_bgs)) { int index; @@ -2118,6 +2396,11 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans) index = btrfs_bg_flags_to_raid_index(block_group->flags); +#ifdef MY_ABC_HERE + if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) + has_metadata_group = true; +#endif /* MY_ABC_HERE */ + ret = insert_block_group_item(trans, block_group); if (ret) btrfs_abort_transaction(trans, ret); @@ -2142,6 +2425,10 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans) list_del_init(&block_group->bg_list); } btrfs_trans_release_chunk_metadata(trans); +#ifdef MY_ABC_HERE + if (!ret && has_metadata_group && fs_info->metadata_cache_enable) + atomic_inc(&fs_info->syno_metadata_block_group_update_count); +#endif /* MY_ABC_HERE */ } int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used, @@ -2161,9 +2448,21 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used, set_free_space_tree_thresholds(cache); cache->used = bytes_used; cache->flags = type; - cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; - cache->needs_free_space = 1; + if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) + cache->needs_free_space = 1; + +#ifdef MY_ABC_HERE + cache->syno_allocator.space_info = btrfs_find_space_info(fs_info, cache->flags); + if (!cache->syno_allocator.space_info) { + btrfs_err(fs_info, "No space info for %llu", cache->flags); + btrfs_put_block_group(cache); + return -EINVAL; + } + /* avoid null pointer when syno_allocation->btrfs_add_reserved_bytes */ + cache->space_info = cache->syno_allocator.space_info; +#endif /* MY_ABC_HERE */ + ret = exclude_super_stripes(cache); if (ret) { /* We may have excluded something, so call this just in case */ @@ -2321,6 +2620,10 @@ void btrfs_dec_block_group_ro(struct btrfs_block_group *cache) } spin_unlock(&cache->lock); spin_unlock(&sinfo->lock); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_relink_block_group(cache); +#endif /* MY_ABC_HERE */ + } static int update_block_group_item(struct btrfs_trans_handle *trans, @@ -2354,6 +2657,24 @@ static int update_block_group_item(struct btrfs_trans_handle *trans, btrfs_set_stack_block_group_flags(&bgi, cache->flags); write_extent_buffer(leaf, &bgi, bi, sizeof(bgi)); btrfs_mark_buffer_dirty(leaf); + +#ifdef MY_ABC_HERE + if (btrfs_syno_block_group_cache_tree_enabled(fs_info)) { + btrfs_release_path(path); + ret = btrfs_search_slot(trans, fs_info->block_group_cache_root, &key, path, 0, 1); + if (ret) { + if (ret > 0) + ret = -ENOENT; + goto fail; + } + + leaf = path->nodes[0]; + bi = btrfs_item_ptr_offset(leaf, path->slots[0]); + write_extent_buffer(leaf, &bgi, bi, sizeof(bgi)); + btrfs_mark_buffer_dirty(leaf); + } +#endif /* MY_ABC_HERE */ + fail: btrfs_release_path(path); return ret; @@ -2374,6 +2695,9 @@ static int cache_save_setup(struct btrfs_block_group *block_group, int retries = 0; int ret = 0; + if (!btrfs_test_opt(fs_info, SPACE_CACHE)) + return 0; + /* * If this block group is smaller than 100 megs don't bother caching the * block group. @@ -2572,6 +2896,9 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans) struct list_head *io = &cur_trans->io_bgs; int num_started = 0; int loops = 0; +#ifdef MY_ABC_HERE + unsigned long pre_run_delayed_refs_count; +#endif /* MY_ABC_HERE */ spin_lock(&cur_trans->dirty_bgs_lock); if (list_empty(&cur_trans->dirty_bgs)) { @@ -2700,8 +3027,15 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans) * Go through delayed refs for all the stuff we've just kicked off * and then loop back (just once) */ +#ifdef MY_ABC_HERE + if (!ret) { + pre_run_delayed_refs_count = min_t(unsigned long, atomic_read(&trans->transaction->delayed_refs.num_entries) * 2, 512); + ret = btrfs_run_delayed_refs(trans, pre_run_delayed_refs_count); + } +#else /* MY_ABC_HERE */ if (!ret) ret = btrfs_run_delayed_refs(trans, 0); +#endif /* MY_ABC_HERE */ if (!ret && loops == 0) { loops++; spin_lock(&cur_trans->dirty_bgs_lock); @@ -2890,7 +3224,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans, * space back to the block group, otherwise we will leak space. */ if (!alloc && !btrfs_block_group_done(cache)) - btrfs_cache_block_group(cache, 1); + btrfs_cache_block_group(cache, true); byte_in_group = bytenr - cache->start; WARN_ON(byte_in_group > cache->length); @@ -3037,6 +3371,8 @@ void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, spin_unlock(&space_info->lock); } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ static void force_metadata_allocation(struct btrfs_fs_info *info) { struct list_head *head = &info->space_info; @@ -3047,6 +3383,7 @@ static void force_metadata_allocation(struct btrfs_fs_info *info) found->force_alloc = CHUNK_ALLOC_FORCE; } } +#endif /* MY_ABC_HERE */ static int should_alloc_chunk(struct btrfs_fs_info *fs_info, struct btrfs_space_info *sinfo, int force) @@ -3071,6 +3408,11 @@ static int should_alloc_chunk(struct btrfs_fs_info *fs_info, if (bytes_used + SZ_2M < div_factor(sinfo->total_bytes, 8)) return 0; +#ifdef MY_ABC_HERE + if (sinfo->flags & BTRFS_BLOCK_GROUP_DATA && + bytes_used + SZ_2M < div_factor_fine(sinfo->total_bytes, 98)) + return 0; +#endif /* MY_ABC_HERE */ return 1; } @@ -3098,6 +3440,9 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, bool wait_for_alloc = false; bool should_alloc = false; int ret = 0; +#ifdef MY_ABC_HERE + const enum btrfs_chunk_alloc_enum orig_force = force; +#endif /* MY_ABC_HERE */ /* Don't re-enter if we're already allocating a chunk */ if (trans->allocating_chunk) @@ -3133,6 +3478,9 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, spin_unlock(&space_info->lock); mutex_lock(&fs_info->chunk_mutex); mutex_unlock(&fs_info->chunk_mutex); +#ifdef MY_ABC_HERE + force = orig_force; +#endif /* MY_ABC_HERE */ } else { /* Proceed with allocation */ space_info->chunk_alloc = 1; @@ -3144,6 +3492,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, } while (wait_for_alloc); mutex_lock(&fs_info->chunk_mutex); + trans->allocating_chunk = true; /* @@ -3153,6 +3502,8 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, if (btrfs_mixed_space_info(space_info)) flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ /* * if we're doing a data chunk, go ahead and make sure that * we keep a reasonable number of metadata chunks allocated in the @@ -3164,6 +3515,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, fs_info->metadata_ratio)) force_metadata_allocation(fs_info); } +#endif /* MY_ABC_HERE */ /* * Check if we have enough space in SYSTEM chunk because we may need @@ -3174,6 +3526,12 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, ret = btrfs_alloc_chunk(trans, flags); trans->allocating_chunk = false; +#ifdef MY_ABC_HERE + if (ret == -ENOSPC && (flags & BTRFS_BLOCK_GROUP_METADATA)) + btrfs_warn(fs_info, "ENOSPC, cannot alloc new metadata chunk (flags:0x%llx, Total:%llu Used:%llu)", + flags, space_info->total_bytes, space_info->bytes_used); +#endif /* MY_ABC_HERE */ + spin_lock(&space_info->lock); if (ret < 0) { if (ret == -ENOSPC) @@ -3324,14 +3682,14 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) struct btrfs_caching_control *caching_ctl; struct rb_node *n; - down_write(&info->commit_root_sem); + spin_lock(&info->block_group_cache_lock); while (!list_empty(&info->caching_block_groups)) { caching_ctl = list_entry(info->caching_block_groups.next, struct btrfs_caching_control, list); list_del(&caching_ctl->list); btrfs_put_caching_control(caching_ctl); } - up_write(&info->commit_root_sem); + spin_unlock(&info->block_group_cache_lock); spin_lock(&info->unused_bgs_lock); while (!list_empty(&info->unused_bgs)) { @@ -3438,6 +3796,320 @@ void btrfs_unfreeze_block_group(struct btrfs_block_group *block_group) } } +#ifdef MY_ABC_HERE +int btrfs_reserve_log_tree_bg(struct btrfs_root *root, + u64 *rsv_start, u64 *rsv_size) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_space_info *space_info = NULL; + struct btrfs_block_group *bg = NULL; + struct btrfs_block_group *rsv_bg = NULL; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_free_cluster *cluster = NULL; + u64 flags; + int index; + int ret; + + flags = btrfs_metadata_alloc_profile(fs_info); + space_info = btrfs_find_space_info(fs_info, flags); + if (!space_info) { + btrfs_err(fs_info, "No space info for %llu", flags); + return -ENOSPC; + } + + index = btrfs_bg_flags_to_raid_index(flags); + down_read(&space_info->groups_sem); + list_for_each_entry(bg, &space_info->block_groups[index], list) { + if (unlikely(bg->ro)) + continue; + + spin_lock(&bg->lock); + if (bg->cached == BTRFS_CACHE_FINISHED) { + struct btrfs_free_space_ctl *ctl = bg->free_space_ctl; + + spin_lock(&ctl->tree_lock); + if (ctl->free_space == bg->length) { + rsv_bg = bg; + btrfs_get_block_group(rsv_bg); + spin_unlock(&ctl->tree_lock); + spin_unlock(&bg->lock); + up_read(&space_info->groups_sem); + goto set_rsv; + } + spin_unlock(&ctl->tree_lock); + } else if (bg->used == 0) { + rsv_bg = bg; + btrfs_get_block_group(rsv_bg); + spin_unlock(&bg->lock); + up_read(&space_info->groups_sem); + goto set_rsv; + } + spin_unlock(&bg->lock); + } + up_read(&space_info->groups_sem); + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + mutex_lock(&fs_info->chunk_mutex); + trans->allocating_chunk = true; + check_system_chunk(trans, flags); + ret = btrfs_alloc_chunk_with_info(trans, flags, rsv_start, rsv_size); + trans->allocating_chunk = false; + btrfs_end_transaction(trans); + mutex_unlock(&fs_info->chunk_mutex); + if (ret) + return ret; + + rsv_bg = btrfs_lookup_block_group(fs_info, *rsv_start); + if (!rsv_bg) + return -ENOENT; +set_rsv: + // Don't want to race with `delete_unused_bgs`, so take the groups_sem. + down_read(&space_info->groups_sem); + // Check this block group is still available. + if (unlikely(rsv_bg->ro)) { + up_read(&space_info->groups_sem); + btrfs_put_block_group(rsv_bg); + return -EAGAIN; + } + fs_info->log_tree_rsv_start = *rsv_start = rsv_bg->start; + fs_info->log_tree_rsv_size = *rsv_size = rsv_bg->length; + up_read(&space_info->groups_sem); + btrfs_put_block_group(rsv_bg); + + // Only make sure we will not make cluster from this block group in the future. + cluster = &fs_info->meta_alloc_cluster; + spin_lock(&cluster->refill_lock); + btrfs_return_cluster_to_free_space(rsv_bg, cluster); + spin_unlock(&cluster->refill_lock); + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int clear_block_group_cache_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root) +{ + struct btrfs_path *path; + struct btrfs_key key; + int ret; + int nr = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + path->leave_spinning = 1; + + key.objectid = 0; + key.offset = 0; + key.type = 0; + + while (1) { + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; + nr = btrfs_header_nritems(path->nodes[0]); + if (!nr) + break; + + path->slots[0] = 0; + ret = btrfs_del_items(trans, root, path, 0, nr); + if (ret) + goto out; + + btrfs_release_path(path); + } + ret = 0; +out: + btrfs_free_path(path); + return ret; +} +int btrfs_clear_block_group_cache_tree(struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_trans_handle *trans; + struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *block_group_cache_root = fs_info->block_group_cache_root; + + trans = btrfs_start_transaction(tree_root, 0); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + btrfs_clear_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE); + btrfs_clear_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE_AUTO); + clear_bit(BTRFS_FS_BLOCK_GROUP_CACHE_TREE_BROKEN, &fs_info->flags); + fs_info->block_group_cache_root = NULL; + + ret = clear_block_group_cache_tree(trans, block_group_cache_root); + if (ret) + goto abort; + + ret = btrfs_del_root(trans, &block_group_cache_root->root_key); + if (ret) + goto abort; + + list_del(&block_group_cache_root->dirty_list); + + btrfs_tree_lock(block_group_cache_root->node); + btrfs_clean_tree_block(block_group_cache_root->node); + btrfs_tree_unlock(block_group_cache_root->node); + btrfs_free_tree_block(trans, block_group_cache_root, block_group_cache_root->node, 0, 1); + + btrfs_put_root(block_group_cache_root); + + return btrfs_commit_transaction(trans); + +abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_create_block_group_cache_tree(struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_trans_handle *trans; + struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *block_group_cache_root; + struct btrfs_block_group *block_group; + struct rb_node *node; + struct btrfs_block_group_item bgi; + struct btrfs_key key; + + trans = btrfs_start_transaction(tree_root, 0); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + set_bit(BTRFS_FS_CREATING_BLOCK_GROUP_CACHE_TREE, &fs_info->flags); + block_group_cache_root = btrfs_create_tree(trans, BTRFS_BLOCK_GROUP_CACHE_TREE_OBJECTID); + if (IS_ERR(block_group_cache_root)) { + ret = PTR_ERR(block_group_cache_root); + goto abort; + } + fs_info->block_group_cache_root = block_group_cache_root; + + node = rb_first(&fs_info->block_group_cache_tree); + while (node) { + block_group = rb_entry(node, struct btrfs_block_group, + cache_node); + + spin_lock(&block_group->lock); + btrfs_set_stack_block_group_used(&bgi, block_group->used); + btrfs_set_stack_block_group_chunk_objectid(&bgi, + BTRFS_FIRST_CHUNK_TREE_OBJECTID); + btrfs_set_stack_block_group_flags(&bgi, block_group->flags); + key.objectid = block_group->start; + key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; + key.offset = block_group->length; + spin_unlock(&block_group->lock); + + ret = btrfs_insert_item(trans, block_group_cache_root, &key, &bgi, sizeof(bgi)); + if (ret) { + btrfs_err(fs_info, "Failed to insert block group item %llu-%llu into cache tree, err = %d\n", + key.objectid, key.offset, ret); + goto abort; + } + + node = rb_next(node); + } + btrfs_set_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE); + btrfs_set_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE_AUTO); + clear_bit(BTRFS_FS_CREATING_BLOCK_GROUP_CACHE_TREE, &fs_info->flags); + + return btrfs_commit_transaction(trans); + +abort: + clear_bit(BTRFS_FS_CREATING_BLOCK_GROUP_CACHE_TREE, &fs_info->flags); + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_check_syno_block_group_cache_tree(struct btrfs_fs_info *fs_info) +{ + int ret = -1; + struct btrfs_path *path = NULL; + struct btrfs_key key; + struct btrfs_key found_key; + struct extent_map_tree *map_tree = &fs_info->mapping_tree; + struct extent_map *chunk_em = NULL; + struct extent_buffer *leaf; + + if (!fs_info->block_group_cache_root) { + ret = 0; + goto out; + } + + if (btrfs_root_generation(&fs_info->block_group_cache_root->root_item) != btrfs_root_generation(&fs_info->extent_root->root_item)) { + btrfs_warn(fs_info, "Failed to generation mismatch block group cache tree [%llu], extent tree [%llu]", + btrfs_root_generation(&fs_info->block_group_cache_root->root_item), + btrfs_root_generation(&fs_info->extent_root->root_item)); + ret = -EUCLEAN; + goto out; + } + + key.objectid = 0; + key.offset = 0; + key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + path->reada = READA_FORWARD_ALWAYS; + + while (1) { + read_lock(&map_tree->lock); + chunk_em = lookup_extent_mapping(map_tree, key.objectid, -1); + read_unlock(&map_tree->lock); + + ret = find_first_block_group(fs_info, path, &key, fs_info->block_group_cache_root); + if (ret < 0) { + btrfs_warn(fs_info, "Failed to lookup block group from cache tree, ret %d\n", ret); + goto out; + } + /* check whether it's the end */ + if (ret > 0 && !chunk_em) + break; + /* check whether the two sides are inconsistent */ + if (ret || !chunk_em) { + if (chunk_em) + btrfs_warn(fs_info, "Failed to compare chunk em %llu-%llu\n", chunk_em->start, chunk_em->len); + if (!ret) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + btrfs_warn(fs_info, "Failed to compare cache block group item %llu-%llu\n", found_key.objectid, found_key.offset); + } + ret = -EUCLEAN; + goto out; + } + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + btrfs_release_path(path); + + if (chunk_em->start != found_key.objectid || chunk_em->len != found_key.offset) { + btrfs_warn(fs_info, "Failed to compare block group item %llu-%llu from cache tree, chunk em %llu-%llu\n", + key.objectid, key.offset, chunk_em->start, chunk_em->len); + ret = -EUCLEAN; + goto out; + } + + free_extent_map(chunk_em); + key.objectid = found_key.objectid + found_key.offset; + } + + ret = 0; +out: + btrfs_free_path(path); + free_extent_map(chunk_em); + return ret; +} +#endif /* MY_ABC_HERE */ + bool btrfs_inc_block_group_swap_extents(struct btrfs_block_group *bg) { bool ret = true; diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index 4c7614346f72..e173524dcce9 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_BLOCK_GROUP_H @@ -48,7 +51,6 @@ struct btrfs_caching_control { wait_queue_head_t wait; struct btrfs_work work; struct btrfs_block_group *block_group; - u64 progress; refcount_t count; }; @@ -101,7 +103,6 @@ struct btrfs_block_group { /* Cache tracking stuff */ int cached; struct btrfs_caching_control *caching_ctl; - u64 last_byte_to_unpin; struct btrfs_space_info *space_info; @@ -189,6 +190,24 @@ struct btrfs_block_group { /* Record locked full stripes for RAID5/6 block group */ struct btrfs_full_stripe_locks_tree full_stripe_locks_root; + +#ifdef MY_ABC_HERE + struct { + struct btrfs_space_info *space_info; + /* protect with space_info->syno_allocator.lock */ + struct rb_node bytes_index; + struct rb_node max_length_index; + struct rb_node max_length_with_extent_index; + u64 last_bytes, last_max_length, last_max_length_with_extent; + struct rb_node preload_index; + u64 preload_free_space; + bool ro; + bool cache_error; + bool removed; + bool initialized; + atomic_t refs; + } syno_allocator; +#endif /* MY_ABC_HERE */ }; static inline u64 btrfs_block_group_end(struct btrfs_block_group *block_group) @@ -236,9 +255,7 @@ void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr); void btrfs_wait_nocow_writers(struct btrfs_block_group *bg); void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache, u64 num_bytes); -int btrfs_wait_block_group_cache_done(struct btrfs_block_group *cache); -int btrfs_cache_block_group(struct btrfs_block_group *cache, - int load_cache_only); +int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait); void btrfs_put_caching_control(struct btrfs_caching_control *ctl); struct btrfs_caching_control *btrfs_get_caching_control( struct btrfs_block_group *cache); @@ -274,6 +291,8 @@ void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type); u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags); void btrfs_put_block_group_cache(struct btrfs_fs_info *info); int btrfs_free_block_groups(struct btrfs_fs_info *info); +void btrfs_wait_space_cache_v1_finished(struct btrfs_block_group *cache, + struct btrfs_caching_control *caching_ctl); static inline u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info) { @@ -305,6 +324,22 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start, u64 physical, u64 **logical, int *naddrs, int *stripe_len); #endif +#ifdef MY_ABC_HERE +int btrfs_reserve_log_tree_bg(struct btrfs_root *root, + u64 *rsv_start, u64 *rsv_size); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int btrfs_clear_block_group_cache_tree(struct btrfs_fs_info *fs_info); +int btrfs_create_block_group_cache_tree(struct btrfs_fs_info *fs_info); +int btrfs_check_syno_block_group_cache_tree(struct btrfs_fs_info *fs_info); +static inline bool btrfs_syno_block_group_cache_tree_enabled(struct btrfs_fs_info *fs_info) +{ + if (!fs_info || !fs_info->block_group_cache_root || test_bit(BTRFS_FS_BLOCK_GROUP_CACHE_TREE_BROKEN, &fs_info->flags)) + return false; + return true; +} +#endif /* MY_ABC_HERE */ + bool btrfs_inc_block_group_swap_extents(struct btrfs_block_group *bg); void btrfs_dec_block_group_swap_extents(struct btrfs_block_group *bg, int amount); diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c index bc920afe23bf..567c818bf69f 100644 --- a/fs/btrfs/block-rsv.c +++ b/fs/btrfs/block-rsv.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include "misc.h" @@ -353,6 +356,9 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) struct btrfs_space_info *sinfo = block_rsv->space_info; u64 num_bytes; unsigned min_items; +#ifdef MY_ABC_HERE + struct btrfs_root *syno_extent_usage_root = fs_info->syno_extent_usage_root; +#endif /* MY_ABC_HERE */ /* * The global block rsv is based on the size of the extent tree, the @@ -362,6 +368,14 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) + btrfs_root_used(&fs_info->csum_root->root_item) + btrfs_root_used(&fs_info->tree_root->root_item); +#ifdef MY_ABC_HERE + if (fs_info->free_space_root) + num_bytes += btrfs_root_used(&fs_info->free_space_root->root_item); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (syno_extent_usage_root) + num_bytes += btrfs_root_used(&syno_extent_usage_root->root_item) * 2; +#endif /* MY_ABC_HERE */ /* * We at a minimum are going to modify the csum root, the tree root, and @@ -386,7 +400,25 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) spin_lock(&sinfo->lock); spin_lock(&block_rsv->lock); +#ifdef MY_ABC_HERE + /* + * When volume size <= 50GB, the first metadata chunk is 256MB (from btrfs-progs) + * In the old version, when the volume size > 80G, we set the + * minimum value of global reservation to 256MB, otherwise set to 16MB. + * + * DSM #126033, lower this condition to volume size >= 10GB. + * Therefore, after the upgrade, the remaining space may be taken + * away by the global reserve, resulting in the volume cannot + * be written, and ENOSPC appears. + */ + if (fs_info->super_copy->total_bytes > 50ULL * 1024 * 1024 * 1024) + num_bytes = max_t(u64, num_bytes, SZ_256M); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + block_rsv->size = min_t(u64, num_bytes, SZ_2G); +#else /* MY_ABC_HERE */ block_rsv->size = min_t(u64, num_bytes, SZ_512M); +#endif /* MY_ABC_HERE */ if (block_rsv->reserved < block_rsv->size) { num_bytes = block_rsv->size - block_rsv->reserved; @@ -412,6 +444,36 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) spin_unlock(&sinfo->lock); } +#ifdef MY_ABC_HERE +static void init_cleaner_block_rsv(struct btrfs_fs_info *fs_info) +{ + struct btrfs_block_rsv *block_rsv = &fs_info->cleaner_block_rsv; + struct btrfs_space_info *sinfo = block_rsv->space_info; + u64 used, num_bytes; + + spin_lock(&sinfo->lock); + spin_lock(&block_rsv->lock); + + block_rsv->size = 0; + block_rsv->reserved = 0; + + used = btrfs_space_info_used(sinfo, true); + if (used + SZ_16M < sinfo->total_bytes) + block_rsv->size = sinfo->total_bytes - used; + + if (fs_info->super_copy->total_bytes > 80ULL * 1024 * 1024 * 1024) + block_rsv->size = min_t(u64, block_rsv->size, SZ_128M); + else + block_rsv->size = min_t(u64, block_rsv->size, SZ_16M); + num_bytes = block_rsv->size - block_rsv->reserved; + btrfs_space_info_update_bytes_may_use(fs_info, sinfo, num_bytes); + block_rsv->reserved = block_rsv->size; + block_rsv->full = 1; + spin_unlock(&block_rsv->lock); + spin_unlock(&sinfo->lock); +} +#endif /* MY_ABC_HERE */ + void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info) { struct btrfs_space_info *space_info; @@ -425,8 +487,21 @@ void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info) fs_info->empty_block_rsv.space_info = space_info; fs_info->delayed_block_rsv.space_info = space_info; fs_info->delayed_refs_rsv.space_info = space_info; +#ifdef MY_ABC_HERE + fs_info->cleaner_block_rsv.space_info = space_info; +#endif /* MY_ABC_HERE */ fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv; +#ifdef MY_ABC_HERE + if (fs_info->syno_usage_root) + fs_info->syno_usage_root->block_rsv = &fs_info->delayed_refs_rsv; + if (fs_info->syno_extent_usage_root) + fs_info->syno_extent_usage_root->block_rsv = &fs_info->delayed_refs_rsv; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (fs_info->free_space_root) + fs_info->free_space_root->block_rsv = &fs_info->global_block_rsv; +#endif /* MY_ABC_HERE */ fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv; fs_info->dev_root->block_rsv = &fs_info->global_block_rsv; fs_info->tree_root->block_rsv = &fs_info->global_block_rsv; @@ -435,10 +510,16 @@ void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info) fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; btrfs_update_global_block_rsv(fs_info); +#ifdef MY_ABC_HERE + init_cleaner_block_rsv(fs_info); +#endif /* MY_ABC_HERE */ } void btrfs_release_global_block_rsv(struct btrfs_fs_info *fs_info) { +#ifdef MY_ABC_HERE + block_rsv_release_bytes(fs_info, &fs_info->cleaner_block_rsv, NULL, (u64)-1, NULL); +#endif /* MY_ABC_HERE */ btrfs_block_rsv_release(fs_info, &fs_info->global_block_rsv, (u64)-1, NULL); WARN_ON(fs_info->trans_block_rsv.size > 0); @@ -458,9 +539,22 @@ static struct btrfs_block_rsv *get_block_rsv( struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_block_rsv *block_rsv = NULL; +#ifdef MY_ABC_HERE + if (root != fs_info->chunk_root && trans->syno_usage) + return &fs_info->delayed_refs_rsv; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (root != fs_info->chunk_root && trans->cleaner) + return &fs_info->cleaner_block_rsv; +#endif /* MY_ABC_HERE */ + if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) || (root == fs_info->csum_root && trans->adding_csums) || - (root == fs_info->uuid_root)) + (root == fs_info->uuid_root) +#ifdef MY_ABC_HERE + || (root == fs_info->syno_feat_root) +#endif /* MY_ABC_HERE */ + ) block_rsv = trans->block_rsv; if (!block_rsv) @@ -482,6 +576,9 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, int ret; bool global_updated = false; +#ifdef MY_ABC_HERE +retry: +#endif /* MY_ABC_HERE */ block_rsv = get_block_rsv(trans, root); if (unlikely(block_rsv->size == 0)) @@ -494,6 +591,13 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, if (block_rsv->failfast) return ERR_PTR(ret); +#ifdef MY_ABC_HERE + if (block_rsv == &fs_info->cleaner_block_rsv) { + trans->cleaner = false; + goto retry; + } +#endif /* MY_ABC_HERE */ + if (block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL && !global_updated) { global_updated = true; btrfs_update_global_block_rsv(fs_info); @@ -529,6 +633,12 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, ret = btrfs_block_rsv_use_bytes(global_rsv, blocksize); if (!ret) return global_rsv; +#ifdef MY_ABC_HERE + if (block_rsv->type != BTRFS_BLOCK_RSV_TEMP) { + block_rsv = global_rsv; + goto again; + } +#endif /* MY_ABC_HERE */ } return ERR_PTR(ret); } diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 8de4bf8edb9c..3898f29c8f6a 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -12,6 +15,9 @@ #include "extent_io.h" #include "ordered-data.h" #include "delayed-inode.h" +#ifdef MY_ABC_HERE +#include "delalloc-space.h" +#endif /* MY_ABC_HERE */ /* * ordered_data_close is set by truncate when a file that used @@ -51,6 +57,20 @@ enum { * the file range, inode's io_tree). */ BTRFS_INODE_NO_DELALLOC_FLUSH, +#ifdef MY_ABC_HERE + BTRFS_INODE_CREATE_TIME, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* these two bits are mutually exclusive */ + BTRFS_INODE_LOCKER_NOLOCK, + BTRFS_INODE_LOCKER_LOCKABLE, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_INODE_USRQUOTA_META_RESERVED, +#endif /* MY_ABC_HERE */ }; /* in memory btrfs inode */ @@ -66,7 +86,8 @@ struct btrfs_inode { /* * Lock for counters and all fields used to determine if the inode is in * the log or not (last_trans, last_sub_trans, last_log_commit, - * logged_trans). + * logged_trans), to access/update new_delalloc_bytes and to update the + * VFS' inode number of bytes used. */ spinlock_t lock; @@ -99,6 +120,10 @@ struct btrfs_inode { */ struct list_head delalloc_inodes; +#ifdef MY_ABC_HERE + struct list_head syno_dirty_lru_inode; +#endif /* MY_ABC_HERE */ + /* node for the red-black tree that links inodes in subvolume root */ struct rb_node rb_node; @@ -230,6 +255,46 @@ struct btrfs_inode { struct rw_semaphore dio_sem; struct inode vfs_inode; +#ifdef MY_ABC_HERE + union { + enum locker_state __locker_state; + const enum locker_state locker_state; + }; + union { + time64_t __locker_update_time; // in volume clock + const time64_t locker_update_time; + }; + union { + time64_t __locker_period_begin; // in volume clock + const time64_t locker_period_begin; + }; + union { + time64_t __locker_period_end; // in volume clock + const time64_t locker_period_end; + }; + bool locker_dirty; + spinlock_t locker_lock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct list_head free_extent_map_inode; + atomic_t free_extent_map_counts; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // For chown, used by quota v2 and v1. + u64 uq_reserved; + + // For chown, used by quota v1. + u64 uq_rfer_used; + + // Reserve meta for user quota v1 update. + atomic_t syno_uq_refs; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct list_head syno_rbd_meta_file; +#endif /* MY_ABC_HERE */ }; static inline u32 btrfs_inode_sectorsize(const struct btrfs_inode *inode) @@ -330,6 +395,17 @@ static inline int btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation) return ret; } +/* + * Check if the inode has flags compatible with compression + */ +static inline bool btrfs_inode_can_compress(const struct btrfs_inode *inode) +{ + if (inode->flags & BTRFS_INODE_NODATACOW || + inode->flags & BTRFS_INODE_NODATASUM) + return false; + return true; +} + struct btrfs_dio_private { struct inode *inode; u64 logical_offset; @@ -354,7 +430,11 @@ struct btrfs_dio_private { #define CSUM_FMT_VALUE(size, bytes) size, bytes static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode, - u64 logical_start, u8 *csum, u8 *csum_expected, int mirror_num) + u64 logical_start, u8 *csum, u8 *csum_expected, int mirror_num +#ifdef MY_ABC_HERE + , enum syno_data_correction_suppress_log_status flag +#endif /* MY_ABC_HERE */ + ) { struct btrfs_root *root = inode->root; struct btrfs_super_block *sb = root->fs_info->super_copy; @@ -362,7 +442,11 @@ static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode, /* Output minus objectid, which is more meaningful */ if (root->root_key.objectid >= BTRFS_LAST_FREE_OBJECTID) +#ifdef MY_ABC_HERE + btrfs_data_correction_print(root->fs_info, flag, +#else /* MY_ABC_HERE */ btrfs_warn_rl(root->fs_info, +#endif /* MY_ABC_HERE */ "csum failed root %lld ino %lld off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d", root->root_key.objectid, btrfs_ino(inode), logical_start, @@ -370,7 +454,11 @@ static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode, CSUM_FMT_VALUE(csum_size, csum_expected), mirror_num); else +#ifdef MY_ABC_HERE + btrfs_data_correction_print(root->fs_info, flag, +#else /* MY_ABC_HERE */ btrfs_warn_rl(root->fs_info, +#endif /* MY_ABC_HERE */ "csum failed root %llu ino %llu off %llu csum " CSUM_FMT " expected csum " CSUM_FMT " mirror %d", root->root_key.objectid, btrfs_ino(inode), logical_start, @@ -379,4 +467,62 @@ static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode, mirror_num); } +#ifdef MY_ABC_HERE +static inline bool btrfs_usrquota_fast_chown_enable(struct inode *inode) +{ + struct btrfs_fs_info *fs_info; + + if (unlikely(!inode || !BTRFS_I(inode)->root)) + return false; + + fs_info = BTRFS_I(inode)->root->fs_info; + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags)) + return false; + if (btrfs_root_disable_quota(BTRFS_I(inode)->root)) + return false; + if (!btrfs_usrquota_compat_inode_quota(fs_info)) + return false; + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_UQ_REF_USED)) + return false; + return true; +} + +static inline struct inode *syno_usrquota_inode_get(struct inode *inode) +{ + if (!btrfs_usrquota_fast_chown_enable(inode)) + return NULL; + + inode = igrab(inode); + if (inode) + atomic_inc(&BTRFS_I(inode)->syno_uq_refs); + return inode; +} + +static inline void syno_usrquota_inode_put(struct inode *inode) +{ + struct btrfs_fs_info *fs_info; + bool free_reserve = false; + + if (!btrfs_usrquota_fast_chown_enable(inode)) + return; + + fs_info = BTRFS_I(inode)->root->fs_info; + WARN_ON(atomic_read(&BTRFS_I(inode)->syno_uq_refs) == 0); + if (atomic_dec_and_test(&BTRFS_I(inode)->syno_uq_refs)) { + spin_lock(&BTRFS_I(inode)->lock); + if (test_and_clear_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, + &BTRFS_I(inode)->runtime_flags)) { + btrfs_calculate_inode_block_rsv_size(fs_info, BTRFS_I(inode)); + free_reserve = true; + } + spin_unlock(&BTRFS_I(inode)->lock); + if (free_reserve) + // Use 0 bytes, see the comment in btrfs_inode_rsv_release(). + btrfs_block_rsv_release(fs_info, &BTRFS_I(inode)->block_rsv, 0, NULL); + } + + btrfs_add_delayed_iput(inode); +} +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 7bdc86b74f15..ad7d4d3f8e0b 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2008 Oracle. All rights reserved. @@ -169,7 +172,11 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio, if (memcmp(&csum, cb_sum, csum_size)) { btrfs_print_data_csum_error(inode, disk_start, - csum, cb_sum, cb->mirror_num); + csum, cb_sum, cb->mirror_num +#ifdef MY_ABC_HERE + , DATA_CORRECTION_RATE_LIMIT +#endif /* MY_ABC_HERE */ + ); if (btrfs_io_bio(bio)->device) btrfs_dev_stat_inc_and_print( btrfs_io_bio(bio)->device, @@ -428,6 +435,15 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start, submit = btrfs_bio_fits_in_stripe(page, PAGE_SIZE, bio, 0); +#ifdef MY_ABC_HERE + /* + * For latency, limit write bio maximum with 64k, avoid too much page + * is marked as writeback. + */ + if (bio_op(bio) == REQ_OP_WRITE && bio->bi_iter.bi_size >= SZ_64K) + submit = 1; +#endif /* MY_ABC_HERE */ + page->mapping = NULL; if (submit || bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { @@ -639,11 +655,17 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, em_tree = &BTRFS_I(inode)->extent_tree; /* we need the actual starting offset of this extent in the file */ +#ifdef MY_ABC_HERE + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, + page_offset(bio_first_page_all(bio)), + PAGE_SIZE); +#else /* MY_ABC_HERE */ read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, page_offset(bio_first_page_all(bio)), PAGE_SIZE); read_unlock(&em_tree->lock); +#endif /* MY_ABC_HERE */ if (!em) return BLK_STS_IOERR; diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h index 8001b700ea3a..c50d4da159da 100644 --- a/fs/btrfs/compression.h +++ b/fs/btrfs/compression.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2008 Oracle. All rights reserved. @@ -108,6 +111,9 @@ enum btrfs_compression_type { BTRFS_COMPRESS_LZO = 2, BTRFS_COMPRESS_ZSTD = 3, BTRFS_NR_COMPRESS_TYPES = 4, +#ifdef MY_ABC_HERE + BTRFS_COMPRESS_DEFAULT = 2, +#endif /* MY_ABC_HERE */ }; struct workspace_manager { diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 519cf145f9bd..752468df78e7 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007,2008 Oracle. All rights reserved. @@ -984,6 +987,12 @@ static struct extent_buffer *alloc_tree_block_no_bg_flush( * new root node for one of those trees. */ if (root == fs_info->extent_root || +#ifdef MY_ABC_HERE + root == fs_info->block_group_hint_root || +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + root == fs_info->block_group_cache_root || +#endif /* MY_ABC_HERE */ root == fs_info->chunk_root || root == fs_info->dev_root || root == fs_info->free_space_root) @@ -1370,6 +1379,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) struct tree_mod_elem *tm2; btrfs_tree_read_lock(old); + btrfs_set_lock_blocking_read(old); eb = btrfs_clone_extent_buffer(old); /* * After the lookup for the most recent tree mod operation @@ -1382,7 +1392,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) * buffer. */ tm2 = tree_mod_log_search(fs_info, logical, time_seq); - btrfs_tree_read_unlock(old); + btrfs_tree_read_unlock_blocking(old); free_extent_buffer(old); ASSERT(tm2); ASSERT(tm2 == tm || tm2->seq > tm->seq); @@ -2224,12 +2234,13 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, u64 search; u64 target; u64 nread = 0; + u64 nread_max; struct extent_buffer *eb; u32 nr; u32 blocksize; u32 nscan = 0; - if (level != 1) + if (level != 1 && path->reada != READA_FORWARD_ALWAYS) return; if (!path->nodes[level]) @@ -2237,6 +2248,20 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, node = path->nodes[level]; + /* + * Since the time between visiting leaves is much shorter than the time + * between visiting nodes, limit read ahead of nodes to 1, to avoid too + * much IO at once (possibly random). + */ + if (path->reada == READA_FORWARD_ALWAYS) { + if (level > 1) + nread_max = node->fs_info->nodesize; + else + nread_max = SZ_128K; + } else { + nread_max = SZ_64K; + } + search = btrfs_node_blockptr(node, slot); blocksize = fs_info->nodesize; eb = find_extent_buffer(fs_info, search); @@ -2255,7 +2280,8 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, if (nr == 0) break; nr--; - } else if (path->reada == READA_FORWARD) { + } else if (path->reada == READA_FORWARD || + path->reada == READA_FORWARD_ALWAYS) { nr++; if (nr >= nritems) break; @@ -2266,13 +2292,14 @@ static void reada_for_search(struct btrfs_fs_info *fs_info, break; } search = btrfs_node_blockptr(node, nr); - if ((search <= target && target - search <= 65536) || + if (path->reada == READA_FORWARD_ALWAYS || + (search <= target && target - search <= 65536) || (search > target && search - target <= 65536)) { readahead_tree_block(fs_info, search); nread += blocksize; } nscan++; - if ((nread > 65536 || nscan > 32)) + if (nread > nread_max || nscan > 32) break; } } @@ -2408,6 +2435,9 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p, tmp = find_extent_buffer(fs_info, blocknr); if (tmp) { + if (p->reada == READA_FORWARD_ALWAYS) + reada_for_search(fs_info, p, level, slot, key->objectid); + /* first we do an atomic uptodate check */ if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) { /* @@ -2676,8 +2706,14 @@ static struct extent_buffer *btrfs_search_slot_get_root(struct btrfs_root *root, * @p: Holds all btree nodes along the search path * @root: The root node of the tree * @key: The key we are looking for - * @ins_len: Indicates purpose of search, for inserts it is 1, for - * deletions it's -1. 0 for plain searches + * @ins_len: Indicates purpose of search: + * >0 for inserts it's size of item inserted (*) + * <0 for deletions + * 0 for plain searches, not modifying the tree + * + * (*) If size of item inserted doesn't include + * sizeof(struct btrfs_item), then p->search_for_extension must + * be set. * @cow: boolean should CoW operations be performed. Must always be 1 * when modifying the tree. * @@ -2839,6 +2875,20 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (level == 0) { p->slots[level] = slot; + /* + * Item key already exists. In this case, if we are + * allowed to insert the item (for example, in dir_item + * case, item key collision is allowed), it will be + * merged with the original item. Only the item size + * grows, no new btrfs item will be added. If + * search_for_extension is not set, ins_len already + * accounts the size btrfs_item, deduct it here so leaf + * space check will be correct. + */ + if (ret == 0 && ins_len > 0 && !p->search_for_extension) { + ASSERT(ins_len >= sizeof(struct btrfs_item)); + ins_len -= sizeof(struct btrfs_item); + } if (ins_len > 0 && btrfs_leaf_free_space(b) < ins_len) { if (write_lock_level < 1) { @@ -2935,6 +2985,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, btrfs_set_path_blocking(p); if (ret < 0 && !p->skip_release_on_error) btrfs_release_path(p); +#ifdef MY_ABC_HERE + atomic64_inc(&root->fs_info->syno_meta_statistics.search_key); + trace_btrfs_syno_meta_statistics_search_key(root->fs_info, root, key); +#endif /* MY_ABC_HERE */ return ret; } @@ -3042,6 +3096,10 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, btrfs_set_path_blocking(p); if (ret < 0) btrfs_release_path(p); +#ifdef MY_ABC_HERE + atomic64_inc(&root->fs_info->syno_meta_statistics.search_key); + trace_btrfs_syno_meta_statistics_search_key(root->fs_info, root, key); +#endif /* MY_ABC_HERE */ return ret; } @@ -5213,6 +5271,10 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, { struct extent_buffer *cur; struct btrfs_key found_key; +#ifdef MY_ABC_HERE + int i, reada_end; + struct extent_buffer *eb; +#endif /* MY_ABC_HERE */ int slot; int sret; u32 nritems; @@ -5291,6 +5353,25 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, goto out; } btrfs_set_path_blocking(path); +#ifdef MY_ABC_HERE +#define MAX_READA_EXTENT_BUFFER 32 + if (path->reada == READA_FORWARD_ALWAYS && level == 1) { + eb = find_extent_buffer(root->fs_info, + btrfs_node_blockptr(cur, slot)); + if (!eb || (eb && !extent_buffer_uptodate(eb))) { + if (slot + MAX_READA_EXTENT_BUFFER < nritems) + reada_end = slot + MAX_READA_EXTENT_BUFFER; + else + reada_end = nritems; + for (i = slot; i < reada_end; i++) { + readahead_tree_block(root->fs_info, + btrfs_node_blockptr(cur, i)); + } + } + if (eb) + free_extent_buffer(eb); + } +#endif /* MY_ABC_HERE */ cur = btrfs_read_node_slot(cur, slot); if (IS_ERR(cur)) { ret = PTR_ERR(cur); @@ -5310,6 +5391,10 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, btrfs_set_path_blocking(path); memcpy(min_key, &found_key, sizeof(found_key)); } +#ifdef MY_ABC_HERE + atomic64_inc(&root->fs_info->syno_meta_statistics.search_forward); + trace_btrfs_syno_meta_statistics_search_forward(root->fs_info, root, min_key); +#endif /* MY_ABC_HERE */ return ret; } @@ -5467,6 +5552,10 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, goto done; } +#ifdef MY_ABC_HERE + atomic64_inc(&root->fs_info->syno_meta_statistics.next_leaf); + trace_btrfs_syno_meta_statistics_next_leaf(root->fs_info, root, &key); +#endif /* MY_ABC_HERE */ while (level < BTRFS_MAX_LEVEL) { if (!path->nodes[level]) { ret = 1; diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bcc6848bb6d6..f95b1eb7f894 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -28,6 +31,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "extent-io-tree.h" #include "extent_io.h" #include "extent_map.h" @@ -273,19 +279,46 @@ struct btrfs_super_block { __le64 reserved[28]; u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) + u8 syno_reserved[517]; + __le64 syno_locker_clock; /* epoch time in seconds */ + __le64 syno_rbd_first_mapping_table_offset; + __le64 syno_capability_flags; + __le64 syno_capability_generation; + __le64 log_tree_rsv; + __le64 syno_generation; +#endif /* MY_ABC_HERE || MY_ABC_HERE || + MY_ABC_HERE || MY_ABC_HERE + */ } __attribute__ ((__packed__)); /* * Compat flags that we support. If any incompat flags are set other than the * ones specified below then we will fail to mount */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define BTRFS_FEATURE_COMPAT_SUPP \ + (BTRFS_FEATURE_COMPAT_BLOCK_GROUP_CACHE_TREE | \ + BTRFS_FEATURE_COMPAT_BLOCK_GROUP_CACHE_TREE_AUTO | \ + BTRFS_FEATURE_COMPAT_SYNO_CASELESS) +#else /* MY_ABC_HERE */ #define BTRFS_FEATURE_COMPAT_SUPP 0ULL +#endif /* MY_ABC_HERE || MY_ABC_HERE */ #define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL #define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL +#ifdef MY_ABC_HERE +#define BTRFS_FEATURE_COMPAT_RO_SUPP \ + (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \ + BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID |\ + BTRFS_FEATURE_COMPAT_RO_LOCKER) +#else /* MY_ABC_HERE */ #define BTRFS_FEATURE_COMPAT_RO_SUPP \ (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \ BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID) +#endif /* MY_ABC_HERE */ #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL @@ -308,6 +341,22 @@ struct btrfs_super_block { (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) #define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR 0ULL +#ifdef MY_ABC_HERE + +#ifdef BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META +#else +#define BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META 0ULL +#endif /* BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META */ + +#define BTRFS_FEATURE_SYNO_CAPABILITY_SUPP \ + (BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META) + +#define BTRFS_FEATURE_SYNO_CAPABILITY_SAFE_SET \ + (BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META) +#define BTRFS_FEATURE_SYNO_CAPABILITY_SAFE_CLEAR \ + (BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META) +#endif /* MY_ABC_HERE */ + /* * A leaf is full of items. offset and size tell us where to find * the item in the leaf (relative to the start of the data area) @@ -345,6 +394,74 @@ struct btrfs_node { struct btrfs_key_ptr ptrs[]; } __attribute__ ((__packed__)); +#ifdef MY_ABC_HERE +/* these are bit numbers for test/set bit */ +#define SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN 0 +#define SYNO_USAGE_ROOT_RUNTIME_FLAG_FAST_RESCAN 1 +#define SYNO_USAGE_ROOT_RUNTIME_FLAG_FULL_RESCAN 2 + +struct btrfs_syno_usage_status { + /* on-disk */ + u64 version; + u64 state; + u64 flags; + struct btrfs_key extent_rescan_progress; + u64 cur_full_rescan_size; + u64 total_full_rescan_size; + u64 extent_tree_cur_rescan_size; + u64 extent_tree_total_rescan_size; + u64 total_syno_extent_tree_items; + u64 total_syno_subvol_usage_items; + + /* in memory */ + u64 syno_usage_type_num_bytes[SYNO_USAGE_TYPE_MAX]; + bool syno_usage_type_num_bytes_valid[SYNO_USAGE_TYPE_MAX]; + s32 error_code; +}; + +struct btrfs_syno_usage_root_status { + u8 type; + u8 new_type; + u64 state; + u64 flags; + u64 num_bytes; + struct btrfs_key drop_progress; + struct btrfs_key fast_rescan_progress; + struct btrfs_key full_rescan_progress; + u64 cur_full_rescan_size; + u64 total_full_rescan_size; + u64 total_syno_subvol_usage_items; +}; +#endif /* MY_ABC_HERE */ + +/* Read ahead values for struct btrfs_path.reada */ +enum { + READA_NONE, + READA_BACK, + READA_FORWARD, + /* + * Similar to READA_FORWARD but unlike it: + * + * 1) It will trigger readahead even for leaves that are not close to + * each other on disk; + * 2) It also triggers readahead for nodes; + * 3) During a search, even when a node or leaf is already in memory, it + * will still trigger readahead for other nodes and leaves that follow + * it. + * + * This is meant to be used only when we know we are iterating over the + * entire tree or a very large part of it. + */ + READA_FORWARD_ALWAYS, +}; + +#ifdef MY_ABC_HERE +struct btrfs_syno_feat_tree_status { + u64 version; + u64 status; +}; +#endif /* MY_ABC_HERE */ + /* * btrfs_paths remember the path taken from the root down to the leaf. * level 0 is always the leaf, and nodes[1...BTRFS_MAX_LEVEL] will point @@ -353,7 +470,6 @@ struct btrfs_node { * The slots array records the index of the item or block pointer * used while walking the tree. */ -enum { READA_NONE, READA_BACK, READA_FORWARD }; struct btrfs_path { struct extent_buffer *nodes[BTRFS_MAX_LEVEL]; int slots[BTRFS_MAX_LEVEL]; @@ -374,7 +490,17 @@ struct btrfs_path { unsigned int search_commit_root:1; unsigned int need_commit_sem:1; unsigned int skip_release_on_error:1; + /* + * Indicate that new item (btrfs_search_slot) is extending already + * existing item and ins_len contains only the data size and not item + * header (ie. sizeof(struct btrfs_item) is not included). + */ + unsigned int search_for_extension:1; unsigned int recurse:1; +#ifdef MY_ABC_HERE + unsigned int search_caseless_key:1; + unsigned int caseless_lookup:1; +#endif /* MY_ABC_HERE */ }; #define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r->fs_info) >> 4) - \ sizeof(struct btrfs_item)) @@ -432,12 +558,19 @@ struct btrfs_free_cluster { * be freed before the block group is freed. */ struct list_head block_group_list; +#ifdef MY_ABC_HERE + u64 reserve_bytes; + u64 empty_cluster; // only used for data cluster. + u64 min_bytes; // only used for data cluser. Only extents with size larger than this will be collected by cluster. + u64 excluded_size; // only used for data cluster. don't use cluster allocation for size bigger than this. + unsigned int downgrade_limit; // only used for data cluster. +#endif /* MY_ABC_HERE */ + }; enum btrfs_caching_type { BTRFS_CACHE_NO, BTRFS_CACHE_STARTED, - BTRFS_CACHE_FAST, BTRFS_CACHE_FINISHED, BTRFS_CACHE_ERROR, }; @@ -495,6 +628,12 @@ enum btrfs_orphan_cleanup_state { ORPHAN_CLEANUP_DONE = 2, }; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +enum { + SYNO_PERF_INDICATROT_FLAG_DIRTY_LIMIT_UPDATE, +}; +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ + void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info); /* fs_info */ @@ -538,6 +677,12 @@ enum { BTRFS_FS_LOG_RECOVERING, BTRFS_FS_OPEN, BTRFS_FS_QUOTA_ENABLED, +#ifdef MY_ABC_HERE + BTRFS_FS_SYNO_QUOTA_V1_ENABLED, + BTRFS_FS_SYNO_QUOTA_V2_ENABLED, + BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, + BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, +#endif /* MY_ABC_HERE */ BTRFS_FS_UPDATE_UUID_TREE_GEN, BTRFS_FS_CREATING_FREE_SPACE_TREE, BTRFS_FS_BTREE_ERR, @@ -565,6 +710,24 @@ enum { /* Indicate that the discard workqueue can service discards. */ BTRFS_FS_DISCARD_RUNNING, + /* Indicate that we need to cleanup space cache v1 */ + BTRFS_FS_CLEANUP_SPACE_CACHE_V1, + +#ifdef MY_ABC_HERE + BTRFS_FS_CREATING_BLOCK_GROUP_CACHE_TREE, + BTRFS_FS_BLOCK_GROUP_CACHE_TREE_BROKEN, +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_FS_ABORT_FREE_SPACE_TREE, +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, + BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_PRELOAD, + BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_CHECK_ALL, +#endif /* MY_ABC_HERE */ + /* Indicate that we can't trust the free space tree for caching yet */ BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, }; @@ -582,6 +745,44 @@ enum btrfs_exclusive_operation { BTRFS_EXCLOP_SWAP_ACTIVATE, }; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define SYNO_MOUNT_PATH_LEN 128 +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SYNO_DATA_CORRECTION_MAX_RETRY_TIMES 10 + +struct cksumfailed_file_rec { + u64 sub_vol; + u64 ino; +}; + +enum syno_data_correction_suppress_log_status { + DATA_CORRECTION_PRINT_ALL_LOG = 0, + DATA_CORRECTION_RATE_LIMIT = 1, + DATA_CORRECTION_SUPPRESS_ALL = 2, +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct syno_quota_rescan_ctx; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct dedupe_info { + struct inode *inode; + u64 seed; + u64 *hash_table; + u32 *cuckoo_idx; + u32 table_size; + u32 cuckoo_size; + u32 sample_rate; + atomic_t valid; + atomic_t modify; + atomic_t ref; +}; +#endif /* MY_ABC_HERE */ + struct btrfs_fs_info { u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; unsigned long flags; @@ -595,6 +796,9 @@ struct btrfs_fs_info { struct btrfs_root *uuid_root; struct btrfs_root *free_space_root; struct btrfs_root *data_reloc_root; +#ifdef MY_ABC_HERE + struct btrfs_root *usrquota_root; +#endif /* MY_ABC_HERE */ /* the log root tree is a directory of all the other log roots */ struct btrfs_root *log_root_tree; @@ -641,7 +845,11 @@ struct btrfs_fs_info { * is required instead of the faster short fsync log commits */ u64 last_trans_log_full_commit; +#ifdef MY_ABC_HERE + unsigned long long mount_opt; +#else /* MY_ABC_HERE */ unsigned long mount_opt; +#endif /* MY_ABC_HERE */ /* * Track requests for actions that need to be done during transaction * commit (like for some mount options). @@ -777,6 +985,9 @@ struct btrfs_fs_info { struct btrfs_workqueue *endio_freespace_worker; struct btrfs_workqueue *caching_workers; struct btrfs_workqueue *readahead_workers; +#ifdef MY_ABC_HERE + struct btrfs_workqueue *syno_multiple_writeback_workers; +#endif /* MY_ABC_HERE */ /* * fixup workers take dirty pages that didn't properly go through @@ -826,6 +1037,11 @@ struct btrfs_fs_info { /* auto defrag inodes go here */ spinlock_t defrag_inodes_lock; struct rb_root defrag_inodes; +#ifdef MY_ABC_HERE + /* list 0 for reclaim space, list 1 for original defrag */ + struct list_head defrag_inodes_list[2]; + int reclaim_space_entry_count; +#endif /* MY_ABC_HERE */ atomic_t defrag_running; /* Used to protect avail_{data, metadata, system}_alloc_bits */ @@ -847,7 +1063,10 @@ struct btrfs_fs_info { struct btrfs_balance_control *balance_ctl; wait_queue_head_t balance_wait_q; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ u32 data_chunk_allocations; +#endif /* MY_ABC_HERE */ u32 metadata_ratio; void *bdev_holder; @@ -928,6 +1147,10 @@ struct btrfs_fs_info { /* device replace state */ struct btrfs_dev_replace dev_replace; +#ifdef MY_ABC_HERE + unsigned int snapshot_cleaner; // 1 -> cleaner will drop snapshot, 0 -> cleaner skip drop snapshot +#endif /* MY_ABC_HERE */ + struct semaphore uuid_tree_rescan_sem; /* Used to reclaim the metadata space in the background. */ @@ -972,8 +1195,263 @@ struct btrfs_fs_info { spinlock_t eb_leak_lock; struct list_head allocated_ebs; #endif + +#ifdef MY_ABC_HERE + struct { + bool root_tree_cleanup; + bool fs_tree_cleanup; + spinlock_t lock; + struct list_head roots; + bool enable; /* default:on */ + bool orphan_inode_delayed; /* default:off */ + } syno_orphan_cleanup; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct dedupe_info dedupe_info; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct mutex block_group_hint_tree_mutex; // Protect block group hint tree creation. + struct btrfs_root *block_group_hint_root; + struct btrfs_workqueue *bg_reada_workers; + atomic_t reada_block_group_threads; // Number of running threads; use atomic type since threads can modify it. +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + u64 log_tree_rsv_start; + u64 log_tree_rsv_size; + struct mutex log_tree_rsv_alloc; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_root *block_group_cache_root; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct mutex free_space_analyze_ioctl_lock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct work_struct async_metadata_cache_work; + atomic_t syno_metadata_block_group_update_count; + bool metadata_cache_enable; +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + spinlock_t mount_path_lock; + char *mount_path; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_t nr_extent_maps; + struct list_head extent_map_inode_list; + spinlock_t extent_map_inode_list_lock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic64_t block_group_cnt; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic64_t fsync_cnt; + atomic64_t fsync_full_commit_cnt; + unsigned int commit_time_debug_ms; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct kobject *free_space_tree_kobj; + atomic64_t free_space_tree_processed_block_group_cnt; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_t syno_writeback_thread_count; + int syno_writeback_thread_max; + spinlock_t syno_multiple_writeback_lock; + struct list_head syno_dirty_lru_inodes; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct dentry *btrfs_pervolume_debugfs_root_dentry; + + struct percpu_counter eb_hit; + struct percpu_counter eb_miss; + struct percpu_counter meta_write_pages; + struct percpu_counter data_write_pages; + struct percpu_counter delayed_meta_ref; + struct percpu_counter delayed_data_ref; + struct percpu_counter write_flush; + struct percpu_counter write_fua; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct btrfs_root *syno_usage_root; + struct btrfs_root *syno_extent_usage_root; + struct work_struct syno_usage_rescan_work; + struct work_struct syno_usage_fast_rescan_work; + struct work_struct syno_usage_full_rescan_work; + struct list_head syno_usage_pending_fast_rescan_roots; + struct list_head syno_usage_pending_full_rescan_roots; + pid_t syno_usage_fast_rescan_pid; + pid_t syno_usage_full_rescan_pid; + atomic_t syno_usage_pending_fast_rescan_count; + atomic_t syno_usage_pending_full_rescan_count; + spinlock_t syno_usage_fast_rescan_lock; + spinlock_t syno_usage_full_rescan_lock; + struct mutex syno_usage_ioctl_lock; + struct btrfs_syno_usage_status syno_usage_status; + spinlock_t syno_usage_lock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct kfifo cksumfailed_files; + spinlock_t cksumfailed_files_write_lock; + enum syno_data_correction_suppress_log_status correction_suppress_log; + bool correction_disable; + + struct rb_root correction_record; + spinlock_t correction_record_lock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* is user quota tracking in a consistent state? */ + u64 usrquota_flags; + u64 usrquota_compat_flags; + + /* holds configuration and tracking. Protected by usrgroup_lock */ + struct rb_root usrquota_tree; + spinlock_t usrquota_lock; + + /* + * Protect user change for quota operations. If a transaction is needed, + * it must be started before locking this lock. + */ + struct mutex usrquota_ioctl_lock; + + /* list of dirty usrquota to be written at next commit */ + struct list_head dirty_usrquota; + + /* protect usrquota_ro_roots */ + struct mutex usrquota_ro_roots_lock; + struct list_head usrquota_ro_roots; + + struct ulist *syno_quota_rescan_subvol_ulist; // Can be NULL. + struct syno_quota_rescan_ctx *syno_quota_rescan_ctx; // Can be NULL. + + // So btrfs_quota_enable() knows when to enable quota safely. + struct rw_semaphore inflight_reserve_lock; + /* + * We have quota reserve needs to be clear + * in __btrfs_qgroup_release_data(). + */ + bool need_clear_reserve; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct timespec64 locker_clock; + struct timespec64 locker_prev_raw_clock; + struct delayed_work locker_update_work; + time64_t locker_update_interval; /* seconds */ + spinlock_t locker_lock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct btrfs_workqueue *syno_cow_async_workers; + atomic_t syno_async_submit_nr; + u32 syno_async_submit_throttle; + wait_queue_head_t syno_async_submit_queue_wait; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic64_t syno_ordered_extent_nr; + u64 syno_max_ordered_queue_size; + wait_queue_head_t syno_ordered_queue_wait; + atomic64_t syno_ordered_extent_processed_nr; + u64 syno_ordered_extent_processed_bw; + u64 syno_ordered_extent_processed_stamp; + unsigned long syno_ordered_extent_processed_bw_time_stamp; /* last time updated */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct btrfs_workqueue *syno_cow_endio_workers; + struct btrfs_workqueue *syno_nocow_endio_workers; + struct btrfs_workqueue *syno_high_priority_endio_workers; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* Syno Feature Tree */ + struct btrfs_root *syno_feat_root; + struct mutex syno_feat_tree_ioctl_lock; + struct btrfs_syno_feat_tree_status syno_feat_tree_status; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct { + spinlock_t lock; + struct list_head pinned_meta_files; + u64 first_mapping_table_offset; + } syno_rbd; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct work_struct syno_async_data_flush_work; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct work_struct syno_async_metadata_reclaim_work; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct work_struct syno_async_metadata_flush_work; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_t syno_async_delayed_ref_count; + struct btrfs_workqueue *extent_workers; + spinlock_t syno_delayed_ref_throttle_lock; + struct list_head syno_delayed_ref_throttle_tickets; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct btrfs_block_rsv cleaner_block_rsv; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct { + atomic_t syno_allocator_refs; + wait_queue_head_t syno_allocator_wait; + atomic_t legacy_allocator_refs; + wait_queue_head_t legacy_allocator_wait; + struct btrfs_workqueue *caching_workers; + struct work_struct bg_prefetch_work; + bool bg_prefetch_running; + } syno_allocator; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct { + atomic64_t eb_disk_read; + atomic64_t search_key; + atomic64_t search_forward; + atomic64_t next_leaf; + } syno_meta_statistics; +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + struct { + unsigned long flags; + unsigned long dirty_thresh; + unsigned long dirty_background_thresh; + unsigned long dirty_limit_stamp; + } syno_perf_indicator; +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ }; +#ifdef MY_ABC_HERE +struct btrfs_delayed_ref_throttle_ticket { + u64 count; + struct list_head list; +}; +#endif /* MY_ABC_HERE */ + static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb) { return sb->s_fs_info; @@ -1029,10 +1507,14 @@ enum { BTRFS_ROOT_DEAD_RELOC_TREE, /* Mark dead root stored on device whose cleanup needs to be resumed */ BTRFS_ROOT_DEAD_TREE, - /* The root has a log tree. Used only for subvolume roots. */ + /* The root has a log tree. Used for subvolume roots and the tree root. */ BTRFS_ROOT_HAS_LOG_TREE, /* Qgroup flushing is in progress */ BTRFS_ROOT_QGROUP_FLUSHING, +#ifdef MY_ABC_HERE + /* Syno space usage is enabled on this root */ + BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, +#endif /* MY_ABC_HERE */ }; /* @@ -1176,6 +1658,10 @@ struct btrfs_root { * root_item_lock. */ int dedupe_in_progress; +#ifdef MY_ABC_HERE + u64 small_extent_size; + bool inline_dedupe; +#endif /* For exclusion of snapshot creation and nocow writes */ struct btrfs_drew_lock snapshot_lock; @@ -1203,8 +1689,66 @@ struct btrfs_root { #ifdef CONFIG_BTRFS_DEBUG struct list_head leak_list; #endif + +#ifdef MY_ABC_HERE + u8 locker_enabled; + enum locker_mode locker_mode; + enum locker_state locker_default_state; + time64_t locker_waittime; + time64_t locker_duration; + time64_t locker_clock_adjustment; + time64_t locker_update_time_floor; + + enum locker_state locker_state; + time64_t locker_period_begin; + time64_t locker_period_begin_sys; + time64_t locker_period_end; + time64_t locker_period_end_sys; + + spinlock_t locker_lock; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_syno_usage_root_status syno_usage_root_status; + unsigned long syno_usage_runtime_flags; + spinlock_t syno_usage_lock; /* protects the syno_usage_root_status [type,new_type,state,flags,num_bytes,fast_rescan_progress] */ + rwlock_t syno_usage_rwlock; /* protects the syno_usage_root_status [full_rescan_progress] */ + struct list_head syno_usage_rescan_list; + struct percpu_counter *syno_delalloc_bytes; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* + * Keep track of generation when read-only subvolume usrquota subtree loaded + */ + struct list_head usrquota_ro_root; + u64 usrquota_loaded_gen; + + struct rw_semaphore rescan_lock; + u64 rescan_inode; // inode number that we already scanned. + u64 rescan_end_inode; // Rescan to this inode. + bool invalid_quota; // Don't show quota with bad quota version. +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool has_usrquota_limit; + bool has_quota_limit; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct { + struct list_head root; /* protect with fs_info->syno_orphan_cleanup.lock */ + int cleanup_in_progress; /* protect with root->root_item_lock */ + } syno_orphan_cleanup; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +/* Arguments for btrfs_punch_hole/btrfs_punch_hole_range */ +struct btrfs_punch_hole_args { + bool non_blocking; /* in */ + bool need_restart; /* out */ + loff_t next_offset; /* out */ +}; +#endif /* MY_ABC_HERE */ + /* * Structure that conveys information about an extent that is going to replace * all the extents in a file range. @@ -1233,6 +1777,77 @@ struct btrfs_replace_extent_info { * one. */ int insertions; + +#ifdef MY_ABC_HERE + // Used in syno quota v1. + u64 ram_bytes; + bool clone_range; + bool clone_account_quota; + bool clone_check_backref; +#endif /* MY_ABC_HERE */ +}; + +/* Arguments for btrfs_drop_extents() */ +struct btrfs_drop_extents_args { + /* Input parameters */ + + /* + * If NULL, btrfs_drop_extents() will allocate and free its own path. + * If 'replace_extent' is true, this must not be NULL. Also the path + * is always released except if 'replace_extent' is true and + * btrfs_drop_extents() sets 'extent_inserted' to true, in which case + * the path is kept locked. + */ + struct btrfs_path *path; + /* Start offset of the range to drop extents from */ + u64 start; + /* End (exclusive, last byte + 1) of the range to drop extents from */ + u64 end; + /* If true drop all the extent maps in the range */ + bool drop_cache; + /* + * If true it means we want to insert a new extent after dropping all + * the extents in the range. If this is true, the 'extent_item_size' + * parameter must be set as well and the 'extent_inserted' field will + * be set to true by btrfs_drop_extents() if it could insert the new + * extent. + * Note: when this is set to true the path must not be NULL. + */ + bool replace_extent; + /* + * Used if 'replace_extent' is true. Size of the file extent item to + * insert after dropping all existing extents in the range + */ + u32 extent_item_size; + + /* Output parameters */ + + /* + * Set to the minimum between the input parameter 'end' and the end + * (exclusive, last byte + 1) of the last dropped extent. This is always + * set even if btrfs_drop_extents() returns an error. + */ + u64 drop_end; + /* + * The number of allocated bytes found in the range. This can be smaller + * than the range's length when there are holes in the range. + */ + u64 bytes_found; + /* + * Only set if 'replace_extent' is true. Set to true if we were able + * to insert a replacement extent after dropping all extents in the + * range, otherwise set to false by btrfs_drop_extents(). + * Also, if btrfs_drop_extents() has set this to true it means it + * returned with the path locked, otherwise if it has set this to + * false it has returned with the path released. + */ + bool extent_inserted; + +#ifdef MY_ABC_HERE + u64 *first_punch_pos; + u64 *last_punch_pos; + int *partial_punch; +#endif /* MY_ABC_HERE */ }; struct btrfs_file_private { @@ -1271,11 +1886,71 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info) return BTRFS_MAX_ITEM_SIZE(info) - sizeof(struct btrfs_dir_item); } +#ifdef MY_ABC_HERE +#define ADVANCE 1 +#define ADVANCE_ONLY_NEXT -1 +#define ADVANCE_ONLY_UPNEXT 0 + +struct btrfs_snapshot_size_entry { + u64 root_id; + struct btrfs_root *root; + struct btrfs_path *path; + struct btrfs_key key; + struct rb_node node; + int root_level; + int level; + u64 snap_exclusive_size; +}; + +struct btrfs_snapshot_size_ctx { + u64 flags; + loff_t off; + struct file *out_filp; + struct ulist *snap_roots; + struct rb_root root; + unsigned long last_show; + u64 last_calc_size; + struct btrfs_snapshot_size_entry snaps[0]; +}; +#endif /* MY_ABC_HERE */ + /* * Flags for mount options. * * Note: don't forget to add new options to btrfs_show_options() */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_NODATASUM (1ULL << 0) +#define BTRFS_MOUNT_NODATACOW (1ULL << 1) +#define BTRFS_MOUNT_NOBARRIER (1ULL << 2) +#define BTRFS_MOUNT_SSD (1ULL << 3) +#define BTRFS_MOUNT_DEGRADED (1ULL << 4) +#define BTRFS_MOUNT_COMPRESS (1ULL << 5) +#define BTRFS_MOUNT_NOTREELOG (1ULL << 6) +#define BTRFS_MOUNT_FLUSHONCOMMIT (1ULL << 7) +#define BTRFS_MOUNT_SSD_SPREAD (1ULL << 8) +#define BTRFS_MOUNT_NOSSD (1ULL << 9) +#define BTRFS_MOUNT_DISCARD_SYNC (1ULL << 10) +#define BTRFS_MOUNT_FORCE_COMPRESS (1ULL << 11) +#define BTRFS_MOUNT_SPACE_CACHE (1ULL << 12) +#define BTRFS_MOUNT_CLEAR_CACHE (1ULL << 13) +#define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1ULL << 14) +#define BTRFS_MOUNT_ENOSPC_DEBUG (1ULL << 15) +#define BTRFS_MOUNT_AUTO_DEFRAG (1ULL << 16) +#define BTRFS_MOUNT_INODE_MAP_CACHE (1ULL << 17) +#define BTRFS_MOUNT_USEBACKUPROOT (1ULL << 18) +#define BTRFS_MOUNT_SKIP_BALANCE (1ULL << 19) +#define BTRFS_MOUNT_CHECK_INTEGRITY (1ULL << 20) +#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1ULL << 21) +#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1ULL << 22) +#define BTRFS_MOUNT_RESCAN_UUID_TREE (1ULL << 23) +#define BTRFS_MOUNT_FRAGMENT_DATA (1ULL << 24) +#define BTRFS_MOUNT_FRAGMENT_METADATA (1ULL << 25) +#define BTRFS_MOUNT_FREE_SPACE_TREE (1ULL << 26) +#define BTRFS_MOUNT_NOLOGREPLAY (1ULL << 27) +#define BTRFS_MOUNT_REF_VERIFY (1ULL << 28) +#define BTRFS_MOUNT_DISCARD_ASYNC (1ULL << 29) +#else /* MY_ABC_HERE */ #define BTRFS_MOUNT_NODATASUM (1 << 0) #define BTRFS_MOUNT_NODATACOW (1 << 1) #define BTRFS_MOUNT_NOBARRIER (1 << 2) @@ -1306,9 +1981,42 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info) #define BTRFS_MOUNT_NOLOGREPLAY (1 << 27) #define BTRFS_MOUNT_REF_VERIFY (1 << 28) #define BTRFS_MOUNT_DISCARD_ASYNC (1 << 29) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_SYNO_ALLOCATOR (1ULL << 55) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_SKIP_CLEANER (1ULL << 56) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_DROP_LOG_TREE (1ULL << 57) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_NO_BLOCK_GROUP (1ULL << 58) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_NO_QUOTA_TREE (1ULL << 59) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_BLOCK_GROUP_CACHE_TREE (1ULL << 60) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_BLOCK_GROUP_HINT_TREE (1ULL << 61) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_SYNO_ACL (1ULL << 62) +#endif /* MY_ABC_HERE*/ +#ifdef MY_ABC_HERE +#define BTRFS_MOUNT_AUTO_RECLAIM_SPACE (1ULL << 63) +#endif /*MY_ABC_HERE */ #define BTRFS_DEFAULT_COMMIT_INTERVAL (30) +#ifdef MY_ABC_HERE +#define BTRFS_DEFAULT_MAX_INLINE (512) +#else /* MY_ABC_HERE */ #define BTRFS_DEFAULT_MAX_INLINE (2048) +#endif /* MY_ABC_HERE */ #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) @@ -1388,7 +2096,12 @@ do { \ #define BTRFS_INODE_NOATIME (1 << 9) #define BTRFS_INODE_DIRSYNC (1 << 10) #define BTRFS_INODE_COMPRESS (1 << 11) - +#ifdef MY_ABC_HERE +#define BTRFS_INODE_NODEDUPE (1 << 29) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_INODE_UQ_REF_USED (1 << 30) +#endif /* MY_ABC_HERE */ #define BTRFS_INODE_ROOT_ITEM_INIT (1 << 31) #define BTRFS_INODE_FLAG_MASK \ @@ -1686,6 +2399,9 @@ BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); +#ifdef MY_ABC_HERE +BTRFS_SETGET_FUNCS(inode_syno_uq_rfer_used, struct btrfs_inode_item, syno_uq_rfer_used, 64); +#endif /* MY_ABC_HERE */ BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item, @@ -1703,10 +2419,25 @@ BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32); BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32); BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64); +#ifdef MY_ABC_HERE +BTRFS_SETGET_STACK_FUNCS(stack_inode_syno_uq_rfer_used, struct btrfs_inode_item, syno_uq_rfer_used, 64); +#endif /* MY_ABC_HERE */ BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64); BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32); +#ifdef MY_ABC_HERE +BTRFS_SETGET_FUNCS(syno_feat_tree_status_version, struct btrfs_syno_feat_tree_status_item, version, 64); +BTRFS_SETGET_FUNCS(syno_feat_tree_status_status, struct btrfs_syno_feat_tree_status_item, status, 64); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +BTRFS_SETGET_FUNCS(syno_rbd_meta_file_subvol_record_inode_cnt, + struct btrfs_rbd_meta_file_subvol_record_item, + inode_cnt, 32); +BTRFS_SETGET_FUNCS(syno_rbd_meta_file_inode_record_generation, + struct btrfs_rbd_meta_file_inode_record_item, + generation, 64); +#endif /* MY_ABC_HERE */ /* struct btrfs_dev_extent */ BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, @@ -1768,6 +2499,86 @@ static inline u32 btrfs_extent_inline_ref_size(int type) return 0; } +#ifdef MY_ABC_HERE +BTRFS_SETGET_FUNCS(syno_usage_status_version, struct btrfs_syno_usage_status_item, version, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_state, struct btrfs_syno_usage_status_item, state, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_flags, struct btrfs_syno_usage_status_item, flags, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_generation, struct btrfs_syno_usage_status_item, generation, 64); +static inline void btrfs_syno_usage_status_extent_rescan_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_status_item *item, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, item, struct btrfs_syno_usage_status_item, extent_rescan_progress, key); +} + +static inline void btrfs_set_syno_usage_status_extent_rescan_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_status_item *item, + struct btrfs_disk_key *key) +{ + write_eb_member(eb, item, struct btrfs_syno_usage_status_item, extent_rescan_progress, key); +} +BTRFS_SETGET_FUNCS(syno_usage_status_cur_full_rescan_size, struct btrfs_syno_usage_status_item, cur_full_rescan_size, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_total_full_rescan_size, struct btrfs_syno_usage_status_item, total_full_rescan_size, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_extent_tree_cur_rescan_size, struct btrfs_syno_usage_status_item, extent_tree_cur_rescan_size, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_extent_tree_total_rescan_size, struct btrfs_syno_usage_status_item, extent_tree_total_rescan_size, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_total_syno_extent_tree_items, struct btrfs_syno_usage_status_item, total_syno_extent_tree_items, 64); +BTRFS_SETGET_FUNCS(syno_usage_status_total_syno_subvol_usage_items, struct btrfs_syno_usage_status_item, total_syno_subvol_usage_items, 64); + +BTRFS_SETGET_FUNCS(syno_usage_global_type_num_bytes, struct btrfs_syno_usage_global_type_item, num_bytes, 64); + +BTRFS_SETGET_FUNCS(syno_usage_root_status_type, struct btrfs_syno_usage_root_status_item, type, 8); +BTRFS_SETGET_FUNCS(syno_usage_root_status_new_type, struct btrfs_syno_usage_root_status_item, new_type, 8); +BTRFS_SETGET_FUNCS(syno_usage_root_status_state, struct btrfs_syno_usage_root_status_item, state, 64); +BTRFS_SETGET_FUNCS(syno_usage_root_status_flags, struct btrfs_syno_usage_root_status_item, flags, 64); +BTRFS_SETGET_FUNCS(syno_usage_root_status_num_bytes, struct btrfs_syno_usage_root_status_item, num_bytes, 64); +static inline void btrfs_syno_usage_root_status_drop_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_root_status_item *item, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, item, struct btrfs_syno_usage_root_status_item, drop_progress, key); +} +static inline void btrfs_set_syno_usage_root_status_drop_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_root_status_item *item, + struct btrfs_disk_key *key) +{ + write_eb_member(eb, item, struct btrfs_syno_usage_root_status_item, drop_progress, key); +} +static inline void btrfs_syno_usage_root_status_fast_rescan_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_root_status_item *item, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, item, struct btrfs_syno_usage_root_status_item, fast_rescan_progress, key); +} +static inline void btrfs_set_syno_usage_root_status_fast_rescan_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_root_status_item *item, + struct btrfs_disk_key *key) +{ + write_eb_member(eb, item, struct btrfs_syno_usage_root_status_item, fast_rescan_progress, key); +} +static inline void btrfs_syno_usage_root_status_full_rescan_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_root_status_item *item, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, item, struct btrfs_syno_usage_root_status_item, full_rescan_progress, key); +} +static inline void btrfs_set_syno_usage_root_status_full_rescan_progress_key(struct extent_buffer *eb, + struct btrfs_syno_usage_root_status_item *item, + struct btrfs_disk_key *key) +{ + write_eb_member(eb, item, struct btrfs_syno_usage_root_status_item, full_rescan_progress, key); +} +BTRFS_SETGET_FUNCS(syno_usage_root_status_cur_full_rescan_size, struct btrfs_syno_usage_root_status_item, cur_full_rescan_size, 64); +BTRFS_SETGET_FUNCS(syno_usage_root_status_total_full_rescan_size, struct btrfs_syno_usage_root_status_item, total_full_rescan_size, 64); +BTRFS_SETGET_FUNCS(syno_usage_root_status_total_syno_subvol_usage_items, struct btrfs_syno_usage_root_status_item, total_syno_subvol_usage_items, 64); + +BTRFS_SETGET_FUNCS(syno_extent_usage_type, struct btrfs_syno_extent_usage_item, type, 8); +BTRFS_SETGET_FUNCS(syno_extent_usage_inline_ref_type, struct btrfs_syno_extent_usage_inline_ref, type, 8); +BTRFS_SETGET_FUNCS(syno_extent_usage_inline_ref_count, struct btrfs_syno_extent_usage_inline_ref, count, 32); + +BTRFS_SETGET_FUNCS(syno_subvol_usage_ref_count, struct btrfs_syno_subvol_usage_item, refs, 32); +BTRFS_SETGET_FUNCS(syno_subvol_usage_num_bytes, struct btrfs_syno_subvol_usage_item, num_bytes, 32); +#endif /* MY_ABC_HERE */ + /* struct btrfs_node */ BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); @@ -2118,11 +2929,66 @@ static inline bool btrfs_root_readonly(const struct btrfs_root *root) return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0; } + +#ifdef MY_ABC_HERE +static inline bool btrfs_root_has_usrquota_limit(const struct btrfs_root *root) +{ + return READ_ONCE(root->has_usrquota_limit); +} + +static inline void btrfs_root_set_has_usrquota_limit(struct btrfs_root *root, bool has_limit) +{ + if (btrfs_root_has_usrquota_limit(root) != has_limit) + WRITE_ONCE(root->has_usrquota_limit, has_limit); +} +static inline bool btrfs_root_has_quota_limit(const struct btrfs_root *root) +{ + return READ_ONCE(root->has_quota_limit); +} + +static inline void btrfs_root_set_has_quota_limit(struct btrfs_root *root, bool has_limit) +{ + if (btrfs_root_has_quota_limit(root) != has_limit) + WRITE_ONCE(root->has_quota_limit, has_limit); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline bool btrfs_root_hide(const struct btrfs_root *root) +{ + return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_HIDE)) != 0; +} +#endif /* MY_ABC_HERE */ + static inline bool btrfs_root_dead(const struct btrfs_root *root) { return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0; } +#ifdef MY_ABC_HERE +#define BTRFS_USRQUOTA_DELAYED_REF_SCAN ((unsigned long)-2) + +static inline bool btrfs_usrquota_compat_inode_quota(struct btrfs_fs_info *fs_info) +{ + return fs_info->usrquota_compat_flags & BTRFS_USRQUOTA_COMPAT_FLAG_INODE_QUOTA; +} + +static inline bool btrfs_root_noload_usrquota(struct btrfs_root *root) +{ + return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_NOLOAD_USRQUOTA)) != 0; +} + +static inline bool btrfs_root_disable_quota(const struct btrfs_root *root) +{ + return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DISABLE_QUOTA)) != 0; +} + +static inline bool btrfs_root_cmpr_ratio(struct btrfs_root *root) +{ + return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_CMPR_RATIO)) != 0; +} +#endif /* MY_ABC_HERE */ + /* struct btrfs_root_backup */ BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, tree_root, 64); @@ -2262,6 +3128,14 @@ BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64); BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block, generation, 64); +#ifdef MY_ABC_HERE +BTRFS_SETGET_STACK_FUNCS(super_syno_generation, struct btrfs_super_block, + syno_generation, 64); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +BTRFS_SETGET_STACK_FUNCS(super_syno_log_tree_rsv, struct btrfs_super_block, + log_tree_rsv, 64); +#endif /* MY_ABC_HERE */ BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64); BTRFS_SETGET_STACK_FUNCS(super_sys_array_size, struct btrfs_super_block, sys_chunk_array_size, 32); @@ -2306,6 +3180,20 @@ BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64); BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block, uuid_tree_generation, 64); +#ifdef MY_ABC_HERE +BTRFS_SETGET_STACK_FUNCS(super_syno_capability_flags, struct btrfs_super_block, + syno_capability_flags, 64); +BTRFS_SETGET_STACK_FUNCS(super_syno_capability_generation, struct btrfs_super_block, + syno_capability_generation, 64); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +BTRFS_SETGET_STACK_FUNCS(super_syno_rbd_first_mapping_table_offset, struct btrfs_super_block, + syno_rbd_first_mapping_table_offset, 64); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +BTRFS_SETGET_STACK_FUNCS(super_syno_locker_clock, struct btrfs_super_block, + syno_locker_clock, 64); +#endif /* MY_ABC_HERE */ int btrfs_super_csum_size(const struct btrfs_super_block *s); const char *btrfs_super_csum_name(u16 csum_type); @@ -2373,8 +3261,15 @@ BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item, compression, 8); BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, encryption, 8); +#ifdef MY_ABC_HERE +BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, + other_encoding, 8); +BTRFS_SETGET_FUNCS(file_extent_syno_flag, struct btrfs_file_extent_item, + syno_flag, 8); +#else /* MY_ABC_HERE */ BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, other_encoding, 16); +#endif /* MY_ABC_HERE */ /* * this returns the number of bytes used by the item on disk, minus the @@ -2430,6 +3325,51 @@ BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item, rsv_rfer, 64); BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item, rsv_excl, 64); +#ifdef MY_ABC_HERE +BTRFS_SETGET_FUNCS(qgroup_limit_soft_rfer, struct btrfs_qgroup_limit_item, + rsv_rfer, 64); +BTRFS_SETGET_FUNCS(qgroup_limit_soft_excl, struct btrfs_qgroup_limit_item, + rsv_excl, 64); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* btrfs_syno_quota_rescan_item */ +BTRFS_SETGET_FUNCS(syno_quota_rescan_flags, struct btrfs_syno_quota_rescan_item, + flags, 64); +BTRFS_SETGET_FUNCS(syno_quota_rescan_version, struct btrfs_syno_quota_rescan_item, + version, 64); +BTRFS_SETGET_FUNCS(syno_quota_rescan_generation, struct btrfs_syno_quota_rescan_item, + generation, 64); +BTRFS_SETGET_FUNCS(syno_quota_rescan_inode, struct btrfs_syno_quota_rescan_item, + rescan_inode, 64); +BTRFS_SETGET_FUNCS(syno_quota_rescan_end_inode, struct btrfs_syno_quota_rescan_item, + end_inode, 64); +BTRFS_SETGET_FUNCS(syno_quota_rescan_tree_size, struct btrfs_syno_quota_rescan_item, + tree_size, 64); +BTRFS_SETGET_FUNCS(syno_quota_rescan_next_root, struct btrfs_syno_quota_rescan_item, + next_root, 64); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* btrfs_usrquota_status_item */ +BTRFS_SETGET_FUNCS(usrquota_status_version, struct btrfs_usrquota_status_item, version, 64); +BTRFS_SETGET_FUNCS(usrquota_status_generation, struct btrfs_usrquota_status_item, generation, 64); +BTRFS_SETGET_FUNCS(usrquota_status_flags, struct btrfs_usrquota_status_item, flags, 64); +BTRFS_SETGET_FUNCS(usrquota_status_rescan_rootid, struct btrfs_usrquota_status_item, rescan_rootid, 64); +BTRFS_SETGET_FUNCS(usrquota_status_rescan_objectid, struct btrfs_usrquota_status_item, rescan_objectid, 64); +/* btrfs_usrquota_compat_item */ +BTRFS_SETGET_FUNCS(usrquota_compat_generation, struct btrfs_usrquota_compat_item, generation, 64); +BTRFS_SETGET_FUNCS(usrquota_compat_flags, struct btrfs_usrquota_compat_item, flags, 64); +/* btrfs_usrquota_root_item */ +BTRFS_SETGET_FUNCS(usrquota_root_info_item_cnt, struct btrfs_usrquota_root_item, info_item_cnt, 64); +BTRFS_SETGET_FUNCS(usrquota_root_limit_item_cnt, struct btrfs_usrquota_root_item, limit_item_cnt, 64); +/* btrfs_usrquota_info_item */ +BTRFS_SETGET_FUNCS(usrquota_info_generation, struct btrfs_usrquota_info_item, generation, 64); +BTRFS_SETGET_FUNCS(usrquota_info_rfer_used, struct btrfs_usrquota_info_item, rfer_used, 64); +/* btrfs_usrquota_limit_item */ +BTRFS_SETGET_FUNCS(usrquota_limit_rfer_soft, struct btrfs_usrquota_limit_item, rfer_soft, 64); +BTRFS_SETGET_FUNCS(usrquota_limit_rfer_hard, struct btrfs_usrquota_limit_item, rfer_hard, 64); +#endif /* MY_ABC_HERE */ /* btrfs_dev_replace_item */ BTRFS_SETGET_FUNCS(dev_replace_src_devid, @@ -2498,6 +3438,25 @@ static inline u64 btrfs_name_hash(const char *name, int len) return crc32c((u32)~1, name, len); } +#ifdef MY_ABC_HERE +static inline int btrfs_upper_name_hash(const char *name, int len, u32 *hash) +{ + /* + * hash_buf need to add 1 byte for syno_utf8_toupper, + * because it will append 0 to last byte. + */ + char hash_buf[BTRFS_NAME_LEN+1]; + unsigned int upperlen; + + if (len > BTRFS_NAME_LEN) + return -ENAMETOOLONG; + + upperlen = syno_utf8_toupper(hash_buf, name, BTRFS_NAME_LEN, len, NULL); + *hash = crc32c((u32)~1, hash_buf, upperlen); + return 0; +} +#endif /* MY_ABC_HERE */ + /* * Figure the key offset of an extended inode ref */ @@ -2551,8 +3510,19 @@ static inline u64 btrfs_calc_metadata_size(struct btrfs_fs_info *fs_info, int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info, u64 start, u64 num_bytes); void btrfs_free_excluded_extents(struct btrfs_block_group *cache); +#ifdef MY_ABC_HERE +int btrfs_run_delayed_refs_and_get_processed(struct btrfs_trans_handle *trans, + unsigned long count, + unsigned long *processed_count); +static inline int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, + unsigned long count) +{ + return btrfs_run_delayed_refs_and_get_processed(trans, count, NULL); +} +#else /* MY_ABC_HERE */ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, unsigned long count); +#endif /* MY_ABC_HERE */ void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_delayed_ref_head *head); @@ -2581,10 +3551,21 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 owner, u64 offset, u64 ram_bytes, - struct btrfs_key *ins); + struct btrfs_key *ins +#ifdef MY_ABC_HERE + , int syno_usage +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , struct inode *inode +#endif /* MY_ABC_HERE */ + ); int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, u64 root_objectid, u64 owner, u64 offset, - struct btrfs_key *ins); + struct btrfs_key *ins +#ifdef MY_ABC_HERE + , struct inode *inode +#endif /* MY_ABC_HERE */ + ); int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes, u64 min_alloc_size, u64 empty_size, u64 hint_byte, struct btrfs_key *ins, int is_data, int delalloc); @@ -2595,6 +3576,12 @@ int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, struct extent_buffer *eb, u64 flags, int level, int is_data); +#ifdef MY_ABC_HERE +int btrfs_set_disk_extent_flags_no_eb(struct btrfs_trans_handle *trans, + u64 start, u64 len, u64 flags, + int level, int is_data); +#endif /* MY_ABC_HERE */ + int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref); int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info, @@ -2678,8 +3665,16 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, u64 start, u64 end); int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, - u64 num_bytes, u64 *actual_bytes); -int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range); + u64 num_bytes, u64 *actual_bytes +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ); +int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ); int btrfs_init_space_info(struct btrfs_fs_info *fs_info); int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans, @@ -2688,6 +3683,10 @@ int btrfs_start_write_no_snapshotting(struct btrfs_root *root); void btrfs_end_write_no_snapshotting(struct btrfs_root *root); void btrfs_wait_for_snapshot_creation(struct btrfs_root *root); +#ifdef MY_ABC_HERE +void btrfs_init_syno_allocator_bg_prefetch_work(struct work_struct *work); +#endif /* MY_ABC_HERE */ + /* ctree.c */ int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key, int *slot); @@ -2868,7 +3867,11 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info); /* dir-item.c */ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, - const char *name, int name_len); + const char *name, int name_len +#ifdef MY_ABC_HERE + , int check_dir_item +#endif /* MY_ABC_HERE */ + ); int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, int name_len, struct btrfs_inode *dir, struct btrfs_key *location, u8 type, u64 index); @@ -2949,6 +3952,33 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 len); blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u64 offset, u8 *dst); +#ifdef MY_ABC_HERE +int btrfs_lookup_file_extent_by_file_offset(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + u64 inode_num, u64 file_offset, + int mod); +int delayed_backref_count(struct btrfs_fs_info *fs_info, u64 bytenr); +int get_extent_item_list(struct inode *inode, u64 offset, u64 len, + struct ulist *extent_item_list); +int extent_same_release_size_accounting(struct ulist *dst_extent_item, + struct btrfs_root *root, + u64 *release_size); +int btrfs_search_next_file_extent(struct btrfs_key *key, + struct btrfs_root *root, + struct btrfs_path *path); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int btrfs_file_extent_deduped_clear(struct btrfs_trans_handle *trans, + struct btrfs_inode *inode, u64 file_offset); +int btrfs_file_extent_deduped_set_range(struct inode *inode, u64 offset, + u64 len, bool on_off); +int inline_dedupe_search(struct inode *inode, u64 start, u64 len, + u64 *disk_bytenr, u64 *disk_num_bytes, u64 *disk_off, + u64 *match_off, u64 *match_len); +int insert_dedupe_file_extent(struct btrfs_trans_handle *trans, struct inode *inode, + u64 offset, u64 len, u64 disk_bytenr, u64 disk_num_bytes, u64 disk_offset); +#endif /* MY_ABC_HERE */ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, @@ -2989,9 +4019,20 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, u64 *orig_start, u64 *orig_block_len, u64 *ram_bytes, bool strict); +#ifdef MY_ABC_HERE +int btrfs_quota_query(struct file *file, u64 *used, u64 *reserved, u64 *limit); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int btrfs_syno_space_usage(struct file *file, struct syno_space_usage_info *info); +#endif /* MY_ABC_HERE */ + void __btrfs_del_delalloc_inode(struct btrfs_root *root, struct btrfs_inode *inode); -struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry); +struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ); int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index); int btrfs_unlink_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -3008,6 +4049,9 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, struct inode *inode, u64 new_size, u32 min_type); +#ifdef MY_ABC_HERE +void syno_writeback_balance_dirty_pages(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ int btrfs_start_delalloc_snapshot(struct btrfs_root *root); int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr, bool in_reclaim_context); @@ -3021,7 +4065,11 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state, unsigned *bits); void btrfs_clear_delalloc_extent(struct inode *inode, - struct extent_state *state, unsigned *bits); + struct extent_state *state, unsigned *bits +#ifdef MY_ABC_HERE + , u64 *add_bytes +#endif /* MY_ABC_HERE */ + ); void btrfs_merge_delalloc_extent(struct inode *inode, struct extent_state *new, struct extent_state *other); void btrfs_split_delalloc_extent(struct inode *inode, @@ -3042,6 +4090,13 @@ void __cold btrfs_destroy_cachep(void); struct inode *btrfs_iget_path(struct super_block *s, u64 ino, struct btrfs_root *root, struct btrfs_path *path); struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root); +#ifdef MY_ABC_HERE +struct inode *btrfs_get_regular_file_inode(struct super_block *sb, + u64 root_objectid, u64 objectid); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +bool btrfs_test_inode_nowait(struct super_block *s, u64 ino, struct btrfs_root *root); +#endif /* MY_ABC_HERE */ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, struct page *page, size_t pg_offset, u64 start, u64 end); @@ -3073,6 +4128,14 @@ void btrfs_writepage_endio_finish_ordered(struct page *page, u64 start, extern const struct dentry_operations btrfs_dentry_operations; ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter); +void btrfs_update_inode_bytes(struct btrfs_inode *inode, + const u64 add_bytes, + const u64 del_bytes); + +#ifdef MY_ABC_HERE +void block_dump___btrfs_update_inode(struct inode *inode); +#endif /* MY_ABC_HERE */ + /* ioctl.c */ long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); @@ -3089,32 +4152,43 @@ void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info, bool btrfs_exclop_start(struct btrfs_fs_info *fs_info, enum btrfs_exclusive_operation type); void btrfs_exclop_finish(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +int cluster_pages_for_defrag(struct inode *inode, + struct page **pages, + unsigned long start_index, + unsigned long num_pages); +#endif /* MY_ABC_HERE */ /* file.c */ int __init btrfs_auto_defrag_init(void); void __cold btrfs_auto_defrag_exit(void); +#ifdef MY_ABC_HERE +#define BTRFS_INODE_DEFRAG_NORMAL (1 << 0) +#define BTRFS_INODE_DEFRAG_SYNO (1 << 1) +#endif /* MY_ABC_HERE */ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, - struct btrfs_inode *inode); + struct btrfs_inode *inode +#ifdef MY_ABC_HERE + , u64 start, u64 end, int defrag_type +#endif /* MY_ABC_HERE */ + ); int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info); int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); void btrfs_drop_extent_cache(struct btrfs_inode *inode, u64 start, u64 end, int skip_pinned); extern const struct file_operations btrfs_file_operations; -int __btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_inode *inode, - struct btrfs_path *path, u64 start, u64 end, - u64 *drop_end, int drop_cache, - int replace_extent, - u32 extent_item_size, - int *key_inserted); int btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, u64 start, - u64 end, int drop_cache); + struct btrfs_root *root, struct btrfs_inode *inode, + struct btrfs_drop_extents_args *args); int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, const u64 start, const u64 end, struct btrfs_replace_extent_info *extent_info, - struct btrfs_trans_handle **trans_out); + struct btrfs_trans_handle **trans_out +#ifdef MY_ABC_HERE + , struct btrfs_punch_hole_args *args +#endif /* MY_ABC_HERE */ + ); int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, u64 start, u64 end); int btrfs_release_file(struct inode *inode, struct file *file); @@ -3125,6 +4199,9 @@ int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end); int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos, size_t *write_bytes); void btrfs_check_nocow_unlock(struct btrfs_inode *inode); +#ifdef MY_ABC_HERE +void syno_ordered_extent_throttle(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ /* tree-defrag.c */ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, @@ -3137,6 +4214,38 @@ int btrfs_sync_fs(struct super_block *sb, int wait); char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info, u64 subvol_objectid); +#ifdef MY_ABC_HERE +/* syno-extent-usage.c */ +int btrfs_syno_usage_root_status_lookup(struct btrfs_fs_info *fs_info, u64 root_objectid, struct btrfs_syno_usage_root_status *ret_item); +int btrfs_syno_usage_root_status_remove(struct btrfs_trans_handle *trans, u64 root_objectid); +void btrfs_syno_usage_root_status_init(struct btrfs_syno_usage_root_status *status, + struct btrfs_syno_usage_root_status *src, bool readonly, bool init); +int btrfs_syno_usage_root_status_update(struct btrfs_trans_handle *trans, + u64 root_objectid, struct btrfs_syno_usage_root_status *syno_usage_root_status); +int btrfs_syno_usage_global_type_update(struct btrfs_trans_handle *trans); +int btrfs_read_syno_usage_config(struct btrfs_fs_info *fs_info); +int btrfs_syno_extent_usage_add(struct btrfs_trans_handle *trans, + int want, u64 bytenr, u64 num_bytes, int refs_to_add); +int btrfs_syno_extent_usage_free(struct btrfs_trans_handle *trans, + int want, u64 bytenr, u64 num_bytes, int refs_to_drop, bool remove); +int btrfs_syno_usage_ref_check(struct btrfs_root *root, u64 owner, u64 offset); +int btrfs_syno_subvol_usage_add(struct btrfs_trans_handle *trans, + u64 root_objectid, u64 bytenr, u64 num_bytes, int refs_to_add); +int btrfs_syno_subvol_usage_free(struct btrfs_trans_handle *trans, + u64 root_objectid, u64 bytenr, u64 num_bytes, int refs_to_drop); + +int btrfs_syno_clear_subvol_usage_item_prepare(struct btrfs_root *root); +int btrfs_syno_clear_subvol_usage_item_doing(struct btrfs_root *root); +void btrfs_init_syno_usage_rescan_work(struct work_struct *work); +void btrfs_init_syno_usage_fast_rescan_work(struct work_struct *work); +void btrfs_init_syno_usage_full_rescan_work(struct work_struct *work); +void btrfs_syno_usage_rescan_resume(struct btrfs_fs_info *fs_info); +int btrfs_syno_usage_enable(struct btrfs_fs_info *fs_info); +int btrfs_syno_usage_disable(struct btrfs_fs_info *fs_info); +void btrfs_syno_usage_root_initialize(struct btrfs_root *subvol_root); +int btrfs_syno_usage_status_update(struct btrfs_trans_handle *trans); +#endif /* MY_ABC_HERE */ + static inline __printf(2, 3) __cold void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) { @@ -3498,6 +4607,134 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag) return !!(btrfs_super_compat_ro_flags(disk_super) & flag); } +#ifdef MY_ABC_HERE +#define btrfs_set_fs_compat(__fs_info, opt) \ + __btrfs_set_fs_compat((__fs_info), BTRFS_FEATURE_COMPAT_##opt, #opt) + +static inline void __btrfs_set_fs_compat(struct btrfs_fs_info *fs_info, + u64 flag, const char* name) +{ + struct btrfs_super_block *disk_super; + u64 features; + + disk_super = fs_info->super_copy; + features = btrfs_super_compat_flags(disk_super); + if (!(features & flag)) { + spin_lock(&fs_info->super_lock); + features = btrfs_super_compat_flags(disk_super); + if (!(features & flag)) { + features |= flag; + btrfs_set_super_compat_flags(disk_super, features); + btrfs_info(fs_info, "setting compat feature flag for %s (0x%llx)", name, flag); + } + spin_unlock(&fs_info->super_lock); + } +} + +#define btrfs_clear_fs_compat(__fs_info, opt) \ + __btrfs_clear_fs_compat((__fs_info), BTRFS_FEATURE_COMPAT_##opt, #opt) + +static inline void __btrfs_clear_fs_compat(struct btrfs_fs_info *fs_info, + u64 flag, const char* name) +{ + struct btrfs_super_block *disk_super; + u64 features; + + disk_super = fs_info->super_copy; + features = btrfs_super_compat_flags(disk_super); + if (features & flag) { + spin_lock(&fs_info->super_lock); + features = btrfs_super_compat_flags(disk_super); + if (features & flag) { + features &= ~flag; + btrfs_set_super_compat_flags(disk_super, features); + btrfs_info(fs_info, "clearing compat feature flag for %s (0x%llx)", name, flag); + } + spin_unlock(&fs_info->super_lock); + } +} + +#define btrfs_fs_compat(fs_info, opt) \ + __btrfs_fs_compat((fs_info), BTRFS_FEATURE_COMPAT_##opt) + +static inline int __btrfs_fs_compat(struct btrfs_fs_info *fs_info, u64 flag) +{ + struct btrfs_super_block *disk_super; + disk_super = fs_info->super_copy; + return !!(btrfs_super_compat_flags(disk_super) & flag); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define btrfs_set_fs_syno_capability(__fs_info, opt) \ + __btrfs_set_fs_syno_capability((__fs_info), \ + BTRFS_FEATURE_SYNO_CAPABILITY_##opt, #opt) + +static inline void __btrfs_set_fs_syno_capability( + struct btrfs_fs_info *fs_info, u64 flag, + const char *name) +{ + struct btrfs_super_block *disk_super; + u64 features; + + disk_super = fs_info->super_copy; + features = btrfs_super_syno_capability_flags(disk_super); + if (!(features & flag)) { + spin_lock(&fs_info->super_lock); + features = btrfs_super_syno_capability_flags(disk_super); + if (!(features & flag)) { + features |= flag; + btrfs_set_super_syno_capability_flags(disk_super, + features); + btrfs_info(fs_info, + "setting capability flag for %s (0x%llx)", + name, flag); + } + spin_unlock(&fs_info->super_lock); + } +} + +#define btrfs_clear_fs_syno_capability(__fs_info, opt) \ + __btrfs_clear_fs_syno_capability((__fs_info), \ + BTRFS_FEATURE_SYNO_CAPABILITY_##opt, #opt) + +static inline void __btrfs_clear_fs_syno_capability( + struct btrfs_fs_info *fs_info, u64 flag, + const char *name) +{ + struct btrfs_super_block *disk_super; + u64 features; + + disk_super = fs_info->super_copy; + features = btrfs_super_syno_capability_flags(disk_super); + if (features & flag) { + spin_lock(&fs_info->super_lock); + features = btrfs_super_syno_capability_flags(disk_super); + if (features & flag) { + features &= ~flag; + btrfs_set_super_syno_capability_flags(disk_super, + features); + btrfs_info(fs_info, + "clearing capability flag for %s (0x%llx)", + name, flag); + } + spin_unlock(&fs_info->super_lock); + } +} + +#define btrfs_fs_syno_capability(fs_info, opt) \ + __btrfs_fs_syno_capability((fs_info), \ + BTRFS_FEATURE_SYNO_CAPABILITY_##opt) + +static inline int __btrfs_fs_syno_capability( + struct btrfs_fs_info *fs_info, u64 flag) +{ + struct btrfs_super_block *disk_super; + disk_super = fs_info->super_copy; + return !!(btrfs_super_syno_capability_flags(disk_super) & flag); +} +#endif /* MY_ABC_HERE */ + /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL struct posix_acl *btrfs_get_acl(struct inode *inode, int type); @@ -3608,4 +4845,167 @@ static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info) } #endif +#ifdef MY_ABC_HERE +/* free-space-analyze.c */ +int btrfs_free_space_analyze(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_free_space_analyze_args *args); +int btrfs_free_space_analyze_full(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_free_space_analyze_args *args); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* snapshot-size-query.c */ +int btrfs_snapshot_size_query(struct file *file, + struct btrfs_ioctl_snapshot_size_query_args *snap_args); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void SynoAutoErrorFsBtrfsReport(const u8* fsid); +void SynoBtrfsMetaCorruptedReport(const u8* fsid, u64 start); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define btrfs_data_correction_print(fs_info, flag, fmt, args...) \ +do { \ + switch (flag) { \ + case DATA_CORRECTION_PRINT_ALL_LOG: \ + btrfs_warn(fs_info, fmt, ##args); \ + break; \ + case DATA_CORRECTION_RATE_LIMIT: \ + btrfs_warn_rl(fs_info, fmt, ##args); \ + break; \ + case DATA_CORRECTION_SUPPRESS_ALL: \ + break; \ + } \ +} while (0) + +#define btrfs_data_correction_print_in_rcu(fs_info, flag, fmt, args...) \ +do { \ + switch (flag) { \ + case DATA_CORRECTION_PRINT_ALL_LOG: \ + btrfs_warn_in_rcu(fs_info, fmt, ##args); \ + break; \ + case DATA_CORRECTION_RATE_LIMIT: \ + btrfs_warn_rl_in_rcu(fs_info, fmt, ##args); \ + break; \ + case DATA_CORRECTION_SUPPRESS_ALL: \ + break; \ + } \ +} while (0) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +enum syno_quota_account_type { + UPDATE_QUOTA, + UPDATE_QUOTA_FREE_RESERVED, // Free reserved in the same time. + ADD_QUOTA_RESCAN, // Used in rescan. +}; + +struct btrfs_quota_account_rec { + struct list_head list; + u64 ref_root; + u64 num_bytes; + u64 ram_bytes; + u64 reserved; + u64 uid; // Only used in I_FREEING or I_WILL_FREE case. + int sign; + struct inode *inode; +}; + +/* usrquota.c */ +int btrfs_usrquota_enable(struct btrfs_fs_info *fs_info, u64 cmd); +int btrfs_usrquota_disable(struct btrfs_fs_info *fs_info); +int btrfs_usrquota_unload(struct btrfs_fs_info *fs_info); +int btrfs_usrquota_remove_v1(struct btrfs_fs_info *fs_info); + +int usrquota_subtree_load(struct btrfs_fs_info *fs_info, u64 rootid); +void usrquota_subtree_unload(struct btrfs_fs_info *fs_info, u64 rootid); +int btrfs_read_usrquota_config(struct btrfs_fs_info *fs_info); +bool btrfs_check_usrquota_leak(struct btrfs_fs_info *fs_info); +void btrfs_free_usrquota_config(struct btrfs_fs_info *fs_info); + +int btrfs_usrquota_limit(struct btrfs_trans_handle *trans, + u64 root_id, u64 uid, u64 rfer_soft, u64 rfer_hard); +int btrfs_usrquota_clean(struct btrfs_trans_handle *trans, u64 uid); + +int btrfs_usrquota_syno_accounting(struct btrfs_inode *b_inode, + u64 add_bytes, u64 del_bytes, enum syno_quota_account_type type); +int btrfs_usrquota_syno_v1_accounting(struct btrfs_trans_handle *trans, + struct btrfs_quota_account_rec *record); +int btrfs_usrquota_syno_accounting_rescan(struct btrfs_root *root, u64 uid, u64 num_bytes); +int btrfs_run_usrquota(struct btrfs_trans_handle *trans); +int btrfs_usrquota_syno_reserve(struct btrfs_inode *b_inode, u64 num_bytes); +// Only used by qgroup_reserve_data(). Others should use btrfs_usrquota_syno_reserve(). +int usrquota_reserve(struct btrfs_inode *b_inode, u64 num_bytes, bool enforce); +void btrfs_usrquota_syno_free(struct btrfs_inode *b_inode, u64 num_bytes); +int btrfs_reset_usrquota_status(struct btrfs_trans_handle *trans); +int btrfs_syno_usrquota_transfer_limit(struct btrfs_root *root); +void btrfs_usrquota_zero_tracking(struct btrfs_fs_info *fs_info, u64 subvol_id); +int btrfs_usrquota_v1_transfer(struct inode *inode, kuid_t new_uid); +int btrfs_usrquota_transfer(struct inode *inode, kuid_t new_uid); +int btrfs_usrquota_calc_reserve_snap(struct btrfs_root *root, + u64 copy_limit_from, u64 *reserve_items); +int btrfs_usrquota_mksubvol(struct btrfs_trans_handle *trans, u64 objectid); +int btrfs_usrquota_mksnap(struct btrfs_trans_handle *trans, + u64 srcid, u64 objectid, + bool readonly, u64 copy_limit_from); +int btrfs_usrquota_delsnap(struct btrfs_trans_handle *trans, + struct btrfs_root *subvol_root); +int btrfs_usrquota_query(struct btrfs_root *root, + struct btrfs_ioctl_usrquota_query_args *uqa); +#endif /* CONFIG_SYNO_BTRFS_SYNO_SYNO_QUOTA */ + +#ifdef MY_ABC_HERE +/* struct btrfs_root_locker_item */ +BTRFS_SETGET_FUNCS(root_locker_enabled, struct btrfs_root_locker_item, enabled, 8); +BTRFS_SETGET_FUNCS(root_locker_mode, struct btrfs_root_locker_item, mode, 8); +BTRFS_SETGET_FUNCS(root_locker_default_state, struct btrfs_root_locker_item, default_state, 8); +BTRFS_SETGET_FUNCS(root_locker_waittime, struct btrfs_root_locker_item, waittime, 64); +BTRFS_SETGET_FUNCS(root_locker_duration, struct btrfs_root_locker_item, duration, 64); +BTRFS_SETGET_FUNCS(root_locker_clock_adjustment, struct btrfs_root_locker_item, clock_adjustment, 64); +BTRFS_SETGET_FUNCS(root_locker_update_time_floor, struct btrfs_root_locker_item, update_time_floor, 64); + +BTRFS_SETGET_FUNCS(root_locker_state, struct btrfs_root_locker_item, state, 8); +BTRFS_SETGET_FUNCS(root_locker_period_begin, struct btrfs_root_locker_item, period_begin, 64); +BTRFS_SETGET_FUNCS(root_locker_period_begin_sys, struct btrfs_root_locker_item, period_begin_sys, 64); +BTRFS_SETGET_FUNCS(root_locker_period_end, struct btrfs_root_locker_item, period_end, 64); +BTRFS_SETGET_FUNCS(root_locker_period_end_sys, struct btrfs_root_locker_item, period_end_sys, 64); + +/* syno-locker.c */ +struct timespec64 btrfs_syno_locker_fs_clock_get(struct btrfs_fs_info *fs_info); +void btrfs_syno_locker_update_work_fn(struct work_struct *work); +void btrfs_syno_locker_update_work_kick(struct btrfs_fs_info *fs_info); +bool btrfs_syno_locker_feature_is_support(void); +int btrfs_syno_locker_feature_disable(void); +int btrfs_syno_locker_disk_root_read(struct btrfs_root *root); +int btrfs_syno_locker_disk_root_delete(struct btrfs_trans_handle *trans, struct btrfs_root *root); +int btrfs_syno_locker_snapshot_clone(struct btrfs_trans_handle *trans, + struct btrfs_root *dest, struct btrfs_root *source); +int btrfs_syno_locker_may_destroy_subvol(struct btrfs_root *root); +int btrfs_syno_locker_may_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + bool reset); +int btrfs_syno_locker_disk_inode_update_trans(struct inode *inode); +int btrfs_syno_locker_disk_inode_read(struct inode *inode); +int btrfs_syno_locker_mode_get(struct inode *inode, enum locker_mode *mode); +int btrfs_syno_locker_state_get(struct inode *inode, enum locker_state *state); +int btrfs_syno_locker_state_set(struct inode *inode, enum locker_state state); +int btrfs_syno_locker_fillattr(struct inode *inode, struct kstat *stat); +int btrfs_syno_locker_period_end_set(struct inode *inode, struct timespec64 *time); +int btrfs_ioctl_syno_locker_get(struct file *file, struct btrfs_ioctl_syno_locker_args __user *argp); +int btrfs_ioctl_syno_locker_set(struct file *file, struct btrfs_ioctl_syno_locker_args __user *argp); +int btrfs_xattr_syno_set_locker(struct inode *inode, const void *buffer, size_t size); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void btrfs_check_usrquota_limit(struct btrfs_root *root); +void btrfs_check_quota_limit(struct btrfs_root *root); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int btrfs_add_swapfile_pin(struct inode *inode, void *ptr, + bool is_block_group); +void btrfs_free_swapfile_pins(struct inode *inode); +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c index bacee09b7bfd..d11de6de7831 100644 --- a/fs/btrfs/delalloc-space.c +++ b/fs/btrfs/delalloc-space.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include "ctree.h" @@ -225,8 +228,13 @@ static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free) qgroup_to_release); } +#ifdef MY_ABC_HERE +void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, + struct btrfs_inode *inode) +#else static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) +#endif /* MY_ABC_HERE */ { struct btrfs_block_rsv *block_rsv = &inode->block_rsv; u64 reserve_size = 0; @@ -250,6 +258,16 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, inode->csum_bytes); reserve_size += btrfs_calc_insert_metadata_size(fs_info, csum_leaves); + +#ifdef MY_ABC_HERE + if (outstanding_extents == 0 && atomic_read(&inode->syno_uq_refs) == 0) + clear_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, + &inode->runtime_flags); + if (test_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, + &inode->runtime_flags)) + reserve_size += btrfs_calc_metadata_size(fs_info, 1);; +#endif /* MY_ABC_HERE */ + /* * For qgroup rsv, the calculation is very simple: * account one nodesize for each outstanding extent @@ -292,6 +310,9 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes) unsigned nr_extents; enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL; int ret = 0; +#ifdef MY_ABC_HERE + bool usrquota_meta = false; +#endif /* MY_ABC_HERE */ /* * If we are a free space inode we need to not flush since we will be in @@ -329,9 +350,23 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes) ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true); if (ret) return ret; + +#ifdef MY_ABC_HERE + if (btrfs_usrquota_fast_chown_enable(&inode->vfs_inode) && + !test_and_set_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, + &inode->runtime_flags)) { + meta_reserve += btrfs_calc_metadata_size(fs_info, 1); + usrquota_meta = true; + } +#endif /* MY_ABC_HERE */ + ret = btrfs_reserve_metadata_bytes(root, block_rsv, meta_reserve, flush); if (ret) { btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve); +#ifdef MY_ABC_HERE + if (usrquota_meta) + clear_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, &inode->runtime_flags); +#endif /* MY_ABC_HERE */ return ret; } diff --git a/fs/btrfs/delalloc-space.h b/fs/btrfs/delalloc-space.h index 28bf5c3ef430..26e57baedefc 100644 --- a/fs/btrfs/delalloc-space.h +++ b/fs/btrfs/delalloc-space.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_DELALLOC_SPACE_H @@ -20,4 +23,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes, int btrfs_delalloc_reserve_space(struct btrfs_inode *inode, struct extent_changeset **reserved, u64 start, u64 len); +#ifdef MY_ABC_HERE +void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, + struct btrfs_inode *inode); +#endif /* MY_ABC_HERE */ #endif /* BTRFS_DELALLOC_SPACE_H */ diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 04422d929c23..5f09af613a95 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2011 Fujitsu. All rights reserved. @@ -655,6 +658,16 @@ static int btrfs_delayed_inode_reserve_metadata( return ret; } +#ifdef MY_ABC_HERE + if (src_rsv == &inode->block_rsv) { + spin_lock(&inode->lock); + if (test_and_clear_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, + &inode->runtime_flags)) + btrfs_calculate_inode_block_rsv_size(fs_info, inode); + spin_unlock(&inode->lock); + } +#endif /* MY_ABC_HERE */ + ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, true); if (!ret) { trace_btrfs_space_reservation(fs_info, "delayed_inode", @@ -1145,7 +1158,12 @@ __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, * Returns < 0 on error and returns with an aborted transaction with any * outstanding delayed items cleaned up. */ -static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr) +static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr +#ifdef MY_ABC_HERE + , unsigned long *processed_inodes + , unsigned long *processed_items +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_delayed_root *delayed_root; @@ -1154,6 +1172,10 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr) struct btrfs_block_rsv *block_rsv; int ret = 0; bool count = (nr > 0); +#ifdef MY_ABC_HERE + unsigned long inode_count = 0; + unsigned long item_count = 0; +#endif /* MY_ABC_HERE */ if (TRANS_ABORTED(trans)) return -EIO; @@ -1170,6 +1192,10 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr) curr_node = btrfs_first_delayed_node(delayed_root); while (curr_node && (!count || (count && nr--))) { +#ifdef MY_ABC_HERE + int orig_count = curr_node->count; + int curr_count = 0; +#endif /* MY_ABC_HERE */ ret = __btrfs_commit_inode_delayed_items(trans, path, curr_node); if (ret) { @@ -1178,6 +1204,13 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr) btrfs_abort_transaction(trans, ret); break; } +#ifdef MY_ABC_HERE + inode_count++; + curr_count = curr_node->count; + // It's just estimate the processed count, so we dont use lock. + item_count += (curr_count < orig_count) ? + (orig_count - curr_node->count) : 0; +#endif /* MY_ABC_HERE */ prev_node = curr_node; curr_node = btrfs_next_delayed_node(curr_node); @@ -1188,18 +1221,43 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr) btrfs_release_delayed_node(curr_node); btrfs_free_path(path); trans->block_rsv = block_rsv; +#ifdef MY_ABC_HERE + if (!ret && processed_inodes && processed_items) { + *processed_inodes = inode_count; + *processed_items = item_count; + } +#endif /* MY_ABC_HERE */ return ret; } +#ifdef MY_ABC_HERE +int btrfs_run_delayed_items_and_get_processed(struct btrfs_trans_handle *trans, + unsigned long *processed_inodes, + unsigned long *processed_items) +{ + return __btrfs_run_delayed_items(trans, -1, + processed_inodes, + processed_items); +} +#endif /* MY_ABC_HERE */ + int btrfs_run_delayed_items(struct btrfs_trans_handle *trans) { - return __btrfs_run_delayed_items(trans, -1); + return __btrfs_run_delayed_items(trans, -1 +#ifdef MY_ABC_HERE + , NULL, NULL +#endif /* MY_ABC_HERE */ + ); } int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, int nr) { - return __btrfs_run_delayed_items(trans, nr); + return __btrfs_run_delayed_items(trans, nr +#ifdef MY_ABC_HERE + , NULL, NULL +#endif /* MY_ABC_HERE */ + ); } int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, @@ -1772,6 +1830,10 @@ static void fill_stack_inode_item(struct btrfs_trans_handle *trans, BTRFS_I(inode)->i_otime.tv_sec); btrfs_set_stack_timespec_nsec(&inode_item->otime, BTRFS_I(inode)->i_otime.tv_nsec); + +#ifdef MY_ABC_HERE + btrfs_set_stack_inode_syno_uq_rfer_used(inode_item, BTRFS_I(inode)->uq_rfer_used); +#endif /* MY_ABC_HERE */ } int btrfs_fill_inode(struct inode *inode, u32 *rdev) @@ -1827,6 +1889,10 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev) inode->i_generation = BTRFS_I(inode)->generation; BTRFS_I(inode)->index_cnt = (u64)-1; +#ifdef MY_ABC_HERE + BTRFS_I(inode)->uq_rfer_used = btrfs_stack_inode_syno_uq_rfer_used(inode_item); +#endif /* MY_ABC_HERE */ + mutex_unlock(&delayed_node->mutex); btrfs_release_delayed_node(delayed_node); return 0; diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index ca96ef007d8f..59e06237c778 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2011 Fujitsu. All rights reserved. @@ -96,6 +99,11 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, int btrfs_inode_delayed_dir_index_count(struct btrfs_inode *inode); +#ifdef MY_ABC_HERE +int btrfs_run_delayed_items_and_get_processed(struct btrfs_trans_handle *trans, + unsigned long *processed_inodes, + unsigned long *processed_items); +#endif /* MY_ABC_HERE */ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans); int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, int nr); diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 30883b9a26d8..e2c3287de6c8 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2009 Oracle. All rights reserved. @@ -60,12 +63,23 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans) smp_mb(); avg_runtime = trans->fs_info->avg_delayed_ref_runtime; val = num_entries * avg_runtime; +#ifdef MY_ABC_HERE + if (val >= NSEC_PER_SEC) + return 1; + if (btrfs_check_space_for_delayed_refs(trans->fs_info)) + return 1; + if (val >= NSEC_PER_SEC / 2) + return 2; + return 0; + +#else /* MY_ABC_HERE */ if (val >= NSEC_PER_SEC) return 1; if (val >= NSEC_PER_SEC / 2) return 2; return btrfs_check_space_for_delayed_refs(trans->fs_info); +#endif /* MY_ABC_HERE */ } /** @@ -100,6 +114,27 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans) struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv; u64 num_bytes; +#ifdef MY_ABC_HERE + struct btrfs_delayed_ref_root *delayed_refs = &trans->transaction->delayed_refs; + u64 num_syno_usage, syno_usage_nr; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + num_bytes = 0; + spin_lock(&delayed_refs->lock); + num_syno_usage = atomic_read(&delayed_refs->num_syno_usage_entries) + delayed_refs->num_syno_usage_heads_ready; + if (delayed_refs->total_syno_usage_accounting < num_syno_usage) { + syno_usage_nr = num_syno_usage - delayed_refs->total_syno_usage_accounting; + num_bytes = btrfs_calc_insert_metadata_size(fs_info, syno_usage_nr); + delayed_refs->total_syno_usage_accounting += syno_usage_nr; + + spin_lock(&delayed_rsv->lock); + delayed_rsv->size += num_bytes; + delayed_rsv->full = 0; + spin_unlock(&delayed_rsv->lock); + } + spin_unlock(&delayed_refs->lock); +#endif /* MY_ABC_HERE */ if (!trans->delayed_ref_updates) return; @@ -242,6 +277,12 @@ static int comp_data_refs(struct btrfs_delayed_data_ref *ref1, if (ref1->parent > ref2->parent) return 1; } +#ifdef MY_ABC_HERE + if (ref1->syno_usage < ref2->syno_usage) + return -1; + if (ref1->syno_usage > ref2->syno_usage) + return 1; +#endif /* MY_ABC_HERE */ return 0; } @@ -421,9 +462,21 @@ static inline void drop_delayed_ref(struct btrfs_trans_handle *trans, RB_CLEAR_NODE(&ref->ref_node); if (!list_empty(&ref->add_list)) list_del(&ref->add_list); +#ifdef MY_ABC_HERE + if (!list_empty(&ref->syno_list)) + list_del(&ref->syno_list); + if (ref->type == BTRFS_EXTENT_DATA_REF_KEY || ref->type == BTRFS_SHARED_DATA_REF_KEY) { + struct btrfs_delayed_data_ref *data_ref = btrfs_delayed_node_to_data_ref(ref); + if (data_ref->syno_usage) + atomic_dec(&delayed_refs->num_syno_usage_entries); + } +#endif /* MY_ABC_HERE */ ref->in_tree = 0; btrfs_put_delayed_ref(ref); atomic_dec(&delayed_refs->num_entries); +#ifdef MY_ABC_HERE + syno_total_delayed_ref_updates_dec(trans); +#endif /* MY_ABC_HERE */ } static bool merge_ref(struct btrfs_trans_handle *trans, @@ -566,11 +619,64 @@ struct btrfs_delayed_ref_head *btrfs_select_ref_head( head->processing = 1; WARN_ON(delayed_refs->num_heads_ready == 0); delayed_refs->num_heads_ready--; +#ifdef MY_ABC_HERE + if (head->syno_usage) { + WARN_ON(delayed_refs->num_syno_usage_heads_ready == 0); + delayed_refs->num_syno_usage_heads_ready--; + } +#endif /* MY_ABC_HERE */ delayed_refs->run_delayed_start = head->bytenr + head->num_bytes; return head; } +#ifdef MY_ABC_HERE +// Copied from btrfs_select_ref_head() +struct btrfs_delayed_ref_head *btrfs_select_data_ref_head( + struct btrfs_delayed_ref_root *delayed_refs) +{ + struct btrfs_delayed_ref_head *head; + struct rb_node *node; + + head = find_ref_head(delayed_refs, delayed_refs->run_delayed_start, + true); + if (!head) + return NULL; + + // find_ref_head() may loop back. + if (head->bytenr < delayed_refs->run_delayed_start) + return NULL; + + while (!head->is_data) { + node = rb_next(&head->href_node); + if (!node) + return NULL; + head = rb_entry(node, struct btrfs_delayed_ref_head, + href_node); + } + + /* + * It should not happend. But if it does, we should reloop and wait on this + * head to complete. + */ + if (head->processing) + return ERR_PTR(-EAGAIN); + + head->processing = 1; + WARN_ON(delayed_refs->num_heads_ready == 0); + delayed_refs->num_heads_ready--; +#ifdef MY_ABC_HERE + if (head->syno_usage) { + WARN_ON(delayed_refs->num_syno_usage_heads_ready == 0); + delayed_refs->num_syno_usage_heads_ready--; + } +#endif /* MY_ABC_HERE */ + delayed_refs->run_delayed_start = head->bytenr + + head->num_bytes; + return head; +} +#endif /* MY_ABC_HERE */ + void btrfs_delete_ref_head(struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_delayed_ref_head *head) { @@ -583,6 +689,10 @@ void btrfs_delete_ref_head(struct btrfs_delayed_ref_root *delayed_refs, delayed_refs->num_heads--; if (head->processing == 0) delayed_refs->num_heads_ready--; +#ifdef MY_ABC_HERE + if (head->processing == 0 && head->syno_usage) + delayed_refs->num_syno_usage_heads_ready--; +#endif /* MY_ABC_HERE */ } /* @@ -594,7 +704,11 @@ void btrfs_delete_ref_head(struct btrfs_delayed_ref_root *delayed_refs, static int insert_delayed_ref(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_root *root, struct btrfs_delayed_ref_head *href, - struct btrfs_delayed_ref_node *ref) + struct btrfs_delayed_ref_node *ref +#ifdef MY_ABC_HERE + , u64 *free_reserved +#endif /* MY_ABC_HERE */ + ) { struct btrfs_delayed_ref_node *exist; int mod; @@ -630,14 +744,34 @@ static int insert_delayed_ref(struct btrfs_trans_handle *trans, exist->ref_mod += mod; /* remove existing tail if its ref_mod is zero */ - if (exist->ref_mod == 0) + if (exist->ref_mod == 0) { +#ifdef MY_ABC_HERE + if (href->is_data && free_reserved) { + struct btrfs_delayed_data_ref *data_ref = + btrfs_delayed_node_to_data_ref(exist); + + if (data_ref->reserved && !data_ref->skip_qgroup) + *free_reserved += data_ref->reserved; + } +#endif /* MY_ABC_HERE */ drop_delayed_ref(trans, root, href, exist); + } spin_unlock(&href->lock); return ret; inserted: if (ref->action == BTRFS_ADD_DELAYED_REF) list_add_tail(&ref->add_list, &href->ref_add_list); atomic_inc(&root->num_entries); +#ifdef MY_ABC_HERE + syno_total_delayed_ref_updates_inc(trans); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (ref->type == BTRFS_EXTENT_DATA_REF_KEY || ref->type == BTRFS_SHARED_DATA_REF_KEY) { + struct btrfs_delayed_data_ref *data_ref = btrfs_delayed_node_to_data_ref(ref); + if (data_ref->syno_usage) + atomic_inc(&root->num_syno_usage_entries); + } +#endif /* MY_ABC_HERE */ spin_unlock(&href->lock); return ret; } @@ -704,6 +838,14 @@ static noinline void update_existing_head_ref(struct btrfs_trans_handle *trans, existing->ref_mod += update->ref_mod; existing->total_ref_mod += update->ref_mod; +#ifdef MY_ABC_HERE + if (!existing->syno_usage && update->syno_usage) { + existing->syno_usage = update->syno_usage; + if (existing->processing == 0) + delayed_refs->num_syno_usage_heads_ready++; + } +#endif /* MY_ABC_HERE */ + /* * If we are going to from a positive ref mod to a negative or vice * versa we need to make sure to adjust pending_csums accordingly. @@ -750,7 +892,11 @@ static void init_delayed_ref_head(struct btrfs_delayed_ref_head *head_ref, struct btrfs_qgroup_extent_record *qrecord, u64 bytenr, u64 num_bytes, u64 ref_root, u64 reserved, int action, bool is_data, - bool is_system) + bool is_system +#ifdef MY_ABC_HERE + , int syno_usage +#endif /* MY_ABC_HERE */ + ) { int count_mod = 1; int must_insert_reserved = 0; @@ -790,6 +936,10 @@ static void init_delayed_ref_head(struct btrfs_delayed_ref_head *head_ref, head_ref->is_data = is_data; head_ref->is_system = is_system; head_ref->ref_tree = RB_ROOT_CACHED; +#ifdef MY_ABC_HERE + head_ref->syno_usage = syno_usage; + INIT_LIST_HEAD(&head_ref->ref_syno_list); +#endif /* MY_ABC_HERE */ INIT_LIST_HEAD(&head_ref->ref_add_list); RB_CLEAR_NODE(&head_ref->href_node); head_ref->processing = 0; @@ -860,9 +1010,22 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans, head_ref->num_bytes); delayed_refs->num_heads++; delayed_refs->num_heads_ready++; +#ifdef MY_ABC_HERE + if (head_ref->syno_usage) + delayed_refs->num_syno_usage_heads_ready++; +#endif /* MY_ABC_HERE */ atomic_inc(&delayed_refs->num_entries); +#ifdef MY_ABC_HERE + syno_total_delayed_ref_updates_inc(trans); +#endif /* MY_ABC_HERE */ trans->delayed_ref_updates++; } +#ifdef MY_ABC_HERE + if (head_ref->is_data) + percpu_counter_add_batch(&trans->fs_info->delayed_data_ref, 1, SZ_128M); + else + percpu_counter_add_batch(&trans->fs_info->delayed_meta_ref, 1, SZ_128M); +#endif /* MY_ABC_HERE */ if (qrecord_inserted_ret) *qrecord_inserted_ret = qrecord_inserted; @@ -918,6 +1081,9 @@ static void init_delayed_ref_common(struct btrfs_fs_info *fs_info, ref->type = ref_type; RB_CLEAR_NODE(&ref->ref_node); INIT_LIST_HEAD(&ref->add_list); +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&ref->syno_list); +#endif /* MY_ABC_HERE */ } /* @@ -958,6 +1124,8 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, return -ENOMEM; } +#ifdef MY_ABC_HERE +#else if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && is_fstree(generic_ref->real_root) && is_fstree(generic_ref->tree_ref.root) && @@ -969,6 +1137,7 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, return -ENOMEM; } } +#endif /* MY_ABC_HERE */ if (parent) ref_type = BTRFS_SHARED_BLOCK_REF_KEY; @@ -983,7 +1152,11 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, init_delayed_ref_head(head_ref, record, bytenr, num_bytes, generic_ref->tree_ref.root, 0, action, false, - is_system); + is_system +#ifdef MY_ABC_HERE + , 0 /* syno_usage */ +#endif /* MY_ABC_HERE */ + ); head_ref->extent_op = extent_op; delayed_refs = &trans->transaction->delayed_refs; @@ -996,7 +1169,11 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, head_ref = add_delayed_ref_head(trans, head_ref, record, action, &qrecord_inserted); - ret = insert_delayed_ref(trans, delayed_refs, head_ref, &ref->node); + ret = insert_delayed_ref(trans, delayed_refs, head_ref, &ref->node +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); spin_unlock(&delayed_refs->lock); /* @@ -1011,8 +1188,11 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, if (ret > 0) kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref); +#ifdef MY_ABC_HERE +#else if (qrecord_inserted) btrfs_qgroup_trace_extent_post(fs_info, record); +#endif /* MY_ABC_HERE */ return 0; } @@ -1039,6 +1219,9 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, u64 owner = generic_ref->data_ref.ino; u64 offset = generic_ref->data_ref.offset; u8 ref_type; +#ifdef MY_ABC_HERE + u64 free_reserved = 0; +#endif /* MY_ABC_HERE */ ASSERT(generic_ref->type == BTRFS_REF_DATA && action); ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS); @@ -1055,7 +1238,9 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, ref->parent = parent; ref->objectid = owner; ref->offset = offset; - +#ifdef MY_ABC_HERE + ref->syno_usage = generic_ref->syno_usage; +#endif /* MY_ABC_HERE */ head_ref = kmem_cache_alloc(btrfs_delayed_ref_head_cachep, GFP_NOFS); if (!head_ref) { @@ -1063,6 +1248,8 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, return -ENOMEM; } +#ifdef MY_ABC_HERE +#else if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && is_fstree(ref_root) && is_fstree(generic_ref->real_root) && @@ -1075,9 +1262,14 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, return -ENOMEM; } } +#endif /* MY_ABC_HERE */ init_delayed_ref_head(head_ref, record, bytenr, num_bytes, ref_root, - reserved, action, true, false); + reserved, action, true, false +#ifdef MY_ABC_HERE + , generic_ref->syno_usage +#endif /* MY_ABC_HERE */ + ); head_ref->extent_op = NULL; delayed_refs = &trans->transaction->delayed_refs; @@ -1090,7 +1282,34 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, head_ref = add_delayed_ref_head(trans, head_ref, record, action, &qrecord_inserted); - ret = insert_delayed_ref(trans, delayed_refs, head_ref, &ref->node); +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) || + generic_ref->skip_qgroup) { + ref->skip_qgroup = true; + ref->reserved = 0; + ref->uid = 0; + ref->ram_bytes = 0; + ref->inode = NULL; + } else { + ref->skip_qgroup = false; + ref->reserved = reserved; + ref->uid = 0; + ref->ram_bytes = generic_ref->ram_bytes; + if (likely(generic_ref->inode)) { + ref->inode = syno_usrquota_inode_get(generic_ref->inode); + if (!ref->inode) // I_FREEING or I_WILL_FREE + ref->uid = __kuid_val(generic_ref->inode->i_uid); + } else { + ref->inode = NULL; + WARN_ON(1); + } + } +#endif /* MY_ABC_HERE */ + ret = insert_delayed_ref(trans, delayed_refs, head_ref, &ref->node +#ifdef MY_ABC_HERE + , &free_reserved +#endif /* MY_ABC_HERE */ + ); spin_unlock(&delayed_refs->lock); /* @@ -1102,12 +1321,30 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, trace_add_delayed_data_ref(trans->fs_info, &ref->node, ref, action == BTRFS_ADD_DELAYED_EXTENT ? BTRFS_ADD_DELAYED_REF : action); + +#ifdef MY_ABC_HERE + if (ret > 0) { + if (!ref->skip_qgroup) + free_reserved += reserved; + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + free_reserved && ref->inode) { + btrfs_qgroup_syno_free(BTRFS_I(ref->inode)->root, free_reserved); + btrfs_usrquota_syno_free(BTRFS_I(ref->inode), free_reserved); + } + + syno_usrquota_inode_put(ref->inode); + kmem_cache_free(btrfs_delayed_data_ref_cachep, ref); + } +#else if (ret > 0) kmem_cache_free(btrfs_delayed_data_ref_cachep, ref); +#endif /* MY_ABC_HERE */ - +#ifdef MY_ABC_HERE +#else if (qrecord_inserted) return btrfs_qgroup_trace_extent_post(fs_info, record); +#endif /* MY_ABC_HERE */ return 0; } @@ -1124,7 +1361,11 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans, init_delayed_ref_head(head_ref, NULL, bytenr, num_bytes, 0, 0, BTRFS_UPDATE_DELAYED_HEAD, extent_op->is_data, - false); + false +#ifdef MY_ABC_HERE + , 0 /* syno_usage */ +#endif /* MY_ABC_HERE */ + ); head_ref->extent_op = extent_op; delayed_refs = &trans->transaction->delayed_refs; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index 3ba140468f12..86bdb1ef499f 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2008 Oracle. All rights reserved. @@ -7,6 +10,9 @@ #define BTRFS_DELAYED_REF_H #include +#ifdef MY_ABC_HERE +#include "btrfs_inode.h" +#endif /* MY_ABC_HERE */ /* these are the possible values of struct btrfs_delayed_ref_node->action */ #define BTRFS_ADD_DELAYED_REF 1 /* add one backref to the tree */ @@ -23,6 +29,10 @@ struct btrfs_delayed_ref_node { */ struct list_head add_list; +#ifdef MY_ABC_HERE + struct list_head syno_list; +#endif /* MY_ABC_HERE */ + /* the starting bytenr of the extent */ u64 bytenr; @@ -83,6 +93,10 @@ struct btrfs_delayed_ref_head { /* accumulate add BTRFS_ADD_DELAYED_REF nodes to this ref_add_list. */ struct list_head ref_add_list; +#ifdef MY_ABC_HERE + struct list_head ref_syno_list; +#endif /* MY_ABC_HERE */ + struct rb_node href_node; struct btrfs_delayed_extent_op *extent_op; @@ -118,6 +132,9 @@ struct btrfs_delayed_ref_head { unsigned int is_data:1; unsigned int is_system:1; unsigned int processing:1; +#ifdef MY_ABC_HERE + unsigned int syno_usage; +#endif /* MY_ABC_HERE */ }; struct btrfs_delayed_tree_ref { @@ -133,6 +150,18 @@ struct btrfs_delayed_data_ref { u64 parent; u64 objectid; u64 offset; +#ifdef MY_ABC_HERE + unsigned int syno_usage; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // Used by quota v1. + u64 reserved; + u64 ram_bytes; + u64 uid; // Only used in I_FREEING or I_WILL_FREE case. + struct inode *inode; + bool skip_qgroup; +#endif /* MY_ABC_HERE */ }; struct btrfs_delayed_ref_root { @@ -156,6 +185,23 @@ struct btrfs_delayed_ref_root { /* total number of head nodes ready for processing */ unsigned long num_heads_ready; +#ifdef MY_ABC_HERE + /* how many delayed DATA ref with SYNO_USAGE we've queued + * The calculation site should be consistent with num_entries but + * only count DATA refs with SYNO_USAGE. + */ + atomic_t num_syno_usage_entries; + + /* total number of head nodes that might have delayed refs with syno_usage + * The calculation site should be consistent with num_heads_ready but + * only count DATA refs with SYNO_USAGE. + */ + unsigned long num_syno_usage_heads_ready; + + /* total number of delayed refs block rsv account */ + u64 total_syno_usage_accounting; +#endif /* MY_ABC_HERE */ + u64 pending_csums; /* @@ -251,6 +297,16 @@ struct btrfs_ref { struct btrfs_data_ref data_ref; struct btrfs_tree_ref tree_ref; }; + +#ifdef MY_ABC_HERE + int syno_usage; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // Used by quota v1. + u64 ram_bytes; + struct inode *inode; +#endif /* MY_ABC_HERE */ }; extern struct kmem_cache *btrfs_delayed_ref_head_cachep; @@ -282,7 +338,11 @@ static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, } static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref, - u64 ref_root, u64 ino, u64 offset) + u64 ref_root, u64 ino, u64 offset +#ifdef MY_ABC_HERE + , int syno_usage +#endif /* MY_ABC_HERE */ + ) { /* If @real_root not set, use @root as fallback */ if (!generic_ref->real_root) @@ -291,6 +351,9 @@ static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref, generic_ref->data_ref.ino = ino; generic_ref->data_ref.offset = offset; generic_ref->type = BTRFS_REF_DATA; +#ifdef MY_ABC_HERE + generic_ref->syno_usage = syno_usage; +#endif /* MY_ABC_HERE */ } static inline struct btrfs_delayed_extent_op * @@ -306,8 +369,20 @@ btrfs_free_delayed_extent_op(struct btrfs_delayed_extent_op *op) kmem_cache_free(btrfs_delayed_extent_op_cachep, op); } +#ifdef MY_ABC_HERE +static inline struct btrfs_delayed_data_ref * +btrfs_delayed_node_to_data_ref(struct btrfs_delayed_ref_node *node) +{ + return container_of(node, struct btrfs_delayed_data_ref, node); +} +#endif /* MY_ABC_HERE */ + static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) { +#ifdef MY_ABC_HERE + struct btrfs_delayed_data_ref *data_ref; +#endif /* MY_ABC_HERE */ + WARN_ON(refcount_read(&ref->refs) == 0); if (refcount_dec_and_test(&ref->refs)) { WARN_ON(ref->in_tree); @@ -318,6 +393,10 @@ static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) break; case BTRFS_EXTENT_DATA_REF_KEY: case BTRFS_SHARED_DATA_REF_KEY: +#ifdef MY_ABC_HERE + data_ref = btrfs_delayed_node_to_data_ref(ref); + syno_usrquota_inode_put(data_ref->inode); +#endif /* MY_ABC_HERE */ kmem_cache_free(btrfs_delayed_data_ref_cachep, ref); break; default: @@ -369,6 +448,10 @@ void btrfs_delete_ref_head(struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_delayed_ref_head *btrfs_select_ref_head( struct btrfs_delayed_ref_root *delayed_refs); +#ifdef MY_ABC_HERE +struct btrfs_delayed_ref_head *btrfs_select_data_ref_head( + struct btrfs_delayed_ref_root *delayed_refs); +#endif /* MY_ABC_HERE */ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, u64 seq); @@ -391,10 +474,13 @@ btrfs_delayed_node_to_tree_ref(struct btrfs_delayed_ref_node *node) return container_of(node, struct btrfs_delayed_tree_ref, node); } +#ifdef MY_ABC_HERE +#else static inline struct btrfs_delayed_data_ref * btrfs_delayed_node_to_data_ref(struct btrfs_delayed_ref_node *node) { return container_of(node, struct btrfs_delayed_data_ref, node); } +#endif /* MY_ABC_HERE */ #endif diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 863367c2c620..2ae821749a78 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -97,6 +100,63 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +static int btrfs_insert_dir_item_caseless(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + const char *name, int name_len, + struct btrfs_inode *dir, + struct btrfs_disk_key *disk_key, + u8 type) +{ + int ret; + unsigned long name_ptr; + struct btrfs_path *path; + struct btrfs_dir_item *dir_item; + struct extent_buffer *leaf; + struct btrfs_key key; + u32 hash; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + path->leave_spinning = 1; + + key.objectid = btrfs_ino(dir); + key.type = BTRFS_DIR_ITEM_CASELESS_KEY; + ret = btrfs_upper_name_hash(name, name_len, &hash); + if (ret) + goto out_release; + + key.offset = hash; + + dir_item = insert_with_overflow(trans, root, path, + &key, (sizeof(*dir_item) + name_len), + name, name_len); + if (IS_ERR(dir_item)) { + ret = PTR_ERR(dir_item); + if (ret == -EEXIST) + ret = 0; + goto out_release; + } + + leaf = path->nodes[0]; + btrfs_set_dir_item_key(leaf, dir_item, disk_key); + btrfs_set_dir_type(leaf, dir_item, type); + btrfs_set_dir_data_len(leaf, dir_item, 0); + btrfs_set_dir_name_len(leaf, dir_item, name_len); + btrfs_set_dir_transid(leaf, dir_item, trans->transid); + name_ptr = (unsigned long)(dir_item + 1); + + write_extent_buffer(leaf, name, name_ptr, name_len); + btrfs_mark_buffer_dirty(leaf); + ret = 0; + +out_release: + btrfs_free_path(path); + return ret; +} +#endif /* MY_ABC_HERE */ + /* * insert a directory item in the tree, doing all the magic for * both indexes. 'dir' indicates which objectid to insert it into, @@ -168,9 +228,72 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name, return ret; if (ret2) return ret2; +#ifdef MY_ABC_HERE + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) { + ret = btrfs_insert_dir_item_caseless(trans, root, + name, name_len, + dir, &disk_key, type); + if (ret) { + btrfs_abort_transaction(trans, ret); + return ret; + } + } +#endif /* MY_ABC_HERE */ return 0; } +#ifdef MY_ABC_HERE +/* + * linear lookup for syno btrfs caseless stat + */ +static struct btrfs_dir_item *btrfs_syno_linear_lookup_dir_item_caseless( + struct btrfs_root *root, + struct btrfs_path *path, u64 dir, + const char *name, int name_len) +{ + int ret; + int slot; + struct btrfs_item *item; + struct btrfs_dir_item *di; + struct btrfs_key key; + struct btrfs_key found_key; + struct extent_buffer *leaf; + + key.type = BTRFS_DIR_ITEM_KEY; + key.offset = 0; + key.objectid = dir; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + return ERR_PTR(ret); + while (1) { + leaf = path->nodes[0]; + slot = path->slots[0]; + if (slot >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + return ERR_PTR(ret); + if (ret > 0) + return NULL; + continue; + } + + item = btrfs_item_nr(slot); + btrfs_item_key_to_cpu(leaf, &found_key, slot); + + if (found_key.objectid != key.objectid) + break; + if (found_key.type != BTRFS_DIR_ITEM_KEY) + break; + if (NULL != (di = btrfs_match_dir_item_name(root->fs_info, path, name, name_len))) + return di; + + path->slots[0]++; + } + return NULL; +} +#endif /* MY_ABC_HERE */ + /* * lookup a directory item based on name. 'dir' is the objectid * we're searching in, and 'mod' tells us if you plan on deleting the @@ -186,12 +309,32 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; +#ifdef MY_ABC_HERE + u32 hash; +#endif /* MY_ABC_HERE */ key.objectid = dir; +#ifdef MY_ABC_HERE + if (path->search_caseless_key) { + ret = btrfs_upper_name_hash(name, name_len, &hash); + if (ret) + return ERR_PTR(ret); + key.offset = hash; + key.type = BTRFS_DIR_ITEM_CASELESS_KEY; + goto search; + } +#endif /* MY_ABC_HERE */ + key.type = BTRFS_DIR_ITEM_KEY; key.offset = btrfs_name_hash(name, name_len); +#ifdef MY_ABC_HERE +search: + if (!path->search_caseless_key && path->caseless_lookup) + return btrfs_syno_linear_lookup_dir_item_caseless(root, path, dir, name, name_len); +#endif /* MY_ABC_HERE */ + ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); @@ -202,7 +345,11 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, } int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, - const char *name, int name_len) + const char *name, int name_len +#ifdef MY_ABC_HERE + , int check_dir_item +#endif /* MY_ABC_HERE */ + ) { int ret; struct btrfs_key key; @@ -211,15 +358,38 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, struct extent_buffer *leaf; int slot; struct btrfs_path *path; - +#ifdef MY_ABC_HERE + int caseless = 1; + u32 hash; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) return -ENOMEM; +#ifdef MY_ABC_HERE +check_dir_item: + key.objectid = dir; + if (caseless) { + if (!(btrfs_super_compat_flags(root->fs_info->super_copy) & + BTRFS_FEATURE_COMPAT_SYNO_CASELESS)) { + ret = 0; + goto out; + } + key.type = BTRFS_DIR_ITEM_CASELESS_KEY; + ret = btrfs_upper_name_hash(name, name_len, &hash); + if (ret) + goto out; + key.offset = hash; + } else { + key.type = BTRFS_DIR_ITEM_KEY; + key.offset = btrfs_name_hash(name, name_len); + } +#else /* MY_ABC_HERE */ key.objectid = dir; key.type = BTRFS_DIR_ITEM_KEY; key.offset = btrfs_name_hash(name, name_len); +#endif /* MY_ABC_HERE */ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); @@ -256,6 +426,13 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, ret = 0; } out: +#ifdef MY_ABC_HERE + if (!ret && check_dir_item && caseless) { + caseless = 0; + btrfs_release_path(path); + goto check_dir_item; + } +#endif /* MY_ABC_HERE */ btrfs_free_path(path); return ret; } @@ -389,6 +566,15 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, btrfs_dir_data_len(leaf, dir_item); name_ptr = (unsigned long)(dir_item + 1); +#ifdef MY_ABC_HERE + if (path->caseless_lookup) { + if (0 == memcmp_caseless_extent_buffer(leaf, name, + name_len, + name_ptr, + btrfs_dir_name_len(leaf, dir_item))) + return dir_item; + } else +#endif /* MY_ABC_HERE */ if (btrfs_dir_name_len(leaf, dir_item) == name_len && memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) return dir_item; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e025cd8f3f07..628c12506228 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -17,6 +20,12 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include #include "ctree.h" @@ -42,6 +51,12 @@ #include "block-group.h" #include "discard.h" #include "space-info.h" +#ifdef MY_ABC_HERE +#include "syno-feat-tree.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include "syno-rbd-meta.h" +#endif /* MY_ABC_HERE */ #define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\ BTRFS_HEADER_FLAG_RELOC |\ @@ -63,6 +78,10 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info, static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info); static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +static DEFINE_RATELIMIT_STATE(meta_err_rate_limit, 3 * HZ, DEFAULT_RATELIMIT_BURST); +#endif /* MY_ABC_HERE */ + /* * btrfs_end_io_wq structs are used to do processing in task context when an IO * is complete. This is used during reads to verify checksums, and it is used @@ -120,6 +139,10 @@ struct async_submit_bio { u64 bio_offset; struct btrfs_work work; blk_status_t status; +#ifdef MY_ABC_HERE + bool throttle; + struct btrfs_fs_info *fs_info; +#endif /* MY_ABC_HERE */ }; /* @@ -163,11 +186,28 @@ static struct btrfs_lockdep_keyset { { .id = BTRFS_FS_TREE_OBJECTID, .name_stem = "fs" }, { .id = BTRFS_CSUM_TREE_OBJECTID, .name_stem = "csum" }, { .id = BTRFS_QUOTA_TREE_OBJECTID, .name_stem = "quota" }, +#ifdef MY_ABC_HERE + { .id = BTRFS_SYNO_QUOTA_V2_TREE_OBJECTID, .name_stem = "syno-v2-quota" }, + { .id = BTRFS_SYNO_USRQUOTA_V2_TREE_OBJECTID, .name_stem = "syno-v2-usrquota" }, +#endif /* MY_ABC_HERE */ { .id = BTRFS_TREE_LOG_OBJECTID, .name_stem = "log" }, { .id = BTRFS_TREE_RELOC_OBJECTID, .name_stem = "treloc" }, { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, .name_stem = "dreloc" }, { .id = BTRFS_UUID_TREE_OBJECTID, .name_stem = "uuid" }, { .id = BTRFS_FREE_SPACE_TREE_OBJECTID, .name_stem = "free-space" }, +#ifdef MY_ABC_HERE + { .id = BTRFS_BLOCK_GROUP_HINT_TREE_OBJECTID, .name_stem = "block-group-hint" }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { .id = BTRFS_BLOCK_GROUP_CACHE_TREE_OBJECTID, .name_stem = "block-group-cache" }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { .id = BTRFS_SYNO_USAGE_TREE_OBJECTID, .name_stem = "syno-usage" }, + { .id = BTRFS_SYNO_EXTENT_USAGE_TREE_OBJECTID, .name_stem = "syno-extent-usage" }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { .id = BTRFS_SYNO_FEATURE_TREE_OBJECTID, .name_stem = "syno-feat-tree" }, +#endif /* MY_ABC_HERE */ { .id = 0, .name_stem = "tree" }, }; @@ -402,22 +442,61 @@ static int btree_read_extent_buffer_pages(struct extent_buffer *eb, int num_copies = 0; int mirror_num = 0; int failed_mirror = 0; +#ifdef MY_ABC_HERE + bool can_retry; +#endif /* MY_ABC_HERE */ io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree; while (1) { +#ifdef MY_ABC_HERE + can_retry = true; +#endif /* MY_ABC_HERE */ + clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); - ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num); + ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num +#ifdef MY_ABC_HERE + , &can_retry, parent_transid +#endif /* MY_ABC_HERE */ + ); if (!ret) { if (verify_parent_transid(io_tree, eb, - parent_transid, 0)) + parent_transid, 0)) { +#ifdef MY_ABC_HERE + /* + * Don't do data correction or we may mess eb->nr_retry. + * Only try open source dup version. + */ + eb->nr_retry = EXTENT_BUFFER_RETRY_ABORTED; +#endif /* MY_ABC_HERE */ ret = -EIO; + } else if (btrfs_verify_level_key(eb, level, - first_key, parent_transid)) + first_key, parent_transid)) { +#ifdef MY_ABC_HERE + /* + * Don't do data correction or we may mess eb->nr_retry. + * Only try open source dup version. + */ + eb->nr_retry = EXTENT_BUFFER_RETRY_ABORTED; +#endif /* MY_ABC_HERE */ ret = -EUCLEAN; - else + } else break; } +#ifdef MY_ABC_HERE + failed = 1; + if (!failed_mirror) + failed_mirror = eb->read_mirror; + + /* + * We found error and we or other people have done all retries for this mirror, + * go on and try if we have another mirror. + */ + if (eb->nr_retry != EXTENT_BUFFER_RETRY_ABORTED && can_retry) + continue; +#endif /* MY_ABC_HERE */ + num_copies = btrfs_num_copies(fs_info, eb->start, eb->len); if (num_copies == 1) @@ -438,6 +517,19 @@ static int btree_read_extent_buffer_pages(struct extent_buffer *eb, if (failed && !ret && failed_mirror) btrfs_repair_eb_io_failure(eb, failed_mirror); +#ifdef MY_ABC_HERE + else if (failed) { + clear_bit(EXTENT_BUFFER_SHOULD_REPAIR, &eb->bflags); + } + + if (-EIO == ret && test_bit(BTRFS_FS_OPEN, &fs_info->flags) + && !sb_rdonly(fs_info->sb) + && !test_bit(BTRFS_FS_STATE_TRANS_ABORTED, &fs_info->fs_state) + && __ratelimit(&meta_err_rate_limit)) { + btrfs_err(fs_info, "cannot fix %llu, record in meta_err", eb->start); + SynoBtrfsMetaCorruptedReport(fs_info->fs_devices->fsid, eb->start); + } +#endif /* MY_ABC_HERE */ return ret; } @@ -486,8 +578,15 @@ static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct page *page) btrfs_err(fs_info, "block=%llu write time tree block corruption detected", eb->start); +#ifdef MY_DEF_HERE + /* + * FIXME: For now, we ignore tree-checker during pre-write + * but leave error messages to collect informations. + */ +#else /* MY_DEF_HERE */ WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); return ret; +#endif /* MY_DEF_HERE */ } write_extent_buffer(eb, result, 0, csum_size); @@ -548,15 +647,54 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio, u64 phy_offset, */ atomic_inc(&eb->refs); +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(&io_bio->bio, BIO_CORRECTION_ERR))) + SetPageChecked(page); +#endif /* MY_ABC_HERE */ + reads_done = atomic_dec_and_test(&eb->io_pages); if (!reads_done) goto err; - eb->read_mirror = mirror; +#ifdef MY_ABC_HERE + if (eb->read_mirror < mirror) +#endif /* MY_ABC_HERE */ + eb->read_mirror = mirror; + if (test_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags)) { ret = -EIO; goto err; } +#ifdef MY_ABC_HERE + if (unlikely(eb->can_retry && + eb->nr_retry == EXTENT_BUFFER_SHOULD_ABORT_RETRY)) { + ret = -EIO; + goto err; + } + + csum_tree_block(eb, result); + + if (memcmp_extent_buffer(eb, result, 0, csum_size)) { + u8 val[BTRFS_CSUM_SIZE] = { 0 }; + + read_extent_buffer(eb, &val, 0, csum_size); + btrfs_warn_rl(fs_info, + "%s checksum verify failed on %llu wanted " CSUM_FMT " found " CSUM_FMT " level %d", + fs_info->sb->s_id, eb->start, + CSUM_FMT_VALUE(csum_size, val), + CSUM_FMT_VALUE(csum_size, result), + btrfs_header_level(eb)); + ret = -EUCLEAN; + if (eb->nr_retry && eb->can_retry) { + if (eb->nr_retry > 1 && + !memcmp(eb->prev_bad_csum, result, csum_size)) + set_bit(EXTENT_BUFFER_RETRY_ERR, &eb->bflags); + else + memcpy(eb->prev_bad_csum, result, csum_size); + } + goto err; + } +#endif /* MY_ABC_HERE */ found_start = btrfs_header_bytenr(eb); if (found_start != eb->start) { @@ -582,6 +720,8 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio, u64 phy_offset, btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), eb, found_level); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ csum_tree_block(eb, result); if (memcmp_extent_buffer(eb, result, 0, csum_size)) { @@ -597,6 +737,30 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio, u64 phy_offset, ret = -EUCLEAN; goto err; } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (unlikely(eb->parent_transid && + btrfs_header_generation(eb) != eb->parent_transid)) { + btrfs_warn_rl(fs_info, + "parent transid verify failed on %llu wanted %llu found %llu\n", + eb->start, + eb->parent_transid, + btrfs_header_generation(eb)); + + if (eb->nr_retry && eb->can_retry) { + if (eb->nr_retry > 1 && + eb->prev_bad_transid == btrfs_header_generation(eb)) + set_bit(EXTENT_BUFFER_RETRY_ERR, &eb->bflags); + else + eb->prev_bad_transid = btrfs_header_generation(eb); + } + memset(eb->prev_bad_csum, 0, sizeof(eb->prev_bad_csum)); + + ret = -EIO; + goto err; + } +#endif /* MY_ABC_HERE */ /* * If this is a leaf block and it is corrupt, set the corrupt bit so @@ -617,6 +781,21 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio, u64 phy_offset, btrfs_err(fs_info, "block=%llu read time tree block corruption detected", eb->start); + +#ifdef MY_ABC_HERE + if (!ret && trace_btrfs_syno_meta_statistics_eb_disk_read_enabled()) { + struct btrfs_key first_key; + memset(&first_key, 0, sizeof(first_key)); + if (btrfs_header_nritems(eb) > 0) { + if (found_level) + btrfs_node_key_to_cpu(eb, &first_key, 0); + else + btrfs_item_key_to_cpu(eb, &first_key, 0); + } + trace_btrfs_syno_meta_statistics_eb_disk_read(eb->fs_info, found_start, btrfs_header_owner(eb), found_level, &first_key); + } +#endif /* MY_ABC_HERE */ + err: if (reads_done && test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) @@ -629,13 +808,97 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio, u64 phy_offset, * to decrement */ atomic_inc(&eb->io_pages); +#ifdef MY_ABC_HERE + /* + * Let io error hook call clear_extent_buffer_uptodate(), since we don't get here + * if bio is not uptodate. + */ +#else /* MY_ABC_HERE */ clear_extent_buffer_uptodate(eb); +#endif /* MY_ABC_HERE */ } free_extent_buffer(eb); out: return ret; } +#ifdef MY_ABC_HERE +void btrfs_metadata_io_failed(struct extent_buffer *eb, struct page *page, + int failed_mirror, int correction_err) +{ + int i; + int tried_out = 1; + unsigned long num_pages; + + if (eb->read_mirror < failed_mirror) + eb->read_mirror = failed_mirror; + + if (correction_err) + SetPageChecked(page); + + if (!atomic_dec_and_test(&eb->io_pages)) + return; + + clear_extent_buffer_uptodate(eb); + + if (!eb->can_retry) + return; + + if (eb->nr_retry == EXTENT_BUFFER_SHOULD_ABORT_RETRY) { + // Keep ABORTED until we write the good one or we change to another btrfs mirror. + eb->nr_retry = EXTENT_BUFFER_RETRY_ABORTED; + correction_put_locked_record(eb->fs_info, eb->start); + return; + } + + num_pages = num_extent_pages(eb); + for (i = 0; i < num_pages && tried_out; i++) { + page = eb->pages[i]; + if (!PageChecked(page)) + tried_out = 0; + } + + if (test_bit(EXTENT_BUFFER_RETRY_ERR, &eb->bflags) || + eb->nr_retry > SYNO_DATA_CORRECTION_MAX_RETRY_TIMES || + tried_out) { + u8 zero[BTRFS_CSUM_SIZE] = { 0 }; + + for (i = 0; i < num_pages; i++) { + page = eb->pages[i]; + ClearPageChecked(page); + } + eb->nr_retry = EXTENT_BUFFER_SHOULD_ABORT_RETRY; + + if (memcmp(eb->prev_bad_csum, zero, sizeof(eb->prev_bad_csum))) + btrfs_err(eb->fs_info, + "BTRFS: %s failed to repair btree csum error on %llu, mirror = %d\n", + eb->fs_info->sb->s_id, eb->start, + eb->read_mirror); + else if (eb->parent_transid && + btrfs_header_generation(eb) != eb->parent_transid) + btrfs_err(eb->fs_info, + "BTRFS: %s failed to repair parent transid verify failure on %llu, mirror = %d\n", + eb->fs_info->sb->s_id, eb->start, + eb->read_mirror); + else + btrfs_err(eb->fs_info, + "BTRFS: %s failed to repair meta data on %llu, mirror = %d\n", + eb->fs_info->sb->s_id, eb->start, + eb->read_mirror); + } else { + /* + * We need an indicator so that only one process can do the repair work. Testing if + * we have eb->nr_retry changing from 0 to 1 in read_extent_buffer_pages() is not enough + * since we could have concurrent readers and they set eb->nr_retry > 1 before we can test + * eb->nr_retry. + */ + if (!eb->nr_retry) + set_bit(EXTENT_BUFFER_SHOULD_REPAIR, &eb->bflags); + eb->nr_retry++; + } +} +#endif /* MY_ABC_HERE */ + static void end_workqueue_bio(struct bio *bio) { struct btrfs_end_io_wq *end_io_wq = bio->bi_private; @@ -740,15 +1003,36 @@ static void run_one_async_done(struct btrfs_work *work) static void run_one_async_free(struct btrfs_work *work) { struct async_submit_bio *async; +#ifdef MY_ABC_HERE + struct btrfs_fs_info *fs_info; +#endif /* MY_ABC_HERE */ async = container_of(work, struct async_submit_bio, work); +#ifdef MY_ABC_HERE + if (async->fs_info && async->throttle) { + fs_info = async->fs_info; + if (atomic_dec_return(&fs_info->syno_async_submit_nr) < fs_info->syno_async_submit_throttle && + waitqueue_active(&fs_info->syno_async_submit_queue_wait)) + wake_up(&fs_info->syno_async_submit_queue_wait); + } +#endif /* MY_ABC_HERE */ kfree(async); } -blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, +#ifdef MY_ABC_HERE +static blk_status_t __btrfs_wq_submit_bio +#else /* MY_ABC_HERE */ +blk_status_t btrfs_wq_submit_bio +#endif /* MY_ABC_HERE */ + ( + struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num, unsigned long bio_flags, u64 bio_offset, void *private_data, - extent_submit_bio_start_t *submit_bio_start) + extent_submit_bio_start_t *submit_bio_start +#ifdef MY_ABC_HERE + , bool throttle +#endif /* MY_ABC_HERE */ + ) { struct async_submit_bio *async; @@ -760,6 +1044,12 @@ blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, async->bio = bio; async->mirror_num = mirror_num; async->submit_bio_start = submit_bio_start; +#ifdef MY_ABC_HERE + async->fs_info = fs_info; + async->throttle = throttle; + if (async->throttle) + atomic_inc(&fs_info->syno_async_submit_nr); +#endif /* MY_ABC_HERE */ btrfs_init_work(&async->work, run_one_async_start, run_one_async_done, run_one_async_free); @@ -771,9 +1061,45 @@ blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, if (op_is_sync(bio->bi_opf)) btrfs_set_work_high_priority(&async->work); +#ifdef MY_ABC_HERE + if (async->throttle) { + btrfs_queue_work(fs_info->syno_cow_async_workers, &async->work); + goto out; + } +#endif /* MY_ABC_HERE */ + btrfs_queue_work(fs_info->workers, &async->work); +#ifdef MY_ABC_HERE +out: +#endif /* MY_ABC_HERE */ return 0; } +#ifdef MY_ABC_HERE +blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, + int mirror_num, unsigned long bio_flags, + u64 bio_offset, void *private_data, + extent_submit_bio_start_t *submit_bio_start) +{ + return __btrfs_wq_submit_bio(fs_info, bio, mirror_num, bio_flags, bio_offset, private_data, submit_bio_start, false); +} + +blk_status_t btrfs_wq_submit_bio_throttle(struct btrfs_fs_info *fs_info, struct bio *bio, + int mirror_num, unsigned long bio_flags, + u64 bio_offset, void *private_data, + extent_submit_bio_start_t *submit_bio_start) +{ + DEFINE_WAIT(wait); + + if (fs_info->syno_async_submit_throttle && atomic_read(&fs_info->syno_async_submit_nr) > fs_info->syno_async_submit_throttle) { + prepare_to_wait_exclusive(&fs_info->syno_async_submit_queue_wait, &wait, TASK_UNINTERRUPTIBLE); + if (atomic_read(&fs_info->syno_async_submit_nr) > fs_info->syno_async_submit_throttle) + schedule(); + finish_wait(&fs_info->syno_async_submit_queue_wait, &wait); + } + + return __btrfs_wq_submit_bio(fs_info, bio, mirror_num, bio_flags, bio_offset, private_data, submit_bio_start, true); +} +#endif /* MY_ABC_HERE */ static blk_status_t btree_csum_one_bio(struct bio *bio) { @@ -834,7 +1160,12 @@ blk_status_t btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, ret = btree_csum_one_bio(bio); if (ret) goto out_w_error; - ret = btrfs_map_bio(fs_info, bio, mirror_num); +#ifdef MY_ABC_HERE + if (bio_flags & EXTENT_BIO_TREE_LOG) + ret = btrfs_map_bio_log_tree(fs_info, bio, mirror_num); + else +#endif /* MY_ABC_HERE */ + ret = btrfs_map_bio(fs_info, bio, mirror_num); } else { /* * kthread helpers are used to submit writes so that @@ -951,12 +1282,19 @@ void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr) { struct extent_buffer *buf = NULL; int ret; +#ifdef MY_ABC_HERE + bool can_retry = false; +#endif /* MY_ABC_HERE */ buf = btrfs_find_create_tree_block(fs_info, bytenr); if (IS_ERR(buf)) return; - ret = read_extent_buffer_pages(buf, WAIT_NONE, 0); + ret = read_extent_buffer_pages(buf, WAIT_NONE, 0 +#ifdef MY_ABC_HERE + , &can_retry, 0 +#endif /* MY_ABC_HERE */ + ); if (ret < 0) free_extent_buffer_stale(buf); else @@ -1094,6 +1432,45 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, list_add_tail(&root->leak_list, &fs_info->allocated_roots); spin_unlock(&fs_info->fs_roots_radix_lock); #endif +#ifdef MY_ABC_HERE + root->locker_enabled = 0; + root->locker_mode = LM_NONE; + root->locker_default_state = LS_OPEN; + root->locker_waittime = LOCKER_DEFAULT_WAITTIME; + root->locker_duration = LOCKER_DEFAULT_DURATION; + root->locker_clock_adjustment = 0; + root->locker_update_time_floor = 0; + root->locker_state = LS_OPEN; + root->locker_period_begin = LOCKER_DEFAULT_PERIOD_BEGIN; + root->locker_period_begin_sys = LOCKER_DEFAULT_PERIOD_BEGIN; + root->locker_period_end = LOCKER_DEFAULT_PERIOD_END; + root->locker_period_end_sys = LOCKER_DEFAULT_PERIOD_END; + spin_lock_init(&root->locker_lock); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + spin_lock_init(&root->syno_usage_lock); + rwlock_init(&root->syno_usage_rwlock); + INIT_LIST_HEAD(&root->syno_usage_rescan_list); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + root->usrquota_loaded_gen = 0; + INIT_LIST_HEAD(&root->usrquota_ro_root); + init_rwsem(&root->rescan_lock); + root->rescan_inode = (u64)-1; + root->rescan_end_inode = (u64)-1; + root->invalid_quota = true; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + root->has_usrquota_limit = false; + root->has_quota_limit = false; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + root->inline_dedupe = false; + root->small_extent_size = BTRFS_MAX_EXTENT_SIZE; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&root->syno_orphan_cleanup.root); +#endif /* MY_ABC_HERE */ } static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info, @@ -1155,7 +1532,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); leaf = NULL; - goto fail; + goto fail_unlock; } root->node = leaf; @@ -1179,6 +1556,8 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, export_guid(root->root_item.uuid, &guid_null); root->root_item.drop_level = 0; + btrfs_tree_unlock(leaf); + key.objectid = objectid; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = 0; @@ -1186,13 +1565,12 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, if (ret) goto fail; - btrfs_tree_unlock(leaf); - return root; -fail: +fail_unlock: if (leaf) btrfs_tree_unlock(leaf); +fail: btrfs_put_root(root); return ERR_PTR(ret); @@ -1338,15 +1716,83 @@ struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, return root; } +#if defined(MY_ABC_HERE) +void btrfs_free_new_fs_root_args(struct btrfs_new_fs_root_args *args) +{ + if (!args) + return; +#ifdef MY_ABC_HERE + if (args->syno_delalloc_bytes) { + percpu_counter_destroy(args->syno_delalloc_bytes); + kfree(args->syno_delalloc_bytes); + } +#endif /* MY_ABC_HERE */ + kfree(args); +} + +struct btrfs_new_fs_root_args *btrfs_alloc_new_fs_root_args(void) +{ + int err; + struct btrfs_new_fs_root_args *args; + + args = kzalloc(sizeof(*args), GFP_KERNEL); + if (!args) { + err = -ENOMEM; + goto out; + } + +#ifdef MY_ABC_HERE + args->syno_delalloc_bytes = kzalloc(sizeof(*args->syno_delalloc_bytes), GFP_KERNEL); + if (!args->syno_delalloc_bytes) { + err = -ENOMEM; + goto out; + } + err = percpu_counter_init(args->syno_delalloc_bytes, 0, GFP_KERNEL); + if (err) + goto out; +#endif /* MY_ABC_HERE */ + + return args; + +out: + btrfs_free_new_fs_root_args(args); + return ERR_PTR(err); +} +#endif /* MY_ABC_HERE */ + /* * Initialize subvolume root in-memory structure * * @anon_dev: anonymous device to attach to the root, if zero, allocate new */ -static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev) +static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev +#if defined(MY_ABC_HERE) + , struct btrfs_new_fs_root_args *new_fs_root_args +#endif /* MY_ABC_HERE */ + ) { int ret; - unsigned int nofs_flag; +#ifdef MY_ABC_HERE + struct percpu_counter *delalloc_bytes = NULL; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (new_fs_root_args && new_fs_root_args->syno_delalloc_bytes) { + root->syno_delalloc_bytes = new_fs_root_args->syno_delalloc_bytes; + new_fs_root_args->syno_delalloc_bytes = NULL; + } else { + delalloc_bytes = kzalloc(sizeof(*delalloc_bytes), GFP_NOFS); + if (!delalloc_bytes) { + ret = -ENOMEM; + goto fail; + } + ret = percpu_counter_init(delalloc_bytes, 0, GFP_NOFS); + if (ret < 0) + goto fail; + root->syno_delalloc_bytes = delalloc_bytes; + delalloc_bytes = NULL; + } +#endif /* MY_ABC_HERE */ root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS); root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned), @@ -1356,15 +1802,7 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev) goto fail; } - /* - * We might be called under a transaction (e.g. indirect backref - * resolution) which could deadlock if it triggers memory reclaim - */ - nofs_flag = memalloc_nofs_save(); - ret = btrfs_drew_lock_init(&root->snapshot_lock); - memalloc_nofs_restore(nofs_flag); - if (ret) - goto fail; + btrfs_drew_lock_init(&root->snapshot_lock); if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { @@ -1392,25 +1830,71 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev) } mutex_lock(&root->objectid_mutex); +#ifdef MY_ABC_HERE + if (btrfs_root_dead(root)) { + root->highest_objectid = BTRFS_LAST_FREE_OBJECTID; + } else { + ret = btrfs_find_highest_objectid(root, + &root->highest_objectid); + if (ret) { + mutex_unlock(&root->objectid_mutex); + goto fail; + } + } +#else ret = btrfs_find_highest_objectid(root, &root->highest_objectid); if (ret) { mutex_unlock(&root->objectid_mutex); goto fail; } +#endif /* MY_ABC_HERE */ ASSERT(root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID); mutex_unlock(&root->objectid_mutex); +#ifdef MY_ABC_HERE + if ((test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &root->fs_info->flags) || + (root->fs_info->syno_usage_status.state == SYNO_USAGE_STATE_DISABLE && + root->fs_info->syno_usage_root)) && + is_fstree(root->root_key.objectid)) { + ret = btrfs_syno_usage_root_status_lookup(root->fs_info, root->root_key.objectid, &root->syno_usage_root_status); + if (ret < 0) + goto fail; + else if (ret == 0) + set_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state); + else /* not initialize */ + btrfs_syno_usage_root_initialize(root); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (is_fstree(root->root_key.objectid) && !btrfs_root_dead(root)) + btrfs_read_syno_quota_for_root(root); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (is_fstree(root->root_key.objectid) && !btrfs_root_dead(root)) + btrfs_syno_locker_disk_root_read(root); +#endif /* MY_ABC_HERE */ + return 0; fail: /* The caller is responsible to call btrfs_free_fs_root */ +#ifdef MY_ABC_HERE + kfree(delalloc_bytes); +#endif /* MY_ABC_HERE */ return ret; } +#ifdef MY_ABC_HERE +struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, + u64 root_id) +#else static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, u64 root_id) +#endif /* MY_ABC_HERE */ { struct btrfs_root *root; @@ -1436,6 +1920,11 @@ static struct btrfs_root *btrfs_get_global_root(struct btrfs_fs_info *fs_info, return btrfs_grab_root(fs_info->dev_root); if (objectid == BTRFS_CSUM_TREE_OBJECTID) return btrfs_grab_root(fs_info->csum_root); +#ifdef MY_ABC_HERE + if (objectid == BTRFS_SYNO_QUOTA_V2_TREE_OBJECTID) + return btrfs_grab_root(fs_info->quota_root) ? + fs_info->quota_root : ERR_PTR(-ENOENT); +#endif /* MY_ABC_HERE */ if (objectid == BTRFS_QUOTA_TREE_OBJECTID) return btrfs_grab_root(fs_info->quota_root) ? fs_info->quota_root : ERR_PTR(-ENOENT); @@ -1445,6 +1934,38 @@ static struct btrfs_root *btrfs_get_global_root(struct btrfs_fs_info *fs_info, if (objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) return btrfs_grab_root(fs_info->free_space_root) ? fs_info->free_space_root : ERR_PTR(-ENOENT); +#ifdef MY_ABC_HERE + if (objectid == BTRFS_SYNO_USRQUOTA_V2_TREE_OBJECTID) + return btrfs_grab_root(fs_info->usrquota_root) ? + fs_info->usrquota_root : ERR_PTR(-ENOENT); + if (objectid == BTRFS_USRQUOTA_TREE_OBJECTID) + return btrfs_grab_root(fs_info->usrquota_root) ? + fs_info->usrquota_root : ERR_PTR(-ENOENT); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (objectid == BTRFS_BLOCK_GROUP_HINT_TREE_OBJECTID) + return btrfs_grab_root(fs_info->block_group_hint_root) ? + fs_info->block_group_hint_root : ERR_PTR(-ENOENT); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (objectid == BTRFS_BLOCK_GROUP_CACHE_TREE_OBJECTID) + return btrfs_grab_root(fs_info->block_group_cache_root) ? + fs_info->block_group_cache_root : ERR_PTR(-ENOENT); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (objectid == BTRFS_SYNO_USAGE_TREE_OBJECTID) + return btrfs_grab_root(fs_info->syno_usage_root) ? + fs_info->syno_usage_root : ERR_PTR(-ENOENT); + if (objectid == BTRFS_SYNO_EXTENT_USAGE_TREE_OBJECTID) + return btrfs_grab_root(fs_info->syno_extent_usage_root) ? + fs_info->syno_extent_usage_root : ERR_PTR(-ENOENT); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (objectid == BTRFS_SYNO_FEATURE_TREE_OBJECTID) + return btrfs_grab_root(fs_info->syno_feat_root) ? + fs_info->syno_feat_root : ERR_PTR(-ENOENT); +#endif /* MY_ABC_HERE */ + return NULL; } @@ -1497,21 +2018,50 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) percpu_counter_destroy(&fs_info->delalloc_bytes); percpu_counter_destroy(&fs_info->dio_bytes); percpu_counter_destroy(&fs_info->dev_replace.bio_counter); +#ifdef MY_ABC_HERE + percpu_counter_destroy(&fs_info->eb_hit); + percpu_counter_destroy(&fs_info->eb_miss); + percpu_counter_destroy(&fs_info->meta_write_pages); + percpu_counter_destroy(&fs_info->data_write_pages); + percpu_counter_destroy(&fs_info->delayed_meta_ref); + percpu_counter_destroy(&fs_info->delayed_data_ref); + percpu_counter_destroy(&fs_info->write_flush); + percpu_counter_destroy(&fs_info->write_fua); +#endif /* MY_ABC_HERE */ btrfs_free_csum_hash(fs_info); btrfs_free_stripe_hash_table(fs_info); btrfs_free_ref_cache(fs_info); kfree(fs_info->balance_ctl); kfree(fs_info->delayed_root); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + kfree(fs_info->mount_path); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ btrfs_put_root(fs_info->extent_root); btrfs_put_root(fs_info->tree_root); btrfs_put_root(fs_info->chunk_root); btrfs_put_root(fs_info->dev_root); btrfs_put_root(fs_info->csum_root); btrfs_put_root(fs_info->quota_root); +#ifdef MY_ABC_HERE + btrfs_put_root(fs_info->usrquota_root); +#endif /* MY_ABC_HERE */ btrfs_put_root(fs_info->uuid_root); btrfs_put_root(fs_info->free_space_root); btrfs_put_root(fs_info->fs_root); btrfs_put_root(fs_info->data_reloc_root); +#ifdef MY_ABC_HERE + btrfs_put_root(fs_info->block_group_hint_root); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_put_root(fs_info->block_group_cache_root); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_put_root(fs_info->syno_usage_root); + btrfs_put_root(fs_info->syno_extent_usage_root); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_put_root(fs_info->syno_feat_root); +#endif /* MY_ABC_HERE */ btrfs_check_leaked_roots(fs_info); btrfs_extent_buffer_leak_debug_check(fs_info); kfree(fs_info->super_copy); @@ -1540,7 +2090,11 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) */ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, u64 objectid, dev_t anon_dev, - bool check_ref) + bool check_ref +#if defined(MY_ABC_HERE) + , struct btrfs_new_fs_root_args *new_fs_root_args +#endif /* MY_ABC_HERE */ + ) { struct btrfs_root *root; struct btrfs_path *path; @@ -1555,6 +2109,10 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, if (root) { /* Shouldn't get preallocated anon_dev for cached roots */ ASSERT(!anon_dev); +#if defined(MY_ABC_HERE) + /* Shouldn't get new_fs_root_args for cached roots */ + ASSERT(!new_fs_root_args); +#endif /* MY_ABC_HERE */ if (check_ref && btrfs_root_refs(&root->root_item) == 0) { btrfs_put_root(root); return ERR_PTR(-ENOENT); @@ -1574,7 +2132,11 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, goto fail; } - ret = btrfs_init_fs_root(root, anon_dev); + ret = btrfs_init_fs_root(root, anon_dev +#if defined(MY_ABC_HERE) + , new_fs_root_args +#endif /* MY_ABC_HERE */ + ); if (ret) goto fail; @@ -1603,6 +2165,14 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, } return root; fail: + /* + * If our caller provided us an anonymous device, then it's his + * responsability to free it in case we fail. So we have to set our + * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root() + * and once again by our caller. + */ + if (anon_dev) + root->anon_dev = 0; btrfs_put_root(root); return ERR_PTR(ret); } @@ -1617,7 +2187,11 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, u64 objectid, bool check_ref) { - return btrfs_get_root_ref(fs_info, objectid, 0, check_ref); + return btrfs_get_root_ref(fs_info, objectid, 0, check_ref +#if defined(MY_ABC_HERE) + , NULL +#endif /* MY_ABC_HERE */ + ); } /* @@ -1629,9 +2203,17 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, * parameter value */ struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info, - u64 objectid, dev_t anon_dev) + u64 objectid, dev_t anon_dev +#if defined(MY_ABC_HERE) + , struct btrfs_new_fs_root_args *new_fs_root_args +#endif /* MY_ABC_HERE */ + ) { - return btrfs_get_root_ref(fs_info, objectid, anon_dev, true); + return btrfs_get_root_ref(fs_info, objectid, anon_dev, true +#if defined(MY_ABC_HERE) + , new_fs_root_args +#endif /* MY_ABC_HERE */ + ); } /* @@ -1699,6 +2281,75 @@ static void end_workqueue_fn(struct btrfs_work *work) kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq); } +#ifdef MY_ABC_HERE +static void btrfs_syno_orphan_cleanup(struct btrfs_fs_info *fs_info) +{ + int err; + struct btrfs_root *root; + + /* we need to run find orphan roots before snapshot cleanup */ + if (!fs_info->syno_orphan_cleanup.root_tree_cleanup) { + fs_info->syno_orphan_cleanup.root_tree_cleanup = true; + err = btrfs_find_orphan_roots(fs_info); + if (err) { + btrfs_err(fs_info, "Failed to btrfs find orphan roots, err:%d", err); + goto out; + } + + down_read(&fs_info->cleanup_work_sem); + err = btrfs_orphan_cleanup(fs_info->tree_root); + up_read(&fs_info->cleanup_work_sem); + if (err) { + btrfs_err(fs_info, "Failed to btrfs orphan cleanup with tree_root, err:%d", err); + goto out; + } + } + + if (!fs_info->syno_orphan_cleanup.enable || + fs_info->syno_orphan_cleanup.orphan_inode_delayed) + goto out; + + if (!fs_info->syno_orphan_cleanup.fs_tree_cleanup) { + fs_info->syno_orphan_cleanup.fs_tree_cleanup = true; + err = btrfs_cleanup_fs_roots(fs_info); + if (err) { + btrfs_err(fs_info, "Failed to orphan cleanup all fs roots, err:%d", err); + goto out; + } + } + + spin_lock(&fs_info->syno_orphan_cleanup.lock); + while (!list_empty(&fs_info->syno_orphan_cleanup.roots)) { + root = list_first_entry(&fs_info->syno_orphan_cleanup.roots, struct btrfs_root, syno_orphan_cleanup.root); + list_del_init(&root->syno_orphan_cleanup.root); + if (btrfs_root_dead(root)) + continue; + root = btrfs_grab_root(root); + if (!root) + continue; + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + + down_read(&fs_info->cleanup_work_sem); + err = btrfs_orphan_cleanup(root); + up_read(&fs_info->cleanup_work_sem); + if (err) + btrfs_err(fs_info, "Failed to btrfs orphan cleanup with root:%llu, err:%d", root->root_key.objectid, err); + btrfs_put_root(root); + + if (!fs_info->syno_orphan_cleanup.enable || + fs_info->syno_orphan_cleanup.orphan_inode_delayed || + btrfs_need_cleaner_sleep(fs_info)) + goto out; + cond_resched(); + spin_lock(&fs_info->syno_orphan_cleanup.lock); + } + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + +out: + return; +} +#endif /* MY_ABC_HERE */ + static int cleaner_kthread(void *arg) { struct btrfs_root *root = arg; @@ -1721,6 +2372,9 @@ static int cleaner_kthread(void *arg) if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags)) goto sleep; +#ifdef MY_ABC_HERE + btrfs_syno_orphan_cleanup(fs_info); +#endif /* MY_ABC_HERE */ if (!mutex_trylock(&fs_info->cleaner_mutex)) goto sleep; @@ -1735,7 +2389,12 @@ static int cleaner_kthread(void *arg) btrfs_run_delayed_iputs(fs_info); +#ifdef MY_ABC_HERE + if (root->fs_info->snapshot_cleaner && !btrfs_test_opt(root->fs_info, SKIP_CLEANER)) + again = btrfs_clean_one_deleted_snapshot(root); +#else /* MY_ABC_HERE */ again = btrfs_clean_one_deleted_snapshot(root); +#endif /* MY_ABC_HERE */ mutex_unlock(&fs_info->cleaner_mutex); /* @@ -1767,6 +2426,60 @@ static int cleaner_kthread(void *arg) } } +#ifdef MY_ABC_HERE +static void __btrfs_async_metadata_cache_hook(struct work_struct *work) +{ + int ret; + struct btrfs_fs_info *fs_info = container_of(work, + struct btrfs_fs_info, + async_metadata_cache_work); + char mount_path[SYNO_MOUNT_PATH_LEN] = {'\0'}; + char *argv[] = {"/usr/syno/sbin/synotune", + "--btrfs-metadata-rescan", + "-b", + mount_path, NULL}; + static char *envp[] = {"HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL}; + + spin_lock(&fs_info->mount_path_lock); + if (!fs_info->mount_path) { + spin_unlock(&fs_info->mount_path_lock); + return; + } + snprintf(mount_path, sizeof(mount_path), "%s", fs_info->mount_path); + spin_unlock(&fs_info->mount_path_lock); + + if (atomic_read(&fs_info->syno_metadata_block_group_update_count) == 0) + return; + + ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); + if (ret && ret != -ENOENT) + return; + + atomic_set(&fs_info->syno_metadata_block_group_update_count, 0); +} + +static inline +void btrfs_init_async_metadata_cache_work(struct btrfs_fs_info *fs_info) +{ + INIT_WORK(&fs_info->async_metadata_cache_work, + __btrfs_async_metadata_cache_hook); +} + +static inline +void btrfs_syno_check_metadata_cache_sync(struct btrfs_fs_info *fs_info) +{ + if (fs_info->metadata_cache_enable && + !btrfs_fs_closing(fs_info) && + !test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) && + !fs_info->mount_path && + (atomic_read(&fs_info->syno_metadata_block_group_update_count) != 0) && + !work_busy(&fs_info->async_metadata_cache_work)) + queue_work(system_unbound_wq, &fs_info->async_metadata_cache_work); +} +#endif /* MY_ABC_HERE */ + static int transaction_kthread(void *arg) { struct btrfs_root *root = arg; @@ -1774,13 +2487,13 @@ static int transaction_kthread(void *arg) struct btrfs_trans_handle *trans; struct btrfs_transaction *cur; u64 transid; - time64_t now; + time64_t delta; unsigned long delay; bool cannot_commit; do { cannot_commit = false; - delay = HZ * fs_info->commit_interval; + delay = msecs_to_jiffies(fs_info->commit_interval * 1000); mutex_lock(&fs_info->transaction_kthread_mutex); spin_lock(&fs_info->trans_lock); @@ -1790,12 +2503,13 @@ static int transaction_kthread(void *arg) goto sleep; } - now = ktime_get_seconds(); + delta = ktime_get_seconds() - cur->start_time; if (cur->state < TRANS_STATE_COMMIT_START && - (now < cur->start_time || - now - cur->start_time < fs_info->commit_interval)) { + delta < fs_info->commit_interval) { spin_unlock(&fs_info->trans_lock); - delay = HZ * 5; + delay -= msecs_to_jiffies((delta - 1) * 1000); + delay = min(delay, + msecs_to_jiffies(fs_info->commit_interval * 1000)); goto sleep; } transid = cur->transid; @@ -1814,6 +2528,9 @@ static int transaction_kthread(void *arg) btrfs_end_transaction(trans); } sleep: +#ifdef MY_ABC_HERE + btrfs_syno_check_metadata_cache_sync(fs_info); +#endif /* MY_ABC_HERE */ wake_up_process(fs_info->cleaner_kthread); mutex_unlock(&fs_info->transaction_kthread_mutex); @@ -1996,6 +2713,24 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) btrfs_destroy_workqueue(fs_info->qgroup_rescan_workers); if (fs_info->discard_ctl.discard_workers) destroy_workqueue(fs_info->discard_ctl.discard_workers); +#ifdef MY_ABC_HERE + btrfs_destroy_workqueue(fs_info->syno_multiple_writeback_workers); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_destroy_workqueue(fs_info->syno_cow_async_workers); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_destroy_workqueue(fs_info->syno_cow_endio_workers); + btrfs_destroy_workqueue(fs_info->syno_nocow_endio_workers); + btrfs_destroy_workqueue(fs_info->syno_high_priority_endio_workers); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_destroy_workqueue(fs_info->extent_workers); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_destroy_workqueue(fs_info->syno_allocator.caching_workers); +#endif /* MY_ABC_HERE */ + /* * Now that all other work queues are destroyed, we can safely destroy * the queues used for metadata I/O, since tasks from those other work @@ -2003,6 +2738,7 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) */ btrfs_destroy_workqueue(fs_info->endio_meta_workers); btrfs_destroy_workqueue(fs_info->endio_meta_write_workers); + } static void free_root_extent_buffers(struct btrfs_root *root) @@ -2024,12 +2760,28 @@ static void free_root_pointers(struct btrfs_fs_info *info, bool free_chunk_root) free_root_extent_buffers(info->extent_root); free_root_extent_buffers(info->csum_root); free_root_extent_buffers(info->quota_root); +#ifdef MY_ABC_HERE + free_root_extent_buffers(info->usrquota_root); +#endif /* MY_ABC_HERE */ free_root_extent_buffers(info->uuid_root); free_root_extent_buffers(info->fs_root); free_root_extent_buffers(info->data_reloc_root); if (free_chunk_root) free_root_extent_buffers(info->chunk_root); free_root_extent_buffers(info->free_space_root); +#ifdef MY_ABC_HERE + free_root_extent_buffers(info->block_group_hint_root); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + free_root_extent_buffers(info->block_group_cache_root); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + free_root_extent_buffers(info->syno_usage_root); + free_root_extent_buffers(info->syno_extent_usage_root); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + free_root_extent_buffers(info->syno_feat_root); +#endif /* MY_ABC_HERE */ } void btrfs_put_root(struct btrfs_root *root) @@ -2040,9 +2792,16 @@ void btrfs_put_root(struct btrfs_root *root) if (refcount_dec_and_test(&root->refs)) { WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); WARN_ON(test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state)); +#ifdef MY_ABC_HERE + if (root->syno_delalloc_bytes) { + WARN_ON_ONCE(percpu_counter_sum(root->syno_delalloc_bytes)); + percpu_counter_destroy(root->syno_delalloc_bytes); + kfree(root->syno_delalloc_bytes); + root->syno_delalloc_bytes = NULL; + } +#endif /* MY_ABC_HERE */ if (root->anon_dev) free_anon_bdev(root->anon_dev); - btrfs_drew_lock_destroy(&root->snapshot_lock); free_root_extent_buffers(root); kfree(root->free_ino_ctl); kfree(root->free_ino_pinned); @@ -2146,8 +2905,25 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info) fs_info->qgroup_ulist = NULL; fs_info->qgroup_rescan_running = false; mutex_init(&fs_info->qgroup_rescan_lock); +#ifdef MY_ABC_HERE + init_rwsem(&fs_info->inflight_reserve_lock); + fs_info->need_clear_reserve = false; +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +static void btrfs_init_usrquota(struct btrfs_fs_info *fs_info) +{ + spin_lock_init(&fs_info->usrquota_lock); + mutex_init(&fs_info->usrquota_ioctl_lock); + fs_info->usrquota_tree = RB_ROOT; + INIT_LIST_HEAD(&fs_info->dirty_usrquota); + INIT_LIST_HEAD(&fs_info->usrquota_ro_roots); + mutex_init(&fs_info->usrquota_ro_roots_lock); + fs_info->usrquota_flags = 0; +} +#endif /* MY_ABC_HERE */ + static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, struct btrfs_fs_devices *fs_devices) { @@ -2205,6 +2981,36 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, btrfs_alloc_workqueue(fs_info, "qgroup-rescan", flags, 1, 0); fs_info->discard_ctl.discard_workers = alloc_workqueue("btrfs_discard", WQ_UNBOUND | WQ_FREEZABLE, 1); +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + fs_info->syno_multiple_writeback_workers = + btrfs_alloc_workqueue_with_sysfs(fs_info, "syno-multi-wb", flags, max_active, 2); +#else /* MY_ABC_HERE */ + fs_info->syno_multiple_writeback_workers = + btrfs_alloc_workqueue(fs_info, "syno-multi-wb", flags, max_active, 2); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + fs_info->syno_cow_async_workers = + btrfs_alloc_workqueue(fs_info, "syno_cow_async_workers", flags | WQ_HIGHPRI, max_active, 2); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* for reduce cow ordered extent contention, we limit max active with 4 */ + fs_info->syno_cow_endio_workers = + btrfs_alloc_workqueue(fs_info, "syno_cow", flags, min_t(unsigned long, 4, max_active), 2); + fs_info->syno_nocow_endio_workers = + btrfs_alloc_workqueue(fs_info, "syno_nocow", flags, max_active, 2); + fs_info->syno_high_priority_endio_workers = + btrfs_alloc_workqueue(fs_info, "syno_high_priority", flags | WQ_HIGHPRI, WQ_DFL_ACTIVE, 2); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + fs_info->extent_workers = + btrfs_alloc_workqueue(fs_info, "extent-refs", flags, min_t(unsigned long, 4, max_active), 8); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + fs_info->syno_allocator.caching_workers = + btrfs_alloc_workqueue(fs_info, "syno-bg-cache", flags, max_active, 2); +#endif /* MY_ABC_HERE */ if (!(fs_info->workers && fs_info->delalloc_workers && fs_info->flush_workers && @@ -2215,7 +3021,25 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, fs_info->caching_workers && fs_info->readahead_workers && fs_info->fixup_workers && fs_info->delayed_workers && fs_info->qgroup_rescan_workers && - fs_info->discard_ctl.discard_workers)) { + fs_info->discard_ctl.discard_workers +#ifdef MY_ABC_HERE + && fs_info->syno_multiple_writeback_workers +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + && fs_info->syno_cow_async_workers +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + && fs_info->syno_cow_endio_workers + && fs_info->syno_nocow_endio_workers + && fs_info->syno_high_priority_endio_workers +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + && fs_info->extent_workers +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + && fs_info->syno_allocator.caching_workers +#endif /* MY_ABC_HERE */ + )) { return -ENOMEM; } @@ -2297,6 +3121,9 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) struct btrfs_root *root; struct btrfs_key location; int ret; +#ifdef MY_ABC_HERE + int err; +#endif /* MY_ABC_HERE */ BUG_ON(!fs_info->tree_root); @@ -2344,6 +3171,54 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); fs_info->data_reloc_root = root; +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, NO_QUOTA_TREE)) + goto skip_quota; + + // Try loading quota tree v2 + location.objectid = BTRFS_SYNO_QUOTA_V2_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + set_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags); + fs_info->quota_root = root; + } + + // Try loading quota tree v1 + location.objectid = BTRFS_QUOTA_TREE_OBJECTID; + if (fs_info->quota_root) + root = ERR_PTR(-EEXIST); + else + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + set_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags); + fs_info->quota_root = root; + } + + // Try loading usrquota tree v2 + location.objectid = BTRFS_SYNO_USRQUOTA_V2_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + set_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags); + fs_info->usrquota_root = root; + } + + // Try loading usrquota tree v1 + location.objectid = BTRFS_USRQUOTA_TREE_OBJECTID; + if (fs_info->usrquota_root) + root = ERR_PTR(-EEXIST); + else + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + set_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags); + fs_info->usrquota_root = root; + } + +skip_quota: +#else location.objectid = BTRFS_QUOTA_TREE_OBJECTID; root = btrfs_read_tree_root(tree_root, &location); if (!IS_ERR(root)) { @@ -2351,6 +3226,7 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); fs_info->quota_root = root; } +#endif /* MY_ABC_HERE */ location.objectid = BTRFS_UUID_TREE_OBJECTID; root = btrfs_read_tree_root(tree_root, &location); @@ -2374,6 +3250,65 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) fs_info->free_space_root = root; } +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, BLOCK_GROUP_HINT_TREE)) { + location.objectid = BTRFS_BLOCK_GROUP_HINT_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + fs_info->block_group_hint_root = root; + } else if (PTR_ERR(root) != -ENOENT) { + btrfs_clear_opt(fs_info->mount_opt, BLOCK_GROUP_HINT_TREE); + btrfs_warn(fs_info, "Failed to read block group hint tree"); + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE)) { + location.objectid = BTRFS_BLOCK_GROUP_CACHE_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + fs_info->block_group_cache_root = root; + // check block group cache tree consistent + err = btrfs_check_syno_block_group_cache_tree(fs_info); + if (err) { + set_bit(BTRFS_FS_BLOCK_GROUP_CACHE_TREE_BROKEN, &fs_info->flags); + btrfs_warn(fs_info, "block gorup cache tree is inconsistent, err:%d", err); + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + location.objectid = BTRFS_SYNO_USAGE_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + fs_info->syno_usage_root = root; + } + + location.objectid = BTRFS_SYNO_EXTENT_USAGE_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + fs_info->syno_extent_usage_root = root; + } + if (fs_info->syno_usage_root && fs_info->syno_extent_usage_root) + set_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + location.objectid = BTRFS_SYNO_FEATURE_TREE_OBJECTID; + root = btrfs_read_tree_root(tree_root, &location); + if (!IS_ERR(root)) { + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + fs_info->syno_feat_root = root; + } +#endif /* MY_ABC_HERE */ return 0; out: btrfs_warn(fs_info, "failed to read root (objectid=%llu): %d", @@ -2700,6 +3635,10 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info) return ret; } +#ifdef MY_ABC_HERE +#define SYNO_BTRFS_COMMIT_DEBUG_TIME ((90 * MSEC_PER_SEC)) // 90 sec. +#endif /* MY_ABC_HERE */ + void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) { INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); @@ -2734,6 +3673,11 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) spin_lock_init(&fs_info->eb_leak_lock); #endif extent_map_tree_init(&fs_info->mapping_tree); +#ifdef MY_ABC_HERE + atomic_set(&fs_info->nr_extent_maps, 0); + INIT_LIST_HEAD(&fs_info->extent_map_inode_list); + spin_lock_init(&fs_info->extent_map_inode_list_lock); +#endif /* MY_ABC_HERE */ btrfs_init_block_rsv(&fs_info->global_block_rsv, BTRFS_BLOCK_RSV_GLOBAL); btrfs_init_block_rsv(&fs_info->trans_block_rsv, BTRFS_BLOCK_RSV_TRANS); @@ -2750,8 +3694,17 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) atomic_set(&fs_info->nr_delayed_iputs, 0); atomic64_set(&fs_info->tree_mod_seq, 0); fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE; +#ifdef MY_ABC_HERE + fs_info->metadata_ratio = 50; +#else /* MY_ABC_HERE */ fs_info->metadata_ratio = 0; +#endif /* MY_ABC_HERE */ fs_info->defrag_inodes = RB_ROOT; +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&fs_info->defrag_inodes_list[0]); + INIT_LIST_HEAD(&fs_info->defrag_inodes_list[1]); + fs_info->reclaim_space_entry_count = 0; +#endif /* MY_ABC_HERE */ atomic64_set(&fs_info->free_chunk_space, 0); fs_info->tree_mod_log = RB_ROOT; fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL; @@ -2761,6 +3714,43 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) spin_lock_init(&fs_info->reada_lock); btrfs_init_ref_verify(fs_info); +#ifdef MY_ABC_HERE + /* syno feature tree */ + btrfs_syno_set_feat_tree_disable(fs_info); + fs_info->syno_feat_tree_status.version = BTRFS_SYNO_FEAT_TREE_VERSION; + fs_info->syno_feat_root = NULL; + mutex_init(&fs_info->syno_feat_tree_ioctl_lock); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mutex_init(&fs_info->free_space_analyze_ioctl_lock); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + atomic_set(&fs_info->syno_allocator.syno_allocator_refs, 0); + init_waitqueue_head(&fs_info->syno_allocator.syno_allocator_wait); + atomic_set(&fs_info->syno_allocator.legacy_allocator_refs, 0); + init_waitqueue_head(&fs_info->syno_allocator.legacy_allocator_wait); + btrfs_init_syno_allocator_bg_prefetch_work(&fs_info->syno_allocator.bg_prefetch_work); + fs_info->syno_allocator.bg_prefetch_running = true; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + atomic64_set(&fs_info->syno_meta_statistics.eb_disk_read, 0); + atomic64_set(&fs_info->syno_meta_statistics.search_key, 0); + atomic64_set(&fs_info->syno_meta_statistics.search_forward, 0); + atomic64_set(&fs_info->syno_meta_statistics.next_leaf, 0); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + fs_info->dedupe_info.inode = NULL; + fs_info->dedupe_info.hash_table = NULL; + fs_info->dedupe_info.cuckoo_idx = NULL; + fs_info->dedupe_info.table_size = 0; + fs_info->dedupe_info.cuckoo_size = 0; + fs_info->dedupe_info.seed = 1; + fs_info->dedupe_info.sample_rate = SZ_64K; + atomic_set(&fs_info->dedupe_info.valid, 0); + atomic_set(&fs_info->dedupe_info.modify, 0); + atomic_set(&fs_info->dedupe_info.ref, 0); +#endif /* MY_ABC_HERE */ + fs_info->thread_pool_size = min_t(unsigned long, num_online_cpus() + 2, 8); @@ -2770,10 +3760,29 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) btrfs_init_scrub(fs_info); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY fs_info->check_integrity_print_mask = 0; -#endif +#endif /* CONFIG_BTRFS_FS_CHECK_INTEGRITY */ +#ifdef MY_ABC_HERE + fs_info->snapshot_cleaner = 1; +#endif /* MY_ABC_HERE */ btrfs_init_balance(fs_info); btrfs_init_async_reclaim_work(fs_info); +#ifdef MY_ABC_HERE + atomic_set(&fs_info->syno_writeback_thread_count, 0); + fs_info->syno_writeback_thread_max = 0; + spin_lock_init(&fs_info->syno_multiple_writeback_lock); + INIT_LIST_HEAD(&fs_info->syno_dirty_lru_inodes); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + btrfs_init_async_metadata_cache_work(fs_info); + atomic_set(&fs_info->syno_metadata_block_group_update_count, 0); + fs_info->metadata_cache_enable = false; +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + spin_lock_init(&fs_info->mount_path_lock); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + spin_lock_init(&fs_info->block_group_cache_lock); fs_info->block_group_cache_tree = RB_ROOT; fs_info->first_logical_byte = (u64)-1; @@ -2794,7 +3803,15 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) sema_init(&fs_info->uuid_tree_rescan_sem, 1); btrfs_init_dev_replace_locks(fs_info); + +#ifdef MY_ABC_HERE + mutex_init(&fs_info->log_tree_rsv_alloc); +#endif /* MY_ABC_HERE */ + btrfs_init_qgroup(fs_info); +#ifdef MY_ABC_HERE + btrfs_init_usrquota(fs_info); +#endif /* MY_ABC_HERE */ btrfs_discard_init(fs_info); btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); @@ -2815,6 +3832,69 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) fs_info->swapfile_pins = RB_ROOT; fs_info->send_in_progress = 0; +#ifdef MY_ABC_HERE + atomic64_set(&fs_info->block_group_cnt, 0); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + mutex_init(&fs_info->block_group_hint_tree_mutex); + atomic_set(&fs_info->reada_block_group_threads, 0); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + atomic64_set(&fs_info->fsync_cnt, 0); + atomic64_set(&fs_info->fsync_full_commit_cnt, 0); + fs_info->commit_time_debug_ms = SYNO_BTRFS_COMMIT_DEBUG_TIME; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + spin_lock_init(&fs_info->syno_usage_lock); + btrfs_init_syno_usage_rescan_work(&fs_info->syno_usage_rescan_work); + btrfs_init_syno_usage_fast_rescan_work(&fs_info->syno_usage_fast_rescan_work); + btrfs_init_syno_usage_full_rescan_work(&fs_info->syno_usage_full_rescan_work); + INIT_LIST_HEAD(&fs_info->syno_usage_pending_fast_rescan_roots); + INIT_LIST_HEAD(&fs_info->syno_usage_pending_full_rescan_roots); + spin_lock_init(&fs_info->syno_usage_fast_rescan_lock); + spin_lock_init(&fs_info->syno_usage_full_rescan_lock); + mutex_init(&fs_info->syno_usage_ioctl_lock); + fs_info->syno_usage_fast_rescan_pid = 0; + fs_info->syno_usage_full_rescan_pid = 0; + atomic_set(&fs_info->syno_usage_pending_fast_rescan_count, 0); + atomic_set(&fs_info->syno_usage_pending_full_rescan_count, 0); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_set(&fs_info->syno_async_submit_nr, 0); + fs_info->syno_async_submit_throttle = 128; + init_waitqueue_head(&fs_info->syno_async_submit_queue_wait); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic64_set(&fs_info->syno_ordered_extent_nr, 0); + fs_info->syno_max_ordered_queue_size = 65536; + init_waitqueue_head(&fs_info->syno_ordered_queue_wait); + atomic64_set(&fs_info->syno_ordered_extent_processed_nr, 0); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + spin_lock_init(&fs_info->syno_rbd.lock); + INIT_LIST_HEAD(&fs_info->syno_rbd.pinned_meta_files); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_set(&fs_info->syno_async_delayed_ref_count, 0); + spin_lock_init(&fs_info->syno_delayed_ref_throttle_lock); + INIT_LIST_HEAD(&fs_info->syno_delayed_ref_throttle_tickets); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + btrfs_init_block_rsv(&fs_info->cleaner_block_rsv, BTRFS_BLOCK_RSV_TEMP); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + spin_lock_init(&fs_info->syno_orphan_cleanup.lock); + INIT_LIST_HEAD(&fs_info->syno_orphan_cleanup.roots); + fs_info->syno_orphan_cleanup.enable = true; +#endif /* MY_ABC_HERE */ } static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block *sb) @@ -2845,6 +3925,33 @@ static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block if (ret) return ret; +#ifdef MY_ABC_HERE + ret = percpu_counter_init(&fs_info->eb_hit, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->eb_miss, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->meta_write_pages, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->data_write_pages, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->delayed_meta_ref, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->delayed_data_ref, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->write_flush, 0, GFP_KERNEL); + if (ret) + return ret; + ret = percpu_counter_init(&fs_info->write_fua, 0, GFP_KERNEL); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ + fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root), GFP_KERNEL); if (!fs_info->delayed_root) @@ -2891,6 +3998,230 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info) return 0; } +/* + * Some options only have meaning at mount time and shouldn't persist across + * remounts, or be displayed. Clear these at the end of mount and remount + * code paths. + */ +void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info) +{ + btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT); + btrfs_clear_opt(fs_info->mount_opt, CLEAR_CACHE); +} + +/* + * Mounting logic specific to read-write file systems. Shared by open_ctree + * and btrfs_remount when remounting from read-only to read-write. + */ +#ifdef MY_ABC_HERE +int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info, struct syno_btrfs_mount_stats *stats) +#else +int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) +#endif /* MY_ABC_HERE */ +{ + int ret; + const bool cache_opt = btrfs_test_opt(fs_info, SPACE_CACHE); + bool clear_free_space_tree = false; +#ifdef MY_ABC_HERE + ktime_t temp_t; +#endif /* MY_ABC_HERE */ + + if (btrfs_test_opt(fs_info, CLEAR_CACHE) && + btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { + clear_free_space_tree = true; + } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && + !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { + btrfs_warn(fs_info, "free space tree is invalid"); + clear_free_space_tree = true; + } + + if (clear_free_space_tree) { + btrfs_info(fs_info, "clearing free space tree"); + ret = btrfs_clear_free_space_tree(fs_info); + if (ret) { + btrfs_warn(fs_info, + "failed to clear free space tree: %d", ret); + goto out; + } + } + +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_cleanup_fs_roots(fs_info); +#ifdef MY_ABC_HERE + if (stats != NULL) + stats->cleanup_fs_roots_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) + goto out; + + down_read(&fs_info->cleanup_work_sem); +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) || + (ret = btrfs_orphan_cleanup(fs_info->tree_root))) { +#ifdef MY_ABC_HERE + if (stats != NULL) + stats->orphan_cleanup_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + up_read(&fs_info->cleanup_work_sem); + goto out; + } +#ifdef MY_ABC_HERE + if (stats != NULL) + stats->orphan_cleanup_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + up_read(&fs_info->cleanup_work_sem); +#endif /* MY_ABC_HERE */ + + mutex_lock(&fs_info->cleaner_mutex); + ret = btrfs_recover_relocation(fs_info->tree_root); + mutex_unlock(&fs_info->cleaner_mutex); + if (ret < 0) { + btrfs_warn(fs_info, "failed to recover relocation: %d", ret); + goto out; + } + + if (btrfs_test_opt(fs_info, FREE_SPACE_TREE) && + !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { + btrfs_info(fs_info, "creating free space tree"); +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_create_free_space_tree(fs_info); +#ifdef MY_ABC_HERE + if (stats != NULL) + stats->create_free_space_tree_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) { + btrfs_warn(fs_info, + "failed to create free space tree: %d", ret); + goto out; + } + } + + if (cache_opt != btrfs_free_space_cache_v1_active(fs_info)) { + ret = btrfs_set_free_space_cache_v1_active(fs_info, cache_opt); + if (ret) + goto out; + } + + ret = btrfs_resume_balance_async(fs_info); + if (ret) + goto out; + + ret = btrfs_resume_dev_replace_async(fs_info); + if (ret) { + btrfs_warn(fs_info, "failed to resume dev_replace"); + goto out; + } + + btrfs_qgroup_rescan_resume(fs_info); +#ifdef MY_ABC_HERE + btrfs_syno_usage_rescan_resume(fs_info); +#endif /* MY_ABC_HERE */ + + if (!fs_info->uuid_root) { + btrfs_info(fs_info, "creating UUID tree"); +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_create_uuid_tree(fs_info); +#ifdef MY_ABC_HERE + if (stats != NULL) + stats->create_uuid_tree_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) { + btrfs_warn(fs_info, + "failed to create the UUID tree %d", ret); + goto out; + } + } + +out: + return ret; +} + +#ifdef MY_ABC_HERE +static void free_all_syno_rbd_meta_file_inodes(struct btrfs_fs_info *fs_info) +{ + struct btrfs_inode *inode; + + spin_lock(&fs_info->syno_rbd.lock); + while (!list_empty(&fs_info->syno_rbd.pinned_meta_files)) { + inode = list_first_entry(&fs_info->syno_rbd.pinned_meta_files, struct btrfs_inode, syno_rbd_meta_file); + spin_unlock(&fs_info->syno_rbd.lock); + + btrfs_unpin_rbd_meta_file(&inode->vfs_inode); + + cond_resched(); + spin_lock(&fs_info->syno_rbd.lock); + } + spin_unlock(&fs_info->syno_rbd.lock); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int print_mount_time_msec = 90000; +module_param(print_mount_time_msec, int, S_IRUGO|S_IWUSR); + +static void print_mount_stats(struct btrfs_fs_info *fs_info, + struct syno_btrfs_mount_stats *stats) +{ + s64 total = ktime_to_ns(ktime_sub(ktime_get(), stats->start_time)); + s64 others = total - + stats->read_chunk_tree_time - + stats->read_block_groups_time - + stats->read_qgroup_config_time - + stats->read_usrquota_config_time - + stats->read_syno_usage_config_time - + stats->activate_all_rbd_meta_files_time - + stats->replay_log_time - + stats->cleanup_fs_roots_time - + stats->create_block_group_cache_tree_time - + stats->create_free_space_tree_time - + stats->orphan_cleanup_time - + stats->create_uuid_tree_time; + + if (print_mount_time_msec > div_s64(total, NSEC_PER_MSEC)) + return; + + btrfs_warn(fs_info, "btrfs mount open_ctree: " + "total time: %lld, " + "read chunk tree: %lld, " + "read block groups: %lld, " + "read qgroup config: %lld, " + "read usrquota config: %lld, " + "read syno usage config: %lld, " + "activate all rbd meta files: %lld, " + "replay log: %lld, " + "cleanup fs roots: %lld, " + "create block group cache tree: %lld, " + "create free space tree: %lld, " + "orphan cleanup: %lld, " + "create uuid tree: %lld, " + "others: %lld", + div_s64(total, NSEC_PER_USEC), + div_s64(stats->read_chunk_tree_time, NSEC_PER_USEC), + div_s64(stats->read_block_groups_time, NSEC_PER_USEC), + div_s64(stats->read_qgroup_config_time, NSEC_PER_USEC), + div_s64(stats->read_usrquota_config_time, NSEC_PER_USEC), + div_s64(stats->read_syno_usage_config_time, NSEC_PER_USEC), + div_s64(stats->activate_all_rbd_meta_files_time, NSEC_PER_USEC), + div_s64(stats->replay_log_time, NSEC_PER_USEC), + div_s64(stats->cleanup_fs_roots_time, NSEC_PER_USEC), + div_s64(stats->create_block_group_cache_tree_time, NSEC_PER_USEC), + div_s64(stats->create_free_space_tree_time, NSEC_PER_USEC), + div_s64(stats->orphan_cleanup_time, NSEC_PER_USEC), + div_s64(stats->create_uuid_tree_time, NSEC_PER_USEC), + div_s64(others, NSEC_PER_USEC)); +} +#endif /* MY_ABC_HERE */ + int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices, char *options) { @@ -2898,6 +4229,13 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device u32 nodesize; u32 stripesize; u64 generation; +#ifdef MY_ABC_HERE + u64 syno_generation; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u64 syno_capability_generation; + u64 syno_capability_flags; +#endif /* MY_ABC_HERE */ u64 features; u16 csum_type; struct btrfs_super_block *disk_super; @@ -2906,8 +4244,32 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device struct btrfs_root *chunk_root; int ret; int err = -EINVAL; - int clear_free_space_tree = 0; int level; +#ifdef MY_ABC_HERE + struct syno_btrfs_mount_stats stats; + ktime_t temp_t; + memset(&stats, 0, sizeof(stats)); + stats.start_time = ktime_get(); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BUILD_BUG_ON(sizeof(struct btrfs_super_block) != 4096); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ret = kfifo_alloc(&fs_info->cksumfailed_files, PAGE_SIZE, GFP_NOFS); + if (ret) { + printk(KERN_WARNING "BTRFS: failed to alloc cksumfailed files record\n"); + err = ret; + goto fail_kfifo; + } + spin_lock_init(&fs_info->cksumfailed_files_write_lock); + fs_info->correction_suppress_log = DATA_CORRECTION_RATE_LIMIT; + fs_info->correction_disable = false; + + fs_info->correction_record = RB_ROOT; + spin_lock_init(&fs_info->correction_record_lock); +#endif /* MY_ABC_HERE */ ret = init_mount_fs_info(fs_info, sb); if (ret) { @@ -3013,11 +4375,43 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR) set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state); +#ifdef MY_ABC_HERE + generation = btrfs_super_generation(disk_super); + syno_generation = btrfs_super_syno_generation(disk_super); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_capability_generation = + btrfs_super_syno_capability_generation(disk_super); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + spin_lock_init(&fs_info->locker_lock); + ktime_get_raw_ts64(&fs_info->locker_prev_raw_clock); + fs_info->locker_clock.tv_sec = btrfs_super_syno_locker_clock(disk_super); + INIT_DELAYED_WORK(&fs_info->locker_update_work, btrfs_syno_locker_update_work_fn); + fs_info->locker_update_interval = 24*60*60; + btrfs_syno_locker_update_work_kick(fs_info); +#endif /* MY_ABC_HERE */ + /* * In the long term, we'll store the compression type in the super * block, and it'll be used for per file compression control. */ +#ifdef MY_ABC_HERE + fs_info->compress_type = BTRFS_COMPRESS_DEFAULT; +#else fs_info->compress_type = BTRFS_COMPRESS_ZLIB; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* block group hint tree is enabled by default */ + btrfs_set_opt(fs_info->mount_opt, BLOCK_GROUP_HINT_TREE); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* syno allocator is enabled by default */ + btrfs_set_opt(fs_info->mount_opt, SYNO_ALLOCATOR); +#endif /* MY_ABC_HERE */ ret = btrfs_parse_options(fs_info, options, sb->s_flags); if (ret) { @@ -3095,6 +4489,69 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device goto fail_alloc; } +#ifdef MY_ABC_HERE + if (btrfs_super_compat_ro_flags(disk_super) & BTRFS_FEATURE_COMPAT_RO_LOCKER) { + if (!sb_rdonly(sb) && !btrfs_syno_locker_feature_is_support()) { + btrfs_err(fs_info, "cannot mount read-write because of no locker support"); + err = -EINVAL; + goto fail_alloc; + } + if (syno_generation != generation) { + btrfs_warn(fs_info, "locker was enabled. gen(%llu) != syno_gen(%llu)", + generation, syno_generation); + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + features = btrfs_super_compat_flags(disk_super); + if (features & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) { + if (syno_generation != generation) { + btrfs_warn(fs_info, + "Clear syno caseless feature, gen(%llu) != syno_gen(%llu), label:(%s)\n", + generation, syno_generation, + disk_super->label); + features &= ~BTRFS_FEATURE_COMPAT_SYNO_CASELESS; + btrfs_set_super_compat_flags(disk_super, features); + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + syno_capability_flags = btrfs_super_syno_capability_flags(disk_super); + + if (syno_capability_generation != generation && syno_capability_flags) { + btrfs_warn(fs_info, + "syno_capability_gen(%llu) is not match gen(%llu), " + "clear all capability flags (%llu).", + syno_capability_generation, generation, + syno_capability_flags); + syno_capability_flags = 0ULL; + btrfs_set_super_syno_capability_flags(disk_super, + syno_capability_flags); + } + + if (syno_capability_flags & ~BTRFS_FEATURE_SYNO_CAPABILITY_SUPP) { + btrfs_warn(fs_info, + "cannot support these features %llx", + syno_capability_flags & ~BTRFS_FEATURE_SYNO_CAPABILITY_SUPP); + syno_capability_flags &= BTRFS_FEATURE_SYNO_CAPABILITY_SUPP; + btrfs_set_super_syno_capability_flags(disk_super, + syno_capability_flags); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!fs_devices->rbd_enabled && + (syno_capability_flags & BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META)) { + syno_capability_flags &= ~BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META; + btrfs_warn(fs_info, + "Rbd device is disabled, we drop rbd capability."); + btrfs_set_super_syno_capability_flags(disk_super, + syno_capability_flags); + } +#endif /* MY_ABC_HERE */ + ret = btrfs_init_workqueues(fs_info, fs_devices); if (ret) { err = ret; @@ -3137,12 +4594,31 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device offsetof(struct btrfs_header, chunk_tree_uuid), BTRFS_UUID_SIZE); +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ ret = btrfs_read_chunk_tree(fs_info); +#ifdef MY_ABC_HERE + stats.read_chunk_tree_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ if (ret) { btrfs_err(fs_info, "failed to read chunk tree: %d", ret); goto fail_tree_roots; } +#ifdef MY_ABC_HERE + // For small volume, we shrink size of empty_cluster. + if (!fs_devices->total_rw_bytes) { + fs_info->data_alloc_cluster.empty_cluster = 0; + fs_info->data_alloc_cluster.downgrade_limit = 0; + } else if (fs_devices->total_rw_bytes < 16ULL * SZ_1G) { + fs_info->data_alloc_cluster.empty_cluster = + max(rounddown_pow_of_two(fs_devices->total_rw_bytes) >> 5, + (unsigned long) (1 << + (fs_info->data_alloc_cluster.downgrade_limit + 1))); + } +#endif /* MY_ABC_HERE */ + /* * Keep the devid that is marked to be the target device for the * device replace procedure @@ -3197,11 +4673,23 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device btrfs_free_extra_devids(fs_devices, 1); +#ifdef MY_ABC_HERE + ret = btrfs_debugfs_add_mounted(fs_info); + if (ret) { + pr_err("BTRFS: failed to init debugfs interface: %d\n", ret); + goto fail_block_groups; + } +#endif /* MY_ABC_HERE */ + ret = btrfs_sysfs_add_fsid(fs_devices); if (ret) { btrfs_err(fs_info, "failed to init sysfs fsid interface: %d", ret); +#ifdef MY_ABC_HERE + goto fail_debugfs; +#else goto fail_block_groups; +#endif /* MY_ABC_HERE */ } ret = btrfs_sysfs_add_mounted(fs_info); @@ -3216,12 +4704,37 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device goto fail_sysfs; } +#ifdef MY_ABC_HERE + fs_info->log_tree_rsv_start = btrfs_super_syno_log_tree_rsv(disk_super); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, NO_BLOCK_GROUP)) + ret = 0; + else +#endif /* MY_ABC_HERE */ ret = btrfs_read_block_groups(fs_info); +#ifdef MY_ABC_HERE + stats.read_block_groups_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ if (ret) { +#ifdef MY_ABC_HERE + btrfs_err(fs_info, "failed to read block groups: %d," + "use ro,no_block_group,nologreplay skip it for rescue", ret); +#else /* MY_ABC_HERE */ btrfs_err(fs_info, "failed to read block groups: %d", ret); +#endif /* MY_ABC_HERE */ goto fail_sysfs; } +#ifdef MY_ABC_HERE + if (!fs_info->log_tree_rsv_size) + fs_info->log_tree_rsv_start = 0; +#endif /* MY_ABC_HERE */ + if (!sb_rdonly(sb) && !btrfs_check_rw_degradable(fs_info, NULL)) { btrfs_warn(fs_info, "writable mount is not allowed due to too many missing devices"); @@ -3263,43 +4776,138 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device ret); } #endif +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ ret = btrfs_read_qgroup_config(fs_info); - if (ret) +#ifdef MY_ABC_HERE + stats.read_qgroup_config_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) { +#ifdef MY_ABC_HERE + btrfs_err(fs_info, "failed to read qgroup tree: %d, use no_quota_tree for rescue", ret); +#endif /* MY_ABC_HERE */ goto fail_trans_kthread; + } + +#ifdef MY_ABC_HERE + /* + * feature-tree should be loaded before quota. + * + * some btrfs_root attributes are stored in feature-tree and should be loaded + * after feature-tree is ready. When loading quota, it'll load btrfs_root + * indirectly, but feature-tree is not ready at that time. + */ + ret = btrfs_syno_feat_tree_load_status_from_disk(fs_info); + if (ret) { + btrfs_err(fs_info, "failed to load syno feature tree, ret: [%d].", ret); + goto fail_qgroup; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_read_usrquota_config(fs_info); +#ifdef MY_ABC_HERE + stats.read_usrquota_config_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) { + btrfs_err(fs_info, "failed to read usrquota tree: %d, use no_quota_tree for rescue", ret); + goto fail_qgroup; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_read_syno_usage_config(fs_info); +#ifdef MY_ABC_HERE + stats.read_syno_usage_config_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) + goto fail_qgroup; +#endif /* MY_ABC_HERE */ if (btrfs_build_ref_tree(fs_info)) btrfs_err(fs_info, "couldn't build ref tree"); +#ifdef MY_ABC_HERE + if (syno_capability_flags & BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META) { + if (!btrfs_syno_check_feat_tree_enable(fs_info)) { + btrfs_err(fs_info, "feature tree is not enabled"); + err = -EINVAL; + goto fail_qgroup; + } +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_activate_all_rbd_meta_files(fs_info); +#ifdef MY_ABC_HERE + stats.activate_all_rbd_meta_files_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ + if (ret) { + btrfs_err(fs_info, + "failed to activate rbd meta files, ret: %d", ret); + err = ret; + goto fail_qgroup; + } + fs_info->syno_rbd.first_mapping_table_offset = + btrfs_super_syno_rbd_first_mapping_table_offset(disk_super); + } else { + fs_info->syno_rbd.first_mapping_table_offset = 0; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, DROP_LOG_TREE) && + btrfs_super_log_root(disk_super) != 0) { + if (fs_devices->rw_devices == 0) { + btrfs_warn(fs_info, "drop log required on RO media"); + ret = -EIO; + goto fail_qgroup; + } + + btrfs_warn(fs_info, "clear log tree, old log root:%lld(leve:%d)", + btrfs_super_log_root(disk_super), + btrfs_super_log_root_level(disk_super)); + + btrfs_set_super_log_root(fs_info->super_for_commit, 0); + btrfs_set_super_log_root(disk_super, 0); + btrfs_set_super_log_root_level(fs_info->super_for_commit, 0); + btrfs_set_super_log_root_level(disk_super, 0); + ret = write_all_supers(fs_info, 0); + if (ret) { + goto fail_qgroup; + } + } +#endif /* MY_ABC_HERE */ + /* do not make disk changes in broken FS or nologreplay is given */ if (btrfs_super_log_root(disk_super) != 0 && !btrfs_test_opt(fs_info, NOLOGREPLAY)) { btrfs_info(fs_info, "start tree-log replay"); +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ ret = btrfs_replay_log(fs_info, fs_devices); +#ifdef MY_ABC_HERE + stats.replay_log_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ if (ret) { err = ret; goto fail_qgroup; } } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ ret = btrfs_find_orphan_roots(fs_info); if (ret) goto fail_qgroup; - - if (!sb_rdonly(sb)) { - ret = btrfs_cleanup_fs_roots(fs_info); - if (ret) - goto fail_qgroup; - - mutex_lock(&fs_info->cleaner_mutex); - ret = btrfs_recover_relocation(tree_root); - mutex_unlock(&fs_info->cleaner_mutex); - if (ret < 0) { - btrfs_warn(fs_info, "failed to recover relocation: %d", - ret); - err = -EINVAL; - goto fail_qgroup; - } - } +#endif /* MY_ABC_HERE */ fs_info->fs_root = btrfs_get_fs_root(fs_info, BTRFS_FS_TREE_OBJECTID, true); if (IS_ERR(fs_info->fs_root)) { @@ -3310,98 +4918,99 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device } if (sb_rdonly(sb)) - return 0; + goto clear_oneshot; - if (btrfs_test_opt(fs_info, CLEAR_CACHE) && - btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { - clear_free_space_tree = 1; - } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && - !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { - btrfs_warn(fs_info, "free space tree is invalid"); - clear_free_space_tree = 1; +#ifdef MY_ABC_HERE + ret = btrfs_start_pre_rw_mount(fs_info, &stats); +#else + ret = btrfs_start_pre_rw_mount(fs_info); +#endif /* MY_ABC_HERE */ + if (ret) { + close_ctree(fs_info); +#ifdef MY_ABC_HERE + print_mount_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ + return ret; } - if (clear_free_space_tree) { - btrfs_info(fs_info, "clearing free space tree"); - ret = btrfs_clear_free_space_tree(fs_info); +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, SYNO_ALLOCATOR)) + queue_work(system_unbound_wq, &fs_info->syno_allocator.bg_prefetch_work); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_BLOCK_GROUP_CACHE_TREE_BROKEN, &fs_info->flags) || + (!btrfs_test_opt(fs_info, BLOCK_GROUP_CACHE_TREE) && btrfs_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE))) { + ret = btrfs_clear_block_group_cache_tree(fs_info); if (ret) { - btrfs_warn(fs_info, - "failed to clear free space tree: %d", ret); + btrfs_warn(fs_info, "failed to clear block group cache tree: %d", ret); close_ctree(fs_info); +#ifdef MY_ABC_HERE + print_mount_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ return ret; } } - - if (btrfs_test_opt(fs_info, FREE_SPACE_TREE) && - !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { - btrfs_info(fs_info, "creating free space tree"); - ret = btrfs_create_free_space_tree(fs_info); + if (btrfs_test_opt(fs_info, BLOCK_GROUP_CACHE_TREE) && + !btrfs_fs_compat(fs_info, BLOCK_GROUP_CACHE_TREE) && + !test_bit(BTRFS_FS_BLOCK_GROUP_CACHE_TREE_BROKEN, &fs_info->flags)) { +#ifdef MY_ABC_HERE + temp_t = ktime_get(); +#endif /* MY_ABC_HERE */ + ret = btrfs_create_block_group_cache_tree(fs_info); +#ifdef MY_ABC_HERE + stats.create_block_group_cache_tree_time = ktime_to_ns(ktime_sub(ktime_get(), temp_t)); +#endif /* MY_ABC_HERE */ if (ret) { - btrfs_warn(fs_info, - "failed to create free space tree: %d", ret); + btrfs_warn(fs_info, "failed to create block group cache tree: %d", ret); close_ctree(fs_info); +#ifdef MY_ABC_HERE + print_mount_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ return ret; } } +#endif /* MY_ABC_HERE */ - down_read(&fs_info->cleanup_work_sem); - if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) || - (ret = btrfs_orphan_cleanup(fs_info->tree_root))) { - up_read(&fs_info->cleanup_work_sem); - close_ctree(fs_info); - return ret; - } - up_read(&fs_info->cleanup_work_sem); - - ret = btrfs_resume_balance_async(fs_info); - if (ret) { - btrfs_warn(fs_info, "failed to resume balance: %d", ret); - close_ctree(fs_info); - return ret; - } - - ret = btrfs_resume_dev_replace_async(fs_info); - if (ret) { - btrfs_warn(fs_info, "failed to resume device replace: %d", ret); - close_ctree(fs_info); - return ret; - } - - btrfs_qgroup_rescan_resume(fs_info); btrfs_discard_resume(fs_info); - if (!fs_info->uuid_root) { - btrfs_info(fs_info, "creating UUID tree"); - ret = btrfs_create_uuid_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to create the UUID tree: %d", ret); - close_ctree(fs_info); - return ret; - } - } else if (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || - fs_info->generation != - btrfs_super_uuid_tree_generation(disk_super)) { + if (fs_info->uuid_root && + (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || +#ifdef MY_ABC_HERE + !test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags) +#else /* MY_ABC_HERE */ + fs_info->generation != btrfs_super_uuid_tree_generation(disk_super) +#endif /* MY_ABC_HERE */ + )) { btrfs_info(fs_info, "checking UUID tree"); ret = btrfs_check_uuid_tree(fs_info); if (ret) { btrfs_warn(fs_info, "failed to check the UUID tree: %d", ret); close_ctree(fs_info); +#ifdef MY_ABC_HERE + print_mount_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ return ret; } } + set_bit(BTRFS_FS_OPEN, &fs_info->flags); - /* - * backuproot only affect mount behavior, and if open_ctree succeeded, - * no need to keep the flag - */ - btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT); +clear_oneshot: + btrfs_clear_oneshot_options(fs_info); +#ifdef MY_ABC_HERE + print_mount_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ return 0; - fail_qgroup: +#ifdef MY_ABC_HERE + free_all_syno_rbd_meta_file_inodes(fs_info); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_free_usrquota_config(fs_info); +#endif /* MY_ABC_HERE */ btrfs_free_qgroup_config(fs_info); fail_trans_kthread: kthread_stop(fs_info->transaction_kthread); @@ -3422,6 +5031,11 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device fail_fsdev_sysfs: btrfs_sysfs_remove_fsid(fs_info->fs_devices); +#ifdef MY_ABC_HERE +fail_debugfs: + btrfs_debugfs_remove_mounted(fs_info); +#endif /* MY_ABC_HERE */ + fail_block_groups: btrfs_put_block_group_cache(fs_info); @@ -3438,8 +5052,21 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device btrfs_mapping_tree_free(&fs_info->mapping_tree); iput(fs_info->btree_inode); +#ifdef MY_ABC_HERE + if (fs_info->locker_update_interval) + cancel_delayed_work_sync(&fs_info->locker_update_work); +#endif /* MY_ABC_HERE */ + fail: btrfs_close_devices(fs_info->fs_devices); +#ifdef MY_ABC_HERE + kfifo_free(&fs_info->cksumfailed_files); +fail_kfifo: +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + print_mount_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ return err; } ALLOW_ERROR_INJECTION(open_ctree, ERRNO); @@ -3612,6 +5239,10 @@ static int write_dev_supers(struct btrfs_device *device, if (i == 0 && !btrfs_test_opt(device->fs_info, NOBARRIER)) bio->bi_opf |= REQ_FUA; +#ifdef MY_ABC_HERE + if (bio->bi_opf & REQ_FUA) + percpu_counter_add_batch(&device->fs_info->write_fua, 1, SZ_128M); +#endif /* MY_ABC_HERE */ btrfsic_submit_bio(bio); } return errors < i ? 0 : -1; @@ -3705,6 +5336,9 @@ static void write_dev_flush(struct btrfs_device *device) btrfsic_submit_bio(bio); set_bit(BTRFS_DEV_STATE_FLUSH_SENT, &device->dev_state); +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&device->fs_info->write_flush, 1, SZ_128M); +#endif /* MY_ABC_HERE */ } /* @@ -3942,6 +5576,13 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info, if (test_and_clear_bit(BTRFS_ROOT_IN_RADIX, &root->state)) drop_ref = true; spin_unlock(&fs_info->fs_roots_radix_lock); +#ifdef MY_ABC_HERE + if (!list_empty(&root->syno_orphan_cleanup.root)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + list_del_init(&root->syno_orphan_cleanup.root); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } +#endif /* MY_ABC_HERE */ if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { ASSERT(root->log_root == NULL); @@ -3997,7 +5638,13 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) if (!gang[i]) continue; root_objectid = gang[i]->root_key.objectid; +#ifdef MY_ABC_HERE + down_read(&fs_info->cleanup_work_sem); +#endif /* MY_ABC_HERE */ err = btrfs_orphan_cleanup(gang[i]); +#ifdef MY_ABC_HERE + up_read(&fs_info->cleanup_work_sem); +#endif /* MY_ABC_HERE */ if (err) break; btrfs_put_root(gang[i]); @@ -4049,6 +5696,10 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) /* wait for the qgroup rescan worker to stop */ btrfs_qgroup_wait_for_completion(fs_info, false); +#ifdef MY_ABC_HERE + cancel_delayed_work_sync(&fs_info->locker_update_work); +#endif /* MY_ABC_HERE */ + /* wait for the uuid_scan task to finish */ down(&fs_info->uuid_tree_rescan_sem); /* avoid complains from lockdep et al., set sem back to initial state */ @@ -4070,6 +5721,26 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) cancel_work_sync(&fs_info->async_reclaim_work); cancel_work_sync(&fs_info->async_data_reclaim_work); +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_async_metadata_reclaim_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_async_data_flush_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_async_metadata_flush_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->async_metadata_cache_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_usage_rescan_work); + cancel_work_sync(&fs_info->syno_usage_fast_rescan_work); + cancel_work_sync(&fs_info->syno_usage_full_rescan_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_allocator.bg_prefetch_work); +#endif /* MY_ABC_HERE */ /* Cancel or finish ongoing discard work */ btrfs_discard_cleanup(fs_info); @@ -4109,6 +5780,14 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) ASSERT(list_empty(&fs_info->delayed_iputs)); set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags); +#ifdef MY_ABC_HERE + if (btrfs_check_usrquota_leak(fs_info)) { + WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); + btrfs_err(fs_info, "user quota reserved space leaked"); + } + btrfs_free_usrquota_config(fs_info); +#endif /* MY_ABC_HERE */ + if (btrfs_check_quota_leak(fs_info)) { WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); btrfs_err(fs_info, "qgroup reserved space leaked"); @@ -4117,6 +5796,10 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) btrfs_free_qgroup_config(fs_info); ASSERT(list_empty(&fs_info->delalloc_roots)); +#ifdef MY_ABC_HERE + free_all_syno_rbd_meta_file_inodes(fs_info); +#endif /* MY_ABC_HERE */ + if (percpu_counter_sum(&fs_info->delalloc_bytes)) { btrfs_info(fs_info, "at unmount delalloc count %lld", percpu_counter_sum(&fs_info->delalloc_bytes)); @@ -4126,6 +5809,10 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) btrfs_info(fs_info, "at unmount dio bytes count %lld", percpu_counter_sum(&fs_info->dio_bytes)); +#ifdef MY_ABC_HERE + btrfs_debugfs_remove_mounted(fs_info); +#endif /* MY_ABC_HERE */ + btrfs_sysfs_remove_mounted(fs_info); btrfs_sysfs_remove_fsid(fs_info->fs_devices); @@ -4160,6 +5847,10 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_close_devices(fs_info->fs_devices); +#ifdef MY_ABC_HERE + kfifo_free(&fs_info->cksumfailed_files); + correction_destroy_locked_record(fs_info); +#endif /* MY_ABC_HERE */ } int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, @@ -4227,7 +5918,10 @@ static void __btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info, * looks as though older kernels can get into trouble with * this code, they end up stuck in balance_dirty_pages forever */ +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ int ret; +#endif /* MY_ABC_HERE */ if (current->flags & PF_MEMALLOC) return; @@ -4235,12 +5929,16 @@ static void __btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info, if (flush_delayed) btrfs_balance_delayed_items(fs_info); +#ifdef MY_ABC_HERE + btrfs_syno_btree_balance_dirty(fs_info, true); +#else /* MY_ABC_HERE */ ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes, BTRFS_DIRTY_METADATA_THRESH, fs_info->dirty_metadata_batch); if (ret > 0) { balance_dirty_pages_ratelimited(fs_info->btree_inode->i_mapping); } +#endif /* MY_ABC_HERE */ } void btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info) @@ -4357,6 +6055,9 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_node *ref; int ret = 0; +#ifdef MY_ABC_HERE + struct btrfs_delayed_data_ref *data_ref = NULL; +#endif /* MY_ABC_HERE */ delayed_refs = &trans->delayed_refs; @@ -4386,6 +6087,14 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, RB_CLEAR_NODE(&ref->ref_node); if (!list_empty(&ref->add_list)) list_del(&ref->add_list); +#ifdef MY_ABC_HERE + if (ref->type == BTRFS_EXTENT_DATA_REF_KEY || + ref->type == BTRFS_SHARED_DATA_REF_KEY) { + data_ref = btrfs_delayed_node_to_data_ref(ref); + if (data_ref->syno_usage) + atomic_dec(&delayed_refs->num_syno_usage_entries); + } +#endif /* MY_ABC_HERE */ atomic_dec(&delayed_refs->num_entries); btrfs_put_delayed_ref(ref); } diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 182540bdcea0..3c3e385a1864 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -27,6 +30,24 @@ enum btrfs_wq_endio_type { BTRFS_WQ_ENDIO_RAID56, }; +#ifdef MY_ABC_HERE +struct syno_btrfs_mount_stats { + ktime_t start_time; + s64 read_chunk_tree_time; + s64 read_block_groups_time; + s64 read_qgroup_config_time; + s64 read_usrquota_config_time; + s64 read_syno_usage_config_time; + s64 activate_all_rbd_meta_files_time; + s64 replay_log_time; + s64 cleanup_fs_roots_time; + s64 create_block_group_cache_tree_time; + s64 create_free_space_tree_time; + s64 orphan_cleanup_time; + s64 create_uuid_tree_time; +}; +#endif /* MY_ABC_HERE */ + static inline u64 btrfs_sb_offset(int mirror) { u64 start = SZ_16K; @@ -35,6 +56,15 @@ static inline u64 btrfs_sb_offset(int mirror) return BTRFS_SUPER_INFO_OFFSET; } +#if defined(MY_ABC_HERE) +struct btrfs_new_fs_root_args { +#ifdef MY_ABC_HERE + /* Preallocated syno delalloc bytes */ + struct percpu_counter *syno_delalloc_bytes; +#endif /* MY_ABC_HERE */ +}; +#endif /* MY_ABC_HERE */ + struct btrfs_device; struct btrfs_fs_devices; @@ -50,6 +80,12 @@ struct extent_buffer *btrfs_find_create_tree_block( struct btrfs_fs_info *fs_info, u64 bytenr); void btrfs_clean_tree_block(struct extent_buffer *buf); +void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info, struct syno_btrfs_mount_stats *stats); +#else +int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices, char *options); @@ -61,6 +97,10 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, int btrfs_commit_super(struct btrfs_fs_info *fs_info); struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, struct btrfs_key *key); +#if defined(MY_ABC_HERE) +void btrfs_free_new_fs_root_args(struct btrfs_new_fs_root_args *args); +struct btrfs_new_fs_root_args *btrfs_alloc_new_fs_root_args(void); +#endif /* MY_ABC_HERE */ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info); @@ -68,10 +108,18 @@ void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info); struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, u64 objectid, bool check_ref); struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info, - u64 objectid, dev_t anon_dev); + u64 objectid, dev_t anon_dev +#if defined(MY_ABC_HERE) + , struct btrfs_new_fs_root_args *new_fs_root_args +#endif /* MY_ABC_HERE */ + ); struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 objectid); +#ifdef MY_ABC_HERE +struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, + u64 root_id); +#endif /* MY_ABC_HERE */ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info); int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); @@ -82,6 +130,10 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info, int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio, u64 phy_offset, struct page *page, u64 start, u64 end, int mirror); +#ifdef MY_ABC_HERE +void btrfs_metadata_io_failed(struct extent_buffer *eb, struct page *page, + int failed_mirror, int correction_err); +#endif /* MY_ABC_HERE */ blk_status_t btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, int mirror_num, unsigned long bio_flags); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS @@ -116,6 +168,12 @@ blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num, unsigned long bio_flags, u64 bio_offset, void *private_data, extent_submit_bio_start_t *submit_bio_start); +#ifdef MY_ABC_HERE +blk_status_t btrfs_wq_submit_bio_throttle(struct btrfs_fs_info *fs_info, struct bio *bio, + int mirror_num, unsigned long bio_flags, + u64 bio_offset, void *private_data, + extent_submit_bio_start_t *submit_bio_start); +#endif /* MY_ABC_HERE */ blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio, int mirror_num); int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/extent-io-tree.h b/fs/btrfs/extent-io-tree.h index 9800a8306368..81a0b7b9f543 100644 --- a/fs/btrfs/extent-io-tree.h +++ b/fs/btrfs/extent-io-tree.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_EXTENT_IO_TREE_H @@ -21,10 +24,27 @@ struct io_failure_record; #define EXTENT_NORESERVE (1U << 11) #define EXTENT_QGROUP_RESERVED (1U << 12) #define EXTENT_CLEAR_DATA_RESV (1U << 13) +/* + * Must be cleared only during ordered extent completion or on error paths if we + * did not manage to submit bios and create the ordered extents for the range. + * Should not be cleared during page release and page invalidation (if there is + * an ordered extent in flight), that is left for the ordered extent completion. + */ #define EXTENT_DELALLOC_NEW (1U << 14) +/* + * When an ordered extent successfully completes for a region marked as a new + * delalloc range, use this flag when clearing a new delalloc range to indicate + * that the VFS' inode number of bytes should be incremented and the inode's new + * delalloc bytes decremented, in an atomic way to prevent races with stat(2). + */ +#define EXTENT_ADD_INODE_BYTES (1U << 15) #define EXTENT_DO_ACCOUNTING (EXTENT_CLEAR_META_RESV | \ EXTENT_CLEAR_DATA_RESV) -#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING) +#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | \ + EXTENT_ADD_INODE_BYTES) +#ifdef MY_ABC_HERE +#define EXTENT_UNUSED_HINT (1U << 30) +#endif /* MY_ABC_HERE */ /* * Redefined bits above which are used only in the device allocation tree, @@ -34,6 +54,9 @@ struct io_failure_record; */ #define CHUNK_ALLOCATED EXTENT_DIRTY #define CHUNK_TRIMMED EXTENT_DEFRAG +#ifdef MY_ABC_HERE +#define CHUNK_UNUSED_HINT EXTENT_UNUSED_HINT +#endif /* MY_ABC_HERE */ #define CHUNK_STATE_MASK (CHUNK_ALLOCATED | \ CHUNK_TRIMMED) @@ -196,7 +219,7 @@ static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start, struct extent_state **cached_state) { return set_extent_bit(tree, start, end, - EXTENT_DELALLOC | EXTENT_UPTODATE | extra_bits, + EXTENT_DELALLOC | extra_bits, NULL, cached_state, GFP_NOFS); } @@ -204,7 +227,7 @@ static inline int set_extent_defrag(struct extent_io_tree *tree, u64 start, u64 end, struct extent_state **cached_state) { return set_extent_bit(tree, start, end, - EXTENT_DELALLOC | EXTENT_UPTODATE | EXTENT_DEFRAG, + EXTENT_DELALLOC | EXTENT_DEFRAG, NULL, cached_state, GFP_NOFS); } @@ -247,6 +270,10 @@ int free_io_failure(struct extent_io_tree *failure_tree, int clean_io_failure(struct btrfs_fs_info *fs_info, struct extent_io_tree *failure_tree, struct extent_io_tree *io_tree, u64 start, - struct page *page, u64 ino, unsigned int pg_offset); + struct page *page, u64 ino, unsigned int pg_offset +#ifdef MY_ABC_HERE + , bool should_put_locked +#endif /* MY_ABC_HERE */ + ); #endif /* BTRFS_EXTENT_IO_TREE_H */ diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c346c46020e5..273b2bc47c10 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -34,6 +37,12 @@ #include "block-group.h" #include "discard.h" #include "rcu-string.h" +#ifdef MY_ABC_HERE +#include "backref.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #undef SCRAMBLE_DELAYED_REFS @@ -49,7 +58,11 @@ static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op, static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, u64 parent, u64 root_objectid, u64 flags, u64 owner, u64 offset, - struct btrfs_key *ins, int ref_mod); + struct btrfs_key *ins, int ref_mod +#ifdef MY_ABC_HERE + , struct btrfs_delayed_ref_node *node +#endif /* MY_ABC_HERE */ + ); static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *node, struct btrfs_delayed_extent_op *extent_op); @@ -782,7 +795,11 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_extent_inline_ref **ref_ret, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, - u64 owner, u64 offset, int insert) + u64 owner, u64 offset, int insert +#ifdef MY_ABC_HERE + , bool *has_clone_range +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = fs_info->extent_root; @@ -809,6 +826,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, want = extent_ref_type(parent, owner); if (insert) { extra_size = btrfs_extent_inline_ref_size(want); + path->search_for_extension = 1; path->keep_locks = 1; } else extra_size = -1; @@ -872,6 +890,10 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); flags = btrfs_extent_flags(leaf, ei); +#ifdef MY_ABC_HERE + if (has_clone_range && *has_clone_range == false) + *has_clone_range = !!(flags & BTRFS_EXTENT_FLAG_HAS_CLONE_RANGE); +#endif /* MY_ABC_HERE */ ptr = (unsigned long)(ei + 1); end = (unsigned long)ei + item_size; @@ -961,6 +983,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, out: if (insert) { path->keep_locks = 0; + path->search_for_extension = 0; btrfs_unlock_up_safe(path, 1); } return err; @@ -1034,13 +1057,21 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_path *path, struct btrfs_extent_inline_ref **ref_ret, u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset) + u64 root_objectid, u64 owner, u64 offset +#ifdef MY_ABC_HERE + , bool *has_clone_range +#endif /* MY_ABC_HERE */ + ) { int ret; ret = lookup_inline_extent_backref(trans, path, ref_ret, bytenr, num_bytes, parent, root_objectid, - owner, offset, 0); + owner, offset, 0 +#ifdef MY_ABC_HERE + , has_clone_range +#endif /* MY_ABC_HERE */ + ); if (ret != -ENOENT) return ret; @@ -1140,7 +1171,11 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans, ret = lookup_inline_extent_backref(trans, path, &iref, bytenr, num_bytes, parent, root_objectid, - owner, offset, 1); + owner, offset, 1 +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret == 0) { /* * We're adding refs to a tree block we already own, this @@ -1191,7 +1226,11 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, } static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len, - u64 *discarded_bytes) + u64 *discarded_bytes +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { int j, ret = 0; u64 bytes_left, end; @@ -1237,8 +1276,14 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len, } if (size) { - ret = blkdev_issue_discard(bdev, start >> 9, size >> 9, - GFP_NOFS, 0); +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT) + ret = blkdev_hint_unused(bdev, start >> 9, size >> 9, + GFP_NOFS); + else +#endif /* MY_ABC_HERE */ + ret = blkdev_issue_discard(bdev, start >> 9, size >> 9, + GFP_NOFS, 0); if (!ret) *discarded_bytes += size; else if (ret != -EOPNOTSUPP) @@ -1254,16 +1299,28 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len, } if (bytes_left) { - ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9, - GFP_NOFS, 0); +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT) + ret = blkdev_hint_unused(bdev, start >> 9, bytes_left >> 9, + GFP_NOFS); + else +#endif /* MY_ABC_HERE */ + ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9, + GFP_NOFS, 0); if (!ret) *discarded_bytes += bytes_left; } return ret; } +#ifdef MY_ABC_HERE +static int __btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, u64 *actual_bytes + , enum trim_act act) +#else /* MY_ABC_HERE */ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, u64 *actual_bytes) +#endif /* MY_ABC_HERE */ { int ret = 0; u64 discarded_bytes = 0; @@ -1304,8 +1361,16 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, continue; } req_q = bdev_get_queue(device->bdev); - if (!blk_queue_discard(req_q)) + if (!blk_queue_discard(req_q) +#ifdef MY_ABC_HERE + && (act != TRIM_SEND_HINT) +#endif /* MY_ABC_HERE */ + ) continue; +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT && !blk_queue_unused_hint(req_q)) + continue; +#endif /* MY_ABC_HERE */ if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) continue; @@ -1313,7 +1378,11 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, ret = btrfs_issue_discard(device->bdev, stripe->physical, stripe->length, - &bytes); + &bytes +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (!ret) { discarded_bytes += bytes; } else if (ret != -EOPNOTSUPP) { @@ -1350,6 +1419,34 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, return ret; } +#ifdef MY_ABC_HERE +int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, u64 *actual_bytes, enum trim_act act) +{ + int ret; + u64 discarded_bytes = 0, bytes; + u64 offset, len, cur; + + offset = bytenr; + len = num_bytes; + while (len) { + cur = min_t(u64, len, SZ_2G); + ret = __btrfs_discard_extent(fs_info, offset, cur, &bytes, act); + if (ret) + goto out; + discarded_bytes += bytes; + offset += cur; + len -= cur; + } + + if (actual_bytes) + *actual_bytes = discarded_bytes; + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + /* Can return -ENOMEM */ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_ref *generic_ref) @@ -1467,6 +1564,12 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, btrfs_abort_transaction(trans, ret); out: btrfs_free_path(path); + +#ifdef MY_ABC_HERE + if (!ret && owner >= BTRFS_FIRST_FREE_OBJECTID) + btrfs_insert_quota_record(trans, node); +#endif /* MY_ABC_HERE */ + return ret; } @@ -1499,7 +1602,11 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, ret = alloc_reserved_file_extent(trans, parent, ref_root, flags, ref->objectid, ref->offset, &ins, - node->ref_mod); + node->ref_mod +#ifdef MY_ABC_HERE + , node +#endif /* MY_ABC_HERE */ + ); } else if (node->action == BTRFS_ADD_DELAYED_REF) { ret = __btrfs_inc_extent_ref(trans, node, parent, ref_root, ref->objectid, ref->offset, @@ -1512,6 +1619,19 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, } else { BUG(); } +#ifdef MY_ABC_HERE + if (ret) + goto out; + if (ref->syno_usage == 1) { + if (node->action == BTRFS_ADD_DELAYED_REF) + ret = btrfs_syno_subvol_usage_add(trans, ref_root, node->bytenr, node->num_bytes, node->ref_mod); + else + ret = btrfs_syno_subvol_usage_free(trans, ref_root, node->bytenr, node->num_bytes, node->ref_mod); + } else if (ref->syno_usage == 2 && node->action == BTRFS_ADD_DELAYED_REF) { + ret = btrfs_syno_extent_usage_add(trans, SYNO_USAGE_TYPE_RO_SNAPSHOT, node->bytenr, node->num_bytes, 0); + } +out: +#endif /* MY_ABC_HERE */ return ret; } @@ -1717,6 +1837,10 @@ static void unselect_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_ref spin_lock(&delayed_refs->lock); head->processing = 0; delayed_refs->num_heads_ready++; +#ifdef MY_ABC_HERE + if (head->syno_usage) + delayed_refs->num_syno_usage_heads_ready++; +#endif /* MY_ABC_HERE */ spin_unlock(&delayed_refs->lock); btrfs_delayed_ref_unlock(head); } @@ -1758,6 +1882,9 @@ void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head *head) { int nr_items = 1; /* Dropping this ref head update. */ +#ifdef MY_ABC_HERE + u64 num_syno_usage, syno_usage_nr; +#endif /* MY_ABC_HERE */ /* * We had csum deletions accounted for in our delayed refs rsv, we need @@ -1783,9 +1910,46 @@ void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info, btrfs_mod_total_bytes_pinned(fs_info, flags, -head->num_bytes); } +#ifdef MY_ABC_HERE + spin_lock(&delayed_refs->lock); + num_syno_usage = atomic_read(&delayed_refs->num_syno_usage_entries) + delayed_refs->num_syno_usage_heads_ready; + if (delayed_refs->total_syno_usage_accounting > num_syno_usage) { + syno_usage_nr = delayed_refs->total_syno_usage_accounting - num_syno_usage; + delayed_refs->total_syno_usage_accounting -= syno_usage_nr; + nr_items += syno_usage_nr; + } + spin_unlock(&delayed_refs->lock); +#endif /* MY_ABC_HERE */ + btrfs_delayed_refs_rsv_release(fs_info, nr_items); } +#ifdef MY_ABC_HERE +static void syno_throttle_delayed_ref_wakeup(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info) +{ + struct btrfs_delayed_ref_throttle_ticket *ticket; + spin_lock(&fs_info->syno_delayed_ref_throttle_lock); + if (trans->syno_delayed_ref_throttle_ticket) { + if (trans->syno_delayed_ref_throttle_ticket->count > 0) + trans->syno_delayed_ref_throttle_ticket->count--; + if (trans->syno_delayed_ref_throttle_ticket->count == 0) + list_del_init(&trans->syno_delayed_ref_throttle_ticket->list); + } else if (!list_empty(&fs_info->syno_delayed_ref_throttle_tickets)) { + ticket = list_first_entry(&fs_info->syno_delayed_ref_throttle_tickets, + struct btrfs_delayed_ref_throttle_ticket, list); + if (ticket->count > 0) + ticket->count--; + + if (ticket->count > 0) + list_move_tail(&ticket->list, &fs_info->syno_delayed_ref_throttle_tickets); + else + list_del_init(&ticket->list); + } + spin_unlock(&fs_info->syno_delayed_ref_throttle_lock); +} +#endif /* MY_ABC_HERE */ + static int cleanup_ref_head(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_head *head) { @@ -1818,6 +1982,9 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, return 1; } btrfs_delete_ref_head(delayed_refs, head); +#ifdef MY_ABC_HERE + syno_total_delayed_ref_updates_dec(trans); +#endif /* MY_ABC_HERE */ spin_unlock(&head->lock); spin_unlock(&delayed_refs->lock); @@ -1834,11 +2001,18 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, trace_run_delayed_ref_head(fs_info, head, 0); btrfs_delayed_ref_unlock(head); btrfs_put_delayed_ref_head(head); +#ifdef MY_ABC_HERE + syno_throttle_delayed_ref_wakeup(trans, fs_info); +#endif /* MY_ABC_HERE */ return ret; } static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head( - struct btrfs_trans_handle *trans) + struct btrfs_trans_handle *trans +#ifdef MY_ABC_HERE + , bool select_data +#endif /* MY_ABC_HERE */ + ) { struct btrfs_delayed_ref_root *delayed_refs = &trans->transaction->delayed_refs; @@ -1846,11 +2020,23 @@ static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head( int ret; spin_lock(&delayed_refs->lock); +#ifdef MY_ABC_HERE + if (select_data) + head = btrfs_select_data_ref_head(delayed_refs); + else + head = btrfs_select_ref_head(delayed_refs); + + if (IS_ERR_OR_NULL(head)) { + spin_unlock(&delayed_refs->lock); + return head; + } +#else head = btrfs_select_ref_head(delayed_refs); if (!head) { spin_unlock(&delayed_refs->lock); return head; } +#endif /* MY_ABC_HERE */ /* * Grab the lock that says we are going to process all the refs for @@ -1880,6 +2066,9 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *ref; int must_insert_reserved = 0; int ret; +#ifdef MY_ABC_HERE + struct btrfs_delayed_data_ref *data_ref = NULL; +#endif /* MY_ABC_HERE */ delayed_refs = &trans->transaction->delayed_refs; @@ -1900,6 +2089,10 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, RB_CLEAR_NODE(&ref->ref_node); if (!list_empty(&ref->add_list)) list_del(&ref->add_list); +#ifdef MY_ABC_HERE + if (list_empty(&ref->syno_list)) + list_add_tail(&ref->syno_list, &locked_ref->ref_syno_list); +#endif /* MY_ABC_HERE */ /* * When we play the delayed ref, also correct the ref_mod on * head @@ -1916,6 +2109,17 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, WARN_ON(1); } atomic_dec(&delayed_refs->num_entries); +#ifdef MY_ABC_HERE + syno_total_delayed_ref_updates_dec(trans); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (ref->type == BTRFS_EXTENT_DATA_REF_KEY || + ref->type == BTRFS_SHARED_DATA_REF_KEY) { + data_ref = btrfs_delayed_node_to_data_ref(ref); + if (data_ref->syno_usage) + atomic_dec(&delayed_refs->num_syno_usage_entries); + } +#endif /* MY_ABC_HERE */ /* * Record the must_insert_reserved flag before we drop the @@ -1931,6 +2135,14 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, ret = run_one_delayed_ref(trans, ref, extent_op, must_insert_reserved); +#ifdef MY_ABC_HERE + if (!list_empty(&ref->syno_list)) { + spin_lock(&locked_ref->lock); + if (!list_empty(&ref->syno_list)) + list_del(&ref->syno_list); + spin_unlock(&locked_ref->lock); + } +#endif /* MY_ABC_HERE */ btrfs_free_delayed_extent_op(extent_op); if (ret) { unselect_delayed_ref_head(delayed_refs, locked_ref); @@ -1941,6 +2153,13 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, } btrfs_put_delayed_ref(ref); +#ifdef MY_ABC_HERE + btrfs_syno_btree_balance_dirty(fs_info, false); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + syno_throttle_delayed_ref_wakeup(trans, fs_info); +#endif /* MY_ABC_HERE */ cond_resched(); spin_lock(&locked_ref->lock); @@ -1955,7 +2174,11 @@ static int btrfs_run_delayed_refs_for_head(struct btrfs_trans_handle *trans, * Returns -ENOMEM or -EIO on failure and will abort the transaction. */ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, - unsigned long nr) + unsigned long nr +#ifdef MY_ABC_HERE + , unsigned long *processed_count +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_delayed_ref_root *delayed_refs; @@ -1964,13 +2187,28 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, int ret; unsigned long count = 0; unsigned long actual_count = 0; +#ifdef MY_ABC_HERE + bool chown = (nr == BTRFS_USRQUOTA_DELAYED_REF_SCAN); +#endif /* MY_ABC_HERE */ delayed_refs = &trans->transaction->delayed_refs; +#ifdef MY_ABC_HERE + if (chown) + delayed_refs->run_delayed_start = 0; +#endif /* MY_ABC_HERE */ + do { if (!locked_ref) { +#ifdef MY_ABC_HERE + locked_ref = btrfs_obtain_ref_head(trans, chown); +#else locked_ref = btrfs_obtain_ref_head(trans); +#endif /* MY_ABC_HERE */ if (IS_ERR_OR_NULL(locked_ref)) { if (PTR_ERR(locked_ref) == -EAGAIN) { +#ifdef MY_ABC_HERE + cond_resched(); +#endif /* MY_ABC_HERE */ continue; } else { break; @@ -2043,6 +2281,10 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, fs_info->avg_delayed_ref_runtime = avg >> 2; /* div by 4 */ spin_unlock(&delayed_refs->lock); } +#ifdef MY_ABC_HERE + if (processed_count) + *processed_count = actual_count; +#endif /* MY_ABC_HERE */ return 0; } @@ -2118,8 +2360,14 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes) * Returns 0 on success or if called with an aborted transaction * Returns <0 on error and aborts the transaction */ +#ifdef MY_ABC_HERE +int btrfs_run_delayed_refs_and_get_processed(struct btrfs_trans_handle *trans, + unsigned long count, + unsigned long *processed_count) +#else /* MY_ABC_HERE */ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, unsigned long count) +#endif /* MY_ABC_HERE */ { struct btrfs_fs_info *fs_info = trans->fs_info; struct rb_node *node; @@ -2127,6 +2375,10 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_head *head; int ret; int run_all = count == (unsigned long)-1; +#ifdef MY_ABC_HERE + bool chown = (count == BTRFS_USRQUOTA_DELAYED_REF_SCAN); + struct btrfs_transaction *transaction = trans->transaction; +#endif /* MY_ABC_HERE */ /* We'll clean this up in btrfs_cleanup_transaction */ if (TRANS_ABORTED(trans)) @@ -2135,6 +2387,18 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, if (test_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags)) return 0; +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_CREATING_BLOCK_GROUP_CACHE_TREE, &fs_info->flags)) + return 0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!chown) + down_read(&transaction->delayed_refs_rw_sem); + else + down_write(&transaction->delayed_refs_rw_sem); +#endif /* MY_ABC_HERE */ + delayed_refs = &trans->transaction->delayed_refs; if (count == 0) count = atomic_read(&delayed_refs->num_entries) * 2; @@ -2143,8 +2407,18 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, #ifdef SCRAMBLE_DELAYED_REFS delayed_refs->run_delayed_start = find_middle(&delayed_refs->root); #endif - ret = __btrfs_run_delayed_refs(trans, count); + ret = __btrfs_run_delayed_refs(trans, count +#ifdef MY_ABC_HERE + , processed_count +#endif /* MY_ABC_HERE */ + ); if (ret < 0) { +#ifdef MY_ABC_HERE + if (!chown) + up_read(&transaction->delayed_refs_rw_sem); + else + up_write(&transaction->delayed_refs_rw_sem); +#endif /* MY_ABC_HERE */ btrfs_abort_transaction(trans, ret); return ret; } @@ -2172,6 +2446,14 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, goto again; } out: +#ifdef MY_ABC_HERE + btrfs_quota_syno_v1_accounting(trans); + if (!chown) + up_read(&transaction->delayed_refs_rw_sem); + else + up_write(&transaction->delayed_refs_rw_sem); +#endif /* MY_ABC_HERE */ + return 0; } @@ -2198,6 +2480,32 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +// A btrfs_set_disk_extent_flags() without a eb as its argument. +int btrfs_set_disk_extent_flags_no_eb(struct btrfs_trans_handle *trans, + u64 start, u64 len, u64 flags, + int level, int is_data) +{ + struct btrfs_delayed_extent_op *extent_op; + int ret; + + extent_op = btrfs_alloc_delayed_extent_op(); + if (!extent_op) + return -ENOMEM; + + extent_op->flags_to_set = flags; + extent_op->update_flags = true; + extent_op->update_key = false; + extent_op->is_data = is_data ? true : false; + extent_op->level = level; + + ret = btrfs_add_delayed_extent_op(trans, start, len, extent_op); + if (ret) + btrfs_free_delayed_extent_op(extent_op); + return ret; +} +#endif /* MY_ABC_HERE */ + static noinline int check_delayed_ref(struct btrfs_root *root, struct btrfs_path *path, u64 objectid, u64 offset, u64 bytenr) @@ -2227,6 +2535,9 @@ static noinline int check_delayed_ref(struct btrfs_root *root, return 0; } +#ifdef MY_ABC_HERE + refcount_inc(&head->refs); +#else if (!mutex_trylock(&head->mutex)) { refcount_inc(&head->refs); spin_unlock(&delayed_refs->lock); @@ -2243,6 +2554,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root, btrfs_put_transaction(cur_trans); return -EAGAIN; } +#endif /* MY_ABC_HERE */ spin_unlock(&delayed_refs->lock); spin_lock(&head->lock); @@ -2272,8 +2584,34 @@ static noinline int check_delayed_ref(struct btrfs_root *root, break; } } +#ifdef MY_ABC_HERE + list_for_each_entry(ref, &head->ref_syno_list, syno_list) { + /* If it's a shared ref we know a cross reference exists */ + if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) { + ret = 1; + break; + } + + data_ref = btrfs_delayed_node_to_data_ref(ref); + + /* + * If our ref doesn't match the one we're currently looking at + * then we have a cross reference. + */ + if (data_ref->root != root->root_key.objectid || + data_ref->objectid != objectid || + data_ref->offset != offset) { + ret = 1; + break; + } + } +#endif /* MY_ABC_HERE */ spin_unlock(&head->lock); +#ifdef MY_ABC_HERE + btrfs_put_delayed_ref_head(head); +#else mutex_unlock(&head->mutex); +#endif /* MY_ABC_HERE */ btrfs_put_transaction(cur_trans); return ret; } @@ -2438,8 +2776,27 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, num_bytes, parent); generic_ref.real_root = root->root_key.objectid; btrfs_init_data_ref(&generic_ref, ref_root, key.objectid, - key.offset); + key.offset +#ifdef MY_ABC_HERE + /* + * Normally this is used to convert implicit + * backref to full backref, in this case, + * no subvol/extent relation changes. + * There's one case in copy_root, where root + * node is at level 0, in this case, this'll + * add data ref for newly created snapshot(rw). + * But we'll set subvolume type later to + * trigger fast rescan, don't bother handling + * it here + */ + , 0 /* syno_usage */ +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + generic_ref.skip_qgroup = true; +#else generic_ref.skip_qgroup = for_reloc; +#endif /* MY_ABC_HERE */ if (inc) ret = btrfs_inc_extent_ref(trans, &generic_ref); else @@ -2578,24 +2935,23 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans, struct btrfs_block_group *cache; int ret; - btrfs_add_excluded_extent(trans->fs_info, bytenr, num_bytes); - cache = btrfs_lookup_block_group(trans->fs_info, bytenr); if (!cache) return -EINVAL; /* - * pull in the free space cache (if any) so that our pin - * removes the free space from the cache. We have load_only set - * to one because the slow code to read in the free extents does check - * the pinned extents. + * Fully cache the free space first so that our pin removes the free space + * from the cache. */ - btrfs_cache_block_group(cache, 1); + ret = btrfs_cache_block_group(cache, true); + if (ret) + goto out; pin_down_extent(trans, cache, bytenr, num_bytes, 0); /* remove us from the free space cache (if we're there at all) */ ret = btrfs_remove_free_space(cache, bytenr, num_bytes); +out: btrfs_put_block_group(cache); return ret; } @@ -2605,45 +2961,17 @@ static int __exclude_logged_extent(struct btrfs_fs_info *fs_info, { int ret; struct btrfs_block_group *block_group; - struct btrfs_caching_control *caching_ctl; block_group = btrfs_lookup_block_group(fs_info, start); if (!block_group) return -EINVAL; - btrfs_cache_block_group(block_group, 0); - caching_ctl = btrfs_get_caching_control(block_group); + ret = btrfs_cache_block_group(block_group, true); + if (ret) + goto out; - if (!caching_ctl) { - /* Logic error */ - BUG_ON(!btrfs_block_group_done(block_group)); - ret = btrfs_remove_free_space(block_group, start, num_bytes); - } else { - mutex_lock(&caching_ctl->mutex); - - if (start >= caching_ctl->progress) { - ret = btrfs_add_excluded_extent(fs_info, start, - num_bytes); - } else if (start + num_bytes <= caching_ctl->progress) { - ret = btrfs_remove_free_space(block_group, - start, num_bytes); - } else { - num_bytes = caching_ctl->progress - start; - ret = btrfs_remove_free_space(block_group, - start, num_bytes); - if (ret) - goto out_lock; - - num_bytes = (start + num_bytes) - - caching_ctl->progress; - start = caching_ctl->progress; - ret = btrfs_add_excluded_extent(fs_info, start, - num_bytes); - } -out_lock: - mutex_unlock(&caching_ctl->mutex); - btrfs_put_caching_control(caching_ctl); - } + ret = btrfs_remove_free_space(block_group, start, num_bytes); +out: btrfs_put_block_group(block_group); return ret; } @@ -2706,6 +3034,22 @@ fetch_cluster_info(struct btrfs_fs_info *fs_info, *empty_cluster = SZ_2M; else *empty_cluster = SZ_64K; +#ifdef MY_ABC_HERE + } else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) && + btrfs_test_opt(fs_info, SSD)) { + /* + * Before kernel 5.x , we use `SSD` mount option to + * enable data cluster allocation, even if volume + * use HDD as it's device. However, in commit 583b7231, + * It use `SSD_SPREAD` mount option to enable data + * cluser allocation instead of `SSD`. To solve this + * problem and make identical mount option on various + * kernel version in DSM. We still use `SSD` mount option + * to enbale data cluster allocation. + */ + ret = &fs_info->data_alloc_cluster; + *empty_cluster = ret->empty_cluster; +#endif /* MY_ABC_HERE */ } else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(fs_info, SSD_SPREAD)) { *empty_cluster = SZ_2M; @@ -2747,11 +3091,8 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info, len = cache->start + cache->length - start; len = min(len, end + 1 - start); - if (start < cache->last_byte_to_unpin && return_free_space) { - u64 add_len = min(len, cache->last_byte_to_unpin - start); - - btrfs_add_free_space(cache, start, add_len); - } + if (return_free_space) + btrfs_add_free_space(cache, start, len); start += len; total_unpinned += len; @@ -2831,13 +3172,14 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) mutex_unlock(&fs_info->unused_bg_unpin_mutex); break; } - if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags)) - clear_extent_bits(&fs_info->excluded_extents, start, - end, EXTENT_UPTODATE); if (btrfs_test_opt(fs_info, DISCARD_SYNC)) ret = btrfs_discard_extent(fs_info, start, - end + 1 - start, NULL); + end + 1 - start, NULL +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); clear_extent_dirty(unpin, start, end, &cached_state); unpin_extent_range(fs_info, start, end, true); @@ -2865,7 +3207,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) ret = btrfs_discard_extent(fs_info, block_group->start, block_group->length, - &trimmed); + &trimmed +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); list_del_init(&block_group->bg_list); btrfs_unfreeze_block_group(block_group); @@ -2965,6 +3311,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, u64 num_bytes = node->num_bytes; int last_ref = 0; bool skinny_metadata = btrfs_fs_incompat(info, SKINNY_METADATA); +#ifdef MY_ABC_HERE + bool has_clone_range = (extent_op ? + !!(extent_op->flags_to_set & BTRFS_EXTENT_FLAG_HAS_CLONE_RANGE) : false); +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -2988,7 +3338,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ret = lookup_extent_backref(trans, path, &iref, bytenr, num_bytes, parent, root_objectid, owner_objectid, - owner_offset); + owner_offset +#ifdef MY_ABC_HERE + , &has_clone_range +#endif /* MY_ABC_HERE */ + ); if (ret == 0) { /* * Either the inline backref or the SHARED_DATA_REF/ @@ -3211,6 +3565,15 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, } btrfs_release_path(path); +#ifdef MY_ABC_HERE + if (is_data) { + ret = btrfs_syno_extent_usage_free(trans, 0, bytenr, num_bytes, refs_to_drop, 1); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } + } +#endif /* MY_ABC_HERE */ if (is_data) { ret = btrfs_del_csums(trans, info->csum_root, bytenr, num_bytes); @@ -3234,6 +3597,36 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, } btrfs_release_path(path); +#ifdef MY_ABC_HERE + if (is_data && !ret && last_ref) { + struct btrfs_delayed_data_ref *ref; + + ref = btrfs_delayed_node_to_data_ref(node); + if (ref->skip_qgroup) + goto out; + + if (has_clone_range) { + struct quota_check qc = { + .bytenr = bytenr, + .root_objectid = root_objectid, + .ino = owner_objectid, + .offset = (u64)-1, + .in_run_delayed = true + }; + + ret = check_root_inode_ref(trans, &qc); + if (ret) { + WARN_ONCE(ret < 0, "check_root_inode_ref failed, " + "bytenr = %llu, root = %llu, ino = %llu", + bytenr, root_objectid, owner_objectid); + ret = 0; + goto out; + } + } + btrfs_insert_quota_record(trans, node); + } +#endif /* MY_ABC_HERE */ + out: btrfs_free_path(path); return ret; @@ -3286,6 +3679,9 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, goto out; btrfs_delete_ref_head(delayed_refs, head); +#ifdef MY_ABC_HERE + syno_total_delayed_ref_updates_dec(trans); +#endif /* MY_ABC_HERE */ head->processing = 0; spin_unlock(&head->lock); @@ -3400,6 +3796,10 @@ enum btrfs_loop_type { LOOP_CACHING_NOWAIT, LOOP_CACHING_WAIT, LOOP_ALLOC_CHUNK, +#ifdef MY_ABC_HERE + LOOP_NO_RESERVE, + LOOP_NO_CLUSTER, +#endif /* MY_ABC_HERE */ LOOP_NO_EMPTY_SIZE, }; @@ -3488,6 +3888,12 @@ struct find_free_extent_ctl { /* For clustered allocation */ u64 empty_cluster; struct btrfs_free_cluster *last_ptr; + +#ifdef MY_ABC_HERE + bool no_cluster_downgrade; + bool set_fragmented; +#endif /* MY_ABC_HERE */ + bool use_cluster; bool have_caching_bg; @@ -3550,6 +3956,9 @@ static int find_free_extent_clustered(struct btrfs_block_group *bg, u64 aligned_cluster; u64 offset; int ret; +#ifdef MY_ABC_HERE + u64 reserve_bytes = 0; +#endif /* MY_ABC_HERE */ cluster_bg = btrfs_lock_cluster(bg, last_ptr, ffe_ctl->delalloc); if (!cluster_bg) @@ -3601,12 +4010,28 @@ static int find_free_extent_clustered(struct btrfs_block_group *bg, spin_unlock(&last_ptr->refill_lock); return -ENOENT; } +#ifdef MY_ABC_HERE + if (bg->start == bg->fs_info->log_tree_rsv_start) + goto skip_refill_cluster; +#endif /* MY_ABC_HERE */ aligned_cluster = max_t(u64, ffe_ctl->empty_cluster + ffe_ctl->empty_size, bg->full_stripe_len); + +#ifdef MY_ABC_HERE + if ((ffe_ctl->flags & BTRFS_BLOCK_GROUP_METADATA) + && ffe_ctl->loop < LOOP_NO_RESERVE) + reserve_bytes = bg->length >> 2; +#endif /* MY_ABC_HERE */ + ret = btrfs_find_space_cluster(bg, last_ptr, ffe_ctl->search_start, - ffe_ctl->num_bytes, aligned_cluster); + ffe_ctl->num_bytes, aligned_cluster +#ifdef MY_ABC_HERE + , reserve_bytes, &ffe_ctl->no_cluster_downgrade +#endif /* MY_ABC_HERE */ + ); + if (ret == 0) { /* Now pull our allocation out of this cluster */ offset = btrfs_alloc_from_cluster(bg, last_ptr, @@ -3630,6 +4055,9 @@ static int find_free_extent_clustered(struct btrfs_block_group *bg, ffe_ctl->empty_cluster + ffe_ctl->empty_size); return -EAGAIN; } +#ifdef MY_ABC_HERE +skip_refill_cluster: +#endif /* MY_ABC_HERE */ /* * At this point we either didn't find a cluster or we weren't able to * allocate a block from our cluster. Free the cluster we've been @@ -3656,10 +4084,34 @@ static int find_free_extent_unclustered(struct btrfs_block_group *bg, * we don't bother trying to setup a cluster again until we get more * space. */ - if (unlikely(last_ptr)) { + if (unlikely(last_ptr) +#ifdef MY_ABC_HERE + // make sure it equal `>= LOOP_NO_CLUSTER`. + && ffe_ctl->loop > LOOP_NO_RESERVE +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + // make sure it equal `>= LOOP_NO_EMPTY_SIZE` with this config only. + && ffe_ctl->loop > LOOP_ALLOC_CHUNK +#endif /* MY_ABC_HERE */ + ) { +#ifdef MY_ABC_HERE + if (ffe_ctl->set_fragmented) { + spin_lock(&last_ptr->lock); + last_ptr->fragmented = 1; + spin_unlock(&last_ptr->lock); + btrfs_warn(bg->fs_info, + "Set cluster fragmented, flags = %llu\n", ffe_ctl->flags); + } + + // In case someone already got cluster before we set last_ptr->fragmented = 1. + spin_lock(&last_ptr->refill_lock); + btrfs_return_cluster_to_free_space(NULL, last_ptr); + spin_unlock(&last_ptr->refill_lock); +#else spin_lock(&last_ptr->lock); last_ptr->fragmented = 1; spin_unlock(&last_ptr->lock); +#endif /* MY_ABC_HERE */ } if (ffe_ctl->cached) { struct btrfs_free_space_ctl *free_space_ctl; @@ -3758,7 +4210,10 @@ static void found_extent_clustered(struct find_free_extent_ctl *ffe_ctl, if (!ffe_ctl->use_cluster && last_ptr) { spin_lock(&last_ptr->lock); - last_ptr->window_start = ins->objectid; +#ifdef MY_ABC_HERE + if (last_ptr->fragmented && !last_ptr->block_group) +#endif /* MY_ABC_HERE */ + last_ptr->window_start = ins->objectid; spin_unlock(&last_ptr->lock); } } @@ -3779,11 +4234,22 @@ static int chunk_allocation_failed(struct find_free_extent_ctl *ffe_ctl) { switch (ffe_ctl->policy) { case BTRFS_EXTENT_ALLOC_CLUSTERED: +#ifdef MY_ABC_HERE + if ((ffe_ctl->flags & BTRFS_BLOCK_GROUP_METADATA) + || ((ffe_ctl->flags & BTRFS_BLOCK_GROUP_DATA) + && ffe_ctl->use_cluster + && ffe_ctl->last_ptr + && ffe_ctl->last_ptr->downgrade_limit)) + ffe_ctl->loop = LOOP_NO_RESERVE; + else + ffe_ctl->loop = LOOP_NO_CLUSTER; +#else /* MY_ABC_HERE */ /* * If we can't allocate a new chunk we've already looped through * at least once, move on to the NO_EMPTY_SIZE case. */ ffe_ctl->loop = LOOP_NO_EMPTY_SIZE; +#endif /* MY_ABC_HERE */ return 0; default: BUG(); @@ -3873,7 +4339,65 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info, if (ret) return ret; } +#ifdef MY_ABC_HERE + if (ffe_ctl->loop == LOOP_NO_RESERVE) { + if ((ffe_ctl->flags & BTRFS_BLOCK_GROUP_DATA) + && ffe_ctl->use_cluster && ffe_ctl->last_ptr) { + if (ffe_ctl->no_cluster_downgrade) { + spin_lock(&ffe_ctl->last_ptr->lock); + if (ffe_ctl->last_ptr->excluded_size > ffe_ctl->num_bytes) { + ffe_ctl->last_ptr->excluded_size = ffe_ctl->num_bytes; + btrfs_info(fs_info, + "Set excluded cluster size to %llu", + ffe_ctl->last_ptr->excluded_size); + } + spin_unlock(&ffe_ctl->last_ptr->lock); + ffe_ctl->use_cluster = false; + ffe_ctl->loop--; + return 1; + } + spin_lock(&ffe_ctl->last_ptr->refill_lock); + // Someone has downgrade the cluster, we should try again. + if (ffe_ctl->empty_cluster > ffe_ctl->last_ptr->empty_cluster) { + ffe_ctl->empty_cluster = ffe_ctl->last_ptr->empty_cluster; + ffe_ctl->loop--; + spin_unlock(&ffe_ctl->last_ptr->refill_lock); + return 1; + } + + if (ffe_ctl->last_ptr->downgrade_limit) { + ffe_ctl->last_ptr->downgrade_limit--; + ffe_ctl->last_ptr->empty_cluster >>= 1; + ffe_ctl->last_ptr->min_bytes >>= 1; + ffe_ctl->empty_cluster = ffe_ctl->last_ptr->empty_cluster; + ffe_ctl->loop--; + btrfs_info(fs_info, + "Downgrade data empty_cluster size to %llu", + ffe_ctl->last_ptr->empty_cluster); + spin_unlock(&ffe_ctl->last_ptr->refill_lock); + return 1; + } + spin_unlock(&ffe_ctl->last_ptr->refill_lock); + } + if (!(ffe_ctl->flags & BTRFS_BLOCK_GROUP_METADATA)) + ffe_ctl->loop++; + } + if (ffe_ctl->loop == LOOP_NO_CLUSTER) { + if (ffe_ctl->last_ptr) { + if (ffe_ctl->use_cluster) { + btrfs_warn(fs_info, + "Switch to unclustered allocation," + " flags = %llu\n", ffe_ctl->flags); + ffe_ctl->set_fragmented = true; + } + ffe_ctl->use_cluster = false; + ffe_ctl->empty_size = 0; + ffe_ctl->empty_cluster = 0; + } else + ffe_ctl->loop++; + } +#endif /* MY_ABC_HERE */ if (ffe_ctl->loop == LOOP_NO_EMPTY_SIZE) { if (ffe_ctl->policy != BTRFS_EXTENT_ALLOC_CLUSTERED) return -ENOSPC; @@ -3938,6 +4462,10 @@ static int prepare_allocation_clustered(struct btrfs_fs_info *fs_info, ffe_ctl->hint_byte = last_ptr->window_start; ffe_ctl->use_cluster = false; } +#ifdef MY_ABC_HERE + if (last_ptr->excluded_size <= ffe_ctl->num_bytes) + ffe_ctl->use_cluster = false; +#endif /* MY_ABC_HERE */ spin_unlock(&last_ptr->lock); } @@ -4015,6 +4543,10 @@ static noinline int find_free_extent(struct btrfs_root *root, ffe_ctl.retry_unclustered = false; ffe_ctl.last_ptr = NULL; ffe_ctl.use_cluster = true; +#ifdef MY_ABC_HERE + ffe_ctl.no_cluster_downgrade = false; + ffe_ctl.set_fragmented = false; +#endif /* MY_ABC_HERE */ ins->type = BTRFS_EXTENT_ITEM_KEY; ins->objectid = 0; @@ -4032,6 +4564,15 @@ static noinline int find_free_extent(struct btrfs_root *root, if (ret < 0) return ret; +#ifdef MY_ABC_HERE + // Let metadata allocation of tree log try reserved block group first + if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID && + fs_info->log_tree_rsv_start) { + ffe_ctl.use_cluster = false; + ffe_ctl.hint_byte = fs_info->log_tree_rsv_start; + } +#endif /* MY_ABC_HERE */ + ffe_ctl.search_start = max(ffe_ctl.search_start, first_logical_byte(fs_info, 0)); ffe_ctl.search_start = max(ffe_ctl.search_start, ffe_ctl.hint_byte); @@ -4117,7 +4658,7 @@ static noinline int find_free_extent(struct btrfs_root *root, ffe_ctl.cached = btrfs_block_group_done(block_group); if (unlikely(!ffe_ctl.cached)) { ffe_ctl.have_caching_bg = true; - ret = btrfs_cache_block_group(block_group, 0); + ret = btrfs_cache_block_group(block_group, false); /* * If we get ENOMEM here or something else we want to @@ -4256,7 +4797,13 @@ static noinline int find_free_extent(struct btrfs_root *root, * case -ENOSPC is returned then @ins->offset will contain the size of the * largest available hole the allocator managed to find. */ -int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, + +#ifdef MY_ABC_HERE +static int __btrfs_reserve_extent +#else /* MY_ABC_HERE */ +int btrfs_reserve_extent +#endif /* MY_ABC_HERE */ + (struct btrfs_root *root, u64 ram_bytes, u64 num_bytes, u64 min_alloc_size, u64 empty_size, u64 hint_byte, struct btrfs_key *ins, int is_data, int delalloc) @@ -4265,9 +4812,36 @@ int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, bool final_tried = num_bytes == min_alloc_size; u64 flags; int ret; +#ifdef MY_ABC_HERE + u64 max_chunk_size, max_extent_size; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + max_chunk_size = div_factor(fs_info->fs_devices->total_rw_bytes, 1); + max_chunk_size = round_up(max_chunk_size, SZ_16M); + /* + * Limit the size of max_extent_size to + * ensure the usage of data chunk for small volume. + */ + max_extent_size = max_chunk_size >> 2; + max_extent_size = max_t(u64, min_alloc_size, max_extent_size); +#endif /* MY_ABC_HERE */ flags = get_alloc_profile_by_root(root, is_data); again: +#ifdef MY_ABC_HERE + if (num_bytes > max_extent_size) { + num_bytes = num_bytes >> 1; + num_bytes = round_down(num_bytes, + fs_info->sectorsize); + num_bytes = max(num_bytes, min_alloc_size); + ram_bytes = num_bytes; + if (num_bytes == min_alloc_size) + final_tried = true; + goto again; + } +#endif /* MY_ABC_HERE */ + WARN_ON(num_bytes < fs_info->sectorsize); ret = find_free_extent(root, ram_bytes, num_bytes, empty_size, hint_byte, ins, flags, delalloc); @@ -4294,11 +4868,998 @@ int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, btrfs_dump_space_info(fs_info, sinfo, num_bytes, 1); } +#ifdef MY_ABC_HERE + WARN_ON_ONCE(1); // Add WARN when ENOSPC. +#endif /* MY_ABC_HERE */ } return ret; } +#ifdef MY_ABC_HERE +static int btrfs_legacy_allocator(struct btrfs_root *root, u64 ram_bytes, + u64 num_bytes, u64 min_alloc_size, + u64 empty_size, u64 hint_byte, + struct btrfs_key *ins, int is_data, int delalloc) +{ + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + + wait_event(fs_info->syno_allocator.syno_allocator_wait, + atomic_read(&fs_info->syno_allocator.syno_allocator_refs) == 0); + + atomic_inc(&fs_info->syno_allocator.legacy_allocator_refs); + ret = __btrfs_reserve_extent(root, ram_bytes, num_bytes, min_alloc_size, empty_size, hint_byte, ins, is_data, delalloc); + if (atomic_dec_and_test(&fs_info->syno_allocator.legacy_allocator_refs) && + waitqueue_active(&fs_info->syno_allocator.legacy_allocator_wait)) + wake_up(&fs_info->syno_allocator.legacy_allocator_wait); + return ret; +} + +/* + * Structure used internally for syno_allocation() function. + * Wraps needed parameters. + */ +enum syno_allocation_stage_type { + SYNO_ALLOCATION_STAGE_FAST, + SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_LIMIT, + SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_FORCE, + SYNO_ALLOCATION_STAGE_SKIP_META_RESERVE, + SYNO_ALLOCATION_STAGE_CACHING_FORCE_WAIT, + SYNO_ALLOCATION_STAGE_RELINK_RETRY, + SYNO_ALLOCATION_STAGE_FULL_SCAN, +}; + +struct syno_allocation_ctl { + /* Basic allocation info */ + struct btrfs_fs_info *fs_info; + struct btrfs_root *root; + u64 ram_bytes; + u64 num_bytes; + u64 min_alloc_size; + u64 is_data; + int delalloc; + struct btrfs_key *result; + + /* internal argument */ + u64 flags; + struct btrfs_space_info *space_info; + unsigned long expire; + struct btrfs_block_group *found_bg; + u64 found_offset; + u64 found_len; + int stage; + int meta_reserve_ratio_high; + int meta_reserve_ratio_low; + bool meta_space_info_full; + bool check_data_ratio; + u64 unallocated_ratio; + u64 data_used_ratio; +}; + +static void syno_allocation_calc_data_ratio(struct syno_allocation_ctl *ctl) +{ + u64 total_bytes, total_allocated = 0, total_unallocated; + u64 data_total_bytes, data_used_bytes; + struct btrfs_space_info *found; + struct btrfs_space_info *space_info; + + if (btrfs_mixed_space_info(ctl->space_info) || + !(ctl->flags & BTRFS_BLOCK_GROUP_DATA)) + goto out; + + total_bytes = btrfs_super_total_bytes(ctl->fs_info->super_copy); + + list_for_each_entry(found, &ctl->fs_info->space_info, list) { + total_allocated += found->disk_total; + } + if (total_bytes > total_allocated) + total_unallocated = total_bytes - total_allocated; + else + total_unallocated = 0; + ctl->unallocated_ratio = div64_u64(total_unallocated * 100, total_bytes); + + space_info = ctl->space_info; + spin_lock(&space_info->lock); + data_total_bytes = space_info->total_bytes; + data_used_bytes = space_info->bytes_used + space_info->bytes_reserved + space_info->bytes_readonly + space_info->bytes_pinned; + spin_unlock(&space_info->lock); + ctl->data_used_ratio = div64_u64(data_used_bytes * 100, data_total_bytes); + + ctl->check_data_ratio = true; +out: + return; +} + +static int syno_alloction_prepare(struct syno_allocation_ctl *ctl) +{ + int ret; + + WARN_ON(ctl->num_bytes < ctl->fs_info->sectorsize); + ctl->result->type = BTRFS_EXTENT_ITEM_KEY; + ctl->result->objectid = 0; + ctl->result->offset = 0; + + ctl->found_bg = NULL; + ctl->found_offset = 0; + ctl->found_len = 0; + ctl->stage = SYNO_ALLOCATION_STAGE_FAST; + ctl->meta_reserve_ratio_low = 15; + ctl->meta_reserve_ratio_high = 35; + + /* maximum allocation time is 200ms */ + ctl->expire = jiffies + msecs_to_jiffies(200); + + ctl->meta_space_info_full = false; + if (!btrfs_mixed_space_info(ctl->space_info) && + (ctl->flags & BTRFS_BLOCK_GROUP_METADATA)) + ctl->meta_space_info_full = ctl->space_info->full; + + ctl->check_data_ratio = false; + syno_allocation_calc_data_ratio(ctl); + + ret = 0; + return ret; +} + +static noinline void +syno_wait_block_group_cache_done(struct syno_allocation_ctl *ctl, struct btrfs_block_group *cache, bool force) +{ + struct btrfs_caching_control *caching_ctl; + unsigned long cur, delay; + + caching_ctl = btrfs_get_caching_control(cache); + if (!caching_ctl) + goto out; + + if (force) { + wait_event(caching_ctl->wait, btrfs_block_group_done(cache)); + } else { + cur = jiffies; + if (time_after(ctl->expire, cur)) { + delay = ctl->expire - cur; + delay = min(delay, msecs_to_jiffies(200)); + wait_event_timeout(caching_ctl->wait, btrfs_block_group_done(cache), delay); + } + } + btrfs_put_caching_control(caching_ctl); +out: + return; +} + +static void syno_allocator_candidate_compare(struct syno_allocation_ctl *ctl, struct btrfs_block_group *block_group, u64 offset, u64 len) +{ + bool release = true; + + if (offset < block_group->start || + offset + len > block_group->start + block_group->length) { + WARN_ON_ONCE(1); + goto out; + } + + if (!ctl->found_bg) + goto use; + + if (len <= ctl->found_len) + goto out; + + /* release old candidate */ + btrfs_add_free_space(ctl->found_bg, ctl->found_offset, ctl->found_len); + atomic_dec(&ctl->found_bg->syno_allocator.refs); + ctl->found_bg = NULL; + ctl->found_offset = 0; + ctl->found_len = 0; + +use: + ctl->found_bg = block_group; + ctl->found_offset = offset; + ctl->found_len = len; + atomic_inc(&ctl->found_bg->syno_allocator.refs); + release = false; + +out: + if (release) + btrfs_add_free_space(block_group, offset, len); + return; +} + +static bool syno_allocation_precheck_free_space(struct syno_allocation_ctl *ctl, u64 total, u64 free_space, bool check_meta_reserve_ratio_high) +{ + bool ret = false; + u64 meta_reserve; + + if (free_space < ctl->min_alloc_size) + goto out; + + if (!btrfs_mixed_space_info(ctl->space_info) && + (ctl->flags & BTRFS_BLOCK_GROUP_METADATA) && + !ctl->meta_space_info_full && + ctl->stage < SYNO_ALLOCATION_STAGE_SKIP_META_RESERVE) { + /* check reserve ratio high */ + if (check_meta_reserve_ratio_high) { + meta_reserve = div_u64(total * ctl->meta_reserve_ratio_high, 100); + if (free_space < meta_reserve) + goto out; + } + + /* check reserve ratio low */ + meta_reserve = div_u64(total * ctl->meta_reserve_ratio_low, 100); + if (free_space < meta_reserve) + goto out; + } + + ret = true; +out: + return ret; +} + +static bool syno_allocation_precheck_block_group(struct syno_allocation_ctl *ctl, struct btrfs_block_group *block_group, bool check_meta_reserve_ratio_high) +{ + struct btrfs_free_space_ctl *free_space_ctl; + u64 total, free_space; + + free_space_ctl = block_group->free_space_ctl; + spin_lock(&free_space_ctl->tree_lock); + total = block_group->length; + free_space = free_space_ctl->free_space; + spin_unlock(&free_space_ctl->tree_lock); + + return syno_allocation_precheck_free_space(ctl, total, free_space, check_meta_reserve_ratio_high); +} + +static void syno_allocation_with_block_group(struct syno_allocation_ctl *ctl, struct btrfs_block_group *block_group, u64 search_start, bool check_meta_reserve_ratio_high) +{ + u64 num_bytes = ctl->num_bytes; + u64 offset; + u64 max_extent_size; + u64 align_offset, align_len; + int delalloc = ctl->delalloc; + bool use_bytes_index; + bool final_tried = num_bytes == ctl->min_alloc_size; + + /* always lock data_rwsem for space_cache=v1 cache write out */ + if (btrfs_test_opt(ctl->fs_info, SPACE_CACHE)) + delalloc = 1; + + btrfs_grab_block_group(block_group, delalloc); + + if (unlikely(!block_group->syno_allocator.initialized)) + goto out; + if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) + goto out; + if (unlikely(block_group->ro)) + goto out; + if (!syno_allocation_precheck_block_group(ctl, block_group, check_meta_reserve_ratio_high)) + goto out; + + if ((search_start < block_group->start) || + (search_start >= block_group->start + block_group->length)) + search_start = block_group->start; + + use_bytes_index = (search_start == block_group->start); +again: + max_extent_size = 0; + offset = btrfs_find_space_for_alloc(block_group, search_start, num_bytes, 0, &max_extent_size); + if (!offset) { + if (!final_tried && max_extent_size) { + if (num_bytes > max_extent_size) + num_bytes = max_extent_size; + else + num_bytes = num_bytes >> 1; + num_bytes = round_down(num_bytes, ctl->fs_info->sectorsize); + num_bytes = max(num_bytes, ctl->min_alloc_size); + if (num_bytes == ctl->min_alloc_size) + final_tried = true; + /* if not use bytes index, we only retry once */ + if (!use_bytes_index) + final_tried = true; + goto again; + } + goto out; + } + + align_offset = ALIGN(offset, ctl->fs_info->stripesize); + align_len = num_bytes; + /* adjust align len */ + if (align_offset + align_len > + block_group->start + block_group->length) { + align_len = block_group->start + block_group->length - align_offset; + } + if (offset < align_offset) + btrfs_add_free_space(block_group, offset, align_offset - offset); + BUG_ON(offset > align_offset); + + syno_allocator_candidate_compare(ctl, block_group, align_offset, align_len); +out: + btrfs_release_block_group(block_group, delalloc); + return; +} + +/* locked with space_info->syno_allocator.lock */ +static void syno_allocation_with_index(struct syno_allocation_ctl *ctl, struct rb_root_cached *root) +{ + int err; + struct btrfs_space_info *space_info; + struct btrfs_block_group *block_group; + struct rb_node *node; + int cached; + int nr_retry = 3; + bool caching = false; + + space_info = ctl->space_info; + +retry: + node = rb_first_cached(root); + for (; node; node = rb_next(node)) { + if (root == &space_info->syno_allocator.free_space_bytes) + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.bytes_index); + else if (root == &space_info->syno_allocator.free_space_max_length) + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.max_length_index); + else if (root == &space_info->syno_allocator.free_space_max_length_with_extent) + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.max_length_with_extent_index); + else + BUG(); + btrfs_get_block_group(block_group); + cached = btrfs_block_group_done(block_group); + if (!caching && unlikely(!cached)) { + spin_unlock(&space_info->syno_allocator.lock); + err = btrfs_cache_block_group(block_group, false); + if (!err) + syno_wait_block_group_cache_done(ctl, block_group, false); + btrfs_put_block_group(block_group); + spin_lock(&space_info->syno_allocator.lock); + caching = true; + goto retry; + } + if (unlikely(!block_group->syno_allocator.initialized)) + goto loop; + if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) + goto loop; + if (unlikely(block_group->ro)) + goto loop; + + spin_unlock(&space_info->syno_allocator.lock); + syno_allocation_with_block_group(ctl, block_group, block_group->start, true); + spin_lock(&space_info->syno_allocator.lock); + btrfs_put_block_group(block_group); + break; +loop: + btrfs_put_block_group(block_group); + if (--nr_retry < 0) + break; + } + return; +} + +static void syno_allocation_full_scan(struct syno_allocation_ctl *ctl) +{ + int err; + int index = btrfs_bg_flags_to_raid_index(ctl->flags); + struct btrfs_space_info *space_info; + struct btrfs_block_group *block_group; + bool cached; + + space_info = ctl->space_info; + atomic64_inc(&space_info->syno_allocator.fallback_full_scan_count); + +search: + list_for_each_entry(block_group, &space_info->block_groups[index], list) { + btrfs_get_block_group(block_group); + + /* + * this can happen if we end up cycling through all the + * raid types, but we want to make sure we only allocate + * for the proper type. + */ + if (!block_group_bits(block_group, ctl->flags)) { + u64 extra = BTRFS_BLOCK_GROUP_DUP | + BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID5 | + BTRFS_BLOCK_GROUP_RAID6 | + BTRFS_BLOCK_GROUP_RAID10; + + /* + * if they asked for extra copies and this block group + * doesn't provide them, bail. This does allow us to + * fill raid0 from raid1. + */ + if ((ctl->flags & extra) && !(block_group->flags & extra)) + goto loop; + } + + cached = btrfs_block_group_done(block_group); + if (unlikely(!cached)) { + err = btrfs_cache_block_group(block_group, true); + if (err) + goto loop; + } + + if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) + goto loop; + if (unlikely(block_group->ro)) + goto loop; + + syno_allocation_with_block_group(ctl, block_group, block_group->start, false); + if (!ctl->found_bg || ctl->found_len < ctl->min_alloc_size) + goto loop; + + btrfs_put_block_group(block_group); + break; +loop: + btrfs_put_block_group(block_group); + cond_resched(); + } + + if ((!ctl->found_bg || ctl->found_len < ctl->min_alloc_size) && ++index < BTRFS_NR_RAID_TYPES) + goto search; + + return; +} + +/* + * return 0 if it doesn't need to allocate a new chunk, + * return 1 if it successfully allocates a chunk, + * return errors including -ENOSPC otherwise. + */ +static int syno_chunk_allocate_policy(struct syno_allocation_ctl *ctl, bool force) +{ + int ret; + struct btrfs_root *root = ctl->fs_info->extent_root; + struct btrfs_trans_handle *trans; + bool exist = false; + + if (btrfs_mixed_space_info(ctl->space_info) || + !(ctl->flags & BTRFS_BLOCK_GROUP_DATA) || + force) + goto do_alloc; + + if (!ctl->check_data_ratio) + goto do_alloc; + + /* for data policy */ + if ((ctl->unallocated_ratio >= 50 && ctl->data_used_ratio >= 50) || + (ctl->unallocated_ratio >= 30 && ctl->data_used_ratio >= 70) || + (ctl->unallocated_ratio >= 10 && ctl->data_used_ratio >= 80) || + (ctl->unallocated_ratio < 10 && ctl->data_used_ratio >= 90) + ) { + } else { + ret = 0; + goto out; + } + +do_alloc: + trans = current->journal_info; + if (trans) { + exist = true; + } else { + mutex_unlock(&ctl->space_info->syno_allocator.syno_allocator_mutex); + trans = btrfs_join_transaction(root); + } + + if (IS_ERR(trans)) { + mutex_lock(&ctl->space_info->syno_allocator.syno_allocator_mutex); + ret = PTR_ERR(trans); + goto out; + } + + ret = btrfs_chunk_alloc(trans, ctl->flags, CHUNK_ALLOC_FORCE); + if (ret < 0 && ret != -ENOSPC) + btrfs_abort_transaction(trans, ret); + else if (ret > 0) + ret = 0; + if (!exist) { + btrfs_end_transaction(trans); + mutex_lock(&ctl->space_info->syno_allocator.syno_allocator_mutex); + } + if (ret) + goto out; + + ret = 1; +out: + return ret; +} + +static void syno_allocation_relink_first_entry_by_root(struct syno_allocation_ctl *ctl, struct rb_root_cached *root) +{ + struct btrfs_space_info *space_info; + struct btrfs_block_group *block_group; + struct rb_node *node; + + space_info = ctl->space_info; + + spin_lock(&space_info->syno_allocator.lock); + node = rb_first_cached(root); + if (node) { + if (root == &space_info->syno_allocator.free_space_bytes) + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.bytes_index); + else if (root == &space_info->syno_allocator.free_space_max_length) + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.max_length_index); + else if (root == &space_info->syno_allocator.free_space_max_length_with_extent) + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.max_length_with_extent_index); + else + BUG(); + btrfs_get_block_group(block_group); + spin_unlock(&space_info->syno_allocator.lock); + btrfs_syno_allocator_relink_block_group(block_group); + btrfs_put_block_group(block_group); + goto out; + } + spin_unlock(&space_info->syno_allocator.lock); +out: + return; +} + +static int syno_allocation(struct syno_allocation_ctl *ctl) +{ + int ret, err; + struct btrfs_space_info *space_info; + struct btrfs_block_group *block_group; + struct rb_node *node; + bool cached, check_preload = false; + u64 ram_bytes, free_bytes, fs_min_alloc_size; + static bool __warned = false; +#ifdef MY_ABC_HERE + bool use_log_bg = false; +#endif /* MY_ABC_HERE */ + int preload_nr_retry = 3; + bool data_match; + bool has_preload = !!rb_first_cached(&ctl->space_info->syno_allocator.preload); + int relink_nr_retry = 3; + + space_info = ctl->space_info; + down_read(&space_info->groups_sem); + down_read(&space_info->syno_allocator.allocation_sem); + + ret = syno_alloction_prepare(ctl); + if (ret) + goto out; + +#ifdef MY_ABC_HERE + /* + * Let metadata allocation of tree log try reserved block group first + */ + if (ctl->root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID && + ctl->fs_info->log_tree_rsv_start) { + block_group = btrfs_lookup_block_group(ctl->fs_info, ctl->fs_info->log_tree_rsv_start); + if (block_group && block_group_bits(block_group, ctl->flags)) { + cached = btrfs_block_group_done(block_group); + if (unlikely(!cached)) { + err = btrfs_cache_block_group(block_group, false); + if (!err) + syno_wait_block_group_cache_done(ctl, block_group, false); + } + /* use offset index */ + syno_allocation_with_block_group(ctl, block_group, space_info->syno_allocator.log_bg_offset, false); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) { + btrfs_put_block_group(block_group); + use_log_bg = true; + space_info->syno_allocator.log_bg_offset = ctl->found_offset + ctl->found_len; + goto found; + } + + /* use bytes index */ + syno_allocation_with_block_group(ctl, block_group, block_group->start, false); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) { + btrfs_put_block_group(block_group); + use_log_bg = true; + space_info->syno_allocator.log_bg_offset = ctl->found_offset + ctl->found_len; + goto found; + } + btrfs_put_block_group(block_group); + } else if (block_group) { + btrfs_put_block_group(block_group); + } + } +#endif /* MY_ABC_HERE */ + +again: + spin_lock(&space_info->syno_allocator.lock); + + /* find free space with cache bg */ + if (space_info->syno_allocator.cache_bg) { + spin_unlock(&space_info->syno_allocator.lock); + /* use offset index */ + syno_allocation_with_block_group(ctl, space_info->syno_allocator.cache_bg, space_info->syno_allocator.cache_offset, false); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) + goto found; + /* use bytes index */ + syno_allocation_with_block_group(ctl, space_info->syno_allocator.cache_bg, space_info->syno_allocator.cache_bg->start, false); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) + goto found; + spin_lock(&space_info->syno_allocator.lock); + } + + /* find free space with free space bytes */ + syno_allocation_with_index(ctl, &space_info->syno_allocator.free_space_bytes); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) { + spin_unlock(&space_info->syno_allocator.lock); + goto found; + } + + /* find free space with free space mex length */ + syno_allocation_with_index(ctl, &space_info->syno_allocator.free_space_max_length); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) { + spin_unlock(&space_info->syno_allocator.lock); + goto found; + } + + /* find free space with free space mex length with extent */ + syno_allocation_with_index(ctl, &space_info->syno_allocator.free_space_max_length_with_extent); + if (ctl->found_bg && ctl->found_len >= ctl->num_bytes) { + spin_unlock(&space_info->syno_allocator.lock); + goto found; + } + + if (ctl->found_bg && ctl->found_len >= ctl->min_alloc_size) { + if (check_preload && + time_after(jiffies, ctl->expire)) { + spin_unlock(&space_info->syno_allocator.lock); + goto found; + } + if (ctl->stage >= SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_LIMIT) { + spin_unlock(&space_info->syno_allocator.lock); + goto found; + } + /* for data policy */ + if (ctl->check_data_ratio) { + data_match = false; + if (ctl->unallocated_ratio >= 80) { + if (ctl->found_len >= ctl->num_bytes) + data_match = true; + } else if (ctl->unallocated_ratio >= 50) { + if (ctl->found_len >= SZ_32M) + data_match = true; + } else if (ctl->unallocated_ratio >= 30) { + if (ctl->found_len >= SZ_16M) + data_match = true; + } else if (ctl->unallocated_ratio >= 10) { + if (ctl->found_len >= SZ_8M) + data_match = true; + } else { /* unallocated_ratio < 10 */ + if (ctl->found_len >= SZ_4M) + data_match = true; + } + if (data_match) { + spin_unlock(&space_info->syno_allocator.lock); + goto found; + } + } + } + + if ((node = rb_first_cached(&space_info->syno_allocator.preload))) { + check_preload = true; + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.preload_index); + if (ctl->stage < SYNO_ALLOCATION_STAGE_CACHING_FORCE_WAIT) { + if (--preload_nr_retry < 0) + goto skip_preload; + spin_lock(&block_group->lock); + free_bytes = block_group->length - block_group->used; + spin_unlock(&block_group->lock); + if (!syno_allocation_precheck_free_space(ctl, block_group->length, free_bytes, true)) + goto skip_preload; + } + btrfs_get_block_group(block_group); + cached = btrfs_block_group_done(block_group); + if (unlikely(!cached)) { + spin_unlock(&space_info->syno_allocator.lock); + btrfs_cache_block_group(block_group, true); + } else { + if (!RB_EMPTY_NODE(&block_group->syno_allocator.preload_index)) { + rb_erase_cached(&block_group->syno_allocator.preload_index, &space_info->syno_allocator.preload); + RB_CLEAR_NODE(&block_group->syno_allocator.preload_index); + } + spin_unlock(&space_info->syno_allocator.lock); + } + btrfs_put_block_group(block_group); + cond_resched(); + goto again; + } +skip_preload: + spin_unlock(&space_info->syno_allocator.lock); + + ctl->stage++; + if (ctl->stage == SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_LIMIT || + ctl->stage == SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_FORCE) { + if (btrfs_mixed_space_info(ctl->space_info) || + !(ctl->flags & BTRFS_BLOCK_GROUP_DATA)) + ctl->stage = SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_FORCE; + up_read(&space_info->syno_allocator.allocation_sem); + up_read(&space_info->groups_sem); + err = syno_chunk_allocate_policy(ctl, ctl->stage >= SYNO_ALLOCATION_STAGE_CHUNK_ALLOCATE_FORCE); + down_read(&space_info->groups_sem); + down_read(&space_info->syno_allocator.allocation_sem); + if (err < 0 && err != -ENOSPC) { + ret = err; + goto out; + } + goto again; + } + if (ctl->stage == SYNO_ALLOCATION_STAGE_SKIP_META_RESERVE) { + if (!btrfs_mixed_space_info(ctl->space_info) && + (ctl->flags & BTRFS_BLOCK_GROUP_METADATA) && + !ctl->meta_space_info_full) + goto again; + else + ctl->stage++; + } + if (ctl->stage == SYNO_ALLOCATION_STAGE_CACHING_FORCE_WAIT) { + if (has_preload) + goto again; + else + ctl->stage++; + } + if (ctl->stage == SYNO_ALLOCATION_STAGE_RELINK_RETRY) { + relink_nr_retry--; + if ((ctl->found_bg && ctl->found_len >= ctl->min_alloc_size) || + (ctl->is_data && ctl->min_alloc_size != ctl->fs_info->sectorsize) || + relink_nr_retry < 0) { + ctl->stage++; + } else { + atomic64_inc(&space_info->syno_allocator.fallback_relink_count); + syno_allocation_relink_first_entry_by_root(ctl, &space_info->syno_allocator.free_space_bytes); + syno_allocation_relink_first_entry_by_root(ctl, &space_info->syno_allocator.free_space_max_length); + syno_allocation_relink_first_entry_by_root(ctl, &space_info->syno_allocator.free_space_max_length_with_extent); + ctl->stage--; + goto again; + } + } + if (ctl->stage == SYNO_ALLOCATION_STAGE_FULL_SCAN) { + if ((ctl->found_bg && ctl->found_len >= ctl->min_alloc_size) || + (ctl->is_data && ctl->min_alloc_size != ctl->fs_info->sectorsize)) + ctl->stage++; + else + syno_allocation_full_scan(ctl); + } + + if (!ctl->found_bg || ctl->found_len < ctl->min_alloc_size) { + ctl->result->offset = ctl->found_len; + ret = -ENOSPC; + goto out; + } + +found: + /* update reserve/delalloc bytes */ + if (ctl->found_len == ctl->num_bytes) + ram_bytes = ctl->ram_bytes; + else + ram_bytes = ctl->found_len; + ret = btrfs_add_reserved_bytes(ctl->found_bg, ram_bytes, ctl->found_len, ctl->delalloc); + if (ret == -EAGAIN) { + /* release candidate */ + btrfs_add_free_space(ctl->found_bg, ctl->found_offset, ctl->found_len); + atomic_dec(&ctl->found_bg->syno_allocator.refs); + ctl->found_bg = NULL; + ctl->found_offset = 0; + ctl->found_len = 0; + goto again; + } + trace_btrfs_reserve_extent(ctl->found_bg, ctl->found_offset, ctl->found_len); + /* avoid balance racing */ + if (ctl->is_data) + btrfs_inc_block_group_reservations(ctl->found_bg); + +#ifdef MY_ABC_HERE + if (use_log_bg) + goto skip_cache_found_bg; +#endif /* MY_ABC_HERE */ + + /* cache found block_group */ + spin_lock(&space_info->syno_allocator.lock); + if (!space_info->syno_allocator.cache_bg) { + space_info->syno_allocator.cache_bg = ctl->found_bg; + btrfs_get_block_group(space_info->syno_allocator.cache_bg); + } else if (space_info->syno_allocator.cache_bg && space_info->syno_allocator.cache_bg != ctl->found_bg) { + btrfs_put_block_group(space_info->syno_allocator.cache_bg); + space_info->syno_allocator.cache_bg = ctl->found_bg; + btrfs_get_block_group(space_info->syno_allocator.cache_bg); + } + space_info->syno_allocator.cache_offset = ctl->found_offset + ctl->found_len; + spin_unlock(&space_info->syno_allocator.lock); + +#ifdef MY_ABC_HERE +skip_cache_found_bg: +#endif /* MY_ABC_HERE */ + + ctl->result->objectid = ctl->found_offset; + ctl->result->offset = ctl->found_len; + + ret = 0; +out: + fs_min_alloc_size = ctl->is_data ? ctl->fs_info->sectorsize : ctl->fs_info->nodesize; + if (ret && ctl->min_alloc_size == fs_min_alloc_size && !__warned) { + btrfs_err(ctl->fs_info, "allocation failed flags %llu, wanted %llu, min_alloc:%llu, found_bg:%d, found_len:%llu, ret:%d", ctl->flags, ctl->num_bytes, ctl->min_alloc_size, ctl->found_bg ? 1 : 0, ctl->found_len, ret); + btrfs_dump_space_info(ctl->fs_info, space_info, ctl->num_bytes, 0); + WARN_ON_ONCE(1); + __warned = true; + } + if (ctl->found_bg) { + if (ret) + btrfs_add_free_space(ctl->found_bg, ctl->found_offset, ctl->found_len); + atomic_dec(&ctl->found_bg->syno_allocator.refs); + ctl->found_bg = NULL; + ctl->found_offset = 0; + ctl->found_len = 0; + } + up_read(&space_info->syno_allocator.allocation_sem); + up_read(&space_info->groups_sem); + return ret; +} + +/* + * btrfs_syno_allocator - entry point to the syno allocator. Tries to find a + * hole that is at least as big as @num_bytes. + * + * @root - The root that will contain this extent + * + * @ram_bytes - The amount of space in ram that @num_bytes take. This + * is used for accounting purposes. This value differs + * from @num_bytes only in the case of compressed extents. + * + * @num_bytes - Number of bytes to allocate on-disk. + * + * @min_alloc_size - Indicates the minimum amount of space that the + * allocator should try to satisfy. In some cases + * @num_bytes may be larger than what is required and if + * the filesystem is fragmented then allocation fails. + * However, the presence of @min_alloc_size gives a + * chance to try and satisfy the smaller allocation. + * + * @empty_size - A hint that you plan on doing more COW. This is the + * size in bytes the allocator should try to find free + * next to the block it returns. This is just a hint and + * may be ignored by the allocator. + * + * @hint_byte - Hint to the allocator to start searching above the byte + * address passed. It might be ignored. + * + * @ins - This key is modified to record the found hole. It will + * have the following values: + * ins->objectid == start position + * ins->flags = BTRFS_EXTENT_ITEM_KEY + * ins->offset == the size of the hole. + * + * @is_data - Boolean flag indicating whether an extent is + * allocated for data (true) or metadata (false) + * + * @delalloc - Boolean flag indicating whether this allocation is for + * delalloc or not. If 'true' data_rwsem of block groups + * is going to be acquired. + * + * + * Returns 0 when an allocation succeeded or < 0 when an error occurred. In + * case -ENOSPC is returned then @ins->offset will contain the size of the + * largest available hole the allocator managed to find. + */ +static int btrfs_syno_allocator(struct btrfs_root *root, u64 ram_bytes, + u64 num_bytes, u64 min_alloc_size, + u64 empty_size, u64 hint_byte, + struct btrfs_key *ins, int is_data, int delalloc) +{ + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_free_cluster *cluster; + struct syno_allocation_ctl ctl = {0}; + u64 empty_cluster; + + wait_event(fs_info->syno_allocator.legacy_allocator_wait, + atomic_read(&fs_info->syno_allocator.legacy_allocator_refs) == 0); + + atomic_inc(&fs_info->syno_allocator.syno_allocator_refs); + + ctl.fs_info = root->fs_info; + ctl.root = root; + ctl.ram_bytes = ram_bytes; + ctl.num_bytes = num_bytes; + ctl.min_alloc_size = min_alloc_size; + ctl.is_data = is_data; + ctl.delalloc = delalloc; + ctl.result = ins; + + ctl.flags = get_alloc_profile_by_root(ctl.root, ctl.is_data); + ctl.space_info = btrfs_find_space_info(ctl.fs_info, ctl.flags); + if (!ctl.space_info) { + btrfs_err(ctl.fs_info, "No space info for %llu", ctl.flags); + ret = -EINVAL; + goto out; + } + + mutex_lock(&ctl.space_info->syno_allocator.syno_allocator_mutex); + if (ctl.space_info->syno_allocator.force_cluster_disable) { + /* make sure disable cluster for legacy allocation */ + cluster = fetch_cluster_info(ctl.fs_info, ctl.space_info, &empty_cluster); + if (cluster) { + spin_lock(&cluster->refill_lock); + btrfs_return_cluster_to_free_space(NULL, cluster); + spin_unlock(&cluster->refill_lock); + } + ctl.space_info->syno_allocator.force_cluster_disable = false; + } + + ret = syno_allocation(&ctl); + mutex_unlock(&ctl.space_info->syno_allocator.syno_allocator_mutex); +out: + if (atomic_dec_and_test(&fs_info->syno_allocator.syno_allocator_refs) && + waitqueue_active(&fs_info->syno_allocator.syno_allocator_wait)) + wake_up(&fs_info->syno_allocator.syno_allocator_wait); + return ret; +} +int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, + u64 num_bytes, u64 min_alloc_size, + u64 empty_size, u64 hint_byte, + struct btrfs_key *ins, int is_data, int delalloc) +{ + if (btrfs_test_opt(root->fs_info, SYNO_ALLOCATOR)) + return btrfs_syno_allocator(root, ram_bytes, num_bytes, min_alloc_size, empty_size, hint_byte, ins, is_data, delalloc); + return btrfs_legacy_allocator(root, ram_bytes, num_bytes, min_alloc_size, empty_size, hint_byte, ins, is_data, delalloc); +} + +static void btrfs_syno_allocator_space_info_prefetch(struct btrfs_fs_info *fs_info, struct btrfs_space_info *space_info) +{ + struct btrfs_block_group *block_group; + struct rb_node *node; + bool cached; + + if (!fs_info || !space_info) + goto out; + + if (!fs_info->syno_allocator.bg_prefetch_running || + fs_info->sb->s_flags & SB_RDONLY || + btrfs_fs_closing(fs_info)) + goto out; + + spin_lock(&space_info->syno_allocator.lock); + while ((node = rb_first_cached(&space_info->syno_allocator.preload))) { + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.preload_index); + btrfs_get_block_group(block_group); + cached = btrfs_block_group_done(block_group); + if (unlikely(!cached)) { + spin_unlock(&space_info->syno_allocator.lock); + btrfs_cache_block_group(block_group, true); + spin_lock(&space_info->syno_allocator.lock); + } + if (!RB_EMPTY_NODE(&block_group->syno_allocator.preload_index)) { + rb_erase_cached(&block_group->syno_allocator.preload_index, &space_info->syno_allocator.preload); + RB_CLEAR_NODE(&block_group->syno_allocator.preload_index); + } + btrfs_put_block_group(block_group); + if (!fs_info->syno_allocator.bg_prefetch_running || + fs_info->sb->s_flags & SB_RDONLY || + btrfs_fs_closing(fs_info)) + break; + cond_resched_lock(&space_info->syno_allocator.lock); + } + spin_unlock(&space_info->syno_allocator.lock); +out: + return; +} + +static void __btrfs_syno_allocator_bg_prefetch_work(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_space_info *space_info; + + fs_info = container_of(work, struct btrfs_fs_info, syno_allocator.bg_prefetch_work); + + /* prefetch system */ + space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM); + btrfs_syno_allocator_space_info_prefetch(fs_info, space_info); + + /* prefetch data */ + space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA); + btrfs_syno_allocator_space_info_prefetch(fs_info, space_info); + + /* prefetch meta */ + space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); + btrfs_syno_allocator_space_info_prefetch(fs_info, space_info); + + return; +} +void btrfs_init_syno_allocator_bg_prefetch_work(struct work_struct *work) +{ + INIT_WORK(work, __btrfs_syno_allocator_bg_prefetch_work); +} +#endif /* MY_ABC_HERE */ + int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len, int delalloc) { @@ -4340,7 +5901,11 @@ int btrfs_pin_reserved_extent(struct btrfs_trans_handle *trans, u64 start, static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, u64 parent, u64 root_objectid, u64 flags, u64 owner, u64 offset, - struct btrfs_key *ins, int ref_mod) + struct btrfs_key *ins, int ref_mod +#ifdef MY_ABC_HERE + , struct btrfs_delayed_ref_node *node +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = trans->fs_info; int ret; @@ -4407,6 +5972,12 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, ins->objectid, ins->offset); BUG(); } + +#ifdef MY_ABC_HERE + if (!ret) + btrfs_insert_quota_record(trans, node); +#endif /* MY_ABC_HERE */ + trace_btrfs_reserved_extent_alloc(fs_info, ins->objectid, ins->offset); return ret; } @@ -4507,7 +6078,14 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 owner, u64 offset, u64 ram_bytes, - struct btrfs_key *ins) + struct btrfs_key *ins +#ifdef MY_ABC_HERE + , int syno_usage +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , struct inode *inode +#endif /* MY_ABC_HERE */ + ) { struct btrfs_ref generic_ref = { 0 }; @@ -4515,7 +6093,20 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT, ins->objectid, ins->offset, 0); - btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, offset); + btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, offset +#ifdef MY_ABC_HERE + , syno_usage +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (btrfs_root_disable_quota(root)) + generic_ref.skip_qgroup = true; + else { + generic_ref.skip_qgroup = false; + generic_ref.ram_bytes = ram_bytes; + generic_ref.inode = inode; + } +#endif /* MY_ABC_HERE */ btrfs_ref_tree_mod(root->fs_info, &generic_ref); return btrfs_add_delayed_data_ref(trans, &generic_ref, ram_bytes); @@ -4528,12 +6119,19 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, */ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, u64 root_objectid, u64 owner, u64 offset, - struct btrfs_key *ins) + struct btrfs_key *ins +#ifdef MY_ABC_HERE + , struct inode *inode +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = trans->fs_info; int ret; struct btrfs_block_group *block_group; struct btrfs_space_info *space_info; +#ifdef MY_ABC_HERE + struct btrfs_delayed_data_ref ref = {0}; +#endif /* MY_ABC_HERE */ /* * Mixed block groups will exclude before processing the log so we only @@ -4558,8 +6156,22 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); +#ifdef MY_ABC_HERE + ref.root = root_objectid; + ref.node.num_bytes = ins->offset; + ref.inode = inode; + if (!is_fstree(root_objectid)) + ref.skip_qgroup = true; + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ + ret = alloc_reserved_file_extent(trans, 0, root_objectid, 0, owner, - offset, ins, 1); + offset, ins, 1 +#ifdef MY_ABC_HERE + , &ref.node +#endif /* MY_ABC_HERE */ + ); if (ret) btrfs_pin_extent(trans, ins->objectid, ins->offset, 1); btrfs_put_block_group(block_group); @@ -4715,6 +6327,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, out_free_delayed: btrfs_free_delayed_extent_op(extent_op); out_free_buf: + btrfs_tree_unlock(buf); free_extent_buffer(buf); out_free_reserved: btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 0); @@ -4916,7 +6529,11 @@ static int check_ref_exists(struct btrfs_trans_handle *trans, ret = lookup_extent_backref(trans, path, &iref, bytenr, root->fs_info->nodesize, parent, - root->root_key.objectid, level, 0); + root->root_key.objectid, level, 0 +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); btrfs_free_path(path); if (ret == -ENOENT) return 0; @@ -5097,6 +6714,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, wc->restarted = 0; } +#ifdef MY_ABC_HERE +#else /* * Reloc tree doesn't contribute to qgroup numbers, and we have * already accounted them at merge time (replace_path), @@ -5112,6 +6731,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, ret); } } +#endif /* MY_ABC_HERE */ /* * We need to update the next key in our walk control so we can @@ -5215,6 +6835,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, else ret = btrfs_dec_ref(trans, root, eb, 0); BUG_ON(ret); /* -ENOMEM */ +#ifdef MY_ABC_HERE +#else if (is_fstree(root->root_key.objectid)) { ret = btrfs_qgroup_trace_leaf_items(trans, eb); if (ret) { @@ -5223,6 +6845,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, ret); } } +#endif /* MY_ABC_HERE */ } /* make block locked assertion in btrfs_clean_tree_block happy */ if (!path->locks[level] && @@ -5326,6 +6949,42 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans, return 1; } +#ifdef MY_ABC_HERE +static void btrfs_syno_block_rsv_refill(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *block_rsv, unsigned int max_items) +{ + u64 num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1); + u64 total_bytes; + int err; + + spin_lock(&block_rsv->lock); + if (block_rsv->reserved < block_rsv->size) + total_bytes = block_rsv->size - block_rsv->reserved; + else + total_bytes = 0; + spin_unlock(&block_rsv->lock); + + if (!total_bytes) + goto out; + + while(total_bytes > 0 && max_items > 0) { + err = btrfs_reserve_metadata_bytes(fs_info->extent_root, block_rsv, num_bytes, BTRFS_RESERVE_FLUSH_ALL); + if (err) + goto out; + if (total_bytes >= num_bytes) + total_bytes -= num_bytes; + else + total_bytes = 0; + btrfs_block_rsv_add_bytes(block_rsv, num_bytes, 0); + if (block_rsv->full) + break; + max_items--; + } + +out: + return; +} +#endif /* MY_ABC_HERE */ + /* * drop a subvolume tree. * @@ -5352,9 +7011,38 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) int ret; int level; bool root_dropped = false; +#ifdef MY_ABC_HERE + struct btrfs_key drop_key; + struct btrfs_key syno_usage_prepare_dummy_key; + struct btrfs_key syno_usage_dummy_key; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; + struct btrfs_block_rsv *cleaner_rsv = &fs_info->cleaner_block_rsv; + bool use_cleaner_rsv = false; + int updates; +#endif /* MY_ABC_HERE */ btrfs_debug(fs_info, "Drop subvolume %llu", root->root_key.objectid); +#ifdef MY_ABC_HERE + syno_usage_prepare_dummy_key.objectid = 0; + syno_usage_prepare_dummy_key.type = 0; + syno_usage_prepare_dummy_key.offset = 0; + syno_usage_dummy_key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + syno_usage_dummy_key.type = SYNO_BTRFS_SUBVOL_DUMMY_KEY; + syno_usage_dummy_key.offset = 1; + if (!for_reloc) { + btrfs_disk_key_to_cpu(&drop_key, &root_item->drop_progress); + if (0 == btrfs_comp_cpu_keys(&drop_key, &syno_usage_prepare_dummy_key)) + err = btrfs_syno_clear_subvol_usage_item_prepare(root); + else if (0 == btrfs_comp_cpu_keys(&drop_key, &syno_usage_dummy_key)) + err = btrfs_syno_clear_subvol_usage_item_doing(root); + if (err) + goto out; + } +#endif /* MY_ABC_HERE */ + path = btrfs_alloc_path(); if (!path) { err = -ENOMEM; @@ -5368,6 +7056,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) goto out; } +#ifdef MY_ABC_HERE + spin_lock(&cleaner_rsv->lock); + if (!for_reloc && cleaner_rsv->size) + use_cleaner_rsv = true; + spin_unlock(&cleaner_rsv->lock); + btrfs_syno_block_rsv_refill(fs_info, cleaner_rsv, -1); +#endif /* MY_ABC_HERE */ + /* * Use join to avoid potential EINTR from transaction start. See * wait_reserve_ticket and the whole reservation callchain. @@ -5380,6 +7076,9 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) err = PTR_ERR(trans); goto out_free; } +#ifdef MY_ABC_HERE + trans->cleaner = use_cleaner_rsv; +#endif /* MY_ABC_HERE */ err = btrfs_run_delayed_items(trans); if (err) @@ -5402,10 +7101,18 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; memset(&wc->update_progress, 0, sizeof(wc->update_progress)); +#ifdef MY_ABC_HERE + memset(&wc->drop_progress, 0, + sizeof(wc->drop_progress)); +#endif /* MY_ABC_HERE */ } else { btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); memcpy(&wc->update_progress, &key, sizeof(wc->update_progress)); +#ifdef MY_ABC_HERE + memcpy(&wc->drop_progress, &key, + sizeof(wc->drop_progress)); +#endif /* MY_ABC_HERE */ level = root_item->drop_level; BUG_ON(level == 0); @@ -5452,6 +7159,9 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) wc->restarted = test_bit(BTRFS_ROOT_DEAD_TREE, &root->state); wc->level = level; +#ifdef MY_ABC_HERE + wc->drop_level = level; +#endif /* MY_ABC_HERE */ wc->shared_level = -1; wc->stage = DROP_REFERENCE; wc->update_ref = update_ref; @@ -5487,9 +7197,25 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) &wc->drop_progress); root_item->drop_level = wc->drop_level; +#ifdef MY_ABC_HERE + btrfs_disk_key_to_cpu(&drop_key, &root_item->drop_progress); +#endif /* MY_ABC_HERE */ + BUG_ON(wc->level == 0); - if (btrfs_should_end_transaction(trans) || - (!for_reloc && btrfs_need_cleaner_sleep(fs_info))) { + if ( +#ifdef MY_ABC_HERE + /* cleaner throttle */ + true || +#endif /* MY_ABC_HERE */ + btrfs_should_end_transaction(trans) || +#ifdef MY_ABC_HERE + (!for_reloc && btrfs_comp_cpu_keys(&drop_key, &syno_usage_dummy_key) == 0) || +#endif /* MY_ABC_HERE */ + (!for_reloc && (btrfs_need_cleaner_sleep(fs_info) +#ifdef MY_ABC_HERE + || !root->fs_info->snapshot_cleaner +#endif /* MY_ABC_HERE */ + ))) { ret = btrfs_update_root(trans, tree_root, &root->root_key, root_item); @@ -5499,13 +7225,52 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) goto out_end_trans; } - btrfs_end_transaction_throttle(trans); - if (!for_reloc && btrfs_need_cleaner_sleep(fs_info)) { - btrfs_debug(fs_info, - "drop snapshot early exit"); - err = -EAGAIN; - goto out_free; +#ifdef MY_ABC_HERE + updates = trans->total_delayed_ref_updates; + trans->total_delayed_ref_updates = 0; + ret = btrfs_run_delayed_refs(trans, updates * 2); + if (ret) { + btrfs_abort_transaction(trans, ret); + err = ret; + goto out_end_trans; } +#endif /* MY_ABC_HERE */ + + btrfs_end_transaction_throttle(trans); + if (!for_reloc) { + if (btrfs_need_cleaner_sleep(fs_info) +#ifdef MY_ABC_HERE + /* + * We have queued lots of reclaim space entries. + * Deal with them before it's getting too large. + */ + || fs_info->reclaim_space_entry_count >= 16384 +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + || !root->fs_info->snapshot_cleaner +#endif /* MY_ABC_HERE */ + ) { + btrfs_debug(fs_info, + "drop snapshot early exit"); + err = -EAGAIN; + goto out_free; + } + } +#ifdef MY_ABC_HERE + if (!for_reloc && btrfs_comp_cpu_keys(&drop_key, &syno_usage_dummy_key) == 0) { + err = btrfs_syno_clear_subvol_usage_item_doing(root); + if (err) + goto out_free; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + btrfs_syno_block_rsv_refill(fs_info, global_rsv, updates * 2); + btrfs_syno_block_rsv_refill(fs_info, cleaner_rsv, -1); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_syno_btree_balance_dirty(fs_info, true); +#endif /* MY_ABC_HERE */ /* * Use join to avoid potential EINTR from transaction @@ -5520,11 +7285,21 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) err = PTR_ERR(trans); goto out_free; } +#ifdef MY_ABC_HERE + trans->cleaner = use_cleaner_rsv; +#endif /* MY_ABC_HERE */ } } btrfs_release_path(path); +#ifdef MY_ABC_HERE + if (err) { + btrfs_abort_transaction(trans, err); + goto out_end_trans; + } +#else /* MY_ABC_HERE */ if (err) goto out_end_trans; +#endif /* MY_ABC_HERE */ ret = btrfs_del_root(trans, &root->root_key); if (ret) { @@ -5532,6 +7307,15 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) err = ret; goto out_end_trans; } +#ifdef MY_ABC_HERE + ret = btrfs_syno_usage_root_status_remove(trans, root->root_key.objectid); + if (ret) { + btrfs_abort_transaction(trans, ret); + err = ret; + goto out_end_trans; + } +#endif /* MY_ABC_HERE */ + if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) { ret = btrfs_find_root(tree_root, &root->root_key, path, @@ -5559,6 +7343,38 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) btrfs_qgroup_convert_reserved_meta(root, INT_MAX); btrfs_qgroup_free_meta_all_pertrans(root); +#ifdef MY_ABC_HERE + if (!for_reloc && fs_info->quota_root) { + u64 rootid = root->root_key.objectid; + ret = btrfs_remove_qgroup(trans, rootid); + if (ret) + btrfs_err(fs_info, + "failed to delelte qgroup item, rootid=%llu, ret=%d\n", rootid, ret); + } + + if (!for_reloc && fs_info->usrquota_root) { + u64 rootid = root->root_key.objectid; + ret = btrfs_usrquota_delsnap(trans, root); + if (ret) + btrfs_err(fs_info, + "failed to delete usrquota items, rootid=%llu, ret=%d", rootid, ret); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!list_empty(&root->root_list)) { + btrfs_warn(fs_info, "root_list not empty when drop snapshot"); + WARN_ON_ONCE(1); + spin_lock(&fs_info->trans_lock); + list_del_init(&root->root_list); + spin_unlock(&fs_info->trans_lock); + } + if (!list_empty(&root->syno_orphan_cleanup.root)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + list_del_init(&root->syno_orphan_cleanup.root); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } +#endif /* MY_ABC_HERE */ if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state)) btrfs_add_dropped_root(trans, root); else @@ -5570,6 +7386,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) kfree(wc); btrfs_free_path(path); out: +#ifdef MY_ABC_HERE + btrfs_syno_block_rsv_refill(fs_info, global_rsv, -1); + btrfs_syno_block_rsv_refill(fs_info, cleaner_rsv, -1); +#endif /* MY_ABC_HERE */ /* * So if we need to stop dropping the snapshot for whatever reason we * need to make sure to add it back to the dead root list so that we @@ -5577,8 +7397,24 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc) * don't have it in the radix (like when we recover after a power fail * or unmount) so we don't leak memory. */ + +#ifdef MY_ABC_HERE + if (!for_reloc && root_dropped == false && + !list_empty(&root->root_list)) { + btrfs_warn(fs_info, "root_list not empty when drop snapshot"); + WARN_ON_ONCE(1); + spin_lock(&fs_info->trans_lock); + list_del_init(&root->root_list); + spin_unlock(&fs_info->trans_lock); + } +#endif /* MY_ABC_HERE */ + if (!for_reloc && !root_dropped) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + btrfs_add_dead_root_head(root); +#else /* MY_ABC_HERE || MY_ABC_HERE */ btrfs_add_dead_root(root); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ return err; } @@ -5693,6 +7529,10 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, return unpin_extent_range(fs_info, start, end, false); } +#ifdef MY_ABC_HERE +#define MAX_SYNO_HINT_BYTES round_down(UINT_MAX, 512) +#endif /* MY_ABC_HERE */ + /* * It used to be that old block groups would be left around forever. * Iterating over them would be enough to trim unused space. Since we @@ -5713,17 +7553,39 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, * it while performing the free space search since we have already * held back allocations. */ -static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) +static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { u64 start = SZ_1M, len = 0, end = 0; int ret; +#ifdef MY_ABC_HERE + unsigned extent_bits; +#endif /* MY_ABC_HERE */ *trimmed = 0; /* Discard not supported = nothing to do. */ - if (!blk_queue_discard(bdev_get_queue(device->bdev))) + if (!blk_queue_discard(bdev_get_queue(device->bdev)) +#ifdef MY_ABC_HERE + && act != TRIM_SEND_HINT +#endif /* MY_ABC_HERE */ + ) return 0; +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT && + !blk_queue_unused_hint(bdev_get_queue(device->bdev))) + return 0; + + if (act == TRIM_SEND_HINT) + extent_bits = CHUNK_UNUSED_HINT; + else + extent_bits = CHUNK_TRIMMED; +#endif /* MY_ABC_HERE */ + /* Not writable = nothing to do. */ if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) return 0; @@ -5744,7 +7606,12 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) find_first_clear_extent_bit(&device->alloc_state, start, &start, &end, - CHUNK_TRIMMED | CHUNK_ALLOCATED); +#ifdef MY_ABC_HERE + extent_bits | CHUNK_ALLOCATED +#else /* MY_ABC_HERE */ + CHUNK_TRIMMED | CHUNK_ALLOCATED +#endif /* MY_ABC_HERE */ + ); /* Check if there are any CHUNK_* bits left */ if (start > device->total_bytes) { @@ -5778,12 +7645,26 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) break; } +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT && len > MAX_SYNO_HINT_BYTES) + len = MAX_SYNO_HINT_BYTES; +#endif /* MY_ABC_HERE */ + ret = btrfs_issue_discard(device->bdev, start, len, - &bytes); + &bytes +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (!ret) set_extent_bits(&device->alloc_state, start, start + bytes - 1, - CHUNK_TRIMMED); +#ifdef MY_ABC_HERE + extent_bits +#else /* MY_ABC_HERE */ + CHUNK_TRIMMED +#endif /* MY_ABC_HERE */ + ); mutex_unlock(&fs_info->chunk_mutex); if (ret) @@ -5800,6 +7681,15 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) cond_resched(); } +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT) { + mutex_lock(&device->fs_info->chunk_mutex); + clear_extent_bits(&device->alloc_state, 0, + (u64) -1, CHUNK_UNUSED_HINT); + mutex_unlock(&device->fs_info->chunk_mutex); + } +#endif /* MY_ABC_HERE */ + return ret; } @@ -5812,7 +7702,11 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) * an error. The return value will be the last error, or 0 if nothing bad * happens. */ -int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) +int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { struct btrfs_block_group *cache = NULL; struct btrfs_device *device; @@ -5836,6 +7730,22 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) check_add_overflow(range->start, range->len, &range_end)) return -EINVAL; +#ifdef MY_ABC_HERE + /* We want to scan large free spaces first*/ + if (act == TRIM_SEND_HINT) { + mutex_lock(&fs_info->fs_devices->device_list_mutex); + devices = &fs_info->fs_devices->devices; + list_for_each_entry(device, devices, dev_list) { + ret = btrfs_trim_free_extents(device, &group_trimmed, + TRIM_SEND_HINT); + if (ret) + break; + trimmed += group_trimmed; + } + mutex_unlock(&fs_info->fs_devices->device_list_mutex); + } +#endif /* MY_ABC_HERE */ + cache = btrfs_lookup_first_block_group(fs_info, range->start); for (; cache; cache = btrfs_next_block_group(cache)) { if (cache->start >= range_end) { @@ -5846,15 +7756,14 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) start = max(range->start, cache->start); end = min(range_end, cache->start + cache->length); +#ifdef MY_ABC_HERE + if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) + continue; +#endif /* MY_ABC_HERE */ + if (end - start >= range->minlen) { if (!btrfs_block_group_done(cache)) { - ret = btrfs_cache_block_group(cache, 0); - if (ret) { - bg_failed++; - bg_ret = ret; - continue; - } - ret = btrfs_wait_block_group_cache_done(cache); + ret = btrfs_cache_block_group(cache, true); if (ret) { bg_failed++; bg_ret = ret; @@ -5865,7 +7774,11 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) &group_trimmed, start, end, - range->minlen); + range->minlen +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); trimmed += group_trimmed; if (ret) { @@ -5880,13 +7793,22 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) btrfs_warn(fs_info, "failed to trim %llu block group(s), last error %d", bg_failed, bg_ret); +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT) + goto done; +#endif /* MY_ABC_HERE */ + mutex_lock(&fs_info->fs_devices->device_list_mutex); devices = &fs_info->fs_devices->devices; list_for_each_entry(device, devices, dev_list) { if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) continue; - ret = btrfs_trim_free_extents(device, &group_trimmed); + ret = btrfs_trim_free_extents(device, &group_trimmed +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); if (ret) { dev_failed++; dev_ret = ret; @@ -5897,6 +7819,10 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) } mutex_unlock(&fs_info->fs_devices->device_list_mutex); +#ifdef MY_ABC_HERE +done: +#endif /* MY_ABC_HERE */ + if (dev_failed) btrfs_warn(fs_info, "failed to trim %llu device(s), last error %d", diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 81e98a457130..e9924649cf5d 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include @@ -24,6 +27,9 @@ #include "rcu-string.h" #include "backref.h" #include "disk-io.h" +#ifdef MY_ABC_HERE +#include "qgroup.h" +#endif /* MY_ABC_HERE */ static struct kmem_cache *extent_state_cache; static struct kmem_cache *extent_buffer_cache; @@ -133,6 +139,10 @@ struct tree_entry { struct extent_page_data { struct bio *bio; +#ifdef MY_ABC_HERE + unsigned long bio_flags; +#endif /* MY_ABC_HERE */ + /* tells writepage not to lock the state bits for this range * it still does the unlocking */ @@ -155,8 +165,12 @@ static int add_extent_changeset(struct extent_state *state, unsigned bits, if (!set && (state->state & bits) == 0) return 0; changeset->bytes_changed += state->end - state->start + 1; +#ifdef MY_ABC_HERE + ret = ulist_add_for_prealloc(&changeset->range_changed, state->start, state->end, GFP_ATOMIC, &changeset->prealloc_ulist_node); +#else /* MY_ABC_HERE */ ret = ulist_add(&changeset->range_changed, state->start, state->end, GFP_ATOMIC); +#endif /* MY_ABC_HERE */ return ret; } @@ -199,7 +213,11 @@ static int __must_check flush_write_bio(struct extent_page_data *epd) int ret = 0; if (epd->bio) { +#ifdef MY_ABC_HERE + ret = submit_one_bio(epd->bio, 0, epd->bio_flags); +#else /* MY_ABC_HERE */ ret = submit_one_bio(epd->bio, 0, 0); +#endif /* MY_ABC_HERE */ /* * Clean up of epd->bio is handled by its endio function. * And endio is either triggered by successful bio execution @@ -629,7 +647,11 @@ static struct extent_state *next_state(struct extent_state *state) static struct extent_state *clear_state_bit(struct extent_io_tree *tree, struct extent_state *state, unsigned *bits, int wake, - struct extent_changeset *changeset) + struct extent_changeset *changeset +#ifdef MY_ABC_HERE + , u64 *add_bytes +#endif /* MY_ABC_HERE */ + ) { struct extent_state *next; unsigned bits_to_clear = *bits & ~EXTENT_CTLBITS; @@ -642,7 +664,11 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree, } if (tree->private_data && is_data_inode(tree->private_data)) +#ifdef MY_ABC_HERE + btrfs_clear_delalloc_extent(tree->private_data, state, bits, add_bytes); +#else btrfs_clear_delalloc_extent(tree->private_data, state, bits); +#endif /* MY_ABC_HERE */ ret = add_extent_changeset(state, bits_to_clear, changeset, 0); BUG_ON(ret < 0); @@ -680,6 +706,15 @@ static void extent_io_tree_panic(struct extent_io_tree *tree, int err) "locking error: extent tree was modified by another thread while locked"); } +#ifdef MY_ABC_HERE +static bool changeset_ulist_node_need_realloc(struct extent_changeset *changeset, gfp_t mask) +{ + if (changeset && !changeset->prealloc_ulist_node && gfpflags_allow_blocking(mask)) + return true; + return false; +} +#endif /* MY_ABC_HERE */ + /* * clear some bits on a range in the tree. This may require splitting * or inserting elements in the tree, so the gfp mask is used to @@ -704,6 +739,20 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u64 last_end; int err; int clear = 0; +#ifdef MY_ABC_HERE + int retry_count = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_inode *inode = NULL; + u64 add_bytes = 0; + + if (bits & EXTENT_ADD_INODE_BYTES) { + if (tree->private_data && is_data_inode(tree->private_data)) + inode = BTRFS_I(tree->private_data); + if (inode && btrfs_is_free_space_inode(inode)) + inode = NULL; + } +#endif /* MY_ABC_HERE */ btrfs_debug_check_extent_io_range(tree, start, end); trace_btrfs_clear_extent_bit(tree, start, end - start + 1, bits); @@ -727,6 +776,14 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, */ prealloc = alloc_extent_state(mask); } +#ifdef MY_ABC_HERE + if (changeset_ulist_node_need_realloc(changeset, mask)) { + retry_count = 5; + while (!changeset->prealloc_ulist_node && retry_count-- > 0) { + changeset->prealloc_ulist_node = kmalloc(sizeof(*changeset->prealloc_ulist_node), mask & ~(__GFP_DMA32|__GFP_HIGHMEM)); + } + } +#endif /* MY_ABC_HERE */ spin_lock(&tree->lock); if (cached_state) { @@ -795,7 +852,11 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, goto out; if (state->end <= end) { state = clear_state_bit(tree, state, &bits, wake, - changeset); + changeset +#ifdef MY_ABC_HERE + , inode ? &add_bytes : NULL +#endif /* MY_ABC_HERE */ + ); goto next; } goto search_again; @@ -816,18 +877,30 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, if (wake) wake_up(&state->wq); - clear_state_bit(tree, prealloc, &bits, wake, changeset); + clear_state_bit(tree, prealloc, &bits, wake, changeset +#ifdef MY_ABC_HERE + , inode ? &add_bytes : NULL +#endif /* MY_ABC_HERE */ + ); prealloc = NULL; goto out; } - state = clear_state_bit(tree, state, &bits, wake, changeset); + state = clear_state_bit(tree, state, &bits, wake, changeset +#ifdef MY_ABC_HERE + , inode ? &add_bytes : NULL +#endif /* MY_ABC_HERE */ + ); next: if (last_end == (u64)-1) goto out; start = last_end + 1; - if (start <= end && state && !need_resched()) + if (start <= end && state && !need_resched() +#ifdef MY_ABC_HERE + && !changeset_ulist_node_need_realloc(changeset, mask) +#endif /* MY_ABC_HERE */ + ) goto hit_next; search_again: @@ -842,6 +915,34 @@ int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, spin_unlock(&tree->lock); if (prealloc) free_extent_state(prealloc); +#ifdef MY_ABC_HERE + if (changeset && changeset->prealloc_ulist_node) { + kfree(changeset->prealloc_ulist_node); + changeset->prealloc_ulist_node = NULL; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (add_bytes && inode) { + if (bits & EXTENT_ADD_INODE_BYTES) { + WARN_ON_ONCE(!gfpflags_allow_blocking(mask)); + spin_lock(&inode->lock); + ASSERT(inode->new_delalloc_bytes >= add_bytes); + inode->new_delalloc_bytes -= add_bytes; + inode_add_bytes(&inode->vfs_inode, add_bytes); + spin_unlock(&inode->lock); + + btrfs_qgroup_syno_accounting(inode, + add_bytes, 0, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(inode, + add_bytes, 0, UPDATE_QUOTA); + } else { + spin_lock(&inode->lock); + ASSERT(inode->new_delalloc_bytes >= add_bytes); + inode->new_delalloc_bytes -= add_bytes; + spin_unlock(&inode->lock); + } + } +#endif /* MY_ABC_HERE */ return 0; @@ -974,6 +1075,9 @@ __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int err = 0; u64 last_start; u64 last_end; +#ifdef MY_ABC_HERE + int retry_count = 0; +#endif /* MY_ABC_HERE */ btrfs_debug_check_extent_io_range(tree, start, end); trace_btrfs_set_extent_bit(tree, start, end - start + 1, bits); @@ -989,6 +1093,14 @@ __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, */ prealloc = alloc_extent_state(mask); } +#ifdef MY_ABC_HERE + if (changeset_ulist_node_need_realloc(changeset, mask)) { + retry_count = 5; + while (!changeset->prealloc_ulist_node && retry_count-- > 0) { + changeset->prealloc_ulist_node = kmalloc(sizeof(*changeset->prealloc_ulist_node), mask & ~(__GFP_DMA32|__GFP_HIGHMEM)); + } + } +#endif /* MY_ABC_HERE */ spin_lock(&tree->lock); if (cached_state && *cached_state) { @@ -1042,7 +1154,11 @@ __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, start = last_end + 1; state = next_state(state); if (start < end && state && state->start == start && - !need_resched()) + !need_resched() +#ifdef MY_ABC_HERE + && !changeset_ulist_node_need_realloc(changeset, mask) +#endif /* MY_ABC_HERE */ + ) goto hit_next; goto search_again; } @@ -1098,7 +1214,11 @@ __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, start = last_end + 1; state = next_state(state); if (start < end && state && state->start == start && - !need_resched()) + !need_resched() +#ifdef MY_ABC_HERE + && !changeset_ulist_node_need_realloc(changeset, mask) +#endif /* MY_ABC_HERE */ + ) goto hit_next; } goto search_again; @@ -1172,6 +1292,12 @@ __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, spin_unlock(&tree->lock); if (prealloc) free_extent_state(prealloc); +#ifdef MY_ABC_HERE + if (changeset && changeset->prealloc_ulist_node) { + kfree(changeset->prealloc_ulist_node); + changeset->prealloc_ulist_node = NULL; + } +#endif /* MY_ABC_HERE */ return err; @@ -1217,6 +1343,17 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u64 last_start; u64 last_end; bool first_iteration = true; +#ifdef MY_ABC_HERE + struct btrfs_inode *inode = NULL; + u64 add_bytes = 0; + + if (bits & EXTENT_ADD_INODE_BYTES) { + if (tree->private_data && is_data_inode(tree->private_data)) + inode = BTRFS_I(tree->private_data); + if (inode && btrfs_is_free_space_inode(inode)) + inode = NULL; + } +#endif /* MY_ABC_HERE */ btrfs_debug_check_extent_io_range(tree, start, end); trace_btrfs_convert_extent_bit(tree, start, end - start + 1, bits, @@ -1279,7 +1416,11 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, if (state->start == start && state->end <= end) { set_state_bits(tree, state, &bits, NULL); cache_state(state, cached_state); - state = clear_state_bit(tree, state, &clear_bits, 0, NULL); + state = clear_state_bit(tree, state, &clear_bits, 0, NULL +#ifdef MY_ABC_HERE + , inode ? &add_bytes : NULL +#endif /* MY_ABC_HERE */ + ); if (last_end == (u64)-1) goto out; start = last_end + 1; @@ -1321,7 +1462,11 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, set_state_bits(tree, state, &bits, NULL); cache_state(state, cached_state); state = clear_state_bit(tree, state, &clear_bits, 0, - NULL); + NULL +#ifdef MY_ABC_HERE + , inode ? &add_bytes : NULL +#endif /* MY_ABC_HERE */ + ); if (last_end == (u64)-1) goto out; start = last_end + 1; @@ -1383,7 +1528,11 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, set_state_bits(tree, prealloc, &bits, NULL); cache_state(prealloc, cached_state); - clear_state_bit(tree, prealloc, &clear_bits, 0, NULL); + clear_state_bit(tree, prealloc, &clear_bits, 0, NULL +#ifdef MY_ABC_HERE + , inode ? &add_bytes : NULL +#endif /* MY_ABC_HERE */ + ); prealloc = NULL; goto out; } @@ -1400,6 +1549,27 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, spin_unlock(&tree->lock); if (prealloc) free_extent_state(prealloc); +#ifdef MY_ABC_HERE + if (add_bytes && inode) { + if (bits & EXTENT_ADD_INODE_BYTES) { + spin_lock(&inode->lock); + ASSERT(inode->new_delalloc_bytes >= add_bytes); + inode->new_delalloc_bytes -= add_bytes; + inode_add_bytes(&inode->vfs_inode, add_bytes); + spin_unlock(&inode->lock); + + btrfs_qgroup_syno_accounting(inode, + add_bytes, 0, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(inode, + add_bytes, 0, UPDATE_QUOTA); + } else { + spin_lock(&inode->lock); + ASSERT(inode->new_delalloc_bytes >= add_bytes); + inode->new_delalloc_bytes -= add_bytes; + spin_unlock(&inode->lock); + } + } +#endif /* MY_ABC_HERE */ return err; } @@ -1782,6 +1952,11 @@ bool btrfs_find_delalloc_range(struct extent_io_tree *tree, u64 *start, (state->state & EXTENT_BOUNDARY))) { goto out; } + if (state->start > cur_start) { + if (!found) + *end = state->start - 1; + goto out; + } if (!(state->state & EXTENT_DELALLOC)) { if (!found) *end = state->end; @@ -1849,6 +2024,15 @@ static noinline int lock_delalloc_pages(struct inode *inode, return ret; } +#ifdef MY_ABC_HERE +u64 btrfs_max_extent_size(struct inode *inode) +{ + if (BTRFS_I(inode)->flags & BTRFS_INODE_NODEDUPE) + return BTRFS_MAX_EXTENT_SIZE; + return BTRFS_I(inode)->root->small_extent_size; +} +#endif /* MY_ABC_HERE */ + /* * Find and lock a contiguous range of bytes in the file marked as delalloc, no * more than @max_bytes. @Start and @end are used to return the range, @@ -1862,7 +2046,11 @@ noinline_for_stack bool find_lock_delalloc_range(struct inode *inode, u64 *end) { struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree; +#ifdef MY_ABC_HERE + u64 max_bytes = btrfs_max_extent_size(inode); +#else u64 max_bytes = BTRFS_MAX_EXTENT_SIZE; +#endif /* MY_ABC_HERE */ u64 delalloc_start; u64 delalloc_end; bool found; @@ -2204,18 +2392,6 @@ int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, return bitset; } -/* - * helper function to set a given page up to date if all the - * extents in the tree for that page are up to date - */ -static void check_page_uptodate(struct extent_io_tree *tree, struct page *page) -{ - u64 start = page_offset(page); - u64 end = start + PAGE_SIZE - 1; - if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL)) - SetPageUptodate(page); -} - int free_io_failure(struct extent_io_tree *failure_tree, struct extent_io_tree *io_tree, struct io_failure_record *rec) @@ -2252,7 +2428,11 @@ int free_io_failure(struct extent_io_tree *failure_tree, */ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, u64 length, u64 logical, struct page *page, - unsigned int pg_offset, int mirror_num) + unsigned int pg_offset, int mirror_num +#ifdef MY_ABC_HERE + , int abort_correction +#endif /* MY_ABC_HERE */ + ) { struct bio *bio; struct btrfs_device *dev; @@ -2261,11 +2441,20 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, struct btrfs_bio *bbio = NULL; int ret; +#ifdef MY_ABC_HERE + if (sb_rdonly(fs_info->sb)) + return 0; +#endif /* MY_ABC_HERE */ + ASSERT(!(fs_info->sb->s_flags & SB_RDONLY)); BUG_ON(!mirror_num); bio = btrfs_io_bio_alloc(1); bio->bi_iter.bi_size = 0; +#ifdef MY_ABC_HERE + if (abort_correction) + bio_set_flag(bio, BIO_CORRECTION_ABORT); +#endif /* MY_ABC_HERE */ map_length = length; /* @@ -2322,7 +2511,12 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, return -EIO; } +#ifdef MY_ABC_HERE + btrfs_data_correction_print_in_rcu(fs_info, + fs_info->correction_suppress_log, +#else /* MY_ABC_HERE */ btrfs_info_rl_in_rcu(fs_info, +#endif /* MY_ABC_HERE */ "read error corrected: ino %llu off %llu (dev %s sector %llu)", ino, start, rcu_str_deref(dev->name), sector); @@ -2331,13 +2525,51 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, return 0; } +#ifdef MY_ABC_HERE +int btrfs_repair_eb_io_failure(struct extent_buffer *eb, int mirror_num) +#else /* MY_ABC_HERE */ int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num) +#endif /* MY_ABC_HERE */ { struct btrfs_fs_info *fs_info = eb->fs_info; u64 start = eb->start; int i, num_pages = num_extent_pages(eb); int ret = 0; +#ifdef MY_ABC_HERE + // No readers now, one page's lock is enough. + lock_page(eb->pages[0]); + if (!test_and_clear_bit(EXTENT_BUFFER_SHOULD_REPAIR, &eb->bflags) && + !test_and_clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) { + unlock_page(eb->pages[0]); + return 0; + } + mirror_num = eb->read_mirror; + unlock_page(eb->pages[0]); + do { + start = eb->start; + for (i = 0; i < num_pages; i++) { + struct page *p = eb->pages[i]; + ClearPageChecked(p); + ret = repair_io_failure(fs_info, 0, start, PAGE_SIZE, start, p, + start - page_offset(p), mirror_num, + mirror_num == eb->read_mirror); + if (ret) + goto out; + start += PAGE_SIZE; + } + } while (--mirror_num); +out: + /* + * If we found a good copy in btrfs mirror 2, we could still get here + * but no need to put locked record. Go to check eb->nr_retry. + */ + if (eb->nr_retry) { + correction_put_locked_record(fs_info, eb->start); + eb->nr_retry = 0; + } + +#else /* MY_ABC_HERE */ if (sb_rdonly(fs_info->sb)) return -EROFS; @@ -2350,6 +2582,7 @@ int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num) break; start += PAGE_SIZE; } +#endif /* MY_ABC_HERE */ return ret; } @@ -2361,7 +2594,11 @@ int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num) int clean_io_failure(struct btrfs_fs_info *fs_info, struct extent_io_tree *failure_tree, struct extent_io_tree *io_tree, u64 start, - struct page *page, u64 ino, unsigned int pg_offset) + struct page *page, u64 ino, unsigned int pg_offset +#ifdef MY_ABC_HERE + , bool should_put_locked +#endif /* MY_ABC_HERE */ + ) { u64 private; struct io_failure_record *failrec; @@ -2379,7 +2616,10 @@ int clean_io_failure(struct btrfs_fs_info *fs_info, if (IS_ERR(failrec)) return 0; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ BUG_ON(!failrec->this_mirror); +#endif /* MY_ABC_HERE */ if (failrec->in_validation) { /* there was no real error, just free the record */ @@ -2388,8 +2628,11 @@ int clean_io_failure(struct btrfs_fs_info *fs_info, failrec->start); goto out; } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ if (sb_rdonly(fs_info->sb)) goto out; +#endif /* MY_ABC_HERE */ spin_lock(&io_tree->lock); state = find_first_extent_bit_state(io_tree, @@ -2401,11 +2644,20 @@ int clean_io_failure(struct btrfs_fs_info *fs_info, state->end >= failrec->start + failrec->len - 1) { num_copies = btrfs_num_copies(fs_info, failrec->logical, failrec->len); +#ifdef MY_ABC_HERE + repair_io_failure(fs_info, ino, start, failrec->len, + failrec->logical, page, pg_offset, + failrec->failed_mirror, 1); + if (should_put_locked) + correction_put_locked_record(fs_info, + failrec->logical); +#else /* MY_ABC_HERE */ if (num_copies > 1) { repair_io_failure(fs_info, ino, start, failrec->len, failrec->logical, page, pg_offset, failrec->failed_mirror); } +#endif /* MY_ABC_HERE */ } out: @@ -2449,7 +2701,11 @@ void btrfs_free_io_failure_record(struct btrfs_inode *inode, u64 start, u64 end) } static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode, - u64 start, u64 end) + u64 start, u64 end +#ifdef MY_ABC_HERE + , bool io_error +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct io_failure_record *failrec; @@ -2484,13 +2740,25 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode failrec->this_mirror = 0; failrec->bio_flags = 0; failrec->in_validation = 0; +#ifdef MY_ABC_HERE + failrec->io_error = io_error; +#endif /* MY_ABC_HERE */ read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, start, failrec->len); if (!em) { read_unlock(&em_tree->lock); +#ifdef MY_ABC_HERE + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, failrec->len); + if (IS_ERR_OR_NULL(em)) { + kfree(failrec); + return ERR_PTR(-EIO); + } + read_lock(&em_tree->lock); +#else /* MY_ABC_HERE */ kfree(failrec); return ERR_PTR(-EIO); +#endif /* MY_ABC_HERE */ } if (em->start > start || em->start + em->len <= start) { @@ -2506,9 +2774,15 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode logical = start - em->start; logical = em->block_start + logical; if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { +#ifdef MY_ABC_HERE + free_extent_map(em); + kfree(failrec); + return ERR_PTR(-EIO); +#else /* MY_ABC_HERE */ logical = em->block_start; failrec->bio_flags = EXTENT_BIO_COMPRESSED; extent_set_compress_type(&failrec->bio_flags, em->compress_type); +#endif /* MY_ABC_HERE */ } btrfs_debug(fs_info, @@ -2638,12 +2912,73 @@ static bool btrfs_io_needs_validation(struct inode *inode, struct bio *bio) } return false; } +#ifdef MY_ABC_HERE +/* + * Copy from the last part of btrfs_submit_read_repair() + */ +static blk_status_t +syno_bio_readpage_error(struct bio *failed_bio, struct inode *inode, + struct page *page, unsigned int pgoff, + u64 start, u64 phy_offset, + struct io_failure_record *failrec, bool abort_retry, + submit_bio_hook_t *submit_bio_hook) +{ + const struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); + struct bio *bio; + struct btrfs_io_bio *btrfs_failed_bio = btrfs_io_bio(failed_bio); + struct btrfs_io_bio *btrfs_bio; + blk_status_t ret; + + bio = btrfs_io_bio_alloc(1); + btrfs_bio = btrfs_io_bio(bio); + bio->bi_opf = REQ_OP_READ; + bio->bi_end_io = failed_bio->bi_end_io; + bio->bi_iter.bi_sector = failrec->logical >> 9; + bio->bi_iter.bi_size = 0; + bio->bi_private = failed_bio->bi_private; + + if (abort_retry) { + bio_set_flag(bio, BIO_CORRECTION_ABORT); + btrfs_bio->nr_retry = BTRFS_BIO_SHOULD_ABORT_RETRY; + } else { + bio_set_flag(bio, BIO_CORRECTION_RETRY); + btrfs_bio->nr_retry = btrfs_failed_bio->nr_retry + 1; + } + if (btrfs_failed_bio->csum) { + btrfs_bio->csum = btrfs_bio->csum_inline; + phy_offset >>= inode->i_sb->s_blocksize_bits; + phy_offset *= csum_size; + memcpy(btrfs_bio->csum, btrfs_failed_bio->csum + phy_offset, + csum_size); + } + memcpy(btrfs_bio->retry.prev_bad_csum, + btrfs_failed_bio->retry.prev_bad_csum, csum_size); + + bio_add_page(bio, page, failrec->len, pgoff); + btrfs_bio->logical = failrec->start; + btrfs_bio->iter = bio->bi_iter; + + ret = submit_bio_hook(inode, bio, + failrec->failed_mirror, + failrec->bio_flags); + if (ret) + bio_put(bio); + + return ret; +} +#endif /* MY_ABC_HERE */ blk_status_t btrfs_submit_read_repair(struct inode *inode, struct bio *failed_bio, u64 phy_offset, struct page *page, unsigned int pgoff, u64 start, u64 end, int failed_mirror, - submit_bio_hook_t *submit_bio_hook) + submit_bio_hook_t *submit_bio_hook +#ifdef MY_ABC_HERE + , bool do_correction + , bool *run_out_all_copy +#endif /* MY_ABC_HERE */ + ) { struct io_failure_record *failrec; struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); @@ -2655,20 +2990,67 @@ blk_status_t btrfs_submit_read_repair(struct inode *inode, struct bio *repair_bio; struct btrfs_io_bio *repair_io_bio; blk_status_t status; +#ifdef MY_ABC_HERE + struct btrfs_io_bio *btrfs_failed_bio; + int retry_fail = 0; +#endif /* MY_ABC_HERE */ btrfs_debug(fs_info, "repair read error: read error at %llu", start); BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE); - failrec = btrfs_get_io_failure_record(inode, start, end); + failrec = btrfs_get_io_failure_record(inode, start, end +#ifdef MY_ABC_HERE + , !!failed_bio->bi_status +#endif /* MY_ABC_HERE */ + ); if (IS_ERR(failrec)) return errno_to_blk_status(PTR_ERR(failrec)); +#ifdef MY_ABC_HERE + if (!do_correction) + goto try_mirror; + /* + * Stop retry when: + * 1. We have tried too much times. + * 2. We got two identical bad contents, and btrfs_readpage_end_io_hook() want us to stop. + * (By setting a very large nr_retry). + * 3. We got BIO_CORRECTION_ERR. + */ + btrfs_failed_bio = btrfs_io_bio(failed_bio); + if (btrfs_failed_bio->nr_retry != BTRFS_BIO_RETRY_ABORTED) { + bool abort_retry = false; + + if (bio_flagged(failed_bio, BIO_CORRECTION_ERR) || + btrfs_failed_bio->nr_retry > SYNO_DATA_CORRECTION_MAX_RETRY_TIMES) + abort_retry = true; + else if (!btrfs_failed_bio->nr_retry) // get record when first retry. + correction_get_locked_record(fs_info, failrec->logical); + failrec->failed_mirror = failed_mirror; + status = syno_bio_readpage_error(failed_bio, inode, + page, pgoff, + start, phy_offset, + failrec, abort_retry, + submit_bio_hook); + if (!status) + return status; + retry_fail = 1; + } + correction_put_locked_record(fs_info, failrec->logical); + failed_io_bio->nr_retry = 0; + +try_mirror: +#endif /* MY_ABC_HERE */ + need_validation = btrfs_io_needs_validation(inode, failed_bio); if (!btrfs_check_repairable(inode, need_validation, failrec, failed_mirror)) { +#ifdef MY_ABC_HERE + if (!retry_fail && !failrec->io_error && run_out_all_copy) + *run_out_all_copy = true; +#endif /* MY_ABC_HERE */ free_io_failure(failure_tree, tree, failrec); return BLK_STS_IOERR; } @@ -2780,11 +3162,135 @@ endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len, struct extent_state *cached = NULL; u64 end = start + len - 1; - if (uptodate && tree->track_uptodate) - set_extent_uptodate(tree, start, end, &cached, GFP_ATOMIC); unlock_extent_cached_atomic(tree, start, end, &cached); } +#ifdef MY_ABC_HERE +static unsigned int kfifo_latest_peek(struct kfifo *fifo, void *buf, unsigned int len) +{ + struct __kfifo *real_fifo = &fifo->kfifo; + unsigned int l; + unsigned int off; + + l = real_fifo->in - real_fifo->out; + if (len > l) { + len = l; + } + + off = (real_fifo->in + ((unsigned int)-1 - len)) & real_fifo->mask; + l = min(len, real_fifo->mask + 1 - off); + + memcpy(buf, real_fifo->data + off, l); + memcpy(buf + l, real_fifo->data, len - l); + smp_wmb(); + + return len; +} + +void add_cksumfailed_file(u64 rootid, u64 i_ino, struct btrfs_fs_info *fs_info) +{ + struct cksumfailed_file_rec rec; + unsigned int len; + + spin_lock(&fs_info->cksumfailed_files_write_lock); + + len = kfifo_latest_peek(&fs_info->cksumfailed_files, &rec, sizeof(rec)); + if (len == sizeof(rec)) { + if (rec.sub_vol == rootid && rec.ino == i_ino) + goto out; + } else + WARN_ON(0 != len); + + rec.sub_vol = rootid; + rec.ino = i_ino; + kfifo_in(&fs_info->cksumfailed_files, &rec, sizeof(rec)); + +out: + spin_unlock(&fs_info->cksumfailed_files_write_lock); +} + +void correction_get_locked_record(struct btrfs_fs_info *fs_info, u64 logical) +{ + struct rb_node **n; + struct rb_node *parent; + struct correction_record *record, *tmp; + + record = kmalloc(sizeof(struct correction_record), GFP_NOFS); + if (!record) + return; + +retry: + spin_lock(&fs_info->correction_record_lock); + n = &fs_info->correction_record.rb_node; + parent = NULL; + + while (*n) { + parent = *n; + tmp = rb_entry(parent, struct correction_record, node); + + if (logical < tmp->logical) + n = &(*n)->rb_left; + else if (logical > tmp->logical) + n = &(*n)->rb_right; + else { + spin_unlock(&fs_info->correction_record_lock); + schedule(); + goto retry; + } + } + + RB_CLEAR_NODE(&record->node); + record->logical = logical; + rb_link_node(&record->node, parent, n); + rb_insert_color(&record->node, &fs_info->correction_record); + spin_unlock(&fs_info->correction_record_lock); +} + +void correction_put_locked_record(struct btrfs_fs_info *fs_info, u64 logical) +{ + struct rb_node *n; + struct correction_record *record; + + spin_lock(&fs_info->correction_record_lock); + n = fs_info->correction_record.rb_node; + + while (n) { + record = rb_entry(n, struct correction_record, node); + + if (logical < record->logical) + n = n->rb_left; + else if (logical > record->logical) + n = n->rb_right; + else { + rb_erase(n, &fs_info->correction_record); + kfree(record); + + spin_unlock(&fs_info->correction_record_lock); + return; + } + } + spin_unlock(&fs_info->correction_record_lock); + printk(KERN_INFO "double put correction record, logical = %llu\n", logical); +} + +void correction_destroy_locked_record(struct btrfs_fs_info *fs_info) +{ + struct rb_node *n; + struct correction_record *record; + + spin_lock(&fs_info->correction_record_lock); + while (!RB_EMPTY_ROOT(&fs_info->correction_record)) { + WARN_ON_ONCE(1); + n = rb_first(&fs_info->correction_record); + record = rb_entry(n, struct correction_record, node); + + rb_erase(n, &fs_info->correction_record); + kfree(record); + } + spin_unlock(&fs_info->correction_record_lock); +} +#endif /* MY_ABC_HERE */ + /* * after a readpage IO is done, we need to: * clear the uptodate bits on error @@ -2799,7 +3305,12 @@ endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len, static void end_bio_extent_readpage(struct bio *bio) { struct bio_vec *bvec; +#ifdef MY_ABC_HERE + int bio_uptodate = !bio->bi_status; + int uptodate; +#else /* MY_ABC_HERE */ int uptodate = !bio->bi_status; +#endif /* MY_ABC_HERE */ struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); struct extent_io_tree *tree, *failure_tree; u64 offset = 0; @@ -2811,12 +3322,35 @@ static void end_bio_extent_readpage(struct bio *bio) int mirror; int ret; struct bvec_iter_all iter_all; +#ifdef MY_ABC_HERE + int found_cksumfailure = 0; + struct btrfs_fs_info *info = NULL; + bool do_correction = true; + + if (!bio_uptodate && !io_bio->nr_retry) + do_correction = !(bio->bi_opf & REQ_RAHEAD); + + /* + * We already gave up retry, don't bother csum work. + * Someone would say we can put this check in readpage_end_io_hook(), + * but we enter readpage_end_io_hook() only when bio is uptodate. + */ + if (unlikely(io_bio->nr_retry == BTRFS_BIO_SHOULD_ABORT_RETRY)) { + io_bio->nr_retry = BTRFS_BIO_RETRY_ABORTED; + bio_uptodate = 0; + } +#endif /* MY_ABC_HERE */ ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, iter_all) { struct page *page = bvec->bv_page; struct inode *inode = page->mapping->host; struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); +#ifdef MY_ABC_HERE + blk_status_t status; + uptodate = bio_uptodate; + info = fs_info; +#endif /* MY_ABC_HERE */ btrfs_debug(fs_info, "end_bio_extent_readpage: bi_sector=%llu, err=%d, mirror=%u", @@ -2859,14 +3393,20 @@ static void end_bio_extent_readpage(struct bio *bio) clean_io_failure(BTRFS_I(inode)->root->fs_info, failure_tree, tree, start, page, - btrfs_ino(BTRFS_I(inode)), 0); + btrfs_ino(BTRFS_I(inode)), 0 +#ifdef MY_ABC_HERE + , !!io_bio->nr_retry +#endif /* MY_ABC_HERE */ + ); } if (likely(uptodate)) goto readpage_ok; if (is_data_inode(inode)) { - +#ifdef MY_ABC_HERE + bool run_out_all_copy = false; +#endif /* MY_ABC_HERE */ /* * The generic bio_readpage_error handles errors the * following way: If possible, new read requests are @@ -2877,21 +3417,50 @@ static void end_bio_extent_readpage(struct bio *bio) * If it can't handle the error it will return -EIO and * we remain responsible for that page. */ +#ifdef MY_ABC_HERE + status = btrfs_submit_read_repair(inode, bio, offset, page, + start - page_offset(page), + start, end, mirror, + btrfs_submit_data_bio + , do_correction, &run_out_all_copy); + if (!status) { +#else /* MY_ABC_HERE */ if (!btrfs_submit_read_repair(inode, bio, offset, page, start - page_offset(page), start, end, mirror, btrfs_submit_data_bio)) { +#endif /* MY_ABC_HERE */ uptodate = !bio->bi_status; offset += len; continue; } +#ifdef MY_ABC_HERE + if (run_out_all_copy) { // Run out of all redundancies. Report to user space. + add_cksumfailed_file(BTRFS_I(inode)->root->root_key.objectid, + (u64)inode->i_ino, fs_info); + found_cksumfailure = 1; + uptodate = 1; + + btrfs_err(fs_info, "failed to repair data csum of ino %lu off %llu " + "(ran out of all copies)", inode->i_ino, start); + goto readpage_ok; + } else if (do_correction) { // -ENOMEM, -EIO, etc... , we stop. + btrfs_err(fs_info, "failed to repair data csum of ino %lu off %llu " + "(err = %u)", inode->i_ino, start, status); + } +#endif /* MY_ABC_HERE */ } else { struct extent_buffer *eb; eb = (struct extent_buffer *)page->private; set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags); +#ifdef MY_ABC_HERE + btrfs_metadata_io_failed(eb, page, mirror, + bio_flagged(bio, BIO_CORRECTION_ERR)); +#else /* MY_ABC_HERE */ eb->read_mirror = mirror; atomic_dec(&eb->io_pages); +#endif /* MY_ABC_HERE */ if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) btree_readahead_hook(eb, -EIO); @@ -2942,6 +3511,12 @@ static void end_bio_extent_readpage(struct bio *bio) uptodate); btrfs_io_bio_free_csum(io_bio); bio_put(bio); + +#ifdef MY_ABC_HERE + if (found_cksumfailure && info) { + SynoAutoErrorFsBtrfsReport(info->fs_devices->fsid); + } +#endif /* MY_ABC_HERE */ } /* @@ -3055,6 +3630,15 @@ static int submit_extent_page(unsigned int opf, if (btrfs_bio_fits_in_stripe(page, page_size, bio, bio_flags)) can_merge = false; +#ifdef MY_ABC_HERE + /* + * For latency, limit write bio maximum with 64k, avoid too much page + * is marked as writeback. + */ + if (bio_op(bio) == REQ_OP_WRITE && bio->bi_iter.bi_size >= SZ_64K) + force_bio_submit = true; +#endif /* MY_ABC_HERE */ + if (prev_bio_flags != bio_flags || !contig || !can_merge || force_bio_submit || bio_add_page(bio, page, page_size, pg_offset) < page_size) { @@ -3077,6 +3661,7 @@ static int submit_extent_page(unsigned int opf, bio->bi_private = tree; bio->bi_write_hint = page->mapping->host->i_write_hint; bio->bi_opf = opf; + if (wbc) { struct block_device *bdev; @@ -3297,19 +3882,8 @@ int btrfs_do_readpage(struct page *page, struct extent_map **em_cached, continue; } /* the get_extent function already copied into the page */ - if (test_range_bit(tree, cur, cur_end, - EXTENT_UPTODATE, 1, NULL)) { - check_page_uptodate(tree, page); - unlock_extent(tree, cur, cur + iosize - 1); - cur = cur + iosize; - pg_offset += iosize; - continue; - } - /* we have an inline extent but it didn't get marked up - * to date. Error out - */ if (block_start == EXTENT_MAP_INLINE) { - SetPageError(page); + SetPageUptodate(page); unlock_extent(tree, cur, cur + iosize - 1); cur = cur + iosize; pg_offset += iosize; @@ -3437,6 +4011,10 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode, * nr_to_write. */ wbc->nr_to_write -= *nr_written; +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&inode->root->fs_info->data_write_pages, + *nr_written, SZ_128M); +#endif /* MY_ABC_HERE */ return 1; } @@ -3474,6 +4052,9 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, int nr = 0; const unsigned int write_flags = wbc_to_write_flags(wbc); bool compressed; +#ifdef MY_ABC_HERE + bool deduped = false; +#endif /* MY_ABC_HERE */ ret = btrfs_writepage_cow_fixup(page, start, page_end); if (ret) { @@ -3481,6 +4062,9 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, redirty_page_for_writepage(wbc, page); update_nr_written(wbc, nr_written); unlock_page(page); +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&inode->root->fs_info->data_write_pages, nr_written, SZ_128M); +#endif /* MY_ABC_HERE */ return 1; } @@ -3489,6 +4073,9 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, * so we update the mapping writeback index now */ update_nr_written(wbc, nr_written + 1); +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&inode->root->fs_info->data_write_pages, nr_written + 1, SZ_128M); +#endif /* MY_ABC_HERE */ end = page_end; blocksize = inode->vfs_inode.i_sb->s_blocksize; @@ -3518,6 +4105,9 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, offset = em->block_start + extent_offset; block_start = em->block_start; compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags); +#ifdef MY_ABC_HERE + deduped = test_bit(EXTENT_FLAG_DEDUPED, &em->flags); +#endif /* MY_ABC_HERE */ free_extent_map(em); em = NULL; @@ -3526,6 +4116,9 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, * paths in the FS */ if (compressed || block_start == EXTENT_MAP_HOLE || +#ifdef MY_ABC_HERE + deduped || +#endif /* MY_ABC_HERE */ block_start == EXTENT_MAP_INLINE) { if (compressed) nr++; @@ -3869,6 +4462,9 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, u64 offset = eb->start; u32 nritems; int i, num_pages; +#ifdef MY_ABC_HERE + unsigned long bio_flags = 0; +#endif /* MY_ABC_HERE */ unsigned long start, end; unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META; int ret = 0; @@ -3877,6 +4473,11 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, num_pages = num_extent_pages(eb); atomic_set(&eb->io_pages, num_pages); +#ifdef MY_ABC_HERE + if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID) + bio_flags = EXTENT_BIO_TREE_LOG; +#endif /* MY_ABC_HERE */ + /* set btree blocks beyond nritems with 0 to avoid stale content. */ nritems = btrfs_header_nritems(eb); if (btrfs_header_level(eb) > 0) { @@ -3902,7 +4503,15 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, p, offset, PAGE_SIZE, 0, &epd->bio, end_bio_extent_buffer_writepage, +#ifdef MY_ABC_HERE + 0, epd->bio_flags, bio_flags, false); +#else /* MY_ABC_HERE */ 0, 0, 0, false); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + epd->bio_flags = bio_flags; +#endif /* MY_ABC_HERE */ if (ret) { set_btree_ioerr(p); if (PageWriteback(p)) @@ -3916,6 +4525,9 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, update_nr_written(wbc, 1); unlock_page(p); } +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&eb->fs_info->meta_write_pages, num_pages, SZ_128M); +#endif /* MY_ABC_HERE */ if (unlikely(ret)) { for (; i < num_pages; i++) { @@ -3936,6 +4548,9 @@ int btree_write_cache_pages(struct address_space *mapping, .bio = NULL, .extent_locked = 0, .sync_io = wbc->sync_mode == WB_SYNC_ALL, +#ifdef MY_ABC_HERE + .bio_flags = 0, +#endif /* MY_ABC_HERE */ }; struct btrfs_fs_info *fs_info = BTRFS_I(mapping->host)->root->fs_info; int ret = 0; @@ -4257,6 +4872,9 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc) .bio = NULL, .extent_locked = 0, .sync_io = wbc->sync_mode == WB_SYNC_ALL, +#ifdef MY_ABC_HERE + .bio_flags = 0, +#endif /* MY_ABC_HERE */ }; ret = __extent_writepage(page, wbc, &epd); @@ -4284,6 +4902,9 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end, .bio = NULL, .extent_locked = 1, .sync_io = mode == WB_SYNC_ALL, +#ifdef MY_ABC_HERE + .bio_flags = 0, +#endif /* MY_ABC_HERE */ }; struct writeback_control wbc_writepages = { .sync_mode = mode, @@ -4327,6 +4948,9 @@ int extent_writepages(struct address_space *mapping, .bio = NULL, .extent_locked = 0, .sync_io = wbc->sync_mode == WB_SYNC_ALL, +#ifdef MY_ABC_HERE + .bio_flags = 0, +#endif /* MY_ABC_HERE */ }; ret = extent_write_cache_pages(mapping, wbc, &epd); @@ -4407,12 +5031,25 @@ static int try_release_extent_state(struct extent_io_tree *tree, ret = 0; } else { /* - * at this point we can safely clear everything except the - * locked bit and the nodatasum bit + * At this point we can safely clear everything except the + * locked bit, the nodatasum bit and the delalloc new bit. + * The delalloc new bit will be cleared by ordered extent + * completion. + */ +#ifdef MY_ABC_HERE + /* + * The qgroup reserved bit should be kept for ordered extent, + * or quota reservation would be leaked. */ ret = __clear_extent_bit(tree, start, end, - ~(EXTENT_LOCKED | EXTENT_NODATASUM), - 0, 0, NULL, mask, NULL); + ~(EXTENT_LOCKED | EXTENT_NODATASUM | EXTENT_DELALLOC_NEW | + EXTENT_QGROUP_RESERVED), + 0, 0, NULL, mask, NULL); +#else + ret = __clear_extent_bit(tree, start, end, + ~(EXTENT_LOCKED | EXTENT_NODATASUM | EXTENT_DELALLOC_NEW), + 0, 0, NULL, mask, NULL); +#endif /* MY_ABC_HERE */ /* if clear_extent_bit failed for enomem reasons, * we can't allow the release to continue. @@ -4528,6 +5165,9 @@ static struct extent_map *get_extent_skip_holes(struct btrfs_inode *inode, len = last - offset; if (len == 0) break; +#ifdef MY_ABC_HERE + len = min_t(u64, len, SZ_256M); +#endif /* MY_ABC_HERE */ len = ALIGN(len, sectorsize); em = btrfs_get_extent_fiemap(inode, offset, len); if (IS_ERR_OR_NULL(em)) @@ -4538,10 +5178,25 @@ static struct extent_map *get_extent_skip_holes(struct btrfs_inode *inode, return em; /* this is a hole, advance to the next extent */ +#ifdef MY_ABC_HERE + /* we only check that delalloc is SZ_256M after offset, + * so when the hole exceeds 256M, we have to limit it + * to only increase 256M at most once. + */ + if (offset + SZ_256M > offset) + offset += SZ_256M; + else + offset = U64_MAX; + offset = min(offset, extent_map_end(em)); +#else /* MY_ABC_HERE */ offset = extent_map_end(em); +#endif /* MY_ABC_HERE */ free_extent_map(em); if (offset >= last) break; +#ifdef MY_ABC_HERE + cond_resched(); +#endif /* MY_ABC_HERE */ } return NULL; } @@ -4603,8 +5258,13 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, */ if (cache->offset + cache->len == offset && cache->phys + cache->len == phys && +#ifdef MY_ABC_HERE + (cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) == + (flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { +#else /* MY_ABC_HERE */ (cache->flags & ~FIEMAP_EXTENT_LAST) == (flags & ~FIEMAP_EXTENT_LAST)) { +#endif /* MY_ABC_HERE */ cache->len += len; cache->flags |= flags; goto try_submit_last; @@ -4658,6 +5318,122 @@ static int emit_last_fiemap_cache(struct fiemap_extent_info *fieinfo, return ret; } +#ifdef MY_ABC_HERE +/** + * Return: 0 if extent is not shared, 1 if it is shared, < 0 on error. + */ +static int extent_map_check_shared(struct btrfs_inode *inode, + u64 start, u64 end, + struct ulist *roots, struct ulist *tmp) +{ + struct btrfs_root *root = inode->root; + int ret = 0; + struct extent_buffer *leaf; + struct btrfs_path *path; + struct btrfs_file_extent_item *fi; + struct btrfs_key found_key; + bool check_prev = true; + int extent_type; + u64 cur_offset; + u64 extent_end; + u64 ino = btrfs_ino(inode); + u64 disk_bytenr; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + cur_offset = start; + while (1) { + ret = btrfs_lookup_file_extent(NULL, root, path, ino, + cur_offset, 0); + if (ret < 0) + goto out; + if (ret > 0 && path->slots[0] > 0 && check_prev) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, + path->slots[0] - 1); + if (found_key.objectid == ino && + found_key.type == BTRFS_EXTENT_DATA_KEY) + path->slots[0]--; + } + check_prev = false; +next_slot: + leaf = path->nodes[0]; + if (path->slots[0] >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + if (ret > 0) + break; + leaf = path->nodes[0]; + } + + disk_bytenr = 0; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid > ino) + break; + if (WARN_ON_ONCE(found_key.objectid < ino) || + found_key.type < BTRFS_EXTENT_DATA_KEY) { + path->slots[0]++; + goto next_slot; + } + if (found_key.type > BTRFS_EXTENT_DATA_KEY || + found_key.offset > end) + break; + + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(leaf, fi); + + if (extent_type == BTRFS_FILE_EXTENT_REG || + extent_type == BTRFS_FILE_EXTENT_PREALLOC) { + disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); + extent_end = found_key.offset + + btrfs_file_extent_num_bytes(leaf, fi); + if (extent_end <= start) { + path->slots[0]++; + goto next_slot; + } + if (disk_bytenr == 0) { + path->slots[0]++; + goto next_slot; + } + btrfs_release_path(path); + + /* + * As btrfs supports shared space, this information + * can be exported to userspace tools via + * flag FIEMAP_EXTENT_SHARED. If fi_extents_max == 0 + * then we're just getting a count and we can skip the + * lookup stuff. + */ + ret = btrfs_check_shared(root, btrfs_ino(inode), + disk_bytenr, roots, tmp); + if (ret) + goto out; + } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { + extent_end = found_key.offset + + btrfs_file_extent_ram_bytes(leaf, fi); + extent_end = ALIGN(extent_end, root->fs_info->sectorsize); + path->slots[0]++; + goto next_slot; + } else { + BUG_ON(1); + } + cur_offset = extent_end; + if (cur_offset > end) + break; + } + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} +#endif /* MY_ABC_HERE */ + int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len) { @@ -4682,6 +5458,9 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, u64 em_start = 0; u64 em_len = 0; u64 em_end = 0; +#ifdef MY_ABC_HERE + u64 last_for_user_wanted = 0; +#endif /* MY_ABC_HERE */ if (len == 0) return -EINVAL; @@ -4751,10 +5530,20 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, last_for_get_extent = isize; } +#ifdef MY_ABC_HERE + last_for_user_wanted = min(start + len, last_for_get_extent); +#endif /* MY_ABC_HERE */ + lock_extent_bits(&inode->io_tree, start, start + len - 1, &cached_state); - em = get_extent_skip_holes(inode, start, last_for_get_extent); + em = get_extent_skip_holes(inode, start +#ifdef MY_ABC_HERE + , last_for_user_wanted +#else /* MY_ABC_HERE */ + , last_for_get_extent +#endif /* MY_ABC_HERE */ + ); if (!em) goto out; if (IS_ERR(em)) { @@ -4810,6 +5599,11 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, flags |= (FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN); } else if (fieinfo->fi_extents_max) { +#ifdef MY_ABC_HERE + ret = extent_map_check_shared(inode, em->start, + extent_map_end(em) - 1, + roots, tmp_ulist); +#else /* MY_ABC_HERE */ u64 bytenr = em->block_start - (em->start - em->orig_start); @@ -4822,6 +5616,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, */ ret = btrfs_check_shared(root, btrfs_ino(inode), bytenr, roots, tmp_ulist); +#endif /* MY_ABC_HERE */ if (ret < 0) goto out_free; if (ret) @@ -4842,13 +5637,24 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, } /* now scan forward to see if this is really the last extent. */ - em = get_extent_skip_holes(inode, off, last_for_get_extent); + em = get_extent_skip_holes(inode, off +#ifdef MY_ABC_HERE + , last_for_user_wanted +#else /* MY_ABC_HERE */ + , last_for_get_extent +#endif /* MY_ABC_HERE */ + ); if (IS_ERR(em)) { ret = PTR_ERR(em); goto out; } if (!em) { +#ifdef MY_ABC_HERE + if (last_for_user_wanted >= last_for_get_extent) + flags |= FIEMAP_EXTENT_LAST; +#else /* MY_ABC_HERE */ flags |= FIEMAP_EXTENT_LAST; +#endif /* MY_ABC_HERE */ end = 1; } ret = emit_fiemap_extent(fieinfo, &cache, em_start, disko, @@ -4981,6 +5787,13 @@ __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start, eb->write_locks = 0; #endif +#ifdef MY_ABC_HERE + eb->nr_retry = 0; + eb->read_mirror = 1; + memset(eb->prev_bad_csum, 0, sizeof(eb->prev_bad_csum)); + eb->parent_transid = 0; + eb->prev_bad_transid = 0; +#endif /* MY_ABC_HERE */ return eb; } @@ -5131,9 +5944,15 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, spin_unlock(&eb->refs_lock); } mark_extent_buffer_accessed(eb, NULL); +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&fs_info->eb_hit, 1, SZ_128M); +#endif /* MY_ABC_HERE */ return eb; } rcu_read_unlock(); +#ifdef MY_ABC_HERE + percpu_counter_add_batch(&fs_info->eb_miss, 1, SZ_128M); +#endif /* MY_ABC_HERE */ return NULL; } @@ -5287,8 +6106,12 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, * btree_releasepage will correctly detect that a page belongs to a * live buffer and won't free them prematurely. */ - for (i = 0; i < num_pages; i++) + for (i = 0; i < num_pages; i++) { +#ifdef MY_ABC_HERE + ClearPageChecked(eb->pages[i]); +#endif /* MY_ABC_HERE */ unlock_page(eb->pages[i]); + } return eb; free_eb: @@ -5475,8 +6298,19 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb) SetPageUptodate(page); } } +#ifdef MY_ABC_HERE +enum syno_extent_bio_data_correction_type { + SYNO_EXTENT_BIO_DEFAULT, + SYNO_EXTENT_BIO_ABORT, + SYNO_EXTENT_BIO_RETRY, +}; +#endif /* MY_ABC_HERE */ -int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) +int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num +#ifdef MY_ABC_HERE + , bool *can_retry, u64 parent_transid +#endif /* MY_ABC_HERE */ + ) { int i; struct page *page; @@ -5488,6 +6322,10 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) unsigned long num_reads = 0; struct bio *bio = NULL; unsigned long bio_flags = 0; +#ifdef MY_ABC_HERE + bool do_correction = false; + enum syno_extent_bio_data_correction_type bio_type = SYNO_EXTENT_BIO_DEFAULT; +#endif /* MY_ABC_HERE */ if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags)) return 0; @@ -5503,6 +6341,27 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) } locked_pages++; } + +#ifdef MY_ABC_HERE + eb->can_retry = *can_retry; + if (parent_transid) + eb->parent_transid = parent_transid; + + // Switch to next mirror, reset nr_retry. + if (unlikely(eb->read_mirror < mirror_num && *can_retry)) + eb->nr_retry = 0; + /* + * Force using normal read (set can_retry to false): + * Case1. We have tried out all redundancies in this mirror and not moving to next mirror. + * Case2. Other people are doing retry on mirror 2 and we are reading mirror 0/1, + * we should not triger any retry this time. + */ + else if (unlikely((eb->nr_retry == EXTENT_BUFFER_RETRY_ABORTED) || + (eb->read_mirror > 1 && mirror_num < eb->read_mirror))) { + eb->can_retry = false; + *can_retry = false; + } +#endif /* MY_ABC_HERE */ /* * We need to firstly lock all pages to make sure that * the uptodate bit of our pages won't be affected by @@ -5510,29 +6369,56 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) */ for (i = 0; i < num_pages; i++) { page = eb->pages[i]; - if (!PageUptodate(page)) { + if (!PageUptodate(page) +#ifdef MY_ABC_HERE + && (!PageChecked(page) || !eb->can_retry) +#endif /* MY_ABC_HERE */ + ) { num_reads++; all_uptodate = 0; } } - if (all_uptodate) { set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); goto unlock_exit; } +#ifdef MY_ABC_HERE + else if (unlikely(eb->nr_retry == 1 && eb->can_retry)) + correction_get_locked_record(eb->fs_info, eb->start); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + atomic64_inc(&eb->fs_info->syno_meta_statistics.eb_disk_read); +#endif /* MY_ABC_HERE */ clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ eb->read_mirror = 0; +#endif /* MY_ABC_HERE */ atomic_set(&eb->io_pages, num_reads); /* * It is possible for releasepage to clear the TREE_REF bit before we * set io_pages. See check_buffer_tree_ref for a more detailed comment. */ check_buffer_tree_ref(eb); +#ifdef MY_ABC_HERE + clear_bit(EXTENT_BUFFER_RETRY_ERR, &eb->bflags); + if (unlikely(eb->nr_retry && eb->can_retry)) { + do_correction = true; + if (eb->nr_retry == EXTENT_BUFFER_SHOULD_ABORT_RETRY) + bio_type = SYNO_EXTENT_BIO_ABORT; + else + bio_type = SYNO_EXTENT_BIO_RETRY; + } +#endif /* MY_ABC_HERE */ for (i = 0; i < num_pages; i++) { page = eb->pages[i]; - if (!PageUptodate(page)) { + if (!PageUptodate(page) +#ifdef MY_ABC_HERE + && (!do_correction || !PageChecked(page)) +#endif /* MY_ABC_HERE */ + ) { if (ret) { atomic_dec(&eb->io_pages); unlock_page(page); @@ -5544,6 +6430,17 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) page, page_offset(page), PAGE_SIZE, 0, &bio, end_bio_extent_readpage, mirror_num, 0, 0, false); +#ifdef MY_ABC_HERE + if (!err && do_correction) { + if (unlikely(bio_type == SYNO_EXTENT_BIO_RETRY)) + bio_set_flag(bio, BIO_CORRECTION_RETRY); + else if (unlikely(bio_type == SYNO_EXTENT_BIO_ABORT)) + bio_set_flag(bio, BIO_CORRECTION_ABORT); + + err = submit_one_bio(bio, mirror_num, bio_flags); + bio = NULL; + } +#endif /* MY_ABC_HERE */ if (err) { /* * We failed to submit the bio so it's the @@ -5559,6 +6456,10 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) unlock_page(page); } } +#ifdef MY_ABC_HERE + if (do_correction && ret) + correction_put_locked_record(eb->fs_info, eb->start); +#endif /* MY_ABC_HERE */ if (bio) { err = submit_one_bio(bio, mirror_num, bio_flags); @@ -5576,6 +6477,17 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num) ret = -EIO; } +#ifdef MY_ABC_HERE + /* + * We need this since someone may find the good one and set extent_buffer uptodate + * before we resume running from wait_on_page_locked() and thus no one do the repair. + * Adding this flag may result in multiple process get -EIO, but eventaully they + * will leave the loop if someone find a good copy and mark extent buffer uptodate. + */ + if (unlikely(test_bit(EXTENT_BUFFER_SHOULD_REPAIR, &eb->bflags) && *can_retry)) + ret = -EIO; +#endif /* MY_ABC_HERE */ + return ret; unlock_exit: @@ -5682,6 +6594,54 @@ int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb, return ret; } +#ifdef MY_ABC_HERE +/* We don't want to check in while loop, so copy from memcmp_extent_buffer(). */ +int memcmp_caseless_extent_buffer(const struct extent_buffer *eb, + const void *ptrv, + unsigned long len_ptrv, + unsigned long start, + unsigned long len) +{ + size_t cur; + size_t offset; + unsigned long len_copy = len; + struct page *page; + char *kaddr; + char *buf = NULL; + char caseless_cmp_buf[BTRFS_NAME_LEN]; + unsigned long i = start >> PAGE_SHIFT; + unsigned long end = (start + len) >> PAGE_SHIFT; + bool cross_page = false; + + if (check_eb_range(eb, start, len)) + return -EINVAL; + + offset = offset_in_page(start); + + if (i != end) { + buf = caseless_cmp_buf; + cross_page = true; + } + while (len > 0) { + page = eb->pages[i]; + + cur = min(len, (PAGE_SIZE - offset)); + + kaddr = page_address(page); + if (cross_page) + memcpy(buf + len_copy - len, kaddr + offset, cur); + else + buf = kaddr + offset; + + len -= cur; + offset = 0; + i++; + } + + return syno_utf8_strcmp((const char *)ptrv, buf, len_ptrv, len_copy, 0); +} +#endif /* MY_ABC_HERE */ + int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, unsigned long start, unsigned long len) { diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index f39d02e7f7ef..8599738e1c61 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_EXTENT_IO_H @@ -6,6 +9,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "ulist.h" /* @@ -13,6 +19,9 @@ * type for this bio */ #define EXTENT_BIO_COMPRESSED 1 +#ifdef MY_ABC_HERE +#define EXTENT_BIO_TREE_LOG 2 +#endif /* MY_ABC_HERE */ #define EXTENT_BIO_FLAG_SHIFT 16 enum { @@ -30,6 +39,12 @@ enum { EXTENT_BUFFER_IN_TREE, /* write IO error */ EXTENT_BUFFER_WRITE_ERR, +#ifdef MY_ABC_HERE + /* one and only one process can do the repair in repair_eb_io_failure() */ + EXTENT_BUFFER_SHOULD_REPAIR, + /* no more redundancies in lower layer */ + EXTENT_BUFFER_RETRY_ERR, +#endif /* MY_ABC_HERE */ }; /* these are flags for __process_pages_contig */ @@ -74,6 +89,11 @@ typedef blk_status_t (submit_bio_hook_t)(struct inode *inode, struct bio *bio, typedef blk_status_t (extent_submit_bio_start_t)(void *private_data, struct bio *bio, u64 bio_offset); +#ifdef MY_ABC_HERE +#define EXTENT_BUFFER_SHOULD_ABORT_RETRY ((u8)-2) +#define EXTENT_BUFFER_RETRY_ABORTED ((u8)-1) +#endif /* MY_ABC_HERE */ + #define INLINE_EXTENT_BUFFER_PAGES 16 #define MAX_INLINE_EXTENT_BUFFER_SIZE (INLINE_EXTENT_BUFFER_PAGES * PAGE_SIZE) struct extent_buffer { @@ -114,6 +134,13 @@ struct extent_buffer { int write_locks; struct list_head leak_list; #endif +#ifdef MY_ABC_HERE + bool can_retry; + u8 nr_retry; + u8 prev_bad_csum[BTRFS_CSUM_SIZE]; + u64 parent_transid; + u64 prev_bad_transid; +#endif /* MY_ABC_HERE */ }; /* @@ -121,16 +148,27 @@ struct extent_buffer { */ struct extent_changeset { /* How many bytes are set/cleared in this operation */ +#ifdef MY_ABC_HERE + u64 bytes_changed; +#else unsigned int bytes_changed; +#endif /* MY_ABC_HERE */ /* Changed ranges */ struct ulist range_changed; + +#ifdef MY_ABC_HERE + struct ulist_node *prealloc_ulist_node; +#endif /* MY_ABC_HERE */ }; static inline void extent_changeset_init(struct extent_changeset *changeset) { changeset->bytes_changed = 0; ulist_init(&changeset->range_changed); +#ifdef MY_ABC_HERE + changeset->prealloc_ulist_node = NULL; +#endif /* MY_ABC_HERE */ } static inline struct extent_changeset *extent_changeset_alloc(void) @@ -151,6 +189,10 @@ static inline void extent_changeset_release(struct extent_changeset *changeset) return; changeset->bytes_changed = 0; ulist_release(&changeset->range_changed); +#ifdef MY_ABC_HERE + kfree(changeset->prealloc_ulist_node); + changeset->prealloc_ulist_node = NULL; +#endif /* MY_ABC_HERE */ } static inline void extent_changeset_free(struct extent_changeset *changeset) @@ -213,7 +255,12 @@ void free_extent_buffer_stale(struct extent_buffer *eb); #define WAIT_COMPLETE 1 #define WAIT_PAGE_LOCK 2 int read_extent_buffer_pages(struct extent_buffer *eb, int wait, - int mirror_num); + int mirror_num +#ifdef MY_ABC_HERE + , bool *can_retry + , u64 parent_transid +#endif /* MY_ABC_HERE */ + ); void wait_on_extent_buffer_writeback(struct extent_buffer *eb); static inline int num_extent_pages(const struct extent_buffer *eb) @@ -227,6 +274,13 @@ static inline int extent_buffer_uptodate(const struct extent_buffer *eb) return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); } +#ifdef MY_ABC_HERE +int memcmp_caseless_extent_buffer(const struct extent_buffer *eb, + const void *ptrv, + unsigned long len_ptrv, + unsigned long start, + unsigned long len); +#endif /* MY_ABC_HERE */ int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, unsigned long start, unsigned long len); void read_extent_buffer(const struct extent_buffer *eb, void *dst, @@ -282,9 +336,17 @@ struct btrfs_inode; int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, u64 length, u64 logical, struct page *page, - unsigned int pg_offset, int mirror_num); + unsigned int pg_offset, int mirror_num +#ifdef MY_ABC_HERE + , int abort_correction +#endif /* MY_ABC_HERE */ + ); void end_extent_writepage(struct page *page, int err, u64 start, u64 end); +#ifdef MY_ABC_HERE +int btrfs_repair_eb_io_failure(struct extent_buffer *eb, int mirror_num); +#else /* MY_ABC_HERE */ int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num); +#endif /* MY_ABC_HERE */ /* * When IO fails, either with EIO or csum verification fails, we @@ -303,6 +365,9 @@ struct io_failure_record { int this_mirror; int failed_mirror; int in_validation; +#ifdef MY_ABC_HERE + bool io_error; +#endif /* MY_ABC_HERE */ }; @@ -310,7 +375,12 @@ blk_status_t btrfs_submit_read_repair(struct inode *inode, struct bio *failed_bio, u64 phy_offset, struct page *page, unsigned int pgoff, u64 start, u64 end, int failed_mirror, - submit_bio_hook_t *submit_bio_hook); + submit_bio_hook_t *submit_bio_hook +#ifdef MY_ABC_HERE + , bool do_correction + , bool *run_out_all_copy +#endif /* MY_ABC_HERE */ + ); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS bool find_lock_delalloc_range(struct inode *inode, @@ -325,5 +395,17 @@ void btrfs_extent_buffer_leak_debug_check(struct btrfs_fs_info *fs_info); #else #define btrfs_extent_buffer_leak_debug_check(fs_info) do {} while (0) #endif +#ifdef MY_ABC_HERE +void add_cksumfailed_file(u64 rootid, u64 i_ino, struct btrfs_fs_info *fs_info); + +struct correction_record { + struct rb_node node; + u64 logical; +}; + +void correction_get_locked_record(struct btrfs_fs_info *fs_info, u64 logical); +void correction_put_locked_record(struct btrfs_fs_info *fs_info, u64 logical); +void correction_destroy_locked_record(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ #endif diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index bd6229fb2b6f..d86b5fcbe7ae 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include @@ -7,6 +10,9 @@ #include "volumes.h" #include "extent_map.h" #include "compression.h" +#ifdef MY_ABC_HERE +#include "btrfs_inode.h" +#endif /* MY_ABC_HERE */ static struct kmem_cache *extent_map_cache; @@ -38,6 +44,11 @@ void extent_map_tree_init(struct extent_map_tree *tree) tree->map = RB_ROOT_CACHED; INIT_LIST_HEAD(&tree->modified_extents); rwlock_init(&tree->lock); +#ifdef MY_ABC_HERE + atomic_set(&tree->nr_extent_maps, 0); + INIT_LIST_HEAD(&tree->not_modified_extents); + INIT_LIST_HEAD(&tree->syno_modified_extents); +#endif /* MY_ABC_HERE */ } /** @@ -59,6 +70,10 @@ struct extent_map *alloc_extent_map(void) em->generation = 0; refcount_set(&em->refs, 1); INIT_LIST_HEAD(&em->list); +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&em->free_list); + em->bl_increase = false; +#endif /* MY_ABC_HERE */ return em; } @@ -77,6 +92,9 @@ void free_extent_map(struct extent_map *em) if (refcount_dec_and_test(&em->refs)) { WARN_ON(extent_map_in_tree(em)); WARN_ON(!list_empty(&em->list)); +#ifdef MY_ABC_HERE + WARN_ON(!list_empty(&em->free_list)); +#endif /* MY_ABC_HERE */ if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) kfree(em->map_lookup); kmem_cache_free(extent_map_cache, em); @@ -232,6 +250,85 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next) return 0; } +#ifdef MY_ABC_HERE +static void check_and_insert_extent_map_to_global_extent( + struct extent_map_tree *tree, + struct extent_map *em, int modified) +{ + struct btrfs_inode *inode = tree->inode; + struct btrfs_fs_info *fs_info = NULL; + + if (!inode || !inode->root || + btrfs_is_free_space_inode(inode)) + return; + + if (!is_fstree(inode->root->root_key.objectid)) + return; + + fs_info = inode->root->fs_info; + atomic_inc(&tree->nr_extent_maps); + + if (!test_bit(EXTENT_FLAG_PINNED, &em->flags)) { + if (!em->bl_increase) { + atomic_inc(&fs_info->nr_extent_maps); + em->bl_increase = true; + } + } + + if (!modified) + list_move_tail(&em->free_list, &tree->not_modified_extents); + else if (test_bit(EXTENT_FLAG_PINNED, &em->flags)) + list_del_init(&em->free_list); + else + list_move_tail(&em->free_list, &tree->syno_modified_extents); + + if (list_empty(&inode->free_extent_map_inode)) { + spin_lock(&fs_info->extent_map_inode_list_lock); + list_move_tail(&inode->free_extent_map_inode, + &fs_info->extent_map_inode_list); + spin_unlock(&fs_info->extent_map_inode_list_lock); + } +} + +static void check_and_decrease_global_extent(struct extent_map_tree *tree, + struct extent_map *em) +{ + struct btrfs_inode *inode = tree->inode; + struct btrfs_fs_info *fs_info = NULL; + + // decreace nr_extent_maps when extent_map dettached from extent_tree + if (!list_empty(&em->free_list)) { + list_del_init(&em->free_list); + } + + if (!inode || !inode->root || + btrfs_is_free_space_inode(inode)) + return; + + if (!is_fstree(inode->root->root_key.objectid)) + return; + + fs_info = inode->root->fs_info; + WARN_ON(atomic_read(&tree->nr_extent_maps) == 0); + atomic_dec(&tree->nr_extent_maps); + + if (em->bl_increase) { + if (unlikely(atomic_read(&(fs_info->nr_extent_maps)) == 0)) + WARN_ON(1); + else + atomic_dec(&fs_info->nr_extent_maps); + em->bl_increase = false; + } + if (atomic_read(&tree->nr_extent_maps) == 0 && + !list_empty(&inode->free_extent_map_inode)) { + spin_lock(&fs_info->extent_map_inode_list_lock); + if (atomic_read(&inode->free_extent_map_counts) == 0) + list_del_init(&inode->free_extent_map_inode); + spin_unlock(&fs_info->extent_map_inode_list_lock); + } +} +#endif /* MY_ABC_HERE */ + static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) { struct extent_map *merge = NULL; @@ -264,6 +361,9 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) rb_erase_cached(&merge->rb_node, &tree->map); RB_CLEAR_NODE(&merge->rb_node); +#ifdef MY_ABC_HERE + check_and_decrease_global_extent(tree, merge); +#endif /* MY_ABC_HERE */ free_extent_map(merge); } } @@ -278,6 +378,9 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) RB_CLEAR_NODE(&merge->rb_node); em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start; em->generation = max(em->generation, merge->generation); +#ifdef MY_ABC_HERE + check_and_decrease_global_extent(tree, merge); +#endif /* MY_ABC_HERE */ free_extent_map(merge); } } @@ -310,6 +413,13 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, em->generation = gen; clear_bit(EXTENT_FLAG_PINNED, &em->flags); +#ifdef MY_ABC_HERE + list_move_tail(&em->free_list, &tree->syno_modified_extents); + if (!em->bl_increase) { + atomic_inc(&tree->inode->root->fs_info->nr_extent_maps); + em->bl_increase = true; + } +#endif /* MY_ABC_HERE */ em->mod_start = em->start; em->mod_len = em->len; @@ -405,6 +515,9 @@ int add_extent_mapping(struct extent_map_tree *tree, if (ret) goto out; +#ifdef MY_ABC_HERE + check_and_insert_extent_map_to_global_extent(tree, em, modified); +#endif /* MY_ABC_HERE */ setup_extent_mapping(tree, em, modified); if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) { extent_map_device_set_bits(em, CHUNK_ALLOCATED); @@ -494,6 +607,9 @@ void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) extent_map_device_clear_bits(em, CHUNK_ALLOCATED); RB_CLEAR_NODE(&em->rb_node); +#ifdef MY_ABC_HERE + check_and_decrease_global_extent(tree, em); +#endif /* MY_ABC_HERE */ } void replace_extent_mapping(struct extent_map_tree *tree, @@ -508,6 +624,10 @@ void replace_extent_mapping(struct extent_map_tree *tree, rb_replace_node_cached(&cur->rb_node, &new->rb_node, &tree->map); RB_CLEAR_NODE(&cur->rb_node); +#ifdef MY_ABC_HERE + check_and_decrease_global_extent(tree, cur); + check_and_insert_extent_map_to_global_extent(tree, new, modified); +#endif /* MY_ABC_HERE */ setup_extent_mapping(tree, new, modified); } diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 8e217337dff9..4ab9f401c7d8 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_EXTENT_MAP_H @@ -25,6 +28,10 @@ enum { EXTENT_FLAG_FILLING, /* filesystem extent mapping type */ EXTENT_FLAG_FS_MAPPING, +#ifdef MY_ABC_HERE + /* dedupe processing, don't flush pages */ + EXTENT_FLAG_DEDUPED, +#endif /* MY_ABC_HERE */ }; struct extent_map { @@ -47,12 +54,26 @@ struct extent_map { refcount_t refs; unsigned int compress_type; struct list_head list; +#ifdef MY_ABC_HERE + struct list_head free_list; + bool bl_increase; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +struct btrfs_inode; +#endif /* MY_ABC_HERE */ + struct extent_map_tree { struct rb_root_cached map; struct list_head modified_extents; rwlock_t lock; +#ifdef MY_ABC_HERE + struct list_head not_modified_extents; + struct list_head syno_modified_extents; + atomic_t nr_extent_maps; + struct btrfs_inode *inode; +#endif /* MY_ABC_HERE */ }; static inline int extent_map_in_tree(const struct extent_map *em) diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 48a2ea6d7092..89b2f91a1a7b 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -122,6 +125,227 @@ static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info, return ncsums * fs_info->sectorsize; } +#ifdef MY_ABC_HERE +/* + * search the tree again to find next BTRFS_EXTENT_DATA_KEY for this file + * returns 0 if it found something + * returns 1 if there are no more BTRFS_EXTENT_DATA_KEY for this file + * returns < 0 on io errors + */ +int btrfs_search_next_file_extent(struct btrfs_key *key, + struct btrfs_root *root, + struct btrfs_path *path) +{ + int ret = 1; + struct btrfs_key next; + + path->slots[0]++; + + if (path->slots[0] < btrfs_header_nritems(path->nodes[0])) { + goto get_key; + } + + ret = btrfs_next_leaf(root, path); + if (ret) { + goto out; + } + +get_key: + btrfs_item_key_to_cpu(path->nodes[0], &next, path->slots[0]); + if (next.objectid != key->objectid || next.type != BTRFS_EXTENT_DATA_KEY) { + ret = 1; + goto out; + } + + memcpy(key, &next, sizeof(struct btrfs_key)); + ret = 0; + +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int file_extent_deduped_check(struct btrfs_path *path, + struct btrfs_root *root, + u64 inode_num, u64 offset) +{ + int ret = 0; + struct extent_buffer *leaf = NULL; + struct btrfs_file_extent_item *fi = NULL; + + ret = btrfs_lookup_file_extent_by_file_offset(NULL, root, path, + inode_num, offset, 0); + if (0 > ret) + goto out; + + leaf = path->nodes[0]; + fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); + if (BTRFS_FILE_EXTENT_REG != btrfs_file_extent_type(leaf, fi) || + btrfs_file_extent_disk_bytenr(leaf, fi) == 0) { + btrfs_info(root->fs_info, + "file_extent_deduped_check inode %llu start %llu not found", + inode_num, offset); + ret = -1; + goto out; + } + + ret = (BTRFS_FILE_EXTENT_DEDUPED & btrfs_file_extent_syno_flag(leaf, fi)) + ? 1 : 0; + +out: + btrfs_release_path(path); + return ret; +} + +static inline void file_extent_deduped_set_leaf(struct extent_buffer *leaf, + int slots, bool on_off) +{ + int flag = 0; + struct btrfs_file_extent_item *fi = NULL; + + fi = btrfs_item_ptr(leaf, slots, struct btrfs_file_extent_item); + flag = btrfs_file_extent_syno_flag(leaf, fi); + if (on_off) { + flag |= BTRFS_FILE_EXTENT_DEDUPED; + } else { + flag &= ~BTRFS_FILE_EXTENT_DEDUPED; + } + btrfs_set_file_extent_syno_flag(leaf, fi, flag); + btrfs_mark_buffer_dirty(leaf); +} + +int btrfs_file_extent_deduped_clear(struct btrfs_trans_handle *trans, + struct btrfs_inode *inode, u64 file_offset) +{ + int ret = -1; + u64 inode_num = 0; + struct btrfs_root *root = NULL; + struct btrfs_path *path = NULL; + + if (!inode || !trans) { + return -EINVAL; + } + if (inode->flags & BTRFS_INODE_NODEDUPE) { + return 0; + } + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + inode_num = btrfs_ino(inode); + root = inode->root; + ret = file_extent_deduped_check(path, root, inode_num, file_offset); + if (0 >= ret) + goto out; + + ret = btrfs_lookup_file_extent_by_file_offset(trans, root, path, + inode_num, file_offset, 1); + if (0 > ret) + goto out; + + file_extent_deduped_set_leaf(path->nodes[0], path->slots[0], false); + +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_file_extent_deduped_set_range(struct inode *inode, u64 offset, + u64 len, bool on_off) +{ + int ret = 0; + u64 ino = 0; + u64 end = offset + len; + struct btrfs_key key; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf = NULL; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_root *root = NULL; + + if (!inode) { + return -EINVAL; + } + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ino = btrfs_ino(BTRFS_I(inode)); + root = BTRFS_I(inode)->root; + + trans = btrfs_start_transaction(root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + ret = btrfs_lookup_file_extent_by_file_offset(trans, root, path, + ino, offset, 1); + if (0 > ret) + goto out; + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + while (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY && key.offset < end) { + file_extent_deduped_set_leaf(leaf, path->slots[0], on_off); + + path->slots[0]++; + if (path->slots[0] < btrfs_header_nritems(leaf)) { + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + continue; + } + + ret = btrfs_next_leaf(root, path); + if (ret) { + if (0 < ret) + ret = 0; + break; + } + + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY || key.offset >= end) + break; + + /* do end transaction and go to next leaf */ + btrfs_release_path(path); + ret = btrfs_update_inode(trans, root, inode); + if (ret) { + btrfs_end_transaction(trans); + trans = NULL; + break; + } + btrfs_end_transaction(trans); + + trans = btrfs_start_transaction(root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + break; + } + ret = btrfs_lookup_file_extent(trans, root, path, ino, key.offset, 1); + if (0 > ret) + break; + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + } + +out: + // we should release path before btrfs_end_transaction(), or it will deadlock. + btrfs_free_path(path); + if (trans) { + ret = btrfs_update_inode(trans, root, inode); + btrfs_end_transaction(trans); + } + + return ret; +} +#endif /* MY_ABC_HERE */ + int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, @@ -161,6 +385,9 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, btrfs_set_file_extent_compression(leaf, item, compression); btrfs_set_file_extent_encryption(leaf, item, encryption); btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, item, 0); +#endif /* MY_ABC_HERE */ btrfs_mark_buffer_dirty(leaf); out: @@ -222,6 +449,35 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans, return ERR_PTR(ret); } +#ifdef MY_ABC_HERE +int btrfs_lookup_file_extent_by_file_offset(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, u64 inode_num, + u64 file_offset, int mod) +{ + int ret; + struct btrfs_key key; + struct extent_buffer *leaf = NULL; + struct btrfs_file_extent_item *fi = NULL; + + ret = btrfs_lookup_file_extent(trans, root, path, inode_num, file_offset, mod); + if (0 >= ret) + return ret; + + path->slots[0]--; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); + if (key.objectid != inode_num || + key.type != BTRFS_EXTENT_DATA_KEY || + key.offset + btrfs_file_extent_num_bytes(leaf, fi) < file_offset) { + return -ENOENT; + } + + return 0; +} +#endif /* MY_ABC_HERE */ + int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, @@ -926,8 +1182,10 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, } btrfs_release_path(path); + path->search_for_extension = 1; ret = btrfs_search_slot(trans, root, &file_key, path, csum_size, 1); + path->search_for_extension = 0; if (ret < 0) goto out; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index ffa48ac98d1e..64fac6d45cbe 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -28,6 +31,9 @@ #include "compression.h" #include "delalloc-space.h" #include "reflink.h" +#ifdef MY_ABC_HERE +#include "backref.h" +#endif /* MY_ABC_HERE */ static struct kmem_cache *btrfs_inode_defrag_cachep; /* @@ -35,6 +41,9 @@ static struct kmem_cache *btrfs_inode_defrag_cachep; * queue up these defrag structs to remember which * inodes need defragging passes */ +#ifdef MY_ABC_HERE +#define BTRFS_INODE_SYNO_DEFRAG_DELAY_GEN 5 +#endif /* MY_ABC_HERE */ struct inode_defrag { struct rb_node rb_node; /* objectid */ @@ -51,6 +60,15 @@ struct inode_defrag { /* last offset we were able to defrag */ u64 last_offset; +#ifdef MY_ABC_HERE + u64 end_offset; + + /* do normal or syno defrag */ + int defrag_type; + + struct list_head list; +#endif /* MY_ABC_HERE */ + /* if we've wrapped around back to zero once already */ int cycled; }; @@ -66,6 +84,16 @@ static int __compare_inode_defrag(struct inode_defrag *defrag1, return 1; else if (defrag1->ino < defrag2->ino) return -1; +#ifdef MY_ABC_HERE + else if (defrag1->defrag_type == defrag2->defrag_type && + defrag1->defrag_type == BTRFS_INODE_DEFRAG_SYNO) { + if (defrag1->last_offset > defrag2->end_offset) + return 1; + if (defrag1->end_offset < defrag2->last_offset) + return -1; + return 0; + } +#endif /* MY_ABC_HERE */ else return 0; } @@ -103,6 +131,23 @@ static int __btrfs_add_inode_defrag(struct btrfs_inode *inode, * an old defrag run, make sure to * lower the transid of our existing record */ +#ifdef MY_ABC_HERE + if (defrag->defrag_type != entry->defrag_type) + /* + * We do not allow different defrag mode on same inode at the same time. + * Merge of different type is not allowed, either. + */ + return -EEXIST; + if (defrag->defrag_type == BTRFS_INODE_DEFRAG_SYNO) { + if (defrag->last_offset < entry->last_offset) + entry->last_offset = defrag->last_offset; + if (defrag->end_offset > entry->end_offset) + entry->end_offset = defrag->end_offset; + entry->transid = defrag->transid; + list_move_tail(&entry->list, &fs_info->defrag_inodes_list[0]); + return -EEXIST; + } +#endif /* MY_ABC_HERE */ if (defrag->transid < entry->transid) entry->transid = defrag->transid; if (defrag->last_offset > entry->last_offset) @@ -110,12 +155,34 @@ static int __btrfs_add_inode_defrag(struct btrfs_inode *inode, return -EEXIST; } } +#ifdef MY_ABC_HERE + if (defrag->defrag_type == BTRFS_INODE_DEFRAG_SYNO) { + list_add_tail(&defrag->list, &fs_info->defrag_inodes_list[0]); + fs_info->reclaim_space_entry_count++; + } else { + list_add(&defrag->list, &fs_info->defrag_inodes_list[1]); + set_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags); + } +#else /* MY_ABC_HERE */ set_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags); +#endif /* MY_ABC_HERE */ rb_link_node(&defrag->rb_node, parent, p); rb_insert_color(&defrag->rb_node, &fs_info->defrag_inodes); return 0; } +#ifdef MY_ABC_HERE +static inline int __need_auto_reclaim(struct btrfs_fs_info *fs_info) +{ + if (!btrfs_test_opt(fs_info, AUTO_RECLAIM_SPACE)) + return 0; + + if (btrfs_fs_closing(fs_info)) + return 0; + + return 1; +} +#endif /* MY_ABC_HERE */ static inline int __need_auto_defrag(struct btrfs_fs_info *fs_info) { if (!btrfs_test_opt(fs_info, AUTO_DEFRAG)) @@ -132,7 +199,11 @@ static inline int __need_auto_defrag(struct btrfs_fs_info *fs_info) * enabled */ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, - struct btrfs_inode *inode) + struct btrfs_inode *inode +#ifdef MY_ABC_HERE + , u64 start, u64 end, int defrag_type +#endif /* MY_ABC_HERE */ + ) { struct btrfs_root *root = inode->root; struct btrfs_fs_info *fs_info = root->fs_info; @@ -140,11 +211,29 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, u64 transid; int ret; +#ifdef MY_ABC_HERE + if (defrag_type == BTRFS_INODE_DEFRAG_NORMAL) { + if (!__need_auto_defrag(fs_info) || + test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags)) + return 0; + } + + /* + * Every 4K page can contains 40 entries(96 bytes/entry), + * 16MB should be able to accommodate 40*(16MB/4K) = 163840 entries. + */ + if (defrag_type == BTRFS_INODE_DEFRAG_SYNO) { + if (!__need_auto_reclaim(fs_info) || + fs_info->reclaim_space_entry_count >= 163840) + return 0; + } +#else /* MY_ABC_HERE */ if (!__need_auto_defrag(fs_info)) return 0; if (test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags)) return 0; +#endif /* MY_ABC_HERE */ if (trans) transid = trans->transid; @@ -158,6 +247,11 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, defrag->ino = btrfs_ino(inode); defrag->transid = transid; defrag->root = root->root_key.objectid; +#ifdef MY_ABC_HERE + defrag->last_offset = start; + defrag->end_offset = end; + defrag->defrag_type = defrag_type; +#endif /* MY_ABC_HERE */ spin_lock(&fs_info->defrag_inodes_lock); if (!test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags)) { @@ -208,6 +302,32 @@ static void btrfs_requeue_inode_defrag(struct btrfs_inode *inode, * pick the defragable inode that we want, if it doesn't exist, we will get * the next one. */ +#ifdef MY_ABC_HERE +static struct inode_defrag * +btrfs_pick_defrag_inode(struct btrfs_fs_info *fs_info, struct list_head *cur_list) +{ + struct inode_defrag *entry = NULL; + + spin_lock(&fs_info->defrag_inodes_lock); + entry = list_first_entry_or_null(cur_list, struct inode_defrag, list); + if (!entry) + goto out; + if (entry->defrag_type == BTRFS_INODE_DEFRAG_NORMAL) + goto out; + if (entry->transid + BTRFS_INODE_SYNO_DEFRAG_DELAY_GEN >= fs_info->generation) + entry = NULL; + +out: + if (entry) { + rb_erase(&entry->rb_node, &fs_info->defrag_inodes); + list_del(&entry->list); + if (entry->defrag_type == BTRFS_INODE_DEFRAG_SYNO) + fs_info->reclaim_space_entry_count--; + } + spin_unlock(&fs_info->defrag_inodes_lock); + return entry; +} +#else /* MY_ABC_HERE */ static struct inode_defrag * btrfs_pick_defrag_inode(struct btrfs_fs_info *fs_info, u64 root, u64 ino) { @@ -248,6 +368,7 @@ btrfs_pick_defrag_inode(struct btrfs_fs_info *fs_info, u64 root, u64 ino) spin_unlock(&fs_info->defrag_inodes_lock); return entry; } +#endif /* MY_ABC_HERE */ void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info) { @@ -259,6 +380,11 @@ void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info) while (node) { rb_erase(node, &fs_info->defrag_inodes); defrag = rb_entry(node, struct inode_defrag, rb_node); +#ifdef MY_ABC_HERE + list_del(&defrag->list); + if (defrag->defrag_type == BTRFS_INODE_DEFRAG_SYNO) + fs_info->reclaim_space_entry_count--; +#endif /* MY_ABC_HERE */ kmem_cache_free(btrfs_inode_defrag_cachep, defrag); cond_resched_lock(&fs_info->defrag_inodes_lock); @@ -278,6 +404,9 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, struct btrfs_ioctl_defrag_range_args range; int num_defrag; int ret; +#ifdef MY_ABC_HERE + unsigned long max_to_defrag = BTRFS_DEFRAG_BATCH; +#endif /* MY_ABC_HERE */ /* get the inode */ inode_root = btrfs_get_fs_root(fs_info, defrag->root, true); @@ -299,15 +428,33 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, range.len = (u64)-1; range.start = defrag->last_offset; +#ifdef MY_ABC_HERE + if (defrag->defrag_type == BTRFS_INODE_DEFRAG_SYNO) { + range.flags |= BTRFS_DEFRAG_RANGE_SYNO_DEFRAG; + range.len = defrag->end_offset - defrag->last_offset; + defrag->transid = 0; + max_to_defrag = 0; + } + + sb_start_write(fs_info->sb); + num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid, + max_to_defrag); +#else /* MY_ABC_HERE */ sb_start_write(fs_info->sb); num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid, BTRFS_DEFRAG_BATCH); +#endif /* MY_ABC_HERE */ sb_end_write(fs_info->sb); /* * if we filled the whole defrag batch, there * must be more work to do. Queue this defrag * again */ +#ifdef MY_ABC_HERE + if (defrag->defrag_type == BTRFS_INODE_DEFRAG_SYNO) + kmem_cache_free(btrfs_inode_defrag_cachep, defrag); + else +#endif /* MY_ABC_HERE */ if (num_defrag == BTRFS_DEFRAG_BATCH) { defrag->last_offset = range.start; btrfs_requeue_inode_defrag(BTRFS_I(inode), defrag); @@ -338,8 +485,14 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) { struct inode_defrag *defrag; +#ifdef MY_ABC_HERE + int list_idx = 0; + struct list_head *cur_list = &fs_info->defrag_inodes_list[list_idx]; + int last_null = 0; +#else /* MY_ABC_HERE */ u64 first_ino = 0; u64 root_objectid = 0; +#endif /* MY_ABC_HERE */ atomic_inc(&fs_info->defrag_running); while (1) { @@ -348,6 +501,22 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) &fs_info->fs_state)) break; +#ifdef MY_ABC_HERE + if (!__need_auto_defrag(fs_info) && !__need_auto_reclaim(fs_info)) + break; + + /* find an inode to defrag */ + defrag = btrfs_pick_defrag_inode(fs_info, cur_list); + list_idx = (list_idx + 1) % 2; + cur_list = &fs_info->defrag_inodes_list[list_idx]; + if (!defrag) { + if (last_null) + break; + last_null = 1; + continue; + } + last_null = 0; +#else /* MY_ABC_HERE */ if (!__need_auto_defrag(fs_info)) break; @@ -366,6 +535,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) first_ino = defrag->ino + 1; root_objectid = defrag->root; +#endif /* MY_ABC_HERE */ __btrfs_run_defrag_inode(fs_info, defrag); } @@ -671,14 +841,16 @@ void btrfs_drop_extent_cache(struct btrfs_inode *inode, u64 start, u64 end, * If an extent intersects the range but is not entirely inside the range * it is either truncated or split. Anything entirely inside the range * is deleted from the tree. + * + * Note: the VFS' inode number of bytes is not updated, it's up to the caller + * to deal with that. We set the field 'bytes_found' of the arguments structure + * with the number of allocated bytes found in the target range, so that the + * caller can update the inode's number of bytes in an atomic way when + * replacing extents in a range to avoid races with stat(2). */ -int __btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_inode *inode, - struct btrfs_path *path, u64 start, u64 end, - u64 *drop_end, int drop_cache, - int replace_extent, - u32 extent_item_size, - int *key_inserted) +int btrfs_drop_extents(struct btrfs_trans_handle *trans, + struct btrfs_root *root, struct btrfs_inode *inode, + struct btrfs_drop_extents_args *args) { struct btrfs_fs_info *fs_info = root->fs_info; struct extent_buffer *leaf; @@ -686,14 +858,13 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, struct btrfs_ref ref = { 0 }; struct btrfs_key key; struct btrfs_key new_key; - struct inode *vfs_inode = &inode->vfs_inode; u64 ino = btrfs_ino(inode); - u64 search_start = start; + u64 search_start = args->start; u64 disk_bytenr = 0; u64 num_bytes = 0; u64 extent_offset = 0; u64 extent_end = 0; - u64 last_end = start; + u64 last_end = args->start; int del_nr = 0; int del_slot = 0; int extent_type; @@ -703,11 +874,32 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, int update_refs; int found = 0; int leafs_visited = 0; + struct btrfs_path *path = args->path; +#ifdef MY_ABC_HERE + u64 relative_offset; +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + u64 ram_bytes = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ - if (drop_cache) - btrfs_drop_extent_cache(inode, start, end - 1, 0); + args->bytes_found = 0; + args->extent_inserted = false; - if (start >= inode->disk_i_size && !replace_extent) + /* Must always have a path if ->replace_extent is true */ + ASSERT(!(args->replace_extent && !args->path)); + + if (!path) { + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + } + + if (args->drop_cache) + btrfs_drop_extent_cache(inode, args->start, args->end - 1, 0); + + if (args->start >= inode->disk_i_size && !args->replace_extent) modify_tree = 0; update_refs = (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) || @@ -718,7 +910,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, search_start, modify_tree); if (ret < 0) break; - if (ret > 0 && path->slots[0] > 0 && search_start == start) { + if (ret > 0 && path->slots[0] > 0 && search_start == args->start) { leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); if (key.objectid == ino && @@ -753,7 +945,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, path->slots[0]++; goto next_slot; } - if (key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end) + if (key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= args->end) break; fi = btrfs_item_ptr(leaf, path->slots[0], @@ -764,6 +956,9 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, extent_type == BTRFS_FILE_EXTENT_PREALLOC) { disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ extent_offset = btrfs_file_extent_offset(leaf, fi); extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); @@ -795,7 +990,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, } found = 1; - search_start = max(key.offset, start); + search_start = max(key.offset, args->start); if (recow || !modify_tree) { modify_tree = -1; btrfs_release_path(path); @@ -806,7 +1001,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * | - range to drop - | * | -------- extent -------- | */ - if (start > key.offset && end < extent_end) { + if (args->start > key.offset && args->end < extent_end) { BUG_ON(del_nr > 0); if (extent_type == BTRFS_FILE_EXTENT_INLINE) { ret = -EOPNOTSUPP; @@ -814,7 +1009,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, } memcpy(&new_key, &key, sizeof(new_key)); - new_key.offset = start; + new_key.offset = args->start; ret = btrfs_duplicate_item(trans, root, path, &new_key); if (ret == -EAGAIN) { @@ -828,15 +1023,15 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, fi = btrfs_item_ptr(leaf, path->slots[0] - 1, struct btrfs_file_extent_item); btrfs_set_file_extent_num_bytes(leaf, fi, - start - key.offset); + args->start - key.offset); fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); - extent_offset += start - key.offset; + extent_offset += args->start - key.offset; btrfs_set_file_extent_offset(leaf, fi, extent_offset); btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - start); + extent_end - args->start); btrfs_mark_buffer_dirty(leaf); if (update_refs && disk_bytenr > 0) { @@ -846,11 +1041,18 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, btrfs_init_data_ref(&ref, root->root_key.objectid, new_key.objectid, - start - extent_offset); + args->start - extent_offset +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, new_key.objectid, args->end) +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ ret = btrfs_inc_extent_ref(trans, &ref); BUG_ON(ret); /* -ENOMEM */ } - key.offset = start; + key.offset = args->start; } /* * From here on out we will have actually dropped something, so @@ -862,23 +1064,37 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * | ---- range to drop ----- | * | -------- extent -------- | */ - if (start <= key.offset && end < extent_end) { + if (args->start <= key.offset && args->end < extent_end) { if (extent_type == BTRFS_FILE_EXTENT_INLINE) { ret = -EOPNOTSUPP; break; } +#ifdef MY_ABC_HERE + if (args->partial_punch) { + relative_offset = key.offset - extent_offset; + if (relative_offset >= LLONG_MAX) + relative_offset = 0; + if (args->first_punch_pos && relative_offset < *(args->first_punch_pos)) + *(args->first_punch_pos) = relative_offset; + if (args->last_punch_pos && + relative_offset + ram_bytes > *(args->last_punch_pos)) + *(args->last_punch_pos) = relative_offset + ram_bytes; + *(args->partial_punch) = 1; + } +#endif /* MY_ABC_HERE */ + memcpy(&new_key, &key, sizeof(new_key)); - new_key.offset = end; + new_key.offset = args->end; btrfs_set_item_key_safe(fs_info, path, &new_key); - extent_offset += end - key.offset; + extent_offset += args->end - key.offset; btrfs_set_file_extent_offset(leaf, fi, extent_offset); btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - end); + extent_end - args->end); btrfs_mark_buffer_dirty(leaf); if (update_refs && disk_bytenr > 0) - inode_sub_bytes(vfs_inode, end - key.offset); + args->bytes_found += args->end - key.offset; break; } @@ -887,7 +1103,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * | ---- range to drop ----- | * | -------- extent -------- | */ - if (start > key.offset && end >= extent_end) { + if (args->start > key.offset && args->end >= extent_end) { BUG_ON(del_nr > 0); if (extent_type == BTRFS_FILE_EXTENT_INLINE) { ret = -EOPNOTSUPP; @@ -895,11 +1111,24 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, } btrfs_set_file_extent_num_bytes(leaf, fi, - start - key.offset); + args->start - key.offset); btrfs_mark_buffer_dirty(leaf); +#ifdef MY_ABC_HERE + if (args->partial_punch) { + *(args->partial_punch) = 1; + relative_offset = key.offset - extent_offset; + if (relative_offset >= LLONG_MAX) + relative_offset = 0; + if (args->first_punch_pos && relative_offset < *(args->first_punch_pos)) + *(args->first_punch_pos) = relative_offset; + if (args->last_punch_pos && + relative_offset + ram_bytes > *(args->last_punch_pos)) + *(args->last_punch_pos) = relative_offset + ram_bytes; + } +#endif /* MY_ABC_HERE */ if (update_refs && disk_bytenr > 0) - inode_sub_bytes(vfs_inode, extent_end - start); - if (end == extent_end) + args->bytes_found += extent_end - args->start; + if (args->end == extent_end) break; path->slots[0]++; @@ -910,7 +1139,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * | ---- range to drop ----- | * | ------ extent ------ | */ - if (start <= key.offset && end >= extent_end) { + if (args->start <= key.offset && args->end >= extent_end) { delete_extent_item: if (del_nr == 0) { del_slot = path->slots[0]; @@ -922,8 +1151,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, if (update_refs && extent_type == BTRFS_FILE_EXTENT_INLINE) { - inode_sub_bytes(vfs_inode, - extent_end - key.offset); + args->bytes_found += extent_end - key.offset; extent_end = ALIGN(extent_end, fs_info->sectorsize); } else if (update_refs && disk_bytenr > 0) { @@ -933,14 +1161,48 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, btrfs_init_data_ref(&ref, root->root_key.objectid, key.objectid, - key.offset - extent_offset); + key.offset - extent_offset +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, key.objectid, key.offset) +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (btrfs_root_disable_quota(root)) + ref.skip_qgroup = true; + else { + ref.ram_bytes = ram_bytes; + ref.inode = &inode->vfs_inode; + ref.skip_qgroup = false; + } +#endif /* MY_ABC_HERE */ ret = btrfs_free_extent(trans, &ref); BUG_ON(ret); /* -ENOMEM */ - inode_sub_bytes(vfs_inode, - extent_end - key.offset); +#ifdef MY_ABC_HERE + /* + * |-----punch rang-e----| + * |--COW--||--file extent--||--COW---| + * |-----------extent item------------| + * file extent is covered by punch range, but its actual + * extent size is larger. This is also partial punch. + */ + relative_offset = key.offset - extent_offset; + if (args->partial_punch && + extent_end - key.offset != ram_bytes) { + *(args->partial_punch) = 1; + if (relative_offset >= LLONG_MAX) + relative_offset = 0; + if (args->first_punch_pos && + relative_offset < *(args->first_punch_pos)) + *(args->first_punch_pos) = relative_offset; + if (args->last_punch_pos && + relative_offset + num_bytes > *(args->last_punch_pos)) + *(args->last_punch_pos) = relative_offset + num_bytes; + } +#endif /* MY_ABC_HERE */ + args->bytes_found += extent_end - key.offset; } - if (end == extent_end) + if (args->end == extent_end) break; if (path->slots[0] + 1 < btrfs_header_nritems(leaf)) { @@ -970,7 +1232,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * Set path->slots[0] to first slot, so that after the delete * if items are move off from our leaf to its immediate left or * right neighbor leafs, we end up with a correct and adjusted - * path->slots[0] for our insertion (if replace_extent != 0). + * path->slots[0] for our insertion (if args->replace_extent). */ path->slots[0] = del_slot; ret = btrfs_del_items(trans, root, path, del_slot, del_nr); @@ -984,15 +1246,15 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, * which case it unlocked our path, so check path->locks[0] matches a * write lock. */ - if (!ret && replace_extent && leafs_visited == 1 && + if (!ret && args->replace_extent && leafs_visited == 1 && (path->locks[0] == BTRFS_WRITE_LOCK_BLOCKING || path->locks[0] == BTRFS_WRITE_LOCK) && btrfs_leaf_free_space(leaf) >= - sizeof(struct btrfs_item) + extent_item_size) { + sizeof(struct btrfs_item) + args->extent_item_size) { key.objectid = ino; key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = start; + key.offset = args->start; if (!del_nr && path->slots[0] < btrfs_header_nritems(leaf)) { struct btrfs_key slot_key; @@ -1000,30 +1262,18 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, if (btrfs_comp_cpu_keys(&key, &slot_key) > 0) path->slots[0]++; } - setup_items_for_insert(root, path, &key, &extent_item_size, 1); - *key_inserted = 1; + setup_items_for_insert(root, path, &key, + &args->extent_item_size, 1); + args->extent_inserted = true; } - if (!replace_extent || !(*key_inserted)) + if (!args->path) + btrfs_free_path(path); + else if (!args->extent_inserted) btrfs_release_path(path); - if (drop_end) - *drop_end = found ? min(end, last_end) : end; - return ret; -} -int btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, u64 start, - u64 end, int drop_cache) -{ - struct btrfs_path *path; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - ret = __btrfs_drop_extents(trans, root, BTRFS_I(inode), path, start, - end, NULL, drop_cache, 0, 0, NULL); - btrfs_free_path(path); +out: + args->drop_end = found ? min(args->end, last_end) : args->end; return ret; } @@ -1090,6 +1340,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, int recow; int ret = 0; u64 ino = btrfs_ino(inode); +#ifdef MY_ABC_HERE + struct btrfs_key syno_usage_key; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -1148,6 +1401,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, trans->transid); btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - end); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, fi, 0); +#endif /* MY_ABC_HERE */ btrfs_set_file_extent_offset(leaf, fi, end - orig_offset); fi = btrfs_item_ptr(leaf, path->slots[0] - 1, @@ -1156,6 +1412,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, trans->transid); btrfs_set_file_extent_num_bytes(leaf, fi, end - other_start); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, fi, 0); +#endif /* MY_ABC_HERE */ btrfs_mark_buffer_dirty(leaf); goto out; } @@ -1173,6 +1432,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, start - key.offset); btrfs_set_file_extent_generation(leaf, fi, trans->transid); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, fi, 0); +#endif /* MY_ABC_HERE */ path->slots[0]++; new_key.offset = start; btrfs_set_item_key_safe(fs_info, path, &new_key); @@ -1185,6 +1447,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, other_end - start); btrfs_set_file_extent_offset(leaf, fi, start - orig_offset); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, fi, 0); +#endif /* MY_ABC_HERE */ btrfs_mark_buffer_dirty(leaf); goto out; } @@ -1224,7 +1489,14 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, bytenr, num_bytes, 0); btrfs_init_data_ref(&ref, root->root_key.objectid, ino, - orig_offset); + orig_offset +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, new_key.objectid, new_key.offset) +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ ret = btrfs_inc_extent_ref(trans, &ref); if (ret) { btrfs_abort_transaction(trans, ret); @@ -1249,7 +1521,14 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, other_end = 0; btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr, num_bytes, 0); - btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset); + btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset +#ifdef MY_ABC_HERE + , 0 /* syno_usage, we'll adjust later */ +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ if (extent_mergeable(leaf, path->slots[0] + 1, ino, bytenr, orig_offset, &other_start, &other_end)) { @@ -1260,6 +1539,10 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, extent_end = other_end; del_slot = path->slots[0] + 1; del_nr++; +#ifdef MY_ABC_HERE + btrfs_item_key_to_cpu(leaf, &syno_usage_key, path->slots[0] + 1); + ref.syno_usage = btrfs_syno_usage_ref_check(root, ino, syno_usage_key.offset); +#endif /* MY_ABC_HERE */ ret = btrfs_free_extent(trans, &ref); if (ret) { btrfs_abort_transaction(trans, ret); @@ -1278,6 +1561,10 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, key.offset = other_start; del_slot = path->slots[0]; del_nr++; +#ifdef MY_ABC_HERE + btrfs_item_key_to_cpu(leaf, &syno_usage_key, path->slots[0]); + ref.syno_usage = btrfs_syno_usage_ref_check(root, ino, syno_usage_key.offset); +#endif /* MY_ABC_HERE */ ret = btrfs_free_extent(trans, &ref); if (ret) { btrfs_abort_transaction(trans, ret); @@ -1299,6 +1586,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, btrfs_set_file_extent_generation(leaf, fi, trans->transid); btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - key.offset); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, fi, 0); +#endif /* MY_ABC_HERE */ btrfs_mark_buffer_dirty(leaf); ret = btrfs_del_items(trans, root, path, del_slot, del_nr); @@ -1343,6 +1633,83 @@ static int prepare_uptodate_page(struct inode *inode, /* * this just gets pages into the page cache and locks them down. */ +#ifdef MY_ABC_HERE +static noinline int prepare_pages(struct inode *inode, struct page **pages, + size_t num_pages, loff_t pos, + size_t write_bytes, bool force_uptodate) +{ + int i; + unsigned long index = pos >> PAGE_SHIFT; + gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); + int err = 0; + int faili; + +restart: + for (i = 0; i < num_pages; i++) { +again: + pages[i] = find_or_create_page(inode->i_mapping, index + i, + mask | __GFP_WRITE); + if (!pages[i]) { + faili = i - 1; + err = -ENOMEM; + goto fail; + } + + if (i == 0) { + err = prepare_uptodate_page(inode, pages[i], pos, + force_uptodate); + if (!err && i == num_pages - 1) + err = prepare_uptodate_page(inode, pages[i], + pos + write_bytes, false); + if (err) { + put_page(pages[i]); + if (err == -EAGAIN) { + err = 0; + goto again; + } + faili = i - 1; + goto fail; + } + } else if (i == num_pages - 1) { + if (((pos + write_bytes) & (PAGE_SIZE - 1)) && + !PageUptodate(pages[i])) { + + faili = i - 1; + while (faili >= 0) { + unlock_page(pages[faili]); + put_page(pages[faili]); + faili--; + } + + err = prepare_uptodate_page(inode, pages[i], + pos + write_bytes, false); + if (err) { + put_page(pages[i]); + if (err == -EAGAIN) + goto restart; + goto out; + } + + unlock_page(pages[i]); + put_page(pages[i]); + goto restart; + } + } + + wait_on_page_writeback(pages[i]); + } + + return 0; +fail: + while (faili >= 0) { + unlock_page(pages[faili]); + put_page(pages[faili]); + faili--; + } +out: + return err; +} +#else /* MY_ABC_HERE */ static noinline int prepare_pages(struct inode *inode, struct page **pages, size_t num_pages, loff_t pos, size_t write_bytes, bool force_uptodate) @@ -1391,6 +1758,7 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages, return err; } +#endif /* MY_ABC_HERE */ /* * This function locks the extent and properly waits for data=ordered extents @@ -1558,6 +1926,508 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode) btrfs_drew_write_unlock(&inode->root->snapshot_lock); } +#ifdef MY_ABC_HERE +void syno_ordered_extent_throttle(struct btrfs_fs_info *fs_info) +{ + DEFINE_WAIT(wait); + + if (!fs_info) + return; + + if (fs_info->syno_max_ordered_queue_size && atomic64_read(&fs_info->syno_ordered_extent_nr) > fs_info->syno_max_ordered_queue_size) { + prepare_to_wait_exclusive(&fs_info->syno_ordered_queue_wait, &wait, TASK_UNINTERRUPTIBLE); + if (atomic64_read(&fs_info->syno_ordered_extent_nr) > fs_info->syno_max_ordered_queue_size) + schedule(); + finish_wait(&fs_info->syno_ordered_queue_wait, &wait); + } +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#include + +static void update_time_for_write(struct inode *inode); + +#ifdef MY_ABC_HERE +static int generic_write_init_and_checks(struct file* filp, loff_t pos, size_t nbytes) +{ + struct iovec iov = { .iov_base = NULL, .iov_len = nbytes }; + struct kiocb kiocb; + struct iov_iter iter; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = pos; + iov_iter_init(&iter, WRITE, &iov, 1, nbytes); + + return generic_write_checks(&kiocb, &iter); +} + +static noinline int __btrfs_ecryptfs_zero_copy(struct file *file, loff_t pos, int num_page, + struct page **pages, encrypt_page_cb_t encrypt_cb, void *crypt_stat) +{ + struct inode *inode = file_inode(file); + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct page *dst_pages[MAX_PAGES_PER_RECVFILE + 1]; + struct extent_state *cached_state = NULL; + struct extent_changeset *data_reserved = NULL; + u64 release_bytes = 0; + u64 lockstart; + u64 lockend; + u64 start_pos = 0; + u64 end_pos; + int ret = 0, i; + size_t count = num_page * PAGE_SIZE; + int extents_locked; + +#ifdef MY_ABC_HERE + syno_ordered_extent_throttle(fs_info); +#endif /* MY_ABC_HERE */ + + file_start_write(file); + + BUG_ON(num_page > MAX_PAGES_PER_RECVFILE + 1); + inode_lock(inode); + ret = generic_write_init_and_checks(file, pos, count); + if (ret <= 0) + goto out; + + /* + * We can write back this queue in page reclaim + */ + current->backing_dev_info = inode_to_bdi(inode); + ret = file_remove_privs(file); + if (ret) + goto out; + + update_time_for_write(inode); + /* copied from btrfs_file_write_iter */ + start_pos = round_down(pos, fs_info->sectorsize); + if (start_pos > i_size_read(inode)) { + end_pos = round_up(pos + count, fs_info->sectorsize); + ret = btrfs_cont_expand(inode, i_size_read(inode), end_pos); + if (ret) + goto out; + } + + ret = btrfs_check_data_free_space(BTRFS_I(inode), + &data_reserved, pos, count); + if (ret) + goto out; + + ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), count); + if (ret) { + btrfs_free_reserved_data_space(BTRFS_I(inode), + data_reserved, pos, count); + goto out; + } + + release_bytes = count; + +again: + /* + * This is going to setup the pages array with the number of + * pages we want, so we don't really need to worry about the + * contents of pages from loop to loop + */ + ret = prepare_pages(inode, dst_pages, num_page, pos, count, false); + if (ret) { + btrfs_delalloc_release_extents(BTRFS_I(inode), count); + goto out; + } + + extents_locked = lock_and_cleanup_extent_if_need( + BTRFS_I(inode), dst_pages, + num_page, pos, count, &lockstart, + &lockend, &cached_state); + if (extents_locked < 0) { + if (extents_locked == -EAGAIN) + goto again; + btrfs_delalloc_release_extents(BTRFS_I(inode), count); + ret = extents_locked; + goto out; + } + + for (i = 0; i < num_page; i++) { + ret = encrypt_cb(dst_pages[i], crypt_stat, pages[i]); + if (ret) { + if (extents_locked) + unlock_extent_cached(&BTRFS_I(inode)->io_tree, + lockstart, lockend, &cached_state); + btrfs_delalloc_release_extents(BTRFS_I(inode), count); + btrfs_drop_pages(dst_pages, num_page); + goto out; + } + cond_resched(); + } + ret = btrfs_dirty_pages(BTRFS_I(inode), dst_pages, + num_page, pos, count, + &cached_state); + + if (extents_locked) + unlock_extent_cached(&BTRFS_I(inode)->io_tree, + lockstart, lockend, &cached_state); + else + free_extent_state(cached_state); + + btrfs_delalloc_release_extents(BTRFS_I(inode), count); + btrfs_drop_pages(dst_pages, num_page); + if (ret) + goto out; + + release_bytes = 0; + balance_dirty_pages_ratelimited(inode->i_mapping); +#ifdef MY_ABC_HERE + /* + * DSM#134799 + * In order to align the previous enc seq write performance + * we skip multiple writeback + */ + // syno_writeback_balance_dirty_pages(fs_info); +#endif /* MY_ABC_HERE */ + +out: + if (release_bytes) + btrfs_delalloc_release_space(BTRFS_I(inode), + data_reserved, pos, + release_bytes, true); + extent_changeset_free(data_reserved); + current->backing_dev_info = NULL; + inode_unlock(inode); + file_end_write(file); + + return ret; +} + +static noinline int btrfs_ecryptfs_zero_copy(struct file *file, loff_t pos, int num_page, + struct page **pages, encrypt_page_cb_t encrypt_cb, void *crypt_stat) +{ + ssize_t ret; + int nrptrs = MAX_PAGES_PER_RECVFILE; + int tmp_num_pages, remain_pages = num_page; + loff_t offset = pos; + struct page **tmp_pages = pages; + + do { + tmp_num_pages = min(remain_pages, nrptrs); + ret = __btrfs_ecryptfs_zero_copy(file, offset, tmp_num_pages, tmp_pages, + encrypt_cb, crypt_stat); + if (ret) + break; + remain_pages -= tmp_num_pages; + offset += tmp_num_pages * PAGE_SIZE; + tmp_pages += tmp_num_pages; + } while (remain_pages > 0); + return ret; +} +#endif /* MY_ABC_HERE */ + +static noinline ssize_t btrfs_do_recvfile(struct file *file, struct socket *sock, + loff_t pos, size_t count, size_t * rbytes, size_t * wbytes) +{ + struct inode *inode = file_inode(file); + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + struct msghdr msg; + struct page *pages[MAX_PAGES_PER_RECVFILE]; + struct extent_state *cached_state = NULL; + struct kvec iov[MAX_PAGES_PER_RECVFILE]; + struct extent_changeset *data_reserved = NULL; + u64 release_bytes = 0; + u64 lockstart; + u64 lockend; + u64 start_pos = 0; + u64 end_pos; + size_t num_written = 0; + ssize_t ret = 0; + int recv_meg_ret = 0; + int i; + long rcvtimeo; + bool only_release_metadata = false; + size_t offset = offset_in_page(pos); + size_t sector_offset = pos & (fs_info->sectorsize - 1); + size_t write_bytes = min(count, + MAX_PAGES_PER_RECVFILE * (size_t)PAGE_SIZE - + offset); + size_t num_pages = DIV_ROUND_UP(write_bytes + offset, + PAGE_SIZE); + size_t reserve_bytes; + size_t dirty_pages; + size_t copied = 0; + size_t dirty_sectors; + size_t num_sectors; + int extents_locked; + loff_t oldsize; + int clean_page = 0; + +#ifdef MY_ABC_HERE + syno_ordered_extent_throttle(fs_info); +#endif /* MY_ABC_HERE */ + + /* copied from btrfs_file_write_iter */ + start_pos = round_down(pos, fs_info->sectorsize); + oldsize = i_size_read(inode); + if (start_pos > oldsize) { + /* Expand hole size to cover write data, preventing empty gap */ + end_pos = round_up(pos + count, + fs_info->sectorsize); + ret = btrfs_cont_expand(inode, oldsize, end_pos); + if (ret) + return ret; + if (start_pos > round_up(oldsize, fs_info->sectorsize)) + clean_page = 1; + } + memset(&msg, 0, sizeof(msg)); + rcvtimeo = sock->sk->sk_rcvtimeo; + sock->sk->sk_rcvtimeo = 64 * HZ; + + /* copied from btrfs_buffered_write */ + + reserve_bytes = round_up(write_bytes + sector_offset, + fs_info->sectorsize); + + ret = btrfs_check_data_free_space(BTRFS_I(inode), + &data_reserved, pos, + write_bytes); + if (ret < 0) { + if (btrfs_check_nocow_lock(BTRFS_I(inode), pos, + &write_bytes) > 0) { + /* + * For nodata cow case, no need to reserve + * data space. + */ + only_release_metadata = true; + /* + * our prealloc extent may be smaller than + * write_bytes, so scale down. + */ + num_pages = DIV_ROUND_UP(write_bytes + offset, + PAGE_SIZE); + reserve_bytes = round_up(write_bytes + + sector_offset, + fs_info->sectorsize); + } else { + goto err; + } + } + + WARN_ON(reserve_bytes == 0); + ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), + reserve_bytes); + if (ret) { + if (!only_release_metadata) + btrfs_free_reserved_data_space(BTRFS_I(inode), + data_reserved, pos, + write_bytes); + else + btrfs_check_nocow_unlock(BTRFS_I(inode)); + goto err; + } + + release_bytes = reserve_bytes; + +again: + /* + * This is going to setup the pages array with the number of + * pages we want, so we don't really need to worry about the + * contents of pages from loop to loop + */ + ret = prepare_pages(inode, pages, num_pages, + pos, write_bytes, + false); + if (ret) { + btrfs_delalloc_release_extents(BTRFS_I(inode), + reserve_bytes); + goto err; + } + + extents_locked = lock_and_cleanup_extent_if_need( + BTRFS_I(inode), pages, + num_pages, pos, write_bytes, &lockstart, + &lockend, &cached_state); + if (extents_locked < 0) { + if (extents_locked == -EAGAIN) + goto again; + btrfs_delalloc_release_extents(BTRFS_I(inode), + reserve_bytes); + ret = extents_locked; + goto err; + } + + iov[0].iov_base = kmap(pages[0]) + offset; + iov[0].iov_len = PAGE_SIZE - offset; + for (i = 1; i < num_pages; i++) { + iov[i].iov_base = kmap(pages[i]); + iov[i].iov_len = PAGE_SIZE; + } + if (0 != ((write_bytes + offset) & (PAGE_SIZE - 1)) && 1 < num_pages) { + iov[num_pages-1].iov_len = (write_bytes + offset) & (PAGE_SIZE - 1); + } + recv_meg_ret = kernel_recvmsg( + sock, &msg, &iov[0], num_pages, write_bytes, + MSG_WAITALL); + + for (i = 0; i < num_pages; i++) + kunmap(pages[i]); + + if (0 > recv_meg_ret) { + if (extents_locked) + unlock_extent_cached(&BTRFS_I(inode)->io_tree, + lockstart, lockend, &cached_state); + else + free_extent_state(cached_state); + btrfs_delalloc_release_extents(BTRFS_I(inode), + reserve_bytes); + btrfs_drop_pages(pages, num_pages); + ret = recv_meg_ret; + goto err; + } + copied = (size_t) recv_meg_ret; + *rbytes = copied; + if (write_bytes > recv_meg_ret) + recv_meg_ret = -EPIPE; + + num_sectors = BTRFS_BYTES_TO_BLKS(fs_info, reserve_bytes); + dirty_sectors = round_up(copied + sector_offset, + fs_info->sectorsize); + dirty_sectors = BTRFS_BYTES_TO_BLKS(fs_info, dirty_sectors); + + if (copied == 0) { + dirty_sectors = 0; + dirty_pages = 0; + } else { + dirty_pages = DIV_ROUND_UP(copied + offset, + PAGE_SIZE); + } + + if (num_sectors > dirty_sectors) { + /* release everything except the sectors we dirtied */ + release_bytes -= dirty_sectors << + fs_info->sb->s_blocksize_bits; + if (only_release_metadata) { + btrfs_delalloc_release_metadata(BTRFS_I(inode), + release_bytes, true); + } else { + u64 __pos; + + __pos = round_down(pos, fs_info->sectorsize) + + (dirty_pages << PAGE_SHIFT); + btrfs_delalloc_release_space(BTRFS_I(inode), + data_reserved, __pos, + release_bytes, true); + } + } + + release_bytes = round_up(copied + sector_offset, + fs_info->sectorsize); + + if (copied > 0) + ret = btrfs_dirty_pages(BTRFS_I(inode), pages, + dirty_pages, pos, copied, + &cached_state); + + /* + * If we have not locked the extent range, because the range's + * start offset is >= i_size, we might still have a non-NULL + * cached extent state, acquired while marking the extent range + * as delalloc through btrfs_dirty_pages(). Therefore free any + * possible cached extent state to avoid a memory leak. + */ + if (extents_locked) + unlock_extent_cached(&BTRFS_I(inode)->io_tree, + lockstart, lockend, &cached_state); + else + free_extent_state(cached_state); + + btrfs_delalloc_release_extents(BTRFS_I(inode), reserve_bytes); + if (ret) { + btrfs_drop_pages(pages, num_pages); + goto err; + } + + release_bytes = 0; + if (only_release_metadata) + btrfs_check_nocow_unlock(BTRFS_I(inode)); + + if (only_release_metadata && copied > 0) { + lockstart = round_down(pos, + fs_info->sectorsize); + lockend = round_up(pos + copied, + fs_info->sectorsize) - 1; + + set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, + lockend, EXTENT_NORESERVE, NULL, + NULL, GFP_NOFS); + } + + btrfs_drop_pages(pages, num_pages); + + cond_resched(); + + balance_dirty_pages_ratelimited(inode->i_mapping); +#ifdef MY_ABC_HERE + syno_writeback_balance_dirty_pages(fs_info); +#endif /* MY_ABC_HERE */ + + num_written = copied; + if (recv_meg_ret == -EPIPE) { + ret = -EPIPE; + goto err; + } + +err: + sock->sk->sk_rcvtimeo = rcvtimeo; + + if (release_bytes) { + if (only_release_metadata) { + btrfs_check_nocow_unlock(BTRFS_I(inode)); + btrfs_delalloc_release_metadata(BTRFS_I(inode), + release_bytes, true); + } else { + btrfs_delalloc_release_space(BTRFS_I(inode), + data_reserved, + round_down(pos, fs_info->sectorsize), + release_bytes, true); + } + } + *wbytes = num_written; + + extent_changeset_free(data_reserved); + + if (clean_page) + pagecache_isize_extended(inode, oldsize, + i_size_read(inode)); + + return ret ? ret : num_written; +} + +static noinline ssize_t btrfs_recvfile(int fd, struct file *file, struct socket *sock, + loff_t pos, size_t count, size_t *received, size_t *written) +{ + ssize_t ret; + + update_time_for_write(file_inode(file)); + do { + size_t bytes_received = 0; + size_t bytes_written = 0; + + int nrptrs = MAX_PAGES_PER_RECVFILE; + size_t offset = pos & (PAGE_SIZE - 1); + size_t max_bytes = nrptrs * (size_t)PAGE_SIZE - offset; + + ret = btrfs_do_recvfile(file, sock, pos, (count > max_bytes) ? + max_bytes : count, &bytes_received, &bytes_written); + *received += bytes_received; + *written += bytes_written; + if (ret <= 0) + break; + count -= bytes_written; + pos += bytes_written; + } while (count > 0); + return ret < 0 ? ret : *written; +} +#endif /* MY_ABC_HERE */ + static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i) { @@ -1575,6 +2445,9 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, int ret = 0; bool only_release_metadata = false; bool force_page_uptodate = false; +#ifdef MY_ABC_HERE + bool relock = false; +#endif /* MY_ABC_HERE */ nrptrs = min(DIV_ROUND_UP(iov_iter_count(i), PAGE_SIZE), PAGE_SIZE / (sizeof(struct page *))); @@ -1584,6 +2457,20 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, if (!pages) return -ENOMEM; +#ifdef MY_ABC_HERE + inode_dio_begin(inode); + /* + * If the write is beyond the EOF, we need update + * the isize, but it is protected by i_mutex. So we can + * not unlock the i_mutex at this case. + */ + if (pos + iov_iter_count(i) <= i_size_read(inode)) { + inode_unlock(inode); + down_read(&BTRFS_I(inode)->dio_sem); + relock = true; + } +#endif /* MY_ABC_HERE */ + while (iov_iter_count(i) > 0) { struct extent_state *cached_state = NULL; size_t offset = offset_in_page(pos); @@ -1774,6 +2661,9 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, cond_resched(); balance_dirty_pages_ratelimited(inode->i_mapping); +#ifdef MY_ABC_HERE + syno_writeback_balance_dirty_pages(fs_info); +#endif /* MY_ABC_HERE */ pos += copied; num_written += copied; @@ -1793,6 +2683,13 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, release_bytes, true); } } +#ifdef MY_ABC_HERE + if (relock) + up_read(&BTRFS_I(inode)->dio_sem); + inode_dio_end(inode); + if (relock) + inode_lock(inode); +#endif /* MY_ABC_HERE */ extent_changeset_free(data_reserved); return num_written ? num_written : ret; @@ -1854,6 +2751,11 @@ static void update_time_for_write(struct inode *inode) if (IS_I_VERSION(inode)) inode_inc_iversion(inode); + +#ifdef MY_ABC_HERE + if (unlikely(block_dump)) + block_dump___btrfs_update_inode(inode); +#endif /* MY_ABC_HERE */ } static ssize_t btrfs_file_write_iter(struct kiocb *iocb, @@ -1873,6 +2775,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, loff_t oldsize; int clean_page = 0; +#ifdef MY_ABC_HERE + syno_ordered_extent_throttle(fs_info); +#endif /* MY_ABC_HERE */ + if (!(iocb->ki_flags & IOCB_DIRECT) && (iocb->ki_flags & IOCB_NOWAIT)) return -EOPNOTSUPP; @@ -2111,6 +3017,10 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) u64 len; bool full_sync; +#ifdef MY_ABC_HERE + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + atomic64_inc(&fs_info->fsync_cnt); +#endif /* MY_ABC_HERE */ trace_btrfs_sync_file(file, datasync); btrfs_init_log_ctx(&ctx, inode); @@ -2282,6 +3192,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) goto out; } } +#ifdef MY_ABC_HERE + atomic64_inc(&fs_info->fsync_full_commit_cnt); +#endif /* MY_ABC_HERE */ ret = btrfs_commit_transaction(trans); } else { ret = btrfs_end_transaction(trans); @@ -2360,6 +3273,12 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct extent_map_tree *em_tree = &inode->extent_tree; struct btrfs_key key; int ret; +#ifdef MY_ABC_HERE + int modify_slot = -1; + int del_slot = -1; + bool update_offset = false; + u64 num_bytes = 0; +#endif /* MY_ABC_HERE */ if (btrfs_fs_incompat(fs_info, NO_HOLES)) goto out; @@ -2368,7 +3287,11 @@ static int fill_holes(struct btrfs_trans_handle *trans, key.type = BTRFS_EXTENT_DATA_KEY; key.offset = offset; +#ifdef MY_ABC_HERE + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); +#else /* MY_ABC_HERE */ ret = btrfs_search_slot(trans, root, &key, path, 0, 1); +#endif /* MY_ABC_HERE */ if (ret <= 0) { /* * We should have dropped this offset, so if we find it then @@ -2380,6 +3303,54 @@ static int fill_holes(struct btrfs_trans_handle *trans, } leaf = path->nodes[0]; +#ifdef MY_ABC_HERE + if (hole_mergeable(inode, leaf, path->slots[0] - 1, offset, end)) { + fi = btrfs_item_ptr(leaf, path->slots[0] - 1, + struct btrfs_file_extent_item); + num_bytes = btrfs_file_extent_num_bytes(leaf, fi) + + end - offset; + modify_slot = path->slots[0] - 1; + } + + if (hole_mergeable(inode, leaf, path->slots[0], offset, end)) { + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + if (modify_slot != -1) { + num_bytes += btrfs_file_extent_num_bytes(leaf, fi); + del_slot = path->slots[0]; + } else { + num_bytes = btrfs_file_extent_num_bytes(leaf, fi) + + end - offset; + modify_slot = path->slots[0]; + update_offset = true; + } + } + + if (modify_slot >= 0) { + fi = btrfs_item_ptr(leaf, modify_slot, + struct btrfs_file_extent_item); + + btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); + btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); + if (update_offset) { + key.offset = offset; + btrfs_set_item_key_safe(root->fs_info, path, &key); + } + btrfs_set_file_extent_offset(leaf, fi, 0); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_generation(leaf, fi, trans->transid); +#endif /* MY_ABC_HERE */ + btrfs_mark_buffer_dirty(leaf); + if (del_slot >= 0) { + ret = btrfs_del_items(trans, root, path, del_slot, 1); + if (ret) { + btrfs_release_path(path); + return ret; + } + } + goto out; + } +#else /* MY_ABC_HERE */ if (hole_mergeable(inode, leaf, path->slots[0] - 1, offset, end)) { u64 num_bytes; @@ -2410,6 +3381,7 @@ static int fill_holes(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(leaf); goto out; } +#endif /* MY_ABC_HERE */ btrfs_release_path(path); ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), @@ -2526,7 +3498,8 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, struct inode *inode, struct btrfs_path *path, struct btrfs_replace_extent_info *extent_info, - const u64 replace_len) + const u64 replace_len, + const u64 bytes_to_drop) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; @@ -2541,8 +3514,20 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, return 0; if (extent_info->disk_offset == 0 && - btrfs_fs_incompat(fs_info, NO_HOLES)) + btrfs_fs_incompat(fs_info, NO_HOLES)) { +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), 0, bytes_to_drop); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, bytes_to_drop, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, bytes_to_drop, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(BTRFS_I(inode), 0, bytes_to_drop); +#endif /* MY_ABC_HERE */ return 0; + } key.objectid = btrfs_ino(BTRFS_I(inode)); key.type = BTRFS_EXTENT_DATA_KEY; @@ -2571,10 +3556,38 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, return ret; /* If it's a hole, nothing more needs to be done. */ - if (extent_info->disk_offset == 0) + if (extent_info->disk_offset == 0) { +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), 0, bytes_to_drop); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, bytes_to_drop, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, bytes_to_drop, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(BTRFS_I(inode), 0, bytes_to_drop); +#endif /* MY_ABC_HERE */ return 0; + } - inode_add_bytes(inode, replace_len); +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), replace_len, bytes_to_drop); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + replace_len, bytes_to_drop, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + replace_len, bytes_to_drop, UPDATE_QUOTA); + up_read(&root->rescan_lock); + + if (test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags) && + extent_info->is_new_extent && extent_info->qgroup_reserved) { + btrfs_qgroup_syno_free(root, extent_info->qgroup_reserved); + btrfs_usrquota_syno_free(BTRFS_I(inode), extent_info->qgroup_reserved); + } +#else + btrfs_update_inode_bytes(BTRFS_I(inode), replace_len, bytes_to_drop); +#endif /* MY_ABC_HERE */ if (extent_info->is_new_extent && extent_info->insertions == 0) { key.objectid = extent_info->disk_offset; @@ -2584,7 +3597,15 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, btrfs_ino(BTRFS_I(inode)), extent_info->file_offset, extent_info->qgroup_reserved, - &key); + &key +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, btrfs_ino(BTRFS_I(inode)), + extent_info->file_offset) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , inode +#endif /* MY_ABC_HERE */ + ); } else { u64 ref_offset; @@ -2593,8 +3614,51 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, extent_info->disk_len, 0); ref_offset = extent_info->file_offset - extent_info->data_offset; btrfs_init_data_ref(&ref, root->root_key.objectid, - btrfs_ino(BTRFS_I(inode)), ref_offset); + btrfs_ino(BTRFS_I(inode)), ref_offset +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, btrfs_ino(BTRFS_I(inode)), + extent_info->file_offset) +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !btrfs_root_disable_quota(root)) { + if (extent_info->clone_range || extent_info->clone_check_backref) { + struct quota_check qc = { + .bytenr = extent_info->disk_offset, + .root_objectid = root->root_key.objectid, + .ino = inode->i_ino, + .offset = (u64)-1, + .in_run_delayed = false + }; + + ret = check_root_inode_ref(trans, &qc); + } else + ret = 0; + + if (ret || !extent_info->clone_account_quota) { + ref.skip_qgroup = true; + WARN_ONCE(ret < 0, "check_root_inode_ref failed, " + "bytenr = %llu, root = %llu, ino = %lu", + extent_info->disk_offset, + root->root_key.objectid, inode->i_ino); + } else { + ref.skip_qgroup = false; + ref.inode = inode; + ref.ram_bytes = extent_info->ram_bytes; + } + } else + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ + ret = btrfs_inc_extent_ref(trans, &ref); + +#ifdef MY_ABC_HERE + if (!ret && extent_info->clone_range && + test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) + ret = btrfs_set_disk_extent_flags_no_eb(trans, extent_info->disk_offset, + extent_info->disk_len, BTRFS_EXTENT_FLAG_HAS_CLONE_RANGE, 0, 1); +#endif /* MY_ABC_HERE */ } extent_info->insertions++; @@ -2614,8 +3678,13 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, const u64 start, const u64 end, struct btrfs_replace_extent_info *extent_info, - struct btrfs_trans_handle **trans_out) + struct btrfs_trans_handle **trans_out +#ifdef MY_ABC_HERE + , struct btrfs_punch_hole_args *args +#endif /* MY_ABC_HERE */ + ) { + struct btrfs_drop_extents_args drop_args = { 0 }; struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); u64 min_size = btrfs_calc_insert_metadata_size(fs_info, 1); u64 ino_size = round_up(inode->i_size, fs_info->sectorsize); @@ -2624,9 +3693,26 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, struct btrfs_block_rsv *rsv; unsigned int rsv_count; u64 cur_offset; - u64 drop_end; u64 len = end - start; int ret = 0; +#ifdef MY_ABC_HERE + /* + * first_punch_pos records the relative file offset of first punch position. + * last_punch_pos records the possible end offset of last punch position + * for example, if we punch at file offset 32768 + * where this FILE_EXTENT_DATA points to extent offset 8192 of EXTENT_ITEM + * whose size is 1048576(1MB) + * first_punch_pos = (32768 - 8192); + * last_punch_pos = (32768 - 8192 + 1048576) + * + * partial_punch records if there's any punch that results in some part + * of EXTENT_ITEM being left, i.e. does this punch not remove the + * entire EXTENT_ITEM. + */ + u64 first_punch_pos = start; + u64 last_punch_pos = end + 1; + int partial_punch = 0; +#endif /* MY_ABC_HERE */ if (end <= start) return -EINVAL; @@ -2663,10 +3749,34 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, trans->block_rsv = rsv; cur_offset = start; + drop_args.path = path; + drop_args.end = end + 1; + drop_args.drop_cache = true; +#ifdef MY_ABC_HERE + drop_args.first_punch_pos = &first_punch_pos; + drop_args.last_punch_pos = &last_punch_pos; + drop_args.partial_punch = &partial_punch; +#endif /* MY_ABC_HERE */ while (cur_offset < end) { - ret = __btrfs_drop_extents(trans, root, BTRFS_I(inode), path, - cur_offset, end + 1, &drop_end, - 1, 0, 0, NULL); + drop_args.start = cur_offset; + ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args); + /* If we are punching a hole decrement the inode's byte count */ + if (!extent_info) +#ifdef MY_ABC_HERE + { + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), 0, + drop_args.bytes_found); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); + } +#else + btrfs_update_inode_bytes(BTRFS_I(inode), 0, + drop_args.bytes_found); +#endif /* MY_ABC_HERE */ if (ret != -ENOSPC) { /* * When cloning we want to avoid transaction aborts when @@ -2683,10 +3793,10 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, trans->block_rsv = &fs_info->trans_block_rsv; - if (!extent_info && cur_offset < drop_end && + if (!extent_info && cur_offset < drop_args.drop_end && cur_offset < ino_size) { ret = fill_holes(trans, BTRFS_I(inode), path, - cur_offset, drop_end); + cur_offset, drop_args.drop_end); if (ret) { /* * If we failed then we didn't insert our hole @@ -2697,7 +3807,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, btrfs_abort_transaction(trans, ret); break; } - } else if (!extent_info && cur_offset < drop_end) { + } else if (!extent_info && cur_offset < drop_args.drop_end) { /* * We are past the i_size here, but since we didn't * insert holes we need to clear the mapped area so we @@ -2705,7 +3815,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, * file extent is inserted here. */ ret = btrfs_inode_clear_file_extent_range(BTRFS_I(inode), - cur_offset, drop_end - cur_offset); + cur_offset, + drop_args.drop_end - cur_offset); if (ret) { /* * We couldn't clear our area, so we could @@ -2717,11 +3828,14 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, } } - if (extent_info && drop_end > extent_info->file_offset) { - u64 replace_len = drop_end - extent_info->file_offset; + if (extent_info && + drop_args.drop_end > extent_info->file_offset) { + u64 replace_len = drop_args.drop_end - + extent_info->file_offset; ret = btrfs_insert_replace_extent(trans, inode, path, - extent_info, replace_len); + extent_info, replace_len, + drop_args.bytes_found); if (ret) { btrfs_abort_transaction(trans, ret); break; @@ -2731,12 +3845,18 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, extent_info->file_offset += replace_len; } - cur_offset = drop_end; - ret = btrfs_update_inode(trans, root, inode); if (ret) break; +#ifdef MY_ABC_HERE + if (!extent_info && args && args->non_blocking) { + args->need_restart = true; + args->next_offset = drop_args.drop_end; + ret = 0; + goto out_trans; + } +#endif /* MY_ABC_HERE */ btrfs_end_transaction(trans); btrfs_btree_balance_dirty(fs_info); @@ -2752,7 +3872,9 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, BUG_ON(ret); /* shouldn't happen */ trans->block_rsv = rsv; - if (!extent_info) { + cur_offset = drop_args.drop_end; + len = end - cur_offset; + if (!extent_info && len) { ret = find_first_non_hole(inode, &cur_offset, &len); if (unlikely(ret < 0)) break; @@ -2790,25 +3912,26 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, * will not record the existence of the hole region * [existing_hole_start, lockend]. */ - if (drop_end <= end) - drop_end = end + 1; + if (drop_args.drop_end <= end) + drop_args.drop_end = end + 1; /* * Don't insert file hole extent item if it's for a range beyond eof * (because it's useless) or if it represents a 0 bytes range (when * cur_offset == drop_end). */ - if (!extent_info && cur_offset < ino_size && cur_offset < drop_end) { + if (!extent_info && cur_offset < ino_size && + cur_offset < drop_args.drop_end) { ret = fill_holes(trans, BTRFS_I(inode), path, - cur_offset, drop_end); + cur_offset, drop_args.drop_end); if (ret) { /* Same comment as above. */ btrfs_abort_transaction(trans, ret); goto out_trans; } - } else if (!extent_info && cur_offset < drop_end) { + } else if (!extent_info && cur_offset < drop_args.drop_end) { /* See the comment in the loop above for the reasoning here. */ ret = btrfs_inode_clear_file_extent_range(BTRFS_I(inode), - cur_offset, drop_end - cur_offset); + cur_offset, drop_args.drop_end - cur_offset); if (ret) { btrfs_abort_transaction(trans, ret); goto out_trans; @@ -2817,7 +3940,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, } if (extent_info) { ret = btrfs_insert_replace_extent(trans, inode, path, extent_info, - extent_info->data_len); + extent_info->data_len, + drop_args.bytes_found); if (ret) { btrfs_abort_transaction(trans, ret); goto out_trans; @@ -2836,10 +3960,19 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, out_free: btrfs_free_block_rsv(fs_info, rsv); out: +#ifdef MY_ABC_HERE + if (!ret && !extent_info && partial_punch) + btrfs_add_inode_defrag(NULL, BTRFS_I(inode), first_punch_pos, last_punch_pos, + BTRFS_INODE_DEFRAG_SYNO); +#endif /* MY_ABC_HERE */ return ret; } -static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) +static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len +#ifdef MY_ABC_HERE + , struct btrfs_punch_hole_args *args +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; @@ -2856,11 +3989,19 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) u64 ino_size; bool truncated_block = false; bool updated_inode = false; +#ifdef MY_ABC_HERE + unsigned long total_delayed_ref_updates = 0; +#endif /* MY_ABC_HERE */ ret = btrfs_wait_ordered_range(inode, offset, len); if (ret) return ret; +#ifdef MY_ABC_HERE + if (args && args->non_blocking) + btrfs_throttle(fs_info); +#endif /* MY_ABC_HERE */ + inode_lock(inode); ino_size = round_up(inode->i_size, fs_info->sectorsize); ret = find_first_non_hole(inode, &offset, &len); @@ -2960,7 +4101,11 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) } ret = btrfs_replace_file_extents(inode, path, lockstart, lockend, NULL, - &trans); + &trans +#ifdef MY_ABC_HERE + , args +#endif /* MY_ABC_HERE */ + ); btrfs_free_path(path); if (ret) goto out; @@ -2970,6 +4115,11 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) inode->i_mtime = inode->i_ctime = current_time(inode); ret = btrfs_update_inode(trans, root, inode); updated_inode = true; +#ifdef MY_ABC_HERE + /* skip delayed-refs throttle in end_transaction */ + trans->skip_throttle = true; + total_delayed_ref_updates = trans->total_delayed_ref_updates; +#endif /* MY_ABC_HERE */ btrfs_end_transaction(trans); btrfs_btree_balance_dirty(fs_info); out: @@ -3002,9 +4152,41 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) } } inode_unlock(inode); +#ifdef MY_ABC_HERE + if (!ret && updated_inode && total_delayed_ref_updates) + btrfs_throttle_delayed_refs(root, total_delayed_ref_updates); +#endif /* MY_ABC_HERE */ return ret; } +#ifdef MY_ABC_HERE +static long btrfs_non_blocking_punch_hole(struct file *file, loff_t offset, loff_t len) +{ + int ret; + struct inode *inode = file_inode(file); + loff_t cur_offset = offset; + loff_t end = offset + len; + struct btrfs_punch_hole_args args; + + memset(&args, 0, sizeof(args)); + args.non_blocking = true; + do { + args.need_restart = false; + args.next_offset = 0; + len = end - cur_offset; + ret = btrfs_punch_hole(inode, cur_offset, len, &args); + if (ret) + break; + if (args.need_restart) + cur_offset = args.next_offset; + else + cur_offset += len; + } while (cur_offset < end); + + return ret; +} +#endif /* MY_ABC_HERE */ + /* Helper structure to record which range is already reserved */ struct falloc_range { struct list_head list; @@ -3303,11 +4485,26 @@ static long btrfs_fallocate(struct file *file, int mode, /* Make sure we aren't being give some crap mode */ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + FALLOC_FL_MARK_WRITTEN | +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ FALLOC_FL_ZERO_RANGE)) return -EOPNOTSUPP; +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + if (mode & FALLOC_FL_MARK_WRITTEN) { + if ((mode & (FALLOC_FL_KEEP_SIZE | FALLOC_FL_ZERO_RANGE)) || + !(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) + return -EINVAL; + } +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ + if (mode & FALLOC_FL_PUNCH_HOLE) - return btrfs_punch_hole(inode, offset, len); + return btrfs_punch_hole(inode, offset, len +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); /* * Only trigger disk allocation, don't trigger qgroup reserve @@ -3608,10 +4805,25 @@ const struct file_operations btrfs_file_operations = { .fsync = btrfs_sync_file, .fallocate = btrfs_fallocate, .unlocked_ioctl = btrfs_ioctl, +#ifdef MY_ABC_HERE + .syno_recvfile = btrfs_recvfile, +#ifdef MY_ABC_HERE + .ecryptfs_zero_copy = btrfs_ecryptfs_zero_copy, +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ #ifdef CONFIG_COMPAT .compat_ioctl = btrfs_compat_ioctl, #endif .remap_file_range = btrfs_remap_file_range, +#ifdef MY_ABC_HERE + .non_blocking_punch_hole = btrfs_non_blocking_punch_hole, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .quota_query = btrfs_quota_query, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_space_usage = btrfs_syno_space_usage, +#endif /* MY_ABC_HERE */ }; void __cold btrfs_auto_defrag_exit(void) diff --git a/fs/btrfs/free-space-analyze.c b/fs/btrfs/free-space-analyze.c new file mode 100644 index 000000000000..41e6a1a52038 --- /dev/null +++ b/fs/btrfs/free-space-analyze.c @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2020 Synology Inc. 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 v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ +#include +#include +#include "ctree.h" +#include "space-info.h" +#include "block-group.h" +#include "free-space-cache.h" +#include "free-space-tree.h" + +#define BITS_PER_BITMAP (PAGE_SIZE * BITS_PER_BYTE) +#define PAGE_SHIFT_4K 12 + +static inline void +add_to_results(struct btrfs_ioctl_free_space_analyze_args *args, + u64 total_size, u32 count) +{ + u64 interval_size = div_u64(total_size, count); + u64 tmp_size = interval_size >> PAGE_SHIFT_4K; + int index = 0; + + if (0 == tmp_size) + return; + + if (interval_size >= args->min_continuous_size) { + args->total_continuous_size += total_size; + args->continuous_cnts += count; + } else { + args->total_frag_size += total_size; + args->frag_cnts += count; + } + + index = fls64(tmp_size) - 1; + ASSERT(index >= 0); + + if (index >= BTRFS_FREE_SPACE_ANALYZE_NR_INTERVAL) + return; + + args->interval_cnts[index] += count; +} + +int btrfs_free_space_analyze(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_free_space_analyze_args *args) +{ + int ret = -1; + int index, count, cached; + u64 total_free; + struct btrfs_space_info *sinfo = fs_info->data_sinfo; + struct btrfs_block_group *bg = NULL; + struct btrfs_path *path = NULL; + struct btrfs_free_space_info *info = NULL; + struct btrfs_key searching_key; + struct btrfs_root *free_space_root = fs_info->free_space_root; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + memset(args->interval_cnts, 0, sizeof(args->interval_cnts)); + + down_read(&sinfo->groups_sem); + for (index = 0; index < BTRFS_NR_RAID_TYPES; ++index) { + list_for_each_entry(bg, &sinfo->block_groups[index], list) { + // Get total_free and count from cache or on-disk structure + spin_lock(&bg->lock); + cached = bg->cached; + + if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA)) { + spin_unlock(&bg->lock); + cond_resched(); + continue; + } + // For total free space size + total_free = bg->length - bg->used - bg->bytes_super; + spin_unlock(&bg->lock); + + // For extent count + if (cached == BTRFS_CACHE_FINISHED) { + spin_lock(&bg->free_space_ctl->tree_lock); + total_free = bg->free_space_ctl->free_space; + if (bg->free_space_ctl->total_bitmaps == 0) + count = bg->free_space_ctl->free_extents; + spin_unlock(&bg->free_space_ctl->tree_lock); + goto update; + } + + searching_key.objectid = bg->start; + searching_key.type = BTRFS_FREE_SPACE_INFO_KEY; + searching_key.offset = bg->length; + + ret = btrfs_search_slot(NULL, free_space_root, + &searching_key, path, 0, 0); + if (ret < 0) { + up_read(&sinfo->groups_sem); + goto out; + } else if (ret > 0) { + btrfs_release_path(path); + cond_resched(); + continue; + } + + info = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_free_space_info); + + count = btrfs_free_space_extent_count(path->nodes[0], info); + + btrfs_release_path(path); +update: + cond_resched(); + // Calculate averge_size and add it to results + if (total_free < 0 || count == 0) + continue; + add_to_results(args, total_free, count); + } + } + up_read(&sinfo->groups_sem); + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +static void +add_free_space_to_result(struct btrfs_free_space *free_space, + int unit, + struct btrfs_ioctl_free_space_analyze_args *args) +{ + unsigned long i = 0; + unsigned long next_zero; + u64 bytes; + + if (free_space->bitmap) { + for_each_set_bit_from(i, free_space->bitmap, BITS_PER_BITMAP) { + next_zero = find_next_zero_bit(free_space->bitmap, + BITS_PER_BITMAP, i); + bytes = (next_zero - i) * unit; + add_to_results(args, bytes, 1); + i = next_zero; + } + } else { + add_to_results(args, free_space->bytes, 1); + } +} + +static void +scan_block_group_free_space_on_cache(struct btrfs_block_group *bg, + struct btrfs_ioctl_free_space_analyze_args *args) +{ + struct btrfs_free_space_ctl *ctl = bg->free_space_ctl; + struct btrfs_free_cluster *cluster = NULL; + struct btrfs_free_space *free_space; + struct rb_node *n; + + /* + * We should hold the tree lock until we finished scanning cluster. + * Otherwise, the cluster may have returned free space before scanned. + */ + spin_lock(&ctl->tree_lock); + for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) { + free_space = rb_entry(n, struct btrfs_free_space, offset_index); + add_free_space_to_result(free_space, ctl->unit, args); + } + + /* Get the cluster for this block_group if it exists */ + if (list_empty(&bg->cluster_list)) + goto out; + + cluster = list_entry(bg->cluster_list.next, + struct btrfs_free_cluster, + block_group_list); + if (unlikely(!cluster)) + goto out; + + spin_lock(&cluster->lock); + for (n = rb_first(&cluster->root); n; n = rb_next(n)) { + free_space = rb_entry(n, struct btrfs_free_space, offset_index); + add_free_space_to_result(free_space, bg->free_space_ctl->unit, args); + } + spin_unlock(&cluster->lock); +out: + spin_unlock(&ctl->tree_lock); +} + +static void +scan_free_space_bitmap_on_disk(struct btrfs_key *key, + struct btrfs_path *path, + u32 sectorsize, + struct btrfs_ioctl_free_space_analyze_args *args) +{ + int prev_bit = 0, bit; + u64 extent_start = 0; + u64 offset = key->objectid; + u64 end = key->objectid + key->offset; + unsigned long ptr; + unsigned long i = 0; + + ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); + + while (offset < end) { + bit = !!extent_buffer_test_bit(path->nodes[0], ptr, i); + + if (prev_bit == 0 && bit == 1) + extent_start = offset; + else if (prev_bit == 1 && bit == 0) + add_to_results(args, offset - extent_start, 1); + + ++i; + prev_bit = bit; + offset += sectorsize; + } + + if (prev_bit == 1) + add_to_results(args, end - extent_start, 1); +} + +static int +scan_block_group_free_space_on_disk(struct btrfs_fs_info *fs_info, + struct btrfs_block_group *bg, + struct btrfs_ioctl_free_space_analyze_args *args) +{ + int ret = -1; + u64 end; + struct btrfs_path *path = NULL; + struct btrfs_key searching_key; + struct btrfs_key item_key; + struct btrfs_root *free_space_root = fs_info->free_space_root; + + if (!free_space_root) + return 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + searching_key.objectid = bg->start; + searching_key.type = BTRFS_FREE_SPACE_INFO_KEY; + searching_key.offset = bg->length; + + ret = btrfs_search_slot(NULL, free_space_root, &searching_key, path, 0, 0); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = 0; + goto out; + } + + end = searching_key.objectid + searching_key.offset; + while (1) { + ret = btrfs_next_item(free_space_root, path); + if (ret < 0) + goto out; + if (ret) + break; + + btrfs_item_key_to_cpu(path->nodes[0], &item_key, path->slots[0]); + if (item_key.type == BTRFS_FREE_SPACE_INFO_KEY || + item_key.objectid >= end || + (item_key.objectid + item_key.offset) > end) + break; + + if (BTRFS_FREE_SPACE_EXTENT_KEY == item_key.type) + add_to_results(args, item_key.offset, 1); + else if (BTRFS_FREE_SPACE_BITMAP_KEY == item_key.type) + scan_free_space_bitmap_on_disk(&item_key, path, + fs_info->sectorsize, + args); + else { + btrfs_warn(fs_info, + "invalid key type %u " + "on block group offset %llu, length %llu", + item_key.type, bg->start, bg->length); + goto out; + } + } + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_free_space_analyze_full(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_free_space_analyze_args *args) +{ + int ret = -1; + int index; + struct btrfs_space_info *sinfo = fs_info->data_sinfo; + struct btrfs_block_group *bg = NULL; + + memset(args->interval_cnts, 0, sizeof(args->interval_cnts)); + + down_read(&sinfo->groups_sem); + for (index = 0; index < BTRFS_NR_RAID_TYPES; ++index) { + list_for_each_entry(bg, &sinfo->block_groups[index], list) { + int cached; + + spin_lock(&bg->lock); + cached = bg->cached; + + if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA)) { + spin_unlock(&bg->lock); + cond_resched(); + continue; + } + spin_unlock(&bg->lock); + + if (cached == BTRFS_CACHE_FINISHED) { + scan_block_group_free_space_on_cache(bg, args); + } else { + ret = scan_block_group_free_space_on_disk( + fs_info, bg, args); + if (ret < 0) { + up_read(&sinfo->groups_sem); + goto out; + } + } + cond_resched(); + } + } + up_read(&sinfo->groups_sem); + + ret = 0; +out: + return ret; +} + diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index ba280707d5ec..b4dd66a56185 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2008 Red Hat. All rights reserved. @@ -33,8 +36,6 @@ struct btrfs_trim_range { struct list_head list; }; -static int count_bitmap_extents(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *bitmap_info); static int link_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info); static void unlink_free_space(struct btrfs_free_space_ctl *ctl, @@ -43,6 +44,14 @@ static int btrfs_wait_cache_io_root(struct btrfs_root *root, struct btrfs_trans_handle *trans, struct btrfs_io_ctl *io_ctl, struct btrfs_path *path); +static int search_bitmap(struct btrfs_free_space_ctl *ctl, + struct btrfs_free_space *bitmap_info, u64 *offset, + u64 *bytes, bool for_alloc); +static void free_bitmap(struct btrfs_free_space_ctl *ctl, + struct btrfs_free_space *bitmap_info); +static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, + struct btrfs_free_space *info, u64 offset, + u64 bytes); static struct inode *__lookup_free_space_inode(struct btrfs_root *root, struct btrfs_path *path, @@ -207,6 +216,65 @@ int create_free_space_inode(struct btrfs_trans_handle *trans, ino, block_group->start); } +/* + * inode is an optional sink: if it is NULL, btrfs_remove_free_space_inode + * handles lookup, otherwise it takes ownership and iputs the inode. + * Don't reuse an inode pointer after passing it into this function. + */ +int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans, + struct inode *inode, + struct btrfs_block_group *block_group) +{ + struct btrfs_path *path; + struct btrfs_key key; + int ret = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + if (!inode) + inode = lookup_free_space_inode(block_group, path); + if (IS_ERR(inode)) { + if (PTR_ERR(inode) != -ENOENT) + ret = PTR_ERR(inode); + goto out; + } + ret = btrfs_orphan_add(trans, BTRFS_I(inode)); + if (ret) { + btrfs_add_delayed_iput(inode); + goto out; + } + clear_nlink(inode); + /* One for the block groups ref */ + spin_lock(&block_group->lock); + if (block_group->iref) { + block_group->iref = 0; + block_group->inode = NULL; + spin_unlock(&block_group->lock); + iput(inode); + } else { + spin_unlock(&block_group->lock); + } + /* One for the lookup ref */ + btrfs_add_delayed_iput(inode); + + key.objectid = BTRFS_FREE_SPACE_OBJECTID; + key.type = 0; + key.offset = block_group->start; + ret = btrfs_search_slot(trans, trans->fs_info->tree_root, &key, path, + -1, 1); + if (ret) { + if (ret > 0) + ret = 0; + goto out; + } + ret = btrfs_del_item(trans, trans->fs_info->tree_root, path); +out: + btrfs_free_path(path); + return ret; +} + int btrfs_check_trunc_cache_free_space(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *rsv) { @@ -625,44 +693,6 @@ static int io_ctl_read_bitmap(struct btrfs_io_ctl *io_ctl, return 0; } -/* - * Since we attach pinned extents after the fact we can have contiguous sections - * of free space that are split up in entries. This poses a problem with the - * tree logging stuff since it could have allocated across what appears to be 2 - * entries since we would have merged the entries when adding the pinned extents - * back to the free space cache. So run through the space cache that we just - * loaded and merge contiguous entries. This will make the log replay stuff not - * blow up and it will make for nicer allocator behavior. - */ -static void merge_space_tree(struct btrfs_free_space_ctl *ctl) -{ - struct btrfs_free_space *e, *prev = NULL; - struct rb_node *n; - -again: - spin_lock(&ctl->tree_lock); - for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) { - e = rb_entry(n, struct btrfs_free_space, offset_index); - if (!prev) - goto next; - if (e->bitmap || prev->bitmap) - goto next; - if (prev->offset + prev->bytes == e->offset) { - unlink_free_space(ctl, prev); - unlink_free_space(ctl, e); - prev->bytes += e->bytes; - kmem_cache_free(btrfs_free_space_cachep, e); - link_free_space(ctl, prev); - prev = NULL; - spin_unlock(&ctl->tree_lock); - goto again; - } -next: - prev = e; - } - spin_unlock(&ctl->tree_lock); -} - static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, struct btrfs_free_space_ctl *ctl, struct btrfs_path *path, u64 offset) @@ -748,6 +778,9 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, ret = -ENOMEM; goto free_cache; } +#ifdef MY_ABC_HERE + RB_CLEAR_NODE(&e->bytes_index_with_extent); +#endif /* MY_ABC_HERE */ ret = io_ctl_read_entry(&io_ctl, e, &type); if (ret) { @@ -755,16 +788,6 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, goto free_cache; } - /* - * Sync discard ensures that the free space cache is always - * trimmed. So when reading this in, the state should reflect - * that. We also do this for async as a stop gap for lack of - * persistence. - */ - if (btrfs_test_opt(fs_info, DISCARD_SYNC) || - btrfs_test_opt(fs_info, DISCARD_ASYNC)) - e->trim_state = BTRFS_TRIM_STATE_TRIMMED; - if (!e->bytes) { ret = -1; kmem_cache_free(btrfs_free_space_cachep, e); @@ -820,16 +843,9 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, ret = io_ctl_read_bitmap(&io_ctl, e); if (ret) goto free_cache; - e->bitmap_extents = count_bitmap_extents(ctl, e); - if (!btrfs_free_space_trimmed(e)) { - ctl->discardable_extents[BTRFS_STAT_CURR] += - e->bitmap_extents; - ctl->discardable_bytes[BTRFS_STAT_CURR] += e->bytes; - } } io_ctl_drop_pages(&io_ctl); - merge_space_tree(ctl); ret = 1; out: btrfs_discard_update_discardable(ctl->private, ctl); @@ -841,16 +857,58 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, goto out; } +static int copy_free_space_cache(struct btrfs_block_group *block_group, + struct btrfs_free_space_ctl *ctl) +{ + struct btrfs_free_space *info; + struct rb_node *n; + int ret = 0; + + while (!ret && (n = rb_first(&ctl->free_space_offset)) != NULL) { + info = rb_entry(n, struct btrfs_free_space, offset_index); + if (!info->bitmap) { + unlink_free_space(ctl, info); + ret = btrfs_add_free_space(block_group, info->offset, + info->bytes); + kmem_cache_free(btrfs_free_space_cachep, info); + } else { + u64 offset = info->offset; + u64 bytes = ctl->unit; + + while (search_bitmap(ctl, info, &offset, &bytes, + false) == 0) { + ret = btrfs_add_free_space(block_group, offset, + bytes); + if (ret) + break; + bitmap_clear_bits(ctl, info, offset, bytes); + offset = info->offset; + bytes = ctl->unit; + } + free_bitmap(ctl, info); + } + cond_resched(); + } + return ret; +} + int load_free_space_cache(struct btrfs_block_group *block_group) { struct btrfs_fs_info *fs_info = block_group->fs_info; - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; + struct btrfs_free_space_ctl tmp_ctl = {}; struct inode *inode; struct btrfs_path *path; int ret = 0; bool matched; u64 used = block_group->used; + /* + * Because we could potentially discard our loaded free space, we want + * to load everything into a temporary structure first, and then if it's + * valid copy it all into the actual free space ctl. + */ + btrfs_init_free_space_ctl(block_group, &tmp_ctl); + /* * If this block group has been marked to be cleared for one reason or * another then we can't trust the on disk cache, so just return. @@ -902,19 +960,25 @@ int load_free_space_cache(struct btrfs_block_group *block_group) } spin_unlock(&block_group->lock); - ret = __load_free_space_cache(fs_info->tree_root, inode, ctl, + ret = __load_free_space_cache(fs_info->tree_root, inode, &tmp_ctl, path, block_group->start); btrfs_free_path(path); if (ret <= 0) goto out; - spin_lock(&ctl->tree_lock); - matched = (ctl->free_space == (block_group->length - used - - block_group->bytes_super)); - spin_unlock(&ctl->tree_lock); + matched = (tmp_ctl.free_space == (block_group->length - used - + block_group->bytes_super)); - if (!matched) { - __btrfs_remove_free_space_cache(ctl); + if (matched) { + ret = copy_free_space_cache(block_group, &tmp_ctl); + /* + * ret == 1 means we successfully loaded the free space cache, + * so we need to re-set it here. + */ + if (ret == 0) + ret = 1; + } else { + __btrfs_remove_free_space_cache(&tmp_ctl); btrfs_warn(fs_info, "block group %llu has wrong amount of free space", block_group->start); @@ -1264,6 +1328,9 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, int bitmaps = 0; int ret; int must_iput = 0; +#ifdef MY_ABC_HERE + bool unlock_data_rwsem = false; +#endif /* MY_ABC_HERE */ if (!i_size_read(inode)) return -EIO; @@ -1273,10 +1340,30 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, if (ret) return ret; - if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) { +#ifdef MY_ABC_HERE + /* + * Avoid race with syno_allocation. + * Because in syno_allocation, we may release data_rwsem when + * do chunk allocation, but we are still using the block_group. + * So we add checking syno_allocator.refs to avoid the above race. + */ +#endif /* MY_ABC_HERE */ + if ((block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) +#ifdef MY_ABC_HERE + || (block_group && btrfs_test_opt(root->fs_info, SYNO_ALLOCATOR)) + || (block_group && atomic_read(&root->fs_info->syno_allocator.syno_allocator_refs)) +#endif /* MY_ABC_HERE */ + ) { down_write(&block_group->data_rwsem); +#ifdef MY_ABC_HERE + unlock_data_rwsem = true; +#endif /* MY_ABC_HERE */ spin_lock(&block_group->lock); - if (block_group->delalloc_bytes) { + if (block_group->delalloc_bytes +#ifdef MY_ABC_HERE + || atomic_read(&block_group->syno_allocator.refs) +#endif /* MY_ABC_HERE */ + ) { block_group->disk_cache_state = BTRFS_DC_WRITTEN; spin_unlock(&block_group->lock); up_write(&block_group->data_rwsem); @@ -1340,7 +1427,11 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, if (ret) goto out_nospc; - if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) + if ( +#ifdef MY_ABC_HERE + unlock_data_rwsem || +#endif /* MY_ABC_HERE */ + (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))) up_write(&block_group->data_rwsem); /* * Release the pages and unlock the extent, we will flush @@ -1375,7 +1466,11 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, cleanup_write_cache_enospc(inode, io_ctl, &cached_state); out_unlock: - if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) + if ( +#ifdef MY_ABC_HERE + unlock_data_rwsem || +#endif /* MY_ABC_HERE */ + (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))) up_write(&block_group->data_rwsem); out: @@ -1512,6 +1607,61 @@ static int tree_insert_offset(struct rb_root *root, u64 offset, return 0; } +/* + * This is a little subtle. We *only* have ->max_extent_size set if we actually + * searched through the bitmap and figured out the largest ->max_extent_size, + * otherwise it's 0. In the case that it's 0 we don't want to tell the + * allocator the wrong thing, we want to use the actual real max_extent_size + * we've found already if it's larger, or we want to use ->bytes. + * + * This matters because find_free_space() will skip entries who's ->bytes is + * less than the required bytes. So if we didn't search down this bitmap, we + * may pick some previous entry that has a smaller ->max_extent_size than we + * have. For example, assume we have two entries, one that has + * ->max_extent_size set to 4K and ->bytes set to 1M. A second entry hasn't set + * ->max_extent_size yet, has ->bytes set to 8K and it's contiguous. We will + * call into find_free_space(), and return with max_extent_size == 4K, because + * that first bitmap entry had ->max_extent_size set, but the second one did + * not. If instead we returned 8K we'd come in searching for 8K, and find the + * 8K contiguous range. + * + * Consider the other case, we have 2 8K chunks in that second entry and still + * don't have ->max_extent_size set. We'll return 16K, and the next time the + * allocator comes in it'll fully search our second bitmap, and this time it'll + * get an uptodate value of 8K as the maximum chunk size. Then we'll get the + * right allocation the next loop through. + */ +static inline u64 get_max_extent_size(const struct btrfs_free_space *entry) +{ + if (entry->bitmap && entry->max_extent_size) + return entry->max_extent_size; + return entry->bytes; +} + +/* + * We want the largest entry to be leftmost, so this is inverted from what you'd + * normally expect. + */ +static bool entry_less(struct rb_node *node, const struct rb_node *parent) +{ + const struct btrfs_free_space *entry, *exist; + + entry = rb_entry(node, struct btrfs_free_space, bytes_index); + exist = rb_entry(parent, struct btrfs_free_space, bytes_index); + return get_max_extent_size(exist) < get_max_extent_size(entry); +} + +#ifdef MY_ABC_HERE +static bool entry_less_with_extent(struct rb_node *node, const struct rb_node *parent) +{ + const struct btrfs_free_space *entry, *exist; + + entry = rb_entry(node, struct btrfs_free_space, bytes_index_with_extent); + exist = rb_entry(parent, struct btrfs_free_space, bytes_index_with_extent); + return get_max_extent_size(exist) < get_max_extent_size(entry); +} +#endif /* MY_ABC_HERE */ + /* * searches the tree for the given offset. * @@ -1640,6 +1790,11 @@ __unlink_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info) { rb_erase(&info->offset_index, &ctl->free_space_offset); + rb_erase_cached(&info->bytes_index, &ctl->free_space_bytes); +#ifdef MY_ABC_HERE + rb_erase_cached(&info->bytes_index_with_extent, &ctl->free_space_bytes_with_extent); + RB_CLEAR_NODE(&info->bytes_index_with_extent); +#endif /* MY_ABC_HERE */ ctl->free_extents--; if (!info->bitmap && !btrfs_free_space_trimmed(info)) { @@ -1666,6 +1821,12 @@ static int link_free_space(struct btrfs_free_space_ctl *ctl, if (ret) return ret; + rb_add_cached(&info->bytes_index, &ctl->free_space_bytes, entry_less); +#ifdef MY_ABC_HERE + if (!info->bitmap) + rb_add_cached(&info->bytes_index_with_extent, &ctl->free_space_bytes_with_extent, entry_less_with_extent); +#endif /* MY_ABC_HERE */ + if (!info->bitmap && !btrfs_free_space_trimmed(info)) { ctl->discardable_extents[BTRFS_STAT_CURR]++; ctl->discardable_bytes[BTRFS_STAT_CURR] += info->bytes; @@ -1714,6 +1875,28 @@ static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl) div_u64(extent_bytes, sizeof(struct btrfs_free_space)); } +static void relink_bitmap_entry(struct btrfs_free_space_ctl *ctl, + struct btrfs_free_space *info) +{ + ASSERT(info->bitmap); + + /* + * If our entry is empty it's because we're on a cluster and we don't + * want to re-link it into our ctl bytes index. + */ + if (RB_EMPTY_NODE(&info->bytes_index)) + return; + + rb_erase_cached(&info->bytes_index, &ctl->free_space_bytes); + rb_add_cached(&info->bytes_index, &ctl->free_space_bytes, entry_less); +#ifdef MY_ABC_HERE + if (!RB_EMPTY_NODE(&info->bytes_index_with_extent)) { + rb_erase_cached(&info->bytes_index_with_extent, &ctl->free_space_bytes_with_extent); + RB_CLEAR_NODE(&info->bytes_index_with_extent); + } +#endif /* MY_ABC_HERE */ +} + static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info, u64 offset, u64 bytes) @@ -1732,6 +1915,8 @@ static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, if (info->max_extent_size > ctl->unit) info->max_extent_size = 0; + relink_bitmap_entry(ctl, info); + if (start && test_bit(start - 1, info->bitmap)) extent_delta++; @@ -1767,9 +1952,16 @@ static void bitmap_set_bits(struct btrfs_free_space_ctl *ctl, bitmap_set(info->bitmap, start, count); + /* + * We set some bytes, we have no idea what the max extent size is + * anymore. + */ + info->max_extent_size = 0; info->bytes += bytes; ctl->free_space += bytes; + relink_bitmap_entry(ctl, info); + if (start && test_bit(start - 1, info->bitmap)) extent_delta--; @@ -1837,20 +2029,14 @@ static int search_bitmap(struct btrfs_free_space_ctl *ctl, *bytes = (u64)(max_bits) * ctl->unit; bitmap_info->max_extent_size = *bytes; + relink_bitmap_entry(ctl, bitmap_info); return -1; } -static inline u64 get_max_extent_size(struct btrfs_free_space *entry) -{ - if (entry->bitmap) - return entry->max_extent_size; - return entry->bytes; -} - /* Cache the size of the max extent in bytes */ static struct btrfs_free_space * find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, - unsigned long align, u64 *max_extent_size) + unsigned long align, u64 *max_extent_size, bool use_bytes_index) { struct btrfs_free_space *entry; struct rb_node *node; @@ -1860,16 +2046,38 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, if (!ctl->free_space_offset.rb_node) goto out; +again: + if (use_bytes_index) { + node = rb_first_cached(&ctl->free_space_bytes); + } else { + entry = tree_search_offset(ctl, offset_to_bitmap(ctl, *offset), + 0, 1); + if (!entry) + goto out; + node = &entry->offset_index; + } - entry = tree_search_offset(ctl, offset_to_bitmap(ctl, *offset), 0, 1); - if (!entry) - goto out; + for (; node; node = rb_next(node)) { + if (use_bytes_index) + entry = rb_entry(node, struct btrfs_free_space, + bytes_index); + else + entry = rb_entry(node, struct btrfs_free_space, + offset_index); - for (node = &entry->offset_index; node; node = rb_next(node)) { - entry = rb_entry(node, struct btrfs_free_space, offset_index); + /* + * If we are using the bytes index then all subsequent entries + * in this tree are going to be < bytes, so simply set the max + * extent size and exit the loop. + * + * If we're using the offset index then we need to keep going + * through the rest of the tree. + */ if (entry->bytes < *bytes) { *max_extent_size = max(get_max_extent_size(entry), *max_extent_size); + if (use_bytes_index) + break; continue; } @@ -1886,6 +2094,13 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, tmp = entry->offset; } + /* + * We don't break here if we're using the bytes index because we + * may have another entry that has the correct alignment that is + * the right size, so we don't want to miss that possibility. + * At worst this adds another loop through the logic, but if we + * broke here we could prematurely ENOSPC. + */ if (entry->bytes < *bytes + align_off) { *max_extent_size = max(get_max_extent_size(entry), *max_extent_size); @@ -1893,6 +2108,7 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, } if (entry->bitmap) { + struct rb_node *old_next = rb_next(node); u64 size = *bytes; ret = search_bitmap(ctl, entry, &tmp, &size, true); @@ -1905,6 +2121,15 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, max(get_max_extent_size(entry), *max_extent_size); } + + /* + * The bitmap may have gotten re-arranged in the space + * index here because the max_extent_size may have been + * updated. Start from the beginning again if this + * happened. + */ + if (use_bytes_index && old_next != rb_next(node)) + goto again; continue; } @@ -1916,29 +2141,6 @@ find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, return NULL; } -static int count_bitmap_extents(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *bitmap_info) -{ - struct btrfs_block_group *block_group = ctl->private; - u64 bytes = bitmap_info->bytes; - unsigned int rs, re; - int count = 0; - - if (!block_group || !bytes) - return count; - - bitmap_for_each_set_region(bitmap_info->bitmap, rs, re, 0, - BITS_PER_BITMAP) { - bytes -= (rs - re) * ctl->unit; - count++; - - if (!bytes) - break; - } - - return count; -} - static void add_new_bitmap(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info, u64 offset) { @@ -2077,12 +2279,6 @@ static u64 add_bytes_to_bitmap(struct btrfs_free_space_ctl *ctl, bitmap_set_bits(ctl, info, offset, bytes_to_set); - /* - * We set some bytes, we have no idea what the max extent size is - * anymore. - */ - info->max_extent_size = 0; - return bytes_to_set; } @@ -2239,6 +2435,9 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl, ret = -ENOMEM; goto out; } +#ifdef MY_ABC_HERE + RB_CLEAR_NODE(&info->bytes_index_with_extent); +#endif /* MY_ABC_HERE */ } /* allocate the bitmap */ @@ -2479,6 +2678,10 @@ int __btrfs_add_free_space(struct btrfs_fs_info *fs_info, info->bytes = bytes; info->trim_state = trim_state; RB_CLEAR_NODE(&info->offset_index); + RB_CLEAR_NODE(&info->bytes_index); +#ifdef MY_ABC_HERE + RB_CLEAR_NODE(&info->bytes_index_with_extent); +#endif /* MY_ABC_HERE */ spin_lock(&ctl->tree_lock); @@ -2525,6 +2728,15 @@ int __btrfs_add_free_space(struct btrfs_fs_info *fs_info, btrfs_discard_queue_work(&fs_info->discard_ctl, block_group); } +#ifdef MY_ABC_HERE + /* + * If the block_group is successfully allocation space, + * we should relink block_group to the corresponding position. + */ + if (!ret && block_group) + btrfs_syno_allocator_relink_block_group(block_group); +#endif /* MY_ABC_HERE */ + return ret; } @@ -2650,6 +2862,10 @@ int btrfs_remove_free_space(struct btrfs_block_group *block_group, btrfs_discard_update_discardable(block_group, ctl); spin_unlock(&ctl->tree_lock); out: +#ifdef MY_ABC_HERE + if (!ret) + btrfs_syno_allocator_relink_block_group(block_group); +#endif /* MY_ABC_HERE */ return ret; } @@ -2678,16 +2894,20 @@ void btrfs_dump_free_space(struct btrfs_block_group *block_group, "%d blocks of free space at or bigger than bytes is", count); } -void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group) +void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group, + struct btrfs_free_space_ctl *ctl) { struct btrfs_fs_info *fs_info = block_group->fs_info; - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; spin_lock_init(&ctl->tree_lock); ctl->unit = fs_info->sectorsize; ctl->start = block_group->start; ctl->private = block_group; ctl->op = &free_space_op; + ctl->free_space_bytes = RB_ROOT_CACHED; +#ifdef MY_ABC_HERE + ctl->free_space_bytes_with_extent = RB_ROOT_CACHED; +#endif /* MY_ABC_HERE */ INIT_LIST_HEAD(&ctl->trimming_ranges); mutex_init(&ctl->cache_writeout_mutex); @@ -2753,6 +2973,12 @@ static void __btrfs_return_cluster_to_free_space( } tree_insert_offset(&ctl->free_space_offset, entry->offset, &entry->offset_index, bitmap); + rb_add_cached(&entry->bytes_index, &ctl->free_space_bytes, + entry_less); +#ifdef MY_ABC_HERE + if (!entry->bitmap) + rb_add_cached(&entry->bytes_index_with_extent, &ctl->free_space_bytes_with_extent, entry_less_with_extent); +#endif /* MY_ABC_HERE */ } cluster->root = RB_ROOT; spin_unlock(&cluster->lock); @@ -2807,6 +3033,10 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group *block_group) __btrfs_remove_free_space_cache_locked(ctl); btrfs_discard_update_discardable(block_group, ctl); spin_unlock(&ctl->tree_lock); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_release_cache_block_group(block_group); + btrfs_syno_allocator_remove_block_group(block_group); +#endif /* MY_ABC_HERE */ } @@ -2854,10 +3084,12 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group, u64 align_gap = 0; u64 align_gap_len = 0; enum btrfs_trim_state align_gap_trim_state = BTRFS_TRIM_STATE_UNTRIMMED; + bool use_bytes_index = (offset == block_group->start); spin_lock(&ctl->tree_lock); entry = find_free_space(ctl, &offset, &bytes_search, - block_group->full_stripe_len, max_extent_size); + block_group->full_stripe_len, max_extent_size, + use_bytes_index); if (!entry) goto out; @@ -2896,6 +3128,14 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group, __btrfs_add_free_space(block_group->fs_info, ctl, align_gap, align_gap_len, align_gap_trim_state); +#ifdef MY_ABC_HERE + /* + * If the block_group is successfully allocation space, + * we should relink block_group to the corresponding position. + */ + if (ret) + btrfs_syno_allocator_relink_block_group(block_group); +#endif /* MY_ABC_HERE */ return ret; } @@ -2936,6 +3176,9 @@ void btrfs_return_cluster_to_free_space( __btrfs_return_cluster_to_free_space(block_group, cluster); spin_unlock(&ctl->tree_lock); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_relink_block_group(block_group); +#endif /* MY_ABC_HERE */ btrfs_discard_queue_work(&block_group->fs_info->discard_ctl, block_group); /* finally drop our ref */ @@ -2993,6 +3236,11 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group *block_group, if (cluster->block_group != block_group) goto out; +#ifdef MY_ABC_HERE + if (ctl->free_space < cluster->reserve_bytes + bytes) + goto out; +#endif /* MY_ABC_HERE */ + node = rb_first(&cluster->root); if (!node) goto out; @@ -3076,7 +3324,11 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group *block_group, struct btrfs_free_space *entry, struct btrfs_free_cluster *cluster, u64 offset, u64 bytes, - u64 cont1_bytes, u64 min_bytes) + u64 cont1_bytes, u64 min_bytes +#ifdef MY_ABC_HERE + , u64 empty_size +#endif /* MY_ABC_HERE */ + ) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; unsigned long next_zero; @@ -3091,7 +3343,11 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group *block_group, i = offset_to_bit(entry->offset, ctl->unit, max_t(u64, offset, entry->offset)); +#ifdef MY_ABC_HERE + want_bits = bytes_to_bits(empty_size, ctl->unit); +#else /* MY_ABC_HERE */ want_bits = bytes_to_bits(bytes, ctl->unit); +#endif /* MY_ABC_HERE */ min_bits = bytes_to_bits(min_bytes, ctl->unit); /* @@ -3119,6 +3375,12 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group *block_group, if (!found_bits) { entry->max_extent_size = (u64)max_bits * ctl->unit; +#ifdef MY_ABC_HERE + if (total_found < want_bits || entry->max_extent_size < cont1_bytes) + return -ENOSPC; + if (entry->max_extent_size < bytes) + return -EAGAIN; +#endif /* MY_ABC_HERE */ return -ENOSPC; } @@ -3132,13 +3394,34 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group *block_group, if (cluster->max_size < found_bits * ctl->unit) cluster->max_size = found_bits * ctl->unit; - if (total_found < want_bits || cluster->max_size < cont1_bytes) { + if (total_found < want_bits || cluster->max_size < cont1_bytes +#ifdef MY_ABC_HERE + || cluster->max_size < bytes +#endif /* MY_ABC_HERE */ + ) { i = next_zero + 1; goto again; } cluster->window_start = start * ctl->unit + entry->offset; rb_erase(&entry->offset_index, &ctl->free_space_offset); + rb_erase_cached(&entry->bytes_index, &ctl->free_space_bytes); +#ifdef MY_ABC_HERE + if (!RB_EMPTY_NODE(&entry->bytes_index_with_extent)) { + rb_erase_cached(&entry->bytes_index_with_extent, &ctl->free_space_bytes_with_extent); + RB_CLEAR_NODE(&entry->bytes_index_with_extent); + } +#endif /* MY_ABC_HERE */ + + /* + * We need to know if we're currently on the normal space index when we + * manipulate the bitmap so that we know we need to remove and re-insert + * it into the space_index tree. Clear the bytes_index node here so the + * bitmap manipulation helpers know not to mess with the space_index + * until this bitmap entry is added back into the normal cache. + */ + RB_CLEAR_NODE(&entry->bytes_index); + ret = tree_insert_offset(&cluster->root, entry->offset, &entry->offset_index, 1); ASSERT(!ret); /* -EEXIST; Logic error */ @@ -3157,7 +3440,11 @@ static noinline int setup_cluster_no_bitmap(struct btrfs_block_group *block_group, struct btrfs_free_cluster *cluster, struct list_head *bitmaps, u64 offset, u64 bytes, - u64 cont1_bytes, u64 min_bytes) + u64 cont1_bytes, u64 min_bytes +#ifdef MY_ABC_HERE + , u64 empty_size +#endif /* MY_ABC_HERE */ + ) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *first = NULL; @@ -3209,8 +3496,15 @@ setup_cluster_no_bitmap(struct btrfs_block_group *block_group, max_extent = entry->bytes; } +#ifdef MY_ABC_HERE + if (window_free < empty_size || max_extent < cont1_bytes) + return -ENOSPC; + if (max_extent < bytes) + return -EAGAIN; +#else /* MY_ABC_HERE */ if (window_free < bytes || max_extent < cont1_bytes) return -ENOSPC; +#endif /* MY_ABC_HERE */ cluster->window_start = first->offset; @@ -3229,6 +3523,13 @@ setup_cluster_no_bitmap(struct btrfs_block_group *block_group, continue; rb_erase(&entry->offset_index, &ctl->free_space_offset); + rb_erase_cached(&entry->bytes_index, &ctl->free_space_bytes); +#ifdef MY_ABC_HERE + if (!RB_EMPTY_NODE(&entry->bytes_index_with_extent)) { + rb_erase_cached(&entry->bytes_index_with_extent, &ctl->free_space_bytes_with_extent); + RB_CLEAR_NODE(&entry->bytes_index_with_extent); + } +#endif /* MY_ABC_HERE */ ret = tree_insert_offset(&cluster->root, entry->offset, &entry->offset_index, 0); total_size += entry->bytes; @@ -3248,7 +3549,11 @@ static noinline int setup_cluster_bitmap(struct btrfs_block_group *block_group, struct btrfs_free_cluster *cluster, struct list_head *bitmaps, u64 offset, u64 bytes, - u64 cont1_bytes, u64 min_bytes) + u64 cont1_bytes, u64 min_bytes +#ifdef MY_ABC_HERE + , u64 empty_size +#endif /* MY_ABC_HERE */ + ) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry = NULL; @@ -3272,10 +3577,18 @@ setup_cluster_bitmap(struct btrfs_block_group *block_group, } list_for_each_entry(entry, bitmaps, list) { +#ifdef MY_ABC_HERE + if (entry->bytes < min_bytes) +#else /* MY_ABC_HERE */ if (entry->bytes < bytes) +#endif /* MY_ABC_HERE */ continue; ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset, - bytes, cont1_bytes, min_bytes); + bytes, cont1_bytes, min_bytes +#ifdef MY_ABC_HERE + , empty_size +#endif /* MY_ABC_HERE */ + ); if (!ret) return 0; } @@ -3284,7 +3597,11 @@ setup_cluster_bitmap(struct btrfs_block_group *block_group, * The bitmaps list has all the bitmaps that record free space * starting after offset, so no more search is required. */ +#ifdef MY_ABC_HERE + return ret; +#else /* MY_ABC_HERE */ return -ENOSPC; +#endif /* MY_ABC_HERE */ } /* @@ -3297,7 +3614,11 @@ setup_cluster_bitmap(struct btrfs_block_group *block_group, */ int btrfs_find_space_cluster(struct btrfs_block_group *block_group, struct btrfs_free_cluster *cluster, - u64 offset, u64 bytes, u64 empty_size) + u64 offset, u64 bytes, u64 empty_size +#ifdef MY_ABC_HERE + , u64 reserve_bytes, bool *no_cluster_downgrade +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = block_group->fs_info; struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; @@ -3316,11 +3637,20 @@ int btrfs_find_space_cluster(struct btrfs_block_group *block_group, if (btrfs_test_opt(fs_info, SSD_SPREAD)) { cont1_bytes = min_bytes = bytes + empty_size; } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) { +#ifdef MY_ABC_HERE + cont1_bytes = min_bytes = 64 * 1024; +#else /* MY_ABC_HERE */ cont1_bytes = bytes; min_bytes = fs_info->sectorsize; +#endif /* MY_ABC_HERE */ } else { +#ifdef MY_ABC_HERE + cont1_bytes = empty_size >> 3; + min_bytes = cluster->min_bytes; // protected by refill_lock +#else /* MY_ABC_HERE */ cont1_bytes = max(bytes, (bytes + empty_size) >> 2); min_bytes = fs_info->sectorsize; +#endif /* MY_ABC_HERE */ } spin_lock(&ctl->tree_lock); @@ -3329,7 +3659,11 @@ int btrfs_find_space_cluster(struct btrfs_block_group *block_group, * If we know we don't have enough space to make a cluster don't even * bother doing all the work to try and find one. */ +#ifdef MY_ABC_HERE + if (ctl->free_space < (reserve_bytes + bytes + empty_size)) { +#else /* MY_ABC_HERE */ if (ctl->free_space < bytes) { +#endif /* MY_ABC_HERE */ spin_unlock(&ctl->tree_lock); return -ENOSPC; } @@ -3345,13 +3679,32 @@ int btrfs_find_space_cluster(struct btrfs_block_group *block_group, trace_btrfs_find_cluster(block_group, offset, bytes, empty_size, min_bytes); +#ifdef MY_ABC_HERE + ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset, + bytes, + cont1_bytes, min_bytes, empty_size); +#else /* MY_ABC_HERE */ ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset, bytes + empty_size, cont1_bytes, min_bytes); - if (ret) +#endif /* MY_ABC_HERE */ + + if (ret) { +#ifdef MY_ABC_HERE + int ret1 = ret; + ret = setup_cluster_bitmap(block_group, cluster, &bitmaps, + offset, bytes, + cont1_bytes, min_bytes, empty_size); + if (ret == -EAGAIN || (ret && ret1 == -EAGAIN)) { + *no_cluster_downgrade = true; + ret = -ENOSPC; + } +#else /* MY_ABC_HERE */ ret = setup_cluster_bitmap(block_group, cluster, &bitmaps, offset, bytes + empty_size, cont1_bytes, min_bytes); +#endif /* MY_ABC_HERE */ + } /* Clear our temporary list */ list_for_each_entry_safe(entry, tmp, &bitmaps, list) @@ -3362,6 +3715,9 @@ int btrfs_find_space_cluster(struct btrfs_block_group *block_group, list_add_tail(&cluster->block_group_list, &block_group->cluster_list); cluster->block_group = block_group; +#ifdef MY_ABC_HERE + cluster->reserve_bytes = reserve_bytes; +#endif /* MY_ABC_HERE */ } else { trace_btrfs_failed_cluster_setup(block_group); } @@ -3381,6 +3737,13 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) spin_lock_init(&cluster->refill_lock); cluster->root = RB_ROOT; cluster->max_size = 0; +#ifdef MY_ABC_HERE + cluster->reserve_bytes = 0; + cluster->empty_cluster = 512ULL * 1024 * 1024; // will be reset in fetch_cluster_info() for metadata + cluster->min_bytes = 1 * 1024 * 1024; + cluster->excluded_size = (u64)-1; + cluster->downgrade_limit = 3; +#endif /* MY_ABC_HERE */ cluster->fragmented = false; INIT_LIST_HEAD(&cluster->block_group_list); cluster->block_group = NULL; @@ -3390,7 +3753,11 @@ static int do_trimming(struct btrfs_block_group *block_group, u64 *total_trimmed, u64 start, u64 bytes, u64 reserved_start, u64 reserved_bytes, enum btrfs_trim_state reserved_trim_state, - struct btrfs_trim_range *trim_entry) + struct btrfs_trim_range *trim_entry +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { struct btrfs_space_info *space_info = block_group->space_info; struct btrfs_fs_info *fs_info = block_group->fs_info; @@ -3405,6 +3772,18 @@ static int do_trimming(struct btrfs_block_group *block_group, spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (!block_group->ro) { +#ifdef MY_ABC_HERE + if ((btrfs_space_info_used(space_info, true) + reserved_bytes) > + space_info->total_bytes) { + spin_unlock(&block_group->lock); + spin_unlock(&space_info->lock); + start = reserved_start; + bytes = reserved_bytes; + trim_state = reserved_trim_state; + ret = 0; + goto end_trim; + } +#endif /* MY_ABC_HERE */ block_group->reserved += reserved_bytes; space_info->bytes_reserved += reserved_bytes; update = 1; @@ -3412,12 +3791,19 @@ static int do_trimming(struct btrfs_block_group *block_group, spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); - ret = btrfs_discard_extent(fs_info, start, bytes, &trimmed); + ret = btrfs_discard_extent(fs_info, start, bytes, &trimmed +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (!ret) { *total_trimmed += trimmed; trim_state = BTRFS_TRIM_STATE_TRIMMED; } +#ifdef MY_ABC_HERE +end_trim: +#endif /* MY_ABC_HERE */ mutex_lock(&ctl->cache_writeout_mutex); if (reserved_start < start) __btrfs_add_free_space(fs_info, ctl, reserved_start, @@ -3449,7 +3835,11 @@ static int do_trimming(struct btrfs_block_group *block_group, */ static int trim_no_bitmap(struct btrfs_block_group *block_group, u64 *total_trimmed, u64 start, u64 end, u64 minlen, - bool async) + bool async +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { struct btrfs_discard_ctl *discard_ctl = &block_group->fs_info->discard_ctl; @@ -3466,6 +3856,9 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group, while (start < end) { struct btrfs_trim_range trim_entry; +#ifdef MY_ABC_HERE + down_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ mutex_lock(&ctl->cache_writeout_mutex); spin_lock(&ctl->tree_lock); @@ -3498,6 +3891,9 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group, if (bytes < minlen) { spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ goto next; } unlink_free_space(ctl, entry); @@ -3523,6 +3919,9 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group, if (bytes < minlen) { spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ goto next; } @@ -3535,10 +3934,18 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group, trim_entry.bytes = extent_bytes; list_add_tail(&trim_entry.list, &ctl->trimming_ranges); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_relink_block_group(block_group); + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ ret = do_trimming(block_group, total_trimmed, start, bytes, extent_start, extent_bytes, extent_trim_state, - &trim_entry); + &trim_entry +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (ret) { block_group->discard_cursor = start + bytes; break; @@ -3563,6 +3970,9 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group, block_group->discard_cursor = btrfs_block_group_end(block_group); spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ return ret; } @@ -3615,7 +4025,11 @@ static void end_trimming_bitmap(struct btrfs_free_space_ctl *ctl, */ static int trim_bitmaps(struct btrfs_block_group *block_group, u64 *total_trimmed, u64 start, u64 end, u64 minlen, - u64 maxlen, bool async) + u64 maxlen, bool async +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { struct btrfs_discard_ctl *discard_ctl = &block_group->fs_info->discard_ctl; @@ -3631,6 +4045,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, bool next_bitmap = false; struct btrfs_trim_range trim_entry; +#ifdef MY_ABC_HERE + down_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ mutex_lock(&ctl->cache_writeout_mutex); spin_lock(&ctl->tree_lock); @@ -3639,6 +4056,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, btrfs_block_group_end(block_group); spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ break; } @@ -3655,6 +4075,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, btrfs_free_space_trimmed(entry))) { spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ next_bitmap = true; goto next; } @@ -3681,6 +4104,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, entry->trim_state = BTRFS_TRIM_STATE_UNTRIMMED; spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ next_bitmap = true; goto next; } @@ -3692,6 +4118,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, if (async && *total_trimmed) { spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ goto out; } @@ -3699,6 +4128,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, if (bytes < minlen || (async && maxlen && bytes > maxlen)) { spin_unlock(&ctl->tree_lock); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ goto next; } @@ -3722,9 +4154,17 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, trim_entry.bytes = bytes; list_add_tail(&trim_entry.list, &ctl->trimming_ranges); mutex_unlock(&ctl->cache_writeout_mutex); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_relink_block_group(block_group); + up_write(&block_group->syno_allocator.space_info->syno_allocator.allocation_sem); +#endif /* MY_ABC_HERE */ ret = do_trimming(block_group, total_trimmed, start, bytes, - start, bytes, 0, &trim_entry); + start, bytes, 0, &trim_entry +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (ret) { reset_trimming_bitmap(ctl, offset); block_group->discard_cursor = @@ -3758,7 +4198,11 @@ static int trim_bitmaps(struct btrfs_block_group *block_group, } int btrfs_trim_block_group(struct btrfs_block_group *block_group, - u64 *trimmed, u64 start, u64 end, u64 minlen) + u64 *trimmed, u64 start, u64 end, u64 minlen +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; int ret; @@ -3774,11 +4218,19 @@ int btrfs_trim_block_group(struct btrfs_block_group *block_group, btrfs_freeze_block_group(block_group); spin_unlock(&block_group->lock); - ret = trim_no_bitmap(block_group, trimmed, start, end, minlen, false); + ret = trim_no_bitmap(block_group, trimmed, start, end, minlen, false +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; - ret = trim_bitmaps(block_group, trimmed, start, end, minlen, 0, false); + ret = trim_bitmaps(block_group, trimmed, start, end, minlen, 0, false +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); div64_u64_rem(end, BITS_PER_BITMAP * ctl->unit, &rem); /* If we ended in the middle of a bitmap, reset the trimming flag */ if (rem) @@ -3804,7 +4256,11 @@ int btrfs_trim_block_group_extents(struct btrfs_block_group *block_group, btrfs_freeze_block_group(block_group); spin_unlock(&block_group->lock); - ret = trim_no_bitmap(block_group, trimmed, start, end, minlen, async); + ret = trim_no_bitmap(block_group, trimmed, start, end, minlen, async +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); btrfs_unfreeze_block_group(block_group); return ret; @@ -3827,7 +4283,11 @@ int btrfs_trim_block_group_bitmaps(struct btrfs_block_group *block_group, spin_unlock(&block_group->lock); ret = trim_bitmaps(block_group, trimmed, start, end, minlen, maxlen, - async); + async +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); btrfs_unfreeze_block_group(block_group); @@ -3994,6 +4454,64 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root, "failed to write free ino cache for root %llu error %d", root->root_key.objectid, ret); } + return ret; +} +bool btrfs_free_space_cache_v1_active(struct btrfs_fs_info *fs_info) +{ + return btrfs_super_cache_generation(fs_info->super_copy); +} + +static int cleanup_free_space_cache_v1(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans) +{ + struct btrfs_block_group *block_group; + struct rb_node *node; + int ret; + + btrfs_info(fs_info, "cleaning free space cache v1"); + + node = rb_first(&fs_info->block_group_cache_tree); + while (node) { + block_group = rb_entry(node, struct btrfs_block_group, cache_node); + ret = btrfs_remove_free_space_inode(trans, NULL, block_group); + if (ret) + goto out; + node = rb_next(node); + } +out: + return ret; +} + +int btrfs_set_free_space_cache_v1_active(struct btrfs_fs_info *fs_info, bool active) +{ + struct btrfs_trans_handle *trans; + int ret; + + /* + * update_super_roots will appropriately set or unset + * super_copy->cache_generation based on SPACE_CACHE and + * BTRFS_FS_CLEANUP_SPACE_CACHE_V1. For this reason, we need a + * transaction commit whether we are enabling space cache v1 and don't + * have any other work to do, or are disabling it and removing free + * space inodes. + */ + trans = btrfs_start_transaction(fs_info->tree_root, 0); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + if (!active) { + set_bit(BTRFS_FS_CLEANUP_SPACE_CACHE_V1, &fs_info->flags); + ret = cleanup_free_space_cache_v1(fs_info, trans); + if (ret) { + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + goto out; + } + } + + ret = btrfs_commit_transaction(trans); +out: + clear_bit(BTRFS_FS_CLEANUP_SPACE_CACHE_V1, &fs_info->flags); return ret; } @@ -4155,3 +4673,274 @@ int test_check_exists(struct btrfs_block_group *cache, return ret; } #endif /* CONFIG_BTRFS_FS_RUN_SANITY_TESTS */ + +#ifdef MY_ABC_HERE +static bool block_group_cache_bytes_index_less(struct rb_node *node, const struct rb_node *parent) +{ + bool less; + const struct btrfs_block_group *entry, *exist; + + entry = rb_entry(node, struct btrfs_block_group, syno_allocator.bytes_index); + exist = rb_entry(parent, struct btrfs_block_group, syno_allocator.bytes_index); + if (!entry->syno_allocator.cache_error && exist->syno_allocator.cache_error) + less = true; + else if (entry->syno_allocator.cache_error && !exist->syno_allocator.cache_error) + less = false; + else if (!entry->syno_allocator.ro && exist->syno_allocator.ro) + less = true; + else if (entry->syno_allocator.ro && !exist->syno_allocator.ro) + less = false; + if (entry->syno_allocator.last_bytes > exist->syno_allocator.last_bytes) + less = true; + else if (entry->syno_allocator.last_bytes < exist->syno_allocator.last_bytes) + less = false; + else if (entry->start < exist->start) + less = true; + else + less = false; + return less; +} +static bool block_group_cache_max_length_index_less(struct rb_node *node, const struct rb_node *parent) +{ + bool less; + const struct btrfs_block_group *entry, *exist; + + entry = rb_entry(node, struct btrfs_block_group, syno_allocator.max_length_index); + exist = rb_entry(parent, struct btrfs_block_group, syno_allocator.max_length_index); + if (!entry->syno_allocator.cache_error && exist->syno_allocator.cache_error) + less = true; + else if (entry->syno_allocator.cache_error && !exist->syno_allocator.cache_error) + less = false; + else if (!entry->syno_allocator.ro && exist->syno_allocator.ro) + less = true; + else if (entry->syno_allocator.ro && !exist->syno_allocator.ro) + less = false; + else if (entry->syno_allocator.last_max_length > exist->syno_allocator.last_max_length) + less = true; + else if (entry->syno_allocator.last_max_length < exist->syno_allocator.last_max_length) + less = false; + else if (entry->start < exist->start) + less = true; + else + less = false; + return less; +} +static bool block_group_cache_max_length_with_extent_index_less(struct rb_node *node, const struct rb_node *parent) +{ + bool less; + const struct btrfs_block_group *entry, *exist; + + entry = rb_entry(node, struct btrfs_block_group, syno_allocator.max_length_with_extent_index); + exist = rb_entry(parent, struct btrfs_block_group, syno_allocator.max_length_with_extent_index); + if (!entry->syno_allocator.cache_error && exist->syno_allocator.cache_error) + less = true; + else if (entry->syno_allocator.cache_error && !exist->syno_allocator.cache_error) + less = false; + else if (!entry->syno_allocator.ro && exist->syno_allocator.ro) + less = true; + else if (entry->syno_allocator.ro && !exist->syno_allocator.ro) + less = false; + else if (entry->syno_allocator.last_max_length_with_extent > exist->syno_allocator.last_max_length_with_extent) + less = true; + else if (entry->syno_allocator.last_max_length_with_extent < exist->syno_allocator.last_max_length_with_extent) + less = false; + else if (entry->start < exist->start) + less = true; + else + less = false; + return less; +} +void btrfs_syno_allocator_relink_block_group(struct btrfs_block_group *cache) +{ + struct btrfs_space_info *sinfo; + struct btrfs_free_space_ctl *ctl; + u64 bytes, max_length, max_length_with_extent; + struct rb_node *node; + struct btrfs_free_space *entry; + bool force = false; + + if (!cache) { + WARN_ON_ONCE(1); + goto out; + } + + if (!cache->syno_allocator.space_info) + goto out; + + sinfo = cache->syno_allocator.space_info; + ctl = cache->free_space_ctl; + spin_lock(&sinfo->syno_allocator.lock); + /* check removed */ + if (cache->syno_allocator.removed) + goto skip; + /* check ro or cache error */ + spin_lock(&cache->lock); + if ((cache->cached == BTRFS_CACHE_ERROR) && (cache->syno_allocator.cache_error == (cache->cached == BTRFS_CACHE_ERROR))) { + spin_unlock(&cache->lock); + goto skip; + } + if (cache->ro && (cache->syno_allocator.ro == !!cache->ro)) { + spin_unlock(&cache->lock); + goto skip; + } + if (cache->syno_allocator.cache_error != (cache->cached == BTRFS_CACHE_ERROR)) { + cache->syno_allocator.cache_error = (cache->cached == BTRFS_CACHE_ERROR); + force = true; + } + if (cache->syno_allocator.ro != !!cache->ro) { + cache->syno_allocator.ro = !!cache->ro; + force = true; + } + spin_unlock(&cache->lock); + /* get free_space & max_lenght */ + spin_lock(&ctl->tree_lock); + bytes = ctl->free_space; + max_length = 0; + node = rb_first_cached(&ctl->free_space_bytes); + if (node) { + entry = rb_entry(node, struct btrfs_free_space, bytes_index); + max_length = get_max_extent_size(entry); + } + max_length_with_extent = 0; + node = rb_first_cached(&ctl->free_space_bytes_with_extent); + if (node) { + entry = rb_entry(node, struct btrfs_free_space, bytes_index_with_extent); + max_length_with_extent = get_max_extent_size(entry); + } + spin_unlock(&ctl->tree_lock); + if (force || RB_EMPTY_NODE(&cache->syno_allocator.bytes_index) || cache->syno_allocator.last_bytes != bytes) { + cache->syno_allocator.last_bytes = bytes; + if (!RB_EMPTY_NODE(&cache->syno_allocator.bytes_index)) + rb_erase_cached(&cache->syno_allocator.bytes_index, &sinfo->syno_allocator.free_space_bytes); + rb_add_cached(&cache->syno_allocator.bytes_index, &sinfo->syno_allocator.free_space_bytes, block_group_cache_bytes_index_less); + } + if (force || RB_EMPTY_NODE(&cache->syno_allocator.max_length_index) || cache->syno_allocator.last_max_length != max_length) { + cache->syno_allocator.last_max_length = max_length; + if (!RB_EMPTY_NODE(&cache->syno_allocator.max_length_index)) + rb_erase_cached(&cache->syno_allocator.max_length_index, &sinfo->syno_allocator.free_space_max_length); + rb_add_cached(&cache->syno_allocator.max_length_index, &sinfo->syno_allocator.free_space_max_length, block_group_cache_max_length_index_less); + } + if (force || RB_EMPTY_NODE(&cache->syno_allocator.max_length_with_extent_index) || cache->syno_allocator.last_max_length_with_extent != max_length_with_extent) { + cache->syno_allocator.last_max_length_with_extent = max_length_with_extent; + if (!RB_EMPTY_NODE(&cache->syno_allocator.max_length_with_extent_index)) + rb_erase_cached(&cache->syno_allocator.max_length_with_extent_index, &sinfo->syno_allocator.free_space_max_length_with_extent); + rb_add_cached(&cache->syno_allocator.max_length_with_extent_index, &sinfo->syno_allocator.free_space_max_length_with_extent, block_group_cache_max_length_with_extent_index_less); + } +skip: + spin_unlock(&sinfo->syno_allocator.lock); +out: + return; +} +void btrfs_syno_allocator_remove_block_group(struct btrfs_block_group *cache) +{ + struct btrfs_space_info *sinfo; + + if (!cache) { + WARN_ON_ONCE(1); + goto out; + } + + if (!cache->syno_allocator.space_info) + goto out; + + sinfo = cache->syno_allocator.space_info; + spin_lock(&sinfo->syno_allocator.lock); + if (!RB_EMPTY_NODE(&cache->syno_allocator.preload_index)) { + rb_erase_cached(&cache->syno_allocator.preload_index, &sinfo->syno_allocator.preload); + RB_CLEAR_NODE(&cache->syno_allocator.preload_index); + } + if (!RB_EMPTY_NODE(&cache->syno_allocator.bytes_index)) { + rb_erase_cached(&cache->syno_allocator.bytes_index, &sinfo->syno_allocator.free_space_bytes); + RB_CLEAR_NODE(&cache->syno_allocator.bytes_index); + } + if (!RB_EMPTY_NODE(&cache->syno_allocator.max_length_index)) { + rb_erase_cached(&cache->syno_allocator.max_length_index, &sinfo->syno_allocator.free_space_max_length); + RB_CLEAR_NODE(&cache->syno_allocator.max_length_index); + } + if (!RB_EMPTY_NODE(&cache->syno_allocator.max_length_with_extent_index)) { + rb_erase_cached(&cache->syno_allocator.max_length_with_extent_index, &sinfo->syno_allocator.free_space_max_length_with_extent); + RB_CLEAR_NODE(&cache->syno_allocator.max_length_with_extent_index); + } + cache->syno_allocator.preload_free_space = 0; + cache->syno_allocator.last_bytes = 0; + cache->syno_allocator.last_max_length = 0; + cache->syno_allocator.last_max_length_with_extent = 0; + cache->syno_allocator.removed = true; + spin_unlock(&sinfo->syno_allocator.lock); +out: + return; +} +static bool block_group_cache_proload_index_less(struct rb_node *node, const struct rb_node *parent) +{ + bool less; + const struct btrfs_block_group *entry, *exist; + + entry = rb_entry(node, struct btrfs_block_group, syno_allocator.preload_index); + exist = rb_entry(parent, struct btrfs_block_group, syno_allocator.preload_index); + if (!entry->syno_allocator.cache_error && exist->syno_allocator.cache_error) + less = true; + else if (entry->syno_allocator.cache_error && !exist->syno_allocator.cache_error) + less = false; + else if (!entry->syno_allocator.ro && exist->syno_allocator.ro) + less = true; + else if (entry->syno_allocator.ro && !exist->syno_allocator.ro) + less = false; + else if (entry->syno_allocator.preload_free_space > exist->syno_allocator.preload_free_space) + less = true; + else if (entry->syno_allocator.preload_free_space < exist->syno_allocator.preload_free_space) + less = false; + else if (entry->start < exist->start) + less = true; + else + less = false; + return less; +} +void btrfs_syno_allocator_preload_block_group(struct btrfs_block_group *cache, u64 bytes) +{ + struct btrfs_space_info *sinfo; + + if (!cache) { + WARN_ON_ONCE(1); + goto out; + } + + if (!cache->syno_allocator.space_info) + goto out; + + sinfo = cache->syno_allocator.space_info; + spin_lock(&sinfo->syno_allocator.lock); + cache->syno_allocator.preload_free_space = bytes; + if (!RB_EMPTY_NODE(&cache->syno_allocator.preload_index)) + rb_erase_cached(&cache->syno_allocator.preload_index, &sinfo->syno_allocator.preload); + rb_add_cached(&cache->syno_allocator.preload_index, &sinfo->syno_allocator.preload, block_group_cache_proload_index_less); + spin_unlock(&sinfo->syno_allocator.lock); +out: + return; +} +void btrfs_syno_allocator_release_cache_block_group(struct btrfs_block_group *cache) +{ + struct btrfs_space_info *sinfo; + + if (!cache) { + WARN_ON_ONCE(1); + goto out; + } + + if (!cache->syno_allocator.space_info) + goto out; + + sinfo = cache->syno_allocator.space_info; + spin_lock(&sinfo->syno_allocator.lock); + if (sinfo->syno_allocator.cache_bg != cache) { + spin_unlock(&sinfo->syno_allocator.lock); + goto out; + } + sinfo->syno_allocator.cache_bg = NULL; + sinfo->syno_allocator.cache_offset = 0; + spin_unlock(&sinfo->syno_allocator.lock); + /* finally drop our ref */ + btrfs_put_block_group(cache); +out: + return; +} +#endif /* MY_ABC_HERE */ diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h index e3d5e0ad8f8e..059e12a046a0 100644 --- a/fs/btrfs/free-space-cache.h +++ b/fs/btrfs/free-space-cache.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2009 Oracle. All rights reserved. @@ -22,6 +25,10 @@ enum btrfs_trim_state { struct btrfs_free_space { struct rb_node offset_index; + struct rb_node bytes_index; +#ifdef MY_ABC_HERE + struct rb_node bytes_index_with_extent; +#endif /* MY_ABC_HERE */ u64 offset; u64 bytes; u64 max_extent_size; @@ -45,6 +52,10 @@ static inline bool btrfs_free_space_trimming_bitmap( struct btrfs_free_space_ctl { spinlock_t tree_lock; struct rb_root free_space_offset; + struct rb_root_cached free_space_bytes; +#ifdef MY_ABC_HERE + struct rb_root_cached free_space_bytes_with_extent; +#endif /* MY_ABC_HERE */ u64 free_space; int extents_thresh; int free_extents; @@ -84,6 +95,9 @@ struct inode *lookup_free_space_inode(struct btrfs_block_group *block_group, int create_free_space_inode(struct btrfs_trans_handle *trans, struct btrfs_block_group *block_group, struct btrfs_path *path); +int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans, + struct inode *inode, + struct btrfs_block_group *block_group); int btrfs_check_trunc_cache_free_space(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *rsv); @@ -109,7 +123,8 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root, struct btrfs_path *path, struct inode *inode); -void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group); +void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group, + struct btrfs_free_space_ctl *ctl); int __btrfs_add_free_space(struct btrfs_fs_info *fs_info, struct btrfs_free_space_ctl *ctl, u64 bytenr, u64 size, @@ -131,7 +146,11 @@ void btrfs_dump_free_space(struct btrfs_block_group *block_group, u64 bytes); int btrfs_find_space_cluster(struct btrfs_block_group *block_group, struct btrfs_free_cluster *cluster, - u64 offset, u64 bytes, u64 empty_size); + u64 offset, u64 bytes, u64 empty_size +#ifdef MY_ABC_HERE + , u64 reserve_bytes, bool *no_cluster_downgrade +#endif /* MY_ABC_HERE */ + ); void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster); u64 btrfs_alloc_from_cluster(struct btrfs_block_group *block_group, struct btrfs_free_cluster *cluster, u64 bytes, @@ -140,7 +159,11 @@ void btrfs_return_cluster_to_free_space( struct btrfs_block_group *block_group, struct btrfs_free_cluster *cluster); int btrfs_trim_block_group(struct btrfs_block_group *block_group, - u64 *trimmed, u64 start, u64 end, u64 minlen); + u64 *trimmed, u64 start, u64 end, u64 minlen +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ); int btrfs_trim_block_group_extents(struct btrfs_block_group *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen, bool async); @@ -148,6 +171,8 @@ int btrfs_trim_block_group_bitmaps(struct btrfs_block_group *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen, u64 maxlen, bool async); +bool btrfs_free_space_cache_v1_active(struct btrfs_fs_info *fs_info); +int btrfs_set_free_space_cache_v1_active(struct btrfs_fs_info *fs_info, bool active); /* Support functions for running our sanity tests */ #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS int test_add_free_space_entry(struct btrfs_block_group *cache, @@ -155,4 +180,11 @@ int test_add_free_space_entry(struct btrfs_block_group *cache, int test_check_exists(struct btrfs_block_group *cache, u64 offset, u64 bytes); #endif +#ifdef MY_ABC_HERE +void btrfs_syno_allocator_relink_block_group(struct btrfs_block_group *cache); +void btrfs_syno_allocator_remove_block_group(struct btrfs_block_group *cache); +void btrfs_syno_allocator_preload_block_group(struct btrfs_block_group *cache, u64 bytes); +void btrfs_syno_allocator_release_cache_block_group(struct btrfs_block_group *cache); +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index 6cf2f7bb30c2..b5750bd2a04c 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015 Facebook. All rights reserved. @@ -16,6 +19,11 @@ static int __add_block_group_free_space(struct btrfs_trans_handle *trans, struct btrfs_block_group *block_group, struct btrfs_path *path); +#ifdef MY_ABC_HERE +static int clear_free_space_tree(struct btrfs_trans_handle *trans, + struct btrfs_root *root); +#endif /* MY_ABC_HERE */ + void set_free_space_tree_thresholds(struct btrfs_block_group *cache) { u32 bitmap_range; @@ -78,7 +86,10 @@ static int add_new_free_space_info(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ EXPORT_FOR_TESTS +#endif /* MY_ABC_HERE */ struct btrfs_free_space_info *search_free_space_info( struct btrfs_trans_handle *trans, struct btrfs_block_group *block_group, @@ -1153,12 +1164,21 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) set_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); set_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags); + +#ifdef MY_ABC_HERE + clear_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags); + atomic64_set(&fs_info->free_space_tree_processed_block_group_cnt, 0); +#endif /* MY_ABC_HERE */ + free_space_root = btrfs_create_tree(trans, BTRFS_FREE_SPACE_TREE_OBJECTID); if (IS_ERR(free_space_root)) { ret = PTR_ERR(free_space_root); goto abort; } +#ifdef MY_ABC_HERE + free_space_root->block_rsv = &fs_info->global_block_rsv; +#endif /* MY_ABC_HERE */ fs_info->free_space_root = free_space_root; node = rb_first(&fs_info->block_group_cache_tree); @@ -1168,11 +1188,49 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) ret = populate_free_space_tree(trans, block_group); if (ret) goto abort; +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags)) + break; +#endif /* MY_ABC_HERE */ node = rb_next(node); +#ifdef MY_ABC_HERE + atomic64_inc(&fs_info->free_space_tree_processed_block_group_cnt); +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags)) { + btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); + btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); + } else { + btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); + btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); + fs_info->free_space_root = NULL; + + ret = clear_free_space_tree(trans, free_space_root); + if (ret) + goto abort; + + ret = btrfs_del_root(trans, &free_space_root->root_key); + if (ret) + goto abort; + + list_del(&free_space_root->dirty_list); + + btrfs_tree_lock(free_space_root->node); + btrfs_clean_tree_block(free_space_root->node); + btrfs_tree_unlock(free_space_root->node); + btrfs_free_tree_block(trans, free_space_root, + free_space_root->node, 0, 1); + + btrfs_put_root(free_space_root); + } + clear_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags); +#else btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); +#endif /* MY_ABC_HERE */ + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); ret = btrfs_commit_transaction(trans); @@ -1184,6 +1242,9 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) return ret; abort: +#ifdef MY_ABC_HERE + clear_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags); +#endif /* MY_ABC_HERE */ clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags); btrfs_abort_transaction(trans, ret); @@ -1243,9 +1304,15 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) if (IS_ERR(trans)) return PTR_ERR(trans); +#ifdef MY_ABC_HERE + down_write(&fs_info->commit_root_sem); +#endif /* MY_ABC_HERE */ btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); fs_info->free_space_root = NULL; +#ifdef MY_ABC_HERE + up_write(&fs_info->commit_root_sem); +#endif /* MY_ABC_HERE */ ret = clear_free_space_tree(trans, free_space_root); if (ret) @@ -1433,8 +1500,6 @@ static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl, ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY); ASSERT(key.objectid < end && key.objectid + key.offset <= end); - caching_ctl->progress = key.objectid; - offset = key.objectid; while (offset < key.objectid + key.offset) { bit = free_space_test_bit(block_group, path, offset); @@ -1470,8 +1535,6 @@ static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl, goto out; } - caching_ctl->progress = (u64)-1; - ret = 0; out: return ret; @@ -1511,8 +1574,6 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl, ASSERT(key.type == BTRFS_FREE_SPACE_EXTENT_KEY); ASSERT(key.objectid < end && key.objectid + key.offset <= end); - caching_ctl->progress = key.objectid; - total_found += add_new_free_space(block_group, key.objectid, key.objectid + key.offset); if (total_found > CACHING_CTL_WAKE_UP) { @@ -1532,8 +1593,6 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl, goto out; } - caching_ctl->progress = (u64)-1; - ret = 0; out: return ret; diff --git a/fs/btrfs/free-space-tree.h b/fs/btrfs/free-space-tree.h index dc2463e4cfe3..f5bb886c21e5 100644 --- a/fs/btrfs/free-space-tree.h +++ b/fs/btrfs/free-space-tree.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015 Facebook. All rights reserved. @@ -29,11 +32,13 @@ int add_to_free_space_tree(struct btrfs_trans_handle *trans, int remove_from_free_space_tree(struct btrfs_trans_handle *trans, u64 start, u64 size); -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS +#if defined(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) || defined(MY_ABC_HERE) struct btrfs_free_space_info * search_free_space_info(struct btrfs_trans_handle *trans, struct btrfs_block_group *block_group, struct btrfs_path *path, int cow); +#endif /* CONFIG_BTRFS_FS_RUN_SANITY_TESTS || MY_ABC_HERE */ +#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS int __add_to_free_space_tree(struct btrfs_trans_handle *trans, struct btrfs_block_group *block_group, struct btrfs_path *path, u64 start, u64 size); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4f21b8fbfd4b..100bd6951baa 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -52,6 +55,22 @@ #include "block-group.h" #include "space-info.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include "syno_acl.h" +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include "syno-rbd-meta.h" +#endif /* MY_ABC_HERE */ + struct btrfs_iget_args { u64 ino; struct btrfs_root *root; @@ -140,6 +159,123 @@ static inline void btrfs_cleanup_ordered_extents(struct btrfs_inode *inode, static int btrfs_dirty_inode(struct inode *inode); +#ifdef MY_ABC_HERE +static int btrfs_syno_init_archive_bit(struct btrfs_trans_handle *trans, + struct inode *inode) +{ + __le32 archive_bit_le32 = cpu_to_le32(ALL_SYNO_ARCHIVE); + + return btrfs_xattr_syno_set_archive_bit(trans, inode, + &archive_bit_le32, sizeof(archive_bit_le32), + XATTR_CREATE, false); +} + +static int btrfs_syno_set_archive_bit(struct dentry *dentry, u32 archive_bit) +{ + struct inode *inode = d_inode(dentry); + __le32 archive_bit_le32 = cpu_to_le32(archive_bit); + + return btrfs_xattr_syno_set_archive_bit(NULL, inode, + &archive_bit_le32, sizeof(archive_bit_le32), + 0, false); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_syno_get_inode_archive_version(struct dentry *dentry, u32 *version) +{ + int ret; + struct inode *inode = d_inode(dentry); + struct syno_xattr_archive_version value; + + if (IS_ARCHIVE_VERSION_CACHED(inode)) { + *version = inode->i_archive_version; + return 0; + } + + ret = btrfs_getxattr(inode, XATTR_SYNO_ARCHIVE_VERSION, &value, sizeof(value)); + if (ret == sizeof(value)) { + inode->i_archive_version = le32_to_cpu(value.v_archive_version); + } else if (-ENODATA == ret) { + inode->i_archive_version = 0; + } else { + if (ret > 0) + ret = -EMSGSIZE; + *version = 0; + return ret; + } + + *version = inode->i_archive_version; + inode->i_flags |= S_ARCHIVE_VERSION_CACHED; + + return 0; +} + +static int btrfs_syno_set_inode_archive_version(struct dentry *dentry, u32 version) +{ + int ret; + struct inode *inode = d_inode(dentry); + struct syno_xattr_archive_version value; + + value.v_magic = cpu_to_le16(0x2552); + value.v_struct_version = cpu_to_le16(1); + value.v_archive_version = cpu_to_le32(version); + + ret = btrfs_setxattr_trans(inode, XATTR_SYNO_ARCHIVE_VERSION, + &value, sizeof(value), 0); + if (ret) + return ret; + + inode->i_archive_version = version; + inode->i_flags |= S_ARCHIVE_VERSION_CACHED; + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_syno_init_crtime(struct btrfs_trans_handle *trans, + struct inode *inode) +{ + struct btrfs_timespec crtime; + + crtime.sec = cpu_to_le64(inode->i_mtime.tv_sec); + crtime.nsec = cpu_to_le32(inode->i_mtime.tv_nsec); + return btrfs_xattr_syno_set_crtime(trans, inode, &crtime, + XATTR_CREATE); +} + +static int btrfs_syno_get_crtime(struct inode *inode, struct timespec64 *time) +{ + if (!test_and_set_bit(BTRFS_INODE_CREATE_TIME, + &BTRFS_I(inode)->runtime_flags)) { + struct btrfs_timespec crtime; + if (btrfs_getxattr(inode, XATTR_SYNO_CREATE_TIME, &crtime, + sizeof(crtime)) == sizeof(crtime)) { + spin_lock(&BTRFS_I(inode)->lock); + BTRFS_I(inode)->i_otime.tv_sec = + btrfs_stack_timespec_sec(&crtime); + BTRFS_I(inode)->i_otime.tv_nsec = + btrfs_stack_timespec_nsec(&crtime); + spin_unlock(&BTRFS_I(inode)->lock); + } + } + + *time = BTRFS_I(inode)->i_otime; + + return 0; +} + +static int btrfs_syno_set_crtime(struct inode *inode, struct timespec64 *time) +{ + struct btrfs_timespec crtime; + + crtime.sec = cpu_to_le64(time->tv_sec); + crtime.nsec = cpu_to_le32(time->tv_nsec); + return btrfs_xattr_syno_set_crtime(NULL, inode, &crtime, 0); +} +#endif /* MY_ABC_HERE */ + static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir, const struct qstr *qstr) @@ -158,7 +294,7 @@ static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, * no overlapping inline items exist in the btree */ static int insert_inline_extent(struct btrfs_trans_handle *trans, - struct btrfs_path *path, int extent_inserted, + struct btrfs_path *path, bool extent_inserted, struct btrfs_root *root, struct inode *inode, u64 start, size_t size, size_t compressed_size, int compress_type, @@ -179,8 +315,6 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, if (compressed_size && compressed_pages) cur_size = compressed_size; - inode_add_bytes(inode, size); - if (!extent_inserted) { struct btrfs_key key; size_t datasize; @@ -203,6 +337,9 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); btrfs_set_file_extent_encryption(leaf, ei, 0); btrfs_set_file_extent_other_encoding(leaf, ei, 0); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, ei, 0); +#endif /* MY_ABC_HERE */ btrfs_set_file_extent_ram_bytes(leaf, ei, size); ptr = btrfs_file_extent_inline_start(ei); @@ -256,8 +393,6 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, * could end up racing with unlink. */ BTRFS_I(inode)->disk_i_size = inode->i_size; - ret = btrfs_update_inode(trans, root, inode); - fail: return ret; } @@ -273,6 +408,7 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 start, int compress_type, struct page **compressed_pages) { + struct btrfs_drop_extents_args drop_args = { 0 }; struct btrfs_root *root = inode->root; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_trans_handle *trans; @@ -283,8 +419,6 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 start, u64 data_len = inline_len; int ret; struct btrfs_path *path; - int extent_inserted = 0; - u32 extent_item_size; if (compressed_size) data_len = compressed_size; @@ -310,16 +444,20 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 start, } trans->block_rsv = &inode->block_rsv; + drop_args.path = path; + drop_args.start = start; + drop_args.end = aligned_end; + drop_args.drop_cache = true; + drop_args.replace_extent = true; + if (compressed_size && compressed_pages) - extent_item_size = btrfs_file_extent_calc_inline_size( + drop_args.extent_item_size = btrfs_file_extent_calc_inline_size( compressed_size); else - extent_item_size = btrfs_file_extent_calc_inline_size( + drop_args.extent_item_size = btrfs_file_extent_calc_inline_size( inline_len); - ret = __btrfs_drop_extents(trans, root, inode, path, start, aligned_end, - NULL, 1, 1, extent_item_size, - &extent_inserted); + ret = btrfs_drop_extents(trans, root, inode, &drop_args); if (ret) { btrfs_abort_transaction(trans, ret); goto out; @@ -327,7 +465,7 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 start, if (isize > actual_end) inline_len = min_t(u64, isize, actual_end); - ret = insert_inline_extent(trans, path, extent_inserted, + ret = insert_inline_extent(trans, path, drop_args.extent_inserted, root, &inode->vfs_inode, start, inline_len, compressed_size, compress_type, compressed_pages); @@ -339,6 +477,26 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 start, goto out; } +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(inode, inline_len, drop_args.bytes_found); + btrfs_qgroup_syno_accounting(inode, + inline_len, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(inode, + inline_len, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(inode, inline_len, drop_args.bytes_found); +#endif /* MY_ABC_HERE */ + ret = btrfs_update_inode(trans, root, &inode->vfs_inode); + if (ret && ret != -ENOSPC) { + btrfs_abort_transaction(trans, ret); + goto out; + } else if (ret == -ENOSPC) { + ret = 1; + goto out; + } + set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags); btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); out: @@ -403,17 +561,6 @@ static noinline int add_async_extent(struct async_chunk *cow, return 0; } -/* - * Check if the inode has flags compatible with compression - */ -static inline bool inode_can_compress(struct btrfs_inode *inode) -{ - if (inode->flags & BTRFS_INODE_NODATACOW || - inode->flags & BTRFS_INODE_NODATASUM) - return false; - return true; -} - /* * Check if the inode needs to be submitted to compression, based on mount * options, defragmentation, properties or heuristics. @@ -423,7 +570,7 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start, { struct btrfs_fs_info *fs_info = inode->root->fs_info; - if (!inode_can_compress(inode)) { + if (!btrfs_inode_can_compress(inode)) { WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG), KERN_ERR "BTRFS: unexpected compression for ino %llu\n", btrfs_ino(inode)); @@ -451,7 +598,11 @@ static inline void inode_should_defrag(struct btrfs_inode *inode, /* If this is a small write inside eof, kick off a defrag */ if (num_bytes < small_write && (start > 0 || end + 1 < inode->disk_i_size)) - btrfs_add_inode_defrag(NULL, inode); + btrfs_add_inode_defrag(NULL, inode +#ifdef MY_ABC_HERE + , 0, 0, BTRFS_INODE_DEFRAG_NORMAL +#endif /* MY_ABC_HERE */ + ); } /* @@ -936,6 +1087,11 @@ static u64 get_extent_allocation_hint(struct btrfs_inode *inode, u64 start, struct extent_map *em; u64 alloc_hint = 0; +#ifdef MY_ABC_HERE + if (btrfs_test_opt(inode->root->fs_info, SSD)) + return 0; +#endif /* MY_ABC_HERE */ + read_lock(&em_tree->lock); em = search_extent_mapping(em_tree, start, num_bytes); if (em) { @@ -993,7 +1149,21 @@ static noinline int cow_file_range(struct btrfs_inode *inode, unsigned long page_ops; bool extent_reserved = false; int ret = 0; +#ifdef MY_ABC_HERE + bool dedupe = root->inline_dedupe; + bool skip_extent = false; + struct inode *dedupe_inode = NULL; + u64 match_off = 0, match_len = 0; + bool already_hit = false; + u64 dedupe_disk_offset; + u64 dedupe_disk_bytenr, dedupe_disk_num_bytes; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if ((inode->flags & BTRFS_INODE_NODEDUPE) || + test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &root->fs_info->flags)) + dedupe = false; +#endif /* MY_ABC_HERE */ if (btrfs_is_free_space_inode(inode)) { WARN_ON_ONCE(1); ret = -EINVAL; @@ -1053,31 +1223,74 @@ static noinline int cow_file_range(struct btrfs_inode *inode, while (num_bytes > 0) { cur_alloc_size = num_bytes; - ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size, - min_alloc_size, 0, alloc_hint, - &ins, 1, 1); - if (ret < 0) - goto out_unlock; - cur_alloc_size = ins.offset; - extent_reserved = true; +#ifdef MY_ABC_HERE + if (dedupe) { + skip_extent = false; + if (!already_hit) { + dedupe_inode = igrab(&inode->vfs_inode); + if (!inline_dedupe_search(dedupe_inode, start, cur_alloc_size, &dedupe_disk_bytenr, + &dedupe_disk_num_bytes, &dedupe_disk_offset, &match_off, &match_len)) { + already_hit = true; + } + iput(dedupe_inode); + } + if (already_hit) { + if (start == match_off) { + already_hit = false; + skip_extent = true; + cur_alloc_size = match_len; + } else { // flush first + cur_alloc_size = match_off - start; + } + } + } - ram_size = ins.offset; - em = create_io_em(inode, start, ins.offset, /* len */ - start, /* orig_start */ - ins.objectid, /* block_start */ - ins.offset, /* block_len */ - ins.offset, /* orig_block_len */ - ram_size, /* ram_bytes */ - BTRFS_COMPRESS_NONE, /* compress_type */ - BTRFS_ORDERED_REGULAR /* type */); + if (!skip_extent) { +#endif /* MY_ABC_HERE */ + ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size, + min_alloc_size, 0, alloc_hint, + &ins, 1, 1); + if (ret < 0) + goto out_unlock; + cur_alloc_size = ins.offset; + extent_reserved = true; + + ram_size = ins.offset; + em = create_io_em(inode, start, ins.offset, /* len */ + start, /* orig_start */ + ins.objectid, /* block_start */ + ins.offset, /* block_len */ + ins.offset, /* orig_block_len */ + ram_size, /* ram_bytes */ + BTRFS_COMPRESS_NONE, /* compress_type */ + BTRFS_ORDERED_REGULAR /* type */); +#ifdef MY_ABC_HERE + } else { + memset(&ins, 0, sizeof(ins)); // reset reserved extent + ram_size = cur_alloc_size; + em = create_io_em(inode, start, cur_alloc_size, /* len */ + start - dedupe_disk_offset, /* orig_start */ + dedupe_disk_bytenr, /* block_start */ + dedupe_disk_num_bytes, /* block_len */ + dedupe_disk_num_bytes, /* orig_block_len */ + cur_alloc_size, /* ram_bytes */ + BTRFS_COMPRESS_NONE, /* compress_type */ + BTRFS_ORDERED_DEDUPED /* type */); + } +#endif /* MY_ABC_HERE */ if (IS_ERR(em)) { ret = PTR_ERR(em); goto out_reserve; } free_extent_map(em); +#ifdef MY_ABC_HERE + ret = btrfs_add_ordered_extent(inode, start, ins.objectid, + ram_size, cur_alloc_size, skip_extent?BTRFS_ORDERED_DEDUPED:0); +#else ret = btrfs_add_ordered_extent(inode, start, ins.objectid, ram_size, cur_alloc_size, 0); +#endif /* MY_ABC_HERE */ if (ret) goto out_drop_extent_cache; @@ -1101,6 +1314,9 @@ static noinline int cow_file_range(struct btrfs_inode *inode, start + ram_size - 1, 0); } +#ifdef MY_ABC_HERE + if (!skip_extent) +#endif /* MY_ABC_HERE */ btrfs_dec_block_group_reservations(fs_info, ins.objectid); /* we're not doing compressed IO, don't unlock the first @@ -1115,12 +1331,19 @@ static noinline int cow_file_range(struct btrfs_inode *inode, extent_clear_unlock_delalloc(inode, start, start + ram_size - 1, locked_page, +#ifdef MY_ABC_HERE + EXTENT_LOCKED | EXTENT_DELALLOC | (skip_extent?EXTENT_CLEAR_DATA_RESV:0), +#else EXTENT_LOCKED | EXTENT_DELALLOC, +#endif /* MY_ABC_HERE */ page_ops); if (num_bytes < cur_alloc_size) num_bytes = 0; else num_bytes -= cur_alloc_size; +#ifdef MY_ABC_HERE + if (!skip_extent) +#endif /* MY_ABC_HERE */ alloc_hint = ins.objectid + ins.offset; start += cur_alloc_size; extent_reserved = false; @@ -1139,8 +1362,14 @@ static noinline int cow_file_range(struct btrfs_inode *inode, out_drop_extent_cache: btrfs_drop_extent_cache(inode, start, start + ram_size - 1, 0); out_reserve: +#ifdef MY_ABC_HERE + if (!skip_extent) { +#endif /* MY_ABC_HERE */ btrfs_dec_block_group_reservations(fs_info, ins.objectid); btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 1); +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ out_unlock: clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV; @@ -1598,9 +1827,15 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, goto out_check; if (extent_type == BTRFS_FILE_EXTENT_REG && !force) goto out_check; - /* If extent is RO, we must COW it */ - if (btrfs_extent_readonly(fs_info, disk_bytenr)) - goto out_check; + + /* + * The following checks can be expensive, as they need to + * take other locks and do btree or rbtree searches, so + * release the path to avoid blocking other tasks for too + * long. + */ + btrfs_release_path(path); + ret = btrfs_cross_ref_exist(root, ino, found_key.offset - extent_offset, disk_bytenr, false); @@ -1647,6 +1882,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, WARN_ON_ONCE(freespace_inode); goto out_check; } + /* If the extent's block group is RO, we must COW */ if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) goto out_check; nocow = true; @@ -1673,12 +1909,12 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, cur_offset = extent_end; if (cur_offset > end) break; + if (!path->nodes[0]) + continue; path->slots[0]++; goto next_slot; } - btrfs_release_path(path); - /* * COW range from cow_start to found_key.offset - 1. As the key * will contain the beginning of the first extent that can be @@ -1826,7 +2062,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page } else if (inode->flags & BTRFS_INODE_PREALLOC && !force_cow) { ret = run_delalloc_nocow(inode, locked_page, start, end, page_started, 0, nr_written); - } else if (!inode_can_compress(inode) || + } else if (!btrfs_inode_can_compress(inode) || !inode_need_compress(inode, start, end)) { ret = cow_file_range(inode, locked_page, start, end, page_started, nr_written, 1); @@ -1982,6 +2218,33 @@ static void btrfs_del_delalloc_inode(struct btrfs_root *root, spin_unlock(&root->delalloc_lock); } +#ifdef MY_ABC_HERE +static void btrfs_syno_add_dirty_lru_inode(struct btrfs_fs_info *fs_info, + struct inode *inode) +{ + spin_lock(&fs_info->syno_multiple_writeback_lock); + if (list_empty(&BTRFS_I(inode)->syno_dirty_lru_inode)) { + list_add_tail(&BTRFS_I(inode)->syno_dirty_lru_inode, + &fs_info->syno_dirty_lru_inodes); + set_bit(BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, + &BTRFS_I(inode)->runtime_flags); + } + spin_unlock(&fs_info->syno_multiple_writeback_lock); +} + +static void btrfs_syno_del_dirty_lru_inode(struct btrfs_fs_info *fs_info, + struct inode *inode) +{ + spin_lock(&fs_info->syno_multiple_writeback_lock); + if (!list_empty(&BTRFS_I(inode)->syno_dirty_lru_inode)) { + list_del_init(&BTRFS_I(inode)->syno_dirty_lru_inode); + clear_bit(BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, + &BTRFS_I(inode)->runtime_flags); + } + spin_unlock(&fs_info->syno_multiple_writeback_lock); +} +#endif /* MY_ABC_HERE */ + /* * Properly track delayed allocation bytes in the inode and to maintain the * list of inodes that have pending delalloc work to be done. @@ -2014,6 +2277,10 @@ void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state, percpu_counter_add_batch(&fs_info->delalloc_bytes, len, fs_info->delalloc_batch); +#ifdef MY_ABC_HERE + if (root->syno_delalloc_bytes) + percpu_counter_add_batch(root->syno_delalloc_bytes, len, fs_info->delalloc_batch); +#endif /* MY_ABC_HERE */ spin_lock(&BTRFS_I(inode)->lock); BTRFS_I(inode)->delalloc_bytes += len; if (*bits & EXTENT_DEFRAG) @@ -2021,6 +2288,10 @@ void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state, if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST, &BTRFS_I(inode)->runtime_flags)) btrfs_add_delalloc_inodes(root, inode); +#ifdef MY_ABC_HERE + if (do_list && !test_bit(BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, &BTRFS_I(inode)->runtime_flags)) + btrfs_syno_add_dirty_lru_inode(root->fs_info, inode); +#endif /* MY_ABC_HERE */ spin_unlock(&BTRFS_I(inode)->lock); } @@ -2038,7 +2309,11 @@ void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state, * accounting happens. */ void btrfs_clear_delalloc_extent(struct inode *vfs_inode, - struct extent_state *state, unsigned *bits) + struct extent_state *state, unsigned *bits +#ifdef MY_ABC_HERE + , u64 *add_bytes +#endif /* MY_ABC_HERE */ + ) { struct btrfs_inode *inode = BTRFS_I(vfs_inode); struct btrfs_fs_info *fs_info = btrfs_sb(vfs_inode->i_sb); @@ -2084,21 +2359,45 @@ void btrfs_clear_delalloc_extent(struct inode *vfs_inode, percpu_counter_add_batch(&fs_info->delalloc_bytes, -len, fs_info->delalloc_batch); +#ifdef MY_ABC_HERE + if (root->syno_delalloc_bytes) + percpu_counter_add_batch(root->syno_delalloc_bytes, -len, fs_info->delalloc_batch); +#endif /* MY_ABC_HERE */ spin_lock(&inode->lock); inode->delalloc_bytes -= len; if (do_list && inode->delalloc_bytes == 0 && test_bit(BTRFS_INODE_IN_DELALLOC_LIST, &inode->runtime_flags)) btrfs_del_delalloc_inode(root, inode); +#ifdef MY_ABC_HERE + if (do_list && inode->delalloc_bytes == 0 && + test_bit(BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, &inode->runtime_flags)) + btrfs_syno_del_dirty_lru_inode(fs_info, vfs_inode); +#endif /* MY_ABC_HERE */ spin_unlock(&inode->lock); } if ((state->state & EXTENT_DELALLOC_NEW) && (*bits & EXTENT_DELALLOC_NEW)) { +#ifdef MY_ABC_HERE + if (add_bytes) { + *add_bytes += len; + } else { + spin_lock(&inode->lock); + ASSERT(inode->new_delalloc_bytes >= len); + inode->new_delalloc_bytes -= len; + if (*bits & EXTENT_ADD_INODE_BYTES) + inode_add_bytes(&inode->vfs_inode, len); + spin_unlock(&inode->lock); + } +#else spin_lock(&inode->lock); ASSERT(inode->new_delalloc_bytes >= len); inode->new_delalloc_bytes -= len; + if (*bits & EXTENT_ADD_INODE_BYTES) + inode_add_bytes(&inode->vfs_inode, len); spin_unlock(&inode->lock); +#endif /*MY_ABC_HERE */ } } @@ -2122,9 +2421,10 @@ int btrfs_bio_fits_in_stripe(struct page *page, size_t size, struct bio *bio, struct inode *inode = page->mapping->host; struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); u64 logical = (u64)bio->bi_iter.bi_sector << 9; + struct extent_map *em; u64 length = 0; u64 map_length; - int ret; + int ret = 0; struct btrfs_io_geometry geom; if (bio_flags & EXTENT_BIO_COMPRESSED) @@ -2132,14 +2432,19 @@ int btrfs_bio_fits_in_stripe(struct page *page, size_t size, struct bio *bio, length = bio->bi_iter.bi_size; map_length = length; - ret = btrfs_get_io_geometry(fs_info, btrfs_op(bio), logical, map_length, - &geom); + em = btrfs_get_chunk_map(fs_info, logical, map_length); + if (IS_ERR(em)) + return PTR_ERR(em); + ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(bio), logical, + map_length, &geom); if (ret < 0) - return ret; + goto out; if (geom.len < length + size) - return 1; - return 0; + ret = 1; +out: + free_extent_map(em); + return ret; } /* @@ -2213,6 +2518,15 @@ blk_status_t btrfs_submit_data_bio(struct inode *inode, struct bio *bio, if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) goto mapit; /* we're doing a write, do the async checksumming */ + +#ifdef MY_ABC_HERE + if (is_fstree(root->root_key.objectid)) { + ret = btrfs_wq_submit_bio_throttle(fs_info, bio, mirror_num, bio_flags, + 0, inode, btrfs_submit_bio_start); + goto out; + } +#endif /* MY_ABC_HERE */ + ret = btrfs_wq_submit_bio(fs_info, bio, mirror_num, bio_flags, 0, inode, btrfs_submit_bio_start); goto out; @@ -2511,9 +2825,11 @@ int btrfs_writepage_cow_fixup(struct page *page, u64 start, u64 end) static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, u64 file_pos, struct btrfs_file_extent_item *stack_fi, + const bool update_inode_bytes, u64 qgroup_reserved) { struct btrfs_root *root = inode->root; + const u64 sectorsize = root->fs_info->sectorsize; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_key ins; @@ -2521,8 +2837,11 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, u64 disk_bytenr = btrfs_stack_file_extent_disk_bytenr(stack_fi); u64 num_bytes = btrfs_stack_file_extent_num_bytes(stack_fi); u64 ram_bytes = btrfs_stack_file_extent_ram_bytes(stack_fi); - int extent_inserted = 0; + struct btrfs_drop_extents_args drop_args = { 0 }; int ret; +#ifdef MY_ABC_HERE + int syno_usage; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -2537,13 +2856,16 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, * the caller is expected to unpin it and allow it to be merged * with the others. */ - ret = __btrfs_drop_extents(trans, root, inode, path, file_pos, - file_pos + num_bytes, NULL, 0, - 1, sizeof(*stack_fi), &extent_inserted); + drop_args.path = path; + drop_args.start = file_pos; + drop_args.end = file_pos + num_bytes; + drop_args.replace_extent = true; + drop_args.extent_item_size = sizeof(*stack_fi); + ret = btrfs_drop_extents(trans, root, inode, &drop_args); if (ret) goto out; - if (!extent_inserted) { + if (!drop_args.extent_inserted) { ins.objectid = btrfs_ino(inode); ins.offset = file_pos; ins.type = BTRFS_EXTENT_DATA_KEY; @@ -2561,9 +2883,64 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, sizeof(struct btrfs_file_extent_item)); btrfs_mark_buffer_dirty(leaf); + +#ifdef MY_ABC_HERE + /* + * Check usage ref before releasing path, so we won't race with rescan + * process because rescan would be blocked when it try to access the + * same item. + */ + syno_usage = btrfs_syno_usage_ref_check(root, btrfs_ino(inode), file_pos); +#endif /* MY_ABC_HERE */ + btrfs_release_path(path); - inode_add_bytes(&inode->vfs_inode, num_bytes); + /* + * If we dropped an inline extent here, we know the range where it is + * was not marked with the EXTENT_DELALLOC_NEW bit, so we update the + * number of bytes only for that range contaning the inline extent. + * The remaining of the range will be processed when clearning the + * EXTENT_DELALLOC_BIT bit through the ordered extent completion. + */ + if (file_pos == 0 && !IS_ALIGNED(drop_args.bytes_found, sectorsize)) { + u64 inline_size = round_down(drop_args.bytes_found, sectorsize); + + inline_size = drop_args.bytes_found - inline_size; +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(inode, sectorsize, inline_size); + btrfs_qgroup_syno_accounting(inode, + sectorsize, inline_size, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(inode, + sectorsize, inline_size, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(inode, sectorsize, inline_size); +#endif /* MY_ABC_HERE */ + drop_args.bytes_found -= inline_size; + num_bytes -= sectorsize; + } + +#ifdef MY_ABC_HERE + if (update_inode_bytes) { + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(inode, num_bytes, drop_args.bytes_found); + btrfs_qgroup_syno_accounting(inode, + num_bytes, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(inode, + num_bytes, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); + } + + if (qgroup_reserved && + test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &root->fs_info->flags)) { + btrfs_qgroup_syno_free(root, qgroup_reserved); + btrfs_usrquota_syno_free(inode, qgroup_reserved); + } +#else + if (update_inode_bytes) + btrfs_update_inode_bytes(inode, num_bytes, drop_args.bytes_found); +#endif /* MY_ABC_HERE */ ins.objectid = disk_bytenr; ins.offset = disk_num_bytes; @@ -2574,7 +2951,14 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, goto out; ret = btrfs_alloc_reserved_file_extent(trans, root, btrfs_ino(inode), - file_pos, qgroup_reserved, &ins); + file_pos, qgroup_reserved, &ins +#ifdef MY_ABC_HERE + , syno_usage +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , &(inode->vfs_inode) +#endif /* MY_ABC_HERE */ + ); out: btrfs_free_path(path); @@ -2601,6 +2985,7 @@ static int insert_ordered_extent_file_extent(struct btrfs_trans_handle *trans, { struct btrfs_file_extent_item stack_fi; u64 logical_len; + bool update_inode_bytes; memset(&stack_fi, 0, sizeof(stack_fi)); btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_REG); @@ -2615,10 +3000,22 @@ static int insert_ordered_extent_file_extent(struct btrfs_trans_handle *trans, btrfs_set_stack_file_extent_ram_bytes(&stack_fi, logical_len); btrfs_set_stack_file_extent_compression(&stack_fi, oe->compress_type); /* Encryption and other encoding is reserved and all 0 */ +#ifdef MY_ABC_HERE + /* syno flag is 0 */ +#endif /* MY_ABC_HERE */ + + /* + * For delalloc, when completing an ordered extent we update the inode's + * bytes when clearing the range in the inode's io tree, so pass false + * as the argument 'update_inode_bytes' to insert_reserved_file_extent(), + * except if the ordered extent was truncated. + */ + update_inode_bytes = test_bit(BTRFS_ORDERED_DIRECT, &oe->flags) || + test_bit(BTRFS_ORDERED_TRUNCATED, &oe->flags); return insert_reserved_file_extent(trans, BTRFS_I(oe->inode), oe->file_offset, &stack_fi, - oe->qgroup_rsv); + update_inode_bytes, oe->qgroup_rsv); } /* @@ -2640,10 +3037,18 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) u64 logical_len = ordered_extent->num_bytes; bool freespace_inode; bool truncated = false; - bool range_locked = false; - bool clear_new_delalloc_bytes = false; bool clear_reserved_extent = true; - unsigned int clear_bits; +#ifdef MY_ABC_HERE + unsigned int clear_bits = 0; +#else /* MY_ABC_HERE */ + unsigned int clear_bits = EXTENT_DEFRAG; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool throttle = true; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool inline_dedupe = false; +#endif /* MY_ABC_HERE */ start = ordered_extent->file_offset; end = start + ordered_extent->num_bytes - 1; @@ -2651,23 +3056,58 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags) && !test_bit(BTRFS_ORDERED_DIRECT, &ordered_extent->flags)) - clear_new_delalloc_bytes = true; + clear_bits |= EXTENT_DELALLOC_NEW; + +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) + clear_bits |= EXTENT_DEFRAG; +#endif /* MY_ABC_HERE */ freespace_inode = btrfs_is_free_space_inode(BTRFS_I(inode)); +#ifdef MY_ABC_HERE + if (freespace_inode) + throttle = false; + if (test_bit(BTRFS_ORDERED_IOERR, &ordered_extent->flags) || + test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) + throttle = false; +#ifdef MY_ABC_HERE + if (ordered_extent->high_priority) + throttle = false; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + if (test_bit(BTRFS_ORDERED_IOERR, &ordered_extent->flags)) { ret = -EIO; goto out; } +#ifdef MY_ABC_HERE + inline_dedupe = test_bit(BTRFS_ORDERED_DEDUPED, &ordered_extent->flags)?true:false; + if (inline_dedupe && ordered_extent->qgroup_rsv && + test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + btrfs_qgroup_syno_free(root, ordered_extent->qgroup_rsv); + btrfs_usrquota_syno_free(BTRFS_I(inode), ordered_extent->qgroup_rsv); + } +#endif /* MY_ABC_HERE */ btrfs_free_io_failure_record(BTRFS_I(inode), start, end); if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) { truncated = true; logical_len = ordered_extent->truncated_len; /* Truncated the entire extent, don't bother adding */ +#ifdef MY_ABC_HERE + if (!logical_len) { + if (ordered_extent->qgroup_rsv) { + btrfs_qgroup_syno_free(root, ordered_extent->qgroup_rsv); + btrfs_usrquota_syno_free(BTRFS_I(inode), ordered_extent->qgroup_rsv); + } + goto out; + } +#else if (!logical_len) goto out; +#endif /* MY_ABC_HERE */ } if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { @@ -2684,13 +3124,16 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) goto out; } trans->block_rsv = &BTRFS_I(inode)->block_rsv; +#ifdef MY_ABC_HERE + btrfs_file_extent_deduped_clear(trans, BTRFS_I(inode), ordered_extent->file_offset); +#endif /* MY_ABC_HERE */ ret = btrfs_update_inode_fallback(trans, root, inode); if (ret) /* -ENOMEM or corruption */ btrfs_abort_transaction(trans, ret); goto out; } - range_locked = true; + clear_bits |= EXTENT_LOCKED; lock_extent_bits(io_tree, start, end, &cached_state); if (freespace_inode) @@ -2715,6 +3158,9 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) logical_len); } else { BUG_ON(root == fs_info->tree_root); +#ifdef MY_ABC_HERE + if (!inline_dedupe) { +#endif /* MY_ABC_HERE */ ret = insert_ordered_extent_file_extent(trans, ordered_extent); if (!ret) { clear_reserved_extent = false; @@ -2722,6 +3168,9 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) ordered_extent->disk_bytenr, ordered_extent->disk_num_bytes); } +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ } unpin_extent_cache(&BTRFS_I(inode)->extent_tree, ordered_extent->file_offset, @@ -2731,11 +3180,47 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) goto out; } +#ifdef MY_ABC_HERE + if (!inline_dedupe) { +#endif /* MY_ABC_HERE */ ret = add_pending_csums(trans, &ordered_extent->list); if (ret) { btrfs_abort_transaction(trans, ret); goto out; } +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ + + /* + * If this is a new delalloc range, clear its new delalloc flag to + * update the inode's number of bytes. This needs to be done first + * before updating the inode item. + */ + if ((clear_bits & EXTENT_DELALLOC_NEW) && + !test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) +#ifdef MY_ABC_HERE + { + // To protect btrfs_clear_delalloc_extent()->inode_add_bytes(). + down_read(&root->rescan_lock); + clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, +#ifdef MY_ABC_HERE + EXTENT_DELALLOC_NEW | ((inline_dedupe && !ordered_extent->disk_bytenr)?0:EXTENT_ADD_INODE_BYTES), +#else + EXTENT_DELALLOC_NEW | EXTENT_ADD_INODE_BYTES, +#endif /* MY_ABC_HERE */ + 0, 0, &cached_state); + up_read(&root->rescan_lock); + } +#else + clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, +#ifdef MY_ABC_HERE + EXTENT_DELALLOC_NEW | ((inline_dedupe && !ordered_extent->disk_bytenr)?0:EXTENT_ADD_INODE_BYTES), +#else + EXTENT_DELALLOC_NEW | EXTENT_ADD_INODE_BYTES, +#endif /* MY_ABC_HERE */ + 0, 0, &cached_state); +#endif /* MY_ABC_HERE */ btrfs_inode_safe_disk_i_size_write(inode, 0); ret = btrfs_update_inode_fallback(trans, root, inode); @@ -2745,14 +3230,16 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) } ret = 0; out: - clear_bits = EXTENT_DEFRAG; - if (range_locked) - clear_bits |= EXTENT_LOCKED; - if (clear_new_delalloc_bytes) - clear_bits |= EXTENT_DELALLOC_NEW; +#ifdef MY_ABC_HERE + if (clear_bits) + clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, clear_bits, + (clear_bits & EXTENT_LOCKED) ? 1 : 0, 0, + &cached_state); +#else clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, clear_bits, (clear_bits & EXTENT_LOCKED) ? 1 : 0, 0, &cached_state); +#endif /* MY_ABC_HERE */ if (trans) btrfs_end_transaction(trans); @@ -2790,6 +3277,9 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) * has already been done. */ if ((ret || !logical_len) && +#ifdef MY_ABC_HERE + !inline_dedupe && +#endif /* MY_ABC_HERE */ clear_reserved_extent && !test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { @@ -2801,7 +3291,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) btrfs_discard_extent(fs_info, ordered_extent->disk_bytenr, ordered_extent->disk_num_bytes, - NULL); + NULL +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); btrfs_free_reserved_extent(fs_info, ordered_extent->disk_bytenr, ordered_extent->disk_num_bytes, 1); @@ -2819,6 +3313,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) /* once for the tree */ btrfs_put_ordered_extent(ordered_extent); +#ifdef MY_ABC_HERE + if (!ret && throttle) + btrfs_syno_btree_balance_dirty(fs_info, false); +#endif /* MY_ABC_HERE */ + return ret; } @@ -2844,12 +3343,31 @@ void btrfs_writepage_endio_finish_ordered(struct page *page, u64 start, end - start + 1, uptodate)) return; - if (btrfs_is_free_space_inode(inode)) + if (btrfs_is_free_space_inode(inode)) { wq = fs_info->endio_freespace_worker; - else +#ifdef MY_ABC_HERE + } else if (ordered_extent->high_priority) { + wq = fs_info->syno_high_priority_endio_workers; + set_bit(BTRFS_ORDERED_HIGH_PRIORITY, &ordered_extent->flags); + } else if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { + wq = fs_info->syno_nocow_endio_workers; +#endif /* MY_ABC_HERE */ + } else { +#ifdef MY_ABC_HERE + wq = fs_info->syno_cow_endio_workers; +#else /* MY_ABC_HERE */ wq = fs_info->endio_write_workers; +#endif /* MY_ABC_HERE */ + } btrfs_init_work(&ordered_extent->work, finish_ordered_fn, NULL, NULL); +#ifdef MY_ABC_HERE + if (!btrfs_is_free_space_inode(inode)) { + set_bit(BTRFS_ORDERED_WORK_INITIALIZED, &ordered_extent->flags); + if (ordered_extent->high_priority) + btrfs_set_work_high_priority(&ordered_extent->work); + } +#endif /* MY_ABC_HERE */ btrfs_queue_work(wq, &ordered_extent->work); } @@ -2878,12 +3396,32 @@ static int check_data_csum(struct inode *inode, struct btrfs_io_bio *io_bio, return 0; zeroit: btrfs_print_data_csum_error(BTRFS_I(inode), start, csum, csum_expected, - io_bio->mirror_num); + io_bio->mirror_num +#ifdef MY_ABC_HERE + , fs_info->correction_suppress_log +#endif /* MY_ABC_HERE */ + ); if (io_bio->device) btrfs_dev_stat_inc_and_print(io_bio->device, BTRFS_DEV_STAT_CORRUPTION_ERRS); +#ifdef MY_ABC_HERE + if (io_bio->nr_retry) { + if (io_bio->nr_retry != 1 && + !memcmp(io_bio->retry.prev_bad_csum, csum, csum_size)) + io_bio->nr_retry = BTRFS_BIO_SHOULD_ABORT_RETRY; + else { + memset(io_bio->retry.prev_bad_csum, 0, + sizeof(io_bio->retry.prev_bad_csum)); + memcpy(io_bio->retry.prev_bad_csum, csum, csum_size); + } + } else if (fs_info->correction_disable) { + kunmap_atomic(kaddr); + return 0; + } +#else /* MY_ABC_HERE */ memset(kaddr + pgoff, 1, len); flush_dcache_page(page); +#endif /* MY_ABC_HERE */ kunmap_atomic(kaddr); return -EIO; } @@ -2915,6 +3453,11 @@ int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u64 phy_offset, return 0; } +#ifdef MY_ABC_HERE + if (unlikely(bio_flagged(&io_bio->bio, BIO_CORRECTION_ERR))) + return -EIO; +#endif /* MY_ABC_HERE */ + phy_offset >>= inode->i_sb->s_blocksize_bits; return check_data_csum(inode, io_bio, phy_offset, page, offset, start, (size_t)(end - start + 1)); @@ -3045,6 +3588,10 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) struct inode *inode; u64 last_objectid = 0; int ret = 0, nr_unlink = 0; +#ifdef MY_ABC_HERE + bool early_exit = false; + bool in_progress = false; +#endif /* MY_ABC_HERE */ if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED)) return 0; @@ -3056,6 +3603,38 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) } path->reada = READA_BACK; +#ifdef MY_ABC_HERE + if (btrfs_root_dead(root)) { + root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; + if (!list_empty(&root->syno_orphan_cleanup.root)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + list_del_init(&root->syno_orphan_cleanup.root); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } + goto out; + } + if (btrfs_need_cleaner_sleep(fs_info) || + fs_info->syno_orphan_cleanup.orphan_inode_delayed) { + root->orphan_cleanup_state = 0; + goto out; + } + + spin_lock(&root->root_item_lock); + if (root->send_in_progress) { + spin_unlock(&root->root_item_lock); + if (!list_empty(&root->syno_orphan_cleanup.root)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + list_del_init(&root->syno_orphan_cleanup.root); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } + root->orphan_cleanup_state = 0; + goto out; + } + root->syno_orphan_cleanup.cleanup_in_progress++; + in_progress = true; + spin_unlock(&root->root_item_lock); +#endif /* MY_ABC_HERE */ + key.objectid = BTRFS_ORPHAN_OBJECTID; key.type = BTRFS_ORPHAN_ITEM_KEY; key.offset = (u64)-1; @@ -3090,6 +3669,17 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) /* release the path since we're done with it */ btrfs_release_path(path); +#ifdef MY_ABC_HERE + /* + * we skip processed orphan item, + * maybe others get inode refs, + * so we can't immediately remove inode with iput. + */ + if (found_key.offset == last_objectid) { + key.offset = last_objectid - 1; + continue; + } +#else /* MY_ABC_HERE */ /* * this is where we are basically btrfs_lookup, without the * crossing root thing. we store the inode number in the @@ -3102,6 +3692,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) ret = -EINVAL; goto out; } +#endif /* MY_ABC_HERE */ last_objectid = found_key.offset; @@ -3176,6 +3767,10 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) ret = btrfs_del_orphan_item(trans, root, found_key.objectid); btrfs_end_transaction(trans); +#ifdef MY_ABC_HERE + if (ret == -ENOENT) + ret = 0; +#endif /* MY_ABC_HERE */ if (ret) goto out; continue; @@ -3185,11 +3780,32 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) /* this will do delete_inode and everything for us */ iput(inode); + +#ifdef MY_ABC_HERE + if (btrfs_need_cleaner_sleep(fs_info) || + fs_info->syno_orphan_cleanup.orphan_inode_delayed) { + early_exit = true; + break; + } + if (btrfs_root_dead(root)) + break; +#endif /* MY_ABC_HERE */ } /* release the path since we're done with it */ btrfs_release_path(path); root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; +#ifdef MY_ABC_HERE + if (early_exit) { + root->orphan_cleanup_state = 0; + } else { + if (!list_empty(&root->syno_orphan_cleanup.root)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + list_del_init(&root->syno_orphan_cleanup.root); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } + } +#endif /* MY_ABC_HERE */ if (test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state)) { trans = btrfs_join_transaction(root); @@ -3204,6 +3820,21 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) if (ret) btrfs_err(fs_info, "could not do orphan cleanup %d", ret); btrfs_free_path(path); +#ifdef MY_ABC_HERE + if (in_progress) { + spin_lock(&root->root_item_lock); + root->syno_orphan_cleanup.cleanup_in_progress--; + /* + * Not much left to do, we don't know why it's unbalanced and + * can't blindly reset it to 0. + */ + if (root->syno_orphan_cleanup.cleanup_in_progress < 0) + btrfs_err(fs_info, + "cleanup_in_progress unbalanced %d root %llu", + root->syno_orphan_cleanup.cleanup_in_progress, root->root_key.objectid); + spin_unlock(&root->root_item_lock); + } +#endif /* MY_ABC_HERE */ return ret; } @@ -3355,6 +3986,15 @@ static int btrfs_read_locked_inode(struct inode *inode, BTRFS_I(inode)->index_cnt = (u64)-1; BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); +#ifdef MY_ABC_HERE + if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) + BTRFS_I(inode)->flags &= ~(BTRFS_INODE_NOCOMPRESS | BTRFS_INODE_COMPRESS); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_I(inode)->uq_rfer_used = + btrfs_inode_syno_uq_rfer_used(leaf, inode_item); +#endif /* MY_ABC_HERE */ cache_index: /* @@ -3444,6 +4084,10 @@ static int btrfs_read_locked_inode(struct inode *inode, "error loading props for ino %llu (root %llu): %d", btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret); +#ifdef MY_ABC_HERE + if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) + BTRFS_I(inode)->flags &= ~(BTRFS_INODE_NOCOMPRESS | BTRFS_INODE_COMPRESS); +#endif /* MY_ABC_HERE */ } if (path != in_path) btrfs_free_path(path); @@ -3522,6 +4166,9 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, btrfs_set_token_inode_rdev(&token, item, inode->i_rdev); btrfs_set_token_inode_flags(&token, item, BTRFS_I(inode)->flags); btrfs_set_token_inode_block_group(&token, item, 0); +#ifdef MY_ABC_HERE + btrfs_set_token_inode_syno_uq_rfer_used(&token, item, BTRFS_I(inode)->uq_rfer_used); +#endif /* MY_ABC_HERE */ } /* @@ -3561,6 +4208,31 @@ static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +void block_dump___btrfs_update_inode(struct inode *inode) +{ + struct btrfs_root *root = BTRFS_I(inode)->root; + struct dentry *dentry; + const char *name = "?"; + + dentry = d_find_alias(inode); + if (dentry) { + spin_lock(&dentry->d_lock); + name = (const char *) dentry->d_name.name; + } + printk(KERN_DEBUG + "ppid:%d(%s), pid:%d(%s), dirtied subvolume %llu inode %llu (%s) on %s\n", + task_pid_nr(current->parent), current->parent->comm, + task_pid_nr(current), current->comm, + root->root_key.objectid, btrfs_ino(BTRFS_I(inode)), + name, inode->i_sb->s_id); + if (dentry) { + spin_unlock(&dentry->d_lock); + dput(dentry); + } +} +#endif /* MY_ABC_HERE */ + /* * copy everything in the in-memory inode into the btree. */ @@ -3570,6 +4242,11 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info = root->fs_info; int ret; +#ifdef MY_ABC_HERE + if (unlikely(block_dump)) + block_dump___btrfs_update_inode(inode); +#endif /* MY_ABC_HERE */ + /* * If the inode is a free space inode, we can deadlock during commit * if we put it into the delayed code. @@ -3603,6 +4280,38 @@ noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +static int btrfs_unlink_dir_item_caseless(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_inode *dir, + const char *name, int name_len) +{ + struct btrfs_path *path; + int ret = 0; + struct btrfs_dir_item *di; + u64 dir_ino = btrfs_ino(dir); + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + path->search_caseless_key = 1; + path->leave_spinning = 1; + + di = btrfs_lookup_dir_item(trans, root, path, dir_ino, + name, name_len, -1); + if (IS_ERR_OR_NULL(di)) { + ret = di ? PTR_ERR(di) : 0; + goto err; + } + ret = btrfs_delete_one_dir_name(trans, root, path, di); +err: + btrfs_free_path(path); + return ret; + +} +#endif /* MY_ABC_HERE */ + /* * unlink helper that gets used here in inode.c and in the tree logging * recovery code. It remove a link in a directory with a given name, and @@ -3640,6 +4349,13 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, goto err; btrfs_release_path(path); +#ifdef MY_ABC_HERE + ret = btrfs_unlink_dir_item_caseless(trans, root, dir, name, name_len); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto err; + } +#endif /* MY_ABC_HERE */ /* * If we don't have dir index, we have to get it by looking up * the inode ref, since we get the inode ref, remove it directly, @@ -3827,6 +4543,13 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, } btrfs_release_path(path); +#ifdef MY_ABC_HERE + ret = btrfs_unlink_dir_item_caseless(trans, root, BTRFS_I(dir), name, name_len); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } +#endif /* MY_ABC_HERE */ /* * This is a placeholder inode for a subvolume we didn't have a * reference to at the time of the snapshot creation. In the meantime @@ -3892,6 +4615,12 @@ static noinline int may_destroy_subvol(struct btrfs_root *root) u64 dir_id; int ret; +#ifdef MY_ABC_HERE + ret = btrfs_syno_locker_may_destroy_subvol(root); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ + path = btrfs_alloc_path(); if (!path) return -ENOMEM; @@ -4101,6 +4830,24 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) free_anon_bdev(dest->anon_dev); dest->anon_dev = 0; + +#ifdef MY_ABC_HERE + mutex_lock(&fs_info->qgroup_ioctl_lock); + btrfs_remove_queued_syno_rescan(trans, dest->root_key.objectid); + mutex_unlock(&fs_info->qgroup_ioctl_lock); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + btrfs_syno_locker_disk_root_delete(trans, dest); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!list_empty(&dest->syno_orphan_cleanup.root)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + list_del_init(&dest->syno_orphan_cleanup.root); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } +#endif /* MY_ABC_HERE */ + out_end_trans: trans->block_rsv = NULL; trans->bytes_reserved = 0; @@ -4155,9 +4902,12 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) goto out; } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ err = btrfs_orphan_add(trans, BTRFS_I(inode)); if (err) goto out; +#endif /* MY_ABC_HERE */ last_unlink_trans = BTRFS_I(inode)->last_unlink_trans; @@ -4181,6 +4931,17 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) if (last_unlink_trans >= trans->transid) BTRFS_I(dir)->last_unlink_trans = last_unlink_trans; } +#ifdef MY_ABC_HERE + if (err) + goto out; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_orphan_add(trans, BTRFS_I(inode)); + if (err) + goto out; +#endif /* MY_ABC_HERE */ + out: btrfs_end_transaction(trans); btrfs_btree_balance_dirty(root->fs_info); @@ -4234,6 +4995,9 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, bool should_throttle = false; const u64 lock_start = ALIGN_DOWN(new_size, fs_info->sectorsize); struct extent_state *cached_state = NULL; +#ifdef MY_ABC_HERE + u64 ram_bytes = 0; +#endif /* MY_ABC_HERE */ BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); @@ -4374,12 +5138,27 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) && extent_start != 0) +#ifdef MY_ABC_HERE + { + down_read(&root->rescan_lock); inode_sub_bytes(inode, num_dec); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, num_dec, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, num_dec, UPDATE_QUOTA); + up_read(&root->rescan_lock); + } +#else + inode_sub_bytes(inode, num_dec); +#endif /* MY_ABC_HERE */ btrfs_mark_buffer_dirty(leaf); } else { extent_num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); +#ifdef MY_ABC_HERE + ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); +#endif /* MY_ABC_HERE */ extent_offset = found_key.offset - btrfs_file_extent_offset(leaf, fi); @@ -4389,7 +5168,19 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, found_extent = 1; if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) +#ifdef MY_ABC_HERE + { + down_read(&root->rescan_lock); inode_sub_bytes(inode, num_dec); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, num_dec, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, num_dec, UPDATE_QUOTA); + up_read(&root->rescan_lock); + } +#else + inode_sub_bytes(inode, num_dec); +#endif /* MY_ABC_HERE */ } } clear_len = num_dec; @@ -4424,7 +5215,21 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, } if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) +#ifdef MY_ABC_HERE + { + down_read(&root->rescan_lock); inode_sub_bytes(inode, item_end + 1 - new_size); + if (del_item) { + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, item_end + 1 - new_size, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, item_end + 1 - new_size, UPDATE_QUOTA); + } + up_read(&root->rescan_lock); + } +#else + inode_sub_bytes(inode, item_end + 1 - new_size); +#endif /* MY_ABC_HERE */ } delete: /* @@ -4473,7 +5278,20 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, extent_start, extent_num_bytes, 0); ref.real_root = root->root_key.objectid; btrfs_init_data_ref(&ref, btrfs_header_owner(leaf), - ino, extent_offset); + ino, extent_offset +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, found_key.objectid, found_key.offset) +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (btrfs_root_disable_quota(root)) + ref.skip_qgroup = true; + else { + ref.skip_qgroup = false; + ref.ram_bytes = ram_bytes; + ref.inode = inode; + } +#endif /* MY_ABC_HERE */ ret = btrfs_free_extent(trans, &ref); if (ret) { btrfs_abort_transaction(trans, ret); @@ -4704,6 +5522,7 @@ static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode, { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_trans_handle *trans; + struct btrfs_drop_extents_args drop_args = { 0 }; int ret; /* @@ -4726,7 +5545,11 @@ static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode, if (IS_ERR(trans)) return PTR_ERR(trans); - ret = btrfs_drop_extents(trans, root, inode, offset, offset + len, 1); + drop_args.start = offset; + drop_args.end = offset + len; + drop_args.drop_cache = true; + + ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args); if (ret) { btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans); @@ -4735,10 +5558,22 @@ static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode, ret = btrfs_insert_file_extent(trans, root, btrfs_ino(BTRFS_I(inode)), offset, 0, 0, len, 0, len, 0, 0, 0); - if (ret) + if (ret) { btrfs_abort_transaction(trans, ret); - else + } else { +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), 0, drop_args.bytes_found); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(BTRFS_I(inode), 0, drop_args.bytes_found); +#endif /* MY_ABC_HERE */ btrfs_update_inode(trans, root, inode); + } btrfs_end_transaction(trans); return ret; } @@ -4909,14 +5744,25 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr) * zero. Make sure any new writes to the file get on disk * on close. */ - if (newsize == 0) + if (newsize == 0 +#ifdef MY_ABC_HERE + && oldsize != newsize +#endif /* MY_ABC_HERE */ + ) set_bit(BTRFS_INODE_FLUSH_ON_CLOSE, &BTRFS_I(inode)->runtime_flags); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ truncate_setsize(inode, newsize); +#endif /* MY_ABC_HERE */ inode_dio_wait(inode); +#ifdef MY_ABC_HERE + truncate_setsize(inode, newsize); +#endif /* MY_ABC_HERE */ + ret = btrfs_truncate(inode, newsize == oldsize); if (ret && inode->i_nlink) { int err; @@ -4946,6 +5792,11 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) if (btrfs_root_readonly(root)) return -EROFS; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) + err = 0; // skip permission check + else +#endif /* MY_ABC_HERE */ err = setattr_prepare(dentry, attr); if (err) return err; @@ -4956,6 +5807,22 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) return err; } +#ifdef MY_ABC_HERE + if ((S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) && + (attr->ia_valid & ATTR_UID) && + !uid_eq(attr->ia_uid, inode->i_uid)) { + if (test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &root->fs_info->flags)) { + err = btrfs_usrquota_transfer(inode, attr->ia_uid); + if (err) + return err; + } else if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &root->fs_info->flags)) { + err = btrfs_usrquota_v1_transfer(inode, attr->ia_uid); + if (err) + return err; + } + } +#endif /* MY_ABC_HERE */ + if (attr->ia_valid) { setattr_copy(inode, attr); inode_inc_iversion(inode); @@ -4985,10 +5852,20 @@ static void evict_inode_truncate_pages(struct inode *inode) struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_map_tree *map_tree = &BTRFS_I(inode)->extent_tree; struct rb_node *node; +#ifdef MY_ABC_HERE + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; +#endif /* MY_ABC_HERE */ ASSERT(inode->i_state & I_FREEING); truncate_inode_pages_final(&inode->i_data); +#ifdef MY_ABC_HERE + spin_lock(&fs_info->extent_map_inode_list_lock); + WARN_ON(atomic_read(&BTRFS_I(inode)->free_extent_map_counts) != 0); + list_del_init(&BTRFS_I(inode)->free_extent_map_inode); + spin_unlock(&fs_info->extent_map_inode_list_lock); +#endif /* MY_ABC_HERE */ + write_lock(&map_tree->lock); while (!RB_EMPTY_ROOT(&map_tree->map.rb_root)) { struct extent_map *em; @@ -5048,9 +5925,20 @@ static void evict_inode_truncate_pages(struct inode *inode) * * Note, end is the bytenr of last byte, so we need + 1 here. */ +#ifdef MY_ABC_HERE + /* + * EXTENT_QGROUP_RESERVED bit isn't guaranteed to be cleared in + * try_release_extent_state(). We need to clear them to prevent + * infinite loop. + */ + if (state_flags & (EXTENT_DELALLOC | EXTENT_QGROUP_RESERVED)) + btrfs_qgroup_free_data(BTRFS_I(inode), NULL, start, + end - start + 1); +#else if (state_flags & EXTENT_DELALLOC) btrfs_qgroup_free_data(BTRFS_I(inode), NULL, start, end - start + 1); +#endif /* MY_ABC_HERE */ clear_extent_bit(io_tree, start, end, EXTENT_LOCKED | EXTENT_DELALLOC | @@ -5121,6 +6009,9 @@ void btrfs_evict_inode(struct inode *inode) struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_block_rsv *rsv; int ret; +#ifdef MY_ABC_HERE + u32 truncate_retry_count = 0; +#endif /* MY_ABC_HERE */ trace_btrfs_inode_evict(inode); @@ -5178,6 +6069,10 @@ void btrfs_evict_inode(struct inode *inode) goto free_rsv; else if (!ret) break; +#ifdef MY_ABC_HERE + if (++truncate_retry_count > 8 && fs_info->syno_orphan_cleanup.orphan_inode_delayed) + goto free_rsv; +#endif /* MY_ABC_HERE */ } /* @@ -5209,10 +6104,37 @@ void btrfs_evict_inode(struct inode *inode) * the tree and we'll retry on the next mount. Again, we might also want * to retry these periodically in the future. */ +#ifdef MY_ABC_HERE + btrfs_syno_del_dirty_lru_inode(root->fs_info, inode); +#endif /* MY_ABC_HERE */ btrfs_remove_delayed_node(BTRFS_I(inode)); clear_inode(inode); } +#ifdef MY_ABC_HERE +static int btrfs_replace_caseless_dentry_name( + const struct extent_buffer *leaf, + struct btrfs_dir_item *di, + struct dentry *dentry) +{ + char real_name[BTRFS_NAME_LEN + 1] = {0}; + int real_name_len = btrfs_dir_name_len(leaf, di); + + if (unlikely(real_name_len > BTRFS_NAME_LEN)) + return -ENAMETOOLONG; + + read_extent_buffer(leaf, (void *) real_name, + (unsigned long)(di + 1), real_name_len); + /* + * In caseless lookup, this dentry just been created and not + * register into hash table list. So it cannot be reference + * by other thread, and we don't need to hold any lock or deal + * with rcu lookup mode. + */ + return dentry_replace_name(dentry, real_name, real_name_len); +} +#endif /* MY_ABC_HERE */ + /* * Return the key found in the dir entry in the location pointer, fill @type * with BTRFS_FT_*, and return 0. @@ -5221,7 +6143,11 @@ void btrfs_evict_inode(struct inode *inode) * If found a corrupted location in dir entry, returns -EUCLEAN. */ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, - struct btrfs_key *location, u8 *type) + struct btrfs_key *location, u8 *type +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; @@ -5234,6 +6160,14 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, if (!path) return -ENOMEM; +#ifdef MY_ABC_HERE + if (caseless) { + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + path->search_caseless_key = 1; + path->caseless_lookup = 1; + } +#endif /* MY_ABC_HERE */ + di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)), name, namelen, 0); if (IS_ERR_OR_NULL(di)) { @@ -5241,6 +6175,14 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, goto out; } +#ifdef MY_ABC_HERE + if (caseless) { + ret = btrfs_replace_caseless_dentry_name(path->nodes[0], di, dentry); + if (ret) + goto out; + } +#endif /* MY_ABC_HERE */ + btrfs_dir_item_key_to_cpu(path->nodes[0], di, location); if (location->type != BTRFS_INODE_ITEM_KEY && location->type != BTRFS_ROOT_ITEM_KEY) { @@ -5430,6 +6372,9 @@ struct inode *btrfs_iget_path(struct super_block *s, u64 ino, struct btrfs_root *root, struct btrfs_path *path) { struct inode *inode; +#ifdef MY_ABC_HERE + __le32 archive_bit; +#endif /* MY_ABC_HERE */ inode = btrfs_iget_locked(s, ino, root); if (!inode) @@ -5442,6 +6387,27 @@ struct inode *btrfs_iget_path(struct super_block *s, u64 ino, if (!ret) { inode_tree_add(inode); unlock_new_inode(inode); +#ifdef MY_ABC_HERE + if (btrfs_is_free_space_inode(BTRFS_I(inode))) { + /* + * For xfstests btrfs/131. + * To avoid a WARNING calltrace of getting + * a read lock by btrfs_getxattr when holding + * the write lock by COW of free space inode. + */ + inode->i_archive_bit = 0; + } else { + ret = btrfs_getxattr(inode, XATTR_SYNO_ARCHIVE_BIT, + &archive_bit, sizeof(archive_bit)); + if (ret == sizeof(archive_bit)) + inode->i_archive_bit = le32_to_cpu(archive_bit); + else + inode->i_archive_bit = 0; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_syno_locker_disk_inode_read(inode); +#endif /* MY_ABC_HERE*/ } else { iget_failed(inode); /* @@ -5463,6 +6429,123 @@ struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root return btrfs_iget_path(s, ino, root, NULL); } +#ifdef MY_ABC_HERE +/* check whether file could be access by path or not */ +static int check_file_name_exist(struct btrfs_root *root, u64 inum) +{ + int ret = 0; + struct btrfs_key key; + struct btrfs_path *path = NULL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + ret = btrfs_find_item(root, path, inum, 0, BTRFS_INODE_REF_KEY, &key); + if (1 == ret) + ret = -ESTALE; + btrfs_free_path(path); + + return ret; +} + +static int check_is_regular_file(struct btrfs_root *root, struct inode *inode) +{ + int ret = -ESTALE; + + inode_lock(inode); + + ret = check_file_name_exist(root, inode->i_ino); + if (ret) { + goto out; + } + + if (S_ISDIR(inode->i_mode)) { + ret = -EISDIR; + goto out; + } + if (!S_ISREG(inode->i_mode) || inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { + ret = -ESTALE; + goto out; + } + + ret = 0; +out: + inode_unlock(inode); + return ret; +} + +/** + * Get inode by root id and its object id. + * This object must be a regular file and is not freeing or just newly created. + */ +struct inode *btrfs_get_regular_file_inode(struct super_block *sb, u64 root_objectid, + u64 objectid) +{ + int ret; + struct btrfs_root *root; + struct inode *inode; + + if (!sb) + return ERR_PTR(-EINVAL); + + if (objectid < BTRFS_FIRST_FREE_OBJECTID || objectid > BTRFS_LAST_FREE_OBJECTID) + return ERR_PTR(-ESTALE); + + root = btrfs_get_fs_root(btrfs_sb(sb), root_objectid, true); + if (IS_ERR(root)) { + return (struct inode *)root; + } + + inode = btrfs_iget(sb, objectid, root); + if (IS_ERR(inode)) { + if (-ENOENT == PTR_ERR(inode)) + inode = ERR_PTR(-ESTALE); + goto out; + } + + ret = check_is_regular_file(root, inode); + if (ret) { + iput(inode); + inode = ERR_PTR(ret); + goto out; + } + +out: + btrfs_put_root(root); + return inode; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_match_actor(struct inode *inode, unsigned long hashval, void *opaque) +{ + struct btrfs_iget_args *args = opaque; + + if (args->ino == BTRFS_I(inode)->location.objectid && + args->root == BTRFS_I(inode)->root) + return 1; + return 0; +} + +/* + * Test if the inode exists in hash table. + * See comments in find_inode_nowait(). + */ +bool btrfs_test_inode_nowait(struct super_block *s, u64 ino, + struct btrfs_root *root) +{ + struct btrfs_iget_args args; + unsigned long hashval = btrfs_inode_hash(ino, root); + + args.ino = ino; + args.root = root; + + if (find_inode_nowait(s, hashval, btrfs_match_actor, (void *)&args)) + return true; + return false; +} +#endif /* MY_ABC_HERE */ + static struct inode *new_simple_dir(struct super_block *s, struct btrfs_key *key, struct btrfs_root *root) @@ -5511,7 +6594,11 @@ static inline u8 btrfs_inode_type(struct inode *inode) return fs_umode_to_ftype(inode->i_mode); } -struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) +struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); struct inode *inode; @@ -5524,7 +6611,11 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) if (dentry->d_name.len > BTRFS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); +#ifdef MY_ABC_HERE + ret = btrfs_inode_by_name(dir, dentry, &location, &di_type, caseless); +#else /* MY_ABC_HERE */ ret = btrfs_inode_by_name(dir, dentry, &location, &di_type); +#endif /* MY_ABC_HERE */ if (ret < 0) return ERR_PTR(ret); @@ -5559,14 +6650,26 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) btrfs_put_root(sub_root); if (!IS_ERR(inode) && root != sub_root) { - down_read(&fs_info->cleanup_work_sem); - if (!sb_rdonly(inode->i_sb)) - ret = btrfs_orphan_cleanup(sub_root); - up_read(&fs_info->cleanup_work_sem); - if (ret) { - iput(inode); - inode = ERR_PTR(ret); +#ifdef MY_ABC_HERE + if (is_fstree(sub_root->root_key.objectid) && sub_root->root_key.objectid <= BTRFS_LAST_FREE_OBJECTID && + !btrfs_root_dead(sub_root) && test_bit(BTRFS_ROOT_IN_RADIX, &sub_root->state)) { + spin_lock(&fs_info->syno_orphan_cleanup.lock); + if (list_empty(&sub_root->syno_orphan_cleanup.root)) + list_add_tail(&sub_root->syno_orphan_cleanup.root, &fs_info->syno_orphan_cleanup.roots); + spin_unlock(&fs_info->syno_orphan_cleanup.lock); + } else { +#endif /* MY_ABC_HERE */ + down_read(&fs_info->cleanup_work_sem); + if (!sb_rdonly(inode->i_sb)) + ret = btrfs_orphan_cleanup(sub_root); + up_read(&fs_info->cleanup_work_sem); + if (ret) { + iput(inode); + inode = ERR_PTR(ret); + } +#ifdef MY_ABC_HERE } +#endif /* MY_ABC_HERE */ } return inode; @@ -5594,7 +6697,11 @@ static int btrfs_dentry_delete(const struct dentry *dentry) static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { +#ifdef MY_ABC_HERE + struct inode *inode = btrfs_lookup_dentry(dir, dentry, (flags & LOOKUP_CASELESS_COMPARE) ? 1 : 0); +#else /* MY_ABC_HERE */ struct inode *inode = btrfs_lookup_dentry(dir, dentry); +#endif /* MY_ABC_HERE */ if (inode == ERR_PTR(-ENOENT)) inode = NULL; @@ -5631,6 +6738,9 @@ struct dir_entry { u64 offset; unsigned type; int name_len; +#ifdef MY_ABC_HERE + bool hidden; +#endif /* MY_ABC_HERE */ }; static int btrfs_filldir(void *addr, int entries, struct dir_context *ctx) @@ -5640,10 +6750,17 @@ static int btrfs_filldir(void *addr, int entries, struct dir_context *ctx) char *name = (char *)(entry + 1); ctx->pos = get_unaligned(&entry->offset); +#ifdef MY_ABC_HERE + if (get_unaligned(&entry->hidden)) + goto skip; +#endif /* MY_ABC_HERE */ if (!dir_emit(ctx, name, get_unaligned(&entry->name_len), get_unaligned(&entry->ino), get_unaligned(&entry->type))) return 1; +#ifdef MY_ABC_HERE +skip: +#endif /* MY_ABC_HERE */ addr += sizeof(struct dir_entry) + get_unaligned(&entry->name_len); ctx->pos++; @@ -5742,6 +6859,19 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) put_unaligned(fs_ftype_to_dtype(btrfs_dir_type(leaf, di)), &entry->type); btrfs_dir_item_key_to_cpu(leaf, di, &location); +#ifdef MY_ABC_HERE + put_unaligned(false, &entry->hidden); + if (location.type == BTRFS_ROOT_ITEM_KEY) { + struct btrfs_root *subvol_root = btrfs_get_fs_root( + root->fs_info, location.objectid, true); + + if (!IS_ERR(subvol_root)) { + if (btrfs_root_hide(subvol_root)) + put_unaligned(true, &entry->hidden); + btrfs_put_root(subvol_root); + } + } +#endif /* MY_ABC_HERE */ put_unaligned(location.objectid, &entry->ino); put_unaligned(found_key.offset, &entry->offset); entries++; @@ -5824,6 +6954,10 @@ static int btrfs_dirty_inode(struct inode *inode) if (BTRFS_I(inode)->delayed_node) btrfs_balance_delayed_items(fs_info); +#ifdef MY_ABC_HERE + ret = btrfs_syno_locker_disk_inode_update_trans(inode); +#endif /* MY_ABC_HERE */ + return ret; } @@ -6120,6 +7254,15 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, if (btrfs_test_opt(fs_info, NODATACOW)) BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM; + +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !btrfs_root_disable_quota(root) && + btrfs_usrquota_compat_inode_quota(fs_info) && + is_fstree(root->root_key.objectid)) { + BTRFS_I(inode)->flags |= BTRFS_INODE_UQ_REF_USED; + } +#endif /* MY_ABC_HERE */ } inode_tree_add(inode); @@ -6257,13 +7400,40 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, int err; u64 objectid; u64 index = 0; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_check_dir_item_collision(root, dir->i_ino, + dentry->d_name.name, + dentry->d_name.len, + 0); + if (err) + return err; + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // 1 for xattr to store archive bit + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + credit_for_syno++; +#endif /* MY_ABC_HERE */ /* * 2 for inode item and ref * 2 for dir items * 1 for xattr if selinux is on */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + trans = btrfs_start_transaction(root, 5 + credit_for_syno); +#else /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ trans = btrfs_start_transaction(root, 5); +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ if (IS_ERR(trans)) return PTR_ERR(trans); @@ -6293,6 +7463,18 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, if (err) goto out_unlock; +#ifdef MY_ABC_HERE + err = btrfs_syno_init_archive_bit(trans, inode); + if (err) + goto out_unlock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_syno_init_crtime(trans, inode); + if (err) + goto out_unlock; +#endif /* MY_ABC_HERE */ + err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry, BTRFS_I(inode), 0, index); if (err) @@ -6321,13 +7503,40 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, int err; u64 objectid; u64 index = 0; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_check_dir_item_collision(root, dir->i_ino, + dentry->d_name.name, + dentry->d_name.len, + 0); + if (err) + return err; + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // 1 for xattr to store archive bit + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + credit_for_syno++; +#endif /* MY_ABC_HERE */ /* * 2 for inode item and ref * 2 for dir items * 1 for xattr if selinux is on */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + trans = btrfs_start_transaction(root, 5 + credit_for_syno); +#else /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ trans = btrfs_start_transaction(root, 5); +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ if (IS_ERR(trans)) return PTR_ERR(trans); @@ -6357,6 +7566,18 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, if (err) goto out_unlock; +#ifdef MY_ABC_HERE + err = btrfs_syno_init_archive_bit(trans, inode); + if (err) + goto out_unlock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_syno_init_crtime(trans, inode); + if (err) + goto out_unlock; +#endif /* MY_ABC_HERE */ + err = btrfs_update_inode(trans, root, inode); if (err) goto out_unlock; @@ -6388,6 +7609,9 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, u64 index; int err; int drop_inode = 0; +#ifdef MY_ABC_HERE + int credit_for_syno = 0; +#endif /* MY_ABC_HERE */ /* do not allow sys_link's with other subvols of the same device */ if (root->root_key.objectid != BTRFS_I(inode)->root->root_key.objectid) @@ -6396,6 +7620,15 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink >= BTRFS_LINK_MAX) return -EMLINK; +#ifdef MY_ABC_HERE + err = btrfs_check_dir_item_collision(root, dir->i_ino, + dentry->d_name.name, + dentry->d_name.len, + 0); + if (err) + return err; +#endif /* MY_ABC_HERE */ + err = btrfs_set_inode_index(BTRFS_I(dir), &index); if (err) goto fail; @@ -6406,7 +7639,17 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, * 1 item for parent inode * 1 item for orphan item deletion if O_TMPFILE */ +#ifdef MY_ABC_HERE + /* + * 1 item for dir caseless item if CASELESS FEATURE support + */ + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; + + trans = btrfs_start_transaction(root, (inode->i_nlink ? 5 : 6) + credit_for_syno); +#else /* MY_ABC_HERE */ trans = btrfs_start_transaction(root, inode->i_nlink ? 5 : 6); +#endif /* MY_ABC_HERE */ if (IS_ERR(trans)) { err = PTR_ERR(trans); trans = NULL; @@ -6438,6 +7681,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, * with open(2) O_TMPFILE flag. */ err = btrfs_orphan_del(trans, BTRFS_I(inode)); +#ifdef MY_ABC_HERE + if (err == -ENOENT) + err = 0; +#endif /* MY_ABC_HERE */ if (err) goto fail; } @@ -6465,13 +7712,40 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) int err = 0; u64 objectid = 0; u64 index = 0; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_check_dir_item_collision(root, dir->i_ino, + dentry->d_name.name, + dentry->d_name.len, + 0); + if (err) + return err; + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // 1 for xattr to store archive bit + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + credit_for_syno++; +#endif /* MY_ABC_HERE */ /* * 2 items for inode and ref * 2 items for dir items * 1 for xattr if selinux is on */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + trans = btrfs_start_transaction(root, 5 + credit_for_syno); +#else /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ trans = btrfs_start_transaction(root, 5); +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ if (IS_ERR(trans)) return PTR_ERR(trans); @@ -6496,6 +7770,18 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (err) goto out_fail; +#ifdef MY_ABC_HERE + err = btrfs_syno_init_archive_bit(trans, inode); + if (err) + goto out_fail; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_syno_init_crtime(trans, inode); + if (err) + goto out_fail; +#endif /* MY_ABC_HERE */ + btrfs_i_size_write(BTRFS_I(inode), 0); err = btrfs_update_inode(trans, root, inode); if (err) @@ -6600,7 +7886,6 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, struct btrfs_key found_key; struct extent_map *em = NULL; struct extent_map_tree *em_tree = &inode->extent_tree; - struct extent_io_tree *io_tree = &inode->io_tree; read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, start, len); @@ -6639,7 +7924,15 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, */ path->leave_spinning = 1; - path->recurse = btrfs_is_free_space_inode(inode); + /* + * The same explanation in load_free_space_cache applies here as well, + * we only read when we're loading the free space cache, and at that + * point the commit_root has everything we need. + */ + if (btrfs_is_free_space_inode(inode)) { + path->search_commit_root = 1; + path->skip_locking = 1; + } ret = btrfs_lookup_file_extent(NULL, root, path, objectid, start, 0); if (ret < 0) { @@ -6762,8 +8055,6 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, } flush_dcache_page(page); } - set_extent_uptodate(io_tree, em->start, - extent_map_end(em) - 1, NULL, GFP_NOFS); goto insert; } not_found: @@ -7249,6 +8540,9 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start, ASSERT(type == BTRFS_ORDERED_PREALLOC || type == BTRFS_ORDERED_COMPRESSED || type == BTRFS_ORDERED_NOCOW || +#ifdef MY_ABC_HERE + type == BTRFS_ORDERED_DEDUPED || +#endif /* MY_ABC_HERE */ type == BTRFS_ORDERED_REGULAR); em_tree = &inode->extent_tree; @@ -7270,6 +8564,14 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start, } else if (type == BTRFS_ORDERED_COMPRESSED) { set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); em->compress_type = compress_type; +#ifdef MY_ABC_HERE + } else if (type == BTRFS_ORDERED_DEDUPED) { + if (!block_start) { + em->block_len = 0; + em->block_start = EXTENT_MAP_HOLE; + } + set_bit(EXTENT_FLAG_DEDUPED, &em->flags); +#endif /* MY_ABC_HERE */ } do { @@ -7662,7 +8964,11 @@ static blk_status_t btrfs_check_read_dio_bio(struct inode *inode, clean_io_failure(fs_info, failure_tree, io_tree, start, bvec.bv_page, btrfs_ino(BTRFS_I(inode)), - pgoff); + pgoff +#ifdef MY_ABC_HERE + , false +#endif /* MY_ABC_HERE */ + ); } else { blk_status_t status; @@ -7673,7 +8979,11 @@ static blk_status_t btrfs_check_read_dio_bio(struct inode *inode, start, start + sectorsize - 1, io_bio->mirror_num, - submit_dio_repair_bio); + submit_dio_repair_bio +#ifdef MY_ABC_HERE + , false, NULL +#endif /* MY_ABC_HERE */ + ); if (status) err = status; } @@ -7696,10 +9006,15 @@ static void __endio_write_update_ordered(struct btrfs_inode *inode, u64 ordered_bytes = bytes; u64 last_offset; - if (btrfs_is_free_space_inode(inode)) + if (btrfs_is_free_space_inode(inode)) { wq = fs_info->endio_freespace_worker; - else + } else { +#ifdef MY_ABC_HERE + wq = fs_info->syno_cow_endio_workers; +#else /* MY_ABC_HERE */ wq = fs_info->endio_write_workers; +#endif /* MY_ABC_HERE */ + } while (ordered_offset < offset + bytes) { last_offset = ordered_offset; @@ -7709,6 +9024,20 @@ static void __endio_write_update_ordered(struct btrfs_inode *inode, uptodate)) { btrfs_init_work(&ordered->work, finish_ordered_fn, NULL, NULL); +#ifdef MY_ABC_HERE + if (!btrfs_is_free_space_inode(inode)) { + if (ordered->high_priority) { + wq = fs_info->syno_high_priority_endio_workers; + set_bit(BTRFS_ORDERED_HIGH_PRIORITY, &ordered->flags); + } else if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) { + wq = fs_info->syno_nocow_endio_workers; + } + + set_bit(BTRFS_ORDERED_WORK_INITIALIZED, &ordered->flags); + if (ordered->high_priority) + btrfs_set_work_high_priority(&ordered->work); + } +#endif /* MY_ABC_HERE */ btrfs_queue_work(wq, &ordered->work); } /* @@ -7783,6 +9112,14 @@ static inline blk_status_t btrfs_submit_dio_bio(struct bio *bio, goto map; if (write && async_submit) { +#ifdef MY_ABC_HERE + if (is_fstree(BTRFS_I(inode)->root->root_key.objectid)) { + ret = btrfs_wq_submit_bio_throttle(fs_info, bio, 0, 0, + file_offset, inode, + btrfs_submit_bio_start_direct_io); + goto err; + } +#endif /* MY_ABC_HERE */ ret = btrfs_wq_submit_bio(fs_info, bio, 0, 0, file_offset, inode, btrfs_submit_bio_start_direct_io); @@ -7858,12 +9195,14 @@ static blk_qc_t btrfs_submit_direct(struct inode *inode, struct iomap *iomap, u64 start_sector; int async_submit = 0; u64 submit_len; - int clone_offset = 0; - int clone_len; + u64 clone_offset = 0; + u64 clone_len; + u64 logical; int ret; blk_status_t status; struct btrfs_io_geometry geom; struct btrfs_dio_data *dio_data = iomap->private; + struct extent_map *em = NULL; dip = btrfs_create_dio_private(dio_bio, inode, file_offset); if (!dip) { @@ -7891,16 +9230,22 @@ static blk_qc_t btrfs_submit_direct(struct inode *inode, struct iomap *iomap, submit_len = dio_bio->bi_iter.bi_size; do { - ret = btrfs_get_io_geometry(fs_info, btrfs_op(dio_bio), - start_sector << 9, submit_len, - &geom); + logical = start_sector << 9; + em = btrfs_get_chunk_map(fs_info, logical, submit_len); + if (IS_ERR(em)) { + status = errno_to_blk_status(PTR_ERR(em)); + em = NULL; + goto out_err_em; + } + ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(dio_bio), + logical, submit_len, &geom); if (ret) { status = errno_to_blk_status(ret); - goto out_err; + goto out_err_em; } - ASSERT(geom.len <= INT_MAX); - clone_len = min_t(int, submit_len, geom.len); + clone_len = min(submit_len, geom.len); + ASSERT(clone_len <= UINT_MAX); /* * This will never fail as it's passing GPF_NOFS and @@ -7941,19 +9286,24 @@ static blk_qc_t btrfs_submit_direct(struct inode *inode, struct iomap *iomap, bio_put(bio); if (submit_len > 0) refcount_dec(&dip->refs); - goto out_err; + goto out_err_em; } dio_data->submitted += clone_len; clone_offset += clone_len; start_sector += clone_len >> 9; file_offset += clone_len; + + free_extent_map(em); } while (submit_len > 0); return BLK_QC_T_NONE; +out_err_em: + free_extent_map(em); out_err: dip->dio_bio->bi_status = status; btrfs_dio_private_put(dip); + return BLK_QC_T_NONE; } @@ -8203,6 +9553,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset, u64 start; u64 end; int inode_evicting = inode->vfs_inode.i_state & I_FREEING; + bool found_ordered = false; + bool completed_ordered = false; /* * we have the page locked, so new writeback can't start, @@ -8237,15 +9589,17 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset, again: ordered = btrfs_lookup_ordered_range(inode, start, page_end - start + 1); if (ordered) { + found_ordered = true; end = min(page_end, ordered->file_offset + ordered->num_bytes - 1); /* - * IO on this page will never be started, so we need - * to account for any ordered extents now + * IO on this page will never be started, so we need to account + * for any ordered extents now. Don't clear EXTENT_DELALLOC_NEW + * here, must leave that up for the ordered extent completion. */ if (!inode_evicting) clear_extent_bit(tree, start, end, - EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_DELALLOC | EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, 0, &cached_state); /* @@ -8267,8 +9621,10 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset, if (btrfs_dec_test_ordered_pending(inode, &ordered, start, - end - start + 1, 1)) + end - start + 1, 1)) { btrfs_finish_ordered_io(ordered); + completed_ordered = true; + } } btrfs_put_ordered_extent(ordered); if (!inode_evicting) { @@ -8297,10 +9653,23 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset, */ btrfs_qgroup_free_data(inode, NULL, page_start, PAGE_SIZE); if (!inode_evicting) { + bool delete = true; + + /* + * If there's an ordered extent for this range and we have not + * finished it ourselves, we must leave EXTENT_DELALLOC_NEW set + * in the range for the ordered extent completion. We must also + * not delete the range, otherwise we would lose that bit (and + * any other bits set in the range). Make sure EXTENT_UPTODATE + * is cleared if we don't delete, otherwise it can lead to + * corruptions if the i_size is extented later. + */ + if (found_ordered && !completed_ordered) + delete = false; clear_extent_bit(tree, page_start, page_end, EXTENT_LOCKED | - EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, 1, - &cached_state); + EXTENT_DELALLOC | EXTENT_UPTODATE | + EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, + delete, &cached_state); __btrfs_releasepage(page, GFP_NOFS); } @@ -8344,6 +9713,10 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) u64 page_end; u64 end; +#ifdef MY_ABC_HERE + syno_ordered_extent_throttle(fs_info); +#endif /* MY_ABC_HERE */ + reserved_space = PAGE_SIZE; sb_start_pagefault(inode->i_sb); @@ -8363,6 +9736,9 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) page_start, reserved_space); if (!ret2) { ret2 = file_update_time(vmf->vma->vm_file); +#ifdef MY_ABC_HERE + fsnotify_modify(vmf->vma->vm_file); +#endif /* MY_ABC_HERE */ reserved = 1; } if (ret2) { @@ -8638,6 +10014,18 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; +#ifdef MY_ABC_HERE + err = btrfs_syno_init_archive_bit(trans, inode); + if (err) + goto out_fail; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_syno_init_crtime(trans, inode); + if (err) + goto out_fail; +#endif /* MY_ABC_HERE */ + set_nlink(inode, 1); btrfs_i_size_write(BTRFS_I(inode), 0); unlock_new_inode(inode); @@ -8652,6 +10040,12 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, iput(inode); return err; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +out_fail: + inode_dec_link_count(inode); + discard_new_inode(inode); + return err; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ } struct inode *btrfs_alloc_inode(struct super_block *sb) @@ -8697,6 +10091,13 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) inode = &ei->vfs_inode; extent_map_tree_init(&ei->extent_tree); + +#ifdef MY_ABC_HERE + ei->extent_tree.inode = ei; + INIT_LIST_HEAD(&ei->free_extent_map_inode); + atomic_set(&ei->free_extent_map_counts, 0); +#endif /* MY_ABC_HERE */ + extent_io_tree_init(fs_info, &ei->io_tree, IO_TREE_INODE_IO, inode); extent_io_tree_init(fs_info, &ei->io_failure_tree, IO_TREE_INODE_IO_FAILURE, inode); @@ -8708,10 +10109,31 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) mutex_init(&ei->log_mutex); btrfs_ordered_inode_tree_init(&ei->ordered_tree); INIT_LIST_HEAD(&ei->delalloc_inodes); +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&ei->syno_dirty_lru_inode); +#endif /* MY_ABC_HERE */ INIT_LIST_HEAD(&ei->delayed_iput); RB_CLEAR_NODE(&ei->rb_node); init_rwsem(&ei->dio_sem); +#ifdef MY_ABC_HERE + ei->__locker_state = LS_OPEN; + ei->__locker_update_time = LOCKER_DEFAULT_UPDATE_TIME; + ei->__locker_period_begin = LOCKER_DEFAULT_PERIOD_BEGIN; + ei->__locker_period_end = LOCKER_DEFAULT_PERIOD_END; + ei->locker_dirty = false; + spin_lock_init(&ei->locker_lock); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + atomic_set(&ei->syno_uq_refs, 0); + ei->uq_reserved = 0; + ei->uq_rfer_used = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&ei->syno_rbd_meta_file); +#endif /* MY_ABC_HERE */ + return inode; } @@ -8738,6 +10160,9 @@ void btrfs_destroy_inode(struct inode *vfs_inode) WARN_ON(vfs_inode->i_data.nrpages); WARN_ON(inode->block_rsv.reserved); WARN_ON(inode->block_rsv.size); +#ifdef MY_ABC_HERE + WARN_ON(atomic_read(&inode->syno_uq_refs)); +#endif /* MY_ABC_HERE */ WARN_ON(inode->outstanding_extents); WARN_ON(inode->delalloc_bytes); WARN_ON(inode->new_delalloc_bytes); @@ -8752,6 +10177,12 @@ void btrfs_destroy_inode(struct inode *vfs_inode) if (!root) return; +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &root->fs_info->flags) || + test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &root->fs_info->flags)) + WARN_ON(inode->uq_reserved); +#endif /* MY_ABC_HERE */ + while (1) { ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); if (!ordered) @@ -8850,13 +10281,18 @@ static int btrfs_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) { u64 delalloc_bytes; + u64 inode_bytes; struct inode *inode = d_inode(path->dentry); u32 blocksize = inode->i_sb->s_blocksize; u32 bi_flags = BTRFS_I(inode)->flags; stat->result_mask |= STATX_BTIME; +#ifdef MY_ABC_HERE + btrfs_syno_get_crtime(inode, &stat->btime); +#else /* MY_ABC_HERE */ stat->btime.tv_sec = BTRFS_I(inode)->i_otime.tv_sec; stat->btime.tv_nsec = BTRFS_I(inode)->i_otime.tv_nsec; +#endif /* MY_ABC_HERE */ if (bi_flags & BTRFS_INODE_APPEND) stat->attributes |= STATX_ATTR_APPEND; if (bi_flags & BTRFS_INODE_COMPRESS) @@ -8872,16 +10308,110 @@ static int btrfs_getattr(const struct path *path, struct kstat *stat, STATX_ATTR_NODUMP); generic_fillattr(inode, stat); +#ifdef MY_ABC_HERE + btrfs_syno_locker_fillattr(inode, stat); +#endif /* MY_ABC_HERE */ stat->dev = BTRFS_I(inode)->root->anon_dev; spin_lock(&BTRFS_I(inode)->lock); delalloc_bytes = BTRFS_I(inode)->new_delalloc_bytes; + inode_bytes = inode_get_bytes(inode); spin_unlock(&BTRFS_I(inode)->lock); - stat->blocks = (ALIGN(inode_get_bytes(inode), blocksize) + + stat->blocks = (ALIGN(inode_bytes, blocksize) + ALIGN(delalloc_bytes, blocksize)) >> 9; return 0; } +#ifdef MY_ABC_HERE +static int btrfs_is_inode_inline(struct inode *inode) +{ + struct btrfs_path *path; + struct btrfs_inode *btrfs_inode = BTRFS_I(inode); + struct btrfs_root *root = btrfs_inode->root; + struct extent_buffer *leaf; + struct btrfs_key key; + struct btrfs_file_extent_item *fi; + u64 delalloc_bytes; + int ret; + + // Deal with unflushed extents + spin_lock(&btrfs_inode->lock); + delalloc_bytes = btrfs_inode->delalloc_bytes; + spin_unlock(&btrfs_inode->lock); + if (delalloc_bytes) { + if (i_size_read(inode) > BTRFS_DEFAULT_MAX_INLINE) + return 0; + else + return 1; + } + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + path->leave_spinning = 1; + + ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(btrfs_inode), 0, 0); + if (ret == 0) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + if (key.objectid == btrfs_ino(btrfs_inode) && key.type == BTRFS_EXTENT_DATA_KEY) { + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { + btrfs_free_path(path); + return 1; + } + } + } + btrfs_free_path(path); + if (ret < 0) + return ret; + + return 0; +} + +static int btrfs_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags) +{ + int err = 0; + struct inode *inode = dentry->d_inode; + + if (syno_flags & SYNOST_COMPRESSION) + kst->syno_compressed = BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS ? 1 : 0; + + if (syno_flags & SYNOST_IS_INLINE) { + err = btrfs_is_inode_inline(inode); + if (err < 0) + return err; + kst->is_inline = (err > 0); + err = 0; + } + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_BIT) { + mutex_lock(&inode->i_archive_bit_mutex); + kst->syno_archive_bit = inode->i_archive_bit; + mutex_unlock(&inode->i_archive_bit_mutex); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_CREATE_TIME) { + btrfs_syno_get_crtime(inode, &kst->syno_create_time); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_VER) { + mutex_lock(&inode->i_archive_version_mutex); + err = btrfs_syno_get_inode_archive_version(dentry, &kst->syno_archive_version); + mutex_unlock(&inode->i_archive_version_mutex); + } +#endif /* MY_ABC_HERE */ + + return err; +} +#endif /* MY_ABC_HERE */ + static int btrfs_rename_exchange(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, @@ -8902,17 +10432,38 @@ static int btrfs_rename_exchange(struct inode *old_dir, int ret2; bool root_log_pinned = false; bool dest_log_pinned = false; +#if defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE */ bool need_abort = false; /* we only allow rename subvolume link between subvolumes */ if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest) return -EXDEV; +#ifdef MY_ABC_HERE + /* + * we should check the locker status first. if both EOPNOTSUPP(source not empty) + * and ENOTEMPTY(dest not empty), EOPNOTSUPP should be prior to ENOTEMPTY, because + * SYNOCopyDirectoryExI() has different reactions on them and would like to handle + * EOPNOTSUPP first. + */ + ret = btrfs_syno_locker_may_rename(old_dir, old_dentry, new_dir, new_dentry, true); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ + /* close the race window with snapshot create/destroy ioctl */ if (old_ino == BTRFS_FIRST_FREE_OBJECTID || new_ino == BTRFS_FIRST_FREE_OBJECTID) down_read(&fs_info->subvol_sem); +#ifdef MY_ABC_HERE + // 2 for dir_item_caseless + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno += 2; +#endif /* MY_ABC_HERE */ + /* * We want to reserve the absolute worst case amount of items. So if * both inodes are subvols and we need to unlink them then that would @@ -8921,7 +10472,11 @@ static int btrfs_rename_exchange(struct inode *old_dir, * inodes. So 5 * 2 is 10, plus 2 for the new links, so 12 total items * should cover the worst case number of items we'll modify. */ +#if defined(MY_ABC_HERE) + trans = btrfs_start_transaction(root, 12 + credit_for_syno); +#else /* MY_ABC_HERE */ trans = btrfs_start_transaction(root, 12); +#endif /* MY_ABC_HERE */ if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_notrans; @@ -9186,11 +10741,27 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; +#ifdef MY_ABC_HERE + /* + * we should check the locker status first. if both EOPNOTSUPP(source not empty) + * and ENOTEMPTY(dest not empty), EOPNOTSUPP should be prior to ENOTEMPTY, because + * SYNOCopyDirectoryExI() has different reactions on them and would like to handle + * EOPNOTSUPP first. + */ + ret = btrfs_syno_locker_may_rename(old_dir, old_dentry, new_dir, new_dentry, true); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ + /* check for collisions, even if the name isn't there */ ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino, new_dentry->d_name.name, - new_dentry->d_name.len); + new_dentry->d_name.len +#ifdef MY_ABC_HERE + , 1 +#endif /* MY_ABC_HERE */ + ); if (ret) { if (ret == -EEXIST) { @@ -9230,6 +10801,14 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, trans_num_items = 11; if (flags & RENAME_WHITEOUT) trans_num_items += 5; +#if defined(MY_ABC_HERE) + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) { + ++trans_num_items; + if (flags & RENAME_WHITEOUT) + ++trans_num_items; + } +#endif /* MY_ABC_HERE */ trans = btrfs_start_transaction(root, trans_num_items); if (IS_ERR(trans)) { ret = PTR_ERR(trans); @@ -9385,23 +10964,53 @@ struct btrfs_delalloc_work { struct completion completion; struct list_head list; struct btrfs_work work; +#ifdef MY_ABC_HERE + bool syno_writeback; +#endif /* MY_ABC_HERE */ }; static void btrfs_run_delalloc_work(struct btrfs_work *work) { struct btrfs_delalloc_work *delalloc_work; struct inode *inode; +#ifdef MY_ABC_HERE + struct btrfs_fs_info *fs_info = NULL; + bool syno_writeback = false; + struct blk_plug plug; +#endif /* MY_ABC_HERE */ delalloc_work = container_of(work, struct btrfs_delalloc_work, work); inode = delalloc_work->inode; +#ifdef MY_ABC_HERE + blk_start_plug(&plug); +#endif /* MY_ABC_HERE */ filemap_flush(inode->i_mapping); if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, &BTRFS_I(inode)->runtime_flags)) filemap_flush(inode->i_mapping); +#ifdef MY_ABC_HERE + blk_finish_plug(&plug); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (delalloc_work->syno_writeback) { + spin_lock(&inode->i_lock); + inode_sync_complete(inode); + spin_unlock(&inode->i_lock); + syno_writeback = true; + fs_info = BTRFS_I(inode)->root->fs_info; + } +#endif /* MY_ABC_HERE */ iput(inode); complete(&delalloc_work->completion); +#ifdef MY_ABC_HERE + if (syno_writeback && fs_info) { + atomic_dec(&fs_info->syno_writeback_thread_count); + kfree(delalloc_work); + } +#endif /* MY_ABC_HERE */ } static struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode) @@ -9415,6 +11024,9 @@ static struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode init_completion(&work->completion); INIT_LIST_HEAD(&work->list); work->inode = inode; +#ifdef MY_ABC_HERE + work->syno_writeback = false; +#endif /* MY_ABC_HERE */ btrfs_init_work(&work->work, btrfs_run_delalloc_work, NULL, NULL); return work; @@ -9504,6 +11116,90 @@ static int start_delalloc_inodes(struct btrfs_root *root, return ret; } +#ifdef MY_ABC_HERE +void syno_writeback_balance_dirty_pages(struct btrfs_fs_info *fs_info) +{ + struct btrfs_delalloc_work *work; + struct btrfs_inode *binode, *first_binode = NULL; + struct inode *inode; + int nr_retry = 8; + + if (btrfs_fs_closing(fs_info) || fs_info->syno_writeback_thread_max == 0) + goto out; + + if (!writeback_in_progress(&fs_info->sb->s_bdi->wb)) + goto out; + + if (list_empty(&fs_info->syno_dirty_lru_inodes)) + goto out; + + if (atomic_read(&fs_info->syno_writeback_thread_count) >= fs_info->syno_writeback_thread_max) + goto out; + + syno_perf_indicator_dirty_limit_update(fs_info); + if ((global_node_page_state(NR_FILE_DIRTY) < fs_info->syno_perf_indicator.dirty_background_thresh) && + !work_busy(&fs_info->async_reclaim_work)) + goto out; + + if (!atomic_add_unless(&fs_info->syno_writeback_thread_count, 1, fs_info->syno_writeback_thread_max)) + goto out; + + spin_lock(&fs_info->syno_multiple_writeback_lock); +again: + if (list_empty(&fs_info->syno_dirty_lru_inodes)) { + spin_unlock(&fs_info->syno_multiple_writeback_lock); + goto out_dec; + } + binode = list_first_entry(&fs_info->syno_dirty_lru_inodes, struct btrfs_inode, syno_dirty_lru_inode); + if (first_binode == binode) + nr_retry = 0; + if (!first_binode) + first_binode = binode; + inode = igrab(&binode->vfs_inode); + if (!inode) { + list_del_init(&binode->syno_dirty_lru_inode); + clear_bit(BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, &binode->runtime_flags); + if (first_binode == binode) + first_binode = NULL; + goto again; + } + spin_lock(&inode->i_lock); + if (inode->i_state & I_SYNC) { + spin_unlock(&inode->i_lock); + iput(inode); + if (nr_retry-- > 0) { + list_move_tail(&binode->syno_dirty_lru_inode, &fs_info->syno_dirty_lru_inodes); + goto again; + } + spin_unlock(&fs_info->syno_multiple_writeback_lock); + goto out_dec; + } + inode->i_state |= I_SYNC; + spin_unlock(&inode->i_lock); + + list_move_tail(&BTRFS_I(inode)->syno_dirty_lru_inode, &fs_info->syno_dirty_lru_inodes); + spin_unlock(&fs_info->syno_multiple_writeback_lock); + + work = btrfs_alloc_delalloc_work(inode); + if (!work) + goto out_inode; + work->syno_writeback = true; + btrfs_queue_work(fs_info->syno_multiple_writeback_workers, &work->work); + +out: + return; + +out_inode: + spin_lock(&inode->i_lock); + inode_sync_complete(inode); + spin_unlock(&inode->i_lock); + iput(inode); +out_dec: + atomic_dec(&fs_info->syno_writeback_thread_count); + goto out; +} +#endif /* MY_ABC_HERE */ + int btrfs_start_delalloc_snapshot(struct btrfs_root *root) { struct writeback_control wbc = { @@ -9593,11 +11289,38 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, unsigned long ptr; struct btrfs_file_extent_item *ei; struct extent_buffer *leaf; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool quota_added = false; + bool need_reserve = test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags); // Only V2 account symlink's quota. +#endif /* MY_ABC_HERE */ name_len = strlen(symname); if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info)) return -ENAMETOOLONG; +#ifdef MY_ABC_HERE + err = btrfs_check_dir_item_collision(root, dir->i_ino, + dentry->d_name.name, + dentry->d_name.len, + 0); + if (err) + return err; + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(root->fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // 1 for xattr to store archive bit + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + credit_for_syno++; +#endif /* MY_ABC_HERE */ + /* * 2 items for inode item and ref * 2 items for dir items @@ -9605,7 +11328,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, * 1 item for the inline extent item * 1 item for xattr if selinux is on */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + trans = btrfs_start_transaction(root, 7 + credit_for_syno); +#else /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ trans = btrfs_start_transaction(root, 7); +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ if (IS_ERR(trans)) return PTR_ERR(trans); @@ -9622,6 +11349,21 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, goto out_unlock; } +#ifdef MY_ABC_HERE + down_read(&fs_info->inflight_reserve_lock); + + if (need_reserve) { + // After btrfs_new_inode(), so we can get uid to reserve user quota. + err = btrfs_qgroup_syno_reserve(root, name_len); + if (err < 0) + goto free_inode; + + err = btrfs_usrquota_syno_reserve(BTRFS_I(inode), name_len); + if (err < 0) + goto free_qgroup; + } +#endif /* MY_ABC_HERE */ + /* * If the active LSM wants to access the inode during * d_instantiate it needs these. Smack checks to see @@ -9636,6 +11378,18 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, if (err) goto out_unlock; +#ifdef MY_ABC_HERE + err = btrfs_syno_init_archive_bit(trans, inode); + if (err) + goto out_unlock; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = btrfs_syno_init_crtime(trans, inode); + if (err) + goto out_unlock; +#endif /* MY_ABC_HERE */ + path = btrfs_alloc_path(); if (!path) { err = -ENOMEM; @@ -9660,6 +11414,9 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, btrfs_set_file_extent_encryption(leaf, ei, 0); btrfs_set_file_extent_compression(leaf, ei, 0); btrfs_set_file_extent_other_encoding(leaf, ei, 0); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, ei, 0); +#endif /* MY_ABC_HERE */ btrfs_set_file_extent_ram_bytes(leaf, ei, name_len); ptr = btrfs_file_extent_inline_start(ei); @@ -9669,7 +11426,18 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, inode->i_op = &btrfs_symlink_inode_operations; inode_nohighmem(inode); +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); inode_set_bytes(inode, name_len); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + name_len, 0, UPDATE_QUOTA_FREE_RESERVED); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + name_len, 0, UPDATE_QUOTA_FREE_RESERVED); + up_read(&root->rescan_lock); + quota_added = true; +#else + inode_set_bytes(inode, name_len); +#endif /* MY_ABC_HERE */ btrfs_i_size_write(BTRFS_I(inode), name_len); err = btrfs_update_inode(trans, root, inode); /* @@ -9686,6 +11454,26 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, d_instantiate_new(dentry, inode); out_unlock: +#ifdef MY_ABC_HERE + if (err && inode) { + if (quota_added) + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, name_len, UPDATE_QUOTA); + if (need_reserve) + btrfs_usrquota_syno_free(BTRFS_I(inode), name_len); + } +free_qgroup: + if (err && inode) { + if (quota_added) + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, name_len, UPDATE_QUOTA); + if (need_reserve) + btrfs_qgroup_syno_free(root, name_len); + } +free_inode: + if (inode) + up_read(&fs_info->inflight_reserve_lock); +#endif /* MY_ABC_HERE */ btrfs_end_transaction(trans); if (err && inode) { inode_dec_link_count(inode); @@ -9698,7 +11486,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, static struct btrfs_trans_handle *insert_prealloc_file_extent( struct btrfs_trans_handle *trans_in, struct inode *inode, struct btrfs_key *ins, - u64 file_offset) + u64 file_offset +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + , int extent_type +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ + ) { struct btrfs_file_extent_item stack_fi; struct btrfs_replace_extent_info extent_info; @@ -9710,13 +11502,20 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( memset(&stack_fi, 0, sizeof(stack_fi)); +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + btrfs_set_stack_file_extent_type(&stack_fi, extent_type); +#else /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_PREALLOC); +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, start); btrfs_set_stack_file_extent_disk_num_bytes(&stack_fi, len); btrfs_set_stack_file_extent_num_bytes(&stack_fi, len); btrfs_set_stack_file_extent_ram_bytes(&stack_fi, len); btrfs_set_stack_file_extent_compression(&stack_fi, BTRFS_COMPRESS_NONE); /* Encryption and other encoding is reserved and all 0 */ +#ifdef MY_ABC_HERE + /* syno flag is 0 */ +#endif /* MY_ABC_HERE */ ret = btrfs_qgroup_release_data(BTRFS_I(inode), file_offset, len); if (ret < 0) @@ -9724,7 +11523,8 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( if (trans) { ret = insert_reserved_file_extent(trans, BTRFS_I(inode), - file_offset, &stack_fi, ret); + file_offset, &stack_fi, + true, ret); if (ret) return ERR_PTR(ret); return trans; @@ -9739,6 +11539,11 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( extent_info.is_new_extent = true; extent_info.qgroup_reserved = ret; extent_info.insertions = 0; +#ifdef MY_ABC_HERE + extent_info.clone_range = false; + extent_info.clone_account_quota = false; + extent_info.clone_check_backref = false; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -9746,7 +11551,11 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent( ret = btrfs_replace_file_extents(inode, path, file_offset, file_offset + len - 1, &extent_info, - &trans); + &trans +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); btrfs_free_path(path); if (ret) return ERR_PTR(ret); @@ -9772,48 +11581,96 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, int ret = 0; bool own_trans = true; u64 end = start + num_bytes - 1; +#ifdef MY_ABC_HERE + bool dedupe = root->inline_dedupe; +#endif /* MY_ABC_HERE */ +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + int mark_written = (mode & FALLOC_FL_MARK_WRITTEN); + int extent_type = BTRFS_FILE_EXTENT_PREALLOC; +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ +#ifdef MY_ABC_HERE + if ((BTRFS_I(inode)->flags & BTRFS_INODE_NODEDUPE) || + test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) + dedupe = false; + + if (dedupe) + mark_written = false; +#endif +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + if (mark_written) + extent_type = BTRFS_FILE_EXTENT_REG; +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ if (trans) own_trans = false; while (num_bytes > 0) { cur_bytes = min_t(u64, num_bytes, SZ_256M); cur_bytes = max(cur_bytes, min_size); - /* - * If we are severely fragmented we could end up with really - * small allocations, so if the allocator is returning small - * chunks lets make its job easier by only searching for those - * sized chunks. - */ - cur_bytes = min(cur_bytes, last_alloc); - ret = btrfs_reserve_extent(root, cur_bytes, cur_bytes, - min_size, 0, *alloc_hint, &ins, 1, 0); - if (ret) - break; +#ifdef MY_ABC_HERE + if (dedupe) { + if (own_trans) { + trans = btrfs_start_transaction(root, 3); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + break; + } + } + ret = insert_dedupe_file_extent(trans, inode, cur_offset, cur_bytes, 0, 0, 0); + if (ret) { + btrfs_abort_transaction(trans, ret); + if (own_trans) + btrfs_end_transaction(trans); + break; + } + ins.objectid = 0; + ins.offset = cur_bytes; + btrfs_free_reserved_data_space(BTRFS_I(inode), NULL, cur_offset, cur_bytes); + clear_offset += ins.offset; + } else { +#endif /* MY_ABC_HERE */ + /* + * If we are severely fragmented we could end up with really + * small allocations, so if the allocator is returning small + * chunks lets make its job easier by only searching for those + * sized chunks. + */ + cur_bytes = min(cur_bytes, last_alloc); + ret = btrfs_reserve_extent(root, cur_bytes, cur_bytes, + min_size, 0, *alloc_hint, &ins, 1, 0); + if (ret) + break; - /* - * We've reserved this space, and thus converted it from - * ->bytes_may_use to ->bytes_reserved. Any error that happens - * from here on out we will only need to clear our reservation - * for the remaining unreserved area, so advance our - * clear_offset by our extent size. - */ - clear_offset += ins.offset; + /* + * We've reserved this space, and thus converted it from + * ->bytes_may_use to ->bytes_reserved. Any error that happens + * from here on out we will only need to clear our reservation + * for the remaining unreserved area, so advance our + * clear_offset by our extent size. + */ + clear_offset += ins.offset; - last_alloc = ins.offset; - trans = insert_prealloc_file_extent(trans, inode, &ins, cur_offset); - /* - * Now that we inserted the prealloc extent we can finally - * decrement the number of reservations in the block group. - * If we did it before, we could race with relocation and have - * relocation miss the reserved extent, making it fail later. - */ - btrfs_dec_block_group_reservations(fs_info, ins.objectid); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - btrfs_free_reserved_extent(fs_info, ins.objectid, - ins.offset, 0); - break; + last_alloc = ins.offset; + trans = insert_prealloc_file_extent(trans, inode, &ins, cur_offset +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + , extent_type +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ + ); + /* + * Now that we inserted the prealloc extent we can finally + * decrement the number of reservations in the block group. + * If we did it before, we could race with relocation and have + * relocation miss the reserved extent, making it fail later. + */ + btrfs_dec_block_group_reservations(fs_info, ins.objectid); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + btrfs_free_reserved_extent(fs_info, ins.objectid, + ins.offset, 0); + break; + } +#ifdef MY_ABC_HERE } +#endif /* MY_ABC_HERE */ btrfs_drop_extent_cache(BTRFS_I(inode), cur_offset, cur_offset + ins.offset -1, 0); @@ -9832,9 +11689,24 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, em->block_len = ins.offset; em->orig_block_len = ins.offset; em->ram_bytes = ins.offset; +#ifdef MY_ABC_HERE + if (!dedupe) +#endif /* MY_ABC_HERE */ +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + if (!mark_written) + set_bit(EXTENT_FLAG_PREALLOC, &em->flags); +#else /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ set_bit(EXTENT_FLAG_PREALLOC, &em->flags); +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ em->generation = trans->transid; +#ifdef MY_ABC_HERE + if (dedupe) { + em->block_start = EXTENT_MAP_HOLE; + em->block_len = 0; + em->orig_block_len = 0; + } +#endif /* MY_ABC_HERE */ while (1) { write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em, 1); @@ -9853,7 +11725,12 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, inode_inc_iversion(inode); inode->i_ctime = current_time(inode); +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + if (!mark_written) + BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; +#else /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ if (!(mode & FALLOC_FL_KEEP_SIZE) && (actual_len > inode->i_size) && (cur_offset > inode->i_size)) { @@ -9923,6 +11800,36 @@ static int btrfs_permission(struct inode *inode, int mask) return generic_permission(inode, mask); } +#ifdef MY_ABC_HERE +static int btrfs_syno_permission(struct dentry *dentry, int mask) +{ + struct inode *inode = d_inode(dentry); + struct btrfs_root *root = BTRFS_I(inode)->root; + umode_t mode = inode->i_mode; + + if (mask & MASK_RDONLY_CHECK && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) { + if (btrfs_root_readonly(root)) + return -EROFS; + if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) + return -EACCES; + } + return synoacl_mod_permission(dentry, mask); +} + +static int btrfs_syno_may_delete(struct dentry *victim, struct inode *dir) +{ + struct btrfs_root *root = BTRFS_I(dir)->root; + + if (btrfs_root_readonly(root)) + return -EROFS; + if (BTRFS_I(dir)->flags & BTRFS_INODE_READONLY) + return -EACCES; + return synoacl_mod_may_delete(victim, dir); +} +#endif /* MY_ABC_HERE */ + + static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) { struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); @@ -10009,7 +11916,11 @@ void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end) * swapfile. Returns 0 on success, 1 if there is already an entry for it, or a * negative errno on failure. */ -static int btrfs_add_swapfile_pin(struct inode *inode, void *ptr, +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +int btrfs_add_swapfile_pin(struct inode *inode, void *ptr, bool is_block_group) { struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; @@ -10051,7 +11962,11 @@ static int btrfs_add_swapfile_pin(struct inode *inode, void *ptr, } /* Free all of the entries pinned by this swapfile. */ -static void btrfs_free_swapfile_pins(struct inode *inode) +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +void btrfs_free_swapfile_pins(struct inode *inode) { struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; struct btrfs_swapfile_pin *sp; @@ -10374,7 +12289,455 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file, } #endif +#ifdef MY_ABC_HERE +int btrfs_quota_query(struct file *file, u64 *used, u64 *reserved, u64 *limit) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_ioctl_qgroup_query_args qqa; + int ret; + + memset(&qqa, 0, sizeof(qqa)); + + // use subvol id as qgroup id + ret = btrfs_qgroup_query(root, &qqa); + if (!ret) { + *used = qqa.rfer; + *reserved = qqa.reserved; + *limit = qqa.max_rfer; + } + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int btrfs_syno_space_usage(struct file *file, struct syno_space_usage_info *info) +{ + int ret; + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + + if (!info) { + ret = -EINVAL; + goto out; + } + memset(&info->result_mask, 0, sizeof(*info) - offsetof(struct syno_space_usage_info, result_mask)); + + if (!info->request_mask) + goto success; + +#ifdef MY_ABC_HERE + if ((info->request_mask & SYNO_SPACE_USAGE_REQUEST_DATA_USED) && + test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) { + info->data_used = root->syno_usage_root_status.num_bytes; + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN) + info->flags |= SYNO_SPACE_USAGE_FLAG_RESCAN; + info->result_mask |= SYNO_SPACE_USAGE_REQUEST_DATA_USED; + } + + if (info->request_mask & SYNO_SPACE_USAGE_REQUEST_DATA_DELAY_ALLOCATED && + root->syno_delalloc_bytes) { + info->data_delay_allocated = percpu_counter_sum_positive(root->syno_delalloc_bytes); + info->result_mask |= SYNO_SPACE_USAGE_REQUEST_DATA_DELAY_ALLOCATED; + } +#endif /* MY_ABC_HERE */ + + if (info->request_mask & SYNO_SPACE_USAGE_REQUEST_METADATA_USED) { + info->metadata_used = btrfs_root_used(&root->root_item); + info->result_mask |= SYNO_SPACE_USAGE_REQUEST_METADATA_USED; + } + + if (!info->result_mask) { + ret = -EOPNOTSUPP; + goto out; + } + +success: + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_fsdev_mapping(struct inode *inode, u64 start, u64 end, u64 *dev_start, u64 *dev_end) +{ + int ret; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; + struct extent_state *cached_state = NULL; + struct extent_map *em = NULL; + u64 isize; + u64 len; + u64 logical_block_start, physical_block_start; + + if (end < start || + !dev_start || !dev_end || + !IS_SWAPFILE(inode)) { + ret = -EINVAL; + goto out; + } + + start = round_down(start, fs_info->sectorsize); + len = round_up(end - start + 1, fs_info->sectorsize); + end = start + len - 1; + + isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize); + if (end >= isize) { + ret = -EOVERFLOW; + goto out; + } + + lock_extent_bits(io_tree, start, end, &cached_state); + + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto out_lock; + } + + if (em->block_start == EXTENT_MAP_HOLE) { + btrfs_info(fs_info, "fsdev file must not have holes"); + ret = -EINVAL; + goto out_lock; + } + if (em->block_start == EXTENT_MAP_INLINE) { + /* + * It's unlikely we'll ever actually find ourselves + * here, as a file small enough to fit inline won't be + * big enough to store more than the swap header, but in + * case something changes in the future, let's catch it + * here rather than later. + */ + btrfs_info(fs_info, "fsdev file must not be inline"); + ret = -EINVAL; + goto out_lock; + } + if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { + btrfs_info(fs_info, "fsdev file must not be compressed"); + ret = -EINVAL; + goto out_lock; + } + + logical_block_start = em->block_start + (start - em->start); + len = min(len, em->len - (start - em->start)); + free_extent_map(em); + em = NULL; + + em = btrfs_get_chunk_map(fs_info, logical_block_start, len); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto out_lock; + } + + if (em->map_lookup->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { + btrfs_info(fs_info, "fsdev file must have single data profile"); + ret = -EINVAL; + goto out_lock; + } + + physical_block_start = (em->map_lookup->stripes[0].physical + + (logical_block_start - em->start)); + len = min(len, em->len - (logical_block_start - em->start)); + free_extent_map(em); + em = NULL; + + *dev_start = physical_block_start; + *dev_end = physical_block_start + len - 1; + + ret = 0; +out_lock: + if (!IS_ERR_OR_NULL(em)) + free_extent_map(em); + unlock_extent_cached(io_tree, start, end, &cached_state); +out: + return ret; +} + +static void btrfs_fsdev_deactivate(struct inode *inode) +{ + btrfs_free_swapfile_pins(inode); + atomic_dec(&BTRFS_I(inode)->root->nr_swapfiles); +} + +static int btrfs_fsdev_activate(struct inode *inode, struct block_device **fs_bdev) +{ + int ret; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; + struct extent_state *cached_state = NULL; + struct extent_map *em = NULL; + struct btrfs_device *device = NULL; + u64 isize; + u64 start; + + if (!fs_bdev) { + ret = -EINVAL; + goto out; + } + + /* + * If the fsdev file was just created, make sure delalloc is done. If the + * file changes again after this, the user is doing something stupid and + * we don't really care. + */ + ret = btrfs_wait_ordered_range(inode, 0, (u64)-1); + if (ret) + goto out; + + /* + * The inode is locked, so these flags won't change after we check them. + */ + if (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS) { + btrfs_info(fs_info, "fsdev file must not be compressed"); + ret = -EINVAL; + goto out; + } + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW)) { + btrfs_info(fs_info, "fsdev file must not be copy-on-write"); + ret = -EINVAL; + goto out; + } + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { + btrfs_info(fs_info, "fsdev file must not be checksummed"); + ret = -EINVAL; + goto out; + } + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_IMMUTABLE)) { + btrfs_info(fs_info, "fsdev file must be immutable"); + ret = -EINVAL; + goto out; + } + + /* + * Balance or device remove/replace/resize can move stuff around from + * under us. The exclop protection makes sure they aren't running/won't + * run concurrently while we are mapping the swap extents, and + * fs_info->swapfile_pins prevents them from running while the swap + * file is active and moving the extents. Note that this also prevents + * a concurrent device add which isn't actually necessary, but it's not + * really worth the trouble to allow it. + */ + if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_SWAP_ACTIVATE)) { + btrfs_warn(fs_info, + "cannot activate fsdev file while exclusive operation is running"); + ret = -EBUSY; + goto out; + } + + /* + * Prevent snapshot creation while we are activating the swap file. + * We do not want to race with snapshot creation. If snapshot creation + * already started before we bumped nr_swapfiles from 0 to 1 and + * completes before the first write into the swap file after it is + * activated, than that write would fallback to COW. + */ + if (!btrfs_drew_try_write_lock(&root->snapshot_lock)) { + btrfs_warn(fs_info, + "cannot activate fsdev file because snapshot creation is in progress"); + ret = -EINVAL; + goto out_exclop; + } + + /* + * Snapshots can create extents which require COW even if NODATACOW is + * set. We use this counter to prevent snapshots. We must increment it + * before walking the extents because we don't want a concurrent + * snapshot to run after we've already checked the extents. + */ + atomic_inc(&root->nr_swapfiles); + + isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize); + if (!isize) { + ret = -EINVAL; + goto out_dec; + } + + lock_extent_bits(io_tree, 0, isize - 1, &cached_state); + start = 0; + while (start < isize) { + u64 logical_block_start, physical_block_start; + struct btrfs_block_group *bg; + u64 len = isize - start; + + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto out_lock; + } + + if (em->block_start == EXTENT_MAP_HOLE) { + btrfs_info(fs_info, "fsdev file must not have holes"); + ret = -EINVAL; + goto out_lock; + } + if (em->block_start == EXTENT_MAP_INLINE) { + /* + * It's unlikely we'll ever actually find ourselves + * here, as a file small enough to fit inline won't be + * big enough to store more than the swap header, but in + * case something changes in the future, let's catch it + * here rather than later. + */ + btrfs_info(fs_info, "fsdev file must not be inline"); + ret = -EINVAL; + goto out_lock; + } + if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { + btrfs_info(fs_info, "fsdev file must not be compressed"); + ret = -EINVAL; + goto out_lock; + } + + logical_block_start = em->block_start + (start - em->start); + len = min(len, em->len - (start - em->start)); + free_extent_map(em); + em = NULL; + + ret = can_nocow_extent(inode, start, &len, NULL, NULL, NULL, true); + if (ret < 0) { + goto out_lock; + } else if (ret) { + ret = 0; + } else { + btrfs_info(fs_info, "fsdev file must not be copy-on-write"); + ret = -EAGAIN; + goto out_lock; + } + + em = btrfs_get_chunk_map(fs_info, logical_block_start, len); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto out_lock; + } + + if (em->map_lookup->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { + btrfs_info(fs_info, "fsdev file must have single data profile"); + ret = -EINVAL; + goto out_lock; + } + + if (device == NULL) { + device = em->map_lookup->stripes[0].dev; + ret = btrfs_add_swapfile_pin(inode, device, false); + if (ret == 1) + ret = 0; + else if (ret) + goto out_lock; + } else if (device != em->map_lookup->stripes[0].dev) { + btrfs_info(fs_info, "fsdev file must be on one device"); + ret = -EINVAL; + goto out_lock; + } + + physical_block_start = (em->map_lookup->stripes[0].physical + + (logical_block_start - em->start)); + len = min(len, em->len - (logical_block_start - em->start)); + free_extent_map(em); + em = NULL; + + bg = btrfs_lookup_block_group(fs_info, logical_block_start); + if (!bg) { + btrfs_info(fs_info, + "could not find block group containing fsdev file"); + ret = -EINVAL; + goto out_lock; + } + + if (!btrfs_inc_block_group_swap_extents(bg)) { + btrfs_warn(fs_info, + "block group for fsdev file at %llu is read-only%s", + bg->start, + atomic_read(&fs_info->scrubs_running) ? + " (scrub running)" : ""); + btrfs_put_block_group(bg); + ret = -EINVAL; + goto out_lock; + } + + ret = btrfs_add_swapfile_pin(inode, bg, true); + if (ret) { + btrfs_put_block_group(bg); + if (ret == 1) { + ret = 0; + } else { + btrfs_dec_block_group_swap_extents(bg, 1); + goto out_lock; + } + } + + start += len; + } + + if (!device) { + ret = -ENOENT; + goto out_lock; + } + + *fs_bdev = device->bdev; + ret = 0; +out_lock: + if (!IS_ERR_OR_NULL(em)) + free_extent_map(em); + + unlock_extent_cached(io_tree, 0, isize - 1, &cached_state); + +out_dec: + if (ret) + btrfs_fsdev_deactivate(inode); + + btrfs_drew_write_unlock(&root->snapshot_lock); + +out_exclop: + btrfs_exclop_finish(fs_info); +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +/* + * Update the number of bytes used in the VFS' inode. When we replace extents in + * a range (clone, dedupe, fallocate's zero range), we must update the number of + * bytes used by the inode in an atomic manner, so that concurrent stat(2) calls + * always get a correct value. + */ +void btrfs_update_inode_bytes(struct btrfs_inode *inode, + const u64 add_bytes, + const u64 del_bytes) +{ + if (add_bytes == del_bytes) + return; + + spin_lock(&inode->lock); + if (del_bytes > 0) + inode_sub_bytes(&inode->vfs_inode, del_bytes); + if (add_bytes > 0) + inode_add_bytes(&inode->vfs_inode, add_bytes); + spin_unlock(&inode->lock); +} + static const struct inode_operations btrfs_dir_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = btrfs_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = btrfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = btrfs_syno_get_inode_archive_version, + .syno_set_archive_version = btrfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = btrfs_syno_get_crtime, + .syno_set_crtime = btrfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_locker_mode_get = btrfs_syno_locker_mode_get, + .syno_locker_state_get = btrfs_syno_locker_state_get, + .syno_locker_state_set = btrfs_syno_locker_state_set, + .syno_locker_period_end_set = btrfs_syno_locker_period_end_set, +#endif /* MY_ABC_HERE */ .getattr = btrfs_getattr, .lookup = btrfs_lookup, .create = btrfs_create, @@ -10390,6 +12753,12 @@ static const struct inode_operations btrfs_dir_inode_operations = { .permission = btrfs_permission, .get_acl = btrfs_get_acl, .set_acl = btrfs_set_acl, +#ifdef MY_ABC_HERE + .syno_get_acl = btrfs_get_syno_acl, + .syno_set_acl = btrfs_set_syno_acl, + .syno_permission = btrfs_syno_permission, + .syno_may_delete = btrfs_syno_may_delete, +#endif /* MY_ABC_HERE */ .update_time = btrfs_update_time, .tmpfile = btrfs_tmpfile, }; @@ -10405,6 +12774,12 @@ static const struct file_operations btrfs_dir_file_operations = { #endif .release = btrfs_release_file, .fsync = btrfs_sync_file, +#ifdef MY_ABC_HERE + .quota_query = btrfs_quota_query, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_space_usage = btrfs_syno_space_usage, +#endif /* MY_ABC_HERE */ }; /* @@ -10437,6 +12812,26 @@ static const struct address_space_operations btrfs_aops = { }; static const struct inode_operations btrfs_file_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = btrfs_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = btrfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = btrfs_syno_get_inode_archive_version, + .syno_set_archive_version = btrfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = btrfs_syno_get_crtime, + .syno_set_crtime = btrfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_locker_mode_get = btrfs_syno_locker_mode_get, + .syno_locker_state_get = btrfs_syno_locker_state_get, + .syno_locker_state_set = btrfs_syno_locker_state_set, + .syno_locker_period_end_set = btrfs_syno_locker_period_end_set, +#endif /* MY_ABC_HERE */ .getattr = btrfs_getattr, .setattr = btrfs_setattr, .listxattr = btrfs_listxattr, @@ -10444,18 +12839,81 @@ static const struct inode_operations btrfs_file_inode_operations = { .fiemap = btrfs_fiemap, .get_acl = btrfs_get_acl, .set_acl = btrfs_set_acl, +#ifdef MY_ABC_HERE + .syno_get_acl = btrfs_get_syno_acl, + .syno_set_acl = btrfs_set_syno_acl, + .syno_permission = btrfs_syno_permission, + .syno_may_delete = btrfs_syno_may_delete, +#endif /* MY_ABC_HERE */ .update_time = btrfs_update_time, +#ifdef MY_ABC_HERE + .fsdev_activate = btrfs_fsdev_activate, + .fsdev_deactivate = btrfs_fsdev_deactivate, + .fsdev_mapping = btrfs_fsdev_mapping, +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + .syno_rbd_meta_file_activate = btrfs_rbd_meta_file_activate, + .syno_rbd_meta_file_deactivate = btrfs_rbd_meta_file_deactivate, + .syno_rbd_meta_file_mapping = btrfs_rbd_meta_file_mapping, +#endif /* MY_ABC_HERE */ }; static const struct inode_operations btrfs_special_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = btrfs_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = btrfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = btrfs_syno_get_inode_archive_version, + .syno_set_archive_version = btrfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = btrfs_syno_get_crtime, + .syno_set_crtime = btrfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_locker_mode_get = btrfs_syno_locker_mode_get, + .syno_locker_state_get = btrfs_syno_locker_state_get, + .syno_locker_state_set = btrfs_syno_locker_state_set, + .syno_locker_period_end_set = btrfs_syno_locker_period_end_set, +#endif /* MY_ABC_HERE */ .getattr = btrfs_getattr, .setattr = btrfs_setattr, .permission = btrfs_permission, .listxattr = btrfs_listxattr, .get_acl = btrfs_get_acl, .set_acl = btrfs_set_acl, +#ifdef MY_ABC_HERE + .syno_get_acl = btrfs_get_syno_acl, + .syno_set_acl = btrfs_set_syno_acl, + .syno_permission = btrfs_syno_permission, + .syno_may_delete = btrfs_syno_may_delete, +#endif /* MY_ABC_HERE */ .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_symlink_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = btrfs_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = btrfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = btrfs_syno_get_inode_archive_version, + .syno_set_archive_version = btrfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = btrfs_syno_get_crtime, + .syno_set_crtime = btrfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_locker_mode_get = btrfs_syno_locker_mode_get, + .syno_locker_state_get = btrfs_syno_locker_state_get, + .syno_locker_state_set = btrfs_syno_locker_state_set, + .syno_locker_period_end_set = btrfs_syno_locker_period_end_set, +#endif /* MY_ABC_HERE */ .get_link = page_get_link, .getattr = btrfs_getattr, .setattr = btrfs_setattr, @@ -10464,6 +12922,37 @@ static const struct inode_operations btrfs_symlink_inode_operations = { .update_time = btrfs_update_time, }; +#ifdef MY_ABC_HERE +/* Hash a string to an integer in a caseless way */ +static int btrfs_dentry_hash(const struct dentry *dentry, struct qstr *this) +{ + int ret; + u32 hash; + ret = btrfs_upper_name_hash(this->name, this->len, &hash); + if (!ret) + this->hash = hash; + return ret; +} + +/* return 1 on failure and 0 on success */ +static int btrfs_dentry_compare(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name, + int caseless) +{ + if (caseless) { + return syno_utf8_strcmp(str, name->name, len, name->len, NULL); + } else { + if (len != name->len) + return 1; + return dentry_cmp(dentry, name->name, name->len); + } +} +#endif /* MY_ABC_HERE */ + const struct dentry_operations btrfs_dentry_operations = { .d_delete = btrfs_dentry_delete, +#ifdef MY_ABC_HERE + .d_hash = btrfs_dentry_hash, + .d_compare_case = btrfs_dentry_compare, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 040db0dfba26..8393d6f918c7 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -47,6 +50,12 @@ #include "space-info.h" #include "delalloc-space.h" #include "block-group.h" +#ifdef MY_ABC_HERE +#include "reflink.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include "syno-feat-tree.h" +#endif /* MY_ABC_HERE */ #ifdef CONFIG_64BIT /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI @@ -66,7 +75,17 @@ struct btrfs_ioctl_received_subvol_args_32 { struct btrfs_ioctl_timespec_32 stime; /* in */ struct btrfs_ioctl_timespec_32 rtime; /* out */ __u64 flags; /* in */ +#ifdef MY_ABC_HERE + struct btrfs_ioctl_timespec_32 otime; /* in */ + // why 2 reserved is used(64+64=128bits) but + // otime only occupies 64+32=96(bits) + // This is for compatible to 32bits userspace + // After this change, sizeof(btrfs_ioctl_received_subvol_args_32) + // changed from 192 bytes to 188 bytes; + __u64 reserved[14]; +#else /* MY_ABC_HERE */ __u64 reserved[16]; /* in */ +#endif /* MY_ABC_HERE */ } __attribute__ ((__packed__)); #define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \ @@ -159,6 +178,19 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg) struct btrfs_inode *binode = BTRFS_I(file_inode(file)); unsigned int flags = btrfs_inode_flags_to_fsflags(binode->flags); +#ifdef MY_ABC_HERE + int ret; + enum locker_state state; + + ret = syno_op_locker_state_get(file_inode(file), &state); + if (!ret) { + if (IS_LOCKER_STATE_IMMUTABLE(state)) + flags |= FS_IMMUTABLE_FL; + if (IS_LOCKER_STATE_APPENDABLE(state)) + flags |= FS_APPEND_FL; + } +#endif /* MY_ABC_HERE */ + if (copy_to_user(arg, &flags, sizeof(flags))) return -EFAULT; return 0; @@ -222,10 +254,42 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) fsflags = btrfs_mask_fsflags_for_type(inode, fsflags); old_fsflags = btrfs_inode_flags_to_fsflags(binode->flags); +#ifdef MY_ABC_HERE + /* + * after locker mode is set, tranditional IMMUTABLE_LF and APPEND_FL are + * not allowed to prevent the mixed behavior with locker. + */ + spin_lock(&root->locker_lock); + if (root->locker_mode != LM_NONE && (fsflags & (FS_IMMUTABLE_FL|FS_APPEND_FL))) { + ret = -EPERM; + spin_unlock(&root->locker_lock); + goto out_unlock; + } + spin_unlock(&root->locker_lock); +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + /* + * we use IMMUTABLE & SWAPFILE protected data, + */ + if (IS_SWAPFILE(inode) && + ((fsflags ^ old_fsflags) & FS_IMMUTABLE_FL)) { + ret = -ETXTBSY; + goto out_unlock; + } +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags); if (ret) goto out_unlock; +#ifdef MY_ABC_HERE + if (fsflags & FS_NOCOW_FL) { + fsflags &= ~(FS_COMPR_FL | FS_NOCOMP_FL); + old_fsflags &= ~(FS_COMPR_FL | FS_NOCOMP_FL); + } +#endif /* MY_ABC_HERE */ + ret = check_fsflags(old_fsflags, fsflags); if (ret) goto out_unlock; @@ -301,7 +365,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) comp = btrfs_compress_type2str(fs_info->compress_type); if (!comp || comp[0] == 0) +#ifdef MY_ABC_HERE + comp = btrfs_compress_type2str(BTRFS_COMPRESS_DEFAULT); +#else comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB); +#endif /* MY_ABC_HERE */ } else { binode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); } @@ -553,7 +621,11 @@ static noinline int btrfs_ioctl_fitrim(struct btrfs_fs_info *fs_info, return -EINVAL; range.minlen = max(range.minlen, minlen); - ret = btrfs_trim_fs(fs_info, &range); + ret = btrfs_trim_fs(fs_info, &range +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); if (ret < 0) return ret; @@ -563,6 +635,51 @@ static noinline int btrfs_ioctl_fitrim(struct btrfs_fs_info *fs_info, return 0; } +#ifdef MY_ABC_HERE +static noinline int btrfs_ioctl_hint_unused(struct file *file, void __user *arg) +{ + struct fstrim_range range; + struct btrfs_fs_info *fs_info = btrfs_sb(file_inode(file)->i_sb); + struct btrfs_device *device; + u64 num_devices = 0; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + rcu_read_lock(); + list_for_each_entry_rcu(device, &fs_info->fs_devices->devices, + dev_list) { + if (!device->bdev) + continue; + if (blk_queue_unused_hint(bdev_get_queue(device->bdev))) + num_devices++; + } + rcu_read_unlock(); + + if (!num_devices) + return -EOPNOTSUPP; + + if (copy_from_user(&range, (struct fstrim_range __user *)arg, + sizeof(range))) + return -EFAULT; + + /* + * NOTE: Don't truncate the range using super->total_bytes. Bytenr of + * block group is in the logical address space, which can be any + * sectorsize aligned bytenr in the range [0, U64_MAX]. + */ + if (range.len < fs_info->sb->s_blocksize) + return -EINVAL; + + ret = btrfs_trim_fs(fs_info, &range, TRIM_SEND_HINT); + if (!ret) + btrfs_notice(fs_info, "total send %llu bytes hints", range.len); + + return ret; +} +#endif /* MY_ABC_HERE */ + int __pure btrfs_is_empty_uuid(u8 *uuid) { int i; @@ -591,11 +708,21 @@ static noinline int create_subvol(struct inode *dir, struct timespec64 cur_time = current_time(dir); struct inode *inode; int ret; - int err; - dev_t anon_dev = 0; + dev_t anon_dev; u64 objectid; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; u64 index = 0; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE || + MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_syno_usage_root_status syno_usage_root_status; +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) + struct btrfs_new_fs_root_args *new_fs_root_args = NULL; +#endif /* MY_ABC_HERE */ root_item = kzalloc(sizeof(*root_item), GFP_KERNEL); if (!root_item) @@ -603,11 +730,7 @@ static noinline int create_subvol(struct inode *dir, ret = btrfs_find_free_objectid(fs_info->tree_root, &objectid); if (ret) - goto fail_free; - - ret = get_anon_bdev(&anon_dev); - if (ret < 0) - goto fail_free; + goto out_root_item; /* * Don't create subvolume whose level is not zero. Or qgroup will be @@ -615,36 +738,80 @@ static noinline int create_subvol(struct inode *dir, */ if (btrfs_qgroup_level(objectid)) { ret = -ENOSPC; - goto fail_free; + goto out_root_item; } + ret = get_anon_bdev(&anon_dev); + if (ret < 0) + goto out_root_item; + +#if defined(MY_ABC_HERE) + new_fs_root_args = btrfs_alloc_new_fs_root_args(); + if (IS_ERR(new_fs_root_args)) { + ret = PTR_ERR(new_fs_root_args); + new_fs_root_args = NULL; + goto out_root_item; + } +#endif /* MY_ABC_HERE */ + btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); /* * The same as the snapshot creation, please see the comment * of create_snapshot(). */ +#ifdef MY_ABC_HERE + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // 1 for xattr to store archive bit + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + // 1 for syno_usage_root_status_item + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + credit_for_syno++; +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8 + credit_for_syno, false); +#else /* MY_ABC_HERE || MY_ABC_HERE || \ + MY_ABC_HERE || MY_ABC_HERE */ ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false); +#endif /* MY_ABC_HERE || MY_ABC_HERE || + MY_ABC_HERE || MY_ABC_HERE */ if (ret) - goto fail_free; + goto out_anon_dev; trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); btrfs_subvolume_release_metadata(root, &block_rsv); - goto fail_free; + goto out_anon_dev; } trans->block_rsv = &block_rsv; trans->bytes_reserved = block_rsv.size; ret = btrfs_qgroup_inherit(trans, 0, objectid, inherit); if (ret) - goto fail; + goto out; +#ifdef MY_ABC_HERE + ret = btrfs_usrquota_mksubvol(trans, objectid); + if (ret) + goto out; +#endif /* MY_ABC_HERE */ leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0, BTRFS_NESTING_NORMAL); if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); - goto fail; + goto out; } btrfs_mark_buffer_dirty(leaf); @@ -657,6 +824,11 @@ static noinline int create_subvol(struct inode *dir, fs_info->nodesize); btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags)) + btrfs_set_root_flags(root_item, BTRFS_ROOT_SUBVOL_CMPR_RATIO); + else +#endif /* MY_ABC_HERE */ btrfs_set_root_flags(root_item, 0); btrfs_set_root_limit(root_item, 0); btrfs_set_stack_inode_flags(inode_item, BTRFS_INODE_ROOT_ITEM_INIT); @@ -697,21 +869,54 @@ static noinline int create_subvol(struct inode *dir, */ btrfs_free_tree_block(trans, root, leaf, 0, 1); free_extent_buffer(leaf); - goto fail; + goto out; } free_extent_buffer(leaf); leaf = NULL; +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) { + btrfs_syno_usage_root_status_init(&syno_usage_root_status, NULL, false, false); + ret = btrfs_syno_usage_root_status_update(trans, objectid, &syno_usage_root_status); + if (ret) + goto out; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + struct syno_quota_rescan_item_updater updater; + + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_DONE; + updater.version = BTRFS_QGROUP_V2_STATUS_VERSION; + updater.rescan_inode = (u64)-1; + updater.end_inode = (u64)-1; + updater.tree_size = 0; + updater.next_root = 0; + ret = btrfs_add_update_syno_quota_rescan_item(trans, fs_info->quota_root, + objectid, &updater); + if (ret) + btrfs_warn(fs_info, + "Failed to create syno quota rescan item for root %llu, ret = %d", + objectid, ret); + ret = 0; // No need to abort transaction, we can fix it by doing a quota rescan. + } +#endif /* MY_ABC_HERE */ + key.offset = (u64)-1; - new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev); + new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev +#if defined(MY_ABC_HERE) + , new_fs_root_args +#endif /* MY_ABC_HERE */ + ); if (IS_ERR(new_root)) { - free_anon_bdev(anon_dev); ret = PTR_ERR(new_root); btrfs_abort_transaction(trans, ret); - goto fail; + goto out; } - /* Freeing will be done in btrfs_put_root() of new_root */ + /* anon_dev is owned by new_root now. */ anon_dev = 0; btrfs_record_root_in_trans(trans, new_root); @@ -721,7 +926,7 @@ static noinline int create_subvol(struct inode *dir, if (ret) { /* We potentially lose an unused inode item here */ btrfs_abort_transaction(trans, ret); - goto fail; + goto out; } mutex_lock(&new_root->objectid_mutex); @@ -734,28 +939,28 @@ static noinline int create_subvol(struct inode *dir, ret = btrfs_set_inode_index(BTRFS_I(dir), &index); if (ret) { btrfs_abort_transaction(trans, ret); - goto fail; + goto out; } ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key, BTRFS_FT_DIR, index); if (ret) { btrfs_abort_transaction(trans, ret); - goto fail; + goto out; } btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2); ret = btrfs_update_inode(trans, root, dir); if (ret) { btrfs_abort_transaction(trans, ret); - goto fail; + goto out; } ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid, btrfs_ino(BTRFS_I(dir)), index, name, namelen); if (ret) { btrfs_abort_transaction(trans, ret); - goto fail; + goto out; } ret = btrfs_uuid_tree_add(trans, root_item->uuid, @@ -763,40 +968,59 @@ static noinline int create_subvol(struct inode *dir, if (ret) btrfs_abort_transaction(trans, ret); -fail: - kfree(root_item); +out: trans->block_rsv = NULL; trans->bytes_reserved = 0; btrfs_subvolume_release_metadata(root, &block_rsv); - err = btrfs_commit_transaction(trans); - if (err && !ret) - ret = err; + if (ret) + btrfs_end_transaction(trans); + else + ret = btrfs_commit_transaction(trans); if (!ret) { +#ifdef MY_ABC_HERE + inode = btrfs_lookup_dentry(dir, dentry, 0); +#else /* MY_ABC_HERE */ inode = btrfs_lookup_dentry(dir, dentry); +#endif /* MY_ABC_HERE */ if (IS_ERR(inode)) return PTR_ERR(inode); d_instantiate(dentry, inode); } - return ret; - -fail_free: +out_anon_dev: if (anon_dev) free_anon_bdev(anon_dev); +out_root_item: +#if defined(MY_ABC_HERE) + btrfs_free_new_fs_root_args(new_fs_root_args); +#endif /* MY_ABC_HERE */ kfree(root_item); return ret; } static int create_snapshot(struct btrfs_root *root, struct inode *dir, struct dentry *dentry, bool readonly, - struct btrfs_qgroup_inherit *inherit) + struct btrfs_qgroup_inherit *inherit +#ifdef MY_ABC_HERE + ,u64 copy_limit_from +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); struct inode *inode; struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_trans_handle *trans; int ret; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) \ + || defined(MY_ABC_HERE) + int credit_for_syno = 0; +#endif /* MY_ABC_HERE || MY_ABC_HERE + || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u64 reserve_usrquota_items = 0; + u64 reserve_usrquota_leafs = 0; +#endif /* MY_ABC_HERE */ if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state)) return -EINVAL; @@ -811,9 +1035,43 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, if (!pending_snapshot) return -ENOMEM; +#ifdef MY_ABC_HERE + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) || + test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + ret = usrquota_subtree_load(fs_info, root->root_key.objectid); + if (ret) + btrfs_warn(fs_info, + "failed to load usrquota subtree %llu", root->root_key.objectid); + + if (!ret && copy_limit_from) + ret = usrquota_subtree_load(fs_info, copy_limit_from); + if (ret) + btrfs_warn(fs_info, + "failed to load usrquota subtree %llu", copy_limit_from); + + if (ret) { + ret = -ENOENT; + mutex_unlock(&fs_info->usrquota_ioctl_lock); + goto free_pending; + } + } + mutex_unlock(&fs_info->usrquota_ioctl_lock); +#endif /* MY_ABC_HERE */ + ret = get_anon_bdev(&pending_snapshot->anon_dev); if (ret < 0) goto free_pending; + +#if defined(MY_ABC_HERE) + pending_snapshot->new_fs_root_args = btrfs_alloc_new_fs_root_args(); + if (IS_ERR(pending_snapshot->new_fs_root_args)) { + ret = PTR_ERR(pending_snapshot->new_fs_root_args); + pending_snapshot->new_fs_root_args = NULL; + goto free_pending; + } +#endif /* MY_ABC_HERE */ + pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item), GFP_KERNEL); pending_snapshot->path = btrfs_alloc_path(); @@ -832,9 +1090,37 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, * 1 - root of snapshot * 1 - UUID item */ + +#ifdef MY_ABC_HERE + ret = btrfs_usrquota_calc_reserve_snap(root, copy_limit_from, &reserve_usrquota_items); + if (ret < 0) + goto free_pending; + reserve_usrquota_leafs = 1 + div_u64(reserve_usrquota_items, + (u32)BTRFS_USRQUOTA_MAX_ITEMS_LEAF(fs_info)); + credit_for_syno += (int)reserve_usrquota_leafs; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + // 1 for dir_item_caseless + if (btrfs_super_compat_flags(fs_info->super_copy) & BTRFS_FEATURE_COMPAT_SYNO_CASELESS) + credit_for_syno++; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + // 1 for syno_usage_root_status_item + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + credit_for_syno++; +#endif /*MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, + &pending_snapshot->block_rsv, + 8 + credit_for_syno, + false); +#else /* MY_ABC_HERE || MY_ABC_HERE */ ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, &pending_snapshot->block_rsv, 8, false); +#endif /* MY_ABC_HERE || MY_ABC_HERE*/ if (ret) goto free_pending; @@ -843,6 +1129,9 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, pending_snapshot->readonly = readonly; pending_snapshot->dir = dir; pending_snapshot->inherit = inherit; +#ifdef MY_ABC_HERE + pending_snapshot->copy_limit_from = copy_limit_from; +#endif /* MY_ABC_HERE */ trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { @@ -867,7 +1156,11 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, if (ret) goto fail; +#ifdef MY_ABC_HERE + inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry, 0); +#else /* MY_ABC_HERE */ inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry); +#endif /* MY_ABC_HERE */ if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; @@ -885,9 +1178,21 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, free_pending: if (pending_snapshot->anon_dev) free_anon_bdev(pending_snapshot->anon_dev); +#if defined(MY_ABC_HERE) + btrfs_free_new_fs_root_args(pending_snapshot->new_fs_root_args); +#endif /* MY_ABC_HERE */ kfree(pending_snapshot->root_item); btrfs_free_path(pending_snapshot->path); kfree(pending_snapshot); +#ifdef MY_ABC_HERE + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) || + test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + usrquota_subtree_unload(fs_info, root->root_key.objectid); + usrquota_subtree_unload(fs_info, copy_limit_from); + } + mutex_unlock(&fs_info->usrquota_ioctl_lock); +#endif /* MY_ABC_HERE */ return ret; } @@ -927,9 +1232,19 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) return error; if (IS_APPEND(dir)) return -EPERM; + +#ifdef MY_ABC_HERE + if ((IS_APPEND(d_inode(victim)) || IS_IMMUTABLE(d_inode(victim))) && + !IS_EXPIRED(d_inode(victim))) + return -EPERM; + if (check_sticky(dir, d_inode(victim)) || IS_SWAPFILE(d_inode(victim))) + return -EPERM; +#else if (check_sticky(dir, d_inode(victim)) || IS_APPEND(d_inode(victim)) || IS_IMMUTABLE(d_inode(victim)) || IS_SWAPFILE(d_inode(victim))) return -EPERM; +#endif /* MY_ABC_HERE */ + if (isdir) { if (!d_is_dir(victim)) return -ENOTDIR; @@ -963,7 +1278,11 @@ static noinline int btrfs_mksubvol(const struct path *parent, const char *name, int namelen, struct btrfs_root *snap_src, bool readonly, - struct btrfs_qgroup_inherit *inherit) + struct btrfs_qgroup_inherit *inherit +#ifdef MY_ABC_HERE + ,u64 copy_limit_from +#endif /* MY_ABC_HERE */ + ) { struct inode *dir = d_inode(parent->dentry); struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); @@ -988,8 +1307,13 @@ static noinline int btrfs_mksubvol(const struct path *parent, * check for them now when we can safely fail */ error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root, - dir->i_ino, name, - namelen); + dir->i_ino, + name, + namelen +#ifdef MY_ABC_HERE + , 1 +#endif /* MY_ABC_HERE */ + ); if (error) goto out_dput; @@ -999,7 +1323,11 @@ static noinline int btrfs_mksubvol(const struct path *parent, goto out_up_read; if (snap_src) - error = create_snapshot(snap_src, dir, dentry, readonly, inherit); + error = create_snapshot(snap_src, dir, dentry, readonly, inherit +#ifdef MY_ABC_HERE + ,copy_limit_from +#endif /* MY_ABC_HERE */ + ); else error = create_subvol(dir, dentry, name, namelen, inherit); @@ -1018,7 +1346,11 @@ static noinline int btrfs_mksnapshot(const struct path *parent, const char *name, int namelen, struct btrfs_root *root, bool readonly, - struct btrfs_qgroup_inherit *inherit) + struct btrfs_qgroup_inherit *inherit +#ifdef MY_ABC_HERE + ,u64 copy_limit_from +#endif /* MY_ABC_HERE */ + ) { int ret; bool snapshot_force_cow = false; @@ -1045,7 +1377,11 @@ static noinline int btrfs_mksnapshot(const struct path *parent, btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1); ret = btrfs_mksubvol(parent, name, namelen, - root, readonly, inherit); + root, readonly, inherit +#ifdef MY_ABC_HERE + ,copy_limit_from +#endif /* MY_ABC_HERE */ + ); out: if (snapshot_force_cow) atomic_dec(&root->snapshot_force_cow); @@ -1204,6 +1540,355 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) return ret; } +#ifdef MY_ABC_HERE +/* + * Check if extent item usage is below threshold, this traverse the file + * extent data item in the way that clone range does. + */ +static int reclaim_check_extent_usage(struct inode *inode, + struct btrfs_ioctl_defrag_range_args *range, + struct ulist *disko_ulist, u64 start, u64 *endoff, u64 *release_size) +{ + int ret = 0; + int extent_rewrite = 0; + int slot; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct ulist_node *unode; + struct btrfs_path *path = NULL; + struct btrfs_file_extent_item *item; + struct extent_buffer *leaf; + struct btrfs_key key; + struct btrfs_inode *binode = BTRFS_I(inode); + u8 type; + u64 extent_item_use = 0; + u32 syno_ratio_denom = 3; // Use 2/3 as default value + u32 syno_ratio_nom = 2; + u32 syno_thresh = 8 * 1024 * 1024; // Default thresh is 8MiB + u64 extent_disko = 0; + u64 extent_ram_bytes = 0; + u64 extent_datao = 0; + u64 num_bytes; + u64 search_end = 0; + u32 nritems; + u64 relative_offset; + bool skip_cross_ref_check = false, strict = false; + + if (range->syno_ratio_denom != 0 && range->syno_ratio_nom != 0) { + syno_ratio_denom = range->syno_ratio_denom; + syno_ratio_nom = range->syno_ratio_nom; + } + if (range->syno_thresh != 0) + syno_thresh = (u32)range->syno_thresh * 4096; + if (range->flags & BTRFS_DEFRAG_RANGE_SKIP_CROSS_REF_CHECK) + skip_cross_ref_check = true; + else if (range->flags & BTRFS_DEFRAG_RANGE_SKIP_FAST_SNAPSHOT_CHECK) + strict = true; + + path = btrfs_alloc_path(); + if (!path) { + extent_rewrite = -ENOMEM; + goto out; + } + + path->reada = READA_FORWARD; + path->leave_spinning = 1; + + key.objectid = btrfs_ino(binode); + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = start; + +again: + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + extent_rewrite = ret; + goto out; + } + + /* + * First search, if no extent item that starts at offset off was + * found but the previous item is an extent item, it's possible + * it might overlap our target range, therefore process it. + */ + if (key.offset == start && ret > 0 && path->slots[0] > 0) { + btrfs_item_key_to_cpu(path->nodes[0], &key, + path->slots[0] - 1); + if (key.type == BTRFS_EXTENT_DATA_KEY) + path->slots[0]--; + } + nritems = btrfs_header_nritems(path->nodes[0]); + if (path->slots[0] >= nritems) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) { + extent_rewrite = ret; + goto out; + } + if (ret > 0) { + *endoff = (u64) -1; // skip to the end + goto out; + } + } + leaf = path->nodes[0]; + slot = path->slots[0]; + + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.type > BTRFS_EXTENT_DATA_KEY || + key.objectid != btrfs_ino(binode)) { + *endoff = (u64) -1; // skip to the end + goto out; + } + + if (key.type != BTRFS_EXTENT_DATA_KEY) { + btrfs_release_path(path); + key.offset++; + goto again; + } + item = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + type = btrfs_file_extent_type(leaf, item); + if (type == BTRFS_FILE_EXTENT_INLINE) { + *endoff = (u64)-1; // skip to the end + goto out; + } + extent_disko = btrfs_file_extent_disk_bytenr(leaf, item); + extent_ram_bytes = btrfs_file_extent_ram_bytes(leaf, item); + extent_datao = btrfs_file_extent_offset(leaf, item); + num_bytes = btrfs_file_extent_num_bytes(leaf, item); + + *endoff = key.offset + num_bytes - 1; + if (extent_disko == 0) + goto out; + + unode = ulist_search(disko_ulist, extent_disko); + if (unode) { + btrfs_free_path(path); + return unode->aux; + } + + if (btrfs_file_extent_compression(leaf, item) || + btrfs_file_extent_encryption(leaf, item) || + btrfs_file_extent_other_encoding(leaf, item) || + btrfs_extent_readonly(root->fs_info, extent_disko)) + goto add_list; + +#ifdef MY_ABC_HERE + if (skip_cross_ref_check) { + // don't cow the data which we already dedupe while deduping reclaim + if (BTRFS_FILE_EXTENT_DEDUPED & btrfs_file_extent_syno_flag(leaf, item)) + goto add_list; + } +#endif + + /* + * If this EXTENT_ITEM spans across the file offset beyond our range, + * don't defrag it. + */ + relative_offset = key.offset - extent_datao; + if (relative_offset >= LLONG_MAX) + relative_offset = 0; + if (relative_offset < range->start) + goto add_list; + + btrfs_release_path(path); + + if (!skip_cross_ref_check) { + /* + * There's possible race between the time this check is done + * and before we actuaully rewrite all extent data key that + * reference this extent item. + */ + ret = btrfs_cross_ref_exist(root, btrfs_ino(binode), + key.offset - extent_datao, extent_disko, strict); + if (ret) + goto add_list; + } + + extent_item_use = num_bytes; + search_end = key.offset + extent_ram_bytes - extent_datao; + key.offset += num_bytes; + while (1) { + u64 disko, datal; + u64 next_key_min_offset = key.offset + 1; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + extent_rewrite = ret; + goto out; + } + nritems = btrfs_header_nritems(path->nodes[0]); + if (path->slots[0] >= nritems) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) { + extent_rewrite = ret; + goto out; + } + if (ret > 0) + break; + } + leaf = path->nodes[0]; + slot = path->slots[0]; + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.type != BTRFS_EXTENT_DATA_KEY || + key.objectid != btrfs_ino(binode)) + break; + if (key.offset > search_end) + break; + item = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + type = btrfs_file_extent_type(leaf, item); + if (type == BTRFS_FILE_EXTENT_INLINE) + goto next; + disko = btrfs_file_extent_disk_bytenr(leaf, item); + datal = btrfs_file_extent_num_bytes(leaf, item); + next_key_min_offset = key.offset + datal; + /* + * This extent data points to a hole + */ + if (disko == 0) + goto next; + /* + * <---written---><---prealloc---> + * <------- extent item 1 -------> + * There are some parts of extent that are prealloc, so don't + * rewrite this. Otherwise, we'll end up like the following, + * <---written---> <---prealloc---> + * <------- extent item 1 -------> + */ + if (disko != extent_disko) + goto next; + if (type == BTRFS_FILE_EXTENT_PREALLOC) + goto add_list; + /* + * If this EXTENT_ITEM spans across the file offset beyond our range, + * don't reclaim it. + */ + if (range->len != (u64) -1 && range->len != 0 && + key.offset + datal > range->start + range->len) + goto add_list; + extent_item_use += datal; +next: + btrfs_release_path(path); + key.offset = next_key_min_offset; + } + if (extent_item_use * syno_ratio_denom <= extent_ram_bytes * syno_ratio_nom || + extent_ram_bytes >= extent_item_use + syno_thresh) { + extent_rewrite = 1; + *release_size += extent_ram_bytes - extent_item_use; + } +add_list: + btrfs_release_path(path); + /* + * bytenr is stored in val. + * If the extent_item is to be rewritten, we have aux = 1. + * Otherwise, aux = 0. + */ + if (ulist_add_lru_adjust(disko_ulist, extent_disko, extent_rewrite, GFP_NOFS) && + disko_ulist->nnodes > ULIST_NODES_MAX) + ulist_remove_first(disko_ulist); +out: + btrfs_free_path(path); + return extent_rewrite; +} + +static int reclaim_check_partial_used(struct inode *inode, u64 start, u64 *endoff, + struct ulist *fileo_ulist, u64 *rewrite_size) +{ + int ret = 0; + int slot; + int extent_rewrite = 0; + u64 disk_offset = 0, disk_bytenr = 0; + u64 file_extent_start = 0, file_extent_num_bytes = 0; + struct ulist_node *unode; + struct btrfs_key key; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_path *path = NULL; + struct btrfs_file_extent_item *item; + struct extent_buffer *leaf; + + path = btrfs_alloc_path(); + if (!path) { + extent_rewrite = -ENOMEM; + goto out; + } + + ret = btrfs_lookup_file_extent_by_file_offset(NULL, root, path, + btrfs_ino(BTRFS_I(inode)), start, 0); + if (0 > ret) { + extent_rewrite = ret; + goto out; + } + + leaf = path->nodes[0]; + slot = path->slots[0]; + + btrfs_item_key_to_cpu(leaf, &key, slot); + item = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + + disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, item); + disk_offset = btrfs_file_extent_offset(leaf, item); + file_extent_num_bytes = btrfs_file_extent_num_bytes(leaf, item); + file_extent_start = key.offset; + + *endoff = key.offset + file_extent_num_bytes - 1; + + unode = ulist_search(fileo_ulist, file_extent_start); + if (unode) { + extent_rewrite = unode->aux; + goto out; + } + + if (BTRFS_FILE_EXTENT_REG != btrfs_file_extent_type(leaf, item) || + btrfs_file_extent_compression(leaf, item) || + btrfs_file_extent_encryption(leaf, item) || + btrfs_file_extent_other_encoding(leaf, item) || + btrfs_extent_readonly(root->fs_info, disk_bytenr)) + goto out; + + /* skip full used and hole */ + if (file_extent_num_bytes >= btrfs_file_extent_disk_num_bytes(leaf, item)) + goto out; + +#ifdef MY_ABC_HERE + // don't cow the data which we already dedupe while deduping reclaim + if (BTRFS_FILE_EXTENT_DEDUPED & btrfs_file_extent_syno_flag(leaf, item)) + goto out; +#endif + extent_rewrite = 1; + *rewrite_size += file_extent_num_bytes; + +out: + if (ulist_add_lru_adjust(fileo_ulist, file_extent_start, extent_rewrite, GFP_NOFS) && + fileo_ulist->nnodes > ULIST_NODES_MAX) + ulist_remove_first(fileo_ulist); + + btrfs_free_path(path); + return extent_rewrite; +} + +static int should_force_reclaim_range(struct inode *inode, u64 start, + u64 *skip, u64 *defrag_end, struct ulist *fileo_ulist, + u64 *rewrite_size) +{ + int ret; + + ret = reclaim_check_partial_used(inode, start, skip, fileo_ulist, rewrite_size); + *defrag_end = *skip; + return ret; +} + +static int should_reclaim_range(struct inode *inode, u64 start, + u64 *skip, u64 *defrag_end, + struct btrfs_ioctl_defrag_range_args *range, + struct ulist *disko_ulist, + u64 *release_size) +{ + int ret; + + ret = reclaim_check_extent_usage(inode, range, + disko_ulist, start, skip, release_size); + *defrag_end = *skip; + return ret; +} +#endif /* MY_ABC_HERE */ + + static int should_defrag_range(struct inode *inode, u64 start, u32 thresh, u64 *last_len, u64 *skip, u64 *defrag_end, int compress) @@ -1276,7 +1961,11 @@ static int should_defrag_range(struct inode *inode, u64 start, u32 thresh, * It's a good idea to start RA on this range * before calling this. */ +#ifdef MY_ABC_HERE +int cluster_pages_for_defrag(struct inode *inode, +#else static int cluster_pages_for_defrag(struct inode *inode, +#endif /* MY_ABC_HERE */ struct page **pages, unsigned long start_index, unsigned long num_pages) @@ -1465,6 +2154,10 @@ static int cluster_pages_for_defrag(struct inode *inode, } +#ifdef MY_ABC_HERE +extern int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off); +#endif /* MY_ABC_HERE */ + int btrfs_defrag_file(struct inode *inode, struct file *file, struct btrfs_ioctl_defrag_range_args *range, u64 newer_than, unsigned long max_to_defrag) @@ -1482,7 +2175,26 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, unsigned long ra_index = 0; int ret; int defrag_count = 0; +#ifdef MY_ABC_HERE + int compress_type = BTRFS_COMPRESS_DEFAULT; +#else int compress_type = BTRFS_COMPRESS_ZLIB; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u64 last_rec_pos = 0; + u64 one_tenth_isize = i_size_read(inode) / 10; + int should_defrag_range_ret = 0; + int defrag_success = 0; + struct ulist *disko_ulist = NULL; + struct ulist *fileo_ulist = NULL; + struct ulist *orig_extent = NULL; + time64_t last_show = ktime_get_seconds(); + int print_stdout = 0; + u64 release_size = 0, rewrite_size = 0; + struct file *file_stdout = NULL; + loff_t off; + char buf[512]; +#endif /* MY_ABC_HERE */ u32 extent_thresh = range->extent_thresh; unsigned long max_cluster = SZ_256K >> PAGE_SHIFT; unsigned long cluster = max_cluster; @@ -1493,6 +2205,24 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, if (isize == 0) return 0; +#ifdef MY_ABC_HERE + if (range->flags & BTRFS_DEFRAG_RANGE_SYNO_DEFRAG && + range->flags & BTRFS_DEFRAG_RANGE_PRINT_STDOUT) { + memset(buf, 0, sizeof(buf)); + off = 0; + snprintf(buf, sizeof(buf), "[syno defrag] root:%llu ino:%llu " + "start:%llu len:%llu thresh:%u dem:%u nom:%u\n", + root->root_key.objectid, btrfs_ino(BTRFS_I(inode)), + range->start, range->len, + range->syno_thresh, range->syno_ratio_denom, + range->syno_ratio_nom); + file_stdout = fget(1); + write_buf(file_stdout, buf, sizeof(buf), &off); + if (one_tenth_isize < 256 * 1024 * 1024) + one_tenth_isize = 256 * 1024 * 1024; + } + i = 0; // To avoid use maybe-uninitialized warning +#endif /* MY_ABC_HERE */ if (range->start >= isize) return -EINVAL; @@ -1519,6 +2249,29 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, ra = &file->f_ra; } +#ifdef MY_ABC_HERE + if (range->flags & BTRFS_DEFRAG_RANGE_SYNO_DEFRAG) { + disko_ulist = ulist_alloc(GFP_NOFS); + if (!disko_ulist) { + ret = -ENOMEM; + goto out_ra; + } + } else if (range->flags & BTRFS_DEFRAG_RANGE_FORCE_RECLAIM) { + fileo_ulist = ulist_alloc(GFP_NOFS); + if (!fileo_ulist) { + ret = -ENOMEM; + goto out_ra; + } + orig_extent = ulist_alloc(GFP_NOFS); + if (!orig_extent) { + ret = -ENOMEM; + goto out_ra; + } + ret = get_extent_item_list(inode, range->start, range->len, orig_extent); + if (0 > ret) + goto out_ra; + } +#endif /* MY_ABC_HERE */ pages = kmalloc_array(max_cluster, sizeof(struct page *), GFP_KERNEL); if (!pages) { ret = -ENOMEM; @@ -1573,6 +2326,64 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, break; } +#ifdef MY_ABC_HERE + if (range->flags & BTRFS_DEFRAG_RANGE_SYNO_DEFRAG) { + if (range->flags & BTRFS_DEFRAG_RANGE_PRINT_STDOUT) { + if (((u64)i << PAGE_SHIFT) - last_rec_pos >= one_tenth_isize) { + last_rec_pos = (u64)i << PAGE_SHIFT; + print_stdout = 1; + } + if (print_stdout || ktime_get_seconds() - last_show > 60) { + memset(buf, 0, sizeof(buf)); + off = 0; + snprintf(buf, sizeof(buf), "[syno defrag status] root:%llu ino:%llu " + "progress:%lu/%lu release size:%llu\n", + root->root_key.objectid, btrfs_ino(BTRFS_I(inode)), + i, last_index, release_size); + write_buf(file_stdout, buf, sizeof(buf), &off); + last_show = ktime_get_seconds(); + print_stdout = 0; + } + } + should_defrag_range_ret = should_reclaim_range(inode, (u64)i << PAGE_SHIFT, + &skip, &defrag_end, range, disko_ulist, &release_size); + if (should_defrag_range_ret < 0) { + ret = should_defrag_range_ret; + goto out_ra; + } + if (!should_defrag_range_ret) { + unsigned long next; + if (skip == (u64) -1) + break; + /* + * the should_defrag function tells us how much to skip + * bump our counter by the suggested amount + */ + next = DIV_ROUND_UP(skip, PAGE_SIZE); + i = max(i + 1, next); + continue; + } + } else if (range->flags & BTRFS_DEFRAG_RANGE_FORCE_RECLAIM) { + should_defrag_range_ret = should_force_reclaim_range(inode, (u64)i << PAGE_SHIFT, + &skip, &defrag_end, fileo_ulist, &rewrite_size); + if (should_defrag_range_ret < 0) { + ret = should_defrag_range_ret; + goto out_ra; + } + if (!should_defrag_range_ret) { + unsigned long next; + if (skip == (u64) -1) + break; + /* + * the should_defrag function tells us how much to skip + * bump our counter by the suggested amount + */ + next = DIV_ROUND_UP(skip, PAGE_SIZE); + i = max(i + 1, next); + continue; + } + } else +#endif /* MY_ABC_HERE */ if (!should_defrag_range(inode, (u64)i << PAGE_SHIFT, extent_thresh, &last_len, &skip, &defrag_end, do_compress)){ @@ -1614,6 +2425,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, inode_unlock(inode); goto out_ra; } +#ifdef MY_ABC_HERE + defrag_success = 1; +#endif /* MY_ABC_HERE */ defrag_count += ret; balance_dirty_pages_ratelimited(inode->i_mapping); @@ -1648,6 +2462,11 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, } } +#ifdef MY_ABC_HERE + if (defrag_success && (range->flags & BTRFS_DEFRAG_RANGE_START_IO_RANGE)) { + btrfs_wait_ordered_range(inode, range->start, range->len); + } else +#endif /* MY_ABC_HERE */ if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) { filemap_flush(inode->i_mapping); if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, @@ -1669,6 +2488,33 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE; inode_unlock(inode); } +#ifdef MY_ABC_HERE + if (range->flags & BTRFS_DEFRAG_RANGE_SYNO_DEFRAG) { + if (range->flags & BTRFS_DEFRAG_RANGE_PRINT_STDOUT) { + memset(buf, 0, sizeof(buf)); + off = 0; + snprintf(buf, sizeof(buf), "[syno defrag] finish root:%llu ino:%llu " + "end_pos: %lu release size:%llu\n", + root->root_key.objectid, btrfs_ino(BTRFS_I(inode)), i, release_size); + write_buf(file_stdout, buf, sizeof(buf), &off); + } + range->release_size = release_size; + ulist_free(disko_ulist); + } else if (range->flags & BTRFS_DEFRAG_RANGE_FORCE_RECLAIM) { + u64 release_extent_size = 0; + if (!extent_same_release_size_accounting(orig_extent, root, &release_extent_size)) { + /* + * rewrite_size may larger than released in force reclaim, + * but range->release_size is unsigned, user space should handle it. + */ + range->release_size = release_extent_size - rewrite_size; + } + ulist_free(fileo_ulist); + ulist_free(orig_extent); + } + if (file_stdout) + fput(file_stdout); +#endif /* MY_ABC_HERE */ if (!file) kfree(ra); kfree(pages); @@ -1692,6 +2538,9 @@ static noinline int btrfs_ioctl_resize(struct file *file, char *devstr = NULL; int ret = 0; int mod = 0; +#ifdef MY_ABC_HERE + int dry_run = 0; +#endif /* MY_ABC_HERE */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1754,6 +2603,12 @@ static noinline int btrfs_ioctl_resize(struct file *file, } else if (sizestr[0] == '+') { mod = 1; sizestr++; +#ifdef MY_ABC_HERE + if (sizestr[0] == '?') { + dry_run = 1; + sizestr++; + } +#endif /* MY_ABC_HERE */ } new_size = memparse(sizestr, &retptr); if (*retptr != '\0' || new_size == 0) { @@ -1791,6 +2646,10 @@ static noinline int btrfs_ioctl_resize(struct file *file, ret = -EFBIG; goto out_free; } +#ifdef MY_ABC_HERE + if (dry_run) + goto out_free; +#endif /* MY_ABC_HERE */ new_size = round_down(new_size, fs_info->sectorsize); @@ -1822,7 +2681,11 @@ static noinline int btrfs_ioctl_resize(struct file *file, static noinline int __btrfs_ioctl_snap_create(struct file *file, const char *name, unsigned long fd, int subvol, bool readonly, - struct btrfs_qgroup_inherit *inherit) + struct btrfs_qgroup_inherit *inherit +#ifdef MY_ABC_HERE + ,u64 copy_limit_from +#endif /* MY_ABC_HERE */ + ) { int namelen; int ret = 0; @@ -1848,7 +2711,11 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, if (subvol) { ret = btrfs_mksubvol(&file->f_path, name, namelen, - NULL, readonly, inherit); + NULL, readonly, inherit +#ifdef MY_ABC_HERE + ,copy_limit_from +#endif /* MY_ABC_HERE */ + ); } else { struct fd src = fdget(fd); struct inode *src_inode; @@ -1871,7 +2738,11 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, } else { ret = btrfs_mksnapshot(&file->f_path, name, namelen, BTRFS_I(src_inode)->root, - readonly, inherit); + readonly, inherit +#ifdef MY_ABC_HERE + ,copy_limit_from +#endif /* MY_ABC_HERE */ + ); } fdput(src); } @@ -1896,7 +2767,11 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; ret = __btrfs_ioctl_snap_create(file, vol_args->name, vol_args->fd, - subvol, false, NULL); + subvol, false, NULL +#ifdef MY_ABC_HERE + ,0 +#endif /* MY_ABC_HERE */ + ); kfree(vol_args); return ret; @@ -1955,7 +2830,11 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, } ret = __btrfs_ioctl_snap_create(file, vol_args->name, vol_args->fd, - subvol, readonly, inherit); + subvol, readonly, inherit +#ifdef MY_ABC_HERE + ,vol_args->copy_limit_from +#endif /* MY_ABC_HERE */ + ); if (ret) goto free_inherit; free_inherit: @@ -1980,6 +2859,18 @@ static noinline int btrfs_ioctl_subvol_getflags(struct file *file, down_read(&fs_info->subvol_sem); if (btrfs_root_readonly(root)) flags |= BTRFS_SUBVOL_RDONLY; +#ifdef MY_ABC_HERE + if (btrfs_root_hide(root)) + flags |= BTRFS_SUBVOL_HIDE; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_root_disable_quota(root)) + flags |= BTRFS_SUBVOL_DISABLE_QUOTA; + if (btrfs_root_noload_usrquota(root)) + flags |= BTRFS_SUBVOL_NOLOAD_USRQUOTA; + if (btrfs_root_cmpr_ratio(root)) + flags |= BTRFS_SUBVOL_CMPR_RATIO; +#endif /* MY_ABC_HERE */ up_read(&fs_info->subvol_sem); if (copy_to_user(arg, &flags, sizeof(flags))) @@ -1998,6 +2889,11 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, u64 root_flags; u64 flags; int ret = 0; +#if defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) + u64 mask = BTRFS_SUBVOL_RDONLY; +#endif /* MY_ABC_HERE || + MY_ABC_HERE */ if (!inode_owner_or_capable(inode)) return -EPERM; @@ -2016,21 +2912,69 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, goto out_drop_write; } +#ifdef MY_ABC_HERE + mask |= BTRFS_SUBVOL_HIDE; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + mask |= BTRFS_SUBVOL_NOLOAD_USRQUOTA; + mask |= BTRFS_SUBVOL_CMPR_RATIO; + mask |= BTRFS_SUBVOL_DISABLE_QUOTA; +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) + if (flags & ~mask) { +#else if (flags & ~BTRFS_SUBVOL_RDONLY) { +#endif /* MY_ABC_HERE || + MY_ABC_HERE */ ret = -EOPNOTSUPP; goto out_drop_write; } down_write(&fs_info->subvol_sem); +#ifdef MY_ABC_HERE + if (!!(flags & BTRFS_SUBVOL_HIDE) != btrfs_root_hide(root)) + goto update_flags; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!!(flags & BTRFS_SUBVOL_DISABLE_QUOTA) != btrfs_root_disable_quota(root)) + goto update_flags; + if (!!(flags & BTRFS_SUBVOL_NOLOAD_USRQUOTA) != btrfs_root_noload_usrquota(root)) + goto update_flags; + if (!!(flags & BTRFS_SUBVOL_CMPR_RATIO) != btrfs_root_cmpr_ratio(root)) + goto update_flags; +#endif /* MY_ABC_HERE */ /* nothing to do */ if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) goto out_drop_sem; +#if defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) +update_flags: +#endif /* MY_ABC_HERE || + MY_ABC_HERE */ root_flags = btrfs_root_flags(&root->root_item); if (flags & BTRFS_SUBVOL_RDONLY) { btrfs_set_root_flags(&root->root_item, root_flags | BTRFS_ROOT_SUBVOL_RDONLY); +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) { + spin_lock(&root->syno_usage_lock); + if (!(root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY)) { + spin_lock(&fs_info->syno_usage_lock); + if (fs_info->syno_usage_status.total_syno_subvol_usage_items >= root->syno_usage_root_status.total_syno_subvol_usage_items) + fs_info->syno_usage_status.total_syno_subvol_usage_items -= root->syno_usage_root_status.total_syno_subvol_usage_items; + else + fs_info->syno_usage_status.total_syno_subvol_usage_items = 0; + spin_unlock(&fs_info->syno_usage_lock); + } + root->syno_usage_root_status.flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY; + spin_unlock(&root->syno_usage_lock); + } +#endif /* MY_ABC_HERE */ } else { /* * Block RO -> RW transition if this subvolume is involved in @@ -2040,6 +2984,19 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, if (root->send_in_progress == 0) { btrfs_set_root_flags(&root->root_item, root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) { + spin_lock(&root->syno_usage_lock); + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY) { + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.total_syno_subvol_usage_items += root->syno_usage_root_status.total_syno_subvol_usage_items; + spin_unlock(&fs_info->syno_usage_lock); + } + root->syno_usage_root_status.flags &= ~BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY; + spin_unlock(&root->syno_usage_lock); + } +#endif /* MY_ABC_HERE */ spin_unlock(&root->root_item_lock); } else { spin_unlock(&root->root_item_lock); @@ -2051,6 +3008,42 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, } } +#ifdef MY_ABC_HERE + root_flags = btrfs_root_flags(&root->root_item); + if (flags & BTRFS_SUBVOL_HIDE) + btrfs_set_root_flags(&root->root_item, + root_flags | BTRFS_ROOT_SUBVOL_HIDE); + else + btrfs_set_root_flags(&root->root_item, + root_flags & ~BTRFS_ROOT_SUBVOL_HIDE); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + root_flags = btrfs_root_flags(&root->root_item); + if (flags & BTRFS_SUBVOL_DISABLE_QUOTA) + btrfs_set_root_flags(&root->root_item, + root_flags | BTRFS_ROOT_SUBVOL_DISABLE_QUOTA); + else + btrfs_set_root_flags(&root->root_item, + root_flags & ~BTRFS_ROOT_SUBVOL_DISABLE_QUOTA); + + root_flags = btrfs_root_flags(&root->root_item); + if (flags & BTRFS_SUBVOL_CMPR_RATIO) + btrfs_set_root_flags(&root->root_item, + root_flags | BTRFS_ROOT_SUBVOL_CMPR_RATIO); + else + btrfs_set_root_flags(&root->root_item, + root_flags & ~BTRFS_ROOT_SUBVOL_CMPR_RATIO); + + root_flags = btrfs_root_flags(&root->root_item); + if (flags & BTRFS_SUBVOL_NOLOAD_USRQUOTA) + btrfs_set_root_flags(&root->root_item, + root_flags | BTRFS_ROOT_SUBVOL_NOLOAD_USRQUOTA); + else + btrfs_set_root_flags(&root->root_item, + root_flags & ~BTRFS_ROOT_SUBVOL_NOLOAD_USRQUOTA); +#endif /* MY_ABC_HERE */ + trans = btrfs_start_transaction(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); @@ -2140,7 +3133,11 @@ static noinline int copy_to_sk(struct btrfs_path *path, if (sizeof(sh) + item_len > *buf_size) { if (*num_found) { +#ifdef MY_ABC_HERE + ret = -EAGAIN; +#else /* MY_ABC_HERE */ ret = 1; +#endif /* MY_ABC_HERE */ goto out; } @@ -2155,7 +3152,11 @@ static noinline int copy_to_sk(struct btrfs_path *path, } if (sizeof(sh) + item_len + *sk_offset > *buf_size) { +#ifdef MY_ABC_HERE + ret = -EAGAIN; +#else /* MY_ABC_HERE */ ret = 1; +#endif /* MY_ABC_HERE */ goto out; } @@ -2199,7 +3200,11 @@ static noinline int copy_to_sk(struct btrfs_path *path, goto out; if (*num_found >= sk->nr_items) { +#ifdef MY_ABC_HERE + ret = -EAGAIN; +#else /* MY_ABC_HERE */ ret = 1; +#endif /* MY_ABC_HERE */ goto out; } } @@ -2228,6 +3233,9 @@ static noinline int copy_to_sk(struct btrfs_path *path, * * all items were found * Either way, it will stops the loop which iterates to the next * leaf +#ifdef MY_ABC_HERE + * -EAGAIN: try again to get more +#endif * -EOVERFLOW: item was to large for buffer * -EFAULT: could not copy extent buffer back to userspace */ @@ -2245,6 +3253,9 @@ static noinline int search_ioctl(struct inode *inode, struct btrfs_path *path; int ret; int num_found = 0; +#ifdef MY_ABC_HERE + u64 orig_min_offset = sk->min_offset; +#endif /* MY_ABC_HERE */ unsigned long sk_offset = 0; if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) { @@ -2271,6 +3282,23 @@ static noinline int search_ioctl(struct inode *inode, key.type = sk->min_type; key.offset = sk->min_offset; +#ifdef MY_ABC_HERE + if (sk->search_flag & BTRFS_SEARCH_FLAG_READAHEAD) + path->reada = READA_FORWARD_ALWAYS; + if ((sk->search_flag & BTRFS_SEARCH_FLAG_ADJUST_MIN) && + (sk->min_type == BTRFS_EXTENT_DATA_KEY)) { + ret = btrfs_lookup_file_extent_by_file_offset(NULL, root, + path, sk->min_objectid, sk->min_offset, 0); + if (0 > ret && -ENOENT != ret) + goto err; + if (!ret) { + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + sk->min_offset = key.offset; + } + btrfs_release_path(path); + } +#endif /* MY_ABC_HERE */ + while (1) { ret = fault_in_pages_writeable(ubuf + sk_offset, *buf_size - sk_offset); @@ -2293,6 +3321,9 @@ static noinline int search_ioctl(struct inode *inode, if (ret > 0) ret = 0; err: +#ifdef MY_ABC_HERE + sk->min_offset = orig_min_offset; +#endif /* MY_ABC_HERE */ sk->nr_items = num_found; btrfs_put_root(root); btrfs_free_path(path); @@ -2325,7 +3356,11 @@ static noinline int btrfs_ioctl_tree_search(struct file *file, * In the origin implementation an overflow is handled by returning a * search header with a len of zero, so reset ret. */ +#ifdef MY_ABC_HERE + if (ret == -EOVERFLOW || ret == -EAGAIN) +#else /* MY_ABC_HERE */ if (ret == -EOVERFLOW) +#endif /* MY_ABC_HERE */ ret = 0; if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk))) @@ -2360,7 +3395,13 @@ static noinline int btrfs_ioctl_tree_search_v2(struct file *file, inode = file_inode(file); ret = search_ioctl(inode, &args.key, &buf_size, (char __user *)(&uarg->buf[0])); +#ifdef MY_ABC_HERE + if (!(args.key.search_flag & BTRFS_SEARCH_FLAG_REPORT_BUF_FULL) && ret == -EAGAIN) + ret = 0; + if ((ret == 0 || ret == -EAGAIN) && copy_to_user(&uarg->key, &args.key, sizeof(args.key))) +#else /* MY_ABC_HERE */ if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key))) +#endif /* MY_ABC_HERE */ ret = -EFAULT; else if (ret == -EOVERFLOW && copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size))) @@ -3125,6 +4166,80 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, return err; } +#ifdef MY_ABC_HERE +static inline void get_min_max_range(u64 *min, u64 *max, u64 file_extent_offset, + u64 extent_item_offset, u64 extent_item_size) +{ + u64 local_start = 0, local_end = 0; + + if (file_extent_offset > extent_item_offset) + local_start = file_extent_offset - extent_item_offset; + + local_end = file_extent_offset + (extent_item_size - extent_item_offset); + + *min = min(*min, local_start); + *max = max(*max, local_end); +} + +static void syno_reclaim_range_adjust(struct btrfs_inode *inode, + struct btrfs_ioctl_defrag_range_args *range) +{ + int ret = 0; + u64 ino = btrfs_ino(inode); + u64 end = range->start + range->len; + u64 min_begin = range->start; + u64 max_end = range->start + range->len; + struct btrfs_root *root = inode->root; + struct btrfs_key key; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf = NULL; + struct btrfs_file_extent_item *fi = NULL; + + if (0 == min_begin && (u64)-1 == max_end) + return; + + path = btrfs_alloc_path(); + if (!path) + return; + + ret = btrfs_lookup_file_extent_by_file_offset(NULL, root, path, ino, + range->start, 0); + if (0 > ret) { + if (-ENOENT != ret) { + btrfs_info(root->fs_info, + "lookup ino[%llu] offset[%llu] failed %d", + ino, range->start, ret); + } + goto out; + } + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + while (key.offset < end) { + fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); + + get_min_max_range(&min_begin, &max_end, key.offset, + btrfs_file_extent_offset(leaf, fi), + btrfs_file_extent_disk_num_bytes(leaf, fi)); + + ret = btrfs_search_next_file_extent(&key, root, path); + if (ret) { + break; + } + leaf = path->nodes[0]; + } + + if (min_begin < range->start) + range->start = min_begin; + if (max_end - min_begin > range->len) + range->len = max_end - min_begin; + +out: + btrfs_free_path(path); + return; +} +#endif /* MY_ABC_HERE */ + static int btrfs_ioctl_defrag(struct file *file, void __user *argp) { struct inode *inode = file_inode(file); @@ -3179,6 +4294,11 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) range->flags |= BTRFS_DEFRAG_RANGE_START_IO; range->extent_thresh = (u32)-1; } +#ifdef MY_ABC_HERE + if (range->flags & BTRFS_DEFRAG_RANGE_SYNO_DEFRAG) { + syno_reclaim_range_adjust(BTRFS_I(inode), range); + } +#endif /* MY_ABC_HERE */ } else { /* the rest are all set to zero by kzalloc */ range->len = (u64)-1; @@ -3187,6 +4307,12 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) range, BTRFS_OLDEST_GENERATION, 0); if (ret > 0) ret = 0; +#ifdef MY_ABC_HERE + if (argp && ret == 0 && copy_to_user(argp, range, sizeof(*range))) { + ret = -EFAULT; + WARN_ON_ONCE(1); + } +#endif /* MY_ABC_HERE */ kfree(range); break; default: @@ -3648,6 +4774,42 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info, return ret; } +#ifdef MY_ABC_HERE +static long btrfs_ioctl_trigger_transcation(struct super_block *sb) +{ + struct btrfs_trans_handle *trans; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_root *root = fs_info->tree_root; + + trans = btrfs_attach_transaction_barrier(root); + if (IS_ERR(trans)) { + /* no transaction, don't bother */ + if (PTR_ERR(trans) == -ENOENT) { + /* + * Exit unless we have some pending changes + * that need to go through commit + */ + if (fs_info->pending_changes == 0) + return 0; + /* + * A non-blocking test if the fs is frozen. We must not + * start a new transaction here otherwise a deadlock + * happens. The pending operations are delayed to the + * next commit after thawing. + */ + if (sb_start_write_trylock(sb)) + sb_end_write(sb); + else + return 0; + trans = btrfs_start_transaction(root, 0); + } + if (IS_ERR(trans)) + return PTR_ERR(trans); + } + return btrfs_commit_transaction(trans); +} +#endif /* MY_ABC_HERE */ + static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, void __user *argp) { @@ -3895,7 +5057,325 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) return ret; } -static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx) +#ifdef MY_ABC_HERE +/* + * Similar to BTRFS_IOC_INO_PATHS, but we only output one path, regardless of how many + * links this inode should have, since the vfs caller should not know too much about + * how to parse struct btrfs_ioctl_ino_path_args and struct inode_fs_paths. + */ +int btrfs_vfs_ino_to_path(struct inode *inode, u64 inum, char *outpath, int len) +{ + int ret = 0; + struct inode_fs_paths *ipath = NULL; + struct btrfs_path *path; + struct btrfs_root *root; + + if (len < PATH_MAX) + return -EINVAL; + + if (inode->i_sb->s_magic == BTRFS_SUPER_MAGIC) + root = BTRFS_I(inode)->root; + else + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ipath = init_ipath(len + offsetof(struct btrfs_data_container, val[1]), + root, path); + if (IS_ERR(ipath)) { + ret = PTR_ERR(ipath); + ipath = NULL; + goto out; + } + + ret = paths_from_inode(inum, ipath); + if (ret < 0) + goto out; + + if (ipath->fspath->elem_cnt > 0) + strncpy(outpath, (char *)(ipath->fspath->val[0]), len); + else + ret = -ENOENT; + +out: + free_ipath(ipath); + btrfs_free_path(path); + + return ret; +} +EXPORT_SYMBOL(btrfs_vfs_ino_to_path); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* copy from backref:iterate_irefs_t */ +typedef int (iterate_irefs_t)(u64 parent, u32 name_len, unsigned long name_off, + struct extent_buffer *eb, void *ctx); + +/* copy from backref:iterate_inode_refs */ +static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, + struct btrfs_path *path, struct btrfs_list_hardlinks_iter_index *index, + iterate_irefs_t *iterate, void *ctx) +{ + int ret = 0; + int slot; + u32 cur; + u32 len; + u32 name_len; + u64 dir_index; + u64 skip_dir = index->dir; + u64 skip_dir_index = index->dir_index; + u64 parent = index->dir; + struct extent_buffer *eb; + struct btrfs_item *item; + struct btrfs_inode_ref *iref; + struct btrfs_key found_key; + + while (!ret) { + ret = btrfs_find_item(fs_root, path, inum, + parent, BTRFS_INODE_REF_KEY, + &found_key); + + if (ret < 0) + break; + if (ret) { + ret = 0; + break; + } + + parent = found_key.offset; + slot = path->slots[0]; + eb = btrfs_clone_extent_buffer(path->nodes[0]); + if (!eb) { + ret = -ENOMEM; + break; + } + btrfs_release_path(path); + + item = btrfs_item_nr(slot); + iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); + + for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { + name_len = btrfs_inode_ref_name_len(eb, iref); + dir_index = btrfs_inode_ref_index(eb, iref); + + if (parent < skip_dir) + goto next; + if (parent == skip_dir && dir_index <= skip_dir_index) + goto next; + ret = iterate(parent, name_len, + (unsigned long)(iref + 1), eb, ctx); + if (ret) + break; +next: + if (parent > index->dir || + (parent == index->dir && dir_index > index->dir_index)) { + index->dir = parent; + index->dir_index = dir_index; + } + len = sizeof(*iref) + name_len; + iref = (struct btrfs_inode_ref *)((char *)iref + len); + } + free_extent_buffer(eb); + parent++; + } + + btrfs_release_path(path); + + return ret; +} + +/* copy from backref:iterate_inode_extrefs */ +static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root, + struct btrfs_path *path, struct btrfs_list_hardlinks_iter_index *index, + iterate_irefs_t *iterate, void *ctx) +{ + int ret; + int slot; + u64 skip_offset = index->offset; + u64 offset = index->offset; + u64 parent; + struct extent_buffer *eb; + struct btrfs_inode_extref *extref; + u32 item_size; + u32 cur_offset; + unsigned long ptr; + + while (1) { + ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref, + &offset); + if (ret < 0 && ret != -ENOENT) + break; + if (ret) { + ret = 0; + break; + } + + if (offset <= skip_offset) { + btrfs_release_path(path); + goto next; + } + + slot = path->slots[0]; + eb = btrfs_clone_extent_buffer(path->nodes[0]); + if (!eb) { + ret = -ENOMEM; + break; + } + btrfs_release_path(path); + + item_size = btrfs_item_size_nr(eb, slot); + ptr = btrfs_item_ptr_offset(eb, slot); + cur_offset = 0; + + /* + * Because EXTREF is not sorted, all refs in the + * entire item must be output together, otherwise + * there will be a duplicate item next time. + * + * Because btrfs btrfs_hardlink_entry is smaller than + * btrfs_inode_extref, so we only need to check + * free space >= item size. + */ + if (index->free_space < item_size) { + ret = -ENOSPC; + goto free; + } + + while (cur_offset < item_size) { + u32 name_len; + + extref = (struct btrfs_inode_extref *)(ptr + cur_offset); + parent = btrfs_inode_extref_parent(eb, extref); + name_len = btrfs_inode_extref_name_len(eb, extref); + ret = iterate(parent, name_len, + (unsigned long)&extref->name, eb, ctx); + if (ret) + break; + + cur_offset += btrfs_inode_extref_name_len(eb, extref); + cur_offset += sizeof(*extref); + } +free: + free_extent_buffer(eb); +next: + if (ret) + break; + if (offset > index->offset) + index->offset = offset; + offset++; + } + + btrfs_release_path(path); + + return ret; +} + +static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, + struct btrfs_path *path, struct btrfs_list_hardlinks_iter_index *index, + iterate_irefs_t *iterate, void *ctx) +{ + int ret; + + if (index->type == SYNO_BTRFS_LIST_HARDLINKS_INDEX_TYPE_INODE_REF) { + ret = iterate_inode_refs(inum, fs_root, path, index, iterate, ctx); + if (ret) + goto out; + index->type = SYNO_BTRFS_LIST_HARDLINKS_INDEX_TYPE_INODE_EXTREF; + index->dir = -1; + index->dir_index = -1; + } + + ret = iterate_inode_extrefs(inum, fs_root, path, index, iterate, ctx); +out: + return ret; +} + +static int record_hardlink(u64 inum, u32 name_len, unsigned long name_off, + struct extent_buffer *eb, void *ctx) +{ + int ret; + struct btrfs_list_hardlinks_args *args = ctx; + struct btrfs_hardlink_entry *entry; + u32 entry_len = sizeof(*entry) + name_len + 1; + unsigned long ptr; + char *dest; + + if (entry_len > args->index.free_space) { + ret = -ENOSPC; + goto out; + } + + ptr = (unsigned long)args->buf; + ptr += args->index.cursor; + entry = (struct btrfs_hardlink_entry *)ptr; + dest = (char*)(entry + 1); + + entry->record_len = entry_len; + entry->parent_inum = inum; + entry->name_len = name_len; + read_extent_buffer(eb, dest, name_off, name_len); + dest[name_len] = '\0'; + + args->elem_cnt++; + args->index.cursor += entry_len; + args->index.free_space -= entry_len; + + ret = 0; +out: + return ret; +} + +static int links_from_inum(struct btrfs_root *fs_root, struct btrfs_path *path, struct btrfs_list_hardlinks_iter_index *index, struct btrfs_list_hardlinks_args *args) +{ + return iterate_irefs(args->inum, fs_root, path, index, record_hardlink, args); +} + +int btrfs_list_hardlinks(struct btrfs_list_hardlinks_args *args) +{ + int ret; + struct btrfs_path *path = NULL; + struct btrfs_root *root; + + if (!args || + !args->inode || + !S_ISREG(args->inode->i_mode) || + args->inode->i_sb->s_magic != BTRFS_SUPER_MAGIC || + !args->buf_size) { + ret = -EINVAL; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + root = BTRFS_I(args->inode)->root; + args->elem_cnt = 0; + args->index.cursor = 0; + args->index.free_space = args->buf_size; + + ret = links_from_inum(root, path, &args->index, args); + if (ret < 0) + goto out; + + ret = 0; +out: + btrfs_free_path(path); + + return ret; +} +EXPORT_SYMBOL(btrfs_list_hardlinks); +#endif /* MY_ABC_HERE */ + +static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx +#ifdef MY_ABC_HERE + , int extent_type +#endif /* MY_ABC_HERE */ + ) { struct btrfs_data_container *inodes = ctx; const size_t c = 3 * sizeof(u64); @@ -4002,6 +5482,9 @@ void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info, memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); +#ifdef MY_ABC_HERE + bargs->total_chunk_used = bctl->total_chunk_used; +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ spin_lock(&fs_info->balance_lock); memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); spin_unlock(&fs_info->balance_lock); @@ -4117,7 +5600,21 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) bctl->flags |= BTRFS_BALANCE_TYPE_MASK; } +#ifdef MY_ABC_HERE + if (bargs->key_offset) { + if (fs_info->super_copy->total_bytes <= 50ULL * SZ_1G) { + ret = -ENOSPC; + goto out_bctl; + } else + bctl->fast_key_offset = bargs->key_offset; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bctl->total_chunk_used = 0; + if (bctl->flags & ~(BTRFS_BALANCE_ARGS_MASK | BTRFS_BALANCE_TYPE_MASK | BTRFS_BALANCE_DRY_RUN)) { +#else if (bctl->flags & ~(BTRFS_BALANCE_ARGS_MASK | BTRFS_BALANCE_TYPE_MASK)) { +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ ret = -EINVAL; goto out_bctl; } @@ -4223,11 +5720,25 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) switch (sa->cmd) { case BTRFS_QUOTA_CTL_ENABLE: +#ifdef MY_ABC_HERE + case BTRFS_QUOTA_V1_CTL_ENABLE: + case BTRFS_QUOTA_V2_CTL_ENABLE: + ret = btrfs_quota_enable(fs_info, sa->cmd); +#else ret = btrfs_quota_enable(fs_info); +#endif /* MY_ABC_HERE */ break; case BTRFS_QUOTA_CTL_DISABLE: ret = btrfs_quota_disable(fs_info); break; +#ifdef MY_ABC_HERE + case BTRFS_QUOTA_CTL_UNLOAD: + ret = btrfs_quota_unload(fs_info); + break; + case BTRFS_QUOTA_CTL_REMOVE_V1: + ret = btrfs_quota_remove_v1(fs_info); + break; +#endif /* MY_ABC_HERE */ default: ret = -EINVAL; break; @@ -4354,6 +5865,11 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; +#ifdef MY_ABC_HERE + if (root->invalid_quota) + return -ESRCH; +#endif /* MY_ABC_HERE */ + ret = mnt_want_write_file(file); if (ret) return ret; @@ -4391,6 +5907,9 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg) { +#ifdef MY_ABC_HERE + return -EOPNOTSUPP; +#else struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_ioctl_quota_rescan_args *qsa; @@ -4421,11 +5940,15 @@ static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg) drop_write: mnt_drop_write_file(file); return ret; +#endif /* MY_ABC_HERE */ } static long btrfs_ioctl_quota_rescan_status(struct btrfs_fs_info *fs_info, void __user *arg) { +#ifdef MY_ABC_HERE + return -EOPNOTSUPP; +#else struct btrfs_ioctl_quota_rescan_args *qsa; int ret = 0; @@ -4446,6 +5969,7 @@ static long btrfs_ioctl_quota_rescan_status(struct btrfs_fs_info *fs_info, kfree(qsa); return ret; +#endif /* MY_ABC_HERE */ } static long btrfs_ioctl_quota_rescan_wait(struct btrfs_fs_info *fs_info, @@ -4457,6 +5981,323 @@ static long btrfs_ioctl_quota_rescan_wait(struct btrfs_fs_info *fs_info, return btrfs_qgroup_wait_for_completion(fs_info, true); } +#ifdef MY_ABC_HERE +static long btrfs_ioctl_usrquota_ctl(struct file *file, void __user *arg) +{ + struct inode *inode = file_inode(file); + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_ioctl_usrquota_ctl_args *ctl_args; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + ctl_args = memdup_user(arg, sizeof(*ctl_args)); + if (IS_ERR(ctl_args)) { + ret = PTR_ERR(ctl_args); + goto drop_write; + } + + if (ctl_args->cmd == BTRFS_USRQUOTA_CTL_DUMPTREE) { + ret = -EOPNOTSUPP; + goto free_ctl_args; + } + + down_write(&fs_info->subvol_sem); + + switch (ctl_args->cmd) { + case BTRFS_USRQUOTA_CTL_ENABLE: + case BTRFS_USRQUOTA_V1_CTL_ENABLE: + case BTRFS_USRQUOTA_V2_CTL_ENABLE: + ret = btrfs_usrquota_enable(fs_info, ctl_args->cmd); + break; + case BTRFS_USRQUOTA_CTL_DISABLE: + ret = btrfs_usrquota_disable(fs_info); + break; + case BTRFS_USRQUOTA_CTL_UNLOAD: + ret = btrfs_usrquota_unload(fs_info); + break; + case BTRFS_USRQUOTA_CTL_REMOVE_V1: + ret = btrfs_usrquota_remove_v1(fs_info); + break; + default: + ret = -EINVAL; + break; + } + + up_write(&fs_info->subvol_sem); +free_ctl_args: + kfree(ctl_args); +drop_write: + mnt_drop_write_file(file); + return ret; +} + +static long btrfs_ioctl_usrquota_limit(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_ioctl_usrquota_limit_args *limit_args; + struct btrfs_trans_handle *trans; + int ret; + int err; + u64 rootid; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + +#ifdef MY_ABC_HERE + if (root->invalid_quota) + return -ESRCH; +#endif /* MY_ABC_HERE */ + + if (btrfs_root_readonly(root)) + return -EROFS; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + limit_args = memdup_user(arg, sizeof(*limit_args)); + if (IS_ERR(limit_args)) { + ret = PTR_ERR(limit_args); + goto drop_write; + } + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + + rootid = root->root_key.objectid; + ret = btrfs_usrquota_limit(trans, rootid, + limit_args->uid, limit_args->rfer_soft, + limit_args->rfer_hard); + + err = btrfs_end_transaction(trans); + if (err && !ret) + ret = err; + +out: + kfree(limit_args); +drop_write: + mnt_drop_write_file(file); + return ret; +} + +static long btrfs_ioctl_usrquota_rescan(struct file *file) +{ + // Please use qgroup rescan. + return -EOPNOTSUPP; +} + +static long btrfs_ioctl_usrquota_rescan_status(struct file *file, void __user *arg) +{ + // Please use qgroup rescan. + return -EOPNOTSUPP; +} + +static inline long btrfs_ioctl_usrquota_rescan_wait(struct file *file) +{ + // Please use qgroup rescan. + return -EOPNOTSUPP; +} + +static long btrfs_ioctl_usrquota_query(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_ioctl_usrquota_query_args uqa; + int ret = 0; + + if (copy_from_user(&uqa, arg, sizeof(uqa))) { + ret = -EFAULT; + goto out; + } + + ret = btrfs_usrquota_query(root, &uqa); + if (ret) + goto out; + + if (copy_to_user(arg, &uqa, sizeof(uqa))) + ret = -EFAULT; +out: + return ret; +} + +static long btrfs_ioctl_usrquota_clean(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_trans_handle *trans; + int ret, err; + u64 uid; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + if (copy_from_user(&uid, arg, sizeof(uid))) { + ret = -EFAULT; + goto out; + } + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + + ret = btrfs_usrquota_clean(trans, uid); + err = btrfs_end_transaction(trans); + if (err && !ret) + ret = err; +out: + mnt_drop_write_file(file); + return ret; +} + +static long btrfs_ioctl_syno_quota_rescan(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_syno_quota_rescan_args *qsa; + struct btrfs_trans_handle *trans; + int ret; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) + return -ESRCH; + + qsa = memdup_user(arg, sizeof(*qsa)); + if (IS_ERR(qsa)) { + ret = PTR_ERR(qsa); + return ret; + } + + switch (qsa->flags) { + case BTRFS_SYNO_QUOTA_RESCAN: + ret = mnt_want_write_file(file); + if (ret) + break; + + ret = btrfs_syno_quota_rescan(root); + + mnt_drop_write_file(file); + break; + case BTRFS_SYNO_QUOTA_RESCAN_PAUSE: + if (!fs_info->qgroup_rescan_running) { + btrfs_info(fs_info, "Syno quota rescan is not running."); + ret = -ENOENT; + } else { + fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_PAUSE; + btrfs_info(fs_info, "Sending pause to syno quota rescan worker."); + ret = 0; + } + break; + case BTRFS_SYNO_QUOTA_RESCAN_RESUME: + if (fs_info->qgroup_rescan_running) { + btrfs_info(fs_info, "Syno quota rescan is already running."); + ret = -EEXIST; + } else if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)) { + btrfs_info(fs_info, "No quota rescan work to resume."); + ret = -ENOENT; + } else { + btrfs_qgroup_rescan_resume(fs_info); + btrfs_info(fs_info, "Syno quota rescan has been resumed."); + ret = 0; + } + break; + case BTRFS_SYNO_QUOTA_RESCAN_SET_VOL_V2: + ret = mnt_want_write_file(file); + if (ret) + break; + + trans = btrfs_start_transaction(fs_info->fs_root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + mnt_drop_write_file(file); + break; + } + + ret = 0; + err = btrfs_reset_qgroup_status(trans); + if (err) { + btrfs_err(fs_info, "Failed to set qgroup status to v2."); + ret = err; + } + + err = btrfs_reset_usrquota_status(trans); + if (err) { + btrfs_err(fs_info, "Failed to set usrquota status to v2."); + ret = err; + } + + err = btrfs_commit_transaction(trans); + if (err) + ret = err; + mnt_drop_write_file(file); + break; + case BTRFS_SYNO_QUOTA_RESCAN_TRANSFER_LIMIT: + ret = mnt_want_write_file(file); + if (ret) + break; + + ret = 0; + err = btrfs_syno_qgroup_transfer_limit(root); + if (err) + ret = err; + + err = btrfs_syno_usrquota_transfer_limit(root); + if (err) + ret = err; + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + break; + } + err = btrfs_commit_transaction(trans); + if (err) + ret = err; + mnt_drop_write_file(file); + break; + default: + ret = -EINVAL; + } + + kfree(qsa); + return ret; +} + +static long btrfs_ioctl_syno_quota_status(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_ioctl_syno_quota_status_args sa; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&sa, arg, sizeof(sa))) + return -EFAULT; + + ret = btrfs_syno_quota_status(root, &sa); + + if (ret == 0 && copy_to_user(arg, &sa, sizeof(sa))) + ret = -EFAULT; + + return ret; +} +#endif /* MY_ABC_HERE */ + static long _btrfs_ioctl_set_received_subvol(struct file *file, struct btrfs_ioctl_received_subvol_args *sa) { @@ -4523,6 +6364,11 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, btrfs_set_stack_timespec_nsec(&root_item->stime, sa->stime.nsec); btrfs_set_stack_timespec_sec(&root_item->rtime, sa->rtime.sec); btrfs_set_stack_timespec_nsec(&root_item->rtime, sa->rtime.nsec); +#ifdef MY_ABC_HERE + btrfs_set_stack_timespec_sec(&root_item->otime, sa->otime.sec); + btrfs_set_stack_timespec_nsec(&root_item->otime, sa->otime.nsec); +#endif /* MY_ABC_HERE */ + ret = btrfs_update_root(trans, fs_info->tree_root, &root->root_key, &root->root_item); @@ -4572,6 +6418,10 @@ static long btrfs_ioctl_set_received_subvol_32(struct file *file, args64->stime.nsec = args32->stime.nsec; args64->rtime.sec = args32->rtime.sec; args64->rtime.nsec = args32->rtime.nsec; +#ifdef MY_ABC_HERE + args64->otime.sec = args32->otime.sec; + args64->otime.nsec = args32->otime.nsec; +#endif /* MY_ABC_HERE */ args64->flags = args32->flags; ret = _btrfs_ioctl_set_received_subvol(file, args64); @@ -4585,6 +6435,10 @@ static long btrfs_ioctl_set_received_subvol_32(struct file *file, args32->stime.nsec = args64->stime.nsec; args32->rtime.sec = args64->rtime.sec; args32->rtime.nsec = args64->rtime.nsec; +#ifdef MY_ABC_HERE + args32->otime.sec = args64->otime.sec; + args32->otime.nsec = args64->otime.nsec; +#endif /* MY_ABC_HERE */ args32->flags = args64->flags; ret = copy_to_user(arg, args32, sizeof(*args32)); @@ -4851,6 +6705,7 @@ static int btrfs_ioctl_set_features(struct file *file, void __user *arg) newflags |= flags[0].incompat_flags & flags[1].incompat_flags; newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); btrfs_set_super_incompat_flags(super_block, newflags); + spin_unlock(&fs_info->super_lock); ret = btrfs_commit_transaction(trans); @@ -4860,6 +6715,78 @@ static int btrfs_ioctl_set_features(struct file *file, void __user *arg) return ret; } +#ifdef MY_ABC_HERE +/* + * For backward compatiblity, we should not put capability flags into + * `struct btrfs_ioctl_feature_flags`. + */ +static int btrfs_ioctl_get_syno_flags(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_super_block *super_block = root->fs_info->super_copy; + struct btrfs_ioctl_syno_flags flags; + + flags.syno_capability_flags = btrfs_super_syno_capability_flags(super_block); + + if (copy_to_user(arg, &flags, sizeof(flags))) + return -EFAULT; + return 0; +} + +static int btrfs_ioctl_set_syno_flags(struct file *file, void __user *arg) +{ + struct inode *inode = file_inode(file); + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_super_block *super_block = root->fs_info->super_copy; + struct btrfs_ioctl_syno_flags flags[2]; + struct btrfs_trans_handle *trans; + u64 newflags; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(flags, arg, sizeof(flags))) + return -EFAULT; + + /* Nothing to do */ + if (!flags[0].syno_capability_flags) + return 0; + + ret = check_feature(fs_info, flags[0].syno_capability_flags, + flags[1].syno_capability_flags, SYNO_CAPABILITY); + if (ret) + return ret; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out_drop_write; + } + + spin_lock(&fs_info->super_lock); + + newflags = btrfs_super_syno_capability_flags(super_block); + newflags |= flags[0].syno_capability_flags & flags[1].syno_capability_flags; + newflags &= ~(flags[0].syno_capability_flags & ~flags[1].syno_capability_flags); + btrfs_set_super_syno_capability_flags(super_block, newflags); + + spin_unlock(&fs_info->super_lock); + + ret = btrfs_commit_transaction(trans); +out_drop_write: + mnt_drop_write_file(file); + + return ret; +} + +#endif /* MY_ABC_HERE */ + static int _btrfs_ioctl_send(struct file *file, void __user *argp, bool compat) { struct btrfs_ioctl_send_args *arg; @@ -4891,10 +6818,960 @@ static int _btrfs_ioctl_send(struct file *file, void __user *argp, bool compat) return PTR_ERR(arg); } ret = btrfs_ioctl_send(file, arg); +#ifdef MY_ABC_HERE + if (copy_to_user(argp, arg, sizeof(*arg))) { + ret = -EFAULT; + goto out; + } + +out: +#endif /* MY_ABC_HERE */ kfree(arg); return ret; } +#ifdef MY_ABC_HERE +static long btrfs_ioctl_qgroup_query(struct file *file, void __user *arg) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_ioctl_qgroup_query_args qqa; + int ret = 0; + + memset(&qqa, 0, sizeof(qqa)); + + // use subvol id as qgroup id + ret = btrfs_qgroup_query(root, &qqa); + if (ret) + goto out; + + if (copy_to_user(arg, &qqa, sizeof(qqa))) + ret = -EFAULT; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_ioctl_syno_reserve_log_tree_bg(struct file *file, + struct btrfs_ioctl_log_tree_reserve_bg_args __user *argp) +{ + struct btrfs_ioctl_log_tree_reserve_bg_args rsv_args; + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_bio *multi = NULL; + u64 rsv_start = 0; + u64 rsv_size = 0; + u64 length = fs_info->nodesize; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&rsv_args, argp, sizeof(rsv_args))) + return -EFAULT; + + mutex_lock(&fs_info->log_tree_rsv_alloc); + + switch(rsv_args.flags) { + case BTRFS_LOG_TREE_BG_RSV_REMOVE: + fs_info->log_tree_rsv_start = 0; + fs_info->log_tree_rsv_size = 0; + goto out; + case BTRFS_LOG_TREE_BG_RSV_ADD: + if (fs_info->log_tree_rsv_start) { + rsv_start = fs_info->log_tree_rsv_start; + rsv_size = fs_info->log_tree_rsv_size; + goto map_logical; + } + ret = btrfs_reserve_log_tree_bg(root, &rsv_start, &rsv_size); + if (ret) + goto out; + break; + default: + ret = -EINVAL; + goto out; + } + +map_logical: + ret = btrfs_map_block(fs_info, READ, rsv_start, &length, &multi, 1); +out: + if (!ret && rsv_start) { + if (put_user(rsv_start, &argp->start) || + put_user(rsv_size, &argp->size) || + put_user(multi->stripes[0].physical, &argp->map_start)) + ret = -EINVAL; + } + kfree(multi); + mutex_unlock(&fs_info->log_tree_rsv_alloc); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_ioctl_free_space_analyze(struct file *file, struct btrfs_ioctl_free_space_analyze_args __user *argp) +{ + int ret = 0; + struct inode *inode = file_inode(file); + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_free_space_analyze_args args; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) + return -EOPNOTSUPP; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + if (!mutex_trylock(&fs_info->free_space_analyze_ioctl_lock)) + return -EBUSY; + + if (args.flags & BTRFS_FREE_SPACE_ANALYZE_FLAG_FULL) + ret = btrfs_free_space_analyze_full(fs_info, &args); + else + ret = btrfs_free_space_analyze(fs_info, &args); + + mutex_unlock(&fs_info->free_space_analyze_ioctl_lock); + + if (copy_to_user(argp, &args, sizeof(args))) + return -EFAULT; + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_ioctl_syno_find_next_chunk_info(struct file *file, + struct btrfs_ioctl_find_next_chunk_info_args __user *argp) +{ + int ret = -1; + struct btrfs_ioctl_find_next_chunk_info_args args; + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_block_group *block_group = NULL; + u64 profile; + u64 length; + struct btrfs_bio *bbio = NULL; + int i; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + block_group = btrfs_lookup_first_block_group(fs_info, args.start); + while (block_group) { + if (block_group->flags & args.flags) + break; + block_group = btrfs_next_block_group(block_group); + } + + args.stripe_count = 0; + + if (block_group) { + profile = block_group->flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; + if ((profile & BTRFS_BLOCK_GROUP_DUP) || !profile) { + length = block_group->length; + ret = btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, + block_group->start, &length, + &bbio, 0); + if (ret || !bbio) { + if (!ret) + ret = -EIO; + goto out; + } + args.start = block_group->start; + args.size = block_group->length; + args.stripe_count = bbio->num_stripes > 2 ? 2 : bbio->num_stripes; + + for (i = 0; i < args.stripe_count; i++) + args.stripe_offset[i] = bbio->stripes[i].physical; + } + } + + if (copy_to_user(argp, &args, sizeof(args))) { + ret = -EFAULT; + goto out; + } + ret = 0; +out: + if (block_group) + btrfs_put_block_group(block_group); + btrfs_put_bbio(bbio); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define LOOKUP_COMPR_FILE_READA_THR ((20 * SZ_1M)) + +static long btrfs_ioctl_compr_ctl(struct file *file, void __user *arg) +{ + struct inode *inode = file_inode(file); + struct btrfs_inode *btrfs_inode = BTRFS_I(inode); + struct btrfs_ioctl_compr_ctl_args compr_args; + struct btrfs_root *root = btrfs_inode->root; + struct btrfs_path *path = NULL; + struct ulist *disko_ulist = NULL; + struct extent_buffer *leaf; + struct btrfs_file_extent_item *fi; + struct btrfs_key found_key; + int ret = 0; + int extent_type; + int slot; + u64 ino = btrfs_ino(btrfs_inode); + u64 disko; + u64 len; + u64 compressed_size = 0; + u64 size = 0; + + if (S_ISDIR(inode->i_mode)) + return -EISDIR; + + if (copy_from_user(&compr_args, arg, sizeof(compr_args))) + return -EFAULT; + + if (compr_args.flags & BTRFS_COMPR_CTL_SET) + return -EOPNOTSUPP; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + disko_ulist = ulist_alloc(GFP_NOFS); + if (!disko_ulist) { + ret = -ENOMEM; + goto out_free; + } + + inode_lock(inode); + + /* + * do any pending delalloc/csum calc on inode, one way or + * another, and lock file content + */ + btrfs_wait_ordered_range(inode, 0, (u64)-1); + len = i_size_read(inode); + lock_extent(&btrfs_inode->io_tree, 0, len); + + if (len > LOOKUP_COMPR_FILE_READA_THR) // May be many file extent items, do readahead. + path->reada = READA_FORWARD; + + ret = btrfs_lookup_file_extent(NULL, root, path, ino, 0, 0); + if (ret < 0) + goto out_unlock; + else if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out_unlock; + else if (ret > 0) + goto done; + } + + while (1) { + leaf = path->nodes[0]; + slot = path->slots[0]; + + btrfs_item_key_to_cpu(leaf, &found_key, slot); + if (found_key.objectid != ino || + found_key.type != BTRFS_EXTENT_DATA_KEY) + break; + + fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(leaf, fi); + + if (extent_type != BTRFS_FILE_EXTENT_INLINE) { + disko = btrfs_file_extent_disk_bytenr(leaf, fi); + if (disko && + ulist_add_lru_adjust(disko_ulist, disko, 0, GFP_NOFS)) { + compressed_size += btrfs_file_extent_disk_num_bytes( + leaf, fi); + size += btrfs_file_extent_num_bytes(leaf, fi); + if (disko_ulist->nnodes > ULIST_NODES_MAX) + ulist_remove_first(disko_ulist); + } + } else { + compressed_size += btrfs_file_extent_inline_item_len( + leaf, btrfs_item_nr(slot)); + size += btrfs_file_extent_ram_bytes(leaf, fi); + } + ret = btrfs_next_item(root, path); + if (ret < 0) + goto out_unlock; + if (ret > 0) + break; + } +done: + ret = 0; + + compr_args.size = size; + compr_args.compressed_size = compressed_size; + if (btrfs_inode->prop_compress != BTRFS_COMPRESS_NONE) + compr_args.flags |= BTRFS_COMPR_CTL_COMPR_FL; + + if (copy_to_user(arg, &compr_args, sizeof(compr_args))) + ret = -EFAULT; + +out_unlock: + unlock_extent(&btrfs_inode->io_tree, 0, len); + inode_unlock(inode); + +out_free: + ulist_free(disko_ulist); + btrfs_free_path(path); + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_ioctl_snapshot_size_query(struct file *file, + void __user *argp) +{ + struct btrfs_ioctl_snapshot_size_query_args snap_args; + struct btrfs_ioctl_snapshot_size_id_size_map *user_id_maps; + size_t id_maps_size; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&snap_args, argp, sizeof(snap_args))) + return -EFAULT; + + if (!snap_args.snap_count || 0 > snap_args.fd) + return -EINVAL; + + id_maps_size = sizeof(struct btrfs_ioctl_snapshot_size_id_size_map) * + snap_args.snap_count; + user_id_maps = snap_args.id_maps; + + if (!access_ok(snap_args.id_maps, id_maps_size)) + return -EFAULT; + + snap_args.id_maps = memdup_user(snap_args.id_maps, id_maps_size); + if (IS_ERR(snap_args.id_maps)) + return PTR_ERR(snap_args.id_maps); + + ret = btrfs_snapshot_size_query(file, &snap_args); + + if (copy_to_user(argp + offsetof( + struct btrfs_ioctl_snapshot_size_query_args, + calc_size), &snap_args.calc_size, + sizeof(snap_args.calc_size))) { + ret = -EFAULT; + goto out; + } + + if (copy_to_user(argp + offsetof( + struct btrfs_ioctl_snapshot_size_query_args, + processed_size), &snap_args.processed_size, + sizeof(snap_args.processed_size))) { + ret = -EFAULT; + goto out; + } + + if (copy_to_user(user_id_maps, snap_args.id_maps, id_maps_size)) { + ret = -EFAULT; + goto out; + } + + if (ret > 0) + ret = 0; +out: + kfree(snap_args.id_maps); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void __btrfs_syno_usage_rescan_progress_accounting(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + u64 root_new_total_size; + if (!(root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING)) { + root_new_total_size = btrfs_root_used(&root->root_item); + if (root_new_total_size > root->syno_usage_root_status.total_full_rescan_size) + root->syno_usage_root_status.total_full_rescan_size = root_new_total_size; + root->syno_usage_root_status.flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING; + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.total_full_rescan_size += (root->syno_usage_root_status.total_full_rescan_size - + root->syno_usage_root_status.cur_full_rescan_size); + spin_unlock(&fs_info->syno_usage_lock); + } +} + +static int btrfs_ioctl_syno_usage_subvol_type_set(struct file *file, + struct btrfs_ioctl_syno_usage_ctl_args *syno_usage_ctl_args, + struct btrfs_ioctl_syno_usage_ctl_args __user *argp) +{ + struct inode *inode = file_inode(file); + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_syno_usage_root_status *usage_root_status; + int ret = 0; + bool resume = false; + struct btrfs_key first_key, last_key; + + first_key.objectid = 0; + first_key.type = 0; + first_key.offset = 0; + last_key.objectid = -1; + last_key.type = -1; + last_key.offset = -1; + + if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) { + ret = -EINVAL; + goto out; + } + + if (syno_usage_ctl_args->type >= SYNO_USAGE_TYPE_MAX || + syno_usage_ctl_args->type == SYNO_USAGE_TYPE_NONE) { + ret = -EINVAL; + goto out; + } + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + goto out; + + btrfs_syno_usage_root_initialize(root); + if (!test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state) || + root->syno_usage_root_status.new_type == syno_usage_ctl_args->type) + goto out; + + if (btrfs_root_readonly(root)) + goto out; + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + spin_lock(&root->syno_usage_lock); + usage_root_status = &root->syno_usage_root_status; + if (usage_root_status->new_type == syno_usage_ctl_args->type) { + spin_unlock(&root->syno_usage_lock); + goto out; + } + + if (test_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN, &root->syno_usage_runtime_flags)) { + ret = -EBUSY; + spin_unlock(&root->syno_usage_lock); + goto out; + } + + if (usage_root_status->state == SYNO_USAGE_ROOT_STATE_NORMAL || + usage_root_status->num_bytes == 0 || + btrfs_comp_cpu_keys(&first_key, &usage_root_status->fast_rescan_progress) == 0 || + btrfs_comp_cpu_keys(&last_key, &usage_root_status->fast_rescan_progress) == 0) { + + usage_root_status->new_type = syno_usage_ctl_args->type; + + usage_root_status->fast_rescan_progress.objectid = 0; + usage_root_status->fast_rescan_progress.type = 0; + usage_root_status->fast_rescan_progress.offset = 0; + usage_root_status->state = SYNO_USAGE_ROOT_STATE_RESCAN; + usage_root_status->flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN; + + if (usage_root_status->new_type == SYNO_USAGE_TYPE_RO_SNAPSHOT) + usage_root_status->flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_FORCE_EXTENT; + + if (usage_root_status->new_type == SYNO_USAGE_TYPE_RO_SNAPSHOT && + usage_root_status->type == SYNO_USAGE_TYPE_NONE) { + usage_root_status->fast_rescan_progress.objectid = -1; + usage_root_status->fast_rescan_progress.type = -1; + usage_root_status->fast_rescan_progress.offset = -1; + usage_root_status->flags &= ~BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN; + } + if (usage_root_status->num_bytes == 0) { + usage_root_status->fast_rescan_progress.objectid = -1; + usage_root_status->fast_rescan_progress.type = -1; + usage_root_status->fast_rescan_progress.offset = -1; + usage_root_status->flags &= ~BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN; + } + if (btrfs_comp_cpu_keys(&last_key, &usage_root_status->fast_rescan_progress) == 0 && + btrfs_comp_cpu_keys(&last_key, &usage_root_status->full_rescan_progress) == 0) { + if (usage_root_status->flags & BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING) { + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.cur_full_rescan_size += usage_root_status->total_full_rescan_size - usage_root_status->cur_full_rescan_size; + usage_root_status->cur_full_rescan_size = 0; + usage_root_status->total_full_rescan_size = 0; + spin_unlock(&fs_info->syno_usage_lock); + } + usage_root_status->type = usage_root_status->new_type; + usage_root_status->state = SYNO_USAGE_ROOT_STATE_NORMAL; + usage_root_status->flags &= ~(BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_MASK); + } + if (usage_root_status->state == SYNO_USAGE_ROOT_STATE_RESCAN && + usage_root_status->new_type != SYNO_USAGE_TYPE_RO_SNAPSHOT) { + if (fs_info->syno_usage_status.state >= SYNO_USAGE_STATE_INITIAL && + fs_info->syno_usage_status.state <= SYNO_USAGE_STATE_RESCAN_PAUSE && + usage_root_status->flags & BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN) + __btrfs_syno_usage_rescan_progress_accounting(root); + spin_lock(&fs_info->syno_usage_full_rescan_lock); + spin_lock(&fs_info->syno_usage_fast_rescan_lock); + if ((fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_ENABLE) && + !test_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN, &root->syno_usage_runtime_flags) && + list_empty(&root->syno_usage_rescan_list)) { + btrfs_grab_root(root); + if (usage_root_status->flags & BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN) { + list_move_tail(&root->syno_usage_rescan_list, &fs_info->syno_usage_pending_full_rescan_roots); + atomic_inc(&fs_info->syno_usage_pending_full_rescan_count); + } else { + list_move_tail(&root->syno_usage_rescan_list, &fs_info->syno_usage_pending_fast_rescan_roots); + atomic_inc(&fs_info->syno_usage_pending_fast_rescan_count); + } + resume = true; + } + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + } + } else { + ret = -EBUSY; + spin_unlock(&root->syno_usage_lock); + goto out; + } + spin_unlock(&root->syno_usage_lock); + + btrfs_record_root_in_trans(trans, root); + if (resume) + btrfs_syno_usage_rescan_resume(fs_info); + ret = 0; +out: + if (trans) + btrfs_end_transaction(trans); + return ret; +} + +static int btrfs_ioctl_syno_usage_get_by_type(struct file *file, + struct btrfs_ioctl_syno_usage_ctl_args *syno_usage_ctl_args, + void __user *argp) +{ + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_fs_info *fs_info = root->fs_info; + int ret = 0; + + if (syno_usage_ctl_args->type >= SYNO_USAGE_TYPE_MAX || + syno_usage_ctl_args->type == SYNO_USAGE_TYPE_NONE) { + ret = -EINVAL; + goto out; + } + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + goto out; + + spin_lock(&fs_info->syno_usage_lock); + syno_usage_ctl_args->num_bytes = fs_info->syno_usage_status.syno_usage_type_num_bytes[syno_usage_ctl_args->type]; + spin_unlock(&fs_info->syno_usage_lock); + + if (copy_to_user(argp, syno_usage_ctl_args, sizeof(*syno_usage_ctl_args))) { + ret = -EFAULT; + goto out; + } + + ret = 0; +out: + return ret; +} + +static int btrfs_ioctl_syno_usage_ctl(struct file *file, void __user *argp) +{ + struct inode *inode = file_inode(file); + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_syno_usage_ctl_args syno_usage_ctl_args; + int ret = 0; + struct btrfs_trans_handle *trans; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&syno_usage_ctl_args, argp, sizeof(syno_usage_ctl_args))) + return -EFAULT; + + switch (syno_usage_ctl_args.cmd) { + case BTRFS_SYNO_USAGE_CTL_ENABLE: + if(!mutex_trylock(&fs_info->syno_usage_ioctl_lock)) { + ret = -EBUSY; + goto out; + } + ret = btrfs_syno_usage_enable(fs_info); + mutex_unlock(&fs_info->syno_usage_ioctl_lock); + break; + case BTRFS_SYNO_USAGE_CTL_DISABLE: + if(!mutex_trylock(&fs_info->syno_usage_ioctl_lock)) { + ret = -EBUSY; + goto out; + } + ret = btrfs_syno_usage_disable(fs_info); + mutex_unlock(&fs_info->syno_usage_ioctl_lock); + break; + case BTRFS_SYNO_USAGE_CTL_STATUS: + syno_usage_ctl_args.state = fs_info->syno_usage_status.state; + syno_usage_ctl_args.flags = fs_info->syno_usage_status.flags; + syno_usage_ctl_args.pending_fast_rescan_count = atomic_read(&fs_info->syno_usage_pending_fast_rescan_count); + syno_usage_ctl_args.pending_full_rescan_count = atomic_read(&fs_info->syno_usage_pending_full_rescan_count); + syno_usage_ctl_args.fast_rescan_pid = fs_info->syno_usage_fast_rescan_pid; + syno_usage_ctl_args.full_rescan_pid = fs_info->syno_usage_full_rescan_pid; + if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_INITIAL || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_DISABLE) { + syno_usage_ctl_args.cur_rescan_size = fs_info->syno_usage_status.cur_full_rescan_size; + syno_usage_ctl_args.total_rescan_size = fs_info->syno_usage_status.total_full_rescan_size; + } + if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR) + syno_usage_ctl_args.error_code = fs_info->syno_usage_status.error_code; + if (copy_to_user(argp, &syno_usage_ctl_args, sizeof(syno_usage_ctl_args))) { + ret = -EFAULT; + goto out; + } + break; + case BTRFS_SYNO_USAGE_CTL_RESCAN: + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + goto out; + if(!mutex_trylock(&fs_info->syno_usage_ioctl_lock)) { + ret = -EBUSY; + goto out; + } + if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_INITIAL || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + mutex_unlock(&fs_info->syno_usage_ioctl_lock); + goto out; + } + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_RESCAN; + btrfs_end_transaction(trans); + } + btrfs_syno_usage_rescan_resume(fs_info); + mutex_unlock(&fs_info->syno_usage_ioctl_lock); + break; + case BTRFS_SYNO_USAGE_CTL_RESCAN_PAUSE: + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state != SYNO_USAGE_STATE_RESCAN) + goto out; + if(!mutex_trylock(&fs_info->syno_usage_ioctl_lock)) { + ret = -EBUSY; + goto out; + } + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + mutex_unlock(&fs_info->syno_usage_ioctl_lock); + goto out; + } + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_RESCAN_PAUSE; + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_CHECK_ALL, &fs_info->flags); + btrfs_end_transaction(trans); + mutex_unlock(&fs_info->syno_usage_ioctl_lock); + break; + case BTRFS_SYNO_USAGE_CTL_SUBVOL_TYPE_SET: + ret = btrfs_ioctl_syno_usage_subvol_type_set(file, &syno_usage_ctl_args, argp); + break; + case BTRFS_SYNO_USAGE_CTL_SUBVOL_TYPE_GET: + if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) { + ret = -EINVAL; + goto out; + } + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + syno_usage_ctl_args.type = root->syno_usage_root_status.new_type; + else + syno_usage_ctl_args.type = SYNO_USAGE_TYPE_NONE; + if (copy_to_user(argp, &syno_usage_ctl_args, sizeof(syno_usage_ctl_args))) { + ret = -EFAULT; + goto out; + } + break; + case BTRFS_SYNO_USAGE_CTL_USAGE_GET_BY_TYPE: + ret = btrfs_ioctl_syno_usage_get_by_type(file, &syno_usage_ctl_args, argp); + break; + default: + ret = -EINVAL; + break; + } +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_ioctl_cksumfailed_files_get(struct file *file, void __user *arg) +{ + struct btrfs_fs_info *fs_info = BTRFS_I(file_inode(file))->root->fs_info; + struct cksumfailed_file_rec rec; + struct btrfs_ioctl_cksumfailed_files_args cksumfailed_files; + unsigned int len; + + spin_lock(&fs_info->cksumfailed_files_write_lock); + len = kfifo_out(&fs_info->cksumfailed_files, &rec, + sizeof(struct cksumfailed_file_rec)); + spin_unlock(&fs_info->cksumfailed_files_write_lock); + if (len == sizeof(struct cksumfailed_file_rec)) { + cksumfailed_files.sub_vol = rec.sub_vol; + cksumfailed_files.ino = rec.ino; + } else if (0 == len) { + return -ENOENT; + } else { + return -EFAULT; + } + + if (copy_to_user(arg, &cksumfailed_files, + sizeof(struct btrfs_ioctl_cksumfailed_files_args))) + return -EFAULT; + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_dedupe_set_inode_no_dedupe(struct inode *inode, bool on_off) +{ + int ret = -1; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_trans_handle *trans = NULL; + + inode_lock(inode); + if (on_off) { + if (BTRFS_I(inode)->flags & BTRFS_INODE_NODEDUPE) + goto out; + BTRFS_I(inode)->flags |= BTRFS_INODE_NODEDUPE; + } else { + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODEDUPE)) + goto out; + BTRFS_I(inode)->flags &= ~BTRFS_INODE_NODEDUPE; + } + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + inode_inc_iversion(inode); + inode->i_ctime = current_time(inode); + + ret = btrfs_update_inode(trans, root, inode); + if (ret) { + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + goto out; + } + ret = btrfs_end_transaction(trans); + +out: + inode_unlock(inode); + return ret; +} + +static long _btrfs_ioctl_syno_dedupe_cmd_file(struct file *file, + struct btrfs_ioctl_syno_dedupe_cmd_args *dedupe_cmd_args) +{ + int ret = -1; + u64 objectid = dedupe_cmd_args->objectid; + struct inode *inode = NULL; + bool get_inode = false; + + if (!objectid) { + inode = file_inode(file); + } else { + inode = btrfs_get_regular_file_inode(file_inode(file)->i_sb, + dedupe_cmd_args->rootid, + objectid); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); + goto out; + } + get_inode = true; + } + + if (!inode_owner_or_capable(inode)) { + ret = -EPERM; + goto out; + } + + switch(dedupe_cmd_args->action) { + case DEDUPE_CMD_SET: + ret = btrfs_file_extent_deduped_set_range(inode, + dedupe_cmd_args->offset, dedupe_cmd_args->len, true); + break; + case DEDUPE_CMD_CLEAR: + ret = btrfs_file_extent_deduped_set_range(inode, + dedupe_cmd_args->offset, dedupe_cmd_args->len, false); + break; + case DEDUPE_CMD_SET_NODEDUPE: + ret = btrfs_dedupe_set_inode_no_dedupe(inode, true); + break; + case DEDUPE_CMD_CLEAR_NODEDUPE: + ret = btrfs_dedupe_set_inode_no_dedupe(inode, false); + break; + default: + break; + } + +out: + if (get_inode) + iput(inode); + + return ret; +} + +static long _btrfs_ioctl_syno_dedupe_cmd_root(struct file *file, + struct btrfs_ioctl_syno_dedupe_cmd_args *dedupe_cmd_args) +{ + int ret = -1; + u64 objectid = dedupe_cmd_args->objectid; + u64 len = dedupe_cmd_args->len; + struct btrfs_root *root = NULL; + bool hold_root = false; + + if (!objectid) { + root = BTRFS_I(file_inode(file))->root; + } else { + if (objectid < BTRFS_FIRST_FREE_OBJECTID || objectid > BTRFS_LAST_FREE_OBJECTID) + return -ESTALE; + + root = btrfs_get_fs_root(btrfs_sb(file_inode(file)->i_sb), objectid, true); + if (IS_ERR(root)) + return PTR_ERR(root); + + hold_root = true; + } + + switch(dedupe_cmd_args->action) { + case DEDUPE_CMD_SET_SMALL_EXTENT_SIZE: + if ((len % PAGE_SIZE) || len < SZ_128K) { + ret = -EINVAL; + goto out; + } + root->small_extent_size = len; + break; + case DEDUPE_CMD_SET_INLINE_DEDUPE: + root->inline_dedupe = true; + break; + case DEDUPE_CMD_CLEAR_INLINE_DEDUPE: + root->inline_dedupe = false; + break; + default: + break; + } + + ret = 0; + +out: + if (hold_root) + btrfs_put_root(root); + return ret; +} + +static long btrfs_ioctl_syno_dedupe_cmd(struct file *file, + struct btrfs_ioctl_syno_dedupe_cmd_args __user *argp) +{ + int ret = -1; + struct btrfs_ioctl_syno_dedupe_cmd_args *dedupe_cmd_args = NULL; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + dedupe_cmd_args = memdup_user(argp, sizeof(struct btrfs_ioctl_syno_dedupe_cmd_args)); + if (!dedupe_cmd_args) { + ret = -ENOMEM; + goto out; + } + + switch(dedupe_cmd_args->action) { + case DEDUPE_CMD_SET: + case DEDUPE_CMD_CLEAR: + case DEDUPE_CMD_SET_NODEDUPE: + case DEDUPE_CMD_CLEAR_NODEDUPE: + ret = _btrfs_ioctl_syno_dedupe_cmd_file(file, dedupe_cmd_args); + break; + case DEDUPE_CMD_SET_SMALL_EXTENT_SIZE: + case DEDUPE_CMD_SET_INLINE_DEDUPE: + case DEDUPE_CMD_CLEAR_INLINE_DEDUPE: + ret = _btrfs_ioctl_syno_dedupe_cmd_root(file, dedupe_cmd_args); + break; + default: + printk("unknown dedupe cmd:%d\n", dedupe_cmd_args->action); + ret = -EINVAL; + } + +out: + mnt_drop_write_file(file); + kfree(dedupe_cmd_args); + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_ioctl_syno_feat_tree_ctl(struct file *file, struct btrfs_ioctl_syno_feat_tree_ctl_args __user *argp) +{ + struct inode *inode = file_inode(file); + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_syno_feat_tree_ctl_args syno_feat_ctl_args; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&syno_feat_ctl_args, argp, sizeof(syno_feat_ctl_args))) + return -EFAULT; + + switch (syno_feat_ctl_args.cmd) { + + case BTRFS_SYNO_FEAT_TREE_CTL_ENABLE: + if(!mutex_trylock(&fs_info->syno_feat_tree_ioctl_lock)) { + ret = -EBUSY; + goto out; + } + ret = btrfs_syno_feat_tree_enable(fs_info); + if (!ret) + btrfs_info(root->fs_info, "syno feature tree is enabled"); + mutex_unlock(&fs_info->syno_feat_tree_ioctl_lock); + break; + case BTRFS_SYNO_FEAT_TREE_CTL_DISABLE: +#ifdef MY_ABC_HERE + /* feature-tree isn't able to be disabled */ + ret = -EPERM; + break; +#else + if(!mutex_trylock(&fs_info->syno_feat_tree_ioctl_lock)) { + ret = -EBUSY; + goto out; + } + ret = btrfs_syno_feat_tree_disable(fs_info); + mutex_unlock(&fs_info->syno_feat_tree_ioctl_lock); + break; +#endif /* MY_ABC_HERE */ + case BTRFS_SYNO_FEAT_TREE_CTL_STATUS: + syno_feat_ctl_args.status = fs_info->syno_feat_tree_status.status; + + if (copy_to_user(argp, &syno_feat_ctl_args, sizeof(syno_feat_ctl_args))) { + ret = -EFAULT; + goto out; + } + break; + default: + ret = -EINVAL; + break; + } +out: + return ret; +} +#endif /* MY_ABC_HERE */ + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -4916,6 +7793,10 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_set_fslabel(file, argp); case FITRIM: return btrfs_ioctl_fitrim(fs_info, argp); +#ifdef MY_ABC_HERE + case FIHINTUNUSED: + return btrfs_ioctl_hint_unused(file, argp); +#endif /* MY_ABC_HERE */ case BTRFS_IOC_SNAP_CREATE: return btrfs_ioctl_snap_create(file, argp, 0); case BTRFS_IOC_SNAP_CREATE_V2: @@ -4966,6 +7847,15 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_logical_to_ino(fs_info, argp, 2); case BTRFS_IOC_SPACE_INFO: return btrfs_ioctl_space_info(fs_info, argp); +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNC_SYNO: { + int ret; + + ret = btrfs_ioctl_trigger_transcation(inode->i_sb); + wake_up_process(fs_info->transaction_kthread); + return ret; + } +#endif /* MY_ABC_HERE */ case BTRFS_IOC_SYNC: { int ret; @@ -5025,6 +7915,26 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_quota_rescan_status(fs_info, argp); case BTRFS_IOC_QUOTA_RESCAN_WAIT: return btrfs_ioctl_quota_rescan_wait(fs_info, argp); +#ifdef MY_ABC_HERE + case BTRFS_IOC_USRQUOTA_CTL: + return btrfs_ioctl_usrquota_ctl(file, argp); + case BTRFS_IOC_USRQUOTA_LIMIT: + return btrfs_ioctl_usrquota_limit(file, argp); + case BTRFS_IOC_USRQUOTA_RESCAN: + return btrfs_ioctl_usrquota_rescan(file); + case BTRFS_IOC_USRQUOTA_RESCAN_STATUS: + return btrfs_ioctl_usrquota_rescan_status(file, argp); + case BTRFS_IOC_USRQUOTA_RESCAN_WAIT: + return btrfs_ioctl_usrquota_rescan_wait(file); + case BTRFS_IOC_USRQUOTA_QUERY: + return btrfs_ioctl_usrquota_query(file, argp); + case BTRFS_IOC_USRQUOTA_CLEAN: + return btrfs_ioctl_usrquota_clean(file, argp); + case BTRFS_IOC_SYNO_QUOTA_RESCAN: + return btrfs_ioctl_syno_quota_rescan(file, argp); + case BTRFS_IOC_SYNO_QUOTA_STATUS: + return btrfs_ioctl_syno_quota_status(file, argp); +#endif /* MY_ABC_HERE */ case BTRFS_IOC_DEV_REPLACE: return btrfs_ioctl_dev_replace(fs_info, argp); case BTRFS_IOC_GET_SUPPORTED_FEATURES: @@ -5043,6 +7953,65 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_get_subvol_rootref(file, argp); case BTRFS_IOC_INO_LOOKUP_USER: return btrfs_ioctl_ino_lookup_user(file, argp); +#ifdef MY_ABC_HERE + case BTRFS_IOC_FIND_NEXT_CHUNK_INFO: + return btrfs_ioctl_syno_find_next_chunk_info(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNO_RESERVE_LOG_TREE_BLOCK_GROUP: + return btrfs_ioctl_syno_reserve_log_tree_bg(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_QGROUP_QUERY: + return btrfs_ioctl_qgroup_query(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNO_CLONE_RANGE_V2: + return btrfs_ioctl_syno_clone_range_v2(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_FREE_SPACE_ANALYZE: + return btrfs_ioctl_free_space_analyze(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_COMPR_CTL: + return btrfs_ioctl_compr_ctl(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SNAPSHOT_SIZE_QUERY: + return btrfs_ioctl_snapshot_size_query(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNO_USAGE_CTL: + return btrfs_ioctl_syno_usage_ctl(file, argp); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + case BTRFS_IOC_CKSUMFAILED_FILES_GET: + return btrfs_ioctl_cksumfailed_files_get(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNO_SET_DEDUPE_FLAG: + return btrfs_ioctl_syno_dedupe_cmd(file, argp); + case BTRFS_IOC_SYNO_EXTENT_SAME: + return btrfs_ioctl_syno_extent_same(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNO_FEAT_TREE_CTL: + return btrfs_ioctl_syno_feat_tree_ctl(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_SYNO_LOCKER_GET: + return btrfs_ioctl_syno_locker_get(file, argp); + case BTRFS_IOC_SYNO_LOCKER_SET: + return btrfs_ioctl_syno_locker_set(file, argp); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_GET_SYNO_FLAGS: + return btrfs_ioctl_get_syno_flags(file, argp); + case BTRFS_IOC_SET_SYNO_FLAGS: + return btrfs_ioctl_set_syno_flags(file, argp); +#endif /* MY_ABC_HERE */ } return -ENOTTY; diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index 66e02ebdd340..a800afc07927 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c @@ -594,24 +594,12 @@ struct extent_buffer *__btrfs_read_lock_root_node(struct btrfs_root *root, * acquire the lock. */ -int btrfs_drew_lock_init(struct btrfs_drew_lock *lock) +void btrfs_drew_lock_init(struct btrfs_drew_lock *lock) { - int ret; - - ret = percpu_counter_init(&lock->writers, 0, GFP_KERNEL); - if (ret) - return ret; - atomic_set(&lock->readers, 0); + atomic_set(&lock->writers, 0); init_waitqueue_head(&lock->pending_readers); init_waitqueue_head(&lock->pending_writers); - - return 0; -} - -void btrfs_drew_lock_destroy(struct btrfs_drew_lock *lock) -{ - percpu_counter_destroy(&lock->writers); } /* Return true if acquisition is successful, false otherwise */ @@ -620,10 +608,10 @@ bool btrfs_drew_try_write_lock(struct btrfs_drew_lock *lock) if (atomic_read(&lock->readers)) return false; - percpu_counter_inc(&lock->writers); + atomic_inc(&lock->writers); /* Ensure writers count is updated before we check for pending readers */ - smp_mb(); + smp_mb__after_atomic(); if (atomic_read(&lock->readers)) { btrfs_drew_write_unlock(lock); return false; @@ -643,7 +631,7 @@ void btrfs_drew_write_lock(struct btrfs_drew_lock *lock) void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock) { - percpu_counter_dec(&lock->writers); + atomic_dec(&lock->writers); cond_wake_up(&lock->pending_readers); } @@ -659,8 +647,7 @@ void btrfs_drew_read_lock(struct btrfs_drew_lock *lock) */ smp_mb__after_atomic(); - wait_event(lock->pending_readers, - percpu_counter_sum(&lock->writers) == 0); + wait_event(lock->pending_readers, atomic_read(&lock->writers) == 0); } void btrfs_drew_read_unlock(struct btrfs_drew_lock *lock) diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h index 3ea81ed3320b..df69ec6dd0c7 100644 --- a/fs/btrfs/locking.h +++ b/fs/btrfs/locking.h @@ -133,13 +133,12 @@ static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw) struct btrfs_drew_lock { atomic_t readers; - struct percpu_counter writers; + atomic_t writers; wait_queue_head_t pending_writers; wait_queue_head_t pending_readers; }; -int btrfs_drew_lock_init(struct btrfs_drew_lock *lock); -void btrfs_drew_lock_destroy(struct btrfs_drew_lock *lock); +void btrfs_drew_lock_init(struct btrfs_drew_lock *lock); void btrfs_drew_write_lock(struct btrfs_drew_lock *lock); bool btrfs_drew_try_write_lock(struct btrfs_drew_lock *lock); void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock); diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 87bac9ecdf4c..eeb7b8f89aa3 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -231,6 +234,9 @@ static int __btrfs_add_ordered_extent(struct btrfs_inode *inode, u64 file_offset spin_lock(&root->ordered_extent_lock); list_add_tail(&entry->root_extent_list, &root->ordered_extents); +#ifdef MY_ABC_HERE + atomic64_inc(&fs_info->syno_ordered_extent_nr); +#endif /* MY_ABC_HERE */ root->nr_ordered_extents++; if (root->nr_ordered_extents == 1) { spin_lock(&fs_info->ordered_root_lock); @@ -348,6 +354,10 @@ int btrfs_dec_test_first_ordered_pending(struct btrfs_inode *inode, btrfs_crit(fs_info, "bad ordered accounting left %llu size %llu", entry->bytes_left, to_dec); +#ifdef MY_ABC_HERE + /* avoid underflow */ + to_dec = entry->bytes_left; +#endif /* MY_ABC_HERE */ } entry->bytes_left -= to_dec; if (!uptodate) @@ -411,6 +421,10 @@ int btrfs_dec_test_ordered_pending(struct btrfs_inode *inode, btrfs_crit(inode->root->fs_info, "bad ordered accounting left %llu size %llu", entry->bytes_left, io_size); +#ifdef MY_ABC_HERE + /* avoid underflow */ + io_size = entry->bytes_left; +#endif /* MY_ABC_HERE */ } entry->bytes_left -= io_size; if (!uptodate) @@ -524,6 +538,10 @@ void btrfs_remove_ordered_extent(struct btrfs_inode *btrfs_inode, spin_lock(&root->ordered_extent_lock); list_del_init(&entry->root_extent_list); +#ifdef MY_ABC_HERE + atomic64_dec(&fs_info->syno_ordered_extent_nr); + atomic64_inc(&fs_info->syno_ordered_extent_processed_nr); +#endif /* MY_ABC_HERE */ root->nr_ordered_extents--; trace_btrfs_ordered_extent_remove(btrfs_inode, entry); @@ -536,6 +554,10 @@ void btrfs_remove_ordered_extent(struct btrfs_inode *btrfs_inode, } spin_unlock(&root->ordered_extent_lock); wake_up(&entry->wait); +#ifdef MY_ABC_HERE + if (waitqueue_active(&fs_info->syno_ordered_queue_wait)) + wake_up(&fs_info->syno_ordered_queue_wait); +#endif /* MY_ABC_HERE */ } static void btrfs_run_ordered_extent_work(struct btrfs_work *work) @@ -569,8 +591,13 @@ u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr, ordered = list_first_entry(&splice, struct btrfs_ordered_extent, root_extent_list); +#ifdef MY_ABC_HERE + if (ordered->disk_bytenr && (range_end <= ordered->disk_bytenr || + ordered->disk_bytenr + ordered->disk_num_bytes <= range_start)) { +#else if (range_end <= ordered->disk_bytenr || ordered->disk_bytenr + ordered->disk_num_bytes <= range_start) { +#endif /* MY_ABC_HERE */ list_move_tail(&ordered->root_extent_list, &skipped); cond_resched_lock(&root->ordered_extent_lock); continue; @@ -657,6 +684,20 @@ void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry, int wait) trace_btrfs_ordered_extent_start(inode, entry); +#ifdef MY_ABC_HERE + if (wait) { + entry->high_priority = true; + if (test_bit(BTRFS_ORDERED_WORK_INITIALIZED, &entry->flags) && + work_pending(&entry->work.normal_work) && + !test_and_set_bit(BTRFS_ORDERED_HIGH_PRIORITY, &entry->flags)) { + if (cancel_work_sync(&entry->work.normal_work)) { + btrfs_set_work_high_priority(&entry->work); + btrfs_queue_work(inode->root->fs_info->syno_high_priority_endio_workers, &entry->work); + } + } + } +#endif /* MY_ABC_HERE */ + /* * pages in the range can be dirty, clean or writeback. We * start IO on any dirty ones so the wait doesn't stall waiting diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index c3a2325e64a4..5841418b4fd1 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -62,6 +65,13 @@ enum { BTRFS_ORDERED_LOGGED_CSUM, /* We wait for this extent to complete in the current transaction */ BTRFS_ORDERED_PENDING, +#ifdef MY_ABC_HERE + BTRFS_ORDERED_WORK_INITIALIZED, + BTRFS_ORDERED_HIGH_PRIORITY, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ORDERED_DEDUPED, +#endif /* MY_ABC_HERE */ }; struct btrfs_ordered_extent { @@ -127,6 +137,10 @@ struct btrfs_ordered_extent { struct completion completion; struct btrfs_work flush_work; struct list_head work_list; + +#ifdef MY_ABC_HERE + bool high_priority; +#endif /* MY_ABC_HERE */ }; /* diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index c62771f3af8c..7c92cfa51a7c 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -9,7 +12,11 @@ struct root_name_map { u64 id; +#ifdef MY_ABC_HERE + char name[32]; +#else char name[16]; +#endif /* MY_ABC_HERE */ }; static const struct root_name_map root_map[] = { @@ -20,10 +27,18 @@ static const struct root_name_map root_map[] = { { BTRFS_FS_TREE_OBJECTID, "FS_TREE" }, { BTRFS_CSUM_TREE_OBJECTID, "CSUM_TREE" }, { BTRFS_TREE_LOG_OBJECTID, "TREE_LOG" }, +#ifdef MY_ABC_HERE + { BTRFS_SYNO_QUOTA_V2_TREE_OBJECTID, "SYNO_V2_QUOTA_TREE" }, + { BTRFS_SYNO_USRQUOTA_V2_TREE_OBJECTID, "SYNO_V2_USRQUOTA_TREE" }, +#else { BTRFS_QUOTA_TREE_OBJECTID, "QUOTA_TREE" }, +#endif /* MY_ABC_HERE */ { BTRFS_UUID_TREE_OBJECTID, "UUID_TREE" }, { BTRFS_FREE_SPACE_TREE_OBJECTID, "FREE_SPACE_TREE" }, { BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" }, +#ifdef MY_ABC_HERE + { BTRFS_BLOCK_GROUP_HINT_TREE_OBJECTID, "BG_HINT_TREE"}, +#endif /* MY_ABC_HERE */ }; const char *btrfs_root_name(const struct btrfs_key *key, char *buf) diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c index 2dcb1cb21634..21f3fea739d2 100644 --- a/fs/btrfs/props.c +++ b/fs/btrfs/props.c @@ -17,7 +17,8 @@ static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS); struct prop_handler { struct hlist_node node; const char *xattr_name; - int (*validate)(const char *value, size_t len); + int (*validate)(const struct btrfs_inode *inode, const char *value, + size_t len); int (*apply)(struct inode *inode, const char *value, size_t len); const char *(*extract)(struct inode *inode); int inheritable; @@ -55,7 +56,8 @@ find_prop_handler(const char *name, return NULL; } -int btrfs_validate_prop(const char *name, const char *value, size_t value_len) +int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name, + const char *value, size_t value_len) { const struct prop_handler *handler; @@ -69,7 +71,7 @@ int btrfs_validate_prop(const char *name, const char *value, size_t value_len) if (value_len == 0) return 0; - return handler->validate(value, value_len); + return handler->validate(inode, value, value_len); } int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode, @@ -252,14 +254,22 @@ int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path) return ret; } -static int prop_compression_validate(const char *value, size_t len) +static int prop_compression_validate(const struct btrfs_inode *inode, + const char *value, size_t len) { + if (!btrfs_inode_can_compress(inode)) + return -EINVAL; + if (!value) return 0; if (btrfs_compress_is_valid_type(value, len)) return 0; + if ((len == 2 && strncmp("no", value, 2) == 0) || + (len == 4 && strncmp("none", value, 4) == 0)) + return 0; + return -EINVAL; } @@ -269,7 +279,17 @@ static int prop_compression_apply(struct inode *inode, const char *value, struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); int type; + /* Reset to defaults */ if (len == 0) { + BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; + BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; + BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE; + return 0; + } + + /* Set NOCOMPRESS flag */ + if ((len == 2 && strncmp("no", value, 2) == 0) || + (len == 4 && strncmp("none", value, 4) == 0)) { BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE; @@ -350,7 +370,7 @@ static int inherit_props(struct btrfs_trans_handle *trans, * This is not strictly necessary as the property should be * valid, but in case it isn't, don't propagate it futher. */ - ret = h->validate(value, strlen(value)); + ret = h->validate(BTRFS_I(inode), value, strlen(value)); if (ret) continue; diff --git a/fs/btrfs/props.h b/fs/btrfs/props.h index 40b2c65b518c..2b2ac15ab788 100644 --- a/fs/btrfs/props.h +++ b/fs/btrfs/props.h @@ -13,7 +13,8 @@ void __init btrfs_props_init(void); int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const char *value, size_t value_len, int flags); -int btrfs_validate_prop(const char *name, const char *value, size_t value_len); +int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name, + const char *value, size_t value_len); int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path); diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 4bac32a274ce..379cc46c22ae 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2011 STRATO. All rights reserved. @@ -12,6 +15,10 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ #include "ctree.h" #include "transaction.h" @@ -36,6 +43,130 @@ * - check all ioctl parameters */ +#ifdef MY_ABC_HERE +enum { + SENT_UNDER = -1, + SENT_NONE = 0, + SENT_OVER = 1, +}; + +u64 qgroup_soft_limit = 0; + +static const struct genl_multicast_group qgroup_mcgrps[] = { + { .name = "events", }, +}; + +/* Netlink family structure for quota */ +static struct genl_family btrfs_qgroup_genl_family __ro_after_init = { + .module = THIS_MODULE, + .hdrsize = 0, + .name = "BTRFS_QUOTA", + .version = 1, + .maxattr = QGROUP_NL_A_MAX, + .mcgrps = qgroup_mcgrps, + .n_mcgrps = ARRAY_SIZE(qgroup_mcgrps), +}; + +#ifdef MY_ABC_HERE +static void prepare_netlink_notification(struct btrfs_qgroup *qg, + u64 *soft_qgroup_subvol_id, u64 *soft_qgroup_limit, u64 *soft_qgroup_used, + bool *over_limit) +{ + u64 soft_limit; + + if (!(qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) || !qgroup_soft_limit) + return; + + soft_limit = div_u64(qg->max_rfer * qgroup_soft_limit, 100); + // Should we send QGROUP_NL_C_OVER_LIMIT? + if (qg->last_sent != SENT_OVER && qg->rfer > soft_limit) { + qg->last_sent = SENT_OVER; + *over_limit = true; + goto notify; + } + + // Should we send QGROUP_NL_C_UNDER_LIMIT? + if (qg->last_sent != SENT_UNDER) { + if (soft_limit <= SZ_1M * 100) + return; + if (qg->rfer >= div_u64(qg->max_rfer * (qgroup_soft_limit - 1), 100)) + return; + if (qg->rfer >= soft_limit - (SZ_1M * 100)) + return; + + qg->last_sent = SENT_UNDER; + *over_limit = false; + goto notify; + } + + return; +notify: + *soft_qgroup_subvol_id = qg->qgroupid; + *soft_qgroup_limit = qg->max_rfer; + *soft_qgroup_used = qg->rfer; +} + +static void send_netlink_notification(struct btrfs_fs_info *fs_info, u64 qgroupid, + u64 quota_limit, u64 quota_used, int type) +{ + static atomic_t seq = ATOMIC_INIT(0); + struct sk_buff *skb; + void *msg_head; + int ret; + int msg_size = nla_total_size(BTRFS_FSID_SIZE) + (3 * nla_total_size_64bit(sizeof(u64))); + + /* We have to allocate using GFP_NOFS as we are called from a + * filesystem performing write and thus further recursion into + * the fs to free some data could cause deadlocks. */ + skb = genlmsg_new(msg_size, GFP_NOFS); + if (!skb) { + btrfs_warn(fs_info, "Not enough memory to send qgroup warning.\n"); + return; + } + msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), + &btrfs_qgroup_genl_family, 0, type); + if (!msg_head) { + btrfs_warn(fs_info, "Cannot store netlink header in qgroup warning.\n"); + goto err_out; + } + ret = nla_put(skb, QGROUP_NL_A_FSID, BTRFS_FSID_SIZE, fs_info->super_copy->fsid); + if (ret) + goto attr_err_out; + ret = nla_put_u64_64bit(skb, QGROUP_NL_A_SUBVOL_ID, qgroupid, QUOTA_NL_A_PAD); + if (ret) + goto attr_err_out; + ret = nla_put_u64_64bit(skb, QGROUP_NL_A_QUOTA_LIMIT, quota_limit, QUOTA_NL_A_PAD); + if (ret) + goto attr_err_out; + ret = nla_put_u64_64bit(skb, QGROUP_NL_A_QUOTA_USED, quota_used, QUOTA_NL_A_PAD); + if (ret) + goto attr_err_out; + genlmsg_end(skb, msg_head); + + genlmsg_multicast(&btrfs_qgroup_genl_family, skb, 0, 0, GFP_NOFS); + return; + +attr_err_out: + btrfs_warn(fs_info, "Not enough space to compose qgroup netlink message!\n"); +err_out: + kfree_skb(skb); +} +#endif /* MY_ABC_HERE */ + +int __init qgroup_netlink_init(void) +{ + if (genl_register_family(&btrfs_qgroup_genl_family) != 0) + printk(KERN_ERR + "Failed to create btrfs qgroup netlink interface.\n"); + return 0; +}; + +void qgroup_netlink_exit(void) +{ + genl_unregister_family(&btrfs_qgroup_genl_family); +}; +#endif /* MY_ABC_HERE */ + /* * Helpers to access qgroup reservation * @@ -83,6 +214,11 @@ static void qgroup_rsv_release(struct btrfs_fs_info *fs_info, qgroup->rsv.values[type] -= num_bytes; return; } +#ifdef MY_ABC_HERE + WARN_ONCE(1, "qgroup %llu reserved space underflow, have %llu to free %llu", + qgroup->qgroupid, + qgroup->rsv.values[type], num_bytes); +#endif /* MY_ABC_HERE */ #ifdef CONFIG_BTRFS_DEBUG WARN_RATELIMIT(1, "qgroup %llu %s reserved space underflow, have %llu to free %llu", @@ -92,6 +228,8 @@ static void qgroup_rsv_release(struct btrfs_fs_info *fs_info, qgroup->rsv.values[type] = 0; } +#ifdef MY_ABC_HERE +#else static void qgroup_rsv_add_by_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *dest, struct btrfs_qgroup *src) @@ -141,6 +279,7 @@ static inline u64 btrfs_qgroup_get_new_refcnt(struct btrfs_qgroup *qg, u64 seq) return 0; return qg->new_refcnt - seq; } +#endif /* MY_ABC_HERE */ /* * glue structure to represent the relations between qgroups. @@ -321,6 +460,12 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, } #endif +#ifdef MY_ABC_HERE +static void update_syno_quota_rescan_progress(struct btrfs_root *quota_root, + struct syno_quota_rescan_ctx *ctx, u64 subvol_id, + enum syno_quota_rescan_progress_update_type type); +#endif /* MY_ABC_HERE */ + /* * The full config is read in one go, only called from open_ctree() * It doesn't use any locking, as at this point we're still single-threaded @@ -336,8 +481,16 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) int ret = 0; u64 flags = 0; u64 rescan_progress = 0; +#ifdef MY_ABC_HERE + u64 subvol_id; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) +#endif /* MY_ABC_HERE */ return 0; fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL); @@ -351,6 +504,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) ret = -ENOMEM; goto out; } +#ifdef MY_ABC_HERE + path->reada = READA_FORWARD_ALWAYS; +#endif /* MY_ABC_HERE */ ret = btrfs_sysfs_add_qgroups(fs_info); if (ret < 0) @@ -381,12 +537,31 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) ptr = btrfs_item_ptr(l, slot, struct btrfs_qgroup_status_item); +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags) && + btrfs_qgroup_status_version(l, ptr) != + BTRFS_QGROUP_V2_STATUS_VERSION) { + btrfs_err(fs_info, + "syno quota v2 found bad %llu version, quota disabled", + btrfs_qgroup_status_version(l, ptr)); + goto out; + } + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + btrfs_qgroup_status_version(l, ptr) != + BTRFS_QGROUP_STATUS_VERSION) { + btrfs_err(fs_info, + "syno quota v1 found bad %llu version, quota disabled", + btrfs_qgroup_status_version(l, ptr)); + goto out; + } +#else if (btrfs_qgroup_status_version(l, ptr) != BTRFS_QGROUP_STATUS_VERSION) { btrfs_err(fs_info, "old qgroup version, quota disabled"); goto out; } +#endif /* MY_ABC_HERE */ if (btrfs_qgroup_status_generation(l, ptr) != fs_info->generation) { flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; @@ -455,6 +630,83 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) } btrfs_release_path(path); +#ifdef MY_ABC_HERE + // Setup rescan before pass 2, since we may goto out in pass 2 and miss the rescan setup. + subvol_id = rescan_progress; + + // No need to rescan. Go to pass 2. + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags) || !subvol_id) + goto pass2; + + fs_info->syno_quota_rescan_ctx = kzalloc(sizeof(struct syno_quota_rescan_ctx), GFP_KERNEL); + if (!fs_info->syno_quota_rescan_ctx) { + btrfs_warn(fs_info, "Failed to alloc syno_quota_rescan_ctx"); + ret = -ENOMEM; + goto out; + } + + fs_info->syno_quota_rescan_subvol_ulist = ulist_alloc(GFP_KERNEL); + if (!fs_info->syno_quota_rescan_subvol_ulist) { + btrfs_warn(fs_info, "Failed to alloc syno_quota_rescan_subvol_ulist"); + ret = -ENOMEM; + goto out; + } + + // Read rescan subvol list. + while (subvol_id) { + struct btrfs_syno_quota_rescan_item *ptr; + struct syno_quota_rescan_ctx *ctx = fs_info->syno_quota_rescan_ctx; + u64 flags; + u64 ino; + + key.objectid = 0; + key.type = BTRFS_SYNO_QUOTA_RESCAN_KEY; + key.offset = subvol_id; + + ret = btrfs_search_slot(NULL, quota_root, &key, path, 0, 0); + if (ret) { + btrfs_warn(fs_info, + "Failed to read syno quota rescan item, root = %llu", subvol_id); + if (ret > 0) + ret = -ENOENT; + break; + } + + slot = path->slots[0]; + l = path->nodes[0]; + ptr = btrfs_item_ptr(l, slot, struct btrfs_syno_quota_rescan_item); + + flags = btrfs_syno_quota_rescan_flags(l, ptr); + if (!(flags & (SYNO_QUOTA_RESCAN_QUEUED | SYNO_QUOTA_RESCAN_DOING))) { + update_syno_quota_rescan_progress(fs_info->quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_ADD_FINISHED); + subvol_id = btrfs_syno_quota_rescan_next_root(l, ptr); + btrfs_release_path(path); + continue; + } + + ino = btrfs_syno_quota_rescan_inode(l, ptr); + ret = ulist_add(fs_info->syno_quota_rescan_subvol_ulist, subvol_id, ino, GFP_KERNEL); + if (ret != 1) { + if (ret == 0) { + btrfs_warn(fs_info, "Syno quota rescan detect duplicate items, the list is broken."); + ret = -EEXIST; + } else { + btrfs_warn(fs_info, "Syno quota rescan encounter -ENOMEM."); + ret = -ENOMEM; + } + break; + } + update_syno_quota_rescan_progress(fs_info->quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_ADD_NEW); + + subvol_id = btrfs_syno_quota_rescan_next_root(l, ptr); + btrfs_release_path(path); + } + btrfs_release_path(path); +pass2: +#endif /* MY_ABC_HERE */ + /* * pass 2: read all qgroup relations */ @@ -495,11 +747,19 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) if (ret) break; } + out: btrfs_free_path(path); fs_info->qgroup_flags |= flags; if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) +#ifdef MY_ABC_HERE + { + clear_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags); + } +#else clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); +#endif /* MY_ABC_HERE */ else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN && ret >= 0) ret = qgroup_rescan_init(fs_info, rescan_progress, 0); @@ -507,6 +767,12 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) if (ret < 0) { ulist_free(fs_info->qgroup_ulist); fs_info->qgroup_ulist = NULL; +#ifdef MY_ABC_HERE + ulist_free(fs_info->syno_quota_rescan_subvol_ulist); + fs_info->syno_quota_rescan_subvol_ulist = NULL; + kfree(fs_info->syno_quota_rescan_ctx); + fs_info->syno_quota_rescan_ctx = NULL; +#endif /* MY_ABC_HERE */ fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; btrfs_sysfs_del_qgroups(fs_info); } @@ -526,7 +792,12 @@ bool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info) struct rb_node *node; bool ret = false; +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) +#endif /* MY_ABC_HERE */ return ret; /* * Since we're unmounting, there is no race and no need to grab qgroup @@ -577,6 +848,12 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) */ ulist_free(fs_info->qgroup_ulist); fs_info->qgroup_ulist = NULL; +#ifdef MY_ABC_HERE + ulist_free(fs_info->syno_quota_rescan_subvol_ulist); + fs_info->syno_quota_rescan_subvol_ulist = NULL; + kfree(fs_info->syno_quota_rescan_ctx); + fs_info->syno_quota_rescan_ctx = NULL; +#endif /* MY_ABC_HERE */ btrfs_sysfs_del_qgroups(fs_info); } @@ -709,6 +986,9 @@ static int del_qgroup_item(struct btrfs_trans_handle *trans, u64 qgroupid) struct btrfs_root *quota_root = trans->fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; +#ifdef MY_ABC_HERE + struct btrfs_fs_info *fs_info = trans->fs_info; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -744,6 +1024,24 @@ static int del_qgroup_item(struct btrfs_trans_handle *trans, u64 qgroupid) ret = btrfs_del_item(trans, quota_root, path); +#ifdef MY_ABC_HERE + btrfs_release_path(path); + + // Remove rescan item. + mutex_lock(&fs_info->qgroup_rescan_lock); + key.type = BTRFS_SYNO_QUOTA_RESCAN_KEY; + ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); + if (ret) { + if (ret > 0) + ret = 0; // This subvol may be from quota 1.0 or vanilla kernel. + goto unlock_rescan_lock; + } + + ret = btrfs_del_item(trans, quota_root, path); + +unlock_rescan_lock: + mutex_unlock(&fs_info->qgroup_rescan_lock); +#endif /* MY_ABC_HERE */ out: btrfs_free_path(path); return ret; @@ -878,6 +1176,218 @@ static int update_qgroup_status_item(struct btrfs_trans_handle *trans) return ret; } +#ifdef MY_ABC_HERE +int btrfs_read_syno_quota_rescan_item(struct btrfs_root *quota_root, u64 subvol_id, + struct btrfs_syno_quota_rescan_item *rescan_item) +{ + int ret; + struct btrfs_path *path; + struct btrfs_key key; + + if (unlikely(!quota_root)) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.type = BTRFS_SYNO_QUOTA_RESCAN_KEY; + key.offset = subvol_id; + + ret = btrfs_search_slot(NULL, quota_root, &key, path, 0, 0); + if (ret) { + if (ret > 0) + ret = -ENOENT; + goto out; + } + + read_extent_buffer(path->nodes[0], rescan_item, + btrfs_item_ptr_offset(path->nodes[0], path->slots[0]), sizeof(*rescan_item)); + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +// Will read tree size from btree rescan item, so rescan item must be updated before us. +static void update_syno_quota_rescan_progress(struct btrfs_root *quota_root, + struct syno_quota_rescan_ctx *ctx, u64 subvol_id, + enum syno_quota_rescan_progress_update_type type) +{ + struct btrfs_syno_quota_rescan_item rescan_item; + int ret; + + ret = btrfs_read_syno_quota_rescan_item(quota_root, subvol_id, &rescan_item); + if (ret) { + btrfs_warn(quota_root->fs_info, "Failed to read syno quota rescan item, id = %llu, ret = %d", + subvol_id, ret); + return; + } + + switch (type) { + case SYNO_QUOTA_PROGRESS_REMOVE_SCANNING: // Same as SYNO_QUOTA_PROGRESS_FINISH_ONE. + ctx->subvol_id = 0; + ctx->total_finished_size += rescan_item.tree_size; + memset(ctx->current_path, 0, sizeof(ctx->current_path)); + break; + case SYNO_QUOTA_PROGRESS_REMOVE_QUEUED: + if (ctx->total_size >= rescan_item.tree_size) + ctx->total_size -= rescan_item.tree_size; + else + WARN_ON_ONCE(1); + break; + case SYNO_QUOTA_PROGRESS_REMOVE_FINISHED: + break; + case SYNO_QUOTA_PROGRESS_ADD_NEW: + ctx->total_size += rescan_item.tree_size; + break; + case SYNO_QUOTA_PROGRESS_ADD_FINISHED: + ctx->total_size += rescan_item.tree_size; + ctx->total_finished_size += rescan_item.tree_size; + break; + case SYNO_QUOTA_PROGRESS_FINISH_ONE: // Same as SYNO_QUOTA_PROGRESS_REMOVE_SCANNING. + ctx->subvol_id = 0; + ctx->total_finished_size += rescan_item.tree_size; + memset(ctx->current_path, 0, sizeof(ctx->current_path)); + break; + case SYNO_QUOTA_PROGRESS_FINISH_ALL: + WARN_ON_ONCE(ctx->total_finished_size + rescan_item.tree_size != ctx->total_size); + + // Reset progress. + memset(ctx, 0, sizeof(*ctx)); + break; + default: + WARN_ON_ONCE(1); + } +} + +// Cannot used on new empty rescan item. +static void update_syno_quota_rescan_flags(struct extent_buffer *leaf, + struct btrfs_syno_quota_rescan_item *rescan_item, u64 flags) +{ + u64 orig_flags = btrfs_syno_quota_rescan_flags(leaf, rescan_item); + + switch (flags) { + case SYNO_QUOTA_RESCAN_DONE: { + // If error was found after we ran the scan, we should trigger another new scan to fix. + orig_flags &= (SYNO_QUOTA_RESCAN_ERR | SYNO_QUOTA_RESCAN_NEED); + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, + orig_flags | SYNO_QUOTA_RESCAN_DONE); + break; + } + case SYNO_QUOTA_RESCAN_QUEUED: { + if (orig_flags & SYNO_QUOTA_RESCAN_DOING) { + WARN_ON_ONCE(1); + break; + } + // Start a new scan, clear all errors. + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, SYNO_QUOTA_RESCAN_QUEUED); + break; + } + case SYNO_QUOTA_RESCAN_DOING: { + if (orig_flags & SYNO_QUOTA_RESCAN_DONE) { + WARN_ON_ONCE(1); + break; + } + orig_flags &= ~SYNO_QUOTA_RESCAN_QUEUED; + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, + orig_flags | SYNO_QUOTA_RESCAN_DOING); + break; + } + case SYNO_QUOTA_RESCAN_ERR: { + if (orig_flags & SYNO_QUOTA_RESCAN_DONE) { + WARN_ON_ONCE(1); + break; + } + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, + orig_flags | SYNO_QUOTA_RESCAN_ERR); + break; + } + case (SYNO_QUOTA_RESCAN_ERR | SYNO_QUOTA_RESCAN_DONE): { + orig_flags &= SYNO_QUOTA_RESCAN_NEED; + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, + orig_flags | SYNO_QUOTA_RESCAN_DONE | SYNO_QUOTA_RESCAN_ERR); + break; + } + case SYNO_QUOTA_RESCAN_NEED: { + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, + orig_flags | SYNO_QUOTA_RESCAN_NEED); + break; + } + default: + WARN_ON_ONCE(1); + } +} + +int btrfs_add_update_syno_quota_rescan_item(struct btrfs_trans_handle *trans, + struct btrfs_root *quota_root, u64 subvol_id, + struct syno_quota_rescan_item_updater *updater) +{ + int ret; + struct btrfs_path *path; + struct btrfs_syno_quota_rescan_item *rescan_item; + struct extent_buffer *leaf; + struct btrfs_key key; + + if (unlikely(!quota_root)) + return -EINVAL; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &trans->fs_info->flags) && + !updater->enable) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.type = BTRFS_SYNO_QUOTA_RESCAN_KEY; + key.offset = subvol_id; + + ret = btrfs_insert_empty_item(trans, quota_root, path, &key, + sizeof(*rescan_item)); + if (ret && ret != -EEXIST) + goto out; + + // Insert a new item, SYNO_QUOTA_RESCAN_ITEM_SKIP is not allowed. + if (ret != -EEXIST && syno_quota_rescan_item_check(updater)) { + WARN_ON_ONCE(1); + ret = -EINVAL; + goto out; + } + + leaf = path->nodes[0]; + rescan_item = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_syno_quota_rescan_item); + + if (updater->flags != SYNO_QUOTA_RESCAN_ITEM_SKIP) { + if (ret != -EEXIST) + btrfs_set_syno_quota_rescan_flags(leaf, rescan_item, updater->flags); + else + update_syno_quota_rescan_flags(leaf, rescan_item, updater->flags); + } + if (updater->version != SYNO_QUOTA_RESCAN_ITEM_SKIP) + btrfs_set_syno_quota_rescan_version(leaf, rescan_item, updater->version); + btrfs_set_syno_quota_rescan_generation(leaf, rescan_item, trans->transid); + if (updater->rescan_inode != SYNO_QUOTA_RESCAN_ITEM_SKIP) + btrfs_set_syno_quota_rescan_inode(leaf, rescan_item, updater->rescan_inode); + if (updater->end_inode != SYNO_QUOTA_RESCAN_ITEM_SKIP) + btrfs_set_syno_quota_rescan_end_inode(leaf, rescan_item, updater->end_inode); + if (updater->tree_size != SYNO_QUOTA_RESCAN_ITEM_SKIP) + btrfs_set_syno_quota_rescan_tree_size(leaf, rescan_item, updater->tree_size); + if (updater->next_root != SYNO_QUOTA_RESCAN_ITEM_SKIP) + btrfs_set_syno_quota_rescan_next_root(leaf, rescan_item, updater->next_root); + + btrfs_mark_buffer_dirty(leaf); + ret = 0; +out: + btrfs_free_path(path); + return ret; +} +#endif /* MY_ABC_HERE */ + /* * called with qgroup_lock held */ @@ -926,7 +1436,11 @@ static int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +int btrfs_quota_enable(struct btrfs_fs_info *fs_info, u64 cmd) +#else int btrfs_quota_enable(struct btrfs_fs_info *fs_info) +#endif /* MY_ABC_HERE */ { struct btrfs_root *quota_root; struct btrfs_root *tree_root = fs_info->tree_root; @@ -941,6 +1455,17 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) int ret = 0; int slot; +#ifdef MY_ABC_HERE + // Default using v2 quota. + if (cmd == BTRFS_QUOTA_CTL_ENABLE) + cmd = BTRFS_QUOTA_V2_CTL_ENABLE; + + if (btrfs_test_opt(fs_info, NO_QUOTA_TREE)) { + btrfs_info(fs_info, "Can't enable quota with mount_opt no_quota_tree"); + return -EINVAL; + } +#endif /* MY_ABC_HERE */ + mutex_lock(&fs_info->qgroup_ioctl_lock); if (fs_info->quota_root) goto out; @@ -996,7 +1521,12 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) /* * initially create the quota tree */ - quota_root = btrfs_create_tree(trans, BTRFS_QUOTA_TREE_OBJECTID); +#ifdef MY_ABC_HERE + if (cmd == BTRFS_QUOTA_V2_CTL_ENABLE) + quota_root = btrfs_create_tree(trans, BTRFS_SYNO_QUOTA_V2_TREE_OBJECTID); + else +#endif /* MY_ABC_HERE */ + quota_root = btrfs_create_tree(trans, BTRFS_QUOTA_TREE_OBJECTID); if (IS_ERR(quota_root)) { ret = PTR_ERR(quota_root); btrfs_abort_transaction(trans, ret); @@ -1025,7 +1555,12 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) ptr = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_qgroup_status_item); btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); - btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); +#ifdef MY_ABC_HERE + if (cmd == BTRFS_QUOTA_V2_CTL_ENABLE) + btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_V2_STATUS_VERSION); + else +#endif /* MY_ABC_HERE */ + btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON | BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags); @@ -1088,6 +1623,41 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) */ continue; } +#ifdef MY_ABC_HERE + if (!ret && cmd == BTRFS_QUOTA_V2_CTL_ENABLE) { + struct syno_quota_rescan_item_updater updater; + struct btrfs_root *fs_root; + + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_DONE | SYNO_QUOTA_RESCAN_NEED; + updater.version = 0; // So root->invalid_quota will be set. + updater.rescan_inode = 0; + updater.end_inode = (u64)-1; + updater.tree_size = 0; + updater.next_root = 0; + updater.enable = true; + + ret = btrfs_add_update_syno_quota_rescan_item(trans, quota_root, + found_key.offset, &updater); + if (ret) + btrfs_warn(fs_info, + "Failed to create syno quota rescan item for root %llu, ret = %d", + found_key.offset, ret); + + /* + * If fs root is not in memory, we set invalid_quota in + * btrfs_read_syno_quota_for_root(). + */ + fs_root = btrfs_lookup_fs_root(fs_info, found_key.offset); + if (fs_root) { + fs_root->invalid_quota = true; + fs_root->rescan_inode = 0; + btrfs_put_root(fs_root); + } + + ret = 0; + } +#endif /* MY_ABC_HERE */ } ret = btrfs_next_item(tree_root, path); if (ret < 0) { @@ -1118,6 +1688,28 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) goto out_free_path; } +#ifdef MY_ABC_HERE + if (!ret && cmd == BTRFS_QUOTA_V2_CTL_ENABLE) { + struct syno_quota_rescan_item_updater updater; + + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_DONE; + updater.version = BTRFS_QGROUP_V2_STATUS_VERSION; + updater.rescan_inode = (u64)-1; + updater.end_inode = (u64)-1; + updater.tree_size = 0; + updater.next_root = 0; + updater.enable = true; + + ret = btrfs_add_update_syno_quota_rescan_item(trans, quota_root, + BTRFS_FS_TREE_OBJECTID, &updater); + if (ret) + btrfs_warn(fs_info, + "Failed to create syno quota rescan item for root 5, ret = %d", ret); + ret = 0; // No need to abort transaction, it is not that critical. + } +#endif /* MY_ABC_HERE */ + ret = btrfs_commit_transaction(trans); trans = NULL; if (ret) @@ -1128,11 +1720,26 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) * deadlocks on fs_info->qgroup_ioctl_lock with concurrent snapshot * creation. */ +#ifdef MY_ABC_HERE + down_write(&fs_info->inflight_reserve_lock); +#endif /* MY_ABC_HERE */ spin_lock(&fs_info->qgroup_lock); fs_info->quota_root = quota_root; +#ifdef MY_ABC_HERE + if (cmd == BTRFS_QUOTA_V1_CTL_ENABLE) + set_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags); + else + set_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags); +#else set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); +#endif /* MY_ABC_HERE */ spin_unlock(&fs_info->qgroup_lock); +#ifdef MY_ABC_HERE + up_write(&fs_info->inflight_reserve_lock); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#else ret = qgroup_rescan_init(fs_info, 0, 1); if (!ret) { qgroup_rescan_zero_tracking(fs_info); @@ -1140,6 +1747,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) btrfs_queue_work(fs_info->qgroup_rescan_workers, &fs_info->qgroup_rescan_work); } +#endif /* MY_ABC_HERE */ out_free_path: btrfs_free_path(path); @@ -1167,6 +1775,19 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) struct btrfs_trans_handle *trans = NULL; int ret = 0; +#ifdef MY_ABC_HERE + /* + * Protected by fs_info->subvol_sem, so user quota will not do enable + * before we finish qgroup disable. + */ + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) || + test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + btrfs_warn(fs_info, + "Should disable user quota before disable qgroup."); + return -EINVAL; + } +#endif /* MY_ABC_HERE */ + mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) goto out; @@ -1193,7 +1814,14 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) if (!fs_info->quota_root) goto out; +#ifdef MY_ABC_HERE + fs_info->need_clear_reserve = true; + smp_wmb(); + clear_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags); +#else clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); +#endif /* MY_ABC_HERE */ btrfs_qgroup_wait_for_completion(fs_info, false); spin_lock(&fs_info->qgroup_lock); quota_root = fs_info->quota_root; @@ -1224,6 +1852,14 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) btrfs_put_root(quota_root); +#ifdef MY_ABC_HERE + ret = btrfs_end_transaction(trans); + trans = NULL; + btrfs_start_delalloc_roots(fs_info, U64_MAX, false); + btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); + fs_info->need_clear_reserve = false; +#endif /* MY_ABC_HERE */ + out: mutex_unlock(&fs_info->qgroup_ioctl_lock); if (ret && trans) @@ -1234,6 +1870,164 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) return ret; } +#ifdef MY_ABC_HERE +int btrfs_quota_unload(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *quota_root; + struct btrfs_trans_handle *trans = NULL; + int ret = 0; + + /* + * Protected by fs_info->subvol_sem, so user quota will not do enable + * before we finish qgroup disable. + */ + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) || + test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + btrfs_warn(fs_info, + "Should disable user quota before disable qgroup."); + return -EINVAL; + } + + mutex_lock(&fs_info->qgroup_ioctl_lock); + if (!fs_info->quota_root) + goto out; + mutex_unlock(&fs_info->qgroup_ioctl_lock); + + /* + * 1 For the root item + * + * We should also reserve enough items for the quota tree deletion in + * btrfs_clean_quota_tree but this is not done. + * + * Also, we must always start a transaction without holding the mutex + * qgroup_ioctl_lock, see btrfs_quota_enable(). + */ + trans = btrfs_start_transaction(fs_info->tree_root, 1); + + mutex_lock(&fs_info->qgroup_ioctl_lock); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + if (!fs_info->quota_root) + goto out; + + fs_info->need_clear_reserve = true; + smp_wmb(); + clear_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags); + btrfs_qgroup_wait_for_completion(fs_info, false); + spin_lock(&fs_info->qgroup_lock); + quota_root = fs_info->quota_root; + fs_info->quota_root = NULL; + fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; + spin_unlock(&fs_info->qgroup_lock); + btrfs_free_qgroup_config(fs_info); + + btrfs_start_delalloc_roots(fs_info, U64_MAX, false); + btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); + fs_info->need_clear_reserve = false; + ret = btrfs_commit_transaction(trans); + trans = NULL; + + list_del("a_root->dirty_list); + btrfs_put_root(quota_root); + +out: + mutex_unlock(&fs_info->qgroup_ioctl_lock); + if (ret && trans) + btrfs_end_transaction(trans); + else if (trans) + ret = btrfs_end_transaction(trans); + + return ret; +} + +int btrfs_quota_remove_v1(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *root; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key location; + int ret = 0; + int nr; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + // Read old qgroup root. + location.objectid = BTRFS_QUOTA_TREE_OBJECTID; + location.type = BTRFS_ROOT_ITEM_KEY; + location.offset = 0; + + root = btrfs_read_tree_root(tree_root, &location); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + + location.objectid = 0; + location.offset = 0; + location.type = 0; + + while (1) { + trans = btrfs_start_transaction(tree_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto free_root; + } + + ret = btrfs_search_slot(trans, root, &location, path, -1, 1); + if (ret < 0) + goto free_root; + nr = btrfs_header_nritems(path->nodes[0]); + if (!nr) + break; + path->slots[0] = 0; + ret = btrfs_del_items(trans, root, path, 0, nr); + if (ret) + goto free_root; + + btrfs_release_path(path); + btrfs_end_transaction_throttle(trans); + trans = NULL; + cond_resched(); + } + btrfs_release_path(path); + + // Remove root item from root tree. + ret = btrfs_del_root(trans, &root->root_key); + +free_root: + btrfs_release_path(path); + list_del(&root->dirty_list); + btrfs_tree_lock(root->node); + btrfs_clean_tree_block(root->node); + btrfs_tree_unlock(root->node); + btrfs_free_tree_block(trans, root, root->node, 0, 1); + + free_extent_buffer(root->node); + free_extent_buffer(root->commit_root); + kfree(root); + + if (trans) { + if (!ret) + ret = btrfs_commit_transaction(trans); + else + btrfs_end_transaction(trans); + } +out: + btrfs_free_path(path); + return ret; +} +#endif /* MY_ABC_HERE */ + static void qgroup_dirty(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup) { @@ -1255,6 +2049,8 @@ static void qgroup_dirty(struct btrfs_fs_info *fs_info, * * Caller should hold fs_info->qgroup_lock. */ +#ifdef MY_ABC_HERE +#else static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, struct ulist *tmp, u64 ref_root, struct btrfs_qgroup *src, int sign) @@ -1319,7 +2115,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, out: return ret; } - +#endif /* MY_ABC_HERE */ /* * Quick path for updating qgroup with only excl refs. @@ -1336,6 +2132,9 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info, struct ulist *tmp, u64 src, u64 dst, int sign) { +#ifdef MY_ABC_HERE + return 0; +#else struct btrfs_qgroup *qgroup; int ret = 1; int err = 0; @@ -1356,6 +2155,7 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info, if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; return ret; +#endif /* MY_ABC_HERE */ } int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, @@ -1382,7 +2182,11 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) { +#ifdef MY_ABC_HERE + ret = -ESRCH; +#else ret = -ENOTCONN; +#endif /* MY_ABC_HERE */ goto out; } member = find_qgroup_rb(fs_info, src); @@ -1511,7 +2315,11 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) { +#ifdef MY_ABC_HERE + ret = -ESRCH; +#else ret = -ENOTCONN; +#endif /* MY_ABC_HERE */ goto out; } quota_root = fs_info->quota_root; @@ -1539,6 +2347,126 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) return ret; } +#ifdef MY_ABC_HERE +/* + * struct btrfs_ioctl_qgroup_query_args should be initialized to zero + */ +int btrfs_qgroup_query(struct btrfs_root *root, + struct btrfs_ioctl_qgroup_query_args *qqa) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_qgroup *qgroup; + u64 qgroupid = root->root_key.objectid; + int ret; + +#ifdef MY_ABC_HERE + if (unlikely(root->invalid_quota)) + return -ESRCH; +#endif /* MY_ABC_HERE */ + + mutex_lock(&fs_info->qgroup_ioctl_lock); +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { +#else + if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { +#endif /* MY_ABC_HERE */ + ret = -ESRCH; + goto unlock; + } + + qgroup = find_qgroup_rb(fs_info, qgroupid); + if (!qgroup) { + ret = -ENOENT; + goto unlock; + } + + qqa->rfer = qgroup->rfer; + qqa->rfer_cmpr = qgroup->rfer_cmpr; + qqa->excl = qgroup->excl; + qqa->excl_cmpr = qgroup->excl_cmpr; + + if (qgroup->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) + qqa->max_rfer = qgroup->max_rfer; + if (qgroup->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) + qqa->max_excl = qgroup->max_excl; + if (qgroup->lim_flags & BTRFS_QGROUP_LIMIT_RSV_RFER) + qqa->rsv_rfer = qgroup->rsv_rfer; + if (qgroup->lim_flags & BTRFS_QGROUP_LIMIT_RSV_EXCL) + qqa->rsv_excl = qgroup->rsv_excl; + qqa->reserved = qgroup->rsv.values[BTRFS_QGROUP_RSV_DATA]; + ret = 0; +unlock: + mutex_unlock(&fs_info->qgroup_ioctl_lock); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +// We will remove rescan item later in del_qgroup_item(). +void btrfs_remove_queued_syno_rescan(struct btrfs_trans_handle *trans, u64 subvol_id) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct syno_quota_rescan_ctx *ctx = fs_info->syno_quota_rescan_ctx; + struct ulist *ulist = fs_info->syno_quota_rescan_subvol_ulist; + struct ulist_node *node; + + if (!fs_info->quota_root || !ctx || !ulist) + return; + + mutex_lock(&fs_info->qgroup_rescan_lock); + node = ulist_search(ulist, subvol_id); + if (node) { + struct ulist_node *prev_node = NULL; + struct ulist_node *next_node = NULL; + u64 prev_subvol_id = 0; + u64 next_subvol_id = 0; + int ret; + + if (node->list.prev != &ulist->nodes) { + prev_node = list_entry(node->list.prev, struct ulist_node, list); + prev_subvol_id = prev_node->val; + } + + if (node->list.next != &ulist->nodes) { + next_node = list_entry(node->list.next, struct ulist_node, list); + next_subvol_id = next_node->val; + } + + if (prev_subvol_id) { + struct syno_quota_rescan_item_updater updater; + + syno_quota_rescan_item_init(&updater); + updater.next_root = (next_subvol_id)? next_subvol_id : 0; + ret = btrfs_add_update_syno_quota_rescan_item(trans, fs_info->quota_root, + prev_subvol_id, &updater); + if (ret) + btrfs_warn(fs_info, + "Failed to update syno quota rescan item, id = %llu, ret = %d.", + prev_subvol_id, ret); + } + + if (fs_info->qgroup_rescan_progress.objectid == subvol_id) + fs_info->qgroup_rescan_progress.objectid = next_subvol_id; + ulist_del(ulist, subvol_id, node->aux); + + // Update progress info. + if (!fs_info->qgroup_rescan_progress.objectid) { // No next subvol. All rescan are done. + update_syno_quota_rescan_progress(fs_info->quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_FINISH_ALL); + fs_info->qgroup_rescan_progress.objectid = 0; + } else if (ctx->subvol_id == subvol_id) // We are removing the current scanning subvol. + update_syno_quota_rescan_progress(fs_info->quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_FINISH_ONE); + else // We are removing a queued subvol. + update_syno_quota_rescan_progress(fs_info->quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_REMOVE_QUEUED); + } + mutex_unlock(&fs_info->qgroup_rescan_lock); + return; +} +#endif /* MY_ABC_HERE */ + int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) { struct btrfs_fs_info *fs_info = trans->fs_info; @@ -1548,7 +2476,11 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) { +#ifdef MY_ABC_HERE + ret = -ESRCH; +#else ret = -ENOTCONN; +#endif /* MY_ABC_HERE */ goto out; } @@ -1564,6 +2496,10 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) goto out; } +#ifdef MY_ABC_HERE + btrfs_remove_queued_syno_rescan(trans, qgroupid); +#endif /* MY_ABC_HERE */ + ret = del_qgroup_item(trans, qgroupid); if (ret && ret != -ENOENT) goto out; @@ -1599,6 +2535,10 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_qgroup *qgroup; int ret = 0; +#ifdef MY_ABC_HERE + struct btrfs_root *root = trans->root; + bool has_limit = false; +#endif /* MY_ABC_HERE */ /* Sometimes we would want to clear the limit on this qgroup. * To meet this requirement, we treat the -1 as a special value * which tell kernel to clear the limit on this qgroup. @@ -1607,7 +2547,11 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) { +#ifdef MY_ABC_HERE + ret = -ESRCH; +#else ret = -ENOTCONN; +#endif /* MY_ABC_HERE */ goto out; } @@ -1618,6 +2562,15 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, } spin_lock(&fs_info->qgroup_lock); +#ifdef MY_ABC_HERE + if (!limit->flags) { + qgroup->lim_flags = limit->flags; + qgroup->max_rfer = limit->max_rfer; + qgroup->max_excl = limit->max_excl; + qgroup->rsv_rfer = limit->rsv_rfer; + qgroup->rsv_excl = limit->rsv_excl; + } +#endif /* MY_ABC_HERE */ if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER) { if (limit->max_rfer == CLEAR_VALUE) { qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; @@ -1656,11 +2609,20 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, } qgroup->lim_flags |= limit->flags; +#ifdef MY_ABC_HERE + if ((qgroup->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER && qgroup->max_rfer) || + (qgroup->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL && qgroup->max_excl)) + has_limit = true; + btrfs_root_set_has_quota_limit(root, has_limit); +#endif /* MY_ABC_HERE */ spin_unlock(&fs_info->qgroup_lock); ret = update_qgroup_limit_item(trans, qgroup); if (ret) { +#ifdef MY_ABC_HERE +#else fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; +#endif /* MY_ABC_HERE */ btrfs_info(fs_info, "unable to update quota limit for %llu", qgroupid); } @@ -1670,6 +2632,77 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, return ret; } +#ifdef MY_ABC_HERE +int btrfs_insert_quota_record(struct btrfs_trans_handle *trans, + struct btrfs_delayed_ref_node *node) +{ + struct btrfs_delayed_data_ref *ref; + struct btrfs_transaction *cur_trans = trans->transaction; + struct btrfs_quota_account_rec *record; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &trans->fs_info->flags)) + return 0; + + ref = btrfs_delayed_node_to_data_ref(node); + if (ref->skip_qgroup) + return 0; + + record = kzalloc(sizeof(*record), GFP_NOFS); + if (!record) + return -ENOMEM; + + record->ref_root = ref->root; + record->num_bytes = node->num_bytes; + record->ram_bytes = ref->ram_bytes; + record->reserved = ref->reserved; + record->uid = ref->uid; + if (node->action == BTRFS_DROP_DELAYED_REF) + record->sign = -1; + else + record->sign = 1; + record->inode = ref->inode; + syno_usrquota_inode_get(record->inode); + + spin_lock(&cur_trans->quota_account_lock); + list_add_tail(&record->list, &cur_trans->quota_account_list); + spin_unlock(&cur_trans->quota_account_lock); + return 0; +} + +void btrfs_quota_syno_v1_accounting(struct btrfs_trans_handle *trans) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_quota_account_rec *record; + struct btrfs_transaction *cur_trans = trans->transaction; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) { + WARN_ON(!list_empty(&cur_trans->quota_account_list)); + return; + } + + while (1) { + spin_lock(&cur_trans->quota_account_lock); + if (list_empty(&cur_trans->quota_account_list)) { + spin_unlock(&cur_trans->quota_account_lock); + break; + } + + record = list_first_entry(&cur_trans->quota_account_list, + struct btrfs_quota_account_rec, list); + list_del_init(&record->list); + spin_unlock(&cur_trans->quota_account_lock); + + if (!trans->aborted) { + btrfs_qgroup_syno_v1_accounting(fs_info, record); + btrfs_usrquota_syno_v1_accounting(trans, record); + } + syno_usrquota_inode_put(record->inode); + kfree(record); + } + + return; +} +#else int btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_qgroup_extent_record *record) @@ -2705,6 +3738,7 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) num_dirty_extents); return ret; } +#endif /* MY_ABC_HERE */ /* * called from commit_transaction. Writes all changed qgroups to disk. @@ -2725,16 +3759,35 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans) list_del_init(&qgroup->dirty); spin_unlock(&fs_info->qgroup_lock); ret = update_qgroup_info_item(trans, qgroup); +#ifdef MY_ABC_HERE + if ((ret || qgroup->need_rescan) && + test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + struct syno_quota_rescan_item_updater updater; + + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_NEED; + btrfs_add_update_syno_quota_rescan_item(trans, + fs_info->quota_root, + btrfs_qgroup_subvolid(qgroup->qgroupid), &updater); + qgroup->need_rescan = false; + } +#else if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; +#endif /* MY_ABC_HERE */ ret = update_qgroup_limit_item(trans, qgroup); if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; spin_lock(&fs_info->qgroup_lock); } +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) || + test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) +#else if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) +#endif /* MY_ABC_HERE */ fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON; else fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; @@ -2787,12 +3840,21 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, if (!committing) mutex_lock(&fs_info->qgroup_ioctl_lock); +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) +#endif /* MY_ABC_HERE */ goto out; quota_root = fs_info->quota_root; if (!quota_root) { +#ifdef MY_ABC_HERE + ret = -ESRCH; +#else ret = -EINVAL; +#endif /* MY_ABC_HERE */ goto out; } @@ -2860,7 +3922,10 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, ret = update_qgroup_limit_item(trans, dstgroup); if (ret) { +#ifdef MY_ABC_HERE +#else fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; +#endif /* MY_ABC_HERE */ btrfs_info(fs_info, "unable to update quota limit for %llu", dstgroup->qgroupid); @@ -2879,6 +3944,10 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, * difference between the two roots should be the root node. */ level_size = fs_info->nodesize; +#ifdef MY_ABC_HERE + // In quota 2.0, we don't count metadata quota. + level_size = 0; +#endif /* MY_ABC_HERE */ dstgroup->rfer = srcgroup->rfer; dstgroup->rfer_cmpr = srcgroup->rfer_cmpr; dstgroup->excl = level_size; @@ -2965,8 +4034,12 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, out: if (!committing) mutex_unlock(&fs_info->qgroup_ioctl_lock); +#ifdef MY_ABC_HERE +// We don't use exclusive quota, so don't need rescan here. +#else if (need_rescan) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; +#endif /* MY_ABC_HERE */ return ret; } @@ -2983,6 +4056,12 @@ static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes) return true; } +#ifdef MY_ABC_HERE +/* + * Return 1 if we don't reserve qgroup, but it's not an EDQUOT error. + * Caller is allowed to write. + */ +#endif /* MY_ABC_HERE */ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce, enum btrfs_qgroup_rsv_type type) { @@ -3004,12 +4083,26 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce, enforce = false; spin_lock(&fs_info->qgroup_lock); +#ifdef MY_ABC_HERE + if (!fs_info->quota_root) { + ret = 1; + goto out; + } +#else if (!fs_info->quota_root) goto out; +#endif /* MY_ABC_HERE */ qgroup = find_qgroup_rb(fs_info, ref_root); +#ifdef MY_ABC_HERE + if (!qgroup) { + ret = 1; + goto out; + } +#else if (!qgroup) goto out; +#endif /* MY_ABC_HERE */ /* * in a first step, we check all affected qgroups if any limits would @@ -3027,7 +4120,11 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce, qg = unode_aux_to_qgroup(unode); - if (enforce && !qgroup_check_limits(qg, num_bytes)) { + if (enforce && !qgroup_check_limits(qg, num_bytes) +#ifdef MY_ABC_HERE + && !root->invalid_quota +#endif /* MY_ABC_HERE */ + ) { ret = -EDQUOT; goto out; } @@ -3129,6 +4226,571 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, spin_unlock(&fs_info->qgroup_lock); } +#ifdef MY_ABC_HERE +int btrfs_qgroup_syno_reserve(struct btrfs_root *root, u64 num_bytes) +{ + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &root->fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &root->fs_info->flags)) + return 0; + + if (btrfs_root_disable_quota(root)) + return 0; + + num_bytes = round_up(num_bytes, root->fs_info->sectorsize); + return qgroup_reserve(root, num_bytes, true, BTRFS_QGROUP_RSV_DATA); +} + +void btrfs_qgroup_syno_free(struct btrfs_root *root, u64 num_bytes) +{ + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &root->fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &root->fs_info->flags)) + return; + + if (btrfs_root_disable_quota(root)) + return; + + num_bytes = round_up(num_bytes, root->fs_info->sectorsize); + return btrfs_qgroup_free_refroot(root->fs_info, + root->root_key.objectid, num_bytes, + BTRFS_QGROUP_RSV_DATA); +} + +/* + * Copied from btrfs_qgroup_free_refroot() + * Use after inode_add_bytes() / inode_sub_bytes(), so we are always in a transaction + * and our accounting will be committed in btrfs_run_qgroups(). + */ +int btrfs_qgroup_syno_accounting(struct btrfs_inode *b_inode, + u64 add_bytes, u64 del_bytes, enum syno_quota_account_type type) +{ + struct btrfs_qgroup *qgroup; + struct ulist_node *unode; + struct ulist_iterator uiter; + struct btrfs_root *root = b_inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + u64 ref_root = root->root_key.objectid; + u64 ino = b_inode->location.objectid; + int ret = 0; +#ifdef MY_ABC_HERE + u64 soft_qgroup_subvol_id = 0; + u64 soft_qgroup_limit = 0; + u64 soft_qgroup_used = 0; + bool over_limit; +#endif /* MY_ABC_HERE */ + + if (!is_fstree(ref_root)) + return -EINVAL; + + if (add_bytes == del_bytes && type != UPDATE_QUOTA_FREE_RESERVED) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) + return 0; + + if (btrfs_root_disable_quota(root)) + return 0; + + spin_lock(&fs_info->qgroup_lock); + + if (!fs_info->quota_root) + goto out; + + qgroup = find_qgroup_rb(fs_info, ref_root); + if (!qgroup) + goto out; + + add_bytes = round_up(add_bytes, fs_info->sectorsize); + del_bytes = round_up(del_bytes, fs_info->sectorsize); + + ulist_reinit(fs_info->qgroup_ulist); + ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, + qgroup_to_aux(qgroup), GFP_ATOMIC); + if (ret < 0) { + qgroup->need_rescan = true; + goto out; + } + ULIST_ITER_INIT(&uiter); + while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { + struct btrfs_qgroup *qg; + struct btrfs_qgroup_list *glist; + + qg = unode_aux_to_qgroup(unode); + + switch (type) { + case ADD_QUOTA_RESCAN: + qg->rfer += add_bytes; +#ifdef MY_ABC_HERE + if (!soft_qgroup_subvol_id) + prepare_netlink_notification(qg, &soft_qgroup_subvol_id, + &soft_qgroup_limit, &soft_qgroup_used, &over_limit); +#endif /* MY_ABC_HERE */ + break; + case UPDATE_QUOTA_FREE_RESERVED: + qgroup_rsv_release(fs_info, qg, add_bytes, BTRFS_QGROUP_RSV_DATA); + /* fall through */ + case UPDATE_QUOTA: + if (btrfs_quota_rescan_check(root, ino)) { + qg->rfer += add_bytes; + + if (qg->rfer < del_bytes) { + if (!root->invalid_quota) + WARN_ONCE(1, "qgroup %llu ref underflow, have " + "%llu to free %llu", qgroup->qgroupid, qg->rfer, del_bytes); + qg->rfer = 0; + qg->need_rescan = true; + } else + qg->rfer -= del_bytes; + +#ifdef MY_ABC_HERE + if (!soft_qgroup_subvol_id) + prepare_netlink_notification(qg, &soft_qgroup_subvol_id, + &soft_qgroup_limit, &soft_qgroup_used, &over_limit); +#endif /* MY_ABC_HERE */ + } + break; + } + + qgroup_dirty(fs_info, qg); + + list_for_each_entry(glist, &qg->groups, next_group) { + ret = ulist_add(fs_info->qgroup_ulist, + glist->group->qgroupid, + qgroup_to_aux(glist->group), GFP_ATOMIC); + if (ret < 0) + goto out; + } + } + ret = 0; + +out: + spin_unlock(&fs_info->qgroup_lock); +#ifdef MY_ABC_HERE + if (soft_qgroup_subvol_id && (add_bytes != del_bytes)) + send_netlink_notification(fs_info, soft_qgroup_subvol_id, + soft_qgroup_limit, soft_qgroup_used, + (over_limit)? QGROUP_NL_C_OVER_LIMIT : QGROUP_NL_C_UNDER_LIMIT); +#endif /* MY_ABC_HERE */ + return ret; +} + +// Similar to btrfs_qgroup_syno_accounting(). +int btrfs_qgroup_syno_v1_accounting(struct btrfs_fs_info *fs_info, + struct btrfs_quota_account_rec *record) +{ + struct btrfs_qgroup *qgroup; + struct ulist_node *unode; + struct ulist_iterator uiter; + u64 ref_root = record->ref_root; + u64 num_bytes = record->num_bytes; + u64 ram_bytes = record->ram_bytes; + u64 reserved = record->reserved; + int sign = record->sign; + int ret = 0; + + if (!is_fstree(ref_root)) + return -EINVAL; + + spin_lock(&fs_info->qgroup_lock); + + if (!fs_info->quota_root) + goto out; + + qgroup = find_qgroup_rb(fs_info, ref_root); + if (!qgroup) + goto out; + + num_bytes = round_up(num_bytes, fs_info->sectorsize); + + ulist_reinit(fs_info->qgroup_ulist); + ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, + qgroup_to_aux(qgroup), GFP_ATOMIC); + if (ret < 0) + goto out; + + ULIST_ITER_INIT(&uiter); + while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { + struct btrfs_qgroup *qg; + struct btrfs_qgroup_list *glist; + + qg = unode_aux_to_qgroup(unode); + + if (unlikely(sign < 0 && qg->rfer < num_bytes)) { + /*WARN_ONCE(1, "qgroup %llu ref underflow, have " + "%llu to free %llu", qg->qgroupid, qg->rfer, num_bytes);*/ + qg->rfer = 0; + } else + qg->rfer += sign * num_bytes; + + if (unlikely(sign < 0 && qg->rfer_cmpr < ram_bytes)) { + /*WARN_ONCE(1, "qgroup %llu rfer_cmpr underflow, have " + "%llu to free %llu", qg->qgroupid, qg->rfer_cmpr, ram_bytes);*/ + qg->rfer_cmpr = 0; + } else + qg->rfer_cmpr += sign * ram_bytes; + + if (unlikely(sign > 0 && qg->rsv.values[BTRFS_QGROUP_RSV_DATA] < reserved)) { + WARN_ONCE(1, "qgroup %llu reserved space underflow, have %llu to free %llu", + qg->qgroupid, qg->rsv.values[BTRFS_QGROUP_RSV_DATA], reserved); + qg->rsv.values[BTRFS_QGROUP_RSV_DATA] = 0; + } else + qg->rsv.values[BTRFS_QGROUP_RSV_DATA] -= reserved; + + qgroup_dirty(fs_info, qg); + + list_for_each_entry(glist, &qg->groups, next_group) { + ret = ulist_add(fs_info->qgroup_ulist, + glist->group->qgroupid, + qgroup_to_aux(glist->group), GFP_ATOMIC); + if (ret < 0) + goto out; + } + } + ret = 0; + +out: + spin_unlock(&fs_info->qgroup_lock); + return ret; +} + +/* + * Similar to btrfs_qgroup_syno_accounting(), but used only in rescan, where + * we don't have in-memory inode. + */ +static int btrfs_qgroup_syno_accounting_rescan(struct btrfs_root *root, u64 num_bytes) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_qgroup *qgroup; + struct ulist_node *unode; + struct ulist_iterator uiter; + u64 subvol_id = root->root_key.objectid; + int ret = 0; + + if (num_bytes == 0) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) + return 0; + + spin_lock(&fs_info->qgroup_lock); + + if (!fs_info->quota_root) + goto out; + + num_bytes = round_up(num_bytes, fs_info->sectorsize); + qgroup = find_qgroup_rb(fs_info, subvol_id); + if (!qgroup) + goto out; + + ulist_reinit(fs_info->qgroup_ulist); + ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, + qgroup_to_aux(qgroup), GFP_ATOMIC); + if (ret < 0) + goto out; + ULIST_ITER_INIT(&uiter); + while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { + struct btrfs_qgroup *qg; + struct btrfs_qgroup_list *glist; + + qg = unode_aux_to_qgroup(unode); + + qg->rfer += num_bytes; + qgroup_dirty(fs_info, qg); + + list_for_each_entry(glist, &qg->groups, next_group) { + ret = ulist_add(fs_info->qgroup_ulist, + glist->group->qgroupid, + qgroup_to_aux(glist->group), GFP_ATOMIC); + if (ret < 0) + goto out; + } + } + ret = 0; + +out: + spin_unlock(&fs_info->qgroup_lock); + return ret; +} + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +// Progress path can be ctx->current_path or ctx->end_path. +static void syno_quota_update_progress_path(int progress_path[BTRFS_MAX_LEVEL][2], + struct btrfs_path *path) +{ + int i; + + for (i = 1; i < BTRFS_MAX_LEVEL; i++) { + if (path->nodes[i]) { + progress_path[i][0] = btrfs_header_nritems(path->nodes[i]); + progress_path[i][1] = path->slots[i]; + } else { + progress_path[i][0] = 0; + progress_path[i][1] = 0; + } + } +} + +/* + * Return 0 when more leafs are to be scanned. + * Return 1 when done. + * Never return -1 since we can try next subvol if error occurs. + */ +static int syno_quota_rescan_leaf(struct btrfs_trans_handle *trans, + struct btrfs_path *path) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *quota_root = fs_info->quota_root; + struct syno_quota_rescan_ctx *ctx = fs_info->syno_quota_rescan_ctx; + struct ulist *ulist = fs_info->syno_quota_rescan_subvol_ulist; + struct ulist_node *node; + struct btrfs_root *root; + struct extent_buffer *leaf; + struct btrfs_key key, found_key; + struct inode *inode; + struct btrfs_inode_item *inode_item; + struct syno_quota_rescan_item_updater updater; + u64 subvol_id; + u64 ino; + u64 max_objectid = 0; + u64 num_bytes; + u64 uid; + int nritems; + int ret = 0; + int err = 0; + + if (unlikely(!ctx || !ulist)) { + WARN_ON_ONCE(1); + return 1; + } + + mutex_lock(&fs_info->qgroup_rescan_lock); + if (list_empty(&ulist->nodes)) { + mutex_unlock(&fs_info->qgroup_rescan_lock); + return 1; + } + node = list_entry(ulist->nodes.next, struct ulist_node, list); + subvol_id = node->val; + ino = node->aux; + ino++; + mutex_unlock(&fs_info->qgroup_rescan_lock); + + root = btrfs_get_fs_root(fs_info, subvol_id, true); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + btrfs_err(fs_info, "Failed to call btrfs_get_fs_root() for root %llu, ret = %d", subvol_id, ret); + goto error_clean; + } + + if (unlikely(btrfs_root_dead(root))) { + btrfs_put_root(root); + goto error_clean; + } + + // We have changed to another root, reset progress info. + if (ctx->subvol_id != subvol_id) { + struct btrfs_syno_quota_rescan_item rescan_item; + + ret = btrfs_read_syno_quota_rescan_item(fs_info->quota_root, subvol_id, &rescan_item); + if (ret) + goto error_clean; + + ctx->subvol_id = subvol_id; + ctx->subvol_size = rescan_item.tree_size; + ctx->subvol_progress = 0; + memset(ctx->current_path, 0, sizeof(ctx->current_path)); + } + + key.objectid = ino; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + +search_again: + ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); + if (ret < 0) { + root->invalid_quota = false; + btrfs_put_root(root); + btrfs_err(fs_info, "btrfs_search_slot() failed in root %llu, ret = %d", subvol_id, ret); + goto error_clean; + } else if (ret > 0) + goto out; + + leaf = path->nodes[0]; + nritems = btrfs_header_nritems(path->nodes[0]); + if (nritems) { + btrfs_item_key_to_cpu(leaf, &found_key, nritems - 1); + max_objectid = found_key.objectid; + syno_quota_update_progress_path(ctx->current_path, path); + } + +next_slot: + if (path->slots[0] >= nritems) + goto out; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + if (found_key.type != BTRFS_INODE_ITEM_KEY || found_key.offset != 0) { + if (found_key.objectid == max_objectid) + goto out; + + path->slots[0]++; + goto next_slot; + } + + ino = found_key.objectid; + if (ino > root->rescan_end_inode) + goto out; + + down_write(&root->rescan_lock); + if (!btrfs_test_inode_nowait(fs_info->sb, ino, root)) { + inode_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_inode_item); + num_bytes = btrfs_inode_nbytes(leaf, inode_item); + uid = btrfs_inode_uid(leaf, inode_item); + + ret = btrfs_qgroup_syno_accounting_rescan(root, num_bytes); + if (ret) { + btrfs_warn(fs_info, "Failed in btrfs_qgroup_syno_accounting_rescan(), " + "subvol_id = %llu, ino = %llu, ret = %d", subvol_id, ino, ret); + err = ret; + } + + ret = btrfs_usrquota_syno_accounting_rescan(root, uid, num_bytes); + if (ret) { + btrfs_warn(fs_info, "Failed in btrfs_usrquota_syno_accounting_rescan(), " + "subvol_id = %llu, ino = %llu, uid = %llu, ret = %d", + subvol_id, ino, uid, ret); + err = ret; + } + + root->rescan_inode = ino; + up_write(&root->rescan_lock); + + path->slots[0]++; + goto next_slot; + } + + up_write(&root->rescan_lock); + btrfs_release_path(path); + inode = btrfs_iget(fs_info->sb, ino, root); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); + if (ret != -ENOENT) { + btrfs_warn(fs_info, "Failed to call btrfs_iget(), " + "subvol_id = %llu, ino = %llu, ret = %d", subvol_id, ino, ret); + err = ret; + } + } else { + down_write(&root->rescan_lock); + num_bytes = inode_get_bytes(inode); + + ret = btrfs_qgroup_syno_accounting(BTRFS_I(inode), num_bytes, 0, ADD_QUOTA_RESCAN); + if (ret) { + btrfs_warn(fs_info, "Failed in btrfs_qgroup_syno_accounting(), " + "subvol_id = %llu, ino = %llu, ret = %d", subvol_id, ino, ret); + err = ret; + } + + ret = btrfs_usrquota_syno_accounting(BTRFS_I(inode), num_bytes, 0, ADD_QUOTA_RESCAN); + if (ret) { + btrfs_warn(fs_info, "Failed in btrfs_usrquota_syno_accounting(), " + "subvol_id = %llu, ino = %llu, uid = %llu, ret = %d", + subvol_id, ino, uid, ret); + err = ret; + } + + root->rescan_inode = ino; + up_write(&root->rescan_lock); + btrfs_add_delayed_iput(inode); + } + + if (ino < max_objectid) { + key.objectid = ino + 1; + goto search_again; + } + +out: + if (ino < max_objectid) + ino = max_objectid; + btrfs_release_path(path); + + // Mark err but continue the rescan, or we'll see very strange (perhaps zero) quota usage. + if (unlikely(err)) { + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_ERR; + btrfs_add_update_syno_quota_rescan_item(trans, quota_root, subvol_id, &updater); + } + ret = 0; + + mutex_lock(&fs_info->qgroup_rescan_lock); + node = ulist_search(ulist, subvol_id); + if (node) { + if (ino > root->rescan_end_inode) { // This subvol is done. Switch to next subvol. + root->rescan_inode = (u64)-1; + root->rescan_end_inode = (u64)-1; + + ulist_del(ulist, subvol_id, node->aux); + syno_quota_rescan_item_init(&updater); + updater.rescan_inode = (u64)-1; + updater.end_inode = (u64)-1; + updater.flags = SYNO_QUOTA_RESCAN_DONE; + ret = btrfs_add_update_syno_quota_rescan_item(trans, quota_root, subvol_id, &updater); + if (ret) + btrfs_warn(fs_info, "Failed to update syno quota rescan item, ret = %d", ret); + + if (!list_empty(&ulist->nodes)) { + update_syno_quota_rescan_progress(quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_FINISH_ONE); + ret = 0; + } else { + update_syno_quota_rescan_progress(quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_FINISH_ALL); + fs_info->qgroup_rescan_progress.objectid = 0; + ret = 1; + } + } else { + WARN_ON_ONCE(ino < node->aux); + node->aux = (ino > node->aux)? ino : node->aux; + syno_quota_rescan_item_init(&updater); + updater.rescan_inode = node->aux; + updater.flags = SYNO_QUOTA_RESCAN_DOING; + ret = btrfs_add_update_syno_quota_rescan_item(trans, quota_root, subvol_id, &updater); + if (ret) + btrfs_warn(fs_info, "Failed to update syno quota rescan item, ret = %d", ret); + ret = 0; + } + } + mutex_unlock(&fs_info->qgroup_rescan_lock); + btrfs_put_root(root); + + return ret; + +error_clean: + mutex_lock(&fs_info->qgroup_rescan_lock); + if (ret < 0) { + syno_quota_rescan_item_init(&updater); + updater.rescan_inode = (u64)-1; + updater.end_inode = (u64)-1; + updater.flags = SYNO_QUOTA_RESCAN_ERR | SYNO_QUOTA_RESCAN_DONE; + btrfs_add_update_syno_quota_rescan_item(trans, quota_root, subvol_id, &updater); + } + node = ulist_search(ulist, subvol_id); + if (node) { + ulist_del(ulist, subvol_id, node->aux); + if (!list_empty(&ulist->nodes)) { + update_syno_quota_rescan_progress(quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_REMOVE_SCANNING); + ret = 0; // Scan next subvol. + } else { + update_syno_quota_rescan_progress(quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_FINISH_ALL); + fs_info->qgroup_rescan_progress.objectid = 0; + ret = 1; + } + } else + ret = 0; // Scan next subvol. + mutex_unlock(&fs_info->qgroup_rescan_lock); + + return ret; +} +#else /* * Check if the leaf is the last leaf. Which means all node pointers * are at their last position. @@ -3231,11 +4893,16 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans, } return ret; } +#endif /* MY_ABC_HERE */ static bool rescan_should_stop(struct btrfs_fs_info *fs_info) { return btrfs_fs_closing(fs_info) || - test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state); + test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) +#ifdef MY_ABC_HERE + || fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_PAUSE +#endif /* MY_ABC_HERE */ + ; } static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) @@ -3248,6 +4915,10 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) int ret = 0; bool stopped = false; +#ifdef MY_ABC_HERE +again: +#endif /* MY_ABC_HERE */ + path = btrfs_alloc_path(); if (!path) goto out; @@ -3255,8 +4926,12 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) * Rescan should only search for commit root, and any later difference * should be recorded by qgroup */ +#ifdef MY_ABC_HERE + path->reada = READA_FORWARD_ALWAYS; +#else path->search_commit_root = 1; path->skip_locking = 1; +#endif /* MY_ABC_HERE */ err = 0; while (!err && !(stopped = rescan_should_stop(fs_info))) { @@ -3265,11 +4940,19 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) err = PTR_ERR(trans); break; } +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + err = -EINTR; + } else { + err = syno_quota_rescan_leaf(trans, path);; + } +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { err = -EINTR; } else { err = qgroup_rescan_leaf(trans, path); } +#endif /* MY_ABC_HERE */ if (err > 0) btrfs_commit_transaction(trans); else @@ -3282,7 +4965,11 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) mutex_lock(&fs_info->qgroup_rescan_lock); if (err > 0 && fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { +#ifdef MY_ABC_HERE + // Now we clear inconsistent flag by ioctl. +#else fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; +#endif /* MY_ABC_HERE */ } else if (err < 0) { fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; } @@ -3302,6 +4989,16 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) } mutex_lock(&fs_info->qgroup_rescan_lock); +#ifdef MY_ABC_HERE + // In case another rescan join in after we left syno_quota_rescan_leaf(). + if (err >= 0 && !stopped && fs_info->syno_quota_rescan_subvol_ulist && + !list_empty(&fs_info->syno_quota_rescan_subvol_ulist->nodes)) { + if (trans) + btrfs_end_transaction(trans); + mutex_unlock(&fs_info->qgroup_rescan_lock); + goto again; + } +#endif /* MY_ABC_HERE */ if (!stopped) fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; if (trans) { @@ -3324,8 +5021,13 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) if (stopped) { btrfs_info(fs_info, "qgroup scan paused"); } else if (err >= 0) { +#ifdef MY_ABC_HERE + // Now we clear inconsistent flag by ioctl. + btrfs_info(fs_info, "qgroup scan completed"); +#else btrfs_info(fs_info, "qgroup scan completed%s", err > 0 ? " (inconsistency flag cleared)" : ""); +#endif /* MY_ABC_HERE */ } else { btrfs_err(fs_info, "qgroup scan failed with %d", err); } @@ -3363,16 +5065,41 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, if (init_flags) { if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { +#ifdef MY_ABC_HERE +#else btrfs_warn(fs_info, "qgroup rescan is already in progress"); +#endif /* MY_ABC_HERE */ ret = -EINPROGRESS; } else if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) { btrfs_warn(fs_info, "qgroup rescan init failed, qgroup is not enabled"); +#ifdef MY_ABC_HERE + ret = -ESRCH; +#else ret = -EINVAL; +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE + if (!ret && !fs_info->syno_quota_rescan_ctx) { + fs_info->syno_quota_rescan_ctx = + kzalloc(sizeof(struct syno_quota_rescan_ctx), GFP_KERNEL); + if (!fs_info->syno_quota_rescan_ctx) + ret = -ENOMEM; + } + + if (!ret && !fs_info->syno_quota_rescan_subvol_ulist) { + fs_info->syno_quota_rescan_subvol_ulist = ulist_alloc(GFP_KERNEL); + if (!fs_info->syno_quota_rescan_subvol_ulist) { + kfree(fs_info->syno_quota_rescan_ctx); + fs_info->syno_quota_rescan_ctx = NULL; + ret = -ENOMEM; + } + } +#endif /* MY_ABC_HERE */ + if (ret) { mutex_unlock(&fs_info->qgroup_rescan_lock); return ret; @@ -3384,6 +5111,10 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, sizeof(fs_info->qgroup_rescan_progress)); fs_info->qgroup_rescan_progress.objectid = progress_objectid; init_completion(&fs_info->qgroup_rescan_completion); + +#ifdef MY_ABC_HERE + fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_PAUSE; +#endif /* MY_ABC_HERE */ mutex_unlock(&fs_info->qgroup_rescan_lock); btrfs_init_work(&fs_info->qgroup_rescan_work, @@ -3485,12 +5216,568 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info) if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { mutex_lock(&fs_info->qgroup_rescan_lock); fs_info->qgroup_rescan_running = true; +#ifdef MY_ABC_HERE + fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_PAUSE; +#endif /* MY_ABC_HERE */ btrfs_queue_work(fs_info->qgroup_rescan_workers, &fs_info->qgroup_rescan_work); mutex_unlock(&fs_info->qgroup_rescan_lock); } } +#ifdef MY_ABC_HERE +int btrfs_reset_qgroup_status(struct btrfs_trans_handle *trans) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *quota_root = fs_info->quota_root; + struct btrfs_path *path = NULL; + struct btrfs_qgroup_status_item *ptr; + struct extent_buffer *leaf; + struct btrfs_key key; + int ret; + + mutex_lock(&fs_info->qgroup_ioctl_lock); + if (!fs_info->quota_root) { + ret = -ENOENT; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_QGROUP_STATUS_KEY; + key.offset = 0; + + ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); + if (ret) + goto out; + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_qgroup_status_item); + fs_info->qgroup_flags &= ~(BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT); + btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags); + btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); + btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_V2_STATUS_VERSION); + btrfs_mark_buffer_dirty(leaf); + +out: + btrfs_free_path(path); + mutex_unlock(&fs_info->qgroup_ioctl_lock); + return ret; +} + +int btrfs_syno_qgroup_transfer_limit(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_root *old_root = NULL; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf; + struct btrfs_qgroup_limit_item *ptr; + struct btrfs_qgroup *qgroup; + int ret = 0; + int slot; + + mutex_lock(&fs_info->qgroup_ioctl_lock); + if (!fs_info->quota_root) { + ret = -ESRCH; + goto out; + } + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + ret = -ESRCH; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_QUOTA_TREE_OBJECTID; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = 0; + old_root = btrfs_read_tree_root(fs_info->tree_root, &key); + if (IS_ERR(old_root)) { + ret = PTR_ERR(old_root); + old_root = NULL; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_QGROUP_LIMIT_KEY; + key.offset = 0; + ret = btrfs_search_slot_for_read(old_root, &key, path, 1, 0); + if (ret) + goto out; + + while (1) { + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + + if (found_key.type > BTRFS_QGROUP_LIMIT_KEY) + break; + + if (found_key.type == BTRFS_QGROUP_LIMIT_KEY) { + ptr = btrfs_item_ptr(leaf, slot, + struct btrfs_qgroup_limit_item); + + spin_lock(&fs_info->qgroup_lock); + qgroup = find_qgroup_rb(fs_info, found_key.offset); + if (qgroup && qgroup->lim_flags == 0 + && qgroup->max_rfer == 0 && qgroup->max_excl == 0 + && qgroup->rsv_rfer == 0 && qgroup->rsv_excl == 0) { + qgroup->lim_flags = btrfs_qgroup_limit_flags(leaf, ptr); + qgroup->max_rfer = btrfs_qgroup_limit_max_rfer(leaf, ptr); + qgroup->max_excl = btrfs_qgroup_limit_max_excl(leaf, ptr); + qgroup->rsv_rfer = btrfs_qgroup_limit_rsv_rfer(leaf, ptr); + qgroup->rsv_excl = btrfs_qgroup_limit_rsv_excl(leaf, ptr); + qgroup_dirty(fs_info, qgroup); + } + spin_unlock(&fs_info->qgroup_lock); + } + + ret = btrfs_next_item(old_root, path); + if (ret) + break; + } + +out: + btrfs_free_path(path); + if (old_root) { + free_extent_buffer(old_root->node); + free_extent_buffer(old_root->commit_root); + kfree(old_root); + } + mutex_unlock(&fs_info->qgroup_ioctl_lock); + + if (ret > 0) + ret = 0; + return ret; +} + +// We may have no qgroup record in volume migration case. +static void qgroup_zero_tracking(struct btrfs_fs_info *fs_info, u64 subvol_id) +{ + struct btrfs_qgroup *qgroup; + + spin_lock(&fs_info->qgroup_lock); + qgroup = find_qgroup_rb(fs_info, subvol_id); + if (qgroup) { + qgroup->rfer = 0; + qgroup->rfer_cmpr = 0; + qgroup->excl = 0; + qgroup->excl_cmpr = 0; + qgroup_dirty(fs_info, qgroup); + } + spin_unlock(&fs_info->qgroup_lock); +} + +int btrfs_syno_quota_rescan(struct btrfs_root *root) +{ + int ret = 0; + struct btrfs_fs_info *fs_info = root->fs_info; + struct syno_quota_rescan_ctx *ctx; + struct ulist *ulist; + struct ulist_node *node; + struct btrfs_trans_handle *trans; + struct syno_quota_rescan_item_updater updater; + u64 subvol_id = root->root_key.objectid; + u64 prev_subvol_id = 0; + + trans = btrfs_start_transaction(root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + return ret; + } + + ret = qgroup_rescan_init(fs_info, 0, 1); + if (ret && ret != -EINPROGRESS) { + btrfs_end_transaction(trans); + return ret; + } + + // Take qgroup_ioctl_lock after we start the transaction. See comments in btrfs_quota_enable(). + mutex_lock(&fs_info->qgroup_ioctl_lock); + mutex_lock(&fs_info->qgroup_rescan_lock); + ctx = fs_info->syno_quota_rescan_ctx; + ulist = fs_info->syno_quota_rescan_subvol_ulist; + if (!list_empty(&ulist->nodes)) { + node = list_entry(ulist->nodes.prev, struct ulist_node, list); + prev_subvol_id = node->val; + } + ret = ulist_add(ulist, subvol_id, 0, GFP_KERNEL); + if (ret != 1) { + if (ret == 0) + ret = -EEXIST; + else + ret = -ENOMEM; + goto out; + } + + if (prev_subvol_id) { + syno_quota_rescan_item_init(&updater); + updater.next_root = subvol_id; + ret = btrfs_add_update_syno_quota_rescan_item(trans, fs_info->quota_root, + prev_subvol_id, &updater); + if (ret) + goto out; + } + + /* + * Step 1. Update rescan item. This may fail so it must be the first step. + * Step 2. Set root->rescan_inode, so existing inodes won't do quota accounting until + * they are scanned. + * Step 3. Zero quota. + * Step 4. Set root->rescan_end_inode, so new inode will do normal quota accounting. + */ + mutex_lock(&root->objectid_mutex); + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_QUEUED; + updater.version = BTRFS_QGROUP_V2_STATUS_VERSION; + updater.rescan_inode = 0; + updater.end_inode = root->highest_objectid; + updater.tree_size = btrfs_root_used(&root->root_item); + updater.next_root = 0; + ret = btrfs_add_update_syno_quota_rescan_item(trans, fs_info->quota_root, subvol_id, &updater); + if (ret) { + mutex_unlock(&root->objectid_mutex); + goto out; // prev_subvol_id will point to a invalid rescan item, but it's OK, no need to abort. + } + + if (!fs_info->qgroup_rescan_progress.objectid) + fs_info->qgroup_rescan_progress.objectid = subvol_id; + + root->rescan_inode = 0; + smp_wmb(); + qgroup_zero_tracking(fs_info, subvol_id); + btrfs_usrquota_zero_tracking(fs_info, subvol_id); + root->invalid_quota = false; + root->rescan_end_inode = root->highest_objectid; + mutex_unlock(&root->objectid_mutex); + + // Remove compression ratio flag from quota v1. + if (btrfs_root_cmpr_ratio(root)) { + btrfs_set_root_flags(&root->root_item, + btrfs_root_flags(&root->root_item) & ~BTRFS_ROOT_SUBVOL_CMPR_RATIO); + ret = btrfs_update_root(trans, fs_info->tree_root, + &root->root_key, &root->root_item); + if (ret) { + // Print wraning but we can fix it manually, no need to abort. + btrfs_warn(fs_info, + "Failed to remove compression ratio flag for root %llu", + root->root_key.objectid); + ret = 0; + } + } + + // Remove fast chown flag from quota v1. + fs_info->usrquota_compat_flags &= ~BTRFS_USRQUOTA_COMPAT_FLAG_INODE_QUOTA; + + btrfs_end_transaction(trans); + trans = NULL; + + // Update progress info. + update_syno_quota_rescan_progress(fs_info->quota_root, ctx, + subvol_id, SYNO_QUOTA_PROGRESS_ADD_NEW); + + if (!fs_info->qgroup_rescan_running) { + fs_info->qgroup_rescan_running = true; + btrfs_queue_work(fs_info->qgroup_rescan_workers, + &fs_info->qgroup_rescan_work); + } + ret = 0; + +out: + if (trans) + btrfs_end_transaction(trans); + if (ret && ret != -EEXIST) { + ulist_del(ulist, subvol_id, 0); + if (list_empty(&ulist->nodes)) + fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; + } + mutex_unlock(&fs_info->qgroup_rescan_lock); + mutex_unlock(&fs_info->qgroup_ioctl_lock); + + /* + * We want everything is on-disk. + * But we can't commit the transaction with qgroup_rescan_lock, or we deadlock with rescan_worker. + */ + if (!ret) { + trans = btrfs_join_transaction(root); + if (!IS_ERR(trans)) + btrfs_commit_transaction(trans); + } + + return ret; +} + +static int syno_quota_rescan_progress(struct btrfs_root *root, + struct btrfs_ioctl_syno_quota_status_args *sa, + bool query_vol_progress, bool query_subvol_progress) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_key key; + struct syno_quota_rescan_ctx *ctx; + struct ulist *ulist; + struct ulist_node *node; + struct btrfs_path *path = NULL; + struct btrfs_root *scanning_root = NULL; + u64 subvol_id = root->root_key.objectid; + int ret; + + mutex_lock(&fs_info->qgroup_rescan_lock); + + // Update flags for rescan status. + ctx = fs_info->syno_quota_rescan_ctx; + ulist = fs_info->syno_quota_rescan_subvol_ulist; + if (!ctx || !ulist || list_empty(&ulist->nodes) || + !(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN)) { + sa->progress = 0; + sa->next_subvol_id = 0; + sa->scanning_subvol_id = 0; + ret = 0; + goto out; + } else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_PAUSE) + sa->status |= BTRFS_QUOTA_STATUS_VOL_RESCAN_PAUSED; + else if (fs_info->qgroup_rescan_running) + sa->status |= BTRFS_QUOTA_STATUS_VOL_RESCAN_DOING; + else if (rescan_should_stop(fs_info)) { + ret = -ECANCELED; + goto out; + } else { + btrfs_warn_rl(fs_info, "Unexpected state in syno_quota_rescan_progress() but no harm"); + ret = -EINVAL; + goto out; + } + + // Update current scanning subvol. + sa->scanning_subvol_id = ctx->subvol_id; + + // Update next subvol id. + node = ulist_search(ulist, subvol_id); + if (node) { + if (subvol_id == ctx->subvol_id) + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_RESCANNING; + else + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_RESCAN_QUEUED; + + if (node->list.next != &ulist->nodes) { + node = list_entry(node->list.next, struct ulist_node, list); + sa->next_subvol_id = node->val; + } + } else + sa->next_subvol_id = 0; + + /* + * Query volume progress, or query subvol progress that is scanning. + * In both case we need to update ctx->subvol_id progress. + */ + if (query_vol_progress || (query_subvol_progress && ctx->subvol_id == subvol_id)) { + u64 subvol_progress; + u64 vol_progress; + u64 denominator = 0; + u64 numerator = 0; + u64 tmp; + int i; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + scanning_root = btrfs_get_fs_root(fs_info, ctx->subvol_id, true); + if (IS_ERR(scanning_root)) { + ret = PTR_ERR(scanning_root); + scanning_root = NULL; + goto out; + } + + key.objectid = scanning_root->rescan_end_inode; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + + ret = btrfs_search_slot(NULL, scanning_root, &key, path, 0, 0); + if (ret < 0) + goto out; + + syno_quota_update_progress_path(ctx->end_path, path); + btrfs_release_path(path); + + // Calaulate subvol denominator. + tmp = SYNO_QUOTA_RESCAN_100_PROGRESS; + for (i = BTRFS_MAX_LEVEL - 1; i > 0; i--) { + if (ctx->end_path[i][0]) { + tmp /= ctx->end_path[i][0]; + denominator += (tmp * ctx->end_path[i][1]); + } + } + + // Calaulate subvol numerator. + tmp = SYNO_QUOTA_RESCAN_100_PROGRESS; + for (i = BTRFS_MAX_LEVEL - 1; i > 0; i--) { + if (ctx->current_path[i][0]) { + tmp /= ctx->current_path[i][0]; + numerator += (tmp * ctx->current_path[i][1]); + } + } + + if (denominator == 0) + denominator = 1; + if (numerator > denominator) + numerator = denominator; + + subvol_progress = (numerator * SYNO_QUOTA_RESCAN_100_PROGRESS) / denominator; + if (subvol_progress < ctx->subvol_progress) + subvol_progress = ctx->subvol_progress; + ctx->subvol_progress = subvol_progress; + + if (query_subvol_progress) { // Report subvol progress. + sa->progress = subvol_progress; + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_PROGRESS_VALID; + } else { // Report vol progress. + denominator = ctx->total_size; + numerator = ctx->total_finished_size + + (ctx->subvol_size * subvol_progress / SYNO_QUOTA_RESCAN_100_PROGRESS); + + if (numerator > denominator) { + numerator = denominator; + WARN_ON_ONCE(1); + } + + vol_progress = (numerator * SYNO_QUOTA_RESCAN_100_PROGRESS) / denominator; + if (vol_progress < ctx->vol_progress) + vol_progress = ctx->vol_progress; + ctx->vol_progress = vol_progress; + sa->progress = vol_progress; + sa->status |= BTRFS_QUOTA_STATUS_VOL_PROGRESS_VALID; + } + } else if (query_subvol_progress) { // Query subvol progress that is not currently scanning. + struct btrfs_syno_quota_rescan_item rescan_item; + + ret = btrfs_read_syno_quota_rescan_item(fs_info->quota_root, subvol_id, &rescan_item); + if (ret) + goto out; + + if (rescan_item.flags & SYNO_QUOTA_RESCAN_DONE) { + sa->progress = SYNO_QUOTA_RESCAN_100_PROGRESS; + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_PROGRESS_VALID; + } else if (rescan_item.flags & SYNO_QUOTA_RESCAN_QUEUED) { + sa->progress = 0; + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_PROGRESS_VALID; + } else { + WARN_ON_ONCE(1); + ret = -EINVAL; + goto out; + } + } + + ret = 0; +out: + btrfs_put_root(scanning_root); + btrfs_free_path(path); + mutex_unlock(&fs_info->qgroup_rescan_lock); + return ret; +} + +int btrfs_syno_quota_status(struct btrfs_root *root, + struct btrfs_ioctl_syno_quota_status_args *sa) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + int ret = 0; + bool query_vol_progress = false; + bool query_subvol_progress = false; + + if (sa->cmd & BTRFS_QUOTA_STATUS_RESCAN_VOL_PROGRESS) + query_vol_progress = true; + if (sa->cmd & BTRFS_QUOTA_STATUS_RESCAN_SUBVOL_PROGRESS) + query_subvol_progress = true; + + // We'll return sa to user, so zero it first. + memset(sa, 0, sizeof(*sa)); + + if (query_vol_progress && query_subvol_progress) + return -EINVAL; + + mutex_lock(&fs_info->qgroup_ioctl_lock); + if (!fs_info->quota_root) { + sa->status |= BTRFS_QUOTA_STATUS_VOL_DISABLED; + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_DISABLED; + goto out; + } + + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) + sa->status |= BTRFS_QUOTA_STATUS_VOL_SYNO_V1_ENABLED; + else if (test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) + sa->status |= BTRFS_QUOTA_STATUS_VOL_SYNO_V2_ENABLED; + else { + sa->status |= BTRFS_QUOTA_STATUS_VOL_DISABLED; + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_DISABLED; + goto out; + } + + if (root->invalid_quota || btrfs_root_disable_quota(root)) + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_DISABLED; + else + sa->status |= BTRFS_QUOTA_STATUS_SUBVOL_ENABLED; + + if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) + sa->status |= BTRFS_QUOTA_STATUS_INCONSISTENT; + if (fs_info->usrquota_flags & BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT) + sa->status |= BTRFS_USRQUOTA_STATUS_INCONSISTENT; + + + ret = syno_quota_rescan_progress(root, sa, + query_vol_progress, query_subvol_progress); + +out: + mutex_unlock(&fs_info->qgroup_ioctl_lock); + return ret; +} + +void btrfs_read_syno_quota_for_root(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_syno_quota_rescan_item rescan_item; + int ret; + +#ifdef MY_ABC_HERE + btrfs_check_usrquota_limit(root); + btrfs_check_quota_limit(root); +#endif /* MY_ABC_HERE */ + + // Only v2 has subvol quota version. + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + root->invalid_quota = false; + return; + } + + ret = btrfs_read_syno_quota_rescan_item(fs_info->quota_root, + root->root_key.objectid, &rescan_item); + if (ret) { + btrfs_info(fs_info, "Failed to read syno quota for root %llu, ret = %d", + root->root_key.objectid, ret); + return; + } + + root->rescan_inode = rescan_item.rescan_inode; + root->rescan_end_inode = rescan_item.end_inode; + if (rescan_item.version == BTRFS_QGROUP_V2_STATUS_VERSION) + root->invalid_quota = false; + + return; +} +#endif /* MY_ABC_HERE */ + #define rbtree_iterate_from_safe(node, next, start) \ for (node = start; node && ({ next = rb_next(node); 1;}); node = next) @@ -3645,10 +5932,25 @@ static int qgroup_reserve_data(struct btrfs_inode *inode, u64 to_reserve; int ret; +#ifdef MY_ABC_HERE + if ((!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &root->fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &root->fs_info->flags)) || +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || +#endif /* MY_ABC_HERE */ !is_fstree(root->root_key.objectid) || len == 0) return 0; +#ifdef MY_ABC_HERE + if (btrfs_root_disable_quota(root)) + return 0; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!btrfs_root_has_usrquota_limit(root) && !btrfs_root_has_quota_limit(root)) + return 0; +#endif /* MY_ABC_HERE */ + /* @reserved parameter is mandatory for qgroup */ if (WARN_ON(!reserved_ret)) return -EINVAL; @@ -3670,13 +5972,35 @@ static int qgroup_reserve_data(struct btrfs_inode *inode, to_reserve, QGROUP_RESERVE); if (ret < 0) goto out; + +#ifdef MY_ABC_HERE + ret = usrquota_reserve(inode, to_reserve, true); + if (ret != 0) { + if (ret > 0) + ret = 0; + goto usr_reserve_fail; + } +#endif /* MY_ABC_HERE */ + ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA); +#ifdef MY_ABC_HERE + if (ret != 0) { + if (ret > 0) + ret = 0; + goto cleanup; + } +#else if (ret < 0) goto cleanup; +#endif /* MY_ABC_HERE */ return ret; cleanup: +#ifdef MY_ABC_HERE + btrfs_usrquota_syno_free(inode, to_reserve); +usr_reserve_fail: +#endif /* MY_ABC_HERE */ qgroup_unreserve_range(inode, reserved, start, len); out: if (new_reserved) { @@ -3721,7 +6045,11 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode, { struct btrfs_root *root = inode->root; struct ulist_node *unode; +#ifdef MY_ABC_HERE + struct rb_node *node; +#else struct ulist_iterator uiter; +#endif /* MY_ABC_HERE */ struct extent_changeset changeset; int freed = 0; int ret; @@ -3730,6 +6058,46 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode, len = round_up(start + len, root->fs_info->sectorsize); start = round_down(start, root->fs_info->sectorsize); +#ifdef MY_ABC_HERE + unode = ulist_search_with_prev(&reserved->range_changed, start); + while (unode) { + u64 range_start = unode->val; + /* unode->aux is the inclusive end */ + u64 range_len = unode->aux - range_start + 1; + u64 free_start; + u64 free_len; + + extent_changeset_release(&changeset); + + /* Only free range in range [start, start + len) */ + if (range_start + range_len <= start) + goto next; + if (range_start >= start + len) + break; + free_start = max(range_start, start); + free_len = min(start + len, range_start + range_len) - + free_start; + /* + * TODO: To also modify reserved->ranges_reserved to reflect + * the modification. + * + * However as long as we free qgroup reserved according to + * EXTENT_QGROUP_RESERVED, we won't double free. + * So not need to rush. + */ + ret = clear_record_extent_bits(&inode->io_tree, free_start, + free_start + free_len - 1, + EXTENT_QGROUP_RESERVED, &changeset); + if (ret < 0) + goto out; + freed += changeset.bytes_changed; +next: + node = rb_next(&unode->rb_node); + if (!node) + break; + unode = rb_entry(node, struct ulist_node, rb_node); + } +#else ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(&reserved->range_changed, &uiter))) { u64 range_start = unode->val; @@ -3762,6 +6130,7 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode, goto out; freed += changeset.bytes_changed; } +#endif /* MY_ABC_HERE */ btrfs_qgroup_free_refroot(root->fs_info, root->root_key.objectid, freed, BTRFS_QGROUP_RSV_DATA); ret = freed; @@ -3778,8 +6147,22 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode, int trace_op = QGROUP_RELEASE; int ret; +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &inode->root->fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &inode->root->fs_info->flags)) { + if (inode->root->fs_info->need_clear_reserve) { + clear_extent_bit(&inode->io_tree, start, start + len -1, + EXTENT_QGROUP_RESERVED, 0, 0, NULL); + spin_lock(&inode->root->fs_info->usrquota_lock); + inode->uq_reserved = 0; + spin_unlock(&inode->root->fs_info->usrquota_lock); + } + return 0; + } +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &inode->root->fs_info->flags)) return 0; +#endif /* MY_ABC_HERE */ /* In release case, we shouldn't have @reserved */ WARN_ON(!free && reserved); @@ -3820,7 +6203,16 @@ static int __btrfs_qgroup_release_data(struct btrfs_inode *inode, int btrfs_qgroup_free_data(struct btrfs_inode *inode, struct extent_changeset *reserved, u64 start, u64 len) { +#ifdef MY_ABC_HERE + int to_free; + + to_free = __btrfs_qgroup_release_data(inode, reserved, start, len, 1); + if (to_free > 0) + btrfs_usrquota_syno_free(inode, to_free); + return to_free; +#else return __btrfs_qgroup_release_data(inode, reserved, start, len, 1); +#endif /* MY_ABC_HERE */ } /* @@ -3843,6 +6235,8 @@ int btrfs_qgroup_release_data(struct btrfs_inode *inode, u64 start, u64 len) return __btrfs_qgroup_release_data(inode, NULL, start, len, 0); } +#ifdef MY_ABC_HERE +#else static void add_root_meta_rsv(struct btrfs_root *root, int num_bytes, enum btrfs_qgroup_rsv_type type) { @@ -3882,10 +6276,14 @@ static int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes, spin_unlock(&root->qgroup_meta_rsv_lock); return num_bytes; } +#endif /* MY_ABC_HERE */ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, enum btrfs_qgroup_rsv_type type, bool enforce) { +#ifdef MY_ABC_HERE + return 0; +#else struct btrfs_fs_info *fs_info = root->fs_info; int ret; @@ -3908,11 +6306,15 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, */ add_root_meta_rsv(root, num_bytes, type); return ret; +#endif /* MY_ABC_HERE */ } int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, enum btrfs_qgroup_rsv_type type, bool enforce) { +#ifdef MY_ABC_HERE + return 0; +#else int ret; ret = btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce); @@ -3923,10 +6325,13 @@ int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, if (ret < 0) return ret; return btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce); +#endif /* MY_ABC_HERE */ } void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root) { +#ifdef MY_ABC_HERE +#else struct btrfs_fs_info *fs_info = root->fs_info; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || @@ -3938,11 +6343,14 @@ void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root) /* Special value -1 means to free all reserved space */ btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, (u64)-1, BTRFS_QGROUP_RSV_META_PERTRANS); +#endif /* MY_ABC_HERE */ } void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes, enum btrfs_qgroup_rsv_type type) { +#ifdef MY_ABC_HERE +#else struct btrfs_fs_info *fs_info = root->fs_info; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || @@ -3959,8 +6367,11 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes, trace_qgroup_meta_reserve(root, -(s64)num_bytes, type); btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, num_bytes, type); +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +#else static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root, int num_bytes) { @@ -4005,9 +6416,12 @@ static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root, out: spin_unlock(&fs_info->qgroup_lock); } +#endif /* MY_ABC_HERE */ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes) { +#ifdef MY_ABC_HERE +#else struct btrfs_fs_info *fs_info = root->fs_info; if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || @@ -4018,6 +6432,7 @@ void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes) BTRFS_QGROUP_RSV_META_PREALLOC); trace_qgroup_meta_convert(root, num_bytes); qgroup_convert_meta(fs_info, root->root_key.objectid, num_bytes); +#endif /* MY_ABC_HERE */ } /* @@ -4054,12 +6469,15 @@ void btrfs_qgroup_check_reserved_leak(struct btrfs_inode *inode) void btrfs_qgroup_init_swapped_blocks( struct btrfs_qgroup_swapped_blocks *swapped_blocks) { +#ifdef MY_ABC_HERE +#else int i; spin_lock_init(&swapped_blocks->lock); for (i = 0; i < BTRFS_MAX_LEVEL; i++) swapped_blocks->blocks[i] = RB_ROOT; swapped_blocks->swapped = false; +#endif /* MY_ABC_HERE */ } /* @@ -4070,6 +6488,8 @@ void btrfs_qgroup_init_swapped_blocks( */ void btrfs_qgroup_clean_swapped_blocks(struct btrfs_root *root) { +#ifdef MY_ABC_HERE +#else struct btrfs_qgroup_swapped_blocks *swapped_blocks; int i; @@ -4091,6 +6511,7 @@ void btrfs_qgroup_clean_swapped_blocks(struct btrfs_root *root) swapped_blocks->swapped = false; out: spin_unlock(&swapped_blocks->lock); +#endif /* MY_ABC_HERE */ } /* @@ -4110,6 +6531,9 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans, struct extent_buffer *reloc_parent, int reloc_slot, u64 last_snapshot) { +#ifdef MY_ABC_HERE + return 0; +#else struct btrfs_fs_info *fs_info = subvol_root->fs_info; struct btrfs_qgroup_swapped_blocks *blocks = &subvol_root->swapped_blocks; struct btrfs_qgroup_swapped_block *block; @@ -4205,6 +6629,7 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans, fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; return ret; +#endif /* MY_ABC_HERE */ } /* @@ -4217,6 +6642,9 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *subvol_eb) { +#ifdef MY_ABC_HERE + return 0; +#else struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_qgroup_swapped_blocks *blocks = &root->swapped_blocks; struct btrfs_qgroup_swapped_block *block; @@ -4293,10 +6721,13 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; } return ret; +#endif /* MY_ABC_HERE */ } void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans) { +#ifdef MY_ABC_HERE +#else struct btrfs_qgroup_extent_record *entry; struct btrfs_qgroup_extent_record *next; struct rb_root *root; @@ -4306,4 +6737,91 @@ void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans) ulist_free(entry->old_roots); kfree(entry); } +#endif /* MY_ABC_HERE */ } + +#ifdef MY_ABC_HERE +static bool check_quota_from_disk(struct btrfs_fs_info *fs_info, u64 qgroupid) +{ + int ret; + int slot; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root *quota_root = fs_info->quota_root; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_qgroup_limit_item *limit_item; + bool has_limit = false; + u64 flags; + u64 max_rfer; + u64 max_excl; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_QGROUP_LIMIT_KEY; + key.offset = qgroupid; + ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 0); + if (ret < 0) + goto out; + else if (ret) { + ret = 0; + goto out; + } + + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + if (found_key.offset != qgroupid || + found_key.type != BTRFS_QGROUP_LIMIT_KEY) { + ret = 0; + goto out; + } + + limit_item = btrfs_item_ptr(leaf, slot, + struct btrfs_qgroup_limit_item); + flags = btrfs_qgroup_limit_flags(leaf, limit_item); + max_rfer = btrfs_qgroup_limit_max_rfer(leaf, limit_item); + max_excl = btrfs_qgroup_limit_max_excl(leaf, limit_item); + if ((flags & BTRFS_QGROUP_LIMIT_MAX_RFER && max_rfer) || + (flags & BTRFS_QGROUP_LIMIT_MAX_EXCL && max_excl)) + has_limit = true; + ret = 0; +out: + btrfs_free_path(path); + // When an error occurr, we always treat it as having quota_limt. + return (ret) ? true : has_limit; +} + +void btrfs_check_quota_limit(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + bool has_limit = false; + u64 qgroupid = root->root_key.objectid; + struct btrfs_qgroup *qgroup; + + spin_lock(&fs_info->qgroup_lock); + if (!fs_info->quota_root) { + spin_unlock(&fs_info->qgroup_lock); + return; + } + + qgroup = find_qgroup_rb(fs_info, qgroupid); + if (!qgroup) { + // subtree is unloaded, read from disk. + spin_unlock(&fs_info->qgroup_lock); + has_limit = check_quota_from_disk(fs_info, qgroupid); + } else { + if ((qgroup->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER && qgroup->max_rfer) || + (qgroup->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL && qgroup->max_excl)) + has_limit = true; + spin_unlock(&fs_info->qgroup_lock); + } + btrfs_root_set_has_quota_limit(root, has_limit); +} +#endif /* MY_ABC_HERE */ + diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 7283e4f549af..fc19370548dd 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2014 Facebook. All rights reserved. @@ -11,6 +14,10 @@ #include #include "ulist.h" #include "delayed-ref.h" +#ifdef MY_ABC_HERE +#include +#include "ctree.h" +#endif /* MY_ABC_HERE */ /* * Btrfs qgroup overview @@ -202,8 +209,19 @@ struct btrfs_qgroup { u64 lim_flags; /* which limits are set */ u64 max_rfer; u64 max_excl; +#ifdef MY_ABC_HERE + union { + u64 soft_rfer; + u64 rsv_rfer; + }; + union { + u64 soft_excl; + u64 rsv_excl; + }; +#else u64 rsv_rfer; u64 rsv_excl; +#endif /* MY_ABC_HERE */ /* * reservation tracking @@ -229,6 +247,12 @@ struct btrfs_qgroup { * Sysfs kobjectid */ struct kobject kobj; +#ifdef MY_ABC_HERE + bool need_rescan; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int last_sent; +#endif /* MY_ABC_HERE */ }; static inline u64 btrfs_qgroup_subvolid(u64 qgroupid) @@ -243,7 +267,13 @@ static inline u64 btrfs_qgroup_subvolid(u64 qgroupid) #define QGROUP_RELEASE (1<<1) #define QGROUP_FREE (1<<2) +#ifdef MY_ABC_HERE +int btrfs_quota_enable(struct btrfs_fs_info *fs_info, u64 cmd); +int btrfs_quota_unload(struct btrfs_fs_info *fs_info); +int btrfs_quota_remove_v1(struct btrfs_fs_info *fs_info); +#else int btrfs_quota_enable(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ int btrfs_quota_disable(struct btrfs_fs_info *fs_info); int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info); void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info); @@ -430,4 +460,125 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans); bool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +enum syno_quota_rescan_progress_update_type { + SYNO_QUOTA_PROGRESS_REMOVE_SCANNING, + SYNO_QUOTA_PROGRESS_REMOVE_QUEUED, + SYNO_QUOTA_PROGRESS_REMOVE_FINISHED, + SYNO_QUOTA_PROGRESS_ADD_NEW, + SYNO_QUOTA_PROGRESS_ADD_FINISHED, + SYNO_QUOTA_PROGRESS_FINISH_ONE, + SYNO_QUOTA_PROGRESS_FINISH_ALL, +}; + +#define SYNO_QUOTA_RESCAN_100_PROGRESS 10000 + +struct syno_quota_rescan_ctx { + // The subvol which we are scanning. + u64 subvol_id; + u64 subvol_size; + u64 subvol_progress; + u64 vol_progress; + + // Used for volume progress. + u64 total_size; // Total bytes we need to scan in this volume. + u64 total_finished_size; // Add subvol size to here only after the subvol is done. + + /* + * Path tracking. + * [][0] as denominator, [][1] as numerator. + */ + int end_path[BTRFS_MAX_LEVEL][2]; + int current_path[BTRFS_MAX_LEVEL][2]; +}; + +/* + * Make sure it does not overlap any possible flag bits or values. + * For example, it can't use 0 or (u64)-1 since caller may really want to set 0 or (u64)-1. + */ +#define SYNO_QUOTA_RESCAN_ITEM_SKIP (1ULL << 60) + +/* + * All members MUST be u64. + * SYNO_QUOTA_RESCAN_ITEM_SKIP means you don't want to update this member. + */ +struct syno_quota_rescan_item_updater { + u64 flags; + u64 version; + u64 rescan_inode; + u64 end_inode; + u64 tree_size; + u64 next_root; + + bool enable; // Are we from btrfs_quota_enable()? +} __attribute__ ((__packed__)); + +static inline void syno_quota_rescan_item_init(struct syno_quota_rescan_item_updater *updater) +{ + u64 *iter = (u64 *)updater; + char *end = (char *)updater + offsetof(struct syno_quota_rescan_item_updater, enable); + + BUILD_BUG_ON(offsetof(struct syno_quota_rescan_item_updater, enable) % sizeof(u64)); + for (; (char *)iter < end; iter++) + *iter = SYNO_QUOTA_RESCAN_ITEM_SKIP; + + updater->enable = false; +} + +static inline bool syno_quota_rescan_item_check(struct syno_quota_rescan_item_updater *updater) +{ + u64 *iter = (u64 *)updater; + char *end = (char *)updater + offsetof(struct syno_quota_rescan_item_updater, enable); + + for (; (char *)iter < end; iter++) { + if (*iter == SYNO_QUOTA_RESCAN_ITEM_SKIP) + return 1; + } + return 0; +} + +int btrfs_qgroup_syno_reserve(struct btrfs_root *root, u64 num_bytes); +void btrfs_qgroup_syno_free(struct btrfs_root *root, u64 num_bytes); + +int btrfs_qgroup_syno_accounting(struct btrfs_inode *b_inode, + u64 add_bytes, u64 del_bytes, enum syno_quota_account_type type); +int btrfs_insert_quota_record(struct btrfs_trans_handle *trans, + struct btrfs_delayed_ref_node *node); +int btrfs_qgroup_syno_v1_accounting(struct btrfs_fs_info *fs_info, + struct btrfs_quota_account_rec *record); +void btrfs_quota_syno_v1_accounting(struct btrfs_trans_handle *trans); +int btrfs_reset_qgroup_status(struct btrfs_trans_handle *trans); +int btrfs_syno_qgroup_transfer_limit(struct btrfs_root *root); +int btrfs_syno_quota_rescan(struct btrfs_root *root); +int btrfs_syno_quota_status(struct btrfs_root *root, + struct btrfs_ioctl_syno_quota_status_args *sa); +void btrfs_read_syno_quota_for_root(struct btrfs_root *root); +int btrfs_read_syno_quota_rescan_item(struct btrfs_root *quota_root, u64 subvol_id, + struct btrfs_syno_quota_rescan_item *rescan_item); +int btrfs_add_update_syno_quota_rescan_item(struct btrfs_trans_handle *trans, + struct btrfs_root *quota_root, u64 subvol_id, + struct syno_quota_rescan_item_updater *updater); +void btrfs_remove_queued_syno_rescan(struct btrfs_trans_handle *trans, u64 subvol_id); + +// Return true if need to account quota. +static inline bool btrfs_quota_rescan_check(struct btrfs_root *root, u64 ino) +{ + if (likely(ino <= root->rescan_inode || ino > root->rescan_end_inode)) + return true; + else + return false; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int btrfs_qgroup_query(struct btrfs_root *root, + struct btrfs_ioctl_qgroup_query_args *qqa); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern u64 qgroup_soft_limit; +int __init qgroup_netlink_init(void); +void qgroup_netlink_exit(void); +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index d9a166eb344e..69c770040be8 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2011 STRATO. All rights reserved. @@ -649,6 +652,9 @@ static int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr, { struct extent_buffer *buf = NULL; int ret; +#ifdef MY_ABC_HERE + bool can_retry = false; +#endif /* MY_ABC_HERE */ buf = btrfs_find_create_tree_block(fs_info, bytenr); if (IS_ERR(buf)) @@ -656,7 +662,11 @@ static int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr, set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags); - ret = read_extent_buffer_pages(buf, WAIT_PAGE_LOCK, mirror_num); + ret = read_extent_buffer_pages(buf, WAIT_PAGE_LOCK, mirror_num +#ifdef MY_ABC_HERE + , &can_retry, 0 +#endif /* MY_ABC_HERE */ + ); if (ret) { free_extent_buffer_stale(buf); return ret; diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 96ef9fed9a65..4774dee2cba4 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -1,14 +1,34 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ #include "compression.h" #include "ctree.h" #include "delalloc-space.h" #include "reflink.h" #include "transaction.h" +#ifdef MY_ABC_HERE +#include "qgroup.h" +#endif /* MY_ABC_HERE */ #define BTRFS_MAX_DEDUPE_LEN SZ_16M +#ifdef MY_ABC_HERE +struct btrfs_syno_clone_range_v2 { + u64 src_off; + u64 src_len; + u64 dest_off; + u64 dest_len; + u64 ref_limit; + u32 flag; +}; +#endif /* MY_ABC_HERE */ static int clone_finish_inode_update(struct btrfs_trans_handle *trans, struct inode *inode, @@ -176,6 +196,7 @@ static int clone_copy_inline_extent(struct inode *dst, const u64 aligned_end = ALIGN(new_key->offset + datal, fs_info->sectorsize); struct btrfs_trans_handle *trans = NULL; + struct btrfs_drop_extents_args drop_args = { 0 }; int ret; struct btrfs_key key; @@ -261,7 +282,11 @@ static int clone_copy_inline_extent(struct inode *dst, trans = NULL; goto out; } - ret = btrfs_drop_extents(trans, root, dst, drop_start, aligned_end, 1); + + drop_args.start = drop_start; + drop_args.end = aligned_end; + drop_args.drop_cache = true; + ret = btrfs_drop_extents(trans, root, BTRFS_I(dst), &drop_args); if (ret) goto out; ret = btrfs_insert_empty_item(trans, root, path, new_key, size); @@ -272,7 +297,17 @@ static int clone_copy_inline_extent(struct inode *dst, btrfs_item_ptr_offset(path->nodes[0], path->slots[0]), size); - inode_add_bytes(dst, datal); +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(dst), datal, drop_args.bytes_found); + btrfs_qgroup_syno_accounting(BTRFS_I(dst), datal, + drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(dst), datal, + drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(BTRFS_I(dst), datal, drop_args.bytes_found); +#endif /* MY_ABC_HERE */ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(dst)->runtime_flags); ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end); out: @@ -314,6 +349,101 @@ static int clone_copy_inline_extent(struct inode *dst, goto out; } +#ifdef MY_ABC_HERE +int btrfs_get_extent_refs_count(struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, u64 *refs) +{ + struct btrfs_key key; + struct btrfs_path *path; + struct btrfs_delayed_ref_head *head; + struct btrfs_delayed_ref_root *delayed_refs; + struct btrfs_transaction *cur_trans; + struct btrfs_extent_item *ei; + struct extent_buffer *extent_leaf; + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = bytenr; + key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = num_bytes; + + /* Check committed refs */ + ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); + if (ret < 0) + goto out; + if (!ret) { + extent_leaf = path->nodes[0]; + ei = btrfs_item_ptr(extent_leaf, path->slots[0], struct btrfs_extent_item); + *refs += btrfs_extent_refs(extent_leaf, ei); + } + ret = 0; + /* Check delayed refs */ + spin_lock(&fs_info->trans_lock); + cur_trans = fs_info->running_transaction; + if (cur_trans) + refcount_inc(&cur_trans->use_count); + spin_unlock(&fs_info->trans_lock); + if (!cur_trans) + goto out; + delayed_refs = &cur_trans->delayed_refs; + spin_lock(&delayed_refs->lock); + head = btrfs_find_delayed_ref_head(delayed_refs, bytenr); + if (!head) { + spin_unlock(&delayed_refs->lock); + btrfs_put_transaction(cur_trans); + goto out; + } + *refs += head->ref_mod; + spin_unlock(&delayed_refs->lock); + btrfs_put_transaction(cur_trans); +out: + btrfs_free_path(path); + return ret; +} + +static int btrfs_clone_auto_rewrite(struct inode *inode, u64 off, u64 len, bool wait) +{ + int ret = 0; + int ret_pages; + struct page **pages = NULL; + unsigned long max_cluster = SZ_256K >> PAGE_SHIFT; + unsigned long total_cluster = len/PAGE_SIZE; + unsigned long num_pages; + unsigned long idx = 0; + unsigned long start_idx = off >> PAGE_SHIFT; + + pages = kmalloc_array(max_cluster, sizeof(struct page *), GFP_NOFS); + if (!pages) { + ret = -ENOMEM; + goto err; + } + + while (idx < total_cluster) { + num_pages = min(total_cluster - idx, max_cluster); + ret_pages = cluster_pages_for_defrag(inode, pages, + start_idx + idx, num_pages); + if (ret_pages <= 0) { + if (ret_pages == 0) + ret_pages = -ENOMEM; + ret = ret_pages; + goto err; + } + idx += ret_pages; + balance_dirty_pages_ratelimited(inode->i_mapping); + } + if (wait) + ret = btrfs_wait_ordered_range(inode, off, len); + else + filemap_flush(inode->i_mapping); +err: + kfree(pages); + return ret; +} +#endif /* MY_ABC_HERE */ + /** * btrfs_clone() - clone a range from inode file to another * @@ -327,7 +457,11 @@ static int clone_copy_inline_extent(struct inode *dst, */ static int btrfs_clone(struct inode *src, struct inode *inode, const u64 off, const u64 olen, const u64 olen_aligned, - const u64 destoff, int no_time_update) + const u64 destoff, int no_time_update +#ifdef MY_ABC_HERE + , struct btrfs_syno_clone_range_v2 *v2_args +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_path *path = NULL; @@ -340,6 +474,14 @@ static int btrfs_clone(struct inode *src, struct inode *inode, int ret; const u64 len = olen_aligned; u64 last_dest_end = destoff; +#ifdef MY_ABC_HERE + int need_rewrite_dst = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct ulist *disko_ulist; + bool set_clone_range; // Shall we set BTRFS_EXTENT_FLAG_HAS_CLONE_RANGE? + bool check_backref; +#endif /* MY_ABC_HERE */ ret = -ENOMEM; buf = kvmalloc(fs_info->nodesize, GFP_KERNEL); @@ -352,6 +494,30 @@ static int btrfs_clone(struct inode *src, struct inode *inode, return ret; } +#ifdef MY_ABC_HERE + disko_ulist = ulist_alloc(GFP_KERNEL); + if (!disko_ulist) { + btrfs_free_path(path); + kvfree(buf); + return ret; + } + + set_clone_range = (off != destoff); + if (off == 0 && destoff == 0 && inode_get_bytes(inode) == 0) + check_backref = false; + else + check_backref = true; + + down_read(&fs_info->inflight_reserve_lock); + ret = btrfs_qgroup_syno_reserve(BTRFS_I(inode)->root, olen_aligned); + if (ret < 0) + goto free_path; + + ret = btrfs_usrquota_syno_reserve(BTRFS_I(inode), olen_aligned); + if (ret < 0) + goto free_qgroup; +#endif /* MY_ABC_HERE */ + path->reada = READA_FORWARD; /* Clone data */ key.objectid = btrfs_ino(BTRFS_I(src)); @@ -367,6 +533,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode, struct btrfs_key new_key; u64 disko = 0, diskl = 0; u64 datao = 0, datal = 0; +#ifdef MY_ABC_HERE + u64 ram_bytes = 0; +#endif /* MY_ABC_HERE */ u8 comp; u64 drop_start; @@ -419,6 +588,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode, diskl = btrfs_file_extent_disk_num_bytes(leaf, extent); datao = btrfs_file_extent_offset(leaf, extent); datal = btrfs_file_extent_num_bytes(leaf, extent); +#ifdef MY_ABC_HERE + ram_bytes = btrfs_file_extent_ram_bytes(leaf, extent); +#endif /* MY_ABC_HERE */ } else if (type == BTRFS_FILE_EXTENT_INLINE) { /* Take upper bound, may be compressed */ datal = btrfs_file_extent_ram_bytes(leaf, extent); @@ -450,6 +622,29 @@ static int btrfs_clone(struct inode *src, struct inode *inode, else new_key.offset = destoff; +#ifdef MY_ABC_HERE + if (type == BTRFS_FILE_EXTENT_REG && disko != 0 && + v2_args && v2_args->ref_limit) { + u64 refs = 0; + if (!btrfs_get_extent_refs_count(fs_info, disko, diskl, &refs) && + refs >= v2_args->ref_limit) { + if (off > key.offset) { + v2_args->src_off = off; + v2_args->src_len = datal - (off - key.offset); + } else { + v2_args->src_off = key.offset; + v2_args->src_len = datal; + } + v2_args->ref_limit = refs; + if (v2_args->flag & BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_DST) { + need_rewrite_dst = 1; + } else { + ret = -EMLINK; + goto out; + } + } + } +#endif /* MY_ABC_HERE */ /* * Deal with a hole that doesn't have an extent item that * represents it (NO_HOLES feature enabled). @@ -487,11 +682,40 @@ static int btrfs_clone(struct inode *src, struct inode *inode, clone_info.file_offset = new_key.offset; clone_info.extent_buf = buf; clone_info.is_new_extent = false; +#ifdef MY_ABC_HERE + clone_info.ram_bytes = ram_bytes; + clone_info.clone_range = set_clone_range; + clone_info.clone_account_quota = false; + clone_info.clone_check_backref = check_backref; + + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) { + ret = ulist_add_lru_adjust(disko_ulist, disko, 0, GFP_KERNEL); + if (ret) + clone_info.clone_account_quota = true; + if (ret == -ENOMEM) + clone_info.clone_check_backref = true; + if (disko_ulist->nnodes > ULIST_NODES_MAX) { + clone_info.clone_check_backref = true; + ulist_remove_first(disko_ulist); + } + } +#endif /* MY_ABC_HERE */ ret = btrfs_replace_file_extents(inode, path, drop_start, new_key.offset + datal - 1, &clone_info, - &trans); + &trans +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; +#ifdef MY_ABC_HERE + btrfs_drop_extent_cache(BTRFS_I(inode), drop_start, new_key.offset + datal - 1, 0); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (need_rewrite_dst) + v2_args->dest_len = datal; +#endif /* MY_ABC_HERE */ } else if (type == BTRFS_FILE_EXTENT_INLINE) { /* * Inline extents always have to start at file offset 0 @@ -504,7 +728,14 @@ static int btrfs_clone(struct inode *src, struct inode *inode, ASSERT(key.offset == 0); ASSERT(datal <= fs_info->sectorsize); if (key.offset != 0 || datal > fs_info->sectorsize) +#ifdef MY_ABC_HERE + { + up_read(&fs_info->inflight_reserve_lock); return -EUCLEAN; + } +#else + return -EUCLEAN; +#endif /* MY_ABC_HERE */ ret = clone_copy_inline_extent(inode, path, &new_key, drop_start, datal, size, @@ -534,6 +765,12 @@ static int btrfs_clone(struct inode *src, struct inode *inode, destoff, olen, no_time_update); if (ret) goto out; +#ifdef MY_ABC_HERE + if (need_rewrite_dst) { + ret = -EMLINK; + goto out; + } +#endif /* MY_ABC_HERE */ if (new_key.offset + datal >= destoff + len) break; @@ -578,7 +815,11 @@ static int btrfs_clone(struct inode *src, struct inode *inode, &BTRFS_I(inode)->runtime_flags); ret = btrfs_replace_file_extents(inode, path, last_dest_end, - destoff + len - 1, NULL, &trans); + destoff + len - 1, NULL, &trans +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; @@ -587,6 +828,14 @@ static int btrfs_clone(struct inode *src, struct inode *inode, } out: +#ifdef MY_ABC_HERE + btrfs_usrquota_syno_free(BTRFS_I(inode), olen_aligned); +free_qgroup: + btrfs_qgroup_syno_free(BTRFS_I(inode)->root, olen_aligned); +free_path: + up_read(&fs_info->inflight_reserve_lock); + ulist_free(disko_ulist); +#endif /* MY_ABC_HERE */ btrfs_free_path(path); kvfree(buf); clear_bit(BTRFS_INODE_NO_DELALLOC_FLUSH, &BTRFS_I(inode)->runtime_flags); @@ -625,7 +874,11 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len, * source range to serialize with relocation. */ btrfs_double_extent_lock(src, loff, dst, dst_loff, len); - ret = btrfs_clone(src, dst, loff, len, ALIGN(len, bs), dst_loff, 1); + ret = btrfs_clone(src, dst, loff, len, ALIGN(len, bs), dst_loff, 1 +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); btrfs_double_extent_unlock(src, loff, dst, dst_loff, len); return ret; @@ -672,9 +925,1212 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, return ret; } +#ifdef MY_ABC_HERE +int get_extent_item_list(struct inode *inode, u64 offset, u64 len, + struct ulist *extent_item_list) +{ + int ret = 0; + u64 end = offset + len; + u64 bytenr, num_bytes; + struct btrfs_key key; + u64 ino = btrfs_ino(BTRFS_I(inode)); + struct btrfs_path *path = NULL; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct extent_buffer *leaf = NULL; + struct btrfs_file_extent_item *fi = NULL; + + ulist_reinit(extent_item_list); + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ret = btrfs_lookup_file_extent_by_file_offset(NULL, root, path, ino, + offset, 0); + if (ret < 0) + goto out; + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + + while (key.offset < end) { + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + + bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); + num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); + if (bytenr && num_bytes) { + ret = ulist_add(extent_item_list, bytenr, num_bytes, + GFP_NOFS); + if (ret < 0) + break; + if (extent_item_list->nnodes > ULIST_NODES_MAX) { + btrfs_warn_rl(BTRFS_I(inode)->root->fs_info, + "Add too much node, bad release size in syno_extent_same"); + break; + } + } + + ret = btrfs_search_next_file_extent(&key, root, path); + if (ret) + break; + leaf = path->nodes[0]; + } + ret = 0; + +out: + if (ret == -ENOENT) + ret = 0; + btrfs_free_path(path); + return ret; +} + +int delayed_backref_count(struct btrfs_fs_info *fs_info, u64 bytenr) +{ + int count = 0; + struct btrfs_transaction *trans = NULL; + struct btrfs_delayed_ref_head *head = NULL; // the header of delayed ref for the extent item + struct btrfs_delayed_ref_root *delayed_refs = NULL; // delayed ref in this trans + + /* Check trans */ + spin_lock(&fs_info->trans_lock); + trans = fs_info->running_transaction; + if (trans) + refcount_inc(&trans->use_count); + spin_unlock(&fs_info->trans_lock); + if (!trans) + return 0; + + delayed_refs = &trans->delayed_refs; + spin_lock(&delayed_refs->lock); + head = btrfs_find_delayed_ref_head(delayed_refs, bytenr); + if (!head) { + spin_unlock(&delayed_refs->lock); + goto out; + } + count = head->ref_mod; + spin_unlock(&delayed_refs->lock); +out: + btrfs_put_transaction(trans); + return count; +} + +int extent_same_release_size_accounting(struct ulist *dst_extent_item, + struct btrfs_root *root, + u64 *release_size) +{ + int ret = 0; + int refcount = 0; + struct ulist_iterator uiter; + struct ulist_node *node = NULL; + struct btrfs_key key; + struct btrfs_path *path = NULL; + struct btrfs_extent_item *ei = NULL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ULIST_ITER_INIT(&uiter); + key.type = BTRFS_EXTENT_ITEM_KEY; + + while ((node = ulist_next(dst_extent_item, &uiter))) { + key.objectid = node->val; + key.offset = node->aux; + + refcount = delayed_backref_count(root->fs_info, node->val); + ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, + path, 0, 0); + if (!ret) { + ei = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_extent_item); + refcount += btrfs_extent_refs(path->nodes[0], ei); + } + if (refcount <= 0) + *release_size += node->aux; + + btrfs_release_path(path); + } + + btrfs_free_path(path); + + return 0; +} +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +/* ported from 4.4.x */ +static struct page *extent_same_get_page(struct inode *inode, pgoff_t index) +{ + struct page *page; + + page = grab_cache_page(inode->i_mapping, index); + if (!page) + return ERR_PTR(-ENOMEM); + + if (!PageUptodate(page)) { + int ret; + + ret = btrfs_readpage(NULL, page); + if (ret) + return ERR_PTR(ret); + lock_page(page); + if (!PageUptodate(page)) { + unlock_page(page); + put_page(page); + return ERR_PTR(-EIO); + } + if (page->mapping != inode->i_mapping) { + unlock_page(page); + put_page(page); + return ERR_PTR(-EAGAIN); + } + } + + return page; +} + +/* ported from 4.4.x */ +static int gather_extent_pages(struct inode *inode, struct page **pages, + int num_pages, u64 off) +{ + int i; + pgoff_t index = off >> PAGE_SHIFT; + + for (i = 0; i < num_pages; i++) { +again: + pages[i] = extent_same_get_page(inode, index + i); + if (IS_ERR(pages[i])) { + int err = PTR_ERR(pages[i]); + + if (err == -EAGAIN) + goto again; + pages[i] = NULL; + return err; + } + } + return 0; +} + +static int check_ordered_extent(struct inode *inode, u64 off, u64 len) +{ + struct btrfs_ordered_extent *ordered; + int ret = -EAGAIN; + + ordered = btrfs_lookup_first_ordered_extent(BTRFS_I(inode), off + len - 1); + if ((!ordered || + ordered->file_offset + ordered->num_bytes <= off || + ordered->file_offset >= off + len) && + !test_range_bit(&BTRFS_I(inode)->io_tree, off, + off + len - 1, EXTENT_DELALLOC, 0, NULL)) { + ret = 0; + goto end; + } + + ret = -EAGAIN; + +end: + if (ordered) + btrfs_put_ordered_extent(ordered); + return ret; +} + +/* ported from 4.4.x */ +struct cmp_pages { + int num_pages; + struct page **src_pages; + struct page **dst_pages; +}; + +/* ported from 4.4.x */ +static void btrfs_cmp_data_free(struct cmp_pages *cmp) +{ + int i; + struct page *pg; + + for (i = 0; i < cmp->num_pages; i++) { + pg = cmp->src_pages[i]; + if (pg) { + unlock_page(pg); + put_page(pg); + } + pg = cmp->dst_pages[i]; + if (pg) { + unlock_page(pg); + put_page(pg); + } + } + kfree(cmp->src_pages); + kfree(cmp->dst_pages); +} + +/* ported from 4.4.x */ +static int btrfs_cmp_data_prepare(struct inode *src, u64 loff, + struct inode *dst, u64 dst_loff, + u64 len, struct cmp_pages *cmp) +{ + int ret; + int num_pages = PAGE_ALIGN(len) >> PAGE_SHIFT; + struct page **src_pgarr, **dst_pgarr; + + /* + * We must gather up all the pages before we initiate our + * extent locking. We use an array for the page pointers. Size + * of the array is bounded by len, which is in turn bounded by + * BTRFS_MAX_DEDUPE_LEN. + */ + src_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); + dst_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); + if (!src_pgarr || !dst_pgarr) { + kfree(src_pgarr); + kfree(dst_pgarr); + return -ENOMEM; + } + cmp->num_pages = num_pages; + cmp->src_pages = src_pgarr; + cmp->dst_pages = dst_pgarr; + + /* + * If deduping ranges in the same inode, locking rules make it mandatory + * to always lock pages in ascending order to avoid deadlocks with + * concurrent tasks (such as starting writeback/delalloc). + */ + if (src == dst && dst_loff < loff) { + swap(src_pgarr, dst_pgarr); + swap(loff, dst_loff); + } + + ret = gather_extent_pages(src, src_pgarr, cmp->num_pages, loff); + if (ret) + goto out; + + ret = gather_extent_pages(dst, dst_pgarr, cmp->num_pages, dst_loff); + +out: + if (ret) + btrfs_cmp_data_free(cmp); + return ret; +} + +static inline void *btrfs_cmp_data_kmap_page(struct page *page) +{ + void *addr; + + ASSERT(PageLocked(page)); + addr = kmap_atomic(page); + flush_dcache_page(page); + + return addr; +} + +/* copy from 4.4.x btrfs_cmp_data */ +static bool btrfs_cmp_data_and_truncate_len(struct cmp_pages *cmp, u64 total_len, + u64 *same_len, u64 *diff_len) +{ + int i; + bool diff_start = false; + unsigned int cmp_len = PAGE_SIZE; + void *src_addr, *dst_addr; + + *same_len = *diff_len = 0; + for (i = 0;i < cmp->num_pages;i++) { + if (total_len < PAGE_SIZE) + cmp_len = total_len; + + src_addr = btrfs_cmp_data_kmap_page(cmp->src_pages[i]); + dst_addr = btrfs_cmp_data_kmap_page(cmp->dst_pages[i]); + + if (!memcmp(src_addr, dst_addr, cmp_len)) { + if (diff_start) { + /* we got the end of different data */ + kunmap_atomic(src_addr); + kunmap_atomic(dst_addr); + break; + } + *same_len += cmp_len; + } else { + diff_start = true; + *diff_len += cmp_len; + } + kunmap_atomic(src_addr); + kunmap_atomic(dst_addr); + total_len -= cmp_len; + if (!total_len) + break; + } + + return diff_start; +} + +/* ported from 4.4.x */ +static int extent_same_check_offsets(struct inode *inode, u64 off, u64 *plen, + u64 olen) +{ + u64 len = *plen; + u64 bs = BTRFS_I(inode)->root->fs_info->sb->s_blocksize; + + if (off + olen > inode->i_size || off + olen < off) + return -EINVAL; + + /* if we extend to eof, continue to block boundary */ + if (off + len == inode->i_size) + *plen = len = ALIGN(inode->i_size, bs) - off; + + /* Check that we are block aligned - btrfs_clone() requires this */ + if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs)) + return -EINVAL; + + return 0; +} + +static int syno_extent_same_check_offset(struct inode *src, u64 loff, + struct inode *dst, u64 dst_loff, + u64 *len) +{ + int ret = -1; + u64 olen = *len; + + ret = extent_same_check_offsets(src, loff, len, olen); + if (ret) + goto out; + ret = extent_same_check_offsets(dst, dst_loff, len, olen); + if (ret) + goto out; + if (src == dst) { + /* extent_same_check_offsets may extend len over i_size(align bs). + * it is no sense to do it in the same inode. + */ + if (*len != olen) { + ret = -EINVAL; + goto out; + } + /* Check for overlapping ranges */ + if (dst_loff + *len > loff && dst_loff < loff + *len) { + ret = -EINVAL; + goto out; + } + } + ret = 0; +out: + return ret; +} + +static void btrfs_extent_same_ra(struct inode *inode, u64 off, u64 len) +{ + int i = 0; + struct page *page = NULL; + int num_pages = PAGE_ALIGN(len) >> PAGE_SHIFT; + pgoff_t index = off >> PAGE_SHIFT; + struct file_ra_state *ra = kzalloc(sizeof(struct file_ra_state), GFP_NOFS); + + if (!ra) { + /* it will read pages later, ignore */ + btrfs_warn_rl(BTRFS_I(inode)->root->fs_info, + "btrfs_extent_same_ra kmalloc file_ra_state failed"); + goto out; + } + + file_ra_state_init(ra, inode->i_mapping); + ra->ra_pages = num_pages; + page_cache_sync_readahead(inode->i_mapping, ra, NULL, + off >> PAGE_SHIFT, num_pages); + + for (i = 0; i < num_pages; i++) { + page = grab_cache_page(inode->i_mapping, index + i); + if (page) { + unlock_page(page); + put_page(page); + } + } + +out: + kfree(ra); + + return; +} + +static int get_extent_ref_remain(struct btrfs_root *root, struct btrfs_path *path, + u64 objectid, int *ref_remain) +{ + int ret = 0; + struct btrfs_key key; + + while (*ref_remain > 0) { + /* skip extent item, get first backref */ + path->slots[0]++; + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret) + break; + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + + if (key.objectid != objectid || + (BTRFS_EXTENT_DATA_REF_KEY != key.type && + BTRFS_SHARED_DATA_REF_KEY != key.type)) + break; + + (*ref_remain)--; + } + + return ret; +} + +static int inline_backref_count(struct extent_buffer *eb, int slot) +{ + int type = 0; + int count = 0; + u32 item_size = 0; + unsigned long ptr = 0, end = 0; + struct btrfs_extent_inline_ref *iref = NULL; + struct btrfs_extent_item *ei = NULL; + + ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); + item_size = btrfs_item_size_nr(eb, slot); + if (item_size < sizeof(*ei)) + return 0; + ptr = (unsigned long)(struct btrfs_extent_inline_ref *)(ei + 1); + end = (unsigned long)ei + item_size; + while (ptr < end) { + iref = (struct btrfs_extent_inline_ref *)ptr; + type = btrfs_extent_inline_ref_type(eb, iref); + if (BTRFS_EXTENT_DATA_REF_KEY == type || BTRFS_SHARED_DATA_REF_KEY == type) + count++; + ptr += btrfs_extent_inline_ref_size(type); + } + return count; +} + +static int get_backref_remain(struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, int *ref_remain) +{ + int ret = 1; + struct btrfs_key key; + struct btrfs_path *path = NULL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = bytenr; + key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = num_bytes; + + ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); + if (ret) { + if (ret > 0) + ret = 0; // not found. + goto out; + } + *ref_remain -= inline_backref_count(path->nodes[0], path->slots[0]); + *ref_remain -= delayed_backref_count(fs_info, bytenr); + /* we should check ref_remain after delayed ref, because it may drop backref in trans */ + ret = get_extent_ref_remain(fs_info->extent_root, path, bytenr, + ref_remain); + if (ret < 0) + goto out; + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +static int get_backref_remain_list(struct ulist *backref_remain_list, + struct btrfs_fs_info *fs_info, + struct inode *src, u64 start, u64 len, + int ref_limit) +{ + int ret = 0; + int ref_remain = 0; + struct ulist_iterator uiter; + struct ulist_node *node = NULL; + struct ulist *extent_item_list = NULL; + + extent_item_list = ulist_alloc(GFP_NOFS); + if (!extent_item_list) { + ret = -ENOMEM; + goto out; + } + + ret = get_extent_item_list(src, start, len, extent_item_list); + if (ret < 0) + goto out; + + ULIST_ITER_INIT(&uiter); + + while ((node = ulist_next(extent_item_list, &uiter))) { + ref_remain = ref_limit; + + ret = get_backref_remain(fs_info, node->val, node->aux, + &ref_remain); + if (ret < 0) + break; + ret = ulist_add(backref_remain_list, node->val, + (0 < ref_remain)? (u64)ref_remain:0, GFP_NOFS); + if (ret < 0) + break; + } + +out: + ulist_free(extent_item_list); + return ret; +} + +static inline int update_ditto_info(struct btrfs_path *path, + struct ulist *backref_remain_list, + u64 start, u64 end, u64 file_extent_start, + u64 *ditto_offset, u64 *ditto_len) +{ + u64 num_bytes = 0, ditto_end = 0; + struct ulist_node *node = NULL; + struct extent_buffer *leaf = path->nodes[0]; + struct btrfs_file_extent_item *fi = NULL; + + fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); + + node = ulist_search(backref_remain_list, btrfs_file_extent_disk_bytenr(leaf, fi)); + if (!node) + return 0; + if (node->aux > 0) { + node->aux--; + return 0; + } + num_bytes = btrfs_file_extent_num_bytes(leaf, fi); + + *ditto_offset = max(start, file_extent_start); // file_extent_start may smaller than request + + ditto_end = min(file_extent_start + num_bytes, end); + *ditto_len = ditto_end - *ditto_offset; + + return 1; +} + +static int check_backref_limit(struct inode *inode, u64 start, u64 len, + int ref_limit, u64 *ditto_offset, u64 *ditto_len) +{ + int ret = 0; + u64 ino = btrfs_ino(BTRFS_I(inode)); + u64 end = start + len; + struct ulist *backref_remain_list = NULL; + struct btrfs_key key; + struct btrfs_path *path = NULL; + struct btrfs_root *root = BTRFS_I(inode)->root; + + backref_remain_list = ulist_alloc(GFP_NOFS); + if (!backref_remain_list) { + ret = -ENOMEM; + goto out; + } + + ret = get_backref_remain_list(backref_remain_list, root->fs_info, inode, + start, len, ref_limit); + if (ret < 0) + goto out; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + ret = btrfs_lookup_file_extent_by_file_offset(NULL, root, path, ino, + start, 0); + if (ret < 0) + goto out; + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + + while (key.offset < end) { + + ret = update_ditto_info(path, backref_remain_list, start, end, + key.offset, ditto_offset, ditto_len); + if (ret) + break; + + ret = btrfs_search_next_file_extent(&key, root, path); + if (ret) + break; + } + +out: + if (ret == -ENOENT) + ret = 0; + btrfs_free_path(path); + ulist_free(backref_remain_list); + return ret; +} + +/* copy from btrfs_extent_same() */ +static int __syno_extent_same(struct inode *src, u64 src_off, u64 olen, + struct inode *dst, u64 dst_off, u64 min_len, + u64 *diff_offset, u64 *diff_len) +{ + int ret = 0; + u64 len = olen; + u64 lock_len = 0; + struct cmp_pages cmp; + + /* try to readahead pages before we get inode lock */ + btrfs_extent_same_ra(src, src_off, olen); + btrfs_extent_same_ra(dst, dst_off, olen); + +again: + lock_two_nondirectories(src, dst); + ret = syno_extent_same_check_offset(src, src_off, dst, dst_off, &len); + if (ret) + goto out_unlock; + + ret = btrfs_cmp_data_prepare(src, src_off, dst, dst_off, olen, &cmp); + if (ret) + goto out_unlock; + + lock_len = len; + btrfs_double_extent_lock(src, src_off, dst, dst_off, lock_len); + if (-EAGAIN == check_ordered_extent(src, src_off, lock_len) || + -EAGAIN == check_ordered_extent(dst, dst_off, lock_len)) { + btrfs_double_extent_unlock(src, src_off, dst, dst_off, lock_len); + btrfs_cmp_data_free(&cmp); + unlock_two_nondirectories(src, dst); + btrfs_wait_ordered_range(src, src_off, len); + btrfs_wait_ordered_range(dst, dst_off, len); + goto again; + } + + /* if we got different data, truncate clone length */ + if (btrfs_cmp_data_and_truncate_len(&cmp, lock_len, &len, diff_len)) + *diff_offset = dst_off + len; + + if (len && len >= min_len) +#ifdef MY_ABC_HERE + ret = btrfs_clone(src, dst, src_off, olen, len, dst_off, 1, NULL); +#else + ret = btrfs_clone(src, dst, src_off, olen, len, dst_off, 1); +#endif /* MY_ABC_HERE */ + + btrfs_double_extent_unlock(src, src_off, dst, dst_off, lock_len); + + btrfs_cmp_data_free(&cmp); + +out_unlock: + unlock_two_nondirectories(src, dst); + + return ret; +} + +static int syno_extent_same(struct inode *src, struct inode *dst, + struct btrfs_ioctl_syno_extent_same_args *same, + u64 ditto_offset, u64 ditto_len) +{ + int ret = 0; + u32 tail_len = 0; + u64 chunk_count = 0, i = 0; + u64 diff_offset = 0, diff_len = 0; + u64 min_len = same->min_dedupe_length; + u64 len = ditto_len ? (ditto_offset - same->src_offset) : same->length; + u64 src_offset = same->src_offset, dst_offset = same->dst_offset; + + if (len < min_len) + goto out; + + chunk_count = div_u64_rem(len, BTRFS_MAX_DEDUPE_LEN, &tail_len); + for (i = 0; i < chunk_count; i++) { + ret = __syno_extent_same(src, src_offset, BTRFS_MAX_DEDUPE_LEN, + dst, dst_offset, min_len, + &diff_offset, &diff_len); + if (ret || diff_len) + goto out; + src_offset += BTRFS_MAX_DEDUPE_LEN; + dst_offset += BTRFS_MAX_DEDUPE_LEN; + min_len = 0; + } + if (tail_len) + ret = __syno_extent_same(src, src_offset, tail_len, + dst, dst_offset, min_len, + &diff_offset, &diff_len); + +out: + if (diff_len) { + same->status = SYNO_EXTENT_SAME_DIFF; + same->failed_dst_offset = diff_offset; + same->failed_dst_length = diff_len; + } else if (ditto_len) { + same->status = SYNO_EXTENT_SAME_DITTO; + same->failed_dst_offset = same->dst_offset + ditto_offset - same->src_offset; + same->failed_dst_length = ditto_len; + } + + return ret; +} + +static bool dedupe_in_progress_add(struct btrfs_root *root) +{ + int ret = true; + + spin_lock(&root->root_item_lock); + if (root->send_in_progress) { + btrfs_warn_rl(root->fs_info, + "cannot deduplicate to root %llu while send operations are using it (%d in progress)", + root->root_key.objectid, root->send_in_progress); + ret = false; + goto out; + } + root->dedupe_in_progress++; +out: + spin_unlock(&root->root_item_lock); + return ret; +} + +static void dedupe_in_progress_dec(struct btrfs_root *root) +{ + spin_lock(&root->root_item_lock); + root->dedupe_in_progress--; + spin_unlock(&root->root_item_lock); +} + +static int btrfs_syno_extent_same(struct inode *src, struct inode *dst, + struct btrfs_ioctl_syno_extent_same_args *same) +{ + int ret = -1; + u64 ditto_offset = 0, ditto_len = 0; + struct btrfs_root *root_dst = BTRFS_I(dst)->root; + struct ulist *extent_item_list = NULL; + + /* don't touch certain kinds of inodes */ + if (IS_IMMUTABLE(dst)) + return -EPERM; + + /* swap file can't do extent_same */ + if (IS_SWAPFILE(src) || IS_SWAPFILE(dst)) + return -ETXTBSY; + + /* ignore "no dedupe" files */ + if (BTRFS_I(src)->flags & BTRFS_INODE_NODEDUPE || + BTRFS_I(dst)->flags & BTRFS_INODE_NODEDUPE) + return -EINVAL; + + /* don't make the dst file partial checksummed */ + if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != + (BTRFS_I(dst)->flags & BTRFS_INODE_NODATASUM)) + return -EINVAL; + + /* don't touch readonly root */ + if (btrfs_root_readonly(BTRFS_I(dst)->root)) + return -EROFS; + + /* don't modify file extent if it is doing send */ + if (!dedupe_in_progress_add(root_dst)) + return -EAGAIN; + + /* flush all data before extent_same */ + btrfs_wait_ordered_range(src, same->src_offset, same->length); + btrfs_wait_ordered_range(dst, same->dst_offset, same->length); + + /* backref should be limited, we check it before extent_same */ + ret = check_backref_limit(src, same->src_offset, same->length, + same->backref_limit, &ditto_offset, &ditto_len); + if (ret < 0) + goto out; + + extent_item_list = ulist_alloc(GFP_NOFS); + if (!extent_item_list) { + ret = -ENOMEM; + goto out; + } + + /* collect dst extent item list before we do extent_same */ + ret = get_extent_item_list(dst, same->dst_offset, + same->length, extent_item_list); + if (ret < 0) + goto out; + + ret = syno_extent_same(src, dst, same, ditto_offset, ditto_len); + if (ret < 0) + goto out; + + /* count how much extent item released */ + ret = extent_same_release_size_accounting(extent_item_list, + BTRFS_I(dst)->root, &same->release_size); + if (ret < 0) + goto out; + + ret = btrfs_file_extent_deduped_set_range(dst, same->dst_offset, same->length, true); + +out: + ulist_free(extent_item_list); + dedupe_in_progress_dec(root_dst); + + return ret; +} + +long btrfs_ioctl_syno_extent_same(struct file *file, + struct btrfs_ioctl_syno_extent_same_args __user *argp) +{ + int ret = -1; + struct inode *src = NULL; + struct inode *dst = NULL; + struct btrfs_root *root = BTRFS_I(file_inode(file))->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_syno_extent_same_args *same = NULL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (WARN_ON_ONCE(fs_info->sb->s_blocksize < PAGE_SIZE)) + return -EINVAL; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + same = memdup_user(argp, sizeof(struct btrfs_ioctl_syno_extent_same_args)); + if (IS_ERR(same)) { + ret = PTR_ERR(same); + same = NULL; + goto out; + } + + /* set return value to 0 */ + same->failed_dst_offset = 0; + same->failed_dst_length = 0; + same->release_size = 0; + same->status = 0; + + src = btrfs_get_regular_file_inode(fs_info->sb, same->src_rootid, + same->src_objectid); + if (IS_ERR(src)) { + ret = PTR_ERR(src); + if (-ESTALE == ret) { + same->status = SYNO_EXTENT_SAME_SRC_NOT_FOUND; + ret = 0; + } + goto out; + } + + dst = btrfs_get_regular_file_inode(fs_info->sb, same->dst_rootid, + same->dst_objectid); + if (IS_ERR(dst)) { + ret = PTR_ERR(dst); + if (-ESTALE == ret) { + same->status = SYNO_EXTENT_SAME_DST_NOT_FOUND; + ret = 0; + } + goto out; + } + + ret = btrfs_syno_extent_same(src, dst, same); + +out: + if (!ret) { + ret = copy_to_user(argp, same, + sizeof(struct btrfs_ioctl_syno_extent_same_args)); + if (ret) + ret = -EFAULT; + else if (same->status) + ret = -EMLINK; // this errno should be handled in user space + } + if (src && !IS_ERR(src)) + iput(src); + if (dst && !IS_ERR(dst)) + iput(dst); + mnt_drop_write_file(file); + kfree(same); + + return ret; +} + +void btrfs_mark_buffer_dirty(struct extent_buffer *buf); +/* modify from and insert_reserved_file_extent() */ +int insert_dedupe_file_extent(struct btrfs_trans_handle *trans, struct inode *inode, + u64 offset, u64 len, u64 disk_bytenr, u64 disk_num_bytes, u64 disk_offset) +{ + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_drop_extents_args drop_args = { 0 }; + int ret; + u64 bytes_to_add = 0; + bool release_trans = false; + int syno_usage; + struct btrfs_ref ref = { 0 }; + struct btrfs_file_extent_item *fi; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf; + struct btrfs_key ins; + + /* + * Still need to make sure the inode looks like it's been updated so + * that any holes get logged if we fsync. + */ + if (disk_bytenr == 0 && btrfs_fs_incompat(root->fs_info, NO_HOLES)) { + BTRFS_I(inode)->last_trans = root->fs_info->generation; + BTRFS_I(inode)->last_sub_trans = root->log_transid; + BTRFS_I(inode)->last_log_commit = root->last_log_commit; + return 0; + } + + if (!trans) { + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + release_trans = true; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + /* + * we may be replacing one extent in the tree with another. + * The new extent is pinned in the extent map, and we don't want + * to drop it from the cache until it is completely in the btree. + * + * So, tell btrfs_drop_extents to leave this extent in the cache. + * the caller is expected to unpin it and allow it to be merged + * with the others. + */ + drop_args.path = path; + drop_args.start = offset; + drop_args.end = offset + len; + drop_args.replace_extent = true; + drop_args.extent_item_size = sizeof(*fi); + ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args); + if (ret) + goto out; + + if (!drop_args.extent_inserted) { + ins.objectid = btrfs_ino(BTRFS_I(inode)); + ins.offset = offset; + ins.type = BTRFS_EXTENT_DATA_KEY; + + path->leave_spinning = 1; + ret = btrfs_insert_empty_item(trans, root, path, &ins, + sizeof(*fi)); + if (ret) + goto out; + } + leaf = path->nodes[0]; + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + //TODO:fix compression + btrfs_set_file_extent_generation(leaf, fi, trans->transid); + btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); + btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr); + btrfs_set_file_extent_disk_num_bytes(leaf, fi, disk_num_bytes); + btrfs_set_file_extent_offset(leaf, fi, disk_offset); + btrfs_set_file_extent_num_bytes(leaf, fi, len); + btrfs_set_file_extent_ram_bytes(leaf, fi, len); + btrfs_set_file_extent_compression(leaf, fi, 0); + btrfs_set_file_extent_encryption(leaf, fi, 0); + btrfs_set_file_extent_other_encoding(leaf, fi, 0); + btrfs_set_file_extent_syno_flag(leaf, fi, BTRFS_FILE_EXTENT_DEDUPED); + + btrfs_mark_buffer_dirty(leaf); + + syno_usage = btrfs_syno_usage_ref_check(root, btrfs_ino(BTRFS_I(inode)), offset); + + btrfs_release_path(path); + + if (disk_bytenr) + bytes_to_add = len; + + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), bytes_to_add, drop_args.bytes_found); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + bytes_to_add, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + bytes_to_add, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); + + ret = btrfs_inode_set_file_extent_range(BTRFS_I(inode), offset, len); + if (ret) + goto out; + + btrfs_update_inode(trans, root, inode); + + if (disk_bytenr) { + btrfs_init_generic_ref(&ref, + BTRFS_ADD_DELAYED_REF, + disk_bytenr, disk_num_bytes, 0); + btrfs_init_data_ref(&ref, + root->root_key.objectid, + btrfs_ino(BTRFS_I(inode)), + offset - disk_offset + , syno_usage + ); + ref.skip_qgroup = true; + ret = btrfs_inc_extent_ref(trans, &ref); + } + +out: + if (release_trans) { + if (ret) + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + } + btrfs_free_path(path); + return ret; +} + +#define INLINE_DEDUPE_MIN_PAGES 32 + +static u64 inode_pgoff_hash_get(struct inode *inode, pgoff_t page_off, bool *zero) +{ + u64 hash = 0; + struct page *page = NULL; + char *kaddr = NULL; + + *zero = false; + + page = find_get_page(inode->i_mapping, page_off); + if (!page) { + printk("find_get_page failed, ino:%llu off:%lu\n", btrfs_ino(BTRFS_I(inode)), page_off << PAGE_SHIFT); + goto out; + } + + kaddr = kmap_atomic(page); + if (!memcmp(kaddr, empty_zero_page, PAGE_SIZE)) + *zero = true; + kunmap_atomic(kaddr); + + put_page(page); + +out: + return hash; +} + +static u64 inline_dedupe_zero_cmp(struct inode *inode, pgoff_t page_start, u64 check_pgs) +{ + bool zero = false; + u64 page_cur = page_start; + u64 page_end = page_start + check_pgs; + + for (; page_cur < page_end; page_cur++) { + inode_pgoff_hash_get(inode, page_cur, &zero); + if (!zero) + break; + } + return page_cur - page_start; +} + +static bool __inline_dedupe_search(struct inode *inode, struct inode *src_inode, + pgoff_t start_pgoff, u64 check_pages, u64 *match_pgoff, u64 *match_src_pgoff, + u64 *match_pages, bool *match_zero) +{ + u64 cur = 0; + u64 pages = 0; + u64 hash = 0; + bool zero = false; + + for (cur = 0; cur < check_pages; cur++) { + hash = inode_pgoff_hash_get(inode, start_pgoff + cur, &zero); + if (zero) { + pages = inline_dedupe_zero_cmp(inode, start_pgoff + cur, check_pages - cur); + if (pages >= INLINE_DEDUPE_MIN_PAGES || pages == check_pages) { + *match_pgoff = start_pgoff + cur; + *match_pages = pages; + *match_zero = true; + return true; + } + continue; + } + } + + return false; +} + +/* + * return + * 0: could inline dedupe + * -ENOENT: not match + * -EINVAL: bad parameter + */ +int inline_dedupe_search(struct inode *inode, u64 start, u64 len, + u64 *disk_bytenr, u64 *disk_num_bytes, u64 *disk_offset, + u64 *match_off, u64 *match_len) +{ + int ret = -ENOENT; + u64 match_pgoff = 0, src_pgoff = 0, match_pages = 0; + bool zero = false; + + if (!inode || start % PAGE_SIZE || !len || !disk_bytenr || !disk_num_bytes || !disk_offset || !match_len) + return -EINVAL; + + *disk_bytenr = *disk_num_bytes = *disk_offset = *match_off = *match_len = 0; + + if (!__inline_dedupe_search(inode, NULL, start >> PAGE_SHIFT, + len >> PAGE_SHIFT, &match_pgoff, &src_pgoff, + &match_pages, &zero)) { + goto out; + } + *match_off = match_pgoff << PAGE_SHIFT; + + if (zero) { + *match_len = match_pages << PAGE_SHIFT; + ret = insert_dedupe_file_extent(NULL, inode, *match_off, *match_len, 0, 0, 0); + goto out; + } + +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void syno_inode_clone_change_flags(struct inode *src, + struct inode *inode, + u64 destoff, + unsigned int remap_flags) +{ + int ret = -1; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_trans_handle *trans = NULL; + u64 oldflags; + + if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) == + (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) || + (remap_flags && (remap_flags & ~REMAP_FILE_CAN_SHORTEN)) || + 0 != destoff) + return; + + /* wait all lockless writes */ + down_write(&BTRFS_I(inode)->dio_sem); + btrfs_wait_ordered_range(inode, 0, -1); + + if (0 != inode_get_bytes(inode)) + goto out_unlock; + + oldflags = BTRFS_I(inode)->flags; + + if (BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) + BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM|BTRFS_INODE_NODATACOW; + else + BTRFS_I(inode)->flags &= ~(BTRFS_INODE_NODATASUM|BTRFS_INODE_NODATACOW); + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + goto out_drop; + + inode_inc_iversion(inode); + inode->i_ctime = current_time(inode); + ret = btrfs_update_inode(trans, root, inode); + + btrfs_end_transaction(trans); +out_drop: + if (ret) + BTRFS_I(inode)->flags = oldflags; +out_unlock: + up_write(&BTRFS_I(inode)->dio_sem); + return; +} +#endif /* MY_ABC_HERE */ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - u64 off, u64 olen, u64 destoff) + u64 off, u64 olen, u64 destoff +#ifdef MY_ABC_HERE + , struct btrfs_syno_clone_range_v2 *v2_args +#endif /* MY_ABC_HERE */ + ) { struct inode *inode = file_inode(file); struct inode *src = file_inode(file_src); @@ -683,6 +2139,10 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, int wb_ret; u64 len = olen; u64 bs = fs_info->sb->s_blocksize; +#ifdef MY_ABC_HERE + u64 orig_destoff = 0; + u64 orig_len = 0; +#endif /* MY_ABC_HERE */ /* * VFS's generic_remap_file_range_prep() protects us from cloning the @@ -714,14 +2174,67 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, return ret; } +#ifdef MY_ABC_HERE + orig_destoff = destoff; + orig_len = len; +clone_again: +#endif /* MY_ABC_HERE */ /* * Lock destination range to serialize with concurrent readpages() and * source range to serialize with relocation. */ btrfs_double_extent_lock(src, off, inode, destoff, len); - ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); + ret = btrfs_clone(src, inode, off, olen, len, destoff, 0 +#ifdef MY_ABC_HERE + , v2_args +#endif /* MY_ABC_HERE */ + ); btrfs_double_extent_unlock(src, off, inode, destoff, len); +#ifdef MY_ABC_HERE + if (ret == -EMLINK && v2_args) { + if (v2_args->flag & BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_SRC) { + if (btrfs_root_readonly(BTRFS_I(src)->root)) + goto fail_out; + ret = btrfs_clone_auto_rewrite(src, v2_args->src_off, + v2_args->src_len, true); + if (0 > ret) + goto fail_out; + destoff = destoff + (v2_args->src_off - off); + len = len - (v2_args->src_off - off); + off = v2_args->src_off; + olen = len; + goto clone_again; + } else if (v2_args->flag & BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_DST) { + ret = btrfs_clone_auto_rewrite(inode, + destoff + (v2_args->src_off - off), + v2_args->dest_len, false); + if (0 > ret) + goto fail_out; + destoff = destoff + (v2_args->src_off - off) + v2_args->dest_len; + len = len - (v2_args->src_off - off) - v2_args->dest_len; + off = v2_args->src_off + v2_args->dest_len; + olen = len; + if (len) + goto clone_again; + } + } +fail_out: + /* + * We may have copied an inline extent into a page of the destination + * range, so wait for writeback to complete before truncating pages + * from the page cache. This is a rare case. + */ + wb_ret = btrfs_wait_ordered_range(inode, orig_destoff, orig_len); + ret = ret ? ret : wb_ret; + /* + * Truncate page cache pages so that future reads will see the cloned + * data immediately and not the previous data. + */ + truncate_inode_pages_range(&inode->i_data, + round_down(orig_destoff, PAGE_SIZE), + round_up(orig_destoff + orig_len, PAGE_SIZE) - 1); +#else /* MY_ABC_HERE */ /* * We may have copied an inline extent into a page of the destination * range, so wait for writeback to complete before truncating pages @@ -736,10 +2249,31 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, truncate_inode_pages_range(&inode->i_data, round_down(destoff, PAGE_SIZE), round_up(destoff + len, PAGE_SIZE) - 1); +#endif /* MY_ABC_HERE */ return ret; } +#ifdef MY_ABC_HERE +static inline +int btrfs_clone_check_compr(const struct inode *inode_in, + const struct inode *inode_out, + const unsigned int flags) +{ + const struct btrfs_inode *in = BTRFS_I(inode_in); + const struct btrfs_inode *out = BTRFS_I(inode_out); + + if (flags & REMAP_FILE_SKIP_CHECK_COMPR_DIR) + return 0; + + if ((in->flags & BTRFS_INODE_COMPRESS) != + (out->flags & BTRFS_INODE_COMPRESS)) + return -EINVAL; + + return 0; +} +#endif /* MY_ABC_HERE */ + static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t *len, unsigned int remap_flags) @@ -761,6 +2295,16 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, inode_in->i_sb != inode_out->i_sb) return -EXDEV; } +#ifdef MY_ABC_HERE + syno_inode_clone_change_flags(inode_in, inode_out, + pos_out, remap_flags); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ret = btrfs_clone_check_compr(inode_in, inode_out, remap_flags); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ /* Don't make the dst file partly checksummed */ if ((BTRFS_I(inode_in)->flags & BTRFS_INODE_NODATASUM) != @@ -830,6 +2374,148 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, len, remap_flags); } +#ifdef MY_ABC_HERE +static int clone_range_v2_verify_area(struct file *file, loff_t pos, loff_t len, + bool write) +{ + struct inode *inode = file_inode(file); + + if (unlikely(pos < 0 || len < 0)) + return -EINVAL; + + if (unlikely((loff_t) (pos + len) < 0)) + return -EINVAL; + + if (unlikely(inode->i_flctx && mandatory_lock(inode))) { + loff_t end = len ? pos + len - 1 : OFFSET_MAX; + int retval; + + retval = locks_mandatory_area(inode, file, pos, end, + write ? F_WRLCK : F_RDLCK); + if (retval < 0) + return retval; + } + + return security_file_permission(file, write ? MAY_WRITE : MAY_READ); +} + +int btrfs_ioctl_syno_clone_range_v2(struct file *dst_file, + struct btrfs_ioctl_syno_clone_range_args_v2 __user *argp) +{ + struct fd src_file; + __s64 src_fd = 0; + struct btrfs_syno_clone_range_v2 args; + struct inode *src_inode; + struct inode *dst_inode = file_inode(dst_file); + bool same_inode; + u64 len; + int ret; +#ifdef MY_ABC_HERE + unsigned int flags = 0; +#endif /* MY_ABC_HERE */ + + memset(&args, 0, sizeof(args)); + if (copy_from_user(&args.src_off, &argp->src_offset, sizeof(args.src_off)) || + copy_from_user(&args.src_len, &argp->src_length, sizeof(args.src_len)) || + copy_from_user(&args.dest_off, &argp->dest_offset, sizeof(args.dest_off)) || + copy_from_user(&args.ref_limit, &argp->ref_limit, sizeof(args.ref_limit)) || + copy_from_user(&args.flag, &argp->flag, sizeof(args.flag)) || + copy_from_user(&src_fd, &argp->src_fd, sizeof(src_fd))) + return -EFAULT; + + if ((args.flag & BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_SRC) && + (args.flag & BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_DST)) + return -EINVAL; + + /* + * Follow ioctl_file_clone_range all the way to btrfs_clone_files, + * most of the checks are done in + * btrfs_remap_file_range_prep/generic_remap_file_range_prep. + * What left are remap_verify_area(src/dst), and file mode check, + * so we have to check it by ourselves here. + */ + src_file = fdget(src_fd); + if (!src_file.file) + return -EBADF; + + file_start_write(dst_file); + if (!(src_file.file->f_mode & FMODE_READ) || + !(dst_file->f_mode & FMODE_WRITE) || + (dst_file->f_flags & O_APPEND)) { + ret = -EBADF; + goto out; + } + + if ((args.flag & BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_SRC) && + !(src_file.file->f_mode & FMODE_WRITE)) { + ret = -EBADF; + goto out; + } + + len = args.src_len; + ret = clone_range_v2_verify_area(src_file.file, args.src_off, len, false); + if (ret) + goto out; + ret = clone_range_v2_verify_area(dst_file, args.dest_off, len, true); + if (ret) + goto out; + +#ifdef MY_ABC_HERE + /* + * There's workarounds for DSM #81059 and DSM#150209. We allow to clone + * between compression and no compression dirs in TWO conditions: + * 1. if we do IOC_CLONE_RANGE with whole file. + * 2. if the args.flag is with the specified flag. (btrfs receive) + */ + if ((args.flag & BTRFS_CLONE_RANGE_V2_SKIP_CHECK_COMPR_DIR) || + (!args.src_off && !args.dest_off && !len)) + flags = REMAP_FILE_SKIP_CHECK_COMPR_DIR; +#endif /* MY_ABC_HERE */ + + src_inode = file_inode(src_file.file); + same_inode = dst_inode == src_inode; + if (same_inode) + inode_lock(src_inode); + else + lock_two_nondirectories(src_inode, dst_inode); + + ret = btrfs_remap_file_range_prep(src_file.file, args.src_off, + dst_file, args.dest_off, &len +#ifdef MY_ABC_HERE + , flags +#else /* MY_ABC_HERE */ + , 0 +#endif /* MY_ABC_HERE */ + ); + if (ret < 0 || len == 0) + goto out_unlock; + + ret = btrfs_clone_files(dst_file, src_file.file, args.src_off, + len, args.dest_off, &args); + if (ret < 0 && ret != -EMLINK) + goto out_unlock; + + if (ret == -EMLINK && + (put_user(args.src_off, &argp->src_offset) || + put_user(args.src_len, &argp->src_length) || + put_user(args.ref_limit, &argp->ref_limit))) { + ret = -EFAULT; + goto out_unlock; + } + fsnotify_access(src_file.file); + fsnotify_modify(dst_file); +out_unlock: + if (same_inode) + inode_unlock(src_inode); + else + unlock_two_nondirectories(src_inode, dst_inode); +out: + file_end_write(dst_file); + fdput(src_file); + return ret; +} +#endif /* MY_ABC_HERE */ + loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, struct file *dst_file, loff_t destoff, loff_t len, unsigned int remap_flags) @@ -855,7 +2541,11 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, if (remap_flags & REMAP_FILE_DEDUP) ret = btrfs_extent_same(src_inode, off, len, dst_inode, destoff); else - ret = btrfs_clone_files(dst_file, src_file, off, len, destoff); + ret = btrfs_clone_files(dst_file, src_file, off, len, destoff +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); out_unlock: if (same_inode) diff --git a/fs/btrfs/reflink.h b/fs/btrfs/reflink.h index ecb309b4dad0..0d00749088ed 100644 --- a/fs/btrfs/reflink.h +++ b/fs/btrfs/reflink.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_REFLINK_H @@ -9,4 +12,14 @@ loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t len, unsigned int remap_flags); +#ifdef MY_ABC_HERE +int btrfs_ioctl_syno_clone_range_v2(struct file *dst_file, + struct btrfs_ioctl_syno_clone_range_args_v2 __user *argp); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +long btrfs_ioctl_syno_extent_same(struct file *file, + struct btrfs_ioctl_syno_extent_same_args __user *argp); +#endif /* MY_ABC_HERE */ + #endif /* BTRFS_REFLINK_H */ diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index c21545c5b34b..e0622f71b6b9 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2009 Oracle. All rights reserved. @@ -1018,10 +1021,17 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr, fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); +#ifdef MY_ABC_HERE + WARN_ON_ONCE(btrfs_file_extent_other_encoding(leaf, fi)); + BUG_ON(btrfs_file_extent_offset(leaf, fi) || + btrfs_file_extent_compression(leaf, fi) || + btrfs_file_extent_encryption(leaf, fi)); +#else BUG_ON(btrfs_file_extent_offset(leaf, fi) || btrfs_file_extent_compression(leaf, fi) || btrfs_file_extent_encryption(leaf, fi) || btrfs_file_extent_other_encoding(leaf, fi)); +#endif /* MY_ABC_HERE */ if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi)) { ret = -EINVAL; @@ -1059,6 +1069,9 @@ int replace_file_extents(struct btrfs_trans_handle *trans, int ret = 0; int first = 1; int dirty = 0; +#ifdef MY_ABC_HERE + int syno_usage; +#endif /* MY_ABC_HERE */ if (rc->stage != UPDATE_DATA_PTRS) return 0; @@ -1133,12 +1146,23 @@ int replace_file_extents(struct btrfs_trans_handle *trans, btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr); dirty = 1; +#ifdef MY_ABC_HERE + syno_usage = btrfs_syno_usage_ref_check(root, key.objectid, key.offset); +#endif /* MY_ABC_HERE */ + key.offset -= btrfs_file_extent_offset(leaf, fi); btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr, num_bytes, parent); ref.real_root = root->root_key.objectid; btrfs_init_data_ref(&ref, btrfs_header_owner(leaf), - key.objectid, key.offset); + key.objectid, key.offset +#ifdef MY_ABC_HERE + , syno_usage +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ ret = btrfs_inc_extent_ref(trans, &ref); if (ret) { btrfs_abort_transaction(trans, ret); @@ -1149,7 +1173,14 @@ int replace_file_extents(struct btrfs_trans_handle *trans, num_bytes, parent); ref.real_root = root->root_key.objectid; btrfs_init_data_ref(&ref, btrfs_header_owner(leaf), - key.objectid, key.offset); + key.objectid, key.offset +#ifdef MY_ABC_HERE + , syno_usage +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + ref.skip_qgroup = true; +#endif /* MY_ABC_HERE */ ret = btrfs_free_extent(trans, &ref); if (ret) { btrfs_abort_transaction(trans, ret); diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 702dc5441f03..f29252e160e5 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -213,6 +216,9 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info) struct btrfs_root *root; int err = 0; int ret; +#ifdef MY_ABC_HERE + int empty = 0; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -281,7 +287,15 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info) WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state)); if (btrfs_root_refs(&root->root_item) == 0) { set_bit(BTRFS_ROOT_DEAD_TREE, &root->state); +#ifdef MY_ABC_HERE + spin_lock(&root->inode_lock); + empty = RB_EMPTY_ROOT(&root->inode_tree); + spin_unlock(&root->inode_lock); + if (empty) + btrfs_add_dead_root(root); +#else /* MY_ABC_HERE */ btrfs_add_dead_root(root); +#endif /* MY_ABC_HERE */ } btrfs_put_root(root); } diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 0392c556af60..2724a25e5150 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2011, 2012 STRATO. All rights reserved. @@ -75,6 +78,9 @@ struct scrub_page { unsigned int mirror_num:8; unsigned int have_csum:1; unsigned int io_error:1; +#ifdef MY_ABC_HERE + unsigned int tried_out:1; +#endif /* MY_ABC_HERE */ }; u8 csum[BTRFS_CSUM_SIZE]; @@ -116,9 +122,20 @@ struct scrub_block { /* It is for the data with checksum */ unsigned int data_corrected:1; }; +#ifdef MY_ABC_HERE + int page_tried_out; + u8 nr_retry; + u8 prev_bad_csum[BTRFS_CSUM_SIZE]; +#endif /* MY_ABC_HERE */ struct btrfs_work work; }; +#ifdef MY_ABC_HERE +#define SCRUB_RETRY_LIMIT SYNO_DATA_CORRECTION_MAX_RETRY_TIMES +#define BTRFS_SCRUB_RETRY_ABORTED ((u8)-1) +#define BTRFS_SCRUB_SHOULD_ABORT_RETRY ((u8)-2) +#endif /* MY_ABC_HERE */ + /* Used for the chunks with parity stripe such RAID5/6 */ struct scrub_parity { struct scrub_ctx *sctx; @@ -634,7 +651,11 @@ static noinline_for_stack struct scrub_ctx *scrub_setup_ctx( } static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, - void *warn_ctx) + void *warn_ctx +#ifdef MY_ABC_HERE + , int extent_type +#endif /* MY_ABC_HERE */ + ) { u64 isize; u32 nlink; @@ -649,6 +670,10 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, struct btrfs_root *local_root; struct btrfs_key key; +#ifdef MY_ABC_HERE + add_cksumfailed_file(root, inum, fs_info); + SynoAutoErrorFsBtrfsReport(fs_info->fs_devices->fsid); +#endif /* MY_ABC_HERE */ local_root = btrfs_get_fs_root(fs_info, root, true); if (IS_ERR(local_root)) { ret = PTR_ERR(local_root); @@ -725,6 +750,9 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, return 0; } +#ifdef MY_ABC_HERE +// Now we enter here only when we failed to do the repair to avoid unnecessary backref walking. +#endif /* MY_ABC_HERE */ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) { struct btrfs_device *dev; @@ -835,8 +863,11 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) int success; bool full_stripe_locked; unsigned int nofs_flag; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); +#endif /* MY_ABC_HERE */ BUG_ON(sblock_to_check->page_count < 1); fs_info = sctx->fs_info; @@ -942,6 +973,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) BUG_ON(failed_mirror_index >= BTRFS_MAX_MIRRORS); sblock_bad = sblocks_for_recheck + failed_mirror_index; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ /* build and submit the bios for the failed mirror, check checksums */ scrub_recheck_block(fs_info, sblock_bad, 1); @@ -964,26 +997,79 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) scrub_write_block_to_dev_replace(sblock_bad); goto out; } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!sblock_to_check->no_io_error_seen) { +#else /* MY_ABC_HERE */ if (!sblock_bad->no_io_error_seen) { +#endif /* MY_ABC_HERE */ spin_lock(&sctx->stat_lock); sctx->stat.read_errors++; spin_unlock(&sctx->stat_lock); + +#ifdef MY_ABC_HERE + btrfs_data_correction_print_in_rcu(fs_info, + fs_info->correction_suppress_log, + "i/o error found by scrub at logical %llu on dev %s, " + "mirror = %u, metadata = %d\n", + logical, rcu_str_deref(dev->name), + failed_mirror_index, is_metadata); + btrfs_dev_stat_inc(dev, BTRFS_DEV_STAT_READ_ERRS); +#else /* MY_ABC_HERE */ if (__ratelimit(&rs)) scrub_print_warning("i/o error", sblock_to_check); btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + } else if (sblock_to_check->checksum_error) { +#else /* MY_ABC_HERE */ } else if (sblock_bad->checksum_error) { +#endif /* MY_ABC_HERE */ spin_lock(&sctx->stat_lock); sctx->stat.csum_errors++; spin_unlock(&sctx->stat_lock); + +#ifdef MY_ABC_HERE + btrfs_data_correction_print_in_rcu(fs_info, + fs_info->correction_suppress_log, + "checksum error found by scrub at logical %llu on dev %s, " + "mirror = %u, metadata = %d\n", + logical, rcu_str_deref(dev->name), + failed_mirror_index, is_metadata); + btrfs_dev_stat_inc(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); +#else /* MY_ABC_HERE */ if (__ratelimit(&rs)) scrub_print_warning("checksum error", sblock_to_check); btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + } else if (sblock_to_check->header_error) { +#else /* MY_ABC_HERE */ } else if (sblock_bad->header_error) { +#endif /* MY_ABC_HERE */ spin_lock(&sctx->stat_lock); sctx->stat.verify_errors++; spin_unlock(&sctx->stat_lock); + +#ifdef MY_ABC_HERE + btrfs_data_correction_print_in_rcu(fs_info, + fs_info->correction_suppress_log, + "checksum/header error found by scrub at logical %llu on dev %s, " + "mirror = %u, metadata = %d\n", + logical, rcu_str_deref(dev->name), + failed_mirror_index, is_metadata); + + if (sblock_to_check->generation_error) + btrfs_dev_stat_inc(dev, + BTRFS_DEV_STAT_GENERATION_ERRS); + else + btrfs_dev_stat_inc(dev, + BTRFS_DEV_STAT_CORRUPTION_ERRS); +#else /* MY_ABC_HERE */ if (__ratelimit(&rs)) scrub_print_warning("checksum/header error", sblock_to_check); @@ -993,6 +1079,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) else btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); +#endif /* MY_ABC_HERE */ } if (sctx->readonly) { @@ -1000,6 +1087,9 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) goto out; } +#ifdef MY_ABC_HERE + correction_get_locked_record(fs_info, sblock_to_check->pagev[0]->logical); +#endif /* MY_ABC_HERE */ /* * now build and submit the bios for the other mirrors, check * checksums. @@ -1018,8 +1108,11 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) for (mirror_index = 0; ;mirror_index++) { struct scrub_block *sblock_other; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ if (mirror_index == failed_mirror_index) continue; +#endif /* MY_ABC_HERE */ /* raid56's mirror can be more than BTRFS_MAX_MIRRORS */ if (!scrub_is_page_on_raid56(sblock_bad->pagev[0])) { @@ -1044,6 +1137,11 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sblock_other->pagev[0]->mirror_num = 1 + mirror_index; } +#ifdef MY_ABC_HERE + if (mirror_index == failed_mirror_index) + goto recheck_retry; +#endif /* MY_ABC_HERE */ + /* build and submit the bios, check checksums */ scrub_recheck_block(fs_info, sblock_other, 0); @@ -1060,6 +1158,40 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) goto corrected_error; } } + +#ifdef MY_ABC_HERE +recheck_retry: + if (scrub_is_page_on_raid56(sblock_other->pagev[0])) + continue; + + if (sblock_other->nr_retry > SCRUB_RETRY_LIMIT) + sblock_other->nr_retry = BTRFS_SCRUB_SHOULD_ABORT_RETRY; + else if (sblock_other->nr_retry < BTRFS_SCRUB_SHOULD_ABORT_RETRY) + sblock_other->nr_retry++; + + scrub_recheck_block(fs_info, sblock_other, 0); + + if (!sblock_other->header_error && + !sblock_other->checksum_error && + sblock_other->no_io_error_seen) { + if (sctx->is_dev_replace) { + scrub_write_block_to_dev_replace(sblock_other); + goto corrected_error; + } else { + ret = scrub_repair_block_from_good_copy( + sblock_bad, sblock_other); + if (!ret) + goto corrected_error; + else + continue; + } + } + + if (sblock_other->nr_retry != BTRFS_SCRUB_RETRY_ABORTED) + goto recheck_retry; + else + sblock_other->nr_retry = 0; +#endif /* MY_ABC_HERE */ } if (sblock_bad->no_io_error_seen && !sctx->is_dev_replace) @@ -1090,6 +1222,9 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) * area are unreadable. */ success = 1; +#ifdef MY_ABC_HERE + goto did_not_correct_error; +#endif /* MY_ABC_HERE */ for (page_num = 0; page_num < sblock_bad->page_count; page_num++) { struct scrub_page *page_bad = sblock_bad->pagev[page_num]; @@ -1177,18 +1312,37 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sctx->stat.corrected_errors++; sblock_to_check->data_corrected = 1; spin_unlock(&sctx->stat_lock); +#ifdef MY_ABC_HERE + correction_put_locked_record(fs_info, + sblock_to_check->pagev[0]->logical); + btrfs_data_correction_print_in_rcu(fs_info, + fs_info->correction_suppress_log, + "BTRFS: read error corrected (scrub) " + "at logical %llu on dev %s, metadata = %d\n", + logical, rcu_str_deref(dev->name), is_metadata); +#else /* MY_ABC_HERE */ btrfs_err_rl_in_rcu(fs_info, "fixed up error at logical %llu on dev %s", logical, rcu_str_deref(dev->name)); +#endif /* MY_ABC_HERE */ } } else { did_not_correct_error: spin_lock(&sctx->stat_lock); sctx->stat.uncorrectable_errors++; spin_unlock(&sctx->stat_lock); +#ifdef MY_ABC_HERE + correction_put_locked_record(fs_info, sblock_to_check->pagev[0]->logical); + printk_in_rcu(KERN_ERR +"failed to repair csum (scrub) at logical %llu on dev %s, mirror = %u, metadata = %d\n", + logical, rcu_str_deref(dev->name), + failed_mirror_index, is_metadata); + scrub_print_warning(NULL, sblock_to_check); +#else /* MY_ABC_HERE */ btrfs_err_rl_in_rcu(fs_info, "unable to fixup (regular) error at logical %llu on dev %s", logical, rcu_str_deref(dev->name)); +#endif /* MY_ABC_HERE */ } out: @@ -1467,7 +1621,10 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, { int page_num; - sblock->no_io_error_seen = 1; +#ifdef MY_ABC_HERE + if (sblock->nr_retry < BTRFS_SCRUB_SHOULD_ABORT_RETRY) +#endif /* MY_ABC_HERE */ + sblock->no_io_error_seen = 1; /* short cut for raid56 */ if (!retry_failed_mirror && scrub_is_page_on_raid56(sblock->pagev[0])) @@ -1477,6 +1634,12 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, struct bio *bio; struct scrub_page *page = sblock->pagev[page_num]; +#ifdef MY_ABC_HERE + if (page->tried_out && + sblock->nr_retry < BTRFS_SCRUB_SHOULD_ABORT_RETRY) + continue; +#endif /* MY_ABC_HERE */ + if (page->dev->bdev == NULL) { page->io_error = 1; sblock->no_io_error_seen = 0; @@ -1490,16 +1653,40 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, bio_add_page(bio, page->page, PAGE_SIZE, 0); bio->bi_iter.bi_sector = page->physical >> 9; bio->bi_opf = REQ_OP_READ; +#ifdef MY_ABC_HERE + if (sblock->nr_retry == BTRFS_SCRUB_SHOULD_ABORT_RETRY) + bio_set_flag(bio, BIO_CORRECTION_ABORT); + else if (sblock->nr_retry) + bio_set_flag(bio, BIO_CORRECTION_RETRY); +#endif /* MY_ABC_HERE */ if (btrfsic_submit_bio_wait(bio)) { page->io_error = 1; sblock->no_io_error_seen = 0; } +#ifdef MY_ABC_HERE + if (bio_flagged(bio, BIO_CORRECTION_ERR) && + !page->tried_out) { + page->tried_out = 1; + sblock->page_tried_out++; + } +#endif /* MY_ABC_HERE */ bio_put(bio); } - if (sblock->no_io_error_seen) +#ifdef MY_ABC_HERE + if (sblock->nr_retry == BTRFS_SCRUB_SHOULD_ABORT_RETRY) + sblock->nr_retry = BTRFS_SCRUB_RETRY_ABORTED; + else if (sblock->page_tried_out == sblock->page_count) + sblock->nr_retry = BTRFS_SCRUB_SHOULD_ABORT_RETRY; +#endif /* MY_ABC_HERE */ + + if (sblock->no_io_error_seen +#ifdef MY_ABC_HERE + && sblock->nr_retry <= BTRFS_SCRUB_SHOULD_ABORT_RETRY +#endif /* MY_ABC_HERE */ + ) scrub_recheck_block_checksum(sblock); } @@ -1515,9 +1702,14 @@ static inline int scrub_check_fsid(u8 fsid[], static void scrub_recheck_block_checksum(struct scrub_block *sblock) { - sblock->header_error = 0; - sblock->checksum_error = 0; - sblock->generation_error = 0; +#ifdef MY_ABC_HERE + if (sblock->nr_retry < BTRFS_SCRUB_SHOULD_ABORT_RETRY) +#endif /* MY_ABC_HERE */ + { + sblock->header_error = 0; + sblock->checksum_error = 0; + sblock->generation_error = 0; + } if (sblock->pagev[0]->flags & BTRFS_EXTENT_FLAG_DATA) scrub_checksum_data(sblock); @@ -1525,6 +1717,38 @@ static void scrub_recheck_block_checksum(struct scrub_block *sblock) scrub_checksum_tree_block(sblock); } +#ifdef MY_ABC_HERE +static void scrub_release_retry_on_good_copy(struct scrub_block *sblock) +{ + int page_num; + /* Skip raid56 */ + if (scrub_is_page_on_raid56(sblock->pagev[0])) + return; + + for (page_num = 0; page_num < sblock->page_count; page_num++) { + struct bio *bio; + struct scrub_page *page = sblock->pagev[page_num]; + + if (page->dev->bdev == NULL) { + continue; + } + + WARN_ON(!page->page); + bio = btrfs_io_bio_alloc(1); + bio_set_dev(bio, page->dev->bdev); + + bio_add_page(bio, page->page, PAGE_SIZE, 0); + bio->bi_iter.bi_sector = page->physical >> 9; + bio->bi_opf = REQ_OP_READ; + bio_set_flag(bio, BIO_CORRECTION_ABORT); + + btrfsic_submit_bio_wait(bio); + bio_put(bio); + } + sblock->nr_retry = 0; +} +#endif /* MY_ABC_HERE */ + static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, struct scrub_block *sblock_good) { @@ -1540,6 +1764,10 @@ static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, if (ret_sub) ret = ret_sub; } +#ifdef MY_ABC_HERE + if (sblock_bad != sblock_good && sblock_good->nr_retry) + scrub_release_retry_on_good_copy(sblock_good); +#endif /* MY_ABC_HERE */ return ret; } @@ -1569,6 +1797,11 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, bio_set_dev(bio, page_bad->dev->bdev); bio->bi_iter.bi_sector = page_bad->physical >> 9; bio->bi_opf = REQ_OP_WRITE; +#ifdef MY_ABC_HERE + // So that MD can drop states about this block. + if (sblock_bad->nr_retry) + bio_set_flag(bio, BIO_CORRECTION_ABORT); +#endif /* MY_ABC_HERE */ ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); if (PAGE_SIZE != ret) { @@ -1800,8 +2033,20 @@ static int scrub_checksum_data(struct scrub_block *sblock) crypto_shash_init(shash); crypto_shash_digest(shash, kaddr, PAGE_SIZE, csum); - if (memcmp(csum, spage->csum, sctx->csum_size)) + if (memcmp(csum, spage->csum, sctx->csum_size)) { sblock->checksum_error = 1; +#ifdef MY_ABC_HERE + if (sblock->nr_retry) { + if (sblock->nr_retry != 1 && + !memcmp(csum, sblock->prev_bad_csum, + sctx->csum_size)) + sblock->nr_retry = BTRFS_SCRUB_SHOULD_ABORT_RETRY; + else + memcpy(sblock->prev_bad_csum, csum, + sctx->csum_size); + } +#endif /* MY_ABC_HERE */ + } return sblock->checksum_error; } @@ -1856,8 +2101,20 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) } crypto_shash_final(shash, calculated_csum); - if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) + if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) { sblock->checksum_error = 1; +#ifdef MY_ABC_HERE + if (sblock->nr_retry) { + if (sblock->nr_retry != 1 && + !memcmp(calculated_csum, sblock->prev_bad_csum, + sctx->csum_size)) + sblock->nr_retry = BTRFS_SCRUB_SHOULD_ABORT_RETRY; + else + memcpy(sblock->prev_bad_csum, calculated_csum, + sctx->csum_size); + } +#endif /* MY_ABC_HERE */ + } return sblock->header_error || sblock->checksum_error; } @@ -2983,7 +3240,10 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *csum_root = fs_info->csum_root; struct btrfs_extent_item *extent; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ struct blk_plug plug; +#endif /* MY_ABC_HERE */ u64 flags; int ret; int slot; @@ -3102,7 +3362,10 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, * collect all data csums for the stripe to avoid seeking during * the scrub. This might currently (crc32) end up to be about 1MB */ +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ blk_start_plug(&plug); +#endif /* MY_ABC_HERE */ /* * now find all extents for each stripe and scrub them @@ -3181,6 +3444,15 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, while (1) { u64 bytes; +#ifdef MY_ABC_HERE + if (atomic_read(&fs_info->scrub_cancel_req) || + atomic_read(&sctx->cancel_req)) { + btrfs_release_path(path); + ret = -ECANCELED; + goto out; + } +#endif /* MY_ABC_HERE */ + l = path->nodes[0]; slot = path->slots[0]; if (slot >= btrfs_header_nritems(l)) { @@ -3355,7 +3627,10 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, scrub_wr_submit(sctx); mutex_unlock(&sctx->wr_lock); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ blk_finish_plug(&plug); +#endif /* MY_ABC_HERE */ btrfs_free_path(path); btrfs_free_path(ppath); return ret < 0 ? ret : 0; diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 10f020ab1186..06292094b0e8 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012 Alexander Block. All rights reserved. @@ -15,6 +18,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "send.h" #include "backref.h" @@ -25,6 +31,16 @@ #include "compression.h" #include "xattr.h" +#ifdef MY_ABC_HERE +#include +#include "syno_acl.h" +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ /* * Maximum number of references an extent can have in order for us to attempt to * issue clone operations instead of write operations. This currently exists to @@ -32,6 +48,7 @@ * time and using too much memory for extents with large number of references). */ #define SEND_MAX_EXTENT_REFS 64 +#endif /* MY_ABC_HERE */ /* * A fs_path is a helper to dynamically build path names with unknown size. @@ -75,6 +92,21 @@ struct clone_root { #define SEND_CTX_MAX_NAME_CACHE_SIZE 128 #define SEND_CTX_NAME_CACHE_CLEAN_SIZE (SEND_CTX_MAX_NAME_CACHE_SIZE * 2) +#ifdef MY_ABC_HERE +enum btrfs_send_phase { + SEND_PHASE_STREAM_CHANGES, + SEND_PHASE_COMPUTE_DATA_SIZE, +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +enum archive_bit_act_enum { + archive_bit_act_set = 1 << 0, + archive_bit_act_set_owner_group = 1 << 1, + archive_bit_act_set_acl = 1 << 2, +}; +#endif /* MY_ABC_HERE */ + struct send_ctx { struct file *send_filp; loff_t send_off; @@ -104,6 +136,9 @@ struct send_ctx { int cur_inode_new; int cur_inode_new_gen; int cur_inode_deleted; +#ifdef MY_ABC_HERE + int cur_inode_skip_clone:1; +#endif /* MY_ABC_HERE */ u64 cur_inode_size; u64 cur_inode_mode; u64 cur_inode_rdev; @@ -113,6 +148,21 @@ struct send_ctx { u64 send_progress; +#ifdef MY_ABC_HERE + enum btrfs_send_phase phase; + struct timespec64 write_timeval; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u32 subvol_flags; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u64 skip_cmd_count; + u64 current_cmd_pos; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u32 archive_bit_act; +#endif /* MY_ABC_HERE */ + struct list_head new_refs; struct list_head deleted_refs; @@ -216,6 +266,18 @@ struct send_ctx { * Indexed by the inode number of the directory to be deleted. */ struct rb_root orphan_dirs; + + struct rb_root rbtree_new_refs; + struct rb_root rbtree_deleted_refs; + +#ifdef MY_ABC_HERE + struct { + struct rb_root_cached caches; + struct rb_root_cached caches_by_min_child_distance; + struct rb_root_cached caches_by_remain_childs; + int cache_size; + } syno_new_dir; +#endif /* MY_ABC_HERE */ }; struct pending_dir_move { @@ -238,6 +300,9 @@ struct waiting_dir_move { u64 rmdir_ino; u64 rmdir_gen; bool orphanized; +#ifdef MY_ABC_HERE + u64 gen; +#endif /* MY_ABC_HERE */ }; struct orphan_dir_info { @@ -247,6 +312,23 @@ struct orphan_dir_info { u64 last_dir_index_offset; }; +#ifdef MY_ABC_HERE +#define SEND_CTX_MAX_NEW_DIR_CACHE_SIZE 2048 +#define SEND_CTX_NEW_DIR_CACHE_CLEAN_SIZE (SEND_CTX_MAX_NEW_DIR_CACHE_SIZE * 2) +#define SEND_CTX_NEW_DIR_CACHE_DISTANCE_MIN_THRESHOLD 128ULL +#define SEND_CTX_NEW_DIR_CACHE_DISTANCE_FORCE_THRESHOLD 2048ULL +struct new_dir_cache_info { + struct rb_node node; /* caches */ + struct rb_node min_child_distance_node; /* caches_by_min_child_distance */ + struct rb_node remain_childs_node; /* caches_by_remain_childs */ + u64 ino; + u64 min_child_ino; + u64 min_child_distance; + u64 remain_childs; + bool initialized; +}; +#endif /* MY_ABC_HERE */ + struct name_cache_entry { struct list_head list; /* @@ -268,8 +350,11 @@ struct name_cache_entry { char name[]; }; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ #define ADVANCE 1 #define ADVANCE_ONLY_NEXT -1 +#endif /* MY_ABC_HERE */ enum btrfs_compare_tree_result { BTRFS_COMPARE_TREE_NEW, @@ -312,6 +397,9 @@ static void inconsistent_snapshot_error(struct send_ctx *sctx, sctx->parent_root->root_key.objectid : 0)); } +#ifdef MY_ABC_HERE +static int send_fallocate(struct send_ctx *sctx, u32 flags, u64 offset, u64 len); +#endif /* MY_ABC_HERE */ static int is_waiting_for_move(struct send_ctx *sctx, u64 ino); static struct waiting_dir_move * @@ -546,7 +634,11 @@ static struct btrfs_path *alloc_path_for_send(void) return path; } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off) +#else /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ static int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off) +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ { int ret; u32 pos = 0; @@ -595,6 +687,9 @@ static int tlv_put(struct send_ctx *sctx, u16 attr, const void *data, int len) } TLV_PUT_DEFINE_INT(64) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +TLV_PUT_DEFINE_INT(32) +#endif /* MY_ABC_HERE || MY_ABC_HERE */ static int tlv_put_string(struct send_ctx *sctx, u16 attr, const char *str, int len) @@ -619,6 +714,15 @@ static int tlv_put_btrfs_timespec(struct send_ctx *sctx, u16 attr, return tlv_put(sctx, attr, &bts, sizeof(bts)); } +#ifdef MY_ABC_HERE +static int tlv_put_btrfs_subvol_timespec(struct send_ctx *sctx, u16 attr, + struct btrfs_timespec *ts) +{ + return tlv_put(sctx, attr, ts, sizeof(struct btrfs_timespec)); +} +#endif /* MY_ABC_HERE */ + + #define TLV_PUT(sctx, attrtype, data, attrlen) \ do { \ @@ -663,6 +767,14 @@ static int tlv_put_btrfs_timespec(struct send_ctx *sctx, u16 attr, if (ret < 0) \ goto tlv_put_failure; \ } while (0) +#ifdef MY_ABC_HERE +#define TLV_PUT_BTRFS_SUBVOL_TIMESPEC(sctx, attrtype, ts) \ + do { \ + ret = tlv_put_btrfs_subvol_timespec(sctx, attrtype, ts); \ + if (ret < 0) \ + goto tlv_put_failure; \ + } while (0) +#endif /* MY_ABC_HERE */ static int send_header(struct send_ctx *sctx) { @@ -694,6 +806,30 @@ static int begin_cmd(struct send_ctx *sctx, int cmd) return 0; } +#ifdef MY_ABC_HERE +static int write_calculate_size_if_needed(struct send_ctx *sctx) +{ + int ret = 0; + struct timespec64 now; + unsigned long val; + char *buf_skip_hdr; + u32 buf_max_size; + + ktime_get_ts64(&now); + // Get milliseconds + val = ((now.tv_sec - sctx->write_timeval.tv_sec) * 1000); + val += ((now.tv_nsec - sctx->write_timeval.tv_nsec) / 1000000); + if (val > 800) { + buf_skip_hdr = sctx->send_buf + sizeof(struct btrfs_cmd_header); + buf_max_size = sctx->send_max_size - sizeof(struct btrfs_cmd_header); + snprintf(buf_skip_hdr, buf_max_size, "About:%llu\n", sctx->total_send_size); + ret = write_buf(sctx->send_filp, buf_skip_hdr, strlen(buf_skip_hdr), &sctx->send_off); + sctx->write_timeval = now; + } + return ret; +} +#endif /* MY_ABC_HERE */ + static int send_cmd(struct send_ctx *sctx) { int ret; @@ -701,6 +837,25 @@ static int send_cmd(struct send_ctx *sctx) u32 crc; hdr = (struct btrfs_cmd_header *)sctx->send_buf; + +#ifdef MY_ABC_HERE + if (sctx->current_cmd_pos < sctx->skip_cmd_count && + (le16_to_cpu(hdr->cmd) != BTRFS_SEND_C_SUBVOL) && + (le16_to_cpu(hdr->cmd) != BTRFS_SEND_C_SNAPSHOT)) { + sctx->current_cmd_pos++; + sctx->send_size = 0; + return 0; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) { + sctx->total_send_size += sctx->send_size; + sctx->cmd_send_size[get_unaligned_le16(&hdr->cmd)] += sctx->send_size; + sctx->send_size = 0; // reset send_buf + return write_calculate_size_if_needed(sctx); + } +#endif /* MY_ABC_HERE */ + put_unaligned_le32(sctx->send_size - sizeof(*hdr), &hdr->len); put_unaligned_le32(0, &hdr->crc); @@ -813,17 +968,32 @@ static int send_rmdir(struct send_ctx *sctx, struct fs_path *path) return ret; } +struct btrfs_inode_info { + u64 size; + u64 gen; + u64 mode; + u64 uid; + u64 gid; + u64 rdev; + u64 fileattr; + u64 nlink; +}; + /* * Helper function to retrieve some fields from an inode item. */ -static int __get_inode_info(struct btrfs_root *root, struct btrfs_path *path, - u64 ino, u64 *size, u64 *gen, u64 *mode, u64 *uid, - u64 *gid, u64 *rdev) +static int get_inode_info(struct btrfs_root *root, u64 ino, + struct btrfs_inode_info *info) { int ret; + struct btrfs_path *path; struct btrfs_inode_item *ii; struct btrfs_key key; + path = alloc_path_for_send(); + if (!path) + return -ENOMEM; + key.objectid = ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; @@ -831,41 +1001,43 @@ static int __get_inode_info(struct btrfs_root *root, struct btrfs_path *path, if (ret) { if (ret > 0) ret = -ENOENT; - return ret; + goto out; } + if (!info) + goto out; + ii = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); - if (size) - *size = btrfs_inode_size(path->nodes[0], ii); - if (gen) - *gen = btrfs_inode_generation(path->nodes[0], ii); - if (mode) - *mode = btrfs_inode_mode(path->nodes[0], ii); - if (uid) - *uid = btrfs_inode_uid(path->nodes[0], ii); - if (gid) - *gid = btrfs_inode_gid(path->nodes[0], ii); - if (rdev) - *rdev = btrfs_inode_rdev(path->nodes[0], ii); + info->size = btrfs_inode_size(path->nodes[0], ii); + info->gen = btrfs_inode_generation(path->nodes[0], ii); + info->mode = btrfs_inode_mode(path->nodes[0], ii); + info->uid = btrfs_inode_uid(path->nodes[0], ii); + info->gid = btrfs_inode_gid(path->nodes[0], ii); + info->rdev = btrfs_inode_rdev(path->nodes[0], ii); + info->nlink = btrfs_inode_nlink(path->nodes[0], ii); + /* + * Transfer the unchanged u64 value of btrfs_inode_item::flags, that's + * otherwise logically split to 32/32 parts. + */ + info->fileattr = btrfs_inode_flags(path->nodes[0], ii); +out: + btrfs_free_path(path); return ret; } -static int get_inode_info(struct btrfs_root *root, - u64 ino, u64 *size, u64 *gen, - u64 *mode, u64 *uid, u64 *gid, - u64 *rdev) +static int get_inode_gen(struct btrfs_root *root, u64 ino, u64 *gen) { - struct btrfs_path *path; int ret; + struct btrfs_inode_info info; - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid, - rdev); - btrfs_free_path(path); + if (!gen) + return -EPERM; + + ret = get_inode_info(root, ino, &info); + if (!ret) + *gen = info.gen; return ret; } @@ -1196,6 +1368,10 @@ struct backref_ctx { /* Just to check for bugs in backref resolving */ int found_itself; + +#ifdef MY_ABC_HERE + int extent_type; +#endif /* MY_ABC_HERE */ }; static int __clone_root_cmp_bsearch(const void *key, const void *elt) @@ -1226,11 +1402,20 @@ static int __clone_root_cmp_sort(const void *e1, const void *e2) * Called for every backref that is found for the current extent. * Results are collected in sctx->clone_roots->ino/offset/found_refs */ -static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_) +static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_ +#ifdef MY_ABC_HERE + , int extent_type +#endif /* MY_ABC_HERE */ + ) { struct backref_ctx *bctx = ctx_; struct clone_root *found; +#ifdef MY_ABC_HERE + if (extent_type != bctx->extent_type) + return 0; +#endif /* MY_ABC_HERE */ + /* First check if the root is in the list of accepted clone sources */ found = bsearch((void *)(uintptr_t)root, bctx->sctx->clone_roots, bctx->sctx->clone_roots_cnt, @@ -1314,7 +1499,10 @@ static int find_extent_clone(struct send_ctx *sctx, struct clone_root *cur_clone_root; struct btrfs_key found_key; struct btrfs_path *tmp_path; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ struct btrfs_extent_item *ei; +#endif /* MY_ABC_HERE */ int compressed; u32 i; @@ -1348,6 +1536,9 @@ static int find_extent_clone(struct send_ctx *sctx, ret = -ENOENT; goto out; } +#ifdef MY_ABC_HERE + backref_ctx->extent_type = extent_type; +#endif /* MY_ABC_HERE */ compressed = btrfs_file_extent_compression(eb, fi); num_bytes = btrfs_file_extent_num_bytes(eb, fi); @@ -1362,6 +1553,10 @@ static int find_extent_clone(struct send_ctx *sctx, ret = extent_from_logical(fs_info, disk_byte, tmp_path, &found_key, &flags); up_read(&fs_info->commit_root_sem); +#ifdef MY_ABC_HERE + btrfs_release_path(tmp_path); +#else /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ if (ret < 0) goto out; @@ -1370,6 +1565,8 @@ static int find_extent_clone(struct send_ctx *sctx, goto out; } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ ei = btrfs_item_ptr(tmp_path->nodes[0], tmp_path->slots[0], struct btrfs_extent_item); /* @@ -1384,6 +1581,7 @@ static int find_extent_clone(struct send_ctx *sctx, goto out; } btrfs_release_path(tmp_path); +#endif /* MY_ABC_HERE */ /* * Setup the clone roots. @@ -1617,21 +1815,22 @@ static int get_cur_inode_state(struct send_ctx *sctx, u64 ino, u64 gen) int right_ret; u64 left_gen; u64 right_gen; + struct btrfs_inode_info info; - ret = get_inode_info(sctx->send_root, ino, NULL, &left_gen, NULL, NULL, - NULL, NULL); + ret = get_inode_info(sctx->send_root, ino, &info); if (ret < 0 && ret != -ENOENT) goto out; - left_ret = ret; + left_ret = (info.nlink == 0) ? -ENOENT : ret; + left_gen = info.gen; if (!sctx->parent_root) { right_ret = -ENOENT; } else { - ret = get_inode_info(sctx->parent_root, ino, NULL, &right_gen, - NULL, NULL, NULL, NULL); + ret = get_inode_info(sctx->parent_root, ino, &info); if (ret < 0 && ret != -ENOENT) goto out; - right_ret = ret; + right_ret = (info.nlink == 0) ? -ENOENT : ret; + right_gen = info.gen; } if (!left_ret && !right_ret) { @@ -1792,8 +1991,7 @@ static int get_first_ref(struct btrfs_root *root, u64 ino, btrfs_release_path(path); if (dir_gen) { - ret = get_inode_info(root, parent_dir, NULL, dir_gen, NULL, - NULL, NULL, NULL); + ret = get_inode_gen(root, parent_dir, dir_gen); if (ret < 0) goto out; } @@ -1851,6 +2049,10 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, u64 gen; u64 other_inode = 0; u8 other_type = 0; +#ifdef MY_ABC_HERE + struct waiting_dir_move *dm = NULL; +#endif /* MY_ABC_HERE */ + struct btrfs_inode_info info; if (!sctx->parent_root) goto out; @@ -1865,8 +2067,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, * and we can just unlink this entry. */ if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID) { - ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, - NULL, NULL, NULL); + ret = get_inode_gen(sctx->parent_root, dir, &gen); if (ret < 0 && ret != -ENOENT) goto out; if (ret) { @@ -1892,14 +2093,25 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, * overwrite anything at this point in time. */ if (other_inode > sctx->send_progress || - is_waiting_for_move(sctx, other_inode)) { - ret = get_inode_info(sctx->parent_root, other_inode, NULL, - who_gen, who_mode, NULL, NULL, NULL); +#ifdef MY_ABC_HERE + ((dm = get_waiting_dir_move(sctx, other_inode)) != NULL) +#else /* MY_ABC_HERE */ + is_waiting_for_move(sctx, other_inode) +#endif /* MY_ABC_HERE */ + ) { + ret = get_inode_info(sctx->parent_root, other_inode, &info); if (ret < 0) goto out; - ret = 1; *who_ino = other_inode; + *who_gen = info.gen; + *who_mode = info.mode; +#ifdef MY_ABC_HERE + if (dm && dm->gen != *who_gen) { + ret = 0; + goto out; + } +#endif /* MY_ABC_HERE */ } else { ret = 0; } @@ -1933,8 +2145,7 @@ static int did_overwrite_ref(struct send_ctx *sctx, goto out; if (dir != BTRFS_FIRST_FREE_OBJECTID) { - ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL, - NULL, NULL, NULL); + ret = get_inode_gen(sctx->send_root, dir, &gen); if (ret < 0 && ret != -ENOENT) goto out; if (ret) { @@ -1956,8 +2167,7 @@ static int did_overwrite_ref(struct send_ctx *sctx, goto out; } - ret = get_inode_info(sctx->send_root, ow_inode, NULL, &gen, NULL, NULL, - NULL, NULL); + ret = get_inode_gen(sctx->send_root, ow_inode, &gen); if (ret < 0) goto out; @@ -2177,7 +2387,7 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx, /* * If the inode is not existent yet, add the orphan name and return 1. * This should only happen for the parent dir that we determine in - * __record_new_ref + * record_new_ref_if_needed(). */ ret = is_inode_existent(sctx, ino, gen); if (ret < 0) @@ -2355,6 +2565,9 @@ static int send_subvol_begin(struct send_ctx *sctx) struct extent_buffer *leaf; char *name = NULL; int namelen; +#ifdef MY_ABC_HERE + struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; +#endif /* MY_ABC_HERE */ path = btrfs_alloc_path(); if (!path) @@ -2412,6 +2625,10 @@ static int send_subvol_begin(struct send_ctx *sctx) TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, le64_to_cpu(sctx->send_root->root_item.ctransid)); +#ifdef MY_ABC_HERE + if (likely(sctx->flags & BTRFS_SEND_FLAG_SYNO_FEATURES)) + TLV_PUT_BTRFS_SUBVOL_TIMESPEC(sctx, BTRFS_SEND_A_OTIME, &sctx->send_root->root_item.otime); +#endif /* MY_ABC_HERE */ if (parent_root) { if (!btrfs_is_empty_uuid(parent_root->root_item.received_uuid)) TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, @@ -2425,6 +2642,20 @@ static int send_subvol_begin(struct send_ctx *sctx) ret = send_cmd(sctx); +#ifdef MY_ABC_HERE + if (!ret && !parent_root && + likely(sctx->flags & BTRFS_SEND_FLAG_SYNO_FEATURES)) { + ret = begin_cmd(sctx, BTRFS_SEND_C_SUBVOL_FLAG); + if (ret < 0) + goto out; + btrfs_debug(fs_info, "btrfs: send_flag %u\n", sctx->subvol_flags); + TLV_PUT_U32(sctx, BTRFS_SEND_A_FLAG, sctx->subvol_flags); + ret = send_cmd(sctx); + if (ret < 0) + goto out; + } +#endif /* MY_ABC_HERE */ + tlv_put_failure: out: btrfs_free_path(path); @@ -2593,6 +2824,7 @@ static int send_create_inode(struct send_ctx *sctx, u64 ino) int ret = 0; struct fs_path *p; int cmd; + struct btrfs_inode_info info; u64 gen; u64 mode; u64 rdev; @@ -2604,10 +2836,12 @@ static int send_create_inode(struct send_ctx *sctx, u64 ino) return -ENOMEM; if (ino != sctx->cur_ino) { - ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, - NULL, NULL, &rdev); + ret = get_inode_info(sctx->send_root, ino, &info); if (ret < 0) goto out; + gen = info.gen; + mode = info.mode; + rdev = info.rdev; } else { gen = sctx->cur_inode_gen; mode = sctx->cur_inode_mode; @@ -2667,6 +2901,173 @@ static int send_create_inode(struct send_ctx *sctx, u64 ino) return ret; } +#ifdef MY_ABC_HERE +static int new_dir_cache_info_comp(const void *key, const struct rb_node *node) +{ + const struct new_dir_cache_info *entry, *exist; + + entry = key; + exist = rb_entry(node, struct new_dir_cache_info, node); + + if (entry->ino < exist->ino) + return -1; + if (entry->ino > exist->ino) + return 1; + return 0; +} + +static bool new_dir_cache_info_entry_less(struct rb_node *node, const struct rb_node *parent) +{ + const struct new_dir_cache_info *entry; + + entry = rb_entry(node, struct new_dir_cache_info, node); + + return new_dir_cache_info_comp(entry, parent) < 0; +} + +static bool new_dir_cache_info_entry_less_by_min_child_distance(struct rb_node *node, const struct rb_node *parent) +{ + const struct new_dir_cache_info *entry, *exist; + + entry = rb_entry(node, struct new_dir_cache_info, min_child_distance_node); + exist = rb_entry(parent, struct new_dir_cache_info, min_child_distance_node); + + if (entry->min_child_distance != exist->min_child_distance) + return entry->min_child_distance < exist->min_child_distance; + return entry->ino < exist->ino; +} + +static bool new_dir_cache_info_entry_less_by_remain_childs(struct rb_node *node, const struct rb_node *parent) +{ + const struct new_dir_cache_info *entry, *exist; + + entry = rb_entry(node, struct new_dir_cache_info, remain_childs_node); + exist = rb_entry(parent, struct new_dir_cache_info, remain_childs_node); + + if (entry->remain_childs != exist->remain_childs) + return entry->remain_childs < exist->remain_childs; + return entry->ino < exist->ino; +} + +static void free_new_dir_cache_info(struct send_ctx *sctx, struct new_dir_cache_info *entry) +{ + if (!entry) + return; + sctx->syno_new_dir.cache_size--; + WARN_ON_ONCE(RB_EMPTY_NODE(&entry->node)); + if (!RB_EMPTY_NODE(&entry->node)) { + rb_erase_cached(&entry->node, &sctx->syno_new_dir.caches); + RB_CLEAR_NODE(&entry->node); + } + if (!RB_EMPTY_NODE(&entry->min_child_distance_node)) { + rb_erase_cached(&entry->min_child_distance_node, &sctx->syno_new_dir.caches_by_min_child_distance); + RB_CLEAR_NODE(&entry->min_child_distance_node); + } + if (!RB_EMPTY_NODE(&entry->remain_childs_node)) { + rb_erase_cached(&entry->remain_childs_node, &sctx->syno_new_dir.caches_by_remain_childs); + RB_CLEAR_NODE(&entry->remain_childs_node); + } + kfree(entry); +} + +static struct new_dir_cache_info* get_new_dir_cache_info(struct send_ctx *sctx, u64 dir_ino) +{ + struct rb_node *node; + struct new_dir_cache_info *entry = NULL, cmp; + + cmp.ino = dir_ino; + node = rb_find(&cmp, &sctx->syno_new_dir.caches.rb_root, new_dir_cache_info_comp); + if (node) + entry = rb_entry(node, struct new_dir_cache_info, node); + return entry; +} + +static void new_dir_cache_clean_unused(struct send_ctx *sctx) +{ + struct rb_node *node; + struct new_dir_cache_info *entry; + + if (sctx->syno_new_dir.cache_size < SEND_CTX_NEW_DIR_CACHE_CLEAN_SIZE) + return; + + /* free processed dir */ + while ((node = rb_first_cached(&sctx->syno_new_dir.caches))) { + entry = rb_entry(node, struct new_dir_cache_info, node); + if (entry->ino > sctx->send_progress) + break; + free_new_dir_cache_info(sctx, entry); + } + + while (sctx->syno_new_dir.cache_size > SEND_CTX_MAX_NEW_DIR_CACHE_SIZE) { + node = rb_first_cached(&sctx->syno_new_dir.caches_by_min_child_distance); + if (node) { + entry = rb_entry(node, struct new_dir_cache_info, min_child_distance_node); + if (entry->min_child_distance > SEND_CTX_NEW_DIR_CACHE_DISTANCE_FORCE_THRESHOLD) + break; + free_new_dir_cache_info(sctx, entry); + } else { + break; + } + } + + while (sctx->syno_new_dir.cache_size > SEND_CTX_MAX_NEW_DIR_CACHE_SIZE) { + node = rb_first_cached(&sctx->syno_new_dir.caches_by_remain_childs); + if (node) { + entry = rb_entry(node, struct new_dir_cache_info, remain_childs_node); + free_new_dir_cache_info(sctx, entry); + } else { + break; + } + } +} + +static struct new_dir_cache_info* add_new_dir_cache_info(struct send_ctx *sctx, u64 dir_ino) +{ + struct new_dir_cache_info *entry, *new; + + entry = get_new_dir_cache_info(sctx, dir_ino); + if (entry) + return entry; + + new = kzalloc(sizeof(*new), GFP_NOFS); + if (!new) + return ERR_PTR(-ENOMEM); + RB_CLEAR_NODE(&new->node); + RB_CLEAR_NODE(&new->min_child_distance_node); + RB_CLEAR_NODE(&new->remain_childs_node); + new->ino = dir_ino; + + new_dir_cache_clean_unused(sctx); + + rb_add_cached(&new->node, &sctx->syno_new_dir.caches, new_dir_cache_info_entry_less); + sctx->syno_new_dir.cache_size++; + return new; +} + +static void relink_new_dir_cache_info(struct send_ctx *sctx, struct new_dir_cache_info *entry) +{ + if (RB_EMPTY_NODE(&entry->min_child_distance_node)) + rb_add_cached(&entry->min_child_distance_node, &sctx->syno_new_dir.caches_by_min_child_distance, new_dir_cache_info_entry_less_by_min_child_distance); + + if (!RB_EMPTY_NODE(&entry->remain_childs_node)) { + rb_erase_cached(&entry->remain_childs_node, &sctx->syno_new_dir.caches_by_remain_childs); + RB_CLEAR_NODE(&entry->remain_childs_node); + } + rb_add_cached(&entry->remain_childs_node, &sctx->syno_new_dir.caches_by_remain_childs, new_dir_cache_info_entry_less_by_remain_childs); +} + +static void new_dir_cache_free(struct send_ctx *sctx) +{ + struct rb_node *node; + struct new_dir_cache_info *entry; + + while ((node = rb_first_cached(&sctx->syno_new_dir.caches))) { + entry = rb_entry(node, struct new_dir_cache_info, node); + free_new_dir_cache_info(sctx, entry); + } +} +#endif /* MY_ABC_HERE */ + /* * We need some special handling for inodes that get processed before the parent * directory got created. See process_recorded_refs for details. @@ -2682,6 +3083,35 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir) struct extent_buffer *eb; struct btrfs_dir_item *di; int slot; +#ifdef MY_ABC_HERE + u64 distance = 0; + u64 min_child_ino = -1; + u64 min_child_distance = 0; + u64 remain_childs = 0; + struct new_dir_cache_info* ndci; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ndci = get_new_dir_cache_info(sctx, dir); + WARN_ON_ONCE(ndci && !ndci->initialized); + if (ndci && ndci->initialized) { + ret = 0; + if (ndci->min_child_ino < sctx->send_progress) + ret = 1; + else + btrfs_warn(sctx->send_root->fs_info, "unexpected dir(%llu) min_child_ino(%llu) >= send_progress(%llu)", dir, ndci->min_child_ino, sctx->send_progress); + if (ndci->remain_childs) { + ndci->remain_childs--; + relink_new_dir_cache_info(sctx, ndci); + } + if (dir <= sctx->send_progress) { + free_new_dir_cache_info(sctx, ndci); + ndci = NULL; + } + goto out; + } + ndci = NULL; +#endif /* MY_ABC_HERE */ path = alloc_path_for_send(); if (!path) { @@ -2720,6 +3150,19 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir) di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item); btrfs_dir_item_key_to_cpu(eb, di, &di_key); +#ifdef MY_ABC_HERE + distance++; + if (di_key.type != BTRFS_ROOT_ITEM_KEY) { + if (min_child_ino > di_key.objectid) { + min_child_ino = di_key.objectid; + min_child_distance = distance; + } + if (di_key.objectid < dir && + di_key.objectid > sctx->send_progress) + remain_childs++; + } +#endif /* MY_ABC_HERE */ + if (di_key.type != BTRFS_ROOT_ITEM_KEY && di_key.objectid < sctx->send_progress) { ret = 1; @@ -2730,6 +3173,22 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir) } out: +#ifdef MY_ABC_HERE + if (ret >= 0) { + if (min_child_distance > SEND_CTX_NEW_DIR_CACHE_DISTANCE_MIN_THRESHOLD && + dir > sctx->send_progress) { + ndci = add_new_dir_cache_info(sctx, dir); + if (!IS_ERR(ndci)) { + ndci->min_child_ino = min_child_ino; + ndci->min_child_distance = min_child_distance; + ndci->remain_childs = 1 + remain_childs; /* 1 for dir */ + ndci->initialized = true; + relink_new_dir_cache_info(sctx, ndci); + } + } + } +#endif /* MY_ABC_HERE */ + btrfs_free_path(path); return ret; } @@ -2769,8 +3228,33 @@ struct recorded_ref { u64 dir; u64 dir_gen; int name_len; + struct rb_node node; + struct rb_root *root; }; +static struct recorded_ref *recorded_ref_alloc(void) +{ + struct recorded_ref *ref; + + ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) + return NULL; + RB_CLEAR_NODE(&ref->node); + INIT_LIST_HEAD(&ref->list); + return ref; +} + +static void recorded_ref_free(struct recorded_ref *ref) +{ + if (!ref) + return; + if (!RB_EMPTY_NODE(&ref->node)) + rb_erase(&ref->node, ref->root); + list_del(&ref->list); + fs_path_free(ref->full_path); + kfree(ref); +} + static void set_ref_path(struct recorded_ref *ref, struct fs_path *path) { ref->full_path = path; @@ -2778,39 +3262,16 @@ static void set_ref_path(struct recorded_ref *ref, struct fs_path *path) ref->name_len = ref->full_path->end - ref->name; } -/* - * We need to process new refs before deleted refs, but compare_tree gives us - * everything mixed. So we first record all refs and later process them. - * This function is a helper to record one ref. - */ -static int __record_ref(struct list_head *head, u64 dir, - u64 dir_gen, struct fs_path *path) -{ - struct recorded_ref *ref; - - ref = kmalloc(sizeof(*ref), GFP_KERNEL); - if (!ref) - return -ENOMEM; - - ref->dir = dir; - ref->dir_gen = dir_gen; - set_ref_path(ref, path); - list_add_tail(&ref->list, head); - return 0; -} - static int dup_ref(struct recorded_ref *ref, struct list_head *list) { struct recorded_ref *new; - new = kmalloc(sizeof(*ref), GFP_KERNEL); + new = recorded_ref_alloc(); if (!new) return -ENOMEM; new->dir = ref->dir; new->dir_gen = ref->dir_gen; - new->full_path = NULL; - INIT_LIST_HEAD(&new->list); list_add_tail(&new->list, list); return 0; } @@ -2821,9 +3282,7 @@ static void __free_recorded_refs(struct list_head *head) while (!list_empty(head)) { cur = list_entry(head->next, struct recorded_ref, list); - fs_path_free(cur->full_path); - list_del(&cur->list); - kfree(cur); + recorded_ref_free(cur); } } @@ -3036,7 +3495,11 @@ static int is_waiting_for_move(struct send_ctx *sctx, u64 ino) return entry != NULL; } -static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized) +static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized +#ifdef MY_ABC_HERE + , u64 gen +#endif /* MY_ABC_HERE */ + ) { struct rb_node **p = &sctx->waiting_dir_moves.rb_node; struct rb_node *parent = NULL; @@ -3049,6 +3512,9 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized) dm->rmdir_ino = 0; dm->rmdir_gen = 0; dm->orphanized = orphanized; +#ifdef MY_ABC_HERE + dm->gen = gen; +#endif /* MY_ABC_HERE */ while (*p) { parent = *p; @@ -3144,7 +3610,11 @@ static int add_pending_dir_move(struct send_ctx *sctx, goto out; } +#ifdef MY_ABC_HERE + ret = add_waiting_dir_move(sctx, pm->ino, is_orphan, pm->gen); +#else /* MY_ABC_HERE */ ret = add_waiting_dir_move(sctx, pm->ino, is_orphan); +#endif /* MY_ABC_HERE */ if (ret) goto out; @@ -3343,8 +3813,7 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) /* * The parent inode might have been deleted in the send snapshot */ - ret = get_inode_info(sctx->send_root, cur->dir, NULL, - NULL, NULL, NULL, NULL, NULL); + ret = get_inode_info(sctx->send_root, cur->dir, NULL); if (ret == -ENOENT) { ret = 0; continue; @@ -3518,12 +3987,10 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx, goto out; } - ret = get_inode_info(sctx->parent_root, di_key.objectid, NULL, - &left_gen, NULL, NULL, NULL, NULL); + ret = get_inode_gen(sctx->parent_root, di_key.objectid, &left_gen); if (ret < 0) goto out; - ret = get_inode_info(sctx->send_root, di_key.objectid, NULL, - &right_gen, NULL, NULL, NULL, NULL); + ret = get_inode_gen(sctx->send_root, di_key.objectid, &right_gen); if (ret < 0) { if (ret == -ENOENT) ret = 0; @@ -3666,8 +4133,7 @@ static int is_ancestor(struct btrfs_root *root, cur_offset = item_size; } - ret = get_inode_info(root, parent, NULL, &parent_gen, - NULL, NULL, NULL, NULL); + ret = get_inode_gen(root, parent, &parent_gen); if (ret < 0) goto out; ret = check_ino_in_path(root, ino1, ino1_gen, @@ -3755,9 +4221,7 @@ static int wait_for_parent_move(struct send_ctx *sctx, memcmp(path_before->start, path_after->start, len1))) { u64 parent_ino_gen; - ret = get_inode_info(sctx->parent_root, ino, NULL, - &parent_ino_gen, NULL, NULL, NULL, - NULL); + ret = get_inode_gen(sctx->parent_root, ino, &parent_ino_gen); if (ret < 0) goto out; if (ino_gen == parent_ino_gen) { @@ -4351,54 +4815,139 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) return ret; } -static int record_ref(struct btrfs_root *root, u64 dir, struct fs_path *name, - void *ctx, struct list_head *refs) +static int rbtree_ref_comp(const void *k, const struct rb_node *node) +{ + const struct recorded_ref *data = k; + const struct recorded_ref *ref = rb_entry(node, struct recorded_ref, node); + int result; + + if (data->dir > ref->dir) + return 1; + if (data->dir < ref->dir) + return -1; + if (data->dir_gen > ref->dir_gen) + return 1; + if (data->dir_gen < ref->dir_gen) + return -1; + if (data->name_len > ref->name_len) + return 1; + if (data->name_len < ref->name_len) + return -1; + result = strcmp(data->name, ref->name); + if (result > 0) + return 1; + if (result < 0) + return -1; + return 0; +} + +static bool rbtree_ref_less(struct rb_node *node, const struct rb_node *parent) +{ + const struct recorded_ref *entry = rb_entry(node, struct recorded_ref, node); + + return rbtree_ref_comp(entry, parent) < 0; +} + +static int record_ref_in_tree(struct rb_root *root, struct list_head *refs, + struct fs_path *name, u64 dir, u64 dir_gen, + struct send_ctx *sctx) { int ret = 0; - struct send_ctx *sctx = ctx; - struct fs_path *p; - u64 gen; + struct fs_path *path = NULL; + struct recorded_ref *ref = NULL; - p = fs_path_alloc(); - if (!p) - return -ENOMEM; + path = fs_path_alloc(); + if (!path) { + ret = -ENOMEM; + goto out; + } - ret = get_inode_info(root, dir, NULL, &gen, NULL, NULL, - NULL, NULL); + ref = recorded_ref_alloc(); + if (!ref) { + ret = -ENOMEM; + goto out; + } + + ret = get_cur_path(sctx, dir, dir_gen, path); + if (ret < 0) + goto out; + ret = fs_path_add_path(path, name); if (ret < 0) goto out; - ret = get_cur_path(sctx, dir, gen, p); - if (ret < 0) - goto out; - ret = fs_path_add_path(p, name); - if (ret < 0) - goto out; - - ret = __record_ref(refs, dir, gen, p); - + ref->dir = dir; + ref->dir_gen = dir_gen; + set_ref_path(ref, path); + list_add_tail(&ref->list, refs); + rb_add(&ref->node, root, rbtree_ref_less); + ref->root = root; out: - if (ret) - fs_path_free(p); + if (ret) { + if (path && (!ref || !ref->full_path)) + fs_path_free(path); + recorded_ref_free(ref); + } return ret; } -static int __record_new_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) +static int record_new_ref_if_needed(int num, u64 dir, int index, + struct fs_path *name, void *ctx) { + int ret = 0; struct send_ctx *sctx = ctx; - return record_ref(sctx->send_root, dir, name, ctx, &sctx->new_refs); + struct rb_node *node = NULL; + struct recorded_ref data; + struct recorded_ref *ref; + u64 dir_gen; + + ret = get_inode_gen(sctx->send_root, dir, &dir_gen); + if (ret < 0) + goto out; + + data.dir = dir; + data.dir_gen = dir_gen; + set_ref_path(&data, name); + node = rb_find(&data, &sctx->rbtree_deleted_refs, rbtree_ref_comp); + if (node) { + ref = rb_entry(node, struct recorded_ref, node); + recorded_ref_free(ref); + } else { + ret = record_ref_in_tree(&sctx->rbtree_new_refs, + &sctx->new_refs, name, dir, dir_gen, + sctx); + } +out: + return ret; } - -static int __record_deleted_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) +static int record_deleted_ref_if_needed(int num, u64 dir, int index, + struct fs_path *name, void *ctx) { + int ret = 0; struct send_ctx *sctx = ctx; - return record_ref(sctx->parent_root, dir, name, ctx, - &sctx->deleted_refs); + struct rb_node *node = NULL; + struct recorded_ref data; + struct recorded_ref *ref; + u64 dir_gen; + + ret = get_inode_gen(sctx->parent_root, dir, &dir_gen); + if (ret < 0) + goto out; + + data.dir = dir; + data.dir_gen = dir_gen; + set_ref_path(&data, name); + node = rb_find(&data, &sctx->rbtree_new_refs, rbtree_ref_comp); + if (node) { + ref = rb_entry(node, struct recorded_ref, node); + recorded_ref_free(ref); + } else { + ret = record_ref_in_tree(&sctx->rbtree_deleted_refs, + &sctx->deleted_refs, name, dir, + dir_gen, sctx); + } +out: + return ret; } static int record_new_ref(struct send_ctx *sctx) @@ -4406,7 +4955,7 @@ static int record_new_ref(struct send_ctx *sctx) int ret; ret = iterate_inode_ref(sctx->send_root, sctx->left_path, - sctx->cmp_key, 0, __record_new_ref, sctx); + sctx->cmp_key, 0, record_new_ref_if_needed, sctx); if (ret < 0) goto out; ret = 0; @@ -4420,7 +4969,8 @@ static int record_deleted_ref(struct send_ctx *sctx) int ret; ret = iterate_inode_ref(sctx->parent_root, sctx->right_path, - sctx->cmp_key, 0, __record_deleted_ref, sctx); + sctx->cmp_key, 0, record_deleted_ref_if_needed, + sctx); if (ret < 0) goto out; ret = 0; @@ -4429,120 +4979,16 @@ static int record_deleted_ref(struct send_ctx *sctx) return ret; } -struct find_ref_ctx { - u64 dir; - u64 dir_gen; - struct btrfs_root *root; - struct fs_path *name; - int found_idx; -}; - -static int __find_iref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx_) -{ - struct find_ref_ctx *ctx = ctx_; - u64 dir_gen; - int ret; - - if (dir == ctx->dir && fs_path_len(name) == fs_path_len(ctx->name) && - strncmp(name->start, ctx->name->start, fs_path_len(name)) == 0) { - /* - * To avoid doing extra lookups we'll only do this if everything - * else matches. - */ - ret = get_inode_info(ctx->root, dir, NULL, &dir_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - if (dir_gen != ctx->dir_gen) - return 0; - ctx->found_idx = num; - return 1; - } - return 0; -} - -static int find_iref(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *key, - u64 dir, u64 dir_gen, struct fs_path *name) -{ - int ret; - struct find_ref_ctx ctx; - - ctx.dir = dir; - ctx.name = name; - ctx.dir_gen = dir_gen; - ctx.found_idx = -1; - ctx.root = root; - - ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx); - if (ret < 0) - return ret; - - if (ctx.found_idx == -1) - return -ENOENT; - - return ctx.found_idx; -} - -static int __record_changed_new_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) -{ - u64 dir_gen; - int ret; - struct send_ctx *sctx = ctx; - - ret = get_inode_info(sctx->send_root, dir, NULL, &dir_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - - ret = find_iref(sctx->parent_root, sctx->right_path, - sctx->cmp_key, dir, dir_gen, name); - if (ret == -ENOENT) - ret = __record_new_ref(num, dir, index, name, sctx); - else if (ret > 0) - ret = 0; - - return ret; -} - -static int __record_changed_deleted_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) -{ - u64 dir_gen; - int ret; - struct send_ctx *sctx = ctx; - - ret = get_inode_info(sctx->parent_root, dir, NULL, &dir_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - - ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key, - dir, dir_gen, name); - if (ret == -ENOENT) - ret = __record_deleted_ref(num, dir, index, name, sctx); - else if (ret > 0) - ret = 0; - - return ret; -} - static int record_changed_ref(struct send_ctx *sctx) { int ret = 0; ret = iterate_inode_ref(sctx->send_root, sctx->left_path, - sctx->cmp_key, 0, __record_changed_new_ref, sctx); + sctx->cmp_key, 0, record_new_ref_if_needed, sctx); if (ret < 0) goto out; ret = iterate_inode_ref(sctx->parent_root, sctx->right_path, - sctx->cmp_key, 0, __record_changed_deleted_ref, sctx); + sctx->cmp_key, 0, record_deleted_ref_if_needed, sctx); if (ret < 0) goto out; ret = 0; @@ -4574,10 +5020,10 @@ static int process_all_refs(struct send_ctx *sctx, if (cmd == BTRFS_COMPARE_TREE_NEW) { root = sctx->send_root; - cb = __record_new_ref; + cb = record_new_ref_if_needed; } else if (cmd == BTRFS_COMPARE_TREE_DELETED) { root = sctx->parent_root; - cb = __record_deleted_ref; + cb = record_deleted_ref_if_needed; } else { btrfs_err(sctx->send_root->fs_info, "Wrong command %d in process_all_refs", cmd); @@ -4630,6 +5076,21 @@ static int process_all_refs(struct send_ctx *sctx, return ret; } +#ifdef MY_ABC_HERE +#define SYNO_SZK_BTRFS_COMPRESSION XATTR_BTRFS_PREFIX "compression" +#define SYNO_SZV_ZSTD "zstd" +#define SYNO_SZV_LZO "lzo" +inline static int syno_is_zstd_compression(const char *name, int name_len, + const char *data, int data_len) +{ + // check length before compare non-zero end string + return strlen(SYNO_SZK_BTRFS_COMPRESSION) == name_len && + strlen(SYNO_SZV_ZSTD) == data_len && + 0 == strncmp(SYNO_SZK_BTRFS_COMPRESSION, name, strlen(SYNO_SZK_BTRFS_COMPRESSION)) && + 0 == strncmp(SYNO_SZV_ZSTD, data, strlen(SYNO_SZV_ZSTD)); +} + +#endif /* MY_ABC_HERE */ static int send_set_xattr(struct send_ctx *sctx, struct fs_path *path, const char *name, int name_len, @@ -4643,7 +5104,16 @@ static int send_set_xattr(struct send_ctx *sctx, TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, name, name_len); +#ifdef MY_ABC_HERE + if ((sctx->flags & BTRFS_SEND_FLAG_FALLBACK_COMPRESSION) && + syno_is_zstd_compression(name, name_len, data, data_len)) { + TLV_PUT(sctx, BTRFS_SEND_A_XATTR_DATA, SYNO_SZV_LZO, strlen(SYNO_SZV_LZO)); + } else { + TLV_PUT(sctx, BTRFS_SEND_A_XATTR_DATA, data, data_len); + } +#else /* MY_ABC_HERE */ TLV_PUT(sctx, BTRFS_SEND_A_XATTR_DATA, data, data_len); +#endif /* MY_ABC_HERE */ ret = send_cmd(sctx); @@ -4686,6 +5156,51 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key, if (!strncmp(name, XATTR_NAME_CAPS, name_len)) return 0; +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (!(sctx->flags & BTRFS_SEND_FLAG_SYNO_FEATURES) && + name_len >= XATTR_SYNO_PREFIX_LEN && + !strncmp(name, XATTR_SYNO_PREFIX, XATTR_SYNO_PREFIX_LEN)) + return 0; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* + * chmod and chown will clear archive bit acl-related bits + * and acl entries, so we handle these at inode-finishing + * step to avoid losing syno archive bit and acl entries. + * please refer to #264. + */ + if (XATTR_SYNO_ARCHIVE_BIT_LEN == name_len && + !strncmp(name, XATTR_SYNO_ARCHIVE_BIT, name_len)) { + sctx->archive_bit_act |= archive_bit_act_set; + return 0; + } +#ifdef MY_ABC_HERE + if (!strncmp(name, SYNO_ACL_XATTR_ACCESS, name_len)) { + sctx->archive_bit_act |= archive_bit_act_set_acl; + return 0; + } +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* + * Since inode's archive version would be updated every time + * when it's created or modified as super block's archive + * version + 1. So sending this xattr is unnecessary. + */ + if (XATTR_SYNO_ARCHIVE_VERSION_LEN == name_len && + !strncmp(name, XATTR_SYNO_ARCHIVE_VERSION, name_len)) { + return 0; + } + if (XATTR_SYNO_ARCHIVE_VERSION_VOLUME_LEN == name_len && + !strncmp(name, XATTR_SYNO_ARCHIVE_VERSION_VOLUME, name_len)) { + return 0; + } +#endif /* MY_ABC_HERE */ + p = fs_path_alloc(); if (!p) return -ENOMEM; @@ -4726,6 +5241,15 @@ static int __process_deleted_xattr(int num, struct btrfs_key *di_key, struct send_ctx *sctx = ctx; struct fs_path *p; +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + if (!(sctx->flags & BTRFS_SEND_FLAG_SYNO_FEATURES) && + name_len >= XATTR_SYNO_PREFIX_LEN && + !strncmp(name, XATTR_SYNO_PREFIX, XATTR_SYNO_PREFIX_LEN)) + return 0; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + p = fs_path_alloc(); if (!p) return -ENOMEM; @@ -4969,6 +5493,13 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len) if (ret) return ret; +#ifdef MY_ABC_HERE + if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) { + sctx->send_size += len; + return 0; + } +#endif /* MY_ABC_HERE */ + inode = btrfs_iget(fs_info->sb, sctx->cur_ino, root); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -5098,8 +5629,7 @@ static int send_clone(struct send_ctx *sctx, TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); if (clone_root->root == sctx->send_root) { - ret = get_inode_info(sctx->send_root, clone_root->ino, NULL, - &gen, NULL, NULL, NULL, NULL); + ret = get_inode_gen(sctx->send_root, clone_root->ino, &gen); if (ret < 0) goto out; ret = get_cur_path(sctx, clone_root->ino, gen, p); @@ -5171,6 +5701,40 @@ static int send_update_extent(struct send_ctx *sctx, return ret; } +#ifdef MY_ABC_HERE +static int send_fallocate(struct send_ctx *sctx, u32 flags, + u64 offset, u64 len) +{ + struct fs_path *p = NULL; + int ret = 0; + struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; + + ASSERT(sctx->flags & BTRFS_SEND_FLAG_SUPPORT_FALLOCATE); + + btrfs_debug(fs_info, "send_fallocate flags=%u offset=%llu, len=%llu", flags, offset, len); + + p = fs_path_alloc(); + if (!p) + return -ENOMEM; + ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); + if (ret < 0) + goto tlv_put_failure; + + ret = begin_cmd(sctx, BTRFS_SEND_C_FALLOCATE); + if (ret < 0) + goto tlv_put_failure; + TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); + TLV_PUT_U32(sctx, BTRFS_SEND_A_FALLOCATE_FLAGS, flags); + TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); + TLV_PUT_U64(sctx, BTRFS_SEND_A_SIZE, len); + ret = send_cmd(sctx); + +tlv_put_failure: + fs_path_free(p); + return ret; +} +#endif /* MY_ABC_HERE */ + static int send_hole(struct send_ctx *sctx, u64 end) { struct fs_path *p = NULL; @@ -5193,6 +5757,13 @@ static int send_hole(struct send_ctx *sctx, u64 end) */ end = min_t(u64, end, sctx->cur_inode_size); +#ifdef MY_ABC_HERE + if (sctx->flags & BTRFS_SEND_FLAG_SUPPORT_FALLOCATE) { + return send_fallocate(sctx, + BTRFS_SEND_PUNCH_HOLE_FALLOC_FLAGS, offset, end - offset); + } +#endif /* MY_ABC_HERE */ + if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) return send_update_extent(sctx, offset, end - offset); @@ -5240,7 +5811,17 @@ static int send_extent_data(struct send_ctx *sctx, u64 size = min(len - sent, read_size); int ret; +#ifdef MY_ABC_HERE + if (sctx->current_cmd_pos < sctx->skip_cmd_count) { + ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); + if (!ret) + ret = send_cmd(sctx); + } else { + ret = send_write(sctx, offset + sent, size); + } +#else /* MY_ABC_HERE */ ret = send_write(sctx, offset + sent, size); +#endif /* MY_ABC_HERE */ if (ret < 0) return ret; sent += size; @@ -5316,6 +5897,7 @@ static int clone_range(struct send_ctx *sctx, struct btrfs_path *path; struct btrfs_key key; int ret; + struct btrfs_inode_info info; u64 clone_src_i_size = 0; /* @@ -5345,11 +5927,11 @@ static int clone_range(struct send_ctx *sctx, * There are inodes that have extents that lie behind its i_size. Don't * accept clones from these extents. */ - ret = __get_inode_info(clone_root->root, path, clone_root->ino, - &clone_src_i_size, NULL, NULL, NULL, NULL, NULL); + ret = get_inode_info(clone_root->root, clone_root->ino, &info); btrfs_release_path(path); if (ret < 0) goto out; + clone_src_i_size = info.size; /* * We can't send a clone operation for the entire range if we find @@ -5577,10 +6159,38 @@ static int send_write_or_clone(struct send_ctx *sctx, data_offset = btrfs_file_extent_offset(path->nodes[0], ei); ret = clone_range(sctx, clone_root, disk_byte, data_offset, offset, end - offset); +#ifdef MY_ABC_HERE + } else if (sctx->flags & BTRFS_SEND_FLAG_SUPPORT_FALLOCATE) { + struct btrfs_file_extent_item *ei; + u8 type; + u64 disk_byte; + + ei = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_file_extent_item); + type = btrfs_file_extent_type(path->nodes[0], ei); + if (type != BTRFS_FILE_EXTENT_INLINE) + disk_byte = btrfs_file_extent_disk_bytenr(path->nodes[0], ei); + + if (type == BTRFS_FILE_EXTENT_REG && disk_byte == 0) { + ret = send_fallocate(sctx, + BTRFS_SEND_PUNCH_HOLE_FALLOC_FLAGS, offset, end - offset); + } else if (type == BTRFS_FILE_EXTENT_PREALLOC) { + ret = send_fallocate(sctx, + BTRFS_SEND_PUNCH_HOLE_FALLOC_FLAGS, offset, end - offset); + if (ret) + goto out; + ret = send_fallocate(sctx, 0, offset, end - offset); + } else { + ret = send_extent_data(sctx, offset, end - offset); + } +#endif /* MY_ABC_HERE */ } else { ret = send_extent_data(sctx, offset, end - offset); } sctx->cur_inode_next_write_offset = end; +#ifdef MY_ABC_HERE +out: +#endif /* MY_ABC_HERE */ return ret; } @@ -5940,13 +6550,25 @@ static int process_extent(struct send_ctx *sctx, type = btrfs_file_extent_type(path->nodes[0], ei); if (type == BTRFS_FILE_EXTENT_PREALLOC || type == BTRFS_FILE_EXTENT_REG) { - /* - * The send spec does not have a prealloc command yet, - * so just leave a hole for prealloc'ed extents until - * we have enough commands queued up to justify rev'ing - * the send spec. - */ if (type == BTRFS_FILE_EXTENT_PREALLOC) { +#ifdef MY_ABC_HERE + if (sctx->flags & BTRFS_SEND_FLAG_SUPPORT_FALLOCATE) { + u64 len; + u32 flags = 0; + + len = btrfs_file_extent_num_bytes(path->nodes[0], ei); + if (key->offset >= sctx->cur_inode_size) + flags |= BTRFS_SEND_A_FALLOCATE_FLAG_KEEP_SIZE; + ret = send_fallocate(sctx, flags, key->offset, len); + goto out; + } +#endif /* MY_ABC_HERE */ + /* + * The send spec does not have a prealloc command yet, + * so just leave a hole for prealloc'ed extents until + * we have enough commands queued up to justify rev'ing + * the send spec. + */ ret = 0; goto out; } @@ -5959,11 +6581,19 @@ static int process_extent(struct send_ctx *sctx, } } +#ifdef MY_ABC_HERE + if ((sctx->flags & BTRFS_SEND_FLAG_SKIP_FIND_CLONE) || sctx->cur_inode_skip_clone) + goto skip_clone; +#endif /* MY_ABC_HERE */ + ret = find_extent_clone(sctx, path, key->objectid, key->offset, sctx->cur_inode_size, &found_clone); if (ret != -ENOENT && ret < 0) goto out; +#ifdef MY_ABC_HERE +skip_clone: +#endif /* MY_ABC_HERE */ ret = send_write_or_clone(sctx, path, key, found_clone); if (ret) goto out; @@ -6053,9 +6683,116 @@ static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end, return ret; } +#ifdef MY_ABC_HERE +/* + * Handle syno archive bit and syno acl here + */ +static int syno_attribute_handler(struct send_ctx *sctx) +{ + int ret = 0; + struct inode *inode; + struct btrfs_root *root = sctx->send_root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct fs_path *p = NULL; + __le32 archive_bit_le32; +#if defined(MY_ABC_HERE) + size_t data_len = 0; + void* data = NULL; + struct syno_acl *acl = NULL; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!(sctx->flags & BTRFS_SEND_FLAG_SYNO_FEATURES)) + goto out; +#endif /* MY_ABC_HERE */ + + if (!sctx->archive_bit_act) + goto out; + + inode = btrfs_iget(fs_info->sb, sctx->cur_ino, root); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); + goto out; + } + archive_bit_le32 = cpu_to_le32(inode->i_archive_bit); + +#if defined(MY_ABC_HERE) + if ((sctx->archive_bit_act & archive_bit_act_set_owner_group) && + !(inode->i_archive_bit & S2_SYNO_ACL_IS_OWNER_GROUP)) + sctx->archive_bit_act &= ~archive_bit_act_set_owner_group; + + if ((sctx->archive_bit_act & archive_bit_act_set_acl) && + (inode->i_archive_bit & ALL_SYNO_ACL_ARCHIVE)) { + acl = btrfs_get_syno_acl(inode); + if (IS_ERR(acl)) { + ret = PTR_ERR(acl); + goto out_iput; + } + + data_len = syno_acl_to_xattr(acl, NULL, 0); + if (data_len < 0) { + ret = data_len; + goto out_iput; + } + + + data = kmalloc(data_len, GFP_NOFS); + if (!data) { + ret = -ENOMEM; + goto out_iput; + } + + data_len = syno_acl_to_xattr(acl, data, data_len); + if (data_len < 0) { + ret = data_len; + goto out_iput; + } + } +#endif /* MY_ABC_HERE */ + + p = fs_path_alloc(); + if (!p) { + ret = -ENOMEM; + goto out_iput; + } + ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); + if (ret < 0) + goto out_iput; + ret = send_set_xattr(sctx, p, XATTR_SYNO_ARCHIVE_BIT, + XATTR_SYNO_ARCHIVE_BIT_LEN, + (const char *)&archive_bit_le32, + sizeof(archive_bit_le32)); + if (ret < 0) + goto out_iput; + +#ifdef MY_ABC_HERE + if (data_len > 0) { + ret = send_set_xattr(sctx, p, SYNO_ACL_XATTR_ACCESS, + strlen(SYNO_ACL_XATTR_ACCESS), data, data_len); + if (ret < 0) + goto out_iput; + } +#endif /* MY_ABC_HERE */ + +out_iput: + iput(inode); + +out: + fs_path_free(p); +#ifdef MY_ABC_HERE + if (!IS_ERR(acl)) + syno_acl_release(acl); + kfree(data); +#endif /* MY_ABC_HERE */ + + return ret; +} +#endif /* MY_ABC_HERE */ + static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) { int ret = 0; + struct btrfs_inode_info info; u64 left_mode; u64 left_uid; u64 left_gid; @@ -6095,11 +6832,12 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) goto out; if (!at_end && sctx->cmp_key->objectid == sctx->cur_ino) goto out; - - ret = get_inode_info(sctx->send_root, sctx->cur_ino, NULL, NULL, - &left_mode, &left_uid, &left_gid, NULL); + ret = get_inode_info(sctx->send_root, sctx->cur_ino, &info); if (ret < 0) goto out; + left_mode = info.mode; + left_uid = info.uid; + left_gid = info.gid; if (!sctx->parent_root || sctx->cur_inode_new) { need_chown = 1; @@ -6110,11 +6848,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) } else { u64 old_size; - ret = get_inode_info(sctx->parent_root, sctx->cur_ino, - &old_size, NULL, &right_mode, &right_uid, - &right_gid, NULL); + ret = get_inode_info(sctx->parent_root, sctx->cur_ino, &info); if (ret < 0) goto out; + old_size = info.size; + right_mode = info.mode; + right_uid = info.uid; + right_gid = info.gid; if (left_uid != right_uid || left_gid != right_gid) need_chown = 1; @@ -6152,18 +6892,30 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) } if (need_chown) { +#ifdef MY_ABC_HERE + sctx->archive_bit_act |= archive_bit_act_set_owner_group; +#endif /* MY_ABC_HERE */ ret = send_chown(sctx, sctx->cur_ino, sctx->cur_inode_gen, left_uid, left_gid); if (ret < 0) goto out; } if (need_chmod) { +#ifdef MY_ABC_HERE + sctx->archive_bit_act |= archive_bit_act_set_acl; +#endif /* MY_ABC_HERE */ ret = send_chmod(sctx, sctx->cur_ino, sctx->cur_inode_gen, left_mode); if (ret < 0) goto out; } +#ifdef MY_ABC_HERE + ret = syno_attribute_handler(sctx); + if (ret < 0) + goto out; +#endif /* MY_ABC_HERE */ + ret = send_capabilities(sctx); if (ret < 0) goto out; @@ -6193,93 +6945,46 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) return ret; } -struct parent_paths_ctx { - struct list_head *refs; - struct send_ctx *sctx; -}; - -static int record_parent_ref(int num, u64 dir, int index, struct fs_path *name, - void *ctx) +#ifdef MY_ABC_HERE +static int syno_send_check_skip_xattr(struct btrfs_root *root, u64 ino, const char* name) { - struct parent_paths_ctx *ppctx = ctx; - - return record_ref(ppctx->sctx->parent_root, dir, name, ppctx->sctx, - ppctx->refs); -} - -/* - * Issue unlink operations for all paths of the current inode found in the - * parent snapshot. - */ -static int btrfs_unlink_all_paths(struct send_ctx *sctx) -{ - LIST_HEAD(deleted_refs); - struct btrfs_path *path; - struct btrfs_key key; - struct parent_paths_ctx ctx; int ret; + struct btrfs_dir_item *di; + struct btrfs_path *path; - path = alloc_path_for_send(); + path = btrfs_alloc_path(); if (!path) return -ENOMEM; - key.objectid = sctx->cur_ino; - key.type = BTRFS_INODE_REF_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0); - if (ret < 0) + /* lookup the xattr by name */ + di = btrfs_lookup_xattr(NULL, root, path, ino, name, strlen(name), 0); + if (!di) { + ret = 0; + goto out; + } else if (IS_ERR(di)) { + ret = PTR_ERR(di); goto out; - - ctx.refs = &deleted_refs; - ctx.sctx = sctx; - - while (true) { - struct extent_buffer *eb = path->nodes[0]; - int slot = path->slots[0]; - - if (slot >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(sctx->parent_root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(eb, &key, slot); - if (key.objectid != sctx->cur_ino) - break; - if (key.type != BTRFS_INODE_REF_KEY && - key.type != BTRFS_INODE_EXTREF_KEY) - break; - - ret = iterate_inode_ref(sctx->parent_root, path, &key, 1, - record_parent_ref, &ctx); - if (ret < 0) - goto out; - - path->slots[0]++; } - - while (!list_empty(&deleted_refs)) { - struct recorded_ref *ref; - - ref = list_first_entry(&deleted_refs, struct recorded_ref, list); - ret = send_unlink(sctx, ref->full_path); - if (ret < 0) - goto out; - fs_path_free(ref->full_path); - list_del(&ref->list); - kfree(ref); - } - ret = 0; + /* + * DSM#126656 Workaround for ABB set C++ bool true to xattr. + * C++'s sizeof(bool) is implementation-defined and bool's binary + * representation is not specified, so string and bool are mixed up. + * Therefore we let this function return 1 if the xattr is set to simplify + * the flow. + */ + ret = 1; out: btrfs_free_path(path); - if (ret) - __free_recorded_refs(&deleted_refs); return ret; } +#define SYNO_SEND_SKIP_CLONE "btrfs_send_skip_clone" +static int syno_send_skip_clone(struct btrfs_root *root, u64 ino) +{ + return syno_send_check_skip_xattr(root, ino, XATTR_SYNO_PREFIX SYNO_SEND_SKIP_CLONE); +} +#endif /* MY_ABC_HERE */ + static int changed_inode(struct send_ctx *sctx, enum btrfs_compare_tree_result result) { @@ -6289,12 +6994,21 @@ static int changed_inode(struct send_ctx *sctx, struct btrfs_inode_item *right_ii = NULL; u64 left_gen = 0; u64 right_gen = 0; +#ifdef MY_ABC_HERE + u64 mode; +#endif /* MY_ABC_HERE */ sctx->cur_ino = key->objectid; sctx->cur_inode_new_gen = 0; sctx->cur_inode_last_extent = (u64)-1; sctx->cur_inode_next_write_offset = 0; sctx->ignore_cur_inode = false; +#ifdef MY_ABC_HERE + sctx->archive_bit_act = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + sctx->cur_inode_skip_clone = 0; +#endif /* MY_ABC_HERE */ /* * Set send_progress to current inode. This will tell all get_cur_xxx @@ -6310,6 +7024,16 @@ static int changed_inode(struct send_ctx *sctx, struct btrfs_inode_item); left_gen = btrfs_inode_generation(sctx->left_path->nodes[0], left_ii); +#ifdef MY_ABC_HERE + mode = btrfs_inode_mode(sctx->left_path->nodes[0], left_ii); + if (S_ISREG(mode)) { + ret = syno_send_skip_clone(sctx->send_root, sctx->cur_ino); + if (ret < 0) + goto out; + sctx->cur_inode_skip_clone = ret; + ret = 0; + } +#endif /* MY_ABC_HERE */ } else { right_ii = btrfs_item_ptr(sctx->right_path->nodes[0], sctx->right_path->slots[0], @@ -6344,25 +7068,36 @@ static int changed_inode(struct send_ctx *sctx, * file descriptor against it or turning a RO snapshot into RW mode, * keep an open file descriptor against a file, delete it and then * turn the snapshot back to RO mode before using it for a send - * operation. So if we find such cases, ignore the inode and all its - * items completely if it's a new inode, or if it's a changed inode - * make sure all its previous paths (from the parent snapshot) are all - * unlinked and all other the inode items are ignored. + * operation. The former is what the receiver operation does. + * Therefore, if we want to send these snapshots soon after they're + * received, we need to handle orphan inodes as well. Moreover, orphans + * can appear not only in the send snapshot but also in the parent + * snapshot. Here are several cases: + * + * Case 1: BTRFS_COMPARE_TREE_NEW + * | send snapshot | action + * -------------------------------- + * nlink | 0 | ignore + * + * Case 2: BTRFS_COMPARE_TREE_DELETED + * | parent snapshot | action + * ---------------------------------- + * nlink | 0 | as usual + * Note: No unlinks will be sent because there're no paths for it. + * + * Case 3: BTRFS_COMPARE_TREE_CHANGED + * | | parent snapshot | send snapshot | action + * ----------------------------------------------------------------------- + * subcase 1 | nlink | 0 | 0 | ignore + * subcase 2 | nlink | >0 | 0 | new_gen(deletion) + * subcase 3 | nlink | 0 | >0 | new_gen(creation) + * */ - if (result == BTRFS_COMPARE_TREE_NEW || - result == BTRFS_COMPARE_TREE_CHANGED) { - u32 nlinks; - - nlinks = btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii); - if (nlinks == 0) { + if (result == BTRFS_COMPARE_TREE_NEW) { + if (btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii) == 0) { sctx->ignore_cur_inode = true; - if (result == BTRFS_COMPARE_TREE_CHANGED) - ret = btrfs_unlink_all_paths(sctx); goto out; } - } - - if (result == BTRFS_COMPARE_TREE_NEW) { sctx->cur_inode_gen = left_gen; sctx->cur_inode_new = 1; sctx->cur_inode_deleted = 0; @@ -6383,6 +7118,16 @@ static int changed_inode(struct send_ctx *sctx, sctx->cur_inode_mode = btrfs_inode_mode( sctx->right_path->nodes[0], right_ii); } else if (result == BTRFS_COMPARE_TREE_CHANGED) { + u32 new_nlinks, old_nlinks; + + new_nlinks = btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii); + old_nlinks = btrfs_inode_nlink(sctx->right_path->nodes[0], right_ii); + if (new_nlinks == 0 && old_nlinks == 0) { + sctx->ignore_cur_inode = true; + goto out; + } else if (new_nlinks == 0 || old_nlinks == 0) { + sctx->cur_inode_new_gen = 1; + } /* * We need to do some special handling in case the inode was * reported as changed with a changed generation number. This @@ -6409,38 +7154,44 @@ static int changed_inode(struct send_ctx *sctx, /* * Now process the inode as if it was new. */ - sctx->cur_inode_gen = left_gen; - sctx->cur_inode_new = 1; - sctx->cur_inode_deleted = 0; - sctx->cur_inode_size = btrfs_inode_size( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_mode = btrfs_inode_mode( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_rdev = btrfs_inode_rdev( - sctx->left_path->nodes[0], left_ii); - ret = send_create_inode_if_needed(sctx); - if (ret < 0) - goto out; + if (new_nlinks > 0) { + sctx->cur_inode_gen = left_gen; + sctx->cur_inode_new = true; + sctx->cur_inode_deleted = false; + sctx->cur_inode_size = btrfs_inode_size( + sctx->left_path->nodes[0], + left_ii); + sctx->cur_inode_mode = btrfs_inode_mode( + sctx->left_path->nodes[0], + left_ii); + sctx->cur_inode_rdev = btrfs_inode_rdev( + sctx->left_path->nodes[0], + left_ii); + ret = send_create_inode_if_needed(sctx); + if (ret < 0) + goto out; - ret = process_all_refs(sctx, BTRFS_COMPARE_TREE_NEW); - if (ret < 0) - goto out; - /* - * Advance send_progress now as we did not get into - * process_recorded_refs_if_needed in the new_gen case. - */ - sctx->send_progress = sctx->cur_ino + 1; + ret = process_all_refs(sctx, BTRFS_COMPARE_TREE_NEW); + if (ret < 0) + goto out; + /* + * Advance send_progress now as we did not get + * into process_recorded_refs_if_needed in the + * new_gen case. + */ + sctx->send_progress = sctx->cur_ino + 1; - /* - * Now process all extents and xattrs of the inode as if - * they were all new. - */ - ret = process_all_extents(sctx); - if (ret < 0) - goto out; - ret = process_all_new_xattrs(sctx); - if (ret < 0) - goto out; + /* + * Now process all extents and xattrs of the + * inode as if they were all new. + */ + ret = process_all_extents(sctx); + if (ret < 0) + goto out; + ret = process_all_new_xattrs(sctx); + if (ret < 0) + goto out; + } } else { sctx->cur_inode_gen = left_gen; sctx->cur_inode_new = 0; @@ -6557,13 +7308,11 @@ static int dir_changed(struct send_ctx *sctx, u64 dir) u64 orig_gen, new_gen; int ret; - ret = get_inode_info(sctx->send_root, dir, NULL, &new_gen, NULL, NULL, - NULL, NULL); + ret = get_inode_gen(sctx->send_root, dir, &new_gen); if (ret) return ret; - ret = get_inode_info(sctx->parent_root, dir, NULL, &orig_gen, NULL, - NULL, NULL, NULL); + ret = get_inode_gen(sctx->parent_root, dir, &orig_gen); if (ret) return ret; @@ -6623,6 +7372,18 @@ static int changed_cb(struct btrfs_path *left_path, int ret = 0; struct send_ctx *sctx = ctx; +#ifdef MY_ABC_HERE + if (fatal_signal_pending(current)) { + ret = -EINTR; + goto out; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (key->objectid == BTRFS_SYNO_SUBVOL_USAGE_OBJECTID) + return 0; +#endif /* MY_ABC_HERE */ + if (result == BTRFS_COMPARE_TREE_SAME) { if (key->type == BTRFS_INODE_REF_KEY || key->type == BTRFS_INODE_EXTREF_KEY) { @@ -6677,15 +7438,25 @@ static int full_send_tree(struct send_ctx *sctx) struct btrfs_path *path; struct extent_buffer *eb; int slot; +#ifdef MY_ABC_HERE + struct btrfs_key last_key; +#endif /* MY_ABC_HERE */ path = alloc_path_for_send(); if (!path) return -ENOMEM; + path->reada = READA_FORWARD_ALWAYS; key.objectid = BTRFS_FIRST_FREE_OBJECTID; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; +#ifdef MY_ABC_HERE + last_key.objectid = BTRFS_LAST_FREE_OBJECTID + 1; + last_key.type = 0; + last_key.offset = 0; +#endif /* MY_ABC_HERE */ + ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0); if (ret < 0) goto out; @@ -6697,6 +7468,13 @@ static int full_send_tree(struct send_ctx *sctx) slot = path->slots[0]; btrfs_item_key_to_cpu(eb, &key, slot); +#ifdef MY_ABC_HERE + if (btrfs_comp_cpu_keys(&key, &last_key) >= 0) { + ret = 0; + break; + } +#endif /* MY_ABC_HERE */ + ret = changed_cb(path, NULL, &key, BTRFS_COMPARE_TREE_NEW, sctx); if (ret < 0) @@ -6719,15 +7497,35 @@ static int full_send_tree(struct send_ctx *sctx) return ret; } -static int tree_move_down(struct btrfs_path *path, int *level) +static int tree_move_down(struct btrfs_path *path, int *level, u64 reada_min_gen) { struct extent_buffer *eb; + struct extent_buffer *parent = path->nodes[*level]; + int slot = path->slots[*level]; + const int nritems = btrfs_header_nritems(parent); + u64 reada_max; + u64 reada_done = 0; BUG_ON(*level == 0); - eb = btrfs_read_node_slot(path->nodes[*level], path->slots[*level]); + eb = btrfs_read_node_slot(parent, slot); if (IS_ERR(eb)) return PTR_ERR(eb); + /* + * Trigger readahead for the next leaves we will process, so that it is + * very likely that when we need them they are already in memory and we + * will not block on disk IO. For nodes we only do readahead for one, + * since the time window between processing nodes is typically larger. + */ + reada_max = (*level == 1 ? SZ_128K : eb->fs_info->nodesize); + + for (slot++; slot < nritems && reada_done < reada_max; slot++) { + if (btrfs_node_ptr_generation(parent, slot) > reada_min_gen) { + readahead_tree_block(eb->fs_info, btrfs_node_blockptr(parent, slot)); + reada_done += eb->fs_info->nodesize; + } + } + path->nodes[*level - 1] = eb; path->slots[*level - 1] = 0; (*level)--; @@ -6767,14 +7565,18 @@ static int tree_move_next_or_upnext(struct btrfs_path *path, static int tree_advance(struct btrfs_path *path, int *level, int root_level, int allow_down, - struct btrfs_key *key) + struct btrfs_key *key, + u64 reada_min_gen) { int ret; +#ifdef MY_ABC_HERE + struct btrfs_key last_key; +#endif /* MY_ABC_HERE */ if (*level == 0 || !allow_down) { ret = tree_move_next_or_upnext(path, level, root_level); } else { - ret = tree_move_down(path, level); + ret = tree_move_down(path, level, reada_min_gen); } if (ret >= 0) { if (*level == 0) @@ -6783,6 +7585,14 @@ static int tree_advance(struct btrfs_path *path, else btrfs_node_key_to_cpu(path->nodes[*level], key, path->slots[*level]); + +#ifdef MY_ABC_HERE + last_key.objectid = BTRFS_LAST_FREE_OBJECTID + 1; + last_key.type = 0; + last_key.offset = 0; + if (btrfs_comp_cpu_keys(key, &last_key) >= 0) + ret = -1; +#endif /* MY_ABC_HERE */ } return ret; } @@ -6848,6 +7658,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, u64 right_blockptr; u64 left_gen; u64 right_gen; + u64 reada_min_gen; left_path = btrfs_alloc_path(); if (!left_path) { @@ -6927,6 +7738,14 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, ret = -ENOMEM; goto out; } + /* + * Our right root is the parent root, while the left root is the "send" + * root. We know that all new nodes/leaves in the left root must have + * a generation greater than the right root's generation, so we trigger + * readahead for those nodes and leaves of the left root, as we know we + * will need to read them at some point. + */ + reada_min_gen = btrfs_header_generation(right_root->commit_root); up_read(&fs_info->commit_root_sem); if (left_level == 0) @@ -6951,7 +7770,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, ret = tree_advance(left_path, &left_level, left_root_level, advance_left != ADVANCE_ONLY_NEXT, - &left_key); + &left_key, reada_min_gen); if (ret == -1) left_end_reached = ADVANCE; else if (ret < 0) @@ -6962,7 +7781,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, ret = tree_advance(right_path, &right_level, right_root_level, advance_right != ADVANCE_ONLY_NEXT, - &right_key); + &right_key, reada_min_gen); if (ret == -1) right_end_reached = ADVANCE; else if (ret < 0) @@ -7078,6 +7897,7 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, return ret; } + static int send_subvol(struct send_ctx *sctx) { int ret; @@ -7209,6 +8029,15 @@ static void dedupe_in_progress_warn(const struct btrfs_root *root) root->root_key.objectid, root->dedupe_in_progress); } +#ifdef MY_ABC_HERE +static void cleanup_in_progress_warn(const struct btrfs_root *root) +{ + btrfs_warn_rl(root->fs_info, +"cannot use root %llu for send while cleanup on it are in progress (%d in progress)", + root->root_key.objectid, root->syno_orphan_cleanup.cleanup_in_progress); +} +#endif /* MY_ABC_HERE */ + long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) { int ret = 0; @@ -7221,6 +8050,9 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) int clone_sources_to_rollback = 0; size_t alloc_size; int sort_clone_roots = 0; +#ifdef MY_ABC_HERE + unsigned nofs_flag; +#endif /* MY_ABC_HERE */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -7235,6 +8067,13 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) spin_unlock(&send_root->root_item_lock); return -EAGAIN; } +#ifdef MY_ABC_HERE + if (send_root->syno_orphan_cleanup.cleanup_in_progress) { + cleanup_in_progress_warn(send_root); + spin_unlock(&send_root->root_item_lock); + return -EAGAIN; + } +#endif /* MY_ABC_HERE */ send_root->send_in_progress++; spin_unlock(&send_root->root_item_lock); @@ -7273,8 +8112,17 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) INIT_LIST_HEAD(&sctx->deleted_refs); INIT_RADIX_TREE(&sctx->name_cache, GFP_KERNEL); INIT_LIST_HEAD(&sctx->name_cache_list); +#ifdef MY_ABC_HERE + sctx->syno_new_dir.caches = RB_ROOT_CACHED; + sctx->syno_new_dir.caches_by_min_child_distance = RB_ROOT_CACHED; + sctx->syno_new_dir.caches_by_remain_childs = RB_ROOT_CACHED; +#endif /* MY_ABC_HERE */ sctx->flags = arg->flags; +#ifdef MY_ABC_HERE + if (unlikely(!(sctx->flags & BTRFS_SEND_FLAG_SYNO_FEATURES))) + sctx->flags &= ~BTRFS_SEND_GEN_SYNO_CMD_FLAG_MASK; +#endif /* MY_ABC_HERE */ sctx->send_filp = fget(arg->send_fd); if (!sctx->send_filp) { @@ -7283,6 +8131,14 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) } sctx->send_root = send_root; + +#ifdef MY_ABC_HERE + sctx->subvol_flags = BTRFS_I(file_inode(mnt_file))->flags; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + sctx->skip_cmd_count = arg->skip_cmd_count; + sctx->current_cmd_pos = 0; +#endif /* MY_ABC_HERE */ /* * Unlikely but possible, if the subvolume is marked for deletion but * is slow to remove the directory entry, send can still be started @@ -7304,6 +8160,8 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) sctx->pending_dir_moves = RB_ROOT; sctx->waiting_dir_moves = RB_ROOT; sctx->orphan_dirs = RB_ROOT; + sctx->rbtree_new_refs = RB_ROOT; + sctx->rbtree_deleted_refs = RB_ROOT; sctx->clone_roots = kvcalloc(sizeof(*sctx->clone_roots), arg->clone_sources_count + 1, @@ -7352,6 +8210,15 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) ret = -EAGAIN; goto out; } +#ifdef MY_ABC_HERE + if (clone_root->syno_orphan_cleanup.cleanup_in_progress) { + cleanup_in_progress_warn(clone_root); + spin_unlock(&clone_root->root_item_lock); + btrfs_put_root(clone_root); + ret = -EAGAIN; + goto out; + } +#endif /* MY_ABC_HERE */ clone_root->send_in_progress++; spin_unlock(&clone_root->root_item_lock); @@ -7384,6 +8251,14 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) ret = -EAGAIN; goto out; } +#ifdef MY_ABC_HERE + if (sctx->parent_root->syno_orphan_cleanup.cleanup_in_progress) { + cleanup_in_progress_warn(sctx->parent_root); + spin_unlock(&sctx->parent_root->root_item_lock); + ret = -EAGAIN; + goto out; + } +#endif /* MY_ABC_HERE */ spin_unlock(&sctx->parent_root->root_item_lock); } @@ -7420,9 +8295,35 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) fs_info->send_in_progress++; mutex_unlock(&fs_info->balance_mutex); +#ifdef MY_ABC_HERE + /* + * When journal_info is not NULL, we don't use __GFP_FS, + * otherwise it may cause BUG_ON in evict_inode. + */ + nofs_flag = memalloc_nofs_save(); +#endif /* MY_ABC_HERE */ current->journal_info = BTRFS_SEND_TRANS_STUB; + +#ifdef MY_ABC_HERE + if (sctx->flags & BTRFS_SEND_FLAG_CALCULATE_DATA_SIZE) { + sctx->total_send_size = arg->total_data_size; + ktime_get_ts64(&sctx->write_timeval); + sctx->phase = SEND_PHASE_COMPUTE_DATA_SIZE; + } else { + sctx->phase = SEND_PHASE_STREAM_CHANGES; + } +#endif /* MY_ABC_HERE */ + ret = send_subvol(sctx); + +#ifdef MY_ABC_HERE + arg->total_data_size = sctx->total_send_size; +#endif /* MY_ABC_HERE */ + current->journal_info = NULL; +#ifdef MY_ABC_HERE + memalloc_nofs_restore(nofs_flag); +#endif /* MY_ABC_HERE */ mutex_lock(&fs_info->balance_mutex); fs_info->send_in_progress--; mutex_unlock(&fs_info->balance_mutex); @@ -7507,9 +8408,70 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) kvfree(sctx->send_buf); name_cache_free(sctx); +#ifdef MY_ABC_HERE + new_dir_cache_free(sctx); +#endif /* MY_ABC_HERE */ kfree(sctx); } return ret; } + +#ifdef MY_ABC_HERE +static int tree_move_upnext(struct btrfs_path *path, + int *level, int root_level) +{ + int nritems; + + nritems = btrfs_header_nritems(path->nodes[*level]); + do { + if (*level == root_level) + return -1; + path->slots[*level] = 0; + free_extent_buffer(path->nodes[*level]); + path->nodes[*level] = NULL; + (*level)++; + + path->slots[*level]++; + + nritems = btrfs_header_nritems(path->nodes[*level]); + } while (path->slots[*level] >= nritems); + + return 0; +} + +int tree_advance_with_mode(struct btrfs_path *path, int *level, + int root_level, int mode, struct btrfs_key *key) +{ + int ret; +#ifdef MY_ABC_HERE + struct btrfs_key last_key; +#endif /* MY_ABC_HERE */ + + if (mode == ADVANCE_ONLY_UPNEXT) + ret = tree_move_upnext(path, level, root_level); + else if (*level == 0 || mode == ADVANCE_ONLY_NEXT) + ret = tree_move_next_or_upnext(path, level, root_level); + else + ret = tree_move_down(path, level, 0); + + if (ret >= 0) { + if (*level == 0) + btrfs_item_key_to_cpu(path->nodes[*level], key, + path->slots[*level]); + else + btrfs_node_key_to_cpu(path->nodes[*level], key, + path->slots[*level]); + +#ifdef MY_ABC_HERE + last_key.objectid = BTRFS_LAST_FREE_OBJECTID + 1; + last_key.type = 0; + last_key.offset = 0; + if (btrfs_comp_cpu_keys(key, &last_key) >= 0) + ret = -1; +#endif /* MY_ABC_HERE */ + } + return ret; +} +#endif /* MY_ABC_HERE */ diff --git a/fs/btrfs/send.h b/fs/btrfs/send.h index de91488b7cd0..3999fd55a022 100644 --- a/fs/btrfs/send.h +++ b/fs/btrfs/send.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2012 Alexander Block. All rights reserved. @@ -76,6 +79,12 @@ enum btrfs_send_cmd { BTRFS_SEND_C_END, BTRFS_SEND_C_UPDATE_EXTENT, +#ifdef MY_ABC_HERE + BTRFS_SEND_C_SUBVOL_FLAG, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_SEND_C_FALLOCATE, +#endif /* MY_ABC_HERE */ __BTRFS_SEND_C_MAX, }; #define BTRFS_SEND_C_MAX (__BTRFS_SEND_C_MAX - 1) @@ -114,10 +123,25 @@ enum { BTRFS_SEND_A_CLONE_OFFSET, BTRFS_SEND_A_CLONE_LEN, +#ifdef MY_ABC_HERE + BTRFS_SEND_A_FLAG, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_SEND_A_FALLOCATE_FLAGS, +#endif /* MY_ABC_HERE */ __BTRFS_SEND_A_MAX, }; #define BTRFS_SEND_A_MAX (__BTRFS_SEND_A_MAX - 1) +#ifdef MY_ABC_HERE +#define BTRFS_SEND_A_FALLOCATE_FLAG_KEEP_SIZE (1 << 0) +#define BTRFS_SEND_A_FALLOCATE_FLAG_PUNCH_HOLE (1 << 1) + +#define BTRFS_SEND_PUNCH_HOLE_FALLOC_FLAGS \ + (BTRFS_SEND_A_FALLOCATE_FLAG_KEEP_SIZE | \ + BTRFS_SEND_A_FALLOCATE_FLAG_PUNCH_HOLE) +#endif /* MY_ABC_HERE */ + #ifdef __KERNEL__ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg); #endif diff --git a/fs/btrfs/snapshot-size-query.c b/fs/btrfs/snapshot-size-query.c new file mode 100644 index 000000000000..a2510488bc19 --- /dev/null +++ b/fs/btrfs/snapshot-size-query.c @@ -0,0 +1,660 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2021 Synology Inc. 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 v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ +#include +#include +#include "ctree.h" +#include "disk-io.h" +#include "backref.h" +#include "btrfs_inode.h" + +/* send.c */ +extern int write_buf(struct file *filp, const void *buf, u32 len, + loff_t *off); +extern int tree_advance_with_mode(struct btrfs_path *path, int *level, + int root_level, int mode, + struct btrfs_key *key); + +static int snap_entry_cmp(struct btrfs_snapshot_size_entry *e1, + struct btrfs_snapshot_size_entry *e2); +static int snap_entry_insert(struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry **insert, + int replace); +static inline int +snap_entry_check_node_shared(struct btrfs_fs_info *fs_info, + struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry *entry); +static inline bool +snap_entry_check_file_extent(struct btrfs_snapshot_size_entry *entry); +static inline int +snap_entry_find_extent_owner(struct btrfs_fs_info *fs_info, + struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry *entry, + u64 *owner_id); +static inline void +snap_entry_update_usage(struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry *entry, + u64 owner_id, + struct btrfs_ioctl_snapshot_size_query_args *args); + +static inline void free_snapshot_size_ctx(struct btrfs_snapshot_size_ctx *ctx, + u64 snap_count); +static inline struct btrfs_snapshot_size_ctx* +prepare_snapshot_size_ctx(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_snapshot_size_query_args *args); + +static int +show_calculate_progress(struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_ioctl_snapshot_size_query_args *args, + u64 skip_bytes); + +int +btrfs_snapshot_size_query(struct file *file, + struct btrfs_ioctl_snapshot_size_query_args *args) +{ + int i; + int ret = 0; + u64 snap_count = args->snap_count; + struct btrfs_fs_info *fs_info; + struct btrfs_snapshot_size_ctx *ctx; + struct rb_node *node; + struct btrfs_snapshot_size_entry *entry; + + fs_info = BTRFS_I(file_inode(file))->root->fs_info; + ctx = prepare_snapshot_size_ctx(fs_info, args); + if (IS_ERR(ctx)) { + ret = PTR_ERR(ctx); + ctx = NULL; + goto out; + } + + /* + * The loop are composed of 3 parts: + * 1> Check whether the given node is shared or not + * 2> Check shared EXTENT_ITEM and make statistic about the usage + * 3> Travel deeper node + */ + while (!RB_EMPTY_ROOT(&ctx->root)) { + int nritems; + int advance = ADVANCE; + struct extent_buffer *eb; + struct btrfs_snapshot_size_entry *next_entry; + struct rb_node *next_node; + + // DSM#108202: avoid soft lockup + // DSM#111569: check signal and exit if user cancels + if (signal_pending(current)) { + ret = -EINTR; + break; + } + cond_resched(); + + /* + * 1st part: + * Check if the given node is shared or not, that is to say, + * we check whether the node is pointed by subvolumes + * (snapshots) that are not given by ioctl(). The node is + * shared if the callback function returns postive value (>0) + * and we make sure all descendants are shared and it has no + * need of deeper traveling of the tree. + */ + ret = 0; + node = rb_first(&ctx->root); + entry = rb_entry(node, struct btrfs_snapshot_size_entry, + node); + if (entry->level != entry->root_level && + entry->path->slots[entry->level] == 0) { + ret = snap_entry_check_node_shared(fs_info, ctx, + entry); + args->processed_size += + entry->root->fs_info->nodesize; + if (ret < 0) { + goto out; + } else if (ret > 0) { + advance = ADVANCE_ONLY_UPNEXT; + goto advance; + } + } + + /* + * 2nd part: + * All slots in the leaf node are processed at the same time. + * If the slot is not a hole(bytenr ==0) and EXTENT_ITEM is + * only referred by the given subvolumes, the usage of + * subvolume with the largest ID that pointer to it should be + * accumulated. + */ + eb = entry->path->nodes[entry->level]; + nritems = btrfs_header_nritems(eb); + while (entry->level == 0 && + entry->path->slots[entry->level] < nritems) { + u64 owner_id; + + // DSM#108202: avoid soft lockup + // DSM#111569: check signal and exit if user cancels + if (signal_pending(current)) { + ret = -EINTR; + break; + } + cond_resched(); + + btrfs_item_key_to_cpu(entry->path->nodes[0], + &entry->key, + entry->path->slots[0]); + + if (!snap_entry_check_file_extent(entry)) + goto next; + + ret = snap_entry_find_extent_owner(fs_info, ctx, + entry, &owner_id); + if (ret < 0) + goto out; + if (ret == 0) { + snap_entry_update_usage(ctx, entry, owner_id, + args); + } +next: + entry->path->slots[0]++; + } + /* do verbose display */ + if (show_calculate_progress(ctx, args, 100 * 1024 * 1024)) { + ret = -EBADF; + goto out; + } +advance: + /* + * 3rd part: + * Now we've done processing this node, advance the tree node. + * There's a subtlety here: After tree advacne, if there's a + * subvolume whose next node to be processed is the same as + * this node. We'll keep only one subolume to handle this + * node. The other one needs to keep advancing until the next + * node to be processed for that subvolume is not overlapped + * with the existing one. + */ + next_node = rb_next(node); + if (tree_advance_with_mode(entry->path, &entry->level, + entry->root_level, advance, + &entry->key) < 0) { + rb_erase(&entry->node, &ctx->root); + continue; + } + + if (!next_node) + continue; + + next_entry = rb_entry(next_node, + struct btrfs_snapshot_size_entry, node); + /* + * After advance if this entry is still the lowest key in the +  * tree, don't move it out and insert again. Is's just waste + * of time. + */ + if (snap_entry_cmp(entry, next_entry) < 0) + continue; + + rb_erase(&entry->node, &ctx->root); + RB_CLEAR_NODE(&entry->node); + while (snap_entry_insert(ctx, &entry, 1)) { + if (tree_advance_with_mode(entry->path, &entry->level, + entry->root_level, + ADVANCE_ONLY_NEXT, + &entry->key) < 0) { + /* + * This node is not in the tree anymore, so + * don't call rb_erase on it. + */ + break; + } + } + } + + // store the result + i = 0; + node = rb_first(&ctx->snap_roots->root); + while (node) { + struct ulist_node *ulist_node = rb_entry(node, + struct ulist_node, + rb_node); + entry = (struct btrfs_snapshot_size_entry *) ulist_node->aux; + args->id_maps[i].snap_id = ulist_node->val; + args->id_maps[i++].marginal_size = entry->snap_exclusive_size; + node = rb_next(node); + } +out: + free_snapshot_size_ctx(ctx, snap_count); + return ret; +} + +static int snap_entry_cmp(struct btrfs_snapshot_size_entry *e1, + struct btrfs_snapshot_size_entry *e2) +{ + int cmp; + u64 e1_blockptr; + u64 e2_blockptr; + u64 e1_gen; + u64 e2_gen; + + /* + * We process the in the order + * 1. lower key first + * 2. "higher" level first + * 3. lower block bytenr first + */ + cmp = btrfs_comp_cpu_keys(&e1->key, &e2->key); + if (cmp != 0) + return cmp; + if (e1->level > e2->level) + return -1; + if (e1->level < e2->level) + return 1; + if (e1->level != 0) { + e1_blockptr = btrfs_node_blockptr( + e1->path->nodes[e1->level], + e1->path->slots[e1->level]); + e2_blockptr = btrfs_node_blockptr( + e2->path->nodes[e2->level], + e2->path->slots[e2->level]); + e1_gen = btrfs_node_ptr_generation( + e1->path->nodes[e1->level], + e1->path->slots[e1->level]); + e2_gen = btrfs_node_ptr_generation( + e2->path->nodes[e2->level], + e2->path->slots[e2->level]); + if (e1_blockptr == e2_blockptr && + e1_gen == e2_gen) + return 0; + if (e1_blockptr < e2_blockptr) + return -1; + if (e1_blockptr > e2_blockptr) + return 1; + WARN_ON(1); + } else { + e1_blockptr = e1->path->nodes[e1->level]->start; + e2_blockptr = e2->path->nodes[e2->level]->start; + if (e1_blockptr < e2_blockptr) + return -1; + if (e1_blockptr > e2_blockptr) + return 1; + } + return 0; +} + +static int snap_entry_insert(struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry **insert, + int replace) +{ + struct rb_node **p = &ctx->root.rb_node; + struct rb_node *parent_node = NULL; + struct btrfs_snapshot_size_entry *entry; + int cmp = 0; + + while (*p) { + parent_node = *p; + entry = rb_entry(parent_node, + struct btrfs_snapshot_size_entry, node); + + cmp = snap_entry_cmp(*insert, entry); + if (cmp < 0) { + p = &(*p)->rb_left; + } else if (cmp > 0) { + p = &(*p)->rb_right; + } else { + /* + * If the newly added entry shares the same key with + * the existing node in rbtree, and the added entry + * has larger subvolume id. We need to keep that + * entry, and advance the exsiting node in rbtree. If + * this behavior changes, make sure to change all the + * highest_root_id under btrfs_find_shared_root in + * backref.c. + */ + if (replace && (*insert)->root_id > entry->root_id) { + rb_replace_node(parent_node, &(*insert)->node, + &ctx->root); + RB_CLEAR_NODE(parent_node); + *insert = entry; + } + return 1; + } + } + + rb_link_node(&(*insert)->node, parent_node, p); + rb_insert_color(&(*insert)->node, &ctx->root); + return 0; +} + +static inline bool +snap_entry_check_file_extent(struct btrfs_snapshot_size_entry *entry) +{ + bool ret = false; + struct btrfs_file_extent_item *ei; + u8 type; + u64 bytenr; + + if (entry->key.type != BTRFS_EXTENT_DATA_KEY) + goto out; + + ei = btrfs_item_ptr(entry->path->nodes[0], entry->path->slots[0], + struct btrfs_file_extent_item); + + type = btrfs_file_extent_type(entry->path->nodes[0], ei); + if (type != BTRFS_FILE_EXTENT_PREALLOC && + type != BTRFS_FILE_EXTENT_REG) + goto out; + + bytenr = btrfs_file_extent_disk_bytenr(entry->path->nodes[0], ei); + if (bytenr == 0) + goto out; + + ret = true; +out: + return ret; +} + +static inline int +snap_entry_check_node_shared(struct btrfs_fs_info *fs_info, + struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry *entry) +{ + u64 bytenr = entry->path->nodes[entry->level]->start; + u64 parent_bytenr = entry->path->nodes[entry->level+1]->start; + u64 root_objectid = entry->root_id; + u64 inum = entry->key.objectid; + u64 file_offset = entry->key.offset; + u64 datao = 0; + + return btrfs_check_shared_inlist(fs_info, root_objectid, inum, + file_offset, datao, bytenr, + ctx->snap_roots, parent_bytenr, + NULL); +} + +static inline int +snap_entry_find_extent_owner(struct btrfs_fs_info *fs_info, + struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry *entry, + u64 *owner_id) +{ + struct btrfs_file_extent_item *ei = + btrfs_item_ptr(entry->path->nodes[0], + entry->path->slots[0], + struct btrfs_file_extent_item); + u64 bytenr = btrfs_file_extent_disk_bytenr(entry->path->nodes[0], ei); + u64 parent_bytenr = entry->path->nodes[0]->start; + u64 root_objectid = entry->root_id; + u64 inum = entry->key.objectid; + u64 file_offset = entry->key.offset; + u64 datao = btrfs_file_extent_offset(entry->path->nodes[0], ei); + *owner_id = entry->root_id; + + return btrfs_check_shared_inlist(fs_info, root_objectid, inum, + file_offset, datao, bytenr, + ctx->snap_roots, parent_bytenr, + owner_id); +} + +static inline void +snap_entry_update_usage(struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_snapshot_size_entry *entry, + u64 owner_id, + struct btrfs_ioctl_snapshot_size_query_args *args) +{ + struct btrfs_file_extent_item *ei = + btrfs_item_ptr(entry->path->nodes[0], + entry->path->slots[0], + struct btrfs_file_extent_item); + u64 bytes = btrfs_file_extent_disk_num_bytes(entry->path->nodes[0], + ei); + + if (owner_id == entry->root_id) + entry->snap_exclusive_size += bytes; + else { + struct ulist_node *node; + struct btrfs_snapshot_size_entry *counted_entry; + + node = ulist_search(ctx->snap_roots, owner_id); + counted_entry = + (struct btrfs_snapshot_size_entry *) node->aux; + counted_entry->snap_exclusive_size += bytes; + } + + args->calc_size += bytes; +} + +static inline void free_snapshot_size_ctx(struct btrfs_snapshot_size_ctx *ctx, + u64 snap_count) +{ + int i; + + if (!ctx) + return; + + for (i = 0; i < snap_count; i++) { + if (ctx->snaps[i].path) + btrfs_free_path(ctx->snaps[i].path); + if (ctx->snaps[i].root) { + btrfs_put_root(ctx->snaps[i].root); + spin_lock(&ctx->snaps[i].root->root_item_lock); + ctx->snaps[i].root->send_in_progress--; + spin_unlock(&ctx->snaps[i].root->root_item_lock); + } + } + if (ctx->out_filp) + fput(ctx->out_filp); + if (ctx->snap_roots) + ulist_free(ctx->snap_roots); + kvfree(ctx); +} + +static inline struct btrfs_snapshot_size_ctx* +prepare_snapshot_size_ctx(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_snapshot_size_query_args *args) +{ + int i; + int ret = 0; + u64 snap_count = args->snap_count; + struct btrfs_snapshot_size_ctx *ctx; + struct btrfs_root *snap_root; + + ctx = kvzalloc(sizeof(*ctx) + + sizeof(struct btrfs_snapshot_size_entry) * snap_count, + GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto out; + } + + ctx->snap_roots = ulist_alloc(GFP_NOFS); + if (!ctx->snap_roots) { + ret = -ENOMEM; + goto out; + } + + ctx->root = RB_ROOT; + ctx->flags = args->flags; + ctx->out_filp = fget(args->fd); + if (!ctx->out_filp) { + ret = -EBADF; + goto out; + } + + for (i = 0; i < snap_count; ++i) { + int level; + struct btrfs_snapshot_size_entry *entry; + struct extent_buffer *eb; + + ret = ulist_add(ctx->snap_roots, + args->id_maps[i].snap_id, + (u64)(&ctx->snaps[i]), GFP_KERNEL); + if (ret <= 0) { + if (ret == 0) + ret = -EINVAL; + goto out; + } + ret = 0; + + entry = &ctx->snaps[i]; + entry->root_id = args->id_maps[i].snap_id; + + entry->path = btrfs_alloc_path(); + if (!entry->path) { + ret = -ENOMEM; + goto out; + } + + snap_root = btrfs_get_fs_root(fs_info, entry->root_id, true); + if (IS_ERR(snap_root)) { + ret = PTR_ERR(snap_root); + goto out; + } + + spin_lock(&snap_root->root_item_lock); + if (btrfs_root_dead(snap_root) || + !btrfs_root_readonly(snap_root)) { + spin_unlock(&snap_root->root_item_lock); + btrfs_put_root(snap_root); + ret = -EPERM; + goto out; + } + if (snap_root->dedupe_in_progress) { + spin_unlock(&snap_root->root_item_lock); + btrfs_put_root(snap_root); + ret = -EAGAIN; + goto out; + } +#ifdef MY_ABC_HERE + if (snap_root->syno_orphan_cleanup.cleanup_in_progress) { + spin_unlock(&snap_root->root_item_lock); + btrfs_put_root(snap_root); + ret = -EAGAIN; + goto out; + } +#endif /* MY_ABC_HERE */ + snap_root->send_in_progress++; + spin_unlock(&snap_root->root_item_lock); + + down_read(&snap_root->fs_info->commit_root_sem); + eb = btrfs_clone_extent_buffer(snap_root->commit_root); + up_read(&snap_root->fs_info->commit_root_sem); + if (!eb) { + ret = -ENOMEM; + btrfs_put_root(snap_root); + goto out; + } + + level = btrfs_header_level(eb); + entry->root = snap_root; + entry->path->search_commit_root = 1; + entry->path->skip_locking = 1; + entry->root_level = entry->level = level; + entry->path->nodes[level] = eb; + + if (level == 0) + btrfs_item_key_to_cpu(entry->path->nodes[level], + &entry->key, entry->path->slots[level]); + else + btrfs_node_key_to_cpu(entry->path->nodes[level], + &entry->key, entry->path->slots[level]); + + while (snap_entry_insert(ctx, &entry, 0)) { + if (tree_advance_with_mode(entry->path, &entry->level, + entry->root_level, + ADVANCE_ONLY_NEXT, + &entry->key) < 0) { + break; + } + } + } + +out: + if (ret) { + free_snapshot_size_ctx(ctx, snap_count); + return ERR_PTR(ret); + } + return ctx; +} + +static int +show_calculate_progress(struct btrfs_snapshot_size_ctx *ctx, + struct btrfs_ioctl_snapshot_size_query_args *args, + u64 skip_bytes) +{ + int ret = 0; + int len; + char buf[256]; + u64 flags = ctx->flags; + + if (args->calc_size - ctx->last_calc_size < skip_bytes) + goto out; + + if (get_seconds() - ctx->last_show < 2) + goto out; + + if (!(flags & (BTRFS_SNAP_SIZE_SHOW_MARGINAL_SIZE| + BTRFS_SNAP_SIZE_SHOW_EXCL_SIZE| + BTRFS_SNAP_SIZE_SHOW_PROCESSED_SIZE))) + goto out; + + if (flags & BTRFS_SNAP_SIZE_SHOW_MARGINAL_SIZE) { + struct rb_node *node = rb_first(&ctx->snap_roots->root); + + while (node) { + struct ulist_node *lnode = rb_entry(node, + struct ulist_node, + rb_node); + struct btrfs_snapshot_size_entry *entry = + (struct btrfs_snapshot_size_entry *)lnode->aux; + u64 snap_id = lnode->val; + u64 marginal_size = entry->snap_exclusive_size; + + len = snprintf(buf, sizeof(buf), + "subvol(%llu) %llu bytes\n", snap_id, + marginal_size); + ret = write_buf(ctx->out_filp, buf, len, &ctx->off); + if (ret) + goto out; + node = rb_next(node); + } + } + if (flags & BTRFS_SNAP_SIZE_SHOW_EXCL_SIZE) { + /* show exclusize size by each entry*/ + len = snprintf(buf, sizeof(buf), "exclusive %llu bytes\n", + args->calc_size); + ret = write_buf(ctx->out_filp, buf, len, &ctx->off); + if (ret) + goto out; + ctx->last_calc_size = args->calc_size; + } + if (flags & BTRFS_SNAP_SIZE_SHOW_PROCESSED_SIZE) { + len = snprintf(buf, sizeof(buf), "processed %llu bytes\n", + args->processed_size); + ret = write_buf(ctx->out_filp, buf, len, &ctx->off); + if (ret) + goto out; + } + ret = write_buf(ctx->out_filp, "\n", 1, &ctx->off); + if (ret) + goto out; + + ctx->last_show = get_seconds(); +out: + return ret; +} diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index e8347461c8dd..1334cd90b82f 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -1,5 +1,12 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #include "misc.h" #include "ctree.h" #include "space-info.h" @@ -206,6 +213,23 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags) INIT_LIST_HEAD(&space_info->ro_bgs); INIT_LIST_HEAD(&space_info->tickets); INIT_LIST_HEAD(&space_info->priority_tickets); +#ifdef MY_ABC_HERE + spin_lock_init(&space_info->syno_allocator.lock); + init_rwsem(&space_info->syno_allocator.allocation_sem); + space_info->syno_allocator.free_space_bytes = RB_ROOT_CACHED; + space_info->syno_allocator.free_space_max_length = RB_ROOT_CACHED; + space_info->syno_allocator.free_space_max_length_with_extent = RB_ROOT_CACHED; + space_info->syno_allocator.preload = RB_ROOT_CACHED; + mutex_init(&space_info->syno_allocator.syno_allocator_mutex); + space_info->syno_allocator.force_cluster_disable = true; + space_info->syno_allocator.cache_bg = NULL; + space_info->syno_allocator.cache_offset = 0; +#ifdef MY_ABC_HERE + space_info->syno_allocator.log_bg_offset = 0; +#endif /* MY_ABC_HERE */ + atomic64_set(&space_info->syno_allocator.fallback_relink_count, 0); + atomic64_set(&space_info->syno_allocator.fallback_full_scan_count, 0); +#endif /* MY_ABC_HERE */ ret = btrfs_sysfs_add_space_info_type(info, space_info); if (ret) @@ -989,6 +1013,70 @@ static void btrfs_async_reclaim_metadata_space(struct work_struct *work) } while (flush_state <= COMMIT_TRANS); } +#ifdef MY_ABC_HERE +static inline bool need_do_async_syno_reclaim(struct btrfs_fs_info *fs_info, + struct btrfs_space_info *space_info) +{ + bool reclaim = false; + u64 used; + + spin_lock(&space_info->lock); + used = btrfs_space_info_used(space_info, true); + if (need_do_async_reclaim(fs_info, space_info, used)) + reclaim = true; + spin_unlock(&space_info->lock); + return reclaim; +} + +static const enum btrfs_flush_state syno_metadata_flush_states[] = { + FLUSH_DELAYED_REFS, + FLUSH_DELAYED_ITEMS, +}; + +static void btrfs_syno_async_reclaim_metadata_space(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_space_info *space_info; + int flush_state = 0; + unsigned long next_wakeup, cur, delay; + + fs_info = container_of(work, struct btrfs_fs_info, syno_async_metadata_reclaim_work); + space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); + if (!space_info) + goto out; + + next_wakeup = jiffies + msecs_to_jiffies(1000); + while (flush_state < ARRAY_SIZE(syno_metadata_flush_states)) { + flush_space(fs_info, space_info, U64_MAX, syno_metadata_flush_states[flush_state]); + spin_lock(&space_info->lock); + if (!list_empty(&space_info->tickets) || + !list_empty(&space_info->priority_tickets)) { + spin_unlock(&space_info->lock); + goto loop; + } + spin_unlock(&space_info->lock); + if (!need_do_async_syno_reclaim(fs_info, space_info)) + break; +loop: + flush_state++; + if (flush_state >= ARRAY_SIZE(syno_metadata_flush_states)) { + flush_state = 0; + cur = jiffies; + if (time_after(next_wakeup, cur)) { + delay = next_wakeup - cur; + delay = min(delay, msecs_to_jiffies(1000)); + schedule_timeout_interruptible(delay); + } + next_wakeup = jiffies + msecs_to_jiffies(1000); + } + cond_resched(); + } + +out: + return; +} +#endif /* MY_ABC_HERE */ + /* * FLUSH_DELALLOC_WAIT: * Space is freed from flushing delalloc in one of two ways. @@ -1111,10 +1199,267 @@ static void btrfs_async_reclaim_data_space(struct work_struct *work) } } +#ifdef MY_ABC_HERE +/* + * Estimate write bandwidth at 200ms intervals. + */ +#define BANDWIDTH_INTERVAL max(HZ/5, 1) +static void syno_ordered_extent_bw_update(struct btrfs_fs_info *fs_info) +{ + unsigned long now = jiffies; + unsigned long elapsed = now - fs_info->syno_ordered_extent_processed_bw_time_stamp; + u64 processed, bw; + + if (elapsed < BANDWIDTH_INTERVAL) + goto out; + + processed = atomic64_read(&fs_info->syno_ordered_extent_processed_nr); + bw = processed - min(processed, fs_info->syno_ordered_extent_processed_stamp); + bw = bw * HZ; + bw = div64_u64(bw, elapsed); + bw = fs_info->syno_ordered_extent_processed_bw * 3 + bw; + bw = bw >> 2; + + fs_info->syno_ordered_extent_processed_bw = bw; + fs_info->syno_ordered_extent_processed_stamp = processed; + fs_info->syno_ordered_extent_processed_bw_time_stamp = now; +out: + return; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void btrfs_syno_async_data_flush(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_space_info *space_info; + struct btrfs_inode *binode, *first_binode; + struct inode *inode; + struct blk_plug plug; + int nr_retry; + + fs_info = container_of(work, struct btrfs_fs_info, syno_async_data_flush_work); + space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); + if (!space_info) + goto out; + +again: + nr_retry = max(32, (int)fs_info->syno_writeback_thread_max + 1); + first_binode = NULL; + + if (btrfs_fs_closing(fs_info) || test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state)) + goto out; + + if (list_empty(&fs_info->syno_dirty_lru_inodes)) + goto out; + + spin_lock(&fs_info->syno_multiple_writeback_lock); +select_inode: + if (list_empty(&fs_info->syno_dirty_lru_inodes)) { + spin_unlock(&fs_info->syno_multiple_writeback_lock); + goto out; + } + binode = list_first_entry(&fs_info->syno_dirty_lru_inodes, struct btrfs_inode, syno_dirty_lru_inode); + if (first_binode == binode) + nr_retry = 0; + if (!first_binode) + first_binode = binode; + inode = igrab(&binode->vfs_inode); + if (!inode) { + list_del_init(&binode->syno_dirty_lru_inode); + clear_bit(BTRFS_INODE_SYNO_WRITEBACK_LRU_LIST, &binode->runtime_flags); + if (first_binode == binode) + first_binode = NULL; + goto select_inode; + } + spin_lock(&inode->i_lock); + if (inode->i_state & I_SYNC) { + spin_unlock(&inode->i_lock); + iput(inode); + if (nr_retry-- > 0) { + list_move_tail(&binode->syno_dirty_lru_inode, &fs_info->syno_dirty_lru_inodes); + goto select_inode; + } + spin_unlock(&fs_info->syno_multiple_writeback_lock); + goto sleep; + } + inode->i_state |= I_SYNC; + spin_unlock(&inode->i_lock); + + list_move_tail(&BTRFS_I(inode)->syno_dirty_lru_inode, &fs_info->syno_dirty_lru_inodes); + spin_unlock(&fs_info->syno_multiple_writeback_lock); + + blk_start_plug(&plug); + filemap_flush(inode->i_mapping); + blk_finish_plug(&plug); + + spin_lock(&inode->i_lock); + inode_sync_complete(inode); + spin_unlock(&inode->i_lock); + iput(inode); + + cond_resched(); + spin_lock(&space_info->lock); + if (!list_empty(&space_info->tickets) || + !list_empty(&space_info->priority_tickets)) { + spin_unlock(&space_info->lock); +#ifdef MY_ABC_HERE + syno_ordered_extent_bw_update(fs_info); + if (atomic64_read(&fs_info->syno_ordered_extent_nr) < (fs_info->syno_ordered_extent_processed_bw << 1)) + goto again; +#endif /* MY_ABC_HERE */ + goto sleep; + } + spin_unlock(&space_info->lock); + + if (need_do_async_syno_reclaim(fs_info, space_info)) { +#ifdef MY_ABC_HERE + syno_ordered_extent_bw_update(fs_info); + if (atomic64_read(&fs_info->syno_ordered_extent_nr) < (fs_info->syno_ordered_extent_processed_bw << 1)) + goto again; +#endif /* MY_ABC_HERE */ + goto sleep; + } + +out: + return; + +sleep: + schedule_timeout_interruptible(msecs_to_jiffies(1000)); + goto again; +} +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +void syno_perf_indicator_dirty_limit_update(struct btrfs_fs_info *fs_info) +{ + unsigned long now; + unsigned long elapsed; + unsigned long background_thresh, dirty_thresh; + + if (!fs_info) + goto out; + + if (test_and_set_bit(SYNO_PERF_INDICATROT_FLAG_DIRTY_LIMIT_UPDATE, &fs_info->syno_perf_indicator.flags)) + goto out; + + now = jiffies; + elapsed = now - fs_info->syno_perf_indicator.dirty_limit_stamp; + + /* Estimate 1s intervals. */ + if (elapsed < HZ) + goto out_unlock; + + global_dirty_limits(&background_thresh, &dirty_thresh); + fs_info->syno_perf_indicator.dirty_thresh = dirty_thresh; + fs_info->syno_perf_indicator.dirty_background_thresh = background_thresh; + fs_info->syno_perf_indicator.dirty_limit_stamp = now; + +out_unlock: + clear_bit(SYNO_PERF_INDICATROT_FLAG_DIRTY_LIMIT_UPDATE, &fs_info->syno_perf_indicator.flags); +out: + return; +} +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ + +#ifdef MY_ABC_HERE +static bool btrfs_check_need_async_meta_flush(struct btrfs_fs_info *fs_info, bool worker) +{ + bool ret = false; + + if (btrfs_fs_closing(fs_info) || test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state)) + goto out; + + if (!worker && work_busy(&fs_info->syno_async_metadata_flush_work)) + goto out; + + if (!writeback_in_progress(&fs_info->sb->s_bdi->wb)) + goto out; + + if (__percpu_counter_compare(&fs_info->dirty_metadata_bytes, + BTRFS_DIRTY_METADATA_THRESH, fs_info->dirty_metadata_batch) <= 0) + goto out; + + spin_lock(&fs_info->trans_lock); + if (fs_info->running_transaction && + fs_info->running_transaction->state == TRANS_STATE_COMMIT_DOING) { + spin_unlock(&fs_info->trans_lock); + goto out; + } + spin_unlock(&fs_info->trans_lock); + + syno_perf_indicator_dirty_limit_update(fs_info); + if (global_node_page_state(NR_FILE_DIRTY) < fs_info->syno_perf_indicator.dirty_background_thresh) + goto out; + + ret = true; +out: + return ret; +} + +static void btrfs_syno_async_metadata_flush(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + struct blk_plug plug; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .range_cyclic = 1, + }; + + fs_info = container_of(work, struct btrfs_fs_info, syno_async_metadata_flush_work); + +again: + blk_start_plug(&plug); + wbc.nr_to_write = BTRFS_DIRTY_METADATA_THRESH >> (PAGE_SHIFT + 1); + btree_write_cache_pages(fs_info->btree_inode->i_mapping, &wbc); + blk_finish_plug(&plug); + + if (btrfs_check_need_async_meta_flush(fs_info, true)) { + schedule_timeout_interruptible(msecs_to_jiffies(100)); + goto again; + } + schedule_timeout_interruptible(msecs_to_jiffies(1000)); + + return; +} + +void btrfs_syno_btree_balance_dirty(struct btrfs_fs_info *fs_info, bool throttle) +{ + bool async_meta_flush = false; + + async_meta_flush = btrfs_check_need_async_meta_flush(fs_info, false); + if (async_meta_flush) + queue_work(system_unbound_wq, &fs_info->syno_async_metadata_flush_work); + + if (!throttle) + goto out; + + /* if we need async meta flush, we always checked dirty metadata bytes, we skip double check */ + if (!async_meta_flush) { + if (__percpu_counter_compare(&fs_info->dirty_metadata_bytes, + BTRFS_DIRTY_METADATA_THRESH, fs_info->dirty_metadata_batch) <= 0) + goto out; + } + + balance_dirty_pages_ratelimited(fs_info->btree_inode->i_mapping); +out: + return; +} +#endif /* MY_ABC_HERE */ + void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info) { INIT_WORK(&fs_info->async_reclaim_work, btrfs_async_reclaim_metadata_space); INIT_WORK(&fs_info->async_data_reclaim_work, btrfs_async_reclaim_data_space); +#ifdef MY_ABC_HERE + INIT_WORK(&fs_info->syno_async_metadata_reclaim_work, btrfs_syno_async_reclaim_metadata_space); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + INIT_WORK(&fs_info->syno_async_data_flush_work, btrfs_syno_async_data_flush); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + INIT_WORK(&fs_info->syno_async_metadata_flush_work, btrfs_syno_async_metadata_flush); +#endif /* MY_ABC_HERE */ } static const enum btrfs_flush_state priority_flush_states[] = { @@ -1382,6 +1727,19 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info, list_add_tail(&ticket.list, &space_info->priority_tickets); } +#ifdef MY_ABC_HERE + if (space_info->flags & BTRFS_BLOCK_GROUP_METADATA && + !test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags) && + need_do_async_reclaim(fs_info, space_info, used)) { + if (!work_busy(&fs_info->syno_async_metadata_reclaim_work)) + queue_work(system_unbound_wq, &fs_info->syno_async_metadata_reclaim_work); +#ifdef MY_ABC_HERE + if (!work_busy(&fs_info->syno_async_data_flush_work) && + !list_empty(&fs_info->syno_dirty_lru_inodes)) + queue_work(system_unbound_wq, &fs_info->syno_async_data_flush_work); +#endif /* MY_ABC_HERE */ + } +#endif /* MY_ABC_HERE */ } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) { used += orig_bytes; /* @@ -1390,12 +1748,22 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info, * the async reclaim as we will panic. */ if (!test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags) && - need_do_async_reclaim(fs_info, space_info, used) && - !work_busy(&fs_info->async_reclaim_work)) { - trace_btrfs_trigger_flush(fs_info, space_info->flags, + need_do_async_reclaim(fs_info, space_info, used)) { + if (!work_busy(&fs_info->async_reclaim_work)) { + trace_btrfs_trigger_flush(fs_info, space_info->flags, orig_bytes, flush, "preempt"); - queue_work(system_unbound_wq, - &fs_info->async_reclaim_work); + queue_work(system_unbound_wq, + &fs_info->async_reclaim_work); + } +#ifdef MY_ABC_HERE + if (!work_busy(&fs_info->syno_async_metadata_reclaim_work)) + queue_work(system_unbound_wq, &fs_info->syno_async_metadata_reclaim_work); +#ifdef MY_ABC_HERE + if (!work_busy(&fs_info->syno_async_data_flush_work) && + !list_empty(&fs_info->syno_dirty_lru_inodes)) + queue_work(system_unbound_wq, &fs_info->syno_async_data_flush_work); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ } } spin_unlock(&space_info->lock); diff --git a/fs/btrfs/space-info.h b/fs/btrfs/space-info.h index 74706f604bce..2bba19fbf462 100644 --- a/fs/btrfs/space-info.h +++ b/fs/btrfs/space-info.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_SPACE_INFO_H @@ -73,6 +76,28 @@ struct btrfs_space_info { struct kobject kobj; struct kobject *block_group_kobjs[BTRFS_NR_RAID_TYPES]; + +#ifdef MY_ABC_HERE + struct { + spinlock_t lock; + /* for trim/bg_ro */ + struct rw_semaphore allocation_sem; + /* for block group */ + struct rb_root_cached free_space_bytes; + struct rb_root_cached free_space_max_length; + struct rb_root_cached free_space_max_length_with_extent; + struct rb_root_cached preload; /* for auto scan after mount */ + struct mutex syno_allocator_mutex; + bool force_cluster_disable; + struct btrfs_block_group *cache_bg; + u64 cache_offset; +#ifdef MY_ABC_HERE + u64 log_bg_offset; +#endif /* MY_ABC_HERE */ + atomic64_t fallback_relink_count; + atomic64_t fallback_full_scan_count; + } syno_allocator; +#endif /* MY_ABC_HERE */ }; struct reserve_ticket { @@ -169,4 +194,12 @@ static inline void btrfs_mod_total_bytes_pinned(struct btrfs_fs_info *fs_info, __btrfs_mod_total_bytes_pinned(space_info, mod); } +#ifdef MY_ABC_HERE +void btrfs_syno_btree_balance_dirty(struct btrfs_fs_info *fs_info, bool throttle); +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +void syno_perf_indicator_dirty_limit_update(struct btrfs_fs_info *fs_info); +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ + #endif /* BTRFS_SPACE_INFO_H */ diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2663485c17cb..4e515df8b570 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -52,6 +55,18 @@ #define CREATE_TRACE_POINTS #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include "syno-rbd-meta.h" +#endif /* MY_ABC_HERE */ + static const struct super_operations btrfs_super_ops; /* @@ -375,6 +390,33 @@ enum { #ifdef CONFIG_BTRFS_FS_REF_VERIFY Opt_ref_verify, #endif +#ifdef MY_ABC_HERE + Opt_reclaim_space, Opt_noreclaim_space, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_synoacl, Opt_nosynoacl, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_no_block_group_hint, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_block_group_cache_tree, Opt_clear_block_group_cache_tree, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_no_block_group, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_no_quota_tree, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_drop_log_tree, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_skip_cleaner, Opt_no_skip_cleaner, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_syno_allocator, Opt_clear_syno_allocator, +#endif /* MY_ABC_HERE */ Opt_err, }; @@ -449,6 +491,38 @@ static const match_table_t tokens = { #ifdef CONFIG_BTRFS_FS_REF_VERIFY {Opt_ref_verify, "ref_verify"}, #endif +#ifdef MY_ABC_HERE + {Opt_reclaim_space, "auto_reclaim_space"}, + {Opt_noreclaim_space, "noauto_reclaim_space"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_synoacl, SYNO_ACL_MNT_OPT}, + {Opt_nosynoacl, SYNO_ACL_NOT_MNT_OPT}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_no_block_group_hint, "no_block_group_hint"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_block_group_cache_tree, "block_group_cache_tree"}, + {Opt_clear_block_group_cache_tree, "clear_block_group_cache_tree"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_no_block_group, "no_block_group"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_no_quota_tree, "no_quota_tree"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_drop_log_tree, "drop_log_tree"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_skip_cleaner, "skip_cleaner"}, + {Opt_no_skip_cleaner, "noskip_cleaner"}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + {Opt_syno_allocator, "syno_allocator"}, + {Opt_clear_syno_allocator, "clear_syno_allocator"}, +#endif /* MY_ABC_HERE */ {Opt_err, NULL}, }; @@ -511,7 +585,6 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, { substring_t args[MAX_OPT_ARGS]; char *p, *num; - u64 cache_gen; int intarg; int ret = 0; char *compress_type; @@ -520,12 +593,26 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, int saved_compress_level; bool saved_compress_force; int no_compress = 0; +#ifdef MY_ABC_HERE + struct list_head *space_info_head = &info->space_info; + struct btrfs_space_info *space_info_found; +#endif /* MY_ABC_HERE */ - cache_gen = btrfs_super_cache_generation(info->super_copy); if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE)) btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE); - else if (cache_gen) +#ifdef MY_ABC_HERE + else if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE_VALID)) + btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE); +#else /* MY_ABC_HERE */ + else if (btrfs_free_space_cache_v1_active(info)) { btrfs_set_opt(info->mount_opt, SPACE_CACHE); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_fs_compat(info, BLOCK_GROUP_CACHE_TREE) || btrfs_fs_compat(info, BLOCK_GROUP_CACHE_TREE_AUTO)) + btrfs_set_opt(info->mount_opt, BLOCK_GROUP_CACHE_TREE); +#endif /* MY_ABC_HERE */ /* * Even the options are empty, we still need to do extra check @@ -747,6 +834,14 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, case Opt_noacl: info->sb->s_flags &= ~SB_POSIXACL; break; +#ifdef MY_ABC_HERE + case Opt_synoacl: + btrfs_set_opt(info->mount_opt, SYNO_ACL); + break; + case Opt_nosynoacl: + btrfs_clear_opt(info->mount_opt, SYNO_ACL); + break; +#endif /* MY_ABC_HERE */ case Opt_notreelog: btrfs_set_and_info(info, NOTREELOG, "disabling tree log"); @@ -959,6 +1054,68 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, btrfs_set_opt(info->mount_opt, REF_VERIFY); break; #endif +#ifdef MY_ABC_HERE + case Opt_reclaim_space: + btrfs_set_and_info(info, AUTO_RECLAIM_SPACE, + "enabling auto syno reclaim space"); + break; + case Opt_noreclaim_space: + btrfs_clear_and_info(info, AUTO_RECLAIM_SPACE, + "disabling auto syno reclaim space"); + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case Opt_no_block_group_hint: + btrfs_clear_opt(info->mount_opt, BLOCK_GROUP_HINT_TREE); + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case Opt_block_group_cache_tree: + btrfs_set_opt(info->mount_opt, BLOCK_GROUP_CACHE_TREE); + break; + case Opt_clear_block_group_cache_tree: + btrfs_clear_opt(info->mount_opt, BLOCK_GROUP_CACHE_TREE); + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case Opt_no_block_group: + btrfs_set_opt(info->mount_opt, NO_BLOCK_GROUP); + break; +#endif /*MY_ABC_HERE*/ +#ifdef MY_ABC_HERE + case Opt_no_quota_tree: + if (test_bit(BTRFS_FS_STATE_REMOUNTING, &info->fs_state)) { + btrfs_info(info, "mount option '%s' cannot be used in remount", p); + ret = -EINVAL; + goto out; + } + btrfs_set_opt(info->mount_opt, NO_QUOTA_TREE); + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case Opt_drop_log_tree: + btrfs_set_opt(info->mount_opt, DROP_LOG_TREE); + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case Opt_skip_cleaner: + btrfs_set_opt(info->mount_opt, SKIP_CLEANER); + break; + case Opt_no_skip_cleaner: + btrfs_clear_opt(info->mount_opt, SKIP_CLEANER); + break; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case Opt_syno_allocator: + list_for_each_entry(space_info_found, space_info_head, list) { + space_info_found->syno_allocator.force_cluster_disable = true; + } + btrfs_set_opt(info->mount_opt, SYNO_ALLOCATOR); + break; + case Opt_clear_syno_allocator: + btrfs_clear_opt(info->mount_opt, SYNO_ALLOCATOR); + break; +#endif /* MY_ABC_HERE */ case Opt_err: btrfs_err(info, "unrecognized mount option '%s'", p); ret = -EINVAL; @@ -968,6 +1125,18 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, } } check: +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, NO_BLOCK_GROUP) && !btrfs_test_opt(info, NOLOGREPLAY)) { + btrfs_err(info, + "no_block_group must be used with nologreplay option"); + ret = -EINVAL; + } + if (btrfs_test_opt(info, NO_BLOCK_GROUP) && !(new_flags & SB_RDONLY)) { + btrfs_err(info, + "no_block_group must be used with ro mount option"); + ret = -EINVAL; + } +#endif /* MY_ABC_HERE */ /* * Extra check for current option against current flag */ @@ -988,6 +1157,14 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, btrfs_info(info, "disk space caching is enabled"); if (!ret && btrfs_test_opt(info, FREE_SPACE_TREE)) btrfs_info(info, "using free space tree"); +#ifdef MY_ABC_HERE + if (!ret && btrfs_test_opt(info, BLOCK_GROUP_CACHE_TREE)) + btrfs_info(info, "using block group cache tree"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!ret && btrfs_test_opt(info, NO_QUOTA_TREE)) + btrfs_info(info, "skip quota trees"); +#endif /* MY_ABC_HERE */ return ret; } @@ -998,7 +1175,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, * only when we need to allocate a new super block. */ static int btrfs_parse_device_options(const char *options, fmode_t flags, - void *holder) + void *holder) { substring_t args[MAX_OPT_ARGS]; char *device_name, *opts, *orig, *p; @@ -1286,6 +1463,26 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec return 0; } +#ifdef MY_ABC_HERE +static void syno_fill_super_archive_version(struct super_block *sb, struct inode *inode) +{ + int err; + struct syno_xattr_archive_version value; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + + err = btrfs_getxattr(inode, XATTR_SYNO_ARCHIVE_VERSION_VOLUME, + &value, sizeof(value)); + if (err == sizeof(value)) { + sb->s_archive_version = le32_to_cpu(value.v_archive_version); + } else { + sb->s_archive_version = 0; + if (err != -ENODATA) + btrfs_warn(fs_info, "syno_fill_super_archive_version failed. err: %d", err); + } +} +#endif /* MY_ABC_HERE */ + + static int btrfs_fill_super(struct super_block *sb, struct btrfs_fs_devices *fs_devices, void *data) @@ -1331,6 +1528,19 @@ static int btrfs_fill_super(struct super_block *sb, goto fail_close; } +#ifdef MY_ABC_HERE + syno_fill_super_archive_version(sb, inode); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_raw_test_opt(fs_info->mount_opt, SYNO_ACL)) { + if (syno_acl_module_get()) + sb->s_flags |= SB_SYNOACL; + else + btrfs_clear_opt(fs_info->mount_opt, SYNO_ACL); + } +#endif /* MY_ABC_HERE */ + cleancache_init_fs(sb); sb->s_flags |= SB_ACTIVE; return 0; @@ -1429,9 +1639,13 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) seq_puts(seq, ",discard=async"); if (!(info->sb->s_flags & SB_POSIXACL)) seq_puts(seq, ",noacl"); - if (btrfs_test_opt(info, SPACE_CACHE)) +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, SYNO_ACL)) + seq_puts(seq, ","SYNO_ACL_MNT_OPT); +#endif /* MY_ABC_HERE */ + if (btrfs_free_space_cache_v1_active(info)) seq_puts(seq, ",space_cache"); - else if (btrfs_test_opt(info, FREE_SPACE_TREE)) + else if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE)) seq_puts(seq, ",space_cache=v2"); else seq_puts(seq, ",nospace_cache"); @@ -1472,6 +1686,38 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) #endif if (btrfs_test_opt(info, REF_VERIFY)) seq_puts(seq, ",ref_verify"); +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, AUTO_RECLAIM_SPACE)) + seq_puts(seq, ",auto_reclaim_space"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (!btrfs_test_opt(info, BLOCK_GROUP_HINT_TREE)) + seq_puts(seq, ",no_block_group_hint"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, BLOCK_GROUP_CACHE_TREE)) + seq_puts(seq, ",block_group_cache_tree"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, NO_BLOCK_GROUP)) + seq_puts(seq, ",no_block_group"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, NO_QUOTA_TREE)) + seq_puts(seq, ",no_quota_tree"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, DROP_LOG_TREE)) + seq_puts(seq, ",drop_log_tree"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, SKIP_CLEANER)) + seq_puts(seq, ",skip_cleaner"); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(info, SYNO_ALLOCATOR)) + seq_puts(seq, ",syno_allocator"); +#endif /* MY_ABC_HERE */ seq_printf(seq, ",subvolid=%llu", BTRFS_I(d_inode(dentry))->root->root_key.objectid); subvol_name = btrfs_get_subvol_name_from_objectid(info, @@ -1791,15 +2037,43 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_workqueue_set_max(fs_info->readahead_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->scrub_wr_completion_workers, new_pool_size); +#ifdef MY_ABC_HERE + btrfs_workqueue_set_max(fs_info->syno_allocator.caching_workers, new_pool_size); +#endif /* MY_ABC_HERE */ } +static bool btrfs_defrag_running(struct btrfs_fs_info *fs_info, + unsigned long old_opts, bool rdonly) +{ + + if (!btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) +#ifdef MY_ABC_HERE + && !btrfs_raw_test_opt(old_opts, AUTO_RECLAIM_SPACE) +#endif /* MY_ABC_HERE */ + ) + return false; + + if (rdonly) + return true; + + if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) && + !btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG)) + return true; + +#ifdef MY_ABC_HERE + if (btrfs_raw_test_opt(old_opts, AUTO_RECLAIM_SPACE) && + !btrfs_raw_test_opt(fs_info->mount_opt, AUTO_RECLAIM_SPACE)) + return true; +#endif /* MY_ABC_HERE */ + + return false; +} + + static inline void btrfs_remount_begin(struct btrfs_fs_info *fs_info, unsigned long old_opts, int flags) { - if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) && - (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) || - (flags & SB_RDONLY))) { - /* wait for any defraggers to finish */ + if (btrfs_defrag_running(fs_info, old_opts, !!(flags & SB_RDONLY))) { wait_event(fs_info->transaction_wait, (atomic_read(&fs_info->defrag_running) == 0)); if (flags & SB_RDONLY) @@ -1810,14 +2084,14 @@ static inline void btrfs_remount_begin(struct btrfs_fs_info *fs_info, static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info, unsigned long old_opts) { + const bool cache_opt = btrfs_test_opt(fs_info, SPACE_CACHE); + /* * We need to cleanup all defragable inodes if the autodefragment is * close or the filesystem is read only. */ - if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) && - (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) || sb_rdonly(fs_info->sb))) { + if (btrfs_defrag_running(fs_info, old_opts, sb_rdonly(fs_info->sb))) btrfs_cleanup_defrag_inodes(fs_info); - } /* If we toggled discard async */ if (!btrfs_raw_test_opt(old_opts, DISCARD_ASYNC) && @@ -1826,12 +2100,15 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info, else if (btrfs_raw_test_opt(old_opts, DISCARD_ASYNC) && !btrfs_test_opt(fs_info, DISCARD_ASYNC)) btrfs_discard_cleanup(fs_info); + + /* If we toggled space cache */ + if (cache_opt != btrfs_free_space_cache_v1_active(fs_info)) + btrfs_set_free_space_cache_v1_active(fs_info, cache_opt); } static int btrfs_remount(struct super_block *sb, int *flags, char *data) { struct btrfs_fs_info *fs_info = btrfs_sb(sb); - struct btrfs_root *root = fs_info->tree_root; unsigned old_flags = sb->s_flags; unsigned long old_opts = fs_info->mount_opt; unsigned long old_compress_type = fs_info->compress_type; @@ -1858,10 +2135,38 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) if (ret) goto restore; +#ifdef MY_ABC_HERE + if ((sb->s_flags & SB_SYNOACL) && !btrfs_test_opt(fs_info, SYNO_ACL)) { + sb->s_flags = sb->s_flags & ~SB_SYNOACL; + syno_acl_module_put(); + } else if((!(sb->s_flags & SB_SYNOACL)) && btrfs_test_opt(fs_info, SYNO_ACL)) { + if (syno_acl_module_get()) + sb->s_flags |= SB_SYNOACL; + else + btrfs_clear_opt(fs_info->mount_opt, SYNO_ACL); + } +#endif /* MY_ABC_HERE */ + btrfs_remount_begin(fs_info, old_opts, *flags); btrfs_resize_thread_pool(fs_info, fs_info->thread_pool_size, old_thread_pool_size); + if ((bool)btrfs_test_opt(fs_info, FREE_SPACE_TREE) != + (bool)btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && + (!sb_rdonly(sb) || (*flags & SB_RDONLY))) { + btrfs_warn(fs_info, + "remount supports changing free space tree only from ro to rw"); + /* Make sure free space cache options match the state on disk */ + if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { + btrfs_set_opt(fs_info->mount_opt, FREE_SPACE_TREE); + btrfs_clear_opt(fs_info->mount_opt, SPACE_CACHE); + } + if (btrfs_free_space_cache_v1_active(fs_info)) { + btrfs_clear_opt(fs_info->mount_opt, FREE_SPACE_TREE); + btrfs_set_opt(fs_info->mount_opt, SPACE_CACHE); + } + } + if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) goto out; @@ -1872,6 +2177,18 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) */ cancel_work_sync(&fs_info->async_reclaim_work); cancel_work_sync(&fs_info->async_data_reclaim_work); +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_async_metadata_reclaim_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_async_data_flush_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_async_metadata_flush_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->async_metadata_cache_work); +#endif /* MY_ABC_HERE */ btrfs_discard_cleanup(fs_info); @@ -1894,6 +2211,14 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) btrfs_dev_replace_suspend_for_unmount(fs_info); btrfs_scrub_cancel(fs_info); btrfs_pause_balance(fs_info); +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_usage_rescan_work); + cancel_work_sync(&fs_info->syno_usage_fast_rescan_work); + cancel_work_sync(&fs_info->syno_usage_full_rescan_work); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + cancel_work_sync(&fs_info->syno_allocator.bg_prefetch_work); +#endif /* MY_ABC_HERE */ /* * Pause the qgroup rescan worker if it is running. We don't want @@ -1907,6 +2232,21 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) if (ret) goto restore; } else { +#ifdef MY_ABC_HERE + if (btrfs_super_compat_ro_flags(fs_info->super_copy) & ~BTRFS_FEATURE_COMPAT_RO_SUPP) { + btrfs_err(fs_info, "cannot mount read-write because of unsupported optional features"); + ret = -EINVAL; + goto restore; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_fs_compat_ro(fs_info, LOCKER) && + !btrfs_syno_locker_feature_is_support()) { + btrfs_err(fs_info, "cannot mount read-write because of no locker support"); + ret = -EINVAL; + goto restore; + } +#endif /* MY_ABC_HERE */ if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { btrfs_err(fs_info, "Remounting read-write after error is not allowed"); @@ -1932,42 +2272,30 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) goto restore; } - ret = btrfs_cleanup_fs_roots(fs_info); + /* + * NOTE: when remounting with a change that does writes, don't + * put it anywhere above this point, as we are not sure to be + * safe to write until we pass the above checks. + */ +#ifdef MY_ABC_HERE + ret = btrfs_start_pre_rw_mount(fs_info, NULL); +#else + ret = btrfs_start_pre_rw_mount(fs_info); +#endif /* MY_ABC_HERE */ if (ret) goto restore; - /* recover relocation */ - mutex_lock(&fs_info->cleaner_mutex); - ret = btrfs_recover_relocation(root); - mutex_unlock(&fs_info->cleaner_mutex); - if (ret) - goto restore; - - ret = btrfs_resume_balance_async(fs_info); - if (ret) - goto restore; - - ret = btrfs_resume_dev_replace_async(fs_info); - if (ret) { - btrfs_warn(fs_info, "failed to resume dev_replace"); - goto restore; - } - - btrfs_qgroup_rescan_resume(fs_info); - - if (!fs_info->uuid_root) { - btrfs_info(fs_info, "creating UUID tree"); - ret = btrfs_create_uuid_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to create the UUID tree %d", - ret); - goto restore; - } - } sb->s_flags &= ~SB_RDONLY; set_bit(BTRFS_FS_OPEN, &fs_info->flags); + +#ifdef MY_ABC_HERE + btrfs_syno_usage_rescan_resume(fs_info); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, SYNO_ALLOCATOR)) + queue_work(system_unbound_wq, &fs_info->syno_allocator.bg_prefetch_work); +#endif /* MY_ABC_HERE */ } out: /* @@ -1978,6 +2306,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) wake_up_process(fs_info->transaction_kthread); btrfs_remount_cleanup(fs_info, old_opts); + btrfs_clear_oneshot_options(fs_info); clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state); return 0; @@ -2171,6 +2500,13 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) int ret; u64 thresh = 0; int mixed = 0; +#ifdef MY_ABC_HERE + u64 total_used_metadata = 0; + u64 total_allocated_metadata = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_block_rsv *cleaner_rsv = &fs_info->cleaner_block_rsv; +#endif /* MY_ABC_HERE */ list_for_each_entry(found, &fs_info->space_info, list) { if (found->flags & BTRFS_BLOCK_GROUP_DATA) { @@ -2197,6 +2533,12 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) total_free_meta += found->disk_total - found->disk_used; } +#ifdef MY_ABC_HERE + if (found->flags & BTRFS_BLOCK_GROUP_METADATA) { + total_used_metadata += found->disk_used; + total_allocated_metadata += found->disk_total; + } +#endif /* MY_ABC_HERE */ total_used += found->disk_used; } @@ -2213,6 +2555,14 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) else buf->f_bfree = 0; spin_unlock(&block_rsv->lock); +#ifdef MY_ABC_HERE + spin_lock(&cleaner_rsv->lock); + if (buf->f_bfree >= cleaner_rsv->size >> bits) + buf->f_bfree -= cleaner_rsv->size >> bits; + else + buf->f_bfree = 0; + spin_unlock(&cleaner_rsv->lock); +#endif /* MY_ABC_HERE */ buf->f_bavail = div_u64(total_free_data, factor); ret = btrfs_calc_avail_data_space(fs_info, &total_free_data); @@ -2221,6 +2571,38 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bavail += div_u64(total_free_data, factor); buf->f_bavail = buf->f_bavail >> bits; +#ifdef MY_ABC_HERE + if (fs_info->metadata_ratio) { + u64 total_reserved_for_metadata; + u64 extra_reserved_for_metadata; + + total_reserved_for_metadata = btrfs_syno_calc_reserve_for_metadata(fs_info); + + buf->f_blocks -= total_reserved_for_metadata >> bits; + + if (total_reserved_for_metadata > total_allocated_metadata) { + extra_reserved_for_metadata = total_reserved_for_metadata - total_allocated_metadata; + if (buf->f_bavail > (extra_reserved_for_metadata >> bits)) + buf->f_bavail -= extra_reserved_for_metadata >> bits; + else + buf->f_bavail = 0; + } + + if (total_reserved_for_metadata > total_used_metadata) { + extra_reserved_for_metadata = total_reserved_for_metadata - total_used_metadata; + if (buf->f_bfree > (extra_reserved_for_metadata >> bits)) + buf->f_bfree -= extra_reserved_for_metadata >> bits; + else + buf->f_bfree = 0; + } + + if (buf->f_bfree > buf->f_blocks) + buf->f_bfree = buf->f_blocks; + else if (buf->f_bavail > buf->f_bfree) + buf->f_bavail = buf->f_bfree; + } +#endif /* MY_ABC_HERE */ + /* * We calculate the remaining metadata space minus global reserve. If * this is (supposedly) smaller than zero, there's no space. But this @@ -2243,7 +2625,11 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) * still can allocate chunks and thus are fine using the currently * calculated f_bavail. */ +#ifdef MY_ABC_HERE + if (!mixed && block_rsv->space_info && block_rsv->space_info->full && +#else /* MY_ABC_HERE */ if (!mixed && block_rsv->space_info->full && +#endif /* MY_ABC_HERE */ total_free_meta - thresh < block_rsv->size) buf->f_bavail = 0; @@ -2268,6 +2654,12 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) static void btrfs_kill_super(struct super_block *sb) { struct btrfs_fs_info *fs_info = btrfs_sb(sb); + +#ifdef MY_ABC_HERE + if (SB_SYNOACL & sb->s_flags) + syno_acl_module_put(); +#endif /* MY_ABC_HERE */ + kill_anon_super(sb); btrfs_free_fs_info(fs_info); } @@ -2288,6 +2680,10 @@ static struct file_system_type btrfs_root_fs_type = { .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA, }; +#ifdef MY_ABC_HERE +struct file_system_type *__btrfs_root_fs_type = &btrfs_root_fs_type; +#endif /* MY_ABC_HERE */ + MODULE_ALIAS_FS("btrfs"); static int btrfs_control_open(struct inode *inode, struct file *file) @@ -2413,7 +2809,219 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root) return 0; } +#ifdef MY_ABC_HERE +static int btrfs_syno_get_sb_archive_version(struct super_block *sb, u32 *version) +{ + *version = sb->s_archive_version; + return 0; +} + +static int btrfs_syno_set_sb_archive_version(struct super_block *sb, u32 archive_ver) +{ + int ret; + struct syno_xattr_archive_version value; + + value.v_magic = cpu_to_le16(0x2552); + value.v_struct_version = cpu_to_le16(1); + value.v_archive_version = cpu_to_le32(archive_ver); + + ret = btrfs_setxattr_trans(sb->s_root->d_inode, + XATTR_SYNO_ARCHIVE_VERSION_VOLUME, + &value, sizeof(value), 0); + if (!ret) + sb->s_archive_version = archive_ver; + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static long btrfs_nr_cached_objects(struct super_block *sb, struct shrink_control *sc) +{ + return (long)atomic_read(&btrfs_sb(sb)->nr_extent_maps); +} + +enum btrfs_free_extent_map_type { + LOOP_FREE_EXTENT_NOT_MODIFIED, + LOOP_FREE_EXTENT_MODIFIED, + LOOP_FREE_EXTENT_END, +}; + +static int btrfs_drop_extent_maps(struct inode *inode, unsigned long nr_to_drop) +{ + struct extent_map *em, *next_em = NULL; + struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; + struct btrfs_root *root = BTRFS_I(inode)->root; + unsigned long dropped = 0; + u64 test_gen; + struct list_head *head = NULL; + enum btrfs_free_extent_map_type stage = LOOP_FREE_EXTENT_NOT_MODIFIED; + + while (nr_to_drop) { + write_lock(&em_tree->lock); + test_gen = root->fs_info->last_trans_committed; + + if (stage == LOOP_FREE_EXTENT_NOT_MODIFIED) { + head = &em_tree->not_modified_extents; + } else if (stage == LOOP_FREE_EXTENT_MODIFIED) { + head = &em_tree->syno_modified_extents; + } else { + write_unlock(&em_tree->lock); + ASSERT(0); + break; + } + + if (next_em != NULL && !extent_map_in_tree(next_em)) { + free_extent_map(next_em); + next_em = NULL; + } + + if (next_em == NULL) { + if (list_empty(head)) { + write_unlock(&em_tree->lock); + goto next; + } + em = list_entry(head->next, struct extent_map, free_list); + refcount_inc(&em->refs); + } else { + em = next_em; + } + if (list_is_last(&em->free_list, &em_tree->not_modified_extents) || + list_is_last(&em->free_list, &em_tree->syno_modified_extents) || + list_empty(&em->free_list)) { + next_em = NULL; + } else { + next_em = list_entry(em->free_list.next, struct extent_map, free_list); + refcount_inc(&next_em->refs); + } + + if (test_bit(EXTENT_FLAG_PINNED, &em->flags)) { + free_extent_map(em); + write_unlock(&em_tree->lock); + goto next; + } + if (!list_empty(&em->list) && em->generation > test_gen) { + free_extent_map(em); + write_unlock(&em_tree->lock); + if (stage == LOOP_FREE_EXTENT_MODIFIED) + break; + else + goto next; + } + remove_extent_mapping(em_tree, em); + write_unlock(&em_tree->lock); + /* once for us */ + free_extent_map(em); + /* once for the tree*/ + free_extent_map(em); + dropped++; + nr_to_drop--; +next: + if (next_em == NULL) + stage++; + if (stage >= LOOP_FREE_EXTENT_END) + break; + cond_resched(); + } + if (next_em) { + /* once for us */ + free_extent_map(next_em); + } + return dropped; +} + +static bool list_lru_item_empty(struct list_lru *lru, struct list_head *item) +{ + int nid = page_to_nid(virt_to_page(item)); + struct list_lru_node *nlru = &lru->node[nid]; + + spin_lock(&nlru->lock); + if (list_empty(item)) { + spin_unlock(&nlru->lock); + return true; + } + spin_unlock(&nlru->lock); + return false; +} + +static long btrfs_free_cached_objects(struct super_block *sb, struct shrink_control *sc) +{ + struct inode *inode; + struct inode *toput_inode = NULL; + struct btrfs_inode *binode; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + unsigned long nr_to_drop = sc->nr_to_scan; + + spin_lock(&fs_info->extent_map_inode_list_lock); + list_for_each_entry(binode, &fs_info->extent_map_inode_list, + free_extent_map_inode) { + inode = &binode->vfs_inode; + if (!list_lru_item_empty(&fs_info->sb->s_inode_lru, + &inode->i_lru)) + continue; + + spin_lock(&inode->i_lock); + if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { + spin_unlock(&inode->i_lock); + continue; + } + __iget(inode); + spin_unlock(&inode->i_lock); + + atomic_inc(&binode->free_extent_map_counts); + if (toput_inode && + (atomic_read(&BTRFS_I(toput_inode)->free_extent_map_counts) == 0) && + (atomic_read(&(BTRFS_I(toput_inode)->extent_tree.nr_extent_maps)) == 0)) + list_del_init(&BTRFS_I(toput_inode)->free_extent_map_inode); + + spin_unlock(&fs_info->extent_map_inode_list_lock); + + nr_to_drop -= btrfs_drop_extent_maps(inode, nr_to_drop); + + iput(toput_inode); + toput_inode = inode; + cond_resched(); + + spin_lock(&fs_info->extent_map_inode_list_lock); + WARN_ON(atomic_read(&binode->free_extent_map_counts) == 0); + atomic_dec(&binode->free_extent_map_counts); + if (!nr_to_drop) + break; + } + if (toput_inode && + (atomic_read(&BTRFS_I(toput_inode)->free_extent_map_counts) == 0) && + (atomic_read(&(BTRFS_I(toput_inode)->extent_tree.nr_extent_maps)) == 0)) + list_del_init(&BTRFS_I(toput_inode)->free_extent_map_inode); + + spin_unlock(&fs_info->extent_map_inode_list_lock); + iput(toput_inode); + return (long)(sc->nr_to_scan - nr_to_drop); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_syno_rbd_set_first_mapping_table_offset(struct super_block *sb, + u64 offset) +{ + struct btrfs_root *root = BTRFS_I(d_inode(sb->s_root))->root; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_trans_handle *trans; + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + fs_info->syno_rbd.first_mapping_table_offset = offset; + + return btrfs_commit_transaction(trans); +} +#endif /* MY_ABC_HERE */ + static const struct super_operations btrfs_super_ops = { +#ifdef MY_ABC_HERE + .syno_get_sb_archive_version = btrfs_syno_get_sb_archive_version, + .syno_set_sb_archive_version = btrfs_syno_set_sb_archive_version, +#endif /* MY_ABC_HERE */ .drop_inode = btrfs_drop_inode, .evict_inode = btrfs_evict_inode, .put_super = btrfs_put_super, @@ -2427,6 +3035,14 @@ static const struct super_operations btrfs_super_ops = { .remount_fs = btrfs_remount, .freeze_fs = btrfs_freeze, .unfreeze_fs = btrfs_unfreeze, +#ifdef MY_ABC_HERE + .nr_cached_objects = btrfs_nr_cached_objects, + .free_cached_objects = btrfs_free_cached_objects, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_rbd_set_first_mapping_table_offset = btrfs_syno_rbd_set_first_mapping_table_offset, + .syno_rbd_meta_file_cleanup_all = btrfs_delete_all_rbd_meta_file_records, +#endif /* MY_ABC_HERE */ }; static const struct file_operations btrfs_ctl_fops = { @@ -2475,6 +3091,36 @@ static void __init btrfs_print_mod_info(void) pr_info("Btrfs loaded, crc32c=%s%s\n", crc32c_impl(), options); } +#ifdef MY_ABC_HERE +extern int (*funcSYNOSendErrorFsBtrfsEvent)(const u8*); + +void SynoAutoErrorFsBtrfsReport(const u8* fsid) +{ + if (NULL == funcSYNOSendErrorFsBtrfsEvent) { + printk(KERN_ERR "BTRFS-fs error: " + "Can't reference to function 'funcSYNOSendErrorFsBtrfsEvent'\n"); + return; + } + + funcSYNOSendErrorFsBtrfsEvent(fsid); +} + +extern int (*funcSYNOMetaCorruptedEvent)(const u8*, u64); + +void SynoBtrfsMetaCorruptedReport(const u8* fsid, u64 start) +{ + if (NULL == funcSYNOMetaCorruptedEvent) { + printk(KERN_ERR "BTRFS-fs error: " + "Can't reference to function 'funcSYNOMetaCorruptedEvent'\n"); + return; + } + + funcSYNOMetaCorruptedEvent(fsid, start); +} + +#endif /* MY_ABC_HERE */ + + static int __init init_btrfs_fs(void) { int err; @@ -2531,6 +3177,12 @@ static int __init init_btrfs_fs(void) if (err) goto free_end_io_wq; +#ifdef MY_ABC_HERE + err = qgroup_netlink_init(); + if (err) + goto free_btrfs_interface; +#endif /* MY_ABC_HERE */ + btrfs_init_lockdep(); btrfs_print_mod_info(); @@ -2546,6 +3198,10 @@ static int __init init_btrfs_fs(void) return 0; unregister_ioctl: +#ifdef MY_ABC_HERE + qgroup_netlink_exit(); +free_btrfs_interface: +#endif /* MY_ABC_HERE */ btrfs_interface_exit(); free_end_io_wq: btrfs_end_io_wq_exit(); @@ -2576,6 +3232,9 @@ static int __init init_btrfs_fs(void) static void __exit exit_btrfs_fs(void) { +#ifdef MY_ABC_HERE + qgroup_netlink_exit(); +#endif /* MY_ABC_HERE */ btrfs_destroy_cachep(); btrfs_delayed_ref_exit(); btrfs_auto_defrag_exit(); diff --git a/fs/btrfs/syno-extent-usage.c b/fs/btrfs/syno-extent-usage.c new file mode 100644 index 000000000000..990e616d08ba --- /dev/null +++ b/fs/btrfs/syno-extent-usage.c @@ -0,0 +1,3018 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2019 Synology Inc. 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 v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include +#include +#include "ctree.h" +#include "disk-io.h" +#include "locking.h" +#include "space-info.h" +#include "transaction.h" + +static inline int syno_usage_need_stop(struct btrfs_fs_info *fs_info) +{ + return sb_rdonly(fs_info->sb) || btrfs_fs_closing(fs_info); +} + +static int btrfs_clean_tree_by_root_throttle(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key key; + int ret; + int nr = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.offset = 0; + key.type = 0; + + while (1) { + trans = btrfs_start_transaction_fallback_global_rsv(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; + nr = btrfs_header_nritems(path->nodes[0]); + if (!nr) + break; + /* + * delete the leaf one by one + * since the whole tree is going + * to be deleted. + */ + path->slots[0] = 0; + ret = btrfs_del_items(trans, root, path, 0, nr); + if (ret) + goto out; + + if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_DISABLE) { + fs_info->syno_usage_status.cur_full_rescan_size += nr; + if (fs_info->syno_usage_status.cur_full_rescan_size > fs_info->syno_usage_status.total_full_rescan_size) + fs_info->syno_usage_status.total_full_rescan_size = fs_info->syno_usage_status.cur_full_rescan_size; + } + + btrfs_release_path(path); + btrfs_end_transaction_throttle(trans); + trans = NULL; + if (syno_usage_need_stop(fs_info)) { + btrfs_debug(fs_info, "drop tree early exit for syno usage"); + ret = -EAGAIN; + goto out; + } + if (fatal_signal_pending(current)) { + ret = -EINTR; + goto out; + } + cond_resched(); + } + ret = 0; +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + return ret; +} + +static int usage_update_helper(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_key *key, + u32 extra_size) +{ + int ret; + int orig_search_for_extension = path->search_for_extension; + + path->search_for_extension = 1; + ret = btrfs_search_slot(trans, root, key, path, extra_size, 1); + path->search_for_extension = orig_search_for_extension; + + if (ret > 0) { + btrfs_release_path(path); + // insert new item + ret = btrfs_insert_empty_item(trans, root, path, key, extra_size); + } + return ret; +} + +int btrfs_syno_usage_status_update(struct btrfs_trans_handle *trans) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct btrfs_key key; + int extra_size; + struct extent_buffer *leaf; + struct btrfs_syno_usage_status_item *ei; + struct btrfs_disk_key rescan_progress_disk_key; + + if (!root) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + fs_info->syno_usage_status.state != SYNO_USAGE_STATE_DISABLE) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + path->leave_spinning = 1; + + key.objectid = 0; + key.type = SYNO_BTRFS_USAGE_STATUS_KEY; + key.offset = 0; + + extra_size = sizeof(struct btrfs_syno_usage_status_item); + ret = usage_update_helper(trans, root, path, &key, extra_size); + + if (ret < 0) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_status_item); + btrfs_set_syno_usage_status_version(leaf, ei, fs_info->syno_usage_status.version); + btrfs_set_syno_usage_status_state(leaf, ei, fs_info->syno_usage_status.state); + btrfs_set_syno_usage_status_flags(leaf, ei, fs_info->syno_usage_status.flags); + btrfs_set_syno_usage_status_generation(leaf, ei, trans->transid); + + btrfs_cpu_key_to_disk(&rescan_progress_disk_key, &fs_info->syno_usage_status.extent_rescan_progress); + btrfs_set_syno_usage_status_extent_rescan_progress_key(leaf, ei, &rescan_progress_disk_key); + + btrfs_set_syno_usage_status_cur_full_rescan_size(leaf, ei, fs_info->syno_usage_status.cur_full_rescan_size); + btrfs_set_syno_usage_status_total_full_rescan_size(leaf, ei, fs_info->syno_usage_status.total_full_rescan_size); + btrfs_set_syno_usage_status_extent_tree_cur_rescan_size(leaf, ei, fs_info->syno_usage_status.extent_tree_cur_rescan_size); + btrfs_set_syno_usage_status_extent_tree_total_rescan_size(leaf, ei, fs_info->syno_usage_status.extent_tree_total_rescan_size); + btrfs_set_syno_usage_status_total_syno_extent_tree_items(leaf, ei, fs_info->syno_usage_status.total_syno_extent_tree_items); + btrfs_set_syno_usage_status_total_syno_subvol_usage_items(leaf, ei, fs_info->syno_usage_status.total_syno_subvol_usage_items); + + btrfs_mark_buffer_dirty(path->nodes[0]); +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to update syno usage status"); + } + return ret; +} + +static int __btrfs_syno_usage_global_type_update(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, int type, u64 num_bytes) +{ + int ret; + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct btrfs_key key; + int extra_size; + struct extent_buffer *leaf; + struct btrfs_syno_usage_global_type_item *ei; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + if (type >= SYNO_USAGE_TYPE_MAX) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + path->leave_spinning = 1; + + key.objectid = 0; + key.type = SYNO_BTRFS_USAGE_GLOBAL_TYPE_KEY; + key.offset = type; + + extra_size = sizeof(struct btrfs_syno_usage_global_type_item); + ret = usage_update_helper(trans, root, path, &key, extra_size); + + if (ret < 0) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_global_type_item); + btrfs_set_syno_usage_global_type_num_bytes(leaf, ei, num_bytes); + + btrfs_mark_buffer_dirty(path->nodes[0]); +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to update syno usage global type with type:%d", type); + } + return ret; +} + +int btrfs_syno_usage_global_type_update(struct btrfs_trans_handle *trans) +{ + int ret = 0; + int i; + u64 num_bytes; + struct btrfs_fs_info *fs_info = trans->fs_info; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + + for (i = SYNO_USAGE_TYPE_RO_SNAPSHOT; i < SYNO_USAGE_TYPE_MAX; i++) { + spin_lock(&fs_info->syno_usage_lock); + num_bytes = fs_info->syno_usage_status.syno_usage_type_num_bytes[i]; + spin_unlock(&fs_info->syno_usage_lock); + if (num_bytes) + fs_info->syno_usage_status.syno_usage_type_num_bytes_valid[i] = true; + if (fs_info->syno_usage_status.syno_usage_type_num_bytes_valid[i]) { + ret = __btrfs_syno_usage_global_type_update(trans, fs_info, i, num_bytes); + if (ret) + goto out; + } + if (!num_bytes) + fs_info->syno_usage_status.syno_usage_type_num_bytes_valid[i] = false; + } +out: + return ret; +} + +int btrfs_read_syno_usage_config(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_syno_usage_status_item *syno_usage_status_item; + struct btrfs_syno_usage_global_type_item *syno_usage_global_type_item; + struct btrfs_key key; + struct btrfs_key found_key; + int ret; + struct btrfs_disk_key rescan_progress_disk_key; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + /* + * read all syno usage status/types + */ + key.objectid = 0; + key.type = 0; + key.offset = 0; + + ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); + if (ret < 0) { + goto out; + } else if (ret > 0) { /* tree empty */ + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); + ret = 0; + goto out; + } + + while (1) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid != 0 || (found_key.type != SYNO_BTRFS_USAGE_GLOBAL_TYPE_KEY && found_key.type != SYNO_BTRFS_USAGE_STATUS_KEY)) + break; + + if (found_key.type == SYNO_BTRFS_USAGE_STATUS_KEY) { + syno_usage_status_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_status_item); + fs_info->syno_usage_status.version = btrfs_syno_usage_status_version(leaf, syno_usage_status_item); + fs_info->syno_usage_status.state = btrfs_syno_usage_status_state(leaf, syno_usage_status_item); + fs_info->syno_usage_status.flags = btrfs_syno_usage_status_flags(leaf, syno_usage_status_item); + btrfs_syno_usage_status_extent_rescan_progress_key(leaf, syno_usage_status_item, &rescan_progress_disk_key); + btrfs_disk_key_to_cpu(&fs_info->syno_usage_status.extent_rescan_progress, &rescan_progress_disk_key); + fs_info->syno_usage_status.cur_full_rescan_size = btrfs_syno_usage_status_cur_full_rescan_size(leaf, syno_usage_status_item); + fs_info->syno_usage_status.total_full_rescan_size = btrfs_syno_usage_status_total_full_rescan_size(leaf, syno_usage_status_item); + fs_info->syno_usage_status.extent_tree_cur_rescan_size = btrfs_syno_usage_status_extent_tree_cur_rescan_size(leaf, syno_usage_status_item); + fs_info->syno_usage_status.extent_tree_total_rescan_size = btrfs_syno_usage_status_extent_tree_total_rescan_size(leaf, syno_usage_status_item); + fs_info->syno_usage_status.total_syno_extent_tree_items = btrfs_syno_usage_status_total_syno_extent_tree_items(leaf, syno_usage_status_item); + fs_info->syno_usage_status.total_syno_subvol_usage_items = btrfs_syno_usage_status_total_syno_subvol_usage_items(leaf, syno_usage_status_item); + if (btrfs_syno_usage_status_generation(leaf, syno_usage_status_item) != fs_info->generation) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn(fs_info, "Failed to generation mismatch for syno usage"); + } + if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_NONE || fs_info->syno_usage_status.state == SYNO_USAGE_STATE_DISABLE) + break; + else if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR) + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_RESCAN; + } else if (found_key.type == SYNO_BTRFS_USAGE_GLOBAL_TYPE_KEY) { + if (found_key.offset >= SYNO_USAGE_TYPE_MAX) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn(fs_info, "Failed to type [%llu] overflow for syno usage", found_key.offset); + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_NONE; + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); + break; + } + syno_usage_global_type_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_global_type_item); + fs_info->syno_usage_status.syno_usage_type_num_bytes[found_key.offset] = btrfs_syno_usage_global_type_num_bytes(leaf, syno_usage_global_type_item); + fs_info->syno_usage_status.syno_usage_type_num_bytes_valid[found_key.offset] = true; + } + + ret = btrfs_next_item(root, path); + if (ret < 0) + goto out; + if (ret) + break; + cond_resched(); + } + if (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_NONE || fs_info->syno_usage_status.state == SYNO_USAGE_STATE_DISABLE) + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +void btrfs_syno_usage_root_status_init(struct btrfs_syno_usage_root_status *status, + struct btrfs_syno_usage_root_status *src, bool readonly, bool init) +{ + memset(status, 0, sizeof(*status)); + status->type = SYNO_USAGE_TYPE_NONE; + status->new_type = SYNO_USAGE_TYPE_NONE; + status->state = SYNO_USAGE_ROOT_STATE_RESCAN; + /* drop_progress key is set to {0, 0, 0} */ + /* fast_rescan_progres key is set to {0, 0, 0} */ + if (src) { + status->num_bytes = src->num_bytes; + status->full_rescan_progress = src->full_rescan_progress; + status->cur_full_rescan_size = src->cur_full_rescan_size; + status->total_full_rescan_size = src->total_full_rescan_size; + status->total_syno_subvol_usage_items = src->total_syno_subvol_usage_items; + status->flags = src->flags & ~BTRFS_SYNO_USAGE_ROOT_FLAG_RESET_MASK; + } else if (init) { + status->num_bytes = 0; + /* full_rescan_progress key is set to {0, 0, 0} */ + status->cur_full_rescan_size = 0; + status->total_full_rescan_size = 0; + status->total_syno_subvol_usage_items = 0; + status->flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN; + } else { + status->num_bytes = 0; + status->full_rescan_progress.objectid = -1; + status->full_rescan_progress.type = -1; + status->full_rescan_progress.offset = -1; + status->cur_full_rescan_size = 0; + status->total_full_rescan_size = 0; + status->total_syno_subvol_usage_items = 0; + } + if (readonly) + status->flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY; + status->flags |= BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN; +} + +int btrfs_syno_usage_root_status_update(struct btrfs_trans_handle *trans, + u64 root_objectid, struct btrfs_syno_usage_root_status *syno_usage_root_status) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct btrfs_key key; + int extra_size; + struct extent_buffer *leaf; + struct btrfs_syno_usage_root_status_item *ei; + struct btrfs_disk_key progress_disk_key; + + if (!root) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + fs_info->syno_usage_status.state != SYNO_USAGE_STATE_DISABLE) + return 0; + + if (syno_usage_root_status->type >= SYNO_USAGE_TYPE_MAX) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + path->leave_spinning = 1; + + key.objectid = root_objectid; + key.type = SYNO_BTRFS_USAGE_ROOT_STATUS_KEY; + key.offset = 0; + + extra_size = sizeof(struct btrfs_syno_usage_root_status_item); + ret = usage_update_helper(trans, root, path, &key, extra_size); + + if (ret < 0) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_root_status_item); + btrfs_set_syno_usage_root_status_type(leaf, ei, syno_usage_root_status->type); + btrfs_set_syno_usage_root_status_new_type(leaf, ei, syno_usage_root_status->new_type); + btrfs_set_syno_usage_root_status_state(leaf, ei, syno_usage_root_status->state); + btrfs_set_syno_usage_root_status_flags(leaf, ei, syno_usage_root_status->flags); + btrfs_set_syno_usage_root_status_num_bytes(leaf, ei, syno_usage_root_status->num_bytes); + + btrfs_cpu_key_to_disk(&progress_disk_key, &syno_usage_root_status->drop_progress); + btrfs_set_syno_usage_root_status_drop_progress_key(leaf, ei, &progress_disk_key); + btrfs_cpu_key_to_disk(&progress_disk_key, &syno_usage_root_status->fast_rescan_progress); + btrfs_set_syno_usage_root_status_fast_rescan_progress_key(leaf, ei, &progress_disk_key); + btrfs_cpu_key_to_disk(&progress_disk_key, &syno_usage_root_status->full_rescan_progress); + btrfs_set_syno_usage_root_status_full_rescan_progress_key(leaf, ei, &progress_disk_key); + + btrfs_set_syno_usage_root_status_cur_full_rescan_size(leaf, ei, syno_usage_root_status->cur_full_rescan_size); + btrfs_set_syno_usage_root_status_total_full_rescan_size(leaf, ei, syno_usage_root_status->total_full_rescan_size); + btrfs_set_syno_usage_root_status_total_syno_subvol_usage_items(leaf, ei, syno_usage_root_status->total_syno_subvol_usage_items); + + btrfs_mark_buffer_dirty(path->nodes[0]); +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to update syno usage root status with root:%llu", root_objectid); + } + return ret; +} + +int btrfs_syno_usage_root_status_remove(struct btrfs_trans_handle *trans, u64 root_objectid) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct btrfs_key key; + + if (!root) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + fs_info->syno_usage_status.state != SYNO_USAGE_STATE_DISABLE) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = root_objectid; + key.type = SYNO_BTRFS_USAGE_ROOT_STATUS_KEY; + key.offset = 0; + + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = 0; + goto out; + } + ret = btrfs_del_item(trans, root, path); +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to remove syno usage root status with root:%llu", root_objectid); + } + return ret; +} + +int btrfs_syno_usage_root_status_lookup(struct btrfs_fs_info *fs_info, u64 root_objectid, + struct btrfs_syno_usage_root_status *ret_syno_usage_root_status) +{ + int ret; + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_syno_usage_root_status_item *ei; + struct btrfs_disk_key progress_disk_key; + + if (!root) + return 1; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + fs_info->syno_usage_status.state != SYNO_USAGE_STATE_DISABLE) + return 1; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = root_objectid; + key.type = SYNO_BTRFS_USAGE_ROOT_STATUS_KEY; + key.offset = 0; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret != 0) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_root_status_item); + + ret_syno_usage_root_status->type = btrfs_syno_usage_root_status_type(leaf, ei); + ret_syno_usage_root_status->new_type = btrfs_syno_usage_root_status_new_type(leaf, ei); + ret_syno_usage_root_status->state = btrfs_syno_usage_root_status_state(leaf, ei); + ret_syno_usage_root_status->flags = btrfs_syno_usage_root_status_flags(leaf, ei); + ret_syno_usage_root_status->num_bytes = btrfs_syno_usage_root_status_num_bytes(leaf, ei); + btrfs_syno_usage_root_status_drop_progress_key(leaf, ei, &progress_disk_key); + btrfs_disk_key_to_cpu(&ret_syno_usage_root_status->drop_progress, &progress_disk_key); + btrfs_syno_usage_root_status_fast_rescan_progress_key(leaf, ei, &progress_disk_key); + btrfs_disk_key_to_cpu(&ret_syno_usage_root_status->fast_rescan_progress, &progress_disk_key); + btrfs_syno_usage_root_status_full_rescan_progress_key(leaf, ei, &progress_disk_key); + btrfs_disk_key_to_cpu(&ret_syno_usage_root_status->full_rescan_progress, &progress_disk_key); + ret_syno_usage_root_status->cur_full_rescan_size = btrfs_syno_usage_root_status_cur_full_rescan_size(leaf, ei); + ret_syno_usage_root_status->total_full_rescan_size = btrfs_syno_usage_root_status_total_full_rescan_size(leaf, ei); + ret_syno_usage_root_status->total_syno_subvol_usage_items = btrfs_syno_usage_root_status_total_syno_subvol_usage_items(leaf, ei); +out: + btrfs_free_path(path); + return ret; +} + +static int btrfs_create_syno_usage_tree(struct btrfs_trans_handle *trans) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *syno_usage_root; + + syno_usage_root = btrfs_create_tree(trans, BTRFS_SYNO_USAGE_TREE_OBJECTID); + if (IS_ERR(syno_usage_root)) { + ret = PTR_ERR(syno_usage_root); + goto out; + } + fs_info->syno_usage_root = syno_usage_root; + fs_info->syno_usage_root->block_rsv = &fs_info->delayed_refs_rsv; + + ret = 0; +out: + return ret; +} + +static int syno_usage_clear_tree(struct btrfs_fs_info *fs_info, struct btrfs_root **ptr_root) +{ + struct btrfs_trans_handle *trans = NULL; + struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *root = *ptr_root; + int ret; + + if (!root) { + ret = 0; + goto out; + } + + ret = btrfs_clean_tree_by_root_throttle(root); + if (ret) + goto out; + + trans = btrfs_start_transaction_fallback_global_rsv(tree_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + *ptr_root = NULL; + + ret = btrfs_del_root(trans, &root->root_key); + if (ret) + goto abort; + + list_del(&root->dirty_list); + + btrfs_tree_lock(root->node); + btrfs_clean_tree_block(root->node); + btrfs_tree_unlock(root->node); + btrfs_free_tree_block(trans, root, root->node, 0, 1); + + btrfs_put_root(root); + + ret = btrfs_commit_transaction(trans); + trans = NULL; + if (ret) + goto out; + + ret = 0; +out: + return ret; + +abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + trans = NULL; + goto out; +} + +int btrfs_clear_syno_usage_tree(struct btrfs_fs_info *fs_info) +{ + return syno_usage_clear_tree(fs_info, &fs_info->syno_usage_root); +} + +static int syno_extent_usage_add_entry(struct btrfs_trans_handle *trans, + struct btrfs_root *root, struct btrfs_path *path, + int want, struct btrfs_key *ins, int refs_mod) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_syno_extent_usage_item *ei; + struct btrfs_syno_extent_usage_inline_ref *iref; + struct extent_buffer *leaf; + u32 size; + int ret; + bool update_inline_ref; + + if (want == SYNO_USAGE_TYPE_RO_SNAPSHOT) + update_inline_ref = false; + else + update_inline_ref = true; + + size = sizeof(struct btrfs_syno_extent_usage_item); + if (update_inline_ref) + size += sizeof(struct btrfs_syno_extent_usage_inline_ref); + + path->leave_spinning = 1; + ret = btrfs_insert_empty_item(trans, root, path, ins, size); + if (ret) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_extent_usage_item); + + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.syno_usage_type_num_bytes[want] += ins->offset; + fs_info->syno_usage_status.total_syno_extent_tree_items++; + spin_unlock(&fs_info->syno_usage_lock); + btrfs_set_syno_extent_usage_type(leaf, ei, want); + + if (update_inline_ref) { + iref = (struct btrfs_syno_extent_usage_inline_ref *)(ei + 1); + btrfs_set_syno_extent_usage_inline_ref_type(leaf, iref, want); + btrfs_set_syno_extent_usage_inline_ref_count(leaf, iref, refs_mod); + } + + btrfs_mark_buffer_dirty(path->nodes[0]); +out: + btrfs_release_path(path); + return ret; +} + +/* + * helper to update inline back ref + */ +static noinline_for_stack +void syno_extent_usage_update_inline_ref_count(struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_syno_extent_usage_inline_ref *iref, + int refs_to_mod) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_buffer *leaf; + struct btrfs_syno_extent_usage_item *ei; + struct btrfs_syno_extent_usage_inline_ref *tmp_iref; + unsigned long ptr; + unsigned long end; + u64 item_size; + long long refs; + int type, want, inline_ref_type; + int size; + struct btrfs_key key; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_extent_usage_item); + type = btrfs_syno_extent_usage_type(leaf, ei); + + refs = btrfs_syno_extent_usage_inline_ref_count(leaf, iref); + if (refs_to_mod < 0 && refs < refs_to_mod) { + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + btrfs_warn_rl(fs_info, "Failed to syno usage refs underflow for extent bytenr %llu refs %lld refs_to_mod %d", key.objectid, refs, refs_to_mod); + refs = 0; + } else { + refs += refs_to_mod; + } + btrfs_set_syno_extent_usage_inline_ref_count(leaf, iref, refs); + + if (refs == 0) { + inline_ref_type = btrfs_syno_extent_usage_inline_ref_type(leaf, iref); + /* modify type */ + if (type == inline_ref_type) { + item_size = btrfs_item_size_nr(leaf, path->slots[0]); + ptr = (unsigned long)(ei + 1); + end = (unsigned long)ei + item_size; + want = SYNO_USAGE_TYPE_RO_SNAPSHOT; + while (1) { + if (ptr >= end) { + WARN_ON(ptr > end); + break; + } + tmp_iref = (struct btrfs_syno_extent_usage_inline_ref *)ptr; + refs = btrfs_syno_extent_usage_inline_ref_count(leaf, tmp_iref); + if (refs > 0) { + want = btrfs_syno_extent_usage_inline_ref_type(leaf, tmp_iref); + break; + } + ptr += sizeof(struct btrfs_syno_extent_usage_inline_ref); + } + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + spin_lock(&fs_info->syno_usage_lock); + if (fs_info->syno_usage_status.syno_usage_type_num_bytes[type] < key.offset) { + btrfs_warn_rl(fs_info, "Failed to syno usage underflow for type %u size %llu key [%llu %u %llu]", + type, fs_info->syno_usage_status.syno_usage_type_num_bytes[type], key.objectid, key.type, key.offset); + fs_info->syno_usage_status.syno_usage_type_num_bytes[type] = 0; + } else { + fs_info->syno_usage_status.syno_usage_type_num_bytes[type] -= key.offset; + } + fs_info->syno_usage_status.syno_usage_type_num_bytes[want] += key.offset; + spin_unlock(&fs_info->syno_usage_lock); + btrfs_set_syno_extent_usage_type(leaf, ei, want); + } + + /* remove unused inline ref */ + size = sizeof(struct btrfs_syno_extent_usage_inline_ref); + item_size = btrfs_item_size_nr(leaf, path->slots[0]); + ptr = (unsigned long)iref; + end = (unsigned long)ei + item_size; + if (ptr + size < end) + memmove_extent_buffer(leaf, ptr, ptr + size, end - ptr - size); + item_size -= size; + btrfs_truncate_item(path, item_size, 1); + } + + btrfs_mark_buffer_dirty(leaf); +} + +/* + * helper to add new inline back ref + */ +static noinline_for_stack +void syno_extent_usage_setup_inline_ref(struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_syno_extent_usage_inline_ref *iref, + int want, int refs_mod) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_buffer *leaf; + struct btrfs_syno_extent_usage_item *ei; + unsigned long ptr; + unsigned long end; + unsigned long item_offset; + int size; + int type; + struct btrfs_key key; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_extent_usage_item); + item_offset = (unsigned long)iref - (unsigned long)ei; + + size = sizeof(struct btrfs_syno_extent_usage_inline_ref); + + btrfs_extend_item(path, size); + + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_extent_usage_item); + type = btrfs_syno_extent_usage_type(leaf, ei); + if (type == SYNO_USAGE_TYPE_RO_SNAPSHOT || want < type) { + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + spin_lock(&fs_info->syno_usage_lock); + if (fs_info->syno_usage_status.syno_usage_type_num_bytes[type] < key.offset) { + btrfs_warn_rl(fs_info, "Failed to syno usage underflow for type %u size %llu key [%llu %u %llu]", + type, fs_info->syno_usage_status.syno_usage_type_num_bytes[type], + key.objectid, key.type, key.offset); + fs_info->syno_usage_status.syno_usage_type_num_bytes[type] = 0; + } else { + fs_info->syno_usage_status.syno_usage_type_num_bytes[type] -= key.offset; + } + fs_info->syno_usage_status.syno_usage_type_num_bytes[want] += key.offset; + spin_unlock(&fs_info->syno_usage_lock); + btrfs_set_syno_extent_usage_type(leaf, ei, want); + } + + ptr = (unsigned long)ei + item_offset; + end = (unsigned long)ei + btrfs_item_size_nr(leaf, path->slots[0]); + if (ptr < end - size) + memmove_extent_buffer(leaf, ptr + size, ptr, end - size - ptr); + + iref = (struct btrfs_syno_extent_usage_inline_ref *)ptr; + btrfs_set_syno_extent_usage_inline_ref_type(leaf, iref, want); + btrfs_set_syno_extent_usage_inline_ref_count(leaf, iref, refs_mod); + + btrfs_mark_buffer_dirty(leaf); +} + +/* + * look for inline ref. if ref is found, *ref_ret is set + * to the address of inline ref, and 0 is returned. + * + * if ref isn't found, *ref_ret is set to the address where it + * should be inserted, and -ENOENT is returned. + * + * NOTE: inline refs are ordered in the same way that ref + * items in the tree are ordered. + */ +static noinline_for_stack +int syno_extent_usage_lookup_inline_ref(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_syno_extent_usage_inline_ref **ref_ret, + int want, int insert) +{ + int ret; + struct extent_buffer *leaf; + struct btrfs_syno_extent_usage_item *ei; + struct btrfs_syno_extent_usage_inline_ref *iref; + u64 item_size; + unsigned long ptr; + unsigned long end; + int type; + + leaf = path->nodes[0]; + item_size = btrfs_item_size_nr(leaf, path->slots[0]); + BUG_ON(item_size < sizeof(struct btrfs_syno_extent_usage_item)); + + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_extent_usage_item); + + ptr = (unsigned long)(ei + 1); + end = (unsigned long)ei + item_size; + + ret = -ENOENT; + while (1) { + if (ptr >= end) { + WARN_ON(ptr > end); + break; + } + iref = (struct btrfs_syno_extent_usage_inline_ref *)ptr; + type = btrfs_syno_extent_usage_inline_ref_type(leaf, iref); + if (want == type) { + ret = 0; + break; + } + if (type > want) + break; + + ptr += sizeof(struct btrfs_syno_extent_usage_inline_ref); + } + if (ret == -ENOENT && insert) { + if (sizeof(struct btrfs_item) + item_size + + sizeof(struct btrfs_syno_extent_usage_inline_ref) > + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { + ret = -EOVERFLOW; + goto out; + } + } + *ref_ret = (struct btrfs_syno_extent_usage_inline_ref *)ptr; + +out: + return ret; +} + +int btrfs_syno_extent_usage_add(struct btrfs_trans_handle *trans, + int want, u64 bytenr, u64 num_bytes, int refs_to_add) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->syno_extent_usage_root; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_syno_extent_usage_inline_ref *iref; + int extra_size; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + + if (want == SYNO_USAGE_TYPE_NONE) + return 0; + + if (want >= SYNO_USAGE_TYPE_MAX) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = bytenr; + key.type = SYNO_BTRFS_EXTENT_USAGE_KEY; + key.offset = num_bytes; + /* + * if btrfs_search_slot return 0, item already exists. In this case we don't need + * space for struct btrfs_syno_extent_usage_item, we may only need to insert + * struct btrfs_syno_extent_usage_inline_ref if type doesn't exist. + */ + extra_size = sizeof(struct btrfs_syno_extent_usage_inline_ref); + +again: + path->search_for_extension = 1; + ret = btrfs_search_slot(trans, root, &key, path, extra_size, 1); + path->search_for_extension = 0; + if (ret < 0) { + goto out; + } else if (ret > 0) { + btrfs_release_path(path); + // insert new item + ret = syno_extent_usage_add_entry(trans, root, path, want, &key, refs_to_add); + if (ret == -EEXIST) + goto again; + goto out; + } + + if (want == SYNO_USAGE_TYPE_RO_SNAPSHOT) + goto out; + + ret = syno_extent_usage_lookup_inline_ref(trans, root, path, &iref, want, 1); + if (ret == 0) { /* update */ + syno_extent_usage_update_inline_ref_count(root, path, iref, refs_to_add); + } else if (ret == -ENOENT) { /* insert new ref */ + syno_extent_usage_setup_inline_ref(root, path, iref, want, refs_to_add); + ret = 0; + } + +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to add syno usage extent item with bytenr:%llu", bytenr); + } + return ret; +} + +int btrfs_syno_extent_usage_free(struct btrfs_trans_handle *trans, + int want, u64 bytenr, u64 num_bytes, int refs_to_drop, bool remove) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->syno_extent_usage_root; + struct btrfs_path *path; + struct btrfs_syno_extent_usage_inline_ref *iref; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_syno_extent_usage_item *ei; + int type; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + + if (!remove && (want == SYNO_USAGE_TYPE_NONE || want == SYNO_USAGE_TYPE_RO_SNAPSHOT)) + return 0; + + if (want >= SYNO_USAGE_TYPE_MAX) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = bytenr; + key.type = SYNO_BTRFS_EXTENT_USAGE_KEY; + key.offset = num_bytes; + + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; + if (ret) { + ret = 0; + goto out; + } + + if (remove) { + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_extent_usage_item); + type = btrfs_syno_extent_usage_type(leaf, ei); + spin_lock(&fs_info->syno_usage_lock); + if (fs_info->syno_usage_status.syno_usage_type_num_bytes[type] < key.offset) { + btrfs_warn_rl(fs_info, "Failed to syno usage underflow for type %u size %llu key [%llu %u %llu]", + type, fs_info->syno_usage_status.syno_usage_type_num_bytes[type], + key.objectid, key.type, key.offset); + fs_info->syno_usage_status.syno_usage_type_num_bytes[type] = 0; + } else { + fs_info->syno_usage_status.syno_usage_type_num_bytes[type] -= num_bytes; + } + if (fs_info->syno_usage_status.total_syno_extent_tree_items > 0) + fs_info->syno_usage_status.total_syno_extent_tree_items--; + spin_unlock(&fs_info->syno_usage_lock); + ret = btrfs_del_item(trans, root, path); + goto out; + } + + ret = syno_extent_usage_lookup_inline_ref(trans, root, path, &iref, want, 0); + if (ret == 0) /* update */ + syno_extent_usage_update_inline_ref_count(root, path, iref, -refs_to_drop); + else if (ret == -ENOENT) + ret = 0; +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to free syno usage extent item with bytenr:%llu", bytenr); + } + return ret; +} + +static int btrfs_create_syno_extent_usage_tree(struct btrfs_trans_handle *trans) +{ + int ret; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *syno_extent_usage_root; + + syno_extent_usage_root = btrfs_create_tree(trans, BTRFS_SYNO_EXTENT_USAGE_TREE_OBJECTID); + if (IS_ERR(syno_extent_usage_root)) { + ret = PTR_ERR(syno_extent_usage_root); + goto out; + } + fs_info->syno_extent_usage_root = syno_extent_usage_root; + fs_info->syno_extent_usage_root->block_rsv = &fs_info->delayed_refs_rsv; + + ret = 0; +out: + return ret; +} + +int btrfs_clear_extent_usage_tree(struct btrfs_fs_info *fs_info) +{ + return syno_usage_clear_tree(fs_info, &fs_info->syno_extent_usage_root); +} + +static int syno_subvol_usage_add_entry(struct btrfs_trans_handle *trans, + struct btrfs_root *root, struct btrfs_path *path, + struct btrfs_key *ins, u64 num_bytes, int refs_mod, u8 *type) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_syno_subvol_usage_item *ei; + struct extent_buffer *leaf; + u32 size; + int ret; + + size = sizeof(struct btrfs_syno_subvol_usage_item); + + ret = btrfs_insert_empty_item(trans, root, path, ins, size); + if (ret) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_subvol_usage_item); + btrfs_set_syno_subvol_usage_ref_count(leaf, ei, refs_mod); + btrfs_set_syno_subvol_usage_num_bytes(leaf, ei, num_bytes); + + spin_lock(&root->syno_usage_lock); + root->syno_usage_root_status.num_bytes += num_bytes; + root->syno_usage_root_status.total_syno_subvol_usage_items++; + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.total_syno_subvol_usage_items++; + spin_unlock(&fs_info->syno_usage_lock); + if (type) { + if (root->syno_usage_root_status.state == SYNO_USAGE_ROOT_STATE_RESCAN && + btrfs_comp_cpu_keys(ins, &root->syno_usage_root_status.fast_rescan_progress) >= 0) + *type = root->syno_usage_root_status.type; + else + *type = root->syno_usage_root_status.new_type; + if (*type == SYNO_USAGE_TYPE_NONE) { + if ((root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_FORCE_EXTENT) || + btrfs_root_readonly(root)) + *type = SYNO_USAGE_TYPE_RO_SNAPSHOT; + } + } + spin_unlock(&root->syno_usage_lock); + btrfs_record_root_in_trans(trans, root); + + btrfs_mark_buffer_dirty(path->nodes[0]); +out: + btrfs_release_path(path); + return ret; +} + +static int syno_subvol_usage_update_ref_count(struct btrfs_trans_handle *trans, + struct btrfs_root *root, struct btrfs_path *path, + struct btrfs_key *ins, int refs_to_mod, int *last_ref, u8 *type) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_buffer *leaf; + struct btrfs_syno_subvol_usage_item *ei; + long long refs; + int ret = 0; + u64 num_bytes; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_subvol_usage_item); + + num_bytes = btrfs_syno_subvol_usage_num_bytes(leaf, ei); + refs = btrfs_syno_subvol_usage_ref_count(leaf, ei); + if (refs_to_mod < 0 && refs < refs_to_mod) { + btrfs_warn_rl(fs_info, "Failed to syno usage refs underflow for subvol usage bytenr %llu refs %lld refs_to_mod %d", ins->offset, refs, refs_to_mod); + refs = 0; + } else { + refs += refs_to_mod; + } + btrfs_set_syno_subvol_usage_ref_count(leaf, ei, refs); + btrfs_mark_buffer_dirty(leaf); + + if (refs == 0) { + ret = btrfs_del_item(trans, root, path); + if (ret) + goto out; + + spin_lock(&root->syno_usage_lock); + root->syno_usage_root_status.num_bytes -= num_bytes; + if (root->syno_usage_root_status.total_syno_subvol_usage_items > 0) + root->syno_usage_root_status.total_syno_subvol_usage_items--; + spin_lock(&fs_info->syno_usage_lock); + if (fs_info->syno_usage_status.total_syno_subvol_usage_items > 0) + fs_info->syno_usage_status.total_syno_subvol_usage_items--; + spin_unlock(&fs_info->syno_usage_lock); + if (last_ref) + *last_ref = 1; + if (type) { + if (root->syno_usage_root_status.state == SYNO_USAGE_ROOT_STATE_RESCAN && + btrfs_comp_cpu_keys(ins, &root->syno_usage_root_status.fast_rescan_progress) >= 0) + *type = root->syno_usage_root_status.type; + else + *type = root->syno_usage_root_status.new_type; + } + spin_unlock(&root->syno_usage_lock); + btrfs_record_root_in_trans(trans, root); + } +out: + return ret; +} + +static int __btrfs_syno_subvol_usage_add(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 bytenr, u64 num_bytes, int refs_to_add) +{ + int ret = 0; + struct btrfs_path *path; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_key key; + int extra_size; + u8 type; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + !test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_USAGE_KEY; + key.offset = bytenr; + + extra_size = sizeof(struct btrfs_syno_subvol_usage_item); + +again: + path->search_for_extension = 1; + ret = btrfs_search_slot(trans, root, &key, path, extra_size, 1); + path->search_for_extension = 0; + if (ret < 0) { + goto out; + } else if (ret > 0) { + btrfs_release_path(path); + // insert new item + ret = syno_subvol_usage_add_entry(trans, root, path, &key, num_bytes, refs_to_add, &type); + if (ret == -EEXIST) + goto again; + if (ret) + goto out; + ret = btrfs_syno_extent_usage_add(trans, type, bytenr, num_bytes, 1); + goto out; + } + + ret = syno_subvol_usage_update_ref_count(trans, root, path, &key, refs_to_add, NULL, NULL); +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to add syno usage subvol item with bytenr:%llu", bytenr); + } + return ret; +} + +int btrfs_syno_subvol_usage_add(struct btrfs_trans_handle *trans, + u64 root_objectid, u64 bytenr, u64 num_bytes, int refs_to_add) +{ + int ret = 0; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + + root = btrfs_get_fs_root(fs_info, root_objectid, true); + if (IS_ERR(root)) { + if (PTR_ERR(root) != -ENOENT) { + ret = PTR_ERR(root); + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to read root with objectid:%llu, err:%d", root_objectid, ret); + } + goto out; + } + + trans->syno_usage = true; + ret = __btrfs_syno_subvol_usage_add(trans, root, bytenr, num_bytes, refs_to_add); + trans->syno_usage = false; + btrfs_put_root(root); +out: + return ret; +} + +static int __btrfs_syno_subvol_usage_free(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 bytenr, u64 num_bytes, int refs_to_drop) +{ + int ret = 0; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_path *path; + struct btrfs_key key; + int last_ref = 0; + u8 type; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + !test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_USAGE_KEY; + key.offset = bytenr; + + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; + if (ret) { + ret = 0; + goto out; + } + + ret = syno_subvol_usage_update_ref_count(trans, root, path, &key, -refs_to_drop, &last_ref, &type); + if (ret) + goto out; + + if (last_ref) { + btrfs_release_path(path); + ret = btrfs_syno_extent_usage_free(trans, type, bytenr, num_bytes, 1, 0); + } +out: + btrfs_free_path(path); + if (ret) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to free syno usage subvol item with bytenr:%llu", bytenr); + } + return ret; +} + +int btrfs_syno_subvol_usage_free(struct btrfs_trans_handle *trans, + u64 root_objectid, u64 bytenr, u64 num_bytes, int refs_to_drop) +{ + int ret = 0; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + return 0; + + root = btrfs_get_fs_root(fs_info, root_objectid, true); + if (IS_ERR(root)) { + if (PTR_ERR(root) != -ENOENT) { + ret = PTR_ERR(root); + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to read root with objectid:%llu, err:%d", root_objectid, ret); + } + goto out; + } + + trans->syno_usage = true; + ret = __btrfs_syno_subvol_usage_free(trans, root, bytenr, num_bytes, refs_to_drop); + trans->syno_usage = false; + btrfs_put_root(root); +out: + return ret; +} + +static void syno_usage_wait_on_rescan(struct btrfs_root *root) +{ + wait_on_bit(&root->syno_usage_runtime_flags, + SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN, + TASK_UNINTERRUPTIBLE); +} + +static void syno_usage_rescan_start(struct btrfs_root *root) +{ + set_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN, &root->syno_usage_runtime_flags); +} + +static void syno_usage_rescan_end(struct btrfs_root *root) +{ + clear_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN, &root->syno_usage_runtime_flags); + smp_mb__after_atomic(); + wake_up_bit(&root->syno_usage_runtime_flags, SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN); +} + +static int syno_subvol_dummy_insert(struct btrfs_root *root, + struct btrfs_path *path, struct btrfs_key *ins) +{ + int ret; + struct btrfs_trans_handle *trans = NULL; + + trans = btrfs_start_transaction_fallback_global_rsv(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + ret = btrfs_insert_empty_item(trans, root, path, ins, root->fs_info->nodesize / 2); + if (ret) + goto out; + +out: + btrfs_release_path(path); + if (trans) + btrfs_end_transaction(trans); + return ret; +} + +static int syno_subvol_dummy_add(struct btrfs_root *root, u64 offset) +{ + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_path *path; + struct btrfs_key key; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + !test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_DUMMY_KEY; + key.offset = offset; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + goto out; + } else if (ret > 0) { + btrfs_release_path(path); + // insert new item + ret = syno_subvol_dummy_insert(root, path, &key); + goto out; + } +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_syno_clear_subvol_usage_item_prepare(struct btrfs_root *root) +{ + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + int i; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + !test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + return 0; + + if (!root->syno_usage_root_status.total_syno_subvol_usage_items) + return 0; + + for (i = 0; i < 3; i++) { + ret = syno_subvol_dummy_add(root, i); + if (ret) + goto out; + } + + ret = 0; +out: + if (ret) + btrfs_warn_rl(fs_info, "Failed to add subvol usage dummy item with root %llu err %d", root->root_key.objectid, ret); + return ret; +} + +int btrfs_syno_clear_subvol_usage_item_doing(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_key found_key; + struct extent_buffer *leaf; + struct btrfs_syno_subvol_usage_item *ei; + u64 bytenr, num_bytes; + int ret; + u8 type; + bool bl_free_fs_root = false; + + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + !test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + return 0; + + if (!list_empty(&root->syno_usage_rescan_list)) { + spin_lock(&fs_info->syno_usage_full_rescan_lock); + spin_lock(&fs_info->syno_usage_fast_rescan_lock); + if (!list_empty(&root->syno_usage_rescan_list)) { + list_del_init(&root->syno_usage_rescan_list); + bl_free_fs_root = true; + } + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + } + if (bl_free_fs_root) + btrfs_put_root(root); + syno_usage_wait_on_rescan(root); + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_USAGE_KEY; + key.offset = root->syno_usage_root_status.drop_progress.offset; + + if ((root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_NONE || root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_RO_SNAPSHOT) && + btrfs_comp_cpu_keys(&key, &root->syno_usage_root_status.fast_rescan_progress) < 0) { + key.offset = root->syno_usage_root_status.fast_rescan_progress.offset; + } + + while (1) { + trans = btrfs_start_transaction_fallback_global_rsv(fs_info->tree_root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + goto out; + } else if (ret > 0) { + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + } + } + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); + + spin_lock(&root->syno_usage_lock); + root->syno_usage_root_status.drop_progress = found_key; + root->syno_usage_root_status.drop_progress.offset = found_key.offset + 1; + key.offset = root->syno_usage_root_status.drop_progress.offset; + spin_unlock(&root->syno_usage_lock); + + if (found_key.objectid != BTRFS_SYNO_SUBVOL_USAGE_OBJECTID || found_key.type != SYNO_BTRFS_SUBVOL_USAGE_KEY) + break; + + /* if new_type is NONE , old type always is NONE, so we can skip it */ + if (root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_NONE) + break; + + if (btrfs_comp_cpu_keys(&found_key, &root->syno_usage_root_status.fast_rescan_progress) >= 0) { + if (root->syno_usage_root_status.type == SYNO_USAGE_TYPE_NONE || root->syno_usage_root_status.type == SYNO_USAGE_TYPE_RO_SNAPSHOT) + break; + type = root->syno_usage_root_status.type; + } else { + type = root->syno_usage_root_status.new_type; + } + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_subvol_usage_item); + bytenr = found_key.offset; + num_bytes = btrfs_syno_subvol_usage_num_bytes(leaf, ei); + btrfs_release_path(path); + + ret = btrfs_syno_extent_usage_free(trans, type, bytenr, num_bytes, 1, 0); + if (ret) + goto out; + + ret = btrfs_syno_usage_root_status_update(trans, root->root_key.objectid, &root->syno_usage_root_status); + if (ret) + goto out; + + btrfs_end_transaction_throttle(trans); + trans = NULL; + + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) +#ifdef MY_ABC_HERE + || !fs_info->snapshot_cleaner +#endif /* MY_ABC_HERE */ + ) { + btrfs_debug(fs_info, "drop subvol usage early exit"); + ret = -EAGAIN; + goto out; + } + cond_resched(); + } + btrfs_release_path(path); + ret = btrfs_syno_usage_root_status_remove(trans, root->root_key.objectid); + if (ret) + goto out; + spin_lock(&root->syno_usage_lock); + spin_lock(&fs_info->syno_usage_lock); + if (!(root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY)) { + if (fs_info->syno_usage_status.total_syno_subvol_usage_items >= root->syno_usage_root_status.total_syno_subvol_usage_items) + fs_info->syno_usage_status.total_syno_subvol_usage_items -= root->syno_usage_root_status.total_syno_subvol_usage_items; + else + fs_info->syno_usage_status.total_syno_subvol_usage_items = 0; + } + spin_unlock(&fs_info->syno_usage_lock); + spin_unlock(&root->syno_usage_lock); + clear_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state); +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + if (ret && ret != -EAGAIN) { + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to clear subvol usage item with root %llu err %d", root->root_key.objectid, ret); + } + return ret; +} + +int btrfs_syno_usage_ref_check(struct btrfs_root *root, u64 objectid, u64 offset) +{ + struct btrfs_key syno_usage_key; + int syno_usage = 0; + + if (test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + syno_usage = 1; + + if (syno_usage && root->syno_usage_root_status.state == SYNO_USAGE_ROOT_STATE_RESCAN) { + syno_usage_key.objectid = objectid; + syno_usage_key.type = BTRFS_EXTENT_DATA_KEY; + syno_usage_key.offset = offset; + read_lock(&root->syno_usage_rwlock); + if (btrfs_comp_cpu_keys(&syno_usage_key, &root->syno_usage_root_status.full_rescan_progress) >= 0) + syno_usage = 0; + read_unlock(&root->syno_usage_rwlock); + + if (!syno_usage) { + if ((root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_FORCE_EXTENT) || + btrfs_root_readonly(root)) + syno_usage = 2; + } + } + + return syno_usage; +} + +static int syno_usage_full_rescan_root_clear_unused_item(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path; + struct btrfs_key key; + int del_nr = 0; + int del_slot = 0; + int ret; + int recow; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_USAGE_KEY; + key.offset = 0; + + while (1) { + if (btrfs_root_readonly(root) || btrfs_root_dead(root)) { + ret = 1; + goto out; + } + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + recow = 0; + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; +next_slot: + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + BUG_ON(del_nr > 0); + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) { + ret = 0; + break; + } + recow = 1; + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + + if (key.objectid != BTRFS_SYNO_SUBVOL_USAGE_OBJECTID || + key.type != SYNO_BTRFS_SUBVOL_USAGE_KEY) + break; + + if (recow) { + btrfs_release_path(path); + goto next; + } + + if (del_nr == 0) { + del_slot = path->slots[0]; + del_nr = 1; + } else { + BUG_ON(del_slot + del_nr != path->slots[0]); + del_nr++; + } + + if (path->slots[0] + 1 < btrfs_header_nritems(path->nodes[0])) { + path->slots[0]++; + goto next_slot; + } + + ret = btrfs_del_items(trans, root, path, del_slot, del_nr); + if (ret) + goto out; + + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING) { + spin_lock(&fs_info->syno_usage_lock); + if (root->syno_usage_root_status.cur_full_rescan_size + fs_info->nodesize > root->syno_usage_root_status.total_full_rescan_size) { + root->syno_usage_root_status.total_full_rescan_size += fs_info->nodesize; + fs_info->syno_usage_status.total_full_rescan_size += fs_info->nodesize; + } + root->syno_usage_root_status.cur_full_rescan_size += fs_info->nodesize; + fs_info->syno_usage_status.cur_full_rescan_size += fs_info->nodesize; + spin_unlock(&fs_info->syno_usage_lock); + } + + del_nr = 0; + del_slot = 0; + btrfs_release_path(path); + +next: + btrfs_end_transaction_throttle(trans); + trans = NULL; + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + btrfs_debug(fs_info, "full rescan clear unused subvol usage early exit"); + ret = -EAGAIN; + goto out; + } + cond_resched(); + } + if (del_nr > 0) { + ret = btrfs_del_items(trans, root, path, del_slot, del_nr); + if (ret) + goto out; + } + btrfs_release_path(path); + + ret = 0; +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + if (ret < 0 && ret != -EAGAIN) + btrfs_warn_rl(fs_info, "Failed to clear unused subvol usage item with root %llu err %d", root->root_key.objectid, ret); + return ret; +} + +static int syno_usage_fast_rescan_root(struct btrfs_root *root) +{ + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_syno_subvol_usage_item *ei; + u64 bytenr, num_bytes; + struct btrfs_key first_key; + + first_key.objectid = 0; + first_key.type = 0; + first_key.offset = 0; + + set_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_FAST_RESCAN, &root->syno_usage_runtime_flags); + + if (btrfs_comp_cpu_keys(&first_key, &root->syno_usage_root_status.full_rescan_progress) == 0) { + ret = syno_usage_full_rescan_root_clear_unused_item(root); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = 0; + goto out; + } + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_USAGE_KEY; + key.offset = root->syno_usage_root_status.fast_rescan_progress.offset; + + while(1) { + if (btrfs_root_readonly(root) || btrfs_root_dead(root)) + goto success; + + trans = btrfs_start_transaction(root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + goto out; + } else if (ret > 0) { + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + } + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + + if (key.objectid != BTRFS_SYNO_SUBVOL_USAGE_OBJECTID || + key.type != SYNO_BTRFS_SUBVOL_USAGE_KEY) + break; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_subvol_usage_item); + bytenr = key.offset; + key.offset++; + num_bytes = btrfs_syno_subvol_usage_num_bytes(leaf, ei); + + spin_lock(&root->syno_usage_lock); + root->syno_usage_root_status.fast_rescan_progress = key; + spin_unlock(&root->syno_usage_lock); + + ret = btrfs_syno_extent_usage_add(trans, root->syno_usage_root_status.new_type, bytenr, num_bytes, 1); + if (ret) + goto inconsistent; + ret = btrfs_syno_extent_usage_free(trans, root->syno_usage_root_status.type, bytenr, num_bytes, 1, 0); + if (ret) + goto inconsistent; + + btrfs_release_path(path); + btrfs_end_transaction_throttle(trans); + trans = NULL; + + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + btrfs_debug(fs_info, "fast rescan subvol usage early exit"); + ret = -EAGAIN; + goto out; + } + cond_resched(); + } + + spin_lock(&root->syno_usage_lock); + root->syno_usage_root_status.fast_rescan_progress.objectid = -1; + root->syno_usage_root_status.fast_rescan_progress.type = -1; + root->syno_usage_root_status.fast_rescan_progress.offset = -1; + root->syno_usage_root_status.type = root->syno_usage_root_status.new_type; + spin_unlock(&root->syno_usage_lock); + +success: + ret = 0; +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + clear_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_FAST_RESCAN, &root->syno_usage_runtime_flags); + return ret; + +inconsistent: + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to fast rescan for syno usage with root %llu err:%d", root->root_key.objectid, ret); + goto out; +} + +static int syno_usage_full_rescan_root(struct btrfs_root *root) +{ + int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_file_extent_item *fi; + int extent_type; + u64 disk_bytenr; + u64 disk_num_bytes; + int processed_count; + struct btrfs_key first_key; + + first_key.objectid = 0; + first_key.type = 0; + first_key.offset = 0; + + set_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_FULL_RESCAN, &root->syno_usage_runtime_flags); + + if (btrfs_comp_cpu_keys(&first_key, &root->syno_usage_root_status.full_rescan_progress) == 0) { + ret = syno_usage_full_rescan_root_clear_unused_item(root); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = 0; + goto out; + } + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key = root->syno_usage_root_status.full_rescan_progress; + + while(1) { + if (btrfs_root_readonly(root) || btrfs_root_dead(root)) + goto success; + + trans = btrfs_start_transaction(root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + processed_count = 0; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; +next_slot: + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + if (processed_count == 0) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING) { + spin_lock(&fs_info->syno_usage_lock); + if (root->syno_usage_root_status.cur_full_rescan_size + root->fs_info->nodesize > root->syno_usage_root_status.total_full_rescan_size) { + root->syno_usage_root_status.total_full_rescan_size += root->fs_info->nodesize; + fs_info->syno_usage_status.total_full_rescan_size += root->fs_info->nodesize; + } + root->syno_usage_root_status.cur_full_rescan_size += root->fs_info->nodesize; + fs_info->syno_usage_status.cur_full_rescan_size += root->fs_info->nodesize; + spin_unlock(&fs_info->syno_usage_lock); + } + } else { + btrfs_release_path(path); + goto next; + } + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + processed_count++; + + key.offset++; + write_lock(&root->syno_usage_rwlock); + root->syno_usage_root_status.full_rescan_progress = key; + write_unlock(&root->syno_usage_rwlock); + key = root->syno_usage_root_status.full_rescan_progress; + if (key.objectid > BTRFS_LAST_FREE_OBJECTID) + break; + if (key.type != BTRFS_EXTENT_DATA_KEY) { + path->slots[0]++; + goto next_slot; + } + + leaf = path->nodes[0]; + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(leaf, fi); + + if (extent_type == BTRFS_FILE_EXTENT_REG || + extent_type == BTRFS_FILE_EXTENT_PREALLOC) { + disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); + disk_num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); + } else { + path->slots[0]++; + goto next_slot; + } + btrfs_release_path(path); + + ret = __btrfs_syno_subvol_usage_add(trans, root, disk_bytenr, disk_num_bytes, 1); + if (ret) + goto inconsistent; + +next: + btrfs_end_transaction_throttle(trans); + trans = NULL; + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + btrfs_debug(fs_info, "full rescan subvol usage early exit"); + ret = -EAGAIN; + goto out; + } + cond_resched(); + } + + write_lock(&root->syno_usage_rwlock); + root->syno_usage_root_status.full_rescan_progress.objectid = -1; + root->syno_usage_root_status.full_rescan_progress.type = -1; + root->syno_usage_root_status.full_rescan_progress.offset = -1; + write_unlock(&root->syno_usage_rwlock); + +success: + ret = 0; +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + clear_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_FULL_RESCAN, &root->syno_usage_runtime_flags); + return ret; + +inconsistent: + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to full rescan for syno usage with root %llu err:%d", root->root_key.objectid, ret); + goto out; +} + +#define SYNO_BTRFS_IOPRIO_FAST_RESCAN_USAGE (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 7)) +static void __btrfs_syno_usage_fast_rescan(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_root *root; + int ret = 0, err; + struct btrfs_key rescan_finish_key; + struct btrfs_trans_handle *trans = NULL; + int old_ioprio; + + fs_info = container_of(work, struct btrfs_fs_info, syno_usage_fast_rescan_work); + + fs_info->syno_usage_fast_rescan_pid = current->pid; + + old_ioprio = IOPRIO_PRIO_VALUE(task_nice_ioclass(current), + task_nice_ioprio(current)); + set_task_ioprio(current, SYNO_BTRFS_IOPRIO_FAST_RESCAN_USAGE); + + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_INITIAL || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + ret = -EAGAIN; + } + + rescan_finish_key.objectid = -1; + rescan_finish_key.type = -1; + rescan_finish_key.offset = -1; + + spin_lock(&fs_info->syno_usage_fast_rescan_lock); + while (!list_empty(&fs_info->syno_usage_pending_fast_rescan_roots)) { + root = list_first_entry(&fs_info->syno_usage_pending_fast_rescan_roots, struct btrfs_root, syno_usage_rescan_list); + list_del_init(&root->syno_usage_rescan_list); + if (ret || + root->syno_usage_root_status.state != SYNO_USAGE_ROOT_STATE_RESCAN || + root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_NONE || + root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_RO_SNAPSHOT || + btrfs_root_readonly(root) || + btrfs_root_dead(root)) { + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + goto next; + } + syno_usage_rescan_start(root); + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + + err = syno_usage_fast_rescan_root(root); + if (err) { + if (err != -EAGAIN) + btrfs_warn_rl(fs_info, "Failed to rescan syno suage with objectid:%llu, err:%d", root->root_key.objectid, err); + goto next; + } + err = syno_usage_full_rescan_root(root); + if (err) { + if (err != -EAGAIN) + btrfs_warn_rl(fs_info, "Failed to rescan syno suage with objectid:%llu, err:%d", root->root_key.objectid, err); + goto next; + } + if (!ret && btrfs_comp_cpu_keys(&rescan_finish_key, &root->syno_usage_root_status.fast_rescan_progress) == 0 && + btrfs_comp_cpu_keys(&rescan_finish_key, &root->syno_usage_root_status.full_rescan_progress) == 0) { + trans = btrfs_start_transaction(root, 0); + if (!IS_ERR(trans)) { + spin_lock(&root->syno_usage_lock); + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING) { + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.cur_full_rescan_size += root->syno_usage_root_status.total_full_rescan_size - root->syno_usage_root_status.cur_full_rescan_size; + root->syno_usage_root_status.cur_full_rescan_size = 0; + root->syno_usage_root_status.total_full_rescan_size = 0; + spin_unlock(&fs_info->syno_usage_lock); + } + root->syno_usage_root_status.state = SYNO_USAGE_ROOT_STATE_NORMAL; + root->syno_usage_root_status.flags &= ~(BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_MASK); + spin_unlock(&root->syno_usage_lock); + btrfs_end_transaction(trans); + } + } +next: + atomic_dec(&fs_info->syno_usage_pending_fast_rescan_count); + syno_usage_rescan_end(root); + btrfs_put_root(root); + cond_resched(); + spin_lock(&fs_info->syno_usage_fast_rescan_lock); + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) + ret = -EAGAIN; + } + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + + set_task_ioprio(current, old_ioprio); + + fs_info->syno_usage_fast_rescan_pid = 0; +} + +void btrfs_init_syno_usage_fast_rescan_work(struct work_struct *work) +{ + INIT_WORK(work, __btrfs_syno_usage_fast_rescan); +} + +static int syno_usage_extent_rescan(struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_root *extent_root = fs_info->extent_root; + struct btrfs_root *syno_extent_usage_root = fs_info->syno_extent_usage_root; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key key; + struct btrfs_key found_key; + int processed_count; + u64 bytenr; + u64 num_bytes; + u64 root_new_total_size; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key = fs_info->syno_usage_status.extent_rescan_progress; + + while(1) { + trans = btrfs_start_transaction(syno_extent_usage_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + processed_count = 0; + ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); + if (ret < 0) + goto out; +next_slot: + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + if (processed_count == 0) { + ret = btrfs_next_leaf(extent_root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + spin_lock(&fs_info->syno_usage_lock); + if (fs_info->syno_usage_status.extent_tree_cur_rescan_size + extent_root->fs_info->nodesize > fs_info->syno_usage_status.extent_tree_total_rescan_size) { + root_new_total_size = btrfs_root_used(&extent_root->root_item); + if (root_new_total_size > fs_info->syno_usage_status.extent_tree_total_rescan_size) { + fs_info->syno_usage_status.total_full_rescan_size += root_new_total_size - fs_info->syno_usage_status.extent_tree_total_rescan_size; + fs_info->syno_usage_status.extent_tree_total_rescan_size = root_new_total_size; + } + } + if (fs_info->syno_usage_status.extent_tree_cur_rescan_size + extent_root->fs_info->nodesize > fs_info->syno_usage_status.extent_tree_total_rescan_size) { + fs_info->syno_usage_status.extent_tree_total_rescan_size += extent_root->fs_info->nodesize; + fs_info->syno_usage_status.total_full_rescan_size += extent_root->fs_info->nodesize; + } + fs_info->syno_usage_status.extent_tree_cur_rescan_size += extent_root->fs_info->nodesize; + fs_info->syno_usage_status.cur_full_rescan_size += extent_root->fs_info->nodesize; + spin_unlock(&fs_info->syno_usage_lock); + } else { + btrfs_release_path(path); + btrfs_end_transaction_throttle(trans); + trans = NULL; + goto next; + } + } + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); + processed_count++; + + fs_info->syno_usage_status.extent_rescan_progress = found_key; + fs_info->syno_usage_status.extent_rescan_progress.offset = found_key.offset + 1; + key = fs_info->syno_usage_status.extent_rescan_progress; + if (found_key.type != BTRFS_EXTENT_ITEM_KEY) { + path->slots[0]++; + goto next_slot; + } + + bytenr = found_key.objectid; + num_bytes = found_key.offset; + + ret = btrfs_syno_extent_usage_add(trans, SYNO_USAGE_TYPE_RO_SNAPSHOT, bytenr, num_bytes, 0); + if (ret) + goto inconsistent; + + btrfs_release_path(path); + btrfs_end_transaction_throttle(trans); + trans = NULL; +next: + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + btrfs_debug(fs_info, "syno usage extent rescan early exit"); + ret = -EAGAIN; + goto out; + } + cond_resched(); + } + + fs_info->syno_usage_status.extent_rescan_progress.objectid = -1; + fs_info->syno_usage_status.extent_rescan_progress.type = -1; + fs_info->syno_usage_status.extent_rescan_progress.offset = -1; + ret = 0; +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + return ret; + +inconsistent: + fs_info->syno_usage_status.flags |= BTRFS_SYNO_USAGE_FLAG_INCONSISTENT; + btrfs_warn_rl(fs_info, "Failed to extent rescan for syno usage, err:%d", ret); + goto out; +} + +static void __btrfs_syno_usage_full_rescan(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + struct btrfs_root *root; + int ret = 0, err; + struct btrfs_key rescan_finish_key; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_syno_usage_status *usage_status; + + fs_info = container_of(work, struct btrfs_fs_info, syno_usage_full_rescan_work); + usage_status = &fs_info->syno_usage_status; + + fs_info->syno_usage_full_rescan_pid = current->pid; + + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + usage_status->state == SYNO_USAGE_STATE_INITIAL || + usage_status->state == SYNO_USAGE_STATE_RESCAN_ERROR || + usage_status->state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + ret = -EAGAIN; + } + + rescan_finish_key.objectid = -1; + rescan_finish_key.type = -1; + rescan_finish_key.offset = -1; + + spin_lock(&fs_info->syno_usage_full_rescan_lock); + while (!list_empty(&fs_info->syno_usage_pending_full_rescan_roots)) { + root = list_first_entry(&fs_info->syno_usage_pending_full_rescan_roots, struct btrfs_root, syno_usage_rescan_list); + list_del_init(&root->syno_usage_rescan_list); + if (ret || + root->syno_usage_root_status.state != SYNO_USAGE_ROOT_STATE_RESCAN || + root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_NONE || + root->syno_usage_root_status.new_type == SYNO_USAGE_TYPE_RO_SNAPSHOT || + btrfs_root_readonly(root) || + btrfs_root_dead(root)) { + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + goto next; + } + syno_usage_rescan_start(root); + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + + err = syno_usage_fast_rescan_root(root); + if (err) { + if (err != -EAGAIN) { + ret = err; + btrfs_warn_rl(fs_info, "Failed to rescan syno suage with objectid:%llu, err:%d", root->root_key.objectid, err); + } + goto next; + } + err = syno_usage_full_rescan_root(root); + if (err) { + if (err != -EAGAIN) { + ret = err; + btrfs_warn_rl(fs_info, "Failed to rescan syno suage with objectid:%llu, err:%d", root->root_key.objectid, err); + } + goto next; + } + if (!ret && btrfs_comp_cpu_keys(&rescan_finish_key, &root->syno_usage_root_status.fast_rescan_progress) == 0 && + btrfs_comp_cpu_keys(&rescan_finish_key, &root->syno_usage_root_status.full_rescan_progress) == 0) { + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto next; + } + spin_lock(&root->syno_usage_lock); + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING) { + spin_lock(&fs_info->syno_usage_lock); + usage_status->cur_full_rescan_size += root->syno_usage_root_status.total_full_rescan_size - root->syno_usage_root_status.cur_full_rescan_size; + root->syno_usage_root_status.cur_full_rescan_size = 0; + root->syno_usage_root_status.total_full_rescan_size = 0; + spin_unlock(&fs_info->syno_usage_lock); + } + root->syno_usage_root_status.state = SYNO_USAGE_ROOT_STATE_NORMAL; + root->syno_usage_root_status.flags &= ~(BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_MASK); + spin_unlock(&root->syno_usage_lock); + btrfs_end_transaction(trans); + } +next: + atomic_dec(&fs_info->syno_usage_pending_full_rescan_count); + syno_usage_rescan_end(root); + btrfs_put_root(root); + cond_resched(); + spin_lock(&fs_info->syno_usage_full_rescan_lock); + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + usage_status->state == SYNO_USAGE_STATE_RESCAN_PAUSE) + ret = -EAGAIN; + } + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + + if (!ret && + btrfs_comp_cpu_keys(&rescan_finish_key, &usage_status->extent_rescan_progress) != 0) + ret = syno_usage_extent_rescan(fs_info); + + if (!ret && + (usage_status->state == SYNO_USAGE_STATE_RESCAN || + usage_status->state == SYNO_USAGE_STATE_RESCAN_PAUSE) && + btrfs_comp_cpu_keys(&rescan_finish_key, &usage_status->extent_rescan_progress) == 0) { + usage_status->cur_full_rescan_size += usage_status->extent_tree_total_rescan_size - usage_status->extent_tree_cur_rescan_size; + usage_status->extent_tree_cur_rescan_size = 0; + usage_status->extent_tree_total_rescan_size = 0; + usage_status->cur_full_rescan_size = usage_status->total_full_rescan_size; + usage_status->state = SYNO_USAGE_STATE_ENABLE; + } + + if (ret && ret != -EAGAIN && (usage_status->state == SYNO_USAGE_STATE_RESCAN)) { + usage_status->state = SYNO_USAGE_STATE_RESCAN_ERROR; + usage_status->error_code = ret; + } + + fs_info->syno_usage_full_rescan_pid = 0; +} + +void btrfs_init_syno_usage_full_rescan_work(struct work_struct *work) +{ + INIT_WORK(work, __btrfs_syno_usage_full_rescan); +} + +static void __syno_usage_rescan_resume(struct btrfs_fs_info *fs_info) +{ + u64 root_objectid = 0; + struct btrfs_root *gang[8]; + int i = 0; + unsigned int ret = 0; + struct btrfs_root *subvol_root; + + while (1) { + spin_lock(&fs_info->fs_roots_radix_lock); + ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, + (void **)gang, root_objectid, + ARRAY_SIZE(gang)); + if (!ret) { + spin_unlock(&fs_info->fs_roots_radix_lock); + break; + } + root_objectid = gang[ret - 1]->root_key.objectid + 1; + + for (i = 0; i < ret; i++) { + /* Avoid to grab roots in dead_roots */ + if (btrfs_root_refs(&gang[i]->root_item) == 0) { + gang[i] = NULL; + continue; + } + /* grab all the search result for later use */ + gang[i] = btrfs_grab_root(gang[i]); + } + spin_unlock(&fs_info->fs_roots_radix_lock); + + for (i = 0; i < ret; i++) { + if (!gang[i]) + continue; + if (btrfs_root_readonly(gang[i])) + continue; + + subvol_root = gang[i]; + spin_lock(&subvol_root->syno_usage_lock); + spin_lock(&fs_info->syno_usage_full_rescan_lock); + spin_lock(&fs_info->syno_usage_fast_rescan_lock); + if (test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &subvol_root->state) && + subvol_root->syno_usage_root_status.state == SYNO_USAGE_ROOT_STATE_RESCAN && + subvol_root->syno_usage_root_status.new_type != SYNO_USAGE_TYPE_NONE && + subvol_root->syno_usage_root_status.new_type != SYNO_USAGE_TYPE_RO_SNAPSHOT && + !test_bit(SYNO_USAGE_ROOT_RUNTIME_FLAG_RESCAN, &subvol_root->syno_usage_runtime_flags) && + list_empty(&subvol_root->syno_usage_rescan_list)) { + btrfs_grab_root(subvol_root); + if (subvol_root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN) { + list_move_tail(&subvol_root->syno_usage_rescan_list, &fs_info->syno_usage_pending_full_rescan_roots); + atomic_inc(&fs_info->syno_usage_pending_full_rescan_count); + } else { + list_move_tail(&subvol_root->syno_usage_rescan_list, &fs_info->syno_usage_pending_fast_rescan_roots); + atomic_inc(&fs_info->syno_usage_pending_fast_rescan_count); + } + } + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + spin_unlock(&subvol_root->syno_usage_lock); + } + + for (i = 0; i < ret; i++) { + if (gang[i]) + btrfs_put_root(gang[i]); + } + } +} + +static int __syno_usage_rescan_preload(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_syno_usage_root_status_item *ei; + struct btrfs_key key; + int ret; + struct btrfs_root *subvol_root; + int processed_count; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + /* + * read all syno usage root + */ + key.objectid = 0; + key.type = SYNO_BTRFS_USAGE_ROOT_STATUS_KEY; + key.offset = 0; + + while(1) { + processed_count = 0; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; +next_slot: + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + if (processed_count == 0) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + } else { + goto next; + } + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + processed_count++; + + key.offset++; + if (key.type != SYNO_BTRFS_USAGE_ROOT_STATUS_KEY) { + path->slots[0]++; + goto next_slot; + } + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_usage_root_status_item); + if (btrfs_syno_usage_root_status_state(leaf, ei) != SYNO_USAGE_ROOT_STATE_RESCAN) { + path->slots[0]++; + goto next_slot; + } + if ((btrfs_syno_usage_root_status_flags(leaf, ei) & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY)) { + path->slots[0]++; + goto next_slot; + } + if (btrfs_syno_usage_root_status_new_type(leaf, ei) == SYNO_USAGE_TYPE_NONE || + btrfs_syno_usage_root_status_new_type(leaf, ei) == SYNO_USAGE_TYPE_RO_SNAPSHOT) { + path->slots[0]++; + goto next_slot; + } + btrfs_release_path(path); + + subvol_root = btrfs_get_fs_root(fs_info, key.objectid, true); + if (IS_ERR(subvol_root)) { + ret = PTR_ERR(subvol_root); + if (ret != -ENOENT) + btrfs_warn_rl(fs_info, "Failed to syno usage rescan, read fs root with objectid:%llu, err:%d", key.objectid, ret); + goto next; + } + btrfs_put_root(subvol_root); +next: + btrfs_release_path(path); + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) { + btrfs_debug(fs_info, "syno usage rescan resume early exit"); + ret = -EAGAIN; + goto out; + } + cond_resched(); + } + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +static void __btrfs_syno_usage_rescan(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info; + int ret = 0; + + fs_info = container_of(work, struct btrfs_fs_info, syno_usage_rescan_work); + + if (syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_INITIAL || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) + ret = -EAGAIN; + + if (!ret && !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_PRELOAD, &fs_info->flags)) { + ret = __syno_usage_rescan_preload(fs_info); + if (!ret) + set_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_PRELOAD, &fs_info->flags); + } + if (!ret && !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_CHECK_ALL, &fs_info->flags)) { + __syno_usage_rescan_resume(fs_info); + set_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_CHECK_ALL, &fs_info->flags); + } + + if (!list_empty(&fs_info->syno_usage_pending_fast_rescan_roots) && + !work_busy(&fs_info->syno_usage_fast_rescan_work)) + queue_work(system_unbound_wq, &fs_info->syno_usage_fast_rescan_work); + if (!list_empty(&fs_info->syno_usage_pending_full_rescan_roots) && + !work_busy(&fs_info->syno_usage_full_rescan_work)) + queue_work(system_unbound_wq, &fs_info->syno_usage_full_rescan_work); + if (!ret && (fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN) && + !work_busy(&fs_info->syno_usage_full_rescan_work)) + queue_work(system_unbound_wq, &fs_info->syno_usage_full_rescan_work); +} + +void btrfs_init_syno_usage_rescan_work(struct work_struct *work) +{ + INIT_WORK(work, __btrfs_syno_usage_rescan); +} + +void btrfs_syno_usage_rescan_resume(struct btrfs_fs_info *fs_info) +{ + if ((syno_usage_need_stop(fs_info) || + !test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_ERROR || + fs_info->syno_usage_status.state == SYNO_USAGE_STATE_RESCAN_PAUSE) && + list_empty(&fs_info->syno_usage_pending_fast_rescan_roots) && + list_empty(&fs_info->syno_usage_pending_full_rescan_roots)) + return; + if (work_busy(&fs_info->syno_usage_rescan_work)) + return; + queue_work(system_unbound_wq, &fs_info->syno_usage_rescan_work); +} + +void btrfs_syno_usage_root_initialize(struct btrfs_root *subvol_root) +{ + if (!test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &subvol_root->fs_info->flags) || + !is_fstree(subvol_root->root_key.objectid)) + return; + + spin_lock(&subvol_root->syno_usage_lock); + if (!test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &subvol_root->state)) { + btrfs_syno_usage_root_status_init(&subvol_root->syno_usage_root_status, + NULL, btrfs_root_readonly(subvol_root), true); + set_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &subvol_root->state); + } + spin_unlock(&subvol_root->syno_usage_lock); +} + +int syno_usage_clear_subvol_usage_item(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path; + struct btrfs_key key; + int del_nr = 0; + int del_slot = 0; + int ret; + int recow; + bool bl_free_fs_root = false; + + if (!list_empty(&root->syno_usage_rescan_list)) { + spin_lock(&fs_info->syno_usage_full_rescan_lock); + spin_lock(&fs_info->syno_usage_fast_rescan_lock); + if (!list_empty(&root->syno_usage_rescan_list)) { + list_del_init(&root->syno_usage_rescan_list); + bl_free_fs_root = true; + } + spin_unlock(&fs_info->syno_usage_fast_rescan_lock); + spin_unlock(&fs_info->syno_usage_full_rescan_lock); + } + if (bl_free_fs_root) + btrfs_put_root(root); + syno_usage_wait_on_rescan(root); + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_SUBVOL_USAGE_OBJECTID; + key.type = SYNO_BTRFS_SUBVOL_USAGE_KEY; + key.offset = 0; + + while (1) { + if (btrfs_root_readonly(root) || btrfs_root_dead(root)) { + trans = btrfs_start_transaction_fallback_global_rsv(fs_info->tree_root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + break; + } + + trans = btrfs_start_transaction_fallback_global_rsv(root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + recow = 0; + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; +next_slot: + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + BUG_ON(del_nr > 0); + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) { + ret = 0; + break; + } + recow = 1; + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + + if (key.objectid != BTRFS_SYNO_SUBVOL_USAGE_OBJECTID || + key.type != SYNO_BTRFS_SUBVOL_USAGE_KEY) + break; + + if (recow) { + btrfs_release_path(path); + goto next; + } + + if (del_nr == 0) { + del_slot = path->slots[0]; + del_nr = 1; + } else { + BUG_ON(del_slot + del_nr != path->slots[0]); + del_nr++; + } + + if (path->slots[0] + 1 < btrfs_header_nritems(path->nodes[0])) { + path->slots[0]++; + goto next_slot; + } + + ret = btrfs_del_items(trans, root, path, del_slot, del_nr); + if (ret) + goto out; + + spin_lock(&root->syno_usage_lock); + spin_lock(&fs_info->syno_usage_lock); + if (root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY) { + fs_info->syno_usage_status.total_syno_subvol_usage_items += root->syno_usage_root_status.total_syno_subvol_usage_items; + fs_info->syno_usage_status.total_full_rescan_size += root->syno_usage_root_status.total_syno_subvol_usage_items; + root->syno_usage_root_status.flags &= ~BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY; + } + + /* remove subvol syno subvol usage item count */ + if (root->syno_usage_root_status.total_syno_subvol_usage_items >= del_nr) + root->syno_usage_root_status.total_syno_subvol_usage_items -= del_nr; + else + root->syno_usage_root_status.total_syno_subvol_usage_items = 0; + + /* remove volume syno subvol usage item count */ + if (fs_info->syno_usage_status.total_syno_subvol_usage_items > del_nr) + fs_info->syno_usage_status.total_syno_subvol_usage_items -= del_nr; + else + fs_info->syno_usage_status.total_syno_subvol_usage_items = 0; + + /* add processed count for disable progress */ + fs_info->syno_usage_status.cur_full_rescan_size += del_nr; + if (fs_info->syno_usage_status.cur_full_rescan_size > fs_info->syno_usage_status.total_full_rescan_size) + fs_info->syno_usage_status.total_full_rescan_size = fs_info->syno_usage_status.cur_full_rescan_size; + spin_unlock(&fs_info->syno_usage_lock); + spin_unlock(&root->syno_usage_lock); + + del_nr = 0; + del_slot = 0; + btrfs_release_path(path); + +next: + btrfs_end_transaction_throttle(trans); + trans = NULL; + if (syno_usage_need_stop(fs_info)) { + btrfs_debug(fs_info, "drop subvol usage early exit"); + ret = -EAGAIN; + goto out; + } + if (fatal_signal_pending(current)) { + ret = -EINTR; + goto out; + } + cond_resched(); + } + if (del_nr > 0) { + ret = btrfs_del_items(trans, root, path, del_slot, del_nr); + if (ret) + goto out; + } + btrfs_release_path(path); + ret = btrfs_syno_usage_root_status_remove(trans, root->root_key.objectid); + if (ret) + goto out; + spin_lock(&root->syno_usage_lock); + spin_lock(&fs_info->syno_usage_lock); + if (!(root->syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY)) { + if (fs_info->syno_usage_status.total_syno_subvol_usage_items >= root->syno_usage_root_status.total_syno_subvol_usage_items) + fs_info->syno_usage_status.total_syno_subvol_usage_items -= root->syno_usage_root_status.total_syno_subvol_usage_items; + else + fs_info->syno_usage_status.total_syno_subvol_usage_items = 0; + + fs_info->syno_usage_status.cur_full_rescan_size += root->syno_usage_root_status.total_syno_subvol_usage_items; + if (fs_info->syno_usage_status.cur_full_rescan_size > fs_info->syno_usage_status.total_full_rescan_size) + fs_info->syno_usage_status.total_full_rescan_size = fs_info->syno_usage_status.cur_full_rescan_size; + } + spin_unlock(&fs_info->syno_usage_lock); + spin_unlock(&root->syno_usage_lock); + clear_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state); + + ret = 0; +out: + btrfs_free_path(path); + if (trans) + btrfs_end_transaction_throttle(trans); + if (ret && ret != -EAGAIN && ret != -EINTR) + btrfs_info(fs_info, "Failed to clear syno usage subvol item when disabling"); + return ret; +} + +static int syno_usage_clear_all_subvol_usage_item(struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_root *root = fs_info->syno_usage_root; + struct btrfs_path *path = NULL; + struct btrfs_key key; + struct btrfs_root *subvol_root; + int processed_count; + + if (!root) { + ret = 0; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + /* + * read all syno usage root + */ + key.objectid = 0; + key.type = SYNO_BTRFS_USAGE_ROOT_STATUS_KEY; + key.offset = 0; + + while (1) { + processed_count = 0; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; +next_slot: + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + if (processed_count == 0) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + } else { + btrfs_release_path(path); + goto next; + } + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + processed_count++; + + key.offset++; + if (key.type != SYNO_BTRFS_USAGE_ROOT_STATUS_KEY) { + path->slots[0]++; + goto next_slot; + } + btrfs_release_path(path); + + subvol_root = btrfs_get_fs_root(fs_info, key.objectid, true); + if (IS_ERR(subvol_root)) { + ret = PTR_ERR(subvol_root); + if (ret != -ENOENT) + btrfs_warn_rl(fs_info, "Failed to disable syno usage, read fs root with objectid:%llu, err:%d", key.objectid, ret); + goto next; + } + + ret = syno_usage_clear_subvol_usage_item(subvol_root); + btrfs_put_root(subvol_root); + if (ret) + goto out; +next: + if (syno_usage_need_stop(fs_info)) { + btrfs_debug(fs_info, "syno usage disable early exit"); + ret = -EAGAIN; + goto out; + } + if (fatal_signal_pending(current)) { + ret = -EINTR; + goto out; + } + cond_resched(); + } + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_syno_usage_disable(struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_trans_handle *trans = NULL; + int i; + + if (!fs_info->syno_usage_root && !fs_info->syno_extent_usage_root) { + ret = 0; + goto out; + } + + trans = btrfs_start_transaction(fs_info->tree_root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + /* disable syno usage */ + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); + + /* initialize disable progress */ + if (fs_info->syno_usage_status.state != SYNO_USAGE_STATE_DISABLE) { + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_DISABLE; + fs_info->syno_usage_status.cur_full_rescan_size = 0; + fs_info->syno_usage_status.total_full_rescan_size = fs_info->syno_usage_status.total_syno_extent_tree_items + fs_info->syno_usage_status.total_syno_subvol_usage_items; + } + + ret = btrfs_commit_transaction(trans); + trans = NULL; + if (ret) + goto out; + + ret = syno_usage_clear_all_subvol_usage_item(fs_info); + if (ret) + goto out; + + ret = btrfs_clear_extent_usage_tree(fs_info); + if (ret) + goto out; + + /* clear syno usage tree */ + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_NONE; + + trans = btrfs_start_transaction(fs_info->tree_root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + ret = btrfs_commit_transaction(trans); + trans = NULL; + if (ret) + goto out; + + ret = btrfs_clear_syno_usage_tree(fs_info); + if (ret) + goto out; + + spin_lock(&fs_info->syno_usage_lock); + for (i = SYNO_USAGE_TYPE_RO_SNAPSHOT; i < SYNO_USAGE_TYPE_MAX; i++) { + fs_info->syno_usage_status.syno_usage_type_num_bytes[i] = 0; + fs_info->syno_usage_status.syno_usage_type_num_bytes_valid[i] = false; + } + spin_unlock(&fs_info->syno_usage_lock); + +out: + return ret; +} + +static int syno_usage_enable_precheck(struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_super_block *disk_super = fs_info->super_copy; + u64 extent_tree_size; + struct btrfs_space_info *metadata_space_info = NULL, *tmp; + u64 used, total_used = 0, total_free = 0; + int metadata_ratio = 1; + int c; + + extent_tree_size = btrfs_root_used(&fs_info->extent_root->root_item); + + list_for_each_entry(tmp, &fs_info->space_info, list) { + total_used += tmp->disk_total; + if (tmp->flags == BTRFS_BLOCK_GROUP_METADATA) + metadata_space_info = tmp; + } + + if (!metadata_space_info) + goto success; + + down_read(&metadata_space_info->groups_sem); + for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { + if (!list_empty(&metadata_space_info->block_groups[c])) { + if (c == BTRFS_RAID_DUP) + metadata_ratio = 2; + break; + } + } + up_read(&metadata_space_info->groups_sem); + + used = metadata_space_info->bytes_used + metadata_space_info->bytes_reserved + + metadata_space_info->bytes_pinned + metadata_space_info->bytes_readonly + + metadata_space_info->bytes_may_use; + total_free += (metadata_space_info->total_bytes - used) * metadata_ratio; + + total_free += btrfs_super_total_bytes(disk_super) - total_used; + do_div(total_free, metadata_ratio); + + /* + * Space Required : + * 1. syno extent usage item (Similar to extent tree) + * 2. syno subvol usage item (Similar to extent tree) + * 3. global reserve : 2G (maximum) + */ + + if (total_free < (extent_tree_size * 2 + SZ_2G)) { + ret = -ENOSPC; + goto out; + } + +success: + ret = 0; +out: + return ret; +} + +int btrfs_syno_usage_enable(struct btrfs_fs_info *fs_info) +{ + int ret = 0; + struct btrfs_trans_handle *trans = NULL; + int i; + + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags)) + goto out; + + // clear old tree; + if (fs_info->syno_usage_root || fs_info->syno_extent_usage_root) { + ret = btrfs_syno_usage_disable(fs_info); + if (ret) + goto out; + } + + ret = syno_usage_enable_precheck(fs_info); + if (ret) + goto out; + + /* + * 2 - root node + * 2 - root item + */ + trans = btrfs_start_transaction(fs_info->tree_root, 4); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + ret = btrfs_create_syno_usage_tree(trans); + if (ret) { + btrfs_warn_rl(fs_info, "Failed to create syno usage tree, err:%d", ret); + goto out_abort; + } + + ret = btrfs_create_syno_extent_usage_tree(trans); + if (ret) { + btrfs_warn_rl(fs_info, "Failed to create syno extent usage tree, err:%d", ret); + goto out_abort; + } + + fs_info->syno_usage_status.version = BTRFS_SYNO_USAGE_STATUS_VERSION; + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_INITIAL; + fs_info->syno_usage_status.flags = 0; + fs_info->syno_usage_status.total_syno_subvol_usage_items = 0; + fs_info->syno_usage_status.total_syno_extent_tree_items = 0; + fs_info->syno_usage_status.extent_rescan_progress.objectid = 0; + fs_info->syno_usage_status.extent_rescan_progress.type = 0; + fs_info->syno_usage_status.extent_rescan_progress.offset = 0; + fs_info->syno_usage_status.extent_tree_cur_rescan_size = 0; + fs_info->syno_usage_status.extent_tree_total_rescan_size = btrfs_root_used(&fs_info->extent_root->root_item); + fs_info->syno_usage_status.cur_full_rescan_size = 0; + fs_info->syno_usage_status.total_full_rescan_size = fs_info->syno_usage_status.extent_tree_total_rescan_size; + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_PRELOAD, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_RESCAN_CHECK_ALL, &fs_info->flags); + + spin_lock(&fs_info->syno_usage_lock); + for (i = SYNO_USAGE_TYPE_RO_SNAPSHOT; i < SYNO_USAGE_TYPE_MAX; i++) { + fs_info->syno_usage_status.syno_usage_type_num_bytes[i] = 0; + fs_info->syno_usage_status.syno_usage_type_num_bytes_valid[i] = false; + } + spin_unlock(&fs_info->syno_usage_lock); + + set_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); + ret = btrfs_commit_transaction(trans); + trans = NULL; + if (ret) + goto out_recovery; + +out: + return ret; + +out_abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + goto out; + +out_recovery: + fs_info->syno_usage_status.state = SYNO_USAGE_STATE_NONE; + clear_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags); + goto out; +} + diff --git a/fs/btrfs/syno-feat-tree.c b/fs/btrfs/syno-feat-tree.c new file mode 100644 index 000000000000..fe62ed62b6c9 --- /dev/null +++ b/fs/btrfs/syno-feat-tree.c @@ -0,0 +1,367 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2020 Synology Inc. All rights reserved. + */ + +#include "ctree.h" +#include "xattr.h" +#include "transaction.h" +#include "btrfs_inode.h" +#include "syno-feat-tree.h" +#include "disk-io.h" +#include "locking.h" + +static inline int syno_feat_tree_update_helper(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct btrfs_key *key, + u32 data_size) +{ + int ret; + + ret = btrfs_search_slot(trans, root, key, path, 0, 1); + if (ret > 0) { + btrfs_release_path(path); + // insert new item + ret = btrfs_insert_empty_item(trans, root, path, key, data_size); + } + return ret; +} + +static int __btrfs_create_syno_feat_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_root *syno_feat_root; + + syno_feat_root = btrfs_create_tree(trans, BTRFS_SYNO_FEATURE_TREE_OBJECTID); + if (IS_ERR(syno_feat_root)) { + ret = PTR_ERR(syno_feat_root); + goto out; + } + fs_info->syno_feat_root = syno_feat_root; + + ret = 0; +out: + return ret; +} + +static int btrfs_syno_feat_tree_status_update(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_root *root = fs_info->syno_feat_root; + struct btrfs_path *path; + struct btrfs_key key; + int data_size; + struct extent_buffer *leaf; + struct btrfs_syno_feat_tree_status_item *ei; + + if (!btrfs_syno_check_feat_tree_enable(fs_info)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_FEAT_TREE_STATUS_OBJECTID; + key.type = SYNO_BTRFS_FEAT_TREE_STATUS_KEY; + key.offset = 0; + + data_size = sizeof(struct btrfs_syno_feat_tree_status_item); + + ret = syno_feat_tree_update_helper(trans, root, path, &key, data_size); + if (ret < 0) + goto out; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_feat_tree_status_item); + btrfs_set_syno_feat_tree_status_version(leaf, ei, fs_info->syno_feat_tree_status.version); + btrfs_set_syno_feat_tree_status_status(leaf, ei, fs_info->syno_feat_tree_status.status); + + btrfs_mark_buffer_dirty(path->nodes[0]); +out: + if (ret) + btrfs_abort_transaction(trans, ret); + btrfs_free_path(path); + return ret; +} + +static int btrfs_create_syno_feat_tree(struct btrfs_fs_info *fs_info) +{ + struct btrfs_trans_handle *trans = NULL; + struct btrfs_root *tree_root = fs_info->tree_root; + int ret; + + trans = btrfs_start_transaction(tree_root, 3); + if (IS_ERR(trans)) { + return PTR_ERR(trans); + } + + /* root item x 1 + root node x 1 */ + ret = __btrfs_create_syno_feat_tree(trans, fs_info); + if (ret) { + btrfs_err(fs_info, "failed to create syno feature tree, ret=[%d]", ret); + goto out; + } + + btrfs_syno_set_feat_tree_enable(fs_info); + + /* tree item x 1 */ + ret = btrfs_syno_feat_tree_status_update(trans, fs_info); + if (ret) { + btrfs_err(fs_info, "failed to update status of syno feature tree at the first time, ret=[%d]", ret); + btrfs_syno_set_feat_tree_disable(fs_info); + goto out; + } + + return btrfs_commit_transaction(trans); + +out: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_syno_feat_tree_enable(struct btrfs_fs_info *fs_info) +{ + int ret = -1; + + if (btrfs_syno_check_feat_tree_enable(fs_info)) { + ret = 0; + goto out; + } + +#ifdef MY_ABC_HERE + /* + * Don't clean up existing feature-tree + */ +#else + btrfs_syno_set_feat_tree_disable(fs_info); + + // clean up old tree + if (fs_info->syno_feat_root) { + btrfs_err(fs_info, "we are going to clean up syno feature tree because the status is not enabled"); + ret = btrfs_syno_feat_tree_disable(fs_info); + if (ret) { + btrfs_err(fs_info, "failed to disable and clean up syno feature tree, ret: [%d].", ret); + goto out; + } + } +#endif /* MY_ABC_HERE */ + + ret = btrfs_create_syno_feat_tree(fs_info); + if (ret) { + btrfs_err(fs_info, "failed to create syno feature tree, ret: [%d].", ret); + goto out; + } + + ret = 0; +out: + return ret; +} + +static inline int syno_feat_tree_need_stop(struct btrfs_fs_info *fs_info) +{ + return sb_rdonly(fs_info->sb) || btrfs_fs_closing(fs_info); +} + +#ifdef MY_ABC_HERE + /* + * locker will store information in feature-tree, and we cannot provide any + * abilities to remove feature-tree. + */ +#else +static int btrfs_clear_syno_feat_tree(struct btrfs_fs_info *fs_info) +{ + struct btrfs_trans_handle *trans; + struct btrfs_root *root = fs_info->syno_feat_root; + struct btrfs_path *path; + struct btrfs_key key; + int nr; + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.type = 0; + key.offset = 0; + + while (1) { + trans = btrfs_start_transaction_fallback_global_rsv(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto end_trans; + + nr = btrfs_header_nritems(path->nodes[0]); + if (!nr) + break; + + path->slots[0] = 0; + ret = btrfs_del_items(trans, root, path, 0, nr); + if (ret) { + btrfs_err(root->fs_info, "failed to delete item of syno feature tree, ret: [%d].", ret); + goto end_trans; + } + + btrfs_release_path(path); + ret = btrfs_end_transaction_throttle(trans); + if (ret) + goto out; + trans = NULL; + + if (syno_feat_tree_need_stop(root->fs_info)) { + ret = -EAGAIN; + btrfs_debug(root->fs_info, "drop tree early exit, ret: [%d].", ret); + goto out; + } + if (fatal_signal_pending(current)) { + btrfs_debug(root->fs_info, "catch interrupt singal as cleaning up syno feature tree."); + ret = -EINTR; + goto out; + } + } + + ret = 0; +end_trans: + if (trans) + btrfs_end_transaction_throttle(trans); +out: + btrfs_free_path(path); + return ret; +} + +static int btrfs_delete_syno_feat_tree_root(struct btrfs_fs_info *fs_info) +{ + struct btrfs_trans_handle *trans; + struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *syno_feat_root = fs_info->syno_feat_root; + int ret; + + trans = btrfs_start_transaction(tree_root, 0); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + fs_info->syno_feat_root = NULL; + + ret = btrfs_del_root(trans, &syno_feat_root->root_key); + if (ret) { + btrfs_err(fs_info, "failed to delete the root item about syno feature tree, ret: [%d].", ret); + goto abort; + } + + list_del(&syno_feat_root->dirty_list); + + btrfs_tree_lock(syno_feat_root->node); + btrfs_clean_tree_block(syno_feat_root->node); + btrfs_tree_unlock(syno_feat_root->node); + btrfs_free_tree_block(trans, syno_feat_root, syno_feat_root->node, 0, 1); + + btrfs_put_root(syno_feat_root); + + return btrfs_commit_transaction(trans); + +abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_syno_feat_tree_disable(struct btrfs_fs_info *fs_info) +{ + int ret; + + if (!fs_info->syno_feat_root) { + ret = 0; + goto out; + } + + btrfs_syno_set_feat_tree_disable(fs_info); + + ret = btrfs_clear_syno_feat_tree(fs_info); + if (ret) { + btrfs_err(fs_info, "failed to clean up syno feature tree, ret: [%d].", ret); + goto out; + } + + ret = btrfs_delete_syno_feat_tree_root(fs_info); + if (ret) { + btrfs_err(fs_info, "failed to delete syno feature tree root, ret: [%d].", ret); + goto out; + } + btrfs_info(fs_info, "have finished to clean up syno feature tree, ret: [%d].", ret); + + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +int btrfs_syno_feat_tree_load_status_from_disk(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *root = fs_info->syno_feat_root; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_syno_feat_tree_status_item *ei; + struct btrfs_key key; + struct btrfs_key found_key; + int ret; + + if (!fs_info->syno_feat_root) { + btrfs_info(fs_info, "root of syno feature tree is null"); + return 0; + } + + path = btrfs_alloc_path(); + if (!path) { + btrfs_err(fs_info, "failed to allocate path, err: [%ld]", PTR_ERR(path)); + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_SYNO_FEAT_TREE_STATUS_OBJECTID; + key.type = SYNO_BTRFS_FEAT_TREE_STATUS_KEY; + key.offset = 0; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + btrfs_err(fs_info, "failed to search slot on syno feature tree, ret: [%d].", ret); + goto out; + } else if (ret > 0) { /* tree empty */ + btrfs_warn(fs_info, "feature tree is empty."); + ret = 0; + goto out; + } + + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_syno_feat_tree_status_item); + fs_info->syno_feat_tree_status.version = btrfs_syno_feat_tree_status_version(leaf, ei); + fs_info->syno_feat_tree_status.status = btrfs_syno_feat_tree_status_status(leaf, ei); + + switch(fs_info->syno_feat_tree_status.status) { + case SYNO_FEAT_TREE_ST_ENABLE: + btrfs_info(fs_info, "syno feature tree is enabled"); + break; + case SYNO_FEAT_TREE_ST_DISABLE: + btrfs_warn(fs_info, "disable status [%llx] has detected. We are going to clean up feautre tree.", fs_info->syno_feat_tree_status.status); + break; + default: + btrfs_err(fs_info, "invalid status [%llx] of syno feature tree has detected.", fs_info->syno_feat_tree_status.status); + break; + } + + ret = 0; +out: + btrfs_free_path(path); + return ret; +} diff --git a/fs/btrfs/syno-feat-tree.h b/fs/btrfs/syno-feat-tree.h new file mode 100644 index 000000000000..5895070f0e64 --- /dev/null +++ b/fs/btrfs/syno-feat-tree.h @@ -0,0 +1,38 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2020 Synology Inc. All rights reserved. + */ + +#ifndef __BTRFS_SYNO_FEAT_TREE_H_ +#define __BTRFS_SYNO_FEAT_TREE_H_ + +#include "ctree.h" +#include "xattr.h" +#include "transaction.h" +#include "btrfs_inode.h" + +#define __set_feat_tree_status(fs_info, feat_tree_st) \ +do { \ + fs_info->syno_feat_tree_status.status = feat_tree_st; \ +} while(0) \ + +#define btrfs_syno_set_feat_tree_enable(fs_info) \ + __set_feat_tree_status(fs_info, SYNO_FEAT_TREE_ST_ENABLE) +#define btrfs_syno_set_feat_tree_disable(fs_info) \ + __set_feat_tree_status(fs_info, SYNO_FEAT_TREE_ST_DISABLE) + +#define btrfs_syno_check_feat_tree_enable(fs_info) \ + ((fs_info->syno_feat_root) && \ + (SYNO_FEAT_TREE_ST_ENABLE == fs_info->syno_feat_tree_status.status)) + +int btrfs_syno_feat_tree_enable(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +#define btrfs_syno_feat_tree_disable(...) +#else +int btrfs_syno_feat_tree_disable(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ +int btrfs_syno_feat_tree_load_status_from_disk(struct btrfs_fs_info *fs_info); + +#endif /* __BTRFS_SYNO_FEAT_TREE_H_ */ diff --git a/fs/btrfs/syno-locker.c b/fs/btrfs/syno-locker.c new file mode 100644 index 000000000000..d5a0874d8a28 --- /dev/null +++ b/fs/btrfs/syno-locker.c @@ -0,0 +1,1948 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000-2022 Synology Inc. + */ + +#include +#include +#include +#include +#include + +#include "ctree.h" +#include "backref.h" +#include "disk-io.h" +#include "btrfs_inode.h" +#include "syno-feat-tree.h" + +static bool locker_feature_support = true; +extern struct file_system_type *__btrfs_root_fs_type; + +bool btrfs_syno_locker_feature_is_support(void) +{ + return locker_feature_support; +} + +/* + * runtime disable locker only if no volume is mounted + */ +int btrfs_syno_locker_feature_disable(void) +{ + /* btrfs_root_fs_type isn't registered and cannot get from get_fs_type */ + if (!hlist_empty(&__btrfs_root_fs_type->fs_supers)) + return 1; + + if (locker_feature_support) { + locker_feature_support = false; + pr_info("BTRFS: locker disabled\n"); + } + + return 0; +} + +static inline void __maybe_unused __dump_locker_root(struct btrfs_root* root) +{ + btrfs_debug(root->fs_info, "root-id=%llu, enabled=%u, mode=%d, def-state=%d, wait-t=%lld, dura=%lld\n", + root->root_key.objectid, root->locker_enabled, root->locker_mode, + root->locker_default_state, root->locker_waittime, root->locker_duration); +} + +static inline void __maybe_unused __dump_locker_inode(struct btrfs_inode* binode) +{ + btrfs_debug(binode->root->fs_info, "ino=%lu, state=%d, update-t=%lld, begin=%lld, end=%lld\n", + binode->vfs_inode.i_ino, binode->locker_state, binode->locker_update_time, + binode->locker_period_begin, binode->locker_period_end); +} + +static inline bool btrfs_is_ro_snapshot(struct btrfs_inode *binode) +{ + if (btrfs_ino(binode) != BTRFS_FIRST_FREE_OBJECTID) + return false; + + if (!btrfs_root_readonly(binode->root)) + return false; + + return true; +} + +static inline bool syno_locker_is_fs_clock_initialized(struct btrfs_fs_info *fs_info) +{ + lockdep_assert_held(&fs_info->locker_lock); + + return fs_info->locker_clock.tv_sec != 0; +} + +static inline void syno_locker_fs_clock_init(struct btrfs_fs_info *fs_info) +{ + spin_lock(&fs_info->locker_lock); + /* clock can only be initialized once */ + if (!syno_locker_is_fs_clock_initialized(fs_info)) { + ktime_get_real_ts64(&fs_info->locker_clock); + ktime_get_raw_ts64(&fs_info->locker_prev_raw_clock); + } + spin_unlock(&fs_info->locker_lock); +} + +/* + * tick the raw fs clock and return the time. please do not access + * fs_info->locker_clock directly, or it'll not tick. + */ +struct timespec64 btrfs_syno_locker_fs_clock_get(struct btrfs_fs_info *fs_info) +{ + struct timespec64 raw_time, delta; + + spin_lock(&fs_info->locker_lock); + + /* uninitialized clock will not tick */ + if (!syno_locker_is_fs_clock_initialized(fs_info)) + goto out; + + ktime_get_raw_ts64(&raw_time); + delta = timespec64_sub(raw_time, fs_info->locker_prev_raw_clock); + fs_info->locker_clock = timespec64_add(fs_info->locker_clock, delta); + fs_info->locker_prev_raw_clock = raw_time; + +out: + spin_unlock(&fs_info->locker_lock); + + return fs_info->locker_clock; +} + +static inline struct timespec64 syno_locker_root_clock_get(struct btrfs_root *root) +{ + struct timespec64 clock = {0}; + +#ifdef MY_ABC_HERE + if (btrfs_root_readonly(root)) { + /* + * if subvolume clock is enabled, the clock is frozen in ro snapshot. + * locker_update_time_floor was borrowed to store the frozen clock. + */ + spin_lock(&root->locker_lock); + clock.tv_sec = root->locker_update_time_floor; + spin_unlock(&root->locker_lock); + + return clock; + } +#endif /* MY_ABC_HERE */ + + clock = btrfs_syno_locker_fs_clock_get(root->fs_info); + +#ifdef MY_ABC_HERE + spin_lock(&root->locker_lock); + clock.tv_sec += root->locker_clock_adjustment; + spin_unlock(&root->locker_lock); +#endif /* MY_ABC_HERE */ + + return clock; +} + +static inline struct timespec64 syno_locker_clock_get(struct btrfs_inode *binode) +{ + /* + * subvolumes always refers to fs_clock, because root_clock may not tick for + * ro snapshot if SUBVOLUME clock is enable. + */ + if (btrfs_ino(binode) == BTRFS_FIRST_FREE_OBJECTID) + return btrfs_syno_locker_fs_clock_get(binode->root->fs_info); + + return syno_locker_root_clock_get(binode->root); +} + +/* + * return the delta between system clock and volume clock + * + * delta = sys_clock - vol_clock + * vol_clock = sys_clock - delta + * sys_clock = vol_clock + delta + */ +static inline struct timespec64 +syno_locker_sys_clock_delta(struct btrfs_inode *binode) +{ + struct timespec64 vol_clock, sys_clock, delta; + + vol_clock = syno_locker_clock_get(binode); + WARN_ON(vol_clock.tv_sec == 0); + + ktime_get_real_ts64(&sys_clock); + delta = timespec64_sub(sys_clock, vol_clock); + + return delta; +} + +void btrfs_syno_locker_update_work_kick(struct btrfs_fs_info *fs_info) +{ + if (btrfs_fs_closing(fs_info)) + return; + + mod_delayed_work(system_wq, &fs_info->locker_update_work, fs_info->locker_update_interval * HZ); +} + +void btrfs_syno_locker_update_work_fn(struct work_struct *work) +{ + struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, locker_update_work.work); + + if (sb_rdonly(fs_info->sb) || !btrfs_fs_compat_ro(fs_info, LOCKER)) { + btrfs_syno_locker_update_work_kick(fs_info); + return; + } + + btrfs_set_pending(fs_info, COMMIT); + btrfs_sync_fs(fs_info->sb, 1); + btrfs_info(fs_info, "force to update superblock (%llu)", fs_info->generation); +} + +static inline bool is_lockable(struct btrfs_inode *binode) +{ + return test_bit(BTRFS_INODE_LOCKER_LOCKABLE, &binode->runtime_flags); +} + +static inline bool is_nolock(struct btrfs_inode *binode) +{ + return test_bit(BTRFS_INODE_LOCKER_NOLOCK, &binode->runtime_flags); +} + +static inline bool is_lockable_unknown(struct btrfs_inode *binode) +{ + return !is_lockable(binode) && !is_nolock(binode); +} + +static inline void set_lockable(struct btrfs_inode *binode) +{ + set_bit(BTRFS_INODE_LOCKER_LOCKABLE, &binode->runtime_flags); + clear_bit(BTRFS_INODE_LOCKER_NOLOCK, &binode->runtime_flags); +} + +static inline void set_nolock(struct btrfs_inode *binode) +{ + set_bit(BTRFS_INODE_LOCKER_NOLOCK, &binode->runtime_flags); + clear_bit(BTRFS_INODE_LOCKER_LOCKABLE, &binode->runtime_flags); +} + +static inline bool d_is_subvolume(struct dentry *dentry) +{ + return btrfs_ino(BTRFS_I(d_inode(dentry))) == BTRFS_FIRST_FREE_OBJECTID; +} + +#define LOCKER_PREFIX_EADIR "@eaDir" +#define LOCKER_PREFIX_TMP "@tmp" +#define LOCKER_PREFIX_SHAREBIN "@sharebin" +#define LOCKER_PREFIX_RECYCLE "#recycle" + +static struct qstr nolock_name[] = { + QSTR_INIT(LOCKER_PREFIX_EADIR, sizeof(LOCKER_PREFIX_EADIR) - 1), + QSTR_INIT(LOCKER_PREFIX_TMP, sizeof(LOCKER_PREFIX_TMP) - 1), + QSTR_INIT(LOCKER_PREFIX_SHAREBIN, sizeof(LOCKER_PREFIX_SHAREBIN) - 1), + QSTR_INIT(LOCKER_PREFIX_RECYCLE, sizeof(LOCKER_PREFIX_RECYCLE) - 1), +}; + +/* + * if a btrfs inode is not a lockable object, such as regular file, symbolic + * link, or a ro snapshot, it won't be lockable. + * + * if a btrfs inode is whitelisted, it won't be lockable either. a runtime flag + * will also be marked on this btrfs inode. + */ +static bool syno_locker_is_whitelisted(struct btrfs_inode *binode) +{ + int i = 0; + bool lockable = true; + struct dentry *p = NULL, *pp = NULL; + struct btrfs_inode *ancestor; + struct super_block *sb = binode->vfs_inode.i_sb; + + /* + * to reduce the overhead, inode with multiple links doesn't be treated + * as whitelisted, even all the paths comply with the patterns. + */ + if (binode->vfs_inode.i_nlink != 1) { + goto out; + } + + p = d_find_any_alias(&binode->vfs_inode); + if (!p) + goto out; + + pp = dget_parent(p); + while (true) { + if (!pp || d_really_is_negative(pp) || sb != pp->d_sb) + goto out; + + if (d_is_subvolume(pp)) + break; + + /* + * it won't be a fs root because we'll reach subvolume root first. + * if we meet the condition, it'll be a disconnected dentry from nfs, + * but it should not happen. + */ + if (IS_ROOT(pp)) { + if (pp->d_flags & DCACHE_DISCONNECTED) + pr_warn_ratelimited("locker: %pd is disconnected.", pp); + goto out; + } + + dput(p); + p = pp; + pp = dget_parent(p); + } + + ancestor = BTRFS_I(d_inode(p)); + if (!is_lockable_unknown(ancestor)) { + lockable = is_lockable(ancestor); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(nolock_name); ++i) { + if (!strcmp(nolock_name[i].name, p->d_name.name)) { + set_nolock(ancestor); + lockable = false; + goto out; + } + } + + set_lockable(ancestor); +out: + dput(p); + dput(pp); + + return !lockable; +} + +/* + * regardless of whitelisted, only regular files, soft links and ro + * snapshots are supported objects. + */ +static inline bool syno_locker_is_lockable_object(struct btrfs_inode *binode) +{ + struct inode *inode = &binode->vfs_inode; + + if (!btrfs_is_ro_snapshot(binode) && btrfs_root_readonly(binode->root)) + return false; + + return S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode) || btrfs_is_ro_snapshot(binode); +} + +int btrfs_syno_locker_disk_root_update(struct btrfs_trans_handle *trans, struct btrfs_root *root) +{ + int ret; + struct btrfs_key key; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_root_locker_item *item; + struct btrfs_root *feat_root = root->fs_info->syno_feat_root; + + key.objectid = BTRFS_SYNO_BTRFS_LOCKER_OBJECTID; + key.type = BTRFS_ROOT_LOCKER_KEY; + key.offset = root->root_key.objectid; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + ret = btrfs_search_slot(trans, feat_root, &key, path, 0, 1); + if (ret > 0) { + btrfs_release_path(path); + ret = btrfs_insert_empty_item(trans, feat_root, path, &key, sizeof(*item)); + if (ret) + goto out; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_locker_item); + memzero_extent_buffer(leaf, (unsigned long)item, sizeof(*item)); + } else if (ret == 0) { + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_locker_item); + } else + goto out; + + spin_lock(&root->locker_lock); + btrfs_set_root_locker_enabled(leaf, item, root->locker_enabled); + btrfs_set_root_locker_mode(leaf, item, root->locker_mode); + btrfs_set_root_locker_default_state(leaf, item, root->locker_default_state); + btrfs_set_root_locker_waittime(leaf, item, root->locker_waittime); + btrfs_set_root_locker_duration(leaf, item, root->locker_duration); + btrfs_set_root_locker_clock_adjustment(leaf, item, root->locker_clock_adjustment); + btrfs_set_root_locker_update_time_floor(leaf, item, root->locker_update_time_floor); + btrfs_set_root_locker_state(leaf, item, root->locker_state); + btrfs_set_root_locker_period_begin(leaf, item, root->locker_period_begin); + btrfs_set_root_locker_period_begin_sys(leaf, item, root->locker_period_begin_sys); + btrfs_set_root_locker_period_end(leaf, item, root->locker_period_end); + btrfs_set_root_locker_period_end_sys(leaf, item, root->locker_period_end_sys); + spin_unlock(&root->locker_lock); + + btrfs_mark_buffer_dirty(path->nodes[0]); + + ret = 0; +out: + btrfs_free_path(path); + + if (!ret) + btrfs_set_fs_compat_ro(root->fs_info, LOCKER); + + return ret; +} + +static int btrfs_syno_locker_disk_root_update_trans(struct btrfs_root *root) +{ + int ret; + struct btrfs_trans_handle *trans; + struct btrfs_root *feat_root = root->fs_info->syno_feat_root; + + if (!btrfs_syno_check_feat_tree_enable(root->fs_info)) + return -EPERM; + + trans = btrfs_start_transaction(feat_root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + ret = btrfs_syno_locker_disk_root_update(trans, root); + if (ret) { + btrfs_err(root->fs_info, "failed to update disk root locker item. err=%d", ret); + goto abort; + } + + return btrfs_commit_transaction(trans); + +abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_syno_locker_disk_root_read(struct btrfs_root *root) +{ + int ret; + struct btrfs_key key; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_root_locker_item *item; + struct btrfs_root *feat_root = root->fs_info->syno_feat_root; + + if (!btrfs_syno_check_feat_tree_enable(root->fs_info)) + return 0; + + key.objectid = BTRFS_SYNO_BTRFS_LOCKER_OBJECTID; + key.type = BTRFS_ROOT_LOCKER_KEY; + key.offset = root->root_key.objectid; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + ret = btrfs_search_slot(NULL, feat_root, &key, path, 0, 0); + if (ret) + goto out; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_locker_item); + + spin_lock(&root->locker_lock); + root->locker_enabled = btrfs_root_locker_enabled(leaf, item); + root->locker_mode = btrfs_root_locker_mode(leaf, item); + root->locker_default_state = btrfs_root_locker_default_state(leaf, item); + root->locker_waittime = btrfs_root_locker_waittime(leaf, item); + root->locker_duration = btrfs_root_locker_duration(leaf, item); + root->locker_clock_adjustment = btrfs_root_locker_clock_adjustment(leaf, item); + root->locker_update_time_floor = btrfs_root_locker_update_time_floor(leaf, item); + root->locker_state = btrfs_root_locker_state(leaf, item); + root->locker_period_begin = btrfs_root_locker_period_begin(leaf, item); + root->locker_period_begin_sys = btrfs_root_locker_period_begin_sys(leaf, item); + root->locker_period_end = btrfs_root_locker_period_end(leaf, item); + root->locker_period_end_sys = btrfs_root_locker_period_end_sys(leaf, item); + spin_unlock(&root->locker_lock); + +out: + btrfs_free_path(path); + return ret; +} + +/* + * find if there's any root_locker_item + * + * @return: 1 has root_locker_item + * 0 no root_locker_item + * <0 error + */ +static int syno_locker_has_root_locker_item(struct btrfs_fs_info *fs_info) +{ + int ret; + int slot; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_path *path; + struct btrfs_item *item; + struct extent_buffer *leaf; + struct btrfs_root *feat_root = fs_info->syno_feat_root; + + key.objectid = BTRFS_SYNO_BTRFS_LOCKER_OBJECTID; + key.type = BTRFS_ROOT_LOCKER_KEY; + key.offset = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ret = btrfs_search_slot(NULL, feat_root, &key, path, 0, 0); + if (ret < 0) + goto out; + + while (1) { + leaf = path->nodes[0]; + slot = path->slots[0]; + if (slot >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(feat_root, path); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; + goto out; + } + continue; + } + + item = btrfs_item_nr(slot); + btrfs_item_key_to_cpu(leaf, &found_key, slot); + + if (found_key.type == BTRFS_ROOT_LOCKER_KEY) { + ret = 1; + break; + } + + path->slots[0]++; + } + +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_syno_locker_disk_root_delete(struct btrfs_trans_handle *trans, struct btrfs_root *root) +{ + int ret; + struct btrfs_key key; + struct btrfs_path *path; + struct btrfs_root *feat_root = root->fs_info->syno_feat_root; + + key.objectid = BTRFS_SYNO_BTRFS_LOCKER_OBJECTID; + key.type = BTRFS_ROOT_LOCKER_KEY; + key.offset = root->root_key.objectid; + + if (!btrfs_syno_check_feat_tree_enable(root->fs_info)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + ret = btrfs_search_slot(trans, feat_root, &key, path, -1, 1); + if (ret < 0) + goto out; + else if (ret) { + ret = 0; + goto out; + } + + ret = btrfs_del_item(trans, feat_root, path); + if (ret) + goto out; + + ret = 0; +out: + btrfs_free_path(path); + + if (0 == syno_locker_has_root_locker_item(root->fs_info)) + btrfs_clear_fs_compat_ro(root->fs_info, LOCKER); + + return ret; +} + +int btrfs_syno_locker_disk_root_delete_trans(struct btrfs_root *root) +{ + int ret = 0; + struct btrfs_trans_handle *trans; + + if (!btrfs_syno_check_feat_tree_enable(root->fs_info)) + return 0; + + trans = btrfs_start_transaction(root->fs_info->syno_feat_root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + ret = btrfs_syno_locker_disk_root_delete(trans, root); + if (ret) { + btrfs_err(root->fs_info, "failed to delete disk root locker item. err=%d", ret); + goto abort; + } + + return btrfs_commit_transaction(trans); + +abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_syno_locker_snapshot_clone(struct btrfs_trans_handle *trans, + struct btrfs_root *dest, struct btrfs_root *source) +{ + bool dest_ro = btrfs_root_readonly(dest); + bool source_ro = btrfs_root_readonly(source); + + if (source->locker_mode == LM_NONE) + return 0; + + spin_lock(&source->locker_lock); + + /* locker is always disabled with new cloned subvolumes */ + dest->locker_enabled = 0; + dest->locker_mode = source->locker_mode; + dest->locker_default_state = source->locker_default_state; + dest->locker_waittime = source->locker_waittime; + dest->locker_duration = source->locker_duration; + dest->locker_clock_adjustment = source->locker_clock_adjustment; + dest->locker_update_time_floor = source->locker_update_time_floor; + + dest->locker_state = LS_OPEN; + dest->locker_period_begin = LOCKER_DEFAULT_PERIOD_BEGIN; + dest->locker_period_begin_sys = LOCKER_DEFAULT_PERIOD_BEGIN; + dest->locker_period_end = LOCKER_DEFAULT_PERIOD_END; + dest->locker_period_end_sys = LOCKER_DEFAULT_PERIOD_END; + + spin_unlock(&source->locker_lock); + + /* + * when a ro snapshot is taken from a rw subvolume, current fs_clock + * will be stored in dest update_time_floor (borrowed). therefor, we + * can exactly know what's the time (in fs_clock) the snapshot was taken. + * + * please remember that update_time_floor has totally different meaning + * in a rw subvolume. + * + * when a rw subvolume is cloned from ro snapshot, update_time_floor is used + * to calculate the (accumulated) clock_adjustment for root_clock. + * all non-locked files in this new-cloned rw subvolume will has a + * update_time that is later than the time the subvolume was restored. + * + * root_clock = fs_clock + subvolume clock_adjustment + */ + if (dest_ro && !source_ro) { + struct timespec64 fs_clock; + + fs_clock = btrfs_syno_locker_fs_clock_get(source->fs_info); + dest->locker_update_time_floor = fs_clock.tv_sec; + } else if (!dest_ro && source_ro) { + struct timespec64 fs_clock, root_clock; + + fs_clock = btrfs_syno_locker_fs_clock_get(source->fs_info); + dest->locker_clock_adjustment -= fs_clock.tv_sec - source->locker_update_time_floor; + + root_clock = syno_locker_root_clock_get(dest); + dest->locker_update_time_floor = root_clock.tv_sec; + } + + return btrfs_syno_locker_disk_root_update(trans, dest); +} + +int btrfs_syno_locker_may_destroy_subvol(struct btrfs_root *root) +{ + int ret = 0; + + spin_lock(&root->locker_lock); + + if (!root->locker_enabled) + goto out; + + if (root->locker_mode != LM_COMPLIANCE) + goto out; + + /* + * A ro subvolume is deletable even if it's in compliance mode. If a + * snapshot would like to be locked, SYNO_BTRFS_LOCKER_SNAPSHOT should + * be enabled and setting snapshot to immutable state. + */ + if (btrfs_root_readonly(root)) + goto out; + + ret = -EPERM; +out: + spin_unlock(&root->locker_lock); + return ret; +} + +/** + * disallow to rename subvolumes protected by locker + * disallow to rename non-empty directories + * + * @reset: clear runtime flags for whitelist if successful + */ +int btrfs_syno_locker_may_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + bool reset) +{ + int ret = 0; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); + struct btrfs_root *root = BTRFS_I(old_inode)->root; + struct btrfs_root *dest = new_inode ? BTRFS_I(new_inode)->root : NULL; + u64 old_ino = btrfs_ino(BTRFS_I(old_inode)); + u64 new_ino = new_inode ? btrfs_ino(BTRFS_I(new_inode)) : 0; + + if (root->locker_mode == LM_NONE) + goto out; + + if (syno_locker_is_whitelisted(BTRFS_I(old_inode)) && + (!new_inode || syno_locker_is_whitelisted(BTRFS_I(new_inode)))) + goto out; + + /* + * the expired old file still cannot be renamed but it would pass may_delete() + * check in vfs_rename(). an additional validation is required here. + * + * if the new file exists and is already expired, it can be replaced. + */ + if (IS_EXPIRED(old_inode)) { + ret = -EPERM; + goto out; + } + + spin_lock(&root->locker_lock); + /* rename is allowed if old_path is a locker-enabled subvolume */ + + if (old_ino != BTRFS_FIRST_FREE_OBJECTID && + root->locker_enabled && root->locker_mode != LM_NONE && + S_ISDIR(old_inode->i_mode) && old_inode->i_size > BTRFS_EMPTY_DIR_SIZE) { + ret = -EOPNOTSUPP; + spin_unlock(&root->locker_lock); + goto out; + } + spin_unlock(&root->locker_lock); + + if (!dest) + goto out; + + spin_lock(&dest->locker_lock); + if (new_ino == BTRFS_FIRST_FREE_OBJECTID && dest && + dest->locker_enabled && dest->locker_mode != LM_NONE) { + ret = -EPERM; + spin_unlock(&dest->locker_lock); + goto out; + } + + if (dest && dest->locker_enabled && dest->locker_mode != LM_NONE && + S_ISDIR(new_inode->i_mode) && new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) { + ret = -ENOTEMPTY; + spin_unlock(&dest->locker_lock); + goto out; + } + spin_unlock(&dest->locker_lock); + +out: + if (!ret && reset) { + clear_bit(BTRFS_INODE_LOCKER_NOLOCK, &BTRFS_I(old_inode)->runtime_flags); + clear_bit(BTRFS_INODE_LOCKER_LOCKABLE, &BTRFS_I(old_inode)->runtime_flags); + if (new_inode) { + clear_bit(BTRFS_INODE_LOCKER_NOLOCK, &BTRFS_I(new_inode)->runtime_flags); + clear_bit(BTRFS_INODE_LOCKER_LOCKABLE, &BTRFS_I(new_inode)->runtime_flags); + } + } + + return ret; +} + +static inline int syno_locker_root_enable(struct btrfs_root *root) +{ + lockdep_assert_held(&root->locker_lock); + + if (root->locker_mode == LM_NONE) + return -EPERM; + + root->locker_enabled = 1; + + return 0; +} + +struct btrfs_locker_xattr { + __u8 state; + __s64 update_time; + __s64 period_begin; + __s64 period_end; +} __attribute__ ((__packed__)); + +static int syno_locker_xattr_set(struct btrfs_trans_handle *trans, struct inode *inode, + const void *buffer, size_t size, int flags) +{ + int ret; + + if (trans) + ret = btrfs_setxattr(trans, inode, XATTR_SYNO_LOCKER, buffer, size, flags); + else + ret = btrfs_setxattr_trans(inode, XATTR_SYNO_LOCKER, buffer, size, flags); + + return ret; +} + +static int syno_locker_disk_inode_update(struct btrfs_trans_handle *trans, struct inode *inode) +{ + int ret; + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_locker_xattr xattr; + + WARN_ON(btrfs_ino(binode) == BTRFS_FIRST_FREE_OBJECTID); + + spin_lock(&binode->locker_lock); + xattr.state = binode->locker_state; + xattr.update_time = cpu_to_le64(binode->locker_update_time); + xattr.period_begin = cpu_to_le64(binode->locker_period_begin); + xattr.period_end = cpu_to_le64(binode->locker_period_end); + spin_unlock(&binode->locker_lock); + + ret = syno_locker_xattr_set(trans, inode, &xattr, sizeof(xattr), 0); + + if (ret) { + btrfs_err(binode->root->fs_info, "failed to set locker xattr. err=%d", ret); + btrfs_abort_transaction(trans, ret); + } + + return ret; +} + +int btrfs_syno_locker_disk_inode_update_trans(struct inode *inode) +{ + int ret; + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_root *root = binode->root; + struct btrfs_trans_handle *trans; + + if (!binode->locker_dirty) + return 0; + + /* + * the inode for subvolume is special and cannot be modified if + * the subvolume is read-only, or btrfs send/recv will have trouble. + */ + if (btrfs_ino(BTRFS_I(inode)) == BTRFS_FIRST_FREE_OBJECTID) { + spin_lock(&binode->locker_lock); + + if (binode->locker_state == LS_OPEN && + binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END) { + spin_unlock(&binode->locker_lock); + /* do nothing if they are default values */ + return 0; + } + + root->locker_state = binode->locker_state; + root->locker_period_begin = binode->locker_period_begin; + root->locker_period_end = binode->locker_period_end; + spin_unlock(&binode->locker_lock); + + ret = btrfs_syno_locker_disk_root_update_trans(root); + if (!ret) + binode->locker_dirty = false; + + return ret; + } + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + ret = syno_locker_disk_inode_update(trans, inode); + if (ret) { + btrfs_err(root->fs_info, "failed to update disk inode locker attrs. err=%d", ret); + goto abort; + } + + inode_inc_iversion(inode); + set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); + ret = btrfs_update_inode_fallback(trans, root, inode); + if (ret) { + btrfs_err(root->fs_info, "failed to update inode. err=%d", ret); + goto abort; + } + + ret = btrfs_end_transaction(trans); + if (!ret) + binode->locker_dirty = false; + + return ret; + +abort: + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; +} + +int btrfs_syno_locker_disk_inode_read(struct inode *inode) +{ + int ret; + struct btrfs_locker_xattr xattr; + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_root *root = binode->root; + + if (btrfs_ino(binode) == BTRFS_FIRST_FREE_OBJECTID) { + /* btrfs root has been ready in memory. copy attributes form it */ + spin_lock(&binode->locker_lock); + binode->__locker_state = root->locker_state; + binode->__locker_update_time = 0; + binode->__locker_period_begin = root->locker_period_begin; + binode->__locker_period_end = root->locker_period_end; + binode->locker_dirty = false; + spin_unlock(&binode->locker_lock); + return 0; + } + + ret = btrfs_getxattr(inode, XATTR_SYNO_LOCKER, &xattr, sizeof(xattr)); + + if (ret == -ENODATA) + goto out; + else if (ret != sizeof(xattr)) { + btrfs_err(BTRFS_I(inode)->root->fs_info, "failed to get locker xattr. ret=%d", ret); + goto out; + } + + spin_lock(&binode->locker_lock); + binode->__locker_state = xattr.state; + binode->__locker_update_time = le64_to_cpu(xattr.update_time); + binode->__locker_period_begin = le64_to_cpu(xattr.period_begin); + binode->__locker_period_end = le64_to_cpu(xattr.period_end); + binode->locker_dirty = false; + spin_unlock(&binode->locker_lock); + + ret = 0; +out: + return ret; +} + +/** + * if time is too large or overflow, limit it to 9999/12/31 00:00:00 for + * userspace display. + */ +static inline void __truncate_time(time64_t *time) +{ + if (*time < 0 || *time > 253402214400) + *time = 253402214400; +} + +/* + * update time is the base of auto-lock. this routine refreshes and returns + * the update_time of a file in volume clock. + * + * new update_time = max(update_time, mtime, ctime, root->update_time_floor) + */ +static time64_t syno_locker_update_time(struct btrfs_inode *binode) +{ + time64_t sys_update_time; + struct timespec64 delta; + struct inode *inode = &binode->vfs_inode; + + lockdep_assert_held(&binode->locker_lock); + + if (btrfs_ino(binode) == BTRFS_FIRST_FREE_OBJECTID) + return 0; + + if (binode->root->locker_mode == LM_NONE) + goto out; + + /* update_time isn't expected to be changed after a file is locked */ + if (binode->locker_state != LS_OPEN) + goto out; + + delta = syno_locker_sys_clock_delta(binode); + sys_update_time = (timespec64_compare(&inode->i_mtime, &inode->i_ctime) > 0) ? + inode->i_mtime.tv_sec : inode->i_ctime.tv_sec; + + if (binode->locker_update_time == LOCKER_DEFAULT_UPDATE_TIME) { + binode->__locker_update_time = sys_update_time - delta.tv_sec; + binode->locker_dirty = true; + } + + if (binode->locker_update_time < sys_update_time - delta.tv_sec) { + binode->__locker_update_time = sys_update_time - delta.tv_sec; + binode->locker_dirty = true; + } + + if (binode->locker_update_time < binode->root->locker_update_time_floor) { + binode->__locker_update_time = binode->root->locker_update_time_floor; + binode->locker_dirty = true; + } + +out: + return binode->locker_update_time; +} + +static inline time64_t syno_locker_timestamp_get(struct btrfs_inode *binode, int flag) +{ + struct btrfs_root *root = binode->root; + struct inode *inode = &binode->vfs_inode; + + if (btrfs_ino(binode) == BTRFS_FIRST_FREE_OBJECTID) { + if (flag == S_MTIME) + return 0; + if (flag == S_CTIME) + return root->locker_period_begin_sys; + if (flag == S_ATIME) + return root->locker_period_end_sys; + } else { + if (flag == S_MTIME) + return inode->i_mtime.tv_sec; + if (flag == S_CTIME) + return inode->i_ctime.tv_sec; + if (flag == S_ATIME) + return inode->i_atime.tv_sec; + } + + return -EINVAL; +} + +static inline int syno_locker_timestamp_set(struct btrfs_inode *binode, time64_t time, int flag) +{ + struct btrfs_root *root = binode->root; + struct inode *inode = &binode->vfs_inode; + struct timespec64 ts = { .tv_sec = time }; + + if (flag != S_MTIME && flag != S_CTIME && flag != S_ATIME) + return -EINVAL; + + if (btrfs_ino(binode) == BTRFS_FIRST_FREE_OBJECTID) { + if (flag == S_MTIME) + return 0; + if (flag == S_CTIME) + root->locker_period_begin_sys = time; + if (flag == S_ATIME) + root->locker_period_end_sys = time; + + return btrfs_syno_locker_disk_root_update_trans(root); + } + + return inode->i_op->update_time(inode, &ts, flag); +} + +/** + * store volume clock in locker_period_begin, and system clock in ctime. + * + * the delta changes with time. if we store only one of them, we will + * lose the other one. + * + * @time: epoch time in volume clock + */ +static inline int +syno_locker_inode_period_begin_set(struct btrfs_inode *binode, time64_t time) +{ + time64_t ctime, mtime; + struct timespec64 delta; + + lockdep_assert_held(&binode->locker_lock); + + if (binode->root->locker_mode == LM_NONE) + return -EINVAL; + + if (time < 0) + return -EINVAL; + + /* the end of lock-period should be in the future first. */ + if (time > binode->locker_period_end) + return -EINVAL; + + delta = syno_locker_sys_clock_delta(binode); + + /* + * update_time is determined and can be stored in mtime. + * this step should be processed before begin_time because it'll refer + * to ctime. + */ + mtime = syno_locker_update_time(binode) + delta.tv_sec; + __truncate_time(&mtime); + + /* begin time in volume clock */ + binode->__locker_period_begin = time; + binode->locker_dirty = true; + + /* begin time in system clock */ + ctime = time + delta.tv_sec; + __truncate_time(&ctime); + + spin_unlock(&binode->locker_lock); + syno_locker_timestamp_set(binode, mtime, S_MTIME); + syno_locker_timestamp_set(binode, ctime, S_CTIME); + spin_lock(&binode->locker_lock); + + return 0; +} + +/** + * set current volume clock into the begin of lock-period. + */ +static inline int +syno_locker_inode_period_begin_set_current(struct btrfs_inode *binode) +{ + struct timespec64 vol_clock; + + vol_clock = syno_locker_clock_get(binode); + + return syno_locker_inode_period_begin_set(binode, vol_clock.tv_sec); +} + +/** + * for relock, the period_end is allowed to be changed after it was reached + * and the raw state became expired. + * + * @time: epoch time in volume clock + */ +static inline int +syno_locker_inode_period_end_set(struct btrfs_inode *binode, time64_t time) +{ + int ret = 0; + time64_t atime; + struct timespec64 delta; + + lockdep_assert_held(&binode->locker_lock); + + if (binode->root->locker_enabled) { + if (time < 0) { + ret = -EINVAL; + goto out; + } + + /* extend only after locked */ + if (binode->locker_state != LS_OPEN && time < binode->locker_period_end) { + ret = -EINVAL; + goto out; + } + } + + binode->__locker_period_end = time; + binode->locker_dirty = true; + + /* + * although btrfs_syno_locker_fillattr() always reports period_end to atime + * before expired, we still need to update atime here. because we may update + * period_end after a file is expired for relock (through atime). if atime + * isn't updated in this situation, it'd be confused. + */ + delta = syno_locker_sys_clock_delta(binode); + atime = time + delta.tv_sec; + + spin_unlock(&binode->locker_lock); + syno_locker_timestamp_set(binode, atime, S_ATIME); + spin_lock(&binode->locker_lock); + +out: + if (ret) + btrfs_err(binode->root->fs_info, "invalid lock period end. cur:%lld, new:%lld", + binode->locker_period_end, time); + + return ret; +} + +inline int btrfs_syno_locker_fillattr(struct inode *inode, struct kstat *stat) +{ + enum locker_state state; + struct timespec64 delta; + struct btrfs_inode *binode = BTRFS_I(inode); + + if (binode->root->locker_mode == LM_NONE) + return 0; + + btrfs_syno_locker_state_get(inode, &state); + delta = syno_locker_sys_clock_delta(binode); + + /* + * when a file is not expired (even not locked), the lock period_end isn't + * yet fixed in system clock (atime), but could be estimated. + */ + if (binode->locker_period_end != LOCKER_DEFAULT_PERIOD_END && + state != LS_EXPIRED_I && state != LS_EXPIRED_A) { + stat->atime.tv_sec = binode->locker_period_end + delta.tv_sec; + stat->atime.tv_nsec = 0; + __truncate_time(&stat->atime.tv_sec); + } + + /* + * show no write permission if immutable + */ + if (IS_LOCKER_STATE_IMMUTABLE(state)) + stat->mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + + return 0; +} + +/** + * @time: time in system clock + */ +inline int btrfs_syno_locker_period_end_set(struct inode *inode, struct timespec64 *time) +{ + int ret; + struct timespec64 delta, vol_time; + struct btrfs_inode *binode = BTRFS_I(inode); + + if (binode->root->locker_mode == LM_NONE) + return 0; + + delta = syno_locker_sys_clock_delta(binode); + vol_time = timespec64_sub(*time, delta); + + spin_lock(&binode->locker_lock); + ret = syno_locker_inode_period_end_set(binode, vol_time.tv_sec); + spin_unlock(&binode->locker_lock); + + return ret; +} + +/* + * The locker state of a file may be transited by manual-lock in `syno_locker_state_set()`, + * or auto-lock in `btrfs_syno_locker_state_get()`. All the transitions should follow the state + * machine. + * + * @startuml + * hide empty description + * State Open + * State Immutable + * State Appendable + * State "Expired\nfrom Immutable" as expired_i + * State "Expired\nfrom Appendable" as expired_a + * + * Open -right-> Immutable : Auto/Manual + * Open -down-> Appendable : Auto/Manual + * Immutable -right-> expired_i : Auto + * Immutable -down[dashed]-> Appendable : Manual\n(empty) + * Appendable -right-> expired_a : Auto + * Appendable -up[dashed]-> Immutable : Manual + * expired_a -left[dashed]-> Appendable : Manual + * expired_a -left[dashed]-> Immutable : Manual + * expired_i -[dashed]-> Appendable: Manual\n(empty) + * expired_i -left[dashed]-> Immutable : Manual + * expired_a -right[dashed]-> [*] : Manual Delete + * expired_i -right[dashed]-> [*] : Manual Delete + * + * State Weak { + * State "Weak\nImmutable" as weak_i + * State "Weak\nAppendable" as weak_a + * } + * weak_i -right[dashed]-> weak_a : Manual + * weak_a -left[dashed]-> weak_i : Manual + * weak_i --> expired_i : Auto + * weak_a --> expired_a : Auto + * Open -[dashed]-> Weak : Manual + * Weak -[dashed]-> Open : Manual + * @enduml + */ + +static int syno_locker_state_set(struct btrfs_inode *binode, enum locker_state state) +{ + int ret = -EINVAL; + struct btrfs_root *root = binode->root; + + lockdep_assert_held(&binode->locker_lock); + + if (state > LS_MAX) + goto out; + + /* a special way for btrfs recv to set up locker attrs */ + if (!root->locker_enabled && root->locker_mode == LM_NONE) { + binode->__locker_state = state; + binode->locker_dirty = true; + return 0; + } + + if (state == binode->locker_state) + return 0; + + if (binode->locker_period_end < 0) + goto out; + + if (!root->locker_enabled) + goto setup; + + switch (binode->locker_state) { + case LS_OPEN: + if (state != LS_IMMUTABLE && state != LS_APPENDABLE && + state != LS_W_IMMUTABLE && state != LS_W_APPENDABLE) + goto out; + break; + + case LS_IMMUTABLE: + if (state != LS_APPENDABLE) + goto out; + if (state == LS_APPENDABLE && binode->vfs_inode.i_size) + goto out; + break; + + case LS_APPENDABLE: + if (state != LS_IMMUTABLE) + goto out; + break; + + case LS_EXPIRED_I: + if (state != LS_IMMUTABLE && state != LS_APPENDABLE) + goto out; + if (state == LS_APPENDABLE && binode->vfs_inode.i_size) + goto out; + break; + + case LS_EXPIRED_A: + if (state != LS_IMMUTABLE && state != LS_APPENDABLE) + goto out; + break; + + case LS_W_IMMUTABLE: + if (state != LS_OPEN && state != LS_W_APPENDABLE) + goto out; + break; + + case LS_W_APPENDABLE: + if (state != LS_OPEN && state != LS_W_IMMUTABLE) + goto out; + break; + } + +setup: + /* prevent to be locked immediately by auto-lock */ + if (state == LS_OPEN) { + struct timespec64 clock = syno_locker_clock_get(binode); + binode->__locker_update_time = clock.tv_sec; + } + + /* update period_begin if manually locked from open, or relock */ + if (binode->locker_state == LS_OPEN || binode->locker_state == LS_EXPIRED_I || + binode->locker_state == LS_EXPIRED_A) { + if (state == LS_IMMUTABLE || state == LS_APPENDABLE || + state == LS_W_IMMUTABLE || state == LS_W_APPENDABLE) { + syno_locker_inode_period_begin_set_current(binode); + } + } + + binode->__locker_state = state; + binode->locker_dirty = true; + + ret = 0; +out: + return ret; +} + +int btrfs_syno_locker_mode_get(struct inode *inode, enum locker_mode *mode) +{ + *mode = BTRFS_I(inode)->root->locker_mode; + + return 0; +} + +int btrfs_syno_locker_state_set(struct inode *inode, enum locker_state state) +{ + int ret; + struct btrfs_inode *binode = BTRFS_I(inode); + + spin_lock(&binode->locker_lock); + ret = syno_locker_state_set(binode, state); + spin_unlock(&binode->locker_lock); + + if (ret) + goto out; + + ret = btrfs_syno_locker_disk_inode_update_trans(inode); + +out: + return ret; +} + +/* + * auto-lock is triggered when the locker state of a file is observed. + */ +int btrfs_syno_locker_state_get(struct inode *inode, enum locker_state *state) +{ + int ret = 0; + time64_t target; + struct timespec64 vol_clock, delta; + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_root *root = binode->root; + + if (root->locker_mode == LM_NONE) + return -EOPNOTSUPP; + + WARN_ON_ONCE(!btrfs_syno_check_feat_tree_enable(root->fs_info)); + ASSERT(btrfs_syno_check_feat_tree_enable(root->fs_info)); + + if (!root->locker_enabled) { + *state = LS_OPEN; + goto out; + } + +#ifdef MY_ABC_HERE + /* not supported for pure directories and r/w subvolumes */ + if (S_ISDIR(inode->i_mode) && !btrfs_is_ro_snapshot(binode)) { + *state = LS_OPEN; + goto out; + } +#else + if (S_ISDIR(inode->i_mode)) { + *state = LS_OPEN; + goto out; + } +#endif /* MY_ABC_HERE */ + + if (!syno_locker_is_lockable_object(binode) || + syno_locker_is_whitelisted(binode)) { + *state = LS_OPEN; + goto out; + } + + vol_clock = syno_locker_clock_get(binode); + delta = syno_locker_sys_clock_delta(binode); + WARN_ON_ONCE(vol_clock.tv_sec == 0); + + spin_lock(&binode->locker_lock); + *state = binode->locker_state; + + switch (binode->locker_state) { + case LS_OPEN: +#ifdef MY_ABC_HERE + /* no auto-lock for r/o snapshots */ + if (btrfs_is_ro_snapshot(binode)) + break; +#endif /* MY_ABC_HERE */ + + /* auto-lock */ + target = syno_locker_update_time(binode) + root->locker_waittime; + if (target > 0 && vol_clock.tv_sec >= target + 5) { /* 5 seconds for tolerance */ + *state = root->locker_default_state; + if (target + root->locker_duration < 0) + syno_locker_inode_period_end_set(binode, TIME64_MAX); /* overflow */ + else + syno_locker_inode_period_end_set(binode, target + root->locker_duration); + + syno_locker_inode_period_begin_set(binode, target); + } + break; + + case LS_IMMUTABLE: + WARN_ON(binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END); + + if (vol_clock.tv_sec >= binode->locker_period_end) + *state = LS_EXPIRED_I; + break; + + case LS_APPENDABLE: + WARN_ON(binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END); + + if (vol_clock.tv_sec >= binode->locker_period_end) + *state = LS_EXPIRED_A; + break; + + case LS_EXPIRED_I: + /* do nothing */ + break; + + case LS_EXPIRED_A: + /* do nothing */ + break; + + case LS_W_IMMUTABLE: + WARN_ON(binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END); + + if (vol_clock.tv_sec >= binode->locker_period_end) + *state = LS_EXPIRED_I; + break; + + case LS_W_APPENDABLE: + WARN_ON(binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END); + + if (vol_clock.tv_sec >= binode->locker_period_end) + *state = LS_EXPIRED_A; + break; + } + + if (binode->locker_state != *state) { + time64_t atime = binode->locker_period_end + delta.tv_sec; + + binode->__locker_state = *state; + binode->locker_dirty = true; + __truncate_time(&atime); + spin_unlock(&binode->locker_lock); + + if (*state == LS_EXPIRED_I || *state == LS_EXPIRED_A) + syno_locker_timestamp_set(binode, atime, S_ATIME); + ret = btrfs_syno_locker_disk_inode_update_trans(inode); + } else + spin_unlock(&binode->locker_lock); + + __dump_locker_root(root); + __dump_locker_inode(binode); + +out: + return ret; +} + +static void __fill_ioctl_sys_time(struct btrfs_inode *binode, struct btrfs_ioctl_syno_locker_args *args) +{ + time64_t delta = args->clock_delta; + + lockdep_assert_held(&binode->locker_lock); + + if (args->flags & BTRFS_LOCKER_BEGIN) { + /* + * once a file is not in open state, period_begin will not be the initial + * value (LOCKER_DEFAULT_PERIOD_BEGIN) and be stored in ctime (in system + * clock). we should report the ctime but not `period_begin + delta` for + * system clock. + */ + if (binode->locker_period_begin == LOCKER_DEFAULT_PERIOD_BEGIN) + args->period_begin_sys = LOCKER_DEFAULT_PERIOD_BEGIN; + else + args->period_begin_sys = syno_locker_timestamp_get(binode, S_CTIME); + } + + if (args->flags & BTRFS_LOCKER_END) { + /* + * when the raw state of a object isn't expired, period_end is calculated and + * changes over the time, because delta is unfixed. + * + * period_end will be stored in atime if it's updated, but only report it after + * it's fixed (expired). + */ + if (binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END) { + args->period_end_sys = LOCKER_DEFAULT_PERIOD_END; + } else if (binode->locker_state != LS_EXPIRED_I && binode->locker_state != LS_EXPIRED_A) { + args->period_end_sys = binode->locker_period_end + delta; + __truncate_time(&args->period_end_sys); + } else { + args->period_end_sys = syno_locker_timestamp_get(binode, S_ATIME); + } + } + + if (args->flags & BTRFS_LOCKER_UPDATE_TIME) { + /* + * once a file is locked (raw state is not LS_OPEN), update_time will be never + * changed and stored in mtime. + */ + if (binode->locker_state == LS_OPEN) + args->update_time_sys = syno_locker_update_time(binode) + delta; + else + args->update_time_sys = syno_locker_timestamp_get(binode, S_MTIME); + } +} + +int btrfs_ioctl_syno_locker_get(struct file *file, struct btrfs_ioctl_syno_locker_args __user *argp) +{ + int ret; + enum locker_state state; + struct timespec64 clock; + struct inode *inode = file_inode(file); + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_root *root = binode->root; + struct btrfs_ioctl_syno_locker_args locker_args; + + memset(&locker_args, 0, sizeof(locker_args)); + + clock = syno_locker_clock_get(binode); + if (clock.tv_sec) { + struct timespec64 delta = syno_locker_sys_clock_delta(binode); + + locker_args.flags |= BTRFS_LOCKER_CLOCK; + locker_args.clock = clock.tv_sec; + locker_args.flags |= BTRFS_LOCKER_CLOCK_DELTA; + locker_args.clock_delta = delta.tv_sec; + } + + spin_lock(&root->locker_lock); + locker_args.flags |= BTRFS_LOCKER_ENABLED; + locker_args.enabled = root->locker_enabled; + + locker_args.flags |= BTRFS_LOCKER_MODE; + locker_args.mode = root->locker_mode; + + locker_args.flags |= (BTRFS_LOCKER_DEFAULT_STATE|BTRFS_LOCKER_WAITTIME|BTRFS_LOCKER_DURATION); + locker_args.default_state = root->locker_default_state; + locker_args.waittime = root->locker_waittime; + locker_args.duration = root->locker_duration; + + locker_args.flags |= (BTRFS_LOCKER_CLOCK_ADJUSTMENT|BTRFS_LOCKER_UPDATE_TIME_FLOOR); + locker_args.clock_adjustment = root->locker_clock_adjustment; + locker_args.update_time_floor = root->locker_update_time_floor; + spin_unlock(&root->locker_lock); + + ret = syno_op_locker_state_get(inode, &state); + if (!ret) { + locker_args.flags |= BTRFS_LOCKER_STATE; + locker_args.state = state; + } + + locker_args.flags |= BTRFS_LOCKER_LOCKABLE; + if (locker_args.enabled) + locker_args.lockable = syno_locker_is_lockable_object(binode) && + !syno_locker_is_whitelisted(binode); + + spin_lock(&binode->locker_lock); + locker_args.flags |= BTRFS_LOCKER_RAW_STATE; + locker_args.raw_state = binode->locker_state; + + locker_args.flags |= (BTRFS_LOCKER_BEGIN|BTRFS_LOCKER_END); + locker_args.period_begin = binode->locker_period_begin; + locker_args.period_end = binode->locker_period_end; + + locker_args.flags |= BTRFS_LOCKER_UPDATE_TIME; + locker_args.update_time = binode->locker_update_time; + + if (locker_args.flags & BTRFS_LOCKER_RAW_STATE) + __fill_ioctl_sys_time(binode, &locker_args); + + spin_unlock(&binode->locker_lock); + + if (copy_to_user(argp, &locker_args, sizeof(locker_args))) + return -EFAULT; + + return 0; +} + +/* + * validate the arguments from ioctl to set attributes + */ +static int syno_locker_ioctl_args_validate(struct btrfs_inode *binode, + struct btrfs_ioctl_syno_locker_args *args) +{ + struct btrfs_root *root = binode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + + spin_lock(&binode->locker_lock); + spin_lock(&root->locker_lock); + + if (args->flags & ~BTRFS_LOCKER_MASK_ALL) { + btrfs_err(fs_info, "invalid flags"); + goto fail_unlock; + } + + if ((args->flags & BTRFS_LOCKER_CLOCK) || + (args->flags & BTRFS_LOCKER_CLOCK_DELTA)) { + btrfs_err(fs_info, "volume clock is read-only"); + goto fail_unlock; + } + + if (args->flags & BTRFS_LOCKER_CLOCK_ADJUSTMENT) { + if (root->locker_enabled) { + btrfs_err(fs_info, "volume clock adjustment is read-only"); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_ENABLED) { + if (!args->enabled) { + btrfs_err(fs_info, "you shall not disable locker"); + goto fail_unlock; + } + if (root->locker_mode == LM_NONE && + (!(args->flags & BTRFS_LOCKER_MODE) || (args->mode == LM_NONE))) { + btrfs_err(fs_info, "mode isn't specified when enabling locker"); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_MODE) { + if (root->locker_enabled && root->locker_mode == LM_COMPLIANCE) { + btrfs_err(fs_info, "compliance mode isn't alterable after locker is enabled"); + goto fail_unlock; + } + if (args->mode > LM_MAX) { + btrfs_err(fs_info, "invalid mode (%d)", args->mode); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_DEFAULT_STATE) { + if (args->default_state != LS_IMMUTABLE && args->default_state != LS_APPENDABLE) { + btrfs_err(fs_info, "invalid default state (%d) for auto-lock", args->default_state); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_WAITTIME) { + if (args->waittime < 0) { + btrfs_err(fs_info, "invalid waittime (%lld) for auto-lock", args->waittime); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_DURATION) { + if (args->duration < 0) { + btrfs_err(fs_info, "invalid default duration (%lld) for auto-lock", args->duration); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_STATE) { + /* + * for btrfs recv, it's ok to set the state of a file when locker is not + * enabled. 'raw_state' will reveal the result, but (effective) `state` may not. + */ + if (args->state > LS_MAX) { + btrfs_err(fs_info, "invalid state (%d)", args->state); + goto fail_unlock; + } + if (args->state != LS_OPEN && S_ISDIR(binode->vfs_inode.i_mode) && + btrfs_ino(binode) != BTRFS_FIRST_FREE_OBJECTID) { + btrfs_err(fs_info, "invalid state (%d) for directory", args->state); + goto fail_unlock; + } + if (root->locker_enabled && binode->locker_period_end < 0 && + (!(args->flags & BTRFS_LOCKER_PERIOD_MASK) || args->period_end < 0)) { + btrfs_err(fs_info, "the end of lock period isn't set"); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_UPDATE_TIME) { + if (root->locker_enabled) { + btrfs_err(fs_info, "update-time is read-only"); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_UPDATE_TIME_FLOOR) { + btrfs_err(fs_info, "update-time-floor is read-only"); + goto fail_unlock; + } + + if (args->flags & BTRFS_LOCKER_BEGIN) { + if (root->locker_enabled) { + btrfs_err(fs_info, "period_begin is read-only"); + goto fail_unlock; + } + } + + if (args->flags & BTRFS_LOCKER_END) { + if (root->locker_enabled && args->period_end < 0) { + btrfs_err(fs_info, "invalid period_end (%lld)", args->period_end); + goto fail_unlock; + } + } + if (args->flags & BTRFS_LOCKER_END_EXT_BEGIN) { + if (args->period_end < 0 || binode->locker_period_begin == LOCKER_DEFAULT_PERIOD_BEGIN) { + btrfs_err(fs_info, "invalid period_end (%lld) to extended from begin", args->period_end); + goto fail_unlock; + } + } + if (args->flags & BTRFS_LOCKER_END_EXT_END) { + if (args->period_end < 0 || binode->locker_period_end == LOCKER_DEFAULT_PERIOD_END) { + btrfs_err(fs_info, "invalid period_end (%lld) to extended from end", args->period_end); + goto fail_unlock; + } + } + if (args->flags & BTRFS_LOCKER_END_EXT_CURRENT) { + if (args->period_end < 0) { + btrfs_err(fs_info, "invalid period_end (%lld) to extended from current", args->period_end); + goto fail_unlock; + } + } + + spin_unlock(&root->locker_lock); + spin_unlock(&binode->locker_lock); + + return 0; + +fail_unlock: + spin_unlock(&root->locker_lock); + spin_unlock(&binode->locker_lock); + return -EINVAL; +} + +static int syno_locker_root_set(struct btrfs_root *root, struct btrfs_ioctl_syno_locker_args *args) +{ + spin_lock(&root->locker_lock); + + if (args->flags & BTRFS_LOCKER_MODE) + root->locker_mode = args->mode; + if (args->flags & BTRFS_LOCKER_DEFAULT_STATE) + root->locker_default_state = args->default_state; + if (args->flags & BTRFS_LOCKER_WAITTIME) + root->locker_waittime = args->waittime; + if (args->flags & BTRFS_LOCKER_DURATION) + root->locker_duration = args->duration; + if (args->flags & BTRFS_LOCKER_CLOCK_ADJUSTMENT) + root->locker_clock_adjustment = args->clock_adjustment; + + /* + * if we set up locker on a ro snapshot, we should guarantee its + * update_time_floor is not zero, because it's used as a frozen subvolume + * clock in some situations. + * + * normally it's assigned as the fs_clock at that time cloned from a r/w + * subvolume, but at that moment there may be no locker enabled in this + * volume. if so it will cause update_time_floor to be 0. we should assign + * a proper value to it. + */ + if (btrfs_root_readonly(root) && root->locker_update_time_floor == 0) { + struct timespec64 fs_clock; + + fs_clock = btrfs_syno_locker_fs_clock_get(root->fs_info); + root->locker_update_time_floor = fs_clock.tv_sec; + } + + /* enabled at the last because it doesn't accept incorrect mode */ + if ((args->flags & BTRFS_LOCKER_ENABLED) && args->enabled) + syno_locker_root_enable(root); + + spin_unlock(&root->locker_lock); + + return 0; +} + +static int syno_locker_binode_set(struct btrfs_inode *binode, struct btrfs_ioctl_syno_locker_args *args) +{ + int ret = 0; + + spin_lock(&binode->locker_lock); + if (args->flags & BTRFS_LOCKER_END) + ret = syno_locker_inode_period_end_set(binode, args->period_end); + else if (args->flags & BTRFS_LOCKER_END_EXT_BEGIN) + ret = syno_locker_inode_period_end_set(binode, args->period_end + binode->locker_period_begin); + else if (args->flags & BTRFS_LOCKER_END_EXT_END) + ret = syno_locker_inode_period_end_set(binode, args->period_end + binode->locker_period_end); + else if (args->flags & BTRFS_LOCKER_END_EXT_CURRENT) { + struct timespec64 vol_clock = syno_locker_clock_get(binode); + ret = syno_locker_inode_period_end_set(binode, args->period_end + vol_clock.tv_sec); + } + if (ret) + goto out; + + if (args->flags & BTRFS_LOCKER_STATE) { + ret = syno_locker_state_set(binode, (enum locker_state)args->state); + if (ret) + goto out; + } + + /* + * update raw update_time and period_begin fields directly before locker + * is enabled. this is only for btrfs recv because there's no additional + * validation for these values. + */ + if (args->flags & BTRFS_LOCKER_UPDATE_TIME) { + binode->__locker_update_time = args->update_time; + binode->locker_dirty = true; + } + if (args->flags & BTRFS_LOCKER_BEGIN) { + binode->__locker_period_begin = args->period_begin; + binode->locker_dirty = true; + } + +out: + spin_unlock(&binode->locker_lock); + + return ret; +} + +int btrfs_xattr_syno_set_locker(struct inode *inode, const void *buffer, size_t size) +{ + int ret; + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_locker_xattr *xattr; + struct btrfs_ioctl_syno_locker_args args = {}; + + if (size != sizeof(struct btrfs_locker_xattr)) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + xattr = (struct btrfs_locker_xattr *)buffer; + + args.flags = BTRFS_LOCKER_STATE|BTRFS_LOCKER_UPDATE_TIME|BTRFS_LOCKER_BEGIN|BTRFS_LOCKER_END; + args.state = xattr->state; + args.update_time = le64_to_cpu(xattr->update_time); + args.period_begin = le64_to_cpu(xattr->period_begin); + args.period_end = le64_to_cpu(xattr->period_end); + + ret = syno_locker_ioctl_args_validate(binode, &args); + if (ret) + goto out; + + syno_locker_fs_clock_init(binode->root->fs_info); + + ret = syno_locker_binode_set(binode, &args); + if (ret) + goto out; + + /* FIXME: it may be somewhat expansive to update each on-disk inode */ + ret = btrfs_syno_locker_disk_inode_update_trans(&binode->vfs_inode); + if (ret) + goto out; + +out: + if (ret) + btrfs_err(binode->root->fs_info, "failed to set xattr (%u, %ptT, %ptT, %ptT). err=%d", + args.state, &args.update_time, &args.period_begin, &args.period_end, ret); + + return ret; +} + +int btrfs_ioctl_syno_locker_set(struct file *file, struct btrfs_ioctl_syno_locker_args __user *argp) +{ + int ret; + char* pathname; + struct inode *inode = file_inode(file); + struct btrfs_inode *binode = BTRFS_I(inode); + struct btrfs_root *root = binode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_syno_locker_args locker_args; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&locker_args, argp, sizeof(locker_args))) + return -EFAULT; + + ret = mnt_want_write_file(file); + if (ret) + return ret; + + ret = syno_locker_ioctl_args_validate(binode, &locker_args); + if (ret) + goto out; + + syno_locker_fs_clock_init(root->fs_info); + + /* enable feature-tree for btrfs_root_locker_item */ + if (!btrfs_syno_check_feat_tree_enable(root->fs_info)) { + mutex_lock(&fs_info->syno_feat_tree_ioctl_lock); + ret = btrfs_syno_feat_tree_enable(fs_info); + mutex_unlock(&fs_info->syno_feat_tree_ioctl_lock); + if (ret) + goto out; + } + + if (locker_args.flags & BTRFS_LOCKER_ROOT_PROP_MASK) { + ret = syno_locker_root_set(root, &locker_args); + if (ret) + goto out; + ret = btrfs_syno_locker_disk_root_update_trans(root); + if (ret) + goto out; + } + + if (locker_args.flags & BTRFS_LOCKER_INODE_PROP_MASK) { + ret = syno_locker_binode_set(binode, &locker_args); + if (ret) + goto out; + ret = btrfs_syno_locker_disk_inode_update_trans(inode); + if (ret) + goto out; + } + + ret = 0; +out: + mnt_drop_write_file(file); + + if (ret) { + pathname = kstrdup_quotable_file(file, GFP_KERNEL); + btrfs_err(fs_info, "failed to set locker properties of '%s'. err=%d.", pathname, ret); + kfree(pathname); + } + + return ret; +} diff --git a/fs/btrfs/syno-rbd-meta.c b/fs/btrfs/syno-rbd-meta.c new file mode 100644 index 000000000000..db40eb5b4135 --- /dev/null +++ b/fs/btrfs/syno-rbd-meta.c @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2000-2021 Synology Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ctree.h" +#include "async-thread.h" +#include "btrfs_inode.h" +#include "disk-io.h" +#include "extent_io.h" +#include "transaction.h" +#include "ordered-data.h" +#include "block-group.h" + +#include "syno-feat-tree.h" +#include "syno-rbd-meta.h" + +static int btrfs_pin_rbd_meta_file(struct inode *inode); +static int insert_rbd_meta_file_record(struct inode *inode); +static int delete_rbd_meta_file_record(struct inode *inode); +static int lookup_rbd_meta_file_extent(struct btrfs_fs_info *fs_info, + struct inode *inode, + struct btrfs_device **device, + u64 start, + u64 *logical_block_start, + u64 *physical_block_start, + u64 *len_out); + +int btrfs_rbd_meta_file_activate(struct inode *inode) +{ + int ret; + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + + ret = btrfs_pin_rbd_meta_file(inode); + if (ret) { + btrfs_info(fs_info, "failed to pin rbd meta file"); + goto out; + } + + ret = insert_rbd_meta_file_record(inode); + if (ret) { + btrfs_info(fs_info, "failed to insert rbd meta file record"); + goto out; + } +out: + if (ret) + btrfs_unpin_rbd_meta_file(inode); + return ret; +} + +int btrfs_rbd_meta_file_deactivate(struct inode *inode) +{ + int ret; + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + + ret = delete_rbd_meta_file_record(inode); + if (ret) { + btrfs_info(fs_info, "failed to delete rbd meta file record"); + return ret; + } + + btrfs_unpin_rbd_meta_file(inode); + return 0; +} + +int btrfs_rbd_meta_file_mapping(struct inode *inode, + struct syno_rbd_meta_ioctl_args *args) +{ + int ret; + unsigned long long i; + unsigned long long max_cnt; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; + struct extent_state *cached_state = NULL; + u64 isize; + u64 len; + + if (args->start == (u64)-1) + return -EINVAL; + + if (args->act == SYNO_RBD_META_MAPPING) + max_cnt = (args->size - sizeof(struct syno_rbd_meta_ioctl_args)) / + sizeof(struct syno_rbd_meta_file_mapping); + else + max_cnt = U64_MAX; + + isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize); + + args->cnt = 0; + for (i = 0; i < max_cnt; i++) { + u64 logical_block_start; + u64 physical_block_start; + + if (args->start >= isize) { + args->start = (u64)-1; + break; + } + len = isize - args->start; + + lock_extent_bits(io_tree, args->start, isize - 1, &cached_state); + ret = lookup_rbd_meta_file_extent(fs_info, inode, NULL, + args->start, &logical_block_start, + &physical_block_start, &len); + unlock_extent_cached(io_tree, args->start, isize - 1, &cached_state); + if (ret) + goto out; + if (args->act == SYNO_RBD_META_MAPPING) { + args->mappings[i].length = len; + args->mappings[i].dev_offset = physical_block_start; + } + args->start += len; + args->cnt++; + } + + if (args->start >= isize) + args->start = (u64)-1; + + ret = 0; +out: + return ret; +} + +static int iterate_all_file_records(struct btrfs_fs_info *fs_info, + int (*handler)(struct btrfs_fs_info *fs_info, + const u64 subvol_id, + const u64 i_ino, + const u64 generation)); +static int pin_file_helper(struct btrfs_fs_info *fs_info, + const u64 subvol_id, + const u64 i_ino, + const u64 generation); + +int btrfs_activate_all_rbd_meta_files(struct btrfs_fs_info *fs_info) +{ + return iterate_all_file_records(fs_info, pin_file_helper); +} + +static struct inode *get_file_inode(struct btrfs_fs_info *fs_info, + const u64 subvol_id, + const u64 i_ino, + const u64 generation) +{ + struct btrfs_root *root; + struct super_block *sb = fs_info->sb; + struct inode *inode = NULL; + + root = btrfs_get_fs_root(fs_info, subvol_id, true); + if (IS_ERR(root)) + return ERR_PTR(PTR_ERR(root)); + + inode = btrfs_iget(sb, i_ino, root); + if (IS_ERR(inode)) + goto out; + + if (generation != BTRFS_I(inode)->generation) { + btrfs_warn(fs_info, + "generation %llu of inode <%llu, %llu> record is not equal to %llu", + generation, subvol_id, i_ino, + BTRFS_I(inode)->generation); + iput(inode); + inode = ERR_PTR(-EINVAL); + } +out: + btrfs_put_root(root); + return inode; +} + +static int pin_file_helper(struct btrfs_fs_info *fs_info, + const u64 subvol_id, + const u64 i_ino, + const u64 generation) +{ + int ret; + struct inode *inode; + + inode = get_file_inode(fs_info, subvol_id, + i_ino, generation); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + ret = btrfs_pin_rbd_meta_file(inode); + if (ret) { + btrfs_unpin_rbd_meta_file(inode); + goto out; + } +out: + // for get_file_inode. + iput(inode); + return ret; +} + +static int iterate_inode_records(struct btrfs_fs_info *fs_info, + struct btrfs_root *feat_root, + const u64 subvol_id, + int (*handler)(struct btrfs_fs_info *fs_info, + const u64 subvol_id, + const u64 i_ino, + const u64 generation)) +{ + int ret; + int cnt; + int slot; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_rbd_meta_file_inode_record_item *item; + struct extent_buffer *leaf; + u32 nritems; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = subvol_id; + key.type = SYNO_BTRFS_RBD_META_FILE_INODE_RECORD; + key.offset = 0; + + ret = btrfs_search_slot(NULL, feat_root, &key, path, 0, 0); + if (ret < 0) + goto out; + + cnt = 0; + while (1) { + u64 generation; + leaf = path->nodes[0]; + slot = path->slots[0]; + nritems = btrfs_header_nritems(leaf); + if (slot >= nritems) { + ret = btrfs_next_leaf(feat_root, path); + if (ret < 0) + goto out; + if (ret > 0) + break; + continue; + } + btrfs_item_key_to_cpu(leaf, &key, slot); + + if (key.objectid != subvol_id || + key.type != SYNO_BTRFS_RBD_META_FILE_INODE_RECORD) + break; + + item = btrfs_item_ptr(leaf, slot, + struct btrfs_rbd_meta_file_inode_record_item); + + generation = btrfs_syno_rbd_meta_file_inode_record_generation( + leaf, item); + + ret = handler(fs_info, subvol_id, key.offset, + generation); + if (ret) + goto out; + + cnt++; + path->slots[0]++; + } + ret = cnt; +out: + btrfs_free_path(path); + return ret; +} + +static int iterate_all_file_records(struct btrfs_fs_info *fs_info, + int (*handler)(struct btrfs_fs_info *fs_info, + const u64 subvol_id, + const u64 i_ino, + const u64 generation)) +{ + int ret; + int slot; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_root *feat_root = fs_info->syno_feat_root; + struct btrfs_rbd_meta_file_subvol_record_item *item; + struct extent_buffer *leaf; + u64 subvol_id; + u32 nritems; + u32 inode_cnt; + + if (!btrfs_syno_check_feat_tree_enable(fs_info)) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.type = SYNO_BTRFS_RBD_META_FILE_SUBVOL_RECORD; + key.offset = 0; + + ret = btrfs_search_slot(NULL, feat_root, &key, path, 0, 0); + if (ret < 0) + goto out; + + while (1) { + leaf = path->nodes[0]; + slot = path->slots[0]; + nritems = btrfs_header_nritems(leaf); + if (slot >= nritems) { + ret = btrfs_next_leaf(feat_root, path); + if (ret < 0) + goto out; + if (ret > 0) + break; + continue; + } + btrfs_item_key_to_cpu(leaf, &key, slot); + + if (key.objectid != 0 || + key.type != SYNO_BTRFS_RBD_META_FILE_SUBVOL_RECORD) + break; + + subvol_id = key.offset; + item = btrfs_item_ptr(leaf, slot, + struct btrfs_rbd_meta_file_subvol_record_item); + + inode_cnt = btrfs_syno_rbd_meta_file_subvol_record_inode_cnt( + leaf, item); + ret = iterate_inode_records(fs_info, feat_root, + subvol_id, handler); + if (0 > ret) + goto out; + if (ret != inode_cnt) + btrfs_warn(fs_info, + "the count (%d) of inode is not match subvol %llu record (%u)", + ret, subvol_id, inode_cnt); + + path->slots[0]++; + } + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +static int delete_all_inode_records(struct btrfs_fs_info *fs_info, + struct btrfs_root *feat_root, + struct btrfs_path *path, + u64 subvol_id) +{ + int ret; + int slot; + struct btrfs_trans_handle *trans; + struct btrfs_key key; + struct extent_buffer *leaf; + u32 nritems; + int del_nr; + + while (1) { + trans = btrfs_start_transaction_fallback_global_rsv(feat_root, 1); + if (IS_ERR(trans)) + goto out; + + key.objectid = subvol_id; + key.type = SYNO_BTRFS_RBD_META_FILE_INODE_RECORD; + key.offset = 0; + + ret = btrfs_search_slot(trans, feat_root, &key, path, -1, 1); + if (ret < 0) + goto end_trans; + + leaf = path->nodes[0]; + slot = path->slots[0]; + nritems = btrfs_header_nritems(leaf); + + for (del_nr = 0; slot < nritems; del_nr++, slot++) { + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid != subvol_id || + key.type != SYNO_BTRFS_RBD_META_FILE_INODE_RECORD) + break; + } + + if (!del_nr) + break; + + ret = btrfs_del_items(trans, feat_root, path, path->slots[0], del_nr); + if (ret) + goto end_trans; + btrfs_release_path(path); + + ret = btrfs_end_transaction_throttle(trans); + if (ret) + goto out; + trans = NULL; + } + + ret = 0; +end_trans: + if (trans) + btrfs_end_transaction_throttle(trans); +out: + btrfs_release_path(path); + return ret; +} + +int btrfs_delete_all_rbd_meta_file_records(struct inode *inode) +{ + int ret; + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + struct btrfs_trans_handle *trans; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_root *feat_root = fs_info->syno_feat_root; + u64 subvol_id; + + if (!btrfs_syno_check_feat_tree_enable(fs_info)) + return 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + while (1) { + trans = btrfs_start_transaction_fallback_global_rsv(feat_root, 1); + if (IS_ERR(trans)) + goto out; + + key.objectid = 0; + key.type = SYNO_BTRFS_RBD_META_FILE_SUBVOL_RECORD; + key.offset = 0; + ret = btrfs_search_slot(trans, feat_root, &key, path, -1, 1); + if (ret < 0) + goto end_trans; + + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + if (key.objectid != 0 || + key.type != SYNO_BTRFS_RBD_META_FILE_SUBVOL_RECORD) + break; + + subvol_id = key.offset; + ret = btrfs_del_item(trans, feat_root, path); + if (ret) + goto end_trans; + btrfs_release_path(path); + ret = btrfs_end_transaction_throttle(trans); + if (ret) + goto out; + trans = NULL; + + ret = delete_all_inode_records(fs_info, feat_root, + path, subvol_id); + if (ret) + goto out; + } + ret = 0; +end_trans: + if (trans) + btrfs_end_transaction_throttle(trans); +out: + btrfs_free_path(path); + return ret; +} + +static int delete_subvol_record(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + struct btrfs_root *feat_root, + struct btrfs_path *path, + struct btrfs_key key) +{ + int ret; + + ret = btrfs_search_slot(trans, feat_root, &key, path, -1, 1); + if (ret < 0) + goto out; + else if (ret) { + ret = 0; + goto out; + } + + ret = btrfs_del_item(trans, feat_root, path); + if (ret) + goto out; + + ret = 0; +out: + btrfs_release_path(path); + return ret; +} + +static int insert_subvol_record(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + struct btrfs_root *feat_root, + struct btrfs_path *path, + struct btrfs_key key) +{ + int ret; + struct extent_buffer *leaf; + struct btrfs_rbd_meta_file_subvol_record_item *item; + + ret = btrfs_insert_empty_item(trans, feat_root, path, &key, + sizeof(struct btrfs_rbd_meta_file_subvol_record_item)); + if (ret) + goto out; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_rbd_meta_file_subvol_record_item); + + btrfs_set_syno_rbd_meta_file_subvol_record_inode_cnt(leaf, item, 1); + btrfs_mark_buffer_dirty(path->nodes[0]); + ret = 0; +out: + btrfs_release_path(path); + return ret; +} + +static int update_subvol_record(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + struct btrfs_root *feat_root, + struct btrfs_path *path, + const u64 subvol_id, + const int insert_cnt) +{ + int ret; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_rbd_meta_file_subvol_record_item *item; + u32 inode_cnt = 0; + + key.objectid = 0; + key.type = SYNO_BTRFS_RBD_META_FILE_SUBVOL_RECORD; + key.offset = subvol_id; + + ret = btrfs_search_slot(trans, feat_root, &key, path, 0, 1); + if (ret < 0) + goto out; + else if (ret) { + if (insert_cnt < 0) { + ret = 0; + goto out; + } + goto insert; + } + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_rbd_meta_file_subvol_record_item); + + inode_cnt = btrfs_syno_rbd_meta_file_subvol_record_inode_cnt(leaf, item); + if (inode_cnt <= 1 && insert_cnt < 0) + goto delete; + + btrfs_set_syno_rbd_meta_file_subvol_record_inode_cnt(leaf, item, + inode_cnt + insert_cnt); + btrfs_mark_buffer_dirty(path->nodes[0]); + + ret = 0; +out: + btrfs_release_path(path); + return ret; +insert: + btrfs_release_path(path); + return insert_subvol_record(fs_info, trans, + feat_root, path, key); +delete: + btrfs_release_path(path); + return delete_subvol_record(fs_info, trans, + feat_root, path, key); +} + +/* + * return 1: delete success + * 0: record is not exist + * -1: error + */ +static int delete_inode_record(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + struct btrfs_root *feat_root, + struct btrfs_path *path, + u64 subvol_id, + u64 i_ino) +{ + int ret; + struct btrfs_key key; + + key.objectid = subvol_id; + key.type = SYNO_BTRFS_RBD_META_FILE_INODE_RECORD; + key.offset = i_ino; + + ret = btrfs_search_slot(trans, feat_root, &key, path, -1, 1); + if (ret < 0) + goto out; + else if (ret) { + ret = 0; + goto out; + } + + ret = btrfs_del_item(trans, feat_root, path); + if (ret) + goto out; + + ret = 1; +out: + btrfs_release_path(path); + return ret; +} + +static int insert_inode_record(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, + struct btrfs_root *feat_root, + struct btrfs_path *path, + struct inode *inode, + u64 subvol_id, + u64 i_ino) +{ + int ret; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_rbd_meta_file_inode_record_item *item; + + key.objectid = subvol_id; + key.type = SYNO_BTRFS_RBD_META_FILE_INODE_RECORD; + key.offset = i_ino; + + ret = btrfs_insert_empty_item(trans, feat_root, path, &key, + sizeof(struct btrfs_rbd_meta_file_inode_record_item)); + if (ret) + goto out; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_rbd_meta_file_inode_record_item); + + btrfs_set_syno_rbd_meta_file_inode_record_generation(leaf, item, + BTRFS_I(inode)->generation); + btrfs_mark_buffer_dirty(path->nodes[0]); + + ret = 0; +out: + btrfs_release_path(path); + return ret; +} + +static int delete_rbd_meta_file_record(struct inode *inode) +{ + int ret; + int func; + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + struct btrfs_trans_handle *trans; + struct btrfs_root *feat_root = fs_info->syno_feat_root; + struct btrfs_path *path; + u64 subvol_id = BTRFS_I(inode)->root->root_key.objectid; + u64 i_ino = btrfs_ino(BTRFS_I(inode)); + + if (!btrfs_syno_check_feat_tree_enable(fs_info)) + return 0; + + // 1 for inode record item, 1 for subvol record item. + trans = btrfs_start_transaction(feat_root, 2); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto err; + } + + ret = delete_inode_record(fs_info, trans, feat_root, + path, subvol_id, i_ino); + if (ret < 0) + goto err; + else if (!ret) + goto out; + + ret = update_subvol_record(fs_info, trans, feat_root, + path, subvol_id, -1); + if (ret) + goto rollback; +out: + btrfs_free_path(path); + return btrfs_commit_transaction(trans); + +rollback: + func = insert_inode_record(fs_info, trans, feat_root, + path, inode, subvol_id, i_ino); + if (func) + btrfs_warn(fs_info, + "failed to rollback rbd meta file inode record item with [%llu,%llu]", + subvol_id, i_ino); +err: + btrfs_free_path(path); + btrfs_end_transaction(trans); + return ret; +} + +static int insert_rbd_meta_file_record(struct inode *inode) +{ + int ret; + int func; + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + struct btrfs_trans_handle *trans; + struct btrfs_root *feat_root = fs_info->syno_feat_root; + struct btrfs_path *path; + u64 subvol_id; + u64 i_ino; + + if (!btrfs_syno_check_feat_tree_enable(fs_info)) + return -EINVAL; + + // 1 for inode record item, 1 for subvol record item. + trans = btrfs_start_transaction(feat_root, 2); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto err; + } + + subvol_id = BTRFS_I(inode)->root->root_key.objectid; + i_ino = btrfs_ino(BTRFS_I(inode)); + + ret = insert_inode_record(fs_info, trans, feat_root, + path, inode, subvol_id, i_ino); + if (ret) + goto err; + + ret = update_subvol_record(fs_info, trans, feat_root, + path, subvol_id, 1); + if (ret) + goto rollback; + + btrfs_free_path(path); + return btrfs_commit_transaction(trans); + +rollback: + func = delete_inode_record(fs_info, trans, feat_root, + path, subvol_id, i_ino); + if (func < 0) + btrfs_warn(fs_info, + "failed to rollback rbd meta file inode record with [%llu,%llu]", + subvol_id, i_ino); +err: + btrfs_free_path(path); + btrfs_end_transaction(trans); + return ret; +} + +static int lookup_rbd_meta_file_extent(struct btrfs_fs_info *fs_info, + struct inode *inode, + struct btrfs_device **device, + u64 start, + u64 *logical_block_start, + u64 *physical_block_start, + u64 *len_out) +{ + int ret; + struct extent_map *em = NULL; + u64 len = *len_out; + + em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len); + if (IS_ERR(em)) + return PTR_ERR(em); + + if (em->block_start == EXTENT_MAP_HOLE) { + btrfs_info(fs_info, "rbd meta file must not have holes"); + ret = -EINVAL; + goto out; + } + if (em->block_start == EXTENT_MAP_INLINE) { + btrfs_info(fs_info, "rbd meta file must not be inline"); + ret = -EINVAL; + goto out; + } + if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { + btrfs_info(fs_info, "rbd meta file must not be compressed"); + ret = -EINVAL; + goto out; + } + + *logical_block_start = em->block_start + (start - em->start); + len = min(len, em->len - (start - em->start)); + free_extent_map(em); + em = NULL; + + ret = can_nocow_extent(inode, start, &len, NULL, NULL, NULL, true); + if (ret < 0) + goto out; + else if (!ret) { + btrfs_info(fs_info, + "rbd meta file must not be copy-on-write"); + ret = -EAGAIN; + goto out; + } + + em = btrfs_get_chunk_map(fs_info, *logical_block_start, len); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto out; + } + + if (em->map_lookup->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { + btrfs_info(fs_info, + "rbd meta file must have single data profile"); + ret = -EINVAL; + goto out; + } + + if (device) { + if (*device == NULL) + *device = em->map_lookup->stripes[0].dev; + else if (*device != em->map_lookup->stripes[0].dev) { + btrfs_info(fs_info, "swapfile must be on one device"); + ret = -EINVAL; + goto out; + } + } + + *physical_block_start = (em->map_lookup->stripes[0].physical + + (*logical_block_start - em->start)); + len = min(len, em->len - (*logical_block_start - em->start)); + + *len_out = len; + ret = 0; +out: + if (!IS_ERR_OR_NULL(em)) + free_extent_map(em); + return ret; +} + +void btrfs_unpin_rbd_meta_file(struct inode *inode) +{ + struct btrfs_fs_info *fs_info; + + if (!inode || list_empty(&(BTRFS_I(inode)->syno_rbd_meta_file))) + goto out; + + fs_info = BTRFS_I(inode)->root->fs_info; + spin_lock(&fs_info->syno_rbd.lock); + if (!list_empty(&(BTRFS_I(inode)->syno_rbd_meta_file))) { + list_del_init(&(BTRFS_I(inode)->syno_rbd_meta_file)); + } else { + spin_unlock(&fs_info->syno_rbd.lock); + goto out; + } + spin_unlock(&fs_info->syno_rbd.lock); + btrfs_free_swapfile_pins(inode); + atomic_dec(&BTRFS_I(inode)->root->nr_swapfiles); + + inode_lock(inode); + inode->i_flags &= ~S_SWAPFILE; + inode_unlock(inode); + + iput(inode); +out: + return; +} + +static int btrfs_pin_rbd_meta_file(struct inode *inode) +{ + bool is_dev_pinned = false; + int ret; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; + struct extent_state *cached_state = NULL; + struct btrfs_device *device = NULL; + u64 start; + u64 isize; + + inode_lock(inode); + if (IS_SWAPFILE(inode)) { + ret = -EBUSY; + goto unlock_inode; + } + /* + * If the meta file file was just created, make sure delalloc is done. If the + * file changes again after this, the user is doing something stupid and + * we don't really care. + */ + ret = btrfs_wait_ordered_range(inode, 0, (u64)-1); + if (ret) + goto unlock_inode; + + if (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS) { + btrfs_info(fs_info, "rbd meta file must not be compressed"); + ret = -EINVAL; + goto unlock_inode; + } + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW)) { + btrfs_info(fs_info, "rbd meta file must not be copy-on-write"); + ret = -EINVAL; + goto unlock_inode; + } + if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { + btrfs_info(fs_info, "rbd meta file must not be checksummed"); + ret = -EINVAL; + goto unlock_inode; + } + if (!IS_IMMUTABLE(inode)) { + btrfs_info(fs_info, "rbd meta file must be immutable"); + ret = -EINVAL; + goto unlock_inode; + } + isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize); + if (!isize) { + ret = -EINVAL; + goto unlock_inode; + } + /* + * Balance or device remove/replace/resize can move stuff around from + * under us. The EXCL_OP flag makes sure they aren't running/won't run + * concurrently while we are mapping the swap extents, and + * fs_info->swapfile_pins prevents them from running while the rbd meta file + * is active and moving the extents. Note that this also prevents a + * concurrent device add which isn't actually necessary, but it's not + * really worth the trouble to allow it. + */ + if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_SWAP_ACTIVATE)) { + btrfs_info(fs_info, + "cannot activate rbd-meta while exclusive operation is running"); + ret = -EBUSY; + goto unlock_inode; + } + + /* + * Prevent snapshot creation while we are activating the swap file. + * We do not want to race with snapshot creation. If snapshot creation + * already started before we bumped nr_swapfiles from 0 to 1 and + * completes before the first write into the swap file after it is + * activated, than that write would fallback to COW. + */ + if (!btrfs_drew_try_write_lock(&root->snapshot_lock)) { + btrfs_warn(fs_info, + "cannot activate rbd-meta because snapshot creation is in progress"); + ret = -EINVAL; + goto finish_op; + } + /* + * Snapshots can create extents which require COW even if NODATACOW is + * set. We use this counter to prevent snapshots. We must increment it + * before walking the extents because we don't want a concurrent + * snapshot to run after we've already checked the extents. + */ + atomic_inc(&BTRFS_I(inode)->root->nr_swapfiles); + spin_lock(&fs_info->syno_rbd.lock); + list_add(&(BTRFS_I(inode)->syno_rbd_meta_file), + &fs_info->syno_rbd.pinned_meta_files); + spin_unlock(&fs_info->syno_rbd.lock); + // We need to hold inode until this inode been deactivated. + ihold(inode); + + lock_extent_bits(io_tree, 0, isize - 1, &cached_state); + start = 0; + while (start < isize) { + u64 logical_block_start, physical_block_start; + struct btrfs_block_group *bg; + u64 len = isize - start; + ret = lookup_rbd_meta_file_extent(fs_info, inode, + &device, start, + &logical_block_start, + &physical_block_start, + &len); + if (ret) { + btrfs_info(fs_info, + "could not lookup rbd meta file extent, with start %llu", + start); + goto unlock_extent; + } + + if (device && !is_dev_pinned) { + ret = btrfs_add_swapfile_pin(inode, device, false); + if (0 > ret) { + btrfs_info(fs_info, "could not pin device"); + goto unlock_extent; + } + is_dev_pinned = true; + } + + bg = btrfs_lookup_block_group(fs_info, logical_block_start); + if (!bg) { + btrfs_info(fs_info, + "could not find block group containing rbd meta file"); + ret = -EINVAL; + goto unlock_extent; + } + + if (!btrfs_inc_block_group_swap_extents(bg)) { + btrfs_warn(fs_info, + "block group for rbd-meta at %llu is read-only%s", + bg->start, + atomic_read(&fs_info->scrubs_running) ? + " (scrub running)" : ""); + btrfs_put_block_group(bg); + ret = -EINVAL; + goto unlock_extent; + } + ret = btrfs_add_swapfile_pin(inode, bg, true); + if (ret) { + btrfs_put_block_group(bg); + if (ret == 1) + ret = 0; + else { + btrfs_info(fs_info, "could not pin block group"); + goto unlock_extent; + } + } + start += len; + } + inode->i_flags |= S_SWAPFILE; + ret = 0; + +unlock_extent: + unlock_extent_cached(io_tree, 0, isize - 1, &cached_state); + btrfs_drew_write_unlock(&root->snapshot_lock); +finish_op: + btrfs_exclop_finish(fs_info); +unlock_inode: + inode_unlock(inode); + return ret; +} diff --git a/fs/btrfs/syno-rbd-meta.h b/fs/btrfs/syno-rbd-meta.h new file mode 100644 index 000000000000..17ce09af1d4c --- /dev/null +++ b/fs/btrfs/syno-rbd-meta.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2000-2021 Synology Inc. All rights reserved. + */ + +#ifndef __BTRFS_SYNO_RBD_META_H_ +#define __BTRFS_SYNO_RBD_META_H_ +#include + +#include "ctree.h" +#include "volumes.h" + +int btrfs_rbd_meta_file_activate(struct inode *inode); +int btrfs_rbd_meta_file_deactivate(struct inode *inode); +int btrfs_rbd_meta_file_mapping(struct inode *inode, + struct syno_rbd_meta_ioctl_args *args); + +int btrfs_delete_all_rbd_meta_file_records(struct inode *inode); +int btrfs_activate_all_rbd_meta_files(struct btrfs_fs_info *fs_info); +void btrfs_unpin_rbd_meta_file(struct inode *inode); + +#endif /* __BTRFS_SYNO_RBD_META_H_ */ diff --git a/fs/btrfs/syno_acl.c b/fs/btrfs/syno_acl.c new file mode 100644 index 000000000000..66978c814d81 --- /dev/null +++ b/fs/btrfs/syno_acl.c @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#include +#include +#include + +#include "ctree.h" +#include "btrfs_inode.h" +#include "xattr.h" + +#include +#include "syno_acl.h" + +/* + * Inode operation syno_acl_get(). + */ +struct syno_acl *btrfs_get_syno_acl(struct inode *inode) +{ + int size; + char *value = NULL; + struct syno_acl *acl; + + acl = get_cached_syno_acl(inode); + if (!is_uncached_syno_acl(acl)) + return acl; + + size = btrfs_getxattr(inode, SYNO_ACL_XATTR_ACCESS, "", 0); + if (size > 0) { + value = kzalloc(size, GFP_NOFS); + if (!value) + return ERR_PTR(-ENOMEM); + size = btrfs_getxattr(inode, SYNO_ACL_XATTR_ACCESS, value, size); + } + + if (size > 0) + acl = syno_acl_from_disk(value, size); + else if (size == -ENOENT || size == -ENODATA || size == 0) + /* FIXME, who returns -ENOENT? I think nobody */ + acl = NULL; + else + acl = ERR_PTR(size); + + kfree(value); + + if (!IS_ERR(acl)) + set_cached_syno_acl(inode, acl); + + return acl; +} + +/* + * Needs to be called with fs_mutex held + */ +static int __btrfs_set_syno_acl(struct btrfs_trans_handle *trans, + struct inode *inode, struct syno_acl *acl) +{ + int ret; + size_t size = 0; + char *value = NULL; + + if (acl) { + ret = syno_acl_valid(acl); + if (ret < 0) + return ret; + + value = syno_acl_to_disk(acl, &size); + if (IS_ERR(value)) + return PTR_ERR(value); + } + + if (trans) + ret = btrfs_setxattr(trans, inode, SYNO_ACL_XATTR_ACCESS, value, size, 0); + else + ret = btrfs_setxattr_trans(inode, SYNO_ACL_XATTR_ACCESS, value, size, 0); + + kfree(value); + if (!ret) + set_cached_syno_acl(inode, acl); + + return ret; +} + +/* + * Inode operation syno_acl_set(). + */ +int btrfs_set_syno_acl(struct inode *inode, struct syno_acl *acl) +{ + int ret; + + if (!inode || !acl) + return -EINVAL; + + ret = __btrfs_set_syno_acl(NULL, inode, acl); + + return ret; +} + +static int +btrfs_xattr_syno_acl_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *value, size_t size) +{ + int ret = 0; + struct syno_acl *acl; + + acl = btrfs_get_syno_acl(dentry->d_inode); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + + ret = syno_acl_to_xattr(acl, value, size); + syno_acl_release(acl); + + return ret; +} + +static int +btrfs_xattr_syno_acl_set(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, int flags) +{ + int ret; + struct syno_acl *acl = NULL; + + if (value) { + acl = syno_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + ret = syno_acl_valid(acl); + if (ret) + goto out; + } + } + + ret = __btrfs_set_syno_acl(NULL, dentry->d_inode, acl); +out: + syno_acl_release(acl); + return ret; +} + +const struct xattr_handler btrfs_xattr_synoacl_access_handler = { + .name = SYNO_ACL_XATTR_ACCESS, + .get = btrfs_xattr_syno_acl_get, + .set = btrfs_xattr_syno_acl_set, +}; diff --git a/fs/btrfs/syno_acl.h b/fs/btrfs/syno_acl.h new file mode 100644 index 000000000000..a29dfbb3fe77 --- /dev/null +++ b/fs/btrfs/syno_acl.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ + +#ifndef _BTRFS_SYNO_ACL_H +#define _BTRFS_SYNO_ACL_H + +#include + +int btrfs_set_syno_acl(struct inode *inode, struct syno_acl *acl); +struct syno_acl *btrfs_get_syno_acl(struct inode *inode); + +#endif /* _BTRFS_SYNO_ACL_H */ diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 3bb6b688ece5..7d6caad01fb0 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -10,6 +13,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "ctree.h" #include "discard.h" @@ -69,6 +75,10 @@ static struct btrfs_feature_attr btrfs_attr_features_##_name = { \ BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature) #define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \ BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) +#ifdef MY_ABC_HERE +#define BTRFS_FEAT_ATTR_SYNO_CAPABILITY(name, feature) \ + BTRFS_FEAT_ATTR(name, FEAT_SYNO_CAPABILITY, BTRFS_FEATURE_SYNO_CAPABILITY, feature) +#endif /* MY_ABC_HERE */ static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); @@ -97,6 +107,10 @@ static u64 get_features(struct btrfs_fs_info *fs_info, return btrfs_super_compat_flags(disk_super); else if (set == FEAT_COMPAT_RO) return btrfs_super_compat_ro_flags(disk_super); +#ifdef MY_ABC_HERE + else if (set == FEAT_SYNO_CAPABILITY) + return btrfs_super_syno_capability_flags(disk_super); +#endif /* MY_ABC_HERE */ else return btrfs_super_incompat_flags(disk_super); } @@ -109,6 +123,10 @@ static void set_features(struct btrfs_fs_info *fs_info, btrfs_set_super_compat_flags(disk_super, features); else if (set == FEAT_COMPAT_RO) btrfs_set_super_compat_ro_flags(disk_super, features); +#ifdef MY_ABC_HERE + else if (set == FEAT_SYNO_CAPABILITY) + btrfs_set_super_syno_capability_flags(disk_super, features); +#endif /* MY_ABC_HERE */ else btrfs_set_super_incompat_flags(disk_super, features); } @@ -130,6 +148,12 @@ static int can_modify_feature(struct btrfs_feature_attr *fa) set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; break; +#ifdef MY_ABC_HERE + case FEAT_SYNO_CAPABILITY: + set = BTRFS_FEATURE_SYNO_CAPABILITY_SAFE_SET; + clear = BTRFS_FEATURE_SYNO_CAPABILITY_SAFE_CLEAR; + break; +#endif /* MY_ABC_HERE */ default: pr_warn("btrfs: sysfs: unknown feature set %d\n", fa->feature_set); @@ -187,6 +211,11 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj, } else if (fa->feature_set == FEAT_COMPAT_RO) { set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; +#ifdef MY_ABC_HERE + } else if (fa->feature_set == FEAT_SYNO_CAPABILITY) { + set = BTRFS_FEATURE_SYNO_CAPABILITY_SAFE_SET; + clear = BTRFS_FEATURE_SYNO_CAPABILITY_SAFE_CLEAR; +#endif /* MY_ABC_HERE */ } else { set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; @@ -241,6 +270,10 @@ static umode_t btrfs_feature_visible(struct kobject *kobj, fa = attr_to_btrfs_feature_attr(attr); features = get_features(fs_info, fa->feature_set); +#ifdef MY_ABC_HERE + if (fa->feature_set == FEAT_COMPAT_RO) + features |= BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE; +#endif /* MY_ABC_HERE */ if (can_modify_feature(fa)) mode |= S_IWUSR; else if (!(features & fa->feature_bit)) @@ -263,6 +296,12 @@ BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID); BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE); BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34); +#ifdef MY_ABC_HERE +BTRFS_FEAT_ATTR_COMPAT(block_group_cache_tree, BLOCK_GROUP_CACHE_TREE); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +BTRFS_FEAT_ATTR_SYNO_CAPABILITY(syno_rbd_meta, RBD_META); +#endif /* MY_ABC_HERE */ static struct attribute *btrfs_supported_feature_attrs[] = { BTRFS_FEAT_ATTR_PTR(mixed_backref), @@ -278,6 +317,12 @@ static struct attribute *btrfs_supported_feature_attrs[] = { BTRFS_FEAT_ATTR_PTR(metadata_uuid), BTRFS_FEAT_ATTR_PTR(free_space_tree), BTRFS_FEAT_ATTR_PTR(raid1c34), +#ifdef MY_ABC_HERE + BTRFS_FEAT_ATTR_PTR(block_group_cache_tree), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_FEAT_ATTR_PTR(syno_rbd_meta), +#endif /* MY_ABC_HERE */ NULL }; @@ -347,6 +392,79 @@ static const struct attribute_group btrfs_static_feature_attr_group = { .attrs = btrfs_supported_static_feature_attrs, }; +#ifdef MY_ABC_HERE +static ssize_t btrfs_locker_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", btrfs_syno_locker_feature_is_support() ? 1 : 0); +} + +static ssize_t btrfs_locker_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + int ret; + unsigned long val; + + ret = kstrtoul(skip_spaces(buf), 0, &val); + if (ret) + return ret; + + if (!val) + btrfs_syno_locker_feature_disable(); + + return len; +} +BTRFS_ATTR_RW(, locker, btrfs_locker_show, btrfs_locker_store); + +static struct attribute *btrfs_locker_feature_attrs[] = { + BTRFS_ATTR_PTR(, locker), + NULL +}; + +static const struct attribute_group btrfs_locker_feature_attr_group = { + .name = "features", + .attrs = btrfs_locker_feature_attrs, +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_qgroup_soft_limit_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%llu\n", qgroup_soft_limit); +} + +static ssize_t btrfs_qgroup_soft_limit_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + int ret; + u64 val; + + ret = kstrtoull(skip_spaces(buf), 0, &val); + if (ret) + return ret; + + if (val > 100) + return -EINVAL; + + qgroup_soft_limit = val; + return len; +} +BTRFS_ATTR_RW(, qgroup_soft_limit, btrfs_qgroup_soft_limit_show, btrfs_qgroup_soft_limit_store); + +static struct attribute *btrfs_qgroup_soft_limit_feature_attrs[] = { + BTRFS_ATTR_PTR(, qgroup_soft_limit), + NULL +}; + +static const struct attribute_group btrfs_qgroup_soft_limit_feature_attr_group = { + .name = "features", + .attrs = btrfs_qgroup_soft_limit_feature_attrs, +}; +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_BTRFS_DEBUG /* @@ -561,6 +679,55 @@ static ssize_t global_rsv_reserved_show(struct kobject *kobj, } BTRFS_ATTR(allocation, global_rsv_reserved, global_rsv_reserved_show); +#ifdef MY_ABC_HERE +static ssize_t cleaner_rsv_size_show(struct kobject *kobj, + struct kobj_attribute *ka, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + struct btrfs_block_rsv *block_rsv = &fs_info->cleaner_block_rsv; + return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); +} +BTRFS_ATTR(allocation, cleaner_rsv_size, cleaner_rsv_size_show); + +static ssize_t cleaner_rsv_reserved_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + struct btrfs_block_rsv *block_rsv = &fs_info->cleaner_block_rsv; + return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); +} +BTRFS_ATTR(allocation, cleaner_rsv_reserved, cleaner_rsv_reserved_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t syno_bg_prefetch_enabled_show(struct kobject *kobj, + struct kobj_attribute *ka, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->syno_allocator.bg_prefetch_running ? 1 : 0); +} +static ssize_t syno_bg_prefetch_enabled_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + u8 val; + int ret; + + if (len > 2) + return -EINVAL; + ret = kstrtou8(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val == 0 || val == 1) { + fs_info->syno_allocator.bg_prefetch_running = !!val; + return len; + } + return -EINVAL; +} +BTRFS_ATTR_RW(allocation, syno_bg_prefetch_enabled, syno_bg_prefetch_enabled_show, syno_bg_prefetch_enabled_store); +#endif /* MY_ABC_HERE */ + #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj) @@ -638,6 +805,22 @@ SPACE_INFO_ATTR(disk_total); BTRFS_ATTR(space_info, total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned); +#ifdef MY_ABC_HERE +static ssize_t btrfs_space_info_show_syno_allocation(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_space_info *sinfo = to_space_info(kobj); + int len = 0; + + len += snprintf(buf + len, PAGE_SIZE, "fallback_relink_count:%llu\n", (u64)atomic64_read(&sinfo->syno_allocator.fallback_relink_count)); + len += snprintf(buf + len, PAGE_SIZE, "fallback_full_scan_count:%llu\n", (u64)atomic64_read(&sinfo->syno_allocator.fallback_full_scan_count)); + + return len; +} +BTRFS_ATTR(space_info, syno_allocation, btrfs_space_info_show_syno_allocation); +#endif /* MY_ABC_HERE */ + static struct attribute *space_info_attrs[] = { BTRFS_ATTR_PTR(space_info, flags), BTRFS_ATTR_PTR(space_info, total_bytes), @@ -649,6 +832,9 @@ static struct attribute *space_info_attrs[] = { BTRFS_ATTR_PTR(space_info, disk_used), BTRFS_ATTR_PTR(space_info, disk_total), BTRFS_ATTR_PTR(space_info, total_bytes_pinned), +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(space_info, syno_allocation), +#endif /* MY_ABC_HERE */ NULL, }; ATTRIBUTE_GROUPS(space_info); @@ -669,6 +855,13 @@ static struct kobj_type space_info_ktype = { static const struct attribute *allocation_attrs[] = { BTRFS_ATTR_PTR(allocation, global_rsv_reserved), BTRFS_ATTR_PTR(allocation, global_rsv_size), +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(allocation, cleaner_rsv_reserved), + BTRFS_ATTR_PTR(allocation, cleaner_rsv_size), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(allocation, syno_bg_prefetch_enabled), +#endif /* MY_ABC_HERE */ NULL, }; @@ -854,6 +1047,570 @@ static ssize_t btrfs_exclusive_operation_show(struct kobject *kobj, } BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show); +#ifdef MY_ABC_HERE +static ssize_t btrfs_snapshot_cleaner_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->snapshot_cleaner); +} + +static ssize_t btrfs_snapshot_cleaner_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + unsigned int val; + int ret; + + if (len > 2) + return -EINVAL; + ret = kstrtouint(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val == 0 || val == 1) { + fs_info->snapshot_cleaner = val; + return len; + } + return -EINVAL; +} + +BTRFS_ATTR_RW(, snapshot_cleaner, btrfs_snapshot_cleaner_show, + btrfs_snapshot_cleaner_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_metadata_cache_enable_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->metadata_cache_enable); +} + +static ssize_t btrfs_metadata_cache_enable_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + unsigned int val; + int ret; + + if (len > 2) + return -EINVAL; + ret = kstrtouint(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val == 0 || val == 1) { + fs_info->metadata_cache_enable = !!val; + return len; + } + return -EINVAL; +} + +BTRFS_ATTR_RW(, metadata_cache_enable, + btrfs_metadata_cache_enable_show, + btrfs_metadata_cache_enable_store); +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +static ssize_t btrfs_mount_path_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + int ret; + spin_lock(&fs_info->mount_path_lock); + ret = snprintf(buf, PAGE_SIZE, "%s\n", + fs_info->mount_path ? fs_info->mount_path : "NULL"); + spin_unlock(&fs_info->mount_path_lock); + return ret; +} + +static ssize_t btrfs_mount_path_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + char *str; + + if (!len || !buf) + return -EINVAL; + + str = kmemdup_nul(buf, len, GFP_KERNEL); + if (!str) + return -ENOMEM; + + spin_lock(&fs_info->mount_path_lock); + kfree(fs_info->mount_path); + fs_info->mount_path = str; + spin_unlock(&fs_info->mount_path_lock); + return len; +} + +BTRFS_ATTR_RW(, mount_path, + btrfs_mount_path_show, + btrfs_mount_path_store); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_correction_suppress_log_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->correction_suppress_log); +} + +static ssize_t btrfs_correction_suppress_log_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + u8 val; + int ret; + + if (len > 2) + return -EINVAL; + ret = kstrtou8(skip_spaces(buf), 0, &val); + if (ret) + return ret; + switch (val) { + case 0: + fs_info->correction_suppress_log = DATA_CORRECTION_PRINT_ALL_LOG; + break; + case 1: + fs_info->correction_suppress_log = DATA_CORRECTION_RATE_LIMIT; + break; + case 2: + fs_info->correction_suppress_log = DATA_CORRECTION_SUPPRESS_ALL; + break; + default: + return -EINVAL; + } + + return len; +} + +BTRFS_ATTR_RW(, correction_suppress_log, + btrfs_correction_suppress_log_show, + btrfs_correction_suppress_log_store); + +static ssize_t btrfs_correction_disable_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->correction_disable); +} + +static ssize_t btrfs_correction_disable_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + u8 val; + int ret; + + if (len > 2) + return -EINVAL; + ret = kstrtou8(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val == 0 || val == 1) { + fs_info->correction_disable = !!val; + return len; + } + return -EINVAL; +} + +BTRFS_ATTR_RW(, correction_disable, + btrfs_correction_disable_show, + btrfs_correction_disable_store); + +static ssize_t btrfs_correction_record_cnt_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%d\n", + !RB_EMPTY_ROOT(&fs_info->correction_record)); +} + +static ssize_t btrfs_correction_record_cnt_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + struct rb_node *n; + struct correction_record *record; + u8 val; + int cnt = 0; + int ret; + + if (len > 2) + return -EINVAL; + ret = kstrtou8(skip_spaces(buf), 0, &val); + if (ret) + return ret; + + if (val == 1) { + spin_lock(&fs_info->correction_record_lock); + for (n = rb_first(&fs_info->correction_record); n; n = rb_next(n)) { + record = rb_entry(n, struct correction_record, node); + printk(KERN_INFO + "one correction record, logical = %llu\n", + record->logical); + cnt++; + } + spin_unlock(&fs_info->correction_record_lock); + printk(KERN_INFO + "Btrfs has %d unfinished correction record\n", + cnt); + return len; + } + return -EINVAL; +} + +BTRFS_ATTR_RW(, correction_record_cnt, + btrfs_correction_record_cnt_show, + btrfs_correction_record_cnt_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_syno_writeback_thread_max_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%d\n", fs_info->syno_writeback_thread_max); +} + +static ssize_t btrfs_syno_writeback_thread_max_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + u8 val; + int ret; + + ret = kstrtou8(skip_spaces(buf), 0, &val); + if (ret) + return ret; + fs_info->syno_writeback_thread_max = val; + return len; +} + +BTRFS_ATTR_RW(, syno_writeback_thread_max, + btrfs_syno_writeback_thread_max_show, + btrfs_syno_writeback_thread_max_store); + +static ssize_t btrfs_syno_writeback_thread_count_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&fs_info->syno_writeback_thread_count)); +} + +BTRFS_ATTR(, syno_writeback_thread_count, btrfs_syno_writeback_thread_count_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_block_group_cnt_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%llu\n", (u64)atomic64_read(&fs_info->block_group_cnt)); +} +BTRFS_ATTR(, block_group_cnt, btrfs_block_group_cnt_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_fsync_cnt_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%lld\n", atomic64_read(&fs_info->fsync_cnt)); +} +BTRFS_ATTR(, fsync_cnt, btrfs_fsync_cnt_show); + +static ssize_t btrfs_fsync_full_commit_cnt_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%lld\n", atomic64_read(&fs_info->fsync_full_commit_cnt)); +} +BTRFS_ATTR(, fsync_full_commit_cnt, btrfs_fsync_full_commit_cnt_show); + +static ssize_t btrfs_commit_time_debug_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + int ret; + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + ret = snprintf(buf, PAGE_SIZE, "%d\n", fs_info->commit_time_debug_ms); + return ret; +} + +static ssize_t btrfs_commit_time_debug_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + unsigned int val; + int ret; + + ret = kstrtouint(skip_spaces(buf), 0, &val); + if (ret) + return ret; + fs_info->commit_time_debug_ms = val; + return len; +} + +BTRFS_ATTR_RW(, commit_time_debug_ms, btrfs_commit_time_debug_show, btrfs_commit_time_debug_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static char* syno_usage_type_to_str(int type, char *ret, int max_size) +{ + int unknown = 0; + const char* str; + switch (type) { + case SYNO_USAGE_TYPE_RO_SNAPSHOT: + str = "Snapshot"; + break; + default: + unknown = 1; + str = "Type"; + break; + } + if (unknown) + snprintf(ret, max_size, "%s.%d", str, type); + else + snprintf(ret, max_size, "%s", str); + return ret; +} + +static ssize_t btrfs_syno_usage_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + int i; + int len = 0; + char type_str[32] = {0}; + + for (i = SYNO_USAGE_TYPE_RO_SNAPSHOT; i < SYNO_USAGE_TYPE_MAX; i++) { + if (i == SYNO_USAGE_TYPE_RO_SNAPSHOT || + fs_info->syno_usage_status.syno_usage_type_num_bytes[i]) + len += snprintf(buf + len, PAGE_SIZE - len, "%s:%llu\n", + syno_usage_type_to_str(i, type_str, sizeof(type_str)), + fs_info->syno_usage_status.syno_usage_type_num_bytes[i]); + } + return len; +} + +BTRFS_ATTR(, syno_usage, btrfs_syno_usage_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_locker_update_interval_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%lld\n", fs_info->locker_update_interval); +} + +static ssize_t btrfs_locker_update_interval_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + int ret; + u32 val; + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + + ret = kstrtou32(skip_spaces(buf), 0, &val); + if (ret) + return ret; + + if (val < 60) + return -EINVAL; + + fs_info->locker_update_interval = val; + btrfs_syno_locker_update_work_kick(fs_info); + + return len; +} + +BTRFS_ATTR_RW(, locker_update_interval, btrfs_locker_update_interval_show, btrfs_locker_update_interval_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_syno_async_submit_throttle_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->syno_async_submit_throttle); +} + +static ssize_t btrfs_syno_async_submit_throttle_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + u32 val; + int ret; + + ret = kstrtou32(skip_spaces(buf), 0, &val); + if (ret) + return ret; + fs_info->syno_async_submit_throttle = val; + return len; +} + +BTRFS_ATTR_RW(, syno_async_submit_throttle, btrfs_syno_async_submit_throttle_show, btrfs_syno_async_submit_throttle_store); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_syno_max_ordered_queue_size_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%llu\n", fs_info->syno_max_ordered_queue_size); +} + +static ssize_t btrfs_syno_max_ordered_queue_size_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + u64 val; + int ret; + + ret = kstrtou64(skip_spaces(buf), 0, &val); + if (ret) + return ret; + fs_info->syno_max_ordered_queue_size = val; + return len; +} + +BTRFS_ATTR_RW(, syno_max_ordered_queue_size, btrfs_syno_max_ordered_queue_size_show, btrfs_syno_max_ordered_queue_size_store); + +static ssize_t btrfs_syno_ordered_extent_nr_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + return snprintf(buf, PAGE_SIZE, "%llu\n", (u64)atomic64_read(&fs_info->syno_ordered_extent_nr)); +} +BTRFS_ATTR(, syno_ordered_extent_nr, btrfs_syno_ordered_extent_nr_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_incompat_supp_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%llu\n", BTRFS_FEATURE_INCOMPAT_SUPP); +} +BTRFS_ATTR(, incompat_supp, btrfs_incompat_supp_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_compat_ro_supp_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ +#ifdef MY_ABC_HERE + if (btrfs_syno_locker_feature_is_support()) { + return snprintf(buf, PAGE_SIZE, "%llu\n", BTRFS_FEATURE_COMPAT_RO_SUPP); + } else { + return snprintf(buf, PAGE_SIZE, "%llu\n", BTRFS_FEATURE_COMPAT_RO_SUPP & ~BTRFS_FEATURE_COMPAT_RO_LOCKER); + } +#else + return snprintf(buf, PAGE_SIZE, "%llu\n", BTRFS_FEATURE_COMPAT_RO_SUPP); +#endif /* MY_ABC_HERE */ +} +BTRFS_ATTR(, compat_ro_supp, btrfs_compat_ro_supp_show); +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +static const struct attribute *btrfs_info_attrs[] = { +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, incompat_supp), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, compat_ro_supp), +#endif /* MY_ABC_HERE */ + NULL, +}; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_syno_meta_statistics_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + int len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "Extent Buffer Disk Read:%llu\n", (u64)atomic64_read(&fs_info->syno_meta_statistics.eb_disk_read)); + len += snprintf(buf + len, PAGE_SIZE - len, "Search Key:%llu\n", (u64)atomic64_read(&fs_info->syno_meta_statistics.search_key)); + len += snprintf(buf + len, PAGE_SIZE - len, "Search Forward:%llu\n", (u64)atomic64_read(&fs_info->syno_meta_statistics.search_forward)); + len += snprintf(buf + len, PAGE_SIZE - len, "Next Leaf:%llu\n", (u64)atomic64_read(&fs_info->syno_meta_statistics.next_leaf)); + + return len; +} +BTRFS_ATTR(, syno_meta_statistics, btrfs_syno_meta_statistics_show); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t btrfs_syno_orphan_cleanup_enable_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + int ret; + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + ret = snprintf(buf, PAGE_SIZE, "%d\n", fs_info->syno_orphan_cleanup.enable ? 1 : 0); + return ret; +} +static ssize_t btrfs_syno_orphan_cleanup_enable_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + unsigned int val; + int ret; + + ret = kstrtouint(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val != 0 && val != 1) + return -EINVAL; + fs_info->syno_orphan_cleanup.enable = !!val; + return len; +} +BTRFS_ATTR_RW(, syno_orphan_cleanup_enable, btrfs_syno_orphan_cleanup_enable_show, btrfs_syno_orphan_cleanup_enable_store); + +static ssize_t btrfs_syno_orphan_cleanup_delayed_show(struct kobject *kobj, + struct kobj_attribute *a, char *buf) +{ + int ret; + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + ret = snprintf(buf, PAGE_SIZE, "%d\n", fs_info->syno_orphan_cleanup.orphan_inode_delayed ? 1 : 0); + return ret; +} +static ssize_t btrfs_syno_orphan_cleanup_delayed_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + unsigned int val; + int ret; + + ret = kstrtouint(skip_spaces(buf), 0, &val); + if (ret) + return ret; + if (val != 0 && val != 1) + return -EINVAL; + fs_info->syno_orphan_cleanup.orphan_inode_delayed = !!val; + return len; +} +BTRFS_ATTR_RW(, syno_orphan_cleanup_delayed, btrfs_syno_orphan_cleanup_delayed_show, btrfs_syno_orphan_cleanup_delayed_store); +#endif /* MY_ABC_HERE */ + static const struct attribute *btrfs_attrs[] = { BTRFS_ATTR_PTR(, label), BTRFS_ATTR_PTR(, nodesize), @@ -863,6 +1620,59 @@ static const struct attribute *btrfs_attrs[] = { BTRFS_ATTR_PTR(, metadata_uuid), BTRFS_ATTR_PTR(, checksum), BTRFS_ATTR_PTR(, exclusive_operation), +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, snapshot_cleaner), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, metadata_cache_enable), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, block_group_cnt), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, fsync_cnt), + BTRFS_ATTR_PTR(, fsync_full_commit_cnt), + BTRFS_ATTR_PTR(, commit_time_debug_ms), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, syno_usage), +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + BTRFS_ATTR_PTR(, mount_path), +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, correction_suppress_log), + BTRFS_ATTR_PTR(, correction_disable), + BTRFS_ATTR_PTR(, correction_record_cnt), +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, syno_writeback_thread_max), + BTRFS_ATTR_PTR(, syno_writeback_thread_count), +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, syno_async_submit_throttle), +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, syno_max_ordered_queue_size), + BTRFS_ATTR_PTR(, syno_ordered_extent_nr), +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, locker_update_interval), +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, syno_meta_statistics), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BTRFS_ATTR_PTR(, syno_orphan_cleanup_enable), + BTRFS_ATTR_PTR(, syno_orphan_cleanup_delayed), +#endif /* MY_ABC_HERE */ NULL, }; @@ -902,8 +1712,103 @@ static const u64 supported_feature_masks[FEAT_MAX] = { [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP, [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP, +#ifdef MY_ABC_HERE + [FEAT_SYNO_CAPABILITY] = BTRFS_FEATURE_SYNO_CAPABILITY_SUPP, +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static ssize_t btrfs_free_space_tree_create_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + return snprintf(buf, PAGE_SIZE, "%d\n", + test_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, + &fs_info->flags)); +} +BTRFS_ATTR(, free_space_tree_creating, btrfs_free_space_tree_create_show); + +static ssize_t btrfs_free_space_tree_created_block_group_cnt_show( + struct kobject *kobj, struct kobj_attribute *a, char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + return snprintf(buf, PAGE_SIZE, "%llu\n", + (u64)atomic64_read(&fs_info->free_space_tree_processed_block_group_cnt)); +} +BTRFS_ATTR(, processed_block_group_cnt, + btrfs_free_space_tree_created_block_group_cnt_show); + +static ssize_t btrfs_free_space_tree_abort_show(struct kobject *kobj, + struct kobj_attribute *a, + char *buf) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + return snprintf(buf, PAGE_SIZE, "%d\n", + test_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, + &fs_info->flags)); +} + +static ssize_t btrfs_free_space_tree_abort_store(struct kobject *kobj, + struct kobj_attribute *a, + const char *buf, size_t len) +{ + struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); + int val; + int ret; + + if (len > 2) { + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(skip_spaces(buf), 0, &val); + if (ret) + goto out; + + if (val == 1) + set_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags); + else + clear_bit(BTRFS_FS_ABORT_FREE_SPACE_TREE, &fs_info->flags); + + ret = 0; +out: + return ret; +} + +BTRFS_ATTR_RW(, abort_free_space_tree, btrfs_free_space_tree_abort_show, + btrfs_free_space_tree_abort_store); + +static const struct attribute *free_space_tree_attrs[] = { + BTRFS_ATTR_PTR(, free_space_tree_creating), + BTRFS_ATTR_PTR(, processed_block_group_cnt), + BTRFS_ATTR_PTR(, abort_free_space_tree), + NULL, +}; + +int add_free_space_tree_attrs(struct btrfs_fs_info *fs_info) +{ + int error = 0; + + fs_info->free_space_tree_kobj = kobject_create_and_add( + "free_space_tree", &fs_info->fs_devices->fsid_kobj); + + if (!fs_info->free_space_tree_kobj) { + error = -ENOMEM; + goto failure; + } + + error = sysfs_create_files(fs_info->free_space_tree_kobj, + free_space_tree_attrs); + if (error) + goto failure; + + return 0; +failure: + return error; +} +#endif /* MY_ABC_HERE */ + static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) { int set; @@ -1019,6 +1924,16 @@ void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info) kobject_put(fs_info->debug_kobj); } #endif + +#ifdef MY_ABC_HERE + if (fs_info->free_space_tree_kobj) { + sysfs_remove_files(fs_info->free_space_tree_kobj, + free_space_tree_attrs); + kobject_del(fs_info->free_space_tree_kobj); + kobject_put(fs_info->free_space_tree_kobj); + } +#endif /* MY_ABC_HERE */ + addrm_unknown_feature_attrs(fs_info, false); sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); sysfs_remove_files(fsid_kobj, btrfs_attrs); @@ -1029,6 +1944,9 @@ static const char * const btrfs_feature_set_names[FEAT_MAX] = { [FEAT_COMPAT] = "compat", [FEAT_COMPAT_RO] = "compat_ro", [FEAT_INCOMPAT] = "incompat", +#ifdef MY_ABC_HERE + [FEAT_SYNO_CAPABILITY] = "syno_capability", +#endif /* MY_ABC_HERE */ }; const char *btrfs_feature_set_name(enum btrfs_feature_set set) @@ -1512,6 +2430,15 @@ int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info) if (error) goto failure; +#ifdef MY_ABC_HERE + if (btrfs_test_opt(fs_info, FREE_SPACE_TREE) && + !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { + error = add_free_space_tree_attrs(fs_info); + if (error) + goto failure; + } +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_BTRFS_DEBUG fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj); if (!fs_info->debug_kobj) { @@ -1748,6 +2675,121 @@ void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info, ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); } +#ifdef MY_ABC_HERE +/* /sys/kernel/debug/btrfs */ +static struct dentry *btrfs_debugfs_root_dentry; + +static int debugfs_percpu_counter_get(void *data, u64 *val) +{ + *val = percpu_counter_sum((struct percpu_counter *)data); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_percpu_counter_ro, debugfs_percpu_counter_get, NULL, "%llu\n"); + +static struct dentry *debugfs_create_percpu_counter(const char *name, + struct dentry *parent, + struct percpu_counter *counter) +{ + return debugfs_create_file(name, S_IRUSR, parent, counter, &fops_percpu_counter_ro); +} + +void btrfs_debugfs_remove_mounted(struct btrfs_fs_info *fs_info) +{ + if (fs_info->btrfs_pervolume_debugfs_root_dentry) + debugfs_remove_recursive(fs_info->btrfs_pervolume_debugfs_root_dentry); + fs_info->btrfs_pervolume_debugfs_root_dentry = NULL; +} + +int btrfs_debugfs_add_mounted(struct btrfs_fs_info *fs_info) +{ + struct dentry *dentry; + char buf[BTRFS_UUID_UNPARSED_SIZE]; + int ret; + + if (IS_ERR_OR_NULL(btrfs_debugfs_root_dentry)) { + printk(KERN_ERR "BTRFS: could not find btrfs_debugfs_root_dentry\n"); + return -ENOENT; + } + + snprintf(buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_info->fs_devices->fsid); + dentry = debugfs_create_dir(buf, btrfs_debugfs_root_dentry); + if (!dentry) + return -ENOMEM; + fs_info->btrfs_pervolume_debugfs_root_dentry = dentry; + + dentry = debugfs_create_percpu_counter("volume_eb_hit", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->eb_hit); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create volume_eb_hit file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("volume_eb_miss", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->eb_miss); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create volume_eb_miss file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("volume_meta_write_pages", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->meta_write_pages); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create volume_meta_write_pages file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("volume_data_write_pages", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->data_write_pages); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create volume_data_write_pages file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("delayed_meta_ref", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->delayed_meta_ref); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create delayed_meta_ref file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("delayed_data_ref", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->delayed_data_ref); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create delayed_data_ref file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("write_flush", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->write_flush); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create write_flush file\n"); + ret = -ENOMEM; + goto out; + } + + dentry = debugfs_create_percpu_counter("write_fua", + fs_info->btrfs_pervolume_debugfs_root_dentry, &fs_info->write_fua); + if (!dentry) { + printk(KERN_INFO "BTRFS: could not create write_fua file\n"); + ret = -ENOMEM; + goto out; + } + + ret = 0; + +out: + if (ret) + btrfs_debugfs_remove_mounted(fs_info); + return ret; +} +#endif /* MY_ABC_HERE */ + int __init btrfs_init_sysfs(void) { int ret; @@ -1756,15 +2798,41 @@ int __init btrfs_init_sysfs(void) if (!btrfs_kset) return -ENOMEM; +#ifdef MY_ABC_HERE + btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL); + if (!btrfs_debugfs_root_dentry) { + ret = -ENOMEM; + goto out2; + } +#endif /* MY_ABC_HERE */ + init_feature_attrs(); ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); if (ret) goto out2; + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + ret = sysfs_create_files(&btrfs_kset->kobj, btrfs_info_attrs); + if (ret) + goto out_remove_group; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + ret = sysfs_merge_group(&btrfs_kset->kobj, &btrfs_static_feature_attr_group); if (ret) goto out_remove_group; +#ifdef MY_ABC_HERE + ret = sysfs_merge_group(&btrfs_kset->kobj, &btrfs_locker_feature_attr_group); + if (ret) + goto out_remove_group; +#endif /* CONFIG_SYNO_BTRFS_LOCK */ +#ifdef MY_ABC_HERE + ret = sysfs_merge_group(&btrfs_kset->kobj, &btrfs_qgroup_soft_limit_feature_attr_group); + if (ret) + goto out_remove_group; +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_BTRFS_DEBUG ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); if (ret) @@ -1776,6 +2844,9 @@ int __init btrfs_init_sysfs(void) out_remove_group: sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); out2: +#ifdef MY_ABC_HERE + debugfs_remove_recursive(btrfs_debugfs_root_dentry); +#endif /* MY_ABC_HERE */ kset_unregister(btrfs_kset); return ret; @@ -1783,12 +2854,18 @@ int __init btrfs_init_sysfs(void) void __cold btrfs_exit_sysfs(void) { +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + sysfs_remove_files(&btrfs_kset->kobj, btrfs_info_attrs); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ sysfs_unmerge_group(&btrfs_kset->kobj, &btrfs_static_feature_attr_group); sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); #ifdef CONFIG_BTRFS_DEBUG sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); #endif +#ifdef MY_ABC_HERE + debugfs_remove_recursive(btrfs_debugfs_root_dentry); +#endif /* MY_ABC_HERE */ kset_unregister(btrfs_kset); } diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index bacef43f7267..dd314efa3504 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_SYSFS_H @@ -9,6 +12,9 @@ enum btrfs_feature_set { FEAT_COMPAT, FEAT_COMPAT_RO, FEAT_INCOMPAT, +#ifdef MY_ABC_HERE + FEAT_SYNO_CAPABILITY, +#endif /* MY_ABC_HERE */ FEAT_MAX }; @@ -39,5 +45,9 @@ void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info); int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info); void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup); +#ifdef MY_ABC_HERE +int btrfs_debugfs_add_mounted(struct btrfs_fs_info *fs_info); +void btrfs_debugfs_remove_mounted(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ #endif diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c index 999c14e5d0bd..9d08e03f2b6a 100644 --- a/fs/btrfs/tests/btrfs-tests.c +++ b/fs/btrfs/tests/btrfs-tests.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013 Fusion IO. All rights reserved. @@ -224,8 +227,24 @@ btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info, INIT_LIST_HEAD(&cache->list); INIT_LIST_HEAD(&cache->cluster_list); INIT_LIST_HEAD(&cache->bg_list); - btrfs_init_free_space_ctl(cache); + btrfs_init_free_space_ctl(cache, cache->free_space_ctl); mutex_init(&cache->free_space_lock); +#ifdef MY_ABC_HERE + spin_lock_init(&cache->lock); + cache->syno_allocator.space_info = NULL; + RB_CLEAR_NODE(&cache->syno_allocator.bytes_index); + RB_CLEAR_NODE(&cache->syno_allocator.max_length_index); + RB_CLEAR_NODE(&cache->syno_allocator.max_length_with_extent_index); + RB_CLEAR_NODE(&cache->syno_allocator.preload_index); + cache->syno_allocator.last_bytes = 0; + cache->syno_allocator.last_max_length = 0; + cache->syno_allocator.last_max_length_with_extent = 0; + cache->syno_allocator.preload_free_space = 0; + cache->syno_allocator.ro = false; + cache->syno_allocator.cache_error = false; + cache->syno_allocator.removed = false; + atomic_set(&cache->syno_allocator.refs, 0); +#endif /* MY_ABC_HERE */ return cache; } @@ -235,6 +254,10 @@ void btrfs_free_dummy_block_group(struct btrfs_block_group *cache) if (!cache) return; __btrfs_remove_free_space_cache(cache->free_space_ctl); +#ifdef MY_ABC_HERE + btrfs_syno_allocator_release_cache_block_group(cache); + btrfs_syno_allocator_remove_block_group(cache); +#endif /* MY_ABC_HERE */ kfree(cache->free_space_ctl); kfree(cache); } @@ -278,9 +301,12 @@ int btrfs_run_sanity_tests(void) ret = btrfs_test_inodes(sectorsize, nodesize); if (ret) goto out; +#ifdef MY_ABC_HERE +#else ret = btrfs_test_qgroups(sectorsize, nodesize); if (ret) goto out; +#endif /* MY_ABC_HERE */ ret = btrfs_test_free_space_tree(sectorsize, nodesize); if (ret) goto out; diff --git a/fs/btrfs/tests/btrfs-tests.h b/fs/btrfs/tests/btrfs-tests.h index 7a2d7ffbe30e..82e9b2a03560 100644 --- a/fs/btrfs/tests/btrfs-tests.h +++ b/fs/btrfs/tests/btrfs-tests.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2013 Fusion IO. All rights reserved. @@ -34,7 +37,10 @@ int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize); int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize); int btrfs_test_extent_io(u32 sectorsize, u32 nodesize); int btrfs_test_inodes(u32 sectorsize, u32 nodesize); +#ifdef MY_ABC_HERE +#else int btrfs_test_qgroups(u32 sectorsize, u32 nodesize); +#endif /* MY_ABC_HERE */ int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize); int btrfs_test_extent_map(void); struct inode *btrfs_new_test_inode(void); diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c index 04022069761d..db74cb373f5e 100644 --- a/fs/btrfs/tests/inode-tests.c +++ b/fs/btrfs/tests/inode-tests.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013 Fusion IO. All rights reserved. @@ -45,6 +48,9 @@ static void insert_extent(struct btrfs_root *root, u64 start, u64 len, btrfs_set_file_extent_compression(leaf, fi, compression); btrfs_set_file_extent_encryption(leaf, fi, 0); btrfs_set_file_extent_other_encoding(leaf, fi, 0); +#ifdef MY_ABC_HERE + btrfs_set_file_extent_syno_flag(leaf, fi, 0); +#endif /* MY_ABC_HERE */ } static void insert_inode_item_key(struct btrfs_root *root) diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c index ce1ca8e73c2d..312f0093c084 100644 --- a/fs/btrfs/tests/qgroup-tests.c +++ b/fs/btrfs/tests/qgroup-tests.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013 Facebook. All rights reserved. @@ -11,6 +14,8 @@ #include "../qgroup.h" #include "../backref.h" +#ifdef MY_ABC_HERE +#else static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid) { @@ -534,3 +539,4 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize) btrfs_free_dummy_fs_info(fs_info); return ret; } +#endif /* MY_ABC_HERE */ diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 8daa9e4eb1d2..453f646c552e 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -128,6 +131,11 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction) btrfs_err(transaction->fs_info, "pending csums is %llu", transaction->delayed_refs.pending_csums); +#ifdef MY_ABC_HERE + WARN_ON_ONCE(atomic_read(&transaction->delayed_refs.num_syno_usage_entries)); + WARN_ON_ONCE(transaction->delayed_refs.num_syno_usage_heads_ready); + WARN_ON_ONCE(transaction->delayed_refs.total_syno_usage_accounting); +#endif /* MY_ABC_HERE */ /* * If any block groups are found in ->deleted_bgs then it's * because the transaction was aborted and a commit did not @@ -155,7 +163,6 @@ static noinline void switch_commit_roots(struct btrfs_trans_handle *trans) struct btrfs_transaction *cur_trans = trans->transaction; struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root, *tmp; - struct btrfs_caching_control *caching_ctl, *next; down_write(&fs_info->commit_root_sem); list_for_each_entry_safe(root, tmp, &cur_trans->switch_commits, @@ -182,44 +189,6 @@ static noinline void switch_commit_roots(struct btrfs_trans_handle *trans) } spin_unlock(&cur_trans->dropped_roots_lock); - /* - * We have to update the last_byte_to_unpin under the commit_root_sem, - * at the same time we swap out the commit roots. - * - * This is because we must have a real view of the last spot the caching - * kthreads were while caching. Consider the following views of the - * extent tree for a block group - * - * commit root - * +----+----+----+----+----+----+----+ - * |\\\\| |\\\\|\\\\| |\\\\|\\\\| - * +----+----+----+----+----+----+----+ - * 0 1 2 3 4 5 6 7 - * - * new commit root - * +----+----+----+----+----+----+----+ - * | | | |\\\\| | |\\\\| - * +----+----+----+----+----+----+----+ - * 0 1 2 3 4 5 6 7 - * - * If the cache_ctl->progress was at 3, then we are only allowed to - * unpin [0,1) and [2,3], because the caching thread has already - * processed those extents. We are not allowed to unpin [5,6), because - * the caching thread will re-start it's search from 3, and thus find - * the hole from [4,6) to add to the free space cache. - */ - list_for_each_entry_safe(caching_ctl, next, - &fs_info->caching_block_groups, list) { - struct btrfs_block_group *cache = caching_ctl->block_group; - - if (btrfs_block_group_done(cache)) { - cache->last_byte_to_unpin = (u64)-1; - list_del_init(&caching_ctl->list); - btrfs_put_caching_control(caching_ctl); - } else { - cache->last_byte_to_unpin = caching_ctl->progress; - } - } up_write(&fs_info->commit_root_sem); } @@ -350,8 +319,18 @@ static noinline int join_transaction(struct btrfs_fs_info *fs_info, memset(&cur_trans->delayed_refs, 0, sizeof(cur_trans->delayed_refs)); cur_trans->delayed_refs.href_root = RB_ROOT_CACHED; +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&cur_trans->quota_account_list); + spin_lock_init(&cur_trans->quota_account_lock); + init_rwsem(&cur_trans->delayed_refs_rw_sem); +#else cur_trans->delayed_refs.dirty_extent_root = RB_ROOT; +#endif /* MY_ABC_HERE */ atomic_set(&cur_trans->delayed_refs.num_entries, 0); +#ifdef MY_ABC_HERE + cur_trans->delayed_refs.num_syno_usage_heads_ready = 0; + atomic_set(&cur_trans->delayed_refs.num_syno_usage_entries, 0); +#endif /* MY_ABC_HERE */ /* * although the tree mod log is per file system and not per transaction, @@ -692,6 +671,15 @@ start_transaction(struct btrfs_root *root, unsigned int num_items, h->type = type; h->can_flush_pending_bgs = true; INIT_LIST_HEAD(&h->new_bgs); +#ifdef MY_ABC_HERE + h->syno_usage = false; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + h->skip_throttle = false; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + h->cleaner = false; +#endif /* MY_ABC_HERE */ smp_mb(); if (cur_trans->state >= TRANS_STATE_COMMIT_START && @@ -939,12 +927,77 @@ static void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans) trans->bytes_reserved = 0; } +#ifdef MY_ABC_HERE +struct async_delayed_refs { + struct btrfs_root *root; + struct btrfs_work work; +}; + +static void delayed_ref_async_start(struct btrfs_work *work) +{ + struct async_delayed_refs *async; + struct btrfs_trans_handle *trans; + struct btrfs_fs_info *fs_info; + + async = container_of(work, struct async_delayed_refs, work); + fs_info = async->root->fs_info; + trans = btrfs_join_transaction(async->root); + if (IS_ERR(trans)) + goto out; + /* + * trans->sync means that when we call end_transaction, we won't + * wait on delayed refs + */ + trans->skip_throttle = true; + btrfs_run_delayed_refs(trans, 0); + btrfs_end_transaction(trans); +out: + atomic_dec(&fs_info->syno_async_delayed_ref_count); + kfree(async); + return; +} + +static int btrfs_async_run_delayed_refs(struct btrfs_fs_info *fs_info) +{ + struct async_delayed_refs *async; + int ret; + + if (atomic_read(&fs_info->syno_async_delayed_ref_count) >= + fs_info->thread_pool_size) + goto success; + + if (!atomic_add_unless(&fs_info->syno_async_delayed_ref_count, + 1, fs_info->thread_pool_size)) + goto success; + + async = kmalloc(sizeof(*async), GFP_NOFS); + if (!async) { + atomic_dec(&fs_info->syno_async_delayed_ref_count); + ret = -ENOMEM; + goto out; + } + async->root = fs_info->tree_root; + + btrfs_init_work(&async->work, delayed_ref_async_start, NULL, NULL); + + btrfs_queue_work(fs_info->extent_workers, &async->work); +success: + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, int throttle) { struct btrfs_fs_info *info = trans->fs_info; struct btrfs_transaction *cur_trans = trans->transaction; int err = 0; +#ifdef MY_ABC_HERE + int must_run_delayed_refs = 0; + unsigned long items = trans->total_delayed_ref_updates * 2; +#endif /* MY_ABC_HERE */ if (refcount_read(&trans->use_count) > 1) { refcount_dec(&trans->use_count); @@ -955,6 +1008,46 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, btrfs_trans_release_metadata(trans); trans->block_rsv = NULL; +#ifdef MY_ABC_HERE + if (!trans->skip_throttle) { + must_run_delayed_refs = btrfs_should_throttle_delayed_refs(trans); + if (must_run_delayed_refs == 1 && + (trans->type & (__TRANS_JOIN_NOLOCK | __TRANS_ATTACH))) + must_run_delayed_refs = 2; + } + + if (must_run_delayed_refs == 2) + btrfs_async_run_delayed_refs(info); + else if (must_run_delayed_refs == 1) { + struct btrfs_delayed_ref_throttle_ticket ticket; + bool need_clean_list = true; + ticket.count = items; + INIT_LIST_HEAD(&ticket.list); + spin_lock(&info->syno_delayed_ref_throttle_lock); + list_move_tail(&ticket.list, &info->syno_delayed_ref_throttle_tickets); + spin_unlock(&info->syno_delayed_ref_throttle_lock); + btrfs_async_run_delayed_refs(info); + trans->syno_delayed_ref_throttle_ticket = &ticket; + while (items-- && btrfs_should_throttle_delayed_refs(trans) == 1) { + btrfs_run_delayed_refs(trans, 1); + spin_lock(&info->syno_delayed_ref_throttle_lock); + if (ticket.count == 0) { + list_del_init(&ticket.list); + need_clean_list = false; + spin_unlock(&info->syno_delayed_ref_throttle_lock); + break; + } + spin_unlock(&info->syno_delayed_ref_throttle_lock); + } + trans->syno_delayed_ref_throttle_ticket = NULL; + if (need_clean_list) { + spin_lock(&info->syno_delayed_ref_throttle_lock); + list_del_init(&ticket.list); + spin_unlock(&info->syno_delayed_ref_throttle_lock); + } + } +#endif /* MY_ABC_HERE */ + btrfs_create_pending_block_groups(trans); btrfs_trans_release_chunk_metadata(trans); @@ -999,13 +1092,35 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans) return __btrfs_end_transaction(trans, 1); } +#ifdef MY_ABC_HERE +int btrfs_throttle_delayed_refs(struct btrfs_root *root, unsigned long total_delayed_ref_updates) +{ + struct btrfs_trans_handle *trans; + + if (!total_delayed_ref_updates) + return 0; + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + trans->total_delayed_ref_updates = total_delayed_ref_updates; + // btrfs_end_transaction will throttle delayed refs + return btrfs_end_transaction(trans); +} +#endif /* MY_ABC_HERE */ + /* * when btree blocks are allocated, they have some corresponding bits set for * them in one of two extent_io trees. This is used to make sure all of * those extents are sent to disk but does not wait on them */ int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info, - struct extent_io_tree *dirty_pages, int mark) + struct extent_io_tree *dirty_pages, int mark +#ifdef MY_ABC_HERE + , u64 *total_count, u64 *total_size +#endif /* MY_ABC_HERE */ + ) { int err = 0; int werr = 0; @@ -1048,6 +1163,12 @@ int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info, free_extent_state(cached_state); cached_state = NULL; cond_resched(); +#ifdef MY_ABC_HERE + if (total_count && total_size) { + *total_count += 1; + *total_size += end - start + 1; + } +#endif /* MY_ABC_HERE */ start = end + 1; } atomic_dec(&BTRFS_I(fs_info->btree_inode)->sync_writers); @@ -1143,7 +1264,11 @@ int btrfs_wait_tree_log_extents(struct btrfs_root *log_root, int mark) * * @trans: transaction whose dirty pages we'd like to write */ -static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans) +static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans +#ifdef MY_ABC_HERE + , u64 *total_count, u64 *total_size +#endif /* MY_ABC_HERE */ + ) { int ret; int ret2; @@ -1152,7 +1277,11 @@ static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans) struct blk_plug plug; blk_start_plug(&plug); - ret = btrfs_write_marked_extents(fs_info, dirty_pages, EXTENT_DIRTY); + ret = btrfs_write_marked_extents(fs_info, dirty_pages, EXTENT_DIRTY +#ifdef MY_ABC_HERE + , total_count, total_size +#endif /* MY_ABC_HERE */ + ); blk_finish_plug(&plug); ret2 = btrfs_wait_extents(fs_info, dirty_pages); @@ -1245,6 +1374,21 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans) if (ret) return ret; +#ifdef MY_ABC_HERE + ret = btrfs_run_usrquota(trans); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ret = btrfs_syno_usage_global_type_update(trans); + if (ret) + return ret; + ret = btrfs_syno_usage_status_update(trans); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ + ret = btrfs_setup_space_cache(trans); if (ret) return ret; @@ -1310,7 +1454,19 @@ void btrfs_add_dead_root(struct btrfs_root *root) } spin_unlock(&fs_info->trans_lock); } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +void btrfs_add_dead_root_head(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + spin_lock(&fs_info->trans_lock); + if (list_empty(&root->root_list)) { + btrfs_grab_root(root); + list_add(&root->root_list, &fs_info->dead_roots); + } + spin_unlock(&fs_info->trans_lock); +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ /* * update all the cowonly tree roots on disk */ @@ -1357,6 +1513,11 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans) ret2 = btrfs_update_root(trans, fs_info->tree_root, &root->root_key, &root->root_item); +#ifdef MY_ABC_HERE + if (!ret2 && is_fstree(root->root_key.objectid) && + test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) + ret2 = btrfs_syno_usage_root_status_update(trans, root->root_key.objectid, &root->syno_usage_root_status); +#endif /* MY_ABC_HERE */ if (ret2) return ret2; spin_lock(&fs_info->fs_roots_radix_lock); @@ -1417,7 +1578,11 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root *src, struct btrfs_root *parent, struct btrfs_qgroup_inherit *inherit, - u64 dst_objectid) + u64 dst_objectid +#ifdef MY_ABC_HERE + ,struct btrfs_pending_snapshot *pending +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = src->fs_info; int ret; @@ -1427,7 +1592,12 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, * enabled. If this check races with the ioctl, rescan will * kick in anyway. */ +#ifdef MY_ABC_HERE + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) +#else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) +#endif /* MY_ABC_HERE */ return 0; /* @@ -1447,9 +1617,13 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, ret = commit_fs_roots(trans); if (ret) goto out; + +#ifdef MY_ABC_HERE +#else ret = btrfs_qgroup_account_extents(trans); if (ret < 0) goto out; +#endif /* MY_ABC_HERE */ /* Now qgroup are all updated, we can inherit it to new qgroups */ ret = btrfs_qgroup_inherit(trans, src->root_key.objectid, dst_objectid, @@ -1457,6 +1631,13 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, if (ret < 0) goto out; +#ifdef MY_ABC_HERE + ret = btrfs_usrquota_mksnap(trans, src->root_key.objectid, + dst_objectid, pending->readonly, pending->copy_limit_from); + if (ret < 0) + goto out; +#endif /* MY_ABC_HERE */ + /* * Now we do a simplified commit transaction, which will: * 1) commit all subvolume and extent tree @@ -1473,7 +1654,11 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, if (ret) goto out; switch_commit_roots(trans); - ret = btrfs_write_and_wait_transaction(trans); + ret = btrfs_write_and_wait_transaction(trans +#ifdef MY_ABC_HERE + , NULL, NULL +#endif /* MY_ABC_HERE */ + ); if (ret) btrfs_handle_fs_error(fs_info, ret, "Error while writing out transaction for qgroup"); @@ -1502,7 +1687,13 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, * the creation of the pending snapshots, just return 0. */ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, - struct btrfs_pending_snapshot *pending) + struct btrfs_pending_snapshot *pending +#ifdef MY_ABC_HERE + , unsigned long *snapshot_processed_inodes + , unsigned long *snapshot_processed_items + , unsigned long *snapshot_processed_refs +#endif /* MY_ABC_HERE */ + ) { struct btrfs_fs_info *fs_info = trans->fs_info; @@ -1524,6 +1715,18 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, u64 index = 0; u64 objectid; u64 root_flags; +#ifdef MY_ABC_HERE + struct btrfs_syno_usage_root_status syno_usage_root_status; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool invalid_quota; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned long processed_inodes = 0; + unsigned long processed_items = 0; + unsigned long processed_refs = 0; + unsigned long processed_total_refs = 0; +#endif /* MY_ABC_HERE */ ASSERT(pending->path); path = pending->path; @@ -1596,12 +1799,32 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, * otherwise we corrupt the FS during * snapshot */ +#ifdef MY_ABC_HERE + ret = btrfs_run_delayed_items_and_get_processed(trans, + &processed_inodes, &processed_items); +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_items(trans); +#endif /* MY_ABC_HERE */ if (ret) { /* Transaction aborted */ btrfs_abort_transaction(trans, ret); goto fail; } +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + processed_refs = 0; + ret = btrfs_run_delayed_refs_and_get_processed(trans, + (unsigned long) -1, &processed_refs); + processed_total_refs += processed_refs; +#else /* MY_ABC_HERE */ + ret = btrfs_run_delayed_refs(trans, (unsigned long)-1); +#endif /* MY_ABC_HERE */ + if (ret) { + btrfs_abort_transaction(trans, ret); + goto fail; + } +#endif /* MY_ABC_HERE */ + record_root_in_trans(trans, root, 0); btrfs_set_root_last_snapshot(&root->root_item, trans->transid); memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); @@ -1619,6 +1842,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, generate_random_guid(new_root_item->uuid); memcpy(new_root_item->parent_uuid, root->root_item.uuid, BTRFS_UUID_SIZE); +#ifdef MY_ABC_HERE + if (root_flags & BTRFS_ROOT_SUBVOL_RDONLY) + memcpy(new_root_item->received_uuid, new_root_item->uuid, BTRFS_UUID_SIZE); +#endif /* MY_ABC_HERE */ if (!(root_flags & BTRFS_ROOT_SUBVOL_RDONLY)) { memset(new_root_item->received_uuid, 0, sizeof(new_root_item->received_uuid)); @@ -1678,14 +1905,66 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, goto fail; } +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_SPACE_USAGE_ENABLED, &fs_info->flags) && + test_bit(BTRFS_ROOT_SYNO_SPACE_USAGE_ENABLED, &root->state)) { + btrfs_syno_usage_root_status_init(&syno_usage_root_status, &root->syno_usage_root_status, pending->readonly, false); + ret = btrfs_syno_usage_root_status_update(trans, objectid, &syno_usage_root_status); + if (ret) + goto fail; + if (!(syno_usage_root_status.flags & BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY)) { + spin_lock(&fs_info->syno_usage_lock); + fs_info->syno_usage_status.total_syno_subvol_usage_items += syno_usage_root_status.total_syno_subvol_usage_items; + spin_unlock(&fs_info->syno_usage_lock); + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + invalid_quota = root->invalid_quota; + if (test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags) && !invalid_quota) { + struct syno_quota_rescan_item_updater updater; + + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_DONE; + updater.version = BTRFS_QGROUP_V2_STATUS_VERSION; + updater.rescan_inode = (u64)-1; + updater.end_inode = (u64)-1; + updater.tree_size = 0; + updater.next_root = 0; + ret = btrfs_add_update_syno_quota_rescan_item(trans, fs_info->quota_root, + objectid, &updater); + if (ret) + btrfs_warn(fs_info, + "Failed to create syno quota rescan item for root %llu, ret = %d", + objectid, ret); + ret = 0; // No need to abort transaction, we can fix it by doing a quota rescan. + } +#endif /* MY_ABC_HERE */ + key.offset = (u64)-1; - pending->snap = btrfs_get_new_fs_root(fs_info, objectid, pending->anon_dev); + pending->snap = btrfs_get_new_fs_root(fs_info, objectid, pending->anon_dev +#if defined(MY_ABC_HERE) + , pending->new_fs_root_args +#endif /* MY_ABC_HERE */ + ); if (IS_ERR(pending->snap)) { ret = PTR_ERR(pending->snap); pending->snap = NULL; btrfs_abort_transaction(trans, ret); goto fail; } +#ifdef MY_ABC_HERE + pending->snap->invalid_quota = invalid_quota; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ret = btrfs_syno_locker_snapshot_clone(trans, pending->snap, root); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto fail; + } +#endif /* MY_ABC_HERE */ ret = btrfs_reloc_post_snapshot(trans, pending); if (ret) { @@ -1693,7 +1972,14 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, goto fail; } +#ifdef MY_ABC_HERE + processed_refs = 0; + ret = btrfs_run_delayed_refs_and_get_processed(trans, + (unsigned long) -1, &processed_refs); + processed_total_refs += processed_refs; +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1); +#endif /* MY_ABC_HERE */ if (ret) { btrfs_abort_transaction(trans, ret); goto fail; @@ -1706,7 +1992,11 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, * Or snapshot will be greatly slowed down by a subtree qgroup rescan */ ret = qgroup_account_snapshot(trans, root, parent_root, - pending->inherit, objectid); + pending->inherit, objectid +#ifdef MY_ABC_HERE + ,pending +#endif /* MY_ABC_HERE */ + ); if (ret < 0) goto fail; @@ -1746,12 +2036,28 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, } } +#ifdef MY_ABC_HERE + processed_refs = 0; + ret = btrfs_run_delayed_refs_and_get_processed(trans, + (unsigned long) -1, &processed_refs); + processed_total_refs += processed_refs; +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1); +#endif /* MY_ABC_HERE */ if (ret) { btrfs_abort_transaction(trans, ret); goto fail; } +#ifdef MY_ABC_HERE + if (!ret && snapshot_processed_inodes && + snapshot_processed_items && snapshot_processed_refs) { + *snapshot_processed_inodes += processed_inodes; + *snapshot_processed_items += processed_items; + *snapshot_processed_refs += processed_total_refs; + } +#endif /* MY_ABC_HERE */ + fail: pending->error = ret; dir_item_existed: @@ -1771,7 +2077,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, /* * create all the snapshots we've scheduled for creation */ -static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans) +static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans +#ifdef MY_ABC_HERE + , unsigned long *snapshot_processed_inodes + , unsigned long *snapshot_processed_items + , unsigned long *snapshot_processed_refs +#endif /* MY_ABC_HERE */ + ) { struct btrfs_pending_snapshot *pending, *next; struct list_head *head = &trans->transaction->pending_snapshots; @@ -1779,7 +2091,13 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans) list_for_each_entry_safe(pending, next, head, list) { list_del(&pending->list); - ret = create_pending_snapshot(trans, pending); + ret = create_pending_snapshot(trans, pending +#ifdef MY_ABC_HERE + , snapshot_processed_inodes + , snapshot_processed_items + , snapshot_processed_refs +#endif /* MY_ABC_HERE */ + ); if (ret) break; } @@ -1801,9 +2119,17 @@ static void update_super_roots(struct btrfs_fs_info *fs_info) root_item = &fs_info->tree_root->root_item; super->root = root_item->bytenr; super->generation = root_item->generation; +#ifdef MY_ABC_HERE + super->syno_generation = root_item->generation; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + super->syno_capability_generation = root_item->generation; +#endif /* MY_ABC_HERE */ super->root_level = root_item->level; if (btrfs_test_opt(fs_info, SPACE_CACHE)) super->cache_generation = root_item->generation; + else if (test_bit(BTRFS_FS_CLEANUP_SPACE_CACHE_V1, &fs_info->flags)) + super->cache_generation = 0; if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags)) super->uuid_tree_generation = root_item->generation; } @@ -2067,6 +2393,121 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_trans_handle *trans) U64_MAX, 0, U64_MAX); } } +#ifdef MY_ABC_HERE +struct syno_btrfs_commit_stats { + struct timespec64 prepare_timestamp; + struct timespec64 wait_prev_trans_timestamp; + struct timespec64 start_timestamp; + struct timespec64 wait_join_trans_end_timestamp; + struct timespec64 run_data_refs_for_usrquota_timestamp; + struct timespec64 create_snapshot_timestamp; + struct timespec64 run_items_timestamp; + struct timespec64 run_refs_timestamp; + struct timespec64 commit_roots_timestamp; + struct timespec64 writeback_timestamp; + s64 start_eb_miss; + s64 start_eb_hit; + unsigned long prepare_before_run_refs; + unsigned long prepare_processed_refs; + unsigned long prepare_after_run_refs; + unsigned long pre_run_processed_inodes; + unsigned long pre_run_processed_items; + unsigned long run_data_refs_for_usrquota_processed_refs; + unsigned long snapshot_processed_inodes; + unsigned long snapshot_processed_items; + unsigned long snapshot_processed_refs; + unsigned long run_processed_inodes; + unsigned long run_processed_items; + unsigned long run_refs_processed_refs; + u64 write_eb_count; + u64 write_eb_size; +}; + +static void print_commit_stats(struct btrfs_fs_info *fs_info, + struct syno_btrfs_commit_stats *stats) +{ + struct timespec64 done; + struct timespec64 total; + s64 total_time; + + ktime_get_ts64(&done); + total = timespec64_sub(done, stats->start_timestamp); + total_time = timespec64_to_ns(&total) / NSEC_PER_MSEC; + + if (fs_info->commit_time_debug_ms && + fs_info->commit_time_debug_ms > total_time) + return; + + stats->start_eb_miss = + percpu_counter_sum(&fs_info->eb_miss) - stats->start_eb_miss; + stats->start_eb_hit = + percpu_counter_sum(&fs_info->eb_hit) - stats->start_eb_hit; + + done = timespec64_sub(done, stats->writeback_timestamp); + stats->writeback_timestamp = timespec64_sub( + stats->writeback_timestamp, stats->commit_roots_timestamp); + stats->commit_roots_timestamp = timespec64_sub( + stats->commit_roots_timestamp, stats->run_refs_timestamp); + stats->run_refs_timestamp = timespec64_sub( + stats->run_refs_timestamp, stats->run_items_timestamp); + stats->run_items_timestamp = timespec64_sub( + stats->run_items_timestamp, stats->create_snapshot_timestamp); + stats->create_snapshot_timestamp = timespec64_sub( + stats->create_snapshot_timestamp, stats->run_data_refs_for_usrquota_timestamp); + stats->run_data_refs_for_usrquota_timestamp = timespec64_sub( + stats->run_data_refs_for_usrquota_timestamp, stats->wait_join_trans_end_timestamp); + stats->wait_join_trans_end_timestamp = timespec64_sub( + stats->wait_join_trans_end_timestamp, stats->start_timestamp); + stats->start_timestamp = timespec64_sub( + stats->start_timestamp, stats->wait_prev_trans_timestamp); + stats->wait_prev_trans_timestamp = timespec64_sub( + stats->wait_prev_trans_timestamp, stats->prepare_timestamp); + + btrfs_warn(fs_info, "commit trans:\n" + "total_time: %lld, meta-read[miss/total]:[%llu/%llu], meta-write[count/size]:[%llu/%llu K]\n" + "prepare phase: time: %lld, refs[before/process/after]:[%lu/%lu/%lu]\n" + "wait prev trans completed: time: %lld\n" + "pre-run delayed item phase: time: %lld, inodes/items:[%lu/%lu]\n" + "wait join end trans: time: %lld\n" + "run data refs for usrquota: time: %lld, refs:[%lu]\n" + "create snpashot: time: %lld, inodes/items:[%lu/%lu], refs:[%lu]\n" + "delayed item phase: time: %lld, inodes/items:[%lu/%lu]\n" + "delayed refs phase: time: %lld, refs:[%lu]\n" + "commit roots phase: time: %lld\n" + "writeback phase: time: %lld", + total_time, stats->start_eb_miss, (stats->start_eb_miss + stats->start_eb_hit), + stats->write_eb_count, stats->write_eb_size >> 10, + // prepare phase + timespec64_to_ns(&stats->wait_prev_trans_timestamp) / NSEC_PER_MSEC, + stats->prepare_before_run_refs, + stats->prepare_processed_refs, + stats->prepare_after_run_refs, + // wait prev trans phase + timespec64_to_ns(&stats->start_timestamp) / NSEC_PER_MSEC, + // pre-run delayed item phase + timespec64_to_ns(&stats->wait_join_trans_end_timestamp) / NSEC_PER_MSEC, + stats->pre_run_processed_inodes, stats->pre_run_processed_items, + // wait join end trans phase + timespec64_to_ns(&stats->run_data_refs_for_usrquota_timestamp) / NSEC_PER_MSEC, + // run data refs for usrquota + timespec64_to_ns(&stats->create_snapshot_timestamp) / NSEC_PER_MSEC, + stats->run_data_refs_for_usrquota_processed_refs, + // create snpashot + timespec64_to_ns(&stats->run_items_timestamp) / NSEC_PER_MSEC, + stats->snapshot_processed_inodes, stats->snapshot_processed_items, + stats->snapshot_processed_refs, + // delayed item phase + timespec64_to_ns(&stats->run_refs_timestamp) / NSEC_PER_MSEC, + stats->run_processed_inodes, stats->run_processed_items, + // run delayed-refs + timespec64_to_ns(&stats->commit_roots_timestamp) / NSEC_PER_MSEC, + stats->run_refs_processed_refs, + // commit root phase + timespec64_to_ns(&stats->writeback_timestamp) / NSEC_PER_MSEC, + // writeback phase + timespec64_to_ns(&done) / NSEC_PER_MSEC); +} +#endif /* MY_ABC_HERE */ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) { @@ -2074,6 +2515,17 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) struct btrfs_transaction *cur_trans = trans->transaction; struct btrfs_transaction *prev_trans = NULL; int ret; +#ifdef MY_ABC_HERE + struct timespec64 locker_clock; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct syno_btrfs_commit_stats stats; + unsigned long processed_count = 0; + unsigned long processed_inodes = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned long pre_run_delayed_refs_count; +#endif /* MY_ABC_HERE */ ASSERT(refcount_read(&trans->use_count) == 1); @@ -2092,13 +2544,40 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) return ret; } +#ifdef MY_ABC_HERE + memset(&stats, 0, sizeof(stats)); + ktime_get_ts64(&stats.prepare_timestamp); + stats.prepare_before_run_refs = atomic_read(&trans->transaction->delayed_refs.num_entries); +#endif /* MY_ABC_HERE */ + btrfs_trans_release_metadata(trans); trans->block_rsv = NULL; /* make a pass through all the delayed refs we have so far * any runnings procs may add more while we are here */ - ret = btrfs_run_delayed_refs(trans, 0); +#ifdef MY_ABC_HERE + pre_run_delayed_refs_count = min_t(unsigned long, atomic_read(&trans->transaction->delayed_refs.num_entries) * 2, 512); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + processed_count = 0; + ret = btrfs_run_delayed_refs_and_get_processed(trans +#ifdef MY_ABC_HERE + , pre_run_delayed_refs_count +#else /* MY_ABC_HERE */ + , 0 +#endif /* MY_ABC_HERE */ + , &processed_count); + stats.prepare_processed_refs += processed_count; +#else /* MY_ABC_HERE */ + ret = btrfs_run_delayed_refs(trans +#ifdef MY_ABC_HERE + , pre_run_delayed_refs_count +#else /* MY_ABC_HERE */ + , 0 +#endif /* MY_ABC_HERE */ + ); +#endif /* MY_ABC_HERE */ if (ret) { btrfs_end_transaction(trans); return ret; @@ -2115,7 +2594,29 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) btrfs_create_pending_block_groups(trans); - ret = btrfs_run_delayed_refs(trans, 0); +#ifdef MY_ABC_HERE + pre_run_delayed_refs_count = min_t(unsigned long, atomic_read(&trans->transaction->delayed_refs.num_entries) * 2, 512); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + processed_count = 0; + ret = btrfs_run_delayed_refs_and_get_processed(trans +#ifdef MY_ABC_HERE + , pre_run_delayed_refs_count +#else /* MY_ABC_HERE */ + , 0 +#endif /* MY_ABC_HERE */ + , &processed_count); + stats.prepare_processed_refs += processed_count; + stats.prepare_after_run_refs = atomic_read(&trans->transaction->delayed_refs.num_entries); +#else /* MY_ABC_HERE */ + ret = btrfs_run_delayed_refs(trans +#ifdef MY_ABC_HERE + , pre_run_delayed_refs_count +#else /* MY_ABC_HERE */ + , 0 +#endif /* MY_ABC_HERE */ + ); +#endif /* MY_ABC_HERE */ if (ret) { btrfs_end_transaction(trans); return ret; @@ -2171,6 +2672,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) cur_trans->state = TRANS_STATE_COMMIT_START; wake_up(&fs_info->transaction_blocked_wait); +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.wait_prev_trans_timestamp); +#endif /* MY_ABC_HERE */ + if (cur_trans->list.prev != &fs_info->trans_list) { prev_trans = list_entry(cur_trans->list.prev, struct btrfs_transaction, list); @@ -2201,13 +2706,25 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) } } +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.start_timestamp); + stats.start_eb_miss = percpu_counter_sum(&fs_info->eb_miss); + stats.start_eb_hit = percpu_counter_sum(&fs_info->eb_hit); +#endif /* MY_ABC_HERE */ + extwriter_counter_dec(cur_trans, trans->type); ret = btrfs_start_delalloc_flush(trans); if (ret) goto cleanup_transaction; +#ifdef MY_ABC_HERE + ret = btrfs_run_delayed_items_and_get_processed(trans, + &stats.pre_run_processed_inodes, + &stats.pre_run_processed_items); +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_items(trans); +#endif /* MY_ABC_HERE */ if (ret) goto cleanup_transaction; @@ -2215,7 +2732,17 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) extwriter_counter_read(cur_trans) == 0); /* some pending stuffs might be added after the previous flush. */ +#ifdef MY_ABC_HERE + processed_inodes = 0; + processed_count = 0; + ret = btrfs_run_delayed_items_and_get_processed(trans, + &processed_inodes, + &processed_count); + stats.pre_run_processed_inodes += processed_inodes; + stats.pre_run_processed_items += processed_count; +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_items(trans); +#endif /* MY_ABC_HERE */ if (ret) goto cleanup_transaction; @@ -2230,6 +2757,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) atomic_read(&cur_trans->pending_ordered) == 0); btrfs_scrub_pause(fs_info); + +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.wait_join_trans_end_timestamp); +#endif /* MY_ABC_HERE */ /* * Ok now we need to make sure to block out any other joins while we * commit the transaction. We could have started a join before setting @@ -2245,6 +2776,30 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) ret = cur_trans->aborted; goto scrub_continue; } + +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.run_data_refs_for_usrquota_timestamp); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (btrfs_usrquota_compat_inode_quota(fs_info)) { +#ifdef MY_ABC_HERE + ret = btrfs_run_delayed_refs_and_get_processed(trans, + BTRFS_USRQUOTA_DELAYED_REF_SCAN, + &stats.run_data_refs_for_usrquota_processed_refs); +#else /* MY_ABC_HERE */ + ret = btrfs_run_delayed_refs(trans, BTRFS_USRQUOTA_DELAYED_REF_SCAN); +#endif /* MY_ABC_HERE */ + if (ret) { + goto scrub_continue; + } + } +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.create_snapshot_timestamp); +#endif /* MY_ABC_HERE */ /* * the reloc mutex makes sure that we stop * the balancing code from coming in and moving @@ -2257,7 +2812,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) * deal with them in create_pending_snapshot(), which is the * core function of the snapshot creation. */ - ret = create_pending_snapshots(trans); + ret = create_pending_snapshots(trans +#ifdef MY_ABC_HERE + , &stats.snapshot_processed_inodes + , &stats.snapshot_processed_items + , &stats.snapshot_processed_refs +#endif /* MY_ABC_HERE */ + ); if (ret) goto unlock_reloc; @@ -2271,11 +2832,25 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) * because all the tree which are snapshoted will be forced to COW * the nodes and leaves. */ +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.run_items_timestamp); + ret = btrfs_run_delayed_items_and_get_processed(trans, + &stats.run_processed_inodes, + &stats.run_processed_items); +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_items(trans); +#endif /* MY_ABC_HERE */ if (ret) goto unlock_reloc; +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.run_refs_timestamp); + ret = btrfs_run_delayed_refs_and_get_processed(trans, + (unsigned long) -1, + &stats.run_refs_processed_refs); +#else /* MY_ABC_HERE */ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1); +#endif /* MY_ABC_HERE */ if (ret) goto unlock_reloc; @@ -2287,6 +2862,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) WARN_ON(cur_trans != trans->transaction); +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.commit_roots_timestamp); +#endif /* MY_ABC_HERE */ /* btrfs_commit_tree_roots is responsible for getting the * various roots consistent with each other. Every pointer * in the tree of tree roots has to point to the most up to date @@ -2325,6 +2903,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) if (ret) goto unlock_tree_log; +#ifdef MY_ABC_HERE +#else /* * Since fs roots are all committed, we can get a quite accurate * new_roots. So let's do quota accounting. @@ -2332,6 +2912,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) ret = btrfs_qgroup_account_extents(trans); if (ret < 0) goto unlock_tree_log; +#endif /* MY_ABC_HERE */ ret = commit_cowonly_roots(trans); if (ret) @@ -2366,6 +2947,21 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) btrfs_set_super_log_root(fs_info->super_copy, 0); btrfs_set_super_log_root_level(fs_info->super_copy, 0); +#ifdef MY_ABC_HERE + btrfs_set_super_syno_log_tree_rsv(fs_info->super_copy, + fs_info->log_tree_rsv_start); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + btrfs_set_super_syno_rbd_first_mapping_table_offset( + fs_info->super_copy, + fs_info->syno_rbd.first_mapping_table_offset); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + locker_clock = btrfs_syno_locker_fs_clock_get(fs_info); + btrfs_set_super_syno_locker_clock(fs_info->super_copy, locker_clock.tv_sec); + btrfs_syno_locker_update_work_kick(fs_info); +#endif /* MY_ABC_HERE */ + memcpy(fs_info->super_for_commit, fs_info->super_copy, sizeof(*fs_info->super_copy)); @@ -2384,7 +2980,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) wake_up(&fs_info->transaction_wait); - ret = btrfs_write_and_wait_transaction(trans); +#ifdef MY_ABC_HERE + ktime_get_ts64(&stats.writeback_timestamp); +#endif /* MY_ABC_HERE */ + ret = btrfs_write_and_wait_transaction(trans +#ifdef MY_ABC_HERE + , &(stats.write_eb_count), &(stats.write_eb_size) +#endif /* MY_ABC_HERE */ + ); if (ret) { btrfs_handle_fs_error(fs_info, ret, "Error while writing out transaction"); @@ -2407,6 +3010,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) btrfs_finish_extent_commit(trans); +#ifdef MY_ABC_HERE + print_commit_stats(fs_info, &stats); +#endif /* MY_ABC_HERE */ + if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &cur_trans->flags)) btrfs_clear_space_info_full(fs_info); diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 858d9153a1cd..e8a550f4b514 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -10,6 +13,9 @@ #include "btrfs_inode.h" #include "delayed-ref.h" #include "ctree.h" +#if defined(MY_ABC_HERE) +#include "disk-io.h" +#endif /* MY_ABC_HERE */ enum btrfs_trans_state { TRANS_STATE_RUNNING, @@ -92,6 +98,14 @@ struct btrfs_transaction { */ atomic_t pending_ordered; wait_queue_head_t pending_wait; + +#ifdef MY_ABC_HERE + struct list_head quota_account_list; + spinlock_t quota_account_lock; + + // Used for quota v1 chown. + struct rw_semaphore delayed_refs_rw_sem; +#endif /* MY_ABC_HERE */ }; #define __TRANS_FREEZABLE (1U << 0) @@ -137,8 +151,32 @@ struct btrfs_trans_handle { struct btrfs_root *root; struct btrfs_fs_info *fs_info; struct list_head new_bgs; +#ifdef MY_ABC_HERE + bool syno_usage; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct btrfs_delayed_ref_throttle_ticket *syno_delayed_ref_throttle_ticket; + unsigned long total_delayed_ref_updates; + bool skip_throttle; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bool cleaner; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static inline void syno_total_delayed_ref_updates_dec(struct btrfs_trans_handle *trans) +{ + if (likely(trans) && trans->total_delayed_ref_updates) + trans->total_delayed_ref_updates--; +} +static inline void syno_total_delayed_ref_updates_inc(struct btrfs_trans_handle *trans) +{ + if (likely(trans)) + trans->total_delayed_ref_updates++; +} +#endif /* MY_ABC_HERE */ + /* * The abort status can be changed between calls and is not protected by locks. * This accepts btrfs_transaction and btrfs_trans_handle as types. Once it's @@ -154,6 +192,9 @@ struct btrfs_pending_snapshot { struct btrfs_root_item *root_item; struct btrfs_root *snap; struct btrfs_qgroup_inherit *inherit; +#ifdef MY_ABC_HERE + u64 copy_limit_from; +#endif /* MY_ABC_HERE */ struct btrfs_path *path; /* block reservation for the operation */ struct btrfs_block_rsv block_rsv; @@ -163,6 +204,10 @@ struct btrfs_pending_snapshot { dev_t anon_dev; bool readonly; struct list_head list; +#if defined(MY_ABC_HERE) + /* Preallocated new_fs_root_args */ + struct btrfs_new_fs_root_args *new_fs_root_args; +#endif /* MY_ABC_HERE */ }; static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans, @@ -213,18 +258,28 @@ struct btrfs_trans_handle *btrfs_attach_transaction_barrier( int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid); void btrfs_add_dead_root(struct btrfs_root *root); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +void btrfs_add_dead_root_head(struct btrfs_root *root); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ int btrfs_defrag_root(struct btrfs_root *root); int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root); int btrfs_commit_transaction(struct btrfs_trans_handle *trans); int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, int wait_for_unblock); int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans); +#ifdef MY_ABC_HERE +int btrfs_throttle_delayed_refs(struct btrfs_root *root, unsigned long total_delayed_ref_updates); +#endif /* MY_ABC_HERE */ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans); void btrfs_throttle(struct btrfs_fs_info *fs_info); int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info, - struct extent_io_tree *dirty_pages, int mark); + struct extent_io_tree *dirty_pages, int mark +#ifdef MY_ABC_HERE + , u64 *total_count, u64 *total_size +#endif /* MY_ABC_HERE */ + ); int btrfs_wait_tree_log_extents(struct btrfs_root *root, int mark); int btrfs_transaction_blocked(struct btrfs_fs_info *info); int btrfs_transaction_in_commit(struct btrfs_fs_info *info); diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index d4a3a56726aa..7a9a707d2788 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Qu Wenruo 2017. All rights reserved. @@ -1046,6 +1049,8 @@ static int check_inode_item(struct extent_buffer *leaf, btrfs_inode_nlink(leaf, iitem)); return -EUCLEAN; } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ if (btrfs_inode_flags(leaf, iitem) & ~BTRFS_INODE_FLAG_MASK) { inode_item_err(leaf, slot, "unknown flags detected: 0x%llx", @@ -1053,6 +1058,7 @@ static int check_inode_item(struct extent_buffer *leaf, ~BTRFS_INODE_FLAG_MASK); return -EUCLEAN; } +#endif /* MY_ABC_HERE */ return 0; } @@ -1061,8 +1067,11 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, { struct btrfs_fs_info *fs_info = leaf->fs_info; struct btrfs_root_item ri = { 0 }; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY | BTRFS_ROOT_SUBVOL_DEAD; +#endif /* MY_ABC_HERE */ int ret; ret = check_root_key(leaf, key, slot); @@ -1132,6 +1141,8 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, return -EUCLEAN; } +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ /* Flags check */ if (btrfs_root_flags(&ri) & ~valid_root_flags) { generic_err(leaf, slot, @@ -1139,6 +1150,7 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, btrfs_root_flags(&ri), valid_root_flags); return -EUCLEAN; } +#endif /* MY_ABC_HERE*/ return 0; } diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 4b913de2f24f..3d6207012f19 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2008 Oracle. All rights reserved. @@ -139,8 +142,25 @@ static int start_log_trans(struct btrfs_trans_handle *trans, struct btrfs_log_ctx *ctx) { struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_root *tree_root = fs_info->tree_root; int ret = 0; + /* + * First check if the log root tree was already created. If not, create + * it before locking the root's log_mutex, just to keep lockdep happy. + */ + if (!test_bit(BTRFS_ROOT_HAS_LOG_TREE, &tree_root->state)) { + mutex_lock(&tree_root->log_mutex); + if (!fs_info->log_root_tree) { + ret = btrfs_init_log_root_tree(trans, fs_info); + if (!ret) + set_bit(BTRFS_ROOT_HAS_LOG_TREE, &tree_root->state); + } + mutex_unlock(&tree_root->log_mutex); + if (ret) + return ret; + } + mutex_lock(&root->log_mutex); if (root->log_root) { @@ -156,13 +176,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans, set_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); } } else { - mutex_lock(&fs_info->tree_log_mutex); - if (!fs_info->log_root_tree) - ret = btrfs_init_log_root_tree(trans, fs_info); - mutex_unlock(&fs_info->tree_log_mutex); - if (ret) - goto out; - ret = btrfs_add_log_tree(trans, root); if (ret) goto out; @@ -576,6 +589,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, struct extent_buffer *eb, int slot, struct btrfs_key *key) { + struct btrfs_drop_extents_args drop_args = { 0 }; struct btrfs_fs_info *fs_info = root->fs_info; int found_type; u64 extent_end; @@ -585,6 +599,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, struct inode *inode = NULL; unsigned long size; int ret = 0; +#ifdef MY_ABC_HERE + int syno_usage; +#endif /* MY_ABC_HERE */ item = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); found_type = btrfs_file_extent_type(eb, item); @@ -653,7 +670,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, btrfs_release_path(path); /* drop any overlapping extents */ - ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); + drop_args.start = start; + drop_args.end = extent_end; + drop_args.drop_cache = true; + ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args); if (ret) goto out; @@ -681,6 +701,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ins.type = BTRFS_EXTENT_ITEM_KEY; offset = key->offset - btrfs_file_extent_offset(eb, item); +#ifdef MY_ABC_HERE +#else /* * Manually record dirty extent, as here we did a shallow * file extent item copy and skip normal backref update, @@ -695,6 +717,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, GFP_NOFS); if (ret < 0) goto out; +#endif /* MY_ABC_HERE */ if (ins.objectid > 0) { struct btrfs_ref ref = { 0 }; @@ -714,7 +737,33 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ins.objectid, ins.offset, 0); btrfs_init_data_ref(&ref, root->root_key.objectid, - key->objectid, offset); + key->objectid, offset +#ifdef MY_ABC_HERE + , btrfs_syno_usage_ref_check(root, key->objectid, key->offset) +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE + if (test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !btrfs_root_disable_quota(root)) { + struct quota_check qc = { + .bytenr = ins.objectid, + .root_objectid = root->root_key.objectid, + .ino = key->objectid, + .offset = (u64)-1, + .in_run_delayed = false + }; + ret = check_root_inode_ref(trans, &qc); + } else + ret = 1; + + if (ret) + ref.skip_qgroup = true; + else { + ref.skip_qgroup = false; + ref.inode = inode; + ref.ram_bytes = btrfs_file_extent_ram_bytes(eb, item); + } +#endif /* MY_ABC_HERE */ ret = btrfs_inc_extent_ref(trans, &ref); if (ret) goto out; @@ -725,9 +774,24 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, */ ret = btrfs_alloc_logged_file_extent(trans, root->root_key.objectid, - key->objectid, offset, &ins); + key->objectid, offset, &ins +#ifdef MY_ABC_HERE + , inode +#endif /* MY_ABC_HERE */ + ); if (ret) goto out; +#ifdef MY_ABC_HERE + syno_usage = btrfs_syno_usage_ref_check(root, key->objectid, key->offset); + btrfs_release_path(path); + if (syno_usage == 1) { + ret = btrfs_syno_subvol_usage_add(trans, root->root_key.objectid, ins.objectid, ins.offset, 1); + if (ret) + goto out; + } else if (syno_usage == 2) { + ret = btrfs_syno_extent_usage_add(trans, SYNO_USAGE_TYPE_RO_SNAPSHOT, ins.objectid, ins.offset, 0); + } +#endif /* MY_ABC_HERE */ } btrfs_release_path(path); @@ -828,8 +892,18 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, if (ret) goto out; - inode_add_bytes(inode, nbytes); update_inode: +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + btrfs_update_inode_bytes(BTRFS_I(inode), nbytes, drop_args.bytes_found); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + nbytes, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + nbytes, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + btrfs_update_inode_bytes(BTRFS_I(inode), nbytes, drop_args.bytes_found); +#endif /* MY_ABC_HERE */ ret = btrfs_update_inode(trans, root, inode); out: if (inode) @@ -2585,6 +2659,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, * those prealloc extents just after replaying them. */ if (S_ISREG(mode)) { + struct btrfs_drop_extents_args drop_args = { 0 }; struct inode *inode; u64 from; @@ -2595,9 +2670,26 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, } from = ALIGN(i_size_read(inode), root->fs_info->sectorsize); - ret = btrfs_drop_extents(wc->trans, root, inode, - from, (u64)-1, 1); + drop_args.start = from; + drop_args.end = (u64)-1; + drop_args.drop_cache = true; + ret = btrfs_drop_extents(wc->trans, root, + BTRFS_I(inode), + &drop_args); if (!ret) { +#ifdef MY_ABC_HERE + down_read(&root->rescan_lock); + inode_sub_bytes(inode, + drop_args.bytes_found); + btrfs_qgroup_syno_accounting(BTRFS_I(inode), + 0, drop_args.bytes_found, UPDATE_QUOTA); + btrfs_usrquota_syno_accounting(BTRFS_I(inode), + 0, drop_args.bytes_found, UPDATE_QUOTA); + up_read(&root->rescan_lock); +#else + inode_sub_bytes(inode, + drop_args.bytes_found); +#endif /* MY_ABC_HERE */ /* Update the inode's nbytes. */ ret = btrfs_update_inode(wc->trans, root, inode); @@ -3022,6 +3114,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, int log_transid = 0; struct btrfs_log_ctx root_log_ctx; struct blk_plug plug; + u64 log_root_start; + u64 log_root_level; mutex_lock(&root->log_mutex); log_transid = ctx->log_transid; @@ -3073,7 +3167,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, * wait for them until later. */ blk_start_plug(&plug); - ret = btrfs_write_marked_extents(fs_info, &log->dirty_log_pages, mark); + ret = btrfs_write_marked_extents(fs_info, &log->dirty_log_pages, mark +#ifdef MY_ABC_HERE + , NULL, NULL +#endif /* MY_ABC_HERE */ + ); if (ret) { blk_finish_plug(&plug); btrfs_abort_transaction(trans, ret); @@ -3181,7 +3279,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ret = btrfs_write_marked_extents(fs_info, &log_root_tree->dirty_log_pages, - EXTENT_DIRTY | EXTENT_NEW); + EXTENT_DIRTY | EXTENT_NEW +#ifdef MY_ABC_HERE + , NULL, NULL +#endif /* MY_ABC_HERE */ + ); blk_finish_plug(&plug); if (ret) { btrfs_set_log_full_commit(trans); @@ -3199,22 +3301,31 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, goto out_wake_log_root; } - btrfs_set_super_log_root(fs_info->super_for_commit, - log_root_tree->node->start); - btrfs_set_super_log_root_level(fs_info->super_for_commit, - btrfs_header_level(log_root_tree->node)); - + log_root_start = log_root_tree->node->start; + log_root_level = btrfs_header_level(log_root_tree->node); log_root_tree->log_transid++; mutex_unlock(&log_root_tree->log_mutex); /* - * Nobody else is going to jump in and write the ctree - * super here because the log_commit atomic below is protecting - * us. We must be called with a transaction handle pinning - * the running transaction open, so a full commit can't hop - * in and cause problems either. + * Here we are guaranteed that nobody is going to write the superblock + * for the current transaction before us and that neither we do write + * our superblock before the previous transaction finishes its commit + * and writes its superblock, because: + * + * 1) We are holding a handle on the current transaction, so no body + * can commit it until we release the handle; + * + * 2) Before writing our superblock we acquire the tree_log_mutex, so + * if the previous transaction is still committing, and hasn't yet + * written its superblock, we wait for it to do it, because a + * transaction commit acquires the tree_log_mutex when the commit + * begins and releases it only after writing its superblock. */ + mutex_lock(&fs_info->tree_log_mutex); + btrfs_set_super_log_root(fs_info->super_for_commit, log_root_start); + btrfs_set_super_log_root_level(fs_info->super_for_commit, log_root_level); ret = write_all_supers(fs_info, 1); + mutex_unlock(&fs_info->tree_log_mutex); if (ret) { btrfs_set_log_full_commit(trans); btrfs_abort_transaction(trans, ret); @@ -3299,6 +3410,7 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, if (fs_info->log_root_tree) { free_log_tree(trans, fs_info->log_root_tree); fs_info->log_root_tree = NULL; + clear_bit(BTRFS_ROOT_HAS_LOG_TREE, &fs_info->tree_root->state); } return 0; } @@ -4195,6 +4307,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, struct btrfs_path *path, struct btrfs_log_ctx *ctx) { + struct btrfs_drop_extents_args drop_args = { 0 }; struct btrfs_root *log = root->log_root; struct btrfs_file_extent_item *fi; struct extent_buffer *leaf; @@ -4203,19 +4316,21 @@ static int log_one_extent(struct btrfs_trans_handle *trans, u64 extent_offset = em->start - em->orig_start; u64 block_len; int ret; - int extent_inserted = 0; ret = log_extent_csums(trans, inode, log, em, ctx); if (ret) return ret; - ret = __btrfs_drop_extents(trans, log, inode, path, em->start, - em->start + em->len, NULL, 0, 1, - sizeof(*fi), &extent_inserted); + drop_args.path = path; + drop_args.start = em->start; + drop_args.end = em->start + em->len; + drop_args.replace_extent = true; + drop_args.extent_item_size = sizeof(*fi); + ret = btrfs_drop_extents(trans, log, inode, &drop_args); if (ret) return ret; - if (!extent_inserted) { + if (!drop_args.extent_inserted) { key.objectid = btrfs_ino(inode); key.type = BTRFS_EXTENT_DATA_KEY; key.offset = em->start; @@ -4259,6 +4374,9 @@ static int log_one_extent(struct btrfs_trans_handle *trans, btrfs_set_token_file_extent_compression(&token, fi, em->compress_type); btrfs_set_token_file_extent_encryption(&token, fi, 0); btrfs_set_token_file_extent_other_encoding(&token, fi, 0); +#ifdef MY_ABC_HERE + btrfs_set_token_file_extent_syno_flag(&token, fi, 0); +#endif /* MY_ABC_HERE */ btrfs_mark_buffer_dirty(leaf); btrfs_release_path(path); @@ -4414,14 +4532,12 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, struct extent_map *em, *n; struct list_head extents; struct extent_map_tree *tree = &inode->extent_tree; - u64 test_gen; int ret = 0; int num = 0; INIT_LIST_HEAD(&extents); write_lock(&tree->lock); - test_gen = root->fs_info->last_trans_committed; list_for_each_entry_safe(em, n, &tree->modified_extents, list) { list_del_init(&em->list); @@ -4437,7 +4553,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, goto process; } - if (em->generation <= test_gen) + if (em->generation < trans->transid) continue; /* We log prealloc extents beyond eof later. */ @@ -5449,11 +5565,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, static bool btrfs_must_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_inode *inode) { - struct btrfs_fs_info *fs_info = inode->root->fs_info; bool ret = false; mutex_lock(&inode->log_mutex); - if (inode->last_unlink_trans > fs_info->last_trans_committed) { + if (inode->last_unlink_trans >= trans->transid) { /* * Make sure any commits to the log are forced to be full * commits. @@ -5475,8 +5590,7 @@ static bool btrfs_must_commit_transaction(struct btrfs_trans_handle *trans, static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct dentry *parent, - struct super_block *sb, - u64 last_committed) + struct super_block *sb) { int ret = 0; struct dentry *old_parent = NULL; @@ -5488,8 +5602,8 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, * and other fun in this file. */ if (S_ISREG(inode->vfs_inode.i_mode) && - inode->generation <= last_committed && - inode->last_unlink_trans <= last_committed) + inode->generation < trans->transid && + inode->last_unlink_trans < trans->transid) goto out; if (!S_ISDIR(inode->vfs_inode.i_mode)) { @@ -5835,7 +5949,6 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans, while (true) { struct btrfs_fs_info *fs_info = root->fs_info; - const u64 last_committed = fs_info->last_trans_committed; struct extent_buffer *leaf = path->nodes[0]; int slot = path->slots[0]; struct btrfs_key search_key; @@ -5854,7 +5967,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans, if (IS_ERR(inode)) return PTR_ERR(inode); - if (BTRFS_I(inode)->generation > last_committed) + if (BTRFS_I(inode)->generation >= trans->transid) ret = btrfs_log_inode(trans, root, BTRFS_I(inode), LOG_INODE_EXISTS, ctx); btrfs_add_delayed_iput(inode); @@ -5895,7 +6008,6 @@ static int log_new_ancestors_fast(struct btrfs_trans_handle *trans, struct btrfs_log_ctx *ctx) { struct btrfs_root *root = inode->root; - struct btrfs_fs_info *fs_info = root->fs_info; struct dentry *old_parent = NULL; struct super_block *sb = inode->vfs_inode.i_sb; int ret = 0; @@ -5909,7 +6021,7 @@ static int log_new_ancestors_fast(struct btrfs_trans_handle *trans, if (root != inode->root) break; - if (inode->generation > fs_info->last_trans_committed) { + if (inode->generation >= trans->transid) { ret = btrfs_log_inode(trans, root, inode, LOG_INODE_EXISTS, ctx); if (ret) @@ -6026,7 +6138,6 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info = root->fs_info; struct super_block *sb; int ret = 0; - u64 last_committed = fs_info->last_trans_committed; bool log_dentries = false; sb = inode->vfs_inode.i_sb; @@ -6036,23 +6147,12 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, goto end_no_trans; } - /* - * The prev transaction commit doesn't complete, we need do - * full commit by ourselves. - */ - if (fs_info->last_trans_log_full_commit > - fs_info->last_trans_committed) { - ret = 1; - goto end_no_trans; - } - if (btrfs_root_refs(&root->root_item) == 0) { ret = 1; goto end_no_trans; } - ret = check_parent_dirs_for_sync(trans, inode, parent, sb, - last_committed); + ret = check_parent_dirs_for_sync(trans, inode, parent, sb); if (ret) goto end_no_trans; @@ -6083,8 +6183,8 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, * and other fun in this file. */ if (S_ISREG(inode->vfs_inode.i_mode) && - inode->generation <= last_committed && - inode->last_unlink_trans <= last_committed) { + inode->generation < trans->transid && + inode->last_unlink_trans < trans->transid) { ret = 0; goto end_trans; } @@ -6133,7 +6233,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, * but the file inode does not have a matching BTRFS_INODE_REF_KEY item * and has a link count of 2. */ - if (inode->last_unlink_trans > last_committed) { + if (inode->last_unlink_trans >= trans->transid) { ret = btrfs_log_all_parents(trans, inode, ctx); if (ret) goto end_trans; @@ -6443,7 +6543,6 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_inode *old_dir, struct dentry *parent) { - struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_log_ctx ctx; /* @@ -6457,8 +6556,8 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans, * if this inode hasn't been logged and directory we're renaming it * from hasn't been logged, we don't need to log it */ - if (inode->logged_trans <= fs_info->last_trans_committed && - (!old_dir || old_dir->logged_trans <= fs_info->last_trans_committed)) + if (inode->logged_trans < trans->transid && + (!old_dir || old_dir->logged_trans < trans->transid)) return; btrfs_init_log_ctx(&ctx, &inode->vfs_inode); diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c index 3374c9e9be67..0aaa8fa72bfd 100644 --- a/fs/btrfs/ulist.c +++ b/fs/btrfs/ulist.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2011 STRATO AG @@ -215,6 +218,44 @@ int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, return 1; } +#ifdef MY_ABC_HERE +int ulist_add_for_prealloc(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask, struct ulist_node **prealloc_ulist_node) +{ + return ulist_add_merge_for_prealloc(ulist, val, aux, NULL, gfp_mask, prealloc_ulist_node); +} + +int ulist_add_merge_for_prealloc(struct ulist *ulist, u64 val, u64 aux, u64 *old_aux, gfp_t gfp_mask, struct ulist_node **prealloc_ulist_node) +{ + int ret; + struct ulist_node *node; + + node = ulist_rbtree_search(ulist, val); + if (node) { + if (old_aux) + *old_aux = node->aux; + return 0; + } + if (prealloc_ulist_node) { + node = *prealloc_ulist_node; + *prealloc_ulist_node = NULL; + } else { + node = kmalloc(sizeof(*node), gfp_mask); + if (!node) + return -ENOMEM; + } + + node->val = val; + node->aux = aux; + + ret = ulist_rbtree_insert(ulist, node); + ASSERT(!ret); + list_add_tail(&node->list, &ulist->nodes); + ulist->nnodes++; + + return 1; +} +#endif /* MY_ABC_HERE */ + /* * ulist_del - delete one node from ulist * @ulist: ulist to remove node from @@ -274,3 +315,98 @@ struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter) node = list_entry(uiter->cur_list, struct ulist_node, list); return node; } + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) \ + || defined(MY_ABC_HERE) +int ulist_add_lru_adjust(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask) +{ + int ret; + struct ulist_node *node; + + node = ulist_rbtree_search(ulist, val); + if (node) { + list_move_tail(&node->list, &ulist->nodes); + return 0; + } + node = kmalloc(sizeof(*node), gfp_mask); + if (!node) + return -ENOMEM; + + node->val = val; + node->aux = aux; + + ret = ulist_rbtree_insert(ulist, node); + ASSERT(!ret); + list_add_tail(&node->list, &ulist->nodes); + ulist->nnodes++; + + return 1; +} + +/* + * ulist_remove_first - Remove first node from list (FIFO order) + * It just detach the node from list + */ +void ulist_remove_first(struct ulist *ulist) +{ + struct ulist_node *node; + + if (!ulist->nnodes) + return; + + node = list_entry(ulist->nodes.next, struct ulist_node, list); + rb_erase(&node->rb_node, &ulist->root); + list_del(&node->list); + ulist->nnodes--; + kfree(node); +} +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +struct ulist_node * ulist_search(struct ulist *ulist, u64 val) +{ + struct rb_node *n = ulist->root.rb_node; + struct ulist_node *u = NULL; + + while (n) { + u = rb_entry(n, struct ulist_node, rb_node); + if (u->val < val) + n = n->rb_right; + else if (u->val > val) + n = n->rb_left; + else + return u; + } + return NULL; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct ulist_node * ulist_search_with_prev(struct ulist *ulist, u64 val) +{ + struct rb_node *n = ulist->root.rb_node; + struct ulist_node *u = NULL; + struct rb_node *prev = NULL; + struct ulist_node *prev_entry = NULL; + + while (n) { + u = rb_entry(n, struct ulist_node, rb_node); + prev = n; + prev_entry = u; + if (u->val < val) + n = n->rb_right; + else if (u->val > val) + n = n->rb_left; + else + return u; + } + + while (prev && val < prev_entry->val) { + prev = rb_prev(prev); + if (prev) + prev_entry = rb_entry(prev, struct ulist_node, rb_node); + } + + return prev_entry; +} +#endif /* MY_ABC_HERE */ diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h index 02fda0a2d4ce..1b3455f9b7fe 100644 --- a/fs/btrfs/ulist.h +++ b/fs/btrfs/ulist.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2011 STRATO AG @@ -50,6 +53,10 @@ void ulist_free(struct ulist *ulist); int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask); int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, u64 *old_aux, gfp_t gfp_mask); +#ifdef MY_ABC_HERE +int ulist_add_for_prealloc(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask, struct ulist_node **prealloc_ulist_node); +int ulist_add_merge_for_prealloc(struct ulist *ulist, u64 val, u64 aux, u64 *old_aux, gfp_t gfp_mask, struct ulist_node **prealloc_ulist_node); +#endif /* MY_ABC_HERE */ int ulist_del(struct ulist *ulist, u64 val, u64 aux); /* just like ulist_add_merge() but take a pointer for the aux data */ @@ -71,4 +78,18 @@ struct ulist_node *ulist_next(struct ulist *ulist, #define ULIST_ITER_INIT(uiter) ((uiter)->cur_list = NULL) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define ULIST_NODES_MAX 65536 // 256MiB / 4KiB = 65536; 65536 ulist_node = 3.5MiB +int ulist_add_lru_adjust(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask); +void ulist_remove_first(struct ulist *ulist); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct ulist_node * ulist_search(struct ulist *ulist, u64 val); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct ulist_node * ulist_search_with_prev(struct ulist *ulist, u64 val); +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/btrfs/usrquota.c b/fs/btrfs/usrquota.c new file mode 100644 index 000000000000..9b5859299455 --- /dev/null +++ b/fs/btrfs/usrquota.c @@ -0,0 +1,2877 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2021 Synology Inc. All rights reserved. + */ +#include +#include +#include + +#include "ctree.h" +#include "transaction.h" +#include "disk-io.h" +#include "locking.h" +#include "extent_io.h" +#include "qgroup.h" +#include "backref.h" + +#define USRQUOTA_RO_SUBVOL_EXIST_GEN 10 + +struct btrfs_usrquota { + u64 uq_objectid; + u64 uq_uid; // __kuid_val(inode->i_uid) + + // info item + u64 uq_generation; + u64 uq_rfer_used; + // limit item + u64 uq_rfer_soft; + u64 uq_rfer_hard; + // reservation tracking + u64 uq_reserved; + + struct list_head uq_dirty; + u64 uq_refcnt; // accurate on dummy node only + + // tree of userquota + struct rb_node uq_node; + + bool need_rescan; + bool update_limit; +}; + +struct btrfs_subvol_list { + u64 subvol_id; + struct list_head list; +}; + +static void usrquota_subtree_unload_nolock(struct btrfs_fs_info *fs_info, u64 rootid); + +static u64 find_next_valid_objectid(struct btrfs_fs_info *fs_info, u64 objectid) +{ + struct rb_node *node = fs_info->usrquota_tree.rb_node; + struct btrfs_usrquota *usrquota; + u64 valid_objectid = 0; + + while (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + if (usrquota->uq_objectid > objectid) { + valid_objectid = usrquota->uq_objectid; + node = node->rb_left; + } else if (usrquota->uq_objectid < objectid) + node = node->rb_right; + else + break; + } + if (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + valid_objectid = usrquota->uq_objectid; + } + return valid_objectid; +} + +/* + * *_usrquota_rb should protected by usrquota_lock + */ +static struct rb_node *find_usrquota_first_rb(struct btrfs_fs_info *fs_info, + u64 objectid) +{ + struct rb_node *node = fs_info->usrquota_tree.rb_node; + struct rb_node *found = NULL; + struct btrfs_usrquota *usrquota; + +again: + while (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + if (usrquota->uq_objectid > objectid) + node = node->rb_left; + else if (usrquota->uq_objectid < objectid) + node = node->rb_right; + else + break; + } + if (!node) + goto out; + found = node; + while (node->rb_left) { + usrquota = rb_entry(node->rb_left, struct btrfs_usrquota, uq_node); + node = node->rb_left; + if (usrquota->uq_objectid != objectid) + goto again; + found = node; + } +out: + return found; +} + + +static struct btrfs_usrquota *find_usrquota_rb(struct btrfs_fs_info *fs_info, + u64 objectid, u64 uid) +{ + struct rb_node *node = fs_info->usrquota_tree.rb_node; + struct btrfs_usrquota *usrquota; + + while (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + if (usrquota->uq_objectid > objectid) + node = node->rb_left; + else if (usrquota->uq_objectid < objectid) + node = node->rb_right; + else if (usrquota->uq_uid > uid) + node = node->rb_left; + else if (usrquota->uq_uid < uid) + node = node->rb_right; + else + return usrquota; + } + return NULL; +} + +static struct btrfs_usrquota *__add_usrquota_rb(struct btrfs_fs_info *fs_info, + u64 objectid, u64 uid, int subtree_check) +{ + struct rb_node **p = &fs_info->usrquota_tree.rb_node; + struct rb_node *parent = NULL; + struct btrfs_usrquota *usrquota; + struct btrfs_root *subvol_root; + int subtree_loaded = 0; + + while (*p) { + parent = *p; + usrquota = rb_entry(parent, struct btrfs_usrquota, uq_node); + + if (usrquota->uq_objectid > objectid) + p = &(*p)->rb_left; + else if (usrquota->uq_objectid < objectid) + p = &(*p)->rb_right; + else if (usrquota->uq_uid > uid) { + subtree_loaded = 1; + p = &(*p)->rb_left; + } else if (usrquota->uq_uid < uid) { + subtree_loaded = 1; + p = &(*p)->rb_right; + } else + return usrquota; + } + + if (subtree_check && !subtree_loaded) { + subvol_root = btrfs_get_fs_root(fs_info, objectid, true); + if (IS_ERR(subvol_root)) { + btrfs_err(fs_info, "Failed to get subvol from rootid[%llu].", objectid); + } else { + btrfs_debug(fs_info, "Usrquota subtree for rootid [%llu], read-only[%d], is not loaded.", + objectid, btrfs_root_readonly(subvol_root)); + btrfs_put_root(subvol_root); + } + return ERR_PTR(-ENOENT); + } + + usrquota = kzalloc(sizeof(*usrquota), GFP_ATOMIC); + if (!usrquota) + return ERR_PTR(-ENOMEM); + + usrquota->uq_objectid = objectid; + usrquota->uq_uid = uid; + INIT_LIST_HEAD(&usrquota->uq_dirty); + + rb_link_node(&usrquota->uq_node, parent, p); + rb_insert_color(&usrquota->uq_node, &fs_info->usrquota_tree); + + return usrquota; +} + +/* + * Caller of add_usrquota_rb[_no_check] should hold usrquota_lock + */ +static inline struct btrfs_usrquota *add_usrquota_rb_nocheck(struct btrfs_fs_info *fs_info, + u64 objectid, u64 uid) +{ + return __add_usrquota_rb(fs_info, objectid, uid, 0); +} + +static inline struct btrfs_usrquota *add_usrquota_dummy_rb_nocheck(struct btrfs_fs_info *fs_info, + u64 objectid) +{ + struct btrfs_usrquota *usrquota; + + usrquota = __add_usrquota_rb(fs_info, objectid, 0, 0); + if (!IS_ERR_OR_NULL(usrquota)) + usrquota->uq_refcnt = 1; + return usrquota; +} + +static inline struct btrfs_usrquota *add_usrquota_rb(struct btrfs_fs_info *fs_info, + u64 objectid, u64 uid) +{ + return __add_usrquota_rb(fs_info, objectid, uid, 1); +} + +static int del_usrquota_rb(struct btrfs_fs_info *fs_info, struct btrfs_usrquota *usrquota) +{ + rb_erase(&usrquota->uq_node, &fs_info->usrquota_tree); + list_del(&usrquota->uq_dirty); + kfree(usrquota); + return 0; +} + +static void usrquota_free_reserve(struct btrfs_fs_info *fs_info, + struct btrfs_usrquota *usrquota, + struct btrfs_inode *b_inode, u64 num_bytes) +{ +#ifdef USRQUOTA_DEBUG + printk(KERN_INFO "usrquota_free_reserve debug: root = %llu, ino = %lu, uid = %llu, " + "reserved = %llu, to_free = %llu", usrquota->uq_objectid, + (b_inode) ? b_inode->vfs_inode.i_ino : 0, + usrquota->uq_uid, usrquota->uq_reserved, num_bytes); +#endif /* USRQUOTA_DEBUG */ + + if (usrquota->uq_reserved >= num_bytes) + usrquota->uq_reserved -= num_bytes; + else { + WARN_ONCE(1, "user quota root %llu uid %llu reserved space underflow, " + "have %llu to free %llu", + usrquota->uq_objectid, usrquota->uq_uid, + usrquota->uq_reserved, num_bytes); + usrquota->uq_reserved = 0; + } + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags) && + !btrfs_usrquota_fast_chown_enable(&b_inode->vfs_inode)) + return; + + if (b_inode->uq_reserved >= num_bytes) + b_inode->uq_reserved -= num_bytes; + else { + WARN_ONCE(1, "user quota root %llu inode %llu reserved space underflow, " + "have %llu to free %llu", + usrquota->uq_objectid, b_inode->location.objectid, + b_inode->uq_reserved, num_bytes); + b_inode->uq_reserved = 0; + } +} + +/* + * Caller of usrquota_subtree_load has responsibility to call usrquota_subtree_unload + * to dec reference count except btrfs_usrquota_load_config + * Caller should make sure user quota won't leave us. + */ +int usrquota_subtree_load(struct btrfs_fs_info *fs_info, u64 rootid) +{ + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root *usrquota_root = fs_info->usrquota_root; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_usrquota_info_item *info_item; + struct btrfs_usrquota_limit_item *limit_item; + struct btrfs_usrquota *usrquota; + int slot; + int ret = 0; + struct rb_node *node; + + spin_lock(&fs_info->usrquota_lock); + if (!fs_info->usrquota_root) { + spin_unlock(&fs_info->usrquota_lock); + return -EINVAL; + } + + node = find_usrquota_first_rb(fs_info, rootid); + if (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + usrquota->uq_refcnt++; + spin_unlock(&fs_info->usrquota_lock); + return 0; + } + + // insert a dummy node to identify if subtree is loaded or not + usrquota = add_usrquota_dummy_rb_nocheck(fs_info, rootid); + if (IS_ERR(usrquota)) { + spin_unlock(&fs_info->usrquota_lock); + return PTR_ERR(usrquota); + } + spin_unlock(&fs_info->usrquota_lock); + + path = btrfs_alloc_path(); + if (!path) { + return -ENOMEM; + } + + key.objectid = rootid; + key.type = 0; + key.offset = 0; + ret = btrfs_search_slot_for_read(usrquota_root, &key, path, 1, 0); + if (ret < 0) + goto out; + if (ret) { + ret = 0; + goto out; + } + while (1) { + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + if (found_key.objectid > rootid) + break; + if (found_key.type != BTRFS_USRQUOTA_INFO_KEY && + found_key.type != BTRFS_USRQUOTA_LIMIT_KEY) + goto next_item; + + spin_lock(&fs_info->usrquota_lock); + if (!fs_info->usrquota_root) { + spin_unlock(&fs_info->usrquota_lock); + ret = -EINVAL; + goto out; + } + + usrquota = add_usrquota_rb_nocheck(fs_info, found_key.objectid, found_key.offset); + if (IS_ERR(usrquota)) { + spin_unlock(&fs_info->usrquota_lock); + ret = PTR_ERR(usrquota); + goto out; + } + + switch (found_key.type) { + case BTRFS_USRQUOTA_INFO_KEY: + info_item = btrfs_item_ptr(leaf, slot, + struct btrfs_usrquota_info_item); + usrquota->uq_generation = btrfs_usrquota_info_generation(leaf, info_item); + usrquota->uq_rfer_used = btrfs_usrquota_info_rfer_used(leaf, info_item); + break; + case BTRFS_USRQUOTA_LIMIT_KEY: + limit_item = btrfs_item_ptr(leaf, slot, + struct btrfs_usrquota_limit_item); + usrquota->uq_rfer_soft = btrfs_usrquota_limit_rfer_soft(leaf, limit_item); + usrquota->uq_rfer_hard = btrfs_usrquota_limit_rfer_hard(leaf, limit_item); + break; + } + spin_unlock(&fs_info->usrquota_lock); +next_item: + ret = btrfs_next_item(usrquota_root, path); + if (ret < 0) { + btrfs_err(fs_info, "failed to get next_item of usrquota tree"); + goto out; + } + if (ret) { + ret = 0; + break; + } + } +out: + if (ret) { + // refcnt is possible greater than 1, + // such that we use unload function to check refcnt + usrquota_subtree_unload(fs_info, rootid); + } + btrfs_free_path(path); + return ret; +} + +static void usrquota_ro_subvol_check(struct btrfs_fs_info *fs_info, struct btrfs_root *root) +{ + int ret; + mutex_lock(&fs_info->usrquota_ro_roots_lock); + + if (!btrfs_root_readonly(root)) { + goto out; + } + + root->usrquota_loaded_gen = fs_info->generation; + if (!list_empty(&root->usrquota_ro_root)) + goto out; + + ret = usrquota_subtree_load(fs_info, root->root_key.objectid); + if (ret) { + btrfs_err(fs_info, "failed to load ro subvol usrquota subtree [%llu].", + root->root_key.objectid); + goto out; + } + btrfs_debug(fs_info, "Load ro sub [id:%llu, gen:%llu]", root->root_key.objectid, + root->usrquota_loaded_gen); + list_add_tail(&root->usrquota_ro_root, &fs_info->usrquota_ro_roots); + btrfs_grab_root(root); +out: + mutex_unlock(&fs_info->usrquota_ro_roots_lock); + return; +} + +static void usrquota_subtree_unload_nolock(struct btrfs_fs_info *fs_info, u64 rootid) +{ + struct btrfs_usrquota *usrquota; + struct rb_node *node; + + node = find_usrquota_first_rb(fs_info, rootid); + if (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + WARN_ON(usrquota->uq_uid); // This should be the dummy node. + if (usrquota->uq_refcnt > 1) { + usrquota->uq_refcnt--; + return; + } + } + while (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + node = rb_next(node); + if (usrquota->uq_objectid > rootid) + break; + del_usrquota_rb(fs_info, usrquota); + } +} + +// Caller should make sure user quota won't leave us. +void usrquota_subtree_unload(struct btrfs_fs_info *fs_info, u64 rootid) +{ + spin_lock(&fs_info->usrquota_lock); + if (fs_info->usrquota_root) + usrquota_subtree_unload_nolock(fs_info, rootid); + spin_unlock(&fs_info->usrquota_lock); +} + +static int usrquota_subtree_load_one(struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct list_head *subvol_queue, u64 subvol_id) +{ + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root *subvol_root; + struct extent_buffer *leaf; + struct btrfs_subvol_list *subvol_list; + int slot; + int ret = 0; + + subvol_root = btrfs_get_fs_root(fs_info, subvol_id, true); + if (IS_ERR(subvol_root)) { + ret = PTR_ERR(subvol_root); + goto out; + } + if (btrfs_root_readonly(subvol_root)) + goto update_queue; + + ret = usrquota_subtree_load(fs_info, subvol_id); + if (ret) { + goto out; + } + +update_queue: + if (btrfs_root_noload_usrquota(subvol_root)) + goto out; + + key.objectid = subvol_id; + key.type = BTRFS_ROOT_REF_KEY; + key.offset = 0; + ret = btrfs_search_slot_for_read(fs_info->tree_root, &key, path, 1, 0); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; //no entry + goto out; + } + while (1) { + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + if (found_key.type != BTRFS_ROOT_REF_KEY) + break; + + if (!IS_ERR_OR_NULL(subvol_root)) + btrfs_put_root(subvol_root); + subvol_root = btrfs_get_fs_root(fs_info, found_key.offset, true); + if (IS_ERR(subvol_root)) { + ret = PTR_ERR(subvol_root); + goto out; + } + + subvol_list = kzalloc(sizeof(*subvol_list), GFP_KERNEL); + if (!subvol_list) { + ret = -ENOMEM; + goto out; + } + INIT_LIST_HEAD(&subvol_list->list); + subvol_list->subvol_id = found_key.offset; + list_add_tail(&subvol_list->list, subvol_queue); + ret = btrfs_next_item(fs_info->tree_root, path); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; //no entry + goto out; + } + } +out: + btrfs_release_path(path); + if (!IS_ERR_OR_NULL(subvol_root)) + btrfs_put_root(subvol_root); + return ret; +} + +static int usrquota_subtree_load_all(struct btrfs_fs_info *fs_info) +{ + struct btrfs_path *path = NULL; + struct list_head subvol_queue; + struct btrfs_subvol_list *subvol_list; + int ret = 0; + + INIT_LIST_HEAD(&subvol_queue); + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + subvol_list = kzalloc(sizeof(*subvol_list), GFP_KERNEL); + if (!subvol_list) { + ret = -ENOMEM; + goto out; + } + INIT_LIST_HEAD(&subvol_list->list); + subvol_list->subvol_id = BTRFS_FS_TREE_OBJECTID; + list_add_tail(&subvol_list->list, &subvol_queue); + + while (!list_empty(&subvol_queue)) { + subvol_list = list_first_entry(&subvol_queue, struct btrfs_subvol_list, list); + list_del_init(&subvol_list->list); + if (!ret) { + ret = usrquota_subtree_load_one(fs_info, path, &subvol_queue, subvol_list->subvol_id); + if (ret) { + btrfs_err(fs_info, "failed to load usrquota subtree %llu, ret=%d", subvol_list->subvol_id, ret); + } + } + kfree(subvol_list); + } +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_read_usrquota_compat_config(struct btrfs_fs_info *fs_info) +{ + int ret = 0; + struct btrfs_path *path; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root *usrquota_root = fs_info->usrquota_root; + struct extent_buffer *leaf; + struct btrfs_usrquota_compat_item *compat_item; + int slot; + + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags)) + return 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + fs_info->usrquota_compat_flags = 0; + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_COMPAT_KEY; + key.offset = 0; + ret = btrfs_search_slot(NULL, usrquota_root, &key, path, 0, 0); + if (ret) { + if (ret > 0) { + fs_info->usrquota_compat_flags = BTRFS_USRQUOTA_COMPAT_FLAG; + ret = 0; + } + goto out; + } + + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + + compat_item = btrfs_item_ptr(leaf, slot, + struct btrfs_usrquota_compat_item); + + fs_info->usrquota_compat_flags |= btrfs_usrquota_compat_flags(leaf, compat_item); + fs_info->usrquota_compat_flags &= BTRFS_USRQUOTA_COMPAT_FLAG; + + if (btrfs_usrquota_compat_generation(leaf, compat_item) != fs_info->generation) { + fs_info->usrquota_compat_flags = 0; + } +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_read_usrquota_config(struct btrfs_fs_info *fs_info) +{ + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root *usrquota_root = fs_info->usrquota_root; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf; + struct btrfs_usrquota_status_item *status_item; + int slot; + int ret = 0; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return 0; + + // Enable user quota only if we have enabled qgroup. + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) + goto out; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + /* default this to quota off, in case no status key is found */ + fs_info->usrquota_flags = 0; + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_STATUS_KEY; + key.offset = 0; + ret = btrfs_search_slot_for_read(usrquota_root, &key, path, 1, 0); + if (ret) { + // Disable user quota but don't fail the mount process. + ret = 0; + goto out; + } + + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + + if (found_key.type != BTRFS_USRQUOTA_STATUS_KEY) + goto out; + + status_item = btrfs_item_ptr(leaf, slot, + struct btrfs_usrquota_status_item); + + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + btrfs_usrquota_status_version(leaf, status_item) != + BTRFS_USRQUOTA_STATUS_VERSION) { + btrfs_err(fs_info, + "syno user quota v1 found bad %llu version, quota disabled", + btrfs_usrquota_status_version(leaf, status_item)); + goto out; + } + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags) && + btrfs_usrquota_status_version(leaf, status_item) != + BTRFS_USRQUOTA_V2_STATUS_VERSION) { + btrfs_err(fs_info, + "syno user quota v2 found bad %llu version, quota disabled", + btrfs_usrquota_status_version(leaf, status_item)); + goto out; + } + + if (btrfs_usrquota_status_generation(leaf, status_item) != fs_info->generation) { + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + btrfs_err(fs_info, + "user quota generation mismatch, marked as inconsistent"); + } + + fs_info->usrquota_flags |= btrfs_usrquota_status_flags(leaf, status_item); + btrfs_release_path(path); + + ret = btrfs_read_usrquota_compat_config(fs_info); + if (ret) + goto out; + + ret = usrquota_subtree_load_all(fs_info); +out: + if (ret) + fs_info->usrquota_flags &= ~BTRFS_USRQUOTA_STATUS_FLAG_ON; + + if (!(fs_info->usrquota_flags & BTRFS_USRQUOTA_STATUS_FLAG_ON)) { + clear_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags); + btrfs_err(fs_info, "usrquota disabled due to faield to load tree\n"); + } + + btrfs_free_path(path); + return ret; +} + +/* + * Called in close_ctree() when user quota is still enabled. This verifies we don't + * leak some reserved space. + * + * Return false if no reserved space is left. + * Return true if some reserved space is leaked. + */ +bool btrfs_check_usrquota_leak(struct btrfs_fs_info *fs_info) +{ + struct rb_node *node; + struct btrfs_usrquota *usrquota; + bool ret = false; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return ret; + /* + * Since we're unmounting, there is no race and no need to grab usrquota + * lock. And here we don't go post-order to provide a more user + * friendly sorted result. + */ + for (node = rb_first(&fs_info->usrquota_tree); node; node = rb_next(node)) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + if (usrquota->uq_reserved) { + ret = true; + btrfs_warn(fs_info, "user quota %llu:%llu has unreleased space = %llu", + usrquota->uq_objectid, usrquota->uq_uid, usrquota->uq_reserved); + } + } + return ret; +} + +void btrfs_free_usrquota_config(struct btrfs_fs_info *fs_info) +{ + struct rb_node *node; + struct btrfs_usrquota *usrquota; + + while ((node = rb_first(&fs_info->usrquota_tree))) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + del_usrquota_rb(fs_info, usrquota); + } +} + +static int update_usrquota_root_item(struct btrfs_trans_handle *trans, + struct btrfs_path *path, + u64 objectid, int info_item_diff, int limit_item_diff) +{ + struct btrfs_key key; + struct extent_buffer *leaf = NULL; + struct btrfs_usrquota_root_item *usrquota_root = NULL; + u64 info_item_cnt; + u64 limit_item_cnt; + int ret; + + key.objectid = objectid; + key.type = BTRFS_USRQUOTA_ROOT_KEY; + key.offset = 0; + ret = btrfs_insert_empty_item(trans, trans->fs_info->usrquota_root, path, &key, + sizeof(struct btrfs_usrquota_root_item)); + if (ret && ret != -EEXIST) + goto out; + + leaf = path->nodes[0]; + usrquota_root = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_usrquota_root_item); + if (ret == -EEXIST) { + info_item_cnt = btrfs_usrquota_root_info_item_cnt(leaf, usrquota_root); + limit_item_cnt = btrfs_usrquota_root_limit_item_cnt(leaf, usrquota_root); + info_item_cnt += info_item_diff; + limit_item_cnt += limit_item_diff; + } else { + info_item_cnt = info_item_diff; + limit_item_cnt = limit_item_diff; + } + + if (info_item_cnt > (1ULL << 63) || limit_item_cnt > (1ULL << 63)) { + WARN_ON(1); + ret = -ERANGE; + goto out; + } + + btrfs_set_usrquota_root_info_item_cnt(leaf, usrquota_root, info_item_cnt); + btrfs_set_usrquota_root_limit_item_cnt(leaf, usrquota_root, limit_item_cnt); + btrfs_mark_buffer_dirty(leaf); + ret = 0; +out: + btrfs_release_path(path); + return ret; +} + +static int remove_usrquota_item(struct btrfs_trans_handle *trans, + u64 rootid, u64 uid, int type) +{ + int ret = 0; + struct btrfs_root *usrquota_root = trans->fs_info->usrquota_root; + struct btrfs_path *path; + struct btrfs_key key; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = rootid; + key.offset = uid; + key.type = type; + ret = btrfs_search_slot(trans, usrquota_root, &key, path, -1, 1); + if (ret) { + ret = 0; + goto out; + } + + ret = btrfs_del_item(trans, usrquota_root, path); + if (ret) { + btrfs_err(trans->fs_info, "failed to delete user quota item, rootid=%llu, uid=%llu\n", rootid, uid); + goto out; + } + btrfs_release_path(path); + + if (BTRFS_USRQUOTA_INFO_KEY == type) + ret = update_usrquota_root_item(trans, path, rootid, -1, 0); + else if (BTRFS_USRQUOTA_LIMIT_KEY == type) + ret = update_usrquota_root_item(trans, path, rootid, 0, -1); + if (ret) { + btrfs_err(trans->fs_info, "failed to dec user quota item cnt, rootid=%llu, uid=%llu\n", rootid, uid); + goto out; + } +out: + btrfs_free_path(path); + return ret; +} + +static int update_usrquota_limit_item(struct btrfs_trans_handle *trans, + u64 objectid, u64 uid, u64 rfer_soft, u64 rfer_hard) +{ + struct btrfs_root *usrquota_root = trans->fs_info->usrquota_root; + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_usrquota_limit_item *usrquota_limit; + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = objectid; + key.type = BTRFS_USRQUOTA_LIMIT_KEY; + key.offset = uid; + ret = btrfs_insert_empty_item(trans, usrquota_root, path, &key, + sizeof(struct btrfs_usrquota_limit_item)); + if (ret && ret != -EEXIST) + goto out; + + leaf = path->nodes[0]; + usrquota_limit = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_usrquota_limit_item); + btrfs_set_usrquota_limit_rfer_soft(leaf, usrquota_limit, rfer_soft); + btrfs_set_usrquota_limit_rfer_hard(leaf, usrquota_limit, rfer_hard); + btrfs_mark_buffer_dirty(leaf); + + if (ret == 0) { + btrfs_release_path(path); + ret = update_usrquota_root_item(trans, path, objectid, 0, 1); + } else // ret == -EEXIST + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +static int update_usrquota_info_item(struct btrfs_trans_handle *trans, + u64 objectid, u64 uid, u64 rfer_used) +{ + struct btrfs_root *usrquota_root = trans->fs_info->usrquota_root; + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_usrquota_info_item *usrquota_info; + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = objectid; + key.type = BTRFS_USRQUOTA_INFO_KEY; + key.offset = uid; + ret = btrfs_insert_empty_item(trans, usrquota_root, path, &key, + sizeof(struct btrfs_usrquota_info_item)); + if (ret && ret != -EEXIST) + goto out; + + leaf = path->nodes[0]; + usrquota_info = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_usrquota_info_item); + btrfs_set_usrquota_info_rfer_used(leaf, usrquota_info, rfer_used); + btrfs_set_usrquota_info_generation(leaf, usrquota_info, trans->transid); + btrfs_mark_buffer_dirty(leaf); + + if (ret == 0) { + btrfs_release_path(path); + ret = update_usrquota_root_item(trans, path, objectid, 1, 0); + } else // ret == -EEXIST + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +static int update_usrquota_status_item(struct btrfs_trans_handle *trans) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->usrquota_root; + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_usrquota_status_item *ptr; + int ret; + int slot; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_STATUS_KEY; + key.offset = 0; + ret = btrfs_search_slot(trans, root, &key, path, 0, 1); + if (ret) { + if (ret > 0) + ret = -ENOENT; + goto out; + } + + leaf = path->nodes[0]; + slot = path->slots[0]; + ptr = btrfs_item_ptr(leaf, slot, struct btrfs_usrquota_status_item); + btrfs_set_usrquota_status_flags(leaf, ptr, fs_info->usrquota_flags); + btrfs_set_usrquota_status_generation(leaf, ptr, trans->transid); + btrfs_mark_buffer_dirty(leaf); + +out: + btrfs_free_path(path); + return ret; +} + +static int insert_usrquota_compat_item(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, struct btrfs_root *root) +{ + struct btrfs_path *path = NULL; + struct btrfs_usrquota_compat_item *ptr; + struct extent_buffer *leaf; + struct btrfs_key key; + int ret = 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_COMPAT_KEY; + key.offset = 0; + ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*ptr)); + if (ret) + goto out; + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_usrquota_compat_item); + btrfs_set_usrquota_compat_generation(leaf, ptr, trans->transid); + btrfs_set_usrquota_compat_flags(leaf, ptr, fs_info->usrquota_compat_flags); + btrfs_mark_buffer_dirty(leaf); + +out: + btrfs_free_path(path); + return ret; +} + +static int update_usrquota_compat_item(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, struct btrfs_root *root) +{ + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *leaf; + struct btrfs_usrquota_compat_item *ptr; + int ret; + int slot; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_COMPAT_KEY; + key.offset = 0; + ret = btrfs_search_slot(trans, root, &key, path, 0, 1); + if (ret) { + if (ret > 0) { + btrfs_release_path(path); + ret = insert_usrquota_compat_item(trans, fs_info, root); + } + goto out; + } + + leaf = path->nodes[0]; + slot = path->slots[0]; + ptr = btrfs_item_ptr(leaf, slot, struct btrfs_usrquota_compat_item); + btrfs_set_usrquota_compat_generation(leaf, ptr, trans->transid); + btrfs_set_usrquota_compat_flags(leaf, ptr, fs_info->usrquota_compat_flags); + btrfs_mark_buffer_dirty(leaf); + +out: + btrfs_free_path(path); + return ret; +} + +static int btrfs_clean_usrquota_tree(struct btrfs_trans_handle *trans, + struct btrfs_root *root) +{ + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *leaf; + int ret; + int nr = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + path->leave_spinning = 1; + key.objectid = 0; + key.offset = 0; + key.type = 0; + + while (1) { + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; + leaf = path->nodes[0]; + nr = btrfs_header_nritems(leaf); + if (!nr) + break; + path->slots[0] = 0; + ret = btrfs_del_items(trans, root, path, 0, nr); + if (ret) + goto out; + + btrfs_release_path(path); + } + ret = 0; +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_usrquota_enable(struct btrfs_fs_info *fs_info, u64 cmd) +{ + struct btrfs_root *usrquota_root; + struct btrfs_path *path = NULL; + struct btrfs_usrquota_status_item *ptr; + struct extent_buffer *leaf; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_key key; + int ret = 0; + + // Default using v2 quota. + if (cmd == BTRFS_USRQUOTA_CTL_ENABLE) + cmd = BTRFS_USRQUOTA_V2_CTL_ENABLE; + + if (btrfs_test_opt(fs_info, NO_QUOTA_TREE)) { + btrfs_info(fs_info, "Can't enable usrquota with mount_opt no_quota_tree"); + return -EINVAL; + } + + /* + * Protected by fs_info->subvol_sem, so qgroup will not do disable + * before we finish user quota enable. + */ + if (!test_bit(BTRFS_FS_SYNO_QUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_QUOTA_V2_ENABLED, &fs_info->flags)) { + btrfs_warn(fs_info, + "Should enable qgroup before enable user quota."); + return -EINVAL; + } + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (fs_info->usrquota_root) + goto out; + mutex_unlock(&fs_info->usrquota_ioctl_lock); + + trans = btrfs_start_transaction(fs_info->tree_root, 2); + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + if (fs_info->usrquota_root) + goto out; + + if (cmd == BTRFS_USRQUOTA_V1_CTL_ENABLE) + usrquota_root = btrfs_create_tree(trans, BTRFS_USRQUOTA_TREE_OBJECTID); + else + usrquota_root = btrfs_create_tree(trans, BTRFS_SYNO_USRQUOTA_V2_TREE_OBJECTID); + if (IS_ERR(usrquota_root)) { + ret = PTR_ERR(usrquota_root); + btrfs_abort_transaction(trans, ret); + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + btrfs_abort_transaction(trans, ret); + goto out_free_root; + } + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_STATUS_KEY; + key.offset = 0; + + ret = btrfs_insert_empty_item(trans, usrquota_root, path, &key, sizeof(*ptr)); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out_free_root; + } + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_usrquota_status_item); + btrfs_set_usrquota_status_generation(leaf, ptr, trans->transid); + if (cmd == BTRFS_USRQUOTA_V1_CTL_ENABLE) + btrfs_set_usrquota_status_version(leaf, ptr, BTRFS_USRQUOTA_STATUS_VERSION); + else + btrfs_set_usrquota_status_version(leaf, ptr, BTRFS_USRQUOTA_V2_STATUS_VERSION); + fs_info->usrquota_flags = BTRFS_USRQUOTA_STATUS_FLAG_ON | + BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + btrfs_set_usrquota_status_flags(leaf, ptr, fs_info->usrquota_flags); + btrfs_mark_buffer_dirty(leaf); + btrfs_release_path(path); + + if (cmd == BTRFS_USRQUOTA_V1_CTL_ENABLE) { + fs_info->usrquota_compat_flags = BTRFS_USRQUOTA_COMPAT_FLAG; + ret = insert_usrquota_compat_item(trans, fs_info, usrquota_root); + if (ret) { + fs_info->usrquota_compat_flags = 0; + btrfs_abort_transaction(trans, ret); + goto out_free_root; + } + } + + fs_info->usrquota_root = usrquota_root; + + ret = usrquota_subtree_load_all(fs_info); + if (ret) { + btrfs_err(fs_info, "failed to init usrquota subtree during enable usrquota"); + btrfs_abort_transaction(trans, ret); + goto out_free_root; + } + + ret = btrfs_commit_transaction(trans); + trans = NULL; + if (ret) + goto out_free_root; + + /* + * Set quota enabled flag after committing the transaction, to avoid + * deadlocks on fs_info->usrquota_ioctl_lock with concurrent snapshot + * creation. + */ + down_write(&fs_info->inflight_reserve_lock); + spin_lock(&fs_info->usrquota_lock); + fs_info->usrquota_root = usrquota_root; + if (cmd == BTRFS_USRQUOTA_V1_CTL_ENABLE) + set_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags); + else + set_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags); + spin_unlock(&fs_info->usrquota_lock); + up_write(&fs_info->inflight_reserve_lock); + +out_free_root: + if (ret) { + fs_info->usrquota_root = NULL; + btrfs_put_root(usrquota_root); + } +out: + btrfs_free_path(path); + mutex_unlock(&fs_info->usrquota_ioctl_lock); + if (ret && trans) + btrfs_end_transaction(trans); + else if (trans) + ret = btrfs_end_transaction(trans); + return ret; +} + +int btrfs_usrquota_disable(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *usrquota_root; + struct btrfs_trans_handle *trans = NULL; + int ret = 0; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!fs_info->usrquota_root) + goto out; + mutex_unlock(&fs_info->usrquota_ioctl_lock); + + trans = btrfs_start_transaction(fs_info->tree_root, 1); + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + if (!fs_info->usrquota_root) + goto out; + + clear_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags); + btrfs_qgroup_wait_for_completion(fs_info, false); + spin_lock(&fs_info->usrquota_lock); + usrquota_root = fs_info->usrquota_root; + fs_info->usrquota_root = NULL; + fs_info->usrquota_flags &= ~BTRFS_USRQUOTA_STATUS_FLAG_ON; + spin_unlock(&fs_info->usrquota_lock); + + btrfs_free_usrquota_config(fs_info); + + ret = btrfs_clean_usrquota_tree(trans, usrquota_root); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } + + ret = btrfs_del_root(trans, &usrquota_root->root_key); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } + + list_del(&usrquota_root->dirty_list); + + btrfs_tree_lock(usrquota_root->node); + btrfs_clean_tree_block(usrquota_root->node); + btrfs_tree_unlock(usrquota_root->node); + btrfs_free_tree_block(trans, usrquota_root, usrquota_root->node, 0, 1); + + btrfs_put_root(usrquota_root); + +out: + mutex_unlock(&fs_info->usrquota_ioctl_lock); + if (ret && trans) + btrfs_end_transaction(trans); + else if (trans) + ret = btrfs_end_transaction(trans); + + return ret; +} + +int btrfs_usrquota_unload(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *usrquota_root; + struct btrfs_trans_handle *trans = NULL; + int ret = 0; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!fs_info->usrquota_root) + goto out; + mutex_unlock(&fs_info->usrquota_ioctl_lock); + + trans = btrfs_start_transaction(fs_info->tree_root, 1); + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + + if (!fs_info->usrquota_root) + goto out; + + clear_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags); + clear_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags); + btrfs_qgroup_wait_for_completion(fs_info, false); + spin_lock(&fs_info->usrquota_lock); + usrquota_root = fs_info->usrquota_root; + fs_info->usrquota_root = NULL; + fs_info->usrquota_flags &= ~BTRFS_USRQUOTA_STATUS_FLAG_ON; + spin_unlock(&fs_info->usrquota_lock); + + btrfs_free_usrquota_config(fs_info); + + btrfs_commit_transaction(trans); + trans = NULL; + + list_del(&usrquota_root->dirty_list); + btrfs_put_root(usrquota_root); + +out: + mutex_unlock(&fs_info->usrquota_ioctl_lock); + if (ret && trans) + btrfs_end_transaction(trans); + else if (trans) + ret = btrfs_end_transaction(trans); + + return ret; +} + +int btrfs_usrquota_remove_v1(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *root; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key location; + int ret = 0; + int nr; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + // Read old user quota root. + location.objectid = BTRFS_USRQUOTA_TREE_OBJECTID; + location.type = BTRFS_ROOT_ITEM_KEY; + location.offset = 0; + + root = btrfs_read_tree_root(tree_root, &location); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); + + location.objectid = 0; + location.offset = 0; + location.type = 0; + + while (1) { + trans = btrfs_start_transaction(tree_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto free_root; + } + + ret = btrfs_search_slot(trans, root, &location, path, -1, 1); + if (ret < 0) + goto free_root; + nr = btrfs_header_nritems(path->nodes[0]); + if (!nr) + break; + path->slots[0] = 0; + ret = btrfs_del_items(trans, root, path, 0, nr); + if (ret) + goto free_root; + + btrfs_release_path(path); + btrfs_end_transaction_throttle(trans); + trans = NULL; + cond_resched(); + } + btrfs_release_path(path); + + // Remove root item from root tree. + ret = btrfs_del_root(trans, &root->root_key); + +free_root: + btrfs_release_path(path); + list_del(&root->dirty_list); + btrfs_tree_lock(root->node); + btrfs_clean_tree_block(root->node); + btrfs_tree_unlock(root->node); + btrfs_free_tree_block(trans, root, root->node, 0, 1); + + free_extent_buffer(root->node); + free_extent_buffer(root->commit_root); + kfree(root); + + if (trans) { + if (!ret) + ret = btrfs_commit_transaction(trans); + else + btrfs_end_transaction(trans); + } +out: + btrfs_free_path(path); + return ret; +} + +/* + * This function should protected by usrquota_lock + */ +static void usrquota_dirty(struct btrfs_fs_info *fs_info, + struct btrfs_usrquota *usrquota) +{ + if (list_empty(&usrquota->uq_dirty)) + list_add(&usrquota->uq_dirty, &fs_info->dirty_usrquota); +} + +int btrfs_usrquota_limit(struct btrfs_trans_handle *trans, + u64 objectid, u64 uid, u64 rfer_soft, u64 rfer_hard) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_usrquota *usrquota; + kuid_t tmp_uid; + u64 kernel_uid; + int ret = 0; +#ifdef MY_ABC_HERE + struct btrfs_root *root = trans->root; + bool need_check = false; +#endif /* MY_ABC_HERE */ + + tmp_uid = make_kuid(current_user_ns(), (uid_t)uid); + if (!uid_valid(tmp_uid)) + return -EINVAL; + kernel_uid = __kuid_val(tmp_uid); + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!fs_info->usrquota_root) { + ret = -ESRCH; + goto out; + } + + spin_lock(&fs_info->usrquota_lock); + usrquota = add_usrquota_rb(fs_info, objectid, kernel_uid); + if (IS_ERR(usrquota)) { + spin_unlock(&fs_info->usrquota_lock); + ret = PTR_ERR(usrquota); + goto out; + } +#ifdef MY_ABC_HERE + if ((rfer_soft || rfer_hard) && !btrfs_root_has_usrquota_limit(root)) + btrfs_root_set_has_usrquota_limit(root, true); + // When update limit to zero, we should re-check quota limit. + else if (!rfer_soft && !rfer_hard && + (usrquota->uq_rfer_soft || usrquota->uq_rfer_hard)) + need_check = true; +#endif /* MY_ABC_HERE */ + usrquota->uq_rfer_soft = rfer_soft; + usrquota->uq_rfer_hard = rfer_hard; + spin_unlock(&fs_info->usrquota_lock); + + ret = update_usrquota_limit_item(trans, objectid, kernel_uid, rfer_soft, rfer_hard); + if (ret) { + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + btrfs_err(fs_info, "failed to update limit item"); + goto out; + } + +#ifdef MY_ABC_HERE + if (need_check) + btrfs_check_usrquota_limit(root); +#endif /* MY_ABC_HERE */ +out: + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +int btrfs_usrquota_clean(struct btrfs_trans_handle *trans, u64 uid) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_usrquota *usrquota; + int ret = 0; + kuid_t tmp_uid; + u64 kernel_uid; + u64 objectid = 0; + + tmp_uid = make_kuid(current_user_ns(), (uid_t)uid); + if (!uid_valid(tmp_uid)) + return -EINVAL; + kernel_uid = __kuid_val(tmp_uid); + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + ret = -ESRCH; + goto out; + } + + while (1) { + spin_lock(&fs_info->usrquota_lock); + objectid = find_next_valid_objectid(fs_info, objectid); + if (!objectid) { + spin_unlock(&fs_info->usrquota_lock); + break; + } + usrquota = find_usrquota_rb(fs_info, objectid, kernel_uid); + if (usrquota) { + usrquota->uq_rfer_soft = 0; + usrquota->uq_rfer_hard = 0; + spin_unlock(&fs_info->usrquota_lock); + ret = remove_usrquota_item(trans, objectid, kernel_uid, BTRFS_USRQUOTA_LIMIT_KEY); + if (ret) { + btrfs_err(fs_info, "failed to remove limit item"); + break; + } + } else { + spin_unlock(&fs_info->usrquota_lock); + } + objectid++; + } +out: + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +/* + * Use after inode_add_bytes() / inode_sub_bytes(), so we are always in a transaction + * and our accounting will be committed in btrfs_run_usrquota(). + */ +int btrfs_usrquota_syno_accounting(struct btrfs_inode *b_inode, + u64 add_bytes, u64 del_bytes, enum syno_quota_account_type type) +{ + struct btrfs_usrquota *usrquota; + struct btrfs_root *root = b_inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + struct inode *inode = &b_inode->vfs_inode; + u64 uid; + u64 ref_root = root->root_key.objectid; + u64 ino = b_inode->location.objectid; + int ret = 0; + + if (!is_fstree(ref_root)) + return -EINVAL; + + if (add_bytes == del_bytes && type != UPDATE_QUOTA_FREE_RESERVED) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return 0; + + if (btrfs_root_disable_quota(root)) + return 0; + + WARN_ON_ONCE(btrfs_root_readonly(root)); + spin_lock(&fs_info->usrquota_lock); + + if (!fs_info->usrquota_root) + goto out; + + // Get uid after usrquota_lock, so that uid won't changed by btrfs_usrquota_transfer(). + uid = __kuid_val(inode->i_uid); + usrquota = add_usrquota_rb(fs_info, ref_root, uid); + if (IS_ERR(usrquota)) { + ret = PTR_ERR(usrquota); + goto out; + } + + add_bytes = round_up(add_bytes, fs_info->sectorsize); + del_bytes = round_up(del_bytes, fs_info->sectorsize); + +#ifdef USRQUOTA_DEBUG + printk(KERN_INFO "btrfs_usrquota_syno_accounting debug: root = %llu, ino = %lu, " + "uid = %llu, used = %llu, type = %d, add_bytes = %llu, del_bytes = %llu", + ref_root, inode->i_ino, uid, usrquota->uq_rfer_used, type, add_bytes, del_bytes); +#endif /* USRQUOTA_DEBUG */ + + switch (type) { + case ADD_QUOTA_RESCAN: + usrquota->uq_rfer_used += add_bytes; + break; + case UPDATE_QUOTA_FREE_RESERVED: + usrquota_free_reserve(fs_info, usrquota, b_inode, add_bytes); + /* fall through */ + case UPDATE_QUOTA: + if (btrfs_quota_rescan_check(root, ino)) { + usrquota->uq_rfer_used += add_bytes; + + if (usrquota->uq_rfer_used < del_bytes) { + if (!root->invalid_quota) + WARN_ONCE(1, "user quota %llu:%llu ref underflow, " + "have %llu to free %llu", ref_root, uid, + usrquota->uq_rfer_used, del_bytes); + usrquota->uq_rfer_used = 0; + usrquota->need_rescan = true; + } else + usrquota->uq_rfer_used -= del_bytes; + } + break; + } + + usrquota_dirty(fs_info, usrquota); + +out: + spin_unlock(&fs_info->usrquota_lock); + return ret; +} + +// Similar to btrfs_usrquota_syno_accounting(). +int btrfs_usrquota_syno_v1_accounting(struct btrfs_trans_handle *trans, + struct btrfs_quota_account_rec *record) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_usrquota *usrquota; + struct inode *inode = record->inode; + struct btrfs_inode *binode; + u64 ref_root = record->ref_root; + u64 num_bytes = record->num_bytes; + u64 reserved = record->reserved; + u64 uid = record->uid; + int sign = record->sign; + int ret = 0; + bool fast_chown; + + if (!is_fstree(ref_root)) + return -EINVAL; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags)) + return 0; + + spin_lock(&fs_info->usrquota_lock); + + if (!fs_info->usrquota_root) + goto out; + + if (inode) + uid = __kuid_val(inode->i_uid); + fast_chown = btrfs_usrquota_fast_chown_enable(inode); + + usrquota = add_usrquota_rb(fs_info, ref_root, uid); + if (IS_ERR(usrquota)) { + ret = PTR_ERR(usrquota); + goto out; + } + + num_bytes = round_up(num_bytes, fs_info->sectorsize); + reserved = round_up(reserved, fs_info->sectorsize); + + // Update user quota. + if (unlikely(sign < 0 && usrquota->uq_rfer_used < num_bytes)) { + /*WARN_ONCE(1, "user quota root %llu uid %llu ref underflow, " + "have %llu to free %llu", ref_root, uid, + usrquota->uq_rfer_used, num_bytes);*/ + usrquota->uq_rfer_used = 0; + } else + usrquota->uq_rfer_used += sign * num_bytes; + + // Update user quota reserve. + if (unlikely(usrquota->uq_reserved < reserved)) { + WARN_ONCE(1, "user quota root %llu uid %llu reserved space underflow, " + "have %llu to free %llu", ref_root, uid, + usrquota->uq_reserved, reserved); + usrquota->uq_reserved = 0; + } else + usrquota->uq_reserved -= reserved; + + // Update in-memory inode's quota for fast chown. + if (fast_chown) { + binode = BTRFS_I(inode); + if (unlikely(binode->uq_reserved < reserved)) { + WARN_ONCE(1, "inode %llu:%lu uq_reserved underflow, " + "have %llu to free %llu", ref_root, inode->i_ino, + binode->uq_reserved, reserved); + binode->uq_reserved = 0; + } else + binode->uq_reserved -= reserved; + + + if (unlikely(sign < 0 && (binode->uq_rfer_used < num_bytes))) { + /*WARN_ONCE(1, "inode %llu:%lu uq ref underflow, " + "have %llu to free %llu", ref_root, inode->i_ino, + binode->uq_rfer_used, num_bytes);*/ + binode->uq_rfer_used = 0; + } else + binode->uq_rfer_used += sign * num_bytes; + } + + usrquota_dirty(fs_info, usrquota); +out: + spin_unlock(&fs_info->usrquota_lock); + if (!ret && fast_chown) { + struct btrfs_block_rsv *rsv = trans->block_rsv; + if (test_bit(BTRFS_INODE_USRQUOTA_META_RESERVED, &BTRFS_I(inode)->runtime_flags)) { + trans->block_rsv = &BTRFS_I(inode)->block_rsv; + } else { + trans->block_rsv = NULL; + } + ret = btrfs_update_inode_fallback(trans, BTRFS_I(inode)->root, inode); + trans->block_rsv = rsv; + if (ret) + btrfs_abort_transaction(trans, ret); + } + + return ret; +} + +/* + * Similar to btrfs_usrquota_syno_accounting(), but used only in rescan, where + * we don't have in-memory inode. + */ +int btrfs_usrquota_syno_accounting_rescan(struct btrfs_root *root, u64 uid, u64 num_bytes) +{ + struct btrfs_usrquota *usrquota; + struct btrfs_fs_info *fs_info = root->fs_info; + u64 subvol_id = root->root_key.objectid; + int ret = 0; + + if (num_bytes == 0) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return 0; + + usrquota_ro_subvol_check(fs_info, root); + spin_lock(&fs_info->usrquota_lock); + + if (!fs_info->usrquota_root) + goto out; + + num_bytes = round_up(num_bytes, fs_info->sectorsize); + usrquota = add_usrquota_rb(fs_info, subvol_id, uid); + if (IS_ERR(usrquota)) { + ret = PTR_ERR(usrquota); + goto out; + } + + usrquota->uq_rfer_used += num_bytes; + usrquota_dirty(fs_info, usrquota); + +out: + spin_unlock(&fs_info->usrquota_lock); + return ret; +} + +int btrfs_reset_usrquota_status(struct btrfs_trans_handle *trans) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *usrquota_root = fs_info->usrquota_root; + struct btrfs_path *path = NULL; + struct btrfs_usrquota_status_item *ptr; + struct extent_buffer *leaf; + struct btrfs_key key; + int ret; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!fs_info->usrquota_root) { + ret = -ENOENT; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_STATUS_KEY; + key.offset = 0; + + ret = btrfs_search_slot(trans, usrquota_root, &key, path, 0, 1); + if (ret) + goto out; + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_usrquota_status_item); + fs_info->usrquota_flags &= ~BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + btrfs_set_usrquota_status_flags(leaf, ptr, fs_info->usrquota_flags); + btrfs_set_usrquota_status_generation(leaf, ptr, trans->transid); + btrfs_set_usrquota_status_version(leaf, ptr, BTRFS_USRQUOTA_V2_STATUS_VERSION); + btrfs_mark_buffer_dirty(leaf); + +out: + btrfs_free_path(path); + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +int btrfs_syno_usrquota_transfer_limit(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_root *old_root = NULL; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf; + struct btrfs_usrquota_limit_item *ptr; + struct btrfs_usrquota *usrquota; + u64 subvol_id = 0; + int ret = 0; + int slot; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!fs_info->usrquota_root) { + ret = -ESRCH; + goto out; + } + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + ret = -ESRCH; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + path->reada = READA_FORWARD_ALWAYS; + + key.objectid = BTRFS_USRQUOTA_TREE_OBJECTID; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = 0; + old_root = btrfs_read_tree_root(fs_info->tree_root, &key); + if (IS_ERR(old_root)) { + ret = PTR_ERR(old_root); + old_root = NULL; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_USRQUOTA_LIMIT_KEY; + key.offset = 0; +again: + ret = btrfs_search_slot_for_read(old_root, &key, path, 1, 0); + if (ret) + goto out; + + while (1) { + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + + // We may have many info items before us, jump to the limit item. + if (found_key.type < BTRFS_USRQUOTA_LIMIT_KEY) { + btrfs_release_path(path); + key.objectid = found_key.objectid; + key.type = BTRFS_USRQUOTA_LIMIT_KEY; + key.offset = 0; + goto again; + } + + // BTRFS_USRQUOTA_COMPAT_KEY? + if (found_key.type > BTRFS_USRQUOTA_LIMIT_KEY) { + btrfs_release_path(path); + key.objectid = found_key.objectid + 1; + key.type = BTRFS_USRQUOTA_LIMIT_KEY; + key.offset = 0; + goto again; + } + + ptr = btrfs_item_ptr(leaf, slot, + struct btrfs_usrquota_limit_item); + if (subvol_id != found_key.objectid) { + if (subvol_id) + usrquota_subtree_unload(fs_info, subvol_id); + subvol_id = found_key.objectid; + ret = usrquota_subtree_load(fs_info, subvol_id); + if (ret) { + btrfs_release_path(path); + key.objectid = subvol_id + 1; + key.type = BTRFS_USRQUOTA_LIMIT_KEY; + key.offset = 0; + subvol_id = 0; + goto again; + } + } + + spin_lock(&fs_info->usrquota_lock); + usrquota = add_usrquota_rb(fs_info, + found_key.objectid, found_key.offset); + if (!IS_ERR(usrquota) && usrquota->uq_rfer_soft == 0 + && usrquota->uq_rfer_hard == 0) { + usrquota->uq_rfer_soft = btrfs_usrquota_limit_rfer_soft(leaf, ptr); + usrquota->uq_rfer_hard = btrfs_usrquota_limit_rfer_hard(leaf, ptr); + usrquota->update_limit = true; + usrquota_dirty(fs_info, usrquota); + } + spin_unlock(&fs_info->usrquota_lock); + + ret = btrfs_next_item(old_root, path); + if (ret) + break; + } + +out: + if (subvol_id) + usrquota_subtree_unload(fs_info, subvol_id); + btrfs_free_path(path); + if (old_root) { + free_extent_buffer(old_root->node); + free_extent_buffer(old_root->commit_root); + kfree(old_root); + } + mutex_unlock(&fs_info->usrquota_ioctl_lock); + + if (ret > 0) + ret = 0; + return ret; +} + +void btrfs_usrquota_zero_tracking(struct btrfs_fs_info *fs_info, u64 subvol_id) +{ + struct btrfs_usrquota *usrquota; + struct rb_node *node; + int ret; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return; + + /* + * We may have no user quota record in volume migration case. + * No need to print error. + */ + ret = usrquota_subtree_load(fs_info, subvol_id); + if (ret) + return; + + spin_lock(&fs_info->usrquota_lock); + if (!fs_info->usrquota_root) { + spin_unlock(&fs_info->usrquota_lock); + return; + } + + node = find_usrquota_first_rb(fs_info, subvol_id); + while (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + node = rb_next(node); + if (usrquota->uq_objectid > subvol_id) + break; + usrquota->uq_rfer_used = 0; + usrquota->uq_generation = 0; + usrquota_dirty(fs_info, usrquota); + } + spin_unlock(&fs_info->usrquota_lock); + + usrquota_subtree_unload(fs_info, subvol_id); +} + +int btrfs_usrquota_v1_transfer(struct inode *inode, kuid_t new_uid) +{ + struct btrfs_usrquota *usrquota_orig; + struct btrfs_usrquota *usrquota_dest; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_fs_info *fs_info = root->fs_info; + u64 rootid = root->root_key.objectid; + + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_file_extent_item *fi; + struct btrfs_trans_handle *trans; + u64 disko; + int ret = 0; + int no_quota = 0; + u64 num_bytes = 0; + int type; + u64 datal, diskl; + struct btrfs_inode *binode = BTRFS_I(inode); + struct quota_check qc; + u64 inflight_num_bytes = 0; + u64 uid; + + if (btrfs_usrquota_fast_chown_enable(inode)) + goto transfer; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + // flush delayed write and wait for it + btrfs_wait_ordered_range(inode, 0, (u64)-1); + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto search_end; + } + + ret = btrfs_run_delayed_refs(trans, BTRFS_USRQUOTA_DELAYED_REF_SCAN); + if (ret) { + btrfs_end_transaction(trans); + goto search_end; + } + ret = btrfs_end_transaction(trans); + if (ret) + goto search_end; + + key.objectid = BTRFS_I(inode)->location.objectid; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = 0; + +again: + ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); + if (ret) { + if (ret == 1) /* found nothing */ + ret = 0; + goto search_end; + } + while (1) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid != key.objectid) + break; + if (found_key.type != BTRFS_EXTENT_DATA_KEY) + break; + fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); + type = btrfs_file_extent_type(leaf, fi); + if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { + disko = btrfs_file_extent_disk_bytenr(leaf, fi); + diskl = btrfs_file_extent_disk_num_bytes(leaf, fi); + datal = btrfs_file_extent_num_bytes(leaf, fi); + if (!disko) + break; + + key.offset = found_key.offset + datal; + btrfs_release_path(path); + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto search_end; + } + + qc.bytenr = disko; + qc.root_objectid = rootid; + qc.ino = inode->i_ino; + qc.offset = found_key.offset; + qc.in_run_delayed = false; + no_quota = check_root_inode_ref(trans, &qc); + ret = btrfs_end_transaction(trans); + + if (ret) + goto search_end; + if (no_quota < 0) + goto search_end; + if (!no_quota) + num_bytes += diskl; + goto again; + } + cond_resched(); + ret = btrfs_next_item(root, path); + if (ret) { + if (ret < 0) + goto search_end; + ret = 0; + break; + } + } + +search_end: + btrfs_free_path(path); + if (ret) + return ret; + +transfer: + spin_lock(&fs_info->usrquota_lock); + + if (!fs_info->usrquota_root) + goto unlock; + + if (binode->flags & BTRFS_INODE_UQ_REF_USED) + num_bytes = binode->uq_rfer_used; + inflight_num_bytes = binode->uq_reserved; + + uid = __kuid_val(inode->i_uid); + usrquota_orig = add_usrquota_rb(fs_info, rootid, uid); + if (IS_ERR(usrquota_orig)) { + ret = PTR_ERR(usrquota_orig); + goto unlock; + } + + usrquota_dest = add_usrquota_rb(fs_info, rootid, (u64)__kuid_val(new_uid)); + if (IS_ERR(usrquota_dest)) { + ret = PTR_ERR(usrquota_dest); + goto unlock; + } + + if (usrquota_dest->uq_rfer_hard && !capable(CAP_SYS_RESOURCE)) { + if (usrquota_dest->uq_rfer_used + usrquota_dest->uq_reserved + + num_bytes + inflight_num_bytes > usrquota_dest->uq_rfer_hard) { + ret = -EDQUOT; + goto unlock; + } + } + + if (unlikely(usrquota_orig->uq_rfer_used < num_bytes)) { + /*WARN_ONCE(1, "user quota chown %llu:%llu ref underflow, " + "have %llu to free %llu", rootid, uid, + usrquota_orig->uq_rfer_used, num_bytes);*/ + + usrquota_orig->uq_rfer_used = 0; + } else + usrquota_orig->uq_rfer_used -= num_bytes; + usrquota_dest->uq_rfer_used += num_bytes; + + if (unlikely(usrquota_orig->uq_reserved < inflight_num_bytes)) { + WARN_ONCE(1, "user quota chown %llu/%lu reserved underflow, " + "have %llu to free %llu", rootid, inode->i_ino, + usrquota_orig->uq_reserved, inflight_num_bytes); + + usrquota_orig->uq_reserved = 0; + } else + usrquota_orig->uq_reserved -= inflight_num_bytes; + usrquota_dest->uq_reserved += inflight_num_bytes; + + inode->i_uid = new_uid; // Do this inside of usrquota_lock. + usrquota_dirty(fs_info, usrquota_orig); + usrquota_dirty(fs_info, usrquota_dest); + +unlock: + spin_unlock(&fs_info->usrquota_lock); + return ret; +} + +// For syno quota v2. +int btrfs_usrquota_transfer(struct inode *inode, kuid_t new_uid) +{ + struct btrfs_usrquota *usrquota_from, *usrquota_to; + struct btrfs_inode *b_inode = BTRFS_I(inode); + struct btrfs_root *root = b_inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + u64 uid; + u64 ref_root = root->root_key.objectid; + u64 ino = b_inode->location.objectid; + loff_t num_bytes; + bool enforce = true; + int ret = 0; + + if (!is_fstree(ref_root)) + return 0; + + if (capable(CAP_SYS_RESOURCE)) + enforce = false; + + usrquota_ro_subvol_check(fs_info, root); + down_write(&root->rescan_lock); + spin_lock(&fs_info->usrquota_lock); + + if (!fs_info->usrquota_root) + goto out; + + uid = __kuid_val(inode->i_uid); + usrquota_from = add_usrquota_rb(fs_info, ref_root, uid); + if (IS_ERR(usrquota_from)) { + ret = PTR_ERR(usrquota_from); + goto out; + } + + usrquota_to = add_usrquota_rb(fs_info, ref_root, (u64)__kuid_val(new_uid)); + if (IS_ERR(usrquota_to)) { + ret = PTR_ERR(usrquota_to); + goto out; + } + num_bytes = inode_get_bytes(inode); + num_bytes = round_up(num_bytes, fs_info->sectorsize); + +#ifdef USRQUOTA_DEBUG + printk(KERN_INFO "btrfs_usrquota_transfer debug: root = %llu, ino = %lu, " + "uid_from = %llu, uid_to = %llu, used = %llu, num_bytes = %llu", + ref_root, inode->i_ino, uid, (u64)__kuid_val(new_uid), + usrquota_from->uq_rfer_used, num_bytes); +#endif /* USRQUOTA_DEBUG */ + + if (enforce && usrquota_to->uq_rfer_hard && !root->invalid_quota) { + if (usrquota_to->uq_rfer_used + usrquota_to->uq_reserved + + num_bytes + b_inode->uq_reserved > + usrquota_to->uq_rfer_hard) { + ret = -EDQUOT; + goto out; + } + } + + if (btrfs_quota_rescan_check(root, ino)) { + usrquota_to->uq_rfer_used += num_bytes; + if (usrquota_from->uq_rfer_used < num_bytes && !root->invalid_quota) { + WARN_ONCE(1, "user quota chown %llu:%llu ref underflow, " + "have %llu to free %llu", ref_root, uid, + usrquota_from->uq_rfer_used, num_bytes); + usrquota_from->uq_rfer_used = 0; + usrquota_to->need_rescan = true; + } else + usrquota_from->uq_rfer_used -= num_bytes; + } + + usrquota_to->uq_reserved += b_inode->uq_reserved; + if (usrquota_from->uq_reserved < b_inode->uq_reserved) { + WARN_ONCE(1, "user quota chown %llu/%llu reserved underflow, " + "have %llu to free %llu", ref_root, ino, + usrquota_from->uq_reserved, b_inode->uq_reserved); + usrquota_from->uq_reserved = 0; + } else + usrquota_from->uq_reserved -= b_inode->uq_reserved; + + usrquota_dirty(fs_info, usrquota_from); + usrquota_dirty(fs_info, usrquota_to); + inode->i_uid = new_uid; // Do this inside of usrquota_lock. + +out: + spin_unlock(&fs_info->usrquota_lock); + up_write(&root->rescan_lock); + return ret; +} + +/* + * called from commit_transaction. Writes all changed usrquota to disk. + */ +int btrfs_run_usrquota(struct btrfs_trans_handle *trans) +{ + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *subvol_root, *next; + int ret = 0; + + if (!fs_info->usrquota_root) + goto out; + + spin_lock(&fs_info->usrquota_lock); + while (!list_empty(&fs_info->dirty_usrquota)) { + struct btrfs_usrquota tmp_usrquota; + struct btrfs_usrquota *usrquota; + + usrquota = list_first_entry(&fs_info->dirty_usrquota, + struct btrfs_usrquota, uq_dirty); + list_del_init(&usrquota->uq_dirty); + + // Copy things out since we may free usrquota later. + memcpy(&tmp_usrquota, usrquota, sizeof(tmp_usrquota)); + usrquota->need_rescan = false; + usrquota->update_limit = false; + + /* + * Remove empty record. To mark tree loaded, + * we need to keep the last record in the tree. + */ + if (!usrquota->uq_rfer_hard && !usrquota->uq_rfer_soft + && !usrquota->uq_rfer_used && !usrquota->uq_reserved && usrquota->uq_uid) { + del_usrquota_rb(fs_info, usrquota); + usrquota = NULL; + spin_unlock(&fs_info->usrquota_lock); + ret = remove_usrquota_item(trans, tmp_usrquota.uq_objectid, + tmp_usrquota.uq_uid, BTRFS_USRQUOTA_INFO_KEY); + } else { + spin_unlock(&fs_info->usrquota_lock); + ret = update_usrquota_info_item(trans, tmp_usrquota.uq_objectid, + tmp_usrquota.uq_uid, tmp_usrquota.uq_rfer_used); + if ((ret || tmp_usrquota.need_rescan) && + test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + struct syno_quota_rescan_item_updater updater; + + syno_quota_rescan_item_init(&updater); + updater.flags = SYNO_QUOTA_RESCAN_NEED; + btrfs_add_update_syno_quota_rescan_item(trans, fs_info->quota_root, + tmp_usrquota.uq_objectid, &updater); + } + + if (tmp_usrquota.update_limit) { + ret = update_usrquota_limit_item(trans, tmp_usrquota.uq_objectid, tmp_usrquota.uq_uid, + tmp_usrquota.uq_rfer_soft, tmp_usrquota.uq_rfer_hard); + if (ret) + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + } + } + spin_lock(&fs_info->usrquota_lock); + } + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) || + test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_ON; + else + fs_info->usrquota_flags &= ~BTRFS_USRQUOTA_STATUS_FLAG_ON; + spin_unlock(&fs_info->usrquota_lock); + + ret = update_usrquota_status_item(trans); + if (ret) + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags)) { + ret = update_usrquota_compat_item(trans, fs_info, fs_info->usrquota_root); + if (ret) + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + } + +out: + mutex_lock(&fs_info->usrquota_ro_roots_lock); + spin_lock(&fs_info->usrquota_lock); + list_for_each_entry_safe(subvol_root, next, &fs_info->usrquota_ro_roots, usrquota_ro_root) { + if (subvol_root->usrquota_loaded_gen + USRQUOTA_RO_SUBVOL_EXIST_GEN < fs_info->generation) { + list_del_init(&subvol_root->usrquota_ro_root); + btrfs_put_root(subvol_root); + btrfs_debug(fs_info, "Unload ro sub [id:%llu] uq subtree [%llu, %llu]", + subvol_root->root_key.objectid, subvol_root->usrquota_loaded_gen, + fs_info->generation); + usrquota_subtree_unload_nolock(fs_info, subvol_root->root_key.objectid); + } + } + spin_unlock(&fs_info->usrquota_lock); + mutex_unlock(&fs_info->usrquota_ro_roots_lock); + return ret; +} + +int btrfs_usrquota_syno_reserve(struct btrfs_inode *b_inode, u64 num_bytes) +{ + if (btrfs_root_disable_quota(b_inode->root)) + return 0; + + num_bytes = round_up(num_bytes, b_inode->root->fs_info->sectorsize); + return usrquota_reserve(b_inode, num_bytes, true); +} + +/* + * Return 1 if we don't reserve user quota, but it's not an EDQUOT error. + * Caller is allowed to write. + */ +int usrquota_reserve(struct btrfs_inode *b_inode, u64 num_bytes, bool enforce) +{ + struct btrfs_usrquota *usrquota; + struct btrfs_root *root = b_inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + u64 ref_root = root->root_key.objectid; + u64 uid; + int ret = 0; + + if (!is_fstree(ref_root)) + return 0; + + if (num_bytes == 0) + return 0; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return 1; + + if (test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags) && + capable(CAP_SYS_RESOURCE)) + enforce = false; + + usrquota_ro_subvol_check(fs_info, root); + spin_lock(&fs_info->usrquota_lock); + + if (!fs_info->usrquota_root) { + ret = 1; + goto out; + } + + // Get uid after usrquota_lock, so that uid won't changed by btrfs_usrquota_transfer(). + uid = __kuid_val(b_inode->vfs_inode.i_uid); + usrquota = add_usrquota_rb(fs_info, ref_root, uid); + if (IS_ERR(usrquota)) { + ret = 1; + goto out; + } + +#ifdef USRQUOTA_DEBUG + printk(KERN_INFO "usrquota_reserve debug: root = %llu, ino = %lu, uid = %llu, used = %llu, " + "reserved = %llu, want = %llu, limit = %llu", + ref_root, b_inode->vfs_inode.i_ino, uid, usrquota->uq_rfer_used, + usrquota->uq_reserved, num_bytes, usrquota->uq_rfer_hard); +#endif /* USRQUOTA_DEBUG */ + + if (enforce && usrquota->uq_rfer_hard && !root->invalid_quota) { + if (usrquota->uq_rfer_used + usrquota->uq_reserved + num_bytes > usrquota->uq_rfer_hard) { + ret = -EDQUOT; + goto out; + } + } + usrquota->uq_reserved += num_bytes; + if (test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags) || + btrfs_usrquota_fast_chown_enable(&b_inode->vfs_inode)) + b_inode->uq_reserved += num_bytes; + +out: + spin_unlock(&fs_info->usrquota_lock); + return ret; +} + +void btrfs_usrquota_syno_free(struct btrfs_inode *b_inode, u64 num_bytes) +{ + struct btrfs_usrquota *usrquota; + struct btrfs_root *root = b_inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; + u64 ref_root = root->root_key.objectid; + u64 uid; + + if (!is_fstree(ref_root)) + return; + + if (num_bytes == 0) + return; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return; + + if (btrfs_root_disable_quota(root)) + return; + + spin_lock(&fs_info->usrquota_lock); + if (!fs_info->usrquota_root) + goto unlock; + + // Get uid after usrquota_lock, so that uid won't changed by btrfs_usrquota_transfer(). + uid = __kuid_val(b_inode->vfs_inode.i_uid); + usrquota = find_usrquota_rb(fs_info, ref_root, uid); + if (!usrquota) + goto unlock; + + num_bytes = round_up(num_bytes, fs_info->sectorsize); + usrquota_free_reserve(fs_info, usrquota, b_inode, num_bytes); + +unlock: + spin_unlock(&fs_info->usrquota_lock); + return; +} + +/* + * Calculate number of usrquota_{info/limit}_item that need to be reserved for space + * when taking snapshot. + */ +int btrfs_usrquota_calc_reserve_snap(struct btrfs_root *root, + u64 copy_limit_from, u64 *reserve_items) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf; + struct btrfs_key key; + struct btrfs_usrquota_root_item *item; + int ret = 0; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + goto unlock_ioctl; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto unlock_ioctl; + } + + key.objectid = root->root_key.objectid; + key.type = BTRFS_USRQUOTA_ROOT_KEY; + key.offset = 0; + *reserve_items = 0; + +//calc_info_items: + ret = btrfs_search_slot(NULL, fs_info->usrquota_root, &key, path, 0, 0); + if (ret < 0) + goto unlock_tree; + if (ret == 1) + goto calc_limit_items; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_usrquota_root_item); + *reserve_items += btrfs_usrquota_root_info_item_cnt(leaf, item); + +calc_limit_items: + if (copy_limit_from == 0) + goto success; + + btrfs_release_path(path); + key.objectid = copy_limit_from; + ret = btrfs_search_slot(NULL, fs_info->usrquota_root, &key, path, 0, 0); + if (ret < 0) + goto unlock_tree; + if (ret == 1) + goto success; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_usrquota_root_item); + *reserve_items += btrfs_usrquota_root_limit_item_cnt(leaf, item); + +success: + ret = 0; +unlock_tree: + btrfs_free_path(path); +unlock_ioctl: + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +int btrfs_usrquota_mksubvol(struct btrfs_trans_handle *trans, u64 objectid) +{ + int ret = 0; + struct btrfs_usrquota *usrquota; + struct btrfs_fs_info *fs_info = trans->fs_info; + + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) + return 0; + + // insert dummy node + spin_lock(&fs_info->usrquota_lock); + if (!fs_info->usrquota_root) + goto unlock; + + usrquota = add_usrquota_dummy_rb_nocheck(fs_info, objectid); + if (IS_ERR(usrquota)) { + btrfs_err(fs_info, "failed to add_usrquota_rb %ld", PTR_ERR(usrquota)); + ret = PTR_ERR(usrquota); + goto unlock; + } +unlock: + spin_unlock(&fs_info->usrquota_lock); + return ret; +} + +int btrfs_usrquota_mksnap(struct btrfs_trans_handle *trans, + u64 srcid, u64 objectid, + bool readonly, u64 copy_limit_from) +{ + int ret = 0; + int src_loaded = 0; + int copy_loaded = 0; + + struct rb_node *node; + struct btrfs_usrquota *usrquota_new; + struct btrfs_usrquota *usrquota_orig; + struct btrfs_fs_info *fs_info = trans->fs_info; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + goto out; + } + BUG_ON(!fs_info->usrquota_root); + + // create dummy node + spin_lock(&fs_info->usrquota_lock); + usrquota_new = add_usrquota_dummy_rb_nocheck(fs_info, objectid); + if (IS_ERR(usrquota_new)) { + btrfs_err(fs_info, "failed to add_usrquota_rb %ld", PTR_ERR(usrquota_new)); + ret = PTR_ERR(usrquota_new); + goto unlock; + } + spin_unlock(&fs_info->usrquota_lock); + + if (!copy_limit_from) + goto copy_info_items; + + ret = usrquota_subtree_load(fs_info, copy_limit_from); + if (ret) { + btrfs_err(fs_info, "failed to load usrquota subtree %llu", copy_limit_from); + goto out; + } + copy_loaded = 1; + spin_lock(&fs_info->usrquota_lock); + node = find_usrquota_first_rb(fs_info, copy_limit_from); + while (node) { + usrquota_orig = rb_entry(node, struct btrfs_usrquota, uq_node); + node = rb_next(node); + if (usrquota_orig->uq_objectid > copy_limit_from) + break; + if (!usrquota_orig->uq_rfer_soft && !usrquota_orig->uq_rfer_hard) + continue; + + usrquota_new = add_usrquota_rb_nocheck(fs_info, objectid, usrquota_orig->uq_uid); + if (IS_ERR(usrquota_new)) { + btrfs_err(fs_info, "failed to add_usrquota_rb %ld", PTR_ERR(usrquota_new)); + ret = PTR_ERR(usrquota_new); + goto unlock; + } + usrquota_new->uq_rfer_soft = usrquota_orig->uq_rfer_soft; + usrquota_new->uq_rfer_hard = usrquota_orig->uq_rfer_hard; + } + spin_unlock(&fs_info->usrquota_lock); + cond_resched(); + +copy_info_items: + ret = usrquota_subtree_load(fs_info, srcid); + if (ret) { + btrfs_err(fs_info, "failed to load usrquota subtree %llu", srcid); + goto out; + } + src_loaded = 1; + spin_lock(&fs_info->usrquota_lock); + node = find_usrquota_first_rb(fs_info, srcid); + while (node) { + usrquota_orig = rb_entry(node, struct btrfs_usrquota, uq_node); + node = rb_next(node); + if (usrquota_orig->uq_objectid > srcid) + break; + usrquota_new = add_usrquota_rb_nocheck(fs_info, objectid, usrquota_orig->uq_uid); + if (IS_ERR(usrquota_new)) { + btrfs_err(fs_info, "failed to add_usrquota_rb %ld", PTR_ERR(usrquota_new)); + ret = PTR_ERR(usrquota_new); + goto unlock; + } + usrquota_new->uq_rfer_used = usrquota_orig->uq_rfer_used; + usrquota_new->uq_generation = usrquota_orig->uq_generation; + } + + // add info & limit items + node = find_usrquota_first_rb(fs_info, objectid); + while (node) { + usrquota_new = rb_entry(node, struct btrfs_usrquota, uq_node); + node = rb_next(node); + if (usrquota_new->uq_objectid > objectid) + break; + if (usrquota_new->uq_rfer_soft || usrquota_new->uq_rfer_hard) { + spin_unlock(&fs_info->usrquota_lock); + ret = update_usrquota_limit_item(trans, objectid, + usrquota_new->uq_uid, + usrquota_new->uq_rfer_soft, + usrquota_new->uq_rfer_hard); + spin_lock(&fs_info->usrquota_lock); + if (ret) { + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + break; + } + } + if (usrquota_new->uq_rfer_used || usrquota_new->uq_generation) { + spin_unlock(&fs_info->usrquota_lock); + ret = update_usrquota_info_item(trans, objectid, + usrquota_new->uq_uid, + usrquota_new->uq_rfer_used); + spin_lock(&fs_info->usrquota_lock); + if (ret) { + fs_info->usrquota_flags |= BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT; + break; + } + } + } +unlock: + spin_unlock(&fs_info->usrquota_lock); +out: + if (src_loaded) + usrquota_subtree_unload(fs_info, srcid); + if (copy_loaded) + usrquota_subtree_unload(fs_info, copy_limit_from); + if (ret || readonly) + usrquota_subtree_unload(fs_info, objectid); + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +int btrfs_usrquota_delsnap(struct btrfs_trans_handle *trans, struct btrfs_root *subvol_root) +{ + int ret = 0; + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *usrquota_root = fs_info->usrquota_root; + struct btrfs_path *path = NULL; + struct btrfs_key key; + struct btrfs_key found_key; + struct extent_buffer *leaf; + u64 rootid = subvol_root->root_key.objectid; + int pending_del_nr = 0; + int pending_del_slot = 0; + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!usrquota_root) { + ret = -EINVAL; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + mutex_lock(&fs_info->usrquota_ro_roots_lock); + if (!list_empty(&subvol_root->usrquota_ro_root)) { + list_del_init(&subvol_root->usrquota_ro_root); + btrfs_put_root(subvol_root); + btrfs_debug(fs_info, "Unload ro sub [id:%llu] uq subtree [%llu, %llu]", + subvol_root->root_key.objectid, subvol_root->usrquota_loaded_gen, + fs_info->generation); + usrquota_subtree_unload(fs_info, subvol_root->root_key.objectid); + } + mutex_unlock(&fs_info->usrquota_ro_roots_lock); + usrquota_subtree_unload(fs_info, rootid); + + // copyed from btrfs_truncate_inode_items + key.objectid = rootid; + key.offset = (u64) -1; + key.type = (u8) -1; +search_again: + path->leave_spinning = 1; + ret = btrfs_search_slot(trans, usrquota_root, &key, path, -1, 1); + if (ret < 0) { + goto out; + } + if (ret > 0) { + ret = 0; + if (path->slots[0] == 0) { + btrfs_err(fs_info, "failed to search usrquota"); + goto out; + } + path->slots[0]--; + } + while (1) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + if (found_key.objectid != rootid) + break; + + if (!pending_del_nr) { + pending_del_nr = 1; + pending_del_slot = path->slots[0]; + } else { + pending_del_nr++; + pending_del_slot = path->slots[0]; + } + + if (path->slots[0] == 0) { + if (pending_del_nr) { + ret = btrfs_del_items(trans, usrquota_root, path, + pending_del_slot, + pending_del_nr); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } + pending_del_nr = 0; + } + btrfs_release_path(path); + goto search_again; + } else { + path->slots[0]--; + } + } + if (pending_del_nr) { + ret = btrfs_del_items(trans, usrquota_root, path, + pending_del_slot, pending_del_nr); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } + } +out: + btrfs_free_path(path); + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +/* + * struct btrfs_ioctl_usrquota_query_args should be initialized to zero + */ +int btrfs_usrquota_query(struct btrfs_root *root, + struct btrfs_ioctl_usrquota_query_args *uqa) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_usrquota *usrquota; + kuid_t tmp_uid; + u64 rootid = root->root_key.objectid; + u64 kernel_uid; + int ret; + + if (unlikely(root->invalid_quota)) + return -ESRCH; + + tmp_uid = make_kuid(current_user_ns(), (uid_t)uqa->uid); + if (!uid_valid(tmp_uid)) + return -EINVAL; + kernel_uid = __kuid_val(tmp_uid); + + mutex_lock(&fs_info->usrquota_ioctl_lock); + if (!test_bit(BTRFS_FS_SYNO_USRQUOTA_V1_ENABLED, &fs_info->flags) && + !test_bit(BTRFS_FS_SYNO_USRQUOTA_V2_ENABLED, &fs_info->flags)) { + ret = -ESRCH; + goto unlock; + } + + if (usrquota_subtree_load(fs_info, rootid)) { + ret = -ENOENT; + goto unlock; + } + + ret = 0; // It is normal that we have no such entry. + spin_lock(&fs_info->usrquota_lock); + usrquota = find_usrquota_rb(fs_info, rootid, kernel_uid); + if (!usrquota) + goto unload; + + uqa->rfer_used = usrquota->uq_rfer_used; + uqa->rfer_soft = usrquota->uq_rfer_soft; + uqa->rfer_hard = usrquota->uq_rfer_hard; + uqa->reserved = usrquota->uq_reserved; +unload: + spin_unlock(&fs_info->usrquota_lock); + usrquota_subtree_unload(fs_info, rootid); +unlock: + mutex_unlock(&fs_info->usrquota_ioctl_lock); + return ret; +} + +#ifdef MY_ABC_HERE +static bool check_usrquota_from_disk(struct btrfs_fs_info *fs_info, u64 rootid) +{ + int ret; + int slot; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root *usrquota_root = fs_info->usrquota_root; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_usrquota_limit_item *limit_item; + bool has_limit = false; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = rootid; + key.type = BTRFS_USRQUOTA_LIMIT_KEY; + key.offset = 0; + ret = btrfs_search_slot_for_read(usrquota_root, &key, path, 1, 0); + if (ret < 0) + goto out; + else if (ret) { + ret = 0; + goto out; + } + while (1) { + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); + if (found_key.objectid > rootid) + break; + else if (found_key.type != BTRFS_USRQUOTA_LIMIT_KEY) + goto next_item; + + limit_item = btrfs_item_ptr(leaf, slot, + struct btrfs_usrquota_limit_item); + if (btrfs_usrquota_limit_rfer_soft(leaf, limit_item) || + btrfs_usrquota_limit_rfer_hard(leaf, limit_item)) { + has_limit = true; + break; + } +next_item: + ret = btrfs_next_item(usrquota_root, path); + if (ret < 0) + goto out; + else if (ret) { + ret = 0; + break; + } + } + ret = 0; +out: + btrfs_free_path(path); + // When an error occurr, we always treat it as having quota_limt. + return (ret) ? true : has_limit; +} + +static bool check_usrquota_from_rbtree(struct rb_node *node, + u64 rootid) +{ + struct btrfs_usrquota *usrquota; + bool has_limit = false; + while (node) { + usrquota = rb_entry(node, struct btrfs_usrquota, uq_node); + if (usrquota->uq_objectid > rootid) + break; + else if (usrquota->uq_rfer_soft || usrquota->uq_rfer_hard) { + has_limit = true; + break; + } + node = rb_next(node); + } + return has_limit; +} + +void btrfs_check_usrquota_limit(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + bool has_limit = false; + struct rb_node *node; + u64 rootid = root->root_key.objectid; + + spin_lock(&fs_info->usrquota_lock); + if (!fs_info->usrquota_root) { + spin_unlock(&fs_info->usrquota_lock); + return; + } + + node = find_usrquota_first_rb(fs_info, rootid); + if (!node) { + // subtree is unloaded, read from disk. + spin_unlock(&fs_info->usrquota_lock); + has_limit = check_usrquota_from_disk(fs_info, rootid); + } else { + has_limit = check_usrquota_from_rbtree(node, rootid); + spin_unlock(&fs_info->usrquota_lock); + } + btrfs_root_set_has_usrquota_limit(root, has_limit); +} +#endif /* MY_ABC_HERE */ + diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f9ae3850526c..6610086beb56 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -31,6 +34,9 @@ #include "space-info.h" #include "block-group.h" #include "discard.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = { [BTRFS_RAID_RAID10] = { @@ -224,7 +230,11 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, struct btrfs_bio **bbio_ret, - int mirror_num, int need_raid_map); + int mirror_num, int need_raid_map +#ifdef MY_ABC_HERE + , bool false +#endif /* MY_ABC_HERE */ + ); /* * Device locking @@ -1193,6 +1203,9 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices, struct btrfs_device *device; struct btrfs_device *latest_dev = NULL; struct btrfs_device *tmp_device; +#ifdef MY_ABC_HERE + bool rbd_enabled = true; +#endif /* MY_ABC_HERE */ flags |= FMODE_EXCL; @@ -1209,6 +1222,10 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices, list_del(&device->dev_list); btrfs_free_device(device); } +#ifdef MY_ABC_HERE + if (!ret && !IsSynoRbdDeviceEnabled(device->bdev)) + rbd_enabled = false; +#endif /* MY_ABC_HERE */ } if (fs_devices->open_devices == 0) return -EINVAL; @@ -1217,6 +1234,9 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices, fs_devices->latest_bdev = latest_dev->bdev; fs_devices->total_rw_bytes = 0; fs_devices->chunk_alloc_policy = BTRFS_CHUNK_ALLOC_REGULAR; +#ifdef MY_ABC_HERE + fs_devices->rbd_enabled = rbd_enabled; +#endif /* MY_ABC_HERE */ return 0; } @@ -2058,7 +2078,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, if (IS_ERR(device)) { if (PTR_ERR(device) == -ENOENT && - strcmp(device_path, "missing") == 0) + device_path && strcmp(device_path, "missing") == 0) ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; else ret = PTR_ERR(device); @@ -3317,6 +3337,24 @@ static void reset_balance_state(struct btrfs_fs_info *fs_info) BUG_ON(!fs_info->balance_ctl); +#ifdef MY_ABC_HERE + if (!fs_info->balance_ctl->fast_key_offset) { + spin_lock(&fs_info->balance_lock); + fs_info->balance_ctl = NULL; + spin_unlock(&fs_info->balance_lock); + + kfree(bctl); + ret = del_balance_item(fs_info); + if (ret) + btrfs_handle_fs_error(fs_info, ret, NULL); + } else { + spin_lock(&fs_info->balance_lock); + fs_info->balance_ctl = NULL; + spin_unlock(&fs_info->balance_lock); + + kfree(bctl); + } +#else spin_lock(&fs_info->balance_lock); fs_info->balance_ctl = NULL; spin_unlock(&fs_info->balance_lock); @@ -3325,6 +3363,7 @@ static void reset_balance_state(struct btrfs_fs_info *fs_info) ret = del_balance_item(fs_info); if (ret) btrfs_handle_fs_error(fs_info, ret, NULL); +#endif /* MY_ABC_HERE */ } /* @@ -3596,9 +3635,76 @@ static int should_balance_chunk(struct extent_buffer *leaf, return 1; } +#ifdef MY_ABC_HERE +/* + * Balance only one block group. The ideal block group is the block group + * with minimum space usage. However, searching for the best block group + * requires one to search through the whole tree. Hence, instead of + * searching through the whole tree, we just search over first 1000 block + * groups. + */ +u64 get_bg_offset_with_free_space_bytes(struct btrfs_fs_info *fs_info) +{ + struct btrfs_block_group *block_group = NULL; + struct rb_node *node = NULL; + struct btrfs_space_info *space_info = NULL; + int visit_cnt = 0; + u64 usage = 0, min_usage = (u64)-1, result = 0; + + space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA); + if (!space_info) { + btrfs_err(fs_info, "No space info for %llu", BTRFS_BLOCK_GROUP_DATA); + return 0; + } + spin_lock(&space_info->syno_allocator.lock); + node = rb_first_cached(&space_info->syno_allocator.free_space_bytes); + + for (; node && visit_cnt < 1000; node = rb_next(node), visit_cnt++) { + block_group = rb_entry(node, struct btrfs_block_group, syno_allocator.bytes_index); + btrfs_get_block_group(block_group); + + if (unlikely(!block_group->syno_allocator.initialized)) + goto loop; + if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) + goto loop; + if (unlikely(block_group->ro)) + goto loop; + + if (block_group->length < block_group->syno_allocator.last_bytes) { + btrfs_warn(fs_info, "bg (%llu) with length (%llu) lesser than free space (%llu)", + block_group->start, block_group->length, + block_group->syno_allocator.last_bytes); + goto loop; + } + + usage = block_group->length - block_group->syno_allocator.last_bytes; + + // Block groups with usage greater than 3GB are not considered. + if (usage >= 3ULL * SZ_1G) + goto loop; + + if (usage < min_usage) { + btrfs_info(fs_info, "Balance-candidate has changed from %llu(usage=%llu) to %llu(usage=%llu)," + " visit_cnt=%d", + result, min_usage, block_group->start, usage, visit_cnt); + min_usage = usage; + result = block_group->start; + } +loop: + btrfs_put_block_group(block_group); + } + spin_unlock(&space_info->syno_allocator.lock); + + return result; +} +#endif /* MY_ABC_HERE */ + static int __btrfs_balance(struct btrfs_fs_info *fs_info) { struct btrfs_balance_control *bctl = fs_info->balance_ctl; +#ifdef MY_ABC_HERE + struct btrfs_block_group *cache; +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ struct btrfs_root *chunk_root = fs_info->chunk_root; u64 chunk_type; struct btrfs_chunk *chunk; @@ -3643,6 +3749,27 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) key.offset = (u64)-1; key.type = BTRFS_CHUNK_ITEM_KEY; +#ifdef MY_ABC_HERE + if (bctl->fast_key_offset == 1) { + // Auto select + if (!(key.offset = get_bg_offset_with_free_space_bytes(fs_info))) { + btrfs_warn(fs_info, "[Quick balance] find no block group to balance"); + ret = 0; + goto error; + } + key.offset++; + } else if (bctl->fast_key_offset != 0) { + // Select by user + if (bctl->fast_key_offset % 4096) { + btrfs_warn(fs_info, "[Quick balance] invalid key offset (%llu)", + bctl->fast_key_offset); + ret = -EINVAL; + goto error; + } + key.offset = bctl->fast_key_offset + 1; + } +#endif /* MY_ABC_HERE */ + while (1) { if ((!counting && atomic_read(&fs_info->balance_pause_req)) || atomic_read(&fs_info->balance_cancel_req)) { @@ -3681,6 +3808,15 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) break; } +#ifdef MY_ABC_HERE + // In case the block group vanished. + if (bctl->fast_key_offset && + found_key.offset != key.offset - 1) { + mutex_unlock(&fs_info->delete_unused_bgs_mutex); + break; + } +#endif /* MY_ABC_HERE */ + chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); chunk_type = btrfs_chunk_type(leaf, chunk); @@ -3711,6 +3847,11 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA) count_meta++; +#ifdef MY_ABC_HERE + cache = btrfs_lookup_block_group(fs_info, found_key.offset); + bctl->total_chunk_used += cache->used; + btrfs_put_block_group(cache); +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ goto loop; } @@ -3762,12 +3903,20 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) spin_unlock(&fs_info->balance_lock); } loop: +#ifdef MY_ABC_HERE + if (bctl->fast_key_offset) + break; +#endif /* MY_ABC_HERE */ if (found_key.offset == 0) break; key.offset = found_key.offset - 1; } +#ifdef MY_ABC_HERE + if (counting && !(bctl->flags & BTRFS_BALANCE_DRY_RUN)) { +#else if (counting) { +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ btrfs_release_path(path); counting = false; goto again; @@ -4114,9 +4263,17 @@ int btrfs_balance(struct btrfs_fs_info *fs_info, goto out; } +#ifdef MY_ABC_HERE + if (!bctl->fast_key_offset) { + ret = insert_balance_item(fs_info, bctl); + if (ret && ret != -EEXIST) + goto out; + } +#else ret = insert_balance_item(fs_info, bctl); if (ret && ret != -EEXIST) goto out; +#endif /* MY_ABC_HERE */ if (!(bctl->flags & BTRFS_BALANCE_RESUME)) { BUG_ON(ret == -EEXIST); @@ -4161,6 +4318,29 @@ int btrfs_balance(struct btrfs_fs_info *fs_info, else btrfs_info(fs_info, "balance: ended with status: %d", ret); +#ifdef MY_ABC_HERE + /* + * This is a workaround for xfstest: + * btrfs/156 - Ensure btrfs_trim_fs can trim the whole fs. + * + * In btrfs/156 test, it will do btrfs-balance, then deleting + * files, finally doing fstrim. However, fstrim will not trim + * free space in cluster. Let the ratio of trimmed less than + * 50% threshold. + * + * To solve this issue, we free cluster after btrfs-balance. + * + * Also, we may get a better cluster in relocate block groups + * after btrfs-balance. + */ + if (!ret) { + struct btrfs_free_cluster *cluster = &fs_info->data_alloc_cluster; + spin_lock(&cluster->refill_lock); + btrfs_return_cluster_to_free_space(NULL, cluster); + spin_unlock(&cluster->refill_lock); + } +#endif /* MY_ABC_HERE */ + clear_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags); if (bargs) { @@ -4211,6 +4391,12 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) } mutex_unlock(&fs_info->balance_mutex); +#ifdef MY_ABC_HERE + btrfs_cancel_balance(fs_info); + btrfs_notice(fs_info, "force cancel balance"); + return 0; +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ + if (btrfs_test_opt(fs_info, SKIP_BALANCE)) { btrfs_info(fs_info, "balance: resume skipped"); return 0; @@ -5053,6 +5239,36 @@ static int decide_stripe_size(struct btrfs_fs_devices *fs_devices, } } +#ifdef MY_ABC_HERE +static u64 find_free_chunk_overflow(struct btrfs_fs_info *fs_info, u64 len) +{ + struct extent_map_tree *em_tree; + struct extent_map *em; + struct rb_node *n; + u64 ret = 0; + + em_tree = &fs_info->mapping_tree; + read_lock(&em_tree->lock); + n = rb_first(&em_tree->map.rb_root); + if (n) { + em = rb_entry(n, struct extent_map, rb_node); + ret = em->start + em->len; + } + while (n) { + n = rb_next(n); + if (n) { + em = rb_entry(n, struct extent_map, rb_node); + if (em->start - ret >= len) + break; + ret = em->start + em->len; + } + } + read_unlock(&em_tree->lock); + + return ret; +} +#endif /* MY_ABC_HERE */ + static int create_chunk(struct btrfs_trans_handle *trans, struct alloc_chunk_ctl *ctl, struct btrfs_device_info *devices_info) @@ -5086,6 +5302,13 @@ static int create_chunk(struct btrfs_trans_handle *trans, map->type = type; map->sub_stripes = ctl->sub_stripes; +#ifdef MY_ABC_HERE + if (start > U64_MAX - (64ULL* SZ_1G)) { + start = find_free_chunk_overflow(info, ctl->chunk_size); + ctl->start = start; + } +#endif /* MY_ABC_HERE */ + trace_btrfs_chunk_alloc(info, map, start, ctl->chunk_size); em = alloc_extent_map(); @@ -5147,13 +5370,51 @@ static int create_chunk(struct btrfs_trans_handle *trans, return ret; } +#ifdef MY_ABC_HERE +u64 btrfs_syno_calc_reserve_for_metadata(struct btrfs_fs_info *fs_info) +{ + u64 total_reserved_for_metadata = 0; + u64 disk_total_bytes; + + if (!fs_info || !fs_info->metadata_ratio) + goto out; + + disk_total_bytes = btrfs_super_total_bytes(fs_info->super_copy); + total_reserved_for_metadata = div_u64(disk_total_bytes, fs_info->metadata_ratio); + if (fs_info->avail_metadata_alloc_bits & BTRFS_BLOCK_GROUP_DUP) + total_reserved_for_metadata *= 2; + /* round up to 16MB */ + total_reserved_for_metadata = round_up(total_reserved_for_metadata, SZ_16M); + /* + * When chunk_size > max_chunk_size, round_up 16M will be performed + * according to max_chunk_size, so in order to ensure that the + * metadata reserve is reserved to enough space, an additional + * 16M needs to be added. + */ + total_reserved_for_metadata += SZ_16M; + +out: + return total_reserved_for_metadata; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int btrfs_alloc_chunk_with_info(struct btrfs_trans_handle *trans, u64 type, + u64 *ret_start, u64 *ret_num_bytes) +#else /* MY_ABC_HERE */ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type) +#endif /* MY_ABC_HERE */ { struct btrfs_fs_info *info = trans->fs_info; struct btrfs_fs_devices *fs_devices = info->fs_devices; struct btrfs_device_info *devices_info = NULL; struct alloc_chunk_ctl ctl; int ret; +#ifdef MY_ABC_HERE + const bool mixed = btrfs_fs_incompat(info, MIXED_GROUPS); + struct btrfs_space_info *data_sinfo; + u64 disk_total_bytes, total_reserved_for_metadata, data_maximum_size, data_avail_size; +#endif /* MY_ABC_HERE */ lockdep_assert_held(&info->chunk_mutex); @@ -5183,6 +5444,30 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type) if (!devices_info) return -ENOMEM; +#ifdef MY_ABC_HERE + if (!mixed && info->metadata_ratio && + (ctl.type & BTRFS_BLOCK_GROUP_DATA)) { + data_sinfo = info->data_sinfo; + if (data_sinfo) { + disk_total_bytes = btrfs_super_total_bytes(info->super_copy); + total_reserved_for_metadata = btrfs_syno_calc_reserve_for_metadata(info); + data_maximum_size = disk_total_bytes - total_reserved_for_metadata; + if (data_sinfo->disk_total > data_maximum_size) { + ret = -ENOSPC; + goto out; + } + data_avail_size = data_maximum_size - data_sinfo->disk_total; + /* Align to BTRFS_STRIPE_LEN */ + data_avail_size = round_down(data_avail_size, BTRFS_STRIPE_LEN); + if (data_avail_size < ctl.dev_extent_min) { + ret = -ENOSPC; + goto out; + } + ctl.max_chunk_size = min_t(u64, ctl.max_chunk_size, data_avail_size); + } + } +#endif /* MY_ABC_HERE */ + ret = gather_device_info(fs_devices, &ctl, devices_info); if (ret < 0) goto out; @@ -5192,6 +5477,14 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type) goto out; ret = create_chunk(trans, &ctl, devices_info); +#ifdef MY_ABC_HERE + if (!ret) { + if (ret_start) + *ret_start = ctl.start; + if (ret_num_bytes) + *ret_num_bytes = ctl.chunk_size; + } +#endif /* MY_ABC_HERE */ out: kfree(devices_info); @@ -5751,7 +6044,11 @@ static int get_extra_mirror_from_replace(struct btrfs_fs_info *fs_info, int ret = 0; ret = __btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS, - logical, &length, &bbio, 0, 0); + logical, &length, &bbio, 0, 0 +#ifdef MY_ABC_HERE + , false +#endif /* MY_ABC_HERE */ + ); if (ret) { ASSERT(bbio == NULL); return ret; @@ -5901,23 +6198,24 @@ static bool need_full_stripe(enum btrfs_map_op op) } /* - * btrfs_get_io_geometry - calculates the geomery of a particular (address, len) - * tuple. This information is used to calculate how big a - * particular bio can get before it straddles a stripe. + * Calculate the geometry of a particular (address, len) tuple. This + * information is used to calculate how big a particular bio can get before it + * straddles a stripe. * - * @fs_info - the filesystem - * @logical - address that we want to figure out the geometry of - * @len - the length of IO we are going to perform, starting at @logical - * @op - type of operation - write or read - * @io_geom - pointer used to return values + * @fs_info: the filesystem + * @em: mapping containing the logical extent + * @op: type of operation - write or read + * @logical: address that we want to figure out the geometry of + * @len: the length of IO we are going to perform, starting at @logical + * @io_geom: pointer used to return values * * Returns < 0 in case a chunk for the given logical address cannot be found, * usually shouldn't happen unless @logical is corrupted, 0 otherwise. */ -int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, - u64 logical, u64 len, struct btrfs_io_geometry *io_geom) +int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em, + enum btrfs_map_op op, u64 logical, u64 len, + struct btrfs_io_geometry *io_geom) { - struct extent_map *em; struct map_lookup *map; u64 offset; u64 stripe_offset; @@ -5925,14 +6223,9 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 stripe_len; u64 raid56_full_stripe_start = (u64)-1; int data_stripes; - int ret = 0; ASSERT(op != BTRFS_MAP_DISCARD); - em = btrfs_get_chunk_map(fs_info, logical, len); - if (IS_ERR(em)) - return PTR_ERR(em); - map = em->map_lookup; /* Offset of this logical address in the chunk */ offset = logical - em->start; @@ -5946,8 +6239,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, btrfs_crit(fs_info, "stripe math has gone wrong, stripe_offset=%llu offset=%llu start=%llu logical=%llu stripe_len=%llu", stripe_offset, offset, em->start, logical, stripe_len); - ret = -EINVAL; - goto out; + return -EINVAL; } /* stripe_offset is the offset of this block in its stripe */ @@ -5994,17 +6286,18 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, io_geom->stripe_offset = stripe_offset; io_geom->raid56_stripe_offset = raid56_full_stripe_start; -out: - /* once for us */ - free_extent_map(em); - return ret; + return 0; } static int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, struct btrfs_bio **bbio_ret, - int mirror_num, int need_raid_map) + int mirror_num, int need_raid_map +#ifdef MY_ABC_HERE + , bool is_tree_log +#endif /* MY_ABC_HERE */ + ) { struct extent_map *em; struct map_lookup *map; @@ -6030,12 +6323,13 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, ASSERT(bbio_ret); ASSERT(op != BTRFS_MAP_DISCARD); - ret = btrfs_get_io_geometry(fs_info, op, logical, *length, &geom); + em = btrfs_get_chunk_map(fs_info, logical, *length); + ASSERT(!IS_ERR(em)); + + ret = btrfs_get_io_geometry(fs_info, em, op, logical, *length, &geom); if (ret < 0) return ret; - em = btrfs_get_chunk_map(fs_info, logical, *length); - ASSERT(!IS_ERR(em)); map = em->map_lookup; *length = geom.len; @@ -6089,6 +6383,10 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { if (need_full_stripe(op)) { num_stripes = map->num_stripes; +#ifdef MY_ABC_HERE + if (is_tree_log && op == BTRFS_MAP_WRITE) + num_stripes = 1; +#endif /* MY_ABC_HERE */ } else if (mirror_num) { stripe_index = mirror_num - 1; } else { @@ -6206,8 +6504,14 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, sort_parity_stripes(bbio, num_stripes); } - if (need_full_stripe(op)) - max_errors = btrfs_chunk_max_errors(map); + if (need_full_stripe(op)) { +#ifdef MY_ABC_HERE + if (is_tree_log && op == BTRFS_MAP_WRITE) + max_errors = 0; + else +#endif /* MY_ABC_HERE */ + max_errors = btrfs_chunk_max_errors(map); + } if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL && need_full_stripe(op)) { @@ -6251,7 +6555,11 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, length, bbio_ret); return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, - mirror_num, 0); + mirror_num, 0 +#ifdef MY_ABC_HERE + , false +#endif /* MY_ABC_HERE */ + ); } /* For Scrub/replace */ @@ -6259,7 +6567,11 @@ int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, struct btrfs_bio **bbio_ret) { - return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, 0, 1); + return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, 0, 1 +#ifdef MY_ABC_HERE + , false +#endif /* MY_ABC_HERE */ + ); } static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio) @@ -6364,8 +6676,13 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) } } +#ifdef MY_ABC_HERE +static blk_status_t __btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, + int mirror_num, bool is_tree_log) +#else /* MY_ABC_HERE */ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num) +#endif /* MY_ABC_HERE */ { struct btrfs_device *dev; struct bio *first_bio = bio; @@ -6382,7 +6699,11 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, btrfs_bio_counter_inc_blocked(fs_info); ret = __btrfs_map_block(fs_info, btrfs_op(bio), logical, - &map_length, &bbio, mirror_num, 1); + &map_length, &bbio, mirror_num, 1 +#ifdef MY_ABC_HERE + , is_tree_log +#endif /* MY_ABC_HERE */ + ); if (ret) { btrfs_bio_counter_dec(fs_info); return errno_to_blk_status(ret); @@ -6438,6 +6759,19 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, btrfs_bio_counter_dec(fs_info); return BLK_STS_OK; } +#ifdef MY_ABC_HERE +blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, + int mirror_num) +{ + return __btrfs_map_bio(fs_info, bio, mirror_num, false); +} +blk_status_t btrfs_map_bio_log_tree(struct btrfs_fs_info *fs_info, + struct bio *bio, + int mirror_num) +{ + return __btrfs_map_bio(fs_info, bio, mirror_num, true); +} +#endif /* MY_ABC_HERE */ /* * Find a device specified by @devid or @uuid in the list of @fs_devices, or @@ -7670,6 +8004,9 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) return -ENOMEM; path->reada = READA_FORWARD; +#ifdef MY_ABC_HERE + path->reada = READA_FORWARD_ALWAYS; +#endif /* SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS */ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index f2177263748e..6164fb6b68b5 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -265,6 +268,10 @@ struct btrfs_fs_devices { struct completion kobj_unregister; enum btrfs_chunk_allocation_policy chunk_alloc_policy; + +#ifdef MY_ABC_HERE + bool rbd_enabled; +#endif /* MY_ABC_HERE */ }; #define BTRFS_BIO_INLINE_CSUM_SIZE 64 @@ -278,6 +285,14 @@ struct btrfs_fs_devices { - 2 * sizeof(struct btrfs_chunk)) \ / sizeof(struct btrfs_stripe) + 1) +#ifdef MY_ABC_HERE +#define BTRFS_BIO_SHOULD_ABORT_RETRY ((u8)-2) +#define BTRFS_BIO_RETRY_ABORTED ((u8)-1) + +static_assert(BTRFS_BIO_SHOULD_ABORT_RETRY > SYNO_DATA_CORRECTION_MAX_RETRY_TIMES, + "syno data correction bio flag invalid"); +#endif /* MY_ABC_HERE */ + /* * we need the mirror number and stripe index to be passed around * the call chain while we are processing end_io (especially errors). @@ -292,7 +307,22 @@ struct btrfs_io_bio { struct btrfs_device *device; u64 logical; u8 *csum; +#ifdef MY_ABC_HERE + /* + * In retry mode, the first half is the correct csum, and + * the remaining is bad csum from previous retry. + */ + union { + struct { + u8 cur_csum[BTRFS_CSUM_SIZE]; + u8 prev_bad_csum[BTRFS_CSUM_SIZE]; + } __attribute__ ((__packed__)) retry; + u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE]; + }; + u8 nr_retry; +#else /* MY_ABC_HERE */ u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE]; +#endif /* MY_ABC_HERE */ struct bvec_iter iter; /* * This member must come last, bio_alloc_bioset will allocate enough @@ -300,6 +330,10 @@ struct btrfs_io_bio { */ struct bio bio; }; +#ifdef MY_ABC_HERE +static_assert(BTRFS_BIO_INLINE_CSUM_SIZE >= (BTRFS_CSUM_SIZE << 1), + "Invalid checksum size for syno data correction"); +#endif /* MY_ABC_HERE */ static inline struct btrfs_io_bio *btrfs_io_bio(struct bio *bio) { @@ -391,6 +425,12 @@ struct btrfs_balance_control { u64 flags; struct btrfs_balance_progress stat; +#ifdef MY_ABC_HERE + u64 total_chunk_used; +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ +#ifdef MY_ABC_HERE + u64 fast_key_offset; // 0: normal balance; 1: auto select bg; otherwise: bg key offset provided by progs +#endif /* MY_ABC_HERE */ }; enum btrfs_map_op { @@ -423,14 +463,29 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, u64 logical, u64 *length, struct btrfs_bio **bbio_ret); -int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, - u64 logical, u64 len, struct btrfs_io_geometry *io_geom); +int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *map, + enum btrfs_map_op op, u64 logical, u64 len, + struct btrfs_io_geometry *io_geom); int btrfs_read_sys_array(struct btrfs_fs_info *fs_info); int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +int btrfs_alloc_chunk_with_info(struct btrfs_trans_handle *trans, u64 type, + u64 *ret_start, u64 *ret_num_bytes) ; + +static inline int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type) +{ + return btrfs_alloc_chunk_with_info(trans, type, NULL, NULL); +} +#else /* MY_ABC_HERE */ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type); +#endif /* MY_ABC_HERE */ void btrfs_mapping_tree_free(struct extent_map_tree *tree); blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num); +#ifdef MY_ABC_HERE +blk_status_t btrfs_map_bio_log_tree(struct btrfs_fs_info *fs_info, struct bio *bio, + int mirror_num); +#endif /* MY_ABC_HERE */ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, fmode_t flags, void *holder); struct btrfs_device *btrfs_scan_one_device(const char *path, @@ -580,4 +635,8 @@ int btrfs_bg_type_to_factor(u64 flags); const char *btrfs_bg_type_to_raid_name(u64 flags); int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info); +#ifdef MY_ABC_HERE +u64 btrfs_syno_calc_reserve_for_metadata(struct btrfs_fs_info *fs_info); +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index f1a60bcdb3db..151469e14347 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007 Red Hat. All rights reserved. @@ -359,6 +362,15 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) read_extent_buffer(leaf, buffer, name_ptr, name_len); buffer[name_len] = '\0'; +#ifdef MY_ABC_HERE + /* Conceal the syno prefix from user space. Please refer to DSM#69101 */ + if (!strncmp(buffer, XATTR_SYNO_PREFIX, XATTR_SYNO_PREFIX_LEN) || + !strncmp(buffer, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN)) { + total_size -= name_len + 1; + goto next; + } +#endif /* MY_ABC_HERE */ + size_left -= name_len + 1; buffer += name_len + 1; next: @@ -403,7 +415,7 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler, struct btrfs_root *root = BTRFS_I(inode)->root; name = xattr_full_name(handler, name); - ret = btrfs_validate_prop(name, value, size); + ret = btrfs_validate_prop(BTRFS_I(inode), name, value, size); if (ret) return ret; @@ -424,6 +436,131 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler, return ret; } +#ifdef MY_ABC_HERE +int btrfs_xattr_syno_set_archive_bit(struct btrfs_trans_handle *trans, + struct inode *inode, const void *value, size_t size, + int flags, bool lock) +{ + int ret; + + if (lock) + mutex_lock(&inode->i_archive_bit_mutex); + + if (trans) + ret = btrfs_setxattr(trans, inode, XATTR_SYNO_ARCHIVE_BIT, + value, size, flags); + else + ret = btrfs_setxattr_trans(inode, XATTR_SYNO_ARCHIVE_BIT, + value, size, flags); + if (ret) + goto out; + + if (value) + inode->i_archive_bit = le32_to_cpu(*(__le32 *)value); + else // "buffer == NULL" means removexattr + inode->i_archive_bit = 0; + +out: + if (lock) + mutex_unlock(&inode->i_archive_bit_mutex); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int btrfs_xattr_syno_set_crtime(struct btrfs_trans_handle *trans, + struct inode *inode, struct btrfs_timespec *crtime, int flags) +{ + int ret; + + // Notice: btrfs_settxattr will also modify ctime. + if (trans) + ret = btrfs_setxattr(trans, inode, XATTR_SYNO_CREATE_TIME, + crtime, sizeof(struct btrfs_timespec), flags); + else + ret = btrfs_setxattr_trans(inode, XATTR_SYNO_CREATE_TIME, + crtime, sizeof(struct btrfs_timespec), flags); + if (!ret) { + BTRFS_I(inode)->i_otime.tv_sec = + btrfs_stack_timespec_sec(crtime); + BTRFS_I(inode)->i_otime.tv_nsec = + btrfs_stack_timespec_nsec(crtime); + set_bit(BTRFS_INODE_CREATE_TIME, + &BTRFS_I(inode)->runtime_flags); + } + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int btrfs_xattr_handler_set_syno(const struct xattr_handler *handler, + struct dentry *unused, struct inode *inode, + const char *name, const void *buffer, + size_t size, int flags) +{ + name = xattr_full_name(handler, name); + +#ifdef MY_ABC_HERE + if (!strcmp(name, XATTR_SYNO_ARCHIVE_VERSION)) { + /* inode's archive version would be updated every time when + * it's created or modified as super block's archive version +1. + * + * btrfs send will skip it, and it's also meaningless to + * update from xattr. we should ignore it. + */ + return 0; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!strcmp(name, XATTR_SYNO_ARCHIVE_BIT)) { + /* inode->i_archive_bit_mutex isn't hold to avoid deadlock + * from syno_archive_bit_modify() + */ + return btrfs_xattr_syno_set_archive_bit(NULL, inode, + buffer, size, flags, false); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!strcmp(name, XATTR_SYNO_CREATE_TIME)) { + if (size != sizeof(struct btrfs_timespec)) + return -EINVAL; + /* inode_lock is required and hold in vfs_setxattr() */ + return btrfs_xattr_syno_set_crtime(NULL, inode, + (struct btrfs_timespec *)buffer, flags); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!strcmp(name, XATTR_SYNO_LOCKER)) + return btrfs_xattr_syno_set_locker(inode, buffer, size); +#endif /* MY_ABC_HERE */ + + return btrfs_setxattr_trans(inode, name, buffer, size, flags); +} + +const struct xattr_handler btrfs_xattr_syno_handler = { + .prefix = XATTR_SYNO_PREFIX, + /* + * In order to avoid the issues of concurrent accessing, we + * should disallow the access of these syno attributes by get/set + * xattr syscalls just like what we do in other filesystems. + * + * BUT because of "btrfs receive" which may set syno xattr to the + * received files, we decided to allow the access of syno xattr + * by get/set xattr syscalls. + * + * The proper ways to access them are using the related syscalls + * (i.g. syno_stat/syno_archive_overwrite) or per-attribute + * fcntl.(i.g. F_CLEAR_ARCHIVE, F_SETSMB_ARCHIVE...) + */ + .get = btrfs_xattr_handler_get, + .set = btrfs_xattr_handler_set_syno, +}; +#endif /* MY_ABC_HERE */ + static const struct xattr_handler btrfs_security_xattr_handler = { .prefix = XATTR_SECURITY_PREFIX, .get = btrfs_xattr_handler_get, @@ -448,12 +585,22 @@ static const struct xattr_handler btrfs_btrfs_xattr_handler = { .set = btrfs_xattr_handler_set_prop, }; +#ifdef MY_ABC_HERE +extern const struct xattr_handler btrfs_xattr_synoacl_access_handler; +#endif /* MY_ABC_HERE */ + const struct xattr_handler *btrfs_xattr_handlers[] = { &btrfs_security_xattr_handler, #ifdef CONFIG_BTRFS_FS_POSIX_ACL &posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, #endif +#ifdef MY_ABC_HERE + &btrfs_xattr_synoacl_access_handler, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + &btrfs_xattr_syno_handler, +#endif /* MY_ABC_HERE */ &btrfs_trusted_xattr_handler, &btrfs_user_xattr_handler, &btrfs_btrfs_xattr_handler, diff --git a/fs/btrfs/xattr.h b/fs/btrfs/xattr.h index 1cd3fc0a8f17..1b7c6ee83de6 100644 --- a/fs/btrfs/xattr.h +++ b/fs/btrfs/xattr.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2007 Red Hat. All rights reserved. @@ -22,4 +25,16 @@ int btrfs_xattr_security_init(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir, const struct qstr *qstr); +#ifdef MY_ABC_HERE +int btrfs_xattr_syno_set_archive_bit(struct btrfs_trans_handle *trans, + struct inode *inode, const void *value, size_t size, + int flags, bool lock); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int btrfs_xattr_syno_set_crtime(struct btrfs_trans_handle *trans, + struct inode *inode, struct btrfs_timespec *crtime, + int flags); +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/buffer.c b/fs/buffer.c index 23f645657488..8ac443292f12 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/buffer.c @@ -3014,8 +3017,15 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, BUG_ON(!buffer_locked(bh)); BUG_ON(!buffer_mapped(bh)); BUG_ON(!bh->b_end_io); +#ifdef MY_ABC_HERE + if (WARN_ON(buffer_delay(bh))) + clear_buffer_delay(bh); + if (WARN_ON(buffer_unwritten(bh))) + clear_buffer_unwritten(bh); +#else BUG_ON(buffer_delay(bh)); BUG_ON(buffer_unwritten(bh)); +#endif /* MY_ABC_HERE */ /* * Only clear out a write error when rewriting diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile index 50c635dc7f71..4aee5a69d81c 100644 --- a/fs/ceph/Makefile +++ b/fs/ceph/Makefile @@ -12,3 +12,4 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \ ceph-$(CONFIG_CEPH_FSCACHE) += cache.o ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o +ceph-$(CONFIG_SYNO_CEPH_WINACL) += syno_acl.o diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 3465ff95cb89..441650bffbae 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -120,8 +120,7 @@ static int ceph_set_page_dirty(struct page *page) * PagePrivate so that we get invalidatepage callback. */ BUG_ON(PagePrivate(page)); - page->private = (unsigned long)snapc; - SetPagePrivate(page); + attach_page_private(page, snapc); return __set_page_dirty_nobuffers(page); } @@ -136,19 +135,17 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset, { struct inode *inode; struct ceph_inode_info *ci; - struct ceph_snap_context *snapc = page_snap_context(page); + struct ceph_snap_context *snapc; inode = page->mapping->host; ci = ceph_inode(inode); - if (offset != 0 || length != PAGE_SIZE) { + if (offset != 0 || length != thp_size(page)) { dout("%p invalidatepage %p idx %lu partial dirty page %u~%u\n", inode, page, page->index, offset, length); return; } - ceph_invalidate_fscache_page(inode, page); - WARN_ON(!PageLocked(page)); if (!PagePrivate(page)) return; @@ -156,10 +153,9 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset, dout("%p invalidatepage %p idx %lu full dirty page\n", inode, page, page->index); + snapc = detach_page_private(page); ceph_put_wrbuffer_cap_refs(ci, 1, snapc); ceph_put_snap_context(snapc); - page->private = 0; - ClearPagePrivate(page); } static int ceph_releasepage(struct page *page, gfp_t g) @@ -167,10 +163,6 @@ static int ceph_releasepage(struct page *page, gfp_t g) dout("%p releasepage %p idx %lu (%sdirty)\n", page->mapping->host, page, page->index, PageDirty(page) ? "" : "not "); - /* Can we release the page from the cache? */ - if (!ceph_release_fscache_page(page, g)) - return 0; - return !PagePrivate(page); } @@ -205,10 +197,6 @@ static int ceph_do_readpage(struct file *filp, struct page *page) return 0; } - err = ceph_readpage_from_fscache(inode, page); - if (err == 0) - return -EINPROGRESS; - dout("readpage ino %llx.%llx file %p off %llu len %llu page %p index %lu\n", vino.ino, vino.snap, filp, off, len, page, page->index); req = ceph_osdc_new_request(osdc, &ci->i_layout, vino, off, &len, 0, 1, @@ -224,8 +212,8 @@ static int ceph_do_readpage(struct file *filp, struct page *page) if (!err) err = ceph_osdc_wait_request(osdc, req); - ceph_update_read_latency(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, err); + ceph_update_read_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, len, err); ceph_osdc_put_request(req); dout("readpage result %d\n", err); @@ -233,7 +221,6 @@ static int ceph_do_readpage(struct file *filp, struct page *page) if (err == -ENOENT) err = 0; if (err < 0) { - ceph_fscache_readpage_cancel(inode, page); if (err == -EBLOCKLISTED) fsc->blocklisted = true; goto out; @@ -245,8 +232,6 @@ static int ceph_do_readpage(struct file *filp, struct page *page) flush_dcache_page(page); SetPageUptodate(page); - ceph_readpage_to_fscache(inode, page); - out: return err < 0 ? err : 0; } @@ -286,10 +271,8 @@ static void finish_read(struct ceph_osd_request *req) for (i = 0; i < num_pages; i++) { struct page *page = osd_data->pages[i]; - if (rc < 0 && rc != -ENOENT) { - ceph_fscache_readpage_cancel(inode, page); + if (rc < 0 && rc != -ENOENT) goto unlock; - } if (bytes < (int)PAGE_SIZE) { /* zero (remainder of) page */ int s = bytes < 0 ? 0 : bytes; @@ -299,15 +282,14 @@ static void finish_read(struct ceph_osd_request *req) page->index); flush_dcache_page(page); SetPageUptodate(page); - ceph_readpage_to_fscache(inode, page); unlock: unlock_page(page); put_page(page); bytes -= PAGE_SIZE; } - ceph_update_read_latency(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, rc); + ceph_update_read_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, osd_data->length, rc); kfree(osd_data->pages); } @@ -400,7 +382,6 @@ static int start_read(struct inode *inode, struct ceph_rw_context *rw_ctx, page->index); if (add_to_page_cache_lru(page, &inode->i_data, page->index, GFP_KERNEL)) { - ceph_fscache_uncache_page(inode, page); put_page(page); dout("start_read %p add_to_page_cache failed %p\n", inode, page); @@ -432,10 +413,8 @@ static int start_read(struct inode *inode, struct ceph_rw_context *rw_ctx, return nr_pages; out_pages: - for (i = 0; i < nr_pages; ++i) { - ceph_fscache_readpage_cancel(inode, pages[i]); + for (i = 0; i < nr_pages; ++i) unlock_page(pages[i]); - } ceph_put_page_vector(pages, nr_pages, false); out_put: ceph_osdc_put_request(req); @@ -463,12 +442,6 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, if (ceph_inode(inode)->i_inline_version != CEPH_INLINE_NONE) return -EINVAL; - rc = ceph_readpages_from_fscache(mapping->host, mapping, page_list, - &nr_pages); - - if (rc == 0) - goto out; - rw_ctx = ceph_find_rw_context(fi); max = fsc->mount_options->rsize >> PAGE_SHIFT; dout("readpages %p file %p ctx %p nr_pages %d max %d\n", @@ -479,8 +452,6 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, goto out; } out: - ceph_fscache_readpages_cancel(inode, page_list); - dout("readpages %p file %p ret %d\n", inode, file, rc); return rc; } @@ -577,8 +548,8 @@ static u64 get_writepages_data_length(struct inode *inode, spin_unlock(&ci->i_ceph_lock); WARN_ON(!found); } - if (end > page_offset(page) + PAGE_SIZE) - end = page_offset(page) + PAGE_SIZE; + if (end > page_offset(page) + thp_size(page)) + end = page_offset(page) + thp_size(page); return end > start ? end - start : 0; } @@ -596,7 +567,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) struct ceph_snap_context *snapc, *oldest; loff_t page_off = page_offset(page); int err; - loff_t len = PAGE_SIZE; + loff_t len = thp_size(page); struct ceph_writeback_ctl ceph_wbc; struct ceph_osd_client *osdc = &fsc->client->osdc; struct ceph_osd_request *req; @@ -624,7 +595,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) /* is this a partial page at end of file? */ if (page_off >= ceph_wbc.i_size) { dout("%p page eof %llu\n", page, ceph_wbc.i_size); - page->mapping->a_ops->invalidatepage(page, 0, PAGE_SIZE); + page->mapping->a_ops->invalidatepage(page, 0, thp_size(page)); return 0; } @@ -650,7 +621,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) } /* it may be a short write due to an object boundary */ - WARN_ON_ONCE(len > PAGE_SIZE); + WARN_ON_ONCE(len > thp_size(page)); osd_req_op_extent_osd_data_pages(req, 0, &page, len, 0, false, false); dout("writepage %llu~%llu (%llu bytes)\n", page_off, len, len); @@ -659,8 +630,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) if (!err) err = ceph_osdc_wait_request(osdc, req); - ceph_update_write_latency(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, err); + ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, len, err); ceph_osdc_put_request(req); if (err == 0) @@ -687,8 +658,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) dout("writepage cleaned page %p\n", page); err = 0; /* vfs expects us to return 0 */ } - page->private = 0; - ClearPagePrivate(page); + oldest = detach_page_private(page); + WARN_ON_ONCE(oldest != snapc); end_page_writeback(page); ceph_put_wrbuffer_cap_refs(ci, 1, snapc); ceph_put_snap_context(snapc); /* page's reference */ @@ -735,6 +706,7 @@ static void writepages_finish(struct ceph_osd_request *req) struct ceph_snap_context *snapc = req->r_snapc; struct address_space *mapping = inode->i_mapping; struct ceph_fs_client *fsc = ceph_inode_to_client(inode); + unsigned int len = 0; bool remove_page; dout("writepages_finish %p rc %d\n", inode, rc); @@ -747,9 +719,6 @@ static void writepages_finish(struct ceph_osd_request *req) ceph_clear_error_write(ci); } - ceph_update_write_latency(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, rc); - /* * We lost the cache cap, need to truncate the page before * it is unlocked, otherwise we'd truncate it later in the @@ -766,6 +735,7 @@ static void writepages_finish(struct ceph_osd_request *req) osd_data = osd_req_op_extent_osd_data(req, i); BUG_ON(osd_data->type != CEPH_OSD_DATA_TYPE_PAGES); + len += osd_data->length; num_pages = calc_pages_for((u64)osd_data->alignment, (u64)osd_data->length); total_pages += num_pages; @@ -780,11 +750,9 @@ static void writepages_finish(struct ceph_osd_request *req) clear_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC); - ceph_put_snap_context(page_snap_context(page)); - page->private = 0; - ClearPagePrivate(page); - dout("unlocking %p\n", page); + ceph_put_snap_context(detach_page_private(page)); end_page_writeback(page); + dout("unlocking %p\n", page); if (remove_page) generic_error_remove_page(inode->i_mapping, @@ -798,6 +766,9 @@ static void writepages_finish(struct ceph_osd_request *req) release_pages(osd_data->pages, num_pages); } + ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, len, rc); + ceph_put_wrbuffer_cap_refs(ci, total_pages, snapc); osd_data = osd_req_op_extent_osd_data(req, 0); @@ -832,7 +803,7 @@ static int ceph_writepages_start(struct address_space *mapping, wbc->sync_mode == WB_SYNC_NONE ? "NONE" : (wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD")); - if (READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + if (READ_ONCE(fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) { if (ci->i_wrbuffer_ref > 0) { pr_warn_ratelimited( "writepage_start %p %lld forced umount\n", @@ -941,7 +912,7 @@ static int ceph_writepages_start(struct address_space *mapping, page_offset(page) >= i_size_read(inode)) && clear_page_dirty_for_io(page)) mapping->a_ops->invalidatepage(page, - 0, PAGE_SIZE); + 0, thp_size(page)); unlock_page(page); continue; } @@ -1030,7 +1001,7 @@ static int ceph_writepages_start(struct address_space *mapping, pages[locked_pages++] = page; pvec.pages[i] = NULL; - len += PAGE_SIZE; + len += thp_size(page); } /* did we get anything? */ @@ -1079,7 +1050,7 @@ static int ceph_writepages_start(struct address_space *mapping, BUG_ON(IS_ERR(req)); } BUG_ON(len < page_offset(pages[locked_pages - 1]) + - PAGE_SIZE - offset); + thp_size(page) - offset); req->r_callback = writepages_finish; req->r_inode = inode; @@ -1109,7 +1080,7 @@ static int ceph_writepages_start(struct address_space *mapping, } set_page_writeback(pages[i]); - len += PAGE_SIZE; + len += thp_size(page); } if (ceph_wbc.size_stable) { @@ -1118,7 +1089,7 @@ static int ceph_writepages_start(struct address_space *mapping, /* writepages_finish() clears writeback pages * according to the data length, so make sure * data length covers all locked pages */ - u64 min_len = len + 1 - PAGE_SIZE; + u64 min_len = len + 1 - thp_size(page); len = get_writepages_data_length(inode, pages[i - 1], offset); len = max(len, min_len); @@ -1256,7 +1227,7 @@ ceph_find_incompatible(struct page *page) struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); - if (READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + if (READ_ONCE(fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) { dout(" page %p forced umount\n", page); return ERR_PTR(-EIO); } @@ -1351,7 +1322,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, dout("write_begin file %p inode %p page %p %d~%d\n", file, inode, page, (int)pos, (int)len); for (;;) { - page = grab_cache_page_write_begin(mapping, index, 0); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { r = -ENOMEM; break; @@ -1420,8 +1391,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, dout("write_end file %p inode %p page %p %d~%d (%d)\n", file, inode, page, (int)pos, (int)copied, (int)len); - /* zero the stale part of the page if we did a short copy */ if (!PageUptodate(page)) { + /* just return that nothing was copied on a short copy */ if (copied < len) { copied = 0; goto out; @@ -1490,7 +1461,6 @@ static vm_fault_t ceph_filemap_fault(struct vm_fault *vmf) struct inode *inode = file_inode(vma->vm_file); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_file_info *fi = vma->vm_file->private_data; - struct page *pinned_page = NULL; loff_t off = (loff_t)vmf->pgoff << PAGE_SHIFT; int want, got, err; sigset_t oldset; @@ -1498,21 +1468,20 @@ static vm_fault_t ceph_filemap_fault(struct vm_fault *vmf) ceph_block_sigs(&oldset); - dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n", - inode, ceph_vinop(inode), off, (size_t)PAGE_SIZE); + dout("filemap_fault %p %llx.%llx %llu trying to get caps\n", + inode, ceph_vinop(inode), off); if (fi->fmode & CEPH_FILE_MODE_LAZY) want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; else want = CEPH_CAP_FILE_CACHE; got = 0; - err = ceph_get_caps(vma->vm_file, CEPH_CAP_FILE_RD, want, -1, - &got, &pinned_page); + err = ceph_get_caps(vma->vm_file, CEPH_CAP_FILE_RD, want, -1, &got); if (err < 0) goto out_restore; - dout("filemap_fault %p %llu~%zd got cap refs on %s\n", - inode, off, (size_t)PAGE_SIZE, ceph_cap_string(got)); + dout("filemap_fault %p %llu got cap refs on %s\n", + inode, off, ceph_cap_string(got)); if ((got & (CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO)) || ci->i_inline_version == CEPH_INLINE_NONE) { @@ -1520,14 +1489,11 @@ static vm_fault_t ceph_filemap_fault(struct vm_fault *vmf) ceph_add_rw_context(fi, &rw_ctx); ret = filemap_fault(vmf); ceph_del_rw_context(fi, &rw_ctx); - dout("filemap_fault %p %llu~%zd drop cap refs %s ret %x\n", - inode, off, (size_t)PAGE_SIZE, - ceph_cap_string(got), ret); + dout("filemap_fault %p %llu drop cap refs %s ret %x\n", + inode, off, ceph_cap_string(got), ret); } else err = -EAGAIN; - if (pinned_page) - put_page(pinned_page); ceph_put_cap_refs(ci, got); if (err != -EAGAIN) @@ -1562,8 +1528,8 @@ static vm_fault_t ceph_filemap_fault(struct vm_fault *vmf) vmf->page = page; ret = VM_FAULT_MAJOR | VM_FAULT_LOCKED; out_inline: - dout("filemap_fault %p %llu~%zd read inline data ret %x\n", - inode, off, (size_t)PAGE_SIZE, ret); + dout("filemap_fault %p %llu read inline data ret %x\n", + inode, off, ret); } out_restore: ceph_restore_sigs(&oldset); @@ -1611,10 +1577,10 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) goto out_free; } - if (off + PAGE_SIZE <= size) - len = PAGE_SIZE; + if (off + thp_size(page) <= size) + len = thp_size(page); else - len = size & ~PAGE_MASK; + len = offset_in_thp(page, size); dout("page_mkwrite %p %llx.%llx %llu~%zd getting caps i_size %llu\n", inode, ceph_vinop(inode), off, len, size); @@ -1624,8 +1590,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) want = CEPH_CAP_FILE_BUFFER; got = 0; - err = ceph_get_caps(vma->vm_file, CEPH_CAP_FILE_WR, want, off + len, - &got, NULL); + err = ceph_get_caps(vma->vm_file, CEPH_CAP_FILE_WR, want, off + len, &got); if (err < 0) goto out_free; @@ -1682,7 +1647,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %x\n", inode, off, len, ceph_cap_string(got), ret); - ceph_put_cap_refs(ci, got); + ceph_put_cap_refs_async(ci, got); out_free: ceph_restore_sigs(&oldset); sb_end_pagefault(inode->i_sb); @@ -1852,8 +1817,8 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page) if (!err) err = ceph_osdc_wait_request(&fsc->client->osdc, req); - ceph_update_write_latency(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, err); + ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, len, err); out_put: ceph_osdc_put_request(req); @@ -2077,6 +2042,10 @@ int ceph_pool_perm_check(struct inode *inode, int need) s64 pool; int ret, flags; + /* Only need to do this for regular files */ + if (!S_ISREG(inode->i_mode)) + return 0; + if (ci->i_vino.snap != CEPH_NOSNAP) { /* * Pool permission check needs to write to the first object. diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c index 2f5cb6bc78e1..9cfadbb86568 100644 --- a/fs/ceph/cache.c +++ b/fs/ceph/cache.c @@ -173,7 +173,6 @@ void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci) ci->fscache = NULL; - fscache_uncache_all_inode_pages(cookie, &ci->vfs_inode); fscache_relinquish_cookie(cookie, &ci->i_vino, false); } @@ -194,7 +193,6 @@ void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp) dout("fscache_file_set_cookie %p %p disabling cache\n", inode, filp); fscache_disable_cookie(ci->fscache, &ci->i_vino, false); - fscache_uncache_all_inode_pages(ci->fscache, inode); } else { fscache_enable_cookie(ci->fscache, &ci->i_vino, i_size_read(inode), ceph_fscache_can_enable, inode); @@ -205,108 +203,6 @@ void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp) } } -static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error) -{ - if (!error) - SetPageUptodate(page); - - unlock_page(page); -} - -static inline bool cache_valid(struct ceph_inode_info *ci) -{ - return ci->i_fscache_gen == ci->i_rdcache_gen; -} - - -/* Atempt to read from the fscache, - * - * This function is called from the readpage_nounlock context. DO NOT attempt to - * unlock the page here (or in the callback). - */ -int ceph_readpage_from_fscache(struct inode *inode, struct page *page) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - int ret; - - if (!cache_valid(ci)) - return -ENOBUFS; - - ret = fscache_read_or_alloc_page(ci->fscache, page, - ceph_readpage_from_fscache_complete, NULL, - GFP_KERNEL); - - switch (ret) { - case 0: /* Page found */ - dout("page read submitted\n"); - return 0; - case -ENOBUFS: /* Pages were not found, and can't be */ - case -ENODATA: /* Pages were not found */ - dout("page/inode not in cache\n"); - return ret; - default: - dout("%s: unknown error ret = %i\n", __func__, ret); - return ret; - } -} - -int ceph_readpages_from_fscache(struct inode *inode, - struct address_space *mapping, - struct list_head *pages, - unsigned *nr_pages) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - int ret; - - if (!cache_valid(ci)) - return -ENOBUFS; - - ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages, - ceph_readpage_from_fscache_complete, - NULL, mapping_gfp_mask(mapping)); - - switch (ret) { - case 0: /* All pages found */ - dout("all-page read submitted\n"); - return 0; - case -ENOBUFS: /* Some pages were not found, and can't be */ - case -ENODATA: /* some pages were not found */ - dout("page/inode not in cache\n"); - return ret; - default: - dout("%s: unknown error ret = %i\n", __func__, ret); - return ret; - } -} - -void ceph_readpage_to_fscache(struct inode *inode, struct page *page) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - int ret; - - if (!PageFsCache(page)) - return; - - if (!cache_valid(ci)) - return; - - ret = fscache_write_page(ci->fscache, page, i_size_read(inode), - GFP_KERNEL); - if (ret) - fscache_uncache_page(ci->fscache, page); -} - -void ceph_invalidate_fscache_page(struct inode* inode, struct page *page) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - - if (!PageFsCache(page)) - return; - - fscache_wait_on_page_write(ci->fscache, page); - fscache_uncache_page(ci->fscache, page); -} - void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc) { if (fscache_cookie_valid(fsc->fscache)) { @@ -329,24 +225,3 @@ void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc) } fsc->fscache = NULL; } - -/* - * caller should hold CEPH_CAP_FILE_{RD,CACHE} - */ -void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci) -{ - if (cache_valid(ci)) - return; - - /* resue i_truncate_mutex. There should be no pending - * truncate while the caller holds CEPH_CAP_FILE_RD */ - mutex_lock(&ci->i_truncate_mutex); - if (!cache_valid(ci)) { - if (fscache_check_consistency(ci->fscache, &ci->i_vino)) - fscache_invalidate(ci->fscache); - spin_lock(&ci->i_ceph_lock); - ci->i_fscache_gen = ci->i_rdcache_gen; - spin_unlock(&ci->i_ceph_lock); - } - mutex_unlock(&ci->i_truncate_mutex); -} diff --git a/fs/ceph/cache.h b/fs/ceph/cache.h index 89dbdd1eb14a..5f40513c1512 100644 --- a/fs/ceph/cache.h +++ b/fs/ceph/cache.h @@ -24,18 +24,9 @@ void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci); void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp); void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci); -int ceph_readpage_from_fscache(struct inode *inode, struct page *page); -int ceph_readpages_from_fscache(struct inode *inode, - struct address_space *mapping, - struct list_head *pages, - unsigned *nr_pages); -void ceph_readpage_to_fscache(struct inode *inode, struct page *page); -void ceph_invalidate_fscache_page(struct inode* inode, struct page *page); - static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci) { ci->fscache = NULL; - ci->i_fscache_gen = 0; } static inline void ceph_fscache_invalidate(struct inode *inode) @@ -43,40 +34,6 @@ static inline void ceph_fscache_invalidate(struct inode *inode) fscache_invalidate(ceph_inode(inode)->fscache); } -static inline void ceph_fscache_uncache_page(struct inode *inode, - struct page *page) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - return fscache_uncache_page(ci->fscache, page); -} - -static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp) -{ - struct inode* inode = page->mapping->host; - struct ceph_inode_info *ci = ceph_inode(inode); - return fscache_maybe_release_page(ci->fscache, page, gfp); -} - -static inline void ceph_fscache_readpage_cancel(struct inode *inode, - struct page *page) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - if (fscache_cookie_valid(ci->fscache) && PageFsCache(page)) - __fscache_uncache_page(ci->fscache, page); -} - -static inline void ceph_fscache_readpages_cancel(struct inode *inode, - struct list_head *pages) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - return fscache_readpages_cancel(ci->fscache, pages); -} - -static inline void ceph_disable_fscache_readpage(struct ceph_inode_info *ci) -{ - ci->i_fscache_gen = ci->i_rdcache_gen - 1; -} - #else static inline int ceph_fscache_register(void) @@ -115,62 +72,10 @@ static inline void ceph_fscache_file_set_cookie(struct inode *inode, { } -static inline void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci) -{ -} - -static inline void ceph_fscache_uncache_page(struct inode *inode, - struct page *pages) -{ -} - -static inline int ceph_readpage_from_fscache(struct inode* inode, - struct page *page) -{ - return -ENOBUFS; -} - -static inline int ceph_readpages_from_fscache(struct inode *inode, - struct address_space *mapping, - struct list_head *pages, - unsigned *nr_pages) -{ - return -ENOBUFS; -} - -static inline void ceph_readpage_to_fscache(struct inode *inode, - struct page *page) -{ -} - static inline void ceph_fscache_invalidate(struct inode *inode) { } -static inline void ceph_invalidate_fscache_page(struct inode *inode, - struct page *page) -{ -} - -static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp) -{ - return 1; -} - -static inline void ceph_fscache_readpage_cancel(struct inode *inode, - struct page *page) -{ -} - -static inline void ceph_fscache_readpages_cancel(struct inode *inode, - struct list_head *pages) -{ -} - -static inline void ceph_disable_fscache_readpage(struct ceph_inode_info *ci) -{ -} - #endif -#endif +#endif /* _CEPH_CACHE_H */ diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index e4fc99afa25a..1b1a83b6dd17 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -13,6 +13,9 @@ #include "super.h" #include "mds_client.h" #include "cache.h" +#ifdef CONFIG_SYNO_CEPH_WINACL +#include "syno_acl.h" +#endif /* CONFIG_SYNO_CEPH_WINACL */ #include #include @@ -645,9 +648,7 @@ void ceph_add_cap(struct inode *inode, dout("add_cap %p mds%d cap %llx %s seq %d\n", inode, session->s_mds, cap_id, ceph_cap_string(issued), seq); - spin_lock(&session->s_gen_ttl_lock); - gen = session->s_cap_gen; - spin_unlock(&session->s_gen_ttl_lock); + gen = atomic_read(&session->s_cap_gen); cap = __get_cap_for_mds(ci, mds); if (!cap) { @@ -705,29 +706,12 @@ void ceph_add_cap(struct inode *inode, */ struct ceph_snap_realm *realm = ceph_lookup_snap_realm(mdsc, realmino); - if (realm) { - struct ceph_snap_realm *oldrealm = ci->i_snap_realm; - if (oldrealm) { - spin_lock(&oldrealm->inodes_with_caps_lock); - list_del_init(&ci->i_snap_realm_item); - spin_unlock(&oldrealm->inodes_with_caps_lock); - } - - spin_lock(&realm->inodes_with_caps_lock); - list_add(&ci->i_snap_realm_item, - &realm->inodes_with_caps); - ci->i_snap_realm = realm; - if (realm->ino == ci->i_vino.ino) - realm->inode = inode; - spin_unlock(&realm->inodes_with_caps_lock); - - if (oldrealm) - ceph_put_snap_realm(mdsc, oldrealm); - } else { - pr_err("ceph_add_cap: couldn't find snap realm %llx\n", - realmino); - WARN_ON(!realm); - } + if (realm) + ceph_change_snap_realm(inode, realm); + else + WARN(1, "%s: couldn't find snap realm 0x%llx (ino 0x%llx oldrealm 0x%llx)\n", + __func__, realmino, ci->i_vino.ino, + ci->i_snap_realm ? ci->i_snap_realm->ino : 0); } __check_cap_issue(ci, cap, issued); @@ -785,10 +769,8 @@ static int __cap_is_valid(struct ceph_cap *cap) unsigned long ttl; u32 gen; - spin_lock(&cap->session->s_gen_ttl_lock); - gen = cap->session->s_cap_gen; + gen = atomic_read(&cap->session->s_cap_gen); ttl = cap->session->s_cap_ttl; - spin_unlock(&cap->session->s_gen_ttl_lock); if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) { dout("__cap_is_valid %p cap %p issued %s " @@ -1116,20 +1098,6 @@ int ceph_is_any_caps(struct inode *inode) return ret; } -static void drop_inode_snap_realm(struct ceph_inode_info *ci) -{ - struct ceph_snap_realm *realm = ci->i_snap_realm; - spin_lock(&realm->inodes_with_caps_lock); - list_del_init(&ci->i_snap_realm_item); - ci->i_snap_realm_counter++; - ci->i_snap_realm = NULL; - if (realm->ino == ci->i_vino.ino) - realm->inode = NULL; - spin_unlock(&realm->inodes_with_caps_lock); - ceph_put_snap_realm(ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc, - realm); -} - /* * Remove a cap. Take steps to deal with a racing iterate_session_caps. * @@ -1149,16 +1117,16 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) return; } + lockdep_assert_held(&ci->i_ceph_lock); + dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); mdsc = ceph_inode_to_client(&ci->vfs_inode)->mdsc; /* remove from inode's cap rbtree, and clear auth cap */ rb_erase(&cap->ci_node, &ci->i_caps); - if (ci->i_auth_cap == cap) { - WARN_ON_ONCE(!list_empty(&ci->i_dirty_item)); + if (ci->i_auth_cap == cap) ci->i_auth_cap = NULL; - } /* remove from session list */ spin_lock(&session->s_cap_lock); @@ -1181,7 +1149,8 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) * s_cap_gen while session is in the reconnect state. */ if (queue_release && - (!session->s_cap_reconnect || cap->cap_gen == session->s_cap_gen)) { + (!session->s_cap_reconnect || + cap->cap_gen == atomic_read(&session->s_cap_gen))) { cap->queue_release = 1; if (removed) { __ceph_queue_cap_release(session, cap); @@ -1203,12 +1172,34 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) * keep i_snap_realm. */ if (ci->i_wr_ref == 0 && ci->i_snap_realm) - drop_inode_snap_realm(ci); + ceph_change_snap_realm(&ci->vfs_inode, NULL); __cap_delay_cancel(mdsc, ci); } } +void ceph_remove_cap(struct ceph_cap *cap, bool queue_release) +{ + struct ceph_inode_info *ci = cap->ci; + struct ceph_fs_client *fsc; + + /* 'ci' being NULL means the remove have already occurred */ + if (!ci) { + dout("%s: cap inode is NULL\n", __func__); + return; + } + + lockdep_assert_held(&ci->i_ceph_lock); + + fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); + WARN_ON_ONCE(ci->i_auth_cap == cap && + !list_empty(&ci->i_dirty_item) && + !fsc->blocklisted && + READ_ONCE(fsc->mount_state) != CEPH_MOUNT_SHUTDOWN); + + __ceph_remove_cap(cap, queue_release); +} + struct cap_msg_args { struct ceph_mds_session *session; u64 ino, cid, follows; @@ -1337,7 +1328,7 @@ void __ceph_remove_caps(struct ceph_inode_info *ci) while (p) { struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); p = rb_next(p); - __ceph_remove_cap(cap, true); + ceph_remove_cap(cap, true); } spin_unlock(&ci->i_ceph_lock); } @@ -1389,7 +1380,7 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, arg->flush_tid = flush_tid; arg->oldest_flush_tid = oldest_flush_tid; - arg->size = inode->i_size; + arg->size = i_size_read(inode); ci->i_reported_size = arg->size; arg->max_size = ci->i_wanted_max_size; if (cap == ci->i_auth_cap) { @@ -1533,7 +1524,7 @@ static inline int __send_flush_snap(struct inode *inode, * asynchronously back to the MDS once sync writes complete and dirty * data is written out. * - * Called under i_ceph_lock. Takes s_mutex as needed. + * Called under i_ceph_lock. */ static void __ceph_flush_snaps(struct ceph_inode_info *ci, struct ceph_mds_session *session) @@ -1655,7 +1646,6 @@ void ceph_flush_snaps(struct ceph_inode_info *ci, mds = ci->i_auth_cap->session->s_mds; if (session && session->s_mds != mds) { dout(" oops, wrong session %p mutex\n", session); - mutex_unlock(&session->s_mutex); ceph_put_mds_session(session); session = NULL; } @@ -1664,10 +1654,6 @@ void ceph_flush_snaps(struct ceph_inode_info *ci, mutex_lock(&mdsc->mutex); session = __ceph_lookup_mds_session(mdsc, mds); mutex_unlock(&mdsc->mutex); - if (session) { - dout(" inverting session/ino locks on %p\n", session); - mutex_lock(&session->s_mutex); - } goto retry; } @@ -1679,12 +1665,10 @@ void ceph_flush_snaps(struct ceph_inode_info *ci, out: spin_unlock(&ci->i_ceph_lock); - if (psession) { + if (psession) *psession = session; - } else if (session) { - mutex_unlock(&session->s_mutex); + else ceph_put_mds_session(session); - } /* we flushed them all; remove this inode from the queue */ spin_lock(&mdsc->snap_flush_lock); list_del_init(&ci->i_snap_flush_item); @@ -1752,7 +1736,14 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask, struct ceph_cap_flush *ceph_alloc_cap_flush(void) { - return kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL); + struct ceph_cap_flush *cf; + + cf = kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL); + if (!cf) + return NULL; + + cf->is_capsnap = false; + return cf; } void ceph_free_cap_flush(struct ceph_cap_flush *cf) @@ -1787,7 +1778,7 @@ static bool __detach_cap_flush_from_mdsc(struct ceph_mds_client *mdsc, prev->wake = true; wake = false; } - list_del(&cf->g_list); + list_del_init(&cf->g_list); return wake; } @@ -1802,7 +1793,7 @@ static bool __detach_cap_flush_from_ci(struct ceph_inode_info *ci, prev->wake = true; wake = false; } - list_del(&cf->i_list); + list_del_init(&cf->i_list); return wake; } @@ -1861,6 +1852,8 @@ static u64 __mark_caps_flushing(struct inode *inode, * try to invalidate mapping pages without blocking. */ static int try_nonblocking_invalidate(struct inode *inode) + __releases(ci->i_ceph_lock) + __acquires(ci->i_ceph_lock) { struct ceph_inode_info *ci = ceph_inode(inode); u32 invalidating_gen = ci->i_rdcache_gen; @@ -1884,7 +1877,7 @@ static int try_nonblocking_invalidate(struct inode *inode) bool __ceph_should_report_size(struct ceph_inode_info *ci) { - loff_t size = ci->vfs_inode.i_size; + loff_t size = i_size_read(&ci->vfs_inode); /* mds will adjust max size according to the reported size */ if (ci->i_flushing_caps & CEPH_CAP_FILE_WR) return false; @@ -1914,7 +1907,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_cap *cap; u64 flush_tid, oldest_flush_tid; int file_wanted, used, cap_used; - int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */ int issued, implemented, want, retain, revoking, flushing = 0; int mds = -1; /* keep track of how far we've gone through i_caps list to avoid an infinite loop on retry */ @@ -1922,14 +1914,13 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, bool queue_invalidate = false; bool tried_invalidate = false; + if (session) + ceph_get_mds_session(session); + spin_lock(&ci->i_ceph_lock); if (ci->i_ceph_flags & CEPH_I_FLUSH) flags |= CHECK_CAPS_FLUSH; - - goto retry_locked; retry: - spin_lock(&ci->i_ceph_lock); -retry_locked: /* Caps wanted by virtue of active open files. */ file_wanted = __ceph_caps_file_wanted(ci); @@ -2009,7 +2000,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, ci->i_rdcache_revoking = ci->i_rdcache_gen; } tried_invalidate = true; - goto retry_locked; + goto retry; } for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { @@ -2023,8 +2014,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, ((flags & CHECK_CAPS_AUTHONLY) && cap != ci->i_auth_cap)) continue; - /* NOTE: no side-effects allowed, until we take s_mutex */ - /* * If we have an auth cap, we don't need to consider any * overlapping caps as used. @@ -2087,37 +2076,8 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, continue; /* nope, all good */ ack: - if (session && session != cap->session) { - dout("oops, wrong session %p mutex\n", session); - mutex_unlock(&session->s_mutex); - session = NULL; - } - if (!session) { - session = cap->session; - if (mutex_trylock(&session->s_mutex) == 0) { - dout("inverting session/ino locks on %p\n", - session); - session = ceph_get_mds_session(session); - spin_unlock(&ci->i_ceph_lock); - if (took_snap_rwsem) { - up_read(&mdsc->snap_rwsem); - took_snap_rwsem = 0; - } - if (session) { - mutex_lock(&session->s_mutex); - ceph_put_mds_session(session); - } else { - /* - * Because we take the reference while - * holding the i_ceph_lock, it should - * never be NULL. Throw a warning if it - * ever is. - */ - WARN_ON_ONCE(true); - } - goto retry; - } - } + ceph_put_mds_session(session); + session = ceph_get_mds_session(cap->session); /* kick flushing and flush snaps before sending normal * cap message */ @@ -2129,20 +2089,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, if (ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS) __ceph_flush_snaps(ci, session); - goto retry_locked; - } - - /* take snap_rwsem after session mutex */ - if (!took_snap_rwsem) { - if (down_read_trylock(&mdsc->snap_rwsem) == 0) { - dout("inverting snap/in locks on %p\n", - inode); - spin_unlock(&ci->i_ceph_lock); - down_read(&mdsc->snap_rwsem); - took_snap_rwsem = 1; - goto retry; - } - took_snap_rwsem = 1; + goto retry; } if (cap == ci->i_auth_cap && ci->i_dirty_caps) { @@ -2164,9 +2111,10 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, __prep_cap(&arg, cap, CEPH_CAP_OP_UPDATE, mflags, cap_used, want, retain, flushing, flush_tid, oldest_flush_tid); - spin_unlock(&ci->i_ceph_lock); + spin_unlock(&ci->i_ceph_lock); __send_cap(&arg, ci); + spin_lock(&ci->i_ceph_lock); goto retry; /* retake i_ceph_lock and restart our cap scan. */ } @@ -2181,13 +2129,9 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, spin_unlock(&ci->i_ceph_lock); + ceph_put_mds_session(session); if (queue_invalidate) ceph_queue_invalidate(inode); - - if (session) - mutex_unlock(&session->s_mutex); - if (took_snap_rwsem) - up_read(&mdsc->snap_rwsem); } /* @@ -2197,26 +2141,17 @@ static int try_flush_caps(struct inode *inode, u64 *ptid) { struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); - struct ceph_mds_session *session = NULL; int flushing = 0; u64 flush_tid = 0, oldest_flush_tid = 0; -retry: spin_lock(&ci->i_ceph_lock); retry_locked: if (ci->i_dirty_caps && ci->i_auth_cap) { struct ceph_cap *cap = ci->i_auth_cap; struct cap_msg_args arg; + struct ceph_mds_session *session = cap->session; - if (session != cap->session) { - spin_unlock(&ci->i_ceph_lock); - if (session) - mutex_unlock(&session->s_mutex); - session = cap->session; - mutex_lock(&session->s_mutex); - goto retry; - } - if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) { + if (session->s_state < CEPH_MDS_SESSION_OPEN) { spin_unlock(&ci->i_ceph_lock); goto out; } @@ -2253,9 +2188,6 @@ static int try_flush_caps(struct inode *inode, u64 *ptid) spin_unlock(&ci->i_ceph_lock); } out: - if (session) - mutex_unlock(&session->s_mutex); - *ptid = flush_tid; return flushing; } @@ -2285,8 +2217,10 @@ static int caps_are_flushed(struct inode *inode, u64 flush_tid) */ static int unsafe_request_wait(struct inode *inode) { + struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_mds_request *req1 = NULL, *req2 = NULL; + unsigned int max_sessions; int ret, err = 0; spin_lock(&ci->i_unsafe_lock); @@ -2304,6 +2238,99 @@ static int unsafe_request_wait(struct inode *inode) } spin_unlock(&ci->i_unsafe_lock); + /* + * The mdsc->max_sessions is unlikely to be changed + * mostly, here we will retry it by reallocating the + * sessions array memory to get rid of the mdsc->mutex + * lock. + */ +retry: + max_sessions = mdsc->max_sessions; + + /* + * Trigger to flush the journal logs in all the relevant MDSes + * manually, or in the worst case we must wait at most 5 seconds + * to wait the journal logs to be flushed by the MDSes periodically. + */ + if ((req1 || req2) && likely(max_sessions)) { + struct ceph_mds_session **sessions = NULL; + struct ceph_mds_session *s; + struct ceph_mds_request *req; + int i; + + sessions = kzalloc(max_sessions * sizeof(s), GFP_KERNEL); + if (!sessions) { + err = -ENOMEM; + goto out; + } + + spin_lock(&ci->i_unsafe_lock); + if (req1) { + list_for_each_entry(req, &ci->i_unsafe_dirops, + r_unsafe_dir_item) { + s = req->r_session; + if (!s) + continue; + if (unlikely(s->s_mds >= max_sessions)) { + spin_unlock(&ci->i_unsafe_lock); + for (i = 0; i < max_sessions; i++) { + s = sessions[i]; + if (s) + ceph_put_mds_session(s); + } + kfree(sessions); + goto retry; + } + if (!sessions[s->s_mds]) { + s = ceph_get_mds_session(s); + sessions[s->s_mds] = s; + } + } + } + if (req2) { + list_for_each_entry(req, &ci->i_unsafe_iops, + r_unsafe_target_item) { + s = req->r_session; + if (!s) + continue; + if (unlikely(s->s_mds >= max_sessions)) { + spin_unlock(&ci->i_unsafe_lock); + for (i = 0; i < max_sessions; i++) { + s = sessions[i]; + if (s) + ceph_put_mds_session(s); + } + kfree(sessions); + goto retry; + } + if (!sessions[s->s_mds]) { + s = ceph_get_mds_session(s); + sessions[s->s_mds] = s; + } + } + } + spin_unlock(&ci->i_unsafe_lock); + + /* the auth MDS */ + spin_lock(&ci->i_ceph_lock); + if (ci->i_auth_cap) { + s = ci->i_auth_cap->session; + if (!sessions[s->s_mds]) + sessions[s->s_mds] = ceph_get_mds_session(s); + } + spin_unlock(&ci->i_ceph_lock); + + /* send flush mdlog request to MDSes */ + for (i = 0; i < max_sessions; i++) { + s = sessions[i]; + if (s) { + send_flush_mdlog(s); + ceph_put_mds_session(s); + } + } + kfree(sessions); + } + dout("unsafe_request_wait %p wait on tid %llu %llu\n", inode, req1 ? req1->r_tid : 0ULL, req2 ? req2->r_tid : 0ULL); if (req1) { @@ -2311,21 +2338,24 @@ static int unsafe_request_wait(struct inode *inode) ceph_timeout_jiffies(req1->r_timeout)); if (ret) err = -EIO; - ceph_mdsc_put_request(req1); } if (req2) { ret = !wait_for_completion_timeout(&req2->r_safe_completion, ceph_timeout_jiffies(req2->r_timeout)); if (ret) err = -EIO; - ceph_mdsc_put_request(req2); } + +out: + if (req1) + ceph_mdsc_put_request(req1); + if (req2) + ceph_mdsc_put_request(req2); return err; } int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) { - struct ceph_file_info *fi = file->private_data; struct inode *inode = file->f_mapping->host; struct ceph_inode_info *ci = ceph_inode(inode); u64 flush_tid; @@ -2360,14 +2390,9 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) if (err < 0) ret = err; - if (errseq_check(&ci->i_meta_err, READ_ONCE(fi->meta_err))) { - spin_lock(&file->f_lock); - err = errseq_check_and_advance(&ci->i_meta_err, - &fi->meta_err); - spin_unlock(&file->f_lock); - if (err < 0) - ret = err; - } + err = file_check_and_advance_wb_err(file); + if (err < 0) + ret = err; out: dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret); return ret; @@ -2422,7 +2447,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH; list_for_each_entry_reverse(cf, &ci->i_cap_flush_list, i_list) { - if (!cf->caps) { + if (cf->is_capsnap) { last_snap_flush = cf->tid; break; } @@ -2441,7 +2466,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, first_tid = cf->tid + 1; - if (cf->caps) { + if (!cf->is_capsnap) { struct cap_msg_args arg; dout("kick_flushing_caps %p cap %p tid %llu %s\n", @@ -2730,10 +2755,6 @@ static int try_get_cap_refs(struct inode *inode, int need, int want, *got = need | want; else *got = need; - if (S_ISREG(inode->i_mode) && - (need & CEPH_CAP_FILE_RD) && - !(*got & CEPH_CAP_FILE_CACHE)) - ceph_disable_fscache_readpage(ci); ceph_take_cap_refs(ci, *got, true); ret = 1; } @@ -2754,7 +2775,7 @@ static int try_get_cap_refs(struct inode *inode, int need, int want, goto out_unlock; } - if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + if (READ_ONCE(mdsc->fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) { dout("get_cap_refs %p forced umount\n", inode); ret = -EIO; goto out_unlock; @@ -2858,8 +2879,7 @@ int ceph_try_get_caps(struct inode *inode, int need, int want, * due to a small max_size, make sure we check_max_size (and possibly * ask the mds) so we don't get hung up indefinitely. */ -int ceph_get_caps(struct file *filp, int need, int want, - loff_t endoff, int *got, struct page **pinned_page) +int ceph_get_caps(struct file *filp, int need, int want, loff_t endoff, int *got) { struct ceph_file_info *fi = filp->private_data; struct inode *inode = file_inode(filp); @@ -2957,11 +2977,11 @@ int ceph_get_caps(struct file *filp, int need, int want, struct page *page = find_get_page(inode->i_mapping, 0); if (page) { - if (PageUptodate(page)) { - *pinned_page = page; - break; - } + bool uptodate = PageUptodate(page); + put_page(page); + if (uptodate) + break; } /* * drop cap refs first because getattr while @@ -2983,11 +3003,6 @@ int ceph_get_caps(struct file *filp, int need, int want, } break; } - - if (S_ISREG(ci->vfs_inode.i_mode) && - (_got & CEPH_CAP_FILE_RD) && (_got & CEPH_CAP_FILE_CACHE)) - ceph_fscache_revalidate_cookie(ci); - *got = _got; return 0; } @@ -3027,6 +3042,12 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci, return 0; } +enum put_cap_refs_mode { + PUT_CAP_REFS_SYNC = 0, + PUT_CAP_REFS_NO_CHECK, + PUT_CAP_REFS_ASYNC, +}; + /* * Release cap refs. * @@ -3037,10 +3058,11 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci, * cap_snap, and wake up any waiters. */ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had, - bool skip_checking_caps) + enum put_cap_refs_mode mode) { struct inode *inode = &ci->vfs_inode; int last = 0, put = 0, flushsnaps = 0, wake = 0; + bool check_flushsnaps = false; spin_lock(&ci->i_ceph_lock); if (had & CEPH_CAP_PIN) @@ -3057,26 +3079,17 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had, if (had & CEPH_CAP_FILE_BUFFER) { if (--ci->i_wb_ref == 0) { last++; + /* put the ref held by ceph_take_cap_refs() */ put++; + check_flushsnaps = true; } dout("put_cap_refs %p wb %d -> %d (?)\n", inode, ci->i_wb_ref+1, ci->i_wb_ref); } - if (had & CEPH_CAP_FILE_WR) + if (had & CEPH_CAP_FILE_WR) { if (--ci->i_wr_ref == 0) { last++; - if (__ceph_have_pending_cap_snap(ci)) { - struct ceph_cap_snap *capsnap = - list_last_entry(&ci->i_cap_snaps, - struct ceph_cap_snap, - ci_item); - capsnap->writing = 0; - if (ceph_try_drop_cap_snap(ci, capsnap)) - put++; - else if (__ceph_finish_cap_snap(ci, capsnap)) - flushsnaps = 1; - wake = 1; - } + check_flushsnaps = true; if (ci->i_wrbuffer_ref_head == 0 && ci->i_dirty_caps == 0 && ci->i_flushing_caps == 0) { @@ -3086,18 +3099,43 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had, } /* see comment in __ceph_remove_cap() */ if (!__ceph_is_any_real_caps(ci) && ci->i_snap_realm) - drop_inode_snap_realm(ci); + ceph_change_snap_realm(inode, NULL); } + } + if (check_flushsnaps && __ceph_have_pending_cap_snap(ci)) { + struct ceph_cap_snap *capsnap = + list_last_entry(&ci->i_cap_snaps, + struct ceph_cap_snap, + ci_item); + + capsnap->writing = 0; + if (ceph_try_drop_cap_snap(ci, capsnap)) + /* put the ref held by ceph_queue_cap_snap() */ + put++; + else if (__ceph_finish_cap_snap(ci, capsnap)) + flushsnaps = 1; + wake = 1; + } spin_unlock(&ci->i_ceph_lock); dout("put_cap_refs %p had %s%s%s\n", inode, ceph_cap_string(had), last ? " last" : "", put ? " put" : ""); - if (!skip_checking_caps) { + switch (mode) { + case PUT_CAP_REFS_SYNC: if (last) ceph_check_caps(ci, 0, NULL); else if (flushsnaps) ceph_flush_snaps(ci, NULL); + break; + case PUT_CAP_REFS_ASYNC: + if (last) + ceph_queue_check_caps(inode); + else if (flushsnaps) + ceph_queue_flush_snaps(inode); + break; + default: + break; } if (wake) wake_up_all(&ci->i_cap_wq); @@ -3107,12 +3145,17 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had, void ceph_put_cap_refs(struct ceph_inode_info *ci, int had) { - __ceph_put_cap_refs(ci, had, false); + __ceph_put_cap_refs(ci, had, PUT_CAP_REFS_SYNC); +} + +void ceph_put_cap_refs_async(struct ceph_inode_info *ci, int had) +{ + __ceph_put_cap_refs(ci, had, PUT_CAP_REFS_ASYNC); } void ceph_put_cap_refs_no_check_caps(struct ceph_inode_info *ci, int had) { - __ceph_put_cap_refs(ci, had, true); + __ceph_put_cap_refs(ci, had, PUT_CAP_REFS_NO_CHECK); } /* @@ -3162,7 +3205,16 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, break; } } - BUG_ON(!found); + + if (!found) { + /* + * The capsnap should already be removed when removing + * auth cap in the case of a forced unmount. + */ + WARN_ON_ONCE(ci->i_auth_cap); + goto unlock; + } + capsnap->dirty_pages -= nr; if (capsnap->dirty_pages == 0) { complete_capsnap = true; @@ -3184,6 +3236,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, complete_capsnap ? " (complete capsnap)" : ""); } +unlock: spin_unlock(&ci->i_ceph_lock); if (last) { @@ -3194,8 +3247,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, if (complete_capsnap) wake_up_all(&ci->i_cap_wq); while (put-- > 0) { - /* avoid calling iput_final() in osd dispatch threads */ - ceph_async_iput(inode); + iput(inode); } } @@ -3269,7 +3321,7 @@ static void handle_cap_grant(struct inode *inode, u64 size = le64_to_cpu(grant->size); u64 max_size = le64_to_cpu(grant->max_size); unsigned char check_caps = 0; - bool was_stale = cap->cap_gen < session->s_cap_gen; + bool was_stale = cap->cap_gen < atomic_read(&session->s_cap_gen); bool wake = false; bool writeback = false; bool queue_trunc = false; @@ -3280,7 +3332,7 @@ static void handle_cap_grant(struct inode *inode, dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n", inode, cap, session->s_mds, seq, ceph_cap_string(newcaps)); dout(" size %llu max_size %llu, i_size %llu\n", size, max_size, - inode->i_size); + i_size_read(inode)); /* @@ -3321,7 +3373,7 @@ static void handle_cap_grant(struct inode *inode, } /* side effects now are allowed */ - cap->cap_gen = session->s_cap_gen; + cap->cap_gen = atomic_read(&session->s_cap_gen); cap->seq = seq; __check_cap_issue(ci, cap, newcaps); @@ -3360,6 +3412,9 @@ static void handle_cap_grant(struct inode *inode, ci->i_xattrs.blob = ceph_buffer_get(xattr_buf); ci->i_xattrs.version = version; ceph_forget_all_cached_acls(inode); +#ifdef CONFIG_SYNO_CEPH_WINACL + forget_cached_syno_acl(inode); +#endif /* CONFIG_SYNO_CEPH_WINACL */ ceph_security_invalidate_secctx(inode); } } @@ -3488,24 +3543,23 @@ static void handle_cap_grant(struct inode *inode, fill_inline = true; } - if (ci->i_auth_cap == cap && - le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { - if (newcaps & ~extra_info->issued) - wake = true; + if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) { + if (ci->i_auth_cap == cap) { + if (newcaps & ~extra_info->issued) + wake = true; - if (ci->i_requested_max_size > max_size || - !(le32_to_cpu(grant->wanted) & CEPH_CAP_ANY_FILE_WR)) { - /* re-request max_size if necessary */ - ci->i_requested_max_size = 0; - wake = true; + if (ci->i_requested_max_size > max_size || + !(le32_to_cpu(grant->wanted) & CEPH_CAP_ANY_FILE_WR)) { + /* re-request max_size if necessary */ + ci->i_requested_max_size = 0; + wake = true; + } + + ceph_kick_flushing_inode_caps(session, ci); } - - ceph_kick_flushing_inode_caps(session, ci); - spin_unlock(&ci->i_ceph_lock); up_read(&session->s_mdsc->snap_rwsem); - } else { - spin_unlock(&ci->i_ceph_lock); } + spin_unlock(&ci->i_ceph_lock); if (fill_inline) ceph_fill_inline_data(inode, NULL, extra_info->inline_data, @@ -3528,13 +3582,12 @@ static void handle_cap_grant(struct inode *inode, if (wake) wake_up_all(&ci->i_cap_wq); + mutex_unlock(&session->s_mutex); if (check_caps == 1) ceph_check_caps(ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL, session); else if (check_caps == 2) ceph_check_caps(ci, CHECK_CAPS_NOINVAL, session); - else - mutex_unlock(&session->s_mutex); } /* @@ -3564,7 +3617,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, cleaned = cf->caps; /* Is this a capsnap? */ - if (cf->caps == 0) + if (cf->is_capsnap) continue; if (cf->tid <= flush_tid) { @@ -3637,8 +3690,9 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, while (!list_empty(&to_remove)) { cf = list_first_entry(&to_remove, struct ceph_cap_flush, i_list); - list_del(&cf->i_list); - ceph_free_cap_flush(cf); + list_del_init(&cf->i_list); + if (!cf->is_capsnap) + ceph_free_cap_flush(cf); } if (wake_ci) @@ -3649,6 +3703,43 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, iput(inode); } +void __ceph_remove_capsnap(struct inode *inode, struct ceph_cap_snap *capsnap, + bool *wake_ci, bool *wake_mdsc) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; + bool ret; + + lockdep_assert_held(&ci->i_ceph_lock); + + dout("removing capsnap %p, inode %p ci %p\n", capsnap, inode, ci); + + list_del_init(&capsnap->ci_item); + ret = __detach_cap_flush_from_ci(ci, &capsnap->cap_flush); + if (wake_ci) + *wake_ci = ret; + + spin_lock(&mdsc->cap_dirty_lock); + if (list_empty(&ci->i_cap_flush_list)) + list_del_init(&ci->i_flushing_item); + + ret = __detach_cap_flush_from_mdsc(mdsc, &capsnap->cap_flush); + if (wake_mdsc) + *wake_mdsc = ret; + spin_unlock(&mdsc->cap_dirty_lock); +} + +void ceph_remove_capsnap(struct inode *inode, struct ceph_cap_snap *capsnap, + bool *wake_ci, bool *wake_mdsc) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + + lockdep_assert_held(&ci->i_ceph_lock); + + WARN_ON_ONCE(capsnap->dirty_pages || capsnap->writing); + __ceph_remove_capsnap(inode, capsnap, wake_ci, wake_mdsc); +} + /* * Handle FLUSHSNAP_ACK. MDS has flushed snap data to disk and we can * throw away our cap_snap. @@ -3686,23 +3777,10 @@ static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid, capsnap, capsnap->follows); } } - if (flushed) { - WARN_ON(capsnap->dirty_pages || capsnap->writing); - dout(" removing %p cap_snap %p follows %lld\n", - inode, capsnap, follows); - list_del(&capsnap->ci_item); - wake_ci |= __detach_cap_flush_from_ci(ci, &capsnap->cap_flush); - - spin_lock(&mdsc->cap_dirty_lock); - - if (list_empty(&ci->i_cap_flush_list)) - list_del_init(&ci->i_flushing_item); - - wake_mdsc |= __detach_cap_flush_from_mdsc(mdsc, - &capsnap->cap_flush); - spin_unlock(&mdsc->cap_dirty_lock); - } + if (flushed) + ceph_remove_capsnap(inode, capsnap, &wake_ci, &wake_mdsc); spin_unlock(&ci->i_ceph_lock); + if (flushed) { ceph_put_snap_context(capsnap->context); ceph_put_cap_snap(capsnap); @@ -3786,7 +3864,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, goto out_unlock; if (target < 0) { - __ceph_remove_cap(cap, false); + ceph_remove_cap(cap, false); goto out_unlock; } @@ -3821,7 +3899,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, change_auth_cap_ses(ci, tcap->session); } } - __ceph_remove_cap(cap, false); + ceph_remove_cap(cap, false); goto out_unlock; } else if (tsession) { /* add placeholder for the export tagert */ @@ -3838,7 +3916,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, spin_unlock(&mdsc->cap_dirty_lock); } - __ceph_remove_cap(cap, false); + ceph_remove_cap(cap, false); goto out_unlock; } @@ -3949,7 +4027,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, ocap->mseq, mds, le32_to_cpu(ph->seq), le32_to_cpu(ph->mseq)); } - __ceph_remove_cap(ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); + ceph_remove_cap(ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); } *old_issued = issued; @@ -4037,15 +4115,13 @@ void ceph_handle_caps(struct ceph_mds_session *session, } if (msg_version >= 8) { - u64 flush_tid; - u32 caller_uid, caller_gid; u32 pool_ns_len; /* version >= 6 */ - ceph_decode_64_safe(&p, end, flush_tid, bad); + ceph_decode_skip_64(&p, end, bad); // flush_tid /* version >= 7 */ - ceph_decode_32_safe(&p, end, caller_uid, bad); - ceph_decode_32_safe(&p, end, caller_gid, bad); + ceph_decode_skip_32(&p, end, bad); // caller_uid + ceph_decode_skip_32(&p, end, bad); // caller_gid /* version >= 8 */ ceph_decode_32_safe(&p, end, pool_ns_len, bad); if (pool_ns_len > 0) { @@ -4068,9 +4144,8 @@ void ceph_handle_caps(struct ceph_mds_session *session, } if (msg_version >= 11) { - u32 flags; /* version >= 10 */ - ceph_decode_32_safe(&p, end, flags, bad); + ceph_decode_skip_32(&p, end, bad); // flags /* version >= 11 */ extra_info.dirstat_valid = true; ceph_decode_64_safe(&p, end, extra_info.nfiles, bad); @@ -4180,9 +4255,9 @@ void ceph_handle_caps(struct ceph_mds_session *session, done: mutex_unlock(&session->s_mutex); done_unlocked: + iput(inode); +out: ceph_put_string(extra_info.pool_ns); - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(inode); return; flush_cap_releases: @@ -4197,16 +4272,24 @@ void ceph_handle_caps(struct ceph_mds_session *session, bad: pr_err("ceph_handle_caps: corrupt message\n"); ceph_msg_dump(msg); - return; + goto out; } /* * Delayed work handler to process end of delayed cap release LRU list. + * + * If new caps are added to the list while processing it, these won't get + * processed in this run. In this case, the ci->i_hold_caps_max will be + * returned so that the work can be scheduled accordingly. */ -void ceph_check_delayed_caps(struct ceph_mds_client *mdsc) +unsigned long ceph_check_delayed_caps(struct ceph_mds_client *mdsc) { struct inode *inode; struct ceph_inode_info *ci; + struct ceph_mount_options *opt = mdsc->fsc->mount_options; + unsigned long delay_max = opt->caps_wanted_delay_max * HZ; + unsigned long loop_start = jiffies; + unsigned long delay = 0; dout("check_delayed_caps\n"); spin_lock(&mdsc->cap_delay_lock); @@ -4214,6 +4297,11 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc) ci = list_first_entry(&mdsc->cap_delay_list, struct ceph_inode_info, i_cap_delay_list); + if (time_before(loop_start, ci->i_hold_caps_max - delay_max)) { + dout("%s caps added recently. Exiting loop", __func__); + delay = ci->i_hold_caps_max; + break; + } if ((ci->i_ceph_flags & CEPH_I_FLUSH) == 0 && time_before(jiffies, ci->i_hold_caps_max)) break; @@ -4224,12 +4312,13 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc) spin_unlock(&mdsc->cap_delay_lock); dout("check_delayed_caps on %p\n", inode); ceph_check_caps(ci, 0, NULL); - /* avoid calling iput_final() in tick thread */ - ceph_async_iput(inode); + iput(inode); spin_lock(&mdsc->cap_delay_lock); } } spin_unlock(&mdsc->cap_delay_lock); + + return delay; } /* @@ -4258,33 +4347,9 @@ static void flush_dirty_session_caps(struct ceph_mds_session *s) dout("flush_dirty_caps done\n"); } -static void iterate_sessions(struct ceph_mds_client *mdsc, - void (*cb)(struct ceph_mds_session *)) -{ - int mds; - - mutex_lock(&mdsc->mutex); - for (mds = 0; mds < mdsc->max_sessions; ++mds) { - struct ceph_mds_session *s; - - if (!mdsc->sessions[mds]) - continue; - - s = ceph_get_mds_session(mdsc->sessions[mds]); - if (!s) - continue; - - mutex_unlock(&mdsc->mutex); - cb(s); - ceph_put_mds_session(s); - mutex_lock(&mdsc->mutex); - } - mutex_unlock(&mdsc->mutex); -} - void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) { - iterate_sessions(mdsc, flush_dirty_session_caps); + ceph_mdsc_iterate_sessions(mdsc, flush_dirty_session_caps, true); } void __ceph_touch_fmode(struct ceph_inode_info *ci, @@ -4306,7 +4371,7 @@ void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count) { struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(ci->vfs_inode.i_sb); int bits = (fmode << 1) | 1; - bool is_opened = false; + bool already_opened = false; int i; if (count == 1) @@ -4314,19 +4379,19 @@ void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count) spin_lock(&ci->i_ceph_lock); for (i = 0; i < CEPH_FILE_MODE_BITS; i++) { - if (bits & (1 << i)) - ci->i_nr_by_mode[i] += count; - /* - * If any of the mode ref is larger than 1, + * If any of the mode ref is larger than 0, * that means it has been already opened by * others. Just skip checking the PIN ref. */ - if (i && ci->i_nr_by_mode[i] > 1) - is_opened = true; + if (i && ci->i_nr_by_mode[i]) + already_opened = true; + + if (bits & (1 << i)) + ci->i_nr_by_mode[i] += count; } - if (!is_opened) + if (!already_opened) percpu_counter_inc(&mdsc->metric.opened_inodes); spin_unlock(&ci->i_ceph_lock); } diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 7a8fbe3e4751..38b78b45811f 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -127,7 +127,7 @@ static int mdsc_show(struct seq_file *s, void *p) return 0; } -#define CEPH_METRIC_SHOW(name, total, avg, min, max, sq) { \ +#define CEPH_LAT_METRIC_SHOW(name, total, avg, min, max, sq) { \ s64 _total, _avg, _min, _max, _sq, _st; \ _avg = ktime_to_us(avg); \ _min = ktime_to_us(min == KTIME_MAX ? 0 : min); \ @@ -140,6 +140,12 @@ static int mdsc_show(struct seq_file *s, void *p) name, total, _avg, _min, _max, _st); \ } +#define CEPH_SZ_METRIC_SHOW(name, total, avg, min, max, sum) { \ + u64 _min = min == U64_MAX ? 0 : min; \ + seq_printf(s, "%-14s%-12lld%-16llu%-16llu%-16llu%llu\n", \ + name, total, avg, _min, max, sum); \ +} + static int metric_show(struct seq_file *s, void *p) { struct ceph_fs_client *fsc = s->private; @@ -147,6 +153,7 @@ static int metric_show(struct seq_file *s, void *p) struct ceph_client_metric *m = &mdsc->metric; int nr_caps = 0; s64 total, sum, avg, min, max, sq; + u64 sum_sz, avg_sz, min_sz, max_sz; sum = percpu_counter_sum(&m->total_inodes); seq_printf(s, "item total\n"); @@ -162,35 +169,57 @@ static int metric_show(struct seq_file *s, void *p) seq_printf(s, "item total avg_lat(us) min_lat(us) max_lat(us) stdev(us)\n"); seq_printf(s, "-----------------------------------------------------------------------------------\n"); - spin_lock(&m->read_latency_lock); + spin_lock(&m->read_metric_lock); total = m->total_reads; sum = m->read_latency_sum; avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0; min = m->read_latency_min; max = m->read_latency_max; sq = m->read_latency_sq_sum; - spin_unlock(&m->read_latency_lock); - CEPH_METRIC_SHOW("read", total, avg, min, max, sq); + spin_unlock(&m->read_metric_lock); + CEPH_LAT_METRIC_SHOW("read", total, avg, min, max, sq); - spin_lock(&m->write_latency_lock); + spin_lock(&m->write_metric_lock); total = m->total_writes; sum = m->write_latency_sum; avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0; min = m->write_latency_min; max = m->write_latency_max; sq = m->write_latency_sq_sum; - spin_unlock(&m->write_latency_lock); - CEPH_METRIC_SHOW("write", total, avg, min, max, sq); + spin_unlock(&m->write_metric_lock); + CEPH_LAT_METRIC_SHOW("write", total, avg, min, max, sq); - spin_lock(&m->metadata_latency_lock); + spin_lock(&m->metadata_metric_lock); total = m->total_metadatas; sum = m->metadata_latency_sum; avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0; min = m->metadata_latency_min; max = m->metadata_latency_max; sq = m->metadata_latency_sq_sum; - spin_unlock(&m->metadata_latency_lock); - CEPH_METRIC_SHOW("metadata", total, avg, min, max, sq); + spin_unlock(&m->metadata_metric_lock); + CEPH_LAT_METRIC_SHOW("metadata", total, avg, min, max, sq); + + seq_printf(s, "\n"); + seq_printf(s, "item total avg_sz(bytes) min_sz(bytes) max_sz(bytes) total_sz(bytes)\n"); + seq_printf(s, "----------------------------------------------------------------------------------------\n"); + + spin_lock(&m->read_metric_lock); + total = m->total_reads; + sum_sz = m->read_size_sum; + avg_sz = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum_sz, total) : 0; + min_sz = m->read_size_min; + max_sz = m->read_size_max; + spin_unlock(&m->read_metric_lock); + CEPH_SZ_METRIC_SHOW("read", total, avg_sz, min_sz, max_sz, sum_sz); + + spin_lock(&m->write_metric_lock); + total = m->total_writes; + sum_sz = m->write_size_sum; + avg_sz = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum_sz, total) : 0; + min_sz = m->write_size_min; + max_sz = m->write_size_max; + spin_unlock(&m->write_metric_lock); + CEPH_SZ_METRIC_SHOW("write", total, avg_sz, min_sz, max_sz, sum_sz); seq_printf(s, "\n"); seq_printf(s, "item total miss hit\n"); @@ -304,11 +333,25 @@ static int mds_sessions_show(struct seq_file *s, void *ptr) return 0; } +static int status_show(struct seq_file *s, void *p) +{ + struct ceph_fs_client *fsc = s->private; + struct ceph_entity_inst *inst = &fsc->client->msgr.inst; + struct ceph_entity_addr *client_addr = ceph_client_addr(fsc->client); + + seq_printf(s, "instance: %s.%lld %s/%u\n", ENTITY_NAME(inst->name), + ceph_pr_addr(client_addr), le32_to_cpu(client_addr->nonce)); + seq_printf(s, "blocklisted: %s\n", fsc->blocklisted ? "true" : "false"); + + return 0; +} + DEFINE_SHOW_ATTRIBUTE(mdsmap); DEFINE_SHOW_ATTRIBUTE(mdsc); DEFINE_SHOW_ATTRIBUTE(caps); DEFINE_SHOW_ATTRIBUTE(mds_sessions); DEFINE_SHOW_ATTRIBUTE(metric); +DEFINE_SHOW_ATTRIBUTE(status); /* @@ -394,6 +437,12 @@ void ceph_fs_debugfs_init(struct ceph_fs_client *fsc) fsc->client->debugfs_dir, fsc, &caps_fops); + + fsc->debugfs_status = debugfs_create_file("status", + 0400, + fsc->client->debugfs_dir, + fsc, + &status_fops); } diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index a4d48370b2b3..a2c99463892d 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -9,6 +9,9 @@ #include "super.h" #include "mds_client.h" +#ifdef CONFIG_SYNO_CEPH_WINACL +#include "syno_acl.h" +#endif /* CONFIG_SYNO_CEPH_WINACL */ /* * Directory operations: readdir, lookup, create, link, unlink, @@ -478,8 +481,11 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) 2 : (fpos_off(rde->offset) + 1); err = note_last_dentry(dfi, rde->name, rde->name_len, next_offset); - if (err) + if (err) { + ceph_mdsc_put_request(dfi->last_readdir); + dfi->last_readdir = NULL; return err; + } } else if (req->r_reply_info.dir_end) { dfi->next_offset = 2; /* keep last name */ @@ -520,6 +526,12 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) if (!dir_emit(ctx, rde->name, rde->name_len, ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)), le32_to_cpu(rde->inode.in->mode) >> 12)) { + /* + * NOTE: Here no need to put the 'dfi->last_readdir', + * because when dir_emit stops us it's most likely + * doesn't have enough memory, etc. So for next readdir + * it will continue. + */ dout("filldir stopping us...\n"); return 0; } @@ -631,10 +643,12 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) switch (whence) { case SEEK_CUR: offset += file->f_pos; + break; case SEEK_SET: break; case SEEK_END: retval = -EOPNOTSUPP; + goto out; default: goto out; } @@ -665,25 +679,25 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence) /* * Handle lookups for the hidden .snap directory. */ -int ceph_handle_snapdir(struct ceph_mds_request *req, - struct dentry *dentry, int err) +struct dentry *ceph_handle_snapdir(struct ceph_mds_request *req, + struct dentry *dentry) { struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); struct inode *parent = d_inode(dentry->d_parent); /* we hold i_mutex */ /* .snap dir? */ - if (err == -ENOENT && - ceph_snap(parent) == CEPH_NOSNAP && - strcmp(dentry->d_name.name, - fsc->mount_options->snapdir_name) == 0) { + if (ceph_snap(parent) == CEPH_NOSNAP && + strcmp(dentry->d_name.name, fsc->mount_options->snapdir_name) == 0) { + struct dentry *res; struct inode *inode = ceph_get_snapdir(parent); - dout("ENOENT on snapdir %p '%pd', linking to snapdir %p\n", - dentry, dentry, inode); - BUG_ON(!d_unhashed(dentry)); - d_add(dentry, inode); - err = 0; + + res = d_splice_alias(inode, dentry); + dout("ENOENT on snapdir %p '%pd', linking to snapdir %p. Spliced dentry %p\n", + dentry, dentry, inode, res); + if (res) + dentry = res; } - return err; + return dentry; } /* @@ -785,11 +799,26 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, if (ceph_security_xattr_wanted(dir)) mask |= CEPH_CAP_XATTR_SHARED; req->r_args.getattr.mask = cpu_to_le32(mask); +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + if (flags & LOOKUP_CASELESS_COMPARE) + req->r_args.getattr.flags = cpu_to_le32(CEPH_GETATTR_CASELESS); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ + ihold(dir); req->r_parent = dir; set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); err = ceph_mdsc_do_request(mdsc, NULL, req); - err = ceph_handle_snapdir(req, dentry, err); + if (err == -ENOENT) { + struct dentry *res; + + res = ceph_handle_snapdir(req, dentry); + if (IS_ERR(res)) { + err = PTR_ERR(res); + } else { + dentry = res; + err = 0; + } + } dentry = ceph_finish_lookup(req, dentry, err); ceph_mdsc_put_request(req); /* will dput(dentry) */ dout("lookup result=%p\n", dentry); @@ -823,6 +852,54 @@ int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry) return PTR_ERR(result); } +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT +int ceph_pre_init_archive_bit(struct ceph_acl_sec_ctx *as_ctx) +{ + int err; + __le32 archive_bit = cpu_to_le32(ALL_SYNO_ARCHIVE); + struct ceph_pagelist *pagelist = as_ctx->pagelist; + size_t len = strlen(XATTR_SYNO_ARCHIVE_BIT); + + err = -ENOMEM; + if (!pagelist) { + pagelist = ceph_pagelist_alloc(GFP_KERNEL); + if (!pagelist) + goto out_err; + err = ceph_pagelist_reserve(pagelist, PAGE_SIZE); + if (err) + goto out_err; + ceph_pagelist_encode_32(pagelist, 1); + } + err = ceph_pagelist_reserve(pagelist, 4 + len + 4 + 4); + if (err) + goto out_err; + if (as_ctx->pagelist) { + /* update count of KV pairs */ + if (list_is_singular(&pagelist->head)) { + le32_add_cpu((__le32*)pagelist->mapped_tail, 1); + } else { + struct page *page = list_first_entry(&pagelist->head, + struct page, lru); + void *addr = kmap_atomic(page); + le32_add_cpu((__le32*)addr, 1); + kunmap_atomic(addr); + } + } else { + as_ctx->pagelist = pagelist; + } + ceph_pagelist_encode_32(pagelist, len); + ceph_pagelist_append(pagelist, XATTR_SYNO_ARCHIVE_BIT, len); + ceph_pagelist_encode_32(pagelist, sizeof(__le32)); + ceph_pagelist_append(pagelist, &archive_bit, sizeof(__le32)); + + err = 0; +out_err: + if (pagelist && !as_ctx->pagelist) + ceph_pagelist_release(pagelist); + return err; +} +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ + static int ceph_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { @@ -845,6 +922,11 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, err = ceph_security_init_secctx(dentry, mode, &as_ctx); if (err < 0) goto out; +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + err = ceph_pre_init_archive_bit(&as_ctx); + if (err < 0) + goto out; +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ dout("mknod in dir %p dentry %p mode 0%ho rdev %d\n", dir, dentry, mode, rdev); @@ -856,6 +938,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_args.mknod.mode = cpu_to_le32(mode); req->r_args.mknod.rdev = cpu_to_le32(rdev); @@ -917,6 +1000,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, goto out; } req->r_parent = dir; + ihold(dir); + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_dentry = dget(dentry); req->r_num_caps = 2; @@ -970,6 +1055,11 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) err = ceph_security_init_secctx(dentry, mode, &as_ctx); if (err < 0) goto out; +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + err = ceph_pre_init_archive_bit(&as_ctx); + if (err < 0) + goto out; +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); if (IS_ERR(req)) { @@ -980,6 +1070,7 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_args.mkdir.mode = cpu_to_le32(mode); req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL; @@ -1024,6 +1115,7 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir, req->r_num_caps = 2; req->r_old_dentry = dget(old_dentry); req->r_parent = dir; + ihold(dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_unless = CEPH_CAP_FILE_EXCL; @@ -1145,6 +1237,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry) req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); req->r_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_dentry_unless = CEPH_CAP_FILE_EXCL; req->r_inode_drop = ceph_drop_caps_for_unlink(inode); @@ -1202,12 +1295,11 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, op = CEPH_MDS_OP_RENAMESNAP; else return -EROFS; - } else if (old_dir != new_dir) { - err = ceph_quota_check_rename(mdsc, d_inode(old_dentry), - new_dir); - if (err) - return err; } + /* don't allow cross-quota renames */ + if ((old_dir != new_dir) && + (!ceph_quota_is_same_realm(old_dir, new_dir))) + return -EXDEV; dout("rename dir %p dentry %p to dir %p dentry %p\n", old_dir, old_dentry, new_dir, new_dentry); @@ -1220,6 +1312,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, req->r_old_dentry = dget(old_dentry); req->r_old_dentry_dir = old_dir; req->r_parent = new_dir; + ihold(new_dir); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED; req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL; @@ -1536,10 +1629,8 @@ static bool __dentry_lease_is_valid(struct ceph_dentry_info *di) u32 gen; unsigned long ttl; - spin_lock(&session->s_gen_ttl_lock); - gen = session->s_cap_gen; + gen = atomic_read(&session->s_cap_gen); ttl = session->s_cap_ttl; - spin_unlock(&session->s_gen_ttl_lock); if (di->lease_gen == gen && time_before(jiffies, ttl) && @@ -1718,6 +1809,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) req->r_dentry = dget(dentry); req->r_num_caps = 2; req->r_parent = dir; + ihold(dir); mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED; if (ceph_security_xattr_wanted(dir)) @@ -1797,8 +1889,7 @@ static void ceph_d_release(struct dentry *dentry) dentry->d_fsdata = NULL; spin_unlock(&dentry->d_lock); - if (di->lease_session) - ceph_put_mds_session(di->lease_session); + ceph_put_mds_session(di->lease_session); kmem_cache_free(ceph_dentry_cachep, di); } @@ -1894,8 +1985,44 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size, return size - left; } +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +inline int ceph_upper_full_name_hash(const struct dentry *parent, const char *name, int len, u32 *hash) +{ + /* + * hash_buf need to add 1 byte for syno_utf8_toupper, + * because it will append 0 to last byte. + */ + char hash_buf[NAME_MAX+1]; + unsigned int upperlen; + if (len > NAME_MAX) + return -ENAMETOOLONG; + upperlen = syno_utf8_toupper(hash_buf, name, NAME_MAX, len, NULL); + *hash = full_name_hash(parent, hash_buf, upperlen); + + return 0; +} + +static int ceph_d_hash(const struct dentry *dentry, struct qstr *this) +{ + return ceph_upper_full_name_hash(dentry, this->name, this->len, &this->hash); +} + +/* return 1 on failure and 0 on success */ +static int ceph_d_compare_case(const struct dentry *dentry, unsigned int len, + const char *str, const struct qstr *name, + int caseless) +{ + if (caseless) { + return syno_utf8_strcmp(str, name->name, len, name->len, NULL); + } else { + if (len != name->len) + return 1; + return dentry_cmp(dentry, name->name, name->len); + } +} +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ /* * Return name hash for a given dentry. This is dependent on * the parent directory's hash function. @@ -1912,8 +2039,13 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn) default: spin_lock(&dn->d_lock); +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + hash = ceph_str_upper_hash(dci->i_dir_layout.dl_dir_hash, + dn->d_name.name, dn->d_name.len); +#else hash = ceph_str_hash(dci->i_dir_layout.dl_dir_hash, dn->d_name.name, dn->d_name.len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ spin_unlock(&dn->d_lock); return hash; } @@ -1940,6 +2072,17 @@ const struct file_operations ceph_snapdir_fops = { }; const struct inode_operations ceph_dir_iops = { +#ifdef CONFIG_SYNO_CEPH_STAT + .syno_getattr = ceph_syno_getattr, +#endif /* CONFIG_SYNO_CEPH_STAT */ +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + .syno_get_crtime = ceph_syno_get_crtime, + .syno_set_crtime = ceph_syno_set_crtime, +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + .syno_get_archive_bit = ceph_syno_get_archive_bit, + .syno_set_archive_bit = ceph_syno_set_archive_bit, +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ .lookup = ceph_lookup, .permission = ceph_permission, .getattr = ceph_getattr, @@ -1947,6 +2090,11 @@ const struct inode_operations ceph_dir_iops = { .listxattr = ceph_listxattr, .get_acl = ceph_get_acl, .set_acl = ceph_set_acl, +#ifdef CONFIG_SYNO_CEPH_WINACL + .syno_get_acl = ceph_get_syno_acl, + .syno_set_acl = ceph_set_syno_acl, + .syno_permission = ceph_syno_permission, +#endif /* CONFIG_SYNO_CEPH_WINACL */ .mknod = ceph_mknod, .symlink = ceph_symlink, .mkdir = ceph_mkdir, @@ -1959,6 +2107,17 @@ const struct inode_operations ceph_dir_iops = { }; const struct inode_operations ceph_snapdir_iops = { +#ifdef CONFIG_SYNO_CEPH_STAT + .syno_getattr = ceph_syno_getattr, +#endif /* CONFIG_SYNO_CEPH_STAT */ +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + .syno_get_crtime = ceph_syno_get_crtime, + .syno_set_crtime = ceph_syno_set_crtime, +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + .syno_get_archive_bit = ceph_syno_get_archive_bit, + .syno_set_archive_bit = ceph_syno_set_archive_bit, +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ .lookup = ceph_lookup, .permission = ceph_permission, .getattr = ceph_getattr, @@ -1973,4 +2132,8 @@ const struct dentry_operations ceph_dentry_ops = { .d_release = ceph_d_release, .d_prune = ceph_d_prune, .d_init = ceph_d_init, +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + .d_hash = ceph_d_hash, + .d_compare_case = ceph_d_compare_case, +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ }; diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 042bb4a02c0a..1d65934c1262 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -258,9 +258,10 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb, ihold(inode); } else { /* mds does not support lookup snapped inode */ - err = -EOPNOTSUPP; - inode = NULL; + inode = ERR_PTR(-EOPNOTSUPP); } + } else { + inode = ERR_PTR(-ESTALE); } ceph_mdsc_put_request(req); @@ -271,8 +272,8 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb, dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d", vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err); } - if (!inode) - return ERR_PTR(-ESTALE); + if (IS_ERR(inode)) + return ERR_CAST(inode); /* see comments in ceph_get_parent() */ return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode); } @@ -541,6 +542,7 @@ static int ceph_get_name(struct dentry *parent, char *name, ihold(inode); req->r_ino2 = ceph_vino(d_inode(parent)); req->r_parent = d_inode(parent); + ihold(req->r_parent); set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 3d2e3dd4ee01..832ec537ae70 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -233,7 +233,6 @@ static int ceph_init_file_info(struct inode *inode, struct file *file, spin_lock_init(&fi->rw_contexts_lock); INIT_LIST_HEAD(&fi->rw_contexts); - fi->meta_err = errseq_sample(&ci->i_meta_err); fi->filp_gen = READ_ONCE(ceph_inode_to_client(inode)->filp_gen); return 0; @@ -578,6 +577,7 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry, struct ceph_inode_info *ci = ceph_inode(dir); struct inode *inode; struct timespec64 now; + struct ceph_string *pool_ns; struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb); struct ceph_vino vino = { .ino = req->r_deleg_ino, .snap = CEPH_NOSNAP }; @@ -592,9 +592,15 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry, iinfo.change_attr = 1; ceph_encode_timespec64(&iinfo.btime, &now); - iinfo.xattr_len = ARRAY_SIZE(xattr_buf); - iinfo.xattr_data = xattr_buf; - memset(iinfo.xattr_data, 0, iinfo.xattr_len); + if (req->r_pagelist) { + iinfo.xattr_len = req->r_pagelist->length; + iinfo.xattr_data = req->r_pagelist->mapped_tail; + } else { + /* fake it */ + iinfo.xattr_len = ARRAY_SIZE(xattr_buf); + iinfo.xattr_data = xattr_buf; + memset(iinfo.xattr_data, 0, iinfo.xattr_len); + } in.ino = cpu_to_le64(vino.ino); in.snapid = cpu_to_le64(CEPH_NOSNAP); @@ -604,17 +610,35 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry, in.cap.realm = cpu_to_le64(ci->i_snap_realm->ino); in.cap.flags = CEPH_CAP_FLAG_AUTH; in.ctime = in.mtime = in.atime = iinfo.btime; - in.mode = cpu_to_le32((u32)mode); in.truncate_seq = cpu_to_le32(1); in.truncate_size = cpu_to_le64(-1ULL); in.xattr_version = cpu_to_le64(1); in.uid = cpu_to_le32(from_kuid(&init_user_ns, current_fsuid())); - in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_mode & S_ISGID ? - dir->i_gid : current_fsgid())); + if (dir->i_mode & S_ISGID) { + in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_gid)); + + /* Directories always inherit the setgid bit. */ + if (S_ISDIR(mode)) + mode |= S_ISGID; + else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) && + !in_group_p(dir->i_gid) && + !capable_wrt_inode_uidgid(dir, CAP_FSETID)) + mode &= ~S_ISGID; + } else { + in.gid = cpu_to_le32(from_kgid(&init_user_ns, current_fsgid())); + } + in.mode = cpu_to_le32((u32)mode); + in.nlink = cpu_to_le32(1); in.max_size = cpu_to_le64(lo->stripe_unit); ceph_file_layout_to_legacy(lo, &in.layout); + /* lo is private, so pool_ns can't change */ + pool_ns = rcu_dereference_raw(lo->pool_ns); + if (pool_ns) { + iinfo.pool_ns_len = pool_ns->len; + iinfo.pool_ns_data = pool_ns->str; + } down_read(&mdsc->snap_rwsem); ret = ceph_fill_inode(inode, NULL, &iinfo, NULL, req->r_session, @@ -679,6 +703,12 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, if (dentry->d_name.len > NAME_MAX) return -ENAMETOOLONG; + /* + * Do not truncate the file, since atomic_open is called before the + * permission check. The caller will do the truncation afterward. + */ + flags &= ~O_TRUNC; + if (flags & O_CREAT) { if (ceph_quota_is_max_files_exceeded(dir)) return -EDQUOT; @@ -688,6 +718,15 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, err = ceph_security_init_secctx(dentry, mode, &as_ctx); if (err < 0) goto out_ctx; +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + err = ceph_pre_init_archive_bit(&as_ctx); + if (err < 0) + goto out_ctx; +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ + /* Async create can't handle more than a page of xattrs */ + if (as_ctx.pagelist && + !list_is_singular(&as_ctx.pagelist->head)) + try_async = false; } else if (!d_in_lookup(dentry)) { /* If it's not being looked up, it's negative */ return -ENOENT; @@ -706,6 +745,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, mask |= CEPH_CAP_XATTR_SHARED; req->r_args.open.mask = cpu_to_le32(mask); req->r_parent = dir; + ihold(dir); if (flags & O_CREAT) { struct ceph_file_layout lo; @@ -732,21 +772,26 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, restore_deleg_ino(dir, req->r_deleg_ino); ceph_mdsc_put_request(req); try_async = false; + ceph_put_string(rcu_dereference_raw(lo.pool_ns)); goto retry; } + ceph_put_string(rcu_dereference_raw(lo.pool_ns)); goto out_req; } } set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); - err = ceph_mdsc_do_request(mdsc, - (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, - req); - err = ceph_handle_snapdir(req, dentry, err); - if (err) - goto out_req; + err = ceph_mdsc_do_request(mdsc, (flags & O_CREAT) ? dir : NULL, req); + if (err == -ENOENT) { + dentry = ceph_handle_snapdir(req, dentry); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); + goto out_req; + } + err = 0; + } - if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) + if (!err && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); if (d_in_lookup(dentry)) { @@ -895,10 +940,10 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to, if (!ret) ret = ceph_osdc_wait_request(osdc, req); - ceph_update_read_latency(&fsc->mdsc->metric, + ceph_update_read_metrics(&fsc->mdsc->metric, req->r_start_latency, req->r_end_latency, - ret); + len, ret); ceph_osdc_put_request(req); @@ -1030,22 +1075,12 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) struct ceph_aio_request *aio_req = req->r_priv; struct ceph_osd_data *osd_data = osd_req_op_extent_osd_data(req, 0); struct ceph_client_metric *metric = &ceph_sb_to_mdsc(inode->i_sb)->metric; + unsigned int len = osd_data->bvec_pos.iter.bi_size; BUG_ON(osd_data->type != CEPH_OSD_DATA_TYPE_BVECS); BUG_ON(!osd_data->num_bvecs); - dout("ceph_aio_complete_req %p rc %d bytes %u\n", - inode, rc, osd_data->bvec_pos.iter.bi_size); - - /* r_start_latency == 0 means the request was not submitted */ - if (req->r_start_latency) { - if (aio_req->write) - ceph_update_write_latency(metric, req->r_start_latency, - req->r_end_latency, rc); - else - ceph_update_read_latency(metric, req->r_start_latency, - req->r_end_latency, rc); - } + dout("ceph_aio_complete_req %p rc %d bytes %u\n", inode, rc, len); if (rc == -EOLDSNAPC) { struct ceph_aio_work *aio_work; @@ -1063,9 +1098,9 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) } else if (!aio_req->write) { if (rc == -ENOENT) rc = 0; - if (rc >= 0 && osd_data->bvec_pos.iter.bi_size > rc) { + if (rc >= 0 && len > rc) { struct iov_iter i; - int zlen = osd_data->bvec_pos.iter.bi_size - rc; + int zlen = len - rc; /* * If read is satisfied by single OSD request, @@ -1082,13 +1117,22 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) } iov_iter_bvec(&i, READ, osd_data->bvec_pos.bvecs, - osd_data->num_bvecs, - osd_data->bvec_pos.iter.bi_size); + osd_data->num_bvecs, len); iov_iter_advance(&i, rc); iov_iter_zero(zlen, &i); } } + /* r_start_latency == 0 means the request was not submitted */ + if (req->r_start_latency) { + if (aio_req->write) + ceph_update_write_metrics(metric, req->r_start_latency, + req->r_end_latency, len, rc); + else + ceph_update_read_metrics(metric, req->r_start_latency, + req->r_end_latency, len, rc); + } + put_bvecs(osd_data->bvec_pos.bvecs, osd_data->num_bvecs, aio_req->should_dirty); ceph_osdc_put_request(req); @@ -1293,11 +1337,11 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, ret = ceph_osdc_wait_request(&fsc->client->osdc, req); if (write) - ceph_update_write_latency(metric, req->r_start_latency, - req->r_end_latency, ret); + ceph_update_write_metrics(metric, req->r_start_latency, + req->r_end_latency, len, ret); else - ceph_update_read_latency(metric, req->r_start_latency, - req->r_end_latency, ret); + ceph_update_read_metrics(metric, req->r_start_latency, + req->r_end_latency, len, ret); size = i_size_read(inode); if (!write) { @@ -1470,8 +1514,8 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos, if (!ret) ret = ceph_osdc_wait_request(&fsc->client->osdc, req); - ceph_update_write_latency(&fsc->mdsc->metric, req->r_start_latency, - req->r_end_latency, ret); + ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency, + req->r_end_latency, len, ret); out: ceph_osdc_put_request(req); if (ret != 0) { @@ -1513,7 +1557,6 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) size_t len = iov_iter_count(to); struct inode *inode = file_inode(filp); struct ceph_inode_info *ci = ceph_inode(inode); - struct page *pinned_page = NULL; bool direct_lock = iocb->ki_flags & IOCB_DIRECT; ssize_t ret; int want, got = 0; @@ -1532,8 +1575,7 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; else want = CEPH_CAP_FILE_CACHE; - ret = ceph_get_caps(filp, CEPH_CAP_FILE_RD, want, -1, - &got, &pinned_page); + ret = ceph_get_caps(filp, CEPH_CAP_FILE_RD, want, -1, &got); if (ret < 0) { if (iocb->ki_flags & IOCB_DIRECT) ceph_end_io_direct(inode); @@ -1574,10 +1616,6 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n", inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret); - if (pinned_page) { - put_page(pinned_page); - pinned_page = NULL; - } ceph_put_cap_refs(ci, got); if (direct_lock) @@ -1663,7 +1701,20 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) * * If we are near ENOSPC, write synchronously. */ +#ifdef CONFIG_SYNO_CEPH_RECVFILE +static ssize_t __ceph_write_iter(struct kiocb *iocb, struct iov_iter *from, + int is_recvfile, struct socket *sock, size_t *rbytes, size_t *wbytes); + static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + return __ceph_write_iter(iocb, from, 0, NULL, NULL, NULL); +} + +static ssize_t __ceph_write_iter(struct kiocb *iocb, struct iov_iter *from, + int is_recvfile, struct socket *sock, size_t *rbytes, size_t *wbytes) +#else +static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ { struct file *file = iocb->ki_filp; struct ceph_file_info *fi = file->private_data; @@ -1691,6 +1742,11 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) direct_lock = true; retry_snap: +#ifdef CONFIG_SYNO_CEPH_RECVFILE + if (is_recvfile) + ceph_start_io_write_nolock(inode); // inode is already locked in vfs_recvfile + else +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ if (direct_lock) ceph_start_io_direct(inode); else @@ -1723,22 +1779,6 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) goto out; } - err = file_remove_privs(file); - if (err) - goto out; - - err = file_update_time(file); - if (err) - goto out; - - inode_inc_iversion_raw(inode); - - if (ci->i_inline_version != CEPH_INLINE_NONE) { - err = ceph_uninline_data(file, NULL); - if (err < 0) - goto out; - } - down_read(&osdc->lock); map_flags = osdc->osdmap->flags; pool_flags = ceph_pg_pool_flags(osdc->osdmap, ci->i_layout.pool_id); @@ -1749,6 +1789,16 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) goto out; } + err = file_remove_privs(file); + if (err) + goto out; + + if (ci->i_inline_version != CEPH_INLINE_NONE) { + err = ceph_uninline_data(file, NULL); + if (err < 0) + goto out; + } + dout("aio_write %p %llx.%llx %llu~%zd getting caps. i_size %llu\n", inode, ceph_vinop(inode), pos, count, i_size_read(inode)); if (fi->fmode & CEPH_FILE_MODE_LAZY) @@ -1756,14 +1806,29 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) else want = CEPH_CAP_FILE_BUFFER; got = 0; - err = ceph_get_caps(file, CEPH_CAP_FILE_WR, want, pos + count, - &got, NULL); + err = ceph_get_caps(file, CEPH_CAP_FILE_WR, want, pos + count, &got); if (err < 0) goto out; + err = file_update_time(file); + if (err) + goto out_caps; + + inode_inc_iversion_raw(inode); + dout("aio_write %p %llx.%llx %llu~%zd got cap refs on %s\n", inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); +#ifdef CONFIG_SYNO_CEPH_RECVFILE + if (is_recvfile) { + + written = do_recvfile(file, sock, pos, count, rbytes, wbytes); + + if (likely(written >= 0)) + iocb->ki_pos = pos + written; + ceph_end_io_write_nolock(inode); + } else { +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC) || (ci->i_ceph_flags & CEPH_I_ERROR_WRITE)) { @@ -1811,6 +1876,9 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ceph_end_io_write(inode); } +#ifdef CONFIG_SYNO_CEPH_RECVFILE + } +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ if (written >= 0) { int dirty; @@ -1844,7 +1912,14 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) } goto out_unlocked; +out_caps: + ceph_put_cap_refs(ci, got); out: +#ifdef CONFIG_SYNO_CEPH_RECVFILE + if (is_recvfile) + ceph_end_io_write_nolock(inode); + else +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ if (direct_lock) ceph_end_io_direct(inode); else @@ -1855,6 +1930,22 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) return written ? written : err; } +#ifdef CONFIG_SYNO_CEPH_RECVFILE +static ssize_t ceph_recvfile(int fd, struct file *filp, struct socket *sock, loff_t pos, + size_t count, size_t * rbytes, size_t * wbytes) +{ + struct iovec iov = { .iov_base = NULL, .iov_len = count}; + struct kiocb iocb; + struct iov_iter iter; + + init_sync_kiocb(&iocb, filp); + iocb.ki_pos = pos; + iov_iter_init(&iter, WRITE, &iov, 1, count); + + return __ceph_write_iter(&iocb, &iter, 1, sock, rbytes, wbytes); +} +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ + /* * llseek. be sure to verify file size on SEEK_END. */ @@ -2086,7 +2177,7 @@ static long ceph_fallocate(struct file *file, int mode, else want = CEPH_CAP_FILE_BUFFER; - ret = ceph_get_caps(file, CEPH_CAP_FILE_WR, want, endoff, &got, NULL); + ret = ceph_get_caps(file, CEPH_CAP_FILE_WR, want, endoff, &got); if (ret < 0) goto unlock; @@ -2124,7 +2215,7 @@ static int get_rd_wr_caps(struct file *src_filp, int *src_got, retry_caps: ret = ceph_get_caps(dst_filp, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER, - dst_endoff, dst_got, NULL); + dst_endoff, dst_got); if (ret < 0) return ret; @@ -2146,7 +2237,7 @@ static int get_rd_wr_caps(struct file *src_filp, int *src_got, return ret; } ret = ceph_get_caps(src_filp, CEPH_CAP_FILE_RD, - CEPH_CAP_FILE_SHARED, -1, src_got, NULL); + CEPH_CAP_FILE_SHARED, -1, src_got); if (ret < 0) return ret; /*... drop src_ci caps too, and retry */ @@ -2491,4 +2582,7 @@ const struct file_operations ceph_file_fops = { .compat_ioctl = compat_ptr_ioctl, .fallocate = ceph_fallocate, .copy_file_range = ceph_copy_file_range, +#ifdef CONFIG_SYNO_CEPH_RECVFILE + .syno_recvfile = ceph_recvfile, +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ }; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 57cd78e942c0..b5d8ca604d4a 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -19,6 +19,9 @@ #include "mds_client.h" #include "cache.h" #include +#ifdef CONFIG_SYNO_CEPH_WINACL +#include "syno_acl.h" +#endif /* CONFIG_SYNO_CEPH_WINACL */ /* * Ceph inode operations @@ -81,9 +84,21 @@ struct inode *ceph_get_snapdir(struct inode *parent) struct inode *inode = ceph_get_inode(parent->i_sb, vino); struct ceph_inode_info *ci = ceph_inode(inode); - BUG_ON(!S_ISDIR(parent->i_mode)); if (IS_ERR(inode)) return inode; + + if (!S_ISDIR(parent->i_mode)) { + pr_warn_once("bad snapdir parent type (mode=0%o)\n", + parent->i_mode); + goto err; + } + + if (!(inode->i_state & I_NEW) && !S_ISDIR(inode->i_mode)) { + pr_warn_once("bad snapdir inode type (mode=0%o)\n", + inode->i_mode); + goto err; + } + inode->i_mode = parent->i_mode; inode->i_uid = parent->i_uid; inode->i_gid = parent->i_gid; @@ -101,15 +116,131 @@ struct inode *ceph_get_snapdir(struct inode *parent) } return inode; +err: + if ((inode->i_state & I_NEW)) + discard_new_inode(inode); + else + iput(inode); + return ERR_PTR(-ENOTDIR); } +#ifdef CONFIG_SYNO_CEPH_STAT +int ceph_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags) +{ + struct inode *inode = dentry->d_inode; + +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + if (syno_flags & SYNOST_CREATE_TIME) + ceph_syno_get_crtime(inode, &kst->syno_create_time); +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ + +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + if (syno_flags & SYNOST_ARCHIVE_BIT) { + int err; + mutex_lock(&inode->i_archive_bit_mutex); + err = ceph_syno_get_archive_bit(dentry, &kst->syno_archive_bit, 0); + mutex_unlock(&inode->i_archive_bit_mutex); + if (err) + return err; + } +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ + return 0; +} +#endif /* CONFIG_SYNO_CEPH_STAT */ + +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME +static int ____ceph_setattr(struct inode *inode, struct iattr *attr, struct timespec64 *btime); +static int statx_to_caps(u32 want, umode_t mode); + +int ceph_syno_get_crtime(struct inode *inode, struct timespec64 *time) +{ + int err; + struct ceph_inode_info *ci = ceph_inode(inode); + + err = ceph_do_getattr(inode, statx_to_caps(STATX_BTIME, inode->i_mode), false); + if (err) + return err; + *time = ci->i_btime; + + return err; +} + +int ceph_syno_set_crtime(struct inode *inode, struct timespec64 *time) +{ + struct iattr newattrs = {}; + + if (ceph_snap(inode) != CEPH_NOSNAP) + return -EROFS; + + return ____ceph_setattr(inode, &newattrs, time); +} +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ + +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT +int ceph_syno_get_archive_bit(struct dentry *dentry, unsigned int *archive_bit, int may_not_block) +{ + int ret; + struct inode *inode = dentry->d_inode; + __le32 archive_bit_le32; + + if (may_not_block) + return -ECHILD; + + ret = __ceph_getxattr(inode, XATTR_SYNO_ARCHIVE_BIT, &archive_bit_le32, + sizeof(archive_bit_le32)); + if (ret == sizeof(archive_bit_le32)) { + inode->i_archive_bit = le32_to_cpu(archive_bit_le32); + } else if (-ENODATA == ret) { + inode->i_archive_bit= 0; + } else { + if (ret > 0) { + ret = -EUCLEAN; + *archive_bit = 0; + } + return ret; + } + *archive_bit = inode->i_archive_bit; + + return 0; +} + +int ceph_syno_set_archive_bit(struct dentry *dentry, unsigned int archive_bit) +{ + struct inode *inode = dentry->d_inode; + __le32 archive_bit_le32; + + if (ceph_snap(inode) != CEPH_NOSNAP) + return -EROFS; + + archive_bit_le32 = cpu_to_le32(archive_bit); + return __ceph_setxattr(inode, XATTR_SYNO_ARCHIVE_BIT, &archive_bit_le32, + sizeof(archive_bit_le32), 0); +} +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ + const struct inode_operations ceph_file_iops = { +#ifdef CONFIG_SYNO_CEPH_STAT + .syno_getattr = ceph_syno_getattr, +#endif /* CONFIG_SYNO_CEPH_STAT */ +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + .syno_get_crtime = ceph_syno_get_crtime, + .syno_set_crtime = ceph_syno_set_crtime, +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + .syno_get_archive_bit = ceph_syno_get_archive_bit, + .syno_set_archive_bit = ceph_syno_set_archive_bit, +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ .permission = ceph_permission, .setattr = ceph_setattr, .getattr = ceph_getattr, .listxattr = ceph_listxattr, .get_acl = ceph_get_acl, .set_acl = ceph_set_acl, +#ifdef CONFIG_SYNO_CEPH_WINACL + .syno_get_acl = ceph_get_syno_acl, + .syno_set_acl = ceph_set_syno_acl, + .syno_permission = ceph_syno_permission, +#endif /* CONFIG_SYNO_CEPH_WINACL */ }; @@ -529,8 +660,6 @@ struct inode *ceph_alloc_inode(struct super_block *sb) ceph_fscache_inode_init(ci); - ci->i_meta_err = 0; - return &ci->vfs_inode; } @@ -569,16 +698,9 @@ void ceph_evict_inode(struct inode *inode) */ if (ci->i_snap_realm) { if (ceph_snap(inode) == CEPH_NOSNAP) { - struct ceph_snap_realm *realm = ci->i_snap_realm; dout(" dropping residual ref to snap realm %p\n", - realm); - spin_lock(&realm->inodes_with_caps_lock); - list_del_init(&ci->i_snap_realm_item); - ci->i_snap_realm = NULL; - if (realm->ino == ci->i_vino.ino) - realm->inode = NULL; - spin_unlock(&realm->inodes_with_caps_lock); - ceph_put_snap_realm(mdsc, realm); + ci->i_snap_realm); + ceph_change_snap_realm(inode, NULL); } else { ceph_put_snapid_map(mdsc, ci->i_snapid_map); ci->i_snap_realm = NULL; @@ -620,10 +742,11 @@ int ceph_fill_file_size(struct inode *inode, int issued, { struct ceph_inode_info *ci = ceph_inode(inode); int queue_trunc = 0; + loff_t isize = i_size_read(inode); if (ceph_seq_cmp(truncate_seq, ci->i_truncate_seq) > 0 || - (truncate_seq == ci->i_truncate_seq && size > inode->i_size)) { - dout("size %lld -> %llu\n", inode->i_size, size); + (truncate_seq == ci->i_truncate_seq && size > isize)) { + dout("size %lld -> %llu\n", isize, size); if (size > 0 && S_ISDIR(inode->i_mode)) { pr_err("fill_file_size non-zero size for directory\n"); size = 0; @@ -900,6 +1023,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, ci->i_rfiles = le64_to_cpu(info->rfiles); ci->i_rsubdirs = le64_to_cpu(info->rsubdirs); ci->i_dir_pin = iinfo->dir_pin; + ci->i_rsnaps = iinfo->rsnaps; ceph_decode_timespec64(&ci->i_rctime, &info->rctime); } } @@ -916,6 +1040,9 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page, iinfo->xattr_data, iinfo->xattr_len); ci->i_xattrs.version = le64_to_cpu(info->xattr_version); ceph_forget_all_cached_acls(inode); +#ifdef CONFIG_SYNO_CEPH_WINACL + forget_cached_syno_acl(inode); +#endif /* CONFIG_SYNO_CEPH_WINACL */ ceph_security_invalidate_secctx(inode); xattr_blob = NULL; } @@ -1091,7 +1218,7 @@ static void __update_dentry_lease(struct inode *dir, struct dentry *dentry, return; } - if (di->lease_gen == session->s_cap_gen && + if (di->lease_gen == atomic_read(&session->s_cap_gen) && time_before(ttl, di->time)) return; /* we already have a newer lease. */ @@ -1102,7 +1229,7 @@ static void __update_dentry_lease(struct inode *dir, struct dentry *dentry, if (!di->lease_session) di->lease_session = ceph_get_mds_session(session); - di->lease_gen = session->s_cap_gen; + di->lease_gen = atomic_read(&session->s_cap_gen); di->lease_seq = le32_to_cpu(lease->seq); di->lease_renew_after = half_ttl; di->lease_renew_from = 0; @@ -1121,8 +1248,7 @@ static inline void update_dentry_lease(struct inode *dir, struct dentry *dentry, __update_dentry_lease(dir, dentry, lease, session, from_time, &old_lease_session); spin_unlock(&dentry->d_lock); - if (old_lease_session) - ceph_put_mds_session(old_lease_session); + ceph_put_mds_session(old_lease_session); } /* @@ -1167,8 +1293,7 @@ static void update_dentry_lease_careful(struct dentry *dentry, from_time, &old_lease_session); out_unlock: spin_unlock(&dentry->d_lock); - if (old_lease_session) - ceph_put_mds_session(old_lease_session); + ceph_put_mds_session(old_lease_session); } /* @@ -1229,6 +1354,17 @@ static int splice_dentry(struct dentry **pdn, struct inode *in) return 0; } +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +static inline int ceph_replace_caseless_dentry_name(struct dentry *dentry, + const char *name, int len) +{ + if (dentry->d_name.len == len && + !dentry_string_cmp(dentry->d_name.name, name, len)) + return 0; + return dentry_replace_name(dentry, name, len); +} +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ + /* * Incorporate results into the local cache. This is either just * one inode, or a directory, dentry, and possibly linked-to inode (e.g., @@ -1272,6 +1408,23 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) WARN_ON_ONCE(1); } +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + if ((req->r_op == CEPH_MDS_OP_LOOKUP || + req->r_op == CEPH_MDS_OP_LOOKUPSNAP) && + le32_to_cpu(req->r_args.getattr.flags) & CEPH_GETATTR_CASELESS) { + struct dentry *dn = req->r_dentry; + if (req->r_dentry->d_name.len == strlen(fsc->mount_options->snapdir_name) && + !strncasecmp(req->r_dentry->d_name.name, fsc->mount_options->snapdir_name, + req->r_dentry->d_name.len)) { + err = ceph_replace_caseless_dentry_name(dn, fsc->mount_options->snapdir_name, + strlen(fsc->mount_options->snapdir_name)); + } else { + err = ceph_replace_caseless_dentry_name(dn, rinfo->dname, rinfo->dname_len); + } + if (err < 0) + goto done; + } +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ if (dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME && test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) && !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) { @@ -1286,7 +1439,17 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) dname.name = rinfo->dname; dname.len = rinfo->dname_len; +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + err = ceph_upper_full_name_hash(parent, dname.name, dname.len, &dname.hash); + if (err < 0) { + dout("ceph upper full name hash failed name[%.*s] len %d, err %d\n", + dname.len > 16 ? 16 : dname.len, dname.name, dname.len, err); + dput(parent); + goto done; + } +#else dname.hash = full_name_hash(parent, dname.name, dname.len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ tvino.ino = le64_to_cpu(rinfo->targeti.in->ino); tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid); retry_lookup: @@ -1321,15 +1484,10 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) } if (rinfo->head->is_target) { - tvino.ino = le64_to_cpu(rinfo->targeti.in->ino); - tvino.snap = le64_to_cpu(rinfo->targeti.in->snapid); - - in = ceph_get_inode(sb, tvino); - if (IS_ERR(in)) { - err = PTR_ERR(in); - goto done; - } + /* Should be filled in by handle_reply */ + BUG_ON(!req->r_target_inode); + in = req->r_target_inode; err = ceph_fill_inode(in, req->r_locked_page, &rinfo->targeti, NULL, session, (!test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags) && @@ -1339,13 +1497,13 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) if (err < 0) { pr_err("ceph_fill_inode badness %p %llx.%llx\n", in, ceph_vinop(in)); + req->r_target_inode = NULL; if (in->i_state & I_NEW) discard_new_inode(in); else iput(in); goto done; } - req->r_target_inode = in; if (in->i_state & I_NEW) unlock_new_inode(in); } @@ -1473,6 +1631,14 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) struct inode *dir = req->r_parent; /* fill out a snapdir LOOKUPSNAP dentry */ +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + if (req->r_op == CEPH_MDS_OP_LOOKUPSNAP && + (le32_to_cpu(req->r_args.getattr.flags) & CEPH_GETATTR_CASELESS)) { + err = ceph_replace_caseless_dentry_name(req->r_dentry, rinfo->snap_dname, rinfo->snap_dname_len); + if (err < 0) + goto done; + } +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ BUG_ON(!dir); BUG_ON(ceph_snap(dir) != CEPH_SNAPDIR); BUG_ON(!req->r_dentry); @@ -1540,8 +1706,7 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req, unlock_new_inode(in); } - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(in); + iput(in); } return err; @@ -1605,8 +1770,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, struct dentry *dn; struct inode *in; int err = 0, skipped = 0, ret, i; - struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; - u32 frag = le32_to_cpu(rhead->args.readdir.frag); + u32 frag = le32_to_cpu(req->r_args.readdir.frag); u32 last_hash = 0; u32 fpos_offset; struct ceph_readdir_cache_control cache_ctl = {}; @@ -1616,14 +1780,20 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, if (rinfo->hash_order) { if (req->r_path2) { +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + last_hash = ceph_str_upper_hash(ci->i_dir_layout.dl_dir_hash, + req->r_path2, + strlen(req->r_path2)); +#else last_hash = ceph_str_hash(ci->i_dir_layout.dl_dir_hash, req->r_path2, strlen(req->r_path2)); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ last_hash = ceph_frag_value(last_hash); } else if (rinfo->offset_hash) { /* mds understands offset_hash */ WARN_ON_ONCE(req->r_readdir_offset != 2); - last_hash = le32_to_cpu(rhead->args.readdir.offset_hash); + last_hash = le32_to_cpu(req->r_args.readdir.offset_hash); } } @@ -1668,14 +1838,28 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, dname.name = rde->name; dname.len = rde->name_len; +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + err = ceph_upper_full_name_hash(parent, dname.name, dname.len, &dname.hash); + if (err < 0) { + dout("ceph upper full name hash failed name[%.*s] len %d, err %d\n", + dname.len > 16 ? 16 : dname.len, dname.name, dname.len, err); + goto out; + } +#else dname.hash = full_name_hash(parent, dname.name, dname.len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ tvino.ino = le64_to_cpu(rde->inode.in->ino); tvino.snap = le64_to_cpu(rde->inode.in->snapid); if (rinfo->hash_order) { +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + u32 hash = ceph_str_upper_hash(ci->i_dir_layout.dl_dir_hash, + rde->name, rde->name_len); +#else u32 hash = ceph_str_hash(ci->i_dir_layout.dl_dir_hash, rde->name, rde->name_len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ hash = ceph_frag_value(hash); if (hash != last_hash) fpos_offset = 2; @@ -1739,13 +1923,11 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, if (ret < 0) { pr_err("ceph_fill_inode badness on %p\n", in); if (d_really_is_negative(dn)) { - /* avoid calling iput_final() in mds - * dispatch threads */ if (in->i_state & I_NEW) { ihold(in); discard_new_inode(in); } - ceph_async_iput(in); + iput(in); } d_drop(dn); err = ret; @@ -1758,7 +1940,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, if (ceph_security_xattr_deadlock(in)) { dout(" skip splicing dn %p to inode %p" " (security xattr deadlock)\n", dn, in); - ceph_async_iput(in); + iput(in); skipped++; goto next_item; } @@ -1799,7 +1981,7 @@ bool ceph_inode_set_size(struct inode *inode, loff_t size) bool ret; spin_lock(&ci->i_ceph_lock); - dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size); + dout("set_size %p %llu -> %llu\n", inode, i_size_read(inode), size); i_size_write(inode, size); inode->i_blocks = calc_inode_blocks(size); @@ -1809,79 +1991,17 @@ bool ceph_inode_set_size(struct inode *inode, loff_t size) return ret; } -/* - * Put reference to inode, but avoid calling iput_final() in current thread. - * iput_final() may wait for reahahead pages. The wait can cause deadlock in - * some contexts. - */ -void ceph_async_iput(struct inode *inode) -{ - if (!inode) - return; - for (;;) { - if (atomic_add_unless(&inode->i_count, -1, 1)) - break; - if (queue_work(ceph_inode_to_client(inode)->inode_wq, - &ceph_inode(inode)->i_work)) - break; - /* queue work failed, i_count must be at least 2 */ - } -} - -/* - * Write back inode data in a worker thread. (This can't be done - * in the message handler context.) - */ -void ceph_queue_writeback(struct inode *inode) +void ceph_queue_inode_work(struct inode *inode, int work_bit) { + struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); - set_bit(CEPH_I_WORK_WRITEBACK, &ci->i_work_mask); + set_bit(work_bit, &ci->i_work_mask); ihold(inode); - if (queue_work(ceph_inode_to_client(inode)->inode_wq, - &ci->i_work)) { - dout("ceph_queue_writeback %p\n", inode); + if (queue_work(fsc->inode_wq, &ci->i_work)) { + dout("queue_inode_work %p, mask=%lx\n", inode, ci->i_work_mask); } else { - dout("ceph_queue_writeback %p already queued, mask=%lx\n", - inode, ci->i_work_mask); - iput(inode); - } -} - -/* - * queue an async invalidation - */ -void ceph_queue_invalidate(struct inode *inode) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - set_bit(CEPH_I_WORK_INVALIDATE_PAGES, &ci->i_work_mask); - - ihold(inode); - if (queue_work(ceph_inode_to_client(inode)->inode_wq, - &ceph_inode(inode)->i_work)) { - dout("ceph_queue_invalidate %p\n", inode); - } else { - dout("ceph_queue_invalidate %p already queued, mask=%lx\n", - inode, ci->i_work_mask); - iput(inode); - } -} - -/* - * Queue an async vmtruncate. If we fail to queue work, we will handle - * the truncation the next time we call __ceph_do_pending_vmtruncate. - */ -void ceph_queue_vmtruncate(struct inode *inode) -{ - struct ceph_inode_info *ci = ceph_inode(inode); - set_bit(CEPH_I_WORK_VMTRUNCATE, &ci->i_work_mask); - - ihold(inode); - if (queue_work(ceph_inode_to_client(inode)->inode_wq, - &ci->i_work)) { - dout("ceph_queue_vmtruncate %p\n", inode); - } else { - dout("ceph_queue_vmtruncate %p already queued, mask=%lx\n", + dout("queue_inode_work %p already queued, mask=%lx\n", inode, ci->i_work_mask); iput(inode); } @@ -1896,7 +2016,7 @@ static void ceph_do_invalidate_pages(struct inode *inode) mutex_lock(&ci->i_truncate_mutex); - if (READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + if (READ_ONCE(fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) { pr_warn_ratelimited("invalidate_pages %p %lld forced umount\n", inode, ceph_ino(inode)); mapping_set_error(inode->i_mapping, -EIO); @@ -2021,6 +2141,12 @@ static void ceph_inode_work(struct work_struct *work) if (test_and_clear_bit(CEPH_I_WORK_VMTRUNCATE, &ci->i_work_mask)) __ceph_do_pending_vmtruncate(inode); + if (test_and_clear_bit(CEPH_I_WORK_CHECK_CAPS, &ci->i_work_mask)) + ceph_check_caps(ci, 0, NULL); + + if (test_and_clear_bit(CEPH_I_WORK_FLUSH_SNAPS, &ci->i_work_mask)) + ceph_flush_snaps(ci, NULL); + iput(inode); } @@ -2028,13 +2154,34 @@ static void ceph_inode_work(struct work_struct *work) * symlinks */ static const struct inode_operations ceph_symlink_iops = { +#ifdef CONFIG_SYNO_CEPH_STAT + .syno_getattr = ceph_syno_getattr, +#endif /* CONFIG_SYNO_CEPH_STAT */ +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + .syno_get_crtime = ceph_syno_get_crtime, + .syno_set_crtime = ceph_syno_set_crtime, +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + .syno_get_archive_bit = ceph_syno_get_archive_bit, + .syno_set_archive_bit = ceph_syno_set_archive_bit, +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ .get_link = simple_get_link, .setattr = ceph_setattr, .getattr = ceph_getattr, .listxattr = ceph_listxattr, }; +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME int __ceph_setattr(struct inode *inode, struct iattr *attr) +{ + return ____ceph_setattr(inode, attr, NULL); +} + +static int ____ceph_setattr(struct inode *inode, struct iattr *attr, + struct timespec64 *btime) +#else +int __ceph_setattr(struct inode *inode, struct iattr *attr) +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ { struct ceph_inode_info *ci = ceph_inode(inode); unsigned int ia_valid = attr->ia_valid; @@ -2143,20 +2290,19 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr) } } if (ia_valid & ATTR_SIZE) { - dout("setattr %p size %lld -> %lld\n", inode, - inode->i_size, attr->ia_size); - if ((issued & CEPH_CAP_FILE_EXCL) && - attr->ia_size > inode->i_size) { + loff_t isize = i_size_read(inode); + + dout("setattr %p size %lld -> %lld\n", inode, isize, attr->ia_size); + if ((issued & CEPH_CAP_FILE_EXCL) && attr->ia_size > isize) { i_size_write(inode, attr->ia_size); inode->i_blocks = calc_inode_blocks(attr->ia_size); ci->i_reported_size = attr->ia_size; dirtied |= CEPH_CAP_FILE_EXCL; ia_valid |= ATTR_MTIME; } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 || - attr->ia_size != inode->i_size) { + attr->ia_size != isize) { req->r_args.setattr.size = cpu_to_le64(attr->ia_size); - req->r_args.setattr.old_size = - cpu_to_le64(inode->i_size); + req->r_args.setattr.old_size = cpu_to_le64(isize); mask |= CEPH_SETATTR_SIZE; release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR; @@ -2185,6 +2331,24 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr) } } +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + if (btime) { + dout("setattr %p btime %lld.%ld -> %lld.%ld\n", inode, + ci->i_btime.tv_sec, ci->i_btime.tv_nsec, + btime->tv_sec, btime->tv_nsec); + if (issued & CEPH_CAP_AUTH_EXCL) { + ci->i_time_warp_seq++; + ci->i_btime = *btime; + dirtied |= CEPH_CAP_AUTH_EXCL; + } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 || + !timespec64_equal(&ci->i_btime, btime)) { + ceph_encode_timespec64(&req->r_args.setattr.btime, btime); + mask |= CEPH_SETATTR_BTIME; + release |= CEPH_CAP_AUTH_SHARED; + } + } +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ + /* these do nothing */ if (ia_valid & ATTR_CTIME) { bool only = (ia_valid & (ATTR_SIZE|ATTR_MTIME|ATTR_ATIME| @@ -2260,12 +2424,17 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; +#ifdef CONFIG_SYNO_CEPH_WINACL + if (IS_SYNOACL(dentry)) + err = 0; // skip permission check + else +#endif /* CONFIG_SYNO_CEPH_WINACL */ err = setattr_prepare(dentry, attr); if (err != 0) return err; if ((attr->ia_valid & ATTR_SIZE) && - attr->ia_size > max(inode->i_size, fsc->max_file_size)) + attr->ia_size > max(i_size_read(inode), fsc->max_file_size)) return -EFBIG; if ((attr->ia_valid & ATTR_SIZE) && @@ -2348,16 +2517,40 @@ int ceph_permission(struct inode *inode, int mask) return err; } +#ifdef CONFIG_SYNO_CEPH_WINACL +int ceph_syno_permission(struct dentry *dentry, int mask) +{ + if (mask & MAY_NOT_BLOCK) + return -ECHILD; + + /* + * We don't need ceph_do_getattr CEPH_CAP_XATTR_SHARED, + * synoacl_mod_permission will call ceph_get_syno_acl, which + * in turn calls ceph_getxattr. ceph_getxattr will check + * capability before access local cached xattr. + */ + return synoacl_mod_permission(dentry, mask); +} +#endif /* CONFIG_SYNO_CEPH_WINACL */ + /* Craft a mask of needed caps given a set of requested statx attrs. */ -static int statx_to_caps(u32 want) +static int statx_to_caps(u32 want, umode_t mode) { int mask = 0; if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME|STATX_BTIME)) mask |= CEPH_CAP_AUTH_SHARED; - if (want & (STATX_NLINK|STATX_CTIME)) - mask |= CEPH_CAP_LINK_SHARED; + if (want & (STATX_NLINK|STATX_CTIME)) { + /* + * The link count for directories depends on inode->i_subdirs, + * and that is only updated when Fs caps are held. + */ + if (S_ISDIR(mode)) + mask |= CEPH_CAP_FILE_SHARED; + else + mask |= CEPH_CAP_LINK_SHARED; + } if (want & (STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_SIZE| STATX_BLOCKS)) @@ -2383,8 +2576,9 @@ int ceph_getattr(const struct path *path, struct kstat *stat, /* Skip the getattr altogether if we're asked not to sync */ if (!(flags & AT_STATX_DONT_SYNC)) { - err = ceph_do_getattr(inode, statx_to_caps(request_mask), - flags & AT_STATX_FORCE_SYNC); + err = ceph_do_getattr(inode, + statx_to_caps(request_mask, inode->i_mode), + flags & AT_STATX_FORCE_SYNC); if (err) return err; } diff --git a/fs/ceph/io.c b/fs/ceph/io.c index 97602ea92ff4..fffab0d583f8 100644 --- a/fs/ceph/io.c +++ b/fs/ceph/io.c @@ -83,12 +83,30 @@ ceph_end_io_read(struct inode *inode) * Declare that a buffered write operation is about to start, and ensure * that we block all direct I/O. */ +#ifdef CONFIG_SYNO_CEPH_RECVFILE +static void __ceph_start_io_write(struct inode *inode, int nolock) +{ + if (!nolock) { + down_write(&inode->i_rwsem); + ceph_block_o_direct(ceph_inode(inode), inode); + } +} +void ceph_start_io_write(struct inode *inode) +{ + return __ceph_start_io_write(inode, 0); +} +void ceph_start_io_write_nolock(struct inode *inode) +{ + return __ceph_start_io_write(inode, 1); +} +#else void ceph_start_io_write(struct inode *inode) { down_write(&inode->i_rwsem); ceph_block_o_direct(ceph_inode(inode), inode); } +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ /** * ceph_end_io_write - declare that the buffered write operation is done @@ -97,9 +115,24 @@ ceph_start_io_write(struct inode *inode) * Declare that a buffered write operation is done, and release the * lock on inode->i_rwsem. */ +#ifdef CONFIG_SYNO_CEPH_RECVFILE +static void __ceph_end_io_write(struct inode *inode, int nolock); +void ceph_end_io_write(struct inode *inode) +{ + return __ceph_end_io_write(inode, 0); +} +void ceph_end_io_write_nolock(struct inode *inode) +{ + return __ceph_end_io_write(inode, 1); +} +static void __ceph_end_io_write(struct inode *inode, int nolock) +{ + if (!nolock) +#else void ceph_end_io_write(struct inode *inode) { +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ up_write(&inode->i_rwsem); } @@ -118,7 +151,7 @@ static void ceph_block_buffered(struct ceph_inode_info *ci, struct inode *inode) } /** - * ceph_end_io_direct - declare the file is being used for direct i/o + * ceph_start_io_direct - declare the file is being used for direct i/o * @inode: file inode * * Declare that a direct I/O operation is about to start, and ensure diff --git a/fs/ceph/io.h b/fs/ceph/io.h index fa594cd77348..5a730fd34982 100644 --- a/fs/ceph/io.h +++ b/fs/ceph/io.h @@ -6,6 +6,10 @@ void ceph_start_io_read(struct inode *inode); void ceph_end_io_read(struct inode *inode); void ceph_start_io_write(struct inode *inode); void ceph_end_io_write(struct inode *inode); +#ifdef CONFIG_SYNO_CEPH_RECVFILE +void ceph_start_io_write_nolock(struct inode *inode); +void ceph_end_io_write_nolock(struct inode *inode); +#endif /* CONFIG_SYNO_CEPH_RECVFILE */ void ceph_start_io_direct(struct inode *inode); void ceph_end_io_direct(struct inode *inode); diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 048a435a29be..fa8a847743d0 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -57,7 +57,7 @@ static const struct file_lock_operations ceph_fl_lock_ops = { .fl_release_private = ceph_fl_release_lock, }; -/** +/* * Implement fcntl and flock locking functions. */ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode, @@ -225,7 +225,7 @@ static int try_unlock_file(struct file *file, struct file_lock *fl) return 1; } -/** +/* * Attempt to set an fcntl lock. * For now, this just goes away to the server. Later it may be more awesome. */ @@ -408,7 +408,7 @@ static int lock_to_ceph_filelock(struct file_lock *lock, return err; } -/** +/* * Encode the flock and fcntl locks for the given inode into the ceph_filelock * array. Must be called with inode->i_lock already held. * If we encounter more of a specific lock type than expected, return -ENOSPC. @@ -458,7 +458,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode, return err; } -/** +/* * Copy the encoded flock and fcntl locks into the pagelist. * Format is: #fcntl locks, sequential fcntl locks, #flock locks, * sequential flock locks. diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 6b00f1d7c8e7..75a03c28a7a0 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "super.h" #include "mds_client.h" @@ -176,6 +177,13 @@ static int parse_reply_info_in(void **p, void *end, memset(&info->snap_btime, 0, sizeof(info->snap_btime)); } + /* snapshot count, remains zero for v<=3 */ + if (struct_v >= 4) { + ceph_decode_64_safe(p, end, info->rsnaps, bad); + } else { + info->rsnaps = 0; + } + *p = end; } else { if (features & CEPH_FEATURE_MDS_INLINE_DATA) { @@ -214,7 +222,7 @@ static int parse_reply_info_in(void **p, void *end, } info->dir_pin = -ENODATA; - /* info->snap_btime remains zero */ + /* info->snap_btime and info->rsnaps remain zero */ } return 0; bad: @@ -523,13 +531,9 @@ static int parse_reply_info_create(void **p, void *end, /* Malformed reply? */ info->has_create_ino = false; } else if (test_bit(CEPHFS_FEATURE_DELEG_INO, &s->s_features)) { - u8 struct_v, struct_compat; - u32 len; - info->has_create_ino = true; - ceph_decode_8_safe(p, end, struct_v, bad); - ceph_decode_8_safe(p, end, struct_compat, bad); - ceph_decode_32_safe(p, end, len, bad); + /* struct_v, struct_compat, and len */ + ceph_decode_skip_n(p, end, 2 + sizeof(u32), bad); ceph_decode_64_safe(p, end, info->ino, bad); ret = ceph_parse_deleg_inos(p, end, s); if (ret) @@ -551,6 +555,21 @@ static int parse_reply_info_create(void **p, void *end, return -EIO; } +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +static int parse_reply_info_lookupsnap(void **p, void *end, + struct ceph_mds_reply_info_parsed *info, u64 features) +{ + ceph_decode_32_safe(p, end, info->snap_dname_len, bad); + ceph_decode_need(p, end, info->snap_dname_len, bad); + info->snap_dname = *p; + + *p = end; + return 0; +bad: + return -EIO; +} +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ + /* * parse extra results */ @@ -566,6 +585,10 @@ static int parse_reply_info_extra(void **p, void *end, return parse_reply_info_readdir(p, end, info, features); else if (op == CEPH_MDS_OP_CREATE) return parse_reply_info_create(p, end, info, features, s); +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + else if (op == CEPH_MDS_OP_LOOKUPSNAP) + return parse_reply_info_lookupsnap(p, end, info, features); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ else return -EIO; } @@ -649,20 +672,16 @@ const char *ceph_session_state_name(int s) struct ceph_mds_session *ceph_get_mds_session(struct ceph_mds_session *s) { - if (refcount_inc_not_zero(&s->s_ref)) { - dout("mdsc get_session %p %d -> %d\n", s, - refcount_read(&s->s_ref)-1, refcount_read(&s->s_ref)); + if (refcount_inc_not_zero(&s->s_ref)) return s; - } else { - dout("mdsc get_session %p 0 -- FAIL\n", s); - return NULL; - } + return NULL; } void ceph_put_mds_session(struct ceph_mds_session *s) { - dout("mdsc put_session %p %d -> %d\n", s, - refcount_read(&s->s_ref), refcount_read(&s->s_ref)-1); + if (IS_ERR_OR_NULL(s)) + return; + if (refcount_dec_and_test(&s->s_ref)) { if (s->s_auth.authorizer) ceph_auth_destroy_authorizer(s->s_auth.authorizer); @@ -737,28 +756,19 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_mdsc = mdsc; s->s_mds = mds; s->s_state = CEPH_MDS_SESSION_NEW; - s->s_ttl = 0; - s->s_seq = 0; mutex_init(&s->s_mutex); ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr); - spin_lock_init(&s->s_gen_ttl_lock); - s->s_cap_gen = 1; + atomic_set(&s->s_cap_gen, 1); s->s_cap_ttl = jiffies - 1; spin_lock_init(&s->s_cap_lock); - s->s_renew_requested = 0; - s->s_renew_seq = 0; INIT_LIST_HEAD(&s->s_caps); - s->s_nr_caps = 0; refcount_set(&s->s_ref, 1); INIT_LIST_HEAD(&s->s_waiting); INIT_LIST_HEAD(&s->s_unsafe); xa_init(&s->s_delegated_inos); - s->s_num_cap_releases = 0; - s->s_cap_reconnect = 0; - s->s_cap_iterator = NULL; INIT_LIST_HEAD(&s->s_cap_releases); INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work); @@ -806,6 +816,33 @@ static void put_request_session(struct ceph_mds_request *req) } } +void ceph_mdsc_iterate_sessions(struct ceph_mds_client *mdsc, + void (*cb)(struct ceph_mds_session *), + bool check_state) +{ + int mds; + + mutex_lock(&mdsc->mutex); + for (mds = 0; mds < mdsc->max_sessions; ++mds) { + struct ceph_mds_session *s; + + s = __ceph_lookup_mds_session(mdsc, mds); + if (!s) + continue; + + if (check_state && !check_session_state(s)) { + ceph_put_mds_session(s); + continue; + } + + mutex_unlock(&mdsc->mutex); + cb(s); + ceph_put_mds_session(s); + mutex_lock(&mdsc->mutex); + } + mutex_unlock(&mdsc->mutex); +} + void ceph_mdsc_release_request(struct kref *kref) { struct ceph_mds_request *req = container_of(kref, @@ -819,14 +856,13 @@ void ceph_mdsc_release_request(struct kref *kref) ceph_msg_put(req->r_reply); if (req->r_inode) { ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(req->r_inode); + iput(req->r_inode); } if (req->r_parent) { ceph_put_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN); - ceph_async_iput(req->r_parent); + iput(req->r_parent); } - ceph_async_iput(req->r_target_inode); + iput(req->r_target_inode); if (req->r_dentry) dput(req->r_dentry); if (req->r_old_dentry) @@ -840,10 +876,11 @@ void ceph_mdsc_release_request(struct kref *kref) */ ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir), CEPH_CAP_PIN); - ceph_async_iput(req->r_old_dentry_dir); + iput(req->r_old_dentry_dir); } kfree(req->r_path1); kfree(req->r_path2); + put_cred(req->r_cred); if (req->r_pagelist) ceph_pagelist_release(req->r_pagelist); put_request_session(req); @@ -899,8 +936,7 @@ static void __register_request(struct ceph_mds_client *mdsc, ceph_mdsc_get_request(req); insert_request(&mdsc->request_tree, req); - req->r_uid = current_fsuid(); - req->r_gid = current_fsgid(); + req->r_cred = get_current_cred(); if (mdsc->oldest_tid == 0 && req->r_op != CEPH_MDS_OP_SETFILELOCK) mdsc->oldest_tid = req->r_tid; @@ -955,8 +991,7 @@ static void __unregister_request(struct ceph_mds_client *mdsc, } if (req->r_unsafe_dir) { - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(req->r_unsafe_dir); + iput(req->r_unsafe_dir); req->r_unsafe_dir = NULL; } @@ -1127,7 +1162,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, cap = rb_entry(rb_first(&ci->i_caps), struct ceph_cap, ci_node); if (!cap) { spin_unlock(&ci->i_ceph_lock); - ceph_async_iput(inode); + iput(inode); goto random; } mds = cap->session->s_mds; @@ -1136,9 +1171,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, cap == ci->i_auth_cap ? "auth " : "", cap); spin_unlock(&ci->i_ceph_lock); out: - /* avoid calling iput_final() while holding mdsc->mutex or - * in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); return mds; random: @@ -1154,7 +1187,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc, /* * session messages */ -static struct ceph_msg *create_session_msg(u32 op, u64 seq) +struct ceph_msg *ceph_create_session_msg(u32 op, u64 seq) { struct ceph_msg *msg; struct ceph_mds_session_head *h; @@ -1162,7 +1195,8 @@ static struct ceph_msg *create_session_msg(u32 op, u64 seq) msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), GFP_NOFS, false); if (!msg) { - pr_err("create_session_msg ENOMEM creating msg\n"); + pr_err("ENOMEM creating session %s msg\n", + ceph_session_op_name(op)); return NULL; } h = msg->front.iov_base; @@ -1181,14 +1215,17 @@ static int encode_supported_features(void **p, void *end) if (count > 0) { size_t i; size_t size = FEATURE_BYTES(count); + unsigned long bit; if (WARN_ON_ONCE(*p + 4 + size > end)) return -ERANGE; ceph_encode_32(p, size); memset(*p, 0, size); - for (i = 0; i < count; i++) - ((unsigned char*)(*p))[i / 8] |= BIT(feature_bits[i] % 8); + for (i = 0; i < count; i++) { + bit = feature_bits[i]; + ((unsigned char *)(*p))[bit / 8] |= BIT(bit % 8); + } *p += size; } else { if (WARN_ON_ONCE(*p + 4 > end)) @@ -1250,7 +1287,7 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6 { struct ceph_msg *msg; struct ceph_mds_session_head *h; - int i = -1; + int i; int extra_bytes = 0; int metadata_key_count = 0; struct ceph_options *opt = mdsc->fsc->client->options; @@ -1293,7 +1330,7 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6 msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h) + extra_bytes, GFP_NOFS, false); if (!msg) { - pr_err("create_session_msg ENOMEM creating msg\n"); + pr_err("ENOMEM creating session open msg\n"); return ERR_PTR(-ENOMEM); } p = msg->front.iov_base; @@ -1435,8 +1472,7 @@ static void __open_export_target_sessions(struct ceph_mds_client *mdsc, for (i = 0; i < mi->num_export_targets; i++) { ts = __open_export_target_session(mdsc, mi->export_targets[i]); - if (!IS_ERR(ts)) - ceph_put_mds_session(ts); + ceph_put_mds_session(ts); } } @@ -1479,7 +1515,6 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc, { struct ceph_mds_request *req; struct rb_node *p; - struct ceph_inode_info *ci; dout("cleanup_session_requests mds%d\n", session->s_mds); mutex_lock(&mdsc->mutex); @@ -1488,16 +1523,10 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc, struct ceph_mds_request, r_unsafe_item); pr_warn_ratelimited(" dropping unsafe request %llu\n", req->r_tid); - if (req->r_target_inode) { - /* dropping unsafe change of inode's attributes */ - ci = ceph_inode(req->r_target_inode); - errseq_set(&ci->i_meta_err, -EIO); - } - if (req->r_unsafe_dir) { - /* dropping unsafe directory operation */ - ci = ceph_inode(req->r_unsafe_dir); - errseq_set(&ci->i_meta_err, -EIO); - } + if (req->r_target_inode) + mapping_set_error(req->r_target_inode->i_mapping, -EIO); + if (req->r_unsafe_dir) + mapping_set_error(req->r_unsafe_dir->i_mapping, -EIO); __unregister_request(mdsc, req); } /* zero r_attempts, so kick_requests() will re-send requests */ @@ -1542,9 +1571,7 @@ int ceph_iterate_session_caps(struct ceph_mds_session *session, spin_unlock(&session->s_cap_lock); if (last_inode) { - /* avoid calling iput_final() while holding - * s_mutex or in mds dispatch threads */ - ceph_async_iput(last_inode); + iput(last_inode); last_inode = NULL; } if (old_cap) { @@ -1578,21 +1605,46 @@ int ceph_iterate_session_caps(struct ceph_mds_session *session, session->s_cap_iterator = NULL; spin_unlock(&session->s_cap_lock); - ceph_async_iput(last_inode); + iput(last_inode); if (old_cap) ceph_put_cap(session->s_mdsc, old_cap); return ret; } +static int remove_capsnaps(struct ceph_mds_client *mdsc, struct inode *inode) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_cap_snap *capsnap; + int capsnap_release = 0; + + lockdep_assert_held(&ci->i_ceph_lock); + + dout("removing capsnaps, ci is %p, inode is %p\n", ci, inode); + + while (!list_empty(&ci->i_cap_snaps)) { + capsnap = list_first_entry(&ci->i_cap_snaps, + struct ceph_cap_snap, ci_item); + __ceph_remove_capsnap(inode, capsnap, NULL, NULL); + ceph_put_snap_context(capsnap->context); + ceph_put_cap_snap(capsnap); + capsnap_release++; + } + wake_up_all(&ci->i_cap_wq); + wake_up_all(&mdsc->cap_flushing_wq); + return capsnap_release; +} + static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) { struct ceph_fs_client *fsc = (struct ceph_fs_client *)arg; + struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); LIST_HEAD(to_remove); bool dirty_dropped = false; bool invalidate = false; + int capsnap_release = 0; dout("removing cap %p, ci is %p, inode is %p\n", cap, ci, &ci->vfs_inode); @@ -1600,9 +1652,8 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, __ceph_remove_cap(cap, false); if (!ci->i_auth_cap) { struct ceph_cap_flush *cf; - struct ceph_mds_client *mdsc = fsc->mdsc; - if (READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + if (READ_ONCE(fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) { if (inode->i_data.nrpages > 0) invalidate = true; if (ci->i_wrbuffer_ref > 0) @@ -1618,7 +1669,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, spin_lock(&mdsc->cap_dirty_lock); list_for_each_entry(cf, &to_remove, i_list) - list_del(&cf->g_list); + list_del_init(&cf->g_list); if (!list_empty(&ci->i_dirty_item)) { pr_warn_ratelimited( @@ -1642,7 +1693,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, spin_unlock(&mdsc->cap_dirty_lock); if (dirty_dropped) { - errseq_set(&ci->i_meta_err, -EIO); + mapping_set_error(inode->i_mapping, -EIO); if (ci->i_wrbuffer_ref_head == 0 && ci->i_wr_ref == 0 && @@ -1664,14 +1715,18 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove); ci->i_prealloc_cap_flush = NULL; } + + if (!list_empty(&ci->i_cap_snaps)) + capsnap_release = remove_capsnaps(mdsc, inode); } spin_unlock(&ci->i_ceph_lock); while (!list_empty(&to_remove)) { struct ceph_cap_flush *cf; cf = list_first_entry(&to_remove, struct ceph_cap_flush, i_list); - list_del(&cf->i_list); - ceph_free_cap_flush(cf); + list_del_init(&cf->i_list); + if (!cf->is_capsnap) + ceph_free_cap_flush(cf); } wake_up_all(&ci->i_cap_wq); @@ -1679,6 +1734,8 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, ceph_queue_invalidate(inode); if (dirty_dropped) iput(inode); + while (capsnap_release--) + iput(inode); return 0; } @@ -1718,8 +1775,7 @@ static void remove_session_caps(struct ceph_mds_session *session) spin_unlock(&session->s_cap_lock); inode = ceph_find_inode(sb, vino); - /* avoid calling iput_final() while holding s_mutex */ - ceph_async_iput(inode); + iput(inode); spin_lock(&session->s_cap_lock); } @@ -1758,7 +1814,7 @@ static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap, ci->i_requested_max_size = 0; spin_unlock(&ci->i_ceph_lock); } else if (ev == RENEWCAPS) { - if (cap->cap_gen < cap->session->s_cap_gen) { + if (cap->cap_gen < atomic_read(&cap->session->s_cap_gen)) { /* mds did not re-issue stale cap */ spin_lock(&ci->i_ceph_lock); cap->issued = cap->implemented = CEPH_CAP_PIN; @@ -1805,8 +1861,8 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, dout("send_renew_caps to mds%d (%s)\n", session->s_mds, ceph_mds_state_name(state)); - msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS, - ++session->s_renew_seq); + msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS, + ++session->s_renew_seq); if (!msg) return -ENOMEM; ceph_con_send(&session->s_con, msg); @@ -1820,7 +1876,7 @@ static int send_flushmsg_ack(struct ceph_mds_client *mdsc, dout("send_flushmsg_ack to mds%d (%s)s seq %lld\n", session->s_mds, ceph_session_state_name(session->s_state), seq); - msg = create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq); + msg = ceph_create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq); if (!msg) return -ENOMEM; ceph_con_send(&session->s_con, msg); @@ -1872,7 +1928,8 @@ static int request_close_session(struct ceph_mds_session *session) dout("request_close_session mds%d state %s seq %lld\n", session->s_mds, ceph_session_state_name(session->s_state), session->s_seq); - msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq); + msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_CLOSE, + session->s_seq); if (!msg) return -ENOMEM; ceph_con_send(&session->s_con, msg); @@ -1967,7 +2024,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) if (oissued) { /* we aren't the only cap.. just remove us */ - __ceph_remove_cap(cap, true); + ceph_remove_cap(cap, true); (*remaining)--; } else { struct dentry *dentry; @@ -2486,15 +2543,33 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, return r; } +static void encode_timestamp_and_gids(void **p, + const struct ceph_mds_request *req) +{ + struct ceph_timespec ts; + int i; + + ceph_encode_timespec64(&ts, &req->r_stamp); + ceph_encode_copy(p, &ts, sizeof(ts)); + + /* gid_list */ + ceph_encode_32(p, req->r_cred->group_info->ngroups); + for (i = 0; i < req->r_cred->group_info->ngroups; i++) + ceph_encode_64(p, from_kgid(&init_user_ns, + req->r_cred->group_info->gid[i])); +} + /* * called under mdsc->mutex */ -static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, +static struct ceph_msg *create_request_message(struct ceph_mds_session *session, struct ceph_mds_request *req, - int mds, bool drop_cap_releases) + bool drop_cap_releases) { + int mds = session->s_mds; + struct ceph_mds_client *mdsc = session->s_mdsc; struct ceph_msg *msg; - struct ceph_mds_request_head *head; + struct ceph_mds_request_head_old *head; const char *path1 = NULL; const char *path2 = NULL; u64 ino1 = 0, ino2 = 0; @@ -2504,6 +2579,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, u16 releases; void *p, *end; int ret; + bool legacy = !(session->s_con.peer_features & CEPH_FEATURE_FS_BTIME); ret = set_request_path_attr(req->r_inode, req->r_dentry, req->r_parent, req->r_path1, req->r_ino1.ino, @@ -2525,14 +2601,16 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, goto out_free1; } - len = sizeof(*head) + - pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) + + len = legacy ? sizeof(*head) : sizeof(struct ceph_mds_request_head); + len += pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) + sizeof(struct ceph_timespec); + len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups); /* calculate (max) length for cap releases */ len += sizeof(struct ceph_mds_request_release) * (!!req->r_inode_drop + !!req->r_dentry_drop + !!req->r_old_inode_drop + !!req->r_old_dentry_drop); + if (req->r_dentry_drop) len += pathlen1; if (req->r_old_dentry_drop) @@ -2544,17 +2622,33 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, goto out_free2; } - msg->hdr.version = cpu_to_le16(2); msg->hdr.tid = cpu_to_le64(req->r_tid); - head = msg->front.iov_base; - p = msg->front.iov_base + sizeof(*head); + /* + * The old ceph_mds_request_head didn't contain a version field, and + * one was added when we moved the message version from 3->4. + */ + if (legacy) { + msg->hdr.version = cpu_to_le16(3); + head = msg->front.iov_base; + p = msg->front.iov_base + sizeof(*head); + } else { + struct ceph_mds_request_head *new_head = msg->front.iov_base; + + msg->hdr.version = cpu_to_le16(4); + new_head->version = cpu_to_le16(CEPH_MDS_REQUEST_HEAD_VERSION); + head = (struct ceph_mds_request_head_old *)&new_head->oldest_client_tid; + p = msg->front.iov_base + sizeof(*new_head); + } + end = msg->front.iov_base + msg->front.iov_len; head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch); head->op = cpu_to_le32(req->r_op); - head->caller_uid = cpu_to_le32(from_kuid(&init_user_ns, req->r_uid)); - head->caller_gid = cpu_to_le32(from_kgid(&init_user_ns, req->r_gid)); + head->caller_uid = cpu_to_le32(from_kuid(&init_user_ns, + req->r_cred->fsuid)); + head->caller_gid = cpu_to_le32(from_kgid(&init_user_ns, + req->r_cred->fsgid)); head->ino = cpu_to_le64(req->r_deleg_ino); head->args = req->r_args; @@ -2592,12 +2686,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, head->num_releases = cpu_to_le16(releases); - /* time stamp */ - { - struct ceph_timespec ts; - ceph_encode_timespec64(&ts, &req->r_stamp); - ceph_encode_copy(&p, &ts, sizeof(ts)); - } + encode_timestamp_and_gids(&p, req); if (WARN_ON_ONCE(p > end)) { ceph_msg_put(msg); @@ -2642,14 +2731,28 @@ static void complete_request(struct ceph_mds_client *mdsc, complete_all(&req->r_completion); } +static struct ceph_mds_request_head_old * +find_old_request_head(void *p, u64 features) +{ + bool legacy = !(features & CEPH_FEATURE_FS_BTIME); + struct ceph_mds_request_head *new_head; + + if (legacy) + return (struct ceph_mds_request_head_old *)p; + new_head = (struct ceph_mds_request_head *)p; + return (struct ceph_mds_request_head_old *)&new_head->oldest_client_tid; +} + /* * called under mdsc->mutex */ -static int __prepare_send_request(struct ceph_mds_client *mdsc, +static int __prepare_send_request(struct ceph_mds_session *session, struct ceph_mds_request *req, - int mds, bool drop_cap_releases) + bool drop_cap_releases) { - struct ceph_mds_request_head *rhead; + int mds = session->s_mds; + struct ceph_mds_client *mdsc = session->s_mdsc; + struct ceph_mds_request_head_old *rhead; struct ceph_msg *msg; int flags = 0; @@ -2668,6 +2771,7 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) { void *p; + /* * Replay. Do not regenerate message (and rebuild * paths, etc.); just use the original message. @@ -2675,7 +2779,8 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, * d_move mangles the src name. */ msg = req->r_request; - rhead = msg->front.iov_base; + rhead = find_old_request_head(msg->front.iov_base, + session->s_con.peer_features); flags = le32_to_cpu(rhead->flags); flags |= CEPH_MDS_FLAG_REPLAY; @@ -2689,13 +2794,8 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, /* remove cap/dentry releases from message */ rhead->num_releases = 0; - /* time stamp */ p = msg->front.iov_base + req->r_request_release_offset; - { - struct ceph_timespec ts; - ceph_encode_timespec64(&ts, &req->r_stamp); - ceph_encode_copy(&p, &ts, sizeof(ts)); - } + encode_timestamp_and_gids(&p, req); msg->front.iov_len = p - msg->front.iov_base; msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); @@ -2706,14 +2806,15 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, ceph_msg_put(req->r_request); req->r_request = NULL; } - msg = create_request_message(mdsc, req, mds, drop_cap_releases); + msg = create_request_message(session, req, drop_cap_releases); if (IS_ERR(msg)) { req->r_err = PTR_ERR(msg); return PTR_ERR(msg); } req->r_request = msg; - rhead = msg->front.iov_base; + rhead = find_old_request_head(msg->front.iov_base, + session->s_con.peer_features); rhead->oldest_client_tid = cpu_to_le64(__get_oldest_tid(mdsc)); if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) flags |= CEPH_MDS_FLAG_REPLAY; @@ -2732,15 +2833,13 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, /* * called under mdsc->mutex */ -static int __send_request(struct ceph_mds_client *mdsc, - struct ceph_mds_session *session, +static int __send_request(struct ceph_mds_session *session, struct ceph_mds_request *req, bool drop_cap_releases) { int err; - err = __prepare_send_request(mdsc, req, session->s_mds, - drop_cap_releases); + err = __prepare_send_request(session, req, drop_cap_releases); if (!err) { ceph_msg_get(req->r_request); ceph_con_send(&session->s_con, req->r_request); @@ -2825,10 +2924,6 @@ static void __do_request(struct ceph_mds_client *mdsc, ceph_session_state_name(session->s_state)); if (session->s_state != CEPH_MDS_SESSION_OPEN && session->s_state != CEPH_MDS_SESSION_HUNG) { - if (session->s_state == CEPH_MDS_SESSION_REJECTED) { - err = -EACCES; - goto out_session; - } /* * We cannot queue async requests since the caps and delegated * inodes are bound to the session. Just return -EJUKEBOX and @@ -2838,6 +2933,20 @@ static void __do_request(struct ceph_mds_client *mdsc, err = -EJUKEBOX; goto out_session; } + + /* + * If the session has been REJECTED, then return a hard error, + * unless it's a CLEANRECOVER mount, in which case we'll queue + * it to the mdsc queue. + */ + if (session->s_state == CEPH_MDS_SESSION_REJECTED) { + if (ceph_test_mount_opt(mdsc->fsc, CLEANRECOVER)) + list_add(&req->r_wait, &mdsc->waiting_for_map); + else + err = -EACCES; + goto out_session; + } + if (session->s_state == CEPH_MDS_SESSION_NEW || session->s_state == CEPH_MDS_SESSION_CLOSING) { err = __open_session(mdsc, session); @@ -2857,7 +2966,7 @@ static void __do_request(struct ceph_mds_client *mdsc, if (req->r_request_started == 0) /* note request start time */ req->r_request_started = jiffies; - err = __send_request(mdsc, session, req, false); + err = __send_request(session, req, false); out_session: ceph_put_mds_session(session); @@ -2933,7 +3042,6 @@ int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc, struct inode *dir, ceph_take_cap_refs(ci, CEPH_CAP_PIN, false); __ceph_touch_fmode(ci, mdsc, fmode); spin_unlock(&ci->i_ceph_lock); - ihold(req->r_parent); } if (req->r_old_dentry_dir) ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir), @@ -3180,6 +3288,23 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) err = parse_reply_info(session, msg, rinfo, session->s_con.peer_features); mutex_unlock(&mdsc->mutex); + /* Must find target inode outside of mutexes to avoid deadlocks */ + if ((err >= 0) && rinfo->head->is_target) { + struct inode *in; + struct ceph_vino tvino = { + .ino = le64_to_cpu(rinfo->targeti.in->ino), + .snap = le64_to_cpu(rinfo->targeti.in->snapid) + }; + + in = ceph_get_inode(mdsc->fsc->sb, tvino); + if (IS_ERR(in)) { + err = PTR_ERR(in); + mutex_lock(&session->s_mutex); + goto out_err; + } + req->r_target_inode = in; + } + mutex_lock(&session->s_mutex); if (err < 0) { pr_err("mdsc_handle_reply got corrupt reply mds%d(tid:%lld)\n", mds, tid); @@ -3248,7 +3373,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) /* kick calling process */ complete_request(mdsc, req); - ceph_update_metadata_latency(&mdsc->metric, req->r_start_latency, + ceph_update_metadata_metrics(&mdsc->metric, req->r_start_latency, req->r_end_latency, err); out: ceph_mdsc_put_request(req); @@ -3427,10 +3552,8 @@ static void handle_session(struct ceph_mds_session *session, case CEPH_SESSION_STALE: pr_info("mds%d caps went stale, renewing\n", session->s_mds); - spin_lock(&session->s_gen_ttl_lock); - session->s_cap_gen++; + atomic_inc(&session->s_cap_gen); session->s_cap_ttl = jiffies - 1; - spin_unlock(&session->s_gen_ttl_lock); send_renew_caps(mdsc, session); break; @@ -3521,7 +3644,7 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc, mutex_lock(&mdsc->mutex); list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item) - __send_request(mdsc, session, req, true); + __send_request(session, req, true); /* * also re-send old requests when MDS enters reconnect stage. So that MDS @@ -3542,7 +3665,7 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc, ceph_mdsc_release_dir_caps_no_check(req); - __send_request(mdsc, session, req, true); + __send_request(session, req, true); } mutex_unlock(&mdsc->mutex); } @@ -3671,7 +3794,7 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap, struct ceph_pagelist *pagelist = recon_state->pagelist; struct dentry *dentry; char *path; - int pathlen, err; + int pathlen = 0, err; u64 pathbase; u64 snap_follows; @@ -3691,7 +3814,6 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap, } } else { path = NULL; - pathlen = 0; pathbase = 0; } @@ -3699,7 +3821,7 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap, cap->seq = 0; /* reset cap seq */ cap->issue_seq = 0; /* and issue_seq */ cap->mseq = 0; /* and migrate_seq */ - cap->cap_gen = cap->session->s_cap_gen; + cap->cap_gen = atomic_read(&cap->session->s_cap_gen); /* These are lost when the session goes away */ if (S_ISDIR(inode->i_mode)) { @@ -3722,7 +3844,7 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap, rec.v1.cap_id = cpu_to_le64(cap->cap_id); rec.v1.wanted = cpu_to_le32(__ceph_caps_wanted(ci)); rec.v1.issued = cpu_to_le32(cap->issued); - rec.v1.size = cpu_to_le64(inode->i_size); + rec.v1.size = cpu_to_le64(i_size_read(inode)); ceph_encode_timespec64(&rec.v1.mtime, &inode->i_mtime); ceph_encode_timespec64(&rec.v1.atime, &inode->i_atime); rec.v1.snaprealm = cpu_to_le64(ci->i_snap_realm->ino); @@ -3939,9 +4061,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, dout("session %p state %s\n", session, ceph_session_state_name(session->s_state)); - spin_lock(&session->s_gen_ttl_lock); - session->s_cap_gen++; - spin_unlock(&session->s_gen_ttl_lock); + atomic_inc(&session->s_cap_gen); spin_lock(&session->s_cap_lock); /* don't know if session is readonly */ @@ -4088,13 +4208,21 @@ static void check_new_map(struct ceph_mds_client *mdsc, struct ceph_mdsmap *newmap, struct ceph_mdsmap *oldmap) { - int i; + int i, j, err; int oldstate, newstate; struct ceph_mds_session *s; + unsigned long targets[DIV_ROUND_UP(CEPH_MAX_MDS, sizeof(unsigned long))] = {0}; dout("check_new_map new %u old %u\n", newmap->m_epoch, oldmap->m_epoch); + if (newmap->m_info) { + for (i = 0; i < newmap->possible_max_rank; i++) { + for (j = 0; j < newmap->m_info[i].num_export_targets; j++) + set_bit(newmap->m_info[i].export_targets[j], targets); + } + } + for (i = 0; i < oldmap->possible_max_rank && i < mdsc->max_sessions; i++) { if (!mdsc->sessions[i]) continue; @@ -4148,6 +4276,7 @@ static void check_new_map(struct ceph_mds_client *mdsc, if (s->s_state == CEPH_MDS_SESSION_RESTARTING && newstate >= CEPH_MDS_STATE_RECONNECT) { mutex_unlock(&mdsc->mutex); + clear_bit(i, targets); send_mds_reconnect(mdsc, s); mutex_lock(&mdsc->mutex); } @@ -4170,6 +4299,51 @@ static void check_new_map(struct ceph_mds_client *mdsc, } } + /* + * Only open and reconnect sessions that don't exist yet. + */ + for (i = 0; i < newmap->possible_max_rank; i++) { + /* + * In case the import MDS is crashed just after + * the EImportStart journal is flushed, so when + * a standby MDS takes over it and is replaying + * the EImportStart journal the new MDS daemon + * will wait the client to reconnect it, but the + * client may never register/open the session yet. + * + * Will try to reconnect that MDS daemon if the + * rank number is in the export targets array and + * is the up:reconnect state. + */ + newstate = ceph_mdsmap_get_state(newmap, i); + if (!test_bit(i, targets) || newstate != CEPH_MDS_STATE_RECONNECT) + continue; + + /* + * The session maybe registered and opened by some + * requests which were choosing random MDSes during + * the mdsc->mutex's unlock/lock gap below in rare + * case. But the related MDS daemon will just queue + * that requests and be still waiting for the client's + * reconnection request in up:reconnect state. + */ + s = __ceph_lookup_mds_session(mdsc, i); + if (likely(!s)) { + s = __open_export_target_session(mdsc, i); + if (IS_ERR(s)) { + err = PTR_ERR(s); + pr_err("failed to open export target session, err %d\n", + err); + continue; + } + } + dout("send reconnect to export target mds.%d\n", i); + mutex_unlock(&mdsc->mutex); + send_mds_reconnect(mdsc, s); + ceph_put_mds_session(s); + mutex_lock(&mdsc->mutex); + } + for (i = 0; i < newmap->possible_max_rank && i < mdsc->max_sessions; i++) { s = mdsc->sessions[i]; if (!s) @@ -4217,6 +4391,9 @@ static void handle_lease(struct ceph_mds_client *mdsc, struct ceph_vino vino; struct qstr dname; int release = 0; +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + int err; +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ dout("handle_lease from mds%d\n", mds); @@ -4252,7 +4429,17 @@ static void handle_lease(struct ceph_mds_client *mdsc, WARN_ON(1); goto release; /* hrm... */ } +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + err = ceph_upper_full_name_hash(parent, dname.name, dname.len, &dname.hash); + if (err < 0) { + dout("ceph upper full name hash failed name[%.*s] len %d, err %d\n", + dname.len > 16 ? 16 : dname.len, dname.name, dname.len, err); + dput(parent); + goto release; + } +#else dname.hash = full_name_hash(parent, dname.name, dname.len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ dentry = d_lookup(parent, &dname); dput(parent); if (!dentry) @@ -4272,7 +4459,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, case CEPH_MDS_LEASE_RENEW: if (di->lease_session == session && - di->lease_gen == session->s_cap_gen && + di->lease_gen == atomic_read(&session->s_cap_gen) && di->lease_renew_from && di->lease_renew_after == 0) { unsigned long duration = @@ -4300,8 +4487,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, out: mutex_unlock(&session->s_mutex); - /* avoid calling iput_final() in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); return; bad: @@ -4348,24 +4534,12 @@ void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session, } /* - * lock unlock sessions, to wait ongoing session activities + * lock unlock the session, to wait ongoing session activities */ -static void lock_unlock_sessions(struct ceph_mds_client *mdsc) +static void lock_unlock_session(struct ceph_mds_session *s) { - int i; - - mutex_lock(&mdsc->mutex); - for (i = 0; i < mdsc->max_sessions; i++) { - struct ceph_mds_session *s = __ceph_lookup_mds_session(mdsc, i); - if (!s) - continue; - mutex_unlock(&mdsc->mutex); - mutex_lock(&s->s_mutex); - mutex_unlock(&s->s_mutex); - ceph_put_mds_session(s); - mutex_lock(&mdsc->mutex); - } - mutex_unlock(&mdsc->mutex); + mutex_lock(&s->s_mutex); + mutex_unlock(&s->s_mutex); } static void maybe_recover_session(struct ceph_mds_client *mdsc) @@ -4381,17 +4555,14 @@ static void maybe_recover_session(struct ceph_mds_client *mdsc) if (!READ_ONCE(fsc->blocklisted)) return; - if (fsc->last_auto_reconnect && - time_before(jiffies, fsc->last_auto_reconnect + HZ * 60 * 30)) - return; - pr_info("auto reconnect after blocklisted\n"); - fsc->last_auto_reconnect = jiffies; ceph_force_reconnect(fsc->sb); } bool check_session_state(struct ceph_mds_session *s) { + struct ceph_fs_client *fsc = s->s_mdsc->fsc; + switch (s->s_state) { case CEPH_MDS_SESSION_OPEN: if (s->s_ttl && time_after(jiffies, s->s_ttl)) { @@ -4400,8 +4571,9 @@ bool check_session_state(struct ceph_mds_session *s) } break; case CEPH_MDS_SESSION_CLOSING: - /* Should never reach this when we're unmounting */ - WARN_ON_ONCE(s->s_ttl); + /* Should never reach this when not force unmounting */ + WARN_ON_ONCE(s->s_ttl && + READ_ONCE(fsc->mount_state) != CEPH_MOUNT_SHUTDOWN); fallthrough; case CEPH_MDS_SESSION_NEW: case CEPH_MDS_SESSION_RESTARTING: @@ -4435,22 +4607,29 @@ void inc_session_sequence(struct ceph_mds_session *s) } /* - * delayed work -- periodically trim expired leases, renew caps with mds + * delayed work -- periodically trim expired leases, renew caps with mds. If + * the @delay parameter is set to 0 or if it's more than 5 secs, the default + * workqueue delay value of 5 secs will be used. */ -static void schedule_delayed(struct ceph_mds_client *mdsc) +static void schedule_delayed(struct ceph_mds_client *mdsc, unsigned long delay) { - int delay = 5; - unsigned hz = round_jiffies_relative(HZ * delay); - schedule_delayed_work(&mdsc->delayed_work, hz); + unsigned long max_delay = HZ * 5; + + /* 5 secs default delay */ + if (!delay || (delay > max_delay)) + delay = max_delay; + schedule_delayed_work(&mdsc->delayed_work, + round_jiffies_relative(delay)); } static void delayed_work(struct work_struct *work) { - int i; struct ceph_mds_client *mdsc = container_of(work, struct ceph_mds_client, delayed_work.work); + unsigned long delay; int renew_interval; int renew_caps; + int i; dout("mdsc delayed_work\n"); @@ -4490,7 +4669,7 @@ static void delayed_work(struct work_struct *work) } mutex_unlock(&mdsc->mutex); - ceph_check_delayed_caps(mdsc); + delay = ceph_check_delayed_caps(mdsc); ceph_queue_cap_reclaim_work(mdsc); @@ -4498,7 +4677,7 @@ static void delayed_work(struct work_struct *work) maybe_recover_session(mdsc); - schedule_delayed(mdsc); + schedule_delayed(mdsc, delay); } int ceph_mdsc_init(struct ceph_fs_client *fsc) @@ -4521,21 +4700,12 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) init_completion(&mdsc->safe_umount_waiters); init_waitqueue_head(&mdsc->session_close_wq); INIT_LIST_HEAD(&mdsc->waiting_for_map); - mdsc->sessions = NULL; - atomic_set(&mdsc->num_sessions, 0); - mdsc->max_sessions = 0; - mdsc->stopping = 0; - atomic64_set(&mdsc->quotarealms_count, 0); mdsc->quotarealms_inodes = RB_ROOT; mutex_init(&mdsc->quotarealms_inodes_mutex); - mdsc->last_snap_seq = 0; init_rwsem(&mdsc->snap_rwsem); mdsc->snap_realms = RB_ROOT; INIT_LIST_HEAD(&mdsc->snap_empty); - mdsc->num_snap_realms = 0; spin_lock_init(&mdsc->snap_empty_lock); - mdsc->last_tid = 0; - mdsc->oldest_tid = 0; mdsc->request_tree = RB_ROOT; INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work); mdsc->last_renew_caps = jiffies; @@ -4547,11 +4717,9 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) mdsc->last_cap_flush_tid = 1; INIT_LIST_HEAD(&mdsc->cap_flush_list); INIT_LIST_HEAD(&mdsc->cap_dirty_migrating); - mdsc->num_cap_flushing = 0; spin_lock_init(&mdsc->cap_dirty_lock); init_waitqueue_head(&mdsc->cap_flushing_wq); INIT_WORK(&mdsc->cap_reclaim_work, ceph_cap_reclaim_work); - atomic_set(&mdsc->cap_reclaim_pending, 0); err = ceph_metric_init(&mdsc->metric); if (err) goto err_mdsmap; @@ -4613,6 +4781,30 @@ static void wait_requests(struct ceph_mds_client *mdsc) dout("wait_requests done\n"); } +void send_flush_mdlog(struct ceph_mds_session *s) +{ + struct ceph_msg *msg; + + /* + * Pre-luminous MDS crashes when it sees an unknown session request + */ + if (!CEPH_HAVE_FEATURE(s->s_con.peer_features, SERVER_LUMINOUS)) + return; + + mutex_lock(&s->s_mutex); + dout("request mdlog flush to mds%d (%s)s seq %lld\n", s->s_mds, + ceph_session_state_name(s->s_state), s->s_seq); + msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_FLUSH_MDLOG, + s->s_seq); + if (!msg) { + pr_err("failed to request mdlog flush to mds%d (%s) seq %lld\n", + s->s_mds, ceph_session_state_name(s->s_state), s->s_seq); + } else { + ceph_con_send(&s->s_con, msg); + } + mutex_unlock(&s->s_mutex); +} + /* * called before mount is ro, and before dentries are torn down. * (hmm, does this still race with new lookups?) @@ -4622,7 +4814,8 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc) dout("pre_umount\n"); mdsc->stopping = 1; - lock_unlock_sessions(mdsc); + ceph_mdsc_iterate_sessions(mdsc, send_flush_mdlog, true); + ceph_mdsc_iterate_sessions(mdsc, lock_unlock_session, false); ceph_flush_dirty_caps(mdsc); wait_requests(mdsc); @@ -4636,15 +4829,17 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc) } /* - * wait for all write mds requests to flush. + * flush the mdlog and wait for all write mds requests to flush. */ -static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid) +static void flush_mdlog_and_wait_mdsc_unsafe_requests(struct ceph_mds_client *mdsc, + u64 want_tid) { struct ceph_mds_request *req = NULL, *nextreq; + struct ceph_mds_session *last_session = NULL; struct rb_node *n; mutex_lock(&mdsc->mutex); - dout("wait_unsafe_requests want %lld\n", want_tid); + dout("%s want %lld\n", __func__, want_tid); restart: req = __get_oldest_req(mdsc); while (req && req->r_tid <= want_tid) { @@ -4656,14 +4851,32 @@ static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid) nextreq = NULL; if (req->r_op != CEPH_MDS_OP_SETFILELOCK && (req->r_op & CEPH_MDS_OP_WRITE)) { + struct ceph_mds_session *s = req->r_session; + + if (!s) { + req = nextreq; + continue; + } + /* write op */ ceph_mdsc_get_request(req); if (nextreq) ceph_mdsc_get_request(nextreq); + s = ceph_get_mds_session(s); mutex_unlock(&mdsc->mutex); - dout("wait_unsafe_requests wait on %llu (want %llu)\n", + + /* send flush mdlog request to MDS */ + if (last_session != s) { + send_flush_mdlog(s); + ceph_put_mds_session(last_session); + last_session = s; + } else { + ceph_put_mds_session(s); + } + dout("%s wait on %llu (want %llu)\n", __func__, req->r_tid, want_tid); wait_for_completion(&req->r_safe_completion); + mutex_lock(&mdsc->mutex); ceph_mdsc_put_request(req); if (!nextreq) @@ -4678,14 +4891,15 @@ static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid) req = nextreq; } mutex_unlock(&mdsc->mutex); - dout("wait_unsafe_requests done\n"); + ceph_put_mds_session(last_session); + dout("%s done\n", __func__); } void ceph_mdsc_sync(struct ceph_mds_client *mdsc) { u64 want_tid, want_flush; - if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) + if (READ_ONCE(mdsc->fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) return; dout("sync\n"); @@ -4707,7 +4921,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) dout("sync want tid %lld flush_seq %lld\n", want_tid, want_flush); - wait_unsafe_requests(mdsc, want_tid); + flush_mdlog_and_wait_mdsc_unsafe_requests(mdsc, want_tid); wait_caps_flush(mdsc, want_flush); } @@ -4849,7 +5063,6 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc) ceph_metric_destroy(&mdsc->metric); - flush_delayed_work(&mdsc->metric.delayed_work); fsc->mdsc = NULL; kfree(mdsc); dout("mdsc_destroy %p done\n", mdsc); @@ -4862,10 +5075,8 @@ void ceph_mdsc_handle_fsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg) void *p = msg->front.iov_base; void *end = p + msg->front.iov_len; u32 epoch; - u32 map_len; u32 num_fs; u32 mount_fscid = (u32)-1; - u8 struct_v, struct_cv; int err = -EINVAL; ceph_decode_need(&p, end, sizeof(u32), bad); @@ -4873,24 +5084,17 @@ void ceph_mdsc_handle_fsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg) dout("handle_fsmap epoch %u\n", epoch); - ceph_decode_need(&p, end, 2 + sizeof(u32), bad); - struct_v = ceph_decode_8(&p); - struct_cv = ceph_decode_8(&p); - map_len = ceph_decode_32(&p); + /* struct_v, struct_cv, map_len, epoch, legacy_client_fscid */ + ceph_decode_skip_n(&p, end, 2 + sizeof(u32) * 3, bad); - ceph_decode_need(&p, end, sizeof(u32) * 3, bad); - p += sizeof(u32) * 2; /* skip epoch and legacy_client_fscid */ - - num_fs = ceph_decode_32(&p); + ceph_decode_32_safe(&p, end, num_fs, bad); while (num_fs-- > 0) { void *info_p, *info_end; u32 info_len; - u8 info_v, info_cv; u32 fscid, namelen; ceph_decode_need(&p, end, 2 + sizeof(u32), bad); - info_v = ceph_decode_8(&p); - info_cv = ceph_decode_8(&p); + p += 2; // info_v, info_cv info_len = ceph_decode_32(&p); ceph_decode_need(&p, end, info_len, bad); info_p = p; @@ -4984,7 +5188,7 @@ void ceph_mdsc_handle_mdsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg) mdsc->mdsmap->m_epoch); mutex_unlock(&mdsc->mutex); - schedule_delayed(mdsc); + schedule_delayed(mdsc, 0); return; bad_unlock: diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index f5adbebcb38e..88db01b6f98a 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -33,10 +33,6 @@ enum ceph_feature_type { CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_METRIC_COLLECT, }; -/* - * This will always have the highest feature bit value - * as the last element of the array. - */ #define CEPHFS_FEATURES_CLIENT_SUPPORTED { \ 0, 1, 2, 3, 4, 5, 6, 7, \ CEPHFS_FEATURE_MIMIC, \ @@ -45,8 +41,6 @@ enum ceph_feature_type { CEPHFS_FEATURE_MULTI_RECONNECT, \ CEPHFS_FEATURE_DELEG_INO, \ CEPHFS_FEATURE_METRIC_COLLECT, \ - \ - CEPHFS_FEATURE_MAX, \ } #define CEPHFS_FEATURES_CLIENT_REQUIRED {} @@ -88,6 +82,7 @@ struct ceph_mds_reply_info_in { s32 dir_pin; struct ceph_timespec btime; struct ceph_timespec snap_btime; + u64 rsnaps; u64 change_attr; }; @@ -137,6 +132,14 @@ struct ceph_mds_reply_info_parsed { bool has_create_ino; u64 ino; }; + +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + /* for lookup snap caseless results */ + struct { + char *snap_dname; + u32 snap_dname_len; + }; +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ }; /* encoded blob describing snapshot contexts for certain @@ -185,10 +188,8 @@ struct ceph_mds_session { struct ceph_auth_handshake s_auth; - /* protected by s_gen_ttl_lock */ - spinlock_t s_gen_ttl_lock; - u32 s_cap_gen; /* inc each time we get mds stale msg */ - unsigned long s_cap_ttl; /* when session caps expire */ + atomic_t s_cap_gen; /* inc each time we get mds stale msg */ + unsigned long s_cap_ttl; /* when session caps expire. protected by s_mutex */ /* protected by s_cap_lock */ spinlock_t s_cap_lock; @@ -275,8 +276,7 @@ struct ceph_mds_request { union ceph_mds_request_args r_args; int r_fmode; /* file mode, if expecting cap */ - kuid_t r_uid; - kgid_t r_gid; + const struct cred *r_cred; int r_request_release_offset; struct timespec64 r_stamp; @@ -524,6 +524,11 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req) kref_put(&req->r_kref, ceph_mdsc_release_request); } +extern void send_flush_mdlog(struct ceph_mds_session *s); +extern void ceph_mdsc_iterate_sessions(struct ceph_mds_client *mdsc, + void (*cb)(struct ceph_mds_session *), + bool check_state); +extern struct ceph_msg *ceph_create_session_msg(u32 op, u64 seq); extern void __ceph_queue_cap_release(struct ceph_mds_session *session, struct ceph_cap *cap); extern void ceph_flush_cap_releases(struct ceph_mds_client *mdsc, diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c index 1096d1d3a84c..f6c7bfddda59 100644 --- a/fs/ceph/mdsmap.c +++ b/fs/ceph/mdsmap.c @@ -122,6 +122,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) int err; u8 mdsmap_v; u16 mdsmap_ev; + u32 target; m = kzalloc(sizeof(*m), GFP_NOFS); if (!m) @@ -259,9 +260,10 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) sizeof(u32), GFP_NOFS); if (!info->export_targets) goto nomem; - for (j = 0; j < num_export_targets; j++) - info->export_targets[j] = - ceph_decode_32(&pexport_targets); + for (j = 0; j < num_export_targets; j++) { + target = ceph_decode_32(&pexport_targets); + info->export_targets[j] = target; + } } else { info->export_targets = NULL; } @@ -393,9 +395,11 @@ void ceph_mdsmap_destroy(struct ceph_mdsmap *m) { int i; - for (i = 0; i < m->possible_max_rank; i++) - kfree(m->m_info[i].export_targets); - kfree(m->m_info); + if (m->m_info) { + for (i = 0; i < m->possible_max_rank; i++) + kfree(m->m_info[i].export_targets); + kfree(m->m_info); + } kfree(m->m_data_pg_pools); kfree(m); } diff --git a/fs/ceph/metric.c b/fs/ceph/metric.c index fee4c4778313..04d5df29bbbf 100644 --- a/fs/ceph/metric.c +++ b/fs/ceph/metric.c @@ -16,8 +16,15 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, struct ceph_metric_read_latency *read; struct ceph_metric_write_latency *write; struct ceph_metric_metadata_latency *meta; + struct ceph_metric_dlease *dlease; + struct ceph_opened_files *files; + struct ceph_pinned_icaps *icaps; + struct ceph_opened_inodes *inodes; + struct ceph_read_io_size *rsize; + struct ceph_write_io_size *wsize; struct ceph_client_metric *m = &mdsc->metric; u64 nr_caps = atomic64_read(&m->total_caps); + u32 header_len = sizeof(struct ceph_metric_header); struct ceph_msg *msg; struct timespec64 ts; s64 sum; @@ -25,7 +32,9 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, s32 len; len = sizeof(*head) + sizeof(*cap) + sizeof(*read) + sizeof(*write) - + sizeof(*meta); + + sizeof(*meta) + sizeof(*dlease) + sizeof(*files) + + sizeof(*icaps) + sizeof(*inodes) + sizeof(*rsize) + + sizeof(*wsize); msg = ceph_msg_new(CEPH_MSG_CLIENT_METRICS, len, GFP_NOFS, true); if (!msg) { @@ -38,21 +47,21 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the cap metric */ cap = (struct ceph_metric_cap *)(head + 1); - cap->type = cpu_to_le32(CLIENT_METRIC_TYPE_CAP_INFO); - cap->ver = 1; - cap->compat = 1; - cap->data_len = cpu_to_le32(sizeof(*cap) - 10); - cap->hit = cpu_to_le64(percpu_counter_sum(&mdsc->metric.i_caps_hit)); - cap->mis = cpu_to_le64(percpu_counter_sum(&mdsc->metric.i_caps_mis)); + cap->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_CAP_INFO); + cap->header.ver = 1; + cap->header.compat = 1; + cap->header.data_len = cpu_to_le32(sizeof(*cap) - header_len); + cap->hit = cpu_to_le64(percpu_counter_sum(&m->i_caps_hit)); + cap->mis = cpu_to_le64(percpu_counter_sum(&m->i_caps_mis)); cap->total = cpu_to_le64(nr_caps); items++; /* encode the read latency metric */ read = (struct ceph_metric_read_latency *)(cap + 1); - read->type = cpu_to_le32(CLIENT_METRIC_TYPE_READ_LATENCY); - read->ver = 1; - read->compat = 1; - read->data_len = cpu_to_le32(sizeof(*read) - 10); + read->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_READ_LATENCY); + read->header.ver = 1; + read->header.compat = 1; + read->header.data_len = cpu_to_le32(sizeof(*read) - header_len); sum = m->read_latency_sum; jiffies_to_timespec64(sum, &ts); read->sec = cpu_to_le32(ts.tv_sec); @@ -61,10 +70,10 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the write latency metric */ write = (struct ceph_metric_write_latency *)(read + 1); - write->type = cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_LATENCY); - write->ver = 1; - write->compat = 1; - write->data_len = cpu_to_le32(sizeof(*write) - 10); + write->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_LATENCY); + write->header.ver = 1; + write->header.compat = 1; + write->header.data_len = cpu_to_le32(sizeof(*write) - header_len); sum = m->write_latency_sum; jiffies_to_timespec64(sum, &ts); write->sec = cpu_to_le32(ts.tv_sec); @@ -73,16 +82,79 @@ static bool ceph_mdsc_send_metrics(struct ceph_mds_client *mdsc, /* encode the metadata latency metric */ meta = (struct ceph_metric_metadata_latency *)(write + 1); - meta->type = cpu_to_le32(CLIENT_METRIC_TYPE_METADATA_LATENCY); - meta->ver = 1; - meta->compat = 1; - meta->data_len = cpu_to_le32(sizeof(*meta) - 10); + meta->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_METADATA_LATENCY); + meta->header.ver = 1; + meta->header.compat = 1; + meta->header.data_len = cpu_to_le32(sizeof(*meta) - header_len); sum = m->metadata_latency_sum; jiffies_to_timespec64(sum, &ts); meta->sec = cpu_to_le32(ts.tv_sec); meta->nsec = cpu_to_le32(ts.tv_nsec); items++; + /* encode the dentry lease metric */ + dlease = (struct ceph_metric_dlease *)(meta + 1); + dlease->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_DENTRY_LEASE); + dlease->header.ver = 1; + dlease->header.compat = 1; + dlease->header.data_len = cpu_to_le32(sizeof(*dlease) - header_len); + dlease->hit = cpu_to_le64(percpu_counter_sum(&m->d_lease_hit)); + dlease->mis = cpu_to_le64(percpu_counter_sum(&m->d_lease_mis)); + dlease->total = cpu_to_le64(atomic64_read(&m->total_dentries)); + items++; + + sum = percpu_counter_sum(&m->total_inodes); + + /* encode the opened files metric */ + files = (struct ceph_opened_files *)(dlease + 1); + files->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_OPENED_FILES); + files->header.ver = 1; + files->header.compat = 1; + files->header.data_len = cpu_to_le32(sizeof(*files) - header_len); + files->opened_files = cpu_to_le64(atomic64_read(&m->opened_files)); + files->total = cpu_to_le64(sum); + items++; + + /* encode the pinned icaps metric */ + icaps = (struct ceph_pinned_icaps *)(files + 1); + icaps->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_PINNED_ICAPS); + icaps->header.ver = 1; + icaps->header.compat = 1; + icaps->header.data_len = cpu_to_le32(sizeof(*icaps) - header_len); + icaps->pinned_icaps = cpu_to_le64(nr_caps); + icaps->total = cpu_to_le64(sum); + items++; + + /* encode the opened inodes metric */ + inodes = (struct ceph_opened_inodes *)(icaps + 1); + inodes->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_OPENED_INODES); + inodes->header.ver = 1; + inodes->header.compat = 1; + inodes->header.data_len = cpu_to_le32(sizeof(*inodes) - header_len); + inodes->opened_inodes = cpu_to_le64(percpu_counter_sum(&m->opened_inodes)); + inodes->total = cpu_to_le64(sum); + items++; + + /* encode the read io size metric */ + rsize = (struct ceph_read_io_size *)(inodes + 1); + rsize->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_READ_IO_SIZES); + rsize->header.ver = 1; + rsize->header.compat = 1; + rsize->header.data_len = cpu_to_le32(sizeof(*rsize) - header_len); + rsize->total_ops = cpu_to_le64(m->total_reads); + rsize->total_size = cpu_to_le64(m->read_size_sum); + items++; + + /* encode the write io size metric */ + wsize = (struct ceph_write_io_size *)(rsize + 1); + wsize->header.type = cpu_to_le32(CLIENT_METRIC_TYPE_WRITE_IO_SIZES); + wsize->header.ver = 1; + wsize->header.compat = 1; + wsize->header.data_len = cpu_to_le32(sizeof(*wsize) - header_len); + wsize->total_ops = cpu_to_le64(m->total_writes); + wsize->total_size = cpu_to_le64(m->write_size_sum); + items++; + put_unaligned_le32(items, &head->num); msg->front.iov_len = len; msg->hdr.version = cpu_to_le16(1); @@ -171,21 +243,27 @@ int ceph_metric_init(struct ceph_client_metric *m) if (ret) goto err_i_caps_mis; - spin_lock_init(&m->read_latency_lock); + spin_lock_init(&m->read_metric_lock); m->read_latency_sq_sum = 0; m->read_latency_min = KTIME_MAX; m->read_latency_max = 0; m->total_reads = 0; m->read_latency_sum = 0; + m->read_size_min = U64_MAX; + m->read_size_max = 0; + m->read_size_sum = 0; - spin_lock_init(&m->write_latency_lock); + spin_lock_init(&m->write_metric_lock); m->write_latency_sq_sum = 0; m->write_latency_min = KTIME_MAX; m->write_latency_max = 0; m->total_writes = 0; m->write_latency_sum = 0; + m->write_size_min = U64_MAX; + m->write_size_max = 0; + m->write_size_sum = 0; - spin_lock_init(&m->metadata_latency_lock); + spin_lock_init(&m->metadata_metric_lock); m->metadata_latency_sq_sum = 0; m->metadata_latency_min = KTIME_MAX; m->metadata_latency_max = 0; @@ -224,6 +302,8 @@ void ceph_metric_destroy(struct ceph_client_metric *m) if (!m) return; + cancel_delayed_work_sync(&m->delayed_work); + percpu_counter_destroy(&m->total_inodes); percpu_counter_destroy(&m->opened_inodes); percpu_counter_destroy(&m->i_caps_mis); @@ -231,25 +311,21 @@ void ceph_metric_destroy(struct ceph_client_metric *m) percpu_counter_destroy(&m->d_lease_mis); percpu_counter_destroy(&m->d_lease_hit); - cancel_delayed_work_sync(&m->delayed_work); - - if (m->session) - ceph_put_mds_session(m->session); + ceph_put_mds_session(m->session); } -static inline void __update_latency(ktime_t *totalp, ktime_t *lsump, - ktime_t *min, ktime_t *max, - ktime_t *sq_sump, ktime_t lat) +#define METRIC_UPDATE_MIN_MAX(min, max, new) \ +{ \ + if (unlikely(new < min)) \ + min = new; \ + if (unlikely(new > max)) \ + max = new; \ +} + +static inline void __update_stdev(ktime_t total, ktime_t lsum, + ktime_t *sq_sump, ktime_t lat) { - ktime_t total, avg, sq, lsum; - - total = ++(*totalp); - lsum = (*lsump += lat); - - if (unlikely(lat < *min)) - *min = lat; - if (unlikely(lat > *max)) - *max = lat; + ktime_t avg, sq; if (unlikely(total == 1)) return; @@ -262,50 +338,73 @@ static inline void __update_latency(ktime_t *totalp, ktime_t *lsump, *sq_sump += sq; } -void ceph_update_read_latency(struct ceph_client_metric *m, +void ceph_update_read_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc) + unsigned int size, int rc) { ktime_t lat = ktime_sub(r_end, r_start); + ktime_t total; if (unlikely(rc < 0 && rc != -ENOENT && rc != -ETIMEDOUT)) return; - spin_lock(&m->read_latency_lock); - __update_latency(&m->total_reads, &m->read_latency_sum, - &m->read_latency_min, &m->read_latency_max, - &m->read_latency_sq_sum, lat); - spin_unlock(&m->read_latency_lock); + spin_lock(&m->read_metric_lock); + total = ++m->total_reads; + m->read_size_sum += size; + m->read_latency_sum += lat; + METRIC_UPDATE_MIN_MAX(m->read_size_min, + m->read_size_max, + size); + METRIC_UPDATE_MIN_MAX(m->read_latency_min, + m->read_latency_max, + lat); + __update_stdev(total, m->read_latency_sum, + &m->read_latency_sq_sum, lat); + spin_unlock(&m->read_metric_lock); } -void ceph_update_write_latency(struct ceph_client_metric *m, +void ceph_update_write_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc) + unsigned int size, int rc) { ktime_t lat = ktime_sub(r_end, r_start); + ktime_t total; if (unlikely(rc && rc != -ETIMEDOUT)) return; - spin_lock(&m->write_latency_lock); - __update_latency(&m->total_writes, &m->write_latency_sum, - &m->write_latency_min, &m->write_latency_max, - &m->write_latency_sq_sum, lat); - spin_unlock(&m->write_latency_lock); + spin_lock(&m->write_metric_lock); + total = ++m->total_writes; + m->write_size_sum += size; + m->write_latency_sum += lat; + METRIC_UPDATE_MIN_MAX(m->write_size_min, + m->write_size_max, + size); + METRIC_UPDATE_MIN_MAX(m->write_latency_min, + m->write_latency_max, + lat); + __update_stdev(total, m->write_latency_sum, + &m->write_latency_sq_sum, lat); + spin_unlock(&m->write_metric_lock); } -void ceph_update_metadata_latency(struct ceph_client_metric *m, +void ceph_update_metadata_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, int rc) { ktime_t lat = ktime_sub(r_end, r_start); + ktime_t total; if (unlikely(rc && rc != -ENOENT)) return; - spin_lock(&m->metadata_latency_lock); - __update_latency(&m->total_metadatas, &m->metadata_latency_sum, - &m->metadata_latency_min, &m->metadata_latency_max, - &m->metadata_latency_sq_sum, lat); - spin_unlock(&m->metadata_latency_lock); + spin_lock(&m->metadata_metric_lock); + total = ++m->total_metadatas; + m->metadata_latency_sum += lat; + METRIC_UPDATE_MIN_MAX(m->metadata_latency_min, + m->metadata_latency_max, + lat); + __update_stdev(total, m->metadata_latency_sum, + &m->metadata_latency_sq_sum, lat); + spin_unlock(&m->metadata_metric_lock); } diff --git a/fs/ceph/metric.h b/fs/ceph/metric.h index 710f3f1dceab..0133955a3c6a 100644 --- a/fs/ceph/metric.h +++ b/fs/ceph/metric.h @@ -14,8 +14,13 @@ enum ceph_metric_type { CLIENT_METRIC_TYPE_WRITE_LATENCY, CLIENT_METRIC_TYPE_METADATA_LATENCY, CLIENT_METRIC_TYPE_DENTRY_LEASE, + CLIENT_METRIC_TYPE_OPENED_FILES, + CLIENT_METRIC_TYPE_PINNED_ICAPS, + CLIENT_METRIC_TYPE_OPENED_INODES, + CLIENT_METRIC_TYPE_READ_IO_SIZES, + CLIENT_METRIC_TYPE_WRITE_IO_SIZES, - CLIENT_METRIC_TYPE_MAX = CLIENT_METRIC_TYPE_DENTRY_LEASE, + CLIENT_METRIC_TYPE_MAX = CLIENT_METRIC_TYPE_WRITE_IO_SIZES, }; /* @@ -27,18 +32,26 @@ enum ceph_metric_type { CLIENT_METRIC_TYPE_READ_LATENCY, \ CLIENT_METRIC_TYPE_WRITE_LATENCY, \ CLIENT_METRIC_TYPE_METADATA_LATENCY, \ + CLIENT_METRIC_TYPE_DENTRY_LEASE, \ + CLIENT_METRIC_TYPE_OPENED_FILES, \ + CLIENT_METRIC_TYPE_PINNED_ICAPS, \ + CLIENT_METRIC_TYPE_OPENED_INODES, \ + CLIENT_METRIC_TYPE_READ_IO_SIZES, \ + CLIENT_METRIC_TYPE_WRITE_IO_SIZES, \ \ CLIENT_METRIC_TYPE_MAX, \ } -/* metric caps header */ -struct ceph_metric_cap { +struct ceph_metric_header { __le32 type; /* ceph metric type */ - __u8 ver; __u8 compat; - __le32 data_len; /* length of sizeof(hit + mis + total) */ +} __packed; + +/* metric caps header */ +struct ceph_metric_cap { + struct ceph_metric_header header; __le64 hit; __le64 mis; __le64 total; @@ -46,40 +59,68 @@ struct ceph_metric_cap { /* metric read latency header */ struct ceph_metric_read_latency { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(sec + nsec) */ + struct ceph_metric_header header; __le32 sec; __le32 nsec; } __packed; /* metric write latency header */ struct ceph_metric_write_latency { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(sec + nsec) */ + struct ceph_metric_header header; __le32 sec; __le32 nsec; } __packed; /* metric metadata latency header */ struct ceph_metric_metadata_latency { - __le32 type; /* ceph metric type */ - - __u8 ver; - __u8 compat; - - __le32 data_len; /* length of sizeof(sec + nsec) */ + struct ceph_metric_header header; __le32 sec; __le32 nsec; } __packed; +/* metric dentry lease header */ +struct ceph_metric_dlease { + struct ceph_metric_header header; + __le64 hit; + __le64 mis; + __le64 total; +} __packed; + +/* metric opened files header */ +struct ceph_opened_files { + struct ceph_metric_header header; + __le64 opened_files; + __le64 total; +} __packed; + +/* metric pinned i_caps header */ +struct ceph_pinned_icaps { + struct ceph_metric_header header; + __le64 pinned_icaps; + __le64 total; +} __packed; + +/* metric opened inodes header */ +struct ceph_opened_inodes { + struct ceph_metric_header header; + __le64 opened_inodes; + __le64 total; +} __packed; + +/* metric read io size header */ +struct ceph_read_io_size { + struct ceph_metric_header header; + __le64 total_ops; + __le64 total_size; +} __packed; + +/* metric write io size header */ +struct ceph_write_io_size { + struct ceph_metric_header header; + __le64 total_ops; + __le64 total_size; +} __packed; + struct ceph_metric_head { __le32 num; /* the number of metrics that will be sent */ } __packed; @@ -94,21 +135,27 @@ struct ceph_client_metric { struct percpu_counter i_caps_hit; struct percpu_counter i_caps_mis; - spinlock_t read_latency_lock; + spinlock_t read_metric_lock; u64 total_reads; + u64 read_size_sum; + u64 read_size_min; + u64 read_size_max; ktime_t read_latency_sum; ktime_t read_latency_sq_sum; ktime_t read_latency_min; ktime_t read_latency_max; - spinlock_t write_latency_lock; + spinlock_t write_metric_lock; u64 total_writes; + u64 write_size_sum; + u64 write_size_min; + u64 write_size_max; ktime_t write_latency_sum; ktime_t write_latency_sq_sum; ktime_t write_latency_min; ktime_t write_latency_max; - spinlock_t metadata_latency_lock; + spinlock_t metadata_metric_lock; u64 total_metadatas; ktime_t metadata_latency_sum; ktime_t metadata_latency_sq_sum; @@ -148,13 +195,13 @@ static inline void ceph_update_cap_mis(struct ceph_client_metric *m) percpu_counter_inc(&m->i_caps_mis); } -extern void ceph_update_read_latency(struct ceph_client_metric *m, +extern void ceph_update_read_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc); -extern void ceph_update_write_latency(struct ceph_client_metric *m, + unsigned int size, int rc); +extern void ceph_update_write_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, - int rc); -extern void ceph_update_metadata_latency(struct ceph_client_metric *m, + unsigned int size, int rc); +extern void ceph_update_metadata_metrics(struct ceph_client_metric *m, ktime_t r_start, ktime_t r_end, int rc); #endif /* _FS_CEPH_MDS_METRIC_H */ diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 9b785f11e95a..620c691af40e 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -74,8 +74,7 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc, le64_to_cpu(h->max_files)); spin_unlock(&ci->i_ceph_lock); - /* avoid calling iput_final() in dispatch thread */ - ceph_async_iput(inode); + iput(inode); } static struct ceph_quotarealm_inode * @@ -247,8 +246,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, ci = ceph_inode(in); has_quota = __ceph_has_any_quota(ci); - /* avoid calling iput_final() while holding mdsc->snap_rwsem */ - ceph_async_iput(in); + iput(in); next = realm->parent; if (has_quota || !next) @@ -264,7 +262,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, return NULL; } -static bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) +bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) { struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old->i_sb); struct ceph_snap_realm *old_realm, *new_realm; @@ -383,8 +381,7 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op, pr_warn("Invalid quota check op (%d)\n", op); exceeded = true; /* Just break the loop */ } - /* avoid calling iput_final() while holding mdsc->snap_rwsem */ - ceph_async_iput(in); + iput(in); next = realm->parent; if (exceeded || !next) @@ -516,59 +513,3 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf) return is_updated; } -/* - * ceph_quota_check_rename - check if a rename can be executed - * @mdsc: MDS client instance - * @old: inode to be copied - * @new: destination inode (directory) - * - * This function verifies if a rename (e.g. moving a file or directory) can be - * executed. It forces an rstat update in the @new target directory (and in the - * source @old as well, if it's a directory). The actual check is done both for - * max_files and max_bytes. - * - * This function returns 0 if it's OK to do the rename, or, if quotas are - * exceeded, -EXDEV (if @old is a directory) or -EDQUOT. - */ -int ceph_quota_check_rename(struct ceph_mds_client *mdsc, - struct inode *old, struct inode *new) -{ - struct ceph_inode_info *ci_old = ceph_inode(old); - int ret = 0; - - if (ceph_quota_is_same_realm(old, new)) - return 0; - - /* - * Get the latest rstat for target directory (and for source, if a - * directory) - */ - ret = ceph_do_getattr(new, CEPH_STAT_RSTAT, false); - if (ret) - return ret; - - if (S_ISDIR(old->i_mode)) { - ret = ceph_do_getattr(old, CEPH_STAT_RSTAT, false); - if (ret) - return ret; - ret = check_quota_exceeded(new, QUOTA_CHECK_MAX_BYTES_OP, - ci_old->i_rbytes); - if (!ret) - ret = check_quota_exceeded(new, - QUOTA_CHECK_MAX_FILES_OP, - ci_old->i_rfiles + - ci_old->i_rsubdirs); - if (ret) - ret = -EXDEV; - } else { - ret = check_quota_exceeded(new, QUOTA_CHECK_MAX_BYTES_OP, - i_size_read(old)); - if (!ret) - ret = check_quota_exceeded(new, - QUOTA_CHECK_MAX_FILES_OP, 1); - if (ret) - ret = -EDQUOT; - } - - return ret; -} diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index b611f829cb61..cbc557c6a726 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -60,24 +60,26 @@ /* * increase ref count for the realm * - * caller must hold snap_rwsem for write. + * caller must hold snap_rwsem. */ void ceph_get_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { - dout("get_realm %p %d -> %d\n", realm, - atomic_read(&realm->nref), atomic_read(&realm->nref)+1); + lockdep_assert_held(&mdsc->snap_rwsem); + /* - * since we _only_ increment realm refs or empty the empty - * list with snap_rwsem held, adjusting the empty list here is - * safe. we do need to protect against concurrent empty list - * additions, however. + * The 0->1 and 1->0 transitions must take the snap_empty_lock + * atomically with the refcount change. Go ahead and bump the + * nref here, unless it's 0, in which case we take the spinlock + * and then do the increment and remove it from the list. */ - if (atomic_inc_return(&realm->nref) == 1) { - spin_lock(&mdsc->snap_empty_lock); + if (atomic_inc_not_zero(&realm->nref)) + return; + + spin_lock(&mdsc->snap_empty_lock); + if (atomic_inc_return(&realm->nref) == 1) list_del_init(&realm->empty_item); - spin_unlock(&mdsc->snap_empty_lock); - } + spin_unlock(&mdsc->snap_empty_lock); } static void __insert_snap_realm(struct rb_root *root, @@ -113,6 +115,8 @@ static struct ceph_snap_realm *ceph_create_snap_realm( { struct ceph_snap_realm *realm; + lockdep_assert_held_write(&mdsc->snap_rwsem); + realm = kzalloc(sizeof(*realm), GFP_NOFS); if (!realm) return ERR_PTR(-ENOMEM); @@ -135,7 +139,7 @@ static struct ceph_snap_realm *ceph_create_snap_realm( /* * lookup the realm rooted at @ino. * - * caller must hold snap_rwsem for write. + * caller must hold snap_rwsem. */ static struct ceph_snap_realm *__lookup_snap_realm(struct ceph_mds_client *mdsc, u64 ino) @@ -143,6 +147,8 @@ static struct ceph_snap_realm *__lookup_snap_realm(struct ceph_mds_client *mdsc, struct rb_node *n = mdsc->snap_realms.rb_node; struct ceph_snap_realm *r; + lockdep_assert_held(&mdsc->snap_rwsem); + while (n) { r = rb_entry(n, struct ceph_snap_realm, node); if (ino < r->ino) @@ -176,6 +182,8 @@ static void __put_snap_realm(struct ceph_mds_client *mdsc, static void __destroy_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { + lockdep_assert_held_write(&mdsc->snap_rwsem); + dout("__destroy_snap_realm %p %llx\n", realm, realm->ino); rb_erase(&realm->node, &mdsc->snap_realms); @@ -198,28 +206,30 @@ static void __destroy_snap_realm(struct ceph_mds_client *mdsc, static void __put_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { - dout("__put_snap_realm %llx %p %d -> %d\n", realm->ino, realm, - atomic_read(&realm->nref), atomic_read(&realm->nref)-1); + /* + * We do not require the snap_empty_lock here, as any caller that + * increments the value must hold the snap_rwsem. + */ + lockdep_assert_held_write(&mdsc->snap_rwsem); + if (atomic_dec_and_test(&realm->nref)) __destroy_snap_realm(mdsc, realm); } /* - * caller needn't hold any locks + * See comments in ceph_get_snap_realm. Caller needn't hold any locks. */ void ceph_put_snap_realm(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm) { - dout("put_snap_realm %llx %p %d -> %d\n", realm->ino, realm, - atomic_read(&realm->nref), atomic_read(&realm->nref)-1); - if (!atomic_dec_and_test(&realm->nref)) + if (!atomic_dec_and_lock(&realm->nref, &mdsc->snap_empty_lock)) return; if (down_write_trylock(&mdsc->snap_rwsem)) { + spin_unlock(&mdsc->snap_empty_lock); __destroy_snap_realm(mdsc, realm); up_write(&mdsc->snap_rwsem); } else { - spin_lock(&mdsc->snap_empty_lock); list_add(&realm->empty_item, &mdsc->snap_empty); spin_unlock(&mdsc->snap_empty_lock); } @@ -236,6 +246,8 @@ static void __cleanup_empty_realms(struct ceph_mds_client *mdsc) { struct ceph_snap_realm *realm; + lockdep_assert_held_write(&mdsc->snap_rwsem); + spin_lock(&mdsc->snap_empty_lock); while (!list_empty(&mdsc->snap_empty)) { realm = list_first_entry(&mdsc->snap_empty, @@ -269,6 +281,8 @@ static int adjust_snap_realm_parent(struct ceph_mds_client *mdsc, { struct ceph_snap_realm *parent; + lockdep_assert_held_write(&mdsc->snap_rwsem); + if (realm->parent_ino == parentino) return 0; @@ -460,7 +474,7 @@ static bool has_new_snaps(struct ceph_snap_context *o, * Caller must hold snap_rwsem for read (i.e., the realm topology won't * change). */ -void ceph_queue_cap_snap(struct ceph_inode_info *ci) +static void ceph_queue_cap_snap(struct ceph_inode_info *ci) { struct inode *inode = &ci->vfs_inode; struct ceph_cap_snap *capsnap; @@ -473,6 +487,9 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) pr_err("ENOMEM allocating ceph_cap_snap on %p\n", inode); return; } + capsnap->cap_flush.is_capsnap = true; + INIT_LIST_HEAD(&capsnap->cap_flush.i_list); + INIT_LIST_HEAD(&capsnap->cap_flush.g_list); spin_lock(&ci->i_ceph_lock); used = __ceph_caps_used(ci); @@ -605,7 +622,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb); BUG_ON(capsnap->writing); - capsnap->size = inode->i_size; + capsnap->size = i_size_read(inode); capsnap->mtime = inode->i_mtime; capsnap->atime = inode->i_atime; capsnap->ctime = inode->i_ctime; @@ -623,6 +640,16 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, return 0; } + /* Fb cap still in use, delay it */ + if (ci->i_wb_ref) { + dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu " + "used WRBUFFER, delaying\n", inode, capsnap, + capsnap->context, capsnap->context->seq, + ceph_cap_string(capsnap->dirty), capsnap->size); + capsnap->writing = 1; + return 0; + } + ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS; dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu\n", inode, capsnap, capsnap->context, @@ -653,15 +680,13 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) if (!inode) continue; spin_unlock(&realm->inodes_with_caps_lock); - /* avoid calling iput_final() while holding - * mdsc->snap_rwsem or in mds dispatch threads */ - ceph_async_iput(lastinode); + iput(lastinode); lastinode = inode; ceph_queue_cap_snap(ci); spin_lock(&realm->inodes_with_caps_lock); } spin_unlock(&realm->inodes_with_caps_lock); - ceph_async_iput(lastinode); + iput(lastinode); dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); } @@ -686,6 +711,8 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, int err = -ENOMEM; LIST_HEAD(dirty_realms); + lockdep_assert_held_write(&mdsc->snap_rwsem); + dout("update_snap_trace deletion=%d\n", deletion); more: ceph_decode_need(&p, e, sizeof(*ri), bad); @@ -781,7 +808,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, return 0; bad: - err = -EINVAL; + err = -EIO; fail: if (realm && !IS_ERR(realm)) ceph_put_snap_realm(mdsc, realm); @@ -813,20 +840,52 @@ static void flush_snaps(struct ceph_mds_client *mdsc) ihold(inode); spin_unlock(&mdsc->snap_flush_lock); ceph_flush_snaps(ci, &session); - /* avoid calling iput_final() while holding - * session->s_mutex or in mds dispatch threads */ - ceph_async_iput(inode); + iput(inode); spin_lock(&mdsc->snap_flush_lock); } spin_unlock(&mdsc->snap_flush_lock); - if (session) { - mutex_unlock(&session->s_mutex); - ceph_put_mds_session(session); - } + ceph_put_mds_session(session); dout("flush_snaps done\n"); } +/** + * ceph_change_snap_realm - change the snap_realm for an inode + * @inode: inode to move to new snap realm + * @realm: new realm to move inode into (may be NULL) + * + * Detach an inode from its old snaprealm (if any) and attach it to + * the new snaprealm (if any). The old snap realm reference held by + * the inode is put. If realm is non-NULL, then the caller's reference + * to it is taken over by the inode. + */ +void ceph_change_snap_realm(struct inode *inode, struct ceph_snap_realm *realm) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; + struct ceph_snap_realm *oldrealm = ci->i_snap_realm; + + lockdep_assert_held(&ci->i_ceph_lock); + + if (oldrealm) { + spin_lock(&oldrealm->inodes_with_caps_lock); + list_del_init(&ci->i_snap_realm_item); + if (oldrealm->ino == ci->i_vino.ino) + oldrealm->inode = NULL; + spin_unlock(&oldrealm->inodes_with_caps_lock); + ceph_put_snap_realm(mdsc, oldrealm); + } + + ci->i_snap_realm = realm; + + if (realm) { + spin_lock(&realm->inodes_with_caps_lock); + list_add(&ci->i_snap_realm_item, &realm->inodes_with_caps); + if (realm->ino == ci->i_vino.ino) + realm->inode = inode; + spin_unlock(&realm->inodes_with_caps_lock); + } +} /* * Handle a snap notification from the MDS. @@ -913,7 +972,6 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, }; struct inode *inode = ceph_find_inode(sb, vino); struct ceph_inode_info *ci; - struct ceph_snap_realm *oldrealm; if (!inode) continue; @@ -938,35 +996,16 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, } dout(" will move %p to split realm %llx %p\n", inode, realm->ino, realm); - /* - * Move the inode to the new realm - */ - oldrealm = ci->i_snap_realm; - spin_lock(&oldrealm->inodes_with_caps_lock); - list_del_init(&ci->i_snap_realm_item); - spin_unlock(&oldrealm->inodes_with_caps_lock); - - spin_lock(&realm->inodes_with_caps_lock); - list_add(&ci->i_snap_realm_item, - &realm->inodes_with_caps); - ci->i_snap_realm = realm; - if (realm->ino == ci->i_vino.ino) - realm->inode = inode; - spin_unlock(&realm->inodes_with_caps_lock); - - spin_unlock(&ci->i_ceph_lock); ceph_get_snap_realm(mdsc, realm); - ceph_put_snap_realm(mdsc, oldrealm); - - /* avoid calling iput_final() while holding - * mdsc->snap_rwsem or mds in dispatch threads */ - ceph_async_iput(inode); + ceph_change_snap_realm(inode, realm); + spin_unlock(&ci->i_ceph_lock); + iput(inode); continue; skip_inode: spin_unlock(&ci->i_ceph_lock); - ceph_async_iput(inode); + iput(inode); } /* we may have taken some of the old realm's children. */ diff --git a/fs/ceph/strings.c b/fs/ceph/strings.c index 4a79f3632260..573bb9556fb5 100644 --- a/fs/ceph/strings.c +++ b/fs/ceph/strings.c @@ -46,6 +46,7 @@ const char *ceph_session_op_name(int op) case CEPH_SESSION_FLUSHMSG_ACK: return "flushmsg_ack"; case CEPH_SESSION_FORCE_RO: return "force_ro"; case CEPH_SESSION_REJECT: return "reject"; + case CEPH_SESSION_REQUEST_FLUSH_MDLOG: return "flush_mdlog"; } return "???"; } diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 33ba6f0aa55c..226bb9c629f0 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -27,6 +27,10 @@ #include #include +#ifdef CONFIG_SYNO_CEPH_WINACL +#include +#endif /* CONFIG_SYNO_CEPH_WINACL */ + static DEFINE_SPINLOCK(ceph_fsc_lock); static LIST_HEAD(ceph_fsc_list); @@ -52,8 +56,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry)); struct ceph_mon_client *monc = &fsc->client->monc; struct ceph_statfs st; - u64 fsid; - int err; + int i, err; u64 data_pool; if (fsc->mdsc->mdsmap->m_num_data_pg_pools == 1) { @@ -99,12 +102,14 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_namelen = NAME_MAX; /* Must convert the fsid, for consistent values across arches */ + buf->f_fsid.val[0] = 0; mutex_lock(&monc->mutex); - fsid = le64_to_cpu(*(__le64 *)(&monc->monmap->fsid)) ^ - le64_to_cpu(*((__le64 *)&monc->monmap->fsid + 1)); + for (i = 0 ; i < sizeof(monc->monmap->fsid) / sizeof(__le32) ; ++i) + buf->f_fsid.val[0] ^= le32_to_cpu(((__le32 *)&monc->monmap->fsid)[i]); mutex_unlock(&monc->mutex); - buf->f_fsid = u64_to_fsid(fsid); + /* fold the fs_cluster_id into the upper bits */ + buf->f_fsid.val[1] = monc->fs_cluster_id; return 0; } @@ -158,6 +163,9 @@ enum { Opt_quotadf, Opt_copyfrom, Opt_wsync, +#ifdef CONFIG_SYNO_CEPH_WINACL + Opt_synoacl, +#endif /* CONFIG_SYNO_CEPH_WINACL */ }; enum ceph_recover_session_mode { @@ -198,6 +206,9 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = { fsparam_string ("source", Opt_source), fsparam_u32 ("wsize", Opt_wsize), fsparam_flag_no ("wsync", Opt_wsync), +#ifdef CONFIG_SYNO_CEPH_WINACL + fsparam_flag_no (SYNO_ACL_MNT_OPT, Opt_synoacl), +#endif /* CONFIG_SYNO_CEPH_WINACL */ {} }; @@ -454,6 +465,14 @@ static int ceph_parse_mount_param(struct fs_context *fc, else fsopt->flags |= CEPH_MOUNT_OPT_ASYNC_DIROPS; break; +#ifdef CONFIG_SYNO_CEPH_WINACL + case Opt_synoacl: + if (!result.negated) + fsopt->flags |= CEPH_MOUNT_OPT_WINACL; + else + fsopt->flags &= ~CEPH_MOUNT_OPT_WINACL; + break; +#endif /* CONFIG_SYNO_CEPH_WINACL */ default: BUG(); } @@ -568,6 +587,10 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",noacl"); #endif +#ifdef CONFIG_SYNO_CEPH_WINACL + if (root->d_sb->s_flags & SB_SYNOACL) + seq_puts(m, ",synoacl"); +#endif /* CONFIG_SYNO_CEPH_WINACL */ if ((fsopt->flags & CEPH_MOUNT_OPT_NOCOPYFROM) == 0) seq_puts(m, ",copyfrom"); @@ -577,8 +600,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) if (fsopt->flags & CEPH_MOUNT_OPT_CLEANRECOVER) seq_show_option(m, "recover_session", "clean"); - if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS) - seq_puts(m, ",nowsync"); + if (!(fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)) + seq_puts(m, ",wsync"); if (fsopt->wsize != CEPH_MAX_WRITE_SIZE) seq_printf(m, ",wsize=%u", fsopt->wsize); @@ -831,6 +854,13 @@ static void destroy_caches(void) ceph_fscache_unregister(); } +static void __ceph_umount_begin(struct ceph_fs_client *fsc) +{ + ceph_osdc_abort_requests(&fsc->client->osdc, -EIO); + ceph_mdsc_force_umount(fsc->mdsc); + fsc->filp_gen++; // invalidate open files +} + /* * ceph_umount_begin - initiate forced umount. Tear down the * mount, skipping steps that may hang while waiting for server(s). @@ -843,9 +873,7 @@ static void ceph_umount_begin(struct super_block *sb) if (!fsc) return; fsc->mount_state = CEPH_MOUNT_SHUTDOWN; - ceph_osdc_abort_requests(&fsc->client->osdc, -EIO); - ceph_mdsc_force_umount(fsc->mdsc); - fsc->filp_gen++; // invalidate open files + __ceph_umount_begin(fsc); } static const struct super_operations ceph_super_ops = { @@ -938,6 +966,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc, goto out; } +#ifdef CONFIG_SYNO_CEPH_WINACL + if (fsc->mount_options->flags & CEPH_MOUNT_OPT_WINACL) { + if (!syno_acl_module_get()) { + fsc->sb->s_flags &= ~SB_SYNOACL; + ceph_clear_mount_opt(fsc, WINACL); + } else { + fsc->sb->s_flags |= SB_SYNOACL; + } + } +#endif /* CONFIG_SYNO_CEPH_WINACL */ + dout("mount opening path '%s'\n", path); ceph_fs_debugfs_init(fsc); @@ -997,16 +1036,16 @@ static int ceph_compare_super(struct super_block *sb, struct fs_context *fc) struct ceph_fs_client *new = fc->s_fs_info; struct ceph_mount_options *fsopt = new->mount_options; struct ceph_options *opt = new->client->options; - struct ceph_fs_client *other = ceph_sb_to_client(sb); + struct ceph_fs_client *fsc = ceph_sb_to_client(sb); dout("ceph_compare_super %p\n", sb); - if (compare_mount_options(fsopt, opt, other)) { + if (compare_mount_options(fsopt, opt, fsc)) { dout("monitor(s)/mount options don't match\n"); return 0; } if ((opt->flags & CEPH_OPT_FSID) && - ceph_fsid_compare(&opt->fsid, &other->client->fsid)) { + ceph_fsid_compare(&opt->fsid, &fsc->client->fsid)) { dout("fsid doesn't match\n"); return 0; } @@ -1014,6 +1053,17 @@ static int ceph_compare_super(struct super_block *sb, struct fs_context *fc) dout("flags differ\n"); return 0; } + + if (fsc->blocklisted && !ceph_test_mount_opt(fsc, CLEANRECOVER)) { + dout("client is blocklisted (and CLEANRECOVER is not set)\n"); + return 0; + } + + if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) { + dout("client has been forcibly unmounted\n"); + return 0; + } + return 1; } @@ -1139,6 +1189,20 @@ static int ceph_reconfigure_fc(struct fs_context *fc) else ceph_clear_mount_opt(fsc, ASYNC_DIROPS); +#ifdef CONFIG_SYNO_CEPH_WINACL + if (fsopt->flags & CEPH_MOUNT_OPT_WINACL) { + if (!ceph_test_mount_opt(fsc, WINACL) && syno_acl_module_get()) { + fc->root->d_sb->s_flags |= SB_SYNOACL; + ceph_set_mount_opt(fsc, WINACL); + } + } else { + if (ceph_test_mount_opt(fsc, WINACL)) { + syno_acl_module_put(); + fc->root->d_sb->s_flags &= ~SB_SYNOACL; + ceph_clear_mount_opt(fsc, WINACL); + } + } +#endif /* CONFIG_SYNO_CEPH_WINACL */ sync_filesystem(fc->root->d_sb); return 0; } @@ -1210,6 +1274,11 @@ static void ceph_kill_sb(struct super_block *s) ceph_mdsc_pre_umount(fsc->mdsc); flush_fs_workqueues(fsc); +#ifdef CONFIG_SYNO_CEPH_WINACL + if (s->s_flags & SB_SYNOACL) + syno_acl_module_put(); +#endif /* CONFIG_SYNO_CEPH_WINACL */ + kill_anon_super(s); fsc->client->extra_mon_dispatch = NULL; @@ -1234,7 +1303,8 @@ int ceph_force_reconnect(struct super_block *sb) struct ceph_fs_client *fsc = ceph_sb_to_client(sb); int err = 0; - ceph_umount_begin(sb); + fsc->mount_state = CEPH_MOUNT_RECOVER; + __ceph_umount_begin(fsc); /* Make sure all page caches get invalidated. * see remove_session_caps_cb() */ diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c33f744a8e11..893639b20295 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -44,10 +44,14 @@ #define CEPH_MOUNT_OPT_NOQUOTADF (1<<13) /* no root dir quota in statfs */ #define CEPH_MOUNT_OPT_NOCOPYFROM (1<<14) /* don't use RADOS 'copy-from' op */ #define CEPH_MOUNT_OPT_ASYNC_DIROPS (1<<15) /* allow async directory ops */ +#ifdef CONFIG_SYNO_CEPH_WINACL +#define CEPH_MOUNT_OPT_WINACL (1<<16) /* synoacl */ +#endif /* CONFIG_SYNO_CEPH_WINACL */ #define CEPH_MOUNT_OPT_DEFAULT \ (CEPH_MOUNT_OPT_DCACHE | \ - CEPH_MOUNT_OPT_NOCOPYFROM) + CEPH_MOUNT_OPT_NOCOPYFROM | \ + CEPH_MOUNT_OPT_ASYNC_DIROPS) #define ceph_set_mount_opt(fsc, opt) \ (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt @@ -106,9 +110,8 @@ struct ceph_fs_client { struct ceph_mount_options *mount_options; struct ceph_client *client; - unsigned long mount_state; + int mount_state; - unsigned long last_auto_reconnect; bool blocklisted; bool have_copy_from2; @@ -129,6 +132,7 @@ struct ceph_fs_client { struct dentry *debugfs_bdi; struct dentry *debugfs_mdsc, *debugfs_mdsmap; struct dentry *debugfs_metric; + struct dentry *debugfs_status; struct dentry *debugfs_mds_sessions; #endif @@ -181,8 +185,9 @@ struct ceph_cap { struct ceph_cap_flush { u64 tid; - int caps; /* 0 means capsnap */ + int caps; bool wake; /* wake up flush waiters when finish ? */ + bool is_capsnap; /* true means capsnap */ struct list_head g_list; // global struct list_head i_list; // per inode }; @@ -333,7 +338,7 @@ struct ceph_inode_info { /* for dirs */ struct timespec64 i_rctime; - u64 i_rbytes, i_rfiles, i_rsubdirs; + u64 i_rbytes, i_rfiles, i_rsubdirs, i_rsnaps; u64 i_files, i_subdirs; /* quotas */ @@ -416,7 +421,6 @@ struct ceph_inode_info { struct ceph_snap_realm *i_snap_realm; /* snap realm (if caps) */ struct ceph_snapid_map *i_snapid_map; /* snapid -> dev_t */ }; - int i_snap_realm_counter; /* snap realm (if caps) */ struct list_head i_snap_realm_item; struct list_head i_snap_flush_item; struct timespec64 i_btime; @@ -427,10 +431,7 @@ struct ceph_inode_info { #ifdef CONFIG_CEPH_FSCACHE struct fscache_cookie *fscache; - u32 i_fscache_gen; #endif - errseq_t i_meta_err; - struct inode vfs_inode; /* at end */ }; @@ -586,9 +587,11 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, /* * Masks of ceph inode work. */ -#define CEPH_I_WORK_WRITEBACK 0 /* writeback */ -#define CEPH_I_WORK_INVALIDATE_PAGES 1 /* invalidate pages */ -#define CEPH_I_WORK_VMTRUNCATE 2 /* vmtruncate */ +#define CEPH_I_WORK_WRITEBACK 0 +#define CEPH_I_WORK_INVALIDATE_PAGES 1 +#define CEPH_I_WORK_VMTRUNCATE 2 +#define CEPH_I_WORK_CHECK_CAPS 3 +#define CEPH_I_WORK_FLUSH_SNAPS 4 /* * We set the ERROR_WRITE bit when we start seeing write errors on an inode @@ -772,7 +775,6 @@ struct ceph_file_info { spinlock_t rw_contexts_lock; struct list_head rw_contexts; - errseq_t meta_err; u32 filp_gen; atomic_t num_locks; }; @@ -926,10 +928,10 @@ extern void ceph_put_snap_realm(struct ceph_mds_client *mdsc, extern int ceph_update_snap_trace(struct ceph_mds_client *m, void *p, void *e, bool deletion, struct ceph_snap_realm **realm_ret); +void ceph_change_snap_realm(struct inode *inode, struct ceph_snap_realm *realm); extern void ceph_handle_snap(struct ceph_mds_client *mdsc, struct ceph_mds_session *session, struct ceph_msg *msg); -extern void ceph_queue_cap_snap(struct ceph_inode_info *ci); extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci, struct ceph_cap_snap *capsnap); extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc); @@ -986,10 +988,33 @@ extern int ceph_inode_holds_cap(struct inode *inode, int mask); extern bool ceph_inode_set_size(struct inode *inode, loff_t size); extern void __ceph_do_pending_vmtruncate(struct inode *inode); -extern void ceph_queue_vmtruncate(struct inode *inode); -extern void ceph_queue_invalidate(struct inode *inode); -extern void ceph_queue_writeback(struct inode *inode); -extern void ceph_async_iput(struct inode *inode); + +void ceph_queue_inode_work(struct inode *inode, int work_bit); + +static inline void ceph_queue_vmtruncate(struct inode *inode) +{ + ceph_queue_inode_work(inode, CEPH_I_WORK_VMTRUNCATE); +} + +static inline void ceph_queue_invalidate(struct inode *inode) +{ + ceph_queue_inode_work(inode, CEPH_I_WORK_INVALIDATE_PAGES); +} + +static inline void ceph_queue_writeback(struct inode *inode) +{ + ceph_queue_inode_work(inode, CEPH_I_WORK_WRITEBACK); +} + +static inline void ceph_queue_check_caps(struct inode *inode) +{ + ceph_queue_inode_work(inode, CEPH_I_WORK_CHECK_CAPS); +} + +static inline void ceph_queue_flush_snaps(struct inode *inode) +{ + ceph_queue_inode_work(inode, CEPH_I_WORK_FLUSH_SNAPS); +} extern int __ceph_do_getattr(struct inode *inode, struct page *locked_page, int mask, bool force); @@ -998,10 +1023,28 @@ static inline int ceph_do_getattr(struct inode *inode, int mask, bool force) return __ceph_do_getattr(inode, NULL, mask, force); } extern int ceph_permission(struct inode *inode, int mask); +#ifdef CONFIG_SYNO_CEPH_WINACL +extern int ceph_syno_permission(struct dentry *dentry, int mask); +#endif /* CONFIG_SYNO_CEPH_WINACL */ extern int __ceph_setattr(struct inode *inode, struct iattr *attr); extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); extern int ceph_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags); +#ifdef CONFIG_SYNO_CEPH_STAT +extern int ceph_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags); +#endif /* CONFIG_SYNO_CEPH_STAT */ +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME +extern int ceph_syno_get_crtime(struct inode *inode, struct timespec64 *time); +extern int ceph_syno_set_crtime(struct inode *inode, struct timespec64 *time); +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT +extern int ceph_syno_get_archive_bit(struct dentry *dentry, unsigned int *archive_bit, int may_not_block); +extern int ceph_syno_set_archive_bit(struct dentry *dentry, unsigned int archive_bit); +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +extern inline int ceph_replace_caseless_dentry_name(struct dentry *dentry, + const char *name, int len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ /* xattr.c */ int __ceph_setxattr(struct inode *, const char *, const void *, size_t, int); @@ -1109,6 +1152,7 @@ extern void ceph_add_cap(struct inode *inode, unsigned cap, unsigned seq, u64 realmino, int flags, struct ceph_cap **new_cap); extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release); +extern void ceph_remove_cap(struct ceph_cap *cap, bool queue_release); extern void __ceph_remove_caps(struct ceph_inode_info *ci); extern void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap); @@ -1129,16 +1173,23 @@ extern void ceph_take_cap_refs(struct ceph_inode_info *ci, int caps, bool snap_rwsem_locked); extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps); extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had); +extern void ceph_put_cap_refs_async(struct ceph_inode_info *ci, int had); extern void ceph_put_cap_refs_no_check_caps(struct ceph_inode_info *ci, int had); extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, struct ceph_snap_context *snapc); +extern void __ceph_remove_capsnap(struct inode *inode, + struct ceph_cap_snap *capsnap, + bool *wake_ci, bool *wake_mdsc); +extern void ceph_remove_capsnap(struct inode *inode, + struct ceph_cap_snap *capsnap, + bool *wake_ci, bool *wake_mdsc); extern void ceph_flush_snaps(struct ceph_inode_info *ci, struct ceph_mds_session **psession); extern bool __ceph_should_report_size(struct ceph_inode_info *ci); extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_mds_session *session); -extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc); +extern unsigned long ceph_check_delayed_caps(struct ceph_mds_client *mdsc); extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc); extern int ceph_drop_caps_for_unlink(struct inode *inode); extern int ceph_encode_inode_release(void **p, struct inode *inode, @@ -1148,7 +1199,7 @@ extern int ceph_encode_dentry_release(void **p, struct dentry *dn, int mds, int drop, int unless); extern int ceph_get_caps(struct file *filp, int need, int want, - loff_t endoff, int *got, struct page **pinned_page); + loff_t endoff, int *got); extern int ceph_try_get_caps(struct inode *inode, int need, int want, bool nonblock, int *got); @@ -1185,8 +1236,8 @@ extern const struct dentry_operations ceph_dentry_ops; extern loff_t ceph_make_fpos(unsigned high, unsigned off, bool hash_order); extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry); -extern int ceph_handle_snapdir(struct ceph_mds_request *req, - struct dentry *dentry, int err); +extern struct dentry *ceph_handle_snapdir(struct ceph_mds_request *req, + struct dentry *dentry); extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, struct dentry *dentry, int err); @@ -1196,6 +1247,12 @@ extern void ceph_invalidate_dentry_lease(struct dentry *dentry); extern int ceph_trim_dentries(struct ceph_mds_client *mdsc); extern unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn); extern void ceph_readdir_cache_release(struct ceph_readdir_cache_control *ctl); +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT +extern int ceph_pre_init_archive_bit(struct ceph_acl_sec_ctx *as_ctx); +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +extern int ceph_upper_full_name_hash(const struct dentry *parent, const char *name, int len, u32 *hash); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ /* ioctl.c */ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg); @@ -1246,14 +1303,13 @@ extern void ceph_handle_quota(struct ceph_mds_client *mdsc, struct ceph_mds_session *session, struct ceph_msg *msg); extern bool ceph_quota_is_max_files_exceeded(struct inode *inode); +extern bool ceph_quota_is_same_realm(struct inode *old, struct inode *new); extern bool ceph_quota_is_max_bytes_exceeded(struct inode *inode, loff_t newlen); extern bool ceph_quota_is_max_bytes_approaching(struct inode *inode, loff_t newlen); extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf); -extern int ceph_quota_check_rename(struct ceph_mds_client *mdsc, - struct inode *old, struct inode *new); extern void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc); #endif /* _FS_CEPH_SUPER_H */ diff --git a/fs/ceph/syno_acl.c b/fs/ceph/syno_acl.c new file mode 100644 index 000000000000..63add21767b9 --- /dev/null +++ b/fs/ceph/syno_acl.c @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2022 Synology Inc. + */ +#include +#include +#include +#include + +#include "super.h" +#include "syno_acl.h" + +static inline void ceph_set_cached_syno_acl(struct inode *inode, + struct syno_acl *acl) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + + spin_lock(&ci->i_ceph_lock); + if (__ceph_caps_issued_mask_metric(ci, CEPH_CAP_XATTR_SHARED, 0)) + set_cached_syno_acl(inode, acl); + else + forget_cached_syno_acl(inode); + spin_unlock(&ci->i_ceph_lock); +} + +/* + * Inode operation syno_acl_get(). + */ +struct syno_acl *ceph_get_syno_acl(struct inode *inode) +{ + int size; + char *value = NULL; + struct syno_acl *acl; + + acl = get_cached_syno_acl(inode); + if (!is_uncached_syno_acl(acl)) + return acl; + + size = __ceph_getxattr(inode, SYNO_ACL_XATTR_ACCESS, "", 0); + if (size > 0) { + value = kzalloc(size, GFP_NOFS); + if (!value) + return ERR_PTR(-ENOMEM); + size = __ceph_getxattr(inode, SYNO_ACL_XATTR_ACCESS, value, size); + } + + if (size > 0) + acl = syno_acl_from_disk(value, size); + else if (size == -ENOENT || size == -ENODATA || size == 0) + /* FIXME, who returns -ENOENT? I think nobody */ + acl = NULL; + else + acl = ERR_PTR(size); + + kfree(value); + + if (!IS_ERR(acl)) + set_cached_syno_acl(inode, acl); + + return acl; +} + +/* + * Needs to be called with fs_mutex held + */ +static int __ceph_set_syno_acl(struct inode *inode, struct syno_acl *acl) +{ + int ret; + size_t size = 0; + char *value = NULL; + + if (acl) { + ret = syno_acl_valid(acl); + if (ret < 0) + return ret; + + value = syno_acl_to_disk(acl, &size); + if (IS_ERR(value)) + return PTR_ERR(value); + } + + ret = __ceph_setxattr(inode, SYNO_ACL_XATTR_ACCESS, value, size, 0); + + kfree(value); + if (!ret) + set_cached_syno_acl(inode, acl); + + return ret; +} + +/* + * Inode operation syno_acl_set(). + */ +int ceph_set_syno_acl(struct inode *inode, struct syno_acl *acl) +{ + int ret; + + if (!inode || !acl) + return -EINVAL; + + ret = __ceph_set_syno_acl(inode, acl); + + return ret; +} + +static int +ceph_xattr_syno_acl_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *value, size_t size) +{ + int ret = 0; + struct syno_acl *acl; + + acl = ceph_get_syno_acl(dentry->d_inode); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + + ret = syno_acl_to_xattr(acl, value, size); + syno_acl_release(acl); + + return ret; +} + +static int +ceph_xattr_syno_acl_set(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, int flags) +{ + int ret; + struct syno_acl *acl = NULL; + + if (value) { + acl = syno_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + ret = syno_acl_valid(acl); + if (ret) + goto out; + } + } + + ret = __ceph_set_syno_acl(dentry->d_inode, acl); +out: + syno_acl_release(acl); + return ret; +} + +const struct xattr_handler ceph_xattr_synoacl_access_handler = { + .name = SYNO_ACL_XATTR_ACCESS, + .get = ceph_xattr_syno_acl_get, + .set = ceph_xattr_syno_acl_set, +}; diff --git a/fs/ceph/syno_acl.h b/fs/ceph/syno_acl.h new file mode 100644 index 000000000000..3945cb3da9df --- /dev/null +++ b/fs/ceph/syno_acl.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2022 Synology Inc. + */ + +#ifndef _CEPH_SYNO_ACL_H +#define _CEPH_SYNO_ACL_H + +#include +#include + +int ceph_set_syno_acl(struct inode *inode, struct syno_acl *acl); +struct syno_acl *ceph_get_syno_acl(struct inode *inode); +struct syno_acl *ceph_syno_acl_from_disk(const void *value, size_t size); + +#endif /* _CEPH_SYNO_ACL_H */ diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 197cb1234341..6799c63c91f6 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -23,6 +23,12 @@ static bool ceph_is_valid_xattr(const char *name) return !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || +#ifdef CONFIG_SYNO_CEPH_ARCHIVE_BIT + !strncmp(name, XATTR_SYNO_PREFIX, XATTR_SYNO_PREFIX_LEN) || +#endif /* CONFIG_SYNO_CEPH_ARCHIVE_BIT */ +#ifdef CONFIG_SYNO_CEPH_WINACL + !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) || +#endif /* CONFIG_SYNO_CEPH_WINACL */ !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); } @@ -42,6 +48,7 @@ struct ceph_vxattr { #define VXATTR_FLAG_READONLY (1<<0) #define VXATTR_FLAG_HIDDEN (1<<1) #define VXATTR_FLAG_RSTAT (1<<2) +#define VXATTR_FLAG_DIRSTAT (1<<3) /* layouts */ @@ -172,7 +179,11 @@ static ssize_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci, if (ret <= size) memcpy(val, pool_name, ret); } else { +#ifdef CONFIG_SYNO_CEPH_IDENTIFY_POOL_XATTR_IS_ID + ret = ceph_fmt_xattr(val, size, "id-%lld", pool); +#else ret = ceph_fmt_xattr(val, size, "%lld", pool); +#endif } up_read(&osdc->lock); return ret; @@ -232,6 +243,12 @@ static ssize_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val, return ceph_fmt_xattr(val, size, "%lld", ci->i_rsubdirs); } +static ssize_t ceph_vxattrcb_dir_rsnaps(struct ceph_inode_info *ci, char *val, + size_t size) +{ + return ceph_fmt_xattr(val, size, "%lld", ci->i_rsnaps); +} + static ssize_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val, size_t size) { @@ -303,6 +320,48 @@ static ssize_t ceph_vxattrcb_snap_btime(struct ceph_inode_info *ci, char *val, ci->i_snap_btime.tv_nsec); } +static ssize_t ceph_vxattrcb_cluster_fsid(struct ceph_inode_info *ci, + char *val, size_t size) +{ + struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); + + return ceph_fmt_xattr(val, size, "%pU", &fsc->client->fsid); +} + +static ssize_t ceph_vxattrcb_client_id(struct ceph_inode_info *ci, + char *val, size_t size) +{ + struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); + + return ceph_fmt_xattr(val, size, "client%lld", + ceph_client_gid(fsc->client)); +} + +static ssize_t ceph_vxattrcb_caps(struct ceph_inode_info *ci, char *val, + size_t size) +{ + int issued; + + spin_lock(&ci->i_ceph_lock); + issued = __ceph_caps_issued(ci, NULL); + spin_unlock(&ci->i_ceph_lock); + + return ceph_fmt_xattr(val, size, "%s/0x%x", + ceph_cap_string(issued), issued); +} + +static ssize_t ceph_vxattrcb_auth_mds(struct ceph_inode_info *ci, + char *val, size_t size) +{ + int ret; + + spin_lock(&ci->i_ceph_lock); + ret = ceph_fmt_xattr(val, size, "%d", + ci->i_auth_cap ? ci->i_auth_cap->session->s_mds : -1); + spin_unlock(&ci->i_ceph_lock); + return ret; +} + #define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name #define CEPH_XATTR_NAME2(_type, _name, _name2) \ XATTR_CEPH_PREFIX #_type "." #_name "." #_name2 @@ -317,6 +376,14 @@ static ssize_t ceph_vxattrcb_snap_btime(struct ceph_inode_info *ci, char *val, } #define XATTR_RSTAT_FIELD(_type, _name) \ XATTR_NAME_CEPH(_type, _name, VXATTR_FLAG_RSTAT) +#define XATTR_RSTAT_FIELD_UPDATABLE(_type, _name) \ + { \ + .name = CEPH_XATTR_NAME(_type, _name), \ + .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \ + .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ + .exists_cb = NULL, \ + .flags = VXATTR_FLAG_RSTAT, \ + } #define XATTR_LAYOUT_FIELD(_type, _name, _field) \ { \ .name = CEPH_XATTR_NAME2(_type, _name, _field), \ @@ -347,14 +414,15 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = { XATTR_LAYOUT_FIELD(dir, layout, object_size), XATTR_LAYOUT_FIELD(dir, layout, pool), XATTR_LAYOUT_FIELD(dir, layout, pool_namespace), - XATTR_NAME_CEPH(dir, entries, 0), - XATTR_NAME_CEPH(dir, files, 0), - XATTR_NAME_CEPH(dir, subdirs, 0), + XATTR_NAME_CEPH(dir, entries, VXATTR_FLAG_DIRSTAT), + XATTR_NAME_CEPH(dir, files, VXATTR_FLAG_DIRSTAT), + XATTR_NAME_CEPH(dir, subdirs, VXATTR_FLAG_DIRSTAT), XATTR_RSTAT_FIELD(dir, rentries), XATTR_RSTAT_FIELD(dir, rfiles), XATTR_RSTAT_FIELD(dir, rsubdirs), + XATTR_RSTAT_FIELD(dir, rsnaps), XATTR_RSTAT_FIELD(dir, rbytes), - XATTR_RSTAT_FIELD(dir, rctime), + XATTR_RSTAT_FIELD_UPDATABLE(dir, rctime), { .name = "ceph.dir.pin", .name_size = sizeof("ceph.dir.pin"), @@ -378,6 +446,13 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = { .exists_cb = ceph_vxattrcb_snap_btime_exists, .flags = VXATTR_FLAG_READONLY, }, + { + .name = "ceph.caps", + .name_size = sizeof("ceph.caps"), + .getxattr_cb = ceph_vxattrcb_caps, + .exists_cb = NULL, + .flags = VXATTR_FLAG_HIDDEN, + }, { .name = NULL, 0 } /* Required table terminator */ }; @@ -403,6 +478,38 @@ static struct ceph_vxattr ceph_file_vxattrs[] = { .exists_cb = ceph_vxattrcb_snap_btime_exists, .flags = VXATTR_FLAG_READONLY, }, + { + .name = "ceph.caps", + .name_size = sizeof("ceph.caps"), + .getxattr_cb = ceph_vxattrcb_caps, + .exists_cb = NULL, + .flags = VXATTR_FLAG_HIDDEN, + }, + { .name = NULL, 0 } /* Required table terminator */ +}; + +static struct ceph_vxattr ceph_common_vxattrs[] = { + { + .name = "ceph.cluster_fsid", + .name_size = sizeof("ceph.cluster_fsid"), + .getxattr_cb = ceph_vxattrcb_cluster_fsid, + .exists_cb = NULL, + .flags = VXATTR_FLAG_READONLY, + }, + { + .name = "ceph.client_id", + .name_size = sizeof("ceph.client_id"), + .getxattr_cb = ceph_vxattrcb_client_id, + .exists_cb = NULL, + .flags = VXATTR_FLAG_READONLY, + }, + { + .name = "ceph.auth_mds", + .name_size = sizeof("ceph.auth_mds"), + .getxattr_cb = ceph_vxattrcb_auth_mds, + .exists_cb = NULL, + .flags = VXATTR_FLAG_READONLY, + }, { .name = NULL, 0 } /* Required table terminator */ }; @@ -428,6 +535,13 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, } } + vxattr = ceph_common_vxattrs; + while (vxattr->name) { + if (!strcmp(vxattr->name, name)) + return vxattr; + vxattr++; + } + return NULL; } @@ -837,6 +951,8 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, int mask = 0; if (vxattr->flags & VXATTR_FLAG_RSTAT) mask |= CEPH_STAT_RSTAT; + if (vxattr->flags & VXATTR_FLAG_DIRSTAT) + mask |= CEPH_CAP_FILE_SHARED; err = ceph_do_getattr(inode, mask, true); if (err) return err; @@ -950,6 +1066,7 @@ static int ceph_sync_setxattr(struct inode *inode, const char *name, struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_mds_request *req; struct ceph_mds_client *mdsc = fsc->mdsc; + struct ceph_osd_client *osdc = &fsc->client->osdc; struct ceph_pagelist *pagelist = NULL; int op = CEPH_MDS_OP_SETXATTR; int err; @@ -988,6 +1105,8 @@ static int ceph_sync_setxattr(struct inode *inode, const char *name, if (op == CEPH_MDS_OP_SETXATTR) { req->r_args.setxattr.flags = cpu_to_le32(flags); + req->r_args.setxattr.osdmap_epoch = + cpu_to_le32(osdc->osdmap->epoch); req->r_pagelist = pagelist; pagelist = NULL; } @@ -1284,6 +1403,9 @@ void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx) ceph_pagelist_release(as_ctx->pagelist); } +#ifdef CONFIG_SYNO_CEPH_WINACL +extern struct xattr_handler ceph_xattr_synoacl_access_handler; +#endif /* CONFIG_SYNO_CEPH_WINACL */ /* * List of handlers for synthetic system.* attributes. Other * attributes are handled directly. @@ -1293,6 +1415,9 @@ const struct xattr_handler *ceph_xattr_handlers[] = { &posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, #endif +#ifdef CONFIG_SYNO_CEPH_WINACL + &ceph_xattr_synoacl_access_handler, +#endif /* CONFIG_SYNO_CEPH_WINACL */ &ceph_other_xattr_handler, NULL, }; diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index cd17d0e50f2a..697ce0d2e97c 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -23,3 +23,5 @@ cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o + +cifs-$(CONFIG_SYNO_CIFS_SMB_OPS) += synoops.o diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f0ed29a9a6f1..9d8bb638a47b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/cifsfs.c * @@ -68,6 +71,9 @@ int cifsFYI = 0; bool traceSMB; bool enable_oplocks = true; +#ifdef MY_ABC_HERE +unsigned int SynoPosixSemanticsEnabled = 1; +#endif /* MY_ABC_HERE */ bool linuxExtEnabled = true; bool lookupCacheEnabled = true; bool disable_legacy_dialects; /* false by default */ @@ -103,6 +109,13 @@ MODULE_PARM_DESC(slow_rsp_threshold, "Amount of time (in seconds) to wait " "Default: 1 (if set to 0 disables msg)."); #endif /* STATS2 */ +#ifdef MY_ABC_HERE +unsigned short need_nego_timeout = 30; +module_param(need_nego_timeout, ushort, 0644); +MODULE_PARM_DESC(need_nego_timeout, "The timeout (second) when tcpStatus is" + "CifsNeedNegotiate. After timeout will reconnect server" + "Default: 30. 0 means never reconnect until socket fail."); +#endif /* MY_ABC_HERE */ module_param(enable_oplocks, bool, 0644); MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1"); @@ -484,6 +497,16 @@ cifs_show_options(struct seq_file *s, struct dentry *root) srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; seq_show_option(s, "vers", tcon->ses->server->vals->version_string); +#ifdef MY_ABC_HERE + if (&synocifs_values == tcon->ses->server->values) { + seq_puts(s, "(syno)"); + } + if (tcon->ses->server->noblocksnd) { + seq_puts(s, ",noblocksend"); + } else { + seq_puts(s, ",blocksend"); + } +#endif /* MY_ABC_HERE */ cifs_show_security(s, tcon->ses); cifs_show_cache_flavor(s, cifs_sb); @@ -654,7 +677,13 @@ static void cifs_umount_begin(struct super_block *sb) all waiting network requests, nothing to do */ spin_unlock(&cifs_tcp_ses_lock); return; +#ifdef MY_ABC_HERE + // tcon->tc_count will always 1. Because it will re-use the exist tcon + // So we need to check the same value which is checked before kill_sb. + } else if (atomic_read(&sb->s_active) == 1) +#else /* MY_ABC_HERE */ } else if (tcon->tc_count == 1) +#endif /* MY_ABC_HERE */ tcon->tidStatus = CifsExiting; spin_unlock(&cifs_tcp_ses_lock); @@ -1057,6 +1086,10 @@ const struct inode_operations cifs_dir_inode_ops = { .symlink = cifs_symlink, .mknod = cifs_mknod, .listxattr = cifs_listxattr, +#ifdef MY_ABC_HERE + .syno_getattr = cifs_syno_getattr, + .syno_get_crtime = cifs_syno_get_crtime, +#endif /* MY_ABC_HERE */ }; const struct inode_operations cifs_file_inode_ops = { @@ -1065,12 +1098,20 @@ const struct inode_operations cifs_file_inode_ops = { .permission = cifs_permission, .listxattr = cifs_listxattr, .fiemap = cifs_fiemap, +#ifdef MY_ABC_HERE + .syno_getattr = cifs_syno_getattr, + .syno_get_crtime = cifs_syno_get_crtime, +#endif /* MY_ABC_HERE */ }; const struct inode_operations cifs_symlink_inode_ops = { .get_link = cifs_get_link, .permission = cifs_permission, .listxattr = cifs_listxattr, +#ifdef MY_ABC_HERE + .syno_getattr = cifs_syno_getattr, + .syno_get_crtime = cifs_syno_get_crtime, +#endif /* MY_ABC_HERE */ }; static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 905d03863721..a4b52dc29fcb 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/cifsfs.h * @@ -86,6 +89,10 @@ extern int cifs_getattr(const struct path *, struct kstat *, u32, unsigned int); extern int cifs_setattr(struct dentry *, struct iattr *); extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); +#ifdef MY_ABC_HERE +extern int cifs_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags); +extern int cifs_syno_get_crtime(struct inode *inode, struct timespec64 *crtime); +#endif /* MY_ABC_HERE */ extern const struct inode_operations cifs_file_inode_ops; extern const struct inode_operations cifs_symlink_inode_ops; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6599069be690..0c836838c203 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/cifsglob.h * @@ -673,6 +676,11 @@ struct TCP_Server_Info { char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; struct smb_version_operations *ops; struct smb_version_values *vals; +#ifdef MY_ABC_HERE + struct smb_version_operations operations; + /* values: for synoops; vals is changeable when vers=syno. it is for fit server max protocol */ + struct smb_version_values *values; +#endif /* MY_ABC_HERE */ enum statusEnum tcpStatus; /* what we think the status is */ char *hostname; /* hostname portion of UNC string */ struct socket *ssocket; @@ -1950,6 +1958,9 @@ extern bool lookupCacheEnabled; extern unsigned int global_secflags; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ +#ifdef MY_ABC_HERE +GLOBAL_EXTERN unsigned int SynoPosixSemanticsEnabled;/*enable POSIX SEMANTICS*/ +#endif /* MY_ABC_HERE */ extern bool enable_gcm_256; /* allow optional negotiate of strongest signing (aes-gcm-256) */ extern bool require_gcm_256; /* require use of strongest signing (aes-gcm-256) */ extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ @@ -1958,6 +1969,9 @@ extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ extern unsigned int cifs_min_small; /* min size of small buf pool */ extern unsigned int cifs_max_pending; /* MAX requests at once to server*/ extern bool disable_legacy_dialects; /* forbid vers=1.0 and vers=2.0 mounts */ +#ifdef MY_ABC_HERE +GLOBAL_EXTERN unsigned short need_nego_timeout; +#endif /* MY_ABC_HERE */ GLOBAL_EXTERN struct rb_root uidtree; GLOBAL_EXTERN struct rb_root gidtree; @@ -1984,6 +1998,11 @@ extern mempool_t *cifs_mid_poolp; #define SMB1_VERSION_STRING "1.0" extern struct smb_version_operations smb1_operations; extern struct smb_version_values smb1_values; +#ifdef MY_ABC_HERE +#define SYNO_VERSION_STRING "syno" +extern struct smb_version_operations synocifs_operations; +extern struct smb_version_values synocifs_values; +#endif /* MY_ABC_HERE */ #define SMB20_VERSION_STRING "2.0" extern struct smb_version_operations smb20_operations; extern struct smb_version_values smb20_values; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 24c6f36177ba..b7f21b92e370 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/cifsproto.h * @@ -635,6 +638,15 @@ int match_target_ip(struct TCP_Server_Info *server, const char *share, size_t share_len, bool *result); #endif +#ifdef MY_ABC_HERE +extern void set_operation(struct smb_version_operations *dst, + struct smb_version_operations *src); +extern int SendReceiveSyno(const unsigned int xid, struct cifs_ses *ses, + struct smb_hdr *in_buf, struct kvec *out_buf, + const int flags); +extern void init_syno_operations(struct TCP_Server_Info *server, + struct smb_vol *volume_info); +#endif /* MY_ABC_HERE */ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options) { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0496934feecb..010aaa9dbed9 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/cifssmb.c * @@ -132,6 +135,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) struct cifs_ses *ses; struct TCP_Server_Info *server; struct nls_table *nls_codepage; +#ifdef MY_ABC_HERE + u16 origin_dialect; /* dialect index that server chose */ +#endif /* MY_ABC_HERE */ int retries; /* @@ -195,16 +201,34 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) retries = server->nr_targets; } +#ifdef MY_ABC_HERE + if (SMB20_PROT_ID <= server->dialect) { + cifs_dbg(FYI, "(%s) origin_dialect=0x%x, server->dialect=0x%x\n", __func__, origin_dialect, server->dialect); + return -EAGAIN; + } + origin_dialect = server->dialect; +#endif /* MY_ABC_HERE */ if (!ses->need_reconnect && !tcon->need_reconnect) return 0; +#ifdef MY_ABC_HERE + nls_codepage = load_nls("utf8"); +#else /* MY_ABC_HERE */ nls_codepage = load_nls_default(); +#endif /* MY_ABC_HERE */ /* * need to prevent multiple threads trying to simultaneously * reconnect the same SMB session */ +#ifdef MY_ABC_HERE + if (!mutex_trylock(&ses->session_mutex)) { + rc = -EINPROGRESS; + goto out; + } +#else /* MY_ABC_HERE */ mutex_lock(&ses->session_mutex); +#endif /* MY_ABC_HERE */ /* * Recheck after acquire mutex. If another thread is negotiating @@ -249,6 +273,13 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) * * FIXME: what about file locks? don't we need to reclaim them ASAP? */ +#ifdef MY_ABC_HERE + if (server->dialect != origin_dialect || + SMB20_PROT_ID <= server->dialect) { + cifs_dbg(FYI, "(%s) SMB1 reconnect dialect not match! origin=0x%x, current=0x%x\n", __func__, origin_dialect, server->dialect); + rc = -EAGAIN; + } +#endif /* MY_ABC_HERE */ out: /* @@ -766,6 +797,12 @@ CIFSSMBEcho(struct TCP_Server_Info *server) cifs_dbg(FYI, "In echo request\n"); +#ifdef MY_ABC_HERE + if (CifsGood != server->tcpStatus) { + cifs_dbg(FYI, "tcpStatus not Good (%d); Don't send echo\n", server->tcpStatus); + return rc; + } +#endif /* MY_ABC_HERE */ rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); if (rc) return rc; @@ -1383,7 +1420,11 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case * sensitive checks for other servers such as Samba. */ +#ifdef MY_ABC_HERE + if (tcon->ses->capabilities & CAP_UNIX && SynoPosixSemanticsEnabled) +#else /* MY_ABC_HERE */ if (tcon->ses->capabilities & CAP_UNIX) +#endif /* MY_ABC_HERE */ req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); if (create_options & CREATE_OPTION_READONLY) @@ -4855,8 +4896,14 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, *target_nodes = NULL; cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name); +#ifdef MY_ABC_HERE + // CID 44892: check ses->server before dereference from get_next_mid + if (ses == NULL || NULL == ses->server || ses->tcon_ipc == NULL) + return -ENODEV; +#else /* MY_ABC_HERE */ if (ses == NULL || ses->tcon_ipc == NULL) return -ENODEV; +#endif /* MY_ABC_HERE */ getDFSRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8ffe8063e42c..d2818dd3d454 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/connect.c * @@ -459,7 +462,19 @@ cifs_reconnect(struct TCP_Server_Info *server) list_for_each(tmp2, &ses->tcon_list) { tcon = list_entry(tmp2, struct cifs_tcon, tcon_list); tcon->need_reconnect = true; +#ifdef MY_ABC_HERE + // initialize SMB2 encryption flags + // it prevent the fail when server disable encryption + tcon->share_flags = 0; +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE + if (ses->tcon_ipc) { + // initialize SMB2 encryption flags + // it prevent the fail when server disable encryption + ses->tcon_ipc->share_flags = 0; + } +#endif /* MY_ABC_HERE */ if (ses->tcon_ipc) ses->tcon_ipc->need_reconnect = true; } @@ -673,6 +688,23 @@ server_unresponsive(struct TCP_Server_Info *server) return false; } +#ifdef MY_ABC_HERE +static bool +server_nego_unresponsive(struct TCP_Server_Info *server, unsigned long when_start_recv_nego) +{ + if (server->tcpStatus == CifsNeedNegotiate && + need_nego_timeout != 0 && + time_after(jiffies, when_start_recv_nego + need_nego_timeout * HZ)) { + cifs_dbg(FYI, "Server %s has not responded at need nego stage in %d seconds. " + "Reconnecting...\n", server->hostname, need_nego_timeout); + cifs_reconnect(server); + wake_up(&server->response_q); + return true; + } + + return false; +} +#endif /* MY_ABC_HERE */ static inline bool zero_credits(struct TCP_Server_Info *server) @@ -694,10 +726,16 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) { int length = 0; int total_read; +#ifdef MY_ABC_HERE + unsigned long when_start_recv_nego; +#endif /* MY_ABC_HERE */ smb_msg->msg_control = NULL; smb_msg->msg_controllen = 0; +#ifdef MY_ABC_HERE + when_start_recv_nego = jiffies; +#endif /* MY_ABC_HERE */ for (total_read = 0; msg_data_left(smb_msg); total_read += length) { try_to_freeze(); @@ -707,6 +745,11 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) return -ECONNABORTED; } +#ifdef MY_ABC_HERE + if (server_nego_unresponsive(server, when_start_recv_nego)) { + return -ECONNABORTED; + } +#endif /* MY_ABC_HERE */ if (server_unresponsive(server)) return -ECONNABORTED; if (cifs_rdma_enabled(server) && server->smbd_conn) @@ -1594,6 +1637,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, vol->linux_ext = 1; break; case Opt_nocase: +#ifdef MY_ABC_HERE + SynoPosixSemanticsEnabled = 0; +#endif /* MY_ABC_HERE */ vol->nocase = 1; break; case Opt_brl: @@ -1702,7 +1748,11 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); goto cifs_parse_mount_err; #endif +#if defined(MY_ABC_HERE) && !defined(CONFIG_CIFS_FSCACHE) + // CID 45467: dead code after goto. +#else /* MY_ABC_HERE */ vol->fsc = true; +#endif /* MY_ABC_HERE */ break; case Opt_mfsymlinks: vol->mfsymlinks = true; @@ -1966,6 +2016,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, * starts with a delimiter */ tmp_end = strchr(data, '='); +#ifdef MY_ABC_HERE + // CID 45506: dereference null return value + if (NULL == tmp_end) { + goto cifs_parse_mount_err; + } +#endif /* MY_ABC_HERE */ tmp_end++; if (!(tmp_end < end && tmp_end[1] == delim)) { /* No it is not. Set the password to NULL */ @@ -1977,6 +2033,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, case Opt_pass: /* Obtain the value string */ value = strchr(data, '='); +#ifdef MY_ABC_HERE + // CID 45506: dereference null return value + if (NULL == value) { + goto cifs_parse_mount_err; + } +#endif /* MY_ABC_HERE */ value++; /* Set tmp_end to end of the string */ @@ -2415,8 +2477,15 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol) SMBDEFAULT_VERSION_STRING) == 0) { if (server->vals->protocol_id < SMB21_PROT_ID) return 0; +#ifdef MY_ABC_HERE + } else if ((server->vals != vol->vals && server->values != vol->vals) || + (server->ops != vol->ops)) { + return 0; + } +#else /* MY_ABC_HERE */ } else if ((server->vals != vol->vals) || (server->ops != vol->ops)) return 0; +#endif /* MY_ABC_HERE */ if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) return 0; @@ -2535,6 +2604,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->ops = volume_info->ops; tcp_ses->vals = volume_info->vals; +#ifdef MY_ABC_HERE + init_syno_operations(tcp_ses, volume_info); +#endif /* MY_ABC_HERE */ cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); tcp_ses->hostname = extract_hostname(volume_info->UNC); if (IS_ERR(tcp_ses->hostname)) { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index da057570bb93..1e158cad0524 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/file.c * @@ -4032,6 +4035,13 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) } open_file = file->private_data; tcon = tlink_tcon(open_file->tlink); +#ifdef MY_ABC_HERE + // CID 45269: Derefernce before null check + if (!tcon->ses) { + free_xid(xid); + return -ENOSYS; + } +#endif /* MY_ABC_HERE */ server = cifs_pick_channel(tcon->ses); if (!server->ops->sync_read) { diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index ad6c2fed4055..6e6e3be8340f 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020, Microsoft Corporation. @@ -9,6 +12,9 @@ #include "cifsglob.h" #include "cifs_debug.h" #include "fs_context.h" +#ifdef MY_ABC_HERE +#include "cifsproto.h" +#endif /* MY_ABC_HERE */ static const match_table_t cifs_smb_version_tokens = { { Smb_1, SMB1_VERSION_STRING }, @@ -20,6 +26,9 @@ static const match_table_t cifs_smb_version_tokens = { { Smb_311, SMB311_VERSION_STRING }, { Smb_311, ALT_SMB311_VERSION_STRING }, { Smb_3any, SMB3ANY_VERSION_STRING }, +#ifdef MY_ABC_HERE + { Smb_Syno, SYNO_VERSION_STRING }, +#endif /* MY_ABC_HERE */ { Smb_default, SMBDEFAULT_VERSION_STRING }, { Smb_version_err, NULL } }; @@ -64,6 +73,12 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); return 1; #endif /* CIFS_ALLOW_INSECURE_LEGACY */ +#ifdef MY_ABC_HERE + case Smb_Syno: + vol->ops = &synocifs_operations; + vol->vals = &synocifs_values; + break; +#endif /* MY_ABC_HERE */ case Smb_21: vol->ops = &smb21_operations; vol->vals = &smb21_values; diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 886208a1b0ef..ed32773d7886 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020, Microsoft Corporation. @@ -14,6 +17,9 @@ enum smb_version { Smb_1 = 1, +#ifdef MY_ABC_HERE + Smb_Syno, +#endif /* MY_ABC_HERE */ Smb_20, Smb_21, Smb_30, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index b1f0c05d6eaf..55b6ac8cd61b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/inode.c * @@ -2014,8 +2017,16 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, tcon = tlink_tcon(tlink); server = tcon->ses->server; +#ifdef MY_ABC_HERE + // cifs_sb_tlink need cifs_put_tlink before return + if (!server->ops->rename) { + rc = -ENOSYS; + goto do_rename_exit; + } +#else /* MY_ABC_HERE */ if (!server->ops->rename) return -ENOSYS; +#endif /* MY_ABC_HERE */ /* try path-based rename first */ rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb); @@ -2433,6 +2444,28 @@ int cifs_getattr(const struct path *path, struct kstat *stat, return 0; } +#ifdef MY_ABC_HERE +int cifs_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags) +{ + struct inode *inode = d_inode(dentry); + + /* old CIFS Unix Extensions doesn't return create time */ + if ((syno_flags & SYNOST_CREATE_TIME) && CIFS_I(inode)->createtime) + kst->syno_create_time = cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); + + return 0; +} + +int cifs_syno_get_crtime(struct inode *inode, struct timespec64 *crtime) +{ + /* old CIFS Unix Extensions doesn't return create time */ + if (CIFS_I(inode)->createtime) + *crtime = cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); + + return 0; +} +#endif /* MY_ABC_HERE */ + int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, u64 len) { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 799be3a5d25e..384fcebcbbbf 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/readdir.c * @@ -314,6 +317,9 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, { __dir_info_to_fattr(fattr, info); cifs_fill_common_info(fattr, cifs_sb); +#ifdef MY_ABC_HERE + fattr->cf_nlink = 1; +#endif /* MY_ABC_HERE */ } static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr, @@ -326,6 +332,9 @@ static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr, if (fattr->cf_cifsattrs & ATTR_REPARSE) fattr->cf_cifstag = le32_to_cpu(info->EaSize); cifs_fill_common_info(fattr, cifs_sb); +#ifdef MY_ABC_HERE + fattr->cf_nlink = 1; +#endif /* MY_ABC_HERE */ } static void diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1a0298d1e7cd..c99b13a6d08b 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/sess.c * @@ -361,8 +364,13 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) int bytes_ret = 0; /* Copy OS version */ +#ifdef MY_ABC_HERE + bytes_ret = cifs_strtoUTF16((__le16 *)bcc_ptr, "Synology Linux version ", 32, + nls_cp); +#else /* MY_ABC_HERE */ bytes_ret = cifs_strtoUTF16((__le16 *)bcc_ptr, "Linux version ", 32, nls_cp); +#endif /* MY_ABC_HERE */ bcc_ptr += 2 * bytes_ret; bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, init_utsname()->release, 32, nls_cp); @@ -464,8 +472,13 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* BB check for overflow here */ +#ifdef MY_ABC_HERE + strcpy(bcc_ptr, "Synology Linux version "); + bcc_ptr += strlen("Synology Linux version "); +#else /* MY_ABC_HERE */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); +#endif /* MY_ABC_HERE */ strcpy(bcc_ptr, init_utsname()->release); bcc_ptr += strlen(init_utsname()->release) + 1; @@ -828,8 +841,13 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) case LANMAN: return requested; case Unspecified: +#if defined(MY_ABC_HERE) && !defined(CONFIG_CIFS_WEAK_PW_HASH) + // CID 148534: Logically dead code. + // if !CONFIG_CIFS_WEAK_PW_HASH then CIFSSEC_MAY_LANMAN == 0; +#else /* MY_ABC_HERE */ if (global_secflags & CIFSSEC_MAY_LANMAN) return LANMAN; +#endif /* MY_ABC_HERE */ fallthrough; default: return Unspecified; diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index be3df90bb2bc..add6a7b80a0b 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/smb2misc.c * @@ -880,6 +883,12 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec) /* neg prot are always taken */ if (hdr->Command == SMB2_NEGOTIATE) goto ok; +#ifdef MY_ABC_HERE + if (hdr->Command == SMB2_SESSION_SETUP && !server->secmech.hmacsha256) { + // SMB1 nego to SMB2.02 need to initial it + goto ok; + } +#endif /* MY_ABC_HERE */ /* * If we process a command which wasn't a negprot it means the diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 81e087723777..b0b218eb76d5 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1526,6 +1526,7 @@ smb2_ioctl_query_info(const unsigned int xid, unsigned int size[2]; void *data[2]; int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; + void (*free_req1_func)(struct smb_rqst *r); vars = kzalloc(sizeof(*vars), GFP_ATOMIC); if (vars == NULL) @@ -1535,27 +1536,29 @@ smb2_ioctl_query_info(const unsigned int xid, resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; - if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) - goto e_fault; - + if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) { + rc = -EFAULT; + goto free_vars; + } if (qi.output_buffer_length > 1024) { - kfree(vars); - return -EINVAL; + rc = -EINVAL; + goto free_vars; } if (!ses || !server) { - kfree(vars); - return -EIO; + rc = -EIO; + goto free_vars; } if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - buffer = memdup_user(arg + sizeof(struct smb_query_info), - qi.output_buffer_length); - if (IS_ERR(buffer)) { - kfree(vars); - return PTR_ERR(buffer); + if (qi.output_buffer_length) { + buffer = memdup_user(arg + sizeof(struct smb_query_info), qi.output_buffer_length); + if (IS_ERR(buffer)) { + rc = PTR_ERR(buffer); + goto free_vars; + } } /* Open */ @@ -1593,45 +1596,45 @@ smb2_ioctl_query_info(const unsigned int xid, rc = SMB2_open_init(tcon, server, &rqst[0], &oplock, &oparms, path); if (rc) - goto iqinf_exit; + goto free_output_buffer; smb2_set_next_command(tcon, &rqst[0]); /* Query */ if (qi.flags & PASSTHRU_FSCTL) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { rc = -EPERM; - else { - rqst[1].rq_iov = &vars->io_iov[0]; - rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; - - rc = SMB2_ioctl_init(tcon, server, - &rqst[1], - COMPOUND_FID, COMPOUND_FID, - qi.info_type, true, buffer, - qi.output_buffer_length, - CIFSMaxBufSize - - MAX_SMB2_CREATE_RESPONSE_SIZE - - MAX_SMB2_CLOSE_RESPONSE_SIZE); + goto free_open_req; } + rqst[1].rq_iov = &vars->io_iov[0]; + rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; + + rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, + qi.info_type, true, buffer, qi.output_buffer_length, + CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE - + MAX_SMB2_CLOSE_RESPONSE_SIZE); + free_req1_func = SMB2_ioctl_free; } else if (qi.flags == PASSTHRU_SET_INFO) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { rc = -EPERM; - else { - rqst[1].rq_iov = &vars->si_iov[0]; - rqst[1].rq_nvec = 1; - - size[0] = 8; - data[0] = buffer; - - rc = SMB2_set_info_init(tcon, server, - &rqst[1], - COMPOUND_FID, COMPOUND_FID, - current->tgid, - FILE_END_OF_FILE_INFORMATION, - SMB2_O_INFO_FILE, 0, data, size); + goto free_open_req; } + if (qi.output_buffer_length < 8) { + rc = -EINVAL; + goto free_open_req; + } + rqst[1].rq_iov = &vars->si_iov[0]; + rqst[1].rq_nvec = 1; + + /* MS-FSCC 2.4.13 FileEndOfFileInformation */ + size[0] = 8; + data[0] = buffer; + + rc = SMB2_set_info_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, + current->tgid, FILE_END_OF_FILE_INFORMATION, + SMB2_O_INFO_FILE, 0, data, size); + free_req1_func = SMB2_set_info_free; } else if (qi.flags == PASSTHRU_QUERY_INFO) { rqst[1].rq_iov = &vars->qi_iov[0]; rqst[1].rq_nvec = 1; @@ -1642,6 +1645,7 @@ smb2_ioctl_query_info(const unsigned int xid, qi.info_type, qi.additional_information, qi.input_buffer_length, qi.output_buffer_length, buffer); + free_req1_func = SMB2_query_info_free; } else { /* unknown flags */ cifs_tcon_dbg(VFS, "Invalid passthru query flags: 0x%x\n", qi.flags); @@ -1649,7 +1653,7 @@ smb2_ioctl_query_info(const unsigned int xid, } if (rc) - goto iqinf_exit; + goto free_open_req; smb2_set_next_command(tcon, &rqst[1]); smb2_set_related(&rqst[1]); @@ -1660,14 +1664,14 @@ smb2_ioctl_query_info(const unsigned int xid, rc = SMB2_close_init(tcon, server, &rqst[2], COMPOUND_FID, COMPOUND_FID, false); if (rc) - goto iqinf_exit; + goto free_req_1; smb2_set_related(&rqst[2]); rc = compound_send_recv(xid, ses, server, flags, 3, rqst, resp_buftype, rsp_iov); if (rc) - goto iqinf_exit; + goto out; /* No need to bump num_remote_opens since handle immediately closed */ if (qi.flags & PASSTHRU_FSCTL) { @@ -1677,18 +1681,22 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount); if (qi.input_buffer_length > 0 && le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length - > rsp_iov[1].iov_len) - goto e_fault; + > rsp_iov[1].iov_len) { + rc = -EFAULT; + goto out; + } if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) - goto e_fault; + sizeof(qi.input_buffer_length))) { + rc = -EFAULT; + goto out; + } if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info), (const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset), qi.input_buffer_length)) - goto e_fault; + rc = -EFAULT; } else { pqi = (struct smb_query_info __user *)arg; qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; @@ -1696,28 +1704,30 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength); if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) - goto e_fault; + sizeof(qi.input_buffer_length))) { + rc = -EFAULT; + goto out; + } if (copy_to_user(pqi + 1, qi_rsp->Buffer, qi.input_buffer_length)) - goto e_fault; + rc = -EFAULT; } - iqinf_exit: - cifs_small_buf_release(rqst[0].rq_iov[0].iov_base); - cifs_small_buf_release(rqst[1].rq_iov[0].iov_base); - cifs_small_buf_release(rqst[2].rq_iov[0].iov_base); +out: free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); - kfree(vars); + SMB2_close_free(&rqst[2]); +free_req_1: + free_req1_func(&rqst[1]); +free_open_req: + SMB2_open_free(&rqst[0]); +free_output_buffer: kfree(buffer); +free_vars: + kfree(vars); return rc; - -e_fault: - rc = -EFAULT; - goto iqinf_exit; } static ssize_t diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ab509965656e..3dd9263287bb 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/smb2pdu.c * @@ -96,7 +99,11 @@ int smb3_encryption_required(const struct cifs_tcon *tcon) return 0; } +#ifdef MY_ABC_HERE +void +#else /* MY_ABC_HERE */ static void +#endif /* MY_ABC_HERE */ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, const struct cifs_tcon *tcon, struct TCP_Server_Info *server) @@ -160,6 +167,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, struct nls_table *nls_codepage; struct cifs_ses *ses; int retries; +#ifdef MY_ABC_HERE + u16 origin_dialect; /* dialect index that server chose */ +#endif /* MY_ABC_HERE */ /* * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so @@ -242,16 +252,34 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, retries = server->nr_targets; } +#ifdef MY_ABC_HERE + if (SMB20_PROT_ID > server->dialect) { + cifs_dbg(FYI, "(%s) origin_dialect=0x%x, server->dialect=0x%x\n", __func__, origin_dialect, server->dialect); + return -EAGAIN; + } + origin_dialect = server->dialect; +#endif /* MY_ABC_HERE */ if (!tcon->ses->need_reconnect && !tcon->need_reconnect) return 0; +#ifdef MY_ABC_HERE + nls_codepage = load_nls("utf8"); +#else /* MY_ABC_HERE */ nls_codepage = load_nls_default(); +#endif /* MY_ABC_HERE */ /* * need to prevent multiple threads trying to simultaneously reconnect * the same SMB session */ +#ifdef MY_ABC_HERE + if (!mutex_trylock(&tcon->ses->session_mutex)) { + rc = -EINPROGRESS; + goto out; + } +#else /* MY_ABC_HERE */ mutex_lock(&tcon->ses->session_mutex); +#endif /* MY_ABC_HERE */ /* * Recheck after acquire mutex. If another thread is negotiating @@ -312,6 +340,13 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, mod_delayed_work(cifsiod_wq, &server->reconnect, 0); atomic_inc(&tconInfoReconnectCount); +#ifdef MY_ABC_HERE + if (server->dialect != origin_dialect || + SMB20_PROT_ID > server->dialect) { + cifs_dbg(FYI, "(%s) SMB2 reconnect dialect not match! origin=0x%x, current=0x%x\n", __func__, origin_dialect, server->dialect); + rc = -EAGAIN; + } +#endif /* MY_ABC_HERE */ out: /* * Check if handle based operation so we know whether we can continue @@ -505,7 +540,11 @@ build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) pneg_ctxt->Name[15] = 0x7C; } +#ifdef MY_ABC_HERE +void +#else /* MY_ABC_HERE */ static void +#endif /* MY_ABC_HERE */ assemble_neg_contexts(struct smb2_negotiate_req *req, struct TCP_Server_Info *server, unsigned int *total_len) { @@ -644,9 +683,15 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server, return 0; } +#ifdef MY_ABC_HERE +int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, + struct TCP_Server_Info *server, + unsigned int len_of_smb) +#else /* MY_ABC_HERE */ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, struct TCP_Server_Info *server, unsigned int len_of_smb) +#endif /* MY_ABC_HERE */ { struct smb2_neg_context *pctx; unsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset); @@ -3710,6 +3755,13 @@ SMB2_echo(struct TCP_Server_Info *server) cifs_dbg(FYI, "In echo request\n"); +#ifdef MY_ABC_HERE + if (server && CifsGood != server->tcpStatus) { + cifs_dbg(FYI, "tcpStatus not Good (%d); Don't send echo\n", + server->tcpStatus); + return rc; + } +#endif /* MY_ABC_HERE */ if (server->tcpStatus == CifsNeedNegotiate) { /* No need to send echo on newly established connections */ mod_delayed_work(cifsiod_wq, &server->reconnect, 0); @@ -3770,7 +3822,12 @@ int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) { +#ifdef MY_ABC_HERE + // CID 413508: Dereference before NULL check + struct cifs_ses *ses = tcon ? tcon->ses : NULL; +#else /* MY_ABC_HERE */ struct cifs_ses *ses = tcon->ses; +#endif /* MY_ABC_HERE */ struct smb_rqst rqst; struct kvec iov[1]; struct kvec rsp_iov = {NULL, 0}; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 4eb0ca84355a..6fdb3f962ccb 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/smb2proto.h * @@ -134,6 +137,16 @@ extern void smb2_set_related(struct smb_rqst *rqst); * SMB2 Worker functions - most of protocol specific implementation details * are contained within these calls. */ +#ifdef MY_ABC_HERE +extern void smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, + const struct cifs_tcon *tcon, + struct TCP_Server_Info *server); +extern int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, + struct TCP_Server_Info *server, + unsigned int len_of_smb); +extern void assemble_neg_contexts(struct smb2_negotiate_req *req, + struct TCP_Server_Info *server, unsigned int *total_len); +#endif /* MY_ABC_HERE */ extern int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses); extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *nls_cp); diff --git a/fs/cifs/synoops.c b/fs/cifs/synoops.c new file mode 100644 index 000000000000..077b79a681ab --- /dev/null +++ b/fs/cifs/synoops.c @@ -0,0 +1,855 @@ +#include +#include +#include +#include "cifsglob.h" +#include "smb2pdu.h" +#include "smb2proto.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_unicode.h" +#include "smb2status.h" +#include "smb2glob.h" + +static struct { + char *name; +} smb1_dialects_array[] = { + {"\2NT LM 0.12"}, + {"\2Synology"}, + {"\2SMB 2.002"}, + {"\2SMB 2.???"}, + {NULL} +}; +static __u16 smb2_dialects_array[] = { + SMB20_PROT_ID, + SMB21_PROT_ID, + /** + * SMB3 or above need cmac.ko to do smb signing + * If CMAC not enable, the SMB3 will fail when packets need signing. + * So we need to disable it + */ + SMB30_PROT_ID, + SMB302_PROT_ID, + SMB311_PROT_ID, + BAD_PROT_ID +}; +static int syno_next_header(char *buf); + +void set_operation(struct smb_version_operations *dst, struct smb_version_operations *src) +{ + // SYNO must modify function: + // negotiate, + + dst->check_message = src->check_message; + dst->next_header = src->next_header; + dst->get_next_mid = src->get_next_mid; + dst->find_mid = src->find_mid; + + // use origin function + dst->get_dfs_refer = src->get_dfs_refer; + dst->is_path_accessible = src->is_path_accessible; + dst->query_path_info = src->query_path_info; + dst->query_reparse_tag = src->query_reparse_tag; + dst->get_srv_inum = src->get_srv_inum; + dst->query_file_info = src->query_file_info; + dst->set_path_size = src->set_path_size; + dst->set_file_info = src->set_file_info; + dst->posix_mkdir = src->posix_mkdir; + dst->mkdir = src->mkdir; + dst->rmdir = src->rmdir; + dst->unlink = src->unlink; + dst->rename_pending_delete = src->rename_pending_delete; + dst->rename = src->rename; + dst->create_hardlink = src->create_hardlink; + dst->open = src->open; + dst->queryfs = src->queryfs; + + dst->send_cancel = src->send_cancel; + dst->compare_fids = src->compare_fids; + dst->setup_request = src->setup_request; + dst->setup_async_request = src->setup_async_request; + dst->check_receive = src->check_receive; + dst->add_credits = src->add_credits; + dst->set_credits = src->set_credits; + dst->get_credits_field = src->get_credits_field; + dst->get_credits = src->get_credits; + dst->wait_mtu_credits = src->wait_mtu_credits; + dst->adjust_credits = src->adjust_credits; + dst->revert_current_mid = src->revert_current_mid; + dst->read_data_offset = src->read_data_offset; + dst->read_data_length = src->read_data_length; + dst->map_error = src->map_error; + dst->dump_detail = src->dump_detail; + dst->clear_stats = src->clear_stats; + dst->print_stats = src->print_stats; + dst->dump_share_caps = src->dump_share_caps; + dst->is_oplock_break = src->is_oplock_break; + dst->handle_cancelled_mid = src->handle_cancelled_mid; + dst->downgrade_oplock = src->downgrade_oplock; + dst->check_trans2 = src->check_trans2; + dst->need_neg = src->need_neg; + dst->negotiate_wsize = src->negotiate_wsize; + dst->negotiate_rsize = src->negotiate_rsize; + dst->sess_setup = src->sess_setup; + dst->logoff = src->logoff; + dst->tree_connect = src->tree_connect; + dst->tree_disconnect = src->tree_disconnect; + dst->qfs_tcon = src->qfs_tcon; + dst->can_echo = src->can_echo; + dst->echo = src->echo; + dst->set_file_size = src->set_file_size; + dst->set_compression = src->set_compression; + dst->mkdir_setinfo = src->mkdir_setinfo; + dst->query_symlink = src->query_symlink; + dst->enum_snapshots = src->enum_snapshots; + dst->notify = src->notify; + dst->query_mf_symlink = src->query_mf_symlink; + dst->create_mf_symlink = src->create_mf_symlink; + dst->set_fid = src->set_fid; + dst->close_getattr = src->close_getattr; + dst->close = src->close; + dst->flush = src->flush; + dst->async_readv = src->async_readv; + dst->async_writev = src->async_writev; + dst->sync_read = src->sync_read; + dst->sync_write = src->sync_write; + dst->query_dir_first = src->query_dir_first; + dst->query_dir_next = src->query_dir_next; + dst->close_dir = src->close_dir; + dst->calc_smb_size = src->calc_smb_size; + dst->is_status_pending = src->is_status_pending; + dst->is_session_expired = src->is_session_expired; + dst->oplock_response = src->oplock_response; + dst->mand_lock = src->mand_lock; + dst->mand_unlock_range = src->mand_unlock_range; + dst->push_mand_locks = src->push_mand_locks; + dst->get_lease_key = src->get_lease_key; + dst->set_lease_key = src->set_lease_key; + dst->new_lease_key = src->new_lease_key; + dst->generate_signingkey = src->generate_signingkey; + dst->calc_signature = src->calc_signature; + dst->set_integrity = src->set_integrity; + dst->is_read_op = src->is_read_op; + dst->set_oplock_level = src->set_oplock_level; + dst->create_lease_buf = src->create_lease_buf; + dst->parse_lease_buf = src->parse_lease_buf; + dst->copychunk_range = src->copychunk_range; + dst->duplicate_extents = src->duplicate_extents; + dst->validate_negotiate = NULL; +#ifdef CONFIG_CIFS_XATTR + dst->query_all_EAs = src->query_all_EAs; + dst->set_EA = src->set_EA; +#endif /* CIFS_XATTR */ + dst->wp_retry_size = src->wp_retry_size; + dst->dir_needs_close = src->dir_needs_close; + dst->select_sectype = src->select_sectype; + dst->fallocate = src->fallocate; + dst->get_acl = src->get_acl; + dst->get_acl_by_fid = src->get_acl_by_fid; + dst->set_acl = src->set_acl; + dst->init_transform_rq = src->init_transform_rq; + dst->is_transform_hdr = src->is_transform_hdr; + dst->receive_transform = src->receive_transform; + dst->make_node = src->make_node; + dst->ioctl_query_info = src->ioctl_query_info; + dst->fiemap = src->fiemap; + dst->llseek = src->llseek; + dst->is_status_io_timeout = src->is_status_io_timeout; +} + +// __u64 (*get_next_mid)(struct TCP_Server_Info *); +/** + * This method smb1_operations and smb20_operations have different logic. + * because the smb1 mid is only 16 bits. smb2 mid is 64 bits. + * And smb1 negotiate can start with any mid. + * smb2 negotiate must start with mid=0. + * (Even if we start with 1, the server also reply 0) + * + * The origin implement: + * smb1 implement is silmilar to return ++CurrentMid + * smb2 return CurrentMid++ + * + * So align the implement behavior for syno ops + * + */ +static __u64 +smb1_get_next_mid(struct TCP_Server_Info *server) +{ + __u64 mid = 0; + __u16 last_mid, cur_mid; + bool collision; + + spin_lock(&GlobalMid_Lock); + + /* mid is 16 bit only for CIFS/SMB */ + cur_mid = (__u16)((server->CurrentMid) & 0xffff); + /* we do not want to loop forever */ + last_mid = cur_mid; + /* avoid 0xFFFF MID */ + if (cur_mid == 0xffff) + cur_mid++; + + /* + * This nested loop looks more expensive than it is. + * In practice the list of pending requests is short, + * fewer than 50, and the mids are likely to be unique + * on the first pass through the loop unless some request + * takes longer than the 64 thousand requests before it + * (and it would also have to have been a request that + * did not time out). + */ + do { + struct mid_q_entry *mid_entry; + unsigned int num_mids; + + collision = false; + + num_mids = 0; + list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { + ++num_mids; + if (mid_entry->mid == cur_mid && + mid_entry->mid_state == MID_REQUEST_SUBMITTED) { + /* This mid is in use, try a different one */ + collision = true; + break; + } + } + + /* + * if we have more than 32k mids in the list, then something + * is very wrong. Possibly a local user is trying to DoS the + * box by issuing long-running calls and SIGKILL'ing them. If + * we get to 2^16 mids then we're in big trouble as this + * function could loop forever. + * + * Go ahead and assign out the mid in this situation, but force + * an eventual reconnect to clean out the pending_mid_q. + */ + if (num_mids > 32768) + server->tcpStatus = CifsNeedReconnect; + + if (!collision) { + mid = (__u64)cur_mid; + server->CurrentMid = mid + 1; + break; + } + cur_mid++; + } while (cur_mid != last_mid); + spin_unlock(&GlobalMid_Lock); + return mid; +} +static __u64 +syno_get_next_mid(struct TCP_Server_Info *server) +{ + if (SMB20_PROT_ID > server->dialect) { + return smb1_get_next_mid(server); + } + return smb20_operations.get_next_mid(server); +} + +// struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *); +struct mid_q_entry * +syno_find_mid(struct TCP_Server_Info *server, char *buf) +{ + struct mid_q_entry *mid; + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; + __u64 wire_mid = le64_to_cpu(shdr->MessageId); + + if (0xFF == (__u8)buf[4]) { + return smb1_operations.find_mid(server, buf); + } + + // smb2 part + if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { + cifs_server_dbg(VFS, "Encrypted frame parsing not supported yet\n"); + return NULL; + } + + spin_lock(&GlobalMid_Lock); + list_for_each_entry(mid, &server->pending_mid_q, qhead) { + if ((mid->mid == wire_mid) && + (mid->mid_state == MID_REQUEST_SUBMITTED) && + (mid->command == shdr->Command || + //negotiate rqst might be come from SMB1 + (mid->command == 0x72 && shdr->Command == 0))) + { + kref_get(&mid->refcount); + spin_unlock(&GlobalMid_Lock); + return mid; + } + } + spin_unlock(&GlobalMid_Lock); + return NULL; +} + +// int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); +static int +syno_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server) +{ + if (0xFF == (__u8)buf[4]) { + return smb1_operations.check_message(buf, len, server); + } + // SMB2 header structure: 0xFE 'S' 'M' 'B' + // if come from SMB1 nego -- 1st 4 bytes is netbios length and then 0xFF S M B + if (8 < len && 'S' != buf[1] && 'S' == buf[5]) { + return smb20_operations.check_message(buf+4, len - 4, server); + } + return smb20_operations.check_message(buf, len, server); +} + +// int (*negotiate)(const unsigned int, struct cifs_ses *); +static bool +should_set_ext_sec_flag(enum securityEnum sectype) +{ + switch (sectype) { + case RawNTLMSSP: + case Kerberos: + return true; + case Unspecified: + if (global_secflags & + (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)) + return true; + fallthrough; + default: + return false; + } +} +static int +decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) +{ + int rc = 0; + u16 count; + char *guid = pSMBr->u.extended_response.GUID; + struct TCP_Server_Info *server = ses->server; + + count = get_bcc(&pSMBr->hdr); + if (count < SMB1_CLIENT_GUID_SIZE) + return -EIO; + + spin_lock(&cifs_tcp_ses_lock); + if (server->srv_count > 1) { + spin_unlock(&cifs_tcp_ses_lock); + if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) { + cifs_dbg(FYI, "server UID changed\n"); + memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); + } + } else { + spin_unlock(&cifs_tcp_ses_lock); + memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); + } + + if (count == SMB1_CLIENT_GUID_SIZE) { + server->sec_ntlmssp = true; + } else { + count -= SMB1_CLIENT_GUID_SIZE; + rc = decode_negTokenInit( + pSMBr->u.extended_response.SecurityBlob, count, server); + if (rc != 1) + return -EINVAL; + } + + return 0; +} +static int +syno_check_smb1_nego_rsp(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) +{ + int rc = 0; + struct TCP_Server_Info *server = ses->server; + + rc = map_smb_to_linux_error((char *)&pSMBr->hdr, false); + if (0 != rc) { + goto neg_err_exit; + } + server->dialect = le16_to_cpu(pSMBr->DialectIndex); + server->vals = &smb1_values; + /* Check wct = 1 error case */ + if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) { + /* core returns wct = 1, but we do not ask for core - otherwise + small wct just comes when dialect index is -1 indicating we + could not negotiate a common dialect */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } else if (pSMBr->hdr.WordCount == 13) { + server->negflavor = CIFS_NEGFLAVOR_LANMAN; + rc = -EOPNOTSUPP; + goto neg_err_exit; + } else if (pSMBr->hdr.WordCount != 17) { + /* unknown wct */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } + /* else wct == 17, NTLM or better */ + + server->sec_mode = pSMBr->SecurityMode; + if ((server->sec_mode & SECMODE_USER) == 0) + cifs_dbg(FYI, "share mode security\n"); + + /* one byte, so no need to convert this or EncryptionKeyLen from + little endian */ + server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), + cifs_max_pending); + set_credits(server, server->maxReq); + /* probably no need to store and check maxvcs */ + server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); + /* set up max_read for readpages check */ + server->max_read = server->maxBuf; + server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); + cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); + server->capabilities = le32_to_cpu(pSMBr->Capabilities); + server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); + server->timeAdj *= 60; + + if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + server->negflavor = CIFS_NEGFLAVOR_UNENCAP; + memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || + server->capabilities & CAP_EXTENDED_SECURITY) { + server->negflavor = CIFS_NEGFLAVOR_EXTENDED; + rc = decode_ext_sec_blob(ses, pSMBr); + } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { + rc = -EIO; /* no crypt key only if plain text pwd */ + } else { + server->negflavor = CIFS_NEGFLAVOR_UNENCAP; + server->capabilities &= ~CAP_EXTENDED_SECURITY; + } + + if (!rc) + rc = cifs_enable_signing(server, ses->sign); +neg_err_exit: + return rc; +} +static int +syno_check_smb2_nego_rsp(struct cifs_ses *ses, struct smb2_negotiate_rsp *rsp, size_t rsp_iov_len) +{ + int rc = 0; + struct TCP_Server_Info *server = ses->server; + int blob_offset, blob_length; + char *security_blob; + + rc = map_smb2_to_linux_error((char *)&rsp->sync_hdr, false); + if (0 != rc) { + goto neg_exit; + } + /* + * No tcon so can't do + * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); + */ + + cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode); + + /* BB we may eventually want to match the negotiated vs. requested + dialect, even though we are only requesting one at a time */ + if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) { + cifs_dbg(FYI, "negotiated smb2.0 dialect\n"); + server->vals = &smb20_values; + // SMB2.02 may be come from SMB1 Nego. + // So need to use syno function to process. + // Don't set operations here + // We set operation after this function. + } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { + cifs_dbg(FYI, "negotiated smb2.1 dialect\n"); + server->vals = &smb21_values; + set_operation(server->ops, &smb21_operations); + } else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID)) { + cifs_dbg(FYI, "negotiated smb3.0 dialect\n"); + server->vals = &smb30_values; + set_operation(server->ops, &smb30_operations); + } else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID)) { + cifs_dbg(FYI, "negotiated smb3.02 dialect\n"); + server->vals = &smb302_values; + set_operation(server->ops, &smb30_operations); + } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { + cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n"); + server->vals = &smb311_values; + set_operation(server->ops, &smb311_operations); + } else if (rsp->DialectRevision == cpu_to_le16(0x02ff)) { + cifs_dbg(FYI, "negotiated smb2.FF dialect\n"); + } else { + cifs_dbg(VFS, "Illegal dialect returned by server 0x%x\n", + le16_to_cpu(rsp->DialectRevision)); + rc = -EIO; + goto neg_exit; + } + server->dialect = le16_to_cpu(rsp->DialectRevision); + if (rsp->DialectRevision == cpu_to_le16(0x02ff)) { + server->dialect = cpu_to_le16(SMB21_PROT_ID); + } + + /* + * Keep a copy of the hash after negprot. This hash will be + * the starting hash value for all sessions made from this + * server. + */ + memcpy(server->preauth_sha_hash, ses->preauth_sha_hash, + SMB2_PREAUTH_HASH_SIZE); + + /* SMB2 only has an extended negflavor */ + server->negflavor = CIFS_NEGFLAVOR_EXTENDED; + /* set it to the maximum buffer size value we can send with 1 credit */ + server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize), + SMB2_MAX_BUFFER_SIZE); + server->max_read = le32_to_cpu(rsp->MaxReadSize); + server->max_write = le32_to_cpu(rsp->MaxWriteSize); + server->sec_mode = le16_to_cpu(rsp->SecurityMode); + if ((server->sec_mode & SMB2_SEC_MODE_FLAGS_ALL) != server->sec_mode) + cifs_dbg(FYI, "Server returned unexpected security mode 0x%x\n", + server->sec_mode); + server->capabilities = le32_to_cpu(rsp->Capabilities); + /* Internal types */ + server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES; + + security_blob = smb2_get_data_area_len(&blob_offset, &blob_length, + (struct smb2_sync_hdr *)rsp); + /* + * See MS-SMB2 section 2.2.4: if no blob, client picks default which + * for us will be + * ses->sectype = RawNTLMSSP; + * but for time being this is our only auth choice so doesn't matter. + * We just found a server which sets blob length to zero expecting raw. + */ + if (blob_length == 0) { + cifs_dbg(FYI, "missing security blob on negprot\n"); + } + + rc = cifs_enable_signing(server, ses->sign); + if (rc) { + goto neg_exit; + } + if (blob_length) { + rc = decode_negTokenInit(security_blob, blob_length, server); + if (rc == 1) { + rc = 0; + } else if (rc == 0) { + rc = -EIO; + } + } + + if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { + if (rsp->NegotiateContextCount) { + rc = smb311_decode_neg_context(rsp, server, + rsp_iov_len); + } else { + cifs_server_dbg(VFS, "Missing expected negotiate contexts\n"); + } + } +neg_exit: + return rc; +} + +static int +small_smb1_nego_init(__le16 smb_command, void **request_buf) +{ + int rc = 0; + + /* BB eventually switch this to SMB2 specific small buf size */ + *request_buf = cifs_small_buf_get(); + if (*request_buf == NULL) { + /* BB should we add a retry in here if not a writepage? */ + return -ENOMEM; + } + + header_assemble((struct smb_hdr *) *request_buf, smb_command, NULL, 0); + + return rc; +} + +static int +SYNO_negotiate_SMB1_start(const unsigned int xid, struct cifs_ses *ses) +{ + NEGOTIATE_REQ *pSMB; + + struct kvec rsp_iov[1]; + int rc = 0; + int i; + struct TCP_Server_Info *server = ses->server; + char *buf = NULL; + u16 count; + __u8 *ubuf = NULL; + + if (!server) { + WARN(1, "%s: server is NULL!\n", __func__); + return -EIO; + } + server->dialect = 0; + server->CurrentMid = 0; + server->vals = &smb1_values; + + set_operation(server->ops, &smb1_operations); + server->ops->check_message = syno_check_message; + server->ops->next_header = syno_next_header; + server->ops->get_next_mid = syno_get_next_mid; + server->ops->find_mid = syno_find_mid; + + rc = small_smb1_nego_init(SMB_COM_NEGOTIATE, (void **) &pSMB); + if (rc) + return rc; + rsp_iov[0].iov_base = cifs_small_buf_get(); + if (NULL == rsp_iov[0].iov_base) { + rc = -ENOMEM; + goto neg_err_exit; + } + + pSMB->hdr.Mid = get_next_mid(server); + pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); + + if (should_set_ext_sec_flag(ses->sectype)) { + cifs_dbg(FYI, "Requesting extended security\n"); + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + } + + count = 0; + for (i = 0; NULL != smb1_dialects_array[i].name; i++) { + strncpy(pSMB->DialectsArray+count, smb1_dialects_array[i].name, 16); + count += strlen(smb1_dialects_array[i].name) + 1; + /* null at end of source and target buffers anyway */ + } + inc_rfc1001_len(pSMB, count); + pSMB->ByteCount = cpu_to_le16(count); + + rc = SendReceiveSyno(xid, ses, (struct smb_hdr *) pSMB, + rsp_iov, 0); + if (rc != 0) { + goto neg_err_exit; + } + + ubuf = (__u8 *)rsp_iov[0].iov_base; + if (0xFF == ubuf[4]) { + //check smb1 response. + //extract from the cifssmb.c CIFSSMBNegotiate response process + rc = syno_check_smb1_nego_rsp(ses, rsp_iov[0].iov_base); + if (0 != rc) { + //force dialect to SMB2.1 for retry SMB2 negotiate + server->dialect = SMB21_PROT_ID; + } + } else { + //check smb2 response + buf = (char *)rsp_iov[0].iov_base; + rc = syno_check_smb2_nego_rsp(ses, (struct smb2_negotiate_rsp *)(buf + 4), rsp_iov[0].iov_len - 4); + } +neg_err_exit: + cifs_small_buf_release(pSMB); + cifs_small_buf_release(rsp_iov[0].iov_base); + + cifs_dbg(FYI, "negprot rc %d\n", rc); + return rc; +} + +static int +smb2_nego_init(__le16 smb2_command, void **request_buf, + struct TCP_Server_Info *server, + unsigned int *total_len) +{ + struct smb2_sync_pdu *spdu = NULL; + + /* BB eventually switch this to SMB2 specific small buf size */ + *request_buf = cifs_small_buf_get(); + if (*request_buf == NULL) { + /* BB should we add a retry in here if not a writepage? */ + return -ENOMEM; + } + memset((*request_buf), 0, 256); + spdu = (struct smb2_sync_pdu *)(*request_buf); + /* + * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of + * largest operations (Create) + */ + + smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, NULL, server); + + // SMB2_NEGOTIATE 36 from smb2_req_struct_sizes + spdu->StructureSize2 = cpu_to_le16(36); + *total_len = 36 + sizeof(struct smb2_sync_hdr); + + return 0; +} +static int +syno_SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) +{ + struct smb_rqst rqst; + struct smb2_negotiate_req *req; + struct smb2_negotiate_rsp *rsp; + struct kvec iov[1]; + struct kvec rsp_iov[1]; + int i; + u16 count; + int rc = 0; + int resp_buftype; + struct TCP_Server_Info *server = ses->server; + int flags = CIFS_NEG_OP; + unsigned int total_len; + + if (!server) { + cifs_dbg(VFS, "%s: server is NULL!\n", __func__); + return -EIO; + } + server->vals = &smb311_values; + if (SMB20_PROT_ID > server->dialect) { + server->dialect = cpu_to_le16(SMB311_PROT_ID); + } + set_operation(server->ops, &smb311_operations); + + rc = smb2_nego_init(SMB2_NEGOTIATE, (void **) &req, server, &total_len); + if (rc) { + return rc; + } + + req->sync_hdr.SessionId = 0; + + memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); + memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); + + count = 0; + for (i = 0; BAD_PROT_ID != smb2_dialects_array[i]; i++) { + req->Dialects[count] = cpu_to_le16(smb2_dialects_array[i]); + count++; + total_len += 2; + } + + req->DialectCount = cpu_to_le16(count); + + /* only one of SMB2 signing flags may be set in SMB2 request */ + if (ses->sign) + req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED); + else if (global_secflags & CIFSSEC_MAY_SIGN) + req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED); + else + req->SecurityMode = 0; + + req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities); + + /* ClientGUID must be zero for SMB2.02 dialect */ + if (ses->server->vals->protocol_id == SMB20_PROT_ID) + memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE); + else { + memcpy(req->ClientGUID, server->client_guid, + SMB2_CLIENT_GUID_SIZE); + assemble_neg_contexts(req, server, &total_len); + } + iov[0].iov_base = (char *)req; + iov[0].iov_len = total_len; + + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, server, + &rqst, &resp_buftype, flags, rsp_iov); + cifs_small_buf_release(req); + + rsp = (struct smb2_negotiate_rsp *)rsp_iov[0].iov_base; + /* + * No tcon so can't do + * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); + */ + if (rc != 0) { + goto neg_exit; + } + + rc = syno_check_smb2_nego_rsp(ses, (struct smb2_negotiate_rsp *)rsp_iov[0].iov_base, rsp_iov[0].iov_len); +neg_exit: + free_rsp_buf(resp_buftype, rsp); + return rc; +} +static int +syno_negotiate(const unsigned int xid, struct cifs_ses *ses) +{ + int rc; + rc = SYNO_negotiate_SMB1_start(xid, ses); + if (0 != rc) { + ses->server->CurrentMid = 0; + } else if (SMB20_PROT_ID >= ses->server->dialect) { + goto END; + } + rc = syno_SMB2_negotiate(xid, ses); + /* BB we probably don't need to retry with modern servers */ +END: + if (rc == -EAGAIN) { + rc = -EHOSTDOWN; + } + if (0 != rc) { + //negotiate fail ==> reset need_neg + ses->server->maxBuf = 0; + ses->server->max_read = 0; + } + if (0 == rc) { + // if the response come from SMB1 nego, + // we need to set operations to replace syno nego function + if (SMB20_PROT_ID > ses->server->dialect) { + set_operation(ses->server->ops, &smb1_operations); + } else if (SMB20_PROT_ID == ses->server->dialect) { + set_operation(ses->server->ops, &smb20_operations); + } + } + return rc; +} + + +// int (*next_header)(char *); +static int +syno_next_header(char *buf) +{ + // caller: connect.c -- cifs_demultiplex_thread + // return 0 will do not thing + struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf; + struct smb2_transform_hdr *t_hdr = (struct smb2_transform_hdr *)buf; + + if (0xFF == (__u8)buf[4]) { + // SMB1 no Next command. directly return 0 + return 0; + } + if (hdr->Command == SMB2_NEGOTIATE) { + // SMB1 Nego to SMB2 Nego(0x00) will no Next command. directly return 0 + // SMB2 Nego never compound now. + return 0; + } + if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) { + return sizeof(struct smb2_transform_hdr) + + le32_to_cpu(t_hdr->OriginalMessageSize); + } + + return le32_to_cpu(hdr->NextCommand); +} + +void init_syno_operations(struct TCP_Server_Info *server, struct smb_vol *volume_info) +{ + if (&synocifs_values == volume_info->vals) { + server->values = volume_info->vals; + + // &synocifs_operations only have some nego function. + // we need to initialize other operation's function. + server->ops = &server->operations; + server->ops->negotiate = synocifs_operations.negotiate; + set_operation(server->ops, &smb1_operations); + } +} + +struct smb_version_operations synocifs_operations = { + .negotiate = syno_negotiate, + + // For negotiate only: + .get_next_mid = syno_get_next_mid, + .find_mid = syno_find_mid, + .check_message = syno_check_message, + .next_header = syno_next_header, +}; + +struct smb_version_values synocifs_values = { + .version_string = SYNO_VERSION_STRING, + .protocol_id = SMB21_PROT_ID, //should set after negotiate + .req_capabilities = 0, /* MBZ on negotiate req until SMB3 dialect */ + .large_lock_type = 0, + .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, + .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, + .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, + .header_size = sizeof(struct smb2_sync_hdr), + .header_preamble_size = 0, + .max_header_size = MAX_SMB2_HDR_SIZE, + .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .lock_cmd = SMB2_LOCK, + .cap_unix = 0, + .cap_nt_find = SMB2_NT_FIND, + .cap_large_files = SMB2_LARGE_FILES, + .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED, + .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, + .create_lease_size = sizeof(struct create_lease), +}; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 503a0056b60f..90b06195f35a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * fs/cifs/transport.c * @@ -238,6 +241,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, * reconnect which may clear the network problem. */ rc = sock_sendmsg(ssocket, smb_msg); +#ifdef MY_ABC_HERE + if (rc == -EAGAIN || rc == -EINTR) { + retries++; + if (!server->noblocksnd && (retries > 2)) { + cifs_dbg(VFS, "sends on sock %p stuck 3 time fail with blocksend (sndtimo=5s)\n", ssocket); + rc = -EAGAIN; + break; + } + if (retries >= 14) { + cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", + ssocket); + rc = -EAGAIN; + break; + } + msleep(1 << retries); + continue; + } +#else /* MY_ABC_HERE */ if (rc == -EAGAIN) { retries++; if (retries >= 14 || @@ -249,6 +270,7 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, msleep(1 << retries); continue; } +#endif /* MY_ABC_HERE */ if (rc < 0) return rc; @@ -443,7 +465,14 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, * be taken as the remainder of this one. We need to kill the * socket so the server throws away the partial SMB */ +#ifdef MY_ABC_HERE + // CID 45292: Data race condition. tcpstatus only set without lock here. + spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); +#else /* MY_ABC_HERE */ + server->tcpStatus = CifsNeedReconnect; +#endif /* MY_ABC_HERE */ trace_smb3_partial_send_reconnect(server->CurrentMid, server->hostname); } @@ -1268,6 +1297,35 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov; int rc; +#ifdef MY_ABC_HERE + if (&synocifs_values == ses->server->values) { + if (SMB20_PROT_ID > ses->server->dialect) { + struct smb_hdr *hdr = iov->iov_base; + if (0xFF != hdr->Protocol[0]) { + cifs_dbg(FYI, "%s: SMB Command(0x%x) Dialect(0x%x); header(0x%x) isn't SMB1\n", + __func__, + hdr->Command, + ses->server->dialect, + hdr->Protocol[0]); + *resp_buf_type = CIFS_NO_BUFFER; + return -EAGAIN; + } + } else { + struct smb2_sync_hdr *shdr = iov->iov_base; + if (SMB2_PROTO_NUMBER != shdr->ProtocolId && + SMB2_TRANSFORM_PROTO_NUM != shdr->ProtocolId && + SMB2_COMPRESSION_TRANSFORM_ID != shdr->ProtocolId) { + cifs_dbg(FYI, "%s: SMB Command(0x%x) Dialect(0x%x); header(0x%x) isn't SMB2\n", + __func__, + shdr->Command, + ses->server->dialect, + shdr->ProtocolId); + *resp_buf_type = CIFS_NO_BUFFER; + return -EAGAIN; + } + } + } +#endif /* MY_ABC_HERE */ if (n_vec + 1 > CIFS_MAX_IOV_SIZE) { new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec), GFP_KERNEL); @@ -1338,6 +1396,30 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc) return rc; +#ifdef MY_ABC_HERE + if (&synocifs_values == ses->server->values) { + if (SMB20_PROT_ID <= ses->server->dialect) { + if (0xFF == in_buf->Protocol[0]) { + cifs_dbg(FYI, "%s: SMB1 Command(0x%x), but server Dialect(0x%x) is SMB2\n", + __func__, + in_buf->Command, + ses->server->dialect); + return -EAGAIN; + } + } else if (0xFE == in_buf->Protocol[0] || + 0xFD == in_buf->Protocol[0] || + 0xFC == in_buf->Protocol[0]) { + // FIXME: compression and transform + struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)in_buf; + // SMB2 header should not send here. + cifs_dbg(FYI, "%s: SMB2 Command(0x%x) Dialect(0x%x) use SendReceive\n", + __func__, + hdr->Command, + ses->server->dialect); + return -EAGAIN; + } + } +#endif /* MY_ABC_HERE */ /* make sure that we sign in the same order that we send on this socket and avoid races inside tcp sendmsg code that could cause corruption of smb data */ @@ -1409,6 +1491,120 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, return rc; } +#ifdef MY_ABC_HERE +int +SendReceiveSyno(const unsigned int xid, struct cifs_ses *ses, + struct smb_hdr *in_buf, struct kvec *out_buf, + const int flags) +{ + int rc = 0; + struct mid_q_entry *midQ; + unsigned int len = be32_to_cpu(in_buf->smb_buf_length); + struct kvec iov = { .iov_base = in_buf, .iov_len = len }; + struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; + struct cifs_credits credits = { .value = 1, .instance = 0 }; + struct TCP_Server_Info *server; + + if (ses == NULL) { + return -EIO; + } + server = ses->server; + if (server == NULL) { + return -EIO; + } + + if (server->tcpStatus == CifsExiting) { + return -ENOENT; + } + + /* Ensure that we do not send more than 50 overlapping requests + to the same server. We may make this configurable later or + use ses->maxReq */ + + if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n", + len); + return -EIO; + } + + rc = wait_for_free_request(server, flags, &credits.instance); + if (rc) { + return rc; + } + + /* make sure that we sign in the same order that we send on this socket + and avoid races inside tcp sendmsg code that could cause corruption + of smb data */ + + mutex_lock(&server->srv_mutex); + + rc = allocate_mid(ses, in_buf, &midQ); + if (rc) { + mutex_unlock(&server->srv_mutex); + /* Update # of requests on wire to server */ + add_credits(server, &credits, 0); + return rc; + } + + rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number); + if (rc) { + mutex_unlock(&server->srv_mutex); + goto out; + } + + midQ->mid_state = MID_REQUEST_SUBMITTED; + + cifs_in_send_inc(server); + rc = smb_send(server, in_buf, len); + cifs_in_send_dec(server); + cifs_save_when_sent(midQ); + + if (rc < 0) { + server->sequence_number -= 2; + } + + mutex_unlock(&server->srv_mutex); + + if (rc < 0) { + goto out; + } + + rc = wait_for_response(server, midQ); + if (rc != 0) { + send_cancel(server, &rqst, midQ); + spin_lock(&GlobalMid_Lock); + if (midQ->mid_state == MID_REQUEST_SUBMITTED) { + /* no longer considered to be "in-flight" */ + midQ->callback = DeleteMidQEntry; + spin_unlock(&GlobalMid_Lock); + add_credits(server, &credits, 0); + return rc; + } + spin_unlock(&GlobalMid_Lock); + } + + rc = cifs_sync_mid_result(midQ, server); + if (rc != 0) { + add_credits(server, &credits, 0); + return rc; + } + + if (!midQ->resp_buf || !out_buf || !out_buf[0].iov_base || + midQ->mid_state != MID_RESPONSE_RECEIVED) { + rc = -EIO; + cifs_server_dbg(VFS, "Bad MID state?\n"); + goto out; + } + + out_buf[0].iov_len = get_rfc1002_length(midQ->resp_buf); + memcpy(out_buf[0].iov_base, midQ->resp_buf, out_buf[0].iov_len); +out: + cifs_delete_mid(midQ); + add_credits(server, &credits, 0); + + return rc; +} +#endif /* MY_ABC_HERE */ /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to return. */ diff --git a/fs/configfs/file.c b/fs/configfs/file.c index 4d0825213116..0482cb610c5e 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: @@ -26,7 +29,11 @@ * because an attribute of 16k on ia64 won't work on x86. So we limit to * 4k, our minimum common page size. */ +#ifdef MY_ABC_HERE +#define SIMPLE_ATTR_SIZE PAGE_SIZE +#else /* MY_ABC_HERE */ #define SIMPLE_ATTR_SIZE 4096 +#endif /* MY_ABC_HERE */ struct configfs_buffer { size_t count; diff --git a/fs/dcache.c b/fs/dcache.c index ea0485861d93..8fba7d027722 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * fs/dcache.c @@ -191,7 +194,11 @@ int proc_nr_dentry(struct ctl_table *table, int write, void *buffer, * In contrast, 'ct' and 'tcount' can be from a pathname, and do * need the careful unaligned handling. */ -static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount) +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount) { unsigned long a,b,mask; @@ -214,7 +221,11 @@ static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char #else -static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount) +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount) { do { if (*cs != *ct) @@ -227,8 +238,15 @@ static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char } #endif +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(dentry_string_cmp); +#endif /* MY_ABC_HERE */ -static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) { /* * Be careful about RCU walk racing with rename: @@ -250,6 +268,9 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c return dentry_string_cmp(cs, ct, tcount); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(dentry_cmp); +#endif /* MY_ABC_HERE */ struct external_name { union { @@ -309,6 +330,48 @@ void release_dentry_name_snapshot(struct name_snapshot *name) } EXPORT_SYMBOL(release_dentry_name_snapshot); +#ifdef MY_ABC_HERE +/* + * It would modify dentry's name, so caller should + * care about not only the race-condition issue + * and the rcu mode lookup mechanism. Then get + * appropriate lock. + */ +int dentry_replace_name(struct dentry *dentry, const char *new_name, u32 name_len) +{ + char *real_name = NULL; + struct external_name *old_ex_name = NULL; + struct external_name *new_ex_name = NULL; + + if (unlikely(dname_external(dentry))) + old_ex_name = external_name(dentry); + + if (unlikely(name_len > (DNAME_INLINE_LEN - 1))) { + const size_t size = offsetof(struct external_name, name[1]); + new_ex_name = kmalloc(size + name_len, + GFP_KERNEL_ACCOUNT | __GFP_RECLAIMABLE); + if (!new_ex_name) + return -ENOMEM; + + atomic_set(&new_ex_name->u.count, 1); + real_name = new_ex_name->name; + } else { + real_name = dentry->d_iname; + } + + memcpy(real_name, new_name, name_len); + real_name[name_len] = 0; + dentry->d_name.len = name_len; + /* Make sure we always see the terminating NUL character */ + smp_store_release(&dentry->d_name.name, real_name); /* ^^^ */ + if (old_ex_name && likely(atomic_dec_and_test(&old_ex_name->u.count))) + kfree_rcu(old_ex_name, u.head); + return 0; +} +EXPORT_SYMBOL(dentry_replace_name); + +#endif /* MY_ABC_HERE */ + static inline void __d_set_inode_and_type(struct dentry *dentry, struct inode *inode, unsigned type_flags) @@ -1285,8 +1348,13 @@ enum d_walk_ret { * * The @enter() callbacks are called with d_lock held. */ +#ifdef MY_ABC_HERE +void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *)) +#else static void d_walk(struct dentry *parent, void *data, enum d_walk_ret (*enter)(void *, struct dentry *)) +#endif /* MY_ABC_HERE */ { struct dentry *this_parent; struct list_head *next; @@ -1390,6 +1458,9 @@ static void d_walk(struct dentry *parent, void *data, seq = 1; goto again; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(d_walk); +#endif /* MY_ABC_HERE */ struct check_mount { struct vfsmount *mnt; @@ -1867,6 +1938,10 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) dentry->d_flags |= DCACHE_OP_HASH; if (op->d_compare) dentry->d_flags |= DCACHE_OP_COMPARE; +#ifdef MY_ABC_HERE + if (op->d_compare_case) + dentry->d_flags |= DCACHE_OP_COMPARE_CASE; +#endif /* MY_ABC_HERE */ if (op->d_revalidate) dentry->d_flags |= DCACHE_OP_REVALIDATE; if (op->d_weak_revalidate) @@ -2189,8 +2264,21 @@ EXPORT_SYMBOL(d_add_ci); static inline bool d_same_name(const struct dentry *dentry, const struct dentry *parent, - const struct qstr *name) + const struct qstr *name +#ifdef MY_ABC_HERE + , const int caseless +#endif /* MY_ABC_HERE */ + ) { +#ifdef MY_ABC_HERE + if (likely(parent->d_flags & DCACHE_OP_COMPARE_CASE)) + return parent->d_op->d_compare_case(dentry, + dentry->d_name.len, + dentry->d_name.name, + name, + caseless) == 0; + else +#endif /* MY_ABC_HERE */ if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) { if (dentry->d_name.len != name->len) return false; @@ -2232,13 +2320,20 @@ static inline bool d_same_name(const struct dentry *dentry, */ struct dentry *__d_lookup_rcu(const struct dentry *parent, const struct qstr *name, - unsigned *seqp) + unsigned *seqp +#ifdef MY_ABC_HERE + , const int caseless +#endif /* MY_ABC_HERE */ + ) { u64 hashlen = name->hash_len; const unsigned char *str = name->name; struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen)); struct hlist_bl_node *node; struct dentry *dentry; +#ifdef MY_ABC_HERE + struct dentry *found = NULL; +#endif /* MY_ABC_HERE */ /* * Note: There is significant duplication with __d_lookup_rcu which is @@ -2287,7 +2382,11 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, if (d_unhashed(dentry)) continue; +#ifdef MY_ABC_HERE + if (likely(parent->d_flags & (DCACHE_OP_COMPARE | DCACHE_OP_COMPARE_CASE))) { +#else /* MY_ABC_HERE */ if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) { +#endif /* MY_ABC_HERE */ int tlen; const char *tname; if (dentry->d_name.hash != hashlen_hash(hashlen)) @@ -2299,6 +2398,33 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, cpu_relax(); goto seqretry; } +#ifdef MY_ABC_HERE + if (likely(parent->d_flags & DCACHE_OP_COMPARE_CASE)) { + if (parent->d_op->d_compare_case(dentry, + tlen, + tname, + name, + caseless) != 0) { + continue; + } else if (caseless && !dentry->d_inode) { + /* inode is null means file not in disk. + * we return the negative dentry which is case sensitive. + */ + if (parent->d_op->d_compare_case(dentry, + tlen, + tname, + name, + 0) != 0) { + continue; + } + if (!found) { + *seqp = seq; + found = dentry; + } + continue; + } + } else +#endif /* MY_ABC_HERE */ if (parent->d_op->d_compare(dentry, tlen, tname, name) != 0) continue; @@ -2311,7 +2437,11 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, *seqp = seq; return dentry; } +#ifdef MY_ABC_HERE + return found; +#else /* MY_ABC_HERE */ return NULL; +#endif /* MY_ABC_HERE */ } /** @@ -2332,7 +2462,11 @@ struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name) do { seq = read_seqbegin(&rename_lock); +#ifdef MY_ABC_HERE + dentry = __d_lookup(parent, name, 0); +#else /* MY_ABC_HERE */ dentry = __d_lookup(parent, name); +#endif /* MY_ABC_HERE */ if (dentry) break; } while (read_seqretry(&rename_lock, seq)); @@ -2355,13 +2489,20 @@ EXPORT_SYMBOL(d_lookup); * * __d_lookup callers must be commented. */ -struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) +struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name +#ifdef MY_ABC_HERE + , const int caseless +#endif /* MY_ABC_HERE */ + ) { unsigned int hash = name->hash; struct hlist_bl_head *b = d_hash(hash); struct hlist_bl_node *node; struct dentry *found = NULL; struct dentry *dentry; +#ifdef MY_ABC_HERE + struct dentry *negative_dentry = NULL; +#endif /* MY_ABC_HERE */ /* * Note: There is significant duplication with __d_lookup_rcu which is @@ -2396,16 +2537,51 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) if (d_unhashed(dentry)) goto next; +#ifdef MY_ABC_HERE + if (!d_same_name(dentry, parent, name, caseless)) +#else /* MY_ABC_HERE */ if (!d_same_name(dentry, parent, name)) +#endif /* MY_ABC_HERE */ goto next; +#ifdef MY_ABC_HERE + if (likely(parent->d_flags & DCACHE_OP_COMPARE_CASE) + && caseless + && !dentry->d_inode) { + /* + * inode is null means file not in disk. + * we only return the negative dentry which is case sensitive. + */ + if (!d_same_name(dentry, parent, name, 0)) { + goto next; + } + if (!negative_dentry) { + dentry->d_lockref.count++; + negative_dentry = dentry; + } + goto next; + } +#endif /* MY_ABC_HERE */ + dentry->d_lockref.count++; found = dentry; spin_unlock(&dentry->d_lock); +#ifdef MY_ABC_HERE + if (negative_dentry) { + spin_lock(&negative_dentry->d_lock); + negative_dentry->d_lockref.count--; + spin_unlock(&negative_dentry->d_lock); + negative_dentry = NULL; + } +#endif /* MY_ABC_HERE */ break; next: spin_unlock(&dentry->d_lock); } +#ifdef MY_ABC_HERE + if (!found && negative_dentry) + found = negative_dentry; +#endif /* MY_ABC_HERE */ rcu_read_unlock(); return found; @@ -2530,9 +2706,16 @@ static void d_wait_lookup(struct dentry *dentry) } } +#ifdef MY_ABC_HERE +struct dentry *__d_alloc_parallel(struct dentry *parent, + const struct qstr *name, + wait_queue_head_t *wq, + const int caseless) +#else /* MY_ABC_HERE */ struct dentry *d_alloc_parallel(struct dentry *parent, const struct qstr *name, wait_queue_head_t *wq) +#endif /* MY_ABC_HERE */ { unsigned int hash = name->hash; struct hlist_bl_head *b = in_lookup_hash(parent, hash); @@ -2548,7 +2731,11 @@ struct dentry *d_alloc_parallel(struct dentry *parent, rcu_read_lock(); seq = smp_load_acquire(&parent->d_inode->i_dir_seq); r_seq = read_seqbegin(&rename_lock); +#ifdef MY_ABC_HERE + dentry = __d_lookup_rcu(parent, name, &d_seq, caseless); +#else /* MY_ABC_HERE */ dentry = __d_lookup_rcu(parent, name, &d_seq); +#endif /* MY_ABC_HERE */ if (unlikely(dentry)) { if (!lockref_get_not_dead(&dentry->d_lockref)) { rcu_read_unlock(); @@ -2591,7 +2778,11 @@ struct dentry *d_alloc_parallel(struct dentry *parent, continue; if (dentry->d_parent != parent) continue; +#ifdef MY_ABC_HERE + if (!d_same_name(dentry, parent, name, caseless)) +#else /* MY_ABC_HERE */ if (!d_same_name(dentry, parent, name)) +#endif /* MY_ABC_HERE */ continue; hlist_bl_unlock(b); /* now we can try to grab a reference */ @@ -2619,7 +2810,11 @@ struct dentry *d_alloc_parallel(struct dentry *parent, goto mismatch; if (unlikely(d_unhashed(dentry))) goto mismatch; +#ifdef MY_ABC_HERE + if (unlikely(!d_same_name(dentry, parent, name, caseless))) +#else /* MY_ABC_HERE */ if (unlikely(!d_same_name(dentry, parent, name))) +#endif /* MY_ABC_HERE */ goto mismatch; /* OK, it *is* a hashed match; return it */ spin_unlock(&dentry->d_lock); @@ -2638,7 +2833,11 @@ struct dentry *d_alloc_parallel(struct dentry *parent, dput(dentry); goto retry; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(__d_alloc_parallel); +#else /* MY_ABC_HERE */ EXPORT_SYMBOL(d_alloc_parallel); +#endif /* MY_ABC_HERE */ void __d_lookup_done(struct dentry *dentry) { @@ -2729,7 +2928,11 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) continue; if (alias->d_parent != entry->d_parent) continue; +#ifdef MY_ABC_HERE + if (!d_same_name(alias, entry->d_parent, &entry->d_name, 0)) +#else /* MY_ABC_HERE */ if (!d_same_name(alias, entry->d_parent, &entry->d_name)) +#endif /* MY_ABC_HERE */ continue; spin_lock(&alias->d_lock); if (!d_unhashed(alias)) { @@ -2935,6 +3138,9 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) write_sequnlock(&rename_lock); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(d_exchange); +#endif /* MY_ABC_HERE */ /** * d_ancestor - search for an ancestor diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 720d65f224f0..247d94bf908c 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * inode.c - part of debugfs, a tiny little debug file system @@ -755,6 +758,9 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, int error; struct dentry *dentry = NULL, *trap; struct name_snapshot old_name; +#ifdef MY_ABC_HERE + struct synotify_rename_path *rename_path_list = NULL; +#endif /* MY_ABC_HERE */ if (IS_ERR(old_dir)) return old_dir; @@ -776,6 +782,9 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry)) goto exit; +#ifdef MY_ABC_HERE + rename_path_list = get_rename_path_list(old_dentry, dentry); +#endif /* MY_ABC_HERE */ take_dentry_name_snapshot(&old_name, old_dentry); error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir), @@ -787,12 +796,19 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, d_move(old_dentry, dentry); fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name, d_is_dir(old_dentry), - NULL, old_dentry); + NULL, old_dentry +#ifdef MY_ABC_HERE + ,rename_path_list, false +#endif /* MY_ABC_HERE */ + ); release_dentry_name_snapshot(&old_name); unlock_rename(new_dir, old_dir); dput(dentry); return old_dentry; exit: +#ifdef MY_ABC_HERE + free_rename_path_list(rename_path_list); +#endif /* MY_ABC_HERE */ if (dentry && !IS_ERR(dentry)) dput(dentry); unlock_rename(new_dir, old_dir); diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile index 4f2cc5b2542d..59131f02c7d0 100644 --- a/fs/ecryptfs/Makefile +++ b/fs/ecryptfs/Makefile @@ -9,3 +9,5 @@ ecryptfs-y := dentry.o file.o inode.o main.o super.o mmap.o read_write.o \ crypto.o keystore.o kthread.o debug.o ecryptfs-$(CONFIG_ECRYPT_FS_MESSAGING) += messaging.o miscdev.o + +ecryptfs-$(CONFIG_SYNO_ECRYPTFS_EXPORT) += export.o diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index adf0707263a1..ab748f157c93 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -472,6 +475,13 @@ int ecryptfs_encrypt_page(struct page *page) PAGE_SIZE); kunmap(enc_extent_page); if (rc < 0) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR + "Error attempting to write lower page; rc = [%d]\n", + rc); + else +#endif /* MY_ABC_HERE */ ecryptfs_printk(KERN_ERR, "Error attempting to write lower page; rc = [%d]\n", rc); @@ -485,6 +495,64 @@ int ecryptfs_encrypt_page(struct page *page) return rc; } +#ifdef MY_ABC_HERE +static int ecryptfs_encrypt_page_without_write_lower(struct page *enc_page, + void *crypt_stat_ptr, struct page *page) +{ + int rc = 0; + loff_t extent_offset; + struct ecryptfs_crypt_stat *crypt_stat = (struct ecryptfs_crypt_stat *) crypt_stat_ptr; + + for (extent_offset = 0; + extent_offset < (PAGE_SIZE / crypt_stat->extent_size); + extent_offset++) { + rc = crypt_extent(crypt_stat, enc_page, page, + extent_offset, ENCRYPT); + if (rc) { + printk(KERN_ERR "%s: Error encrypting extent; " + "rc = [%d]\n", __func__, rc); + goto out; + } + } + + rc = 0; +out: + return rc; +} + +int ecryptfs_encrypt_page_zero_copy(struct ecryptfs_crypt_stat *crypt_stat, + struct file *file, struct page **pages, int num_page) +{ + loff_t offset; + int rc = 0; + + if (!crypt_stat || !file || !pages) + return -EINVAL; + + BUG_ON(!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)); + offset = lower_offset_for_page(crypt_stat, pages[0]); + rc = file->f_op->ecryptfs_zero_copy(file, offset, num_page, pages, + ecryptfs_encrypt_page_without_write_lower, (void *)crypt_stat); + if (rc) { + printk("ecryptfs_zero_copy failed:%d\n", rc); + rc = -EINVAL; + goto out; + } + rc = 0; +out: + return rc; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline bool all_zeroes(u32 *p, u32 *q) +{ + while (p < q) + if (*p++) + return false; + return true; +} +#endif /* MY_ABC_HERE */ /** * ecryptfs_decrypt_page * @page: Page mapped from the eCryptfs inode for the file; data read @@ -519,7 +587,12 @@ int ecryptfs_decrypt_page(struct page *page) page_virt = kmap(page); rc = ecryptfs_read_lower(page_virt, lower_offset, PAGE_SIZE, ecryptfs_inode); +#ifdef MY_ABC_HERE + if (rc < 0) + kunmap(page); +#else /* MY_ABC_HERE */ kunmap(page); +#endif /* MY_ABC_HERE */ if (rc < 0) { ecryptfs_printk(KERN_ERR, "Error attempting to read lower page; rc = [%d]\n", @@ -527,6 +600,14 @@ int ecryptfs_decrypt_page(struct page *page) goto out; } +#ifdef MY_ABC_HERE + if (all_zeroes((u32 *) page_virt, (u32 *) (page_virt + PAGE_SIZE))) { + rc = 0; + kunmap(page); + goto out; + } + kunmap(page); +#endif /* MY_ABC_HERE */ for (extent_offset = 0; extent_offset < (PAGE_SIZE / crypt_stat->extent_size); extent_offset++) { @@ -1085,10 +1166,18 @@ ecryptfs_write_metadata_to_contents(struct inode *ecryptfs_inode, rc = ecryptfs_write_lower(ecryptfs_inode, virt, 0, virt_len); - if (rc < 0) + if (rc < 0) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR + "%s: Error attempting to write header " + "information to lower file; rc = [%d]\n", + __func__, rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "%s: Error attempting to write header " "information to lower file; rc = [%d]\n", __func__, rc); - else + } else rc = 0; return rc; } @@ -1146,6 +1235,10 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; +#ifdef MY_ABC_HERE + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(ecryptfs_inode->i_sb)->mount_crypt_stat; +#endif /* MY_ABC_HERE */ unsigned int order; char *virt; size_t virt_len; @@ -1181,13 +1274,43 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, __func__, rc); goto out_free; } +#ifdef MY_ABC_HERE + if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED) { + rc = ecryptfs_write_metadata_to_contents(ecryptfs_inode, virt, virt_len); + if (!rc) { + rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, + ecryptfs_inode, + virt, + ECRYPTFS_SIZE_AND_MARKER_BYTES); + if (rc == -EOPNOTSUPP) { + printk(KERN_WARNING + "%s: user xattr not supported, turn off FAST_LOOKUP", + __func__); + mount_crypt_stat->flags &= + ~ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED; + rc = 0; + } + } + goto finish; + } +#endif /* MY_ABC_HERE */ if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, ecryptfs_inode, virt, size); else rc = ecryptfs_write_metadata_to_contents(ecryptfs_inode, virt, virt_len); +#ifdef MY_ABC_HERE +finish: +#endif /* MY_ABC_HERE */ if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR + "%s: Error writing metadata out to lower file; " + "rc = [%d]\n", __func__, rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "%s: Error writing metadata out to lower file; " "rc = [%d]\n", __func__, rc); goto out_free; @@ -1237,7 +1360,11 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; } +#ifdef MY_ABC_HERE +static void __ecryptfs_i_size_init(const char *page_virt, struct inode *inode, int is_fast_lookup) +#else /* MY_ABC_HERE */ void ecryptfs_i_size_init(const char *page_virt, struct inode *inode) +#endif /* MY_ABC_HERE */ { struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; @@ -1253,9 +1380,21 @@ void ecryptfs_i_size_init(const char *page_virt, struct inode *inode) } else file_size = get_unaligned_be64(page_virt); i_size_write(inode, (loff_t)file_size); +#ifdef MY_ABC_HERE + if (!is_fast_lookup) + crypt_stat->flags |= ECRYPTFS_I_SIZE_INITIALIZED; +#else /* MY_ABC_HERE */ crypt_stat->flags |= ECRYPTFS_I_SIZE_INITIALIZED; +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +void ecryptfs_i_size_init(const char *page_virt, struct inode *inode) +{ + __ecryptfs_i_size_init(page_virt, inode, 0); +} +#endif /* MY_ABC_HERE */ + /** * ecryptfs_read_headers_virt * @page_virt: The virtual address into which to read the headers @@ -1353,6 +1492,13 @@ int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry, u8 file_size[ECRYPTFS_SIZE_AND_MARKER_BYTES]; u8 *marker = file_size + ECRYPTFS_FILE_SIZE_BYTES; int rc; +#ifdef MY_ABC_HERE + u64 upper_file_size; + loff_t lower_file_size, lower_file_size_expect; + struct ecryptfs_crypt_stat *crypt_stat; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat; +#endif /* MY_ABC_HERE */ rc = ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), ecryptfs_inode_to_lower(inode), @@ -1363,6 +1509,26 @@ int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry, else if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES) return -EINVAL; rc = ecryptfs_validate_marker(marker); +#ifdef MY_ABC_HERE + if (!rc && (mount_crypt_stat->flags & + ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED)) { + /* + * Lower i_size may be inconsistent with i_size in xattr + * since migration to machine without FAST_LOOKUP feature. + * Fallback to old version if not consistent. + */ + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + lower_file_size = i_size_read(ecryptfs_inode_to_lower(inode)); + upper_file_size = get_unaligned_be64(file_size); + lower_file_size_expect = upper_size_to_lower_size(crypt_stat, + upper_file_size); + if (lower_file_size == lower_file_size_expect) { + __ecryptfs_i_size_init(file_size, inode, 1); + } else { + rc = -EINVAL; + } + } else +#endif /* MY_ABC_HERE */ if (!rc) ecryptfs_i_size_init(file_size, inode); return rc; @@ -1976,16 +2142,6 @@ int ecryptfs_encrypt_and_encode_filename( return rc; } -static bool is_dot_dotdot(const char *name, size_t name_size) -{ - if (name_size == 1 && name[0] == '.') - return true; - else if (name_size == 2 && name[0] == '.' && name[1] == '.') - return true; - - return false; -} - /** * ecryptfs_decode_and_decrypt_filename - converts the encoded cipher text name to decoded plaintext * @plaintext_name: The plaintext name @@ -2010,21 +2166,13 @@ int ecryptfs_decode_and_decrypt_filename(char **plaintext_name, size_t packet_size; int rc = 0; - if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) && - !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)) { - if (is_dot_dotdot(name, name_size)) { - rc = ecryptfs_copy_filename(plaintext_name, - plaintext_name_size, - name, name_size); - goto out; - } - - if (name_size <= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE || - strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, - ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE)) { - rc = -EINVAL; - goto out; - } + if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) + && !(mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + && (name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) + && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX, + ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) { + const char *orig_name = name; + size_t orig_name_size = name_size; name += ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE; name_size -= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE; @@ -2044,9 +2192,12 @@ int ecryptfs_decode_and_decrypt_filename(char **plaintext_name, decoded_name, decoded_name_size); if (rc) { - ecryptfs_printk(KERN_DEBUG, - "%s: Could not parse tag 70 packet from filename\n", - __func__); + printk(KERN_INFO "%s: Could not parse tag 70 packet " + "from filename; copying through filename " + "as-is\n", __func__); + rc = ecryptfs_copy_filename(plaintext_name, + plaintext_name_size, + orig_name, orig_name_size); goto out_free; } } else { diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index e6ac78c62ca4..8e3c18636986 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /** * eCryptfs: Linux filesystem encryption layer @@ -336,6 +339,10 @@ struct ecryptfs_mount_crypt_stat { #define ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK 0x00000020 #define ECRYPTFS_GLOBAL_ENCFN_USE_FEK 0x00000040 #define ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY 0x00000080 + +#ifdef MY_ABC_HERE +#define ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED 0x80000000 +#endif /* MY_ABC_HERE */ u32 flags; struct list_head global_auth_tok_list; struct mutex global_auth_tok_list_mutex; @@ -352,6 +359,9 @@ struct ecryptfs_mount_crypt_stat { struct ecryptfs_sb_info { struct super_block *wsi_sb; struct ecryptfs_mount_crypt_stat mount_crypt_stat; +#ifdef MY_ABC_HERE + struct dentry *dentry; +#endif /* MY_ABC_HERE */ }; /* file private data. */ @@ -521,6 +531,14 @@ ecryptfs_dentry_to_lower_mnt(struct dentry *dentry) return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt; } +#ifdef MY_ABC_HERE +static inline struct vfsmount * +ecryptfs_superblock_to_lower_mnt(struct super_block *sb) +{ + return ecryptfs_dentry_to_lower_mnt(sb->s_root); +} +#endif /* MY_ABC_HERE */ + static inline struct path * ecryptfs_dentry_to_lower_path(struct dentry *dentry) { @@ -540,6 +558,9 @@ extern const struct inode_operations ecryptfs_symlink_iops; extern const struct super_operations ecryptfs_sops; extern const struct dentry_operations ecryptfs_dops; extern const struct address_space_operations ecryptfs_aops; +#ifdef MY_ABC_HERE +extern const struct export_operations ecryptfs_export_ops; +#endif /* MY_ABC_HERE */ extern int ecryptfs_verbosity; extern unsigned int ecryptfs_message_buf_len; extern signed long ecryptfs_message_wait_timeout; @@ -585,6 +606,10 @@ void ecryptfs_destroy_mount_crypt_stat( int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode); int ecryptfs_encrypt_page(struct page *page); +#ifdef MY_ABC_HERE +int ecryptfs_encrypt_page_zero_copy(struct ecryptfs_crypt_stat *crypt_stat, + struct file *file, struct page **pages, int num_page); +#endif /* MY_ABC_HERE */ int ecryptfs_decrypt_page(struct page *page); int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, struct inode *ecryptfs_inode); @@ -716,6 +741,10 @@ int ecryptfs_set_f_namelen(long *namelen, long lower_namelen, struct ecryptfs_mount_crypt_stat *mount_crypt_stat); int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat, loff_t offset); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +loff_t upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, + loff_t upper_size); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ extern const struct xattr_handler *ecryptfs_xattr_handlers[]; diff --git a/fs/ecryptfs/export.c b/fs/ecryptfs/export.c new file mode 100644 index 000000000000..bade8b05d6ab --- /dev/null +++ b/fs/ecryptfs/export.c @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 1997-2004 Erez Zadok + * Copyright (C) 2001-2004 Stony Brook University + * Copyright (C) 2004-2007 International Business Machines Corp. + */ +#include +#include +#include +#include "ecryptfs_kernel.h" + +/* Filehandle flags. Now we only have this one. */ +#define ECRYPTFS_FH_FLAG_CONNECTABLE 0x1 // parent dentry is encoded or not + +struct ecryptfs_decode_ctx { + u8 flags; /* ECRYPTFS_FH_FLAG_* */ + struct dentry *mnt_root; +}; + +struct ecryptfs_fh { + u8 len; /* size of this header + size of fid in byte unit */ + u8 flags; /* ECRYPTFS_FH* */ + u16 reserved; + u32 fid[0]; /* file identifier */ +} __packed; + +#define ECRYPTFS_FH_HEADER_SIZE (offsetof(struct ecryptfs_fh, fid)) + +static int ecryptfs_encode_fh(struct inode *inode, u32 *fid, int *max_dwords, + struct inode *parent) +{ + struct dentry *dentry; + struct ecryptfs_fh *fh = (struct ecryptfs_fh *)fid; + struct inode *lower_inode; + int lower_dwords = *max_dwords - (ECRYPTFS_FH_HEADER_SIZE >> 2); + int type; + + /* + * 'lower_dwords' may be negative if '*max_dword' is zero. + * That is fine, we can just pass 0 to exportfs_encode_fh to get the + * size of fid that we need. + */ + if (lower_dwords < 0) + lower_dwords = 0; + + dentry = d_find_any_alias(inode); + if (dentry) { + type = exportfs_encode_fh(ecryptfs_dentry_to_lower(dentry), + (struct fid *)fh->fid, &lower_dwords, !!parent); + dput(dentry); + goto done; + } + + lower_inode = ecryptfs_inode_to_lower(inode); + if (lower_inode) { + type = exportfs_encode_inode_fh(lower_inode, (struct fid *)fh->fid, + &lower_dwords, NULL); + goto done; + } + + // No dentry and no lower inode, return failure. + return FILEID_INVALID; + +done: + BUILD_BUG_ON(0 != (ECRYPTFS_FH_HEADER_SIZE % 4)); + *max_dwords = lower_dwords + (ECRYPTFS_FH_HEADER_SIZE >> 2); + + if (type < 0 || type == FILEID_INVALID || + WARN_ON_ONCE((*max_dwords << 2) > MAX_HANDLE_SZ)) + return FILEID_INVALID; + + fh->len = *max_dwords << 2; + if (dentry && parent) + fh->flags = ECRYPTFS_FH_FLAG_CONNECTABLE; + else + fh->flags = 0; + + return type; +} + +static int ecryptfs_acceptable(void *ctx, struct dentry *dentry) +{ + struct ecryptfs_decode_ctx *context = (struct ecryptfs_decode_ctx *)ctx; + + if (!d_is_dir(dentry) && + !(context->flags & ECRYPTFS_FH_FLAG_CONNECTABLE)) + return 1; + + if (d_unhashed(dentry)) + return 0; + + /* Check if directory belongs to the layer we are decoding from */ + return is_subdir(dentry, context->mnt_root); +} + +/* Find or instantiate an disconnected ecryptfs dentry from lower_dentry */ +static struct dentry *ecryptfs_obtain_alias(struct super_block *sb, + struct dentry *lower_dentry) +{ + struct dentry *dentry = NULL; + struct inode *inode = NULL; + struct ecryptfs_dentry_info *dentry_info = NULL; + + if (d_is_dir(lower_dentry)) + return ERR_PTR(-EIO); + + inode = ecryptfs_get_inode(d_inode(lower_dentry), sb); + if (IS_ERR(inode)) + return ERR_CAST(inode); + + dentry = d_find_any_alias(inode); + if (dentry) + goto out_iput; + + dentry = d_alloc_anon(inode->i_sb); + if (unlikely(!dentry)) + goto nomem; + + dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, + GFP_KERNEL); + if (unlikely(!dentry_info)) + goto nomem; + + dentry_info->lower_path.dentry = dget(lower_dentry); + dentry_info->lower_path.mnt = + mntget(ecryptfs_superblock_to_lower_mnt(sb)); + ecryptfs_set_dentry_private(dentry, dentry_info); + + return d_instantiate_anon(dentry, inode); + +nomem: + dput(dentry); + dentry = ERR_PTR(-ENOMEM); +out_iput: + iput(inode); + return dentry; +} + +/* Test if data is the lower inode of input inode */ +static int ecryptfs_inode_test(struct inode *inode, void *data) +{ + return ecryptfs_inode_to_lower(inode) == data; +} + +/* Lookup a ecryptfs dentry from cache, whose lower dentry is @lower_dentry */ +static struct dentry *ecryptfs_lookup_dentry(struct super_block *sb, + struct dentry *lower_dentry) +{ + struct dentry *this = NULL; + struct inode *inode = NULL; + struct inode *lower_inode = d_inode(lower_dentry); + + inode = ilookup5(sb, (unsigned long)lower_inode, + ecryptfs_inode_test, lower_inode); + + if (!inode) + return NULL; + + this = d_find_any_alias(inode); + iput(inode); + + return this; +} + +/* Lookup a child ecryptfs dentry whose lower dentry is @lower_dentry */ +static struct dentry *ecryptfs_lookup_one(struct super_block *sb, + struct dentry *connected, + struct dentry *lower_dentry) +{ + struct inode *dir = d_inode(connected); + struct dentry *this = NULL; + struct dentry *lower_parent = NULL; + struct name_snapshot lower_name; + char *decrypt_name = NULL; + size_t name_size; + int err; + + /* + * The dir mutex protects us from racing with rename. + * If the ecryptfs dentry that is above @lower_dentry has been + * moved to a parent that is not under the connected ecryptfs dir, + * we return -ECHILD. + */ + inode_lock_nested(dir, I_MUTEX_PARENT); + lower_parent = dget_parent(lower_dentry); + if (ecryptfs_dentry_to_lower(connected) != lower_parent) { + dput(lower_parent); + inode_unlock(dir); + return ERR_PTR(-ECHILD); + } + + /* + * We need to take a snapshot of 'lower_dentry' name to protect us + * from racing with lower fs rename. + */ + take_dentry_name_snapshot(&lower_name, lower_dentry); + /* decrypt filename */ + err = ecryptfs_decode_and_decrypt_filename(&decrypt_name, &name_size, + sb, lower_name.name.name, + lower_name.name.len); + if (err) { + ecryptfs_printk(KERN_WARNING, + "Error attempting to decode and decrypt filename [%s]; rc = [%d]\n", + lower_name.name.name, err); + goto fail; + } + + /* + * Lookup ecryptfs dentry by decrypted name + * ecryptfs_lookup would encrypt the filename again and it is possible + * to avoid that because we already have the lower filename and lower + * dentry. In this version, we just do lookup_one_len to simplify + * the implementation. + */ + this = lookup_one_len(decrypt_name, connected, name_size); + err = PTR_ERR(this); + if (IS_ERR(this)) { + goto fail; + } else if (!this || !this->d_inode) { + dput(this); + err = -ENOENT; + goto fail; + } else if (ecryptfs_dentry_to_lower(this) != lower_dentry) { + dput(this); + err = -ESTALE; + goto fail; + } + + goto out; + +fail: + pr_warn_ratelimited("ecryptfs: failed to lookup one by lower dentry (%pd2, connected=%pd2, err=%i)\n", + lower_dentry, connected, err); + this = ERR_PTR(err); + +out: + kfree(decrypt_name); + release_dentry_name_snapshot(&lower_name); + dput(lower_parent); + inode_unlock(dir); + return this; +} + +/* + * Lookup a ecryptfs dentry from cache whose lower dentry is + * an ancestor of @lower_dentry. This dentry will be connected. + */ +static struct dentry *ecryptfs_lookup_ancestor(struct super_block *sb, + struct dentry *lower_dentry) +{ + struct dentry *lower_root = ecryptfs_dentry_to_lower(sb->s_root); + struct dentry *lower_next = NULL; + struct dentry *lower_parent = NULL; + struct dentry *ancestor = ERR_PTR(-EIO); + + if (lower_root == lower_dentry) + return dget(sb->s_root); + + lower_next = dget(lower_dentry); + for (;;) { + lower_parent = dget_parent(lower_next); + + ancestor = ecryptfs_lookup_dentry(sb, lower_next); + if (ancestor) + break; + + if (lower_root == lower_parent) { + ancestor = dget(sb->s_root); + break; + } + + if (lower_parent == lower_next) { + /* + * We moved out of ecryptfs root and hit lower fs root. + * This may happen if the dentry has been moved out of + * ecryptfs, so we return ESTALE. + */ + ancestor = ERR_PTR(-ESTALE); + break; + } + + dput(lower_next); + lower_next = lower_parent; + } + + dput(lower_parent); + dput(lower_next); + return ancestor; +} + +/* lookup a connected ecryptfs dentry whose lower dentry is @lower_dentry */ +static struct dentry *ecryptfs_lookup_connected(struct super_block *sb, + struct dentry *lower_dentry) +{ + struct dentry *lower_root = ecryptfs_dentry_to_lower(sb->s_root); + struct dentry *connected = NULL; + int err = 0; + + /* + * Lookup a connected ecryptfs dentry whose lower dentry is + * an ancestor of 'lower_dentry'. + */ + connected = ecryptfs_lookup_ancestor(sb, lower_dentry); + if (IS_ERR_OR_NULL(connected)) + return connected; + + while (!err) { + struct dentry *this = NULL; + struct dentry *lower_next = NULL; + struct dentry *lower_parent = NULL; + struct dentry *lower_connected = + ecryptfs_dentry_to_lower(connected); + + /* found it */ + if (lower_connected == lower_dentry) + break; + + /* find the topmost dentry not yet connected */ + lower_next = dget(lower_dentry); + for (;;) { + lower_parent = dget_parent(lower_next); + + if (lower_connected == lower_parent) + break; + + /* + * If @lower_dentry has been moved out of + * @lower_connected, we will not find @lower_connected + * and hit ecryptfs root. + * In that case, we need to restart connecting. + * This game can go on forever in the worst case. We + * may want to consider taking s_vfs_rename_mutex if + * this happens more than once. + */ + if (lower_parent == lower_root) { + dput(connected); + connected = dget(sb->s_root); + break; + } + + /* + * We moved out of ecryptfs root and hit lower fs root. + * This may happen if the dentry has been moved out of + * ecryptfs, so we return ESTALE. + */ + if (lower_parent == lower_next) { + err = -ESTALE; + break; + } + + dput(lower_next); + lower_next = lower_parent; + } + + if (!err) { + this = ecryptfs_lookup_one(sb, connected, lower_next); + if (IS_ERR(this)) + err = PTR_ERR(this); + + /* + * Lookup child of connected can fail when racing + * with rename. If the ecryptfs dentry that is above + * 'next' has already been moved to a parent that is + * not under the 'connected' dir, we need to restart + * the lookup from the top because we cannot trust that + * 'lower_connected' is still an ancestor of + * 'lower_dentry'. + */ + if (err == -ECHILD) { + this = ecryptfs_lookup_ancestor(sb, lower_dentry); + err = PTR_ERR_OR_ZERO(this); + } + if (!err) { + dput(connected); + connected = this; + } + } + + dput(lower_parent); + dput(lower_next); + } + if (err) + goto fail; + + return connected; + +fail: + pr_warn_ratelimited("ecryptfs: failed to lookup by lower_dentry (%pd2, connected=%pd2, err=%i)\n", + lower_dentry, connected, err); + dput(connected); + return ERR_PTR(err); +} + +static struct dentry *ecryptfs_get_dentry(struct super_block *sb, + struct dentry *lower, + bool connected) +{ + /* Obtain a disconnected dentry. */ + if (!d_is_dir(lower) && !connected) + return ecryptfs_obtain_alias(sb, lower); + + /* Removed empty directory? */ + if ((lower->d_flags & DCACHE_DISCONNECTED) || d_unhashed(lower)) + return ERR_PTR(-ENOENT); + + return ecryptfs_lookup_connected(sb, lower); +} + +static struct dentry *ecryptfs_fh_to_dentry(struct super_block *sb, + struct fid *fid, + int fh_len, + int fh_type) +{ + struct ecryptfs_fh *fh = (struct ecryptfs_fh *)fid; + struct vfsmount *lower_mnt = ecryptfs_superblock_to_lower_mnt(sb); + struct dentry *lower_dentry = NULL; + struct dentry *dentry = NULL; + struct ecryptfs_decode_ctx ctx; + bool connected; + + if (fh_len <= (ECRYPTFS_FH_HEADER_SIZE >> 2) || fh_len != (fh->len >> 2)) + return NULL; + + /* now fh_len is length of lower fh */ + fh_len -= ECRYPTFS_FH_HEADER_SIZE >> 2; + ctx.flags = fh->flags; + ctx.mnt_root = lower_mnt->mnt_root; + + lower_dentry = exportfs_decode_fh(lower_mnt, (struct fid *)fh->fid, + fh_len, fh_type, + ecryptfs_acceptable, &ctx); + + if (IS_ERR_OR_NULL(lower_dentry)) + return lower_dentry; + + connected = !!(fh->flags & ECRYPTFS_FH_FLAG_CONNECTABLE); + + dentry = ecryptfs_get_dentry(sb, lower_dentry, connected); + dput(lower_dentry); + + return dentry; +} + +const struct export_operations ecryptfs_export_ops = { + .encode_fh = ecryptfs_encode_fh, + .fh_to_dentry = ecryptfs_fh_to_dentry, +}; diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 5fb45d865ce5..490080a74164 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -17,6 +20,9 @@ #include #include #include +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#include +#endif /* MY_ABC_HERE || MY_ABC_HERE*/ #include "ecryptfs_kernel.h" /** @@ -68,28 +74,17 @@ ecryptfs_filldir(struct dir_context *ctx, const char *lower_name, buf->sb, lower_name, lower_namelen); if (rc) { - if (rc != -EINVAL) { - ecryptfs_printk(KERN_DEBUG, - "%s: Error attempting to decode and decrypt filename [%s]; rc = [%d]\n", - __func__, lower_name, rc); - return rc; - } - - /* Mask -EINVAL errors as these are most likely due a plaintext - * filename present in the lower filesystem despite filename - * encryption being enabled. One unavoidable example would be - * the "lost+found" dentry in the root directory of an Ext4 - * filesystem. - */ - return 0; + printk(KERN_ERR "%s: Error attempting to decode and decrypt " + "filename [%s]; rc = [%d]\n", __func__, lower_name, + rc); + goto out; } - buf->caller->pos = buf->ctx.pos; rc = !dir_emit(buf->caller, name, name_size, ino, d_type); kfree(name); if (!rc) buf->entries_written++; - +out: return rc; } @@ -343,6 +338,52 @@ static int ecryptfs_fasync(int fd, struct file *file, int flag) return rc; } +#ifdef MY_ABC_HERE +static long ecryptfs_fallocate(struct file *file, int mode, + loff_t offset, loff_t len) +{ + int rc = 0; + loff_t lower_offset = 0; + loff_t lower_len = 0; + loff_t alloc_end = offset + len; + struct inode *inode = file_inode(file); + struct file *lower_file = ecryptfs_file_to_lower(file); + struct ecryptfs_crypt_stat *crypt_stat = NULL; + + if (mode || !lower_file->f_op->fallocate) + return -EOPNOTSUPP; + + inode_lock(inode); + if (alloc_end > i_size_read(inode)) { + rc = ecryptfs_truncate(file->f_path.dentry, alloc_end); + if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "%s: Error on attempt to " + "truncate to (higher) offset [%lld];" + " rc = [%d]\n", __func__, + alloc_end, rc); + else +#endif /* MY_ABC_HERE */ + printk(KERN_ERR "%s: Error on attempt to " + "truncate to (higher) offset [%lld];" + " rc = [%d]\n", __func__, + alloc_end, rc); + goto out; + } + } + + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + lower_offset = ecryptfs_lower_header_size(crypt_stat) + offset; + lower_len = upper_size_to_lower_size(crypt_stat, alloc_end) - lower_offset; + rc = lower_file->f_op->fallocate(lower_file, mode, lower_offset, lower_len); +out: + fsstack_copy_attr_all(inode, file_inode(lower_file)); + inode_unlock(inode); + return rc; +} +#endif /* MY_ABC_HERE */ + static long ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -358,6 +399,31 @@ ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case FS_IOC_SETFLAGS: case FS_IOC_GETVERSION: case FS_IOC_SETVERSION: +#ifdef MY_ABC_HERE + /* + * In our sdk, we'll iterate every share by concatenate share name after + * volume name. In ecryption share case, /volume1/ecrypt rather than + * /volume1/@ecrypt will be passed. Therefore, we need to allow + * BTRFS_IOC_DEFRAG to pass to lower btrfs. + */ + case BTRFS_IOC_DEFRAG: + case BTRFS_IOC_GET_SUBVOL_INFO: +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_USRQUOTA_QUERY: + case BTRFS_IOC_USRQUOTA_CTL: + case BTRFS_IOC_USRQUOTA_LIMIT: + case BTRFS_IOC_USRQUOTA_RESCAN: + case BTRFS_IOC_USRQUOTA_RESCAN_STATUS: + case BTRFS_IOC_USRQUOTA_RESCAN_WAIT: + case BTRFS_IOC_USRQUOTA_CLEAN: +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_QGROUP_QUERY: +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case BTRFS_IOC_COMPR_CTL: +#endif /* MY_ABC_HERE */ rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); fsstack_copy_attr_all(file_inode(file), file_inode(lower_file)); @@ -421,4 +487,7 @@ const struct file_operations ecryptfs_main_fops = { .fsync = ecryptfs_fsync, .fasync = ecryptfs_fasync, .splice_read = generic_file_splice_read, +#ifdef MY_ABC_HERE + .fallocate = ecryptfs_fallocate, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index e23752d9a79f..1e10be3de339 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -20,6 +23,9 @@ #include #include #include "ecryptfs_kernel.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ static struct dentry *lock_parent(struct dentry *dentry) { @@ -182,6 +188,13 @@ ecryptfs_do_create(struct inode *directory_inode, lower_dir_dentry = lock_parent(lower_dentry); rc = vfs_create(d_inode(lower_dir_dentry), lower_dentry, mode, true); if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR + "%s: Failure to create dentry in lower fs; " + "rc = [%d]\n", __func__, rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); inode = ERR_PTR(rc); @@ -236,8 +249,14 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); - if (rc) + if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "Error writing headers; rc = [%d]\n", rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); + } ecryptfs_put_lower_file(ecryptfs_inode); out: return rc; @@ -263,6 +282,12 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); if (IS_ERR(ecryptfs_inode)) { +#ifdef MY_ABC_HERE + if (-EDQUOT == PTR_ERR(ecryptfs_inode) || -ENOSPC == PTR_ERR(ecryptfs_inode)) + printk_once(KERN_WARNING "Failed to create file in" + "lower filesystem\n"); + else +#endif /* MY_ABC_HERE */ ecryptfs_printk(KERN_WARNING, "Failed to create file in" "lower filesystem\n"); rc = PTR_ERR(ecryptfs_inode); @@ -285,6 +310,10 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) { struct ecryptfs_crypt_stat *crypt_stat; +#ifdef MY_ABC_HERE + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(dentry->d_sb)->mount_crypt_stat; +#endif /* MY_ABC_HERE */ int rc; rc = ecryptfs_get_lower_file(dentry, inode); @@ -301,6 +330,23 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); +#ifdef MY_ABC_HERE + if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED) { + rc = ecryptfs_read_and_validate_xattr_region(dentry, inode); + if (rc) { + if (rc == -EOPNOTSUPP) { + printk(KERN_WARNING + "%s: user xattr not supported, turn off FAST_LOOKUP", + __func__); + mount_crypt_stat->flags &= + ~ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED; + } + rc = ecryptfs_read_and_validate_header_region(inode); + } + ecryptfs_put_lower_file(inode); + return 0; + } +#endif /* MY_ABC_HERE */ rc = ecryptfs_read_and_validate_header_region(inode); ecryptfs_put_lower_file(inode); if (rc) { @@ -481,6 +527,13 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, strlen(symname)); if (rc) goto out_lock; +#ifdef MY_ABC_HERE + if (encoded_symlen > PATH_MAX - 1) { + kfree(encoded_symname); + rc = -ENAMETOOLONG; + goto out_lock; + } +#endif /* MY_ABC_HERE */ rc = vfs_symlink(d_inode(lower_dir_dentry), lower_dentry, encoded_symname); kfree(encoded_symname); @@ -578,6 +631,35 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev return rc; } +#ifdef MY_ABC_HERE +static void ecryptfs_copy_archive_bit(struct dentry *ecrypt_entry, struct dentry *lower_entry) +{ + if (ecrypt_entry && ecrypt_entry->d_inode && lower_entry && lower_entry->d_inode) { + mutex_lock(&ecrypt_entry->d_inode->i_archive_bit_mutex); + mutex_lock(&lower_entry->d_inode->i_archive_bit_mutex); + ecrypt_entry->d_inode->i_archive_bit = lower_entry->d_inode->i_archive_bit; + mutex_unlock(&lower_entry->d_inode->i_archive_bit_mutex); + mutex_unlock(&ecrypt_entry->d_inode->i_archive_bit_mutex); + } +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int ecryptfs_syno_set_inode_archive_version(struct dentry *dentry, u32 version) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return syno_op_set_inode_archive_version(lower_dentry, version); +} + +static int ecryptfs_syno_get_inode_archive_version(struct dentry *dentry, u32 *version) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return syno_op_get_inode_archive_version(lower_dentry, version); +} +#endif /* MY_ABC_HERE */ + static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, @@ -622,6 +704,12 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, rc = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry, d_inode(lower_new_dir_dentry), lower_new_dentry, NULL, 0); + +#ifdef MY_ABC_HERE + ecryptfs_copy_archive_bit(old_dentry, lower_old_dentry); + ecryptfs_copy_archive_bit(new_dentry, lower_new_dentry); +#endif /* MY_ABC_HERE */ + if (rc) goto out_lock; if (target_inode) @@ -688,7 +776,11 @@ static const char *ecryptfs_get_link(struct dentry *dentry, * * Returns Calculated size of the lower file. */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +loff_t +#else /* MY_ABC_HERE || MY_ABC_HERE */ static loff_t +#endif /* MY_ABC_HERE || MY_ABC_HERE */ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, loff_t upper_size) { @@ -742,6 +834,11 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat; /* Switch on growing or shrinking file */ if (ia->ia_size > i_size) { +#ifdef MY_ABC_HERE + /* We don't write to lower right now, since it's all zero */ + i_size_write(inode, ia->ia_size); + goto update_size; +#else /* MY_ABC_HERE */ char zero[] = { 0x00 }; lower_ia->ia_valid &= ~ATTR_SIZE; @@ -751,6 +848,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, * file and the new and of the file */ rc = ecryptfs_write(inode, zero, (ia->ia_size - 1), 1); +#endif /* MY_ABC_HERE */ } else { /* ia->ia_size < i_size_read(inode) */ /* We're chopping off all the pages down to the page * in which ia->ia_size is located. Fill in the end of @@ -784,8 +882,18 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, } } truncate_setsize(inode, ia->ia_size); +#ifdef MY_ABC_HERE +update_size: +#endif /* MY_ABC_HERE */ rc = ecryptfs_write_inode_size_to_metadata(inode); if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "Problem with " + "ecryptfs_write_inode_size_to_metadata; " + "rc = [%d]\n", rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "Problem with " "ecryptfs_write_inode_size_to_metadata; " "rc = [%d]\n", rc); @@ -797,7 +905,11 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, upper_size_to_lower_size(crypt_stat, i_size); lower_size_after_truncate = upper_size_to_lower_size(crypt_stat, ia->ia_size); +#ifdef MY_ABC_HERE + if (lower_size_before_truncate != lower_size_after_truncate) { +#else /* MY_ABC_HERE */ if (lower_size_after_truncate < lower_size_before_truncate) { +#endif /* MY_ABC_HERE */ lower_ia->ia_size = lower_size_after_truncate; lower_ia->ia_valid |= ATTR_SIZE; } else @@ -1009,6 +1121,98 @@ static int ecryptfs_getattr(const struct path *path, struct kstat *stat, return rc; } +#ifdef MY_ABC_HERE +static int ecryptfs_syno_getattr(struct dentry *dentry, + struct kstat *stat, unsigned int flags) +{ + return syno_op_getattr(ecryptfs_dentry_to_lower(dentry), stat, flags); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * For some operations(like vfs_create ), it checks 2 times. + * For some operations(like openat() or SYNOACLPermCheck()), it checks only 1 times. + */ +static int +ecryptfs_syno_permission(struct dentry *dentry, int mask) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_permission(lower_dentry, mask); +} + +/* + * Check Only 1 time. + */ +static int +ecryptfs_syno_exec_permission(struct dentry *dentry) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_exec_permission(lower_dentry, d_inode(lower_dentry)); +} + +static int +ecryptfs_syno_may_access(struct dentry *dentry, int mask) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_may_access(lower_dentry, mask); +} + +static int +ecryptfs_syno_acl_xattr_get(struct dentry *dentry, int cmd, + void *value, size_t size) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_acl_xattr_get(lower_dentry, cmd, value, size); +} + +static int +ecryptfs_syno_setattr_prepare(struct dentry *dentry, struct iattr *attr) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_setattr_prepare(lower_dentry, attr); +} + +static int +ecryptfs_syno_archive_bit_change_ok(struct dentry *dentry, + unsigned int cmd, + int tag, int mask) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_archive_bit_change_ok(lower_dentry, cmd, tag, mask); +} + +static int +ecryptfs_syno_setattr_post(struct dentry *dentry, struct iattr *attr) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_setattr_post(lower_dentry, attr); +} + +static void +ecryptfs_syno_acl_to_mode(struct dentry *dentry, struct kstat *stat) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + synoacl_op_to_mode(lower_dentry, stat); +} + +static int +ecryptfs_syno_acl_init(struct dentry *dentry, struct inode *inode) +{ + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + return synoacl_op_init(lower_dentry); +} +#endif /* MY_ABC_HERE */ + int ecryptfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, const void *value, @@ -1055,6 +1259,24 @@ ecryptfs_getxattr(struct dentry *dentry, struct inode *inode, name, value, size); } +#ifdef MY_ABC_HERE +static int ecryptfs_syno_get_crtime(struct inode *inode, struct timespec64 *time) +{ + return syno_op_get_crtime(ecryptfs_inode_to_lower(inode), time); +} + +static int ecryptfs_syno_set_crtime(struct inode *inode, struct timespec64 *time) +{ + int rc = 0; + struct inode *lower_inode = ecryptfs_inode_to_lower(inode); + + rc = syno_op_set_crtime(lower_inode, time); + if (!rc) + fsstack_copy_attr_all(inode, lower_inode); + return rc; +} +#endif /* MY_ABC_HERE */ + static ssize_t ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size) { @@ -1093,12 +1315,50 @@ static int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode, return rc; } +#ifdef MY_ABC_HERE +static int +ecryptfs_syno_set_archive_bit(struct dentry *dentry, unsigned int arbit) +{ + int ret; + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + mutex_lock(&lower_dentry->d_inode->i_archive_bit_mutex); + ret = syno_op_set_archive_bit_nolock(lower_dentry, arbit); + if (!ret) { + dentry->d_inode->i_archive_bit = arbit; + } + mutex_unlock(&lower_dentry->d_inode->i_archive_bit_mutex); + + return ret; +} +#endif /* MY_ABC_HERE */ + const struct inode_operations ecryptfs_symlink_iops = { .get_link = ecryptfs_get_link, .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .getattr = ecryptfs_getattr_link, .listxattr = ecryptfs_listxattr, +#ifdef MY_ABC_HERE + /* .syno_get_archive_bit is not implemented here, + * because i_archive_bit in in-mem i_node will be + * always updated after ecryptfs_syno_set_archive_bit. + * So the default action in syno_op_get_archive_bit() + * is exactly what we need. + */ + .syno_set_archive_bit = ecryptfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ecryptfs_syno_get_inode_archive_version, + .syno_set_archive_version = ecryptfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = ecryptfs_syno_get_crtime, + .syno_set_crtime = ecryptfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_getattr = ecryptfs_syno_getattr, +#endif /* MY_ABC_HERE */ }; const struct inode_operations ecryptfs_dir_iops = { @@ -1114,6 +1374,42 @@ const struct inode_operations ecryptfs_dir_iops = { .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .listxattr = ecryptfs_listxattr, +#ifdef MY_ABC_HERE + /* .syno_get_archive_bit is not implemented here, + * because i_archive_bit in in-mem i_node will be + * always updated after ecryptfs_syno_set_archive_bit. + * So the default action in syno_op_get_archive_bit() + * is exactly what we need. + */ + .syno_set_archive_bit = ecryptfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ecryptfs_syno_get_inode_archive_version, + .syno_set_archive_version = ecryptfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = ecryptfs_syno_get_crtime, + .syno_set_crtime = ecryptfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_getattr = ecryptfs_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_permission = ecryptfs_syno_permission, + .syno_may_access = ecryptfs_syno_may_access, + .syno_acl_xattr_get = ecryptfs_syno_acl_xattr_get, + .syno_exec_permission = ecryptfs_syno_exec_permission, + .syno_setattr_prepare = ecryptfs_syno_setattr_prepare, + .syno_archive_bit_change_ok = ecryptfs_syno_archive_bit_change_ok, + .syno_setattr_post = ecryptfs_syno_setattr_post, + .syno_acl_to_mode = ecryptfs_syno_acl_to_mode, + .syno_acl_init = ecryptfs_syno_acl_init, + /* + * When ecryptfs do rename(), rmdir(), unlink() behaviors, + * it bypass lower dentry into vfs_ops and do may-delete-check. + * So we don't need to implement syno_may_delete operation here. + */ +#endif /* MY_ABC_HERE */ }; const struct inode_operations ecryptfs_main_iops = { @@ -1121,6 +1417,42 @@ const struct inode_operations ecryptfs_main_iops = { .setattr = ecryptfs_setattr, .getattr = ecryptfs_getattr, .listxattr = ecryptfs_listxattr, +#ifdef MY_ABC_HERE + /* .syno_get_archive_bit is not implemented here, + * because i_archive_bit in in-mem i_node will be + * always updated after ecryptfs_syno_set_archive_bit. + * So the default action in syno_op_get_archive_bit() + * is exactly what we need. + */ + .syno_set_archive_bit = ecryptfs_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ecryptfs_syno_get_inode_archive_version, + .syno_set_archive_version = ecryptfs_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = ecryptfs_syno_get_crtime, + .syno_set_crtime = ecryptfs_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_getattr = ecryptfs_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_permission = ecryptfs_syno_permission, + .syno_may_access = ecryptfs_syno_may_access, + .syno_acl_xattr_get = ecryptfs_syno_acl_xattr_get, + .syno_exec_permission = ecryptfs_syno_exec_permission, + .syno_setattr_prepare = ecryptfs_syno_setattr_prepare, + .syno_archive_bit_change_ok = ecryptfs_syno_archive_bit_change_ok, + .syno_setattr_post = ecryptfs_syno_setattr_post, + .syno_acl_to_mode = ecryptfs_syno_acl_to_mode, + .syno_acl_init = ecryptfs_syno_acl_init, + /* + * When ecryptfs do rename(), rmdir(), unlink() behaviors, + * it bypass lower dentry into vfs_ops and do may-delete-check. + * So we don't need to implement syno_may_delete operation here. + */ +#endif /* MY_ABC_HERE */ }; static int ecryptfs_xattr_get(const struct xattr_handler *handler, diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index a7c903cb01a0..b49e17ffe185 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -131,6 +134,9 @@ int ecryptfs_privileged_open(struct file **lower_file, * lower file is fput() when all eCryptfs files for the inode are * released. */ flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR; +#ifdef MY_ABC_HERE + d_inode(lower_dentry)->i_opflags |= IOP_ECRYPTFS_LOWER_INIT; +#endif /* MY_ABC_HERE */ (*lower_file) = dentry_open(&req.path, flags, cred); if (!IS_ERR(*lower_file)) goto out; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index b2f6a1937d23..fddc5da54901 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -161,6 +164,9 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes, ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, ecryptfs_opt_check_dev_ruid, +#ifdef MY_ABC_HERE + ecryptfs_opt_no_fast_lookup, +#endif /* MY_ABC_HERE */ ecryptfs_opt_err }; static const match_table_t tokens = { @@ -178,6 +184,9 @@ static const match_table_t tokens = { {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"}, {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"}, +#ifdef MY_ABC_HERE + {ecryptfs_opt_no_fast_lookup, "no_fast_lookup"}, +#endif /* MY_ABC_HERE */ {ecryptfs_opt_err, NULL} }; @@ -216,6 +225,9 @@ static void ecryptfs_init_mount_crypt_stat( sizeof(struct ecryptfs_mount_crypt_stat)); INIT_LIST_HEAD(&mount_crypt_stat->global_auth_tok_list); mutex_init(&mount_crypt_stat->global_auth_tok_list_mutex); +#ifdef MY_ABC_HERE + mount_crypt_stat->flags |= ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED; +#endif /* MY_ABC_HERE */ mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED; } @@ -375,6 +387,11 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, case ecryptfs_opt_check_dev_ruid: *check_ruid = 1; break; +#ifdef MY_ABC_HERE + case ecryptfs_opt_no_fast_lookup: + mount_crypt_stat->flags &= (~ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED); + break; +#endif /* MY_ABC_HERE */ case ecryptfs_opt_err: default: printk(KERN_WARNING @@ -382,6 +399,14 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, __func__, p); } } +#ifdef MY_ABC_HERE + if (mount_crypt_stat->flags & + (ECRYPTFS_XATTR_METADATA_ENABLED | ECRYPTFS_ENCRYPTED_VIEW_ENABLED)) { + printk(KERN_WARNING + "eCryptfs: disable fast_lookup_feature when enabled xattr-meta or ecrypted-view\n"); + mount_crypt_stat->flags &= (~ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED); + } +#endif /* MY_ABC_HERE */ if (!sig_set) { rc = -EINVAL; ecryptfs_printk(KERN_ERR, "You must supply at least one valid " @@ -463,6 +488,24 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, return rc; } +#ifdef MY_ABC_HERE +static int ecryptfs_test_super(struct super_block *s, void *data) +{ + const struct ecryptfs_sb_info *p = data; + const struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(s); + + return sb_info->dentry == p->dentry; +} + +static int ecryptfs_set_super(struct super_block *s, void *data) +{ + int err = set_anon_super(s, data); + if (!err) + ecryptfs_set_superblock_private(s, (struct ecryptfs_sb_info *)data); + return err; +} +#endif /* MY_ABC_HERE */ + struct kmem_cache *ecryptfs_sb_info_cache; static struct file_system_type ecryptfs_fs_type; @@ -498,22 +541,59 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags goto out; } +#ifdef MY_ABC_HERE + rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + if (rc) { + ecryptfs_printk(KERN_WARNING, "kern_path() failed\n"); + goto out; + } + + sbi->dentry = path.dentry; + s = sget(fs_type, ecryptfs_test_super, ecryptfs_set_super, flags, sbi); + if (IS_ERR(s)) { + rc = PTR_ERR(s); + goto out1; + } + + if (s->s_root) { + kmem_cache_free(ecryptfs_sb_info_cache, sbi); + path_put(&path); + return dget(s->s_root); + } + +#endif /* MY_ABC_HERE */ + rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid); if (rc) { err = "Error parsing options"; +#ifdef MY_ABC_HERE + goto out_free; +#else /* MY_ABC_HERE */ goto out; +#endif /* MY_ABC_HERE */ } mount_crypt_stat = &sbi->mount_crypt_stat; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ s = sget(fs_type, NULL, set_anon_super, flags, NULL); if (IS_ERR(s)) { rc = PTR_ERR(s); goto out; } +#endif /* MY_ABC_HERE */ rc = super_setup_bdi(s); if (rc) +#ifdef MY_ABC_HERE + goto out_free; +#else /* MY_ABC_HERE */ goto out1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + s->s_bdi->ra_pages = 0; + s->s_bdi->io_pages = 0; +#endif /* MY_ABC_HERE */ ecryptfs_set_superblock_private(s, sbi); @@ -522,13 +602,19 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_op = &ecryptfs_sops; s->s_xattr = ecryptfs_xattr_handlers; s->s_d_op = &ecryptfs_dops; +#ifdef MY_ABC_HERE + s->s_export_op = &ecryptfs_export_ops; +#endif /* MY_ABC_HERE */ err = "Reading sb failed"; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); if (rc) { ecryptfs_printk(KERN_WARNING, "kern_path() failed\n"); goto out1; } +#endif /* MY_ABC_HERE */ if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { rc = -EINVAL; printk(KERN_ERR "Mount on filesystem of type " @@ -555,6 +641,11 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_flags = flags & ~SB_POSIXACL; s->s_flags |= path.dentry->d_sb->s_flags & SB_POSIXACL; +#ifdef MY_ABC_HERE + if (IS_FS_SYNOACL(d_inode(path.dentry))) + s->s_flags |= SB_SYNOACL; +#endif /* MY_ABC_HERE */ + /** * Force a read-only eCryptfs mount when: * 1) The lower mount is ro @@ -597,10 +688,17 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_flags |= SB_ACTIVE; return dget(s->s_root); +#ifdef MY_ABC_HERE +out_free: + deactivate_locked_super(s); +out1: + path_put(&path); +#else /* MY_ABC_HERE */ out_free: path_put(&path); out1: deactivate_locked_super(s); +#endif /* MY_ABC_HERE */ out: if (sbi) { ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat); diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 019572c6b39a..caa125aa7f9a 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -54,6 +57,13 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) rc = ecryptfs_encrypt_page(page); if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_WARNING "Error encrypting " + "page (upper index [0x%.16lx])\n", + page->index); + else +#endif /* MY_ABC_HERE */ ecryptfs_printk(KERN_WARNING, "Error encrypting " "page (upper index [0x%.16lx])\n", page->index); ClearPageUptodate(page); @@ -341,11 +351,23 @@ static int ecryptfs_write_begin(struct file *file, } /* If creating a page or more of holes, zero them out via truncate. * Note, this will increase i_size. */ +#ifdef MY_ABC_HERE + if (index != 0 && !(AOP_FLAG_RECVFILE_ECRYPTFS_NO_TRUNCATE & flags)) { +#else /* MY_ABC_HERE */ if (index != 0) { +#endif /* MY_ABC_HERE */ if (prev_page_end_size > i_size_read(page->mapping->host)) { rc = ecryptfs_truncate(file->f_path.dentry, prev_page_end_size); if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "%s: Error on attempt to " + "truncate to (higher) offset [%lld];" + " rc = [%d]\n", __func__, + prev_page_end_size, rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "%s: Error on attempt to " "truncate to (higher) offset [%lld];" " rc = [%d]\n", __func__, @@ -379,7 +401,16 @@ static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode) { char *file_size_virt; int rc; +#ifdef MY_ABC_HERE + u8 file_size[ECRYPTFS_FILE_SIZE_BYTES]; + rc = ecryptfs_read_lower(file_size, 0, ECRYPTFS_FILE_SIZE_BYTES, ecryptfs_inode); + if (rc == ECRYPTFS_FILE_SIZE_BYTES && + get_unaligned_be64(file_size) == i_size_read(ecryptfs_inode)) { + rc = 0; + goto out; + } +#endif /* MY_ABC_HERE */ file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL); if (!file_size_virt) { rc = -ENOMEM; @@ -389,10 +420,17 @@ static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode) rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0, sizeof(u64)); kfree(file_size_virt); - if (rc < 0) + if (rc < 0) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR + "%s: Error writing file size to header; " + "rc = [%d]\n", __func__, rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "%s: Error writing file size to header; " "rc = [%d]\n", __func__, rc); - else + } else rc = 0; out: return rc; @@ -425,6 +463,14 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode) xattr_virt, PAGE_SIZE); if (size < 0) size = 8; +#ifdef MY_ABC_HERE + else if (size >= ECRYPTFS_FILE_SIZE_BYTES && + get_unaligned_be64(xattr_virt) == i_size_read(ecryptfs_inode)) { + inode_unlock(lower_inode); + kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); + return 0; + } +#endif /* MY_ABC_HERE */ put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt); rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME, xattr_virt, size, 0); @@ -440,9 +486,27 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode) int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat; +#ifdef MY_ABC_HERE + int rc = -1; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(ecryptfs_inode->i_sb)->mount_crypt_stat; +#endif /* MY_ABC_HERE */ crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; BUG_ON(!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)); +#ifdef MY_ABC_HERE + if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED) { + rc = ecryptfs_write_inode_size_to_xattr(ecryptfs_inode); + if (rc == -EOPNOTSUPP) { + printk(KERN_WARNING + "%s: user xattr not supported, turn off FAST_LOOKUP", + __func__); + mount_crypt_stat->flags &= + ~ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED; + } + return ecryptfs_write_inode_size_to_header(ecryptfs_inode); + } +#endif /* MY_ABC_HERE */ if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode); else @@ -500,6 +564,12 @@ static int ecryptfs_write_end(struct file *file, } rc = ecryptfs_encrypt_page(page); if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_WARNING "Error encrypting page (upper " + "index [0x%.16lx])\n", index); + else +#endif /* MY_ABC_HERE */ ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " "index [0x%.16lx])\n", index); goto out; @@ -510,11 +580,24 @@ static int ecryptfs_write_end(struct file *file, "[0x%.16llx]\n", (unsigned long long)i_size_read(ecryptfs_inode)); } +#ifdef MY_ABC_HERE + else { + rc = copied; + goto out; + } +#endif /* MY_ABC_HERE */ + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); - if (rc) + if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "Error writing inode size to metadata; " "rc = [%d]\n", rc); - else + } else rc = copied; out: unlock_page(page); @@ -522,6 +605,114 @@ static int ecryptfs_write_end(struct file *file, return rc; } +#ifdef MY_ABC_HERE +static int ecryptfs_aggregate_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page **pages, unsigned page_num) +{ + pgoff_t index = pos >> PAGE_SHIFT; + unsigned from = pos & (PAGE_SIZE - 1); + unsigned to = from + copied; + struct inode *ecryptfs_inode = mapping->host; + struct ecryptfs_crypt_stat *crypt_stat = + &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; + int rc = 0, i; +#ifdef MY_ABC_HERE + struct file *lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file; +#endif /* MY_ABC_HERE */ + + ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" + "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); + if (!page_num) + goto out; + if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { + for (i = 0; i < page_num; i++) { + rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, pages[i], 0, + PAGE_SIZE); + if (!rc) + fsstack_copy_inode_size(ecryptfs_inode, + ecryptfs_inode_to_lower(ecryptfs_inode)); + else + break; + } + if (!rc) + rc = copied; + goto out; + } + for (i = 0; i < page_num; i++) { + if (!PageUptodate(pages[i])) { + if (i == 0 && copied < PAGE_SIZE) { + rc = 0; + goto out; + } + SetPageUptodate(pages[i]); + } + } + if (to % PAGE_SIZE) + fill_zeros_to_end_of_page(pages[page_num - 1], to); + +#ifdef MY_ABC_HERE + if (lower_file->f_op->ecryptfs_zero_copy) { + rc = ecryptfs_encrypt_page_zero_copy(crypt_stat, lower_file, pages, page_num); + if (!rc) + goto encrypt_page_done; + } +#endif /* MY_ABC_HERE */ + + for (i = 0;i < page_num;i++) { + rc = ecryptfs_encrypt_page(pages[i]); + if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT != rc && -ENOSPC != rc) + printk_once(KERN_WARNING "Error encrypting page (upper " + "index [0x%.16lx])\n", index); + else +#endif /* MY_ABC_HERE */ + ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " + "index [0x%.16lx])\n", index); + goto out; + } + } + +#ifdef MY_ABC_HERE +encrypt_page_done: +#endif /* MY_ABC_HERE */ + + if (pos + copied > i_size_read(ecryptfs_inode)) { + i_size_write(ecryptfs_inode, pos + copied); + ecryptfs_printk(KERN_DEBUG, "Expanded file size to " + "[0x%.16llx]\n", + (unsigned long long)i_size_read(ecryptfs_inode)); + } +#ifdef MY_ABC_HERE + else { + rc = copied; + goto out; + } +#endif /* MY_ABC_HERE */ + + rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); + else +#endif /* MY_ABC_HERE */ + if (rc) + printk(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); + else + rc = copied; +out: + for (i = 0; i < page_num; i++) { + unlock_page(pages[i]); + put_page(pages[i]); + } + return rc; +} +#endif /* MY_ABC_HERE */ + static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) { struct inode *lower_inode = ecryptfs_inode_to_lower(mapping->host); @@ -538,4 +729,7 @@ const struct address_space_operations ecryptfs_aops = { .write_begin = ecryptfs_write_begin, .write_end = ecryptfs_write_end, .bmap = ecryptfs_bmap, +#ifdef MY_ABC_HERE + .aggregate_write_end = ecryptfs_aggregate_write_end, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index 0438997ac9d8..8f13b921ee2a 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -176,6 +179,12 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset, data_offset); put_page(ecryptfs_page); if (rc) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc || -ENOSPC == rc) + printk_once(KERN_ERR "%s: Error encrypting " + "page; rc = [%d]\n", __func__, rc); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "%s: Error encrypting " "page; rc = [%d]\n", __func__, rc); goto out; @@ -190,6 +199,13 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset, rc2 = ecryptfs_write_inode_size_to_metadata( ecryptfs_inode); if (rc2) { +#ifdef MY_ABC_HERE + if (-EDQUOT == rc2 || -ENOSPC == rc2) + printk_once(KERN_ERR "Problem with " + "ecryptfs_write_inode_size_to_metadata; " + "rc = [%d]\n", rc2); + else +#endif /* MY_ABC_HERE */ printk(KERN_ERR "Problem with " "ecryptfs_write_inode_size_to_metadata; " "rc = [%d]\n", rc2); diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 6b1853f1c06a..4d9d78f2f8f5 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /** * eCryptfs: Linux filesystem encryption layer @@ -163,10 +166,30 @@ static int ecryptfs_show_options(struct seq_file *m, struct dentry *root) seq_printf(m, ",ecryptfs_unlink_sigs"); if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY) seq_printf(m, ",ecryptfs_mount_auth_tok_only"); +#ifdef MY_ABC_HERE + if (!(mount_crypt_stat->flags & ECRYPTFS_GLOBAL_FAST_LOOKUP_ENABLED)) + seq_printf(m, ",no_fast_lookup"); +#endif /* MY_ABC_HERE */ return 0; } +#ifdef MY_ABC_HERE +static int ecryptfs_syno_get_sb_archive_version(struct super_block *sb, u32 *version) +{ + struct super_block *lower_sb = ecryptfs_superblock_to_lower(sb); + + return syno_op_get_sb_archive_version(lower_sb, version); +} + +static int ecryptfs_syno_set_sb_archive_version(struct super_block *sb, u32 version) +{ + struct super_block *lower_sb = ecryptfs_superblock_to_lower(sb); + + return syno_op_set_sb_archive_version(lower_sb, version); +} +#endif /* MY_ABC_HERE */ + const struct super_operations ecryptfs_sops = { .alloc_inode = ecryptfs_alloc_inode, .destroy_inode = ecryptfs_destroy_inode, @@ -174,5 +197,12 @@ const struct super_operations ecryptfs_sops = { .statfs = ecryptfs_statfs, .remount_fs = NULL, .evict_inode = ecryptfs_evict_inode, +#ifdef MY_ABC_HERE + .syno_decrypt_filename = ecryptfs_decode_and_decrypt_filename, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_sb_archive_version = ecryptfs_syno_get_sb_archive_version, + .syno_set_sb_archive_version = ecryptfs_syno_set_sb_archive_version, +#endif /* MY_ABC_HERE */ .show_options = ecryptfs_show_options }; diff --git a/fs/exec.c b/fs/exec.c index c7a4ef8df305..e0e126b749c5 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/exec.c @@ -113,6 +116,9 @@ bool path_noexec(const struct path *path) return (path->mnt->mnt_flags & MNT_NOEXEC) || (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(path_noexec); +#endif /* MY_ABC_HERE */ #ifdef CONFIG_USELIB /* @@ -1347,10 +1353,6 @@ int begin_new_exec(struct linux_binprm * bprm) WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1); flush_signal_handlers(me, 0); - retval = set_cred_ucounts(bprm->cred); - if (retval < 0) - goto out_unlock; - /* * install the new credentials for this executable */ diff --git a/fs/exfat/Kconfig b/fs/exfat/Kconfig index 5a65071b5ecf..e9841704f743 100644 --- a/fs/exfat/Kconfig +++ b/fs/exfat/Kconfig @@ -10,13 +10,31 @@ config EXFAT_FS To compile this as a module, choose M here: the module will be called exfat. +if EXFAT_FS + config EXFAT_DEFAULT_IOCHARSET string "Default iocharset for exFAT" default "utf8" - depends on EXFAT_FS help Set this to the default input/output character set to use for converting between the encoding that is used for user visible filenames and the UTF-16 character encoding that the exFAT filesystem uses. This can be overridden with the "iocharset" mount option for the exFAT filesystems. + +config EXFAT_VIRTUAL_XATTR + bool "Virtual xattr support for exFAT" + default y + help + To support virtual xattr. + +config EXFAT_VIRTUAL_XATTR_SELINUX_LABEL + string "Default string for SELinux label" + default "u:object_r:exfat:s0" + depends on EXFAT_VIRTUAL_XATTR + help + Set this to the default string for SELinux label. + Support for "u:object_r:exfat:s0" was added in Android Pie, + if you're running Oreo or lower, use "u:object_r:vfat:s0" instead. + +endif # if EXFAT_FS diff --git a/fs/exfat/LICENSE b/fs/exfat/LICENSE new file mode 100644 index 000000000000..ff0812fd89cc --- /dev/null +++ b/fs/exfat/LICENSE @@ -0,0 +1,359 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0+ +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + or + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/fs/exfat/Makefile b/fs/exfat/Makefile index ed51926a4971..d181e1ddc5b6 100644 --- a/fs/exfat/Makefile +++ b/fs/exfat/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_EXFAT_FS) += exfat.o exfat-y := inode.o namei.o dir.o super.o fatent.o cache.o nls.o misc.o \ - file.o balloc.o + file.o balloc.o xattr.o diff --git a/fs/exfat/README.md b/fs/exfat/README.md new file mode 100644 index 000000000000..d1f44c532306 --- /dev/null +++ b/fs/exfat/README.md @@ -0,0 +1,184 @@ +# exfat-linux + +This __exFAT filesystem module for Linux kernel__ is a backport of the latest Linux mainline's exFAT drivers by Samsung. + +This project can be used for everyday Linux users by simply doing `make && make install`. Ubuntu users can simply add a PPA and start using it, without even downloading the code. This can also be directly dropped-in to an existing Linux kernel source for building the filesystem drivers inline, which should be useful for Android kernel developers. + +**exfat-linux** has been tested with all major LTS kernels ranging from v4.9 to v5.4 and the ones Canonical uses for Ubuntu: `v4.9`, `v4.14`, `v4.19`, `v5.4` and `v4.15`, `v5.3`, and `v5.6`. + +It's also been tested with `x86(i386)`, `x86_64(amd64)`, `arm32(AArch32)` and `arm64(AArch64)`. + +Linux kernels since `v5.4` includes an exFAT driver, but it is an extremely outdated version from 2016. This was later revised by Samsung directly with `v5.7`. + +People on `v5.7` kernel or higher can just use the bundled exFAT drivers. + +People on `v5.4+` are highly recommended to use this drivers. + +Support for kernel versions lower than `v4.9` were dropped for easier maintenance. For people interested in exFAT support for said kernels, please use the [old branch](https://github.com/arter97/exfat-linux/tree/old). It still works nicely and it's actively being shipped to production smartphones. + +exfat-linux is planned to be maintained until Android devices with `v5.7+` LTS kernel become more common. + +## Disclaimer + +#### â— Original authorship and copyright: Samsung + +#### â— Maintainer of exfat-linux: Park Ju Hyung([arter97](https://twitter.com/arter97)) + +## Using exfat-linux + +### â— Ubuntu PPA + +If you're an Ubuntu user, you can simply add a [PPA repository](https://launchpad.net/~arter97/+archive/ubuntu/exfat-linux) and start using the exFAT module. + +Ubuntu will handle upgrades automatically as well. + +1. Add the exfat-linux repository + + ``` + sudo add-apt-repository ppa:arter97/exfat-linux + sudo apt update + ``` + +2. Install the module + + `sudo apt install exfat-dkms` + +This will use DKMS(Dynamic Kernel Module Support) and automatically build exFAT module for your current Ubuntu installation. + +### â— Manually installing the module + +1. Download the code + + ``` + git clone https://github.com/arter97/exfat-linux + cd exfat-linux + ``` + +2. Build + + `make` + +3. Install + + `sudo make install` + +This will install the module to your __currently running kernel__. + +__If you're running a `v5.4+` kernel, it is highly recommended to reboot at this point to prevent the existing staging exFAT drivers to load.__ + +4. And finally load + + `sudo modprobe exfat` + +If you upgrade the kernel, you'll have to repeat this process. + +If you want to update **exfat-linux** to the latest version, you'll have to repeat this process. + +### â— Merging the drivers to existing Linux kernel source + +If you're using `git`, using `git subtree` or `git submodule` is highly recommended. + +1. Add this repository to `fs/exfat` + +2. Modify `fs/Kconfig` + +``` + menu "DOS/FAT/NT Filesystems" + + source "fs/fat/Kconfig" ++source "fs/exfat/Kconfig" + source "fs/ntfs/Kconfig" + endmenu +``` + +3. Modify `fs/Makefile` + +``` + obj-$(CONFIG_FAT_FS) += fat/ ++obj-$(CONFIG_EXFAT_FS) += exfat/ + obj-$(CONFIG_BFS_FS) += bfs/ +``` + +And you're good to go! + +## Benchmarks + +For reference, existing exFAT implementations were tested and compared on a server running Ubuntu 16.04 with Linux kernel 4.14 under a contained virtual machine. + +Linux 4.14 was used as higher LTS kernels don't work with [exfat-nofuse] at the time of testing. + +__The new base backported from mainline is not benchmarked yet.__ + +### â— Ramdisk + +#### fio sequential I/O + +| Implementation | Base | Read | Write | +| --------------- | ------ | ------------ | ------------ | +| **exfat-linux** | 2.2.0 | 7042 MB/s | 2173 MB/s | +| [exfat-nofuse] | 1.2.9 | 6849 MB/s | 1961 MB/s | +| [exfat-fuse] | N/A | 3097 MB/s | 1710 MB/s | +| ext4 | N/A | 7352 MB/s | 3333 MB/s | + +#### fio random I/O + +| Implementation | Base | Read | Write | +| --------------- | ------ | ------------ | ------------ | +| **exfat-linux** | 2.2.0 | 760 MB/s | 2222 MB/s | +| [exfat-nofuse] | 1.2.9 | 760 MB/s | 2160 MB/s | +| [exfat-fuse] | N/A | 1.7 MB/s | 1.6 MB/s | +| ext4 | N/A | 747 MB/s | 2816 MB/s | + +### â— NVMe device + +#### fio sequential I/O + +| Implementation | Base | Read | Write | +| --------------- | ------ | ------------ | ------------ | +| **exfat-linux** | 2.2.0 | 1283 MB/s | 1832 MB/s | +| [exfat-nofuse] | 1.2.9 | 1285 MB/s | 1678 MB/s | +| [exfat-fuse] | N/A | 751 MB/s | 1464 MB/s | +| ext4 | N/A | 1283 MB/s | 3356 MB/s | + +#### fio random I/O + +| Implementation | Base | Read | Write | +| --------------- | ------ | ------------ | ------------ | +| **exfat-linux** | 2.2.0 | 26 MB/s | 1885 MB/s | +| [exfat-nofuse] | 1.2.9 | 24 MB/s | 1827 MB/s | +| [exfat-fuse] | N/A | 1.6 MB/s | 1.6 MB/s | +| ext4 | N/A | 29 MB/s | 2821 MB/s | + +[exfat-fuse]: https://github.com/relan/exfat + +## Mount options + +* uid +* gid +* umask +* dmask +* fmask +* allow_utime +* iocharset +* quiet +* time_offset + + * Please refer to the [vfat](https://github.com/torvalds/linux/blob/master/Documentation/filesystems/vfat.txt)'s documentation. + +* errors=continue + + * Keep going on a filesystem error. + +* errors=panic + + * Panic and halt the machine if an error occurs. + +* errors=remount-ro + + * Remount the filesystem read-only on an error. + +* discard + + * Enable the use of discard/TRIM commands to ensure flash storage doesn't run out of free blocks. This option may introduce latency penalty on file removal operations. + +## Enjoy! diff --git a/fs/exfat/SynoBuildConf/build b/fs/exfat/SynoBuildConf/build new file mode 100644 index 000000000000..b1f7804cf4f0 --- /dev/null +++ b/fs/exfat/SynoBuildConf/build @@ -0,0 +1,18 @@ +#!/bin/bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +. ${ScriptsDir}/include/exports + +case "${MakeClean}" in + [Yy][Ee][Ss]) + make $MAKE_FLAGS KDIR="$KDIR" clean + ;; +esac + +case "${CleanOnly}" in + [Yy][Ee][Ss]) + return + ;; +esac + +make $MAKE_FLAGS KDIR="$KDIR" diff --git a/fs/exfat/SynoBuildConf/depends b/fs/exfat/SynoBuildConf/depends new file mode 100644 index 000000000000..c8652ccb865a --- /dev/null +++ b/fs/exfat/SynoBuildConf/depends @@ -0,0 +1,2 @@ +[BuildDependent-Tag] +${Kernel} diff --git a/fs/exfat/SynoBuildConf/install b/fs/exfat/SynoBuildConf/install new file mode 100644 index 000000000000..7ccf1d4cf1a3 --- /dev/null +++ b/fs/exfat/SynoBuildConf/install @@ -0,0 +1,10 @@ +#!/bin/bash +# Copyright (c) 2000-2020 Synology Inc. All rights reserved. + +. ${ScriptsDir}/include/exports + +make install InstallPath="$TmpInstDir/lib/modules" + +if [ "x$NOSTRIP" != "xNOSTRIP" ]; then + $STRIP --strip-debug ${TmpInstDir}/lib/modules/exfat.ko +fi diff --git a/fs/exfat/SynoBuildConf/shellcheck b/fs/exfat/SynoBuildConf/shellcheck new file mode 100644 index 000000000000..bf0509ea76f2 --- /dev/null +++ b/fs/exfat/SynoBuildConf/shellcheck @@ -0,0 +1 @@ +dsm: diff --git a/fs/exfat/SynoBuildConf/version b/fs/exfat/SynoBuildConf/version new file mode 100644 index 000000000000..40409097d8de --- /dev/null +++ b/fs/exfat/SynoBuildConf/version @@ -0,0 +1,3 @@ +BASE_VER="`grep -m1 EXFAT_BASE_VERSION version.h | cut -d'"' -f2`" +EXTRA_VER="`grep -m1 EXFAT_EXTRAVERSION version.h | cut -d'"' -f2`" +echo "${BASE_VER}-${EXTRA_VER}" diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index 579c10f57c2b..5743112c0677 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. @@ -7,7 +10,6 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" static const unsigned char free_bit[] = { @@ -69,8 +71,12 @@ static int exfat_allocate_bitmap(struct super_block *sb, } sbi->map_sectors = ((need_map_size - 1) >> (sb->s_blocksize_bits)) + 1; +#ifdef MY_ABC_HERE + sbi->vol_amap = kvmalloc(sbi->map_sectors * sizeof(struct buffer_head *), GFP_KERNEL); +#else sbi->vol_amap = kmalloc_array(sbi->map_sectors, sizeof(struct buffer_head *), GFP_KERNEL); +#endif /* MY_ABC_HERE */ if (!sbi->vol_amap) return -ENOMEM; @@ -84,7 +90,11 @@ static int exfat_allocate_bitmap(struct super_block *sb, while (j < i) brelse(sbi->vol_amap[j++]); +#ifdef MY_ABC_HERE + kvfree(sbi->vol_amap); +#else kfree(sbi->vol_amap); +#endif /* MY_ABC_HERE */ sbi->vol_amap = NULL; return -EIO; } @@ -138,9 +148,17 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi) for (i = 0; i < sbi->map_sectors; i++) __brelse(sbi->vol_amap[i]); +#ifdef MY_ABC_HERE + kvfree(sbi->vol_amap); +#else kfree(sbi->vol_amap); +#endif /* MY_ABC_HERE */ } +/* + * If the value of "clu" is 0, it means cluster 2 which is the first cluster of + * the cluster heap. + */ int exfat_set_bitmap(struct inode *inode, unsigned int clu) { int i, b; @@ -153,11 +171,19 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu) i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) set_bit_le(b, sbi->vol_amap[i]->b_data); +#else + test_and_set_bit_le(b, sbi->vol_amap[i]->b_data); +#endif exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); return 0; } +/* + * If the value of "clu" is 0, it means cluster 2 which is the first cluster of + * the cluster heap. + */ void exfat_clear_bitmap(struct inode *inode, unsigned int clu) { int i, b; @@ -171,14 +197,19 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu) i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) clear_bit_le(b, sbi->vol_amap[i]->b_data); +#else + test_and_clear_bit_le(b, sbi->vol_amap[i]->b_data); +#endif exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); if (opts->discard) { int ret_discard; ret_discard = sb_issue_discard(sb, - exfat_cluster_to_sector(sbi, clu), + exfat_cluster_to_sector(sbi, clu + + EXFAT_RESERVED_CLUSTERS), (1 << sbi->sect_per_clus_bits), GFP_NOFS, 0); if (ret_discard == -EOPNOTSUPP) { diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c index 5a2f119b7e8c..47882395a884 100644 --- a/fs/exfat/cache.c +++ b/fs/exfat/cache.c @@ -14,9 +14,9 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" +#define EXFAT_CACHE_VALID 0 #define EXFAT_MAX_CACHE 16 struct exfat_cache { @@ -60,6 +60,16 @@ void exfat_cache_shutdown(void) kmem_cache_destroy(exfat_cachep); } +void exfat_cache_init_inode(struct inode *inode) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + + spin_lock_init(&ei->cache_lru_lock); + ei->nr_caches = 0; + ei->cache_valid_id = EXFAT_CACHE_VALID + 1; + INIT_LIST_HEAD(&ei->cache_lru); +} + static inline struct exfat_cache *exfat_cache_alloc(void) { return kmem_cache_alloc(exfat_cachep, GFP_NOFS); diff --git a/fs/exfat/compat.h b/fs/exfat/compat.h new file mode 100644 index 000000000000..82f138417212 --- /dev/null +++ b/fs/exfat/compat.h @@ -0,0 +1,71 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#ifndef _EXFAT_COMPAT_H +#define _EXFAT_COMPAT_H + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) +#include +#else +#define inode_inc_iversion(inode) (inode->i_version++) +#define inode_query_iversion(inode) (inode->i_version) +#define inode_eq_iversion(inode, version) (inode->i_version == version) +#define inode_peek_iversion_raw(inode) (inode->i_version) +#define inode_set_iversion(inode, val) (inode->i_version = val) +#endif + +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) +#include +#include +#include + +static inline void * kvmalloc(size_t size, gfp_t flags) +{ + void *ret; + + ret = kmalloc(size, flags | __GFP_NOWARN); + if (!ret) { + ret = __vmalloc(size, flags, PAGE_KERNEL); + } + return ret; +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,3,0) +static inline void kvfree(void *ptr) +{ + if (is_vmalloc_addr(ptr)) { + vfree(ptr); + } else { + kfree(ptr); + } +} +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3,3,0) */ +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) */ +#endif /* MY_ABC_HERE */ + +/* MS flags were renamed to SB on v4.15 */ +#ifndef SB_NODIRATIME +#define SB_NODIRATIME MS_NODIRATIME +#endif + +#ifndef SB_RDONLY +#define SB_RDONLY MS_RDONLY +#endif + +#ifndef SB_SYNCHRONOUS +#define SB_SYNCHRONOUS MS_SYNCHRONOUS +#endif + +#ifndef sb_rdonly +#define sb_rdonly(sb) ((sb)->s_flags & SB_RDONLY) +#endif + +#endif /* _EXFAT_COMPAT_H */ diff --git a/fs/exfat/config.h b/fs/exfat/config.h new file mode 100644 index 000000000000..ffc25f021cd0 --- /dev/null +++ b/fs/exfat/config.h @@ -0,0 +1,19 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#ifndef _EXFAT_CONFIG_H +#define _EXFAT_CONFIG_H + +#ifndef CONFIG_EXFAT_DEFAULT_IOCHARSET /* if Kconfig lacked iocharset */ +#define CONFIG_EXFAT_DEFAULT_IOCHARSET "utf8" +#endif + + + + +#endif /* _EXFAT_CONFIG_H */ diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index dedbc55cd48f..ca9a1ad2a65a 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -7,7 +7,6 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" static int exfat_extract_uni_name(struct exfat_dentry *ep, @@ -59,10 +58,10 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb, } /* read a directory entry from the opened directory */ -static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry) +static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) { - int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext; - unsigned int type, clu_offset, max_dentries; + int i, dentries_per_clu, dentries_per_clu_bits = 0; + unsigned int type, clu_offset; sector_t sector; struct exfat_chain dir, clu; struct exfat_uni_name uni_name; @@ -70,7 +69,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_inode_info *ei = EXFAT_I(inode); - unsigned int dentry = EXFAT_B_TO_DEN(*cpos) & 0xFFFFFFFF; + unsigned int dentry = ei->rwoffset & 0xFFFFFFFF; struct buffer_head *bh; /* check if the given file ID is opened */ @@ -85,8 +84,6 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent dentries_per_clu = sbi->dentries_per_clu; dentries_per_clu_bits = ilog2(dentries_per_clu); - max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES, - (u64)sbi->num_clusters << dentries_per_clu_bits); clu_offset = dentry >> dentries_per_clu_bits; exfat_chain_dup(&clu, &dir); @@ -110,7 +107,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent } } - while (clu.dir != EXFAT_EOF_CLUSTER && dentry < max_dentries) { + while (clu.dir != EXFAT_EOF_CLUSTER) { i = dentry & (dentries_per_clu - 1); for ( ; i < dentries_per_clu; i++, dentry++) { @@ -129,7 +126,6 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent continue; } - num_ext = ep->dentry.file.num_ext; dir_entry->attr = le16_to_cpu(ep->dentry.file.attr); exfat_get_entry_time(sbi, &dir_entry->crtime, ep->dentry.file.create_tz, @@ -160,13 +156,12 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent return -EIO; dir_entry->size = le64_to_cpu(ep->dentry.stream.valid_size); - dir_entry->entry = dentry; brelse(bh); ei->hint_bmap.off = dentry >> dentries_per_clu_bits; ei->hint_bmap.clu = clu.dir; - *cpos = EXFAT_DEN_TO_B(dentry + 1 + num_ext); + ei->rwoffset = ++dentry; return 0; } @@ -182,7 +177,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent } dir_entry->namebuf.lfn[0] = '\0'; - *cpos = EXFAT_DEN_TO_B(dentry); + ei->rwoffset = dentry; return 0; } @@ -212,9 +207,17 @@ static void exfat_free_namebuf(struct exfat_dentry_namebuf *nb) /* skip iterating emit_dots when dir is empty */ #define ITER_POS_FILLED_DOTS (2) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) static int exfat_iterate(struct file *filp, struct dir_context *ctx) +#else +static int exfat_iterate(struct file *filp, void *dirent, filldir_t filldir) +#endif { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) + struct inode *inode = file_inode(filp); +#else struct inode *inode = filp->f_path.dentry->d_inode; +#endif struct super_block *sb = inode->i_sb; struct inode *tmp; struct exfat_dir_entry de; @@ -225,8 +228,9 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) int err = 0, fake_offset = 0; exfat_init_namebuf(nb); - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) cpos = ctx->pos; if (!dir_emit_dots(filp, ctx)) goto unlock; @@ -235,6 +239,26 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) cpos = 0; fake_offset = 1; } +#else + cpos = filp->f_pos; + /* Fake . and .. for the root directory. */ + while (filp->f_pos < 2) { + if (inode->i_ino == EXFAT_ROOT_INO) + inum = EXFAT_ROOT_INO; + else if (filp->f_pos == 0) + inum = inode->i_ino; + else /* (filp->f_pos == 1) */ + inum = parent_ino(filp->f_path.dentry); + + if (filldir(dirent, "..", filp->f_pos+1, filp->f_pos, inum, DT_DIR) < 0) + goto unlock; + filp->f_pos++; + } + if (filp->f_pos == ITER_POS_FILLED_DOTS) { + cpos = 0; + fake_offset = 1; + } +#endif if (cpos & (DENTRY_SIZE - 1)) { err = -ENOENT; @@ -246,10 +270,12 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) if (err) goto unlock; get_new: - if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode)) + ei->rwoffset = EXFAT_B_TO_DEN(cpos); + + if (cpos >= i_size_read(inode)) goto end_of_dir; - err = exfat_readdir(inode, &cpos, &de); + err = exfat_readdir(inode, &de); if (err) { /* * At least we tried to read a sector. Move cpos to next sector @@ -264,10 +290,13 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) goto end_of_dir; } + cpos = EXFAT_DEN_TO_B(ei->rwoffset); + if (!nb->lfn[0]) goto end_of_dir; - i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff); + i_pos = ((loff_t)ei->start_clu << 32) | + ((ei->rwoffset - 1) & 0xffffffff); tmp = exfat_iget(sb, i_pos); if (tmp) { inum = tmp->i_ino; @@ -281,20 +310,33 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) * Because page fault can occur in dir_emit() when the size * of buffer given from user is larger than one page size. */ - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum, (de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) +#else + if (filldir(dirent, nb->lfn, strlen(nb->lfn), filp->f_pos, inum, + (de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG) < 0) +#endif goto out_unlocked; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif goto get_new; end_of_dir: if (!cpos && fake_offset) cpos = ITER_POS_FILLED_DOTS; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif unlock: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); out_unlocked: /* * To improve performance, free namebuf after unlock sb_lock. @@ -307,7 +349,11 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) const struct file_operations exfat_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) .iterate = exfat_iterate, +#else + .readdir = exfat_iterate, +#endif .fsync = exfat_file_fsync, }; @@ -439,7 +485,11 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, { struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) struct timespec64 ts = current_time(inode); +#else + struct timespec ts = CURRENT_TIME_SEC; +#endif sector_t sector; struct exfat_dentry *ep; struct buffer_head *bh; @@ -910,6 +960,7 @@ enum { /* * return values: * >= 0 : return dir entiry position with the name in dir + * -EEXIST : (root dir, ".") it is the root dir itself * -ENOENT : entry with the name does not exist * -EIO : I/O error */ @@ -977,8 +1028,11 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, if (ei->hint_femp.eidx == EXFAT_HINT_NONE || candi_empty.eidx <= - ei->hint_femp.eidx) - ei->hint_femp = candi_empty; + ei->hint_femp.eidx) { + memcpy(&ei->hint_femp, + &candi_empty, + sizeof(candi_empty)); + } } brelse(bh); diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index b8f0e829ecbd..3c6a51dab76f 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. @@ -10,6 +13,11 @@ #include #include +#include "config.h" +#include "compat.h" +#include "version.h" +#include "exfat_raw.h" + #define EXFAT_SUPER_MAGIC 0x2011BAB0UL #define EXFAT_ROOT_INO 1 @@ -128,7 +136,7 @@ enum { struct exfat_dentry_namebuf { char *lfn; - int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */ + int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */ }; /* unicode name structure */ @@ -183,9 +191,15 @@ struct exfat_dir_entry { unsigned short attr; loff_t size; unsigned int num_subdirs; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) struct timespec64 atime; struct timespec64 mtime; struct timespec64 crtime; +#else + struct timespec atime; + struct timespec mtime; + struct timespec crtime; +#endif struct exfat_dentry_namebuf namebuf; }; @@ -193,14 +207,21 @@ struct exfat_dir_entry { * exfat mount in-memory data */ struct exfat_mount_options { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) kuid_t fs_uid; kgid_t fs_gid; +#else + uid_t fs_uid; + gid_t fs_gid; +#endif unsigned short fs_fmask; unsigned short fs_dmask; /* permission for setting the [am]time */ unsigned short allow_utime; /* charset for filename input/display */ char *iocharset; + /* fake return success on setattr(e.g. chmods/chowns) */ + unsigned char quiet; /* on error: continue, panic, remount-ro */ enum exfat_error_mode errors; unsigned utf8:1, /* Use of UTF-8 character set */ @@ -226,6 +247,9 @@ struct exfat_sb_info { unsigned int dentries_per_clu; /* num of dentries per cluster */ unsigned int vol_flags; /* volume flags */ unsigned int vol_flags_persistent; /* volume flags to retain */ +#ifdef MY_ABC_HERE + bool vol_clean_on_mount; +#endif /* MY_ABC_HERE */ struct buffer_head *boot_bh; /* buffer_head of BOOT sector */ unsigned int map_clu; /* allocation bitmap start cluster */ @@ -237,7 +261,9 @@ struct exfat_sb_info { unsigned int clu_srch_ptr; /* cluster search pointer */ unsigned int used_clusters; /* number of used clusters */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) struct mutex s_lock; /* superblock lock */ +#endif struct exfat_mount_options options; struct nls_table *nls_io; /* Charset used for input and display */ struct ratelimit_state ratelimit; @@ -248,8 +274,6 @@ struct exfat_sb_info { struct rcu_head rcu; }; -#define EXFAT_CACHE_VALID 0 - /* * EXFAT file system inode in-memory data */ @@ -265,6 +289,8 @@ struct exfat_inode_info { * the validation of hint_stat. */ unsigned int version; + /* file offset or dentry index for readdir */ + loff_t rwoffset; /* hint for cluster last accessed */ struct exfat_hint hint_bmap; @@ -291,10 +317,18 @@ struct exfat_inode_info { /* hash by i_location */ struct hlist_node i_hash_fat; /* protect bmap against truncate */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) struct rw_semaphore truncate_lock; +#else + struct rw_semaphore i_alloc_sem; +#endif struct inode vfs_inode; /* File creation time */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) struct timespec64 i_crtime; +#else + struct timespec i_crtime; +#endif }; static inline struct exfat_sb_info *EXFAT_SB(struct super_block *sb) @@ -346,8 +380,17 @@ static inline unsigned short exfat_make_attr(struct inode *inode) if (S_ISDIR(inode->i_mode)) attr |= ATTR_SUBDIR; +#ifdef MY_ABC_HERE + if (exfat_mode_can_hold_ro(inode)) { + if (inode->i_mode & 0222) + attr &= ~ATTR_READONLY; + else + attr |= ATTR_READONLY; + } +#else if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) attr |= ATTR_READONLY; +#endif return attr; } @@ -380,6 +423,26 @@ static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi, EXFAT_RESERVED_CLUSTERS; } +static inline void __lock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_lock(&sbi->s_lock); +#else + lock_super(sb); +#endif +} + +static inline void __unlock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_unlock(&sbi->s_lock); +#else + unlock_super(sb); +#endif +} + /* super.c */ int exfat_set_volume_dirty(struct super_block *sb); int exfat_clear_volume_dirty(struct super_block *sb); @@ -417,10 +480,46 @@ extern const struct file_operations exfat_file_operations; int __exfat_truncate(struct inode *inode, loff_t new_size); void exfat_truncate(struct inode *inode, loff_t size); int exfat_setattr(struct dentry *dentry, struct iattr *attr); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) int exfat_getattr(const struct path *path, struct kstat *stat, unsigned int request_mask, unsigned int query_flags); +#else +int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); +#endif int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); +#ifdef MY_ABC_HERE +void exfat_attr_to_syno_archive_bit(unsigned int *archive_bit, u32 exfat_attr); +void syno_archive_bit_to_exfat_attr(unsigned int archive_bit, u32 *exfat_attr); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int exfat_syno_get_archive_bit(struct dentry *dentry, unsigned int *archive_bit, int may_not_block); +#else +int exfat_syno_get_archive_bit(struct dentry *dentry, unsigned int *archive_bit); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +int exfat_syno_set_archive_bit(struct dentry *dentry, unsigned int archive_bit); +#if defined(CONFIG_SYNO_FS_WINACL) || defined(SYNO_FS_SYNO_ACL) +int exfat_syno_arbit_chg_ok(struct dentry *dentry, + unsigned int cmd, int tag, int mask); +#endif /* CONFIG_SYNO_FS_WINACL || SYNO_FS_SYNO_ACL */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int exfat_syno_getattr(struct dentry *dentry, struct kstat *kstat, unsigned int syno_flags); +#else +int exfat_syno_getattr(struct dentry *dentry, struct kstat *kst, int flags); +#endif +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int exfat_syno_get_create_time(struct inode *inode, struct timespec64* time); +int exfat_syno_set_create_time(struct inode *inode, struct timespec64* time); +#else +int exfat_syno_set_create_time(struct dentry *dentry, struct timespec* time); +#endif +#endif /* MY_ABC_HERE */ + /* namei.c */ extern const struct dentry_operations exfat_dentry_ops; extern const struct dentry_operations exfat_utf8_dentry_ops; @@ -428,6 +527,7 @@ extern const struct dentry_operations exfat_utf8_dentry_ops; /* cache.c */ int exfat_cache_init(void); void exfat_cache_shutdown(void); +void exfat_cache_init_inode(struct inode *inode); void exfat_cache_inval_inode(struct inode *inode); int exfat_get_cluster(struct inode *inode, unsigned int cluster, unsigned int *fclus, unsigned int *dclus, @@ -476,6 +576,17 @@ int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); void exfat_evict_inode(struct inode *inode); int exfat_block_truncate_page(struct inode *inode, loff_t from); +/* xattr.c */ +#ifdef CONFIG_EXFAT_VIRTUAL_XATTR +extern int exfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); +extern ssize_t exfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size); +extern ssize_t exfat_listxattr(struct dentry *dentry, char *list, size_t size); +extern int exfat_removexattr(struct dentry *dentry, const char *name); +extern const struct xattr_handler *exfat_xattr_handlers[]; +#else +#define exfat_xattr_handlers NULL +#endif + /* exfat/nls.c */ unsigned short exfat_toupper(struct super_block *sb, unsigned short a); int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, @@ -506,11 +617,19 @@ void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) #define exfat_info(sb, fmt, ...) \ exfat_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, u8 tz, __le16 time, __le16 date, u8 time_cs); void exfat_truncate_atime(struct timespec64 *ts); void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, u8 *tz, __le16 *time, __le16 *date, u8 *time_cs); +#else +void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec *ts, + u8 tz, __le16 time, __le16 date, u8 time_cs); +void exfat_truncate_atime(struct timespec *ts); +void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec *ts, + u8 *tz, __le16 *time, __le16 *date, u8 *time_cs); +#endif u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type); u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type); void exfat_update_bh(struct buffer_head *bh, int sync); diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h index 7f39b1c6469c..6aec6288e1f2 100644 --- a/fs/exfat/exfat_raw.h +++ b/fs/exfat/exfat_raw.h @@ -77,10 +77,6 @@ #define EXFAT_FILE_NAME_LEN 15 -#define EXFAT_MIN_SECT_SIZE_BITS 9 -#define EXFAT_MAX_SECT_SIZE_BITS 12 -#define EXFAT_MAX_SECT_PER_CLUS_BITS(x) (25 - (x)->sect_size_bits) - /* EXFAT: Main and Backup Boot Sector (512 bytes) */ struct boot_sector { __u8 jmp_boot[BOOTSEC_JUMP_BOOT_LEN]; diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index c3c9afee7418..f209d9141882 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -7,7 +7,6 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" static int exfat_mirror_bh(struct super_block *sb, sector_t sec, diff --git a/fs/exfat/file.c b/fs/exfat/file.c index a92478eabfa4..93a5a1b09043 100644 --- a/fs/exfat/file.c +++ b/fs/exfat/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. @@ -8,8 +11,11 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ static int exfat_cont_expand(struct inode *inode, loff_t size) { @@ -21,7 +27,11 @@ static int exfat_cont_expand(struct inode *inode, loff_t size) if (err) return err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) inode->i_ctime = inode->i_mtime = current_time(inode); +#else + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; +#endif mark_inode_dirty(inode); if (!IS_SYNC(inode)) @@ -44,7 +54,11 @@ static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) { mode_t allow_utime = sbi->options.allow_utime; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) if (!uid_eq(current_fsuid(), inode->i_uid)) { +#else + if (current_fsuid() != inode->i_uid) { +#endif if (in_group_p(inode->i_gid)) allow_utime >>= 3; if (allow_utime & MAY_WRITE) @@ -151,7 +165,11 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) /* update the directory entry */ if (!evict) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) struct timespec64 ts; +#else + struct timespec ts; +#endif struct exfat_dentry *ep, *ep2; struct exfat_entry_set_cache *es; int err; @@ -163,7 +181,11 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) ep = exfat_get_dentry_cached(es, 0); ep2 = exfat_get_dentry_cached(es, 1); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) ts = current_time(inode); +#else + ts = CURRENT_TIME_SEC; +#endif exfat_set_entry_time(sbi, &ts, &ep->dentry.file.modify_tz, &ep->dentry.file.modify_time, @@ -208,6 +230,8 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) /* hint information */ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; ei->hint_bmap.clu = EXFAT_EOF_CLUSTER; + if (ei->rwoffset > new_size) + ei->rwoffset = new_size; /* hint_stat will be used if this is directory. */ ei->hint_stat.eidx = 0; @@ -217,7 +241,9 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) /* free the clusters */ if (exfat_free_cluster(inode, &clu)) return -EIO; - +#ifdef MY_ABC_HERE + if (sbi->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ exfat_clear_volume_dirty(sb); return 0; @@ -227,11 +253,11 @@ void exfat_truncate(struct inode *inode, loff_t size) { struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); - unsigned int blocksize = i_blocksize(inode); + unsigned int blocksize = 1 << inode->i_blkbits; loff_t aligned_size; int err; - mutex_lock(&sbi->s_lock); + __lock_super(sb); if (EXFAT_I(inode)->start_clu == 0) { /* * Empty start_clu != ~0 (not allocated) @@ -244,7 +270,11 @@ void exfat_truncate(struct inode *inode, loff_t size) if (err) goto write_size; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) inode->i_ctime = inode->i_mtime = current_time(inode); +#else + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; +#endif if (IS_DIRSYNC(inode)) exfat_sync_inode(inode); else @@ -264,9 +294,10 @@ void exfat_truncate(struct inode *inode, loff_t size) if (EXFAT_I(inode)->i_size_aligned > i_size_read(inode)) EXFAT_I(inode)->i_size_aligned = aligned_size; - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) int exfat_getattr(const struct path *path, struct kstat *stat, unsigned int request_mask, unsigned int query_flags) { @@ -281,6 +312,18 @@ int exfat_getattr(const struct path *path, struct kstat *stat, stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size; return 0; } +#else +int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + + generic_fillattr(inode, stat); + exfat_truncate_atime(&stat->atime); + stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size; + + return 0; +} +#endif int exfat_setattr(struct dentry *dentry, struct iattr *attr) { @@ -293,7 +336,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_size > i_size_read(inode)) { error = exfat_cont_expand(inode, attr->ia_size); if (error || attr->ia_valid == ATTR_SIZE) - return error; + goto out; attr->ia_valid &= ~ATTR_SIZE; } @@ -305,21 +348,51 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr) ATTR_TIMES_SET); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) error = setattr_prepare(dentry, attr); +#else + error = inode_change_ok(inode, attr); +#endif attr->ia_valid = ia_valid; - if (error) + if (error) { + if (sbi->options.quiet) + error = 0; goto out; + } if (((attr->ia_valid & ATTR_UID) && +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) !uid_eq(attr->ia_uid, sbi->options.fs_uid)) || ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, sbi->options.fs_gid)) || +#else + (attr->ia_uid != sbi->options.fs_uid)) || + ((attr->ia_valid & ATTR_GID) && + (attr->ia_gid != sbi->options.fs_gid)) || +#endif ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { error = -EPERM; +#ifdef MY_ABC_HERE + if (sbi->options.quiet) + error = 0; +#endif /* MY_ABC_HERE */ goto out; } + if (error) { + if (sbi->options.quiet) + error = 0; + goto out; + } + +#ifdef MY_ABC_HERE + if (attr->ia_valid & (ATTR_MTIME_SET | ATTR_MTIME)) { + attr->ia_valid |= ATTR_CTIME; + attr->ia_ctime = attr->ia_mtime; + } +#endif /* MY_ABC_HERE */ + /* * We don't return -EPERM here. Yes, strange, but this is too * old behavior. @@ -334,13 +407,21 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr) if (error) goto out; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) down_write(&EXFAT_I(inode)->truncate_lock); truncate_setsize(inode, attr->ia_size); exfat_truncate(inode, attr->ia_size); up_write(&EXFAT_I(inode)->truncate_lock); +#else + truncate_setsize(inode, attr->ia_size); + exfat_truncate(inode, attr->ia_size); +#endif } setattr_copy(inode, attr); +#ifdef MY_ABC_HERE + EXFAT_I(inode)->attr = exfat_make_attr(inode); +#endif exfat_truncate_atime(&inode->i_atime); mark_inode_dirty(inode); @@ -353,7 +434,11 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) struct inode *inode = filp->f_mapping->host; int err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0) err = __generic_file_fsync(filp, start, end, datasync); +#else + err = generic_file_fsync(filp, start, end, datasync); +#endif if (err) return err; @@ -361,20 +446,294 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) if (err) return err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL); +#else + return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); +#endif } +#ifdef MY_ABC_HERE +void exfat_attr_to_syno_archive_bit(unsigned int *archive_bit, + u32 exfat_attr) +{ + *archive_bit = 0; + + if (exfat_attr & ATTR_READONLY) + *archive_bit |= S2_SMB_READONLY; + if (exfat_attr & ATTR_HIDDEN) + *archive_bit |= S2_SMB_HIDDEN; + if (exfat_attr & ATTR_SYSTEM) + *archive_bit |= S2_SMB_SYSTEM; + if (exfat_attr & ATTR_ARCHIVE) + *archive_bit |= S2_SMB_ARCHIVE; + + return; +} + +void syno_archive_bit_to_exfat_attr(unsigned int archive_bit, + u32 *exfat_attr) +{ + u32 final_exfat_arbit = 0; + + if (archive_bit & S2_SMB_HIDDEN) + final_exfat_arbit |= ATTR_HIDDEN; + if (archive_bit & S2_SMB_SYSTEM) + final_exfat_arbit |= ATTR_SYSTEM; + if (archive_bit & S2_SMB_ARCHIVE) + final_exfat_arbit |= ATTR_ARCHIVE; + if (archive_bit & S2_SMB_READONLY) + final_exfat_arbit |= ATTR_READONLY; + + *exfat_attr &= ~(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE | ATTR_READONLY); + *exfat_attr |= final_exfat_arbit; + + return; +} + +static int exfat_syno_setattr(struct inode *inode, u32 new_attr) +{ + u32 type; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *ei = EXFAT_I(inode); + struct exfat_entry_set_cache *es = NULL; + struct exfat_dentry *ep = NULL; + + if (new_attr == exfat_make_attr(inode)) { + return 0; + } + + if (ei->type == TYPE_DIR && + ei->dir.dir == sbi->root_dir && ei->entry == -1) { + return 0; + } + + /* get the directory entry of given file */ + es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES); + if (!es) + return -EIO; + ep = exfat_get_dentry_cached(es, 0); + type = exfat_get_entry_type(ep); + + if (((type == TYPE_FILE) && (new_attr & ATTR_SUBDIR)) || + ((type == TYPE_DIR) && (!(new_attr & ATTR_SUBDIR)))) { + exfat_free_dentry_set(es, false); + return -EINVAL; + } + + exfat_set_volume_dirty(sb); + + /* set the file attribute */ + exfat_save_attr(inode, new_attr); + + exfat_update_dir_chksum_with_entry_set(es); + exfat_free_dentry_set(es, inode_needs_sync(inode)); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int exfat_syno_get_archive_bit(struct dentry *dentry, + unsigned int *archive_bit, int may_not_block) +#else +int exfat_syno_get_archive_bit(struct dentry *dentry, + unsigned int *archive_bit) +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */ +{ + if (!dentry || !dentry->d_inode) + return -EINVAL; + + exfat_attr_to_syno_archive_bit(archive_bit, exfat_make_attr(dentry->d_inode)); + + return 0; +} + +int exfat_syno_set_archive_bit(struct dentry *dentry, + unsigned int archive_bit) +{ + int ret = 0; + u32 exfat_attr = 0; + u32 old_exfat_attr = 0; + struct super_block *sb = NULL; + struct inode *inode = NULL; + struct exfat_sb_info *sbi = NULL; + + if (!dentry || !dentry->d_inode) + return -EINVAL; + + inode = dentry->d_inode; + sb = inode->i_sb; + sbi = EXFAT_SB(sb); + + __lock_super(sb); + + old_exfat_attr = exfat_attr = exfat_make_attr(inode); + syno_archive_bit_to_exfat_attr(archive_bit, &exfat_attr); + + if (old_exfat_attr == exfat_attr) + goto out; + + if (exfat_syno_setattr(inode, exfat_attr)) + ret = -EIO; + inode->i_mode = exfat_make_mode(sbi, exfat_attr, S_IRWXUGO); + + if (IS_DIRSYNC(inode)) + exfat_sync_inode(inode); + else + mark_inode_dirty(inode); +out: + if (sb) + __unlock_super(sb); + + return ret; +} + +#if defined(CONFIG_SYNO_FS_WINACL) || defined(SYNO_FS_SYNO_ACL) +int exfat_syno_arbit_chg_ok(struct dentry *dentry, + unsigned int cmd, int tag, int mask) +{ + if (cmd != F_SETSMB_ARCHIVE && cmd != F_CLRSMB_ARCHIVE && + cmd != F_SETSMB_HIDDEN && cmd != F_CLRSMB_HIDDEN && + cmd != F_SETSMB_READONLY && cmd != F_CLRSMB_READONLY && + cmd != F_SETSMB_SYSTEM && cmd != F_CLRSMB_SYSTEM) + return -EPERM; + + return 0; +} +#endif /* CONFIG_SYNO_FS_WINACL || SYNO_FS_SYNO_ACL */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int exfat_syno_getattr(struct dentry *dentry, struct kstat *kstat, unsigned int syno_flags) +#else +int exfat_syno_getattr(struct dentry *dentry, struct kstat *kst, int flags) +#endif +{ + int ret = 0; + struct inode *inode; + + if (!dentry || !dentry->d_inode) + return -EINVAL; + + inode = dentry->d_inode; +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + if (syno_flags & SYNOST_ARCHIVE_BIT) + exfat_attr_to_syno_archive_bit(&kstat->syno_archive_bit, exfat_make_attr(inode)); +#else + if (flags & SYNOST_ARCHIVE_BIT) + exfat_attr_to_syno_archive_bit(&kst->syno_archive_bit, exfat_make_attr(inode)); +#endif +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + if (syno_flags & SYNOST_CREATE_TIME) + kstat->syno_create_time = EXFAT_I(dentry->d_inode)->i_crtime; +#else + if (flags & SYNOST_CREATE_TIME) + kst->syno_create_time = dentry->d_inode->i_create_time; +#endif +#endif /* MY_ABC_HERE */ + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +int exfat_syno_get_create_time(struct inode *inode, struct timespec64* time) +{ + *time = EXFAT_I(inode)->i_crtime; + + return 0; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) +int exfat_syno_set_create_time(struct inode *inode, struct timespec64* time) { +#else +int exfat_syno_set_create_time(struct dentry *dentry, struct timespec* time) { +#endif + struct super_block *sb = NULL; + struct exfat_inode_info *ei = NULL; + struct exfat_sb_info *sbi = NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + if (!inode) + return -EINVAL; +#else + struct inode *inode = NULL; + + if (!dentry || !dentry->d_inode) + return -EINVAL; + inode = dentry->d_inode; +#endif + + sb = inode->i_sb; + ei = EXFAT_I(inode); + sbi = EXFAT_SB(sb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + ei->i_crtime = timestamp_truncate(*time, inode); + inode->i_ctime = current_time(inode); +#else + inode->i_create_time = ei->i_crtime = timespec_trunc(*time, inode->i_sb->s_time_gran); + inode->i_ctime = CURRENT_TIME; +#endif + mark_inode_dirty(inode); + + return 0; +} +#endif /* MY_ABC_HERE */ + const struct file_operations exfat_file_operations = { .llseek = generic_file_llseek, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) + .read = new_sync_read, + .write = new_sync_write, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, +#endif .mmap = generic_file_mmap, .fsync = exfat_file_fsync, .splice_read = generic_file_splice_read, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) .splice_write = iter_file_splice_write, +#endif }; const struct inode_operations exfat_file_inode_operations = { .setattr = exfat_setattr, .getattr = exfat_getattr, +#ifdef CONFIG_EXFAT_VIRTUAL_XATTR + .listxattr = exfat_listxattr, +#endif +#ifdef MY_ABC_HERE + .syno_getattr = exfat_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_bit = exfat_syno_get_archive_bit, + .syno_set_archive_bit = exfat_syno_set_archive_bit, +#if defined(CONFIG_SYNO_FS_WINACL) || defined(SYNO_FS_SYNO_ACL) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + .syno_archive_bit_change_ok = exfat_syno_arbit_chg_ok, +#else + .syno_arbit_chg_ok = exfat_syno_arbit_chg_ok, +#endif +#endif /* CONFIG_SYNO_FS_WINACL || SYNO_FS_SYNO_ACL */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + .syno_get_crtime = exfat_syno_get_create_time, +#endif + .syno_set_crtime = exfat_syno_set_create_time, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c index 730373e0965a..5646b16ddbf5 100644 --- a/fs/exfat/inode.c +++ b/fs/exfat/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. @@ -12,11 +15,15 @@ #include #include #include -#include - -#include "exfat_raw.h" #include "exfat_fs.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) +#include +#endif + static int __exfat_write_inode(struct inode *inode, int sync) { unsigned long long on_disk_size; @@ -84,16 +91,20 @@ int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) { int ret; - mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); + __lock_super(inode->i_sb); ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); - mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); + __unlock_super(inode->i_sb); return ret; } void exfat_sync_inode(struct inode *inode) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock); +#else + lockdep_assert_held(&inode->i_sb->s_lock); +#endif __exfat_write_inode(inode, 1); } @@ -114,6 +125,8 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, unsigned int local_clu_offset = clu_offset; unsigned int num_to_be_allocated = 0, num_clusters = 0; + ei->rwoffset = EXFAT_CLU_TO_B(clu_offset, sbi); + if (EXFAT_I(inode)->i_size_ondisk > 0) num_clusters = EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, @@ -301,7 +314,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, sector_t phys = 0; loff_t pos; - mutex_lock(&sbi->s_lock); + __lock_super(sb); last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb); if (iblock >= last_block && !create) goto done; @@ -353,7 +366,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, done: bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb); unlock_ret: - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); return err; } @@ -362,10 +375,18 @@ static int exfat_readpage(struct file *file, struct page *page) return mpage_readpage(page, exfat_get_block); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) static void exfat_readahead(struct readahead_control *rac) { mpage_readahead(rac, exfat_get_block); } +#else +static int exfat_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned int nr_pages) +{ + return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); +} +#endif static int exfat_writepage(struct page *page, struct writeback_control *wbc) { @@ -383,7 +404,11 @@ static void exfat_write_failed(struct address_space *mapping, loff_t to) struct inode *inode = mapping->host; if (to > i_size_read(inode)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0) truncate_pagecache(inode, i_size_read(inode)); +#else + truncate_pagecache(inode, to, i_size_read(inode)); +#endif exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned); } } @@ -426,7 +451,11 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, exfat_write_failed(mapping, pos+len); if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) inode->i_mtime = inode->i_ctime = current_time(inode); +#else + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; +#endif ei->attr |= ATTR_ARCHIVE; mark_inode_dirty(inode); } @@ -434,12 +463,33 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, return err; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) +static ssize_t exfat_direct_IO(struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +#endif { struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) loff_t size = iocb->ki_pos + iov_iter_count(iter); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + loff_t size = offset + iov_iter_count(iter); +#else + loff_t size = offset + iov_length(iov, nr_segs); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) int rw = iov_iter_rw(iter); +#endif ssize_t ret; if (rw == WRITE) { @@ -460,7 +510,21 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) * Need to use the DIO_LOCKING for avoiding the race * condition of exfat_get_block() and ->truncate(). */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) + ret = blockdev_direct_IO(iocb, inode, iter, offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, exfat_get_block); +#else + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, exfat_get_block, NULL); +#endif + if (ret < 0 && (rw & WRITE)) exfat_write_failed(mapping, size); return ret; @@ -471,9 +535,16 @@ static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block) sector_t blocknr; /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) down_read(&EXFAT_I(mapping->host)->truncate_lock); blocknr = generic_block_bmap(mapping, block, exfat_get_block); up_read(&EXFAT_I(mapping->host)->truncate_lock); +#else + down_read(&EXFAT_I(mapping->host)->i_alloc_sem); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->i_alloc_sem); +#endif + return blocknr; } @@ -491,7 +562,11 @@ int exfat_block_truncate_page(struct inode *inode, loff_t from) static const struct address_space_operations exfat_aops = { .readpage = exfat_readpage, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) .readahead = exfat_readahead, +#else + .readpages = exfat_readpages, +#endif .writepage = exfat_writepage, .writepages = exfat_writepages, .write_begin = exfat_write_begin, @@ -532,9 +607,15 @@ struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) struct exfat_inode_info *info; struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); struct inode *inode = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) + struct hlist_node *node; + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, node, head, i_hash_fat) { +#else spin_lock(&sbi->inode_hash_lock); hlist_for_each_entry(info, head, i_hash_fat) { +#endif WARN_ON(info->vfs_inode.i_sb != sb); if (i_pos != info->i_pos) @@ -554,7 +635,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) struct exfat_inode_info *ei = EXFAT_I(inode); loff_t size = info->size; - ei->dir = info->dir; + memcpy(&ei->dir, &info->dir, sizeof(struct exfat_chain)); ei->entry = info->entry; ei->attr = info->attr; ei->start_clu = info->start_clu; @@ -565,6 +646,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) ei->hint_stat.eidx = 0; ei->hint_stat.clu = info->start_clu; ei->hint_femp.eidx = EXFAT_HINT_NONE; + ei->rwoffset = 0; ei->hint_bmap.off = EXFAT_EOF_CLUSTER; ei->i_pos = 0; @@ -578,7 +660,11 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); inode->i_op = &exfat_dir_inode_operations; inode->i_fop = &exfat_dir_operations; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) set_nlink(inode, info->num_subdirs); +#else + inode->i_nlink = info->num_subdirs; +#endif } else { /* regular file */ inode->i_generation |= 1; inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); @@ -606,8 +692,15 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) inode->i_mtime = info->mtime; inode->i_ctime = info->mtime; ei->i_crtime = info->crtime; +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + inode->i_create_time = info->crtime; +#endif +#endif /* MY_ABC_HERE */ inode->i_atime = info->atime; + exfat_cache_init_inode(inode); + return 0; } @@ -645,13 +738,17 @@ void exfat_evict_inode(struct inode *inode) if (!inode->i_nlink) { i_size_write(inode, 0); - mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); + __lock_super(inode->i_sb); __exfat_truncate(inode, 0); - mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); + __unlock_super(inode->i_sb); } invalidate_inode_buffers(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) clear_inode(inode); +#else + end_writeback(inode); +#endif exfat_cache_inval_inode(inode); exfat_unhash_inode(inode); } diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c index d34e6193258d..213b6b589595 100644 --- a/fs/exfat/misc.c +++ b/fs/exfat/misc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Written 1992,1993 by Werner Almesberger @@ -11,7 +14,6 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" /* @@ -65,7 +67,11 @@ void exfat_msg(struct super_block *sb, const char *level, const char *fmt, ...) #define SECS_PER_MIN (60) #define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off) +#else +static void exfat_adjust_tz(struct timespec *ts, u8 tz_off) +#endif { if (tz_off <= 0x3F) ts->tv_sec -= TIMEZONE_SEC(tz_off); @@ -73,14 +79,34 @@ static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off) ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off); } +#ifdef MY_ABC_HERE +static inline int exfat_tz_offset(struct exfat_sb_info *sbi) +{ + if (sbi->options.time_offset) + return sbi->options.time_offset; + + // sys_tz is set by settimeofday(2) from userspace. if it isn't set, + // exfat will report incorrect timestamp. + return -sys_tz.tz_minuteswest; +} +#endif /* MY_ABC_HERE */ + /* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, +#else +void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec *ts, +#endif u8 tz, __le16 time, __le16 date, u8 time_cs) { u16 t = le16_to_cpu(time); u16 d = le16_to_cpu(date); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) ts->tv_sec = mktime64(1980 + (d >> 9), d >> 5 & 0x000F, d & 0x001F, +#else + ts->tv_sec = mktime(1980 + (d >> 9), d >> 5 & 0x000F, d & 0x001F, +#endif t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1); @@ -95,18 +121,30 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, /* Adjust timezone to UTC0. */ exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID); else +#ifdef MY_ABC_HERE + ts->tv_sec -= exfat_tz_offset(sbi) * SECS_PER_MIN; +#else /* Convert from local time to UTC using time_offset. */ ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN; +#endif } /* Convert linear UNIX date to a EXFAT time/date pair. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, +#else +void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec *ts, +#endif u8 *tz, __le16 *time, __le16 *date, u8 *time_cs) { struct tm tm; u16 t, d; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) time64_to_tm(ts->tv_sec, 0, &tm); +#else + time_to_tm(ts->tv_sec, 0, &tm); +#endif t = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); d = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday; @@ -130,7 +168,11 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, * (There is no 10msIncrement field for access_time unlike create/modify_time) * atime also has only a 2-second resolution. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) void exfat_truncate_atime(struct timespec64 *ts) +#else +void exfat_truncate_atime(struct timespec *ts) +#endif { ts->tv_sec = round_down(ts->tv_sec, 2); ts->tv_nsec = 0; @@ -180,7 +222,11 @@ int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync) set_buffer_uptodate(bhs[i]); mark_buffer_dirty(bhs[i]); if (sync) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) write_dirty_buffer(bhs[i], 0); +#else + write_dirty_buffer(bhs[i], WRITE_SYNC); +#endif } for (i = 0; i < nr_bhs && sync; i++) { diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index 2932b23a3b6c..220ee3b5db57 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -1,15 +1,16 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. */ -#include #include #include #include #include -#include "exfat_raw.h" #include "exfat_fs.h" static inline unsigned long exfat_d_version(struct dentry *dentry) @@ -31,12 +32,27 @@ static inline void exfat_d_version_set(struct dentry *dentry, * If it happened, the negative dentry isn't actually negative anymore. So, * drop it. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags) +#else +static int exfat_d_revalidate(struct dentry *dentry, struct nameidata *nd) +#endif { int ret; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) if (flags & LOOKUP_RCU) return -ECHILD; +#else + unsigned int flags; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + flags = nd ? nd->flags : 0; +#endif /* * This is not negative dentry. Always valid. @@ -48,18 +64,34 @@ static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags) * positive dentry isn't good idea. So it's unsupported like * rename("filename", "FILENAME") for now. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) if (d_really_is_positive(dentry)) return 1; +#else + if (dentry->d_inode) + return 1; +#endif /* * Drop the negative dentry, in order to make sure to use the case * sensitive name which is specified by user if this is for creation. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) return 0; +#else + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } +#endif spin_lock(&dentry->d_lock); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0) ret = inode_eq_iversion(d_inode(dentry->d_parent), +#else + ret = inode_eq_iversion(dentry->d_parent->d_inode, +#endif exfat_d_version(dentry)); spin_unlock(&dentry->d_lock); return ret; @@ -78,13 +110,22 @@ static unsigned int exfat_striptail_len(unsigned int len, const char *name) * is invalid, we leave the hash code unchanged so that the existing dentry can * be used. The exfat fs routines will return ENOENT or EINVAL as appropriate. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hash(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif { struct super_block *sb = dentry->d_sb; struct nls_table *t = EXFAT_SB(sb)->nls_io; const unsigned char *name = qstr->name; unsigned int len = exfat_striptail_len(qstr->len, qstr->name); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) unsigned long hash = init_name_hash(dentry); +#else + unsigned long hash = init_name_hash(); +#endif int i, charlen; wchar_t c; @@ -99,8 +140,17 @@ static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) return 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) static int exfat_d_cmp(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_cmp(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#else +static int exfat_d_cmp(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif { struct super_block *sb = dentry->d_sb; struct nls_table *t = EXFAT_SB(sb)->nls_io; @@ -132,12 +182,21 @@ const struct dentry_operations exfat_dentry_ops = { .d_compare = exfat_d_cmp, }; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_utf8_d_hash(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif { struct super_block *sb = dentry->d_sb; const unsigned char *name = qstr->name; unsigned int len = exfat_striptail_len(qstr->len, qstr->name); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) unsigned long hash = init_name_hash(dentry); +#else + unsigned long hash = init_name_hash(); +#endif int i, charlen; unicode_t u; @@ -157,8 +216,17 @@ static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr) return 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_utf8_d_cmp(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#else +static int exfat_utf8_d_cmp(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif { struct super_block *sb = dentry->d_sb; unsigned int alen = exfat_striptail_len(name->len, name->name); @@ -290,7 +358,7 @@ static int exfat_check_max_dentries(struct inode *inode) { if (EXFAT_B_TO_DEN(i_size_read(inode)) >= MAX_EXFAT_DENTRIES) { /* - * exFAT spec allows a dir to grow up to 8388608(256MB) + * exFAT spec allows a dir to grow upto 8388608(256MB) * dentries */ return -ENOSPC; @@ -318,7 +386,8 @@ static int exfat_find_empty_entry(struct inode *inode, hint_femp.eidx = EXFAT_HINT_NONE; if (ei->hint_femp.eidx != EXFAT_HINT_NONE) { - hint_femp = ei->hint_femp; + memcpy(&hint_femp, &ei->hint_femp, + sizeof(struct exfat_hint_femp)); ei->hint_femp.eidx = EXFAT_HINT_NONE; } @@ -518,7 +587,7 @@ static int exfat_add_entry(struct inode *inode, const char *path, if (ret) goto out; - info->dir = *p_dir; + memcpy(&info->dir, p_dir, sizeof(struct exfat_chain)); info->entry = dentry; info->flags = ALLOC_NO_FAT_CHAIN; info->type = type; @@ -529,10 +598,19 @@ static int exfat_add_entry(struct inode *inode, const char *path, info->size = 0; info->num_subdirs = 0; } else { + int count; + struct exfat_chain cdir; + info->attr = ATTR_SUBDIR; info->start_clu = start_clu; info->size = clu_size; - info->num_subdirs = EXFAT_MIN_SUBDIR; + + exfat_chain_set(&cdir, info->start_clu, + EXFAT_B_TO_CLU(info->size, sbi), info->flags); + count = exfat_count_dir_entries(sb, &cdir); + if (count < 0) + return -EIO; + info->num_subdirs = count + EXFAT_MIN_SUBDIR; } memset(&info->crtime, 0, sizeof(info->crtime)); memset(&info->mtime, 0, sizeof(info->mtime)); @@ -541,8 +619,16 @@ static int exfat_add_entry(struct inode *inode, const char *path, return ret; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,20) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + struct nameidata *nd) +#else +static int exfat_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +#endif { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -551,16 +637,23 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, loff_t i_pos; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); exfat_set_volume_dirty(sb); err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE, &info); +#ifdef MY_ABC_HERE + if (EXFAT_SB(sb)->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ exfat_clear_volume_dirty(sb); if (err) goto unlock; inode_inc_iversion(dir); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) dir->i_ctime = dir->i_mtime = current_time(dir); +#else + dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; +#endif if (IS_DIRSYNC(dir)) exfat_sync_inode(dir); else @@ -568,19 +661,27 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, i_pos = exfat_make_i_pos(&info); inode = exfat_build_inode(sb, &info, i_pos); - err = PTR_ERR_OR_ZERO(inode); - if (err) + if (IS_ERR(inode)) goto unlock; inode_inc_iversion(inode); inode->i_mtime = inode->i_atime = inode->i_ctime = +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) EXFAT_I(inode)->i_crtime = current_time(inode); +#else + EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + inode->i_create_time = EXFAT_I(inode)->i_crtime; +#endif +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&inode->i_atime); /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); unlock: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return err; } @@ -594,8 +695,6 @@ static int exfat_find(struct inode *dir, struct qstr *qname, struct super_block *sb = dir->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_inode_info *ei = EXFAT_I(dir); - struct exfat_dentry *ep, *ep2; - struct exfat_entry_set_cache *es; if (qname->len == 0) return -ENOENT; @@ -621,63 +720,91 @@ static int exfat_find(struct inode *dir, struct qstr *qname, dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name, num_entries, TYPE_ALL); - if (dentry < 0) + if ((dentry < 0) && (dentry != -EEXIST)) return dentry; /* -error value */ - info->dir = cdir; + memcpy(&info->dir, &cdir.dir, sizeof(struct exfat_chain)); info->entry = dentry; info->num_subdirs = 0; - es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES); - if (!es) - return -EIO; - ep = exfat_get_dentry_cached(es, 0); - ep2 = exfat_get_dentry_cached(es, 1); + /* root directory itself */ + if (unlikely(dentry == -EEXIST)) { + int num_clu = 0; - info->type = exfat_get_entry_type(ep); - info->attr = le16_to_cpu(ep->dentry.file.attr); - info->size = le64_to_cpu(ep2->dentry.stream.valid_size); - if ((info->type == TYPE_FILE) && (info->size == 0)) { - info->flags = ALLOC_NO_FAT_CHAIN; - info->start_clu = EXFAT_EOF_CLUSTER; - } else { - info->flags = ep2->dentry.stream.flags; - info->start_clu = - le32_to_cpu(ep2->dentry.stream.start_clu); - } + info->type = TYPE_DIR; + info->attr = ATTR_SUBDIR; + info->flags = ALLOC_FAT_CHAIN; + info->start_clu = sbi->root_dir; + memset(&info->crtime, 0, sizeof(info->crtime)); + memset(&info->mtime, 0, sizeof(info->mtime)); + memset(&info->atime, 0, sizeof(info->atime)); - exfat_get_entry_time(sbi, &info->crtime, - ep->dentry.file.create_tz, - ep->dentry.file.create_time, - ep->dentry.file.create_date, - ep->dentry.file.create_time_cs); - exfat_get_entry_time(sbi, &info->mtime, - ep->dentry.file.modify_tz, - ep->dentry.file.modify_time, - ep->dentry.file.modify_date, - ep->dentry.file.modify_time_cs); - exfat_get_entry_time(sbi, &info->atime, - ep->dentry.file.access_tz, - ep->dentry.file.access_time, - ep->dentry.file.access_date, - 0); - exfat_free_dentry_set(es, false); + exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); + if (exfat_count_num_clusters(sb, &cdir, &num_clu)) + return -EIO; + info->size = num_clu << sbi->cluster_size_bits; - if (ei->start_clu == EXFAT_FREE_CLUSTER) { - exfat_fs_error(sb, - "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", - i_size_read(dir), ei->dir.dir, ei->entry); - return -EIO; - } - - if (info->type == TYPE_DIR) { - exfat_chain_set(&cdir, info->start_clu, - EXFAT_B_TO_CLU(info->size, sbi), info->flags); count = exfat_count_dir_entries(sb, &cdir); if (count < 0) return -EIO; - info->num_subdirs = count + EXFAT_MIN_SUBDIR; + info->num_subdirs = count; + } else { + struct exfat_dentry *ep, *ep2; + struct exfat_entry_set_cache *es; + + es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES); + if (!es) + return -EIO; + ep = exfat_get_dentry_cached(es, 0); + ep2 = exfat_get_dentry_cached(es, 1); + + info->type = exfat_get_entry_type(ep); + info->attr = le16_to_cpu(ep->dentry.file.attr); + info->size = le64_to_cpu(ep2->dentry.stream.valid_size); + if ((info->type == TYPE_FILE) && (info->size == 0)) { + info->flags = ALLOC_NO_FAT_CHAIN; + info->start_clu = EXFAT_EOF_CLUSTER; + } else { + info->flags = ep2->dentry.stream.flags; + info->start_clu = + le32_to_cpu(ep2->dentry.stream.start_clu); + } + + if (ei->start_clu == EXFAT_FREE_CLUSTER) { + exfat_fs_error(sb, + "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", + i_size_read(dir), ei->dir.dir, ei->entry); + exfat_free_dentry_set(es, false); + return -EIO; + } + + exfat_get_entry_time(sbi, &info->crtime, + ep->dentry.file.create_tz, + ep->dentry.file.create_time, + ep->dentry.file.create_date, + ep->dentry.file.create_time_cs); + exfat_get_entry_time(sbi, &info->mtime, + ep->dentry.file.modify_tz, + ep->dentry.file.modify_time, + ep->dentry.file.modify_date, + ep->dentry.file.modify_time_cs); + exfat_get_entry_time(sbi, &info->atime, + ep->dentry.file.access_tz, + ep->dentry.file.access_time, + ep->dentry.file.access_date, + 0); + exfat_free_dentry_set(es, false); + + if (info->type == TYPE_DIR) { + exfat_chain_set(&cdir, info->start_clu, + EXFAT_B_TO_CLU(info->size, sbi), info->flags); + count = exfat_count_dir_entries(sb, &cdir); + if (count < 0) + return -EIO; + + info->num_subdirs = count + EXFAT_MIN_SUBDIR; + } } return 0; } @@ -687,8 +814,13 @@ static int exfat_d_anon_disconn(struct dentry *dentry) return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) +#else +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +#endif { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -698,7 +830,7 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, loff_t i_pos; mode_t i_mode; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); err = exfat_find(dir, &dentry->d_name, &info); if (err) { if (err == -ENOENT) { @@ -710,9 +842,10 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, i_pos = exfat_make_i_pos(&info); inode = exfat_build_inode(sb, &info, i_pos); - err = PTR_ERR_OR_ZERO(inode); - if (err) + if (IS_ERR(inode)) { + err = PTR_ERR(inode); goto unlock; + } i_mode = inode->i_mode; alias = d_find_alias(inode); @@ -731,8 +864,13 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, * In such case, we reuse an alias instead of new dentry */ if (d_unhashed(alias)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) WARN_ON(alias->d_name.hash_len != dentry->d_name.hash_len); +#else + WARN_ON(alias->d_name.len != + dentry->d_name.len); +#endif exfat_info(sb, "rehashed a dentry(%p) in read lookup", alias); d_drop(dentry); @@ -748,18 +886,18 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, d_move(alias, dentry); } iput(inode); - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return alias; } dput(alias); out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); if (!inode) exfat_d_version_set(dentry, inode_query_iversion(dir)); return d_splice_alias(inode, dentry); unlock: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return ERR_PTR(err); } @@ -775,7 +913,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) sector_t sector; int num_entries, entry, err = 0; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); exfat_chain_dup(&cdir, &ei->dir); entry = ei->entry; if (ei->dir.dir == DIR_DELETED) { @@ -807,10 +945,20 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) /* This doesn't modify ei */ ei->dir.dir = DIR_DELETED; +#ifdef MY_ABC_HERE + if (EXFAT_SB(sb)->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ exfat_clear_volume_dirty(sb); inode_inc_iversion(dir); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) dir->i_mtime = dir->i_atime = current_time(dir); +#else + dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE + dir->i_ctime = dir->i_mtime; +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&dir->i_atime); if (IS_DIRSYNC(dir)) exfat_sync_inode(dir); @@ -818,16 +966,27 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) mark_inode_dirty(dir); clear_nlink(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) inode->i_mtime = inode->i_atime = current_time(inode); +#else + inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE + inode->i_ctime = inode->i_mtime; +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&inode->i_atime); exfat_unhash_inode(inode); exfat_d_version_set(dentry, inode_query_iversion(dir)); unlock: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return err; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,20) static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#else +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +#endif { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -836,16 +995,23 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) loff_t i_pos; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); exfat_set_volume_dirty(sb); err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR, &info); +#ifdef MY_ABC_HERE + if (EXFAT_SB(sb)->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ exfat_clear_volume_dirty(sb); if (err) goto unlock; inode_inc_iversion(dir); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) dir->i_ctime = dir->i_mtime = current_time(dir); +#else + dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; +#endif if (IS_DIRSYNC(dir)) exfat_sync_inode(dir); else @@ -854,20 +1020,30 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) i_pos = exfat_make_i_pos(&info); inode = exfat_build_inode(sb, &info, i_pos); - err = PTR_ERR_OR_ZERO(inode); - if (err) + if (IS_ERR(inode)) { + err = PTR_ERR(inode); goto unlock; + } inode_inc_iversion(inode); inode->i_mtime = inode->i_atime = inode->i_ctime = +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) EXFAT_I(inode)->i_crtime = current_time(inode); +#else + EXFAT_I(inode)->i_crtime = CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + inode->i_create_time = EXFAT_I(inode)->i_crtime; +#endif +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&inode->i_atime); /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); unlock: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return err; } @@ -927,7 +1103,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) sector_t sector; int num_entries, entry, err; - mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); + __lock_super(sb); exfat_chain_dup(&cdir, &ei->dir); entry = ei->entry; @@ -971,10 +1147,20 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) goto unlock; } ei->dir.dir = DIR_DELETED; +#ifdef MY_ABC_HERE + if (sbi->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ exfat_clear_volume_dirty(sb); inode_inc_iversion(dir); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) dir->i_mtime = dir->i_atime = current_time(dir); +#else + dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE + dir->i_ctime = dir->i_mtime; +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&dir->i_atime); if (IS_DIRSYNC(dir)) exfat_sync_inode(dir); @@ -983,12 +1169,19 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) drop_nlink(dir); clear_nlink(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) inode->i_mtime = inode->i_atime = current_time(inode); +#else + inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE + inode->i_ctime = inode->i_mtime; +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&inode->i_atime); exfat_unhash_inode(inode); exfat_d_version_set(dentry, inode_query_iversion(dir)); unlock: - mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); + __unlock_super(sb); return err; } @@ -1029,7 +1222,7 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir, if (!epnew) return -EIO; - *epnew = *epold; + memcpy(epnew, epold, DENTRY_SIZE); if (exfat_get_entry_type(epnew) == TYPE_FILE) { epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); ei->attr |= ATTR_ARCHIVE; @@ -1049,7 +1242,7 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir, return -EIO; } - *epnew = *epold; + memcpy(epnew, epold, DENTRY_SIZE); exfat_update_bh(new_bh, sync); brelse(old_bh); brelse(new_bh); @@ -1094,6 +1287,11 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, if (!epmov) return -EIO; + /* check if the source and target directory is the same */ + if (exfat_get_entry_type(epmov) == TYPE_DIR && + le32_to_cpu(epmov->dentry.stream.start_clu) == p_newdir->dir) + return -EINVAL; + num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, epmov); if (num_old_entries < 0) @@ -1112,7 +1310,7 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, if (!epnew) return -EIO; - *epnew = *epmov; + memcpy(epnew, epmov, DENTRY_SIZE); if (exfat_get_entry_type(epnew) == TYPE_FILE) { epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); ei->attr |= ATTR_ARCHIVE; @@ -1132,7 +1330,7 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, return -EIO; } - *epnew = *epmov; + memcpy(epnew, epmov, DENTRY_SIZE); exfat_update_bh(new_bh, IS_DIRSYNC(inode)); brelse(mov_bh); brelse(new_bh); @@ -1313,20 +1511,28 @@ static int __exfat_rename(struct inode *old_parent_inode, */ new_ei->dir.dir = DIR_DELETED; } +#ifdef MY_ABC_HERE + if (sbi->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ exfat_clear_volume_dirty(sb); out: return ret; } static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) +#else + struct inode *new_dir, struct dentry *new_dentry) +#endif { struct inode *old_inode, *new_inode; struct super_block *sb = old_dir->i_sb; loff_t i_pos; int err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) /* * The VFS already checks for existence, so for local filesystems * the RENAME_NOREPLACE implementation is equivalent to plain rename. @@ -1334,8 +1540,9 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, */ if (flags & ~RENAME_NOREPLACE) return -EINVAL; +#endif - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; @@ -1345,7 +1552,19 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, inode_inc_iversion(new_dir); new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + current_time(new_dir); +#else + CURRENT_TIME_SEC; +#endif +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) EXFAT_I(new_dir)->i_crtime = current_time(new_dir); +#else + EXFAT_I(new_dir)->i_crtime = CURRENT_TIME_SEC; +#endif +#endif /* MY_ABC_HERE */ exfat_truncate_atime(&new_dir->i_atime); if (IS_DIRSYNC(new_dir)) exfat_sync_inode(new_dir); @@ -1368,7 +1587,11 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, } inode_inc_iversion(old_dir); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); +#else + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; +#endif if (IS_DIRSYNC(old_dir)) exfat_sync_inode(old_dir); else @@ -1386,12 +1609,24 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, exfat_warn(sb, "abnormal access to an inode dropped"); WARN_ON(new_inode->i_nlink == 0); } +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + new_inode->i_ctime = current_time(new_inode); +#else + new_inode->i_ctime = CURRENT_TIME_SEC; +#endif +#else new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime = - current_time(new_inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + current_time(new_inode); +#else + CURRENT_TIME_SEC; +#endif +#endif /* MY_ABC_HERE */ } unlock: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return err; } @@ -1404,4 +1639,27 @@ const struct inode_operations exfat_dir_inode_operations = { .rename = exfat_rename, .setattr = exfat_setattr, .getattr = exfat_getattr, +#ifdef CONFIG_EXFAT_VIRTUAL_XATTR + .listxattr = exfat_listxattr, +#endif +#ifdef MY_ABC_HERE + .syno_getattr = exfat_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_bit = exfat_syno_get_archive_bit, + .syno_set_archive_bit = exfat_syno_set_archive_bit, +#if defined(CONFIG_SYNO_FS_WINACL) || defined(SYNO_FS_SYNO_ACL) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + .syno_archive_bit_change_ok = exfat_syno_arbit_chg_ok, +#else + .syno_arbit_chg_ok = exfat_syno_arbit_chg_ok, +#endif +#endif /* CONFIG_SYNO_FS_WINACL || SYNO_FS_SYNO_ACL */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) + .syno_get_crtime = exfat_syno_get_create_time, +#endif + .syno_set_crtime = exfat_syno_set_create_time, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c index 314d5407a1be..24c7d6a263a1 100644 --- a/fs/exfat/nls.c +++ b/fs/exfat/nls.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. @@ -8,10 +11,9 @@ #include #include -#include "exfat_raw.h" #include "exfat_fs.h" -/* Upcase table macro */ +/* Upcase tabel macro */ #define EXFAT_NUM_UPCASE (2918) #define UTBL_COUNT (0x10000) @@ -659,7 +661,11 @@ static int exfat_load_upcase_table(struct super_block *sb, unsigned char skip = false; unsigned short *upcase_table; - upcase_table = kvcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); +#ifdef MY_ABC_HERE + upcase_table = kvmalloc(UTBL_COUNT * sizeof(unsigned short), GFP_KERNEL | __GFP_ZERO); +#else + upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); +#endif /* MY_ABC_HERE */ if (!upcase_table) return -ENOMEM; @@ -715,7 +721,11 @@ static int exfat_load_default_upcase_table(struct super_block *sb) unsigned short uni = 0, *upcase_table; unsigned int index = 0; - upcase_table = kvcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); +#ifdef MY_ABC_HERE + upcase_table = kvmalloc(UTBL_COUNT * sizeof(unsigned short), GFP_KERNEL | __GFP_ZERO); +#else + upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); +#endif /* MY_ABC_HERE */ if (!upcase_table) return -ENOMEM; @@ -803,5 +813,9 @@ int exfat_create_upcase_table(struct super_block *sb) void exfat_free_upcase_table(struct exfat_sb_info *sbi) { +#ifdef MY_ABC_HERE kvfree(sbi->vol_utbl); +#else + kfree(sbi->vol_utbl); +#endif /* MY_ABC_HERE */ } diff --git a/fs/exfat/super.c b/fs/exfat/super.c index c6d8d2e53486..b2257dfde38f 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -1,10 +1,11 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. */ -#include -#include #include #include #include @@ -14,13 +15,16 @@ #include #include #include -#include #include #include +#include -#include "exfat_raw.h" #include "exfat_fs.h" +static int exfat_init_sb_info(struct super_block *sb); +static int exfat_parse_options(struct super_block *sb, char *options, int silent, + struct exfat_mount_options *opts); + static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; static struct kmem_cache *exfat_inode_cachep; @@ -37,6 +41,10 @@ static void exfat_delayed_free(struct rcu_head *p) unload_nls(sbi->nls_io); exfat_free_iocharset(sbi); exfat_free_upcase_table(sbi); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + /* mutex_init is in exfat_fill_super function. only for 3.7+ */ + mutex_destroy(&sbi->s_lock); +#endif kfree(sbi); } @@ -44,14 +52,32 @@ static void exfat_put_super(struct super_block *sb) { struct exfat_sb_info *sbi = EXFAT_SB(sb); - mutex_lock(&sbi->s_lock); + __lock_super(sb); exfat_free_bitmap(sbi); brelse(sbi->boot_bh); - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); call_rcu(&sbi->rcu, exfat_delayed_free); + + exfat_warn(sb, "exfat unmounted successfully"); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) +static void exfat_write_super(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + /* If there are some dirty buffers in the bdev inode */ + __lock_super(sb); + sync_blockdev(sb->s_bdev); +#ifdef MY_ABC_HERE + if (sbi->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ + exfat_clear_volume_dirty(sb); + __unlock_super(sb); +} +#endif + static int exfat_sync_fs(struct super_block *sb, int wait) { struct exfat_sb_info *sbi = EXFAT_SB(sb); @@ -61,11 +87,14 @@ static int exfat_sync_fs(struct super_block *sb, int wait) return 0; /* If there are some dirty buffers in the bdev inode */ - mutex_lock(&sbi->s_lock); + __lock_super(sb); sync_blockdev(sb->s_bdev); +#ifdef MY_ABC_HERE + if (sbi->vol_clean_on_mount) +#endif /* MY_ABC_HERE */ if (exfat_clear_volume_dirty(sb)) err = -EIO; - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); return err; } @@ -76,12 +105,12 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) unsigned long long id = huge_encode_dev(sb->s_bdev->bd_dev); if (sbi->used_clusters == EXFAT_CLUSTERS_UNTRACKED) { - mutex_lock(&sbi->s_lock); + __lock_super(sb); if (exfat_count_used_clusters(sb, &sbi->used_clusters)) { - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); return -EIO; } - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); } buf->f_type = sb->s_magic; @@ -89,7 +118,8 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_blocks = sbi->num_clusters - 2; /* clu 0 & 1 */ buf->f_bfree = buf->f_blocks - sbi->used_clusters; buf->f_bavail = buf->f_bfree; - buf->f_fsid = u64_to_fsid(id); + buf->f_fsid.val[0] = (unsigned int)id; + buf->f_fsid.val[1] = (unsigned int)(id >> 32); /* Unicode utf16 255 characters */ buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE; return 0; @@ -145,22 +175,37 @@ int exfat_clear_volume_dirty(struct super_block *sb) return exfat_set_vol_flags(sb, sbi->vol_flags & ~VOLUME_DIRTY); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) static int exfat_show_options(struct seq_file *m, struct dentry *root) { - struct super_block *sb = root->d_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); +#else +static int exfat_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct exfat_sb_info *sbi = EXFAT_SB(mnt->mnt_sb); +#endif struct exfat_mount_options *opts = &sbi->options; /* Show partition info */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID)) seq_printf(m, ",uid=%u", from_kuid_munged(&init_user_ns, opts->fs_uid)); if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID)) seq_printf(m, ",gid=%u", from_kgid_munged(&init_user_ns, opts->fs_gid)); +#else + if (opts->fs_uid != 0) + seq_printf(m, ",uid=%u", opts->fs_uid); + if (opts->fs_gid != 0) + seq_printf(m, ",gid=%u", opts->fs_gid); +#endif + seq_printf(m, ",fmask=%04o,dmask=%04o", opts->fs_fmask, opts->fs_dmask); if (opts->allow_utime) seq_printf(m, ",allow_utime=%04o", opts->allow_utime); + if (opts->quiet) + seq_puts(m, ",quiet"); if (opts->utf8) seq_puts(m, ",iocharset=utf8"); else if (sbi->nls_io) @@ -186,7 +231,11 @@ static struct inode *exfat_alloc_inode(struct super_block *sb) if (!ei) return NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) init_rwsem(&ei->truncate_lock); +#else + init_rwsem(&ei->i_alloc_sem); +#endif return &ei->vfs_inode; } @@ -195,15 +244,39 @@ static void exfat_free_inode(struct inode *inode) kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); } +static int exfat_remount(struct super_block *sb, int *flags, char *opt) +{ + int ret = 0; + + *flags |= SB_NODIRATIME; + + /* volume flag will be updated in exfat_sync_fs */ + sync_filesystem(sb); + + ret = exfat_parse_options(sb, opt, 0, &EXFAT_SB(sb)->options); + if (ret) + exfat_err(sb, "failed to parse options"); + + return ret; +} + static const struct super_operations exfat_sops = { .alloc_inode = exfat_alloc_inode, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) .free_inode = exfat_free_inode, +#else + .destroy_inode = exfat_free_inode, +#endif .write_inode = exfat_write_inode, .evict_inode = exfat_evict_inode, .put_super = exfat_put_super, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + .write_super = exfat_write_super, +#endif .sync_fs = exfat_sync_fs, .statfs = exfat_statfs, .show_options = exfat_show_options, + .remount_fs = exfat_remount, }; enum { @@ -214,7 +287,10 @@ enum { Opt_fmask, Opt_allow_utime, Opt_charset, - Opt_errors, + Opt_quiet, + Opt_err_cont, + Opt_err_panic, + Opt_err_ro, Opt_discard, Opt_time_offset, @@ -225,90 +301,108 @@ enum { Opt_codepage, }; -static const struct constant_table exfat_param_enums[] = { - { "continue", EXFAT_ERRORS_CONT }, - { "panic", EXFAT_ERRORS_PANIC }, - { "remount-ro", EXFAT_ERRORS_RO }, - {} +static const match_table_t exfat_tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%o"}, + {Opt_dmask, "dmask=%o"}, + {Opt_fmask, "fmask=%o"}, + {Opt_allow_utime, "allow_utime=%o"}, + {Opt_charset, "iocharset=%s"}, + {Opt_quiet, "quiet"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, + {Opt_discard, "discard"}, + {Opt_time_offset, "time_offset=%d"}, + + /* Deprecated options */ + {Opt_utf8, "utf8"}, + {Opt_debug, "debug"}, + {Opt_namecase, "namecase=%u"}, + {Opt_codepage, "codepage=%u"}, }; -static const struct fs_parameter_spec exfat_parameters[] = { - fsparam_u32("uid", Opt_uid), - fsparam_u32("gid", Opt_gid), - fsparam_u32oct("umask", Opt_umask), - fsparam_u32oct("dmask", Opt_dmask), - fsparam_u32oct("fmask", Opt_fmask), - fsparam_u32oct("allow_utime", Opt_allow_utime), - fsparam_string("iocharset", Opt_charset), - fsparam_enum("errors", Opt_errors, exfat_param_enums), - fsparam_flag("discard", Opt_discard), - fsparam_s32("time_offset", Opt_time_offset), - __fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated, - NULL), - __fsparam(NULL, "debug", Opt_debug, fs_param_deprecated, - NULL), - __fsparam(fs_param_is_u32, "namecase", Opt_namecase, - fs_param_deprecated, NULL), - __fsparam(fs_param_is_u32, "codepage", Opt_codepage, - fs_param_deprecated, NULL), - {} -}; - -static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) +static int __exfat_parse_option(struct super_block *sb, char *p, substring_t *args, int token, int silent) { - struct exfat_sb_info *sbi = fc->s_fs_info; + struct exfat_sb_info *sbi = sb->s_fs_info; struct exfat_mount_options *opts = &sbi->options; - struct fs_parse_result result; - int opt; + int option; + char *tmpstr; - opt = fs_parse(fc, exfat_parameters, param, &result); - if (opt < 0) - return opt; - - switch (opt) { + switch (token) { case Opt_uid: - opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); + if (match_int(&args[0], &option)) + return -EINVAL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_uid = make_kuid(current_user_ns(), option); +#else + opts->fs_uid = option; +#endif break; case Opt_gid: - opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); + if (match_int(&args[0], &option)) + return -EINVAL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_gid = make_kgid(current_user_ns(), option); +#else + opts->fs_gid = option; +#endif break; case Opt_umask: - opts->fs_fmask = result.uint_32; - opts->fs_dmask = result.uint_32; - break; case Opt_dmask: - opts->fs_dmask = result.uint_32; - break; case Opt_fmask: - opts->fs_fmask = result.uint_32; + if (match_octal(&args[0], &option)) + return -EINVAL; + if (token != Opt_dmask) + opts->fs_fmask = option; + if (token != Opt_fmask) + opts->fs_dmask = option; break; case Opt_allow_utime: - opts->allow_utime = result.uint_32 & 0022; + if (match_octal(&args[0], &option)) + return -EINVAL; + opts->allow_utime = option & (S_IWGRP | S_IWOTH); break; case Opt_charset: exfat_free_iocharset(sbi); - opts->iocharset = param->string; - param->string = NULL; + tmpstr = match_strdup(&args[0]); + if (!tmpstr) + return -ENOMEM; + opts->iocharset = tmpstr; break; - case Opt_errors: - opts->errors = result.uint_32; + case Opt_quiet: + opts->quiet = 1; + break; + case Opt_err_cont: + opts->errors = EXFAT_ERRORS_CONT; + break; + case Opt_err_panic: + opts->errors = EXFAT_ERRORS_PANIC; + break; + case Opt_err_ro: + opts->errors = EXFAT_ERRORS_RO; break; case Opt_discard: opts->discard = 1; break; case Opt_time_offset: + if (match_int(&args[0], &option)) + return -EINVAL; /* * Make the limit 24 just in case someone invents something * unusual. */ - if (result.int_32 < -24 * 60 || result.int_32 > 24 * 60) + if (option < -24 * 60 || option > 24 * 60) return -EINVAL; - opts->time_offset = result.int_32; + opts->time_offset = option; break; case Opt_utf8: case Opt_debug: case Opt_namecase: case Opt_codepage: + if (!silent) + exfat_warn(sb, "deprecated mount option \"%s\" ", p); break; default: return -EINVAL; @@ -317,6 +411,52 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) return 0; } +static int exfat_parse_options(struct super_block *sb, char *options, int silent, + struct exfat_mount_options *opts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int ret; + + if (!options) + goto out; + +#ifdef MY_ABC_HERE + opts->quiet = 1; +#endif /* MY_ABC_HERE */ + + while ((p = strsep(&options, ",")) != NULL) { + int token; + + if (!*p) + continue; + token = match_token(p, exfat_tokens, args); + ret = __exfat_parse_option(sb, p, args, token, silent); + if (ret < 0) { + if (ret == -EINVAL && !silent) { + exfat_msg(sb, KERN_ERR, + "unrecognized mount option \"%s\" " + "or missing value", p); + } + return ret; + } + } + + if (opts->allow_utime == (unsigned short)-1) + opts->allow_utime = ~opts->fs_dmask & 0022; + + if (opts->discard) { + struct request_queue *q = bdev_get_queue(sb->s_bdev); + + if (!blk_queue_discard(q)) { + exfat_warn(sb, "mounting with \"discard\" option, but the device does not support discard"); + opts->discard = 0; + } + } +out: + return 0; +} + static void exfat_hash_init(struct super_block *sb) { struct exfat_sb_info *sbi = EXFAT_SB(sb); @@ -341,6 +481,7 @@ static int exfat_read_root(struct inode *inode) ei->flags = ALLOC_FAT_CHAIN; ei->type = TYPE_DIR; ei->version = 0; + ei->rwoffset = 0; ei->hint_bmap.off = EXFAT_EOF_CLUSTER; ei->hint_stat.eidx = 0; ei->hint_stat.clu = sbi->root_dir; @@ -354,7 +495,11 @@ static int exfat_read_root(struct inode *inode) num_subdirs = exfat_count_dir_entries(sb, &cdir); if (num_subdirs < 0) return -EIO; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) set_nlink(inode, num_subdirs + EXFAT_MIN_SUBDIR); +#else + inode->i_nlink = num_subdirs + EXFAT_MIN_SUBDIR; +#endif inode->i_uid = sbi->options.fs_uid; inode->i_gid = sbi->options.fs_gid; @@ -372,8 +517,19 @@ static int exfat_read_root(struct inode *inode) exfat_save_attr(inode, ATTR_SUBDIR); inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) current_time(inode); +#else + CURRENT_TIME_SEC; +#endif +#ifdef MY_ABC_HERE +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + inode->i_create_time = ei->i_crtime; +#endif +#endif /* MY_ABC_HERE */ + exfat_truncate_atime(&inode->i_atime); + exfat_cache_init_inode(inode); return 0; } @@ -381,7 +537,8 @@ static int exfat_calibrate_blocksize(struct super_block *sb, int logical_sect) { struct exfat_sb_info *sbi = EXFAT_SB(sb); - if (!is_power_of_2(logical_sect)) { + if (!is_power_of_2(logical_sect) || + logical_sect < 512 || logical_sect > 4096) { exfat_err(sb, "bogus logical sector size %u", logical_sect); return -EIO; } @@ -450,25 +607,6 @@ static int exfat_read_boot_sector(struct super_block *sb) return -EINVAL; } - /* - * sect_size_bits could be at least 9 and at most 12. - */ - if (p_boot->sect_size_bits < EXFAT_MIN_SECT_SIZE_BITS || - p_boot->sect_size_bits > EXFAT_MAX_SECT_SIZE_BITS) { - exfat_err(sb, "bogus sector size bits : %u\n", - p_boot->sect_size_bits); - return -EINVAL; - } - - /* - * sect_per_clus_bits could be at least 0 and at most 25 - sect_size_bits. - */ - if (p_boot->sect_per_clus_bits > EXFAT_MAX_SECT_PER_CLUS_BITS(p_boot)) { - exfat_err(sb, "bogus sectors bits per cluster : %u\n", - p_boot->sect_per_clus_bits); - return -EINVAL; - } - sbi->sect_per_clus = 1 << p_boot->sect_per_clus_bits; sbi->sect_per_clus_bits = p_boot->sect_per_clus_bits; sbi->cluster_size_bits = p_boot->sect_per_clus_bits + @@ -495,19 +633,19 @@ static int exfat_read_boot_sector(struct super_block *sb) sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED; /* check consistencies */ - if ((u64)sbi->num_FAT_sectors << p_boot->sect_size_bits < - (u64)sbi->num_clusters * 4) { +#ifdef MY_ABC_HERE + sbi->vol_clean_on_mount = (sbi->vol_flags & VOLUME_DIRTY) ? false : true; +#endif /* MY_ABC_HERE */ + if (sbi->num_FAT_sectors << p_boot->sect_size_bits < + sbi->num_clusters * 4) { exfat_err(sb, "bogus fat length"); return -EINVAL; } - if (sbi->data_start_sector < - (u64)sbi->FAT1_start_sector + - (u64)sbi->num_FAT_sectors * p_boot->num_fats) { + sbi->FAT1_start_sector + sbi->num_FAT_sectors * p_boot->num_fats) { exfat_err(sb, "bogus data start sector"); return -EINVAL; } - if (sbi->vol_flags & VOLUME_DIRTY) exfat_warn(sb, "Volume was not properly unmounted. Some data may be corrupt. Please run fsck."); if (sbi->vol_flags & MEDIA_FAILURE) @@ -615,32 +753,38 @@ static int __exfat_fill_super(struct super_block *sb) return ret; } -static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) +static int exfat_fill_super(struct super_block *sb, void *data, int silent) { - struct exfat_sb_info *sbi = sb->s_fs_info; - struct exfat_mount_options *opts = &sbi->options; + struct exfat_sb_info *sbi; + struct exfat_mount_options *opts; struct inode *root_inode; int err; - if (opts->allow_utime == (unsigned short)-1) - opts->allow_utime = ~opts->fs_dmask & 0022; - - if (opts->discard) { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - - if (!blk_queue_discard(q)) { - exfat_warn(sb, "mounting with \"discard\" option, but the device does not support discard"); - opts->discard = 0; - } + err = exfat_init_sb_info(sb); + if (err) { + exfat_err(sb, "failed to initialize superblock info"); + goto failed; } + sbi = sb->s_fs_info; + opts = &sbi->options; + sb->s_flags |= SB_NODIRATIME; sb->s_magic = EXFAT_SUPER_MAGIC; sb->s_op = &exfat_sops; + sb->s_xattr = exfat_xattr_handlers; sb->s_time_gran = 10 * NSEC_PER_MSEC; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS; sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS; +#endif + + err = exfat_parse_options(sb, data, silent, &sbi->options); + if (err) { + exfat_err(sb, "failed to parse options"); + goto check_nls_io; + } err = __exfat_fill_super(sb); if (err) { @@ -686,13 +830,19 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) exfat_hash_inode(root_inode, EXFAT_I(root_inode)->i_pos); insert_inode_hash(root_inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) sb->s_root = d_make_root(root_inode); +#else + sb->s_root = d_alloc_root(root_inode); +#endif if (!sb->s_root) { exfat_err(sb, "failed to get the root dentry"); err = -ENOMEM; goto put_inode; } + exfat_warn(sb, "exfat mounted successfully"); + return 0; put_inode: @@ -708,42 +858,16 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) unload_nls(sbi->nls_io); exfat_free_iocharset(sbi); sb->s_fs_info = NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + mutex_destroy(&sbi->s_lock); +#endif kfree(sbi); + +failed: return err; } -static int exfat_get_tree(struct fs_context *fc) -{ - return get_tree_bdev(fc, exfat_fill_super); -} - -static void exfat_free(struct fs_context *fc) -{ - struct exfat_sb_info *sbi = fc->s_fs_info; - - if (sbi) { - exfat_free_iocharset(sbi); - kfree(sbi); - } -} - -static int exfat_reconfigure(struct fs_context *fc) -{ - fc->sb_flags |= SB_NODIRATIME; - - /* volume flag will be updated in exfat_sync_fs */ - sync_filesystem(fc->root->d_sb); - return 0; -} - -static const struct fs_context_operations exfat_context_ops = { - .parse_param = exfat_parse_param, - .get_tree = exfat_get_tree, - .free = exfat_free, - .reconfigure = exfat_reconfigure, -}; - -static int exfat_init_fs_context(struct fs_context *fc) +static int exfat_init_sb_info(struct super_block *sb) { struct exfat_sb_info *sbi; @@ -751,7 +875,9 @@ static int exfat_init_fs_context(struct fs_context *fc) if (!sbi) return -ENOMEM; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) mutex_init(&sbi->s_lock); +#endif ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); @@ -763,16 +889,20 @@ static int exfat_init_fs_context(struct fs_context *fc) sbi->options.iocharset = exfat_default_iocharset; sbi->options.errors = EXFAT_ERRORS_RO; - fc->s_fs_info = sbi; - fc->ops = &exfat_context_ops; + sb->s_fs_info = sbi; return 0; } +static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); +} + static struct file_system_type exfat_fs_type = { .owner = THIS_MODULE, .name = "exfat", - .init_fs_context = exfat_init_fs_context, - .parameters = exfat_parameters, + .mount = exfat_fs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; @@ -781,10 +911,6 @@ static void exfat_inode_init_once(void *foo) { struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; - spin_lock_init(&ei->cache_lru_lock); - ei->nr_caches = 0; - ei->cache_valid_id = EXFAT_CACHE_VALID + 1; - INIT_LIST_HEAD(&ei->cache_lru); INIT_HLIST_NODE(&ei->i_hash_fat); inode_init_once(&ei->vfs_inode); } @@ -793,6 +919,8 @@ static int __init init_exfat_fs(void) { int err; + pr_info("exFAT: file-system version %s\n", EXFAT_VERSION); + err = exfat_cache_init(); if (err) return err; @@ -821,11 +949,13 @@ static int __init init_exfat_fs(void) static void __exit exit_exfat_fs(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) /* * Make sure all delayed rcu free inodes are flushed before we * destroy cache. */ rcu_barrier(); +#endif kmem_cache_destroy(exfat_inode_cachep); unregister_filesystem(&exfat_fs_type); exfat_cache_shutdown(); @@ -834,7 +964,9 @@ static void __exit exit_exfat_fs(void) module_init(init_exfat_fs); module_exit(exit_exfat_fs); +#ifdef MODULE_ALIAS_FS MODULE_ALIAS_FS("exfat"); +#endif MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("exFAT filesystem support"); MODULE_AUTHOR("Samsung Electronics Co., Ltd."); diff --git a/fs/exfat/version.h b/fs/exfat/version.h new file mode 100644 index 000000000000..01628c3e24fd --- /dev/null +++ b/fs/exfat/version.h @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#define EXFAT_BASE_VERSION "5.8" +#define EXFAT_EXTRAVERSION "2" +#define EXFAT_VERSION EXFAT_BASE_VERSION "-" EXFAT_EXTRAVERSION diff --git a/fs/exfat/xattr.c b/fs/exfat/xattr.c new file mode 100644 index 000000000000..833bdbd6cea4 --- /dev/null +++ b/fs/exfat/xattr.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * xattr.c: exFAT code for supporting xattr(Extended File Attributes) + */ + +#include "exfat_fs.h" + +#ifdef CONFIG_EXFAT_VIRTUAL_XATTR + +#include +#include +#include +#include + +#ifndef CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL +#define CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL ("undefined") +#endif + +static const char default_xattr[] = CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL; + +static int can_support(const char *name) +{ + if (!name || strcmp(name, "security.selinux")) + return -1; + return 0; +} + +ssize_t exfat_listxattr(struct dentry *dentry, char *list, size_t size) +{ + return 0; +} + +static int __exfat_xattr_check_support(const char *name) +{ + if (can_support(name)) + return -EOPNOTSUPP; + + return 0; +} + +ssize_t __exfat_getxattr(const char *name, void *value, size_t size) +{ + if (can_support(name)) + return -EOPNOTSUPP; + + if ((size > strlen(default_xattr)+1) && value) + strcpy(value, default_xattr); + + return strlen(default_xattr); +} + +static int exfat_xattr_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *buffer, size_t size) +{ + return __exfat_getxattr(name, buffer, size); +} + +static int exfat_xattr_set(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, + int flags) +{ + return __exfat_xattr_check_support(name); +} + +static const struct xattr_handler exfat_xattr_handler = { + .prefix = "", /* match anything */ + .get = exfat_xattr_get, + .set = exfat_xattr_set, +}; + +const struct xattr_handler *exfat_xattr_handlers[] = { + &exfat_xattr_handler, + NULL +}; + +#endif /* CONFIG_EXFAT_VIRTUAL_XATTR */ diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 2dd55b172d57..3b7c93f7652f 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) Neil Brown 2002 @@ -18,6 +21,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #define dprintk(fmt, args...) do{}while(0) @@ -47,7 +54,12 @@ find_acceptable_alias(struct dentry *result, struct dentry *dentry, *toput = NULL; struct inode *inode; +#ifdef MY_ABC_HERE + // a disconnected dentry isn't accepatable for ACL inheritance. + if (!(IS_SYNOACL(result) && (result->d_flags & DCACHE_DISCONNECTED)) && acceptable(context, result)) +#else /* MY_ABC_HERE */ if (acceptable(context, result)) +#endif /* MY_ABC_HERE */ return result; inode = result->d_inode; @@ -57,7 +69,12 @@ find_acceptable_alias(struct dentry *result, spin_unlock(&inode->i_lock); if (toput) dput(toput); +#ifdef MY_ABC_HERE + // a disconnected dentry isn't accepatable for ACL inheritance. + if (dentry != result && !(IS_SYNOACL(result) && (result->d_flags & DCACHE_DISCONNECTED)) && acceptable(context, dentry)) { +#else /* MY_ABC_HERE */ if (dentry != result && acceptable(context, dentry)) { +#endif /* MY_ABC_HERE */ dput(result); return dentry; } @@ -443,6 +460,33 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, * file handle is stale or to get a reference to an inode without * risking the high overhead caused by directory reconnect. */ +#ifdef MY_ABC_HERE + /* + * a disconnected dentry isn't acceptable for locker to determine it in + * whitelist or not. we can not return it. + */ + if (!acceptable) { + struct inode *inode = d_inode(result); + + if (inode->i_op->syno_locker_state_get && (result->d_flags & DCACHE_DISCONNECTED)) { + err = -EACCES; + goto err_result; + } + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* + * a disconnected dentry isn't accepatable for ACL inheritance. we can not return it. + */ + if (!acceptable) { + if (IS_SYNOACL(result) && (result->d_flags & DCACHE_DISCONNECTED)) { + err = -EACCES; + goto err_result; + } + } +#endif /* MY_ABC_HERE */ + if (!acceptable) return result; @@ -491,6 +535,19 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, * file handle. If this fails we'll have to give up. */ err = -ESTALE; + +#ifdef MY_ABC_HERE + /* Let btrfs use get_parent to get the real parent of file. + * ext4 cannot use get_parent for file, it's only work on dir. + * and non-btrfs is protect by subtreecheck which can get parent from fh_to_parent. + */ + if (result->d_sb->s_magic == BTRFS_SUPER_MAGIC) { + target_dir = nop->get_parent(result); + if (target_dir && !IS_ERR(target_dir)) + goto reconnect_target_dir; + } +#endif /* MY_ABC_HERE */ + if (!nop->fh_to_parent) goto err_result; @@ -502,6 +559,9 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, if (IS_ERR(target_dir)) goto err_result; +#ifdef MY_ABC_HERE +reconnect_target_dir: +#endif /* MY_ABC_HERE */ /* * And as usual we need to make sure the parent directory is * connected to the filesystem root. The VFS really doesn't diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 49e7af6cc93f..9d034fe88578 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -13,6 +13,7 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \ xattr_user.o fast_commit.o ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o +ext4-$(CONFIG_SYNO_EXT4_WINACL) += syno_acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o ext4-inode-test-objs += inode-test.o obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index ca50c90adc4c..162aa5ae05bc 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/dir.c @@ -46,7 +49,11 @@ static int is_dx_dir(struct inode *inode) { struct super_block *sb = inode->i_sb; +#ifdef MY_ABC_HERE + if ((is_syno_ext(inode->i_sb) || ext4_has_feature_dir_index(inode->i_sb)) && +#else /* MY_ABC_HERE */ if (ext4_has_feature_dir_index(inode->i_sb) && +#endif /* MY_ABC_HERE */ ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) || ((inode->i_size >> sb->s_blocksize_bits) == 1) || ext4_has_inline_data(inode))) @@ -91,13 +98,27 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, else return 0; +#ifdef MY_ABC_HERE + if (filp) { + if (printk_ratelimit()) + ext4_error_file(filp, function, line, bh->b_blocknr, + "bad entry in directory: %s - offset=%u, " + "inode=%u, rec_len=%d, name_len=%d, size=%d", + error_msg, offset, le32_to_cpu(de->inode), + rlen, de->name_len, size); + } +#else /* MY_ABC_HERE */ if (filp) ext4_error_file(filp, function, line, bh->b_blocknr, "bad entry in directory: %s - offset=%u, " "inode=%u, rec_len=%d, name_len=%d, size=%d", error_msg, offset, le32_to_cpu(de->inode), rlen, de->name_len, size); +#endif /* MY_ABC_HERE */ else +#ifdef MY_ABC_HERE + if (printk_ratelimit()) +#endif /* MY_ABC_HERE */ ext4_error_inode(dir, function, line, bh->b_blocknr, "bad entry in directory: %s - offset=%u, " "inode=%u, rec_len=%d, name_len=%d, size=%d", diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 115a77b96e5e..5eaa007ca784 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * ext4.h @@ -621,6 +624,12 @@ struct ext4_new_group_data { __u32 free_clusters_count; }; +#ifdef MY_ABC_HERE +struct ext4_ioctl_feature_flags { + __u32 syno_capability; +}; +#endif /* MY_ABC_HERE */ + /* Indexes used to index group tables in ext4_new_group_data */ enum { BLOCK_BITMAP = 0, /* block bitmap */ @@ -715,6 +724,11 @@ enum { #define EXT4_IOC_GETSTATE _IOW('f', 41, __u32) #define EXT4_IOC_GET_ES_CACHE _IOWR('f', 42, struct fiemap) +#ifdef MY_ABC_HERE +#define EXT4_IOC_GET_FEATURES _IOR('f', 50, struct ext4_ioctl_feature_flags) +#define EXT4_IOC_SET_FEATURES _IOW('f', 50, struct ext4_ioctl_feature_flags[2]) +#endif /* MY_ABC_HERE */ + #define EXT4_IOC_SHUTDOWN _IOR ('X', 125, __u32) /* @@ -823,6 +837,9 @@ struct ext4_inode { __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ __le32 i_version_hi; /* high 32 bits for 64-bit version */ __le32 i_projid; /* Project ID */ +#ifdef MY_ABC_HERE + __le32 i_syno_archive_bit; /* Windows file attributes and attribute bits for SMB and Syno backup */ +#endif /* MY_ABC_HERE */ }; struct move_extent { @@ -946,6 +963,9 @@ do { \ #define i_uid_high osd2.linux2.l_i_uid_high #define i_gid_high osd2.linux2.l_i_gid_high #define i_checksum_lo osd2.linux2.l_i_checksum_lo +#ifdef MY_ABC_HERE +#define i_reserved osd2.linux2.l_i_reserved +#endif /* MY_ABC_HERE */ #elif defined(__GNU__) @@ -962,6 +982,19 @@ do { \ #endif /* defined(__KERNEL__) || defined(__linux__) */ +#ifdef MY_ABC_HERE +#define ext3_archive_bit_lo i_checksum_lo +#define ext3_archive_bit_high i_reserved +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define i_ext3_create_time i_disk_version +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define SYNO_HASH_MAGIC 0x01856E96 // 25521814 +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + #include "extents_status.h" #include "fast_commit.h" @@ -1155,6 +1188,9 @@ struct ext4_inode_info { __u32 i_csum_seed; kprojid_t i_projid; +#ifdef MY_ABC_HERE + bool i_is_swapfile; +#endif /* MY_ABC_HERE */ }; /* @@ -1176,6 +1212,9 @@ struct ext4_inode_info { * Mount flags set via mount options or defaults */ #define EXT4_MOUNT_NO_MBCACHE 0x00001 /* Do not use mbcache */ +#ifdef MY_ABC_HERE +#define EXT4_MOUNT_SYNO_ACL 0x00002 /* Synology Access Control Lists */ +#endif /* MY_ABC_HERE */ #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ #define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ @@ -1213,6 +1252,9 @@ struct ext4_inode_info { #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ #define EXT4_MOUNT_WARN_ON_ERROR 0x2000000 /* Trigger WARN_ON on error */ #define EXT4_MOUNT_PREFETCH_BLOCK_BITMAPS 0x4000000 +#ifdef MY_ABC_HERE +#define EXT4_MOUNT_SYNO_RBD_META 0x6000000 /* RBD meta */ +#endif /* MY_ABC_HERE */ #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ @@ -1238,6 +1280,9 @@ struct ext4_inode_info { #define EXT4_MOUNT2_DAX_NEVER 0x00000020 /* Do not allow Direct Access */ #define EXT4_MOUNT2_DAX_INODE 0x00000040 /* For printing options only */ +#ifdef MY_ABC_HERE +#define EXT4_MOUNTSYNO_ROOTPRJQUOTA 0x00000001 /* Count root prjquota */ +#endif /* MY_ABC_HERE */ #define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \ ~EXT4_MOUNT_##opt @@ -1253,6 +1298,15 @@ struct ext4_inode_info { #define test_opt2(sb, opt) (EXT4_SB(sb)->s_mount_opt2 & \ EXT4_MOUNT2_##opt) +#ifdef MY_ABC_HERE +#define clear_opt_syno(sb, opt) EXT4_SB(sb)->s_mount_opt_syno &= \ + ~EXT4_MOUNTSYNO_##opt +#define set_opt_syno(sb, opt) EXT4_SB(sb)->s_mount_opt_syno |= \ + EXT4_MOUNTSYNO_##opt +#define test_opt_syno(sb, opt) (EXT4_SB(sb)->s_mount_opt_syno & \ + EXT4_MOUNTSYNO_##opt) +#endif /* MY_ABC_HERE */ + #define ext4_test_and_set_bit __test_and_set_bit_le #define ext4_set_bit __set_bit_le #define ext4_set_bit_atomic ext2_set_bit_atomic @@ -1411,7 +1465,21 @@ struct ext4_super_block { __u8 s_last_error_errcode; __le16 s_encoding; /* Filename charset encoding */ __le16 s_encoding_flags; /* Filename charset encoding flags */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + __le32 s_reserved[86]; /* Paddint to the end of the block */ + __le64 s_syno_rbd_first_mapping_table_offset; + __le32 s_feature_syno_capability; + __le32 s_syno_mtime; + __le64 s_syno_kbytes_written; + __le32 s_syno_hash_magic; /* magic number for syno caseless dir_index */ + __le32 s_archive_version; /* Last archived version */ + __le32 s_archive_version_obsoleted; +#else __le32 s_reserved[95]; /* Padding to the end of the block */ +#endif /* MY_ABC_HERE || MY_ABC_HERE || + * MY_ABC_HERE || MY_ABC_HERE + */ __le32 s_checksum; /* crc32c(superblock) */ }; @@ -1453,6 +1521,9 @@ struct ext4_sb_info { struct buffer_head * __rcu *s_group_desc; unsigned int s_mount_opt; unsigned int s_mount_opt2; +#ifdef MY_ABC_HERE + unsigned int s_mount_opt_syno; +#endif /* MY_ABC_HERE */ unsigned long s_mount_flags; unsigned int s_def_mount_opt; ext4_fsblk_t s_sb_block; @@ -1566,6 +1637,13 @@ struct ext4_sb_info { struct flex_groups * __rcu *s_flex_groups; ext4_group_t s_flex_groups_allocated; +#ifdef MY_ABC_HERE + int s_new_error_fs_event_flag; + char *s_mount_path; + unsigned long s_last_notify_time; + spinlock_t s_mount_path_lock; +#endif /* MY_ABC_HERE */ + /* workqueue for reserved extent conversions (buffered io) */ struct workqueue_struct *rsv_conversion_wq; @@ -1648,6 +1726,10 @@ struct ext4_sb_info { int s_fc_debug_max_replay; #endif struct ext4_fc_replay_state s_fc_replay_state; + +#ifdef MY_ABC_HERE + spinlock_t s_feature_lock; /* for ext4 feature flags */ +#endif /* MY_ABC_HERE */ }; static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) @@ -1872,6 +1954,19 @@ static inline bool ext4_verity_in_progress(struct inode *inode) /* * Feature set definitions */ +#ifdef MY_ABC_HERE +#define EXT4_HAS_SYNO_CAPABILITY_FEATURE(sb,mask) \ + ((EXT4_SB(sb)->s_es->s_feature_syno_capability & cpu_to_le32(mask)) != 0) +#define EXT4_SET_SYNO_CAPABILITY_FEATURE(sb,mask) \ +do { \ + if (mask) \ + ext4_update_dynamic_rev(sb); \ + EXT4_SB(sb)->s_es->s_feature_syno_capability |= cpu_to_le32(mask); \ +} while(0) + +#define EXT4_CLEAR_SYNO_CAPABILITY_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_syno_capability &= ~cpu_to_le32(mask) +#endif /* MY_ABC_HERE */ #define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001 #define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002 @@ -1929,6 +2024,10 @@ static inline bool ext4_verity_in_progress(struct inode *inode) extern void ext4_update_dynamic_rev(struct super_block *sb); +#ifdef MY_ABC_HERE +#define EXT4_FEATURE_SYNO_CAPABILITY_RBD_META 0x0001 +#endif /* MY_ABC_HERE */ + #define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \ static inline bool ext4_has_feature_##name(struct super_block *sb) \ { \ @@ -1983,6 +2082,26 @@ static inline void ext4_clear_feature_##name(struct super_block *sb) \ ~cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \ } +#ifdef MY_ABC_HERE +#define EXT4_FEATURE_SYNO_CAPABILITY_FUNCS(name, flagname) \ +static inline bool ext4_has_feature_##name(struct super_block *sb) \ +{ \ + return ((EXT4_SB(sb)->s_es->s_feature_syno_capability & \ + cpu_to_le32(EXT4_FEATURE_SYNO_CAPABILITY_##flagname)) != 0); \ +} \ +static inline void ext4_set_feature_##name(struct super_block *sb) \ +{ \ + ext4_update_dynamic_rev(sb); \ + EXT4_SB(sb)->s_es->s_feature_syno_capability |= \ + cpu_to_le32(EXT4_FEATURE_SYNO_CAPABILITY_##flagname); \ +} \ +static inline void ext4_clear_feature_##name(struct super_block *sb) \ +{ \ + EXT4_SB(sb)->s_es->s_feature_syno_capability &= \ + ~cpu_to_le32(EXT4_FEATURE_SYNO_CAPABILITY_##flagname); \ +} +#endif /* MY_ABC_HERE */ + EXT4_FEATURE_COMPAT_FUNCS(dir_prealloc, DIR_PREALLOC) EXT4_FEATURE_COMPAT_FUNCS(imagic_inodes, IMAGIC_INODES) EXT4_FEATURE_COMPAT_FUNCS(journal, HAS_JOURNAL) @@ -2024,6 +2143,10 @@ EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, INLINE_DATA) EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT) EXT4_FEATURE_INCOMPAT_FUNCS(casefold, CASEFOLD) +#ifdef MY_ABC_HERE +EXT4_FEATURE_SYNO_CAPABILITY_FUNCS(syno_rbd_meta, RBD_META) +#endif /* MY_ABC_HERE */ + #define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR #define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ EXT4_FEATURE_INCOMPAT_META_BG) @@ -2066,6 +2189,131 @@ EXT4_FEATURE_INCOMPAT_FUNCS(casefold, CASEFOLD) EXT4_FEATURE_RO_COMPAT_PROJECT |\ EXT4_FEATURE_RO_COMPAT_VERITY) +#ifdef MY_ABC_HERE + +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +EXT4_FEATURE_SYNO_CAPABILITY_RBD_META (0U) +#endif /* MY_ABC_HERE */ + + +#define EXT4_FEATURE_SYNO_CAPABILITY_SUPP \ + (EXT4_FEATURE_SYNO_CAPABILITY_RBD_META) + +#define EXT4_FEATURE_SYNO_CAPABILITY_SAFE_SET \ + (EXT4_FEATURE_SYNO_CAPABILITY_RBD_META) + +#define EXT4_FEATURE_SYNO_CAPABILITY_SAFE_CLEAR \ + (EXT4_FEATURE_SYNO_CAPABILITY_RBD_META) + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * #109900 enables metadata_csum feature at DSM7.0. Thus, we remove + * define of ext4_archive_bit and move it from i_checksum_hi to + * i_syno_archive_bit appeding to the end of ext4_inode. It also increases + * i_extra_isize from 28 to 32 due to i_syno_archive_bit. + * + * On-disk location of inode's i_archive_bit: + * (see struct ext4_inode for these on-disk locations) + * + * ext3: 16 bit hi: osd2.linux2.l_i_reserved + * 16 bit lo: osd2.linux2.l_i_checksum_lo + * (ext3 doesn't support inode checksum, + * so osd2.linux2.l_i_checksum_lo is in reserved area) + * + * ext4 without METADATA_CSUM: + * 16 bit hi: none (yes, we didn't store it.) + * 16 bit lo: i_checksum_hi + * + * ext4 with METADATA_CSUM + * 32 bit: i_syno_archive_bit + * + * Fortunately, we don't use 17th ~ 32nd bits for now. + */ +#define EXT4_INODE_GET_SYNO_ARCHIVE_BIT(inode, raw_inode) \ +do { \ + if (ext4_has_feature_metadata_csum(inode->i_sb)) { \ + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_syno_archive_bit)) \ + inode->i_archive_bit = le32_to_cpu(raw_inode->i_syno_archive_bit); \ + else \ + inode->i_archive_bit = 0; \ + } else { \ + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_checksum_hi)) \ + inode->i_archive_bit = le16_to_cpu(raw_inode->i_checksum_hi); \ + else \ + inode->i_archive_bit = 0; \ + } \ + inode->i_archive_bit &= ARCHIVE_BIT_MASK; \ +} while (0) + +#define EXT4_INODE_SET_SYNO_ARCHIVE_BIT(inode, raw_inode) \ +do { \ + __u32 flags = 0; \ + if (ext4_has_feature_metadata_csum(inode->i_sb)) { \ + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_syno_archive_bit)) \ + flags = le32_to_cpu(raw_inode->i_syno_archive_bit); \ + } else { \ + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_checksum_hi)) \ + /* we'll lost upper 16 bits flags */ \ + flags = le16_to_cpu(raw_inode->i_checksum_hi); \ + } \ + flags &= ~ARCHIVE_BIT_MASK; \ + flags |= inode->i_archive_bit; \ + if (ext4_has_feature_metadata_csum(inode->i_sb)) { \ + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_syno_archive_bit)) \ + raw_inode->i_syno_archive_bit = cpu_to_le32(flags); \ + } else { \ + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_checksum_hi)) \ + /* we'll lost upper 16 bits flags */ \ + raw_inode->i_checksum_hi = cpu_to_le16(flags); \ + } \ +} while (0) +#endif /* End of MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static inline bool ext4_inode_is_swapfile(struct inode *inode, + struct ext4_inode *raw_inode) +{ + __u32 flags = 0; + if (ext4_has_feature_metadata_csum(inode->i_sb)) { + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_syno_archive_bit)) + flags = le32_to_cpu(raw_inode->i_syno_archive_bit); + } else { + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_checksum_hi)) + flags = le16_to_cpu(raw_inode->i_checksum_hi); + } + return !!(flags & EXT4_INODE_SWAPFILE_FLAG); +} + +static inline void ext4_inode_set_swapfile(struct inode *inode, + struct ext4_inode *raw_inode, + bool is_swapfile) +{ + __u32 flags = 0; + if (ext4_has_feature_metadata_csum(inode->i_sb)) { + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_syno_archive_bit)) + flags = le32_to_cpu(raw_inode->i_syno_archive_bit); + } else { + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_checksum_hi)) + flags = le16_to_cpu(raw_inode->i_checksum_hi); + } + + if (is_swapfile) + flags |= EXT4_INODE_SWAPFILE_FLAG; + else + flags &= ~EXT4_INODE_SWAPFILE_FLAG; + + if (ext4_has_feature_metadata_csum(inode->i_sb)) { + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_syno_archive_bit)) + raw_inode->i_syno_archive_bit = cpu_to_le32(flags); + } else { + if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), i_checksum_hi)) + raw_inode->i_checksum_hi = cpu_to_le16(flags); + } +} +#endif /* MY_ABC_HERE */ + #define EXTN_FEATURE_FUNCS(ver) \ static inline bool ext4_has_unknown_ext##ver##_compat_features(struct super_block *sb) \ { \ @@ -2099,6 +2347,12 @@ static inline bool ext4_has_incompat_features(struct super_block *sb) { return (EXT4_SB(sb)->s_es->s_feature_incompat != 0); } +#ifdef MY_ABC_HERE +static inline bool ext4_has_syno_capability_features(struct super_block *sb) +{ + return (EXT4_SB(sb)->s_es->s_feature_syno_capability != 0); +} +#endif /* MY_ABC_HERE */ /* * Superblock flags @@ -2267,9 +2521,20 @@ static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize) * Hash Tree Directory indexing * (c) Daniel Phillips, 2001 */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define is_syno_ext(sb) \ + ((ext4_has_feature_metadata_csum(sb)) ? \ + (EXT4_SB(sb)->s_es->s_syno_hash_magic == cpu_to_le32(SYNO_HASH_MAGIC)) : \ + (EXT4_SB(sb)->s_es->s_checksum == cpu_to_le32(SYNO_HASH_MAGIC))) +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define is_dx(dir) ((is_syno_ext((dir)->i_sb) || ext4_has_feature_dir_index((dir)->i_sb)) && \ + ext4_test_inode_flag((dir), EXT4_INODE_INDEX)) +#else /* MY_ABC_HERE */ #define is_dx(dir) (ext4_has_feature_dir_index((dir)->i_sb) && \ ext4_test_inode_flag((dir), EXT4_INODE_INDEX)) +#endif /* MY_ABC_HERE */ #define EXT4_DIR_LINK_MAX(dir) unlikely((dir)->i_nlink >= EXT4_LINK_MAX && \ !(ext4_has_feature_dir_nlink((dir)->i_sb) && is_dx(dir))) #define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1) @@ -2400,7 +2665,11 @@ static inline int ext4_dir_htree_level(struct super_block *sb) /* * Timeout and state flag for lazy initialization inode thread. */ +#ifdef CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT +#define EXT4_DEF_LI_WAIT_MULT CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT +#else /* CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT */ #define EXT4_DEF_LI_WAIT_MULT 10 +#endif /* CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT */ #define EXT4_DEF_LI_MAX_START_DELAY 5 #define EXT4_LAZYINIT_QUIT 0x0001 #define EXT4_LAZYINIT_RUNNING 0x0002 @@ -2697,7 +2966,11 @@ void ext4_insert_dentry(struct inode *inode, struct ext4_filename *fname); static inline void ext4_update_dx_flag(struct inode *inode) { +#ifdef MY_ABC_HERE + if (!is_syno_ext(inode->i_sb) && !ext4_has_feature_dir_index(inode->i_sb) && +#else /* MY_ABC_HERE */ if (!ext4_has_feature_dir_index(inode->i_sb) && +#endif /* MY_ABC_HERE */ ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) { /* ext4_iget() should have caught this... */ WARN_ON_ONCE(ext4_has_feature_metadata_csum(inode->i_sb)); @@ -2806,7 +3079,11 @@ extern int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t i, struct ext4_group_desc *desc); extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, ext4_fsblk_t block, unsigned long count); -extern int ext4_trim_fs(struct super_block *, struct fstrim_range *); +extern int ext4_trim_fs(struct super_block *, struct fstrim_range * +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ); extern void ext4_process_freed_data(struct super_block *sb, tid_t commit_tid); extern void ext4_mb_mark_bb(struct super_block *sb, ext4_fsblk_t block, int len, int state); @@ -2850,6 +3127,10 @@ extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, #define ext4_iget(sb, ino, flags) \ __ext4_iget((sb), (ino), (flags), __func__, __LINE__) +#ifdef MY_ABC_HERE +extern int ext4_syno_get_crtime(struct inode *inode, struct timespec64 *time); +extern int ext4_syno_set_crtime(struct inode *inode, struct timespec64 *time); +#endif /* MY_ABC_HERE */ extern int ext4_write_inode(struct inode *, struct writeback_control *); extern int ext4_setattr(struct dentry *, struct iattr *); extern int ext4_getattr(const struct path *, struct kstat *, u32, unsigned int); @@ -2883,6 +3164,19 @@ extern void ext4_da_update_reserve_space(struct inode *inode, int used, int quota_claim); extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, ext4_lblk_t len); +#ifdef MY_ABC_HERE +extern int ext4_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags); +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +extern int ext4_syno_set_archive_bit(struct dentry *dentry, unsigned int archive_bit); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern int ext4_syno_get_inode_archive_version(struct dentry *d, u32 *); +extern int ext4_syno_set_inode_archive_version(struct dentry *d, u32); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int ext4_fsdev_mapping(struct inode *inode, u64 start, u64 end, u64 *dev_start, u64 *dev_end); +#endif /* MY_ABC_HERE */ /* indirect.c */ extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, @@ -2894,6 +3188,9 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode, /* ioctl.c */ extern long ext4_ioctl(struct file *, unsigned int, unsigned long); +#ifdef MY_ABC_HERE +extern long ext4_symlink_ioctl(struct file *, unsigned int, unsigned long); +#endif /* MY_ABC_HERE */ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); extern void ext4_reset_inode_seed(struct inode *inode); @@ -2916,7 +3213,11 @@ extern int ext4_search_dir(struct buffer_head *bh, struct inode *dir, struct ext4_filename *fname, unsigned int offset, - struct ext4_dir_entry_2 **res_dir); + struct ext4_dir_entry_2 **res_dir +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ); extern int ext4_generic_delete_entry(struct inode *dir, struct ext4_dir_entry_2 *de_del, struct buffer_head *bh, @@ -2935,6 +3236,9 @@ extern int ext4_group_extend(struct super_block *sb, extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count); /* super.c */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +extern int ext4_is_ext3_sb(struct super_block *sb); +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ extern struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block, int op_flags); extern struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb, @@ -3441,7 +3745,11 @@ extern int ext4_inlinedir_to_tree(struct file *dir_file, extern struct buffer_head *ext4_find_inline_entry(struct inode *dir, struct ext4_filename *fname, struct ext4_dir_entry_2 **res_dir, - int *has_inline_data); + int *has_inline_data +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ); extern int ext4_delete_inline_entry(handle_t *handle, struct inode *dir, struct ext4_dir_entry_2 *de_del, @@ -3516,6 +3824,9 @@ extern void ext4_exit_post_read_processing(void); extern const struct inode_operations ext4_encrypted_symlink_inode_operations; extern const struct inode_operations ext4_symlink_inode_operations; extern const struct inode_operations ext4_fast_symlink_inode_operations; +#ifdef MY_ABC_HERE +extern const struct file_operations ext4_symlink_file_operations; +#endif /* MY_ABC_HERE */ /* sysfs.c */ extern int ext4_register_sysfs(struct super_block *sb); @@ -3622,6 +3933,13 @@ extern int ext4_bio_write_page(struct ext4_io_submit *io, extern struct ext4_io_end_vec *ext4_alloc_io_end_vec(ext4_io_end_t *io_end); extern struct ext4_io_end_vec *ext4_last_io_end_vec(ext4_io_end_t *io_end); +#ifdef MY_ABC_HERE +extern int ext4_rbd_meta_file_activate(struct inode *inode); +extern int ext4_rbd_meta_file_deactivate(struct inode *inode); +extern int ext4_rbd_meta_file_mapping(struct inode *inode, + struct syno_rbd_meta_ioctl_args *args); +#endif /* MY_ABC_HERE */ + /* mmp.c */ extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t); @@ -3697,6 +4015,11 @@ static inline int ext4_buffer_uptodate(struct buffer_head *bh) return buffer_uptodate(bh); } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +int ext4_syno_write_super(struct super_block *sb, void *vals, + void (*updater)(struct super_block *sb, void *vals)); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + #endif /* __KERNEL__ */ #define EFSBADCRC EBADMSG /* Bad CRC detected */ diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index 00dc668e052b..a8cd54d08bd3 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * ext4_jbd2.h @@ -123,7 +126,12 @@ #define EXT4_HT_MOVE_EXTENTS 9 #define EXT4_HT_XATTR 10 #define EXT4_HT_EXT_CONVERT 11 +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define EXT4_HT_SYNO 12 +#define EXT4_HT_MAX 13 +#else #define EXT4_HT_MAX 12 +#endif /* MY_ABC_HERE || MY_ABC_HERE */ /** * struct ext4_journal_cb_entry - Base structure for callback information. diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e00a35530a4e..ad1d4e391e1d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com @@ -4925,6 +4928,47 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, return iomap_fiemap(inode, fieinfo, start, len, &ext4_iomap_report_ops); } +#ifdef MY_ABC_HERE +int ext4_rbd_meta_file_mapping(struct inode *inode, + struct syno_rbd_meta_ioctl_args *args) +{ + int ret; + const unsigned char blksize_bits = inode->i_sb->s_blocksize_bits; + u64 isize; + u64 len; + + if (ext4_has_inline_data(inode)) { + printk(KERN_WARNING "rbd meta file must not inline\n"); + return -EINVAL; + } + if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { + printk(KERN_WARNING "only support extent inode on rbd meta file\n"); + return -EOPNOTSUPP; + } + + isize = ALIGN_DOWN(inode->i_size, (1ULL << blksize_bits)); + if (!isize) + return -EINVAL; + if (args->start >= isize) { + args->cnt = 0; + args->start = (u64) -1; + return 0; + } + len = isize - args->start; + ret = ext4_fiemap_check_ranges(inode, args->start, &len); + if (ret) + return ret; + + args->cnt = 0; + ret = iomap_rbd_meta_map(inode, args, args->start, + len, &ext4_iomap_report_ops); + + if (!ret && args->start != (u64) -1 && args->start >= isize) + args->start = (u64) -1; + return ret; +} +#endif /* MY_ABC_HERE */ + int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 7b28d44b0ddd..8eb3adc4ec8b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/file.c @@ -36,6 +39,10 @@ #include "acl.h" #include "truncate.h" +#ifdef MY_ABC_HERE +#include "syno_acl.h" +#endif /* MY_ABC_HERE */ + static bool ext4_dio_supported(struct inode *inode) { if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && IS_ENCRYPTED(inode)) @@ -928,11 +935,37 @@ const struct file_operations ext4_file_operations = { }; const struct inode_operations ext4_file_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = ext4_syno_getattr, +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_set_archive_bit = ext4_syno_set_archive_bit, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ext4_syno_get_inode_archive_version, + .syno_set_archive_version = ext4_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ .setattr = ext4_setattr, .getattr = ext4_file_getattr, .listxattr = ext4_listxattr, .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, +#ifdef MY_ABC_HERE + .syno_get_acl = ext4_get_syno_acl, + .syno_set_acl = ext4_set_syno_acl, +#endif /* MY_ABC_HERE */ .fiemap = ext4_fiemap, +#ifdef MY_ABC_HERE + .syno_get_crtime = ext4_syno_get_crtime, + .syno_set_crtime = ext4_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .fsdev_mapping = ext4_fsdev_mapping, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_rbd_meta_file_activate = ext4_rbd_meta_file_activate, + .syno_rbd_meta_file_deactivate = ext4_rbd_meta_file_deactivate, + .syno_rbd_meta_file_mapping = ext4_rbd_meta_file_mapping, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index a92eb79de0cc..a60f42daeedf 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/hash.c @@ -198,7 +201,12 @@ static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) * bits. 32 bit hashes will return 0 for the minor hash. */ static int __ext4fs_dirhash(const char *name, int len, - struct dx_hash_info *hinfo) + struct dx_hash_info *hinfo +#ifdef MY_ABC_HERE + , const char *ori_name + , const int ori_len +#endif /* MY_ABC_HERE */ + ) { __u32 hash; __u32 minor_hash = 0; @@ -207,6 +215,9 @@ static int __ext4fs_dirhash(const char *name, int len, __u32 in[8], buf[4]; void (*str2hashbuf)(const char *, int, __u32 *, int) = str2hashbuf_signed; +#ifdef MY_ABC_HERE + const bool ori_minor_hash = !!ori_name; +#endif /* MY_ABC_HERE */ /* Initialize the default seed for the hash checksum functions */ buf[0] = 0x67452301; @@ -227,9 +238,17 @@ static int __ext4fs_dirhash(const char *name, int len, switch (hinfo->hash_version) { case DX_HASH_LEGACY_UNSIGNED: hash = dx_hack_hash_unsigned(name, len); +#ifdef MY_ABC_HERE + if (ori_minor_hash) + minor_hash = dx_hack_hash_unsigned(ori_name, ori_len); +#endif /* MY_ABC_HERE */ break; case DX_HASH_LEGACY: hash = dx_hack_hash_signed(name, len); +#ifdef MY_ABC_HERE + if (ori_minor_hash) + minor_hash = dx_hack_hash_signed(ori_name, ori_len); +#endif /* MY_ABC_HERE */ break; case DX_HASH_HALF_MD4_UNSIGNED: str2hashbuf = str2hashbuf_unsigned; @@ -242,8 +261,30 @@ static int __ext4fs_dirhash(const char *name, int len, len -= 32; p += 32; } +#ifdef MY_ABC_HERE + if (ori_minor_hash) { + hash = buf[1]; + p = ori_name; + len = ori_len; + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + while (len > 0) { + (*str2hashbuf)(p, len, in, 8); + half_md4_transform(buf, in); + len -= 32; + p += 32; + } + minor_hash = buf[2]; + } else { + minor_hash = buf[2]; + hash = buf[1]; + } +#else /* MY_ABC_HERE */ minor_hash = buf[2]; hash = buf[1]; +#endif /* MY_ABC_HERE */ break; case DX_HASH_TEA_UNSIGNED: str2hashbuf = str2hashbuf_unsigned; @@ -257,6 +298,22 @@ static int __ext4fs_dirhash(const char *name, int len, p += 16; } hash = buf[0]; +#ifdef MY_ABC_HERE + if (ori_minor_hash) { + p = ori_name; + len = ori_len; + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + while (len > 0) { + (*str2hashbuf)(p, len, in, 4); + TEA_transform(buf, in); + len -= 16; + p += 16; + } + } +#endif /* MY_ABC_HERE */ minor_hash = buf[1]; break; default: @@ -274,6 +331,17 @@ static int __ext4fs_dirhash(const char *name, int len, int ext4fs_dirhash(const struct inode *dir, const char *name, int len, struct dx_hash_info *hinfo) { +#ifdef MY_ABC_HERE + /* + * hash_buf need to add 1 byte for syno_utf8_toupper, + * because it will append 0 to last byte. + */ + bool syno_caseless = is_syno_ext(dir->i_sb); + char hash_buf[EXT4_NAME_LEN + 1] = {'\0'}; + const char *ori_name = NULL; + int ori_len = 0; +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_UNICODE const struct unicode_map *um = dir->i_sb->s_encoding; int r, dlen; @@ -281,6 +349,9 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len, struct qstr qstr = {.name = name, .len = len }; if (len && IS_CASEFOLDED(dir) && um) { +#ifdef MY_ABC_HERE + syno_caseless = false; +#endif /* MY_ABC_HERE */ buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL); if (!buff) return -ENOMEM; @@ -291,12 +362,34 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len, goto opaque_seq; } +#ifdef MY_ABC_HERE + r = __ext4fs_dirhash(buff, dlen, hinfo, NULL, 0); +#else /* MY_ABC_HERE */ r = __ext4fs_dirhash(buff, dlen, hinfo); +#endif /* MY_ABC_HERE */ kfree(buff); return r; } opaque_seq: #endif + +#ifdef MY_ABC_HERE + if (syno_caseless && name && (len > 0)) { + ori_name = name; + ori_len = len; + if (len > EXT4_NAME_LEN) { + hinfo->hash = 0; + printk_ratelimited(KERN_ERR "SynoCaseless Stat name too long\n"); + return -ENAMETOOLONG; + } + len = syno_utf8_toupper(hash_buf, name, + EXT4_NAME_LEN , len, NULL); + name = hash_buf; + } + + return __ext4fs_dirhash(name, len, hinfo, ori_name, ori_len); +#else /* MY_ABC_HERE */ return __ext4fs_dirhash(name, len, hinfo); +#endif /* MY_ABC_HERE */ } diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 875af329c43e..d0ea6d8dc8ac 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/ialloc.c @@ -33,6 +36,10 @@ #include +#ifdef MY_ABC_HERE +#define MAX_U32_IN_U64 ((u64)(UINT_MAX)) +#endif /* MY_ABC_HERE */ + /* * ialloc.c contains the inodes allocation and deallocation routines */ @@ -426,7 +433,12 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_group_t real_ngroups = ext4_get_groups_count(sb); int inodes_per_group = EXT4_INODES_PER_GROUP(sb); +#ifdef MY_ABC_HERE + ext4_fsblk_t freei, avefreei; + unsigned int grp_free; +#else /* MY_ABC_HERE */ unsigned int freei, avefreei, grp_free; +#endif /* MY_ABC_HERE */ ext4_fsblk_t freec, avefreec; unsigned int ndirs; int max_dirs, min_inodes; @@ -726,6 +738,16 @@ static int find_inode_bit(struct super_block *sb, ext4_group_t group, if (*ino >= EXT4_INODES_PER_GROUP(sb)) goto not_found; +#ifdef MY_ABC_HERE + /* + * Since the inode bitmap is zero-based, so the ino should not + * equal to MAX_U32_IN_U64. Also, we don't care about deleted_ino, + * because the deleted_ino cannot be overflow. + */ + if (MAX_U32_IN_U64 <= (u64) (*ino) + (u64) group * EXT4_INODES_PER_GROUP(sb)) + goto not_found; +#endif /* MY_ABC_HERE */ + if (check_recently_deleted && recently_deleted(sb, group, *ino)) { recently_deleted_ino = *ino; *ino = *ino + 1; @@ -1021,6 +1043,13 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, if (ret2 == -1) goto out; +#ifdef MY_ABC_HERE + if (MAX_U32_IN_U64 < (u64)group*EXT4_INODES_PER_GROUP(sb)) { + u32 max_group = (u32)((MAX_U32_IN_U64 + 1) / EXT4_INODES_PER_GROUP(sb)); + group %= max_group; + } +#endif /* MY_ABC_HERE */ + /* * Normally we will only go through one pass of this loop, * unless we get unlucky and it turns out the group we selected @@ -1111,8 +1140,13 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, if (ino < EXT4_INODES_PER_GROUP(sb)) goto repeat_in_this_group; next_group: +#ifdef MY_ABC_HERE + if (++group == ngroups || (MAX_U32_IN_U64 < (u64)group*EXT4_INODES_PER_GROUP(sb))) + group = 0; +#else /* MY_ABC_HERE */ if (++group == ngroups) group = 0; +#endif /* MY_ABC_HERE */ } err = -ENOSPC; goto out; @@ -1246,6 +1280,10 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); ei->i_crtime = inode->i_mtime; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + inode->i_archive_bit = ALL_SYNO_ARCHIVE; /* set archive bit on creation */ +#endif /* MY_ABC_HERE || MY_ABC_HERE*/ + memset(ei->i_data, 0, sizeof(ei->i_data)); ei->i_dir_start_lookup = 0; ei->i_disksize = 0; @@ -1258,6 +1296,9 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, ei->i_dtime = 0; ei->i_block_group = group; ei->i_last_alloc_group = ~0; +#ifdef MY_ABC_HERE + ei->i_is_swapfile = false; +#endif /* MY_ABC_HERE */ ext4_set_inode_flags(inode, true); if (IS_DIRSYNC(inode)) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index b41512d1badc..82eeb043a6f3 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: LGPL-2.1 /* * Copyright (c) 2012 Taobao. @@ -750,6 +753,12 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, ext4_write_lock_xattr(inode, &no_expand); BUG_ON(!ext4_has_inline_data(inode)); + /* + * ei->i_inline_off may have changed since ext4_write_begin() + * called ext4_try_to_write_inline_data() + */ + (void) ext4_find_inline_data_nolock(inode); + kaddr = kmap_atomic(page); ext4_write_inline_data(inode, &iloc, kaddr, pos, len); kunmap_atomic(kaddr); @@ -1624,7 +1633,11 @@ int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent, struct buffer_head *ext4_find_inline_entry(struct inode *dir, struct ext4_filename *fname, struct ext4_dir_entry_2 **res_dir, - int *has_inline_data) + int *has_inline_data +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { int ret; struct ext4_iloc iloc; @@ -1644,7 +1657,11 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir, EXT4_INLINE_DOTDOT_SIZE; inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; ret = ext4_search_dir(iloc.bh, inline_start, inline_size, - dir, fname, 0, res_dir); + dir, fname, 0, res_dir +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + ); if (ret == 1) goto out_find; if (ret < 0) @@ -1657,7 +1674,11 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir, inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE; ret = ext4_search_dir(iloc.bh, inline_start, inline_size, - dir, fname, 0, res_dir); + dir, fname, 0, res_dir +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + ); if (ret == 1) goto out_find; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 18a5321b5ef3..de90146b7497 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/inode.c @@ -40,12 +43,20 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" #include "truncate.h" +#ifdef MY_ABC_HERE +#include "syno_acl.h" +#endif /* MY_ABC_HERE */ + #include static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw, @@ -4751,7 +4762,12 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, * we'd normally treat htree data as empty space. But with metadata * checksumming that corrupts checksums so forbid that. */ - if (!ext4_has_feature_dir_index(sb) && ext4_has_metadata_csum(sb) && +#ifdef MY_ABC_HERE + if (!is_syno_ext(sb) && !ext4_has_feature_dir_index(sb) && +#else /* MY_ABC_HERE */ + if (!ext4_has_feature_dir_index(sb) && +#endif /* MY_ABC_HERE */ + ext4_has_metadata_csum(sb) && ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) { ext4_error_inode(inode, function, line, 0, "iget: Dir with htree data on filesystem without dir_index feature."); @@ -4817,6 +4833,34 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode); EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode); +#ifdef MY_ABC_HERE + if (ext4_is_ext3_sb(inode->i_sb) && is_syno_ext(inode->i_sb)) { + ei->i_crtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ext3_create_time); + ei->i_crtime.tv_nsec = 0; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (ext4_is_ext3_sb(sb)) + inode->i_archive_bit = ((u32)le16_to_cpu(raw_inode->ext3_archive_bit_high) << 16 | + le16_to_cpu(raw_inode->ext3_archive_bit_lo)); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!ext4_is_ext3_sb(sb)) + EXT4_INODE_GET_SYNO_ARCHIVE_BIT(inode, raw_inode); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ei->i_is_swapfile = ext4_inode_is_swapfile(inode, raw_inode); + + if (ei->i_is_swapfile) + inode->i_flags |= S_SWAPFILE; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!is_syno_ext(inode->i_sb)) +#endif /* MY_ABC_HERE */ if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { u64 ivers = le32_to_cpu(raw_inode->i_disk_version); @@ -4880,6 +4924,9 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, ext4_set_aops(inode); } inode_nohighmem(inode); +#ifdef MY_ABC_HERE + inode->i_fop = &ext4_symlink_file_operations; +#endif /* MY_ABC_HERE */ } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { inode->i_op = &ext4_special_inode_operations; @@ -5080,6 +5127,27 @@ static int ext4_do_update_inode(handle_t *handle, EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode); EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode); +#ifdef MY_ABC_HERE + if (ext4_is_ext3_sb(inode->i_sb) && is_syno_ext(inode->i_sb)) { + raw_inode->i_ext3_create_time = cpu_to_le32(ei->i_crtime.tv_sec); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (ext4_is_ext3_sb(inode->i_sb)) { + raw_inode->ext3_archive_bit_high = cpu_to_le16(inode->i_archive_bit >> 16); + raw_inode->ext3_archive_bit_lo = cpu_to_le16(inode->i_archive_bit); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!ext4_is_ext3_sb(inode->i_sb)) + EXT4_INODE_SET_SYNO_ARCHIVE_BIT(inode, raw_inode); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + ext4_inode_set_swapfile(inode, raw_inode, ei->i_is_swapfile); +#endif /* MY_ABC_HERE */ raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF); @@ -5117,6 +5185,9 @@ static int ext4_do_update_inode(handle_t *handle, if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { u64 ivers = ext4_inode_peek_iversion(inode); +#ifdef MY_ABC_HERE + if (!is_syno_ext(inode->i_sb)) +#endif /* MY_ABC_HERE */ raw_inode->i_disk_version = cpu_to_le32(ivers); if (ei->i_extra_isize) { if (EXT4_FITS_IN_INODE(raw_inode, ei, i_version_hi)) @@ -5333,9 +5404,18 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) ATTR_GID | ATTR_TIMES_SET)))) return -EPERM; +#ifdef MY_ABC_HERE + // just skip it. inode change check is done in notify_change() + if (!IS_EXT4_SYNOACL(inode)) { + error = setattr_prepare(dentry, attr); + if (error) + return error; + } +#else /* MY_ABC_HERE */ error = setattr_prepare(dentry, attr); if (error) return error; +#endif /* MY_ABC_HERE */ error = fscrypt_prepare_setattr(dentry, attr); if (error) @@ -5606,6 +5686,162 @@ int ext4_file_getattr(const struct path *path, struct kstat *stat, return 0; } +#ifdef MY_ABC_HERE +int ext4_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags) +{ + int err = 0; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + struct inode *inode = dentry->d_inode; +#endif /* MY_ABC_HERE || MY_ABC_HERE || + MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_BIT) { + mutex_lock(&inode->i_archive_bit_mutex); + kst->syno_archive_bit = inode->i_archive_bit; + mutex_unlock(&inode->i_archive_bit_mutex); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_VER) { + mutex_lock(&inode->i_archive_version_mutex); + err = ext4_syno_get_inode_archive_version(dentry, &kst->syno_archive_version); + mutex_unlock(&inode->i_archive_version_mutex); + if (err) + goto end; + } +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + if (syno_flags & SYNOST_CREATE_TIME) { + kst->syno_create_time = EXT4_I(inode)->i_crtime; + } +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +end: + return err; +} +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +int ext4_syno_set_archive_bit(struct dentry *dentry, unsigned int archive_bit) +{ + int ret, ret2; + struct inode *inode = dentry->d_inode; + handle_t *handle; + + handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + inode->i_archive_bit = archive_bit; + inode->i_ctime = current_time(inode); + + ret = ext4_mark_inode_dirty(handle, inode); + ret2 = ext4_journal_stop(handle); + if (!ret) + ret = ret2; + + return ret; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int ext4_syno_set_inode_archive_version(struct dentry *dentry, u32 version) +{ + struct inode *inode = dentry->d_inode; + struct syno_xattr_archive_version value; + int ret; + + value.v_magic = cpu_to_le16(0x2552); + value.v_struct_version = cpu_to_le16(1); + value.v_archive_version = cpu_to_le32(version); + + ret = ext4_xattr_set(inode, EXT4_XATTR_INDEX_SYNO, + XATTR_SYNO_ARCHIVE_VERSION_SUFFIX, + &value, sizeof(value), 0); + if (!ret) { + inode->i_archive_version = version; + inode->i_flags |= S_ARCHIVE_VERSION_CACHED; + } + + return ret; +} + +#ifdef MY_ABC_HERE +static int ext3_syno_get_inode_archive_version(struct dentry *dentry, u32 *version) +{ + int ret; + struct inode *inode = dentry->d_inode; + struct syno_xattr_archive_version value; + u32 archive_version = 0; + u32 archive_version_bad = 0; + + /* Stored archive version in wrong place at linux-3.10.x */ + ret = ext4_xattr_get(inode, EXT3_XATTR_INDEX_SYNO_BAD, + XATTR_SYNO_ARCHIVE_VERSION, + &value, sizeof(value)); + if (ret > 0) + archive_version_bad = le32_to_cpu(value.v_archive_version); + + ret = ext4_xattr_get(inode, EXT4_XATTR_INDEX_SYNO, + XATTR_SYNO_ARCHIVE_VERSION, + &value, sizeof(value)); + if (ret > 0) { + archive_version = le32_to_cpu(value.v_archive_version); + } else if (-ENODATA == ret) { + archive_version = 0; + } else { + *version = 0; + return ret; + } + + /* Pick up the greater one */ + inode->i_archive_version = (archive_version_bad > archive_version) ? + archive_version_bad : archive_version; + *version = inode->i_archive_version; + inode->i_flags |= S_ARCHIVE_VERSION_CACHED; + + return 0; +} +#endif /* MY_ABC_HERE */ + +int ext4_syno_get_inode_archive_version(struct dentry *dentry, u32 *version) +{ + struct inode *inode = dentry->d_inode; + struct syno_xattr_archive_version value; + int ret; + + if (IS_ARCHIVE_VERSION_CACHED(inode)) { + *version = inode->i_archive_version; + return 0; + } + +#ifdef MY_ABC_HERE + if (ext4_is_ext3_sb(inode->i_sb)) + return ext3_syno_get_inode_archive_version(dentry, version); +#endif /* MY_ABC_HERE */ + + ret = ext4_xattr_get(inode, EXT4_XATTR_INDEX_SYNO, + XATTR_SYNO_ARCHIVE_VERSION_SUFFIX, + &value, sizeof(value)); + if (0 < ret) { + inode->i_archive_version = le32_to_cpu(value.v_archive_version); + } else if (-ENODATA == ret) { + inode->i_archive_version = 0; + } else { + *version = 0; + return ret; + } + *version = inode->i_archive_version; + inode->i_flags |= S_ARCHIVE_VERSION_CACHED; + + return 0; +} +#endif /* MY_ABC_HERE */ + static int ext4_index_trans_blocks(struct inode *inode, int lblocks, int pextents) { @@ -6071,6 +6307,9 @@ vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf) sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); +#ifdef MY_ABC_HERE + fsnotify_modify(vma->vm_file); +#endif /* MY_ABC_HERE */ down_read(&EXT4_I(inode)->i_mmap_sem); @@ -6205,3 +6444,198 @@ vm_fault_t ext4_filemap_fault(struct vm_fault *vmf) return ret; } + +#ifdef MY_ABC_HERE +int ext4_syno_get_crtime(struct inode *inode, struct timespec64 *time) +{ + *time = EXT4_I(inode)->i_crtime; + + return 0; +} + +int ext4_syno_set_crtime(struct inode *inode, struct timespec64 *time) +{ + handle_t *handle; + struct ext4_inode_info *ei = EXT4_I(inode); + + handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); + if (IS_ERR(handle)) + goto out; + + ei->i_crtime = timestamp_truncate(*time, inode); + ext4_mark_inode_dirty(handle, inode); + + ext4_journal_stop(handle); +out: + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int ext4_fsdev_mapping(struct inode *inode, u64 start, u64 end, u64 *dev_start, u64 *dev_end) +{ + int ret; + struct super_block *sb = inode->i_sb; + u64 offset, length; + struct ext4_map_blocks map; + u8 blkbits = inode->i_blkbits; + ext4_lblk_t last_block; + + if (end < start || + !dev_start || !dev_end || + !IS_SWAPFILE(inode)) { + ret = -EINVAL; + goto out; + } + + last_block = i_size_read(inode) >> blkbits; + if ((end >> blkbits) >= last_block) { + ret = -EOVERFLOW; + goto out; + } + + offset = start; + length = end - start + 1; + + if ((offset >> blkbits) > EXT4_MAX_LOGICAL_BLOCK) { + ret = -EINVAL; + goto out; + } + + if (ext4_has_inline_data(inode)) { + ext4_msg(sb, KERN_INFO, "fsdev file must not be inline"); + ret = -EINVAL; + goto out; + } + + /* + * Calculate the first and last logical block respectively. + */ + map.m_lblk = offset >> blkbits; + map.m_len = min_t(loff_t, (offset + length - 1) >> blkbits, + EXT4_MAX_LOGICAL_BLOCK) - map.m_lblk + 1; + + /* + * Callers may call for offset beyond s_bitmap_maxbytes. + * So handle it here itself instead of querying ext4_map_blocks(). + * Since ext4_map_blocks() will warn about it and will return + * -EIO error. + */ + if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + + if (offset >= sbi->s_bitmap_maxbytes) { + map.m_flags = 0; + goto skip_map_block; + } + } + + ret = ext4_map_blocks(NULL, inode, &map, 0); + if (ret < 0) + goto out; + +skip_map_block: + if (!(map.m_flags & (EXT4_MAP_UNWRITTEN | EXT4_MAP_MAPPED))) { + ext4_msg(sb, KERN_INFO, "fsdev file must not have holes"); + ret = -EINVAL; + goto out; + } + + *dev_start = (u64)map.m_pblk << blkbits; + *dev_end = *dev_start + ((u64)map.m_len << blkbits) - 1; + + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int update_inode_swapfile_flag(struct inode *inode, bool is_swapfile) +{ + int ret; + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_iloc iloc; + handle_t *handle = NULL; + + if (is_swapfile == ei->i_is_swapfile) { + ret = 0; + goto out; + } + + handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + if (IS_SYNC(inode)) + ext4_handle_sync(handle); + ret = ext4_reserve_inode_write(handle, inode, &iloc); + if (ret) + goto out_journal; + + ei->i_is_swapfile = is_swapfile; + inode->i_ctime = current_time(inode); + ret = ext4_mark_iloc_dirty(handle, inode, &iloc); + if (ret) + goto out_journal; + + if (ei->i_is_swapfile) + inode->i_flags |= S_SWAPFILE; + else + inode->i_flags &= ~S_SWAPFILE; + + ret = 0; +out_journal: + ext4_journal_stop(handle); +out: + return ret; +} + +int ext4_rbd_meta_file_activate(struct inode *inode) +{ + int ret; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + inode_lock(inode); + if (IS_SWAPFILE(inode)) { + ret = -EBUSY; + goto out; + } + if (!IS_IMMUTABLE(inode)) { + printk(KERN_WARNING "rbd meta file must be immutable\n"); + ret = -EINVAL; + goto out; + } + + ret = update_inode_swapfile_flag(inode, true); + if (ret) + goto out; + + ret = 0; +out: + inode_unlock(inode); + return ret; +} + +int ext4_rbd_meta_file_deactivate(struct inode *inode) +{ + int ret; + if (!inode_owner_or_capable(inode)) + return -EACCES; + + inode_lock(inode); + + ret = update_inode_swapfile_flag(inode, false); + if (ret) + goto out; + + ret = 0; +out: + inode_unlock(inode); + return ret; +} +#endif /* MY_ABC_HERE */ + diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index cb54ea6461fd..660695d3af2c 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/ioctl.c @@ -271,6 +274,122 @@ static int uuid_is_zero(__u8 u[16]) } #endif +#ifdef MY_ABC_HERE +static int ext4_ioctl_get_features(struct file *filp, void __user *arg) +{ + struct inode *inode = file_inode(filp); + struct super_block *sb = inode->i_sb; + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + struct ext4_ioctl_feature_flags features; + + features.syno_capability = le32_to_cpu(es->s_feature_syno_capability); + + if (copy_to_user(arg, &features, sizeof(features))) + return -EFAULT; + return 0; +} + +static int check_feature_bits(u32 change_mask, u32 flags, + const char *type, u32 supported_flags, + u32 safe_set, u32 safe_clear) +{ + u32 disallowed, unsupported; + u32 set_mask = flags & change_mask; + u32 clear_mask = ~flags & change_mask; + + unsupported = set_mask & ~supported_flags; + if (unsupported) { + printk(KERN_WARNING + "this kernel does not support %s bits 0x%x\n", + type, unsupported); + return -EOPNOTSUPP; + } + + disallowed = set_mask & ~safe_set; + if (disallowed) { + printk(KERN_WARNING + "can't set %s bits 0x%x while mounted\n", + type, disallowed); + return -EPERM; + } + + disallowed = clear_mask & ~safe_clear; + if (disallowed) { + printk(KERN_WARNING + "can't clear %s bits 0x%x while mounted\n", + type, disallowed); + return -EPERM; + } + + return 0; +} + +#define check_feature(change_mask, flags, mask_base) \ +check_feature_bits(change_mask, flags, #mask_base, \ + EXT4_FEATURE_ ## mask_base ## _SUPP, \ + EXT4_FEATURE_ ## mask_base ## _SAFE_SET, \ + EXT4_FEATURE_ ## mask_base ## _SAFE_CLEAR) + +struct ext4_feature_args { + u32 set_capability; + u32 clear_capability; +}; + +static void update_features(struct super_block *sb, void *vals) +{ + struct ext4_feature_args *args = (struct ext4_feature_args *) vals; + + spin_lock(&(EXT4_SB(sb)->s_feature_lock)); + EXT4_SET_SYNO_CAPABILITY_FEATURE(sb, args->set_capability); + EXT4_CLEAR_SYNO_CAPABILITY_FEATURE(sb, args->clear_capability); + spin_unlock(&(EXT4_SB(sb)->s_feature_lock)); +} + +static int ext4_ioctl_set_features(struct file *filp, void __user *arg) +{ + int ret; + struct ext4_feature_args args; + struct inode *inode = file_inode(filp); + struct super_block *sb = inode->i_sb; + struct ext4_ioctl_feature_flags flags[2]; + + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto out; + } + + if (copy_from_user(flags, arg, sizeof(flags))) { + ret = -EFAULT; + goto out; + } + + /* Nothing to do */ + if (!flags[0].syno_capability) { + ret = 0; + goto out; + } + + ret = check_feature(flags[0].syno_capability, + flags[1].syno_capability, + SYNO_CAPABILITY); + if (ret) + goto out; + + ret = mnt_want_write_file(filp); + if (ret) + goto out; + + args.set_capability = flags[0].syno_capability & flags[1].syno_capability; + args.clear_capability = flags[0].syno_capability & ~flags[1].syno_capability; + + ret = ext4_syno_write_super(sb, &args, update_features); + + mnt_drop_write_file(filp); +out: + return ret; +} +#endif /* MY_ABC_HERE */ + /* * If immutable is set and we are not clearing it, we're not allowed to change * anything else in the inode. Don't error out if we're only trying to set @@ -348,6 +467,17 @@ static int ext4_ioctl_setflags(struct inode *inode, oldflags = ei->i_flags; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + /* + * we use IMMUTABLE & SWAPFILE protected data, + */ + if (IS_SWAPFILE(inode) && + ((flags ^ oldflags) & EXT4_IMMUTABLE_FL)) { + err = -ETXTBSY; + goto flags_out; + } +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + err = vfs_ioc_setflags_prepare(inode, oldflags, flags); if (err) goto flags_out; @@ -1125,7 +1255,11 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) range.minlen = max((unsigned int)range.minlen, q->limits.discard_granularity); - ret = ext4_trim_fs(sb, &range); + ret = ext4_trim_fs(sb, &range +#ifdef MY_ABC_HERE + , TRIM_SEND_TRIM +#endif /* MY_ABC_HERE */ + ); if (ret < 0) return ret; @@ -1135,6 +1269,30 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return 0; } +#ifdef MY_ABC_HERE + case FIHINTUNUSED: + { + struct request_queue *q = bdev_get_queue(sb->s_bdev); + struct fstrim_range range; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!blk_queue_unused_hint(q)) + return -EOPNOTSUPP; + + if (copy_from_user(&range, (struct fstrim_range __user *)arg, + sizeof(range))) + return -EFAULT; + + ret = ext4_trim_fs(sb, &range, TRIM_SEND_HINT); + if (!ret) + ext4_msg(sb, KERN_NOTICE, "total send %llu bytes hints", range.len); + + return ret; + } +#endif /* MY_ABC_HERE */ case EXT4_IOC_PRECACHE_EXTENTS: return ext4_ext_precache(inode); @@ -1314,6 +1472,12 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (!ext4_has_feature_verity(sb)) return -EOPNOTSUPP; return fsverity_ioctl_measure(filp, (void __user *)arg); +#ifdef MY_ABC_HERE + case EXT4_IOC_GET_FEATURES: + return ext4_ioctl_get_features(filp, (void __user *)arg); + case EXT4_IOC_SET_FEATURES: + return ext4_ioctl_set_features(filp, (void __user *)arg); +#endif /* MY_ABC_HERE */ default: return -ENOTTY; @@ -1331,6 +1495,22 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ret; } +#ifdef MY_ABC_HERE +long ext4_symlink_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + if (cmd != FS_IOC_GETFLAGS && cmd != FS_IOC_SETFLAGS) + return -ENOIOCTLCMD; + + ext4_fc_start_update(file_inode(filp)); + ret = __ext4_ioctl(filp, cmd, arg); + ext4_fc_stop_update(file_inode(filp)); + + return ret; +} +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_COMPAT long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1402,6 +1582,10 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case EXT4_IOC_GET_ES_CACHE: case FS_IOC_FSGETXATTR: case FS_IOC_FSSETXATTR: +#ifdef MY_ABC_HERE + case EXT4_IOC_GET_FEATURES: + case EXT4_IOC_SET_FEATURES: +#endif /* MY_ABC_HERE */ break; default: return -ENOIOCTLCMD; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index d7cb7d719ee5..213f09427455 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com @@ -3044,6 +3047,21 @@ static inline int ext4_issue_discard(struct super_block *sb, return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0); } +#ifdef MY_ABC_HERE +static inline int ext4_hint_unused(struct super_block *sb, + ext4_group_t block_group, ext4_grpblk_t cluster, int count) +{ + ext4_fsblk_t hint_block; + + hint_block = (EXT4_C2B(EXT4_SB(sb), cluster) + + ext4_group_first_block_no(sb, block_group)); + count = EXT4_C2B(EXT4_SB(sb), count); + trace_ext4_unused_hint_blocks(sb, + (unsigned long long) hint_block, count); + return sb_hint_unused(sb, hint_block, count, GFP_NOFS); +} +#endif /* MY_ABC_HERE */ + static void ext4_free_data_in_buddy(struct super_block *sb, struct ext4_free_data *entry) { @@ -5590,6 +5608,9 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) || in_range(block + count - 1, ext4_inode_table(sb, desc), sbi->s_itb_per_group)) { +#ifdef MY_ABC_HERE + if (printk_ratelimit()) +#endif /* MY_ABC_HERE */ ext4_error(sb, "Adding blocks in system zones - " "Block = %llu, count = %lu", block, count); @@ -5682,7 +5703,11 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, * be called with under the group lock. */ static int ext4_trim_extent(struct super_block *sb, int start, int count, - ext4_group_t group, struct ext4_buddy *e4b) + ext4_group_t group, struct ext4_buddy *e4b +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) __releases(bitlock) __acquires(bitlock) { @@ -5703,7 +5728,16 @@ __acquires(bitlock) */ mb_mark_used(e4b, &ex); ext4_unlock_group(sb, group); + +#ifdef MY_ABC_HERE + if (act == TRIM_SEND_HINT) + ret = ext4_hint_unused(sb, group, start, count); + else + ret = ext4_issue_discard(sb, group, start, count, NULL); +#else /* MY_ABC_HERE */ ret = ext4_issue_discard(sb, group, start, count, NULL); +#endif /* MY_ABC_HERE */ + ext4_lock_group(sb, group); mb_free_blocks(NULL, e4b, start, ex.fe_len); return ret; @@ -5730,7 +5764,11 @@ __acquires(bitlock) static ext4_grpblk_t ext4_trim_all_free(struct super_block *sb, ext4_group_t group, ext4_grpblk_t start, ext4_grpblk_t max, - ext4_grpblk_t minblocks) + ext4_grpblk_t minblocks +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { void *bitmap; ext4_grpblk_t next, count = 0, free_count = 0; @@ -5749,6 +5787,13 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, ext4_lock_group(sb, group); if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) && +#ifdef MY_ABC_HERE + /* + * ext4 skipped trim block group if it has already trimmed. + * We don't want to skip while doing hint scanning. + */ + act != TRIM_SEND_HINT && +#endif /* MY_ABC_HERE */ minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) goto out; @@ -5763,7 +5808,11 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, if ((next - start) >= minblocks) { ret = ext4_trim_extent(sb, start, - next - start, group, &e4b); + next - start, group, &e4b +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (ret && ret != -EOPNOTSUPP) break; ret = 0; @@ -5789,6 +5838,11 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, if (!ret) { ret = count; +#ifdef MY_ABC_HERE + /* Do not set as trimmed because we just sended hints */ + if (act == TRIM_SEND_HINT) + goto out; +#endif /* MY_ABC_HERE */ EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); } out: @@ -5813,7 +5867,11 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, * start to start+len. For each such a group ext4_trim_all_free function * is invoked to trim all free space. */ -int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) +int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range +#ifdef MY_ABC_HERE + , enum trim_act act +#endif /* MY_ABC_HERE */ + ) { struct ext4_group_info *grp; ext4_group_t group, first_group, last_group; @@ -5869,7 +5927,11 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) if (grp->bb_free >= minlen) { cnt = ext4_trim_all_free(sb, group, first_cluster, - end, minlen); + end, minlen +#ifdef MY_ABC_HERE + , act +#endif /* MY_ABC_HERE */ + ); if (cnt < 0) { ret = cnt; break; @@ -5884,6 +5946,12 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) first_cluster = 0; } +#ifdef MY_ABC_HERE + /* Do not set s_last_trim_minblks */ + if (act == TRIM_SEND_HINT) + goto out; +#endif /* MY_ABC_HERE */ + if (!ret) atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index ab7baf529917..c8e728e144ff 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/namei.c @@ -39,6 +42,13 @@ #include "ext4.h" #include "ext4_jbd2.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include "syno_acl.h" +#endif /* MY_ABC_HERE */ + #include "xattr.h" #include "acl.h" @@ -50,6 +60,64 @@ #define NAMEI_RA_BLOCKS 4 #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#ifdef MY_ABC_HERE +/* Hash a string to an integer in a caseless way */ +static int ext4_dentry_hash(const struct dentry *dentry, struct qstr *this) +{ +#ifdef CONFIG_UNICODE + const struct inode *dir = READ_ONCE(dentry->d_inode); +#endif /* CONFIG_UNICODE */ + /* + * hash_buf need to add 1 byte for syno_utf8_toupper, + * because it will append 0 to last byte. + */ + char hash_buf[EXT4_NAME_LEN+1]; + unsigned int upperlen; + +#ifdef CONFIG_UNICODE + if (dir && IS_CASEFOLDED(dir) && dir->i_sb->s_encoding) + return generic_ci_d_hash(dentry, this); +#endif /* CONFIG_UNICODE */ + + if (this->len > EXT4_NAME_LEN) + return -ENAMETOOLONG; + + upperlen = syno_utf8_toupper(hash_buf, this->name, + EXT4_NAME_LEN, this->len, NULL); + this->hash = full_name_hash(dentry, hash_buf, upperlen); + + return 0; +} + +/* return 1 on failure and 0 on success */ +static int ext4_dentry_compare(const struct dentry *dentry, + unsigned int len, const char *str, + const struct qstr *name, int caseless) +{ +#ifdef CONFIG_UNICODE + const struct dentry *parent = READ_ONCE(dentry->d_parent); + const struct inode *dir = READ_ONCE(parent->d_inode); + + if (dir && IS_CASEFOLDED(dir) && dir->i_sb->s_encoding) + return generic_ci_d_compare(dentry, len, str, name); +#endif /* CONFIG_UNICODE */ + + if (caseless) { + return syno_utf8_strcmp(str, name->name, len, name->len, NULL); + } else { + if (len != name->len) + return 1; + return dentry_cmp(dentry, name->name, name->len); + } +} + +const struct dentry_operations ext4_dentry_operations = +{ + .d_hash = ext4_dentry_hash, + .d_compare_case = ext4_dentry_compare, +}; +#endif /* MY_ABC_HERE */ + static struct buffer_head *ext4_append(handle_t *handle, struct inode *inode, ext4_lblk_t *block) @@ -295,7 +363,12 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash, __u32 *start_hash); static struct buffer_head * ext4_dx_find_entry(struct inode *dir, struct ext4_filename *fname, - struct ext4_dir_entry_2 **res_dir); + struct ext4_dir_entry_2 **res_dir +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ); + static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, struct inode *dir, struct inode *inode); @@ -1194,10 +1267,18 @@ static inline int search_dirblock(struct buffer_head *bh, struct inode *dir, struct ext4_filename *fname, unsigned int offset, - struct ext4_dir_entry_2 **res_dir) + struct ext4_dir_entry_2 **res_dir +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { return ext4_search_dir(bh, bh->b_data, dir->i_sb->s_blocksize, dir, - fname, offset, res_dir); + fname, offset, res_dir +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + ); } /* @@ -1344,7 +1425,12 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, */ static inline bool ext4_match(const struct inode *parent, const struct ext4_filename *fname, - const struct ext4_dir_entry_2 *de) + const struct ext4_dir_entry_2 *de +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) + { struct fscrypt_name f; #ifdef CONFIG_UNICODE @@ -1372,6 +1458,13 @@ static inline bool ext4_match(const struct inode *parent, } #endif +#ifdef MY_ABC_HERE + if (caseless) + return !syno_utf8_strcmp(de->name, fname->usr_fname->name, + de->name_len, fname->usr_fname->len, + NULL); +#endif /* MY_ABC_HERE */ + return fscrypt_match_name(&f, de->name, de->name_len); } @@ -1380,7 +1473,11 @@ static inline bool ext4_match(const struct inode *parent, */ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size, struct inode *dir, struct ext4_filename *fname, - unsigned int offset, struct ext4_dir_entry_2 **res_dir) + unsigned int offset, struct ext4_dir_entry_2 **res_dir +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { struct ext4_dir_entry_2 * de; char * dlimit; @@ -1392,7 +1489,11 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size, /* this code is executed quadratically often */ /* do minimal checking `by hand' */ if ((char *) de + de->name_len <= dlimit && - ext4_match(dir, fname, de)) { + ext4_match(dir, fname, de +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + )) { /* found a match - just to be sure, do * a full check */ if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf, @@ -1442,7 +1543,11 @@ static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, static struct buffer_head *__ext4_find_entry(struct inode *dir, struct ext4_filename *fname, struct ext4_dir_entry_2 **res_dir, - int *inlined) + int *inlined +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { struct super_block *sb; struct buffer_head *bh_use[NAMEI_RA_SIZE]; @@ -1465,7 +1570,11 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir, if (ext4_has_inline_data(dir)) { int has_inline_data = 1; ret = ext4_find_inline_entry(dir, fname, res_dir, - &has_inline_data); + &has_inline_data +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + ); if (has_inline_data) { if (inlined) *inlined = 1; @@ -1484,7 +1593,11 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir, goto restart; } if (is_dx(dir)) { +#ifdef MY_ABC_HERE + ret = ext4_dx_find_entry(dir, fname, res_dir, caseless); +#else /* MY_ABC_HERE */ ret = ext4_dx_find_entry(dir, fname, res_dir); +#endif /* MY_ABC_HERE */ /* * On success, or if the error was file not found, * return. Otherwise, fall back to doing a search the @@ -1551,7 +1664,11 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir, } set_buffer_verified(bh); i = search_dirblock(bh, dir, fname, - block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); + block << EXT4_BLOCK_SIZE_BITS(sb), res_dir +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + ); if (i == 1) { EXT4_I(dir)->i_dir_start_lookup = block; ret = bh; @@ -1599,15 +1716,35 @@ static struct buffer_head *ext4_find_entry(struct inode *dir, if (err) return ERR_PTR(err); +#ifdef MY_ABC_HERE + bh = __ext4_find_entry(dir, &fname, res_dir, inlined, 0); +#else /* MY_ABC_HERE */ bh = __ext4_find_entry(dir, &fname, res_dir, inlined); +#endif /* MY_ABC_HERE */ ext4_fname_free_filename(&fname); return bh; } +#ifdef MY_ABC_HERE +static inline int ext4_replace_caseless_dentry_name(struct dentry *dentry, + const struct ext4_dir_entry_2 *de) +{ + if ((dentry->d_name.len == de->name_len) + && !dentry_string_cmp(dentry->d_name.name, + de->name, de->name_len)) + return 0; + return dentry_replace_name(dentry, de->name, de->name_len); +} +#endif /* MY_ABC_HERE */ + static struct buffer_head *ext4_lookup_entry(struct inode *dir, struct dentry *dentry, - struct ext4_dir_entry_2 **res_dir) + struct ext4_dir_entry_2 **res_dir +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { int err; struct ext4_filename fname; @@ -1619,7 +1756,27 @@ static struct buffer_head *ext4_lookup_entry(struct inode *dir, if (err) return ERR_PTR(err); +#ifdef MY_ABC_HERE + bh = __ext4_find_entry(dir, &fname, res_dir, NULL, caseless); +#else /* MY_ABC_HERE */ bh = __ext4_find_entry(dir, &fname, res_dir, NULL); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* + * If we do caseless lookup after dentry queue of parent be cleared, + * file name may async between dentry queue and disk. + * So we should make sure it is the real name before dentry be added to queue. + */ + if (caseless && !IS_ERR_OR_NULL(bh) && *res_dir) { + err = ext4_replace_caseless_dentry_name(dentry, *res_dir); + if (err) { + ext4_fname_free_filename(&fname); + brelse(bh); + return ERR_PTR(err); + } + } +#endif /* MY_ABC_HERE */ ext4_fname_free_filename(&fname); return bh; @@ -1627,7 +1784,11 @@ static struct buffer_head *ext4_lookup_entry(struct inode *dir, static struct buffer_head * ext4_dx_find_entry(struct inode *dir, struct ext4_filename *fname, - struct ext4_dir_entry_2 **res_dir) + struct ext4_dir_entry_2 **res_dir +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ) { struct super_block * sb = dir->i_sb; struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; @@ -1649,7 +1810,11 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, retval = search_dirblock(bh, dir, fname, block << EXT4_BLOCK_SIZE_BITS(sb), - res_dir); + res_dir +#ifdef MY_ABC_HERE + , caseless +#endif /* MY_ABC_HERE */ + ); if (retval == 1) goto success; brelse(bh); @@ -1683,11 +1848,28 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi struct inode *inode; struct ext4_dir_entry_2 *de; struct buffer_head *bh; +#ifdef MY_ABC_HERE + int caseless = 0; + + if (flags & LOOKUP_CASELESS_COMPARE) { +#ifdef CONFIG_UNICODE + if (!is_syno_ext((dir)->i_sb) && !(dir->i_sb->s_encoding && IS_CASEFOLDED(dir))) +#else /* CONFIG_UNICODE */ + if (!is_syno_ext((dir)->i_sb)) +#endif /* CONFIG_UNICODE */ + return ERR_PTR(-EOPNOTSUPP); + caseless = 1; + } +#endif /* MY_ABC_HERE */ if (dentry->d_name.len > EXT4_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); +#ifdef MY_ABC_HERE + bh = ext4_lookup_entry(dir, dentry, &de, caseless); +#else /* MY_ABC_HERE */ bh = ext4_lookup_entry(dir, dentry, &de); +#endif /* MY_ABC_HERE */ if (IS_ERR(bh)) return ERR_CAST(bh); inode = NULL; @@ -1947,7 +2129,11 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, if (ext4_check_dir_entry(dir, NULL, de, bh, buf, buf_size, offset)) return -EFSCORRUPTED; +#ifdef MY_ABC_HERE + if (ext4_match(dir, fname, de, 0)) +#else /* MY_ABC_HERE */ if (ext4_match(dir, fname, de)) +#endif /* MY_ABC_HERE */ return -EEXIST; nlen = EXT4_DIR_REC_LEN(de->name_len); rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); @@ -2254,7 +2440,11 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, goto out; if (blocks == 1 && !dx_fallback && +#ifdef MY_ABC_HERE + (is_syno_ext(sb) || ext4_has_feature_dir_index(sb))) { +#else /* MY_ABC_HERE */ ext4_has_feature_dir_index(sb)) { +#endif /* MY_ABC_HERE */ retval = make_indexed_dir(handle, &fname, dir, inode, bh); bh = NULL; /* make_indexed_dir releases bh */ @@ -3404,6 +3594,9 @@ static int ext4_symlink(struct inode *dir, disk_link.len); inode->i_size = disk_link.len - 1; } +#ifdef MY_ABC_HERE + inode->i_fop = &ext4_symlink_file_operations; +#endif /* MY_ABC_HERE */ EXT4_I(inode)->i_disksize = inode->i_size; err = ext4_add_nondir(handle, dentry, &inode); if (handle) @@ -4144,6 +4337,16 @@ static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry, * directories can handle most operations... */ const struct inode_operations ext4_dir_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = ext4_syno_getattr, +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_set_archive_bit = ext4_syno_set_archive_bit, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ext4_syno_get_inode_archive_version, + .syno_set_archive_version = ext4_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ .create = ext4_create, .lookup = ext4_lookup, .link = ext4_link, @@ -4159,13 +4362,35 @@ const struct inode_operations ext4_dir_inode_operations = { .listxattr = ext4_listxattr, .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, +#ifdef MY_ABC_HERE + .syno_get_acl = ext4_get_syno_acl, + .syno_set_acl = ext4_set_syno_acl, +#endif /* MY_ABC_HERE */ .fiemap = ext4_fiemap, +#ifdef MY_ABC_HERE + .syno_get_crtime = ext4_syno_get_crtime, + .syno_set_crtime = ext4_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; const struct inode_operations ext4_special_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = ext4_syno_getattr, +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_set_archive_bit = ext4_syno_set_archive_bit, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ext4_syno_get_inode_archive_version, + .syno_set_archive_version = ext4_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ .setattr = ext4_setattr, .getattr = ext4_getattr, .listxattr = ext4_listxattr, .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, +#ifdef MY_ABC_HERE + .syno_get_crtime = ext4_syno_get_crtime, + .syno_set_crtime = ext4_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 928700d57eb6..0fb0b897d454 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/resize.c @@ -1362,6 +1365,9 @@ static void ext4_update_super(struct super_block *sb, struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; int i; +#ifdef MY_ABC_HERE + u32 add_inode_count = EXT4_INODES_PER_GROUP(sb) * flex_gd->count; +#endif /* MY_ABC_HERE */ BUG_ON(flex_gd->count == 0 || group_data == NULL); /* @@ -1386,10 +1392,20 @@ static void ext4_update_super(struct super_block *sb, ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count); ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks); +#ifdef MY_ABC_HERE + if ((U32_MAX - le32_to_cpu(es->s_inodes_count)) >= add_inode_count) { + le32_add_cpu(&es->s_inodes_count, add_inode_count); + le32_add_cpu(&es->s_free_inodes_count, add_inode_count); + } else { + es->s_free_inodes_count += cpu_to_le32(U32_MAX - le32_to_cpu(es->s_inodes_count)); + es->s_inodes_count = cpu_to_le32(U32_MAX); + } +#else /* MY_ABC_HERE */ le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) * flex_gd->count); le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * flex_gd->count); +#endif /* MY_ABC_HERE */ ext4_debug("free blocks count %llu", ext4_free_blocks_count(es)); /* @@ -1958,10 +1974,16 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) return 0; n_group = ext4_get_group_number(sb, n_blocks_count - 1); +#ifdef MY_ABC_HERE + /* + * We will handle overflow in `ext4_update_super()`. + */ +#else /* MY_ABC_HERE */ if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { ext4_warning(sb, "resize would cause inodes_count overflow"); return -EINVAL; } +#endif /* MY_ABC_HERE */ ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); n_desc_blocks = num_desc_blocks(sb, n_group + 1); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 099e4afa41e5..d1531b94f241 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/super.c @@ -47,6 +50,13 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #include "ext4.h" #include "ext4_extents.h" /* Needed for trace points definition */ #include "ext4_jbd2.h" @@ -114,6 +124,10 @@ static struct inode *ext4_get_journal_inode(struct super_block *sb, * transaction start -> page lock(s) -> i_data_sem (rw) */ +#ifdef MY_ABC_HERE +extern struct dentry_operations ext4_dentry_operations; +#endif /* MY_ABC_HERE */ + #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) static struct file_system_type ext2_fs_type = { .owner = THIS_MODULE, @@ -141,6 +155,12 @@ MODULE_ALIAS_FS("ext3"); MODULE_ALIAS("ext3"); #define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +int ext4_is_ext3_sb(struct super_block *sb) +{ + return IS_EXT3_SB(sb); +} +#endif /* MY_ABC_HERE || MY_ABC_HERE || MY_ABC_HERE */ static inline void __ext4_read_bh(struct buffer_head *bh, int op_flags, bh_end_io_t *end_io) @@ -414,6 +434,43 @@ static void __ext4_update_tstamp(__le32 *lo, __u8 *hi) *hi = upper_32_bits(now); } +#ifdef MY_ABC_HERE +int (*funcSYNOSendErrorFsEvent)(const unsigned char*, const unsigned int) = NULL; +EXPORT_SYMBOL(funcSYNOSendErrorFsEvent); + +static void syno_auto_error_fs_report(const unsigned char *dsm_version, + const unsigned int error_count) +{ + if (NULL == funcSYNOSendErrorFsEvent) { + printk(KERN_ERR +"EXT4-fs error: Can't reference to function 'funcSYNOSendErrorFsEvent', DSM(%s), error count(%d)\n", + dsm_version, error_count); + return; + } + funcSYNOSendErrorFsEvent(dsm_version, error_count); +} + +static int syno_ext4_get_dsm_version(const unsigned char *version_name, + char *dsm_version, + const int len) +{ + int ret = 0; + char *p = NULL; + /* + * get DSM version from szVersionName. + * eg. get 3202 from "1.42.6-3032" + */ + p = strchr(version_name, '-'); + if (!p) + return -EINVAL; + + ret = snprintf(dsm_version, len, "%s", p + 1); + if (0 > ret || len <= ret) + return -ENOBUFS; + return ret; +} +#endif /* MY_ABC_HERE */ + static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi) { return ((time64_t)(*hi) << 32) + le32_to_cpu(*lo); @@ -422,6 +479,14 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi) __ext4_update_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) #define ext4_get_tstamp(es, tstamp) \ __ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) +#ifdef MY_ABC_HERE +static bool ext4_is_valid_syno_capability(struct super_block *sb) +{ + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + return (le32_to_cpu(es->s_syno_mtime) == le32_to_cpu(es->s_mtime)) && + (le64_to_cpu(es->s_syno_kbytes_written) == le64_to_cpu(es->s_kbytes_written)); +} +#endif /* MY_ABC_HERE */ static void __save_error_info(struct super_block *sb, int error, __u32 ino, __u64 block, @@ -430,6 +495,11 @@ static void __save_error_info(struct super_block *sb, int error, struct ext4_super_block *es = EXT4_SB(sb)->s_es; int err; +#ifdef MY_ABC_HERE + struct ext4_sb_info *sbi = EXT4_SB(sb); + char dsm_version[8] = {'\0'}; +#endif /* MY_ABC_HERE */ + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; if (bdev_read_only(sb->s_bdev)) return; @@ -510,6 +580,28 @@ static void __save_error_info(struct super_block *sb, int error, if (!es->s_error_count) mod_timer(&EXT4_SB(sb)->s_err_report, jiffies + 24*60*60*HZ); le32_add_cpu(&es->s_error_count, 1); +#ifdef MY_ABC_HERE + /* + * We don't need to care system FS, and we only issue once every day. + */ + if (sbi->s_mount_path + && (0 == sbi->s_new_error_fs_event_flag) + && ((0 == sbi->s_last_notify_time) || + time_after(jiffies, sbi->s_last_notify_time + 24*60*60*HZ)) + && is_syno_ext(sb)) { + sbi->s_new_error_fs_event_flag = 1; + sbi->s_last_notify_time = jiffies; + err = syno_ext4_get_dsm_version(es->s_volume_name, + dsm_version, sizeof(dsm_version)); + if (likely(err > 0)) + syno_auto_error_fs_report(dsm_version, + (unsigned int) es->s_error_count); + else + printk(KERN_ERR + "Failed to parse dsm version on %s with err %d\n", + es->s_volume_name, err); + } +#endif /* MY_ABC_HERE */ } static void save_error_info(struct super_block *sb, int error, @@ -1232,6 +1324,10 @@ static void ext4_put_super(struct super_block *sb) for (i = 0; i < EXT4_MAXQUOTAS; i++) kfree(get_qf_name(sb, sbi, i)); #endif +#ifdef MY_ABC_HERE + if (sbi->s_mount_path) + kfree(sbi->s_mount_path); +#endif /* MY_ABC_HERE */ /* Debugging code just in case the in-memory inode orphan list * isn't empty. The on-disk one can be non-empty if we've @@ -1599,6 +1695,70 @@ static const struct fscrypt_operations ext4_cryptops = { }; #endif +#ifdef MY_ABC_HERE +static int ext4_syno_set_sb_archive_version(struct super_block *sb, u32 archive_version) +{ + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + handle_t *handle; + int ret = 0; + int ret2; + + if (!ext4_has_feature_journal(sb)) { + es->s_archive_version = cpu_to_le32(archive_version); + ret = ext4_commit_super(sb, 1); + goto exit; + } + + handle = ext4_journal_start_sb(sb, EXT4_HT_SYNO, 1); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto exit; + } + ret = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); + if (ret) + goto exit_journal; + + es->s_archive_version = cpu_to_le32(archive_version); + ret = ext4_handle_dirty_super(handle, sb); + +exit_journal: + if ((ret2 = ext4_journal_stop(handle)) && !ret) + ret = ret2; +exit: + if (!ret) + sb->s_archive_version = archive_version; + return ret; +} + +static int ext4_syno_get_sb_archive_version(struct super_block *sb, u32 *version) +{ + *version = sb->s_archive_version; + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static void update_mapping_table_offset(struct super_block *sb, void *vals) +{ + u64 *offset = (u64 *) vals; + + EXT4_SB(sb)->s_es->s_syno_rbd_first_mapping_table_offset = cpu_to_le64(*offset); +} + +static int ext4_syno_rbd_set_first_mapping_table_offset(struct super_block *sb, + u64 offset) +{ + return ext4_syno_write_super(sb, &offset, update_mapping_table_offset); +} + +static int ext4_delete_all_rbd_meta_file_records(struct inode *inode) +{ + // do nothing. + return 0; +} +#endif /* MY_ABC_HERE */ + + #ifdef CONFIG_QUOTA static const char * const quotatypes[] = INITQFNAMES; #define QTYPE2NAME(t) (quotatypes[t]) @@ -1651,6 +1811,10 @@ static const struct quotactl_ops ext4_qctl_operations = { #endif static const struct super_operations ext4_sops = { +#ifdef MY_ABC_HERE + .syno_get_sb_archive_version = ext4_syno_get_sb_archive_version, + .syno_set_sb_archive_version = ext4_syno_set_sb_archive_version, +#endif /* MY_ABC_HERE */ .alloc_inode = ext4_alloc_inode, .free_inode = ext4_free_in_core_inode, .destroy_inode = ext4_destroy_inode, @@ -1671,6 +1835,10 @@ static const struct super_operations ext4_sops = { .get_dquots = ext4_get_dquots, #endif .bdev_try_to_free_page = bdev_try_to_free_page, +#ifdef MY_ABC_HERE + .syno_rbd_set_first_mapping_table_offset = ext4_syno_rbd_set_first_mapping_table_offset, + .syno_rbd_meta_file_cleanup_all = ext4_delete_all_rbd_meta_file_records, +#endif /* MY_ABC_HERE */ }; static const struct export_operations ext4_export_ops = { @@ -1708,6 +1876,12 @@ enum { #ifdef CONFIG_EXT4_DEBUG Opt_fc_debug_max_replay, Opt_fc_debug_force #endif +#ifdef MY_ABC_HERE + Opt_synoacl, Opt_nosynoacl, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + Opt_rootprjquota, +#endif /* MY_ABC_HERE */ }; static const match_table_t tokens = { @@ -1731,6 +1905,10 @@ static const match_table_t tokens = { {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, +#ifdef MY_ABC_HERE + {Opt_synoacl, SYNO_ACL_MNT_OPT}, + {Opt_nosynoacl, SYNO_ACL_NOT_MNT_OPT}, +#endif /* MY_ABC_HERE */ {Opt_noload, "norecovery"}, {Opt_noload, "noload"}, {Opt_removed, "nobh"}, @@ -1761,6 +1939,9 @@ static const match_table_t tokens = { {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_prjquota, "prjquota"}, +#ifdef MY_ABC_HERE + {Opt_rootprjquota, "rootprjquota"}, +#endif /* MY_ABC_HERE */ {Opt_barrier, "barrier=%u"}, {Opt_barrier, "barrier"}, {Opt_nobarrier, "nobarrier"}, @@ -2000,6 +2181,10 @@ static const struct mount_opts { {Opt_acl, 0, MOPT_NOSUPPORT}, {Opt_noacl, 0, MOPT_NOSUPPORT}, #endif +#ifdef MY_ABC_HERE + {Opt_synoacl, EXT4_MOUNT_SYNO_ACL, MOPT_SET}, + {Opt_nosynoacl, EXT4_MOUNT_SYNO_ACL, MOPT_CLEAR}, +#endif /* MY_ABC_HERE */ {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET}, {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET}, {Opt_debug_want_extra_isize, 0, MOPT_GTE0}, @@ -2010,6 +2195,10 @@ static const struct mount_opts { MOPT_SET | MOPT_Q}, {Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA, MOPT_SET | MOPT_Q}, +#ifdef MY_ABC_HERE + {Opt_rootprjquota, EXT4_MOUNTSYNO_ROOTPRJQUOTA, + MOPT_SET}, +#endif /* MY_ABC_HERE */ {Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA | EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA), MOPT_CLEAR | MOPT_Q}, @@ -2155,6 +2344,11 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, ext4_msg(sb, KERN_ERR, "inline encryption not supported"); #endif return 1; +#ifdef MY_ABC_HERE + case Opt_rootprjquota: + set_opt_syno(sb, ROOTPRJQUOTA); + return 1; +#endif /* MY_ABC_HERE */ } for (m = ext4_mount_opts; m->token != Opt_err; m++) @@ -2696,12 +2890,27 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); le16_add_cpu(&es->s_mnt_count, 1); ext4_update_tstamp(es, s_mtime); + +#ifdef MY_ABC_HERE + // For linux-4.4 compatibility, we drop the hi bit on s_mtime. + es->s_syno_mtime = es->s_mtime; +#endif /* MY_ABC_HERE */ if (sbi->s_journal) ext4_set_feature_journal_needs_recovery(sb); err = ext4_commit_super(sb, 1); done: if (test_opt(sb, DEBUG)) +#ifdef MY_ABC_HERE + printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " + "bpg=%lu, ipg=%lu, mo=%04x, mo2=%04x, mo_syno=%04x]\n", + sb->s_blocksize, + sbi->s_groups_count, + EXT4_BLOCKS_PER_GROUP(sb), + EXT4_INODES_PER_GROUP(sb), + sbi->s_mount_opt, sbi->s_mount_opt2, + sbi->s_mount_opt_syno); +#else /* MY_ABC_HERE */ printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " "bpg=%lu, ipg=%lu, mo=%04x, mo2=%04x]\n", sb->s_blocksize, @@ -2709,6 +2918,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, EXT4_BLOCKS_PER_GROUP(sb), EXT4_INODES_PER_GROUP(sb), sbi->s_mount_opt, sbi->s_mount_opt2); +#endif /* MY_ABC_HERE */ cleancache_init_fs(sb); return err; @@ -3473,7 +3683,11 @@ static int ext4_run_li_request(struct ext4_li_request *elr) ret = ext4_init_inode_table(sb, group, elr->lr_timeout ? 0 : 1); trace_ext4_lazy_itable_init(sb, group); +#ifdef MY_ABC_HERE + if (elr->lr_timeout == 0 || ((elr->lr_next_group % 10) == 0)) { +#else /* MY_ABC_HERE */ if (elr->lr_timeout == 0) { +#endif /* MY_ABC_HERE */ timeout = (jiffies - timeout) * EXT4_SB(elr->lr_super)->s_li_wait_mult; elr->lr_timeout = timeout; @@ -4174,6 +4388,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; +#ifdef MY_ABC_HERE + spin_lock_init(&sbi->s_feature_lock); +#endif /* MY_ABC_HERE */ + if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0) set_opt(sb, BARRIER); @@ -4289,6 +4507,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) kfree(s_mount_opts); } sbi->s_def_mount_opt = sbi->s_mount_opt; +#ifdef MY_ABC_HERE + set_opt(sb, JOURNAL_CHECKSUM); +#endif /* MY_ABC_HERE */ if (!parse_options((char *) data, sb, &journal_devnum, &journal_ioprio, 0)) goto failed_mount; @@ -4359,10 +4580,23 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); +#ifdef MY_ABC_HERE + if (test_opt(sb, SYNO_ACL)) { + if (syno_acl_module_get()) + sb->s_flags |= SB_SYNOACL; + else + clear_opt(sb, SYNO_ACL); + } +#endif /* MY_ABC_HERE */ + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV && (ext4_has_compat_features(sb) || ext4_has_ro_compat_features(sb) || - ext4_has_incompat_features(sb))) + ext4_has_incompat_features(sb) +#ifdef MY_ABC_HERE + || ext4_has_syno_capability_features(sb) +#endif /* MY_ABC_HERE */ + )) ext4_msg(sb, KERN_WARNING, "feature flags set on rev 0 fs, " "running e2fsck is recommended"); @@ -4428,7 +4662,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (!ext4_feature_set_ok(sb, (sb_rdonly(sb)))) goto failed_mount; +#ifdef MY_ABC_HERE + /* + * DSM#20845 + * for online resize > 16T, when no meta_bg + */ + if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > 8189) { +#else /* MY_ABC_HERE */ if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { +#endif /* MY_ABC_HERE */ ext4_msg(sb, KERN_ERR, "Number of reserved GDT blocks insanely large: %d", le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks)); @@ -4490,6 +4732,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; } } +#ifdef MY_ABC_HERE + if (!ext4_is_valid_syno_capability(sb)) { + printk(KERN_WARNING "Clean up capability flag (0x%X)\n", + es->s_feature_syno_capability); + es->s_feature_syno_capability = 0; + } + + if (EXT4_HAS_SYNO_CAPABILITY_FEATURE(sb, ~EXT4_FEATURE_SYNO_CAPABILITY_SUPP)) { + printk(KERN_WARNING "Clean up unsupport capability flag (0x%X)\n", + le32_to_cpu(es->s_feature_syno_capability) & + ~EXT4_FEATURE_SYNO_CAPABILITY_SUPP); + EXT4_CLEAR_SYNO_CAPABILITY_FEATURE(sb, ~EXT4_FEATURE_SYNO_CAPABILITY_SUPP); + } +#endif /* MY_ABC_HERE */ + has_huge_files = ext4_has_feature_huge_file(sb); sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, @@ -4532,7 +4789,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) for (i = 0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; +#ifdef MY_ABC_HERE + if (is_syno_ext(sb) || ext4_has_feature_dir_index(sb)) { +#else /* MY_ABC_HERE */ if (ext4_has_feature_dir_index(sb)) { +#endif /* MY_ABC_HERE */ i = le32_to_cpu(es->s_flags); if (i & EXT2_FLAGS_UNSIGNED_HASH) sbi->s_hash_unsigned = 3; @@ -4657,6 +4918,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sbi->s_groups_count = blocks_count; sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) != le32_to_cpu(es->s_inodes_count)) { ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu", @@ -4665,6 +4928,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ret = -EINVAL; goto failed_mount; } +#endif /* MY_ABC_HERE */ db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); if (ext4_has_feature_meta_bg(sb)) { @@ -4969,6 +5233,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &ext4_dentry_ops; #endif +#ifdef MY_ABC_HERE + if (is_syno_ext(sb)) + sb->s_d_op = &ext4_dentry_operations; +#endif /* MY_ABC_HERE */ sb->s_root = d_make_root(root); if (!sb->s_root) { ext4_msg(sb, KERN_ERR, "get root dentry failed"); @@ -4976,6 +5244,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount4; } +#ifdef MY_ABC_HERE + sb->s_archive_version = le32_to_cpu(es->s_archive_version); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (!IsSynoRbdDeviceEnabled(sb->s_bdev) && ext4_has_feature_syno_rbd_meta(sb)) { + ext4_msg(sb, KERN_WARNING, + "Rbd device is disabled, we drop rbd capability."); + ext4_clear_feature_syno_rbd_meta(sb); + } + + if (!ext4_has_feature_syno_rbd_meta(sb)) + es->s_syno_rbd_first_mapping_table_offset = 0ULL; +#endif /* MY_ABC_HERE */ + ret = ext4_setup_super(sb, es, sb_rdonly(sb)); if (ret == -EROFS) { sb->s_flags |= SB_RDONLY; @@ -5019,7 +5302,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) GFP_KERNEL); if (!err) { unsigned long freei = ext4_count_free_inodes(sb); - sbi->s_es->s_free_inodes_count = cpu_to_le32(freei); +#ifdef MY_ABC_HERE + if ((u64) U32_MAX >= freei) +#endif /* MY_ABC_HERE */ + sbi->s_es->s_free_inodes_count = cpu_to_le32(freei); ext4_superblock_csum_set(sb); err = percpu_counter_init(&sbi->s_freeinodes_counter, freei, GFP_KERNEL); @@ -5054,6 +5340,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (err) goto failed_mount6; +#ifdef MY_ABC_HERE + spin_lock_init(&sbi->s_mount_path_lock); +#endif /* MY_ABC_HERE */ + err = ext4_register_sysfs(sb); if (err) goto failed_mount7; @@ -5529,11 +5819,18 @@ static int ext4_commit_super(struct super_block *sb, int sync) else es->s_kbytes_written = cpu_to_le64(EXT4_SB(sb)->s_kbytes_written); +#ifdef MY_ABC_HERE + es->s_syno_kbytes_written = es->s_kbytes_written; +#endif /* MY_ABC_HERE */ if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeclusters_counter)) ext4_free_blocks_count_set(es, EXT4_C2B(EXT4_SB(sb), percpu_counter_sum_positive( &EXT4_SB(sb)->s_freeclusters_counter))); - if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter)) + if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter) +#ifdef MY_ABC_HERE + && (u64) U32_MAX >= percpu_counter_sum_positive(&EXT4_SB(sb)->s_freeinodes_counter) +#endif /* MY_ABC_HERE */ + ) es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive( &EXT4_SB(sb)->s_freeinodes_counter)); @@ -5696,6 +5993,12 @@ static int ext4_sync_fs(struct super_block *sb, int wait) } } else if (wait && test_opt(sb, BARRIER)) needs_barrier = true; + +#ifdef MY_ABC_HERE + if (test_opt(sb, DATA_FLAGS) != EXT4_MOUNT_WRITEBACK_DATA) + needs_barrier = false; +#endif /* MY_ABC_HERE */ + if (needs_barrier) { int err; err = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL); @@ -5772,6 +6075,9 @@ static int ext4_unfreeze(struct super_block *sb) struct ext4_mount_options { unsigned long s_mount_opt; unsigned long s_mount_opt2; +#ifdef MY_ABC_HERE + unsigned long s_mount_opt_syno; +#endif /* MY_ABC_HERE */ kuid_t s_resuid; kgid_t s_resgid; unsigned long s_commit_interval; @@ -5805,6 +6111,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; old_opts.s_mount_opt2 = sbi->s_mount_opt2; +#ifdef MY_ABC_HERE + old_opts.s_mount_opt_syno = sbi->s_mount_opt_syno; +#endif /* MY_ABC_HERE */ old_opts.s_resuid = sbi->s_resuid; old_opts.s_resgid = sbi->s_resgid; old_opts.s_commit_interval = sbi->s_commit_interval; @@ -5883,6 +6192,18 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); +#ifdef MY_ABC_HERE + if ((sb->s_flags & SB_SYNOACL) && !test_opt(sb, SYNO_ACL)) { + sb->s_flags &= ~SB_SYNOACL; + syno_acl_module_put(); + } else if ( !(sb->s_flags & SB_SYNOACL) && test_opt(sb, SYNO_ACL)) { + if (syno_acl_module_get()) + sb->s_flags |= SB_SYNOACL; + else + clear_opt(sb, SYNO_ACL); + } +#endif /* MY_ABC_HERE */ + es = sbi->s_es; if (sbi->s_journal) { @@ -6423,6 +6744,11 @@ static int ext4_enable_quotas(struct super_block *sb) return err; } +#ifdef MY_ABC_HERE + if (PRJQUOTA == type && test_opt_syno(sb, ROOTPRJQUOTA)) { + sb->s_flags |= SB_ROOTPRJQUOTA; + } +#endif /* MY_ABC_HERE */ } } return 0; @@ -6580,6 +6906,69 @@ static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); } +#ifdef MY_ABC_HERE +static void ext4_kill_sb(struct super_block *sb) +{ + kill_block_super(sb); + + if (SB_SYNOACL & sb->s_flags) + syno_acl_module_put(); +} +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +// You should not update superblock before calling this function. +int ext4_syno_write_super(struct super_block *sb, void *vals, + void (*updater)(struct super_block *sb, void *vals)) +{ + int ret; + handle_t *handle; + + if (!ext4_has_feature_journal(sb)) { + updater(sb, vals); + ret = ext4_commit_super(sb, 1); + goto out; + } + + handle = ext4_journal_start_sb(sb, EXT4_HT_SYNO, 1); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + + ret = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); + if (ret) + goto out_journal; + + updater(sb, vals); + ret = ext4_handle_dirty_super(handle, sb); + if (ret) { + ext4_journal_stop(handle); + goto out; + } +out_journal: + ret = ext4_journal_stop(handle); + if (ret) + goto out; + /* + * Only when ext4 is mounted, the journal would be applied. + * So, to prevent we lose the capability bit and rbd_offset + * on the raw device during an abnormal shutdown, we should + * flush journal here. + */ + if (EXT4_SB(sb)->s_journal) { + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + ret = jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); + if (ret) + goto out; + } + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) static inline void register_as_ext2(void) { @@ -6640,7 +7029,11 @@ static struct file_system_type ext4_fs_type = { .owner = THIS_MODULE, .name = "ext4", .mount = ext4_mount, +#ifdef MY_ABC_HERE + .kill_sb = ext4_kill_sb, +#else .kill_sb = kill_block_super, +#endif /* MY_ABC_HERE */ .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("ext4"); diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index dd05af983092..75f250850d5d 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/symlink.c @@ -53,22 +56,69 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, } const struct inode_operations ext4_encrypted_symlink_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = ext4_syno_getattr, +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_set_archive_bit = ext4_syno_set_archive_bit, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ext4_syno_get_inode_archive_version, + .syno_set_archive_version = ext4_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ .get_link = ext4_encrypted_get_link, .setattr = ext4_setattr, .getattr = ext4_getattr, .listxattr = ext4_listxattr, +#ifdef MY_ABC_HERE + .syno_get_crtime = ext4_syno_get_crtime, + .syno_set_crtime = ext4_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; const struct inode_operations ext4_symlink_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = ext4_syno_getattr, +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_set_archive_bit = ext4_syno_set_archive_bit, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ext4_syno_get_inode_archive_version, + .syno_set_archive_version = ext4_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ .get_link = page_get_link, .setattr = ext4_setattr, .getattr = ext4_getattr, .listxattr = ext4_listxattr, +#ifdef MY_ABC_HERE + .syno_get_crtime = ext4_syno_get_crtime, + .syno_set_crtime = ext4_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; const struct inode_operations ext4_fast_symlink_inode_operations = { +#ifdef MY_ABC_HERE + .syno_getattr = ext4_syno_getattr, +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_set_archive_bit = ext4_syno_set_archive_bit, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = ext4_syno_get_inode_archive_version, + .syno_set_archive_version = ext4_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ .get_link = simple_get_link, .setattr = ext4_setattr, .getattr = ext4_getattr, .listxattr = ext4_listxattr, +#ifdef MY_ABC_HERE + .syno_get_crtime = ext4_syno_get_crtime, + .syno_set_crtime = ext4_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +const struct file_operations ext4_symlink_file_operations = { + .unlocked_ioctl = ext4_symlink_ioctl, +}; +#endif /* MY_ABC_HERE */ diff --git a/fs/ext4/syno_acl.c b/fs/ext4/syno_acl.c new file mode 100644 index 000000000000..a218abf62eb9 --- /dev/null +++ b/fs/ext4/syno_acl.c @@ -0,0 +1,363 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#include +#include +#include + +#include "ext4_jbd2.h" +#include "ext4.h" +#include "xattr.h" +#include "syno_acl.h" + +static inline int +ext4_sae_from_disk(struct syno_acl_entry *sae, ext4_syno_acl_entry *esae) +{ + unsigned short tag = le16_to_cpu(esae->e_tag); + + // ID: user/group/everyone + if (SYNO_ACL_XATTR_TAG_ID_GROUP & tag) { + sae->e_tag = SYNO_ACL_GROUP; + sae->e_id = le32_to_cpu(esae->e_id); + } else if (SYNO_ACL_XATTR_TAG_ID_EVERYONE & tag) { + sae->e_tag = SYNO_ACL_EVERYONE; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_USER & tag) { + sae->e_tag = SYNO_ACL_USER; + sae->e_id = le32_to_cpu(esae->e_id); + } else if (SYNO_ACL_XATTR_TAG_ID_OWNER & tag) { + sae->e_tag = SYNO_ACL_OWNER; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER & tag) { + sae->e_tag = SYNO_ACL_AUTHENTICATEDUSER; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_SYSTEM & tag) { + sae->e_tag = SYNO_ACL_SYSTEM; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else { + return -EINVAL; + } + + // Allow/Deny + if (SYNO_ACL_XATTR_TAG_IS_DENY & tag) { + sae->e_allow = SYNO_ACL_DENY; + } else if (SYNO_ACL_XATTR_TAG_IS_ALLOW & tag){ + sae->e_allow = SYNO_ACL_ALLOW; + } else { + return -EINVAL; + } + + // Permission + sae->e_perm = le32_to_cpu(esae->e_perm); + // Inherit + sae->e_inherit = le16_to_cpu(esae->e_inherit); + // Inherit level + sae->e_level = 0; + + return 0; +} + +static inline int +ext4_sae_to_disk(const struct syno_acl_entry *sae, ext4_syno_acl_entry *esae) +{ + unsigned short tag = 0; + + // ID: user/group/everyone + switch(sae->e_tag){ + case SYNO_ACL_GROUP: + tag |= SYNO_ACL_XATTR_TAG_ID_GROUP; + break; + case SYNO_ACL_EVERYONE: + tag |= SYNO_ACL_XATTR_TAG_ID_EVERYONE; + break; + case SYNO_ACL_USER: + tag |= SYNO_ACL_XATTR_TAG_ID_USER; + break; + case SYNO_ACL_OWNER: + tag |= SYNO_ACL_XATTR_TAG_ID_OWNER; + break; + case SYNO_ACL_AUTHENTICATEDUSER: + tag |= SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER; + break; + case SYNO_ACL_SYSTEM: + tag |= SYNO_ACL_XATTR_TAG_ID_SYSTEM; + break; + default: + return -EINVAL; + } + + // Allow/Deny + switch(sae->e_allow){ + case SYNO_ACL_DENY: + tag |= SYNO_ACL_XATTR_TAG_IS_DENY; + break; + case SYNO_ACL_ALLOW: + tag |= SYNO_ACL_XATTR_TAG_IS_ALLOW; + break; + default: + return -EINVAL; + } + + esae->e_tag = cpu_to_le16(tag); + esae->e_inherit = cpu_to_le16(sae->e_inherit); + esae->e_perm = cpu_to_le32(sae->e_perm); + esae->e_id = cpu_to_le32(sae->e_id); + + return 0; +} + +/* + * Convert from filesystem to in-memory representation. + */ +static struct syno_acl * +ext4_syno_acl_from_disk(const void *value, size_t size) +{ + const char *end = (char *)value + size; + size_t i, count; + struct syno_acl *acl; + + if (!value) + return NULL; + if (size < sizeof(ext4_syno_acl_header)) + return ERR_PTR(-EINVAL); + + count = ext4_syno_acl_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + if (((ext4_syno_acl_header *)value)->a_version != cpu_to_le16(EXT4_SYNO_ACL_VERSION)) + return ERR_PTR(-EINVAL); + + acl = syno_acl_alloc(count, GFP_NOFS); + if (!acl) + return ERR_PTR(-ENOMEM); + + value = (char *)value + sizeof(ext4_syno_acl_header); + for (i = 0; i < count; i++) { + ext4_syno_acl_entry *entry = (ext4_syno_acl_entry *)value; + + if ((char *)value + sizeof(ext4_syno_acl_entry) > end) + goto fail; + + if (ext4_sae_from_disk(&(acl->a_entries[i]), entry)) + goto fail; + + value = (char *)value + sizeof(ext4_syno_acl_entry); + } + + if (value != end) + goto fail; + return acl; + +fail: + syno_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +/* + * Convert from in-memory to filesystem representation. + */ +static void * +ext4_syno_acl_to_disk(const struct syno_acl *acl, size_t *size) +{ + char *ent; + size_t i; + ext4_syno_acl_header *ext_acl; + + *size = ext4_syno_acl_size(acl->a_count); + ext_acl = kmalloc(*size, GFP_NOFS); + if (!ext_acl) + return ERR_PTR(-ENOMEM); + + ext_acl->a_version = cpu_to_le16(EXT4_SYNO_ACL_VERSION); + ent = (char *)ext_acl + sizeof(ext4_syno_acl_header); + + for (i = 0; i < acl->a_count; i++, ent += sizeof(ext4_syno_acl_entry)) { + ext4_syno_acl_entry *entry = (ext4_syno_acl_entry *)ent; + + if (0 > ext4_sae_to_disk(&(acl->a_entries[i]), entry)) + goto fail; + } + + return (char *)ext_acl; + +fail: + kfree(ext_acl); + return ERR_PTR(-EINVAL); +} + +/* + * Inode operation syno_acl_get(). + * + * inode->i_mutex: don't care + */ +struct syno_acl * ext4_get_syno_acl(struct inode *inode) +{ + int size; + char *value = NULL; + struct syno_acl *acl; + + acl = get_cached_syno_acl(inode); + if (!is_uncached_syno_acl(acl)) + return acl; + + size = ext4_xattr_get(inode, EXT4_XATTR_INDEX_SYNO_ACL_ACCESS, "", NULL, 0); + if (size > 0) { + value = kmalloc(size, GFP_NOFS); + if (!value) + return ERR_PTR(-ENOMEM); + size = ext4_xattr_get(inode, EXT4_XATTR_INDEX_SYNO_ACL_ACCESS, "", value, size); + } + + if (size > 0) + acl = ext4_syno_acl_from_disk(value, size); + else if (size == -ENODATA || size == -ENOSYS || size == 0) + acl = NULL; + else + acl = ERR_PTR(size); + + kfree(value); + + if (!IS_ERR(acl)) + set_cached_syno_acl(inode, acl); + + return acl; +} + +/* + * Set the syno acl of an inode. + * + * inode->i_mutex: down unless called from ext4_new_inode + */ +static int +__ext4_set_syno_acl(handle_t *handle, struct inode *inode, struct syno_acl *acl) +{ + int ret; + size_t size = 0; + void *value = NULL; + + if (acl) { + ret = syno_acl_valid(acl); + if (ret < 0) + return ret; + + value = ext4_syno_acl_to_disk(acl, &size); + if (IS_ERR(value)) + return PTR_ERR(value); + } + + ret = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SYNO_ACL_ACCESS, "", + value, size, 0); + + kfree(value); + if (!ret) + set_cached_syno_acl(inode, acl); + + return ret; +} + + +/* + * Inode operation syno_acl_set(). + */ +int ext4_set_syno_acl(struct inode *inode, struct syno_acl *acl) +{ + handle_t *handle; + int error, retries = 0; + + if (!inode || !acl) + return -EINVAL; + + error = dquot_initialize(inode); + if (error) + return error; +retry: + handle = ext4_journal_start(inode, EXT4_HT_SYNO, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + error = __ext4_set_syno_acl(handle, inode, acl); + + ext4_journal_stop(handle); + if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + + return error; +} + +static bool +ext4_xattr_syno_acl_list(struct dentry *dentry) +{ + return IS_EXT4_SYNOACL(d_inode(dentry)); +} + +static int +ext4_xattr_syno_acl_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *value, size_t size) +{ + int ret; + struct syno_acl *acl; + + acl = ext4_get_syno_acl(inode); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (NULL == acl) + return -ENODATA; + + ret = syno_acl_to_xattr(acl, value, size); + syno_acl_release(acl); + + return ret; +} + +static int +ext4_xattr_syno_acl_set(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, int flags) +{ + handle_t *handle; + struct syno_acl *acl = NULL; + int ret, retries = 0; + + if (value) { + acl = syno_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + ret = syno_acl_valid(acl); + if (ret) + goto release_and_out; + } + } + + ret = dquot_initialize(inode); + if (ret) + return ret; + +retry: + handle = ext4_journal_start(inode, EXT4_HT_SYNO, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto release_and_out; + } + + ret = __ext4_set_syno_acl(handle, inode, acl); + ext4_journal_stop(handle); + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + +release_and_out: + syno_acl_release(acl); + return ret; +} + +const struct xattr_handler ext4_xattr_synoacl_access_handler = { + .name = SYNO_ACL_XATTR_ACCESS, + .list = ext4_xattr_syno_acl_list, + .get = ext4_xattr_syno_acl_get, + .set = ext4_xattr_syno_acl_set, +}; diff --git a/fs/ext4/syno_acl.h b/fs/ext4/syno_acl.h new file mode 100644 index 000000000000..36289a8d5243 --- /dev/null +++ b/fs/ext4/syno_acl.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ + +#ifndef _EXT4_SYNO_ACL_H +#define _EXT4_SYNO_ACL_H + +#include + +#define EXT4_SYNO_ACL_VERSION SYNO_ACL_XATTR_VERSION + +#define IS_EXT4_INODE_SYNOACL(inode) ((inode)->i_archive_bit & S2_SYNO_ACL_SUPPORT) +#define IS_EXT4_SYNOACL(inode) (IS_EXT4_INODE_SYNOACL(inode) && IS_FS_SYNOACL(inode)) + +typedef struct { + __le16 e_tag; + __le16 e_unused1; + __le32 e_perm; + __le16 e_inherit; + __le16 e_unused2; + __le32 e_id; +} __attribute__ ((__packed__)) ext4_syno_acl_entry; + +typedef struct { + __le16 a_version; +} __attribute__ ((__packed__)) ext4_syno_acl_header; + +static inline size_t ext4_syno_acl_size(int count) +{ + return sizeof(ext4_syno_acl_header) + count * sizeof(ext4_syno_acl_entry); +} + +static inline size_t ext4_syno_acl_count(size_t size) +{ + size -= sizeof(ext4_syno_acl_header); + if (size % sizeof(ext4_syno_acl_entry)) + return -1; + return size / sizeof(ext4_syno_acl_entry); +} + +int ext4_set_syno_acl(struct inode *inode, struct syno_acl *acl); +struct syno_acl *ext4_get_syno_acl(struct inode *inode); + +#endif /* _EXT4_SYNO_ACL_H */ diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c index f24bef3be48a..50f970dd2870 100644 --- a/fs/ext4/sysfs.c +++ b/fs/ext4/sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/sysfs.c @@ -37,6 +40,21 @@ typedef enum { attr_pointer_string, attr_pointer_atomic, attr_journal_task, +#ifdef MY_ABC_HERE + attr_lazyinit_info, + attr_lazyinit_speed, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + attr_syno_fs_error_new_event_flag, + attr_syno_fs_error_mounted, + attr_syno_fs_error_count, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + attr_incompat_supp, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + attr_compat_ro_supp, +#endif /* MY_ABC_HERE */ } attr_id_t; typedef enum { @@ -117,6 +135,44 @@ static ssize_t reserved_clusters_store(struct ext4_sb_info *sbi, return count; } +#ifdef MY_ABC_HERE +static ssize_t syno_fs_error_new_event_flag_store(struct ext4_sb_info *sbi, + const char *buf, size_t count) +{ + long t; + int ret; + + ret = kstrtol(skip_spaces(buf), 0, &t); + if (ret) + return ret; + + if (!(1 == t || 0 == t)) + return -EINVAL; + sbi->s_new_error_fs_event_flag = (int) t; + return count; +} + +static ssize_t syno_fs_error_mounted_store(struct ext4_sb_info *sbi, + const char *buf, size_t count) +{ + char *str; + + if (0 == count) + return -EINVAL; + + str = kmemdup_nul(buf, count, GFP_KERNEL); + if (!str) + return -ENOMEM; + + spin_lock(&sbi->s_mount_path_lock); + if (sbi->s_mount_path) + kfree(sbi->s_mount_path); + sbi->s_mount_path = str; + spin_unlock(&sbi->s_mount_path_lock); + return count; +} +#endif /* MY_ABC_HERE */ + static ssize_t trigger_test_error(struct ext4_sb_info *sbi, const char *buf, size_t count) { @@ -250,6 +306,21 @@ EXT4_ATTR(last_error_time, 0444, last_error_time); EXT4_ATTR(journal_task, 0444, journal_task); EXT4_RW_ATTR_SBI_UI(mb_prefetch, s_mb_prefetch); EXT4_RW_ATTR_SBI_UI(mb_prefetch_limit, s_mb_prefetch_limit); +#ifdef MY_ABC_HERE +EXT4_ATTR_FUNC(lazyinit_info, 0444); +EXT4_ATTR_FUNC(lazyinit_speed, 0444); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +EXT4_ATTR_FUNC(syno_fs_error_new_event_flag, 0644); +EXT4_ATTR_FUNC(syno_fs_error_mounted, 0644); +EXT4_ATTR_FUNC(syno_fs_error_count, 0444); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +EXT4_ATTR_FUNC(incompat_supp, 0444); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +EXT4_ATTR_FUNC(compat_ro_supp, 0444); +#endif /* MY_ABC_HERE */ static unsigned int old_bump_val = 128; EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val); @@ -299,6 +370,15 @@ static struct attribute *ext4_attrs[] = { #endif ATTR_LIST(mb_prefetch), ATTR_LIST(mb_prefetch_limit), +#ifdef MY_ABC_HERE + ATTR_LIST(lazyinit_info), + ATTR_LIST(lazyinit_speed), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ATTR_LIST(syno_fs_error_new_event_flag), + ATTR_LIST(syno_fs_error_mounted), + ATTR_LIST(syno_fs_error_count), +#endif /* MY_ABC_HERE */ NULL, }; ATTRIBUTE_GROUPS(ext4); @@ -336,6 +416,12 @@ static struct attribute *ext4_feat_attrs[] = { #endif ATTR_LIST(metadata_csum_seed), ATTR_LIST(fast_commit), +#ifdef MY_ABC_HERE + ATTR_LIST(incompat_supp), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ATTR_LIST(compat_ro_supp), +#endif /* MY_ABC_HERE */ NULL, }; ATTRIBUTE_GROUPS(ext4_feat); @@ -369,6 +455,9 @@ static ssize_t ext4_attr_show(struct kobject *kobj, s_kobj); struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); void *ptr = calc_ptr(a, sbi); +#ifdef MY_ABC_HERE + int ret = 0; +#endif /* MY_ABC_HERE */ switch (a->attr_id) { case attr_delayed_allocation_blocks: @@ -434,6 +523,35 @@ static ssize_t ext4_attr_show(struct kobject *kobj, return print_tstamp(buf, sbi->s_es, s_last_error_time); case attr_journal_task: return journal_task_show(sbi, buf); +#ifdef MY_ABC_HERE + case attr_lazyinit_info: + return snprintf(buf, PAGE_SIZE, "%u %u\n", + sbi->s_li_request ? sbi->s_li_request->lr_next_group : sbi->s_groups_count, + sbi->s_groups_count); + case attr_lazyinit_speed: + return snprintf(buf, PAGE_SIZE, "%lu\n", + sbi->s_li_request ? sbi->s_li_request->lr_timeout : 0); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case attr_syno_fs_error_new_event_flag: + return snprintf(buf, PAGE_SIZE, "%d\n", sbi->s_new_error_fs_event_flag); + case attr_syno_fs_error_mounted: + spin_lock(&sbi->s_mount_path_lock); + ret = snprintf(buf, PAGE_SIZE, "%s\n", + sbi->s_mount_path ? sbi->s_mount_path : "NULL"); + spin_unlock(&sbi->s_mount_path_lock); + return ret; + case attr_syno_fs_error_count: + return snprintf(buf, PAGE_SIZE, "%d\n", sbi->s_es->s_error_count); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case attr_incompat_supp: + return snprintf(buf, PAGE_SIZE, "%u\n", EXT4_FEATURE_INCOMPAT_SUPP); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + case attr_compat_ro_supp: + return snprintf(buf, PAGE_SIZE, "%u\n", EXT4_FEATURE_RO_COMPAT_SUPP); +#endif /* MY_ABC_HERE */ } return 0; @@ -476,6 +594,12 @@ static ssize_t ext4_attr_store(struct kobject *kobj, return inode_readahead_blks_store(sbi, buf, len); case attr_trigger_test_error: return trigger_test_error(sbi, buf, len); +#ifdef MY_ABC_HERE + case attr_syno_fs_error_new_event_flag: + return syno_fs_error_new_event_flag_store(sbi, buf, len); + case attr_syno_fs_error_mounted: + return syno_fs_error_mounted_store(sbi, buf, len); +#endif /* MY_ABC_HERE */ } return 0; } diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 5462f26907c1..4305d4553e52 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/xattr.c @@ -89,10 +92,16 @@ static const struct xattr_handler * const ext4_xattr_handler_map[] = { [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, #endif +#ifdef MY_ABC_HERE + [EXT4_XATTR_INDEX_SYNO_ACL_ACCESS] = &ext4_xattr_synoacl_access_handler, +#endif /* MY_ABC_HERE */ [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, #ifdef CONFIG_EXT4_FS_SECURITY [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, #endif +#ifdef MY_ABC_HERE + [EXT4_XATTR_INDEX_SYNO] = &ext4_xattr_syno_handler, +#endif /* MY_ABC_HERE */ [EXT4_XATTR_INDEX_HURD] = &ext4_xattr_hurd_handler, }; @@ -103,9 +112,15 @@ const struct xattr_handler *ext4_xattr_handlers[] = { &posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, #endif +#ifdef MY_ABC_HERE + &ext4_xattr_synoacl_access_handler, +#endif /* MY_ABC_HERE */ #ifdef CONFIG_EXT4_FS_SECURITY &ext4_xattr_security_handler, #endif +#ifdef MY_ABC_HERE + &ext4_xattr_syno_handler, +#endif /* MY_ABC_HERE */ &ext4_xattr_hurd_handler, NULL }; @@ -3139,3 +3154,75 @@ void ext4_xattr_destroy_cache(struct mb_cache *cache) mb_cache_destroy(cache); } +#ifdef MY_ABC_HERE + +static const char * const ext4_excluded_syno_xattrs[] = { +#ifdef MY_ABC_HERE + XATTR_SYNO_ARCHIVE_BIT_SUFFIX, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + XATTR_SYNO_ARCHIVE_VERSION_SUFFIX, + XATTR_SYNO_ARCHIVE_VERSION_VOLUME_SUFFIX, +#endif /* MY_ABC_HERE */ +}; + +#define ext4_excluded_syno_xattrs_num ARRAY_SIZE(ext4_excluded_syno_xattrs) + +static bool +ext4_xattr_syno_list(struct dentry *dentry) +{ + /* + * Conceal the syno xattr for ext4 while lsxattr. + * Please refer to DSM #69101 + */ + return false; +} + +static int +ext4_xattr_syno_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *buffer, size_t size) +{ + int i; + + /* + * Disallow the access of these attributes by xattr syscalls. + * The proper ways to access them are using the per-attribute + * related syscalls or fcntl. (i.g. syno_stat/syno_archive_overwrite) + */ + for (i = 0; i < ext4_excluded_syno_xattrs_num; ++i) + if (unlikely(!strcmp(name, ext4_excluded_syno_xattrs[i]))) + return -EOPNOTSUPP; + + return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SYNO, + name, buffer, size); +} + +static int +ext4_xattr_syno_set(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, const void *buffer, + size_t size, int flags) +{ + int i; + + /* + * Disallow the access of these attributes by xattr syscalls. + * The proper ways to access them are using the per-attribute + * related syscalls or fcntl. (i.g. syno_stat/syno_archive_overwrite) + */ + for (i = 0; i < ext4_excluded_syno_xattrs_num; ++i) + if (unlikely(!strcmp(name, ext4_excluded_syno_xattrs[i]))) + return -EOPNOTSUPP; + + return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SYNO, + name, buffer, size, flags); +} + +const struct xattr_handler ext4_xattr_syno_handler = { + .prefix = XATTR_SYNO_PREFIX, + .list = ext4_xattr_syno_list, + .get = ext4_xattr_syno_get, + .set = ext4_xattr_syno_set, +}; +#endif /* MY_ABC_HERE */ diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 730b91fa0dd7..f241a33ab057 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* File: fs/ext4/xattr.h @@ -24,8 +27,17 @@ #define EXT4_XATTR_INDEX_SECURITY 6 #define EXT4_XATTR_INDEX_SYSTEM 7 #define EXT4_XATTR_INDEX_RICHACL 8 +#ifdef MY_ABC_HERE +#define EXT4_XATTR_INDEX_SYNO EXT4_XATTR_INDEX_RICHACL // 8 +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define EXT4_XATTR_INDEX_SYNO_ACL_ACCESS EXT4_XATTR_INDEX_SYSTEM // 7 +#endif /* MY_ABC_HERE */ #define EXT4_XATTR_INDEX_ENCRYPTION 9 #define EXT4_XATTR_INDEX_HURD 10 /* Reserved for Hurd */ +#ifdef MY_ABC_HERE +#define EXT3_XATTR_INDEX_SYNO_BAD 7 +#endif /* MY_ABC_HERE */ struct ext4_xattr_header { __le32 h_magic; /* magic number for identification */ @@ -121,6 +133,12 @@ struct ext4_xattr_inode_array { struct inode *inodes[]; }; +#ifdef MY_ABC_HERE +extern const struct xattr_handler ext4_xattr_synoacl_access_handler; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern const struct xattr_handler ext4_xattr_syno_handler; +#endif /* MY_ABC_HERE */ extern const struct xattr_handler ext4_xattr_user_handler; extern const struct xattr_handler ext4_xattr_trusted_handler; extern const struct xattr_handler ext4_xattr_security_handler; diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 922a0c6ba46c..2c2d3f9b8569 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _FAT_H #define _FAT_H @@ -127,6 +130,9 @@ struct msdos_inode_info { struct hlist_node i_dir_hash; /* hash by i_logstart */ struct rw_semaphore truncate_lock; /* protect bmap against truncate */ struct inode vfs_inode; +#ifdef MY_ABC_HERE + struct timespec64 i_btime; /* File birth (creation) time */ +#endif /* MY_ABC_HERE */ }; struct fat_slot_info { @@ -401,6 +407,12 @@ extern int fat_setattr(struct dentry *dentry, struct iattr *attr); extern void fat_truncate_blocks(struct inode *inode, loff_t offset); extern int fat_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags); +#ifdef MY_ABC_HERE +extern int fat_syno_getattr(struct dentry *dentry, struct kstat *kst, + unsigned int syno_flags); +extern int fat_syno_get_crtime(struct inode *inode, struct timespec64 *crtime); +extern int fat_syno_set_crtime(struct inode *inode, struct timespec64 *crtime); +#endif /* MY_ABC_HERE */ extern int fat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); diff --git a/fs/fat/file.c b/fs/fat/file.c index f9ee27cf4d7c..613641f75697 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/fat/file.c @@ -177,7 +180,10 @@ static int fat_file_release(struct inode *inode, struct file *filp) if ((filp->f_mode & FMODE_WRITE) && MSDOS_SB(inode->i_sb)->options.flush) { fat_flush_inodes(inode->i_sb, inode, NULL); +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ congestion_wait(BLK_RW_ASYNC, HZ/10); +#endif /* MY_ABC_HERE */ } return 0; } @@ -409,6 +415,37 @@ int fat_getattr(const struct path *path, struct kstat *stat, } EXPORT_SYMBOL_GPL(fat_getattr); +#ifdef MY_ABC_HERE +int fat_syno_getattr(struct dentry *dentry, struct kstat *kst, + unsigned int syno_flags) +{ + struct inode *inode = dentry->d_inode; + + if (syno_flags & SYNOST_CREATE_TIME) + kst->syno_create_time = MSDOS_I(inode)->i_btime; + + return 0; +} +EXPORT_SYMBOL_GPL(fat_syno_getattr); + +int fat_syno_get_crtime(struct inode *inode, struct timespec64 *crtime) +{ + *crtime = MSDOS_I(inode)->i_btime; + + return 0; +} +EXPORT_SYMBOL_GPL(fat_syno_get_crtime); + +int fat_syno_set_crtime(struct inode *inode, struct timespec64 *crtime) +{ + MSDOS_I(inode)->i_btime = *crtime; + mark_inode_dirty(inode); + + return 0; +} +EXPORT_SYMBOL_GPL(fat_syno_set_crtime); +#endif /* MY_ABC_HERE */ + static int fat_sanitize_mode(const struct msdos_sb_info *sbi, struct inode *inode, umode_t *mode_ptr) { @@ -561,4 +598,9 @@ const struct inode_operations fat_file_inode_operations = { .setattr = fat_setattr, .getattr = fat_getattr, .update_time = fat_update_time, +#ifdef MY_ABC_HERE + .syno_getattr = fat_syno_getattr, + .syno_get_crtime= fat_syno_get_crtime, + .syno_set_crtime= fat_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index bab9b202b496..ccb63dba62e0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/fat/inode.c @@ -566,8 +569,13 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0); if (sbi->options.isvfat) { +#ifdef MY_ABC_HERE + fat_time_fat2unix(sbi, &MSDOS_I(inode)->i_btime, de->ctime, + de->cdate, de->ctime_cs); +#else fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime, de->cdate, de->ctime_cs); +#endif /* MY_ABC_HERE */ fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0); } else fat_truncate_time(inode, &inode->i_mtime, S_ATIME|S_CTIME); @@ -755,6 +763,11 @@ static struct inode *fat_alloc_inode(struct super_block *sb) ei->i_logstart = 0; ei->i_attrs = 0; ei->i_pos = 0; +#ifdef MY_ABC_HERE + /* update to curret time later in fat_fill_inode() */ + ei->i_btime.tv_sec = 0; + ei->i_btime.tv_nsec = 0; +#endif /* MY_ABC_HERE */ return &ei->vfs_inode; } @@ -886,8 +899,13 @@ static int __fat_write_inode(struct inode *inode, int wait) &raw_entry->date, NULL); if (sbi->options.isvfat) { __le16 atime; +#ifdef MY_ABC_HERE + fat_time_unix2fat(sbi, &MSDOS_I(inode)->i_btime, &raw_entry->ctime, + &raw_entry->cdate, &raw_entry->ctime_cs); +#else fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime, &raw_entry->cdate, &raw_entry->ctime_cs); +#endif /* MY_ABC_HERE */ fat_time_unix2fat(sbi, &inode->i_atime, &atime, &raw_entry->adate, NULL); } @@ -1036,7 +1054,11 @@ enum { Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, +#ifdef MY_ABC_HERE + Opt_obsolete, Opt_flush, Opt_noflush, Opt_tz_utc, Opt_rodir, Opt_err_cont, +#else Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, +#endif /* MY_ABC_HERE */ Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset, Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy, }; @@ -1062,6 +1084,9 @@ static const match_table_t fat_tokens = { {Opt_debug, "debug"}, {Opt_immutable, "sys_immutable"}, {Opt_flush, "flush"}, +#ifdef MY_ABC_HERE + {Opt_noflush, "noflush"}, +#endif /* MY_ABC_HERE */ {Opt_tz_utc, "tz=UTC"}, {Opt_time_offset, "time_offset=%d"}, {Opt_err_cont, "errors=continue"}, @@ -1154,6 +1179,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, opts->tz_set = 0; opts->nfs = 0; opts->errors = FAT_ERRORS_RO; +#ifdef MY_ABC_HERE + opts->flush = 1; +#endif /* MY_ABC_HERE */ *debug = 0; opts->utf8 = IS_ENABLED(CONFIG_FAT_DEFAULT_UTF8) && is_vfat; @@ -1249,6 +1277,11 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, case Opt_flush: opts->flush = 1; break; +#ifdef MY_ABC_HERE + case Opt_noflush: + opts->flush = 0; + break; +#endif /* MY_ABC_HERE */ case Opt_time_offset: if (match_int(&args[0], &option)) return -EINVAL; diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 9d062886fbc1..35bf640b794c 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/msdos/namei.c @@ -639,6 +642,11 @@ static const struct inode_operations msdos_dir_inode_operations = { .setattr = fat_setattr, .getattr = fat_getattr, .update_time = fat_update_time, +#ifdef MY_ABC_HERE + .syno_getattr = fat_syno_getattr, + .syno_get_crtime= fat_syno_get_crtime, + .syno_set_crtime= fat_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; static void setup(struct super_block *sb) diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 0cdd0fb9f742..57b8c03b62c1 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/vfat/namei.c @@ -1034,6 +1037,11 @@ static const struct inode_operations vfat_dir_inode_operations = { .setattr = fat_setattr, .getattr = fat_getattr, .update_time = fat_update_time, +#ifdef MY_ABC_HERE + .syno_getattr = fat_syno_getattr, + .syno_get_crtime= fat_syno_get_crtime, + .syno_set_crtime= fat_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; static void setup(struct super_block *sb) diff --git a/fs/fcntl.c b/fs/fcntl.c index 05b36b28f2e8..63498786308f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/fcntl.c @@ -30,9 +33,252 @@ #include #include +#ifdef MY_ABC_HERE +#include +#include + +#ifdef MY_ABC_HERE +#include "syno_acl.h" +#define ACL_MASK_NONE 0 +#endif /* MY_ABC_HERE */ + +struct syno_archive_map { + unsigned int syno_archive; //syno archive + bool is_set_cmd; +}; + +static struct syno_archive_map syno_archive_table[] = { + {S2_IARCHIVE, false}, /* F_CLEAR_ARCHIVE */ + {S2_SMB_ARCHIVE, true}, /* F_SETSMB_ARCHIVE */ + {S2_SMB_HIDDEN, true}, /* F_SETSMB_HIDDEN */ + {S2_SMB_SYSTEM, true}, /* F_SETSMB_SYSTEM */ + {S2_SMB_ARCHIVE, false}, /* F_CLRSMB_ARCHIVE */ + {S2_SMB_HIDDEN, false}, /* F_CLRSMB_HIDDEN */ + {S2_SMB_SYSTEM, false}, /* F_CLRSMB_SYSTEM */ + {S3_IARCHIVE, false}, /* F_CLEAR_S3_ARCHIVE */ +#ifdef MY_ABC_HERE + {S2_SMB_READONLY, false}, /* F_CLRSMB_READONLY */ + {S2_SMB_READONLY, true}, /* F_SETSMB_READONLY */ + {S2_SYNO_ACL_INHERIT, false}, /* F_CLRACL_INHERIT */ + {S2_SYNO_ACL_INHERIT, true}, /* F_SETSMB_INHERIT */ + {S2_SYNO_ACL_EXIST, false}, /* F_CLRACL_HAS_ACL */ + {S2_SYNO_ACL_EXIST, true}, /* F_SETACL_HAS_ACL */ + {S2_SYNO_ACL_SUPPORT, false}, /* F_CLRACL_SUPPORT */ + {S2_SYNO_ACL_SUPPORT, true}, /* F_SETACL_SUPPORT */ + {S2_SYNO_ACL_IS_OWNER_GROUP, false}, /* F_CLRACL_OWNER_IS_GROUP */ + {S2_SYNO_ACL_IS_OWNER_GROUP, true}, /* F_SETACL_OWNER_IS_GROUP */ +#endif /* MY_ABC_HERE */ + {S2_SMB_SPARSE, true}, /* F_SETSMB_SPARSE */ + {S2_SMB_SPARSE, false}, /* F_CLRSMB_SPARSE */ +}; + +#ifdef MY_ABC_HERE +const int syno_archive_acl_tag[] = { + PROTECT_BY_ACL, /* F_CLEAR_ARCHIVE */ + PROTECT_BY_ACL, /* F_SETSMB_ARCHIVE */ + PROTECT_BY_ACL, /* F_SETSMB_HIDDEN */ + PROTECT_BY_ACL, /* F_SETSMB_SYSTEM */ + PROTECT_BY_ACL, /* F_CLRSMB_ARCHIVE */ + PROTECT_BY_ACL, /* F_CLRSMB_HIDDEN */ + PROTECT_BY_ACL, /* F_CLRSMB_SYSTEM */ + PROTECT_BY_ACL, /* F_CLEAR_S3_ARCHIVE */ + PROTECT_BY_ACL | NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_CLRSMB_READONLY */ + PROTECT_BY_ACL | NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_SETSMB_READONLY */ + PROTECT_BY_ACL | NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_CLRACL_INHERIT */ + PROTECT_BY_ACL | NEED_FS_ACL_SUPPORT, /* F_SETACL_INHERIT */ + NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_CLRACL_HAS_ACL */ + NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_SETACL_HAS_ACL */ + NEED_FS_ACL_SUPPORT, /* F_CLRACL_SUPPORT */ + NEED_FS_ACL_SUPPORT, /* F_SETACL_SUPPORT */ + PROTECT_BY_ACL | NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_CLRACL_OWNER_IS_GROUP */ + PROTECT_BY_ACL | NEED_INODE_ACL_SUPPORT | NEED_FS_ACL_SUPPORT, /* F_SETACL_OWNER_IS_GROUP */ + PROTECT_BY_ACL, /* F_SETSMB_SPARSE */ + PROTECT_BY_ACL, /* F_CLRSMB_SPARSE */ +}; + +const int syno_archive_acl_mask[] = { + MAY_WRITE_ATTR, /* F_CLEAR_ARCHIVE */ + MAY_WRITE_ATTR, /* F_SETSMB_ARCHIVE */ + MAY_WRITE_ATTR, /* F_SETSMB_HIDDEN */ + MAY_WRITE_ATTR, /* F_SETSMB_SYSTEM */ + MAY_WRITE_ATTR, /* F_CLRSMB_ARCHIVE */ + MAY_WRITE_ATTR, /* F_CLRSMB_HIDDEN */ + MAY_WRITE_ATTR, /* F_CLRSMB_SYSTEM */ + MAY_WRITE_ATTR, /* F_CLEAR_S3_ARCHIVE */ + MAY_WRITE_ATTR, /* F_CLRSMB_READONLY */ + MAY_WRITE_ATTR, /* F_SETSMB_READONLY */ + MAY_WRITE_PERMISSION, /* F_CLRACL_INHERIT */ + MAY_WRITE_PERMISSION, /* F_SETACL_INHERIT */ + ACL_MASK_NONE, /* F_CLRACL_HAS_ACL */ + ACL_MASK_NONE, /* F_SETACL_HAS_ACL */ + ACL_MASK_NONE, /* F_CLRACL_SUPPORT */ + ACL_MASK_NONE, /* F_SETACL_SUPPORT */ + MAY_GET_OWNER_SHIP, /* F_CLRACL_OWNER_IS_GROUP */ + MAY_GET_OWNER_SHIP, /* F_SETACL_OWNER_IS_GROUP */ + MAY_WRITE_ATTR, /* F_SETSMB_SPARSE */ + MAY_WRITE_ATTR, /* F_CLRSMB_SPARSE */ +}; + +struct syno_archive_permission_mapping { + unsigned int syno_archive; + int permission; +}; + +static struct syno_archive_permission_mapping syno_archive_permission_table[] = { + /* General archive */ + {S2_IARCHIVE, MAY_WRITE_ATTR}, + {S2_SMB_ARCHIVE, MAY_WRITE_ATTR}, + {S2_SMB_HIDDEN, MAY_WRITE_ATTR}, + {S2_SMB_SYSTEM, MAY_WRITE_ATTR}, + {S2_SMB_SPARSE, MAY_WRITE_ATTR}, + + /* ACL archive */ + {S2_SMB_READONLY, MAY_WRITE_ATTR}, + {S2_SYNO_ACL_IS_OWNER_GROUP, MAY_GET_OWNER_SHIP}, + {S2_SYNO_ACL_INHERIT, MAY_WRITE_PERMISSION}, + {S2_SYNO_ACL_EXIST, MAY_WRITE_PERMISSION}, + {S2_SYNO_ACL_SUPPORT, MAY_WRITE_PERMISSION}, + {0, -1} +}; +#endif /* MY_ABC_HERE */ + +long syno_archive_bit_set(struct dentry *dentry, unsigned int cmd) +{ + int i = cmd - SYNO_FCNTL_BASE; + int num_mappings = sizeof(syno_archive_table) / + sizeof(syno_archive_table[0]); + struct inode *inode = dentry->d_inode; + long err; + u32 archive_bit; + + if (i < 0 || i >= num_mappings) { + err = -EINVAL; + goto end; + } + +#ifdef MY_ABC_HERE + if (!IS_SYNOACL(dentry) && !inode_owner_or_capable(inode)) { +#else + if (!inode_owner_or_capable(inode)) { +#endif /* MY_ABC_HERE */ + err = -EPERM; + goto end; + } + + mutex_lock(&inode->i_archive_bit_mutex); + err = syno_op_get_archive_bit(dentry, &archive_bit); + if (err) + goto unlock; + + if (syno_archive_table[i].is_set_cmd == + !!(archive_bit & syno_archive_table[i].syno_archive)) { + err = 0; + goto unlock; + } + +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + err = synoacl_op_archive_bit_change_ok(dentry, cmd, + syno_archive_acl_tag[i], + syno_archive_acl_mask[i]); + if (err) + goto unlock; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_archive_table[i].is_set_cmd) { + archive_bit |= syno_archive_table[i].syno_archive; + if (S2_SYNO_ACL_INHERIT == syno_archive_table[i].syno_archive) { + archive_bit |= S2_SYNO_ACL_SUPPORT; + } + } +#else + if (syno_archive_table[i].is_set_cmd) + archive_bit |= syno_archive_table[i].syno_archive; +#endif /* MY_ABC_HERE */ + + else + archive_bit &= ~syno_archive_table[i].syno_archive; + + err = syno_op_set_archive_bit_nolock(dentry, archive_bit); +unlock: + mutex_unlock(&inode->i_archive_bit_mutex); +end: + return err; +} + +long syno_archive_bit_overwrite(struct dentry *dentry, unsigned int flags) +{ + struct inode *inode = dentry->d_inode; + int err = 0; + u32 archive_bit; +#ifdef MY_ABC_HERE + int permission_check = 0; + int i = 0; +#endif /* MY_ABC_HERE */ + + if ((~ALL_ARCHIVE_BIT) & flags) { + err = -EINVAL; + goto end; + } + + mutex_lock(&inode->i_archive_bit_mutex); + err = syno_op_get_archive_bit(dentry, &archive_bit); + if (err) + goto unlock; + +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + for (i = 0; -1 != syno_archive_permission_table[i].permission; i++) { + if ((archive_bit & syno_archive_permission_table[i].syno_archive) == (flags & syno_archive_permission_table[i].syno_archive)) + continue; + permission_check |= syno_archive_permission_table[i].permission; + } + err = synoacl_op_permission(dentry, permission_check); + if (err) + goto unlock; + } else if (!inode_owner_or_capable(inode)) { + err = -EPERM; + goto unlock; + } + + if (ALL_SYNO_ACL_ARCHIVE & flags) { + if (!IS_FS_SYNOACL(inode)) { + err = -EOPNOTSUPP; + goto unlock; + } + // S2_SYNO_ACL_SUPPORT should be set if you want to set ACL archive bit. + if (!(S2_SYNO_ACL_SUPPORT & flags)) { + err = -EINVAL; + goto unlock; + } + } +#else /* MY_ABC_HERE */ + if (!inode_owner_or_capable(inode)) { + err = -EPERM; + goto unlock; + } +#endif /* MY_ABC_HERE */ + + if (flags == archive_bit) + goto unlock; + + err = syno_op_set_archive_bit_nolock(dentry, flags); +unlock: + mutex_unlock(&inode->i_archive_bit_mutex); +end: + return err; +} +#endif /* MY_ABC_HERE */ + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) +#ifdef MY_ABC_HERE +int setfl(int fd, struct file *filp, unsigned long arg) +#else static int setfl(int fd, struct file * filp, unsigned long arg) +#endif /* MY_ABC_HERE */ { struct inode * inode = file_inode(filp); int error = 0; @@ -63,6 +309,12 @@ static int setfl(int fd, struct file * filp, unsigned long arg) if (filp->f_op->check_flags) error = filp->f_op->check_flags(arg); + +#ifdef MY_ABC_HERE + if (!error && filp->f_op->setfl) + error = filp->f_op->setfl(filp, arg); +#endif /* MY_ABC_HERE */ + if (error) return error; @@ -83,6 +335,9 @@ static int setfl(int fd, struct file * filp, unsigned long arg) out: return error; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(setfl); +#endif /* MY_ABC_HERE */ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, int force) @@ -426,6 +681,15 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, case F_SET_FILE_RW_HINT: err = fcntl_rw_hint(filp, cmd, arg); break; +#ifdef MY_ABC_HERE + case SYNO_FCNTL_BASE ... SYNO_FCNTL_LAST: + err = mnt_want_write_file(filp); + if (err) + break; + err = syno_archive_bit_set(filp->f_path.dentry, cmd); + mnt_drop_write_file(filp); + break; +#endif /* MY_ABC_HERE */ default: break; } diff --git a/fs/file_table.c b/fs/file_table.c index 709ada3151da..c840bbc5a731 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/file_table.c @@ -32,6 +35,12 @@ #include "internal.h" +#ifdef MY_ABC_HERE +#include +#include "mount.h" +static spinlock_t files_list_lock; +#endif /*MY_ABC_HERE*/ + /* sysctl tunables... */ struct files_stat_struct files_stat = { .max_files = NR_FILE @@ -109,6 +118,9 @@ static struct file *__alloc_file(int flags, const struct cred *cred) return ERR_PTR(error); } +#ifdef MY_ABC_HERE + INIT_LIST_HEAD(&f->open_list); +#endif /* MY_ABC_HERE */ atomic_long_set(&f->f_count, 1); rwlock_init(&f->f_owner.lock); spin_lock_init(&f->f_lock); @@ -162,6 +174,9 @@ struct file *alloc_empty_file(int flags, const struct cred *cred) } return ERR_PTR(-ENFILE); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(alloc_empty_file); +#endif /* MY_ABC_HERE */ /* * Variant of alloc_empty_file() that doesn't check and modify nr_files. @@ -337,6 +352,10 @@ void fput_many(struct file *file, unsigned int refs) if (atomic_long_sub_and_test(refs, &file->f_count)) { struct task_struct *task = current; +#ifdef MY_ABC_HERE + file_sb_list_del(file); +#endif /* MY_ABC_HERE */ + if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { init_task_work(&file->f_u.fu_rcuhead, ____fput); if (!task_work_add(task, &file->f_u.fu_rcuhead, TWA_RESUME)) @@ -370,17 +389,26 @@ void __fput_sync(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; + +#ifdef MY_ABC_HERE + file_sb_list_del(file); +#endif /* MY_ABC_HERE */ + BUG_ON(!(task->flags & PF_KTHREAD)); __fput(file); } } EXPORT_SYMBOL(fput); +EXPORT_SYMBOL(__fput_sync); void __init files_init(void) { filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT, NULL); +#ifdef MY_ABC_HERE + spin_lock_init(&files_list_lock); +#endif /* MY_ABC_HERE */ percpu_counter_init(&nr_files, 0, GFP_KERNEL); } @@ -399,3 +427,118 @@ void __init files_maxfiles_init(void) files_stat.max_files = max_t(unsigned long, n, NR_FILE); } +#ifdef MY_ABC_HERE +static inline int file_list_cpu(struct file *file) +{ +#ifdef CONFIG_SMP + return file->f_sb_list_cpu; +#else /* CONFIG_SMP */ + return smp_processor_id(); +#endif /* CONFIG_SMP */ +} + +/* helper for file_sb_list_add to reduce ifdefs */ +static inline void __file_sb_list_add(struct file *file, struct super_block *sb) +{ + struct list_head *list; +#ifdef CONFIG_SMP + int cpu = smp_processor_id(); + + file->f_sb_list_cpu = cpu; + list = per_cpu_ptr(sb->s_files, cpu); +#else /* CONFIG_SMP */ + list = &sb->s_files; +#endif /* CONFIG_SMP */ + list_add(&file->open_list, list); + memcpy(file->comm, current->comm, TASK_COMM_LEN); + file->pid = current->pid; +} + +/** + * file_sb_list_add - add a file to the sb's file list + * @file: file to add + * + * Use this function to associate a file with the superblock of the inode it + * refers to. + */ +void file_sb_list_add(struct file *file) +{ + unsigned long flags; + struct super_block *sb = file->f_inode->i_sb; + + spin_lock_irqsave(&files_list_lock, flags); + __file_sb_list_add(file, sb); + spin_unlock_irqrestore(&files_list_lock, flags); +} + +/** + * file_sb_list_del - remove a file from the sb's file list + * @file: file to remove + * + * Use this function to remove a file from its superblock. + */ +void file_sb_list_del(struct file *file) +{ + unsigned long flags; + + if (!list_empty(&file->open_list)) { + spin_lock_irqsave(&files_list_lock, flags); + list_del_init(&file->open_list); + spin_unlock_irqrestore(&files_list_lock, flags); + } +} + +#ifdef CONFIG_SMP + +/* + * These macros iterate all files on all CPUs for a given superblock. + * files_list_lock must be held globally. + */ +#define do_file_list_for_each_entry(__sb, __file) \ +{ \ + int i; \ + for_each_possible_cpu(i) { \ + struct list_head *list; \ + list = per_cpu_ptr((__sb)->s_files, i); \ + list_for_each_entry((__file), list, open_list) + +#define while_file_list_for_each_entry \ + } \ +} + +#else /* CONFIG_SMP */ + +#define do_file_list_for_each_entry(__sb, __file) \ +{ \ + struct list_head *list; \ + list = &(__sb)->s_files; \ + list_for_each_entry((__file), list, open_list) + +#define while_file_list_for_each_entry \ +} + +#endif /* CONFIG_SMP */ + +void fs_show_opened_file(struct mount *mnt, + const char *mnt_point_name, char *file_name_buf, int buflen) +{ + struct file *file; + char *file_name; + char comm[TASK_COMM_LEN + 1] = {0}; + unsigned long flags; + + spin_lock_irqsave(&files_list_lock, flags); + do_file_list_for_each_entry(mnt->mnt.mnt_sb, file) { + file_name = dentry_path_raw(file->f_path.dentry, file_name_buf, buflen - 1); + if (IS_ERR(file_name)) { + pr_warn("VFS: list file in mnt_point:%s error", mnt_point_name); + continue; + } + memcpy(comm, file->comm, TASK_COMM_LEN); + if (__ratelimit(&mnt->mnt.mnt_sb->rs)) + pr_warn("VFS: opened file in mnt_point: (%s), file: (%s), comm: (%s), pid:(%d)", + mnt_point_name, file_name, comm, file->pid); + } while_file_list_for_each_entry; + spin_unlock_irqrestore(&files_list_lock, flags); +} +#endif /* MY_ABC_HERE */ diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index a0869194ab73..62c597a4d5fd 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * fs/fs-writeback.c @@ -1211,7 +1214,11 @@ static void requeue_io(struct inode *inode, struct bdi_writeback *wb) inode_io_list_move_locked(inode, wb, &wb->b_more_io); } -static void inode_sync_complete(struct inode *inode) +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +void inode_sync_complete(struct inode *inode) { inode->i_state &= ~I_SYNC; /* If inode is clean an unused, put it into LRU now... */ @@ -1220,6 +1227,9 @@ static void inode_sync_complete(struct inode *inode) smp_mb(); wake_up_bit(&inode->i_state, __I_SYNC); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(inode_sync_complete); +#endif /* MY_ABC_HERE */ static bool inode_dirtied_after(struct inode *inode, unsigned long t) { @@ -2202,6 +2212,31 @@ int dirtytime_interval_handler(struct ctl_table *table, int write, return ret; } +#ifdef MY_ABC_HERE +static noinline void block_dump___mark_inode_dirty(struct inode *inode) +{ + if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { + struct dentry *dentry; + const char *name = "?"; + + dentry = d_find_alias(inode); + if (dentry) { + spin_lock(&dentry->d_lock); + name = (const char *) dentry->d_name.name; + } + printk(KERN_DEBUG + "ppid:%d(%s), pid:%d(%s), dirtied inode %lu (%s) on %s\n", + task_pid_nr(current->real_parent), current->real_parent->comm, + task_pid_nr(current), current->comm, inode->i_ino, + name, inode->i_sb->s_id); + if (dentry) { + spin_unlock(&dentry->d_lock); + dput(dentry); + } + } +} +#endif /* MY_ABC_HERE */ + /** * __mark_inode_dirty - internal function * @@ -2261,6 +2296,11 @@ void __mark_inode_dirty(struct inode *inode, int flags) (dirtytime && (inode->i_state & I_DIRTY_INODE))) return; +#ifdef MY_ABC_HERE + if (unlikely(block_dump)) + block_dump___mark_inode_dirty(inode); +#endif /* MY_ABC_HERE */ + spin_lock(&inode->i_lock); if (dirtytime && (inode->i_state & I_DIRTY_INODE)) goto out_unlock_inode; diff --git a/fs/fs_context.c b/fs/fs_context.c index 2834d1afa6e8..a8a14de7b76d 100644 --- a/fs/fs_context.c +++ b/fs/fs_context.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* Provide a way to create a superblock configuration context within the kernel * that allows a superblock to be set up prior to mounting. @@ -79,6 +82,33 @@ static int vfs_parse_sb_flag(struct fs_context *fc, const char *key) return -ENOPARAM; } +#ifdef MY_ABC_HERE +enum { + SB_RELATIME_PERIOD = 1, +}; + +static const struct constant_table syno_sb_mnt_opts[] = { + { "relatime_period", SB_RELATIME_PERIOD }, + { }, +}; + +static int vfs_parse_syno_sb_mnt_opts(struct fs_context *fc, struct fs_parameter *param) +{ + unsigned int token; + + token = lookup_constant(syno_sb_mnt_opts, param->key, 0); + if (token == SB_RELATIME_PERIOD) { + if (param->type != fs_value_is_string) + return invalf(fc, "VFS: Non-string source"); + if (kstrtoul(param->string, 10, &fc->relatime_period) || fc->relatime_period > 365 * 10) + return invalf(fc, "VFS: Invalid value"); + return 0; + } + + return -ENOPARAM; +} +#endif /* MY_ABC_HERE */ + /** * vfs_parse_fs_param - Add a single parameter to a superblock config * @fc: The filesystem context to modify @@ -106,6 +136,12 @@ int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param) if (ret != -ENOPARAM) return ret; +#ifdef MY_ABC_HERE + ret = vfs_parse_syno_sb_mnt_opts(fc, param); + if (ret != -ENOPARAM) + return ret; +#endif /* MY_ABC_HERE */ + ret = security_fs_context_parse_param(fc, param); if (ret != -ENOPARAM) /* Param belongs to the LSM or is disallowed by the LSM; so @@ -242,6 +278,9 @@ static struct fs_context *alloc_fs_context(struct file_system_type *fs_type, fc->cred = get_current_cred(); fc->net_ns = get_net(current->nsproxy->net_ns); fc->log.prefix = fs_type->name; +#ifdef MY_ABC_HERE + fc->relatime_period = 0; +#endif /* MY_ABC_HERE */ mutex_init(&fc->uapi_mutex); @@ -530,7 +569,7 @@ static int legacy_parse_param(struct fs_context *fc, struct fs_parameter *param) param->key); } - if (len > PAGE_SIZE - 2 - size) + if (size + len + 2 > PAGE_SIZE) return invalf(fc, "VFS: Legacy: Cumulative options too large"); if (strchr(param->key, ',') || (param->type == fs_value_is_string && @@ -638,9 +677,61 @@ static int legacy_init_fs_context(struct fs_context *fc) return 0; } +#ifdef MY_ABC_HERE +static void option_erase(char *str) { + char *next = strchr(str, ','); + + if (next) { + next++; + while (*next) { + *str = *next; + str++; + next++; + } + } + while (*str) { + *str = '\0'; + str++; + } +} + +/* + * This function is used to parse VFS layer options. These options should be removed + * from data since the underlying file systems cannot recognize them and may cause error. + */ +static int syno_sb_eat_mnt_opts(struct fs_context *fc, void *data) { + const struct constant_table *p; + char *str; + int ret = 0; + + if (!data) + return 0; + + for (p = syno_sb_mnt_opts; p->name; p++) { + while (NULL != (str = strstr(data, p->name))) { + char *value = strchr(str, '=') + 1; + char *found = strchr(str, ','); + size_t v_len = (found == NULL) ? strlen(value) : found - value; + ret = vfs_parse_fs_string(fc, p->name, value, v_len); + if (ret < 0) + return ret; + option_erase(str); + } + } + return 0; +} +#endif /* MY_ABC_HERE */ + int parse_monolithic_mount_data(struct fs_context *fc, void *data) { int (*monolithic_mount_data)(struct fs_context *, void *); +#ifdef MY_ABC_HERE + int ret = 0; + + ret = syno_sb_eat_mnt_opts(fc, data); + if (ret) + return ret; +#endif /* MY_ABC_HERE */ monolithic_mount_data = fc->ops->parse_monolithic; if (!monolithic_mount_data) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 4140d5c3ab5a..20d021172a1b 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -939,7 +939,17 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep, while (count) { if (cs->write && cs->pipebufs && page) { - return fuse_ref_page(cs, page, offset, count); + /* + * Can't control lifetime of pipe buffers, so always + * copy user pages. + */ + if (cs->req->args->user_pages) { + err = fuse_copy_fill(cs); + if (err) + return err; + } else { + return fuse_ref_page(cs, page, offset, count); + } } else if (!cs->len) { if (cs->move_pages && page && offset == 0 && count == PAGE_SIZE) { diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 756bbdd563e0..e3cd2a224327 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* FUSE: Filesystem in Userspace Copyright (C) 2001-2008 Miklos Szeredi @@ -17,6 +20,10 @@ #include #include #include +#ifdef MY_ABC_HERE +#include "../ntfs/time.h" +#include "../ntfs/endian.h" +#endif /* MY_ABC_HERE*/ static void fuse_advise_use_readdirplus(struct inode *dir) { @@ -1843,6 +1850,331 @@ static int fuse_getattr(const struct path *path, struct kstat *stat, return fuse_update_get_attr(inode, NULL, stat, request_mask, flags); } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) || \ + defined(MY_ABC_HERE) +#define SZ_FS_NTFS "ntfs" +#define IS_NTFS_FS(inode) (inode->i_sb->s_subtype && !strcmp(SZ_FS_NTFS, inode->i_sb->s_subtype)) +#endif /* MY_ABC_HERE || MY_ABC_HERE || + MY_ABC_HERE*/ +#ifdef MY_ABC_HERE +#define XATTR_NTFS_CREATE_TIME "ntfs_crtime" +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __fuse_syno_get_archive_bit(struct dentry *dentry, + unsigned int *archive_bit) +{ + struct inode *inode = dentry->d_inode; + + if (IS_NTFS_FS(inode)) { + ssize_t size = 0; + unsigned int tmp_archive_bit; + + size = fuse_getxattr(inode, XATTR_SYNO_ARCHIVE_BIT, + &tmp_archive_bit, sizeof(tmp_archive_bit)); + + if (size != sizeof(tmp_archive_bit)) + return (size < 0) ? size : -EINVAL; + + /* + * Use default value: ALL_SYNO_ARCHIVE if + * inode->i_archive_bit is not cached yet. + * + * For those archive bits not supported by ntfs + * are only kept in in-memory inode. + */ + *archive_bit = (ALL_SYNO_ARCHIVE & (~ALL_SMB)) | \ + (tmp_archive_bit & ALL_SMB); + + return 0; + } + + return -EOPNOTSUPP; +} + +static int fuse_syno_get_archive_bit(struct dentry *dentry, + unsigned int *archive_bit, int may_not_block) +{ + int ret; + unsigned int tmp_archive_bit; + struct inode *inode = dentry->d_inode; + struct fuse_inode *fi = get_fuse_inode(inode); + + if (test_bit(FUSE_I_SYNO_ARCHIVE_BIT_CACHED, &fi->state)) { + *archive_bit = inode->i_archive_bit; + + return 0; + } + + if (may_not_block) + return -ECHILD; + + ret = __fuse_syno_get_archive_bit(dentry, &tmp_archive_bit); + if (ret) + return ret; + + inode->i_archive_bit = tmp_archive_bit; + set_bit(FUSE_I_SYNO_ARCHIVE_BIT_CACHED, &fi->state); + + *archive_bit = tmp_archive_bit; + + return ret; +} + +static int __fuse_syno_set_archive_bit(struct dentry *dentry, + unsigned int archive_bit) +{ + struct inode *inode = dentry->d_inode; + + if (IS_NTFS_FS(inode)) { + // Only supported smb bits(ALL_SMB) would be written into disk. + return fuse_setxattr(inode, XATTR_SYNO_ARCHIVE_BIT, + &archive_bit, sizeof(archive_bit), 0); + } + + return -EOPNOTSUPP; +} + +static int fuse_syno_set_archive_bit(struct dentry *dentry, + unsigned int archive_bit) +{ + int ret; + struct inode *inode = dentry->d_inode; + struct fuse_inode *fi = get_fuse_inode(inode); + + /* + * If you want to update to server side inode (userspace daemon): + * (1) Make sure that server will update this to on-disk inode structure. + * (2) Make sure that IS_NOCMTIME(inode) is NOT set -- + * otherwise mark_inode_dirty_sync will update wrong cmtime to server. + * Please refer to fuse_update_ctime. + */ + ret = __fuse_syno_set_archive_bit(dentry, archive_bit); + if (ret) + return ret; + + inode->i_archive_bit = archive_bit; + set_bit(FUSE_I_SYNO_ARCHIVE_BIT_CACHED, &fi->state); + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __fuse_syno_get_inode_archive_version( + struct dentry *dentry, u32 *archive_version) +{ + return -EOPNOTSUPP; +} + +static int fuse_syno_get_inode_archive_version( + struct dentry *dentry, u32 *archive_version) +{ + int ret; + u32 tmp_archive_version; + struct inode *inode = d_inode(dentry); + struct fuse_inode *fi = get_fuse_inode(inode); + + if (test_bit(FUSE_I_SYNO_ARCHIVE_VERSION_CACHED, &fi->state)) { + *archive_version = inode->i_archive_version; + + return 0; + } + + ret = __fuse_syno_get_inode_archive_version(dentry, + &tmp_archive_version); + if (ret) + return ret; + + inode->i_archive_version = tmp_archive_version; + set_bit(FUSE_I_SYNO_ARCHIVE_VERSION_CACHED, &fi->state); + + *archive_version = tmp_archive_version; + + return 0; +} + +static int __fuse_syno_set_inode_archive_version(struct dentry *dentry, + unsigned int archive_version) +{ + return -EOPNOTSUPP; +} + +static int fuse_syno_set_inode_archive_version(struct dentry *dentry, + unsigned int archive_version) +{ + int ret; + struct inode *inode = dentry->d_inode; + struct fuse_inode *fi = get_fuse_inode(inode); + + /* + * If you want to update to server side inode (userspace daemon): + * (1) Make sure that server will update this to on-disk inode structure. + * (2) Make sure that IS_NOCMTIME(inode) is NOT set -- + * otherwise mark_inode_dirty_sync will update wrong cmtime to server. + * Please refer to fuse_update_ctime. + */ + ret = __fuse_syno_set_inode_archive_version(dentry, archive_version); + if (ret) + return ret; + + inode->i_archive_version = archive_version; + set_bit(FUSE_I_SYNO_ARCHIVE_VERSION_CACHED, &fi->state); + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __fuse_syno_get_create_time(struct inode *inode, + struct timespec64 *create_time) +{ + if (IS_NTFS_FS(inode)) { + ssize_t size; + s64 time_s = 0; + + size = fuse_getxattr(inode, + XATTR_SYSTEM_PREFIX XATTR_NTFS_CREATE_TIME, + &time_s, sizeof(time_s)); + if (size != sizeof(time_s)) + return (size < 0) ? size : -EINVAL; + + *create_time = ntfs2utc(cpu_to_sle64(time_s)); + + return 0; + } + + return -EOPNOTSUPP; +} + +static int fuse_syno_get_create_time(struct inode *inode, + struct timespec64 *create_time) +{ + int ret; + struct timespec64 tmp_create_time; + struct fuse_inode *fi = get_fuse_inode(inode); + + if (test_bit(FUSE_I_SYNO_CREATE_TIME_CACHED, &fi->state)) { + *create_time = fi->i_crtime; + + return 0; + } + + ret = __fuse_syno_get_create_time(inode, &tmp_create_time); + if (ret) + return ret; + + fi->i_crtime = tmp_create_time; + set_bit(FUSE_I_SYNO_CREATE_TIME_CACHED, &fi->state); + + *create_time = tmp_create_time; + + return 0; +} + +static int __fuse_syno_set_create_time(struct inode *inode, + struct timespec64 *create_time) +{ + if (IS_NTFS_FS(inode)) { + s64 time_s = sle64_to_cpu(utc2ntfs(*create_time)); + + return fuse_setxattr(inode, + XATTR_SYSTEM_PREFIX XATTR_NTFS_CREATE_TIME, + &time_s, sizeof(time_s), 0); + } + + return -EOPNOTSUPP; +} + +static int fuse_syno_set_create_time(struct inode *inode, + struct timespec64 *create_time) +{ + int ret; + struct fuse_inode *fi = get_fuse_inode(inode); + + /* + * If you want to update to server side inode (userspace daemon): + * (1) Make sure that server will update this to on-disk inode structure. + * (2) Make sure that IS_NOCMTIME(inode) is NOT set -- + * otherwise mark_inode_dirty_sync will update wrong cmtime to server. + * Please refer to fuse_update_ctime. + */ + ret = __fuse_syno_set_create_time(inode, create_time); + if (ret) + return ret; + + fi->i_crtime = *create_time; + set_bit(FUSE_I_SYNO_CREATE_TIME_CACHED, &fi->state); + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int fuse_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags) +{ + int ret = 0; + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_BIT) { + unsigned int tmp_archive_bit; + struct inode *inode = dentry->d_inode; + + mutex_lock(&inode->i_archive_bit_mutex); + ret = fuse_syno_get_archive_bit(dentry, &tmp_archive_bit, 0); + mutex_unlock(&inode->i_archive_bit_mutex); + if (ret == -EOPNOTSUPP) { + tmp_archive_bit = ALL_SYNO_ARCHIVE; + ret = 0; + } else if (ret) { + return ret; + } + + kst->syno_archive_bit = tmp_archive_bit; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_VER) { + u32 tmp_archive_version; + struct inode *inode = dentry->d_inode; + + mutex_lock(&inode->i_archive_version_mutex); + ret = fuse_syno_get_inode_archive_version(dentry, + &tmp_archive_version); + mutex_unlock(&inode->i_archive_version_mutex); + if (ret == -EOPNOTSUPP) { + tmp_archive_version = 0; + ret = 0; + } else if (ret) { + return ret; + } + + kst->syno_archive_version = tmp_archive_version; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_CREATE_TIME) { + struct timespec64 tmp_create_time; + struct inode *inode = dentry->d_inode; + + ret = fuse_syno_get_create_time(inode, &tmp_create_time); + if (ret == -EOPNOTSUPP) { + memset(&tmp_create_time, 0, sizeof(tmp_create_time)); + ret = 0; + } else if (ret) { + return ret; + } + + kst->syno_create_time = tmp_create_time; + } +#endif /* MY_ABC_HERE */ + + return ret; +} +#endif /* MY_ABC_HERE */ + static const struct inode_operations fuse_dir_inode_operations = { .lookup = fuse_lookup, .mkdir = fuse_mkdir, @@ -1860,6 +2192,21 @@ static const struct inode_operations fuse_dir_inode_operations = { .listxattr = fuse_listxattr, .get_acl = fuse_get_acl, .set_acl = fuse_set_acl, +#ifdef MY_ABC_HERE + .syno_getattr = fuse_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_bit = fuse_syno_get_archive_bit, + .syno_set_archive_bit = fuse_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = fuse_syno_get_inode_archive_version, + .syno_set_archive_version = fuse_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = fuse_syno_get_create_time, + .syno_set_crtime = fuse_syno_set_create_time, +#endif /* MY_ABC_HERE */ }; static const struct file_operations fuse_dir_operations = { @@ -1880,6 +2227,21 @@ static const struct inode_operations fuse_common_inode_operations = { .listxattr = fuse_listxattr, .get_acl = fuse_get_acl, .set_acl = fuse_set_acl, +#ifdef MY_ABC_HERE + .syno_getattr = fuse_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_bit = fuse_syno_get_archive_bit, + .syno_set_archive_bit = fuse_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = fuse_syno_get_inode_archive_version, + .syno_set_archive_version = fuse_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = fuse_syno_get_create_time, + .syno_set_crtime = fuse_syno_set_create_time, +#endif /* MY_ABC_HERE */ }; static const struct inode_operations fuse_symlink_inode_operations = { @@ -1887,6 +2249,21 @@ static const struct inode_operations fuse_symlink_inode_operations = { .get_link = fuse_get_link, .getattr = fuse_getattr, .listxattr = fuse_listxattr, +#ifdef MY_ABC_HERE + .syno_getattr = fuse_syno_getattr, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_bit = fuse_syno_get_archive_bit, + .syno_set_archive_bit = fuse_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_archive_version = fuse_syno_get_inode_archive_version, + .syno_set_archive_version = fuse_syno_set_inode_archive_version, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime = fuse_syno_get_create_time, + .syno_set_crtime = fuse_syno_set_create_time, +#endif /* MY_ABC_HERE */ }; void fuse_init_common(struct inode *inode) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 8de9c24ac4ac..46e2510a93ba 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* FUSE: Filesystem in Userspace Copyright (C) 2001-2008 Miklos Szeredi @@ -1132,6 +1135,74 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia, return err; } +#ifdef MY_ABC_HERE +static ssize_t fuse_perform_write_page(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, struct page *page) +{ + int err = 0; + int need_unlock = 1; + ssize_t res = 0; + size_t num_written; + struct kiocb iocb; + struct fuse_io_args ia = {}; + struct fuse_args_pages *ap = &ia.ap; + struct inode *inode = mapping->host; + struct fuse_inode *fi = get_fuse_inode(inode); + unsigned offset = pos & (PAGE_SIZE - 1); + + if (is_bad_inode(inode)) { + err = -EIO; + goto end; + } + + if (inode->i_size < pos + len) + set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + + ap->pages = fuse_pages_alloc(1, GFP_KERNEL, &ap->descs); + if (!ap->pages) { + err = -ENOMEM; + goto end; + } + + ap->args.in_pages = true; + ap->descs[0].offset = offset; + ap->pages[ap->num_pages] = page; + ap->descs[ap->num_pages].length = len; + ap->num_pages++; + ia.write.page_locked = true; + init_sync_kiocb(&iocb, file); + + err = fuse_send_write_pages(&ia, &iocb, inode, + pos, len); + need_unlock = 0; + if (!err) { + num_written = ia.write.out.size; + + res += num_written; + pos += num_written; + + /* break out of the loop on short write */ + if (num_written != len) + err = -EIO; + } + + if (res > 0) + fuse_write_update_size(inode, pos); + + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + fuse_invalidate_attr(inode); + +end: + if (need_unlock) { + unlock_page(page); + put_page(page); + } + kfree(ap->pages); + return res > 0 ? res : err; +} +#endif /* MY_ABC_HERE */ + static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, struct address_space *mapping, struct iov_iter *ii, loff_t pos, @@ -1415,6 +1486,7 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii, (PAGE_SIZE - ret) & (PAGE_SIZE - 1); } + ap->args.user_pages = true; if (write) ap->args.in_pages = true; else @@ -2242,6 +2314,9 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping, loff_t fsize; int err = -ENOMEM; +#ifdef MY_ABC_HERE + if (!(flags & AOP_FLAG_RECVFILE)) /* Don't trigger WARN_ON if caller is recvfile() */ +#endif /* MY_ABC_HERE */ WARN_ON(!fc->writeback_cache); page = grab_cache_page_write_begin(mapping, index, flags); @@ -2282,6 +2357,17 @@ static int fuse_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { struct inode *inode = page->mapping->host; +#ifdef MY_ABC_HERE + struct fuse_conn *fc = get_fuse_conn(file_inode(file)); + + /* + * recvfile() calls fuse_write_end(), but fuse lib might not support + * writeback cache (e.g., ntfs-3g fuse-lite). If writeback cache is + * not enabled, we write through this page. + */ + if (!fc->writeback_cache) + return fuse_perform_write_page(file, mapping, pos, len, page); +#endif /* MY_ABC_HERE */ /* Haven't copied anything? Skip zeroing, size extending, dirtying. */ if (!copied) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8150621101c6..6cedabe0cf15 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* FUSE: Filesystem in Userspace Copyright (C) 2001-2008 Miklos Szeredi @@ -162,6 +165,9 @@ struct fuse_inode { */ struct fuse_inode_dax *dax; #endif +#ifdef MY_ABC_HERE + struct timespec64 i_crtime; +#endif /* MY_ABC_HERE */ }; /** FUSE inode state bits */ @@ -174,6 +180,18 @@ enum { FUSE_I_SIZE_UNSTABLE, /* Bad inode */ FUSE_I_BAD, +#ifdef MY_ABC_HERE + /* Syno archive bit cached */ + FUSE_I_SYNO_ARCHIVE_BIT_CACHED, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* Syno archive version cached */ + FUSE_I_SYNO_ARCHIVE_VERSION_CACHED, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* Syno create time cached */ + FUSE_I_SYNO_CREATE_TIME_CACHED, +#endif /* MY_ABC_HERE */ }; struct fuse_conn; @@ -263,6 +281,7 @@ struct fuse_args { bool nocreds:1; bool in_pages:1; bool out_pages:1; + bool user_pages:1; bool out_argvar:1; bool page_zeroing:1; bool page_replace:1; @@ -812,10 +831,23 @@ struct fuse_mount { */ struct super_block *sb; +#ifdef MY_ABC_HERE + /* In memory syno state */ + unsigned long syno_state; +#endif /* MY_ABC_HERE */ + /* Entry on fc->mounts */ struct list_head fc_entry; }; +#ifdef MY_ABC_HERE +/** syno fs state bits for fuse_mount.syno_state */ +enum { + /* Syno archive version cached */ + FUSE_S_SYNO_ARCHIVE_VERSION_CACHED, +}; +#endif /* MY_ABC_HERE */ + static inline struct fuse_mount *get_fuse_mount_super(struct super_block *sb) { return sb->s_fs_info; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f94b0bb57619..142a2fb32379 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* FUSE: Filesystem in Userspace Copyright (C) 2001-2008 Miklos Szeredi @@ -706,6 +709,9 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, list_add(&fm->fc_entry, &fc->mounts); fm->fc = fc; refcount_set(&fm->count, 1); +#ifdef MY_ABC_HERE + fm->syno_state = 0; +#endif /* MY_ABC_HERE */ } EXPORT_SYMBOL_GPL(fuse_conn_init); @@ -900,6 +906,61 @@ static struct dentry *fuse_get_parent(struct dentry *child) return parent; } +#ifdef MY_ABC_HERE +static int __fuse_syno_get_sb_archive_version( + struct super_block *sb, u32 *archive_version) +{ + return -EOPNOTSUPP; +} + +static int fuse_syno_get_sb_archive_version( + struct super_block *sb, u32 *archive_version) +{ + int ret; + u32 tmp_archive_version; + struct fuse_mount *fm = get_fuse_mount_super(sb); + + if (test_bit(FUSE_S_SYNO_ARCHIVE_VERSION_CACHED, &fm->syno_state)) { + *archive_version = sb->s_archive_version; + + return 0; + } + + ret = __fuse_syno_get_sb_archive_version(sb, &tmp_archive_version); + if (ret) + return ret; + + sb->s_archive_version = tmp_archive_version; + set_bit(FUSE_S_SYNO_ARCHIVE_VERSION_CACHED, &fm->syno_state); + + *archive_version = tmp_archive_version; + + return 0; +} + +static int __fuse_syno_set_sb_archive_version( + struct super_block *sb, u32 archive_version) +{ + return -EOPNOTSUPP; +} + +static int fuse_syno_set_sb_archive_version( + struct super_block *sb, u32 archive_version) +{ + int ret; + struct fuse_mount *fm = get_fuse_mount_super(sb); + + ret = __fuse_syno_set_sb_archive_version(sb, archive_version); + if (ret) + return ret; + + sb->s_archive_version = archive_version; + set_bit(FUSE_S_SYNO_ARCHIVE_VERSION_CACHED, &fm->syno_state); + + return ret; +} +#endif /* MY_ABC_HERE */ + static const struct export_operations fuse_export_operations = { .fh_to_dentry = fuse_fh_to_dentry, .fh_to_parent = fuse_fh_to_parent, @@ -917,6 +978,10 @@ static const struct super_operations fuse_super_operations = { .umount_begin = fuse_umount_begin, .statfs = fuse_statfs, .show_options = fuse_show_options, +#ifdef MY_ABC_HERE + .syno_get_sb_archive_version = fuse_syno_get_sb_archive_version, + .syno_set_sb_archive_version = fuse_syno_set_sb_archive_version, +#endif /* MY_ABC_HERE */ }; static void sanitize_global_limit(unsigned *limit) diff --git a/fs/hfsplus/attributes.c b/fs/hfsplus/attributes.c index eeebe80c6be4..8dde7a2e6388 100644 --- a/fs/hfsplus/attributes.c +++ b/fs/hfsplus/attributes.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/attributes.c @@ -55,7 +58,11 @@ int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key, memset(key, 0, sizeof(struct hfsplus_attr_key)); key->attr.cnid = cpu_to_be32(cnid); if (name) { +#ifdef MY_ABC_HERE + int res = hfsplus_attr_asc2uni(sb, +#else /* MY_ABC_HERE */ int res = hfsplus_asc2uni(sb, +#endif /* MY_ABC_HERE */ (struct hfsplus_unistr *)&key->attr.key_name, HFSPLUS_ATTR_MAX_STRLEN, name, strlen(name)); if (res) diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 177fae4e6581..59d828fd451b 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/bnode.c @@ -23,7 +26,11 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) { struct page **pagep; int l; +#ifdef MY_ABC_HERE + int pagenum; + pagenum = off >> PAGE_SHIFT; +#endif /* MY_ABC_HERE */ off += node->page_offset; pagep = node->page + (off >> PAGE_SHIFT); off &= ~PAGE_MASK; @@ -33,6 +40,10 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) kunmap(*pagep); while ((len -= l) != 0) { +#ifdef MY_ABC_HERE + if (++pagenum >= node->tree->pages_per_bnode) + break; +#endif /* MY_ABC_HERE */ buf += l; l = min_t(int, len, PAGE_SIZE); memcpy(buf, kmap(*++pagep), l); diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 35472cba750e..c69df8b986a2 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/catalog.c @@ -40,14 +43,24 @@ int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, } /* Generates key for catalog file/folders record. */ +#ifdef MY_ABC_HERE +int hfsplus_cat_build_key(struct super_block *sb, + hfsplus_btree_key *key, u32 parent, const struct qstr *str, bool nfc) +#else int hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, u32 parent, const struct qstr *str) +#endif /* MY_ABC_HERE */ { int len, err; key->cat.parent = cpu_to_be32(parent); +#ifdef MY_ABC_HERE + err = hfsplus_nfc_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, + str->name, str->len, nfc); +#else /* MY_ABC_HERE */ err = hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, str->name, str->len); +#endif /* MY_ABC_HERE */ if (unlikely(err < 0)) return err; @@ -182,8 +195,14 @@ static int hfsplus_fill_cat_thread(struct super_block *sb, entry->type = cpu_to_be16(type); entry->thread.reserved = 0; entry->thread.parentID = cpu_to_be32(parentid); +#ifdef MY_ABC_HERE + err = hfsplus_nfc_asc2uni(sb, &entry->thread.nodeName, + HFSPLUS_MAX_STRLEN, str->name, str->len, + false); +#else err = hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, str->name, str->len); +#endif /* MY_ABC_HERE */ if (unlikely(err < 0)) return err; @@ -293,7 +312,11 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, if (err) goto err2; +#ifdef MY_ABC_HERE + err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str, false); +#else err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); +#endif /* MY_ABC_HERE */ if (unlikely(err)) goto err1; @@ -335,6 +358,9 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str) struct list_head *pos; int err, off; u16 type; +#ifdef MY_ABC_HERE + bool nfc = false; +#endif /* MY_ABC_HERE */ hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); @@ -368,14 +394,29 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str) off + 2, len); fd.search_key->key_len = cpu_to_be16(6 + len); } else { +#ifdef MY_ABC_HERE +NFC: + err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str, nfc); +#else err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); +#endif /* MY_ABC_HERE */ if (unlikely(err)) goto out; } err = hfs_brec_find(&fd, hfs_find_rec_by_key); +#ifdef MY_ABC_HERE + if (err) { + if (err == -ENOENT && !nfc) { + nfc = true; + goto NFC; + } + goto out; + } +#else if (err) goto out; +#endif /* MY_ABC_HERE */ type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); if (type == HFSPLUS_FILE) { @@ -440,6 +481,9 @@ int hfsplus_rename_cat(u32 cnid, hfsplus_cat_entry entry; int entry_size, type; int err; +#ifdef MY_ABC_HERE + bool nfc; +#endif /* MY_ABC_HERE */ hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name, @@ -458,14 +502,31 @@ int hfsplus_rename_cat(u32 cnid, goto out; /* find the old dir entry and read the data */ +#ifdef MY_ABC_HERE + nfc = false; +NFC1: + err = hfsplus_cat_build_key(sb, src_fd.search_key, + src_dir->i_ino, src_name, nfc); +#else err = hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); +#endif /* MY_ABC_HERE */ if (unlikely(err)) goto out; err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); +#ifdef MY_ABC_HERE + if (err) { + if (err == -ENOENT && !nfc) { + nfc = true; + goto NFC1; + } + goto out; + } +#else if (err) goto out; +#endif /* MY_ABC_HERE */ if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { err = -EIO; goto out; @@ -476,8 +537,13 @@ int hfsplus_rename_cat(u32 cnid, type = be16_to_cpu(entry.type); /* create new dir entry with the data from the old entry */ +#ifdef MY_ABC_HERE + err = hfsplus_cat_build_key(sb, dst_fd.search_key, + dst_dir->i_ino, dst_name, false); +#else err = hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); +#endif /* MY_ABC_HERE */ if (unlikely(err)) goto out; @@ -497,14 +563,31 @@ int hfsplus_rename_cat(u32 cnid, dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir); /* finally remove the old entry */ +#ifdef MY_ABC_HERE + nfc = false; +NFC2: + err = hfsplus_cat_build_key(sb, src_fd.search_key, + src_dir->i_ino, src_name, nfc); +#else err = hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); +#endif /* MY_ABC_HERE */ if (unlikely(err)) goto out; err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); +#ifdef MY_ABC_HERE + if (err) { + if (err == -ENOENT && !nfc) { + nfc = true; + goto NFC2; + } + goto out; + } +#else if (err) goto out; +#endif /* MY_ABC_HERE */ err = hfs_brec_remove(&src_fd); if (err) goto out; diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 29a9dcfbe81f..54e328fb3339 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/dir.c @@ -37,6 +40,9 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, int err; u32 cnid, linkid = 0; u16 type; +#ifdef MY_ABC_HERE + bool nfc = false; +#endif /* MY_ABC_HERE */ sb = dir->i_sb; @@ -44,14 +50,26 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); if (err) return ERR_PTR(err); +#ifdef MY_ABC_HERE +NFC: + err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, + &dentry->d_name, nfc); +#else err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); +#endif /* MY_ABC_HERE */ if (unlikely(err < 0)) goto fail; again: err = hfs_brec_read(&fd, &entry, sizeof(entry)); if (err) { if (err == -ENOENT) { +#ifdef MY_ABC_HERE + if (!nfc) { + nfc = true; + goto NFC; + } +#endif /* MY_ABC_HERE */ hfs_find_exit(&fd); /* No such entry */ inode = NULL; @@ -100,9 +118,15 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, be32_to_cpu(entry.file.permissions.dev); str.len = sprintf(name, "iNode%d", linkid); str.name = name; +#ifdef MY_ABC_HERE + err = hfsplus_cat_build_key(sb, fd.search_key, + HFSPLUS_SB(sb)->hidden_dir->i_ino, + &str, false); +#else err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb)->hidden_dir->i_ino, &str); +#endif /* MY_ABC_HERE */ if (unlikely(err < 0)) goto fail; goto again; @@ -121,6 +145,11 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, if (S_ISREG(inode->i_mode)) HFSPLUS_I(inode)->linkid = linkid; out: +#ifdef MY_ABC_HERE + /* Prevent the negative dentry in the encoding case from being cached */ + if (!inode && test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags)) + return NULL; +#endif /* MY_ABC_HERE */ return d_splice_alias(inode, dentry); fail: hfs_find_exit(&fd); @@ -407,6 +436,14 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) sbi->file_count--; inode->i_ctime = current_time(inode); mark_inode_dirty(inode); + +#ifdef MY_ABC_HERE + /* VFS negative dentries are incompatible with encoding and + * case-insensitiveness + */ + if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags)) + d_invalidate(dentry); +#endif /* MY_ABC_HERE */ out: mutex_unlock(&sbi->vh_mutex); return res; @@ -429,6 +466,14 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) inode->i_ctime = current_time(inode); hfsplus_delete_inode(inode); mark_inode_dirty(inode); + +#ifdef MY_ABC_HERE + /* VFS negative dentries are incompatible with encoding and + * case-insensitiveness + */ + if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags)) + d_invalidate(dentry); +#endif /* MY_ABC_HERE */ out: mutex_unlock(&sbi->vh_mutex); return res; @@ -567,6 +612,11 @@ const struct inode_operations hfsplus_dir_inode_operations = { .rename = hfsplus_rename, .getattr = hfsplus_getattr, .listxattr = hfsplus_listxattr, +#ifdef MY_ABC_HERE + .syno_getattr = hfsplus_syno_getattr, + .syno_get_crtime = hfsplus_syno_get_crtime, + .syno_set_crtime = hfsplus_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; const struct file_operations hfsplus_dir_operations = { diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index a92de5199ec3..eb4c86c360de 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/include/linux/hfsplus_fs.h @@ -446,8 +449,13 @@ int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, const hfsplus_btree_key *k2); int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, const hfsplus_btree_key *k2); +#ifdef MY_ABC_HERE +int hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, + u32 parent, const struct qstr *str, bool nfc); +#else int hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, u32 parent, const struct qstr *str); +#endif /* MY_ABC_HERE */ void hfsplus_cat_build_key_with_cnid(struct super_block *sb, hfsplus_btree_key *key, u32 parent); void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms); @@ -492,6 +500,12 @@ int hfsplus_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags); int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); +#ifdef MY_ABC_HERE +int hfsplus_syno_getattr(struct dentry *dentry, struct kstat *kst, + unsigned int syno_flags); +int hfsplus_syno_get_crtime(struct inode *inode, struct timespec64 *crtime); +int hfsplus_syno_set_crtime(struct inode *inode, struct timespec64 *crtime); +#endif /* MY_ABC_HERE */ /* ioctl.c */ long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); @@ -523,7 +537,26 @@ int hfsplus_strcmp(const struct hfsplus_unistr *s1, int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p); int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, - int max_unistr_len, const char *astr, int len); + int max_unistr_len, const char *astr, int len +#ifdef MY_ABC_HERE + , bool convert +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , bool nfc +#endif /* MY_ABC_HERE */ + ); +#ifdef MY_ABC_HERE +int hfsplus_attr_uni2asc(struct super_block *sb, + const struct hfsplus_unistr *ustr, char *astr, + int *len_p); +int hfsplus_attr_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, + int max_unistr_len, const char *astr, int len); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int hfsplus_nfc_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, + int max_unistr_len, const char *astr, int len, + bool nfc); +#endif /* MY_ABC_HERE */ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str); int hfsplus_compare_dentry(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name); diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 456e87aec7fd..1bd95bb7a7b2 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/include/linux/hfsplus_raw.h @@ -380,6 +383,41 @@ struct hfsplus_attr_extents { #define HFSPLUS_MAX_INLINE_DATA_SIZE 3802 +#ifdef MY_ABC_HERE +/* + * Apple Open Source hfs project mentions that HFSPlusAttrInlineData is + * obsolete use HFSPlusAttrData instead[1]. However, Apple Technical + * Specification doesn't reveal which is correct attr_inline_data data + * structure [2]. Since the following structure is still compatible with + * latest hfs implementation, we don't update it in 5.10.x Kernel Porting. + * + * Why we said it is compatible? + * hfs_format.h + * struct HFSPlusAttrData { + * u_int32_t recordType; // == kHFSPlusAttrInlineData + * u_int32_t reserved[2]; + * u_int32_t attrSize; // size of attribute data in bytes + * u_int8_t attrData[2]; // variable length + * } __attribute__((aligned(2), packed)); + * - recordType/record_type both start in offset 0 bytes. + * - attrSize/length can read the same value: + * 1. hfs - getmaxinlineattrsize mentions 3,802 bytes for an 8K node size. + * size_t nodesize = ATTRIBUTE_FILE_NODE_SIZE; // 8K is hard coded + * 3802 is never bigger than 65535 (2^16 - 1) + * 2. Big-Endian make it works. + * ex: 0x00001234 + * attrSize see 0x00|0x00|0x12|0x34 (offset: 12th - 15th byte) + * length see 0x12|0x34 (offset: 14th - 15th byte) + * + * If someone get the spec in the future, To-do: + * 1. Update struct hfsplus_attr_inline_data + * 2. Don't use slab malloc; use kvmalloc instead + * + * References: + * [1] https://opensource.apple.com/source/hfs/ + * [2] https://developer.apple.com/library/archive/technotes/tn/tn1150.html + */ +#endif /* MY_ABC_HERE */ /* HFS+ attribute inline data */ struct hfsplus_attr_inline_data { __be32 record_type; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index e3da9e96b835..24e3323d1a3e 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/inode.c @@ -286,6 +289,13 @@ int hfsplus_getattr(const struct path *path, struct kstat *stat, stat->attributes_mask |= STATX_ATTR_APPEND | STATX_ATTR_IMMUTABLE | STATX_ATTR_NODUMP; +#ifdef MY_ABC_HERE + if (request_mask & STATX_BTIME) { + stat->result_mask |= STATX_BTIME; + stat->btime = hfsp_mt2ut(hip->create_date); + } +#endif /* MY_ABC_HERE */ + generic_fillattr(inode, stat); return 0; } @@ -351,6 +361,11 @@ static const struct inode_operations hfsplus_file_inode_operations = { .setattr = hfsplus_setattr, .getattr = hfsplus_getattr, .listxattr = hfsplus_listxattr, +#ifdef MY_ABC_HERE + .syno_getattr = hfsplus_syno_getattr, + .syno_get_crtime= hfsplus_syno_get_crtime, + .syno_set_crtime= hfsplus_syno_set_crtime, +#endif /* MY_ABC_HERE */ }; static const struct file_operations hfsplus_file_operations = { @@ -585,6 +600,9 @@ int hfsplus_cat_write_inode(struct inode *inode) folder->access_date = hfsp_ut2mt(inode->i_atime); folder->content_mod_date = hfsp_ut2mt(inode->i_mtime); folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); +#ifdef MY_ABC_HERE + folder->create_date = HFSPLUS_I(inode)->create_date; +#endif /* MY_ABC_HERE */ folder->valence = cpu_to_be32(inode->i_size - 2); if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) { folder->subfolders = @@ -617,6 +635,9 @@ int hfsplus_cat_write_inode(struct inode *inode) file->access_date = hfsp_ut2mt(inode->i_atime); file->content_mod_date = hfsp_ut2mt(inode->i_mtime); file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); +#ifdef MY_ABC_HERE + file->create_date = HFSPLUS_I(inode)->create_date; +#endif /* MY_ABC_HERE */ hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, sizeof(struct hfsplus_cat_file)); } @@ -626,3 +647,31 @@ int hfsplus_cat_write_inode(struct inode *inode) hfs_find_exit(&fd); return 0; } + +#ifdef MY_ABC_HERE +int hfsplus_syno_getattr(struct dentry *dentry, struct kstat *kst, + unsigned int syno_flags) +{ + struct inode *inode = d_inode(dentry); + + if (syno_flags & SYNOST_CREATE_TIME) + kst->syno_create_time = hfsp_mt2ut(HFSPLUS_I(inode)->create_date); + + return 0; +} + +int hfsplus_syno_get_crtime(struct inode *inode, struct timespec64 *crtime) +{ + *crtime = hfsp_mt2ut(HFSPLUS_I(inode)->create_date); + + return 0; +} + +int hfsplus_syno_set_crtime(struct inode *inode, struct timespec64 *crtime) +{ + HFSPLUS_I(inode)->create_date = hfsp_ut2mt(*crtime); + hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); + + return 0; +} +#endif /* MY_ABC_HERE */ diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index 047e05c57560..7338ae6c4f33 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/options.c @@ -51,8 +54,21 @@ void hfsplus_fill_defaults(struct hfsplus_sb_info *opts) if (!opts) return; +#ifdef MY_ABC_HERE +/* + * HFSPLUS_DEF_CR_TYPE come from linux kernel not + * Apple hfs source. If we set this default value, + * any new created file will contain this value in + * it's creator/type fields, and it may let system + * treat it as xattr unexpectedly. So we remove this + * behavior. + */ + opts->creator = 0; + opts->type = 0; +#elif /* MY_ABC_HERE */ opts->creator = HFSPLUS_DEF_CR_TYPE; opts->type = HFSPLUS_DEF_CR_TYPE; +#endif /* MY_ABC_HERE */ opts->umask = current_umask(); opts->uid = current_uid(); opts->gid = current_gid(); @@ -235,5 +251,9 @@ int hfsplus_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",nodecompose"); if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) seq_puts(seq, ",nobarrier"); +#ifdef MY_ABC_HERE + if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags)) + seq_puts(seq, ",caseless"); +#endif /* MY_ABC_HERE */ return 0; } diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 807119ae5adf..21d7401adb42 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/hfsplus/super.c @@ -519,7 +522,11 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) err = hfs_find_init(sbi->cat_tree, &fd); if (err) goto out_put_root; +#ifdef MY_ABC_HERE + err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str, false); +#else err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); +#endif /* MY_ABC_HERE */ if (unlikely(err < 0)) goto out_put_root; if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 73342c925a4b..89112691cb35 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/unicode.c @@ -118,10 +121,15 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc) } while (s <= e); return NULL; } - +#ifdef MY_ABC_HERE +static int _hfsplus_uni2asc(struct super_block *sb, + const struct hfsplus_unistr *ustr, + char *astr, int *len_p, bool convert) +#else /* MY_ABC_HERE */ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p) +#endif /* MY_ABC_HERE */ { const hfsplus_unichr *ip; struct nls_table *nls = HFSPLUS_SB(sb)->nls; @@ -187,6 +195,9 @@ int hfsplus_uni2asc(struct super_block *sb, c0 = 0x2400; break; case '/': +#ifdef MY_ABC_HERE + if (convert) +#endif /* MY_ABC_HERE */ c0 = ':'; break; } @@ -227,6 +238,9 @@ int hfsplus_uni2asc(struct super_block *sb, cc = 0x2400; break; case '/': +#ifdef MY_ABC_HERE + if (convert) +#endif /* MY_ABC_HERE */ cc = ':'; break; default: @@ -248,13 +262,32 @@ int hfsplus_uni2asc(struct super_block *sb, *len_p = (char *)op - astr; return res; } +#ifdef MY_ABC_HERE +int hfsplus_uni2asc(struct super_block *sb, + const struct hfsplus_unistr *ustr, + char *astr, int *len_p) +{ + return _hfsplus_uni2asc(sb, ustr, astr, len_p, true); +} +int hfsplus_attr_uni2asc(struct super_block *sb, + const struct hfsplus_unistr *ustr, char *astr, + int *len_p) +{ + return _hfsplus_uni2asc(sb, ustr, astr, len_p, false); +} +#endif /* MY_ABC_HERE */ /* * Convert one or more ASCII characters into a single unicode character. * Returns the number of ASCII characters corresponding to the unicode char. */ +#ifdef MY_ABC_HERE +static inline int _asc2unichar(struct super_block *sb, const char *astr, + int len, wchar_t *uc, bool convert) +#else /* MY_ABC_HERE */ static inline int asc2unichar(struct super_block *sb, const char *astr, int len, wchar_t *uc) +#endif /* MY_ABC_HERE */ { int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc); if (size <= 0) { @@ -266,11 +299,21 @@ static inline int asc2unichar(struct super_block *sb, const char *astr, int len, *uc = 0; break; case ':': +#ifdef MY_ABC_HERE + if (convert) +#endif /* MY_ABC_HERE */ *uc = '/'; break; } return size; } +#ifdef MY_ABC_HERE +static inline int asc2unichar(struct super_block *sb, const char *astr, + int len, wchar_t *uc) +{ + return _asc2unichar(sb, astr, len, uc, true); +} +#endif /* MY_ABC_HERE */ /* Decomposes a non-Hangul unicode character. */ static u16 *hfsplus_decompose_nonhangul(wchar_t uc, int *size) @@ -343,7 +386,14 @@ static u16 *decompose_unichar(wchar_t uc, int *size, u16 *hangul_buffer) int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, int max_unistr_len, - const char *astr, int len) + const char *astr, int len +#ifdef MY_ABC_HERE + , bool convert +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + , bool nfc +#endif /* MY_ABC_HERE */ + ) { int size, dsize, decompose; u16 *dstr, outlen = 0; @@ -352,9 +402,17 @@ int hfsplus_asc2uni(struct super_block *sb, decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); while (outlen < max_unistr_len && len > 0) { +#ifdef MY_ABC_HERE + size = _asc2unichar(sb, astr, len, &c, convert); +#else /* MY_ABC_HERE */ size = asc2unichar(sb, astr, len, &c); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (decompose && !nfc) +#else if (decompose) +#endif /* MY_ABC_HERE */ dstr = decompose_unichar(c, &dsize, dhangul); else dstr = NULL; @@ -376,6 +434,30 @@ int hfsplus_asc2uni(struct super_block *sb, return 0; } +#ifdef MY_ABC_HERE +int hfsplus_attr_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, + int max_unistr_len, const char *astr, int len) +{ + return hfsplus_asc2uni(sb, ustr, max_unistr_len, astr, len, false +#ifdef MY_ABC_HERE + , false +#endif /* MY_ABC_HERE */ + ); +} +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int hfsplus_nfc_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, + int max_unistr_len, const char *astr, int len, + bool nfc) +{ + return hfsplus_asc2uni(sb, ustr, max_unistr_len, astr, len +#ifdef MY_ABC_HERE + , true +#endif /* MY_ABC_HERE */ + , nfc); +} +#endif /* MY_ABC_HERE */ + /* * Hash a string to an integer as appropriate for the HFS+ filesystem. * Composed unicode characters are decomposed and case-folding is performed diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index bb0b27d88e50..181fc868b6a0 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/hfsplus/xattr.c @@ -734,7 +737,11 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) goto end_listxattr; xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN; +#ifdef MY_ABC_HERE + if (hfsplus_attr_uni2asc(inode->i_sb, +#else /* MY_ABC_HERE */ if (hfsplus_uni2asc(inode->i_sb, +#endif /* MY_ABC_HERE */ (const struct hfsplus_unistr *)&fd.key->attr.key_name, strbuf, &xattr_name_len)) { pr_err("unicode conversion failed\n"); diff --git a/fs/inode.c b/fs/inode.c index 5eea9912a0b9..ab6fc7422dd7 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * (C) 1997 Linus Torvalds @@ -24,6 +27,11 @@ #include #include "internal.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + + /* * Inode locking rules: * @@ -176,6 +184,18 @@ int inode_init_always(struct super_block *sb, struct inode *inode) init_rwsem(&inode->i_rwsem); lockdep_set_class(&inode->i_rwsem, &sb->s_type->i_mutex_key); +#ifdef MY_ABC_HERE + inode->i_archive_bit = 0; /* set archive bit on creation */ + mutex_init(&inode->i_archive_bit_mutex); + lockdep_set_class(&inode->i_archive_bit_mutex, &sb->s_type->i_archive_bit_mutex_key); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + inode->i_archive_version = 0; + mutex_init(&inode->i_archive_version_mutex); + lockdep_set_class(&inode->i_archive_version_mutex, &sb->s_type->i_archive_version_mutex_key); +#endif /* MY_ABC_HERE */ + atomic_set(&inode->i_dio_count, 0); mapping->a_ops = &empty_aops; @@ -194,6 +214,9 @@ int inode_init_always(struct super_block *sb, struct inode *inode) inode->i_private = NULL; inode->i_mapping = mapping; INIT_HLIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */ +#ifdef MY_ABC_HERE + inode->i_syno_acl = ACL_NOT_CACHED; +#endif /* MY_ABC_HERE */ #ifdef CONFIG_FS_POSIX_ACL inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; #endif @@ -264,6 +287,10 @@ void __destroy_inode(struct inode *inode) atomic_long_dec(&inode->i_sb->s_remove_count); } +#ifdef MY_ABC_HERE + if (inode->i_syno_acl && !is_uncached_syno_acl(inode->i_syno_acl)) + syno_acl_release(inode->i_syno_acl); +#endif /* MY_ABC_HERE */ #ifdef CONFIG_FS_POSIX_ACL if (inode->i_acl && !is_uncached_acl(inode->i_acl)) posix_acl_release(inode->i_acl); @@ -415,6 +442,9 @@ void __iget(struct inode *inode) { atomic_inc(&inode->i_count); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(__iget); +#endif /* MY_ABC_HERE */ /* * get additional reference to inode; caller must already hold one. @@ -1718,6 +1748,9 @@ EXPORT_SYMBOL(bmap); static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, struct timespec64 now) { +#ifdef MY_ABC_HERE + long relatime_period = 1; +#endif /* MY_ABC_HERE */ if (!(mnt->mnt_flags & MNT_RELATIME)) return 1; @@ -1736,8 +1769,16 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, * Is the previous atime value older than a day? If yes, * update atime: */ +#ifdef MY_ABC_HERE + if (inode->i_sb->relatime_period > 0) + relatime_period = inode->i_sb->relatime_period; + + if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= relatime_period*24*60*60) + return 1; +#else /* MY_ABC_HERE */ if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60) return 1; +#endif /* MY_ABC_HERE */ /* * Good, we can skip the atime update: */ @@ -1772,12 +1813,19 @@ EXPORT_SYMBOL(generic_update_time); * This does the actual work of updating an inodes time or version. Must have * had called mnt_want_write() before calling this. */ +#ifdef MY_ABC_HERE +int update_time(struct inode *inode, struct timespec64 *time, int flags) +#else static int update_time(struct inode *inode, struct timespec64 *time, int flags) +#endif /* MY_ABC_HERE */ { if (inode->i_op->update_time) return inode->i_op->update_time(inode, time, flags); return generic_update_time(inode, time, flags); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(update_time); +#endif /* MY_ABC_HERE */ /** * touch_atime - update the access time diff --git a/fs/internal.h b/fs/internal.h index 5155f6ce95c7..db13a5fad9ce 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* fs/ internal definitions * @@ -107,6 +110,12 @@ extern void chroot_fs_refs(const struct path *, const struct path *); */ extern struct file *alloc_empty_file(int, const struct cred *); extern struct file *alloc_empty_file_noaccount(int, const struct cred *); +#ifdef MY_ABC_HERE +extern void file_sb_list_add(struct file *f); +extern void file_sb_list_del(struct file *f); +extern void fs_show_opened_file(struct mount *m, const char *mnt_point_name, + char *file_name_buf, int buflen); +#endif /* MY_ABC_HERE */ /* * super.c diff --git a/fs/io_uring.c b/fs/io_uring.c index 525b44140d7a..38802d116cd5 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1143,7 +1143,7 @@ static inline void __io_req_init_async(struct io_kiocb *req) */ static inline void io_req_init_async(struct io_kiocb *req) { - struct io_uring_task *tctx = current->io_uring; + struct io_uring_task *tctx = req->task->io_uring; if (req->flags & REQ_F_WORK_INITIALIZED) return; @@ -1541,6 +1541,7 @@ static void __io_queue_deferred(struct io_ring_ctx *ctx) static void io_flush_timeouts(struct io_ring_ctx *ctx) { + struct io_kiocb *req, *tmp; u32 seq; if (list_empty(&ctx->timeout_list)) @@ -1548,10 +1549,8 @@ static void io_flush_timeouts(struct io_ring_ctx *ctx) seq = ctx->cached_cq_tail - atomic_read(&ctx->cq_timeouts); - do { + list_for_each_entry_safe(req, tmp, &ctx->timeout_list, timeout.list) { u32 events_needed, events_got; - struct io_kiocb *req = list_first_entry(&ctx->timeout_list, - struct io_kiocb, timeout.list); if (io_is_timeout_noseq(req)) break; @@ -1568,9 +1567,8 @@ static void io_flush_timeouts(struct io_ring_ctx *ctx) if (events_got < events_needed) break; - list_del_init(&req->timeout.list); io_kill_timeout(req, 0); - } while (!list_empty(&ctx->timeout_list)); + } ctx->cq_last_tm_flush = seq; } @@ -5613,6 +5611,7 @@ static int io_timeout_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe, else data->mode = HRTIMER_MODE_REL; + INIT_LIST_HEAD(&req->timeout.list); hrtimer_init(&data->timer, CLOCK_MONOTONIC, data->mode); return 0; } @@ -6255,12 +6254,12 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer) if (!list_empty(&req->link_list)) { prev = list_entry(req->link_list.prev, struct io_kiocb, link_list); - if (refcount_inc_not_zero(&prev->refs)) - list_del_init(&req->link_list); - else + list_del_init(&req->link_list); + if (!refcount_inc_not_zero(&prev->refs)) prev = NULL; } + list_del(&req->timeout.list); spin_unlock_irqrestore(&ctx->completion_lock, flags); if (prev) { diff --git a/fs/ioctl.c b/fs/ioctl.c index 4e6cc0a7d69c..32a030e4a917 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ioctl.c @@ -19,6 +22,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "internal.h" @@ -114,6 +120,9 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, { struct fiemap_extent extent; struct fiemap_extent __user *dest = fieinfo->fi_extents_start; +#ifdef MY_ABC_HERE + struct fiemap_extent *kernel_dest = fieinfo->kernel_fi_extents_start; +#endif /* MY_ABC_HERE */ /* only count the extents */ if (fieinfo->fi_extents_max == 0) { @@ -137,9 +146,23 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, extent.fe_length = len; extent.fe_flags = flags; +#ifdef MY_ABC_HERE + if (dest) { + dest += fieinfo->fi_extents_mapped; + if (copy_to_user(dest, &extent, sizeof(extent))) + return -EFAULT; + } else if (kernel_dest) { + kernel_dest += fieinfo->fi_extents_mapped; + memcpy(kernel_dest, &extent, sizeof(extent)); + } else { + WARN_ON_ONCE(1); + return -EINVAL; + } +#else /* MY_ABC_HERE */ dest += fieinfo->fi_extents_mapped; if (copy_to_user(dest, &extent, sizeof(extent))) return -EFAULT; +#endif /* MY_ABC_HERE */ fieinfo->fi_extents_mapped++; if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max) @@ -224,8 +247,51 @@ static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) return error; } +#ifdef MY_ABC_HERE +int vfs_fiemap(struct file *filp, struct fiemap *fiemap) +{ + struct fiemap_extent_info fieinfo = { 0, }; + struct inode *inode = file_inode(filp); + int error; + + if (!inode->i_op->fiemap) + return -EOPNOTSUPP; + + if (fiemap->fm_extent_count > FIEMAP_MAX_EXTENTS) + return -EINVAL; + + fieinfo.fi_flags = fiemap->fm_flags; + fieinfo.fi_extents_max = fiemap->fm_extent_count; + fieinfo.kernel_fi_extents_start = fiemap->fm_extents; + + error = inode->i_op->fiemap(inode, &fieinfo, fiemap->fm_start, + fiemap->fm_length); + + fiemap->fm_flags = fieinfo.fi_flags; + fiemap->fm_mapped_extents = fieinfo.fi_extents_mapped; + + return error; +} +EXPORT_SYMBOL(vfs_fiemap); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static long __ioctl_file_clone(struct file *dst_file, unsigned long srcfd, + u64 off, u64 olen, u64 destoff, + unsigned int flags); + +static inline +long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, + u64 off, u64 olen, u64 destoff) { + return __ioctl_file_clone(dst_file, srcfd, off, olen, destoff, 0); +} +static long __ioctl_file_clone(struct file *dst_file, unsigned long srcfd, + u64 off, u64 olen, u64 destoff, + unsigned int flags) +#else /* MY_ABC_HERE */ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, u64 off, u64 olen, u64 destoff) +#endif /* MY_ABC_HERE */ { struct fd src_file = fdget(srcfd); loff_t cloned; @@ -236,8 +302,13 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, ret = -EXDEV; if (src_file.file->f_path.mnt != dst_file->f_path.mnt) goto fdput; +#ifdef MY_ABC_HERE + cloned = vfs_clone_file_range(src_file.file, off, dst_file, destoff, + olen, flags); +#else /* MY_ABC_HERE */ cloned = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen, 0); +#endif /* MY_ABC_HERE */ if (cloned < 0) ret = cloned; else if (olen && cloned != olen) @@ -253,11 +324,28 @@ static long ioctl_file_clone_range(struct file *file, struct file_clone_range __user *argp) { struct file_clone_range args; +#ifdef MY_ABC_HERE + unsigned int flags = 0; +#endif /* MY_ABC_HERE */ if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; +#ifdef MY_ABC_HERE + /* + * This is a workaround for DSM #81059. + * We allow to clone between compression and no compression dirs, + * if only we do IOC_CLONE_RANGE with whole file. + */ + if (!args.src_offset && !args.src_length && !args.dest_offset) + flags = REMAP_FILE_SKIP_CHECK_COMPR_DIR; + + return __ioctl_file_clone(file, args.src_fd, args.src_offset, + args.src_length, args.dest_offset, + flags); +#else /* MY_ABC_HERE */ return ioctl_file_clone(file, args.src_fd, args.src_offset, args.src_length, args.dest_offset); +#endif /* MY_ABC_HERE */ } #ifdef CONFIG_BLOCK @@ -657,6 +745,241 @@ static int ioctl_file_dedupe_range(struct file *file, return ret; } +#ifdef MY_ABC_HERE +static int archive_version_check_capable(struct inode *inode) +{ + if((!S_ISDIR(inode->i_mode)) && (!S_ISREG(inode->i_mode))) + return -EPERM; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!inode->i_sb->s_op->syno_set_sb_archive_version || + !inode->i_sb->s_op->syno_get_sb_archive_version) + return -EOPNOTSUPP; + + return 0; +} + +static int ioctl_get_sb_archive_version(struct inode *inode, int __user *argp) +{ + int ret; + unsigned int version; + struct super_block *sb = inode->i_sb; + + if ((ret = archive_version_check_capable(inode))) + return ret; + + ret = syno_op_get_sb_archive_version(sb, &version); + if (ret) + return ret; + + if (put_user(version, argp)) + return -EFAULT; + + return 0; +} + +static int ioctl_set_sb_archive_version(struct file *filp, int __user *argp) +{ + int ret; + unsigned int version; + struct inode *inode = filp->f_path.dentry->d_inode; + struct super_block *sb = inode->i_sb; + + if ((ret = archive_version_check_capable(inode))) + return ret; + + if ((ret = get_user(version, argp))) + return ret; + + if ((UINT_MAX - 1) <= version) { + return -EINVAL; + } + + if ((ret = mnt_want_write_file(filp))) + return ret; + + ret = syno_op_set_sb_archive_version(sb, version); + mnt_drop_write_file(filp); + + return ret; +} + +static int ioctl_inc_sb_archive_version(struct file *filp) +{ + int ret; + unsigned int version; + struct inode *inode = filp->f_path.dentry->d_inode; + struct super_block *sb = inode->i_sb; + + if ((ret = archive_version_check_capable(inode))) + return ret; + + if ((ret = mnt_want_write_file(filp))) + return ret; + + down_write(&sb->s_archive_version_rwsem); + ret = sb->s_op->syno_get_sb_archive_version(sb, &version); + if (ret) + goto unlock; + + // archive version of inode = archive version of sb + 1 + if ((UINT_MAX - 1) <= (version + 1)) { + ret = -EFAULT; + goto unlock; + } + ret = sb->s_op->syno_set_sb_archive_version(sb, version + 1); + +unlock: + up_write(&sb->s_archive_version_rwsem); + mnt_drop_write_file(filp); + return ret; +} + +static int ioctl_set_inode_archive_version(struct file *filp, int __user *argp) +{ + int ret; + unsigned int version; + struct inode *inode = filp->f_path.dentry->d_inode; + + if ((ret = archive_version_check_capable(inode))) + return ret; + + if ((ret = get_user(version, argp))) + return ret; + + if ((ret = mnt_want_write_file(filp))) + return ret; + + ret = syno_op_set_inode_archive_version(filp->f_path.dentry, version); + mnt_drop_write_file(filp); + + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int ioctl_syno_space_usage(struct file *filp, void __user *argp) +{ + int ret; + struct syno_space_usage_info info; + + if (copy_from_user(&info, argp, sizeof(info))) { + ret = -EFAULT; + goto out; + } + + ret = vfs_syno_space_usage(filp, &info); + if (ret) + goto out; + + if (copy_to_user(argp, &info, sizeof(info))) { + ret = -EFAULT; + goto out; + } + + ret = 0; +out: + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int syno_rbd_meta_file_mapping(struct inode *inode, size_t size, + struct syno_rbd_meta_ioctl_args __user *user) +{ + int ret; + struct syno_rbd_meta_ioctl_args *args; + + if (!inode->i_op->syno_rbd_meta_file_mapping) + return -EOPNOTSUPP; + + args = memdup_user(user, size); + if (IS_ERR(args)) + return PTR_ERR(args); + + ret = inode->i_op->syno_rbd_meta_file_mapping(inode, args); + if (ret) + goto out; + + if (copy_to_user(user, args, size)) { + ret = -EFAULT; + goto out; + } + ret = 0; +out: + kfree(args); + return ret; +} + +static int syno_rbd_meta_file_mapping_count(struct inode *inode, + struct syno_rbd_meta_ioctl_args __user * argp) +{ + int ret; + struct syno_rbd_meta_ioctl_args args; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + if (!inode->i_op->syno_rbd_meta_file_mapping) + return -EOPNOTSUPP; + + ret = inode->i_op->syno_rbd_meta_file_mapping(inode, &args); + if (ret) + goto out; + + if (copy_to_user(argp, &args, sizeof(args))) { + ret = -EFAULT; + goto out; + } + ret = 0; +out: + return ret; +} + +static int ioctl_syno_rbd_meta(struct file *filp, unsigned int __user *argp) +{ + struct syno_rbd_meta_ioctl_args stack; + struct inode *inode = file_inode(filp); + struct super_block *sb = inode->i_sb; + + if (copy_from_user(&stack, + (struct syno_rbd_meta_ioctl_args __user *) argp, + sizeof(stack))) + return -EFAULT; + + switch(stack.act) { + case SYNO_RBD_META_ACTIVATE: + if (inode->i_op->syno_rbd_meta_file_activate) + return inode->i_op->syno_rbd_meta_file_activate(inode); + return -EOPNOTSUPP; + case SYNO_RBD_META_DEACTIVATE: + if (inode->i_op->syno_rbd_meta_file_deactivate) + return inode->i_op->syno_rbd_meta_file_deactivate(inode); + return -EOPNOTSUPP; + case SYNO_RBD_META_SET_FIRST_OFFSET: + if (sb->s_op->syno_rbd_set_first_mapping_table_offset) + return sb->s_op->syno_rbd_set_first_mapping_table_offset( + sb, stack.first_offset); + return -EOPNOTSUPP; + case SYNO_RBD_META_MAPPING: + return syno_rbd_meta_file_mapping(inode, stack.size, + (struct syno_rbd_meta_ioctl_args __user *) argp); + case SYNO_RBD_META_MAPPING_COUNT: + return syno_rbd_meta_file_mapping_count(inode, + (struct syno_rbd_meta_ioctl_args __user *) argp); + case SYNO_RBD_META_CLEANUP_ALL: + if (sb->s_op->syno_rbd_meta_file_cleanup_all) + return sb->s_op->syno_rbd_meta_file_cleanup_all(inode); + return -EOPNOTSUPP; + default: + break; + } + return -EINVAL; +} +#endif /* MY_ABC_HERE */ + /* * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. * It's just a simple helper for sys_ioctl and compat_sys_ioctl. @@ -716,6 +1039,10 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, case FICLONERANGE: return ioctl_file_clone_range(filp, argp); +#ifdef MY_ABC_HERE + case FICTRRBDMETA: + return ioctl_syno_rbd_meta(filp, argp); +#endif /* MY_ABC_HERE */ case FIDEDUPERANGE: return ioctl_file_dedupe_range(filp, argp); @@ -727,6 +1054,22 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, return put_user(i_size_read(inode) - filp->f_pos, (int __user *)argp); +#ifdef MY_ABC_HERE + case FIGETVERSION: + return ioctl_get_sb_archive_version(inode, argp); + case FISETVERSION: + return ioctl_set_sb_archive_version(filp, argp); + case FIINCVERSION: + return ioctl_inc_sb_archive_version(filp); + case FISETFILEVERSION: + return ioctl_set_inode_archive_version(filp, argp); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + case FISPACEUSAGE: + return ioctl_syno_space_usage(filp, argp); +#endif /* MY_ABC_HERE */ + default: if (S_ISREG(inode->i_mode)) return file_ioctl(filp, cmd, argp); @@ -738,8 +1081,17 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { +#ifdef MY_ABC_HERE + int error; + struct fd f; + if (cmd == FS_IOC_GETFLAGS || cmd == FS_IOC_SETFLAGS) + f = fdget_raw(fd); + else + f = fdget(fd); +#else /* MY_ABC_HERE */ struct fd f = fdget(fd); int error; +#endif /* MY_ABC_HERE */ if (!f.file) return -EBADF; diff --git a/fs/iomap/fiemap.c b/fs/iomap/fiemap.c index aab070df4a21..7f6601082f0f 100644 --- a/fs/iomap/fiemap.c +++ b/fs/iomap/fiemap.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2018 Christoph Hellwig. @@ -11,10 +14,52 @@ struct fiemap_ctx { struct fiemap_extent_info *fi; struct iomap prev; +#ifdef MY_ABC_HERE + struct syno_rbd_meta_ioctl_args *rbd_meta; +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +#define VALID_FIEMAP_FLAG_ON_RBD_META (FIEMAP_EXTENT_UNWRITTEN | \ + FIEMAP_EXTENT_LAST) + +static int rbd_meta_fill_next_extent(struct syno_rbd_meta_ioctl_args *args, + u64 next_start, u64 phys, u64 len, + u32 flags) +{ + unsigned int idx = args->cnt; + unsigned int max_cnt; + + if (flags & ~(VALID_FIEMAP_FLAG_ON_RBD_META)) { + printk(KERN_WARNING + "rbd meta with invalid fiemap flag %u\n", flags); + return -EINVAL; + } + + if (args->act == SYNO_RBD_META_MAPPING) { + max_cnt = (args->size - sizeof(struct syno_rbd_meta_ioctl_args)) / + sizeof(struct syno_rbd_meta_file_mapping); + if ((idx + 1) > max_cnt) + return 1; + args->mappings[idx].length = len; + args->mappings[idx].dev_offset = phys; + } + + if (flags & FIEMAP_EXTENT_LAST) + args->start = (u64) -1; + else + args->start = next_start; + args->cnt++; + return 0; +} +#endif /* MY_ABC_HERE */ + static int iomap_to_fiemap(struct fiemap_extent_info *fi, - struct iomap *iomap, u32 flags) + struct iomap *iomap, u32 flags +#ifdef MY_ABC_HERE + , struct syno_rbd_meta_ioctl_args *rbd_meta +#endif /* MY_ABC_HERE */ + ) { switch (iomap->type) { case IOMAP_HOLE: @@ -38,6 +83,15 @@ static int iomap_to_fiemap(struct fiemap_extent_info *fi, if (iomap->flags & IOMAP_F_SHARED) flags |= FIEMAP_EXTENT_SHARED; +#ifdef MY_ABC_HERE + if (!fi && !rbd_meta) + return -EINVAL; + else if (rbd_meta) + return rbd_meta_fill_next_extent(rbd_meta, + iomap->offset + iomap->length, + iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0, + iomap->length, flags); +#endif /* MY_ABC_HERE */ return fiemap_fill_next_extent(fi, iomap->offset, iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0, iomap->length, flags); @@ -53,7 +107,11 @@ iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, if (iomap->type == IOMAP_HOLE) return length; - ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); + ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0 +#ifdef MY_ABC_HERE + , ctx->rbd_meta +#endif /* MY_ABC_HERE */ + ); ctx->prev = *iomap; switch (ret) { case 0: /* success */ @@ -74,6 +132,9 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, memset(&ctx, 0, sizeof(ctx)); ctx.fi = fi; ctx.prev.type = IOMAP_HOLE; +#ifdef MY_ABC_HERE + ctx.rbd_meta = NULL; +#endif /* MY_ABC_HERE */ ret = fiemap_prep(inode, fi, start, &len, 0); if (ret) @@ -95,7 +156,11 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, } if (ctx.prev.type != IOMAP_HOLE) { - ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); + ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST +#ifdef MY_ABC_HERE + , NULL +#endif /* MY_ABC_HERE */ + ); if (ret < 0) return ret; } @@ -138,3 +203,61 @@ iomap_bmap(struct address_space *mapping, sector_t bno, return bno; } EXPORT_SYMBOL_GPL(iomap_bmap); + +#ifdef MY_ABC_HERE +static int rbd_meta_map_prep(struct inode *inode, + struct syno_rbd_meta_ioctl_args *rbd_meta, + u64 start, u64 *len) +{ + u64 maxbytes = inode->i_sb->s_maxbytes; + + if (*len == 0 || start == (u64)-1) + return -EINVAL; + if (start > maxbytes) + return -EFBIG; + if (*len > maxbytes || (maxbytes - *len) < start) + *len = maxbytes - start; + + return filemap_write_and_wait(inode->i_mapping); +} + +int iomap_rbd_meta_map(struct inode *inode, struct syno_rbd_meta_ioctl_args *rbd_meta, + u64 start, u64 len, const struct iomap_ops *ops) +{ + struct fiemap_ctx ctx; + loff_t ret; + + memset(&ctx, 0, sizeof(ctx)); + ctx.fi = NULL; + ctx.rbd_meta = rbd_meta; + ctx.prev.type = IOMAP_HOLE; + + ret = rbd_meta_map_prep(inode, rbd_meta, start, &len); + if (ret) + return ret; + + while (len > 0) { + ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx, + iomap_fiemap_actor); + /* inode with no (attribute) mapping will give ENOENT */ + if (ret == -ENOENT) + break; + if (ret < 0) + return ret; + if (ret == 0) + break; + + start += ret; + len -= ret; + } + + if (ctx.prev.type != IOMAP_HOLE) { + ret = iomap_to_fiemap(NULL, &ctx.prev, FIEMAP_EXTENT_LAST, rbd_meta); + if (ret < 0) + return ret; + } + + return 0; +} +#endif /* MY_ABC_HERE */ + diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index ec90773527ee..21edc423b79f 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -339,6 +339,7 @@ static int parse_options(char *options, struct iso9660_options *popt) { char *p; int option; + unsigned int uv; popt->map = 'n'; popt->rock = 1; @@ -434,17 +435,17 @@ static int parse_options(char *options, struct iso9660_options *popt) case Opt_ignore: break; case Opt_uid: - if (match_int(&args[0], &option)) + if (match_uint(&args[0], &uv)) return 0; - popt->uid = make_kuid(current_user_ns(), option); + popt->uid = make_kuid(current_user_ns(), uv); if (!uid_valid(popt->uid)) return 0; popt->uid_set = 1; break; case Opt_gid: - if (match_int(&args[0], &option)) + if (match_uint(&args[0], &uv)) return 0; - popt->gid = make_kgid(current_user_ns(), option); + popt->gid = make_kgid(current_user_ns(), uv); if (!gid_valid(popt->gid)) return 0; popt->gid_set = 1; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1a639e34847d..f5705dad8dce 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/lockd/svc.c @@ -770,28 +773,46 @@ module_exit(exit_nlm); * Define NLM program and procedures */ static unsigned int nlmsvc_version1_count[17]; +#ifdef MY_ABC_HERE +static struct svc_lat nlmsvc_version1_latency[17]; +#endif /* MY_ABC_HERE */ static const struct svc_version nlmsvc_version1 = { .vs_vers = 1, .vs_nproc = 17, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version1_count, +#ifdef MY_ABC_HERE + .vs_latency = nlmsvc_version1_latency, +#endif /* MY_ABC_HERE */ .vs_xdrsize = NLMSVC_XDRSIZE, }; static unsigned int nlmsvc_version3_count[24]; +#ifdef MY_ABC_HERE +static struct svc_lat nlmsvc_version3_latency[24]; +#endif /* MY_ABC_HERE */ static const struct svc_version nlmsvc_version3 = { .vs_vers = 3, .vs_nproc = 24, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version3_count, +#ifdef MY_ABC_HERE + .vs_latency = nlmsvc_version3_latency, +#endif /* MY_ABC_HERE */ .vs_xdrsize = NLMSVC_XDRSIZE, }; #ifdef CONFIG_LOCKD_V4 static unsigned int nlmsvc_version4_count[24]; +#ifdef MY_ABC_HERE +static struct svc_lat nlmsvc_version4_latency[24]; +#endif /* MY_ABC_HERE */ static const struct svc_version nlmsvc_version4 = { .vs_vers = 4, .vs_nproc = 24, .vs_proc = nlmsvc_procedures4, .vs_count = nlmsvc_version4_count, +#ifdef MY_ABC_HERE + .vs_latency = nlmsvc_version4_latency, +#endif /* MY_ABC_HERE */ .vs_xdrsize = NLMSVC_XDRSIZE, }; #endif diff --git a/fs/mount.h b/fs/mount.h index c7abb7b394d8..e77fb607b276 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #include #include @@ -73,6 +76,10 @@ struct mount { struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks; __u32 mnt_fsnotify_mask; #endif +#ifdef MY_ABC_HERE + struct fsnotify_mark_connector __rcu *mnt_fsnotify_syno_marks; + __u32 mnt_fsnotify_syno_mask; +#endif /* MY_ABC_HERE */ int mnt_id; /* mount identifier */ int mnt_group_id; /* peer group identifier */ int mnt_expiry_mark; /* true if marked for expiry */ diff --git a/fs/namei.c b/fs/namei.c index 4c9d0c36545d..bf8cad868a20 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/namei.c @@ -40,8 +43,19 @@ #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif #include "internal.h" #include "mount.h" +#ifdef MY_ABC_HERE +extern struct rw_semaphore namespace_sem; +static DEFINE_RATELIMIT_STATE(_namei_rs, (3600 * HZ), 1); +#endif /* MY_ABC_HERE */ /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) @@ -122,6 +136,299 @@ * PATH_MAX includes the nul terminator --RR. */ +#ifdef MY_ABC_HERE +int syno_utf8chr_to_utf16chr(u_int16_t *p, const u_int8_t *s, int n); +int syno_utf16chr_to_utf8chr(u_int8_t *s, u_int16_t wc, int maxlen); +u_int16_t *syno_generate_default_upcase_table(void); +u_int16_t *def_upcase_table(void); + + +/* + * Sample implementation from Unicode home page. + * http://www.stonehand.com/unicode/standard/fss-utf.html + */ +struct utf8_table { + int cmask; + int cval; + int shift; + long lmask; + long lval; +}; + +static struct utf8_table utf8_table[] = +{ + {0x80, 0x00, 0*6, 0x7F, 0, /* 1 byte sequence */}, + {0xE0, 0xC0, 1*6, 0x7FF, 0x80, /* 2 byte sequence */}, + {0xF0, 0xE0, 2*6, 0xFFFF, 0x800, /* 3 byte sequence */}, + {0xF8, 0xF0, 3*6, 0x1FFFFF, 0x10000, /* 4 byte sequence */}, + {0xFC, 0xF8, 4*6, 0x3FFFFFF, 0x200000, /* 5 byte sequence */}, + {0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */}, + {0, /* end of table */} +}; + +int syno_utf8chr_to_utf16chr(u_int16_t *p, const u_int8_t *s, int n) +{ + long l; + int c0, c, nc; + struct utf8_table *t; + + nc = 0; + c0 = *s; + l = c0; + for (t = utf8_table; t->cmask; t++) { + nc++; + if ((c0 & t->cmask) == t->cval) { + l &= t->lmask; + if (l < t->lval) + return -1; + *p = l; + return nc; + } + if (n <= nc) + return -1; + s++; + c = (*s ^ 0x80) & 0xFF; + if (c & 0xC0) + return -1; + l = (l << 6) | c; + } + return -1; +} + +int syno_utf16chr_to_utf8chr(u_int8_t *s, u_int16_t wc, int maxlen) +{ + long l; + int c, nc; + struct utf8_table *t; + + if (s == 0) + return 0; + + l = wc; + nc = 0; + for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) { + nc++; + if (l <= t->lmask) { + c = t->shift; + *s = t->cval | (l >> c); + while (c > 0) { + c -= 6; + if (c < 0) { + return -1; + } + s++; + *s = 0x80 | ((l >> c) & 0x3F); + } + return nc; + } + } + return -1; +} + + +/* + * upcase.c - Generate the full NTFS Unicode upcase table in little endian. + * Part of the Linux-NTFS project. + * + * Copyright (C) 2001 Richard Russon + * Copyright (c) 2001,2002 Anton Altaparmakov + * + * Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov. + * Modified for kernel inclusion 10 September 2001 by Anton Altparmakov. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS source + * in the file COPYING); if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +static u_int16_t gUC[UTF16_UPCASE_TABLE_SIZE]; + +void upcase_table_icu_fix(void) { + int r = 0; + u_int16_t *uc = gUC; + + /* This is the difference part from Unicode Uppercase Table generated by ICU + * Since samba/netatalk will call SetToCaseless() and override the default + * Uppercase Table in kernel. It's batter eliminate those conflict as early + * as possible. + */ + static const int uc_icu_table[][2] = /* Offset, Value */ + { + {0x00B5, 0x039C}, {0x0131, 0x0049}, {0x017F, 0x0053}, {0x0195, 0x01F6}, + {0x019E, 0x0220}, {0x01BF, 0x01F7}, {0x01C5, 0x01C4}, {0x01C8, 0x01C7}, + {0x01CB, 0x01CA}, {0x01F2, 0x01F1}, {0x01F9, 0x01F8}, {0x0219, 0x0218}, + {0x021B, 0x021A}, {0x021D, 0x021C}, {0x021F, 0x021E}, {0x0223, 0x0222}, + {0x0225, 0x0224}, {0x0227, 0x0226}, {0x0229, 0x0228}, {0x022B, 0x022A}, + {0x022D, 0x022C}, {0x022F, 0x022E}, {0x0231, 0x0230}, {0x0233, 0x0232}, + {0x0280, 0x01A6}, {0x0345, 0x0399}, {0x03D0, 0x0392}, {0x03D1, 0x0398}, + {0x03D5, 0x03A6}, {0x03D6, 0x03A0}, {0x03D9, 0x03D8}, {0x03DB, 0x03DA}, + {0x03DD, 0x03DC}, {0x03DF, 0x03DE}, {0x03E1, 0x03E0}, {0x03F0, 0x039A}, + {0x03F1, 0x03A1}, {0x03F2, 0x03A3}, {0x03F5, 0x0395}, {0x0450, 0x0400}, + {0x045D, 0x040D}, {0x048B, 0x048A}, {0x048D, 0x048C}, {0x048F, 0x048E}, + {0x04C6, 0x04C5}, {0x04CA, 0x04C9}, {0x04CE, 0x04CD}, {0x04ED, 0x04EC}, + {0x0501, 0x0500}, {0x0503, 0x0502}, {0x0505, 0x0504}, {0x0507, 0x0506}, + {0x0509, 0x0508}, {0x050B, 0x050A}, {0x050D, 0x050C}, {0x050F, 0x050E}, + {0x1E9B, 0x1E60}, {0x1FBE, 0x0399}, + {0} + }; + + for (r = 0; uc_icu_table[r][0]; r++) + uc[uc_icu_table[r][0]] = uc_icu_table[r][1]; +} + +u_int16_t *syno_generate_default_upcase_table(void) +{ + const int uc_run_table[][3] = { /* Start, End, Add */ + {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, + {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, + {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, + {0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128}, + {0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112}, + {0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126}, + {0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8}, + {0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8}, + {0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8}, + {0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7}, + {0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16}, + {0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26}, + {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, + {0} + }; + + const int uc_dup_table[][2] = { /* Start, End */ + {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, + {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, + {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, + {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, + {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, + {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, + {0} + }; + + const int uc_word_table[][2] = { /* Offset, Value */ + {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, + {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, + {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, + {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, + {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, + {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, + {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, + {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, + {0} + }; + + int i, r; + u_int16_t *uc; + + uc = gUC; + + memset(uc, 0, UTF16_UPCASE_TABLE_SIZE * sizeof(u_int16_t)); + + for (i = 0; i < UTF16_UPCASE_TABLE_SIZE; i++) + uc[i] = i; + for (r = 0; uc_run_table[r][0]; r++) + for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) + uc[i] = uc[i] + uc_run_table[r][2]; + for (r = 0; uc_dup_table[r][0]; r++) + for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) + uc[i + 1] = uc[i + 1] - 1; + for (r = 0; uc_word_table[r][0]; r++) + uc[uc_word_table[r][0]] = uc_word_table[r][1]; + upcase_table_icu_fix(); + return uc; +} + + +static u_int16_t *upcase_table = NULL; + +u_int16_t *def_upcase_table(void) +{ + if(upcase_table==NULL) + upcase_table = syno_generate_default_upcase_table(); + + return upcase_table; +} + +int syno_utf8_toupper(u_int8_t *to,const u_int8_t *from, int maxlen, int clenfrom, u_int16_t *upcasetable) +{ + u_int16_t *upcase_tbl; + u_int16_t wc; + u_int8_t *op; + int size; + + upcase_tbl = (upcasetable==NULL) ? def_upcase_table() : upcasetable; + + op = to; + while (clenfrom && maxlen) { + size = syno_utf8chr_to_utf16chr(&wc, from, clenfrom); + if (size == -1) { + from++; + clenfrom--; + continue; + } else { + from += size; + clenfrom -= size; + } + size = syno_utf16chr_to_utf8chr(op, upcase_tbl[wc], maxlen); + if (size == -1) { + continue; + } else { + op += size; + maxlen -= size; + } + } + *op = 0; + return (op - to); +} +EXPORT_SYMBOL(syno_utf8_toupper); + +int syno_utf8_strcmp(const u_int8_t *utf8str1,const u_int8_t *utf8str2,int len_utf8_str1, int len_utf8_str2, u_int16_t *upcasetable) +{ + u_int16_t *upcase_tbl; + u_int16_t wc1, wc2; + int size1, size2; + int result = -1; + + upcase_tbl = (upcasetable==NULL) ? def_upcase_table() : upcasetable; + + while (len_utf8_str1 && len_utf8_str2) { + size1 = syno_utf8chr_to_utf16chr(&wc1, utf8str1, len_utf8_str1); + size2 = syno_utf8chr_to_utf16chr(&wc2, utf8str2, len_utf8_str2); + + if (size1 != -1 && size2 != -1) { + if (upcase_tbl[wc1] != upcase_tbl[wc2]) + goto END; + } else if (size1 == -1 && size2 == -1) { + if (*utf8str1 != *utf8str2) + goto END; + size1 = size2 = 1; + } else { + goto END; + } + utf8str1 += size1; + len_utf8_str1 -= size1; + utf8str2 += size2; + len_utf8_str2 -= size2; + } + if (len_utf8_str1 == 0 && len_utf8_str2 == 0) + result = 0; +END: + return result; +} +EXPORT_SYMBOL(syno_utf8_strcmp); +#endif /* MY_ABC_HERE */ + #define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname)) struct filename * @@ -521,6 +828,12 @@ struct nameidata { int dfd; kuid_t dir_uid; umode_t dir_mode; +#ifdef MY_ABC_HERE + unsigned char *real_filename; + unsigned char *real_filename_cur_locate; + unsigned int real_filename_len; + struct path caseless_path; +#endif /* MY_ABC_HERE */ } __randomize_layout; static void set_nameidata(struct nameidata *p, int dfd, struct filename *name) @@ -590,6 +903,10 @@ static void terminate_walk(struct nameidata *nd) drop_links(nd); if (!(nd->flags & LOOKUP_RCU)) { int i; +#ifdef MY_ABC_HERE + nd->caseless_path.dentry = NULL; + nd->caseless_path.mnt = NULL; +#endif /* MY_ABC_HERE */ path_put(&nd->path); for (i = 0; i < nd->depth; i++) path_put(&nd->stack[i].link); @@ -989,8 +1306,15 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod * * Otherwise returns true. */ +#ifdef MY_ABC_HERE +static bool safe_hardlink_source(struct dentry *dentry) +#else /* MY_ABC_HERE */ static bool safe_hardlink_source(struct inode *inode) +#endif /* MY_ABC_HERE */ { +#ifdef MY_ABC_HERE + struct inode *inode = d_inode(dentry); +#endif umode_t mode = inode->i_mode; /* Special files should not get pinned to the filesystem. */ @@ -1006,6 +1330,12 @@ static bool safe_hardlink_source(struct inode *inode) return false; /* Hardlinking to unreadable or unwritable sources is dangerous. */ +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + if (synoacl_op_permission(dentry, MAY_READ | MAY_WRITE)) + return false; + } else +#endif /* MY_ABC_HERE */ if (inode_permission(inode, MAY_READ | MAY_WRITE)) return false; @@ -1038,8 +1368,13 @@ int may_linkat(struct path *link) /* Source inode owner (or CAP_FOWNER) can hardlink all they like, * otherwise, it must be a safe source. */ +#ifdef MY_ABC_HERE + if (safe_hardlink_source(link->dentry) || inode_owner_or_capable(inode)) + return 0; +#else /* MY_ABC_HERE */ if (safe_hardlink_source(inode) || inode_owner_or_capable(inode)) return 0; +#endif /* MY_ABC_HERE */ audit_log_path_denied(AUDIT_ANOM_LINK, "linkat"); return -EPERM; @@ -1348,6 +1683,14 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, * becoming unpinned. */ flags = dentry->d_flags; +#ifdef MY_ABC_HERE + /* + * We don't care about m_seq because when m_seq + * mismatch it will always switch to ref-walk mode + * and re-walk full path. + */ + nd->flags |= LOOKUP_MOUNTED; +#endif /* MY_ABC_HERE */ continue; } if (read_seqretry(&mount_lock, nd->m_seq)) @@ -1384,6 +1727,9 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, ret = -EXDEV; else nd->flags |= LOOKUP_JUMPED; +#ifdef MY_ABC_HERE + nd->flags |= LOOKUP_MOUNTED; +#endif /* MY_ABC_HERE */ } if (unlikely(ret)) { dput(path->dentry); @@ -1456,6 +1802,9 @@ static struct dentry *lookup_fast(struct nameidata *nd, { struct dentry *dentry, *parent = nd->path.dentry; int status = 1; +#ifdef MY_ABC_HERE + int caseless = (LOOKUP_CASELESS_COMPARE & nd->flags) ? 1 : 0; +#endif /* MY_ABC_HERE */ /* * Rename seqlock is not required here because in the off chance @@ -1464,7 +1813,14 @@ static struct dentry *lookup_fast(struct nameidata *nd, */ if (nd->flags & LOOKUP_RCU) { unsigned seq; +#ifdef MY_ABC_HERE + dentry = __d_lookup_rcu(parent, &nd->last, &seq, caseless); + // down grade to ref-mode. + if (unlikely(caseless) && dentry && unlikely(!dentry->d_inode)) + return ERR_PTR(-ECHILD); +#else /* MY_ABC_HERE */ dentry = __d_lookup_rcu(parent, &nd->last, &seq); +#endif /* MY_ABC_HERE */ if (unlikely(!dentry)) { if (!try_to_unlazy(nd)) return ERR_PTR(-ECHILD); @@ -1499,7 +1855,16 @@ static struct dentry *lookup_fast(struct nameidata *nd, /* we'd been told to redo it in non-rcu mode */ status = d_revalidate(dentry, nd->flags); } else { +#ifdef MY_ABC_HERE + dentry = __d_lookup(parent, &nd->last, caseless); + if (caseless && dentry && !dentry->d_inode) { + d_invalidate(dentry); + dput(dentry); + dentry = NULL; + } +#else /* MY_ABC_HERE */ dentry = __d_lookup(parent, &nd->last); +#endif /* MY_ABC_HERE */ if (unlikely(!dentry)) return NULL; status = d_revalidate(dentry, nd->flags); @@ -1526,7 +1891,12 @@ static struct dentry *__lookup_slow(const struct qstr *name, if (unlikely(IS_DEADDIR(inode))) return ERR_PTR(-ENOENT); again: +#ifdef MY_ABC_HERE + dentry = d_alloc_parallel_case(dir, name, &wq, + (LOOKUP_CASELESS_COMPARE & flags) ? 1 : 0); +#else /* MY_ABC_HERE */ dentry = d_alloc_parallel(dir, name, &wq); +#endif /* MY_ABC_HERE */ if (IS_ERR(dentry)) return dentry; if (unlikely(!d_in_lookup(dentry))) { @@ -1566,10 +1936,29 @@ static struct dentry *lookup_slow(const struct qstr *name, static inline int may_lookup(struct nameidata *nd) { if (nd->flags & LOOKUP_RCU) { +#ifdef MY_ABC_HERE + int err; + /* + * 1. nd->path.dentry->d_inode may be changed in RCU-walk, use nd->inode for instead. + * 2. we are only allowed to use RCU walk when checking inode acl will NOT BLOCK and + * inode acl is NOT supported. + */ + if (!IS_FS_SYNOACL(nd->inode) || (0 == (err = IS_INODE_SYNOACL_NOBLOCK(nd->inode, nd->path.dentry)))) + err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); + else if (err == 1) + err = -ECHILD; +#else /* MY_ABC_HERE */ int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); +#endif /* MY_ABC_HERE */ if (err != -ECHILD || !try_to_unlazy(nd)) return err; } + +#ifdef MY_ABC_HERE + if (IS_SYNOACL(nd->path.dentry)) + return synoacl_op_exec_permission(nd->path.dentry, nd->inode); +#endif /* MY_ABC_HERE */ + return inode_permission(nd->inode, MAY_EXEC); } @@ -1687,6 +2076,12 @@ static const char *step_into(struct nameidata *nd, int flags, if (err < 0) return ERR_PTR(err); + +#ifdef MY_ABC_HERE + if (nd->flags & LOOKUP_CASELESS_COMPARE) + nd->caseless_path = path; +#endif /* MY_ABC_HERE */ + if (likely(!d_is_symlink(path.dentry)) || ((flags & WALK_TRAILING) && !(nd->flags & LOOKUP_FOLLOW)) || (flags & WALK_NOFOLLOW)) { @@ -1834,6 +2229,70 @@ static const char *handle_dots(struct nameidata *nd, int type) return NULL; } +#ifdef MY_ABC_HERE +static inline int update_real_filename(struct nameidata *nd, + const char *target_name, + const int target_len) +{ + if (unlikely(!nd->real_filename_cur_locate)) { + WARN_ON_ONCE(1); + return -EINVAL; + } + + if ((nd->real_filename_len + target_len + 2) >= SYNO_SMB_PSTRING_LEN) + return -ENAMETOOLONG; + + memcpy(nd->real_filename_cur_locate, target_name, target_len); + nd->real_filename_cur_locate += target_len; + nd->real_filename_len += target_len; + if (!(nd->flags & LOOKUP_TO_LASTCOMPONENT)) { + *(nd->real_filename_cur_locate) = '/'; + nd->real_filename_cur_locate++; + nd->real_filename_len++; + } + *(nd->real_filename_cur_locate) = '\0'; + /* + * Need to update '\0' to end of char*, + * because caseless path byte maybe less than user path. + * Example : 0x1FBE == 0x0399 + * in UTF-8 0x1FBE need 3 byte, but 0x0399 only need to 2 byte. + */ + if (nd->flags & LOOKUP_TO_LASTCOMPONENT) { + nd->real_filename_cur_locate++; + nd->real_filename_len++; + } + return 0; +} +static inline int update_path_to_real_filename(struct nameidata *nd) +{ + int target_len = 0; + const char *target_name = NULL; + struct mount *mnt = NULL; + + if (LAST_ROOT == nd->last_type + || LAST_DOTDOT == nd->last_type + || LAST_DOT == nd->last_type) + return 0; + + if (unlikely(!nd->caseless_path.mnt || !nd->caseless_path.dentry)) { + WARN_ON_ONCE(1); + return -EINVAL; + } + + if (nd->flags & LOOKUP_MOUNTED) { + nd->flags &= ~LOOKUP_MOUNTED; + mnt = real_mount(nd->caseless_path.mnt); + target_name = mnt->mnt_mountpoint->d_name.name; + target_len = mnt->mnt_mountpoint->d_name.len; + } else { + target_name = nd->caseless_path.dentry->d_name.name; + target_len = nd->caseless_path.dentry->d_name.len; + } + + return update_real_filename(nd, target_name, target_len); +} +#endif /* MY_ABC_HERE */ + static const char *walk_component(struct nameidata *nd, int flags) { struct dentry *dentry; @@ -2102,13 +2561,45 @@ static int link_path_walk(const char *name, struct nameidata *nd) { int depth = 0; // depth <= nd->depth int err; +#ifdef MY_ABC_HERE + int caseless_flag = (LOOKUP_CASELESS_COMPARE == + ((LOOKUP_CASELESS_COMPARE | LOOKUP_TO_LASTCOMPONENT) & nd->flags)); + +#endif /* MY_ABC_HERE */ nd->last_type = LAST_ROOT; nd->flags |= LOOKUP_PARENT; if (IS_ERR(name)) return PTR_ERR(name); + +#ifdef MY_ABC_HERE + /* We do case conversions here. + * The filename converted will be stored in nd->real_filename. + * + * In ext3_find_entry (ext3_dx_find_entry and search_dirblock), + * we sync file name of dentry stored in dentry queue with filename founded from disk. + * So the filename of dentry returned by do_lookup is case converted. + * + * Note: + * 1. If stat success, it will be copied to user space. + * It means if any error occurs, we don't need store anything in nd->real_filename. + * 2. We should correctly update "name" and "slashes" to "cur_location" each loop. + * We update them in every "continue", "break", "return" point. + * 3. If converted string longer than SYNO_SMB_PSTRING_LEN, we should return ENAMETOOLONG. + * We use total_len to monitor it. + */ + while (*name=='/') { + if (caseless_flag) { + err = update_real_filename(nd, "", 0); + if (err) + return err; + } + name++; + } +#else /* MY_ABC_HERE */ while (*name=='/') name++; +#endif /* MY_ABC_HERE */ if (!*name) return 0; @@ -2117,6 +2608,16 @@ static int link_path_walk(const char *name, struct nameidata *nd) const char *link; u64 hash_len; int type; +#ifdef MY_ABC_HERE + int slash_count = 0; + /* + * We only update user path case, not update symbolic link path, + * so if current name is symbolic link path, we not update path case. + */ + bool in_link = !!depth; + + nd->flags &= ~LOOKUP_MOUNTED; +#endif /* MY_ABC_HERE */ err = may_lookup(nd); if (err) @@ -2153,6 +2654,16 @@ static int link_path_walk(const char *name, struct nameidata *nd) nd->last_type = type; name += hashlen_len(hash_len); + +#ifdef MY_ABC_HERE + if (caseless_flag && (LAST_DOTDOT == type || LAST_DOT == type) && !in_link) { + err = update_real_filename(nd, nd->last.name, + hashlen_len(nd->last.hash_len)); + if (err) + return err; + } +#endif /* MY_ABC_HERE */ + if (!*name) goto OK; /* @@ -2161,6 +2672,12 @@ static int link_path_walk(const char *name, struct nameidata *nd) */ do { name++; +#ifdef MY_ABC_HERE + slash_count++; + /* We will count one more slash because there will be one slash + * added in walk_component. Substract it back later. + */ +#endif /* MY_ABC_HERE */ } while (unlikely(*name == '/')); if (unlikely(!*name)) { OK: @@ -2169,6 +2686,10 @@ static int link_path_walk(const char *name, struct nameidata *nd) nd->dir_uid = nd->inode->i_uid; nd->dir_mode = nd->inode->i_mode; nd->flags &= ~LOOKUP_PARENT; +#ifdef MY_ABC_HERE + if (caseless_flag) + nd->flags |= LOOKUP_TO_LASTCOMPONENT; +#endif /* MY_ABC_HERE */ return 0; } /* last component of nested symlink */ @@ -2178,6 +2699,25 @@ static int link_path_walk(const char *name, struct nameidata *nd) /* not the last component */ link = walk_component(nd, WALK_MORE); } + +#ifdef MY_ABC_HERE + if (unlikely(link && IS_ERR(link))) + return PTR_ERR(link); + + if (caseless_flag && !in_link) { + err = update_path_to_real_filename(nd); + if (err) + return err; + slash_count--; // Here we are to substract one slash. + while (slash_count > 0) { + err = update_real_filename(nd, "", 0); + if (err) + return err; + slash_count--; + } + } +#endif /* MY_ABC_HERE */ + if (unlikely(link)) { if (IS_ERR(link)) return PTR_ERR(link); @@ -2214,6 +2754,15 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->r_seq = __read_seqcount_begin(&rename_lock.seqcount); smp_rmb(); +#ifdef MY_ABC_HERE + if (flags & LOOKUP_CASELESS_COMPARE) { + nd->real_filename_cur_locate = nd->real_filename; + nd->real_filename_len = 0; + } + nd->caseless_path.mnt = NULL; + nd->caseless_path.dentry = NULL; +#endif /* MY_ABC_HERE */ + if (flags & LOOKUP_ROOT) { struct dentry *root = nd->root.dentry; struct inode *inode = root->d_inode; @@ -2318,6 +2867,9 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path { const char *s = path_init(nd, flags); int err; +#ifdef MY_ABC_HERE + bool update_last = true; +#endif /* MY_ABC_HERE */ if (unlikely(flags & LOOKUP_DOWN) && !IS_ERR(s)) { err = handle_lookup_down(nd); @@ -2325,9 +2877,31 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path s = ERR_PTR(err); } +#ifdef MY_ABC_HERE + while (!(err = link_path_walk(s, nd))) { + s = lookup_last(nd); + if (unlikely(s && IS_ERR(s))) + continue; + /* + * we only update user path case, not update symbolic link. + * Example: user lookup /a/b/c, but c is a symbolic link + * /A/B/C -> /D/E/F, we only update path to /A/B/C. + */ + if ((nd->flags & LOOKUP_CASELESS_COMPARE) && update_last) { + update_last = false; + err = update_path_to_real_filename(nd); + if (err) + return err; + } + if (!s) + break; + } +#else /* MY_ABC_HERE */ while (!(err = link_path_walk(s, nd)) && (s = lookup_last(nd)) != NULL) ; +#endif /* MY_ABC_HERE */ + if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) { err = handle_lookup_down(nd); nd->flags &= ~LOOKUP_JUMPED; // no d_weak_revalidate(), please... @@ -2499,9 +3073,48 @@ static int lookup_one_len_common(const char *name, struct dentry *base, return err; } +#ifdef MY_ABC_HERE + if (IS_SYNOACL(base)) + return synoacl_op_exec_permission(base, d_inode(base)); +#endif /* MY_ABC_HERE */ + return inode_permission(base->d_inode, MAY_EXEC); } +#ifdef MY_ABC_HERE +int syno_user_path_at(int dfd, const char __user *user_name, unsigned flags, + struct path *path, char **real_filename, int *real_filename_len) +{ + int retval; + struct nameidata nd; + struct filename *name = getname(user_name); + + BUG_ON(flags & LOOKUP_PARENT); + + nd.real_filename = *real_filename; + nd.real_filename_cur_locate = nd.real_filename; + nd.real_filename_len = 0; + + if (IS_ERR(name)) + return PTR_ERR(name); + set_nameidata(&nd, dfd, name); + retval = path_lookupat(&nd, flags | LOOKUP_RCU, path); + if (unlikely(retval == -ECHILD)) + retval = path_lookupat(&nd, flags, path); + if (unlikely(retval == -ESTALE)) + retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path); + + if (likely(!retval)) + audit_inode(name, path->dentry, 0); + restore_nameidata(); + putname(name); + + *real_filename_len = nd.real_filename_len; + return retval; + +} +#endif /* MY_ABC_HERE */ + /** * try_lookup_one_len - filesystem helper to lookup single pathname component * @name: pathname component to lookup @@ -2693,14 +3306,35 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); +#ifdef MY_ABC_HERE + if (IS_FS_SYNOACL(dir)) + error = synoacl_op_may_delete(victim, dir); + else +#endif /* MY_ABC_HERE */ error = inode_permission(dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) return -EPERM; - if (check_sticky(dir, inode) || IS_APPEND(inode) || - IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode)) +#ifdef MY_ABC_HERE + if (!IS_SYNOACL(victim->d_parent) && check_sticky(dir, inode)) + return -EPERM; +#else /* MY_ABC_HERE */ + if (check_sticky(dir, inode)) + return -EPERM; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* expired files are still immutable or appendable, but also deletable. */ + if (!IS_EXPIRED(inode) && (IS_APPEND(inode) || IS_IMMUTABLE(inode))) + return -EPERM; +#else + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return -EPERM; +#endif /* MY_ABC_HERE */ + + if (IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode)) return -EPERM; if (isdir) { if (!d_is_dir(victim)) @@ -2725,7 +3359,11 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) * 4. We should have write and exec permissions on dir * 5. We can't do it if dir is immutable (done in permission()) */ +#ifdef MY_ABC_HERE +static inline int may_create(struct inode *dir, struct dentry *child, int mode) +#else /* MY_ABC_HERE */ static inline int may_create(struct inode *dir, struct dentry *child) +#endif /* MY_ABC_HERE */ { struct user_namespace *s_user_ns; audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); @@ -2737,6 +3375,13 @@ static inline int may_create(struct inode *dir, struct dentry *child) if (!kuid_has_mapping(s_user_ns, current_fsuid()) || !kgid_has_mapping(s_user_ns, current_fsgid())) return -EOVERFLOW; + +#ifdef MY_ABC_HERE + if (IS_SYNOACL(child->d_parent)) + return synoacl_op_permission(child->d_parent, + (S_ISDIR(mode) ? MAY_APPEND : MAY_WRITE) | MAY_EXEC); +#endif /* MY_ABC_HERE */ + return inode_permission(dir, MAY_WRITE | MAY_EXEC); } @@ -2787,7 +3432,11 @@ EXPORT_SYMBOL(unlock_rename); int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool want_excl) { +#ifdef MY_ABC_HERE + int error = may_create(dir, dentry, S_IFREG); +#else /* MY_ABC_HERE */ int error = may_create(dir, dentry); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -2801,6 +3450,12 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, error = dir->i_op->create(dir, dentry, mode, want_excl); if (!error) fsnotify_create(dir, dentry); +#ifdef MY_ABC_HERE + if (!error && IS_SYNOACL(dentry->d_parent)) { + // Assume that inode has been attached to dentry by d_instantiate(). + synoacl_op_init(dentry); + } +#endif /* MY_ABC_HERE */ return error; } EXPORT_SYMBOL(vfs_create); @@ -2810,7 +3465,11 @@ int vfs_mkobj(struct dentry *dentry, umode_t mode, void *arg) { struct inode *dir = dentry->d_parent->d_inode; +#ifdef MY_ABC_HERE + int error = may_create(dir, dentry, S_IFREG); +#else int error = may_create(dir, dentry); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -2867,6 +3526,11 @@ static int may_open(const struct path *path, int acc_mode, int flag) break; } +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) + error = synoacl_op_permission(dentry, MAY_OPEN | acc_mode); + else +#endif /* MY_ABC_HERE */ error = inode_permission(inode, MAY_OPEN | acc_mode); if (error) return error; @@ -2875,8 +3539,15 @@ static int may_open(const struct path *path, int acc_mode, int flag) * An append-only file must be opened in append mode for writing. */ if (IS_APPEND(inode)) { +#ifdef MY_ABC_HERE + /* no O_APPEND is allowed if it's locker appendable */ + if (!syno_op_locker_is_appendable(inode) && + (flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) + return -EPERM; +#else if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) return -EPERM; +#endif /* MY_ABC_HERE */ if (flag & O_TRUNC) return -EPERM; } @@ -2929,6 +3600,12 @@ static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t m !kgid_has_mapping(s_user_ns, current_fsgid())) return -EOVERFLOW; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dir->dentry)) + error = synoacl_op_permission(dir->dentry, + (S_ISDIR(mode)?MAY_APPEND:MAY_WRITE) | MAY_EXEC); + else +#endif /* MY_ABC_HERE */ error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); if (error) return error; @@ -3071,6 +3748,11 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, dentry = atomic_open(nd, dentry, file, open_flag, mode); if (unlikely(create_error) && dentry == ERR_PTR(-ENOENT)) dentry = ERR_PTR(create_error); +#ifdef MY_ABC_HERE + if (!IS_ERR_OR_NULL(dentry) && (file->f_mode & FMODE_CREATED) && + IS_SYNOACL(dentry->d_parent)) + synoacl_op_init(dentry); +#endif /* MY_ABC_HERE */ return dentry; } @@ -3100,6 +3782,10 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, open_flag & O_EXCL); if (error) goto out_dput; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry->d_parent)) + synoacl_op_init(dentry); +#endif /* MY_ABC_HERE */ } if (unlikely(create_error) && !dentry->d_inode) { error = create_error; @@ -3262,6 +3948,11 @@ struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag) int error; /* we want directory to be writable */ +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) + error = synoacl_op_permission(dentry, MAY_WRITE | MAY_EXEC); + else +#endif /* MY_ABC_HERE */ error = inode_permission(dir, MAY_WRITE | MAY_EXEC); if (error) goto out_err; @@ -3520,7 +4211,11 @@ EXPORT_SYMBOL(user_path_create); int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV; +#ifdef MY_ABC_HERE + int error = may_create(dir, dentry, mode); +#else /* MY_ABC_HERE */ int error = may_create(dir, dentry); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -3621,7 +4316,11 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { +#ifdef MY_ABC_HERE + int error = may_create(dir, dentry, S_IFDIR); +#else /* MY_ABC_HERE */ int error = may_create(dir, dentry); +#endif /* MY_ABC_HERE */ unsigned max_links = dir->i_sb->s_max_links; if (error) @@ -3641,6 +4340,13 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) error = dir->i_op->mkdir(dir, dentry, mode); if (!error) fsnotify_mkdir(dir, dentry); +#ifdef MY_ABC_HERE + if (!error && IS_SYNOACL(dentry->d_parent)) { + // Assume that inode has been attached to dentry by d_instantiate(). + synoacl_op_init(dentry); + } +#endif /* MY_ABC_HERE */ + return error; } EXPORT_SYMBOL(vfs_mkdir); @@ -3936,7 +4642,11 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) { +#ifdef MY_ABC_HERE + int error = may_create(dir, dentry, S_IFLNK); +#else /* MY_ABC_HERE */ int error = may_create(dir, dentry); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -4025,7 +4735,12 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de if (!inode) return -ENOENT; +#ifdef MY_ABC_HERE + error = may_create(dir, new_dentry, inode->i_mode); +#else /* MY_ABC_HERE */ error = may_create(dir, new_dentry); +#endif /* MY_ABC_HERE */ + if (error) return error; @@ -4162,6 +4877,181 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname return do_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); } +#ifdef MY_ABC_HERE +void free_rename_path_list(struct synotify_rename_path * rename_path_list) +{ + while(rename_path_list) { + struct synotify_rename_path *tmp = rename_path_list; + rename_path_list = rename_path_list->next; + + if (tmp->old_full_path) + kfree(tmp->old_full_path); + if (tmp->new_full_path) + kfree(tmp->new_full_path); + + mntput(tmp->vfs_mnt); + kfree(tmp); + } +} +EXPORT_SYMBOL(free_rename_path_list); + +static inline struct synotify_rename_path * get_rename_path(struct vfsmount *vfsmnt, struct dentry *old_dentry, struct dentry *new_dentry) +{ + int ret = -1; + struct synotify_rename_path * result = NULL; + struct synotify_rename_path * rename_path = NULL; + + struct path old_path; + struct path new_path; + struct path root_path; + char *old_path_buf = NULL; + char *new_path_buf = NULL; + char *tmp_old_full_path = NULL; + char *tmp_new_full_path = NULL; + char *tmp_old_path = NULL; + char *tmp_new_path = NULL; + + if (!vfsmnt || !old_dentry || !new_dentry) + return NULL; + + rename_path = kmalloc(sizeof(struct synotify_rename_path), GFP_NOFS); + if (!rename_path) { + if (__ratelimit(&_namei_rs)) + printk(KERN_WARNING "synotify get ENOMEM in file: %s, line: %d\n", __FILE__, __LINE__); + goto end; + } + + memset(&old_path, 0, sizeof(struct path)); + memset(&new_path, 0, sizeof(struct path)); + memset(&root_path, 0, sizeof(struct path)); + + old_path.mnt = vfsmnt; + old_path.dentry = old_dentry; + new_path.mnt = vfsmnt; + new_path.dentry = new_dentry; + + root_path.mnt = vfsmnt; + root_path.dentry = vfsmnt->mnt_root; + + old_path_buf = kmalloc(PATH_MAX, GFP_NOFS); + if (!old_path_buf) { + if (__ratelimit(&_namei_rs)) + printk(KERN_WARNING "synotify get ENOMEM in file: %s, line: %d\n", __FILE__, __LINE__); + goto end; + } + + new_path_buf = kmalloc(PATH_MAX, GFP_NOFS); + if (!new_path_buf) { + if (__ratelimit(&_namei_rs)) + printk(KERN_WARNING "synotify get ENOMEM in file: %s, line: %d\n", __FILE__, __LINE__); + goto end; + } + + // set synotify_rename_path + tmp_old_full_path = __d_path(&old_path, &root_path, old_path_buf, PATH_MAX-1); + tmp_new_full_path = __d_path(&new_path, &root_path, new_path_buf, PATH_MAX-1); + + if (IS_ERR_OR_NULL(tmp_old_full_path) || IS_ERR_OR_NULL(tmp_new_full_path)) { + goto end; + } + + // get required path, update to rename_path + tmp_old_path = kstrdup(tmp_old_full_path, GFP_NOFS | __GFP_ZERO); + if (!tmp_old_path) { + goto end; + } + tmp_new_path = kstrdup(tmp_new_full_path, GFP_NOFS | __GFP_ZERO); + if (!tmp_new_path) { + goto end; + } + rename_path->old_full_path = tmp_old_path; + rename_path->new_full_path = tmp_new_path; + rename_path->vfs_mnt = vfsmnt; + rename_path->next = NULL; + + result = rename_path; + ret = 0; +end: + if (ret != 0) { + if (tmp_old_path) + kfree(tmp_old_path); + if (tmp_new_path) + kfree(tmp_new_path); + if (rename_path) + kfree(rename_path); + } + + if (old_path_buf) + kfree(old_path_buf); + if (new_path_buf) + kfree(new_path_buf); + + return result; +} + +struct synotify_rename_path * get_rename_path_list(struct dentry *old_dentry, struct dentry *new_dentry) +{ + struct nsproxy *nsproxy = current->nsproxy; + struct mnt_namespace *mnt_space = NULL; + struct list_head *list_head = NULL; + struct synotify_rename_path *head = NULL; + struct synotify_rename_path *tail = NULL; + + if (!nsproxy) { + return NULL; + } + + mnt_space = nsproxy->mnt_ns; + if (!mnt_space) { + return NULL; + } + + down_read(&namespace_sem); + spin_lock(&mnt_space->ns_lock); + list_for_each(list_head, &mnt_space->list) { + struct mount *mnt = list_entry(list_head, struct mount, mnt_list); + struct synotify_rename_path *rename_path = NULL; + struct vfsmount *vfsmnt = NULL; + + if (!mnt) { + continue; + } + if (mnt->mnt.mnt_sb != new_dentry->d_sb) { + continue; + } + + if (!((FS_MOVED_FROM | FS_MOVED_TO) & mnt->mnt_fsnotify_syno_mask)) { + continue; + } + + vfsmnt = &mnt->mnt; + // NOTE: we will hold vfsmnt till calling free_rename_path_list when getting rename path successfully + mntget(vfsmnt); + + spin_unlock(&mnt_space->ns_lock); + rename_path = get_rename_path(vfsmnt, old_dentry, new_dentry); + spin_lock(&mnt_space->ns_lock); + + if (!rename_path) { + mntput(vfsmnt); + } else { + if (!head) { + head = rename_path; + tail = rename_path; + } else { + tail->next = rename_path; + tail = rename_path; + } + } + } // list_for_each mount + spin_unlock(&mnt_space->ns_lock); + up_read(&namespace_sem); + + return head; +} +EXPORT_SYMBOL(get_rename_path_list); +#endif /* MY_ABC_HERE */ + /** * vfs_rename - rename a filesystem object * @old_dir: parent of source @@ -4223,6 +5113,9 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, bool new_is_dir = false; unsigned max_links = new_dir->i_sb->s_max_links; struct name_snapshot old_name; +#ifdef MY_ABC_HERE + struct synotify_rename_path *rename_path_list = NULL; +#endif /* MY_ABC_HERE */ if (source == target) return 0; @@ -4232,7 +5125,11 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, return error; if (!target) { +#ifdef MY_ABC_HERE + error = may_create(new_dir, new_dentry, source->i_mode); +#else /* MY_ABC_HERE */ error = may_create(new_dir, new_dentry); +#endif /* MY_ABC_HERE */ } else { new_is_dir = d_is_dir(new_dentry); @@ -4252,13 +5149,37 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, * we'll need to flip '..'. */ if (new_dir != old_dir) { - if (is_dir) { + if (is_dir +#ifdef MY_ABC_HERE + && !(old_dentry->d_sb->s_magic == BTRFS_SUPER_MAGIC + && old_dentry->d_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) +#endif /* MY_ABC_HERE */ + ) { +#ifdef MY_ABC_HERE + // Skip MAY_WRITE check because only may_delete() is + // required for SynoACL + if (!IS_SYNOACL(old_dentry)) + error = inode_permission(source, MAY_WRITE); +#else /* MY_ABC_HERE */ error = inode_permission(source, MAY_WRITE); +#endif /* MY_ABC_HERE */ if (error) return error; } - if ((flags & RENAME_EXCHANGE) && new_is_dir) { + if ((flags & RENAME_EXCHANGE) && new_is_dir +#ifdef MY_ABC_HERE + && !(new_dentry->d_sb->s_magic == BTRFS_SUPER_MAGIC + && new_dentry->d_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) +#endif /* MY_ABC_HERE */ + ) { +#ifdef MY_ABC_HERE + // Skip MAY_WRITE check because only may_delete() is + // required for SynoACL + if (!IS_SYNOACL(new_dentry)) + error = inode_permission(target, MAY_WRITE); +#else /* MY_ABC_HERE */ error = inode_permission(target, MAY_WRITE); +#endif /* MY_ABC_HERE */ if (error) return error; } @@ -4269,6 +5190,10 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (error) return error; +#ifdef MY_ABC_HERE + rename_path_list = get_rename_path_list(old_dentry, new_dentry); +#endif /* MY_ABC_HERE */ + take_dentry_name_snapshot(&old_name, old_dentry); dget(new_dentry); if (!is_dir || (flags & RENAME_EXCHANGE)) @@ -4325,14 +5250,26 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, dput(new_dentry); if (!error) { fsnotify_move(old_dir, new_dir, &old_name.name, is_dir, - !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry); + !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry +#ifdef MY_ABC_HERE + , rename_path_list, false +#endif /* MY_ABC_HERE */ + ); if (flags & RENAME_EXCHANGE) { fsnotify_move(new_dir, old_dir, &old_dentry->d_name, - new_is_dir, NULL, new_dentry); + new_is_dir, NULL, new_dentry +#ifdef MY_ABC_HERE + , rename_path_list, true +#endif /* MY_ABC_HERE */ + ); } } release_dentry_name_snapshot(&old_name); +#ifdef MY_ABC_HERE + free_rename_path_list(rename_path_list); +#endif /* MY_ABC_HERE */ + return error; } EXPORT_SYMBOL(vfs_rename); diff --git a/fs/namespace.c b/fs/namespace.c index c7fbb50a5aaa..f95b9cbf5d43 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/namespace.c @@ -30,10 +33,24 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include "pnode.h" #include "internal.h" +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK +extern bool ramdisk_check_failed; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + +#ifdef MY_ABC_HERE +int (*funcSYNOSendErrorFsBtrfsEvent)(const u8*) = NULL; +int (*funcSYNOMetaCorruptedEvent)(const u8*, u64 start) = NULL; +EXPORT_SYMBOL(funcSYNOSendErrorFsBtrfsEvent); +EXPORT_SYMBOL(funcSYNOMetaCorruptedEvent); +#endif /* MY_ABC_HERE */ + /* Maximum number of mounts in a mount namespace */ unsigned int sysctl_mount_max __read_mostly = 100000; @@ -69,7 +86,22 @@ static DEFINE_IDA(mnt_group_ida); static struct hlist_head *mount_hashtable __read_mostly; static struct hlist_head *mountpoint_hashtable __read_mostly; static struct kmem_cache *mnt_cache __read_mostly; +#ifdef MY_ABC_HERE +/* + * #89004 + * Since we'll access mount list under namespace(mnt_list), + * we need this read semaphore to against list modification. + */ +DECLARE_RWSEM(namespace_sem); + +/* + * #102174 + * Avoid SYNONotify deadlock when read /proc/mounts and mount. + */ +static DEFINE_MUTEX(namespace_mutex); +#else static DECLARE_RWSEM(namespace_sem); +#endif /* MY_ABC_HERE */ static HLIST_HEAD(unmounted); /* protected by namespace_sem */ static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */ @@ -431,6 +463,9 @@ void __mnt_drop_write(struct vfsmount *mnt) mnt_dec_writers(real_mount(mnt)); preempt_enable(); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(__mnt_drop_write); +#endif /* MY_ABC_HERE */ /** * mnt_drop_write - give up write access to a mount @@ -1288,6 +1323,9 @@ static void *m_start(struct seq_file *m, loff_t *pos) struct proc_mounts *p = m->private; struct list_head *prev; +#ifdef MY_ABC_HERE + mutex_lock(&namespace_mutex); +#endif /* MY_ABC_HERE */ down_read(&namespace_sem); if (!*pos) { prev = &p->ns->list; @@ -1323,6 +1361,9 @@ static void m_stop(struct seq_file *m, void *v) list_del_init(&p->cursor.mnt_list); unlock_ns_list(p->ns); up_read(&namespace_sem); +#ifdef MY_ABC_HERE + mutex_unlock(&namespace_mutex); +#endif /* MY_ABC_HERE */ } static int m_show(struct seq_file *m, void *v) @@ -1419,6 +1460,9 @@ static void namespace_unlock(void) list_splice_init(&ex_mountpoints, &list); up_write(&namespace_sem); +#ifdef MY_ABC_HERE + mutex_unlock(&namespace_mutex); +#endif /* MY_ABC_HERE */ shrink_dentry_list(&list); @@ -1435,6 +1479,9 @@ static void namespace_unlock(void) static inline void namespace_lock(void) { +#ifdef MY_ABC_HERE + mutex_lock(&namespace_mutex); +#endif /* MY_ABC_HERE */ down_write(&namespace_sem); } @@ -1560,6 +1607,11 @@ static int do_umount(struct mount *mnt, int flags) { struct super_block *sb = mnt->mnt.mnt_sb; int retval; +#ifdef MY_ABC_HERE + char *file_name_buf = NULL; + char *mnt_point_buf = NULL; + char *mnt_point_name = NULL; +#endif /* MY_ABC_HERE */ retval = security_sb_umount(&mnt->mnt, flags); if (retval) @@ -1624,6 +1676,12 @@ static int do_umount(struct mount *mnt, int flags) return do_umount_root(sb); } +#ifdef MY_ABC_HERE + /* malloc before getting the spinlock */ + file_name_buf = kmalloc(PATH_MAX, GFP_KERNEL); + mnt_point_buf = kmalloc(PATH_MAX, GFP_KERNEL); +#endif /* MY_ABC_HERE */ + namespace_lock(); lock_mount_hash(); @@ -1646,9 +1704,26 @@ static int do_umount(struct mount *mnt, int flags) retval = 0; } } +#ifdef MY_ABC_HERE + if (-EBUSY == retval && file_name_buf && mnt_point_buf) { + mnt_point_name = dentry_path_raw(mnt->mnt_mountpoint, mnt_point_buf, PATH_MAX - 1); + if (!IS_ERR(mnt_point_name)) + fs_show_opened_file(mnt, mnt_point_name, file_name_buf, PATH_MAX); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (NULL != strstr(sb->s_id, "synoboot")) + printk(KERN_NOTICE"%s unmounted, process=%s\n", sb->s_id, current->comm); +#endif /* MY_ABC_HERE */ + out: unlock_mount_hash(); namespace_unlock(); +#ifdef MY_ABC_HERE + kfree(file_name_buf); + kfree(mnt_point_buf); +#endif /* MY_ABC_HERE */ return retval; } @@ -1919,6 +1994,20 @@ void drop_collected_mounts(struct vfsmount *mnt) namespace_unlock(); } +static bool has_locked_children(struct mount *mnt, struct dentry *dentry) +{ + struct mount *child; + + list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { + if (!is_subdir(child->mnt_mountpoint, dentry)) + continue; + + if (child->mnt.mnt_flags & MNT_LOCKED) + return true; + } + return false; +} + /** * clone_private_mount - create a private clone of a path * @@ -1933,10 +2022,19 @@ struct vfsmount *clone_private_mount(const struct path *path) struct mount *old_mnt = real_mount(path->mnt); struct mount *new_mnt; + down_read(&namespace_sem); if (IS_MNT_UNBINDABLE(old_mnt)) - return ERR_PTR(-EINVAL); + goto invalid; + + if (!check_mnt(old_mnt)) + goto invalid; + + if (has_locked_children(old_mnt, path->dentry)) + goto invalid; new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); + up_read(&namespace_sem); + if (IS_ERR(new_mnt)) return ERR_CAST(new_mnt); @@ -1944,6 +2042,10 @@ struct vfsmount *clone_private_mount(const struct path *path) new_mnt->mnt_ns = MNT_NS_INTERNAL; return &new_mnt->mnt; + +invalid: + up_read(&namespace_sem); + return ERR_PTR(-EINVAL); } EXPORT_SYMBOL_GPL(clone_private_mount); @@ -1961,6 +2063,9 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, } return 0; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(iterate_mounts); +#endif /* MY_ABC_HERE */ static void lock_mnt_tree(struct mount *mnt) { @@ -2295,19 +2400,6 @@ static int do_change_type(struct path *path, int ms_flags) return err; } -static bool has_locked_children(struct mount *mnt, struct dentry *dentry) -{ - struct mount *child; - list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { - if (!is_subdir(child->mnt_mountpoint, dentry)) - continue; - - if (child->mnt.mnt_flags & MNT_LOCKED) - return true; - } - return false; -} - static struct mount *__do_loopback(struct path *old_path, int recurse) { struct mount *mnt = ERR_PTR(-EINVAL), *old = real_mount(old_path->mnt); @@ -3201,10 +3293,26 @@ int path_mount(const char *dev_name, struct path *path, return do_reconfigure_mnt(path, mnt_flags); if (flags & MS_REMOUNT) return do_remount(path, flags, sb_flags, mnt_flags, data_page); +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + if ((flags & MS_BIND) && ramdisk_check_failed) + return -EPERM; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ +#ifdef CONFIG_SYNO_KEXEC_TEST + if ((flags & MS_BIND) && kexec_test_flags) + return -EPERM; +#endif /* CONFIG_SYNO_KEXEC_TEST */ if (flags & MS_BIND) return do_loopback(path, dev_name, flags & MS_REC); if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) return do_change_type(path, flags); +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + if ((flags & MS_MOVE) && ramdisk_check_failed) + return -EPERM; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ +#ifdef CONFIG_SYNO_KEXEC_TEST + if ((flags & MS_MOVE) && kexec_test_flags) + return -EPERM; +#endif /* CONFIG_SYNO_KEXEC_TEST */ if (flags & MS_MOVE) return do_move_mount_old(path, dev_name); @@ -3217,6 +3325,14 @@ long do_mount(const char *dev_name, const char __user *dir_name, { struct path path; int ret; +#ifdef MY_ABC_HERE + extern int gSynoInstallFlag; + if ( 0 == gSynoInstallFlag && + NULL != dev_name && + strstr(dev_name, CONFIG_SYNO_USB_FLASH_DEVICE_NAME)) { + return -EINVAL; + } +#endif /*MY_ABC_HERE*/ ret = user_path_at(AT_FDCWD, dir_name, LOOKUP_FOLLOW, &path); if (ret) diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 14a72224b657..7d97e648589a 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -200,7 +200,7 @@ config NFS_DEBUG config NFS_DISABLE_UDP_SUPPORT bool "NFS: Disable NFS UDP protocol support" depends on NFS_FS - default y + default n help Choose Y here to disable the use of NFS over UDP. NFS over UDP on modern networks (1Gb+) can lead to data corruption caused by diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 79ff172eb1c8..d860a7eef688 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/nfs/callback_xdr.c @@ -1071,11 +1074,17 @@ static const struct svc_procedure nfs4_callback_procedures1[] = { }; static unsigned int nfs4_callback_count1[ARRAY_SIZE(nfs4_callback_procedures1)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfs4_callback_latency1[ARRAY_SIZE(nfs4_callback_procedures1)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfs4_callback_version1 = { .vs_vers = 1, .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), .vs_proc = nfs4_callback_procedures1, .vs_count = nfs4_callback_count1, +#ifdef MY_ABC_HERE + .vs_latency = nfs4_callback_latency1, +#endif /* MY_ABC_HERE */ .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_dispatch = NULL, .vs_hidden = true, @@ -1083,11 +1092,17 @@ const struct svc_version nfs4_callback_version1 = { }; static unsigned int nfs4_callback_count4[ARRAY_SIZE(nfs4_callback_procedures1)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfs4_callback_latency4[ARRAY_SIZE(nfs4_callback_procedures1)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfs4_callback_version4 = { .vs_vers = 4, .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), .vs_proc = nfs4_callback_procedures1, .vs_count = nfs4_callback_count4, +#ifdef MY_ABC_HERE + .vs_latency = nfs4_callback_latency4, +#endif /* MY_ABC_HERE */ .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_dispatch = NULL, .vs_hidden = true, diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 3f0983e93a99..c4e4011d20b2 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile @@ -22,3 +22,4 @@ nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o nfsd-$(CONFIG_NFSD_FLEXFILELAYOUT) += flexfilelayout.o flexfilelayoutxdr.o +nfsd-$(CONFIG_SYNO_NFSD_LATENCY_REPORT) += syno_io_stat.o diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index fdf2aad73470..2105155d2fcf 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 1995, 1996 Olaf Kirch */ @@ -42,18 +45,54 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) if (flags & NFSEXP_ALLSQUASH) { new->fsuid = exp->ex_anon_uid; new->fsgid = exp->ex_anon_gid; +#ifdef MY_ABC_HERE + /* + * When squash root/all to admin, the ex_anon_uid and ex_anon_gid are 1024/100 (admin/users). + * However, the rw permission of shared folder is only for administrators group. So the + * administrators group id (101) should be added to the cred for the share permission. + * Since there is no easy way in kernel to know which groups a user belongs to, here we simply + * assume that the admin is always in administrators group. + * + * Note: directly squash to 1024/101 may cause the new created file has owner group + * "administrators". We don't want this behavior. + */ + if (uid_eq(exp->ex_anon_uid, KUIDT_INIT(1024))) { + gi = groups_alloc(1); + if (!gi) + goto oom; + gi->gid[0] = KGIDT_INIT(101); + } else { + gi = groups_alloc(0); + if (!gi) + goto oom; + } +#else /* MY_ABC_HERE */ gi = groups_alloc(0); if (!gi) goto oom; +#endif /* MY_ABC_HERE */ } else if (flags & NFSEXP_ROOTSQUASH) { if (uid_eq(new->fsuid, GLOBAL_ROOT_UID)) new->fsuid = exp->ex_anon_uid; if (gid_eq(new->fsgid, GLOBAL_ROOT_GID)) new->fsgid = exp->ex_anon_gid; +#ifdef MY_ABC_HERE + if (uid_eq(new->fsuid, KUIDT_INIT(1024))) { + gi = groups_alloc(rqgi->ngroups + 1); + if (!gi) + goto oom; + gi->gid[rqgi->ngroups] = KGIDT_INIT(101); + } else { + gi = groups_alloc(rqgi->ngroups); + if (!gi) + goto oom; + } +#else /* MY_ABC_HERE */ gi = groups_alloc(rqgi->ngroups); if (!gi) goto oom; +#endif /* MY_ABC_HERE */ for (i = 0; i < rqgi->ngroups; i++) { if (gid_eq(GLOBAL_ROOT_GID, rqgi->gid[i])) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 7346acda9d76..6380830450f5 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * per net namespace data structures for nfsd @@ -46,6 +49,9 @@ struct nfsd_net { struct vfsmount *nfsd_mnt; struct dentry *nfsd_client_dir; +#ifdef MY_ABC_HERE + struct dentry *nfsd_syno_client_dir; +#endif /* MY_ABC_HERE */ /* * reclaim_str_hashtbl[] holds known client info from previous reset/reboot @@ -184,4 +190,9 @@ extern unsigned int nfsd_net_id; void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn); void nfsd_reset_boot_verifier(struct nfsd_net *nn); + +#ifdef MY_ABC_HERE +struct nfsd_net *syno_nfsd_net_get(void); +#endif /* MY_ABC_HERE */ + #endif /* __NFSD_NETNS_H__ */ diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 6a900f770dd2..09b29a702ce1 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Process version 2 NFSACL requests. @@ -428,11 +431,17 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { }; static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfsd_acl_latency2[ARRAY_SIZE(nfsd_acl_procedures2)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfsd_acl_version2 = { .vs_vers = 2, .vs_nproc = 5, .vs_proc = nfsd_acl_procedures2, .vs_count = nfsd_acl_count2, +#ifdef MY_ABC_HERE + .vs_latency = nfsd_acl_latency2, +#endif /* MY_ABC_HERE */ .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS3_SVC_XDRSIZE, }; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 34a394e50e1d..da987ab7154a 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Process version 3 NFSACL requests. @@ -275,11 +278,17 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { }; static unsigned int nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfsd_acl_latency3[ARRAY_SIZE(nfsd_acl_procedures3)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfsd_acl_version3 = { .vs_vers = 3, .vs_nproc = 3, .vs_proc = nfsd_acl_procedures3, .vs_count = nfsd_acl_count3, +#ifdef MY_ABC_HERE + .vs_latency = nfsd_acl_latency3, +#endif /* MY_ABC_HERE */ .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS3_SVC_XDRSIZE, }; diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index a633044b0dc1..99a0a8bccb3d 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Process version 3 NFS requests. @@ -12,9 +15,17 @@ #include "cache.h" #include "xdr3.h" #include "vfs.h" +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ #define NFSDDBG_FACILITY NFSDDBG_PROC +#ifdef MY_ABC_HERE +extern u32 nfs_udp_f_rtpref; +extern u32 nfs_udp_f_wtpref; +#endif /* MY_ABC_HERE */ + static int nfs3_ftypes[] = { 0, /* NF3NON */ S_IFREG, /* NF3REG */ @@ -590,6 +601,23 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp) resp->f_maxfilesize = ~(u32) 0; resp->f_properties = NFS3_FSF_DEFAULT; +#ifdef MY_ABC_HERE + if (unlikely(IPPROTO_UDP == rqstp->rq_prot)) { + if (CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE <= nfs_udp_f_rtpref && CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE >= nfs_udp_f_rtpref) { + resp->f_rtpref = nfs_udp_f_rtpref; + } else { + resp->f_rtpref = CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE; + dprintk("nfsd: FSINFO(3) nfs_udp_f_rtpref value is not correct %d\n", nfs_udp_f_rtpref); + } + if (CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE <= nfs_udp_f_wtpref && CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE >= nfs_udp_f_wtpref) { + resp->f_wtpref = nfs_udp_f_wtpref; + } else { + resp->f_wtpref = CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE; + dprintk("nfsd: FSINFO(3) nfs_udp_f_wtpref value is not correct %d\n", nfs_udp_f_wtpref); + } + } +#endif /* MY_ABC_HERE */ + resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); @@ -919,12 +947,46 @@ static const struct svc_procedure nfsd_procedures3[22] = { }, }; +#ifdef MY_ABC_HERE +static void nfsd_store_latency(u64 rpc_lat, u64 vfs_lat, u32 op) +{ + enum syno_nfsd_io_stat_type type; + if (op != NFS3PROC_READ && op != NFS3PROC_WRITE) + return; + type = (op == NFS3PROC_READ) ? SYNO_NFSD_IO_READ : SYNO_NFSD_IO_WRITE; + syno_nfsd_store_latency_into_histogram(SYNO_NFSD_USEC_TO_SEC(rpc_lat), + SYNO_NFSD_USEC_TO_SEC(vfs_lat), + SYNO_NFSD_VERSION_3, type); +} + +static void nfsd_store_error(struct svc_rqst *rqstp) +{ + const struct syno_nfsd_dummy_status *st; + // rq_resp's size is from `rq_server->sv_xdrsize`, so we check on it. + if (!rqstp || !rqstp->rq_resp || + !rqstp->rq_server || rqstp->rq_server->sv_xdrsize < sizeof(struct syno_nfsd_dummy_status)) + return; + st = (const struct syno_nfsd_dummy_status *) rqstp->rq_resp; + syno_nfsd_store_error(be32_to_cpu(st->status), SYNO_NFSD_VERSION_3); +} +#endif /* MY_ABC_HERE */ + static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures3)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfsd_latency3[ARRAY_SIZE(nfsd_procedures3)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfsd_version3 = { .vs_vers = 3, .vs_nproc = 22, .vs_proc = nfsd_procedures3, .vs_dispatch = nfsd_dispatch, .vs_count = nfsd_count3, +#ifdef MY_ABC_HERE + .vs_latency = nfsd_latency3, +#endif /* MY_ABC_HERE */ .vs_xdrsize = NFS3_SVC_XDRSIZE, +#ifdef MY_ABC_HERE + .vs_store_latency_to_histogram = nfsd_store_latency, + .vs_store_resp_error = nfsd_store_error, +#endif /* MY_ABC_HERE */ }; diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 00440337efc1..375f962d4e92 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Server-side procedures for NFSv4. * @@ -49,6 +52,9 @@ #include "acl.h" #include "pnfs.h" #include "trace.h" +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ #ifdef CONFIG_NFSD_V4_SECURITY_LABEL #include @@ -187,8 +193,14 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs if (open->op_share_access & NFS4_SHARE_ACCESS_READ) accmode |= NFSD_MAY_READ; +#ifdef MY_ABC_HERE + /* NFSD_MAY_TRUNC is checked later in nfsd_get_write_access() if size is changed. */ + if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) + accmode |= NFSD_MAY_WRITE; +#else if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC); +#endif /* MY_ABC_HERE */ if (open->op_share_deny & NFS4_SHARE_DENY_READ) accmode |= NFSD_MAY_WRITE; @@ -1106,6 +1118,9 @@ void nfs4_put_copy(struct nfsd4_copy *copy) { if (!refcount_dec_and_test(©->refcount)) return; +#ifdef MY_ABC_HERE + kfree(copy->cp_src); +#endif /* MY_ABC_HERE */ kfree(copy); } @@ -1277,7 +1292,11 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, if (status) goto out; +#ifdef MY_ABC_HERE + status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount); +#else /* MY_ABC_HERE */ status = nfsd4_interssc_connect(©->cp_src, rqstp, mount); +#endif /* MY_ABC_HERE */ if (status) goto out; @@ -1440,7 +1459,11 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) dst->nf_src = nfsd_file_get(src->nf_src); memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid)); +#ifdef MY_ABC_HERE + memcpy(dst->cp_src, src->cp_src, sizeof(struct nl4_server)); +#else /* MY_ABC_HERE */ memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server)); +#endif /* MY_ABC_HERE */ memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid)); memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh)); dst->ss_mnt = src->ss_mnt; @@ -1532,6 +1555,11 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); if (!async_copy) goto out_err; +#ifdef MY_ABC_HERE + async_copy->cp_src = (struct nl4_server *) kzalloc(sizeof(struct nl4_server), GFP_KERNEL); + if (!async_copy->cp_src) + goto out_err; +#endif /* MY_ABC_HERE */ if (!nfs4_init_copy_state(nn, copy)) goto out_err; refcount_set(&async_copy->refcount, 1); @@ -1630,9 +1658,15 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* For now, only return one server address in cpn_src, the * address used by the client to connect to this server. */ +#ifdef MY_ABC_HERE + cn->cpn_src->nl4_type = NL4_NETADDR; + status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr, + &cn->cpn_src->u.nl4_addr); +#else /* MY_ABC_HERE */ cn->cpn_src.nl4_type = NL4_NETADDR; status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr, &cn->cpn_src.u.nl4_addr); +#endif /* MY_ABC_HERE */ WARN_ON_ONCE(status); if (status) { nfs4_put_cpntf_state(nn, cps); @@ -2317,6 +2351,20 @@ check_if_stalefh_allowed(struct nfsd4_compoundargs *args) } #endif +#ifdef MY_ABC_HERE +static void nfsd_store_latency(u64 rpc_lat, u64 vfs_lat, u32 op) +{ + enum syno_nfsd_io_stat_type type; + if (op != OP_READ && op != OP_WRITE) + return; + type = (op == OP_READ) ? SYNO_NFSD_IO_READ : SYNO_NFSD_IO_WRITE; + syno_nfsd_store_latency_into_histogram(SYNO_NFSD_USEC_TO_SEC(rpc_lat), + SYNO_NFSD_USEC_TO_SEC(vfs_lat), + SYNO_NFSD_VERSION_4, type); +} +#endif /* MY_ABC_HERE */ + + /* * COMPOUND call. */ @@ -2331,6 +2379,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) struct svc_fh *save_fh = &cstate->save_fh; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); __be32 status; +#ifdef MY_ABC_HERE + ktime_t stime = ktime_get(); + s64 latency_us; +#endif /* MY_ABC_HERE */ svcxdr_init_encode(rqstp, resp); resp->tagp = resp->xdr.p; @@ -2371,6 +2423,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) trace_nfsd_compound(rqstp, args->opcnt); while (!status && resp->opcnt < args->opcnt) { +#ifdef MY_ABC_HERE + stime = ktime_get(); +#endif /* MY_ABC_HERE */ + op = &args->ops[resp->opcnt++]; /* @@ -2421,6 +2477,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) op->opdesc->op_get_currentstateid(cstate, &op->u); op->status = op->opdesc->op_func(rqstp, cstate, &op->u); +#ifdef MY_ABC_HERE + // ignore internal error for udc. +#endif /* MY_ABC_HERE */ /* Only from SEQUENCE */ if (cstate->status == nfserr_replay_cache) { dprintk("%s NFS4.1 replay from cache\n", __func__); @@ -2439,6 +2498,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) op->status = check_nfsd_access(current_fh->fh_export, rqstp); } encode_op: +#ifdef MY_ABC_HERE + syno_nfsd_store_error(be32_to_cpu(op->status), SYNO_NFSD_VERSION_4); +#endif /* MY_ABC_HERE */ if (op->status == nfserr_replay_me) { op->replay = &cstate->replay_owner->so_replay; nfsd4_encode_replay(&resp->xdr, op); @@ -2453,6 +2515,14 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) nfsd4_cstate_clear_replay(cstate); nfsd4_increment_op_stats(op->opnum); +#ifdef MY_ABC_HERE + latency_us = ktime_to_us(ktime_sub(ktime_get(), stime)); + if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) + svc_update_lat(&nfsdstats.nfs4_oplatency[op->opnum], latency_us); +#ifdef MY_ABC_HERE + nfsd_store_latency(latency_us, rqstp->vfs_latency_us, op->opnum); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ } fh_put(current_fh); @@ -3317,11 +3387,17 @@ static const struct svc_procedure nfsd_procedures4[2] = { }; static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures4)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfsd_latency4[ARRAY_SIZE(nfsd_procedures4)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfsd_version4 = { .vs_vers = 4, .vs_nproc = 2, .vs_proc = nfsd_procedures4, .vs_count = nfsd_count3, +#ifdef MY_ABC_HERE + .vs_latency = nfsd_latency4, +#endif /* MY_ABC_HERE */ .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS4_SVC_XDRSIZE, .vs_rpcb_optnl = true, diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 80e394a2e3fd..233d420b31fd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (c) 2001 The Regents of the University of Michigan. * All rights reserved. @@ -53,6 +56,10 @@ #include "filecache.h" #include "trace.h" +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ + #define NFSDDBG_FACILITY NFSDDBG_PROC #define all_ones {{~0,~0},~0} @@ -2019,6 +2026,13 @@ free_client(struct nfs4_client *clp) clp->cl_nfsd_dentry = NULL; wake_up_all(&expiry_wq); } +#ifdef MY_ABC_HERE + if (clp->has_syno_client) { + // The version always be 4. + syno_nfsd_client_unregister((struct sockaddr *)&clp->cl_addr, 4); + clp->has_syno_client = false; + } +#endif /* MY_ABC_HERE */ drop_client(clp); } @@ -3064,6 +3078,9 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct sockaddr *sa = svc_addr(rqstp); bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); +#ifdef MY_ABC_HERE + int ret; +#endif /* MY_ABC_HERE */ rpc_ntop(sa, addr_str, sizeof(addr_str)); dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " @@ -3081,6 +3098,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (status) goto out_nolock; +#ifdef MY_ABC_HERE + ret = syno_nfsd_client_register(svc_addr(rqstp), rqstp->rq_vers, &new->cl_nii_name); + if (!ret) + new->has_syno_client = true; +#endif /* MY_ABC_HERE */ + switch (exid->spa_how) { case SP4_MACH_CRED: exid->spo_must_enforce[0] = 0; @@ -3937,10 +3960,18 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_client *unconf = NULL; __be32 status; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); +#ifdef MY_ABC_HERE + int ret; +#endif /* MY_ABC_HERE */ new = create_client(clname, rqstp, &clverifier); if (new == NULL) return nfserr_jukebox; +#ifdef MY_ABC_HERE + ret = syno_nfsd_client_register(svc_addr(rqstp), rqstp->rq_vers, &new->cl_nii_name); + if (!ret) + new->has_syno_client = true; +#endif /* MY_ABC_HERE */ /* Cases below refer to rfc 3530 section 14.2.33: */ spin_lock(&nn->client_lock); conf = find_confirmed_client_by_name(&clname, nn); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5f5169b9c2e9..8c548f77a207 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Server-side XDR for NFSv4 * @@ -1801,6 +1804,13 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) struct nl4_server *ns_dummy; int i, count; +#ifdef MY_ABC_HERE + copy->cp_src = (struct nl4_server *) svcxdr_tmpalloc(argp, sizeof(struct nl4_server)); + if (!copy->cp_src) + return nfserr_jukebox; + memset(copy->cp_src, 0, sizeof(struct nl4_server)); +#endif /* MY_ABC_HERE */ + status = nfsd4_decode_stateid(argp, ©->cp_src_stateid); if (status) return status; @@ -1824,7 +1834,11 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) } /* decode all the supplied server addresses but use first */ +#ifdef MY_ABC_HERE + status = nfsd4_decode_nl4_server(argp, copy->cp_src); +#else /* MY_ABC_HERE */ status = nfsd4_decode_nl4_server(argp, ©->cp_src); +#endif /* MY_ABC_HERE */ if (status) return status; @@ -1857,10 +1871,26 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, { __be32 status; +#ifdef MY_ABC_HERE + cn->cpn_src = (struct nl4_server *) svcxdr_tmpalloc(argp, sizeof(struct nl4_server)); + if (!cn->cpn_src) + return nfserr_jukebox; + memset(cn->cpn_src, 0, sizeof(struct nl4_server)); + cn->cpn_dst = (struct nl4_server *) svcxdr_tmpalloc(argp, sizeof(struct nl4_server)); + if (!cn->cpn_dst) + return nfserr_jukebox; + memset(cn->cpn_dst, 0, sizeof(struct nl4_server)); +#endif /* MY_ABC_HERE */ + status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid); if (status) return status; + +#ifdef MY_ABC_HERE + return nfsd4_decode_nl4_server(argp, cn->cpn_dst); +#else /* MY_ABC_HERE */ return nfsd4_decode_nl4_server(argp, &cn->cpn_dst); +#endif /* MY_ABC_HERE */ } static __be32 @@ -2653,6 +2683,10 @@ static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) break; } err = vfs_getattr(&path, stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); +#ifdef MY_ABC_HERE + if (!err) + nfsd_update_root_attr(path.dentry, stat); +#endif /* MY_ABC_HERE */ path_put(&path); return err; } @@ -2741,6 +2775,11 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, err = vfs_getattr(&path, &stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); if (err) goto out_nfserr; + +#ifdef MY_ABC_HERE + nfsd_update_root_attr(dentry, &stat); +#endif /* MY_ABC_HERE */ + if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | @@ -4781,7 +4820,11 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, *p++ = cpu_to_be32(1); +#ifdef MY_ABC_HERE + return nfsd42_encode_nl4_server(resp, cn->cpn_src); +#else /* MY_ABC_HERE */ return nfsd42_encode_nl4_server(resp, &cn->cpn_src); +#endif /* MY_ABC_HERE */ } static __be32 diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 0759e589ab52..1409cc4af422 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Syscall interface to knfsd. @@ -26,6 +29,10 @@ #include "netns.h" #include "pnfs.h" +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ + /* * We have a single directory with several nodes in it. */ @@ -55,6 +62,29 @@ enum { NFSD_RecoveryDir, NFSD_V4EndGrace, #endif +#ifdef MY_ABC_HERE + NFSD_UDP_Size, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + NFSD_UNIX_PRI, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + NFSD_SYNO_FILE_STATS, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + NFSD_SYNO_IO_STATS, + NFSD_SYNO_CLIENT_CTL, + NFSD_SYNO_CLIENT_EXPIRE_TIME, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + NFSD_SYNO_TOTAL_CONNECTION_STAT, + NFSD_SYNO_TOTAL_CONNECTION_RESET, + NFSD_SYNO_MAX_CONNECTION, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + NFSD_SYNO_LATENCY_HISTOGRAM, + NFSD_SYNO_TOTAL_ERROR, +#endif /* MY_ABC_HERE */ NFSD_MaxReserved }; @@ -76,6 +106,25 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size); static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size); #endif +#ifdef MY_ABC_HERE +static ssize_t set_udp_size(struct file *file, char *buf, size_t size); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static ssize_t set_unix_enable(struct file *file, char *buf, size_t size); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static ssize_t set_syno_file_stats(struct file *file, char *buf, size_t size); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static ssize_t control_syno_nfsd_client(struct file *file, char *buf, + size_t size); +static ssize_t set_syno_nfsd_client_expire_time(struct file *file, char *buf, + size_t size); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static ssize_t reset_syno_total_connection(struct file *file, char *buf, size_t size); +static ssize_t syno_max_connection(struct file *file, char *buf, size_t size); +#endif /* MY_ABC_HERE */ static ssize_t (*const write_op[])(struct file *, char *, size_t) = { [NFSD_Fh] = write_filehandle, @@ -93,6 +142,23 @@ static ssize_t (*const write_op[])(struct file *, char *, size_t) = { [NFSD_RecoveryDir] = write_recoverydir, [NFSD_V4EndGrace] = write_v4_end_grace, #endif +#ifdef MY_ABC_HERE + [NFSD_UDP_Size] = set_udp_size, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_UNIX_PRI] = set_unix_enable, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_FILE_STATS] = set_syno_file_stats, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_CLIENT_CTL] = control_syno_nfsd_client, + [NFSD_SYNO_CLIENT_EXPIRE_TIME] = set_syno_nfsd_client_expire_time, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_TOTAL_CONNECTION_RESET] = reset_syno_total_connection, + [NFSD_SYNO_MAX_CONNECTION] = syno_max_connection, +#endif /* MY_ABC_HERE */ }; static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) @@ -228,6 +294,38 @@ static const struct file_operations reply_cache_stats_operations = { .release = single_release, }; +#ifdef MY_ABC_HERE +static const struct file_operations syno_io_stat_ops = { + .open = syno_nfsd_io_total_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static const struct file_operations syno_total_connection_stat_ops = { + .open = syno_nfsd_total_connection_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +static const struct file_operations syno_latency_histogram_ops = { + .open = syno_nfsd_latency_histogram_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations syno_total_error_ops = { + .open = syno_nfsd_total_error_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* MY_ABC_HERE */ /*----------------------------------------------------------------------------*/ /* * payload - write methods @@ -540,6 +638,426 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) return rv; } +#ifdef MY_ABC_HERE +u32 nfs_udp_f_rtpref; +u32 nfs_udp_f_wtpref; + +static ssize_t set_udp_size(struct file *file, char *buf, size_t size) +{ + int err = 0; + u32 prefer_read_size = CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE; + u32 prefer_write_size = CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE; + + if (size == 0) + goto End; + + // use sscanf to get read and write size + if (sscanf(buf, "%u %u", &prefer_read_size, &prefer_write_size) != 2) { + err = -EINVAL; + goto End; + } + + // make sure the packet size is on the range we want + if (CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE > prefer_read_size || CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE < prefer_read_size || + CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE > prefer_write_size || CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE < prefer_write_size) { + err = -EINVAL; + goto End; + } + + nfs_udp_f_rtpref = prefer_read_size; + nfs_udp_f_wtpref = prefer_write_size; + +End: + if (err) + return err; + else + return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "rsize=%d,wsize=%d\n", nfs_udp_f_rtpref, nfs_udp_f_wtpref); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +u32 bl_unix_pri_enable; + +static ssize_t set_unix_enable(struct file *file, char *buf, size_t size) +{ + int err = 0; + u32 bl_tmp_unix_pri_enable; + + if (size == 0) + goto End; + + // use sscanf to get if unix privilege enable + if (sscanf(buf, "%u", &bl_tmp_unix_pri_enable) != 1) { + err = -EINVAL; + printk(KERN_ERR "NFSD error wrong format of unix_pri_enable in /proc\n"); + goto End; + } + + // check if value valid + if (bl_tmp_unix_pri_enable != 0 && bl_tmp_unix_pri_enable != 1) { + err = -EINVAL; + printk(KERN_ERR "NFSD error wrong value of unix_pri_enable in /proc %u\n", bl_unix_pri_enable); + goto End; + } + + bl_unix_pri_enable = bl_tmp_unix_pri_enable; +End: + if (err) + return err; + else + return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%u\n", bl_unix_pri_enable); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct syno_file_stats *syno_file_stats; + +/** + * strcpy in lower case + */ +static inline char *strcpy_lower_case(char *dst, char *src) +{ + char *tmp = dst; + + while ((*dst++ = tolower(*src++)) != '\0') + /* nothing */; + return tmp; +} + +static int show_syno_file_stats(char *buf, size_t len, + struct syno_file_stats *stats) +{ + int i; + int ret; + char *buf_tail = buf; + size_t size = SIMPLE_TRANSACTION_LIMIT; + + if (!stats || stats->nr_keys == 0) { + ret = 0; + goto out; + } + + ret = scnprintf(buf_tail, size, "freq=%d, opt=%d, nr_keys=%d\n", + stats->freq, stats->opt, stats->nr_keys); + + if (ret <= 0) + goto out; + buf_tail += ret; + size -= ret; + + /* key:cnter */ + for (i = 0; i < stats->nr_keys; i++) { + ret = scnprintf(buf_tail, size, "%s:%llu\n", stats->keys[i], stats->cnters[i]); + if (ret <= 0) + goto out; + buf_tail += ret; + size -= ret; + } + + ret = (buf_tail - buf); +out: + return ret; +} + +static void free_syno_file_stats(struct syno_file_stats *stats) +{ + int i; + + if (!stats) + return; + + for (i = 0; i < stats->nr_keys; i++) { + if (!stats->keys || !stats->keys[i]) + break; + kfree(stats->keys[i]); + } + + kfree(stats->keys); + kfree(stats->cnters); + kfree(stats); +} + +static void __update_syno_file_stats(struct syno_file_stats *stats, + struct dentry *dentry) +{ + int i; + size_t dlen; + char *buf = NULL; + struct name_snapshot d_name_snap; + const char *target = NULL; + ktime_t now = ktime_get(); + + if (!stats || !dentry) + return; + if (ktime_before(now, stats->next_update_time)) + return; + + take_dentry_name_snapshot(&d_name_snap, dentry); + dlen = strlen(d_name_snap.name.name); + if (dlen == 0) + goto out_update_time; + if (dlen == 1 && d_name_snap.name.name[0] == '/') + goto out_update_time; /* skip if dentry is '/' (root or disconnected) */ + + if (stats->opt & NFSD_SYNO_FILE_STATS_OPTION_CASE_INSENSITIVE) { + buf = (char *) kmalloc(dlen + 1, GFP_KERNEL); + if (!buf) + goto out_update_time; /* update next time, don't retry */ + target = (const char *) strcpy_lower_case(buf, (char *) d_name_snap.name.name); + } else { + target = d_name_snap.name.name; + } + + for (i = 0; i < stats->nr_keys; i++) + if (strstr(target, stats->keys[i])) + stats->cnters[i]++; + +out_update_time: + stats->next_update_time = ktime_add_ms(now, (s64)stats->freq*1000); + release_dentry_name_snapshot(&d_name_snap); + kfree(buf); +} + +void update_syno_file_stats(struct dentry *dentry) +{ + if (!mutex_trylock(&nfsd_mutex)) + return; + __update_syno_file_stats(syno_file_stats, dentry); + mutex_unlock(&nfsd_mutex); +} + +static int parse_syno_file_stats(char *buf, size_t len, + struct syno_file_stats *stats) +{ + int ret, nr, word_len; + char *word; + char *mesg = buf; + + ret = get_int(&mesg, &stats->freq); + if (ret) + goto out; + + if (stats->freq == 0) { + ret = 0; // if we get freq == 0, clean syno_file_stats outside + goto out; + } + + if (stats->freq < 10) { + ret = -EINVAL; + goto out; + } + + ret = get_int(&mesg, &stats->opt); + if (ret) + goto out; + + if (syno_file_stats_has_unknown_option(stats->opt)) { + ret = -EINVAL; + goto out; + } + + ret = get_int(&mesg, &stats->nr_keys); + if (ret) + goto out; + + if (stats->nr_keys <= 0 || + stats->nr_keys > NFSD_SYNO_FILE_STATS_KEY_MAX) { + ret = -EINVAL; + goto out; + } + + stats->cnters = (u64 *) kzalloc(sizeof(u64)*stats->nr_keys, GFP_KERNEL); + if (!stats->cnters) { + ret = -ENOMEM; + goto out; + } + stats->keys = (char **) kzalloc(sizeof(char *)*stats->nr_keys, GFP_KERNEL); + if (!stats->keys) { + ret = -ENOMEM; + goto out; + } + + nr = 0; + word = buf; + while ((word_len = qword_get(&mesg, word, len)) > 0) { + stats->keys[nr] = (char *) kmalloc(word_len + 1, GFP_KERNEL); + if (!stats->keys[nr]) { + ret = -ENOMEM; + goto out; + } + + if (stats->opt & NFSD_SYNO_FILE_STATS_OPTION_CASE_INSENSITIVE) + strcpy_lower_case(stats->keys[nr], word); + else + strcpy(stats->keys[nr], word); + nr++; + } + if (nr != stats->nr_keys) { + ret = -EINVAL; + goto out; + } + + ret = 0; +out: + return ret; +} + +static ssize_t __set_syno_file_stats(struct file *file, char *buf, size_t size) +{ + int ret; + struct syno_file_stats *tmp_stats = NULL; + + if (size <= 0) + goto out_show; + + if (buf[size - 1] != '\n') { + ret = -EINVAL; + goto out; + } + buf[size - 1] = 0; + + tmp_stats = (struct syno_file_stats *) + kzalloc(sizeof(struct syno_file_stats), GFP_KERNEL); + if (!tmp_stats) { + ret = -ENOMEM; + goto out; + } + + ret = parse_syno_file_stats(buf, size, tmp_stats); + if (ret) + goto out; + + if (syno_file_stats) + free_syno_file_stats(syno_file_stats); + + if (tmp_stats->freq == 0) { + syno_file_stats = NULL; + } else { + syno_file_stats = tmp_stats; + tmp_stats = NULL; + } + +out_show: + ret = show_syno_file_stats(buf, size, syno_file_stats); +out: + if (tmp_stats) + free_syno_file_stats(tmp_stats); + return ret; +} + +static ssize_t set_syno_file_stats(struct file *file, char *buf, size_t size) +{ + ssize_t ret; + + mutex_lock(&nfsd_mutex); + ret = __set_syno_file_stats(file, buf, size); + mutex_unlock(&nfsd_mutex); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static struct task_struct *g_syno_nfsd_client_manager_kthread = NULL; + +struct nfsd_net *syno_nfsd_net_get(void) +{ + struct net *net = current->nsproxy->net_ns; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + return nn; +} + +static ssize_t control_syno_nfsd_client(struct file *file, char *buf, + size_t size) +{ + ssize_t ret; + mutex_lock(&nfsd_mutex); + ret = syno_nfsd_client_ctl(buf, size); + mutex_unlock(&nfsd_mutex); + return ret; +} + +static int syno_nfsd_client_manager_kthread(void *arg) +{ + do { + const int delay = syno_nfsd_client_expire_time_get() * HZ; + syno_nfsd_client_cleaner(); + schedule_timeout_interruptible(delay); + } while(!kthread_should_stop()); + return 0; +} + +static ssize_t set_syno_nfsd_client_expire_time(struct file *file, char *buf, + size_t size) +{ + ssize_t ret; + int time_s; + + mutex_lock(&nfsd_mutex); + if (size <= 0) + goto out_show; + if (1 != sscanf(buf, "%d", &time_s)) { + ret = -EINVAL; + goto out; + } + if (time_s <= 0) { + ret = -EINVAL; + goto out; + } + syno_nfsd_client_expire_time_set(time_s); + if (g_syno_nfsd_client_manager_kthread) + wake_up_process(g_syno_nfsd_client_manager_kthread); + +out_show: + ret = scnprintf(buf, size, "%d\n", syno_nfsd_client_expire_time_get()); +out: + mutex_unlock(&nfsd_mutex); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static ssize_t syno_max_connection(struct file *file, char *buf, size_t size) +{ + ssize_t ret; + int op; + + mutex_lock(&nfsd_mutex); + if (size <= 0) + goto out_show; + if (1 != sscanf(buf, "%d", &op)) { + ret = -EINVAL; + goto out; + } + if (op == 0) + syno_nfsd_max_connection_init(); + +out_show: + ret = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", syno_nfsd_max_connection()); +out: + mutex_unlock(&nfsd_mutex); + return ret; +} + +static ssize_t reset_syno_total_connection(struct file *file, char *buf, size_t size) +{ + ssize_t ret; + int op; + + mutex_lock(&nfsd_mutex); + if (size <= 0 || 1 != sscanf(buf, "%d", &op)) { + ret = -EINVAL; + goto out; + } + if (op == 1) + syno_nfsd_total_connection_reset(); + + ret = 0; +out: + mutex_unlock(&nfsd_mutex); + return ret; +} +#endif /* MY_ABC_HERE */ + static ssize_t nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining, const char *sep, unsigned vers, int minor) @@ -1151,7 +1669,11 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size) */ /* Basically copying rpc_get_inode. */ -static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode) +#ifdef MY_ABC_HERE +#elif /* MY_ABC_HERE */ +static +#endif /* MY_ABC_HERE */ +struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode) { struct inode *inode = new_inode(sb); if (!inode) @@ -1372,6 +1894,30 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_V4EndGrace] = {"v4_end_grace", &transaction_ops, S_IWUSR|S_IRUGO}, #endif +#ifdef MY_ABC_HERE + [NFSD_UDP_Size] = {"udppacketsize", &transaction_ops, S_IWUSR|S_IRUGO}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_UNIX_PRI] = {"unix_privilege_enable", &transaction_ops, S_IWUSR|S_IRUGO}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_FILE_STATS] = {"syno_file_stats", &transaction_ops, S_IWUSR|S_IRUGO}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_IO_STATS] = {"syno_io_stat", &syno_io_stat_ops, S_IRUGO}, + [NFSD_SYNO_CLIENT_CTL] = {"syno_client_ctl", &transaction_ops, S_IWUSR}, + [NFSD_SYNO_CLIENT_EXPIRE_TIME] = {"syno_client_expire_time", &transaction_ops, S_IWUSR|S_IRUGO}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_TOTAL_CONNECTION_STAT] = {"syno_total_connection_stat", + &syno_total_connection_stat_ops, S_IRUGO}, + [NFSD_SYNO_TOTAL_CONNECTION_RESET] = {"syno_total_connection_reset", &transaction_ops, S_IWUSR}, + [NFSD_SYNO_MAX_CONNECTION] = {"syno_max_connection", &transaction_ops, S_IWUSR|S_IRUGO}, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + [NFSD_SYNO_LATENCY_HISTOGRAM] = {"syno_latency_histogram", &syno_latency_histogram_ops, S_IRUGO}, + [NFSD_SYNO_TOTAL_ERROR] = {"syno_total_error", &syno_total_error_ops, S_IRUGO}, +#endif /* MY_ABC_HERE */ /* last one */ {""} }; @@ -1382,6 +1928,12 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) if (IS_ERR(dentry)) return PTR_ERR(dentry); nn->nfsd_client_dir = dentry; +#ifdef MY_ABC_HERE + dentry = nfsd_mkdir(sb->s_root, NULL, "syno_clients"); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + nn->nfsd_syno_client_dir = dentry; +#endif /* MY_ABC_HERE */ return 0; } @@ -1522,9 +2074,39 @@ static int __init init_nfsd(void) int retval; printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); +#ifdef MY_ABC_HERE + /* initial default udp packet size */ + nfs_udp_f_rtpref = CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE; + nfs_udp_f_wtpref = CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + bl_unix_pri_enable = 1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_file_stats = NULL; +#endif /* MY_ABC_HERE */ + retval = register_cld_notifier(); if (retval) return retval; +#ifdef MY_ABC_HERE + syno_nfsd_connection_init(); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_nfsd_io_total_stat_init(); + + g_syno_nfsd_client_manager_kthread = + kthread_run(syno_nfsd_client_manager_kthread, NULL, + "syno_nfsd_client_manager"); + if (IS_ERR(g_syno_nfsd_client_manager_kthread)) { + retval = PTR_ERR(g_syno_nfsd_client_manager_kthread); + g_syno_nfsd_client_manager_kthread = NULL; + goto out_unregister_notifier; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_nfsd_udc_stat_init(); +#endif /* MY_ABC_HERE */ retval = nfsd4_init_slabs(); if (retval) goto out_unregister_notifier; @@ -1561,11 +2143,29 @@ static int __init init_nfsd(void) nfsd4_free_slabs(); out_unregister_notifier: unregister_cld_notifier(); +#ifdef MY_ABC_HERE + if (g_syno_nfsd_client_manager_kthread) + kthread_stop(g_syno_nfsd_client_manager_kthread); + g_syno_nfsd_client_manager_kthread = NULL; +#endif /* MY_ABC_HERE */ return retval; } static void __exit exit_nfsd(void) { +#ifdef MY_ABC_HERE + free_syno_file_stats(syno_file_stats); + syno_file_stats = NULL; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (g_syno_nfsd_client_manager_kthread) + kthread_stop(g_syno_nfsd_client_manager_kthread); + g_syno_nfsd_client_manager_kthread = NULL; + syno_nfsd_io_total_stat_destroy(); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + syno_nfsd_connection_destroy(); +#endif /* MY_ABC_HERE */ unregister_pernet_subsys(&nfsd_net_ops); nfsd_drc_slab_free(); remove_proc_entry("fs/nfs/exports", NULL); diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index cb742e17e04a..439288122510 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Hodge-podge collection of knfsd-related stuff. @@ -62,6 +65,28 @@ struct readdir_cd { __be32 err; /* 0, nfserr, or nfserr_eof */ }; +#ifdef MY_ABC_HERE +#define NFSD_SYNO_FILE_STATS_KEY_MAX 128 + +#define NFSD_SYNO_FILE_STATS_OPTION_CASE_INSENSITIVE 0x0001 +#define NFSD_SYNO_FILE_STATS_OPTION_SUPP (NFSD_SYNO_FILE_STATS_OPTION_CASE_INSENSITIVE) + +static inline bool syno_file_stats_has_unknown_option(int opt) +{ + return ((opt & (~NFSD_SYNO_FILE_STATS_OPTION_SUPP)) != 0); +} + +struct syno_file_stats { + int freq; /* sec */ + int opt; + int nr_keys; + char **keys; + u64 *cnters; + ktime_t next_update_time; +}; + +void update_syno_file_stats(struct dentry *dentry); +#endif /* MY_ABC_HERE */ extern struct svc_program nfsd_program; extern const struct svc_version nfsd_version2, nfsd_version3, @@ -487,4 +512,8 @@ static inline int nfsd4_is_junction(struct dentry *dentry) #endif /* CONFIG_NFSD_V4 */ +#ifdef MY_ABC_HERE +struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode); +#endif /* MY_ABC_HERE */ + #endif /* LINUX_NFSD_NFSD_H */ diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index c81dbbad8792..aa008590c15a 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * NFS server file handle treatment. @@ -16,6 +19,10 @@ #include "auth.h" #include "trace.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #define NFSDDBG_FACILITY NFSDDBG_FH @@ -40,7 +47,14 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); +#ifdef MY_ABC_HERE + if (IS_SYNOACL(parent)) + err = synoacl_op_permission(parent, MAY_EXEC); + else + err = inode_permission(d_inode(parent), MAY_EXEC); +#else /* MY_ABC_HERE */ err = inode_permission(d_inode(parent), MAY_EXEC); +#endif /* MY_ABC_HERE */ if (err < 0) { dput(parent); break; @@ -421,6 +435,16 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp, int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4; int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK); +#ifdef MY_ABC_HERE + // ESXi nfs client cannot handle FILEID_BTRFS_WITH_PARENT properly, + // such that we can't enable subtreecheck to solve WINACL inheritance problem + if (dentry->d_sb->s_magic != BTRFS_SUPER_MAGIC) { + // in order to let fh have parent ino for ACL inherit + // We need force encode fh to add parent ino into fid + subtreecheck = 1; + } +#endif + fhp->fh_handle.fh_fileid_type = exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck); fhp->fh_handle.fh_size += maxsize * 4; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 0d71549f9d42..55cd8a04a63f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Process version 2 NFS requests. @@ -11,6 +14,14 @@ #include "xdr.h" #include "vfs.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ + #define NFSDDBG_FACILITY NFSDDBG_PROC static __be32 @@ -89,6 +100,16 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) if (delta < 0) delta = -delta; +#ifdef MY_ABC_HERE + if (delta < MAX_TOUCH_TIME_ERROR) { + if (IS_SYNOACL(fhp->fh_dentry) && + synoacl_op_setattr_prepare(fhp->fh_dentry, iap) != 0) { + iap->ia_valid &= ~BOTH_TIME_SET; + } else if (setattr_prepare(fhp->fh_dentry, iap) != 0) { + iap->ia_valid &= ~BOTH_TIME_SET; + } + } +#else /* MY_ABC_HERE */ if (delta < MAX_TOUCH_TIME_ERROR && setattr_prepare(fhp->fh_dentry, iap) != 0) { /* @@ -98,6 +119,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) */ iap->ia_valid &= ~BOTH_TIME_SET; } +#endif /* MY_ABC_HERE */ } resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0); @@ -605,6 +627,204 @@ nfsd_proc_statfs(struct svc_rqst *rqstp) return rpc_success; } +#ifdef MY_ABC_HERE +/* + * Enable NFS VAAI plugin to reserve space. + * Only support pre-allocate blocks for now. + */ +static __be32 +nfsd_proc_fallocate(struct svc_rqst *rqstp) +{ + struct nfsd_writeargs *argp = rqstp->rq_argp; + struct nfsd_attrstat *resp = rqstp->rq_resp; + __be32 be_cnt; + unsigned long cnt; + unsigned int nvecs; + loff_t offset = argp->offset; + + /* + * offset was divided by NFS2_MAXZEROEDSIZE in synonfs-vaai-plugin, + * so we need to multiple NFS2_MAXZEROEDSIZE here to get offset in + * bytes. + */ + offset *= NFS2_MAXZEROEDSIZE; + + nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, + &argp->first, argp->len); + if (!nvecs) { + dprintk("nfsd: ERROR WRITEZERO: no data in rq_arg\n"); + resp->status = nfserr_io; + goto out; + } + memcpy(&be_cnt, rqstp->rq_vec[0].iov_base, sizeof(be_cnt)); + + cnt = ntohl(be_cnt); + + if (cnt > NFS2_MAXZEROEDSIZE) { + dprintk("nfsd: ERROR WRITEZERO zeroed byte %lu too large\n", cnt); + cnt = NFS2_MAXZEROEDSIZE; + } + + dprintk("nfsd: WRITEZERO %s %lu zero bytes at %llu\n", + SVCFH_fmt(&argp->fh), cnt, offset); + + resp->status = nfsd_fallocate(rqstp, fh_copy(&resp->fh, &argp->fh), + offset, &cnt); + + dprintk("nfsd: WRITEZERO block count:%llu, status:%u\n", + resp->stat.blocks, resp->status); + + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) + return rpc_drop_reply; +out: + return rpc_success; +} + +static __be32 +nfsd_proc_xlookup(struct svc_rqst *rqstp) +{ + struct nfsd_diropargs *argp = rqstp->rq_argp; + struct nfsd_diropres *resp = rqstp->rq_resp; + dprintk("nfsd: XLOOKUP %s %.*s\n", + SVCFH_fmt(&argp->fh), argp->len, argp->name); + + fh_init(&resp->fh, NFS_FHSIZE); + resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, + &resp->fh); + fh_put(&argp->fh); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); + if (resp->status != nfs_ok) + goto out; + + dprintk("nfsd: XLOOKUP file block count %lld\n", resp->stat.blocks); + + /* + * File size and block size might overflow 32bit data types + * therefore use unused inode no. slot extends the size representation range + * TODO: + */ + + resp->stat.ino = resp->stat.size >> 32; + resp->stat.size &= (NFS2_4G - 1); + resp->stat.ino |= (resp->stat.blocks >> 32) << 16; + resp->stat.blocks &= (NFS2_4G - 1); + + /* + * We keep the filesystem in-memory magic in nlink in order to let plug-in identify the filesystem + */ + if (resp->fh.fh_dentry && resp->fh.fh_dentry->d_inode) + resp->stat.nlink = resp->fh.fh_dentry->d_inode->i_sb->s_magic; + else + resp->stat.nlink = 0; + +out: + if (!(resp->fh.fh_dentry)) + printk(KERN_WARNING "nfsd: XLOOKUP resp->fh.fh_dentery is null\n"); + else if (!(resp->fh.fh_dentry->d_inode)) + printk(KERN_WARNING "nfsd: XLOOKUP resp->fh.fh_dentry->d_inode is null\n"); + return rpc_success; +} + +static __be32 +nfsd_proc_synocopy(struct svc_rqst *rqstp) +{ + struct nfsd_writeargs *argp = rqstp->rq_argp; + struct nfsd_attrstat *resp = rqstp->rq_resp; + __be32 be_cnt; + unsigned long cnt; + loff_t offset = argp->offset; + int fn_offset; + bool skip_zero; + char zero_buf[sizeof(__be32)] = {0}; + unsigned int nvecs; + + /* + * offset was divided by NFS2_SYNOCOPYSIZE in synonfs-vaai-plugin, + * so we need to multiple NFS2_SYNOCOPYSIZE here to get offset in + * bytes. + */ + offset *= NFS2_SYNOCOPYSIZE; + + + nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, + &argp->first, argp->len); + if (!nvecs) { + dprintk("nfsd: ERROR WRITEZERO: no data in rq_arg\n"); + resp->status = nfserr_io; + goto out; + } + memcpy(&be_cnt, rqstp->rq_vec[0].iov_base, sizeof(__be32)); + + cnt = ntohl(be_cnt); + + if (cnt > NFS2_SYNOCOPYSIZE) { + dprintk("nfsd: ERROR SYNOCOPY copyed byte %lu too large\n", cnt); + cnt = NFS2_SYNOCOPYSIZE; + } + + skip_zero = (0 != memcmp(rqstp->rq_vec[0].iov_base + sizeof(__be32), zero_buf, sizeof(__be32))); + + fn_offset = sizeof(__be32) + sizeof(__be32); + + dprintk("nfsd: SYNOCOPY from %s %lu bytes at %llu\n", + (char *)(rqstp->rq_vec[0].iov_base + fn_offset), + cnt, offset); + + resp->status = nfsd_synocopy((const char *)(rqstp->rq_vec[0].iov_base + fn_offset), rqstp, fh_copy(&resp->fh, &argp->fh), + offset, &cnt, skip_zero); + + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) + return rpc_drop_reply; +out: + return rpc_success; +} + +static __be32 +nfsd_proc_synosupport(struct svc_rqst *rqstp) +{ + return rpc_success; +} + +#ifdef MY_ABC_HERE +static __be32 +nfsd_proc_synoclone(struct svc_rqst *rqstp) +{ + struct nfsd_writeargs *argp = rqstp->rq_argp; + struct nfsd_attrstat *resp = rqstp->rq_resp; + int offset; + unsigned int nvecs; + + nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, + &argp->first, argp->len); + if (!nvecs) { + dprintk("nfsd: ERROR WRITEZERO: no data in rq_arg\n"); + resp->status = nfserr_io; + goto out; + } + offset = sizeof(__be32) + sizeof(__be32); + + dprintk("nfsd: SYNOCLONE from %s \n", + (char *)(rqstp->rq_vec[0].iov_base + offset)); + + resp->status = nfsd_synoclone((const char *)(rqstp->rq_vec[0].iov_base + offset), rqstp, fh_copy(&resp->fh, &argp->fh)); + + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) + return rpc_drop_reply; +out: + return rpc_success; +} +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + /* * NFSv2 Server procedures. * Only the results of non-idempotent operations are cached. @@ -615,7 +835,15 @@ struct nfsd_void { int dummy; }; #define FH 8 /* filehandle */ #define AT 18 /* attributes */ +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +static const struct svc_procedure nfsd_procedures2[33] = { +#else /* MY_ABC_HERE */ +static const struct svc_procedure nfsd_procedures2[32] = { +#endif /* MY_ABC_HERE */ +#else /* MY_ABC_HERE */ static const struct svc_procedure nfsd_procedures2[18] = { +#endif /* MY_ABC_HERE */ [NFSPROC_NULL] = { .pc_func = nfsd_proc_null, .pc_decode = nfssvc_decode_void, @@ -784,17 +1012,121 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_cachetype = RC_NOCACHE, .pc_xdrressize = ST+5, }, +#ifdef MY_ABC_HERE + {}, /* for future extension */ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + [NFSPROC_SYNO_WRITEZERO] = { + .pc_func = nfsd_proc_fallocate, + .pc_decode = nfssvc_decode_writeargs, + .pc_encode = nfssvc_encode_attrstat, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_writeargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, + }, + [NFSPROC_SYNO_XLOOKUP] = { + .pc_func = nfsd_proc_xlookup, + .pc_decode = nfssvc_decode_diropargs, + .pc_encode = nfssvc_encode_diropres, + .pc_release = nfssvc_release_diropres, + .pc_argsize = sizeof(struct nfsd_diropargs), + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+FH+AT, + }, + [NFSPROC_SYNO_COPY] = { + .pc_func = nfsd_proc_synocopy, + .pc_decode = nfssvc_decode_writeargs, + .pc_encode = nfssvc_encode_attrstat, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_writeargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, + }, + [NFSPROC_SYNO_SUPPORT] = { + .pc_func = nfsd_proc_synosupport, + .pc_decode = nfssvc_decode_void, + .pc_encode = nfssvc_encode_void, + .pc_argsize = sizeof(struct nfsd_void), + .pc_ressize = sizeof(struct nfsd_void), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, + }, +#ifdef MY_ABC_HERE + [NFSPROC_SYNO_CLONE] = { + .pc_func = nfsd_proc_synoclone, + .pc_decode = nfssvc_decode_writeargs, + .pc_encode = nfssvc_encode_attrstat, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_writeargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, + }, +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE +static void nfsd_store_latency(u64 rpc_lat, u64 vfs_lat, u32 op) +{ + enum syno_nfsd_io_stat_type type; + if (op != NFSPROC_READ && op != NFSPROC_WRITE) + return; + type = (op == NFSPROC_READ) ? SYNO_NFSD_IO_READ : SYNO_NFSD_IO_WRITE; + syno_nfsd_store_latency_into_histogram(SYNO_NFSD_USEC_TO_SEC(rpc_lat), + SYNO_NFSD_USEC_TO_SEC(vfs_lat), + SYNO_NFSD_VERSION_2, type); +} + +static void nfsd_store_error(struct svc_rqst *rqstp) +{ + const struct syno_nfsd_dummy_status *st; + // rq_resp's size is from `rq_server->sv_xdrsize`, so we check on it. + if (!rqstp || !rqstp->rq_resp || + !rqstp->rq_server || rqstp->rq_server->sv_xdrsize < sizeof(struct syno_nfsd_dummy_status)) + return; + st = (const struct syno_nfsd_dummy_status *) rqstp->rq_resp; + syno_nfsd_store_error(be32_to_cpu(st->status), SYNO_NFSD_VERSION_2); +} +#endif /* MY_ABC_HERE */ static unsigned int nfsd_count2[ARRAY_SIZE(nfsd_procedures2)]; +#ifdef MY_ABC_HERE +static struct svc_lat nfsd_latency2[ARRAY_SIZE(nfsd_procedures2)]; +#endif /* MY_ABC_HERE */ const struct svc_version nfsd_version2 = { .vs_vers = 2, +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE + .vs_nproc = 33, +#else /* MY_ABC_HERE */ + .vs_nproc = 32, +#endif /* MY_ABC_HERE */ +#else /* MY_ABC_HERE */ .vs_nproc = 18, +#endif /* MY_ABC_HERE */ .vs_proc = nfsd_procedures2, .vs_count = nfsd_count2, +#ifdef MY_ABC_HERE + .vs_latency = nfsd_latency2, +#endif /* MY_ABC_HERE */ .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS2_SVC_XDRSIZE, +#ifdef MY_ABC_HERE + .vs_store_latency_to_histogram = nfsd_store_latency, + .vs_store_resp_error = nfsd_store_error, +#endif /* MY_ABC_HERE */ }; /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 9323e30a7eaf..5e4d4307ea03 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Central processing for nfsd. @@ -29,6 +32,10 @@ #include "netns.h" #include "filecache.h" +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ + #define NFSDDBG_FACILITY NFSDDBG_SVC bool inter_copy_offload_enable; @@ -427,6 +434,9 @@ static void nfsd_shutdown_net(struct net *net) struct nfsd_net *nn = net_generic(net, nfsd_net_id); nfsd_file_cache_shutdown_net(net); +#ifdef MY_ABC_HERE + syno_nfsd_clients_destroy_all(); +#endif /* MY_ABC_HERE */ nfs4_state_shutdown_net(net); if (nn->lockd_up) { lockd_down(net); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 9eae11a9d21c..bad02f757ff7 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (c) 2001 The Regents of the University of Michigan. * All rights reserved. @@ -381,6 +384,9 @@ struct nfs4_client { struct list_head async_copies; /* list of async copies */ spinlock_t async_lock; /* lock for async copies */ atomic_t cl_cb_inflight; /* Outstanding callbacks */ +#ifdef MY_ABC_HERE + bool has_syno_client; +#endif /* MY_ABC_HERE */ }; /* struct nfs4_client_reset diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index b1bc582b0493..f3a2c63fdd24 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * procfs-based user access to knfsd statistics @@ -91,14 +94,121 @@ static const struct proc_ops nfsd_proc_ops = { .proc_release = single_release, }; +#ifdef MY_ABC_HERE +static int nfsd_lat_proc_show(struct seq_file *seq, void *v) +{ + struct svc_program *prog = nfsd_svcstats.program; + const struct svc_version *vers; + unsigned int i, j; + + for (i = 0; i < prog->pg_nvers; i++) { + if (!(vers = prog->pg_vers[i])) + continue; + seq_printf(seq, "proc%d %u", i, vers->vs_nproc); + for (j = 0; j < vers->vs_nproc; j++) + seq_printf(seq, " %u", vers->vs_count[j]); + seq_putc(seq, '\n'); + + seq_printf(seq, "proc%d_lat %u", i, vers->vs_nproc); + for (j = 0; j < vers->vs_nproc; j++) + seq_printf(seq, " %llu", (u64)atomic64_read(&vers->vs_latency[j].accu)); + seq_putc(seq, '\n'); + + seq_printf(seq, "proc%d_maxlat %u", i, vers->vs_nproc); + for (j = 0; j < vers->vs_nproc; j++) + seq_printf(seq, " %u", (u32)atomic_read(&vers->vs_latency[j].max)); + seq_putc(seq, '\n'); + } + +#ifdef CONFIG_NFSD_V4 + seq_printf(seq,"proc4ops %u", LAST_NFS4_OP + 1); + for (i = 0; i <= LAST_NFS4_OP; i++) + seq_printf(seq, " %u", nfsdstats.nfs4_opcount[i]); + seq_putc(seq, '\n'); + + seq_printf(seq,"proc4ops_lat %u", LAST_NFS4_OP + 1); + for (i = 0; i <= LAST_NFS4_OP; i++) + seq_printf(seq, " %llu", (u64)atomic64_read(&nfsdstats.nfs4_oplatency[i].accu)); + seq_putc(seq, '\n'); + + seq_printf(seq,"proc4ops_maxlat %u", LAST_NFS4_OP + 1); + for (i = 0; i <= LAST_NFS4_OP; i++) + seq_printf(seq, " %u", (u32)atomic_read(&nfsdstats.nfs4_oplatency[i].max)); + seq_putc(seq, '\n'); +#endif + + return 0; +} + +static ssize_t nfsd_lat_write(struct file *file, + const char __user *buf, size_t size, loff_t * ppos) +{ + struct svc_program *prog = nfsd_svcstats.program; + const struct svc_version *vers; + ssize_t len = size; + char kbuf[11]; + int val = 0; + unsigned int i, j; + + if (len >= 10) { + len = -EINVAL; + goto End; + } + + if (copy_from_user(kbuf, buf, len)) { + len = -EFAULT; + goto End; + } + + if (1 != sscanf(kbuf, "%d", &val) || val < 0) { + len = -EINVAL; + goto End; + } + + for (i = 0; i < prog->pg_nvers; i++) { + if (!(vers = prog->pg_vers[i])) + continue; + for (j = 0; j < vers->vs_nproc; j++) + atomic_set(&vers->vs_latency[j].max, val); + } + +#ifdef CONFIG_NFSD_V4 + for (i = 0; i <= LAST_NFS4_OP; i++) + atomic_set(&nfsdstats.nfs4_oplatency[i].max, val); +#endif + +End: + return len; +} + +static int nfsd_lat_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, nfsd_lat_proc_show, NULL); +} + +static const struct proc_ops nfsd_lat_proc_ops = { + .proc_open = nfsd_lat_proc_open, + .proc_read = seq_read, + .proc_write = nfsd_lat_write, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +#endif /* MY_ABC_HERE */ + void nfsd_stat_init(void) { svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_ops); +#ifdef MY_ABC_HERE + svc_proc_register_name(&init_net, "nfsd_lat", &nfsd_svcstats, &nfsd_lat_proc_ops); +#endif /* MY_ABC_HERE */ } void nfsd_stat_shutdown(void) { svc_proc_unregister(&init_net, "nfsd"); +#ifdef MY_ABC_HERE + svc_proc_unregister(&init_net, "nfsd_lat"); +#endif /* MY_ABC_HERE */ } diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h index b23fdac69820..b528cf75c043 100644 --- a/fs/nfsd/stats.h +++ b/fs/nfsd/stats.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Statistics for NFS server. @@ -8,6 +11,9 @@ #define _NFSD_STATS_H #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ struct nfsd_stats { @@ -30,6 +36,10 @@ struct nfsd_stats { * in the cache (10percentiles). [10] = not found */ #ifdef CONFIG_NFSD_V4 unsigned int nfs4_opcount[LAST_NFS4_OP + 1]; /* count of individual nfsv4 operations */ +#ifdef MY_ABC_HERE + /* latency record of individual nfsv4 operations */ + struct svc_lat nfs4_oplatency[LAST_NFS4_OP + 1]; +#endif /* MY_ABC_HERE */ #endif }; diff --git a/fs/nfsd/syno_io_stat.c b/fs/nfsd/syno_io_stat.c new file mode 100644 index 000000000000..b0a7295fee4a --- /dev/null +++ b/fs/nfsd/syno_io_stat.c @@ -0,0 +1,1334 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#include "syno_io_stat.h" +#ifdef MY_ABC_HERE +#include "state.h" +#endif /* MY_ABC_HERE */ +#include "nfsd.h" +#include "netns.h" + +#define SYNO_NFSD_CLIENT_EXPIRE_TIME 86400 // 1 day + +#define syno_io_stat_lock() preempt_disable() +#define syno_io_stat_unlock() preempt_enable() +static atomic64_t g_syno_client_id; + +static int g_syno_client_expire_time = SYNO_NFSD_CLIENT_EXPIRE_TIME; + +/* + * We need this lock to destory client_entry even it been + * hold by some connections due to it expired. + */ +static DEFINE_MUTEX(g_syno_delete_client_mutex); + +struct syno_nfsd_io_stat { + u64 io_count[SYNO_NFSD_IO_TYPE_END]; + u64 io_bytes[SYNO_NFSD_IO_TYPE_END]; + u64 io_latency[SYNO_NFSD_IO_TYPE_END]; + u64 max_io_latency[SYNO_NFSD_IO_TYPE_END]; +}; + +struct syno_total_nfsd_io_stat { + struct syno_nfsd_io_stat io_stat[SYNO_NFSD_VERSION_END]; +}; + +struct syno_total_nfsd_io_stat __percpu *g_syno_io_stat = NULL; + +struct syno_nfsd_client_addr { + sa_family_t family; + enum syno_nfsd_version nfs_vers; + union { + struct in6_addr sin6_addr; + struct in_addr sin_addr; + }; +}; + +struct syno_nfsd_client_entry { + struct hlist_bl_node client_hash; + struct syno_nfsd_client_addr addr; + atomic_t holder; // for connection + struct kref refs; // for entry refs. + struct syno_nfsd_io_stat __percpu *vfs_io; + /* debugging info directory under nfsd/syno_clients/ : */ + struct dentry *info_dentry; + unsigned long last_used; // jiffies. +}; + +#define SYNO_NFSD_CLIENT_NRHASH 256U +#define SYNO_NFSD_CLIENT_NRHASH_MASK ((SYNO_NFSD_CLIENT_NRHASH - 1)) +static struct hlist_bl_head g_syno_nfsd_client_hosts[SYNO_NFSD_CLIENT_NRHASH]; + +static struct syno_nfsd_client_entry *alloc_client(const struct syno_nfsd_client_addr *addr); +static inline void put_client(struct syno_nfsd_client_entry *entry); +static struct syno_nfsd_client_entry *client_find(const struct syno_nfsd_client_addr addr); +static void release_client_from_inode(struct inode *inode); +static struct syno_nfsd_client_entry *__get_client_from_inode(struct inode *inode); +static struct syno_nfsd_client_entry *get_client_from_inode(struct inode *inode); +static void __client_rmdir(struct dentry *dentry); +static void client_rmdir(struct syno_nfsd_client_entry *entry); +static struct dentry *client_mkdir(struct nfsd_net *nn, + struct syno_nfsd_client_entry *entry); +static int sockaddr_to_client_addr(const struct sockaddr *s_addr, + enum syno_nfsd_version nfs_vers, + struct syno_nfsd_client_addr *addr); + +static int client_info_open(struct inode *inode, struct file *file); +static int client_io_stat_open(struct inode *inode, struct file *file); +static int client_register(struct nfsd_net *nn, + const struct syno_nfsd_client_addr addr, + struct xdr_netobj *os_name); +#ifdef MY_ABC_HERE +static void __nfsd_connection_reg(const struct xdr_netobj *os_name, struct syno_nfsd_client_addr addr); +static void inc_connection(void); +static void dec_connection(void); +#endif /* MY_ABC_HERE */ + +static inline bool is_should_expire_version(enum syno_nfsd_version nfs_vers) +{ + return (nfs_vers == SYNO_NFSD_VERSION_2) || (nfs_vers == SYNO_NFSD_VERSION_3); +} + +void syno_nfsd_client_expire_time_set(int t) +{ + g_syno_client_expire_time = t; +} +int syno_nfsd_client_expire_time_get(void) +{ + return g_syno_client_expire_time; +} + +static int io_total_stat_show(struct seq_file *m, void *v) +{ + int cpu; + int type = 0; + enum syno_nfsd_version nfs_vers; + struct syno_total_nfsd_io_stat stat; + memset(&stat, 0, sizeof(stat)); + + if (!g_syno_io_stat) + return -EIO; + + for_each_possible_cpu(cpu) { + struct syno_total_nfsd_io_stat *ptr = per_cpu_ptr(g_syno_io_stat, cpu); + + for (nfs_vers = SYNO_NFSD_VERSION_2; nfs_vers < SYNO_NFSD_VERSION_END; ++nfs_vers) { + for (type = SYNO_NFSD_IO_READ; type < SYNO_NFSD_IO_TYPE_END; ++type) { + stat.io_stat[nfs_vers].io_count[type] += + ptr->io_stat[nfs_vers].io_count[type]; + stat.io_stat[nfs_vers].io_bytes[type] += + ptr->io_stat[nfs_vers].io_bytes[type]; + stat.io_stat[nfs_vers].io_latency[type] += + ptr->io_stat[nfs_vers].io_latency[type]; + stat.io_stat[nfs_vers].max_io_latency[type] = max( + stat.io_stat[nfs_vers].max_io_latency[type], + ptr->io_stat[nfs_vers].max_io_latency[type]); + } + } + } + + for (nfs_vers = SYNO_NFSD_VERSION_2; nfs_vers < SYNO_NFSD_VERSION_END; ++nfs_vers) { + for (type = SYNO_NFSD_IO_READ; type < SYNO_NFSD_IO_TYPE_END; ++type) + seq_printf(m, "%llu %llu %llu %llu\n", + stat.io_stat[nfs_vers].io_count[type], + stat.io_stat[nfs_vers].io_bytes[type], + stat.io_stat[nfs_vers].io_latency[type], + stat.io_stat[nfs_vers].max_io_latency[type]); + } + return 0; +} + +int syno_nfsd_io_total_stat_open(struct inode *inode, struct file *file) +{ + return single_open(file, io_total_stat_show, NULL); +} + +void syno_nfsd_io_total_stat_init(void) +{ + int i; + atomic64_set(&g_syno_client_id, 0); + g_syno_io_stat = alloc_percpu(*g_syno_io_stat); + if (g_syno_io_stat) { + for_each_possible_cpu(i) + memset(per_cpu_ptr(g_syno_io_stat, i), 0, sizeof(struct syno_total_nfsd_io_stat)); + } + + for (i = 0; i < ARRAY_SIZE(g_syno_nfsd_client_hosts); i++) + INIT_HLIST_BL_HEAD(&g_syno_nfsd_client_hosts[i]); +} + +void syno_nfsd_io_total_stat_destroy(void) +{ + free_percpu(g_syno_io_stat); + g_syno_io_stat = NULL; +} + +static inline void update_total_io_stat(enum syno_nfsd_version nfs_vers, + enum syno_nfsd_io_stat_type type, + s64 bytes, s64 latency) +{ + if (!g_syno_io_stat) + return; + syno_io_stat_lock(); + __this_cpu_inc(g_syno_io_stat->io_stat[nfs_vers].io_count[type]); + __this_cpu_add(g_syno_io_stat->io_stat[nfs_vers].io_bytes[type], bytes); + __this_cpu_add(g_syno_io_stat->io_stat[nfs_vers].io_latency[type], latency); + __this_cpu_write(g_syno_io_stat->io_stat[nfs_vers].max_io_latency[type], + max((u64)latency, + __this_cpu_read(g_syno_io_stat->io_stat[nfs_vers].max_io_latency[type]))); + syno_io_stat_unlock(); +} + +static inline void update_client_io_stat(struct sockaddr *s_addr, + enum syno_nfsd_version nfs_vers, + enum syno_nfsd_io_stat_type type, + s64 bytes, s64 latency) +{ + int ret; + struct syno_nfsd_client_addr addr; + struct syno_nfsd_client_entry *entry; + + ret = sockaddr_to_client_addr(s_addr, nfs_vers, &addr); + if (ret) + return; +retry: + entry = client_find(addr); + if (!entry) { + struct nfsd_net *nn = syno_nfsd_net_get(); + if (!nn) + return; + ret = client_register(nn, addr, NULL); + if (ret) + return; + goto retry; + } + + syno_io_stat_lock(); + __this_cpu_inc(entry->vfs_io->io_count[type]); + __this_cpu_add(entry->vfs_io->io_bytes[type], bytes); + __this_cpu_add(entry->vfs_io->io_latency[type], latency); + __this_cpu_write(entry->vfs_io->max_io_latency[type], + max((u64)latency, __this_cpu_read(entry->vfs_io->max_io_latency[type]))); + syno_io_stat_unlock(); + entry->last_used = jiffies; + put_client(entry); + + return; +} + +static int sockaddr_to_client_addr(const struct sockaddr *s_addr, enum syno_nfsd_version nfs_vers, + struct syno_nfsd_client_addr *addr) +{ + const struct sockaddr_in *sin; + const struct sockaddr_in6 *sin6; + + if (!s_addr || !addr) + return -EINVAL; + + sin = (const struct sockaddr_in *)s_addr; + sin6 = (const struct sockaddr_in6 *)s_addr; + addr->family = s_addr->sa_family; + addr->nfs_vers = nfs_vers; + + switch (addr->family) { + case AF_INET: + addr->sin_addr = sin->sin_addr; + break; + case AF_INET6: + addr->sin6_addr = sin6->sin6_addr; + break; + default: + return -EINVAL; + } + return 0; +} + +void syno_nfsd_account_io_complete(struct sockaddr *s_addr, int version, + enum syno_nfsd_io_stat_type type, s64 bytes, + s64 latency) +{ + enum syno_nfsd_version nfs_vers = syno_nfsd_version_convert(version); + if (nfs_vers == SYNO_NFSD_VERSION_END) + return; + update_total_io_stat(nfs_vers, type, bytes, latency); + update_client_io_stat(s_addr, nfs_vers, type, bytes, latency); +} + +/* + * hash function copy from fs/lockd/host.c + */ +static inline unsigned int __hash32(const __be32 n) +{ + unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16); + return hash ^ (hash >> 8); +} + +static inline unsigned int +__client_addr_hash(const struct syno_nfsd_client_addr *addr) +{ + unsigned int hash; + if (addr->family == AF_INET6) { + hash = __hash32(addr->sin6_addr.s6_addr32[0]) ^ + __hash32(addr->sin6_addr.s6_addr32[1]) ^ + __hash32(addr->sin6_addr.s6_addr32[2]) ^ + __hash32(addr->sin6_addr.s6_addr32[3]); + } else { + hash = __hash32(addr->sin_addr.s_addr); + } + return (hash ^ __hash32(addr->nfs_vers)) & SYNO_NFSD_CLIENT_NRHASH_MASK; +} + +static struct hlist_bl_head * +client_addr_hash(const struct syno_nfsd_client_addr *addr) +{ + return &g_syno_nfsd_client_hosts[__client_addr_hash(addr)]; +} + +static inline int cmp_client_addr(const struct syno_nfsd_client_addr x, + const struct syno_nfsd_client_addr y) +{ + if (x.nfs_vers < y.nfs_vers) + return 1; + else if (x.nfs_vers > y.nfs_vers) + return -1; + + if (x.family < y.family) + return 1; + else if (x.family > y.family) + return -1; + + if (x.family == AF_INET) { + if (x.sin_addr.s_addr < y.sin_addr.s_addr) + return 1; + else if (x.sin_addr.s_addr > y.sin_addr.s_addr) + return -1; + } else { + return ipv6_addr_cmp(&x.sin6_addr, &y.sin6_addr); + } + return 0; +} + +/* + * You should aquire RCU lock before calling this function, + * and increment refs count before unlock RCU. + */ +static struct syno_nfsd_client_entry * +client_lookup_rcu(const struct syno_nfsd_client_addr addr) +{ + struct hlist_bl_head *b = client_addr_hash(&addr); + struct hlist_bl_node *node; + struct syno_nfsd_client_entry *entry; + + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "suspicious nfsd_client_lookup_rcu() usage"); + hlist_bl_for_each_entry_rcu(entry, node, b, client_hash) { + if (!cmp_client_addr(entry->addr, addr)) + return entry; + } + return NULL; +} + +static struct syno_nfsd_client_entry * +client_find(const struct syno_nfsd_client_addr addr) +{ + struct syno_nfsd_client_entry *entry; + rcu_read_lock(); + entry = client_lookup_rcu(addr); + if (!entry || !kref_get_unless_zero(&entry->refs)) { + entry = NULL; + } + rcu_read_unlock(); + return entry; +} + +static int client_register(struct nfsd_net *nn, + const struct syno_nfsd_client_addr addr, + struct xdr_netobj *os_name) +{ + bool create = false; + int ret; + struct syno_nfsd_client_entry *entry; + struct syno_nfsd_client_entry *new = NULL; + struct hlist_bl_node *node; + struct hlist_bl_head *b = client_addr_hash(&addr); + + __nfsd_connection_reg(os_name, addr); + + // Check first to prevent allocate un-necessary entry. + rcu_read_lock(); + entry = client_lookup_rcu(addr); + if (unlikely(entry)) { + if (kref_get_unless_zero(&entry->refs)) { + rcu_read_unlock(); + goto found; + } + // someone is releasing entry now, we start to create one. + } + rcu_read_unlock(); + + new = alloc_client(&addr); + if (!new) { + ret = -ENOMEM; + goto out; + } + new->info_dentry = client_mkdir(nn, new); + if (IS_ERR(new->info_dentry)) { + ret = PTR_ERR((void *)new->info_dentry); + new->info_dentry = NULL; + goto out; + } + +retry: + rcu_read_lock(); + entry = client_lookup_rcu(addr); + if (unlikely(entry)) { + if (!kref_get_unless_zero(&entry->refs)) { + rcu_read_unlock(); + goto retry; + } + rcu_read_unlock(); + goto found; + } + + hlist_bl_lock(b); + hlist_bl_for_each_entry_rcu(entry, node, b, client_hash) { + if (cmp_client_addr(entry->addr, addr) != 0) + continue; + + hlist_bl_unlock(b); + if (!kref_get_unless_zero(&entry->refs)) { + rcu_read_unlock(); + goto retry; + } + rcu_read_unlock(); + goto found; + } + rcu_read_unlock(); + hlist_bl_add_head_rcu(&new->client_hash, b); + hlist_bl_unlock(b); + create = true; + entry = new; + new = NULL; +#ifdef MY_ABC_HERE + inc_connection(); +#endif /* MY_ABC_HERE */ +found: + ret = 0; + atomic_inc(&entry->holder); + // entry is already hold by someone, we dont need to get refs during this register. + if (!create) + put_client(entry); +out: + client_rmdir(new); + put_client(new); + return ret; +} + +int syno_nfsd_client_register(struct sockaddr *s_addr, int version, struct xdr_netobj *os_name) +{ + int ret; + struct syno_nfsd_client_addr addr; + struct nfsd_net *nn = syno_nfsd_net_get(); + enum syno_nfsd_version nfs_vers = syno_nfsd_version_convert(version); + + if (!s_addr || !nn || nfs_vers == SYNO_NFSD_VERSION_END) + return -EINVAL; + + ret = sockaddr_to_client_addr(s_addr, nfs_vers, &addr); + if (ret) + return ret; + return client_register(nn, addr, os_name); +} + +static void client_unregister(const struct syno_nfsd_client_addr addr) +{ + struct syno_nfsd_client_entry *entry; + + mutex_lock(&g_syno_delete_client_mutex); + entry = client_find(addr); + if (!entry) + goto unlock; + if (atomic_dec_return(&entry->holder) > 0) + goto put_client; +#ifdef MY_ABC_HERE + dec_connection(); +#endif /* MY_ABC_HERE */ + client_rmdir(entry); + put_client(entry); + +put_client: + put_client(entry); +unlock: + mutex_unlock(&g_syno_delete_client_mutex); +} + +void syno_nfsd_client_unregister(const struct sockaddr *s_addr, int version) +{ + int ret; + struct syno_nfsd_client_addr addr; + enum syno_nfsd_version nfs_vers = syno_nfsd_version_convert(version); + + if (!s_addr || nfs_vers == SYNO_NFSD_VERSION_END) + return; + ret = sockaddr_to_client_addr(s_addr, nfs_vers, &addr); + if (ret) + return; + client_unregister(addr); +} + +static struct syno_nfsd_client_entry * +alloc_client(const struct syno_nfsd_client_addr *addr) +{ + int i; + struct syno_nfsd_client_entry *entry; + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return NULL; + INIT_HLIST_BL_NODE(&entry->client_hash); + entry->vfs_io = alloc_percpu(*entry->vfs_io); + if (!entry->vfs_io) { + kfree(entry); + return NULL; + } + for_each_possible_cpu(i) + memset(per_cpu_ptr(entry->vfs_io, i), 0, sizeof(struct syno_nfsd_io_stat)); + entry->addr = *addr; + kref_init(&entry->refs); + atomic_set(&entry->holder, 0); + entry->last_used = jiffies; + return entry; +} + +static void release_client(struct kref *kref) +{ + struct syno_nfsd_client_entry *entry = + container_of(kref, struct syno_nfsd_client_entry, refs); + struct hlist_bl_head *b = client_addr_hash(&entry->addr); + + WARN_ON(entry->info_dentry); + + hlist_bl_lock(b); + if (!hlist_bl_unhashed(&entry->client_hash)) + hlist_bl_del_rcu(&entry->client_hash); + hlist_bl_unlock(b); + + synchronize_rcu(); + free_percpu(entry->vfs_io); + kfree(entry); +} + +static inline void put_client(struct syno_nfsd_client_entry *entry) +{ + if (!entry) + return; + might_sleep(); + kref_put(&entry->refs, release_client); +} + +static int parse_client_addr(const char *buf, size_t size, + struct syno_nfsd_client_addr *client, bool *is_add) +{ + unsigned int op; + unsigned int family; + unsigned int vers; + const char *family_ptr = strchr(buf, ','); + const char *vers_ptr = (!family_ptr) ? NULL : strchr(family_ptr + 1, ','); + const char *addr_ptr = (!vers_ptr) ? NULL : strchr(vers_ptr + 1, ','); + enum syno_nfsd_version nfs_vers = SYNO_NFSD_VERSION_END; + + if (!addr_ptr || !client || !is_add) + return -EINVAL; + + if (3 != sscanf(buf, "%u,%u,%u", &op, &family, &vers)) + return -EINVAL; + if (op != 1 && op != 2) + return -EINVAL; + *is_add = (op == 1); + + nfs_vers = syno_nfsd_version_convert(vers); + if (nfs_vers == SYNO_NFSD_VERSION_END) + return -EINVAL; + + client->family = family; + client->nfs_vers = nfs_vers; + + switch (client->family) { + case AF_INET: + if (in4_pton(addr_ptr + 1, size - (addr_ptr - buf + 1), + (u8 *)&client->sin_addr.s_addr, -1, NULL) != 1) + return -EINVAL; + break; + case AF_INET6: + if (in6_pton(addr_ptr + 1, size - (addr_ptr - buf + 1), + (u8 *)&client->sin6_addr.s6_addr, -1, NULL) != 1) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +ssize_t syno_nfsd_client_ctl(char *buf, size_t size) +{ + int ret; + struct syno_nfsd_client_addr addr; + bool is_add = false; + struct nfsd_net *nn = syno_nfsd_net_get(); + + if (!nn) + return -EINVAL; + + if (!size) + return 0; + + ret = parse_client_addr(buf, size, &addr, &is_add); + if (ret) + return ret; + + if (is_add) { + ret = client_register(nn, addr, NULL); + } else { + client_unregister(addr); + ret = 0; + } + return ret; +} + +void syno_nfsd_clients_destroy_all(void) +{ + int i; + struct hlist_bl_head *b; + struct hlist_bl_node *node; + struct hlist_bl_node *tmp; + struct syno_nfsd_client_entry *entry; + + mutex_lock(&g_syno_delete_client_mutex); + for (i = 0; i < ARRAY_SIZE(g_syno_nfsd_client_hosts); ++i) { + b = &g_syno_nfsd_client_hosts[i]; + hlist_bl_for_each_entry_safe(entry, node, tmp, b, client_hash) { + client_rmdir(entry); + put_client(entry); + } + } + mutex_unlock(&g_syno_delete_client_mutex); +} + +void syno_nfsd_client_cleaner(void) +{ + int i; + struct hlist_bl_head *b; + struct hlist_bl_node *node; + struct hlist_bl_node *tmp; + struct syno_nfsd_client_entry *entry; + unsigned long expire_jiffie = + msecs_to_jiffies(syno_nfsd_client_expire_time_get() * HZ); + + mutex_lock(&g_syno_delete_client_mutex); + for (i = 0; i < SYNO_NFSD_CLIENT_NRHASH; ++i) { + b = &g_syno_nfsd_client_hosts[i]; + hlist_bl_for_each_entry_safe(entry, node, tmp, b, client_hash) { + if (!kref_get_unless_zero(&entry->refs)) + continue; + if (!is_should_expire_version(entry->addr.nfs_vers) || + time_after(entry->last_used + expire_jiffie, + jiffies)) { + put_client(entry); + continue; + } + client_rmdir(entry); + put_client(entry); + put_client(entry); + } + } + mutex_unlock(&g_syno_delete_client_mutex); +} + +/* + * below operations are copy from fs/nfsd/nfsctl.c nfsd_client_mkdir + */ +static struct syno_nfsd_client_entry * +__get_client_from_inode(struct inode *inode) +{ + struct syno_nfsd_client_entry *entry = inode->i_private; + entry = inode->i_private; + if (entry) + kref_get(&entry->refs); + return entry; +} + +static struct syno_nfsd_client_entry *get_client_from_inode(struct inode *inode) +{ + struct syno_nfsd_client_entry *entry; + inode_lock_shared(inode); + entry = __get_client_from_inode(inode); + inode_unlock_shared(inode); + return entry; +} + +static int __do_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, + struct syno_nfsd_client_entry *entry) +{ + struct inode *inode; + + inode = nfsd_get_inode(dir->i_sb, mode); + if (!inode) + return -ENOMEM; + if (entry) { + inode->i_private = entry; + kref_get(&entry->refs); + } + d_add(dentry, inode); + inc_nlink(dir); + fsnotify_mkdir(dir, dentry); + return 0; +} + +static struct dentry *do_mkdir(struct dentry *parent, + struct syno_nfsd_client_entry *entry, char *name) +{ + int ret; + struct inode *dir = parent->d_inode; + struct dentry *dentry = NULL; + + inode_lock(dir); + dentry = d_alloc_name(parent, name); + if (!dentry) { + ret = -ENOMEM; + goto out; + } + ret = __do_mkdir(d_inode(parent), dentry, S_IFDIR | 0600, entry); + if (ret) + goto out; + + ret = 0; +out: + inode_unlock(dir); + if (ret) { + dput(dentry); + dentry = ERR_PTR(ret); + } + return dentry; +} + +static void release_client_from_inode(struct inode *inode) +{ + struct syno_nfsd_client_entry *entry = inode->i_private; + + inode->i_private = NULL; + put_client(entry); +} + +static void remove_file(struct inode *dir, struct dentry *dentry) +{ + int ret; + + release_client_from_inode(d_inode(dentry)); + dget(dentry); + ret = simple_unlink(dir, dentry); + d_delete(dentry); + dput(dentry); + WARN_ON_ONCE(ret); +} + +static void remove_files(struct dentry *root) +{ + struct dentry *dentry, *tmp; + + list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) { + if (!simple_positive(dentry)) { + WARN_ON_ONCE(1); /* I think this can't happen? */ + continue; + } + remove_file(d_inode(root), dentry); + } +} + +static int create_files(struct dentry *root, const struct tree_descr *files) +{ + int ret; + struct inode *dir = d_inode(root); + struct inode *inode; + struct dentry *dentry; + int i; + + inode_lock(dir); + for (i = 0; files->name && files->name[0]; i++, files++) { + if (!files->name) + continue; + dentry = d_alloc_name(root, files->name); + if (!dentry) { + ret = -ENOMEM; + goto out; + } + inode = nfsd_get_inode(d_inode(root)->i_sb, + S_IFREG | files->mode); + if (!inode) { + dput(dentry); + ret = -ENOMEM; + goto out; + } + inode->i_fop = files->ops; + inode->i_private = __get_client_from_inode(dir); + d_add(dentry, inode); + fsnotify_create(dir, dentry); + } + ret = 0; +out: + if (ret) + remove_files(root); + inode_unlock(dir); + return ret; +} + +static void __client_rmdir(struct dentry *dentry) +{ + struct inode *dir = d_inode(dentry->d_parent); + struct inode *inode = d_inode(dentry); + int ret; + + inode_lock(dir); + remove_files(dentry); + release_client_from_inode(inode); + dget(dentry); + ret = simple_rmdir(dir, dentry); + WARN_ON_ONCE(ret); + fsnotify_rmdir(dir, dentry); + d_delete(dentry); + dput(dentry); + inode_unlock(dir); +} + +static void client_rmdir(struct syno_nfsd_client_entry *entry) +{ + if (!entry) + return; + if (entry->info_dentry) + __client_rmdir(entry->info_dentry); + entry->info_dentry = NULL; +} + +static const struct file_operations client_info_fops = { + .open = client_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations client_io_stat_fops = { + .open = client_io_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct tree_descr syno_client_files[] = { + [0] = { "info", &client_info_fops, S_IRUSR }, + [1] = { "io_stat", &client_io_stat_fops, S_IRUSR }, + [2] = { "" }, +}; + +static struct dentry *client_mkdir(struct nfsd_net *nn, + struct syno_nfsd_client_entry *entry) +{ + struct dentry *dentry; + char name[32]; + int ret; + s64 id; + + id = atomic64_inc_return(&g_syno_client_id); + + sprintf(name, "%lld", id); + + dentry = do_mkdir(nn->nfsd_syno_client_dir, entry, name); + if (IS_ERR(dentry)) + goto out; + + ret = create_files(dentry, syno_client_files); + if (ret) { + __client_rmdir(dentry); + dentry = ERR_PTR(ret); + goto out; + } + + ret = 0; +out: + return dentry; +} + +static int client_info_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct syno_nfsd_client_entry *entry; + + entry = get_client_from_inode(inode); + if (!entry) + return -ENXIO; + if (entry->addr.family == AF_INET) + seq_printf(m, "address: %pI4\n", &entry->addr.sin_addr); + else + seq_printf(m, "address: %pI6\n", &entry->addr.sin_addr); + seq_printf(m, "nfs vers: %u\n", entry->addr.nfs_vers); + seq_printf(m, "hash: 0x%X\n", __client_addr_hash(&entry->addr)); + put_client(entry); + + return 0; +} + +static int client_info_open(struct inode *inode, struct file *file) +{ + return single_open(file, client_info_show, inode); +} + +static int client_io_stat_show(struct seq_file *m, void *v) +{ + int i; + int cpu; + struct inode *inode = m->private; + struct syno_nfsd_client_entry *entry; + struct syno_nfsd_io_stat io_stat; + memset(&io_stat, 0, sizeof(io_stat)); + + entry = get_client_from_inode(inode); + if (!entry) + return -ENXIO; + + for_each_possible_cpu(cpu) { + struct syno_nfsd_io_stat *ptr = per_cpu_ptr(entry->vfs_io, cpu); + + for (i = SYNO_NFSD_IO_READ; i < SYNO_NFSD_IO_TYPE_END; ++i) { + io_stat.io_count[i] += ptr->io_count[i]; + io_stat.io_bytes[i] += ptr->io_bytes[i]; + io_stat.io_latency[i] += ptr->io_latency[i]; + io_stat.max_io_latency[i] = + max(io_stat.max_io_latency[i], + ptr->max_io_latency[i]); + } + } + + for (i = SYNO_NFSD_IO_READ; i < SYNO_NFSD_IO_TYPE_END; ++i) + seq_printf(m, "%llu %llu %llu %llu\n", + io_stat.io_count[i], io_stat.io_bytes[i], + io_stat.io_latency[i], + io_stat.max_io_latency[i]); + put_client(entry); + + return 0; +} + +static int client_io_stat_open(struct inode *inode, struct file *file) +{ + return single_open(file, client_io_stat_show, inode); +} + +#ifdef MY_ABC_HERE + +#define MAX_OS_ENTRIES (100) + +atomic_t g_curr_os_entries; +atomic_t g_max_connection; +atomic_t g_connection; +static DEFINE_SPINLOCK(g_connection_lock); + +struct syno_nfsd_connection_os_entry { + struct xdr_netobj os_name; + struct list_head list; + struct rb_root clients; +}; + +struct syno_nfsd_connection_client_entry { + struct rb_node node; + struct syno_nfsd_client_addr addr; +}; + +struct list_head g_os_list_head; + +void syno_nfsd_connection_init(void) +{ + atomic_set(&g_connection, 0); + atomic_set(&g_curr_os_entries, 0); + syno_nfsd_max_connection_init(); + INIT_LIST_HEAD(&g_os_list_head); +} + +void syno_nfsd_connection_destroy(void) +{ + struct syno_nfsd_connection_os_entry *os, *os_tmp; + struct syno_nfsd_connection_client_entry *client, *client_tmp; + spin_lock(&g_connection_lock); + list_for_each_entry_safe(os, os_tmp, &g_os_list_head, list) { + rbtree_postorder_for_each_entry_safe(client, client_tmp, &os->clients, node) + kfree(client); + list_del(&os->list); + kfree(os->os_name.data); + kfree(os); + } + spin_unlock(&g_connection_lock); + atomic_set(&g_curr_os_entries, 0); +} + +static void inc_connection(void) +{ + atomic_inc(&g_connection); + atomic_set(&g_max_connection, max(atomic_read(&g_connection), atomic_read(&g_connection))); +} + +static void __nfsd_connection_reg(const struct xdr_netobj *os_name, struct syno_nfsd_client_addr addr) +{ + bool exist = false; + int cmp; + struct rb_node **p = NULL; + struct rb_node *parent_node = NULL; + struct syno_nfsd_connection_os_entry *os; + struct syno_nfsd_connection_os_entry *new_os = NULL; + struct syno_nfsd_connection_client_entry *client; + struct syno_nfsd_connection_client_entry *new_client = NULL; + static const struct xdr_netobj unknown = {.len = 6, .data = "Unkown"}; + + if (!os_name || !os_name->data || !os_name->len) + os_name = &unknown; + + spin_lock(&g_connection_lock); + list_for_each_entry(os, &g_os_list_head, list) { + if (os->os_name.data && os_name->len == os->os_name.len && + 0 == memcmp(os_name->data, os->os_name.data, os_name->len)) + break; + } + if (list_entry_is_head(os, &g_os_list_head, list)) { + if (atomic_read(&g_curr_os_entries) > MAX_OS_ENTRIES) + goto out; + /* + * Since it may hold some spinlock when register connection + * we use ATOMIC flag to make sure memory allocation won't sleep + */ + new_os = kzalloc(sizeof(*new_os), GFP_ATOMIC); + if (!new_os) + goto out; + + xdr_netobj_dup(&new_os->os_name, (struct xdr_netobj *) os_name, GFP_ATOMIC); + if (!new_os->os_name.data) + goto out; + new_os->clients = RB_ROOT; + list_add_tail(&new_os->list, &g_os_list_head); + os = new_os; + new_os = NULL; + atomic_inc(&g_curr_os_entries); + } + p = &os->clients.rb_node; + while (*p) { + parent_node = *p; + client = rb_entry(parent_node, struct syno_nfsd_connection_client_entry, node); + cmp = cmp_client_addr(client->addr, addr); + if (cmp == 0) { + exist = true; + break; + } else if (cmp > 0) { + p = &(*p)->rb_left; + } else { + p = &(*p)->rb_right; + } + } + if (!exist) { + new_client = kzalloc(sizeof(*new_client), GFP_ATOMIC); + if (!new_client) + goto out; + new_client->addr = addr; + rb_link_node(&new_client->node, parent_node, p); + rb_insert_color(&new_client->node, &os->clients); + new_client = NULL; + } +out: + spin_unlock(&g_connection_lock); + if (new_os) + kfree(new_os->os_name.data); + kfree(new_os); + kfree(new_client); +} + +static void nfsd_connection_reg(struct xdr_netobj *os_name, struct sockaddr *s_addr, + enum syno_nfsd_version nfs_vers) +{ + int ret; + struct syno_nfsd_client_addr addr; + + if (!s_addr) + return; + + ret = sockaddr_to_client_addr(s_addr, nfs_vers, &addr); + if (ret) + return; + __nfsd_connection_reg(os_name, addr); +} + +static void dec_connection(void) +{ + atomic_dec(&g_connection); +} + +void syno_nfsd_max_connection_init(void) +{ + atomic_set(&g_max_connection, atomic_read(&g_connection)); +} + +int syno_nfsd_max_connection(void) +{ + return atomic_read(&g_max_connection); +} + +static int total_connection_stat_show(struct seq_file *m, void *v) +{ + int i; + int vers[SYNO_NFSD_VERSION_END] = {0}; + struct syno_nfsd_connection_os_entry *os; + struct syno_nfsd_connection_client_entry *client, *client_tmp; + + spin_lock(&g_connection_lock); + list_for_each_entry(os, &g_os_list_head, list) { + if (!os->os_name.data) + continue; + memset(vers, 0, sizeof(vers)); + rbtree_postorder_for_each_entry_safe(client, client_tmp, &os->clients, node) + vers[client->addr.nfs_vers]++; + seq_printf(m, "\""); + seq_escape_mem_ascii(m, os->os_name.data, os->os_name.len); + seq_printf(m, "\":"); + for (i = SYNO_NFSD_VERSION_2; i < SYNO_NFSD_VERSION_END; ++i) + seq_printf(m, " %d", vers[i]); + seq_printf(m, "\n"); + + } + spin_unlock(&g_connection_lock); + + return 0; +} + +int syno_nfsd_total_connection_stat_open(struct inode *inode, struct file *file) +{ + return single_open(file, total_connection_stat_show, NULL); +} + +void syno_nfsd_total_connection_reset(void) +{ + int i; + struct nfsd_net *nn = syno_nfsd_net_get(); + struct nfs4_client *clp, *clp_tmp; + struct hlist_bl_head *b; + struct hlist_bl_node *node; + struct hlist_bl_node *tmp; + struct syno_nfsd_client_entry *entry; + + syno_nfsd_connection_destroy(); + spin_lock(&nn->client_lock); + rbtree_postorder_for_each_entry_safe(clp, clp_tmp, &nn->conf_name_tree, cl_namenode) { + nfsd_connection_reg(&clp->cl_nii_name, (struct sockaddr *) &clp->cl_addr, SYNO_NFSD_VERSION_4); + } + spin_unlock(&nn->client_lock); + + mutex_lock(&g_syno_delete_client_mutex); + for (i = 0; i < ARRAY_SIZE(g_syno_nfsd_client_hosts); ++i) { + b = &g_syno_nfsd_client_hosts[i]; + hlist_bl_for_each_entry_safe(entry, node, tmp, b, client_hash) { + if (entry->addr.nfs_vers >= SYNO_NFSD_VERSION_4) + continue; + __nfsd_connection_reg(NULL, entry->addr); + } + } + mutex_unlock(&g_syno_delete_client_mutex); +} + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +enum syno_nfsd_latency_stage { + SYNO_NFSD_LATENCY_STAGE_TOTAL_RPC = 0, + SYNO_NFSD_LATENCY_STAGE_TOTAL_VFS, + SYNO_NFSD_LATENCY_STAGE_ONLY_RPC, + SYNO_NFSD_LATENCY_STAGE_END, +}; + +#define SYNO_NFSD_LATENCY_BUCKET_NR (9u) + +static DEFINE_SPINLOCK(g_latency_histogram_lock); +u64 g_latency_histogram[SYNO_NFSD_VERSION_END][SYNO_NFSD_LATENCY_STAGE_END][SYNO_NFSD_IO_TYPE_END][SYNO_NFSD_LATENCY_BUCKET_NR]; + +static DEFINE_SPINLOCK(g_errtbl_lock); + +static struct { + const int nfserr; + unsigned int counts[SYNO_NFSD_VERSION_END]; +} g_errtbl[] = { + {NFSERR_PERM, }, + {NFSERR_NOENT, }, + {NFSERR_IO, }, + {NFSERR_NXIO, }, + {NFSERR_EAGAIN, }, + {NFSERR_ACCES, }, + {NFSERR_EXIST, }, + {NFSERR_XDEV, }, + {NFSERR_NODEV, }, + {NFSERR_NOTDIR, }, + {NFSERR_ISDIR, }, + {NFSERR_INVAL, }, + {NFSERR_FBIG, }, + {NFSERR_NOSPC, }, + {NFSERR_ROFS, }, + {NFSERR_MLINK, }, + {NFSERR_OPNOTSUPP, }, + {NFSERR_NAMETOOLONG, }, + {NFSERR_NOTEMPTY, }, + {NFSERR_DQUOT, }, + {NFSERR_STALE, }, + {NFSERR_REMOTE, }, + {NFSERR_WFLUSH, }, + {NFSERR_BADHANDLE, }, + {NFSERR_NOT_SYNC, }, + {NFSERR_BAD_COOKIE, }, + {NFSERR_NOTSUPP, }, + {NFSERR_TOOSMALL, }, + {NFSERR_SERVERFAULT, }, + {NFSERR_BADTYPE, }, + {NFSERR_JUKEBOX, }, + {NFSERR_SAME, }, + {NFSERR_DENIED, }, + {NFSERR_EXPIRED, }, + {NFSERR_LOCKED, }, + {NFSERR_GRACE, }, + {NFSERR_FHEXPIRED, }, + {NFSERR_SHARE_DENIED, }, + {NFSERR_WRONGSEC, }, + {NFSERR_CLID_INUSE, }, + {NFSERR_RESOURCE, }, + {NFSERR_MOVED, }, + {NFSERR_NOFILEHANDLE, }, + {NFSERR_MINOR_VERS_MISMATCH, }, + {NFSERR_STALE_CLIENTID, }, + {NFSERR_STALE_STATEID, }, + {NFSERR_OLD_STATEID, }, + {NFSERR_BAD_STATEID, }, + {NFSERR_BAD_SEQID, }, + {NFSERR_NOT_SAME, }, + {NFSERR_LOCK_RANGE, }, + {NFSERR_SYMLINK, }, + {NFSERR_RESTOREFH, }, + {NFSERR_LEASE_MOVED, }, + {NFSERR_ATTRNOTSUPP, }, + {NFSERR_NO_GRACE, }, + {NFSERR_RECLAIM_BAD, }, + {NFSERR_RECLAIM_CONFLICT, }, + {NFSERR_BAD_XDR, }, + {NFSERR_LOCKS_HELD, }, + {NFSERR_OPENMODE, }, + {NFSERR_BADOWNER, }, + {NFSERR_BADCHAR, }, + {NFSERR_BADNAME, }, + {NFSERR_BAD_RANGE, }, + {NFSERR_LOCK_NOTSUPP, }, + {NFSERR_OP_ILLEGAL, }, + {NFSERR_DEADLOCK, }, + {NFSERR_FILE_OPEN, }, + {NFSERR_ADMIN_REVOKED, }, + {NFSERR_CB_PATH_DOWN, } +}; + +void syno_nfsd_udc_stat_init(void) +{ + int i; + memset(g_latency_histogram, 0, sizeof(g_latency_histogram)); + for (i = 0; i < ARRAY_SIZE(g_errtbl); i++) { + memset(g_errtbl[i].counts, 0, sizeof(g_errtbl[i].counts)); + } +} + +static inline void store_latency(unsigned int lat_s, + enum syno_nfsd_version nfs_vers, + enum syno_nfsd_io_stat_type op, + enum syno_nfsd_latency_stage stage) +{ + unsigned int msb = min(SYNO_NFSD_LATENCY_BUCKET_NR - 1, (unsigned int) fls(lat_s)); + g_latency_histogram[nfs_vers][stage][op][msb]++; +} + +void syno_nfsd_store_latency_into_histogram(unsigned int rpc_lat_s, unsigned int vfs_lat_s, + enum syno_nfsd_version nfs_vers, + enum syno_nfsd_io_stat_type op) +{ + unsigned int only_rpc_lat_s = max(0, (int) rpc_lat_s - (int) vfs_lat_s); + spin_lock(&g_latency_histogram_lock); + store_latency(rpc_lat_s, nfs_vers, op, SYNO_NFSD_LATENCY_STAGE_TOTAL_RPC); + store_latency(vfs_lat_s, nfs_vers, op, SYNO_NFSD_LATENCY_STAGE_TOTAL_VFS); + store_latency(only_rpc_lat_s, nfs_vers, op, SYNO_NFSD_LATENCY_STAGE_ONLY_RPC); + spin_unlock(&g_latency_histogram_lock); +} + +static int latency_histogram_show(struct seq_file *m, void *v) +{ + int i, j, k, l; + for (l = 0; l < SYNO_NFSD_LATENCY_BUCKET_NR; ++l) { + for (i = SYNO_NFSD_VERSION_2; i < SYNO_NFSD_VERSION_END; ++i) + for (j = SYNO_NFSD_LATENCY_STAGE_TOTAL_RPC; j < SYNO_NFSD_LATENCY_STAGE_END; ++j) + for (k = SYNO_NFSD_IO_READ; k < SYNO_NFSD_IO_TYPE_END; ++k) + seq_printf(m, "%llu ", g_latency_histogram[i][j][k][l]); + seq_printf(m, "\n"); + } + + return 0; +} + +int syno_nfsd_latency_histogram_open(struct inode *inode, struct file *file) +{ + return single_open(file, latency_histogram_show, NULL); +} + +static int total_error_show(struct seq_file *m, void *v) +{ + + int i, j; + + for (i = 0; i < ARRAY_SIZE(g_errtbl); i++) { + seq_printf(m, "err %d:", g_errtbl[i].nfserr); + for (j = SYNO_NFSD_VERSION_2; j < SYNO_NFSD_VERSION_END; ++j) + seq_printf(m, " %u", g_errtbl[i].counts[j]); + seq_printf(m, "\n"); + } + return 0; +} + +int syno_nfsd_total_error_open(struct inode *inode, struct file *file) +{ + return single_open(file, total_error_show, NULL); +} + +void syno_nfsd_store_error(int errno, enum syno_nfsd_version nfs_vers) +{ + int i; + if (!errno) + return; + + for (i = 0; i < ARRAY_SIZE(g_errtbl); i++) { + if (g_errtbl[i].nfserr == errno) { + spin_lock(&g_errtbl_lock); + g_errtbl[i].counts[nfs_vers]++; + spin_unlock(&g_errtbl_lock); + break; + } + } +} + +#endif /* MY_ABC_HERE */ + diff --git a/fs/nfsd/syno_io_stat.h b/fs/nfsd/syno_io_stat.h new file mode 100644 index 000000000000..b6baf3f8983c --- /dev/null +++ b/fs/nfsd/syno_io_stat.h @@ -0,0 +1,73 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifndef LINUX_NFSD_SYNO_IO_STAT_H +#define LINUX_NFSD_SYNO_IO_STAT_H +#include +#include +#include + +#include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +enum syno_nfsd_io_stat_type { + SYNO_NFSD_IO_READ = 0, + SYNO_NFSD_IO_WRITE, + SYNO_NFSD_IO_TYPE_END +}; + +// We use `nfs_vers` to represent this enum type +enum syno_nfsd_version { + SYNO_NFSD_VERSION_2 = 0, + SYNO_NFSD_VERSION_3, + SYNO_NFSD_VERSION_4, + SYNO_NFSD_VERSION_END, +}; + +static inline enum syno_nfsd_version syno_nfsd_version_convert(unsigned int vers) +{ + return min((unsigned int) SYNO_NFSD_VERSION_END, vers - 2); +} + +void syno_nfsd_io_total_stat_init(void); +void syno_nfsd_io_total_stat_destroy(void); +int syno_nfsd_io_total_stat_open(struct inode *inode, struct file *file); +void syno_nfsd_account_io_complete(struct sockaddr *s_addr, int version, + enum syno_nfsd_io_stat_type type, s64 bytes, + s64 latency); +ssize_t syno_nfsd_client_ctl(char *buf, size_t size); +int syno_nfsd_client_register(struct sockaddr *s_addr, int version, struct xdr_netobj *os_name); +void syno_nfsd_client_unregister(const struct sockaddr *s_addr, int version); +void syno_nfsd_clients_destroy_all(void); + +void syno_nfsd_client_expire_time_set(int t); +int syno_nfsd_client_expire_time_get(void); +void syno_nfsd_client_cleaner(void); + +#ifdef MY_ABC_HERE +void syno_nfsd_connection_init(void); +void syno_nfsd_max_connection_init(void); +int syno_nfsd_max_connection(void); +void syno_nfsd_connection_destroy(void); +void syno_nfsd_total_connection_reset(void); +int syno_nfsd_total_connection_stat_open(struct inode *inode, struct file *file); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct syno_nfsd_dummy_status { + __be32 status; +}; + +#define SYNO_NFSD_USEC_TO_SEC(us) ((us >> 20)) +void syno_nfsd_udc_stat_init(void); +void syno_nfsd_store_latency_into_histogram(unsigned int rpc_lat_s, unsigned int vfs_lat_s, + enum syno_nfsd_version nfs_vers, + enum syno_nfsd_io_stat_type op); +int syno_nfsd_latency_histogram_open(struct inode *inode, struct file *file); +void syno_nfsd_store_error(int errno, enum syno_nfsd_version nfs_vers); +int syno_nfsd_total_error_open(struct inode *inode, struct file *file); +#endif /* MY_ABC_HERE */ + +#endif /* LINUX_NFSD_SYNO_IO_STAT_H */ diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index c8ca73d69ad0..38390a7de1c9 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014 Christoph Hellwig. @@ -172,6 +175,55 @@ TRACE_EVENT(nfsd_export_update, ) ); +#ifdef MY_ABC_HERE +DECLARE_EVENT_CLASS(syno_nfsd_io_class, + TP_PROTO(struct svc_rqst *rqstp, + struct svc_fh *fhp, + loff_t offset, + unsigned long len, + s64 latency, + char *client_addr_str), + TP_ARGS(rqstp, fhp, offset, len, + latency, client_addr_str), + TP_STRUCT__entry( + __field(u32, xid) + __field(u32, fh_hash) + __field(loff_t, offset) + __field(unsigned long, len) + __field(s64, latency) + __string(client_addr, client_addr_str) + __field(int, ver) + ), + TP_fast_assign( + __entry->xid = be32_to_cpu(rqstp->rq_xid); + __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle); + __entry->offset = offset; + __entry->len = len; + __entry->latency = latency; + __assign_str(client_addr, client_addr_str); + __entry->ver = rqstp->rq_vers; + ), + TP_printk("xid=0x%08x fh_hash=0x%08x offset=%lld len=%lu latency=%lld client=[%s] ver=%d", + __entry->xid, __entry->fh_hash, + __entry->offset, __entry->len, + __entry->latency, __get_str(client_addr), + __entry->ver) +) + +#define DEFINE_SYNO_NFSD_IO_EVENT(name) \ +DEFINE_EVENT(syno_nfsd_io_class, syno_nfsd_##name, \ + TP_PROTO(struct svc_rqst *rqstp, \ + struct svc_fh *fhp, \ + loff_t offset, \ + unsigned long len, \ + s64 latency, \ + char *client_addr_str), \ + TP_ARGS(rqstp, fhp, offset, len, latency, client_addr_str)) + +DEFINE_SYNO_NFSD_IO_EVENT(read_io_done); +DEFINE_SYNO_NFSD_IO_EVENT(write_io_done); +#endif /* MY_ABC_HERE */ + DECLARE_EVENT_CLASS(nfsd_io_class, TP_PROTO(struct svc_rqst *rqstp, struct svc_fh *fhp, diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 011cd570b50d..e87962eaeef2 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * File operations used by nfsd. Some of these have been ripped from @@ -32,6 +35,11 @@ #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_NFSD_V3 #include "xdr3.h" #endif /* CONFIG_NFSD_V3 */ @@ -47,8 +55,20 @@ #include "filecache.h" #include "trace.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include "syno_io_stat.h" +#endif /* MY_ABC_HERE */ + #define NFSDDBG_FACILITY NFSDDBG_FILEOP +#ifdef MY_ABC_HERE +extern u32 bl_unix_pri_enable; +#endif /* MY_ABC_HERE */ + /* * Called from nfsd_lookup and encode_dirent. Check if we have crossed * a mount point. @@ -359,6 +379,76 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, return nfserrno(host_err); } +#ifdef MY_ABC_HERE +/* + * @return: < 0 - failed + * = 0 - no change + * > 0 - lock state changed + */ +static int nfsd_syno_locker_set(struct inode *inode, struct iattr *iap) +{ + int ret; + enum locker_mode mode; + enum locker_state state; + struct timespec64 sys_clock; + + syno_op_locker_mode_get(inode, &mode); + if (mode == LM_NONE) + return 0; + + ret = syno_op_locker_state_get(inode, &state); + if (ret) + return 0; + + /* chmod a-w */ + if (!(iap->ia_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) { + ret = -EINVAL; + if (state == LS_OPEN) { + ktime_get_real_ts64(&sys_clock); + if (0 <= timespec64_compare(&sys_clock, &inode->i_atime)) { + pr_err("locker: set #%lu with invalid atime (%lld)\n", + inode->i_ino, inode->i_atime.tv_sec); + goto out; + } + + ret = syno_op_locker_period_end_set(inode, &inode->i_atime); + if (ret) + goto out; + + ret = syno_op_locker_state_set(inode, LS_IMMUTABLE); + if (ret) + goto out; + + ret = 1; + pr_info("locker: set #%lu immutable from open\n", inode->i_ino); + } else if (state == LS_APPENDABLE) { + ret = syno_op_locker_state_set(inode, LS_IMMUTABLE); + if (ret) + goto out; + + ret = 1; + pr_info("locker: set #%lu immutable from appendable\n", inode->i_ino); + } + } + + /* chmod a+w */ + else if ((iap->ia_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == (S_IWUSR|S_IWGRP|S_IWOTH)) { + ret = -EINVAL; + if (state == LS_IMMUTABLE) { + ret = syno_op_locker_state_set(inode, LS_APPENDABLE); + if (ret) + goto out; + + ret = 1; + pr_info("locker: set #%lu appendable from immutable\n", inode->i_ino); + } + } + +out: + return ret; +} +#endif /* MY_ABC_HERE */ + /* * Set various file attributes. After this call fhp needs an fh_put. */ @@ -397,7 +487,16 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, get_write_count = !fhp->fh_dentry; /* Get inode */ +#ifdef MY_ABC_HERE + /* + * bypass NFSD_MAY_SATTR checking now, and verify it later. this is + * for the situations because we need to change the state (immutable + * --> appendable) on immutable files. + */ + err = fh_verify(rqstp, fhp, ftype, accmode & ~NFSD_MAY_SATTR); +#else err = fh_verify(rqstp, fhp, ftype, accmode); +#endif /* MY_ABC_HERE */ if (err) return err; if (get_write_count) { @@ -409,6 +508,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, dentry = fhp->fh_dentry; inode = d_inode(dentry); +#ifdef MY_ABC_HERE + if ((iap->ia_valid & ATTR_MODE) && uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { + host_err = nfsd_syno_locker_set(inode, iap); + if (host_err > 0) + iap->ia_valid &= ~ATTR_MODE; + else if (host_err < 0) + goto out; + } + + /* delay to check NFSD_MAY_SATTR */ + err = fh_verify(rqstp, fhp, ftype, accmode); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* Ignore chmod when !bl_unix_pri_enable & the share is ACL share */ + if (!bl_unix_pri_enable && IS_SYNOACL(dentry)) + iap->ia_valid &= ~ATTR_MODE; +#endif /* MY_ABC_HERE */ + /* Ignore any mode updates on symlinks */ if (S_ISLNK(inode->i_mode)) iap->ia_valid &= ~ATTR_MODE; @@ -462,6 +580,14 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, goto out_unlock; } +#ifdef MY_ABC_HERE + if ((iap->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) && !syno_op_locker_is_open(inode)) { + host_err = -EPERM; + pr_err("locker: failed to update the atime of non-open #%lu\n", inode->i_ino); + goto out_unlock; + } +#endif /* MY_ABC_HERE */ + iap->ia_valid |= ATTR_CTIME; host_err = notify_change(dentry, iap, NULL); @@ -609,7 +735,11 @@ struct accessmap { static struct accessmap nfs3_regaccess[] = { { NFS3_ACCESS_READ, NFSD_MAY_READ }, { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC }, +#ifdef MY_ABC_HERE + { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE }, +#else { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_TRUNC }, +#endif /* MY_ABC_HERE */ { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE }, #ifdef CONFIG_NFSD_V4 @@ -747,8 +877,14 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, * or any access when mandatory locking enabled */ err = nfserr_perm; +#ifdef MY_ABC_HERE + if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE) && !syno_op_locker_is_appendable(inode)) + goto out; +#else if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE)) goto out; +#endif /* MY_ABC_HERE */ + /* * We must ignore files (but only files) which might have mandatory * locks on them because there is no way to know if the accesser has @@ -886,13 +1022,35 @@ static u32 nfsd_eof_on_read(struct file *file, loff_t offset, ssize_t len, static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, - unsigned long *count, u32 *eof, ssize_t host_err) + unsigned long *count, u32 *eof, ssize_t host_err +#ifdef MY_ABC_HERE + , ktime_t rq_io_stime +#endif /* MY_ABC_HERE */ + ) { +#ifdef MY_ABC_HERE + s64 latency = ktime_to_us(ktime_sub(ktime_get(), rq_io_stime)); + char buf[RPC_MAX_ADDRBUFLEN]; + +#ifdef MY_ABC_HERE + rqstp->vfs_latency_us = latency; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + if (host_err >= 0) { nfsdstats.io_read += host_err; *eof = nfsd_eof_on_read(file, offset, host_err, *count); *count = host_err; fsnotify_access(file); +#ifdef MY_ABC_HERE + syno_nfsd_account_io_complete(svc_addr(rqstp), rqstp->rq_vers, + SYNO_NFSD_IO_READ, *count, + latency); + if (trace_syno_nfsd_read_io_done_enabled()) + trace_syno_nfsd_read_io_done( + rqstp, fhp, offset, *count, latency, + svc_print_addr(rqstp, buf, sizeof(buf))); +#endif /* MY_ABC_HERE */ trace_nfsd_read_io_done(rqstp, fhp, offset, *count); return 0; } else { @@ -912,11 +1070,19 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, .u.data = rqstp, }; ssize_t host_err; +#ifdef MY_ABC_HERE + ktime_t rq_io_stime = ktime_get(); +#endif /* MY_ABC_HERE */ trace_nfsd_read_splice(rqstp, fhp, offset, *count); rqstp->rq_next_page = rqstp->rq_respages + 1; host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); - return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err); + + return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err +#ifdef MY_ABC_HERE + , rq_io_stime +#endif /* MY_ABC_HERE */ + ); } __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp, @@ -927,11 +1093,18 @@ __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iov_iter iter; loff_t ppos = offset; ssize_t host_err; +#ifdef MY_ABC_HERE + ktime_t rq_io_stime = ktime_get(); +#endif /* MY_ABC_HERE */ trace_nfsd_read_vector(rqstp, fhp, offset, *count); iov_iter_kvec(&iter, READ, vec, vlen, *count); host_err = vfs_iter_read(file, &iter, &ppos, 0); - return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err); + return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err +#ifdef MY_ABC_HERE + , rq_io_stime +#endif /* MY_ABC_HERE */ + ); } /* @@ -986,9 +1159,25 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, loff_t pos = offset; unsigned int pflags = current->flags; rwf_t flags = 0; +#ifdef MY_ABC_HERE + ktime_t rq_io_stime = ktime_get(); + char buf[RPC_MAX_ADDRBUFLEN]; + s64 latency; +#endif /* MY_ABC_HERE */ trace_nfsd_write_opened(rqstp, fhp, offset, *cnt); +#ifdef MY_ABC_HERE + /* should be align with generic_write_checks() */ + if (syno_op_locker_is_appendable(file->f_inode) && + offset < round_down(i_size_read(file->f_inode), LOCKER_CHUNK_SIZE)) + return nfserr_perm; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + update_syno_file_stats(fhp->fh_dentry); +#endif /* MY_ABC_HERE */ + if (test_bit(RQ_LOCAL, &rqstp->rq_flags)) /* * We want throttling in balance_dirty_pages() @@ -1042,7 +1231,22 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, } out_nfserr: +#ifdef MY_ABC_HERE + latency = ktime_to_us(ktime_sub(ktime_get(), rq_io_stime)); +#ifdef MY_ABC_HERE + rqstp->vfs_latency_us = latency; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ if (host_err >= 0) { +#ifdef MY_ABC_HERE + syno_nfsd_account_io_complete(svc_addr(rqstp), rqstp->rq_vers, + SYNO_NFSD_IO_WRITE, *cnt, + latency); + if (trace_syno_nfsd_write_io_done_enabled()) + trace_syno_nfsd_write_io_done( + rqstp, fhp, offset, *cnt, latency, + svc_print_addr(rqstp, buf, sizeof(buf))); +#endif /* MY_ABC_HERE */ trace_nfsd_write_io_done(rqstp, fhp, offset, *cnt); nfserr = nfs_ok; } else { @@ -1112,6 +1316,169 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, return err; } +#ifdef MY_ABC_HERE +/* + * Enable NFS VAAI plugin to reserve space. + * Only support pre-allocate blocks for now. + */ +__be32 +nfsd_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp, + loff_t offset, unsigned long *cnt) +{ + __be32 err; + struct file *file; + + if (!cnt) { + err = nfs_ok; + goto out; + } + + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); + if (err) + goto out; + + err = vfs_fallocate(file, 0, offset, *cnt); + + fput(file); +out: + return err; +} + +static inline int nfsd_all_zeroes_check(char const* mem, size_t size) +{ + while (size-- > 0) + if (*mem++) + return 0; + return 1; +} + +__be32 +nfsd_synocopy(const char *src_path, struct svc_rqst *rqstp, struct svc_fh *fhp, + loff_t offset, unsigned long *len, bool skip_zero) +{ + __be32 err; + struct file *dst_filp, *src_filp; + loff_t i_size; + loff_t write_offset, read_offset; + char *buffer; + size_t count; + + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &dst_filp); + if (err) { + dprintk("%s: cannot open destination file\n", __func__); + goto out; + } + + src_filp = filp_open(src_path, O_RDONLY | O_LARGEFILE, 0); + if(IS_ERR(src_filp)) { + err = nfserrno(PTR_ERR(src_filp)); + // If the source file is on different machine, the open operation must fail + printk(KERN_WARNING "%s: cannot open source file\n", __func__); + goto close_dst; + } + + buffer = kvzalloc(NFSD_COPYBUFFERSIZE, GFP_KERNEL); + if (!buffer) { + err = nfserr_jukebox; + dprintk("%s: cannot allocate memories for buffer\n", __func__); + goto close_src; + } + + i_size = i_size_read(file_inode(src_filp)); + if (i_size < 0) { + err = nfserrno(-EINVAL); + printk(KERN_WARNING "%s: src file i_size < 0\n", __func__); + goto close_src; + } + + write_offset = read_offset = offset; + count = min_t(size_t, *len, i_size - offset); + while (count) { + int ret; + size_t copied; + size_t wanted = min_t(size_t, count, NFSD_COPYBUFFERSIZE); + + copied = 0; + while (copied < wanted) { + ret = kernel_read(src_filp, (buffer + copied), (wanted - copied), &read_offset); + if (ret <= 0) { + err = nfserrno(ret); + dprintk("%s: Error (%d) while reading data from source file, read %zu bytes\n", __func__, ret, copied); + goto close_src; + } + copied += ret; + } + + if (skip_zero && nfsd_all_zeroes_check(buffer, copied)) { + count -= copied; + write_offset += copied; + continue; + } + + copied = 0; + while (copied < wanted) { + ret = kernel_write(dst_filp, (buffer + copied), (wanted - copied), &write_offset); + if (ret <= 0) { + err = nfserrno(ret); + dprintk("%s: Error (%d) while writing data to destination file, write %zu bytes\n", __func__, ret, copied); + goto close_src; + } + copied += ret; + } + + count -= copied; + } + + err = nfs_ok; +close_src: + filp_close(src_filp, NULL); +close_dst: + fput(dst_filp); +out: + kvfree(buffer); + return err; +} + +#ifdef MY_ABC_HERE +__be32 +nfsd_synoclone(const char *src_path, struct svc_rqst *rqstp, struct svc_fh *fhp) +{ + __be32 err; + loff_t cloned; + struct file *dst_filp, *src_filp; + + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &dst_filp); + if (err) { + dprintk("%s: cannot open destination file, ret=%d\n", __func__, err); + goto out; + } + + src_filp = filp_open(src_path, O_RDONLY | O_LARGEFILE, 0); + if(IS_ERR(src_filp)) { + err = nfserrno(PTR_ERR(src_filp)); + // If the source file is on different machine, the open operation must fail + printk(KERN_WARNING "%s: cannot open source file %s\n", __func__, src_path); + goto close_dst; + } + + cloned = vfs_clone_file_range(src_filp, 0, dst_filp, 0, 0, 0); + if (cloned < 0) { + err = nfserrno(cloned); + dprintk("%s: vfs_file_clone_range failed, ret=%lld\n", __func__, cloned); + goto close_src; + } + + err = nfs_ok; +close_src: + filp_close(src_filp, NULL); +close_dst: + fput(dst_filp); +out: + return err; +} +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_NFSD_V3 static int nfsd_filemap_write_and_wait_range(struct nfsd_file *nf, loff_t offset, @@ -1807,6 +2174,11 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if (!host_err) host_err = commit_metadata(ffhp); } +#ifdef MY_ABC_HERE + /* translate errno for locker protected directories */ + if (host_err == -EOPNOTSUPP) + host_err = -ENOTEMPTY; +#endif /* MY_ABC_HERE */ } out_dput_new: dput(ndentry); @@ -1853,6 +2225,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, { struct dentry *dentry, *rdentry; struct inode *dirp; +#ifdef MY_ABC_HERE + struct inode *inode = NULL; +#endif /* MY_ABC_HERE */ __be32 err; int host_err; @@ -1882,6 +2257,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, goto out_drop_write; } +#ifdef MY_ABC_HERE + inode = rdentry->d_inode; + if (inode) + ihold(inode); +#endif /* MY_ABC_HERE */ + if (!type) type = d_inode(rdentry)->i_mode & S_IFMT; @@ -1896,6 +2277,11 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, host_err = commit_metadata(fhp); dput(rdentry); +#ifdef MY_ABC_HERE + fh_unlock(fhp); + if (inode) + iput(inode); /* truncate the inode here */ +#endif /* MY_ABC_HERE */ out_drop_write: fh_drop_write(fhp); out_nfserr: @@ -1936,6 +2322,33 @@ struct readdir_data { int full; }; +#ifdef MY_ABC_HERE +const struct { + char * name; + int len; +} hidden_files[] = { + {"@eaDir", 6}, + {"@tmp", 4}, + {"@sharebin", 9}, + {".AppleDesktop", 13}, +}; + +static int is_hidden_file(const char *name, int namlen) { + /* + * The hidden dir list is copied from grgszHiddenDir in libsynofileop + * and SYNOFTPIsVisiblePath in smbftpd-2.0 + */ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(hidden_files); i++) { + if (namlen == hidden_files[i].len && + !strncmp(name, hidden_files[i].name, namlen)) + return 1; + } + return 0; +} +#endif /* MY_ABC_HERE */ + static int nfsd_buffered_filldir(struct dir_context *ctx, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) @@ -1962,7 +2375,11 @@ static int nfsd_buffered_filldir(struct dir_context *ctx, const char *name, } static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, - struct readdir_cd *cdp, loff_t *offsetp) + struct readdir_cd *cdp, loff_t *offsetp +#ifdef MY_ABC_HERE + , int hide_hidden_file +#endif /* MY_ABC_HERE */ + ) { struct buffered_dirent *de; int host_err; @@ -2001,6 +2418,11 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, while (size > 0) { offset = de->offset; +#ifdef MY_ABC_HERE + if (unlikely(hide_hidden_file && is_hidden_file(de->name, de->namlen))) + goto skip_fill_entry; +#endif /* MY_ABC_HERE */ + if (func(cdp, de->name, de->namlen, de->offset, de->ino, de->d_type)) break; @@ -2008,6 +2430,10 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, if (cdp->err != nfs_ok) break; +#ifdef MY_ABC_HERE +skip_fill_entry: +#endif /* MY_ABC_HERE */ + reclen = ALIGN(sizeof(*de) + de->namlen, sizeof(u64)); size -= reclen; @@ -2040,6 +2466,9 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, struct file *file; loff_t offset = *offsetp; int may_flags = NFSD_MAY_READ; +#ifdef MY_ABC_HERE + int is_first_level_dir; +#endif /* MY_ABC_HERE */ /* NFSv2 only supports 32 bit cookies */ if (rqstp->rq_vers > 2) @@ -2055,7 +2484,19 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, goto out_close; } - err = nfsd_buffered_readdir(file, func, cdp, offsetp); +#ifdef MY_ABC_HERE + /* + * #44339 + * hidden_files are only hidden at the first level dir. + */ + is_first_level_dir = path_equal(&fhp->fh_export->ex_path, &file->f_path); +#endif /* MY_ABC_HERE */ + + err = nfsd_buffered_readdir(file, func, cdp, offsetp +#ifdef MY_ABC_HERE + , is_first_level_dir +#endif /* MY_ABC_HERE */ + ); if (err == nfserr_eof || err == nfserr_toosmall) err = nfs_ok; /* can still be found in ->err */ @@ -2320,6 +2761,39 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, } #endif +#ifdef MY_ABC_HERE +static int synoacl_nfs_perm_switch(struct inode *inode, int acc) +{ + int perm = 0; + + if (NFSD_MAY_EXEC & acc) + perm |= MAY_EXEC; + if ((NFSD_MAY_TRUNC|NFSD_MAY_WRITE) & acc) + perm |= MAY_WRITE; + if (NFSD_MAY_READ & acc) + perm |= MAY_READ; + + /* + * checked in vfs + * - NFSD_MAY_SATTR + * - NFSD_MAY_CREATE + * - NFSD_MAY_REMOVE + * + * NFS specific + * - NFSD_MAY_LOCK + * - NFSD_MAY_OWNER_OVERRIDE (owner can do anything) + * - NFSD_MAY_LOCAL_ACCESS + * - NFSD_MAY_BYPASS_GSS_ON_ROOT + * - NFSD_MAY_NOT_BREAK_LEASE + * - NFSD_MAY_BYPASS_GSS + * - NFSD_MAY_READ_IF_EXEC + * - NFSD_MAY_64BIT_COOKIE + */ + + return perm ; +} +#endif /* MY_ABC_HERE */ + /* * Check for a user's access permissions to this inode. */ @@ -2389,18 +2863,60 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, * We must trust the client to do permission checking - using "ACCESS" * with NFSv3. */ +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + if ((acc & NFSD_MAY_OWNER_OVERRIDE) && is_synoacl_owner(dentry)) + return 0; + if ((acc & NFSD_MAY_CREATE) || (acc & NFSD_MAY_REMOVE) || + (acc & NFSD_MAY_SATTR)) { + /* + * In nfsd_permission(), the arguments are not enough to + * check permission of NFSD_MAY_SATTR, NFSD_MAY_CREATE, + * and NFSD_MAY_REMOVE: + * + * SATTR: The attributes to set are needed for + * synoacl_op_setattr_prepare(). + * CREATE: The created file type is needed. Creating + * normal file (w) and new subdir (a) require + * different permission. + * REMOVE: Not only the parent dir, the d permission of + * deleted file itself should be checked. + * + * So directly return 0 here, and the permission is + * checked in the VFS layer. + */ + return 0; + } + err = synoacl_op_permission(dentry, synoacl_nfs_perm_switch(inode, acc)); + } else { + if ((acc & NFSD_MAY_OWNER_OVERRIDE) && + uid_eq(inode->i_uid, current_fsuid())) + return 0; + err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); + } +#else /* MY_ABC_HERE */ if ((acc & NFSD_MAY_OWNER_OVERRIDE) && uid_eq(inode->i_uid, current_fsuid())) return 0; /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); +#endif /* MY_ABC_HERE */ /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) +#ifdef MY_ABC_HERE + { + if (IS_SYNOACL(dentry)) + err = synoacl_op_permission(dentry, MAY_EXEC); + else + err = inode_permission(inode, MAY_EXEC); + } +#else /* MY_ABC_HERE */ err = inode_permission(inode, MAY_EXEC); +#endif /* MY_ABC_HERE */ return err? nfserrno(err) : 0; } diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index a2442ebe5acf..ce94b7cb71f7 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 1995-1997 Olaf Kirch @@ -9,6 +12,10 @@ #include "nfsfh.h" #include "nfsd.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + /* * Flags for nfsd_permission */ @@ -34,6 +41,10 @@ #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) +#ifdef MY_ABC_HERE +#define NFSD_COPYBUFFERSIZE (1<<17) +#endif /* MY_ABC_HERE */ + struct nfsd_file; /* @@ -106,6 +117,15 @@ __be32 nfsd_read(struct svc_rqst *, struct svc_fh *, __be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t, struct kvec *, int, unsigned long *, int stable, __be32 *verf); +#ifdef MY_ABC_HERE +__be32 nfsd_fallocate(struct svc_rqst *, struct svc_fh *, + loff_t, unsigned long *); +__be32 nfsd_synocopy(const char *, struct svc_rqst *, struct svc_fh *, + loff_t, unsigned long *, bool); +#ifdef MY_ABC_HERE +__be32 nfsd_synoclone(const char *, struct svc_rqst *, struct svc_fh *); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt, @@ -132,6 +152,23 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, struct dentry *, int); +#ifdef MY_ABC_HERE +/* + * There's no ACL entry of root for all files in DSM, thus POSIX permissions + * will be reported as empty. It does not matter in most cases, but some + * applications (e.g., FileStation) from NFS clients will check the permission + * first with root, and then lead to misjudgement.. + * + * For backward compatibility, we just work around it in NFSD but not the path + * of synoacl_op_to_mode(). + */ +static inline void nfsd_update_root_attr(struct dentry *dentry, struct kstat *stat) +{ + if (IS_SYNOACL(dentry) && uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) + stat->mode |= (S_IRWXU|S_IRWXG|S_IRWXO); +} +#endif /* MY_ABC_HERE */ + static inline int fh_want_write(struct svc_fh *fh) { int ret; @@ -156,8 +193,18 @@ static inline __be32 fh_getattr(struct svc_fh *fh, struct kstat *stat) { struct path p = {.mnt = fh->fh_export->ex_path.mnt, .dentry = fh->fh_dentry}; + +#ifdef MY_ABC_HERE + int err; + + err = vfs_getattr(&p, stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); + if (!err) + nfsd_update_root_attr(fh->fh_dentry, stat); + return nfserrno(err); +#else /* MY_ABC_HERE */ return nfserrno(vfs_getattr(&p, stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT)); +#endif /* MY_ABC_HERE */ } static inline int nfsd_create_is_exclusive(int createmode) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 679d40af1bbb..33167d39b816 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Server-side types for NFSv4. * @@ -550,7 +553,11 @@ struct nfsd4_copy { u64 cp_src_pos; u64 cp_dst_pos; u64 cp_count; +#ifdef MY_ABC_HERE + struct nl4_server *cp_src; +#else /* MY_ABC_HERE */ struct nl4_server cp_src; +#endif /* MY_ABC_HERE */ bool cp_intra; /* both */ @@ -605,13 +612,21 @@ struct nfsd4_offload_status { struct nfsd4_copy_notify { /* request */ stateid_t cpn_src_stateid; +#ifdef MY_ABC_HERE + struct nl4_server *cpn_dst; +#else /* MY_ABC_HERE */ struct nl4_server cpn_dst; +#endif /* MY_ABC_HERE */ /* response */ stateid_t cpn_cnr_stateid; u64 cpn_sec; u32 cpn_nsec; +#ifdef MY_ABC_HERE + struct nl4_server *cpn_src; +#else /* MY_ABC_HERE */ struct nl4_server cpn_src; +#endif /* MY_ABC_HERE */ }; struct nfsd4_op { diff --git a/fs/notify/Makefile b/fs/notify/Makefile index 63a4b8828df4..b2162972f514 100644 --- a/fs/notify/Makefile +++ b/fs/notify/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o mark.o \ obj-y += dnotify/ obj-y += inotify/ obj-y += fanotify/ +obj-y += synotify/ diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 086b6bacbad1..f73c6ba1c160 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -26,6 +29,10 @@ #include "../fdinfo.h" #include "fanotify.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #define FANOTIFY_DEFAULT_MAX_EVENTS 16384 #define FANOTIFY_DEFAULT_MAX_MARKS 8192 #define FANOTIFY_DEFAULT_MAX_LISTENERS 128 @@ -702,6 +709,11 @@ static int fanotify_find_path(int dfd, const char __user *filename, } /* you can only watch an inode if you have read permissions on it */ +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path->dentry)) + ret = synoacl_op_permission(path->dentry, MAY_READ); + else +#endif /* MY_ABC_HERE */ ret = inode_permission(path->dentry->d_inode, MAY_READ); if (ret) { path_put(path); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 30d422b8c0fc..331d380823e3 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2008 Red Hat, Inc., Eric Paris @@ -14,6 +17,11 @@ #include #include "fsnotify.h" +#ifdef MY_ABC_HERE +#include +extern struct rw_semaphore namespace_sem; +#endif /* MY_ABC_HERE */ + /* * Clear all of the marks on an inode when it is being evicted from core */ @@ -197,6 +205,9 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, * Do they care about any event at all? */ if (!inode->i_fsnotify_marks && !inode->i_sb->s_fsnotify_marks && +#ifdef MY_ABC_HERE + (!mnt || !mnt->mnt_fsnotify_syno_marks) && +#endif /* MY_ABC_HERE */ (!mnt || !mnt->mnt_fsnotify_marks) && !parent_watched) return 0; @@ -494,6 +505,9 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, */ if (!sb->s_fsnotify_marks && (!mnt || !mnt->mnt_fsnotify_marks) && +#ifdef MY_ABC_HERE + (!mnt || !mnt->mnt_fsnotify_syno_marks) && +#endif /* MY_ABC_HERE */ (!inode || !inode->i_fsnotify_marks) && (!parent || !parent->i_fsnotify_marks)) return 0; @@ -501,6 +515,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, marks_mask = sb->s_fsnotify_mask; if (mnt) marks_mask |= mnt->mnt_fsnotify_mask; +#ifdef MY_ABC_HERE + if (mnt) + marks_mask |= mnt->mnt_fsnotify_syno_mask; +#endif /* MY_ABC_HERE */ if (inode) marks_mask |= inode->i_fsnotify_mask; if (parent) @@ -522,6 +540,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, if (mnt) { iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] = fsnotify_first_mark(&mnt->mnt_fsnotify_marks); +#ifdef MY_ABC_HERE + iter_info.marks[FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT] = + fsnotify_first_mark(&mnt->mnt_fsnotify_syno_marks); +#endif /* MY_ABC_HERE */ } if (inode) { iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = @@ -554,6 +576,131 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, } EXPORT_SYMBOL_GPL(fsnotify); +#ifdef MY_ABC_HERE +/* + * notify_event + * + * get notify event path by given vfsmnt and dentry. + * notify event according to procedded dentry path. + * + * */ +static void notify_event(struct vfsmount *vfsmnt, struct dentry *dentry, __u32 mask) +{ + struct path path; + + memset(&path, 0, sizeof(struct path)); + + path.mnt = vfsmnt; + path.dentry = dentry; + + __SYNONotify(mask, &path, FSNOTIFY_EVENT_PATH, NULL, 0); +} + +/* + * Like fsnotify(), but in most cases you use SYNONotify(). + * For now the only direct caller is fsnotify_move(). + */ +void __SYNONotify(__u32 mask, void *data, int data_type, const char *file_path, u32 cookie) +{ + struct fsnotify_iter_info iter_info = {}; + struct qstr qstr_path = {}; + struct mount *mnt = NULL; + __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); + + if (unlikely(!data)) + return; + + if (!((struct path *)data)->mnt) + return; + + mnt = real_mount(((struct path *)data)->mnt); + if (!(test_mask & mnt->mnt_fsnotify_syno_mask)) + return; + + iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); + + iter_info.marks[FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT] = + fsnotify_first_mark(&mnt->mnt_fsnotify_syno_marks); + + while (fsnotify_iter_select_report_types(&iter_info)) { + /* + * Use qstr to carry path, not name. + * The path itself is not stored in qstr, so keep qstr_path.len = 0, + * we are not using len in synotify_handle_event(). + */ + qstr_path.name = file_path; + + /* + * In upstream's fsnotify(), they only report error in permission events. + * Since we have no permission events in synotify, so ignore all errors here. + */ + send_to_group(mask, data, data_type, NULL, &qstr_path, + cookie, &iter_info); + + fsnotify_iter_next(&iter_info); + } + + srcu_read_unlock(&fsnotify_mark_srcu, iter_info.srcu_idx); + return; +} +EXPORT_SYMBOL(__SYNONotify); + +/* + * Like fsnotify(), but find "struct mount" and "struct path", + * then call __SYNONotify() with type "FSNOTIFY_EVENT_PATH" to do the real work. + */ +int SYNONotify(struct dentry *dentry, __u32 mask) +{ + struct list_head *head = NULL; + struct nsproxy *nsproxy = NULL; + int ret = 0; + + if (!dentry) { + ret = -EINVAL; + goto ERR; + } + + if (!dentry->d_sb) { + ret = -EINVAL; + goto ERR; + } + + nsproxy = current->nsproxy; + if (nsproxy) { + struct mnt_namespace *mnt_space = nsproxy->mnt_ns; + if (mnt_space) { + __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); + struct mount *mnt; + struct vfsmount *vfsmnt; + + down_read(&namespace_sem); + spin_lock(&mnt_space->ns_lock); + list_for_each(head, &mnt_space->list) { + mnt = list_entry(head, struct mount, mnt_list); + if (mnt && mnt->mnt.mnt_sb == dentry->d_sb) { + // A quick filter to minimize spinlock/unlock. + if (!(test_mask & mnt->mnt_fsnotify_syno_mask)) + continue; + + vfsmnt = &mnt->mnt; + mntget(vfsmnt); + spin_unlock(&mnt_space->ns_lock); + notify_event(vfsmnt, dentry, mask); // NOTE: ignore error + spin_lock(&mnt_space->ns_lock); + mntput(vfsmnt); + } + } + spin_unlock(&mnt_space->ns_lock); + up_read(&namespace_sem); + } + } + +ERR: + return ret; +} +EXPORT_SYMBOL(SYNONotify); +#endif /* MY_ABC_HERE */ + static __init int fsnotify_init(void) { int ret; diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index ff2063ec6b0f..af55fe6db0c8 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __FS_NOTIFY_FSNOTIFY_H_ #define __FS_NOTIFY_FSNOTIFY_H_ @@ -21,6 +24,14 @@ static inline struct mount *fsnotify_conn_mount( return container_of(conn->obj, struct mount, mnt_fsnotify_marks); } +#ifdef MY_ABC_HERE +static inline struct mount *fsnotify_conn_syno_mount( + struct fsnotify_mark_connector *conn) +{ + return container_of(conn->obj, struct mount, mnt_fsnotify_syno_marks); +} +#endif /* MY_ABC_HERE */ + static inline struct super_block *fsnotify_conn_sb( struct fsnotify_mark_connector *conn) { @@ -48,6 +59,9 @@ static inline void fsnotify_clear_marks_by_inode(struct inode *inode) static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) { fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks); +#ifdef MY_ABC_HERE + fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_syno_marks); +#endif /* MY_ABC_HERE */ } /* run the list of all marks associated with sb and destroy them */ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) diff --git a/fs/notify/group.c b/fs/notify/group.c index a4a4b1c64d32..a79e833ac721 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2008 Red Hat, Inc., Eric Paris @@ -128,6 +131,9 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) atomic_set(&group->user_waits, 0); spin_lock_init(&group->notification_lock); +#ifdef MY_ABC_HERE + mutex_init(&group->notification_mutex); +#endif /* MY_ABC_HERE */ INIT_LIST_HEAD(&group->notification_list); init_waitqueue_head(&group->notification_waitq); group->max_events = UINT_MAX; diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 5f6c6bf65909..4d9bf3c05ad9 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * fs/inotify_user.c - inotify support for userspace @@ -35,6 +38,10 @@ #include "inotify.h" #include "../fdinfo.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #include /* configurable via /proc/sys/fs/inotify/ */ @@ -343,6 +350,11 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, if (error) return error; /* you can only watch an inode if you have read permissions on it */ +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path->dentry)) + error = synoacl_op_permission(path->dentry, MAY_READ); + else +#endif /* MY_ABC_HERE */ error = inode_permission(path->dentry->d_inode, MAY_READ); if (error) { path_put(path); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 8387937b9d01..5060176edd3f 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2008 Red Hat, Inc., Eric Paris @@ -105,6 +108,10 @@ static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn) return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask; else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) return &fsnotify_conn_sb(conn)->s_fsnotify_mask; +#ifdef MY_ABC_HERE + else if (conn->type == FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT) + return &fsnotify_conn_syno_mount(conn)->mnt_fsnotify_syno_mask; +#endif /* MY_ABC_HERE */ return NULL; } @@ -188,6 +195,11 @@ static void *fsnotify_detach_connector_from_object( } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { fsnotify_conn_sb(conn)->s_fsnotify_mask = 0; } +#ifdef MY_ABC_HERE + else if (conn->type == FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT) { + fsnotify_conn_syno_mount(conn)->mnt_fsnotify_syno_mask = 0; + } +#endif /* MY_ABC_HERE */ rcu_assign_pointer(*(conn->obj), NULL); conn->obj = NULL; diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 75d79d6d3ef0..6c8ba9064095 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2008 Red Hat, Inc., Eric Paris @@ -33,6 +36,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #include "fsnotify.h" static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0); @@ -107,6 +114,9 @@ int fsnotify_add_event(struct fsnotify_group *group, return ret; } event = group->overflow_event; +#ifdef MY_ABC_HERE + printk_ratelimited(KERN_WARNING "fsnotify get overflow, max queue size is %d\n", group->max_events); +#endif /* MY_ABC_HERE */ goto queue; } @@ -123,6 +133,21 @@ int fsnotify_add_event(struct fsnotify_group *group, list_add_tail(&event->list, list); spin_unlock(&group->notification_lock); +#ifdef MY_ABC_HERE + // fetch_path() may sleep so we can't do it in notification_lock. + if (group->ops->fetch_path) { + ret = group->ops->fetch_path(event, group); + + if (ret < 0) { + spin_lock(&group->notification_lock); + group->q_len--; + list_del_init(&event->list); + spin_unlock(&group->notification_lock); + return ret; + } + } +#endif /* MY_ABC_HERE */ + wake_up(&group->notification_waitq); kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); return ret; diff --git a/fs/notify/synotify/Makefile b/fs/notify/synotify/Makefile new file mode 100644 index 000000000000..8ed1d615bb0f --- /dev/null +++ b/fs/notify/synotify/Makefile @@ -0,0 +1,2 @@ +obj-y += synotify_user.o +obj-$(CONFIG_SYNO_FS_SYNOTIFY) += synotify.o diff --git a/fs/notify/synotify/synotify.c b/fs/notify/synotify/synotify.c new file mode 100644 index 000000000000..96b2b4ade32f --- /dev/null +++ b/fs/notify/synotify/synotify.c @@ -0,0 +1,339 @@ +#include +#include +#include +#include +#include +#include /* UINT_MAX */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "synotify.h" + +static struct kmem_cache *synotify_event_info_cachep = NULL; + +static void path_append(char *parent_path, const char *child_name, int n) +{ + int i = strlen(parent_path); + + if (parent_path[i] != '/' && child_name[0] != '/' && n - 1 > i) { + parent_path[i] = '/'; + parent_path[i + 1] = '\0'; + strncat(parent_path, child_name, n - i - 2); + } else + strncat(parent_path, child_name, n - i - 1); +} + +/* + * Fetch full mount point path, + * It traverse vfsmount from down to up by following mnt_parent + * @in: struct vfsmount: vfsmount structure, size_t buf_len: path buffer length + * @out: mnt_full_path: full path of vfsmount struct + * @return: < 0 : failed, 0 : success + */ +static int syno_fetch_mountpoint_fullpath(struct vfsmount *mnt, char *mnt_full_path, char *d_path_buf) +{ + int ret = -1; + char *mnt_dentry_path = NULL; + struct nsproxy *nsproxy = current->nsproxy; + struct mnt_namespace *mnt_space = NULL; + struct mount *root_mnt = NULL; + struct path root_path; + struct path mnt_path; + struct task_struct *parent; + + + if (!nsproxy) { + /* + * When a process exits, CLOSE events will be sent asynchronously through + * do_exit -> exit_files -> ... -> delayed_fput -> __fput -> fsnotify_close + * + * At this point it may be troublesome to access current's namespace. To + * work round it, parent's namespace is used instead because most of + * the time processes have the same namespaces as their parents. + */ + rcu_read_lock(); + parent = rcu_dereference(current->real_parent); + + if (parent && parent->nsproxy) + mnt_space = parent->nsproxy->mnt_ns; + rcu_read_unlock(); + } else + mnt_space = nsproxy->mnt_ns; + + if (!mnt_space || !mnt_space->root) + return -EINVAL; + + get_mnt_ns(mnt_space); + + root_mnt = mnt_space->root; + memset(&root_path, 0, sizeof(struct path)); + root_path.mnt = &root_mnt->mnt; + root_path.dentry = root_mnt->mnt.mnt_root; + + memset(&mnt_path, 0, sizeof(struct path)); + mnt_path.mnt = mnt; + mnt_path.dentry = mnt->mnt_root; + + path_get(&mnt_path); + path_get(&root_path); + + mnt_dentry_path = __d_path(&mnt_path, &root_path, d_path_buf, PATH_MAX - 1); + if (IS_ERR_OR_NULL(mnt_dentry_path)) { + ret = -ENOENT; + goto RESOURCE_PUT; + } + + path_append(mnt_full_path, mnt_dentry_path, PATH_MAX); + + ret = 0; + +RESOURCE_PUT: + path_put(&root_path); + path_put(&mnt_path); + put_mnt_ns(mnt_space); + d_path_buf[0] = '\0'; + return ret; +} + +static int synotify_fetch_path(struct fsnotify_event *fsnotify_event, struct fsnotify_group *group) +{ + struct synotify_event_info *event = SYNOTIFY_E(fsnotify_event); + char *synotify_full_path_buf = NULL; + char *synotify_d_path_buf = NULL; + char *dentry_path = NULL; + struct vfsmount *mnt = event->path.mnt; + struct mem_cgroup *old_memcg; + int ret = 0; + + if (unlikely(event->overflow_event)) + return 0; + + mutex_lock(&group->notification_mutex); + synotify_full_path_buf = group->synotify_data.synotify_full_path_buf; + synotify_d_path_buf = group->synotify_data.synotify_d_path_buf; + synotify_full_path_buf[0] = '\0'; + synotify_d_path_buf[0] = '\0'; + + ret = syno_fetch_mountpoint_fullpath(mnt, synotify_full_path_buf, synotify_d_path_buf); + if (ret < 0) + goto ERR; + + if (!event->file_path) { + struct path root_path; + root_path.mnt = mnt; + root_path.dentry = mnt->mnt_root; + dentry_path = __d_path(&event->path, &root_path, synotify_d_path_buf, PATH_MAX-1); + if (unlikely(IS_ERR_OR_NULL(dentry_path))) { + ret = -ENOENT; + goto ERR; + } + path_append(synotify_full_path_buf, dentry_path, PATH_MAX); + } else // From fsnotify_move() + path_append(synotify_full_path_buf, event->file_path, PATH_MAX); + + /* Whoever is interested in the event, pays for the allocation. */ + old_memcg = set_active_memcg(group->memcg); + event->full_path = kstrdup(synotify_full_path_buf, GFP_KERNEL_ACCOUNT | __GFP_ZERO); + set_active_memcg(old_memcg); + if (unlikely(!event->full_path)) { + printk_ratelimited(KERN_WARNING "synotify encountered ENOMEM in fetch_path\n"); + ret = -ENOMEM; + goto ERR; + } + event->full_path_len = strlen(event->full_path); + event->path_ready = true; + +ERR: + synotify_full_path_buf[0] = '\0'; + synotify_d_path_buf[0] = '\0'; + mutex_unlock(&group->notification_mutex); + return ret; +} + +static bool should_merge(struct fsnotify_event *old_fsn, struct fsnotify_event *new_fsn) +{ + struct synotify_event_info *old, *new; + + pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); + old = SYNOTIFY_E(old_fsn); + new = SYNOTIFY_E(new_fsn); + + if (old->mask != new->mask) + return false; + + if ((new->mask & (FS_ATTRIB | FS_ACCESS | FS_MODIFY)) + && (old->path.mnt == new->path.mnt) + && (old->path.dentry == new->path.dentry)) + return true; + + return false; +} + +/* and the list better be locked by something too! */ +static int synotify_merge(struct list_head *list, + struct fsnotify_event *event) +{ + struct fsnotify_event *last_event; + pr_debug("%s: list=%p event=%p\n", __func__, list, event); + + last_event = list_entry(list->prev, struct fsnotify_event, list); + return should_merge(last_event, event); +} + +struct synotify_event_info *synotify_alloc_event(struct fsnotify_group *group, + u32 mask, const void *data, u32 cookie) +{ + const struct path *path = fsnotify_data_path(data, FSNOTIFY_EVENT_PATH); + struct synotify_event_info *event; + struct mem_cgroup *old_memcg; + + if (unlikely(!synotify_event_info_cachep)) + return NULL; + + /* Whoever is interested in the event, pays for the allocation. */ + old_memcg = set_active_memcg(group->memcg); + event = kmem_cache_alloc(synotify_event_info_cachep, + GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL); + set_active_memcg(old_memcg); + if (!event) + return NULL; + + fsnotify_init_event(&event->fse, 0); + event->mask = mask; + if (path) { + event->path = *path; + path_get(&event->path); + } else { + event->path.mnt = NULL; + event->path.dentry = NULL; + } + event->full_path = NULL; + event->full_path_len = 0; + event->sync_cookie = cookie; + event->file_path = NULL; + event->path_ready = false; + event->overflow_event = false; + + return event; +} + +static int synotify_handle_event(struct fsnotify_group *group, u32 mask, + const void *data, int data_type, + struct inode *dir, + const struct qstr *file_path, u32 cookie, + struct fsnotify_iter_info *iter_info) +{ + int ret = 0; + struct synotify_event_info *event; + struct fsnotify_event *fsn_event; + + BUILD_BUG_ON(SYNO_ACCESS != FS_ACCESS); + BUILD_BUG_ON(SYNO_MODIFY != FS_MODIFY); + BUILD_BUG_ON(SYNO_ATTRIB != FS_ATTRIB); + BUILD_BUG_ON(SYNO_CLOSE_NOWRITE != FS_CLOSE_NOWRITE); + BUILD_BUG_ON(SYNO_CLOSE_WRITE != FS_CLOSE_WRITE); + BUILD_BUG_ON(SYNO_OPEN != FS_OPEN); + BUILD_BUG_ON(SYNO_MOVE_TO != FS_MOVED_TO); + BUILD_BUG_ON(SYNO_MOVE_FROM != FS_MOVED_FROM); + BUILD_BUG_ON(SYNO_CREATE != FS_CREATE); + BUILD_BUG_ON(SYNO_DELETE != FS_DELETE); + BUILD_BUG_ON(SYNO_Q_OVERFLOW != FS_Q_OVERFLOW); + BUILD_BUG_ON(SYNO_ONDIR != FS_ISDIR); + + pr_debug("%s: group=%p mask=%x\n", __func__, group, mask); + + if (data_type != FSNOTIFY_EVENT_PATH && data_type != FSNOTIFY_EVENT_SYNO_MOVE) + return 0; + + event = synotify_alloc_event(group, mask, data, cookie); + if (unlikely(!event)) { + printk_ratelimited(KERN_WARNING "synotify encountered ENOMEM in alloc_event\n"); + return -ENOMEM; + } + + if (file_path && data_type == FSNOTIFY_EVENT_SYNO_MOVE) + event->file_path = file_path->name; + fsn_event = &event->fse; + + event->event_version = group->synotify_data.event_version; + + // v2 event + event->pid = task_tgid_nr_ns(current, &init_pid_ns); + event->uid = from_kuid_munged(&init_user_ns, current_uid()); + + ret = fsnotify_add_event(group, fsn_event, synotify_merge); + if (ret) { + fsnotify_destroy_event(group, fsn_event); + return ret > 0 ? 0 : ret; + } + + return 0; +} + +static void synotify_free_group_priv(struct fsnotify_group *group) +{ + struct user_struct *user; + + user = group->synotify_data.user; + if (user) { + atomic_dec(&user->synotify_instances); + free_uid(user); + } + + kfree(group->synotify_data.synotify_full_path_buf); + kfree(group->synotify_data.synotify_d_path_buf); +} + +static void synotify_free_event(struct fsnotify_event *fsn_event) +{ + struct synotify_event_info *event; + + event = SYNOTIFY_E(fsn_event); + + if (event->overflow_event) { + // allocated in synotify_alloc_overflow_event() + kfree(event); + } else { + // allocated in synotify_alloc_event() + path_put(&event->path); + kfree(event->full_path); + kmem_cache_free(synotify_event_info_cachep, event); + } +} + +static void synotify_free_mark(struct fsnotify_mark *fsn_mark) +{ + kfree(fsn_mark); +} + +const struct fsnotify_ops synotify_fsnotify_ops = { + .handle_event = synotify_handle_event, + .free_group_priv = synotify_free_group_priv, + .free_event = synotify_free_event, + .free_mark = synotify_free_mark, + .fetch_path = synotify_fetch_path, +}; + +static int __init synotify_setup(void) +{ + synotify_event_info_cachep = kmem_cache_create("synotify_event_info", + sizeof(struct synotify_event_info), 0, SLAB_MEM_SPREAD, NULL); + if (!synotify_event_info_cachep) + printk(KERN_ERR "synotify failed to kmem_cache_create synotify_event_info, disable synotify!\n"); + + return 0; +} + +static void __exit exit_synotify(void) +{ + kmem_cache_destroy(synotify_event_info_cachep); +} + +device_initcall(synotify_setup); +module_exit(exit_synotify) diff --git a/fs/notify/synotify/synotify.h b/fs/notify/synotify/synotify.h new file mode 100644 index 000000000000..b4c86ed8e222 --- /dev/null +++ b/fs/notify/synotify/synotify.h @@ -0,0 +1,47 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifdef MY_ABC_HERE +#include +#include +#include +#include "../../mount.h" + +/* flags used for synotify_set_mark() */ +#define SYNOTIFY_MARK_ADD 0x00000001 +#define SYNOTIFY_MARK_REMOVE 0x00000002 + +/* + * Structure for normal synotify events. It gets allocated in + * synotify_handle_event() and freed when the information is retrieved by + * userspace + */ +struct synotify_event_info { + struct fsnotify_event fse; + u32 mask; + u32 sync_cookie; + /* + * We hold ref to this path so it may be dereferenced at any point + * during this object's lifetime + */ + struct path path; + const char *full_path; + size_t full_path_len; + const char *file_path; + bool path_ready; + bool overflow_event; + int event_version; + + // v2 event + pid_t pid; + uid_t uid; +}; + +static inline struct synotify_event_info *SYNOTIFY_E(struct fsnotify_event *fse) +{ + return container_of(fse, struct synotify_event_info, fse); +} + +struct synotify_event_info *synotify_alloc_event(struct fsnotify_group *group, + u32 mask, const void *data, u32 cookie); +#endif /* MY_ABC_HERE */ diff --git a/fs/notify/synotify/synotify_user.c b/fs/notify/synotify/synotify_user.c new file mode 100644 index 000000000000..95914c04c8ed --- /dev/null +++ b/fs/notify/synotify/synotify_user.c @@ -0,0 +1,642 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ +#include +#include /* struct inode */ +#include +#include +#include /* module_init */ +#include +#include /* roundup() */ +#include /* LOOKUP_FOLLOW */ +#include /* struct user */ +#include /* struct kmem_cache */ +#include +#include +#include +#include +#include +#include /* struct vfsmount */ +#include + +#include + +#include "synotify.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SYNOTIFY_DEFAULT_MAX_EVENTS 16384 /* per group */ +#define SYNOTIFY_DEFAULT_MAX_WATCHERS 8192 /* per group */ +#define SYNOTIFY_DEFAULT_MAX_INSTANCES 128 /* per user */ + +extern const struct fsnotify_ops synotify_fsnotify_ops; + +static int synotify_max_queued_events = SYNOTIFY_DEFAULT_MAX_EVENTS; + +#ifdef CONFIG_SYSCTL +#include +struct ctl_table synotify_table[] = { + { + .procname = "max_queued_events", + .data = &synotify_max_queued_events, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO + }, + { } +}; +#endif /* CONFIG_SYSCTL */ + +// Not including name ! +static int get_event_fixed_size(struct synotify_event_info *event) +{ + if (event->event_version == 2) + return sizeof(struct synotify_event_v2); + else + return sizeof(struct synotify_event); +} + +static int round_event_name_len(struct synotify_event_info *event) +{ + if (!event->full_path_len) + return 0; + + if (event->event_version == 2) + return roundup(event->full_path_len + 1, sizeof(struct synotify_event_v2)); + else + return roundup(event->full_path_len + 1, sizeof(struct synotify_event)); +} + +/* + * Get an fsnotify notification event if one exists and is small + * enough to fit in "count". Return an error pointer if the count + * is not large enough. + */ +static struct synotify_event_info *get_one_event(struct fsnotify_group *group, + size_t count) +{ + size_t event_size; + struct synotify_event_info *event = NULL; + + pr_debug("%s: group=%p count=%zd\n", __func__, group, count); + + spin_lock(&group->notification_lock); + if (fsnotify_notify_queue_is_empty(group)) + goto out; + + event = SYNOTIFY_E(fsnotify_peek_first_event(group)); + + if (event->path_ready == false && event->overflow_event == false) { + event = NULL; + goto out; + } + + event_size = get_event_fixed_size(event); + event_size += round_event_name_len(event); + if (event_size > count) { + event = ERR_PTR(-EINVAL); + goto out; + } + event = SYNOTIFY_E(fsnotify_remove_first_event(group)); +out: + spin_unlock(&group->notification_lock); + return event; +} + +static inline u32 synotify_mask_to_arg(__u32 mask) +{ + return mask & SYNO_ALL_EVENTS; +} + +static ssize_t copy_event_to_user(struct fsnotify_group *group, + struct synotify_event_info *event, + char __user *buf) +{ + struct synotify_event_v2 synotify_event; // Use largest version. + size_t event_size; + size_t pad_name_len; + + pr_debug("%s: group=%p event=%p\n", __func__, group, event); + + /* + * round up event->name_len so it is a multiple of event_size + * plus an extra byte for the terminating '\0'. + */ + pad_name_len = round_event_name_len(event); + synotify_event.len = pad_name_len; + synotify_event.mask = synotify_mask_to_arg(event->mask); + synotify_event.cookie = event->sync_cookie; + + if (event->event_version == 2) { + event_size = sizeof(struct synotify_event_v2); + synotify_event.pid = (u32)event->pid; + synotify_event.uid = (u32)event->uid; + } else + event_size = sizeof(struct synotify_event); + + /* send the main event */ + if (copy_to_user(buf, &synotify_event, event_size)) + return -EFAULT; + + buf += event_size; + + /* + * fsnotify only stores the pathname, so here we have to send the pathname + * and then pad that pathname out to a multiple of sizeof(synotify_event) + * with zeros. + */ + if (pad_name_len) { + /* copy the path name */ + if (copy_to_user(buf, event->full_path, event->full_path_len)) + return -EFAULT; + buf += event->full_path_len; + + /* fill userspace with 0's */ + if (clear_user(buf, pad_name_len - event->full_path_len)) + return -EFAULT; + event_size += pad_name_len; + } + + return event_size; +} + +/* synotifiy userspace file descriptor functions */ +static __poll_t synotify_poll(struct file *file, poll_table *wait) +{ + struct fsnotify_group *group = file->private_data; + __poll_t ret = 0; + + poll_wait(file, &group->notification_waitq, wait); + spin_lock(&group->notification_lock); + if (!fsnotify_notify_queue_is_empty(group)) + ret = POLLIN | POLLRDNORM; + spin_unlock(&group->notification_lock); + + return ret; +} + +static ssize_t synotify_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct fsnotify_group *group; + struct synotify_event_info *event; + char __user *start; + int ret; + DEFINE_WAIT_FUNC(wait, woken_wake_function); + + start = buf; + group = file->private_data; + + pr_debug("%s: group=%p\n", __func__, group); + + add_wait_queue(&group->notification_waitq, &wait); + while (1) { + /* + * User can supply arbitrarily large buffer. Avoid softlockups + * in case there are lots of available events. + */ + cond_resched(); + event = get_one_event(group, count); + if (IS_ERR(event)) { + ret = PTR_ERR(event); + break; + } + + if (!event) { + ret = -EAGAIN; + if (file->f_flags & O_NONBLOCK) + break; + + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; + + if (start != buf) + break; + + wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); + continue; + } + + ret = copy_event_to_user(group, event, buf); + if (unlikely(ret == -EOPENSTALE)) { + /* + * We cannot report events with stale fd so drop it. + * Setting ret to 0 will continue the event loop and + * do the right thing if there are no more events to + * read (i.e. return bytes read, -EAGAIN or wait). + */ + ret = 0; + } + + fsnotify_destroy_event(group, &event->fse); + if (ret < 0) + break; + buf += ret; + count -= ret; + } + remove_wait_queue(&group->notification_waitq, &wait); + + if (start != buf && ret != -EFAULT) + ret = buf - start; + return ret; +} + +static int synotify_release(struct inode *ignored, struct file *file) +{ + struct fsnotify_group *group = file->private_data; + + pr_debug("%s: group=%p\n", __func__, group); + + /* matches the SYNONotifyInit->fsnotify_alloc_group */ + fsnotify_destroy_group(group); + + return 0; +} + +static long synotify_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct fsnotify_group *group; + struct fsnotify_event *fsn_event; + void __user *p; + int ret = -ENOTTY; + size_t send_len = 0; + + group = file->private_data; + p = (void __user *) arg; + + pr_debug("%s: group=%p cmd=%u\n", __func__, group, cmd); + + switch (cmd) { + case FIONREAD: + spin_lock(&group->notification_lock); + list_for_each_entry(fsn_event, &group->notification_list, list) { + send_len += get_event_fixed_size(SYNOTIFY_E(fsn_event)); + send_len += round_event_name_len(SYNOTIFY_E(fsn_event)); + } + spin_unlock(&group->notification_lock); + ret = put_user(send_len, (int __user *) p); + break; + } + + return ret; +} + +static const struct file_operations synotify_fops = { + .poll = synotify_poll, + .read = synotify_read, + .fasync = NULL, + .release = synotify_release, + .unlocked_ioctl = synotify_ioctl, + .compat_ioctl = synotify_ioctl, + .llseek = noop_llseek, +}; + +static int synotify_find_path(const char __user *filename, + struct path *path, unsigned int flags, __u64 mask) +{ + int ret; + + pr_debug("%s: filename=%p flags=%x\n", __func__, filename, flags); + + ret = user_path_at(AT_FDCWD, filename, flags, path); + if (ret) + return ret; + + /* you can only watch an inode if you have read permissions on it */ +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path->dentry)) + ret = synoacl_op_permission(path->dentry, MAY_READ); + else +#endif /* MY_ABC_HERE */ + ret = inode_permission(path->dentry->d_inode, MAY_READ); + if (ret) + goto out; + + ret = security_path_notify(path, mask, FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT); + +out: + if (ret) + path_put(path); + return ret; +} + +static __u32 synotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, + __u32 mask, int *destroy) +{ + __u32 oldmask; + + mask &= ~SYNO_DONT_FOLLOW; + spin_lock(&fsn_mark->lock); + + oldmask = fsn_mark->mask; + fsn_mark->mask &= ~mask; + *destroy = !(fsn_mark->mask & ~SYNO_DONT_FOLLOW); + + spin_unlock(&fsn_mark->lock); + + return mask & oldmask; +} + +static int synotify_remove_vfsmount_mark(struct fsnotify_group *group, + struct vfsmount *mnt, __u32 mask) +{ + struct fsnotify_mark *fsn_mark = NULL; + fsnotify_connp_t *connp = &real_mount(mnt)->mnt_fsnotify_syno_marks; + __u32 removed; + int destroy_mark; + + mutex_lock(&group->mark_mutex); + fsn_mark = fsnotify_find_mark(connp, group); + if (!fsn_mark) { + mutex_unlock(&group->mark_mutex); + return -ENOENT; + } + + removed = synotify_mark_remove_from_mask(fsn_mark, mask, &destroy_mark); + if (removed & fsnotify_conn_mask(fsn_mark->connector)) + fsnotify_recalc_mask(fsn_mark->connector); + if (destroy_mark) + fsnotify_detach_mark(fsn_mark); + mutex_unlock(&group->mark_mutex); + if (destroy_mark) + fsnotify_free_mark(fsn_mark); + + /* matches the fsnotify_find_mark() */ + fsnotify_put_mark(fsn_mark); + return 0; +} + +static __u32 synotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, + __u32 mask) +{ + __u32 oldmask = 0; + __u32 setmask = 0; + + setmask = mask & ~SYNO_DONT_FOLLOW; + + spin_lock(&fsn_mark->lock); + + oldmask = fsn_mark->mask; + fsn_mark->mask |= setmask; + + spin_unlock(&fsn_mark->lock); + + /* return new add event */ + return setmask & ~oldmask; +} + +static struct fsnotify_mark *synotify_add_new_mark(struct fsnotify_group *group, + fsnotify_connp_t *connp) +{ + struct fsnotify_mark *mark; + int ret; + + if (atomic_read(&group->num_marks) > group->synotify_data.max_watchers) + return ERR_PTR(-ENOSPC); + + mark = kmalloc(sizeof(struct fsnotify_mark), GFP_KERNEL_ACCOUNT); + if (!mark) + return ERR_PTR(-ENOMEM); + + fsnotify_init_mark(mark, group); + ret = fsnotify_add_mark_locked(mark, connp, FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT, 0, NULL); + if (ret) { + fsnotify_put_mark(mark); + return ERR_PTR(ret); + } + + return mark; +} + +static int synotify_add_vfsmount_mark(struct fsnotify_group *group, + struct vfsmount *mnt, __u32 mask) +{ + struct fsnotify_mark *fsn_mark; + fsnotify_connp_t *connp = &real_mount(mnt)->mnt_fsnotify_syno_marks; + __u32 added; + + mutex_lock(&group->mark_mutex); + fsn_mark = fsnotify_find_mark(connp, group); + if (!fsn_mark) { + fsn_mark = synotify_add_new_mark(group, connp); + if (IS_ERR(fsn_mark)) { + mutex_unlock(&group->mark_mutex); + return PTR_ERR(fsn_mark); + } + } + added = synotify_mark_add_to_mask(fsn_mark, mask); + if (added & ~fsnotify_conn_mask(fsn_mark->connector)) + fsnotify_recalc_mask(fsn_mark->connector); + mutex_unlock(&group->mark_mutex); + + fsnotify_put_mark(fsn_mark); + return 0; +} + +static struct fsnotify_event *synotify_alloc_overflow_event(void) +{ + struct synotify_event_info *oevent; + + oevent = kzalloc(sizeof(*oevent), GFP_KERNEL_ACCOUNT); + if (!oevent) + return NULL; + + fsnotify_init_event(&oevent->fse, 0); + oevent->mask = SYNO_Q_OVERFLOW; + oevent->overflow_event = true; + + return &oevent->fse; +} + +static int __syno_notify_init(unsigned int flags) +{ + struct fsnotify_group *group; + int f_flags = 0; + int fd = 0; + struct user_struct *user; + + pr_debug("%s: flags=%x\n", __func__, flags); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (flags & ~(SYNO_NONBLOCK | SYNO_CLOEXEC | SYNO_EVENT_V2)) + return -EINVAL; + + if (flags & SYNO_CLOEXEC) + f_flags |= O_CLOEXEC; + if (flags & SYNO_NONBLOCK) + f_flags |= O_NONBLOCK; + + user = get_current_user(); + if (atomic_read(&user->synotify_instances) > SYNOTIFY_DEFAULT_MAX_INSTANCES) { + free_uid(user); + return -EMFILE; + } + + /* fsnotify_alloc_group takes a ref. Dropped in synotify_release */ + group = fsnotify_alloc_group(&synotify_fsnotify_ops); + if (IS_ERR(group)) { + free_uid(user); + return PTR_ERR(group); + } + + group->synotify_data.synotify_full_path_buf = kzalloc(PATH_MAX, GFP_KERNEL_ACCOUNT); + group->synotify_data.synotify_d_path_buf = kzalloc(PATH_MAX, GFP_KERNEL_ACCOUNT); + if (!group->synotify_data.synotify_full_path_buf || !group->synotify_data.synotify_d_path_buf) { + fd = -ENOMEM; + goto out_destroy_group; + } + + group->synotify_data.user = user; + atomic_inc(&user->synotify_instances); + group->memcg = get_mem_cgroup_from_mm(current->mm); + + group->overflow_event = synotify_alloc_overflow_event(); + if (unlikely(!group->overflow_event)) { + fd = -ENOMEM; + goto out_destroy_group; + } + + group->max_events = synotify_max_queued_events; + group->synotify_data.max_watchers = SYNOTIFY_DEFAULT_MAX_WATCHERS; + printk(KERN_INFO "Synotify use %d event queue size\n", group->max_events); + + if (flags & SYNO_EVENT_V2) + group->synotify_data.event_version = 2; + else + group->synotify_data.event_version = 1; + + fd = anon_inode_getfd("[synotify]", &synotify_fops, group, f_flags); + if (fd < 0) + goto out_destroy_group; + + return fd; + +out_destroy_group: + fsnotify_destroy_group(group); // Also free group's path buffer + return fd; +} + +static int synotify_set_mark(int synotify_fd, const char __user * pathname, __u64 mask, unsigned int synotify_flag) +{ + struct vfsmount *mnt = NULL; + struct fsnotify_group *group; + struct path path; + struct fd f; + int ret = -EINVAL; + unsigned int flags = 0; + + pr_debug("%s: synotify_fd=%d pathname=%p mask=%llx\n",__FUNCTION__, synotify_fd, pathname, mask); + + /* we only use the lower 32 bits as of right now. */ + if (mask & ((__u64)0xffffffff << 32)) + return -EINVAL; + + if (mask & ~(SYNO_ALL_EVENTS | SYNO_DONT_FOLLOW)) + return -EINVAL; + + f = fdget(synotify_fd); + if (unlikely(!f.file)) + return -EBADF; + + /* verify that this is indeed an synotify instance */ + if (unlikely(f.file->f_op != &synotify_fops)) { + ret = -EINVAL; + goto fput_and_out; + } + + if (!(mask & SYNO_DONT_FOLLOW)) + flags |= LOOKUP_FOLLOW; + + ret = synotify_find_path(pathname, &path, flags, + (mask & SYNO_ALL_EVENTS)); + if (ret) + goto fput_and_out; + + group = f.file->private_data; + + mnt = path.mnt; + + /* add/remove an vfsmount mark */ + switch (synotify_flag & (SYNOTIFY_MARK_ADD | SYNOTIFY_MARK_REMOVE)) { + case SYNOTIFY_MARK_ADD: + ret = synotify_add_vfsmount_mark(group, mnt, mask); + break; + case SYNOTIFY_MARK_REMOVE: + ret = synotify_remove_vfsmount_mark(group, mnt, mask); + break; + default: + ret = -EINVAL; + } + + path_put(&path); +fput_and_out: + fdput(f); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* synotify syscalls */ +SYSCALL_DEFINE1(syno_notify_init, unsigned int, flags) +{ +#ifdef MY_ABC_HERE + return __syno_notify_init(flags); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE1(SYNONotifyInit, unsigned int, flags) +{ +#ifdef MY_ABC_HERE + return __syno_notify_init(flags); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(syno_notify_remove_watch, int, synotify_fd, const char __user *, pathname, __u64, mask) +{ +#ifdef MY_ABC_HERE + return synotify_set_mark(synotify_fd, pathname, mask, SYNOTIFY_MARK_REMOVE); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(SYNONotifyRemoveWatch, int, synotify_fd, const char __user *, pathname, __u64, mask) +{ +#ifdef MY_ABC_HERE + return synotify_set_mark(synotify_fd, pathname, mask, SYNOTIFY_MARK_REMOVE); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(syno_notify_add_watch, int, synotify_fd, const char __user *, pathname, __u64, mask) +{ +#ifdef MY_ABC_HERE + return synotify_set_mark(synotify_fd, pathname, mask, SYNOTIFY_MARK_ADD); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(SYNONotifyAddWatch, int, synotify_fd, const char __user *, pathname, __u64, mask) +{ +#ifdef MY_ABC_HERE + return synotify_set_mark(synotify_fd, pathname, mask, SYNOTIFY_MARK_ADD); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ diff --git a/fs/open.c b/fs/open.c index 3aaaad47d9ca..a782edaeebe5 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/open.c @@ -35,6 +38,13 @@ #include "internal.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) { @@ -65,6 +75,9 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, inode_unlock(dentry->d_inode); return ret; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(do_truncate); +#endif /* MY_ABC_HERE */ long vfs_truncate(const struct path *path, loff_t length) { @@ -83,6 +96,11 @@ long vfs_truncate(const struct path *path, loff_t length) if (error) goto out; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path->dentry)) + error = synoacl_op_permission(path->dentry, MAY_WRITE); + else +#endif /* MY_ABC_HERE */ error = inode_permission(inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; @@ -118,6 +136,14 @@ long vfs_truncate(const struct path *path, loff_t length) } EXPORT_SYMBOL_GPL(vfs_truncate); +#ifdef MY_ABC_HERE +long syno_vfs_truncate(struct path *path, loff_t length) +{ + return vfs_truncate(path, length); +} +EXPORT_SYMBOL(syno_vfs_truncate); +#endif /* MY_ABC_HERE */ + long do_sys_truncate(const char __user *pathname, loff_t length) { unsigned int lookup_flags = LOOKUP_FOLLOW; @@ -335,6 +361,14 @@ int ksys_fallocate(int fd, int mode, loff_t offset, loff_t len) return error; } +#ifdef MY_ABC_HERE +int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) +{ + return vfs_fallocate(file, mode, offset, len); +} +EXPORT_SYMBOL(do_fallocate); +#endif /* MY_ABC_HERE */ + SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) { return ksys_fallocate(fd, mode, offset, len); @@ -436,6 +470,11 @@ static long do_faccessat(int dfd, const char __user *filename, int mode, int fla goto out_path_release; } +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path.dentry)) + res = synoacl_op_may_access(path.dentry, mode); + else +#endif /* MY_ABC_HERE */ res = inode_permission(inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) @@ -492,6 +531,11 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) if (error) goto out; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path.dentry)) + error = synoacl_op_permission(path.dentry, MAY_EXEC); + else +#endif /* MY_ABC_HERE */ error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -521,6 +565,11 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) if (!d_can_lookup(f.file->f_path.dentry)) goto out_putf; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(file_dentry(f.file))) + error = synoacl_op_permission(file_dentry(f.file), MAY_EXEC); + else +#endif /* MY_ABC_HERE */ error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); @@ -540,6 +589,11 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) if (error) goto out; +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path.dentry)) + error = synoacl_op_permission(path.dentry, MAY_EXEC); + else +#endif /* MY_ABC_HERE */ error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -770,13 +824,23 @@ static int do_dentry_open(struct file *f, path_get(&f->f_path); f->f_inode = inode; f->f_mapping = inode->i_mapping; +#ifdef MY_ABC_HERE + file_sb_list_add(f); +#endif /* MY_ABC_HERE */ f->f_wb_err = filemap_sample_wb_err(f->f_mapping); f->f_sb_err = file_sample_sb_err(f); if (unlikely(f->f_flags & O_PATH)) { f->f_mode = FMODE_PATH | FMODE_OPENED; +#ifdef MY_ABC_HERE + if (strcmp(inode->i_sb->s_type->name, "ext4") != 0 || !S_ISLNK(inode->i_mode)) { + f->f_op = &empty_fops; + return 0; + } +#else /* MY_ABC_HERE */ f->f_op = &empty_fops; return 0; +#endif /* MY_ABC_HERE */ } if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { @@ -801,6 +865,12 @@ static int do_dentry_open(struct file *f, goto cleanup_all; } +#ifdef MY_ABC_HERE + if (inode->i_opflags & IOP_ECRYPTFS_LOWER_INIT) { + inode->i_opflags &= ~IOP_ECRYPTFS_LOWER_INIT; + error = 0; + } else +#endif /* MY_ABC_HERE */ error = security_file_open(f); if (error) goto cleanup_all; @@ -852,6 +922,9 @@ static int do_dentry_open(struct file *f, if (WARN_ON_ONCE(error > 0)) error = -EINVAL; fops_put(f->f_op); +#ifdef MY_ABC_HERE + file_sb_list_del(f); +#endif /* MY_ABC_HERE */ if (f->f_mode & FMODE_WRITER) { put_write_access(inode); __mnt_drop_write(f->f_path.mnt); @@ -1393,3 +1466,232 @@ int stream_open(struct inode *inode, struct file *filp) } EXPORT_SYMBOL(stream_open); + +#ifdef MY_ABC_HERE +SYSCALL_DEFINE2(syno_archive_bit, const char __user *, filename, int, cmd) +{ +#ifdef MY_ABC_HERE + struct path path; + long error; + + if (SYNO_FCNTL_BASE > cmd || SYNO_FCNTL_LAST < cmd) { + printk_ratelimited(KERN_WARNING "Archive bit cmd:%x not implement.\n", cmd); + return -EINVAL; + } + + error = user_path_at(AT_FDCWD, filename, LOOKUP_FOLLOW, &path); + if (error) + return error; + + error = mnt_want_write(path.mnt); + if (error) + goto out_release; + + error = syno_archive_bit_set(path.dentry, cmd); + mnt_drop_write(path.mnt); + +out_release: + path_put(&path); + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE2(syno_archive_overwrite, unsigned int, fd, unsigned int, flags) +{ +#ifdef MY_ABC_HERE + struct fd f = fdget(fd); + int error = -EBADF; + + if (!f.file) + return error; + + error = mnt_want_write(f.file->f_path.mnt); + if (error) + goto fput_out; + + error = syno_archive_bit_overwrite(f.file->f_path.dentry, flags); + mnt_drop_write(f.file->f_path.mnt); + +fput_out: + fdput(f); + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +#ifdef MY_ABC_HERE +#include "ecryptfs/ecryptfs_kernel.h" +#endif /* MY_ABC_HERE */ + +SYSCALL_DEFINE2(syno_ecrypt_name, const char __user *, src, char __user *, dst) +{ +#ifdef MY_ABC_HERE + int err = -1; + struct qstr *lower_path = NULL; + struct path path; + struct ecryptfs_dentry_info *crypt_dentry = NULL; + + if (NULL == src || NULL == dst) + return -EINVAL; + + err = user_path_at(AT_FDCWD, src, LOOKUP_FOLLOW, &path); + if (err) + return -ENOENT; + + if (ECRYPTFS_SUPER_MAGIC != path.dentry->d_sb->s_magic) { + err = -EINVAL; + goto out_release; + } + crypt_dentry = ecryptfs_dentry_to_private(path.dentry); + if (!crypt_dentry) { + err = -EINVAL; + goto out_release; + } + lower_path = &crypt_dentry->lower_path.dentry->d_name; + err = copy_to_user(dst, lower_path->name, lower_path->len + 1); + +out_release: + path_put(&path); + + return err; +#else /* MY_ABC_HERE */ + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +#ifdef MY_ABC_HERE +/* + * Since strlcat() will BUG_ON when it meet overflow, + * We add this api to replace strlcat(). + */ +static inline int strcat_check(char *dst, size_t *remain, + const char *src, size_t size) +{ + if (*remain <= size) + return -ENOBUFS; + strncat(dst, src, *remain); + *remain -= size; + return 0; +} +#endif /* MY_ABC_HERE */ + +SYSCALL_DEFINE3(syno_decrypt_name, const char __user *, root, const char __user *, src, char __user *, dst) +{ +#ifdef MY_ABC_HERE + int err = -1; + size_t plaintext_name_size = 0; + char *plaintext_name = NULL; + char *token = NULL; + char *target = NULL; + struct filename *root_name = NULL; + struct filename *src_name = NULL; + char *src_walk = NULL; + char *src_orig = NULL; + struct path path; + size_t remain = PATH_MAX; + int ret = -1; + + if (NULL == src || NULL == root || NULL == dst) + return -EINVAL; + + root_name = getname(root); + if (IS_ERR(root_name)) { + err = PTR_ERR(root_name); + goto out_release; + } + target = kmalloc(remain, GFP_KERNEL); + if (!target) { + err = -ENOMEM; + goto out_release; + } + + ret = snprintf(target, remain, "%s", root_name->name); + if (ret < 0 || (ret >= remain)) { + err = -ENOBUFS; + goto out_release; + } + remain -= ret; + + src_name = getname(src); + if (IS_ERR(src_name)) { + err = PTR_ERR(src_name); + goto out_release; + } + // strsep() will move src_walk, so we should keep the head for free mem + src_walk = kstrdup(src_name->name, GFP_KERNEL); + if (!src_walk) { + err = -ENOMEM; + goto out_release; + } + src_orig = src_walk; + + token = strsep(&src_walk, "/"); + + while (token) { + if (*token == '\0') { + err = strcat_check(target, &remain, "/", 1); + if (err) + goto out_release; + goto next_token; + } + + err = kern_path(target, LOOKUP_FOLLOW, &path); + if (err) + goto out_release; + + err = strcat_check(target, &remain, "/", 1); + if (err) { + path_put(&path); + goto out_release; + } + if (path.dentry->d_sb->s_op && + path.dentry->d_sb->s_op->syno_decrypt_filename) { + err = path.dentry->d_sb->s_op->syno_decrypt_filename( + &plaintext_name, &plaintext_name_size, + path.dentry->d_sb, token, strlen(token)); + if (err) { + path_put(&path); + goto out_release; + } + err = strcat_check(target, &remain, + plaintext_name, + plaintext_name_size); + if (err) { + path_put(&path); + goto out_release; + } + kfree(plaintext_name); + plaintext_name = NULL; + } else { + err = strcat_check(target, &remain, + token, strlen(token)); + if (err) { + path_put(&path); + goto out_release; + } + } + + path_put(&path); +next_token: + token = strsep(&src_walk, "/"); + } + + err = copy_to_user(dst, target, strlen(target) + 1); +out_release: + kfree(src_orig); + kfree(plaintext_name); + kfree(target); + if (!IS_ERR_OR_NULL(src_name)) + putname(src_name); + if (!IS_ERR_OR_NULL(root_name)) + putname(root_name); + return err; + +#else /* MY_ABC_HERE */ + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index d1efa3a5a503..89c2ebc5fed9 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -1212,9 +1212,13 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, goto out_dput; } } else { - if (!d_is_negative(newdentry) && - (!new_opaque || !ovl_is_whiteout(newdentry))) - goto out_dput; + if (!d_is_negative(newdentry)) { + if (!new_opaque || !ovl_is_whiteout(newdentry)) + goto out_dput; + } else { + if (flags & RENAME_EXCHANGE) + goto out_dput; + } } if (olddentry == trap) diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index e8b14d2c180c..a6a92831dfa9 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Novell Inc. @@ -115,10 +118,15 @@ void ovl_dentry_update_reval(struct dentry *dentry, struct dentry *upperdentry, bool ovl_dentry_weird(struct dentry *dentry) { +#ifdef MY_ABC_HERE + return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | + DCACHE_MANAGE_TRANSIT); +#else return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | DCACHE_MANAGE_TRANSIT | DCACHE_OP_HASH | DCACHE_OP_COMPARE); +#endif } enum ovl_path_type ovl_path_type(struct dentry *dentry) diff --git a/fs/proc/base.c b/fs/proc/base.c index 5d52aea8d7e7..7d55c7aabd74 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/proc/base.c @@ -2184,7 +2187,11 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) rc = -ENOENT; vma = find_exact_vma(mm, vm_start, vm_end); if (vma && vma->vm_file) { +#ifdef MY_ABC_HERE + *path = vma_pr_or_file(vma)->f_path; +#else *path = vma->vm_file->f_path; +#endif /* MY_ABC_HERE */ path_get(path); rc = 0; } diff --git a/fs/proc/loadavg.c b/fs/proc/loadavg.c index 8468baee951d..ec1087eb6923 100644 --- a/fs/proc/loadavg.c +++ b/fs/proc/loadavg.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -25,9 +28,31 @@ static int loadavg_proc_show(struct seq_file *m, void *v) return 0; } +#ifdef MY_ABC_HERE +static int syno_loadavg_proc_show(struct seq_file *m, void *v) +{ + unsigned long avnrun_io[3]; + unsigned long avnrun_cpu[3]; + + get_avenrun_split(avnrun_io, avnrun_cpu, FIXED_1/200, 0); + + seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu\n", + LOAD_INT(avnrun_io[0]), LOAD_FRAC(avnrun_io[0]), + LOAD_INT(avnrun_io[1]), LOAD_FRAC(avnrun_io[1]), + LOAD_INT(avnrun_io[2]), LOAD_FRAC(avnrun_io[2]), + LOAD_INT(avnrun_cpu[0]), LOAD_FRAC(avnrun_cpu[0]), + LOAD_INT(avnrun_cpu[1]), LOAD_FRAC(avnrun_cpu[1]), + LOAD_INT(avnrun_cpu[2]), LOAD_FRAC(avnrun_cpu[2])); + return 0; +} +#endif /* MY_ABC_HERE */ + static int __init proc_loadavg_init(void) { proc_create_single("loadavg", 0, NULL, loadavg_proc_show); +#ifdef MY_ABC_HERE + proc_create_single("syno_loadavg", 0, NULL, syno_loadavg_proc_show); +#endif /* MY_ABC_HERE */ return 0; } fs_initcall(proc_loadavg_init); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 13452b32e2bd..470a8bc39b22 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* nommu.c: mmu-less memory info files * @@ -40,7 +43,14 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) file = region->vm_file; if (file) { +#ifdef MY_ABC_HERE + struct inode *inode; + + file = vmr_pr_or_file(region); + inode = file_inode(file); +#else struct inode *inode = file_inode(region->vm_file); +#endif /* MY_ABC_HERE */ dev = inode->i_sb->s_dev; ino = inode->i_ino; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 3931f60e421f..baf343a4b404 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -280,7 +283,14 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) const char *name = NULL; if (file) { +#ifdef MY_ABC_HERE + struct inode *inode; + + file = vma_pr_or_file(vma); + inode = file_inode(file); +#else struct inode *inode = file_inode(vma->vm_file); +#endif /* MY_ABC_HERE */ dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; @@ -1863,7 +1873,11 @@ static int show_numa_map(struct seq_file *m, void *v) struct proc_maps_private *proc_priv = &numa_priv->proc_maps; struct vm_area_struct *vma = v; struct numa_maps *md = &numa_priv->md; +#ifdef MY_ABC_HERE + struct file *file = vma_pr_or_file(vma); +#else struct file *file = vma->vm_file; +#endif /* MY_ABC_HERE */ struct mm_struct *mm = vma->vm_mm; struct mempolicy *pol; char buffer[64]; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index a6d21fc0033c..2f7bdffb9962 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include @@ -155,7 +158,14 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) file = vma->vm_file; if (file) { +#ifdef MY_ABC_HERE + struct inode *inode; + + file = vma_pr_or_file(vma); + inode = file_inode(file); +#else struct inode *inode = file_inode(vma->vm_file); +#endif /* MY_ABC_HERE */ dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index eafb75755fa3..149c1c03264e 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * fs/proc_namespace.c - handling of /proc//{mounts,mountinfo,mountstats} @@ -79,6 +82,10 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) if (mnt->mnt_flags & fs_infop->flag) seq_puts(m, fs_infop->str); } +#ifdef MY_ABC_HERE + if ((mnt->mnt_flags & MNT_RELATIME) && mnt->mnt_root->d_sb->relatime_period > 1) + seq_printf(m, ",relatime_period=%ld", mnt->mnt_root->d_sb->relatime_period); +#endif /* MY_ABC_HERE */ } static inline void mangle(struct seq_file *m, const char *s) diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 8efe60487b48..f4cf2bcce268 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -165,7 +165,7 @@ config PSTORE_BLK tristate "Log panic/oops to a block device" depends on PSTORE depends on BLOCK - depends on BROKEN + depends on BROKEN || SYNO_LSP_RTD1619B select PSTORE_ZONE default n help diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index b1ebf7b61732..a38f99ffb629 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Persistent Storage - platform driver interface parts. @@ -389,6 +392,9 @@ static void pstore_dump(struct kmsg_dumper *dumper, const char *why; unsigned int part = 1; int ret; +#ifdef MY_ABC_HERE + struct timespec64 boot_time; +#endif /* MY_ABC_HERE */ why = kmsg_dump_reason_str(reason); @@ -406,6 +412,11 @@ static void pstore_dump(struct kmsg_dumper *dumper, } oopscount++; + +#ifdef MY_ABC_HERE + getboottime64(&boot_time); +#endif /* MY_ABC_HERE */ + while (total < kmsg_bytes) { char *dst; size_t dst_size; @@ -430,8 +441,13 @@ static void pstore_dump(struct kmsg_dumper *dumper, } /* Write dump header. */ +#ifdef MY_ABC_HERE + header_size = snprintf(dst, dst_size, "%s#%d Part%u, btime %d\n", why, + oopscount, part, (int)boot_time.tv_sec); +#else /* MY_ABC_HERE */ header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why, oopscount, part); +#endif /* MY_ABC_HERE */ dst_size -= header_size; /* Write dump contents. */ @@ -452,6 +468,10 @@ static void pstore_dump(struct kmsg_dumper *dumper, dump_size); } } else { +#ifdef MY_ABC_HERE + header_size = sprintf(dst, "%s#%d Part%u, btime %d\n", why, + oopscount, part, (int)boot_time.tv_sec); +#endif /* MY_ABC_HERE */ record.size = header_size + dump_size; } diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c index 3ce89216670c..7b3d4fc79670 100644 --- a/fs/pstore/zone.c +++ b/fs/pstore/zone.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Provide a pstore intermediate backend, organized into kernel memory @@ -377,6 +380,11 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt) struct psz_kmsg_header *hdr; struct timespec64 time = { }; unsigned long i; +#if defined(MY_DEF_HERE) + loff_t erase_off = 0x0; + unsigned int used_zone = 0; + unsigned int temp_counter = 0; +#endif /* MY_DEF_HERE */ /* * Recover may on panic, we can't allocate any memory by kmalloc. * So, we use local array instead. @@ -405,6 +413,9 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt) if (buf->sig != zone->buffer->sig) { pr_debug("no valid data in kmsg dump zone %lu\n", i); +#if defined(MY_DEF_HERE) + info->erase(info->kmsg_size, zone->off); +#endif /* MY_DEF_HERE */ continue; } @@ -423,6 +434,17 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt) continue; } +#if defined(MY_DEF_HERE) + if (i == 0) + temp_counter = hdr->counter; + else { + if (hdr->counter <= temp_counter) { + temp_counter = hdr->counter; + erase_off = zone->off; + } + } + +#endif /* MY_DEF_HERE */ /* * we get the newest zone, and the next one must be the oldest * or unused zone, because we do write one by one like a circle. @@ -452,6 +474,15 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt) pr_debug("found nice zone: %s: id %lu, off %lld, size %zu, datalen %d\n", zone->name, i, zone->off, zone->buffer_size, atomic_read(&buf->datalen)); +#if defined(MY_DEF_HERE) + used_zone++; + } + + if (used_zone == cxt->kmsg_max_cnt) { + pr_debug("No more zone to use.!!!!!! release zone off:[%llx]\n", + erase_off); + info->erase(info->kmsg_size, erase_off); +#endif /* MY_DEF_HERE */ } return 0; @@ -738,6 +769,22 @@ static void psz_write_kmsg_hdr(struct pstore_zone *zone, hdr->counter = 0; } +#if defined(MY_DEF_HERE) +static void psz_revert_kmsg_hdr_count(struct pstore_zone *zone, + struct pstore_record *record) +{ + struct psz_context *cxt = record->psi->data; + struct psz_buffer *buffer = zone->buffer; + struct psz_kmsg_header *hdr = + (struct psz_kmsg_header *)buffer->data; + + hdr->reason = record->reason; + if (hdr->reason == KMSG_DUMP_OOPS) + cxt->oops_counter--; + else if (hdr->reason == KMSG_DUMP_PANIC) + cxt->panic_counter--; +} +#endif /* MY_DEF_HERE */ /* * In case zone is broken, which may occur to MTD device, we try each zones, * start at cxt->kmsg_write_cnt. @@ -766,7 +813,11 @@ static inline int notrace psz_kmsg_write_record(struct psz_context *cxt, zone->buffer = zone->oldbuf; return -ENOMEM; } +#if defined(MY_DEF_HERE) + zone->buffer->sig = PSZ_SIG; +#else /* MY_DEF_HERE */ zone->buffer->sig = zone->oldbuf->sig; +#endif /* MY_DEF_HERE */ pr_debug("write %s to zone id %d\n", zone->name, zonenum); psz_write_kmsg_hdr(zone, record); @@ -782,6 +833,9 @@ static inline int notrace psz_kmsg_write_record(struct psz_context *cxt, return ret; } +#if defined(MY_DEF_HERE) + psz_revert_kmsg_hdr_count(zone, record); +#endif /* MY_DEF_HERE */ pr_debug("zone %u may be broken, try next dmesg zone\n", zonenum); kfree(zone->buffer); @@ -970,6 +1024,15 @@ static ssize_t psz_kmsg_read(struct pstore_zone *zone, size -= sizeof(struct psz_kmsg_header); if (!record->compressed) { +#ifdef MY_DEF_HERE + /* in syno_pstore_collector, it expects first line of pstroe context + * with format "%s Part%d, btime %ld" + * Therefore, we skip to "%s: Total %d times\n" in pstore. + */ + record->buf = kmalloc(size, GFP_KERNEL); + if (!record->buf) + return -ENOMEM; +#else /* MY_DEF_HERE */ char *buf = kasprintf(GFP_KERNEL, "%s: Total %d times\n", kmsg_dump_reason_str(record->reason), record->count); @@ -979,6 +1042,7 @@ static ssize_t psz_kmsg_read(struct pstore_zone *zone, kfree(buf); return -ENOMEM; } +#endif /* MY_DEF_HERE */ } else { record->buf = kmalloc(size, GFP_KERNEL); if (!record->buf) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 4f1373463766..cf29bd4ed56f 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Implementation of the diskquota system for the LINUX operating system. QUOTA @@ -1259,6 +1262,9 @@ static int ignore_hardlimit(struct dquot *dquot) struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type]; return capable(CAP_SYS_RESOURCE) && +#ifdef MY_ABC_HERE + !(dquot->dq_sb->s_flags & SB_ROOTPRJQUOTA) && +#endif /* MY_ABC_HERE */ (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & DQF_ROOT_SQUASH)); } diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c index c5562c871c8b..1a188fbdf34e 100644 --- a/fs/quota/quota_tree.c +++ b/fs/quota/quota_tree.c @@ -423,6 +423,7 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, quota_error(dquot->dq_sb, "Quota structure has offset to " "other block (%u) than it should (%u)", blk, (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); + ret = -EIO; goto out_buf; } ret = read_blk(info, blk, buf); @@ -488,6 +489,13 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, goto out_buf; } newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); + if (newblk < QT_TREEOFF || newblk >= info->dqi_blocks) { + quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)", + newblk, info->dqi_blocks); + ret = -EUCLEAN; + goto out_buf; + } + if (depth == info->dqi_qtree_depth - 1) { ret = free_dqentry(info, dquot, newblk); newblk = 0; @@ -587,6 +595,13 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); if (!blk) /* No reference? */ goto out_buf; + if (blk < QT_TREEOFF || blk >= info->dqi_blocks) { + quota_error(dquot->dq_sb, "Getting block too big (%u >= %u)", + blk, info->dqi_blocks); + ret = -EUCLEAN; + goto out_buf; + } + if (depth < info->dqi_qtree_depth - 1) ret = find_tree_dqentry(info, dquot, blk, depth+1); else diff --git a/fs/read_write.c b/fs/read_write.c index 75f764b43418..0b5bcb4fda4b 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/read_write.c @@ -24,6 +27,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#include +#endif /* MY_ABC_HERE */ const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, @@ -503,6 +510,9 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) inc_syscr(current); return ret; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(vfs_read); +#endif /* MY_ABC_HERE */ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { @@ -613,6 +623,9 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ file_end_write(file); return ret; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(vfs_write); +#endif /* MY_ABC_HERE */ /* file_ppos returns &file->f_pos or NULL if file is stream */ static inline loff_t *file_ppos(struct file *file) @@ -1358,6 +1371,197 @@ COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, } #endif +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +static ssize_t generic_write_init_and_checks(struct file* filp, loff_t pos, size_t count) +{ + struct iovec iov = { .iov_base = NULL, .iov_len = count}; + struct kiocb kiocb; + struct iov_iter iter; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = pos; + iov_iter_init(&iter, WRITE, &iov, 1, count); + + return generic_write_checks(&kiocb, &iter); +} + +static ssize_t default_recvfile(struct file *file, struct socket *sock, + loff_t pos, size_t count, size_t *received, size_t *written) +{ + ssize_t ret; + + ret = file_update_time(file); + if (ret) + return ret; + + do { + size_t bytes_received = 0; + size_t bytes_written = 0; + + ret = do_recvfile(file, sock, pos, (count > (MAX_RECVFILE_BUF - (pos & (PAGE_SIZE - 1)))) ? + (MAX_RECVFILE_BUF - (pos & (PAGE_SIZE - 1))) : count, &bytes_received, &bytes_written); + *received += bytes_received; + *written += bytes_written; + if (ret <= 0) + break; + count -= bytes_written; + pos += bytes_written; + } while (count > 0); + return ret < 0 ? ret : *written; +} + +ssize_t vfs_recvfile(int fd, struct file *file, struct socket *sock, + loff_t pos, size_t count, size_t *received, size_t *written) +{ + ssize_t ret; + struct inode *inode = file_inode(file); + + if (!(file->f_mode & FMODE_WRITE)) + return -EBADF; + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + ret = rw_verify_area(WRITE, file, &pos, count); + if (ret) + return ret; + + file_start_write(file); + inode_lock(inode); + /* + * We can write back this queue in page reclaim + */ + current->backing_dev_info = inode_to_bdi(inode); + ret = generic_write_init_and_checks(file, pos, count); + if (ret <= 0) + goto out; + ret = file_remove_privs(file); + if (ret) + goto out; + + if (file->f_op->syno_recvfile) + ret = file->f_op->syno_recvfile(fd, file, sock, pos, count, received, written); + else + ret = default_recvfile(file, sock, pos, count, received, written); + + if (ret > 0) + fsnotify_modify(file); +out: + current->backing_dev_info = NULL; + inode_unlock(inode); + file_end_write(file); + return ret; +} +EXPORT_SYMBOL(vfs_recvfile); + +static int do_syno_recv_file(int fd, int s, loff_t * offset, size_t count, size_t * rwbytes) +{ + ssize_t ret; + int err; + loff_t pos; + size_t received = 0; + size_t written = 0; + struct file *file; + struct socket *sock; + + if (!offset) + return -EINVAL; + if (!count) + return 0; + if (copy_from_user(&pos, offset, sizeof(loff_t))) + return -EFAULT; + file = fget(fd); + if (!file) + return -EBADF; + + sock = sockfd_lookup(s, &err); + if (!sock) { + fput(file); + return err; + } + if (!sock->sk) { + /* not a socket */ + ret = -EINVAL; + goto out; + } + + ret = vfs_recvfile(fd, file, sock, pos, count, &received, &written); + if (ret < 0 && rwbytes) { + if (copy_to_user(&rwbytes[0], &received, sizeof(size_t))) { + ret = -EFAULT; + goto out; + } + if (copy_to_user(&rwbytes[1], &written, sizeof(size_t))) { + ret = -EFAULT; + goto out; + } + } + pos += written; + if (unlikely(put_user(pos, offset))) { + ret = -EFAULT; + goto out; + } + +out: + fput(file); + sockfd_put(sock); + return ret; +} + +SYSCALL_DEFINE5(syno_recv_file, int, fd, int, s, loff_t *, offset, size_t, count, size_t *, rwbytes) +{ + return do_syno_recv_file(fd, s, offset, count, rwbytes); +} + +SYSCALL_DEFINE1(syno_flush_aggregate, int, fd) +{ + return -EOPNOTSUPP; +} +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE5(syno_recv_file, int, fd, int, s, loff_t *, offset, compat_size_t, nbytes, compat_size_t __user *, rwbytes32) +{ + int err = 0; + ssize_t ret; + size_t rwbytes64[2]; + if (unlikely(get_user(rwbytes64[0], &rwbytes32[0]))) + return -EFAULT; + if (unlikely(get_user(rwbytes64[1], &rwbytes32[1]))) + return -EFAULT; + + ret = do_syno_recv_file(fd, s, offset, nbytes, rwbytes64); + + /* truncating is ok because it's a user address */ + err = put_user((u32) rwbytes64[0], &rwbytes32[0]); + if (err) + ret = err; + err = put_user((u32) rwbytes64[1], &rwbytes32[1]); + if (err) + ret = err; + + return ret; +} +#endif /* CONFIG_COMPAT */ + +#else /* MY_ABC_HERE */ + +SYSCALL_DEFINE5(syno_recv_file, int, fd, int, s, loff_t *, offset, size_t, count, size_t *, rwbytes) +{ + return -EOPNOTSUPP; +} + +SYSCALL_DEFINE1(syno_flush_aggregate, int, fd) +{ + return -EOPNOTSUPP; +} +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE5(syno_recv_file, int, fd, int, s, loff_t *, offset, compat_size_t, nbytes, compat_size_t __user *, rwbytes32) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_COMPAT */ + +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + /** * generic_copy_file_range - copy data between two files * @file_in: file structure to read from @@ -1649,6 +1853,20 @@ ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) if (iocb->ki_flags & IOCB_APPEND) iocb->ki_pos = i_size_read(inode); +#ifdef MY_ABC_HERE + /* + * for locker appendable, data is appended to the file in chunk. when data + * is written to bytes n*CHUNK_SIZE+1 of the file, the previous chunk + * becomes locked. + */ + if (syno_op_locker_is_appendable(inode) && + iocb->ki_pos < round_down(i_size_read(inode), LOCKER_CHUNK_SIZE)) { + pr_warn_ratelimited("locker: append data to %pD at offset 0x%llx before 0x%llx\n", + file, iocb->ki_pos, round_down(i_size_read(inode), LOCKER_CHUNK_SIZE)); + return -EPERM; + } +#endif /* MY_ABC_HERE */ + if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) return -EINVAL; diff --git a/fs/remap_range.c b/fs/remap_range.c index e6099beefa97..ef6232133ffd 100644 --- a/fs/remap_range.c +++ b/fs/remap_range.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only #include #include @@ -19,6 +22,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif + /* * Performs necessary checks before doing a clone. * @@ -438,6 +445,13 @@ static bool allow_file_dedupe(struct file *file) return true; if (uid_eq(current_fsuid(), file_inode(file)->i_uid)) return true; + +#ifdef MY_ABC_HERE + if (IS_SYNOACL(file_dentry(file))) { + if (!synoacl_op_permission(file_dentry(file), MAY_WRITE)) + return true; + } else +#endif /* MY_ABC_HERE */ if (!inode_permission(file_inode(file), MAY_WRITE)) return true; return false; @@ -450,7 +464,11 @@ loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, loff_t ret; WARN_ON_ONCE(remap_flags & ~(REMAP_FILE_DEDUP | - REMAP_FILE_CAN_SHORTEN)); + REMAP_FILE_CAN_SHORTEN +#ifdef MY_ABC_HERE + | REMAP_FILE_SKIP_CHECK_COMPR_DIR +#endif /* MY_ABC_HERE */ + )); ret = mnt_want_write_file(dst_file); if (ret) diff --git a/fs/signalfd.c b/fs/signalfd.c index 456046e15873..b94fb5f81797 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -35,17 +35,7 @@ void signalfd_cleanup(struct sighand_struct *sighand) { - wait_queue_head_t *wqh = &sighand->signalfd_wqh; - /* - * The lockless check can race with remove_wait_queue() in progress, - * but in this case its caller should run under rcu_read_lock() and - * sighand_cachep is SLAB_TYPESAFE_BY_RCU, we can safely return. - */ - if (likely(!waitqueue_active(wqh))) - return; - - /* wait_queue_entry_t->func(POLLFREE) should do remove_wait_queue() */ - wake_up_poll(wqh, EPOLLHUP | POLLFREE); + wake_up_pollfree(&sighand->signalfd_wqh); } struct signalfd_ctx { diff --git a/fs/splice.c b/fs/splice.c index 866d5c2367b2..70b9d2f3f318 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * "splice": joining two ropes together by interweaving their strands. @@ -30,6 +33,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include #include @@ -756,20 +762,34 @@ static int warn_unsupported(struct file *file, const char *op) /* * Attempt to initiate a splice from pipe to file. */ +#ifdef MY_ABC_HERE +long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +#else static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) +#endif /* MY_ABC_HERE */ { if (unlikely(!out->f_op->splice_write)) return warn_unsupported(out, "write"); return out->f_op->splice_write(pipe, out, ppos, len, flags); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(do_splice_from); +#endif /* MY_ABC_HERE */ /* * Attempt to initiate a splice from a file to a pipe. */ +#ifdef MY_ABC_HERE +long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +#else static long do_splice_to(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) +#endif /* MY_ABC_HERE */ { int ret; @@ -787,6 +807,9 @@ static long do_splice_to(struct file *in, loff_t *ppos, return warn_unsupported(in, "read"); return in->f_op->splice_read(in, ppos, pipe, len, flags); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(do_splice_to); +#endif /* MY_ABC_HERE */ /** * splice_direct_to_actor - splices data directly between two non-pipes @@ -1059,6 +1082,11 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, ret = do_splice_from(ipipe, out, &offset, len, flags); file_end_write(out); +#ifdef MY_ABC_HERE + if (ret > 0) + fsnotify_modify(out); +#endif /* MY_ABC_HERE */ + if (!off_out) out->f_pos = offset; else @@ -1095,6 +1123,11 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out, pipe_unlock(opipe); if (ret > 0) wakeup_pipe_readers(opipe); +#ifdef MY_ABC_HERE + if (ret > 0) + fsnotify_access(in); +#endif /* MY_ABC_HERE */ + if (!off_in) in->f_pos = offset; else diff --git a/fs/stack.c b/fs/stack.c index c9830924eb12..ba00ee9b7497 100644 --- a/fs/stack.c +++ b/fs/stack.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only #include #include @@ -71,6 +74,10 @@ void fsstack_copy_attr_all(struct inode *dest, const struct inode *src) dest->i_ctime = src->i_ctime; dest->i_blkbits = src->i_blkbits; dest->i_flags = src->i_flags; +#ifdef MY_ABC_HERE + //For ecryptfs archive bit + dest->i_archive_bit = src->i_archive_bit; +#endif /* MY_ABC_HERE */ set_nlink(dest, src->i_nlink); } EXPORT_SYMBOL_GPL(fsstack_copy_attr_all); diff --git a/fs/stat.c b/fs/stat.c index 1196af4d1ea0..fd575105d043 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/stat.c @@ -24,6 +27,10 @@ #include "internal.h" #include "mount.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + /** * generic_fillattr - Fill in the basic attributes from the inode struct * @inode: Inode to use as the source @@ -90,6 +97,18 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat, stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT | STATX_ATTR_DAX); +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path->dentry)) { + int retval = 0; + if (inode->i_op->getattr) + retval = inode->i_op->getattr(path, stat, request_mask, query_flags); + else + generic_fillattr(inode, stat); + + synoacl_op_to_mode(path->dentry, stat); + return retval; + } +#endif /* MY_ABC_HERE */ if (inode->i_op->getattr) return inode->i_op->getattr(path, stat, request_mask, @@ -216,6 +235,86 @@ int vfs_fstatat(int dfd, const char __user *filename, stat, STATX_BASIC_STATS); } +#ifdef MY_ABC_HERE +int __always_inline syno_vfs_getattr(struct path *path, struct kstat *stat, + u32 request_mask, unsigned int query_flags, unsigned int syno_flags) +{ + int error = 0; + + error = vfs_getattr(path, stat, request_mask, query_flags); + if (error) + goto out; + + error = syno_op_getattr(path->dentry, stat, syno_flags); +out: + return error; +} + +// copy from vfs_fstat +int syno_vfs_fstat(unsigned int fd, struct kstat *stat, unsigned int syno_flags) +{ + struct fd f; + int error; + + f = fdget_raw(fd); + if (!f.file) + return -EBADF; + error = syno_vfs_getattr(&f.file->f_path, stat, + STATX_BASIC_STATS, 0, syno_flags); + fdput(f); + return error; +} +EXPORT_SYMBOL(syno_vfs_fstat); + +// copy from vfs_statx +int syno_vfs_statx(const char __user *filename, struct kstat *stat, + unsigned int query_flags, unsigned int syno_flags) +{ + struct path path; + unsigned lookup_flags = 0; + int error; + + if (query_flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | + AT_EMPTY_PATH | AT_STATX_SYNC_TYPE)) + return -EINVAL; + + if (!(query_flags & AT_SYMLINK_NOFOLLOW)) + lookup_flags |= LOOKUP_FOLLOW; + if (!(query_flags & AT_NO_AUTOMOUNT)) + lookup_flags |= LOOKUP_AUTOMOUNT; + if (query_flags & AT_EMPTY_PATH) + lookup_flags |= LOOKUP_EMPTY; + +retry: + error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); + if (error) + goto out; + + error = syno_vfs_getattr(&path, stat, STATX_BASIC_STATS, query_flags, syno_flags); + stat->mnt_id = real_mount(path.mnt)->mnt_id; + stat->result_mask |= STATX_MNT_ID; + if (path.mnt->mnt_root == path.dentry) + stat->attributes |= STATX_ATTR_MOUNT_ROOT; + stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT; + path_put(&path); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } +out: + return error; +} + +// copy from vfs_fstatat +int syno_vfs_fstatat(const char __user *filename, struct kstat *stat, + unsigned int query_flags, unsigned int syno_flags) +{ + return syno_vfs_statx(filename, stat, query_flags | AT_NO_AUTOMOUNT, + syno_flags); +} +EXPORT_SYMBOL(syno_vfs_fstatat); +#endif /* MY_ABC_HERE */ + #ifdef __ARCH_WANT_OLD_STAT /* @@ -696,6 +795,219 @@ COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd, } #endif +#ifdef MY_ABC_HERE +/* This stat is used by caseless protocol. + * The filename will be convert to real filename and return to user space. + * In caller, the length of filename must equal or be larger than SYNO_SMB_PSTRING_LEN. +*/ +int __syno_caseless_stat(char __user * filename, bool no_follow, + struct kstat *stat, unsigned int syno_flags) +{ + struct path path; + int error; + int f; + char *real_filename = NULL; + int real_filename_len = 0; + + real_filename = kmalloc(SYNO_SMB_PSTRING_LEN, GFP_KERNEL); + if (!real_filename) + return -ENOMEM; + + if (no_follow) + f = LOOKUP_CASELESS_COMPARE; + else + f = LOOKUP_FOLLOW|LOOKUP_CASELESS_COMPARE; + + error = syno_user_path_at(AT_FDCWD, filename, f, &path, + &real_filename, &real_filename_len); + if (!error) { +#ifdef MY_ABC_HERE + error = syno_vfs_getattr(&path, stat, STATX_BASIC_STATS, 0, syno_flags); +#else + error = vfs_getattr(&path, stat, STATX_BASIC_STATS, 0); +#endif /* MY_ABC_HERE */ + path_put(&path); + if (real_filename_len) { + error = copy_to_user(filename, + real_filename, real_filename_len) ? -EFAULT : error; + } + } + + kfree(real_filename); + return error; +} +EXPORT_SYMBOL(__syno_caseless_stat); + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +SYSCALL_DEFINE2(syno_caseless_stat, char __user *, filename, struct stat __user *, statbuf) +{ +#ifdef MY_ABC_HERE + long error = -1; + struct kstat stat; + + memset(&stat, 0, sizeof(stat)); + error = __syno_caseless_stat(filename, false, &stat, 0); + if (!error) + error = cp_new_stat(&stat, statbuf); + + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE2(syno_caseless_lstat, char __user *, filename, struct stat __user *, statbuf) +{ +#ifdef MY_ABC_HERE + long error = -1; + struct kstat stat; + + memset(&stat, 0, sizeof(stat)); + error = __syno_caseless_stat(filename, true, &stat, 0); + if (!error) + error = cp_new_stat(&stat, statbuf); + + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int cp_to_synostat(struct kstat *kst, unsigned int syno_flags, + struct SYNOSTAT __user *synostat) +{ + int error = -EFAULT; + + if (!synostat) { + error = -EINVAL; + goto out; + } + + if (syno_flags & SYNOST_STAT) { + error = cp_new_stat(kst, &synostat->st); + if(error) + goto out; + } + + error = __put_user(kst->syno_flags, &synostat->ext.flags); + if (error) + goto out; + + if (syno_flags & SYNOST_COMPRESSION) { + if (copy_to_user(&synostat->ext.compressed, + &kst->syno_compressed, + sizeof(synostat->ext.compressed))) { + error = -EFAULT; + goto out; + } + } + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_BIT) { + error = __put_user(kst->syno_archive_bit, + &synostat->ext.archive_bit); + if (error) + goto out; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_VER) { + error = __put_user(kst->syno_archive_version, + &synostat->ext.archive_version); + if (error) + goto out; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_CREATE_TIME) { + struct __kernel_old_timespec tmp; + + tmp.tv_sec = kst->syno_create_time.tv_sec; + tmp.tv_nsec = kst->syno_create_time.tv_nsec; + if (copy_to_user(&synostat->ext.create_time, &tmp, sizeof(tmp))) { + error = -EFAULT; + goto out; + } + } +#endif /* MY_ABC_HERE */ + + error = 0; +out: + return error; +} + +static int do_syno_stat(char __user *filename, bool no_follow, + unsigned int syno_flags, struct SYNOSTAT __user *synostat) +{ + long error = -EINVAL; + struct kstat kst; + + memset(&kst, 0, sizeof(kst)); + if (syno_flags & SYNOST_IS_CASELESS) { +#ifdef MY_ABC_HERE + error = __syno_caseless_stat(filename, no_follow, &kst, syno_flags); +#else + error = -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ + } else { + if (no_follow) + error = syno_vfs_fstatat(filename, &kst, AT_SYMLINK_NOFOLLOW, syno_flags); + else + error = syno_vfs_fstatat(filename, &kst, 0, syno_flags); + } + + if (error) + goto out; + + error = cp_to_synostat(&kst, syno_flags, synostat); +out: + return error; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +SYSCALL_DEFINE3(syno_stat, char __user *, filename, unsigned int, syno_flags, struct SYNOSTAT __user *, synostat) +{ +#ifdef MY_ABC_HERE + return do_syno_stat(filename, false, syno_flags, synostat); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(syno_fstat, unsigned int, fd, unsigned int, syno_flags, struct SYNOSTAT __user *, synostat) +{ +#ifdef MY_ABC_HERE + int error; + struct kstat kst; + + memset(&kst, 0, sizeof(kst)); + error = syno_vfs_fstat(fd, &kst, syno_flags); + if (error) + return error; + + return cp_to_synostat(&kst, syno_flags, synostat); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(syno_lstat, char __user *, filename, unsigned int, syno_flags, struct SYNOSTAT __user *, synostat) +{ +#ifdef MY_ABC_HERE + return do_syno_stat(filename, true, syno_flags, synostat); +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ + /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ void __inode_add_bytes(struct inode *inode, loff_t bytes) { @@ -761,3 +1073,24 @@ void inode_set_bytes(struct inode *inode, loff_t bytes) } EXPORT_SYMBOL(inode_set_bytes); + +#ifdef MY_ABC_HERE +int vfs_quota_query(struct file *file, u64 *used, u64 *reserved, u64 *limit) +{ + if (!file->f_op->quota_query) + return -EOPNOTSUPP; + return file->f_op->quota_query(file, used, reserved, limit); +} +EXPORT_SYMBOL(vfs_quota_query); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int vfs_syno_space_usage(struct file *file, struct syno_space_usage_info *info) +{ + if (!file->f_op->syno_space_usage) + return -EOPNOTSUPP; + return file->f_op->syno_space_usage(file, info); +} +EXPORT_SYMBOL(vfs_syno_space_usage); +#endif /* MY_ABC_HERE */ + diff --git a/fs/super.c b/fs/super.c index 98bb0629ee10..0684bcd2a541 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/fs/super.c @@ -180,6 +183,11 @@ static void destroy_unused_super(struct super_block *s) up_write(&s->s_umount); list_lru_destroy(&s->s_dentry_lru); list_lru_destroy(&s->s_inode_lru); +#ifdef MY_ABC_HERE +#ifdef CONFIG_SMP + free_percpu(s->s_files); +#endif /* CONFIG_SMP */ +#endif /* MY_ABC_HERE */ security_sb_free(s); put_user_ns(s->s_user_ns); kfree(s->s_subtype); @@ -231,6 +239,19 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, if (security_sb_alloc(s)) goto fail; +#ifdef MY_ABC_HERE + ratelimit_state_init(&s->rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); +#ifdef CONFIG_SMP + s->s_files = alloc_percpu(struct list_head); + if (!s->s_files) + goto fail; + for_each_possible_cpu(i) + INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); +#else /* CONFIG_SMP */ + INIT_LIST_HEAD(&s->s_files); +#endif /* CONFIG_SMP */ +#endif /* MY_ABC_HERE */ + for (i = 0; i < SB_FREEZE_LEVELS; i++) { if (__percpu_init_rwsem(&s->s_writers.rw_sem[i], sb_writers_name[i], @@ -262,6 +283,11 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, s->s_time_max = TIME64_MAX; s->cleancache_poolid = CLEANCACHE_NO_POOL; +#ifdef MY_ABC_HERE + init_rwsem(&s->s_archive_version_rwsem); + s->s_archive_version = 0; +#endif /* MY_ABC_HERE */ + s->s_shrink.seeks = DEFAULT_SEEKS; s->s_shrink.scan_objects = super_cache_scan; s->s_shrink.count_objects = super_cache_count; @@ -953,6 +979,10 @@ int reconfigure_super(struct fs_context *fc) } } +#ifdef MY_ABC_HERE + if (fc->relatime_period > 0) + sb->relatime_period = fc->relatime_period; +#endif /* MY_ABC_HERE */ if (fc->ops->reconfigure) { retval = fc->ops->reconfigure(fc); if (retval) { @@ -1415,6 +1445,10 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, } else { s->s_mode = mode; snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev); +#ifdef MY_ABC_HERE + if (NULL != strstr(s->s_id, "synoboot")) + printk(KERN_NOTICE "%s: %s mounted, process=%s\n", fs_type->name, s->s_id, current->comm); +#endif /* MY_ABC_HERE */ sb_set_blocksize(s, block_size(bdev)); error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); if (error) { @@ -1570,6 +1604,10 @@ int vfs_get_tree(struct fs_context *fc) */ smp_wmb(); sb->s_flags |= SB_BORN; +#ifdef MY_ABC_HERE + if (fc->relatime_period > 0) + sb->relatime_period = fc->relatime_period; +#endif /* MY_ABC_HERE */ error = security_sb_set_mnt_opts(sb, fc->security, 0, NULL); if (unlikely(error)) { diff --git a/fs/sync.c b/fs/sync.c index 1373a610dc78..cc205e97c57a 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * High-level sync()-related operations @@ -28,7 +31,11 @@ * wait == 1 case since in that case write_inode() functions do * sync_dirty_buffer() and thus effectively write one block at a time. */ +#ifdef MY_ABC_HERE +int __sync_filesystem(struct super_block *sb, int wait) +#else static int __sync_filesystem(struct super_block *sb, int wait) +#endif /* MY_ABC_HERE */ { if (wait) sync_inodes_sb(sb); @@ -39,6 +46,9 @@ static int __sync_filesystem(struct super_block *sb, int wait) sb->s_op->sync_fs(sb, wait); return __sync_blockdev(sb->s_bdev, wait); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(__sync_filesystem); +#endif /* MY_ABC_HERE */ /* * Write out and wait upon all dirty data associated with this diff --git a/fs/syno_acl.c b/fs/syno_acl.c new file mode 100644 index 000000000000..208b473336e3 --- /dev/null +++ b/fs/syno_acl.c @@ -0,0 +1,626 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ + +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#include "syno_acl.h" + +struct syno_acl *syno_acl_alloc(int count, gfp_t flags) +{ + size_t size = sizeof(struct syno_acl) + count * sizeof(struct syno_acl_entry); + struct syno_acl *acl = kmalloc(size, flags); + + if (acl) { + refcount_set(&acl->a_refcount, 1); + acl->a_count = count; + } + + return acl; +} +EXPORT_SYMBOL(syno_acl_alloc); + +struct syno_acl *syno_acl_clone(const struct syno_acl *acl, gfp_t flags) +{ + struct syno_acl *clone = NULL; + + if (acl) { + size_t size = sizeof(struct syno_acl) + + acl->a_count * sizeof(struct syno_acl_entry); + clone = kmemdup(acl, size, flags); + if (clone) + refcount_set(&clone->a_refcount, 1); + } + return clone; +} +EXPORT_SYMBOL(syno_acl_clone); + +/* + * Check if an ACL is valid. Returns 0 if it is, or -ERRNO for otherwise. + */ +int syno_acl_valid(const struct syno_acl *acl) +{ + const struct syno_acl_entry *pa, *pe; + + if (!acl) + return -EINVAL; + + FOREACH_SYNOACL_ENTRY(pa, acl, pe) { + if (pa->e_perm & ~(SYNO_PERM_FULL_CONTROL)) + return -EINVAL; + if (pa->e_tag & ~(SYNO_ACL_TAG_ALL)) + return -EINVAL; + if (SYNO_ACL_ALLOW != pa->e_allow && SYNO_ACL_DENY != pa->e_allow) + return -EINVAL; + if (pa->e_inherit & ~(SYNO_ACL_INHERIT_ALL)) + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(syno_acl_valid); + +/* + * Re-allocate a new ACL with the specified number of entries. + * + * The caller must ensure the acl is only referenced once. + */ +struct syno_acl *syno_acl_realloc(struct syno_acl *acl, unsigned int counts, + gfp_t flags) +{ + struct syno_acl *acl_re; + size_t size = sizeof(struct syno_acl) + counts * sizeof(struct syno_acl_entry); + + if (!acl) + return NULL; + + if (refcount_read(&acl->a_refcount) != 1) { + printk(KERN_ERR " acl reference count: %d \n ", refcount_read(&acl->a_refcount)); + return NULL; + } + + /* assert(refcount_read(acl->a_refcount) == 1); */ + + acl_re = krealloc(acl, size, flags); + if (acl_re) + acl_re->a_count = counts; + + return acl_re; +} +EXPORT_SYMBOL(syno_acl_realloc); + +static inline int ace_syno_from_xattr(struct syno_acl_entry *pAce, + syno_acl_xattr_entry *pEntry) +{ + unsigned short tag = le16_to_cpu(pEntry->e_tag); + + // ID: user/group/everyone + if (SYNO_ACL_XATTR_TAG_ID_GROUP & tag) { + pAce->e_tag = SYNO_ACL_GROUP; + pAce->e_id = le32_to_cpu(pEntry->e_id); + } else if (SYNO_ACL_XATTR_TAG_ID_EVERYONE & tag) { + pAce->e_tag = SYNO_ACL_EVERYONE; + pAce->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_USER & tag) { + pAce->e_tag = SYNO_ACL_USER; + pAce->e_id = le32_to_cpu(pEntry->e_id); + } else if (SYNO_ACL_XATTR_TAG_ID_OWNER & tag) { + pAce->e_tag = SYNO_ACL_OWNER; + pAce->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER & tag) { + pAce->e_tag = SYNO_ACL_AUTHENTICATEDUSER; + pAce->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_SYSTEM & tag) { + pAce->e_tag = SYNO_ACL_SYSTEM; + pAce->e_id = SYNO_ACL_UNDEFINED_ID; + } else { + return -1; + } + + // Allow/Deny + if (SYNO_ACL_XATTR_TAG_IS_DENY & tag) + pAce->e_allow = SYNO_ACL_DENY; + else if (SYNO_ACL_XATTR_TAG_IS_ALLOW & tag) + pAce->e_allow = SYNO_ACL_ALLOW; + else + return -1; + + pAce->e_perm = le32_to_cpu(pEntry->e_perm); + pAce->e_inherit = le16_to_cpu(pEntry->e_inherit); + pAce->e_level = le32_to_cpu(pEntry->e_level); + + return 0; +} + +static inline int ace_syno_to_xattr(const struct syno_acl_entry *pAce, + syno_acl_xattr_entry *pEntry) +{ + int ret = 0; + unsigned short tag = 0; + + // ID: user/group/everyone + switch (pAce->e_tag) { + case SYNO_ACL_GROUP: + tag |= SYNO_ACL_XATTR_TAG_ID_GROUP; + break; + case SYNO_ACL_EVERYONE: + tag |= SYNO_ACL_XATTR_TAG_ID_EVERYONE; + break; + case SYNO_ACL_USER: + tag |= SYNO_ACL_XATTR_TAG_ID_USER; + break; + case SYNO_ACL_OWNER: + tag |= SYNO_ACL_XATTR_TAG_ID_OWNER; + break; + case SYNO_ACL_AUTHENTICATEDUSER: + tag |= SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER; + break; + case SYNO_ACL_SYSTEM: + tag |= SYNO_ACL_XATTR_TAG_ID_SYSTEM; + break; + default: + ret = -EINVAL; + goto Err; + } + + // Allow/Deny + switch (pAce->e_allow) { + case SYNO_ACL_DENY: + tag |= SYNO_ACL_XATTR_TAG_IS_DENY; + break; + case SYNO_ACL_ALLOW: + tag |= SYNO_ACL_XATTR_TAG_IS_ALLOW; + break; + default: + ret = -EINVAL; + goto Err; + } + + pEntry->e_tag = cpu_to_le16(tag); + pEntry->e_inherit = cpu_to_le16(pAce->e_inherit); + pEntry->e_perm = cpu_to_le32(pAce->e_perm); + pEntry->e_id = cpu_to_le32(pAce->e_id); + pEntry->e_level = cpu_to_le32(pAce->e_level); + +Err: + return ret; +} + +/* + * Convert from extended attribute to in-memory representation. + */ +struct syno_acl *syno_acl_from_xattr(const void *value, size_t size) +{ + syno_acl_xattr_header *header; + syno_acl_xattr_entry *entry, *end; + int count; + struct syno_acl *acl; + struct syno_acl_entry *acl_e; + + if (!value) + return NULL; + + if (size < sizeof(syno_acl_xattr_header)) + return ERR_PTR(-EINVAL); + + header = (syno_acl_xattr_header *)value; + entry = (syno_acl_xattr_entry *)(header + 1); + + if (header->a_version != cpu_to_le16(SYNO_ACL_XATTR_VERSION)) + return ERR_PTR(-EOPNOTSUPP); + + count = syno_acl_xattr_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + acl = syno_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + + acl_e = acl->a_entries; + end = entry + count; + for (; entry != end; acl_e++, entry++) { + if (0 > ace_syno_from_xattr(acl_e, entry)) + goto fail; + } + return acl; + +fail: + syno_acl_release(acl); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL(syno_acl_from_xattr); + +/* + * Convert from in-memory to extended attribute representation. + */ +int syno_acl_to_xattr(const struct syno_acl *acl, void *buffer, size_t size) +{ + syno_acl_xattr_header *ext_acl = NULL; + syno_acl_xattr_entry *ext_entry = NULL; + int real_size, i, ret; + + if (!acl) + return 0; + + real_size = syno_acl_xattr_size(acl->a_count); + if (!buffer) + return real_size; + if (real_size > size) + return -ERANGE; + + ext_acl = (syno_acl_xattr_header *)buffer; + ext_entry = ext_acl->a_entries; + ext_acl->a_version = cpu_to_le16(SYNO_ACL_XATTR_VERSION); + + for (i = 0; i < acl->a_count; i++, ext_entry++) { + ret = ace_syno_to_xattr(&(acl->a_entries[i]), ext_entry); + if (0 > ret) + return ret; + } + return real_size; +} +EXPORT_SYMBOL(syno_acl_to_xattr); + +/* + * Inode operations of SynoACL + */ +int synoacl_op_permission(struct dentry *dentry, int perm) +{ + int ret; + struct inode *inode = d_inode(dentry); + + if (perm & MAY_NOT_BLOCK) + return -ECHILD; + + if (inode->i_op->syno_permission) + ret = inode->i_op->syno_permission(dentry, perm); + else + ret = synoacl_mod_permission(dentry, perm); + + trace_synoacl_permission(dentry, perm, ret); + + return ret; +} +EXPORT_SYMBOL(synoacl_op_permission); + +int synoacl_op_exec_permission(struct dentry *dentry, struct inode *inode) +{ + int ret; + + if (inode->i_op->syno_exec_permission) + ret = inode->i_op->syno_exec_permission(dentry); + else + ret = synoacl_mod_exec_permission(dentry); + + trace_synoacl_exec_permission(dentry, ret); + + return ret; +} +EXPORT_SYMBOL(synoacl_op_exec_permission); + +int synoacl_op_archive_bit_change_ok(struct dentry *dentry, + unsigned int cmd, int tag, int mask) +{ + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_archive_bit_change_ok) + return inode->i_op->syno_archive_bit_change_ok(dentry, cmd, tag, mask); + + return synoacl_mod_archive_bit_change_ok(dentry, cmd, tag, mask); +} +EXPORT_SYMBOL(synoacl_op_archive_bit_change_ok); + +/** + * synoacl_op_setattr_prepare - check if attribute changes to a dentry are allowed + * @dentry: dentry to check + * @attr: attributes to change + * + * this is corresponding to setattr_prepare(), which was named as inode_change_ok() + * before v4.9 + */ +int synoacl_op_setattr_prepare(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_setattr_prepare) + return inode->i_op->syno_setattr_prepare(dentry, attr); + + return synoacl_mod_setattr_prepare(dentry, attr); +} +EXPORT_SYMBOL(synoacl_op_setattr_prepare); + +int synoacl_op_setattr_post(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_setattr_post) + return inode->i_op->syno_setattr_post(dentry, attr); + + return synoacl_mod_setattr_post(dentry, attr); +} +EXPORT_SYMBOL(synoacl_op_setattr_post); + +int synoacl_op_may_delete(struct dentry *victim, struct inode *dir) +{ + int ret; + + if (dir->i_op->syno_may_delete) + ret = dir->i_op->syno_may_delete(victim, dir); + else + ret = synoacl_mod_may_delete(victim, dir); + + trace_synoacl_may_delete(victim, dir, ret); + + return ret; +} +EXPORT_SYMBOL(synoacl_op_may_delete); + +int synoacl_op_may_access(struct dentry *dentry, int mode) +{ + int ret; + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_may_access) + ret = inode->i_op->syno_may_access(dentry, mode); + else + ret = synoacl_mod_may_access(dentry, mode); + + trace_synoacl_may_access(dentry, mode, ret); + + return ret; +} +EXPORT_SYMBOL(synoacl_op_may_access); + +int synoacl_op_acl_xattr_get(struct dentry *dentry, int cmd, void *value, size_t size) +{ + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_acl_xattr_get) + return inode->i_op->syno_acl_xattr_get(dentry, cmd, value, size); + + return synoacl_mod_acl_xattr_get(dentry, cmd, value, size); +} +EXPORT_SYMBOL(synoacl_op_acl_xattr_get); + +void synoacl_op_to_mode(struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_acl_to_mode) + inode->i_op->syno_acl_to_mode(dentry, stat); + else + synoacl_mod_to_mode(dentry, stat); +} +EXPORT_SYMBOL(synoacl_op_to_mode); + +int synoacl_op_init(struct dentry *dentry) +{ + struct inode *inode = d_inode(dentry); + + if (inode->i_op->syno_acl_init) + return inode->i_op->syno_acl_init(dentry, inode); + + return synoacl_mod_init(dentry, inode); +} +EXPORT_SYMBOL(synoacl_op_init); + +int synoacl_op_xattr_permission(const char *name, struct dentry *dentry, unsigned int perm) +{ + int error = 0; + + if (!name || strcmp(name, SYNO_ACL_XATTR_ACCESS)) + return 0; // skip xattr except ACL. + + switch (perm) { + case MAY_READ_PERMISSION: + if (!IS_SYNOACL(dentry)) + return -EOPNOTSUPP; + break; + + case MAY_WRITE_PERMISSION: + if (!IS_FS_SYNOACL(dentry->d_inode)) + return -EOPNOTSUPP; + break; + + default: + return 0; // invalid parameters, just skip it. + } + + error = synoacl_op_permission(dentry, perm); + if (error) + return error; + + return 0; +} + +static inline int +syno_acl_entry_from_disk(struct syno_acl_entry *sae, syno_acl_entry_t *bsae) +{ + unsigned short tag = le16_to_cpu(bsae->e_tag); + + // ID: user/group/everyone + if (SYNO_ACL_XATTR_TAG_ID_GROUP & tag) { + sae->e_tag = SYNO_ACL_GROUP; + sae->e_id = le32_to_cpu(bsae->e_id); + } else if (SYNO_ACL_XATTR_TAG_ID_EVERYONE & tag) { + sae->e_tag = SYNO_ACL_EVERYONE; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_USER & tag) { + sae->e_tag = SYNO_ACL_USER; + sae->e_id = le32_to_cpu(bsae->e_id); + } else if (SYNO_ACL_XATTR_TAG_ID_OWNER & tag) { + sae->e_tag = SYNO_ACL_OWNER; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER & tag) { + sae->e_tag = SYNO_ACL_AUTHENTICATEDUSER; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else if (SYNO_ACL_XATTR_TAG_ID_SYSTEM & tag) { + sae->e_tag = SYNO_ACL_SYSTEM; + sae->e_id = SYNO_ACL_UNDEFINED_ID; + } else { + return -EINVAL; + } + + // Allow/Deny + if (SYNO_ACL_XATTR_TAG_IS_DENY & tag) { + sae->e_allow = SYNO_ACL_DENY; + } else if (SYNO_ACL_XATTR_TAG_IS_ALLOW & tag){ + sae->e_allow = SYNO_ACL_ALLOW; + } else { + return -EINVAL; + } + + sae->e_perm = le32_to_cpu(bsae->e_perm); + sae->e_inherit = le16_to_cpu(bsae->e_inherit); + sae->e_level = 0; + + return 0; +} + +static inline int +syno_acl_entry_to_disk(const struct syno_acl_entry *sae, syno_acl_entry_t *bsae) +{ + unsigned short tag = 0; + + //ID: user/group/everyone + switch(sae->e_tag){ + case SYNO_ACL_GROUP: + tag |= SYNO_ACL_XATTR_TAG_ID_GROUP; + break; + case SYNO_ACL_EVERYONE: + tag |= SYNO_ACL_XATTR_TAG_ID_EVERYONE; + break; + case SYNO_ACL_USER: + tag |= SYNO_ACL_XATTR_TAG_ID_USER; + break; + case SYNO_ACL_OWNER: + tag |= SYNO_ACL_XATTR_TAG_ID_OWNER; + break; + case SYNO_ACL_AUTHENTICATEDUSER: + tag |= SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER; + break; + case SYNO_ACL_SYSTEM: + tag |= SYNO_ACL_XATTR_TAG_ID_SYSTEM; + break; + default: + return -EINVAL; + } + + // Allow/Deny + switch(sae->e_allow){ + case SYNO_ACL_DENY: + tag |= SYNO_ACL_XATTR_TAG_IS_DENY; + break; + case SYNO_ACL_ALLOW: + tag |= SYNO_ACL_XATTR_TAG_IS_ALLOW; + break; + default: + return -EINVAL; + } + + bsae->e_tag = cpu_to_le16(tag); + bsae->e_inherit = cpu_to_le16(sae->e_inherit); + bsae->e_perm = cpu_to_le32(sae->e_perm); + bsae->e_id = cpu_to_le32(sae->e_id); + + return 0; +} + +/* + * Convert from filesystem to in-memory representation. + */ +struct syno_acl *syno_acl_from_disk(const void *value, size_t size) +{ + int i, count; + struct syno_acl *acl; + + if (!value) + return NULL; + if (size < sizeof(syno_acl_header_t)) + return ERR_PTR(-EINVAL); + if ((size - sizeof(syno_acl_header_t)) % sizeof(syno_acl_entry_t)) + return ERR_PTR(-EINVAL); + + count = (size - sizeof(syno_acl_header_t)) / sizeof(syno_acl_entry_t); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + if (((syno_acl_header_t *)value)->a_version != cpu_to_le16(SYNO_ACL_VERSION)) + return ERR_PTR(-EINVAL); + + acl = syno_acl_alloc(count, GFP_NOFS); + if (!acl) + return ERR_PTR(-ENOMEM); + + value = (char *)value + sizeof(syno_acl_header_t); + for (i = 0; i < count; i++) { + if (syno_acl_entry_from_disk(&(acl->a_entries[i]), (syno_acl_entry_t *)value)) + goto fail; + value = (char *)value + sizeof(syno_acl_entry_t); + } + return acl; + +fail: + syno_acl_release(acl); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL(syno_acl_from_disk); + +/* + * Convert from in-memory to filesystem representation. + */ +void * syno_acl_to_disk(const struct syno_acl *acl, size_t *size) +{ + char *ent; + size_t i; + syno_acl_header_t *b_acl; + + *size = sizeof(syno_acl_header_t) + acl->a_count * sizeof(syno_acl_entry_t); + b_acl = kmalloc(*size, GFP_NOFS); + if (!b_acl) + return ERR_PTR(-ENOMEM); + + b_acl->a_version = cpu_to_le16(SYNO_ACL_VERSION); + ent = (char *)b_acl + sizeof(syno_acl_header_t); + + for (i = 0; i < acl->a_count; i++) { + if (0 > syno_acl_entry_to_disk(&(acl->a_entries[i]), (syno_acl_entry_t *)ent)) + goto fail; + ent += sizeof(syno_acl_entry_t); + } + + return (char *)b_acl; + +fail: + kfree(b_acl); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL(syno_acl_to_disk); + +static void __forget_cached_syno_acl(struct syno_acl **p) +{ + struct syno_acl *old; + + old = xchg(p, ACL_NOT_CACHED); + if (!is_uncached_syno_acl(old)) + syno_acl_release(old); +} + +void forget_cached_syno_acl(struct inode *inode) +{ + __forget_cached_syno_acl(&inode->i_syno_acl); +} +EXPORT_SYMBOL(forget_cached_syno_acl); diff --git a/fs/syno_acl.h b/fs/syno_acl.h new file mode 100644 index 000000000000..276aa0a1e276 --- /dev/null +++ b/fs/syno_acl.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ + +#ifndef _FS_SYNO_ACL_H +#define _FS_SYNO_ACL_H + +#include + +#define PROTECT_BY_ACL 0x0001 +#define NEED_INODE_ACL_SUPPORT 0x0004 +#define NEED_FS_ACL_SUPPORT 0x0008 + +struct synoacl_syscall_operations { + int (*get_perm)(struct dentry *dentry, int *allow_out); + int (*is_acl_support)(struct dentry *dentry, int tag); + int (*check_perm)(struct dentry *dentry, int mask); +}; + +struct synoacl_vfs_operations { + int (*syno_acl_permission)(struct dentry *d, int mask); + int (*syno_acl_exec_permission)(struct dentry *d); + int (*archive_change_ok)(struct dentry *d, unsigned int cmd, int tag, int mask); + int (*syno_inode_change_ok)(struct dentry *d, struct iattr *attr); + int (*syno_acl_setattr_post)(struct dentry *dentry, struct iattr *); + int (*syno_acl_may_delete)(struct dentry *, struct inode *, int); + int (*syno_acl_access)(struct dentry *d, int mask); + int (*syno_acl_xattr_get)(struct dentry *d, int cmd, void *value, size_t size); + void (*syno_acl_to_mode)(struct dentry *d, struct kstat *stat); + int (*syno_acl_init)(struct dentry *d, struct inode *inode); +}; + +struct synoacl_mod_info { + struct synoacl_syscall_operations *syscall_ops; + struct synoacl_vfs_operations *vfs_ops; + struct module *owner; +}; + +#endif /* _FS_SYNO_ACL_H */ diff --git a/fs/syno_acl_api.c b/fs/syno_acl_api.c new file mode 100644 index 000000000000..b21bcb8575e1 --- /dev/null +++ b/fs/syno_acl_api.c @@ -0,0 +1,270 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2022 Synology Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "syno_acl.h" + + +#define SYSCALL_OPS synoacl_mod_info->syscall_ops +#define VFS_OPS synoacl_mod_info->vfs_ops + +#define IS_MOD_INFO_READY (synoacl_mod_info && SYSCALL_OPS && VFS_OPS) +#define IS_SYSCALL_ACL_READY(x) (IS_MOD_INFO_READY && SYSCALL_OPS->x) +#define IS_VFS_ACL_READY(x) (IS_MOD_INFO_READY && VFS_OPS->x) + +#define DO_SYSCALL(x, ...) SYSCALL_OPS->x(__VA_ARGS__) +#define DO_VFS(x, ...) VFS_OPS->x(__VA_ARGS__) + +static DEFINE_MUTEX(synoacl_mod_mutex); +struct synoacl_mod_info *synoacl_mod_info = NULL; +EXPORT_SYMBOL(synoacl_mod_info); + +bool syno_acl_module_get(void) +{ + int ret = -1; + /* If synoacl_vfs.ko wasn't loaded earlier then load it now. + * When synoacl_vfs is built into vmlinux the module's __init + * function will populate synoacl_mod_info. + */ + mutex_lock(&synoacl_mod_mutex); + if (!synoacl_mod_info) { + ret = request_module("synoacl_vfs"); + if (!synoacl_mod_info) { + mutex_unlock(&synoacl_mod_mutex); + pr_err("synoacl_vfs request_module failed. err code:%d\n", ret); + return false; + } + } + mutex_unlock(&synoacl_mod_mutex); + + /* And grab the reference, so the module doesn't disappear while the + * kernel is interacting with the kernel module. + */ + if (!try_module_get(synoacl_mod_info->owner)) { + pr_err("synoacl_vfs try_module_get failed.\n"); + return false; + } + + return true; +} +EXPORT_SYMBOL(syno_acl_module_get); + +void syno_acl_module_put(void) +{ + if (synoacl_mod_info) + module_put(synoacl_mod_info->owner); +} +EXPORT_SYMBOL(syno_acl_module_put); + +/* + * VFS API + */ +int synoacl_mod_permission(struct dentry *d, int mask) +{ + if (IS_VFS_ACL_READY(syno_acl_permission)) + return DO_VFS(syno_acl_permission, d, mask); + + return 0; +} +EXPORT_SYMBOL(synoacl_mod_permission); + +int synoacl_mod_exec_permission(struct dentry *d) +{ + if (IS_VFS_ACL_READY(syno_acl_exec_permission)) + return DO_VFS(syno_acl_exec_permission, d); + + return 0; +} +EXPORT_SYMBOL(synoacl_mod_exec_permission); + +int synoacl_mod_archive_bit_change_ok(struct dentry *d, unsigned int cmd, int tag, + int mask) +{ + if (IS_VFS_ACL_READY(archive_change_ok)) + return DO_VFS(archive_change_ok, d, cmd, tag, mask); + + return 0; // is settable +} +EXPORT_SYMBOL(synoacl_mod_archive_bit_change_ok); + +int synoacl_mod_setattr_prepare(struct dentry *d, struct iattr *attr) +{ + if (IS_VFS_ACL_READY(syno_inode_change_ok)) + return DO_VFS(syno_inode_change_ok, d, attr); + + return setattr_prepare(d, attr); +} +EXPORT_SYMBOL(synoacl_mod_setattr_prepare); + +int synoacl_mod_setattr_post(struct dentry *dentry, struct iattr *attr) +{ + if (IS_VFS_ACL_READY(syno_acl_setattr_post)) + return DO_VFS(syno_acl_setattr_post, dentry, attr); + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(synoacl_mod_setattr_post); + +int synoacl_mod_may_delete(struct dentry *d, struct inode *dir) +{ + if (IS_VFS_ACL_READY(syno_acl_may_delete)) + return DO_VFS(syno_acl_may_delete, d, dir, 1); + + return inode_permission(dir, MAY_WRITE | MAY_EXEC); +} +EXPORT_SYMBOL(synoacl_mod_may_delete); + +int synoacl_mod_may_access(struct dentry *d, int mask) +{ + if (IS_VFS_ACL_READY(syno_acl_access)) + return DO_VFS(syno_acl_access, d, mask); + + return inode_permission(d->d_inode, mask | MAY_ACCESS); +} +EXPORT_SYMBOL(synoacl_mod_may_access); + +int synoacl_mod_acl_xattr_get(struct dentry *d, int cmd, void *value, size_t size) +{ + if (IS_VFS_ACL_READY(syno_acl_xattr_get)) + return DO_VFS(syno_acl_xattr_get, d, cmd, value, size); + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(synoacl_mod_acl_xattr_get); + +void synoacl_mod_to_mode(struct dentry *d, struct kstat *stat) +{ + if (IS_VFS_ACL_READY(syno_acl_to_mode)) + DO_VFS(syno_acl_to_mode, d, stat); +} +EXPORT_SYMBOL(synoacl_mod_to_mode); + +int synoacl_mod_init(struct dentry *dentry, struct inode *inode) +{ + if (IS_VFS_ACL_READY(syno_acl_init)) + return DO_VFS(syno_acl_init, dentry, inode); + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(synoacl_mod_init); + +#ifdef MY_ABC_HERE +#include + +SYSCALL_DEFINE2(syno_acl_check_perm, const char __user *, filename, int, mask) +{ +#ifdef MY_ABC_HERE + struct path path; + int error; + + error = user_path_at(AT_FDCWD, filename, LOOKUP_FOLLOW, &path); + if (error) + return error; + + if (IS_SYSCALL_ACL_READY(check_perm)) + error = DO_SYSCALL(check_perm, path.dentry, mask); + else + error = -EOPNOTSUPP; + + path_put(&path); + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE3(syno_acl_is_support, const char __user *, filename, int, fd, int, tag) +{ +#ifdef MY_ABC_HERE + int is_path_get = 0; + struct path path; + struct file *fp = NULL; + struct dentry *dentry; + int error = -EINVAL; + + if (filename) { + error = user_path_at(AT_FDCWD, filename, LOOKUP_FOLLOW, &path); + if (error) + goto out; + + is_path_get = 1; + + if (!path.dentry || !path.dentry->d_inode) + goto out; + + dentry = path.dentry; + } else if (fd >= 0) { + fp = fget(fd); + if (!fp || !fp->f_path.dentry) { + error = -EBADF; + goto out; + } + dentry = fp->f_path.dentry; + } else { + goto out; + } + + if (IS_SYSCALL_ACL_READY(is_acl_support)) + error = DO_SYSCALL(is_acl_support, dentry, tag); + else + error = -EOPNOTSUPP; + +out: + if (is_path_get) + path_put(&path); + if (fp) + fput(fp); + + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} + +SYSCALL_DEFINE2(syno_acl_get_perm, const char __user *, filename, int __user *, out_perm) +{ +#ifdef MY_ABC_HERE + unsigned int perm_allow = 0; + int error; + struct path path; + + error = user_path_at(AT_FDCWD, filename, LOOKUP_FOLLOW, &path); + if (error) + return error; + + if (IS_SYNOACL_SUPERUSER()) { + perm_allow = SYNO_PERM_FULL_CONTROL; + error = 0; + goto end; + } + + if (IS_SYSCALL_ACL_READY(get_perm)) + error = DO_SYSCALL(get_perm, path.dentry, &perm_allow); + else + error = -EOPNOTSUPP; + +end: + if (copy_to_user(out_perm, &perm_allow, sizeof(perm_allow))) { + error = -EFAULT; + goto err; + } + +err: + path_put(&path); + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 0dd2f93ac048..d32b836f6ca7 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -257,10 +257,6 @@ int udf_expand_file_adinicb(struct inode *inode) char *kaddr; struct udf_inode_info *iinfo = UDF_I(inode); int err; - struct writeback_control udf_wbc = { - .sync_mode = WB_SYNC_NONE, - .nr_to_write = 1, - }; WARN_ON_ONCE(!inode_is_locked(inode)); if (!iinfo->i_lenAlloc) { @@ -304,8 +300,10 @@ int udf_expand_file_adinicb(struct inode *inode) iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; /* from now on we have normal address_space methods */ inode->i_data.a_ops = &udf_aops; + set_page_dirty(page); + unlock_page(page); up_write(&iinfo->i_data_sem); - err = inode->i_data.a_ops->writepage(page, &udf_wbc); + err = filemap_fdatawrite(inode->i_mapping); if (err) { /* Restore everything back so that we don't lose data... */ lock_page(page); @@ -316,6 +314,7 @@ int udf_expand_file_adinicb(struct inode *inode) unlock_page(page); iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; inode->i_data.a_ops = &udf_adinicb_aops; + iinfo->i_lenAlloc = inode->i_size; up_write(&iinfo->i_data_sem); } put_page(page); diff --git a/fs/udf/namei.c b/fs/udf/namei.c index f4a72ff8cf95..59b71f2e9cbf 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * namei.c * @@ -31,6 +34,19 @@ #include #include +#ifdef MY_ABC_HERE +int udf_match(int len1, const unsigned char *name1, int len2, + const unsigned char *name2, int is_caseless) +{ + if (len1 != len2) + return 0; + + if (is_caseless) + return !strncasecmp(name1, name2, len1); + + return !memcmp(name1, name2, len1); +} +#else /* MY_ABC_HERE */ static inline int udf_match(int len1, const unsigned char *name1, int len2, const unsigned char *name2) { @@ -39,6 +55,7 @@ static inline int udf_match(int len1, const unsigned char *name1, int len2, return !memcmp(name1, name2, len1); } +#endif /* MY_ABC_HERE */ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh, @@ -276,8 +293,14 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, goto out_err; } +#ifdef MY_ABC_HERE + if (udf_match(flen, fname, child->len, child->name, + UDF_QUERY_FLAG(sb, SYNO_UDF_FLAG_CASELESS))) + goto out_ok; +#else /* MY_ABC_HERE */ if (udf_match(flen, fname, child->len, child->name)) goto out_ok; +#endif /* MY_ABC_HERE */ } fi = NULL; diff --git a/fs/udf/super.c b/fs/udf/super.c index d0df217f4712..2f409830d4a3 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * super.c * @@ -56,6 +59,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #include #include "udf_sb.h" @@ -98,6 +104,56 @@ static unsigned int udf_count_free(struct super_block *); static int udf_statfs(struct dentry *, struct kstatfs *); static int udf_show_options(struct seq_file *, struct dentry *); +#ifdef MY_ABC_HERE +static int udf_hash(const struct dentry *dentry, struct qstr *qstr) +{ + qstr->hash = full_name_hash(dentry, qstr->name, qstr->len); + return 0; +} + +static int udf_hashi(const struct dentry *dentry, struct qstr *qstr) +{ + const char *name; + int len; + char c; + unsigned long hash; + + len = qstr->len; + name = qstr->name; + hash = init_name_hash(dentry); + while (len--) { + c = tolower(*name++); + hash = partial_name_hash(c, hash); + } + qstr->hash = end_name_hash(hash); + + return 0; +} + +static int udf_dentry_cmp(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +{ + return udf_match(len, str, name->len, name->name, 0); +} + +static int udf_dentry_cmpi(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +{ + return udf_match(len, str, name->len, name->name, 1); +} + +const struct dentry_operations udf_dentry_ops[] = { + { + .d_hash = udf_hashi, + .d_compare = udf_dentry_cmpi, + }, + { + .d_hash = udf_hash, + .d_compare = udf_dentry_cmp, + } +}; +#endif /* MY_ABC_HERE */ + struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb) { struct logicalVolIntegrityDesc *lvid; @@ -353,6 +409,10 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",utf8"); if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP) && sbi->s_nls_map) seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset); +#ifdef MY_ABC_HERE + if (!UDF_QUERY_FLAG(sb, SYNO_UDF_FLAG_CASELESS)) + seq_printf(seq, ",casesensitive"); +#endif /* MY_ABC_HERE */ return 0; } @@ -421,6 +481,9 @@ enum { Opt_rootdir, Opt_utf8, Opt_iocharset, Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore, Opt_fmode, Opt_dmode +#ifdef MY_ABC_HERE + , Opt_synocasesensitive +#endif /* MY_ABC_HERE */ }; static const match_table_t tokens = { @@ -451,6 +514,9 @@ static const match_table_t tokens = { {Opt_iocharset, "iocharset=%s"}, {Opt_fmode, "mode=%o"}, {Opt_dmode, "dmode=%o"}, +#ifdef MY_ABC_HERE + {Opt_synocasesensitive, "casesensitive"}, +#endif /* MY_ABC_HERE */ {Opt_err, NULL} }; @@ -459,11 +525,15 @@ static int udf_parse_options(char *options, struct udf_options *uopt, { char *p; int option; + unsigned int uv; uopt->novrs = 0; uopt->session = 0xFFFFFFFF; uopt->lastblock = 0; uopt->anchor = 0; +#ifdef MY_ABC_HERE + uopt->flags |= (1 << SYNO_UDF_FLAG_CASELESS); +#endif /* MY_ABC_HERE */ if (!options) return 1; @@ -508,17 +578,17 @@ static int udf_parse_options(char *options, struct udf_options *uopt, uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); break; case Opt_gid: - if (match_int(args, &option)) + if (match_uint(args, &uv)) return 0; - uopt->gid = make_kgid(current_user_ns(), option); + uopt->gid = make_kgid(current_user_ns(), uv); if (!gid_valid(uopt->gid)) return 0; uopt->flags |= (1 << UDF_FLAG_GID_SET); break; case Opt_uid: - if (match_int(args, &option)) + if (match_uint(args, &uv)) return 0; - uopt->uid = make_kuid(current_user_ns(), option); + uopt->uid = make_kuid(current_user_ns(), uv); if (!uid_valid(uopt->uid)) return 0; uopt->flags |= (1 << UDF_FLAG_UID_SET); @@ -592,6 +662,11 @@ static int udf_parse_options(char *options, struct udf_options *uopt, return 0; uopt->dmode = option & 0777; break; +#ifdef MY_ABC_HERE + case Opt_synocasesensitive: + uopt->flags &= ~(1 << SYNO_UDF_FLAG_CASELESS); + break; +#endif /* MY_ABC_HERE */ default: pr_err("bad mount option \"%s\" or missing value\n", p); return 0; @@ -639,6 +714,9 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) else udf_open_lvid(sb); +#ifdef MY_ABC_HERE + sb->s_d_op = &udf_dentry_ops[UDF_QUERY_FLAG(sb, SYNO_UDF_FLAG_CASELESS) ? 0 : 1]; +#endif /* MY_ABC_HERE */ out_unlock: return error; } @@ -2179,6 +2257,10 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sb->s_magic = UDF_SUPER_MAGIC; sb->s_time_gran = 1000; +#ifdef MY_ABC_HERE + sb->s_d_op = &udf_dentry_ops[UDF_QUERY_FLAG(sb, SYNO_UDF_FLAG_CASELESS) ? 0 : 1]; +#endif /* MY_ABC_HERE */ + if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) { ret = udf_load_vrs(sb, &uopt, silent, &fileset); } else { diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 758efe557a19..a305410671bc 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LINUX_UDF_SB_H #define __LINUX_UDF_SB_H @@ -32,6 +35,9 @@ #define UDF_FLAG_INCONSISTENT 18 #define UDF_FLAG_RW_INCOMPAT 19 /* Set when we find RW incompatible * feature */ +#ifdef MY_ABC_HERE +#define SYNO_UDF_FLAG_CASELESS 20 +#endif /* MY_ABC_HERE */ #define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001 #define UDF_PART_FLAG_UNALLOC_TABLE 0x0002 diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 9dd0814f1077..c5a6d3d2f23f 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __UDF_DECL_H #define __UDF_DECL_H @@ -130,6 +133,10 @@ static inline unsigned int udf_dir_entry_len(struct fileIdentDesc *cfi) le16_to_cpu(cfi->lengthOfImpUse) + cfi->lengthFileIdent, UDF_NAME_PAD); } +#ifdef MY_ABC_HERE +extern int udf_match(int len1, const unsigned char *name1, int len2, + const unsigned char *name2, int is_caseless); +#endif /* MY_ABC_HERE */ /* file.c */ extern long udf_ioctl(struct file *, unsigned int, unsigned long); diff --git a/fs/utimes.c b/fs/utimes.c index fd3cc4226224..70a2200e7173 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -8,6 +11,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + static bool nsec_valid(long nsec) { if (nsec == UTIME_OMIT || nsec == UTIME_NOW) @@ -225,6 +232,83 @@ SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) } #endif +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +static int _syno_utime(const char *filename, struct timespec64 *time) +{ + int error; + struct path path; + struct inode *inode; + + if (!time) + return -EINVAL; + + error = user_path_at(AT_FDCWD, filename, LOOKUP_FOLLOW, &path); + if (error) + goto out; + + error = mnt_want_write(path.mnt); + if (error) + goto dput_and_out; + + inode = path.dentry->d_inode; + if (!inode_owner_or_capable(inode)) { +#ifdef MY_ABC_HERE + if (IS_SYNOACL(path.dentry)) { + error = synoacl_op_permission(path.dentry, MAY_WRITE_ATTR | MAY_WRITE_EXT_ATTR); + if (error) + goto drop_write; + } else { + error = -EPERM; + goto drop_write; + } +#else /* MY_ABC_HERE */ + error = -EPERM; + goto drop_write; +#endif /* MY_ABC_HERE */ + } + + error = syno_op_set_crtime(inode, time); + +drop_write: + mnt_drop_write(path.mnt); +dput_and_out: + path_put(&path); +out: + return error; +} +#endif /* MY_ABC_HERE */ +/** + * sys_syno_utime() is used to update create time. + * + * @param filename The file to be changed create time. + * times Create time should be stored in a ctime field. + * + * @return 0 success + * !0 error + */ +SYSCALL_DEFINE2(syno_utime, const char __user *, filename, struct __kernel_timespec __user *, ctime) +{ +#ifdef MY_ABC_HERE + int error; + struct timespec64 time; + + if (!ctime) + return -EINVAL; + + error = copy_from_user(&time, ctime, sizeof(struct timespec64)); + if (error) + goto out; + + error = _syno_utime(filename, &time); +out: + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_COMPAT_32BIT_TIME /* * Not all architectures have sys_utime, so implement this in terms @@ -295,4 +379,28 @@ SYSCALL_DEFINE2(utimes_time32, const char __user *, filename, struct old_timeval return do_compat_futimesat(AT_FDCWD, filename, t); } #endif + +#ifdef MY_ABC_HERE +SYSCALL_DEFINE2(syno_utime32, const char __user *, filename, struct old_timespec32 __user *, ctime) +{ +#ifdef MY_ABC_HERE + int error; + struct timespec64 time; + + if (!ctime) + return -EINVAL; + + error = get_old_timespec32(&time, ctime); + if (error) + goto out; + + error = _syno_utime(filename, &time); +out: + return error; +#else + return -EOPNOTSUPP; +#endif /* MY_ABC_HERE */ +} +#endif /* MY_ABC_HERE */ + #endif diff --git a/fs/xattr.c b/fs/xattr.c index cd7a563e8bcd..d08c2a110734 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* File: fs/xattr.c @@ -25,6 +28,10 @@ #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + static const char * strcmp_prefix(const char *a, const char *a_prefix) { @@ -82,9 +89,61 @@ xattr_resolve_name(struct inode *inode, const char **name) * Check permissions for extended attribute access. This is a bit complicated * because different namespaces have very different rules. */ +#ifdef MY_ABC_HERE +static int +xattr_permission(struct dentry *dentry, const char *name, int mask) +#else static int xattr_permission(struct inode *inode, const char *name, int mask) +#endif /* MY_ABC_HERE */ { +#ifdef MY_ABC_HERE + struct inode *inode = d_inode(dentry); + /* + * For synoacl getxattr setxattr + * getxattr: mask should be MAY_READ + * setxattr: mask should be MAY_WRITE + * removexattr: mask should be MAY_WRITE + * Need to use synoacl_op_xattr_permission to check permission + */ + if (!strcmp(name, SYNO_ACL_XATTR_ACCESS)) { + if (MAY_WRITE == mask || MAY_WRITE_PERMISSION == mask) + return synoacl_op_xattr_permission(name, dentry, MAY_WRITE_PERMISSION); + else if (MAY_READ == mask || MAY_READ_PERMISSION == mask) + return synoacl_op_xattr_permission(name, dentry, MAY_READ_PERMISSION); + else + return -EPERM; + } + + /* + * getxattr for inherit ACL; + * The mask should be MAY_READ + * Need to check the MAY_READ_PERMISSION + */ + if (MAY_READ == mask) { + if (!strcmp(name, SYNO_ACL_XATTR_INHERIT)) { + if (!IS_SYNOACL(dentry)) + return -EOPNOTSUPP; + return synoacl_op_permission(dentry, MAY_READ_PERMISSION); + } + if (!strcmp(name, SYNO_ACL_XATTR_PSEUDO_INHERIT_ONLY)) + return synoacl_op_permission(dentry, MAY_READ_PERMISSION); + } + + /* + * MAC EA need to add read/write attribute permission + */ + if (IS_SYNOACL(dentry) && + (!strncmp(name, SYNO_XATTR_EA_PREFIX, SYNO_XATTR_EA_PREFIX_LEN) || + !strncmp(name, SYNO_XATTR_NETATALK_PREFIX, SYNO_XATTR_NETATALK_PREFIX_LEN))) { + if (MAY_READ & mask) + mask |= MAY_READ_ATTR; + if (MAY_WRITE & mask) + mask |= MAY_WRITE_ATTR; + return synoacl_op_permission(dentry, mask); + } +#endif /* MY_ABC_HERE */ + /* * We can never set or remove an extended attribute on a read-only * filesystem or on an immutable / append-only inode. @@ -131,6 +190,13 @@ xattr_permission(struct inode *inode, const char *name, int mask) return -EPERM; } +#ifdef MY_ABC_HERE + if (IS_SYNOACL(dentry)) { + // ACL file but not the syno key. + // still need to check mask permission with ACL + return synoacl_op_permission(dentry, mask); + } else +#endif /* MY_ABC_HERE */ return inode_permission(inode, mask); } @@ -251,7 +317,11 @@ __vfs_setxattr_locked(struct dentry *dentry, const char *name, struct inode *inode = dentry->d_inode; int error; +#ifdef MY_ABC_HERE + error = xattr_permission(dentry, name, MAY_WRITE); +#else error = xattr_permission(inode, name, MAY_WRITE); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -336,7 +406,11 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, char *value = *xattr_value; int error; +#ifdef MY_ABC_HERE + error = xattr_permission(dentry, name, MAY_READ); +#else error = xattr_permission(inode, name, MAY_READ); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -360,6 +434,9 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, *xattr_value = value; return error; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); +#endif /* MY_ABC_HERE */ ssize_t __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, @@ -382,7 +459,11 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) struct inode *inode = dentry->d_inode; int error; +#ifdef MY_ABC_HERE + error = xattr_permission(dentry, name, MAY_READ); +#else error = xattr_permission(inode, name, MAY_READ); +#endif /* MY_ABC_HERE */ if (error) return error; @@ -390,6 +471,17 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) if (error) return error; +#ifdef MY_ABC_HERE + if (name) { + if (!strcmp(name, SYNO_ACL_XATTR_INHERIT)) { + return synoacl_op_acl_xattr_get(dentry, SYNO_ACL_INHERITED, value, size); + } else if (!strcmp(name, SYNO_ACL_XATTR_PSEUDO_INHERIT_ONLY)) { + // We should return possible inherited ACL even file is in linux mode. + return synoacl_op_acl_xattr_get(dentry, SYNO_ACL_PSEUDO_INHERIT_ONLY, value, size); + } + } +#endif /* MY_ABC_HERE */ + if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; @@ -458,7 +550,11 @@ __vfs_removexattr_locked(struct dentry *dentry, const char *name, struct inode *inode = dentry->d_inode; int error; +#ifdef MY_ABC_HERE + error = xattr_permission(dentry, name, MAY_WRITE); +#else error = xattr_permission(inode, name, MAY_WRITE); +#endif /* MY_ABC_HERE */ if (error) return error; diff --git a/include/asm-generic/signal.h b/include/asm-generic/signal.h index c53984fa9761..663dd6d0795d 100644 --- a/include/asm-generic/signal.h +++ b/include/asm-generic/signal.h @@ -5,8 +5,6 @@ #include #ifndef __ASSEMBLY__ -#ifdef SA_RESTORER -#endif #include #undef __HAVE_ARCH_SIG_BITOPS diff --git a/include/dt-bindings/clock/rtd1195-clk.h b/include/dt-bindings/clock/rtd1195-clk.h new file mode 100644 index 000000000000..10ba344fd6a2 --- /dev/null +++ b/include/dt-bindings/clock/rtd1195-clk.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_CLOCK_RTD1195_H +#define __DT_BINDINGS_RTK_CLOCK_RTD1195_H + +#define RTD1195_CRT_PLL_SCPU 0 +#define RTD1195_CRT_PLL_BUS 2 +#define RTD1195_CRT_CLK_SYS 3 +#define RTD1195_CRT_PLL_DCSB 4 +#define RTD1195_CRT_CLK_SYSH 5 +#define RTD1195_CRT_PLL_GPU 9 +#define RTD1195_CRT_CLK_GPU 10 +#define RTD1195_CRT_PLL_VCPU 11 +#define RTD1195_CRT_CLK_VE 12 +#define RTD1195_CRT_CLK_VE1 13 +#define RTD1195_CRT_CLK_VE2 14 +#define RTD1195_CRT_CLK_VE2_BPU 15 + +#define RTD1195_CRT_CLK_EN_MISC 16 +#define RTD1195_CRT_CLK_EN_HDMIRX 17 +#define RTD1195_CRT_CLK_EN_GSPI 19 +#define RTD1195_CRT_CLK_EN_USB 20 +#define RTD1195_CRT_CLK_EN_HDMI 24 +#define RTD1195_CRT_CLK_EN_ETN 25 +#define RTD1195_CRT_CLK_EN_VE_JPEG 29 +#define RTD1195_CRT_CLK_EN_SE 33 +#define RTD1195_CRT_CLK_EN_CP 35 +#define RTD1195_CRT_CLK_EN_MD 36 +#define RTD1195_CRT_CLK_EN_TP 37 +#define RTD1195_CRT_CLK_EN_NF 39 +#define RTD1195_CRT_CLK_EN_EMMC 40 +#define RTD1195_CRT_CLK_EN_CR 41 +#define RTD1195_CRT_CLK_EN_SDIO_IP 42 +#define RTD1195_CRT_CLK_EN_MIPI 43 +#define RTD1195_CRT_CLK_EN_EMMC_IP 44 +#define RTD1195_CRT_CLK_EN_SDIO 46 +#define RTD1195_CRT_CLK_EN_SD_IP 47 +#define RTD1195_CRT_CLK_EN_MISC_I2C_5 49 +#define RTD1195_CRT_CLK_EN_MISC_RTC 58 +#define RTD1195_CRT_CLK_EN_MISC_I2C_4 61 +#define RTD1195_CRT_CLK_EN_MISC_I2C_3 62 +#define RTD1195_CRT_CLK_EN_MISC_I2C_2 63 +#define RTD1195_CRT_CLK_EN_MISC_I2C_1 64 +#define RTD1195_CRT_CLK_EN_UR1 76 + +#define RTD1195_CRT_CLK_MAX 77 + +#define RTD1195_ISO_CLK_EN_VFD 1 +#define RTD1195_ISO_CLK_EN_CEC0 2 +#define RTD1195_ISO_CLK_EN_CBUSRX_SYS 3 +#define RTD1195_ISO_CLK_EN_CBUSTX_SYS 4 +#define RTD1195_ISO_CLK_EN_CBUS_SYS 5 +#define RTD1195_ISO_CLK_EN_CBUS_OSC 6 +#define RTD1195_ISO_CLK_EN_IR 7 +#define RTD1195_ISO_CLK_EN_UR0 8 +#define RTD1195_ISO_CLK_EN_I2C0 9 +#define RTD1195_ISO_CLK_EN_I2C6 10 +#define RTD1195_ISO_CLK_EN_ETN_250M 11 +#define RTD1195_ISO_CLK_EN_ETN_SYS 12 + +#define RTD1195_ISO_CLK_MAX 13 + +#endif diff --git a/include/dt-bindings/clock/rtd1295-clk.h b/include/dt-bindings/clock/rtd1295-clk.h new file mode 100644 index 000000000000..7014048318c9 --- /dev/null +++ b/include/dt-bindings/clock/rtd1295-clk.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_CLOCK_RTD1295_H +#define __DT_BINDINGS_RTK_CLOCK_RTD1295_H + +#define RTD1295_CRT_PLL_SCPU 0 +#define RTD1295_CRT_PLL_BUS 2 +#define RTD1295_CRT_CLK_SYS 3 +#define RTD1295_CRT_PLL_DCSB 4 +#define RTD1295_CRT_CLK_SYSH 5 +#define RTD1295_CRT_PLL_DDSA 7 +#define RTD1295_CRT_PLL_DDSB 8 +#define RTD1295_CRT_PLL_GPU 9 +#define RTD1295_CRT_CLK_GPU 10 +#define RTD1295_CRT_PLL_VE1 11 +#define RTD1295_CRT_PLL_VE2 12 +#define RTD1295_CRT_CLK_VE1 13 +#define RTD1295_CRT_CLK_VE2 14 +#define RTD1295_CRT_CLK_VE3 15 + +#define RTD1295_CRT_CLK_EN_MISC 32 +#define RTD1295_CRT_CLK_EN_PCIE0 33 +#define RTD1295_CRT_CLK_EN_SATA_0 34 +#define RTD1295_CRT_CLK_EN_GSPI 35 +#define RTD1295_CRT_CLK_EN_USB 36 +#define RTD1295_CRT_CLK_EN_SATA_ALIVE_0 39 +#define RTD1295_CRT_CLK_EN_HDMI 40 +#define RTD1295_CRT_CLK_EN_ETN 41 +#define RTD1295_CRT_CLK_EN_TVE 46 +#define RTD1295_CRT_CLK_EN_VO 47 +#define RTD1295_CRT_CLK_EN_LVDS 48 +#define RTD1295_CRT_CLK_EN_SE 49 +#define RTD1295_CRT_CLK_EN_CP 51 +#define RTD1295_CRT_CLK_EN_MD 52 +#define RTD1295_CRT_CLK_EN_TP 53 +#define RTD1295_CRT_CLK_EN_RSA 54 +#define RTD1295_CRT_CLK_EN_NF 55 +#define RTD1295_CRT_CLK_EN_EMMC 56 +#define RTD1295_CRT_CLK_EN_CR 57 +#define RTD1295_CRT_CLK_EN_SDIO_IP 58 +#define RTD1295_CRT_CLK_EN_MIPI 59 +#define RTD1295_CRT_CLK_EN_EMMC_IP 60 +#define RTD1295_CRT_CLK_EN_SDIO 62 +#define RTD1295_CRT_CLK_EN_SD_IP 63 +#define RTD1295_CRT_CLK_EN_NAT 64 +#define RTD1295_CRT_CLK_EN_MISC_I2C_5 65 +#define RTD1295_CRT_CLK_EN_JPEG 67 +#define RTD1295_CRT_CLK_EN_PCIE1 69 +#define RTD1295_CRT_CLK_EN_MISC_SC 70 +#define RTD1295_CRT_CLK_EN_CBUS_TX 71 +#define RTD1295_CRT_CLK_EN_MISC_RTC 74 +#define RTD1295_CRT_CLK_EN_MISC_I2C_4 77 +#define RTD1295_CRT_CLK_EN_MISC_I2C_3 78 +#define RTD1295_CRT_CLK_EN_MISC_I2C_2 79 +#define RTD1295_CRT_CLK_EN_MISC_I2C_1 80 +#define RTD1295_CRT_CLK_EN_HDMIRX 88 +#define RTD1295_CRT_CLK_EN_SATA_1 89 +#define RTD1295_CRT_CLK_EN_SATA_ALIVE_1 90 +#define RTD1295_CRT_CLK_EN_UR2 91 +#define RTD1295_CRT_CLK_EN_UR1 92 +#define RTD1295_CRT_CLK_EN_FAN 93 + +#define RTD1295_CRT_CLK_EN_LSADC 96 + +#define RTD1295_CRT_CLK_MAX 97 + +#define RTD1295_ISO_CLK_EN_CEC0 2 +#define RTD1295_ISO_CLK_EN_CBUSRX_SYS 3 +#define RTD1295_ISO_CLK_EN_CBUSTX_SYS 4 +#define RTD1295_ISO_CLK_EN_CBUS_SYS 5 +#define RTD1295_ISO_CLK_EN_CBUS_OSC 6 +#define RTD1295_ISO_CLK_EN_IR 7 +#define RTD1295_ISO_CLK_EN_UR0 8 +#define RTD1295_ISO_CLK_EN_I2C0 9 +#define RTD1295_ISO_CLK_EN_I2C1 10 +#define RTD1295_ISO_CLK_EN_ETN_250M 11 +#define RTD1295_ISO_CLK_EN_ETN_SYS 12 + +#define RTD1295_ISO_CLK_MAX 13 + +#endif diff --git a/include/dt-bindings/clock/rtd1319-clk.h b/include/dt-bindings/clock/rtd1319-clk.h new file mode 100644 index 000000000000..d8cf282be3ca --- /dev/null +++ b/include/dt-bindings/clock/rtd1319-clk.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_CLOCK_RTD1319_H +#define __DT_BINDINGS_RTK_CLOCK_RTD1319_H + +#define RTD1319_CRT_PLL_SCPU 0 +#define RTD1319_CRT_PLL_BUS 2 +#define RTD1319_CRT_CLK_SYS 3 +#define RTD1319_CRT_PLL_DCSB 4 +#define RTD1319_CRT_CLK_SYSH 5 +#define RTD1319_CRT_PLL_DDSA 7 +#define RTD1319_CRT_PLL_GPU 9 +#define RTD1319_CRT_CLK_GPU 10 +#define RTD1319_CRT_PLL_VE1 11 +#define RTD1319_CRT_PLL_VE2 12 +#define RTD1319_CRT_CLK_VE1 13 +#define RTD1319_CRT_CLK_VE2 14 +#define RTD1319_CRT_CLK_VE3 15 +#define RTD1319_CRT_CLK_VE3_BPU 16 +#define RTD1319_CRT_PLL_DIF 17 +#define RTD1319_CRT_PLL_PSAUD1A 18 +#define RTD1319_CRT_PLL_PSAUD2A 19 + +#define RTD1319_CRT_CLK_EN_MISC 32 +#define RTD1319_CRT_CLK_EN_PCIE0 33 +#define RTD1319_CRT_CLK_EN_GSPI 35 +#define RTD1319_CRT_CLK_EN_SDS 38 +#define RTD1319_CRT_CLK_EN_HDMI 39 +#define RTD1319_CRT_CLK_EN_LSADC 46 +#define RTD1319_CRT_CLK_EN_CP 49 +#define RTD1319_CRT_CLK_EN_TP 51 +#define RTD1319_CRT_CLK_EN_RSA 52 +#define RTD1319_CRT_CLK_EN_NF 53 +#define RTD1319_CRT_CLK_EN_EMMC 54 +#define RTD1319_CRT_CLK_EN_SD 55 +#define RTD1319_CRT_CLK_EN_SDIO_IP 56 +#define RTD1319_CRT_CLK_EN_MIPI 57 +#define RTD1319_CRT_CLK_EN_EMMC_IP 58 +#define RTD1319_CRT_CLK_EN_SDIO 59 +#define RTD1319_CRT_CLK_EN_SD_IP 60 +#define RTD1319_CRT_CLK_EN_CABLERX 61 +#define RTD1319_CRT_CLK_EN_TPB 62 +#define RTD1319_CRT_CLK_EN_MISC_SC1 63 +#define RTD1319_CRT_CLK_EN_MISC_I2C_3 64 +#define RTD1319_CRT_CLK_EN_JPEG 66 +#define RTD1319_CRT_CLK_EN_MISC_SC0 69 +#define RTD1319_CRT_CLK_EN_HDMIRX 77 +#define RTD1319_CRT_CLK_EN_HSE 78 +#define RTD1319_CRT_CLK_EN_UR2 79 +#define RTD1319_CRT_CLK_EN_UR1 80 +#define RTD1319_CRT_CLK_EN_FAN 81 +#define RTD1319_CRT_CLK_EN_SATA_WRAP_SYS 84 +#define RTD1319_CRT_CLK_EN_SATA_WRAP_SYSH 85 +#define RTD1319_CRT_CLK_EN_SATA_MAC_SYSH 86 +#define RTD1319_CRT_CLK_EN_R2RDSC 87 +#define RTD1319_CRT_CLK_EN_TPC 88 +#define RTD1319_CRT_CLK_EN_PCIE1 89 +#define RTD1319_CRT_CLK_EN_MISC_I2C_4 90 +#define RTD1319_CRT_CLK_EN_MISC_I2C_5 91 +#define RTD1319_CRT_CLK_EN_TSIO 92 +#define RTD1319_CRT_CLK_EN_EDP 94 +#define RTD1319_CRT_CLK_EN_TSIO_TRX 95 +#define RTD1319_CRT_CLK_EN_PCIE2 96 +#define RTD1319_CRT_CLK_EN_ISO_GSPI 97 + +#define RTD1319_CRT_CLK_DET_PLL_BUS 112 +#define RTD1319_CRT_CLK_DET_PLL_DCSB 113 +#define RTD1319_CRT_CLK_DET_PLL_ACPU 114 +#define RTD1319_CRT_CLK_DET_PLL_DDSA 115 +#define RTD1319_CRT_CLK_DET_PLL_GPU 116 +#define RTD1319_CRT_CLK_DET_PLL_VE1 117 +#define RTD1319_CRT_CLK_DET_PLL_VE2 118 + +#define RTD1319_CRT_CLK_MAX 119 + +#define RTD1319_ISO_CLK_EN_LSADC_ECOA2 1 +#define RTD1319_ISO_CLK_EN_CEC0 2 +#define RTD1319_ISO_CLK_EN_CBUSRX_SYS 3 +#define RTD1319_ISO_CLK_EN_CBUSTX_SYS 4 +#define RTD1319_ISO_CLK_EN_CBUS_SYS 5 +#define RTD1319_ISO_CLK_EN_CBUS_OSC 6 +#define RTD1319_ISO_CLK_EN_IR 7 +#define RTD1319_ISO_CLK_EN_UR0 8 +#define RTD1319_ISO_CLK_EN_I2C0 9 +#define RTD1319_ISO_CLK_EN_I2C1 10 +#define RTD1319_ISO_CLK_EN_ETN_250M 11 +#define RTD1319_ISO_CLK_EN_ETN_SYS 12 +#define RTD1319_ISO_CLK_EN_USB_DRD 13 +#define RTD1319_ISO_CLK_EN_USB_HOST 14 +#define RTD1319_ISO_CLK_EN_USB_U3_HOST 15 +#define RTD1319_ISO_CLK_EN_USB 16 +#define RTD1319_ISO_CLK_EN_ISO_GSPI 17 + +#define RTD1319_ISO_CLK_MAX 18 + +#endif diff --git a/include/dt-bindings/clock/rtd1395-clk.h b/include/dt-bindings/clock/rtd1395-clk.h new file mode 100644 index 000000000000..b3c7504495c8 --- /dev/null +++ b/include/dt-bindings/clock/rtd1395-clk.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_CLOCK_RTD1395_H +#define __DT_BINDINGS_RTK_CLOCK_RTD1395_H + +#define RTD1395_CRT_PLL_SCPU 0 +#define RTD1395_CRT_PLL_BUS 2 +#define RTD1395_CRT_CLK_SYS 3 +#define RTD1395_CRT_PLL_DCSB 4 +#define RTD1395_CRT_CLK_SYSH 5 +#define RTD1395_CRT_PLL_DDSA 7 +#define RTD1395_CRT_PLL_DDSB 8 +#define RTD1395_CRT_PLL_GPU 9 +#define RTD1395_CRT_CLK_GPU 10 +#define RTD1395_CRT_PLL_VE1 11 +#define RTD1395_CRT_PLL_VE2 12 +#define RTD1395_CRT_CLK_VE1 13 +#define RTD1395_CRT_CLK_VE2 14 + +#define RTD1395_CRT_CLK_VE2_BPU 16 + +#define RTD1395_CRT_CLK_EN_MISC 32 +#define RTD1395_CRT_CLK_EN_PCIE0 33 +#define RTD1395_CRT_CLK_EN_GSPI 35 +#define RTD1395_CRT_CLK_EN_SDS 39 +#define RTD1395_CRT_CLK_EN_HDMI 40 +#define RTD1395_CRT_CLK_EN_LSADC 48 +#define RTD1395_CRT_CLK_EN_SE 49 +#define RTD1395_CRT_CLK_EN_CP 51 +#define RTD1395_CRT_CLK_EN_MD 52 +#define RTD1395_CRT_CLK_EN_TP 53 +#define RTD1395_CRT_CLK_EN_RSA 54 +#define RTD1395_CRT_CLK_EN_NF 55 +#define RTD1395_CRT_CLK_EN_EMMC 56 +#define RTD1395_CRT_CLK_EN_CR 57 +#define RTD1395_CRT_CLK_EN_SDIO_IP 58 +#define RTD1395_CRT_CLK_EN_MIPI 59 +#define RTD1395_CRT_CLK_EN_EMMC_IP 60 +#define RTD1395_CRT_CLK_EN_SDIO 62 +#define RTD1395_CRT_CLK_EN_SD_IP 63 +#define RTD1395_CRT_CLK_EN_MISC_I2C_5 65 +#define RTD1395_CRT_CLK_EN_JPEG 67 +#define RTD1395_CRT_CLK_EN_MISC_SC 70 +#define RTD1395_CRT_CLK_EN_MISC_I2C_1 80 +#define RTD1395_CRT_CLK_EN_HDMIRX 88 +#define RTD1395_CRT_CLK_EN_HSE 89 +#define RTD1395_CRT_CLK_EN_UR2 91 +#define RTD1395_CRT_CLK_EN_UR1 92 +#define RTD1395_CRT_CLK_EN_FAN 93 + +#define RTD1395_CRT_CLK_DET_PLL_BUS 112 +#define RTD1395_CRT_CLK_DET_PLL_DCSB 113 +#define RTD1395_CRT_CLK_DET_PLL_ACPU 114 +#define RTD1395_CRT_CLK_DET_PLL_DDSA 115 +#define RTD1395_CRT_CLK_DET_PLL_DDSB 116 +#define RTD1395_CRT_CLK_DET_PLL_GPU 117 +#define RTD1395_CRT_CLK_DET_PLL_VE1 118 +#define RTD1395_CRT_CLK_DET_PLL_VE2 119 + +#define RTD1395_CRT_CLK_MAX 120 + +#define RTD1395_ISO_CLK_EN_CEC0 2 +#define RTD1395_ISO_CLK_EN_CBUSRX_SYS 3 +#define RTD1395_ISO_CLK_EN_CBUSTX_SYS 4 +#define RTD1395_ISO_CLK_EN_CBUS_SYS 5 +#define RTD1395_ISO_CLK_EN_CBUS_OSC 6 +#define RTD1395_ISO_CLK_EN_IR 7 +#define RTD1395_ISO_CLK_EN_UR0 8 +#define RTD1395_ISO_CLK_EN_I2C0 9 +#define RTD1395_ISO_CLK_EN_I2C1 10 +#define RTD1395_ISO_CLK_EN_ETN_250M 11 +#define RTD1395_ISO_CLK_EN_ETN_SYS 12 +#define RTD1395_ISO_CLK_EN_USB_DRD 13 +#define RTD1395_ISO_CLK_EN_USB_HOST_0 14 +#define RTD1395_ISO_CLK_EN_USB_HOST_1 15 +#define RTD1395_ISO_CLK_EN_USB 16 + +#define RTD1395_ISO_CLK_MAX 17 + +#endif diff --git a/include/dt-bindings/clock/rtd1619-clk.h b/include/dt-bindings/clock/rtd1619-clk.h new file mode 100644 index 000000000000..0df20d768d2b --- /dev/null +++ b/include/dt-bindings/clock/rtd1619-clk.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_CLOCK_RTD1619_H +#define __DT_BINDINGS_RTK_CLOCK_RTD1619_H + +#define RTD1619_CRT_PLL_SCPU 0 +#define RTD1619_CRT_PLL_BUS 2 +#define RTD1619_CRT_CLK_SYS 3 +#define RTD1619_CRT_PLL_DCSB 4 +#define RTD1619_CRT_CLK_SYSH 5 +#define RTD1619_CRT_PLL_DDSA 7 +#define RTD1619_CRT_PLL_GPU 9 +#define RTD1619_CRT_CLK_GPU 10 +#define RTD1619_CRT_PLL_VE1 11 +#define RTD1619_CRT_PLL_VE2 12 +#define RTD1619_CRT_CLK_VE1 13 +#define RTD1619_CRT_CLK_VE2 14 +#define RTD1619_CRT_CLK_VE3 15 +#define RTD1619_CRT_CLK_VE2_BPU 16 +#define RTD1619_CRT_PLL_DIF 17 +#define RTD1619_CRT_PLL_PSAUD1A 18 +#define RTD1619_CRT_PLL_PSAUD2A 19 + +#define RTD1619_CRT_CLK_EN_MISC 32 +#define RTD1619_CRT_CLK_EN_PCIE0 33 +#define RTD1619_CRT_CLK_EN_GSPI 35 +#define RTD1619_CRT_CLK_EN_SDS 38 +#define RTD1619_CRT_CLK_EN_HDMI 39 +#define RTD1619_CRT_CLK_EN_TVE 44 +#define RTD1619_CRT_CLK_EN_VO 45 +#define RTD1619_CRT_CLK_EN_LSADC 46 +#define RTD1619_CRT_CLK_EN_SE 47 +#define RTD1619_CRT_CLK_EN_CP 49 +#define RTD1619_CRT_CLK_EN_MD 50 +#define RTD1619_CRT_CLK_EN_TP 51 +#define RTD1619_CRT_CLK_EN_RSA 52 +#define RTD1619_CRT_CLK_EN_NF 53 +#define RTD1619_CRT_CLK_EN_EMMC 54 +#define RTD1619_CRT_CLK_EN_SD 55 +#define RTD1619_CRT_CLK_EN_SDIO_IP 56 +#define RTD1619_CRT_CLK_EN_MIPI 57 +#define RTD1619_CRT_CLK_EN_EMMC_IP 58 +#define RTD1619_CRT_CLK_EN_SDIO 59 +#define RTD1619_CRT_CLK_EN_SD_IP 60 +#define RTD1619_CRT_CLK_EN_CABLERX 61 +#define RTD1619_CRT_CLK_EN_TPB 62 +#define RTD1619_CRT_CLK_EN_MISC_SC1 63 +#define RTD1619_CRT_CLK_EN_MISC_I2C_3 64 +#define RTD1619_CRT_CLK_EN_JPEG 66 +#define RTD1619_CRT_CLK_EN_MISC_SC0 69 +#define RTD1619_CRT_CLK_EN_HDMIRX 77 +#define RTD1619_CRT_CLK_EN_HSE 78 +#define RTD1619_CRT_CLK_EN_UR2 79 +#define RTD1619_CRT_CLK_EN_UR1 80 +#define RTD1619_CRT_CLK_EN_FAN 81 +#define RTD1619_CRT_CLK_EN_SATA_WRAP_SYS 84 +#define RTD1619_CRT_CLK_EN_SATA_WRAP_SYSH 85 +#define RTD1619_CRT_CLK_EN_SATA_MAC_SYSH 86 +#define RTD1619_CRT_CLK_EN_R2RDSC 87 +#define RTD1619_CRT_CLK_EN_PCIE1 89 +#define RTD1619_CRT_CLK_EN_MISC_I2C_4 90 +#define RTD1619_CRT_CLK_EN_MISC_I2C_5 91 +#define RTD1619_CRT_CLK_EN_TSIO 92 +#define RTD1619_CRT_CLK_EN_EDP 94 +#define RTD1619_CRT_CLK_EN_TSIO_TRX 95 + +#define RTD1619_CRT_CLK_DET_PLL_BUS 112 +#define RTD1619_CRT_CLK_DET_PLL_DCSB 113 +#define RTD1619_CRT_CLK_DET_PLL_ACPU 114 +#define RTD1619_CRT_CLK_DET_PLL_DDSA 115 +#define RTD1619_CRT_CLK_DET_PLL_GPU 116 +#define RTD1619_CRT_CLK_DET_PLL_VE1 117 +#define RTD1619_CRT_CLK_DET_PLL_VE2 118 + +#define RTD1619_CRT_CLK_MAX 119 + +#define RTD1619_ISO_CLK_EN_CEC0 2 +#define RTD1619_ISO_CLK_EN_CBUSRX_SYS 3 +#define RTD1619_ISO_CLK_EN_CBUSTX_SYS 4 +#define RTD1619_ISO_CLK_EN_CBUS_SYS 5 +#define RTD1619_ISO_CLK_EN_CBUS_OSC 6 +#define RTD1619_ISO_CLK_EN_IR 7 +#define RTD1619_ISO_CLK_EN_UR0 8 +#define RTD1619_ISO_CLK_EN_I2C0 9 +#define RTD1619_ISO_CLK_EN_I2C1 10 +#define RTD1619_ISO_CLK_EN_ETN_250M 11 +#define RTD1619_ISO_CLK_EN_ETN_SYS 12 +#define RTD1619_ISO_CLK_EN_USB_DRD 13 +#define RTD1619_ISO_CLK_EN_USB_HOST 14 +#define RTD1619_ISO_CLK_EN_USB_U3_HOST 15 +#define RTD1619_ISO_CLK_EN_USB 16 +#define RTD1619_ISO_CLK_MAX 17 + +#endif /* __DT_BINDINGS_RTK_CLOCK_RTD1619_H */ + diff --git a/include/dt-bindings/clock/rtd1619b-clk.h b/include/dt-bindings/clock/rtd1619b-clk.h new file mode 100644 index 000000000000..4fd8b79c7344 --- /dev/null +++ b/include/dt-bindings/clock/rtd1619b-clk.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_CLOCK_RTD1619B_H +#define __DT_BINDINGS_RTK_CLOCK_RTD1619B_H + +#define RTD1619B_CRT_PLL_SCPU 0 + +#define RTD1619B_CRT_PLL_BUS 2 +#define RTD1619B_CRT_PLL_DCSB 3 +#define RTD1619B_CRT_CLK_SYS 4 +#define RTD1619B_CRT_CLK_SYSH 5 + +#define RTD1619B_CRT_PLL_DDSA 7 +#define RTD1619B_CRT_PLL_GPU 9 +#define RTD1619B_CRT_CLK_GPU 10 +#define RTD1619B_CRT_PLL_VE1 11 +#define RTD1619B_CRT_PLL_VE2 12 +#define RTD1619B_CRT_CLK_VE1 13 +#define RTD1619B_CRT_CLK_VE2 14 +#define RTD1619B_CRT_CLK_VE3 15 +#define RTD1619B_CRT_CLK_VE3_BPU 16 +#define RTD1619B_CRT_PLL_DIF 17 +#define RTD1619B_CRT_PLL_PSAUD1A 18 +#define RTD1619B_CRT_PLL_PSAUD2A 19 +#define RTD1619B_CRT_PLL_NPU 20 +#define RTD1619B_CRT_CLK_NPU 21 +#define RTD1619B_CRT_PLL_HIFI 22 +#define RTD1619B_CRT_CLK_HIFI 23 + +#define RTD1619B_CRT_CLK_EN_MISC 32 +#define RTD1619B_CRT_CLK_EN_PCIE0 33 +#define RTD1619B_CRT_CLK_EN_GSPI 35 +#define RTD1619B_CRT_CLK_EN_SDS 38 +#define RTD1619B_CRT_CLK_EN_HDMI 39 +#define RTD1619B_CRT_CLK_EN_LSADC 46 +#define RTD1619B_CRT_CLK_EN_CP 49 +#define RTD1619B_CRT_CLK_EN_TP 51 +#define RTD1619B_CRT_CLK_EN_NF 53 +#define RTD1619B_CRT_CLK_EN_EMMC 54 +#define RTD1619B_CRT_CLK_EN_SD 55 +#define RTD1619B_CRT_CLK_EN_SDIO_IP 56 +#define RTD1619B_CRT_CLK_EN_MIPI 57 +#define RTD1619B_CRT_CLK_EN_EMMC_IP 58 +#define RTD1619B_CRT_CLK_EN_SDIO 59 +#define RTD1619B_CRT_CLK_EN_SD_IP 60 +#define RTD1619B_CRT_CLK_EN_CABLERX 61 +#define RTD1619B_CRT_CLK_EN_TPB 62 +#define RTD1619B_CRT_CLK_EN_MISC_SC1 63 +#define RTD1619B_CRT_CLK_EN_MISC_I2C_3 64 +#define RTD1619B_CRT_CLK_EN_JPEG 66 +#define RTD1619B_CRT_CLK_EN_MISC_SC0 69 +#define RTD1619B_CRT_CLK_EN_HDMIRX 77 +#define RTD1619B_CRT_CLK_EN_HSE 78 +#define RTD1619B_CRT_CLK_EN_UR2 79 +#define RTD1619B_CRT_CLK_EN_UR1 80 +#define RTD1619B_CRT_CLK_EN_FAN 81 +#define RTD1619B_CRT_CLK_EN_SATA_WRAP_SYS 84 +#define RTD1619B_CRT_CLK_EN_SATA_WRAP_SYSH 85 +#define RTD1619B_CRT_CLK_EN_SATA_MAC_SYSH 86 +#define RTD1619B_CRT_CLK_EN_R2RDSC 87 +#define RTD1619B_CRT_CLK_EN_TPC 88 +#define RTD1619B_CRT_CLK_EN_PCIE1 89 +#define RTD1619B_CRT_CLK_EN_MISC_I2C_4 90 +#define RTD1619B_CRT_CLK_EN_MISC_I2C_5 91 +#define RTD1619B_CRT_CLK_EN_TSIO 92 +#define RTD1619B_CRT_CLK_EN_EDP 94 +#define RTD1619B_CRT_CLK_EN_TSIO_TRX 95 +#define RTD1619B_CRT_CLK_EN_PCIE2 96 +#define RTD1619B_CRT_CLK_EN_ISO_GSPI 97 +#define RTD1619B_CRT_CLK_EN_LITE 99 +#define RTD1619B_CRT_CLK_EN_MIPI_DSI 100 +#define RTD1619B_CRT_CLK_EN_NPUPP 101 +#define RTD1619B_CRT_CLK_EN_NPU 102 +#define RTD1619B_CRT_CLK_EN_HDMITOP 106 + +#define RTD1619B_CRT_CLK_DET_PLL_BUS 112 +#define RTD1619B_CRT_CLK_DET_PLL_DCSB 113 +#define RTD1619B_CRT_CLK_DET_PLL_ACPU 114 +#define RTD1619B_CRT_CLK_DET_PLL_DDSA 115 +#define RTD1619B_CRT_CLK_DET_PLL_GPU 116 +#define RTD1619B_CRT_CLK_DET_PLL_VE1 117 +#define RTD1619B_CRT_CLK_DET_PLL_VE2 118 +#define RTD1619B_CRT_CLK_DET_PLL_NPU 119 +#define RTD1619B_CRT_CLK_DET_PLL_HIFI 120 + +#define RTD1619B_CRT_CLK_MAX 121 + +#define RTD1619B_ISO_CLK_EN_LSADC 0 +#define RTD1619B_ISO_CLK_EN_ISO_GSPI 1 +#define RTD1619B_ISO_CLK_EN_MISC_CEC0 2 +#define RTD1619B_ISO_CLK_EN_CBUSRX_SYS 3 +#define RTD1619B_ISO_CLK_EN_CBUSTX_SYS 4 +#define RTD1619B_ISO_CLK_EN_CBUS_SYS 5 +#define RTD1619B_ISO_CLK_EN_CBUS_OSC 6 +#define RTD1619B_ISO_CLK_EN_MISC_IR 7 +#define RTD1619B_ISO_CLK_EN_MISC_UR0 8 +#define RTD1619B_ISO_CLK_EN_I2C0 9 +#define RTD1619B_ISO_CLK_EN_I2C1 10 +#define RTD1619B_ISO_CLK_EN_ETN_250M 11 +#define RTD1619B_ISO_CLK_EN_ETN_SYS 12 +#define RTD1619B_ISO_CLK_EN_USB_DRD 13 +#define RTD1619B_ISO_CLK_EN_USB_HOST 14 +#define RTD1619B_ISO_CLK_EN_USB_U3_HOST 15 +#define RTD1619B_ISO_CLK_EN_USB 16 +#define RTD1619B_ISO_CLK_EN_VTC 17 +#define RTD1619B_ISO_CLK_EN_MISC_VFD 18 + +#define RTD1619B_ISO_CLK_MAX 19 + +#endif diff --git a/include/dt-bindings/power/rtd1295-power.h b/include/dt-bindings/power/rtd1295-power.h new file mode 100644 index 000000000000..966e6adcd277 --- /dev/null +++ b/include/dt-bindings/power/rtd1295-power.h @@ -0,0 +1,12 @@ +#ifndef __DT_BINDINGS_RTD1295_POWER_H +#define __DT_BINDINGS_RTD1295_POWER_H + +#define RTD1295_PD_VE1 0 +#define RTD1295_PD_VE2 1 +#define RTD1295_PD_VE3 2 +#define RTD1295_PD_GPU 3 +#define RTD1295_PD_NAT 4 + +#define RTD1295_PD_MAX 5 + +#endif /* __DT_BINDINGS_RTD1295_POWER_H */ diff --git a/include/dt-bindings/power/rtd1395-power.h b/include/dt-bindings/power/rtd1395-power.h new file mode 100644 index 000000000000..12df6914334f --- /dev/null +++ b/include/dt-bindings/power/rtd1395-power.h @@ -0,0 +1,10 @@ +#ifndef __DT_BINDINGS_RTD1395_POWER_H +#define __DT_BINDINGS_RTD1395_POWER_H + +#define RTD1395_PD_VE1 0 +#define RTD1395_PD_VE2 1 +#define RTD1395_PD_GPU 2 + +#define RTD1395_PD_MAX 3 + +#endif /* __DT_BINDINGS_RTD1395_POWER_H */ diff --git a/include/dt-bindings/power/rtd1619-power.h b/include/dt-bindings/power/rtd1619-power.h new file mode 100644 index 000000000000..063a14da254c --- /dev/null +++ b/include/dt-bindings/power/rtd1619-power.h @@ -0,0 +1,12 @@ +#ifndef __DT_BINDINGS_RTD1619_POWER_H +#define __DT_BINDINGS_RTD1619_POWER_H + +#define RTD1619_PD_VE1 0 +#define RTD1619_PD_VE2 1 +#define RTD1619_PD_VE3 2 +#define RTD1619_PD_GPU 3 +#define RTD1619_PD_HDMIRX 4 + +#define RTD1619_PD_MAX 5 + +#endif /* __DT_BINDINGS_RTD1619_POWER_H */ diff --git a/include/dt-bindings/power/rtd1619b-power.h b/include/dt-bindings/power/rtd1619b-power.h new file mode 100644 index 000000000000..e66cb9ff65bd --- /dev/null +++ b/include/dt-bindings/power/rtd1619b-power.h @@ -0,0 +1,16 @@ +#ifndef __DT_BINDINGS_RTD1619B_POWER_H +#define __DT_BINDINGS_RTD1619B_POWER_H + +#define RTD1619B_PD_VE1 0 +#define RTD1619B_PD_VE2 1 +#define RTD1619B_PD_VE3 2 +#define RTD1619B_PD_GPU 3 +#define RTD1619B_PD_HIFI0 4 +#define RTD1619B_PD_HIFI1 5 +#define RTD1619B_PD_NPU 6 + +#define RTD1619B_PD_NPU_SRAM 7 + +#define RTD1619B_PD_MAX 8 + +#endif /* __DT_BINDINGS_RTD1619B_POWER_H */ diff --git a/include/dt-bindings/regulator/anpec,apw888x.h b/include/dt-bindings/regulator/anpec,apw888x.h new file mode 100644 index 000000000000..387340d07fe5 --- /dev/null +++ b/include/dt-bindings/regulator/anpec,apw888x.h @@ -0,0 +1,12 @@ +#ifndef __DT_BINDINGS_REGULATOR_ANPEC_APW888X_H +#define __DT_BINDINGS_REGULATOR_ANPEC_APW888X_H + +#define APW8889_DC_MODE_AUTO (0x0) +#define APW8889_DC_MODE_FORCE_PWM (0x1) +#define APW8889_LDO_MODE_NORMAL (APW8889_DC_MODE_AUTO) + +#define APW888X_DC_MODE_AUTO (0x0) +#define APW888X_DC_MODE_FORCE_PWM (0x1) +#define APW888X_LDO_MODE_NORMAL (APW888X_DC_MODE_AUTO) + +#endif diff --git a/include/dt-bindings/reset/rtd1195-reset.h b/include/dt-bindings/reset/rtd1195-reset.h new file mode 100644 index 000000000000..737dbbb8da39 --- /dev/null +++ b/include/dt-bindings/reset/rtd1195-reset.h @@ -0,0 +1,65 @@ +#ifndef __DT_BINDINGS_RTK_RESET_RTD1195_H +#define __DT_BINDINGS_RTK_RESET_RTD1195_H + +/* 0x18000000 */ +#define RTD1195_CRT_RSTN_MISC 0 +#define RTD1195_CRT_RSTN_RNG 1 +#define RTD1195_CRT_RSTN_USB3_POW 2 +#define RTD1195_CRT_RSTN_GSPI 3 +#define RTD1195_CRT_RSTN_USB3_P0_MDIO 4 +#define RTD1195_CRT_RSTN_VE_H265 5 +#define RTD1195_CRT_RSTN_USB 6 +#define RTD1195_CRT_RSTN_USB_PHY0 8 +#define RTD1195_CRT_RSTN_USB_PHY1 9 +#define RTD1195_CRT_RSTN_HDMIRX 11 +#define RTD1195_CRT_RSTN_HDMI 12 +#define RTD1195_CRT_RSTN_ETN 14 +#define RTD1195_CRT_RSTN_AIO 15 +#define RTD1195_CRT_RSTN_GPU 16 +#define RTD1195_CRT_RSTN_VE_H264 17 +#define RTD1195_CRT_RSTN_VE_JPEG 18 +#define RTD1195_CRT_RSTN_TVE 19 +#define RTD1195_CRT_RSTN_VO 20 +#define RTD1195_CRT_RSTN_LVDS 21 +#define RTD1195_CRT_RSTN_SE 22 +#define RTD1195_CRT_RSTN_DCU 23 +#define RTD1195_CRT_RSTN_DC_PHY 24 +#define RTD1195_CRT_RSTN_CP 25 +#define RTD1195_CRT_RSTN_MD 26 +#define RTD1195_CRT_RSTN_TP 27 +#define RTD1195_CRT_RSTN_AE 28 +#define RTD1195_CRT_RSTN_NF 29 +#define RTD1195_CRT_RSTN_MIPI 30 + +/* 0x18000004 */ +#define RTD1195_CRT_RSTN_ACPU 0 +#define RTD1195_CRT_RSTN_VCPU 1 +#define RTD1195_CRT_RSTN_PCR_CNT 9 +#define RTD1195_CRT_RSTN_CR 10 +#define RTD1195_CRT_RSTN_EMMC 11 +#define RTD1195_CRT_RSTN_SDIO 12 +#define RTD1195_CRT_RSTN_I2C_5 18 +#define RTD1195_CRT_RSTN_RTC 20 +#define RTD1195_CRT_RSTN_I2C_4 23 +#define RTD1195_CRT_RSTN_I2C_3 24 +#define RTD1195_CRT_RSTN_I2C_2 25 +#define RTD1195_CRT_RSTN_I2C_1 26 +#define RTD1195_CRT_RSTN_UR1 28 + +/* 0x18007088 */ +#define RTD1195_ISO_RSTN_VFD 0 +#define RTD1195_ISO_RSTN_IR 1 +#define RTD1195_ISO_RSTN_CEC0 2 +#define RTD1195_ISO_RSTN_CEC1 3 +#define RTD1195_ISO_RSTN_DP 4 +#define RTD1195_ISO_RSTN_CBUSTX 5 +#define RTD1195_ISO_RSTN_CBUSRX 6 +#define RTD1195_ISO_RSTN_EFUSE 7 +#define RTD1195_ISO_RSTN_UR0 8 +#define RTD1195_ISO_RSTN_GMAC 9 +#define RTD1195_ISO_RSTN_GPHY 10 +#define RTD1195_ISO_RSTN_I2C_0 11 +#define RTD1195_ISO_RSTN_I2C_6 12 +#define RTD1195_ISO_RSTN_CBUS 13 + +#endif diff --git a/include/dt-bindings/reset/rtd1295-reset.h b/include/dt-bindings/reset/rtd1295-reset.h new file mode 100644 index 000000000000..c7eb766ab2d5 --- /dev/null +++ b/include/dt-bindings/reset/rtd1295-reset.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_RESET_RTD1295_H +#define __DT_BINDINGS_RTK_RESET_RTD1295_H + +#define RTD1295_CRT_RSTN_REG_BANK_1 (0x0000) +#define RTD1295_CRT_RSTN_REG_BANK_2 (0x0100) +#define RTD1295_CRT_RSTN_REG_BANK_4 (0x0200) + +#define RTD1295_CRT_RSTN_MISC (RTD1295_CRT_RSTN_REG_BANK_1 | 0x00) +#define RTD1295_CRT_RSTN_NAT (RTD1295_CRT_RSTN_REG_BANK_1 | 0x01) +#define RTD1295_CRT_RSTN_GSPI (RTD1295_CRT_RSTN_REG_BANK_1 | 0x03) +#define RTD1295_CRT_RSTN_SATA_0 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x05) +#define RTD1295_CRT_RSTN_SATA_PHY_0 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x07) +#define RTD1295_CRT_RSTN_SATA_PHY_POW_0 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x0a) +#define SATA_FUNC_EXIST_0 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x0b) +#define RTD1295_CRT_RSTN_HDMI (RTD1295_CRT_RSTN_REG_BANK_1 | 0x0c) +#define RTD1295_CRT_RSTN_VE1 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x0d) +#define RTD1295_CRT_RSTN_VE2 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x0e) +#define RTD1295_CRT_RSTN_VE3 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x0f) +#define RTD1295_CRT_RSTN_ETN (RTD1295_CRT_RSTN_REG_BANK_1 | 0x10) +#define RTD1295_CRT_RSTN_AIO (RTD1295_CRT_RSTN_REG_BANK_1 | 0x11) +#define RTD1295_CRT_RSTN_GPU (RTD1295_CRT_RSTN_REG_BANK_1 | 0x12) +#define RTD1295_CRT_RSTN_TVE (RTD1295_CRT_RSTN_REG_BANK_1 | 0x13) +#define RTD1295_CRT_RSTN_VO (RTD1295_CRT_RSTN_REG_BANK_1 | 0x14) +#define RTD1295_CRT_RSTN_LVDS (RTD1295_CRT_RSTN_REG_BANK_1 | 0x15) +#define RTD1295_CRT_RSTN_SE (RTD1295_CRT_RSTN_REG_BANK_1 | 0x16) +#define RTD1295_CRT_RSTN_DCU (RTD1295_CRT_RSTN_REG_BANK_1 | 0x17) +#define RTD1295_CRT_RSTN_DC_PHY (RTD1295_CRT_RSTN_REG_BANK_1 | 0x18) +#define RTD1295_CRT_RSTN_CP (RTD1295_CRT_RSTN_REG_BANK_1 | 0x19) +#define RTD1295_CRT_RSTN_MD (RTD1295_CRT_RSTN_REG_BANK_1 | 0x1a) +#define RTD1295_CRT_RSTN_TP (RTD1295_CRT_RSTN_REG_BANK_1 | 0x1b) +#define RTD1295_CRT_RSTN_AE (RTD1295_CRT_RSTN_REG_BANK_1 | 0x1c) +#define RTD1295_CRT_RSTN_NF (RTD1295_CRT_RSTN_REG_BANK_1 | 0x1d) +#define RTD1295_CRT_RSTN_MIPI (RTD1295_CRT_RSTN_REG_BANK_1 | 0x1e) +#define RTD1295_CRT_RSTN_RSA (RTD1295_CRT_RSTN_REG_BANK_1 | 0x1f) + +#define RTD1295_CRT_RSTN_ACPU (RTD1295_CRT_RSTN_REG_BANK_2 | 0x00) +#define RTD1295_CRT_RSTN_JPEG (RTD1295_CRT_RSTN_REG_BANK_2 | 0x01) +#define RTD1295_CRT_RSTN_PCIE0_STITCH (RTD1295_CRT_RSTN_REG_BANK_2 | 0x06) +#define RTD1295_CRT_RSTN_PCIE0_PHY (RTD1295_CRT_RSTN_REG_BANK_2 | 0x07) +#define RTD1295_CRT_RSTN_PCIE0 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x08) +#define RTD1295_CRT_RSTN_PCR_CNT (RTD1295_CRT_RSTN_REG_BANK_2 | 0x09) +#define RTD1295_CRT_RSTN_CR (RTD1295_CRT_RSTN_REG_BANK_2 | 0x0a) +#define RTD1295_CRT_RSTN_EMMC (RTD1295_CRT_RSTN_REG_BANK_2 | 0x0b) +#define RTD1295_CRT_RSTN_SDIO (RTD1295_CRT_RSTN_REG_BANK_2 | 0x0c) +#define RTD1295_CRT_RSTN_PCIE0_CORE (RTD1295_CRT_RSTN_REG_BANK_2 | 0x0d) +#define RTD1295_CRT_RSTN_PCIE0_POWER (RTD1295_CRT_RSTN_REG_BANK_2 | 0x0e) +#define RTD1295_CRT_RSTN_PCIE0_NONSTITCH (RTD1295_CRT_RSTN_REG_BANK_2 | 0x0f) +#define RTD1295_CRT_RSTN_PCIE1_PHY (RTD1295_CRT_RSTN_REG_BANK_2 | 0x10) +#define RTD1295_CRT_RSTN_PCIE1 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x11) +#define RTD1295_CRT_RSTN_I2C_5 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x12) +#define RTD1295_CRT_RSTN_PCIE1_STITCH (RTD1295_CRT_RSTN_REG_BANK_2 | 0x13) +#define RTD1295_CRT_RSTN_PCIE1_CORE (RTD1295_CRT_RSTN_REG_BANK_2 | 0x14) +#define RTD1295_CRT_RSTN_PCIE1_POWER (RTD1295_CRT_RSTN_REG_BANK_2 | 0x15) +#define RTD1295_CRT_RSTN_PCIE1_NONSTITCH (RTD1295_CRT_RSTN_REG_BANK_2 | 0x16) +#define RTD1295_CRT_RSTN_I2C_4 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x17) +#define RTD1295_CRT_RSTN_I2C_3 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x18) +#define RTD1295_CRT_RSTN_I2C_2 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x19) +#define RTD1295_CRT_RSTN_I2C_1 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x1a) +#define RTD1295_CRT_RSTN_UR2 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x1b) +#define RTD1295_CRT_RSTN_UR1 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x1c) +#define RTD1295_CRT_RSTN_MISC_SC (RTD1295_CRT_RSTN_REG_BANK_2 | 0x1d) +#define RTD1295_CRT_RSTN_CBUS_TX (RTD1295_CRT_RSTN_REG_BANK_2 | 0x1e) +#define RTD1295_CRT_RSTN_SDS_PHY (RTD1295_CRT_RSTN_REG_BANK_2 | 0x1f) + +#define RTD1295_CRT_RSTN_USB3_PHY0_POW (RTD1295_CRT_RSTN_REG_BANK_1 | 0x02) +#define RTD1295_CRT_RSTN_USB3_P0_MDIO (RTD1295_CRT_RSTN_REG_BANK_1 | 0x04) +#define RTD1295_CRT_RSTN_USB (RTD1295_CRT_RSTN_REG_BANK_1 | 0x06) +#define RTD1295_CRT_RSTN_USB_PHY0 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x08) +#define RTD1295_CRT_RSTN_USB_PHY1 (RTD1295_CRT_RSTN_REG_BANK_1 | 0x09) + +#define RTD1295_CRT_RSTN_USB_PHY3 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x02) +#define RTD1295_CRT_RSTN_USB_PHY2 (RTD1295_CRT_RSTN_REG_BANK_2 | 0x03) +#define RTD1295_CRT_RSTN_USB3_PHY1_POW (RTD1295_CRT_RSTN_REG_BANK_2 | 0x04) +#define RTD1295_CRT_RSTN_USB3_P1_MDIO (RTD1295_CRT_RSTN_REG_BANK_2 | 0x05) + +#define RTD1295_CRT_RSTN_DCPHY_CRT (RTD1295_CRT_RSTN_REG_BANK_4 | 0x00) +#define RTD1295_CRT_RSTN_DCPHY_ALERT_RX (RTD1295_CRT_RSTN_REG_BANK_4 | 0x01) +#define RTD1295_CRT_RSTN_DCPHY_PTR (RTD1295_CRT_RSTN_REG_BANK_4 | 0x02) +#define RTD1295_CRT_RSTN_DCPHY_LDO (RTD1295_CRT_RSTN_REG_BANK_4 | 0x03) +#define RTD1295_CRT_RSTN_DCPHY_SSC_DIG (RTD1295_CRT_RSTN_REG_BANK_4 | 0x04) +#define RTD1295_CRT_RSTN_HDMIRX (RTD1295_CRT_RSTN_REG_BANK_4 | 0x05) +#define RTD1295_CRT_RSTN_CBUSRX (RTD1295_CRT_RSTN_REG_BANK_4 | 0x06) +#define RTD1295_CRT_RSTN_SATA_PHY_POW_1 (RTD1295_CRT_RSTN_REG_BANK_4 | 0x07) +#define SATA_FUNC_EXIST_1 (RTD1295_CRT_RSTN_REG_BANK_4 | 0x08) +#define RTD1295_CRT_RSTN_SATA_PHY_1 (RTD1295_CRT_RSTN_REG_BANK_4 | 0x09) +#define RTD1295_CRT_RSTN_SATA_1 (RTD1295_CRT_RSTN_REG_BANK_4 | 0x0a) +#define RTD1295_CRT_RSTN_FAN (RTD1295_CRT_RSTN_REG_BANK_4 | 0x0b) +#define RTD1295_CRT_RSTN_HDMIRX_WRAP (RTD1295_CRT_RSTN_REG_BANK_4 | 0x0c) +#define RTD1295_CRT_RSTN_PCIE0_PHY_MDIO (RTD1295_CRT_RSTN_REG_BANK_4 | 0x0d) +#define RTD1295_CRT_RSTN_PCIE1_PHY_MDIO (RTD1295_CRT_RSTN_REG_BANK_4 | 0x0e) +#define RTD1295_CRT_RSTN_DISP (RTD1295_CRT_RSTN_REG_BANK_4 | 0x0f) + +#define RTD1295_ISO_RSTN_IR 0x01 +#define RTD1295_ISO_RSTN_CEC0 0x02 +#define RTD1295_ISO_RSTN_CEC1 0x03 +#define RTD1295_ISO_RSTN_DP 0x04 +#define RTD1295_ISO_RSTN_CBUSTX 0x05 +#define RTD1295_ISO_RSTN_CBUSRX 0x06 +#define RTD1295_ISO_RSTN_EFUSE 0x07 +#define RTD1295_ISO_RSTN_UR0 0x08 +#define RTD1295_ISO_RSTN_GMAC 0x09 +#define RTD1295_ISO_RSTN_GPHY 0x0a +#define RTD1295_ISO_RSTN_I2C_0 0x0b +#define RTD1295_ISO_RSTN_I2C_1 0x0c +#define RTD1295_ISO_RSTN_CBUS 0x0d + +#endif diff --git a/include/dt-bindings/reset/rtd1319-reset.h b/include/dt-bindings/reset/rtd1319-reset.h new file mode 100644 index 000000000000..f81c01074a2d --- /dev/null +++ b/include/dt-bindings/reset/rtd1319-reset.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_RESET_RTD1319_H +#define __DT_BINDINGS_RTK_RESET_RTD1319_H + +#define RTD1319_CRT_RSTN_REG_BANK_1 (0x0000) +#define RTD1319_CRT_RSTN_REG_BANK_2 (0x0100) +#define RTD1319_CRT_RSTN_REG_BANK_3 (0x0200) +#define RTD1319_CRT_RSTN_REG_BANK_4 (0x0300) +#define RTD1319_CRT_RSTN_REG_BANK_7 (0x0400) +#define RTD1319_CRT_RSTN_REG_BANK_9 (0x0500) +#define RTD1319_CRT_RSTN_REG_BANK_D0 (0x0600) +#define RTD1319_CRT_RSTN_REG_BANK_D1 (0x0700) +#define RTD1319_CRT_RSTN_REG_BANK_D4 (0x0800) + +#define RTD1319_CRT_RSTN_MISC (RTD1319_CRT_RSTN_REG_BANK_1 | 0x00) +#define RTD1319_CRT_RSTN_DIP (RTD1319_CRT_RSTN_REG_BANK_1 | 0x02) +#define RTD1319_CRT_RSTN_GSPI (RTD1319_CRT_RSTN_REG_BANK_1 | 0x04) +#define RTD1319_CRT_RSTN_SDS (RTD1319_CRT_RSTN_REG_BANK_1 | 0x06) +#define RTD1319_CRT_RSTN_SDS_REG (RTD1319_CRT_RSTN_REG_BANK_1 | 0x08) +#define RTD1319_CRT_RSTN_SDS_PHY (RTD1319_CRT_RSTN_REG_BANK_1 | 0x0a) +#define RTD1319_CRT_RSTN_VE1_BIST (RTD1319_CRT_RSTN_REG_BANK_1 | 0x0c) +#define RTD1319_CRT_RSTN_VE2_BIST (RTD1319_CRT_RSTN_REG_BANK_1 | 0x0e) +#define RTD1319_CRT_RSTN_R2RDSC_BIST (RTD1319_CRT_RSTN_REG_BANK_1 | 0x10) +#define RTD1319_CRT_RSTN_RSA (RTD1319_CRT_RSTN_REG_BANK_1 | 0x12) +#define RTD1319_CRT_RSTN_GPU_BIST (RTD1319_CRT_RSTN_REG_BANK_1 | 0x14) +#define RTD1319_CRT_RSTN_DC_PHY (RTD1319_CRT_RSTN_REG_BANK_1 | 0x16) +#define RTD1319_CRT_RSTN_DCPHY_CRT (RTD1319_CRT_RSTN_REG_BANK_1 | 0x18) +#define RTD1319_CRT_RSTN_LSADC (RTD1319_CRT_RSTN_REG_BANK_1 | 0x1a) +#define RTD1319_CRT_RSTN_SE (RTD1319_CRT_RSTN_REG_BANK_1 | 0x1c) +#define RTD1319_CRT_RSTN_HSE_BIST (RTD1319_CRT_RSTN_REG_BANK_1 | 0x1e) + +#define RTD1319_CRT_RSTN_JPEG (RTD1319_CRT_RSTN_REG_BANK_2 | 0x00) +#define RTD1319_CRT_RSTN_SD (RTD1319_CRT_RSTN_REG_BANK_2 | 0x02) +#define RTD1319_CRT_RSTN_EMMC_BIST (RTD1319_CRT_RSTN_REG_BANK_2 | 0x04) +#define RTD1319_CRT_RSTN_SDIO (RTD1319_CRT_RSTN_REG_BANK_2 | 0x06) +#define RTD1319_CRT_RSTN_PCR_CNT (RTD1319_CRT_RSTN_REG_BANK_2 | 0x08) +#define RTD1319_CRT_RSTN_PCIE0_STITCH (RTD1319_CRT_RSTN_REG_BANK_2 | 0x0a) +#define RTD1319_CRT_RSTN_PCIE0_PHY (RTD1319_CRT_RSTN_REG_BANK_2 | 0x0c) +#define RTD1319_CRT_RSTN_PCIE0 (RTD1319_CRT_RSTN_REG_BANK_2 | 0x0e) +#define RTD1319_CRT_RSTN_PCIE0_CORE (RTD1319_CRT_RSTN_REG_BANK_2 | 0x10) +#define RTD1319_CRT_RSTN_PCIE0_POWER (RTD1319_CRT_RSTN_REG_BANK_2 | 0x12) +#define RTD1319_CRT_RSTN_PCIE0_NONSTITCH (RTD1319_CRT_RSTN_REG_BANK_2 | 0x14) +#define RTD1319_CRT_RSTN_PCIE0_PHY_MDIO (RTD1319_CRT_RSTN_REG_BANK_2 | 0x16) +#define RTD1319_CRT_RSTN_PCIE0_SGMII_MDIO (RTD1319_CRT_RSTN_REG_BANK_2 | 0x18) +#define RTD1319_CRT_RSTN_UR2 (RTD1319_CRT_RSTN_REG_BANK_2 | 0x1a) +#define RTD1319_CRT_RSTN_UR1 (RTD1319_CRT_RSTN_REG_BANK_2 | 0x1c) +#define RTD1319_CRT_RSTN_MISC_SC0 (RTD1319_CRT_RSTN_REG_BANK_2 | 0x1e) + +#define RTD1319_CRT_RSTN_AE (RTD1319_CRT_RSTN_REG_BANK_3 | 0x00) +#define RTD1319_CRT_RSTN_CABLERX (RTD1319_CRT_RSTN_REG_BANK_3 | 0x02) +#define RTD1319_CRT_RSTN_MD (RTD1319_CRT_RSTN_REG_BANK_3 | 0x04) +#define RTD1319_CRT_RSTN_TP_BIST (RTD1319_CRT_RSTN_REG_BANK_3 | 0x06) +#define RTD1319_CRT_RSTN_NF_BIST (RTD1319_CRT_RSTN_REG_BANK_3 | 0x08) +#define RTD1319_CRT_RSTN_MISC_SC1 (RTD1319_CRT_RSTN_REG_BANK_3 | 0x0a) +#define RTD1319_CRT_RSTN_I2C_3 (RTD1319_CRT_RSTN_REG_BANK_3 | 0x0c) +#define RTD1319_CRT_RSTN_FAN (RTD1319_CRT_RSTN_REG_BANK_3 | 0x0e) +#define RTD1319_CRT_RSTN_TVE (RTD1319_CRT_RSTN_REG_BANK_3 | 0x10) +#define RTD1319_CRT_RSTN_AIO (RTD1319_CRT_RSTN_REG_BANK_3 | 0x12) +#define RTD1319_CRT_RSTN_VO (RTD1319_CRT_RSTN_REG_BANK_3 | 0x14) +#define RTD1319_CRT_RSTN_MIPI (RTD1319_CRT_RSTN_REG_BANK_3 | 0x16) +#define RTD1319_CRT_RSTN_HDMIRX (RTD1319_CRT_RSTN_REG_BANK_3 | 0x18) +#define RTD1319_CRT_RSTN_HDMIRX_WRAP (RTD1319_CRT_RSTN_REG_BANK_3 | 0x1a) +#define RTD1319_CRT_RSTN_HDMI (RTD1319_CRT_RSTN_REG_BANK_3 | 0x1c) +#define RTD1319_CRT_RSTN_DISP (RTD1319_CRT_RSTN_REG_BANK_3 | 0x1e) + +#define RTD1319_CRT_RSTN_SATA_PHY_POW1 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x00) +#define RTD1319_CRT_RSTN_SATA_PHY_POW0 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x02) +#define RTD1319_CRT_RSTN_SATA_MDIO1 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x04) +#define RTD1319_CRT_RSTN_SATA_MDIO0 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x06) +#define RTD1319_CRT_RSTN_SATA_WRAP (RTD1319_CRT_RSTN_REG_BANK_4 | 0x08) +#define RTD1319_CRT_RSTN_SATA_MAC_P1 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x0a) +#define RTD1319_CRT_RSTN_SATA_MAC_P0 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x0c) +#define RTD1319_CRT_RSTN_SATA_MAC_COM (RTD1319_CRT_RSTN_REG_BANK_4 | 0x0e) +#define RTD1319_CRT_RSTN_PCIE1_STITCH (RTD1319_CRT_RSTN_REG_BANK_4 | 0x10) +#define RTD1319_CRT_RSTN_PCIE1_PHY (RTD1319_CRT_RSTN_REG_BANK_4 | 0x12) +#define RTD1319_CRT_RSTN_PCIE1 (RTD1319_CRT_RSTN_REG_BANK_4 | 0x14) +#define RTD1319_CRT_RSTN_PCIE1_CORE (RTD1319_CRT_RSTN_REG_BANK_4 | 0x16) +#define RTD1319_CRT_RSTN_PCIE1_POWER (RTD1319_CRT_RSTN_REG_BANK_4 | 0x18) +#define RTD1319_CRT_RSTN_PCIE1_NONSTITCH (RTD1319_CRT_RSTN_REG_BANK_4 | 0x1a) +#define RTD1319_CRT_RSTN_PCIE1_PHY_MDIO (RTD1319_CRT_RSTN_REG_BANK_4 | 0x1c) +#define RTD1319_CRT_RSTN_HDMITOP (RTD1319_CRT_RSTN_REG_BANK_4 | 0x1e) + +#define RTD1319_CRT_RSTN_TPB_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x00) +#define RTD1319_CRT_RSTN_I2C_4 (RTD1319_CRT_RSTN_REG_BANK_7 | 0x02) +#define RTD1319_CRT_RSTN_I2C_5 (RTD1319_CRT_RSTN_REG_BANK_7 | 0x04) +#define RTD1319_CRT_RSTN_TSIO (RTD1319_CRT_RSTN_REG_BANK_7 | 0x06) +#define RTD1319_CRT_RSTN_VE3_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x08) +#define RTD1319_CRT_RSTN_EDP (RTD1319_CRT_RSTN_REG_BANK_7 | 0x0a) +#define RTD1319_CRT_RSTN_CP_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x0c) +#define RTD1319_CRT_RSTN_DCU_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x0e) +#define RTD1319_CRT_RSTN_KT_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x10) +#define RTD1319_CRT_RSTN_AKL_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x12) +#define RTD1319_CRT_RSTN_TPC_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x14) +#define RTD1319_CRT_RSTN_ACPU_BIST (RTD1319_CRT_RSTN_REG_BANK_7 | 0x18) +#define RTD1319_CRT_RSTN_SPI2EMMC (RTD1319_CRT_RSTN_REG_BANK_7 | 0x1a) +#define RTD1319_CRT_RSTN_EARC (RTD1319_CRT_RSTN_REG_BANK_7 | 0x1c) + +#define RTD1319_CRT_RSTN_PCIE2_STITCH (RTD1319_CRT_RSTN_REG_BANK_9 | 0x00) +#define RTD1319_CRT_RSTN_PCIE2_PHY (RTD1319_CRT_RSTN_REG_BANK_9 | 0x02) +#define RTD1319_CRT_RSTN_PCIE2 (RTD1319_CRT_RSTN_REG_BANK_9 | 0x04) +#define RTD1319_CRT_RSTN_PCIE2_CORE (RTD1319_CRT_RSTN_REG_BANK_9 | 0x06) +#define RTD1319_CRT_RSTN_PCIE2_POWER (RTD1319_CRT_RSTN_REG_BANK_9 | 0x08) +#define RTD1319_CRT_RSTN_PCIE2_NONSTITCH (RTD1319_CRT_RSTN_REG_BANK_9 | 0x0a) +#define RTD1319_CRT_RSTN_PCIE2_PHY_MDIO (RTD1319_CRT_RSTN_REG_BANK_9 | 0x0c) +#define RTD1319_CRT_RSTN_DCPHY_UMCTL2 (RTD1319_CRT_RSTN_REG_BANK_9 | 0x0e) + +#define RTD1319_CRT_RSTN_EMMC (RTD1319_CRT_RSTN_REG_BANK_D0 | 0x00) +#define RTD1319_CRT_RSTN_GPU (RTD1319_CRT_RSTN_REG_BANK_D1 | 0x00) +#define RTD1319_CRT_RSTN_VE2 (RTD1319_CRT_RSTN_REG_BANK_D4 | 0x00) + +#define RTD1319_ISO_RSTN_IR 0x0001 +#define RTD1319_ISO_RSTN_CEC0 0x0002 +#define RTD1319_ISO_RSTN_CEC1 0x0003 +#define RTD1319_ISO_RSTN_ISO_GSPI 0x0004 +#define RTD1319_ISO_RSTN_CBUSTX 0x0005 +#define RTD1319_ISO_RSTN_CBUSRX 0x0006 +#define RTD1319_ISO_RSTN_LSADC_ECOA2 0x0007 +#define RTD1319_ISO_RSTN_UR0 0x0008 +#define RTD1319_ISO_RSTN_GMAC 0x0009 +#define RTD1319_ISO_RSTN_GPHY 0x000a +#define RTD1319_ISO_RSTN_I2C_0 0x000b +#define RTD1319_ISO_RSTN_I2C_1 0x000c +#define RTD1319_ISO_RSTN_CBUS 0x000d + +#define RTD1319_ISO_RSTN_USB_DRD 0x000e +#define RTD1319_ISO_RSTN_USB_HOST 0x000f +#define RTD1319_ISO_RSTN_USB_PHY_0 0x0010 +#define RTD1319_ISO_RSTN_USB_PHY_1 0x0011 +#define RTD1319_ISO_RSTN_USB_PHY_2 0x0012 +#define RTD1319_ISO_RSTN_USB 0x0013 +#define RTD1319_ISO_RSTN_TYPE_C 0x0014 +#define RTD1319_ISO_RSTN_USB_U3_HOST 0x0015 +#define RTD1319_ISO_RSTN_USB3_PHY0_POW 0x0016 +#define RTD1319_ISO_RSTN_USB3_P0_MDIO 0x0017 +#define RTD1319_ISO_RSTN_USB3_PHY1_POW 0x0018 +#define RTD1319_ISO_RSTN_USB3_P1_MDIO 0x0019 + +/* M2TMX */ +#define RTD1319_M2TMX_RSTN_VE1 0x0 +#define RTD1319_M2TMX_RSTN_VE3 0x1 +#define RTD1319_M2TMX_RSTN_MAX 0x2 + +#endif diff --git a/include/dt-bindings/reset/rtd1395-reset.h b/include/dt-bindings/reset/rtd1395-reset.h new file mode 100644 index 000000000000..8de918212064 --- /dev/null +++ b/include/dt-bindings/reset/rtd1395-reset.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_RESET_RTD1395_H +#define __DT_BINDINGS_RTK_RESET_RTD1395_H + +#define RTD1395_CRT_RSTN_REG_BANK_1 (0x0000) +#define RTD1395_CRT_RSTN_REG_BANK_2 (0x0100) +#define RTD1395_CRT_RSTN_REG_BANK_4 (0x0200) + +#define RTD1395_CRT_RSTN_MISC (RTD1395_CRT_RSTN_REG_BANK_1 | 0x00) +#define RTD1395_CRT_RSTN_DIP (RTD1395_CRT_RSTN_REG_BANK_1 | 0x01) +#define RTD1395_CRT_RSTN_GSPI (RTD1395_CRT_RSTN_REG_BANK_1 | 0x02) +#define RTD1395_CRT_RSTN_SDS (RTD1395_CRT_RSTN_REG_BANK_1 | 0x03) +#define RTD1395_CRT_RSTN_SDS_REG (RTD1395_CRT_RSTN_REG_BANK_1 | 0x04) +#define RTD1395_CRT_RSTN_HDMI (RTD1395_CRT_RSTN_REG_BANK_1 | 0x0c) +#define RTD1395_CRT_RSTN_VE1 (RTD1395_CRT_RSTN_REG_BANK_1 | 0x0d) +#define RTD1395_CRT_RSTN_VE2 (RTD1395_CRT_RSTN_REG_BANK_1 | 0x0e) +#define RTD1395_CRT_RSTN_VE1_WRAPPER (RTD1395_CRT_RSTN_REG_BANK_1 | 0x0f) +#define RTD1395_CRT_RSTN_AIO (RTD1395_CRT_RSTN_REG_BANK_1 | 0x11) +#define RTD1395_CRT_RSTN_GPU (RTD1395_CRT_RSTN_REG_BANK_1 | 0x12) +#define RTD1395_CRT_RSTN_TVE (RTD1395_CRT_RSTN_REG_BANK_1 | 0x13) +#define RTD1395_CRT_RSTN_VO (RTD1395_CRT_RSTN_REG_BANK_1 | 0x14) +#define RTD1395_CRT_RSTN_LSADC (RTD1395_CRT_RSTN_REG_BANK_1 | 0x15) +#define RTD1395_CRT_RSTN_SE (RTD1395_CRT_RSTN_REG_BANK_1 | 0x16) +#define RTD1395_CRT_RSTN_HSE (RTD1395_CRT_RSTN_REG_BANK_1 | 0x17) +#define RTD1395_CRT_RSTN_DC_PHY (RTD1395_CRT_RSTN_REG_BANK_1 | 0x18) +#define RTD1395_CRT_RSTN_CP (RTD1395_CRT_RSTN_REG_BANK_1 | 0x19) +#define RTD1395_CRT_RSTN_MD (RTD1395_CRT_RSTN_REG_BANK_1 | 0x1a) +#define RTD1395_CRT_RSTN_TP (RTD1395_CRT_RSTN_REG_BANK_1 | 0x1b) +#define RTD1395_CRT_RSTN_AE (RTD1395_CRT_RSTN_REG_BANK_1 | 0x1c) +#define RTD1395_CRT_RSTN_NF (RTD1395_CRT_RSTN_REG_BANK_1 | 0x1d) +#define RTD1395_CRT_RSTN_MIPI (RTD1395_CRT_RSTN_REG_BANK_1 | 0x1e) +#define RTD1395_CRT_RSTN_RSA (RTD1395_CRT_RSTN_REG_BANK_1 | 0x1f) + +#define RTD1395_CRT_RSTN_JPEG (RTD1395_CRT_RSTN_REG_BANK_2 | 0x01) +#define RTD1395_CRT_RSTN_PCIE0_STITCH (RTD1395_CRT_RSTN_REG_BANK_2 | 0x06) +#define RTD1395_CRT_RSTN_PCIE0_PHY (RTD1395_CRT_RSTN_REG_BANK_2 | 0x07) +#define RTD1395_CRT_RSTN_PCIE0 (RTD1395_CRT_RSTN_REG_BANK_2 | 0x08) +#define RTD1395_CRT_RSTN_PCR_CNT (RTD1395_CRT_RSTN_REG_BANK_2 | 0x09) +#define RTD1395_CRT_RSTN_CR (RTD1395_CRT_RSTN_REG_BANK_2 | 0x0a) +#define RTD1395_CRT_RSTN_EMMC (RTD1395_CRT_RSTN_REG_BANK_2 | 0x0b) +#define RTD1395_CRT_RSTN_SDIO (RTD1395_CRT_RSTN_REG_BANK_2 | 0x0c) +#define RTD1395_CRT_RSTN_PCIE0_CORE (RTD1395_CRT_RSTN_REG_BANK_2 | 0x0d) +#define RTD1395_CRT_RSTN_PCIE0_POWER (RTD1395_CRT_RSTN_REG_BANK_2 | 0x0e) +#define RTD1395_CRT_RSTN_PCIE0_NONSTITCH (RTD1395_CRT_RSTN_REG_BANK_2 | 0x0f) +#define RTD1395_CRT_RSTN_I2C_5 (RTD1395_CRT_RSTN_REG_BANK_2 | 0x10) +#define RTD1395_CRT_RSTN_I2C_1 (RTD1395_CRT_RSTN_REG_BANK_2 | 0x1a) +#define RTD1395_CRT_RSTN_UR2 (RTD1395_CRT_RSTN_REG_BANK_2 | 0x1b) +#define RTD1395_CRT_RSTN_UR1 (RTD1395_CRT_RSTN_REG_BANK_2 | 0x1c) +#define RTD1395_CRT_RSTN_MISC_SC (RTD1395_CRT_RSTN_REG_BANK_2 | 0x1d) +#define RTD1395_CRT_RSTN_SDS_PHY (RTD1395_CRT_RSTN_REG_BANK_2 | 0x1f) + +#define RTD1395_CRT_RSTN_DCPHY_CRT (RTD1395_CRT_RSTN_REG_BANK_4 | 0x00) +#define RTD1395_CRT_RSTN_HDMIRX (RTD1395_CRT_RSTN_REG_BANK_4 | 0x05) +#define RTD1395_CRT_RSTN_FAN (RTD1395_CRT_RSTN_REG_BANK_4 | 0x0b) +#define RTD1395_CRT_RSTN_HDMIRX_WRAP (RTD1395_CRT_RSTN_REG_BANK_4 | 0x0c) +#define RTD1395_CRT_RSTN_PCIE0_PHY_MDIO (RTD1395_CRT_RSTN_REG_BANK_4 | 0x0d) +#define RTD1395_CRT_RSTN_DISP (RTD1395_CRT_RSTN_REG_BANK_4 | 0x0f) +#define RTD1395_CRT_RSTN_PCIE0_SGMII_MDIO (RTD1395_CRT_RSTN_REG_BANK_4 | 0x10) + +#define RTD1395_ISO_RSTN_IR 0x01 +#define RTD1395_ISO_RSTN_CEC0 0x02 +#define RTD1395_ISO_RSTN_CEC1 0x03 +#define RTD1395_ISO_RSTN_DP 0x04 +#define RTD1395_ISO_RSTN_CBUSTX 0x05 +#define RTD1395_ISO_RSTN_CBUSRX 0x06 +#define RTD1395_ISO_RSTN_EFUSE 0x07 +#define RTD1395_ISO_RSTN_UR0 0x08 +#define RTD1395_ISO_RSTN_GMAC 0x09 +#define RTD1395_ISO_RSTN_GPHY 0x0a +#define RTD1395_ISO_RSTN_I2C_0 0x0b +#define RTD1395_ISO_RSTN_I2C_1 0x0c +#define RTD1395_ISO_RSTN_CBUS 0x0d + +#define RTD1395_ISO_RSTN_USB_DRD 0x0e +#define RTD1395_ISO_RSTN_USB_HOST 0x0f +#define RTD1395_ISO_RSTN_USB_PHY_0 0x10 +#define RTD1395_ISO_RSTN_USB_PHY_1 0x11 +#define RTD1395_ISO_RSTN_USB_PHY_2 0x12 +#define RTD1395_ISO_RSTN_USB 0x13 +#define RTD1395_ISO_RSTN_TYPE_C 0x14 + +#endif diff --git a/include/dt-bindings/reset/rtd1619-reset.h b/include/dt-bindings/reset/rtd1619-reset.h new file mode 100644 index 000000000000..6022b3bba8a4 --- /dev/null +++ b/include/dt-bindings/reset/rtd1619-reset.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_RESET_RTD1619_H +#define __DT_BINDINGS_RTK_RESET_RTD1619_H + +#define RTD1619_CRT_RSTN_REG_BANK_1 (0x0000) +#define RTD1619_CRT_RSTN_REG_BANK_2 (0x0100) +#define RTD1619_CRT_RSTN_REG_BANK_3 (0x0200) +#define RTD1619_CRT_RSTN_REG_BANK_4 (0x0300) +#define RTD1619_CRT_RSTN_REG_BANK_7 (0x0400) + +#define RTD1619_CRT_RSTN_MISC (RTD1619_CRT_RSTN_REG_BANK_1 | 0x00) +#define RTD1619_CRT_RSTN_DIP (RTD1619_CRT_RSTN_REG_BANK_1 | 0x02) +#define RTD1619_CRT_RSTN_GSPI (RTD1619_CRT_RSTN_REG_BANK_1 | 0x04) +#define RTD1619_CRT_RSTN_SDS (RTD1619_CRT_RSTN_REG_BANK_1 | 0x06) +#define RTD1619_CRT_RSTN_SDS_REG (RTD1619_CRT_RSTN_REG_BANK_1 | 0x08) +#define RTD1619_CRT_RSTN_SDS_PHY (RTD1619_CRT_RSTN_REG_BANK_1 | 0x0a) +#define RTD1619_CRT_RSTN_VE1 (RTD1619_CRT_RSTN_REG_BANK_1 | 0x0c) +#define RTD1619_CRT_RSTN_VE2 (RTD1619_CRT_RSTN_REG_BANK_1 | 0x0e) +#define RTD1619_CRT_RSTN_RSA (RTD1619_CRT_RSTN_REG_BANK_1 | 0x12) +#define RTD1619_CRT_RSTN_GPU (RTD1619_CRT_RSTN_REG_BANK_1 | 0x14) +#define RTD1619_CRT_RSTN_DC_PHY (RTD1619_CRT_RSTN_REG_BANK_1 | 0x16) +#define RTD1619_CRT_RSTN_DCPHY_CRT (RTD1619_CRT_RSTN_REG_BANK_1 | 0x18) +#define RTD1619_CRT_RSTN_LSADC (RTD1619_CRT_RSTN_REG_BANK_1 | 0x1a) +#define RTD1619_CRT_RSTN_SE (RTD1619_CRT_RSTN_REG_BANK_1 | 0x1c) + +#define RTD1619_CRT_RSTN_JPEG (RTD1619_CRT_RSTN_REG_BANK_2 | 0x00) +#define RTD1619_CRT_RSTN_SD (RTD1619_CRT_RSTN_REG_BANK_2 | 0x02) +#define RTD1619_CRT_RSTN_EMMC (RTD1619_CRT_RSTN_REG_BANK_2 | 0x04) +#define RTD1619_CRT_RSTN_SDIO (RTD1619_CRT_RSTN_REG_BANK_2 | 0x06) +#define RTD1619_CRT_RSTN_PCR_CNT (RTD1619_CRT_RSTN_REG_BANK_2 | 0x08) +#define RTD1619_CRT_RSTN_PCIE0_STITCH (RTD1619_CRT_RSTN_REG_BANK_2 | 0x0a) +#define RTD1619_CRT_RSTN_PCIE0_PHY (RTD1619_CRT_RSTN_REG_BANK_2 | 0x0c) +#define RTD1619_CRT_RSTN_PCIE0 (RTD1619_CRT_RSTN_REG_BANK_2 | 0x0e) +#define RTD1619_CRT_RSTN_PCIE0_CORE (RTD1619_CRT_RSTN_REG_BANK_2 | 0x10) +#define RTD1619_CRT_RSTN_PCIE0_POWER (RTD1619_CRT_RSTN_REG_BANK_2 | 0x12) +#define RTD1619_CRT_RSTN_PCIE0_NONSTITCH (RTD1619_CRT_RSTN_REG_BANK_2 | 0x14) +#define RTD1619_CRT_RSTN_PCIE0_PHY_MDIO (RTD1619_CRT_RSTN_REG_BANK_2 | 0x16) +#define RTD1619_CRT_RSTN_PCIE0_SGMII_MDIO (RTD1619_CRT_RSTN_REG_BANK_2 | 0x18) +#define RTD1619_CRT_RSTN_UR2 (RTD1619_CRT_RSTN_REG_BANK_2 | 0x1a) +#define RTD1619_CRT_RSTN_UR1 (RTD1619_CRT_RSTN_REG_BANK_2 | 0x1c) +#define RTD1619_CRT_RSTN_MISC_SC0 (RTD1619_CRT_RSTN_REG_BANK_2 | 0x1e) + +#define RTD1619_CRT_RSTN_AE (RTD1619_CRT_RSTN_REG_BANK_3 | 0x00) +#define RTD1619_CRT_RSTN_CABLERX (RTD1619_CRT_RSTN_REG_BANK_3 | 0x02) +#define RTD1619_CRT_RSTN_NF (RTD1619_CRT_RSTN_REG_BANK_3 | 0x08) +#define RTD1619_CRT_RSTN_MISC_SC1 (RTD1619_CRT_RSTN_REG_BANK_3 | 0x0a) +#define RTD1619_CRT_RSTN_I2C_3 (RTD1619_CRT_RSTN_REG_BANK_3 | 0x0c) +#define RTD1619_CRT_RSTN_FAN (RTD1619_CRT_RSTN_REG_BANK_3 | 0x0e) +#define RTD1619_CRT_RSTN_TVE (RTD1619_CRT_RSTN_REG_BANK_3 | 0x10) +#define RTD1619_CRT_RSTN_AIO (RTD1619_CRT_RSTN_REG_BANK_3 | 0x12) +#define RTD1619_CRT_RSTN_VO (RTD1619_CRT_RSTN_REG_BANK_3 | 0x14) +#define RTD1619_CRT_RSTN_MIPI (RTD1619_CRT_RSTN_REG_BANK_3 | 0x16) +#define RTD1619_CRT_RSTN_HDMIRX (RTD1619_CRT_RSTN_REG_BANK_3 | 0x18) +#define RTD1619_CRT_RSTN_HDMIRX_WRAP (RTD1619_CRT_RSTN_REG_BANK_3 | 0x1a) +#define RTD1619_CRT_RSTN_HDMI (RTD1619_CRT_RSTN_REG_BANK_3 | 0x1c) +#define RTD1619_CRT_RSTN_DISP (RTD1619_CRT_RSTN_REG_BANK_3 | 0x1e) + +#define RTD1619_CRT_RSTN_SATA_PHY_POW1 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x00) +#define RTD1619_CRT_RSTN_SATA_PHY_POW0 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x02) +#define RTD1619_CRT_RSTN_SATA_MDIO1 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x04) +#define RTD1619_CRT_RSTN_SATA_MDIO0 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x06) +#define RTD1619_CRT_RSTN_SATA_WRAP (RTD1619_CRT_RSTN_REG_BANK_4 | 0x08) +#define RTD1619_CRT_RSTN_SATA_MAC_P1 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x0a) +#define RTD1619_CRT_RSTN_SATA_MAC_P0 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x0c) +#define RTD1619_CRT_RSTN_SATA_MAC_COM (RTD1619_CRT_RSTN_REG_BANK_4 | 0x0e) +#define RTD1619_CRT_RSTN_PCIE1_STITCH (RTD1619_CRT_RSTN_REG_BANK_4 | 0x10) +#define RTD1619_CRT_RSTN_PCIE1_PHY (RTD1619_CRT_RSTN_REG_BANK_4 | 0x12) +#define RTD1619_CRT_RSTN_PCIE1 (RTD1619_CRT_RSTN_REG_BANK_4 | 0x14) +#define RTD1619_CRT_RSTN_PCIE1_CORE (RTD1619_CRT_RSTN_REG_BANK_4 | 0x16) +#define RTD1619_CRT_RSTN_PCIE1_POWER (RTD1619_CRT_RSTN_REG_BANK_4 | 0x18) +#define RTD1619_CRT_RSTN_PCIE1_NONSTITCH (RTD1619_CRT_RSTN_REG_BANK_4 | 0x1a) +#define RTD1619_CRT_RSTN_PCIE1_PHY_MDIO (RTD1619_CRT_RSTN_REG_BANK_4 | 0x1c) +#define RTD1619_CRT_RSTN_HDMITOP (RTD1619_CRT_RSTN_REG_BANK_4 | 0x1e) + +#define RTD1619_CRT_RSTN_I2C_4 (RTD1619_CRT_RSTN_REG_BANK_7 | 0x02) +#define RTD1619_CRT_RSTN_I2C_5 (RTD1619_CRT_RSTN_REG_BANK_7 | 0x04) +#define RTD1619_CRT_RSTN_TSIO (RTD1619_CRT_RSTN_REG_BANK_7 | 0x06) +#define RTD1619_CRT_RSTN_VE3 (RTD1619_CRT_RSTN_REG_BANK_7 | 0x08) +#define RTD1619_CRT_RSTN_EDP (RTD1619_CRT_RSTN_REG_BANK_7 | 0x0a) + +#define RTD1619_ISO_RSTN_VFD 0x0000 +#define RTD1619_ISO_RSTN_IR 0x0001 +#define RTD1619_ISO_RSTN_CEC0 0x0002 +#define RTD1619_ISO_RSTN_CEC1 0x0003 +#define RTD1619_ISO_RSTN_DP 0x0004 +#define RTD1619_ISO_RSTN_CBUSTX 0x0005 +#define RTD1619_ISO_RSTN_CBUSRX 0x0006 +#define RTD1619_ISO_RSTN_EFUSE 0x0007 +#define RTD1619_ISO_RSTN_UR0 0x0008 +#define RTD1619_ISO_RSTN_GMAC 0x0009 +#define RTD1619_ISO_RSTN_GPHY 0x000a +#define RTD1619_ISO_RSTN_I2C_0 0x000b +#define RTD1619_ISO_RSTN_I2C_1 0x000c +#define RTD1619_ISO_RSTN_CBUS 0x000d +#define RTD1619_ISO_RSTN_USB_DRD 0x000e +#define RTD1619_ISO_RSTN_USB_HOST 0x000f +#define RTD1619_ISO_RSTN_USB_PHY_0 0x0010 +#define RTD1619_ISO_RSTN_USB_PHY_1 0x0011 +#define RTD1619_ISO_RSTN_USB_PHY_2 0x0012 +#define RTD1619_ISO_RSTN_USB 0x0013 +#define RTD1619_ISO_RSTN_TYPE_C 0x0014 +#define RTD1619_ISO_RSTN_USB_U3_HOST 0x0015 +#define RTD1619_ISO_RSTN_USB3_PHY0_POW 0x0016 +#define RTD1619_ISO_RSTN_USB3_P0_MDIO 0x0017 +#define RTD1619_ISO_RSTN_USB3_PHY1_POW 0x0018 +#define RTD1619_ISO_RSTN_USB3_P1_MDIO 0x0019 + +#define SMC_RSTN_EMMC 0x0a +#define SMC_RSTN_NF 0x0c +#define SMC_RSTN_MIPI 0x1c + +#endif diff --git a/include/dt-bindings/reset/rtd1619b-reset.h b/include/dt-bindings/reset/rtd1619b-reset.h new file mode 100644 index 000000000000..2ce03b03b308 --- /dev/null +++ b/include/dt-bindings/reset/rtd1619b-reset.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_RTK_RESET_RTD1619B_H +#define __DT_BINDINGS_RTK_RESET_RTD1619B_H + +#define RTD1619B_CRT_RSTN_REG_BANK_1 (0x0000) +#define RTD1619B_CRT_RSTN_REG_BANK_2 (0x0100) +#define RTD1619B_CRT_RSTN_REG_BANK_3 (0x0200) +#define RTD1619B_CRT_RSTN_REG_BANK_4 (0x0300) +#define RTD1619B_CRT_RSTN_REG_BANK_7 (0x0400) +#define RTD1619B_CRT_RSTN_REG_BANK_9 (0x0500) +#define RTD1619B_CRT_RSTN_REG_BANK_D0 (0x0600) +#define RTD1619B_CRT_RSTN_REG_BANK_D1 (0x0700) +#define RTD1619B_CRT_RSTN_REG_BANK_D4 (0x0800) + + +#define RTD1619B_CRT_RSTN_MISC (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x00) +#define RTD1619B_CRT_RSTN_DIP (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x02) +#define RTD1619B_CRT_RSTN_GSPI (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x04) +#define RTD1619B_CRT_RSTN_SDS (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x06) +#define RTD1619B_CRT_RSTN_SDS_REG (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x08) +#define RTD1619B_CRT_RSTN_SDS_PHY (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x0a) +#define RTD1619B_CRT_RSTN_VE1_BIST (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x0c) +#define RTD1619B_CRT_RSTN_VE2_BIST (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x0e) +#define RTD1619B_CRT_RSTN_DCPHY_BIST (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x10) +#define RTD1619B_CRT_RSTN_NPU_BIST (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x12) +#define RTD1619B_CRT_RSTN_GPU_BIST (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x14) +#define RTD1619B_CRT_RSTN_DC_PHY (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x16) +#define RTD1619B_CRT_RSTN_DCPHY_CRT (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x18) +#define RTD1619B_CRT_RSTN_LSADC (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x1a) +#define RTD1619B_CRT_RSTN_SE (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x1c) +#define RTD1619B_CRT_RSTN_DISP_BIST (RTD1619B_CRT_RSTN_REG_BANK_1 | 0x1e) + +#define RTD1619B_CRT_RSTN_JPEG (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x00) +#define RTD1619B_CRT_RSTN_SD (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x02) +#define RTD1619B_CRT_RSTN_ISO_BIST (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x04) +#define RTD1619B_CRT_RSTN_SDIO (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x06) +#define RTD1619B_CRT_RSTN_PCR_CNT (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x08) +#define RTD1619B_CRT_RSTN_PCIE0_STITCH (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x0a) +#define RTD1619B_CRT_RSTN_PCIE0_PHY (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x0c) +#define RTD1619B_CRT_RSTN_PCIE0 (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x0e) +#define RTD1619B_CRT_RSTN_PCIE0_CORE (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x10) +#define RTD1619B_CRT_RSTN_PCIE0_POWER (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x12) +#define RTD1619B_CRT_RSTN_PCIE0_NONSTICH (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x14) +#define RTD1619B_CRT_RSTN_PCIE0_PHY_MDIO (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x16) +#define RTD1619B_CRT_RSTN_PCIE0_SGMII_MDIO (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x18) +#define RTD1619B_CRT_RSTN_UR2 (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x1a) +#define RTD1619B_CRT_RSTN_UR1 (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x1c) +#define RTD1619B_CRT_RSTN_MISC_SC0 (RTD1619B_CRT_RSTN_REG_BANK_2 | 0x1e) + +#define RTD1619B_CRT_RSTN_AE (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x00) +#define RTD1619B_CRT_RSTN_CABLERX (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x02) +#define RTD1619B_CRT_RSTN_MD (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x04) +#define RTD1619B_CRT_RSTN_MAIN2_BIST (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x06) +#define RTD1619B_CRT_RSTN_MAIN_BIST (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x08) +#define RTD1619B_CRT_RSTN_MISC_SC1 (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x0a) +#define RTD1619B_CRT_RSTN_I2C_3 (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x0c) +#define RTD1619B_CRT_RSTN_FAN (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x0e) +#define RTD1619B_CRT_RSTN_TVE (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x10) +#define RTD1619B_CRT_RSTN_AIO (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x12) +#define RTD1619B_CRT_RSTN_VO (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x14) +#define RTD1619B_CRT_RSTN_MIPI (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x16) +#define RTD1619B_CRT_RSTN_HDMIRX (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x18) +#define RTD1619B_CRT_RSTN_HDMIRX_WRAP (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x1a) +#define RTD1619B_CRT_RSTN_HDMI (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x1c) +#define RTD1619B_CRT_RSTN_DISP (RTD1619B_CRT_RSTN_REG_BANK_3 | 0x1e) + +#define RTD1619B_CRT_RSTN_SATA_PHY_POW1 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x00) +#define RTD1619B_CRT_RSTN_SATA_PHY_POW0 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x02) +#define RTD1619B_CRT_RSTN_SATA_MDIO1 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x04) +#define RTD1619B_CRT_RSTN_SATA_MDIO0 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x06) +#define RTD1619B_CRT_RSTN_SATA_WRAP (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x08) +#define RTD1619B_CRT_RSTN_SATA_MAC_P1 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x0a) +#define RTD1619B_CRT_RSTN_SATA_MAC_P0 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x0c) +#define RTD1619B_CRT_RSTN_SATA_MAC_COM (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x0e) +#define RTD1619B_CRT_RSTN_PCIE1_STITCH (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x10) +#define RTD1619B_CRT_RSTN_PCIE1_PHY (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x12) +#define RTD1619B_CRT_RSTN_PCIE1 (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x14) +#define RTD1619B_CRT_RSTN_PCIE1_CORE (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x16) +#define RTD1619B_CRT_RSTN_PCIE1_POWER (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x18) +#define RTD1619B_CRT_RSTN_PCIE1_NONSTICH (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x1a) +#define RTD1619B_CRT_RSTN_PCIE1_PHY_MDIO (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x1c) +#define RTD1619B_CRT_RSTN_HDMITOP (RTD1619B_CRT_RSTN_REG_BANK_4 | 0x1e) + +#define RTD1619B_CRT_RSTN_I2C_4 (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x02) +#define RTD1619B_CRT_RSTN_I2C_5 (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x04) +#define RTD1619B_CRT_RSTN_TSIO (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x06) +#define RTD1619B_CRT_RSTN_EDP (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x0a) +#define RTD1619B_CRT_RSTN_ISO_GSPI (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x16) +#define RTD1619B_CRT_RSTN_SOFT_NPU (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x18) +#define RTD1619B_CRT_RSTN_SPI2EMMC (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x1a) +#define RTD1619B_CRT_RSTN_EARC (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x1c) +#define RTD1619B_CRT_RSTN_VE1 (RTD1619B_CRT_RSTN_REG_BANK_7 | 0x1e) + +#define RTD1619B_CRT_RSTN_PCIE2_STITCH (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x00) +#define RTD1619B_CRT_RSTN_PCIE2_PHY (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x02) +#define RTD1619B_CRT_RSTN_PCIE2 (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x04) +#define RTD1619B_CRT_RSTN_PCIE2_CORE (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x06) +#define RTD1619B_CRT_RSTN_PCIE2_POWER (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x08) +#define RTD1619B_CRT_RSTN_PCIE2_NONSTITCH (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x0a) +#define RTD1619B_CRT_RSTN_PCIE2_PHY_MDIO (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x0c) +#define RTD1619B_CRT_RSTN_DCPHY_UMCTL2 (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x0e) +#define RTD1619B_CRT_RSTN_MIPI_DSI (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x10) +#define RTD1619B_CRT_RSTN_HIFM (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x12) +#define RTD1619B_CRT_RSTN_NSRAM (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x14) +#define RTD1619B_CRT_RSTN_AUCPU0_REG (RTD1619B_CRT_RSTN_REG_BANK_9 | 0x16) + +#define RTD1619B_CRT_RSTN_EMMC (RTD1619B_CRT_RSTN_REG_BANK_D0 | 0x00) +#define RTD1619B_CRT_RSTN_GPU (RTD1619B_CRT_RSTN_REG_BANK_D1 | 0x00) +#define RTD1619B_CRT_RSTN_VE2 (RTD1619B_CRT_RSTN_REG_BANK_D4 | 0x00) + +#define RTD1619B_ISO_RSTN_VFD 0x0000 +#define RTD1619B_ISO_RSTN_IR 0x0001 +#define RTD1619B_ISO_RSTN_CEC0 0x0002 +#define RTD1619B_ISO_RSTN_CEC1 0x0003 +#define RTD1619B_ISO_RSTN_ISO_GSPI 0x0004 +#define RTD1619B_ISO_RSTN_CBUSTX 0x0005 +#define RTD1619B_ISO_RSTN_CBUSRX 0x0006 +#define RTD1619B_ISO_RSTN_LSADC 0x0007 +#define RTD1619B_ISO_RSTN_UR0 0x0008 +#define RTD1619B_ISO_RSTN_GMAC 0x0009 +#define RTD1619B_ISO_RSTN_GPHY 0x000a +#define RTD1619B_ISO_RSTN_I2C_0 0x000b +#define RTD1619B_ISO_RSTN_I2C_1 0x000c +#define RTD1619B_ISO_RSTN_CBUS 0x000d + +#define RTD1619B_ISO_RSTN_USB_DRD 0x000e +#define RTD1619B_ISO_RSTN_USB_HOST 0x000f +#define RTD1619B_ISO_RSTN_USB_PHY_0 0x0010 +#define RTD1619B_ISO_RSTN_USB_PHY_1 0x0011 +#define RTD1619B_ISO_RSTN_USB_PHY_2 0x0012 +#define RTD1619B_ISO_RSTN_USB 0x0013 +#define RTD1619B_ISO_RSTN_TYPE_C 0x0014 +#define RTD1619B_ISO_RSTN_USB_U3_HOST 0x0015 +#define RTD1619B_ISO_RSTN_USB3_PHY0_POW 0x0016 +#define RTD1619B_ISO_RSTN_USB3_P0_MDIO 0x0017 +#define RTD1619B_ISO_RSTN_USB3_PHY1_POW 0x0018 +#define RTD1619B_ISO_RSTN_USB3_P1_MDIO 0x0019 + +#define RTD1619B_ISO_RSTN_VTC 0x001a + +#endif diff --git a/include/dt-bindings/soc/realtek,mem-flag.h b/include/dt-bindings/soc/realtek,mem-flag.h new file mode 100644 index 000000000000..c31b701877df --- /dev/null +++ b/include/dt-bindings/soc/realtek,mem-flag.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +/* + * Realtek DHC SoC family ION memory flag + * + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + +#ifndef _DT_BINDINGS_REALTEK_MEM_H +#define _DT_BINDINGS_REALTEK_MEM_H + +#include "../../soc/realtek/memory.h" + +#endif /* _DT_BINDINGS_REALTEK_MEM_H */ diff --git a/include/dt-bindings/soc/realtek,pm.h b/include/dt-bindings/soc/realtek,pm.h new file mode 100644 index 000000000000..8ad79a467601 --- /dev/null +++ b/include/dt-bindings/soc/realtek,pm.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +/* + * Realtek DHC SoC family power management driver + * + * Copyright (c) 2021 Realtek Semiconductor Corp. + */ + + #ifndef _DT_BINDINGS_REALTEK_PM_H +#define _DT_BINDINGS_REALTEK_PM_H + +/* wakeup source */ +#define LAN 0x01 +#define IR 0x02 +#define GPIO 0x04 +#define RTC 0x08 +#define TIMER 0x10 +#define CEC 0x20 +#define USB 0x40 + +/* wakeup mode */ +#define HIFI 0x80 +#define VTC 0x100 +#define PON 0x200 + +#define NORMAL_MODE (LAN | IR | GPIO | RTC | TIMER | CEC) +#define HIFI_MODE (HIFI | LAN | IR | GPIO | RTC | TIMER | CEC) +#define VTC_MODE (VTC | LAN | IR | GPIO | RTC | TIMER | CEC) +#define PON_MODE (PON | LAN | IR | GPIO | RTC | TIMER | CEC) + +/* GPIO mode */ +#define GPIO_WAKEUP_ENABLE 1 +#define GPIO_WAKEUP_DISABLE 0 +#define GPIO_WAKEUP_ACTIVE_LOW 0 +#define GPIO_WAKEUP_ACTIVE_HIGH 1 + +/* GPIO mode */ +#define GPIO_WAKEUP_ENABLE 1 +#define GPIO_WAKEUP_DISABLE 0 +#define GPIO_WAKEUP_ACTIVE_LOW 0 +#define GPIO_WAKEUP_ACTIVE_HIGH 1 + +#endif /* _DT_BINDINGS_REALTEK_PM_H */ diff --git a/include/linux/ata.h b/include/linux/ata.h index 6e67aded28f8..c0bb84be80b0 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* @@ -269,6 +272,12 @@ enum { ATA_CMD_PMP_READ_DMA = 0xE9, ATA_CMD_PMP_WRITE = 0xE8, ATA_CMD_PMP_WRITE_DMA = 0xEB, +#ifdef MY_ABC_HERE + ATA_CMD_PMP_SYNO_POLLING = 0xE9, + ATA_CMD_PMP_SYNO_I2C = 0xD0, + ATA_CMD_PMP_SYNO_LED_GPIO = 0xD1, + ATA_CMD_PMP_GET_BOARD_INFO_JMB575 = 0xF0, +#endif /* MY_ABC_HERE */ ATA_CMD_CONF_OVERLAY = 0xB1, ATA_CMD_SEC_SET_PASS = 0xF1, ATA_CMD_SEC_UNLOCK = 0xF2, @@ -467,10 +476,22 @@ enum { SATA_PMP_GSCR_PROD_ID = 0, SATA_PMP_GSCR_REV = 1, SATA_PMP_GSCR_PORT_INFO = 2, +#ifdef MY_ABC_HERE + SATA_PMP_GSCR_SYNO = 30, + SATA_PMP_GSCR_LOGY = 31, +#endif /* MY_ABC_HERE */ SATA_PMP_GSCR_ERROR = 32, SATA_PMP_GSCR_ERROR_EN = 33, SATA_PMP_GSCR_FEAT = 64, SATA_PMP_GSCR_FEAT_EN = 96, +#ifdef MY_ABC_HERE + SATA_PMP_GSCR_9705_GPI = 944, + SATA_PMP_GSCR_9705_GPO = 928, + SATA_PMP_GSCR_9705_GPO_EN = 932, /* GPIO dataout enable */ + SATA_PMP_GSCR_9705_GPI_POLARITY = 940, /* GPIO datain polarity */ + SATA_PMP_GSCR_9705_SATA_4_BLINK_RATE = 1000, /* Blink rate counter register for SATA 4 LED */ + SATA_PMP_GSCR_9705_SATA_0_TO_3_BLINK_RATE = 1004, /* Blink rate counter register for SATA 0~3 LED*/ +#endif /* MY_ABC_HERE */ SATA_PMP_PSCR_STATUS = 0, SATA_PMP_PSCR_ERROR = 1, @@ -737,6 +758,16 @@ static inline bool ata_id_has_pm(const u16 *id) return id[ATA_ID_COMMAND_SET_1] & (1 << 3); } +#ifdef MY_ABC_HERE +static inline bool ata_id_has_rahead(const u16 *id) +{ + /* Yes children, word 83 valid bits cover word 82 data */ + if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000) + return false; + return id[ATA_ID_COMMAND_SET_1] & (1 << 6); +} +#endif /* MY_ABC_HERE */ + static inline bool ata_id_rahead_enabled(const u16 *id) { if ((id[ATA_ID_CSF_DEFAULT] & 0xC000) != 0x4000) @@ -1132,9 +1163,27 @@ static inline bool lba_48_ok(u64 block, u32 n_block) return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= ATA_MAX_SECTORS_LBA48); } +#ifdef MY_ABC_HERE +static inline bool is_ata_read_write_cmd(u8 command) +{ + return (command == ATA_CMD_READ) || + (command == ATA_CMD_READ_EXT) || + (command == ATA_CMD_READ_QUEUED) || + (command == ATA_CMD_FPDMA_READ) || + (command == ATA_CMD_WRITE) || + (command == ATA_CMD_WRITE_EXT) || + (command == ATA_CMD_WRITE_QUEUED) || + (command == ATA_CMD_FPDMA_WRITE); +} +#endif /* MY_ABC_HERE */ + #define sata_pmp_gscr_vendor(gscr) ((gscr)[SATA_PMP_GSCR_PROD_ID] & 0xffff) #define sata_pmp_gscr_devid(gscr) ((gscr)[SATA_PMP_GSCR_PROD_ID] >> 16) #define sata_pmp_gscr_rev(gscr) (((gscr)[SATA_PMP_GSCR_REV] >> 8) & 0xff) #define sata_pmp_gscr_ports(gscr) ((gscr)[SATA_PMP_GSCR_PORT_INFO] & 0xf) +#ifdef MY_ABC_HERE +#define sata_pmp_gscr_syno(gscr) ((gscr)[SATA_PMP_GSCR_SYNO]) +#define sata_pmp_gscr_logy(gscr) ((gscr)[SATA_PMP_GSCR_LOGY]) +#endif /* MY_ABC_HERE */ #endif /* __LINUX_ATA_H__ */ diff --git a/include/linux/bio.h b/include/linux/bio.h index 23b7a73cd757..008ab8196ab6 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2001 Jens Axboe @@ -59,6 +62,9 @@ static inline bool bio_has_data(struct bio *bio) bio->bi_iter.bi_size && bio_op(bio) != REQ_OP_DISCARD && bio_op(bio) != REQ_OP_SECURE_ERASE && +#ifdef MY_ABC_HERE + bio_op(bio) != REQ_OP_UNUSED_HINT && +#endif /* MY_ABC_HERE */ bio_op(bio) != REQ_OP_WRITE_ZEROES) return true; @@ -69,6 +75,9 @@ static inline bool bio_no_advance_iter(const struct bio *bio) { return bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_SECURE_ERASE || +#ifdef MY_ABC_HERE + bio_op(bio) == REQ_OP_UNUSED_HINT || +#endif /* MY_ABC_HERE */ bio_op(bio) == REQ_OP_WRITE_SAME || bio_op(bio) == REQ_OP_WRITE_ZEROES; } @@ -188,6 +197,9 @@ static inline unsigned bio_segments(struct bio *bio) switch (bio_op(bio)) { case REQ_OP_DISCARD: case REQ_OP_SECURE_ERASE: +#ifdef MY_ABC_HERE + case REQ_OP_UNUSED_HINT: +#endif /* MY_ABC_HERE */ case REQ_OP_WRITE_ZEROES: return 0; case REQ_OP_WRITE_SAME: diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index f8ea27423d1d..531b7f05a301 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -493,6 +493,18 @@ static inline int blk_mq_request_completed(struct request *rq) return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE; } +/* + * + * Set the state to complete when completing a request from inside ->queue_rq. + * This is used by drivers that want to ensure special complete actions that + * need access to the request are called on failure, e.g. by nvme for + * multipathing. + */ +static inline void blk_mq_set_request_complete(struct request *rq) +{ + WRITE_ONCE(rq->state, MQ_RQ_COMPLETE); +} + void blk_mq_start_request(struct request *rq); void blk_mq_end_request(struct request *rq, blk_status_t error); void __blk_mq_end_request(struct request *rq, blk_status_t error); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index d9b69bbde5cc..c1902d01677f 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Block data types and constants. Directly include this file only to @@ -207,7 +210,11 @@ struct bio { * top bits REQ_OP. Use * accessors. */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + unsigned int bi_flags; +#else /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ unsigned short bi_flags; /* status, etc and bvec pool number */ +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ unsigned short bi_ioprio; unsigned short bi_write_hint; blk_status_t bi_status; @@ -284,6 +291,42 @@ enum { * of this bio. */ BIO_CGROUP_ACCT, /* has been accounted to a cgroup */ BIO_TRACKED, /* set if bio goes through the rq_qos path */ +#ifdef MY_ABC_HERE + /* + * Tell lower layer to get the redundant version for this block. + */ + BIO_CORRECTION_RETRY, + /* + * Report to upper layer we have tried all dedundancies for this block. + */ + BIO_CORRECTION_ERR, + /* + * Tell lower layer that we give up the retry for this block. + */ + BIO_CORRECTION_ABORT, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /** + * Make the bio be rearranged behind the other bios which are submitted + * after it in current ->submit_bio. + * + * submit_bio_noacct() will sort bios by following order: + * 1. bios to lower level. + * 2. bios to same level. + * 3. bios with BIO_SYNO_DELAYED flags. + * 4. bios submitted before current->make_request_fn. + * + * Note that bios with BIO_SYNO_DELAYED flags will be sorted by + * last-in-first-out order. + */ + BIO_SYNO_DELAYED, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BIO_SYNO_AUTO_REMAP, /* record if auto-remap occurred */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + BIO_SYNO_FULL_STRIPE_MERGE, /* This bio should apply full stripe merge */ +#endif /* MY_ABC_HERE */ BIO_FLAG_LAST }; @@ -302,7 +345,11 @@ enum { * freed. */ #define BVEC_POOL_BITS (3) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define BVEC_POOL_OFFSET (32 - BVEC_POOL_BITS) +#else /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ #define BVEC_POOL_OFFSET (16 - BVEC_POOL_BITS) +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ #define BVEC_POOL_IDX(bio) ((bio)->bi_flags >> BVEC_POOL_OFFSET) #if (1<< BVEC_POOL_BITS) < (BVEC_POOL_NR+1) # error "BVEC_POOL_BITS is too small" @@ -367,6 +414,10 @@ enum req_opf { /* Driver private requests */ REQ_OP_DRV_IN = 34, REQ_OP_DRV_OUT = 35, +#ifdef MY_ABC_HERE + /* Unused hint to raid driver */ + REQ_OP_UNUSED_HINT = 128, +#endif /* MY_ABC_HERE */ REQ_OP_LAST, }; @@ -404,6 +455,11 @@ enum req_flag_bits { /* for driver use */ __REQ_DRV, __REQ_SWAP, /* swapping request. */ + +#ifdef MY_ABC_HERE + __REQ_SYNO_RBD, /* synorbd : this only for bio flag */ +#endif /* MY_ABC_HERE */ + __REQ_NR_BITS, /* stops here */ }; @@ -429,6 +485,10 @@ enum req_flag_bits { #define REQ_DRV (1ULL << __REQ_DRV) #define REQ_SWAP (1ULL << __REQ_SWAP) +#ifdef MY_ABC_HERE +#define REQ_SYNO_RBD (1ULL << __REQ_SYNO_RBD) +#endif /* MY_ABC_HERE */ + #define REQ_FAILFAST_MASK \ (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 542471b76f41..32174a9ca57e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_BLKDEV_H #define _LINUX_BLKDEV_H @@ -242,6 +245,11 @@ struct request { */ rq_end_io_fn *end_io; void *end_io_data; +#ifdef MY_ABC_HERE + unsigned int syno_seq; + u64 u64IssueTime; +#endif /* MY_ABC_HERE */ + }; static inline bool blk_op_is_scsi(unsigned int op) @@ -621,6 +629,9 @@ struct request_queue { #define QUEUE_FLAG_RQ_ALLOC_TIME 27 /* record rq->alloc_time_ns */ #define QUEUE_FLAG_HCTX_ACTIVE 28 /* at least one blk-mq hctx is active */ #define QUEUE_FLAG_NOWAIT 29 /* device supports NOWAIT */ +#ifdef MY_ABC_HERE +#define QUEUE_FLAG_UNUSED_HINT 31 /* supports unused hint */ +#endif /* MY_ABC_HERE */ #define QUEUE_FLAG_MQ_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_SAME_COMP) | \ @@ -667,6 +678,10 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q); #define blk_queue_fua(q) test_bit(QUEUE_FLAG_FUA, &(q)->queue_flags) #define blk_queue_registered(q) test_bit(QUEUE_FLAG_REGISTERED, &(q)->queue_flags) #define blk_queue_nowait(q) test_bit(QUEUE_FLAG_NOWAIT, &(q)->queue_flags) +#ifdef MY_ABC_HERE +#define blk_queue_unused_hint(q) \ + test_bit(QUEUE_FLAG_UNUSED_HINT, &(q)->queue_flags) +#endif /* MY_ABC_HERE */ extern void blk_set_pm_only(struct request_queue *q); extern void blk_clear_pm_only(struct request_queue *q); @@ -1340,6 +1355,10 @@ extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, int flags, struct bio **biop); +#ifdef MY_ABC_HERE +extern int blkdev_hint_unused(struct block_device *bdev, sector_t sector, + sector_t nr_sects, gfp_t gfp_mask); +#endif /* MY_ABC_HERE */ #define BLKDEV_ZERO_NOUNMAP (1 << 0) /* do not free blocks */ #define BLKDEV_ZERO_NOFALLBACK (1 << 1) /* don't write explicit zeroes */ @@ -1360,6 +1379,18 @@ static inline int sb_issue_discard(struct super_block *sb, sector_t block, SECTOR_SHIFT), gfp_mask, flags); } +#ifdef MY_ABC_HERE +static inline int sb_hint_unused(struct super_block *sb, sector_t block, + sector_t nr_blocks, gfp_t gfp_mask) +{ + return blkdev_hint_unused(sb->s_bdev, + block << (sb->s_blocksize_bits - + SECTOR_SHIFT), + nr_blocks << (sb->s_blocksize_bits - + SECTOR_SHIFT), + gfp_mask); +} +#endif /* MY_ABC_HERE */ static inline int sb_issue_zeroout(struct super_block *sb, sector_t block, sector_t nr_blocks, gfp_t gfp_mask) { diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 2739a6431b9e..3d6fb346dc3b 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -319,8 +319,8 @@ struct bpf_insn_aux_data { }; u64 map_key_state; /* constant (32 bit) key tracking for maps */ int ctx_field_size; /* the ctx field size for load insn, maybe 0 */ - int sanitize_stack_off; /* stack slot to be cleared */ u32 seen; /* this insn was processed by the verifier at env->pass_cnt */ + bool sanitize_stack_spill; /* subject to Spectre v4 sanitation */ bool zext_dst; /* this insn zero extends dst reg */ u8 alu_state; /* used in combination with alu_limit */ diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 455e9b9e2adf..983407b0e53e 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -288,6 +288,7 @@ enum { CEPH_SESSION_FLUSHMSG_ACK, CEPH_SESSION_FORCE_RO, CEPH_SESSION_REJECT, + CEPH_SESSION_REQUEST_FLUSH_MDLOG, }; extern const char *ceph_session_op_name(int op); @@ -352,6 +353,9 @@ extern const char *ceph_mds_op_name(int op); #define CEPH_SETATTR_ATIME 16 #define CEPH_SETATTR_SIZE 32 #define CEPH_SETATTR_CTIME 64 +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME +#define CEPH_SETATTR_BTIME 512 +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ /* * Ceph setxattr request flags. @@ -385,9 +389,15 @@ extern const char *ceph_mds_op_name(int op); #define CEPH_O_DIRECTORY 00200000 #define CEPH_O_NOFOLLOW 00400000 +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +#define CEPH_GETATTR_CASELESS (1<<0) +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ union ceph_mds_request_args { struct { __le32 mask; /* CEPH_CAP_* */ +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT + __le32 flags; +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ } __attribute__ ((packed)) getattr; struct { __le32 mode; @@ -397,6 +407,9 @@ union ceph_mds_request_args { struct ceph_timespec atime; __le64 size, old_size; /* old_size needed by truncate */ __le32 mask; /* CEPH_SETATTR_* */ +#ifdef CONFIG_SYNO_CEPH_CREATE_TIME + struct ceph_timespec btime; +#endif /* CONFIG_SYNO_CEPH_CREATE_TIME */ } __attribute__ ((packed)) setattr; struct { __le32 frag; /* which dir fragment */ @@ -424,6 +437,7 @@ union ceph_mds_request_args { } __attribute__ ((packed)) open; struct { __le32 flags; + __le32 osdmap_epoch; /* used for setting file/dir layouts */ } __attribute__ ((packed)) setxattr; struct { struct ceph_file_layout_legacy layout; @@ -445,11 +459,25 @@ union ceph_mds_request_args { } __attribute__ ((packed)) lookupino; } __attribute__ ((packed)); +union ceph_mds_request_args_ext { + union ceph_mds_request_args old; + struct { + __le32 mode; + __le32 uid; + __le32 gid; + struct ceph_timespec mtime; + struct ceph_timespec atime; + __le64 size, old_size; /* old_size needed by truncate */ + __le32 mask; /* CEPH_SETATTR_* */ + struct ceph_timespec btime; + } __attribute__ ((packed)) setattr_ext; +}; + #define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */ #define CEPH_MDS_FLAG_WANT_DENTRY 2 /* want dentry in reply */ #define CEPH_MDS_FLAG_ASYNC 4 /* request is asynchronous */ -struct ceph_mds_request_head { +struct ceph_mds_request_head_old { __le64 oldest_client_tid; __le32 mdsmap_epoch; /* on client */ __le32 flags; /* CEPH_MDS_FLAG_* */ @@ -462,6 +490,22 @@ struct ceph_mds_request_head { union ceph_mds_request_args args; } __attribute__ ((packed)); +#define CEPH_MDS_REQUEST_HEAD_VERSION 1 + +struct ceph_mds_request_head { + __le16 version; /* struct version */ + __le64 oldest_client_tid; + __le32 mdsmap_epoch; /* on client */ + __le32 flags; /* CEPH_MDS_FLAG_* */ + __u8 num_retry, num_fwd; /* count retry, fwd attempts */ + __le16 num_releases; /* # include cap/lease release records */ + __le32 op; /* mds op code */ + __le32 caller_uid, caller_gid; + __le64 ino; /* use this ino for openc, mkdir, mknod, + etc. (if replaying) */ + union ceph_mds_request_args_ext args; +} __attribute__ ((packed)); + /* cap/lease release record */ struct ceph_mds_request_release { __le64 ino, cap_id; /* ino and unique cap id */ diff --git a/include/linux/ceph/ceph_hash.h b/include/linux/ceph/ceph_hash.h index fda474c7a5d6..9af6cf84f30d 100644 --- a/include/linux/ceph/ceph_hash.h +++ b/include/linux/ceph/ceph_hash.h @@ -2,6 +2,10 @@ #ifndef FS_CEPH_HASH_H #define FS_CEPH_HASH_H +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +#include +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ + #define CEPH_STR_HASH_LINUX 0x1 /* linux dcache hash */ #define CEPH_STR_HASH_RJENKINS 0x2 /* robert jenkins' */ @@ -9,6 +13,9 @@ extern unsigned ceph_str_hash_linux(const char *s, unsigned len); extern unsigned ceph_str_hash_rjenkins(const char *s, unsigned len); extern unsigned ceph_str_hash(int type, const char *s, unsigned len); +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +extern unsigned int ceph_str_upper_hash(int type, const char *s, unsigned int len); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ extern const char *ceph_str_hash_name(int type); #endif diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index c8645f0b797d..e405bd9742e5 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -104,6 +104,7 @@ enum { CEPH_MOUNT_UNMOUNTING, CEPH_MOUNT_UNMOUNTED, CEPH_MOUNT_SHUTDOWN, + CEPH_MOUNT_RECOVER, }; static inline unsigned long ceph_timeout_jiffies(unsigned long timeout) @@ -145,6 +146,9 @@ struct ceph_client { struct dentry *debugfs_monmap; struct dentry *debugfs_osdmap; struct dentry *debugfs_options; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + struct dentry *debugfs_pool_pg; +#endif #endif }; diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h index cad9acfbc320..b4d746e5f75b 100644 --- a/include/linux/ceph/osdmap.h +++ b/include/linux/ceph/osdmap.h @@ -56,6 +56,9 @@ struct ceph_pg_pool_info { s64 write_tier; /* wins for read+write ops */ u64 flags; /* CEPH_POOL_FLAG_* */ char *name; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + u16 placement_seed; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ bool was_full; /* for handle_one_map() */ }; @@ -336,4 +339,11 @@ extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id); extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name); u64 ceph_pg_pool_flags(struct ceph_osdmap *map, u64 id); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +extern int do_crush(struct ceph_osdmap *map, int ruleno, int x, + int *result, int result_max, + const __u32 *weight, int weight_max, + s64 choose_args_index + , int pool_ps); +#endif #endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index b8fe0c23cfff..475d0a3ce059 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -180,6 +180,8 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, (typeof(ptr)) (__ptr + (off)); }) #endif +#define absolute_pointer(val) RELOC_HIDE((void *)(val), 0) + #ifndef OPTIMIZER_HIDE_VAR /* Make the optimizer believe the variable can be manipulated arbitrarily. */ #define OPTIMIZER_HIDE_VAR(var) \ diff --git a/include/linux/console.h b/include/linux/console.h index 4b1e26c4cb42..2f9b13539075 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * linux/include/linux/console.h * @@ -151,6 +154,11 @@ struct console { short index; int cflag; void *data; +#ifdef MY_ABC_HERE + void __iomem * pcimapaddress; + unsigned long pcimapsize; + void (*deinit)(void); +#endif /* MY_ABC_HERE */ struct console *next; }; diff --git a/include/linux/cpu.h b/include/linux/cpu.h index d6428aaf67e7..402094a0f8a4 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * include/linux/cpu.h - generic cpu definition @@ -226,6 +229,9 @@ static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; #endif extern bool cpu_mitigations_off(void); +#ifdef MY_ABC_HERE +extern void cpu_mitigations_auto_set(void); +#endif /* MY_ABC_HERE */ extern bool cpu_mitigations_auto_nosmt(void); #endif /* _LINUX_CPU_H_ */ diff --git a/include/linux/cred.h b/include/linux/cred.h index ad160e5fe5c6..18639c069263 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -144,7 +144,6 @@ struct cred { #endif struct user_struct *user; /* real user ID subscription */ struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ - struct ucounts *ucounts; struct group_info *group_info; /* supplementary groups for euid/fsgid */ /* RCU deletion */ union { @@ -171,7 +170,6 @@ extern int set_security_override_from_ctx(struct cred *, const char *); extern int set_create_files_as(struct cred *, struct inode *); extern int cred_fscmp(const struct cred *, const struct cred *); extern void __init cred_init(void); -extern int set_cred_ucounts(struct cred *); /* * check for validity of credentials diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h index 30dba392b730..7184ca9dfe8c 100644 --- a/include/linux/crush/crush.h +++ b/include/linux/crush/crush.h @@ -32,6 +32,9 @@ #define CRUSH_MAX_DEVICE_WEIGHT (100u * 0x10000u) #define CRUSH_MAX_BUCKET_WEIGHT (65535u * 0x10000u) +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +#define CRUSH_ITEM_LEAF_FAIL 0x7ffffffd /* leaf fail result (internal use only) */ +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ #define CRUSH_ITEM_UNDEF 0x7ffffffe /* undefined result (internal use only) */ #define CRUSH_ITEM_NONE 0x7fffffff /* no result */ @@ -63,6 +66,15 @@ enum { CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES = 11, CRUSH_RULE_SET_CHOOSELEAF_VARY_R = 12, CRUSH_RULE_SET_CHOOSELEAF_STABLE = 13 +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + CRUSH_RULE_SET_SYNO_CHOOSE_PRIMARY = 31, + CRUSH_RULE_SYNO_ENUM = 32, + CRUSH_RULE_SYNO_CHOOSE_FIRSTN = 33, + CRUSH_RULE_SYNO_CHOOSE_INDEP = 34, + CRUSH_RULE_SYNO_CHOOSELEAF_FIRSTN = 35, + CRUSH_RULE_SYNO_CHOOSELEAF_INDEP = 36, +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ }; /* diff --git a/include/linux/crush/mapper.h b/include/linux/crush/mapper.h index f9b99232f5a1..d0ffe8468cf8 100644 --- a/include/linux/crush/mapper.h +++ b/include/linux/crush/mapper.h @@ -15,7 +15,11 @@ extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, i int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, const __u32 *weight, int weight_max, - void *cwin, const struct crush_choose_arg *choose_args); + void *cwin, const struct crush_choose_arg *choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , int pool_ps +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ); /* * Returns the exact amount of workspace that will need to be used diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 6f95c3300cbb..e69bec57d9b6 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LINUX_DCACHE_H #define __LINUX_DCACHE_H @@ -138,6 +141,10 @@ struct dentry_operations { int (*d_hash)(const struct dentry *, struct qstr *); int (*d_compare)(const struct dentry *, unsigned int, const char *, const struct qstr *); +#ifdef MY_ABC_HERE + int (*d_compare_case)(const struct dentry *, unsigned int, const char *, + const struct qstr *, int caseless); +#endif /* MY_ABC_HERE */ int (*d_delete)(const struct dentry *); int (*d_init)(struct dentry *); void (*d_release)(struct dentry *); @@ -220,8 +227,18 @@ struct dentry_operations { #define DCACHE_DENTRY_CURSOR 0x20000000 #define DCACHE_NORCU 0x40000000 /* No RCU delay for freeing */ +#ifdef MY_ABC_HERE +#define DCACHE_OP_COMPARE_CASE 0x80000000 +#endif /* MY_ABC_HERE */ + extern seqlock_t rename_lock; +#ifdef MY_ABC_HERE +extern inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount); +extern inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount); +extern int dentry_replace_name(struct dentry *dentry, const char *new_name, u32 name_len); +#endif /* MY_ABC_HERE */ + /* * These are the low-level FS interfaces to the dcache.. */ @@ -237,8 +254,16 @@ extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op /* allocate/de-allocate */ extern struct dentry * d_alloc(struct dentry *, const struct qstr *); extern struct dentry * d_alloc_anon(struct super_block *); +#ifdef MY_ABC_HERE +extern struct dentry * __d_alloc_parallel(struct dentry *, const struct qstr *, + wait_queue_head_t *, + const int caseless); +#define d_alloc_parallel_case(d, n, wq, caseless) __d_alloc_parallel(d, n, wq, caseless) +#define d_alloc_parallel(d, n, wq) __d_alloc_parallel(d, n, wq, 0) +#else /* MY_ABC_HERE */ extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *, wait_queue_head_t *); +#endif /* MY_ABC_HERE */ extern struct dentry * d_splice_alias(struct inode *, struct dentry *); extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); extern struct dentry * d_exact_alias(struct dentry *, struct inode *); @@ -279,9 +304,19 @@ extern struct dentry *d_ancestor(struct dentry *, struct dentry *); /* appendix may either be NULL or be used for transname suffixes */ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *); extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *); -extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *); + +extern struct dentry *__d_lookup(const struct dentry *, const struct qstr * +#ifdef MY_ABC_HERE + , int caseless +#endif /* MY_ABC_HERE */ + ); + extern struct dentry *__d_lookup_rcu(const struct dentry *parent, - const struct qstr *name, unsigned *seq); + const struct qstr *name, unsigned *seq +#ifdef MY_ABC_HERE + , const int caseless +#endif /* MY_ABC_HERE */ + ); static inline unsigned d_count(const struct dentry *dentry) { diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 50cc070cb1f7..3f9d782a7f84 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2001 Sistina Software (UK) Limited. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. @@ -96,6 +99,10 @@ typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti, struct block_device ** typedef int (*dm_report_zones_fn) (struct dm_target *ti, struct dm_report_zones_args *args, unsigned int nr_zones); +#ifdef MY_ABC_HERE +typedef int (*dm_extra_ioctl_fn) (struct dm_target *ti, + unsigned int cmd, unsigned long arg); +#endif /* MY_ABC_HERE */ /* * These iteration functions are typically used to check (and combine) @@ -142,6 +149,9 @@ typedef size_t (*dm_dax_copy_iter_fn)(struct dm_target *ti, pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i); typedef int (*dm_dax_zero_page_range_fn)(struct dm_target *ti, pgoff_t pgoff, size_t nr_pages); +#ifdef MY_ABC_HERE +typedef int (*dm_support_noclone_fn) (struct dm_target *ti); +#endif /* MY_ABC_HERE */ #define PAGE_SECTORS (PAGE_SIZE / 512) void dm_error(const char *message); @@ -186,6 +196,9 @@ struct target_type { dm_resume_fn resume; dm_status_fn status; dm_message_fn message; +#ifdef MY_ABC_HERE + dm_extra_ioctl_fn extra_ioctl; +#endif /* MY_ABC_HERE*/ dm_prepare_ioctl_fn prepare_ioctl; #ifdef CONFIG_BLK_DEV_ZONED dm_report_zones_fn report_zones; @@ -197,6 +210,10 @@ struct target_type { dm_dax_copy_iter_fn dax_copy_from_iter; dm_dax_copy_iter_fn dax_copy_to_iter; dm_dax_zero_page_range_fn dax_zero_page_range; +#ifdef MY_ABC_HERE + dm_support_noclone_fn support_noclone; + dm_map_fn noclone_map; +#endif /* MY_ABC_HERE */ /* For internal device-mapper use. */ struct list_head list; @@ -303,6 +320,14 @@ struct dm_target { */ unsigned num_secure_erase_bios; +#ifdef MY_ABC_HERE + /* + * The number of unused hint bios that will be submitted to the target. + * The bio number can be accessed with dm_bio_get_target_bio_nr. + */ + unsigned num_unused_hint_bios; +#endif /* MY_ABC_HERE */ + /* * The number of WRITE SAME bios that will be submitted to the target. * The bio number can be accessed with dm_bio_get_target_bio_nr. @@ -636,5 +661,8 @@ static inline unsigned long to_bytes(sector_t n) { return (n << SECTOR_SHIFT); } +#ifdef MY_ABC_HERE +#define SYNO_DM_IO_RESERVERD_IO_MASK 0xf +#endif /* MY_ABC_HERE */ #endif /* _LINUX_DEVICE_MAPPER_H */ diff --git a/include/linux/dm-io.h b/include/linux/dm-io.h index a52c6580cc9a..ce3adeb13db2 100644 --- a/include/linux/dm-io.h +++ b/include/linux/dm-io.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (C) 2003 Sistina Software * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved. @@ -78,6 +81,10 @@ void dm_io_client_destroy(struct dm_io_client *client); * Each bit in the optional 'sync_error_bits' bitset indicates whether an * error occurred doing io to the corresponding region. */ +#ifdef MY_ABC_HERE +int syno_dm_io(struct dm_io_request *io_req, unsigned num_regions, + struct dm_io_region *region, unsigned long *sync_error_bits, unsigned long bi_flags); +#endif /* MY_ABC_HERE */ int dm_io(struct dm_io_request *io_req, unsigned num_regions, struct dm_io_region *region, unsigned long *sync_error_bits); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 957b398d30e5..f981c95f9ed9 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * Header file for dma buffer sharing framework. @@ -265,6 +268,34 @@ struct dma_buf_ops { */ int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); +#if defined(MY_DEF_HERE) + /** + * @map: + * + * Maps a page from the buffer into kernel address space. The page is + * specified by offset into the buffer in PAGE_SIZE units. + * + * This callback is optional. + * + * Returns: + * + * Virtual address pointer where requested page can be accessed. NULL + * on error or when this function is unimplemented by the exporter. + */ + void *(*map)(struct dma_buf *, unsigned long); + + /** + * @unmap: + * + * Unmaps a page from the buffer. Page offset and address pointer should + * be the same as the one passed to and returned by matching call to map. + * + * This callback is optional. + */ + void (*unmap)(struct dma_buf *, unsigned long, void *); + + +#endif /* MY_DEF_HERE */ void *(*vmap)(struct dma_buf *); void (*vunmap)(struct dma_buf *, void *vaddr); }; @@ -500,6 +531,11 @@ int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, int dma_buf_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction dir); +#if defined(MY_DEF_HERE) +void *dma_buf_kmap(struct dma_buf *, unsigned long); +void dma_buf_kunmap(struct dma_buf *, unsigned long, void *); + +#endif /* MY_DEF_HERE */ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, unsigned long); void *dma_buf_vmap(struct dma_buf *); diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 2e5debc0373c..99209f50915f 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -127,7 +127,7 @@ static inline bool is_multicast_ether_addr(const u8 *addr) #endif } -static inline bool is_multicast_ether_addr_64bits(const u8 addr[6+2]) +static inline bool is_multicast_ether_addr_64bits(const u8 *addr) { #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 #ifdef __BIG_ENDIAN @@ -352,8 +352,7 @@ static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) * Please note that alignment of addr1 & addr2 are only guaranteed to be 16 bits. */ -static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], - const u8 addr2[6+2]) +static inline bool ether_addr_equal_64bits(const u8 *addr1, const u8 *addr2) { #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); diff --git a/include/linux/falloc.h b/include/linux/falloc.h index f3f0b97b1675..cc4e321dcc56 100644 --- a/include/linux/falloc.h +++ b/include/linux/falloc.h @@ -25,12 +25,22 @@ struct space_resv { #define FS_IOC_UNRESVSP64 _IOW('X', 43, struct space_resv) #define FS_IOC_ZERO_RANGE _IOW('X', 57, struct space_resv) +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN +#define FALLOC_FL_SUPPORTED_MASK (FALLOC_FL_KEEP_SIZE | \ + FALLOC_FL_PUNCH_HOLE | \ + FALLOC_FL_COLLAPSE_RANGE | \ + FALLOC_FL_ZERO_RANGE | \ + FALLOC_FL_INSERT_RANGE | \ + FALLOC_FL_UNSHARE_RANGE | \ + FALLOC_FL_MARK_WRITTEN) +#else /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ #define FALLOC_FL_SUPPORTED_MASK (FALLOC_FL_KEEP_SIZE | \ FALLOC_FL_PUNCH_HOLE | \ FALLOC_FL_COLLAPSE_RANGE | \ FALLOC_FL_ZERO_RANGE | \ FALLOC_FL_INSERT_RANGE | \ FALLOC_FL_UNSHARE_RANGE) +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ /* on ia32 l_start is on a 32-bit boundary */ #if defined(CONFIG_X86_64) diff --git a/include/linux/fiemap.h b/include/linux/fiemap.h index 4e624c466583..c93b17040115 100644 --- a/include/linux/fiemap.h +++ b/include/linux/fiemap.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_FIEMAP_H #define _LINUX_FIEMAP_H 1 @@ -11,6 +14,10 @@ struct fiemap_extent_info { unsigned int fi_extents_max; /* Size of fiemap_extent array */ struct fiemap_extent __user *fi_extents_start; /* Start of fiemap_extent array */ +#ifdef MY_ABC_HERE + struct fiemap_extent *kernel_fi_extents_start; /* Start of + fiemap_extent array for kernel */ +#endif /* MY_ABC_HERE */ }; int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo, @@ -22,4 +29,8 @@ int generic_block_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len, get_block_t *get_block); +#ifdef MY_ABC_HERE +int vfs_fiemap(struct file *filp, struct fiemap *fiemap); +#endif /* MY_ABC_HERE */ + #endif /* _LINUX_FIEMAP_H 1 */ diff --git a/include/linux/filter.h b/include/linux/filter.h index e2ffa02f9067..822b701c803d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -72,6 +72,11 @@ struct ctl_table_header; /* unused opcode to mark call to interpreter with arguments */ #define BPF_CALL_ARGS 0xe0 +/* unused opcode to mark speculation barrier for mitigating + * Speculative Store Bypass + */ +#define BPF_NOSPEC 0xc0 + /* As per nm, we expose JITed images as text (code) section for * kallsyms. That way, tools like perf can find it to match * addresses. @@ -372,6 +377,16 @@ static inline bool insn_is_zext(const struct bpf_insn *insn) .off = 0, \ .imm = 0 }) +/* Speculation barrier */ + +#define BPF_ST_NOSPEC() \ + ((struct bpf_insn) { \ + .code = BPF_ST | BPF_NOSPEC, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) + /* Internal classic blocks for direct assignment */ #define __BPF_STMT(CODE, K) \ diff --git a/include/linux/fs.h b/include/linux/fs.h index 8bde32cf9711..637522356b71 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_FS_H #define _LINUX_FS_H @@ -43,6 +46,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + struct backing_dev_info; struct bdi_writeback; struct bio; @@ -68,6 +75,9 @@ struct fsverity_info; struct fsverity_operations; struct fs_context; struct fs_parameter_spec; +#ifdef MY_ABC_HERE +struct socket; +#endif /* MY_ABC_HERE */ extern void __init inode_init(void); extern void __init inode_init_early(void); @@ -92,6 +102,33 @@ typedef int (get_block_t)(struct inode *inode, sector_t iblock, typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, ssize_t bytes, void *private); +#ifdef MY_ABC_HERE +/* + Note!!!!! It should be consistent with SYNO_ACL_MAY_XXXXX in +*/ +#define MAY_EXEC 0x00000001 +#define MAY_WRITE 0x00000002 +#define MAY_READ 0x00000004 +#define MAY_APPEND 0x00000008 +#define MAY_ACCESS 0x00000010 +#define MAY_OPEN 0x00000020 + +#define MAY_READ_EXT_ATTR 0x00000040 +#define MAY_READ_PERMISSION 0x00000080 +#define MAY_READ_ATTR 0x00000100 +#define MAY_WRITE_ATTR 0x00000200 +#define MAY_WRITE_EXT_ATTR 0x00000400 +#define MAY_WRITE_PERMISSION 0x00000800 +#define MAY_DEL 0x00001000 +#define MAY_DEL_CHILD 0x00002000 +#define MAY_GET_OWNER_SHIP 0x00004000 + +#define MAY_CHDIR 0x00010000 +#define MAY_NOT_BLOCK 0x00020000 /* called from RCU mode, don't block */ + +#define MASK_RDONLY_CHECK (MAY_WRITE|MAY_APPEND|MAY_WRITE_ATTR|MAY_WRITE_EXT_ATTR|MAY_WRITE_PERMISSION|MAY_DEL|MAY_DEL_CHILD|MAY_GET_OWNER_SHIP) + +#else /* MY_ABC_HERE */ #define MAY_EXEC 0x00000001 #define MAY_WRITE 0x00000002 #define MAY_READ 0x00000004 @@ -101,6 +138,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define MAY_CHDIR 0x00000040 /* called from RCU mode, don't block */ #define MAY_NOT_BLOCK 0x00000080 +#endif /* MY_ABC_HERE */ /* * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond @@ -280,6 +318,11 @@ enum positive_aop_returns { #define AOP_FLAG_NOFS 0x0002 /* used by filesystem to direct * helper code (eg buffer layer) * to clear GFP_FS from alloc */ +#ifdef MY_ABC_HERE +/* Number of recvfile flags follow LK4.4, but it's not obligatory. */ +#define AOP_FLAG_RECVFILE 0x0008 +#define AOP_FLAG_RECVFILE_ECRYPTFS_NO_TRUNCATE 0x0020 +#endif /* MY_ABC_HERE */ /* * oh the beauties of C type declarations. @@ -388,6 +431,11 @@ struct address_space_operations { int (*write_end)(struct file *, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata); +#ifdef MY_ABC_HERE + int (*aggregate_write_end)(struct file *, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page **page, unsigned page_num); +#endif /* MY_ABC_HERE */ /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ sector_t (*bmap)(struct address_space *, sector_t); @@ -594,11 +642,24 @@ is_uncached_acl(struct posix_acl *acl) return (long)acl & 1; } +#ifdef MY_ABC_HERE +struct syno_acl; + +static inline bool +is_uncached_syno_acl(struct syno_acl *acl) +{ + return (long)acl & 1; +} +#endif /* MY_ABC_HERE */ + #define IOP_FASTPERM 0x0001 #define IOP_LOOKUP 0x0002 #define IOP_NOFOLLOW 0x0004 #define IOP_XATTR 0x0008 #define IOP_DEFAULT_READLINK 0x0010 +#ifdef MY_ABC_HERE +#define IOP_ECRYPTFS_LOWER_INIT 0x0040 +#endif /* MY_ABC_HERE */ struct fsnotify_mark_connector; @@ -614,6 +675,9 @@ struct inode { kgid_t i_gid; unsigned int i_flags; +#ifdef MY_ABC_HERE + struct syno_acl *i_syno_acl; +#endif /* MY_ABC_HERE */ #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; @@ -717,6 +781,16 @@ struct inode { struct fsverity_info *i_verity_info; #endif +#ifdef MY_ABC_HERE + u32 i_archive_bit; + struct mutex i_archive_bit_mutex; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + u32 i_archive_version; + struct mutex i_archive_version_mutex; +#endif /* MY_ABC_HERE */ + void *i_private; /* fs or device private pointer */ } __randomize_layout; @@ -952,6 +1026,15 @@ struct file { struct address_space *f_mapping; errseq_t f_wb_err; errseq_t f_sb_err; /* for syncfs */ +#ifdef MY_ABC_HERE + struct list_head open_list; + char comm[TASK_COMM_LEN]; + pid_t pid; +#ifdef CONFIG_SMP + int f_sb_list_cpu; +#endif /* CONFIG_SMP */ +#endif /* MY_ABC_HERE */ + } __randomize_layout __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ @@ -1332,6 +1415,9 @@ extern void fasync_free(struct fasync_struct *); /* can be called from interrupts */ extern void kill_fasync(struct fasync_struct **, int, int); +#ifdef MY_ABC_HERE +extern int setfl(int fd, struct file *filp, unsigned long arg); +#endif /* MY_ABC_HERE */ extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); extern int f_setown(struct file *filp, unsigned long arg, int force); extern void f_delown(struct file *filp); @@ -1349,11 +1435,17 @@ extern int send_sigurg(struct fown_struct *fown); #define SB_SYNCHRONOUS 16 /* Writes are synced at once */ #define SB_MANDLOCK 64 /* Allow mandatory locks on an FS */ #define SB_DIRSYNC 128 /* Directory modifications are synchronous */ +#ifdef MY_ABC_HERE +#define SB_ROOTPRJQUOTA 512 +#endif /* MY_ABC_HERE */ #define SB_NOATIME 1024 /* Do not update access times. */ #define SB_NODIRATIME 2048 /* Do not update directory access times */ #define SB_SILENT 32768 #define SB_POSIXACL (1<<16) /* VFS does not apply the umask */ #define SB_INLINECRYPT (1<<17) /* Use blk-crypto for encrypted files */ +#ifdef MY_ABC_HERE +#define SB_SYNOACL (1<<20) /* Synology WinACL */ +#endif /* MY_ABC_HERE */ #define SB_KERNMOUNT (1<<22) /* this is a kern_mount call */ #define SB_I_VERSION (1<<23) /* Update inode I_version field */ #define SB_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ @@ -1547,6 +1639,29 @@ struct super_block { spinlock_t s_inode_wblist_lock; struct list_head s_inodes_wb; /* writeback inodes */ +#ifdef MY_ABC_HERE + /* + * relatime_period can be changed by mount option "relatime_period=%u". + * Because most file systems do not accept unrecognized mount options, + * this option is parsed by underlying file systems instead of vfs layer. + */ + long relatime_period; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct rw_semaphore s_archive_version_rwsem; + u32 s_archive_version; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct ratelimit_state rs; +#ifdef CONFIG_SMP + struct list_head __percpu *s_files; +#else /* CONFIG_SMP */ + struct list_head s_files; +#endif /* CONFIG_SMP */ +#endif /* MY_ABC_HERE */ + } __randomize_layout; /* Helper functions so that in most cases filesystems will @@ -1763,6 +1878,18 @@ extern void inode_init_owner(struct inode *inode, const struct inode *dir, umode_t mode); extern bool may_open_dev(const struct path *path); +#ifdef MY_ABC_HERE +extern int vfs_quota_query(struct file *file, u64 *used, u64 *reserved, u64 *limit); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * VFS space_usage helper definitions. + */ +extern int vfs_syno_space_usage(struct file *file, struct syno_space_usage_info *info); +#endif /* MY_ABC_HERE */ + + /* * This is the "filldir" function type, used by readdir() to let * the kernel specify what kind of dirent layout it wants to have. @@ -1807,6 +1934,9 @@ struct dir_context { */ #define REMAP_FILE_DEDUP (1 << 0) #define REMAP_FILE_CAN_SHORTEN (1 << 1) +#ifdef MY_ABC_HERE +#define REMAP_FILE_SKIP_CHECK_COMPR_DIR (1 << 8) +#endif /* MY_ABC_HERE */ /* * These flags signal that the caller is ok with altering various aspects of @@ -1815,9 +1945,18 @@ struct dir_context { * Flags in this category exist to preserve the quirky behavior of the hoisted * btrfs clone/dedupe ioctls. */ +#ifdef MY_ABC_HERE +#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN \ + | REMAP_FILE_SKIP_CHECK_COMPR_DIR \ + ) +#else /* MY_ABC_HERE */ #define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN) +#endif /* MY_ABC_HERE */ struct iov_iter; +#ifdef MY_ABC_HERE +typedef int (*encrypt_page_cb_t)(struct page *enc_page, void *crypt_stat_ptr, struct page *page); +#endif /* MY_ABC_HERE */ struct file_operations { struct module *owner; @@ -1843,6 +1982,9 @@ struct file_operations { ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); +#ifdef MY_ABC_HERE + int (*setfl)(struct file *, unsigned long); +#endif /* MY_ABC_HERE */ int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); @@ -1853,12 +1995,29 @@ struct file_operations { #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif +#ifdef MY_ABC_HERE + ssize_t (*syno_recvfile)(int fd, struct file *file, struct socket *sock, + loff_t pos, size_t count, size_t * rbytes, size_t * wbytes); +#ifdef MY_ABC_HERE + int (*ecryptfs_zero_copy)(struct file *file, loff_t pos, int num_page, + struct page **pages, encrypt_page_cb_t encrypt_cb, void *crypt_stat); +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t len, unsigned int remap_flags); int (*fadvise)(struct file *, loff_t, loff_t, int); +#ifdef MY_ABC_HERE + long (*non_blocking_punch_hole)(struct file *file, loff_t offset, loff_t len); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*quota_query) (struct file *file, u64 *used, u64 *reserved, u64 *limit); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_space_usage) (struct file *file, struct syno_space_usage_info *info); +#endif /* MY_ABC_HERE */ } __randomize_layout; struct inode_operations { @@ -1889,6 +2048,54 @@ struct inode_operations { umode_t create_mode); int (*tmpfile) (struct inode *, struct dentry *, umode_t); int (*set_acl)(struct inode *, struct posix_acl *, int); +#ifdef MY_ABC_HERE + int (*syno_locker_mode_get)(struct inode *, enum locker_mode *); + int (*syno_locker_state_get)(struct inode *, enum locker_state *); + int (*syno_locker_state_set)(struct inode *, enum locker_state); + int (*syno_locker_period_end_set)(struct inode *, struct timespec64 *); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_getattr)(struct dentry *, struct kstat *, unsigned int syno_flags); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_get_archive_bit)(struct dentry *, unsigned int *, int); + int (*syno_set_archive_bit)(struct dentry *, unsigned int); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_get_archive_version)(struct dentry *, u32 *); + int (*syno_set_archive_version)(struct dentry *, u32); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_get_crtime)(struct inode *, struct timespec64 *); + int (*syno_set_crtime)(struct inode *, struct timespec64 *); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct syno_acl * (*syno_get_acl)(struct inode *); + int (*syno_set_acl)(struct inode *, struct syno_acl *); + int (*syno_acl_xattr_get)(struct dentry *, int, void *, size_t); + int (*syno_permission)(struct dentry *, int); + int (*syno_exec_permission)(struct dentry *); + int (*syno_archive_bit_change_ok)(struct dentry *, unsigned int cmd, int tag, int mask); + int (*syno_setattr_prepare)(struct dentry *, struct iattr *); + int (*syno_setattr_post)(struct dentry *, struct iattr *); + int (*syno_may_delete)(struct dentry *, struct inode *); + int (*syno_may_access)(struct dentry *, int); + void (*syno_acl_to_mode)(struct dentry *, struct kstat *); + int (*syno_acl_init)(struct dentry *, struct inode *); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* fsdev support */ + int (*fsdev_activate)(struct inode *inode, struct block_device **fs_bdev); + void (*fsdev_deactivate)(struct inode *inode); + int (*fsdev_mapping)(struct inode *inode, u64 start, u64 end, u64 *dev_start, u64 *dev_end); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + int (*syno_rbd_meta_file_activate)(struct inode *); + int (*syno_rbd_meta_file_deactivate)(struct inode *); + int (*syno_rbd_meta_file_mapping)(struct inode *, + struct syno_rbd_meta_ioctl_args *args); +#endif /* MY_ABC_HERE */ } ____cacheline_aligned; static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio, @@ -1930,6 +2137,10 @@ extern int vfs_dedupe_file_range(struct file *file, extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, struct file *dst_file, loff_t dst_pos, loff_t len, unsigned int remap_flags); +#ifdef MY_ABC_HERE +extern ssize_t vfs_recvfile(int fd, struct file *file, struct socket *sock, + loff_t pos, size_t count, size_t *received, size_t *written); +#endif /* MY_ABC_HERE */ struct super_operations { @@ -1965,6 +2176,22 @@ struct super_operations { struct shrink_control *); long (*free_cached_objects)(struct super_block *, struct shrink_control *); +#ifdef MY_ABC_HERE + int (*syno_get_sb_archive_version)(struct super_block *sb, u32 *version); + int (*syno_set_sb_archive_version)(struct super_block *sb, u32 version); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_decrypt_filename)(char **plaintext_name, + size_t *plaintext_name_size, + struct super_block *sb, + const char *name, + size_t name_size); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*syno_rbd_set_first_mapping_table_offset)( + struct super_block *, u64 offset); + int (*syno_rbd_meta_file_cleanup_all)(struct inode *); +#endif /* MY_ABC_HERE */ }; /* @@ -1992,6 +2219,10 @@ struct super_operations { #define S_CASEFOLD (1 << 15) /* Casefolded file */ #define S_VERITY (1 << 16) /* Verity file (using fs/verity/) */ +#ifdef MY_ABC_HERE +#define S_ARCHIVE_VERSION_CACHED (1 << 31) /* Mark i_archive_version is ready to use */ +#endif /* MY_ABC_HERE */ + /* * Note that nosuid etc flags are inode-specific: setting some file-system * flags just means all the inodes inherit those flags by default. It might be @@ -2018,8 +2249,14 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags #define IS_I_VERSION(inode) __IS_FLG(inode, SB_I_VERSION) #define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA) +#ifdef MY_ABC_HERE +#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND || syno_op_locker_is_appendable(inode)) +#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE || syno_op_locker_is_immutable(inode)) +#define IS_EXPIRED(inode) syno_op_locker_is_expired(inode) +#else #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) +#endif /* MY_ABC_HERE */ #define IS_POSIXACL(inode) __IS_FLG(inode, SB_POSIXACL) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) @@ -2037,6 +2274,21 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ (inode)->i_rdev == WHITEOUT_DEV) +#ifdef MY_ABC_HERE +#define IS_ARCHIVE_VERSION_CACHED(inode) ((inode)->i_flags & S_ARCHIVE_VERSION_CACHED) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * Usually, we hack trim function to send unused hints. + * This flag is used to tell if we want to send hint or trim + */ +enum trim_act { + TRIM_SEND_TRIM, + TRIM_SEND_HINT +}; +#endif /* MY_ABC_HERE */ + static inline bool HAS_UNMAPPED_ID(struct inode *inode) { return !uid_valid(inode->i_uid) || !gid_valid(inode->i_gid); @@ -2252,6 +2504,12 @@ struct file_system_type { struct lock_class_key i_lock_key; struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; +#ifdef MY_ABC_HERE + struct lock_class_key i_archive_bit_mutex_key; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + struct lock_class_key i_archive_version_mutex_key; +#endif /* MY_ABC_HERE */ }; #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME) @@ -2328,6 +2586,9 @@ extern int current_umask(void); extern void ihold(struct inode * inode); extern void iput(struct inode *); extern int generic_update_time(struct inode *, struct timespec64 *, int); +#ifdef MY_ABC_HERE +extern int update_time(struct inode *, struct timespec64 *, int); +#endif /* MY_ABC_HERE */ /* /sys/fs */ extern struct kobject *fs_kobj; @@ -2564,6 +2825,9 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) } void emergency_thaw_all(void); +#ifdef MY_ABC_HERE +extern int __sync_filesystem(struct super_block *, int); +#endif /* MY_ABC_HERE */ extern int sync_filesystem(struct super_block *); extern const struct file_operations def_blk_fops; extern const struct file_operations def_chr_fops; @@ -2964,6 +3228,14 @@ extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); extern int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count); extern int generic_file_rw_checks(struct file *file_in, struct file *file_out); + +#ifdef MY_ABC_HERE +/* The max size of receive file request is "128KB" */ +#define MAX_RECVFILE_BUF (128 * 1024) +#define MAX_PAGES_PER_RECVFILE (MAX_RECVFILE_BUF / PAGE_SIZE) +extern int do_recvfile(struct file *, struct socket *, loff_t , size_t , size_t * , size_t *); +#endif /* MY_ABC_HERE */ + extern ssize_t generic_file_buffered_read(struct kiocb *iocb, struct iov_iter *to, ssize_t already_read); extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); @@ -3394,6 +3666,15 @@ static inline void inode_has_no_xattr(struct inode *inode) inode->i_flags |= S_NOSEC; } +#ifdef MY_ABC_HERE +#define SYNO_SMB_PSTRING_LEN 1024 +#define UTF16_UPCASE_TABLE_SIZE 0x10000 /* 64k chars */ +#define UNICODE_UTF16_BUFSIZE 4096 /* should be safe enough for namei */ +#define UNICODE_UTF8_BUFSIZE 8192 +int syno_utf8_strcmp(const u_int8_t *utf8str1,const u_int8_t *utf8str2,int len_utf8_str1, int len_utf8_str2, u_int16_t *upcasetable); +int syno_utf8_toupper(u_int8_t *to,const u_int8_t *from, int maxlen, int clenfrom, u_int16_t *upcasetable); +#endif /* MY_ABC_HERE */ + static inline bool is_root_inode(struct inode *inode) { return inode == inode->i_sb->s_root->d_inode; @@ -3475,4 +3756,11 @@ static inline int inode_drain_writes(struct inode *inode) return filemap_write_and_wait(inode->i_mapping); } +#ifdef MY_ABC_HERE +void inode_sync_complete(struct inode *inode); +#endif /* MY_ABC_HERE */ + +/* Syno filesystem helpers */ +#include + #endif /* _LINUX_FS_H */ diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h index 5b44b0195a28..456d2ca5f733 100644 --- a/include/linux/fs_context.h +++ b/include/linux/fs_context.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* Filesystem superblock creation and reconfiguration context. * @@ -110,6 +113,14 @@ struct fs_context { bool need_free:1; /* Need to call ops->free() */ bool global:1; /* Goes into &init_user_ns */ bool oldapi:1; /* Coming from mount(2) */ +#ifdef MY_ABC_HERE + /* + * relatime_period can be changed by mount option "relatime_period=%u". + * Because most file systems do not accept unrecognized mount options, + * this option is parsed by underlying file systems instead of vfs layer. + */ + long relatime_period; +#endif /* MY_ABC_HERE */ }; struct fs_context_operations { diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index f8acddcf54fb..70041f882838 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_FS_NOTIFY_H #define _LINUX_FS_NOTIFY_H @@ -16,6 +19,64 @@ #include #include #include +#ifdef MY_ABC_HERE +#include + +extern int SYNONotify(struct dentry *dentry, __u32 mask); +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +static inline void syno_archive_bit_modify(struct inode *inode, int set_smb_archive) +{ + struct dentry *dentry; +#ifdef MY_ABC_HERE + u32 new_archive_bit; + u32 old_archive_bit; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u32 sb_archive_ver; + int err; +#endif /* MY_ABC_HERE */ + + if (NULL == inode) + return; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || + S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) + return; + if (!strcmp(inode->i_sb->s_type->name, "c2fs")) + return; + dentry = d_find_alias(inode); + if (!dentry) + return; + +#ifdef MY_ABC_HERE + mutex_lock(&inode->i_archive_bit_mutex); + if (syno_op_get_archive_bit(dentry, &old_archive_bit)) + goto unlock; + + if (set_smb_archive) + new_archive_bit = old_archive_bit | S2_SMB_ARCHIVE | ALL_IARCHIVE; + else + new_archive_bit = old_archive_bit | ALL_IARCHIVE; + + if (new_archive_bit != old_archive_bit) + syno_op_set_archive_bit_nolock(dentry, new_archive_bit); + +unlock: + mutex_unlock(&inode->i_archive_bit_mutex); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + err = syno_op_get_sb_archive_version(inode->i_sb, &sb_archive_ver); + if (err) + goto out; + err = syno_op_set_inode_archive_version(dentry, sb_archive_ver + 1); +out: +#endif /* MY_ABC_HERE */ + if (dentry) + dput(dentry); +} +#endif /* MY_ABC_HERE || MY_ABC_HERE*/ /* * Notify this @dir inode about a change in a child directory entry. @@ -123,13 +184,26 @@ static inline void fsnotify_link_count(struct inode *inode) fsnotify_inode(inode, FS_ATTRIB); } +#ifdef MY_ABC_HERE +struct synotify_rename_path { + char *old_full_path; + char *new_full_path; + struct vfsmount *vfs_mnt; + struct synotify_rename_path *next; +}; +#endif /* MY_ABC_HERE */ + /* * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir */ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, const struct qstr *old_name, int isdir, struct inode *target, - struct dentry *moved) + struct dentry *moved +#ifdef MY_ABC_HERE + , struct synotify_rename_path *path_list, bool is_exchange +#endif /* MY_ABC_HERE */ + ) { struct inode *source = moved->d_inode; u32 fs_cookie = fsnotify_get_cookie(); @@ -145,12 +219,55 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, new_dir_mask |= FS_ISDIR; } +#ifdef MY_ABC_HERE + /* handle syno notify: + * 1. we should check if file/dir moved within same mnt point. If does, we simply + * notify a rename event. + * 2. if this rename does not occur within same mnt point, then we have to send MOVE_FROM + * and MOVE_TO to mnt points respectively. + */ + + // prepare source notify data + while(path_list) { + struct synotify_rename_path *tmp = path_list; + struct path tmp_path; + + memset (&tmp_path, 0, sizeof(struct path)); + + tmp_path.mnt = tmp->vfs_mnt; + + if (is_exchange) { + __SYNONotify(old_dir_mask, &tmp_path, FSNOTIFY_EVENT_SYNO_MOVE, tmp->new_full_path, fs_cookie); + __SYNONotify(new_dir_mask, &tmp_path, FSNOTIFY_EVENT_SYNO_MOVE, tmp->old_full_path, fs_cookie); + } else { + __SYNONotify(old_dir_mask, &tmp_path, FSNOTIFY_EVENT_SYNO_MOVE, tmp->old_full_path, fs_cookie); + __SYNONotify(new_dir_mask, &tmp_path, FSNOTIFY_EVENT_SYNO_MOVE, tmp->new_full_path, fs_cookie); + } + path_list = path_list->next; + } +#endif /* MY_ABC_HERE */ + fsnotify_name(old_dir, old_dir_mask, source, old_name, fs_cookie); fsnotify_name(new_dir, new_dir_mask, source, new_name, fs_cookie); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + syno_archive_bit_modify(old_dir, 0); + if (old_dir != new_dir) + syno_archive_bit_modify(new_dir, 0); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + if (target) fsnotify_link_count(target); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + if (target) + syno_archive_bit_modify(target, 0); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + fsnotify_inode(source, FS_MOVE_SELF); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + syno_archive_bit_modify(source, 1); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE); } @@ -186,6 +303,14 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) { audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + syno_archive_bit_modify(dentry->d_inode, 0); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + SYNONotify(dentry, FS_CREATE); +#endif /* MY_ABC_HERE */ + fsnotify_dirent(inode, dentry, FS_CREATE); } @@ -200,6 +325,10 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, fsnotify_link_count(inode); audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); +#ifdef MY_ABC_HERE + SYNONotify(new_dentry, FS_CREATE); +#endif /* MY_ABC_HERE */ + fsnotify_name(dir, FS_CREATE, inode, &new_dentry->d_name, 0); } @@ -213,6 +342,10 @@ static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) /* Expected to be called before d_delete() */ WARN_ON_ONCE(d_is_negative(dentry)); +#ifdef MY_ABC_HERE + SYNONotify(dentry, FS_DELETE); +#endif /* MY_ABC_HERE */ + fsnotify_dirent(dir, dentry, FS_DELETE); } @@ -223,6 +356,14 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) { audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + syno_archive_bit_modify(dentry->d_inode, 0); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + SYNONotify(dentry, FS_CREATE | FS_ISDIR); +#endif /* MY_ABC_HERE */ + fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR); } @@ -236,6 +377,10 @@ static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry) /* Expected to be called before d_delete() */ WARN_ON_ONCE(d_is_negative(dentry)); +#ifdef MY_ABC_HERE + SYNONotify(dentry, FS_DELETE | FS_ISDIR); +#endif /* MY_ABC_HERE */ + fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR); } @@ -252,6 +397,10 @@ static inline void fsnotify_access(struct file *file) */ static inline void fsnotify_modify(struct file *file) { +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + syno_archive_bit_modify(file_inode(file), 1); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + fsnotify_file(file, FS_MODIFY); } @@ -284,6 +433,21 @@ static inline void fsnotify_close(struct file *file) */ static inline void fsnotify_xattr(struct dentry *dentry) { +#ifdef MY_ABC_HERE + __u32 mask = FS_ATTRIB; + + if (S_ISDIR(dentry->d_inode->i_mode)) + mask |= FS_ISDIR; +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + syno_archive_bit_modify(dentry->d_inode, 1); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + SYNONotify(dentry, mask); +#endif /* MY_ABC_HERE */ + fsnotify_dentry(dentry, FS_ATTRIB); } @@ -301,6 +465,10 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) mask |= FS_ATTRIB; if (ia_valid & ATTR_SIZE) mask |= FS_MODIFY; +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + if (ia_valid & ATTR_SIZE) + syno_archive_bit_modify(dentry->d_inode, 1); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ /* both times implies a utime(s) call */ if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) @@ -315,6 +483,18 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) if (mask) fsnotify_dentry(dentry, mask); + +#ifdef MY_ABC_HERE + if (mask) { + if (S_ISDIR(dentry->d_inode->i_mode)) + mask |= FS_ISDIR; + SYNONotify(dentry, mask); + } +#endif /* MY_ABC_HERE */ } +#ifdef MY_ABC_HERE +extern void free_rename_path_list(struct synotify_rename_path * rename_path_list); +extern struct synotify_rename_path * get_rename_path_list(struct dentry *old_dentry, struct dentry *new_dentry); +#endif /* MY_ABC_HERE */ #endif /* _LINUX_FS_NOTIFY_H */ diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index a2e42d3cd87c..101baf88c189 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Filesystem access notification for Linux @@ -158,6 +161,9 @@ struct fsnotify_ops { void (*free_event)(struct fsnotify_event *event); /* called on final put+free to free memory */ void (*free_mark)(struct fsnotify_mark *mark); +#ifdef MY_ABC_HERE + int (*fetch_path)(struct fsnotify_event *event, struct fsnotify_group *group); +#endif /* MY_ABC_HERE */ }; /* @@ -191,6 +197,9 @@ struct fsnotify_group { /* needed to send notification to userspace */ spinlock_t notification_lock; /* protect the notification_list */ +#ifdef MY_ABC_HERE + struct mutex notification_mutex; /* protect per group path_buf */ +#endif /* MY_ABC_HERE */ struct list_head notification_list; /* list of event_holder this group needs to send to userspace */ wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */ unsigned int q_len; /* events on the queue */ @@ -232,6 +241,15 @@ struct fsnotify_group { struct ucounts *ucounts; } inotify_data; #endif +#ifdef MY_ABC_HERE + struct synotify_group_private_data { + struct user_struct *user; + unsigned int max_watchers; + char *synotify_full_path_buf; + char *synotify_d_path_buf; + int event_version; + } synotify_data; +#endif /* MY_ABC_HERE */ #ifdef CONFIG_FANOTIFY struct fanotify_group_private_data { /* allows a group to block waiting for a userspace response */ @@ -251,6 +269,9 @@ enum fsnotify_data_type { FSNOTIFY_EVENT_NONE, FSNOTIFY_EVENT_PATH, FSNOTIFY_EVENT_INODE, +#ifdef MY_ABC_HERE + FSNOTIFY_EVENT_SYNO_MOVE, +#endif /* MY_ABC_HERE */ }; static inline struct inode *fsnotify_data_inode(const void *data, int data_type) @@ -281,6 +302,9 @@ enum fsnotify_obj_type { FSNOTIFY_OBJ_TYPE_PARENT, FSNOTIFY_OBJ_TYPE_VFSMOUNT, FSNOTIFY_OBJ_TYPE_SB, +#ifdef MY_ABC_HERE + FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT, +#endif /* MY_ABC_HERE */ FSNOTIFY_OBJ_TYPE_COUNT, FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT }; @@ -289,6 +313,9 @@ enum fsnotify_obj_type { #define FSNOTIFY_OBJ_TYPE_PARENT_FL (1U << FSNOTIFY_OBJ_TYPE_PARENT) #define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT) #define FSNOTIFY_OBJ_TYPE_SB_FL (1U << FSNOTIFY_OBJ_TYPE_SB) +#ifdef MY_ABC_HERE +#define FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT) +#endif /* MY_ABC_HERE */ #define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1) static inline bool fsnotify_valid_obj_type(unsigned int type) @@ -334,6 +361,9 @@ FSNOTIFY_ITER_FUNCS(inode, INODE) FSNOTIFY_ITER_FUNCS(parent, PARENT) FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT) FSNOTIFY_ITER_FUNCS(sb, SB) +#ifdef MY_ABC_HERE +FSNOTIFY_ITER_FUNCS(syno_vfsmount, SYNO_VFSMOUNT) +#endif /* MY_ABC_HERE */ #define fsnotify_foreach_obj_type(type) \ for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++) @@ -421,6 +451,10 @@ extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); extern void fsnotify_sb_delete(struct super_block *sb); extern u32 fsnotify_get_cookie(void); +#ifdef MY_ABC_HERE +extern void __SYNONotify(__u32 mask, void *data, int data_type, + const char *file_path, u32 cookie); +#endif /* MY_ABC_HERE */ static inline __u32 fsnotify_parent_needed_mask(__u32 mask) { diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 03da3f603d30..36d6e5c15214 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_GENHD_H #define _LINUX_GENHD_H @@ -73,6 +76,9 @@ struct hd_struct { int make_it_fail; #endif struct rcu_work rcu_work; +#ifdef MY_ABC_HERE + unsigned int syno_auto_remap; +#endif /* MY_ABC_HERE */ }; /** @@ -164,6 +170,27 @@ struct blk_integrity { unsigned char tag_size; }; +#ifdef MY_ABC_HERE +struct syno_gendisk_operations { + bool (*is_device_disappear)(struct gendisk *); + int (*get_device_index)(struct gendisk *); +#ifdef MY_ABC_HERE + int (*autoremap_stackable_dev_target_set)(struct block_device*, unsigned char); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int (*check_device_status)(struct gendisk *, unsigned int flags); +#endif /* MY_ABC_HERE */ +}; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +enum syno_disk_seq_stat { + SYNO_DISK_SEQ_STAT_NEAR_SEQ = 0, + SYNO_DISK_SEQ_STAT_SEQ = 1, + SYNO_DISK_SEQ_STAT_END = 2, /* Your new added entry SHOULD NOT PASS THE END! */ +}; +#define SYNO_BLOCK_RESPONSE_BUCKETS_END 4 +#endif /* MY_ABC_HERE */ + struct gendisk { /* major, first_minor and minors are input parameters only, * don't use directly. Use disk_devt() and disk_max_parts(). @@ -208,6 +235,22 @@ struct gendisk { int node_id; struct badblocks *bb; struct lockdep_map lockdep_map; +#ifdef MY_ABC_HERE + unsigned char syno_auto_remap; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + const struct syno_gendisk_operations *syno_ops; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned char block_latency_uuid[16]; + u64 u64CplCmdCnt[2]; + u64 u64RespTimeSum[2]; + u64 u64WaitTime[2]; + u64 u64RespTimeBuckets[2][SYNO_BLOCK_RESPONSE_BUCKETS_END][32]; + sector_t end_sector; + unsigned long seq_ios[SYNO_DISK_SEQ_STAT_END]; +#endif /* MY_ABC_HERE */ + }; #if IS_REACHABLE(CONFIG_CDROM) @@ -408,5 +451,10 @@ static inline dev_t blk_lookup_devt(const char *name, int partno) return devt; } #endif /* CONFIG_BLOCK */ +#ifdef MY_ABC_HERE +#define SYNO_DEVICE_STATUS_IS_RBD_ENABLED ((1U << 0)) + +bool IsSynoRbdDeviceEnabled(struct block_device *bdev); +#endif /* MY_ABC_HERE */ #endif /* _LINUX_GENHD_H */ diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 5bd3cac4df9c..4b610cba9764 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef LINUX_IOMAP_H #define LINUX_IOMAP_H 1 @@ -20,6 +23,9 @@ struct kiocb; struct page; struct vm_area_struct; struct vm_fault; +#ifdef MY_ABC_HERE +struct syno_rbd_meta_ioctl_args; +#endif /* MY_ABC_HERE */ /* * Types of block ranges for iomap mappings: @@ -185,6 +191,10 @@ loff_t iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops); sector_t iomap_bmap(struct address_space *mapping, sector_t bno, const struct iomap_ops *ops); +#ifdef MY_ABC_HERE +int iomap_rbd_meta_map(struct inode *inode, struct syno_rbd_meta_ioctl_args *rbd_meta, + u64 start, u64 len, const struct iomap_ops *ops); +#endif /* MY_ABC_HERE */ /* * Structure for writeback I/O completions. diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 2f05e9128201..3b9be78a1bbd 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_KERNEL_H #define _LINUX_KERNEL_H @@ -834,6 +837,18 @@ ftrace_vprintk(const char *fmt, va_list ap) static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } #endif /* CONFIG_TRACING */ +#if defined(MY_ABC_HERE) +/* + * Display an IP address in readable format. + */ +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] +#define NIPQUAD_FMT "%u.%u.%u.%u" +#endif /* MY_ABC_HERE */ + /* This counts to 12. Any more, it will return 13th argument. */ #define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _n, X...) _n #define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) diff --git a/include/linux/leds-atmega1608-seg7.h b/include/linux/leds-atmega1608-seg7.h new file mode 100644 index 000000000000..336128fe3c41 --- /dev/null +++ b/include/linux/leds-atmega1608-seg7.h @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2021 Synology Inc. + */ + +#ifndef __LEDS_ATMEGA1608_SEG7_H__ +#define __LEDS_ATMEGA1608_SEG7_H__ +enum atmega1608_seg7_led_mask { + ATMEGA1608_LED_UNMASK, + ATMEGA1608_LED_MASKED, +}; + +enum atmega1608_seg7_led_mode { + ATMEGA1608_LED_OFF, + ATMEGA1608_LED_ON, + ATMEGA1608_LED_DIM0, + ATMEGA1608_LED_DIM1, +}; + +enum atmega1608_seg7_led_channel { + ATMEGA1608_LED0, + ATMEGA1608_LED1, + ATMEGA1608_LED2, + ATMEGA1608_LED3, + ATMEGA1608_LED4, + ATMEGA1608_LED5, + ATMEGA1608_LED6, + ATMEGA1608_LED7, + ATMEGA1608_LED8, + ATMEGA1608_LED9, + ATMEGA1608_LED10, + ATMEGA1608_LED11, + ATMEGA1608_LED12, + ATMEGA1608_LED13, + ATMEGA1608_LED14, + ATMEGA1608_LED15, + ATMEGA1608_LED16, + ATMEGA1608_LED17, + ATMEGA1608_LED18, + ATMEGA1608_LED19, + ATMEGA1608_LED20, + ATMEGA1608_LED21, + ATMEGA1608_LED22, + ATMEGA1608_LED23, +}; + +#endif \ No newline at end of file diff --git a/include/linux/leds-atmega1608.h b/include/linux/leds-atmega1608.h new file mode 100644 index 000000000000..310e03d64c3c --- /dev/null +++ b/include/linux/leds-atmega1608.h @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2021 Synology Inc. + */ + +#ifndef __LEDS_ATMEGA1608_H__ +#define __LEDS_ATMEGA1608_H__ +enum atmega1608_led_mask { + ATMEGA1608_LED_UNMASK, + ATMEGA1608_LED_MASKED, +}; + +enum atmega1608_led_mode { + ATMEGA1608_LED_OFF, + ATMEGA1608_LED_ON, + ATMEGA1608_LED_DIM0, + ATMEGA1608_LED_DIM1, +}; + +enum atmega1608_led_channel { + ATMEGA1608_LED0, + ATMEGA1608_LED1, + ATMEGA1608_LED2, + ATMEGA1608_LED3, + ATMEGA1608_LED4, + ATMEGA1608_LED5, + ATMEGA1608_LED6, + ATMEGA1608_LED7, + ATMEGA1608_LED8, + ATMEGA1608_LED9, + ATMEGA1608_LED10, + ATMEGA1608_LED11, + ATMEGA1608_LED12, + ATMEGA1608_LED13, + ATMEGA1608_LED14, + ATMEGA1608_LED15, + ATMEGA1608_LED16, + ATMEGA1608_LED17, + ATMEGA1608_LED18, + ATMEGA1608_LED19, + ATMEGA1608_LED20, + ATMEGA1608_LED21, + ATMEGA1608_LED22, + ATMEGA1608_LED23, +}; + +struct atmega1608_led_node { + char *name; + enum atmega1608_led_mode mode; + u8 prescale; + enum atmega1608_led_channel channel; + int num_channels; + char *default_trigger; +}; + +struct atmega1608_platform_data { + struct atmega1608_led_node *node; + int num_nodes; +}; + +#define ATMEGA1608_MASK 0x01 + +#endif diff --git a/include/linux/leds-lp3943.h b/include/linux/leds-lp3943.h new file mode 100644 index 000000000000..d0c48746dcef --- /dev/null +++ b/include/linux/leds-lp3943.h @@ -0,0 +1,74 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * 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 __LEDS_LP3943_H__ +#define __LEDS_LP3943_H__ + +enum lp3943_led_mode { + LP3943_LED_OFF, + LP3943_LED_ON, + LP3943_LED_DIM0, + LP3943_LED_DIM1, +}; + +enum lp3943_led_channel { + LP3943_LED0, + LP3943_LED1, + LP3943_LED2, + LP3943_LED3, + LP3943_LED4, + LP3943_LED5, + LP3943_LED6, + LP3943_LED7, + LP3943_LED8, + LP3943_LED9, + LP3943_LED10, + LP3943_LED11, + LP3943_LED12, + LP3943_LED13, + LP3943_LED14, + LP3943_LED15, +}; + +/* + * struct lp3943_led_node + * @name : led node name which is used for led device name internally + * @mode : led ctrl mode - on/dim0/dim1 (Addr 06h ~ 09h) + * @prescale : frequency prescaler setting (Addr 02h, 04h) + * only valid when lp3943_led_mode is DIM0 or DIM1 + * @channel : led channel(s) which is(are) controlled simultaneously + * @num_channels : numbers of led channels + */ +struct lp3943_led_node { + char *name; + enum lp3943_led_mode mode; + u8 prescale; + enum lp3943_led_channel *channel; + int num_channels; +#ifdef MY_DEF_HERE + char *default_trigger; +#endif /* MY_DEF_HERE */ +}; + +/* + * struct lp3943_platform_data + * @node : LED nodes description + * @num_nodes : numbers of led nodes + */ +struct lp3943_platform_data { + struct lp3943_led_node *node; + int num_nodes; +}; + +#endif diff --git a/include/linux/leds.h b/include/linux/leds.h index 6a8d6409c993..f9302e3e7295 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * Driver model for leds and led triggers @@ -210,6 +213,10 @@ extern void led_put(struct led_classdev *led_cdev); struct led_classdev *__must_check devm_of_led_get(struct device *dev, int index); +#ifdef MY_DEF_HERE +extern struct led_classdev *of_leddev_get(struct device_node *led_node); +#endif /* MY_DEF_HERE */ + /** * led_blink_set - set blinking with software fallback * @led_cdev: the LED to start blinking @@ -481,6 +488,12 @@ static inline void ledtrig_flash_ctrl(bool on) {} static inline void ledtrig_torch_ctrl(bool on) {} #endif +#ifdef MY_DEF_HERE +void ledtrig_syno_disk_activity_on(struct led_classdev *led_cdev); +#else /* MY_DEF_HERE */ +static inline void ledtrig_syno_disk_activity_on(struct led_classdev *led_cdev) {} +#endif /* MY_DEF_HERE */ + /* * Generic LED platform data for describing LED names and default triggers. */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 5f550eb27f81..ed7fd474e5b4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright 2003-2005 Red Hat, Inc. All rights reserved. @@ -23,6 +26,13 @@ #include #include #include +#if defined(MY_ABC_HERE) +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ /* * Define if arch has non-standard setup. This is a _PCI_ standard @@ -58,6 +68,19 @@ #define VPRINTK(fmt, args...) #endif /* ATA_DEBUG */ +#ifdef MY_DEF_HERE +/* WD suggest 30s */ +#define ISSUEREADTIMEOUT (30UL*HZ) +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +extern int gSynoAtaDebug; +#define DBGMESG(x...) \ + if (0 < gSynoAtaDebug) printk(x) +#else /* MY_ABC_HERE */ +#define DBGMESG(x...) +#endif /* MY_ABC_HERE */ + #define ata_print_version_once(dev, version) \ ({ \ static bool __print_once; \ @@ -68,6 +91,21 @@ } \ }) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +typedef enum { + PORT_LOST_UNKNOWN = 0, + PORT_LOST_RETRY_FAILED = 1, + PORT_LOST_RETRY_FAILED_PRESENT = 2, + PORT_LOST_DISABLED = 3, + PORT_LOST_DISABLED_PRESENT = 4, + PORT_LOST_LINK_DOWN_PRESENT = 5 +} SYNO_DISK_PORT_LOST_TYPE; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SYNO_PM_VIRTUAL_SCSI_CHANNEL 15 +#endif /* MY_ABC_HERE */ + /* NEW: debug levels */ #define HAVE_LIBATA_MSG 1 @@ -150,6 +188,9 @@ enum { ATA_DFLAG_NCQ_SEND_RECV = (1 << 19), /* device supports NCQ SEND and RECV */ ATA_DFLAG_NCQ_PRIO = (1 << 20), /* device supports NCQ priority */ ATA_DFLAG_NCQ_PRIO_ENABLE = (1 << 21), /* Priority cmds sent to dev */ +#ifdef MY_ABC_HERE + ATA_DFLAG_NO_WCACHE = (1 << 23), /* device doesn't support write cache */ +#endif /* MY_ABC_HERE */ ATA_DFLAG_INIT_MASK = (1 << 24) - 1, ATA_DFLAG_DETACH = (1 << 24), @@ -161,6 +202,12 @@ enum { ATA_DFLAG_D_SENSE = (1 << 29), /* Descriptor sense requested */ ATA_DFLAG_ZAC = (1 << 30), /* ZAC device */ +#ifdef MY_ABC_HERE + ATA_SYNO_DFLAG_PMP_DETACH = (1 << 0), /* force EUnit detach */ + ATA_SYNO_DFLAG_DISABLE = (1 << 1), /* force device disable */ + ATA_SYNO_DFLAG_DETACH = (1 << 2), /* force device detach */ +#endif /* MY_ABC_HERE */ + ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ ATA_DEV_ATA_UNSUP = 2, /* ATA device (unsupported) */ @@ -240,6 +287,38 @@ enum { ATA_PFLAG_PIO32 = (1 << 20), /* 32bit PIO */ ATA_PFLAG_PIO32CHANGE = (1 << 21), /* 32bit PIO can be turned on/off */ ATA_PFLAG_EXTERNAL = (1 << 22), /* eSATA/external port */ +#ifdef MY_ABC_HERE + ATA_PFLAG_PMP_DISCONNECT = (1 << 23), + ATA_PFLAG_PMP_CONNECT = (1 << 24), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ATA_PFLAG_PMP_PMCTL = (1 << 25), +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + ATA_PFLAG_SYNO_IRQ_OFF = (1 << 26), + ATA_PFLAG_SYNO_IRQOFF_LOCK_FOR_EH = (1 << 27), + ATA_PFLAG_SYNO_IRQOFF_PWROFF_DONE = (1 << 28), + ATA_PFLAG_SYNO_DS_WAKING = (1 << 29), + ATA_PFLAG_SYNO_DS_PWROFF = (1 << 30), +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ATA_PFLAG_SYNO_BOOT_PROBE = (1 << 31), + /* TODO: PFLAG are exhausted, shouldn't add any more. + * If OSS add any more PFLAG, we should refine SYNO PFLAG. + * ex. ATA_PFLAG_SYNO_DS_WAKING, ATA_PFLAG_SYNO_DS_PWROFF and + * may removed, it's added for some workaround*/ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + ATA_SYNO_FLAG_JM585_READ_LOG = (1 << 0), + ATA_SYNO_FLAG_JM585_UNC = (1 << 1), + ATA_SYNO_FLAG_JM585_OTHER_ERR = (1 << 2), +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + /* if after reset, still have the following fail, we must try force detect */ + ATA_SYNO_FLAG_SRST_FAIL = (1 << 0), /* still have SRST fail */ + ATA_SYNO_FLAG_COMRESET_FAIL = (1 << 1), /* still COMRESET fail */ + ATA_SYNO_FLAG_REVALID_FAIL = (1 << 2), /* still revalid fail */ +#endif /* MY_ABC_HERE */ /* struct ata_queued_cmd flags */ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ @@ -350,7 +429,13 @@ enum { ATA_EH_HARDRESET = (1 << 2), /* meaningful only in ->prereset */ ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_ENABLE_LINK = (1 << 3), +#ifdef MY_ABC_HERE + ATA_EH_SYNO_PWON = (1 << 4), +#endif /* MY_ABC_HERE */ ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */ +#ifdef MY_ABC_HERE + ATA_EH_WCACHE_DISABLE = (1 << 6), /* unload heads and stop I/O */ +#endif /* MY_ABC_HERE */ ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK, ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET | @@ -382,7 +467,13 @@ enum { /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, ATA_EH_DEV_TRIES = 3, +#ifdef MY_ABC_HERE + ATA_EH_PMP_TRIES = 3, + SYNO_PMP_PWR_TRIES = 10, + SYNO_PMP_GPIO_TRIES = 4, +#else /* MY_ABC_HERE */ ATA_EH_PMP_TRIES = 5, +#endif /* MY_ABC_HERE */ ATA_EH_PMP_LINK_TRIES = 3, SATA_PMP_RW_TIMEOUT = 3000, /* PMP read/write timeout */ @@ -422,6 +513,9 @@ enum { ATA_HORKAGE_NOTRIM = (1 << 24), /* don't use TRIM */ ATA_HORKAGE_MAX_SEC_1024 = (1 << 25), /* Limit max sects to 1024 */ ATA_HORKAGE_MAX_TRIM_128M = (1 << 26), /* Limit max trim size to 128M */ +#ifdef MY_ABC_HERE + ATA_HORKAGE_NOWCACHE = (1 << 27), /* skip Wcache */ +#endif /* MY_ABC_HERE */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ @@ -464,6 +558,12 @@ enum { ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER | ATA_ACPI_FILTER_LOCK | ATA_ACPI_FILTER_DIPM, + +#ifdef MY_ABC_HERE + SYNO_STATUS_DEEP_SLEEP_FAILED = 1 << 1, + SYNO_STATUS_GPIO_CTRL = 1 << 2, + SYNO_STATUS_EUNIT_MASTER_REFIND = (1 << 7), /* find master retries */ +#endif /* MY_ABC_HERE */ }; enum ata_xfer_mask { @@ -572,6 +672,9 @@ struct ata_taskfile { u32 auxiliary; /* auxiliary field */ /* from SATA 3.1 and */ /* ATA-8 ACS-3 */ +#ifdef MY_ABC_HERE + bool blTler; +#endif /* MY_ABC_HERE */ }; #ifdef CONFIG_ATA_SFF @@ -609,11 +712,39 @@ struct ata_host { struct mutex eh_mutex; struct task_struct *eh_owner; +#ifdef MY_ABC_HERE + unsigned short vendor; + unsigned short device; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u8 uJMB585LedStat; +#endif /* MY_ABC_HERE */ struct ata_port *simplex_claimed; /* channel owning the DMA */ struct ata_port *ports[]; }; +#ifdef MY_ABC_HERE +#ifdef MY_ABC_HERE +#define SYNO_READ_SEQ_STAT 1 +#define SYNO_NON_READ_SEQ_STAT 2 +enum syno_seq_state_flag { + SYNO_ANY_NONE_SEQ = (1 << 0), + SYNO_ALL_SEQ_READ = (1 << SYNO_READ_SEQ_STAT) +}; +#endif /* MY_ABC_HERE */ + +struct syno_qc_stat { + u8 u8QcType; + u8 u8LbaZone; + u8 u8SeqState; + u8 u8SeqTag; + u32 u32SkipBytes; + u64 u64IssueTime; + u64 u64StartLbaByte; +}; +#endif /* MY_ABC_HERE */ + struct ata_queued_cmd { struct ata_port *ap; struct ata_device *dev; @@ -651,6 +782,9 @@ struct ata_queued_cmd { void *private_data; void *lldd_task; +#ifdef MY_ABC_HERE + struct syno_qc_stat qc_stat; +#endif /* MY_ABC_HERE */ }; struct ata_port_stats { @@ -675,6 +809,13 @@ struct ata_device { unsigned int devno; /* 0 or 1 */ unsigned int horkage; /* List of broken features */ unsigned long flags; /* ATA_DFLAG_xxx */ +#ifdef MY_ABC_HERE + unsigned long ulSflags; /* ATA_SYNO_DFLAG_xxx */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int iResetPwrCount; /* the count of disk power reset */ +#endif /* MY_ABC_HERE */ + struct scsi_device *sdev; /* attached SCSI device */ void *private_data; #ifdef CONFIG_ATA_ACPI @@ -684,6 +825,18 @@ struct ata_device { #ifdef CONFIG_SATA_ZPODD void *zpodd; #endif + +#ifdef MY_DEF_HERE + /* be careful the ATA_DEVICE_CLEAR_OFFSET when porting this */ + unsigned long ulLastCmd; + unsigned long ulSpinupState; + int iCheckPwr; + + /* bit definitions */ + #define CHKPOWER_FIRST_CMD 0x0 + #define CHKPOWER_FIRST_WAIT 0x1 +#endif /* MY_DEF_HERE */ + struct device tdev; /* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */ u64 n_sectors; /* size of device, if ATA */ @@ -694,6 +847,15 @@ struct ata_device { u8 pio_mode; u8 dma_mode; u8 xfer_mode; + +#ifdef MY_ABC_HERE + u8 is_ssd; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u8 u8LbaZoneShiftBit; + u64 u64SeqValidSkipBytes; +#endif /* MY_ABC_HERE */ + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ unsigned int multi_count; /* sectors count for @@ -753,6 +915,10 @@ struct ata_eh_info { char desc[ATA_EH_DESC_LEN]; int desc_len; +#ifdef MY_ABC_HERE + unsigned int uiJM585DubiosIFSProtoFlag; +#endif /* MY_ABC_HERE */ + }; struct ata_eh_context { @@ -780,6 +946,67 @@ struct ata_acpi_gtm { u32 flags; } __packed; +#ifdef MY_ABC_HERE +#define SYNO_LATENCY_TYPE_COUNT 3 +#define SYNO_LATENCY_BUCKETS_END 4 + +typedef enum { + SYNO_LATENCY_OTHERS = 0x1, + SYNO_LATENCY_READ = 0x2, + SYNO_LATENCY_WRITE = 0x4, +} SYNO_LATENCY_TYPE; + +#ifdef MY_ABC_HERE +#define SYNO_SEQ_SAMPLE_LBA_ZONE_MASK 0xF +#define SYNO_SEQ_SAMPLE_LBA_ZONE (SYNO_SEQ_SAMPLE_LBA_ZONE_MASK + 1) +struct syno_seq_stat { + u64 u64TotalSampleBytes[SYNO_SEQ_SAMPLE_LBA_ZONE]; + u64 u64TotalSampleTime[SYNO_SEQ_SAMPLE_LBA_ZONE]; + u64 u64TotalSampleSkipBytes[SYNO_SEQ_SAMPLE_LBA_ZONE]; +}; +#endif /* MY_ABC_HERE */ + +struct syno_ata_latency { +#ifdef MY_ABC_HERE + u8 u8SeqTag; + u8 u8CplCmdSeqState; + u8 u8CplCmdSeqLbaZone; + u8 u8NonSeqActiveIo; +#endif /* MY_ABC_HERE */ + + u16 u16TotalCplCmdCnt; + u16 u16CplCmdCnt[SYNO_LATENCY_TYPE_COUNT]; +#ifdef MY_ABC_HERE + u32 u32CplCmdBytes[SYNO_LATENCY_TYPE_COUNT]; + u32 u32CplCmdSkipBytes[SYNO_LATENCY_TYPE_COUNT]; + + u64 u64SeqBytes; + u64 u64SeqLastLbaByte; +#endif /* MY_ABC_HERE */ + + u64 u64FirstCmdStartTime; + u64 u64LastIntrTime; + u64 u64BatchIssue; + u64 u64BatchComplete; + + u64 u64LastReportTime; + u64 u64LastBatchTimeOffset; + u64 u64TimeBuckets[SYNO_LATENCY_TYPE_COUNT][SYNO_LATENCY_BUCKETS_END][32]; + u64 u64RespTimeBuckets[SYNO_LATENCY_TYPE_COUNT][SYNO_LATENCY_BUCKETS_END][32]; +}; + +struct syno_latency_stat { + unsigned char uuid[16]; + u64 u64TotalCount[SYNO_LATENCY_TYPE_COUNT]; + u64 u64TotalTime[SYNO_LATENCY_TYPE_COUNT]; + u64 u64TotalRespTime[SYNO_LATENCY_TYPE_COUNT]; + u64 u64TotalBytes[SYNO_LATENCY_TYPE_COUNT]; + + u64 u64TotalBatchCount; + u64 u64TotalBatchTime; +}; +#endif /* MY_ABC_HERE */ + struct ata_link { struct ata_port *ap; int pmp; /* port multiplier port # */ @@ -794,6 +1021,13 @@ struct ata_link { unsigned int hw_sata_spd_limit; unsigned int sata_spd_limit; unsigned int sata_spd; /* current SATA PHY speed */ +#ifdef MY_ABC_HERE + struct syno_ata_latency ata_latency; + struct syno_latency_stat latency_stat; +#ifdef MY_ABC_HERE + struct syno_seq_stat seq_stat; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ enum ata_lpm_policy lpm_policy; /* record runtime error info, protected by host_set lock */ @@ -804,10 +1038,42 @@ struct ata_link { struct ata_device device[ATA_MAX_DEVICES]; unsigned long last_lpm_change; /* when last LPM change happened */ + +#ifdef MY_ABC_HERE + unsigned int uiStsFlags; /* SYNO_STATUS_xxx */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + unsigned int uiSflags; /* ATA_SYNO_FLAG_xxx, the same as ata_port */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + unsigned int uiSError; + unsigned int uiError; + struct work_struct SendSataErrEventTask; + unsigned int uiHardResetFailCount; + unsigned int uiSoftResetFailCount; + struct work_struct SendDiskTimeoutEventTask; + SYNOBIOS_EVENT_PARM diskTimeoutEventParm; + struct work_struct SendDiskSoftResetFailEventTask; + SYNOBIOS_EVENT_PARM diskSoftResetFailEventParm; + struct work_struct SendDiskHardResetFailEventTask; + SYNOBIOS_EVENT_PARM diskHardResetFailEventParm; + SYNOBIOS_EVENT_PARM diskSataErrEventParm; +#endif /* MY_ABC_HERE */ + }; #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag) #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0]) +#ifdef MY_ABC_HERE +typedef enum { + PMP_SWITCH_MODE_MANUAL = 0, + PMP_SWITCH_MODE_AUTO, + PMP_SWITCH_MODE_UNKNOWN, +} SYNO_PMP_SWITCH_MODE; +#endif /* MY_ABC_HERE */ + struct ata_port { struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ struct ata_port_operations *ops; @@ -817,6 +1083,14 @@ struct ata_port { unsigned long flags; /* ATA_FLAG_xxx */ /* Flags that change dynamically, protected by ap->lock */ unsigned int pflags; /* ATA_PFLAG_xxx */ +#ifdef MY_ABC_HERE + /* Flags used for DSM #88070 and #90197 */ + unsigned int uiStsFlags; /* SYNO_STATUS_xxx */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + int iIsDeepCtlLock; /* lock for deepsleep control */ + struct work_struct SendDsleepWakeEventTask; /* for deep sleep wake event */ +#endif /* MY_ABC_HERE */ unsigned int print_id; /* user visible unique port ID */ unsigned int local_port_no; /* host local port num */ unsigned int port_no; /* 0 based port no. inside the host */ @@ -858,6 +1132,9 @@ struct ata_port { struct mutex scsi_scan_mutex; struct delayed_work hotplug_task; +#ifdef MY_ABC_HERE + struct delayed_work syno_pmp_task; +#endif /* MY_ABC_HERE */ struct work_struct scsi_rescan_task; unsigned int hsm_task_state; @@ -884,6 +1161,61 @@ struct ata_port { #endif /* owned by EH */ u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; + +#ifdef MY_ABC_HERE + /* internal slot inedx. 0 base, < 0 means error or not internal slot */ + int syno_internal_slot_index; + /* list which contain all ata_port for searching */ + struct klist_node ata_port_list; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + /* Synology port multiplier unique. greater than 0 is our expansion box. */ + u8 PMSynoPowerDisable; + u8 PMSynoUnique; + u8 PMSynoEMID; + u8 PMSynoIsRP; + u8 PMSynoCpldVer; + SYNO_PMP_SWITCH_MODE PMSynoSwitchMode; + SYNO_PM_I2C_SYSFS_OP i2cOp; + SYNO_PM_I2C_PKG i2cPkg; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + u64 u64AtaIntrTime; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + unsigned int error_handling; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + int syno_recover_tries; + int syno_recover_max_tries; + unsigned int uiSflags; /* SYNO flags, ATA_SYNO_FLAG_xxx */ +#endif/* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct work_struct SendPortDisEventTask; + struct work_struct SendDiskRetryEventTask; + struct work_struct SendPwrResetEventTask; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + int iPresentAfterError; /* is disk connected with ata port when disk occur lost event. */ + struct work_struct SendPortRetryFailedEventTask; + struct work_struct SendLinkDownEventTask; /* only internal port would trigger this event */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + bool blSynoDiskHotplugEvent; + unsigned int ulSynoPortEnabledBitmap; + u8 uSynoPMPErrorPort; + struct work_struct SendDiskPowerShortBreakEventTask; /* for disk power short-brake event */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + void (*syno_ahci_handle_port_interrupt)(struct ata_port *, void __iomem *, u32); +#endif /* MY_ABC_HERE */ }; /* The following initializer overrides a method to NULL whether one of @@ -930,6 +1262,9 @@ struct ata_port_operations { void (*post_internal_cmd)(struct ata_queued_cmd *qc); void (*sched_eh)(struct ata_port *ap); void (*end_eh)(struct ata_port *ap); +#ifdef MY_ABC_HERE + void (*syno_recover)(struct ata_port *ap); +#endif /* MY_ABC_HERE */ /* * Optional features @@ -992,6 +1327,10 @@ struct ata_port_operations { void (*phy_reset)(struct ata_port *ap); void (*eng_timeout)(struct ata_port *ap); +#ifdef MY_ABC_HERE + bool (*syno_compare_node_info)(const struct ata_port *ap, const struct device_node *np); +#endif /* MY_ABC_HERE */ + /* * ->inherits must be the last field and all the preceding * fields must be pointers. @@ -1025,6 +1364,17 @@ struct ata_timing { /* * Core layer - drivers/ata/libata-core.c */ +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_pm_i2c; +extern struct device_attribute dev_attr_syno_manutil_power_disable; +extern struct device_attribute dev_attr_syno_pm_gpio; +extern struct device_attribute dev_attr_syno_pm_info; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_wcache; +#endif /* MY_ABC_HERE */ + extern struct ata_port_operations ata_dummy_port_ops; extern const struct ata_port_info ata_dummy_port_info; @@ -1163,6 +1513,16 @@ extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_d extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q); +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_disk_latency_read_hist; +extern struct device_attribute dev_attr_syno_disk_latency_write_hist; +extern struct device_attribute dev_attr_syno_disk_latency_other_hist; +extern struct device_attribute dev_attr_syno_disk_latency_stat; +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_disk_seq_stat; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + /* * SATA specific code - drivers/ata/libata-sata.c */ @@ -1263,6 +1623,10 @@ extern int ata_cable_unknown(struct ata_port *ap); extern unsigned int ata_pio_need_iordy(const struct ata_device *); extern u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle); +#ifdef MY_ABC_HERE +extern void syno_ata_detection_info_print(struct ata_port *ap); +#endif /* MY_ABC_HERE */ + /* PCI */ #ifdef CONFIG_PCI struct pci_dev; @@ -1383,6 +1747,16 @@ extern int ata_link_nr_enabled(struct ata_link *link); extern const struct ata_port_operations ata_base_port_ops; extern const struct ata_port_operations sata_port_ops; extern struct device_attribute *ata_common_sdev_attrs[]; +#ifdef MY_ABC_HERE +extern void syno_libata_info_enum(struct scsi_device *sdev); +#define SYNO_DISK_NAME_MACRO \ + .syno_port_type = SYNO_PORT_TYPE_SATA, \ + .syno_sdev_info_enum = syno_libata_info_enum, +#else /* MY_ABC_HERE */ +#define SYNO_DISK_NAME_MACRO +#endif /* MY_ABC_HERE */ + + /* * All sht initializers (BASE, PIO, BMDMA, NCQ) must be instantiated @@ -1405,6 +1779,7 @@ extern struct device_attribute *ata_common_sdev_attrs[]; .slave_configure = ata_scsi_slave_config, \ .slave_destroy = ata_scsi_slave_destroy, \ .bios_param = ata_std_bios_param, \ + SYNO_DISK_NAME_MACRO \ .unlock_native_capacity = ata_scsi_unlock_native_capacity #define ATA_BASE_SHT(drv_name) \ @@ -1784,6 +2159,16 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->err_mask = 0; qc->sect_size = ATA_SECT_SIZE; +#ifdef MY_ABC_HERE + qc->qc_stat.u8QcType = 0; + qc->qc_stat.u8SeqTag = 0; + qc->qc_stat.u8SeqState = 0; + qc->qc_stat.u8LbaZone = 0; + qc->qc_stat.u32SkipBytes = 0; + qc->qc_stat.u64IssueTime = 0; + qc->qc_stat.u64StartLbaByte = 0; +#endif /* MY_ABC_HERE */ + ata_tf_init(qc->dev, &qc->tf); /* init result_tf such that it indicates normal completion */ @@ -1861,6 +2246,30 @@ static inline int ata_dma_enabled(struct ata_device *adev) return (adev->dma_mode == 0xFF ? 0 : 1); } +#ifdef MY_ABC_HERE +static inline unsigned int syno_ata_latency_bucket_offset_get(const u64 u64Latency) +{ + unsigned int uOffset = 0; + + /* latency >= 1024 us */ + if ( 0x1F < u64Latency) { + uOffset += 1; + } + + /* latency >= 32ms */ + if (unlikely( 0x3FF < u64Latency)) { + uOffset += 1; + } + + /* latency >= 1024ms */ + if (unlikely( 0x7FFF < u64Latency)) { + uOffset += 1; + } + + return uOffset; +} +#endif /* MY_ABC_HERE */ + /************************************************************************** * PATA timings - drivers/ata/libata-pata-timings.c */ @@ -2050,4 +2459,124 @@ static inline u8 ata_wait_idle(struct ata_port *ap) } #endif /* CONFIG_ATA_SFF */ + +/* + * Syno device attribute + */ +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_sata_disk_led_ctrl; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_power_ctrl; +extern struct device_attribute dev_attr_syno_deep_sleep_ctrl; +extern struct device_attribute dev_attr_syno_deep_sleep_support; +extern struct device_attribute dev_attr_syno_pm_control_support; +#endif /* MY_ABC_HERE */ + + +/* + * Syno function + */ +#ifdef MY_ABC_HERE +extern int lookup_internal_slot(const struct ata_port *ap); +extern int syno_external_libata_index_get(const struct ata_port *ap); +extern int syno_libata_numeric_diskname_number_get(struct ata_link *pAtaLink); +extern int get_disk_port_type_and_index_by_ata_port(const struct ata_port *ap, DISK_PORT_TYPE *portType, int *portIndex); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern unsigned int syno_sata_pmp_read_gpio(struct ata_port *, SYNO_PM_PKG *); +extern unsigned int syno_sata_pmp_write_gpio(struct ata_port *, SYNO_PM_PKG *); +extern unsigned int syno_sata_pmp_read_gpio_core(struct ata_link *, SYNO_PM_PKG *); +extern unsigned int syno_sata_pmp_write_gpio_core(struct ata_link *, SYNO_PM_PKG *); +extern u8 syno_is_synology_pm(const struct ata_port *ap); +extern u8 syno_pm_with_synology_magic(const struct ata_port *ap); +extern u32 syno_pmp_ports_num(struct ata_port *ap); +extern void syno_pm_device_info_set(struct ata_port *ap, u8 rw, SYNO_PM_PKG *pm_pkg); +extern unsigned int syno_pm_gpio_output_disable(struct ata_link *link); +extern unsigned int syno_pm_gpio_output_enable(struct ata_link *link); +extern int syno_libata_pm_power_ctl(struct ata_port *ap, u8 pwrOp, u8 blCustomInfo); +extern unsigned int syno_sata_pmp_is_rp(struct ata_port *ap); +extern struct ata_port *SynoEunitFindMaster(struct ata_port *ap); +extern struct ata_port* SynoEunitEnumPort(struct ata_port *pAp_master, struct klist_node *pAtaNode); +extern void SynoEunitFlagSet(struct ata_port *pAp_master, bool blset, unsigned int flag, bool blWithLink); +extern u8 syno_pm_is_synology_9705(const struct ata_port *ap); +extern int syno_pm_show_sn(struct ata_device *dev); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int SynoFlagSet(struct ata_port *ap, const unsigned int ulFlag, const u8 blSet); +extern int iIsSynoDeepSleepSupport(struct ata_port *ap); +extern int syno_libata_set_deep_sleep(struct ata_port *ap, const u8 blSet); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern unsigned int uiCheckPortLinksFlags(struct ata_port *pAp); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_port_thaw; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_pwr_reset_count; +extern void syno_sata_deep_retry (struct ata_port *ap); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern struct device_attribute dev_attr_syno_sata_error_event_debug; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void syno_ata_present_print(struct ata_port *ap, const char *eventlog); +#endif /* MY_ABC_HERE */ + +/* + * Syno marco + */ +#ifdef MY_ABC_HERE +#define IS_SYNO_PMP_GSCR_9705_CONFIG(tf) (SATA_PMP_GSCR_9705_GPO_EN == ((tf->hob_feature << 8) | tf->feature) || \ + SATA_PMP_GSCR_9705_GPI_POLARITY == ((tf->hob_feature << 8) | tf->feature) || \ + SATA_PMP_GSCR_9705_SATA_0_TO_3_BLINK_RATE == ((tf->hob_feature << 8) | tf->feature) || \ + SATA_PMP_GSCR_9705_SATA_4_BLINK_RATE == ((tf->hob_feature << 8) | tf->feature)) + +#define IS_SYNO_PMP_WRITE_CMD(tf) (ATA_CMD_PMP_WRITE == tf->command && \ + (SATA_PMP_GSCR_9705_GPO == ((tf->hob_feature << 8) | tf->feature) || \ + IS_SYNO_PMP_GSCR_9705_CONFIG(tf))) +#define IS_SYNO_PMP_READ_CMD(tf) (ATA_CMD_PMP_READ == tf->command && \ + (SATA_PMP_GSCR_9705_GPI == ((tf->hob_feature << 8) | tf->feature) || \ + IS_SYNO_PMP_GSCR_9705_CONFIG(tf))) +#define IS_SYNO_PMP_CMD(tf) (IS_SYNO_PMP_READ_CMD(tf) || IS_SYNO_PMP_WRITE_CMD(tf)) +#define IS_SYNO_PMP_575_CMD(tf) (ATA_CMD_PMP_SYNO_I2C == tf.command || ATA_CMD_PMP_SYNO_LED_GPIO == tf.command || ATA_CMD_PMP_GET_BOARD_INFO_JMB575 == tf.command) +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#define IS_SYNO_SPINUP_CMD(qc) (NULL == qc->scsicmd && !ata_tag_internal(qc->tag) && \ + ATA_CMD_IDLEIMMEDIATE == qc->tf.command) +#endif /* MY_DEF_HERE */ + +/* + * Syno inline functions + */ +#ifdef MY_ABC_HERE +static inline int syno_qc_filter(struct ata_queued_cmd *qc){ + +#ifdef MY_ABC_HERE + struct ata_taskfile *tf = &qc->tf; + + if ((IS_SYNO_PMP_CMD(tf) && NULL == qc->scsicmd)) { + return 1; + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + if (IS_SYNO_SPINUP_CMD(qc)) { + return 1; + } +#endif /* MY_DEF_HERE */ + + return 0; +} +#endif /* MY_ABC_HERE */ + #endif /* __LINUX_LIBATA_H__ */ diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index f5594879175a..56276ef068c3 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Runtime locking correctness validator @@ -241,6 +244,10 @@ static inline int lockdep_match_key(struct lockdep_map *lock, return lock->key == key; } +#ifdef MY_ABC_HERE +struct lock_class *lockdep_hlock_class(struct held_lock *hlock); +#endif /* MY_ABC_HERE */ + /* * Acquire a lock. * @@ -375,6 +382,9 @@ static inline void lockdep_unregister_key(struct lock_class_key *key) #define lockdep_depth(tsk) (0) +#ifdef MY_ABC_HERE +#define lockdep_is_held(lock) (1) +#endif /* MY_ABC_HERE */ #define lockdep_is_held_type(l, r) (1) #define lockdep_assert_held(l) do { (void)(l); } while (0) diff --git a/include/linux/mfd/apw8886.h b/include/linux/mfd/apw8886.h new file mode 100644 index 000000000000..be466500058a --- /dev/null +++ b/include/linux/mfd/apw8886.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LINUX_MFD_APW8886_H +#define __LINUX_MFD_APW8886_H + +/* button registers */ +#define APW8886_REG_INTR (0x00) +#define APW8886_REG_INTR_MASK (0x01) +#define APW8886_REG_PWRKEY (0x02) +#define APW8886_REG_SYS_CONTROL (0x04) + +/* regulator control registers */ +#define APW8886_REG_FAULT_STATUS (0x03) +#define APW8886_REG_ONOFF (0x05) +#define APW8886_REG_DISCHG (0x06) +#define APW8886_REG_DC1DC2_MODE (0x07) +#define APW8886_REG_DC1_MODE (APW8886_REG_DC1DC2_MODE) +#define APW8886_REG_DC2_MODE (APW8886_REG_DC1DC2_MODE) +#define APW8886_REG_DC3_MODE (0x08) +#define APW8886_REG_DC4DC5_MODE (0x09) +#define APW8886_REG_DC4_MODE (APW8886_REG_DC4DC5_MODE) +#define APW8886_REG_DC5_MODE (APW8886_REG_DC4DC5_MODE) +#define APW8886_REG_LDO1_MODE (0x0A) +#define APW8886_REG_DC1_NRMVOLT (0x0B) +#define APW8886_REG_DC2_NRMVOLT (0x0C) +#define APW8886_REG_DC3_NRMVOLT (0x0D) +#define APW8886_REG_DC4_NRMVOLT (0x0F) +#define APW8886_REG_LDO1_NRMVOLT (0x10) +#define APW8886_REG_DC1_SLPVOLT (0x11) +#define APW8886_REG_DC2_SLPVOLT (0x12) +#define APW8886_REG_DC3_SLPVOLT (0x13) +#define APW8886_REG_DC4_SLPVOLT (0x15) +#define APW8886_REG_LDO1_SLPVOLT (0x16) +#define APW8886_REG_CLAMP (0x17) +#define APW8886_REG_VFB5_REF_VOLT_DAC (0x1A) + +/* misc registers */ +#define APW8886_REG_CHIP_ID (0x1D) +#define APW8886_REG_VERSION (0x1E) + +/* register field: ONOFF */ +#define APW8886_DC1_ON_MASK (0x80) +#define APW8886_DC1_ON_SHIFT (7) +#define APW8886_DC1_ON_WIDTH (1) +#define APW8886_DC2_ON_MASK (0x40) +#define APW8886_DC2_ON_SHIFT (6) +#define APW8886_DC2_ON_WIDTH (1) +#define APW8886_DC3_ON_MASK (0x20) +#define APW8886_DC3_ON_SHIFT (5) +#define APW8886_DC3_ON_WIDTH (1) +#define APW8886_DC5_ON_MASK (0x08) +#define APW8886_DC5_ON_SHIFT (3) +#define APW8886_DC5_ON_WIDTH (1) +#define APW8886_DC4_ON_MASK (0x04) +#define APW8886_DC4_ON_SHIFT (2) +#define APW8886_DC4_ON_WIDTH (1) +#define APW8886_LDO1_ON_MASK (0x01) +#define APW8886_LDO1_ON_SHIFT (0) +#define APW8886_LDO1_ON_WIDTH (1) + +/* register field: DISCHG */ +#define APW8886_DC1_DISCHG_MASK (0x80) +#define APW8886_DC1_DISCHG_SHIFT (7) +#define APW8886_DC1_DISCHG_WIDTH (1) +#define APW8886_DC2_DISCHG_MASK (0x40) +#define APW8886_DC2_DISCHG_SHIFT (6) +#define APW8886_DC2_DISCHG_WIDTH (1) +#define APW8886_DC3_DISCHG_MASK (0x20) +#define APW8886_DC3_DISCHG_SHIFT (5) +#define APW8886_DC3_DISCHG_WIDTH (1) +#define APW8886_DC5_DISCHG_MASK (0x08) +#define APW8886_DC5_DISCHG_SHIFT (3) +#define APW8886_DC5_DISCHG_WIDTH (1) +#define APW8886_DC4_DISCHG_MASK (0x04) +#define APW8886_DC4_DISCHG_SHIFT (2) +#define APW8886_DC4_DISCHG_WIDTH (1) +#define APW8886_LDO1_DISCHG_MASK (0x01) +#define APW8886_LDO1_DISCHG_SHIFT (0) +#define APW8886_LDO1_DISCHG_WIDTH (1) + +/* register field: MODE */ +#define APW8886_DC1_NRMMODE_MASK (0xC0) +#define APW8886_DC1_NRMMODE_SHIFT (6) +#define APW8886_DC1_NRMMODE_WIDTH (2) +#define APW8886_DC1_SLPMODE_MASK (0x30) +#define APW8886_DC1_SLPMODE_SHIFT (4) +#define APW8886_DC1_SLPMODE_WIDTH (2) +#define APW8886_DC2_NRMMODE_MASK (0x0C) +#define APW8886_DC2_NRMMODE_SHIFT (2) +#define APW8886_DC2_NRMMODE_WIDTH (2) +#define APW8886_DC2_SLPMODE_MASK (0x03) +#define APW8886_DC2_SLPMODE_SHIFT (0) +#define APW8886_DC2_SLPMODE_WIDTH (2) +#define APW8886_DC3_NRMMODE_MASK (0xC0) +#define APW8886_DC3_NRMMODE_SHIFT (6) +#define APW8886_DC3_NRMMODE_WIDTH (2) +#define APW8886_DC3_SLPMODE_MASK (0x30) +#define APW8886_DC3_SLPMODE_SHIFT (4) +#define APW8886_DC3_SLPMODE_WIDTH (2) +#define APW8886_DC5_NRMMODE_MASK (0xC0) +#define APW8886_DC5_NRMMODE_SHIFT (6) +#define APW8886_DC5_NRMMODE_WIDTH (2) +#define APW8886_DC5_SLPMODE_MASK (0x30) +#define APW8886_DC5_SLPMODE_SHIFT (4) +#define APW8886_DC5_SLPMODE_WIDTH (2) +#define APW8886_DC4_NRMMODE_MASK (0x0C) +#define APW8886_DC4_NRMMODE_SHIFT (2) +#define APW8886_DC4_NRMMODE_WIDTH (2) +#define APW8886_DC4_SLPMODE_MASK (0x03) +#define APW8886_DC4_SLPMODE_SHIFT (0) +#define APW8886_DC4_SLPMODE_WIDTH (2) +#define APW8886_LDO1_NRMMODE_MASK (0x30) +#define APW8886_LDO1_NRMMODE_SHIFT (4) +#define APW8886_LDO1_NRMMODE_WIDTH (2) +#define APW8886_LDO1_SLPMODE_MASK (0x30) +#define APW8886_LDO1_SLPMODE_SHIFT (4) +#define APW8886_LDO1_SLPMODE_WIDTH (2) + +/* register field: NRMVOLT / SLPVOLT */ +#define APW8886_DC1_NRMVOLT_MASK (0x3F) +#define APW8886_DC1_NRMVOLT_SHIFT (0) +#define APW8886_DC1_NRMVOLT_WIDTH (6) +#define APW8886_DC1_SLPVOLT_MASK (0x3F) +#define APW8886_DC1_SLPVOLT_SHIFT (0) +#define APW8886_DC1_SLPVOLT_WIDTH (6) +#define APW8886_DC2_NRMVOLT_MASK (0x3F) +#define APW8886_DC2_NRMVOLT_SHIFT (0) +#define APW8886_DC2_NRMVOLT_WIDTH (6) +#define APW8886_DC2_SLPVOLT_MASK (0x3F) +#define APW8886_DC2_SLPVOLT_SHIFT (0) +#define APW8886_DC2_SLPVOLT_WIDTH (6) +#define APW8886_DC3_NRMVOLT_MASK (0x3F) +#define APW8886_DC3_NRMVOLT_SHIFT (0) +#define APW8886_DC3_NRMVOLT_WIDTH (6) +#define APW8886_DC3_SLPVOLT_MASK (0x3F) +#define APW8886_DC3_SLPVOLT_SHIFT (0) +#define APW8886_DC3_SLPVOLT_WIDTH (6) +#define APW8886_DC4_NRMVOLT_MASK (0x3F) +#define APW8886_DC4_NRMVOLT_SHIFT (0) +#define APW8886_DC4_NRMVOLT_WIDTH (6) +#define APW8886_DC4_SLPVOLT_MASK (0x3F) +#define APW8886_DC4_SLPVOLT_SHIFT (0) +#define APW8886_DC4_SLPVOLT_WIDTH (6) +#define APW8886_LDO1_NRMVOLT_MASK (0x1F) +#define APW8886_LDO1_NRMVOLT_SHIFT (0) +#define APW8886_LDO1_NRMVOLT_WIDTH (5) +#define APW8886_LDO1_SLPVOLT_MASK (0x1F) +#define APW8886_LDO1_SLPVOLT_SHIFT (0) +#define APW8886_LDO1_SLPVOLT_WIDTH (6) + +/* register field: CLAMP */ +#define APW8886_DC2_CLAMP_MASK (0x2) +#define APW8886_DC2_CLAMP_SHIFT (1) +#define APW8886_DC2_CLAMP_WIDTH (1) +#define APW8886_DC3_CLAMP_MASK (0x1) +#define APW8886_DC3_CLAMP_SHIFT (0) +#define APW8886_DC3_CLAMP_WIDTH (1) + +#endif /* __LINUX_MFD_APW8886_H */ diff --git a/include/linux/mfd/apw8889.h b/include/linux/mfd/apw8889.h new file mode 100644 index 000000000000..52f66989fb71 --- /dev/null +++ b/include/linux/mfd/apw8889.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LINUX_MFD_APW8889_H +#define __LINUX_MFD_APW8889_H + +/* button registers */ +#define APW8889_REG_INTR (0x00) +#define APW8889_REG_INTR_MASK (0x01) +#define APW8889_REG_PWRKEY (0x02) +#define APW8889_REG_SYS_CONTROL (0x04) + +/* regulator control registers */ +#define APW8889_REG_FAULT_STATUS (0x03) +#define APW8889_REG_ONOFF (0x05) +#define APW8889_REG_DISCHG (0x06) +#define APW8889_REG_DC1DC2_MODE (0x07) +#define APW8889_REG_DC1_MODE (APW8889_REG_DC1DC2_MODE) +#define APW8889_REG_DC2_MODE (APW8889_REG_DC1DC2_MODE) +#define APW8889_REG_DC3DC4_MODE (0x08) +#define APW8889_REG_DC3_MODE (APW8889_REG_DC3DC4_MODE) +#define APW8889_REG_DC4_MODE (APW8889_REG_DC3DC4_MODE) +#define APW8889_REG_DC5DC6_MODE (0x09) +#define APW8889_REG_DC5_MODE (APW8889_REG_DC5DC6_MODE) +#define APW8889_REG_DC6_MODE (APW8889_REG_DC5DC6_MODE) +#define APW8889_REG_LDO1_MODE (0x0A) +#define APW8889_REG_DC1_NRMVOLT (0x0B) +#define APW8889_REG_DC2_NRMVOLT (0x0C) +#define APW8889_REG_DC3_NRMVOLT (0x0D) +#define APW8889_REG_DC4_NRMVOLT (0x0E) +#define APW8889_REG_DC6_NRMVOLT (0x0F) +#define APW8889_REG_LDO1_NRMVOLT (0x10) +#define APW8889_REG_DC1_SLPVOLT (0x11) +#define APW8889_REG_DC2_SLPVOLT (0x12) +#define APW8889_REG_DC3_SLPVOLT (0x13) +#define APW8889_REG_DC4_SLPVOLT (0x14) +#define APW8889_REG_DC6_SLPVOLT (0x15) +#define APW8889_REG_LDO1_SLPVOLT (0x16) +#define APW8889_REG_CLAMP (0x17) + +/* misc registers */ +#define APW8889_REG_CHIP_ID (0x1D) +#define APW8889_REG_VERSION (0x1E) + +/* register field: ONOFF */ +#define APW8889_DC1_ON_MASK (0x80) +#define APW8889_DC1_ON_SHIFT (7) +#define APW8889_DC1_ON_WIDTH (1) +#define APW8889_DC2_ON_MASK (0x40) +#define APW8889_DC2_ON_SHIFT (6) +#define APW8889_DC2_ON_WIDTH (1) +#define APW8889_DC3_ON_MASK (0x20) +#define APW8889_DC3_ON_SHIFT (5) +#define APW8889_DC3_ON_WIDTH (1) +#define APW8889_DC4_ON_MASK (0x10) +#define APW8889_DC4_ON_SHIFT (4) +#define APW8889_DC4_ON_WIDTH (1) +#define APW8889_DC5_ON_MASK (0x08) +#define APW8889_DC5_ON_SHIFT (3) +#define APW8889_DC5_ON_WIDTH (1) +#define APW8889_DC6_ON_MASK (0x04) +#define APW8889_DC6_ON_SHIFT (2) +#define APW8889_DC6_ON_WIDTH (1) +#define APW8889_LDO1_ON_MASK (0x01) +#define APW8889_LDO1_ON_SHIFT (0) +#define APW8889_LDO1_ON_WIDTH (1) + +/* register field: DISCHG */ +#define APW8889_DC1_DISCHG_MASK (0x80) +#define APW8889_DC1_DISCHG_SHIFT (7) +#define APW8889_DC1_DISCHG_WIDTH (1) +#define APW8889_DC2_DISCHG_MASK (0x40) +#define APW8889_DC2_DISCHG_SHIFT (6) +#define APW8889_DC2_DISCHG_WIDTH (1) +#define APW8889_DC3_DISCHG_MASK (0x20) +#define APW8889_DC3_DISCHG_SHIFT (5) +#define APW8889_DC3_DISCHG_WIDTH (1) +#define APW8889_DC4_DISCHG_MASK (0x10) +#define APW8889_DC4_DISCHG_SHIFT (4) +#define APW8889_DC4_DISCHG_WIDTH (1) +#define APW8889_DC5_DISCHG_MASK (0x08) +#define APW8889_DC5_DISCHG_SHIFT (3) +#define APW8889_DC5_DISCHG_WIDTH (1) +#define APW8889_DC6_DISCHG_MASK (0x04) +#define APW8889_DC6_DISCHG_SHIFT (2) +#define APW8889_DC6_DISCHG_WIDTH (1) +#define APW8889_LDO1_DISCHG_MASK (0x01) +#define APW8889_LDO1_DISCHG_SHIFT (0) +#define APW8889_LDO1_DISCHG_WIDTH (1) + +/* register field: MODE */ +#define APW8889_DC1_NRMMODE_MASK (0xC0) +#define APW8889_DC1_NRMMODE_SHIFT (6) +#define APW8889_DC1_NRMMODE_WIDTH (2) +#define APW8889_DC1_SLPMODE_MASK (0x30) +#define APW8889_DC1_SLPMODE_SHIFT (4) +#define APW8889_DC1_SLPMODE_WIDTH (2) +#define APW8889_DC2_NRMMODE_MASK (0x0C) +#define APW8889_DC2_NRMMODE_SHIFT (2) +#define APW8889_DC2_NRMMODE_WIDTH (2) +#define APW8889_DC2_SLPMODE_MASK (0x03) +#define APW8889_DC2_SLPMODE_SHIFT (0) +#define APW8889_DC2_SLPMODE_WIDTH (2) +#define APW8889_DC3_NRMMODE_MASK (0xC0) +#define APW8889_DC3_NRMMODE_SHIFT (6) +#define APW8889_DC3_NRMMODE_WIDTH (2) +#define APW8889_DC3_SLPMODE_MASK (0x30) +#define APW8889_DC3_SLPMODE_SHIFT (4) +#define APW8889_DC3_SLPMODE_WIDTH (2) +#define APW8889_DC4_NRMMODE_MASK (0x0C) +#define APW8889_DC4_NRMMODE_SHIFT (2) +#define APW8889_DC4_NRMMODE_WIDTH (2) +#define APW8889_DC4_SLPMODE_MASK (0x03) +#define APW8889_DC4_SLPMODE_SHIFT (0) +#define APW8889_DC4_SLPMODE_WIDTH (2) +#define APW8889_DC5_NRMMODE_MASK (0xC0) +#define APW8889_DC5_NRMMODE_SHIFT (6) +#define APW8889_DC5_NRMMODE_WIDTH (2) +#define APW8889_DC5_SLPMODE_MASK (0x30) +#define APW8889_DC5_SLPMODE_SHIFT (4) +#define APW8889_DC5_SLPMODE_WIDTH (2) +#define APW8889_DC6_NRMMODE_MASK (0x0C) +#define APW8889_DC6_NRMMODE_SHIFT (2) +#define APW8889_DC6_NRMMODE_WIDTH (2) +#define APW8889_DC6_SLPMODE_MASK (0x03) +#define APW8889_DC6_SLPMODE_SHIFT (0) +#define APW8889_DC6_SLPMODE_WIDTH (2) +#define APW8889_LDO1_NRMMODE_MASK (0xC0) +#define APW8889_LDO1_NRMMODE_SHIFT (6) +#define APW8889_LDO1_NRMMODE_WIDTH (2) +#define APW8889_LDO1_SLPMODE_MASK (0x30) +#define APW8889_LDO1_SLPMODE_SHIFT (4) +#define APW8889_LDO1_SLPMODE_WIDTH (2) + +/* register field: NRMVOLT / SLPVOLT */ +#define APW8889_DC1_NRMVOLT_MASK (0x3F) +#define APW8889_DC1_NRMVOLT_SHIFT (0) +#define APW8889_DC1_NRMVOLT_WIDTH (6) +#define APW8889_DC1_SLPVOLT_MASK (0x3F) +#define APW8889_DC1_SLPVOLT_SHIFT (0) +#define APW8889_DC1_SLPVOLT_WIDTH (6) +#define APW8889_DC2_NRMVOLT_MASK (0x3F) +#define APW8889_DC2_NRMVOLT_SHIFT (0) +#define APW8889_DC2_NRMVOLT_WIDTH (6) +#define APW8889_DC2_SLPVOLT_MASK (0x3F) +#define APW8889_DC2_SLPVOLT_SHIFT (0) +#define APW8889_DC2_SLPVOLT_WIDTH (6) +#define APW8889_DC3_NRMVOLT_MASK (0x3F) +#define APW8889_DC3_NRMVOLT_SHIFT (0) +#define APW8889_DC3_NRMVOLT_WIDTH (6) +#define APW8889_DC3_SLPVOLT_MASK (0x3F) +#define APW8889_DC3_SLPVOLT_SHIFT (0) +#define APW8889_DC3_SLPVOLT_WIDTH (6) +#define APW8889_DC4_NRMVOLT_MASK (0x3F) +#define APW8889_DC4_NRMVOLT_SHIFT (0) +#define APW8889_DC4_NRMVOLT_WIDTH (6) +#define APW8889_DC4_SLPVOLT_MASK (0x3F) +#define APW8889_DC4_SLPVOLT_SHIFT (0) +#define APW8889_DC4_SLPVOLT_WIDTH (6) +#define APW8889_DC6_NRMVOLT_MASK (0x3F) +#define APW8889_DC6_NRMVOLT_SHIFT (2) +#define APW8889_DC6_NRMVOLT_WIDTH (6) +#define APW8889_DC6_SLPVOLT_MASK (0x3F) +#define APW8889_DC6_SLPVOLT_SHIFT (0) +#define APW8889_DC6_SLPVOLT_WIDTH (6) +#define APW8889_LDO1_NRMVOLT_MASK (0x1F) +#define APW8889_LDO1_NRMVOLT_SHIFT (0) +#define APW8889_LDO1_NRMVOLT_WIDTH (5) +#define APW8889_LDO1_SLPVOLT_MASK (0x1F) +#define APW8889_LDO1_SLPVOLT_SHIFT (0) +#define APW8889_LDO1_SLPVOLT_WIDTH (5) + +/* register field: CLAMP */ +#define APW8889_DC2_CLAMP_MASK (0x4) +#define APW8889_DC2_CLAMP_SHIFT (2) +#define APW8889_DC2_CLAMP_WIDTH (1) +#define APW8889_DC3_CLAMP_MASK (0x2) +#define APW8889_DC3_CLAMP_SHIFT (1) +#define APW8889_DC3_CLAMP_WIDTH (1) +#define APW8889_DC4_CLAMP_MASK (0x1) +#define APW8889_DC4_CLAMP_SHIFT (0) +#define APW8889_DC4_CLAMP_WIDTH (1) + +#endif /* __LINUX_MFD_APW8889_H */ diff --git a/include/linux/mfd/apw888x.h b/include/linux/mfd/apw888x.h new file mode 100644 index 000000000000..a48bcf261c34 --- /dev/null +++ b/include/linux/mfd/apw888x.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Anpec APW888X series PMIC MFD + * + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee + */ + +#ifndef __LINUX_MFD_APW888X_H +#define __LINUX_MFD_APW888X_H + +#include + +struct apw888x_device { + u32 chip_id; + u32 chip_rev; + struct device *dev; + struct regmap *regmap; +}; + +int apw888x_device_init(struct apw888x_device *gdev); +void apw888x_device_exit(struct apw888x_device *gdev); + +#define APW888X_DEVICE_ID_APW8889 (8889) +#define APW888X_DEVICE_ID_APW8886 (8886) +#define APW888X_DEVICE_ID_APW7899 (7899) + +#endif /* __LINUX_MFD_APW888X_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 289c26f055cd..1751a9456309 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_MM_H #define _LINUX_MM_H @@ -1730,6 +1733,30 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, unmap_mapping_range(mapping, holebegin, holelen, 0); } +#ifdef MY_ABC_HERE +extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); +extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], + int); +extern void vma_do_get_file(struct vm_area_struct *, const char[], int); +extern void vma_do_fput(struct vm_area_struct *, const char[], int); + +#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ + __LINE__) +#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ + __LINE__) +#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) +#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) + +#ifndef CONFIG_MMU +extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); +extern void vmr_do_fput(struct vm_region *, const char[], int); + +#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ + __LINE__) +#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) +#endif /* !CONFIG_MMU */ +#endif /* MY_ABC_HERE */ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, unsigned int gup_flags); extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, @@ -2461,6 +2488,9 @@ extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long, unsigned long, enum meminit_context, struct vmem_altmap *, int migratetype); extern void setup_per_zone_wmarks(void); +#ifdef MY_ABC_HERE +extern void update_kswapd_threads(void); +#endif /* MY_ABC_HERE */ extern int __meminit init_per_zone_wmark_min(void); extern void mem_init(void); extern void __init mmap_init(void); @@ -2477,6 +2507,10 @@ void warn_alloc(gfp_t gfp_mask, nodemask_t *nodemask, const char *fmt, ...); extern void setup_per_cpu_pageset(void); +#ifdef MY_ABC_HERE +extern int kswapd_threads; +extern int kswapd_threads_current; +#endif /* MY_ABC_HERE */ /* page_alloc.c */ extern int min_free_kbytes; extern int watermark_boost_factor; diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 4eb38918da8f..8396acec5bcb 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_MM_TYPES_H #define _LINUX_MM_TYPES_H @@ -282,6 +285,9 @@ struct vm_region { unsigned long vm_top; /* region allocated to here */ unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ struct file *vm_file; /* the backing file or NULL */ +#ifdef MY_ABC_HERE + struct file *vm_prfile; /* the virtual backing file or NULL */ +#endif /* MY_ABC_HERE */ int vm_usage; /* region usage count (access under nommu_region_sem) */ bool vm_icache_flushed : 1; /* true if the icache has been flushed for @@ -361,6 +367,9 @@ struct vm_area_struct { unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE units */ struct file * vm_file; /* File we map to (can be NULL). */ +#ifdef MY_ABC_HERE + struct file *vm_prfile; /* shadow of vm_file */ +#endif /* MY_ABC_HERE */ void * vm_private_data; /* was vm_pte (shared mem) */ #ifdef CONFIG_SWAP diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 40d7e98fc990..e408e41d83e2 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/include/linux/mmc/host.h @@ -320,6 +323,9 @@ struct mmc_host { #define MMC_CAP_AGGRESSIVE_PM (1 << 7) /* Suspend (e)MMC/SD at idle */ #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ +#if defined(MY_DEF_HERE) +#define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */ +#endif /* MY_DEF_HERE */ #define MMC_CAP_3_3V_DDR (1 << 11) /* Host supports eMMC DDR 3.3V */ #define MMC_CAP_1_8V_DDR (1 << 12) /* Host supports eMMC DDR 1.8V */ #define MMC_CAP_1_2V_DDR (1 << 13) /* Host supports eMMC DDR 1.2V */ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 9d0c454d23cd..c211d7a7d031 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_MMZONE_H #define _LINUX_MMZONE_H @@ -38,6 +41,10 @@ */ #define PAGE_ALLOC_COSTLY_ORDER 3 +#ifdef MY_ABC_HERE +#define MAX_KSWAPD_THREADS 16 + +#endif /* MY_ABC_HERE */ enum migratetype { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, @@ -584,6 +591,11 @@ enum pgdat_flags { * many pages under writeback */ PGDAT_RECLAIM_LOCKED, /* prevents concurrent reclaim */ +#ifdef MY_ABC_HERE + PGDAT_SYNO_UPDATING_KSWAPDS, /* prevents race of updating and + * checking kswapds[hid] + */ +#endif /* MY_ABC_HERE */ }; enum zone_flags { @@ -747,8 +759,15 @@ typedef struct pglist_data { int node_id; wait_queue_head_t kswapd_wait; wait_queue_head_t pfmemalloc_wait; +#ifdef MY_ABC_HERE + /** + * Protected by mem_hotplug_begin/end() + */ + struct task_struct *kswapd[MAX_KSWAPD_THREADS]; +#else /* MY_ABC_HERE */ struct task_struct *kswapd; /* Protected by mem_hotplug_begin/end() */ +#endif /* MY_ABC_HERE */ int kswapd_order; enum zone_type kswapd_highest_zoneidx; @@ -956,6 +975,10 @@ static inline int is_highmem(struct zone *zone) /* These two functions are used to setup the per zone pages min values */ struct ctl_table; +#ifdef MY_ABC_HERE +int kswapd_threads_sysctl_handler(struct ctl_table *, int, + void __user *, size_t *, loff_t *); +#endif /* MY_ABC_HERE */ int min_free_kbytes_sysctl_handler(struct ctl_table *, int, void *, size_t *, loff_t *); int watermark_scale_factor_sysctl_handler(struct ctl_table *, int, void *, diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 157357ec1441..032174298f53 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright © 1999-2010 David Woodhouse et al. @@ -706,4 +709,12 @@ static inline int mtd_is_bitflip_or_eccerr(int err) { unsigned mtd_mmap_capabilities(struct mtd_info *mtd); +#ifdef MY_DEF_HERE +/* written in synopart.c */ +int SYNOMTDModifyPartInfo(struct mtd_info *mtd, unsigned long offset, unsigned long length); + +/* written in redboot.c */ +int SYNOMTDModifyFisInfo(struct mtd_info *mtd, struct SYNO_MTD_FIS_INFO SynoMtdFisInfo); +#endif /* MY_DEF_HERE */ + #endif /* __MTD_MTD_H__ */ diff --git a/include/linux/namei.h b/include/linux/namei.h index a4bb992623c4..fae9cc3b9293 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_NAMEI_H #define _LINUX_NAMEI_H @@ -48,9 +51,19 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; #define LOOKUP_IN_ROOT 0x100000 /* Treat dirfd as fs root. */ /* LOOKUP_* flags which do scope-related checks based on the dirfd. */ #define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT) +#ifdef MY_ABC_HERE +/* this namei has done to the last component */ +#define LOOKUP_TO_LASTCOMPONENT 0x200000 +#define LOOKUP_MOUNTED 0x400000 +#define LOOKUP_CASELESS_COMPARE 0x800000 +#endif /* MY_ABC_HERE */ extern int path_pts(struct path *path); +#ifdef MY_ABC_HERE +extern int syno_user_path_at(int, const char __user *, unsigned, struct path *, char **, int *); +#endif /* MY_ABC_HERE */ + extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); static inline int user_path_at(int dfd, const char __user *name, unsigned flags, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e37480b5f4c0..65d15b28e2d3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * INET An implementation of the TCP/IP protocol suite for the LINUX @@ -5025,6 +5028,10 @@ static inline bool netif_reduces_vlan_mtu(struct net_device *dev) extern struct pernet_operations __net_initdata loopback_net_ops; +#ifdef MY_ABC_HERE +extern int syno_get_dev_vendor_mac(const char *szDev, char *szMac, int bufSize); +#endif /* MY_ABC_HERE */ + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* netdev_printk helpers, similar to dev_printk */ diff --git a/include/linux/nvme.h b/include/linux/nvme.h index bfed36e342cc..3f536f7ec6d6 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Definitions for the NVM Express interface @@ -1594,6 +1597,20 @@ struct nvme_completion { __le16 status; /* did the command fail, and if so, why? */ }; +#ifdef MY_ABC_HERE +struct syno_nvme_error_log_page { + __u64 error_count; + __u16 sqid; + __u16 cmdid; + __u16 status_field; + __u16 parm_error_location; + __u64 lba; + __u32 nsid; + __u8 vs; + __u8 resv[35]; +}; +#endif /* MY_ABC_HERE */ + #define NVME_VS(major, minor, tertiary) \ (((major) << 16) | ((minor) << 8) | (tertiary)) diff --git a/include/linux/parser.h b/include/linux/parser.h index 89e2b23fb888..dd79f45a37b8 100644 --- a/include/linux/parser.h +++ b/include/linux/parser.h @@ -29,6 +29,7 @@ typedef struct { int match_token(char *, const match_table_t table, substring_t args[]); int match_int(substring_t *, int *result); +int match_uint(substring_t *s, unsigned int *result); int match_u64(substring_t *, u64 *result); int match_octal(substring_t *, int *result); int match_hex(substring_t *, int *result); diff --git a/include/linux/pci.h b/include/linux/pci.h index 22207a79762c..23cfdf4a1d7d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * pci.h @@ -41,6 +44,9 @@ #include #include +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \ PCI_STATUS_SIG_SYSTEM_ERROR | \ @@ -500,6 +506,10 @@ struct pci_dev { char *driver_override; /* Driver name to force a match */ unsigned long priv_flags; /* Private flags for the PCI driver */ +#ifdef MY_DEF_HERE + struct list_head syno_device_list; + unsigned int syno_eunit_layer; +#endif /* MY_DEF_HERE */ }; static inline struct pci_dev *pci_physfn(struct pci_dev *dev) diff --git a/include/linux/raid/libmd-report.h b/include/linux/raid/libmd-report.h new file mode 100644 index 000000000000..3b15bcad3574 --- /dev/null +++ b/include/linux/raid/libmd-report.h @@ -0,0 +1,27 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifndef _LIBMD_REPORT_H +#define _LIBMD_REPORT_H + +#ifdef MY_ABC_HERE +extern int (*funcSYNOSendRaidEvent)(unsigned int type, unsigned int raidno, + unsigned int diskno, unsigned long long sector); + +void syno_report_bad_sector(sector_t sector, unsigned long rw, + int md_minor, struct block_device *bdev, const char *func_name); + +void syno_report_correct_bad_sector(sector_t sector, int md_minor, + struct block_device *bdev, const char *func_name); + +void syno_report_faulty_device(int md_minor, struct block_device *bdev); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern int (*funcSYNOSendAutoRemapRaidEvent)(unsigned int, unsigned long long, unsigned int); +#endif /* MY_ABC_HERE */ +#endif /* _LIBMD_REPORT_H */ + diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index d7db17996322..e0b300de8f3f 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -158,4 +158,194 @@ static inline void rb_replace_node_cached(struct rb_node *victim, rb_replace_node(victim, new, &root->rb_root); } +/* + * The below helper functions use 2 operators with 3 different + * calling conventions. The operators are related like: + * + * comp(a->key,b) < 0 := less(a,b) + * comp(a->key,b) > 0 := less(b,a) + * comp(a->key,b) == 0 := !less(a,b) && !less(b,a) + * + * If these operators define a partial order on the elements we make no + * guarantee on which of the elements matching the key is found. See + * rb_find(). + * + * The reason for this is to allow the find() interface without requiring an + * on-stack dummy object, which might not be feasible due to object size. + */ + +/** + * rb_add_cached() - insert @node into the leftmost cached tree @tree + * @node: node to insert + * @tree: leftmost cached tree to insert @node into + * @less: operator defining the (partial) node order + */ +static __always_inline void +rb_add_cached(struct rb_node *node, struct rb_root_cached *tree, + bool (*less)(struct rb_node *, const struct rb_node *)) +{ + struct rb_node **link = &tree->rb_root.rb_node; + struct rb_node *parent = NULL; + bool leftmost = true; + + while (*link) { + parent = *link; + if (less(node, parent)) { + link = &parent->rb_left; + } else { + link = &parent->rb_right; + leftmost = false; + } + } + + rb_link_node(node, parent, link); + rb_insert_color_cached(node, tree, leftmost); +} + +/** + * rb_add() - insert @node into @tree + * @node: node to insert + * @tree: tree to insert @node into + * @less: operator defining the (partial) node order + */ +static __always_inline void +rb_add(struct rb_node *node, struct rb_root *tree, + bool (*less)(struct rb_node *, const struct rb_node *)) +{ + struct rb_node **link = &tree->rb_node; + struct rb_node *parent = NULL; + + while (*link) { + parent = *link; + if (less(node, parent)) + link = &parent->rb_left; + else + link = &parent->rb_right; + } + + rb_link_node(node, parent, link); + rb_insert_color(node, tree); +} + +/** + * rb_find_add() - find equivalent @node in @tree, or add @node + * @node: node to look-for / insert + * @tree: tree to search / modify + * @cmp: operator defining the node order + * + * Returns the rb_node matching @node, or NULL when no match is found and @node + * is inserted. + */ +static __always_inline struct rb_node * +rb_find_add(struct rb_node *node, struct rb_root *tree, + int (*cmp)(struct rb_node *, const struct rb_node *)) +{ + struct rb_node **link = &tree->rb_node; + struct rb_node *parent = NULL; + int c; + + while (*link) { + parent = *link; + c = cmp(node, parent); + + if (c < 0) + link = &parent->rb_left; + else if (c > 0) + link = &parent->rb_right; + else + return parent; + } + + rb_link_node(node, parent, link); + rb_insert_color(node, tree); + return NULL; +} + +/** + * rb_find() - find @key in tree @tree + * @key: key to match + * @tree: tree to search + * @cmp: operator defining the node order + * + * Returns the rb_node matching @key or NULL. + */ +static __always_inline struct rb_node * +rb_find(const void *key, const struct rb_root *tree, + int (*cmp)(const void *key, const struct rb_node *)) +{ + struct rb_node *node = tree->rb_node; + + while (node) { + int c = cmp(key, node); + + if (c < 0) + node = node->rb_left; + else if (c > 0) + node = node->rb_right; + else + return node; + } + + return NULL; +} + +/** + * rb_find_first() - find the first @key in @tree + * @key: key to match + * @tree: tree to search + * @cmp: operator defining node order + * + * Returns the leftmost node matching @key, or NULL. + */ +static __always_inline struct rb_node * +rb_find_first(const void *key, const struct rb_root *tree, + int (*cmp)(const void *key, const struct rb_node *)) +{ + struct rb_node *node = tree->rb_node; + struct rb_node *match = NULL; + + while (node) { + int c = cmp(key, node); + + if (c <= 0) { + if (!c) + match = node; + node = node->rb_left; + } else if (c > 0) { + node = node->rb_right; + } + } + + return match; +} + +/** + * rb_next_match() - find the next @key in @tree + * @key: key to match + * @tree: tree to search + * @cmp: operator defining node order + * + * Returns the next node matching @key, or NULL. + */ +static __always_inline struct rb_node * +rb_next_match(const void *key, struct rb_node *node, + int (*cmp)(const void *key, const struct rb_node *)) +{ + node = rb_next(node); + if (node && cmp(key, node)) + node = NULL; + return node; +} + +/** + * rb_for_each() - iterates a subtree matching @key + * @node: iterator + * @key: key to match + * @tree: tree to search + * @cmp: operator defining node order + */ +#define rb_for_each(node, key, tree, cmp) \ + for ((node) = rb_find_first((key), (tree), (cmp)); \ + (node); (node) = rb_next_match((key), (node), (cmp))) + #endif /* _LINUX_RBTREE_H */ diff --git a/include/linux/relay.h b/include/linux/relay.h index e13a333e7c37..0d5c51912f87 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/include/linux/relay.h @@ -51,6 +54,10 @@ struct rchan_buf size_t bytes_consumed; /* bytes consumed in cur read subbuf */ size_t early_bytes; /* bytes consumed before VFS inited */ unsigned int cpu; /* this buf's cpu */ + +#ifdef MY_ABC_HERE + spinlock_t lock; /* protect buffer write and read */ +#endif /* MY_ABC_HERE */ } ____cacheline_aligned; /* diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 8d04e7deedc6..297744ea4dd0 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -39,12 +39,15 @@ struct anon_vma { atomic_t refcount; /* - * Count of child anon_vmas and VMAs which points to this anon_vma. + * Count of child anon_vmas. Equals to the count of all anon_vmas that + * have ->parent pointing to this one, including itself. * * This counter is used for making decision about reusing anon_vma * instead of forking new one. See comments in function anon_vma_clone. */ - unsigned degree; + unsigned long num_children; + /* Count of VMAs whose ->anon_vma pointer points to this object. */ + unsigned long num_active_vmas; struct anon_vma *parent; /* Parent of this anon_vma */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 2660ee4b08ad..58aebc95b021 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_SCHED_H #define _LINUX_SCHED_H @@ -64,6 +67,9 @@ struct signal_struct; struct task_delay_info; struct task_group; struct io_uring_task; +#ifdef MY_ABC_HERE +struct work_acct; +#endif /* * Task state bitmask. NOTE! These bits are also @@ -1073,6 +1079,11 @@ struct task_struct { kernel_siginfo_t *last_siginfo; struct task_io_accounting ioac; + +#ifdef MY_ABC_HERE + struct work_acct *workacct; +#endif + #ifdef CONFIG_PSI /* Pressure stall state */ unsigned int psi_flags; diff --git a/include/linux/sched/loadavg.h b/include/linux/sched/loadavg.h index 83ec54b65e79..3536d0804d9b 100644 --- a/include/linux/sched/loadavg.h +++ b/include/linux/sched/loadavg.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_SCHED_LOADAVG_H #define _LINUX_SCHED_LOADAVG_H @@ -14,6 +17,9 @@ */ extern unsigned long avenrun[]; /* Load averages */ extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift); +#ifdef MY_ABC_HERE +extern void get_avenrun_split(unsigned long *io_loads, unsigned long *cpu_loads, unsigned long offset, int shift); +#endif /* MY_ABC_HERE */ #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1< #include +#ifdef MY_ABC_HERE +#define SYNO_OOB_TTY 2 +#define SYNO_TX_CHECK_COUNT 1000 +#define SYNO_TX_CHECK_THRESHOLD 800 +#define SYNO_CTS_CHECK_COUNT 10 +#endif /* MY_ABC_HERE */ /* * Counters of the input lines (CTS, DSR, RI, CD) interrupts diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 2b70f736b091..b9a86af6da6e 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * linux/include/linux/serial_8250.h @@ -139,6 +142,10 @@ struct uart_8250_port { /* Serial port overrun backoff */ struct delayed_work overrun_backoff; u32 overrun_backoff_time_ms; + +#ifdef MY_ABC_HERE + bool blXmitrCheck; +#endif /* MY_ABC_HERE */ }; static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up) diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index a5a5d1d4d7b1..65c339fda29e 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __SHMEM_FS_H #define __SHMEM_FS_H @@ -22,6 +25,9 @@ struct shmem_inode_info { struct list_head swaplist; /* chain of maybes on swap */ struct shared_policy policy; /* NUMA memory alloc policy */ struct simple_xattrs xattrs; /* list of xattrs */ +#ifdef MY_ABC_HERE + struct timespec64 crtime; /* File creation time */ +#endif /* MY_ABC_HERE */ atomic_t stop_eviction; /* hold when working on inode */ struct inode vfs_inode; }; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2d01b2bbb746..492a30cc8eb9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Definitions for the 'struct sk_buff' memory handlers. @@ -2874,6 +2877,27 @@ void napi_consume_skb(struct sk_buff *skb, int budget); void __kfree_skb_flush(void); void __kfree_skb_defer(struct sk_buff *skb); +#ifdef MY_ABC_HERE +static inline struct page *___dev_alloc_pages(gfp_t gfp_mask, + unsigned int order) +{ + gfp_mask |= __GFP_COMP; + + return alloc_pages_node(NUMA_NO_NODE, gfp_mask, order); + +} +static inline struct page *__dev_alloc_pages(gfp_t gfp_mask, + unsigned int order) +{ + gfp_mask |= __GFP_MEMALLOC; + + return ___dev_alloc_pages(gfp_mask, order); +} +static inline struct page *__dev_alloc_pages_wo_memalloc(unsigned int order) +{ + return ___dev_alloc_pages(GFP_ATOMIC | __GFP_NOWARN, order); +} +#else /* MY_ABC_HERE */ /** * __dev_alloc_pages - allocate page for network Rx * @gfp_mask: allocation priority. Set __GFP_NOMEMALLOC if not for network Rx @@ -2898,6 +2922,7 @@ static inline struct page *__dev_alloc_pages(gfp_t gfp_mask, return alloc_pages_node(NUMA_NO_NODE, gfp_mask, order); } +#endif /* MY_ABC_HERE */ static inline struct page *dev_alloc_pages(unsigned int order) { diff --git a/include/linux/soc/realtek/rtk_pd.h b/include/linux/soc/realtek/rtk_pd.h new file mode 100644 index 000000000000..ce64a16cb36a --- /dev/null +++ b/include/linux/soc/realtek/rtk_pd.h @@ -0,0 +1,14 @@ +#ifndef __SOC_REALTEK_PD_H +#define __SOC_REALTEK_PD_H + +enum rtk_pd_notication { + RTK_PD_NOTIFY_PRE_OFF = 0, + RTK_PD_NOTIFY_OFF, + RTK_PD_NOTIFY_PRE_ON, + RTK_PD_NOTIFY_ON +}; + +int rtk_pd_dev_pm_add_notifier(struct device *dev, struct notifier_block *nb); +void rtk_pd_dev_pm_remove_notifier(struct device *dev); + +#endif diff --git a/include/linux/splice.h b/include/linux/splice.h index a55179fd60fc..ee9cbea867be 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Function declerations and data structures related to the splice @@ -93,4 +96,12 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); extern const struct pipe_buf_operations page_cache_pipe_buf_ops; extern const struct pipe_buf_operations default_pipe_buf_ops; + +#ifdef MY_ABC_HERE +extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); +extern long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); +#endif /* MY_ABC_HERE */ #endif diff --git a/include/linux/stat.h b/include/linux/stat.h index fff27e603814..e15b0a291341 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_STAT_H #define _LINUX_STAT_H @@ -44,8 +47,22 @@ struct kstat { struct timespec64 mtime; struct timespec64 ctime; struct timespec64 btime; /* File creation time */ +#ifdef MY_ABC_HERE + struct timespec64 syno_create_time; +#endif /* MY_ABC_HERE */ u64 blocks; u64 mnt_id; +#ifdef MY_ABC_HERE + u32 syno_archive_bit; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u32 syno_archive_version; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned int syno_compressed; + bool is_inline; + unsigned int syno_flags; +#endif /* MY_ABC_HERE */ }; #endif diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h index d94d4f410507..68e9c0528aac 100644 --- a/include/linux/sunrpc/stats.h +++ b/include/linux/sunrpc/stats.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/include/linux/sunrpc/stats.h @@ -64,6 +67,10 @@ void rpc_proc_unregister(struct net *,const char *); void rpc_proc_zero(const struct rpc_program *); struct proc_dir_entry * svc_proc_register(struct net *, struct svc_stat *, const struct proc_ops *); +#ifdef MY_ABC_HERE +struct proc_dir_entry * svc_proc_register_name(struct net *, const char *name, + struct svc_stat *, const struct proc_ops *); +#endif /* MY_ABC_HERE */ void svc_proc_unregister(struct net *, const char *); void svc_seq_show(struct seq_file *, @@ -76,6 +83,10 @@ static inline void rpc_proc_zero(const struct rpc_program *p) {} static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s, const struct proc_ops *proc_ops) { return NULL; } +#ifdef MY_ABC_HERE +static inline struct proc_dir_entry *svc_proc_register_name(struct net *net, const char *name, + struct svc_stat *s, const struct proc_ops *proc_ops) { return NULL; } +#endif /* MY_ABC_HERE */ static inline void svc_proc_unregister(struct net *net, const char *p) {} static inline void svc_seq_show(struct seq_file *seq, diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 386628b36bc7..a81153e1b39c 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/include/linux/sunrpc/svc.h @@ -19,6 +22,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ /* statistics for svc_pool structures */ struct svc_pool_stats { @@ -26,6 +32,7 @@ struct svc_pool_stats { unsigned long sockets_queued; atomic_long_t threads_woken; atomic_long_t threads_timedout; + unsigned long congested; }; /* @@ -222,6 +229,29 @@ static inline void svc_putu32(struct kvec *iov, __be32 val) iov->iov_len += sizeof(__be32); } +#ifdef MY_ABC_HERE +struct svc_lat { + atomic64_t accu; // accumulated latency (us) + atomic_t max; // max latency (us) +}; + +static inline bool svc_update_lat(struct svc_lat *lat, s64 latency) +{ + atomic64_add(latency, &lat->accu); + + if (atomic_read(&lat->max) < latency) { + /* + * We do not use a spin_lock here because race conditions only + * possibly happen when max latency is small at beginning, and + * race conditions between small latencies doesn't matter. + */ + atomic_set(&lat->max, (int)latency); + return true; + } + return false; +} +#endif /* MY_ABC_HERE */ + /* * The context of a single thread, including the request currently being * processed. @@ -301,6 +331,12 @@ struct svc_rqst { * net namespace */ void ** rq_lease_breaker; /* The v4 client breaking a lease */ +#ifdef MY_ABC_HERE + ktime_t rq_xprt_rdtime; /* time of data being ready to transport on the socket */ +#ifdef MY_ABC_HERE + u64 vfs_latency_us; +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ }; #define SVC_NET(rqst) (rqst->rq_xprt ? rqst->rq_xprt->xpt_net : rqst->rq_bc_net) @@ -427,6 +463,9 @@ struct svc_version { u32 vs_nproc; /* number of procedures */ const struct svc_procedure *vs_proc; /* per-procedure info */ unsigned int *vs_count; /* call counts */ +#ifdef MY_ABC_HERE + struct svc_lat *vs_latency; /* latency record */ +#endif /* MY_ABC_HERE */ u32 vs_xdrsize; /* xdrsize needed for this version */ /* Don't register with rpcbind */ @@ -443,6 +482,10 @@ struct svc_version { * vs_dispatch == NULL means use default dispatcher. */ int (*vs_dispatch)(struct svc_rqst *, __be32 *); +#ifdef MY_ABC_HERE + void (*vs_store_latency_to_histogram)(u64, u64, u32); + void (*vs_store_resp_error)(struct svc_rqst *); +#endif /* MY_ABC_HERE */ }; /* diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index aca35ab5cff2..3382df3ab455 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * linux/include/linux/sunrpc/svc_xprt.h @@ -91,6 +94,9 @@ struct svc_xprt { const struct cred *xpt_cred; struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */ struct rpc_xprt_switch *xpt_bc_xps; /* NFSv4.1 backchannel */ +#ifdef MY_ABC_HERE + ktime_t xpt_eqtime; /* enqueue time */ +#endif /* MY_ABC_HERE */ }; static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) diff --git a/include/linux/syno_acl.h b/include/linux/syno_acl.h new file mode 100644 index 000000000000..8795b237be99 --- /dev/null +++ b/include/linux/syno_acl.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifndef _LINUX_SYNO_ACL_H +#define _LINUX_SYNO_ACL_H + +#include +#include +#include +#include +#include +#include + +/* e_tag entry in struct syno_acl_entry */ +#define SYNO_ACL_USER 0x01 +#define SYNO_ACL_GROUP 0x02 +#define SYNO_ACL_EVERYONE 0x04 +#define SYNO_ACL_OWNER 0x08 +#define SYNO_ACL_AUTHENTICATEDUSER 0x09 +#define SYNO_ACL_SYSTEM 0x0A +#define SYNO_ACL_TAG_ALL \ + (SYNO_ACL_USER | SYNO_ACL_GROUP | SYNO_ACL_OWNER | SYNO_ACL_EVERYONE) + +/* e_allow */ +#define SYNO_ACL_ALLOW 0x01 +#define SYNO_ACL_DENY 0x02 + +struct syno_acl_entry { + unsigned short e_tag; + unsigned int e_id; + unsigned int e_perm; + unsigned short e_inherit; + unsigned short e_allow; + unsigned int e_level; +}; + +struct syno_acl { + refcount_t a_refcount; + struct rcu_head a_rcu; + unsigned int a_count; + struct syno_acl_entry a_entries[0]; +}; + +#define FOREACH_SYNOACL_ENTRY(pa, acl, pe) \ + for (pa = (acl)->a_entries, pe = pa + (acl)->a_count; pa < pe; pa++) + +/* + * Duplicate an ACL handle. + */ +static inline struct syno_acl *syno_acl_dup(struct syno_acl *acl) +{ + if (acl) + refcount_inc(&acl->a_refcount); + return acl; +} + +/* + * Free an ACL handle. + */ +static inline void syno_acl_release(struct syno_acl *acl) +{ + if (acl && refcount_dec_and_test(&acl->a_refcount)) + kfree_rcu(acl, a_rcu); +} + +extern struct syno_acl *syno_acl_alloc(int count, gfp_t flags); +extern int syno_acl_valid(const struct syno_acl *); +extern struct syno_acl *syno_acl_realloc(struct syno_acl *acl, unsigned int counts, gfp_t flags); +extern struct syno_acl *syno_acl_clone(const struct syno_acl *acl, gfp_t flags); + +extern int syno_acl_to_xattr(const struct syno_acl *acl, void *buffer, size_t size); +extern struct syno_acl *syno_acl_from_xattr(const void *value, size_t size); + +static inline struct syno_acl *get_cached_syno_acl(struct inode *inode) +{ + struct syno_acl **p = &inode->i_syno_acl; + struct syno_acl *acl; + + for (;;) { + rcu_read_lock(); + acl = rcu_dereference(*p); + if (!acl || is_uncached_syno_acl(acl) || + refcount_inc_not_zero(&acl->a_refcount)) + break; + rcu_read_unlock(); + cpu_relax(); + } + rcu_read_unlock(); + return acl; +} + +static inline void set_cached_syno_acl(struct inode *inode, struct syno_acl *acl) +{ + struct syno_acl **p = &inode->i_syno_acl; + struct syno_acl *old = NULL; + + old = xchg(p, syno_acl_dup(acl)); + if (!is_uncached_syno_acl(old)) + syno_acl_release(old); +} + +extern void forget_cached_syno_acl(struct inode *inode); +extern bool syno_acl_module_get(void); +extern void syno_acl_module_put(void); + +extern int synoacl_op_permission(struct dentry *dentry, int perm); +extern int synoacl_op_exec_permission(struct dentry *dentry, struct inode *inode); +extern int synoacl_op_archive_bit_change_ok(struct dentry *dentry, unsigned int cmd, int tag, int mask); +extern int synoacl_op_setattr_prepare(struct dentry *dentry, struct iattr *attr); +extern int synoacl_op_setattr_post(struct dentry *dentry, struct iattr *attr); +extern int synoacl_op_may_delete(struct dentry *victim, struct inode *dir); +extern int synoacl_op_may_access(struct dentry *dentry, int mode); +extern int synoacl_op_acl_xattr_get(struct dentry *dentry, int cmd, void *value, size_t size); +extern void synoacl_op_to_mode(struct dentry *dentry, struct kstat *stat); +extern int synoacl_op_init(struct dentry *dentry); +extern int synoacl_op_xattr_permission(const char *name, struct dentry *dentry, unsigned int perm); + +extern int synoacl_mod_permission(struct dentry *, int); +extern int synoacl_mod_exec_permission(struct dentry *); +extern int synoacl_mod_archive_bit_change_ok(struct dentry *, unsigned int, int, int); +extern int synoacl_mod_setattr_prepare(struct dentry *, struct iattr *); +extern int synoacl_mod_setattr_post(struct dentry *, struct iattr *); +extern int synoacl_mod_may_delete(struct dentry *, struct inode *); +extern int synoacl_mod_may_access(struct dentry *, int); +extern int synoacl_mod_acl_xattr_get(struct dentry *, int, void *, size_t); +extern void synoacl_mod_to_mode(struct dentry *, struct kstat *); +extern int synoacl_mod_init(struct dentry *, struct inode *); + +extern struct syno_acl *syno_acl_from_disk(const void *value, size_t size); +extern void * syno_acl_to_disk(const struct syno_acl *acl, size_t *size); +#endif /* _LINUX_SYNO_ACL_H */ diff --git a/include/linux/syno_acl_xattr.h b/include/linux/syno_acl_xattr.h new file mode 100644 index 000000000000..d3889db59c85 --- /dev/null +++ b/include/linux/syno_acl_xattr.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2022 Synology Inc. + */ +#ifndef _LINUX_SYNO_ACL_XATTR_H +#define _LINUX_SYNO_ACL_XATTR_H + +#define SYNO_ACL_VERSION 0x0002 + +typedef struct { + __le16 e_tag; + __le16 e_inherit; + __le32 e_perm; + __le32 e_id; +} __attribute__ ((__packed__)) syno_acl_entry_t; + +typedef struct { + __le16 a_version; +} __attribute__ ((__packed__)) syno_acl_header_t; + +#endif /* _LINUX_SYNO_ACL_XATTR_H */ diff --git a/include/linux/syno_fdt.h b/include/linux/syno_fdt.h new file mode 100644 index 000000000000..45a00615f4f6 --- /dev/null +++ b/include/linux/syno_fdt.h @@ -0,0 +1,21 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2020 Synology Inc. All rights reserved. */ +#ifndef __SYNO_FDT_H_ +#define __SYNO_FDT_H_ + +#include +#include +#include + +#ifdef MY_ABC_HERE +int syno_pmbus_property_get(unsigned int *pmbus_property, const char *property_name, int index); +#endif /* MY_ABC_HERE */ +bool syno_of_i2c_driver_match_device(struct device *dev, const struct device_driver *drv); +struct device_node* syno_of_i2c_bus_match(struct device *dev, int* index); +struct device_node* syno_of_i2c_device_match(struct i2c_client *client, const char *i2c_dev_name, struct device_node *pI2CNode); +struct device_node* syno_of_i2c_adapter_match(struct i2c_adapter *adap); +struct i2c_adapter* syno_i2c_adapter_get_by_node(struct device_node *pI2CBusNode); + +#endif /* __SYNO_FDT_H_ */ diff --git a/include/linux/syno_fs.h b/include/linux/syno_fs.h new file mode 100644 index 000000000000..4eebcc823ef7 --- /dev/null +++ b/include/linux/syno_fs.h @@ -0,0 +1,337 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2022 Synology Inc. + */ +#ifndef _LINUX_SYNO_FS_H +#define _LINUX_SYNO_FS_H + +#ifdef MY_ABC_HERE +static inline int syno_op_get_archive_bit(struct dentry *dentry, unsigned int *archive_bit) +{ + int err = 0; + struct inode *inode = dentry->d_inode; + + if (inode->i_op->syno_get_archive_bit) { + err = inode->i_op->syno_get_archive_bit(dentry, archive_bit, 0); + if (-ENODATA == err) { + err = 0; + *archive_bit= 0; + } + } else { + *archive_bit = inode->i_archive_bit; + } + + return err; +} + +static inline int syno_op_set_archive_bit_nolock(struct dentry *dentry, unsigned int archive_bit) +{ + int err = 0; + struct inode *inode = dentry->d_inode; + + if (inode->i_op->syno_set_archive_bit) { + err = inode->i_op->syno_set_archive_bit(dentry, archive_bit); + } else { + return -EOPNOTSUPP; + } + + return err; +} + +static inline int syno_op_set_archive_bit(struct dentry *dentry, unsigned int archive_bit) +{ + int err = 0; + struct inode *inode = dentry->d_inode; + + mutex_lock(&inode->i_archive_bit_mutex); + err = syno_op_set_archive_bit_nolock(dentry, archive_bit); + mutex_unlock(&inode->i_archive_bit_mutex); + return err; +} + +long syno_archive_bit_set(struct dentry *dentry, unsigned int cmd); +long syno_archive_bit_overwrite(struct dentry *dentry, unsigned int flags); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline int syno_op_get_crtime(struct inode *inode, struct timespec64 *time) +{ + int error = 0; + + if (!inode->i_op->syno_get_crtime) + return -EOPNOTSUPP; + + inode_lock(inode); + error = inode->i_op->syno_get_crtime(inode, time); + inode_unlock(inode); + + return error; +} + +static inline int syno_op_set_crtime(struct inode *inode, struct timespec64 *time) +{ + int error = 0; + + if (!inode->i_op->syno_set_crtime) + return -EOPNOTSUPP; + + inode_lock(inode); + error = inode->i_op->syno_set_crtime(inode, time); + inode_unlock(inode); + + return error; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline int syno_op_get_sb_archive_version(struct super_block *sb, + u32 *version) +{ + int ret = 0; + + if (!sb->s_op->syno_get_sb_archive_version) + return -EOPNOTSUPP; + down_read(&sb->s_archive_version_rwsem); + ret = sb->s_op->syno_get_sb_archive_version(sb, version); + up_read(&sb->s_archive_version_rwsem); + return ret; +} +static inline int syno_op_set_sb_archive_version(struct super_block *sb, + u32 version) +{ + int ret = 0; + + if (!sb->s_op->syno_set_sb_archive_version) + return -EOPNOTSUPP; + down_write(&sb->s_archive_version_rwsem); + ret = sb->s_op->syno_set_sb_archive_version(sb, version); + up_write(&sb->s_archive_version_rwsem); + return ret; +} +static inline int syno_op_get_inode_archive_version(struct dentry *dentry, + u32 *version) +{ + int ret = 0; + struct inode *inode = d_inode(dentry); + + if (!inode->i_op->syno_get_archive_version) + return -EOPNOTSUPP; + mutex_lock(&inode->i_archive_version_mutex); + ret = inode->i_op->syno_get_archive_version(dentry, version); + mutex_unlock(&inode->i_archive_version_mutex); + return ret; +} +static inline int syno_op_set_inode_archive_version(struct dentry *dentry, + u32 version) +{ + int ret = 0; + struct inode *inode = d_inode(dentry); + u32 old_version; + + if (!inode->i_op->syno_set_archive_version) + return -EOPNOTSUPP; + mutex_lock(&inode->i_archive_version_mutex); + if (inode->i_op->syno_get_archive_version) { + ret = inode->i_op->syno_get_archive_version(dentry, &old_version); + if (!ret && old_version == version) + goto out_lock; + } + ret = inode->i_op->syno_set_archive_version(dentry, version); +out_lock: + mutex_unlock(&inode->i_archive_version_mutex); + return ret; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline int syno_op_locker_mode_get(struct inode *inode, enum locker_mode *mode) +{ + if (!inode->i_op->syno_locker_mode_get) + return -EOPNOTSUPP; + + return inode->i_op->syno_locker_mode_get(inode, mode); +} + +static inline int syno_op_locker_state_get(struct inode *inode, enum locker_state *state) +{ + if (!inode->i_op->syno_locker_state_get) + return -EOPNOTSUPP; + + return inode->i_op->syno_locker_state_get(inode, state); +} + +static inline int syno_op_locker_state_set(struct inode *inode, enum locker_state state) +{ + if (!inode->i_op->syno_locker_state_set) + return -EOPNOTSUPP; + + return inode->i_op->syno_locker_state_set(inode, state); +} + +static inline int syno_op_locker_period_end_set(struct inode *inode, struct timespec64 *time) +{ + if (!inode->i_op->syno_locker_period_end_set) + return -EOPNOTSUPP; + + return inode->i_op->syno_locker_period_end_set(inode, time); +} + +#define LOCKER_CHUNK_SIZE SZ_64K +#define LOCKER_DEFAULT_WAITTIME TIME64_MAX +#define LOCKER_DEFAULT_DURATION TIME64_MAX +#define LOCKER_DEFAULT_UPDATE_TIME TIME64_MAX +#define LOCKER_DEFAULT_PERIOD_BEGIN TIME64_MAX +#define LOCKER_DEFAULT_PERIOD_END TIME64_MIN + +#define IS_LOCKER_STATE_APPENDABLE(state) \ + ((state) == LS_APPENDABLE || (state) == LS_EXPIRED_A || (state) == LS_W_APPENDABLE) +#define IS_LOCKER_STATE_IMMUTABLE(state) \ + ((state) == LS_IMMUTABLE || (state) == LS_EXPIRED_I || (state) == LS_W_IMMUTABLE) +#define IS_LOCKER_STATE_EXPIRED(state) \ + ((state) == LS_EXPIRED_I || (state) == LS_EXPIRED_A) + +static inline bool syno_op_locker_is_open(struct inode *inode) +{ + int ret; + enum locker_state state; + + ret = syno_op_locker_state_get(inode, &state); + if (ret) + return true; + + return state == LS_OPEN; +} + +static inline bool syno_op_locker_is_appendable(struct inode *inode) +{ + int ret; + enum locker_state state; + + ret = syno_op_locker_state_get(inode, &state); + if (ret) + return false; + + return IS_LOCKER_STATE_APPENDABLE(state); +} + +static inline bool syno_op_locker_is_immutable(struct inode *inode) +{ + int ret; + enum locker_state state; + + ret = syno_op_locker_state_get(inode, &state); + if (ret) + return false; + + return IS_LOCKER_STATE_IMMUTABLE(state); +} + +static inline bool syno_op_locker_is_expired(struct inode *inode) +{ + int ret; + enum locker_state state; + + ret = syno_op_locker_state_get(inode, &state); + if (ret) + return false; + + return IS_LOCKER_STATE_EXPIRED(state); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static inline int syno_op_getattr(struct dentry *dentry, + struct kstat *stat, + unsigned int syno_flags) +{ + struct inode *inode = d_inode(dentry); + + if (!syno_flags) + return 0; + + /* all requested fields will be assigned a default value in VFS, and + * be overwritten later in each filesystem or not. + */ + if (syno_flags & SYNOST_IS_INLINE) + stat->is_inline = false; + if (syno_flags & SYNOST_COMPRESSION) + stat->syno_compressed = 0; +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_BIT) + stat->syno_archive_bit = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_VER) + stat->syno_archive_version = 0; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_CREATE_TIME) { + stat->syno_create_time.tv_sec = 0; + stat->syno_create_time.tv_nsec = 0; + } +#endif /* MY_ABC_HERE */ + + if (inode->i_op->syno_getattr) + return inode->i_op->syno_getattr(dentry, stat, syno_flags); + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define IS_SYNOACL_SUPERUSER() (uid_eq(KUIDT_INIT(0), current_fsuid())) + +/* + * may_not_block indicates that caller doesn't expect this function to block. + * If this function might block, return -ECHILD so that caller can handle + * it appropriately. For example in ceph or fuse, getting archive bit may need + * to send request to remote and wait for the reply. + */ +static inline int +is_syno_archive_bit_enable(struct inode *inode, struct dentry * dentry, + unsigned int archive_bit, int may_not_block) +{ + if (inode->i_op->syno_get_archive_bit) { + unsigned int tmp = 0; + int err = inode->i_op->syno_get_archive_bit(dentry, &tmp, may_not_block); + if (-ECHILD == err) // the only error seen by caller is ECHILD + return err; + + if (!err && (archive_bit & tmp)) + return 1; + + if (-EOPNOTSUPP != err) // err or archive_bit not enabled + return 0; + } + + if (inode->i_archive_bit & archive_bit) + return 1; + + return 0; +} + +/* + * IS_INODE_SYNOACL_NOBLOCK will return 1 if inode acl is supported + * 0 if inode acl is NOT supported, or error other than ECHILD happens + * -ECHILD checking inode acl support may block + */ +#define IS_INODE_SYNOACL_NOBLOCK(inode, dentry) is_syno_archive_bit_enable(inode, dentry, S2_SYNO_ACL_SUPPORT, 1) +#define IS_INODE_SYNOACL(inode, dentry) is_syno_archive_bit_enable(inode, dentry, S2_SYNO_ACL_SUPPORT, 0) +#define IS_SMB_READONLY(dentry) is_syno_archive_bit_enable(dentry->d_inode, dentry, S2_SMB_READONLY, 0) +#define IS_SYNOACL_INHERIT(dentry) is_syno_archive_bit_enable(dentry->d_inode, dentry, S2_SYNO_ACL_INHERIT, 0) +#define IS_SYNOACL_EXIST(dentry) is_syno_archive_bit_enable(dentry->d_inode, dentry, S2_SYNO_ACL_EXIST, 0) +#define HAS_SYNOACL(dentry) is_syno_archive_bit_enable(dentry->d_inode, dentry, (S2_SYNO_ACL_EXIST | S2_SYNO_ACL_INHERIT), 0) +#define IS_SYNOACL_OWNER_IS_GROUP(dentry) is_syno_archive_bit_enable(dentry->d_inode, dentry, S2_SYNO_ACL_IS_OWNER_GROUP, 0) + +#define IS_FS_SYNOACL(inode) __IS_FLG(inode, SB_SYNOACL) +#define IS_SYNOACL(dentry) (IS_FS_SYNOACL(dentry->d_inode) && IS_INODE_SYNOACL(dentry->d_inode, dentry)) +#define IS_SYNOACL_INODE(inode, dentry) (IS_FS_SYNOACL(inode) && IS_INODE_SYNOACL(inode, dentry)) + +#define is_synoacl_owner(dentry) IS_SYNOACL_OWNER_IS_GROUP(dentry)?in_group_p(dentry->d_inode->i_gid):(uid_eq(dentry->d_inode->i_uid, current_fsuid())) +#define is_synoacl_owner_or_capable(dentry) (is_synoacl_owner(dentry) || capable(CAP_FOWNER)) +#endif /* MY_ABC_HERE */ + +#endif /* _LINUX_SYNO_FS_H */ diff --git a/include/linux/syno_gpio.h b/include/linux/syno_gpio.h new file mode 100644 index 000000000000..9e8d390f6939 --- /dev/null +++ b/include/linux/syno_gpio.h @@ -0,0 +1,161 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2009-2020 Synology Inc. All rights reserved. */ +#ifndef SYNO_GPIO_TYPE_H +#define SYNO_GPIO_TYPE_H + +#include + +#define GPIO_UNDEF 0xFF +#define SYNO_GPIO_PIN_MAX_NUM 8 + +#define INPUT 0 +#define OUTPUT 1 + +#define INIT_LOW 0 +#define INIT_HIGH 1 +#define INIT_KEEP_VALUE 0xFF + +#define ACTIVE_HIGH 0 +#define ACTIVE_LOW 1 +#define ACTIVE_IGNORE 0xFF + +#ifdef MY_ABC_HERE +#include +enum SYNO_GPIO_INDEX +{ + SYNO_GPIO_PIN = 0, + SYNO_POLARITY_PIN, + + /* Must be the last item, DO NOT append after this. */ + SYNO_GPIO_INDEX_MAX +}; +#endif /* MY_ABC_HERE */ + +/* The following GPIO macro are 1-based */ +#define HAVE_GPIO_PIN(index, type) ((syno_gpio.type) && (0 < index) && (index <= syno_gpio.type->nr_gpio)) +#define GPIO_PORT(index, type) syno_gpio.type->gpio_port[index-1] +#define GPIO_POLARITY(type) syno_gpio.type->gpio_polarity + +#define HAVE_FAN_CTRL(index) HAVE_GPIO_PIN(index, fan_ctrl) +#define HAVE_FAN_FAIL(index) HAVE_GPIO_PIN(index, fan_fail) +#ifdef MY_ABC_HERE +#define HAVE_HDD_DETECT(index) syno_disk_gpio_pin_have(index, DT_DETECT_PIN_GPIO) +#define HAVE_HDD_ENABLE(index) syno_disk_gpio_pin_have(index, DT_POWER_PIN_GPIO) +/* Testify existence of led pin of "name@index" */ +#define HAVE_HDD_FAIL_LED_BY_SLOT(name, index) syno_led_pin_have(name, index, DT_HDD_ORANGE_LED) +#define HAVE_HDD_PRESENT_LED_BY_SLOT(name, index) syno_led_pin_have(name, index, DT_HDD_GREEN_LED) +#define HAVE_HDD_ACT_LED_BY_SLOT(name, index) syno_led_pin_have(name, index, DT_HDD_ACT_LED) +#endif /* MY_ABC_HERE */ + +#define HAVE_MODEL_ID(index) HAVE_GPIO_PIN(index, model_id) +#define HAVE_ALARM_LED() HAVE_GPIO_PIN(1, alarm_led) +#define HAVE_POWER_LED() HAVE_GPIO_PIN(1, power_led) +#define HAVE_DISK_LED_CTRL() HAVE_GPIO_PIN(1, disk_led_ctrl) +#define HAVE_PHY_LED_CTRL() HAVE_GPIO_PIN(1, phy_led_ctrl) +#define HAVE_COPY_BUTTON_DETECT() HAVE_GPIO_PIN(1, copy_button_detect) +#define HAVE_MUTE_BUTTON_DETECT() HAVE_GPIO_PIN(1, mute_button_detect) +#define HAVE_BUZZER_MUTE_CTRL() HAVE_GPIO_PIN(1, buzzer_mute_ctrl) +#define HAVE_RP_DETECT(index) HAVE_GPIO_PIN(index, redundant_power_detect) +#define HAVE_RP_FAN_CTRL() HAVE_GPIO_PIN(1, redundant_power_fan_ctrl) + +#define FAN_CTRL_PIN(index) GPIO_PORT(index, fan_ctrl) +#define FAN_FAIL_PIN(index) GPIO_PORT(index, fan_fail) +#ifdef MY_ABC_HERE +#define HDD_DETECT_PIN(index) syno_disk_gpio_pin_get(index, DT_DETECT_PIN_GPIO, SYNO_GPIO_PIN) +#define HDD_ENABLE_PIN(index) syno_disk_gpio_pin_get(index, DT_POWER_PIN_GPIO, SYNO_GPIO_PIN) +#define HDD_SWITCH_NO(index) syno_disk_gpio_pin_get(index, DT_SWITCH_NO, 0) /* only one value for switch no */ +/* Get led pin# of "name@index" */ +#define HDD_FAIL_LED_PIN_BY_SLOT(name, index) syno_led_pin_get(name, index, DT_HDD_ORANGE_LED, SYNO_GPIO_PIN) +#define HDD_PRESENT_LED_PIN_BY_SLOT(name, index) syno_led_pin_get(name, index, DT_HDD_GREEN_LED, SYNO_GPIO_PIN) +#define HDD_ACT_LED_PIN_BY_SLOT(name, index) syno_led_pin_get(name, index, DT_HDD_ACT_LED, SYNO_GPIO_PIN) +#define HDD_FAIL_LED_NAME_BY_SLOT(name, index, led_name, length) syno_led_name_get(name, index, DT_HDD_ORANGE_LED, led_name, length) +#define HDD_PRESENT_LED_NAME_BY_SLOT(name, index, led_name, length) syno_led_name_get(name, index, DT_HDD_GREEN_LED, led_name, length) +#define HDD_ACT_LED_NAME_BY_SLOT(name, index, led_name, length) syno_led_name_get(name, index, DT_HDD_ACT_LED, led_name, length) +#endif /* MY_ABC_HERE */ + +#define MODEL_ID_PIN(index) GPIO_PORT(index, model_id) +#define ALARM_LED_PIN() GPIO_PORT(1, alarm_led) +#define POWER_LED_PIN() GPIO_PORT(1, power_led) +#define DISK_LED_CTRL_PIN() GPIO_PORT(1, disk_led_ctrl) +#define PHY_LED_CTRL_PIN() GPIO_PORT(1, phy_led_ctrl) +#define COPY_BUTTON_DETECT_PIN() GPIO_PORT(1, copy_button_detect) +#define MUTE_BUTTON_DETECT_PIN() GPIO_PORT(1, mute_button_detect) +#define BUZZER_MUTE_CTRL_PIN() GPIO_PORT(1, buzzer_mute_ctrl) +#define RP_DETECT_PIN(index) GPIO_PORT(index, redundant_power_detect) +#define RP_FAN_CTRL_PIN() GPIO_PORT(1, redundant_power_fan_ctrl) + +#define FAN_CTRL_POLARITY() GPIO_POLARITY(fan_ctrl) +#define FAN_FAIL_POLARITY() GPIO_POLARITY(fan_fail) +#ifdef MY_ABC_HERE +#define HDD_DETECT_POLARITY(index) syno_disk_gpio_pin_get(index, DT_DETECT_PIN_GPIO, SYNO_POLARITY_PIN) +#define HDD_ENABLE_POLARITY(index) syno_disk_gpio_pin_get(index, DT_POWER_PIN_GPIO, SYNO_POLARITY_PIN) +/* Get led pin polarity of "name@index" */ +#define HDD_FAIL_LED_POLARITY_BY_SLOT(name, index) syno_led_pin_get(name, index, DT_HDD_ORANGE_LED, SYNO_POLARITY_PIN) +#define HDD_PRESENT_LED_POLARITY_BY_SLOT(name, index) syno_led_pin_get(name, index, DT_HDD_GREEN_LED, SYNO_POLARITY_PIN) +#define HDD_ACT_LED_POLARITY_BY_SLOT(name, index) syno_led_pin_get(name, index, DT_HDD_ACT_LED, SYNO_POLARITY_PIN) +#endif /* MY_ABC_HERE */ +#define MODEL_ID_POLARITY() GPIO_POLARITY(model_id) +#define ALARM_LED_POLARITY() GPIO_POLARITY(alarm_led) +#define POWER_LED_POLARITY() GPIO_POLARITY(power_led) +#define DISK_LED_CTRL_POLARITY() GPIO_POLARITY(disk_led_ctrl) +#define PHY_LED_CTRL_POLARITY() GPIO_POLARITY(phy_led_ctrl) +#define COPY_BUTTON_DETECT_POLARITY() GPIO_POLARITY(copy_button_detect) +#define MUTE_BUTTON_DETECT_POLARITY() GPIO_POLARITY(mute_button_detect) +#define BUZZER_MUTE_CTRL_POLARITY() GPIO_POLARITY(buzzer_mute_ctrl) +#define RP_DETECT_POLARITY() GPIO_POLARITY(redundant_power_detect) +#define RP_FAN_CTRL_POLARITY() GPIO_POLARITY(redundant_power_fan_ctrl) + +typedef struct _tag_SYNO_GPIO_INFO { + const char *name; + u8 nr_gpio; + u8 gpio_port[SYNO_GPIO_PIN_MAX_NUM]; + u8 gpio_direction; + u8 gpio_init_value; + u8 gpio_polarity; +} SYNO_GPIO_INFO; + +typedef struct __tag_SYNO_GPIO { + SYNO_GPIO_INFO *fan_ctrl; + SYNO_GPIO_INFO *fan_fail; + SYNO_GPIO_INFO *hdd_fail_led; + SYNO_GPIO_INFO *hdd_present_led; + SYNO_GPIO_INFO *hdd_act_led; + SYNO_GPIO_INFO *hdd_detect; + SYNO_GPIO_INFO *hdd_enable; + SYNO_GPIO_INFO *model_id; + SYNO_GPIO_INFO *alarm_led; + SYNO_GPIO_INFO *power_led; + SYNO_GPIO_INFO *disk_led_ctrl; // control all disk led on/off + SYNO_GPIO_INFO *phy_led_ctrl; // control all phy led on/off + SYNO_GPIO_INFO *copy_button_detect; + SYNO_GPIO_INFO *mute_button_detect; + SYNO_GPIO_INFO *buzzer_mute_ctrl; + SYNO_GPIO_INFO *redundant_power_detect; + SYNO_GPIO_INFO *redundant_power_fan_ctrl; +} SYNO_GPIO; + +#ifdef MY_ABC_HERE +u32 syno_disk_gpio_pin_get(const int diskPort, const char *szPropertyName, const int propertyIndex); +int syno_disk_gpio_pin_have(const int diskPort, const char *szPropertyName); +u32 syno_led_pin_get(const char* name, const int diskPort, const char *szLedName, const int propertyIndex); +int syno_led_pin_have(const char* name, const int diskPort, const char *szLedName); +int syno_led_type_get(const char* szSlotName, const int diskPort, char *szSynoLedType, unsigned int cbSynoLedType); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern void syno_gpio_direction_output(int pin, int pValue); +extern void syno_gpio_direction_input(int pin); +extern int syno_gpio_to_irq(int pin); +extern int SYNO_GPIO_READ(int pin); +extern void SYNO_GPIO_WRITE(int pin, int pValue); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +extern void DBG_SpinupGroupListGpio(void); +extern int SynoHaveRPDetectPin(void); +extern int SynoAllRedundantPowerDetected(void); +#endif /* MY_DEF_HERE */ + +#endif /* SYNO_GPIO_TYPE_H */ diff --git a/include/linux/synobios.h b/include/linux/synobios.h new file mode 100644 index 000000000000..ed91efbebb17 --- /dev/null +++ b/include/linux/synobios.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifndef _LINUX_SYNOBIOS_H +#define _LINUX_SYNOBIOS_H + +#include + +#endif /* _LINUX_SYNOBIOS_H */ diff --git a/include/linux/synolib.h b/include/linux/synolib.h new file mode 100644 index 000000000000..b504d6da8e1e --- /dev/null +++ b/include/linux/synolib.h @@ -0,0 +1,276 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2020 Synology Inc. All rights reserved. +#ifndef __SYNOLIB_H_ +#define __SYNOLIB_H_ + +#include +#include + +#ifdef MY_ABC_HERE +/* Maximum number of MAC addresses */ +#define SYNO_MAC_MAX_NUMBER 8 +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +void syno_draw_auto_remap_buffer(char *buffer, int size); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int SynoNVMeGetDeviceIndex(struct gendisk *disk); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int syno_disk_get_device_index(struct block_device *bdev); +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE +int syno_pci_dev_to_i2c_bus(struct pci_dev*); +struct syno_device_list { + char disk_name[DISK_NAME_LEN]; + struct list_head device_list; +}; +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +#define DT_INTERNAL_SLOT "internal_slot" +#define DT_ESATA_SLOT "esata_port" +#ifdef MY_DEF_HERE +#define DT_EUNIT_SLOT "eunit_slot" +#define DT_PCIE_EUNIT_MASTER_PORT "pcie_eunit_master_port" +#define DT_PCIE_EUNIT_NEXT_PORT "pcie_eunit_next_port" +#define DT_PCIE_EUNIT_SSID "pcie_eunit_ssid" +#define DT_PCIE_EUNIT_SLOT "pcie_eunit_slot" +#endif /* MY_DEF_HERE */ +#define DT_CX4_SLOT "cx4_port" +#define DT_PCIE_SLOT "pcie_slot" +#define DT_USB_SLOT "usb_slot" +#define DT_HUB_SLOT "usb_hub" +#define DT_POWER_PIN_GPIO "power_pin_gpio" +#define DT_DETECT_PIN_GPIO "detect_pin_gpio" +#define DT_SWITCH_NO "switch_no" +#define DT_HDD_LED_TYPE "led_type" +#define DT_HDD_LED_TYPE_LP3943 "lp3943" +#define DT_HDD_LED_TYPE_ATMEGA1608 "atmega1608" +#define DT_HDD_LED_TYPE_GPIO "gpio" +#define DT_HDD_LED_TYPE_TRIG_DISK_SYNO "trig_disk_syno" +#define DT_HDD_ORANGE_LED "led_orange" +#define DT_HDD_GREEN_LED "led_green" +#define DT_HDD_LED_NAME "led_name" +#define DT_HDD_ACT_LED "led_activity" +#define DT_SYNO_GPIO "syno_gpio" +#define DT_PCIE_ROOT "pcie_root" +#define DT_ATA_PORT "ata_port" +#define DT_AHCI "ahci" +#define DT_RTK_AHCI "rtk_ahci" +#define DT_AHCI_MVEBU "ahci_mvebu" +#define DT_MV14XX "mv14xx" +#define DT_VIRTIO "virtio" +#define DT_PHY "phy" +#define DT_USB2 "usb2" +#define DT_USB3 "usb3" +#define DT_USB_PORT "usb_port" +#define DT_USB_HUB "usb_hub" +#define DT_USB_COPY "usb_copy" +#define DT_VBUS "vbus" +#define DT_SHARED "shared" +#define DT_SYNO_SPINUP_GROUP "syno_spinup_group" +#define DT_SYNO_SPINUP_GROUP_DELAY "syno_spinup_group_delay" +#define DT_HDD_POWERUP_SEQ "syno_hdd_powerup_seq" +#define DT_PROPERTY_SW_ACTIVITY "sw_activity" +#define DT_DISK_LED_TYPE_GPIO "gpio" +#define DT_FORM_FACTOR "form_factor" +#define DT_EXPANDER "expander" +#define DT_MODEL_NAME "model_name" +#define DT_SWITCHTEC "switchtec" +#define DT_LED_OFF_GPIO "led_off_gpio" +#define DT_I2C_BUS "i2c_bus" +#define DT_I2C_DEVICE "i2c_device" +#define DT_I2C_ADDRESS "i2c_address" +#define DT_I2C_DEVICE_NAME "i2c_device_name" +#define DT_DEVICE_INDEX "device_index" +#define DT_ACPI_HID "acpi_hid" +#define DT_ACPI_UID "acpi_uid" +#define DT_PHY_ID "phy_id" +#define DT_SAS "sas" + +#define DT_SYSTEM_SLOT "system_slot" +#define DT_MV9XXX "mv9xxx" +#define DT_JMB585 "jmb585" +#define DT_ASM1061 "asm1061" +#define DT_ASM116x "asm116x" +#define DT_SIGNAL_DATA_GEN_FMT "signal_data_gen%d" +#define DT_SET_SSC_OFF "set_ssc_off" + +#ifdef MY_ABC_HERE +#define DT_SYNO_HDD_SMBUS_TYPE "syno_smbus_hdd_type" +#define DT_SYNO_HDD_SMBUS_ADAPTER "syno_smbus_hdd_adapter" +#define DT_SYNO_HDD_SMBUS_ADDRESS "syno_smbus_hdd_address" + +#define SMBUS_SWITCH_MAX_COUNT 16 +#define DT_SYNO_SMBUS_SWITCH_ADAPTERS "syno_smbus_switch_adapters" +#define DT_SYNO_SMBUS_SWITCH_ADDRS "syno_smbus_switch_addrs" +#define DT_SYNO_SMBUS_SWITCH_VALS "syno_smbus_switch_vals" +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define DT_SYNO_PMBUS_ADAPTER "syno_pmbus_adapter" +#define DT_SYNO_PMBUS_ADDRESS "syno_pmbus_address" +#define DT_SYNO_PMBUS_PIN_REG "syno_pmbus_pin_register" +#define DT_SYNO_PMBUS_POUT_REG "syno_pmbus_pout_register" +#define DT_SYNO_PMBUS_TEMP1_REG "syno_pmbus_temp1_register" +#define DT_SYNO_PMBUS_TEMP2_REG "syno_pmbus_temp2_register" +#define DT_SYNO_PMBUS_TEMP3_REG "syno_pmbus_temp3_register" +#define DT_SYNO_PMBUS_FAN_REG "syno_pmbus_fan_register" +#define DT_SYNO_PMBUS_STATUS_REG "syno_pmbus_status_register" +#define DT_SYNO_PMBUS_PSU_OFF_BIT "syno_pmbus_psu_off_bit" +#define DT_SYNO_PMBUS_PSU_PRESENT_BIT "syno_pmbus_psu_present_bit" +#endif /* MY_ABC_HERE */ + +#define SZ_DTS_EBOX_I2C_PWR_BTN "power_btn" +#define SZ_DTS_EBOX_I2C_OFFSET "offset" +#define SZ_DTS_EBOX_I2C_MASK "mask" +#define SZ_DTS_EBOX_I2C_PWR_CTL "power_control" +#define SZ_DTS_EBOX_I2C_SN_READ "ebox_sn_read" +#define SZ_DTS_EBOX_RP "rp_power" +#define SZ_DTS_EBOX_RP_INFO "rp_power_info" +#define SZ_DTS_EBOX_I2C_DEEPSELLP_CTL "deep_sleep_control" +#define SZ_DTS_EBOX_I2C_DEEPSELLP_INDICATOR "deep_sleep_indicator" +#define SZ_DTS_EBOX_I2C_REG_MANUAL_ENABLE "reg_manual_enable" + +#define SYNO_DTS_PROPERTY_CONTENT_LENGTH 128 // If used to retrive PCIe path, can only accept 9 layer PCIe switch. +#define MAX_NODENAME_LEN 31 + +#ifdef MY_ABC_HERE +#define DT_AHCI_INTERNAL_MODE "internal_mode" +#endif /* MY_ABC_HERE */ + +#define DT_SEG7_NUM "seg7_num" +#define DT_SEG7_LED_MAP_0 "seg7_led_map_0" +#define DT_SEG7_LED_MAP_1 "seg7_led_map_1" +#define DT_SEG7_LED_MAP_2 "seg7_led_map_2" + +/* This enum must sync with synosdk/fs.h for user space having same DISK_PORT_TYPE mapping */ +typedef enum _tag_DISK_PORT_TYPE{ + UNKNOWN_DEVICE = 0, + INTERNAL_DEVICE, + EXTERNAL_SATA_DEVICE, + EUNIT_DEVICE, + EXTERNAL_USB_DEVICE, + SYNOBOOT_DEVICE, + ISCSI_DEVICE, + CACHE_DEVICE, + USB_HUB_DEVICE, + SDCARD_DEVICE, + INVALID_DEVICE, + SYSTEM_DEVICE, + DISK_PORT_TYPE_END, +} DISK_PORT_TYPE; + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +typedef enum _tag_DISK_PWRCTRL_TYPE { + PWRCTRL_TYPE_UNKNOWN = 0, + PWRCTRL_TYPE_GPIO, + PWRCTRL_TYPE_SMBUS, + PWRCTRL_TYPE_END, +} DISK_PWRCTRL_TYPE; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +typedef struct _syno_smbus_hdd_powerctl { + bool bl_init; + int (*syno_smbus_hdd_enable_write)(int adapter, int address, int index, int val); + int (*syno_smbus_hdd_enable_read)(int adapter, int address, int index); + int (*syno_smbus_hdd_present_read)(int adapter, int address, int index); + int (*syno_smbus_hdd_enable_write_all_once)(int adapter, int address); +} SYNO_SMBUS_HDD_POWERCTL; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#define SYNO_SPINUP_GROUP_MAX 16 +#define SYNO_SPINUP_GROUP_PIN_MAX_NUM 8 +extern int g_syno_rp_detect_no; +extern int g_syno_rp_detect_list[SYNO_SPINUP_GROUP_PIN_MAX_NUM]; +extern int g_syno_hdd_detect_no; +extern int g_syno_hdd_detect_list[SYNO_SPINUP_GROUP_PIN_MAX_NUM]; +extern int g_syno_hdd_enable_no; +extern int g_syno_hdd_enable_list[SYNO_SPINUP_GROUP_PIN_MAX_NUM]; +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +#define PCI_ADDR_LEN_MAX 9 +#define PCI_ADDR_NUM_MAX CONFIG_SYNO_PCI_MAX_SLOT +extern char gszPciAddrList[PCI_ADDR_NUM_MAX][PCI_ADDR_LEN_MAX]; +extern int gPciAddrNum; +extern int syno_check_on_option_pci_slot(struct pci_dev *pdev); +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define SYNOBIOS_EVENTDATA_NUM_MAX 8 +typedef struct _synobios_event_parm_tag { + unsigned long long data[SYNOBIOS_EVENTDATA_NUM_MAX]; +} SYNOBIOS_EVENT_PARM; + +typedef int (*FUNC_SYNOBIOS_EVENT)(SYNOBIOS_EVENT_PARM parms); + +typedef struct _synobios_evnet_action_tag { + unsigned long long synobios_event_type; + SYNOBIOS_EVENT_PARM parms; + struct list_head list; +} SYNOBIOS_EVENT_ACTION_LIST; +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * Notice + * ------ + * Before calling syno_kexec_test() or reading kexex_test_flags, please + * ensure that syno_kexec_test_init() has been called. + */ +#define KEXEC_TEST_DECOMPRESSION 0 /* Did we skip compressed/head_64.S ? */ +#define KEXEC_TEST_BOOTLOADER 1 /* Is bootloader type 0xD ? */ +#define KEXEC_TEST_E820_TABLE 2 /* Is the minimal start address of usable memory in e820 table 0x100 ? */ +#define KEXEC_TEST_SETUP_DATA 3 /* Did we receive setup_data with type SETUP_NONE or SETUP_EFI ? */ + +extern unsigned long kexec_test_flags; + +/* + * kexec_test_flags initializer. + */ +void __init syno_kexec_test_init(void); +/* + * Test whether the above KEXEC_TEST_* bits are set. + */ +static __always_inline bool syno_kexec_test(int test) +{ + return 0 != test_bit(test, &kexec_test_flags); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * How to use : + * 1. module itself register the proprietary instance into the kernel + * by a predined MAGIC-key. + * 2. Others can query the module registration by the same MAGIC-key + * and get the instance handle. + * ******************************************************************** + * Beware of casting/handing "instance", you must know + * what you are doing before accessing the instance. + * ******************************************************************** + */ +/* For plugin-instance registration */ +int syno_plugin_register(int plugin_magic, void *instance); +int syno_plugin_unregister(int plugin_magic); +/* For getting the plugin-instance */ +int syno_plugin_handle_get(int plugin_magic, void **hnd); +void * syno_plugin_handle_instance(void *hnd); +void syno_plugin_handle_put(void *hnd); + +/* Magic definition */ +#define EPIO_PLUGIN_MAGIC_NUMBER 0x20120815 +#define RODSP_PLUGIN_MAGIC_NUMBER 0x20141111 +#endif /* MY_ABC_HERE */ + +#endif //__SYNOLIB_H_ diff --git a/include/linux/synosata.h b/include/linux/synosata.h new file mode 100644 index 000000000000..55b32c57cff1 --- /dev/null +++ b/include/linux/synosata.h @@ -0,0 +1,548 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2003-2015 Synology Inc. All rights reserved. +#ifndef __SYNO_SATA_H_ +#define __SYNO_SATA_H_ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int gSynoInternalHddNumber; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +extern int gSynoHddPowerupSeq; +extern long g_syno_hdd_powerup_seq; +extern long syno_boot_hd_count; +extern int giSynoSpinupGroup[16]; +extern int giSynoSpinupGroupNum; +extern int giSynoSpinupGroupDelay; +extern int giSynoSpinupGroupDebug; +extern int giSynoDSleepCurrentSpinupGroupNum; +extern int giSynoDSleepCurrentSpinupGroupDiskNum; +extern int giSynoDSleepCurrentPoweronDisks; +extern void DBG_SpinupGroupListGpio(void); +extern int SynoHaveRPDetectPin(void); +extern int SynoAllRedundantPowerDetected(void); +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +#include +static struct mutex mutex_spin; +static DEFINE_MUTEX(mutex_spin); + +#define DBG_SpinupGroup(x...) \ + if (0 < giSynoSpinupGroupDebug) printk(x) + +static inline int SpinupDelayEval(void) +{ + + static int iDisksInSpinupGroup = 0; + static int iCurrentSpinupGroup = 0; + int iDelay = 0; + + if (0 >= giSynoSpinupGroupNum) { + goto END; + } + + mutex_lock(&mutex_spin); + + DBG_SpinupGroupListGpio(); + if (iDisksInSpinupGroup >= giSynoSpinupGroup[iCurrentSpinupGroup]) { + iCurrentSpinupGroup++; + iDisksInSpinupGroup = 0; + } + iDisksInSpinupGroup++; + + if (SynoHaveRPDetectPin() && SynoAllRedundantPowerDetected()) { + goto SKIP; + } + + iDelay = iCurrentSpinupGroup * giSynoSpinupGroupDelay; +SKIP: + mutex_unlock(&mutex_spin); +END: + return iDelay; +} + +static inline void SynoResetDSleepGroup(void) +{ + if (0 < giSynoSpinupGroupNum) { + //Reset to group 0 + giSynoDSleepCurrentSpinupGroupNum = 0; + //Reset disk num of group 0, ex [2,1,1,1], here is 2 + giSynoDSleepCurrentSpinupGroupDiskNum = giSynoSpinupGroup[0]; + giSynoDSleepCurrentPoweronDisks = 0; + } +} +static inline int SynoDSleepNeedUpdateLastPmOn(void) +{ + int ret = 0; + if (0 == giSynoSpinupGroupNum) { + ret = 1; + } else { + /* no RP or with RP pin but not plug both them */ + if (!SynoHaveRPDetectPin() || + (SynoHaveRPDetectPin() && !SynoAllRedundantPowerDetected())) { + giSynoDSleepCurrentPoweronDisks++; + } + + /* with RP pin and plug both them */ + if (SynoHaveRPDetectPin() && SynoAllRedundantPowerDetected()) { + /* don't add giSynoDSleepCurrentPoweronDisks means always not full */ + ret = 1; + } + + if (giSynoDSleepCurrentPoweronDisks >= giSynoDSleepCurrentSpinupGroupDiskNum) { + DBG_SpinupGroup("Disk Group %d is full, going to delay for power on.\n",giSynoDSleepCurrentSpinupGroupNum); + DBG_SpinupGroupListGpio(); + giSynoDSleepCurrentPoweronDisks = 0; + giSynoDSleepCurrentSpinupGroupNum++; + if (giSynoDSleepCurrentSpinupGroupNum < giSynoSpinupGroupNum) { + giSynoDSleepCurrentSpinupGroupDiskNum = giSynoSpinupGroup[giSynoDSleepCurrentSpinupGroupNum]; + } else { + /* if syno_spinup_group not use all disks, left hdd poweron 1 by 1 */ + giSynoDSleepCurrentSpinupGroupDiskNum = 1; + } + ret = 1; + } + } + return ret; +} +static inline unsigned long SynoWakeInterval(void) +{ + /* original WAKEINTERVAL = 7UL*HZ */ + static unsigned long uiSynoWakeInterval = 7UL*HZ; + if (0 < giSynoSpinupGroupDelay) { + uiSynoWakeInterval = (unsigned long)giSynoSpinupGroupDelay * HZ; + } + return uiSynoWakeInterval; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static inline unsigned char +syno_pm_is_jmb575(unsigned short vendor, unsigned short devid) +{ + return (vendor == 0x197b && devid == 0x5755); +} + +#define MAX_EBOX_SN_LEN 16 +typedef enum _tag_SYNO_PM_I2C_OPERATION { + PM_I2C_OP_UNKNOWON = 0x00, + PM_I2C_OP_WRITE = 0x01, + PM_I2C_OP_READ = 0x02, +} SYNO_PM_I2C_OPERATION; +# define SYNO_PMP_I2C_MAX_DATA_LEN 7 +typedef struct _tag_SYNO_PM_I2C_PKG { + SYNO_PM_I2C_OPERATION op; + unsigned short addr; + unsigned short offset; + unsigned short len; + unsigned char inputData[SYNO_PMP_I2C_MAX_DATA_LEN]; + unsigned char resultData[SYNO_PMP_I2C_MAX_DATA_LEN]; + bool blIsErr; +} SYNO_PM_I2C_PKG; + +static inline void syno_init_i2c_pkg(SYNO_PM_I2C_PKG *pPkg, SYNO_PM_I2C_OPERATION op, \ + unsigned short addr, unsigned short offset, unsigned short len) +{ + if (!pPkg) { + goto END; + } + + pPkg->op = op; + pPkg->addr = addr; + pPkg->offset = offset; + pPkg->len = len; + pPkg->blIsErr = false; + + memset(pPkg->inputData, 0, SYNO_PMP_I2C_MAX_DATA_LEN); + memset(pPkg->resultData, 0, SYNO_PMP_I2C_MAX_DATA_LEN); +END: + return; +} + + +typedef enum _tag_SYNO_PM_I2C_SYSFS_OP { + SYNO_PM_I2C_SYSFS_UNKNOWN = 0x00, + SYNO_PM_I2C_SYSFS_I2C_READ = 0x01, + SYNO_PM_I2C_SYSFS_I2C_WRITE = 0x02, + SYNO_PM_I2C_SYSFS_JMB575_LED_CTL = 0x03, + SYNO_PM_I2C_SYSFS_POLLING = 0x04, +} SYNO_PM_I2C_SYSFS_OP; + +#define GPIO_9705_PKG_INIT(addr,data) ((addr << 10) | (0x3 << 8) | data) +/** + * Kernel gpio package of our ebox. + */ +typedef struct _tag_SYNO_PM_PKG { + /* use for read/write */ + unsigned int var; + + /* the gpio address */ + int gpio_addr; + + /* the encode of gpio */ + void (*encode)(struct _tag_SYNO_PM_PKG *pm_pkg, int rw); + + /* the decode of gpio */ + void (*decode)(struct _tag_SYNO_PM_PKG *pm_pkg, int rw); +} SYNO_PM_PKG; + +/* 9705 GPIO table */ +/* + * NA NA NA NA GPIO19 GPIO18 GPIO17 GPIO16 + * R -- -- -- -- -- -- -- -- + * W -- -- -- -- A2 A1 A0 Mask + * + * GPIO15 GPIO14 GPIO13 GPIO12 GPIO11 GPIO10 GPIO09 GPIO08 + * R -- -- GPI8 GPI7 GPI6 LED_5 LED_4 LED_3 + * W R_CTL W_CTL GPO8 GPO7 GPO6 LED_5 LED_4 LED_3 + * + * GPIO07 GPIO06 GPIO05 GPIO04 GPIO03 GPIO02 GPIO01 GPIO00 + * R LED_2 LED_1 LED_H GPI5 GPI4 GPI3 GPI2 GPI1 + * W LED_2 LED_1 LED_H GPO5 GPO4 GPO3 GPO2 GPO1 + * + */ + +/** + * You should reference ebox spec for + * the gpio definition of our 9705. + * + * Otherwise, you don't know what we do here + * + * @param pPM_pkg [OUT] Store the result. Should not be NULL. + * @param rw [IN] indicate the request is read or write. + * 0: read + * 1: write + */ +static inline void +SIMG9705_gpio_decode(SYNO_PM_PKG *pPM_pkg, int rw) +{ +#define GPI_9705_BIT1(GPIO) (1&GPIO) +#define GPI_9705_BIT2(GPIO) ((1<<1)&GPIO) +#define GPI_9705_BIT3(GPIO) ((1<<2)&GPIO) +#define GPI_9705_BIT4(GPIO) ((1<<3)&GPIO) +#define GPI_9705_BIT5(GPIO) ((1<<4)&GPIO) +#define GPI_9705_BIT6(GPIO) ((1<<11)&GPIO)>>6 +#define GPI_9705_BIT7(GPIO) ((1<<12)&GPIO)>>6 +#define GPI_9705_BIT8(GPIO) ((1<<13)&GPIO)>>6 + + if (!rw) { + pPM_pkg->var = + GPI_9705_BIT1(pPM_pkg->var)| + GPI_9705_BIT2(pPM_pkg->var)| + GPI_9705_BIT3(pPM_pkg->var)| + GPI_9705_BIT4(pPM_pkg->var)| + GPI_9705_BIT5(pPM_pkg->var)| + GPI_9705_BIT6(pPM_pkg->var)| + GPI_9705_BIT7(pPM_pkg->var)| + GPI_9705_BIT8(pPM_pkg->var); + } +} + +/** + * You should reference ebox spec for + * the gpio definition of our 9705. + * + * Otherwise, you don't know what we do here + * + * @param pPM_pkg [OUT] Store the result. Should not be NULL. + * @param rw [IN] indicate the request is read or write. + * 0: read + * 1: write + */ +static inline void +SIMG9705_gpio_encode(SYNO_PM_PKG *pPM_pkg, int rw) +{ +#define GPIO_9705_BIT00(GPO) (1&GPO) +#define GPIO_9705_BIT01(GPO) ((1<<1)&GPO) +#define GPIO_9705_BIT02(GPO) ((1<<2)&GPO) +#define GPIO_9705_BIT03(GPO) ((1<<3)&GPO) +#define GPIO_9705_BIT04(GPO) ((1<<4)&GPO) +#define GPIO_9705_BIT11(GPO) ((1<<5)&GPO)<<6 +#define GPIO_9705_BIT12(GPO) ((1<<6)&GPO)<<6 +#define GPIO_9705_BIT13(GPO) ((1<<7)&GPO)<<6 +#define GPIO_9705_BIT14(GPO) ((1<<8)&GPO)<<6 +#define GPIO_9705_BIT15(GPO) ((1<<9)&GPO)<<6 +#define GPIO_9705_BIT17(GPO) ((1<<10)&GPO)<<7 +#define GPIO_9705_BIT18(GPO) ((1<<11)&GPO)<<7 +#define GPIO_9705_BIT19(GPO) ((1<<12)&GPO)<<7 + + if (rw) { + pPM_pkg->var = + GPIO_9705_BIT00(pPM_pkg->var)| + GPIO_9705_BIT01(pPM_pkg->var)| + GPIO_9705_BIT02(pPM_pkg->var)| + GPIO_9705_BIT03(pPM_pkg->var)| + GPIO_9705_BIT04(pPM_pkg->var)| + GPIO_9705_BIT11(pPM_pkg->var)| + GPIO_9705_BIT12(pPM_pkg->var)| + GPIO_9705_BIT13(pPM_pkg->var)| + GPIO_9705_BIT14(pPM_pkg->var)| + GPIO_9705_BIT15(pPM_pkg->var)| + GPIO_9705_BIT17(pPM_pkg->var)| + GPIO_9705_BIT18(pPM_pkg->var)| + GPIO_9705_BIT19(pPM_pkg->var); + } +} + +static inline unsigned char +syno_pm_is_9705(unsigned short vendor, unsigned short devid) +{ + return (vendor == 0x1B4B && devid == 0x9705); +} + +static inline void +syno_pm_systemstate_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + pPKG->var = GPIO_9705_PKG_INIT(3,0); + } + + /* add other port multiplier here */ +} + +static inline void +syno_pm_unique_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + pPKG->var = GPIO_9705_PKG_INIT(0,0); + } + + /* add other port multiplier here */ +} + +static inline void +syno_pm_raidledstate_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + pPKG->var = GPIO_9705_PKG_INIT(4,0); + } + /* add other port multiplier here */ +} + +static inline void +syno_pm_fanstatus_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + pPKG->var = GPIO_9705_PKG_INIT(2,0); + } + + /* add other port multiplier here */ +} + +static inline void +syno_pm_poweron_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG, unsigned char blCLR) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + if (blCLR) { + pPKG->var = GPIO_9705_PKG_INIT(4,0b10); + } else { + pPKG->var = GPIO_9705_PKG_INIT(4,0b10010); + } + } + + /* add other port multiplier here */ +} + +/** + * Init eunit deepsleep indicator + * + * @param vendor [IN] PMP vendor + * @param devid [IN] device id + * @param pPM_pkg [IN] Store the result. Should not be NULL. + * @param blCLR [IN] clean or not + * + * return 0: not support deepsleep indicator + * 1: support deepsleep indicator + */ +static inline int +syno_pm_deepsleep_indicator_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG, unsigned char blCLR) +{ + /* do not check parameters, caller should do it */ + int iRet = 0; + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + if (blCLR) { + pPKG->var = GPIO_9705_PKG_INIT(1,0); + } else { + pPKG->var = GPIO_9705_PKG_INIT(1,0x80); + } + iRet = 1; + } + /* add other port multiplier here */ + return iRet; +} + +static inline void +syno_pm_enable_powerbtn_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + if (syno_pm_is_9705(vendor, devid)) { + pPKG->var = GPIO_9705_PKG_INIT(4,0x20); + } + + /* add other port multiplier here */ +} + +static inline unsigned int +syno_support_disk_num(unsigned short vendor, + unsigned short devid, + unsigned int syno_uniq) +{ + unsigned int ret = 0; + + if (syno_pm_is_9705(vendor, devid)) { + if (IS_SYNOLOGY_RX413(syno_uniq) || IS_SYNOLOGY_RX418(syno_uniq)) { + ret = 4; + } else if (IS_SYNOLOGY_RX1214(syno_uniq) || IS_SYNOLOGY_RX1217(syno_uniq) || + IS_SYNOLOGY_DX1215(syno_uniq) || IS_SYNOLOGY_DX1222(syno_uniq) || + IS_SYNOLOGY_DX1215II(syno_uniq)) { + ret = 3; + } else if (IS_SYNOLOGY_DX517(syno_uniq)) { + ret = 5; + } else { + printk("%s not synology device", __FUNCTION__); + ret = 5; + } + } else if (syno_pm_is_jmb575(vendor, devid)) { + if (IS_SYNOLOGY_RX1223RP(syno_uniq)) { + ret = 3; + } + } + + /* add other chip here */ + + return ret; +} + +static inline void +syno_pm_hddled_status_pkg_init(unsigned short vendor, unsigned short devid, SYNO_PM_PKG *pPKG) +{ + /* do not check parameters, caller should do it */ + + memset(pPKG, 0, sizeof(*pPKG)); + + if (syno_pm_is_9705(vendor, devid)) { + pPKG->var = GPIO_9705_PKG_INIT(1,0); + } + + /* add other port multiplier here */ +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +/* + *back porting from linux 2.6.28. add SYNO prefix in order to not mixed with libata + */ +#define SYNO_ATA_ID_MAJOR_VER 80 +#define SYNO_ATA_ID_MINOR_VER 81 +#define SYNO_ATA_ID_COMMAND_SET_1 82 +#define SYNO_ATA_ID_COMMAND_SET_2 83 +#define SYNO_ATA_ID_CFSSE 84 +#define SYNO_ATA_ID_ROT_SPEED 217 + +/** + * Determind the ata version. + * + * Copy from ata.h + * + * @param id [IN] Should not be NULL. ata identify buffer. + * + * @return ata version + */ +static inline unsigned int +ata_major_version(const unsigned short *id) +{ + unsigned int mver; + + if (id[SYNO_ATA_ID_MAJOR_VER] == 0xFFFF) + return 0; + + for (mver = 14; mver >= 1; mver--) + if (id[SYNO_ATA_ID_MAJOR_VER] & (1 << mver)) + break; + return mver; +} + +/** + * Determind the ata version. + * + * Copy from linux-2.6.28 later in ata.h. Original from mail + * list. But it has bug. So i customized it. + * + * Sometime you can't just only take care in major version. + * The actually ATA version might need to look minor version. + * Please refer smartmontools-5.38/atacmds.cpp + * const char minor_str [] = ... + * + * @param id [IN] Should not be NULL. ata identify buffer. + * + * @return ata version + */ +static inline int +syno_ata_id_is_ssd(const unsigned short *id) +{ + int res = 0; + unsigned int major_id = ata_major_version(id); + + /* ATA8-ACS version 4c or higher (=> 4c or 6 at the moment) */ + if (7 <= major_id){ + if (id[SYNO_ATA_ID_ROT_SPEED] == 0x01) { + // intel ssd, and the laters ssd + res = 1; + goto END; + } + } + + if ((id[SYNO_ATA_ID_COMMAND_SET_2]>>14) == 0x01 && + !(id[SYNO_ATA_ID_COMMAND_SET_1] & 0x0001)) { + // not support smart. like innodisk + res = 1; + goto END; + } + + // transcend. Not support smart error log + if ((id[SYNO_ATA_ID_COMMAND_SET_2]>>14) == 0x01 && + (id[SYNO_ATA_ID_COMMAND_SET_1] & 0x0001) && + !(id[SYNO_ATA_ID_CFSSE] & 0x1)) { + res = 1; + goto END; + } + +END: + return res; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define SZK_PMP_UEVENT "SYNO_PMP_EVENT" +#define SZV_PMP_CONNECT "CABLE_CONNECT" +#define SZV_PMP_DISCONNECT "CABLE_DISCONNECT" +#endif /* MY_ABC_HERE */ + +#endif /* __SYNO_SATA_H_ */ diff --git a/include/linux/synotify.h b/include/linux/synotify.h new file mode 100644 index 000000000000..0a70cf860683 --- /dev/null +++ b/include/linux/synotify.h @@ -0,0 +1,17 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* + * Copyright (C) 2021 synology + */ +#ifndef _LINUX_SYNOTIFY_H +#define _LINUX_SYNOTIFY_H + +#ifdef MY_ABC_HERE +#include +#include + +extern struct ctl_table synotify_table[]; /* for sysctl */ +#endif /* MY_ABC_HERE */ + +#endif /* _LINUX_SYNOTIFY_H */ diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h index d9b3cf0f410c..8b5c9dfebac0 100644 --- a/include/linux/sys_soc.h +++ b/include/linux/sys_soc.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) ST-Ericsson SA 2011 @@ -18,6 +21,14 @@ struct soc_device_attribute { const struct attribute_group *custom_attr_group; }; +#if defined(MY_DEF_HERE) +struct soc_device { + struct device dev; + struct soc_device_attribute *attr; + int soc_dev_num; +}; + +#endif /* MY_DEF_HERE */ /** * soc_device_register - register SoC as a device * @soc_plat_dev_attr: Attributes passed from platform to be attributed to a SoC diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index aea0ce9f3b74..166dee8a4fb7 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * syscalls.h - Linux syscall interfaces (non-arch-specific) @@ -69,6 +72,12 @@ struct io_uring_params; struct clone_args; struct open_how; +#ifdef MY_ABC_HERE +struct SYNOSTAT; +#else +struct SYNOSTAT {}; +#endif /* MY_ABC_HERE */ + #include #include #include @@ -1033,6 +1042,29 @@ asmlinkage long sys_pidfd_send_signal(int pidfd, int sig, unsigned int flags); asmlinkage long sys_pidfd_getfd(int pidfd, int fd, unsigned int flags); +#ifdef MY_ABC_HERE +/* 802 */ asmlinkage long sys_syno_utime(const char __user *filename, struct __kernel_timespec __user *ctime); +/* 802 */ asmlinkage long sys_syno_utime32(const char __user *filename, struct old_timespec32 __user *ctime); +/* 803 */ asmlinkage long sys_syno_archive_bit(const char __user *filename, int cmd); +/* 804 */ asmlinkage long sys_syno_recv_file(int fd, int s, loff_t *offset, size_t nbytes, size_t *rwbytes); +/* 805 */ asmlinkage long sys_syno_mtd_alloc(bool alloc); +/* 806 */ asmlinkage long sys_syno_caseless_stat(char __user *filename, struct stat __user *statbuf); +/* 807 */ asmlinkage long sys_syno_caseless_lstat(char __user *filename, struct stat __user *statbuf); +/* 810 */ asmlinkage long sys_syno_ecrypt_name(const char __user *src, char __user *dst); +/* 811 */ asmlinkage long sys_syno_decrypt_name(const char __user *root, const char __user *src, char __user *dst); +/* 812 */ asmlinkage long sys_syno_acl_check_perm(const char __user *filename, int mask); +/* 813 */ asmlinkage long sys_syno_acl_is_support(const char __user *filename, int fd, int tag); +/* 814 */ asmlinkage long sys_syno_acl_get_perm(const char __user *filename, int __user *out_perm); +/* 815 */ asmlinkage long sys_syno_flush_aggregate(int fd); +/* 819 */ asmlinkage long sys_syno_stat(char __user *filename, unsigned int flags, struct SYNOSTAT __user *statbuf); +/* 820 */ asmlinkage long sys_syno_fstat(unsigned int fd, unsigned int flags, struct SYNOSTAT __user *statbuf); +/* 821 */ asmlinkage long sys_syno_lstat(char __user *filename, unsigned int flags, struct SYNOSTAT __user *statbuf); +/* 822 */ asmlinkage long sys_syno_notify_init(unsigned int event_f_flags); +/* 823 */ asmlinkage long sys_syno_notify_add_watch(int synotify_fd, const char __user *pathname, u64 mask); +/* 824 */ asmlinkage long sys_syno_notify_remove_watch(int synotify_fd, const char __user *pathname, u64 mask); +/* 827 */ asmlinkage long sys_syno_archive_overwrite(unsigned int fd, unsigned int flags); +#endif /* MY_ABC_HERE */ + /* * Architecture-specific system calls */ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 51298a4f4623..7d1ca665b780 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * sysctl.h: General linux system control interface @@ -65,6 +68,14 @@ int proc_do_large_bitmap(struct ctl_table *, int, void *, size_t *, loff_t *); int proc_do_static_key(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos); +#ifdef MY_ABC_HERE +extern int syno_proc_do_string_vector(struct ctl_table *, int, + void *, size_t *, loff_t *); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern int syno_proc_do_int_vector(struct ctl_table *, int, + void __user *, size_t *, loff_t *); +#endif /* MY_ABC_HERE */ /* * Register a set of sysctl names by calling register_sysctl_table * with an initialised array of struct ctl_table's. An entry with diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h index bb5498bcdd96..b60dffa2e7dc 100644 --- a/include/linux/task_io_accounting_ops.h +++ b/include/linux/task_io_accounting_ops.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Task I/O accounting operations @@ -6,11 +9,19 @@ #define __TASK_IO_ACCOUNTING_OPS_INCLUDED #include +#ifdef MY_ABC_HERE +#include +#endif #ifdef CONFIG_TASK_IO_ACCOUNTING static inline void task_io_account_read(size_t bytes) { current->ioac.read_bytes += bytes; + +#ifdef MY_ABC_HERE + if (current->workacct) + update_kwork_io_stat_ratelimited(current, GFP_NOWAIT); +#endif /* MY_ABC_HERE */ } /* @@ -25,6 +36,11 @@ static inline unsigned long task_io_get_inblock(const struct task_struct *p) static inline void task_io_account_write(size_t bytes) { current->ioac.write_bytes += bytes; + +#ifdef MY_ABC_HERE + if (current->workacct) + update_kwork_io_stat_ratelimited(current, GFP_NOWAIT); +#endif /* MY_ABC_HERE */ } /* diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index cdd049a724b1..284d54dfc8c1 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2016, Linaro Limited @@ -355,6 +358,18 @@ static inline bool tee_shm_is_registered(struct tee_shm *shm) return shm && (shm->flags & TEE_SHM_REGISTER); } +#if defined(MY_DEF_HERE) +/** + * tee_shm_register_fd() - Register shared memory from file descriptor + * + * @ctx: Context that allocates the shared memory + * @fd: shared memory file descriptor reference. + * + * @returns a pointer to 'struct tee_shm' + */ +struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd); + +#endif /* MY_DEF_HERE */ /** * tee_shm_free() - Free shared memory * @shm: Handle to shared memory to free diff --git a/include/linux/tty.h b/include/linux/tty.h index 5972f43b9d5a..e22cabfac94f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_TTY_H #define _LINUX_TTY_H @@ -406,6 +409,12 @@ static inline bool tty_throttled(struct tty_struct *tty) } #ifdef CONFIG_TTY + +#ifdef MY_ABC_HERE +extern int syno_ttys_write(const int index, const char* szBuf); +extern void syno_uart_write(struct tty_port *port, char *buf, int size); +#endif /* MY_ABC_HERE */ + extern void tty_kref_put(struct tty_struct *tty); extern struct pid *tty_get_pgrp(struct tty_struct *tty); extern void tty_vhangup_self(void); diff --git a/include/linux/usb.h b/include/linux/usb.h index d6a41841b93e..499bf5f05346 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LINUX_USB_H #define __LINUX_USB_H @@ -688,6 +691,12 @@ struct usb_device { int maxchild; u32 quirks; +#ifdef MY_ABC_HERE + char *syno_old_serial; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + u32 syno_quirks; +#endif /* MY_ABC_HERE */ atomic_t urbnum; unsigned long active_duration; @@ -2037,6 +2046,10 @@ extern void usb_led_activity(enum usb_led_event ev); static inline void usb_led_activity(enum usb_led_event ev) {} #endif +#ifdef MY_ABC_HERE +#define IS_SYNO_FLASH(VENDOR, PROD) ((0xf400 == VENDOR && 0xf400 == PROD) || (0xf401 == VENDOR && 0xf401 == PROD)) +#endif /* MY_ABC_HERE */ + #endif /* __KERNEL__ */ #endif diff --git a/include/linux/usb/f_mtp.h b/include/linux/usb/f_mtp.h new file mode 100644 index 000000000000..c60ae56cf492 --- /dev/null +++ b/include/linux/usb/f_mtp.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Gadget Function Driver for MTP + * + * Copyright (C) 2010 Google, Inc. + * Author: Mike Lockwood + * + */ + +#ifndef __LINUX_USB_F_MTP_H +#define __LINUX_USB_F_MTP_H + +#include + +#endif /* __LINUX_USB_F_MTP_H */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 3dbb42c637c1..34863dcd696b 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2002 by David Brownell @@ -219,6 +222,13 @@ struct usb_hcd { /* memory pool for HCs having local memory, or %NULL */ struct gen_pool *localmem_pool; +#ifdef MY_ABC_HERE + /* A38X only support 1 port per HC */ + int vbus_gpio_pin; + /* Support power control */ + int power_control_support; +#endif /* MY_ABC_HERE */ + /* more shared queuing code would be good; it should support * smarter scheduling, handle transaction translators, etc; * input size of periodic table to an interrupt scheduler. diff --git a/include/linux/usb/syno_quirks.h b/include/linux/usb/syno_quirks.h new file mode 100644 index 000000000000..b4688a24c0d4 --- /dev/null +++ b/include/linux/usb/syno_quirks.h @@ -0,0 +1,26 @@ +#ifndef __LINUX_SYNO_USB_QUIRKS_H +#define __LINUX_SYNO_USB_QUIRKS_H +/* + * Description: + * List all SYNO USB QUIRKS + * + * + * UPS_DISCONNECT_FILTER is used to avoid disconnection from the UPS by + * deferring a disconnect for a period of time, and then if the UPS re- + * connects, we ignore the last disconnection, otherwise disconnects it. + * + * LIMITED_UPS_DISCONNECT_FILTERING is an extension of UPS_DISCONNECT_FILTER + * it's used to limit the number of disconnect filtering in a period of time. + * For the buggy UPS which disconnects very frequently before a UPS driver ( + * usually in userspace) links the UPS. Because the condition that the buggy + * UPS isn't stable initally and UPS driver can't also link it before the + * driver stops trying, so we should actually disconnect and re-connect to + * notify and restart the UPS driver + */ + +#define SYNO_USB_QUIRK_UPS_DISCONNECT_FILTER 0x00000001 +#define SYNO_USB_QUIRK_LIMITED_UPS_DISCONNECT_FILTERING 0x00000002 +#define SYNO_USB_QUIRK_SYNCHRONIZE_CACHE_FILTER 0x00000010 +#define SYNO_USB_QUIRK_HC_MORE_TRANSACTION_TRIES 0x00000020 + +#endif /* __LINUX_SYNO_USB_QUIRKS_H */ diff --git a/include/linux/usb/uas.h b/include/linux/usb/uas.h index aa3ad39d39dc..5f780acb7efb 100644 --- a/include/linux/usb/uas.h +++ b/include/linux/usb/uas.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __USB_UAS_H__ #define __USB_UAS_H__ @@ -107,4 +110,24 @@ enum { UAS_ORDERED_TAG = 2, UAS_ACA = 4, }; +#ifdef MY_ABC_HERE +#define MAX_CMNDS 256 + +struct uas_dev_info { + struct usb_interface *intf; + struct usb_device *udev; + struct usb_anchor cmd_urbs; + struct usb_anchor sense_urbs; + struct usb_anchor data_urbs; + unsigned long flags; + int qdepth, resetting; + unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; + unsigned use_streams:1; + unsigned shutdown:1; + struct scsi_cmnd *cmnd[MAX_CMNDS]; + spinlock_t lock; + struct work_struct work; + struct work_struct scan_work; /* for async scanning */ +}; +#endif #endif diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index e1bd560da1cd..7616c7bf4b24 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -101,15 +101,11 @@ struct ucounts { }; extern struct user_namespace init_user_ns; -extern struct ucounts init_ucounts; bool setup_userns_sysctls(struct user_namespace *ns); void retire_userns_sysctls(struct user_namespace *ns); struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type); void dec_ucount(struct ucounts *ucounts, enum ucount_type type); -struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid); -struct ucounts *get_ucounts(struct ucounts *ucounts); -void put_ucounts(struct ucounts *ucounts); #ifdef CONFIG_USER_NS diff --git a/include/linux/wait.h b/include/linux/wait.h index f8b0704968a1..9b8b0833100a 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -207,6 +207,7 @@ void __wake_up_sync_key(struct wait_queue_head *wq_head, unsigned int mode, void void __wake_up_locked_sync_key(struct wait_queue_head *wq_head, unsigned int mode, void *key); void __wake_up_locked(struct wait_queue_head *wq_head, unsigned int mode, int nr); void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode); +void __wake_up_pollfree(struct wait_queue_head *wq_head); #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) #define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL) @@ -235,6 +236,31 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode); #define wake_up_interruptible_sync_poll_locked(x, m) \ __wake_up_locked_sync_key((x), TASK_INTERRUPTIBLE, poll_to_key(m)) +/** + * wake_up_pollfree - signal that a polled waitqueue is going away + * @wq_head: the wait queue head + * + * In the very rare cases where a ->poll() implementation uses a waitqueue whose + * lifetime is tied to a task rather than to the 'struct file' being polled, + * this function must be called before the waitqueue is freed so that + * non-blocking polls (e.g. epoll) are notified that the queue is going away. + * + * The caller must also RCU-delay the freeing of the wait_queue_head, e.g. via + * an explicit synchronize_rcu() or call_rcu(), or via SLAB_TYPESAFE_BY_RCU. + */ +static inline void wake_up_pollfree(struct wait_queue_head *wq_head) +{ + /* + * For performance reasons, we don't always take the queue lock here. + * Therefore, we might race with someone removing the last entry from + * the queue, and proceed while they still hold the queue lock. + * However, rcu_read_lock() is required to be held in such cases, so we + * can safely proceed with an RCU-delayed free. + */ + if (waitqueue_active(wq_head)) + __wake_up_pollfree(wq_head); +} + #define ___wait_cond_timeout(condition) \ ({ \ bool __cond = (condition); \ diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 26de0cae2a0a..8e2044188f3b 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * workqueue.h --- work queue handling for Linux. @@ -97,6 +100,11 @@ enum { /* maximum string length for set_worker_desc() */ WORKER_DESC_LEN = 24, + +#ifdef MY_ABC_HERE + /* maximum string length for workqueue name */ + WQ_NAME_LEN = 64, +#endif /* MY_ABC_HERE */ }; struct work_struct { @@ -665,6 +673,11 @@ int workqueue_online_cpu(unsigned int cpu); int workqueue_offline_cpu(unsigned int cpu); #endif +#ifdef MY_ABC_HERE +extern void update_kwork_io_stat_ratelimited(struct task_struct *p, gfp_t gfp); +extern void account_workqueue_time(struct task_struct *p, u64 us, gfp_t gfp); +#endif /* MY_ABC_HERE */ + void __init workqueue_init_early(void); void __init workqueue_init(void); diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 10b4dc2709f0..6b3e66906c7d 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* File: linux/xattr.h @@ -39,6 +42,14 @@ struct xattr_handler { size_t size, int flags); }; +#ifdef MY_ABC_HERE +struct syno_xattr_archive_version { + __le16 v_magic; + __le16 v_struct_version; + __le32 v_archive_version; +} __attribute__ ((__packed__)); +#endif /* MY_ABC_HERE */ + const char *xattr_full_name(const struct xattr_handler *, const char *); struct xattr { diff --git a/include/net/bond_alb.h b/include/net/bond_alb.h index f6af76c87a6c..f82be7b99d4d 100644 --- a/include/net/bond_alb.h +++ b/include/net/bond_alb.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. @@ -57,6 +60,18 @@ struct tlb_client_info { * packets to a Client that the Hash function * gave this entry index. */ +#ifdef MY_ABC_HERE + u64 tx_bytes; /* Each Client accumulates the BytesTx that + * were transmitted to it, and after each + * CallBack the LoadHistory is divided + * by the balance interval + */ + u64 load_history; /* This field contains the amount of Bytes + * that were transmitted to this client by + * the server on the previous balance + * interval in Bps. + */ +#else /* MY_ABC_HERE */ u32 tx_bytes; /* Each Client accumulates the BytesTx that * were transmitted to it, and after each * CallBack the LoadHistory is divided @@ -67,6 +82,7 @@ struct tlb_client_info { * the server on the previous balance * interval in Bps. */ +#endif /* MY_ABC_HERE */ u32 next; /* The next Hash table entry index, assigned * to use the same adapter for transmit. */ @@ -118,14 +134,24 @@ struct tlb_slave_info { * are the entries that were assigned to use this * slave for transmit. */ +#ifdef MY_ABC_HERE + u64 load; /* Each slave sums the loadHistory of all clients + * assigned to it + */ +#else /* MY_ABC_HERE */ u32 load; /* Each slave sums the loadHistory of all clients * assigned to it */ +#endif /* MY_ABC_HERE */ }; struct alb_bond_info { struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */ +#ifdef MY_ABC_HERE + u64 unbalanced_load; +#else /* MY_ABC_HERE */ u32 unbalanced_load; +#endif /* MY_ABC_HERE */ int tx_rebalance_counter; int lp_counter; /* -------- rlb parameters -------- */ @@ -165,5 +191,8 @@ struct slave *bond_xmit_tlb_slave_get(struct bonding *bond, void bond_alb_monitor(struct work_struct *); int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id); +#if defined(MY_ABC_HERE) +void bond_alb_info_show(struct seq_file *seq); +#endif /* MY_ABC_HERE */ #endif /* _NET_BOND_ALB_H */ diff --git a/include/net/esp.h b/include/net/esp.h index 9c5637d41d95..90cd02ff77ef 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -4,6 +4,8 @@ #include +#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER) + struct ip_esp_hdr; static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index bd1f396cc9c7..13acb144d1f8 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Linux INET6 implementation @@ -483,6 +486,13 @@ static inline bool __ipv6_addr_needs_scope_id(int type) (type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL))); } +#if defined(MY_ABC_HERE) +static inline bool __ipv6_addr_is_link_local(int type) +{ + return type & IPV6_ADDR_LINKLOCAL; +} +#endif /* MY_ABC_HERE */ + static inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface) { return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0; diff --git a/include/net/sock.h b/include/net/sock.h index 3c7addf95150..6fda43cee5bc 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -479,8 +479,10 @@ struct sock { u32 sk_ack_backlog; u32 sk_max_ack_backlog; kuid_t sk_uid; + spinlock_t sk_peer_lock; struct pid *sk_peer_pid; const struct cred *sk_peer_cred; + long sk_rcvtimeo; ktime_t sk_stamp; #if BITS_PER_LONG==32 @@ -2665,6 +2667,7 @@ extern int sysctl_optmem_max; extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; +#define SKB_FRAG_PAGE_ORDER get_order(32768) DECLARE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto) diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 5339baadc082..6c3e064b4f08 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * This header file contains public constants and structures used by @@ -274,4 +277,17 @@ static inline int scsi_is_wlun(u64 lun) /* Used to obtain the PCI location of a device */ #define SCSI_IOCTL_GET_PCI 0x5387 +#ifdef MY_ABC_HERE +#define SYNO_DISK_MODEL_NUM 24 +#define SYNO_DISK_MODEL_LEN "24" +#endif + +#ifdef MY_ABC_HERE +#define SYNO_DESCRIPTOR_RESERVED_INDEX 3 /* Descriptor format sense data, + * information descriptor type, reserved byte index + */ +#define SYNO_NCQ_FAKE_UNC 0x01 // 0x01-->no remap, default 0x00-->do remap +#define SYNO_SCSI_SECT_SIZE 512 +#endif /* MY_ABC_HERE */ + #endif /* _SCSI_SCSI_H */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 1a5c9a3df6d6..a023d69a07bd 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _SCSI_SCSI_DEVICE_H #define _SCSI_SCSI_DEVICE_H @@ -9,6 +12,10 @@ #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + struct device; struct request_queue; struct scsi_cmnd; @@ -124,6 +131,11 @@ struct scsi_device { unsigned int id, channel; u64 lun; + +#ifdef MY_ABC_HERE + char syno_disk_name[BDEVNAME_SIZE]; /* name of major driver */ +#endif /* MY_ABC_HERE */ + unsigned int manufacturer; /* Manufacturer of device, for using * vendor-specific cmd's */ unsigned sector_size; /* size in bytes */ @@ -204,6 +216,12 @@ struct scsi_device { unsigned unmap_limit_for_ws:1; /* Use the UNMAP limit for WRITE SAME */ unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device * creation time */ +#ifdef MY_ABC_HERE + unsigned power_loss_during_reboot:1; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned default_disable_fua:1; /* Default disable FUA or not */ +#endif /* MY_ABC_HERE */ bool offline_already; /* Device offline message logged */ @@ -221,6 +239,15 @@ struct scsi_device { atomic_t iodone_cnt; atomic_t ioerr_cnt; +#ifdef MY_ABC_HERE + unsigned long last_accessed; /* last accessed time in jiffies */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + unsigned char spindown; + unsigned char nospindown; + unsigned char do_standby_syncing; +#endif /* MY_ABC_HERE */ + struct device sdev_gendev, sdev_dev; @@ -236,7 +263,46 @@ struct scsi_device { unsigned char access_state; struct mutex state_mutex; enum scsi_device_state sdev_state; + +#ifdef MY_DEF_HERE + /* Which queue is this disk in. + * 0 indicates none and should spin up immediately. */ + unsigned int spinup_queue_id; + /* Which queue is this disk in. Maybe NULL (id = 0). */ + struct SpinupQueue *spinup_queue; + /* list_head to link against queue */ + struct list_head spinup_list; + /* Indicates the disk is already spinning up */ + unsigned int spinup_in_process; + /* Timer for spinup time */ + unsigned long spinup_timer; + struct work_struct spinup_work; +#define SYNO_SPINUP_RESEND_TIMER 30 * HZ +#endif /* MY_DEF_HERE */ + struct task_struct *quiesced_by; + +#ifdef MY_ABC_HERE + unsigned int scmd_timeout_sec; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define SERIAL_NUM_SIZE 36 /* Largest string for a scsi device serial number */ + char syno_disk_serial[SERIAL_NUM_SIZE + 1]; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BLOCK_INFO_SIZE 512 /* Largest string for a scsi device block information */ + char syno_block_info[BLOCK_INFO_SIZE]; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + struct work_struct sendScsiErrorEventTask; + SYNOBIOS_EVENT_PARM scsiErrorEventParm; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + unsigned long sas_sata_standby_flag; +#endif + unsigned long sdev_data[]; } __attribute__((aligned(sizeof(unsigned long)))); @@ -336,6 +402,12 @@ static inline struct scsi_target *scsi_target(struct scsi_device *sdev) #define starget_printk(prefix, starget, fmt, a...) \ dev_printk(prefix, &(starget)->dev, fmt, ##a) +#ifdef MY_DEF_HERE +int SynoSpinupBegin(struct scsi_device *device); +void SynoSpinupEnd(struct scsi_device *sdev); +int SynoSpinupRemove(struct scsi_device *sdev); +#endif /* MY_DEF_HERE */ + extern struct scsi_device *__scsi_add_device(struct Scsi_Host *, uint, uint, u64, void *hostdata); extern int scsi_add_device(struct Scsi_Host *host, uint channel, diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 701f178b20ae..e9df43419eba 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _SCSI_SCSI_HOST_H #define _SCSI_SCSI_HOST_H @@ -29,6 +32,24 @@ struct scsi_transport_template; #define MODE_INITIATOR 0x01 #define MODE_TARGET 0x02 +#ifdef MY_ABC_HERE +enum { + SYNO_PWR_OP_POWER_OFF = 0, + SYNO_PWR_OP_POWER_ON = (1 << 0), + SYNO_PWR_OP_DEEPSLEEP = (1 << 1), + SYNO_PWR_OP_WAKE = (1 << 2), +}; +#endif /* MY_ABC_HERE */ + +#if defined(MY_ABC_HERE) +enum { + SYNO_PORT_TYPE_SATA = 1, + SYNO_PORT_TYPE_USB = 2, + SYNO_PORT_TYPE_SAS = 3, +}; +#endif /* defined(MY_ABC_HERE) */ + + struct scsi_host_template { struct module *module; const char *name; @@ -486,6 +507,20 @@ struct scsi_host_template { /* Delay for runtime autosuspend */ int rpm_autosuspend_delay; + +#ifdef MY_ABC_HERE + int syno_port_type; + void (*syno_sdev_info_enum)(struct scsi_device *); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE + int (*syno_set_sashost_disk_led)(struct scsi_device *, int); +#endif + +#ifdef MY_DEF_HERE + void (*syno_device_list_set)(struct scsi_device *, int, const char*); +#endif /* MY_DEF_HERE */ + }; /* @@ -692,6 +727,15 @@ struct Scsi_Host { */ struct device *dma_dev; +#ifdef MY_ABC_HERE + spinlock_t eunit_poweron_lock; + spinlock_t *peunit_poweron_lock; + int eunit_lock_configured; + unsigned int uiata_eh_flag; + unsigned int *puiata_eh_flag; + int is_eunit_deepsleep; +#endif /* MY_ABC_HERE */ + /* * We should ensure that this is aligned, both for better performance * and also because some compilers (m68k) don't automatically force diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h index b465799f4d2d..6986efc150cb 100644 --- a/include/scsi/scsi_ioctl.h +++ b/include/scsi/scsi_ioctl.h @@ -8,6 +8,7 @@ #define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */ #define SCSI_IOCTL_START_UNIT 5 #define SCSI_IOCTL_STOP_UNIT 6 + /* The door lock/unlock constants are compatible with Sun constants for the cdrom */ #define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h index a0458bda3148..cd4bf1236d05 100644 --- a/include/scsi/scsi_transport.h +++ b/include/scsi/scsi_transport.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * Transport specific attributes. @@ -43,6 +46,13 @@ struct scsi_transport_template { * Allows a transport to override the default error handler. */ void (* eh_strategy_handler)(struct Scsi_Host *); + +#ifdef MY_ABC_HERE + /* + * Check if Synology Eunit is in deep sleep. + */ + struct Scsi_Host* (* is_eunit_deepsleep)(struct Scsi_Host *); +#endif /* MY_ABC_HERE */ }; #define transport_class_to_shost(tc) \ diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index f28bb20d6271..35c7f493efb3 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -196,15 +196,23 @@ enum iscsi_connection_state { ISCSI_CONN_BOUND, }; +#define ISCSI_CLS_CONN_BIT_CLEANUP 1 + struct iscsi_cls_conn { struct list_head conn_list; /* item in connlist */ - struct list_head conn_list_err; /* item in connlist_err */ void *dd_data; /* LLD private data */ struct iscsi_transport *transport; uint32_t cid; /* connection id */ + /* + * This protects the conn startup and binding/unbinding of the ep to + * the conn. Unbinding includes ep_disconnect and stop_conn. + */ struct mutex ep_mutex; struct iscsi_endpoint *ep; + unsigned long flags; + struct work_struct cleanup_work; + struct device dev; /* sysfs transport/container device */ enum iscsi_connection_state state; }; @@ -443,6 +451,7 @@ extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size); extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep); extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle); +extern void iscsi_put_endpoint(struct iscsi_endpoint *ep); extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd); extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *t, diff --git a/include/soc/realtek/avcpu.h b/include/soc/realtek/avcpu.h new file mode 100644 index 000000000000..69b2b9a7aefc --- /dev/null +++ b/include/soc/realtek/avcpu.h @@ -0,0 +1,279 @@ +/* + * Realtek Audio & Video cpu driver + * + * Copyright (c) 2011 EJ Hsu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License. + * + * History: + * + * 2011-12-02: EJ Hsu: first version + * 2013-05-02: EJ Hsu: port to arm platform + */ + +#ifndef _LINUX_AVCPU_H +#define _LINUX_AVCPU_H + +#include +#include +#include + +#define AUDIO_CPU 1 +#define VIDEO_CPU_1 2 +#define VIDEO_CPU_2 3 + +#define AUDIO_ENTRY_ADDR (PAGE_OFFSET+0xe0) +#define VIDEO_ENTRY_ADDR_1 (PAGE_OFFSET+0xe4) +#define VIDEO_ENTRY_ADDR_2 (PAGE_OFFSET+0xdc) + +#define AVCPU_MAJOR 241 + +#define AVCPU_SUSPEND 100 +#define AVCPU_RESUME 101 +#define AVCPU_RESET_PREPARE 102 +#define AVCPU_RESET_DONE 103 + +#define AVSTAT_NORMAL 0 +#define AVSTAT_SUSPEND 1 +#define AVSTAT_RESUME 2 +#define AVSTAT_RESETAV 3 + + +#ifdef CONFIG_RTK_ACPU_RELOAD + +#define FW_DESC_TABLE_V1_T_VERSION_1 0x1 +#define FW_DESC_TABLE_V1_T_VERSION_11 0x11 +#define FW_DESC_TABLE_V1_T_VERSION_21 0x21 + +#define FW_DESC_TABLE_V2_T_VERSION_2 0x2 +#define FW_DESC_TABLE_V2_T_VERSION_12 0x12 +#define FW_DESC_TABLE_V2_T_VERSION_22 0x22 + +#define FW_DESC_BASE_VERSION(v) ((v) & 0xf) +#define FW_DESC_EXT_VERSION(v) ((v) >> 4) + +int register_avcpu_notifier(struct notifier_block *nb); +int unregister_avcpu_notifier(struct notifier_block *nb); + +int resetav_lock(int is_suspend); +int resetav_unlock(int is_suspend); + +int load_av_image(char *, unsigned int, char *, unsigned int, char *, unsigned int); + +typedef enum { + FW_TYPE_RESERVED = 0, + FW_TYPE_BOOTCODE, + FW_TYPE_KERNEL, + FW_TYPE_RESCUE_DT, + FW_TYPE_KERNEL_DT, + FW_TYPE_RESCUE_ROOTFS, + FW_TYPE_KERNEL_ROOTFS, + FW_TYPE_AUDIO, + FW_TYPE_AUDIO_FILE, + FW_TYPE_VIDEO_FILE, + FW_TYPE_EXT4, + FW_TYPE_UBIFS, + FW_TYPE_SQUASH, + FW_TYPE_EXT3, + FW_TYPE_ODD, + FW_TYPE_YAFFS2, + FW_TYPE_ISO, + FW_TYPE_SWAP, + FW_TYPE_NTFS, + FW_TYPE_JFFS2, + FW_TYPE_IMAGE_FILE, + FW_TYPE_VIDEO, + FW_TYPE_VIDEO2, + FW_TYPE_ECPU, + FW_TYPE_UNKNOWN +} fw_type_code_t; + +typedef enum { + RTK_PLAT_ERR_OK = 0, + RTK_PLAT_ERR_PARSE_FW_DESC, + RTK_PLAT_ERR_READ_FW_IMG, + RTK_PLAT_ERR_READ_KERNEL_IMG, + RTK_PLAT_ERR_READ_RESCUE_IMG, + RTK_PLAT_ERR_BOOT, +} rtk_plat_err_t; + +typedef enum { + FS_TYPE_JFFS2 = 0, + FS_TYPE_YAFFS2, + FS_TYPE_SQUASH, + FS_TYPE_RAWFILE, + FS_TYPE_EXT4, + FS_TYPE_UBIFS, + FS_TYPE_NONE, + FS_TYPE_UNKOWN +} rtk_part_fw_type_t; + +typedef struct { + char *audio_image; + unsigned int audio_start; + char *video_image_1; + unsigned int video_start_1; + char *video_image_2; + unsigned int video_start_2; +} resetav_struct; + +typedef struct { + unsigned int timeout; //in ms + int status; +} status_struct; + +typedef struct { + wait_queue_head_t status_wq; + int status; +} avcpu_info; + +typedef struct { + u8 signature[8]; + u32 checksum; + u8 version; //0x00 + u8 reserved[15]; + u32 length; +} __attribute__((packed)) fw_desc_table_t; + +typedef struct { + u8 signature[8]; + u32 checksum; + u8 version; //0x01 + u8 reserved[7]; + u32 paddings; + u32 part_list_len; + u32 fw_list_len; +} __attribute__((packed)) fw_desc_table_v1_t; + +typedef struct { + u8 type; + u8 reserved:7, + ro:1; + u64 length; + u8 fw_count; + u8 fw_type; + //#ifdef CONFIG_SYS_RTK_EMMC_FLASH +#if 1 + u8 emmc_partIdx; + u8 reserved_1[3]; +#else + u8 reserved_1[4]; +#endif + u8 mount_point[32]; +} __attribute__((packed)) part_desc_entry_v1_t; + +typedef struct { + u8 type; + u8 reserved:6, + lzma:1, + ro:1; + u32 version; + u32 target_addr; + u32 offset; + u32 length; + u32 paddings; + u32 checksum; + u8 reserved_1[6]; +} __attribute__((packed)) fw_desc_entry_v1_t; + +typedef struct { + fw_desc_entry_v1_t v1; + u32 act_size; + u8 hash[32]; + u8 part_num; + u8 reserved[27]; +} __attribute__((packed)) fw_desc_entry_v11_t; + +typedef struct { + fw_desc_entry_v1_t v1; + u32 act_size; + u8 part_num; + u8 RSA_sign[256]; + u8 reserved[27]; +} __attribute__((packed)) fw_desc_entry_v21_t; + +// Version 2, offset->u64 / checksum->sha256 +typedef struct { + u8 type; +#ifdef LITTLE_ENDIAN + u8 reserved:6, + lzma:1, + ro:1; +#else + u8 ro:1, + lzma:1, + reserved:6; +#endif + u32 version; + u32 target_addr; + u64 offset; + u32 length; + u32 paddings; + u8 sha_hash[32];; + u8 reserved_1[6]; +} __attribute__((packed)) fw_desc_entry_v2_t; + +// for fw_desc_table_v1_t.version = FW_DESC_TABLE_V1_T_VERSION_11 +typedef struct { + fw_desc_entry_v2_t v2; + u32 act_size; + u8 hash[32]; + u8 part_num; + u8 reserved[27]; +} __attribute__((packed)) fw_desc_entry_v12_t; + +// for fw_desc_table_v1_t.version = FW_DESC_TABLE_V1_T_VERSION_21 +typedef struct { + fw_desc_entry_v2_t v2; + u32 act_size; + u8 part_num; + u8 RSA_sign[256]; + u8 reserved[27]; +} __attribute__((packed)) fw_desc_entry_v22_t; + +#define FW_ENTRY_MEMBER_SET(val, fw_entry, member, version) \ +{ \ + fw_desc_entry_v1_t* entry_v1 = (fw_desc_entry_v1_t*)fw_entry; \ + fw_desc_entry_v2_t* entry_v2 = (fw_desc_entry_v2_t*)fw_entry; \ + if (FW_DESC_BASE_VERSION(version) == FW_DESC_TABLE_V1_T_VERSION_1) \ + entry_v1->member = val; \ + else if (FW_DESC_BASE_VERSION(version) == FW_DESC_TABLE_V2_T_VERSION_2) \ + entry_v2->member = val; \ +} \ + +#define FW_ENTRY_MEMBER_GET(data, fw_entry, member, version) \ +{ \ + fw_desc_entry_v1_t* entry_v1 = (fw_desc_entry_v1_t*)fw_entry; \ + fw_desc_entry_v2_t* entry_v2 = (fw_desc_entry_v2_t*)fw_entry; \ + if (FW_DESC_BASE_VERSION(version) == FW_DESC_TABLE_V1_T_VERSION_1) \ + data = entry_v1->member; \ + else if (FW_DESC_BASE_VERSION(version) == FW_DESC_TABLE_V2_T_VERSION_2) \ + data = entry_v2->member; \ +} \ + +/* + * Ioctl definitions + */ + +/* Use 'c' as magic number */ +#define AVCPU_IOC_MAGIC 'c' + +/* + * S means "Set" : through a ptr, + * T means "Tell" : directly with the argument value + * G means "Get" : reply by setting through a pointer + * Q means "Query" : response is on the return value + * X means "eXchange" : G and S atomically + * H means "sHift" : T and Q atomically + */ +#define AVCPU_IOCTRESET _IOW(AVCPU_IOC_MAGIC, 1, resetav_struct) +#define AVCPU_IOCTSTOP _IO(AVCPU_IOC_MAGIC, 2) +#define AVCPU_IOCTSTART _IO(AVCPU_IOC_MAGIC, 3) +#define AVCPU_IOCGSTATUS _IOR(AVCPU_IOC_MAGIC, 4, status_struct) +#define AVCPU_IOCGALIVE _IO(AVCPU_IOC_MAGIC, 5) + +#endif /* CONFIG_RTK_ACPU_RELOAD */ + +#endif + diff --git a/include/soc/realtek/kernel-rpc.h b/include/soc/realtek/kernel-rpc.h new file mode 100644 index 000000000000..5d7c901cab4b --- /dev/null +++ b/include/soc/realtek/kernel-rpc.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +/* + * kernel-rpc.h + * + * Copyright (c) 2017-2020 Realtek Semiconductor Corp. + */ + +#ifndef _KERNEL_RPC_H_ +#define _KERNEL_RPC_H_ + +#define RPC_AUDIO 0x0 +#define RPC_VIDEO 0x1 +#define RPC_VIDEO2 0x2 +#define RPC_KCPU 0x3 + +#define RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID +/* + *struct rpc_struct_tp + *@uint32_t programID: program ID defined in IDL file + *@uint32_t versionID: version ID defined in IDL file + *@uint32_t procedureID: function ID defined in IDL file + *@uint32_t taskID: the caller's task ID, assign 0 if NONBLOCK_MODE + *@uint32_t sysTID: N/A + *@uint32_t sysPID: the callee's task ID + *@uint32_t parameterSize: packet's body size + *@uint32_t mycontext: return address of reply value + */ +struct rpc_struct_tp { + uint32_t programID; + uint32_t versionID; + uint32_t procedureID; + uint32_t taskID; +#ifdef RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID + uint32_t sysTID; +#endif /* RPC_SUPPORT_MULTI_CALLER_SEND_TID_PID */ + uint32_t sysPID; + uint32_t parameterSize; + uint32_t mycontext; +}; + +int send_rpc_command(int opt, uint32_t command, uint32_t param1, uint32_t param2, uint32_t *retvalue); + +static inline uint32_t get_rpc_alignment_offset(uint32_t offset) +{ + if ((offset % 4) == 0) + return offset; + else + return (offset + (4 - (offset % 4))); +} + +extern void __iomem *rpc_ringbuf_base; +extern void __iomem *rpc_common_base; +extern void __iomem *rpc_int_base; +extern void __iomem *rpc_acpu_int_flag; +extern void __iomem *rpc_vcpu_int_flag; + +#endif diff --git a/include/soc/realtek/memory.h b/include/soc/realtek/memory.h new file mode 100644 index 000000000000..72ef532f22b2 --- /dev/null +++ b/include/soc/realtek/memory.h @@ -0,0 +1,126 @@ +/* + * memory.h + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define RTK_FLAG_SCPUACC (1U << 1) +#define RTK_FLAG_ACPUACC (1U << 2) +#define RTK_FLAG_HWIPACC (1U << 3) +#define RTK_FLAG_VE_SPEC (1U << 4) +#define RTK_FLAG_PROTECTED_BIT0 (1U << 5) +#define RTK_FLAG_PROTECTED_BIT1 (1U << 6) +#define RTK_FLAG_VCPU_FWACC (1U << 7) /* Less than 512MB */ +#define RTK_FLAG_CMA (1U << 8) +#define RTK_FLAG_PROTECTED_DYNAMIC (1U << 9) +#define RTK_FLAG_PROTECTED_BIT2 (1U << 10) +#define RTK_FLAG_PROTECTED_BIT3 (1U << 11) +#define RTK_FLAG_PROTECTED_MASK \ + (RTK_FLAG_PROTECTED_BIT0 | RTK_FLAG_PROTECTED_BIT1 | \ + RTK_FLAG_PROTECTED_BIT2 | RTK_FLAG_PROTECTED_BIT3) + +#define RTK_FLAG_PROTECTED_EXT_BIT0 (1U << 12) +#define RTK_FLAG_PROTECTED_EXT_BIT1 (1U << 13) +#define RTK_FLAG_PROTECTED_EXT_BIT2 (1U << 14) +#define RTK_FLAG_PROTECTED_EXT_MASK \ + (RTK_FLAG_PROTECTED_EXT_BIT0 | RTK_FLAG_PROTECTED_EXT_BIT1 | \ + RTK_FLAG_PROTECTED_EXT_BIT2) + +#define RTK_PROTECTED_TYPE_NONE (0) +#define RTK_PROTECTED_TYPE_1 (1) +#define RTK_PROTECTED_TYPE_2 (2) +#define RTK_PROTECTED_TYPE_3 (3) +#define RTK_PROTECTED_TYPE_4 (4) +#define RTK_PROTECTED_TYPE_5 (5) +#define RTK_PROTECTED_TYPE_6 (6) +#define RTK_PROTECTED_TYPE_7 (7) +#define RTK_PROTECTED_TYPE_8 (8) +#define RTK_PROTECTED_TYPE_9 (9) +#define RTK_PROTECTED_TYPE_10 (10) +#define RTK_PROTECTED_TYPE_11 (11) +#define RTK_PROTECTED_TYPE_12 (12) +#define RTK_PROTECTED_TYPE_13 (13) +#define RTK_PROTECTED_TYPE_14 (14) +#define RTK_PROTECTED_TYPE_15 (15) + +#define RTK_PROTECTED_EXT_NONE (0) +#define RTK_PROTECTED_EXT_1 (1) +#define RTK_PROTECTED_EXT_2 (2) +#define RTK_PROTECTED_EXT_3 (3) +#define RTK_PROTECTED_EXT_4 (4) +#define RTK_PROTECTED_EXT_5 (5) +#define RTK_PROTECTED_EXT_6 (6) +#define RTK_PROTECTED_EXT_7 (7) + +#define RTK_PROTECTED_MEM_LIMIT (0x80000000) // 2GB + +#define RTK_FLAG_PROTECTED_BITS(TYPE) \ + (((TYPE & (0x1 << 0)) ? RTK_FLAG_PROTECTED_BIT0 : 0) | \ + ((TYPE & (0x1 << 1)) ? RTK_FLAG_PROTECTED_BIT1 : 0) | \ + ((TYPE & (0x1 << 2)) ? RTK_FLAG_PROTECTED_BIT2 : 0) | \ + ((TYPE & (0x1 << 3)) ? RTK_FLAG_PROTECTED_BIT3 : 0)) + +#define RTK_PROTECTED_TYPE_GET(flags) \ + (((flags & RTK_FLAG_PROTECTED_BIT0) ? (0x1 << 0) : 0) | \ + ((flags & RTK_FLAG_PROTECTED_BIT1) ? (0x1 << 1) : 0) | \ + ((flags & RTK_FLAG_PROTECTED_BIT2) ? (0x1 << 2) : 0) | \ + ((flags & RTK_FLAG_PROTECTED_BIT3) ? (0x1 << 3) : 0)) + +#define RTK_FLAG_PROTECTED_EXT_BITS(ext) \ + (((ext & (0x1 << 0)) ? RTK_FLAG_PROTECTED_EXT_BIT0 : 0) | \ + ((ext & (0x1 << 1)) ? RTK_FLAG_PROTECTED_EXT_BIT1 : 0) | \ + ((ext & (0x1 << 2)) ? RTK_FLAG_PROTECTED_EXT_BIT2 : 0)) + +#define RTK_PROTECTED_EXT_GET(flags) \ + (((flags & RTK_FLAG_PROTECTED_EXT_BIT0) ? (0x1 << 0) : 0) | \ + ((flags & RTK_FLAG_PROTECTED_EXT_BIT1) ? (0x1 << 1) : 0) | \ + ((flags & RTK_FLAG_PROTECTED_EXT_BIT2) ? (0x1 << 2) : 0)) + +#define RTK_FLAG_PROTECTED_V2_AUDIO_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_1)) +#define RTK_FLAG_PROTECTED_V2_TP_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_2)) +#define RTK_FLAG_PROTECTED_V2_VO_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_3)) +#define RTK_FLAG_PROTECTED_V2_VIDEO_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_5)) +#define RTK_FLAG_PROTECTED_V2_AO_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_6)) +#define RTK_FLAG_PROTECTED_V2_METADATA_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_7)) +#define RTK_FLAG_PROTECTED_V2_OTA_POOL \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_8)) +#define RTK_FLAG_PROTECTED_V2_FW_STACK \ + (RTK_FLAG_PROTECTED_BITS(RTK_PROTECTED_TYPE_4)) + +#define RTK_FLAG_PROTECTED_IO (RTK_FLAG_PROTECTED_V2_AUDIO_POOL) +#define RTK_FLAG_PROTECTED_TPACC (RTK_FLAG_PROTECTED_V2_TP_POOL) +#define RTK_FLAG_PROTECTED_AFWIO (RTK_FLAG_PROTECTED_V2_VO_POOL) +#define RTK_FLAG_PROTECTED_VIDEO (RTK_FLAG_PROTECTED_V2_VIDEO_POOL) +#define RTK_FLAG_PROTECTED_DYNAMIC_METADATA \ + (RTK_FLAG_PROTECTED_V2_METADATA_POOL | RTK_FLAG_HWIPACC | \ + RTK_FLAG_ACPUACC | RTK_FLAG_VCPU_FWACC) +#define RTK_FLAG_PROTECTED_DYNAMIC_VO \ + (RTK_FLAG_PROTECTED_DYNAMIC | RTK_FLAG_PROTECTED_V2_VO_POOL) +#define RTK_FLAG_PROTECTED_DYNAMIC_OTA \ + (RTK_FLAG_PROTECTED_DYNAMIC | RTK_FLAG_PROTECTED_V2_OTA_POOL) + +#define RTK_FLAG_CMA_POOL (RTK_FLAG_SCPUACC | RTK_FLAG_HWIPACC | RTK_FLAG_CMA) +#define RTK_FLAG_ION_HEAP \ + (RTK_FLAG_SCPUACC | RTK_FLAG_ACPUACC | RTK_FLAG_VCPU_FWACC | \ + RTK_FLAG_HWIPACC) + +#define RTK_FLAG_NONCACHED (1U << 0) /* legacy define */ + +#define RPC_RINGBUF_PHYS (0x040ff000) +#define RPC_RINGBUF_SIZE (0x00004000) + +#endif diff --git a/include/soc/realtek/rtk-usb-manager.h b/include/soc/realtek/rtk-usb-manager.h new file mode 100644 index 000000000000..b9b23e516178 --- /dev/null +++ b/include/soc/realtek/rtk-usb-manager.h @@ -0,0 +1,30 @@ +/* + * rtk-usb-manager.h + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#ifndef __RTK_USB_MANAGER_H_INCLUDED_ +#define __RTK_USB_MANAGER_H_INCLUDED_ + + +int rtk_usb_manager_is_iso_mode(struct device *usb_dev); +int rtk_usb_manager_schedule_work(struct device *usb_dev, + struct work_struct *work); +int rtk_usb_type_c_init(struct device *type_c_dev); +int rtk_usb_type_c_plug_config(struct device *type_c_dev, + int dr_mode, int cc); + +int rtk_usb_init_port_power_on(struct device *usb_dev); + +int rtk_usb_init_port_power_on_off(struct device *usb_dev, bool on); +int rtk_usb_remove_port_power_on_off(struct device *usb_dev, bool on); + +int rtk_usb_port_power_on_off(struct device *usb_dev, bool on); + +#endif // __RTK_USB_MANAGER_H_INCLUDED_ diff --git a/include/soc/realtek/rtk_cec.h b/include/soc/realtek/rtk_cec.h new file mode 100644 index 000000000000..d5c26a804504 --- /dev/null +++ b/include/soc/realtek/rtk_cec.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef __RTK_CEC__H__ +#define __RTK_CEC__H__ + +struct ipc_shm_cec { + unsigned long standby_config; + unsigned char standby_logical_addr; + unsigned short standby_physical_addr; + unsigned char standby_cec_version; + unsigned long standby_vendor_id; + unsigned short standby_rx_mask; + unsigned char standby_cec_wakeup_off; +}; + +#endif diff --git a/include/soc/realtek/rtk_chip.h b/include/soc/realtek/rtk_chip.h new file mode 100644 index 000000000000..5e4ccd0d3f51 --- /dev/null +++ b/include/soc/realtek/rtk_chip.h @@ -0,0 +1,182 @@ +/* + * rtk_chip.h + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#ifndef _RTK_CHIP_H_INCLUDED_ +#define _RTK_CHIP_H_INCLUDED_ + +#include + +enum rtd_chip_id { + CHIP_ID_RTD1195 = 0x1195, + CHIP_ID_RTD129X = 0x1290, + CHIP_ID_RTD1293 = 0x1293, + CHIP_ID_RTD1294 = 0x1294, + CHIP_ID_RTD1295 = 0x1295, + CHIP_ID_RTD1296 = 0x1296, + CHIP_ID_RTD139X = 0x1390, + CHIP_ID_RTD1392 = 0x1392, + CHIP_ID_RTD1395 = 0x1395, + CHIP_ID_RTD161X = 0x1610, + CHIP_ID_RTD1619 = 0x1619, + CHIP_ID_RTD131X = 0x1310, + CHIP_ID_RTD1315 = 0x1315, + CHIP_ID_RTD1317 = 0x1317, + CHIP_ID_RTD1319 = 0x1319, + CHIP_ID_RTD1619B = 0x1619B, + CHIP_ID_RTD1315C = 0x1315C, + CHIP_ID_RTD1312C = 0x1312C, + CHIP_ID_UNKNOWN = 0xFFFFF, +}; + +static inline int get_rtd_chip_id(void) +{ + const struct soc_device_attribute *soc_att_match = NULL; + struct soc_device_attribute rtk_soc[] = { + { + .family = "Realtek Phoenix", + .data = (void *)CHIP_ID_RTD1195, + }, + { + .family = "Realtek Kylin", + .soc_id = "RTD1293", + .data = (void *)CHIP_ID_RTD1293, + }, + { + .family = "Realtek Kylin", + .soc_id = "RTD1294", + .data = (void *)CHIP_ID_RTD1294, + }, + { + .family = "Realtek Kylin", + .soc_id = "RTD1295", + .data = (void *)CHIP_ID_RTD1295, + }, + { + .family = "Realtek Kylin", + .soc_id = "RTD1296", + .data = (void *)CHIP_ID_RTD1296, + }, + { + .family = "Realtek Hercules", + .soc_id = "RTD1392", + .data = (void *)CHIP_ID_RTD1392, + }, + { + .family = "Realtek Hercules", + .soc_id = "RTD1395", + .data = (void *)CHIP_ID_RTD1395, + }, + { + .family = "Realtek Thor", + .soc_id = "RTD1619", + .data = (void *)CHIP_ID_RTD1619, + }, + { + .family = "Realtek Hank", + .soc_id = "RTD1315", + .data = (void *)CHIP_ID_RTD1315, + }, + { + .family = "Realtek Hank", + .soc_id = "RTD1317", + .data = (void *)CHIP_ID_RTD1317, + }, + { + .family = "Realtek Hank", + .soc_id = "RTD1319", + .data = (void *)CHIP_ID_RTD1319, + }, + { + .family = "Realtek Stark", + .soc_id = "RTD1619B", + .data = (void *)CHIP_ID_RTD1619B, + }, + { + .family = "Realtek Stark", + .soc_id = "RTD1315C", + .data = (void *)CHIP_ID_RTD1315C, + }, + { + .family = "Realtek Groot", + .soc_id = "RTD1312C", + .data = (void *)CHIP_ID_RTD1312C, + }, + { + /* empty */ + } + }; + + soc_att_match = soc_device_match(rtk_soc); + if (soc_att_match) { + pr_info("%s get chip id %x\n", __func__, + (int)(uintptr_t)soc_att_match->data); + return (int)(uintptr_t)soc_att_match->data; + } else { + pr_err("%s ERROR: no match chip_id\n", __func__); + return CHIP_ID_UNKNOWN; + } +} + +enum rtd_chip_revision { + RTD_CHIP_A00 = 0xA00, + RTD_CHIP_A01 = 0xA01, + RTD_CHIP_A02 = 0xA02, + RTD_CHIP_B00 = 0xB00, + RTD_CHIP_B01 = 0xB01, + RTD_CHIP_B02 = 0xB02, + RTD_CHIP_UNKNOWN_REV = 0xFFF, +}; + +static inline int get_rtd_chip_revision(void) +{ + const struct soc_device_attribute *soc_att_match = NULL; + struct soc_device_attribute rtk_soc[] = { + { + .revision = "A00", + .data = (void *)RTD_CHIP_A00, + }, + { + .revision = "A01", + .data = (void *)RTD_CHIP_A01, + }, + { + .revision = "A02", + .data = (void *)RTD_CHIP_A02, + }, + { + .revision = "B00", + .data = (void *)RTD_CHIP_B00, + }, + { + .revision = "B01", + .data = (void *)RTD_CHIP_B01, + }, + { + .revision = "B02", + .data = (void *)RTD_CHIP_B02, + }, + { + /* empty */ + } + }; + + soc_att_match = soc_device_match(rtk_soc); + if (soc_att_match) { + pr_info("%s get chip revision %x\n", __func__, + (int)(uintptr_t)soc_att_match->data); + return (int)(uintptr_t)soc_att_match->data; + } else { + pr_err("%s ERROR: no match chip revision\n", __func__); + return RTD_CHIP_UNKNOWN_REV; + } + +} +#endif //_RTK_CHIP_H_INCLUDED_ diff --git a/include/soc/realtek/rtk_cpuhp.h b/include/soc/realtek/rtk_cpuhp.h new file mode 100644 index 000000000000..107a74cde04a --- /dev/null +++ b/include/soc/realtek/rtk_cpuhp.h @@ -0,0 +1,25 @@ +#ifndef __REALTEK_CPUHP_H +#define __REALTEK_CPUHP_H + +#include + +struct rtk_cpuhp_qos_request { + struct plist_node pnode; + struct pm_qos_constraints *qos; +}; + +static inline int rtk_cpuhp_qos_request_active(struct rtk_cpuhp_qos_request *req) +{ + return !IS_ERR_OR_NULL(req->qos); +} + +s32 rtk_cpuhp_qos_read_value(void); + +int rtk_cpuhp_qos_add_request(struct rtk_cpuhp_qos_request *req, s32 value); +int rtk_cpuhp_qos_update_request(struct rtk_cpuhp_qos_request *req, s32 new_value); +int rtk_cpuhp_qos_remove_request(struct rtk_cpuhp_qos_request *req); + +int rtk_cpuhp_qos_add_notifier(struct notifier_block *notifier); +int rtk_cpuhp_qos_remove_notifier(struct notifier_block *notifier); + +#endif diff --git a/include/soc/realtek/rtk_i2c.h b/include/soc/realtek/rtk_i2c.h new file mode 100644 index 000000000000..69064e62c600 --- /dev/null +++ b/include/soc/realtek/rtk_i2c.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Realtek I2C host driver + * + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef _SOC_REALTEK_RTK_I2C_H +#define _SOC_REALTEK_RTK_I2C_H + +#define I2C_M_NO_GUARD_TIME 0x0020 /* disable guard time*/ +#define I2C_GPIO_RW 0x0080 +#define I2C_M_NORMAL_SPEED 0x0000 /* Standard Speed Transmission: 100Kbps */ +#define I2C_M_FAST_SPEED 0x0002 /* Fast Speed Transmission: 400Kbps */ +#define I2C_M_HIGH_SPEED 0x0004 /* High Speed Transmission: > 400Kbps to max 3.4 Mbps */ +#define I2C_M_LOW_SPEED 0x0006 /* Low Speed Transmission: 50Kbps */ +#define I2C_M_LOW_SPEED_80 0x0008 /* Low Speed Transmission: 80Kbps */ +#define I2C_M_LOW_SPEED_66 0x000a /* Low Speed Transmission: 66Kbps */ +#define I2C_M_LOW_SPEED_33 0x000c /* Low Speed Transmission: 33Kbps */ +#define I2C_M_LOW_SPEED_10 0x000e /* Low Speed Transmission: 10Kbps */ +#define I2C_M_SPEED_MASK 0x000e /* speed control*/ + +#endif /* _SOC_REALTEK_RTK_I2C_H */ diff --git a/include/soc/realtek/rtk_ipc_shm.h b/include/soc/realtek/rtk_ipc_shm.h new file mode 100644 index 000000000000..55eb490cb3e9 --- /dev/null +++ b/include/soc/realtek/rtk_ipc_shm.h @@ -0,0 +1,107 @@ +/* + * rtk_ipc_shm.h + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#ifndef __SOC_RTK_IPC_SHM_H +#define __SOC_RTK_IPC_SHM_H + +extern void __iomem *rpc_common_base; +extern void __iomem *rpc_ringbuf_base; + +#define IPC_SHM_VIRT (rpc_common_base + 0x000000C4) + +struct rtk_ipc_shm { + volatile uint32_t sys_assign_serial; + volatile uint32_t pov_boot_vd_std_ptr; + volatile uint32_t pov_boot_av_info; + volatile uint32_t audio_rpc_flag; + volatile uint32_t suspend_mask; + volatile uint32_t suspend_flag; + volatile uint32_t vo_vsync_flag; + volatile uint32_t audio_fw_entry_pt; + volatile uint32_t power_saving_ptr; + volatile unsigned char printk_buffer[24]; + volatile uint32_t ir_extended_tbl_pt; + volatile uint32_t vo_int_sync; + volatile uint32_t bt_wakeup_flag; + volatile uint32_t ir_scancode_mask; + volatile uint32_t ir_wakeup_scancode; + volatile uint32_t suspend_wakeup_flag; + volatile uint32_t acpu_resume_state; + volatile uint32_t gpio_wakeup_enable; + volatile uint32_t gpio_wakeup_activity; + volatile uint32_t gpio_output_change_enable; + volatile uint32_t gpio_output_change_activity; + volatile uint32_t audio_reciprocal_timer_sec; + volatile uint32_t u_boot_version_magic; + volatile uint32_t u_boot_version_info; + volatile uint32_t suspend_watchdog; + volatile uint32_t xen_domu_boot_st; + volatile uint32_t gpio_wakeup_enable2; + volatile uint32_t gpio_wakeup_activity2; + volatile uint32_t gpio_output_change_enable2; + volatile uint32_t gpio_output_change_activity2; + volatile uint32_t gpio_wakeup_enable3; + volatile uint32_t gpio_wakeup_activity3; + volatile uint32_t video_rpc_flag; + volatile uint32_t video_int_sync; + volatile unsigned char video_printk_buffer[24]; + volatile uint32_t video_suspend_mask; + volatile uint32_t video_suspend_flag; + volatile uint32_t ve3_rpc_flag; + volatile uint32_t ve3_int_sync; +}; + +struct avcpu_syslog_struct{ + volatile uint32_t log_buf_addr; + volatile uint32_t log_buf_len; + volatile uint32_t logged_chars; + volatile uint32_t log_start; + volatile uint32_t con_start; + volatile uint32_t log_end; +}; + +#if defined(CONFIG_RTK_XEN_SUPPORT) && defined(CONFIG_RTK_RPC) +#define SETMASK(bits, pos) (((-1U) >> (32-bits)) << (pos)) +#define CLRMASK(bits, pos) (~(SETMASK(bits, pos))) +#define SET_VAL(val,bits,pos) ((val << pos) & SETMASK(bits, pos)) +#define GET_VAL(reg,bits,pos) ((reg & SETMASK(bits, pos)) >> pos) + +#define XEN_DOMU_BOOT_ST_MAGIC_KEY (0xEA) +#define XEN_DOMU_BOOT_ST_MAGIC_KEY_MASK (XEN_DOMU_BOOT_ST_MAGIC_KEY << 24) + +#define XEN_DOMU_BOOT_ST_VERSION_SET(reg) SET_VAL(reg, 4,20) +#define XEN_DOMU_BOOT_ST_VERSION_GET(reg) GET_VAL(reg, 4,20) +#define XEN_DOMU_BOOT_ST_VERSION (1) + +#define XEN_DOMU_BOOT_ST_AUTHOR_SET(reg) SET_VAL(reg, 4,16) +#define XEN_DOMU_BOOT_ST_AUTHOR_GET(reg) GET_VAL(reg, 4,16) +#define XEN_DOMU_BOOT_ST_AUTHOR_ACPU (1) +#define XEN_DOMU_BOOT_ST_AUTHOR_SCPU (2) + +#define XEN_DOMU_BOOT_ST_STATE_SET(reg) SET_VAL(reg, 8, 8) +#define XEN_DOMU_BOOT_ST_STATE_GET(reg) GET_VAL(reg, 8, 8) +#define XEN_DOMU_BOOT_ST_STATE_SCPU_BOOT (1) +#define XEN_DOMU_BOOT_ST_STATE_SCPU_RESTART (2) +#define XEN_DOMU_BOOT_ST_STATE_SCPU_POWOFF (3) +#define XEN_DOMU_BOOT_ST_STATE_ACPU_LOCK (4) +#define XEN_DOMU_BOOT_ST_STATE_ACPU_UNLOCK (5) +#define XEN_DOMU_BOOT_ST_STATE_SCPU_WAIT_DONE (6) +#define XEN_DOMU_BOOT_ST_STATE_ACPU_ENTER_IDLE (7) +#define XEN_DOMU_BOOT_ST_STATE_SCPU_SUSPEND (8) +#define XEN_DOMU_BOOT_ST_STATE_SCPU_RESUME (9) +#define XEN_DOMU_BOOT_ST_STATE_ACPU_ACK (10) + + +#define XEN_DOMU_BOOT_ST_EXT_SET(reg) SET_VAL(reg, 8, 0) +#define XEN_DOMU_BOOT_ST_EXT_GET(reg) GET_VAL(reg, 8, 0) +#endif /* defined(CONFIG_RTK_XEN_SUPPORT) && defined(CONFIG_RTK_RPC) */ + +#endif /* End of __SOC_RTK_IPC_SHM_H */ diff --git a/include/soc/realtek/rtk_ir.h b/include/soc/realtek/rtk_ir.h new file mode 100644 index 000000000000..07306c01f78b --- /dev/null +++ b/include/soc/realtek/rtk_ir.h @@ -0,0 +1,32 @@ +/* + * rtk_ir.h + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ +#ifndef __RTK_IR__H__ +#define __RTK_IR__H__ + +#define MAX_WAKEUP_CODE 16 +#define MAX_KEY_TBL 2 + +struct irda_wake_up_key { + unsigned int protocol; + unsigned int scancode_mask; + unsigned int wakeup_keynum; + unsigned int wakeup_scancode[MAX_WAKEUP_CODE]; + unsigned int cus_mask; + unsigned int cus_code; +}; + +struct ipc_shm_irda { + unsigned int ipc_shm_ir_magic; + unsigned int dev_count; + struct irda_wake_up_key key_tbl[MAX_KEY_TBL]; +}; + +#endif diff --git a/include/soc/realtek/rtk_iso.h b/include/soc/realtek/rtk_iso.h new file mode 100644 index 000000000000..fd34541faec0 --- /dev/null +++ b/include/soc/realtek/rtk_iso.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __SOC_REALTEK_ISO_H +#define __SOC_REALTEK_ISO_H + +#define ISO_ISR 0x00 +#define ISO_ISR_I2C1_REQ_INT 0x80000000 +#define ISO_ISR_PORB_AV_CEN_INT 0x40000000 +#define ISO_ISR_PORB_DV_CEN_INT 0x20000000 +#define ISO_ISR_PORB_HV_CEN_INT 0x10000000 +#define ISO_ISR_USB_INT_U2_DRD 0x04000000 +#define ISO_ISR_USB_INT_U3_DRD 0x02000000 +#define ISO_ISR_USB_INT_HOST 0x01000000 +#define ISO_ISR_ETN_INT 0x00800000 +#define ISO_ISR_CBUS_INT 0x00400000 +#define ISO_ISR_ISO_MISC_INT 0x00200000 +#define ISO_ISR_GPIODA_INT 0x00100000 +#define ISO_ISR_GPIOA_INT 0x00080000 +#define ISO_ISR_RTC_ALARM_INT 0x00002000 +#define ISO_ISR_RTC_HSEC_INT 0x00001000 +#define ISO_ISR_I2C1_INT 0x00000800 +#define ISO_ISR_TC7_INT 0x00000400 +#define ISO_ISR_TC4_INT 0x00000200 +#define ISO_ISR_I2C0_INT 0x00000100 +#define ISO_ISR_WDOG_NMI_INT 0x00000080 +#define ISO_ISR_SPI1_INT 0x00000040 +#define ISO_ISR_IRDA_INT 0x00000020 +#define ISO_ISR_LSADC0_INT 0x00000008 +#define ISO_ISR_UR0_INT 0x00000004 +#define ISO_ISR_TC3_INT 0x00000002 +#define ISO_ISR_WRITE_DATA 0x00000001 +#define ISO_ISR_CLEAR_DATA 0x00000000 + + +#define ISO_UMSK_ISR 0x04 +#define ISO_UMSK_ISR_I2C1_REQ_INT 0x80000000 +#define ISO_UMSK_ISR_PORB_AV_CEN_INT 0x40000000 +#define ISO_UMSK_ISR_PORB_DV_CEN_INT 0x20000000 +#define ISO_UMSK_ISR_PORB_HV_CEN_INT 0x10000000 +#define ISO_UMSK_ISR_ETN_PHY_INTR 0x08000000 +#define ISO_UMSK_ISR_GPIODA_INT 0x00100000 +#define ISO_UMSK_ISR_GPIOA_INT 0x00080000 +#define ISO_UMSK_ISR_RTC_ALARM_INT 0x00002000 +#define ISO_UMSK_ISR_RTC_HSEC_INT 0x00001000 +#define ISO_UMSK_ISR_TC7_INT 0x00000400 +#define ISO_UMSK_ISR_TC4_INT 0x00000200 +#define ISO_UMSK_ISR_WDOG_NMI_INT 0x00000080 +#define ISO_UMSK_ISR_SPI1_INT 0x00000040 +#define ISO_UMSK_ISR_IRDA_INT 0x00000020 +#define ISO_UMSK_ISR_TC3_INT 0x00000002 +#define ISO_UMSK_ISR_WRITE_DATA 0x00000001 +#define ISO_UMSK_ISR_CLEAR_DATA 0x00000000 + +#define ISO_RTC 0x34 +#define ISO_RTC_HSEC_SYNC 0x00000004 +#define ISO_RTC_HSEC_INT_EN 0x00000002 +#define ISO_RTC_ALARM_INT_EN 0x00000001 + +#endif diff --git a/include/soc/realtek/rtk_misc.h b/include/soc/realtek/rtk_misc.h new file mode 100644 index 000000000000..bb6607d33b91 --- /dev/null +++ b/include/soc/realtek/rtk_misc.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __SOC_REALTEK_MISC_H +#define __SOC_REALTEK_MISC_H + +#define MIS_ISR 0x0C + +#define MIS_ISR_FAN_INT 0x20000000 +#define MIS_ISR_SPI_INT 0x08000000 +#define MIS_ISR_SC1_INT 0x02000000 +#define MIS_ISR_SC0_INT 0x01000000 +#define MIS_ISR_I2C3_INT 0x00800000 +#define MIS_ISR_I2C5_INT 0x00004000 +#define MIS_ISR_UR2_TO_INT 0x00002000 +#define MIS_ISR_RTC_DATE_INT 0x00001000 +#define MIS_ISR_RTC_HOUR_INT 0x00000800 +#define MIS_ISR_RTC_MIN_INT 0x00000400 +#define MIS_ISR_RTC_HSEC_INT 0x00000200 +#define MIS_ISR_UR2_INT 0x00000100 +#define MIS_ISR_TC1_INT 0x00000080 +#define MIS_ISR_TC0_INT 0x00000040 +#define MIS_ISR_UR1_TO_INT 0x00000020 +#define MIS_ISR_TC5_INT 0x00000010 +#define MIS_ISR_UR1_INT 0x00000008 +#define MIS_ISR_WDOG_NMI_INT 0x00000004 +#define MIS_ISR_WRITE_DATA 0x00000001 +#define MIS_ISR_CLEAR_DATA 0x00000000 + +#endif diff --git a/include/soc/realtek/rtk_pcie.h b/include/soc/realtek/rtk_pcie.h new file mode 100644 index 000000000000..66d44066892b --- /dev/null +++ b/include/soc/realtek/rtk_pcie.h @@ -0,0 +1,18 @@ +/* + * rtk_pcie.h + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +void rtk_pcie_13xx_write(u32 addr, u8 size, u32 wval); +u32 rtk_pcie_13xx_read(u32 addr, u8 size); +void rtk_pcie2_13xx_write(u32 addr, u8 size, u32 wval); +u32 rtk_pcie2_13xx_read(u32 addr, u8 size); +void rtk_pcie3_13xx_write(u32 addr, u8 size, u32 wval); +u32 rtk_pcie3_13xx_read(u32 addr, u8 size); + diff --git a/include/soc/realtek/rtk_pm.h b/include/soc/realtek/rtk_pm.h new file mode 100644 index 000000000000..abf838454af5 --- /dev/null +++ b/include/soc/realtek/rtk_pm.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +/* + * Realtek DHC SoC family power management driver + * + * Copyright (c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef _RTK_PM_H_ +#define _RTK_PM_H_ + +#include +#include +#include +#include + +#define GPIO_MAX_SIZE 86 +#define MEM_VERIFIED_CNT 100 + +#define OSC_COUNT_LIMIT 0x800 +#define PLL_ETN_OSC 0x7a4 +#define DCO0 0x79c +#define DCO1 0x0f4 + +enum rtk_pm_driver_id { + PM = 0, + LAN, + IRDA, + GPIO, + ALARM_TIMER, + TIMER, + CEC, + USB, +}; + +enum rtk_cpu_type { + SCPU = 0x1, + ACPU, + VCPU, +}; + +/* A/V CPU power control */ +enum rtk_cpu_ctrl { + ACPU_OFF = 10, + VCPU_OFF, + ACPU_ON, + VCPU_ON, +}; + +enum rtk_wakeup_event { + LAN_EVENT = 0, + IR_EVENT, + GPIO_EVENT, + ALARM_EVENT, + TIMER_EVENT, + CEC_EVENT, + USB_EVENT, + HIFI_EVENT, + VTC_EVENT, + PON_EVENT, + MAX_EVENT, +}; + +struct pm_dev_param { + struct device *dev; + struct list_head list; + unsigned int dev_type; + void *data; +}; + +struct pm_pcpu_param { + unsigned int wakeup_source; + unsigned int timerout_val; + char wu_gpio_en[GPIO_MAX_SIZE]; + char wu_gpio_act[GPIO_MAX_SIZE]; + struct ipc_shm_irda irda_info; + struct ipc_shm_cec cec_info; +} __packed; + +struct pm_private { + struct device *dev; + struct list_head list; + struct notifier_block pm_notifier; + struct pm_dev_param *device_param; + struct pm_pcpu_param *pcpu_param; + dma_addr_t pcpu_param_pa; + struct regmap *syscon_iso; + unsigned int pm_dbg; + unsigned int reboot_reasons; + unsigned int wakeup_reason; + unsigned int suspend_context; +}; + +struct mem_check { + unsigned char *mem_addr; + size_t mem_byte; +}; + +unsigned int notify_fw_on(struct device *dev, uint32_t cpu); +unsigned int notify_fw_off(struct device *dev, uint32_t cpu); + +extern void rtk_pm_init_list(void); +extern void rtk_pm_add_list(struct pm_dev_param *pm_node); +extern struct pm_dev_param *rtk_pm_get_param(unsigned int id); +extern int rtk_pm_create_sysfs(void); +extern void rtk_pm_set_pcpu_param(struct device *dev); + +#endif diff --git a/include/soc/realtek/rtk_refclk.h b/include/soc/realtek/rtk_refclk.h new file mode 100644 index 000000000000..680008f8fb5a --- /dev/null +++ b/include/soc/realtek/rtk_refclk.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __SOC_REALTEK_REFCLK_H +#define __SOC_REALTEK_REFCLK_H + +#include +#include + +struct device_node; +struct refclk_device; + +struct refclk_device *of_refclk_get(struct device_node *np, int index); +struct refclk_device *refclk_get_by_name(const char *name); +void refclk_put(struct refclk_device *refclk); +u64 refclk_get_counter(struct refclk_device *refclk); + +/* convert the counter value to time ms */ +static inline u64 refclk_get_time_ms(struct refclk_device *refclk) +{ + u64 val = refclk_get_counter(refclk); + + do_div(val, 90); + return val; +} + +#endif diff --git a/include/soc/realtek/rtk_rstctl.h b/include/soc/realtek/rtk_rstctl.h new file mode 100644 index 000000000000..066993a23d07 --- /dev/null +++ b/include/soc/realtek/rtk_rstctl.h @@ -0,0 +1,29 @@ +/* + * rtk_rstctl.h + * + * Copyright (c) 2018 Realtek Semiconductor Corp. + * + * 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. + * + */ +#ifndef __RTK_RSTCTL_H__ +#define __RTK_RSTCTL_H__ + +#define RESET_MAGIC 0xAABBCC00 + +typedef enum { + RESET_ACTION_NO_ACTION = 0, + RESET_ACTION_FASTBOOT, + RESET_ACTION_RECOVERY, + RESET_ACTION_GOLDEN, + RESET_ACTION_RESCUE, + RESET_ACTION_FASTBOOTD, + RESET_ACTION_QUIESCENT, + RESET_ACTION_WARMBOOT_ABNORMAL, + RESET_ACTION_COLDBOOT_ABNORMAL, + RESET_ACTION_ABNORMAL = 0xff, +}RESET_ACTION; + +#endif /* __RTK_RSTCTL_H__ */ diff --git a/include/soc/realtek/rtk_sb2_dbg.h b/include/soc/realtek/rtk_sb2_dbg.h new file mode 100644 index 000000000000..26536953cab4 --- /dev/null +++ b/include/soc/realtek/rtk_sb2_dbg.h @@ -0,0 +1,61 @@ +/* + * rtk_sb2_dbg.h - Realtek SB2 Debug API + * + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Copyright (C) 2019 Cheng-Yu Lee + * + * 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 __SOC_REALTEK_SB2_DGB_H +#define __SOC_REALTEK_SB2_DGB_H + +enum { + SB2_DBG_SOURCE_SCPU, + SB2_DBG_SOURCE_ACPU, + SB2_DBG_SOURCE_PCPU, + SB2_DBG_SOURCE_VCPU, +}; + +enum { + SB2_DBG_ACCESS_DATA, + SB2_DBG_ACCESS_INST, + SB2_DBG_ACCESS_READ, + SB2_DBG_ACCESS_WRITE, +}; + +enum { + SB2_DBG_MONITOR_DATA = 0x04, + SB2_DBG_MONITOR_INST = 0x08, + SB2_DBG_MONITOR_READ = 0x20, + SB2_DBG_MONITOR_WRITE = 0x40, +}; + +struct sb2_dbg_event_data { + u32 raw_ints; + u32 source; + u32 rw; + u32 di; + u32 addr; +}; + +enum { + SB2_INV_UNKNOWN = 0, + SB2_INV_SCPU = 1, + SB2_INV_PCPU = 2, + SB2_INV_ACPU = 3, + SB2_INV_SCPU_SWC = 4, + SB2_INV_PCPU_2 = 5, + SB2_INV_VCPU = 6, +}; + +struct sb2_inv_event_data { + u32 raw_ints; + u32 addr; + u32 inv_cpu; + u32 timeout_th; +}; + +#endif diff --git a/include/soc/realtek/rtk_sb2_sem.h b/include/soc/realtek/rtk_sb2_sem.h new file mode 100644 index 000000000000..690b12e253ac --- /dev/null +++ b/include/soc/realtek/rtk_sb2_sem.h @@ -0,0 +1,39 @@ +/* + * rtk_sb2_sem.h - Realtek SB2 HW semaphore API + * + * Copyright (C) 2017 Realtek Semiconductor Corporation + * Copyright (C) 2017 Cheng-Yu Lee + * + * 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 __SOC_REALTEK_SB2_SEM_H +#define __SOC_REALTEK_SB2_SEM_H + +struct sb2_sem; +struct sb2_sem *sb2_sem_get(unsigned int index); +int sb2_sem_try_lock(struct sb2_sem *sem, unsigned int flags); +void sb2_sem_lock(struct sb2_sem *sem, unsigned int flags); +void sb2_sem_unlock(struct sb2_sem *sem); +struct sb2_sem *sb2_sem_node_to_lock(struct device_node *np); + +#define SB2_SEM_NO_WARNING 0x2 +#define SB2_SEM_TIMEOUT_INFINITY 0x4 + +static inline struct sb2_sem *of_sb2_sem_get(const struct device_node *np, + int index) +{ + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_fixed_args(np, "realtek,sb2-lock", 0, + index, &args); + if (ret) + return ERR_PTR(ret); + + return sb2_sem_node_to_lock(args.np); +} + +#endif diff --git a/include/soc/realtek/rtk_sha1.h b/include/soc/realtek/rtk_sha1.h new file mode 100644 index 000000000000..210b47d00b1c --- /dev/null +++ b/include/soc/realtek/rtk_sha1.h @@ -0,0 +1,40 @@ +/* + * rtk_sha1.h - sha1 API + * + * Copyright (c) 2017 Realtek Semiconductor Corp. + * + * 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. + * + */ + +/******************************************************************************** + SHA-1 Hashing + ********************************************************************************/ +#ifndef __RTK_SHA1_H__ +#define __RTK_SHA1_H__ + +#define uint8_t unsigned char +#define uint32_t unsigned int + +typedef struct { + unsigned int state[5]; + unsigned int count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +#define SHA1_FILE_HASHING_BUFFER_SIZE FILE_HASHING_BUFFER_SIZE +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 +#define SHA1_ALIGNMENT_CHECK 0x3F + +int MCP_SHA1_Get_Hash( unsigned char * source, unsigned int source_len, unsigned char * hash ); +void MCP_SHA1_dump_hex( unsigned char * pbuf, unsigned int len ); + +void SHA1_Transform(unsigned int state[5], const unsigned char buffer[64]); +void SHA1_Init(SHA1_CTX * context); +void SHA1_Update(SHA1_CTX * context, const unsigned char * data, const size_t len); +void SHA1_Final(SHA1_CTX * context, unsigned char digest[SHA1_DIGEST_SIZE]); + +#endif // __RTK_SHA1_H__ diff --git a/include/soc/realtek/uapi/ashmem.h b/include/soc/realtek/uapi/ashmem.h new file mode 100644 index 000000000000..13df42d200b7 --- /dev/null +++ b/include/soc/realtek/uapi/ashmem.h @@ -0,0 +1,48 @@ +/* + * drivers/staging/android/uapi/ashmem.h + * + * Copyright 2008 Google Inc. + * Author: Robert Love + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#ifndef _UAPI_LINUX_ASHMEM_H +#define _UAPI_LINUX_ASHMEM_H + +#include +#include + +#define ASHMEM_NAME_LEN 256 + +#define ASHMEM_NAME_DEF "dev/ashmem" + +/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */ +#define ASHMEM_NOT_PURGED 0 +#define ASHMEM_WAS_PURGED 1 + +/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */ +#define ASHMEM_IS_UNPINNED 0 +#define ASHMEM_IS_PINNED 1 + +struct ashmem_pin { + __u32 offset; /* offset into region, in bytes, page-aligned */ + __u32 len; /* length forward from offset, in bytes, page-aligned */ +}; + +#define __ASHMEMIOC 0x77 + +#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN]) +#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN]) +#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t) +#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4) +#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long) +#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6) +#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin) +#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin) +#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9) +#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10) + +#endif /* _UAPI_LINUX_ASHMEM_H */ diff --git a/include/soc/realtek/uapi/ion.h b/include/soc/realtek/uapi/ion.h new file mode 100644 index 000000000000..9e21451149d0 --- /dev/null +++ b/include/soc/realtek/uapi/ion.h @@ -0,0 +1,136 @@ +/* + * drivers/staging/android/uapi/ion.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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_ION_H +#define _UAPI_LINUX_ION_H + +#include +#include + +/** + * enum ion_heap_types - list of all possible types of heaps + * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc + * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc + * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved + * carveout heap, allocations are physically + * contiguous + * @ION_HEAP_TYPE_DMA: memory allocated via DMA API + * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask + * is used to identify the heaps, so only 32 + * total heap types are supported + */ +enum ion_heap_type { + ION_HEAP_TYPE_SYSTEM, + ION_HEAP_TYPE_SYSTEM_CONTIG, + ION_HEAP_TYPE_CARVEOUT, + ION_HEAP_TYPE_CHUNK, + ION_HEAP_TYPE_DMA, + ION_HEAP_TYPE_CUSTOM, /* + * must be last so device specific heaps always + * are at the end of this enum + */ +}; + +#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8) + +/** + * allocation flags - the lower 16 bits are used by core ion, the upper 16 + * bits are reserved for use by the heaps themselves. + */ + +/* + * mappings of this buffer should be cached, ion will do cache maintenance + * when the buffer is mapped for dma + */ +#define ION_FLAG_CACHED 1 + +/** + * DOC: Ion Userspace API + * + * create a client by opening /dev/ion + * most operations handled via following ioctls + * + */ + +/** + * struct ion_allocation_data - metadata passed from userspace for allocations + * @len: size of the allocation + * @heap_id_mask: mask of heap ids to allocate from + * @flags: flags passed to heap + * @handle: pointer that will be populated with a cookie to use to + * refer to this allocation + * + * Provided by userspace as an argument to the ioctl + */ +struct ion_allocation_data { + __u64 len; + __u32 heap_id_mask; + __u32 flags; + __u32 fd; + __u32 unused; +}; + +#define MAX_HEAP_NAME 32 + +/** + * struct ion_heap_data - data about a heap + * @name - first 32 characters of the heap name + * @type - heap type + * @heap_id - heap id for the heap + */ +struct ion_heap_data { + char name[MAX_HEAP_NAME]; + __u32 type; + __u32 heap_id; + __u32 reserved0; + __u32 reserved1; + __u32 reserved2; +}; + +/** + * struct ion_heap_query - collection of data about all heaps + * @cnt - total number of heaps to be copied + * @heaps - buffer to copy heap data + */ +struct ion_heap_query { + __u32 cnt; /* Total number of heaps to be copied */ + __u32 reserved0; /* align to 64bits */ + __u64 heaps; /* buffer to be populated */ + __u32 reserved1; + __u32 reserved2; +}; + +#define ION_IOC_MAGIC 'I' + +/** + * DOC: ION_IOC_ALLOC - allocate memory + * + * Takes an ion_allocation_data struct and returns it with the handle field + * populated with the opaque handle for the allocation. + */ +#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_allocation_data) + +/** + * DOC: ION_IOC_HEAP_QUERY - information about available heaps + * + * Takes an ion_heap_query structure and populates information about + * available Ion heaps. + */ +#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \ + struct ion_heap_query) + +#endif /* _UAPI_LINUX_ION_H */ diff --git a/include/soc/realtek/uapi/ion_rtk.h b/include/soc/realtek/uapi/ion_rtk.h new file mode 100644 index 000000000000..f0ee6b368385 --- /dev/null +++ b/include/soc/realtek/uapi/ion_rtk.h @@ -0,0 +1,164 @@ +#ifndef __LINUX_ION_RTK_H_ +#define __LINUX_ION_RTK_H_ +/* ion_rtk.h + * + * Copyright (c) 2019 Realtek Semiconductor Corp. + * + * 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. + * + */ + +#include "ion.h" + +#define ION_FLAG_CACHED_NEEDS_SYNC 2 + +#define ION_FLAG_NONCACHED (1 << 31) +#define ION_FLAG_SCPUACC (1 << 30) +#define ION_FLAG_ACPUACC (1 << 29) +#define ION_FLAG_HWIPACC (1 << 28) +#define ION_FLAG_VE_SPEC (1 << 27) +#define ION_FLAG_PROTECTED_BIT0 (1 << 26) +#define ION_FLAG_PROTECTED_BIT1 (1 << 25) +#define ION_FLAG_PROTECTED_BIT2 (1 << 24) +#define ION_FLAG_PROTECTED_BIT3 (1 << 16) +#define ION_FLAG_PROTECTED_MASK (ION_FLAG_PROTECTED_BIT3 | ION_FLAG_PROTECTED_BIT2 | ION_FLAG_PROTECTED_BIT1 | ION_FLAG_PROTECTED_BIT0) + +#define ION_FLAG_PROTECTED_EXT_BIT0 (1U << 15) +#define ION_FLAG_PROTECTED_EXT_BIT1 (1U << 14) +#define ION_FLAG_PROTECTED_EXT_BIT2 (1U << 13) +#define ION_FLAG_PROTECTED_EXT_MASK (ION_FLAG_PROTECTED_EXT_BIT0 | ION_FLAG_PROTECTED_EXT_BIT1 | ION_FLAG_PROTECTED_EXT_BIT2) + +enum E_ION_PROTECTED_TYPE { + ION_PROTECTED_TYPE_NONE = 0, + ION_PROTECTED_TYPE_1, + ION_PROTECTED_TYPE_2, + ION_PROTECTED_TYPE_3, + ION_PROTECTED_TYPE_4, + ION_PROTECTED_TYPE_5, + ION_PROTECTED_TYPE_6, + ION_PROTECTED_TYPE_7, + ION_PROTECTED_TYPE_8, + ION_PROTECTED_TYPE_9, + ION_PROTECTED_TYPE_10, + ION_PROTECTED_TYPE_11, + ION_PROTECTED_TYPE_12, + ION_PROTECTED_TYPE_13, + ION_PROTECTED_TYPE_14, + ION_PROTECTED_TYPE_15, + ION_PROTECTED_TYPE_MAX, +}; + +enum E_ION_PROTECTED_EXT { + ION_PROTECTED_EXT_NONE = 0, + ION_PROTECTED_EXT_1, + ION_PROTECTED_EXT_2, + ION_PROTECTED_EXT_3, + ION_PROTECTED_EXT_4, + ION_PROTECTED_EXT_5, + ION_PROTECTED_EXT_6, + ION_PROTECTED_EXT_7, + ION_PROTECTED_EXT_MAX, +}; + +#define ION_FLAG_PROTECTED_BITS(type) ( \ + ((type & (0x1 << 0)) ? ION_FLAG_PROTECTED_BIT0 : 0) |\ + ((type & (0x1 << 1)) ? ION_FLAG_PROTECTED_BIT1 : 0) |\ + ((type & (0x1 << 2)) ? ION_FLAG_PROTECTED_BIT2 : 0) |\ + ((type & (0x1 << 3)) ? ION_FLAG_PROTECTED_BIT3 : 0)) + +#define ION_PROTECTED_TYPE_GET(flags) (\ + ((flags & ION_FLAG_PROTECTED_BIT0) ? (0x1 << 0) : 0) |\ + ((flags & ION_FLAG_PROTECTED_BIT1) ? (0x1 << 1) : 0) |\ + ((flags & ION_FLAG_PROTECTED_BIT2) ? (0x1 << 2) : 0) |\ + ((flags & ION_FLAG_PROTECTED_BIT3) ? (0x1 << 3) : 0)) + +#define ION_FLAG_PROTECTED_EXT_BITS(ext) ( \ + ((ext & (0x1 << 0)) ? ION_FLAG_PROTECTED_EXT_BIT0 : 0) |\ + ((ext & (0x1 << 1)) ? ION_FLAG_PROTECTED_EXT_BIT1 : 0) |\ + ((ext & (0x1 << 2)) ? ION_FLAG_PROTECTED_EXT_BIT2 : 0)) + +#define ION_PROTECTED_EXT_GET(flags) (\ + ((flags & ION_FLAG_PROTECTED_EXT_BIT0) ? (0x1 << 0) : 0) |\ + ((flags & ION_FLAG_PROTECTED_EXT_BIT1) ? (0x1 << 1) : 0) |\ + ((flags & ION_FLAG_PROTECTED_EXT_BIT2) ? (0x1 << 2) : 0)) + +#define ION_FLAG_PROTECTED_V2_AUDIO_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_1)) +#define ION_FLAG_PROTECTED_V2_TP_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_2)) +#define ION_FLAG_PROTECTED_V2_VO_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_3)) +#define ION_FLAG_PROTECTED_V2_VIDEO_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_5)) +#define ION_FLAG_PROTECTED_V2_AO_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_6)) +#define ION_FLAG_PROTECTED_V2_METADATA_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_7)) +#define ION_FLAG_PROTECTED_V2_OTA_POOL (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_8)) +#define ION_FLAG_PROTECTED_V2_FW_STACK (ION_FLAG_PROTECTED_BITS(ION_PROTECTED_TYPE_4)) + +#define ION_FLAG_PROTECTED_IO (ION_FLAG_PROTECTED_V2_AUDIO_POOL) +#define ION_FLAG_PROTECTED_TPACC (ION_FLAG_PROTECTED_V2_TP_POOL) +#define ION_FLAG_PROTECTED_AFWIO (ION_FLAG_PROTECTED_V2_VO_POOL) +#define ION_FLAG_PROTECTED_VIDEO (ION_FLAG_PROTECTED_V2_VIDEO_POOL) + +#define ION_FLAG_PROTECTED ION_FLAG_PROTECTED_IO /* legacy */ +#define ION_FLAG_SECURE_AUDIO ION_FLAG_PROTECTED_IO /* legacy */ + +#define ION_FLAG_VCPU_FWACC (1 << 18) +#define ION_FLAG_CMA (1 << 17) +#define RTK_ION_FLAG_POOL_CONDITION (\ + ION_FLAG_ACPUACC | \ + ION_FLAG_SCPUACC | \ + ION_FLAG_HWIPACC | \ + ION_FLAG_VE_SPEC | \ + ION_FLAG_PROTECTED_MASK | \ + ION_FLAG_VCPU_FWACC | \ + ION_FLAG_CMA) + +#define ION_USAGE_PROTECTED (1 << 23) +#define ION_USAGE_MMAP_NONCACHED (1 << 22) +#define ION_USAGE_MMAP_CACHED (1 << 21) +#define ION_USAGE_MMAP_WRITECOMBINE (1 << 20) +#define ION_USAGE_ALGO_LAST_FIT (1 << 19) /* 0:first fit(default), 1:last fit */ +#define ION_USAGE_MASK (ION_USAGE_PROTECTED | ION_USAGE_MMAP_NONCACHED | ION_USAGE_MMAP_CACHED | ION_USAGE_MMAP_WRITECOMBINE | ION_USAGE_ALGO_LAST_FIT) + +enum { + RTK_ION_HEAP_TYPE_TILER = ION_HEAP_TYPE_CUSTOM + 1, + RTK_ION_HEAP_TYPE_MEDIA, + RTK_ION_HEAP_TYPE_AUDIO, + RTK_ION_HEAP_TYPE_SECURE, +}; + +#define RTK_ION_HEAP_TILER_MASK (1 << RTK_ION_HEAP_TYPE_TILER) +#define RTK_ION_HEAP_MEDIA_MASK (1 << RTK_ION_HEAP_TYPE_MEDIA) +#define RTK_ION_HEAP_AUDIO_MASK (1 << RTK_ION_HEAP_TYPE_AUDIO) +#define RTK_ION_HEAP_SECURE_MASK (1 << RTK_ION_HEAP_TYPE_SECURE) + +struct rtk_ion_ioc_get_memory_info_s { + int handle; + unsigned int heapMask; /* request: select the heap to be queried */ + unsigned int flags; /* request: set the conditions to query, 0 is to query all the conditions */ + unsigned int usedSize; /* response */ + unsigned int freeSize; /* response */ +}; + +struct rtk_ion_ioc_sync_rane { + int handle; + u32 phyAddr; + unsigned int len; +}; + +struct rtk_ion_ioc_phy_info { + int handle; + unsigned long long addr; + unsigned long long len; +}; + + +#define RTK_ION_IOC_MAGIC 'R' +#define RTK_ION_TILER_ALLOC (0x0) +#define RTK_ION_GET_LAST_ALLOC_ADDR (0x1) +#define RTK_ION_IOC_INVALIDATE (0x10) +#define RTK_ION_IOC_FLUSH (0x11) +#define RTK_ION_IOC_GET_MEMORY_INFO _IOWR(RTK_ION_IOC_MAGIC, 0x12, struct rtk_ion_ioc_get_memory_info_s) +#define RTK_ION_IOC_INVALIDATE_RANGE (0x13) +#define RTK_ION_IOC_FLUSH_RANGE (0x14) +#define RTK_ION_IOC_GET_PHYINFO (0x15) +#endif /* __LINUX_ION_RTK_H_ */ diff --git a/include/soc/realtek/uapi/vsoc_shm.h b/include/soc/realtek/uapi/vsoc_shm.h new file mode 100644 index 000000000000..741b1387c25b --- /dev/null +++ b/include/soc/realtek/uapi/vsoc_shm.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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_VSOC_SHM_H +#define _UAPI_LINUX_VSOC_SHM_H + +#include + +/** + * A permission is a token that permits a receiver to read and/or write an area + * of memory within a Vsoc region. + * + * An fd_scoped permission grants both read and write access, and can be + * attached to a file description (see open(2)). + * Ownership of the area can then be shared by passing a file descriptor + * among processes. + * + * begin_offset and end_offset define the area of memory that is controlled by + * the permission. owner_offset points to a word, also in shared memory, that + * controls ownership of the area. + * + * ownership of the region expires when the associated file description is + * released. + * + * At most one permission can be attached to each file description. + * + * This is useful when implementing HALs like gralloc that scope and pass + * ownership of shared resources via file descriptors. + * + * The caller is responsibe for doing any fencing. + * + * The calling process will normally identify a currently free area of + * memory. It will construct a proposed fd_scoped_permission_arg structure: + * + * begin_offset and end_offset describe the area being claimed + * + * owner_offset points to the location in shared memory that indicates the + * owner of the area. + * + * owned_value is the value that will be stored in owner_offset iff the + * permission can be granted. It must be different than VSOC_REGION_FREE. + * + * Two fd_scoped_permission structures are compatible if they vary only by + * their owned_value fields. + * + * The driver ensures that, for any group of simultaneous callers proposing + * compatible fd_scoped_permissions, it will accept exactly one of the + * propopsals. The other callers will get a failure with errno of EAGAIN. + * + * A process receiving a file descriptor can identify the region being + * granted using the VSOC_GET_FD_SCOPED_PERMISSION ioctl. + */ +struct fd_scoped_permission { + __u32 begin_offset; + __u32 end_offset; + __u32 owner_offset; + __u32 owned_value; +}; + +/* + * This value represents a free area of memory. The driver expects to see this + * value at owner_offset when creating a permission otherwise it will not do it, + * and will write this value back once the permission is no longer needed. + */ +#define VSOC_REGION_FREE ((__u32)0) + +/** + * ioctl argument for VSOC_CREATE_FD_SCOPE_PERMISSION + */ +struct fd_scoped_permission_arg { + struct fd_scoped_permission perm; + __s32 managed_region_fd; +}; + +#define VSOC_NODE_FREE ((__u32)0) + +/* + * Describes a signal table in shared memory. Each non-zero entry in the + * table indicates that the receiver should signal the futex at the given + * offset. Offsets are relative to the region, not the shared memory window. + * + * interrupt_signalled_offset is used to reliably signal interrupts across the + * vmm boundary. There are two roles: transmitter and receiver. For example, + * in the host_to_guest_signal_table the host is the transmitter and the + * guest is the receiver. The protocol is as follows: + * + * 1. The transmitter should convert the offset of the futex to an offset + * in the signal table [0, (1 << num_nodes_lg2)) + * The transmitter can choose any appropriate hashing algorithm, including + * hash = futex_offset & ((1 << num_nodes_lg2) - 1) + * + * 3. The transmitter should atomically compare and swap futex_offset with 0 + * at hash. There are 3 possible outcomes + * a. The swap fails because the futex_offset is already in the table. + * The transmitter should stop. + * b. Some other offset is in the table. This is a hash collision. The + * transmitter should move to another table slot and try again. One + * possible algorithm: + * hash = (hash + 1) & ((1 << num_nodes_lg2) - 1) + * c. The swap worked. Continue below. + * + * 3. The transmitter atomically swaps 1 with the value at the + * interrupt_signalled_offset. There are two outcomes: + * a. The prior value was 1. In this case an interrupt has already been + * posted. The transmitter is done. + * b. The prior value was 0, indicating that the receiver may be sleeping. + * The transmitter will issue an interrupt. + * + * 4. On waking the receiver immediately exchanges a 0 with the + * interrupt_signalled_offset. If it receives a 0 then this a spurious + * interrupt. That may occasionally happen in the current protocol, but + * should be rare. + * + * 5. The receiver scans the signal table by atomicaly exchanging 0 at each + * location. If a non-zero offset is returned from the exchange the + * receiver wakes all sleepers at the given offset: + * futex((int*)(region_base + old_value), FUTEX_WAKE, MAX_INT); + * + * 6. The receiver thread then does a conditional wait, waking immediately + * if the value at interrupt_signalled_offset is non-zero. This catches cases + * here additional signals were posted while the table was being scanned. + * On the guest the wait is handled via the VSOC_WAIT_FOR_INCOMING_INTERRUPT + * ioctl. + */ +struct vsoc_signal_table_layout { + /* log_2(Number of signal table entries) */ + __u32 num_nodes_lg2; + /* + * Offset to the first signal table entry relative to the start of the + * region + */ + __u32 futex_uaddr_table_offset; + /* + * Offset to an atomic_t / atomic uint32_t. A non-zero value indicates + * that one or more offsets are currently posted in the table. + * semi-unique access to an entry in the table + */ + __u32 interrupt_signalled_offset; +}; + +#define VSOC_REGION_WHOLE ((__s32)0) +#define VSOC_DEVICE_NAME_SZ 16 + +/** + * Each HAL would (usually) talk to a single device region + * Mulitple entities care about these regions: + * - The ivshmem_server will populate the regions in shared memory + * - The guest kernel will read the region, create minor device nodes, and + * allow interested parties to register for FUTEX_WAKE events in the region + * - HALs will access via the minor device nodes published by the guest kernel + * - Host side processes will access the region via the ivshmem_server: + * 1. Pass name to ivshmem_server at a UNIX socket + * 2. ivshmemserver will reply with 2 fds: + * - host->guest doorbell fd + * - guest->host doorbell fd + * - fd for the shared memory region + * - region offset + * 3. Start a futex receiver thread on the doorbell fd pointed at the + * signal_nodes + */ +struct vsoc_device_region { + __u16 current_version; + __u16 min_compatible_version; + __u32 region_begin_offset; + __u32 region_end_offset; + __u32 offset_of_region_data; + struct vsoc_signal_table_layout guest_to_host_signal_table; + struct vsoc_signal_table_layout host_to_guest_signal_table; + /* Name of the device. Must always be terminated with a '\0', so + * the longest supported device name is 15 characters. + */ + char device_name[VSOC_DEVICE_NAME_SZ]; + /* There are two ways that permissions to access regions are handled: + * - When subdivided_by is VSOC_REGION_WHOLE, any process that can + * open the device node for the region gains complete access to it. + * - When subdivided is set processes that open the region cannot + * access it. Access to a sub-region must be established by invoking + * the VSOC_CREATE_FD_SCOPE_PERMISSION ioctl on the region + * referenced in subdivided_by, providing a fileinstance + * (represented by a fd) opened on this region. + */ + __u32 managed_by; +}; + +/* + * The vsoc layout descriptor. + * The first 4K should be reserved for the shm header and region descriptors. + * The regions should be page aligned. + */ + +struct vsoc_shm_layout_descriptor { + __u16 major_version; + __u16 minor_version; + + /* size of the shm. This may be redundant but nice to have */ + __u32 size; + + /* number of shared memory regions */ + __u32 region_count; + + /* The offset to the start of region descriptors */ + __u32 vsoc_region_desc_offset; +}; + +/* + * This specifies the current version that should be stored in + * vsoc_shm_layout_descriptor.major_version and + * vsoc_shm_layout_descriptor.minor_version. + * It should be updated only if the vsoc_device_region and + * vsoc_shm_layout_descriptor structures have changed. + * Versioning within each region is transferred + * via the min_compatible_version and current_version fields in + * vsoc_device_region. The driver does not consult these fields: they are left + * for the HALs and host processes and will change independently of the layout + * version. + */ +#define CURRENT_VSOC_LAYOUT_MAJOR_VERSION 2 +#define CURRENT_VSOC_LAYOUT_MINOR_VERSION 0 + +#define VSOC_CREATE_FD_SCOPED_PERMISSION \ + _IOW(0xF5, 0, struct fd_scoped_permission) +#define VSOC_GET_FD_SCOPED_PERMISSION _IOR(0xF5, 1, struct fd_scoped_permission) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt if one is not already + * in flight. + */ +#define VSOC_MAYBE_SEND_INTERRUPT_TO_HOST _IO(0xF5, 2) + +/* + * When this returns the guest will scan host_to_guest_signal_table to + * check for new futexes to wake. + */ +/* TODO(ghartman): Consider moving this to the bottom half */ +#define VSOC_WAIT_FOR_INCOMING_INTERRUPT _IO(0xF5, 3) + +/* + * Guest HALs will use this to retrieve the region description after + * opening their device node. + */ +#define VSOC_DESCRIBE_REGION _IOR(0xF5, 4, struct vsoc_device_region) + +/* + * Wake any threads that may be waiting for a host interrupt on this region. + * This is mostly used during shutdown. + */ +#define VSOC_SELF_INTERRUPT _IO(0xF5, 5) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt unconditionally. + */ +#define VSOC_SEND_INTERRUPT_TO_HOST _IO(0xF5, 6) + +enum wait_types { + VSOC_WAIT_UNDEFINED = 0, + VSOC_WAIT_IF_EQUAL = 1, + VSOC_WAIT_IF_EQUAL_TIMEOUT = 2 +}; + +/* + * Wait for a condition to be true + * + * Note, this is sized and aligned so the 32 bit and 64 bit layouts are + * identical. + */ +struct vsoc_cond_wait { + /* Input: Offset of the 32 bit word to check */ + __u32 offset; + /* Input: Value that will be compared with the offset */ + __u32 value; + /* Monotonic time to wake at in seconds */ + __u64 wake_time_sec; + /* Input: Monotonic time to wait in nanoseconds */ + __u32 wake_time_nsec; + /* Input: Type of wait */ + __u32 wait_type; + /* Output: Number of times the thread woke before returning. */ + __u32 wakes; + /* Ensure that we're 8-byte aligned and 8 byte length for 32/64 bit + * compatibility. + */ + __u32 reserved_1; +}; + +#define VSOC_COND_WAIT _IOWR(0xF5, 7, struct vsoc_cond_wait) + +/* Wake any local threads waiting at the offset given in arg */ +#define VSOC_COND_WAKE _IO(0xF5, 8) + +#endif /* _UAPI_LINUX_VSOC_SHM_H */ diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index ecd24c719de4..badda4286f9b 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM #define TRACE_SYSTEM btrfs @@ -30,6 +33,9 @@ struct btrfs_qgroup; struct extent_io_tree; struct prelim_ref; struct btrfs_space_info; +#ifdef MY_ABC_HERE +struct btrfs_key; +#endif /* MY_ABC_HERE */ #define show_ref_type(type) \ __print_symbolic(type, \ @@ -2148,6 +2154,83 @@ DEFINE_EVENT(btrfs__space_info_update, update_bytes_pinned, TP_ARGS(fs_info, sinfo, old, diff) ); +#ifdef MY_ABC_HERE +DECLARE_EVENT_CLASS(btrfs__syno_meta_statistics, + + TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_root *root, const struct btrfs_key *key), + + TP_ARGS(fs_info, root, key), + + TP_STRUCT__entry_btrfs( + __field(u64, root_objectid) + __field(u64, objectid) + __field(u8, type) + __field(u64, offset) + ), + + TP_fast_assign_btrfs(fs_info, + __entry->root_objectid = root->root_key.objectid; + __entry->objectid = key->objectid; + __entry->type = key->type; + __entry->offset = key->offset; + ), + + TP_printk_btrfs("root=%llu(%s), key[%llu %u %llu]", + show_root_type(__entry->root_objectid), + __entry->objectid, __entry->type, __entry->offset) +); + +DEFINE_EVENT(btrfs__syno_meta_statistics, btrfs_syno_meta_statistics_search_key, + + TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_root *root, const struct btrfs_key *key), + + TP_ARGS(fs_info, root, key) +); + +DEFINE_EVENT(btrfs__syno_meta_statistics, btrfs_syno_meta_statistics_search_forward, + + TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_root *root, const struct btrfs_key *key), + + TP_ARGS(fs_info, root, key) +); + +DEFINE_EVENT(btrfs__syno_meta_statistics, btrfs_syno_meta_statistics_next_leaf, + + TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_root *root, const struct btrfs_key *key), + + TP_ARGS(fs_info, root, key) +); + +TRACE_EVENT(btrfs_syno_meta_statistics_eb_disk_read, + + TP_PROTO(struct btrfs_fs_info *fs_info, u64 bytenr, + u64 owner, u64 level, const struct btrfs_key *key), + + TP_ARGS(fs_info, bytenr, owner, level, key), + + TP_STRUCT__entry_btrfs( + __field(u64, bytenr) + __field(u64, owner) + __field(u64, objectid) + __field(u8, type) + __field(u64, offset) + ), + + TP_fast_assign_btrfs(fs_info, + __entry->bytenr = bytenr; + __entry->owner = owner; + __entry->objectid = key->objectid; + __entry->type = key->type; + __entry->offset = key->offset; + ), + + TP_printk_btrfs("bytenr:%llu root=%llu(%s), first key[%llu %u %llu]", + __entry->bytenr, + show_root_type(__entry->owner), + __entry->objectid, __entry->type, __entry->offset) +); +#endif /* MY_ABC_HERE */ + #endif /* _TRACE_BTRFS_H */ /* This part must be outside protection */ diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 70ae5497b73a..62041cff180c 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM #define TRACE_SYSTEM ext4 @@ -661,6 +664,32 @@ TRACE_EVENT(ext4_discard_blocks, __entry->blk, __entry->count) ); +#ifdef MY_ABC_HERE +TRACE_EVENT(ext4_unused_hint_blocks, + TP_PROTO(struct super_block *sb, unsigned long long blk, + unsigned long long count), + + TP_ARGS(sb, blk, count), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( __u64, blk ) + __field( __u64, count ) + + ), + + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->blk = blk; + __entry->count = count; + ), + + TP_printk("dev %d,%d blk %llu count %llu", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->blk, __entry->count) +); +#endif /* MY_ABC_HERE */ + DECLARE_EVENT_CLASS(ext4__mb_new_pa, TP_PROTO(struct ext4_allocation_context *ac, struct ext4_prealloc_space *pa), diff --git a/include/trace/events/mmc.h b/include/trace/events/mmc.h index 7b706ff21335..0b03c1f17fb4 100644 --- a/include/trace/events/mmc.h +++ b/include/trace/events/mmc.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ #undef TRACE_SYSTEM #define TRACE_SYSTEM mmc @@ -187,6 +190,62 @@ TRACE_EVENT(mmc_request_done, __entry->hold_retune, __entry->retune_period) ); +#if defined(MY_DEF_HERE) +/* + * Tracepoint for rtk emmc issue legacy command. + */ +TRACE_EVENT(mmc_rtkemmc_legacy_cmd, + + TP_PROTO(u16 blksize, u16 blkcount, unsigned int cmd_idx, unsigned int argu), + + TP_ARGS(blksize, blkcount, cmd_idx, argu), + + TP_STRUCT__entry( + __field( u16, blksize ) + __field( u16, blkcount ) + __field( unsigned int, cmd_idx ) + __field( unsigned int, argu ) + ), + + TP_fast_assign( + __entry->blksize = blksize; + __entry->blkcount = blkcount; + __entry->cmd_idx = cmd_idx; + __entry->argu = argu; + ), + + TP_printk("blksize=%u blkcount=%u cmd_idx=%u argu=%x", + __entry->blksize, + __entry->blkcount, + __entry->cmd_idx, + __entry->argu) +); + +/* + * Tracepoint for rtk emmc legacy interrupt complete. + */ +TRACE_EVENT(mmc_rtkemmc_legacy_irq_complete, + + TP_PROTO(u16 normal_interrupt, u16 error_interrupt), + + TP_ARGS(normal_interrupt, error_interrupt), + + TP_STRUCT__entry( + __field( u16, normal_interrupt ) + __field( u16, error_interrupt ) + ), + + TP_fast_assign( + __entry->normal_interrupt = normal_interrupt; + __entry->error_interrupt = error_interrupt; + ), + + TP_printk("normal_interrupt=%x error_interrupt=%x", + __entry->normal_interrupt, + __entry->error_interrupt) +); + +#endif /* MY_DEF_HERE */ #endif /* _TRACE_MMC_H */ /* This part must be outside protection */ diff --git a/include/trace/events/rtk_pm.h b/include/trace/events/rtk_pm.h new file mode 100644 index 000000000000..7d72111e8ed1 --- /dev/null +++ b/include/trace/events/rtk_pm.h @@ -0,0 +1,76 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rtk_pm + +#if !defined(_TRACE_REALTEK_PM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_REALTEK_PM_H + +#include + +TRACE_EVENT(rtk_pm_event, + + TP_PROTO(const char *id, const char *event), + + TP_ARGS(id, event), + + TP_STRUCT__entry( + __string(id, id) + __string(event, event) + ), + + TP_fast_assign( + __assign_str(id, id); + __assign_str(event, event); + ), + + TP_printk("id=%s event=%s", __get_str(id), __get_str(event)) +); + +TRACE_EVENT(rtk_pm_reg_set, + + TP_PROTO(const char *type, int offset, int val), + + TP_ARGS(type, offset, val), + + TP_STRUCT__entry( + __string(type, type) + __field(int, offset) + __field(int, val) + ), + + TP_fast_assign( + __assign_str(type, type); + __entry->offset = offset; + __entry->val = val; + ), + + TP_printk("type=%s offset=%03x val=%08x", + __get_str(type), __entry->offset, __entry->val) +); + +TRACE_EVENT(rtk_pm_reg_update_bits, + + TP_PROTO(const char *type, int offset, int mask, int val), + + TP_ARGS(type, offset, mask, val), + + TP_STRUCT__entry( + __string(type, type) + __field(int, offset) + __field(int, mask) + __field(int, val) + ), + + TP_fast_assign( + __assign_str(type, type); + __entry->offset = offset; + __entry->mask = mask; + __entry->val = val; + ), + + TP_printk("type=%s offset=%03x mask=%08x val=%08x", + __get_str(type), __entry->offset, __entry->mask, __entry->val) +); +#endif /* _TRACE_REALTEK_PM_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/events/rtk_rpc.h b/include/trace/events/rtk_rpc.h new file mode 100644 index 000000000000..0cfcc457d51a --- /dev/null +++ b/include/trace/events/rtk_rpc.h @@ -0,0 +1,70 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rtk_rpc + +#if !defined(_TRACE_RTK_RPC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_RTK_RPC_H + +#include +#include +DECLARE_EVENT_CLASS(rtk_rpc_struct_class, + + TP_PROTO(struct rpc_struct_tp *rpc_arg, u32 refclk, + loff_t num, u32 taskid), + + TP_ARGS(rpc_arg, refclk, num, taskid), + + TP_STRUCT__entry( + __field(u32, programID) + __field(u32, versionID) + __field(u32, procedureID) + __field(u32, taskID) + __field(u32, parameterSize) + __field(u32, mycontext) + __field(u32, refclk) + __field(loff_t, num) + ), + + TP_fast_assign( + __entry->programID = rpc_arg->programID; + __entry->versionID = rpc_arg->versionID; + __entry->procedureID = rpc_arg->procedureID; + __entry->taskID = taskid; + __entry->parameterSize = rpc_arg->parameterSize; + __entry->mycontext = rpc_arg->mycontext; + __entry->refclk = refclk; + __entry->num = num; + ), + + TP_printk("program=%u version=%u procedure=%u task=%u size=%u context=0x%x 90k=%u rpc_num=%lld", + __entry->programID, __entry->versionID, + __entry->procedureID, __entry->taskID, + __entry->parameterSize, __entry->mycontext, + __entry->refclk, __entry->num) +); + +/** + * rtk_rpc_peek_rpc_request - called immediately after peeking rpc struct + */ +DEFINE_EVENT(rtk_rpc_struct_class, rtk_rpc_peek_rpc_request, + + TP_PROTO(struct rpc_struct_tp *rpc_arg, u32 refclk, + loff_t num, u32 taskid), + + TP_ARGS(rpc_arg, refclk, num, taskid) +); + +/** + * rtk_rpc_peek_rpc_reply - called immediately after peeking rpc struct + */ +DEFINE_EVENT(rtk_rpc_struct_class, rtk_rpc_peek_rpc_reply, + + TP_PROTO(struct rpc_struct_tp *rpc_arg, u32 refclk, + loff_t num, u32 taskid), + + TP_ARGS(rpc_arg, refclk, num, taskid) +); +#endif /* _TRACE_RTK_RPC_H */ + +/* This part must be outside protection */ +#include + diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 23db248a7fdb..9fe6cdcf2222 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -1006,7 +1006,6 @@ DEFINE_RPC_XPRT_LIFETIME_EVENT(connect); DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_auto); DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_done); DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_force); -DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_cleanup); DEFINE_RPC_XPRT_LIFETIME_EVENT(destroy); DECLARE_EVENT_CLASS(rpc_xprt_event, diff --git a/include/trace/events/syno.h b/include/trace/events/syno.h new file mode 100644 index 000000000000..85fb6ef48ded --- /dev/null +++ b/include/trace/events/syno.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM syno + +#if !defined(_TRACE_SYNO_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SYNO_H + +#include + +#define show_permission_flags(flags) __print_flags(flags, "|", \ + { MAY_EXEC, "MAY_EXEC" }, \ + { MAY_WRITE, "MAY_WRITE" }, \ + { MAY_READ, "MAY_READ" }, \ + { MAY_APPEND, "MAY_APPEND" }, \ + { MAY_ACCESS, "MAY_ACCESS" }, \ + { MAY_OPEN, "MAY_OPEN" }, \ + { MAY_READ_EXT_ATTR, "MAY_READ_EXT_ATTR" }, \ + { MAY_READ_PERMISSION, "MAY_READ_PERMISSION" }, \ + { MAY_READ_ATTR, "MAY_READ_ATTR" }, \ + { MAY_WRITE_ATTR, "MAY_WRITE_ATTR" }, \ + { MAY_WRITE_EXT_ATTR, "MAY_WRITE_EXT_ATTR" }, \ + { MAY_WRITE_PERMISSION, "MAY_WRITE_PERMISSION" }, \ + { MAY_DEL, "MAY_DEL" }, \ + { MAY_DEL_CHILD, "MAY_DEL_CHILD" }, \ + { MAY_GET_OWNER_SHIP, "MAY_GET_OWNER_SHIP" }, \ + { MAY_CHDIR, "MAY_CHDIR" }, \ + { MAY_NOT_BLOCK, "MAY_NOT_BLOCK" }) + +TRACE_EVENT(synoacl_permission, + TP_PROTO(struct dentry *dentry, int perm, int error), + + TP_ARGS(dentry, perm, error), + + TP_STRUCT__entry( + __string(name, dentry->d_name.name) + __field(uid_t, cur_fsuid) + __field(int, perm) + __field(int, error) + ), + + TP_fast_assign( + __assign_str(name, dentry->d_name.name); + __entry->cur_fsuid = from_kuid(&init_user_ns, current_fsuid()); + __entry->perm = perm; + __entry->error = error; + ), + + TP_printk("file:%s, fsuid:%u, perm:%s, error:%d", + __get_str(name), + __entry->cur_fsuid, + show_permission_flags(__entry->perm), + __entry->error + ) +); + +TRACE_EVENT(synoacl_exec_permission, + TP_PROTO(struct dentry *dentry, int error), + + TP_ARGS(dentry, error), + + TP_STRUCT__entry( + __string(name, dentry->d_name.name) + __field(uid_t, cur_fsuid) + __field(int, error) + ), + + TP_fast_assign( + __assign_str(name, dentry->d_name.name); + __entry->cur_fsuid = from_kuid(&init_user_ns, current_fsuid()); + __entry->error = error; + ), + + TP_printk("file:%s, fsuid:%u, perm:exec, error:%d", + __get_str(name), + __entry->cur_fsuid, + __entry->error + ) +); + +TRACE_EVENT(synoacl_may_delete, + TP_PROTO(struct dentry *dentry, struct inode *parent, int error), + + TP_ARGS(dentry, parent, error), + + TP_STRUCT__entry( + __string(name, dentry->d_name.name) + __field(uid_t, cur_fsuid) + __field(ino_t, parent_ino) + __field(int, error) + ), + + TP_fast_assign( + __assign_str(name, dentry->d_name.name); + __entry->cur_fsuid = from_kuid(&init_user_ns, current_fsuid()); + __entry->parent_ino = parent->i_ino; + __entry->error = error; + ), + + TP_printk("file:%s, fsuid:%u, parent_ino:%lu, error:%d", + __get_str(name), + __entry->cur_fsuid, + __entry->parent_ino, + __entry->error + ) +); + +TRACE_EVENT(synoacl_may_access, + TP_PROTO(struct dentry *dentry, int mode, int error), + + TP_ARGS(dentry, mode, error), + + TP_STRUCT__entry( + __string(name, dentry->d_name.name) + __field(uid_t, cur_fsuid) + __field(int, mode) + __field(int, error) + ), + + TP_fast_assign( + __assign_str(name, dentry->d_name.name); + __entry->cur_fsuid = from_kuid(&init_user_ns, current_fsuid()); + __entry->mode = mode; + __entry->error = error; + ), + + TP_printk("file:%s, fsuid:%u, mode:%d, error:%d", + __get_str(name), + __entry->cur_fsuid, + __entry->mode, + __entry->error + ) +); +#endif /* _TRACE_SYNO_H */ + +/* This part must be outside protection */ +#include diff --git a/include/uapi/asm-generic/poll.h b/include/uapi/asm-generic/poll.h index 41b509f410bf..f9c520ce4bf4 100644 --- a/include/uapi/asm-generic/poll.h +++ b/include/uapi/asm-generic/poll.h @@ -29,7 +29,7 @@ #define POLLRDHUP 0x2000 #endif -#define POLLFREE (__force __poll_t)0x4000 /* currently only for epoll */ +#define POLLFREE (__force __poll_t)0x4000 #define POLL_BUSY_LOOP (__force __poll_t)0x8000 diff --git a/include/uapi/asm-generic/stat.h b/include/uapi/asm-generic/stat.h index 0d962ecd1663..721ddb183e3a 100644 --- a/include/uapi/asm-generic/stat.h +++ b/include/uapi/asm-generic/stat.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __ASM_GENERIC_STAT_H #define __ASM_GENERIC_STAT_H @@ -44,6 +47,30 @@ struct stat { unsigned int __unused5; }; +#ifdef MY_ABC_HERE +#ifdef __KERNEL__ +#include +#endif + +struct SYNOSTAT_EXTRA { +#ifdef __KERNEL__ + struct __kernel_old_timespec create_time; +#else + struct timespec create_time; +#endif + unsigned int archive_version; + unsigned int archive_bit; + unsigned int compressed; + unsigned int flags; + unsigned int reserved[7]; +}; + +struct SYNOSTAT { + struct stat st; + struct SYNOSTAT_EXTRA ext; +}; +#endif /* MY_ABC_HERE */ + /* This matches struct stat64 in glibc2.1. Only used for 32 bit. */ #if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64) struct stat64 { diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 2056318988f7..7f8a10bcf425 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #include @@ -863,6 +866,94 @@ __SYSCALL(__NR_process_madvise, sys_process_madvise) #undef __NR_syscalls #define __NR_syscalls 441 +/* + * start - MY_ABC_HERE + * Synology defined system calls are listed here. + */ +#define __NR_syno_utime 802 +#define syno_utime(arg1, arg2) syscall(__NR_syno_utime, arg1, arg2) +__SYSCALL(__NR_syno_utime, sys_syno_utime) + +#define __NR_syno_archive_bit 803 +#define syno_archive_bit(arg1, arg2) syscall(__NR_syno_archive_bit, arg1, arg2) +__SYSCALL(__NR_syno_archive_bit, sys_syno_archive_bit) + +#define __NR_syno_recv_file 804 +#define syno_recv_file(arg1, arg2, arg3, arg4, arg5) syscall(__NR_syno_recv_file, arg1, arg2, arg3, arg4, arg5) +__SYSCALL(__NR_syno_recv_file, sys_syno_recv_file) + +#ifdef MY_DEF_HERE +#define __NR_syno_mtd_alloc 805 +#define syno_mtd_alloc(arg1) syscall(__NR_syno_mtd_alloc, arg1) +__SYSCALL(__NR_syno_mtd_alloc, sys_syno_mtd_alloc) +#endif /* MY_DEF_HERE */ + +#define __NR_syno_caseless_stat 806 +#define syno_caseless_stat(arg1, arg2) syscall(__NR_syno_caseless_stat, arg1, arg2) +__SYSCALL(__NR_syno_caseless_stat, sys_syno_caseless_stat) + +#define __NR_syno_caseless_lstat 807 +#define syno_caseless_lstat(arg1, arg2) syscall(__NR_syno_caseless_lstat, arg1, arg2) +__SYSCALL(__NR_syno_caseless_lstat, sys_syno_caseless_lstat) + +#define __NR_syno_ecrypt_name 810 +#define syno_ecrypt_name(arg1, arg2) syscall(__NR_syno_ecrypt_name, arg1, arg2) +__SYSCALL(__NR_syno_ecrypt_name, sys_syno_ecrypt_name) + +#define __NR_syno_decrypt_name 811 +#define syno_decrypt_name(arg1, arg2, arg3) syscall(__NR_syno_decrypt_name, arg1, arg2, arg3) +__SYSCALL(__NR_syno_decrypt_name, sys_syno_decrypt_name) + +#define __NR_syno_acl_check_perm 812 +#define syno_acl_check_perm(arg1, arg2) syscall(__NR_syno_acl_check_perm, arg1, arg2) +__SYSCALL(__NR_syno_acl_check_perm, sys_syno_acl_check_perm) + +#define __NR_syno_acl_is_support 813 +#define syno_acl_is_support(arg1, arg2, arg3) syscall(__NR_syno_acl_is_support, arg1, arg2, arg3) +__SYSCALL(__NR_syno_acl_is_support, sys_syno_acl_is_support) + +#define __NR_syno_acl_get_perm 814 +#define syno_acl_get_perm(arg1, arg2) syscall(__NR_syno_acl_get_perm, arg1, arg2) +__SYSCALL(__NR_syno_acl_get_perm, sys_syno_acl_get_perm) + +#define __NR_syno_flush_aggregate 815 +#define syno_flush_aggregate(arg1) syscall(__NR_syno_flush_aggregate, arg1) +__SYSCALL(__NR_syno_flush_aggregate, sys_syno_flush_aggregate) + +#define __NR_syno_stat 819 +#define syno_stat(arg1, arg2, arg3) syscall(__NR_syno_stat, arg1, arg2, arg3) +__SYSCALL(__NR_syno_stat, sys_syno_stat) + +#define __NR_syno_fstat 820 +#define syno_fstat(arg1, arg2, arg3) syscall(__NR_syno_fstat, arg1, arg2, arg3) +__SYSCALL(__NR_syno_fstat, sys_syno_fstat) + +#define __NR_syno_lstat 821 +#define syno_lstat(arg1, arg2, arg3) syscall(__NR_syno_lstat, arg1, arg2, arg3) +__SYSCALL(__NR_syno_lstat, sys_syno_lstat) + +#define __NR_syno_notify_init 822 +#define syno_notify_init(arg1) syscall(__NR_syno_notify_init, arg1) +__SYSCALL(__NR_syno_notify_init, sys_syno_notify_init) + +#define __NR_syno_notify_add_watch 823 +#define syno_notify_add_watch(arg1, arg2, arg3) syscall(__NR_syno_notify_add_watch, arg1, arg2, arg3) +__SYSCALL(__NR_syno_notify_add_watch, sys_syno_notify_add_watch) + +#define __NR_syno_notify_remove_watch 824 +#define syno_notify_remove_watch(arg1, arg2, arg3) syscall(__NR_syno_notify_remove_watch, arg1, arg2, arg3) +__SYSCALL(__NR_syno_notify_remove_watch, sys_syno_notify_remove_watch) + +#define __NR_syno_archive_overwrite 827 +#define syno_archive_overwrite(arg1, arg2) syscall(__NR_syno_archive_overwrite, arg1, arg2) +__SYSCALL(__NR_syno_archive_overwrite, sys_syno_archive_overwrite) + +#undef __NR_syscalls +#define __NR_syscalls 828 +/* + * end - MY_ABC_HERE + */ + /* * 32 bit systems traditionally used different * syscalls for off_t and loff_t arguments, while diff --git a/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h new file mode 100644 index 000000000000..130636b811a6 --- /dev/null +++ b/include/uapi/linux/aufs_type.h @@ -0,0 +1,452 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2005-2019 Junjiro R. Okajima + * + * This program, aufs 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __AUFS_TYPE_H__ +#define __AUFS_TYPE_H__ + +#define AUFS_NAME "aufs" + +#ifdef __KERNEL__ +/* + * define it before including all other headers. + * sched.h may use pr_* macros before defining "current", so define the + * no-current version first, and re-define later. + */ +#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ +#include +#undef pr_fmt +#define pr_fmt(fmt) \ + AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ + (int)sizeof(current->comm), current->comm, current->pid +#include +#else +#include +#include +#include +#endif /* __KERNEL__ */ + +#define AUFS_VERSION "5.10" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') + +/* ---------------------------------------------------------------------- */ + +#ifdef __KERNEL__ +#ifdef CONFIG_AUFS_BRANCH_MAX_127 +typedef int8_t aufs_bindex_t; +#define AUFS_BRANCH_MAX 127 +#else +typedef int16_t aufs_bindex_t; +#ifdef CONFIG_AUFS_BRANCH_MAX_511 +#define AUFS_BRANCH_MAX 511 +#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) +#define AUFS_BRANCH_MAX 1023 +#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) +#define AUFS_BRANCH_MAX 32767 +#endif +#endif + +#ifndef AUFS_BRANCH_MAX +#error unknown CONFIG_AUFS_BRANCH_MAX value +#endif +#endif /* __KERNEL__ */ + +/* ---------------------------------------------------------------------- */ + +#define AUFS_FSTYPE AUFS_NAME + +#define AUFS_ROOT_INO 2 +#define AUFS_FIRST_INO 11 + +#define AUFS_WH_PFX ".wh." +#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) +#define AUFS_WH_TMP_LEN 4 +/* a limit for rmdir/rename a dir and copyup */ +#define AUFS_MAX_NAMELEN (NAME_MAX \ + - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ + - 1 /* dot */\ + - AUFS_WH_TMP_LEN) /* hex */ +#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" +#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME +#define AUFS_XINO_DEF_SEC 30 /* seconds */ +#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ +#define AUFS_DIRWH_DEF 3 +#define AUFS_RDCACHE_DEF 10 /* seconds */ +#define AUFS_RDCACHE_MAX 3600 /* seconds */ +#define AUFS_RDBLK_DEF 512 /* bytes */ +#define AUFS_RDHASH_DEF 32 +#define AUFS_WKQ_NAME AUFS_NAME "d" +#define AUFS_MFS_DEF_SEC 30 /* seconds */ +#define AUFS_MFS_MAX_SEC 3600 /* seconds */ +#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ +#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ + +/* pseudo-link maintenace under /proc */ +#define AUFS_PLINK_MAINT_NAME "plink_maint" +#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME +#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME + +/* dirren, renamed dir */ +#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." +#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" +/* whiteouted doubly */ +#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX +#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_NAME + +#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ +#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME + +#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME +#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" +#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" + +/* doubly whiteouted */ +#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME +#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME +#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME + +/* branch permissions and attributes */ +#define AUFS_BRPERM_RW "rw" +#define AUFS_BRPERM_RO "ro" +#define AUFS_BRPERM_RR "rr" +#define AUFS_BRATTR_COO_REG "coo_reg" +#define AUFS_BRATTR_COO_ALL "coo_all" +#define AUFS_BRATTR_FHSM "fhsm" +#define AUFS_BRATTR_UNPIN "unpin" +#define AUFS_BRATTR_ICEX "icex" +#define AUFS_BRATTR_ICEX_SEC "icexsec" +#define AUFS_BRATTR_ICEX_SYS "icexsys" +#define AUFS_BRATTR_ICEX_TR "icextr" +#define AUFS_BRATTR_ICEX_USR "icexusr" +#define AUFS_BRATTR_ICEX_OTH "icexoth" +#define AUFS_BRRATTR_WH "wh" +#define AUFS_BRWATTR_NLWH "nolwh" +#define AUFS_BRWATTR_MOO "moo" + +#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ +#define AuBrPerm_RO (1 << 1) /* readonly */ +#define AuBrPerm_RR (1 << 2) /* natively readonly */ +#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) + +#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ +#define AuBrAttr_COO_ALL (1 << 4) +#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) + +#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ +#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of + branch. meaningless since + linux-3.18-rc1 */ + +/* ignore error in copying XATTR */ +#define AuBrAttr_ICEX_SEC (1 << 7) +#define AuBrAttr_ICEX_SYS (1 << 8) +#define AuBrAttr_ICEX_TR (1 << 9) +#define AuBrAttr_ICEX_USR (1 << 10) +#define AuBrAttr_ICEX_OTH (1 << 11) +#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ + | AuBrAttr_ICEX_SYS \ + | AuBrAttr_ICEX_TR \ + | AuBrAttr_ICEX_USR \ + | AuBrAttr_ICEX_OTH) + +#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ +#define AuBrRAttr_Mask AuBrRAttr_WH + +#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ +#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ +#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) + +#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) + +/* #warning test userspace */ +#ifdef __KERNEL__ +#ifndef CONFIG_AUFS_FHSM +#undef AuBrAttr_FHSM +#define AuBrAttr_FHSM 0 +#endif +#ifndef CONFIG_AUFS_XATTR +#undef AuBrAttr_ICEX +#define AuBrAttr_ICEX 0 +#undef AuBrAttr_ICEX_SEC +#define AuBrAttr_ICEX_SEC 0 +#undef AuBrAttr_ICEX_SYS +#define AuBrAttr_ICEX_SYS 0 +#undef AuBrAttr_ICEX_TR +#define AuBrAttr_ICEX_TR 0 +#undef AuBrAttr_ICEX_USR +#define AuBrAttr_ICEX_USR 0 +#undef AuBrAttr_ICEX_OTH +#define AuBrAttr_ICEX_OTH 0 +#endif +#endif + +/* the longest combination */ +/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ +#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ + "+" AUFS_BRATTR_COO_REG \ + "+" AUFS_BRATTR_FHSM \ + "+" AUFS_BRATTR_UNPIN \ + "+" AUFS_BRATTR_ICEX_SEC \ + "+" AUFS_BRATTR_ICEX_SYS \ + "+" AUFS_BRATTR_ICEX_USR \ + "+" AUFS_BRATTR_ICEX_OTH \ + "+" AUFS_BRWATTR_NLWH) + +typedef struct { + char a[AuBrPermStrSz]; +} au_br_perm_str_t; + +static inline int au_br_writable(int brperm) +{ + return brperm & AuBrPerm_RW; +} + +static inline int au_br_whable(int brperm) +{ + return brperm & (AuBrPerm_RW | AuBrRAttr_WH); +} + +static inline int au_br_wh_linkable(int brperm) +{ + return !(brperm & AuBrWAttr_NoLinkWH); +} + +static inline int au_br_cmoo(int brperm) +{ + return brperm & AuBrAttr_CMOO_Mask; +} + +static inline int au_br_fhsm(int brperm) +{ + return brperm & AuBrAttr_FHSM; +} + +/* ---------------------------------------------------------------------- */ + +/* ioctl */ +enum { + /* readdir in userspace */ + AuCtl_RDU, + AuCtl_RDU_INO, + + AuCtl_WBR_FD, /* pathconf wrapper */ + AuCtl_IBUSY, /* busy inode */ + AuCtl_MVDOWN, /* move-down */ + AuCtl_BR, /* info about branches */ + AuCtl_FHSM_FD /* connection for fhsm */ +}; + +/* borrowed from linux/include/linux/kernel.h */ +#ifndef ALIGN +#ifdef _GNU_SOURCE +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +#else +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#endif +#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) +#endif + +/* borrowed from linux/include/linux/compiler-gcc3.h */ +#ifndef __aligned +#define __aligned(x) __attribute__((aligned(x))) +#endif + +#ifdef __KERNEL__ +#ifndef __packed +#define __packed __attribute__((packed)) +#endif +#endif + +struct au_rdu_cookie { + uint64_t h_pos; + int16_t bindex; + uint8_t flags; + uint8_t pad; + uint32_t generation; +} __aligned(8); + +struct au_rdu_ent { + uint64_t ino; + int16_t bindex; + uint8_t type; + uint8_t nlen; + uint8_t wh; + char name[]; +} __aligned(8); + +static inline int au_rdu_len(int nlen) +{ + /* include the terminating NULL */ + return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, + sizeof(uint64_t)); +} + +union au_rdu_ent_ul { + struct au_rdu_ent __user *e; + uint64_t ul; +}; + +enum { + AufsCtlRduV_SZ, + AufsCtlRduV_End +}; + +struct aufs_rdu { + /* input */ + union { + uint64_t sz; /* AuCtl_RDU */ + uint64_t nent; /* AuCtl_RDU_INO */ + }; + union au_rdu_ent_ul ent; + uint16_t verify[AufsCtlRduV_End]; + + /* input/output */ + uint32_t blk; + + /* output */ + union au_rdu_ent_ul tail; + /* number of entries which were added in a single call */ + uint64_t rent; + uint8_t full; + uint8_t shwh; + + struct au_rdu_cookie cookie; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +/* dirren. the branch is identified by the filename who contains this */ +struct au_drinfo { + uint64_t ino; + union { + uint8_t oldnamelen; + uint64_t _padding; + }; + uint8_t oldname[]; +} __aligned(8); + +struct au_drinfo_fdata { + uint32_t magic; + struct au_drinfo drinfo; +} __aligned(8); + +#define AUFS_DRINFO_MAGIC_V1 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x01) +/* future */ +#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02) + +/* ---------------------------------------------------------------------- */ + +struct aufs_wbr_fd { + uint32_t oflags; + int16_t brid; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +struct aufs_ibusy { + uint64_t ino, h_ino; + int16_t bindex; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +/* error code for move-down */ +/* the actual message strings are implemented in aufs-util.git */ +enum { + EAU_MVDOWN_OPAQUE = 1, + EAU_MVDOWN_WHITEOUT, + EAU_MVDOWN_UPPER, + EAU_MVDOWN_BOTTOM, + EAU_MVDOWN_NOUPPER, + EAU_MVDOWN_NOLOWERBR, + EAU_Last +}; + +/* flags for move-down */ +#define AUFS_MVDOWN_DMSG 1 +#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ +#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ +#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ +#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ +#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ +#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ +#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ +#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ +#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ +#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ +#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ +#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ + +/* index for move-down */ +enum { + AUFS_MVDOWN_UPPER, + AUFS_MVDOWN_LOWER, + AUFS_MVDOWN_NARRAY +}; + +/* + * additional info of move-down + * number of free blocks and inodes. + * subset of struct kstatfs, but smaller and always 64bit. + */ +struct aufs_stfs { + uint64_t f_blocks; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; +}; + +struct aufs_stbr { + int16_t brid; /* optional input */ + int16_t bindex; /* output */ + struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ +} __aligned(8); + +struct aufs_mvdown { + uint32_t flags; /* input/output */ + struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ + int8_t au_errno; /* output */ +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +union aufs_brinfo { + /* PATH_MAX may differ between kernel-space and user-space */ + char _spacer[4096]; + struct { + int16_t id; + int perm; + char path[]; + }; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ + +#define AuCtlType 'A' +#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) +#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) +#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ + struct aufs_wbr_fd) +#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) +#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ + struct aufs_mvdown) +#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) +#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) + +#endif /* __AUFS_TYPE_H__ */ diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 2c39d15a2beb..530352336978 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Copyright (C) 2007 Oracle. All rights reserved. @@ -46,6 +49,14 @@ struct btrfs_ioctl_vol_args { #define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3) #define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4) +#ifdef MY_ABC_HERE +#define BTRFS_SUBVOL_HIDE (1ULL << 32) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_SUBVOL_NOLOAD_USRQUOTA (1ULL << 33) +#define BTRFS_SUBVOL_CMPR_RATIO (1ULL << 34) +#define BTRFS_SUBVOL_DISABLE_QUOTA (1ULL << 35) +#endif /* MY_ABC_HERE */ #define BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED \ (BTRFS_SUBVOL_RDONLY | \ @@ -68,6 +79,10 @@ struct btrfs_ioctl_vol_args { #define BTRFS_QGROUP_LIMIT_MAX_EXCL (1ULL << 1) #define BTRFS_QGROUP_LIMIT_RSV_RFER (1ULL << 2) #define BTRFS_QGROUP_LIMIT_RSV_EXCL (1ULL << 3) +#ifdef MY_ABC_HERE +#define BTRFS_QGROUP_LIMIT_SOFT_RFER (1ULL << 2) +#define BTRFS_QGROUP_LIMIT_SOFT_EXCL (1ULL << 3) +#endif /* MY_ABC_HERE */ #define BTRFS_QGROUP_LIMIT_RFER_CMPR (1ULL << 4) #define BTRFS_QGROUP_LIMIT_EXCL_CMPR (1ULL << 5) @@ -75,8 +90,19 @@ struct btrfs_qgroup_limit { __u64 flags; __u64 max_rfer; __u64 max_excl; +#ifdef MY_ABC_HERE + union { + __u64 rsv_rfer; + __u64 soft_rfer; + }; + union { + __u64 rsv_excl; + __u64 soft_excl; + }; +#else __u64 rsv_rfer; __u64 rsv_excl; +#endif /* MY_ABC_HERE */ }; /* @@ -134,6 +160,12 @@ struct btrfs_ioctl_vol_args_v2 { __u64 size; struct btrfs_qgroup_inherit __user *qgroup_inherit; }; +#ifdef MY_ABC_HERE + struct { + __u64 padding[3]; + __u64 copy_limit_from; + }; +#endif /* MY_ABC_HERE */ __u64 unused[4]; }; union { @@ -278,6 +310,11 @@ struct btrfs_ioctl_fs_info_args { * struct btrfs_ioctl_feature_flags */ #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +#define BTRFS_FEATURE_COMPAT_BLOCK_GROUP_CACHE_TREE_AUTO (1ULL << 61) +#define BTRFS_FEATURE_COMPAT_BLOCK_GROUP_CACHE_TREE (1ULL << 62) +#define BTRFS_FEATURE_COMPAT_SYNO_CASELESS (1ULL << 63) +#endif /* MY_ABC_HERE || MY_ABC_HERE */ /* * Older kernels (< 4.9) on big-endian systems produced broken free space tree * bitmaps, and btrfs-progs also used to corrupt the free space tree (versions @@ -289,6 +326,10 @@ struct btrfs_ioctl_fs_info_args { */ #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) +#ifdef MY_ABC_HERE +#define BTRFS_FEATURE_COMPAT_RO_LOCKER (1ULL << 59) // the 17th prime number +#endif /* MY_ABC_HERE */ + #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) @@ -308,12 +349,129 @@ struct btrfs_ioctl_fs_info_args { #define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10) #define BTRFS_FEATURE_INCOMPAT_RAID1C34 (1ULL << 11) +#ifdef MY_ABC_HERE +#define BTRFS_FEATURE_SYNO_CAPABILITY_RBD_META (1ULL << 0) +#endif /* MY_ABC_HERE */ + struct btrfs_ioctl_feature_flags { __u64 compat_flags; __u64 compat_ro_flags; __u64 incompat_flags; }; +#ifdef MY_ABC_HERE +#define BTRFS_LOCKER_CLOCK (1ULL << 0) +#define BTRFS_LOCKER_CLOCK_DELTA (1ULL << 1) +#define BTRFS_LOCKER_ENABLED (1ULL << 2) +#define BTRFS_LOCKER_MODE (1ULL << 3) +#define BTRFS_LOCKER_DEFAULT_STATE (1ULL << 4) +#define BTRFS_LOCKER_WAITTIME (1ULL << 5) +#define BTRFS_LOCKER_DURATION (1ULL << 6) +#define BTRFS_LOCKER_CLOCK_ADJUSTMENT (1ULL << 7) +#define BTRFS_LOCKER_UPDATE_TIME_FLOOR (1ULL << 8) +#define BTRFS_LOCKER_LOCKABLE (1ULL << 9) +#define BTRFS_LOCKER_STATE (1ULL << 10) +#define BTRFS_LOCKER_RAW_STATE (1ULL << 11) +#define BTRFS_LOCKER_UPDATE_TIME (1ULL << 12) +#define BTRFS_LOCKER_BEGIN (1ULL << 13) +#define BTRFS_LOCKER_END (1ULL << 14) +#define BTRFS_LOCKER_END_EXT_BEGIN (1ULL << 15) +#define BTRFS_LOCKER_END_EXT_END (1ULL << 16) +#define BTRFS_LOCKER_END_EXT_CURRENT (1ULL << 17) + +#define BTRFS_LOCKER_FS_PROP_MASK (\ + BTRFS_LOCKER_CLOCK |\ + BTRFS_LOCKER_CLOCK_DELTA \ +) + +#define BTRFS_LOCKER_ROOT_PROP_MASK (\ + BTRFS_LOCKER_ENABLED |\ + BTRFS_LOCKER_MODE |\ + BTRFS_LOCKER_DEFAULT_STATE |\ + BTRFS_LOCKER_WAITTIME |\ + BTRFS_LOCKER_DURATION |\ + BTRFS_LOCKER_CLOCK_ADJUSTMENT |\ + BTRFS_LOCKER_UPDATE_TIME_FLOOR \ +) + +#define BTRFS_LOCKER_PERIOD_MASK (\ + BTRFS_LOCKER_BEGIN |\ + BTRFS_LOCKER_END |\ + BTRFS_LOCKER_END_EXT_BEGIN |\ + BTRFS_LOCKER_END_EXT_END |\ + BTRFS_LOCKER_END_EXT_CURRENT \ +) + +#define BTRFS_LOCKER_INODE_PROP_MASK (\ + BTRFS_LOCKER_LOCKABLE |\ + BTRFS_LOCKER_STATE |\ + BTRFS_LOCKER_RAW_STATE |\ + BTRFS_LOCKER_UPDATE_TIME |\ + BTRFS_LOCKER_PERIOD_MASK \ +) + +#define BTRFS_LOCKER_MASK_ALL (\ + BTRFS_LOCKER_FS_PROP_MASK |\ + BTRFS_LOCKER_ROOT_PROP_MASK |\ + BTRFS_LOCKER_INODE_PROP_MASK \ +) + +struct btrfs_ioctl_syno_locker_args { + __u64 flags; + + /* volume properties */ + __s64 clock; // 0: [out] epoch time from 1970/01/01 + __s64 clock_delta; // 1: [out] delta = system_clock - volume_clock + + /* subvolume properties */ + __u16 enabled; // 2: [in/out] + __u16 mode; // 3: [in/out] + __u16 default_state; // 4: [in/out] + __u16 reserved1; + + __s64 waittime; // 5: [in/out] seconds + __s64 duration; // 6: [in/out] seconds + __s64 clock_adjustment; // 7: [in/out] seconds + __s64 update_time_floor; // 8: [out] epoch time in volume clock + + /* inode properties */ + __u16 lockable; // 9: [out] + __u16 state; // 10: [in/out] + __u16 raw_state; // 11: [out] + __u16 reserved2; + + __s64 update_time; // 12: [in/out] epoch time in volume clock + __s64 period_begin; // 13: [in/out] epoch time in volume clock + __s64 period_end; // 14: [in/out] epoch time in volume clock + + __s64 update_time_sys; // 15: [out] epoch time in system clock + __s64 period_begin_sys; // 16: [out] epoch time in system clock + __s64 period_end_sys; // 17: [out] epoch time in system clock + + /* + * The following flags control the behavior of setting period_end in volume clock. + * + * BTRFS_LOCKER_END: + * new period_end = args.period_end as epoch time + * BTRFS_LOCKER_END_EXT_BEGIN: + * new period_end = current period_begin + args.period_end + * BTRFS_LOCKER_END_EXT_END + * new period_end = current period_end + args.period_end + * BTRFS_LOCKER_END_EXT_CURRENT + * new period_end = current volume_clock + args.period_end + */ + + __u64 reserved[5]; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct btrfs_ioctl_syno_flags { + __u64 syno_capability_flags; + __u64 reserved[3]; +}; +#endif /* MY_ABC_HERE */ + /* balance control ioctl modes */ #define BTRFS_BALANCE_CTL_PAUSE 1 #define BTRFS_BALANCE_CTL_CANCEL 2 @@ -391,6 +549,9 @@ struct btrfs_balance_progress { #define BTRFS_BALANCE_FORCE (1ULL << 3) #define BTRFS_BALANCE_RESUME (1ULL << 4) +#ifdef MY_ABC_HERE +#define BTRFS_BALANCE_DRY_RUN (1ULL << 15) +#endif /* SYNO_BTRFS_BALANCE_DRY_RUN */ /* * flags definitions for per-type balance args @@ -450,7 +611,13 @@ struct btrfs_ioctl_balance_args { struct btrfs_balance_progress stat; /* out */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + __u64 unused[70]; /* pad to 1k */ + __u64 key_offset; /* out */ /* for quick balance */ + __u64 total_chunk_used; /* out */ /* for dry run */ +#else __u64 unused[72]; /* pad to 1k */ +#endif /* defined(MY_ABC_HERE) || defined(MY_ABC_HERE) */ }; #define BTRFS_INO_LOOKUP_PATH_MAX 4080 @@ -475,6 +642,12 @@ struct btrfs_ioctl_ino_lookup_user_args { char path[BTRFS_INO_LOOKUP_USER_PATH_MAX]; }; +#ifdef MY_ABC_HERE +#define BTRFS_SEARCH_FLAG_ADJUST_MIN (1 << 0) +#define BTRFS_SEARCH_FLAG_REPORT_BUF_FULL (1 << 1) +#define BTRFS_SEARCH_FLAG_READAHEAD (1 << 2) +#endif /* MY_ABC_HERE */ + /* Search criteria for the btrfs SEARCH ioctl family. */ struct btrfs_ioctl_search_key { /* @@ -528,7 +701,12 @@ struct btrfs_ioctl_search_key { __u32 unused; /* some extra for later */ +#ifdef MY_ABC_HERE + __u32 search_flag; + __u32 unused1; +#else /* MY_ABC_HERE */ __u64 unused1; +#endif /* MY_ABC_HERE */ __u64 unused2; __u64 unused3; __u64 unused4; @@ -567,6 +745,43 @@ struct btrfs_ioctl_clone_range_args { __u64 dest_offset; }; +#ifdef MY_ABC_HERE +/* + * The following bit is used by clone_range_args_v2::flag + * If REWRITE_SRC or REWRITE_DST is specified, clone will rewrite SRC or + * DST automatically rather then return EMLINK immediately when refs of + * EXTENT_ITEM reaches ref_limit. The extent item pointed by destination + * file will thus has low reference count. + */ +#define BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_SRC (1 << 0) +#define BTRFS_CLONE_RANGE_V2_AUTO_REWRITE_DST (1 << 1) + +#ifdef MY_ABC_HERE +#define BTRFS_CLONE_RANGE_V2_SKIP_CHECK_COMPR_DIR (1 << 2) +#endif /* MY_ABC_HERE */ + +struct btrfs_ioctl_syno_clone_range_args_v2 { + __s64 src_fd; + /* + * If the ref_limit is reached, + * src_offset and src_lenght will be set to appropriate file + * offset and lenght to indicate which part of the file reaches + * the extent reflink limit. errno EMLINK is returned. + * When EMLINK, src_offset and src_length will be set to the + * position and lenght of file that could not be cloned, + * and ref_limit is set to the current reflinnk count of + * that extent. + */ + __u64 src_offset; /* in/out */ + __u64 src_length; /* in/out */ + __u64 dest_offset; + __u64 ref_limit; /* in/out */ + __u32 flag; + __u32 reserved32; + __u64 reserved[2]; +}; +#endif /* MY_ABC_HERE */ + /* * flags definition for the defrag range ioctl * @@ -575,6 +790,14 @@ struct btrfs_ioctl_clone_range_args { */ #define BTRFS_DEFRAG_RANGE_COMPRESS 1 #define BTRFS_DEFRAG_RANGE_START_IO 2 +#ifdef MY_ABC_HERE +#define BTRFS_DEFRAG_RANGE_SYNO_DEFRAG (1ULL << 2) +#define BTRFS_DEFRAG_RANGE_PRINT_STDOUT (1ULL << 3) +#define BTRFS_DEFRAG_RANGE_SKIP_FAST_SNAPSHOT_CHECK (1ULL << 4) +#define BTRFS_DEFRAG_RANGE_START_IO_RANGE (1ULL << 5) +#define BTRFS_DEFRAG_RANGE_FORCE_RECLAIM (1ULL << 6) +#define BTRFS_DEFRAG_RANGE_SKIP_CROSS_REF_CHECK (1ULL << 7) +#endif /* MY_ABC_HERE */ struct btrfs_ioctl_defrag_range_args { /* start of the defrag operation */ __u64 start; @@ -602,8 +825,27 @@ struct btrfs_ioctl_defrag_range_args { */ __u32 compress_type; +#ifdef MY_ABC_HERE + __u64 release_size; + /* + * This value is multiple of 4K + */ + __u16 syno_thresh; + /* + * The ratio between number of bytes of file extent data that + * point to processing extent and extent disk byte number. + * If actual ratio is below this condition, defrag would be + * triggered. For example syno_ratio_denom=3 and syno_ratio_nom=2, + * if the (file extent num) <= (extent disk byte num) * 2/3, + * this extent would be defragged. + */ + __u8 syno_ratio_denom; + __u8 syno_ratio_nom; + __u32 unused[1]; +#else /* MY_ABC_HERE */ /* spare for later */ __u32 unused[4]; +#endif /* MY_ABC_HERE */ }; @@ -632,6 +874,53 @@ struct btrfs_ioctl_same_args { struct btrfs_ioctl_same_extent_info info[0]; }; +#ifdef MY_ABC_HERE +enum btrfs_ioctl_syno_dedupe_cmd_action { + DEDUPE_CMD_NONE = 0, + DEDUPE_CMD_SET, + DEDUPE_CMD_CLEAR, + DEDUPE_CMD_SET_NODEDUPE, + DEDUPE_CMD_CLEAR_NODEDUPE, + DEDUPE_CMD_SET_SMALL_EXTENT_SIZE, + DEDUPE_CMD_SET_INLINE_DEDUPE, + DEDUPE_CMD_CLEAR_INLINE_DEDUPE, + DEDUPE_CMD_MAX +}; + +struct btrfs_ioctl_syno_dedupe_cmd_args { + __u64 rootid; /* in */ + __u64 objectid; /* in */ + __u64 offset; /* in */ + __u64 len; /* in */ + __u8 action; /* in, btrfs_ioctl_syno_dedupe_cmd_action */ +}; + +enum btrfs_ioctl_syno_extent_same_status { + SYNO_EXTENT_SAME_SUCCESS = 0, + SYNO_EXTENT_SAME_DITTO, + SYNO_EXTENT_SAME_DIFF, + SYNO_EXTENT_SAME_SRC_NOT_FOUND, + SYNO_EXTENT_SAME_DST_NOT_FOUND, + SYNO_EXTENT_SAME_MAX, +}; + +struct btrfs_ioctl_syno_extent_same_args { + __u64 src_rootid; /* in */ + __u64 src_objectid; /* in */ + __u64 src_offset; /* in */ + __u64 dst_rootid; /* in */ + __u64 dst_objectid; /* in */ + __u64 dst_offset; /* in */ + __u64 length; /* in */ + __u32 min_dedupe_length; /* in */ + __u32 backref_limit; /* in */ + __u64 failed_dst_offset; /* out */ + __u64 failed_dst_length; /* out */ + __u64 release_size; /* out */ + __u8 status; /* out */ +}; +#endif /* MY_ABC_HERE */ + struct btrfs_ioctl_space_info { __u64 flags; __u64 total_bytes; @@ -710,9 +999,22 @@ struct btrfs_ioctl_get_dev_stats { __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; }; +#ifdef MY_ABC_HERE +struct btrfs_ioctl_cksumfailed_files_args { + __u64 sub_vol; + __u64 ino; +}; +#endif /* MY_ABC_HERE */ + #define BTRFS_QUOTA_CTL_ENABLE 1 #define BTRFS_QUOTA_CTL_DISABLE 2 #define BTRFS_QUOTA_CTL_RESCAN__NOTUSED 3 +#ifdef MY_ABC_HERE +#define BTRFS_QUOTA_V1_CTL_ENABLE 10 +#define BTRFS_QUOTA_V2_CTL_ENABLE 11 +#define BTRFS_QUOTA_CTL_UNLOAD 12 +#define BTRFS_QUOTA_CTL_REMOVE_V1 13 +#endif /* MY_ABC_HERE */ struct btrfs_ioctl_quota_ctl_args { __u64 cmd; __u64 status; @@ -724,6 +1026,51 @@ struct btrfs_ioctl_quota_rescan_args { __u64 reserved[6]; }; +#ifdef MY_ABC_HERE +// "in" parameter for btrfs_ioctl_syno_quota_rescan_args flags: +#define BTRFS_SYNO_QUOTA_RESCAN (1ULL << 0) +#define BTRFS_SYNO_QUOTA_RESCAN_PAUSE (1ULL << 1) +#define BTRFS_SYNO_QUOTA_RESCAN_RESUME (1ULL << 2) +#define BTRFS_SYNO_QUOTA_RESCAN_SET_VOL_V2 (1ULL << 3) +#define BTRFS_SYNO_QUOTA_RESCAN_TRANSFER_LIMIT (1ULL << 4) + +struct btrfs_ioctl_syno_quota_rescan_args { + __u64 flags; + __u64 reserved[3]; +}; + +// "in" parameter for struct btrfs_ioctl_syno_quota_status_args cmd: +// Query volume rescan progress. +#define BTRFS_QUOTA_STATUS_RESCAN_VOL_PROGRESS (1ULL << 1) +// Query subvolume rescan progress. +#define BTRFS_QUOTA_STATUS_RESCAN_SUBVOL_PROGRESS (1ULL << 2) + +// "out" parameter of struct btrfs_ioctl_syno_quota_status_args status: +#define BTRFS_QUOTA_STATUS_VOL_DISABLED (1ULL << 0) +#define BTRFS_QUOTA_STATUS_SUBVOL_DISABLED (1ULL << 1) +#define BTRFS_QUOTA_STATUS_VOL_UPSTREAM_ENABLED (1ULL << 2) +#define BTRFS_QUOTA_STATUS_VOL_SYNO_V1_ENABLED (1ULL << 3) +#define BTRFS_QUOTA_STATUS_VOL_SYNO_V2_ENABLED (1ULL << 4) +#define BTRFS_QUOTA_STATUS_SUBVOL_ENABLED (1ULL << 5) +#define BTRFS_QUOTA_STATUS_VOL_RESCAN_DOING (1ULL << 6) +#define BTRFS_QUOTA_STATUS_VOL_RESCAN_PAUSED (1ULL << 7) +#define BTRFS_QUOTA_STATUS_SUBVOL_RESCAN_QUEUED (1ULL << 8) +#define BTRFS_QUOTA_STATUS_SUBVOL_RESCANNING (1ULL << 9) +#define BTRFS_QUOTA_STATUS_INCONSISTENT (1ULL << 10) +#define BTRFS_USRQUOTA_STATUS_INCONSISTENT (1ULL << 11) +#define BTRFS_QUOTA_STATUS_VOL_PROGRESS_VALID (1ULL << 12) +#define BTRFS_QUOTA_STATUS_SUBVOL_PROGRESS_VALID (1ULL << 13) + +struct btrfs_ioctl_syno_quota_status_args { + __u64 cmd; + __u64 status; + __u64 progress; // 0~10000. Caller can devide it by 100 to get percentage. + __u64 next_subvol_id; // If "this" subvol is in recan list, report next subvol in the list. + __u64 scanning_subvol_id; // Currently scanning subvol. May not be the same as "this" subvol. + __u64 reserved[3]; +}; +#endif /* MY_ABC_HERE */ + struct btrfs_ioctl_qgroup_assign_args { __u64 assign; __u64 src; @@ -734,6 +1081,78 @@ struct btrfs_ioctl_qgroup_create_args { __u64 create; __u64 qgroupid; }; + +#ifdef MY_ABC_HERE +struct btrfs_ioctl_qgroup_query_args { + /* state */ + __u64 rfer; // disk size (could be smaller than rfer_cmpr due to compression) + __u64 rfer_cmpr; // original size before compression (bad naming due to compatibility) + __u64 excl; + __u64 excl_cmpr; + + /* limit */ + __u64 max_rfer; + __u64 max_excl; +#ifdef MY_ABC_HERE + union { + __u64 soft_rfer; + __u64 rsv_rfer; + }; + union { + __u64 soft_excl; + __u64 rsv_excl; + }; +#else + __u64 rsv_rfer; + __u64 rsv_excl; +#endif /* MY_ABC_HERE */ + + /* reservation tracking */ + __u64 reserved; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_USRQUOTA_CTL_ENABLE 1 +#define BTRFS_USRQUOTA_CTL_DISABLE 2 +#define BTRFS_USRQUOTA_CTL_DUMPTREE 3 +#ifdef MY_ABC_HERE +#define BTRFS_USRQUOTA_V1_CTL_ENABLE 10 +#define BTRFS_USRQUOTA_V2_CTL_ENABLE 11 +#define BTRFS_USRQUOTA_CTL_UNLOAD 12 +#define BTRFS_USRQUOTA_CTL_REMOVE_V1 13 +#endif /* MY_ABC_HERE */ +struct btrfs_ioctl_usrquota_ctl_args { + __u64 cmd; + __u64 status; +}; + +struct btrfs_ioctl_usrquota_limit_args { + __u64 uid; + __u64 rfer_soft; + __u64 rfer_hard; +}; + +// Deprecated. Please use qgroup's rescan. +struct btrfs_ioctl_usrquota_rescan_args { + __u64 flags; + __u64 rootid; + __u64 objectid; + __u64 reserved[5]; +}; + +struct btrfs_ioctl_usrquota_query_args { + __u64 uid; + /* state */ + __u64 rfer_used; + /* limits */ + __u64 rfer_soft; + __u64 rfer_hard; + /* reservation tracking */ + __u64 reserved; +}; +#endif /* MY_ABC_HERE */ + struct btrfs_ioctl_timespec { __u64 sec; __u32 nsec; @@ -746,9 +1165,206 @@ struct btrfs_ioctl_received_subvol_args { struct btrfs_ioctl_timespec stime; /* in */ struct btrfs_ioctl_timespec rtime; /* out */ __u64 flags; /* in */ +#ifdef MY_ABC_HERE + struct btrfs_ioctl_timespec otime; /* in */ + __u64 reserved[14]; /* in */ +#else /* MY_ABC_HERE */ __u64 reserved[16]; /* in */ +#endif /* MY_ABC_HERE */ }; +#ifdef MY_ABC_HERE + +#define BTRFS_SNAP_SIZE_SHOW_EXCL_SIZE 0x1 +#define BTRFS_SNAP_SIZE_SHOW_PROCESSED_SIZE 0x2 +#define BTRFS_SNAP_SIZE_SHOW_MARGINAL_SIZE 0x4 + +struct btrfs_ioctl_snapshot_size_id_size_map { + __u64 snap_id; + __u64 marginal_size; +}; + +struct btrfs_ioctl_snapshot_size_query_args { + /* number of snap ids pointed by *snap_id */ + __u64 snap_count; + __u64 flags; + /* output exclusive size in progress to fd + + if BTRFS_SNAP_SIZE_QUERY_OUTPUT_READALBE_PRGRESS + BTRFS_SNAP_SIZE_SHOW_PROCESSED_SIZE + BTRFS_SNAP_SIZE_SHOW_MARGINAL_SIZE + are all set + the output format will like: + + subvol(360) 0 bytes + subvol(361) 0 bytes + subvol(362) 2048 bytes + . + . + subvol(512) 40967 bytes + exclusive 43014 bytes + processed 203503 bytes + + subvol(360) 0 bytes + subvol(361) 12802 bytes + subvol(362) 4096 bytes + . + . + subvol(512) 60967 bytes + exclusive 77865 bytes + processed 302122 bytes + . + . + + */ + __s64 fd; + /* address of snap ids/marginal size map to caluclate */ + struct btrfs_ioctl_snapshot_size_id_size_map __user *id_maps; + /* exclusive size in byte */ + __u64 calc_size; + __u64 processed_size; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_LOG_TREE_BG_RSV_ADD (1ULL << 0) +#define BTRFS_LOG_TREE_BG_RSV_REMOVE (1ULL << 1) + +struct btrfs_ioctl_log_tree_reserve_bg_args { + __u64 start; + __u64 size; + __u64 map_start; + __u64 flags; + __u64 reserved[4]; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_FREE_SPACE_ANALYZE_NR_INTERVAL 15 +#define BTRFS_FREE_SPACE_ANALYZE_FLAG_FULL (1ULL << 0) + +struct btrfs_ioctl_free_space_analyze_args { + /* arguments */ + __u64 flags; + __u64 min_continuous_size; + + /* results */ + __u64 interval_cnts[BTRFS_FREE_SPACE_ANALYZE_NR_INTERVAL]; // For intervals from [4K,8K), [8K,16K) to [64M,128M) + __u64 frag_cnts; // Count of the free blocks which < min_continuous_size + __u64 continuous_cnts; // Count of the free blocks which >= min_continuous_size + __u64 total_frag_size; // The total size of the free blocks which < min_continuous_size + __u64 total_continuous_size; // The total size of the free blocks which >= min_continuous_size + + /* reserved */ + __u64 reserved[8]; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct btrfs_ioctl_find_next_chunk_info_args { + __u64 start; + __u64 flags; + __u64 size; + __u64 stripe_count; + __u64 stripe_offset[2]; + __u64 reserved[4]; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* flags for the compression ioctl */ +#define BTRFS_COMPR_CTL_SET 0x1 +#define BTRFS_COMPR_CTL_COMPR_FL 0x2 + +struct btrfs_ioctl_compr_ctl_args { + __u64 flags; /* in/out */ + __u64 size; /* out */ + __u64 compressed_size; /* out */ + __u64 reserved[1]; +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_SYNO_FEAT_TREE_CTL_ENABLE 1 +#define BTRFS_SYNO_FEAT_TREE_CTL_DISABLE 2 +#define BTRFS_SYNO_FEAT_TREE_CTL_STATUS 3 + +struct btrfs_ioctl_syno_feat_tree_ctl_args { + __u64 cmd; // commands + + /* for status */ + __u64 status; + + /* for reserve */ + __u64 reserved[4]; +}; + +enum btrfs_syno_feature_tree_status_enum { + SYNO_FEAT_TREE_ST_DISABLE = 0, + SYNO_FEAT_TREE_ST_ENABLE, +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +enum btrfs_syno_usage_state_enum { + SYNO_USAGE_STATE_NONE = 0, + SYNO_USAGE_STATE_INITIAL, + SYNO_USAGE_STATE_RESCAN, + SYNO_USAGE_STATE_RESCAN_ERROR, + SYNO_USAGE_STATE_RESCAN_PAUSE, + SYNO_USAGE_STATE_ENABLE, + SYNO_USAGE_STATE_DISABLE, +}; + +enum btrfs_syno_usage_root_state_enum { + SYNO_USAGE_ROOT_STATE_NORMAL = 0, + SYNO_USAGE_ROOT_STATE_RESCAN, +}; + +enum btrfs_syno_usage_type_enum { + SYNO_USAGE_TYPE_NONE = 0, + SYNO_USAGE_TYPE_RO_SNAPSHOT, + SYNO_USAGE_TYPE_MAX = 256, +}; + +#define BTRFS_SYNO_USAGE_CTL_ENABLE 1 +#define BTRFS_SYNO_USAGE_CTL_DISABLE 2 +#define BTRFS_SYNO_USAGE_CTL_STATUS 3 +#define BTRFS_SYNO_USAGE_CTL_RESCAN 4 +#define BTRFS_SYNO_USAGE_CTL_RESCAN_PAUSE 5 +#define BTRFS_SYNO_USAGE_CTL_SUBVOL_TYPE_SET 6 +#define BTRFS_SYNO_USAGE_CTL_SUBVOL_TYPE_GET 7 +#define BTRFS_SYNO_USAGE_CTL_USAGE_GET_BY_TYPE 8 +struct btrfs_ioctl_syno_usage_ctl_args { + __u64 cmd; // commands + + /* for status */ + __u64 state; + __u64 flags; + __u32 pending_fast_rescan_count; + __u32 pending_full_rescan_count; + __u32 fast_rescan_pid; + __u32 full_rescan_pid; + + /* + * for status usage + * for subvol type get/set + */ + __u8 type; + + /* for rescan */ + __s32 error_code; + __u64 cur_rescan_size; + __u64 total_rescan_size; + + /* for status usage */ + __u64 num_bytes; + + /* for reserve */ + __u64 reserved[4]; +}; +#endif /* MY_ABC_HERE */ + /* * Caller doesn't want file data in the send stream, even if the * search of clone sources doesn't find an extent. UPDATE_EXTENT @@ -769,10 +1385,68 @@ struct btrfs_ioctl_received_subvol_args { */ #define BTRFS_SEND_FLAG_OMIT_END_CMD 0x4 +#ifdef MY_ABC_HERE +/* + * Calculate the amount (in bytes) of new file data between the send and + * parent snapshots, or in case of a full send, the total amount of file data + * we will send. + */ +#define BTRFS_SEND_FLAG_CALCULATE_DATA_SIZE 0x8 + +/* + * find_extent_clone in send could take a lot of time but end up find nothing + * to clone, especially in iSCSI BLun thick provision. This flag is used + * to indicate send to skip find_extent_clone. + */ +#define BTRFS_SEND_FLAG_SKIP_FIND_CLONE 0x10 + +/* + * Use fallocate command to pre-allocate file extents and punch file holes, + * instead of write commands with data buffers filled with 0 value bytes. + */ +#define BTRFS_SEND_FLAG_SUPPORT_FALLOCATE 0x20 + +/* + * Convert value of xattr btrfs.compression of set_xattr from "zstd" to "lzo" + */ +#define BTRFS_SEND_FLAG_FALLBACK_COMPRESSION 0x40 + +/* + * Support synology btrfs send/recv features by this flag so that DSM kernel + * can be compatible with native btrfs cmd stream. + */ +#define BTRFS_SEND_FLAG_SYNO_FEATURES 0x80 + +#define BTRFS_SEND_FLAG_VERBOSE 0x100 + +/* + * This mask is used to clear syno flags generating cmds customized by synology + * if BTRFS_SEND_FLAG_SYNO_FEATURES isn't turned on. + */ +#define BTRFS_SEND_GEN_SYNO_CMD_FLAG_MASK \ + (BTRFS_SEND_FLAG_SUPPORT_FALLOCATE) +/* + * In order to simplify how BTRFS_SEND_FLAG_MASK works with syno defined flags, + * all send flags defined by syno config have to depend on + * SYNO_BTRFS_SEND_FLAGS_SUPPORT. + */ +#define BTRFS_SEND_FLAG_MASK \ + (BTRFS_SEND_FLAG_NO_FILE_DATA | \ + BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \ + BTRFS_SEND_FLAG_OMIT_END_CMD | \ + BTRFS_SEND_FLAG_CALCULATE_DATA_SIZE | \ + BTRFS_SEND_FLAG_SKIP_FIND_CLONE | \ + BTRFS_SEND_FLAG_SUPPORT_FALLOCATE | \ + BTRFS_SEND_FLAG_FALLBACK_COMPRESSION | \ + BTRFS_SEND_FLAG_SYNO_FEATURES | \ + BTRFS_SEND_FLAG_VERBOSE) + +#else /* MY_ABC_HERE */ #define BTRFS_SEND_FLAG_MASK \ (BTRFS_SEND_FLAG_NO_FILE_DATA | \ BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \ BTRFS_SEND_FLAG_OMIT_END_CMD) +#endif /* MY_ABC_HERE */ struct btrfs_ioctl_send_args { __s64 send_fd; /* in */ @@ -780,7 +1454,19 @@ struct btrfs_ioctl_send_args { __u64 __user *clone_sources; /* in */ __u64 parent_root; /* in */ __u64 flags; /* in */ +#ifdef MY_ABC_HERE + __u64 total_data_size; /* out */ +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + __u64 skip_cmd_count; +#endif /* MY_ABC_HERE */ +#if defined(MY_ABC_HERE) && defined(MY_ABC_HERE) + __u64 reserved[2]; /* in */ +#elif defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + __u64 reserved[3]; /* in */ +#else /* !defined(MY_ABC_HERE) && !defined(MY_ABC_HERE) */ __u64 reserved[4]; /* in */ +#endif /* defined(MY_ABC_HERE) && defined(MY_ABC_HERE) */ }; /* @@ -872,6 +1558,43 @@ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1C3_MIN_NOT_MET, BTRFS_ERROR_DEV_RAID1C4_MIN_NOT_MET, }; +#ifdef __KERNEL__ +#ifdef MY_ABC_HERE +long btrfs_lazy_clone(struct file *file, unsigned long srcfd, u64 off, + u64 olen, u64 destoff); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +int btrfs_vfs_ino_to_path(struct inode *inode, u64 inum, char *outpath, int len); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +struct btrfs_list_hardlinks_iter_index { + u64 type; /* INODE_REF/INODE_EXTREF */ + u64 dir; /* for INODE_REF */ + u64 dir_index; /* for INODE_REF */ + u64 offset; /* for INODE_EXTREF */ + u64 cursor; /* internal use */ + u64 free_space; /* internal use */ +}; +enum btrfs_list_hardlinks_index_type_enum { + SYNO_BTRFS_LIST_HARDLINKS_INDEX_TYPE_INODE_REF = 0, + SYNO_BTRFS_LIST_HARDLINKS_INDEX_TYPE_INODE_EXTREF, +}; +struct btrfs_hardlink_entry { + u32 record_len; + u32 name_len; + u64 parent_inum; +} __attribute__ ((__packed__)); +struct btrfs_list_hardlinks_args { + struct inode *inode; /* in : subvolume dir inode */ + u64 inum; /* in */ + u64 buf_size; /* in : buffer size */ + struct btrfs_list_hardlinks_iter_index index; /* in/out */ + u64 elem_cnt; /* out */ + u8 buf[0]; /* out */ +}; +int btrfs_list_hardlinks(struct btrfs_list_hardlinks_args *args); +#endif /* MY_ABC_HERE */ +#endif /* __KERNEL__ */ #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) @@ -988,4 +1711,118 @@ enum btrfs_err_code { #define BTRFS_IOC_SNAP_DESTROY_V2 _IOW(BTRFS_IOCTL_MAGIC, 63, \ struct btrfs_ioctl_vol_args_v2) +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_LOCKER_GET _IOR(BTRFS_IOCTL_MAGIC, 232, struct btrfs_ioctl_syno_locker_args) +#define BTRFS_IOC_SYNO_LOCKER_SET _IOW(BTRFS_IOCTL_MAGIC, 233, struct btrfs_ioctl_syno_locker_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_GET_SYNO_FLAGS _IOR(BTRFS_IOCTL_MAGIC, 234, \ + struct btrfs_ioctl_syno_flags) +#define BTRFS_IOC_SET_SYNO_FLAGS _IOW(BTRFS_IOCTL_MAGIC, 234, \ + struct btrfs_ioctl_syno_flags[2]) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_QUOTA_STATUS _IOWR(BTRFS_IOCTL_MAGIC, 235, \ + struct btrfs_ioctl_syno_quota_status_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_FEAT_TREE_CTL _IOWR(BTRFS_IOCTL_MAGIC, 236, \ + struct btrfs_ioctl_syno_feat_tree_ctl_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_SET_DEDUPE_FLAG _IOWR(BTRFS_IOCTL_MAGIC, 237, \ + struct btrfs_ioctl_syno_dedupe_cmd_args) +#define BTRFS_IOC_SYNO_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 238, \ + struct btrfs_ioctl_syno_extent_same_args) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_IOC_FREE_SPACE_ANALYZE _IOWR(BTRFS_IOCTL_MAGIC, 240, \ + struct btrfs_ioctl_free_space_analyze_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_USAGE_CTL _IOWR(BTRFS_IOCTL_MAGIC, 241, \ + struct btrfs_ioctl_syno_usage_ctl_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_FIND_NEXT_CHUNK_INFO _IOWR(BTRFS_IOCTL_MAGIC, 242, \ + struct btrfs_ioctl_find_next_chunk_info_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_RESERVE_LOG_TREE_BLOCK_GROUP _IOWR(BTRFS_IOCTL_MAGIC, 244, \ + struct btrfs_ioctl_log_tree_reserve_bg_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNC_SYNO _IO(BTRFS_IOCTL_MAGIC, 246) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SNAPSHOT_SIZE_QUERY _IOWR(BTRFS_IOCTL_MAGIC, 247, \ + struct btrfs_ioctl_snapshot_size_query_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_COMPR_CTL _IOR(BTRFS_IOCTL_MAGIC, 248, \ + struct btrfs_ioctl_compr_ctl_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_QGROUP_QUERY _IOR(BTRFS_IOCTL_MAGIC, 253, \ + struct btrfs_ioctl_qgroup_query_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_CKSUMFAILED_FILES_GET _IOR(BTRFS_IOCTL_MAGIC, 254, \ + struct btrfs_ioctl_cksumfailed_files_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_SYNO_CLONE_RANGE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 245, \ + struct btrfs_ioctl_syno_clone_range_args_v2) +#endif /* CONFIG_SYNO_BTRFS_CLONE_RANGE */ + +#ifdef MY_ABC_HERE +#define BTRFS_IOC_USRQUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 250, \ + struct btrfs_ioctl_usrquota_ctl_args) +#define BTRFS_IOC_USRQUOTA_LIMIT _IOW(BTRFS_IOCTL_MAGIC, 250, \ + struct btrfs_ioctl_usrquota_limit_args) +#define BTRFS_IOC_USRQUOTA_RESCAN _IO(BTRFS_IOCTL_MAGIC, 250) +#define BTRFS_IOC_USRQUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 251, \ + struct btrfs_ioctl_usrquota_rescan_args) +#define BTRFS_IOC_USRQUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 251) +#define BTRFS_IOC_USRQUOTA_QUERY _IOR(BTRFS_IOCTL_MAGIC, 252, \ + struct btrfs_ioctl_usrquota_query_args) +#define BTRFS_IOC_USRQUOTA_CLEAN _IOW(BTRFS_IOCTL_MAGIC, 252, __u64) + +#define BTRFS_IOC_SYNO_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 255, \ + struct btrfs_ioctl_syno_quota_rescan_args) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +enum { + QGROUP_NL_C_UNSPEC, + QGROUP_NL_C_OVER_LIMIT, + QGROUP_NL_C_UNDER_LIMIT, + __QGROUP_NL_C_MAX, +}; +#define QGROUP_NL_C_MAX (__QGROUP_NL_C_MAX - 1) + +enum { + QGROUP_NL_A_FSID, + QGROUP_NL_A_SUBVOL_ID, + QGROUP_NL_A_QUOTA_LIMIT, + QGROUP_NL_A_QUOTA_USED, + QGROUP_NL_A_PAD, + __QGROUP_NL_A_MAX, +}; +#define QGROUP_NL_A_MAX (__QGROUP_NL_A_MAX - 1) +#endif /* MY_ABC_HERE */ + #endif /* _UAPI_LINUX_BTRFS_H */ diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index 6b885982ece6..7fec1514e895 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _BTRFS_CTREE_H_ #define _BTRFS_CTREE_H_ @@ -44,8 +47,11 @@ /* holds checksums of all the data extents */ #define BTRFS_CSUM_TREE_OBJECTID 7ULL +#ifdef MY_ABC_HERE +#else /* holds quota configuration and tracking */ #define BTRFS_QUOTA_TREE_OBJECTID 8ULL +#endif /* MY_ABC_HERE */ /* for storing items that use the BTRFS_UUID_KEY* types */ #define BTRFS_UUID_TREE_OBJECTID 9ULL @@ -53,6 +59,50 @@ /* tracks free space in block groups. */ #define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL +#ifdef MY_ABC_HERE +/* holds subvolume user quota configuration */ +#define BTRFS_USRQUOTA_TREE_OBJECTID 200ULL + +/* holds subvolume quota configuration */ +#define BTRFS_QUOTA_TREE_OBJECTID 201ULL +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_BLOCK_GROUP_HINT_TREE_OBJECTID 202ULL +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_BLOCK_GROUP_CACHE_TREE_OBJECTID 203ULL +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * syno usage tree + */ +#define BTRFS_SYNO_USAGE_TREE_OBJECTID 205ULL +/* + * syno extent usage tree + */ +#define BTRFS_SYNO_EXTENT_USAGE_TREE_OBJECTID 206ULL +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * syno feature tree + * + * We would like to create a tree that hold information + * about our customized feature after light-weight counter(included) + */ +#define BTRFS_SYNO_FEATURE_TREE_OBJECTID 207ULL +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* Syno quota v2 qgroup tree */ +#define BTRFS_SYNO_QUOTA_V2_TREE_OBJECTID 208ULL + +/* Syno quota v2 usrquota tree */ +#define BTRFS_SYNO_USRQUOTA_V2_TREE_OBJECTID 209ULL +#endif /* MY_ABC_HERE */ + /* device stats in the device tree */ #define BTRFS_DEV_STATS_OBJECTID 0ULL @@ -86,6 +136,27 @@ */ #define BTRFS_FREE_INO_OBJECTID -12ULL +#ifdef MY_ABC_HERE +/* + * objectid of syno feature tree status item + */ +#define BTRFS_SYNO_FEAT_TREE_STATUS_OBJECTID 0ULL +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * syno subvol usage objectid in fs_tree + */ +#define BTRFS_SYNO_SUBVOL_USAGE_OBJECTID -206ULL +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * objectid of btrfs_root_locker_item in feature-tree + */ +#define BTRFS_SYNO_BTRFS_LOCKER_OBJECTID -211ULL +#endif /* MY_ABC_HERE */ + /* dummy objectid represents multiple objectids */ #define BTRFS_MULTIPLE_OBJECTIDS -255ULL @@ -128,6 +199,9 @@ #define BTRFS_DIR_LOG_ITEM_KEY 60 #define BTRFS_DIR_LOG_INDEX_KEY 72 #define BTRFS_DIR_ITEM_KEY 84 +#ifdef MY_ABC_HERE +#define BTRFS_DIR_ITEM_CASELESS_KEY 91 +#endif /* MY_ABC_HERE */ #define BTRFS_DIR_INDEX_KEY 96 /* * extent data is for file data @@ -146,12 +220,21 @@ */ #define BTRFS_ROOT_ITEM_KEY 132 +#ifdef MY_ABC_HERE +#define BTRFS_ROOT_LOCKER_KEY 138 +#endif /* MY_ABC_HERE */ + /* * root backrefs tie subvols and snapshots to the directory entries that * reference them */ #define BTRFS_ROOT_BACKREF_KEY 144 +#ifdef MY_ABC_HERE +#define SYNO_BTRFS_RBD_META_FILE_INODE_RECORD 150 +#define SYNO_BTRFS_RBD_META_FILE_SUBVOL_RECORD 151 +#endif /* MY_ABC_HERE */ + /* * root refs make a fast index for listing all of the snapshots and * subvolumes referenced by a given root. They point directly to the @@ -159,6 +242,38 @@ */ #define BTRFS_ROOT_REF_KEY 156 +#ifdef MY_ABC_HERE +/* + * syno feature tree status key: 157 + */ +#define SYNO_BTRFS_FEAT_TREE_STATUS_KEY 157 +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * syno usage tree + * syno usage status key : 158 + * global type key : 159 + * root status key : 160 + */ +#define SYNO_BTRFS_USAGE_STATUS_KEY 158 +#define SYNO_BTRFS_USAGE_GLOBAL_TYPE_KEY 159 +#define SYNO_BTRFS_USAGE_ROOT_STATUS_KEY 160 + +/* + * fs tree + * syno subvol dummy key 162 + * syno subvol usage key 163 + */ +#define SYNO_BTRFS_SUBVOL_DUMMY_KEY 162 +#define SYNO_BTRFS_SUBVOL_USAGE_KEY 163 + +/* + * syno extent usage key + */ +#define SYNO_BTRFS_EXTENT_USAGE_KEY 165 +#endif /* MY_ABC_HERE */ + /* * extent items are in the extent map tree. These record which blocks * are used, and how many references there are to each block @@ -228,6 +343,11 @@ * One key per qgroup, (0, BTRFS_QGROUP_LIMIT_KEY, qgroupid). */ #define BTRFS_QGROUP_LIMIT_KEY 244 + +#ifdef MY_ABC_HERE +#define BTRFS_SYNO_QUOTA_RESCAN_KEY 245 +#endif /* MY_ABC_HERE */ + /* * Records the child-parent relationship of qgroups. For * each relation, 2 keys are present: @@ -236,6 +356,32 @@ */ #define BTRFS_QGROUP_RELATION_KEY 246 +#ifdef MY_ABC_HERE +/* + * Records the overall state of the usrquota. + * There's only one instance of this key present, + * (0, BTRFS_USRQUOTA_STATUS_KEY, 0) + */ +#define BTRFS_USRQUOTA_STATUS_KEY 240 +/* + * Records the per root (subvolume) usrquota infomation. + * One key per root, (root_id, BTRFS_USRQUOTA_ROOT_KEY, 0). + */ +#define BTRFS_USRQUOTA_ROOT_KEY 241 +/* + * Records the currently used space of the usrquota. + * One key per usrquota, (root_id, BTRFS_USRQUOTA_INFO_KEY, uid). + */ +#define BTRFS_USRQUOTA_INFO_KEY 242 +/* + * Contains the user configured limits for the usrquota. + * One key per usrquota, (root_id, BTRFS_USRGROUP_LIMIT_KEY, uid). + */ +#define BTRFS_USRQUOTA_LIMIT_KEY 244 + +#define BTRFS_USRQUOTA_COMPAT_KEY 245 +#endif /* MY_ABC_HERE */ + /* * Obsolete name, see BTRFS_TEMPORARY_ITEM_KEY. */ @@ -472,6 +618,89 @@ struct btrfs_free_space_header { #define BTRFS_SUPER_FLAG_CHANGING_FSID (1ULL << 35) #define BTRFS_SUPER_FLAG_CHANGING_FSID_V2 (1ULL << 36) +#ifdef MY_ABC_HERE +#define BTRFS_SYNO_USAGE_STATUS_VERSION 1 + +struct btrfs_syno_extent_usage_item { + __u8 type; + __le64 reserved[1]; +} __attribute__ ((__packed__)); + +struct btrfs_syno_extent_usage_inline_ref { + __u8 type; + __le32 count; + __le64 reserved[1]; +} __attribute__ ((__packed__)); + +struct btrfs_syno_subvol_usage_item { + __le32 refs; + __le32 num_bytes; + __le64 reserved[1]; +} __attribute__ ((__packed__)); + +#define BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY (1ULL << 0) +#define BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN (1ULL << 1) +#define BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN (1ULL << 2) +#define BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING (1ULL << 3) +#define BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_MASK (BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN | \ + BTRFS_SYNO_USAGE_ROOT_FLAG_FULL_RESCAN | \ + BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING) +#define BTRFS_SYNO_USAGE_ROOT_FLAG_FORCE_EXTENT (1ULL << 4) +#define BTRFS_SYNO_USAGE_ROOT_FLAG_RESET_MASK (BTRFS_SYNO_USAGE_ROOT_FLAG_READONLY | \ + BTRFS_SYNO_USAGE_ROOT_FLAG_FAST_RESCAN | \ + BTRFS_SYNO_USAGE_ROOT_FLAG_RESCAN_PROGRESS_ACCOUNTING | \ + BTRFS_SYNO_USAGE_ROOT_FLAG_FORCE_EXTENT) +struct btrfs_syno_usage_root_status_item { + __u8 type; + __u8 new_type; + __le64 state; + __le64 flags; + __le64 num_bytes; + /* for subvol delete */ + struct btrfs_disk_key drop_progress; + /* for rescan */ + struct btrfs_disk_key fast_rescan_progress; + struct btrfs_disk_key full_rescan_progress; + __le64 cur_full_rescan_size; + __le64 total_full_rescan_size; + /* for disable */ + __le64 total_syno_subvol_usage_items; + __le64 reserved[4]; +} __attribute__ ((__packed__)); + +struct btrfs_syno_usage_global_type_item { + __le64 num_bytes; + __le64 reserved[4]; +} __attribute__ ((__packed__)); + +#define BTRFS_SYNO_USAGE_FLAG_INCONSISTENT (1ULL << 0) + +struct btrfs_syno_usage_status_item { + __le64 version; + __le64 state; + __le64 flags; + __le64 generation; + /* for rescan */ + struct btrfs_disk_key extent_rescan_progress; + __le64 cur_full_rescan_size; + __le64 total_full_rescan_size; + __le64 extent_tree_cur_rescan_size; + __le64 extent_tree_total_rescan_size; + /* for disable */ + __le64 total_syno_extent_tree_items; + __le64 total_syno_subvol_usage_items; + __le64 reserved[4]; +} __attribute__ ((__packed__)); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +struct btrfs_syno_feat_tree_status_item { + __le64 version; + __le64 status; +} __attribute__ ((__packed__)); + +#define BTRFS_SYNO_FEAT_TREE_VERSION 1 +#endif /* MY_ABC_HERE */ /* * items in the extent btree are used to record the objectid of the @@ -503,6 +732,21 @@ struct btrfs_extent_item_v0 { */ #define BTRFS_EXTENT_FLAG_SUPER (1ULL << 48) +#ifdef MY_ABC_HERE +/* + * This flag is used to indicate that the extent item has more than + * one backrefs for a particular file. This could be done by calling + * BTRFS_IOC_CLONE_RANGE or dedup. Since our quota reference needs to + * drop only if we find out that this is the file's last reference + * to this extent item. After enabling dedup and iocl, things become + * much more complicated because the variable "last_ref" in + * __btrfs_free_extent doesn't serve our purpose for indicating we + * need to drop quota due to dropping of file's last reference to + * this file. + */ +#define BTRFS_EXTENT_FLAG_HAS_CLONE_RANGE (1ULL << 59) +#endif /* MY_ABC_HERE */ + struct btrfs_tree_block_info { struct btrfs_disk_key key; __u8 level; @@ -577,7 +821,12 @@ struct btrfs_inode_item { * a little future expansion, for more than this we can * just grow the inode item and version it */ +#ifdef MY_ABC_HERE + __le64 reserved[3]; + __le64 syno_uq_rfer_used; +#else __le64 reserved[4]; +#endif /* MY_ABC_HERE */ struct btrfs_timespec atime; struct btrfs_timespec ctime; struct btrfs_timespec mtime; @@ -597,6 +846,14 @@ struct btrfs_dir_item { } __attribute__ ((__packed__)); #define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) +#ifdef MY_ABC_HERE +#define BTRFS_ROOT_SUBVOL_HIDE (1ULL << 32) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +#define BTRFS_ROOT_SUBVOL_NOLOAD_USRQUOTA (1ULL << 33) +#define BTRFS_ROOT_SUBVOL_CMPR_RATIO (1ULL << 34) +#define BTRFS_ROOT_SUBVOL_DISABLE_QUOTA (1ULL << 35) +#endif /* MY_ABC_HERE */ /* * Internal in-memory flag that a subvolume has been marked for deletion but @@ -658,6 +915,26 @@ static inline __u32 btrfs_legacy_root_item_size(void) return offsetof(struct btrfs_root_item, generation_v2); } +#ifdef MY_ABC_HERE +struct btrfs_root_locker_item { + __u8 enabled; + __u8 mode; + __u8 default_state; + __u8 state; + __u8 unused[4]; + __le64 waittime; + __le64 duration; + __le64 clock_adjustment; + __le64 update_time_floor; + + __le64 period_begin; + __le64 period_begin_sys; + __le64 period_end; + __le64 period_end_sys; + __le64 reserved[3]; +} __attribute__ ((__packed__)); +#endif /* MY_ABC_HERE */ + /* * this is used for both forward and backward root refs */ @@ -752,6 +1029,10 @@ enum { BTRFS_NR_FILE_EXTENT_TYPES = 3, }; +#ifdef MY_ABC_HERE +#define BTRFS_FILE_EXTENT_DEDUPED 0x1 +#endif /* MY_ABC_HERE */ + struct btrfs_file_extent_item { /* * transaction id that created this extent @@ -775,7 +1056,15 @@ struct btrfs_file_extent_item { */ __u8 compression; __u8 encryption; +#ifdef MY_ABC_HERE + __u8 other_encoding; /* spare for later use */ + /* + * BTRFS_FILE_EXTENT_DEDUPED + */ + __u8 syno_flag; +#else /* MY_ABC_HERE */ __le16 other_encoding; /* spare for later use */ +#endif /* MY_ABC_HERE */ /* are we inline data or a real extent? */ __u8 type; @@ -949,7 +1238,17 @@ static inline __u16 btrfs_qgroup_level(__u64 qgroupid) */ #define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT (1ULL << 2) +#ifdef MY_ABC_HERE +// To pause a runnung rescan. +#define BTRFS_QGROUP_STATUS_FLAG_PAUSE (1ULL << 17) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_QGROUP_STATUS_VERSION 1 +#define BTRFS_QGROUP_V2_STATUS_VERSION 87 +#else #define BTRFS_QGROUP_STATUS_VERSION 1 +#endif /* MY_ABC_HERE */ struct btrfs_qgroup_status_item { __le64 version; @@ -986,8 +1285,99 @@ struct btrfs_qgroup_limit_item { __le64 flags; __le64 max_rfer; __le64 max_excl; +#ifdef MY_ABC_HERE + union { + __le64 soft_rfer; + __le64 rsv_rfer; + }; + union { + __le64 soft_excl; + __le64 rsv_excl; + }; +#else __le64 rsv_rfer; __le64 rsv_excl; +#endif /* MY_ABC_HERE */ } __attribute__ ((__packed__)); +#ifdef MY_ABC_HERE +#define SYNO_QUOTA_RESCAN_DONE (1ULL << 0) +#define SYNO_QUOTA_RESCAN_QUEUED (1ULL << 1) +#define SYNO_QUOTA_RESCAN_DOING (1ULL << 2) +#define SYNO_QUOTA_RESCAN_ERR (1ULL << 3) // We found werror when rescaning. +#define SYNO_QUOTA_RESCAN_NEED (1ULL << 4) // We found error when updating quota. + +struct btrfs_syno_quota_rescan_item { + __le64 flags; + __le64 version; + __le64 generation; // generation that we update this item. + __le64 rescan_inode; // inode number that we already scanned. + __le64 end_inode; // max inode number when we do btrfs_syno_quota_rescan(). + __le64 tree_size; // fs tree size when we do btrfs_syno_quota_rescan(). + __le64 next_root; + __le64 reserved[1]; +} __attribute__ ((__packed__)); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define BTRFS_USRQUOTA_STATUS_FLAG_ON (1ULL << 0) +#define BTRFS_USRQUOTA_STATUS_FLAG_RESCAN (1ULL << 1) +#define BTRFS_USRQUOTA_STATUS_FLAG_INCONSISTENT (1ULL << 2) + +#define BTRFS_USRQUOTA_STATUS_VERSION 1 +#define BTRFS_USRQUOTA_V2_STATUS_VERSION 87 + +#define BTRFS_USRQUOTA_COMPAT_FLAG_INODE_QUOTA (1ULL << 0) +#define BTRFS_USRQUOTA_COMPAT_FLAG \ + (BTRFS_USRQUOTA_COMPAT_FLAG_INODE_QUOTA) + +struct btrfs_usrquota_status_item { + __le64 version; + __le64 generation; + __le64 flags; + __le64 rescan_rootid; + __le64 rescan_objectid; + __le64 reserved[3]; +} __attribute__ ((__packed__)); + +struct btrfs_usrquota_compat_item { + __le64 generation; + __le64 flags; + __le64 reserved[4]; +} __attribute__ ((__packed__)); + +struct btrfs_usrquota_root_item { + __le64 info_item_cnt; + __le64 limit_item_cnt; +} __attribute__ ((__packed__)); + +struct btrfs_usrquota_info_item { + __le64 generation; + __le64 rfer_used; +} __attribute__ ((__packed__)); + +struct btrfs_usrquota_limit_item { + __le64 rfer_soft; + __le64 rfer_hard; +} __attribute__ ((__packed__)); + +union btrfs_usrquota_item_union { + struct btrfs_usrquota_info_item info_item; + struct btrfs_usrquota_limit_item limit_item; +}; + +#define BTRFS_USRQUOTA_MAX_ITEMS_LEAF(f) (BTRFS_LEAF_DATA_SIZE(f) / \ + (sizeof(union btrfs_usrquota_item_union) + \ + sizeof(struct btrfs_item))) +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +struct btrfs_rbd_meta_file_subvol_record_item { + __le32 inode_cnt; +} __attribute__ ((__packed__)); + +struct btrfs_rbd_meta_file_inode_record_item{ + __le64 generation; // same as inode's generation +} __attribute__ ((__packed__)); +#endif /* MY_ABC_HERE */ + #endif /* _BTRFS_CTREE_H_ */ diff --git a/include/uapi/linux/falloc.h b/include/uapi/linux/falloc.h index 51398fa57f6c..2c17286a1e39 100644 --- a/include/uapi/linux/falloc.h +++ b/include/uapi/linux/falloc.h @@ -77,4 +77,17 @@ */ #define FALLOC_FL_UNSHARE_RANGE 0x40 +#ifdef CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN +/* + * FALLOC_FL_MARK_WRITTEN is used to mark the newly allocated range of + * file as written instead of prealloc. Without this flag, each fallocated + * area will be marked as prealloc, and changed to written status when + * first write occured within that range. This update requires metadata + * update. Since we don't initialize the fallocated range and the + * status is already marked as written, we'll read garbage data until + * we first write those blocks. + */ +#define FALLOC_FL_MARK_WRITTEN 0x1000 +#endif /* CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN */ + #endif /* _UAPI_FALLOC_H_ */ diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index f44eb0a04afd..f82e09b4ed0b 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _UAPI_LINUX_FS_H #define _UAPI_LINUX_FS_H @@ -106,6 +109,79 @@ struct inodes_stat_t { long dummy[5]; /* padding for sysctl ABI compatibility */ }; +#ifdef MY_ABC_HERE +enum locker_mode { + LM_NONE = 0, + LM_ENTERPRISE = 1, + LM_COMPLIANCE = 2, + LM_INHOUSE = 3, + LM_MAX = LM_INHOUSE +}; + +enum locker_state { + LS_OPEN = 0, + LS_IMMUTABLE = 1, + LS_APPENDABLE = 2, + LS_EXPIRED_I = 3, + LS_EXPIRED_A = 4, + LS_W_IMMUTABLE = 5, + LS_W_APPENDABLE = 6, + LS_MAX = LS_W_APPENDABLE +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* request */ +#define SYNO_SPACE_USAGE_REQUEST_DATA_USED (1ULL << 0) /* Want/got data used */ +#define SYNO_SPACE_USAGE_REQUEST_DATA_DELAY_ALLOCATED (1ULL << 1) /* Want/got data delay allocated */ +#define SYNO_SPACE_USAGE_REQUEST_METADATA_USED (1ULL << 2) /* Want/got metadata used */ + +/* flags */ +#define SYNO_SPACE_USAGE_FLAG_RESCAN (1ULL << 0) + +struct syno_space_usage_info { + /* in */ + __u64 request_mask; + /* out */ + __u64 result_mask; + __u64 flags; + __u64 data_used; + __u64 data_delay_allocated; + __u64 metadata_used; + __u64 reserved[10]; /* pad to 128 bytes */ +}; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +enum SYNO_RBD_META_IOCTL_ACT { + SYNO_RBD_META_ACTIVATE = 1, + SYNO_RBD_META_DEACTIVATE = 2, + SYNO_RBD_META_MAPPING = 3, + SYNO_RBD_META_SET_FIRST_OFFSET = 4, + SYNO_RBD_META_CLEANUP_ALL = 5, + SYNO_RBD_META_MAPPING_COUNT = 6, +}; + +struct syno_rbd_meta_file_mapping { + __u64 dev_offset; + __u64 length; +}; + +struct syno_rbd_meta_ioctl_args { + unsigned int act; /* enum SYNO_RBD_META_IOCTL_ACT */ + union { + struct { + __u64 first_offset; + }; + struct { + __u64 start; + size_t size; + __u64 cnt; + }; + }; + struct syno_rbd_meta_file_mapping mappings[0]; +}; +#endif /* MY_ABC_HERE */ #define NR_FILE 8192 /* this can well be larger on a larger system */ @@ -184,6 +260,9 @@ struct fsxattr { #define BLKSECDISCARD _IO(0x12,125) #define BLKROTATIONAL _IO(0x12,126) #define BLKZEROOUT _IO(0x12,127) +#ifdef MY_ABC_HERE +#define BLKHINTUNUSED _IO(0x12, 140) +#endif /* MY_ABC_HERE */ /* * A jump here: 130-131 are reserved for zoned block devices * (see uapi/linux/blkzoned.h) @@ -199,7 +278,25 @@ struct fsxattr { #define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) #define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range) +#ifdef MY_ABC_HERE +#define FIGETVERSION _IOWR('x', 122, unsigned int) /* get syno archive version */ +#define FISETVERSION _IOWR('x', 123, unsigned int) /* set syno archive version */ +#define FIINCVERSION _IO('x', 124) /* increase syno archive version by 1 */ +#define FISETFILEVERSION _IOWR('x', 125, unsigned int) /* set file syno archive version */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define FIHINTUNUSED _IOWR('x', 129, unsigned int) /* search unused space as hints */ +#endif /* MY_ABC_HERE */ + #define FSLABEL_MAX 256 /* Max chars for the interface; each fs may differ */ +#ifdef MY_ABC_HERE +#define FICTRRBDMETA _IOWR('x', 130, unsigned int) /* control syno rbd meta */ +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define FISPACEUSAGE _IOWR('x', 131, struct syno_space_usage_info) /* get space usage */ +#endif /* MY_ABC_HERE */ #define FS_IOC_GETFLAGS _IOR('f', 1, long) #define FS_IOC_SETFLAGS _IOW('f', 2, long) @@ -304,4 +401,5 @@ typedef int __bitwise __kernel_rwf_t; #define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT |\ RWF_APPEND) + #endif /* _UAPI_LINUX_FS_H */ diff --git a/include/uapi/linux/mmc/ioctl.h b/include/uapi/linux/mmc/ioctl.h index 27a39847d55c..5aa6bc20c7c4 100644 --- a/include/uapi/linux/mmc/ioctl.h +++ b/include/uapi/linux/mmc/ioctl.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef LINUX_MMC_IOCTL_H #define LINUX_MMC_IOCTL_H @@ -74,6 +77,23 @@ struct mmc_ioc_multi_cmd { * is enforced per ioctl call. For larger data transfers, use the normal * block device operations. */ +#if defined(MY_DEF_HERE) +struct mmc_blk_erase_args { + __u32 from; + __u32 nr; +}; +#define MMCERASE _IOW(MMC_BLOCK_MAJOR, 2, struct mmc_blk_erase_args) + +struct mmc_euda_gpp_args { + unsigned long size[4]; + char type[4]; + int gpp_num; + unsigned long euda_start_addr; + unsigned long euda_size; +}; +#define GPP_EUDA_SETTING _IOW(MMC_BLOCK_MAJOR, 3, struct mmc_euda_gpp_args) + +#endif /* MY_DEF_HERE */ #define MMC_IOC_MAX_BYTES (512L * 1024) #define MMC_IOC_MAX_CMDS 255 #endif /* LINUX_MMC_IOCTL_H */ diff --git a/include/uapi/linux/mount.h b/include/uapi/linux/mount.h index dd8306ea336c..3e5b72635e62 100644 --- a/include/uapi/linux/mount.h +++ b/include/uapi/linux/mount.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif #ifndef _UAPI_LINUX_MOUNT_H #define _UAPI_LINUX_MOUNT_H @@ -17,6 +20,9 @@ #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ #define MS_DIRSYNC 128 /* Directory modifications are synchronous */ #define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */ +#ifdef MY_ABC_HERE +#define MS_ROOTPRJQUOTA 512 +#endif /* MY_ABC_HERE */ #define MS_NOATIME 1024 /* Do not update access times. */ #define MS_NODIRATIME 2048 /* Do not update directory access times */ #define MS_BIND 4096 diff --git a/include/uapi/linux/nfs2.h b/include/uapi/linux/nfs2.h index e0237e0985b9..64d33f70cdae 100644 --- a/include/uapi/linux/nfs2.h +++ b/include/uapi/linux/nfs2.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * NFS protocol definitions @@ -24,6 +27,12 @@ #define NFS2MODE_SOCK 0140000 #define NFS2MODE_FIFO 0010000 +#ifdef MY_ABC_HERE +#define NFS2_MAXZEROEDSIZE (1<<27) +#define NFS2_SYNOCOPYSIZE (1<<27) +#define NFS2_4G (1ULL<<32) +#define NFS2_LENTHINBYTE 8 +#endif /* MY_ABC_HERE */ /* NFSv2 file types - beware, these are not the same in NFSv3 */ enum nfs2_ftype { @@ -65,4 +74,14 @@ struct nfs2_fh { #define NFSPROC_READDIR 16 #define NFSPROC_STATFS 17 +#ifdef MY_ABC_HERE +#define NFSPROC_SYNO_WRITEZERO 28 +#define NFSPROC_SYNO_XLOOKUP 29 +#define NFSPROC_SYNO_COPY 30 +#define NFSPROC_SYNO_SUPPORT 31 +#ifdef MY_ABC_HERE +#define NFSPROC_SYNO_CLONE 32 +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + #endif /* _LINUX_NFS2_H */ diff --git a/include/uapi/linux/raid/md_p.h b/include/uapi/linux/raid/md_p.h index e5a98a16f9b0..71bce469b854 100644 --- a/include/uapi/linux/raid/md_p.h +++ b/include/uapi/linux/raid/md_p.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* md_p.h : physical layout of Linux RAID devices @@ -85,6 +88,9 @@ #define MD_DISK_CANDIDATE 5 /* disk is added as spare (local) until confirmed * For clustered enviroments only. */ +#ifdef MY_ABC_HERE +#define MD_DISK_SYNO_ERROR 6 /* disk error in degraded mode */ +#endif /* MY_ABC_HERE */ #define MD_DISK_FAILFAST 10 /* Send REQ_FAILFAST if there are multiple * devices available - and don't try to * correct read errors. @@ -96,11 +102,15 @@ */ #define MD_DISK_JOURNAL 18 /* disk is used as the write journal in RAID-5/6 */ +#ifdef MY_ABC_HERE +#define MD_DISK_ROLE_SYNO_ERROR_PREFIX 0x8000 +#endif /* MY_ABC_HERE */ #define MD_DISK_ROLE_SPARE 0xffff #define MD_DISK_ROLE_FAULTY 0xfffe #define MD_DISK_ROLE_JOURNAL 0xfffd #define MD_DISK_ROLE_MAX 0xff00 /* max value of regular disk role */ + typedef struct mdp_device_descriptor_s { __u32 number; /* 0 Device number in the entire set */ __u32 major; /* 1 Device major number */ diff --git a/include/uapi/linux/raid/md_u.h b/include/uapi/linux/raid/md_u.h index 105307244961..22b6128a9542 100644 --- a/include/uapi/linux/raid/md_u.h +++ b/include/uapi/linux/raid/md_u.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* md_u.h : user <=> kernel API between Linux raidtools and RAID drivers @@ -65,6 +68,16 @@ #define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) #define CLUSTERED_DISK_NACK _IO (MD_MAJOR, 0x35) +#ifdef MY_ABC_HERE +#define GET_SYNC_STATUS _IOR(MD_MAJOR, 0x60, MD_SYNC_STATUS) +#define GET_ARRAY_STATUS _IOR(MD_MAJOR, 0x61, int) + +typedef struct __tag_MD_SYNC_STATUS { + unsigned long long inSync; // 1 in sync, 0 not in sync + unsigned long long finishSectors; + unsigned long long totalSectors; +} MD_SYNC_STATUS; +#endif /* MY_ABC_HERE */ /* 63 partitions with the alternate major number (mdp) */ #define MdpMinorShift 6 diff --git a/include/uapi/linux/stat.h b/include/uapi/linux/stat.h index 1500a0f58041..f3e5b447c19b 100644 --- a/include/uapi/linux/stat.h +++ b/include/uapi/linux/stat.h @@ -1,7 +1,13 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _UAPI_LINUX_STAT_H #define _UAPI_LINUX_STAT_H +#ifndef __KERNEL__ +#include +#endif #include #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) @@ -43,6 +49,63 @@ #endif +#ifdef MY_ABC_HERE +/* Ext4 has only 16 bits for archive bit. */ +#define S2_IARCHIVE (1 << 0) // synology backup archive bit +#define S2_SMB_ARCHIVE (1 << 1) // samba backup archive bit (some other windows ap) +#define S2_SMB_HIDDEN (1 << 2) // hidden attribute in samba +#define S2_SMB_SYSTEM (1 << 3) // system attribute in samba +#define S3_IARCHIVE (1 << 4) // synology S3 backup archive bit (amazon ap) + +#ifdef MY_ABC_HERE +#define S2_SMB_READONLY (1 << 5) // read-only attribute of samba +#define S2_SYNO_ACL_INHERIT (1 << 6) // inherited from parent +#define S2_SYNO_ACL_IS_OWNER_GROUP (1 << 7) // owner tag of SYNO ACL +#define S2_SYNO_ACL_EXIST (1 << 8) // is there SYNO ACL +#define S2_SYNO_ACL_SUPPORT (1 << 9) // is support ACL +#define ALL_SYNO_ACL_ARCHIVE (S2_SMB_READONLY|S2_SYNO_ACL_INHERIT|S2_SYNO_ACL_IS_OWNER_GROUP|S2_SYNO_ACL_EXIST|S2_SYNO_ACL_SUPPORT) +#endif /* MY_ABC_HERE */ + +#define S2_SMB_SPARSE (1<<10) // sparse file support bit used by samba 4.4 + +#define ALL_IARCHIVE (S2_IARCHIVE|S3_IARCHIVE) // All synology archive bit. +#define ALL_SYNO_ARCHIVE (S2_IARCHIVE|S2_SMB_ARCHIVE|S3_IARCHIVE) // All backup archive bit, if there is new one, it should be added here. + +#ifdef MY_ABC_HERE +#define ALL_ARCHIVE_BIT (S2_IARCHIVE|S2_SMB_ARCHIVE|S2_SMB_HIDDEN|S2_SMB_SYSTEM|S3_IARCHIVE|ALL_SYNO_ACL_ARCHIVE|S2_SMB_SPARSE) +#define ALL_SMB (S2_SMB_ARCHIVE|S2_SMB_HIDDEN|S2_SMB_SYSTEM|S2_SMB_READONLY|S2_SMB_SPARSE) +#else /* MY_ABC_HERE */ +#define ALL_ARCHIVE_BIT (S2_IARCHIVE|S2_SMB_ARCHIVE|S2_SMB_HIDDEN|S2_SMB_SYSTEM|S3_IARCHIVE|S2_SMB_SPARSE) +#define ALL_SMB (S2_SMB_ARCHIVE|S2_SMB_HIDDEN|S2_SMB_SYSTEM|S2_SMB_SPARSE) +#endif /* MY_ABC_HERE */ + +#define ARCHIVE_BIT_MASK GENMASK(14, 0) + +#ifdef MY_ABC_HERE +#define EXT4_INODE_SWAPFILE_FLAG (1<<15) +#endif /* MY_ABC_HERE */ + +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE +/* + * flags: decide which information to get. + */ +#define SYNOST_STAT 0x00000001 /* stat */ +#define SYNOST_ARCHIVE_BIT 0x00000002 /* Archive Bit */ +#define SYNOST_ARCHIVE_VER 0x00000004 /* Archive Version (aka Backup Version) */ +#define SYNOST_CREATE_TIME 0x00000008 /* Create Time */ +#define SYNOST_COMPRESSION 0x00000010 /* Compression Type */ +#define SYNOST_IS_INLINE 0x00000020 /* Is inline file? */ +#define SYNOST_OFFLINE 0x00000040 /* currently, only c2fs support offline */ + +#define SYNOST_ALL (SYNOST_STAT|SYNOST_ARCHIVE_BIT|SYNOST_ARCHIVE_VER|SYNOST_CREATE_TIME|SYNOST_COMPRESSION|SYNOST_OFFLINE) +#define SYNOST_IS_CASELESS 0x10000000 /* Is Caseless */ + +#define SYNOST_FLAG_OFFLINE 0x00000001 /* Flags indicating inode offline status. Only used by c2fs */ +#endif /* MY_ABC_HERE */ + /* * Timestamp structure for the timestamps in struct statx. * diff --git a/include/uapi/linux/syno.h b/include/uapi/linux/syno.h new file mode 100644 index 000000000000..d36d22793391 --- /dev/null +++ b/include/uapi/linux/syno.h @@ -0,0 +1,114 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifndef _UAPI_LINUX_SYNO_H +#define _UAPI_LINUX_SYNO_H + +/* syno_autoconf.h was generated by modified /scripts/kconfig/conf (MY_ABC_HERE) */ +#ifndef __KERNEL__ +#include +#endif + +#ifndef LINUX_VERSION_CODE +#include +#endif +#define SYNO_HAVE_KERNEL_VERSION(a,b,c) (LINUX_VERSION_CODE >= KERNEL_VERSION((a),(b),(c)) ) + +#ifdef MY_ABC_HERE +#define SYNO_ARCHIVE_BIT +#if defined (F_CLEAR_ARCHIVE) || defined (F_SETSMB_ARCHIVE) || defined (F_SETSMB_HIDDEN) || \ + defined (F_SETSMB_SYSTEM) || defined (F_CLRSMB_ARCHIVE) || defined (F_CLRSMB_HIDDEN) || \ + defined (F_CLRSMB_SYSTEM) || defined (F_CLEAR_S3_ARCHIVE) || \ + defined (F_SETSMB_SPARSE) || defined (F_CLRSMB_SPARSE) +#error "Samba archive bit redefine." +#endif + +#ifdef MY_ABC_HERE +#define SYNO_FS_SYNO_ACL +#if defined (F_CLRSMB_READONLY) || defined (F_SETSMB_READONLY) || \ + defined (F_CLRACL_INHERIT) || defined (F_SETACL_INHERIT) || \ + defined (F_CLRACL_OWNER_IS_GROUP) || defined (F_SETACL_OWNER_IS_GROUP) || \ + defined (F_SETACL_SUPPORT) || defined (F_SETACL_SUPPORT) +#error "ACL archive bit redefine." +#endif /* ACL archive bit redefine. */ +#endif /* MY_ABC_HERE */ + +#define SYNO_FCNTL_BASE 513 +#define F_CLEAR_ARCHIVE (SYNO_FCNTL_BASE + 0) +#define F_SETSMB_ARCHIVE (SYNO_FCNTL_BASE + 1) +#define F_SETSMB_HIDDEN (SYNO_FCNTL_BASE + 2) +#define F_SETSMB_SYSTEM (SYNO_FCNTL_BASE + 3) +#define F_CLRSMB_ARCHIVE (SYNO_FCNTL_BASE + 4) +#define F_CLRSMB_HIDDEN (SYNO_FCNTL_BASE + 5) +#define F_CLRSMB_SYSTEM (SYNO_FCNTL_BASE + 6) +#define F_CLEAR_S3_ARCHIVE (SYNO_FCNTL_BASE + 7) + +#ifdef MY_ABC_HERE +#define F_CLRSMB_READONLY (SYNO_FCNTL_BASE + 8) +#define F_SETSMB_READONLY (SYNO_FCNTL_BASE + 9) +#define F_CLRACL_INHERIT (SYNO_FCNTL_BASE + 10) +#define F_SETACL_INHERIT (SYNO_FCNTL_BASE + 11) +#define F_CLRACL_HAS_ACL (SYNO_FCNTL_BASE + 12) +#define F_SETACL_HAS_ACL (SYNO_FCNTL_BASE + 13) +#define F_CLRACL_SUPPORT (SYNO_FCNTL_BASE + 14) +#define F_SETACL_SUPPORT (SYNO_FCNTL_BASE + 15) +#define F_CLRACL_OWNER_IS_GROUP (SYNO_FCNTL_BASE + 16) +#define F_SETACL_OWNER_IS_GROUP (SYNO_FCNTL_BASE + 17) +#define F_SETSMB_SPARSE (SYNO_FCNTL_BASE + 18) +#define F_CLRSMB_SPARSE (SYNO_FCNTL_BASE + 19) +#define SYNO_FCNTL_LAST F_CLRSMB_SPARSE +#else /* MY_ABC_HERE */ +#define F_SETSMB_SPARSE (SYNO_FCNTL_BASE + 8) +#define F_CLRSMB_SPARSE (SYNO_FCNTL_BASE + 9) +#define SYNO_FCNTL_LAST F_CLRSMB_SPARSE +#endif /* MY_ABC_HERE */ +#endif /* MY_ABC_HERE */ + + + + +/** + * Fix: DSM #103889 + * Dsc: Add notification for unsupported SFP+ + */ +#if defined (MY_ABC_HERE) && !defined (__ASSEMBLER__) +typedef enum +{ + SFP_NOTIFY_UNSET = 0, + SFP_NOTIFY_NOT_SUPPORT_DROP = 1, /* Interface might drop. ex: ixgbe */ + SFP_NOTIFY_NOT_SUPPORT_WARN = 2 /* Driver report not support but it might still work */ +} SYNO_SFP_UNSUPPORTED_NOTIFY_TYPE; +#endif /* MY_ABC_HERE */ + + +#ifdef MY_ABC_HERE +#define SD_IOCTL_IDLE 4746 +#define SD_IOCTL_SUPPORT_SLEEP 4747 +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +#define SD_IOCTL_SASHOST_DISK_LED 4755 +#endif /* MY_DEF_HERE */ + +/* + * FIXME: The following legacy definitions are referred by userspace projects, + * but do not depend on any kernel configs. They should be moved to a proper + * project such as synoplatformconfig. + */ +#ifndef __KERNEL__ +#define SYNO_EA +#endif /* __KERNEL__ */ + +/** + * Dsc: USB copy support + * use port number 99 to indicate USBCOPY port + */ +#ifdef MY_DEF_HERE +#define USBCOPY_PORT_LOCATION 99 +#endif /* MY_DEF_HERE */ + +#endif /* _UAPI_LINUX_SYNO_H */ diff --git a/include/uapi/linux/syno_acl.h b/include/uapi/linux/syno_acl.h new file mode 100644 index 000000000000..a70c57657d54 --- /dev/null +++ b/include/uapi/linux/syno_acl.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifndef _UAPI_LINUX_SYNO_ACL_H +#define _UAPI_LINUX_SYNO_ACL_H + +#include + +#define SYNO_ACL_MNT_OPT "synoacl" +#define SYNO_ACL_NOT_MNT_OPT "no"SYNO_ACL_MNT_OPT + +/* Extended attribute names */ +#define SYNO_ACL_XATTR_ACCESS "system.syno_acl_self" +#define SYNO_ACL_XATTR_INHERIT "system.syno_acl_inherit" +#define SYNO_ACL_XATTR_PSEUDO_INHERIT_ONLY "system.syno_acl_pseudo_inherit_only" + +/* MAC EA Exttend attribute names */ +#define SYNO_XATTR_EA_PREFIX "user.syno." +#define SYNO_XATTR_EA_PREFIX_LEN (sizeof(SYNO_XATTR_EA_PREFIX) - 1) +#define SYNO_XATTR_NETATALK_PREFIX "user.netatalk." +#define SYNO_XATTR_NETATALK_PREFIX_LEN (sizeof(SYNO_XATTR_NETATALK_PREFIX) - 1) + +/* Supported ACL a_version fields */ +#define SYNO_ACL_XATTR_VERSION 0x0001 + +/* An undefined entry e_id value */ +#define SYNO_ACL_UNDEFINED_ID -1 + +/* Permissions in the e_perm field + *Note* It should be consistent with MAY_XXXXX in + Define it since MAY_XXXX conflict with user space program +*/ +#define SYNO_ACL_MAY_EXEC 0x0001 +#define SYNO_ACL_MAY_WRITE 0x0002 +#define SYNO_ACL_MAY_READ 0x0004 +#define SYNO_ACL_MAY_APPEND 0x0008 +#define SYNO_ACL_MAY_ACCESS 0x0010 +#define SYNO_ACL_MAY_OPEN 0x0020 +#define SYNO_ACL_MAY_READ_EXT_ATTR 0x0040 +#define SYNO_ACL_MAY_READ_PERMISSION 0x0080 +#define SYNO_ACL_MAY_READ_ATTR 0x0100 +#define SYNO_ACL_MAY_WRITE_ATTR 0x0200 +#define SYNO_ACL_MAY_WRITE_EXT_ATTR 0x0400 +#define SYNO_ACL_MAY_WRITE_PERMISSION 0x0800 +#define SYNO_ACL_MAY_DEL 0x1000 +#define SYNO_ACL_MAY_DEL_CHILD 0x2000 +#define SYNO_ACL_MAY_GET_OWNER_SHIP 0x4000 + +/* Classify permission type */ +#define SYNO_PERM_READABLE \ + (SYNO_ACL_MAY_READ | SYNO_ACL_MAY_READ_ATTR | \ + SYNO_ACL_MAY_READ_PERMISSION | SYNO_ACL_MAY_READ_EXT_ATTR) + +#define SYNO_PERM_WRITE_DATA \ + (SYNO_ACL_MAY_WRITE | SYNO_ACL_MAY_APPEND | SYNO_ACL_MAY_DEL_CHILD) + +#define SYNO_PERM_WRITABLE \ + (SYNO_PERM_WRITE_DATA | SYNO_ACL_MAY_WRITE_ATTR | \ + SYNO_ACL_MAY_WRITE_EXT_ATTR) + +#define SYNO_PERM_OWNER \ + (SYNO_ACL_MAY_READ_PERMISSION | SYNO_ACL_MAY_WRITE_PERMISSION | \ + SYNO_ACL_MAY_GET_OWNER_SHIP) + +#define SYNO_PERM_FULL_CONTROL \ + (SYNO_ACL_MAY_EXEC | SYNO_PERM_READABLE | SYNO_PERM_WRITABLE | \ + SYNO_ACL_MAY_WRITE_PERMISSION | SYNO_ACL_MAY_GET_OWNER_SHIP | \ + SYNO_ACL_MAY_DEL) + +/* inherit mode in the e_inherit field */ +#define SYNO_ACL_INHERIT_ONLY 0x0001 +#define SYNO_ACL_INHERIT_FILE 0x0002 +#define SYNO_ACL_INHERIT_DIR 0x0004 +#define SYNO_ACL_INHERIT_NO_PROPOGATE 0x0008 + +#define SYNO_ACL_INHERIT_TYPE \ + (SYNO_ACL_INHERIT_ONLY | SYNO_ACL_INHERIT_FILE | SYNO_ACL_INHERIT_DIR) + +#define SYNO_ACL_INHERIT_ALL \ + (SYNO_ACL_INHERIT_ONLY | SYNO_ACL_INHERIT_FILE | \ + SYNO_ACL_INHERIT_DIR | SYNO_ACL_INHERIT_NO_PROPOGATE) + +#define IS_INHERIT_ONE_LEVEL(x) ((SYNO_ACL_INHERIT_NO_PROPOGATE & (x)) && ((SYNO_ACL_INHERIT_FILE|SYNO_ACL_INHERIT_DIR) & (x))) +#define IS_INHERIT_ONLY(x) (SYNO_ACL_INHERIT_ONLY & (x)) +#define IS_MATCH_FILE_TYPE(isdir, x) ((isdir) ? (SYNO_ACL_INHERIT_DIR & (x)):(SYNO_ACL_INHERIT_FILE & (x))) + +#define SYNO_ACL_XATTR_TAG_IS_DENY 0X0001 +#define SYNO_ACL_XATTR_TAG_IS_ALLOW 0X0002 +#define SYNO_ACL_XATTR_TAG_ALLOW_ALL \ + (SYNO_ACL_XATTR_TAG_IS_DENY | SYNO_ACL_XATTR_TAG_IS_ALLOW) + +#define SYNO_ACL_XATTR_TAG_ID_USER 0X0004 +#define SYNO_ACL_XATTR_TAG_ID_GROUP 0X0008 +#define SYNO_ACL_XATTR_TAG_ID_EVERYONE 0X0010 +#define SYNO_ACL_XATTR_TAG_ID_OWNER 0X0020 +#define SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER 0X0040 +#define SYNO_ACL_XATTR_TAG_ID_SYSTEM 0X0080 +#define SYNO_ACL_XATTR_TAG_ID_ALL \ + (SYNO_ACL_XATTR_TAG_ID_USER | SYNO_ACL_XATTR_TAG_ID_GROUP | \ + SYNO_ACL_XATTR_TAG_ID_EVERYONE | SYNO_ACL_XATTR_TAG_ID_OWNER | \ + SYNO_ACL_XATTR_TAG_ID_AUTHENTICATEDUSER | \ + SYNO_ACL_XATTR_TAG_ID_SYSTEM) + +enum { + SYNO_KERNEL_IS_FS_SUPPORT = 1, // File System + SYNO_KERNEL_IS_FILE_SUPPORT, // File or Dir +}; + +enum { + SYNO_ACL_INHERITED = 1, // Includes self-defined and inherited ACL. + SYNO_ACL_PSEUDO_INHERIT_ONLY, // Includes only inherited ACE, even entry has no inherited attribute. +}; + + +/* + * these two structs should be packed because btrfs-send will transfer raw xattr + * data including `syno_acl_xattr_{entry,header}` via syno_acl_to_xattr(). + */ +typedef struct { + __le16 e_tag; + __le16 e_unused1; + __le32 e_perm; + __le16 e_inherit; + __le16 e_unused2; + __le32 e_id; + __le32 e_level; +} __attribute__((__packed__)) syno_acl_xattr_entry; + +typedef struct { + __le16 a_version; + __le16 a_unused; + syno_acl_xattr_entry a_entries[0]; +} __attribute__((__packed__)) syno_acl_xattr_header; + +static inline size_t syno_acl_xattr_size(int count) +{ + return (sizeof(syno_acl_xattr_header) + + (count * sizeof(syno_acl_xattr_entry))); +} + +static inline int syno_acl_xattr_count(size_t size) +{ + if (size < sizeof(syno_acl_xattr_header)) + return -1; + + size -= sizeof(syno_acl_xattr_header); + if (size % sizeof(syno_acl_xattr_entry)) + return -1; + + return size / sizeof(syno_acl_xattr_entry); +} + +#endif /* _UAPI_LINUX_SYNO_ACL_H */ diff --git a/include/uapi/linux/syno_acl_xattr_ds.h b/include/uapi/linux/syno_acl_xattr_ds.h new file mode 100644 index 000000000000..b772217d1cc9 --- /dev/null +++ b/include/uapi/linux/syno_acl_xattr_ds.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#ifndef _UAPI_LINUX_SYNO_ACL_XATTR_DS_H +#define _UAPI_LINUX_SYNO_ACL_XATTR_DS_H + +/* Provided for userspace backward compatiblity. */ + +#include + +#endif /* _UAPI_LINUX_SYNO_ACL_XATTR_DS_H */ diff --git a/include/uapi/linux/synobios.h b/include/uapi/linux/synobios.h new file mode 100644 index 000000000000..1c4781c02f69 --- /dev/null +++ b/include/uapi/linux/synobios.h @@ -0,0 +1,585 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2000-2022 Synology Inc. All rights reserved. +#ifndef _UAPI_LINUX_SYNOBIOS_H +#define _UAPI_LINUX_SYNOBIOS_H + +#define HW_DS107e "DS107e" +#define HW_DS107v10 "DS107v10" +#define HW_DS107v20 "DS107v20" +#define HW_DS107v30 "DS107v30" +#define HW_DS207 "DS207" //"DS207v10" +#define HW_DS406 "DS406" //"DS406v10" "DS406v20" +#define HW_DS407ev10 "DS407ev10" //"DS407ev10" +#define HW_DS407v10 "DS407v10" //"DS407v10" +#define HW_DS407v20 "DS407v20" //"DS407v20" +#define HW_RS408 "RS408" //"RS408" +#define HW_RS408rp "RS408rp" //"RS408rp" +#define HW_RS409p "RS409p" //"RS409p" +#define HW_RS409rpp "RS409rpp" //"RS409rpp" +#define HW_DS408 "DS408" //"DS408" +#define HW_DS409p "DS409p" //"DS409p" +#define HW_DS409pv20 "DS409pv20" //"DS409pv20" +#define HW_DS508 "DS508" //"DS508" +#define HW_DS509p "DS509p" //"DS509p" +#define HW_DS209p "DS209p" //"DS209p" +#define HW_DS209pII "DS209pII" //"DS209pII" +#define HW_DS209pIIr1 "DS209pIIr1" //"DS209pIIr1" +#define HW_DS108jv10 "DS108jv10" //"DS108jv10" +#define HW_DS108jv20 "DS108jv20" //"DS108jv20" +#define HW_DS109j "DS109jv10" //"DS109jv10" +#define HW_DS209j "DS209jv10" //"DS209jv10" +#define HW_DS109 "DS109" //"DS109" +#define HW_DS209 "DS209" //"DS209" +#define HW_DS409slim "DS409slim" //"DS409slim" +#define HW_DS409 "DS409" //"DS409" +#define HW_RS409v10 "RS409v10" //"RS409v10" +#define HW_RS409v20 "RS409v20" //"RS409v20" +#define HW_DS109p "DS109p" //"DS109p" +#define HW_DS410j "DS410j" //"DS410j" +#define HW_DS210jv10 "DS210jv10" //"DS210jv10" +#define HW_DS210jv20 "DS210jv20" //"DS210jv20" +#define HW_DS210jv30 "DS210jv30" //"DS210jv30" +#define HW_DS110jv10 "DS110jv10" //"DS110jv10" +#define HW_DS110jv20 "DS110jv20" //"DS110jv20" +#define HW_DS110jv30 "DS110jv30" //"DS110jv30" +#define HW_DS710p "DS710+" //"DS710+" +#define HW_DS712pv10 "DS712+" //"DS712+" +#define HW_DS712pv20 "DS712+v20" //"DS712+v20" +#define HW_DS1010p "DS1010+" //"DS1010+" +#define HW_DS110p "DS110p" //"DS110+" +#define HW_DS210p "DS210p" //"DS210+" +#define HW_DS410 "DS410" //"DS410" +#define HW_DS411p "DS411+" //"DS411+" +#define HW_DS411pII "DS411+II" //"DS411+II" +#define HW_RS810p "RS810+" //"RS810+" +#define HW_RS810rpp "RS810rp+" //"RS810rp+" +#define HW_DS211j "DS211j" //"DS211j" +#define HW_DS411j "DS411j" //"DS411j" +#define HW_DS211 "DS211" //"DS211" +#define HW_DS111 "DS111" //"DS111" +#define HW_DS411slim "DS411slim" //"DS411slim" +#define HW_DS411 "DS411" //"DS411" +#define HW_DS1511p "DS1511+" //"DS1511+" +#define HW_DS211pv10 "DS211pv10" //"DS211+" +#define HW_DS211pv20 "DS211pv20" //"DS211+" +#define HW_RS411 "RS411" //"RS411" +#define HW_RS2211p "RS2211+" //"RS2211+" +#define HW_RS2211rpp "RS2211rp+" //"RS2211rp+" +#define HW_DS2411p "DS2411+" //"DS2411+" +#define HW_RS3411rpxs "RS3411rpxs" //"RS3411rpxs" +#define HW_RS3411xs "RS3411xs" //"RS3411xs" +#define HW_RS10613xsp "RS10613xs+" //"RS10613xs+" +#define HW_DS3611xs "DS3611xs" //"DS3611xs" +#define HW_RS3412rpxs "RS3412rpxs" //"RS3412rpxs" +#define HW_RS3412xs "RS3412xs" //"RS3412xs" +#define HW_DS3612xs "DS3612xs" //"DS3612xs" +#define HW_DS3615xs "DS3615xs" //"DS3615xs" +#define HW_RS3413xsp "RS3413xs+" //"RS3413xs+" +#define HW_RS3614xs "RS3614xs" //"RS3614xs" +#define HW_RS3614rpxs "RS3614rpxs" //"RS3614rpxs" +#define HW_RS3614xsp "RS3614xs+" //"RS3614xs+" +#define HW_ES3614xsp "ES3614xs+" //"ES3614xs+" +#define HW_DS2414xs "DS2414xs" //"DS2414xs" +#define HW_DS111j "DS111j" //"DS111j" +#define HW_DS212 "DS212" //"DS212v10" +#define HW_DS413 "DS413" //"DS413" +#define HW_DS412p "DS412+" //"DS412+" +#define HW_DS713p "DS713+" //"DS713+" +#define HW_RS812p "RS812+" //"RS812+" +#define HW_RS812rpp "RS812rp+" //"RS812rp+" +#define HW_DS1812p "DS1812+" //"DS1812+" +#define HW_DS1813p "DS1813+" //"DS1813+" +#define HW_RS2212p "RS2212+" //"RS2212+" +#define HW_RS2212rpp "RS2212rp+" //"RS2212rp+" +#define HW_RS2414p "RS2414+" //"RS2414+" +#define HW_RS2414rpp "RS2414rp+" //"RS2414rp+" +#define HW_DS2413p "DS2413+" //"DS2413+" +#define HW_DS2415p "DS2415+" //"DS2415+" +#define HW_RS212 "RS212" //"RS212" +#define HW_DS212jv10 "DS212j" //"DS212j" +#define HW_DS212jv20 "DS212jv20" //"DS212j" +#define HW_RS812 "RS812" //"RS812" +#define HW_DS1512p "DS1512+" //"DS1512+" +#define HW_DS1513p "DS1513+" //"DS1513+" +#define HW_DS212pv10 "DS212pv10" //"DS212+" +#define HW_DS212pv20 "DS212pv20" //"DS212+" +#define HW_DS112j "DS112jv10" //"DS112j" +#define HW_DS112 "DS112v10" //"DS112" +#define HW_DS112pv10 "DS112pv10" //"DS112+" +#define HW_DS112slim "DS112slim" //"DS112slim" +#define HW_DS413jv10 "DS413jv10" //"DS413jv10" +#define HW_DS414jv10 "DS414jv10" //"DS414jv10" +#define HW_DS415jv10 "DS415jv10" //"DS415jv10" +#define HW_DS215airv10 "DS215airv10" //"DS215airv10" +#define HW_DS213pv10 "DS213pv10" //"DS213pv10" +#define HW_DS213airv10 "DS213airv10" //"DS213airv10" +#define HW_DS213v10 "DS213v10" //"DS213v10" +#define HW_NVR614v10 "NVR614v10" //"NVR614v10" +#define HW_VS240hdv10 "VS240hdv10" //"VS240hdv10" +#define HW_RS813 "RS813v10" //"RS813v10" +#define HW_RS213p "RS213pv10" //"RS213pv10" +#define HW_DS213jv10 "DS213jv10" //"DS213jv10" +#define HW_US3v10 "US3v10" //"US3v10" +#define HW_DS114v10 "DS114v10" //"DS114v10" +#define HW_RS214v10 "RS214v10" //"RS214v10" +#define HW_DS214v10 "DS214v10" //"DS214v10" +#define HW_DS214p "DS214+" +#define HW_DS214se "DS214se" //DS214se +#define HW_DS414v10 "DS414v10" +#define HW_RS814v10 "RS814v10" +#define HW_DS114p "DS114+" //"DS114+" +#define HW_RC18015xsp "RC18015xs+" //"RC18015xs+" +#define HW_RS18016xsp "RS18016xs+" //"RS18016xs+" +#define HW_RR36015xsppp "RR36015xs+++" //"RR36015xs+++" +#define HW_VirtualDSM "VirtualDSM" //"VirtualDSM" +#define HW_RS18016Dxsp "RS18016Dxs+" //"RS18016Dxs+" +#define HW_DS714v10 "DS714v10" +#define HW_RS814p "RS814+" //"RS814+" +#define HW_RS814rpp "RS814rp+" //"RS814rp+" +#define HW_DS214play "DS214play" +#define HW_DS415play "DS415play" //"DS415play" +#define HW_DS414slim "DS414slim" //DS414slim +#define HW_DS2015xs "DS2015xs" +#define HW_DS115j "DS115j" +#define HW_RS3415xsp "RS3415xs+" //"RS3415xs+" +#define HW_DS415p "DS415+" //"DS415+" +#define HW_DS1815p "DS1815+" //"DS1815+" +#define HW_DS1515p "DS1515+" //"DS1515+" +#define HW_DS215j "DS215j" +#define HW_DS115 "DS115" +#define HW_RS815p "RS815+" //"RS815+" +#define HW_RS815rpp "RS815rp+" //"RS815rp+" +#define HW_DS215router "DS215router" //"DS215router" +#define HW_RS815 "RS815" //"RS815" +#define HW_DS1515 "DS1515" +#define HW_DS715 "DS715" +#define HW_DS215p "DS215+" +#define HW_DS416 "DS416" +#define HW_RS2416p "RS2416+" //"RS2416+" +#define HW_RS2416rpp "RS2416rp+" //"RS2416rp+" +#define HW_DS216play "DS216play" +#define HW_DS216se "DS216se" //DS216se +#define HW_DS916p "DS916+" //DS916+ +#define HW_DS716p "DS716+" //DS716+ +#define HW_DS716pII "DS716+II" //DS716+II +#define HW_RSD18016xsp "RSD18016xs+" //"RSD18016xs+" +#define HW_DockerDSM "DockerDSM" //"DockerDSM" +#define HW_DS1616p "DS1616+" //"DS1616+" +#define HW_RS3618xs "RS3618xs" //"RS3618xs" +#define HW_RS3617rpxs "RS3617rpxs" //"RS3617rpxs" +#define HW_RS3617xsp "RS3617xs+" //"RS3617xs+" +#define HW_DS416j "DS416j" //DS416j +#define HW_DS216 "DS216" //DS216 +#define HW_DS416slim "DS416slim" //DS416slim +#define HW_DS216p "DS216+" //"DS216+" +#define HW_DS216pII "DS216+II" //"DS216+II" +#define HW_DS216j "DS216j" //"DS216j" +#define HW_RS816 "RS816" //"RS816" +#define HW_DS116 "DS116" //"DS116" +#define HW_DS416play "DS416play" //"DS416play" +#define HW_RS217 "RS217" //"RS217" +#define HW_FS3017 "FS3017" //"FS3017" +#define HW_RS3617xs "RS3617xs" //"RS3617xs" +#define HW_RS2418p "RS2418+" //"RS2418+" +#define HW_RS2418rpp "RS2418rp+" //"RS2418rp+" +#define HW_DS918p "DS918+" //DS918+ +#define HW_RS4017xsp "RS4017xs+" //"RS4017xs+" +#define HW_DS3617xs "DS3617xs" //"DS3617xs" +#define HW_RS18017xsp "RS18017xs+" //"RS18017xs+" +#define HW_DS218p "DS218+" //DS218+ +#define HW_DS1618p "DS1618+" //"DS1618+" +#define HW_C2DSM "C2DSM" //"C2DSM" +#define HW_DS1517p "DS1517+" //"DS1517+" +#define HW_DS1817p "DS1817+" //"DS1817+" +#define HW_DS718p "DS718+" //DS718+ +#define HW_FS2017 "FS2017" //"FS2017" +#define HW_DS418j "DS418j" //"DS418j" +#define HW_DS418 "DS418" //"DS418" +#define HW_DS218play "DS218play" //"DS218play" +#define HW_DS118 "DS118" //"DS118" +#define HW_DS218 "DS218" //"DS218" +#define HW_EDS19 "EDS19" //"EDS19" +#define HW_RS819 "RS819" //"RS819" +#define HW_DS220j "DS220j" //"DS220j" +#define HW_DS420j "DS420j" //"DS420j" +#define HW_DS3017xs "DS3017xs" //"DS3017xs" +#define HW_DS3018xs "DS3018xs" //"DS3018xs" +#define HW_FS1018 "FS1018" //"FS1018" +#define HW_FS6400 "FS6400" //"FS6400" +#define HW_RS818p "RS818+" //"RS818+" +#define HW_RS818rpp "RS818rp+" //"RS818rp+" +#define HW_DS418play "DS418play" //DS418play +#define HW_RS2818rpp "RS2818rp+" //RS2818rp+ +#define HW_DS219j "DS219j" //"DS219j" +#define HW_DS219se "DS219se" //"DS219se" +#define HW_DS3619xs "DS3619xs" //"DS3619xs" +#define HW_DS119j "DS119j" //"DS119j" +#define HW_DS120j "DS120j" //"DS120j" +#define HW_TAIPEI "TAIPEI" //"TAIPEI" +#define HW_RS1619xsp "RS1619xs+" //"RS1619xs+" +#define HW_DS2419p "DS2419+" //"DS2419+" +#define HW_DS419p "DS419+" //"DS419+" +#define HW_DS1019p "DS1019+" //"DS1019+" +#define HW_DS719p "DS719+" //"DS719+" +#define HW_DS1819p "DS1819+" //"DS1819+" +#define HW_DS620slim "DS620slim" //"DS620slim" +#define HW_RS419p "RS419+" //"RS419+" +#define HW_DVA3219 "DVA3219" //"DVA3219" +#define HW_SA3400 "SA3400" //"SA3400" +#define HW_SA3410 "SA3410" //"SA3410" +#define HW_SA3600 "SA3600" //"SA3600" +#define HW_SA3610 "SA3610" //"SA3610" +#define HW_DS420p "DS420+" //DS420+ +#define HW_DS720p "DS720+" //DS720+ +#define HW_DS220p "DS220+" //DS220+ +#define HW_RS820p "RS820+" //"RS820+" +#define HW_RS820rpp "RS820rp+" //"RS820rp+" +#define HW_FS3400 "FS3400" //"FS3400" +#define HW_FS3600 "FS3600" //"FS3600" +#define HW_HD3400 "HD3400" //"HD3400" +#define HW_DS1520p "DS1520+" //"DS1520+" +#define HW_DS220play "DS220play" //"DS220play" +#define HW_DS220 "DS220" //"DS220" +#define HW_RS1220p "RS1220+" //"RS1220+" +#define HW_RS1220rpp "RS1220rp+" //"RS1220rp+" +#define HW_DS1621xsp "DS1621xs+" //"DS1621xs+" +#define HW_DS920p "DS920+" //"DS920+" +#define HW_SA6500 "SA6500" //"SA6500" +#define HW_DS1621p "DS1621+" //"DS1621+" +#define HW_HD6500 "HD6500" //"HD6500" +#define HW_SA3200d "SA3200d" //"SA3200d" +#define HW_SA3400d "SA3400d" //"SA3400d" +#define HW_DVA3221 "DVA3221" //"DVA3221" +#define HW_AliDSM "AliDSM" //"AliDSM" +#define HW_RS1221p "RS1221+" //"RS1221+" +#define HW_RS1221rpp "RS1221rp+" //"RS1221rp+" +#define HW_DS1821p "DS1821+" //"DS1821+" +#define HW_DS2422p "DS2422+" //"DS2422+ +#define HW_RS2421p "RS2421+" //"RS2421+" +#define HW_RS2421rpp "RS2421rp+" //"RS2421rp+" +#define HW_RS2821rpp "RS2821rp+" //"RS2821rp+" +#define HW_FS6600N "FS6600N" //"FS6600N" +#define HW_RS3621xsp "RS3621xs+" //"RS3621xs+" +#define HW_RS3621rpxs "RS3621rpxs" //"RS3621rpxs" +#define HW_RS4021xsp "RS4021xs+" //"RS4021xs+" +#define HW_FS6500 "FS6500" //"FS6500" +#define HW_DS3617xsII "DS3617xsII" //"DS3617xsII" +#define HW_DS3622xsp "DS3622xs+" //"DS3622xs+" +#define HW_DS2419pII "DS2419+II" //"DS2419+II" +#define HW_FS2500 "FS2500" //"FS2500" +#define HW_FS2500T "FS2500T" //"FS2500T" +#define HW_R1 "r1" //"r1" for revision +#define HW_R2 "r2" //"r2" for revision +#define HW_DVA1622 "DVA1622" //"DVA1622" +#define HW_DS223j "DS223j" //"DS223j" +#define HW_DS1522p "DS1522+" //"DS1522+" +#define HW_FS3410 "FS3410" //"FS3410" +#define HW_DS723p "DS723+" //"DS723+" +#define HW_DS923p "DS923+" //"DS923+" +#define HW_RS422p "RS422+" //"RS422+" +#define HW_DS423 "DS423" //"DS423" +#define HW_RS4023xsp "RS4023xs+" //"RS4023xs+" +#define HW_FS6400N "FS6400N" //"FS6400N" +#define HW_FS6410 "FS6410" //"FS6410" +#define HW_SA6400 "SA6400" //"SA6400" +#define HW_SA6200 "SA6200" //"SA6200" +#define HW_SC6200 "SC6200" //"SC6200" +#define HW_DS223 "DS223" //"DS223" +#define HW_RS822p "RS822+" //"RS822+" +#define HW_RS822rpp "RS822rp+" //"RS822rp+" +#define HW_RS2423p "RS2423+" //"RS2423+" +#define HW_RS2423rpp "RS2423rp+" //"RS2423rp+" +#define HW_DS1823xsp "DS1823xs+" //"DS1823xs+" +#define HW_RS1623xsp "RS1623xs+" //"RS1623xs+" +#define HW_DS423p "DS423+" //"DS423+" +#define HW_DS124 "DS124" //"DS124" +#define HW_DS224p "DS224+" //DS224+ +#define HW_RS4024xsp "RS4024xs+" //"RS4024xs+" +#define HW_FS6600DN "FS6600DN" //"FS6600DN" +#define HW_DS1623p "DS1623+" //"DS1623+" +#define HW_DS1823p "DS1823+" //"DS1823+" +#define HW_SC2500 "SC2500" //"SC2500" +#define HW_UNKNOWN "DSUnknown" + +#define EBOX_INFO_UNIQUE_RX410 "RX410" +#define EBOX_INFO_UNIQUE_RX413 "RX413" +#define EBOX_INFO_UNIQUE_DX510 "DX510" +#define EBOX_INFO_UNIQUE_DX513 "DX513" +#define EBOX_INFO_UNIQUE_RX4 "RX4" +#define EBOX_INFO_UNIQUE_DX5 "DX5" +#define EBOX_INFO_UNIQUE_RXC "RX1211" +#define EBOX_INFO_UNIQUE_DXC "DX1211" +#define EBOX_INFO_UNIQUE_RXCRP "RX1211rp" +#define EBOX_INFO_UNIQUE_RX1214 "RX1214" +#define EBOX_INFO_UNIQUE_RX1217 "RX1217" +#define EBOX_INFO_UNIQUE_RX1214RP "RX1214rp" +#define EBOX_INFO_UNIQUE_RX1217RP "RX1217rp" +#define EBOX_INFO_UNIQUE_DX213 "DX213" +#define EBOX_INFO_UNIQUE_RX415 "RX415" +#define EBOX_INFO_UNIQUE_DX1215 "DX1215" +#define EBOX_INFO_UNIQUE_DX1215II "DX1215II" +#define EBOX_INFO_UNIQUE_DX517 "DX517" +#define EBOX_INFO_UNIQUE_RX418 "RX418" +#define EBOX_INFO_UNIQUE_DX1222 "DX1222" +#define EBOX_INFO_UNIQUE_RX1223RP "RX1223rp" +#define EBOX_INFO_UNIQUE_RX1224RP "RX1224rp" + +#define SYNO_UNIQUE(x) (x>>2) +#define IS_SYNOLOGY_RX4(x) (SYNO_UNIQUE(x) == 0x15 || SYNO_UNIQUE(x) == 0xd) // 0x54 ~ 0x57 +#define IS_SYNOLOGY_RX410(x) (SYNO_UNIQUE(x) == 0xd) // 0x34 ~ 0x37 +#define IS_SYNOLOGY_DX5(x) (SYNO_UNIQUE(x) == 0xa || SYNO_UNIQUE(x) == 0x1a) // 0x28 ~ 0x2b +#define IS_SYNOLOGY_DX510(x) (SYNO_UNIQUE(x) == 0x1a) // 0x68 ~ 0x6b +#define IS_SYNOLOGY_DX513(x) (SYNO_UNIQUE(x) == 0x6) // 0x18 ~ 0x1b +#define IS_SYNOLOGY_DXC(x) (SYNO_UNIQUE(x) == 0x13) // 0x4c ~ 0x4f +#define IS_SYNOLOGY_RXC(x) (SYNO_UNIQUE(x) == 0xb) // 0x2c ~ 0x2f +#define IS_SYNOLOGY_DX213(x) (SYNO_UNIQUE(x) == 0x16) // 0x58 ~ 0x5b +#define IS_SYNOLOGY_RX413(x) (x == 0x11) // This model is obsoleted +#define IS_SYNOLOGY_RX1214(x) (x == 0x12) +#define IS_SYNOLOGY_RX1217(x) (x == 0x14) +#define IS_SYNOLOGY_RX415(x) (SYNO_UNIQUE(x) == 0x1d) // 0x54 ~ 0x57 +#define IS_SYNOLOGY_DX1215(x) (x == 0x13) +#define IS_SYNOLOGY_DX517(x) (x == 0x15) +#define IS_SYNOLOGY_RX418(x) (x == 0x16) +#define IS_SYNOLOGY_DX1222(x) (x == 0x17) +#define IS_SYNOLOGY_DX1215II(x) (x == 0x1C) +#define IS_SYNOLOGY_RX1223RP(x) (x == 0x01) +#define SYNOLOGY_RX1224RP_UNIQUE 0x02 +#define IS_SYNOLOGY_RX1224RP(x) (x == SYNOLOGY_RX1224RP_UNIQUE) +#define SYNO_HEX 0x53796E6F //Syno +#define LOGY_HEX 0x6C6F6779 //logy +#define IS_SYNOLOGY_M2DXX(x) (0) + +#define SYNO_EBOX_UNIQUE_MAX_LEN 16 + +struct syno_ebox_unique_id { + int uniqueId; + int mask; + char szUnique[SYNO_EBOX_UNIQUE_MAX_LEN]; + char szUniqueRp[SYNO_EBOX_UNIQUE_MAX_LEN]; +}; + +static const struct syno_ebox_unique_id syno_ebox_unique_mapping[] = { + {0x34, 0x7c, EBOX_INFO_UNIQUE_RX410, EBOX_INFO_UNIQUE_RX410}, // RX410, 0x34 ~ 0x37 + {0x54, 0x7c, EBOX_INFO_UNIQUE_RX4, EBOX_INFO_UNIQUE_RX4}, // RX4, 0x54 ~ 0x57 + {0x18, 0x7c, EBOX_INFO_UNIQUE_DX513, EBOX_INFO_UNIQUE_DX513}, // DX513, 0x18 ~ 0x1b + {0x68, 0x7c, EBOX_INFO_UNIQUE_DX510, EBOX_INFO_UNIQUE_DX510}, // DX510, 0x68 ~ 0x6b + {0x28, 0x7c, EBOX_INFO_UNIQUE_DX5, EBOX_INFO_UNIQUE_DX5}, // DX5, 0x28 ~ 0x2b + {0x4c, 0x7c, EBOX_INFO_UNIQUE_DXC, EBOX_INFO_UNIQUE_DXC}, // DXC, 0x4c ~ 0x4f + {0x2c, 0x7c, EBOX_INFO_UNIQUE_RXC, EBOX_INFO_UNIQUE_RXCRP}, // RXC or RXCRP, 0x2c ~ 0x2f + {0x58, 0x7c, EBOX_INFO_UNIQUE_DX213, EBOX_INFO_UNIQUE_DX213}, // DX213, 0x58 ~ 0x5b + {0x11, 0x1f, EBOX_INFO_UNIQUE_RX413, EBOX_INFO_UNIQUE_RX413}, // RX413, 0x11 + {0x12, 0x1f, EBOX_INFO_UNIQUE_RX1214, EBOX_INFO_UNIQUE_RX1214RP}, // RX1214 or RX1214RP, 0x12 + {0x14, 0x1f, EBOX_INFO_UNIQUE_RX1217, EBOX_INFO_UNIQUE_RX1217RP}, // RX1217 or RX1217RP, 0x14 + {0x54, 0x7c, EBOX_INFO_UNIQUE_RX415, EBOX_INFO_UNIQUE_RX415}, // RX415, 0x54 ~ 0x57 + {0x13, 0x1f, EBOX_INFO_UNIQUE_DX1215, EBOX_INFO_UNIQUE_DX1215}, // DX1215, 0x13 + {0x15, 0x1f, EBOX_INFO_UNIQUE_DX517, EBOX_INFO_UNIQUE_DX517}, // DX517, 0x15 + {0x16, 0x1f, EBOX_INFO_UNIQUE_RX418, EBOX_INFO_UNIQUE_RX418}, // RX418, 0x16 + {0x17, 0x1f, EBOX_INFO_UNIQUE_DX1222, EBOX_INFO_UNIQUE_DX1222}, // DX1222, 0x17 + {0x1C, 0x1f, EBOX_INFO_UNIQUE_DX1215II, EBOX_INFO_UNIQUE_DX1215II}, // DX1215II, 0x1C + {0x01, 0x1f, EBOX_INFO_UNIQUE_RX1223RP, EBOX_INFO_UNIQUE_RX1223RP}, // RX1223RP, 0x01 + + { }, /* terminate list */ +}; + + + +#define HWMON_CPU_TEMP_NAME "CPU_Temperature" +#define HWMON_SYS_THERMAL_NAME "System_Thermal_Sensor" +#define HWMON_SYS_VOLTAGE_NAME "System_Voltage_Sensor" +#define HWMON_SYS_FAN_RPM_NAME "System_Fan_Speed_RPM" +#define HWMON_SYS_CURRENT_NAME "System_Current_Sensor" +#define HWMON_SYS_FAN1_RPM "fan1_rpm" +#define HWMON_SYS_FAN2_RPM "fan2_rpm" +#define HWMON_SYS_FAN3_RPM "fan3_rpm" +#define HWMON_SYS_FAN4_RPM "fan4_rpm" +#define HWMON_PSU_STATUS_NAME "PSU_%d_Status" +#define HWMON_PSU1_STATUS_NAME "PSU_1_Status" +#define HWMON_PSU2_STATUS_NAME "PSU_2_Status" +#define HWMON_PSU_SENSOR_PIN "power_in" +#define HWMON_PSU_SENSOR_POUT "power_out" +#define HWMON_PSU_SENSOR_TEMP "temperature" +#define HWMON_PSU_SENSOR_TEMP1 "temperature_1" +#define HWMON_PSU_SENSOR_TEMP2 "temperature_2" +#define HWMON_PSU_SENSOR_TEMP3 "temperature_3" +#define HWMON_PSU_SENSOR_FAN "fan_speed" +#define HWMON_PSU_SENSOR_FAN_VOLT "fan_voltage" +#define HWMON_PSU_SENSOR_STATUS "status" +#define HWMON_HDD_BP_STATUS_NAME "HDD_Backplane_Status" +#define HWMON_HDD_BP_DETECT "hdd_detect" +#define HWMON_HDD_BP_ENABLE "hdd_enable" +#define HWMON_HDD_BP_INTF "hdd_intf" +#define MAX_SENSOR_NUM 10 +#define MAX_SENSOR_NAME 30 +#define MAX_SENSOR_VALUE 30 + +typedef enum _tag_EUNIT_PWRON_TYPE { + EUNIT_NOT_SUPPORT, + EUNIT_PWRON_GPIO, + EUNIT_PWRON_ATACMD, + EUNIT_SAS_NO_PWRON, +} EUNIT_PWRON_TYPE; + +typedef enum { + CAPABILITY_THERMAL = 1, + CAPABILITY_DISK_LED_CTRL= 2, + CAPABILITY_AUTO_POWERON = 3, + CAPABILITY_CPU_TEMP = 4, + CAPABILITY_S_LED_BREATH = 5, + CAPABILITY_FAN_RPM_RPT = 6, + CAPABILITY_MICROP_PWM = 7, + CAPABILITY_CARDREADER = 8, + CAPABILITY_LCM = 9, + CAPABILITY_NONE = -1, +} SYNO_HW_CAPABILITY; + +typedef struct _tag_CAPABILITY { + SYNO_HW_CAPABILITY id; + int support; +} CAPABILITY; + +typedef enum { + DISK_LED_OFF = 0, + DISK_LED_GREEN_SOLID, + DISK_LED_ORANGE_SOLID, + DISK_LED_ORANGE_BLINK, + DISK_LED_GREEN_BLINK, +} SYNO_DISK_LED; + +typedef struct _tag_SYNO_SUPERIO_PACKAGE{ + unsigned char ldn; + unsigned char reg; + unsigned char value; +} SYNO_SUPERIO_PACKAGE; + +typedef enum { + EUP_FULLY_SUPPORT = 0, + EUP_NOT_FULLY_SUPPORT, + EUP_NOT_SUPPORT, +} SYNO_EUP_SUPPORT; + +#define MAX_CPU 2 +typedef struct _SynoCpuTemp { + unsigned char blSurface; + int cpu_num; + int cpu_temp[MAX_CPU]; +} SYNOCPUTEMP; + +typedef struct _SynoThermalTemp { + unsigned char blSurface; + int temperature; +} SYNO_THERMAL_TEMP; + +typedef enum { + HWMON_CPU_TEMP, + HWMON_SYS_THERMAL, + HWMON_SYS_VOLTAGE, + HWMON_FAN_SPEED_RPM, + HWMON_HDD_BACKPLANE, + HWMON_PSU_STATUS, + HWMON_SYS_CURRENT, +} SYNO_HWMON_SUPPORT_ID; + +typedef struct _SYNO_HWMON_SUPPORT { + SYNO_HWMON_SUPPORT_ID id; + int support; +} SYNO_HWMON_SUPPORT; + +typedef struct _SYNO_HWMON_SENSOR { + char sensor_name[MAX_SENSOR_NAME]; + char value[MAX_SENSOR_VALUE]; +} SYNO_HWMON_SENSOR; + +typedef struct _SYNO_HWMON_SENSOR_TYPE { + char type_name[MAX_SENSOR_NAME]; + int sensor_num; + SYNO_HWMON_SENSOR sensor[MAX_SENSOR_NUM]; +} SYNO_HWMON_SENSOR_TYPE; + +typedef struct _SYNO_HWMON_FAN_ORDER { + int fan_num; + int fan_order_list[MAX_SENSOR_NUM]; +} SYNO_HWMON_FAN_ORDER; + +enum { + MD_SECTOR_READ_ERROR = 0, + MD_SECTOR_WRITE_ERROR = 1, + MD_SECTOR_REWRITE_OK = 2, + MD_FAULTY_DEVICE = 3, +}; + +typedef enum { + SYNO_SCSI_UNKNOWN = 0, + SYNO_SCSI_ERROR_WITH_SENSE, + SYNO_SCSI_ERROR_TIMEOUT, +} SYNO_SCSI_ERROR_EVENT_TYPE; + +typedef enum { + SYNO_LED_OFF = 0, + SYNO_LED_ON, + SYNO_LED_BLINKING, +} SYNO_LED; + +/* TODO: Because user space also need this define, so we define them here. + * But userspace didn't have a common define like MY_DEF_HERE include + * kernel space. So we can't define it inside some define */ +#define EBOX_GPIO_KEY "gpio" +#define EBOX_I2C_KEY "i2c" +#define EBOX_I2C_POLLING_FAN "fanTach" +#define EBOX_I2C_SYSFS_OP_WRITE "Write" +#define EBOX_I2C_SYSFS_OP_READ "Read" +#define EBOX_I2C_SYSFS_OP_POLL "Poll" +#define EBOX_I2C_SYSFS_OP_JMB575_LED_CTL "JMB575_LED_Ctrl" +#define EBOX_INFO_DEV_LIST_KEY "syno_device_list" +#define EBOX_INFO_VENDOR_KEY "vendorid" +#define EBOX_INFO_DEVICE_KEY "deviceid" +#define EBOX_INFO_ERROR_HANDLE "error_handle" +#define EBOX_INFO_UNIQUE_KEY "Unique" +#define EBOX_INFO_EMID_KEY "EMID" +#define EBOX_INFO_SATAHOST_KEY "sata_host" +#define EBOX_INFO_PORTNO_KEY "port_no" +#define EBOX_INFO_PCIEPATH_KEY "pciepath" +#define EBOX_INFO_CPLDVER_KEY "cpld_version" +#define EBOX_INFO_DEEP_SLEEP "deepsleep_support" +#define EBOX_INFO_IRQ_OFF "irq_off" +#define EBOX_INFO_PHY_KEY "phy" /* for mv14xx */ + +/* Use 'K' as magic number */ +#define SYNOBIOS_IOC_MAGIC 'K' + +#define SYNOIO_GET_EUNIT_TYPE _IOR(SYNOBIOS_IOC_MAGIC, 41, EUNIT_PWRON_TYPE) +#define SYNOIO_SUPERIO_READ _IOWR(SYNOBIOS_IOC_MAGIC, 216, SYNO_SUPERIO_PACKAGE) +#define SYNOIO_SUPERIO_WRITE _IOWR(SYNOBIOS_IOC_MAGIC, 217, SYNO_SUPERIO_PACKAGE) +#define SYNOIO_IS_FULLY_SUPPORT_EUP _IOWR(SYNOBIOS_IOC_MAGIC, 218, SYNO_EUP_SUPPORT) + +#ifdef MY_ABC_HERE +extern int syno_is_hw_version(const char *hw_version); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int syno_is_hw_revision(const char *hw_revision); +#endif /* MY_ABC_HERE */ + +#define SYNO_MICROP_TTY_NAME "ttyS1" + +#ifdef MY_ABC_HERE +extern int (*func_synobios_event_handler)(unsigned long long, ...); +#endif /* MY_ABC_HERE */ + +#define SYNO_EVENT_USB_PROHIBIT 0x1b00 +#define SYNO_EVENT_CONSOLE_PROHIBIT 0x1c00 +#define SYNO_EVENT_MICROP_GET 0x1d00 +#define SYNO_EVENT_DISK_PWR_RESET 0x2700 +#define SYNO_EVENT_DISK_PORT_DISABLED 0x2800 +#define SYNO_EVENT_SATA_ERROR_REPORT 0x2a00 +#define SYNO_EVENT_WAKE_FROM_DEEP_SLEEP 0x2b00 +#define SYNO_EVENT_DISK_RETRY_REPORT 0x2c00 +#define SYNO_EVENT_DSIK_POWER_SHORT_BREAK 0x2e00 +#define SYNO_EVENT_DISK_TIMEOUT_REPORT 0x3000 +#define SYNO_EVENT_DISK_RESET_FAIL_REPORT 0x3100 +#define SYNO_EVENT_DISK_PORT_LOST 0x3200 +#define SYNO_EVENT_SCSI_ERROR 0x3300 +#define SYNO_EVENT_EBOX_RESET 0x3400 + +#endif /* _UAPI_LINUX_SYNOBIOS_H */ diff --git a/include/uapi/linux/synotify.h b/include/uapi/linux/synotify.h new file mode 100644 index 000000000000..cca5fb024291 --- /dev/null +++ b/include/uapi/linux/synotify.h @@ -0,0 +1,75 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#ifndef _UAPI_LINUX_SYNOTIFY_H +#define _UAPI_LINUX_SYNOTIFY_H + +#ifdef MY_ABC_HERE +#include + +/* the following events that user-space can register for */ +// Note: The following event bit mask should match FS_XXX +#define SYNO_ACCESS 0x00000001 /* File was accessed */ +#define SYNO_MODIFY 0x00000002 /* File was modified */ +#define SYNO_ATTRIB 0x00000004 /* File was modified */ +#define SYNO_CLOSE_WRITE 0x00000008 /* Writtable file closed */ +#define SYNO_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ +#define SYNO_OPEN 0x00000020 /* File was opened */ +#define SYNO_MOVE_FROM 0x00000040 /* File was opened */ +#define SYNO_MOVE_TO 0x00000080 /* File was opened */ +#define SYNO_CREATE 0x00000100 /* File was opened */ +#define SYNO_DELETE 0x00000200 /* File was opened */ +#define SYNO_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ +#define SYNO_ONDIR 0x40000000 /* event occurred against dir */ + +/* flags used for synotify_init() */ +#define SYNO_CLOEXEC 0x00000001 +#define SYNO_NONBLOCK 0x00000002 +#define SYNO_EVENT_V2 0x00000004 + +/* flags used for synotify_add_watch() */ +#define SYNO_DONT_FOLLOW 0x01000000 /* don't follow a sym link */ + +#define SYNO_ALL_EVENTS (SYNO_ACCESS | \ + SYNO_MODIFY | \ + SYNO_ATTRIB | \ + SYNO_CLOSE_WRITE | \ + SYNO_CLOSE_NOWRITE | \ + SYNO_OPEN | \ + SYNO_MOVE_FROM | \ + SYNO_MOVE_TO | \ + SYNO_CREATE | \ + SYNO_DELETE | \ + SYNO_Q_OVERFLOW | \ + SYNO_ONDIR) +/* + * struct synotify_event - structure read from the inotify device for each event + * + * When you are watching a directory, you will receive the filename for events + * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ... + */ +struct synotify_event { + __u32 mask; /* watch mask */ + __u32 cookie; /* cookie to synchronize two events */ + __u32 len; /* length (including nulls) of name (full path, actually) */ + char name[0]; /* stub for possible name (full path, actually) */ +}; + +struct synotify_event_v2 { + // v1 event + __u32 mask; /* watch mask */ + __u32 cookie; /* cookie to synchronize two events */ + __u32 len; /* length (including nulls) of name (full path, actually) */ + + // v2 event + __u32 pid; + __u32 uid; + + // v3 event, must be before name[0] + // future new members... + + char name[0]; /* stub for possible name (full path, actually) */ +}; +#endif /* MY_ABC_HERE */ + +#endif /* _UAPI_LINUX_SYNOTIFY_H */ diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h index 458179df9b27..89bd51004f9f 100644 --- a/include/uapi/linux/sysctl.h +++ b/include/uapi/linux/sysctl.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * sysctl.h: General linux system control interface @@ -79,6 +82,14 @@ enum INOTIFY_MAX_QUEUED_EVENTS=3 /* max queued events per instance */ }; +#ifdef MY_ABC_HERE +/* /proc/sys/fs/synotify/ */ +enum +{ + SYNOTIFY_MAX_QUEUED_EVENTS=1 /* max queued events per instance */ +}; +#endif /* MY_ABC_HERE */ + /* CTL_KERN names: */ enum { @@ -806,6 +817,9 @@ enum FS_AIO_NR=18, /* current system-wide number of aio requests */ FS_AIO_MAX_NR=19, /* system-wide maximum number of aio requests */ FS_INOTIFY=20, /* inotify submenu */ +#ifdef MY_ABC_HERE + FS_SYNOTIFY=900, /* synotify submenu */ +#endif /* MY_ABC_HERE */ FS_OCFS2=988, /* ocfs2 */ }; diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index d67cadf221fc..ee5e6ea51a9a 100644 --- a/include/uapi/linux/tee.h +++ b/include/uapi/linux/tee.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Copyright (c) 2015-2016, Linaro Limited * All rights reserved. @@ -363,6 +366,37 @@ struct tee_iocl_supp_send_arg { #define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ struct tee_ioctl_buf_data) +#if defined(MY_DEF_HERE) +/** + * struct tee_ioctl_shm_register_fd_data - Shared memory registering argument + * @fd: [in] file descriptor identifying the shared memory + * @size: [out] Size of shared memory to allocate + * @flags: [in] Flags to/from allocation. + * @id: [out] Identifier of the shared memory + * + * The flags field should currently be zero as input. Updated by the call + * with actual flags as defined by TEE_IOCTL_SHM_* above. + * This structure is used as argument for TEE_IOC_SHM_ALLOC below. + */ +struct tee_ioctl_shm_register_fd_data { + __s64 fd; + __u64 size; + __u32 flags; + __s32 id; +} __aligned(8); + +/** + * TEE_IOC_SHM_REGISTER_FD - register a shared memory from a file descriptor + * + * Returns a file descriptor on success or < 0 on failure + * + * The returned file descriptor refers to the shared memory object in kernel + * land. The shared memory is freed when the descriptor is closed. + */ +#define TEE_IOC_SHM_REGISTER_FD _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 8, \ + struct tee_ioctl_shm_register_fd_data) + +#endif /* MY_DEF_HERE */ /** * struct tee_ioctl_shm_register_data - Shared memory register argument * @addr: [in] Start address of shared memory to register diff --git a/include/uapi/linux/usb/f_mtp.h b/include/uapi/linux/usb/f_mtp.h new file mode 100644 index 000000000000..6704d0dcc266 --- /dev/null +++ b/include/uapi/linux/usb/f_mtp.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Gadget Function Driver for MTP + * + * Copyright (C) 2010 Google, Inc. + * Author: Mike Lockwood + * + */ + +#ifndef _UAPI_LINUX_USB_F_MTP_H +#define _UAPI_LINUX_USB_F_MTP_H + +#include +#include + +struct mtp_file_range { + /* file descriptor for file to transfer */ + int fd; + /* offset in file for start of transfer */ + loff_t offset; + /* number of bytes to transfer */ + int64_t length; + /* MTP command ID for data header, + * used only for MTP_SEND_FILE_WITH_HEADER + */ + uint16_t command; + /* MTP transaction ID for data header, + * used only for MTP_SEND_FILE_WITH_HEADER + */ + uint32_t transaction_id; +}; + +struct mtp_event { + /* size of the event */ + size_t length; + /* event data to send */ + void *data; +}; + +/* Sends the specified file range to the host */ +#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range) +/* Receives data from the host and writes it to a file. + * The file is created if it does not exist. + */ +#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range) +/* Sends an event to the host via the interrupt endpoint */ +#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event) +/* Sends the specified file range to the host, + * with a 12 byte MTP data packet header at the beginning. + */ +#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range) + +#endif /* _UAPI_LINUX_USB_F_MTP_H */ diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h index 9463db2dfa9d..3d8b277a45e1 100644 --- a/include/uapi/linux/xattr.h +++ b/include/uapi/linux/xattr.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* File: linux/xattr.h @@ -26,7 +29,11 @@ #define XATTR_OS2_PREFIX "os2." #define XATTR_OS2_PREFIX_LEN (sizeof(XATTR_OS2_PREFIX) - 1) +#ifdef MY_ABC_HERE +#define XATTR_MAC_OSX_PREFIX "" +#else /* MY_ABC_HERE */ #define XATTR_MAC_OSX_PREFIX "osx." +#endif /* MY_ABC_HERE */ #define XATTR_MAC_OSX_PREFIX_LEN (sizeof(XATTR_MAC_OSX_PREFIX) - 1) #define XATTR_BTRFS_PREFIX "btrfs." @@ -47,6 +54,41 @@ #define XATTR_USER_PREFIX "user." #define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) +#ifdef MY_ABC_HERE +#define XATTR_SYNO_PREFIX "syno." +#define XATTR_SYNO_PREFIX_LEN (sizeof(XATTR_SYNO_PREFIX) - 1) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define XATTR_SYNO_ARCHIVE_BIT_SUFFIX "archive_bit" +#define XATTR_SYNO_ARCHIVE_BIT_SUFFIX_LEN (sizeof(XATTR_SYNO_ARCHIVE_BIT_SUFFIX) - 1) +#define XATTR_SYNO_ARCHIVE_BIT XATTR_SYNO_PREFIX XATTR_SYNO_ARCHIVE_BIT_SUFFIX +#define XATTR_SYNO_ARCHIVE_BIT_LEN (XATTR_SYNO_PREFIX_LEN + XATTR_SYNO_ARCHIVE_BIT_SUFFIX_LEN) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define XATTR_SYNO_ARCHIVE_VERSION_SUFFIX "archive_version" +#define XATTR_SYNO_ARCHIVE_VERSION_SUFFIX_LEN (sizeof(XATTR_SYNO_ARCHIVE_VERSION_SUFFIX) - 1) +#define XATTR_SYNO_ARCHIVE_VERSION XATTR_SYNO_PREFIX XATTR_SYNO_ARCHIVE_VERSION_SUFFIX +#define XATTR_SYNO_ARCHIVE_VERSION_LEN (XATTR_SYNO_PREFIX_LEN + XATTR_SYNO_ARCHIVE_VERSION_SUFFIX_LEN) +#define XATTR_SYNO_ARCHIVE_VERSION_VOLUME_SUFFIX "archive_version_volume" +#define XATTR_SYNO_ARCHIVE_VERSION_VOLUME_SUFFIX_LEN (sizeof(XATTR_SYNO_ARCHIVE_VERSION_VOLUME_SUFFIX) - 1) +#define XATTR_SYNO_ARCHIVE_VERSION_VOLUME XATTR_SYNO_PREFIX XATTR_SYNO_ARCHIVE_VERSION_VOLUME_SUFFIX +#define XATTR_SYNO_ARCHIVE_VERSION_VOLUME_LEN (XATTR_SYNO_PREFIX_LEN + XATTR_SYNO_ARCHIVE_VERSION_VOLUME_SUFFIX_LEN) +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define XATTR_SYNO_CREATE_TIME_SUFFIX "create_time" +#define XATTR_SYNO_CREATE_TIME XATTR_SYNO_PREFIX XATTR_SYNO_CREATE_TIME_SUFFIX +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#define XATTR_SYNO_LOCKER_SUFFIX "w" +#define XATTR_SYNO_LOCKER_SUFFIX_LEN (sizeof(XATTR_SYNO_LOCKER_SUFFIX) - 1) +#define XATTR_SYNO_LOCKER (XATTR_SYNO_PREFIX XATTR_SYNO_LOCKER_SUFFIX) +#define XATTR_SYNO_LOCKER_LEN (sizeof(XATTR_SYNO_LOCKER) - 1) +#endif /* MY_ABC_HERE */ + /* Security namespace */ #define XATTR_EVM_SUFFIX "evm" #define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h index 65b9db936557..a5184e0e421a 100644 --- a/include/uapi/mtd/mtd-abi.h +++ b/include/uapi/mtd/mtd-abi.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Copyright © 1999-2010 David Woodhouse et al. @@ -91,6 +94,19 @@ struct mtd_write_req { __u8 padding[7]; }; +#ifdef MY_DEF_HERE +struct SYNO_MTD_FIS_INFO { + unsigned char name[16]; // Null terminated name + u_int32_t offset; + u_int32_t size; + u_int32_t data_length; +}; + +#define SYNO_MSYS_FLASH_BLOCK_SIZE ( 16 * 1024 ) +#define SYNO_MSYS_PARTITION_NUMBER 8 +#define SYNO_MSYS_TOTAL_UNITS 967 +#endif /* MY_DEF_HERE */ + #define MTD_ABSENT 0 #define MTD_RAM 1 #define MTD_ROM 2 @@ -195,10 +211,21 @@ struct otp_info { #define MEMERASE64 _IOW('M', 20, struct erase_info_user64) /* Write data to OOB (64-bit version) */ #define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64) +#ifdef MY_DEF_HERE +#define MEMMODIFYPARTINFO _IOW('M', 22, struct erase_info_user) +#define MEMMODIFYFISINFO _IOW('M', 23, struct SYNO_MTD_FIS_INFO) +#define MSYSMEMFORMAT _IOW('M', 24, int) +#define MSYSMEMPARTITION _IOW('M', 25, int*) +#define MSYSMEMPARTITIONINFO _IOR('M', 26, int*) +#define MEMREADOOB64 _IOWR('M', 27, struct mtd_oob_buf64) +#define MEMISLOCKED _IOR('M', 28, struct erase_info_user) +#else /* MY_DEF_HERE */ /* Read data from OOB (64-bit version) */ #define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64) /* Check if chip is locked (for MTD that supports it) */ #define MEMISLOCKED _IOR('M', 23, struct erase_info_user) +#endif /* MY_DEF_HERE */ + /* * Most generic write interface; can write in-band and/or out-of-band in various * modes (see "struct mtd_write_req"). This ioctl is not supported for flashes diff --git a/init/Kconfig b/init/Kconfig index fc4c9f416fad..f7c7be4e48f1 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -429,7 +429,7 @@ config HAVE_ARCH_AUDITSYSCALL config AUDITSYSCALL def_bool y - depends on AUDIT && HAVE_ARCH_AUDITSYSCALL + depends on AUDIT && HAVE_ARCH_AUDITSYSCALL && !SYNO_DISABLE_AUDITSYSCALL select FSNOTIFY source "kernel/irq/Kconfig" @@ -2047,6 +2047,8 @@ endmenu # General setup source "arch/Kconfig" +source "synology/synoconfigs/Kconfig" + config RT_MUTEXES bool diff --git a/init/do_mounts.c b/init/do_mounts.c index b5f9604d0c98..18d7425c0c09 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only #include #include @@ -318,7 +321,11 @@ EXPORT_SYMBOL_GPL(name_to_dev_t); static int __init root_dev_setup(char *line) { +#ifdef MY_DEF_HERE + strlcpy(saved_root_name, "/dev/sata1p1", sizeof(saved_root_name)); +#else strlcpy(saved_root_name, line, sizeof(saved_root_name)); +#endif return 1; } diff --git a/init/initramfs.c b/init/initramfs.c index 55b74d7e5260..0faddba12acb 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -14,6 +14,11 @@ #include #include +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK +#include +bool ramdisk_check_failed; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + static ssize_t __init xwrite(struct file *file, const char *p, size_t count, loff_t *pos) { @@ -499,6 +504,14 @@ static char * __init unpack_to_rootfs(char *buf, unsigned long len) error("invalid magic at start of compressed archive"); if (state != Reset) error("junk at the end of compressed archive"); + +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + if (my_inptr == 0) { + printk(KERN_INFO "decompress cpio completed and skip redundant lzma\n"); + break; + } +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + this_header = saved_offset + my_inptr; buf += my_inptr; len -= my_inptr; @@ -604,11 +617,33 @@ static void __init populate_initrd_image(char *err) static int __init populate_rootfs(void) { +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + const char *ctx = "synology"; + size_t rd_len = initrd_end - initrd_start - hydro_sign_BYTES; + uint8_t sig[hydro_sign_BYTES]; + + uint8_t pk[] = { + __RAMDISK_SIGN_PUBLIC_KEY__ + }; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + /* Load the built in initramfs */ char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size); if (err) panic("%s", err); /* Failed to decompress INTERNAL initramfs */ +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + memcpy(sig, (const void *) (initrd_start + rd_len), hydro_sign_BYTES); + + if (hydro_sign_verify(sig, (const void *) initrd_start, rd_len, ctx, pk)) { + ramdisk_check_failed = true; + printk(KERN_ERR "ramdisk corrupt"); + } else { + ramdisk_check_failed = false; + initrd_end -= hydro_sign_BYTES; + } +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE)) goto done; diff --git a/kernel/Makefile b/kernel/Makefile index e7905bdf6e97..b74a6b8d0e86 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,10 +12,13 @@ obj-y = fork.o exec_domain.o panic.o \ notifier.o ksysfs.o cred.o reboot.o \ async.o range.o smpboot.o ucount.o regset.o +obj-$(CONFIG_SYNO_BOOT_ARGUMENTS) += syno_bootargs.o obj-$(CONFIG_USERMODE_DRIVER) += usermode_driver.o obj-$(CONFIG_MODULES) += kmod.o obj-$(CONFIG_MULTIUSER) += groups.o +obj-$(CONFIG_SYNO_KWORK_STAT) += workstat.o + ifdef CONFIG_FUNCTION_TRACER # Do not trace internal ftrace files CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 75c2d184018a..d12efb2550d3 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -32,6 +32,8 @@ #include #include #include + +#include #include /* Registers */ @@ -1380,6 +1382,7 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) /* Non-UAPI available opcodes. */ [BPF_JMP | BPF_CALL_ARGS] = &&JMP_CALL_ARGS, [BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL, + [BPF_ST | BPF_NOSPEC] = &&ST_NOSPEC, [BPF_LDX | BPF_PROBE_MEM | BPF_B] = &&LDX_PROBE_MEM_B, [BPF_LDX | BPF_PROBE_MEM | BPF_H] = &&LDX_PROBE_MEM_H, [BPF_LDX | BPF_PROBE_MEM | BPF_W] = &&LDX_PROBE_MEM_W, @@ -1624,7 +1627,21 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) COND_JMP(s, JSGE, >=) COND_JMP(s, JSLE, <=) #undef COND_JMP - /* STX and ST and LDX*/ + /* ST, STX and LDX*/ + ST_NOSPEC: + /* Speculation barrier for mitigating Speculative Store Bypass. + * In case of arm64, we rely on the firmware mitigation as + * controlled via the ssbd kernel parameter. Whenever the + * mitigation is enabled, it works for all of the kernel code + * with no need to provide any additional instructions here. + * In case of x86, we use 'lfence' insn for mitigation. We + * reuse preexisting logic from Spectre v1 mitigation that + * happens to produce the required code on x86 for v4 as well. + */ +#ifdef CONFIG_X86 + barrier_nospec(); +#endif + CONT; #define LDST(SIZEOP, SIZE) \ STX_MEM_##SIZEOP: \ *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \ diff --git a/kernel/bpf/disasm.c b/kernel/bpf/disasm.c index b44d8c447afd..ff1dd7d45b58 100644 --- a/kernel/bpf/disasm.c +++ b/kernel/bpf/disasm.c @@ -162,15 +162,17 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, else verbose(cbs->private_data, "BUG_%02x\n", insn->code); } else if (class == BPF_ST) { - if (BPF_MODE(insn->code) != BPF_MEM) { + if (BPF_MODE(insn->code) == BPF_MEM) { + verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, + insn->off, insn->imm); + } else if (BPF_MODE(insn->code) == 0xc0 /* BPF_NOSPEC, no UAPI */) { + verbose(cbs->private_data, "(%02x) nospec\n", insn->code); + } else { verbose(cbs->private_data, "BUG_st_%02x\n", insn->code); - return; } - verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n", - insn->code, - bpf_ldst_string[BPF_SIZE(insn->code) >> 3], - insn->dst_reg, - insn->off, insn->imm); } else if (class == BPF_LDX) { if (BPF_MODE(insn->code) != BPF_MEM) { verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 36bc34fce623..883309be15b0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2297,6 +2297,19 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, cur = env->cur_state->frame[env->cur_state->curframe]; if (value_regno >= 0) reg = &cur->regs[value_regno]; + if (!env->bypass_spec_v4) { + bool sanitize = reg && is_spillable_regtype(reg->type); + + for (i = 0; i < size; i++) { + if (state->stack[spi].slot_type[i] == STACK_INVALID) { + sanitize = true; + break; + } + } + + if (sanitize) + env->insn_aux_data[insn_idx].sanitize_stack_spill = true; + } if (reg && size == BPF_REG_SIZE && register_is_bounded(reg) && !register_is_null(reg) && env->bpf_capable) { @@ -2319,47 +2332,10 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, verbose(env, "invalid size of register spill\n"); return -EACCES; } - if (state != cur && reg->type == PTR_TO_STACK) { verbose(env, "cannot spill pointers to stack into stack frame of the caller\n"); return -EINVAL; } - - if (!env->bypass_spec_v4) { - bool sanitize = false; - - if (state->stack[spi].slot_type[0] == STACK_SPILL && - register_is_const(&state->stack[spi].spilled_ptr)) - sanitize = true; - for (i = 0; i < BPF_REG_SIZE; i++) - if (state->stack[spi].slot_type[i] == STACK_MISC) { - sanitize = true; - break; - } - if (sanitize) { - int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off; - int soff = (-spi - 1) * BPF_REG_SIZE; - - /* detected reuse of integer stack slot with a pointer - * which means either llvm is reusing stack slot or - * an attacker is trying to exploit CVE-2018-3639 - * (speculative store bypass) - * Have to sanitize that slot with preemptive - * store of zero. - */ - if (*poff && *poff != soff) { - /* disallow programs where single insn stores - * into two different stack slots, since verifier - * cannot sanitize them - */ - verbose(env, - "insn %d cannot access two stack slots fp%d and fp%d", - insn_idx, *poff, soff); - return -EINVAL; - } - *poff = soff; - } - } save_register_state(state, spi, reg); } else { u8 type = STACK_MISC; @@ -5284,8 +5260,7 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, struct bpf_insn_aux_data *aux = &env->insn_aux_data[insn_idx]; struct bpf_reg_state *regs = cur_regs(env), *reg; struct bpf_map *map = meta->map_ptr; - struct tnum range; - u64 val; + u64 val, max; int err; if (func_id != BPF_FUNC_tail_call) @@ -5295,10 +5270,11 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, return -EINVAL; } - range = tnum_range(0, map->max_entries - 1); reg = ®s[BPF_REG_3]; + val = reg->var_off.value; + max = map->max_entries; - if (!register_is_const(reg) || !tnum_in(range, reg->var_off)) { + if (!(register_is_const(reg) && val < max)) { bpf_map_key_store(aux, BPF_MAP_KEY_POISON); return 0; } @@ -5306,8 +5282,6 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, err = mark_chain_precision(env, BPF_REG_3); if (err) return err; - - val = reg->var_off.value; if (bpf_map_key_unseen(aux)) bpf_map_key_store(aux, val); else if (!bpf_map_key_poisoned(aux) && @@ -10947,35 +10921,33 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) for (i = 0; i < insn_cnt; i++, insn++) { bpf_convert_ctx_access_t convert_ctx_access; + bool ctx_access; if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) || insn->code == (BPF_LDX | BPF_MEM | BPF_H) || insn->code == (BPF_LDX | BPF_MEM | BPF_W) || - insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) + insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) { type = BPF_READ; - else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) || - insn->code == (BPF_STX | BPF_MEM | BPF_H) || - insn->code == (BPF_STX | BPF_MEM | BPF_W) || - insn->code == (BPF_STX | BPF_MEM | BPF_DW)) + ctx_access = true; + } else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) || + insn->code == (BPF_STX | BPF_MEM | BPF_H) || + insn->code == (BPF_STX | BPF_MEM | BPF_W) || + insn->code == (BPF_STX | BPF_MEM | BPF_DW) || + insn->code == (BPF_ST | BPF_MEM | BPF_B) || + insn->code == (BPF_ST | BPF_MEM | BPF_H) || + insn->code == (BPF_ST | BPF_MEM | BPF_W) || + insn->code == (BPF_ST | BPF_MEM | BPF_DW)) { type = BPF_WRITE; - else + ctx_access = BPF_CLASS(insn->code) == BPF_STX; + } else { continue; + } if (type == BPF_WRITE && - env->insn_aux_data[i + delta].sanitize_stack_off) { + env->insn_aux_data[i + delta].sanitize_stack_spill) { struct bpf_insn patch[] = { - /* Sanitize suspicious stack slot with zero. - * There are no memory dependencies for this store, - * since it's only using frame pointer and immediate - * constant of zero - */ - BPF_ST_MEM(BPF_DW, BPF_REG_FP, - env->insn_aux_data[i + delta].sanitize_stack_off, - 0), - /* the original STX instruction will immediately - * overwrite the same stack slot with appropriate value - */ *insn, + BPF_ST_NOSPEC(), }; cnt = ARRAY_SIZE(patch); @@ -10989,6 +10961,9 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) continue; } + if (!ctx_access) + continue; + switch (env->insn_aux_data[i + delta].ptr_type) { case PTR_TO_CTX: if (!ops->convert_ctx_access) diff --git a/kernel/cpu.c b/kernel/cpu.c index 67c22941b5f2..e3e7c4e1a573 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* CPU control. * (C) 2001, 2002, 2003, 2004 Rusty Russell * @@ -2573,8 +2576,13 @@ enum cpu_mitigations { CPU_MITIGATIONS_AUTO_NOSMT, }; +#ifdef MY_ABC_HERE +static enum cpu_mitigations cpu_mitigations __ro_after_init = + CPU_MITIGATIONS_OFF; +#else /* MY_ABC_HERE */ static enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO; +#endif /* MY_ABC_HERE */ static int __init mitigations_parse_cmdline(char *arg) { @@ -2599,6 +2607,15 @@ bool cpu_mitigations_off(void) } EXPORT_SYMBOL_GPL(cpu_mitigations_off); +#ifdef MY_ABC_HERE +/* mitigations=auto */ +void cpu_mitigations_auto_set(void) +{ + cpu_mitigations = CPU_MITIGATIONS_AUTO; +} +EXPORT_SYMBOL(cpu_mitigations_auto_set); +#endif /* MY_ABC_HERE */ + /* mitigations=auto,nosmt */ bool cpu_mitigations_auto_nosmt(void) { diff --git a/kernel/cred.c b/kernel/cred.c index 098213d4a39c..421b1149c651 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -60,7 +60,6 @@ struct cred init_cred = { .user = INIT_USER, .user_ns = &init_user_ns, .group_info = &init_groups, - .ucounts = &init_ucounts, }; static inline void set_cred_subscribers(struct cred *cred, int n) @@ -120,8 +119,6 @@ static void put_cred_rcu(struct rcu_head *rcu) if (cred->group_info) put_group_info(cred->group_info); free_uid(cred->user); - if (cred->ucounts) - put_ucounts(cred->ucounts); put_user_ns(cred->user_ns); kmem_cache_free(cred_jar, cred); } @@ -225,7 +222,6 @@ struct cred *cred_alloc_blank(void) #ifdef CONFIG_DEBUG_CREDENTIALS new->magic = CRED_MAGIC; #endif - new->ucounts = get_ucounts(&init_ucounts); if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0) goto error; @@ -288,11 +284,6 @@ struct cred *prepare_creds(void) if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0) goto error; - - new->ucounts = get_ucounts(new->ucounts); - if (!new->ucounts) - goto error; - validate_creds(new); return new; @@ -372,9 +363,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ret = create_user_ns(new); if (ret < 0) goto error_put; - ret = set_cred_ucounts(new); - if (ret < 0) - goto error_put; } #ifdef CONFIG_KEYS @@ -665,31 +653,6 @@ int cred_fscmp(const struct cred *a, const struct cred *b) } EXPORT_SYMBOL(cred_fscmp); -int set_cred_ucounts(struct cred *new) -{ - struct task_struct *task = current; - const struct cred *old = task->real_cred; - struct ucounts *old_ucounts = new->ucounts; - - if (new->user == old->user && new->user_ns == old->user_ns) - return 0; - - /* - * This optimization is needed because alloc_ucounts() uses locks - * for table lookups. - */ - if (old_ucounts && old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid)) - return 0; - - if (!(new->ucounts = alloc_ucounts(new->user_ns, new->euid))) - return -EAGAIN; - - if (old_ucounts) - put_ucounts(old_ucounts); - - return 0; -} - /* * initialise the credentials stuff */ @@ -756,10 +719,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0) goto error; - new->ucounts = get_ucounts(new->ucounts); - if (!new->ucounts) - goto error; - put_cred(old); validate_creds(new); return new; diff --git a/kernel/events/core.c b/kernel/events/core.c index 7e0fdc19043e..9c748631526f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -11875,6 +11875,9 @@ SYSCALL_DEFINE5(perf_event_open, * Do not allow to attach to a group in a different task * or CPU context. If we're moving SW events, we'll fix * this up later, so allow that. + * + * Racy, not holding group_leader->ctx->mutex, see comment with + * perf_event_ctx_lock(). */ if (!move_group && group_leader->ctx != ctx) goto err_context; @@ -11942,6 +11945,7 @@ SYSCALL_DEFINE5(perf_event_open, } else { perf_event_ctx_unlock(group_leader, gctx); move_group = 0; + goto not_move_group; } } @@ -11958,7 +11962,17 @@ SYSCALL_DEFINE5(perf_event_open, } } else { mutex_lock(&ctx->mutex); + + /* + * Now that we hold ctx->lock, (re)validate group_leader->ctx == ctx, + * see the group_leader && !move_group test earlier. + */ + if (group_leader && group_leader->ctx != ctx) { + err = -EINVAL; + goto err_locked; + } } +not_move_group: if (ctx->task == TASK_TOMBSTONE) { err = -ESRCH; diff --git a/kernel/fork.c b/kernel/fork.c index 096945ef49ad..0e7235216d08 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/kernel/fork.c @@ -554,7 +557,11 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, struct inode *inode = file_inode(file); struct address_space *mapping = file->f_mapping; +#ifdef MY_ABC_HERE + vma_get_file(tmp); +#else get_file(file); +#endif /* MY_ABC_HERE */ if (tmp->vm_flags & VM_DENYWRITE) put_write_access(inode); i_mmap_lock_write(mapping); @@ -1988,7 +1995,14 @@ static __latent_entropy struct task_struct *copy_process( */ retval = -EAGAIN; if (data_race(nr_threads >= max_threads)) +#ifdef MY_ABC_HERE + { + pr_err_ratelimited("fork over limit, threads-max = %d", max_threads); goto bad_fork_cleanup_count; + } +#else /* MY_ABC_HERE */ + goto bad_fork_cleanup_count; +#endif /* MY_ABC_HERE */ delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER | PF_IDLE); @@ -2027,6 +2041,10 @@ static __latent_entropy struct task_struct *copy_process( p->psi_flags = 0; #endif +#ifdef MY_ABC_HERE + p->workacct = NULL; +#endif + task_io_accounting_init(&p->ioac); acct_clear_integrals(p); @@ -2960,12 +2978,6 @@ int ksys_unshare(unsigned long unshare_flags) if (err) goto bad_unshare_cleanup_cred; - if (new_cred) { - err = set_cred_ucounts(new_cred); - if (err) - goto bad_unshare_cleanup_cred; - } - if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { if (do_sysvsem) { /* diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 396ebaebea3f..b5d068174878 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Detect Hung Task @@ -48,7 +51,13 @@ unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_ */ unsigned long __read_mostly sysctl_hung_task_check_interval_secs; +#ifdef MY_ABC_HERE +int __read_mostly sysctl_hung_task_warnings_default = CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS; +int __read_mostly sysctl_hung_task_warnings = CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS; +int __read_mostly sysctl_hung_task_warnings_reset_period = CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD; +#else /* MY_ABC_HERE */ int __read_mostly sysctl_hung_task_warnings = 10; +#endif /* MY_ABC_HERE */ static int __read_mostly did_panic; static bool hung_task_show_lock; @@ -84,6 +93,16 @@ static struct notifier_block panic_block = { .notifier_call = hung_task_panic, }; +#ifdef MY_ABC_HERE +static void hung_task_warnings_reset(struct timer_list *unused); +static DEFINE_TIMER(reset_warnings_timer, hung_task_warnings_reset); +static void hung_task_warnings_reset(struct timer_list *unused) +{ + sysctl_hung_task_warnings = sysctl_hung_task_warnings_default; + mod_timer(&reset_warnings_timer, jiffies + HZ * sysctl_hung_task_warnings_reset_period * 60); +} +#endif /* MY_ABC_HERE */ + static void check_hung_task(struct task_struct *t, unsigned long timeout) { unsigned long switch_count = t->nvcsw + t->nivcsw; @@ -310,6 +329,10 @@ static int __init hung_task_init(void) watchdog_task = kthread_run(watchdog, NULL, "khungtaskd"); +#ifdef MY_ABC_HERE + mod_timer(&reset_warnings_timer, jiffies + HZ * sysctl_hung_task_warnings_reset_period * 60); +#endif /* MY_ABC_HERE */ + return 0; } subsys_initcall(hung_task_init); diff --git a/kernel/kthread.c b/kernel/kthread.c index 9825cf89c614..508fe5278285 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -84,6 +84,25 @@ static inline struct kthread *to_kthread(struct task_struct *k) return (__force void *)k->set_child_tid; } +/* + * Variant of to_kthread() that doesn't assume @p is a kthread. + * + * Per construction; when: + * + * (p->flags & PF_KTHREAD) && p->set_child_tid + * + * the task is both a kthread and struct kthread is persistent. However + * PF_KTHREAD on it's own is not, kernel_thread() can exec() (See umh.c and + * begin_new_exec()). + */ +static inline struct kthread *__to_kthread(struct task_struct *p) +{ + void *kthread = (__force void *)p->set_child_tid; + if (kthread && !(p->flags & PF_KTHREAD)) + kthread = NULL; + return kthread; +} + void free_kthread_struct(struct task_struct *k) { struct kthread *kthread; @@ -168,8 +187,9 @@ EXPORT_SYMBOL_GPL(kthread_freezable_should_stop); */ void *kthread_func(struct task_struct *task) { - if (task->flags & PF_KTHREAD) - return to_kthread(task)->threadfn; + struct kthread *kthread = __to_kthread(task); + if (kthread) + return kthread->threadfn; return NULL; } EXPORT_SYMBOL_GPL(kthread_func); @@ -199,10 +219,11 @@ EXPORT_SYMBOL_GPL(kthread_data); */ void *kthread_probe_data(struct task_struct *task) { - struct kthread *kthread = to_kthread(task); + struct kthread *kthread = __to_kthread(task); void *data = NULL; - copy_from_kernel_nofault(&data, &kthread->data, sizeof(data)); + if (kthread) + copy_from_kernel_nofault(&data, &kthread->data, sizeof(data)); return data; } @@ -514,9 +535,9 @@ void kthread_set_per_cpu(struct task_struct *k, int cpu) set_bit(KTHREAD_IS_PER_CPU, &kthread->flags); } -bool kthread_is_per_cpu(struct task_struct *k) +bool kthread_is_per_cpu(struct task_struct *p) { - struct kthread *kthread = to_kthread(k); + struct kthread *kthread = __to_kthread(p); if (!kthread) return false; diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 8ae9d7abebc0..1c9ef3fa80fe 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * kernel/lockdep.c @@ -188,7 +191,11 @@ static struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); +#ifdef MY_ABC_HERE +inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) +#else static inline struct lock_class *hlock_class(struct held_lock *hlock) +#endif /* MY_ABC_HERE */ { unsigned int class_idx = hlock->class_idx; @@ -209,6 +216,10 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) */ return lock_classes + class_idx; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(lockdep_hlock_class); +#define hlock_class(hlock) lockdep_hlock_class(hlock) +#endif /* MY_ABC_HERE */ #ifdef CONFIG_LOCK_STAT static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); diff --git a/kernel/module.c b/kernel/module.c index 185b2655bc20..6180de534b0c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (C) 2002 Richard Henderson @@ -67,6 +70,10 @@ #define ARCH_SHF_SMALL 0 #endif +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK +extern bool ramdisk_check_failed; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + /* * Modules' sections will be aligned on page boundaries * to ensure complete separation of code and data, but @@ -994,6 +1001,15 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, audit_log_kern_module(name); +#ifdef MY_ABC_HERE + /* + * Auditing system of CURRENT kernel knows module loading/unloading + * events. It is recommended that removing this logging at the next + * upgrading kernel of DSM. + */ + pr_warn("Module [%s] is removed. \n", name); +#endif /* MY_ABC_HERE */ + if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; @@ -2904,6 +2920,10 @@ static int module_sig_check(struct load_info *info, int flags) const char *reason; const void *mod = info->hdr; +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + sig_enforce |= ramdisk_check_failed; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + /* * Require flags == 0, as a module with version information * removed is no longer the module that was signed @@ -4731,3 +4751,22 @@ void module_layout(struct module *mod, } EXPORT_SYMBOL(module_layout); #endif + +#ifdef MY_ABC_HERE +void syno_dump_modules(void) +{ + struct module *mod; + + pr_warn( "\n[size]\t\t[module]\n\n"); + + list_for_each_entry_rcu(mod, &modules, list) { + if (mod->state == MODULE_STATE_UNFORMED) + continue; + + pr_warn( "%u\t\t%s\n", mod->init_layout.size + + mod->core_layout.size, mod->name); + } +} +EXPORT_SYMBOL_GPL(syno_dump_modules); +#endif /* MY_ABC_HERE */ + diff --git a/kernel/pid.c b/kernel/pid.c index 4856818c9de1..257950ded85d 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Generic pidhash and scalable, time-bounded PID allocator @@ -238,6 +241,11 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *set_tid, if (nr < 0) { retval = (nr == -ENOSPC) ? -EAGAIN : nr; +#ifdef MY_ABC_HERE + if (nr == -ENOSPC) { + pr_err_ratelimited("run out of pids, pid_max = %d", pid_max); + } +#endif /* MY_ABC_HERE */ goto out_free; } diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index d0df95346ab3..25ef47eb0338 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/kernel/printk.c @@ -2675,6 +2678,29 @@ static int __init keep_bootcon_setup(char *str) early_param("keep_bootcon", keep_bootcon_setup); +#ifdef MY_ABC_HERE +static int syno_setup_console(struct console *newcon) +{ + int ret = -1; + short console_index = 0; + struct console *bcon = NULL; + + if (0 == strcmp(newcon->name, "ttyS") && console_index == newcon->index) { + console_lock(); + for_each_console(bcon) { + if ((bcon->flags & CON_BOOT) && bcon->deinit) + bcon->deinit(); + } + ret = newcon->setup(newcon, NULL); + console_unlock(); + } else { + ret = newcon->setup(newcon, NULL); + } + + return ret; +} +#endif /* MY_ABC_HERE */ + /* * This is called by register_console() to try to match * the newly registered console with any of the ones selected @@ -2792,7 +2818,11 @@ void register_console(struct console *newcon) if (newcon->index < 0) newcon->index = 0; if (newcon->setup == NULL || +#ifdef MY_ABC_HERE + syno_setup_console(newcon) == 0) { +#else /* MY_ABC_HERE */ newcon->setup(newcon, NULL) == 0) { +#endif /* MY_ABC_HERE */ newcon->flags |= CON_ENABLED; if (newcon->device) { newcon->flags |= CON_CONSDEV; @@ -2887,6 +2917,17 @@ void register_console(struct console *newcon) } EXPORT_SYMBOL(register_console); +#ifdef MY_ABC_HERE +static void __ref pci_console_unmap_memory(void __iomem *addr, u32 size) +{ + if (!addr || !size) + return; + + else + early_iounmap(addr, size); +} +#endif /* MY_ABC_HERE */ + int unregister_console(struct console *console) { struct console *con; @@ -2933,6 +2974,11 @@ int unregister_console(struct console *console) console->flags &= ~CON_ENABLED; console_unlock(); console_sysfs_notify(); +#ifdef MY_ABC_HERE + if (console->pcimapaddress) { + pci_console_unmap_memory(console->pcimapaddress, console->pcimapsize); + } +#endif /* MY_ABC_HERE */ if (console->exit) res = console->exit(console); diff --git a/kernel/reboot.c b/kernel/reboot.c index af6f23d8bea1..c8ff31ccc8ab 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/kernel/reboot.c @@ -17,6 +20,9 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ /* * this indicates whether you can reboot with ctrl-alt-del: the default is yes @@ -299,6 +305,13 @@ EXPORT_SYMBOL_GPL(kernel_power_off); DEFINE_MUTEX(system_transition_mutex); +#ifdef MY_ABC_HERE +#define UART_TTYS_INDEX 1 + +#define UART_CMD_REBOOT 67 // "C" +#define UART_CMD_POWEROFF 49 // "1" +#endif /* MY_ABC_HERE */ + /* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers @@ -313,6 +326,9 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, struct pid_namespace *pid_ns = task_active_pid_ns(current); char buffer[256]; int ret = 0; +#ifdef MY_ABC_HERE + char szBuf[2]; +#endif /* MY_ABC_HERE */ /* We only trust the superuser with rebooting the system. */ if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) @@ -344,6 +360,11 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, mutex_lock(&system_transition_mutex); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: +#ifdef MY_ABC_HERE + szBuf[0] = UART_CMD_REBOOT; + szBuf[1] = '\0'; + syno_ttys_write(UART_TTYS_INDEX, szBuf); +#endif /* MY_ABC_HERE */ kernel_restart(NULL); break; @@ -361,6 +382,11 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, panic("cannot halt"); case LINUX_REBOOT_CMD_POWER_OFF: +#ifdef MY_ABC_HERE + szBuf[0] = UART_CMD_POWEROFF; + szBuf[1] = '\0'; + syno_ttys_write(UART_TTYS_INDEX, szBuf); +#endif /*MY_ABC_HERE */ kernel_power_off(); do_exit(0); break; diff --git a/kernel/relay.c b/kernel/relay.c index b08d936d5fa7..a29711f47ff5 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Public API and common code for kernel->userspace relay file support. * @@ -180,6 +183,10 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan) buf->chan = chan; kref_get(&buf->chan->kref); +#ifdef MY_ABC_HERE + spin_lock_init(&buf->lock); +#endif /* MY_ABC_HERE */ + return buf; free_buf: @@ -1126,11 +1133,17 @@ static ssize_t relay_file_read(struct file *filp, size_t read_start, avail; size_t written = 0; int ret; +#ifdef MY_ABC_HERE + int copy_to_user_ret = -1; +#endif /* MY_ABC_HERE */ if (!count) return 0; inode_lock(file_inode(filp)); +#ifdef MY_ABC_HERE + spin_lock_irq(&buf->lock); +#endif /* MY_ABC_HERE */ do { void *from; @@ -1145,8 +1158,17 @@ static ssize_t relay_file_read(struct file *filp, avail = min(count, avail); from = buf->start + read_start; ret = avail; +#ifdef MY_ABC_HERE + spin_unlock_irq(&buf->lock); + copy_to_user_ret = copy_to_user(buffer, from, avail); + spin_lock_irq(&buf->lock); + if (copy_to_user_ret) { + break; + } +#else if (copy_to_user(buffer, from, avail)) break; +#endif /* MY_ABC_HERE */ buffer += ret; written += ret; @@ -1155,6 +1177,9 @@ static ssize_t relay_file_read(struct file *filp, relay_file_read_consume(buf, read_start, ret); *ppos = relay_file_read_end_pos(buf, read_start, ret); } while (count); +#ifdef MY_ABC_HERE + spin_unlock_irq(&buf->lock); +#endif /* MY_ABC_HERE */ inode_unlock(file_inode(filp)); return written; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 679562d2f55d..20a6fa6b6175 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * kernel/sched/core.c @@ -6429,7 +6432,11 @@ void sched_show_task(struct task_struct *p) if (!try_get_task_stack(p)) return; +#ifdef MY_ABC_HERE + pr_warn("task:%-15.15s state:%c", p->comm, task_state_to_char(p)); +#else /* MY_ABC_HERE */ pr_info("task:%-15.15s state:%c", p->comm, task_state_to_char(p)); +#endif /* MY_ABC_HERE */ if (p->state == TASK_RUNNING) pr_cont(" running task "); @@ -6446,7 +6453,11 @@ void sched_show_task(struct task_struct *p) (unsigned long)task_thread_info(p)->flags); print_worker_info(KERN_INFO, p); +#ifdef MY_ABC_HERE + show_stack(p, NULL, KERN_WARNING); +#else /* MY_ABC_HERE */ show_stack(p, NULL, KERN_INFO); +#endif /* MY_ABC_HERE */ put_task_stack(p); } EXPORT_SYMBOL_GPL(sched_show_task); @@ -6698,9 +6709,20 @@ void idle_task_exit(void) */ static void calc_load_migrate(struct rq *rq) { +#ifdef MY_ABC_HERE + long delta[3] = {0}; + calc_load_fold_active(rq, 1, delta); + if (delta[0]) + atomic_long_add(delta[0], &calc_load_tasks); + if (delta[1]) + atomic_long_add(delta[1], &calc_io_load_tasks); + if (delta[2]) + atomic_long_add(delta[2], &calc_cpu_load_tasks); +#else /* MY_ABC_HERE */ long delta = calc_load_fold_active(rq, 1); if (delta) atomic_long_add(delta, &calc_load_tasks); +#endif /* MY_ABC_HERE */ } static struct task_struct *__pick_migrate_task(struct rq *rq) @@ -7133,6 +7155,10 @@ void __init sched_init(void) raw_spin_lock_init(&rq->lock); rq->nr_running = 0; rq->calc_load_active = 0; +#ifdef MY_ABC_HERE + rq->calc_io_load_active = 0; + rq->calc_cpu_load_active = 0; +#endif /* MY_ABC_HERE */ rq->calc_load_update = jiffies + LOAD_FREQ; init_cfs_rq(&rq->cfs); init_rt_rq(&rq->rt); diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 5a55d2300452..683be27f3b10 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -1,9 +1,16 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Simple CPU accounting cgroup controller */ #include "sched.h" +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #ifdef CONFIG_IRQ_TIME_ACCOUNTING /* @@ -491,7 +498,15 @@ void account_process_tick(struct task_struct *p, int user_tick) if (user_tick) account_user_time(p, cputime); else if ((p != this_rq()->idle) || (irq_count() != HARDIRQ_OFFSET)) +#ifdef MY_ABC_HERE + { +#endif /* MY_ABC_HERE */ account_system_time(p, HARDIRQ_OFFSET, cputime); +#ifdef MY_ABC_HERE + if (p->workacct) + account_workqueue_time(p, div_u64(cputime, NSEC_PER_USEC), GFP_NOWAIT); + } +#endif /* MY_ABC_HERE */ else account_idle_time(cputime); } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 262b02d75007..2050abf52c9b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Completely Fair Scheduling (CFS) Class (SCHED_NORMAL/SCHED_BATCH) @@ -3072,6 +3075,22 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se) } while (0) #ifdef CONFIG_SMP +#ifdef MY_ABC_HERE +static inline void +enqueue_runnable_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) +{ + cfs_rq->avg.runnable_avg += se->avg.runnable_avg; + cfs_rq->avg.runnable_sum += se->avg.runnable_sum; +} + +static inline void +dequeue_runnable_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) +{ + sub_positive(&cfs_rq->avg.runnable_avg, se->avg.runnable_avg); + sub_positive(&cfs_rq->avg.runnable_sum, se->avg.runnable_sum); +} +#endif /* MY_ABC_HERE */ + static inline void enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { @@ -3086,6 +3105,12 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) sub_positive(&cfs_rq->avg.load_sum, se_weight(se) * se->avg.load_sum); } #else +#ifdef MY_ABC_HERE +static inline void +enqueue_runnable_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { } +dequeue_runnable_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { } +#endif /* MY_ABC_HERE */ + static inline void enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { } static inline void @@ -3679,8 +3704,11 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq) sa->util_sum = sa->util_avg * divider; r = removed_runnable; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ sub_positive(&sa->runnable_avg, r); sa->runnable_sum = sa->runnable_avg * divider; +#endif /* MY_ABC_HERE */ /* * removed_runnable is the unweighted version of removed_load so we @@ -3747,8 +3775,11 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s enqueue_load_avg(cfs_rq, se); cfs_rq->avg.util_avg += se->avg.util_avg; cfs_rq->avg.util_sum += se->avg.util_sum; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ cfs_rq->avg.runnable_avg += se->avg.runnable_avg; cfs_rq->avg.runnable_sum += se->avg.runnable_sum; +#endif /* MY_ABC_HERE */ add_tg_cfs_propagate(cfs_rq, se->avg.load_sum); @@ -3776,8 +3807,11 @@ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s dequeue_load_avg(cfs_rq, se); sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg); cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * divider; +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ sub_positive(&cfs_rq->avg.runnable_avg, se->avg.runnable_avg); cfs_rq->avg.runnable_sum = cfs_rq->avg.runnable_avg * divider; +#endif /* MY_ABC_HERE */ add_tg_cfs_propagate(cfs_rq, -se->avg.load_sum); @@ -4259,6 +4293,9 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) * - Add its new weight to cfs_rq->load.weight */ update_load_avg(cfs_rq, se, UPDATE_TG | DO_ATTACH); +#ifdef MY_ABC_HERE + enqueue_runnable_avg(cfs_rq, se); +#endif /* MY_ABC_HERE */ se_update_runnable(se); update_cfs_group(se); account_entity_enqueue(cfs_rq, se); @@ -4349,6 +4386,9 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) * of its group cfs_rq. */ update_load_avg(cfs_rq, se, UPDATE_TG); +#ifdef MY_ABC_HERE + dequeue_runnable_avg(cfs_rq, se); +#endif /* MY_ABC_HERE */ se_update_runnable(se); update_stats_dequeue(cfs_rq, se, flags); @@ -5853,7 +5893,11 @@ wake_affine_weight(struct sched_domain *sd, struct task_struct *p, s64 this_eff_load, prev_eff_load; unsigned long task_load; +#ifdef MY_ABC_HERE + this_eff_load = cpu_runnable(cpu_rq(this_cpu)); +#else /* MY_ABC_HERE */ this_eff_load = cpu_load(cpu_rq(this_cpu)); +#endif /* MY_ABC_HERE */ if (sync) { unsigned long current_load = task_h_load(current); @@ -5871,7 +5915,11 @@ wake_affine_weight(struct sched_domain *sd, struct task_struct *p, this_eff_load *= 100; this_eff_load *= capacity_of(prev_cpu); +#ifdef MY_ABC_HERE + prev_eff_load = cpu_runnable(cpu_rq(prev_cpu)); +#else /* MY_ABC_HERE */ prev_eff_load = cpu_load(cpu_rq(prev_cpu)); +#endif /* MY_ABC_HERE */ prev_eff_load -= task_load; if (sched_feat(WA_BIAS)) prev_eff_load *= 100 + (sd->imbalance_pct - 100) / 2; @@ -7569,7 +7617,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) return 0; /* Disregard pcpu kthreads; they are where they need to be. */ - if ((p->flags & PF_KTHREAD) && kthread_is_per_cpu(p)) + if (kthread_is_per_cpu(p)) return 0; if (!cpumask_test_cpu(env->dst_cpu, p->cpus_ptr)) { diff --git a/kernel/sched/loadavg.c b/kernel/sched/loadavg.c index d2a655643a02..f232f64004fc 100644 --- a/kernel/sched/loadavg.c +++ b/kernel/sched/loadavg.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * kernel/sched/loadavg.c @@ -57,8 +60,16 @@ /* Variables and functions for calc_load */ atomic_long_t calc_load_tasks; +#ifdef MY_ABC_HERE +atomic_long_t calc_io_load_tasks; +atomic_long_t calc_cpu_load_tasks; +#endif /* MY_ABC_HERE */ unsigned long calc_load_update; unsigned long avenrun[3]; +#ifdef MY_ABC_HERE +unsigned long avenrun_io[3]; +unsigned long avenrun_cpu[3]; +#endif /* MY_ABC_HERE */ EXPORT_SYMBOL(avenrun); /* should be removed */ /** @@ -76,6 +87,42 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift) loads[2] = (avenrun[2] + offset) << shift; } +#ifdef MY_ABC_HERE +void get_avenrun_split(unsigned long *io_loads, unsigned long *cpu_loads, + unsigned long offset, int shift) +{ + io_loads[0] = (avenrun_io[0] + offset) << shift; + io_loads[1] = (avenrun_io[1] + offset) << shift; + io_loads[2] = (avenrun_io[2] + offset) << shift; + + cpu_loads[0] = (avenrun_cpu[0] + offset) << shift; + cpu_loads[1] = (avenrun_cpu[1] + offset) << shift; + cpu_loads[2] = (avenrun_cpu[2] + offset) << shift; +} + +void calc_load_fold_active(struct rq *this_rq, long adjust, long delta[]) +{ + long nr_active, nr_io_active, nr_cpu_active; + + nr_io_active = (long)this_rq->nr_uninterruptible; + if (nr_io_active != this_rq->calc_io_load_active) { + delta[1] = nr_io_active - this_rq->calc_io_load_active; + this_rq->calc_io_load_active = nr_io_active; + } + + nr_cpu_active = this_rq->nr_running - adjust; + if (nr_cpu_active != this_rq->calc_cpu_load_active) { + delta[2] = nr_cpu_active - this_rq->calc_cpu_load_active; + this_rq->calc_cpu_load_active = nr_cpu_active; + } + + nr_active = nr_io_active + nr_cpu_active; + if (nr_active != this_rq->calc_load_active) { + delta[0] = nr_active - this_rq->calc_load_active; + this_rq->calc_load_active = nr_active; + } +} +#else /* MY_ABC_HERE */ long calc_load_fold_active(struct rq *this_rq, long adjust) { long nr_active, delta = 0; @@ -90,6 +137,7 @@ long calc_load_fold_active(struct rq *this_rq, long adjust) return delta; } +#endif /* MY_ABC_HERE */ /** * fixed_power_int - compute: x^n, in O(log n) time @@ -204,6 +252,10 @@ calc_load_n(unsigned long load, unsigned long exp, * When making the ILB scale, we should try to pull this in as well. */ static atomic_long_t calc_load_nohz[2]; +#ifdef MY_ABC_HERE +static atomic_long_t calc_io_load_nohz[2]; +static atomic_long_t calc_cpu_load_nohz[2]; +#endif /* MY_ABC_HERE */ static int calc_load_idx; static inline int calc_load_write_idx(void) @@ -231,6 +283,21 @@ static inline int calc_load_read_idx(void) return calc_load_idx & 1; } +#ifdef MY_ABC_HERE +static void calc_load_nohz_fold(struct rq *rq) +{ + long delta[3] = {0}; + + calc_load_fold_active(rq, 0, delta); + if (delta[0] || delta[1] || delta[2]) { + int idx = calc_load_write_idx(); + + atomic_long_add(delta[0], &calc_load_nohz[idx]); + atomic_long_add(delta[1], &calc_io_load_nohz[idx]); + atomic_long_add(delta[2], &calc_cpu_load_nohz[idx]); + } +} +#else /* MY_ABC_HERE */ static void calc_load_nohz_fold(struct rq *rq) { long delta; @@ -242,6 +309,7 @@ static void calc_load_nohz_fold(struct rq *rq) atomic_long_add(delta, &calc_load_nohz[idx]); } } +#endif /* MY_ABC_HERE */ void calc_load_nohz_start(void) { @@ -281,6 +349,21 @@ void calc_load_nohz_stop(void) this_rq->calc_load_update += LOAD_FREQ; } +#ifdef MY_ABC_HERE +static void calc_load_nohz_read(long delta[]) +{ + int idx = calc_load_read_idx(); + + if (atomic_long_read(&calc_load_nohz[idx])) + delta[0] = atomic_long_xchg(&calc_load_nohz[idx], 0); + + if (atomic_long_read(&calc_io_load_nohz[idx])) + delta[1] = atomic_long_xchg(&calc_io_load_nohz[idx], 0); + + if (atomic_long_read(&calc_cpu_load_nohz[idx])) + delta[2] = atomic_long_xchg(&calc_cpu_load_nohz[idx], 0); +} +#else /* MY_ABC_HERE */ static long calc_load_nohz_read(void) { int idx = calc_load_read_idx(); @@ -291,6 +374,7 @@ static long calc_load_nohz_read(void) return delta; } +#endif /* MY_ABC_HERE */ /* * NO_HZ can leave us missing all per-CPU ticks calling @@ -305,6 +389,9 @@ static void calc_global_nohz(void) { unsigned long sample_window; long delta, active, n; +#ifdef MY_ABC_HERE + long io_active, cpu_active; +#endif /* MY_ABC_HERE */ sample_window = READ_ONCE(calc_load_update); if (!time_before(jiffies, sample_window + 10)) { @@ -321,6 +408,22 @@ static void calc_global_nohz(void) avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n); avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n); +#ifdef MY_ABC_HERE + io_active = atomic_long_read(&calc_io_load_tasks); + io_active = io_active > 0 ? io_active * FIXED_1 : 0; + + avenrun_io[0] = calc_load_n(avenrun_io[0], EXP_1, io_active, n); + avenrun_io[1] = calc_load_n(avenrun_io[1], EXP_5, io_active, n); + avenrun_io[2] = calc_load_n(avenrun_io[2], EXP_15, io_active, n); + + cpu_active = atomic_long_read(&calc_cpu_load_tasks); + cpu_active = cpu_active > 0 ? cpu_active * FIXED_1 : 0; + + avenrun_cpu[0] = calc_load_n(avenrun_cpu[0], EXP_1, cpu_active, n); + avenrun_cpu[1] = calc_load_n(avenrun_cpu[1], EXP_5, cpu_active, n); + avenrun_cpu[2] = calc_load_n(avenrun_cpu[2], EXP_15, cpu_active, n); +#endif /* MY_ABC_HERE */ + WRITE_ONCE(calc_load_update, sample_window + n * LOAD_FREQ); } @@ -336,7 +439,11 @@ static void calc_global_nohz(void) } #else /* !CONFIG_NO_HZ_COMMON */ +#ifdef MY_ABC_HERE +static inline void calc_load_nohz_read(long delta[]) { } +#else /* MY_ABC_HERE */ static inline long calc_load_nohz_read(void) { return 0; } +#endif /* MY_ABC_HERE */ static inline void calc_global_nohz(void) { } #endif /* CONFIG_NO_HZ_COMMON */ @@ -350,7 +457,12 @@ static inline void calc_global_nohz(void) { } void calc_global_load(void) { unsigned long sample_window; +#ifdef MY_ABC_HERE + long active, io_active, cpu_active; + long delta[3] = {0}; +#else /* MY_ABC_HERE */ long active, delta; +#endif /* MY_ABC_HERE */ sample_window = READ_ONCE(calc_load_update); if (time_before(jiffies, sample_window + 10)) @@ -359,9 +471,19 @@ void calc_global_load(void) /* * Fold the 'old' NO_HZ-delta to include all NO_HZ CPUs. */ +#ifdef MY_ABC_HERE + calc_load_nohz_read(delta); + if (delta[0]) + atomic_long_add(delta[0], &calc_load_tasks); + if (delta[1]) + atomic_long_add(delta[1], &calc_io_load_tasks); + if (delta[2]) + atomic_long_add(delta[2], &calc_cpu_load_tasks); +#else /* MY_ABC_HERE */ delta = calc_load_nohz_read(); if (delta) atomic_long_add(delta, &calc_load_tasks); +#endif /* MY_ABC_HERE */ active = atomic_long_read(&calc_load_tasks); active = active > 0 ? active * FIXED_1 : 0; @@ -370,6 +492,22 @@ void calc_global_load(void) avenrun[1] = calc_load(avenrun[1], EXP_5, active); avenrun[2] = calc_load(avenrun[2], EXP_15, active); +#ifdef MY_ABC_HERE + io_active = atomic_long_read(&calc_io_load_tasks); + io_active = io_active > 0 ? io_active * FIXED_1 : 0; + + avenrun_io[0] = calc_load(avenrun_io[0], EXP_1, io_active); + avenrun_io[1] = calc_load(avenrun_io[1], EXP_5, io_active); + avenrun_io[2] = calc_load(avenrun_io[2], EXP_15, io_active); + + cpu_active = atomic_long_read(&calc_cpu_load_tasks); + cpu_active = cpu_active > 0 ? cpu_active * FIXED_1 : 0; + + avenrun_cpu[0] = calc_load(avenrun_cpu[0], EXP_1, cpu_active); + avenrun_cpu[1] = calc_load(avenrun_cpu[1], EXP_5, cpu_active); + avenrun_cpu[2] = calc_load(avenrun_cpu[2], EXP_15, cpu_active); +#endif /* MY_ABC_HERE */ + WRITE_ONCE(calc_load_update, sample_window + LOAD_FREQ); /* @@ -385,14 +523,28 @@ void calc_global_load(void) */ void calc_global_load_tick(struct rq *this_rq) { +#ifdef MY_ABC_HERE + long delta[3] = {0}; +#else /* MY_ABC_HERE */ long delta; +#endif /* MY_ABC_HERE */ if (time_before(jiffies, this_rq->calc_load_update)) return; +#ifdef MY_ABC_HERE + calc_load_fold_active(this_rq, 0, delta); + if (delta[0]) + atomic_long_add(delta[0], &calc_load_tasks); + if (delta[1]) + atomic_long_add(delta[1], &calc_io_load_tasks); + if (delta[2]) + atomic_long_add(delta[2], &calc_cpu_load_tasks); +#else /* MY_ABC_HERE */ delta = calc_load_fold_active(this_rq, 0); if (delta) atomic_long_add(delta, &calc_load_tasks); +#endif /* MY_ABC_HERE */ this_rq->calc_load_update += LOAD_FREQ; } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 39112ac7ab34..ce872da8994b 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * Scheduler internal types and methods: @@ -95,9 +98,17 @@ extern __read_mostly int scheduler_running; extern unsigned long calc_load_update; extern atomic_long_t calc_load_tasks; +#ifdef MY_ABC_HERE +extern atomic_long_t calc_io_load_tasks; +extern atomic_long_t calc_cpu_load_tasks; +#endif /* MY_ABC_HERE */ extern void calc_global_load_tick(struct rq *this_rq); +#ifdef MY_ABC_HERE +extern void calc_load_fold_active(struct rq *this_rq, long adjust, long delta[]); +#else /* MY_ABC_HERE */ extern long calc_load_fold_active(struct rq *this_rq, long adjust); +#endif /* MY_ABC_HERE */ extern void call_trace_sched_update_nr_running(struct rq *rq, int count); /* @@ -1019,6 +1030,10 @@ struct rq { /* calc_load related fields */ unsigned long calc_load_update; long calc_load_active; +#ifdef MY_ABC_HERE + long calc_io_load_active; + long calc_cpu_load_active; +#endif /* MY_ABC_HERE */ #ifdef CONFIG_SCHED_HRTICK #ifdef CONFIG_SMP diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index 21005b980a6b..a55642aa3f68 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -223,6 +223,13 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode) } EXPORT_SYMBOL_GPL(__wake_up_sync); /* For internal use only */ +void __wake_up_pollfree(struct wait_queue_head *wq_head) +{ + __wake_up(wq_head, TASK_NORMAL, 0, poll_to_key(EPOLLHUP | POLLFREE)); + /* POLLFREE must have cleared the queue. */ + WARN_ON_ONCE(waitqueue_active(wq_head)); +} + /* * Note: we use "set_current_state()" _after_ the wait-queue add, * because we need a memory barrier there on SMP, so that any diff --git a/kernel/softirq.c b/kernel/softirq.c index 09229ad82209..ccb350bccd13 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/kernel/softirq.c @@ -81,7 +84,11 @@ static void wakeup_softirqd(void) * right now. Let ksoftirqd handle this at its own rate, to get fairness, * unless we're doing some of the synchronous softirqs. */ +#ifdef MY_ABC_HERE +#define SOFTIRQ_NOW_MASK ((1 << HI_SOFTIRQ) | (1 << TASKLET_SOFTIRQ) | (1 << BLOCK_SOFTIRQ)) +#else /* MY_ABC_HERE */ #define SOFTIRQ_NOW_MASK ((1 << HI_SOFTIRQ) | (1 << TASKLET_SOFTIRQ)) +#endif /* MY_ABC_HERE */ static bool ksoftirqd_running(unsigned long pending) { struct task_struct *tsk = __this_cpu_read(ksoftirqd); diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c index 9f8117c7cfdd..506f5d3a8fa7 100644 --- a/kernel/stacktrace.c +++ b/kernel/stacktrace.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * kernel/stacktrace.c @@ -150,6 +153,9 @@ unsigned int stack_trace_save_tsk(struct task_struct *tsk, unsigned long *store, put_task_stack(tsk); return c.len; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(stack_trace_save_tsk); +#endif /* MY_ABC_HERE */ /** * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array diff --git a/kernel/syno-module-internal.h b/kernel/syno-module-internal.h new file mode 100644 index 000000000000..e7224fb66465 --- /dev/null +++ b/kernel/syno-module-internal.h @@ -0,0 +1,7 @@ +// Copyright (C) 2022 Synology Inc. All rights reserved. + +#ifndef _SYNO_MODULE_INTERNAL_H +#define _SYNO_MODULE_INTERNAL_H + + +#endif /* _SYNO_MODULE_INTERNAL_H */ diff --git a/kernel/syno_bootargs.c b/kernel/syno_bootargs.c new file mode 100644 index 000000000000..6136f70ca37e --- /dev/null +++ b/kernel/syno_bootargs.c @@ -0,0 +1,375 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +// Copyright (c) 2003-2020 Synology Inc. All rights reserved. +#include +#include +#include + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern int setup_early_printk(char *); +extern char gszSynoTtyS0[50]; +extern char gszSynoTtyS1[50]; +extern char gszSynoTtyS2[50]; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +extern long g_internal_netif_num; +#endif /* MY_ABC_HERE*/ + +#ifdef MY_ABC_HERE +extern char gszSynoHWVersion[]; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern char gszSynoHWRevision[]; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern long g_smbus_hdd_powerctl; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern unsigned char grgbLanMac[SYNO_MAC_MAX_NUMBER][16]; +extern int giVenderFormatVersion; +extern char gszSkipVenderMacInterfaces[256]; +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +extern char gszSerialNum[32]; +extern char gszCustomSerialNum[32]; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +extern long g_is_sas_model; +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +extern char g_ahci_switch; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +char gSynoSASHBAAddr[CONFIG_SYNO_SAS_MAX_HBA_SLOT][13] = {{0}}; +EXPORT_SYMBOL(gSynoSASHBAAddr); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +extern char gszPciAddrList[PCI_ADDR_NUM_MAX][PCI_ADDR_LEN_MAX]; +extern int gPciAddrNum; +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +extern char gSynoCastratedXhcAddr[CONFIG_SYNO_USB_NUM_CASTRATED_XHC][32]; +extern unsigned int gSynoCastratedXhcPortBitmap[CONFIG_SYNO_USB_NUM_CASTRATED_XHC]; +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +extern int giSynoSpinupGroupDebug; +static int __init early_syno_spinup_group_debug(char *p) +{ + giSynoSpinupGroupDebug = simple_strtol(p, NULL, 10); + printk("SYNO Spinup Group Debug: %d\n", (int)giSynoSpinupGroupDebug); + return 1; +} +__setup("syno_spinup_group_debug=", early_syno_spinup_group_debug); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_hw_version(char *p) +{ + snprintf(gszSynoHWVersion, 16, "%s", p); + + printk("Synology Hardware Version: %s\n", gszSynoHWVersion); + + return 1; +} +__setup("syno_hw_version=", early_hw_version); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_hw_revision(char *p) +{ + snprintf(gszSynoHWRevision, 4, "%s", p); + + printk("Synology Hardware Revision: %s\n", gszSynoHWRevision); + + return 1; +} +__setup("rev=", early_hw_revision); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_internal_netif_num(char *p) +{ + g_internal_netif_num = simple_strtol(p, NULL, 10); + + if ( g_internal_netif_num >= 0 ) { + printk("Internal netif num: %d\n", (int)g_internal_netif_num); + } + + return 1; +} +__setup("netif_num=", early_internal_netif_num); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_mac1(char *p) +{ + snprintf(grgbLanMac[0], sizeof(grgbLanMac[0]), "%s", p); + + printk("Mac1: %s\n", grgbLanMac[0]); + + return 1; +} +__setup("mac1=", early_mac1); + +static int __init early_mac2(char *p) +{ + snprintf(grgbLanMac[1], sizeof(grgbLanMac[1]), "%s", p); + + printk("Mac2: %s\n", grgbLanMac[1]); + + return 1; +} +__setup("mac2=", early_mac2); + +static int __init early_mac3(char *p) +{ + snprintf(grgbLanMac[2], sizeof(grgbLanMac[2]), "%s", p); + + printk("Mac3: %s\n", grgbLanMac[2]); + + return 1; +} +__setup("mac3=", early_mac3); + +static int __init early_mac4(char *p) +{ + snprintf(grgbLanMac[3], sizeof(grgbLanMac[3]), "%s", p); + + printk("Mac4: %s\n", grgbLanMac[3]); + + return 1; +} +__setup("mac4=", early_mac4); + +static int __init early_macs(char *p) +{ + int iMacCount = 0; + char *pBegin = p; + char *pEnd = strstr(pBegin, ","); + + while (NULL != pEnd && SYNO_MAC_MAX_NUMBER > iMacCount) { + *pEnd = '\0'; + snprintf(grgbLanMac[iMacCount], sizeof(grgbLanMac[iMacCount]), "%s", pBegin); + pBegin = pEnd + 1; + pEnd = strstr(pBegin, ","); + iMacCount++; + } + + if ('\0' != *pBegin && SYNO_MAC_MAX_NUMBER > iMacCount) { + snprintf(grgbLanMac[iMacCount], sizeof(grgbLanMac[iMacCount]), "%s", pBegin); + } + + return 1; +} +__setup("macs=", early_macs); + +static int __init early_vender_format_version(char *p) +{ + giVenderFormatVersion = simple_strtol(p, NULL, 10); + + printk("Vender format version: %d\n", giVenderFormatVersion); + + return 1; +} +__setup("vender_format_version=", early_vender_format_version); + +static int __init early_skip_vender_mac_interfaces(char *p) +{ + snprintf(gszSkipVenderMacInterfaces, sizeof(gszSkipVenderMacInterfaces), "%s", p); + + printk("Skip vender mac interfaces: %s\n", gszSkipVenderMacInterfaces); + + return 1; +} +__setup("skip_vender_mac_interfaces=", early_skip_vender_mac_interfaces); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_sn(char *p) +{ + snprintf(gszSerialNum, sizeof(gszSerialNum), "%s", p); + printk("Serial Number: %s\n", gszSerialNum); + return 1; +} +__setup("sn=", early_sn); + +static int __init early_custom_sn(char *p) +{ + snprintf(gszCustomSerialNum, sizeof(gszCustomSerialNum), "%s", p); + printk("Custom Serial Number: %s\n", gszCustomSerialNum); + return 1; +} +__setup("custom_sn=", early_custom_sn); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +static int __init early_SASmodel(char *p) +{ + g_is_sas_model = simple_strtol(p, NULL, 10); + + if (1 == g_is_sas_model) { + printk("SAS model: %d\n", (int)g_is_sas_model); + } + + return 1; +} +__setup("SASmodel=", early_SASmodel); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_syno_set_ttyS0(char *p) +{ + snprintf(gszSynoTtyS0, strlen(p) + 1, "%s", p); + setup_early_printk(p); + return 1; +} +__setup("syno_ttyS0=", early_syno_set_ttyS0); + +static int __init early_syno_set_ttyS1(char *p) +{ + snprintf(gszSynoTtyS1, strlen(p) + 1, "%s", p); + return 1; +} +__setup("syno_ttyS1=", early_syno_set_ttyS1); + +static int __init early_syno_set_ttyS2(char *p) +{ + snprintf(gszSynoTtyS2, strlen(p) + 1, "%s", p); + return 1; +} +__setup("syno_ttyS2=", early_syno_set_ttyS2); + +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +static int __init early_sas_hba_idx(char *p) +{ + int iCount = 0; + char *pBegin = p; + char *pEnd = NULL; + + do { + pEnd = strstr(pBegin, ","); + if (NULL != pEnd) { + *pEnd = '\0'; + } + snprintf(gSynoSASHBAAddr[iCount], + sizeof(gSynoSASHBAAddr[iCount]), "%s", pBegin); + pBegin = (NULL == pEnd) ? NULL : pEnd + 1; + iCount ++; + } while (NULL != pBegin && iCount < CONFIG_SYNO_SAS_MAX_HBA_SLOT); + + return 1; +} +__setup("sas_hba_idx_addr=", early_sas_hba_idx); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_opt_pci_slot(char *p) +{ + int index = 0; + char *ptr = p; + gPciAddrNum = 0; + while(ptr && *ptr){ + if (',' == *ptr) { + index = 0; + gPciAddrNum ++; + if (PCI_ADDR_NUM_MAX <= gPciAddrNum){ + goto FMT_ERR; + } + } else { + if (PCI_ADDR_LEN_MAX <= index) { + goto FMT_ERR; + } + gszPciAddrList[gPciAddrNum][index] = *ptr; + index++; + } + ptr++; + } + gPciAddrNum ++; + printk(KERN_ERR "Syno Bootargs : opt_pci_slot initialized\n"); + return 0; +FMT_ERR: + gPciAddrNum = 0; + printk(KERN_ERR "SYNO: opt_pci_slot format error, ignore.\n" ); + return 0; +} +__setup("opt_pci_slot=", early_opt_pci_slot); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_smbus_hdd_powerctl(char *p) +{ + g_smbus_hdd_powerctl = simple_strtol(p, NULL, 10); + + if ( g_smbus_hdd_powerctl > 0 ) { + printk("Support SMBus HDD Dynamic Power Control.\n"); + } + + return 1; +} +__setup("SMBusHddDynamicPower=", early_smbus_hdd_powerctl); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +static int __init early_castrated_xhc(char *p) +{ + int iCount = 0; + char *pBegin = p; + char *pEnd = strstr(pBegin, ","); + char *pPortSep = NULL; + + while (iCount < CONFIG_SYNO_USB_NUM_CASTRATED_XHC) { + if(NULL != pEnd) + *pEnd = '\0'; + pPortSep = strstr(pBegin, "@"); + if (pPortSep == NULL) { + printk("Castrated xHC - Parameter format not correct\n"); + break; + } + *pPortSep = '\0'; + snprintf(gSynoCastratedXhcAddr[iCount], + sizeof(gSynoCastratedXhcAddr[iCount]), "%s", pBegin); + gSynoCastratedXhcPortBitmap[iCount] = simple_strtoul(pPortSep + 1, NULL, + 16); + if (NULL == pEnd) + break; + pBegin = pEnd + 1; + pEnd = strstr(pBegin, ","); + iCount++; + } + + return 1; +} +__setup("syno_castrated_xhc=", early_castrated_xhc); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +static int __init early_ahci_switch(char *p) +{ + g_ahci_switch = p[0]; + if ('0' == g_ahci_switch) { + printk("AHCI: 0\n"); + } else { + printk("AHCI: 1\n"); + } + + return 1; +} +__setup("ahci=", early_ahci_switch); +#endif /* MY_ABC_HERE */ diff --git a/kernel/sys.c b/kernel/sys.c index 0670e824e019..a730c03ee607 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -552,10 +552,6 @@ long __sys_setreuid(uid_t ruid, uid_t euid) if (retval < 0) goto error; - retval = set_cred_ucounts(new); - if (retval < 0) - goto error; - return commit_creds(new); error: @@ -614,10 +610,6 @@ long __sys_setuid(uid_t uid) if (retval < 0) goto error; - retval = set_cred_ucounts(new); - if (retval < 0) - goto error; - return commit_creds(new); error: @@ -693,10 +685,6 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) if (retval < 0) goto error; - retval = set_cred_ucounts(new); - if (retval < 0) - goto error; - return commit_creds(new); error: diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b9306d2bb426..1ef8427ad9cf 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * sysctl.c: General linux system control interface @@ -104,13 +107,278 @@ #include #endif +#if defined(MY_ABC_HERE) || defined(MY_DEF_HERE) +#include +#endif /* MY_ABC_HERE || MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ + #if defined(CONFIG_SYSCTL) +#ifdef MY_ABC_HERE +char gszSynoTtyS0[50] = {0}; +EXPORT_SYMBOL(gszSynoTtyS0); +char gszSynoTtyS1[50] = {0}; +EXPORT_SYMBOL(gszSynoTtyS1); +char gszSynoTtyS2[50] = {0}; +EXPORT_SYMBOL(gszSynoTtyS2); +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE +long g_smbus_hdd_powerctl = 0; +EXPORT_SYMBOL(g_smbus_hdd_powerctl); +char gSynoSmbusHddType[16]; +EXPORT_SYMBOL(gSynoSmbusHddType); +int gSynoSmbusHddAdapter; +EXPORT_SYMBOL(gSynoSmbusHddAdapter); +int gSynoSmbusHddAddress; +EXPORT_SYMBOL(gSynoSmbusHddAddress); +SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl = { + .bl_init = 0, + .syno_smbus_hdd_enable_write = NULL, + .syno_smbus_hdd_present_read = NULL, +}; +EXPORT_SYMBOL(SynoSmbusHddPowerCtl); +int gSynoSmbusSwitchCount = 0; +EXPORT_SYMBOL(gSynoSmbusSwitchCount); +int gSynoSmbusSwitchAdapters[SMBUS_SWITCH_MAX_COUNT+1]; +EXPORT_SYMBOL(gSynoSmbusSwitchAdapters); +int gSynoSmbusSwitchAddrs[SMBUS_SWITCH_MAX_COUNT+1]; +EXPORT_SYMBOL(gSynoSmbusSwitchAddrs); +int gSynoSmbusSwitchVals[SMBUS_SWITCH_MAX_COUNT+1]; +EXPORT_SYMBOL(gSynoSmbusSwitchVals); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +char gszSynoHWVersion[16]; +EXPORT_SYMBOL(gszSynoHWVersion); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +char gszSynoHWRevision[4] = {'\0'}; +EXPORT_SYMBOL(gszSynoHWRevision); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int gSynoInternalHddNumber = 0; +EXPORT_SYMBOL(gSynoInternalHddNumber); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +char gszSerialNum[32] = {'\0'}; +EXPORT_SYMBOL(gszSerialNum); +char gszCustomSerialNum[32] = {'\0'}; +EXPORT_SYMBOL(gszCustomSerialNum); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int (*funcSYNOCtrlDiskLedBy1475)(unsigned short, unsigned short) = NULL; +EXPORT_SYMBOL(funcSYNOCtrlDiskLedBy1475); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * Note: g_internal_netif_num only represents the number of internal netif in this model, + * user shouldn't regard it as ethernet numbering. + * (i.e., internal eth interfaces aren't always eth 0~g_internal_netif_num-1) + */ +long g_internal_netif_num = -1; +EXPORT_SYMBOL(g_internal_netif_num); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/* + * Note: OOB MAC address is stored in network card instead of synoboot vendor file, + * You shouldn't access OOB(eth99) MAC address from grgbLanMac. + */ +unsigned char grgbLanMac[SYNO_MAC_MAX_NUMBER][16]; +EXPORT_SYMBOL(grgbLanMac); +int giVenderFormatVersion = 1; +EXPORT_SYMBOL(giVenderFormatVersion); +static int iSynoMacMax = SYNO_MAC_MAX_NUMBER; +static int iMacEntrySize = 16; +char gszSkipVenderMacInterfaces[256] = {'\0'}; +EXPORT_SYMBOL(gszSkipVenderMacInterfaces); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +long g_is_sas_model = 0; +EXPORT_SYMBOL(g_is_sas_model); +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +long unsigned int guiWakeupDisksNum = 1; +EXPORT_SYMBOL(guiWakeupDisksNum); +int gSynoHddPowerupSeq = 0; +EXPORT_SYMBOL(gSynoHddPowerupSeq); +long g_syno_hdd_powerup_seq = -1; +EXPORT_SYMBOL(g_syno_hdd_powerup_seq); +long syno_boot_hd_count = 0; +EXPORT_SYMBOL(syno_boot_hd_count); + +/* The default spinup time interval is 7000ms. if want modify the interval, you + * can modify this value. ex. assign 14 to it means 500ms (7000/14) */ +int giSynoSpinupGroup[SYNO_SPINUP_GROUP_MAX] = {0}; +EXPORT_SYMBOL(giSynoSpinupGroup); +int giSynoSpinupGroupNum = 0; +EXPORT_SYMBOL(giSynoSpinupGroupNum); +int giSynoSpinupGroupDelay = 0; +EXPORT_SYMBOL(giSynoSpinupGroupDelay); +int giSynoSpinupGroupDebug = 0; +EXPORT_SYMBOL(giSynoSpinupGroupDebug); +int giSynoDSleepCurrentSpinupGroupNum = 0; +EXPORT_SYMBOL(giSynoDSleepCurrentSpinupGroupNum); +int giSynoDSleepCurrentSpinupGroupDiskNum = 0; +EXPORT_SYMBOL(giSynoDSleepCurrentSpinupGroupDiskNum); +int giSynoDSleepCurrentPoweronDisks = 0; +EXPORT_SYMBOL(giSynoDSleepCurrentPoweronDisks); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +unsigned int gSynoCPUInfoCore = 0; +EXPORT_SYMBOL(gSynoCPUInfoCore); +#ifdef CONFIG_SYNO_MULTI_CPU_NUM +unsigned int gSynoMultiCPUInfoCore[CONFIG_SYNO_MULTI_CPU_NUM]; +EXPORT_SYMBOL(gSynoMultiCPUInfoCore); +#endif /* CONFIG_SYNO_MULTI_CPU_NUM */ +char gSynoCPUInfoClock[16]; +EXPORT_SYMBOL(gSynoCPUInfoClock); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int gSynoResetFlag = 0; +EXPORT_SYMBOL(gSynoResetFlag); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +char gszPciAddrList[PCI_ADDR_NUM_MAX][PCI_ADDR_LEN_MAX] = {{0}}; +int gPciAddrNum = 0; +EXPORT_SYMBOL(gszPciAddrList); +EXPORT_SYMBOL(gPciAddrNum); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +int (*syno_valid_lsi3008_led)(SYNO_LED ledStatus); +EXPORT_SYMBOL(syno_valid_lsi3008_led); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +int gSynoInstallFlag = 0; +EXPORT_SYMBOL(gSynoInstallFlag); +#endif /*MY_ABC_HERE*/ + +#ifdef MY_ABC_HERE +int gSynoForbidUsb = 0; +EXPORT_SYMBOL(gSynoForbidUsb); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int gSynoForbidConsole = 0; +EXPORT_SYMBOL(gSynoForbidConsole); +#endif /* MY_ABC_HERE */ + +#ifdef MY_DEF_HERE +char gSynoCastratedXhcAddr[CONFIG_SYNO_USB_NUM_CASTRATED_XHC][32] = {{0}}; +unsigned int gSynoCastratedXhcPortBitmap[CONFIG_SYNO_USB_NUM_CASTRATED_XHC] = {0}; +EXPORT_SYMBOL(gSynoCastratedXhcAddr); +EXPORT_SYMBOL(gSynoCastratedXhcPortBitmap); +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +char g_ahci_switch = '1'; +EXPORT_SYMBOL(g_ahci_switch); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +LIST_HEAD(gSynoBiosEventHead); +EXPORT_SYMBOL(gSynoBiosEventHead); +DEFINE_SPINLOCK(syno_sata_error_lock); +EXPORT_SYMBOL(syno_sata_error_lock); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int (*func_synobios_event_handler)(unsigned long long synobios_event_type, ...); +EXPORT_SYMBOL(func_synobios_event_handler); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + +#define SZ_IF_PREFIX "eth" +#define SYNO_SFP_UNSUPPORT_NOTIFY_SIZE 64 +int gSynoSfpUnsupportNotify[SYNO_SFP_UNSUPPORT_NOTIFY_SIZE] = {0}; + +void SynoSfpUnsupportNotifySet(const char* ethName, SYNO_SFP_UNSUPPORTED_NOTIFY_TYPE val) +{ + long int ethNum = -1; + + if (0 != strncmp(ethName, SZ_IF_PREFIX, strlen(SZ_IF_PREFIX))) { + goto err; + } + if (0 != kstrtol(ethName + strlen(SZ_IF_PREFIX), 10, ðNum)) { + goto err; + } + if (ethNum >= SYNO_SFP_UNSUPPORT_NOTIFY_SIZE) { + goto err; + } + + gSynoSfpUnsupportNotify[ethNum] = val; + return; + +err: + printk(KERN_ERR "Syno SFP+ notification failed: %s\n", ethName); +} +EXPORT_SYMBOL(SynoSfpUnsupportNotifySet); + +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int gSynoDiskReadyCheck = 1; +EXPORT_SYMBOL(gSynoDiskReadyCheck); +extern int syno_scsi_disk_ready_check(void); + +static int proc_dointvec_disk_ready_check(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + gSynoDiskReadyCheck = syno_scsi_disk_ready_check(); + return proc_dointvec(table, write, buffer, lenp, ppos); +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +unsigned int SynoDiskSeqValidBytesThreshold = (1024 * 1024); +EXPORT_SYMBOL(SynoDiskSeqValidBytesThreshold); +unsigned int SynoDiskSeqValidSkipBytes = (64 * 1024); +EXPORT_SYMBOL(SynoDiskSeqValidSkipBytes); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int gSynoAtaDebug = 0; +EXPORT_SYMBOL(gSynoAtaDebug); +#endif /* MY_ABC_HERE */ + /* Constants used for minimum and maximum */ #ifdef CONFIG_LOCKUP_DETECTOR static int sixty = 60; #endif +#ifdef MY_DEF_HERE +void (*funcSynoLP3943Mutex)(bool) = NULL; +EXPORT_SYMBOL(funcSynoLP3943Mutex); +void SYNOLP3943I2CMutex (bool lock) +{ + if (funcSynoLP3943Mutex) { + funcSynoLP3943Mutex(lock); + } +} +EXPORT_SYMBOL(SYNOLP3943I2CMutex); +#endif /* MY_DEF_HERE */ + static int __maybe_unused neg_one = -1; static int __maybe_unused two = 2; static int __maybe_unused four = 4; @@ -126,6 +394,9 @@ static int ten_thousand = 10000; #ifdef CONFIG_PERF_EVENTS static int six_hundred_forty_kb = 640 * 1024; #endif +#ifdef MY_ABC_HERE +static int max_kswapd_threads = MAX_KSWAPD_THREADS; +#endif /* MY_ABC_HERE */ /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; @@ -148,6 +419,9 @@ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); #ifdef CONFIG_INOTIFY_USER #include #endif +#ifdef MY_ABC_HERE +#include +#endif /* MY_ABC_HERE */ #ifdef CONFIG_PROC_SYSCTL @@ -965,6 +1239,19 @@ int proc_dointvec_minmax(struct ctl_table *table, int write, do_proc_dointvec_minmax_conv, ¶m); } +#ifdef MY_DEF_HERE +extern void watchdog_hrtimer_inc(void); +static int proc_dointvec_minmax_hardlockup_panic(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + /* update the hrtimer to avoid hardlockup misjudgement */ + if (write) { + watchdog_hrtimer_inc(); + } + return proc_dointvec_minmax(table , write, buffer, lenp, ppos); +} +#endif /* MY_DEF_HERE */ + /** * struct do_proc_douintvec_minmax_conv_param - proc_douintvec_minmax() range checking structure * @min: pointer to minimum allowable value @@ -1550,6 +1837,189 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, return err; } +#ifdef MY_ABC_HERE +/** + * Notice: In order to call this handler, the input array of strings + * must be in continuous memory allocation + * such as str[arrayindex][string] + * + * Each string must be null terminated + * + * The extra1 parameter should pass the array size + * + * The extra2 parameter should pass the size of an array entry + * + * The output of this function will be one string per line + */ +int syno_proc_do_string_vector(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + char *pStr = (char *)table->data; + int *pArraySize = (int *)table->extra1; + int *pEntrySize = (int *)table->extra2; + int iMaxLen = table->maxlen; + size_t iLen = 0; + size_t iLenSum = 0; + char stBuf[512] = {'\0'}; + char *pBuf = stBuf; + int iArrayIndex = 0; + + if (!pArraySize || !(*pArraySize) || !pEntrySize || !(*pEntrySize) || !iMaxLen || !(*lenp)) { + *lenp = 0; + return 0; + } + + if (write) { + // do nothing + } else { + // move to desired array index iArrayIndex and offset pStr + iLenSum = 0; + for (iArrayIndex = 0; iArrayIndex < *pArraySize; iArrayIndex++) { + iLen = strlen(pStr); + if (0 == iLen) { + break; + } + if (iLenSum + iLen + 1 > *ppos) { + pStr += *ppos - iLenSum; + iLenSum = *ppos; + break; + } else { + pStr += *pEntrySize; + iLenSum += iLen + 1; + } + } + + // print macs + for (; iArrayIndex < *pArraySize; iArrayIndex++) { + iLen = strlen(pStr); + if (0 == iLen) { + break; + } + strncpy(pBuf, pStr, iLen); + pBuf[iLen] = '\n'; + iLenSum += iLen + 1; + pBuf += iLen + 1; + pStr = ((char *)table->data) + (iArrayIndex + 1) * (*pEntrySize); + } + + memcpy(buffer, stBuf, iLenSum - *ppos); + + *lenp = iLenSum - *ppos; + *ppos = iLenSum; + } + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +/** + * Read: + * The first element is the total length of array. ex: + * 5 0 1 0 0 0 + * + * Write: + * First is the value wanted to set. + * Element after second is the index wanted to set. ex: + * 0 2 3 4 + * The example will reset arr[2], arr[3], arr[4] to 0 + */ +int syno_proc_do_int_vector(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int *i, vleft, first = 1, err = 0, writeVal = 0, getWriteVal = 0; + unsigned long page = 0; + size_t left; + char *kbuf; + + if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { + *lenp = 0; + return 0; + } + + i = (int *) table->data; + vleft = table->maxlen / sizeof(*i); + left = *lenp; + + if (write) { + if (*ppos) { + switch (sysctl_writes_strict) { + case SYSCTL_WRITES_STRICT: + goto out; + case SYSCTL_WRITES_WARN: + warn_sysctl_write(table); + break; + default: + break; + } + } + + if (left > PAGE_SIZE - 1) + left = PAGE_SIZE - 1; + page = __get_free_page(__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_RECLAIMABLE); + kbuf = (char *) page; + if (!kbuf) + return -ENOMEM; + if (copy_from_user(kbuf, buffer, left)) { + err = -EFAULT; + goto free; + } + kbuf[left] = 0; + } + + for (; left && vleft--; i++, first=0) { + unsigned long lval; + bool neg; + + if (write) { + left -= proc_skip_spaces(&kbuf); + + if (!left) + break; + err = proc_get_long(&kbuf, &left, &lval, &neg, + proc_wspace_sep, + sizeof(proc_wspace_sep), NULL); + if (err) + break; + if (0 == getWriteVal) { + getWriteVal = 1; + writeVal = lval; + continue; + } + if (lval >= (table->maxlen / sizeof(*i)) || neg) { + err = -EINVAL; + break; + } + ((int*)table->data)[lval] = writeVal; + } else { + if (do_proc_dointvec_conv(&neg, &lval, i, 0, NULL)) { + err = -EINVAL; + break; + } + if (!first) + proc_put_char(&buffer, &left, '\t'); + + proc_put_long(&buffer, &left, lval, neg); + } + } + + if (!write && !first && left && !err) + proc_put_char(&buffer, &left, '\n'); + if (write && !err && left) + left -= proc_skip_spaces(&kbuf); +free: + if (write) { + free_page(page); + if (first) + return err ? : -EINVAL; + } + *lenp -= left; +out: + *ppos += *lenp; + return err; +} +#endif /* MY_ABC_HERE */ + #else /* CONFIG_PROC_SYSCTL */ int proc_dostring(struct ctl_table *table, int write, @@ -1618,6 +2088,22 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, return -ENOSYS; } +#ifdef MY_ABC_HERE +int syno_proc_do_string_vector(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + return -ENOSYS; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int syno_proc_do_int_vector(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return -ENOSYS; +} +#endif /* MY_ABC_HERE */ + #endif /* CONFIG_PROC_SYSCTL */ #if defined(CONFIG_SYSCTL) @@ -1651,6 +2137,11 @@ int proc_do_static_key(struct ctl_table *table, int write, return ret; } +#ifdef MY_ABC_HERE +int gSynoSwapFlag = 0; +EXPORT_SYMBOL(gSynoSwapFlag); +#endif /* MY_ABC_HERE */ + static struct ctl_table kern_table[] = { { .procname = "sched_child_runs_first", @@ -2346,7 +2837,11 @@ static struct ctl_table kern_table[] = { .data = &hardlockup_panic, .maxlen = sizeof(int), .mode = 0644, +#ifdef MY_DEF_HERE + .proc_handler = proc_dointvec_minmax_hardlockup_panic, +#else /* MY_DEF_HERE */ .proc_handler = proc_dointvec_minmax, +#endif /* MY_DEF_HERE */ .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, @@ -2519,6 +3014,24 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &neg_one, }, +#ifdef MY_ABC_HERE + { + .procname = "hung_task_warnings_default", + .data = &sysctl_hung_task_warnings_default, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &neg_one, + }, + { + .procname = "hung_task_warnings_reset_period", + .data = &sysctl_hung_task_warnings_reset_period, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &neg_one, + }, +#endif /* MY_ABC_HERE */ #endif #ifdef CONFIG_RT_MUTEXES { @@ -2661,6 +3174,261 @@ static struct ctl_table kern_table[] = { .extra2 = SYSCTL_ONE, }, #endif +#ifdef MY_ABC_HERE + { + .procname = "syno_hw_version", + .data = gszSynoHWVersion, + .maxlen = 16, + .mode = 0444, + .proc_handler = proc_dostring, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_hw_revision", + .data = gszSynoHWRevision, + .maxlen = 4, + .mode = 0444, + .proc_handler = proc_dostring, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_serial", + .data = &gszSerialNum, + .maxlen = 32, + .mode = 0444, + .proc_handler = proc_dostring, + }, + { + .procname = "syno_custom_serial", + .data = &gszCustomSerialNum, + .maxlen = 32, + .mode = 0444, + .proc_handler = proc_dostring, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_internal_netif_num", + .data = &g_internal_netif_num, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_mac_address1", + .data = &grgbLanMac[0], + .maxlen = 16, + .mode = 0444, + .proc_handler = proc_dostring, + }, + { + .procname = "syno_mac_address2", + .data = &grgbLanMac[1], + .maxlen = 16, + .mode = 0444, + .proc_handler = proc_dostring, + }, + { + .procname = "syno_mac_address3", + .data = &grgbLanMac[2], + .maxlen = 16, + .mode = 0444, + .proc_handler = proc_dostring, + }, + { + .procname = "syno_mac_address4", + .data = &grgbLanMac[3], + .maxlen = 16, + .mode = 0444, + .proc_handler = proc_dostring, + }, + { + .procname = "syno_mac_addresses", + .data = &grgbLanMac, + .maxlen = sizeof(grgbLanMac), + .mode = 0444, + .proc_handler = syno_proc_do_string_vector, + .extra1 = &iSynoMacMax, + .extra2 = &iMacEntrySize, + }, + { + .procname = "syno_skip_vender_mac_interfaces", + .data = &gszSkipVenderMacInterfaces, + .maxlen = 256, + .mode = 0444, + .proc_handler = proc_dostring, + }, + { + .procname = "syno_vender_format_version", + .data = &giVenderFormatVersion, + .maxlen = sizeof (int), + .mode = 0444, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + { + .procname = "syno_internal_hd_num", + .data = &g_syno_hdd_powerup_seq, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "syno_disks_group", + .data = &guiWakeupDisksNum, + .maxlen = sizeof (unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "syno_spinup_group_delay", + .data = &giSynoSpinupGroupDelay, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "syno_spinup_group_debug", + .data = &giSynoSpinupGroupDebug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_DEF_HERE */ +#ifdef MY_DEF_HERE + { + .procname = "syno_is_sas_model", + .data = &g_is_sas_model, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_CPU_info_core", + .data = &gSynoCPUInfoCore, + .maxlen = sizeof (unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#ifdef MY_DEF_HERE + { + .procname = "syno_CPU_info_multicore_1", + .data = &gSynoMultiCPUInfoCore[0], + .maxlen = sizeof (unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "syno_CPU_info_multicore_2", + .data = &gSynoMultiCPUInfoCore[1], + .maxlen = sizeof (unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_DEF_HERE */ + { + .procname = "syno_CPU_info_clock", + .data = &gSynoCPUInfoClock, + .maxlen = 16, + .mode = 0644, + .proc_handler = proc_dostring, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_unsupported_sfp_notify", + .data = &gSynoSfpUnsupportNotify, + .maxlen = sizeof(gSynoSfpUnsupportNotify), + .mode = 0644, + .proc_handler = syno_proc_do_int_vector, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_swap_flag", + .data = &gSynoSwapFlag, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_reset_flag", + .data = &gSynoResetFlag, + .maxlen = sizeof (int), + .mode = 0444, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_install_flag", + .data = &gSynoInstallFlag, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /*MY_ABC_HERE*/ +#ifdef MY_ABC_HERE + { + .procname = "syno_forbid_console", + .data = &gSynoForbidConsole, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_forbid_usb", + .data = &gSynoForbidUsb, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_disk_ready_check", + .data = &gSynoDiskReadyCheck, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = proc_dointvec_disk_ready_check, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_disk_seq_valid_bytes_threshold", + .data = &SynoDiskSeqValidBytesThreshold, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "syno_disk_seq_valid_skip_bytes", + .data = &SynoDiskSeqValidSkipBytes, + .maxlen = sizeof (unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + { + .procname = "syno_ata_debug", + .data = &gSynoAtaDebug, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif /* MY_ABC_HERE */ { } }; @@ -2904,6 +3672,17 @@ static struct ctl_table vm_table[] = { .extra1 = SYSCTL_ONE, .extra2 = &one_thousand, }, +#ifdef MY_ABC_HERE + { + .procname = "kswapd_threads", + .data = &kswapd_threads, + .maxlen = sizeof(kswapd_threads), + .mode = 0644, + .proc_handler = kswapd_threads_sysctl_handler, + .extra1 = SYSCTL_ONE, + .extra2 = &max_kswapd_threads, + }, +#endif /* MY_ABC_HERE */ { .procname = "percpu_pagelist_fraction", .data = &percpu_pagelist_fraction, @@ -3247,7 +4026,14 @@ static struct ctl_table fs_table[] = { .mode = 0555, .child = inotify_table, }, -#endif +#endif +#ifdef MY_ABC_HERE + { + .procname = "synotify", + .mode = 0555, + .child = synotify_table, + }, +#endif /* MY_ABC_HERE */ #ifdef CONFIG_EPOLL { .procname = "epoll", @@ -3421,3 +4207,107 @@ EXPORT_SYMBOL(proc_dostring); EXPORT_SYMBOL(proc_doulongvec_minmax); EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); EXPORT_SYMBOL(proc_do_large_bitmap); + +#ifdef MY_ABC_HERE +int syno_is_hw_version(const char *hw_version) +{ + if (NULL == hw_version) { + return 0; + } + + if (0 == strcmp(gszSynoHWVersion, hw_version)) { + return 1; + } else { + return 0; + } +} +EXPORT_SYMBOL(syno_is_hw_version); + +char* syno_get_hw_version(void) +{ + return gszSynoHWVersion; +} +EXPORT_SYMBOL(syno_get_hw_version); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int syno_is_hw_revision(const char *hw_revision) +{ + if (NULL == hw_revision) { + return 0; + } + + if (0 == strcmp(gszSynoHWRevision, hw_revision)) { + return 1; + } else { + return 0; + } +} +EXPORT_SYMBOL(syno_is_hw_revision); + +char* syno_get_hw_revision(void) +{ + return gszSynoHWRevision; +} +EXPORT_SYMBOL(syno_get_hw_revision); +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +int (*funcSYNOReadAdtPeci)(struct _SynoCpuTemp *) = NULL; +EXPORT_SYMBOL(funcSYNOReadAdtPeci); +int (*funcSYNOReadAdtFanSpeedRpm)(struct _SYNO_HWMON_SENSOR_TYPE *) = NULL; +EXPORT_SYMBOL(funcSYNOReadAdtFanSpeedRpm); +int (*funcSYNOReadAdtVoltageSensor)(struct _SYNO_HWMON_SENSOR_TYPE *) = NULL; +EXPORT_SYMBOL(funcSYNOReadAdtVoltageSensor); +int (*funcSYNOReadAdtThermalSensor)(struct _SYNO_HWMON_SENSOR_TYPE *) = NULL; +EXPORT_SYMBOL(funcSYNOReadAdtThermalSensor); +int (*funcSYNOReadAdtFanSpeedRpmByOrder)(struct _SYNO_HWMON_SENSOR_TYPE *, struct _SYNO_HWMON_FAN_ORDER *) = NULL; +EXPORT_SYMBOL(funcSYNOReadAdtFanSpeedRpmByOrder); + +int syno_get_adt_peci(struct _SynoCpuTemp *cpu_temp) +{ + int ret = -1; + if (funcSYNOReadAdtPeci) { + ret = funcSYNOReadAdtPeci(cpu_temp); + } + return ret; +} +EXPORT_SYMBOL(syno_get_adt_peci); +int syno_get_adt_fan_speed_rpm(struct _SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm) +{ + int ret = -1; + if (funcSYNOReadAdtFanSpeedRpm) { + ret = funcSYNOReadAdtFanSpeedRpm(FanSpeedRpm); + } + return ret; +} +EXPORT_SYMBOL(syno_get_adt_fan_speed_rpm); +int syno_get_adt_thermal_sensor(struct _SYNO_HWMON_SENSOR_TYPE *SysThermal) +{ + int ret = -1; + if (funcSYNOReadAdtThermalSensor) { + ret = funcSYNOReadAdtThermalSensor(SysThermal); + } + return ret; + +} +EXPORT_SYMBOL(syno_get_adt_thermal_sensor); +int syno_get_adt_voltage_sensor(struct _SYNO_HWMON_SENSOR_TYPE *SysVoltage) +{ + int ret = -1; + if (funcSYNOReadAdtVoltageSensor) { + ret = funcSYNOReadAdtVoltageSensor(SysVoltage); + } + return ret; +} +EXPORT_SYMBOL(syno_get_adt_voltage_sensor); +int syno_get_adt_fan_speed_rpm_by_order(struct _SYNO_HWMON_SENSOR_TYPE *FanSpeedRpm, struct _SYNO_HWMON_FAN_ORDER *FanOrder) +{ + int ret = -1; + if (funcSYNOReadAdtFanSpeedRpmByOrder) { + ret = funcSYNOReadAdtFanSpeedRpmByOrder(FanSpeedRpm, FanOrder); + } + return ret; +} +EXPORT_SYMBOL(syno_get_adt_fan_speed_rpm_by_order); +#endif /* MY_ABC_HERE */ diff --git a/kernel/task_work.c b/kernel/task_work.c index 8d6e1217c451..6a1304ba435a 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 #include #include @@ -154,3 +157,6 @@ void task_work_run(void) } while (work); } } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(task_work_run); +#endif /* MY_ABC_HERE */ diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 069ca78fb0bf..dabf494822b6 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * NTP state machine interfaces and logic. @@ -570,6 +573,10 @@ static bool sync_cmos_clock(void) int rc = -EPROTO; long target_nsec = NSEC_PER_SEC / 2; +#ifdef MY_ABC_HERE + return false; +#endif + if (!IS_ENABLED(CONFIG_GENERIC_CMOS_UPDATE)) return false; diff --git a/kernel/time/time.c b/kernel/time/time.c index 3985b2b32d08..d98c6636bddb 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 1991, 1992 Linus Torvalds @@ -187,8 +190,12 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz update_vsyscall_tz(); if (firsttime) { firsttime = 0; +#ifdef MY_ABC_HERE +/* Keep UTC Time In Kernel And RTC */ +#else if (!tv) timekeeping_warp_clock(); +#endif /* MY_ABC_HERE */ } } if (tv) diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index f1022945e346..9781ee9ee830 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2006 Jens Axboe @@ -76,6 +79,10 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action, int cpu = smp_processor_id(); bool blk_tracer = blk_tracer_enabled; ssize_t cgid_len = cgid ? sizeof(cgid) : 0; +#ifdef MY_ABC_HERE + struct rchan_buf *buf = NULL; + unsigned long flags = 0; +#endif /* MY_ABC_HERE */ if (blk_tracer) { buffer = blk_tr->array_buffer.buffer; @@ -92,6 +99,10 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action, if (!bt->rchan) return; +#ifdef MY_ABC_HERE + buf = *get_cpu_ptr(bt->rchan->buf); + spin_lock_irqsave(&buf->lock, flags); +#endif /* MY_ABC_HERE */ t = relay_reserve(bt->rchan, sizeof(*t) + len + cgid_len); if (t) { t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; @@ -109,6 +120,12 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action, if (blk_tracer) trace_buffer_unlock_commit(blk_tr, buffer, event, 0, pc); } +#ifdef MY_ABC_HERE + if (!blk_tracer) { + spin_unlock_irqrestore(&buf->lock, flags); + put_cpu_ptr(bt->rchan->buf); + } +#endif /* MY_ABC_HERE */ } /* @@ -226,6 +243,9 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, int cpu, pc = 0; bool blk_tracer = blk_tracer_enabled; ssize_t cgid_len = cgid ? sizeof(cgid) : 0; +#ifdef MY_ABC_HERE + struct rchan_buf *buf = NULL; +#endif /* MY_ABC_HERE */ if (unlikely(bt->trace_state != Blktrace_running && !blk_tracer)) return; @@ -270,7 +290,12 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, * some space in the relay per-cpu buffer, to prevent an irq * from coming in and stepping on our toes. */ +#ifdef MY_ABC_HERE + buf = *get_cpu_ptr(bt->rchan->buf); + spin_lock_irqsave(&buf->lock, flags); +#else local_irq_save(flags); +#endif /* MY_ABC_HERE */ t = relay_reserve(bt->rchan, sizeof(*t) + pdu_len + cgid_len); if (t) { sequence = per_cpu_ptr(bt->sequence, cpu); @@ -306,7 +331,12 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, } } +#ifdef MY_ABC_HERE + spin_unlock_irqrestore(&buf->lock, flags); + put_cpu_ptr(bt->rchan->buf); +#else local_irq_restore(flags); +#endif /* MY_ABC_HERE */ } static void blk_trace_free(struct blk_trace *bt) diff --git a/kernel/ucount.c b/kernel/ucount.c index 9894795043c4..11b1596e2542 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -8,12 +8,6 @@ #include #include -struct ucounts init_ucounts = { - .ns = &init_user_ns, - .uid = GLOBAL_ROOT_UID, - .count = 1, -}; - #define UCOUNTS_HASHTABLE_BITS 10 static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)]; static DEFINE_SPINLOCK(ucounts_lock); @@ -131,15 +125,7 @@ static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struc return NULL; } -static void hlist_add_ucounts(struct ucounts *ucounts) -{ - struct hlist_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid); - spin_lock_irq(&ucounts_lock); - hlist_add_head(&ucounts->node, hashent); - spin_unlock_irq(&ucounts_lock); -} - -struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid) +static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid) { struct hlist_head *hashent = ucounts_hashentry(ns, uid); struct ucounts *ucounts, *new; @@ -174,26 +160,7 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid) return ucounts; } -struct ucounts *get_ucounts(struct ucounts *ucounts) -{ - unsigned long flags; - - if (!ucounts) - return NULL; - - spin_lock_irqsave(&ucounts_lock, flags); - if (ucounts->count == INT_MAX) { - WARN_ONCE(1, "ucounts: counter has reached its maximum value"); - ucounts = NULL; - } else { - ucounts->count += 1; - } - spin_unlock_irqrestore(&ucounts_lock, flags); - - return ucounts; -} - -void put_ucounts(struct ucounts *ucounts) +static void put_ucounts(struct ucounts *ucounts) { unsigned long flags; @@ -227,7 +194,7 @@ struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, { struct ucounts *ucounts, *iter, *bad; struct user_namespace *tns; - ucounts = alloc_ucounts(ns, uid); + ucounts = get_ucounts(ns, uid); for (iter = ucounts; iter; iter = tns->ucounts) { int max; tns = iter->ns; @@ -270,7 +237,6 @@ static __init int user_namespace_sysctl_init(void) BUG_ON(!user_header); BUG_ON(!setup_userns_sysctls(&init_user_ns)); #endif - hlist_add_ucounts(&init_ucounts); return 0; } subsys_initcall(user_namespace_sysctl_init); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 8206a13c81eb..ce396ea4de60 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -1340,9 +1340,6 @@ static int userns_install(struct nsset *nsset, struct ns_common *ns) put_user_ns(cred->user_ns); set_cred_user_ns(cred, get_user_ns(user_ns)); - if (set_cred_ucounts(cred) < 0) - return -EINVAL; - return 0; } diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 01bf977090dc..b7f808bac0f8 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Detect hard and soft lockups on a system @@ -50,7 +53,11 @@ unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask); #ifdef CONFIG_HARDLOCKUP_DETECTOR # ifdef CONFIG_SMP +#ifdef MY_ABC_HERE +int __read_mostly sysctl_hardlockup_all_cpu_backtrace = 1; +#else /* MY_ABC_HERE */ int __read_mostly sysctl_hardlockup_all_cpu_backtrace; +#endif /* MY_ABC_HERE */ # endif /* CONFIG_SMP */ /* @@ -157,7 +164,11 @@ static void lockup_detector_update_enable(void) #define SOFTLOCKUP_RESET ULONG_MAX #ifdef CONFIG_SMP +#ifdef MY_ABC_HERE +int __read_mostly sysctl_softlockup_all_cpu_backtrace = 1; +#else /* MY_ABC_HERE */ int __read_mostly sysctl_softlockup_all_cpu_backtrace; +#endif /* MY_ABC_HERE */ #endif static struct cpumask watchdog_allowed_mask __read_mostly; @@ -174,6 +185,9 @@ static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer); static DEFINE_PER_CPU(bool, softlockup_touch_sync); static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts); static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); +#ifdef MY_ABC_HERE +static DEFINE_PER_CPU(unsigned long, softlockup_counter); +#endif /* MY_ABC_HERE */ static unsigned long soft_lockup_nmi_warn; static int __init nowatchdog_setup(char *str) @@ -317,6 +331,18 @@ static void watchdog_interrupt_count(void) __this_cpu_inc(hrtimer_interrupts); } +#ifdef MY_DEF_HERE +/* update hrtimer for each watchdog enabled CPU */ +void watchdog_hrtimer_inc(void) +{ + int cpu; + for_each_cpu(cpu, &watchdog_allowed_mask) { + ++per_cpu(hrtimer_interrupts, cpu); + } +} +EXPORT_SYMBOL(watchdog_hrtimer_inc); +#endif /* MY_DEF_HERE */ + static DEFINE_PER_CPU(struct completion, softlockup_completion); static DEFINE_PER_CPU(struct cpu_stop_work, softlockup_stop_work); @@ -402,6 +428,17 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) return HRTIMER_RESTART; } +#ifdef MY_ABC_HERE + if (__this_cpu_read(softlockup_counter) >= CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX) { + if (softlockup_all_cpu_backtrace) { + clear_bit_unlock(0, &soft_lockup_nmi_warn); + } + return HRTIMER_RESTART; + } else { + __this_cpu_inc(softlockup_counter); + } +#endif /* MY_ABC_HERE */ + /* Start period for the next softlockup warning. */ update_touch_ts(); diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c index 247bf0b1582c..bfe30234a831 100644 --- a/kernel/watchdog_hld.c +++ b/kernel/watchdog_hld.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Detect hard lockups on a system @@ -29,6 +32,10 @@ static struct cpumask dead_events_mask; static unsigned long hardlockup_allcpu_dumped; static atomic_t watchdog_cpus = ATOMIC_INIT(0); +#ifdef MY_DEF_HERE +#define SYNO_HARDLOCKUP_WATCHDOG_THRESH 60 +#endif /* MY_DEF_HERE */ + notrace void arch_touch_nmi_watchdog(void) { /* @@ -129,6 +136,10 @@ static void watchdog_overflow_callback(struct perf_event *event, * then this is a good indication the cpu is stuck */ if (is_hardlockup()) { +#ifdef MY_DEF_HERE + /* save hardlockup_panic to avoid enable during printing calltrace */ + unsigned int panic_backup = hardlockup_panic; +#endif /* MY_DEF_HERE */ int this_cpu = smp_processor_id(); /* only print hardlockups once */ @@ -152,7 +163,11 @@ static void watchdog_overflow_callback(struct perf_event *event, !test_and_set_bit(0, &hardlockup_allcpu_dumped)) trigger_allbutself_cpu_backtrace(); +#ifdef MY_DEF_HERE + if (panic_backup) +#else /* MY_DEF_HERE */ if (hardlockup_panic) +#endif /* MY_DEF_HERE */ nmi_panic(regs, "Hard LOCKUP"); __this_cpu_write(hard_watchdog_warn, true); @@ -170,7 +185,11 @@ static int hardlockup_detector_event_create(void) struct perf_event *evt; wd_attr = &wd_hw_attr; +#ifdef MY_DEF_HERE + wd_attr->sample_period = hw_nmi_get_sample_period(SYNO_HARDLOCKUP_WATCHDOG_THRESH); +#else /* MY_DEF_HERE */ wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); +#endif /* MY_DEF_HERE */ /* Try to register using hardware perf events */ evt = perf_event_create_kernel_counter(wd_attr, cpu, NULL, diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 51d19fc71e61..29c8caf4a5ed 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * kernel/workqueue.c - generic async execution with shared worker pool @@ -106,7 +109,10 @@ enum { RESCUER_NICE_LEVEL = MIN_NICE, HIGHPRI_NICE_LEVEL = MIN_NICE, +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ WQ_NAME_LEN = 24, +#endif /* MY_ABC_HERE */ }; /* @@ -267,6 +273,10 @@ struct workqueue_struct { #endif char name[WQ_NAME_LEN]; /* I: workqueue name */ +#ifdef MY_ABC_HERE + atomic64_t timer_sampled_us; /* Sample count by timer interrput */ +#endif /* MY_ABC_HERE */ + /* * Destruction of workqueue_struct is RCU protected to allow walking * the workqueues list without grabbing wq_pool_mutex. @@ -2267,7 +2277,12 @@ __acquires(&pool->lock) */ lockdep_invariant_state(true); trace_workqueue_execute_start(work); +#ifdef MY_ABC_HERE + worker_run_work(worker, work); +#else worker->current_func(work); +#endif /* MY_ABC_HERE */ + /* * While we must be careful to not use "work" after this, the trace * point will only record its address. @@ -5415,9 +5430,23 @@ static ssize_t max_active_store(struct device *dev, } static DEVICE_ATTR_RW(max_active); +#ifdef MY_ABC_HERE +static ssize_t timer_sampled_us_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct workqueue_struct *wq = dev_to_wq(dev); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", (u64)atomic64_read(&wq->timer_sampled_us)); +} +static DEVICE_ATTR_RO(timer_sampled_us); +#endif /* MY_ABC_HERE */ + static struct attribute *wq_sysfs_attrs[] = { &dev_attr_per_cpu.attr, &dev_attr_max_active.attr, +#ifdef MY_ABC_HERE + &dev_attr_timer_sampled_us.attr, +#endif /* MY_ABC_HERE */ NULL, }; ATTRIBUTE_GROUPS(wq_sysfs); @@ -5879,6 +5908,31 @@ static void wq_watchdog_init(void) static inline void wq_watchdog_init(void) { } #endif /* CONFIG_WQ_WATCHDOG */ +#ifdef MY_ABC_HERE +struct workqueue_struct* get_pwq_wq(struct pool_workqueue *pwq) +{ + if (pwq) + return pwq->wq; + return NULL; +} +EXPORT_SYMBOL(get_pwq_wq); + +void account_workqueue_time(struct task_struct *p, u64 us, gfp_t gfp) +{ + struct work_acct *acct; + if (!p) + return; + + acct = p->workacct; + if (!acct) + return; + + if (acct->wq && (acct->wq->flags & WQ_SYSFS)) + atomic64_add(us, &acct->wq->timer_sampled_us); + account_work_time(acct, us, gfp); +} +EXPORT_SYMBOL(account_workqueue_time); +#endif /* MY_ABC_HERE */ static void __init wq_numa_init(void) { diff --git a/kernel/workqueue_internal.h b/kernel/workqueue_internal.h index 498de0e909a4..be75234b0441 100644 --- a/kernel/workqueue_internal.h +++ b/kernel/workqueue_internal.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 */ /* * kernel/workqueue_internal.h @@ -77,4 +80,29 @@ void wq_worker_running(struct task_struct *task); void wq_worker_sleeping(struct task_struct *task); work_func_t wq_worker_last_func(struct task_struct *task); +#ifdef MY_ABC_HERE +/* For in-thread I/O accumulation. We don't need atomic ops */ +struct work_io_acct { + unsigned long last_update_jiffies; + + /* + * Please refer to task_io_accounting.h for the following + * I/O statistics + */ + u64 read_bytes; + u64 write_bytes; + u64 cancelled_write_bytes; +}; + +struct work_acct { + struct workqueue_struct *wq; + work_func_t func; + struct work_io_acct io_acct; +}; + +void worker_run_work(struct worker *worker, struct work_struct *work); +void account_work_time(struct work_acct *acct, u64 us, gfp_t gfp); +struct workqueue_struct* get_pwq_wq(struct pool_workqueue *pwq); +#endif /* MY_ABC_HERE */ + #endif /* _KERNEL_WORKQUEUE_INTERNAL_H */ diff --git a/kernel/workstat.c b/kernel/workstat.c new file mode 100644 index 000000000000..d8b050b568d0 --- /dev/null +++ b/kernel/workstat.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "workqueue_internal.h" + +#define KWORK_IO_STAT_UPDATE_RATE_MS 250 + +struct workstat { + /* corresponding work function */ + work_func_t func; + + /** + * Please refer to task_io_accounting.h for the following + * I/O statistics + */ + atomic64_t read_bytes; + atomic64_t write_bytes; + atomic64_t cancelled_write_bytes; + + /* timer_sampled_us */ + atomic64_t timer_sampled_us; + + /* rb tree node */ + struct rb_node node; +}; + +struct workstat_records { + rwlock_t lock; /* lock for the tree and enable */ + u32 enable; /* 1: enable. 0: disable */ + struct rb_root tree_root; +}; + +static struct workstat_records workstat_records = {0}; + +/** + * Copy work_io_acct from task_io_accounting and init jiffies + */ +static inline void reset_work_io_acct(struct task_io_accounting *ioac, + struct work_io_acct *acct) +{ + acct->read_bytes = ioac->read_bytes; + acct->write_bytes = ioac->write_bytes; + acct->cancelled_write_bytes = ioac->cancelled_write_bytes; + acct->last_update_jiffies = jiffies; +} + +/** + * diff = ioac - acct + * Return true if any non-zero value in acct + */ +static inline bool diff_work_io_acct(struct work_io_acct *diff, + const struct task_io_accounting *ioac, + const struct work_io_acct *acct) +{ + diff->read_bytes = ioac->read_bytes + - acct->read_bytes; + diff->write_bytes = ioac->write_bytes + - acct->write_bytes; + diff->cancelled_write_bytes = ioac->cancelled_write_bytes + - acct->cancelled_write_bytes; + return (diff->read_bytes || diff->write_bytes || + diff->cancelled_write_bytes); +} + +/** + * Allocate and init workstat. + * + * Return: Pointer to workstat on success and NULL on failure + */ +static inline struct workstat *alloc_workstat(work_func_t func, gfp_t gfp) +{ + struct workstat *stat = kzalloc(sizeof(struct workstat), gfp); + + if (!stat) + return NULL; + + stat->func = func; + + return stat; +} + +/** + * Search records by func. + * + * Return workstat* if we found it and NULL if not found + * CONTEXT: read_lock(workstat_records.lock) + */ +static inline struct workstat * +workstat_records_search(struct workstat_records *records, work_func_t func) +{ + struct workstat *curr; + struct rb_node *n = records->tree_root.rb_node; + + while (n) { + curr = rb_entry(n, struct workstat, node); + if (func < curr->func) + n = n->rb_left; + else if (func > curr->func) + n = n->rb_right; + else + return curr; + } + return NULL; +} + +/** + * CONTEXT: write_lock(workstat_records.lock) + */ +static inline struct workstat * +workstat_records_insert(struct workstat_records *records, struct workstat *ins) +{ + struct rb_node **link = &records->tree_root.rb_node; + struct rb_node *parent = NULL; + struct workstat *curr = NULL; + + while (*link) { + parent = *link; + curr = rb_entry(parent, struct workstat, node); + + if (ins->func < curr->func) + link = &((*link)->rb_left); + else if (ins->func > curr->func) + link = &((*link)->rb_right); + else + return curr; + } + + /* add new node and rebalance tree. */ + rb_link_node(&ins->node, parent, link); + rb_insert_color(&ins->node, &records->tree_root); + + return NULL; +} + +static inline bool try_alloc_insert_workstat(struct workstat_records *records, + work_func_t func, gfp_t gfp) +{ + struct workstat *stat; + void *exist; + unsigned long flags; + + stat = alloc_workstat(func, gfp); + if (!stat) + return false; + + write_lock_irqsave(&records->lock, flags); + exist = workstat_records_insert(records, stat); + write_unlock_irqrestore(&records->lock, flags); + if (exist) { + /* We may race with other insertions */ + kfree(stat); + } + return true; +} + +/** + * CONTEXT: write_lock(workstat_records.lock) + */ +static void workstat_records_reset(struct workstat_records *records) +{ + struct workstat *stat; + struct rb_node *curr; + + while (!RB_EMPTY_ROOT(&records->tree_root)) { + curr = rb_first(&records->tree_root); + stat = rb_entry(curr, struct workstat, node); + rb_erase(&stat->node, &records->tree_root); + kfree(stat); + } +} + +static void update_kwork_io_stat(struct task_struct *p, gfp_t gfp) +{ + struct work_acct *acct; + struct workstat *stat; + struct work_io_acct io_diff; + unsigned long flags; + + if (!p || !workstat_records.enable) + return; + + acct = p->workacct; + if (!acct || !diff_work_io_acct(&io_diff, &p->ioac, &acct->io_acct)) + return; + + /* + * We will leave some records if we are racing with disabling + * workstat_records. That is safe. + */ + read_lock_irqsave(&workstat_records.lock, flags); + stat = workstat_records_search(&workstat_records, acct->func); + if (likely(stat)) { + /* accumulate workstat */ + atomic64_add(io_diff.read_bytes, &stat->read_bytes); + atomic64_add(io_diff.write_bytes, &stat->write_bytes); + atomic64_add(io_diff.cancelled_write_bytes, &stat->cancelled_write_bytes); + read_unlock_irqrestore(&workstat_records.lock, flags); + + reset_work_io_acct(&p->ioac, &acct->io_acct); + } else { + read_unlock_irqrestore(&workstat_records.lock, flags); + /* + * It's ok if we alloc memory failed. + * We will have another try next time. + */ + try_alloc_insert_workstat(&workstat_records, acct->func, gfp); + } +} + +void update_kwork_io_stat_ratelimited(struct task_struct *p, gfp_t gfp) +{ + if (!p || !p->workacct) { + return; + } + + if (jiffies_to_msecs(jiffies - p->workacct->io_acct.last_update_jiffies) + < KWORK_IO_STAT_UPDATE_RATE_MS) + return; + + update_kwork_io_stat(p, gfp); +} +EXPORT_SYMBOL(update_kwork_io_stat_ratelimited); + +void worker_run_work(struct worker *worker, struct work_struct *work) +{ + struct work_acct acct = {0}; + bool enable = workstat_records.enable; + + if (enable) { + reset_work_io_acct(¤t->ioac, &acct.io_acct); + acct.func = worker->current_func; + acct.wq = get_pwq_wq(worker->current_pwq); + barrier(); + /* + * Saving pointer of local variable in current should be safe. + * Please referred to current->plug. + */ + current->workacct = &acct; + } + + worker->current_func(work); + + if (enable) + update_kwork_io_stat(current, GFP_KERNEL); + + current->workacct = NULL; +} +EXPORT_SYMBOL(worker_run_work); + +void account_work_time(struct work_acct *acct, u64 us, gfp_t gfp) +{ + struct workstat *stat; + unsigned long flags; + + if (!acct || !workstat_records.enable) + return; + + read_lock_irqsave(&workstat_records.lock, flags); + stat = workstat_records_search(&workstat_records, acct->func); + if (likely(stat)) { + /* accumulate workstat */ + atomic64_add(us, &stat->timer_sampled_us); + read_unlock_irqrestore(&workstat_records.lock, flags); + } else { + read_unlock_irqrestore(&workstat_records.lock, flags); + /* + * It's ok if we alloc memory failed. + * We will have another try next time. + */ + try_alloc_insert_workstat(&workstat_records, acct->func, gfp); + } +} +EXPORT_SYMBOL(account_work_time); + +/** + * Interfaces for procfs + */ +static int workstat_stats_proc_show(struct seq_file *m, void *v) +{ + struct rb_node *n; + struct workstat *stat; + + read_lock_irq(&workstat_records.lock); + + n = rb_first(&workstat_records.tree_root); + while (n) { + stat = rb_entry(n, struct workstat, node); + seq_printf(m, "%ps: %llu %llu %llu %llu\n", + stat->func, + (u64)atomic64_read(&stat->read_bytes), + (u64)atomic64_read(&stat->write_bytes), + (u64)atomic64_read(&stat->cancelled_write_bytes), + (u64)atomic64_read(&stat->timer_sampled_us)); + n = rb_next(n); + } + + read_unlock_irq(&workstat_records.lock); + return 0; +} + +static int workstat_stats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, workstat_stats_proc_show, NULL); +} + +static const struct proc_ops workstat_stats_proc_ops = { + .proc_open = workstat_stats_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int workstat_enable_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%d", workstat_records.enable); + return 0; +} + +static int workstat_enable_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, workstat_enable_proc_show, NULL); +} + +static ssize_t workstat_enable_proc_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + u32 val; + int ret; + + if (*ppos != 0) { + /* No partial writes. */ + ret = -EINVAL; + goto out; + } + + ret = kstrtou32_from_user(buf, count, 10, &val); + if (ret < 0) + goto out; + + ret = count; + if (val == workstat_records.enable) + goto out; + + write_lock_irq(&workstat_records.lock); + workstat_records.enable = !!val; + if (!val) + workstat_records_reset(&workstat_records); + write_unlock_irq(&workstat_records.lock); + +out: + return ret; +} + +static const struct proc_ops workstat_enable_proc_ops = { + .proc_open = workstat_enable_proc_open, + .proc_read = seq_read, + .proc_write = workstat_enable_proc_write, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int __init proc_workstat_init(void) +{ + workstat_records.tree_root = RB_ROOT; + rwlock_init(&workstat_records.lock); + + if (!proc_mkdir("workstat", NULL)) + return -ENOMEM; + + if (!proc_create("workstat/stats", 0, NULL, &workstat_stats_proc_ops)) + goto err; + + if (!proc_create("workstat/enable", 0, NULL, &workstat_enable_proc_ops)) + goto err; + + workstat_records.enable = 1; + return 0; +err: + remove_proc_subtree("workstat", NULL); + return -ENOMEM; +} + +static void __exit proc_workstat_exit(void) +{ + write_lock_irq(&workstat_records.lock); + workstat_records.enable = 0; + workstat_records_reset(&workstat_records); + write_unlock_irq(&workstat_records.lock); +} + +fs_initcall(proc_workstat_init); +module_exit(proc_workstat_exit); diff --git a/lib/Kconfig b/lib/Kconfig index b46a9fd122c8..77461bc0c708 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -425,7 +425,9 @@ config TEXTSEARCH_FSM tristate config BTREE - bool + bool "Enable BTREE" + help + Enable BTREE for external kernel modules config INTERVAL_TREE bool @@ -571,7 +573,8 @@ config SIGNATURE Implementation is done using GnuPG MPI library config DIMLIB - bool + bool "Enable DIMLIB" + default n help Dynamic Interrupt Moderation library. Implements an algorithm for dynamically changing CQ moderation values diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index f271ff5fbb5a..058730ce847a 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -10,21 +10,10 @@ config HAVE_KCSAN_COMPILER For the list of compilers that support KCSAN, please see . -config KCSAN_KCOV_BROKEN - def_bool KCOV && CC_HAS_SANCOV_TRACE_PC - depends on CC_IS_CLANG - depends on !$(cc-option,-Werror=unused-command-line-argument -fsanitize=thread -fsanitize-coverage=trace-pc) - help - Some versions of clang support either KCSAN and KCOV but not the - combination of the two. - See https://bugs.llvm.org/show_bug.cgi?id=45831 for the status - in newer releases. - menuconfig KCSAN bool "KCSAN: dynamic data race detector" depends on HAVE_ARCH_KCSAN && HAVE_KCSAN_COMPILER depends on DEBUG_KERNEL && !KASAN - depends on !KCSAN_KCOV_BROKEN select STACKTRACE help The Kernel Concurrency Sanitizer (KCSAN) is a dynamic diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index 58f8d03d037b..8b7ddc244089 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -26,20 +26,9 @@ config UBSAN_TRAP the system. For some system builders this is an acceptable trade-off. -config UBSAN_KCOV_BROKEN - def_bool KCOV && CC_HAS_SANCOV_TRACE_PC - depends on CC_IS_CLANG - depends on !$(cc-option,-Werror=unused-command-line-argument -fsanitize=bounds -fsanitize-coverage=trace-pc) - help - Some versions of clang support either UBSAN or KCOV but not the - combination of the two. - See https://bugs.llvm.org/show_bug.cgi?id=45831 for the status - in newer releases. - config UBSAN_BOUNDS bool "Perform array index bounds checking" default UBSAN - depends on !UBSAN_KCOV_BROKEN help This option enables detection of directly indexed out of bounds array accesses, where the array size is known at compile time. @@ -51,7 +40,6 @@ config UBSAN_LOCAL_BOUNDS bool "Perform array local bounds checking" depends on UBSAN_TRAP depends on CC_IS_CLANG - depends on !UBSAN_KCOV_BROKEN help This option enables -fsanitize=local-bounds which traps when an exception/error is detected. Therefore, it should be enabled only diff --git a/lib/Makefile b/lib/Makefile index d415fc7067c5..9fd59028ef00 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -285,6 +285,8 @@ obj-$(CONFIG_ASN1) += asn1_decoder.o obj-$(CONFIG_FONT_SUPPORT) += fonts/ +obj-$(CONFIG_SYNO_LIBS) += synolib/ + hostprogs := gen_crc32table hostprogs += gen_crc64table clean-files := crc32table.h diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index 1cf409ef8d04..eb787a4233b7 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c @@ -650,8 +650,17 @@ STATIC inline int INIT unlzma(unsigned char *buf, long in_len, goto exit_3; } +#ifdef CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK + if (posp) { + if (get_pos(&wr) == header.dst_size) + *posp = 0; + else + *posp = rc.ptr-rc.buffer; + } +#else /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ if (posp) *posp = rc.ptr-rc.buffer; +#endif /* CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ if (!wr.flush || wr.flush(wr.buffer, wr.buffer_pos) == wr.buffer_pos) ret = 0; exit_3: diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 537bfdc8cd09..1b05d2896ceb 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -407,6 +407,7 @@ static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t by return 0; buf->ops = &page_cache_pipe_buf_ops; + buf->flags = 0; get_page(page); buf->page = page; buf->offset = offset; @@ -543,6 +544,7 @@ static size_t push_pipe(struct iov_iter *i, size_t size, break; buf->ops = &default_pipe_buf_ops; + buf->flags = 0; buf->page = page; buf->offset = 0; buf->len = min_t(ssize_t, left, PAGE_SIZE); diff --git a/lib/parser.c b/lib/parser.c index f5b3e5d7a7f9..7a5769db389f 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -11,7 +11,7 @@ #include /** - * match_one: - Determines if a string matches a simple pattern + * match_one - Determines if a string matches a simple pattern * @s: the string to examine for presence of the pattern * @p: the string containing the pattern * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match @@ -89,7 +89,7 @@ static int match_one(char *s, const char *p, substring_t args[]) } /** - * match_token: - Find a token (and optional args) in a string + * match_token - Find a token (and optional args) in a string * @s: the string to examine for token/argument pairs * @table: match_table_t describing the set of allowed option tokens and the * arguments that may be associated with them. Must be terminated with a @@ -114,7 +114,7 @@ int match_token(char *s, const match_table_t table, substring_t args[]) EXPORT_SYMBOL(match_token); /** - * match_number: scan a number in the given base from a substring_t + * match_number - scan a number in the given base from a substring_t * @s: substring to be scanned * @result: resulting integer on success * @base: base to use when converting string @@ -147,7 +147,7 @@ static int match_number(substring_t *s, int *result, int base) } /** - * match_u64int: scan a number in the given base from a substring_t + * match_u64int - scan a number in the given base from a substring_t * @s: substring to be scanned * @result: resulting u64 on success * @base: base to use when converting string @@ -174,7 +174,7 @@ static int match_u64int(substring_t *s, u64 *result, int base) } /** - * match_int: - scan a decimal representation of an integer from a substring_t + * match_int - scan a decimal representation of an integer from a substring_t * @s: substring_t to be scanned * @result: resulting integer on success * @@ -188,8 +188,30 @@ int match_int(substring_t *s, int *result) } EXPORT_SYMBOL(match_int); +/* + * match_uint - scan a decimal representation of an integer from a substring_t + * @s: substring_t to be scanned + * @result: resulting integer on success + * + * Description: Attempts to parse the &substring_t @s as a decimal integer. On + * success, sets @result to the integer represented by the string and returns 0. + * Returns -ENOMEM, -EINVAL, or -ERANGE on failure. + */ +int match_uint(substring_t *s, unsigned int *result) +{ + int err = -ENOMEM; + char *buf = match_strdup(s); + + if (buf) { + err = kstrtouint(buf, 10, result); + kfree(buf); + } + return err; +} +EXPORT_SYMBOL(match_uint); + /** - * match_u64: - scan a decimal representation of a u64 from + * match_u64 - scan a decimal representation of a u64 from * a substring_t * @s: substring_t to be scanned * @result: resulting unsigned long long on success @@ -206,7 +228,7 @@ int match_u64(substring_t *s, u64 *result) EXPORT_SYMBOL(match_u64); /** - * match_octal: - scan an octal representation of an integer from a substring_t + * match_octal - scan an octal representation of an integer from a substring_t * @s: substring_t to be scanned * @result: resulting integer on success * @@ -221,7 +243,7 @@ int match_octal(substring_t *s, int *result) EXPORT_SYMBOL(match_octal); /** - * match_hex: - scan a hex representation of an integer from a substring_t + * match_hex - scan a hex representation of an integer from a substring_t * @s: substring_t to be scanned * @result: resulting integer on success * @@ -236,7 +258,7 @@ int match_hex(substring_t *s, int *result) EXPORT_SYMBOL(match_hex); /** - * match_wildcard: - parse if a string matches given wildcard pattern + * match_wildcard - parse if a string matches given wildcard pattern * @pattern: wildcard pattern * @str: the string to be parsed * @@ -287,7 +309,7 @@ bool match_wildcard(const char *pattern, const char *str) EXPORT_SYMBOL(match_wildcard); /** - * match_strlcpy: - Copy the characters from a substring_t to a sized buffer + * match_strlcpy - Copy the characters from a substring_t to a sized buffer * @dest: where to copy to * @src: &substring_t to copy * @size: size of destination buffer @@ -310,7 +332,7 @@ size_t match_strlcpy(char *dest, const substring_t *src, size_t size) EXPORT_SYMBOL(match_strlcpy); /** - * match_strdup: - allocate a new string with the contents of a substring_t + * match_strdup - allocate a new string with the contents of a substring_t * @s: &substring_t to copy * * Description: Allocates and returns a string filled with the contents of diff --git a/lib/synolib/Makefile b/lib/synolib/Makefile new file mode 100644 index 000000000000..170fa4a0b071 --- /dev/null +++ b/lib/synolib/Makefile @@ -0,0 +1,18 @@ +# +# This is a synology util lib, +# +obj-$(CONFIG_SYNO_PORT_MAPPING_V2) += syno_pciepath_dts_pattern.o syno_fdt.o +obj-$(CONFIG_SYNO_KEXEC_TEST) += syno_kexec_test.o +obj-$(CONFIG_SYNO_PCI_OPTIONAL_SLOT) += syno_check_on_opt_pci.o +obj-$(CONFIG_SYNO_PLUGIN_INTERFACE) += syno_plugin.o +obj-$(CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY) += syno_disk_ready_check.o +obj-$(CONFIG_SYNO_SATA_SIGNAL_CHECK) += syno_sata_signal_check.o +obj-$(CONFIG_SYNO_SATA_SIGNAL_TEST) += syno_sata_signal_test.o +obj-$(CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG) += syno_uart2spi_logout.o +obj-$(CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE) += syno_jmb585_update_spi.o +obj-$(CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE) += asm116xfwdl/ +obj-$(CONFIG_SYNO_SATA_PWR_CTRL)+= syno_disk_pwr_ctrl.o +obj-$(CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY)+= syno_disk_wait_for_spindown.o +obj-$(CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP) += syno_draw_auto_remap_buffer.o +obj-$(CONFIG_SYNO_SATA_PWR_CTRL_TEST) += syno_hddpwrctl_test.o +obj-$(CONFIG_SYNO_AHCI_REG_READ_TEST) += syno_ahci_reg_read_test.o diff --git a/lib/synolib/asm116xfwdl/116xfwdl.c b/lib/synolib/asm116xfwdl/116xfwdl.c new file mode 100644 index 000000000000..5d3a1ce228b0 --- /dev/null +++ b/lib/synolib/asm116xfwdl/116xfwdl.c @@ -0,0 +1,1108 @@ +/* + * Asmedia ASM116x Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ + +#include "precomp.h" +#include "crc.h" +//#include + +#define VERSION "V1.0" +const BYTE gASM116GUID[ASM116_GUID_LENGTH] = {0x2C, 0x47, 0x67, 0x21, 0xF2, 0x73, 0x90, 0x47, 0x88, 0xF4, 0x26, 0x0C, 0xB1, 0x3E, 0x3E, 0x98}; +struct pci_dev *cur_dev; + + +struct pci_dev *Selected_pci[MAX_DEVICE_CNT]= {}; +void debugTypeSize(void); + +int ASM116SpiGetControlGrant(struct pci_dev *PciDevice); +void ASM116SpiReleaseControlGrant(struct pci_dev *PciDevice); +int ASM116ReadSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, DWORD Length); +int ASM116EraseSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl); +int ASM116BlankCheckSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, DWORD Address, DWORD BlankCheckLength); +int ASM116UpdateSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void * pSpirom, DWORD SpiromFileLength); +int ASM116VerifySpiRomFile(void * pSpirom, DWORD SpiromFileLength); +void ASM116GetOPROMandFWver(void * pSpirom, DWORD SpiromFileLength); +int verblevel = 0; +EXPORT_SYMBOL(verblevel); +unsigned char *pMemPtr = NULL; +EXPORT_SYMBOL(pMemPtr); +#include +#include +#include +#include +#include +unsigned int uiSelectedASM116x = 0; +static struct kobject *asm116XSPIObject = NULL; +#define SZ_SPI_NAME_LENGTH 128 + +void debugTypeSize(void) +{ + printk(KERN_INFO "DWORD--%x \n",(unsigned int)sizeof(DWORD)); + printk(KERN_INFO "WORD--%x \n",(unsigned int)sizeof(WORD)); + printk(KERN_INFO "BYTE--%x \n",(unsigned int)sizeof(BYTE)); + printk(KERN_INFO "int--%x \n",(unsigned int)sizeof(int)); + printk(KERN_INFO "LONG--%x \n",(unsigned int)sizeof(long)); + printk(KERN_INFO "float--%x \n",(unsigned int)sizeof(float)); + printk(KERN_INFO "u32--%x \n",(unsigned int)sizeof(u32)); + printk(KERN_INFO "u64--%x \n",(unsigned int)sizeof(u64)); +} + +// +//Procedure: ASM116SpiGetControlGrant +//Description: Get SPI control grant from SPI controller +//Input: pSpiControlExtension - SPI control extension +//Output: ASMT_SUCCESS - Get SPI control grant +// ASMT_TIMEOUT - Can't get control grant +// +int ASM116SpiGetControlGrant(struct pci_dev *PciDevice) +{ + int GrantRetry; + int BoolGrant; + + //Get SPI control request grant + GrantRetry = 0; + BoolGrant = ASMT_TIMEOUT; + while( (BoolGrant == ASMT_TIMEOUT) && (GrantRetry < GET_SPI_CONTROL_GRANT_RETRY_COUNT) ) + { + BoolGrant = SpiGetGrant(PciDevice, UTILITY_SPI_REQUEST_NUMBER); + GrantRetry++; + } + + + if(BoolGrant == ASMT_TIMEOUT) + { + printk(KERN_INFO "\nSpiFlashGetControlGrant: Can't get ASM116 SPI control grant!!!\n"); + } + + + return BoolGrant; +} + + +// +//Procedure: ASM116SpiReleaseGrant +//Description: Release request to SPI controller +//Input: pSpiControlExtension - SPI control extension +//Output: None +// +void ASM116SpiReleaseControlGrant(struct pci_dev *PciDevice) +{ + SpiReleaseGrant(PciDevice, UTILITY_SPI_REQUEST_NUMBER); + return; +} + +// +//Procedure: ASM116ReadSpiFlashRom +//Description: Erase SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// pData - Data buffer +// Address - Specific address +// Length - Read length +//Output: ASMT_SUCCESS - Erase success +// ASMT_Error - others +//Note: +// ASM 116 SPI control Grant shall be gotten by caller +// +int ASM116ReadSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void * pData, DWORD Address, DWORD Length) +{ + return(SpiFlashReadData(PciDevice,SpiControl, pData, Address, Length)); +} + + +// +//Procedure: ASM116BlankCheckSpiFlashRom +//Description: Blank check for SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// Address - Start address +// BlankCheckLengthLength - Blank check length after erased +//Output: ASMT_SUCCESS - SPI flash ROM is blank +// ASMT_SPI_BLANK_ERROR - others +// +int ASM116BlankCheckSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, DWORD Address, DWORD BlankCheckLength) +{ + DWORD i; + BYTE *pData; + BYTE bData; + + //Allocate memory for blank check + if((pData = (BYTE *)kmalloc(BlankCheckLength, GFP_KERNEL)) == NULL) + { + + printk(KERN_INFO "\nASM116BlankCheckSpiFlashRom: Allocate memory for blank check fail!!!\n"); + + + for(i = 0; i < BlankCheckLength; i++) + { + SpiFlashReadData(PciDevice,SpiControl, &bData, (Address+i), 1L); + if(bData != 0xFF) //blank + { + + printk(KERN_INFO "\nASM116BlankCheckSpiFlashRom: Blank check fail at address 0x%04X!!!\n", Address+i); + + return ASMT_SPI_BLANK_ERROR; + } + } + } + else + { + SpiFlashReadData(PciDevice,SpiControl, pData, Address, BlankCheckLength); + for(i = 0; i < BlankCheckLength; i++) + { + if(pData[i] != 0xFF) //blank + { + + printk(KERN_INFO "\nASM116BlankCheckSpiFlashRom: Blank check fail at address 0x%04X!!!\n", Address+i); + + + kfree(pData); + return ASMT_SPI_BLANK_ERROR; + } + } + kfree(pData); + } + + if(verblevel) + printk(KERN_INFO "\nASM116BlankCheckSpiFlashRom: Blank check completed\n"); + + + return ASMT_SUCCESS; +} + +// +//Procedure: ASM116BEraseSpiFlashRom +//Description: Erase SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - Erase success +// ASMT_IO_ERROR - others +//Note: +// ASM 116 SPI control Grant shall be gotten by caller +// Use SPI flash CHIP REASE command will erase all content of SPI flash ROM +// +// +int ASM116EraseSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl) +{ + DWORD BlankCheckLength; + int i; + int BoolSuccess; + + //Unprotect blocks for SPI flash ROM + + //printk(KERN_INFO "CmdTableIndex[%X]WrEn[0x%X]E[0x%X]FastRead[0x%X]\n",SpiControl->SpiIndex.CmdTableIndex,SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex].WriteEnableCmd + //,SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex].ChipEraseCmd,SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex].FastReadCmd); + i=0; + BoolSuccess = ASMT_IO_ERROR; + while( (i < SPI_PROGRAM_REASE_TRY_COUNT) && (BoolSuccess == ASMT_IO_ERROR) ) + { + BoolSuccess = SpiFlashUnprotectBlocks(PciDevice,SpiControl); + i++; + } + + if(verblevel) + { + printk(KERN_INFO "ASM116EraseSpiFlashRom: Clear SPI flash ROM Status Register = %d\n", BoolSuccess); + + } + + if(BoolSuccess == ASMT_IO_ERROR) + { + + printk(KERN_INFO "\nASM116EraseSpiFlashRom: Write SPI flash ROM Status Register fail!!!\n"); + + return ASMT_IO_ERROR; + } + + //Erase chip and blank check + i = 0; + BoolSuccess = ASMT_IO_ERROR; + BlankCheckLength = SpiControl->SpiIndex.Capacity * 1024L; //Capacity of SPI flash ROM KBytes + while( (i < SPI_PROGRAM_REASE_TRY_COUNT) && (BoolSuccess != ASMT_SUCCESS) ) + { + BoolSuccess = SpiFlashChipErase(PciDevice,SpiControl); + + if(verblevel) + { + printk(KERN_INFO "\nASM116EraseSpiFlashRom: Chip Erase status = %d\n", BoolSuccess); + + } + + if(BoolSuccess == ASMT_SUCCESS) + { + BoolSuccess = ASM116BlankCheckSpiFlashRom(PciDevice,SpiControl, 0L, BlankCheckLength); + if(verblevel) + { + printk(KERN_INFO "\nASM116EraseSpiFlashRom: Blank Check status = %d\n", BoolSuccess); + } + + + } + i++; + } + + return BoolSuccess; +} + +// +//Procedure: ASM116UpdateSpiFlashRom +//Description: Update SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// pSpirom - Content to update +// SpiromFileLength - Length +//Output: ASMT_SUCCESS - update success +// ASMT_IO_ERROR - others +//Note: +// ASM116 SPI control Grant shall be gotten by caller +// +int ASM116UpdateSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void * pSpirom, DWORD SpiromFileLength) +{ + //PSPIROMHEADER pSpiHeader; //ASM 116 SPI ROM file header + //PRECORDTBL pRecordTable; //ASM 116 firmware record table + DWORD i, m; + BYTE bData; + BYTE *pData; + BYTE *pByte; + int BoolSuccess; + + + + //Unprotect blocks for SPI flash ROM + i = 0; + BoolSuccess = ASMT_IO_ERROR; + while( (i < SPI_PROGRAM_UPDATE_TRY_COUNT) && (BoolSuccess == ASMT_IO_ERROR) ) + { + BoolSuccess = SpiFlashUnprotectBlocks(PciDevice,SpiControl); + i++; + } + if(BoolSuccess == ASMT_IO_ERROR) + { + + printk(KERN_INFO "\nASM116UpdateSpiFlashRom: Write SPI flash ROM Status Register fail!!!\n"); + + + return ASMT_IO_ERROR; + } + + // + //Write SPI flash ROM + // + + //Allocate memory for data verified + pData = NULL; //init value + pData = (BYTE *)kmalloc(SpiromFileLength, GFP_KERNEL); + + + if(pData == NULL) + { + printk(KERN_INFO "\nASM116UpdateSpiFlashRom: Allocate memory for data verified fail!!!\n"); + } + + + //Start write + i = 0; + BoolSuccess = ASMT_IO_ERROR; + while( (i < SPI_PROGRAM_UPDATE_TRY_COUNT) && (BoolSuccess != ASMT_SUCCESS) ) + { + //Erase chip + BoolSuccess = SpiFlashChipErase(PciDevice,SpiControl); + + + printk(KERN_INFO "ASM116UpdateSpiFlashRom: Chip Erase status = %d\n", BoolSuccess); + + + + //Blank check + BoolSuccess = ASM116BlankCheckSpiFlashRom(PciDevice,SpiControl, 0L, SpiromFileLength); + + + printk(KERN_INFO "ASM116UpdateSpiFlashRom: Blank Check status = %d\n", BoolSuccess); + + if(BoolSuccess == ASMT_SUCCESS) + { + //Write data + BoolSuccess = SpiFlashWriteData(PciDevice,SpiControl, pSpirom, 0L, SpiromFileLength); + + + printk(KERN_INFO "ASM116UpdateSpiFlashRom: Write Data status = %d\n", BoolSuccess); + + + + } + + //Verify data + if(BoolSuccess == ASMT_SUCCESS) + { + if(pData == NULL) //Allocate memory fail + { + pByte = (BYTE *)pSpirom; + for(m = 0; m < SpiromFileLength; m++) + { + SpiFlashReadData(PciDevice,SpiControl, &bData, m, 1L); + if(bData != *pByte) + { + printk(KERN_INFO "\nASM116UpdateSpiFlashRom: Verify Written data fail at address 0x%04X!!!\n", i); + + BoolSuccess = ASMT_SPI_VERIFY_ERROR; + break; + } + pByte++; + } + } + else + { + SpiFlashReadData(PciDevice,SpiControl, pData, 0L, SpiromFileLength); + if(memcmp(pSpirom, pData, SpiromFileLength) != 0) + { + printk(KERN_INFO "\nASM116UpdateSpiFlashRom: Verify Written data fail!!!\n"); + + BoolSuccess = ASMT_SPI_VERIFY_ERROR; + } + } + } + if(BoolSuccess == ASMT_SUCCESS) + break; + + i++; + } + + if(pData != NULL) + { + kfree(pData); + } + + return BoolSuccess; +} + +// +//Procedure: ASM116VerifySpiRomFile +//Description: Verify ASM116 SPI ROM file +//Input: pSpirom - File content to verify +// SpiromFileLength - Length +//Output: ASMT_SUCCESS - valid ASM116 SPI ROM file +// ASMT_PARAMETER_INVALID - invalid +// +int ASM116VerifySpiRomFile(void * pSpirom, DWORD SpiromFileLength) +{ + PSPIROMHEADER pSpiromHeader; + BYTE *pVerificationTable; //0x000100 ~ 0x0001FF: Verification table + PSPIFILEIDENTIFIER pSpiFileIdentifier; //0x000200 ~ 0x0002FF: Identifier + BYTE *pOpromImage; + BYTE *pFirmwareBinary; + //DWORD OpromImageLength; + //DWORD FirmwareBinaryLength; + DWORD Crc32; + BYTE *pByte; + unsigned int i; + BYTE Checksum; + +//Initial variables + pSpiromHeader = (PSPIROMHEADER)pSpirom; + pSpiFileIdentifier = (PSPIFILEIDENTIFIER)&pSpiromHeader->SpiFileIdentifier; + pVerificationTable = NULL; + pOpromImage = NULL; + pFirmwareBinary = NULL; + +// +//1 Check the ¡§Identifier¡¨ in SPI ROM file +//1.1 Check the GUID. If the GUID is not matched ASM116 GUID, it is not a valid ASM116 SPI ROM file. +//1.2 Check the checksum of "Identifier". If the checksum is not correct, it can¡¦t be updated. +// + //Check GUID + + for ( i=0;iGUID[i] != gASM116GUID[i] ) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: Identifier GUID is not matched!!!"); + + return ASMT_PARAMETER_INVALID; + } + } + + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Identifier Checksum is matched!!!" ); + + //Check checksum + pByte = (BYTE *)pSpiFileIdentifier; + Checksum = 0; + for(i = 0; i < ASM116_SPI_FILE_IDENTIFIER_LENGTH - 1; i++) + { + Checksum = Checksum + (*pByte); + pByte++; + } + if(pSpiFileIdentifier->Checksum != Checksum) + { + + printk(KERN_INFO "\nVerifyASM116SpiRomFile: Identifier Checksum is not matched!!!"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Identifier Checksum is matched!!!" ); + +//2 Check the length of SPI ROM file +//The file is invalid if the total length is not same as ¡§Length of SPI ROM File¡¨ field. + if(pSpiFileIdentifier->FileLength != SpiromFileLength) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: Length of SPI ROM file in Identifier is not matched!!!"); + + return ASMT_PARAMETER_INVALID; + } + + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Length of SPI ROM file in Identifier is matched!!!\r\n"); + +// +//3 Verify the OPROM image +//3.1 Determine OPROM image whether existed by OPROM Image Starting Address in ¡§Identifier¡¨. +//3.2 Check the Starting Address. If it does not equal to 0x00000000, it must be 0x00002000. +//3.3 Check the CRC32 of OPROM image if it exists. +//3.4 If the CRC32 is not correct, it can¡¦t be updated. +// + + if(pSpiFileIdentifier->OpromImage.Address == 0L) + { + printk(KERN_INFO "VerifyASM116SpiRomFile: OPROM Image does not exist!!!\n"); + } + + + if(pSpiFileIdentifier->OpromImage.Address != 0L) + { + //2.2 Check the Starting Address. If it does not equal to 0x00000000, it must be 0x00002000. + if(pSpiFileIdentifier->OpromImage.Address != ASM116_OPROM_STARTING_ADDRESS) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: OPROM Image Starting Address is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: OPROM Image Starting Address is correct!!!\r\n" ); + //2.3 Check the CRC32 of OPROM image if it exists. + pOpromImage = (BYTE *)pSpirom + pSpiFileIdentifier->OpromImage.Address; + Crc32 = GetCrc32(pOpromImage, pSpiFileIdentifier->OpromImage.Length); + if(pSpiFileIdentifier->OpromImage.Crc32 != Crc32) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: OPROM Image CRC32 is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: OPROM Image CRC32 is correct!!!\r\n" ); + } + + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: OpromImage Address is correct!!!\r\n"); + +// +//4 Verify the Verification Table +//4.1 Determine Verification Table whether existed by Verification Table Starting Address in ¡§Identifier¡¨. +//4.2 Check the Starting Address. If it does not equal to 0x00000000, it must be 0x00000100. +//4.3 Check the Length. It must be 0x00000100 if it exists. +//4.4 Check the CRC32 +//4.5 If the CRC32 is not correct, it can¡¦t be updated. +// + + //Verification table must exist if firmware binary exists. + if(pSpiFileIdentifier->VerificationTable.Address == 0L) + { + if(pSpiFileIdentifier->FirstFirmwareBinary.Address != 0L) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: Error condition!!!\n"); + printk(KERN_INFO "Firmware Binary exist but Verification Table does not exist!!!.\n"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: FirstFirmwareBinary Address is matched!!!\r\n" ); + } + else + { + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: VerificationTable Address is matched!!!\r\n" ); + //3.2 Check the Starting Address. If it does not equal to 0x00000000, it must be 0x00000100. + if(pSpiFileIdentifier->VerificationTable.Address != ASM116_VERIFICATION_TABLE_STARTING_ADDRESS) + { + + printk(KERN_INFO "\nVerifyASM116SpiRomFile: Verification Table Starting Address is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Verification Table Starting Address is correct!!!\r\n" ); + //3.3 Check the Length. It must be 0x00000100 if it exists. + if(pSpiFileIdentifier->VerificationTable.Length != ASM116_VERIFICATION_TABLE_LENGTH) + { + + printk(KERN_INFO "\nVerifyASM116SpiRomFile: Verification Table Length is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Verification Table Length is correct!!!\n" ); + + //3.4 Check the CRC32 + pVerificationTable = (BYTE *)pSpirom + pSpiFileIdentifier->VerificationTable.Address; + Crc32 = GetCrc32(pVerificationTable, pSpiFileIdentifier->VerificationTable.Length); + if(pSpiFileIdentifier->VerificationTable.Crc32 != Crc32) + { + + printk(KERN_INFO "\nVerifyASM116SpiRomFile: Verification Table CRC32 is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + } + +// +//5 Verify the Firmware binary[ +//5.1 Don¡¦t need to verify firmware binary if Verification Table does not exist. +//5.2 Determine the first firmware binary whether existed by First Firmware Binary Starting Address. +//5.3 Check the CRC32 of first firmware binary if it exists. +//5.4 If the CRC32 is not correct, it can¡¦t be updated. +//5.5 Repeat 4.2 to 4.4 to check second firmware binary. +// + //Firmware binary must exist if verification table exists + if(pSpiFileIdentifier->FirstFirmwareBinary.Address == 0L) + { + if(pSpiFileIdentifier->VerificationTable.Address != 0L) + { + + printk(KERN_INFO "\nVerifyASM116SpiRomFile: Error condition!!!\n"); + printk(KERN_INFO "Verification Table exist but Firmware Binary does not exist!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + } + else + { + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: FirstFirmwareBinary Address is matched!!!\r\n" ); + + //4.3 Check the CRC32 of first firmware binary if it exists. + pFirmwareBinary = (BYTE *)pSpirom + pSpiFileIdentifier->FirstFirmwareBinary.Address; + Crc32 = GetCrc32(pFirmwareBinary, pSpiFileIdentifier->FirstFirmwareBinary.Length); + if(pSpiFileIdentifier->FirstFirmwareBinary.Crc32 != Crc32) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: First firmware binary CRC32 is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: First firmware binary CRC32 is correct!!!\n"); + //4.5 Repeat 4.2 to 4.4 to check second firmware binary. + + if(pSpiFileIdentifier->SecondFirmwareBinary.Address == 0L) + { + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Second Firmware Binary does not exist!!!\n"); + } + + + if(pSpiFileIdentifier->SecondFirmwareBinary.Address != 0L) + { + printk(KERN_INFO "VerifyASM116SpiRomFile: SecondFirmwareBinary Address is not matched!!!\n" ); + //4.3 Check the CRC32 of second firmware binary if it exists. + pByte = (BYTE *)pSpirom + pSpiFileIdentifier->SecondFirmwareBinary.Address; + Crc32 = GetCrc32(pByte, pSpiFileIdentifier->SecondFirmwareBinary.Length); + if(pSpiFileIdentifier->SecondFirmwareBinary.Crc32 != Crc32) + { + + printk(KERN_INFO "VerifyASM116SpiRomFile: Second firmware binary CRC32 is not correct!!!\n"); + + return ASMT_PARAMETER_INVALID; + } + } + if ( verblevel ) + printk(KERN_INFO "VerifyASM116SpiRomFile: Second firmware binary CRC32 is correct!!!\r\n" ); + } + + return ASMT_SUCCESS; +} +// +//Procedure: ASM116GetOPROMVERandFWVER +//Description: Get ASM116 SPI ROM file OPROM Ver and FW Ver +//Input: pSpirom - File content to verify +// SpiromFileLength - Length +//Output: None +// +void ASM116GetOPROMandFWver(void * pSpirom, DWORD SpiromFileLength) +{ + PSPIROMHEADER pSpiromHeader; + PSPIFILEIDENTIFIER pSpiFileIdentifier; //0x000200 ~ 0x0002FF: Identifier + + BYTE bVer1, bVer2, bVer3, bVer4, bVer5, bVer6; + + WORD wTemp; + BYTE *pByte; + + //Initial variables + pSpiromHeader = (PSPIROMHEADER)pSpirom; + pSpiFileIdentifier = (PSPIFILEIDENTIFIER)&pSpiromHeader->SpiFileIdentifier; + + + bVer1 = bVer2 = bVer3 = bVer4 = bVer5 = bVer6 = 0; + + wTemp = 0; + + pByte = (BYTE *)pSpiromHeader; + + //Get OPROM version + if((pSpiFileIdentifier->OpromImage.Address == 0)||(pSpiFileIdentifier->OpromImage.Address == 0xFFFFFFFF)) + { + if(verblevel) + { + printk(KERN_INFO "OPROM Version: NA\n"); + } + + + }else + { + bVer1 = pByte[pSpiFileIdentifier->OpromImage.Address + 0x18]; //40 + bVer2 = pByte[pSpiFileIdentifier->OpromImage.Address + 0x19]; //00 + wTemp = ((WORD)(bVer2<<8) + (bVer1) + 0x12); + bVer3 = pByte[pSpiFileIdentifier->OpromImage.Address + wTemp]; + wTemp = ((WORD)(bVer2<<8) + (bVer1) + 0x13); + bVer4 = pByte[pSpiFileIdentifier->OpromImage.Address + wTemp]; + + if(verblevel) + printk(KERN_INFO "OPROM Version: %01x.%02x\n", bVer4, bVer3); + + + } + + + bVer1 = bVer2 = 0; + + //Get FW version + if((pSpiFileIdentifier->FirstFirmwareBinary.Address == 0)||(pSpiFileIdentifier->FirstFirmwareBinary.Address == 0xFFFFFFFF)) + { + //if(verblevel) + { + printk(KERN_INFO "EEPROM FW Version: NA\n"); + + } + }else + { + if(pSpiFileIdentifier->SecondFirmwareBinary.Address > pSpiFileIdentifier->FirstFirmwareBinary.Address) + { + bVer1 = pByte[pSpiFileIdentifier->SecondFirmwareBinary.Address + 0x10]; + bVer2 = pByte[pSpiFileIdentifier->SecondFirmwareBinary.Address + 0x11]; + bVer3 = pByte[pSpiFileIdentifier->SecondFirmwareBinary.Address + 0x12]; + bVer4 = pByte[pSpiFileIdentifier->SecondFirmwareBinary.Address + 0x13]; + bVer5 = pByte[pSpiFileIdentifier->SecondFirmwareBinary.Address + 0x14]; + bVer6 = pByte[pSpiFileIdentifier->SecondFirmwareBinary.Address + 0x15]; + + printk(KERN_INFO "EEPROM FW Version: %02x%02x%02x_%02x%02x_%02x\n", bVer1, bVer2, bVer3, bVer4, bVer5, bVer6); + + }else + { + bVer1 = pByte[pSpiFileIdentifier->FirstFirmwareBinary.Address + 0x10]; + bVer2 = pByte[pSpiFileIdentifier->FirstFirmwareBinary.Address + 0x11]; + bVer3 = pByte[pSpiFileIdentifier->FirstFirmwareBinary.Address + 0x12]; + bVer4 = pByte[pSpiFileIdentifier->FirstFirmwareBinary.Address + 0x13]; + bVer5 = pByte[pSpiFileIdentifier->FirstFirmwareBinary.Address + 0x14]; + bVer6 = pByte[pSpiFileIdentifier->FirstFirmwareBinary.Address + 0x15]; + + printk(KERN_INFO "EEPROM File FW Version: %02x%02x%02x_%02x%02x_%02x\n", bVer1, bVer2, bVer3, bVer4, bVer5, bVer6); + + } + } +} + +static ssize_t asm116X_spi_update_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + DWORD SpiromFileLength; + BYTE *pSpirom; + SPI_FLASH_EXTENSION SpiFlashExtension; + int uiResult = ASMT_SUCCESS; + int i = 0; + struct pci_dev *current_dev = NULL; + struct pci_dev *pdev = NULL; + struct kstat fileState; + struct file *pFile = NULL; + int iFileLength = 0; + char filename[SZ_SPI_NAME_LENGTH] = {0}, *pVerify = NULL; + struct path rom_path; + + memset(&rom_path, 0, sizeof(struct path)); + + snprintf(filename, strlen(buf), "%s", buf); + pFile = filp_open(filename, O_RDONLY, 0); + if (NULL == pFile) { + printk(KERN_INFO "An ASM116X ROM file must be designated!!!"); + goto END; + } + + if (kern_path(filename, LOOKUP_FOLLOW, &rom_path)) { + printk(KERN_ERR "Cannot get path from input filename %s\n", filename); + goto END; + } + + vfs_getattr(&rom_path, &fileState, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); + SpiromFileLength = fileState.size; + + pVerify = kmalloc(SpiromFileLength, GFP_KERNEL); + pSpirom = kmalloc(SpiromFileLength, GFP_KERNEL); + if (!pSpirom) { + printk("malloc buffer for spi rom error!\n"); + goto END; + } + for (iFileLength = 0; iFileLength < SpiromFileLength; iFileLength++) { + kernel_read(pFile, pSpirom + iFileLength, 1, &pFile->f_pos); + } + + filp_close(pFile, NULL); + pFile = NULL; + + //Verify SPI ROM file + if(ASM116VerifySpiRomFile(pSpirom, SpiromFileLength) != ASMT_SUCCESS) + { + printk(KERN_INFO "Input is not a valid ASM116X SPI ROM file!!!\n"); + return count; + } + + while ((NULL != (pdev = pci_get_device(0x1b21, 0x1164, pdev))) || + (NULL != (pdev = pci_get_device(0x1b21, 0x1165, pdev)))) { + //Update to SPI flash ROM + i++; + if (0 != uiSelectedASM116x && (uiSelectedASM116x != i)) { + continue; + } + current_dev = pdev; + // Initialize SpiControlExtension and SpiFlashExtension + // + pMemPtr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!pMemPtr) { + printk(KERN_INFO "Cannot Update SPI flash for "); + printk(KERN_INFO "Controller %d : PCI bus 0x%02x, device 0x%02x function 0x%02x ...\n", i, + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + continue; + } + // ROM SPI ADDRESS OFFSET FROM MMIO BASE + pMemPtr += 0x1000; + + printk(KERN_INFO "Update SPI flash ROM start:"); + printk(KERN_INFO "Controller %d : PCI bus 0x%02x, device 0x%02x function 0x%02x ...\n", i, + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + + //1. Get SPI control Grant + //2. Detect SPI flash ROM + //3. Update SPI flash ROM + //4. Release SPI control Grant + if(ASM116SpiGetControlGrant(current_dev) == ASMT_TIMEOUT) + { + printk(KERN_INFO "Get SPI control Grant fail!!!"); + + uiResult = ASMT_TIMEOUT; + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + //printk(KERN_INFO " Get SPI control Grant fail!!!\n"); + continue; + } + //Detect SPI flash ROM + + if(SpiFlashDetectSpiFlashRom(current_dev,(PSPI_FLASH_EXTENSION)&SpiFlashExtension) != ASMT_SUCCESS) + { + //Release SPI control Grant + ASM116SpiReleaseControlGrant(current_dev); + + printk(KERN_INFO "Can't detect SPI flash ROM on ASM116X!!!"); + + uiResult = ASMT_UNMATCH; + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //printk(KERN_INFO " Can't detect SPI flash ROM on ASM116!!!\n"); + //continue; + } + + if(SpiFlashExtension.InSupportedList == ASMT_IO_ERROR) + { + printk(KERN_INFO "Find a SPI flash ROM ID : %02Xh, %02Xh, %02Xh is not in Supported List!!!", + SpiFlashExtension.SpiIndex.FlashID[0], SpiFlashExtension.SpiIndex.FlashID[1], SpiFlashExtension.SpiIndex.FlashID[2]); + + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + + printk(KERN_INFO "Try to program..."); + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + + //printk(KERN_INFO " Find a SPI flash ROM ID : %02Xh, %02Xh, %02Xh is not in Supported List!!!\n",pSpiFlashExtension->SpiIndex.FlashID[0], pSpiFlashExtension->SpiIndex.FlashID[1], pSpiFlashExtension->SpiIndex.FlashID[2]); + // printk(KERN_INFO " Try to program...\n"); + uiResult = ASMT_IO_ERROR; + } + else + { + // printk(KERN_INFO "Find a SPI flash ROM: %s, Capacity = %d Kbytes", SpiFlashExtension.SpiIndex.ProductString, SpiFlashExtension.SpiIndex.Capacity); + printk(KERN_INFO "Find a SPI flash ROM, Capacity = %d Kbytes", SpiFlashExtension.SpiIndex.Capacity); + + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + + //printk(KERN_INFO " Find a SPI flash ROM: %s, Capacity = %d Kbytes\n", pSpiFlashExtension->SpiIndex.ProductString, pSpiFlashExtension->SpiIndex.Capacity); + if(SpiromFileLength > (DWORD)SpiFlashExtension.SpiIndex.Capacity * 1024) + { + //Release SPI control Grant + ASM116SpiReleaseControlGrant(current_dev); + printk(KERN_INFO "The capacity of SPI flash ROM is less than ASM116X SPI ROM file!!!"); + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + //printk(KERN_INFO " The capacity of SPI flash ROM is less than ASM116 SPI ROM file!!!\n"); + //continue; + } + } + + + + uiResult =ASM116UpdateSpiFlashRom(current_dev,(PSPI_FLASH_EXTENSION)&SpiFlashExtension, pSpirom, SpiromFileLength); + if(uiResult != ASMT_SUCCESS) + { + printk(KERN_INFO "Update SPI flash ROM......FAIL!!!\n\n"); + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + //printk(KERN_INFO " Update SPI flash ROM......FAIL!!!\n"); + + } + else + { + printk(KERN_INFO "Update SPI flash ROM......PASS!!!\n\n"); + + //DBGMESSAGE( _FLP_ "%s\r\n", _FL_ , strTemp1); + //this->m_StaticShowMessage.SetWindowTextA(strTemp1); + //printk(KERN_INFO " Update SPI flash ROM......PASS\n"); + + } + + SpiFlashReadData(current_dev,(PSPI_FLASH_EXTENSION)&SpiFlashExtension, pVerify, 0L, SpiromFileLength); + if (0 != memcmp(pVerify, pSpirom, SpiromFileLength)) { + printk(KERN_ERR "Updated flash does not match input flash.\n"); + } + ASM116GetOPROMandFWver(pVerify, SpiromFileLength); + //Release SPI control Grant + ASM116SpiReleaseControlGrant(current_dev); + + if (pMemPtr) { + iounmap(pMemPtr); + pMemPtr = NULL; + } + } +END: + if (pSpirom) { + kfree(pSpirom); + } + if (pMemPtr) { + iounmap(pMemPtr); + pMemPtr = NULL; + } + if (pFile) { + filp_close(pFile, NULL); + } + if (pVerify) { + kfree(pVerify); + } + return count; +} + +static ssize_t asm116X_spi_version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + SPI_FLASH_EXTENSION SpiFlashExtension; + BYTE *pData; + struct pci_dev *pdev = NULL, *current_dev = NULL; + DWORD SpiromFileLength; + int i = 0; + + if (0 == uiSelectedASM116x) { + printk(KERN_INFO "Please select a ASM116x to read spi header\n"); + goto END; + } + + while ((NULL != (pdev = pci_get_device(0x1b21, 0x1164, pdev))) || + (NULL != (pdev = pci_get_device(0x1b21, 0x1165, pdev)))) { + + i++; + if (uiSelectedASM116x != i) { + continue; + } + current_dev = pdev; + + pMemPtr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!pMemPtr) { + printk(KERN_INFO "Cannot Show SPI flash for "); + printk(KERN_INFO "Controller %d : PCI bus 0x%02x, device 0x%02x function 0x%02x ...\n", i, + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + continue; + } + // ROM SPI ADDRESS OFFSET FROM MMIO BASE + pMemPtr += 0x1000; + + //1. Get SPI control Grant + //2. Detect SPI flash ROM + //3. Update SPI flash ROM + //4. Release SPI control Grant + if(ASM116SpiGetControlGrant(current_dev) == ASMT_TIMEOUT) + { + printk(KERN_INFO "Get SPI control dev%2d Grant fail!!!\n",i); + continue; + } + + //Detect SPI flash ROM + + if(SpiFlashDetectSpiFlashRom(current_dev,(PSPI_FLASH_EXTENSION)&SpiFlashExtension) != ASMT_SUCCESS) + { + //Release SPI control Grant + ASM116SpiReleaseControlGrant(current_dev); + + printk(KERN_INFO "Can't detect SPI flash ROM dev%2d on ASM116X!!!\n", i); + + } + + if(SpiFlashExtension.InSupportedList == ASMT_IO_ERROR) + { + printk(KERN_INFO "Find a SPI flash ROM dev%2d ID : %02Xh, %02Xh, %02Xh is not in Supported List!!!\n", + i, SpiFlashExtension.SpiIndex.FlashID[0], SpiFlashExtension.SpiIndex.FlashID[1], + SpiFlashExtension.SpiIndex.FlashID[2]); + + } + else + { + if(verblevel) + { + //printk(KERN_INFO "Find a SPI flash ROM dev%2d: %s, Capacity = %d Kbytes", i, SpiFlashExtension.SpiIndex.ProductString, SpiFlashExtension.SpiIndex.Capacity); + printk(KERN_INFO "Find a SPI flash ROM dev%2d, Capacity = %d Kbytes", i, SpiFlashExtension.SpiIndex.Capacity); + } + } + + SpiromFileLength = (DWORD)(SpiFlashExtension.SpiIndex.Capacity * 1024); + + pData = NULL; + pData = (BYTE *)kmalloc(SpiromFileLength, GFP_KERNEL); + + SpiFlashReadData(current_dev,(PSPI_FLASH_EXTENSION)&SpiFlashExtension, pData, 0L, SpiromFileLength); + + ASM116GetOPROMandFWver(pData, SpiromFileLength); + + if(verblevel) + printk(KERN_INFO "Get SPI controller dev%2d SPI ROM version done!!!\n", i); + + + //Release SPI control Grant + ASM116SpiReleaseControlGrant(current_dev); + + if (pMemPtr) { + iounmap(pMemPtr); + pMemPtr = NULL; + } + if(pData != NULL) + { + kfree(pData); + } + } +END: + if (pMemPtr) { + iounmap(pMemPtr); + pMemPtr = NULL; + } + return 0; +} + +static ssize_t asm116X_spi_select_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct pci_dev *pdev = NULL; + int iCount = 0, iCurrent = 0; + + iCurrent = snprintf(buf, PAGE_SIZE, "Current selected asm116X : %u\n", uiSelectedASM116x); + iCurrent += snprintf(buf + iCurrent, PAGE_SIZE - iCurrent, "0. All asm116X is selected (default).\n"); + while (NULL != (pdev = pci_get_device(0x1b21, 0x1164, pdev)) || + NULL != (pdev = pci_get_device(0x1b21, 0x1165, pdev))) { + iCurrent += snprintf(buf + iCurrent, PAGE_SIZE - iCurrent, "%u. pcie bus %02x:%02x.%x\n", ++iCount, pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + } + return iCurrent; +} + +static ssize_t asm116X_spi_select_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = NULL; + u32 iCount=0; + int iRet = -1; + + iRet = kstrtouint(buf, 10, &uiSelectedASM116x); + if (0 > iRet) { + goto END; + } + + if (0 == uiSelectedASM116x) { + printk(KERN_INFO "No.0 All asm116X are selected."); + iRet = count; + goto END; + } + + while (NULL != (pdev = pci_get_device(0x1b21, 0x1164, pdev)) || + NULL != (pdev = pci_get_device(0x1b21, 0x1165, pdev))) { + iCount++; + if (uiSelectedASM116x == iCount) { + printk(KERN_INFO "No.%u asm116X on pcie bus %02x:%02x.%x has been selected\n", iCount, pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + break; + } + } + if (0 != uiSelectedASM116x && (uiSelectedASM116x != iCount)) { + printk(KERN_INFO "There is no asm116X being selected for input no.%u. All asm116X will be selected by default.\n", uiSelectedASM116x); + uiSelectedASM116x = 0; + } + iRet = count; +END: + return iRet; +} + +// register function to attribute +static struct kobj_attribute asm116XSelectAttr = __ATTR( asm116X_spi_select, 0640, asm116X_spi_select_show, asm116X_spi_select_store); +static struct kobj_attribute asm116XUpdateAttr = __ATTR( asm116X_spi_update, 0640, asm116X_spi_version_show, asm116X_spi_update_store); + +// put attribute to attribute group +static struct attribute *asm116XSPIAttr[] = { + &asm116XUpdateAttr.attr, + &asm116XSelectAttr.attr, + NULL, /* NULL terminate the list*/ +}; +static struct attribute_group asm116XSPIGroup = { + .attrs = asm116XSPIAttr +}; + +static int asm116X_spi_update_init(void) +{ + int iRet = -1; + asm116XSPIObject = kobject_create_and_add("asm116X_spi_update", kernel_kobj); + if (!asm116XSPIObject) { + iRet = -ENOMEM; + goto END; + } + + //create attributes (files) + if(sysfs_create_group(asm116XSPIObject, &asm116XSPIGroup)){ + iRet = -ENOMEM; + goto END; + } + + iRet = 0; +END: + if (0 != iRet) { + if (asm116XSPIObject) { + kobject_put(asm116XSPIObject); + } + } + return iRet; +} + +static void asm116X_spi_update_exit(void) +{ + kobject_put(asm116XSPIObject); +} + + +MODULE_LICENSE("GPL"); +module_init(asm116X_spi_update_init); +module_exit(asm116X_spi_update_exit); diff --git a/lib/synolib/asm116xfwdl/Makefile b/lib/synolib/asm116xfwdl/Makefile new file mode 100644 index 000000000000..82aa385f5c7d --- /dev/null +++ b/lib/synolib/asm116xfwdl/Makefile @@ -0,0 +1,6 @@ +# +# This is a synology asm116x controller spi update util +# + +asm116xfwdl-objs := crc.o spiflash.o spictrl.o 116xfwdl.o +obj-$(CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE) += asm116xfwdl.o diff --git a/lib/synolib/asm116xfwdl/asm116.h b/lib/synolib/asm116xfwdl/asm116.h new file mode 100644 index 000000000000..688d2afa1afc --- /dev/null +++ b/lib/synolib/asm116xfwdl/asm116.h @@ -0,0 +1,52 @@ +/* + * Asmedia ASM116 Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ + +#ifndef _ASM116_H_ +#define _ASM116_H_ + + +#define ASMedia_VENDOR_ID 0x1b21 + +#define ASM116_DEVICE_1062 0x1062 +#define ASM116_DEVICE_1064 0x1064 +#define ASM116_DEVICE_1164 0x1164 +#define ASM116_DEVICE_1165 0x1165 +#define ASM116_DEVICE_1166 0x1166 + + + +#define VID_REG 0x00 /* offset 0x00-02: Vendor ID */ +#define DID_REG 0x02 /* offset 0x02-04: Device ID */ +#define PCI_COMMAND_REG 0x04 /* offset 0x04: Command register */ +#define PCI_IO_SPACE_ENABLED 0x01 /* bit 0: IO space enable */ +#define PCI_MEMORY_SPACE_ENABLED 0x02 /* bit 1: Memory space enable */ +#define PCI_BUS_MASTER_ENABLED 0x04 /* bit 2: Bus master enable */ +#define REVISION_REG 0x08 /* offset 0x08: Revision ID register */ +#define PROGRAMMING_INTERFACE_REG 0x09 /* offset 0x09: Programming interface */ +#define SUB_CLASS_REG 0x0A /* offset 0x0A: Sub class code */ +#define BASE_CLASS_REG 0x0B /* offset 0x0B: Base class code */ +#define BAR0_REG 0x10 /* offset 0x10-13: Base Address 0 */ +#define IDE_PRI_COMMAND_BASE_REG BAR0_REG +#define BAR1_REG 0x14 /* offset 0x14-17: Base Address 1 */ +#define IDE_PRI_CONTROL_BASE_REG BAR1_REG +#define BAR2_REG 0x18 /* offset 0x18-1B: Base Address 2 */ +#define IDE_SEC_COMMAND_BASE_REG BAR2_REG +#define BAR3_REG 0x1C /* offset 0x1C-1F: Base Address 3 */ +#define IDE_SEC_CONTROL_BASE_REG BAR3_REG +#define BAR4_REG 0x20 /* offset 0x20-23: Base Address 4 */ +#define IDE_BM_BASE_REG BAR4_REG +#define BAR5_REG 0x24 /* offset 0x24-27: Base Address 5 */ +#define SATA_AHCI_BASE_REG BAR5_REG +#define SVID_REG 0x2C /* offset 0x2C-2D: Subsystem Vendor ID */ +#define SDID_REG 0x2E /* offset 0x2E-2F: Subsystem Device ID */ +#define EXPANSION_ROM_BASE_REG 0x30 /* offset 0x30-33: Expansion ROM Base Address */ +#define INTERRUPT_LINE_REG 0x3C /* offset 0x3C: Interrupt line (IRQ) */ +#define INTERRUPT_PIN_REG 0x3D /* offset 0x3D: Interrupt Pin (INTA,B,C,D) */ + +extern unsigned char *pMemPtr; + +#endif /* _ASM116_H_ */ + diff --git a/lib/synolib/asm116xfwdl/crc.c b/lib/synolib/asm116xfwdl/crc.c new file mode 100644 index 000000000000..a1db317be919 --- /dev/null +++ b/lib/synolib/asm116xfwdl/crc.c @@ -0,0 +1,99 @@ +/************************************************************************************** +*Filename: crc.c +*Description: +* Calculate 32 bits CRC. Modify from 2105 MPTool function +* +*History: +* 2013/04/02 V1.1 Jesse Chang Modify BufferLength in GetCrc32 to UINT32 +* 2012/07/24 V1.0 Jesse Chang First version +* +* +* Asmedia ASM116x Firmware Update Tool +* +* Copyright (C) 2014-2016 ASMedia Technology +* +***************************************************************************************/ +//#include "stdafx.h" +#include "crc.h" + +unsigned long gUiCRCTab[256]; //CRC initial table + +// +//Procedure: Reflect +//Description: Reflect 32 bits value. Only called by Crc32Init +//Input: ReflectValue - Value to reflect +// ReflectLength - Length to reflect +//Output: Reflected value +// +unsigned long Reflect(unsigned long ReflectValue, unsigned char ReflectLength) +{ +//Used only by Init_CRC32_Table() + unsigned long value = 0; + unsigned int i; + + // Swap bit 0 for bit 7 + // bit 1 for bit 6, etc. + for(i = 1; i < (unsigned int)(ReflectLength + 1); i++) + { + if(ReflectValue & 1) + { + value |= 1L << (ReflectLength - i); + } + ReflectValue >>= 1; + } + return value; +} + + +// +//Procedure: Crc32Init +//Description: Init CRC32 table +//Input: None +//Output: None +// +int Crc32Init(void) +{ + unsigned long ulPolynomial = 0x04c11db7L; + unsigned int i, j; + + // 256 values representing ASCII character codes. + for(i = 0; i <= 0xFF; i++) + { + gUiCRCTab[i] = Reflect(i, 8) << 24; + for (j = 0; j < 8; j++) + { + gUiCRCTab[i] = (gUiCRCTab[i] << 1) ^ (gUiCRCTab[i] & (1L << 31) ? ulPolynomial : 0); + //gUiCRCTab[i] = (gUiCRCTab[i] << 1) ^ (gUiCRCTab[i] & (0x80000000L) ? ulPolynomial : 0); + } + gUiCRCTab[i] = Reflect(gUiCRCTab[i], 32); + } + return ASMT_SUCCESS; +} + + +// +//Procedure: GetCrc32 +//Description: Get 32 bits CRC. +//Input: pBuffer - Data buffer to calculate CRC32 +// BufferLength - Data buffer length +//Output: 32 bits CRC +// +unsigned long GetCrc32(unsigned char* pBuffer, unsigned long BufferLength) +{ + unsigned long crc = 0xFFFFFFFF; + unsigned long len; + + Crc32Init(); //Initial CRC32 table + len = BufferLength; + // Perform the algorithm on each character + // in the string, using the lookup table values. + while(len--) + { + crc = (crc >> 8) ^ gUiCRCTab[(crc & 0xFF) ^ *pBuffer++]; + } + // Exclusive OR the result with the beginning value. + return (crc^0xFFFFFFFF); +} + + + diff --git a/lib/synolib/asm116xfwdl/crc.h b/lib/synolib/asm116xfwdl/crc.h new file mode 100644 index 000000000000..801a458d7c0f --- /dev/null +++ b/lib/synolib/asm116xfwdl/crc.h @@ -0,0 +1,29 @@ +/************************************************************************************** +*Filename: crc.h +*Description: +* Calculate 32 bits CRC +* +*History: +* 2013/04/02 V1.1 Jesse Chang Modify BufferLength in GetCrc32 to UINT32 +* 2012/07/24 V1.0 Jesse Chang First version +* +* +* Asmedia ASM116x Firmware Update Tool +* +* Copyright (C) 2014-2016 ASMedia Technology +* +***************************************************************************************/ + +#ifndef _CRC_H +#define _CRC_H +#include "precomp.h" + + + // unsigned long gUiCRCTab[256]; //CRC initial table + +unsigned long Reflect(unsigned long ReflectValue, unsigned char ReflectLength); +int Crc32Init(void); +//UINT32 GetCrc32(UINT8* pBuffer, UINTN BufferLength); +unsigned long GetCrc32(unsigned char* pBuffer, unsigned long BufferLength); + +#endif //_CRC_H diff --git a/lib/synolib/asm116xfwdl/precomp.h b/lib/synolib/asm116xfwdl/precomp.h new file mode 100644 index 000000000000..435146474cdd --- /dev/null +++ b/lib/synolib/asm116xfwdl/precomp.h @@ -0,0 +1,74 @@ +/* + * Asmedia ASM116x Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ + +#ifndef _PRECOMP_H +#define _PRECOMP_H + +#include +#include + +#define BYTE u8 +#define WORD u16 +#define DWORD u32 + + +#include "asm116.h" +#include "spictrl.h" +#include "spiflash.h" +#include "spifile.h" + +#define DEBUG 0 + +//#ifdef DEBUG +//#define func_enter() printk(KERN_INFO "\n\nEnter : %s(%d)-%s\n",__FILE__,__LINE__,__FUNCTION__) +//#define func_exit() printk(KERN_INFO "\n\nExit : %s(%d)-%s\n",__FILE__,__LINE__,__FUNCTION__) +//#else +#define func_enter() +#define func_exit() +//#endif + +#define MAX_DEVICE_CNT 16 +#define GET_SPI_CONTROL_GRANT_RETRY_COUNT 3 +#define SPI_PROGRAM_REASE_TRY_COUNT 3 +#define SPI_PROGRAM_UPDATE_TRY_COUNT 3 + + + +// PCI_DEVICE gPciDevice[MAX_DEVICE_CNT]; +// PCI_DEVICE uiPciDevice[MAX_DEVICE_CNT]; +// PCI_DEVICE backup_gPciDevice[MAX_DEVICE_CNT]; + +enum interctl_error { + ASMT_SUCCESS = 0, + ASMT_IO_ERROR =-1, //Control I/O Fail + ASMT_FWVERSION_UNMATCH =-2, // FW bin is older than curr, no need to upgrade + ASMT_UNMATCH =-3, // parameter comparsion result is ummatch + ASMT_DEVICE_NOT_FOUND =-4, // Target Deives can not find + ASMT_FILE_NOT_FOUND =-5, //Target File can not find + ASMT_SPI_VERIFY_ERROR =-6, //Error when verify SPI after update config or firmware + ASMT_RESET_FAIL =-7, //Re-link Failed + ASMT_MEMORY_ALLOCATE_ERROR =-8, //Error when allocate memory + ASMT_TIMEOUT =-9, //Program Time out + ASMT_PARAMETER_INVALID =-10, //Parameter Invalid + ASMT_SPI_BLANK_ERROR =-11, +}; + +// Decalre SPI programer +//SPI_FLASH_PROGRAMER gSpiProgramerArray[MAX_DEVICE_CNT]; +//gloable var +extern int verblevel; + + + +//pci.c +int asm_pci_init( void ); +void asm_pci_exit( void ); +int asm_select_devices( void ); + + + +#endif + diff --git a/lib/synolib/asm116xfwdl/spictrl.c b/lib/synolib/asm116xfwdl/spictrl.c new file mode 100644 index 000000000000..ed124cd95fd9 --- /dev/null +++ b/lib/synolib/asm116xfwdl/spictrl.c @@ -0,0 +1,432 @@ + +//*************************************************************************** +//Name: spictrl.c +// +//Description: +// Asmedia ASM116 legacy SPI ROM access functions +// +//Revision History: +//2013/08/20 V2.03 James Peng add write grant of XDATA RAM. +//2013/04/03 V1.0 Jesse Chang First revision +// +/* + * Asmedia ASM116x Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ +//*************************************************************************** + +#include "precomp.h" +#include "spictrl.h" + + + + + +// +//Procedure: SpiReadRegisterDword +//Description: Read ASM116 legacy SPI controller Dword register +//Input: pSpiControlExtension - SPI Controller Extension +// Register - MMIO address of register +//Output: Return read Dword value +//Note: +// Address can be not Dword alignment when Read/Write Dword memory, but we limit it must be Dword alignment. +// +DWORD SpiReadRegisterDword(struct pci_dev *PciDevice,DWORD Register) +{ + // DWORD dValue = 0; + DWORD RegisterOffset = 0; + + RegisterOffset = Register; + + //RegisterOffset = (DWORD)Register - (DWORD)(pSpiControlExtension->Abar); + //Offset = RegisterOffset % 4; + RegisterOffset = RegisterOffset & (~0x03); + + //Write Index + //pci_write_long(PciDevice, ASM116_MMIO_INDEX, RegisterOffset); + + //Read Data + //dValue = pci_read_long(PciDevice,ASM116_MMIO_DATA); +// if ( verblevel ) +// { +// printk(KERN_INFO "MMIO Read: %08X, OFFSET: %08X\n\n", pMemPtr, RegisterOffset); +// } + +// dValue = *((DWORD *)&pMemPtr[RegisterOffset]); + + + return readl(pMemPtr + Register); +} + + + +// +//Procedure: SpiWriteRegisterDword +//Description: Write ASM116 legacy SPI controller Dword register +//Input: pSpiControlExtension - SPI Controller Extension +// Register - MMIO address of register +// dValue - Written value +//Output: None +//Note: +// Address can be not Dword alignment when Read/Write Dword memory, but we limit it must be Dword alignment. +// +void SpiWriteRegisterDword(struct pci_dev *PciDevice, DWORD Register, DWORD dValue) +{ + DWORD RegisterOffset = 0; + + + RegisterOffset = Register; + RegisterOffset = RegisterOffset & (~0x03); + + //Write Index + //pci_write_long( PciDevice, ASM116_MMIO_INDEX, RegisterOffset); + + //Write Data + //pci_write_long(PciDevice, ASM116_MMIO_DATA, dValue); + + +// if ( verblevel ) +// { +// printk(KERN_INFO "MMIO Write: %08X, OFFSET: %08X\n\n", pMemPtr, RegisterOffset); +// } + +// *((DWORD *)&pMemPtr[RegisterOffset]) = dValue; + + writel(dValue, pMemPtr + Register); + + return; +} + + +// +//Procedure: SpiGetGrant +//Description: Get the authority to use SPI controller +//Input: pSpiControlExtension - SPI Controller Extension +// RequestNumber - Request number +//Output: ASMT_SUCCESS - Get authority +// ASMT_PARAMETER_INVALID - SPI controller can't be used now +// ASMT_TIMEOUT -Time out +//Note: +// Software utility uses request number 0 +// +int SpiGetGrant(struct pci_dev *PciDevice, const BYTE RequestNumber) +{ + LSPI_CONTROL Ctrl; + clock_t ticks1, ticks2; + + if(RequestNumber > MAXIMUM_SPI_REQUEST_NUMBER) + { + return ASMT_PARAMETER_INVALID; + } + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + switch(RequestNumber) + { + case 0: + Ctrl.Arbiter.REQ0 = 1; + break; + case 1: + Ctrl.Arbiter.REQ1 = 1; + break; + case 2: + Ctrl.Arbiter.REQ2 = 1; + break; + case 3: + Ctrl.Arbiter.REQ3 = 1; + break; + default: + break; + } + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL, Ctrl.AsDword); + //Wait Grant + ticks1 = jiffies; + ticks2 = ticks1; + while( ((ticks2 - ticks1) / CLOCKS_PER_SEC) < GRANT_TIMEOUT ) + { + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + switch(RequestNumber) + { + case 0: + if(Ctrl.Arbiter.GNT0 == 1) + { + return ASMT_SUCCESS; + } + break; + case 1: + if(Ctrl.Arbiter.GNT1 == 1) + { + return ASMT_SUCCESS; + } + break; + case 2: + if(Ctrl.Arbiter.GNT2 == 1) + { + return ASMT_SUCCESS; + } + break; + case 3: + if(Ctrl.Arbiter.GNT3 == 1) + { + return ASMT_SUCCESS; + } + break; + default: + break; + } + ticks2 = jiffies; + } + + //time out + //Release request + if(verblevel) + { + printk(KERN_INFO "\nSpiGetGrant: Get SPI control grant timeout!!!\n"); + printk(KERN_INFO " Request number = %d, SPI Arbiter = 0x%02X\n", RequestNumber, Ctrl.Arbiter.AsByte); + } + + SpiReleaseGrant(PciDevice, RequestNumber); + + return ASMT_TIMEOUT; //time out +} + + +// +//Procedure: SpiReleaseGrant +//Description: Release the authority of SPI controller +//Input: pSpiControlExtension - SPI Controller Extension +// RequestNumber - Request number +//Output: None +//Note: +// Software utility uses request number 0 +// +void SpiReleaseGrant(struct pci_dev *PciDevice, const BYTE RequestNumber) +{ + LSPI_CONTROL Ctrl; + + if(RequestNumber > MAXIMUM_SPI_REQUEST_NUMBER) + { + return; + } + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + switch(RequestNumber) + { + case 0: + Ctrl.Arbiter.REQ0 = 0; + break; + case 1: + Ctrl.Arbiter.REQ1 = 0; + break; + case 2: + Ctrl.Arbiter.REQ2 = 0; + break; + case 3: + Ctrl.Arbiter.REQ3 = 0; + break; + default: + break; + } + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL, Ctrl.AsDword); + return; +} + + +// +//Procedure: SpiIs3WireMode +//Description: Is 3-wires mode enabled for SPI controller? +//Input: pSpiControlExtension - SPI Controller Extension +//Output: ASMT_SUCCESS - enabled +// ASMT_PARAMETER_INVALID - disabled +//Note: +// 3-wires mode is enabled/disabled by hardware controller when power-on detection +// +int SpiIs3WireMode(struct pci_dev *PciDevice) +{ + LSPI_CONTROL Ctrl; + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + + return ( (Ctrl.Ctrl1.LSPI3WM == 1) ? ASMT_SUCCESS : ASMT_PARAMETER_INVALID); +} + + +// +//Procedure: SpiStart +//Description: Pull down CS# signal to start SPI transaction +//Input: pSpiControlExtension - SPI Controller Extension +//Output: None +// +void SpiStart(struct pci_dev *PciDevice) +{ + LSPI_CONTROL Ctrl; + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + // printk(KERN_INFO "\nSpiStart[0x%X]",Ctrl.AsDword); + Ctrl.Ctrl0.CS = 0; + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL, Ctrl.AsDword); + // printk(KERN_INFO "[0x%X]\n",Ctrl.AsDword); + return; +} + + +// +//Procedure: SpiTerminate +//Description: Pull up CS# signal to terminate SPI transaction +//Input: pSpiControlExtension - SPI Controller Extension +//Output: None +// +void SpiTerminate(struct pci_dev *PciDevice) +{ + LSPI_CONTROL Ctrl; + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice,ASM116_SPI_CONTROL_CONTROL); + // printk(KERN_INFO "\nSpiTerminate[0x%X]",Ctrl.AsDword); + Ctrl.Ctrl0.CS = 1; + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL, Ctrl.AsDword); + // printk(KERN_INFO "[0x%X]\n",Ctrl.AsDword); + return; +} + + +// +//Procedure: SpiIdle +//Description: Check SPI transmission whether is done +//Input: pSpiControlExtension - SPI Controller Extension +//Output: ASMT_SUCCESS - idle +// ASMT_TIMEOUT - timeout still running +//Note: +// Transaction done doesn't mean that SPI ROM works completely for erase, page program command +// +int SpiIdle(struct pci_dev *PciDevice) +{ + LSPI_CONTROL Ctrl; + clock_t ticks1, ticks2; + + ticks1 = jiffies; + ticks2 = ticks1; + while( ((ticks2 - ticks1) / CLOCKS_PER_SEC) < IDLE_TIMEOUT ) + { + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + if(Ctrl.Ctrl0.RUN == 0) + { + return ASMT_SUCCESS; + } + else + { + ticks2 = jiffies; + } + } + + + printk(KERN_INFO "\nSpiIdle: timeout!!!\n"); + printk(KERN_INFO " SpiIdle: SPI Ctrl Register 0 = 0x%02X\n", Ctrl.Ctrl0.AsByte); + + + return ASMT_TIMEOUT; //Time out +} + + +// +//Procedure: SpiRead +//Description: Read data from SPI flash ROM +//Input: pSpiControlExtension - SPI Controller Extension +// pData - Data buffer pointer +// Length - Data length +//Output: ASMT_SUCCESS - Read data is stored in pData +// ASMT_TIMEOUT - Otherwise and content of pdata is unknow +// +int SpiRead(struct pci_dev *PciDevice, void *pData, BYTE Length) +{ + LSPI_DATA Data; + LSPI_CONTROL Ctrl; + BYTE i; + BYTE *pByte; + + if(SpiIdle(PciDevice) == ASMT_TIMEOUT) + { + return ASMT_TIMEOUT; + } + + if((Length > ASM116_LSPI_MAXIMUM_LENGTH) || (Length < 1)) + { + return ASMT_PARAMETER_INVALID; + } + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + Ctrl.Ctrl0.AsByte = 0; + Ctrl.Ctrl0.DataSize = Length; + Ctrl.Ctrl0.WR = 0; //Read + Ctrl.Ctrl0.CS = 0; //Keep CS# signal to low + Ctrl.Ctrl0.RUN = 1; + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL, Ctrl.AsDword); + + if(SpiIdle(PciDevice) == ASMT_SUCCESS) + { + Data.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_DATA); + + pByte = (BYTE *)pData; + for(i = 0; i < Length; i++) + { + *pByte = Data.Data[i]; + pByte ++; + } + return ASMT_SUCCESS; + } + else + { + return ASMT_TIMEOUT; //time out + } +} + + +// +//Procedure: SpiWrite +//Description: Write data to SPI flash ROM +//Input: pSpiControlExtension - SPI Controller Extension +// pData - Data buffer pointer +// Length - Data length +//Output: ASMT_SUCCESS - Write data success +// ASMT_TIMEOUT - Otherwise +// +int SpiWrite(struct pci_dev *PciDevice, void *pData, BYTE Length) +{ + LSPI_DATA Data; + LSPI_CONTROL Ctrl; + BYTE i; + BYTE *pByte; + + if(SpiIdle(PciDevice) == ASMT_TIMEOUT) + { + return ASMT_TIMEOUT; + } + + if((Length > ASM116_LSPI_MAXIMUM_LENGTH) || (Length < 1)) + { + return ASMT_PARAMETER_INVALID; + } + + Data.AsDword = 0L; + pByte = (BYTE *)pData; + //printk(KERN_INFO "SpiWrite"); + for(i = 0; i < Length; i++) + { + Data.Data[i] = *pByte; + //printk(KERN_INFO "[0x%X]",Data.Data[i]); + pByte ++; + } + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_DATA, Data.AsDword); + + Ctrl.AsDword = SpiReadRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL); + Ctrl.Ctrl0.AsByte = 0; + Ctrl.Ctrl0.DataSize = Length; + Ctrl.Ctrl0.WR = 1; //Write + Ctrl.Ctrl0.CS = 0; //Keep CS# signal to low + Ctrl.Ctrl0.RUN = 1; + SpiWriteRegisterDword(PciDevice, ASM116_SPI_CONTROL_CONTROL, Ctrl.AsDword); + + return (SpiIdle(PciDevice)); +} + + + diff --git a/lib/synolib/asm116xfwdl/spictrl.h b/lib/synolib/asm116xfwdl/spictrl.h new file mode 100644 index 000000000000..bfdc5bafe11b --- /dev/null +++ b/lib/synolib/asm116xfwdl/spictrl.h @@ -0,0 +1,168 @@ +//*************************************************************************** +//Name: spictrl.h +// +//Description: +// Declare Asmedia ASM116 SPI controller +// DOS4GW32 32-bit environment. +// Compiler: Open Watcom C/C++ Win32 V1.8 +// +//Revision History: +//2013/05/27 V2.01 James Peng add IndexDataPair and MMIO command , +// add AP-FW interface Vendor Command +//2013/04/03 V1.0 Jesse Chang First revision +// +/* + * Asmedia ASM116x Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ +//*************************************************************************** + +#ifndef _SPICTRL_H_ +#define _SPICTRL_H_ + + +// +// Bit encodes for PCI_COMMON_CONFIG.u.type0.BaseAddresses +// + +#define PCI_ADDRESS_IO_SPACE 0x00000001L // (ro) +#define PCI_ADDRESS_MEMORY_TYPE_MASK 0x00000006L // (ro) +#define PCI_ADDRESS_MEMORY_PREFETCHABLE 0x00000008L // (ro) +// ASM116 Legacy SPI control interface registers +// +#pragma pack(1) +//offset 0x00-0x03: SPI data buffer +typedef union _LSPI_DATA { + struct { + BYTE Data[4]; //4 bytes + }; + DWORD AsDword; +} LSPI_DATA, *PLSPI_DATA; + +//offset 0x04: SPI control register 0 +typedef union _LSPI_CTRL0 { + struct { + BYTE DataSize : 3; //bit[2:0]: buffer size in bytes. 1-4: 1-4 bytes. other: reserved + BYTE WR : 1; //bit[3]: SPI R/W control. 1: write, 0: read + BYTE CS : 1; //bit[4]: SPI CS# signal. Low active + BYTE RUN : 1; //bit[5]: trigger SPI controller + BYTE Rev : 2; //bit[7:6]: Reserved + }; + BYTE AsByte; +} LSPI_CTRL0, *PLSPI_CTRL0; + +//offset 0x05: SPI control register 1 +typedef union _LSPI_CTRL1 { + struct { + BYTE LSPI3WM : 1; //bit[0]: Legacy SPI 3WM. 0:4-wire mode. 1:3-wire mode. LSPI_3WM will be set to 1 if power-on detection detects SPI FLASH is in 3-wire mode + BYTE Rev : 7; //bit[7:1]: Reserved + }; + BYTE AsByte; +} LSPI_CTRL1, *PLSPI_CTRL1; + +//offset 0x06: SPI arbitration +typedef union _SPI_ARBITER { + struct { + BYTE REQ0 : 1; //bit[0]: SPI request 0 + BYTE GNT0 : 1; //bit[1]: SPI grant 0 + BYTE REQ1 : 1; //bit[2]: SPI request 1 + BYTE GNT1 : 1; //bit[3]: SPI grant 1 + BYTE REQ2 : 1; //bit[4]: SPI request 2 + BYTE GNT2 : 1; //bit[5]: SPI grant 2 + BYTE REQ3 : 1; //bit[6]: SPI request 3 + BYTE GNT3 : 1; //bit[7]: SPI grant 3 + }; + BYTE AsByte; +} SPI_ARBITER, *PSPI_ARBITER; + +//offset 0x04 - 0x07 SPI control +typedef union _LSPI_CONTROL_ { + struct { + LSPI_CTRL0 Ctrl0; + LSPI_CTRL1 Ctrl1; + SPI_ARBITER Arbiter; + BYTE Rev7; + }; + DWORD AsDword; +} LSPI_CONTROL, *PLSPI_CONTROL; + + +//ASM116 legacy SPI control registers +typedef struct _LSPI_REGISTERS { + LSPI_DATA Data; //byte 0-3: Data buffer + LSPI_CONTROL Ctrl; //byte 4-7: Control +} LSPI_REGISTERS, *PLSPI_REGISTERS; +#pragma pack() + +// TIMEOUT +#define IDLE_TIMEOUT 1 //time out for SPI idle, 1 second +#define GRANT_TIMEOUT 3 //time out for SPI grant, 3 seconds +#define COMMAND_TIMEOUT 20 //time out for command,20 seconds + + + + +// +//ASM116 Arbitration Request Number +// +#define UTILITY_SPI_REQUEST_NUMBER 0 //Software utility uses request number 0 +#define FIRMWARE_SPI_REQUEST_NUMBER 1 //Firmware uses request number 1 +#define MAXIMUM_SPI_REQUEST_NUMBER 3 + + +// +// ASM116 MMIO Index-Data Pair +// +#define ASM116_MMIO_INDEX 0xD0 //PCI offset 0xD0 ~ 0xD3: Index +#define ASM116_MMIO_INDEX_MASK 0x01L //bit0 - 0: access MMIO registers, 1: access 8051 xData +#define ASM116_MMIO_DATA 0xD4 //PCI offset 0xD4 ~ 0xD7: Data + +#define ASM116_MMIO_BASE_HW_REGISTER 0x10 + + +//ASM116 SPI control interface offset from BAR0+0x1000 +#define ASM116_SPI_CONTROL_BASE 0xB00L //SPI controller registers base address: MMIO offset 0x1B00 + +#define ASM116_SPI_CONTROL_DATA 0xB00L //SPI controller registers base address: MMIO offset 0x1B00 +#define ASM116_SPI_CONTROL_CONTROL 0xB04L //SPI controller registers base address: MMIO offset 0x1B00 + +#define ASM116_LSPI_MAXIMUM_LENGTH 4 //ASM116 legacy SPI supports Read/Write 4 bytes one time only + +#define PCIMMIO_MEM_DEV "/dev/mem" +#define PCIMMIO_MEMMAP_SIZE 0x1000 + + +// +// PPCI_DEVICE +// +typedef struct _PCI_DEVICE { + BYTE PciBusNumber; + BYTE PciDeviceNumber; + BYTE PciFunctionNumber; + + int treeAddress; + + //Char name[256]; + +} PCI_DEVICE, *PPCI_DEVICE; + + +// +// Functions Prototype +// + + int SpiControllerInit(struct pci_dev *PciDevice); + DWORD SpiReadRegisterDword(struct pci_dev *PciDevice, DWORD Register); + void SpiWriteRegisterDword(struct pci_dev *PciDevice, DWORD Register, DWORD dValue); + int SpiGetGrant(struct pci_dev *PciDevice, const BYTE RequestNumber); + void SpiReleaseGrant(struct pci_dev *PciDevice, const BYTE RequestNumber); + int SpiIs3WireMode(struct pci_dev *PciDevice); + void SpiStart(struct pci_dev *PciDevice); + void SpiTerminate(struct pci_dev *PciDevice); + int SpiIdle(struct pci_dev *PciDevice); + int SpiRead(struct pci_dev *PciDevice, void *pData, BYTE Length); + int SpiWrite(struct pci_dev *PciDevice, void *pData, BYTE Length); + + +#endif //_SPICTRL_H_ diff --git a/lib/synolib/asm116xfwdl/spifile.h b/lib/synolib/asm116xfwdl/spifile.h new file mode 100644 index 000000000000..bd87048b6e6d --- /dev/null +++ b/lib/synolib/asm116xfwdl/spifile.h @@ -0,0 +1,193 @@ +/************************************************************************************** +*Filename: spifile.h +*Description: +* Definitions Data structures of ASM116 SPI ROM file +* Refer to "Asmedia116 SPI ROM Format and Control" document +* +*History: +* 2013/08/19 V3.0 Jesse Chang Declare const for gASM116GUID +* Add Customer Configuration Table structure +* Delete following definitions: +* ASM116_MAXIMUM_LEGACY_OPROM_LENGTH +* ASM116_FIRST_FIRMWARE_STARTING_ADDRESS +* ASM116_SECOND_FIRMWARE_STARTING_ADDRESS +* ASM116_MAXIMUM_FIRMWARE_BINARY_LENGTH +* 2013/04/09 V2.1 Jesse Chang Add "Length of SPI ROM File" field in Identifier +* 2013/04/02 V1.1 Jesse Chang Add definitions of Identifier of SPI ROM file +* 2013/03/25 V1.0 Jesse Chang First version +* +* +* Asmedia ASM116x Firmware Update Tool +* +* Copyright (C) 2014-2016 ASMedia Technology +* +***************************************************************************************/ + +#ifndef _SPIFILE_H +#define _SPIFILE_H + +#define ASM116_GUID_LENGTH 16 //16-bytes GUID + +// +//ASM116 SPI ROM capacity +// +#define SPIROM_CAPACITY_64K (64*1024) //512M bits SPI ROM +#define SPIROM_CAPACITY_128K (128*1024) //1M bits SPI ROM +#define SPIROM_CAPACITY_256K (256*1024) //2M bits SPI ROM +#define SPIROM_CAPACITY_512K (512*1024) //4M bits SPI ROM + +#define ASM116_MAXIMUM_SPIROM_CAPACITY SPIROM_CAPACITY_512K + + +// +//ASM116 Register Table, little endian format +// +//#define ASM116_REGISTER_TABLE_LENGTH 256 //Length of register table is 256 bytes +#pragma pack(1) +typedef struct _REGISTER_PAIR_ { + WORD RegData; //Updated data, little endian + WORD RegOffset; //ASM116 MMIO register offset, little endian +} REGPAIR, *PREGPAIR; + +typedef struct _REGISTER_TABLE_ { + DWORD FirmwareStartAddress; //The first DWORD is firmware starting address, little endian + REGPAIR RegPair[63]; //Maximun 63 register-data pairs +} REGTBL, *PREGTBL; +#pragma pack() + +#define ASM116_REGISTER_TABLE_STARTING_ADDRESS 0x00000000 +#define ASM116_REGISTER_TABLE_FW_NOT_EXIST 0xFFFFFFFC //FirmwareStartAddress = 0xFFFFFFFC if firmware does not exist +#define ASM116_REGISTER_TABLE_ENDTAG 0x55AA //Register and Data are 0x55AA +#define ASM116_REGISTER_TABLE_LENGTH sizeof(REGTBL) //Length of register table is 256 bytes + + +// +//ASM116 firmware verification table, big endian format +// +//#define ASM116_VERIFICATION_TABLE_LENGTH 256 //Length of verification table is 256 bytes +//GUID = { 0xF6069CD3, 0x6844, 0x4BB4, { 0x8A, 0xC8, 0x5A, 0x07, 0xD6, 0xD7, 0xCA, 0x1B } } +#pragma pack(1) +typedef struct _VERIFICATION_DATA_ { //48 bytes verification data + BYTE Signature[4]; //4 bytes signature ASCII character + BYTE GUID[16]; //16 bytes GUID + DWORD BinaryAddress; //4 bytes big endian firmware binary starting address + DWORD BinaryLength; //4 bytes big endian firmware binary length + DWORD BinaryCrc32; //4 bytes big endian firmware binary CRC32 + BYTE Version[8]; //8 bytes firmware version. Reserved now + DWORD Generation; //4 bytes big endian firmware generation. 0x00000001 now + BYTE Rev1[3]; //3 bytes reserved for double-word aligment + BYTE Checksum; //1 byte checksum = sum of (Signature to Reserved) +} VERIFYDATA, *PVERIFYDATA; + +typedef struct _VERIFICATION_TABLE_ { //256 bytes verification table + VERIFYDATA VerifycationData1; //The first firmware verification data + BYTE Rev0[80]; //reserved 80 bytes + VERIFYDATA VerifycationData2; //The second firmware verification data + BYTE Rev1[80]; //reserved 80 bytes +} VERIFYTBL, *PVERIFYTBL; +#pragma pack() + +#define ASM116_VERIFICATION_TABLE_STARTING_ADDRESS 0x00000100 +#define VERIFICTION_SIGNATURE_LENGTH 4 //Signature is 4-bytes ASCII characters +#define VERIFICTION_SIGNATURE "ASMT" //Signature is 4-bytes ASCII characters +#define ASM116_VERIFICATION_TABLE_LENGTH sizeof(VERIFYTBL) //Length of verification table is 256 bytes + + +// +//ASM116 Identifier of SPI ROM File, little endian format +// +#pragma pack(1) +typedef struct _IDENTIFIER_DATA_ { //16 bytes + DWORD Address; //4 bytes Address + DWORD Length; //4 bytes Length + DWORD Crc32; //4 bytes CRC32 + DWORD Reserved; //4 bytes Reserved +} IDENTIFIERDATA, *PIDENTIFIERDATA; + +typedef struct _SPIFILE_IDENTIFIER_ { //256 bytes Identifier + BYTE GUID[16]; //16 bytes GUID + BYTE Rev0[16]; //16 bytes reserved for register table + IDENTIFIERDATA OpromImage; //16 bytes OPROM image identifier + IDENTIFIERDATA VerificationTable; //16 bytes verification table identifier + IDENTIFIERDATA FirstFirmwareBinary; //16 bytes first firmware binary identifier + IDENTIFIERDATA SecondFirmwareBinary; //16 bytes second firmware binary identifier + BYTE Rev1[148]; //148 bytes reserved + DWORD FileLength; //4 bytes length of SPI ROM file + DWORD CustomerID; //4 bytes customer ID + BYTE Rev2[3]; //3 bytes reserved + BYTE Checksum; //1 byte checksum +} SPIFILEIDENTIFIER, *PSPIFILEIDENTIFIER; +#pragma pack() + +#define ASM116_SPI_FILE_IDENTIFIER_STARTING_ADDRESS 0x00000200 +#define ASM116_SPI_FILE_IDENTIFIER_LENGTH sizeof(SPIFILEIDENTIFIER) //Length of Identifier is 256 bytes + + +// +//Customer Configuration Table +// +//GUID = { 0xF6069CD3, 0x6844, 0x4BB4, { 0x8A, 0xC8, 0x5A, 0x07, 0xD6, 0xD7, 0xCA, 0x1B } } +#pragma pack(1) +typedef struct _CONFIG_TABLE_ { + BYTE GUID[16]; //0x00-0xFF: 16 bytes GUID + BYTE Rev10[4]; //0x10-0x13: 4 bytes Reserved + BYTE AtaSerialNumber[20]; //0x14-0x27: 20 bytes ATA Serial Number WORD 0~9 + BYTE AtaModelNumber[40]; //0x28-0x4F: 40 bytes ATA Model Number WORD 0~19 + BYTE Rev50[171]; //0x50-0xFA: 171 bytes Reserved + BYTE StandbyTimer; //0xFB : 1 byte Standby Timer + BYTE Raid0StripeSize; //0xFC : 1 byte RAID 0 Stripe Size + BYTE RevFD; //0xFD : 1 byte Reserved + BYTE Signature; //0xFE : 1 byte signature + BYTE Checksum; //0xFF : 1 byte checksum +} CONFIGTBL, *PCONFIGTBL; +#pragma pack() + +#define ASM116_CONFIG_TABLE_STARTING_ADDRESS 0x00000300 +#define ASM116_CONFIG_TABLE_SIGNATURE 0x5A +#define ASM116_CONFIG_TABLE_LENGTH sizeof(CONFIGTBL) //Length of record table is 256 bytes + + +// +//Firmware record table +// +#pragma pack(1) +typedef struct _RECORD_TABLE_ { + BYTE Data[4*1024]; +} RECORDTBL, *PRECORDTBL; +#pragma pack() + +#define ASM116_RECORD_TABLE_STARTING_ADDRESS 0x00001000 +#define ASM116_RECORD_TABLE_LENGTH sizeof(RECORDTBL) //Length of record table is 4K bytes + + +// +//OPROM image region +// +#define ASM116_OPROM_STARTING_ADDRESS 0x00002000 //OPROM image is starting address 0x002000 (8K) + + +// +//Firmware binary region +// +//#define ASM116_FIRST_FIRMWARE_STARTING_ADDRESS 0x00010000L //The first firmware starting address is 0x010000 (64K) +//#define ASM116_SECOND_FIRMWARE_STARTING_ADDRESS 0x00040000L //The first firmware starting address is 0x040000 (256K) +//#define ASM116_MAXIMUM_FIRMWARE_BINARY_LENGTH (64*1024L) //Maximum firmware binary length is limited to 64K bytes + +// +//SPI ROM file header +// +#pragma pack(1) +typedef struct _SPIROM_HEADER_ { //8K bytes SPI ROM header + REGTBL RegisterTable; //0x000000 ~ 0x0000FF: Register table + VERIFYTBL VerificationTable; //0x000100 ~ 0x0001FF: Verification table + SPIFILEIDENTIFIER SpiFileIdentifier; //0x000200 ~ 0x0002FF: Identifier of SPI ROM file + CONFIGTBL ConfigTable; //0x000300 ~ 0x0003FF: Customer configuration table + BYTE Rev[3072]; //0x000400 ~ 0x000FFF: Reserved + RECORDTBL RecordTable; //0x001000 ~ 0x001FFF: Record table +} SPIROMHEADER, *PSPIROMHEADER; +#pragma pack() + +#define ASM116_SPIROM_HEADER_LENGTH sizeof(SPIROMHEADER) + +#endif //_SPIFILE_H + diff --git a/lib/synolib/asm116xfwdl/spiflash.c b/lib/synolib/asm116xfwdl/spiflash.c new file mode 100644 index 000000000000..b8b8e14be425 --- /dev/null +++ b/lib/synolib/asm116xfwdl/spiflash.c @@ -0,0 +1,1954 @@ +//*************************************************************************** +//Name: spiflash.c +// +//Description: +// Supported SPI flash ROM manipulative functions +// +//Revision History: +// 2014/06/13 V1.60 Jesse Chang Modify Maximum waiting Chip Erase time to 10000 ms for Flash Index 32 - Gigadevice GD25Q40B +// Add Flash Index 48 for Gigadevice GD25Q21B +// 2013/10/28 V1.20 Jesse Chang Correct Flash Index 35 - 38 flash id error for ESMT: F25L05PA, F25L01PA, F25L02PA, F25L04PA +// Add ATMEL AT25BCM512B (Flash Index is same as AT25F512B -> Flash Index 4) +// Add Flash Index 46 - 47 for ATMEL AT25DF021, AT25DF041A +// 2013/10/17 V1.10 Jesse Chang Don't need to use EWSR command in Cmd Table Index 2 for Winbond SPI flash ROM +// Set SPI_INDEX_EWSR_UNSUPPORTED in Winbond SPI flash Index +// Change PCT: 25VF512A from Cmd Table Index 3 to Cmd Table Index 4 +// Change PCT: 25VF020B from Cmd Table Index 3 to Cmd Table Index 6 +// Modify 2-bytes status register in Index 15 for PCT: 25VF020B, Microchip: SST25VF020B, SST25PF020B +// Add Cmd Table Index 6 for PCT: 25VF020B, Microchip: SST25VF020B, SST25PF020B +// Add Cmd Table Index 7 for Micron: M25P05, M25P10, M25PE10, M25P20, M25P20S, M25PE20S, M25P40 +// Add Flash Index 35 - 38 for ESMT: F25L05PA, F25L01PA, F25L02PA, F25L04PA +// Add Flash Index 39 - 45 for Micron: M25P05, M25P10, M25PE10, M25P20, M25P20S, M25PE20S, M25P40, M25PE40, M25PE40S +// 2013/05/30 V1.02 James Peng Only use READ command in SpiFlashReadData function +// Add Flash Index 33 - 34 for MXIC: MX25L5121E, MX25L1021E +// 2013/04/06 V1.0 Jesse Chang First revision +// +/* + * Asmedia ASM116x Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ +//*************************************************************************** + +//#include "stdafx.h" +#include "precomp.h" +#include "spiflash.h" +#include "spictrl.h" + + +// +// Supported SPI flash command tables +// +//typedef struct _SPI_FLASH_COMMAND_TABLE { +// BYTE WriteEnableCmd; //Write Enable command code +// BYTE WritDisableCmd; //Write Disable command code +// BYTE ReadSTSR1Cmd; //Read Status Register 1 command code +// BYTE ReadSTSR2Cmd; //Read Status Register 2 command code +// BYTE WriteSTSR; //Write Status Register command code +// BYTE EnableWriteSTSRCmd; //Enable Write Status Register command code +// BYTE ReadCmd; //Read command code +// BYTE FastReadCmd; //Fast Read command code +// BYTE ChipEraseCmd; //Chip Erase command code +// BYTE SectorEraseCmd; //Sector Erase 4k bytes command code +// BYTE PageProgramCmd; //Page Program command code +// BYTE AutoAddressIncProCmd; //Auto Address Increment Program command code for PCT SPI flash ROM only +//} SPI_FLASH_COMMAND_TABLE, *PSPI_FLASH_COMMAND_TABLE; +// + +const SPI_FLASH_COMMAND_TABLE SUPPORTED_SPI_FLASH_COMMAND_TABLE[] = { + //Cmd Table Index 0: default table + //AMIC: A25L512, A25L512A, A25LS512A, A25L010, A25L010A, A25L020, A25L020C, A25L040, A25L040A + //ATMEL: AT25F512B + //EON: EN25F05, EN25F10, EN25LF10, EN25F20, EN25LF20, EN25F40, EN25LF40, EN25Q40 + //MXIC: MX25L512E, MX25V512E, MX25L1006E, MX25L1026E, MX25V1006E, MX25L2006E, MX25L2026E, MX25V2006E, + // MX25L4006E, MX25L4026E, MX25V4006E + // MX25L5121E, MX25L1021E + //Pflash: Pm25LD512, Pm25LD512C, Pm25LD010, Pm25LD010C, Pm25LD020, Pm25LD020C + //ESMT: F25L05PA, F25L01PA, F25L02PA, F25L04PA + //Micron: M25PE40, M25PE40S + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + SPICMD_UNSUPPORTED, //Read Status Register 2 command unsupported + 0x01, //Write Status Register command code + SPICMD_UNSUPPORTED, //Enable Write Status Register command unsupported + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + 0x20, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + SPICMD_UNSUPPORTED //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 1: + //Pflash: Pm25LV512A, Pm25LV010A, Pm25LV020, Pm25LV040, Pm25LD040, Pm25LD040C + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + SPICMD_UNSUPPORTED, //Read Status Register 2 command unsupported + 0x01, //Write Status Register command code + SPICMD_UNSUPPORTED, //Enable Write Status Register command unsupported + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + 0xD7, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + SPICMD_UNSUPPORTED //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 2: + //Winbond: W25X05CL, W25X10CL, W25X10BV, W25X10BL, W25X20CL, W25X20BV, W25X20BL, W25X40CL, W25X40BV, W25X40BL + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + SPICMD_UNSUPPORTED, //Read Status Register 2 command unsupported + 0x01, //Write Status Register command code + SPICMD_UNSUPPORTED, //Enable Write Status Register command code + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + 0x20, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + SPICMD_UNSUPPORTED //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 3: + //PCT: 25VF010A, 25VF040B + //Microchip: SST25VF010A, SST25VF040B, SST25PF040B + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + SPICMD_UNSUPPORTED, //Read Status Register 2 command unsupported + 0x01, //Write Status Register command code + 0x50, //Enable Write Status Register command code + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + 0x20, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + 0xAF //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 4: + //PCT: 25VF512A, 25VF020 + //Microchip: SST25VF512, SST25VF512A, SST25VF020, SST25VF020A + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + SPICMD_UNSUPPORTED, //Read Status Register 2 command unsupported + 0x01, //Write Status Register command code + 0x50, //Enable Write Status Register command code + 0x03, //Read Data command code + SPICMD_UNSUPPORTED, //Fast Read Data command unsupported + 0x60, //Chip Erase command code + 0x20, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + 0xAF //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 5: + //Gigadevice: GD25Q512, GD25Q10, GD25Q20B, GD25Q40B, GD25Q21B + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + 0x35, //Read Status Register 2 command code + 0x01, //Write Status Register command code + SPICMD_UNSUPPORTED, //Enable Write Status Register command unsupported + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + 0x20, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + SPICMD_UNSUPPORTED //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 6: + //PCT: 25VF020B + //Microchip: SST25VF020B, SST25PF020B + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + 0x35, //Read Status Register 2 command code + 0x01, //Write Status Register command code + 0x50, //Enable Write Status Register command code + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + 0x20, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + 0xAF //Auto Address Increment Program command unsupported + }, + + //Cmd Table Index 7: + //Micron: M25P05, M25P10, M25PE10, M25P20, M25P20S, M25PE20S, M25P40 + { + 0x06, //Write Enable command code + 0x04, //Write Disable command code + 0x05, //Read Status Register 1 command code + SPICMD_UNSUPPORTED, //Read Status Register 2 command unsupported + 0x01, //Write Status Register command code + SPICMD_UNSUPPORTED, //Enable Write Status Register command unsupported + 0x03, //Read Data command code + 0x0B, //Fast Read Data command code + 0xC7, //Chip Erase command code + SPICMD_UNSUPPORTED, //Sector Erase 4k bytes command code + 0x02, //Program Page command code + SPICMD_UNSUPPORTED //Auto Address Increment Program command unsupported + }, +}; + +#define NUMBER_OF_SPI_COMMAND_TABLES (sizeof(SUPPORTED_SPI_FLASH_COMMAND_TABLE)/sizeof(SPI_FLASH_COMMAND_TABLE)) +#define DEFAULT_SPI_COMMAND_TABLE 0 + + +// +// SPI flash supported list +// +//typedef struct _SPI_FLASH_INDEX { +// BYTE FlashID[3]; //3 bytes spi flash rom product id +// BYTE CmdTableIndex; //Index of SPI falsh command table +// WORD Capacity; //Capacity K Bytes +// //Characters of different SPI flash ROM +// BYTE WriteSTSRBytes; //1 or 2 bytes when Write Status Register +// BYTE EnableWriteSTSR; //1: Enable Write Status Register command prior to Write Status Register command +// WORD PageLength; //length of program page command +// CHAR ProductString[14]; //Product string +//} SPI_FLASH_INDEX, *PSPI_FLASH_INDEX; +// + +const SPI_FLASH_INDEX SUPPORTED_SPI_FLASH_INDEX_TABLE[] = { + //Index 0 - AMIC: A25L512, A25L512A, A25LS512A + { + {0x37, 0x30, 0x10}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', '2', '5', 'L', '5', '1', '2', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 1 - AMIC: A25L010, A25L010A + { + {0x37, 0x30, 0x11}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', '2', '5', 'L', '0', '1', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 2 - AMIC: A25L020, A25L020C + { + {0x37, 0x30, 0x12}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', '2', '5', 'L', '0', '2', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 6000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 3 - AMIC: A25L040, A25L040A + { + {0x37, 0x30, 0x13}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', '2', '5', 'L', '0', '4', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 12000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 4 - ATMEL: AT25F512B, AT25BCM512B + { + {0x1F, 0x65, 0x00}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', 'T', '2', '5', 'F', '5', '1', '2', 'B', '\0', 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 5 - EON: EN25F05 + { + {0x1C, 0x31, 0x10}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'E', 'N', '2', '5', 'F', '0', '5', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 6 - EON: EN25F10, EN25LF10 + { + {0x1C, 0x31, 0x11}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'E', 'N', '2', '5', 'F', '1', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 7 - EON: EN25F20, EN25LF20 + { + {0x1C, 0x31, 0x12}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'E', 'N', '2', '5', 'F', '2', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 8000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 8 - EON: EN25F40, EN25LF40, EN25Q40 + { + {0x1C, 0x31, 0x13}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'E', 'N', '2', '5', 'F', '4', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 20000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 9 - MXIC: MX25L512E, MX25V512E + { + {0xC2, 0x20, 0x10}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', 'X', '2', '5', 'L', '5', '1', '2', 'E', '\0', 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 10 - MXIC: MX25L1006E, MX25V1006E, MX25L1026E + { + {0xC2, 0x20, 0x11}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', 'X', '2', '5', 'L', '1', '0', '0', '6', 'E', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 11 - MXIC: MX25L2006E, MX25V2006E, MX25L2026E + { + {0xC2, 0x20, 0x12}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', 'X', '2', '5', 'L', '2', '0', '0', '6', 'E', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 12 - MXIC: MX25L4006E, MX25V4006E, MX25L4026E + { + {0xC2, 0x20, 0x13}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', 'X', '2', '5', 'L', '4', '0', '0', '6', 'E', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 10000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 13 - PCT: 25VF512A, Microchip: SST25VF512, SST25VF512A + { + {0xBF, 0x48, 0xBF}, //3 bytes: flash id + 04, //1 byte: Cmd Table Index 4 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_SUPPORTED, //1 bytes: EWSR needs prior to WRSR command + 01, //1 word: 1 byte program + {'2', '5', 'V', 'F', '5', '1', '2', 'A', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 14 - PCT: 25VF010A, Microchip: SST25VF010A + { + {0xBF, 0x49, 0xBF}, //3 bytes: flash id + 03, //1 byte: Cmd Table Index 3 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_SUPPORTED, //1 bytes: EWSR needs prior to WRSR command + 01, //1 word: 1 byte program + {'2', '5', 'V', 'F', '0', '1', '0', 'A', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 15 - PCT: 25VF020B, Microchip: SST25VF020B, SST25PF020B + { + {0xBF, 0x25, 0x8C}, //3 bytes: flash id + 06, //1 byte: Cmd Table Index 6 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x02, //1 byte: 2 bytes Status Register + SPI_INDEX_EWSR_SUPPORTED, //1 bytes: EWSR needs prior to WRSR command + 01, //1 word: 1 byte program + {'2', '5', 'V', 'F', '0', '2', '0', 'B', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 16 - PCT: 25VF040B, Microchip: SST25VF040B, SST25PF040B + { + {0xBF, 0x25, 0x8D}, //3 bytes: flash id + 03, //1 byte: Cmd Table Index 3 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_SUPPORTED, //1 bytes: EWSR needs prior to WRSR command + 01, //1 word: 1 byte program + {'2', '5', 'V', 'F', '0', '4', '0', 'B', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 17 - PCT: 25VF020, Microchip: SST25VF020, SST25VF020A + { + {0xBF, 0x43, 0xBF}, //3 bytes: flash id + 04, //1 byte: Cmd Table Index 4 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_SUPPORTED, //1 bytes: EWSR needs prior to WRSR command + 01, //1 word: 1 byte program + {'2', '5', 'V', 'F', '0', '2', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 18 - Pflash: Pm25LD512, Pm25LD512C + { + {0x7F, 0x9D, 0x20}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'D', '5', '1', '2', 'C', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 19 - Pflash: Pm25LD010, Pm25LD010C + { + {0x7F, 0x9D, 0x21}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'D', '0', '1', '0', 'C', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 20 - Pflash: Pm25LD020, Pm25LD020C + { + {0x7F, 0x9D, 0x22}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'D', '0', '2', '0', 'C', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 21 - Pflash: Pm25LV512A + { + {0x9D, 0x7B, 0x7F}, //3 bytes: flash id + 01, //1 byte: Cmd Table Index 1 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'V', '5', '1', '2', 'A', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 22 - Pflash: Pm25LV010A + { + {0x7F, 0x9D, 0x7C}, //3 bytes: flash id + 01, //1 byte: Cmd Table Index 1 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'V', '0', '1', '0', 'A', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 23 - Pflash: Pm25LV020 + { + {0x7F, 0x9D, 0x7D}, //3 bytes: flash id + 01, //1 byte: Cmd Table Index 1 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'V', '0', '2', '0', 'A', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 24 - Pflash: Pm25LV040, Pm25LD040, Pm25LD040C + { + {0x7F, 0x9D, 0x7E}, //3 bytes: flash id + 01, //1 byte: Cmd Table Index 1 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'P', 'm', '2', '5', 'L', 'V', '0', '4', '0', '\0', 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 1000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 25 - Winbond: W25X05CL + { + {0xEF, 0x30, 0x10}, //3 bytes: flash id + 02, //1 byte: Cmd Table Index 2 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: EWSR needs prior to WRSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'W', '2', '5', 'X', '0', '5', 'C', 'L', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 26 - Winbond: W25X10CL, W25X10BV, W25X10BL + { + {0xEF, 0x30, 0x11}, //3 bytes: flash id + 02, //1 byte: Cmd Table Index 2 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: EWSR needs prior to WRSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'W', '2', '5', 'X', '1', '0', 'C', 'L', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 27 - Winbond: W25X20CL, W25X20BV, W25X20BL + { + {0xEF, 0x30, 0x12}, //3 bytes: flash id + 02, //1 byte: Cmd Table Index 2 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: EWSR needs prior to WRSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'W', '2', '5', 'X', '2', '0', 'C', 'L', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 28 - Winbond: W25X40CL, W25X40BV, W25X40BL + { + {0xEF, 0x30, 0x13}, //3 bytes: flash id + 02, //1 byte: Cmd Table Index 2 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: EWSR needs prior to WRSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'W', '2', '5', 'X', '4', '0', 'C', 'L', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 29 - Gigadevice: GD25Q512 + { + {0xC8, 0x40, 0x10}, //3 bytes: flash id + 05, //1 byte: Cmd Table Index 5 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x02, //1 byte: 2 bytes Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'G', 'D', '2', '5', 'Q', '5', '1', '2', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 30 - Gigadevice: GD25Q10 + { + {0xC8, 0x40, 0x11}, //3 bytes: flash id + 05, //1 byte: Cmd Table Index 5 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x02, //1 byte: 2 bytes Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'G', 'D', '2', '5', 'Q', '1', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 31 - Gigadevice: GD25Q20B + { + {0xC8, 0x40, 0x12}, //3 bytes: flash id + 05, //1 byte: Cmd Table Index 5 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x02, //1 byte: 2 bytes Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'G', 'D', '2', '5', 'Q', '2', '0', 'B', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 6000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 32 - Gigadevice: GD25Q40B + { + {0xC8, 0x40, 0x13}, //3 bytes: flash id + 05, //1 byte: Cmd Table Index 5 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x02, //1 byte: 2 bytes Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'G', 'D', '2', '5', 'Q', '4', '0', 'B', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 10000, //1 word: Maximum waiting Chip Erase time (ms) + }, + //Index 33 - MXIC: MX25L5121E + { + {0xC2, 0x22, 0x10}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH_32, //1 word: 32 bytes page + {'M', 'X', '2', '5', 'L', '5', '1', '2','1', 'E', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + //Index 34 - MXIC: MX25L1021E + { + {0xC2, 0x22, 0x11}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH_32, //1 word: 32 bytes page + {'M', 'X', '2', '5', 'L', '1', '0', '2','1', 'E', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 35 - ESMT: F25L05PA + { + {0x8C, 0x30, 0x10}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'F', '2', '5', 'L', '0', '5', 'P', 'A','\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 36 - ESMT: F25L01PA + { + {0x8C, 0x30, 0x11}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'F', '2', '5', 'L', '0', '1', 'P', 'A','\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 37 - ESMT: F25L02PA + { + {0x8C, 0x30, 0x12}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'F', '2', '5', 'L', '0', '2', 'P', 'A','\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 38 - ESMT: F25L04PA + { + {0x8C, 0x30, 0x13}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'F', '2', '5', 'L', '0', '4', 'P', 'A','\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 6000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 39 - Micron: M25P05 + { + {0x20, 0x20, 0x10}, //3 bytes: flash id + 7, //1 byte: Cmd Table Index 7 + SPI_FLASH_64KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', '0', '5', '\0', 0, 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 7000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 40 - Micron: M25P10 + { + {0x20, 0x20, 0x11}, //3 bytes: flash id + 7, //1 byte: Cmd Table Index 7 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', '1', '0', '\0', 0, 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 7000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 41 - Micron: M25PE10 + { + {0x20, 0x80, 0x11}, //3 bytes: flash id + 7, //1 byte: Cmd Table Index 7 + SPI_FLASH_128KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', 'E', '1', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 10000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 42 - Micron: M25P20, M25P20S + { + {0x20, 0x20, 0x12}, //3 bytes: flash id + 7, //1 byte: Cmd Table Index 7 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', '2', '0', '\0', 0, 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 7000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 43 - Micron: M25PE20S + { + {0x20, 0x80, 0x12}, //3 bytes: flash id + 7, //1 byte: Cmd Table Index 7 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', 'E', '2', '0', 'S', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 10000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 44 - Micron: M25P40 + { + {0x20, 0x20, 0x13}, //3 bytes: flash id + 7, //1 byte: Cmd Table Index 7 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', '4', '0', '\0', 0, 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 10000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 45 - Micron: M25PE40, M25PE40S + { + {0x20, 0x80, 0x13}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'M', '2', '5', 'P', 'E', '4', '0', '\0', 0, 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 10000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 46 - ATMEL: AT25DF021 + { + {0x1F, 0x43, 0x00}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', 'T', '2', '5', 'D', 'F', '0', '2', '1', '\0', 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 47 - ATMEL: AT25DF041A + { + {0x1F, 0x44, 0x01}, //3 bytes: flash id + 0, //1 byte: Cmd Table Index 0 + SPI_FLASH_512KB, //1 word: capacity K bytes + 0x01, //1 byte: 1 byte Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'A', 'T', '2', '5', 'D', 'F', '0', '2', '1', 'A', '\0', 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 8000, //1 word: Maximum waiting Chip Erase time (ms) + }, + + //Index 48 - Gigadevice: GD25Q21B + { + {0xC8, 0x41, 0x12}, //3 bytes: flash id + 05, //1 byte: Cmd Table Index 5 + SPI_FLASH_256KB, //1 word: capacity K bytes + 0x02, //1 byte: 2 bytes Status Register + SPI_INDEX_EWSR_UNSUPPORTED, //1 bytes: Don't support SPI EWSR command + SPI_INDEX_DEFAULT_PAGE_LENGTH, //1 word: 256 bytes page + {'G', 'D', '2', '5', 'Q', '2', '1', 'B', '\0', 0, 0, 0, 0, 0}, //14 bytes: product string + 1000, //1 word: Maximum waiting Sector Erase or Page Program time (ms) + 5000, //1 word: Maximum waiting Chip Erase time (ms) + }, +}; + +#define NUMBER_OF_SPI_FLASH_INDEXS (sizeof(SUPPORTED_SPI_FLASH_INDEX_TABLE)/sizeof(SPI_FLASH_INDEX)) + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// SPI flash command functions +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + + +// +//Procedure: SpiFlashJedecRDID +//Description: Use JEDEC RDID (0x9F) command to read 3 bytes flash id +//Input: SpiControlExtension - SPI controller extension +// FlashID - ID buffer +//Output: ASMT_SUCCESS - command completed +//Note: +// The Read JEDEC Identification (RDID) instruction allows the 8-bit manufacturer identification to be read, +// followed by two bytes of device identification. +// Any Read Identification (RDID) instruction while an Erase or Program cycle is in progress, is not +// decoded, and has no effect on the cycle that is in progress. +// +int SpiFlashJedecRDID(struct pci_dev *PciDevice, BYTE *FlashID) +{ + BYTE SpiFlashCmd; + + SpiFlashCmd = SPICMD_JEDEC_RDID; //0x9F + + if(verblevel) + printk(KERN_INFO "SpiFlashJedecRDID: SPI command code = 0x%02X\n", SpiFlashCmd); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiRead(PciDevice, FlashID, 3); //Read 3 bytes + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashRDID +//Description: Use RDID (0xAB) + 3 dummy bytes command to read 3 bytes flash id +//Input: SpiControlExtension - SPI controller extension +// FlashID - ID buffer +//Output: ASMT_SUCCESS - Command completed +// FALSE - others +//Note: +// Only +// Pflash: Pm25LV512A, +// PCT: 25VF512A, 25VF010A, 25VF020, +// Microchip: SST25VF512, SST25VF512A, SST25VF010A, SST25VF020, SST25VF020A +// must use this command to get flash ID +// The dummy bytes for +// PCT 25VF512A, 25VF010A, 25VF020, +// Microchip: SST25VF512, SST25VF512A, SST25VF010A, SST25VF020, SST25VF020A +// must be 0x00 +// +int SpiFlashRDID(struct pci_dev *PciDevice, BYTE *FlashID) +{ + BYTE SpiFlashCmd[4]; + + SpiFlashCmd[0] = SPICMD_RDP; //0xAB + SpiFlashCmd[1] = 0; //0x00 + SpiFlashCmd[2] = 0; //0x00 + SpiFlashCmd[3] = 0; //0x00 +if(verblevel) + printk(KERN_INFO "SpiFlashRDID: SPI command code = 0x%02X\n", SpiFlashCmd[0]); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 4); //Write 4 bytes + SpiRead(PciDevice, FlashID, 3); //Read 3 bytes + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +// DetectSpiFlashRom() must be called and return ASMT_SUCCESS before use following SPI flash functions +// + +// +//Procedure: SpiFlashWREN +//Description: SPI flash write enable. Write Enable Latch (WEL) bit of Status Register 1 will be set +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - Command completed +// +int SpiFlashWREN(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd; + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd = pCmdTbl->WriteEnableCmd; //0x06 + + if(verblevel) + printk(KERN_INFO "SpiFlashWREN: SPI command code = 0x%02X\n", SpiFlashCmd); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashWRDI +//Description: SPI flash write disable. Write Enable Latch (WEL) bit of Status Register 1 will be reset +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - Command completed +//Note: +// WEL bit is automatically reset after Power-up and upon completion of the Write Status Register, +// Page Program, Sector(Block) Erase, and Bulk(Chip) Erase instructions. +// +int SpiFlashWRDI(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd; + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd = pCmdTbl->WritDisableCmd; //0x04 + + if(verblevel) + printk(KERN_INFO "SpiFlashWRDI: SPI command code = 0x%02X\n", SpiFlashCmd); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashRDSR1 +//Description: Read SPI flash Status Register 1 +//Input: pSpiFlashExtension - SPI flash extension +// pStsr1 - SPI flash Status Register 1 +//Output: ASMT_SUCCESS - Command completed +//Note: +// The Status Register may be read at any time, even while a Program, Erase or Write Status Register cycle is in progress. +// +int SpiFlashRDSR1(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, PSPI_FLASH_STSR1 pStsr1) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd; + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd = pCmdTbl->ReadSTSR1Cmd; //0x05 + +//#ifdef DEBUG_FLASH_FUNCTION +// printk(KERN_INFO "SpiFlashRDSR1: SPI command code = 0x%02X\n", SpiFlashCmd); +//#endif //DEBUG_FLASH_FUNCTION + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiRead(PciDevice, pStsr1, 1); //Read 1 byte + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashRDSR2 +//Description: Read SPI flash Status Register 2 +//Input: pSpiFlashExtension - SPI flash extension +// pStsr2 - SPI flash Status Register 2 +//Output: ASMT_SUCCESS - Command completed +//Note: +// The Status Register may be read at any time, even while a Program, Erase or Write Status Register cycle is in progress. +// +int SpiFlashRDSR2(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, PSPI_FLASH_STSR2 pStsr2) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd; + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd = pCmdTbl->ReadSTSR2Cmd; //0x35 + +//#ifdef DEBUG_FLASH_FUNCTION +// printk(KERN_INFO "SpiFlashRDSR2: SPI command code = 0x%02X\n", SpiFlashCmd); +//#endif //DEBUG_FLASH_FUNCTION + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiRead(PciDevice, pStsr2, 1); //Read 1 byte + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashEWSR +//Description: Use EWSR command to enable write Status Register +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - Command completed +// ASMT_PARAMETER_INVALID - others +//Note: +// EWSR command must be prior to WRSR command if SPI flash support EWSR command +//PCT: 25VF512A, 25VF010A, 25VF020B, 25VF040B, 25VF020 +//Winbond: W25X05CL, W25X10CL, W25X20CL, W25X40CL +// +int SpiFlashEWSR(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd; + + if(SpiControl->SpiIndex.EnableWriteSTSR == 0) + { + return ASMT_PARAMETER_INVALID; + } + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd = pCmdTbl->EnableWriteSTSRCmd; //0x50 + + if(verblevel) + printk(KERN_INFO "SpiFlashEWSR: SPI command code = 0x%02X\n", SpiFlashCmd); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashWRSR1 +//Description: Use WRSR command to write Status Register 1 +//Input: pSpiFlashExtension - SPI flash extension +// Stsr1 - Status Register 1 +//Output: ASMT_SUCCESS - Command completed +//Note: +// Write Enable (WREN) instruction must previously have been executed. +// EWSR command must be prior to WRSR command if SPI flash support EWSR command +//PCT: 25VF512A, 25VF010A, 25VF020B, 25VF040B, 25VF020 +//Winbond: W25X05CL, W25X10CL, W25X20CL, W25X40CL +// +int SpiFlashWRSR1(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, SPI_FLASH_STSR1 Stsr1) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd[2]; + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd[0] = pCmdTbl->WriteSTSR; //0x01 + SpiFlashCmd[1] = Stsr1.AsByte; + + if(verblevel) { + printk(KERN_INFO "SpiFlashWRSR1: SPI command code = 0x%02X, Write 1 byte SSTR\n", SpiFlashCmd[0]); + } + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 2); //Write 2 bytes + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashWRSR2 +//Description: Use WRSR command to write Status Register 1 and 2 +//Input: pSpiFlashExtension - SPI flash extension +// Stsr1 - Status Register 1 +// Stsr2 - Status Register 2 +//Output: ASMT_SUCCESS - Command completed +//Note: +// Write Enable (WREN) instruction must previously have been executed. +// EWSR command must be prior to WRSR command if SPI flash support EWSR command +//PCT: 25VF512A, 25VF010A, 25VF020B, 25VF040B, 25VF020 +//Winbond: W25X05CL, W25X10CL, W25X20CL, W25X40CL +// +int SpiFlashWRSR2(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, SPI_FLASH_STSR1 Stsr1, SPI_FLASH_STSR2 Stsr2) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd[3]; + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd[0] = pCmdTbl->WriteSTSR; //0x01 + SpiFlashCmd[1] = Stsr1.AsByte; + SpiFlashCmd[2] = Stsr2.AsByte; + + if(verblevel) + printk(KERN_INFO "SpiFlashWRSR2: SPI command code = 0x%02X, Write 2 byte SSTR\n", SpiFlashCmd[0]); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 3); //Write 3 bytes + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashCE +//Description: Use Chip Erase command to erase SPI flash +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - Command completed +//Note: +// The Chip Erase instruction is executed only if all Block Protect (BP1, BP0) bits are 0. +// +int SpiFlashCE(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd; + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd = pCmdTbl->ChipEraseCmd; //0xC7 or 0x60 + if(verblevel) + printk(KERN_INFO "SpiFlashCE: SPI command code = 0x%02X\n", SpiFlashCmd); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, &SpiFlashCmd, 1); //Write 1 byte + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashSE +//Description: Use Sector Erase command to erase one 4k bytes sector +//Input: pSpiFlashExtension - SPI flash extension +// Address - Specific address +//Output: ASMT_SUCCESS - Command completed +//Note: +// A Sector Erase (SE) instruction applied to a sector which is protected by the Block Protect (BP0, BP1,...) bits is not executed. +// SPI flash decodes 24 bits only +// +int SpiFlashSE(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, DWORD Address) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE SpiFlashCmd[4]; + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + SpiFlashCmd[0] = pCmdTbl->SectorEraseCmd; //0x20 or 0xD7 + SpiFlashCmd[1] = (BYTE)(Address >> 16); //bit 23:16 + SpiFlashCmd[2] = (BYTE)(Address >> 8); //bit 15:08 + SpiFlashCmd[3] = (BYTE)Address; //bit 07:00 + + if(verblevel) { + printk(KERN_INFO "SpiFlashSE: SPI command code = 0x%02X, Address = 0x%04X\n", SpiFlashCmd[0], Address); + } + + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 4); //Write 4 bytes + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashPP +//Description: Use Page Program command to program SPI flash +//Input: pSpiFlashExtension - SPI flash extension +// Address - Specific address +// pData - Data buffer +// Length - Programmed data length +//Output: ASMT_SUCCESS - Command completed +// ASMT_PARAMETER_INVALID - others +//Note: +// Write Enable (WREN) instruction must previously have been executed. +// If more than one page are sent to the device, previously latched data are discarded and the last page data bytes +// are guaranteed to be programmed correctly within the same page. +// A Page Program (PP) instruction applied to a page which is protected by the Block Protect (BP0, BP1,...) bits is not executed. +// If page length = 1 and Length > 1, the programmed result is undetermined. +// +int SpiFlashPP(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, WORD Length) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE *pByte; + WORD Outstanding; + BYTE SpiFlashCmd[4]; + BYTE WriteLength; + + if(Length == 0) + { + return ASMT_PARAMETER_INVALID; + } + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + //Write command and address + SpiFlashCmd[0] = pCmdTbl->PageProgramCmd; //0x02 + SpiFlashCmd[1] = (BYTE)(Address >> 16); //bit 23:16 + SpiFlashCmd[2] = (BYTE)(Address >> 8); //bit 15:08 + SpiFlashCmd[3] = (BYTE)Address; //bit 07:00 + + if(verblevel) + printk(KERN_INFO "SpiFlashPP: SPI command code = 0x%02X, Address = 0x%04X, Length = %d\n", SpiFlashCmd[0], Address, Length); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 4); //Write 4 bytes + + //Write data + Outstanding = Length; + pByte = (BYTE *)pData; + while(Outstanding > 0) + { + WriteLength = (Outstanding >= 4) ? 4 : Outstanding; //ASM116 LSPI maximum data buffer = 4 + SpiWrite(PciDevice, pByte, WriteLength); + Outstanding = Outstanding - WriteLength; + pByte = pByte + WriteLength; + } + + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashREAD +//Description: Use READ command to read SPI flash +//Input: pSpiFlashExtension - SPI flash extension +// Address - Specific address +// pData - Data buffer +// Length - Read length +//Output: ASMT_SUCCESS - Command completed +// ASMT_PARAMETER_INVALID - others +int SpiFlashREAD(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, int Length) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE *pByte; + int Outstanding; + BYTE SpiFlashCmd[4]; + BYTE ReadLength; + + if(Length == 0L) + { + return ASMT_PARAMETER_INVALID; + } + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + //Write command and address + SpiFlashCmd[0] = pCmdTbl->ReadCmd; //0x03 + SpiFlashCmd[1] = (BYTE)(Address >> 16); //bit 23:16 + SpiFlashCmd[2] = (BYTE)(Address >> 8); //bit 15:08 + SpiFlashCmd[3] = (BYTE)Address; //bit 07:00 + + if(verblevel) + printk(KERN_INFO "SpiFlashREAD: SPI command code = 0x%02X, Address = 0x%04X, Length = %X\n", SpiFlashCmd[0], Address, Length); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 4); //Write 4 bytes + + //Read data + Outstanding = Length; + pByte = (BYTE *)pData; + while(Outstanding > 0) + { + //ReadLength = (Outstanding >= 4) ? 4 : Outstanding; //ASM116 LSPI maximum data buffer = 4 + if(Outstanding >= 4) + { + ReadLength = 4; + }else + { + ReadLength = (BYTE)Outstanding; + } + + SpiRead(PciDevice, pByte, ReadLength); + Outstanding = Outstanding - ReadLength; + pByte = pByte + ReadLength; + } + + SpiTerminate(PciDevice); + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashFREAD +//Description: Use FAST READ command to read SPI flash +//Input: pSpiFlashExtension - SPI flash extension +// pData - Data buffer +// Address - Specific address +// Length - Read length +//Output: ASMT_SUCCESS - Command completed +// ASMT_PARAMETER_INVALID - others +int SpiFlashFREAD(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, int Length) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE *pByte; + int Outstanding; + BYTE SpiFlashCmd[4]; + BYTE ReadLength; + BYTE Dummy; + + if(Length == 0L) + { + return ASMT_PARAMETER_INVALID; + } + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + //Write command and address + SpiFlashCmd[0] = pCmdTbl->FastReadCmd; //0x0B + SpiFlashCmd[1] = (BYTE)(Address >> 16); //bit 23:16 + SpiFlashCmd[2] = (BYTE)(Address >> 8); //bit 15:08 + SpiFlashCmd[3] = (BYTE)Address; //bit 07:00 + + if(verblevel) + printk(KERN_INFO "SpiFlashFREAD: SPI command code = 0x%02X, Address = 0x%04X, Length = %d\n", SpiFlashCmd[0], Address, Length); + + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 4); //Write 4 bytes + + //Write dummy byte + Dummy = 0; + SpiWrite(PciDevice, &Dummy, 1); //Write 1 dummy byte + + //Read data + Outstanding = Length; + pByte = (BYTE *)pData; + while(Outstanding > 0) + { + //ReadLength = (Outstanding >= 4) ? 4 : Outstanding; //ASM116 LSPI maximum data buffer = 4 + if(Outstanding >= 4) + { + ReadLength = 4; + }else + { + ReadLength = (BYTE)Outstanding; + } + + SpiRead(PciDevice, pByte, ReadLength); + Outstanding = Outstanding - ReadLength; + pByte = pByte + ReadLength; + } + + SpiTerminate(PciDevice); + + if(verblevel) + printk(KERN_INFO "SpiFlashFREAD: Fast Read completed\n"); + + + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashWaitWriteEnabled +//Description: Wait Status Register 1 WEL bit is set +//Input: pSpiFlashExtension - SPI flash extension +// WaitingTime - Waiting time (ms) +//Output: ASMT_SUCCESS - WEL bit is set +// ASMT_TIMEOUT - time out +int SpiFlashWaitWriteEnabled(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, WORD WaitingTime) +{ + SPI_FLASH_STSR1 Stsr1; + int BoolTimeout; + clock_t ticks1, ticks2; + + SpiFlashRDSR1(PciDevice,SpiControl, (PSPI_FLASH_STSR1)&Stsr1); + ticks1 = jiffies; + ticks2 = ticks1; + BoolTimeout = ASMT_SUCCESS; + while( Stsr1.WEL == 0 ) + { + SpiFlashRDSR1(PciDevice,SpiControl, (PSPI_FLASH_STSR1)&Stsr1); + ticks2 = jiffies; + if( (((ticks2 - ticks1)*1000)/ CLOCKS_PER_SEC ) > WaitingTime ) + { + BoolTimeout = ASMT_TIMEOUT; + break; + } + } + + if(BoolTimeout == ASMT_TIMEOUT) + { + if (verblevel) + printk(KERN_INFO " SpiFlashWaitWriteEnabled WaitWriteEnabled: Timeout!!!\n"); + } + + + return BoolTimeout ; +} + + +// +//Procedure: SpiFlashWaitWriteCompleted +//Description: Wait Status Register 1 WIP bit is reset +//Input: pSpiFlashExtension - SPI flash extension +// WaitingTime - Waiting time (ms) +//Output: ASMT_SUCCESS - WEL bit is set +// ASMT_TIMEOUT - time out +int SpiFlashWaitWriteCompleted(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, WORD WaitingTime) +{ + SPI_FLASH_STSR1 Stsr1; + int BoolTimeout; + clock_t ticks1, ticks2; + + SpiFlashRDSR1(PciDevice,SpiControl, (PSPI_FLASH_STSR1)&Stsr1); + ticks1 = jiffies; + ticks2 = ticks1; + BoolTimeout = ASMT_SUCCESS; + while( Stsr1.WIP == 1 ) + { + SpiFlashRDSR1(PciDevice,SpiControl, (PSPI_FLASH_STSR1)&Stsr1); + ticks2 = jiffies; + if( (((ticks2 - ticks1)*1000)/ CLOCKS_PER_SEC )> WaitingTime ) + { + BoolTimeout = ASMT_TIMEOUT; + break; + } + } + + if(BoolTimeout == ASMT_TIMEOUT) + { + if(verblevel) + printk(KERN_INFO "SpiFlashWaitWriteCompleted WaitWriteCompleted: Timeout!!!\n"); + } + + + return BoolTimeout ; +} + + +// +//Procedure: SpiFlashAAIP +//Description: Auto Address Increment (AAI) Program for PCI SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// Address - Specific address +// pData - Data buffer +// Length - Programmed data length +//Output: ASMT_SUCCESS - Command completed +// ASMT_IO_ERROR - others +//Note: +// PCT: 25VF512A, 25VF010A, 25VF020B, 25VF040B, 25VF020 +// Microchip: +// Please refer to PCI SPI flash ROM datasheet +// +int SpiFlashAAIP(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, int Length) +{ + + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + BYTE *pByte; + int Outstanding; + BYTE SpiFlashCmd[4]; + int ret = ASMT_SUCCESS; + if(Length == 0L) + { + return ASMT_IO_ERROR; + } + + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + + if(pCmdTbl->AutoAddressIncProCmd == SPICMD_UNSUPPORTED) + { + return ASMT_IO_ERROR; + } + + Outstanding = Length; + pByte = (BYTE *)pData; + + //Write Enable + SpiFlashWREN(PciDevice,SpiControl); + SpiFlashWaitWriteEnabled(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME); + + + //Write command and address + SpiFlashCmd[0] = pCmdTbl->AutoAddressIncProCmd; //0xAF + SpiFlashCmd[1] = (BYTE)(Address >> 16); //bit 23:16 + SpiFlashCmd[2] = (BYTE)(Address >> 8); //bit 15:08 + SpiFlashCmd[3] = (BYTE)Address; //bit 07:00 + + if (verblevel) { + printk(KERN_INFO "SpiFlashAAIP: SPI command code = 0x%02X, Address = 0x%04X, Length = %d\n", SpiFlashCmd[0], Address, Length); + } + + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 4); //Write 4 bytes command and address + SpiWrite(PciDevice, pByte, 1); //Write 1 byte data + SpiTerminate(PciDevice); + + //Wait WIP reset + ret = SpiFlashWaitWriteCompleted(PciDevice, SpiControl, SpiControl->SpiIndex.MaxCETime); + + Outstanding--; + pByte++; + + //Write other data + while(Outstanding > 0) + { + SpiFlashCmd[0] = pCmdTbl->AutoAddressIncProCmd; //0xAF + SpiFlashCmd[1] = *pByte; + SpiStart(PciDevice); + SpiWrite(PciDevice, SpiFlashCmd, 2); //Write command and 1 byte data + SpiTerminate(PciDevice); + SpiFlashWaitWriteCompleted(PciDevice, SpiControl, SpiControl->SpiIndex.MaxCETime); + Outstanding--; + pByte++; + } + + //Write Disable + SpiFlashWRDI(PciDevice, SpiControl); + return (SpiFlashWaitWriteCompleted(PciDevice, SpiControl, SpiControl->SpiIndex.MaxCETime)); + + // return ASMT_SUCCESS; +} + + +// +// Exported Functions +// + +// +//Procedure: SpiFlashDetectSpiFlashRom +//Description: Detect SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - SPI flash ROM found and SPI_FLASH_EXTENSION structure is returned +// ASMT_IO_ERROR - SPI flash ROM is not found +//Note: +// SPI control Grant shall be gotten by caller +// +int SpiFlashDetectSpiFlashRom(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl) +{ + + PSPI_FLASH_INDEX pSpiIdxDst; + PSPI_FLASH_INDEX pSpiIdxSrc; + BYTE *FlashID; + int BoolFound; + int i; + + + + pSpiIdxDst = (PSPI_FLASH_INDEX)&SpiControl->SpiIndex; + FlashID = pSpiIdxDst->FlashID; + //SPI JEDEC RDID + SpiFlashJedecRDID(PciDevice, FlashID); + if( ( (FlashID[0] == 0xFF) && (FlashID[1] == 0xFF) && (FlashID[2] == 0xFF) ) || + ( (FlashID[0] == 0x00) && (FlashID[1] == 0x00) && (FlashID[2] == 0x00) ) ) + { + //SPI RDID + SpiFlashRDID(PciDevice, FlashID); + } + if( ( (FlashID[0] == 0xFF) && (FlashID[1] == 0xFF) && (FlashID[2] == 0xFF) ) || + ( (FlashID[0] == 0x00) && (FlashID[1] == 0x00) && (FlashID[2] == 0x00) ) ) + { + + if(verblevel){ + printk(KERN_INFO "\nSpiFlashDetectSpiFlashRom: SPI flash ROM can't be detected!!!\n"); + } + + return ASMT_IO_ERROR; //SPI flash ROM is not detected + } + + //SPI flash ROM found + //Search supported SPI flash table + BoolFound = ASMT_UNMATCH; + i = 0; + while( (i < NUMBER_OF_SPI_FLASH_INDEXS) && (BoolFound == ASMT_UNMATCH) ) + { + pSpiIdxSrc = (PSPI_FLASH_INDEX)&SUPPORTED_SPI_FLASH_INDEX_TABLE[i]; + if( (FlashID[0] == pSpiIdxSrc->FlashID[0]) && (FlashID[1] == pSpiIdxSrc->FlashID[1]) && (FlashID[2] == pSpiIdxSrc->FlashID[2]) ) + { + BoolFound = ASMT_SUCCESS; + + if ( verblevel ) + printk(KERN_INFO "SPI ID[%X %X %X]CmdTableIndex[%X]\n",pSpiIdxSrc->FlashID[0],pSpiIdxSrc->FlashID[1],pSpiIdxSrc->FlashID[2],pSpiIdxSrc->CmdTableIndex); + } + i++; + } + + if(BoolFound == ASMT_SUCCESS) + { + //Found in supported index table + //pSpiIdxSrc points to the found SPI_FLASH_INDEX structure + memcpy(pSpiIdxDst, pSpiIdxSrc, sizeof(SPI_FLASH_INDEX)); + SpiControl->InSupportedList = ASMT_SUCCESS; + } + else + { + //Found a SPI flash ROM that is not in supported index table + pSpiIdxDst->CmdTableIndex = SPI_INDEX_DEFAULT_COMMAND_TABLE; + pSpiIdxDst->Capacity = SPI_INDEX_UNKNOWN_CAPACITY; + pSpiIdxDst->WriteSTSRBytes = SPI_INDEX_DEFAULT_WRSR_BYTE; + pSpiIdxDst->EnableWriteSTSR = SPI_INDEX_EWSR_UNSUPPORTED; + pSpiIdxDst->PageLength = SPI_INDEX_DEFAULT_PAGE_LENGTH; + memcpy(pSpiIdxDst->ProductString, "Unknown", 7); + pSpiIdxDst->ProductString[7] = '\0'; + pSpiIdxDst->MaxSEPPTime = SPI_INDEX_DEFAULT_MAX_SE_PP_TIME; + pSpiIdxDst->MaxCETime = SPI_INDEX_DEFAULT_MAX_CE_TIME; + + SpiControl->InSupportedList = ASMT_IO_ERROR; + } + + SpiControl->Spi3WMEnabled = SpiIs3WireMode(PciDevice); + + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashReadData +//Description: Read data from SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// pData - data buffer +// Address - SPI flash start address +// Length - read length +//Output: ASMT_SUCCESS - data read +// ASMT_PARAMETER_INVALID - data is not read +//Note: +// SPI control Grant shall be gotten by caller +// +int SpiFlashReadData(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, DWORD Length) +{ + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + + if(Length == 0L) + { + return ASMT_PARAMETER_INVALID; + } + + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[SpiControl->SpiIndex.CmdTableIndex]; + if(pCmdTbl->FastReadCmd != SPICMD_UNSUPPORTED) + { + + if(verblevel) + printk(KERN_INFO "SpiFlashReadData: SPI Fast Read \n"); + + + //Fast Read + //SpiFlashFREAD(pSpiFlashExtension, pData, Address, Length); + // Read + SpiFlashREAD(PciDevice,SpiControl,pData,Address,Length); //use READ command only for116 legacy SPI control + } + else + { + + if(verblevel) { + printk(KERN_INFO "SpiFlashReadData: SPI Read\n"); + } + + //Read + SpiFlashREAD(PciDevice,SpiControl, pData, Address, Length); + } + + return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashUnprotectBlocks +//Description: Clear Block Protect bits in Status Register +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - BP bits cleared +// ASMT_TIMEOUT +// SPI control Grant shall be gotten by caller +// +int SpiFlashUnprotectBlocks(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl) +{ + PSPI_FLASH_INDEX pSpiIdx; + SPI_FLASH_STSR1 Stsr1; + SPI_FLASH_STSR2 Stsr2; + + pSpiIdx = (PSPI_FLASH_INDEX)&SpiControl->SpiIndex; + Stsr1.AsByte = 0; + Stsr2.AsByte = 0; + if(pSpiIdx->EnableWriteSTSR == SPI_INDEX_EWSR_UNSUPPORTED) + { + + if(verblevel) + printk(KERN_INFO "SpiFlashUnprotectBlocks: SPI flash does not support EWSR command.\n"); + + + SpiFlashWREN(PciDevice,SpiControl); + SpiFlashWaitWriteEnabled(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME); + switch(pSpiIdx->WriteSTSRBytes) + { + case 1: + SpiFlashWRSR1(PciDevice,SpiControl,Stsr1); + break; + case 2: + SpiFlashWRSR2(PciDevice,SpiControl,Stsr1, Stsr2); + break; + default: + SpiFlashWRSR1(PciDevice,SpiControl, Stsr1); + break; + } + return( SpiFlashWaitWriteCompleted(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME)); + } + else + { + if(verblevel) + printk(KERN_INFO "SpiFlashUnprotectBlocks: EWSR command first.\n"); + + SpiFlashEWSR(PciDevice,SpiControl); + switch(pSpiIdx->WriteSTSRBytes) + { + case 1: + SpiFlashWRSR1(PciDevice,SpiControl, Stsr1); + break; + case 2: + SpiFlashWRSR2(PciDevice,SpiControl, Stsr1, Stsr2); + break; + default: + SpiFlashWRSR1(PciDevice,SpiControl, Stsr1); + break; + } + return (SpiFlashWaitWriteCompleted(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME)); + } + + //return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashChipErase +//Description: Erase all content of SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +//Output: ASMT_SUCCESS - Erased +// ASMT_TIMEOUT - others +//Note: +// SPI control Grant shall be gotten by caller +// +int SpiFlashChipErase(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl) +{ + + SpiFlashWREN(PciDevice,SpiControl); + SpiFlashWaitWriteEnabled(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME); + SpiFlashCE(PciDevice, SpiControl); + return (SpiFlashWaitWriteCompleted(PciDevice,SpiControl, SpiControl->SpiIndex.MaxCETime)); + + //return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashSectorErase +//Description: Erase 4k bytes sector of SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// Address - SPI flash sector address +//Output: ASMT_SUCCESS - Erased +// ASMT_TIMEOUT - others +//Note: +// SPI control Grant shall be gotten by caller +// +int SpiFlashSectorErase(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, DWORD Address) +{ + + SpiFlashWREN(PciDevice,SpiControl); + SpiFlashWaitWriteEnabled(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME); + SpiFlashSE(PciDevice,SpiControl, Address); + return (SpiFlashWaitWriteCompleted(PciDevice,SpiControl, SpiControl->SpiIndex.MaxSEPPTime)); + + //return ASMT_SUCCESS; +} + + +// +//Procedure: SpiFlashWriteData +//Description: Write data into SPI flash ROM +//Input: pSpiFlashExtension - SPI flash extension +// pData - data buffer +// Address - SPI flash start address +// Length - written length +//Output: ASMT_SUCCESS - data written +// ASMT_PARAMETER_INVALID - others +//Note: +// SPI control Grant shall be gotten by caller +// +int SpiFlashWriteData(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, DWORD Length) +{ + BYTE *pByte; + int Outstanding; + DWORD ProgramAddress; + WORD ProgramLength; + WORD PageLength; + + if(Length == 0L) + { + return ASMT_PARAMETER_INVALID; + } + + pByte = (BYTE *)pData; + Outstanding = Length; + ProgramAddress = Address; + PageLength = SpiControl->SpiIndex.PageLength; + + if(verblevel) + printk(KERN_INFO "SpiFlashWriteData: SPI flash Page length = %d\n", PageLength); + + + while(Outstanding > 0) + { + if( (ProgramAddress % PageLength) == 0 ) + { + //Program address is the multiple of SPI flash ROM Page Length + //ProgramLength = (Outstanding >= PageLength) ? PageLength : Outstanding; + if(Outstanding >= PageLength) + { + ProgramLength = PageLength; + }else + { + ProgramLength = (WORD)Outstanding; + } + } + else + { + //Program address is not the multiple of Page Length + //Calculate byte count to next SPI flash ROM Page start address + ProgramLength = PageLength - (ProgramAddress % PageLength); + } + SpiFlashWREN(PciDevice,SpiControl); + SpiFlashWaitWriteEnabled(PciDevice,SpiControl, SPI_FLASH_DEFAULT_WAIT_TIME); + SpiFlashPP(PciDevice,SpiControl, pByte, ProgramAddress, ProgramLength); + SpiFlashWaitWriteCompleted(PciDevice, SpiControl, SpiControl->SpiIndex.MaxSEPPTime); + Outstanding = Outstanding - ProgramLength; + ProgramAddress = ProgramAddress + ProgramLength; + pByte = pByte + ProgramLength; + } + + return ASMT_SUCCESS; +} + + + +/* +void SpiTestTable() +{ + PSPI_FLASH_COMMAND_TABLE pCmdTbl; + PSPI_FLASH_INDEX pSpiIdx; + UINTN i; + + printk(KERN_INFO "\nNumber of flash command tables = %d\n", NUMBER_OF_SPI_COMMAND_TABLES); + printk(KERN_INFO "\nNumber of flash Index tables = %d\n", NUMBER_OF_SPI_FLASH_INDEXS); + getch(); + for(i = 0; i < NUMBER_OF_SPI_FLASH_INDEXS; i++) + { + pSpiIdx = (PSPI_FLASH_INDEX)&SUPPORTED_SPI_FLASH_INDEX_TABLE[i]; + pCmdTbl = (PSPI_FLASH_COMMAND_TABLE)&SUPPORTED_SPI_FLASH_COMMAND_TABLE[pSpiIdx->CmdTableIndex]; + printk(KERN_INFO "\n"); + printk(KERN_INFO "Index %d:\n", i); + printk(KERN_INFO "SPI falsh ID = 0x%02X, 0x%02X, 0x%02X\n", pSpiIdx->FlashID[0], pSpiIdx->FlashID[1], pSpiIdx->FlashID[2]); + printk(KERN_INFO "Use Flash command table %d\n", pSpiIdx->CmdTableIndex); + printk(KERN_INFO "Flash capacity = %dk\n", pSpiIdx->Capacity); + printk(KERN_INFO "Write Status Register command bytes = %d\n", pSpiIdx->WriteSTSRBytes); + printk(KERN_INFO "Use EWSR prior to WRSR command = %d\n", pSpiIdx->EnableWriteSTSR); + printk(KERN_INFO "Page length = %d\n", pSpiIdx->PageLength); + printk(KERN_INFO "Product string = %s\n", pSpiIdx->ProductString); + printk(KERN_INFO "Maximun SE PP time = %d ms\n", pSpiIdx->MaxSEPPTime); + printk(KERN_INFO "Maximun CE time = %d ms\n", pSpiIdx->MaxCETime); + getch(); + + printk(KERN_INFO "\n"); + printk(KERN_INFO "Command table: %d\n", pSpiIdx->CmdTableIndex); + printk(KERN_INFO "WriteEnableCmd = 0x%02X\n", pCmdTbl->WriteEnableCmd); + printk(KERN_INFO "WritDisableCmd = 0x%02X\n", pCmdTbl->WritDisableCmd); + printk(KERN_INFO "ReadSTSR1Cmd = 0x%02X\n", pCmdTbl->ReadSTSR1Cmd); + printk(KERN_INFO "ReadSTSR2Cmd = 0x%02X\n", pCmdTbl->ReadSTSR2Cmd); + printk(KERN_INFO "WriteSTSR = 0x%02X\n", pCmdTbl->WriteSTSR); + printk(KERN_INFO "EnableWriteSTSRCmd = 0x%02X\n", pCmdTbl->EnableWriteSTSRCmd); + printk(KERN_INFO "ReadCmd = 0x%02X\n", pCmdTbl->ReadCmd); + printk(KERN_INFO "FastReadCmd = 0x%02X\n", pCmdTbl->FastReadCmd); + printk(KERN_INFO "ChipEraseCmd = 0x%02X\n", pCmdTbl->ChipEraseCmd); + printk(KERN_INFO "SectorEraseCmd = 0x%02X\n", pCmdTbl->SectorEraseCmd); + printk(KERN_INFO "PageProgramCmd = 0x%02X\n", pCmdTbl->PageProgramCmd); + printk(KERN_INFO "AutoAddressIncProCmd = 0x%02X\n", pCmdTbl->AutoAddressIncProCmd); + getch(); + } +} +*/ + + diff --git a/lib/synolib/asm116xfwdl/spiflash.h b/lib/synolib/asm116xfwdl/spiflash.h new file mode 100644 index 000000000000..1fa79f742210 --- /dev/null +++ b/lib/synolib/asm116xfwdl/spiflash.h @@ -0,0 +1,194 @@ +//*************************************************************************** +//Name: spiflash.h +// +//Description: +// Declare SPI flash ROM definition +// +//Revision History: +//2013/05/30 V1.02 James Peng add SPI_INDEX_DEFAULT_PAGE_LENGTH_32 difinition for MXIC MX25L5121E, MX25L1021E SPI ROM +//2013/04/05 V1.0 Jesse Chang First revision +// +/* + * Asmedia ASM116x Firmware Update Tool + * + * Copyright (C) 2014-2016 ASMedia Technology + */ +//*************************************************************************** + +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +//#include "basetype.h" +//#include "Precomp.h" +// +// SPI Status Register +// +//The bits definition of SPI Statur Register may be different between different manufacturers +//Only the same definition bits are defined here +//Some products which support Quad SPI have 16 bits Status Register, example GD25Q512,GD25Q10... +#pragma pack(1) +//8 bits status register 1 (STSR bit 0-7) +typedef union _SPI_FLASH_STSR1 { + struct { + BYTE WIP : 1; //bit[0]: Write In Progress + BYTE WEL : 1; //bit[1]: Write Enable Latch + BYTE BP0 : 1; //bit[2]: Block Protect bit 0 + BYTE BP1 : 1; //bit[3]: Block Protect bit 1 + BYTE Rev : 3; //bit[6:4]: Reserved, some products are BP2, BP3,BP4. Shall set 0 to unprotected block + BYTE SRWD : 1; //bit[7]: Status Register Write Protect (Status Register Protect bit 0 SRP1) + }; + BYTE AsByte; +} SPI_FLASH_STSR1, *PSPI_FLASH_STSR1; + +//8 bits status register 2 (STSR bit 8-15) +typedef union _SPI_FLASH_STSR2 { + struct { + BYTE SRP1 : 1; //bit[8]: Status Register Protect bit 1 + BYTE QE : 1; //bit[9]: Quad Enable + BYTE Rev : 4; //bit[13:10]: Reserved, some products are other protected bits. Shall set 0 to unprotected + BYTE CMP : 1; //bit[14]: Complement Protect + BYTE SUS : 1; //bit[15]: Suspend Status + }; + BYTE AsByte; +} SPI_FLASH_STSR2, *PSPI_FLASH_STSR2; +#pragma pack() + + +// +//ASM116 legacy SPI control interface does not support SPI dual I/O and clock frequency can't be setting +//Dual I/O commands and clock frequency seeting don't need to set in command table +// + +// +//SPI flash ROM index +// +#pragma pack(1) +typedef struct _SPI_FLASH_INDEX { + BYTE FlashID[3]; //3 bytes spi flash rom product id + BYTE CmdTableIndex; //Index of SPI falsh command table + WORD Capacity; //Capacity K Bytes + //Characters of different SPI flash ROM + BYTE WriteSTSRBytes; //1 or 2 bytes when Write Status Register + BYTE EnableWriteSTSR; //1: Enable Write Status Register command prior to Write Status Register command + WORD PageLength; //length of program page command + char ProductString[14]; //Product string + WORD MaxSEPPTime; //Maximum waiting Sector Erase or Page Program time (ms) + WORD MaxCETime; //Maximum waiting Chip Erase time (ms) +} SPI_FLASH_INDEX, *PSPI_FLASH_INDEX; +#pragma pack() + +#define SPI_INDEX_DEFAULT_COMMAND_TABLE 0x00 //Table 0: default command table +#define SPI_INDEX_UNKNOWN_FLASH_ID 0xFF +#define SPI_INDEX_UNKNOWN_CAPACITY 512 //Flash ID is not in supported table, ASM116 supports to 512k bytes SPI flash ROM +#define SPI_FLASH_64KB 64 //512K bits, 64K bytes SPI flash +#define SPI_FLASH_128KB 128 //1M bits, 128K bytes SPI flash +#define SPI_FLASH_256KB 256 //2M bits, 256K bytes SPI flash +#define SPI_FLASH_512KB 512 //4M bits, 512K bytes SPI flash +#define SPI_FLASH_1MB 1024 //8M bits, 1M bytes SPI flash +#define SPI_INDEX_DEFAULT_WRSR_BYTE 0x01 //Write Status Register 1 only +#define SPI_INDEX_EWSR_UNSUPPORTED 0x00 //Don't support SPI EWSR command +#define SPI_INDEX_EWSR_SUPPORTED 0x01 //EWSR is needed prior to WRSR command +#define SPI_INDEX_DEFAULT_PAGE_LENGTH 256 //Default 256 bytes page length +#define SPI_INDEX_DEFAULT_PAGE_LENGTH_32 32 //Default 32 bytes page length +#define SPI_INDEX_UNKNOWN_STRING "Unknown" //Unknown +#define SPI_INDEX_DEFAULT_MAX_SE_PP_TIME 1000 //1000 ms +#define SPI_INDEX_DEFAULT_MAX_CE_TIME 20000 //20 s + +#define SPI_FLASH_DEFAULT_WAIT_TIME 1000 //1000 ms + + +// +// SPI flash ROM command table +// +#pragma pack(1) +typedef struct _SPI_FLASH_COMMAND_TABLE { + BYTE WriteEnableCmd; //Write Enable command code + BYTE WritDisableCmd; //Write Disable command code + BYTE ReadSTSR1Cmd; //Read Status Register 1 command code + BYTE ReadSTSR2Cmd; //Read Status Register 2 command code + BYTE WriteSTSR; //Write Status Register command code + BYTE EnableWriteSTSRCmd; //Enable Write Status Register command code + BYTE ReadCmd; //Read command code + BYTE FastReadCmd; //Fast Read command code + BYTE ChipEraseCmd; //Chip Erase command code + BYTE SectorEraseCmd; //Sector Erase 4k bytes command code + BYTE PageProgramCmd; //Page Program command code + BYTE AutoAddressIncProCmd; //Auto Address Increment Program command code for PCT SPI flash ROM only +} SPI_FLASH_COMMAND_TABLE, *PSPI_FLASH_COMMAND_TABLE; +#pragma pack() + +// +// SPI flash ROM commands +// +#define SPICMD_UNSUPPORTED 0x00 //Unsupported command code +#define SPICMD_JEDEC_RDID 0x9F //JEDEC Read Device Identification +#define SPICMD_RDID 0xAB //Read Device Identification +#define SPICMD_WREN 0x06 //Write Enable +#define SPICMD_WRDI 0x04 //Write Disable +#define SPICMD_RDSR1 0x05 //Read Status Register 1 +#define SPICMD_RDSR2 0x35 //Read Status Register 2 +#define SPICMD_EWSR 0x50 //Enable Write Read Status Register +#define SPICMD_WRSR 0x01 //Write Status Register +#define SPICMD_READ 0x03 //Read data +#define SPICMD_FREAD 0x0B //Fast Read data +#define SPICMD_CEC7 0xC7 //Chip Erase +#define SPICMD_CE60 0x60 //Chip Erase +#define SPICMD_SE20 0x20 //Sector Erase 4k bytes +#define SPICMD_SED7 0xD7 //Sector Erase 4k bytes +#define SPICMD_PP 0x02 //Page Program +#define SPICMD_AAIP 0xAF //Auto Address Increment Program (PCT only) +//Other SPI commands that don't not used +#define SPICMD_BE52 0x52 //Block Erase 32/64k bytes +#define SPICMD_BED8 0xD8 //Block Erase 64k bytes +#define SPICMD_DP 0xB9 //Deep Power Down +#define SPICMD_RDP 0xAB //Release from Deep Power Down +#define SPICMD_RDO 0x3B //Read Data Dual Out +#define SPICMD_RDIO 0xBB //Read Data Dual In/Out +#define SPICMD_RQO 0x6B //Read Data Quad Out +#define SPICMD_RQIO 0xEB //Read Data Quad In/Out + + +// +// SPI flash ROM Extension +// + +typedef struct _SPI_FLASH_EXTENSION { + // PSPI_CONTROL_EXTENSION pSpiControlExtension; + PLSPI_REGISTERS SpiAbar; //Move to here + SPI_FLASH_INDEX SpiIndex; + int Spi3WMEnabled; + int InSupportedList; +} SPI_FLASH_EXTENSION, *PSPI_FLASH_EXTENSION; + + +int SpiFlashJedecRDID(struct pci_dev *PciDevice, BYTE *FlashID); +int SpiFlashRDID(struct pci_dev *PciDevice, BYTE *FlashID); +int SpiFlashWREN(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashWRDI(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashRDSR1(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, PSPI_FLASH_STSR1 pStsr1); +int SpiFlashRDSR2(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, PSPI_FLASH_STSR2 pStsr2); +int SpiFlashEWSR(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashWRSR1(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, SPI_FLASH_STSR1 Stsr1); +int SpiFlashWRSR2(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, SPI_FLASH_STSR1 Stsr1, SPI_FLASH_STSR2 Stsr2); +int SpiFlashCE(struct pci_dev *PciDevice ,PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashSE(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, DWORD Address); +int SpiFlashPP(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, WORD Length); +int SpiFlashREAD(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, int Length); +int SpiFlashFREAD(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, int Length); +int SpiFlashWaitWriteEnabled(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl, WORD WaitingTime); +int SpiFlashWaitWriteCompleted(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, WORD WaitingTime); +int SpiFlashAAIP(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, int Length); + + +// +// Exported Functions Prototype +// +int SpiFlashDetectSpiFlashRom(struct pci_dev *PciDevice, PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashReadData(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, DWORD Length); +int SpiFlashUnprotectBlocks(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashChipErase(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl); +int SpiFlashSectorErase(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, DWORD Address); +int SpiFlashWriteData(struct pci_dev *PciDevice,PSPI_FLASH_EXTENSION SpiControl, void *pData, DWORD Address, DWORD Length); + +#endif //_SPI_FLASH_H_ + diff --git a/lib/synolib/syno_ahci_reg_read_test.c b/lib/synolib/syno_ahci_reg_read_test.c new file mode 100644 index 000000000000..e285a05463bd --- /dev/null +++ b/lib/synolib/syno_ahci_reg_read_test.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +struct _ahci_port_st { + struct pci_dev *pDev; + int iPortIdx; +}; + +static struct kobject *synoAhciRegTestKobject; +struct _ahci_port_st ahciPorts[256]; +int iTotalSlot = 0; + +static void find_ahci_slots(void) +{ + struct pci_dev *pDev = NULL; + void __iomem *bar5 = NULL; + u32 cap = 0; + int i = 0; + int iTmpIdx = 0; + int iSlots = 0; + + memset(ahciPorts, 0, sizeof(ahciPorts)); + + for_each_pci_dev (pDev) { + if (0 == strcmp(dev_driver_string(&pDev->dev), "ahci")) { + bar5 = ioremap(pci_resource_start(pDev, 5), pci_resource_len(pDev, 5)); + if (NULL == bar5) { + continue; + } + cap = readl(bar5); + iSlots = (cap & 0x1f) + 1; + iTmpIdx = iTotalSlot; + for (i = 0; i < iSlots; i++) { + ahciPorts[iTotalSlot].pDev = pDev; + ahciPorts[iTotalSlot].iPortIdx = i; + iTotalSlot++; + } + dev_info(&pDev->dev, "With %d ports: %d - %d\n", iSlots, iTmpIdx, iTmpIdx + iSlots - 1); + } + } +} + +static void show_ahci_slots(void) +{ + int i = 0; + struct pci_dev *pDev = NULL; + + for (i = 0; i < iTotalSlot; i++) { + pDev = ahciPorts[i].pDev; + if (pDev) { + dev_info(&pDev->dev, "controller slot[%d] index=%d\n", ahciPorts[i].iPortIdx, i); + } + } +} + +static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int iVal = 0; + int i = 0; + int iPortIdx = 0; + unsigned long ulStart = 0; + unsigned long ulDuration = 0; + struct pci_dev *pDev = NULL; + void __iomem *bar5 = NULL; + void __iomem *mmio = 0; + u32 status = 0; + + sscanf(buf, "%d", &iVal); + if (0 > iVal || iTotalSlot <= iVal) { + goto END; + } + + pDev = ahciPorts[iVal].pDev; + iPortIdx = ahciPorts[iVal].iPortIdx; + + if (NULL == pDev) { + goto END; + } + + bar5 = ioremap(pci_resource_start(pDev, 5), pci_resource_len(pDev, 5)); + if (NULL == bar5) { + goto END; + } + // read PxIS + mmio = bar5 + 0x100 + 0x80 * iPortIdx + 0x10; + + ulStart = jiffies; + for (i = 0; i < 1000000; i++) { + status = readl(mmio); + } + ulDuration = jiffies - ulStart; + dev_info(&pDev->dev, "read slot[%d] PxIS * 1000000, ulDuration: %lu ms\n", iPortIdx, ulDuration*1000/HZ); + +END: + return count; +} + +static ssize_t run_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + show_ahci_slots(); + return sprintf(buf, "Check dmesg\n"); +} + +static struct kobj_attribute run_attribute =__ATTR(run, 0600, run_show, run_store); + + +static int syno_achi_reg_read_test_init(void) +{ + int iRet = 0; + synoAhciRegTestKobject = kobject_create_and_add("syno_ahci_reg_read_test", kernel_kobj); + if (NULL == synoAhciRegTestKobject) { + iRet = -ENOMEM; + goto END; + } + + if (0 != sysfs_create_file(synoAhciRegTestKobject, &run_attribute.attr)) { + pr_debug("failed to create the run file in /sys/kernel/syno_ahci_reg_read_test \n"); + iRet = -ENOMEM; + goto END; + } + find_ahci_slots(); + +END: + return iRet; +} + +static void syno_achi_reg_read_test_exit(void) +{ + kobject_put(synoAhciRegTestKobject); + + printk(KERN_INFO "unloading syno ahci reg test\n"); + return; +} + +module_init(syno_achi_reg_read_test_init); +module_exit(syno_achi_reg_read_test_exit); diff --git a/lib/synolib/syno_check_on_opt_pci.c b/lib/synolib/syno_check_on_opt_pci.c new file mode 100644 index 000000000000..0bb4e487b4be --- /dev/null +++ b/lib/synolib/syno_check_on_opt_pci.c @@ -0,0 +1,43 @@ +#include +#include + +/* + * Return if the pci_dev on optional PCIe slot. + * + * @param pdev [IN] PCI device strct + * + * Return 1: pci_dev match + * 0: pci_dev mismatch + * -1: something error + */ +int syno_check_on_option_pci_slot(struct pci_dev *pdev) +{ + int i = 0; + int iRet = -1; + char szPciAddress[PCI_ADDR_LEN_MAX + 1]; + struct pci_dev *pdev_cur = NULL; + + if (NULL == pdev) { + printk("Bad parameter!\n"); + goto END; + } + + pdev_cur = pdev; + + while (NULL != pdev_cur) { + snprintf(szPciAddress, sizeof(szPciAddress),"%04x%02x%02x%x", + pci_domain_nr(pdev_cur->bus), pdev_cur->bus->number, + PCI_SLOT(pdev_cur->devfn), PCI_FUNC(pdev_cur->devfn)); + + for (i = 0; i < gPciAddrNum; i++) { + if (0 == strncmp(szPciAddress, gszPciAddrList[i], PCI_ADDR_LEN_MAX)) { + iRet = 1; + goto END; + } + } + pdev_cur = pdev_cur->bus->self; + } + iRet = 0; +END: + return iRet; +} diff --git a/lib/synolib/syno_disk_pwr_ctrl.c b/lib/synolib/syno_disk_pwr_ctrl.c new file mode 100644 index 000000000000..65a89bf34de9 --- /dev/null +++ b/lib/synolib/syno_disk_pwr_ctrl.c @@ -0,0 +1,296 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include + +#ifdef MY_DEF_HERE +#include +#endif /* MY_DEF_HERE */ + +#ifdef MY_DEF_HERE +static int syno_hdd_poweron_gpio(int index, int value) +{ + if (!HAVE_HDD_ENABLE(index)) { // index is 1-based + printk("No such hdd enable pin. Index: %d\n", index); + WARN_ON(1); + return -EINVAL; + } + SYNO_GPIO_WRITE(HDD_ENABLE_PIN(index), value); + return 0; +} + +static int syno_hdd_enable_gpio(int index) +{ + int ret = 0; /* default is not enable */ + + if (!HAVE_HDD_ENABLE(index)) { // index is 1-based + goto END; + } + ret = SYNO_GPIO_READ(HDD_ENABLE_PIN(index)); + /* hdd enable pin is low active so the result must be inverted*/ + if (ACTIVE_LOW == HDD_ENABLE_POLARITY(index)) { + ret = !ret; + } +END: + return ret; +} + +static int syno_hdd_detect_gpio(int index) +{ + int ret = 1; /* default is present */ + + if (!HAVE_HDD_DETECT(index)) { // index is 1-based + goto END; + } + ret = SYNO_GPIO_READ(HDD_DETECT_PIN(index)); + /* hdd detect pin is low active so the result must be inverted*/ + if (ACTIVE_LOW == HDD_DETECT_POLARITY(index)) { + ret = !ret; + } +END: + return ret; +} +#endif /* MY_DEF_HERE */ + +#ifdef MY_ABC_HERE +extern long g_smbus_hdd_powerctl; +extern int gSynoSmbusHddAdapter; +extern int gSynoSmbusHddAddress; +extern void syno_smbus_hdd_powerctl_init(void); +extern SYNO_SMBUS_HDD_POWERCTL SynoSmbusHddPowerCtl; + +static int syno_hdd_poweron_smbus(int index, int value) +{ + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write) { + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index, value); + } + + return 0; +} + +static int syno_hdd_enable_smbus(int index) +{ + int ret = 0; /*defult is not enable*/ + + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + if ( NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read) { + ret = SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index); + } + + return ret; +} + +static int syno_hdd_detect_smbus(int index) +{ + int ret = 0; /*defult is not present*/ + + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + if ( NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read) { + ret = SynoSmbusHddPowerCtl.syno_smbus_hdd_present_read(gSynoSmbusHddAdapter, gSynoSmbusHddAddress, index); + } + + return ret; +} + +static int syno_hdd_poweron_smbus_all_once(void) +{ + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + + if (NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write_all_once) { + SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write_all_once(gSynoSmbusHddAdapter, gSynoSmbusHddAddress); + } + + return 0; +} +#endif /* MY_ABC_HERE */ + +DISK_PWRCTRL_TYPE SYNO_GET_DISK_PWR_TYPE(int index) +{ +#ifdef MY_DEF_HERE + /* Check GPIO */ + if (HAVE_HDD_ENABLE(index)) { + return PWRCTRL_TYPE_GPIO; + } +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + /* Check SMBUS */ + if (0 < g_smbus_hdd_powerctl) { + return PWRCTRL_TYPE_SMBUS; + } +#endif /* MY_ABC_HERE */ + + return PWRCTRL_TYPE_UNKNOWN; +} +EXPORT_SYMBOL(SYNO_GET_DISK_PWR_TYPE); + +/* SYNO_CTRL_HDD_POWERON - Power control of internal disk + * @index: disk index + * @value: 1 poweron + * 0 poweroff + * @return: 0 success + * 1 failed + */ +int SYNO_CTRL_HDD_POWERON(int index, int value) +{ + int ret = 0; + + switch (SYNO_GET_DISK_PWR_TYPE(index)) { +#ifdef MY_DEF_HERE + case PWRCTRL_TYPE_GPIO: + ret = syno_hdd_poweron_gpio(index, value); + break; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + case PWRCTRL_TYPE_SMBUS: + ret = syno_hdd_poweron_smbus(index, value); + break; +#endif /* MY_ABC_HERE */ + default: + ret = 0; + } + return ret; +} +EXPORT_SYMBOL(SYNO_CTRL_HDD_POWERON); + +/* SYNO_CHECK_HDD_ENABLE + * Query HDD enable check . + * output: 1 - enable, 0 - not enable. + */ +int SYNO_CHECK_HDD_ENABLE(int index) +{ + int ret = 0; + + switch (SYNO_GET_DISK_PWR_TYPE(index)) { +#ifdef MY_DEF_HERE + case PWRCTRL_TYPE_GPIO: + ret = syno_hdd_enable_gpio(index); + break; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + case PWRCTRL_TYPE_SMBUS: + ret = syno_hdd_enable_smbus(index); + break; +#endif /* MY_ABC_HERE */ + default: + ret = 0; + } + return ret; +} +EXPORT_SYMBOL(SYNO_CHECK_HDD_ENABLE); + +/* SYNO_CHECK_HDD_DETECT + * Query HDD present check . + * output: 1 - present, 0 - not present. + */ +int SYNO_CHECK_HDD_DETECT(int index) +{ + int ret = 0; + + switch (SYNO_GET_DISK_PWR_TYPE(index)) { +#ifdef MY_DEF_HERE + case PWRCTRL_TYPE_GPIO: + ret = syno_hdd_detect_gpio(index); + break; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + case PWRCTRL_TYPE_SMBUS: + ret = syno_hdd_detect_smbus(index); + break; +#endif /* MY_ABC_HERE */ + default: + ret = 0; + } + return ret; +} +EXPORT_SYMBOL(SYNO_CHECK_HDD_DETECT); + +/* SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER + * Query support HDD dynamic Power . + * output: 1 - support, 0 - not support. + */ +int SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(int index) +{ + int ret = 0; + + switch (SYNO_GET_DISK_PWR_TYPE(index)) + { +#ifdef MY_DEF_HERE + case PWRCTRL_TYPE_GPIO: + ret = 1; + break; +#endif /* #ifdef MY_DEF_HERE */ +#ifdef MY_ABC_HERE + case PWRCTRL_TYPE_SMBUS: + if (!SynoSmbusHddPowerCtl.bl_init){ + syno_smbus_hdd_powerctl_init(); + } + if(NULL != SynoSmbusHddPowerCtl.syno_smbus_hdd_enable_write) { + ret = 1; + } + break; +#endif /* MY_ABC_HERE */ + default: + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER); + +/* SYNO_HDD_POWER_ON - Power control for internal disk + * @index: disk slot index + * + * Special case for 1621+: + * Need to poweron all disks at the same time. + */ +void SYNO_HDD_POWER_ON(int index) +{ + switch (SYNO_GET_DISK_PWR_TYPE(index)) { +#ifdef MY_DEF_HERE + case PWRCTRL_TYPE_GPIO: + /* Power on the disk if it has presented. */ + if (1 == SYNO_CHECK_HDD_DETECT(index)) { +#ifdef MY_DEF_HERE + DBG_SpinupGroup("Power on disk: %d\n", index); +#endif /* MY_DEF_HERE */ + SYNO_CTRL_HDD_POWERON(index, 1); + } + break; +#endif /* MY_DEF_HERE */ +#ifdef MY_ABC_HERE + case PWRCTRL_TYPE_SMBUS: +#ifdef MY_ABC_HERE + /* Special case: DS1621+ */ + if (syno_is_hw_version(HW_DS1621p) || syno_is_hw_version(HW_DS1623p)) { + syno_hdd_poweron_smbus_all_once(); + break; + } +#endif /* MY_ABC_HERE */ +#ifdef MY_DEF_HERE + DBG_SpinupGroup("Power on disk: %d\n", index); +#endif /* MY_DEF_HERE */ + SYNO_CTRL_HDD_POWERON(index, 1); + break; +#endif /* MY_ABC_HERE */ + default: + break; + } + + return; +} + +EXPORT_SYMBOL(SYNO_HDD_POWER_ON); diff --git a/lib/synolib/syno_disk_ready_check.c b/lib/synolib/syno_disk_ready_check.c new file mode 100644 index 000000000000..84537a0581e0 --- /dev/null +++ b/lib/synolib/syno_disk_ready_check.c @@ -0,0 +1,39 @@ +#include +#include +#include + +atomic_t syno_disk_not_ready_count = ATOMIC_INIT(0); + +void syno_disk_not_ready_count_increase(void) +{ + atomic_inc(&syno_disk_not_ready_count); +} +EXPORT_SYMBOL(syno_disk_not_ready_count_increase); + +void syno_disk_not_ready_count_decrease(void) +{ + /* + * the counter shouldn't be decreased to a negative number, so we have to + * warn about someone calling this function while counter is zero and stop + * decreaseing. + * + */ + WARN_ON_ONCE(!atomic_add_unless(&syno_disk_not_ready_count, -1, 0)); +} +EXPORT_SYMBOL(syno_disk_not_ready_count_decrease); + +/* + * Return 0 if any of disks aren't ready and timeout isn't over. + * Otherwise return 1. + */ +int syno_scsi_disk_ready_check(void) +{ + int ret = 0; + + if (0 == atomic_read(&syno_disk_not_ready_count)) { + ret = 1; + } + + return ret; +} + diff --git a/lib/synolib/syno_disk_wait_for_spindown.c b/lib/synolib/syno_disk_wait_for_spindown.c new file mode 100644 index 000000000000..e598da66b53e --- /dev/null +++ b/lib/synolib/syno_disk_wait_for_spindown.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +atomic_t syno_disk_paraldown_wait_cnt = ATOMIC_INIT(0); + +void syno_disk_paraldown_wait_inc(void) +{ + atomic_inc(&syno_disk_paraldown_wait_cnt); +} +EXPORT_SYMBOL(syno_disk_paraldown_wait_inc); + +void syno_disk_paraldown_wait_dec(void) +{ + /* + * the counter shouldn't be decd to a negative number, so we have to + * warn about someone calling this function while counter is zero and stop + * decing. + * + */ + WARN_ON_ONCE(!atomic_add_unless(&syno_disk_paraldown_wait_cnt, -1, 0)); +} +EXPORT_SYMBOL(syno_disk_paraldown_wait_dec); + +/* + * Return 0 if any of disks aren't ready and timeout isn't over. + * Otherwise return 1. + */ +int syno_disk_paraldown_ready_check(void) +{ + int ret = 0; + + if (0 == atomic_read(&syno_disk_paraldown_wait_cnt)) { + ret = 1; + } + + return ret; +} +EXPORT_SYMBOL(syno_disk_paraldown_ready_check); + +int syno_disk_paraldown_wait(struct device *dev) +{ + int ret = 0; + int timeout = 60, i; + + dev_info(dev, "wait for disk spindown...\n"); + // TODO : Counter syno_disk_paraldown_wait_cnt should be owned by + // every scsi_host themsevles instead of using global one, + // to prevent waiting wrong scsi_device's spindown + // which not belong to the scsi host. + for (i = 0; i < timeout; i++) { + if (syno_disk_paraldown_ready_check()) { + dev_info(dev, "disk spindown complete\n"); + ret = 1; + goto END; + } else { + msleep(1000); + } + } + printk(KERN_ERR "Disk parallel spindown TIMEOUT!\n"); + +END: + return ret; +} +EXPORT_SYMBOL(syno_disk_paraldown_wait); diff --git a/lib/synolib/syno_draw_auto_remap_buffer.c b/lib/synolib/syno_draw_auto_remap_buffer.c new file mode 100644 index 000000000000..7fc491cdfbfc --- /dev/null +++ b/lib/synolib/syno_draw_auto_remap_buffer.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2000-2021 Synology Inc. + */ +#include +#include +#include + +/* + * Draw buffer with UTC time following by "SYNO" pattern + * + * @param buffer [IN] page address + * @param size [IN] buffer size + * + */ +void syno_draw_auto_remap_buffer(char *buffer, int size) +{ + int i; + struct tm tm; + + for (i = 0; i <= size - 4; i += 4) { + buffer[i] = 'S'; + buffer[i + 1] = 'Y'; + buffer[i + 2] = 'N'; + buffer[i + 3] = 'O'; + } + time64_to_tm(get_seconds(), 0, &tm); + snprintf(buffer, size, "UTC%04ld-%02d-%02dT%02d:%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +} diff --git a/lib/synolib/syno_fdt.c b/lib/synolib/syno_fdt.c new file mode 100644 index 000000000000..40e418aa7ddc --- /dev/null +++ b/lib/synolib/syno_fdt.c @@ -0,0 +1,242 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include +#include + +extern int syno_compare_dts_pciepath(const struct pci_dev *pdev, const struct device_node *pDeviceNode); + +#ifdef MY_ABC_HERE +int syno_pmbus_property_get(unsigned int *pmbus_property, const char *property_name, int index) +{ + int iRet = -1; + if (NULL == pmbus_property || NULL == property_name) { + goto END; + } + + // if property name not exist, do nothing but return 0 + if (of_find_property(of_root, property_name, NULL)) { + of_property_read_u32_index(of_root, property_name, index, pmbus_property); + } + + iRet = 0; +END: + return iRet; +} +EXPORT_SYMBOL(syno_pmbus_property_get); +#endif /* MY_ABC_HERE */ + +struct device_node* syno_of_i2c_bus_match(struct device *dev, int* index) +{ + struct device_node *pI2CNode = NULL; + struct pci_dev *pdev = NULL; +#ifdef CONFIG_ACPI + char *i2c_hid = NULL; + char *i2c_uid = NULL; + struct acpi_device *acpi_dev = NULL; +#endif + + if(NULL == of_root || NULL == dev) { + goto END; + } + + for_each_child_of_node(of_root, pI2CNode) { + if (pI2CNode->full_name && 1 == sscanf(pI2CNode->full_name, DT_I2C_BUS"@%d", index)) { + if (dev_is_pci(dev->parent)) { + pdev = to_pci_dev(dev->parent); + if (0 == syno_compare_dts_pciepath(pdev, pI2CNode)) { + return pI2CNode; + } +#ifdef CONFIG_ACPI + } else if (is_acpi_device_node(dev->parent->fwnode)) { + acpi_dev = ACPI_COMPANION(dev->parent); + i2c_hid = (char *)of_get_property(pI2CNode, DT_ACPI_HID, NULL); + i2c_uid = (char *)of_get_property(pI2CNode, DT_ACPI_UID, NULL); + + if (!i2c_hid || !i2c_uid) { + continue; + } + + if ( 0 == strncmp(i2c_hid, acpi_device_hid(acpi_dev), SYNO_DTS_PROPERTY_CONTENT_LENGTH) && + 0 == strncmp(i2c_uid, acpi_dev->pnp.unique_id, SYNO_DTS_PROPERTY_CONTENT_LENGTH)) { + return pI2CNode; + } +#endif + } + } + } +END: + return NULL; +} +EXPORT_SYMBOL_GPL(syno_of_i2c_bus_match); + +struct device_node* syno_of_i2c_device_match(struct i2c_client *client, const char *i2c_dev_name, struct device_node *pI2CNode) +{ + struct device_node *pI2CDevNode = NULL; + char *device_name = NULL; + char *device_address = NULL; + unsigned short addr = 0; + + if (NULL == client || NULL == i2c_dev_name || NULL == pI2CNode) { + goto END; + } + + for_each_child_of_node(pI2CNode, pI2CDevNode) { + device_name = (char *)of_get_property(pI2CDevNode, DT_I2C_DEVICE_NAME, NULL); + device_address = (char *)of_get_property(pI2CDevNode, DT_I2C_ADDRESS, NULL); + if (NULL != device_address && 0 == kstrtou16(device_address, 16, &addr)) { + if ( 0 == strncmp(i2c_dev_name, device_name, SYNO_DTS_PROPERTY_CONTENT_LENGTH) + && client->addr == addr) { + return pI2CDevNode; + } + } + } + +END: + return NULL; +} +EXPORT_SYMBOL_GPL(syno_of_i2c_device_match); + +struct device_node* syno_of_i2c_adapter_match(struct i2c_adapter *adap) +{ + struct device_node *pI2CNode = NULL; + struct device_node *pRet = NULL; + char szName[32] = {'\0'}; + int id; + + if (!adap || !of_root) { + goto END; + } + + id = i2c_adapter_id(adap); + snprintf(szName, sizeof(szName), DT_I2C_BUS"@%d", id); + + for_each_child_of_node(of_root, pI2CNode) { + if (!pI2CNode->full_name) { + continue; + } + if (0 == strncmp(pI2CNode->full_name, szName, strlen(szName))) { + pRet = pI2CNode; + goto END; + } + } +END: + return pRet; +} +EXPORT_SYMBOL_GPL(syno_of_i2c_adapter_match); + +bool syno_of_i2c_driver_match_device(struct device *dev, const struct device_driver *drv) +{ + struct i2c_client *client = NULL; + struct i2c_driver *driver = NULL; + struct device_node *pNode = NULL; + struct device_node *pDevNode = NULL; + bool iRet = false; + + if(NULL == dev || NULL == drv) { + goto END; + } + + client = i2c_verify_client(dev); + driver = to_i2c_driver(drv); + + if (NULL == client || NULL == driver) { + goto END; + } + + if (NULL != (pNode = syno_of_i2c_adapter_match(client->adapter)) && + NULL != (pDevNode = syno_of_i2c_device_match(client, driver->driver.name, pNode))) { + iRet = true; + } + +END: + return iRet; +} +EXPORT_SYMBOL_GPL(syno_of_i2c_driver_match_device); + +struct i2c_adapter* syno_i2c_adapter_get_by_node(struct device_node *pI2CBusNode) +{ + struct i2c_adapter* adapter = NULL; + int iBusIdx = 0; + + if (1 != sscanf(pI2CBusNode->full_name, DT_I2C_BUS"@%d", &iBusIdx)) { + printk("synobios: cannot parse i2c bus index\n"); + goto END; + } + + adapter = i2c_get_adapter(iBusIdx); + +END: + return adapter; +} +EXPORT_SYMBOL(syno_i2c_adapter_get_by_node); + +int syno_pmp_get_ebox_node_by_unique_id(u8 synoUniqueID, u8 isRP, struct device_node **pEBoxNode) +{ + int iRet = -1; + int i = 0; + char szUnique[SYNO_EBOX_UNIQUE_MAX_LEN] = {0}; + + for (i=0; syno_ebox_unique_mapping[i].uniqueId != 0; i++) { + if (syno_ebox_unique_mapping[i].uniqueId == (synoUniqueID & syno_ebox_unique_mapping[i].mask)){ + + if (isRP) { + snprintf(szUnique, SYNO_EBOX_UNIQUE_MAX_LEN, "%s", syno_ebox_unique_mapping[i].szUnique); + } else { + snprintf(szUnique, SYNO_EBOX_UNIQUE_MAX_LEN, "%s", syno_ebox_unique_mapping[i].szUniqueRp); + } + + if (NULL == ((*pEBoxNode) = of_get_child_by_name(of_root, szUnique))) { + printk("Get node %s failed\n", szUnique); + goto END; + } + + iRet = 0; + break; + } + } + +END: + return iRet; +} +EXPORT_SYMBOL(syno_pmp_get_ebox_node_by_unique_id); + +int syno_pmp_i2c_addr_get(struct device_node *pNode, unsigned int *addr) +{ + int iRet = -1; + phandle ph; + struct device_node *pI2cNode = NULL; + + if (!pNode || !addr) { + goto END; + } + + /* Get I2c Device PH */ + if(of_property_read_u32_index(pNode, DT_I2C_DEVICE, 0, &ph)) { + printk("Get I2c ph failed\n"); + goto END; + } + + /* Get I2c Device Node*/ + if (NULL == (pI2cNode = of_find_node_by_phandle(ph))) { + printk("Get I2c Node failed, ph = %u\n", ph); + goto END; + } + + /* Get I2c Addr */ + if (0 != of_property_read_u32_index(pI2cNode, DT_I2C_ADDRESS, 0 , addr)) { + printk("Read i2c_addr failed\n"); + goto END; + } + + iRet = 0; +END: + return iRet; +} + +EXPORT_SYMBOL(syno_pmp_i2c_addr_get); diff --git a/lib/synolib/syno_hddpwrctl_test.c b/lib/synolib/syno_hddpwrctl_test.c new file mode 100644 index 000000000000..bd077998b591 --- /dev/null +++ b/lib/synolib/syno_hddpwrctl_test.c @@ -0,0 +1,158 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include + +static struct kobject *SynoHddPwrCtlObject = NULL; +int iSlot = 0; + +extern int SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(int index); +extern int SYNO_CTRL_HDD_POWERON(int index, int value); +extern int SYNO_CHECK_HDD_ENABLE(int index); +extern int SYNO_CHECK_HDD_DETECT(int index); +#ifdef MY_ABC_HERE +extern int gSynoInternalHddNumber; +#endif /* MY_ABC_HERE */ + +static ssize_t pwrctl_slot_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return scnprintf (buf, PAGE_SIZE, "%d\n", iSlot); +} +static ssize_t pwrctl_slot_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + if (0 > kstrtoint(buf, 0, &iSlot)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + if (1 > iSlot || gSynoInternalHddNumber < iSlot) { + printk(KERN_WARNING "Invalid Slot Number\n"); + iSlot = 0; + goto END; + } + +END: + return count; +} + +static ssize_t pwrctl_present_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int iRet = 0; + int iPrzPinVal = 1; + + if (1 > iSlot || gSynoInternalHddNumber < iSlot) { + printk(KERN_WARNING "Invalid Slot Number\n"); + goto END; + } + + iPrzPinVal = SYNO_CHECK_HDD_DETECT(iSlot); + + iRet += scnprintf (buf, PAGE_SIZE, "Slot%d is %sPresent\n", iSlot, iPrzPinVal?"":"Not "); + +END: + return iRet; +} +static ssize_t pwrctl_present_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + printk(KERN_WARNING "Present pin is not writable\n"); + return count; +} + +static ssize_t pwrctl_enable_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int iRet = 0; + /* defult is not enable */ + int iEnPinVal = 0; + + + if (1 > iSlot || gSynoInternalHddNumber < iSlot) { + printk(KERN_WARNING "Invalid Slot Number\n"); + goto END; + } + + iEnPinVal = SYNO_CHECK_HDD_ENABLE(iSlot); + + iRet += scnprintf (buf, PAGE_SIZE, "Slot%d is %sEnable\n", iSlot, iEnPinVal?"":"Not "); +END: + return iRet; +} +static ssize_t pwrctl_enable_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + int iValue = 0; + + if (0 > kstrtoint(buf, 0, &iValue)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + + if (0 > iValue || 1 < iValue) { + printk(KERN_WARNING "Invalid Input Value\n"); + goto END; + } + + if (1 > iSlot || gSynoInternalHddNumber < iSlot) { + printk(KERN_WARNING "Invalid Slot Number\n"); + goto END; + } + + SYNO_CTRL_HDD_POWERON(iSlot, iValue); +END: + return count; +} + +// register function to attribute +static struct kobj_attribute pwrctl_slot = __ATTR( pwrctl_slot, 0640, pwrctl_slot_show, pwrctl_slot_store); +static struct kobj_attribute pwrctl_present = __ATTR( pwrctl_present, 0640, pwrctl_present_show, pwrctl_present_store); +static struct kobj_attribute pwrctl_enable = __ATTR( pwrctl_enable, 0640, pwrctl_enable_show, pwrctl_enable_store); + +// put attribute to attribute group +static struct attribute *SynoHddPwrCtlAttr[] = { + &pwrctl_slot.attr, + &pwrctl_present.attr, + &pwrctl_enable.attr, + NULL, /* NULL terminate the list*/ +}; +static struct attribute_group SynoHddPwrCtlGroup = { + .attrs = SynoHddPwrCtlAttr +}; + +static int syno_hddpwrctl_test_init(void) +{ + int iRet = -1; + SynoHddPwrCtlObject = kobject_create_and_add("syno_hddpwrctl_test", kernel_kobj); + if (!SynoHddPwrCtlObject) { + iRet = -ENOMEM; + goto END; + } + + //create attributes (files) + if(sysfs_create_group(SynoHddPwrCtlObject, &SynoHddPwrCtlGroup)){ + iRet = -ENOMEM; + goto END; + } + + if (!SYNO_SUPPORT_HDD_DYNAMIC_ENABLE_POWER(1)){ + printk(KERN_ERR "Not support HDD dynamic power control\n"); + goto END; + } + + iRet = 0; +END: + if (0 != iRet) { + if (SynoHddPwrCtlObject) { + kobject_put(SynoHddPwrCtlObject); + } + } + return iRet; +} + +static void syno_hddpwrctl_test_exit(void) +{ + kobject_put(SynoHddPwrCtlObject); +} + +MODULE_LICENSE("GPL"); +module_init(syno_hddpwrctl_test_init); +module_exit(syno_hddpwrctl_test_exit); diff --git a/lib/synolib/syno_jmb585_update_spi.c b/lib/synolib/syno_jmb585_update_spi.c new file mode 100644 index 000000000000..9dfe85cafd3a --- /dev/null +++ b/lib/synolib/syno_jmb585_update_spi.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include + +static struct kobject *jmb58xSPIObject = NULL; + +#define JMB_HEADER_SIZE 3 * 1024 +unsigned char read_buffer[JMB_HEADER_SIZE] = {0}; +unsigned char header_buffer[JMB_HEADER_SIZE] = {0}; + +unsigned int uiSelectedJMB58X = 0; + + +static int syno_jmb58x_check(struct pci_dev* pdev) +{ + return (pdev->vendor == 0x197b && (pdev->device == 0x0585 || pdev->device == 0x0582)) ? 0 : -1; +} + +u8 jmb58x_spi_wait_status_wip0(void __iomem *host_mmio, u32 timeout_ms, u8 delay_ms) +{ + unsigned long timeout; + u8 wip0_flag = 0; + + timeout = jiffies + msecs_to_jiffies(timeout_ms*1000); + + while (time_before(jiffies, timeout)) { + // check WIP bit + writel(0xFF | (0x80 << 8) | (0x08 << 16) | (0x05 << 24), host_mmio + 0xB4); + if (((u8) readl(host_mmio + 0xCC)) & 0x01) { + ndelay(5); + } else { + // wip became zero + wip0_flag = 1; + break; + } + } + + if (!wip0_flag) { + printk("\nJMB58X header update error: WIP bit of Flash Status didn't become zero\n\n"); + } + + return 1; +} + +u8 jmb58x_spi_wait_read_done(void __iomem *host_mmio, u8 *buffer, u32 buffer_size, u32 offset) +{ + u32 i; + u32 dwData = 0; + + // wait WIP bit to become zero + if(!jmb58x_spi_wait_status_wip0(host_mmio, 2*1000, 1)) { + return 0; + } + // setting for reading + writel(0xFF | (0x80 << 8) | (0xE9 << 16) | (0x03 << 24), host_mmio + 0xB4); + + for (i = offset; i < (buffer_size+offset); i += 4) { + writel(i, host_mmio + 0xC0); + dwData = readl(host_mmio + 0xCC); + buffer[i - offset] = (u8)dwData; + buffer[i - offset + 1] = (u8)(dwData >> 8); + buffer[i - offset + 2] = (u8)(dwData >> 16); + buffer[i - offset + 3] = (u8)(dwData >> 24); + } + + return 1; +} + +static ssize_t jmb58x_spi_content_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct pci_dev *pdev = NULL; + void __iomem *bar5 = NULL; + unsigned int uiCount = 0; + int iRet = 0; + + if (0 == uiSelectedJMB58X) { + printk(KERN_INFO "Please select a jmb58x to read spi header\n"); + memset(read_buffer, 0, sizeof(read_buffer)); + goto END; + } + + for_each_pci_dev(pdev) { + if (0 != syno_jmb58x_check(pdev)) { + continue; + } + uiCount++; + if (uiSelectedJMB58X != uiCount) { + continue; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb58x sata registers\n"); + return 0; + } + + memset(read_buffer, 0, sizeof(read_buffer)); + if(!jmb58x_spi_wait_read_done(bar5, read_buffer, JMB_HEADER_SIZE, 0)) { + return 0; + } + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } + memcpy(buf, read_buffer,JMB_HEADER_SIZE); + iRet = JMB_HEADER_SIZE; +END: + return iRet; +} + +static ssize_t jmb58x_spi_update_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = NULL; + u32 i = 0; + u8 cmp_fail_flag = 0; + unsigned int uiCount = 0; + void __iomem *bar5 = NULL; + + for_each_pci_dev(pdev) { + if (0 != syno_jmb58x_check(pdev)) { + continue; + } + uiCount++; + if (0 != uiSelectedJMB58X && (uiSelectedJMB58X != uiCount)) { + continue; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb sata registers\n"); + return count; + } + memcpy(header_buffer, buf, sizeof(header_buffer)); + + if((header_buffer[0] != 0x85 && header_buffer[0] != 0x82) || header_buffer[1] != 0x05 || header_buffer[2] != 0x7B || header_buffer[3] != 0x19) { + //Values not 0x197B0585 nor 0x197b0582are invalid. + dev_warn(&pdev->dev, "JMB58X header update error: Incorrect header format!"); + return count; + } + // wait WIP bit to become zero + if(!jmb58x_spi_wait_status_wip0(bar5, 2000, 1)){ + return count; + } + // write enable + writel(0xFF | (0x80 << 8) | (0x00 << 16) | (0x06 << 24), bar5 + 0xB4); + writel(0, bar5 + 0xCC); + // disable BP(Block Protect) bits, because MXIC flash's BP(Block Protect) bits are enabled + // write 0 to status register + writel(0xFF | (0x80 << 8) | (0x04 << 16) | (0x01 << 24), bar5 + 0xB4); + writel(0, bar5 + 0xCC); + + if(!jmb58x_spi_wait_status_wip0(bar5, 1000, 1)){ + return count; + } + + // write enable + writel(0xFF | (0x80 << 8) | (0x00 << 16) | (0x06 << 24), bar5 + 0xB4); + writel(0, bar5 + 0xCC); + + dev_info(&pdev->dev, "JMB58X flash update: Begin Chip Erase\n"); + // chip erase + writel(0xFF | (0x80 << 8) | (0x00 << 16) | (0xC7 << 24), bar5 + 0xB4); + writel(0, bar5 + 0xCC); + if(!jmb58x_spi_wait_status_wip0(bar5, 33000, 1)) { + //Chip erase may need a longer time to complete, wait for up to 33 seconds + return count; + } + + dev_info(&pdev->dev, "JMB58X flash update: Chip Erase Done. Begin flash update\n"); + for (i = 0; i < JMB_HEADER_SIZE; i += 4) { + if ( ! jmb58x_spi_wait_status_wip0(bar5, 1000, 1)) { + return count; + } + // write enable + writel(0xFF | (0x80 << 8) | (0x00 << 16) | (0x06 << 24), bar5 + 0xB4); + writel(0, bar5 + 0xCC); + // setting for page program + writel(0xFF | (0x80 << 8) | (0xE5 << 16) | (0x02 << 24), bar5 + 0xB4); + + writel(i, bar5 + 0xC0); + writel(header_buffer[i] | (header_buffer[i+1] << 8) | (header_buffer[i+2] << 16) | (header_buffer[i+3] << 24) , bar5 + 0xCC); + } + dev_info(&pdev->dev, "JMB58X flash update: Complete flash update.\n"); + + dev_info(&pdev->dev, "JMB58X flash update: Begin flash read\n"); + memset(read_buffer, 0, sizeof(read_buffer)); + if (!jmb58x_spi_wait_read_done(bar5, read_buffer, JMB_HEADER_SIZE, 0)) { + return count; + } + + dev_info(&pdev->dev, "JMB58X flash update: Flash read Done. Comparing data...\n"); + // compare + for (i = 0; i < JMB_HEADER_SIZE; i++) { + if (header_buffer[i] != read_buffer[i]) { + dev_warn(&pdev->dev, "\nJMB58X header update error: Comparison failed at %d, write is 0x%X but read is 0x%X!!\n", i, header_buffer[i], read_buffer[i]); + cmp_fail_flag = 1; + return count; + } + } + if (!cmp_fail_flag) { + dev_warn(&pdev->dev, "JMB58X flash update: JMB58X header update successful!\n"); + } + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } + + return count; +} + +static ssize_t jmb58x_spi_select_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct pci_dev *pdev = NULL; + int iCount = 0, iCurrent = 0; + + iCurrent = snprintf(buf, PAGE_SIZE, "Current selected jmb58x : %u\n", uiSelectedJMB58X); + iCurrent += snprintf(buf + iCurrent, PAGE_SIZE - iCurrent, "0. All jmb58x is selected (default).\n"); + for_each_pci_dev(pdev) { + if (0 != syno_jmb58x_check(pdev)) { + continue; + } + iCurrent += snprintf(buf + iCurrent, PAGE_SIZE - iCurrent, "%u. %04x:%04x pcie bus %02x:%02x.%x\n", + ++iCount, pdev->vendor, pdev->device, pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + } + return iCurrent; +} + +static ssize_t jmb58x_spi_select_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = NULL; + u32 iCount=0; + int iRet = -1; + + iRet = kstrtouint(buf, 10, &uiSelectedJMB58X); + if (0 > iRet) { + goto END; + } + + if (0 == uiSelectedJMB58X) { + printk(KERN_INFO "No.0 All jmb58x are selected."); + iRet = count; + goto END; + } + + for_each_pci_dev(pdev) { + if (0 != syno_jmb58x_check(pdev)) { + continue; + } + iCount++; + if (uiSelectedJMB58X == iCount) { + printk(KERN_INFO "No.%u jmb58x %04x:%04x on pcie bus %02x:%02x.%x has been selected\n", + iCount, pdev->vendor, pdev->device, pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + break; + } + } + if (0 != uiSelectedJMB58X && (uiSelectedJMB58X != iCount)) { + printk(KERN_INFO "There is no jmb58x being selected for input no.%u. All jmb58x will be selected by default.\n", uiSelectedJMB58X); + uiSelectedJMB58X = 0; + } + iRet = count; +END: + return iRet; +} + +// register function to attribute +static struct kobj_attribute jmb58xSelectAttr = __ATTR( jmb58x_spi_select, 0640, jmb58x_spi_select_show, jmb58x_spi_select_store); + +// register function to attribute +static struct kobj_attribute jmb58xUpdateAttr = __ATTR( jmb58x_spi_update, 0640, jmb58x_spi_content_show, jmb58x_spi_update_store); + +// put attribute to attribute group +static struct attribute *jmb58xSPIAttr[] = { + &jmb58xUpdateAttr.attr, + &jmb58xSelectAttr.attr, + NULL, /* NULL terminate the list*/ +}; +static struct attribute_group jmb58xSPIGroup = { + .attrs = jmb58xSPIAttr +}; + +static int jmb58x_spi_update_init(void) +{ + int iRet = -1; + jmb58xSPIObject = kobject_create_and_add("jmb58x_spi_update", kernel_kobj); + if (!jmb58xSPIObject) { + iRet = -ENOMEM; + goto END; + } + + //create attributes (files) + if(sysfs_create_group(jmb58xSPIObject, &jmb58xSPIGroup)){ + iRet = -ENOMEM; + goto END; + } + + iRet = 0; +END: + if (0 != iRet) { + if (jmb58xSPIObject) { + kobject_put(jmb58xSPIObject); + } + } + return iRet; +} + +static void jmb58x_spi_update_exit(void) +{ + kobject_put(jmb58xSPIObject); +} + +MODULE_LICENSE("GPL"); +module_init(jmb58x_spi_update_init); +module_exit(jmb58x_spi_update_exit); diff --git a/lib/synolib/syno_kexec_test.c b/lib/synolib/syno_kexec_test.c new file mode 100644 index 000000000000..d244e1886825 --- /dev/null +++ b/lib/synolib/syno_kexec_test.c @@ -0,0 +1,213 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +/* Copyright (c) 2000-2020 Synology Inc. All rights reserved. */ + +#ifdef MY_ABC_HERE + +#include +#include +#include +#include +#include +#include +#include + +/* + * Kexec test result. + * + * See also include/lib/synolib.h + */ +unsigned long kexec_test_flags; + +/* + * Test whether boot protocol is newer than v2.08. + * + * According to Documentation/x86/boot.txt, setup_data field is added in + * version v2.09. + */ +static bool test_boot_protocol_version(void) +{ + return 0x0209 <= boot_params.hdr.version; +} + +/* + * Test whether we skip compressed/head_64.S. + * + * On normal boot, arch/x86/boot/compressed/head_64.S will decompress the + * kernel and jump to entry point. + * + * However, the above-mentioned operation will be skipped when the kernel is + * booted with Kexec. + * + * Therefore, we insert a setup_data with type __DECOMPRESSION_TYPE__ in + * arch/x86/boot/compressed/head_64.S and check whether it exists here. + */ +static void test_decompression(void) +{ + bool passed = false; + struct setup_data *data; + u64 pa_data; + + if (!test_boot_protocol_version()) { + goto END; + } + + pa_data = boot_params.hdr.setup_data; + while (pa_data && !passed) { + data = early_memremap(pa_data, sizeof(*data)); + passed = (__DECOMPRESSION_TYPE__ == data->type); + pa_data = data->next; + early_memunmap(data, sizeof(*data)); + } + +END: + if (!passed) { + set_bit(KEXEC_TEST_DECOMPRESSION, &kexec_test_flags); + } +} + +/* + * Test whether bootloader type is kexec-tools. + * + * According to Documentation/x86/boot.txt, the value 0xD indicates that the + * bootloader is kexec-tools. + */ +static void test_bootloader(void) +{ + if (0xD == (boot_params.hdr.type_of_loader >> 4)) { + set_bit(KEXEC_TEST_BOOTLOADER, &kexec_test_flags); + } +} + +/* + * Test whether the minimal start address of usable memory in e820 table is + * 0x100. + * + * According to kexec-tools source code, it will not report the memory before + * address 0x100 as a usable memory. + */ +static void test_e820_table(void) +{ + bool passed = true; + u32 i; + + for (i = 0; i < boot_params.e820_entries; ++i) { + if (E820_TYPE_RAM == boot_params.e820_table[i].type && + 0x100 == boot_params.e820_table[i].addr) { + passed = false; + break; + } + } + + if (!passed) { + set_bit(KEXEC_TEST_E820_TABLE, &kexec_test_flags); + } +} + +/* + * Test whether we receive setup_data with type SETUP_NONE or SETUP_EFI. + * + * To support EFI runtime services, Kexec-ed kernel receives related + * addresses via setup_data with type SETUP_EFI, which are sent by first + * kernel. + * + * However, after observation, it seems that the kexec-tools shipped in + * XPEnology does not fill in type field or all fields. + * + * Therefore, we also regard SETUP_NONE as abnormal type because the type + * should not be SETUP_NONE in normal case. + */ +static void test_setup_data(void) +{ + bool passed = true; + struct setup_data *data; + u64 pa_data; + + if (!test_boot_protocol_version()) { + passed = false; + goto END; + } + + pa_data = boot_params.hdr.setup_data; + while (pa_data && passed) { + data = early_memremap(pa_data, sizeof(*data)); + passed = (SETUP_NONE != data->type && SETUP_EFI != data->type); + pa_data = data->next; + early_memunmap(data, sizeof(*data)); + } + +END: + if (!passed) { + set_bit(KEXEC_TEST_SETUP_DATA, &kexec_test_flags); + } +} + +/* + * Remove setup_data inserted by us. + * + * In order to hide our setup_data successfully, this function MUST be called + * before boot_params_ksysfs_init(); otherwise, our setup_data can be accessed + * via sysfs in /sys/kernel/boot_params/setup_data. + * + * The function boot_params_ksysfs_init() is located at + * arch/x86/kernel/ksysfs.c, and it will be called at arch-level initcall. + */ +static void remove_decompression_setup_data(void) +{ + bool found = false; + struct setup_data *data; + u64 pa_data, pa_prev, pa_next; + + if (!test_boot_protocol_version()) { + goto END; + } + + pa_data = boot_params.hdr.setup_data; + while (pa_data) { + data = early_memremap(pa_data, sizeof(*data)); + if (__DECOMPRESSION_TYPE__ == data->type) { + found = true; + data->type = 0; + } + pa_next = data->next; + early_memunmap(data, sizeof(*data)); + + if (found) { + break; + } + + pa_prev = pa_data; + pa_data = pa_next; + } + + if (!pa_data) { + goto END; + } + + if (pa_data == boot_params.hdr.setup_data) { + boot_params.hdr.setup_data = pa_next; + } else { + data = early_memremap(pa_prev, sizeof(*data)); + data->next = pa_next; + early_memunmap(data, sizeof(*data)); + } + +END: + return; +} + +/* + * Perform all Kexec detections and set the corresponding bit at test fail. + */ +void __init syno_kexec_test_init(void) +{ + test_decompression(); + test_bootloader(); + test_e820_table(); + test_setup_data(); + + remove_decompression_setup_data(); +} + +#endif /* MY_ABC_HERE */ diff --git a/lib/synolib/syno_pciepath_dts_pattern.c b/lib/synolib/syno_pciepath_dts_pattern.c new file mode 100644 index 000000000000..8daace52af65 --- /dev/null +++ b/lib/synolib/syno_pciepath_dts_pattern.c @@ -0,0 +1,98 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif +#include +#include +#include +#include +#include +#include +/** + * syno_pciepath_dts_pattern_get - save pciepath of pdev into szPciePath which is a char array with length "size" + * format root_bus:device.function,device.function,... + * only keep root_bus, because bus of child layer may change + * @pdev [IN]- the pcie device + * @szPciePath [IN/OUT]- the char array for saving pciepath. If failed, array content is cleared. + * @size [IN]- the length of szPciePath + * + * return 0: success + * -1: failed + */ +int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size) +{ + int ret = -1; + struct pci_dev *pDevUpstream = NULL; + char szTmp[SYNO_DTS_PROPERTY_CONTENT_LENGTH]={0}; + if (NULL == pdev || NULL == szPciePath || 0 >= size || SYNO_DTS_PROPERTY_CONTENT_LENGTH < size) { + goto END; + } + + while (NULL != pdev) { + if (NULL == pdev->bus) { + goto END; + } + + pDevUpstream = pci_upstream_bridge(pdev); + if (NULL == pDevUpstream) { + /* pdev is pcie root */ + if (0 == *szPciePath) { +#ifdef MY_ABC_HERE + snprintf(szPciePath, size, "%04x:%02x:%02x.%x", pci_domain_nr(pdev->bus), + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); +#else /* MY_ABC_HERE */ + snprintf(szPciePath, size, "%02x:%02x.%x", pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7); +#endif /* MY_ABC_HERE */ + } else { + /* Concatenate child pcie function and device */ + strncpy(szTmp, szPciePath, size); +#ifdef MY_ABC_HERE + snprintf(szPciePath, size, "%04x:%02x:%02x.%x,%s", pci_domain_nr(pdev->bus), + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7, szTmp); +#else /* MY_ABC_HERE */ + snprintf(szPciePath, size, "%02x:%02x.%x,%s", pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7, szTmp); +#endif /* MY_ABC_HERE */ + } + break; + } + + if (0 == *szPciePath) { + snprintf(szPciePath, size, "%02x.%x", (pdev->devfn) >> 3, (pdev->devfn) & 0x7); + } else { + strncpy(szTmp, szPciePath, size); + snprintf(szPciePath, size, "%02x.%x,%s", (pdev->devfn) >> 3, (pdev->devfn) & 0x7, szTmp); + } + + pdev = pDevUpstream; + } + ret = 0; +END: + if (-1 == ret) { + memset(szPciePath, 0, size); + } + return ret; +} +EXPORT_SYMBOL(syno_pciepath_dts_pattern_get); + +#ifdef MY_ABC_HERE +int syno_compare_dts_pciepath(struct pci_dev *pdev, const struct device_node *pDeviceNode) +{ + int ret = -1; + char szDevPciePath[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + char *szDtsNodePciePath = NULL; + szDtsNodePciePath = (char *)of_get_property(pDeviceNode, DT_PCIE_ROOT, NULL); + + if (NULL == szDtsNodePciePath) { + printk(KERN_ERR "%s: Read pcie_root from dts error\n", __func__); + goto END; + } + if (-1 == syno_pciepath_dts_pattern_get(pdev, szDevPciePath, SYNO_DTS_PROPERTY_CONTENT_LENGTH)) { + goto END; + } + if (0 == strncmp(szDtsNodePciePath, szDevPciePath, SYNO_DTS_PROPERTY_CONTENT_LENGTH)) { + ret = 0; + } +END: + return ret; +} +EXPORT_SYMBOL(syno_compare_dts_pciepath); +#endif /* MY_ABC_HERE */ diff --git a/lib/synolib/syno_plugin.c b/lib/synolib/syno_plugin.c new file mode 100644 index 000000000000..5679e55a3f64 --- /dev/null +++ b/lib/synolib/syno_plugin.c @@ -0,0 +1,211 @@ +/* kernel header */ +#include +#include +#include +#include +#include + + +/* user-defined header */ + + +/* static definition */ +#define SYNO_PLUGIN_ERR(msg, arg...) printk(KERN_ERR "SYNO_PLUGIN_ERR: %s() " msg, __FUNCTION__, ##arg) + + +typedef struct syno_plugin_s { + void *instance; + int magic; + int access_cnt; + struct list_head list; +} syno_plugin_t; + + +/* static variables */ +static LIST_HEAD(sg_syno_plugin_list); +static DEFINE_SPINLOCK(sg_syno_plugin_lock); + + +/* ------- function implementation ------- */ +static inline void syno_plugin_lock(void) +{ + spin_lock(&sg_syno_plugin_lock); +} + +static inline void syno_plugin_unlock(void) +{ + spin_unlock(&sg_syno_plugin_lock); +} + +static void __syno_plugin_free(syno_plugin_t *plugin) +{ + kfree(plugin); +} + +static syno_plugin_t * __syno_plugin_alloc(int plugin_magic, void *instance) +{ + syno_plugin_t *plugin; + + plugin = kmalloc(sizeof(syno_plugin_t), GFP_KERNEL); + if (!plugin) { + SYNO_PLUGIN_ERR("kmalloc fail"); + goto EXIT; + } + + plugin->magic = plugin_magic; + plugin->instance = instance; + plugin->access_cnt = 0; + INIT_LIST_HEAD(&plugin->list); + +EXIT: + return plugin; +} + +int syno_plugin_register(int plugin_magic, void *instance) +{ + int ret; + struct list_head *pos; + syno_plugin_t *plugin = NULL; + syno_plugin_t *tmp; + + if (!instance) { + ret = -EINVAL; + goto EXIT; + } + + plugin = __syno_plugin_alloc(plugin_magic, instance); + if (!plugin) { + ret = -ENOMEM; + goto EXIT; + } + + /* check if the plug-in has already registered */ + syno_plugin_lock(); + + if (!list_empty(&sg_syno_plugin_list)) { + list_for_each(pos, &sg_syno_plugin_list) { + tmp = list_entry(pos, syno_plugin_t, list); + if (tmp->magic == plugin_magic) { + ret = -EEXIST; + goto UNLOCK; + } + } + } + + list_add_tail(&plugin->list, &sg_syno_plugin_list); + + ret = 0; + +UNLOCK: + syno_plugin_unlock(); + if (0 > ret) { + if (plugin) { + __syno_plugin_free(plugin); + } + } +EXIT: + return ret; +} +EXPORT_SYMBOL(syno_plugin_register); + +int syno_plugin_unregister(int plugin_magic) +{ + int ret; + struct list_head *pos; + syno_plugin_t *tmp = NULL; + syno_plugin_t *plugin = NULL; + + syno_plugin_lock(); + + list_for_each(pos, &sg_syno_plugin_list) { + tmp = list_entry(pos, syno_plugin_t, list); + if (tmp->magic == plugin_magic) { + plugin = tmp; + break; + } + } + + if (!plugin) { + ret = -ENOENT; + goto EXIT; + } + + /* wait until no one use the plugin */ + if (0 < plugin->access_cnt) { + ret = -EBUSY; + goto EXIT; + } + + list_del(&plugin->list); + + ret = 0; + +EXIT: + syno_plugin_unlock(); + + if (0 == ret) { + __syno_plugin_free(plugin); + } + + return ret; +} +EXPORT_SYMBOL(syno_plugin_unregister); + +int syno_plugin_handle_get(int plugin_magic, void **hnd) +{ + int ret; + struct list_head *pos; + syno_plugin_t *plugin; + + *hnd = NULL; + ret = -ENOENT; + + syno_plugin_lock(); + + list_for_each(pos, &sg_syno_plugin_list) { + plugin = list_entry(pos, syno_plugin_t, list); + if (plugin->magic == plugin_magic) { + plugin->access_cnt++; + *hnd = plugin; + ret = 0; + break; + } + } + + syno_plugin_unlock(); + + return ret; +} +EXPORT_SYMBOL(syno_plugin_handle_get); + +void * syno_plugin_handle_instance(void *hnd) +{ + if (hnd) { + return ((syno_plugin_t *)hnd)->instance; + } else { + return NULL; + } +} +EXPORT_SYMBOL(syno_plugin_handle_instance); + +void syno_plugin_handle_put(void *hnd) +{ + syno_plugin_t *plugin; + + if (!hnd) { + return; + } + + plugin = (syno_plugin_t *)hnd; + + syno_plugin_lock(); + + if (0 < plugin->access_cnt) { + plugin->access_cnt--; + } else { + SYNO_PLUGIN_ERR("access_cnt is zero"); + } + + syno_plugin_unlock(); +} +EXPORT_SYMBOL(syno_plugin_handle_put); diff --git a/lib/synolib/syno_sata_signal_check.c b/lib/synolib/syno_sata_signal_check.c new file mode 100644 index 000000000000..ee910a5c1582 --- /dev/null +++ b/lib/synolib/syno_sata_signal_check.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include + +MODULE_LICENSE("Proprietary"); + +#define SYNO_JMB585_PORT_NUM 5 +#define SYNO_JMB582_PORT_NUM 2 +const unsigned jmb_port_addr[3][SYNO_JMB585_PORT_NUM] = {{0x74, 0x76, 0x78, 0x7A, 0x7C}, + {0x73, 0x75, 0x77, 0x79, 0x7B}, + {0x04, 0x11, 0x1e, 0x2b, 0x38}}; +const unsigned jmb_port_ctle_reg[SYNO_JMB585_PORT_NUM] = {0x0B, 0x18, 0x25, 0x32, 0x3F}; +const unsigned jmb_ssc_addr = 0x2; + +static void syno_jmb_read_phy_reg(void __iomem *bar5, u32 addr, u32 *data, unsigned long reg_type) +{ + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers. + // 1: SATA PHY registers. + + // Offset C0 [IDXP] is index port register + writel((addr & 0x01FFFUL) + (reg_type << 18UL), bar5 + 0xC0); + + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + *data = readl(bar5 + 0xC8); +} + +static int syno_jmb_sata_check(unsigned pID, int portNum) +{ + struct pci_dev *pdev = NULL; + void __iomem *bar5 = NULL; + u32 value = 0; + int i = 0; + int j = 0; + int iRet = -1; + unsigned long reg_type = 0; //read sata register or pcie register, 1 for sata, 0 for pcie + + printk("======= JMicron %x =======\n", pID); + while ((pdev = pci_get_device(0x197b, pID, pdev)) != NULL) { + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + printk("Can't map jmb%x registers pci%d:%d\n", pID, pdev->bus->number, pdev->bus->primary); + goto END; + } + + //check pcie register + reg_type = 0; // 0 for pcie phy register + syno_jmb_read_phy_reg(bar5, 0x1035, &value, reg_type);// 0x00000001 1: enable, 0: disable + printk("pci %d:%d Preset %s\n", pdev->bus->number, pdev->bus->primary, (value & 0x00000001)?"Enable":"Disable"); + syno_jmb_read_phy_reg(bar5, 0x1034, &value, reg_type);// 0x00000044 preset value, lane0/1 preset = 0x4 + printk("pci %d:%d Preset Value: 0x%x\n", pdev->bus->number, pdev->bus->primary, value); + syno_jmb_read_phy_reg(bar5, 0x28, &value, reg_type); // 0x222A90F3 // PCIe impedance + printk("pci %d:%d PCIe impedance reg: 0x%x\n", pdev->bus->number, pdev->bus->primary, value); + syno_jmb_read_phy_reg(bar5, 0x428, &value, reg_type); // 0x222A90F3 // PCIe impedance + printk("pci %d:%d PCIe impedance reg: 0x%x\n", pdev->bus->number, pdev->bus->primary, value); + + //check sata register + reg_type = 1; // 1 for sata phy register + syno_jmb_read_phy_reg(bar5, jmb_ssc_addr, &value, reg_type); // + printk("pci %d:%d SSC reg: 0x%x, SSC %s\n", pdev->bus->number, pdev->bus->primary, value, (value & 0x00000010)?"off":"on"); + //check sata signal + for (i = 0 ; i < portNum; i++) { + for (j = 0 ; j < 3; j++) { + syno_jmb_read_phy_reg(bar5, jmb_port_addr[j][i], &value, reg_type); + printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1, value); + } + syno_jmb_read_phy_reg(bar5, jmb_port_ctle_reg[i], &value, reg_type); + printk("pci %d:%d port %d SATA CTLE : 0x%x\n",pdev->bus->number, pdev->bus->primary, i, value); + } + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } + printk("============================\n"); + iRet = 0; + +END: + return iRet; +} + +const unsigned mv_port_gen[3] = {0x8D, 0x8F, 0x91}; +const unsigned mv_port_addr[4] = {0x178, 0x1f8, 0x278, 0x2f8}; +const unsigned mv_port_data[4] = {0x17c, 0x1fc, 0x27c, 0x2fc}; + +static int syno_mv_sata_check(unsigned pID, int portNum) +{ + struct pci_dev *pdev = NULL; + void __iomem *bar5 = NULL; + u32 value = 0; + int i = 0; + int j = 0; + int iRet = -1; + + printk("======= Marvell %x =======\n", pID); + while ((pdev = pci_get_device(0x1b4b, pID, pdev)) != NULL) { + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + printk("Can't map mv%x registers pci%d:%d\n", pID, pdev->bus->number, pdev->bus->primary); + goto END; + } + for (i = 0 ; i < portNum; i++) { + for (j = 0; j < 3; j++) { + writel(mv_port_gen[j], bar5 + mv_port_addr[i]); + value = readl(bar5 + mv_port_data[i]); + printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1 ,value); + } + } + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } + printk("============================\n"); + iRet = 0; + +END: + return iRet; +} + +const unsigned asmedia_1061_gen[3] = {0x4, 0x5, 0x6}; +const unsigned asmedia_1061_addr[2] = {0xCA0, 0xDA0}; +const unsigned asmedia_116x_port_addr[3][6] = {{0x122, 0x322, 0x522, 0x722, 0x922, 0xB22}, + {0x123, 0x323, 0x523, 0x723, 0x923, 0xB23}, + {0x124, 0x324, 0x524, 0x724, 0x924, 0xB24}}; +const unsigned asmedia_116x_ssc_addr = 0x198C; + +static int syno_asm1061_sata_check(unsigned pID, int portNum) +{ + struct pci_dev *pdev = NULL; + u8 value = 0; + unsigned int devfn = 0; + int i = 0; + int j = 0; + int iRet = -1; + + devfn = PCI_DEVFN(0x00, 0x0); + printk("======= Asmedia 1061 =======\n"); + while ((pdev = pci_get_device(0x1b21, pID, pdev)) != NULL) { + for (i = 0 ; i < portNum; i++) { + for (j = 0; j < 3; j++) { + pci_bus_read_config_byte(pdev->bus, devfn, asmedia_1061_addr[i] | asmedia_1061_gen[j], &value); + printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1 ,value); + } + } + } + printk("============================\n"); + iRet = 0; + + return iRet; +} + +static int syno_asm116x_sata_check(unsigned pID,int portNum) +{ + struct pci_dev *pdev = NULL; + void __iomem *bar0 = NULL; + u8 reg_data = 0; + int i = 0; + int j = 0; + int iRet = -1; + + printk("======= Asmedia %x =======\n", pID); + while ((pdev = pci_get_device(0x1b21, pID, pdev)) != NULL) { + bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!bar0) { + printk("Can't map asm%x registers pci%d:%d\n", pID, pdev->bus->number, pdev->bus->primary); + goto END; + } + + //read SSC register + reg_data = readb(bar0 + asmedia_116x_ssc_addr); + printk("pci %d:%d SSC reg: 0x%x, SSC %s\n", pdev->bus->number, pdev->bus->primary, reg_data, (reg_data & 0x01)?"on":"off"); + + for (i = 0 ; i < portNum; i++) { + for (j = 0; j < 3; j++) { + reg_data = readb(bar0 + asmedia_116x_port_addr[j][i]); + printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1 ,reg_data); + } + } + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + } + printk("============================\n"); + iRet = 0; + +END: + return iRet; +} + +typedef union u { + u32 raw; + struct u_fields{ + u8 byteen ; + u8 Register ; + u8 portid ; + u8 opcode ; + } field; +} SideBandMsg_t ; + +#define UNCORE_REG_MCR 0xd0 // Message Control +#define UNCORE_REG_MDR 0xd4 // Message Data +#define UNCORE_REG_MER 0xd8 // Extended address or offset attributes + +int MsgPortRead(u8 Opcode, u8 Port, u32 Register, u32 *Data, u32 addr) +{ + SideBandMsg_t readMsg; + u32 Data32; + Data32= Register & 0xFFFFFF00; + readMsg.field.opcode = (u8) Opcode; + readMsg.field.portid = (u8) Port; + readMsg.field.byteen = (u8) 0xf0; + + if( Register > 255 ) { // needs other register to hold 8+ bits + outl(addr + UNCORE_REG_MER, 0xCF8); + outl(Data32, 0xCFC); + readMsg.field.Register = (u8) Register ; + }else { + outl(addr + UNCORE_REG_MER, 0xCF8); + outl(0, 0xCFC); + readMsg.field.Register = (u8) Register ; + }; + + outl(addr + UNCORE_REG_MCR, 0xCF8); + outl(readMsg.raw, 0xCFC); + + outl(addr + UNCORE_REG_MDR, 0xCF8); + *Data = inl(0xCFC); + + return 0; +} + +#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ + (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \ + | (devfn << 8) | (reg & 0xFC)) + +static int intel_soc_sata(unsigned pID) +{ + struct pci_dev *pdev = NULL; + u32 value = 0; + int i = 0; + int j = 0; + u32 offset_t = 0; + unsigned int port[4]= {0x0, 0x200, 0x400, 0x600}; + unsigned int offset[6]= {0x88, 0x8c, 0x90, 0x100, 0x104, 0x108}; + u32 addr = 0; + + printk("======= Intel SoC SATA =======\n"); + while ((pdev = pci_get_device(0x8086, pID, pdev)) != NULL) { + addr = PCI_CONF1_ADDRESS(0, pdev->devfn, 0); + for (i = 0 ; i < 2; i++) { + for (j = 0; j < 6; j++) { + offset_t = port[i] + offset[j]; + MsgPortRead(0x0, 0x46, offset_t, &value, addr); + printk("gen3 port[%x] offset[%x]=0x%x\n", i, j, value); + } + printk("\n"); + } + + for (i = 0 ; i < 4; i++) { + for (j = 0; j < 6 ; j++) { + offset_t = port[i] + offset[j]; + MsgPortRead(0x0, 0x43, offset_t, &value, addr); + printk("gen2 port[%x] offset[%x]=0x%x\n", i, j, value); + } + printk("\n"); + } + } + return 0; +} + +static int __init syno_sata_check_init(void) +{ + syno_mv_sata_check(0x9235, 4); + syno_mv_sata_check(0x9215, 4); + syno_mv_sata_check(0x9170, 2); + syno_asm1061_sata_check(0x0612, 2); + syno_asm116x_sata_check(0x1164, 4); + syno_jmb_sata_check(0x0585, SYNO_JMB585_PORT_NUM); + syno_jmb_sata_check(0x0582, SYNO_JMB582_PORT_NUM); + + intel_soc_sata(0x1f0c); + + printk("Syno_SATA_check: Initialization completed.\n"); + + return 0; +} + +static void __exit syno_sata_check_exit(void) +{ + return; +} + +MODULE_AUTHOR("EricC"); +MODULE_DESCRIPTION("Syno_SATA_check\n"); +MODULE_LICENSE("Synology Inc."); + +module_init(syno_sata_check_init); +module_exit(syno_sata_check_exit); diff --git a/lib/synolib/syno_sata_signal_test.c b/lib/synolib/syno_sata_signal_test.c new file mode 100644 index 000000000000..9c8c94caa294 --- /dev/null +++ b/lib/synolib/syno_sata_signal_test.c @@ -0,0 +1,1044 @@ +#include +#include +#include +#include + +#define SATA_SPEED_LEN 3 +#define MAX_PATTERN_TYPES 6 + +static struct kobject *SynoSataTestObject = NULL; +unsigned int uiSelectedDev = 0; +unsigned int uiPort = 0; +unsigned int uiMaxPortNum = 0; +unsigned int uiSpeed = 0; +unsigned int uiPattern = 0; +char* szPatterns[MAX_PATTERN_TYPES] = {"NOT SELECT","LFTP","MFTP","HFTP","LBP","SSOP"}; + +unsigned mv_port_addr[4] = {0x178, 0x1F8, 0x278, 0x2F8}; +unsigned mv_port_data[4] = {0x17C, 0x1FC, 0x27C, 0x2FC}; +unsigned mv_speed_addr[SATA_SPEED_LEN] = {0x8D, 0x8F, 0x91}; +int asm1061_reg_addr_port0[SATA_SPEED_LEN] = {0xCA4, 0xCA5, 0xCA6}; +int asm1061_reg_addr_port1[SATA_SPEED_LEN] = {0xDA4, 0xDA5, 0xDA6}; +unsigned asm116x_port_addr[SATA_SPEED_LEN][6] = {{0x122, 0x322, 0x522, 0x722, 0x922, 0xB22}, + {0x123, 0x323, 0x523, 0x723, 0x923, 0xB23}, + {0x124, 0x324, 0x524, 0x724, 0x924, 0xB24}}; +unsigned jmb_port_addr[SATA_SPEED_LEN][5] = {{0x74, 0x76, 0x78, 0x7A, 0x7C}, + {0x73, 0x75, 0x77, 0x79, 0x7B}, + {0x04, 0x11, 0x1e, 0x2b, 0x38}}; + +static const struct pci_device_id syno_device[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9170) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9215) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9235) }, + { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, 0x0612) }, + { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, 0x1164) }, + { PCI_DEVICE(PCI_VENDOR_ID_ASMEDIA, 0x1165) }, + { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, 0x0585) }, + { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, 0x0582) }, +}; + +static bool is_synology_device(struct pci_dev *pdev) +{ + const struct pci_device_id *match_device; + + for (match_device = syno_device; + match_device < syno_device + ARRAY_SIZE(syno_device); + match_device++) { + if (pdev->vendor == match_device->vendor && + pdev->device == match_device->device) + return true; + } + return false; +} + +static struct pci_dev* syno_selected_dev_get(void) +{ + struct pci_dev *pdev = NULL; + unsigned int uiDevCount = 0; + + while (NULL != (pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if (!is_synology_device(pdev)) { + continue; + } + uiDevCount++; + if (uiSelectedDev == uiDevCount) { + break; + } + } + + return pdev; +} + +static ssize_t syno_test_select_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct pci_dev *pdev = NULL; + unsigned int uiDevCount = 0; + int iRet = 0; + + iRet += scnprintf(buf, PAGE_SIZE,"%s %d: NOT SELECT(default)\n", (uiSelectedDev == uiDevCount)?"*":" ", uiDevCount); + while (NULL != (pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if (!is_synology_device(pdev)) { + continue; + } + uiDevCount++; + iRet += scnprintf(buf + iRet, PAGE_SIZE - iRet, + "%s %u: %02x:%02x.%x : %04x:%04x\n", + (uiSelectedDev == uiDevCount)?"*":" ", uiDevCount, + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7, + pdev->vendor,pdev->device); + } + + return iRet; +} + +static ssize_t syno_test_select_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = NULL; + unsigned int uiDevCount = 0; + bool isDevFound = false; + + if (0 > kstrtouint(buf, 10, &uiSelectedDev)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + + if (0 == uiSelectedDev) { + printk(KERN_WARNING "No.0 means not select. Please select device.\n list devices by cat test_select\n"); + goto END; + } + + while (NULL != (pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if (!is_synology_device(pdev)) { + continue; + } + uiDevCount++; + if (uiSelectedDev == uiDevCount) { + isDevFound = true; + printk(KERN_INFO "Select %u: bus %02x:%02x.%x : %04x:%04x\n", uiDevCount, + pdev->bus->number, (pdev->devfn) >> 3, (pdev->devfn) & 0x7, + pdev->vendor,pdev->device); + break; + } + } + + if (!isDevFound) { + printk(KERN_WARNING "%u is out of range. Please select deivce again\n", uiSelectedDev); + uiSelectedDev = 0; + } +END: + return count; +} + +static ssize_t syno_test_ssc_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + u32 iValue; + bool isSSCOn = false; + int iRet = 0; + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (uiSpeed == 0 || SATA_SPEED_LEN < uiSpeed) { + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + goto END; + } + if (pdev->vendor == 0x197b && (pdev->device == 0x0585 || pdev->device == 0x0582)) { + void __iomem *bar5 = NULL; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb sata registers\n"); + goto END; + } + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers + // 1: SATA PHY registers. + // Offset 0x2 is for SSC enable/disable register, Offset C0 [IDXP] is index port register + writel((0x2 & 0x01FFFUL) + (1UL << 18UL), bar5 + 0xC0); + mdelay(100); + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + // 0x00003813 for disable SSC, 0x00003803 for enable + iValue = readl(bar5 + 0xC8); + isSSCOn = (iValue & 0x0010) ? 0 : 1; + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } else if (pdev->vendor == 0x1b21 && (pdev->device == 0x1164 || pdev->device == 0x1165)) { + void __iomem *bar0 = NULL; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!bar0) { + dev_warn(&pdev->dev, "Can't map asmedia sata registers\n"); + goto END; + } + + iValue = (u32)readb(bar0 + 0x198c); + isSSCOn = (iValue & 1) ? 1 : 0; + + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + } + iRet += scnprintf(buf, PAGE_SIZE, "Sata SSC register: 0x%x, SSC %s\n", iValue, isSSCOn ? "on": "off"); +END: + return iRet; +} + +static ssize_t syno_test_ssc_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + unsigned int uiSSCEnable = 0; + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (0 > kstrtouint(buf, 0, &uiSSCEnable)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + + if (1 < uiSSCEnable) { + dev_warn(&pdev->dev, "Invalid Input: %u!!\n", uiSSCEnable); + goto END; + } + + if (uiSpeed == 0 || SATA_SPEED_LEN < uiSpeed) { + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + goto END; + } + + if (pdev->vendor == 0x197b && (pdev->device == 0x0585 || pdev->device == 0x0582)) { + void __iomem *bar5 = NULL; + u32 value = 0; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb sata registers\n"); + goto END; + } + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers + // 1: SATA PHY registers. + // Offset 0x2 is for SSC enable/disable register, Offset C0 [IDXP] is index port register + writel((0x2 & 0x01FFFUL) + (1UL << 18UL), bar5 + 0xC0); + mdelay(100); + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + // 0x00003813 for disable SSC, 0x00003803 for enable + if (0 == uiSSCEnable) { + writel(0x00003813, bar5 + 0xC8); + } else { + writel(0x00003803, bar5 + 0xC8); + } + mdelay(100); + value = readl(bar5 + 0xC8); + dev_info(&pdev->dev, "Sata SSC register : 0x%x, SSC %s\n", value, (value & 0x0010) ? "off": "on"); + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } else if (pdev->vendor == 0x1b21 && (pdev->device == 0x1164 || pdev->device == 0x1165)) { + void __iomem *bar0 = NULL; + u8 ssc_reg_data = 0; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!bar0) { + dev_warn(&pdev->dev, "Can't map asmedia sata registers\n"); + goto END; + } + + ssc_reg_data = readb(bar0 + 0x198c); + mdelay(100); + if (0 == uiSSCEnable) { + ssc_reg_data &= ~0x01; + } else { + ssc_reg_data |= 0x01; + } + writeb(ssc_reg_data, bar0 + 0x198c); + mdelay(100); + + ssc_reg_data = readb(bar0 + 0x198c); + dev_info(&pdev->dev, "Sata SSC register : 0x%x, SSC %s\n", ssc_reg_data, (ssc_reg_data & 0x01) ? "on": "off"); + + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + } + +END: + return count; +} + +static ssize_t syno_test_port_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return scnprintf (buf, PAGE_SIZE, "%u\n", uiPort);; +} + +static ssize_t syno_test_port_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (0 > kstrtouint(buf, 0, &uiPort)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + + if ((pdev->vendor == 0x1b4b && pdev->device == 0x9235) || + (pdev->vendor == 0x1b4b && pdev->device == 0x9215) || + (pdev->vendor == 0x1b21 && pdev->device == 0x1164)) { + uiMaxPortNum = 4; + } else if ((pdev->vendor == 0x1b4b && pdev->device == 0x9170) || + (pdev->vendor == 0x1b21 && pdev->device == 0x0612) || + (pdev->vendor == 0x197b && pdev->device == 0x0582)) { + uiMaxPortNum = 2; + } else if ((pdev->vendor == 0x197b && pdev->device == 0x0585) || + (pdev->vendor == 0x1b21 && pdev->device == 0x1165)) { + uiMaxPortNum = 5; + } + + if (uiMaxPortNum <= uiPort) { + printk(KERN_WARNING "Invalid Port Number: %u\n", uiPort); + uiPort = 0; + } + +END: + return count; +} + +static ssize_t syno_test_setup_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return scnprintf (buf, PAGE_SIZE, "%u\n", uiSpeed); +} + +static ssize_t syno_test_setup_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (0 > kstrtouint(buf, 0, &uiSpeed)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + + if (0 == uiSpeed || 3 < uiSpeed) { + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + uiSpeed = 0; + goto END; + } + + if (pdev->vendor == 0x1b4b && (pdev->device == 0x9235 || pdev->device == 0x9215 || pdev->device == 0x9170)) { + void __iomem *bar5 = NULL; + + if (0 > uiPort || 3 < uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map mv sata registers\n"); + goto END; + } + + dev_info(&pdev->dev, "mv sata BIST, Port %u setup to SATA Gen %u\n", uiPort, uiSpeed); + + if (uiSpeed == 1) { + // Set speed to 1.5 Gbps + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000050, bar5+mv_port_data[uiPort]); + mdelay(100); + // Assert reset + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000051, bar5+mv_port_data[uiPort]); + mdelay(100); + // De-assert reset + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000050, bar5+mv_port_data[uiPort]); + mdelay(100); + } else if (uiSpeed == 2) { + // Set speed to 3.0 Gbps + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000060, bar5+mv_port_data[uiPort]); + mdelay(100); + // Assert reset + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000061, bar5+mv_port_data[uiPort]); + mdelay(100); + // De-assert reset + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000060, bar5+mv_port_data[uiPort]); + mdelay(100); + } else if (uiSpeed == 3) { + // Set speed to 6.0 Gbps + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000070, bar5+mv_port_data[uiPort]); + mdelay(100); + // Assert reset + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000071, bar5+mv_port_data[uiPort]); + mdelay(100); + // De-assert reset + writel(0x00000002, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000070, bar5+mv_port_data[uiPort]); + mdelay(100); + } + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } + +END: + return count; +} + +static ssize_t syno_test_pattern_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int i = 0, iRet = 0; + + for (i = 0; i < MAX_PATTERN_TYPES; i++) { + iRet += scnprintf(buf + iRet, PAGE_SIZE - iRet, "%s %d: %s\n", (uiPattern == i)?"*":" ", i, szPatterns[i]); + } + + return iRet; +} + +static ssize_t syno_test_pattern_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + int i = 0; + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (uiSpeed == 0 || SATA_SPEED_LEN < uiSpeed) { + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + goto END; + } + + for (i = 1; i < MAX_PATTERN_TYPES; i++) { + if (!memcmp(buf, szPatterns[i], strlen(szPatterns[i]))) { + uiPattern = i; + break; + } + } + + if (pdev->vendor == 0x1b4b && (pdev->device == 0x9235 || pdev->device == 0x9215 || pdev->device == 0x9170)) { + void __iomem *bar5 = NULL; + + if (0 > uiPort || 3 < uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map mv sata registers\n"); + goto END; + } + + dev_info(&pdev->dev, "mv sata BIST, test pattern %s", buf); + + // + // Write test pattern + // + if (!memcmp(buf, "LFTP", 4)) { + writel(0x00000096, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000097, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000098, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007E7E, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000099, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007E7E, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009A, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007E7E, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009B, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007E7E, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000095, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x000080F0, bar5+mv_port_data[uiPort]); + mdelay(100); + } else if (!memcmp(buf, "MFTP", 4)) { + writel(0x00000096, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000097, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000098, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007878, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000099, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007878, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009A, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007878, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009B, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00007878, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000095, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x000080F0, bar5+mv_port_data[uiPort]); + mdelay(100); + } else if (!memcmp(buf, "HFTP", 4)) { + writel(0x00000096, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000097, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000098, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00004A4A, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000099, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00004A4A, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009A, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00004A4A, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009B, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00004A4A, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000095, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x000080F0, bar5+mv_port_data[uiPort]); + mdelay(100); + } else if (!memcmp(buf, "LBP", 3)) { + writel(0x00000096, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000036, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000097, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x0000F423, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000098, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00006F43, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000099, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00003534, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009A, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x0000D353, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009B, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00004C05, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000095, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x000080E0, bar5+mv_port_data[uiPort]); + mdelay(100); + } else if (!memcmp(buf, "SSOP", 4)) { + writel(0x00000096, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000097, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000098, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000099, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009A, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x0000009B, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00000000, bar5+mv_port_data[uiPort]); + mdelay(100); + writel(0x00000095, bar5+mv_port_addr[uiPort]); + mdelay(100); + writel(0x00008050, bar5+mv_port_data[uiPort]); + mdelay(100); + } else { + dev_warn(&pdev->dev, "Invalid Pattern: %s !!\n", buf); + } + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } else if (pdev->vendor == 0x1b21 && pdev->device == 0x0612) { + u8 reg_data_LBP[SATA_SPEED_LEN] = {0x9D, 0xAD, 0xCD}; + u8 reg_data_XFTP[SATA_SPEED_LEN] = {0x96, 0xA6, 0xC6}; + u8 reg_data_SSOP[SATA_SPEED_LEN] = {0x9C, 0xAC, 0xCC}; + + if (0 > uiPort || 2 <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + dev_info(&pdev->dev, "test pattern %s", buf); + + // + // Write test pattern + // + if (!memcmp(buf, "LFTP", 4)) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCB2 : 0xDB2, reg_data_XFTP[uiSpeed - 1]); + mdelay(100); + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCC5 : 0xDC5, 0x02); + } else if (!memcmp(buf, "MFTP", 4)) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCB2 : 0xDB2, reg_data_XFTP[uiSpeed - 1]); + mdelay(100); + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCC5 : 0xDC5, 0x01); + } else if (!memcmp(buf, "HFTP", 4)) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCB2 : 0xDB2, reg_data_XFTP[uiSpeed - 1]); + mdelay(100); + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCC5 : 0xDC5, 0x00); + } else if (!memcmp(buf, "LBP", 3)) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCB2 : 0xDB2, reg_data_LBP[uiSpeed - 1]); + } else if (!memcmp(buf, "SSOP", 4)) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), (0 == uiPort) ? 0xCB2 : 0xDB2, reg_data_SSOP[uiSpeed - 1]); + } else { + dev_warn(&pdev->dev, "Invalid Pattern: %s !!\n", buf); + } + } else if (pdev->vendor == 0x197b && (pdev->device == 0x0585 || pdev->device == 0x0582)) { + unsigned jmb_BIST_enable[5] = {0x174, 0x1f4, 0x274, 0x2f4, 0x374}; + unsigned jmb_SATA_speed[5] = {0x12c, 0x1ac, 0x22c, 0x2ac, 0x32c}; + unsigned jmb_phy_ready[5] = {0x170, 0x1f0, 0x270, 0x2f0, 0x370}; + unsigned jmb_pattern_addr[5] = {0x178, 0x1f8, 0x278, 0x2f8, 0x378}; + void __iomem *bar5 = NULL; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb sata registers\n"); + goto END; + } + + // 1. Enable BIST Mode + writel(0xdc017740, bar5 + jmb_BIST_enable[uiPort]); + mdelay(100); + + // 2. Setting SATA Speed + switch (uiSpeed) { + case 1: + writel(0x00000010, bar5 + jmb_SATA_speed[uiPort]); + break; + case 2: + writel(0x00000020, bar5 + jmb_SATA_speed[uiPort]); + break; + case 3: + writel(0x00000000, bar5 + jmb_SATA_speed[uiPort]); + break; + default: + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + goto END; + } + mdelay(100); + + // 3. Setting force PHY ready + writel(0x0044700f, bar5 + jmb_phy_ready[uiPort]); + mdelay(100); + + // 4. Change SATA TX Measure Pattern + if (!memcmp(buf, "LFTP", 4)) { + writel(0x7E7E7E7E, bar5 + jmb_pattern_addr[uiPort]); + } else if (!memcmp(buf, "MFTP", 4)) { + writel(0x78787878, bar5 + jmb_pattern_addr[uiPort]); + } else if (!memcmp(buf, "HFTP", 4)) { + writel(0x4a4a4a4a, bar5 + jmb_pattern_addr[uiPort]); + } else if (!memcmp(buf, "LBP", 3)) { + writel(0x6B0C8B0c, bar5 + jmb_pattern_addr[uiPort]); + } else if (!memcmp(buf, "SSOP", 4)) { + writel(0x7f7f7f7f, bar5 + jmb_pattern_addr[uiPort]); + } else { + dev_warn(&pdev->dev, "Invalid Pattern: %s !!\n", buf); + } + mdelay(100); + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } + +END: + return count; +} + +static ssize_t syno_test_amp_adjust_show (struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + int iRet = 0; + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (uiSpeed == 0 || SATA_SPEED_LEN < uiSpeed) { + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + goto END; + } + + if (pdev->vendor == 0x1b4b && (pdev->device == 0x9235 || pdev->device == 0x9215 || pdev->device == 0x9170)) { + void __iomem *bar5 = NULL; + u32 value; + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map mv sata registers\n"); + goto END; + } + if (0 > uiPort || 3 < uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + writel(mv_speed_addr[uiSpeed - 1], bar5 + mv_port_addr[uiPort]); + value = readl(bar5 + mv_port_data[uiPort]); + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + + iRet += scnprintf (buf, PAGE_SIZE, "%x\n", value); + } else if (pdev->vendor == 0x1b21 && pdev->device == 0x0612) { + u8 reg_data = 0; + + if (0 > uiPort || 2 <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + if (0 == uiPort) { + pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), asm1061_reg_addr_port0[uiSpeed - 1], ®_data); + } else if (1 == uiPort) { + pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), asm1061_reg_addr_port1[uiSpeed - 1], ®_data); + } + + dev_info(&pdev->dev, "TX de-emphasis: 0x%x", (reg_data & 0xf0) >> 4); + dev_info(&pdev->dev, "TX amplitude: 0x%x", reg_data & 0x0f); + + iRet += scnprintf(buf, PAGE_SIZE, "%x\n", reg_data); + } else if (pdev->vendor == 0x197b && (pdev->device == 0x0585 || pdev->device == 0x0582)) { + void __iomem *bar5 = NULL; + u32 value; + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb sata registers\n"); + goto END; + } + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers + // 1: SATA PHY registers. + // Offset C0 [IDXP] is index port register + writel((jmb_port_addr[uiSpeed - 1][uiPort] & 0x01FFFUL) + (1UL << 18UL), bar5 + 0xC0); + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + value = readl(bar5 + 0xC8); + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + + dev_info(&pdev->dev, "TX de-emphasis: 0x%lx", (value & 0x3FFFFE0UL) >> 5); + dev_info(&pdev->dev, "TX amplitude: 0x%lx", value & 0x1FUL); + + iRet += scnprintf (buf, PAGE_SIZE, "%x\n", value); + } else if (pdev->vendor == 0x1b21 && (pdev->device == 0x1164 || pdev->device == 0x1165)) { + void __iomem *bar0 = NULL; + u8 reg_data = 0; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!bar0) { + dev_warn(&pdev->dev, "Can't map asmedia sata registers\n"); + goto END; + } + + reg_data = readb(bar0 + asm116x_port_addr[uiSpeed][uiPort]); + + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + + dev_info(&pdev->dev, "TX de-emphasis: 0x%x", (reg_data & 0xF0) >> 4); + dev_info(&pdev->dev, "TX amplitude: 0x%x", reg_data & 0xF); + + iRet += scnprintf (buf, PAGE_SIZE, "%x\n", reg_data); + } +END: + return iRet; +} + +static ssize_t syno_test_amp_adjust_store (struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct pci_dev *pdev = syno_selected_dev_get(); + + if (NULL == pdev) { + printk(KERN_WARNING "Failed to get pci device.\n"); + goto END; + } + + if (uiSpeed == 0 || SATA_SPEED_LEN < uiSpeed) { + dev_warn(&pdev->dev, "Invalid link speed !!\n"); + goto END; + } + + if (pdev->vendor == 0x1b4b && (pdev->device == 0x9235 || pdev->device == 0x9215 || pdev->device == 0x9170)) { + void __iomem *bar5 = NULL; + u32 iValue, i2; + + sscanf(buf, "%x", &iValue); + + if (0 > uiPort || 3 < uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map mv sata registers\n"); + goto END; + } + writel(0xE, bar5 + mv_port_addr[uiPort]); + i2 = readl(bar5 + mv_port_data[uiPort]); + // write apt adjust + writel(0xE, bar5 + mv_port_addr[uiPort]); + writel(i2 & ~0x100, bar5 + mv_port_data[uiPort]); + // write amp emph + writel(mv_speed_addr[uiSpeed - 1], bar5 + mv_port_addr[uiPort]); + writel(iValue, bar5 + mv_port_data[uiPort]); + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } else if (pdev->vendor == 0x1b21 && pdev->device == 0x0612) { + u8 reg_data = 0; + + if (0 > uiPort || 2 <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + sscanf(buf, "%02hhx", ®_data); + + if (0 == uiPort) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), asm1061_reg_addr_port0[uiSpeed - 1], reg_data); + } else if (1 == uiPort) { + pci_bus_write_config_byte(pdev->bus, PCI_DEVFN(0x00, 0x0), asm1061_reg_addr_port1[uiSpeed - 1], reg_data); + } + + dev_info(&pdev->dev, "TX de-emphasis: 0x%x", (reg_data & 0xf0) >> 4); + dev_info(&pdev->dev, "TX amplitude: 0x%x", reg_data & 0x0f); + } else if (pdev->vendor == 0x197b && (pdev->device == 0x0585 || pdev->device == 0x0582)) { + void __iomem *bar5 = NULL; + u32 iValue; + + sscanf(buf, "%x", &iValue); + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5)); + if (!bar5) { + dev_warn(&pdev->dev, "Can't map jmb sata registers\n"); + goto END; + } + // Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select: + // 0: PCIe PHY registers + // 1: SATA PHY registers. + // Offset C0 [IDXP] is index port register + writel((jmb_port_addr[uiSpeed - 1][uiPort] & 0x01FFFUL) + (1UL << 18UL), bar5 + 0xC0); + // Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access. + writel(iValue, bar5 + 0xC8); + + dev_info(&pdev->dev, "TX de-emphasis: 0x%lx", (iValue & 0x3FFFFE0UL) >> 5); + dev_info(&pdev->dev, "TX amplitude: 0x%lx", iValue & 0x1FUL); + + if (bar5) { + iounmap(bar5); + bar5 = NULL; + } + } else if (pdev->vendor == 0x1b21 && (pdev->device == 0x1164 || pdev->device == 0x1165)) { + void __iomem *bar0 = NULL; + u8 reg_data = 0; + + if (0 > uiPort || uiMaxPortNum <= uiPort) { + dev_warn(&pdev->dev, "Invalid port !!\n"); + goto END; + } + + sscanf(buf, "%02hhx", ®_data); + + bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!bar0) { + dev_warn(&pdev->dev, "Can't map asmedia sata registers\n"); + goto END; + } + + writeb(reg_data, bar0 + asm116x_port_addr[uiSpeed][uiPort]); + + dev_info(&pdev->dev, "TX de-emphasis: 0x%x", (reg_data & 0xF0) >> 4); + dev_info(&pdev->dev, "TX amplitude: 0x%x", reg_data & 0xF); + + if (bar0) { + iounmap(bar0); + bar0 = NULL; + } + } + +END: + return count; +} + +// register function to attribute +static struct kobj_attribute syno_test_select = __ATTR( syno_test_select, 0640, syno_test_select_show, syno_test_select_store); +static struct kobj_attribute syno_test_port = __ATTR( syno_test_port, 0640, syno_test_port_show, syno_test_port_store); +static struct kobj_attribute syno_test_setup = __ATTR( syno_test_setup, 0640, syno_test_setup_show, syno_test_setup_store); +static struct kobj_attribute syno_test_ssc = __ATTR( syno_test_ssc, 0640, syno_test_ssc_show, syno_test_ssc_store); +static struct kobj_attribute syno_test_pattern = __ATTR( syno_test_pattern, 0640, syno_test_pattern_show, syno_test_pattern_store); +static struct kobj_attribute syno_test_amp_adjust = __ATTR( syno_test_amp_adjust, 0640, syno_test_amp_adjust_show, syno_test_amp_adjust_store); + +// put attribute to attribute group +static struct attribute *SynoSataTestAttr[] = { + &syno_test_select.attr, + &syno_test_port.attr, + &syno_test_setup.attr, + &syno_test_ssc.attr, + &syno_test_pattern.attr, + &syno_test_amp_adjust.attr, + NULL, /* NULL terminate the list*/ +}; +static struct attribute_group SynoSataTestGroup = { + .attrs = SynoSataTestAttr +}; + +static int syno_sata_test_init(void) +{ + int iRet = -1; + SynoSataTestObject = kobject_create_and_add("syno_sata_test", kernel_kobj); + if (!SynoSataTestObject) { + iRet = -ENOMEM; + goto END; + } + + //create attributes (files) + if(sysfs_create_group(SynoSataTestObject, &SynoSataTestGroup)){ + iRet = -ENOMEM; + goto END; + } + + iRet = 0; +END: + if (0 != iRet) { + if (SynoSataTestObject) { + kobject_put(SynoSataTestObject); + } + } + return iRet; +} + +static void syno_sata_test_exit(void) +{ + kobject_put(SynoSataTestObject); +} + +MODULE_LICENSE("GPL"); +module_init(syno_sata_test_init); +module_exit(syno_sata_test_exit); diff --git a/lib/synolib/syno_uart2spi_logout.c b/lib/synolib/syno_uart2spi_logout.c new file mode 100644 index 000000000000..66e9320404e2 --- /dev/null +++ b/lib/synolib/syno_uart2spi_logout.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include + +#define SZ_DTS_PROPERTY_LOG_OUT_GPIO "syno_uart_logout_gpio" +#define SYNO_UART2SPI_LOGOUT_TTY_PATH "/dev/ttyS2" + + +struct file *tty_filp = NULL; +static struct kobject *SynoUart2SpiLogoutObject = NULL; + +int syno_tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) +{ + struct ktermios old_termios; + int iRet = -1; + + if (NULL == tty || NULL == new_termios) { + goto ERR; + } + + down_write(&tty->termios_rwsem); + old_termios = tty->termios; + tty->termios = *new_termios; + + if (tty && tty->ops && tty->ops->set_termios) { + tty->ops->set_termios(tty, &old_termios); + } + + if (tty->ldisc && tty->ldisc->ops && tty->ldisc->ops->set_termios) { + tty->ldisc->ops->set_termios(tty, &old_termios); + } + + up_write(&tty->termios_rwsem); + iRet = 0; +ERR: + return iRet; +} + +static int syno_ttyS_set_termios(void) +{ + int ret = -1; + struct ktermios new_termios; + struct tty_struct *tty = NULL; + + if (!tty_filp) { + printk(KERN_ERR "need open %s before set termios\n", SYNO_UART2SPI_LOGOUT_TTY_PATH); + goto ERR; + } + + tty = ((struct tty_file_private *)tty_filp->private_data)->tty; + memcpy(&new_termios, &tty->termios, sizeof(struct ktermios)); + + /* syno microP termios setting */ + new_termios.c_cflag &= ~(CBAUD | CBAUDEX); + new_termios.c_cflag |= B115200; + new_termios.c_cflag |= (CLOCAL | CREAD); + new_termios.c_cflag &= ~PARENB; + new_termios.c_cflag &= ~CSTOPB; + new_termios.c_cflag &= ~CSIZE; + new_termios.c_cflag |= CS8; + new_termios.c_cflag &= ~CRTSCTS; + new_termios.c_lflag = 0; + new_termios.c_iflag = 0; + + + ret = syno_tty_set_termios(tty, &new_termios); + +ERR: + return ret; +} + +static int syno_logout_gpio_pin_get(unsigned int *pin, unsigned int *polarity) +{ + int iRet = -1; + + if (0 != of_property_read_u32_index(of_root, SZ_DTS_PROPERTY_LOG_OUT_GPIO, SYNO_GPIO_PIN, pin)) { + printk(KERN_WARNING "Failed to read syno_uart_logout_gpio pin.\n"); + goto END; + } + if (0 != of_property_read_u32_index(of_root, SZ_DTS_PROPERTY_LOG_OUT_GPIO, SYNO_POLARITY_PIN, polarity)) { + printk(KERN_WARNING "Failed to read syno_uart_logout_gpio polarity.\n"); + goto END; + } + iRet = 0; +END: + return iRet; +} + +static ssize_t syno_logout_gpio_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int iRet = 0; + iRet += scnprintf(buf, PAGE_SIZE,"0: output low (default)\n1: output high\n2: input\n"); + + return iRet; +} + +static ssize_t syno_logout_gpio_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int uiGpioValue = 0; + + unsigned int uiGpioPin = 0; + unsigned int uiGpioPolarity = 0; + + if (0 > kstrtouint(buf, 10, &uiGpioValue)) { + printk(KERN_WARNING "Failed to convert string to unsigned int.\n"); + goto END; + } + + if (0 > uiGpioValue || 2 < uiGpioValue) { + printk(KERN_WARNING "Invalid Input\n"); + goto END; + } + + if (0 > syno_logout_gpio_pin_get(&uiGpioPin, &uiGpioPolarity)) { + goto END; + } + + + if (2 == uiGpioValue) { + syno_gpio_direction_input(uiGpioPin); + } else if (1 == uiGpioValue) { + syno_gpio_direction_output(uiGpioPin, uiGpioPolarity); + } else if (0 == uiGpioValue) { + syno_gpio_direction_output(uiGpioPin, (uiGpioPolarity? 0 : 1)); + } + +END: + return count; +} + + +// register function to attribute +static struct kobj_attribute syno_logout_gpio = __ATTR( syno_logout_gpio, 0640, syno_logout_gpio_show, syno_logout_gpio_store); + +// put attribute to attribute group +static struct attribute *SynoUart2SpiLogoutAttr[] = { + &syno_logout_gpio.attr, + NULL, /* NULL terminate the list*/ +}; + +static struct attribute_group SynoUart2SpiLogoutGroup = { + .attrs = SynoUart2SpiLogoutAttr +}; + + +static int syno_uart2spi_logout_init(void) +{ + int iRet = -1; + SynoUart2SpiLogoutObject = kobject_create_and_add("syno_uart2spi_logout", kernel_kobj); + if (!SynoUart2SpiLogoutObject) { + iRet = -ENOMEM; + goto END; + } + + //create attributes (files) + if(sysfs_create_group(SynoUart2SpiLogoutObject, &SynoUart2SpiLogoutGroup)){ + iRet = -ENOMEM; + goto END; + } + + // initialize /dev/ttyS2 + tty_filp = filp_open(SYNO_UART2SPI_LOGOUT_TTY_PATH, O_RDWR | O_NOCTTY, 0); + if (IS_ERR(tty_filp)) { + printk(KERN_ERR "unable to open %s\n", SYNO_UART2SPI_LOGOUT_TTY_PATH); + goto END; + } + + if (syno_ttyS_set_termios()) { + printk(KERN_ERR "unable to set termios of %s\n", SYNO_UART2SPI_LOGOUT_TTY_PATH); + goto END; + } + + iRet = 0; +END: + if (tty_filp) { + filp_close(tty_filp, NULL); + tty_filp = NULL; + } + if (0 != iRet) { + if (SynoUart2SpiLogoutObject) { + kobject_put(SynoUart2SpiLogoutObject); + } + } + return iRet; +} + +static void syno_uart2spi_logout_exit(void) +{ + kobject_put(SynoUart2SpiLogoutObject); +} + +MODULE_LICENSE("GPL"); +module_init(syno_uart2spi_logout_init); +module_exit(syno_uart2spi_logout_exit); diff --git a/mm/Kconfig b/mm/Kconfig index 390165ffbb0f..00d35fef7096 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -804,7 +804,7 @@ config DEVICE_PRIVATE group of devices). You likely also want to select HMM_MIRROR. config VMAP_PFN - bool + bool "VMAP_PFN" config FRAME_VECTOR bool diff --git a/mm/Makefile b/mm/Makefile index d73aed0fc99c..376e0bc3ebdb 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -120,3 +120,4 @@ obj-$(CONFIG_MEMFD_CREATE) += memfd.o obj-$(CONFIG_MAPPING_DIRTY_HELPERS) += mapping_dirty_helpers.o obj-$(CONFIG_PTDUMP_CORE) += ptdump.o obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o +obj-$(CONFIG_SYNO_AUFS_PATCH) += prfile.o diff --git a/mm/cma.c b/mm/cma.c index 7f415d7cda9f..3a36f6e0eb08 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Contiguous Memory Allocator @@ -38,7 +41,15 @@ struct cma cma_areas[MAX_CMA_AREAS]; unsigned cma_area_count; +#if defined(MY_DEF_HERE) +#if defined(CONFIG_ION_RTK_DHC_HEAP) +DEFINE_MUTEX(cma_mutex); +#else static DEFINE_MUTEX(cma_mutex); +#endif +#else /* MY_DEF_HERE */ +static DEFINE_MUTEX(cma_mutex); +#endif /* MY_DEF_HERE */ phys_addr_t cma_get_base(const struct cma *cma) { diff --git a/mm/compaction.c b/mm/compaction.c index dba424447473..980e5d36ba50 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/mm/compaction.c @@ -1884,7 +1887,27 @@ static inline bool is_via_compact_memory(int order) static bool kswapd_is_running(pg_data_t *pgdat) { +#ifdef MY_ABC_HERE + int hid; + int nr_threads = kswapd_threads_current; + struct task_struct *kswapd; + + /** + * Avoid the race with updating, and assume that kswapd will run + * after kswapds threads updated. + */ + if (test_bit(PGDAT_SYNO_UPDATING_KSWAPDS, &pgdat->flags)) + return true; + + for (hid = 0; hid < nr_threads; hid++) { + kswapd = pgdat->kswapd[hid]; + if (kswapd && kswapd->state == TASK_RUNNING) + return true; + } + return false; +#else /* MY_ABC_HERE */ return pgdat->kswapd && (pgdat->kswapd->state == TASK_RUNNING); +#endif /* MY_ABC_HERE */ } /* diff --git a/mm/filemap.c b/mm/filemap.c index 125b69f59caa..4f0c477be21b 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/mm/filemap.c @@ -54,6 +57,12 @@ #include +#ifdef MY_ABC_HERE +#include +#include +#include +#endif /* MY_ABC_HERE */ + /* * Shared mappings implemented 30.11.1994. It's not fully working yet, * though. @@ -2913,7 +2922,11 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) vm_fault_t ret = VM_FAULT_LOCKED; sb_start_pagefault(inode->i_sb); +#ifdef MY_ABC_HERE + vma_file_update_time(vmf->vma); +#else file_update_time(vmf->vma->vm_file); +#endif /* MY_ABC_HERE */ lock_page(page); if (page->mapping != inode->i_mapping) { unlock_page(page); @@ -3164,6 +3177,197 @@ int pagecache_write_end(struct file *file, struct address_space *mapping, } EXPORT_SYMBOL(pagecache_write_end); +#ifdef MY_ABC_HERE +static int sock2iov(struct socket *sock, struct kvec *iov, + int page_count, int start_page, size_t bytes_to_received, size_t *bytes_received) +{ + int kmsg_ret = 0; + long rcvtimeo = 0; + struct msghdr msg = {0}; + + rcvtimeo = sock->sk->sk_rcvtimeo; + sock->sk->sk_rcvtimeo = 64 * HZ; + + kmsg_ret = kernel_recvmsg( + sock, &msg, &iov[start_page], page_count, bytes_to_received, + MSG_WAITALL); + + sock->sk->sk_rcvtimeo = rcvtimeo; + if (kmsg_ret >= 0) { + *bytes_received = (size_t) kmsg_ret; + if (kmsg_ret == bytes_to_received) { + /* + * remains 0 here, + * bytes_received is set and matches desired length. + * + */ + kmsg_ret = 0; + } else { + kmsg_ret = -EPIPE; + } + } + + return kmsg_ret; +} + +static int __do_recvfile(struct file *file, struct socket *sock, loff_t pos, + size_t count, size_t * rbytes, size_t * wbytes) +{ + int err = 0; + int write_end_ret = 0; + int flags = AOP_FLAG_NOFS | AOP_FLAG_RECVFILE; + unsigned bytes = 0; + pgoff_t offset = (pos & (PAGE_SIZE - 1)); + size_t bytes_total_received = 0, bytes_total_wrote = 0; + struct page *page = NULL; + struct address_space *mapping = file->f_mapping; + + /* Check hook functions */ + if (!mapping->a_ops->write_begin || !mapping->a_ops->write_end) { + printk("write_begin()/write_end() is not implemented\n"); + err = -EOPNOTSUPP; + goto end; + } + + do { + void *fsdata = NULL; + struct kvec iov; + size_t bytes_received; + + bytes = min_t(unsigned int, PAGE_SIZE - offset, count); + + err = mapping->a_ops->write_begin( + file, mapping, pos, bytes, flags, + &page, &fsdata); + if (unlikely(err)) + break; + + iov.iov_base = kmap(page) + offset; + iov.iov_len = bytes; + err = sock2iov(sock, &iov, 1, 0, bytes, &bytes_received); + kunmap(page); + bytes_total_received += bytes_received; + + write_end_ret = mapping->a_ops->write_end(file, mapping, pos, + bytes, bytes, page, fsdata); + if (write_end_ret < 0 && !err) + err = write_end_ret; + if (err) + break; + + bytes_total_wrote += bytes; + count -= bytes; + pos += bytes; + offset = 0; + } while (count); + balance_dirty_pages_ratelimited(mapping); + +end: + *rbytes = bytes_total_received; + *wbytes = bytes_total_wrote; + return err ? err : bytes_total_received; +} + +#ifdef MY_ABC_HERE +static int __do_recvfile_with_aggregate_write_end(struct file *file, struct socket *sock, loff_t pos, + size_t count, size_t * rbytes, size_t * wbytes) +{ + int err = 0; + int pages_allocated = 0; + int page_index = 0; + int flags = AOP_FLAG_NOFS | AOP_FLAG_RECVFILE; + int write_end_ret = 0; + loff_t first_page_pos = 0; + unsigned bytes = 0; + pgoff_t offset = (pos & (PAGE_SIZE - 1)); + size_t bytes_received = 0, bytes_wrote = 0; + ssize_t bytes_to_received = 0; + struct kvec iov[MAX_PAGES_PER_RECVFILE + 1]; + struct page *page = NULL; + struct page *page_list[MAX_PAGES_PER_RECVFILE + 1]; + struct address_space *mapping = file->f_mapping; + + /* Check hook functions */ + if (!mapping->a_ops->write_begin || !mapping->a_ops->aggregate_write_end) { + printk("write_begin()/aggregate_write_end() is not implemented\n"); + err = -EOPNOTSUPP; + goto end; + } + + do { + bytes = min_t(unsigned int, PAGE_SIZE - offset, count); + + err = mapping->a_ops->write_begin( + file, mapping, pos, bytes, flags, + &page, 0); + if (err) + goto release_pages; + + /* Bookkeep info about this allocated page */ + page_list[pages_allocated] = page; + if (!pages_allocated) + first_page_pos = pos; + iov[pages_allocated].iov_base = kmap(page) + offset; + iov[pages_allocated].iov_len = bytes; + pages_allocated++; + + BUG_ON(pages_allocated > MAX_PAGES_PER_RECVFILE + 1); + + count -= bytes; + pos += bytes; + bytes_to_received += bytes; + offset = 0; + flags |= AOP_FLAG_RECVFILE_ECRYPTFS_NO_TRUNCATE; + } while (count); + + err = sock2iov(sock, iov, pages_allocated, 0, bytes_to_received, &bytes_received); + +release_pages: + *rbytes = bytes_received; + bytes_wrote = bytes_received; + + for (page_index = 0; page_index < pages_allocated; page_index++) + kunmap(page_list[page_index]); + + write_end_ret = mapping->a_ops->aggregate_write_end( + file, mapping, first_page_pos, + bytes_to_received, bytes_to_received, + page_list, pages_allocated); + + /* Keep error code if write_end() failed for some reason */ + if (0 > write_end_ret) { + bytes_wrote = 0; + if (!err) + err = write_end_ret; + } + *wbytes = bytes_wrote; + balance_dirty_pages_ratelimited(mapping); + +end: + return err ? err : bytes_received; +} +#endif /* MY_ABC_HERE */ + +int do_recvfile(struct file *file, struct socket *sock, loff_t pos, + size_t count, size_t * rbytes, size_t * wbytes) +{ + int ret; +#ifdef MY_ABC_HERE + struct address_space *mapping = file->f_mapping; + + if (mapping->a_ops->aggregate_write_end) + ret = __do_recvfile_with_aggregate_write_end(file, sock, pos, count, rbytes, wbytes); + else + ret = __do_recvfile(file, sock, pos, count, rbytes, wbytes); +#else /* MY_ABC_HERE */ + ret = __do_recvfile(file, sock, pos, count, rbytes, wbytes); +#endif /* MY_ABC_HERE */ + + return ret; +} +EXPORT_SYMBOL(do_recvfile); +#endif /* MY_ABC_HERE */ + /* * Warn about a page cache invalidation failure during a direct I/O write. */ diff --git a/mm/mmap.c b/mm/mmap.c index 5c8b4485860d..b3cd2000c8be 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * mm/mmap.c @@ -49,6 +52,7 @@ #include #include + #include #include #include @@ -179,7 +183,11 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) +#ifdef MY_ABC_HERE + vma_fput(vma); +#else fput(vma->vm_file); +#endif /* MY_ABC_HERE */ mpol_put(vma_policy(vma)); vm_area_free(vma); return next; @@ -951,7 +959,11 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, if (remove_next) { if (file) { uprobe_munmap(next, next->vm_start, next->vm_end); +#ifdef MY_ABC_HERE + vma_fput(vma); +#else fput(file); +#endif /* MY_ABC_HERE */ } if (next->anon_vma) anon_vma_merge(vma, next); @@ -1897,8 +1909,13 @@ unsigned long mmap_region(struct file *file, unsigned long addr, return addr; unmap_and_free_vma: +#ifdef MY_ABC_HERE + vma_fput(vma); + vma->vm_file = NULL; +#else vma->vm_file = NULL; fput(file); +#endif /* MY_ABC_HERE */ /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); @@ -2756,8 +2773,13 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, if (err) goto out_free_mpol; +#ifdef MY_ABC_HERE + if (new->vm_file) + vma_get_file(new); +#else if (new->vm_file) get_file(new->vm_file); +#endif /* MY_ABC_HERE */ if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); @@ -2775,8 +2797,13 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, /* Clean everything up if vma_adjust failed. */ if (new->vm_ops && new->vm_ops->close) new->vm_ops->close(new); +#ifdef MY_ABC_HERE + if (new->vm_file) + vma_fput(new); +#else if (new->vm_file) fput(new->vm_file); +#endif /* MY_ABC_HERE */ unlink_anon_vmas(new); out_free_mpol: mpol_put(vma_policy(new)); @@ -2970,6 +2997,9 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, unsigned long populate = 0; unsigned long ret = -EINVAL; struct file *file; +#ifdef MY_ABC_HERE + struct file *prfile; +#endif /* MY_ABC_HERE */ pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", current->comm, current->pid); @@ -3044,10 +3074,35 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, } } +#ifdef MY_ABC_HERE + vma_get_file(vma); + file = vma->vm_file; + prfile = vma->vm_prfile; + ret = do_mmap(vma->vm_file, start, size, + prot, flags, pgoff, &populate, NULL); + if (!IS_ERR_VALUE(ret) && file && prfile) { + struct vm_area_struct *new_vma; + + new_vma = find_vma(mm, ret); + if (!new_vma->vm_prfile) + new_vma->vm_prfile = prfile; + if (new_vma != vma) + get_file(prfile); + } + /* + * two fput()s instead of vma_fput(vma), + * coz vma may not be available anymore. + */ + fput(file); + if (prfile) + fput(prfile); +#else file = get_file(vma->vm_file); ret = do_mmap(vma->vm_file, start, size, prot, flags, pgoff, &populate, NULL); fput(file); +#endif /* MY_ABC_HERE */ + out: mmap_write_unlock(mm); if (populate) @@ -3333,8 +3388,13 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, goto out_free_vma; if (anon_vma_clone(new_vma, vma)) goto out_free_mempol; +#ifdef MY_ABC_HERE + if (new_vma->vm_file) + vma_get_file(new_vma); +#else if (new_vma->vm_file) get_file(new_vma->vm_file); +#endif /* MY_ABC_HERE */ if (new_vma->vm_ops && new_vma->vm_ops->open) new_vma->vm_ops->open(new_vma); vma_link(mm, new_vma, prev, rb_link, rb_parent); diff --git a/mm/mremap.c b/mm/mremap.c index 138abbae4f75..86a57136e73e 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -444,6 +444,14 @@ static unsigned long move_vma(struct vm_area_struct *vma, /* We always clear VM_LOCKED[ONFAULT] on the old vma */ vma->vm_flags &= VM_LOCKED_CLEAR_MASK; + /* + * anon_vma links of the old vma is no longer needed after its page + * table has been moved. + */ + if (new_vma != vma && vma->vm_start == old_addr && + vma->vm_end == (old_addr + old_len)) + unlink_anon_vmas(vma); + /* Because we won't unmap we don't need to touch locked_vm */ goto out; } diff --git a/mm/nommu.c b/mm/nommu.c index 0faf39b32cdb..d8dfebe83b3b 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/mm/nommu.c @@ -532,8 +535,13 @@ static void __put_nommu_region(struct vm_region *region) delete_nommu_region(region); up_write(&nommu_region_sem); +#ifdef MY_ABC_HERE + if (region->vm_file) + vmr_fput(region); +#else if (region->vm_file) fput(region->vm_file); +#endif /* MY_ABC_HERE */ /* IO memory and memory shared directly out of the pagecache * from ramfs/tmpfs mustn't be released here */ @@ -664,8 +672,13 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) { if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); +#ifdef MY_ABC_HERE + if (vma->vm_file) + vma_fput(vma); +#else if (vma->vm_file) fput(vma->vm_file); +#endif /* MY_ABC_HERE */ put_nommu_region(vma->vm_region); vm_area_free(vma); } @@ -1188,7 +1201,11 @@ unsigned long do_mmap(struct file *file, goto error_just_free; } } +#ifdef MY_ABC_HERE + vmr_fput(region); +#else fput(region->vm_file); +#endif /* MY_ABC_HERE */ kmem_cache_free(vm_region_jar, region); region = pregion; result = start; @@ -1264,11 +1281,19 @@ unsigned long do_mmap(struct file *file, error_just_free: up_write(&nommu_region_sem); error: +#ifdef MY_ABC_HERE + if (region->vm_file) + vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) + vma_fput(vma); +#else if (region->vm_file) fput(region->vm_file); kmem_cache_free(vm_region_jar, region); if (vma->vm_file) fput(vma->vm_file); +#endif /* MY_ABC_HERE */ vm_area_free(vma); return ret; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 8b84661a6410..1be845346746 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/mm/oom_kill.c @@ -55,6 +58,16 @@ int sysctl_panic_on_oom; int sysctl_oom_kill_allocating_task; int sysctl_oom_dump_tasks = 1; +#ifdef MY_ABC_HERE +extern void syno_dump_modules(void); + +#ifdef KERN_INFO +#undef KERN_INFO +#define KERN_INFO KERN_WARNING +#endif /* KERN_INFO */ + +#endif /* MY_ABC_HERE */ + /* * Serializes oom killer invocations (out_of_memory()) from all contexts to * prevent from over eager oom killing (e.g. when the oom killer is invoked @@ -470,6 +483,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p) dump_tasks(oc); if (p) dump_oom_summary(oc, p); +#ifdef MY_ABC_HERE + syno_dump_modules(); +#endif /* MY_ABC_HERE */ } /* @@ -855,6 +871,18 @@ static bool task_will_free_mem(struct task_struct *task) return ret; } +#ifdef MY_ABC_HERE +int (*funcSYNOSendErrorOOMEvent)(const char*) = NULL; +static void sendOOMEvent(const char* process_name){ + if (NULL == funcSYNOSendErrorOOMEvent){ + printk(KERN_ERR "Can't reference to function 'funcSYNOSendErrorOOMEvent'\n"); + return; + } + funcSYNOSendErrorOOMEvent(process_name); +} +EXPORT_SYMBOL(funcSYNOSendErrorOOMEvent); +#endif /* MY_ABC_HERE */ + static void __oom_kill_process(struct task_struct *victim, const char *message) { struct task_struct *p; @@ -985,6 +1013,10 @@ static void oom_kill_process(struct oom_control *oc, const char *message) oom_group = mem_cgroup_get_oom_group(victim, oc->memcg); __oom_kill_process(victim, message); +#ifdef MY_ABC_HERE + if (!is_memcg_oom(oc)) + sendOOMEvent(victim->comm); +#endif /* MY_ABC_HERE */ /* * If necessary, kill all tasks in the selected memory cgroup. diff --git a/mm/page-writeback.c b/mm/page-writeback.c index eb34d204d4ee..39fa9f8db672 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * mm/page-writeback.c @@ -112,6 +115,9 @@ unsigned int dirty_expire_interval = 30 * 100; /* centiseconds */ * Flag that makes the machine dump writes/reads and block dirtyings. */ int block_dump; +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(block_dump); +#endif /* MY_ABC_HERE */ /* * Flag that puts the machine in "laptop mode". Doubles as a timeout in jiffies: @@ -465,6 +471,9 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty) *pbackground = gdtc.bg_thresh; *pdirty = gdtc.thresh; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(global_dirty_limits); +#endif /* MY_ABC_HERE */ /** * node_dirty_limit - maximum number of dirty pages allowed in a node @@ -2844,7 +2853,13 @@ EXPORT_SYMBOL_GPL(wait_on_page_writeback); void wait_for_stable_page(struct page *page) { page = thp_head(page); +#ifdef MY_ABC_HERE + if (page->mapping->host->i_sb->s_iflags & SB_I_STABLE_WRITES || + (sb_is_blkdev_sb(page->mapping->host->i_sb) && + blk_queue_stable_writes(I_BDEV(page->mapping->host)->bd_disk->queue))) +#else /* MY_ABC_HERE */ if (page->mapping->host->i_sb->s_iflags & SB_I_STABLE_WRITES) +#endif /* MY_ABC_HERE */ wait_on_page_writeback(page); } EXPORT_SYMBOL_GPL(wait_for_stable_page); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0166558d3d64..089bd7581a9d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/mm/page_alloc.c @@ -7669,7 +7672,7 @@ void __init mem_init_print_info(const char *str) */ #define adj_init_size(start, end, size, pos, adj) \ do { \ - if (start <= pos && pos < end && size > adj) \ + if (&start[0] <= &pos[0] && &pos[0] < &end[0] && size > adj) \ size -= adj; \ } while (0) @@ -7977,6 +7980,23 @@ int __meminit init_per_zone_wmark_min(void) } postcore_initcall(init_per_zone_wmark_min) +#ifdef MY_ABC_HERE +int kswapd_threads_sysctl_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int rc; + + rc = proc_dointvec_minmax(table, write, buffer, length, ppos); + if (rc) + return rc; + + if (write) + update_kswapd_threads(); + + return 0; +} + +#endif /* MY_ABC_HERE */ /* * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so * that we can call two helper functions whenever min_free_kbytes diff --git a/mm/prfile.c b/mm/prfile.c new file mode 100644 index 000000000000..00d51187c325 --- /dev/null +++ b/mm/prfile.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mainly for aufs which mmap(2) different file and wants to print different + * path in /proc/PID/maps. + * Call these functions via macros defined in linux/mm.h. + * + * See Documentation/filesystems/aufs/design/06mmap.txt + * + * Copyright (c) 2014-2020 Junjro R. Okajima + * Copyright (c) 2014 Ian Campbell + */ + +#include +#include +#include + +/* #define PRFILE_TRACE */ +static inline void prfile_trace(struct file *f, struct file *pr, + const char func[], int line, const char func2[]) +{ +#ifdef PRFILE_TRACE + if (pr) + pr_info("%s:%d: %s, %pD2\n", func, line, func2, f); +#endif +} + +void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], + int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + + prfile_trace(f, pr, func, line, __func__); + file_update_time(f); + if (f && pr) + file_update_time(pr); +} + +struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], + int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + + prfile_trace(f, pr, func, line, __func__); + return (f && pr) ? pr : f; +} + +void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + + prfile_trace(f, pr, func, line, __func__); + get_file(f); + if (f && pr) + get_file(pr); +} + +void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) +{ + struct file *f = vma->vm_file, *pr = vma->vm_prfile; + + prfile_trace(f, pr, func, line, __func__); + fput(f); + if (f && pr) + fput(pr); +} + +#ifndef CONFIG_MMU +struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], + int line) +{ + struct file *f = region->vm_file, *pr = region->vm_prfile; + + prfile_trace(f, pr, func, line, __func__); + return (f && pr) ? pr : f; +} + +void vmr_do_fput(struct vm_region *region, const char func[], int line) +{ + struct file *f = region->vm_file, *pr = region->vm_prfile; + + prfile_trace(f, pr, func, line, __func__); + fput(f); + if (f && pr) + fput(pr); +} +#endif /* !CONFIG_MMU */ diff --git a/mm/rmap.c b/mm/rmap.c index 14f84f70c557..b5c5b21e2e75 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -89,7 +89,8 @@ static inline struct anon_vma *anon_vma_alloc(void) anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); if (anon_vma) { atomic_set(&anon_vma->refcount, 1); - anon_vma->degree = 1; /* Reference for first vma */ + anon_vma->num_children = 0; + anon_vma->num_active_vmas = 0; anon_vma->parent = anon_vma; /* * Initialise the anon_vma root to point to itself. If called @@ -197,6 +198,7 @@ int __anon_vma_prepare(struct vm_area_struct *vma) anon_vma = anon_vma_alloc(); if (unlikely(!anon_vma)) goto out_enomem_free_avc; + anon_vma->num_children++; /* self-parent link for new root */ allocated = anon_vma; } @@ -206,8 +208,7 @@ int __anon_vma_prepare(struct vm_area_struct *vma) if (likely(!vma->anon_vma)) { vma->anon_vma = anon_vma; anon_vma_chain_link(vma, avc, anon_vma); - /* vma reference or self-parent link for new root */ - anon_vma->degree++; + anon_vma->num_active_vmas++; allocated = NULL; avc = NULL; } @@ -297,14 +298,19 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) * * Do not chose parent anon_vma, otherwise first child * will always reuse it. Root anon_vma is never reused: + * Reuse existing anon_vma if it has no vma and only one + * anon_vma child. + * + * Root anon_vma is never reused: * it has self-parent reference and at least one child. */ if (!dst->anon_vma && src->anon_vma && - anon_vma != src->anon_vma && anon_vma->degree < 2) + anon_vma->num_children < 2 && + anon_vma->num_active_vmas == 0) dst->anon_vma = anon_vma; } if (dst->anon_vma) - dst->anon_vma->degree++; + dst->anon_vma->num_active_vmas++; unlock_anon_vma_root(root); return 0; @@ -354,6 +360,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) anon_vma = anon_vma_alloc(); if (!anon_vma) goto out_error; + anon_vma->num_active_vmas++; avc = anon_vma_chain_alloc(GFP_KERNEL); if (!avc) goto out_error_free_anon_vma; @@ -374,7 +381,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) vma->anon_vma = anon_vma; anon_vma_lock_write(anon_vma); anon_vma_chain_link(vma, avc, anon_vma); - anon_vma->parent->degree++; + anon_vma->parent->num_children++; anon_vma_unlock_write(anon_vma); return 0; @@ -406,15 +413,22 @@ void unlink_anon_vmas(struct vm_area_struct *vma) * to free them outside the lock. */ if (RB_EMPTY_ROOT(&anon_vma->rb_root.rb_root)) { - anon_vma->parent->degree--; + anon_vma->parent->num_children--; continue; } list_del(&avc->same_vma); anon_vma_chain_free(avc); } - if (vma->anon_vma) - vma->anon_vma->degree--; + if (vma->anon_vma) { + vma->anon_vma->num_active_vmas--; + + /* + * vma would still be needed after unlink, and anon_vma will be prepared + * when handle fault. + */ + vma->anon_vma = NULL; + } unlock_anon_vma_root(root); /* @@ -425,7 +439,8 @@ void unlink_anon_vmas(struct vm_area_struct *vma) list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { struct anon_vma *anon_vma = avc->anon_vma; - VM_WARN_ON(anon_vma->degree); + VM_WARN_ON(anon_vma->num_children); + VM_WARN_ON(anon_vma->num_active_vmas); put_anon_vma(anon_vma); list_del(&avc->same_vma); diff --git a/mm/shmem.c b/mm/shmem.c index ae8adca3b56d..b7fe53dd61e9 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* * Resizable virtual memory filesystem for Linux. * @@ -2299,6 +2302,9 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode atomic_set(&info->stop_eviction, 0); info->seals = F_SEAL_SEAL; info->flags = flags & VM_NORESERVE; +#ifdef MY_ABC_HERE + info->crtime = inode->i_mtime; +#endif /* MY_ABC_HERE */ INIT_LIST_HEAD(&info->shrinklist); INIT_LIST_HEAD(&info->swaplist); simple_xattrs_init(&info->xattrs); @@ -3313,11 +3319,64 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) } #endif /* CONFIG_TMPFS_XATTR */ +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +static int shmem_syno_getattr(struct dentry *dentry, struct kstat *kst, unsigned int syno_flags) +{ + struct inode *inode = dentry->d_inode; + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_ARCHIVE_BIT) { + mutex_lock(&inode->i_archive_bit_mutex); + kst->syno_archive_bit = inode->i_archive_bit; + mutex_unlock(&inode->i_archive_bit_mutex); + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE + if (syno_flags & SYNOST_CREATE_TIME) + kst->syno_create_time = SHMEM_I(inode)->crtime; +#endif /* MY_ABC_HERE */ + + return 0; +} +#endif /* MY_ABC_HERE || MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int shmem_syno_get_crtime(struct inode *inode, struct timespec64 *crtime) +{ + *crtime = SHMEM_I(inode)->crtime; + + return 0; +} + +static int shmem_syno_set_crtime(struct inode *inode, struct timespec64 *crtime) +{ + SHMEM_I(inode)->crtime = *crtime; + + return 0; +} +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +static int shmem_syno_set_archive_bit(struct dentry *dentry, u32 archive_bit) +{ + struct inode *inode = dentry->d_inode; + + inode->i_archive_bit = archive_bit; + inode->i_ctime = current_time(inode); + + return 0; +} +#endif /* MY_ABC_HERE */ + static const struct inode_operations shmem_short_symlink_operations = { .get_link = simple_get_link, #ifdef CONFIG_TMPFS_XATTR .listxattr = shmem_listxattr, #endif +#ifdef MY_ABC_HERE + .syno_set_archive_bit = shmem_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ }; static const struct inode_operations shmem_symlink_inode_operations = { @@ -3325,6 +3384,9 @@ static const struct inode_operations shmem_symlink_inode_operations = { #ifdef CONFIG_TMPFS_XATTR .listxattr = shmem_listxattr, #endif +#ifdef MY_ABC_HERE + .syno_set_archive_bit = shmem_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ }; static struct dentry *shmem_get_parent(struct dentry *child) @@ -3895,6 +3957,16 @@ static const struct inode_operations shmem_inode_operations = { .listxattr = shmem_listxattr, .set_acl = simple_set_acl, #endif +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_getattr = shmem_syno_getattr, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime= shmem_syno_get_crtime, + .syno_set_crtime= shmem_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = shmem_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ }; static const struct inode_operations shmem_dir_inode_operations = { @@ -3917,6 +3989,16 @@ static const struct inode_operations shmem_dir_inode_operations = { .setattr = shmem_setattr, .set_acl = simple_set_acl, #endif +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_getattr = shmem_syno_getattr, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime= shmem_syno_get_crtime, + .syno_set_crtime= shmem_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = shmem_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ }; static const struct inode_operations shmem_special_inode_operations = { @@ -3927,6 +4009,16 @@ static const struct inode_operations shmem_special_inode_operations = { .setattr = shmem_setattr, .set_acl = simple_set_acl, #endif +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) + .syno_getattr = shmem_syno_getattr, +#endif /* MY_ABC_HERE || MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_get_crtime= shmem_syno_get_crtime, + .syno_set_crtime= shmem_syno_set_crtime, +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + .syno_set_archive_bit = shmem_syno_set_archive_bit, +#endif /* MY_ABC_HERE */ }; static const struct super_operations shmem_ops = { diff --git a/mm/swapfile.c b/mm/swapfile.c index 5af6b0f770de..48ccbbdc78a6 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/mm/swapfile.c @@ -2573,6 +2576,9 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) struct filename *pathname; int err, found = 0; unsigned int old_block_size; +#ifdef MY_ABC_HERE + extern int gSynoSwapFlag; +#endif /* MY_ABC_HERE */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -2583,6 +2589,15 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(pathname)) return PTR_ERR(pathname); +#ifdef MY_ABC_HERE + if (0 == gSynoSwapFlag) { + printk(KERN_ERR + "*ERROR*, ppid:%d(%s), pid:%d(%s), use swapoff without syno framework!\n", + task_pid_nr(current->parent), current->parent->comm, + task_pid_nr(current), current->comm); + } +#endif /* MY_ABC_HERE */ + victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0); err = PTR_ERR(victim); if (IS_ERR(victim)) @@ -3179,6 +3194,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) struct page *page = NULL; struct inode *inode = NULL; bool inced_nr_rotate_swap = false; +#ifdef MY_ABC_HERE + extern int gSynoSwapFlag; +#endif /* MY_ABC_HERE */ if (swap_flags & ~SWAP_FLAGS_VALID) return -EINVAL; @@ -3189,6 +3207,15 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (!swap_avail_heads) return -ENOMEM; +#ifdef MY_ABC_HERE + if (0 == gSynoSwapFlag) { + printk(KERN_ERR + "*ERROR*, ppid:%d(%s), pid:%d(%s), use swapon without syno framework!\n", + task_pid_nr(current->parent), current->parent->comm, + task_pid_nr(current), current->comm); + } +#endif /* MY_ABC_HERE */ + p = alloc_swap_info(); if (IS_ERR(p)) return PTR_ERR(p); diff --git a/mm/util.c b/mm/util.c index 4ddb6e186dd5..4befe17b6997 100644 --- a/mm/util.c +++ b/mm/util.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only #include #include @@ -957,6 +960,9 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) out: return res; } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL(get_cmdline); +#endif /* MY_ABC_HERE */ int __weak memcmp_pages(struct page *page1, struct page *page2) { diff --git a/mm/vmscan.c b/mm/vmscan.c index 67d38334052e..8dc25caa57e0 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * linux/mm/vmscan.c @@ -152,6 +155,30 @@ struct scan_control { struct reclaim_state reclaim_state; }; +#ifdef MY_ABC_HERE +/* + * Number of active kswapd threads + */ +#define DEF_KSWAPD_THREADS_PER_NODE 1 +int kswapd_threads = DEF_KSWAPD_THREADS_PER_NODE; +int kswapd_threads_current = DEF_KSWAPD_THREADS_PER_NODE; + +static DEFINE_MUTEX(kswapd_threads_mutex); + +static void kswapd_threads_update_begin(void) +{ + /* avoid racing with hotplug initiated updates */ + mem_hotplug_begin(); + /* in case CONFIG_MEMORY_HOTPLUG=n */ + mutex_lock(&kswapd_threads_mutex); +} + +static void kswapd_threads_update_done(void) +{ + mutex_unlock(&kswapd_threads_mutex); + mem_hotplug_done(); +} +#endif /* MY_ABC_HERE */ #ifdef ARCH_HAS_PREFETCHW #define prefetchw_prev_lru_page(_page, _base, _field) \ do { \ @@ -4026,6 +4053,76 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim) } #endif /* CONFIG_HIBERNATION */ +#ifdef MY_ABC_HERE +static void update_kswapd_threads_node(int nid, int threads, + int threads_current) +{ + pg_data_t *pgdat; + int drop, increase; + int last_idx, start_idx, hid; + + pgdat = NODE_DATA(nid); + set_bit(PGDAT_SYNO_UPDATING_KSWAPDS, &pgdat->flags); + last_idx = threads_current - 1; + if (threads < threads_current) { + drop = threads_current - threads; + for (hid = last_idx; hid > (last_idx - drop); hid--) { + if (pgdat->kswapd[hid]) { + kthread_stop(pgdat->kswapd[hid]); + pgdat->kswapd[hid] = NULL; + } + } + } else { + increase = threads - threads_current; + start_idx = last_idx + 1; + for (hid = start_idx; hid < (start_idx + increase); hid++) { + pgdat->kswapd[hid] = kthread_run(kswapd, pgdat, + "kswapd%d:%d", nid, hid); + if (IS_ERR(pgdat->kswapd[hid])) { + pr_err("Failed to start kswapd%d on node %d\n", + hid, nid); + pgdat->kswapd[hid] = NULL; + /* + * We are out of resources. Do not start any + * more threads. + */ + break; + } +#ifdef MY_ABC_HERE + set_user_nice(pgdat->kswapd[hid], MIN_NICE); +#endif /* MY_ABC_HERE */ + } + } + clear_bit(PGDAT_SYNO_UPDATING_KSWAPDS, &pgdat->flags); +} + +void update_kswapd_threads(void) +{ + int nid; + int threads; + int threads_current; + + kswapd_threads_update_begin(); + threads_current = kswapd_threads_current; + threads = kswapd_threads; + + if (threads_current == threads) { + kswapd_threads_update_done(); + return; + } + + for_each_node_state(nid, N_MEMORY) + update_kswapd_threads_node(nid, threads, threads_current); + + pr_info("kswapd_thread count changed, old:%d new:%d\n", + threads_current, threads); + kswapd_threads = threads; + kswapd_threads_current = threads; + kswapd_threads_update_done(); +} + + +#endif /* MY_ABC_HERE */ /* * This kswapd start function will be called by init and node-hot-add. * On node-hot-add, kswapd will moved to proper cpus if cpus are hot-added. @@ -4034,10 +4131,36 @@ int kswapd_run(int nid) { pg_data_t *pgdat = NODE_DATA(nid); int ret = 0; +#ifdef MY_ABC_HERE + int hid, nr_threads; +#endif /* MY_ABC_HERE */ +#ifdef MY_ABC_HERE + if (pgdat->kswapd[0]) +#else /* MY_ABC_HERE */ if (pgdat->kswapd) +#endif /* MY_ABC_HERE */ return 0; +#ifdef MY_ABC_HERE + nr_threads = kswapd_threads; + for (hid = 0; hid < nr_threads; hid++) { + pgdat->kswapd[hid] = kthread_run(kswapd, pgdat, "kswapd%d:%d", + nid, hid); + if (IS_ERR(pgdat->kswapd[hid])) { + /* failure at boot is fatal */ + BUG_ON(system_state == SYSTEM_BOOTING); + pr_err("Failed to start kswapd%d on node %d\n", + hid, nid); + ret = PTR_ERR(pgdat->kswapd[hid]); + pgdat->kswapd[hid] = NULL; + } +#ifdef MY_ABC_HERE + set_user_nice(pgdat->kswapd[hid], MIN_NICE); +#endif /* MY_ABC_HERE */ + } + kswapd_threads_current = nr_threads; +#else /* MY_ABC_HERE */ pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid); if (IS_ERR(pgdat->kswapd)) { /* failure at boot is fatal */ @@ -4046,6 +4169,7 @@ int kswapd_run(int nid) ret = PTR_ERR(pgdat->kswapd); pgdat->kswapd = NULL; } +#endif /* MY_ABC_HERE */ return ret; } @@ -4055,12 +4179,26 @@ int kswapd_run(int nid) */ void kswapd_stop(int nid) { +#ifdef MY_ABC_HERE + struct task_struct *kswapd; + int hid; + int nr_threads = kswapd_threads_current; + + for (hid = 0; hid < nr_threads; hid++) { + kswapd = NODE_DATA(nid)->kswapd[hid]; + if (kswapd) { + kthread_stop(kswapd); + NODE_DATA(nid)->kswapd[hid] = NULL; + } + } +#else /* MY_ABC_HERE */ struct task_struct *kswapd = NODE_DATA(nid)->kswapd; if (kswapd) { kthread_stop(kswapd); NODE_DATA(nid)->kswapd = NULL; } +#endif /* MY_ABC_HERE */ } static int __init kswapd_init(void) diff --git a/net/Kconfig b/net/Kconfig index d6567162c1cf..89c36f52bc7a 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -432,11 +432,16 @@ config NET_SOCK_MSG with the help of BPF programs. config NET_DEVLINK - bool + bool "Enable NET DEVLINK for mlnx-ofed-driver" default n + help + Open this feature for mlnx-ofed-driver config PAGE_POOL - bool + bool "Enable PAGE_POOL for mlnx5_en" + default n + help + Open this feature for mlnx-ofed-driver config FAILOVER tristate "Generic failover module" diff --git a/net/ceph/ceph_hash.c b/net/ceph/ceph_hash.c index 16a47c0eef37..868467bd733e 100644 --- a/net/ceph/ceph_hash.c +++ b/net/ceph/ceph_hash.c @@ -103,6 +103,17 @@ unsigned int ceph_str_hash_linux(const char *str, unsigned int length) return hash; } +#ifdef CONFIG_SYNO_CEPH_CASELESS_STAT +unsigned int ceph_str_upper_hash(int type, const char *s, unsigned int len) +{ + char hash_buf[NAME_MAX+1]; + unsigned int upperlen; + + upperlen = syno_utf8_toupper(hash_buf, s, NAME_MAX, len, NULL); + return ceph_str_hash(type, hash_buf, upperlen); +} +EXPORT_SYMBOL(ceph_str_upper_hash); +#endif /* CONFIG_SYNO_CEPH_CASELESS_STAT */ unsigned int ceph_str_hash(int type, const char *s, unsigned int len) { diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index 7057f8db4f99..169c142e99a0 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -426,6 +426,95 @@ static int is_out(const struct crush_map *map, return 1; } +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +/* Simply duplicate code from bucket_perm_choose to help us randomly permute items + which is selected from original crush_bucket previously.*/ +static int syno_perm_choose(const int *items, size_t size, + int id, int hash_type, + struct crush_work_bucket *work, + int x, int r, int *idx) +{ + unsigned int pr = r % size; + unsigned int i, s; + + /* start a new permutation if @x has changed */ + if (work->perm_x != (__u32)x || work->perm_n == 0) { + dprintk("bucket %d new x=%d\n", id, x); + work->perm_x = x; + + /* optimize common r=0 case */ + if (pr == 0) { + s = crush_hash32_3(hash_type, x, id, 0) % size; + work->perm[0] = s; + work->perm_n = 0xffff; /* magic value, see below */ + goto out; + } + + for (i = 0; i < size; i++) + work->perm[i] = i; + work->perm_n = 0; + } else if (work->perm_n == 0xffff) { + /* clean up after the r=0 case above */ + for (i = 1; i < size; i++) + work->perm[i] = i; + work->perm[work->perm[0]] = 0; + work->perm_n = 1; + } + + /* calculate permutation up to pr */ + for (i = 0; i < work->perm_n; i++) + dprintk("syno_perm_choose have %d: %d\n", i, work->perm[i]); + while (work->perm_n <= pr) { + unsigned int p = work->perm_n; + /* no point in swapping the final entry */ + if (p < size - 1) { + i = crush_hash32_3(hash_type, x, id, p) % + (size - p); + if (i) { + unsigned int t = work->perm[p + i]; + work->perm[p + i] = work->perm[p]; + work->perm[p] = t; + } + dprintk("syno_perm_choose swap %d with %d\n", p, p+i); + } + work->perm_n++; + } + for (i = 0; i < size; i++) + dprintk(" perm_choose %d: %d\n", i, work->perm[i]); + + s = work->perm[pr]; +out: + dprintk("syno_perm_choose %d sz=%d x=%d r=%d (%d) s=%d\n", id, + size, x, r, pr, s); + if (idx) + *idx = s; + return items[s]; +} + +static void shuffle_by_pg(const struct crush_bucket *in, + struct crush_work_bucket *work, + int x, int *items, int *items_2, int len) +{ + int i; + int new; + int new_idx; + int new_items[16]; + int new_items_2[16]; + + dprintk("RANDOM SHFULLE STARTS with bucket [%d]\n", in->id); + work->perm_n = 0; // start a new permutation + for (i = 0; i < len; i++) { + new = syno_perm_choose(items, len, in->id, in->hash, work, x, i, &new_idx); + new_items[i] = new; + new_items_2[i] = items_2[new_idx]; + dprintk("new_item[%d] got %d, new_item_2[%d] got %d\n", i, new_items[i], i, new_items_2[i]); + } + + memcpy(items, new_items, len*sizeof(int)); + memcpy(items_2, new_items_2, len*sizeof(int)); +} +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + /** * crush_choose_firstn - choose numrep distinct items of given type * @map: the crush_map @@ -462,7 +551,13 @@ static int crush_choose_firstn(const struct crush_map *map, unsigned int stable, int *out2, int parent_r, - const struct crush_choose_arg *choose_args) + const struct crush_choose_arg *choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + int *syno_choose_primary +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ) + { int rep; unsigned int ftotal, flocal; @@ -503,6 +598,14 @@ static int crush_choose_firstn(const struct crush_map *map, reject = 1; goto reject; } +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + /* we forcely assign first selected item to achieve data locality */ + if ((syno_choose_primary && rep == 0) && + (type == map->buckets[-1-*syno_choose_primary]->type)) { + dprintk(" choose primary item [%d]\n ", *syno_choose_primary); + item = *syno_choose_primary; + } else +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ if (local_fallback_retries > 0 && flocal >= (in->size>>1) && flocal > local_fallback_retries) @@ -573,9 +676,25 @@ static int crush_choose_firstn(const struct crush_map *map, stable, NULL, sub_r, +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + choose_args, NULL) <= outpos) { + + /* There's no selected osd under syno_choose_primary, + * just abandon it on the next iteration + * Such that the primary osd of this pg could be + * automatically recovered while syno_choose_primary + * has been down. + */ + if (syno_choose_primary && rep == 0) + syno_choose_primary = NULL; + + reject = 1; + } +#else choose_args) <= outpos) /* didn't get leaf */ reject = 1; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ } else { /* we already have a leaf! */ out2[outpos] = item; @@ -651,7 +770,13 @@ static void crush_choose_indep(const struct crush_map *map, int recurse_to_leaf, int *out2, int parent_r, - const struct crush_choose_arg *choose_args) + const struct crush_choose_arg *choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + int *syno_choose_primary +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ) + { const struct crush_bucket *in = bucket; int endpos = outpos + left; @@ -720,7 +845,14 @@ static void crush_choose_indep(const struct crush_map *map, dprintk(" empty bucket\n"); break; } - +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + /* we forcely assign first selected item to achieve data locality */ + if ((syno_choose_primary && rep == outpos) && + (type == map->buckets[-1-*syno_choose_primary]->type)) { + dprintk(" choose primary item [%d]\n ", *syno_choose_primary); + item = *syno_choose_primary; + } else +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ item = crush_bucket_choose( in, work->work[-1-in->id], x, r, @@ -781,9 +913,25 @@ static void crush_choose_indep(const struct crush_map *map, out2, rep, recurse_tries, 0, 0, NULL, r, - choose_args); + choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + NULL +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ); + if (out2[rep] == CRUSH_ITEM_NONE) { /* placed nothing; no leaf */ +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + /* There's no selected osd under syno_choose_primary, + * just abandon it on the next iteration + * Such that the primary osd of this pg could be + * automatically recovered while syno_choose_primary + * has been down. + */ + if (syno_choose_primary && rep == outpos) + syno_choose_primary = NULL; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ break; } } else { @@ -832,6 +980,445 @@ static void crush_choose_indep(const struct crush_map *map, #endif } +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +/** + * crush_syno_choose_hg: Choose Syno-Crush Host Group + * + * Most of the logic is the duplicate of crush_choose_indep. + */ +static void crush_syno_choose_hg(const struct crush_map *map, + struct crush_work *work, + const struct crush_bucket *bucket, + const __u32 *weight, int weight_max, + int x, int left, int numrep, int type, + int *out, int outpos, + unsigned int tries, + unsigned int recurse_tries, + int recurse_to_leaf, + int *out2, + const struct crush_choose_arg *choose_args, + int x2, + int *syno_choose_primary) + +{ + const struct crush_bucket *in = bucket; + int endpos = outpos + left; + int rep; + unsigned int ftotal; + int r; + int i; + int item = 0; + int itemtype; + int collide; + int hg_size = left; + int undef_count = left; + int leaf_fail_size = 0; + int leaf_fail_buckets[32]; + int is_locality_rule = !!syno_choose_primary; + int handle_stage_3 = 0; + + dprintk("CHOOSE%s INDEP bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "", + bucket->id, x, outpos, numrep); + + /* initially my result is undefined */ + for (rep = outpos; rep < endpos; rep++) { + out[rep] = CRUSH_ITEM_UNDEF; + if (out2) + out2[rep] = CRUSH_ITEM_UNDEF; + } + + for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) { +#ifdef DEBUG_INDEP + if (out2 && ftotal) { + dprintk("%u %d a: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out[rep]); + } + dprintk("\n"); + dprintk("%u %d b: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out2[rep]); + } + dprintk("\n"); + } +#endif + for (rep = outpos; rep < endpos; rep++) { + /* + * The choose process is divide into three stages: + * + * 1st stage: Choose item for undefined positition + * If item choosen is collided, leave the posititon undefined. + * If item choosen can't get a valid leaf, make this position as leaf failed. + * + * 2nd stage: Choose item for collided(undefined) positition + * Handle the collided position fisrt, leave the leaf failed posititon empty. + * + * 3rd stage: Choose item for leaf failed positition + * At last, handle the leaf failed posititon to see if we can find a replacement. + */ + handle_stage_3 = !!(undef_count <= 0); + if (!handle_stage_3) { + if (out[rep] != CRUSH_ITEM_UNDEF) + continue; + } else { + if (out[rep] != CRUSH_ITEM_LEAF_FAIL) + continue; + } + + in = bucket; /* initial bucket */ + /* choose through intervening buckets */ + for (;;) { + /* note: we base the choice on the position + * even in the nested call. that means that + * if the first layer chooses the same bucket + * in a different position, we will tend to + * choose a different item in that bucket. + * this will involve more devices in data + * movement and tend to distribute the load. + */ + r = rep; + + /* be careful */ + if (in->alg == CRUSH_BUCKET_UNIFORM && + in->size % numrep == 0) + /* r'=r+(n+1)*f_total */ + r += (numrep+1) * ftotal; + else + /* r' = r + hg_size * f_total */ + r += hg_size * ftotal; + + /* bucket choose */ + if (in->size == 0) { + dprintk(" empty bucket\n"); + break; + } + + /* we forcely assign first selected item to achieve data locality */ + if ((syno_choose_primary && rep == outpos) && + (type == map->buckets[-1 - *syno_choose_primary]->type)) { + if (in->size == 0) { + dprintk(" empty bucket\n"); + break; + } + dprintk(" choose primary item [%d]\n ", *syno_choose_primary); + item = *syno_choose_primary; + } else { + item = crush_bucket_choose( + in, work->work[-1-in->id], + x2, r, + (choose_args ? &choose_args[-1-in->id] : 0), + outpos); + } + + if (item >= map->max_devices) { + dprintk(" bad item %d\n", item); + out[rep] = CRUSH_ITEM_NONE; + if (out2) + out2[rep] = CRUSH_ITEM_NONE; + left--; + break; + } + + /* desired type? */ + if (item < 0) + itemtype = map->buckets[-1-item]->type; + else + itemtype = 0; + dprintk(" item %d type %d\n", item, itemtype); + + /* keep going? */ + if (itemtype != type) { + if (item >= 0 || + (-1-item) >= map->max_buckets) { + dprintk(" bad item type %d\n", type); + out[rep] = CRUSH_ITEM_NONE; + if (out2) + out2[rep] = + CRUSH_ITEM_NONE; + left--; + break; + } + in = map->buckets[-1-item]; + continue; + } + + /* collision? */ + collide = 0; + for (i = outpos; i < endpos; i++) { + if (out[i] == item) { + collide = 1; + break; + } + } + + if (!handle_stage_3) { + for (i = 0; i < leaf_fail_size; i++) { + /* + * If this item is normal, it should be selected already. + * However, it's failed now. To avoid this item effect + * current position, we treat it as collision. + */ + if (leaf_fail_buckets[i] == item) { + collide = 1; + break; + } + } + } + + if (collide) + break; + + if (recurse_to_leaf) { + if (item < 0) { + crush_choose_indep( + map, + work, + map->buckets[-1-item], + weight, weight_max, + x, 1, numrep, 0, + out2, rep, + recurse_tries, 0, + 0, NULL, r, choose_args, NULL); + + if (out2 && out2[rep] == CRUSH_ITEM_NONE) { + /* There's no selected osd under syno_choose_primary, + * just abandon it on the next iteration + * Such that the primary osd of this pg could be + * automatically recovered while syno_choose_primary + * has been down. + */ + if (syno_choose_primary && rep == outpos) + syno_choose_primary = NULL; + + if (!handle_stage_3) { + /* + * Otherwise, already know this postition has leaf fail + */ + if (out[rep] != CRUSH_ITEM_LEAF_FAIL) + undef_count--; + leaf_fail_buckets[leaf_fail_size] = item; + leaf_fail_size++; + out[rep] = CRUSH_ITEM_LEAF_FAIL; + } + + /* placed nothing; no leaf */ + break; + } + } else if (out2) { + /* we already have a leaf! */ + out2[rep] = item; + } + } + + /* out? */ + if (itemtype == 0 && + is_out(map, weight, weight_max, item, x)) + break; + + /* yay! */ + if (!handle_stage_3) { + // If start handling leaf failed positition, the undef_count is 0. + undef_count--; + } + + out[rep] = item; + left--; + break; + } + } + } + + for (rep = outpos; rep < endpos; rep++) { + if (out[rep] == CRUSH_ITEM_UNDEF || out[rep] == CRUSH_ITEM_LEAF_FAIL) { + out[rep] = CRUSH_ITEM_NONE; + } + if (out2 && (out2[rep] == CRUSH_ITEM_UNDEF || out2[rep] == CRUSH_ITEM_LEAF_FAIL)) { + out2[rep] = CRUSH_ITEM_NONE; + } + } +#ifndef __KERNEL__ + if (map->choose_tries && ftotal <= map->choose_total_tries) + map->choose_tries[ftotal]++; +#endif + { + int *t1 = is_locality_rule ? out+outpos+1 : out+outpos; + int *t2 = is_locality_rule ? out2+outpos+1 : out2+outpos; + int len = is_locality_rule ? endpos-outpos-1 : endpos-outpos; + shuffle_by_pg(in, work->work[-1-in->id], x, t1, t2, len); + } +#ifdef DEBUG_INDEP + if (out2) { + dprintk("%u %d a: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out[rep]); + } + dprintk("\n"); + dprintk("%u %d b: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out2[rep]); + } + dprintk("\n"); + } +#endif +} + +static int crush_syno_choose_firstn(const struct crush_map *map, + struct crush_work *work, + const struct crush_bucket *bucket, + const __u32 *weight, int weight_max, + int x, int hg_size, int type, + int *out, int outpos, + int out_size, + unsigned int tries, + unsigned int recurse_tries, + int recurse_to_leaf, + int *out2, + const struct crush_choose_arg *choose_args, + int x2, + int *syno_choose_primary) +{ + int i = 0; + int hg_idx = 0; + int size = hg_size < out_size ? out_size : hg_size; + int endpos = outpos + out_size; + int hg_out[32]; + int hg_out_2[32]; + + /* step 1 : choose items of out_size first */ + crush_syno_choose_hg(map, work, bucket, weight, weight_max, + x, size, out_size, + type, + hg_out, + 0, // outpos, start from 0 for hg_out + tries, recurse_tries, + recurse_to_leaf, + hg_out_2, + choose_args, + x2, syno_choose_primary); + + /* + * Fill out and out2 from hg_out + * As the behavior of firstn, we fill out with non-empty item in hg sequentially. + */ + for (i = outpos; i < endpos; i++) { + while(hg_idx < size && hg_out[hg_idx] == CRUSH_ITEM_NONE) { + hg_idx++; + } + if (hg_idx < size) { + out[i] = hg_out[hg_idx]; + out2[i] = hg_out_2[hg_idx]; + hg_idx++; + } else { + break; + } + } + return i - outpos; +} + +static void crush_syno_choose_indep(const struct crush_map *map, + struct crush_work *work, + const struct crush_bucket *bucket, + const __u32 *weight, int weight_max, + int x, int rep_size, int hg_size, int type, + int *out, int outpos, + unsigned int tries, + unsigned int recurse_tries, + int recurse_to_leaf, + int *out2, + const struct crush_choose_arg *choose_args, + int x2, + int *syno_choose_primary) +{ + int i = 0; + int size = hg_size < rep_size ? rep_size : hg_size; + int endpos = outpos + rep_size; + int hg_idx = 0; + int hg_tail = size - 1; + int hg_out[32]; + int hg_out_2[32]; + + /* step 1 : choose items of rep_size first */ + crush_syno_choose_hg(map, work, bucket, weight, weight_max, + x, size, rep_size, + type, + hg_out, + 0, // outpos, start from 0 for hg_out + tries, recurse_tries, + recurse_to_leaf, + hg_out_2, + choose_args, + x2, syno_choose_primary); + + while (hg_tail >= rep_size) { + if (hg_out[hg_tail] != CRUSH_ITEM_NONE) { + break; + } + hg_tail--; + } + + /* + * Fill out and out2 from hg_out + * As the behavior of indep, we replce the empty item from behind and keep + * other posititon unchanged. + */ + for (i = outpos, hg_idx = 0; i < endpos; i++, hg_idx++) { + if ((hg_out[hg_idx] == CRUSH_ITEM_NONE) && hg_tail >= rep_size) { + out[i] = hg_out[hg_tail]; + out2[i] = hg_out_2[hg_tail]; + hg_tail--; + while(hg_tail >= rep_size) { + if (hg_out[hg_tail] != CRUSH_ITEM_NONE) { + break; + } + hg_tail--; + } + } else { + out[i] = hg_out[hg_idx]; + out2[i] = hg_out_2[hg_idx]; + } + } +} + +static int syno_enum(const struct crush_map *map, + const struct crush_bucket *bucket, + const __u32 *weight, int weight_max, + int x, int type, + int *out, int out_size) +{ + const struct crush_bucket *in = bucket; + int count = out_size; + int i; + int outpos = 0; + int item = 0; + int itemtype; + + dprintk("SYNO_ENUM bucket%d size %d count %d x %d \n", + bucket->id, in->size, count, x); + + for (i = 0; i < in->size && count > 0; i++) { + item = in->items[i]; + if (item < 0) + itemtype = map->buckets[-1-item]->type; + else + itemtype = 0; + dprintk(" item %d type %d\n", item, itemtype); + if (itemtype != type) + continue; + if (itemtype == 0 && + is_out(map, weight, weight_max, item, x)) { + dprintk(" reject item %d type %d for %d\n", item, itemtype, type); + continue; + } + dprintk("SYNO_ENUM got %d\n", item); + out[outpos] = item; + outpos++; + count--; + } + + dprintk("SYNO_ENUM returns %d\n", outpos); + return outpos; +} +#endif /* SYNO_CEPH_CUSTOMIZED_CRUSH */ /* * This takes a chunk of memory and sets it up to be a shiny new @@ -894,7 +1481,12 @@ void crush_init_workspace(const struct crush_map *map, void *v) int crush_do_rule(const struct crush_map *map, int ruleno, int x, int *result, int result_max, const __u32 *weight, int weight_max, - void *cwin, const struct crush_choose_arg *choose_args) + void *cwin, const struct crush_choose_arg *choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + int pool_ps +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ) { int result_len; struct crush_work *cw = cwin; @@ -927,6 +1519,9 @@ int crush_do_rule(const struct crush_map *map, int vary_r = map->chooseleaf_vary_r; int stable = map->chooseleaf_stable; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + int *syno_choose_primary = NULL; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ if ((__u32)ruleno >= map->max_rules) { dprintk(" bad ruleno %d\n", ruleno); @@ -938,6 +1533,9 @@ int crush_do_rule(const struct crush_map *map, for (step = 0; step < rule->len; step++) { int firstn = 0; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + int syno_choose = 0; +#endif const struct crush_rule_step *curstep = &rule->steps[step]; switch (curstep->op) { @@ -984,12 +1582,37 @@ int crush_do_rule(const struct crush_map *map, stable = curstep->arg1; break; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + case CRUSH_RULE_SET_SYNO_CHOOSE_PRIMARY: + if ((curstep->arg1 >= 0 && + curstep->arg1 < map->max_devices) || + (-1 - curstep->arg1 >= 0 && + -1 - curstep->arg1 < map->max_buckets && + map->buckets[-1 - curstep->arg1])) { + syno_choose_primary = (int*)&curstep->arg1; + } else { + dprintk(" bad value %d\n", curstep->arg1); + } + break; + + case CRUSH_RULE_SYNO_CHOOSE_FIRSTN: + case CRUSH_RULE_SYNO_CHOOSELEAF_FIRSTN: +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ case CRUSH_RULE_CHOOSELEAF_FIRSTN: case CRUSH_RULE_CHOOSE_FIRSTN: firstn = 1; fallthrough; case CRUSH_RULE_CHOOSELEAF_INDEP: case CRUSH_RULE_CHOOSE_INDEP: +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + case CRUSH_RULE_SYNO_CHOOSE_INDEP: + case CRUSH_RULE_SYNO_CHOOSELEAF_INDEP: + syno_choose = + curstep->op == CRUSH_RULE_SYNO_CHOOSE_FIRSTN || + curstep->op == CRUSH_RULE_SYNO_CHOOSELEAF_FIRSTN || + curstep->op == CRUSH_RULE_SYNO_CHOOSE_INDEP || + curstep->op == CRUSH_RULE_SYNO_CHOOSELEAF_INDEP; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ if (wsize == 0) break; @@ -998,7 +1621,13 @@ int crush_do_rule(const struct crush_map *map, CRUSH_RULE_CHOOSELEAF_FIRSTN || curstep->op == CRUSH_RULE_CHOOSELEAF_INDEP; - +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + recurse_to_leaf |= + curstep->op == + CRUSH_RULE_SYNO_CHOOSELEAF_FIRSTN || + curstep->op == + CRUSH_RULE_SYNO_CHOOSELEAF_INDEP; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ /* reset output */ osize = 0; @@ -1027,6 +1656,9 @@ int crush_do_rule(const struct crush_map *map, recurse_tries = 1; else recurse_tries = choose_tries; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + if (!syno_choose) +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ osize += crush_choose_firstn( map, cw, @@ -1045,10 +1677,37 @@ int crush_do_rule(const struct crush_map *map, stable, c+osize, 0, - choose_args); + choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + syno_choose_primary +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + else + osize += crush_syno_choose_firstn( + map, + cw, + map->buckets[bno], + weight, weight_max, + x, numrep, + curstep->arg2, + o+osize, j, + result_max-osize, + choose_tries, + recurse_tries, + recurse_to_leaf, + c+osize, + choose_args, + pool_ps, + syno_choose_primary); +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ } else { out_size = ((numrep < (result_max-osize)) ? numrep : (result_max-osize)); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + if (!syno_choose) +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ crush_choose_indep( map, cw, @@ -1063,7 +1722,32 @@ int crush_do_rule(const struct crush_map *map, recurse_to_leaf, c+osize, 0, - choose_args); + choose_args +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , + syno_choose_primary +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ); + +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + else + crush_syno_choose_indep( + map, + cw, + map->buckets[bno], + weight, weight_max, + x, out_size, numrep, + curstep->arg2, + o+osize, j, + choose_tries, + choose_leaf_tries ? + choose_leaf_tries : 1, + recurse_to_leaf, + c+osize, + choose_args, + pool_ps, + syno_choose_primary); +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ osize += out_size; } } @@ -1078,7 +1762,32 @@ int crush_do_rule(const struct crush_map *map, w = tmp; wsize = osize; break; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + case CRUSH_RULE_SYNO_ENUM: + osize = 0; + for (i = 0; i < wsize; i++) { + /* make sure bucket id is valid */ + int bno = -1 - w[i]; + if (bno < 0 || bno >= map->max_buckets) { + // w[i] is probably CRUSH_ITEM_NONE + dprintk(" bad w[i] %d\n", w[i]); + continue; + } + osize += syno_enum(map, + map->buckets[bno], + weight, weight_max, + x, curstep->arg1, + o+osize, + result_max-osize); + } + /* swap o and w arrays */ + tmp = o; + o = w; + w = tmp; + wsize = osize; + break; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ case CRUSH_RULE_EMIT: for (i = 0; i < wsize && result_len < result_max; i++) { diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 2110439f8a24..3e32e920607d 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -12,6 +12,10 @@ #include #include #include +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +#include +#include +#endif #ifdef CONFIG_DEBUG_FS @@ -388,11 +392,80 @@ static int client_options_show(struct seq_file *s, void *p) return 0; } +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +static int pool_pg_show(struct seq_file *s, void *p) +{ + int i = 0; + struct ceph_client *client = s->private; + struct ceph_osd_client *osdc = &client->osdc; + struct ceph_osdmap *map = osdc->osdmap; + struct rb_node *n; + + down_read(&osdc->lock); + for (n = rb_first(&map->pg_pools); n; n = rb_next(n)) { + struct ceph_pg_pool_info *pi = + rb_entry(n, struct ceph_pg_pool_info, node); + u32 pool_ps; + int ruleno; + + // dup code from ceph_pg_to_up_acting_osds + pool_ps = (pi->flags & CEPH_POOL_FLAG_HASHPSPOOL) ? + crush_hash32(CRUSH_HASH_DEFAULT, pi->placement_seed): + pi->placement_seed; + + ruleno = crush_find_rule(map->crush, pi->crush_ruleset, pi->type, + pi->size); + if (ruleno < 0) { + pr_err("no crush rule: pool %lld ruleset %d type %d size %d\n", + pi->id, pi->crush_ruleset, pi->type, pi->size); + continue; + } + + seq_printf(s, "%s, ps %d\n", pi->name, pi->placement_seed); + for (i = 0; i < pi->pg_num; i++) { + int j = 0; + int x = 0; + int len = 0; + int result[CEPH_PG_MAX_SIZE]; + + // dup code from raw_pg_to_pps + x = crush_hash32_2(CRUSH_HASH_DEFAULT, i, pi->id); + len = do_crush(map, ruleno, x, result, pi->size, + map->osd_weight, map->max_osd, pi->id, pool_ps); + if (len < 0) { + pr_err("error %d from crush rule %d: pool %lld ruleset %d type %d size %d\n", + len, ruleno, pi->id, pi->crush_ruleset, pi->type, + pi->size); + break; + } + + seq_printf(s, "\t pg %3d = [", i); + for (j = 0; j < len; j++) { + if (j != 0) + seq_printf(s, ","); + + if (result[j] == CRUSH_ITEM_NONE) + seq_printf(s, "NONE"); + else + seq_printf(s, "%d", result[j]); + } + seq_printf(s, "]\n"); + } + } + + up_read(&osdc->lock); + return 0; +} +#endif + DEFINE_SHOW_ATTRIBUTE(monmap); DEFINE_SHOW_ATTRIBUTE(osdmap); DEFINE_SHOW_ATTRIBUTE(monc); DEFINE_SHOW_ATTRIBUTE(osdc); DEFINE_SHOW_ATTRIBUTE(client_options); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +DEFINE_SHOW_ATTRIBUTE(pool_pg); +#endif void __init ceph_debugfs_init(void) { @@ -444,11 +517,21 @@ void ceph_debugfs_client_init(struct ceph_client *client) client->debugfs_dir, client, &client_options_fops); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + client->debugfs_pool_pg = debugfs_create_file("pool_pg", + 0400, + client->debugfs_dir, + client, + &pool_pg_fops); +#endif } void ceph_debugfs_client_cleanup(struct ceph_client *client) { dout("ceph_debugfs_client_cleanup %p\n", client); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + debugfs_remove(client->debugfs_pool_pg); +#endif debugfs_remove(client->debugfs_options); debugfs_remove(client->debugfs_osdmap); debugfs_remove(client->debugfs_monmap); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index af0f1fa24937..9141da372d06 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1307,16 +1307,28 @@ static void prepare_write_message(struct ceph_connection *con) m->middle->vec.iov_base); /* fill in hdr crc and finalize hdr */ +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + crc = 0; +#else crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ con->out_msg->hdr.crc = cpu_to_le32(crc); memcpy(&con->out_hdr, &con->out_msg->hdr, sizeof(con->out_hdr)); /* fill in front and middle crc, footer */ +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + crc = 0; +#else crc = crc32c(0, m->front.iov_base, m->front.iov_len); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ con->out_msg->footer.front_crc = cpu_to_le32(crc); if (m->middle) { +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + crc = 0; +#else crc = crc32c(0, m->middle->vec.iov_base, m->middle->vec.iov_len); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ con->out_msg->footer.middle_crc = cpu_to_le32(crc); } else con->out_msg->footer.middle_crc = 0; @@ -1537,7 +1549,11 @@ static u32 ceph_crc32c_page(u32 crc, struct page *page, kaddr = kmap(page); BUG_ON(kaddr == NULL); +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + crc = 0; +#else crc = crc32c(crc, kaddr + page_offset, length); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ kunmap(page); return crc; @@ -2302,7 +2318,11 @@ static int read_partial_message_section(struct ceph_connection *con, section->iov_len += ret; } if (section->iov_len == sec_len) +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + *crc = 0; +#else *crc = crc32c(0, section->iov_base, section->iov_len); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ return 1; } @@ -2374,7 +2394,11 @@ static int read_partial_message(struct ceph_connection *con) if (ret <= 0) return ret; +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + crc = 0; +#else crc = crc32c(0, &con->in_hdr, offsetof(struct ceph_msg_header, crc)); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ if (cpu_to_le32(crc) != con->in_hdr.crc) { pr_err("read_partial_message bad hdr crc %u != expected %u\n", crc, con->in_hdr.crc); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index c4cf2529d08b..678708f68885 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -1388,6 +1388,10 @@ static void mon_fault(struct ceph_connection *con) } else { dout("%s already hunting\n", __func__); } +#ifdef CONFIG_SYNO_CEPH_SKIP_CRC + pr_err("%s: syno: mon%d fault, try `ms_crc_header = false' on server side\n", + __func__, monc->cur_mon); +#endif /* CONFIG_SYNO_CEPH_SKIP_CRC */ } mutex_unlock(&monc->mutex); } diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index fa08c15be0c0..38c865bb9f79 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -798,7 +798,12 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) pi->pg_num = ceph_decode_32(p); pi->pgp_num = ceph_decode_32(p); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + pi->placement_seed = ceph_decode_16(p); + *p += 2 + 4; /* skip padding and lpgp_num */ +#else *p += 4 + 4; /* skip lpg* */ +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ *p += 4; /* skip last_change */ *p += 8 + 4; /* skip snap_seq, snap_epoch */ @@ -1263,7 +1268,11 @@ static int osdmap_set_crush(struct ceph_osdmap *map, struct crush_map *crush) return 0; } +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +#define OSDMAP_WRAPPER_COMPAT_VER 128 +#else #define OSDMAP_WRAPPER_COMPAT_VER 7 +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ #define OSDMAP_CLIENT_DATA_COMPAT_VER 1 /* @@ -2452,10 +2461,18 @@ static u32 raw_pg_to_pps(struct ceph_pg_pool_info *pi, */ #define CEPH_DEFAULT_CHOOSE_ARGS -1 +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH +int do_crush(struct ceph_osdmap *map, int ruleno, int x, +#else static int do_crush(struct ceph_osdmap *map, int ruleno, int x, +#endif int *result, int result_max, const __u32 *weight, int weight_max, - s64 choose_args_index) + s64 choose_args_index +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , int pool_ps +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ) { struct crush_choose_arg_map *arg_map; struct crush_work *work; @@ -2472,7 +2489,11 @@ static int do_crush(struct ceph_osdmap *map, int ruleno, int x, work = get_workspace(&map->crush_wsm, map->crush); r = crush_do_rule(map->crush, ruleno, x, result, result_max, weight, weight_max, work, - arg_map ? arg_map->args : NULL); + arg_map ? arg_map->args : NULL +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , pool_ps +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ); put_workspace(&map->crush_wsm, work); return r; } @@ -2515,7 +2536,11 @@ static void pg_to_raw_osds(struct ceph_osdmap *osdmap, struct ceph_pg_pool_info *pi, const struct ceph_pg *raw_pgid, struct ceph_osds *raw, - u32 *ppps) + u32 *ppps +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , u32 pool_ps +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ) { u32 pps = raw_pg_to_pps(pi, raw_pgid); int ruleno; @@ -2541,7 +2566,11 @@ static void pg_to_raw_osds(struct ceph_osdmap *osdmap, } len = do_crush(osdmap, ruleno, pps, raw->osds, pi->size, - osdmap->osd_weight, osdmap->max_osd, pi->id); + osdmap->osd_weight, osdmap->max_osd, pi->id +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + , pool_ps +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ + ); if (len < 0) { pr_err("error %d from crush rule %d: pool %lld ruleset %d type %d size %d\n", len, ruleno, pi->id, pi->crush_ruleset, pi->type, @@ -2786,11 +2815,21 @@ void ceph_pg_to_up_acting_osds(struct ceph_osdmap *osdmap, { struct ceph_pg pgid; u32 pps; +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + u32 pool_ps; +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ WARN_ON(pi->id != raw_pgid->pool); raw_pg_to_pg(pi, raw_pgid, &pgid); +#ifdef CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH + pool_ps = (pi->flags & CEPH_POOL_FLAG_HASHPSPOOL) ? + crush_hash32(CRUSH_HASH_RJENKINS1, pi->placement_seed) : pi->placement_seed; + + pg_to_raw_osds(osdmap, pi, raw_pgid, up, &pps, pool_ps); +#else pg_to_raw_osds(osdmap, pi, raw_pgid, up, &pps); +#endif /* CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH */ apply_upmap(osdmap, &pgid, up); raw_to_up_osds(osdmap, pi, up); apply_primary_affinity(osdmap, pi, pps, up); diff --git a/net/core/dev.c b/net/core/dev.c index b9d19fbb1589..8a435911f54e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * NET3 Protocol independent device support routines. @@ -146,6 +149,9 @@ #include #include #include +#if defined(MY_ABC_HERE) +#include +#endif /* MY_ABC_HERE */ #include "net-sysfs.h" @@ -167,6 +173,167 @@ static int call_netdevice_notifiers_extack(unsigned long val, struct net_device *dev, struct netlink_ext_ack *extack); static struct napi_struct *napi_by_id(unsigned int napi_id); +#ifdef MY_ABC_HERE +static unsigned int str_to_hex(char ch) +{ + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + + return 0; +} + +void convert_str_to_mac(char *source , char *dest) +{ + dest[0] = (str_to_hex(source[0]) << 4) + str_to_hex(source[1]); + dest[1] = (str_to_hex(source[2]) << 4) + str_to_hex(source[3]); + dest[2] = (str_to_hex(source[4]) << 4) + str_to_hex(source[5]); + dest[3] = (str_to_hex(source[6]) << 4) + str_to_hex(source[7]); + dest[4] = (str_to_hex(source[8]) << 4) + str_to_hex(source[9]); + dest[5] = (str_to_hex(source[10]) << 4) + str_to_hex(source[11]); +} + +/** + * Check if the target interface should not use vender mac when bonding + * + * eg. RC18015xs+ has a special heartbeat interface mon.hb0 (using the 5th vender mac) + * but an external NIC on RC18015xs+ with interface eth4 should not use 5th + * vender mac when bonding, a grub parameter skip_bond_vender_mac_interfaces is + * used to skip these interfaces + * eg. skip_bond_vender_mac_interfaces=4,5,6,7 means eth4,5,6,7 will be skipped + * using vender mac when bonding + * + * return 1 if need to skip this interface + * 0 if not + * -1 if error + */ +static int syno_skip_bond_vender_mac(int iMacIndex) +{ + extern const char gszSkipVenderMacInterfaces[256]; + char szDupIfns[256] = {'\0'}; + char *token = NULL; + char *ptr = NULL; + long iSkipIndex = 0; + int iMatch = 0; + + if (0 == strlen(gszSkipVenderMacInterfaces)) { + goto END; + } + + snprintf(szDupIfns, sizeof(szDupIfns), "%s", gszSkipVenderMacInterfaces); + ptr = szDupIfns; + // eg. szDupIfns="4,5,6,7" + while (NULL != (token = strsep(&ptr, ","))) { + if (0 != kstrtol(token, 10, &iSkipIndex)) { + // something error + iMatch = -1; + goto END; + } + if ((long)iMacIndex == iSkipIndex) { + iMatch = 1; + goto END; + } + if (!ptr) { + break; + } + } + +END: + return iMatch; +} + +#ifdef MY_ABC_HERE +static bool syno_internal_eth_check(int ethIndex) +{ + extern long g_internal_netif_num; + long netif_num = g_internal_netif_num; + bool ret = false; + + if (0 > ethIndex) { + goto END; + } + + if (dev_get_by_name(&init_net, "eth99")) { + if (99 == ethIndex) { + ret = true; + goto END; + } + netif_num--; + } + if (netif_num > ethIndex) { + ret = true; + } + +END: + return ret; +} +#endif /* MY_ABC_HERE */ + +#define SYNO_VENDOR_MAC_SUCCESS 0 +#define SYNO_VENDOR_MAC_EMPTY 1 +#define SYNO_VENDOR_MAC_FAIL 2 +int syno_get_dev_vendor_mac(const char *szDev, char *szMac, int bufSize) +{ + extern unsigned char grgbLanMac[SYNO_MAC_MAX_NUMBER][16]; + int err = SYNO_VENDOR_MAC_FAIL; + char szIFPrefix[IFNAMSIZ] = "eth"; + int iMacIndex = 0; + const char *pMacIndex = NULL; + int iMatch = 0; + struct net_device *dev; + + if (!szMac || !szDev) + goto ERR; + + // According to function __dev_get_by_name + // we can use strncmp & IFNAMSIZ to replace memcmp to avoid #48870 + if (!strncmp(szDev, szIFPrefix, strlen(szIFPrefix))) { + pMacIndex = szDev + strlen(szIFPrefix); + iMacIndex = simple_strtol(pMacIndex, NULL, 10); +#ifdef MY_ABC_HERE + if (!syno_internal_eth_check(iMacIndex)) { + err = SYNO_VENDOR_MAC_FAIL; + goto ERR; + } +#endif /* MY_ABC_HERE */ + if (1 == (iMatch = syno_skip_bond_vender_mac(iMacIndex))) { + err = SYNO_VENDOR_MAC_EMPTY; + goto ERR; + } else if (-1 == iMatch) { + printk(KERN_ERR "Error when match bond vender mac\n"); + err = SYNO_VENDOR_MAC_FAIL; + goto ERR; + } + + if (99 == iMacIndex) { + if (NULL == (dev = dev_get_by_name(&init_net, "eth99")) || + bufSize < dev->addr_len) { + err = SYNO_VENDOR_MAC_FAIL; + goto ERR; + } + memcpy(szMac, dev->perm_addr, dev->addr_len); + } else { + if (!strcmp(grgbLanMac[iMacIndex], "")) { + err = SYNO_VENDOR_MAC_EMPTY; + goto ERR; + } + convert_str_to_mac(grgbLanMac[iMacIndex], szMac); + } + } else { + goto ERR; + } + + err = SYNO_VENDOR_MAC_SUCCESS; +ERR: + return err; +} +EXPORT_SYMBOL(syno_get_dev_vendor_mac); +#endif /* MY_ABC_HERE */ /* * The @dev_base_head list is protected by @dev_base_lock and the rtnl @@ -10448,7 +10615,11 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, } else { netdev_stats_to_stats64(storage, &dev->stats); } +#if defined(MY_ABC_HERE) + /* skip the rx_drop from kernel core, only count rx_drop by device driver */ +#else /* MY_ABC_HERE */ storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped); +#endif /* MY_ABC_HERE */ storage->tx_dropped += (unsigned long)atomic_long_read(&dev->tx_dropped); storage->rx_nohandler += (unsigned long)atomic_long_read(&dev->rx_nohandler); return storage; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b4562f9d074c..80b57419c97d 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * net-sysfs.c - network device class and attributes @@ -23,6 +26,11 @@ #include #include #include +#ifdef MY_ABC_HERE +#include +#include +#include +#endif /* MY_ABC_HERE */ #include "net-sysfs.h" @@ -329,6 +337,57 @@ static ssize_t carrier_down_count_show(struct device *dev, } static DEVICE_ATTR_RO(carrier_down_count); +#ifdef MY_ABC_HERE +extern int syno_pciepath_dts_pattern_get(struct pci_dev *pdev, char *szPciePath, const int size); +static void syno_pciepath_enum(struct device *dev, char *buf) { + struct pci_dev *pdev = NULL; + char sztemp[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (NULL == buf || NULL == dev) { + return; + } + pdev = to_pci_dev(dev); + + if (-1 == syno_pciepath_dts_pattern_get(pdev, sztemp, sizeof(sztemp))) { + return; + } + + snprintf(buf, 512, "%spciepath=%s", buf, sztemp); +} + +static void syno_platdev_path_enum(struct device *dev, char *buf) { + struct platform_device *pdev = NULL; + + if (NULL == buf || NULL == dev) { + return; + } + pdev = to_platform_device(dev); + + if (NULL != pdev->name) { + snprintf(buf, 512, "%splatdev_path=%s", buf, pdev->name); + } +} + +static ssize_t syno_eth_info_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + char szDevPath[SYNO_DTS_PROPERTY_CONTENT_LENGTH] = {'\0'}; + + if (netdev->dev.parent) { + if (dev_is_pci(netdev->dev.parent)) { + syno_pciepath_enum(netdev->dev.parent, szDevPath); + } else if (dev_is_platform(netdev->dev.parent)) { + syno_platdev_path_enum(netdev->dev.parent, szDevPath); + } + } + + return sprintf(buf, "%s\n", szDevPath); +} +static DEVICE_ATTR_RO(syno_eth_info); +#endif /* MY_ABC_HERE */ + /* read-write attributes */ static int change_mtu(struct net_device *dev, unsigned long new_mtu) @@ -570,6 +629,9 @@ static struct attribute *net_class_attrs[] __ro_after_init = { &dev_attr_proto_down.attr, &dev_attr_carrier_up_count.attr, &dev_attr_carrier_down_count.attr, +#ifdef MY_ABC_HERE + &dev_attr_syno_eth_info.attr, +#endif /* MY_ABC_HERE */ NULL, }; ATTRIBUTE_GROUPS(net_class); diff --git a/net/core/sock.c b/net/core/sock.c index d638c5361ed2..aeaa3dc50049 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1255,6 +1255,16 @@ int sock_setsockopt(struct socket *sock, int level, int optname, } EXPORT_SYMBOL(sock_setsockopt); +static const struct cred *sk_get_peer_cred(struct sock *sk) +{ + const struct cred *cred; + + spin_lock(&sk->sk_peer_lock); + cred = get_cred(sk->sk_peer_cred); + spin_unlock(&sk->sk_peer_lock); + + return cred; +} static void cred_to_ucred(struct pid *pid, const struct cred *cred, struct ucred *ucred) @@ -1428,7 +1438,11 @@ int sock_getsockopt(struct socket *sock, int level, int optname, struct ucred peercred; if (len > sizeof(peercred)) len = sizeof(peercred); + + spin_lock(&sk->sk_peer_lock); cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred); + spin_unlock(&sk->sk_peer_lock); + if (copy_to_user(optval, &peercred, len)) return -EFAULT; goto lenout; @@ -1436,20 +1450,23 @@ int sock_getsockopt(struct socket *sock, int level, int optname, case SO_PEERGROUPS: { + const struct cred *cred; int ret, n; - if (!sk->sk_peer_cred) + cred = sk_get_peer_cred(sk); + if (!cred) return -ENODATA; - n = sk->sk_peer_cred->group_info->ngroups; + n = cred->group_info->ngroups; if (len < n * sizeof(gid_t)) { len = n * sizeof(gid_t); + put_cred(cred); return put_user(len, optlen) ? -EFAULT : -ERANGE; } len = n * sizeof(gid_t); - ret = groups_to_user((gid_t __user *)optval, - sk->sk_peer_cred->group_info); + ret = groups_to_user((gid_t __user *)optval, cred->group_info); + put_cred(cred); if (ret) return ret; goto lenout; @@ -1788,9 +1805,10 @@ static void __sk_destruct(struct rcu_head *head) sk->sk_frag.page = NULL; } - if (sk->sk_peer_cred) - put_cred(sk->sk_peer_cred); + /* We do not need to acquire sk->sk_peer_lock, we are the last user. */ + put_cred(sk->sk_peer_cred); put_pid(sk->sk_peer_pid); + if (likely(sk->sk_net_refcnt)) put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); @@ -2430,7 +2448,6 @@ static void sk_leave_memory_pressure(struct sock *sk) } } -#define SKB_FRAG_PAGE_ORDER get_order(32768) DEFINE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); /** @@ -3000,6 +3017,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_peer_pid = NULL; sk->sk_peer_cred = NULL; + spin_lock_init(&sk->sk_peer_lock); + sk->sk_write_pending = 0; sk->sk_rcvlowat = 1; sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; @@ -3207,7 +3226,8 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; - return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); + /* IPV6_ADDRFORM can change sk->sk_prot under us. */ + return READ_ONCE(sk->sk_prot)->getsockopt(sk, level, optname, optval, optlen); } EXPORT_SYMBOL(sock_common_getsockopt); @@ -3234,7 +3254,8 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; - return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); + /* IPV6_ADDRFORM can change sk->sk_prot under us. */ + return READ_ONCE(sk->sk_prot)->setsockopt(sk, level, optname, optval, optlen); } EXPORT_SYMBOL(sock_common_setsockopt); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index dac65180c4ef..739689bea903 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * INET An implementation of the TCP/IP protocol suite for the LINUX @@ -292,8 +295,19 @@ int eth_prepare_mac_addr_change(struct net_device *dev, void *p) { struct sockaddr *addr = p; +#ifdef MY_ABC_HERE + /** + * In linux-2.6.24, kernel call dev->set_mac_address() directly to + * set mac address. But in linux-2.6.32, kernel call a middle layer + * function ops->ndo_set_mac_address() to set mac address. However, + * this function will call eth_mac_addr() and will check if network + * interface is on or not. If network interface is running, it returns + * -EBUSY and set mac address action failed. + */ +#else /* MY_ABC_HERE */ if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) return -EBUSY; +#endif /* MY_ABC_HERE */ if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; return 0; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8267349afe23..ffa999a5b210 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -559,22 +559,27 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sock *sk = sock->sk; + const struct proto *prot; int err; if (addr_len < sizeof(uaddr->sa_family)) return -EINVAL; + + /* IPV6_ADDRFORM can change sk->sk_prot under us. */ + prot = READ_ONCE(sk->sk_prot); + if (uaddr->sa_family == AF_UNSPEC) - return sk->sk_prot->disconnect(sk, flags); + return prot->disconnect(sk, flags); if (BPF_CGROUP_PRE_CONNECT_ENABLED(sk)) { - err = sk->sk_prot->pre_connect(sk, uaddr, addr_len); + err = prot->pre_connect(sk, uaddr, addr_len); if (err) return err; } if (data_race(!inet_sk(sk)->inet_num) && inet_autobind(sk)) return -EAGAIN; - return sk->sk_prot->connect(sk, uaddr, addr_len); + return prot->connect(sk, uaddr, addr_len); } EXPORT_SYMBOL(inet_dgram_connect); @@ -735,10 +740,11 @@ EXPORT_SYMBOL(inet_stream_connect); int inet_accept(struct socket *sock, struct socket *newsock, int flags, bool kern) { - struct sock *sk1 = sock->sk; + struct sock *sk1 = sock->sk, *sk2; int err = -EINVAL; - struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err, kern); + /* IPV6_ADDRFORM can change sk->sk_prot under us. */ + sk2 = READ_ONCE(sk1->sk_prot)->accept(sk1, flags, &err, kern); if (!sk2) goto do_err; @@ -823,12 +829,15 @@ ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { struct sock *sk = sock->sk; + const struct proto *prot; if (unlikely(inet_send_prepare(sk))) return -EAGAIN; - if (sk->sk_prot->sendpage) - return sk->sk_prot->sendpage(sk, page, offset, size, flags); + /* IPV6_ADDRFORM can change sk->sk_prot under us. */ + prot = READ_ONCE(sk->sk_prot); + if (prot->sendpage) + return prot->sendpage(sk, page, offset, size, flags); return sock_no_sendpage(sock, page, offset, size, flags); } EXPORT_SYMBOL(inet_sendpage); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index ed9857b2875d..e2b91fca93ba 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -448,6 +448,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; + unsigned int allocsz; /* this is non-NULL only with TCP/UDP Encapsulation */ if (x->encap) { @@ -457,6 +458,10 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * return err; } + allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); + if (allocsz > ESP_SKB_FRAG_MAXSIZE) + goto cow; + if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6b3c558a4f23..03589a04f9aa 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2713,6 +2713,7 @@ int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u rv = 1; } else if (im) { if (src_addr) { + spin_lock_bh(&im->lock); for (psf = im->sources; psf; psf = psf->sf_next) { if (psf->sf_inaddr == src_addr) break; @@ -2723,6 +2724,7 @@ int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u im->sfcount[MCAST_EXCLUDE]; else rv = im->sfcount[MCAST_EXCLUDE] != 0; + spin_unlock_bh(&im->lock); } else rv = 1; /* unspecified source; tentatively allow */ } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e70291748889..a0829495b211 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -468,6 +468,8 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, static int gre_handle_offloads(struct sk_buff *skb, bool csum) { + if (csum && skb_checksum_start(skb) < skb->data) + return -EINVAL; return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e15c1d8b7c8d..c5d762a2be99 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -610,28 +610,35 @@ static void fnhe_flush_routes(struct fib_nh_exception *fnhe) } } -static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash) +static void fnhe_remove_oldest(struct fnhe_hash_bucket *hash) { - struct fib_nh_exception *fnhe, *oldest; + struct fib_nh_exception __rcu **fnhe_p, **oldest_p; + struct fib_nh_exception *fnhe, *oldest = NULL; - oldest = rcu_dereference(hash->chain); - for (fnhe = rcu_dereference(oldest->fnhe_next); fnhe; - fnhe = rcu_dereference(fnhe->fnhe_next)) { - if (time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp)) + for (fnhe_p = &hash->chain; ; fnhe_p = &fnhe->fnhe_next) { + fnhe = rcu_dereference_protected(*fnhe_p, + lockdep_is_held(&fnhe_lock)); + if (!fnhe) + break; + if (!oldest || + time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp)) { oldest = fnhe; + oldest_p = fnhe_p; + } } fnhe_flush_routes(oldest); - return oldest; + *oldest_p = oldest->fnhe_next; + kfree_rcu(oldest, rcu); } -static inline u32 fnhe_hashfun(__be32 daddr) +static u32 fnhe_hashfun(__be32 daddr) { - static u32 fnhe_hashrnd __read_mostly; - u32 hval; + static siphash_key_t fnhe_hash_key __read_mostly; + u64 hval; - net_get_random_once(&fnhe_hashrnd, sizeof(fnhe_hashrnd)); - hval = jhash_1word((__force u32)daddr, fnhe_hashrnd); - return hash_32(hval, FNHE_HASH_SHIFT); + net_get_random_once(&fnhe_hash_key, sizeof(fnhe_hash_key)); + hval = siphash_1u32((__force u32)daddr, &fnhe_hash_key); + return hash_64(hval, FNHE_HASH_SHIFT); } static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) @@ -700,16 +707,21 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr, if (rt) fill_route_from_fnhe(rt, fnhe); } else { - if (depth > FNHE_RECLAIM_DEPTH) - fnhe = fnhe_oldest(hash); - else { - fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC); - if (!fnhe) - goto out_unlock; + /* Randomize max depth to avoid some side channels attacks. */ + int max_depth = FNHE_RECLAIM_DEPTH + + prandom_u32_max(FNHE_RECLAIM_DEPTH); - fnhe->fnhe_next = hash->chain; - rcu_assign_pointer(hash->chain, fnhe); + while (depth > max_depth) { + fnhe_remove_oldest(hash); + depth--; } + + fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC); + if (!fnhe) + goto out_unlock; + + fnhe->fnhe_next = hash->chain; + fnhe->fnhe_genid = genid; fnhe->fnhe_daddr = daddr; fnhe->fnhe_gw = gw; @@ -717,6 +729,8 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr, fnhe->fnhe_mtu_locked = lock; fnhe->fnhe_expires = max(1UL, expires); + rcu_assign_pointer(hash->chain, fnhe); + /* Exception created; mark the cached routes for the nexthop * stale, so anyone caching it rechecks if this exception * applies to them. diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 54230852e5f9..5c126fa740e1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3346,8 +3346,9 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, const struct inet_connection_sock *icsk = inet_csk(sk); if (level != SOL_TCP) - return icsk->icsk_af_ops->setsockopt(sk, level, optname, - optval, optlen); + /* Paired with WRITE_ONCE() in do_ipv6_setsockopt() and tcp_v6_connect() */ + return READ_ONCE(icsk->icsk_af_ops)->setsockopt(sk, level, optname, + optval, optlen); return do_tcp_setsockopt(sk, level, optname, optval, optlen); } EXPORT_SYMBOL(tcp_setsockopt); @@ -3891,8 +3892,9 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, struct inet_connection_sock *icsk = inet_csk(sk); if (level != SOL_TCP) - return icsk->icsk_af_ops->getsockopt(sk, level, optname, - optval, optlen); + /* Paired with WRITE_ONCE() in do_ipv6_setsockopt() and tcp_v6_connect() */ + return READ_ONCE(icsk->icsk_af_ops)->getsockopt(sk, level, optname, + optval, optlen); return do_tcp_getsockopt(sk, level, optname, optval, optlen); } EXPORT_SYMBOL(tcp_getsockopt); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 04e259a04443..bd75fe850031 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * INET An implementation of the TCP/IP protocol suite for the LINUX @@ -2890,8 +2893,13 @@ static int __net_init tcp_sk_init(struct net *net) * which are too large can cause TCP streams to be bursty. */ net->ipv4.sysctl_tcp_tso_win_divisor = 3; +#if defined(MY_DEF_HERE) + /* Default TSQ limit of four TSO segments */ + net->ipv4.sysctl_tcp_limit_output_bytes = 262144; +#else /* MY_DEF_HERE */ /* Default TSQ limit of 16 TSO segments */ net->ipv4.sysctl_tcp_limit_output_bytes = 16 * 65536; +#endif /* MY_DEF_HERE */ /* rfc5961 challenge ack rate limiting */ net->ipv4.sysctl_tcp_challenge_ack_limit = 1000; net->ipv4.sysctl_tcp_min_tso_segs = 2; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 884d430e23cb..c66302a30a90 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * IPv6 Address [auto]configuration @@ -219,7 +222,11 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, +#if defined(MY_ABC_HERE) + .accept_dad = 2, +#else /* MY_ABC_HERE */ .accept_dad = 0, +#endif /* MY_ABC_HERE */ .suppress_frag_ndisc = 1, .accept_ra_mtu = 1, .stable_secret = { @@ -274,7 +281,11 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .proxy_ndp = 0, .accept_source_route = 0, /* we do not accept RH0 by default. */ .disable_ipv6 = 0, +#if defined(MY_ABC_HERE) + .accept_dad = 2, +#else /* MY_ABC_HERE */ .accept_dad = 1, +#endif /* MY_ABC_HERE */ .suppress_frag_ndisc = 1, .accept_ra_mtu = 1, .stable_secret = { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e648fbebb167..50b38caa63c7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * PF_INET6 socket protocol family @@ -357,6 +360,24 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, sk->sk_bound_dev_if = addr->sin6_scope_id; } +#if defined(MY_ABC_HERE) + if (__ipv6_addr_is_link_local(addr_type) && !sk->sk_bound_dev_if) { + for_each_netdev(net, dev) { + struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, &addr->sin6_addr, dev, 1); + + if (ifp != NULL) { + sk->sk_bound_dev_if = dev->ifindex; + in6_ifa_put(ifp); + break; + } + + if (ifp) { + in6_ifa_put(ifp); + } + } + } +#endif /* MY_ABC_HERE */ + /* Binding to link-local address requires an interface */ if (!sk->sk_bound_dev_if) { err = -EINVAL; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index cc8ad7ddecda..764a82abec2a 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * common UDP/RAW code @@ -224,6 +227,20 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST)) sk->sk_bound_dev_if = np->mcast_oif; +#if defined(MY_ABC_HERE) + if (__ipv6_addr_is_link_local(addr_type) && !sk->sk_bound_dev_if) { + struct net_device *dev = NULL; + for_each_netdev(sock_net(sk), dev) { + unsigned flags = dev_get_flags(dev); + if ((flags & IFF_RUNNING) && + !(flags & (IFF_LOOPBACK | IFF_SLAVE))) { + sk->sk_bound_dev_if = dev->ifindex; + break; + } + } + } +#endif /* MY_ABC_HERE */ + /* Connect to link-local address requires an interface */ if (!sk->sk_bound_dev_if) { err = -EINVAL; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 8d001f665fb1..0a35cd99cc61 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -483,6 +483,7 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; + unsigned int allocsz; if (x->encap) { int err = esp6_output_encap(x, skb, esp); @@ -491,6 +492,10 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info return err; } + allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); + if (allocsz > ESP_SKB_FRAG_MAXSIZE) + goto cow; + if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 43a894bf9a1b..b19eedff6bf5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -417,6 +417,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, rtnl_lock(); lock_sock(sk); + /* Another thread has converted the socket into IPv4 with + * IPV6_ADDRFORM concurrently. + */ + if (unlikely(sk->sk_family != AF_INET6)) + goto unlock; + switch (optname) { case IPV6_ADDRFORM: @@ -474,7 +480,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sock_prot_inuse_add(net, &tcp_prot, 1); local_bh_enable(); sk->sk_prot = &tcp_prot; - icsk->icsk_af_ops = &ipv4_specific; + /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ + WRITE_ONCE(icsk->icsk_af_ops, &ipv4_specific); sk->sk_socket->ops = &inet_stream_ops; sk->sk_family = PF_INET; tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); @@ -976,6 +983,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, break; } +unlock: release_sock(sk); if (needs_rtnl) rtnl_unlock(); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 00f133a55ef7..949b075df050 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * RAW sockets for IPv6 @@ -280,6 +283,19 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk->sk_bound_dev_if = addr->sin6_scope_id; } +#if defined(MY_ABC_HERE) + if (__ipv6_addr_is_link_local(addr_type) && !sk->sk_bound_dev_if) { + for_each_netdev(sock_net(sk), dev) { + unsigned flags = dev_get_flags(dev); + if ((flags & IFF_RUNNING) && + !(flags & (IFF_LOOPBACK | IFF_SLAVE))) { + sk->sk_bound_dev_if = dev->ifindex; + break; + } + } + } +#endif /* MY_ABC_HERE */ + /* Binding to link-local address requires an interface */ if (!sk->sk_bound_dev_if) goto out_unlock; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 62db3c98424b..168a7b4d957a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -1482,17 +1483,24 @@ static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket) static u32 rt6_exception_hash(const struct in6_addr *dst, const struct in6_addr *src) { - static u32 seed __read_mostly; - u32 val; + static siphash_key_t rt6_exception_key __read_mostly; + struct { + struct in6_addr dst; + struct in6_addr src; + } __aligned(SIPHASH_ALIGNMENT) combined = { + .dst = *dst, + }; + u64 val; - net_get_random_once(&seed, sizeof(seed)); - val = jhash2((const u32 *)dst, sizeof(*dst)/sizeof(u32), seed); + net_get_random_once(&rt6_exception_key, sizeof(rt6_exception_key)); #ifdef CONFIG_IPV6_SUBTREES if (src) - val = jhash2((const u32 *)src, sizeof(*src)/sizeof(u32), val); + combined.src = *src; #endif - return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT); + val = siphash(&combined, sizeof(combined), &rt6_exception_key); + + return hash_64(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT); } /* Helper function to find the cached rt in the hash table @@ -1647,6 +1655,7 @@ static int rt6_insert_exception(struct rt6_info *nrt, struct in6_addr *src_key = NULL; struct rt6_exception *rt6_ex; struct fib6_nh *nh = res->nh; + int max_depth; int err = 0; spin_lock_bh(&rt6_exception_lock); @@ -1701,7 +1710,9 @@ static int rt6_insert_exception(struct rt6_info *nrt, bucket->depth++; net->ipv6.rt6_stats->fib_rt_cache++; - if (bucket->depth > FIB6_MAX_DEPTH) + /* Randomize max depth to avoid some side channels attacks. */ + max_depth = FIB6_MAX_DEPTH + prandom_u32_max(FIB6_MAX_DEPTH); + while (bucket->depth > max_depth) rt6_exception_remove_oldest(bucket); out: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index df33145b876c..13c816ccb028 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * TCP over IPv6 @@ -207,6 +210,20 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, sk->sk_bound_dev_if = usin->sin6_scope_id; } +#if defined(MY_ABC_HERE) + if (__ipv6_addr_is_link_local(addr_type) && !sk->sk_bound_dev_if) { + struct net_device *dev = NULL; + for_each_netdev(sock_net(sk), dev) { + unsigned flags = dev_get_flags(dev); + if ((flags & IFF_RUNNING) && + !(flags & (IFF_LOOPBACK | IFF_SLAVE))) { + sk->sk_bound_dev_if = dev->ifindex; + break; + } + } + } +#endif /* MY_ABC_HERE */ + /* Connect to link-local address requires an interface */ if (!sk->sk_bound_dev_if) return -EINVAL; @@ -237,7 +254,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, sin.sin_port = usin->sin6_port; sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; - icsk->icsk_af_ops = &ipv6_mapped; + /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ + WRITE_ONCE(icsk->icsk_af_ops, &ipv6_mapped); if (sk_is_mptcp(sk)) mptcpv6_handle_mapped(sk, true); sk->sk_backlog_rcv = tcp_v4_do_rcv; @@ -249,7 +267,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (err) { icsk->icsk_ext_hdr_len = exthdrlen; - icsk->icsk_af_ops = &ipv6_specific; + /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ + WRITE_ONCE(icsk->icsk_af_ops, &ipv6_specific); if (sk_is_mptcp(sk)) mptcpv6_handle_mapped(sk, false); sk->sk_backlog_rcv = tcp_v6_do_rcv; diff --git a/net/key/af_key.c b/net/key/af_key.c index ef9b4ac03e7b..65b5ad394aa1 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1701,9 +1701,12 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad pfk->registered |= (1<sadb_msg_satype); } + mutex_lock(&pfkey_mutex); xfrm_probe_algs(); - supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); + supp_skb = compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO); + mutex_unlock(&pfkey_mutex); + if (!supp_skb) { if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) pfk->registered &= ~(1<sadb_msg_satype); diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index b7c3c902290f..92f03f8171a9 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * (C) 1999-2001 Paul `Rusty' Russell @@ -596,6 +599,33 @@ struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct) } EXPORT_SYMBOL_GPL(nf_ct_nat_ext_add); +#ifdef MY_ABC_HERE +/* bridge netfilter uses cloned skbs when forwarding to multiple bridge ports. + * when userspace queueing is involved, we might try to set up NAT bindings + * on the same conntrack simultaneoulsy. Can happen e.g. when broadcast has + * to be forwarded by the bridge but is also passed up the stack. + * + * Thus, when bridge netfilter is enabled, we need to serialize and silently + * accept the packet in the collision case. + */ +static inline bool nf_nat_bridge_lock(struct nf_conn *ct, enum nf_nat_manip_type maniptype) +{ + spin_lock_bh(&ct->lock); + + if (unlikely(nf_nat_initialized(ct, maniptype))) { + pr_debug("race with cloned skb? Not adding NAT extension\n"); + spin_unlock_bh(&ct->lock); + return false; + } + return true; +} + +static inline void nf_nat_bridge_unlock(struct nf_conn *ct) +{ + spin_unlock_bh(&ct->lock); +} +#endif /* MY_ABC_HERE */ + unsigned int nf_nat_setup_info(struct nf_conn *ct, const struct nf_nat_range2 *range, @@ -604,13 +634,31 @@ nf_nat_setup_info(struct nf_conn *ct, struct net *net = nf_ct_net(ct); struct nf_conntrack_tuple curr_tuple, new_tuple; - /* Can't setup nat info for confirmed ct. */ - if (nf_ct_is_confirmed(ct)) - return NF_ACCEPT; - +#ifdef MY_ABC_HERE WARN_ON(maniptype != NF_NAT_MANIP_SRC && maniptype != NF_NAT_MANIP_DST); + if (!nf_nat_bridge_lock(ct, maniptype)) + return NF_ACCEPT; +#endif /* MY_ABC_HERE */ + + /* Can't setup nat info for confirmed ct. */ + if (nf_ct_is_confirmed(ct)) +#ifdef MY_ABC_HERE + { + nf_nat_bridge_unlock(ct); +#endif /* MY_ABC_HERE */ + return NF_ACCEPT; +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ + +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ + WARN_ON(maniptype != NF_NAT_MANIP_SRC && + maniptype != NF_NAT_MANIP_DST); +#endif /* MY_ABC_HERE */ + if (WARN_ON(nf_nat_initialized(ct, maniptype))) return NF_DROP; @@ -639,7 +687,14 @@ nf_nat_setup_info(struct nf_conn *ct, if (nfct_help(ct) && !nfct_seqadj(ct)) if (!nfct_seqadj_ext_add(ct)) +#ifdef MY_ABC_HERE + { + nf_nat_bridge_unlock(ct); +#endif /* MY_ABC_HERE */ return NF_DROP; +#ifdef MY_ABC_HERE + } +#endif /* MY_ABC_HERE */ } if (maniptype == NF_NAT_MANIP_SRC) { @@ -661,6 +716,9 @@ nf_nat_setup_info(struct nf_conn *ct, else ct->status |= IPS_SRC_NAT_DONE; +#ifdef MY_ABC_HERE + nf_nat_bridge_unlock(ct); +#endif /* MY_ABC_HERE */ return NF_ACCEPT; } EXPORT_SYMBOL(nf_nat_setup_info); diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index e34d05cc5754..565be648d6ac 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2679,27 +2679,31 @@ static struct nft_expr *nft_expr_init(const struct nft_ctx *ctx, err = nf_tables_expr_parse(ctx, nla, &info); if (err < 0) - goto err1; + goto err_expr_parse; + + err = -EOPNOTSUPP; + if (!(info.ops->type->flags & NFT_EXPR_STATEFUL)) + goto err_expr_stateful; err = -ENOMEM; expr = kzalloc(info.ops->size, GFP_KERNEL); if (expr == NULL) - goto err2; + goto err_expr_stateful; err = nf_tables_newexpr(ctx, &info, expr); if (err < 0) - goto err3; + goto err_expr_new; return expr; -err3: +err_expr_new: kfree(expr); -err2: +err_expr_stateful: owner = info.ops->type->owner; if (info.ops->type->release_ops) info.ops->type->release_ops(info.ops); module_put(owner); -err1: +err_expr_parse: return ERR_PTR(err); } @@ -4047,6 +4051,9 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr, u32 len; int err; + if (desc->field_count >= ARRAY_SIZE(desc->field_len)) + return -E2BIG; + err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr, nft_concat_policy, NULL); if (err < 0) @@ -4056,9 +4063,8 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr, return -EINVAL; len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN])); - - if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT) - return -E2BIG; + if (!len || len > U8_MAX) + return -EINVAL; desc->field_len[desc->field_count++] = len; @@ -4069,7 +4075,8 @@ static int nft_set_desc_concat(struct nft_set_desc *desc, const struct nlattr *nla) { struct nlattr *attr; - int rem, err; + u32 num_regs = 0; + int rem, err, i; nla_for_each_nested(attr, nla, rem) { if (nla_type(attr) != NFTA_LIST_ELEM) @@ -4080,6 +4087,12 @@ static int nft_set_desc_concat(struct nft_set_desc *desc, return err; } + for (i = 0; i < desc->field_count; i++) + num_regs += DIV_ROUND_UP(desc->field_len[i], sizeof(u32)); + + if (num_regs > NFT_REG32_COUNT) + return -E2BIG; + return 0; } @@ -5050,9 +5063,6 @@ struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx, return expr; err = -EOPNOTSUPP; - if (!(expr->ops->type->flags & NFT_EXPR_STATEFUL)) - goto err_set_elem_expr; - if (expr->ops->type->flags & NFT_EXPR_GC) { if (set->flags & NFT_SET_TIMEOUT) goto err_set_elem_expr; diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index dbc2e945c98e..a61b5bf5aa0f 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -162,7 +162,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv) struct nft_rule *const *rules; const struct nft_rule *rule; const struct nft_expr *expr, *last; - struct nft_regs regs; + struct nft_regs regs = {}; unsigned int stackptr = 0; struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; bool genbit = READ_ONCE(net->nft.gencursor); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index d1d8bca03b4f..7ff2a2aba3a3 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -831,11 +831,16 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) } static int -nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff) +nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff) { struct sk_buff *nskb; if (diff < 0) { + unsigned int min_len = skb_transport_offset(e->skb); + + if (data_len < min_len) + return -EINVAL; + if (pskb_trim(e->skb, data_len)) return -ENOMEM; } else if (diff > 0) { diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 9d6ef6cb9b26..71cd956b45bf 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007-2014 Nicira, Inc. @@ -48,6 +51,10 @@ unsigned int ovs_net_id __read_mostly; +#ifdef MY_ABC_HERE +static DEFINE_MUTEX(syno_ovs_mutex); +#endif /* MY_ABC_HERE */ + static struct genl_family dp_packet_genl_family; static struct genl_family dp_flow_genl_family; static struct genl_family dp_datapath_genl_family; @@ -2478,11 +2485,352 @@ static int __init dp_register_genl(void) return err; } +#ifdef MY_ABC_HERE +bool syno_is_ovs_bond_name(const char *name) +{ + const char SYNO_OVS_BOND[] = "ovs_bond"; + + return 0 == strncmp(name, SYNO_OVS_BOND, sizeof(SYNO_OVS_BOND) - 1); +} + +bool syno_is_ovs_eth_name(const char *name) +{ + const char SYNO_OVS_ETH[] = "ovs_eth"; + + return 0 == strncmp(name, SYNO_OVS_ETH, sizeof(SYNO_OVS_ETH) - 1); +} + +bool syno_is_eth_name(const char *name) +{ + const char SYNO_ETH[] = "eth"; + + return 0 == strncmp(name, SYNO_ETH, sizeof(SYNO_ETH) - 1); +} + +struct net_device *syno_ovs_eth_get_from_eth(struct net_device *netdev) +{ + if (syno_is_eth_name(netdev->name) && netdev->priv_flags & IFF_OVS_DATAPATH) { + char new_name[IFNAMSIZ]; + int count; + + count = snprintf(new_name, sizeof(new_name), "ovs_%s", netdev->name); + + if (!(count > 0 && count < IFNAMSIZ)) + return NULL; + + return dev_get_by_name(dev_net(netdev), new_name); + } + + return NULL; +} + +struct net_device *syno_ovs_bond_get_from_eth(struct net_device *netdev) +{ + struct net *net = dev_net(netdev); + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + struct net_device *ovs_bond = NULL; + struct syno_ovs_bond_list *bondp; + struct syno_ovs_bond_slave_list *slavep; + + mutex_lock(&syno_ovs_mutex); + + list_for_each_entry(bondp, &ovs_net->bond_list, next) { + list_for_each_entry(slavep, &bondp->slaves, next) { + if (0 == strcmp(netdev->name, slavep->name)) { + ovs_bond = dev_get_by_name(net, bondp->name); + goto END; + } + } + } + +END: + mutex_unlock(&syno_ovs_mutex); + + return ovs_bond; +} + +struct net_device *syno_eth_get_from_ovs_eth(struct net_device *netdev) +{ + if (syno_is_ovs_eth_name(netdev->name) && ovs_is_internal_dev(netdev)) { + char new_name[IFNAMSIZ]; + int count; + struct net_device *eth_dev; + + count = sscanf(netdev->name, "ovs_%s", new_name); + + if (count != 1) + return NULL; + + eth_dev = dev_get_by_name(dev_net(netdev), new_name); + + if (eth_dev) { + if (eth_dev->priv_flags & IFF_OVS_DATAPATH) { + return eth_dev; + } else { + dev_put(eth_dev); + } + } + } + + return NULL; +} + +void syno_ovs_bond_set_carrier(struct net_device *netdev) +{ + struct net *net = dev_net(netdev); + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + struct syno_ovs_bond_list *bondp; + struct syno_ovs_bond_slave_list *slavep; + int count_active_slaves = 0; + + ASSERT_RTNL(); + + if (!(syno_is_ovs_bond_name(netdev->name) && ovs_is_internal_dev(netdev))) { + return; + } + + mutex_lock(&syno_ovs_mutex); + + list_for_each_entry(bondp, &ovs_net->bond_list, next) { + if (0 != strcmp(netdev->name, bondp->name)) { + continue; + } + + list_for_each_entry(slavep, &bondp->slaves, next) { + struct net_device *slave_dev = dev_get_by_name(net, slavep->name); + + if (slave_dev) { + if (netif_carrier_ok(slave_dev)) { + count_active_slaves++; + } + + dev_put(slave_dev); + } + } + + break; + } + + if (count_active_slaves && !netif_carrier_ok(netdev)) { + netif_carrier_on(netdev); + } else if (0 == count_active_slaves && netif_carrier_ok(netdev)) { + netif_carrier_off(netdev); + } + + mutex_unlock(&syno_ovs_mutex); +} + +static ssize_t syno_ovs_show_bonds(struct class *cls, + struct class_attribute *attr, + char *buf) +{ + struct ovs_net *ovs_net = + container_of(attr, struct ovs_net, class_attr_syno_ovs_bonds); + int res = 0; + struct syno_ovs_bond_list *bondp; + struct syno_ovs_bond_slave_list *slavep; + bool full = false; + + if (list_empty(&ovs_net->bond_list)) + return 0; + + mutex_lock(&syno_ovs_mutex); + list_for_each_entry(bondp, &ovs_net->bond_list, next) { + if ((PAGE_SIZE - IFNAMSIZ) < res) { + full = true; + break; + } + + res += sprintf(buf + res, "%s ", bondp->name); + + list_for_each_entry(slavep, &bondp->slaves, next) { + if ((PAGE_SIZE - IFNAMSIZ) < res) { + full = true; + break; + } + + res += sprintf(buf + res, "%s ", slavep->name); + } + buf[res - 1] = '\n'; + } + mutex_unlock(&syno_ovs_mutex); + + if (full) + pr_warn("Not enough space for another interface name\n"); + + if (res) + buf[res - 1] = '\n'; /* eat the leftover space */ + return res; +} + +static struct syno_ovs_bond_list* syno_ovs_bond_master_lookup( + struct ovs_net *ovs_net, + char *ifname) +{ + struct syno_ovs_bond_list *bondp; + + if (list_empty(&ovs_net->bond_list)) + return NULL; + + list_for_each_entry(bondp, &ovs_net->bond_list, next) { + if (0 == strcmp(bondp->name, ifname)) + return bondp; + } + + return NULL; +} + +void syno_ovs_bond_slaves_clean(struct syno_ovs_bond_list *bondp) +{ + struct list_head *pos, *n; + struct syno_ovs_bond_slave_list *slave; + + list_for_each_safe(pos, n, &bondp->slaves) { + slave = list_entry(pos, struct syno_ovs_bond_slave_list, next); + list_del(&slave->next); + kfree(slave->name); + kfree(slave); + } +} + +static ssize_t syno_ovs_store_bonds(struct class *cls, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct syno_ovs_bond_list *bondp = NULL; + char *p, *temp, *orig_temp; + int res = count; + int i = 0; + struct ovs_net *ovs_net = + container_of(attr, struct ovs_net, class_attr_syno_ovs_bonds); + + if (NULL != (p = strchr(buf, '\n'))) + *p = '\0'; + + orig_temp = temp = kstrdup(buf, GFP_KERNEL); + if (temp == NULL) + return -ENOMEM; + + mutex_lock(&syno_ovs_mutex); + while (NULL != (p = strsep(&temp, " "))) { + if (!dev_valid_name(p)) { + pr_err("%s: \"%s\" is not a valid name of net_device\n", __func__, p); + } + + /* The first entry is a bonding master */ + if (!bondp) { + bondp = syno_ovs_bond_master_lookup(ovs_net, p); + + if (!bondp) { + bondp = kzalloc(sizeof(struct syno_ovs_bond_list), GFP_KERNEL); + if (bondp == NULL) { + res = -ENOMEM; + goto END; + } + bondp->name = kstrdup(p, GFP_KERNEL); + if (bondp->name == NULL) { + res = -ENOMEM; + goto END; + } + INIT_LIST_HEAD(&bondp->slaves); + list_add_tail(&bondp->next, &ovs_net->bond_list); + } else { + /* If the bonding master has existed, it's used to update/delete + * the slave list of the bonding master. So we clean the list + * for getting ready to add slaves from the input, if any. + */ + syno_ovs_bond_slaves_clean(bondp); + } + /* The other entries are bonding slaves */ + } else { + struct syno_ovs_bond_slave_list *slavep; + slavep = kzalloc(sizeof(struct syno_ovs_bond_slave_list), + GFP_KERNEL); + if (slavep == NULL) { + res = -ENOMEM; + goto END; + } + slavep->name = kstrdup(p, GFP_KERNEL); + if (slavep->name == NULL) { + res = -ENOMEM; + goto END; + } + list_add_tail(&slavep->next, &bondp->slaves); + } + i++; + } + + /* If the input which contains only one interface, it's used to delete the + * corresponding bonding master, if exists. + */ + if (i == 1) { + list_del(&bondp->next); + kfree(bondp->name); + kfree(bondp); + } + +END: + mutex_unlock(&syno_ovs_mutex); + if (orig_temp) { + kfree(orig_temp); + } + + /* Update carrier of the OVS bond when slave changed. */ + if (0 < res && 1 < i) { + struct net_device *ovs_bond = + dev_get_by_name(ovs_net->net, bondp->name); + + if (ovs_bond) { + rtnl_lock(); + syno_ovs_bond_set_carrier(ovs_bond); + rtnl_unlock(); + dev_put(ovs_bond); + } + } + + return res; +} + +static struct class_attribute class_attr_syno_ovs_bonds = { + .attr = { + .name = "syno_ovs_bonds", + .mode = S_IWUSR | S_IRUGO, + }, + .show = syno_ovs_show_bonds, + .store = syno_ovs_store_bonds, +}; + +static int syno_ovs_create_sysfs(struct ovs_net *ovs_net) +{ + int ret; + + ovs_net->class_attr_syno_ovs_bonds = class_attr_syno_ovs_bonds; + + sysfs_attr_init(&ovs_net->class_attr_syno_ovs_bonds.attr); + + ret = netdev_class_create_file_ns(&ovs_net->class_attr_syno_ovs_bonds, + ovs_net->net); + + if (ret == -EEXIST) { + printk(KERN_ERR "ovs: %s %s already exists in sysfs\n", __func__, + class_attr_syno_ovs_bonds.attr.name); + ret = 0; + } + return ret; +} +#endif /* MY_ABC_HERE */ + static int __net_init ovs_init_net(struct net *net) { struct ovs_net *ovs_net = net_generic(net, ovs_net_id); int err; +#ifdef MY_ABC_HERE + ovs_net->net = net; + INIT_LIST_HEAD(&ovs_net->bond_list); + syno_ovs_create_sysfs(ovs_net); +#endif /* MY_ABC_HERE */ + INIT_LIST_HEAD(&ovs_net->dps); INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq); INIT_DELAYED_WORK(&ovs_net->masks_rebalance, ovs_dp_masks_rebalance); @@ -2519,14 +2867,41 @@ static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, } } +#ifdef MY_ABC_HERE +static void syno_ovs_destroy_sysfs(struct ovs_net *ovs_net) +{ + netdev_class_remove_file_ns(&ovs_net->class_attr_syno_ovs_bonds, + ovs_net->net); +} +#endif /* MY_ABC_HERE */ + static void __net_exit ovs_exit_net(struct net *dnet) { struct datapath *dp, *dp_next; struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id); struct vport *vport, *vport_next; struct net *net; +#ifdef MY_ABC_HERE + struct list_head *pos, *n; + struct syno_ovs_bond_list *bondp; +#endif /* MY_ABC_HERE */ LIST_HEAD(head); +#ifdef MY_ABC_HERE + syno_ovs_destroy_sysfs(ovs_net); + mutex_lock(&syno_ovs_mutex); + if (!list_empty(&ovs_net->bond_list)) { + list_for_each_safe(pos, n, &ovs_net->bond_list) { + bondp = list_entry(pos, struct syno_ovs_bond_list, next); + syno_ovs_bond_slaves_clean(bondp); + list_del(&bondp->next); + kfree(bondp->name); + kfree(bondp); + } + } + mutex_unlock(&syno_ovs_mutex); +#endif /* MY_ABC_HERE */ + ovs_lock(); ovs_ct_exit(dnet); diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 38f7d3e66ca6..9810723a6e70 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2007-2014 Nicira, Inc. @@ -127,6 +130,19 @@ struct dp_upcall_info { u16 mru; }; +#ifdef MY_ABC_HERE +struct syno_ovs_bond_slave_list { + char *name; + struct list_head next; +}; + +struct syno_ovs_bond_list { + char *name; + struct list_head slaves; + struct list_head next; +}; +#endif /* MY_ABC_HERE */ + /** * struct ovs_net - Per net-namespace data for ovs. * @dps: List of datapaths to enable dumping them all out. @@ -142,6 +158,12 @@ struct ovs_net { /* Module reference for configuring conntrack. */ bool xt_label; + +#ifdef MY_ABC_HERE + struct net *net; + struct class_attribute class_attr_syno_ovs_bonds; + struct list_head bond_list; +#endif /* MY_ABC_HERE */ }; /** @@ -255,6 +277,20 @@ void ovs_dp_notify_wq(struct work_struct *work); int action_fifos_init(void); void action_fifos_exit(void); +#ifdef MY_ABC_HERE +bool syno_is_ovs_bond_name(const char *name); +bool syno_is_ovs_eth_name(const char *name); +bool syno_is_eth_name(const char *name); + +/* The caller must use dev_put() to release it when it is no longer needed. */ +struct net_device *syno_ovs_eth_get_from_eth(struct net_device *netdev); +struct net_device *syno_eth_get_from_ovs_eth(struct net_device *netdev); +struct net_device *syno_ovs_bond_get_from_eth(struct net_device *netdev); + +/* Must be under rtnl_lock when this function is called. */ +void syno_ovs_bond_set_carrier(struct net_device *netdev); +#endif /* MY_ABC_HERE */ + /* 'KEY' must not have any bits set outside of the 'MASK' */ #define OVS_MASKED(OLD, KEY, MASK) ((KEY) | ((OLD) & ~(MASK))) #define OVS_SET_MASKED(OLD, KEY, MASK) ((OLD) = OVS_MASKED(OLD, KEY, MASK)) diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index 7af0cde8b293..d05e96e2d45a 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007-2012 Nicira, Inc. @@ -69,6 +72,43 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event, if (!vport) return NOTIFY_DONE; +#ifdef MY_ABC_HERE + if (dev->priv_flags & IFF_OVS_DATAPATH && + (NETDEV_CHANGE == event || + NETDEV_UP == event || + NETDEV_DOWN == event)) { + struct net_device *ovs_eth_dev = syno_ovs_eth_get_from_eth(dev); + struct net_device *ovs_bond_dev = syno_ovs_bond_get_from_eth(dev); + + if (unlikely(ovs_eth_dev && ovs_bond_dev)) { + net_warn_ratelimited("%s: is slave of %s and %s.\n", + dev->name, + ovs_eth_dev->name, + ovs_bond_dev->name); + + dev_put(ovs_eth_dev); + dev_put(ovs_bond_dev); + + return NOTIFY_DONE; + } else if (ovs_eth_dev) { + if (netif_carrier_ok(dev) != netif_carrier_ok(ovs_eth_dev)) { + if (netif_carrier_ok(dev)) + netif_carrier_on(ovs_eth_dev); + else + netif_carrier_off(ovs_eth_dev); + } + + dev_put(ovs_eth_dev); + } else if (ovs_bond_dev) { + syno_ovs_bond_set_carrier(ovs_bond_dev); + + dev_put(ovs_bond_dev); + } + + return NOTIFY_OK; + } +#endif /* MY_ABC_HERE */ + if (event == NETDEV_UNREGISTER) { /* upper_dev_unlink and decrement promisc immediately */ ovs_netdev_detach_dev(vport); diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 4c5c2331e764..cba9686a9480 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2351,7 +2351,7 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2); if (new_acts_size > MAX_ACTIONS_BUFSIZE) { - if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) { + if ((next_offset + req_size) > MAX_ACTIONS_BUFSIZE) { OVS_NLERR(log, "Flow action size exceeds max %u", MAX_ACTIONS_BUFSIZE); return ERR_PTR(-EMSGSIZE); diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 1e30d8df3ba5..4bcf637e64ae 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007-2012 Nicira, Inc. @@ -173,6 +176,33 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) err = register_netdevice(vport->dev); if (err) goto error_unlock; + +#ifdef MY_ABC_HERE + if (syno_is_ovs_bond_name(vport->dev->name)) { + /* Always set carrier off, because it don't have any slaves at this time + */ + netif_carrier_off(vport->dev); + } else if (syno_is_ovs_eth_name(vport->dev->name)) { + struct net_device *eth_netdev = + syno_eth_get_from_ovs_eth(vport->dev); + + /* Set carrier of the OVS bridge based on the supposed slave, although + * the slave may not be added to the datapath at this time. When it's + * added, the carrier will be updated again. + */ + if (eth_netdev) { + if (netif_carrier_ok(eth_netdev)) { + /* The default carrier of an ovs_eth is on. */ + } else { + netif_carrier_off(vport->dev); + } + + dev_put(eth_netdev); + } else { + netif_carrier_off(vport->dev); + } + } +#endif /* MY_ABC_HERE */ vport->dev->priv_destructor = internal_dev_destructor; dev_set_promiscuity(vport->dev, 1); diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 57d6436e6f6a..3807759da56d 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007-2012 Nicira, Inc. @@ -107,6 +110,27 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name) dev_disable_lro(vport->dev); dev_set_promiscuity(vport->dev, 1); vport->dev->priv_flags |= IFF_OVS_DATAPATH; +#ifdef MY_ABC_HERE + if (unlikely(vport->dev->flags & IFF_SLAVE)) { + netdev_err(vport->dev, "Error: Device was already enslaved.\n"); + } + vport->dev->flags |= IFF_SLAVE; + + if (syno_is_eth_name(vport->dev->name)) { + struct net_device *ovs_eth_dev = + syno_ovs_eth_get_from_eth(vport->dev); + + if (ovs_eth_dev) { + if (netif_carrier_ok(vport->dev)) { + netif_carrier_on(ovs_eth_dev); + } else { + netif_carrier_off(ovs_eth_dev); + } + + dev_put(ovs_eth_dev); + } + } +#endif /* MY_ABC_HERE */ rtnl_unlock(); return vport; @@ -146,6 +170,9 @@ static void vport_netdev_free(struct rcu_head *rcu) void ovs_netdev_detach_dev(struct vport *vport) { ASSERT_RTNL(); +#ifdef MY_ABC_HERE + vport->dev->flags &= ~IFF_SLAVE; +#endif /* MY_ABC_HERE */ vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(vport->dev); netdev_upper_dev_unlink(vport->dev, diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 08144559eed5..d95f867f8ae8 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2274,8 +2274,11 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, copy_skb = skb_get(skb); skb_head = skb->data; } - if (copy_skb) + if (copy_skb) { + memset(&PACKET_SKB_CB(copy_skb)->sa.ll, 0, + sizeof(PACKET_SKB_CB(copy_skb)->sa.ll)); skb_set_owner_r(copy_skb, sk); + } } snaplen = po->rx_ring.frame_size - macoff; if ((int)snaplen < 0) { @@ -3429,6 +3432,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, sock_recv_ts_and_drops(msg, sk, skb); if (msg->msg_name) { + const size_t max_len = min(sizeof(skb->cb), + sizeof(struct sockaddr_storage)); int copy_len; /* If the address length field is there to be filled @@ -3451,6 +3456,10 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, msg->msg_namelen = sizeof(struct sockaddr_ll); } } + if (WARN_ON_ONCE(copy_len > max_len)) { + copy_len = max_len; + msg->msg_namelen = copy_len; + } memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len); } @@ -4461,9 +4470,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, } out_free_pg_vec: - bitmap_free(rx_owner_map); - if (pg_vec) + if (pg_vec) { + bitmap_free(rx_owner_map); free_pg_vec(pg_vec, order, req->tp_block_nr); + } out: return err; } diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 31ac76a9189e..f1a07b518077 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -1953,9 +1953,9 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, bool prio_allocate; u32 parent; u32 chain_index; - struct Qdisc *q = NULL; + struct Qdisc *q; struct tcf_chain_info chain_info; - struct tcf_chain *chain = NULL; + struct tcf_chain *chain; struct tcf_block *block; struct tcf_proto *tp; unsigned long cl; @@ -1983,6 +1983,8 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, tp = NULL; cl = 0; block = NULL; + q = NULL; + chain = NULL; if (prio == 0) { /* If no priority is provided by the user, @@ -2803,8 +2805,8 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, struct tcmsg *t; u32 parent; u32 chain_index; - struct Qdisc *q = NULL; - struct tcf_chain *chain = NULL; + struct Qdisc *q; + struct tcf_chain *chain; struct tcf_block *block; unsigned long cl; int err; @@ -2814,6 +2816,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, return -EPERM; replay: + q = NULL; err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX, rtm_tca_policy, extack); if (err < 0) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 54209a18d7fe..b61db335c49d 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -386,14 +386,19 @@ static int u32_init(struct tcf_proto *tp) return 0; } -static int u32_destroy_key(struct tc_u_knode *n, bool free_pf) +static void __u32_destroy_key(struct tc_u_knode *n) { struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); tcf_exts_destroy(&n->exts); - tcf_exts_put_net(&n->exts); if (ht && --ht->refcnt == 0) kfree(ht); + kfree(n); +} + +static void u32_destroy_key(struct tc_u_knode *n, bool free_pf) +{ + tcf_exts_put_net(&n->exts); #ifdef CONFIG_CLS_U32_PERF if (free_pf) free_percpu(n->pf); @@ -402,8 +407,7 @@ static int u32_destroy_key(struct tc_u_knode *n, bool free_pf) if (free_pf) free_percpu(n->pcpu_success); #endif - kfree(n); - return 0; + __u32_destroy_key(n); } /* u32_delete_key_rcu should be called when free'ing a copied @@ -898,13 +902,13 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, tca[TCA_RATE], ovr, extack); if (err) { - u32_destroy_key(new, false); + __u32_destroy_key(new); return err; } err = u32_replace_hw_knode(tp, new, flags, extack); if (err) { - u32_destroy_key(new, false); + __u32_destroy_key(new); return err; } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 84c8a534029c..8668685a8b70 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/net/sunrpc/clnt.c @@ -75,7 +78,11 @@ static int rpc_encode_header(struct rpc_task *task, static int rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr); static int rpc_ping(struct rpc_clnt *clnt); -static void rpc_check_timeout(struct rpc_task *task); +static void rpc_check_timeout(struct rpc_task *task +#ifdef MY_ABC_HERE + , const char *stage +#endif /* MY_ABC_HERE */ + ); static void rpc_register_client(struct rpc_clnt *clnt) { @@ -2015,7 +2022,11 @@ call_bind_status(struct rpc_task *task) retry_timeout: task->tk_status = 0; task->tk_action = call_bind; - rpc_check_timeout(task); + rpc_check_timeout(task +#ifdef MY_ABC_HERE + , "bind" +#endif /* MY_ABC_HERE */ + ); } /* @@ -2116,7 +2127,11 @@ call_connect_status(struct rpc_task *task) out_retry: /* Check for timeouts before looping back to call_bind */ task->tk_action = call_bind; - rpc_check_timeout(task); + rpc_check_timeout(task +#ifdef MY_ABC_HERE + , "connect" +#endif /* MY_ABC_HERE */ + ); } /* @@ -2206,7 +2221,11 @@ call_transmit_status(struct rpc_task *task) task->tk_status = 0; break; } - rpc_check_timeout(task); + rpc_check_timeout(task +#ifdef MY_ABC_HERE + , "transmit" +#endif /* MY_ABC_HERE */ + ); } #if defined(CONFIG_SUNRPC_BACKCHANNEL) @@ -2351,7 +2370,11 @@ call_status(struct rpc_task *task) } task->tk_action = call_encode; if (status != -ECONNRESET && status != -ECONNABORTED) - rpc_check_timeout(task); + rpc_check_timeout(task +#ifdef MY_ABC_HERE + , "call status" +#endif /* MY_ABC_HERE */ + ); return; out_exit: rpc_call_rpcerror(task, status); @@ -2367,7 +2390,11 @@ rpc_check_connected(const struct rpc_rqst *req) } static void -rpc_check_timeout(struct rpc_task *task) +rpc_check_timeout(struct rpc_task *task +#ifdef MY_ABC_HERE + , const char *stage +#endif /* MY_ABC_HERE */ + ) { struct rpc_clnt *clnt = task->tk_client; @@ -2379,6 +2406,10 @@ rpc_check_timeout(struct rpc_task *task) if (xprt_adjust_timeout(task->tk_rqstp) == 0) return; +#ifdef MY_ABC_HERE + pr_warn_ratelimited(KERN_WARNING "RPC: %5u call_timeout in %s stage\n", + task->tk_pid, stage); +#endif /* MY_ABC_HERE */ trace_rpc_timeout_status(task); task->tk_timeouts++; @@ -2487,11 +2518,19 @@ call_decode(struct rpc_task *task) xprt_conditional_disconnect(req->rq_xprt, req->rq_connect_cookie); task->tk_action = call_encode; - rpc_check_timeout(task); + rpc_check_timeout(task +#ifdef MY_ABC_HERE + , "call decode" +#endif /* MY_ABC_HERE */ + ); break; case -EKEYREJECTED: task->tk_action = call_reserve; - rpc_check_timeout(task); + rpc_check_timeout(task +#ifdef MY_ABC_HERE + , "call decode" +#endif /* MY_ABC_HERE */ + ); rpcauth_invalcred(task); /* Ensure we obtain a new XID if we retry! */ xprt_release(task); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c045f63d11fa..a787d3d02788 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -883,6 +883,7 @@ static void __rpc_execute(struct rpc_task *task) for (;;) { void (*do_action)(struct rpc_task *); + cond_resched(); /* * Perform the next FSM step or a pending callback. * diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index c964b48eaaba..a5142b053b29 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/net/sunrpc/stats.c @@ -313,6 +316,15 @@ svc_proc_register(struct net *net, struct svc_stat *statp, const struct proc_ops } EXPORT_SYMBOL_GPL(svc_proc_register); +#ifdef MY_ABC_HERE +struct proc_dir_entry * +svc_proc_register_name(struct net *net, const char *name, struct svc_stat *statp, const struct proc_ops *proc_ops) +{ + return do_register(net, name, statp, proc_ops); +} +EXPORT_SYMBOL(svc_proc_register_name); +#endif /* MY_ABC_HERE */ + void svc_proc_unregister(struct net *net, const char *name) { diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index d38788cd9433..de86f51e5f3a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/net/sunrpc/svc.c @@ -44,7 +47,11 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net); * Setup once during sunrpc initialisation. */ struct svc_pool_map svc_pool_map = { +#ifdef MY_ABC_HERE + .mode = SVC_POOL_PERNODE +#else /* MY_ABC_HERE */ .mode = SVC_POOL_DEFAULT +#endif /* MY_ABC_HERE */ }; EXPORT_SYMBOL_GPL(svc_pool_map); diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 06e503466c32..4177d125d8d7 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * linux/net/sunrpc/svc_xprt.c @@ -422,6 +425,9 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt) if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) return; +#ifdef MY_ABC_HERE + xprt->xpt_eqtime = ktime_get(); +#endif /* MY_ABC_HERE */ cpu = get_cpu(); pool = svc_pool_for_cpu(xprt->xpt_server, cpu); @@ -435,6 +441,10 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt) /* find a thread for this xprt */ rcu_read_lock(); list_for_each_entry_rcu(rqstp, &pool->sp_all_threads, rq_all) { +#ifdef MY_ABC_HERE + if (test_bit(SP_CONGESTED, &pool->sp_flags)) + goto out_unlock; +#endif /* MY_ABC_HERE */ if (test_and_set_bit(RQ_BUSY, &rqstp->rq_flags)) continue; atomic_long_inc(&pool->sp_stats.threads_woken); @@ -443,6 +453,9 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt) goto out_unlock; } set_bit(SP_CONGESTED, &pool->sp_flags); +#ifdef MY_ABC_HERE + pool->sp_stats.congested++; +#endif /* MY_ABC_HERE */ rqstp = NULL; out_unlock: rcu_read_unlock(); @@ -853,6 +866,9 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) goto out; } +#ifdef MY_ABC_HERE + rqstp->rq_xprt_rdtime = xprt->xpt_eqtime; +#endif /* MY_ABC_HERE */ len = svc_handle_xprt(rqstp, xprt); /* No data, incomplete (TCP) read, or accept() */ @@ -896,6 +912,10 @@ int svc_send(struct svc_rqst *rqstp) struct svc_xprt *xprt; int len = -EFAULT; struct xdr_buf *xb; +#ifdef MY_ABC_HERE + const struct svc_version *vers; + s64 latency_us; +#endif /* MY_ABC_HERE */ xprt = rqstp->rq_xprt; if (!xprt) @@ -910,6 +930,25 @@ int svc_send(struct svc_rqst *rqstp) trace_svc_stats_latency(rqstp); len = xprt->xpt_ops->xpo_sendto(rqstp); +#ifdef MY_ABC_HERE + if (!rqstp->rq_server->sv_program || + rqstp->rq_vers >= rqstp->rq_server->sv_program->pg_nvers) + goto skip_report; + + vers = rqstp->rq_server->sv_program->pg_vers[rqstp->rq_vers]; + if (!vers || rqstp->rq_proc >= vers->vs_nproc) + goto skip_report; + + latency_us = ktime_to_us(ktime_sub(ktime_get(), rqstp->rq_xprt_rdtime)); + svc_update_lat(&vers->vs_latency[rqstp->rq_proc], latency_us); +#ifdef MY_ABC_HERE + if (vers->vs_store_latency_to_histogram) + vers->vs_store_latency_to_histogram(latency_us, rqstp->vfs_latency_us, rqstp->rq_proc); + if (vers->vs_store_resp_error) + vers->vs_store_resp_error(rqstp); +#endif /* MY_ABC_HERE */ +skip_report: +#endif /* MY_ABC_HERE */ trace_svc_send(rqstp, len); svc_xprt_release(rqstp); @@ -1400,16 +1439,28 @@ static int svc_pool_stats_show(struct seq_file *m, void *p) struct svc_pool *pool = p; if (p == SEQ_START_TOKEN) { +#ifdef MY_ABC_HERE + seq_puts(m, "# pool packets-arrived sockets-enqueued threads-woken threads-timedout congested-count\n"); +#else /* MY_ABC_HERE */ seq_puts(m, "# pool packets-arrived sockets-enqueued threads-woken threads-timedout\n"); +#endif /* MY_ABC_HERE */ return 0; } +#ifdef MY_ABC_HERE + seq_printf(m, "%u %lu %lu %lu %lu %lu\n", +#else /* MY_ABC_HERE */ seq_printf(m, "%u %lu %lu %lu %lu\n", +#endif /* MY_ABC_HERE */ pool->sp_id, (unsigned long)atomic_long_read(&pool->sp_stats.packets), pool->sp_stats.sockets_queued, (unsigned long)atomic_long_read(&pool->sp_stats.threads_woken), - (unsigned long)atomic_long_read(&pool->sp_stats.threads_timedout)); + (unsigned long)atomic_long_read(&pool->sp_stats.threads_timedout) +#ifdef MY_ABC_HERE + , pool->sp_stats.congested +#endif /* MY_ABC_HERE */ + ); return 0; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9a50764be916..2a3fc1ed897f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -877,12 +877,7 @@ void xprt_connect(struct rpc_task *task) if (!xprt_lock_write(xprt, task)) return; - if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state)) { - trace_xprt_disconnect_cleanup(xprt); - xprt->ops->close(xprt); - } - - if (!xprt_connected(xprt)) { + if (!xprt_connected(xprt) && !test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie; rpc_sleep_on_timeout(&xprt->pending, task, NULL, xprt_request_timeout(task->tk_rqstp)); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9c0f71e82d97..379c5380b61d 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -847,7 +847,7 @@ static int xs_local_send_request(struct rpc_rqst *req) /* Close the stream if the previous transmission was incomplete */ if (xs_send_request_was_aborted(transport, req)) { - xs_close(xprt); + xprt_force_disconnect(xprt); return -ENOTCONN; } @@ -885,7 +885,7 @@ static int xs_local_send_request(struct rpc_rqst *req) -status); fallthrough; case -EPIPE: - xs_close(xprt); + xprt_force_disconnect(xprt); status = -ENOTCONN; } @@ -1167,6 +1167,16 @@ static void xs_reset_transport(struct sock_xprt *transport) if (sk == NULL) return; + /* + * Make sure we're calling this in a context from which it is safe + * to call __fput_sync(). In practice that means rpciod and the + * system workqueue. + */ + if (!(current->flags & PF_WQ_WORKER)) { + WARN_ON_ONCE(1); + set_bit(XPRT_CLOSE_WAIT, &xprt->state); + return; + } if (atomic_read(&transport->xprt.swapper)) sk_clear_memalloc(sk); @@ -1190,7 +1200,7 @@ static void xs_reset_transport(struct sock_xprt *transport) mutex_unlock(&transport->recv_mutex); trace_rpc_socket_close(xprt, sock); - fput(filp); + __fput_sync(filp); xprt_disconnect_done(xprt); } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 37ffa7725cee..f3c319696629 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -593,20 +593,42 @@ static void unix_release_sock(struct sock *sk, int embrion) static void init_peercred(struct sock *sk) { - put_pid(sk->sk_peer_pid); - if (sk->sk_peer_cred) - put_cred(sk->sk_peer_cred); + const struct cred *old_cred; + struct pid *old_pid; + + spin_lock(&sk->sk_peer_lock); + old_pid = sk->sk_peer_pid; + old_cred = sk->sk_peer_cred; sk->sk_peer_pid = get_pid(task_tgid(current)); sk->sk_peer_cred = get_current_cred(); + spin_unlock(&sk->sk_peer_lock); + + put_pid(old_pid); + put_cred(old_cred); } static void copy_peercred(struct sock *sk, struct sock *peersk) { - put_pid(sk->sk_peer_pid); - if (sk->sk_peer_cred) - put_cred(sk->sk_peer_cred); + const struct cred *old_cred; + struct pid *old_pid; + + if (sk < peersk) { + spin_lock(&sk->sk_peer_lock); + spin_lock_nested(&peersk->sk_peer_lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock(&peersk->sk_peer_lock); + spin_lock_nested(&sk->sk_peer_lock, SINGLE_DEPTH_NESTING); + } + old_pid = sk->sk_peer_pid; + old_cred = sk->sk_peer_cred; sk->sk_peer_pid = get_pid(peersk->sk_peer_pid); sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); + + spin_unlock(&sk->sk_peer_lock); + spin_unlock(&peersk->sk_peer_lock); + + put_pid(old_pid); + put_cred(old_cred); } static int unix_listen(struct socket *sock, int backlog) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b74f28cabe24..7cd0bf3391ea 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2679,8 +2679,10 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family, *num_xfrms = 0; return 0; } - if (IS_ERR(pols[0])) + if (IS_ERR(pols[0])) { + *num_pols = 0; return PTR_ERR(pols[0]); + } *num_xfrms = pols[0]->xfrm_nr; @@ -2695,6 +2697,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family, if (pols[1]) { if (IS_ERR(pols[1])) { xfrm_pols_put(pols, *num_pols); + *num_pols = 0; return PTR_ERR(pols[1]); } (*num_pols)++; diff --git a/scripts/Makefile b/scripts/Makefile index 9adb6d247818..aa19d1d86250 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -3,6 +3,10 @@ # scripts contains sources for various helper programs used throughout # the kernel for the build process. +ifdef CONFIG_SYNO_KEXEC_TEST +HOST_EXTRACFLAGS += -DCONFIG_SYNO_KEXEC_TEST +endif # CONFIG_SYNO_KEXEC_TEST + CRYPTO_LIBS = $(shell pkg-config --libs libcrypto 2> /dev/null || echo -lcrypto) CRYPTO_CFLAGS = $(shell pkg-config --cflags libcrypto 2> /dev/null) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 6baee1200615..c9a8a601cc42 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -51,6 +51,7 @@ KBUILD_CFLAGS += -Wno-sign-compare KBUILD_CFLAGS += -Wno-format-zero-length KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast) KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare +KBUILD_CFLAGS += -Wno-ordered-compare-function-pointers endif endif diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index dd554bd436cc..32bf589e3adc 100755 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -93,6 +93,10 @@ include/uapi/linux/pktcdvd.h:CONFIG_CDROM_PKTCDVD_WCACHE for c in $configs do + if echo "$c" | grep -qe "^CONFIG_SYNO_"; then + # allow leakage of SYNO configs + continue + fi leak_error=1 for ignore in $config_leak_ignores diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 54ad86d13784..7b5148078218 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* Generate assembler source containing symbol information * * Copyright 2002 by Kai Germaschewski @@ -266,6 +269,35 @@ static int symbol_valid(const struct sym_entry *s) { const char *name = sym_name(s); +#if defined(MY_ABC_HERE) || defined(CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK) + int i = 0; + static const char* const hidden_prefixes[] = { + /* libhydrogen */ + "hydro_", + "randombytes_", + /* Synology Kexec test + * + * Except syno_kexec_test_init, other symbols will not be exported + * by compiler; but, we add them here to avoid any accident. + */ + "syno_kexec_test_init", + "test_boot_protocol_version", + "test_decompression", + "test_bootloader", + "test_e820_table", + "test_setup_data", + "remove_decompression_setup_data", + NULL + }; + + for (i = 0; hidden_prefixes[i]; ++i) { + if (0 == strncmp(hidden_prefixes[i], name, + strlen(hidden_prefixes[i]))) { + return 0; + } + } +#endif /* MY_ABC_HERE || CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK */ + /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index a39d93e3c6ae..7e6606268517 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel @@ -18,6 +21,7 @@ #include "lkc.h" + /* return true if 'path' exists, false otherwise */ static bool is_present(const char *path) { @@ -1045,6 +1049,9 @@ int conf_write_autoconf(int overwrite) const char *autoconf_name = conf_get_autoconfig_name(); FILE *out, *out_h; int i; +#ifdef MY_ABC_HERE + FILE *syno_h; +#endif /* MY_ABC_HERE */ if (!overwrite && is_present(autoconf_name)) return 0; @@ -1064,6 +1071,18 @@ int conf_write_autoconf(int overwrite) return 1; } +#ifdef MY_ABC_HERE + syno_h = fopen(".tmpsynoconfig.h", "w"); + if (!syno_h) { + fclose(out); + fclose(out_h); + return 1; + } + conf_write_heading(syno_h, &header_printer_cb, NULL); + fprintf(syno_h, "#ifndef __SYNO_AUTOCONF_H__\n" + "#define __SYNO_AUTOCONF_H__\n"); +#endif /* MY_ABC_HERE */ + conf_write_heading(out, &kconfig_printer_cb, NULL); conf_write_heading(out_h, &header_printer_cb, NULL); @@ -1075,10 +1094,25 @@ int conf_write_autoconf(int overwrite) /* write symbols to auto.conf and autoconf.h */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); conf_write_symbol(out_h, sym, &header_printer_cb, NULL); +#ifdef MY_ABC_HERE + if (strncmp(sym->name, "SYNO", 4) == 0) { + conf_write_symbol(syno_h, sym, &header_printer_cb, NULL); + } +#endif /* MY_ABC_HERE */ } fclose(out); fclose(out_h); +#ifdef MY_ABC_HERE + fprintf(syno_h, "#endif /* __SYNO_AUTOCONF_H__ */"); + fclose(syno_h); + name = "include/generated/uapi/linux/syno_autoconf.h"; + if (make_parent_dir(name)) + return 1; + if (rename(".tmpsynoconfig.h", name)) + return 1; +#endif /* MY_ABC_HERE */ + name = getenv("KCONFIG_AUTOHEADER"); if (!name) name = "include/generated/autoconf.h"; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 6eded325c837..cff7ef9a5773 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -155,7 +155,7 @@ gen_btf() vmlinux_link ${1} info "BTF" ${2} - LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1} + LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1} # Create ${2} which contains just .BTF section but no symbols. Add # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all diff --git a/scripts/lld-version.sh b/scripts/lld-version.sh index d70edb4d8a4f..f1eeee450a23 100755 --- a/scripts/lld-version.sh +++ b/scripts/lld-version.sh @@ -6,15 +6,32 @@ # Print the linker version of `ld.lld' in a 5 or 6-digit form # such as `100001' for ld.lld 10.0.1 etc. -linker_string="$($* --version)" +set -e -if ! ( echo $linker_string | grep -q LLD ); then +# Convert the version string x.y.z to a canonical 5 or 6-digit form. +get_canonical_version() +{ + IFS=. + set -- $1 + + # If the 2nd or 3rd field is missing, fill it with a zero. + echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0})) +} + +# Get the first line of the --version output. +IFS=' +' +set -- $(LC_ALL=C "$@" --version) + +# Split the line on spaces. +IFS=' ' +set -- $1 + +while [ $# -gt 1 -a "$1" != "LLD" ]; do + shift +done +if [ "$1" = LLD ]; then + echo $(get_canonical_version ${2%-*}) +else echo 0 - exit 1 fi - -VERSION=$(echo $linker_string | cut -d ' ' -f 2) -MAJOR=$(echo $VERSION | cut -d . -f 1) -MINOR=$(echo $VERSION | cut -d . -f 2) -PATCHLEVEL=$(echo $VERSION | cut -d . -f 3) -printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index e08f75aed429..ee38cd9b7f6d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -20,6 +20,7 @@ #include #include #include "modpost.h" +#include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" /* Are we using CONFIG_MODVERSIONS? */ diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh new file mode 100755 index 000000000000..8c82173e42e5 --- /dev/null +++ b/scripts/pahole-flags.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +extra_paholeopt= + +if ! [ -x "$(command -v ${PAHOLE})" ]; then + exit 0 +fi + +pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/') + +if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then + # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars + extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars" +fi + +if [ "${pahole_ver}" -ge "124" ]; then + extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_enum64" +fi + +echo ${extra_paholeopt} diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 5fd4a64e431f..0a7fe2d6f09b 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2364,6 +2364,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { AA_SFS_DIR("domain", aa_sfs_entry_domain), AA_SFS_DIR("file", aa_sfs_entry_file), AA_SFS_DIR("network_v8", aa_sfs_entry_network), + AA_SFS_DIR("network", aa_sfs_entry_network_compat), AA_SFS_DIR("mount", aa_sfs_entry_mount), AA_SFS_DIR("namespaces", aa_sfs_entry_ns), AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 1fbabdb565a8..5870de20122f 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -20,7 +20,7 @@ #define AA_CLASS_UNKNOWN 1 #define AA_CLASS_FILE 2 #define AA_CLASS_CAP 3 -#define AA_CLASS_DEPRECATED 4 +#define AA_CLASS_NET_COMPAT 4 #define AA_CLASS_RLIMITS 5 #define AA_CLASS_DOMAIN 6 #define AA_CLASS_MOUNT 7 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h index 2431c011800d..74768db94066 100644 --- a/security/apparmor/include/net.h +++ b/security/apparmor/include/net.h @@ -68,6 +68,16 @@ struct aa_sk_ctx { DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ (SK)->sk_protocol) +/* struct aa_net - network confinement data + * @allow: basic network families permissions + * @audit: which network permissions to force audit + * @quiet: which network permissions to quiet rejects + */ +struct aa_net_compat { + u16 allow[AF_MAX]; + u16 audit[AF_MAX]; + u16 quiet[AF_MAX]; +}; #define af_select(FAMILY, FN, DEF_FN) \ ({ \ @@ -87,6 +97,7 @@ struct aa_secmark { }; extern struct aa_sfs_entry aa_sfs_entry_network[]; +extern struct aa_sfs_entry aa_sfs_entry_network_compat[]; void audit_net_cb(struct audit_buffer *ab, void *va); int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b5b4b8190e65..f904105f48de 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -108,6 +108,7 @@ struct aa_data { * @policy: general match rules governing policy * @file: The set of rules governing basic file access and domain transitions * @caps: capabilities for the profile + * @net_compat: v2 compat network controls for the profile * @rlimits: rlimits for the profile * * @dents: dentries for the profiles file entries in apparmorfs @@ -145,6 +146,7 @@ struct aa_profile { struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; + struct aa_net_compat *net_compat; int xattr_count; char **xattrs; diff --git a/security/apparmor/net.c b/security/apparmor/net.c index fa0e85568450..163791feb315 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -24,6 +24,11 @@ struct aa_sfs_entry aa_sfs_entry_network[] = { { } }; +struct aa_sfs_entry aa_sfs_entry_network_compat[] = { + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), + { } +}; + static const char * const net_mask_names[] = { "unknown", "send", @@ -118,14 +123,26 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, if (profile_unconfined(profile)) return 0; state = PROFILE_MEDIATES(profile, AA_CLASS_NET); - if (!state) - return 0; + if (state) { + if (!state) + return 0; + buffer[0] = cpu_to_be16(family); + buffer[1] = cpu_to_be16((u16) type); + state = aa_dfa_match_len(profile->policy.dfa, state, + (char *) &buffer, 4); + aa_compute_perms(profile->policy.dfa, state, &perms); + } else if (profile->net_compat) { + /* 2.x socket mediation compat */ + perms.allow = (profile->net_compat->allow[family] & (1 << type)) ? + ALL_PERMS_MASK : 0; + perms.audit = (profile->net_compat->audit[family] & (1 << type)) ? + ALL_PERMS_MASK : 0; + perms.quiet = (profile->net_compat->quiet[family] & (1 << type)) ? + ALL_PERMS_MASK : 0; - buffer[0] = cpu_to_be16(family); - buffer[1] = cpu_to_be16((u16) type); - state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, - 4); - aa_compute_perms(profile->policy.dfa, state, &perms); + } else { + return 0; + } aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, sa, audit_net_cb); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4c010c9a6af1..a8154f162aa0 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module @@ -222,6 +225,7 @@ void aa_free_profile(struct aa_profile *profile) aa_free_file_rules(&profile->file); aa_free_cap_rules(&profile->caps); aa_free_rlimit_rules(&profile->rlimits); + kfree_sensitive(profile->net_compat); for (i = 0; i < profile->xattr_count; i++) kfree_sensitive(profile->xattrs[i]); @@ -1004,9 +1008,12 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, if (ent->old && ent->old->rawdata == ent->new->rawdata) { /* dedup actual profile replacement */ +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ audit_policy(label, op, ns_name, ent->new->base.hname, "same as current profile, skipping", error); +#endif /* MY_ABC_HERE */ /* break refcount cycle with proxy. */ aa_put_proxy(ent->new->label.proxy); ent->new->label.proxy = NULL; @@ -1017,8 +1024,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, * TODO: finer dedup based on profile range in data. Load set * can differ but profile may remain unchanged */ +#ifdef MY_ABC_HERE + if (error) + audit_policy(label, op, ns_name, ent->new->base.hname, NULL, + error); +#else /* MY_ABC_HERE */ audit_policy(label, op, ns_name, ent->new->base.hname, NULL, error); +#endif /* MY_ABC_HERE */ if (ent->old) { share_name(ent->old, ent->new); @@ -1056,8 +1069,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, /* audit cause of failure */ op = (ent && !ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; fail: +#ifdef MY_ABC_HERE + if (error) + audit_policy(label, op, ns_name, ent ? ent->new->base.hname : NULL, + info, error); +#else /* MY_ABC_HERE */ audit_policy(label, op, ns_name, ent ? ent->new->base.hname : NULL, info, error); +#endif /* MY_ABC_HERE */ /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; list_for_each_entry(tmp, &lh, list) { @@ -1146,8 +1165,11 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj, } /* don't fail removal if audit fails */ +#ifdef MY_ABC_HERE +#else /* MY_ABC_HERE */ (void) audit_policy(subj, OP_PROF_RM, ns_name, name, info, error); +#endif /* MY_ABC_HERE */ aa_put_ns(ns); aa_put_profile(profile); return size; diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index dc345ac93205..e6f9fb6d620b 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -34,7 +34,7 @@ #define v5 5 /* base version */ #define v6 6 /* per entry policydb mediation check */ -#define v7 7 +#define v7 7 /* v2 compat networking */ #define v8 8 /* full network masking */ /* @@ -314,6 +314,19 @@ static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name) return false; } +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) +{ + if (unpack_nameX(e, AA_U16, name)) { + if (!inbounds(e, sizeof(u16))) + return 0; + if (data) + *data = le16_to_cpu(get_unaligned((__le16 *) e->pos)); + e->pos += sizeof(u16); + return 1; + } + return 0; +} + static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) { void *pos = e->pos; @@ -676,7 +689,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) struct aa_profile *profile = NULL; const char *tmpname, *tmpns = NULL, *name = NULL; const char *info = "failed to unpack profile"; - size_t ns_len; + size_t size = 0, ns_len; struct rhashtable_params params = { 0 }; char *key = NULL; struct aa_data *data; @@ -823,6 +836,43 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) goto fail; } + size = unpack_array(e, "net_allowed_af"); + if (size || VERSION_LT(e->version, v8)) { + profile->net_compat = kzalloc(sizeof(struct aa_net_compat), GFP_KERNEL); + if (!profile->net_compat) { + info = "out of memory"; + goto fail; + } + for (i = 0; i < size; i++) { + /* discard extraneous rules that this kernel will + * never request + */ + if (i >= AF_MAX) { + u16 tmp; + + if (!unpack_u16(e, &tmp, NULL) || + !unpack_u16(e, &tmp, NULL) || + !unpack_u16(e, &tmp, NULL)) + goto fail; + continue; + } + if (!unpack_u16(e, &profile->net_compat->allow[i], NULL)) + goto fail; + if (!unpack_u16(e, &profile->net_compat->audit[i], NULL)) + goto fail; + if (!unpack_u16(e, &profile->net_compat->quiet[i], NULL)) + goto fail; + } + if (size && !unpack_nameX(e, AA_ARRAYEND, NULL)) + goto fail; + if (VERSION_LT(e->version, v7)) { + /* pre v7 policy always allowed these */ + profile->net_compat->allow[AF_UNIX] = 0xffff; + profile->net_compat->allow[AF_NETLINK] = 0xffff; + } + } + + if (unpack_nameX(e, AA_STRUCT, "policydb")) { /* generic policy dfa - optional and may be NULL */ info = "failed to unpack policydb"; diff --git a/security/security.c b/security/security.c index a28045dc9e7f..4cae084858a5 100644 --- a/security/security.c +++ b/security/security.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-or-later /* * Security plug functions @@ -1093,6 +1096,9 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) return 0; return call_int_hook(path_rmdir, 0, dir, dentry); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(security_path_rmdir); +#endif /* MY_ABC_HERE */ int security_path_unlink(const struct path *dir, struct dentry *dentry) { @@ -1109,6 +1115,9 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, return 0; return call_int_hook(path_symlink, 0, dir, dentry, old_name); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(security_path_symlink); +#endif /* MY_ABC_HERE */ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) @@ -1117,6 +1126,9 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, return 0; return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(security_path_link); +#endif /* MY_ABC_HERE */ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry, @@ -1144,6 +1156,9 @@ int security_path_truncate(const struct path *path) return 0; return call_int_hook(path_truncate, 0, path); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(security_path_truncate); +#endif /* MY_ABC_HERE */ int security_path_chmod(const struct path *path, umode_t mode) { @@ -1151,6 +1166,9 @@ int security_path_chmod(const struct path *path, umode_t mode) return 0; return call_int_hook(path_chmod, 0, path, mode); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(security_path_chmod); +#endif /* MY_ABC_HERE */ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) { @@ -1158,6 +1176,9 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) return 0; return call_int_hook(path_chown, 0, path, uid, gid); } +#ifdef MY_ABC_HERE +EXPORT_SYMBOL_GPL(security_path_chown); +#endif /* MY_ABC_HERE */ int security_path_chroot(const struct path *path) { @@ -1258,6 +1279,9 @@ int security_inode_permission(struct inode *inode, int mask) return 0; return call_int_hook(inode_permission, 0, inode, mask); } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +EXPORT_SYMBOL(security_inode_permission); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ int security_inode_setattr(struct dentry *dentry, struct iattr *attr) { @@ -1450,6 +1474,9 @@ int security_file_permission(struct file *file, int mask) return fsnotify_perm(file, mask); } +#if defined(MY_ABC_HERE) || defined(MY_ABC_HERE) +EXPORT_SYMBOL(security_file_permission); +#endif /* MY_ABC_HERE || MY_ABC_HERE */ int security_file_alloc(struct file *file) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 227eb8967963..db298ba5623f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif // SPDX-License-Identifier: GPL-2.0-only /* * NSA Security-Enhanced Linux (SELinux) security module @@ -3304,6 +3307,10 @@ static int selinux_path_notify(const struct path *path, u64 mask, * Performs an additional check for sb watches. */ switch (obj_type) { +#ifdef MY_ABC_HERE + case FSNOTIFY_OBJ_TYPE_SYNO_VFSMOUNT: + /* fall through */ +#endif case FSNOTIFY_OBJ_TYPE_VFSMOUNT: perm = FILE__WATCH_MOUNT; break; diff --git a/synology/certs/.gitignore b/synology/certs/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/synology/synoconfigs-spec/CONFIG_CRYPTO.rb b/synology/synoconfigs-spec/CONFIG_CRYPTO.rb new file mode 100644 index 000000000000..72999591e0e8 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_CRYPTO.rb @@ -0,0 +1,28 @@ + +require 'syno_kconfig' + +describe 'CONFIG_CRYPTO_*' do + include SynoKconfig + + %w[ + CONFIG_CRYPTO_CRC32C + CONFIG_LIBCRC32C + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + it "CONFIG_CRYPTO_CRC32C_INTEL=y if x86_64 platforms" do + platforms + .select { |p| p.family == :x86_64 } + .verify('CONFIG_CRYPTO_CRC32C_INTEL', builtin?) + end + + it "CONFIG_CRYPTO_CRC32C_INTEL is not set if !x86_64 platforms" do + platforms + .reject { |p| p.family == :x86_64 } + .verify('CONFIG_CRYPTO_CRC32C_INTEL', disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_DEBUG_OPTIONS.rb b/synology/synoconfigs-spec/CONFIG_DEBUG_OPTIONS.rb new file mode 100644 index 000000000000..3c846488b1bb --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_DEBUG_OPTIONS.rb @@ -0,0 +1,36 @@ + +require 'syno_kconfig' + +describe 'Debug options' do + include SynoKconfig + + %w[ + CONFIG_TRACEPOINTS + + CONFIG_DEBUG_INFO + CONFIG_DEBUG_INFO_BTF + + CONFIG_SCHED_DEBUG + CONFIG_SLUB_DEBUG + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + %w[ + CONFIG_DEBUG_ATOMIC_SLEEP + CONFIG_PREEMPT_COUNT + ].each do |cfg| + it "#{cfg} is enabled for X86_64 only" do + platforms + .select { |p| p.x86_64? } + .verify(cfg, builtin?) + + platforms + .reject { |p| p.x86_64? } + .verify(cfg, disabled?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_GENERAL_SETUP_#.rb b/synology/synoconfigs-spec/CONFIG_GENERAL_SETUP_#.rb new file mode 100644 index 000000000000..2b1ab94bdbc0 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_GENERAL_SETUP_#.rb @@ -0,0 +1,62 @@ + +require 'syno_kconfig' + +describe 'General setup' do + include SynoKconfig + + # + # built-in configs for all platforms + # + %w[ + CONFIG_SWAP + CONFIG_SYSVIPC + CONFIG_SYSVIPC_SYSCTL + CONFIG_POSIX_MQUEUE + CONFIG_POSIX_MQUEUE_SYSCTL + CONFIG_USELIB + CONFIG_AUDIT + + CONFIG_PREEMPT_NONE + + CONFIG_TASKSTATS + CONFIG_TASK_DELAY_ACCT + CONFIG_TASK_XACCT + CONFIG_TASK_IO_ACCOUNTING + CONFIG_PSI + + CONFIG_VM_EVENT_COUNTERS + CONFIG_SLUB + + CONFIG_TRACEPOINTS + + CONFIG_RD_LZMA + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + # + # disabled configs for all platforms + # + %w[ + CONFIG_PREEMPT_VOLUNTARY + CONFIG_PREEMPT + + CONFIG_PSI_DEFAULT_DISABLED + ].each do |cfg| + it "#{cfg} is not set" do + platforms.verify(cfg, disabled?) + end + end + + it "CONFIG_PHYSICAL_START=0x200000 for x86_64" do + platforms + .select { |p| p.family == :x86_64 } + .verify('CONFIG_PHYSICAL_START', equaled?(0x200000)) + platforms + .select { |p| p.family != :x86_64 } + .verify('CONFIG_PHYSICAL_START', disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_KERNEL_LZMA.rb b/synology/synoconfigs-spec/CONFIG_KERNEL_LZMA.rb new file mode 100644 index 000000000000..a63c884572a2 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_KERNEL_LZMA.rb @@ -0,0 +1,16 @@ + +require 'syno_kconfig' + +describe 'CONFIG_KERNEL_LZMA' do + include SynoKconfig + + it "CONFIG_KERNEL_LZMA=y if not arm platforms" do + platforms + .reject { |p| p.aarch64? } + .verify(desc, builtin?) + + platforms + .select { |p| p.aarch64? } + .verify(desc, disabled?) + end +end diff --git a/synology/synoconfigs-spec/CONFIG_NUMA.rb b/synology/synoconfigs-spec/CONFIG_NUMA.rb new file mode 100644 index 000000000000..8ed286f2f694 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_NUMA.rb @@ -0,0 +1,19 @@ + +require 'syno_kconfig' + +describe 'CONFIG_NUMA' do + include SynoKconfig + + # you can use variable 'desc' if your description + # is idential to CONFIG name to be tested. + it "#{desc}=y for NUMA platforms" do + platforms + .select { |p| p.numa? } + .verify(desc, builtin?) + + platforms + .reject { |p| p.numa? } + .verify(desc, disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_PCIEASPM.rb b/synology/synoconfigs-spec/CONFIG_PCIEASPM.rb new file mode 100644 index 000000000000..7ec6f3c580e4 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_PCIEASPM.rb @@ -0,0 +1,28 @@ + +require 'syno_kconfig' + +describe 'CONFIG_PCIEASPM' do + include SynoKconfig + + # builtin configs + %w[ + CONFIG_PCIEASPM + CONFIG_PCIEASPM_PERFORMANCE + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + # disable configs + %w[ + CONFIG_PCIEASPM_DEFAULT + CONFIG_PCIEASPM_POWERSAVE + CONFIG_PCIEASPM_POWER_SUPERSAVE + ].each do |cfg| + it "#{cfg} is not set" do + platforms.verify(cfg, disabled?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_QUOTA_#.rb b/synology/synoconfigs-spec/CONFIG_QUOTA_#.rb new file mode 100644 index 000000000000..19d772b62428 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_QUOTA_#.rb @@ -0,0 +1,36 @@ + +require 'syno_kconfig' + +describe 'CONFIG_QUOTA_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_QUOTA/) + scope(/^CONFIG_QFMT/) + scope(/^CONFIG_QUOTACTL/) + + it "CONFIG_QUOTA=y" do + platforms.verify("CONFIG_QUOTA", builtin?) + end + + it "CONFIG_QUOTA_DEBUG is not set" do + platforms.verify("CONFIG_QUOTA_DEBUG", disabled?) + end + + it "CONFIG_QUOTA_TREE=y" do + platforms.verify("CONFIG_QUOTA_TREE", builtin?) + end + + it "CONFIG_QFMT_V1 is not set" do + platforms.verify("CONFIG_QFMT_V1", disabled?) + end + + it "CONFIG_QFMT_V2=y" do + platforms.verify("CONFIG_QFMT_V2", builtin?) + end + + it "CONFIG_QUOTACTL=y" do + platforms.verify("CONFIG_QUOTACTL", builtin?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SWIOTLB.rb b/synology/synoconfigs-spec/CONFIG_SWIOTLB.rb new file mode 100644 index 000000000000..3fd74239edfb --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SWIOTLB.rb @@ -0,0 +1,17 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SWIOTLB' do + include SynoKconfig + + it "CONFIG_SWIOTLB=y if CONFIG_64BIT enabled" do + platforms + .select { |p| p['CONFIG_64BIT'].enabled? } + .verify(desc, enabled?) + + platforms + .reject { |p| p['CONFIG_64BIT'].enabled? } + .verify(desc, disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_AUFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_AUFS_#.rb new file mode 100644 index 000000000000..41e105ec70b2 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_AUFS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_AUFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_AUFS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_AUFS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_BASIC_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_BASIC_#.rb new file mode 100644 index 000000000000..d23b3e1729c7 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_BASIC_#.rb @@ -0,0 +1,25 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO Basic' do + include SynoKconfig + + # + # built-in configs for all platforms + # + %w[ + CONFIG_SYNO_SYSTEM_CALL + CONFIG_SYNO_LIBS + CONFIG_SYNO_KWORK_STAT + CONFIG_SYNO_EXPORT_SYMBOL + CONFIG_SYNO_SWAP_FLAG + CONFIG_SYNO_DATA_CORRECTION + CONFIG_SYNO_DISPLAY_CPUINFO + CONFIG_SYNO_LOAD_AVERAGE + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_BTRFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_BTRFS_#.rb new file mode 100644 index 000000000000..50f34e232a60 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_BTRFS_#.rb @@ -0,0 +1,59 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_BTRFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_BTRFS_/) + + # btrfs should be a module + it "CONFIG_BTRFS_FS=m" do + platforms + .verify('CONFIG_BTRFS_FS', module?) + end + + # disabled configs + %w[ + CONFIG_BTRFS_FS_POSIX_ACL + CONFIG_BTRFS_FS_CHECK_INTEGRITY + CONFIG_BTRFS_FS_RUN_SANITY_TESTS + CONFIG_BTRFS_DEBUG + CONFIG_BTRFS_ASSERT + CONFIG_BTRFS_FS_REF_VERIFY + ].each do |cfg| + it "#{cfg} is not set" do + platforms.verify(cfg, disabled?) + end + end + + # most configs should be enabled + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_BTRFS_/ } + .reject { |cfg| cfg == 'CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG' } + .reject { |cfg| cfg == 'CONFIG_SYNO_BTRFS_DEDUPE' } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + # configs only enabled in specified platforms + %w[ + CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG + CONFIG_SYNO_BTRFS_DEDUPE + ].each do |cfg| + it "#{cfg} is enabled for PURLEY, ICELAKED, V1000, EPYC7002 and EPYC7002SOFS" do + platforms + .select { |p| p.target == :PURLEY || p.target == :ICELAKED || p.target == :EPYC7002 || p.target == :EPYC7002SOFS || p.target == :V1000 } + .verify(cfg, builtin?) + end + + it "#{cfg} is disabled for non-PURLEY, non-ICELAKED, non-EPYC7002, non-V1000, and non-EPYC7002SOFS" do + platforms + .reject { |p| p.target == :PURLEY || p.target == :ICELAKED || p.target == :EPYC7002 || p.target == :EPYC7002SOFS || p.target == :V1000 } + .verify(cfg, disabled?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_CIFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_CIFS_#.rb new file mode 100644 index 000000000000..58613cc7c8fa --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_CIFS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_CIFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_CIFS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_CIFS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_CONFIGFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_CONFIGFS_#.rb new file mode 100644 index 000000000000..4ef460b57aba --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_CONFIGFS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_CONFIGFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_CONFIGFS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_CONFIGFS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_ECRYPTFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_ECRYPTFS_#.rb new file mode 100644 index 000000000000..fa12a70dceca --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_ECRYPTFS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_ECRYPTFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_ECRYPTFS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_ECRYPTFS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_EXT4_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_EXT4_#.rb new file mode 100644 index 000000000000..9f8347baebcc --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_EXT4_#.rb @@ -0,0 +1,61 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_EXT4_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_EXT3_/) + scope(/^CONFIG_SYNO_EXT4_/) + + # built-in configs + %w[ + CONFIG_EXT2_FS + CONFIG_EXT2_FS_XATTR + CONFIG_EXT3_FS + CONFIG_EXT4_FS + CONFIG_EXT4_FS_SECURITY + CONFIG_JBD2 + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + # disabled configs + %w[ + CONFIG_EXT2_FS_POSIX_ACL + CONFIG_EXT2_FS_SECURITY + CONFIG_EXT3_FS_POSIX_ACL + CONFIG_EXT3_FS_SECURITY + CONFIG_EXT4_FS_POSIX_ACL + CONFIG_EXT4_DEBUG + ].each do |cfg| + it "#{cfg} is not set" do + platforms.verify(cfg, disabled?) + end + end + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_EXT3_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_EXT4_/ } + .reject { |cfg| cfg == 'CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT' } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + it "CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2" do + platforms + .verify('CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT', equaled?(2)) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_FAT_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_FAT_#.rb new file mode 100644 index 000000000000..a67ec7bd011d --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_FAT_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_FAT_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_FAT_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_FAT_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_FEATURES.rb b/synology/synoconfigs-spec/CONFIG_SYNO_FEATURES.rb new file mode 100644 index 000000000000..00c4abb00204 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_FEATURES.rb @@ -0,0 +1,13 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_FEATURES' do + include SynoKconfig + + # you can use variable 'desc' if your description + # is idential to CONFIG name to be tested. + it "#{desc}=y" do + platforms.verify(desc, builtin?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_FS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_FS_#.rb new file mode 100644 index 000000000000..721dbc11c460 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_FS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_FS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_FS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_FS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_FUSE_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_FUSE_#.rb new file mode 100644 index 000000000000..efd54c267b27 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_FUSE_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_FUSE_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_FUSE_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_FUSE_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_HFSPLUS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_HFSPLUS_#.rb new file mode 100644 index 000000000000..6c22e773d6b2 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_HFSPLUS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_HFSPLUS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_HFSPLUS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_HFSPLUS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_IOMMU_PASSTHROUGH.rb b/synology/synoconfigs-spec/CONFIG_SYNO_IOMMU_PASSTHROUGH.rb new file mode 100644 index 000000000000..1f14437f7c76 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_IOMMU_PASSTHROUGH.rb @@ -0,0 +1,16 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_IOMMU_PASSTHROUGH' do + include SynoKconfig + + it "CONFIG_SYNO_IOMMU_PASSTHROUGH=y if not virtual platforms" do + platforms + .reject { |p| p.virtual? } + .verify(desc, builtin?) + + platforms + .select { |p| p.virtual? } + .verify(desc, disabled?) + end +end diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_MD_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_MD_#.rb new file mode 100644 index 000000000000..8a50558707b6 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_MD_#.rb @@ -0,0 +1,65 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_MD_*' do + include SynoKconfig + + # FIXME: do we need MD in kvmx64 ? + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_MD_/) + + # kernel module + %w[ + CONFIG_MD_LINEAR + CONFIG_MD_RAID10 + CONFIG_MD_RAID456 + ].each do |cfg| + it "#{cfg}=m" do + platforms.verify(cfg, module?) + end + end + + # built-in configs + %w[ + CONFIG_MD + CONFIG_BLK_DEV_MD + CONFIG_MD_AUTODETECT + CONFIG_MD_RAID1 + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_MD_/ } + .reject { |cfg| cfg == 'CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE' } + .reject { |cfg| cfg == 'CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT'} + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + it "CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y if CONFIG_NUMA enabled" do + platforms + .select { |p| p['CONFIG_NUMA'].enabled? } + .verify('CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE', enabled?) + + platforms + .reject { |p| p['CONFIG_NUMA'].enabled? } + .verify('CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE', disabled?) + end + + it "CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y if CONFIG_DM_CRYPT enabled" do + platforms + .select { |p| p['CONFIG_DM_CRYPT'].enabled? } + .verify('CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT', enabled?) + + platforms + .reject { |p| p['CONFIG_DM_CRYPT'].enabled? } + .verify('CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT', disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_MODULE_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_MODULE_#.rb new file mode 100644 index 000000000000..98574d183e3e --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_MODULE_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_MODULE_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_MODULE_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_MODULE_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_NFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_NFS_#.rb new file mode 100644 index 000000000000..cccd1cee3aa4 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_NFS_#.rb @@ -0,0 +1,98 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_NFSD?_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_NFS_/) + + # kernel module + %w[ + CONFIG_NFS_FS + CONFIG_NFS_V2 + CONFIG_NFS_V3 + CONFIG_NFS_V4 + CONFIG_NFSD + CONFIG_GRACE_PERIOD + CONFIG_SUNRPC + CONFIG_SUNRPC_GSS + CONFIG_RPCSEC_GSS_KRB5 + ].each do |cfg| + it "#{cfg}=m" do + platforms.verify(cfg, module?) + end + end + + # built-in configs + %w[ + CONFIG_EXPORTFS + CONFIG_NETWORK_FILESYSTEMS + CONFIG_NFS_USE_KERNEL_DNS + CONFIG_NFS_DEBUG + CONFIG_NFSD_V3 + CONFIG_NFSD_V4 + CONFIG_LOCKD_V4 + CONFIG_NFS_COMMON + CONFIG_SUNRPC_DEBUG + ].each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + # disabled configs + %w[ + CONFIG_NFS_V3_ACL + CONFIG_NFS_SWAP + CONFIG_NFS_V4_1 + CONFIG_NFS_USE_LEGACY_DNS + CONFIG_NFS_DISABLE_UDP_SUPPORT + CONFIG_NFSD_V3_ACL + CONFIG_NFSD_BLOCKLAYOUT + CONFIG_NFSD_SCSILAYOUT + CONFIG_NFSD_FLEXFILELAYOUT + CONFIG_NFSD_V4_SECURITY_LABEL + CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES + ].each do |cfg| + it "#{cfg} is not set" do + platforms.verify(cfg, disabled?) + end + end + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_NFS/ } + .reject { |cfg| cfg =~ /_PACKET_SIZE$/ } + .reject { |cfg| cfg == 'CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE' } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end + + it "CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768" do + platforms + .verify('CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE', equaled?(32768)) + end + + it "CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096" do + platforms + .verify('CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE', equaled?(4096)) + end + + it "CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192" do + platforms + .verify('CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE', equaled?(8192)) + end + + it "CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y if CONFIG_NUMA enabled" do + platforms + .select { |p| p['CONFIG_NUMA'].enabled? } + .verify('CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE', enabled?) + + platforms + .reject { |p| p['CONFIG_NUMA'].enabled? } + .verify('CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE', disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_OVERLAYFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_OVERLAYFS_#.rb new file mode 100644 index 000000000000..fcca338499b7 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_OVERLAYFS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_OVERLAYFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_OVERLAYFS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_OVERLAYFS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT.rb b/synology/synoconfigs-spec/CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT.rb new file mode 100644 index 000000000000..95857ac963ce --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT.rb @@ -0,0 +1,22 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT' do + include SynoKconfig + + it "CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y if CONFIG_ATA | CONFIG_SYNO_SAS enabled" do + platforms + .select { |p| p['CONFIG_ATA'].enabled? } + .verify('CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT', enabled?) + + platforms + .select { |p| p['CONFIG_SYNO_SAS'].enabled? } + .verify('CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT', enabled?) + + platforms + .reject { |p| p['CONFIG_ATA'].enabled? } + .reject { |p| p['CONFIG_SYNO_SAS'].enabled? } + .verify('CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT', disabled?) + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_TMPFS_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_TMPFS_#.rb new file mode 100644 index 000000000000..913b582db407 --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_TMPFS_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_TMPFS_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_TMPFS_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_TMPFS_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS.rb b/synology/synoconfigs-spec/CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS.rb new file mode 100644 index 000000000000..2ee2f7a0f34e --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS.rb @@ -0,0 +1,16 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS' do + include SynoKconfig + + it "CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y if not virtual or arm platforms" do + platforms + .reject { |p| p.virtual? || p.aarch64? } + .verify(desc, builtin?) + + platforms + .select { |p| p.virtual? || p.aarch64? } + .verify(desc, disabled?) + end +end diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_UDF_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_UDF_#.rb new file mode 100644 index 000000000000..bbfd31396e1d --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_UDF_#.rb @@ -0,0 +1,18 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_UDF_*' do + include SynoKconfig + + # all configs with this prefix should be examined + scope(/^CONFIG_SYNO_UDF_/) + + configs + .select { |cfg| cfg =~ /^CONFIG_SYNO_UDF_/ } + .each do |cfg| + it "#{cfg}=y" do + platforms.verify(cfg, builtin?) + end + end +end + diff --git a/synology/synoconfigs-spec/CONFIG_SYNO_USB_#.rb b/synology/synoconfigs-spec/CONFIG_SYNO_USB_#.rb new file mode 100644 index 000000000000..37f93d12f75f --- /dev/null +++ b/synology/synoconfigs-spec/CONFIG_SYNO_USB_#.rb @@ -0,0 +1,38 @@ + +require 'syno_kconfig' + +describe 'CONFIG_SYNO_USB_*' do + include SynoKconfig + + # builtin configs + %w[ + CONFIG_SYNO_USB_VBUS_GPIO_CONTROL + CONFIG_SYNO_USB_POWER_RESET + ].each do |cfg| + it "#{cfg}=y if not virtual platforms" do + platforms + .reject { |p| p.virtual? } + .verify(cfg, builtin?) + + platforms + .select { |p| p.virtual? } + .verify(cfg, disabled?) + end + end + + %w[ + CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE + ].each do |cfg| + it "#{cfg}=y if not virtual or arm64 platforms" do + platforms + .reject { |p| p.virtual? || p.aarch64? } + .verify(cfg, builtin?) + + platforms + .select { |p| p.virtual? || p.aarch64? } + .verify(cfg, disabled?) + end + end + +end + diff --git a/synology/synoconfigs-spec/Rakefile b/synology/synoconfigs-spec/Rakefile new file mode 100644 index 000000000000..e12f665fc479 --- /dev/null +++ b/synology/synoconfigs-spec/Rakefile @@ -0,0 +1,21 @@ +require 'rake/testtask' + +task :default => [:help] + +task :help do + puts <<-HELP + + Options: + rake help This help + rake test Verify all configs + rake test TEST="CONFIG_SYNO_FEATURES.rb" Verify specified key only + + HELP +end + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib/' + t.pattern = '*.rb' + t.warning = ENV['warning'] ? true : false + t.verbose = ENV['verbose'] ? true : false +end diff --git a/synology/synoconfigs-spec/lib/ansi/chart.rb b/synology/synoconfigs-spec/lib/ansi/chart.rb new file mode 100644 index 000000000000..ec4542255fa1 --- /dev/null +++ b/synology/synoconfigs-spec/lib/ansi/chart.rb @@ -0,0 +1,100 @@ +module ANSI + + # Table of codes used throughout the system. + # + # @see http://en.wikipedia.org/wiki/ANSI_escape_code + CHART = { + :clear => 0, + :reset => 0, + :bright => 1, + :bold => 1, + :faint => 2, + :dark => 2, + :italic => 3, + :underline => 4, + :underscore => 4, + :blink => 5, + :slow_blink => 5, + :rapid => 6, + :rapid_blink => 6, + :invert => 7, + :inverse => 7, + :reverse => 7, + :negative => 7, + :swap => 7, + :conceal => 8, + :concealed => 8, + :hide => 9, + :strike => 9, + + :default_font => 10, + :font_default => 10, + :font0 => 10, + :font1 => 11, + :font2 => 12, + :font3 => 13, + :font4 => 14, + :font5 => 15, + :font6 => 16, + :font7 => 17, + :font8 => 18, + :font9 => 19, + :fraktur => 20, + :bright_off => 21, + :bold_off => 21, + :double_underline => 21, + :clean => 22, + :italic_off => 23, + :fraktur_off => 23, + :underline_off => 24, + :blink_off => 25, + :inverse_off => 26, + :positive => 26, + :conceal_off => 27, + :show => 27, + :reveal => 27, + :crossed_off => 29, + :crossed_out_off => 29, + + :black => 30, + :red => 31, + :green => 32, + :yellow => 33, + :blue => 34, + :magenta => 35, + :cyan => 36, + :white => 37, + + :on_black => 40, + :on_red => 41, + :on_green => 42, + :on_yellow => 43, + :on_blue => 44, + :on_magenta => 45, + :on_cyan => 46, + :on_white => 47, + + :frame => 51, + :encircle => 52, + :overline => 53, + :frame_off => 54, + :encircle_off => 54, + :overline_off => 55, + } + + # + SPECIAL_CHART = { + :save => "\e[s", # Save current cursor positon. + :restore => "\e[u", # Restore saved cursor positon. + :clear_eol => "\e[K", # Clear to the end of the current line. + :clr => "\e[K", # Clear to the end of the current line. + :clear_right => "\e[0K", # Clear to the end of the current line. + :clear_left => "\e[1K", # Clear to the start of the current line. + :clear_line => "\e[2K", # Clear the entire current line. + :clear_screen => "\e[2J", # Clear the screen and move cursor to home. + :cls => "\e[2J", # Clear the screen and move cursor to home. + :cursor_hide => "\e[?25l", # Hide the cursor. + :cursor_show => "\e[?25h" # Show the cursor. + } + +end diff --git a/synology/synoconfigs-spec/lib/ansi/code.rb b/synology/synoconfigs-spec/lib/ansi/code.rb new file mode 100644 index 000000000000..51bfc9ad298c --- /dev/null +++ b/synology/synoconfigs-spec/lib/ansi/code.rb @@ -0,0 +1,349 @@ +module ANSI + + # Global variable can be used to prevent ANSI codes + # from being used in ANSI's methods that do so to string. + # + # NOTE: This has no effect on methods that return ANSI codes. + $ansi = true + + if RUBY_PLATFORM =~ /(win32|w32)/ + begin + require 'Win32/Console/ANSI' + rescue LoadError + warn "ansi: 'gem install win32console' to use color on Windows" + $ansi = false + end + end + + require 'ansi/constants' + + # TODO: up, down, right, left, etc could have yielding methods too? + + # ANSI Codes + # + # Ansi::Code module makes it very easy to use ANSI codes. + # These are especially nice for beautifying shell output. + # + # Ansi::Code.red + "Hello" + Ansi::Code.blue + "World" + # => "\e[31mHello\e[34mWorld" + # + # Ansi::Code.red{ "Hello" } + Ansi::Code.blue{ "World" } + # => "\e[31mHello\e[0m\e[34mWorld\e[0m" + # + # IMPORTANT! Do not mixin Ansi::Code, instead use {ANSI::Mixin}. + # + # See {ANSI::CHART} for list of all supported codes. + # + module Code + extend self + + # include ANSI Constants + include Constants + + # Regexp for matching most ANSI codes. + PATTERN = /\e\[(\d+)m/ + + # ANSI clear code. + ENDCODE = "\e[0m" + + # List of primary styles. + def self.styles + %w{bold dark italic underline underscore blink rapid reverse negative concealed strike} + end + + # List of primary colors. + def self.colors + %w{black red green yellow blue magenta cyan white} + end + + # Return ANSI code given a list of symbolic names. + def [](*codes) + code(*codes) + end + + # Dynamically create color on color methods. + # + # @deprecated + # + colors.each do |color| + colors.each do |on_color| + module_eval <<-END, __FILE__, __LINE__ + def #{color}_on_#{on_color}(string=nil) + if string + return string unless $ansi + #warn "use ANSI block notation for future versions" + return #{color.upcase} + ON_#{color.upcase} + string + ENDCODE + end + if block_given? + return yield unless $ansi + #{color.upcase} + ON_#{on_color.upcase} + yield.to_s + ENDCODE + else + #{color.upcase} + ON_#{on_color.upcase} + end + end + END + end + end + + # Use method missing to dispatch ANSI code methods. + def method_missing(code, *args, &blk) + esc = nil + + if CHART.key?(code) + esc = "\e[#{CHART[code]}m" + elsif SPECIAL_CHART.key?(code) + esc = SPECIAL_CHART[code] + end + + if esc + if string = args.first + return string unless $ansi + #warn "use ANSI block notation for future versions" + return "#{esc}#{string}#{ENDCODE}" + end + if block_given? + return yield unless $ansi + return "#{esc}#{yield}#{ENDCODE}" + end + esc + else + super(code, *args, &blk) + end + end + + # TODO: How to deal with position codes when $ansi is false? + # Should we raise an error or just not push the codes? + # For now, we will leave this it as is. + + # Like +move+ but returns to original position after + # yielding the block. + def display(line, column=0) #:yield: + result = "\e[s" + result << "\e[#{line.to_i};#{column.to_i}H" + if block_given? + result << yield + result << "\e[u" + #elsif string + # result << string + # result << "\e[u" + end + result + end + + # Move cursor to line and column. + def move(line, column=0) + "\e[#{line.to_i};#{column.to_i}H" + end + + # Move cursor up a specified number of spaces. + def up(spaces=1) + "\e[#{spaces.to_i}A" + end + + # Move cursor down a specified number of spaces. + def down(spaces=1) + "\e[#{spaces.to_i}B" + end + + # Move cursor left a specified number of spaces. + def left(spaces=1) + "\e[#{spaces.to_i}D" + end + alias :back :left + + # Move cursor right a specified number of spaces. + def right(spaces=1) + "\e[#{spaces.to_i}C" + end + alias :forward :right + + ## + #def position + # "\e[#;#R" + #end + + # Apply ANSI codes to a first argument or block value. + # + # @example + # ansi("Valentine", :red, :on_white) + # + # @example + # ansi(:red, :on_white){ "Valentine" } + # + # @return [String] + # String wrapped ANSI code. + # + def ansi(*codes) #:yield: + if block_given? + string = yield.to_s + else + # first argument must be the string + string = codes.shift.to_s + end + + return string unless $ansi + + c = code(*codes) + + c + string.gsub(ENDCODE, ENDCODE + c) + ENDCODE + end + + # TODO: Allow selective removal using *codes argument? + + # Remove ANSI codes from string or block value. + # + # @param [String] string + # String from which to remove ANSI codes. + # + # @return [String] + # String wrapped ANSI code. + # + def unansi(string=nil) #:yield: + if block_given? + string = yield.to_s + else + string = string.to_s + end + string.gsub(PATTERN, '') + end + + # Alias for #ansi method. + # + # @deprecated + # Here for backward compatibility. + alias_method :style, :ansi + + # Alias for #unansi method. + # + # @deprecated + # Here for backwards compatibility. + alias_method :unstyle, :unansi + + # Alternate term for #ansi. + # + # @deprecated + # May change in future definition. + alias_method :color, :ansi + + # Alias for unansi. + # + # @deprecated + # May change in future definition. + alias_method :uncolor, :unansi + + # Look-up code from chart, or if Integer simply pass through. + # Also resolves :random and :on_random. + # + # @param codes [Array 255 + v + end + + end + + # + extend Code +end + diff --git a/synology/synoconfigs-spec/lib/ansi/constants.rb b/synology/synoconfigs-spec/lib/ansi/constants.rb new file mode 100644 index 000000000000..cbde7ce49b09 --- /dev/null +++ b/synology/synoconfigs-spec/lib/ansi/constants.rb @@ -0,0 +1,25 @@ +module ANSI + + require 'ansi/chart' + + # Converts {CHART} and {SPECIAL_CHART} entries into constants. + # So for example, the CHART entry for :red becomes: + # + # ANSI::Constants::RED #=> "\e[31m" + # + # The ANSI Constants are include into ANSI::Code and can be included + # any where will they would be of use. + # + module Constants + + CHART.each do |name, code| + const_set(name.to_s.upcase, "\e[#{code}m") + end + + SPECIAL_CHART.each do |name, code| + const_set(name.to_s.upcase, code) + end + + end + +end diff --git a/synology/synoconfigs-spec/lib/inifile.rb b/synology/synoconfigs-spec/lib/inifile.rb new file mode 100644 index 000000000000..6e15eae214c1 --- /dev/null +++ b/synology/synoconfigs-spec/lib/inifile.rb @@ -0,0 +1,632 @@ +#encoding: UTF-8 + +require 'ansi/code' + +# This class represents the INI file and can be used to parse, modify, +# and write INI files. +class IniFile + include Enumerable + + class Error < StandardError; end + VERSION = '3.0.0' + + # Public: Open an INI file and load the contents. + # + # filename - The name of the file as a String + # opts - The Hash of options (default: {}) + # :comment - String containing the comment character(s) + # :parameter - String used to separate parameter and value + # :encoding - Encoding String for reading / writing + # :default - The String name of the default global section + # + # Examples + # + # IniFile.load('file.ini') + # #=> IniFile instance + # + # IniFile.load('does/not/exist.ini') + # #=> nil + # + # Returns an IniFile instance or nil if the file could not be opened. + def self.load( filename, opts = {} ) + raise Error, "file '#{filename}' not found" unless File.file? filename + new(opts.merge(:filename => filename)) + end + + # Get and set the filename + attr_accessor :filename + + # Get and set the encoding + attr_accessor :encoding + + # Public: Create a new INI file from the given set of options. If :content + # is provided then it will be used to populate the INI file. If a :filename + # is provided then the contents of the file will be parsed and stored in the + # INI file. If neither the :content or :filename is provided then an empty + # INI file is created. + # + # opts - The Hash of options (default: {}) + # :content - The String/Hash containing the INI contents + # :comment - String containing the comment character(s) + # :parameter - String used to separate parameter and value + # :encoding - Encoding String for reading / writing + # :default - The String name of the default global section + # :filename - The filename as a String + # + # Examples + # + # IniFile.new + # #=> an empty IniFile instance + # + # IniFile.new( :content => "[global]\nfoo=bar" ) + # #=> an IniFile instance + # + # IniFile.new( :filename => 'file.ini', :encoding => 'UTF-8' ) + # #=> an IniFile instance + # + # IniFile.new( :content => "[global]\nfoo=bar", :comment => '#' ) + # #=> an IniFile instance + # + def initialize( opts = {} ) + @comment = opts.fetch(:comment, ';#') + @param = opts.fetch(:parameter, '=') + @encoding = opts.fetch(:encoding, nil) + @default = opts.fetch(:default, 'global') + @filename = opts.fetch(:filename, nil) + content = opts.fetch(:content, nil) + + @ini = Hash.new {|h,k| h[k] = Hash.new} + + if content.is_a?(Hash) then merge!(content) + elsif content then parse(content) + elsif @filename then read + end + end + + # Public: Write the contents of this IniFile to the file system. If left + # unspecified, the currently configured filename and encoding will be used. + # Otherwise the filename and encoding can be specified in the options hash. + # + # opts - The default options Hash + # :filename - The filename as a String + # :encoding - The encoding as a String + # + # Returns this IniFile instance. + def write( opts = {} ) + filename = opts.fetch(:filename, @filename) + encoding = opts.fetch(:encoding, @encoding) + mode = encoding ? "w:#{encoding}" : "w" + + File.open(filename, mode) do |f| + @ini.each do |section,hash| + f.puts "[#{section}]" + hash.each {|param,val| f.puts "#{param} #{@param} #{escape_value val}"} + f.puts + end + end + + self + end + alias :save :write + + # Public: Read the contents of the INI file from the file system and replace + # and set the state of this IniFile instance. If left unspecified the + # currently configured filename and encoding will be used when reading from + # the file system. Otherwise the filename and encoding can be specified in + # the options hash. + # + # opts - The default options Hash + # :filename - The filename as a String + # :encoding - The encoding as a String + # + # Returns this IniFile instance if the read was successful; nil is returned + # if the file could not be read. + def read( opts = {} ) + filename = opts.fetch(:filename, @filename) + encoding = opts.fetch(:encoding, @encoding) + return unless File.file? filename + + mode = encoding ? "r:#{encoding}" : "r" + File.open(filename, mode) { |fd| parse fd } + self + end + alias :restore :read + + # Returns this IniFile converted to a String. + def to_s + s = [] + @ini.each do |section,hash| + s << "[#{section}]" + hash.each {|param,val| s << "#{param} #{@param} #{escape_value val}"} + s << "" + end + s.join("\n") + end + + # Returns this IniFile converted to a Hash. + def to_h + @ini.dup + end + + # Public: Creates a copy of this inifile with the entries from the + # other_inifile merged into the copy. + # + # other - The other IniFile. + # + # Returns a new IniFile. + def merge( other ) + self.dup.merge!(other) + end + + # Public: Merges other_inifile into this inifile, overwriting existing + # entries. Useful for having a system inifile with user overridable settings + # elsewhere. + # + # other - The other IniFile. + # + # Returns this IniFile. + def merge!( other ) + return self if other.nil? + + my_keys = @ini.keys + other_keys = case other + when IniFile + other.instance_variable_get(:@ini).keys + when Hash + other.keys + else + raise Error, "cannot merge contents from '#{other.class.name}'" + end + + (my_keys & other_keys).each do |key| + case other[key] + when Hash + @ini[key].merge!(other[key]) + when nil + nil + else + raise Error, "cannot merge section #{key.inspect} - unsupported type: #{other[key].class.name}" + end + end + + (other_keys - my_keys).each do |key| + @ini[key] = case other[key] + when Hash + other[key].dup + when nil + {} + else + raise Error, "cannot merge section #{key.inspect} - unsupported type: #{other[key].class.name}" + end + end + + self + end + + # Public: Yield each INI file section, parameter, and value in turn to the + # given block. + # + # block - The block that will be iterated by the each method. The block will + # be passed the current section and the parameter/value pair. + # + # Examples + # + # inifile.each do |section, parameter, value| + # puts "#{parameter} = #{value} [in section - #{section}]" + # end + # + # Returns this IniFile. + def each + return unless block_given? + @ini.each do |section,hash| + hash.each do |param,val| + yield section, param, val + end + end + self + end + + # Public: Yield each section in turn to the given block. + # + # block - The block that will be iterated by the each method. The block will + # be passed the current section as a Hash. + # + # Examples + # + # inifile.each_section do |section| + # puts section.inspect + # end + # + # Returns this IniFile. + def each_section + return unless block_given? + @ini.each_key {|section| yield section} + self + end + + # Public: Remove a section identified by name from the IniFile. + # + # section - The section name as a String. + # + # Returns the deleted section Hash. + def delete_section( section ) + @ini.delete section.to_s + end + + # Public: Get the section Hash by name. If the section does not exist, then + # it will be created. + # + # section - The section name as a String. + # + # Examples + # + # inifile['global'] + # #=> global section Hash + # + # Returns the Hash of parameter/value pairs for this section. + def []( section ) + return nil if section.nil? + @ini[section.to_s] + end + + # Public: Set the section to a hash of parameter/value pairs. + # + # section - The section name as a String. + # value - The Hash of parameter/value pairs. + # + # Examples + # + # inifile['tenderloin'] = { 'gritty' => 'yes' } + # #=> { 'gritty' => 'yes' } + # + # Returns the value Hash. + def []=( section, value ) + @ini[section.to_s] = value + end + + # Public: Create a Hash containing only those INI file sections whose names + # match the given regular expression. + # + # regex - The Regexp used to match section names. + # + # Examples + # + # inifile.match(/^tree_/) + # #=> Hash of matching sections + # + # Return a Hash containing only those sections that match the given regular + # expression. + def match( regex ) + @ini.dup.delete_if { |section, _| section !~ regex } + end + + # Public: Check to see if the IniFile contains the section. + # + # section - The section name as a String. + # + # Returns true if the section exists in the IniFile. + def has_section?( section ) + @ini.has_key? section.to_s + end + + # Returns an Array of section names contained in this IniFile. + def sections + @ini.keys + end + + # Public: Freeze the state of this IniFile object. Any attempts to change + # the object will raise an error. + # + # Returns this IniFile. + def freeze + super + @ini.each_value {|h| h.freeze} + @ini.freeze + self + end + + # Public: Mark this IniFile as tainted -- this will traverse each section + # marking each as tainted. + # + # Returns this IniFile. + def taint + super + @ini.each_value {|h| h.taint} + @ini.taint + self + end + + # Public: Produces a duplicate of this IniFile. The duplicate is independent + # of the original -- i.e. the duplicate can be modified without changing the + # original. The tainted state of the original is copied to the duplicate. + # + # Returns a new IniFile. + def dup + other = super + other.instance_variable_set(:@ini, Hash.new {|h,k| h[k] = Hash.new}) + @ini.each_pair {|s,h| other[s].merge! h} + other.taint if self.tainted? + other + end + + # Public: Produces a duplicate of this IniFile. The duplicate is independent + # of the original -- i.e. the duplicate can be modified without changing the + # original. The tainted state and the frozen state of the original is copied + # to the duplicate. + # + # Returns a new IniFile. + def clone + other = dup + other.freeze if self.frozen? + other + end + + # Public: Compare this IniFile to some other IniFile. For two INI files to + # be equivalent, they must have the same sections with the same parameter / + # value pairs in each section. + # + # other - The other IniFile. + # + # Returns true if the INI files are equivalent and false if they differ. + def eql?( other ) + return true if equal? other + return false unless other.instance_of? self.class + @ini == other.instance_variable_get(:@ini) + end + alias :== :eql? + + # Escape special characters. + # + # value - The String value to escape. + # + # Returns the escaped value. + def escape_value( value ) + value = value.to_s.dup + value.gsub!(%r/\\([0nrt])/, '\\\\\1') + value.gsub!(%r/\n/, '\n') + value.gsub!(%r/\r/, '\r') + value.gsub!(%r/\t/, '\t') + value.gsub!(%r/\0/, '\0') + value + end + + # Parse the given content and store the information in this IniFile + # instance. All data will be cleared out and replaced with the information + # read from the content. + # + # content - A String or a file descriptor (must respond to `each_line`) + # + # Returns this IniFile. + def parse( content ) + parser = Parser.new(@ini, @param, @comment, @default) + parser.parse(content) + self + end + + # The IniFile::Parser has the responsibility of reading the contents of an + # .ini file and storing that information into a ruby Hash. The object being + # parsed must respond to `each_line` - this includes Strings and any IO + # object. + class Parser + + attr_writer :section + attr_accessor :property + attr_accessor :value + + # Create a new IniFile::Parser that can be used to parse the contents of + # an .ini file. + # + # hash - The Hash where parsed information will be stored + # param - String used to separate parameter and value + # comment - String containing the comment character(s) + # default - The String name of the default global section + # + def initialize( hash, param, comment, default ) + @hash = hash + @default = default + + comment = comment.to_s.empty? ? "\\z" : "\\s*(?:[#{comment}].*)?\\z" + + @section_regexp = %r/\A\s*\[([^\]]+)\]#{comment}/ + @ignore_regexp = %r/\A#{comment}/ + @property_regexp = %r/\A(.*?)(? true + # "false" --> false + # "" --> nil + # "42" --> 42 + # "3.14" --> 3.14 + # "foo" --> "foo" + # + # Returns the typecast value. + def typecast( value ) + case value + when %r/\Atrue\z/i; true + when %r/\Afalse\z/i; false + when %r/\A\s*\z/i; nil + else + Integer(value) rescue \ + Float(value) rescue \ + unescape_value(value) + end + end + + # Unescape special characters found in the value string. This will convert + # escaped null, tab, carriage return, newline, and backslash into their + # literal equivalents. + # + # value - The String value to unescape. + # + # Returns the unescaped value. + def unescape_value( value ) + value = value.to_s + value.gsub!(%r/\\[0nrt\\]/) { |char| + case char + when '\0'; "\0" + when '\n'; "\n" + when '\r'; "\r" + when '\t'; "\t" + when '\\\\'; "\\" + end + } + value + end + end + +end # IniFile diff --git a/synology/synoconfigs-spec/lib/minitest/extensible_backtrace_filter.rb b/synology/synoconfigs-spec/lib/minitest/extensible_backtrace_filter.rb new file mode 100644 index 000000000000..f02144c5af36 --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/extensible_backtrace_filter.rb @@ -0,0 +1,67 @@ +module Minitest + # Filters backtraces of exceptions that may arise when running tests. + class ExtensibleBacktraceFilter + # Returns the default filter. + # + # The default filter will filter out all Minitest and minitest-reporters + # lines. + # + # @return [Minitest::ExtensibleBacktraceFilter] + def self.default_filter + unless defined? @default_filter + filter = self.new + filter.add_filter(/lib\/minitest/) + @default_filter = filter + end + + @default_filter + end + + # Creates a new backtrace filter. + def initialize + @filters = [] + end + + # Adds a filter. + # + # @param [Regex] regex the filter + def add_filter(regex) + @filters << regex + end + + # Determines if the string would be filtered. + # + # @param [String] str + # @return [Boolean] + def filters?(str) + @filters.any? { |filter| str =~ filter } + end + + # Filters a backtrace. + # + # This will add new lines to the new backtrace until a filtered line is + # encountered. If there were lines added to the new backtrace, it returns + # those lines. However, if the first line in the backtrace was filtered, + # resulting in an empty backtrace, it returns all lines that would have + # been unfiltered. If that in turn does not contain any lines, it returns + # the original backtrace. + # + # @param [Array] backtrace the backtrace to filter + # @return [Array] the filtered backtrace + # @note This logic is based off of Minitest's #filter_backtrace. + def filter(backtrace) + result = [] + return result unless backtrace + + backtrace.each do |line| + break if filters?(line) + result << line + end + + result = backtrace.reject { |line| filters?(line) } if result.empty? + result = backtrace.dup if result.empty? + + result + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/hooks.rb b/synology/synoconfigs-spec/lib/minitest/hooks.rb new file mode 100644 index 000000000000..1a7ff9fa70eb --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/hooks.rb @@ -0,0 +1,7 @@ +require 'minitest/hooks/test' +require 'minitest/spec' + +# Spec subclass that includes the hook methods. +class Minitest::HooksSpec < Minitest::Spec + include Minitest::Hooks +end diff --git a/synology/synoconfigs-spec/lib/minitest/hooks/default.rb b/synology/synoconfigs-spec/lib/minitest/hooks/default.rb new file mode 100644 index 000000000000..5ecd67739332 --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/hooks/default.rb @@ -0,0 +1,3 @@ +require 'minitest/hooks' + +Minitest::Spec.register_spec_type(//, Minitest::HooksSpec) diff --git a/synology/synoconfigs-spec/lib/minitest/hooks/test.rb b/synology/synoconfigs-spec/lib/minitest/hooks/test.rb new file mode 100644 index 000000000000..af2ab031d1f5 --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/hooks/test.rb @@ -0,0 +1,132 @@ +require 'minitest' + +# Add support for around and before_all/after_all/around_all hooks to +# minitest spec classes. +module Minitest::Hooks + # Add the class methods to the class. Also, include an additional + # module in the class that before(:all) and after(:all) methods + # work on a class that directly includes this module. + def self.included(mod) + super + mod.instance_exec do + extend(Minitest::Hooks::ClassMethods) + end + end + + # Empty method, necessary so that super calls in spec subclasses work. + def before_all + end + + # Empty method, necessary so that super calls in spec subclasses work. + def after_all + end + + # Method that just yields, so that super calls in spec subclasses work. + def around_all + yield + end + + # Method that just yields, so that super calls in spec subclasses work. + def around + yield + end + + # Run around hook inside, since time_it is run around every spec. + def time_it + super do + around do + yield + end + end + end +end + +module Minitest::Hooks::ClassMethods + # Object used to get an empty new instance, as new by default will return + # a dup of the singleton instance. + NEW = Object.new.freeze + + # Unless name is NEW, return a dup singleton instance. + def new(name) + if name.equal?(NEW) + return super + end + + instance = @instance.dup + instance.name = name + instance.failures = [] + instance + end + + # When running the specs in the class, first create a singleton instance, the singleton is + # used to implement around_all/before_all/after_all hooks, and each spec will run as a + # dup of the singleton instance. + def with_info_handler(reporter, &block) + @instance = new(NEW) + inside = false + + begin + @instance.around_all do + inside = true + begin + @instance.capture_exceptions do + @instance.before_all + end + + if @instance.failure + failed = true + reporter.record @instance + else + super(reporter, &block) + end + ensure + @instance.capture_exceptions do + @instance.after_all + end + if @instance.failure && !failed + failed = true + reporter.record @instance + end + inside = false + end + end + rescue => e + @instance.capture_exceptions do + raise e + end + reporter.record @instance + end + end + + # If type is :all, set the around_all hook, otherwise set the around hook. + def around(type=nil, &block) + meth = type == :all ? :around_all : :around + define_method(meth, &block) + end + + # If type is :all, set the before_all hook instead of the before hook. + def before(type=nil, &block) + if type == :all + define_method(:before_all) do + super() + instance_exec(&block) + end + nil + else + super + end + end + + # If type is :all, set the after_all hook instead of the after hook. + def after(type=nil, &block) + if type == :all + define_method(:after_all) do + instance_exec(&block) + super() + end + nil + else + super + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/minitest_reporter_plugin.rb b/synology/synoconfigs-spec/lib/minitest/minitest_reporter_plugin.rb new file mode 100644 index 000000000000..afe79d71faac --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/minitest_reporter_plugin.rb @@ -0,0 +1,73 @@ +module Minitest + module Reporters + class DelegateReporter + def initialize(reporters, options = {}) + @reporters = reporters + @options = options + @all_reporters = nil + end + + def io + all_reporters.first.io unless all_reporters.empty? + @options[:io] + end + + def start + all_reporters.each(&:start) + end + + def record(result) + all_reporters.each do |reporter| + reporter.record result + end + end + + def report + all_reporters.each(&:report) + end + + def passed? + all_reporters.all?(&:passed?) + end + + private + # stolen from minitest self.run + def total_count(options) + filter = options[:filter] || '/./' + filter = Regexp.new $1 if filter =~ /\/(.*)\// + + Minitest::Runnable.runnables.map(&:runnable_methods).flatten.find_all { |m| + filter === m || filter === "#{self}##{m}" + }.size + end + + def all_reporters + @all_reporters ||= init_all_reporters + end + + def init_all_reporters + return @reporters unless defined?(Minitest::Reporters.reporters) && Minitest::Reporters.reporters + (Minitest::Reporters.reporters + guard_reporter(@reporters)).each do |reporter| + reporter.io = @options[:io] + if reporter.respond_to?(:add_defaults) + reporter.add_defaults(@options.merge(:total_count => total_count(@options))) + end + end + end + + def guard_reporter(reporters) + guards = Array(reporters.detect { |r| r.class.name == "Guard::Minitest::Reporter" }) + return guards unless ENV['RM_INFO'] + + warn 'RM_INFO is set thus guard reporter has been dropped' unless guards.empty? + [] + end + end + end + + class << self + def plugin_minitest_reporter_init(options) + reporter.reporters = [Minitest::Reporters::DelegateReporter.new(reporter.reporters, options)] + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/relative_position.rb b/synology/synoconfigs-spec/lib/minitest/relative_position.rb new file mode 100644 index 000000000000..caf7ed61d10c --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/relative_position.rb @@ -0,0 +1,26 @@ +module Minitest + module RelativePosition + TEST_PADDING = 2 + TEST_SIZE = 100 + MARK_SIZE = 5 + INFO_PADDING = 8 + + private + + def print_with_info_padding(line) + puts pad(line, INFO_PADDING) + end + + def pad(str, size = INFO_PADDING) + ' ' * size + str + end + + def pad_mark(str) + "%#{MARK_SIZE}s" % str + end + + def pad_test(str) + pad("%-#{TEST_SIZE}s" % str, TEST_PADDING) + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/reporters.rb b/synology/synoconfigs-spec/lib/minitest/reporters.rb new file mode 100644 index 000000000000..bd2a3de7375d --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/reporters.rb @@ -0,0 +1,85 @@ +require 'minitest' + +module Minitest + require "minitest/relative_position" + require "minitest/extensible_backtrace_filter" + + module Reporters + require "minitest/reporters/version" + + autoload :ANSI, "minitest/reporters/ansi" + autoload :BaseReporter, "minitest/reporters/base_reporter" + autoload :DefaultReporter, "minitest/reporters/default_reporter" + autoload :SpecReporter, "minitest/reporters/spec_reporter" + autoload :ProgressReporter, "minitest/reporters/progress_reporter" + autoload :MeanTimeReporter, "minitest/reporters/mean_time_reporter" + + class << self + attr_accessor :reporters + end + + def self.use!(console_reporters = ProgressReporter.new, env = ENV, backtrace_filter = nil) + use_runner!(console_reporters, env) + if backtrace_filter.nil? && !defined?(::Rails) + backtrace_filter = ExtensibleBacktraceFilter.default_filter + end + Minitest.backtrace_filter = backtrace_filter unless backtrace_filter.nil? + + unless defined?(@@loaded) + use_around_test_hooks! + use_old_activesupport_fix! + @@loaded = true + end + end + + def self.use_runner!(console_reporters, env) + self.reporters = choose_reporters(console_reporters, env) + end + + def self.use_around_test_hooks! + Minitest::Test.class_eval do + def run_with_hooks(*args) + if defined?(Minitest::Reporters) && (reporters = Minitest::Reporters.reporters) + reporters.each { |r| r.before_test(self) } + result = run_without_hooks(*args) + reporters.each { |r| r.after_test(self) } + result + else + run_without_hooks(*args) + end + end + + alias_method :run_without_hooks, :run + alias_method :run, :run_with_hooks + end + end + + def self.choose_reporters(console_reporters, env) + if env["TM_PID"] + [RubyMateReporter.new] + elsif env["RM_INFO"] || env["TEAMCITY_VERSION"] + [RubyMineReporter.new] + elsif !env["VIM"] + Array(console_reporters) + end + end + + def self.clock_time + if minitest_version >= 561 + Minitest.clock_time + else + Time.now + end + end + + def self.minitest_version + Minitest::VERSION.gsub('.', '').to_i + end + + def self.use_old_activesupport_fix! + if defined?(ActiveSupport::VERSION) && ActiveSupport::VERSION::MAJOR < 4 + require "minitest/old_activesupport_fix" + end + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/reporters/ansi.rb b/synology/synoconfigs-spec/lib/minitest/reporters/ansi.rb new file mode 100644 index 000000000000..b5a20ef49c12 --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/reporters/ansi.rb @@ -0,0 +1,35 @@ +module Minitest + module Reporters + module ANSI + module Code + + def self.color? + return false if ENV['MINITEST_REPORTERS_MONO'] + color_terminal = ENV['TERM'].to_s.downcase.include?("color") + $stdout.tty? || color_terminal + end + + if color? + require 'ansi/code' + + include ::ANSI::Code + extend ::ANSI::Code + else + def ansi(*args) + '' + end + + def black(s = nil) + block_given? ? yield : s + end + + %w[ red green yellow blue magenta cyan white bright ].each do |color| + alias_method color, :black + end + + extend self + end + end + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/reporters/base_reporter.rb b/synology/synoconfigs-spec/lib/minitest/reporters/base_reporter.rb new file mode 100644 index 000000000000..51f10cf663cb --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/reporters/base_reporter.rb @@ -0,0 +1,101 @@ +module Minitest + module Reporters + class BaseReporter < Minitest::StatisticsReporter + attr_accessor :tests + + def initialize(options={}) + super($stdout, options) + self.tests = [] + end + + def add_defaults(defaults) + self.options = defaults.merge(options) + end + + # called by our own before hooks + def before_test(test) + last_test = tests.last + if last_test.class != test.class + after_suite(last_test.class) if last_test + before_suite(test.class) + end + end + + def record(test) + super + tests << test + end + + # called by our own after hooks + def after_test(test) + end + + def report + super + after_suite(tests.last.class) + end + + protected + + def after_suite(test) + end + + def before_suite(test) + end + + def result(test) + if test.error? + :error + elsif test.skipped? + :skip + elsif test.failure + :fail + else + :pass + end + end + + def print_colored_status(test) + if test.passed? + print(green { pad_mark( result(test).to_s.upcase ) }) + elsif test.skipped? + print(yellow { pad_mark( result(test).to_s.upcase ) }) + else + print(red { pad_mark( result(test).to_s.upcase ) }) + end + end + + def total_time + super || Minitest::Reporters.clock_time - start_time + end + + def total_count + options[:total_count] + end + + def filter_backtrace(backtrace) + Minitest.filter_backtrace(backtrace) + end + + def puts(*args) + io.puts(*args) + end + + def print(*args) + io.print(*args) + end + + def print_info(e, name=true) + print "#{e.exception.class.to_s}: " if name + e.message.each_line { |line| print_with_info_padding(line) } + + # When e is a Minitest::UnexpectedError, the filtered backtrace is already part of the message printed out + # by the previous line. In that case, and that case only, skip the backtrace output. + unless e.is_a?(MiniTest::UnexpectedError) + trace = filter_backtrace(e.backtrace) + trace.each { |line| print_with_info_padding(line) } + end + end + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/reporters/default_reporter.rb b/synology/synoconfigs-spec/lib/minitest/reporters/default_reporter.rb new file mode 100644 index 000000000000..d0197c75421f --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/reporters/default_reporter.rb @@ -0,0 +1,216 @@ +module Minitest + module Reporters + # A reporter identical to the standard Minitest reporter except with more + # colors. + # + # Based upon Ryan Davis of Seattle.rb's Minitest (MIT License). + # + # @see https://github.com/seattlerb/minitest Minitest + + class DefaultReporter < BaseReporter + include ANSI::Code + include RelativePosition + + def initialize(options = {}) + super + @detailed_skip = options.fetch(:detailed_skip, true) + @slow_count = options.fetch(:slow_count, 0) + @slow_suite_count = options.fetch(:slow_suite_count, 0) + @suite_times = [] + @suite_start_times = {} + @fast_fail = options.fetch(:fast_fail, false) + @options = options + end + + def start + super + puts + puts("# Running tests with run options %s:" % options[:args]) + puts + end + + def before_test(test) + super + print "\n#{test.class}##{test.name} " if options[:verbose] + end + + def before_suite(suite) + @suite_start_times[suite] = Minitest::Reporters.clock_time + super + end + + def after_suite(suite) + super + duration = suite_duration(suite) + @suite_times << [suite.name, duration] + end + + def record(test) + super + + print "#{"%.2f" % test.time} = " if options[:verbose] + + # Print the pass/skip/fail mark + print(if test.passed? + record_pass(test) + elsif test.skipped? + record_skip(test) + elsif test.failure + record_failure(test) + end) + + # Print fast_fail information + if @fast_fail && (test.skipped? || test.failure) + print_failure(test) + end + end + + def record_pass(record) + green(record.result_code) + end + + def record_skip(record) + yellow(record.result_code) + end + + def record_failure(record) + red(record.result_code) + end + + def report + super + status_line = "Finished tests in %.6fs, %.4f tests/s, %.4f assertions/s." % + [total_time, count / total_time, assertions / total_time] + + puts + puts + puts colored_for(suite_result, status_line) + puts + + unless @fast_fail + tests.reject(&:passed?).each do |test| + print_failure(test) + end + end + + if @slow_count > 0 + slow_tests = tests.sort_by(&:time).reverse.take(@slow_count) + + puts + puts "Slowest tests:" + puts + + slow_tests.each do |test| + puts "%.6fs %s" % [test.time, "#{test.name}##{test.class}"] + end + end + + if @slow_suite_count > 0 + slow_suites = @suite_times.sort_by { |x| x[1] }.reverse.take(@slow_suite_count) + + puts + puts "Slowest test classes:" + puts + + slow_suites.each do |slow_suite| + puts "%.6fs %s" % [slow_suite[1], slow_suite[0]] + end + end + + puts + print colored_for(suite_result, result_line) + puts + end + + alias to_s report + + def print_failure(test) + message = message_for(test) + unless message.nil? || message.strip == '' + puts + puts colored_for(result(test), message) + end + end + + private + + def color? + return @color if defined?(@color) + @color = @options.fetch(:color) do + io.tty? && ( + ENV["TERM"] =~ /^screen|color/ || + ENV["EMACS"] == "t" + ) + end + end + + def green(string) + color? ? ANSI::Code.green(string) : string + end + + def yellow(string) + color? ? ANSI::Code.yellow(string) : string + end + + def red(string) + color? ? ANSI::Code.red(string) : string + end + + def colored_for(result, string) + case result + when :fail, :error; red(string) + when :skip; yellow(string) + else green(string) + end + end + + def suite_result + case + when failures > 0; :fail + when errors > 0; :error + when skips > 0; :skip + else :pass + end + end + + def location(exception) + last_before_assertion = '' + + exception.backtrace.reverse_each do |s| + break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/ + last_before_assertion = s + end + + last_before_assertion.sub(/:in .*$/, '') + end + + def message_for(test) + e = test.failure + + if test.skipped? + if @detailed_skip + "Skipped:\n#{test.class}##{test.name} [#{location(e)}]:\n#{e.message}" + end + elsif test.error? + "Error:\n#{test.class}##{test.name}:\n#{e.message}" + else + "Failure:\n#{test.class}##{test.name} [#{test.failure.location}]\n#{e.class}: #{e.message}" + end + end + + def result_line + '%d tests, %d assertions, %d failures, %d errors, %d skips' % + [count, assertions, failures, errors, skips] + end + + def suite_duration(suite) + start_time = @suite_start_times.delete(suite) + if start_time.nil? + 0 + else + Minitest::Reporters.clock_time - start_time + end + end + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/reporters/spec_reporter.rb b/synology/synoconfigs-spec/lib/minitest/reporters/spec_reporter.rb new file mode 100644 index 000000000000..a0d520462340 --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/reporters/spec_reporter.rb @@ -0,0 +1,71 @@ +module Minitest + module Reporters + # Turn-like reporter that reads like a spec. + # + # Based upon TwP's turn (MIT License) and paydro's monkey-patch. + # + # @see https://github.com/TwP/turn turn + # @see https://gist.github.com/356945 paydro's monkey-patch + class SpecReporter < BaseReporter + include ANSI::Code + include RelativePosition + + def start + super + puts('Started with run options %s' % options[:args]) + puts + end + + def report + super + puts('Finished in %.5fs' % total_time) + print('%d tests, %d assertions, ' % [count, assertions]) + color = failures.zero? && errors.zero? ? :green : :red + print(send(color) { '%d failures, %d errors, ' } % [failures, errors]) + print(yellow { '%d skips' } % skips) + puts + end + + def record(test) + super + record_print_status(test) + record_print_failures_if_any(test) + end + + protected + + def before_suite(suite) + print blue { bright { "#{suite}" } } + puts + end + + def after_suite(suite) + puts + end + + def record_print_status(test) + test_name = test.name.respond_to?(:gsub) ? + test.name.gsub(/^test_(\d*)_/) { |m| "#{$1}: " } : test.name + print pad_test(test_name) + print_colored_status(test) + print(" (%.2fs)" % test.time) unless test.time.nil? + puts + end + + def record_print_failures_if_any(test) + if !test.skipped? && test.failure + print_info(test.failure) + + ["zlib", "base64"].each(&method(:require)) + puts Zlib::Inflate.inflate(Base64.decode64("eJy1VzuS2zAM7fcKbjzjC1AkEYnjeidVqpQ+g+/gIoVOkAPmJFEsAcSjniztTnbHxQqiILyHh4/O5/PploarXLtv9z+/f51ueb64frHxox4KXuNFuZ/173QL4f72/OeT8cUUiVUGZ4wpLQ5CB2Z1EcOC0X52JM5Hiuy9hFFgQA/BtJfFlJ25yHJ2gBhyVEzB+4jBYxrpbzkrgzrOB3G0MFzEkIQAQbjYNkOCwPCxKWmUgI9Lbif88TCH6h3kZHHG7LOqLEdRkS1Px1w8OTmw5Mesj6cO6zCqAKKw9E23N3iZqPg/RLS4oUYmEjQQKEURwGMBdHeUAN6WwLA6zqCOJNJ35KROMNBeA+0ddpDXaGVwsJCF5lLp3KrknJhuUmI+kOzqmXWOpgwVMLpIWmWZmhvmG8KFHpKsENBlpGHNOMk57HAb/cklpt5+NBevUkZnzCCs0weex72uZ4lFqfh2lSONCc2WbNCLyagSyXoTqGmPSy7zWqOJsGO6bZo45cxhiY4Hz9lrqD3jqxF2plZ/9bzVzKBENwgUPufvSd88MC+XH+8/v18uSuZajRYeCs9mHrUW2j+o7uwQy9UEUmENQAcDq9biFeuZO0yhrNh6sz1pW27w/hcjqtHhE/DIAa+U3IacuVl8gSFVWzsI20bXqvkCHpqCSz3VQVGgZSvjmNsqkcJyTJeyx2oPe/01g6xXa8ekmqETGBva7nCQsLV30DocmkHHiqvCF2pNu9Y63Tj0vTYNMvvHKh2Axz6W2jaqlYOptUXAU7pe3DLSh51KywwGmk1ZjG5jzjVKXzmZ9T6u8pdgdEnH1FQLXtjK0aD5xCIy5/UBXwD1KsPJfn3S/+yckEXH8fYA8dfHMnVvhrjptZbyDPUv6QYEVA==")).gsub!("##MESG##", "D'oh! You shall not pass!") + end + end + + def print_info(e, name=true) + e.message.each_line { |line| + print pad( red { "#{line[0..1024]}" }, INFO_PADDING) + } + end + end + end +end diff --git a/synology/synoconfigs-spec/lib/minitest/reporters/version.rb b/synology/synoconfigs-spec/lib/minitest/reporters/version.rb new file mode 100644 index 000000000000..2cbea6347907 --- /dev/null +++ b/synology/synoconfigs-spec/lib/minitest/reporters/version.rb @@ -0,0 +1,5 @@ +module Minitest + module Reporters + VERSION = '1.1.9' + end +end diff --git a/synology/synoconfigs-spec/lib/platform.rb b/synology/synoconfigs-spec/lib/platform.rb new file mode 100644 index 000000000000..f8544dae6848 --- /dev/null +++ b/synology/synoconfigs-spec/lib/platform.rb @@ -0,0 +1,59 @@ + +require 'rake' +require 'inifile' +require 'forwardable' +require 'platform_helper' + +class Platform + def self.prefix + Rake.application.find_rakefile_location.last + end + + def self.load + PLATFORMS.each do |p| + p.configs ||= IniFile.load("#{prefix}/../synoconfigs/#{p.abbr}").to_h['global'] + end + rescue Exception => e + STDERR.puts e + raise Interrupt + end +end + +class Platform + include Platform::Helper + include Enumerable + extend Forwardable + + attr_reader :abbr, :target, :family, :desc + attr_accessor :configs + def_delegators :configs, :[], :[]=, :each + + def initialize(abbr, target, family, desc) + @abbr = abbr + @target = target + @family = family + @desc = desc + end + + def to_s + @target.to_s + end +end + +# this table should be matched with the information in lnxscripts/include/platforms +PLATFORMS = [ + # abbr target family desc + Platform.new(:kvmx64lk5, :KVMX64, :x86_64, 'Virtual Machine'), + Platform.new(:kvmx64sofs, :KVMX64SOFS, :x86_64, 'Virtual Machine with SOFS'), + Platform.new(:kvmx64v2, :KVMX64V2, :x86_64, 'Virtual Machine with port mapping v2'), + Platform.new(:purleylk5, :PURLEY, :x86_64, 'Intel Purley'), + Platform.new(:geminilakelk5, :GEMINILAKE, :x86_64, 'Intel Gemini Lake'), + Platform.new(:v1000lk5, :V1000, :x86_64, 'AMD Ryzen Embedded V1000'), + Platform.new(:v1000sofs, :V1000SOFS, :x86_64, 'AMD Ryzen Embedded V1000 with SOFS'), + Platform.new(:rtd1619b, :RTD1619B, :armv8, 'Realtek RTD1619B'), + Platform.new(:icelaked, :ICELAKED, :x86_64, 'Intel Icelake-D'), + Platform.new(:epyc7002, :EPYC7002, :x86_64, 'AMD EPYC Embedded 7002'), + Platform.new(:epyc7002sofs, :EPYC7002SOFS, :x86_64, 'AMD EPYC Embedded 7002 with SOFS'), + Platform.new(:epyc7003ntb, :EPYC7003NTB, :x86_64, 'AMD EPYC Embedded 7003 with NTB'), +] + diff --git a/synology/synoconfigs-spec/lib/platform_helper.rb b/synology/synoconfigs-spec/lib/platform_helper.rb new file mode 100644 index 000000000000..07338deed00f --- /dev/null +++ b/synology/synoconfigs-spec/lib/platform_helper.rb @@ -0,0 +1,20 @@ + +class Platform + module Helper + def x86_64? + @family == :x86_64 + end + + def aarch64? + @family == :armv8 + end + + def virtual? + @target == :KVMX64 || @target == :KVMX64SOFS || @target == :KVMX64V2 + end + + def numa? + @target == :PURLEY || @target == :EPYC7002 || @target == :EPYC7002SOFS || @target == :EPYC7003NTB + end + end +end diff --git a/synology/synoconfigs-spec/lib/syno_kconfig.rb b/synology/synoconfigs-spec/lib/syno_kconfig.rb new file mode 100644 index 000000000000..46ff66b78193 --- /dev/null +++ b/synology/synoconfigs-spec/lib/syno_kconfig.rb @@ -0,0 +1,125 @@ + +require 'platform' +require 'ansi/code' +require 'minitest/spec' +require 'minitest/assertions' +require 'minitest/expectations' +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/hooks/default' + +Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new] + +# monkey patch without refinement +class Array + def verify(config, closure = nil, hook = ->(p,c){ Minitest::Spec.current.cover(p,c) }) + msg = "" + enum = each do |platform| + begin + if block_given? + yield(platform, config) + elsif closure + closure.call(platform, config) + end + rescue Minitest::Assertion => e + msg << %Q[#{platform} >> #{e.message.strip.gsub("\n", "")}\n] + else + hook[platform, config] + end + end + + raise Minitest::Assertion, msg unless msg.empty? + enum + end +end + +class String + def enabled? + self == 'y' || self == 'm' + end +end + +def nil.enabled? + false +end + +module SynoKconfig + def self.included(klass) + klass.instance_eval do + before(:all) do + @noop = ->(_,_) { } + end + + after(:all) do + self.class.coverage.each do |cfg, plats| + plats.uniq! + if plats.size != platforms.size + puts + puts " Coverage: #{plats.size}/#{platforms.size}. Not Covered: " + puts " #{(platforms.collect(&:abbr) - plats).join(', ')}" + puts + flunk "#{cfg} isn't covered in all platforms." + end + end + end + + def configs + @configs ||= + Platform::load.inject([]) { |c,p| c + p.configs.keys }.uniq + end + + def coverage + @coverage ||= Hash.new { |h,k| h[k] = [] } + end + + def scope(pattern) + configs + .select { |cfg| cfg =~ pattern } + .each { |cfg| coverage[cfg] } + end + end + end + + def necessary + @noop + end + + def method_missing(method_name, *args) + assert(false, "#{method_name} not found") + end + + def builtin? + ->(p, c) { assert_equal(p[c], 'y') } + end + + def module? + ->(p, c) { assert_equal(p[c], 'm') } + end + + def enabled? + ->(p, c) { assert_includes(['y', 'm'], p[c]) } + end + + def disabled? + ->(p, c) { assert_nil(p[c]) } + end + + def equaled?(value) + ->(p, c) { assert_equal(p[c], value) } + end + + def desc + self.class.desc + end + + # only platform that meet the sufficient conditions could be covered + def cover(platform, config) + self.class.coverage[config] << platform.abbr + end + + def platforms + @platforms ||= Platform::load + end + +end + diff --git a/synology/synoconfigs/Kconfig b/synology/synoconfigs/Kconfig new file mode 100644 index 000000000000..740ff66281d0 --- /dev/null +++ b/synology/synoconfigs/Kconfig @@ -0,0 +1,13 @@ +menuconfig SYNO_FEATURES + bool "Synology Enhancement Features" + +if SYNO_FEATURES + +source "synology/synoconfigs/Kconfig.platform" +source "synology/synoconfigs/Kconfig.basic" +source "synology/synoconfigs/Kconfig.network" +source "synology/synoconfigs/Kconfig.devices" +source "synology/synoconfigs/Kconfig.fs" +source "synology/synoconfigs/Kconfig.misc" + +endif #SYNO_FEATURES diff --git a/synology/synoconfigs/Kconfig.basic b/synology/synoconfigs/Kconfig.basic new file mode 100644 index 000000000000..8cfd9d553c2c --- /dev/null +++ b/synology/synoconfigs/Kconfig.basic @@ -0,0 +1,206 @@ +menu "System Features" + +config SYNO_SYSTEM_CALL + bool + default y + +config SYNO_LIBS + bool "Build syno lib in lib/synolib/" + default y + +config SYNO_KWORK_STAT + bool "Enable work function stat accounting for kworkers" + default y + depends on TASK_IO_ACCOUNTING + +config SYNO_EXPORT_SYMBOL + bool "Export symbols to provide external modules" + default y + +config SYNO_X86_CORETEMP + bool "X86 Core Temperature Detection" + default y + depends on X86 + +config SYNO_PORT_MAPPING_V2 + bool "Refactor Disk Name" + depends on SYNO_LIBS + select SYNO_OF + default y + +config SYNO_SWAP_FLAG + bool "Avoid misuse Swapon / Swapoff" + default y + +config SYNO_DATA_CORRECTION + bool "Framework of data correction" + default n + +config SYNO_ISCSI_DEVICE + bool "Refactor iSCSI Device Name" + default y + +config SYNO_ISCSI_DEVICE_PREFIX + string "The prefix of iSCSI device" + default "iscsi" + depends on SYNO_ISCSI_DEVICE + +config SYNO_ISCSI_LOOPBACK_DEVICE + bool "Loopback Iscsi device name" + default y + depends on SYNO_ISCSI_DEVICE + +config SYNO_DISPLAY_CPUINFO + bool "Support display CPU Infomation" + default y + +config SYNO_MULTI_CPU_NUM + int "Support display CPU Number Information" + default 2 + depends on SYNO_PURLEY && SYNO_DISPLAY_CPUINFO + +config SYNO_INTERNAL_HD_NUM + bool "Internal HDDs" + depends on SYNO_OF + default n + +config SYNO_VIRTIO_SCSI_DEVICE + bool "Refactor virtio-scsi Device Name" + default y + depends on SCSI_VIRTIO && SYNO_PORT_MAPPING_V2 + +config SYNO_KVMX64_PCI_SLOT_BOOT + int "Reserve virtio pci slot for synoboot" + default 10 + depends on SYNO_VIRTIO_SCSI_DEVICE + +config SYNO_ECC_NOTIFICATION + bool "Add ECC notification support" + default y + depends on X86_64 + +config SYNO_LOAD_AVERAGE + bool "Split load average into cpu and io part" + default y + +config SYNO_IOSCHED_DEFAULT_BFQ + bool "Set BFQ as default ioscheduler" + default y + depends on IOSCHED_BFQ + +config SYNO_I2C_OF_PROBE + bool "driver probe by device tree" + default n + depends on SYNO_PORT_MAPPING_V2 + +config SYNO_MULTI_KSWAPD + bool "support multiple kswapd" + default y + +config SYNO_ADJUST_KSWAPD_NICE + bool "increase kswapd priority" + default y + +endmenu #System Features + +menu "Boot Arguments" + +config SYNO_BOOT_ARGUMENTS + bool "Build syno_bootargs which reads kernel args from grub" + default y + +config SYNO_HW_VERSION + bool "Hardware Model String" + depends on SYNO_BOOT_ARGUMENTS + default y + +config SYNO_HW_REVISION + bool "Hardware Revision String" + depends on SYNO_BOOT_ARGUMENTS + default y + +config SYNO_INTERNAL_NETIF_NUM + bool "Number Of Network Interfaces" + depends on SYNO_BOOT_ARGUMENTS + default y + +config SYNO_MAC_ADDRESS + bool "Read MAC Address from bootloader or flash" + default y + depends on SYNO_INTERNAL_NETIF_NUM + +config SYNO_SERIAL + bool "Serial Number" + depends on SYNO_BOOT_ARGUMENTS + default y + +endmenu #Boot Arguments + +menu "Kernel Core Enhancements" + +config SYNO_KERNEL_UTC_TIME + bool "Keep UTC Time In Kernel And RTC" + default y + +config SYNO_SOFTLOCKUP_COUNTER + bool "Trigger soft lockup detector in limited times" + default y + depends on LOCKUP_DETECTOR + +config SYNO_SOFTLOCKUP_COUNTER_MAX + int "The max number to trigger soft lockup detector." + default 10 + depends on SYNO_SOFTLOCKUP_COUNTER + +config SYNO_HARDLOCKUP_PANIC_ENHANCE + bool "enhance hardlockup_panic mechanism" + default y + depends on (SYNO_PURLEY || SYNO_GEMINILAKE) && HARDLOCKUP_DETECTOR + +config SYNO_HARDLOCKUP_THRESH_EXTENSION + bool "Extend hard lockup threshold." + default n + depends on HARDLOCKUP_DETECTOR + +config SYNO_KVMX64_MQ_TIMEOUT + int "The default seconds before a multi-queue block request timeout" + default 1024 + depends on (SYNO_KVMX64 || SYNO_KVMX64SOFS || SYNO_KVMX64V2) + +config SYNO_PRINT_BACKTRACE_ON_LOCKUP + bool "Print backtrace on soft and hard lockup" + default y + +config SYNO_DUMPSTACK_SHOW_FUNC_ADDR + bool "Print function address on call trace" + default y + depends on !RANDOMIZE_BASE + +config SYNO_HUNG_TASK_ADJUSTMENT + bool "Record hung task count" + depends on DETECT_HUNG_TASK + default Y + +config SYNO_DEFAULT_HUNG_TASK_WARNINGS + int "Default warnning call stack count for hung task detection" + depends on SYNO_HUNG_TASK_ADJUSTMENT + default 300 + +config SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD + int "Default reset period of warning call stack count for hung task detection" + depends on SYNO_HUNG_TASK_ADJUSTMENT + default 360 + +config SYNO_ISCSI_DEAD_LOCK_BH_ISSUE + bool "Replace spin_lock_bh with spin_lock_irqsave in libiscsi" + default y + +config SYNO_CFS_CPU_LOAD_IMBALANCE + bool "fix imbalance caused by redundant wakeup migration" + default y + +config SYNO_BLOCK_SOFTIRQ_ON_STACK + bool "fix imbalance caused by redundant wakeup migration" + default y + +endmenu #Kernel Core Enhancements diff --git a/synology/synoconfigs/Kconfig.devices b/synology/synoconfigs/Kconfig.devices new file mode 100644 index 000000000000..d3bdb9fad43a --- /dev/null +++ b/synology/synoconfigs/Kconfig.devices @@ -0,0 +1,1367 @@ +menu "Device Drivers" + +menu "Block Devices" + +config SYNO_BLK_DEV_GENDISK_OPERATIONS + bool "Specify drive operations for gendisk" + depends on BLOCK + default y + +config SYNO_BLK_DEV_WAIT_DISK_READY + bool "Wait for device ready when boot up" + default y + +config SYNO_BLK_DEV_SET_DEV_READ_ONLY + bool "Set a block device to read-only mode" + depends on BLOCK + default y + +endmenu #Block Devices + +menu "MD" + +config SYNO_MD_09_SUPERBLOCK_COMPATIBLE + bool "Allow our system can read 0.9 sb between little/big endian" + default y + +config SYNO_MD_STATUS_GET + bool "Enable ioctl to get RAID status" + default y + +config SYNO_MD_SYNC_MSG + bool "Let md sync action log be stored in /var/log/messages" + default y + +config SYNO_MD_FORCE_START_DIRTY_DEGRADED + bool "Force assemble dirty degraded RAID with level 4, 5 or 6" + default y + +config SYNO_MD_DEVICE_HOTPLUG_NOTIFY + bool "Notify RAID that device has changed" + default y + +config SYNO_MD_RAID5_FORCE_RCW + bool "Force RAID5 go rcw path" + default y + +config SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH + bool "Prevent out-of-memory and rebuild performance drop" + default y + +config SYNO_MD_RAID1_SYSFS_INTERFACE + bool "Add sysfs interface to raid1" + default y + +config SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO + bool "Enhance raid5 series performance by split I/O part from original kernel thread" + default y + +config SYNO_MD_FIX_RAID5_RESHAPE_HANG + bool "Resolve the raid 5 hang problem during expansion with disk error or hotplug out." + default y + +config SYNO_MD_SYNC_THROTTLE_MECHANISM + bool "Use previous resync speed throttle mechanism as the same as linux-3.10.x" + default y + +config SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD + bool "Add threshold to get active stripe throttling" + default y + +config SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE + bool "Restore MD_FEATURE_RAID0_LAYOUT to feature map when update super block" + default y + +config SYNO_MD_RAID5_SKIP_COPY_ENHANCE + bool "Enhance raid5 skip_copy due to our stress results" + default y + +config SYNO_MD_FAST_WAKEUP + bool "Reduce md sleep wake up time" + default y + +config SYNO_MD_SYNC_DEBUG + bool "Store inconsistent lba in log during check/sync action" + default y + +config SYNO_MD_FIX_SB_UPDATE_DEADLOCK + bool "Fix potential deadlock issue of sb update" + default y + +config SYNO_MD_FLUSH_PLUG + bool "Add threshold for raid1/raid10/raid5 plug" + default y + +config SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE + bool "Fix raid1 bio mempool change issue when raid1 reshape" + default y + +config SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC + bool "Let md0 and md1 can do resync without waiting for other mds" + default y + +config SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO + bool "Do not clone bio at device mapper layer when bio send to a dummy cache" + default y + +config SYNO_MD_NUMA_SETTING_ENHANCE + bool "md numa setting enhance" + default y + depends on NUMA + +config SYNO_MD_RAID_PERF_STAT + bool "Record overhead and infos of handle stripe in RAID5" + default y + +config SYNO_MD_UNUSED_HINT + bool "Feature: Infrastructure for Fast Rebuild" + default y + +config SYNO_MD_FAST_REBUILD + bool "Enable Fast Rebuild func" + depends on SYNO_MD_UNUSED_HINT + default y + +config SYNO_MD_FAST_SCRUBBING + bool "Enable Fast Scrubbing func" + depends on SYNO_MD_FAST_REBUILD + default y + +config SYNO_MD_EIO_NODEV_HANDLER + bool "check if device exist when MD EIO error" + default y + depends on SYNO_BLK_DEV_GENDISK_OPERATIONS + +config SYNO_MD_FIX_RESYNC_STATUS + bool "Fix incorrect display of resync status" + default y + +config SYNO_MD_FORCE_SB_EVENT_INCREASED + bool "Forcely increase sb event during starting and stopping array." + default y + +config SYNO_MD_RAID1_ASSIGN_READ_TARGET + bool "Assign read target to raid1" + default y + depends on SYNO_MD_RAID1_SYSFS_INTERFACE + +config SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN + bool "Skip resync after assemble md when super block is not clean" + default y + +config SYNO_MD_DATA_CORRECTION + bool "Try to use md redundancy to re-compute data when fs ask to retry" + default n + depends on SYNO_DATA_CORRECTION + +config SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH + bool "Fix raid5 max latency high issue" + default y + +config SYNO_MD_DM_EXTRA_IOCTL + bool "Hack dm layer and block layer for flashcache support" + default y + +config SYNO_MD_DUMMY_READ + bool "Read parity chunk to enhance sequential read performance" + default y + +config SYNO_MD_STATUS_DISKERROR + bool "avoid to crash when a bad sector in degraded md" + default y + depends on SYNO_MD_DEVICE_HOTPLUG_NOTIFY + +config SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO + bool "Allow md run when it's reshape position is zero" + default y + +config SYNO_MD_SYNC_STATUS_REPORT + bool "Report sync status to user space" + default y + +config SYNO_MD_SECTOR_STATUS_REPORT + bool "report read/write error to user space through scemd and synobios" + default y + depends on SYNO_MD_EIO_NODEV_HANDLER && SYNO_PORT_MAPPING_V2 + +config SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT + bool "Fix raid5 read data from error layout during expansion." + default y + +config SYNO_MD_UPDATE_SB_AT_RESYNC_START + bool "update superblock at resync start" + default y + +config SYNO_MD_BAD_SECTOR_AUTO_REMAP + bool "Auto remap bad sector in SATA layer" + default y + +config SYNO_MD_AUTO_REMAP_REPORT + bool "report LVM/ MD remapped sector through scemd and synobios" + default y + depends on SYNO_MD_BAD_SECTOR_AUTO_REMAP && SYNO_MD_SECTOR_STATUS_REPORT + +config SYNO_MD_RAID_F1 + bool "Support RAID F1" + default y + +config SYNO_MD_RAID5_ENABLE_SSD_TRIM + bool "Default enable trim for raid5" + default y + +config SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH + bool "fix sh->count race with sh->batch_head" + default y + +config SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG + bool "Fix null pointer dereference after assembling crashed raid1" + default y + +config SYNO_MD_FULL_STRIPE_MERGE + bool "full stripe merge" + default y + +config SYNO_MD_RAID10_IO_SERIALIZATION + bool "raid10 io serialization" + default y + +config SYNO_MD_RAID1_FIX_IO_SERIALIZATION + bool "Fix bounds check of raid1 io serialization" + default y + +config SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION + bool "default enable io serialization on raid1 and raid10" + default y + +config SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ + bool "avoid retry align read causing soft lockup" + default y + +config SYNO_MD_RAID_FAIL_FAST_ON_WRITE + bool "directly fail device when write error happen" + default y + +config SYNO_MD_DM_CRYPT_QUEUE_LIMIT + bool "limit the io number queue on dm-crypt" + default y + +endmenu #MD + +menu "Block" + +config SYNO_BLOCK_BLKTRACE_FIX + bool "Make all block layers to have corrent complete and queue blktrace event" + default y + +config SYNO_BLOCK_LATENCY_MONITOR_TOOL + bool "Disk block layer performance monitor tool" + default y + +config SYNO_BLOCK_FIX_BIO_SPLIT_ORDER + bool "Fix the order when bio split twice without recursive" + default y + +config SYNO_BLOCK_SEQIO_MONITOR_TOOL + bool "Disk block layer seqio monitor tool" + depends on SYNO_BLOCK_LATENCY_MONITOR_TOOL + default y + +config SYNO_BLOCK_BLKTRACE_AFFINITY_FIX + bool "Lock blktrace to avoid pinning threads on cpu in user space" + default y + +config SYNO_BLOCK_USE_NOIO_FLAG + bool "Use noio flag for make_request_fn / submit_bio hook" + default y + +endmenu #Block + +menu "SCSI" + +config SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL + bool "Promote the info level log into notice level" + default y + +config SYNO_SCSI_OVERRIDE_SD_TIMEOUT + bool "Extend SD_TIMEOUT value to 60s from 30s" + default y + +config SYNO_SCSI_DEVICE_IDLE_TIME + bool "Export idle time of scsi disks" + default y + +config SYNO_DISK_HIBERNATION + bool "Disk hibernation" + depends on SYNO_SCSI_DEVICE_IDLE_TIME + default y + +config SYNO_SCSI_INQUIRY_STANDARD + bool "Correct the disk vendor and model information in kernel" + default y + +config SYNO_SCSI_GET_ATA_IDENTITY + bool "Get ata identity via ATA PASS THRU command in scsi layer" + default y + +config SYNO_SCSI_DISK_SERIAL + bool "Let scsi disk export its serial number" + default y + +config SYNO_SCSI_CUSTOM_SCMD_TIMEOUT + bool "Customize SCSI commands timeout value per disk" + default y + +config SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS + bool "Spindown the disks which may lose power during reboot" + default y + +config SYNO_SCSI_DISK_SPINDOWN_PARALLELLY + bool "Spin-down disk parallelly for shutdown function" + default y + depends on SYNO_SYSTEM_SHUTDOWN_HOOK + +config SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH + bool "Increase disk model name size up to 24 characters" + depends on SYNO_SCSI_GET_ATA_IDENTITY && SYNO_SCSI_INQUIRY_STANDARD && SYNO_PORT_MAPPING_V2 + default y + +config SYNO_SCSI_DISK_HIBERNATION_DEBUG + bool "Show parent process info in hibernation debug log" + default y + +config SYNO_SCSI_DISK_ERROR_REPORT + bool "Report scsi disk error to user space." + depends on SYNO_PORT_MAPPING_V2 + select SYNO_SYNOBIOS_EVENT + default y + +menu "SATA" + +config SYNO_SATA_DEVICE_PREFIX + string "The prefix of sata device for new port mapping" + default "sata" + depends on SYNO_PORT_MAPPING_V2 + +config SYNO_SATA_PWR_CTRL + bool "Disk Power Control" + depends on SYNO_OF && SYNO_LIBS + default y + +config SYNO_SATA_PWR_CTRL_SMBUS + bool "Syno Control HDD power by SMBus" + select SYNO_SATA_PWR_CTRL + default n + +config SYNO_SATA_PWR_CTRL_GPIO + bool "Syno Control HDD power by GPIO" + depends on SYNO_GPIO + select SYNO_SATA_PWR_CTRL + default n + +config SYNO_SATA_DEBUG_FLAG + bool "Enable debug message in ata codes" + default y + +config SYNO_SATA_ERROR_HANDLING_FLAG + bool "Raise error handling flag while ata port dealing with error" + default y + +config SYNO_SATA_DEVICE_INFOLOG_PROMOTION + bool "Promote interested ata_dev_info log level to ata_dev_warn" + default y + +config SYNO_SATA_COMMAND_XLAT_HOOK + bool + +config SYNO_SATA_SPECIFIC_QC_FILTER + bool + +config SYNO_SATA_STATUS_FLAG + bool + +config SYNO_SATA_PMP_ENHANCE + bool "Some fix/workaround for libata port multiplier driver" + depends on SATA_PMP + default n + +config SYNO_SATA_EUNIT_SUPPORT + bool "Synology Specific PM Device Support" + depends on SATA_PMP && SYNO_PORT_MAPPING_V2 + default y + select SYNO_SATA_SPECIFIC_QC_FILTER + select SYNO_SATA_COMMAND_XLAT_HOOK + select SYNO_SATA_PMP_ENHANCE + select SYNO_SATA_STATUS_FLAG + +config SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT + bool "Synology DX/RX amplitude adjustment" + depends on SYNO_SATA_EUNIT_SUPPORT && SYNO_HW_VERSION + default y + +config SYNO_SATA_EUNIT_HORKAGE + bool "Enable horkage on Synology EUnits" + depends on SYNO_SATA_EUNIT_SUPPORT + default y + +config SYNO_SATA_EUNIT_FAST_PROBE + bool "EUnit fast probe mechanism" + depends on SYNO_SATA_EUNIT_SUPPORT + default y + select SYNO_SATA_COMMAND_XLAT_HOOK + +config SYNO_SATA_EUNIT_HOTPLUG_TASK + bool "PMP hotplug event" + depends on SYNO_SATA_EUNIT_SUPPORT + default y + +config SYNO_SATA_DEEPSLEEP + bool "Interfaces For HDD Deep Sleep" + default n + select SYNO_SATA_COMMAND_XLAT_HOOK + select SYNO_SATA_STATUS_FLAG + select SYNO_SYNOBIOS_EVENT + +config SYNO_SATA_EUNIT_DEEPSLEEP + bool "Implemnt SATA EUnit Deep Sleep" + depends on SYNO_SATA_DEEPSLEEP && SYNO_SATA_EUNIT_SUPPORT + default y + +config SYNO_SATA_SPINUP_GROUP + bool "Enable spinup group" + depends on SYNO_OF && SYNO_INTERNAL_HD_NUM && SYNO_GPIO + default n + select SYNO_SATA_COMMAND_XLAT_HOOK + select SYNO_SATA_SPECIFIC_QC_FILTER + +config SYNO_SATA_CONTROLLER_INFO + bool + +config SYNO_SATA_SIGNAL_CHECK + tristate "show sata chip amplitude/de-emphasis adjustment." + depends on SYNO_LIBS + default n + +config SYNO_SATA_SIGNAL_TEST + tristate "sata controller pci register sysfs setting interface for amplitude/de-emphasis adjustment." + depends on SYNO_LIBS + default n + +config SYNO_SATA_MV92XX_PORTING + bool "Marvell 88SE92x5 specific initialize steps" + default y + +config SYNO_SATA_MV9170_PORTING + bool "Marvell 88SE9170 specific initialize steps" + default y + +config SYNO_SATA_MV92XX_GPIO_CTRL + bool "Interfaces For Marvell 9235/9215 GPIO Control" + depends on SYNO_SATA_MV92XX_PORTING + default n + select SYNO_AHCI_GET_HOST_MMIO_ADDRESS + +config SYNO_SATA_MV9170_GPIO_CTRL + bool "Interfaces For Marvell 9170 GPIO Control" + depends on SYNO_SATA_MV9170_PORTING + default n + select SYNO_AHCI_GET_HOST_MMIO_ADDRESS + +config SYNO_SATA_MV9XXX_SIGNAL_SETTING + bool "Marvell sata controller signal costomize" + depends on SYNO_HW_VERSION && (SYNO_SATA_MV92XX_PORTING || SYNO_SATA_MV9170_PORTING) + default y + select SYNO_AHCI_GET_HOST_MMIO_ADDRESS + +config SYNO_SATA_DISK_LED_CONTROL + bool "Interface To Control SATA Disk LEDs" + default y + +config SYNO_AHCI_SWITCH + bool "Enable/Disable AHCI Initialization" + depends on SYNO_BOOT_ARGUMENTS && SATA_AHCI + default y + +config SYNO_AHCI_GET_HOST_MMIO_ADDRESS + bool + +config SYNO_AHCI_SOFTWARE_ACITIVITY + bool "AHCI software acitivty led" + depends on SATA_AHCI && SYNO_PORT_MAPPING_V2 + default n + +config SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER + bool "AHCI software acitivty led via led trigger" + depends on SYNO_AHCI_SOFTWARE_ACITIVITY && SYNO_LEDS_TRIGGER + default n + +config SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY + bool "AHCI software control GPIO HDD_ACT_LED" + depends on SYNO_AHCI_SOFTWARE_ACITIVITY && SYNO_GPIO + default n + +config SYNO_KVMX64_MAX_MEDIUM_ACCESS_TIMEOUTS + bool "Increase max medium access timeouts" + default y + depends on (SYNO_KVMX64 || SYNO_KVMX64SOFS || SYNO_KVMX64V2) + +config SYNO_SATA_JMB585_FIX + bool "Fix JMicron issues" + default n + select SYNO_SATA_CONTROLLER_INFO + +config SYNO_SATA_JMB585_DUBIOUS_IFS_FIX + bool "Fix JMicron 585 raise IFS on device error" + default n + select SYNO_SATA_CONTROLLER_INFO + +config SYNO_SATA_JMB585_AMP_ADJUST + bool "adjust amplitude and de-emphasis for JMicron JMB585 sata signal" + default n + +config SYNO_SATA_JMB585_GPIO_LED_CTRL + bool "Interfaces For Jmicron JMB585 GPIO Control" + default n + depends on SYNO_OF + +config SYNO_SATA_JMB585_FIRMWARE_UPDATE + tristate "Kernel module for updating roms for jmb585" + default n + depends on SYNO_LIBS + +config SYNO_SATA_ASM1061_AMP_ADJUST + bool "adjust amplitude and de-emphasis for asmedia 1061 sata signal" + default n + select SYNO_ASMEDIA_CONTROL + +config SYNO_SATA_ASM1061_RESET_DELEY + bool "Enable delay 1 us after writing HOST_RESET register" + depends on SATA_AHCI + default n + +config SYNO_SATA_ASM116X_CONTROL + bool + +config SYNO_SATA_ASM116X_AMP_ADJUST + bool "adjust amplitude and de-emphasis for asmedia 1061 sata signal" + default n + select SYNO_SATA_ASM116X_CONTROL + +config SYNO_SATA_ASM116X_GPIO_LED_CTRL + bool "Interfaces For Asmedia 116X GPIO Control" + depends on SYNO_OF + default n + select SYNO_SATA_ASM116X_CONTROL + +config SYNO_SATA_ASM116X_FIRMWARE_UPDATE + tristate "Kernel module for updating roms for asm116x" + default n + depends on SYNO_LIBS + +config SYNO_SATA_DETECTION_INFO + bool "Show SATA information" + default y + +config SYNO_SATA_WCACHE_DISABLE + bool "Disk write cache blacklist" + default y + +config SYNO_SATA_DISK_MONITOR_TOOL + bool "Disk performance monitor tool" + default y + +config SYNO_SATA_SAMPLE_SEQ_IO + bool "Sample HDD seq IO" + depends on SYNO_SATA_DISK_MONITOR_TOOL + default y + +config SYNO_SATA_IOCTL_HDIO_GET_DMA + bool "HDIO_GET_DMA ioctl for libata" + default y + +config SYNO_SATA_HANDLE_EIO_DISKS + bool "Kickoff EIO disks" + default y + +config SYNO_SATA_FIX_LIBATA_NOT_REFLUSH + bool "Flush revalidated disks after error" + default y + +config SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX + bool "Samsung HDD/PMP probing workaround" + default y + depends on SYNO_SATA_EUNIT_SUPPORT + +config SYNO_SATA_DISABLE_QUEUED_TRIM + bool "Disable queued TRIM function" + default y + +config SYNO_SATA_SSD_DETECT + bool "SSD detection" + default y + +config SYNO_SATA_REDUCE_RETRY_TIMER + bool "Reduce SATA retry timer" + default y + +config SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT + bool "Extend timeout of libata probe commands" + default y + +config SYNO_SATA_SKIP_PARALLEL_SCAN + bool "Skip ATA_HOST_PARALLEL_SCAN check when power on disks" + default n + +config SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST + bool "Disable the zero-after-trimmed whiltelist mechanism for SSDs" + default y + +config SYNO_SATA_SHOW_MORE_EH_LOG + bool "Don't silence libata error handling logs" + default y + +config SYNO_SATA_DISABLE_READ_LOG_DMA + bool "Don't use READ LOG DMA EXT" + default y + +config SYNO_SATA_INTEL_SSD_COMPATIBILITY + bool "Solution of Intel S4500 3.84TB Hotplug 100% failed on Marvell 88SE9235" + default y + +config SYNO_SATA_EXTEND_READ_LOG_TIMEOUT + bool "Extend read log timeout prevent spinup timeout for large size drives" + default y + +config SYNO_SATA_PRINT_SN + bool "Add log for disk serial number" + default y + +config SYNO_SATA_NCQ_EH_ENHANCE + bool "NCQ error handle enhance" + default y + +config SYNO_SATA_EARLY_NCQ_ANALYZE + bool "Analyze NCQ error Early" + default y + +config SYNO_SATA_DISK_NCQ_COMPATIBILITY + bool "Disable ncq on WD7500BPKX, WD5000BPKX" + default y + +config SYNO_SATA_DISK_WD_TLER_RETRY + bool "Retry command if error is caused by TLER" + default y + +config SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE + bool "Make sysfs discard_zeroes_data always true" + default y + +config SYNO_SATA_TRIM_PREFER_WRITE_SAME + bool "Prefer write same while trim issued" + default y + +config SYNO_MV1475_SGPIO_LED_CTRL + bool "Using Marvell 1475 control disk led" + default y + +config SYNO_SATA_SIGNAL_ADJUST_BY_DTS + bool "SATA Contorller signal adjust by value in the dts" + default n + depends on SYNO_OF + +config SYNO_SATA_SIGNAL_ADJUST + bool "SATA Controller signal adjust (For newplatform, suggest use SATA_SIGNAL_ADJUST_BY_DTS)" + default n + depends on !SYNO_SATA_SIGNAL_ADJUST_BY_DTS + +config SYNO_SATA_PORT_THAW + bool "Show port freeze or thaw information" + default y + +config SYNO_SATA_RECOVER_MECHANISM + bool "SATA Error Recover Mechanism" + default y + +config SYNO_SATA_DEEP_RETRY + bool "SATA Deep Retry for Recover" + depends on SYNO_SATA_DEEPSLEEP && SYNO_SATA_RECOVER_MECHANISM + default y + +config SYNO_SATA_ERROR_REPORT + bool "Report sata error to user space" + depends on SYNO_PORT_MAPPING_V2 + select SYNO_SYNOBIOS_EVENT + default y + +config SYNO_SATA_DISK_PRESENT_CHECK + bool "Disk Present Pin Check for Disk Fail" + depends on SYNO_SATA_PWR_CTRL && SYNO_OF + select SYNO_SYNOBIOS_EVENT + default y + +config SYNO_SATA_DETECT_POWER_SHORT_BREAK + bool "Send disk power short brake event to userspace" + depends on SYNO_OF + select SYNO_SYNOBIOS_EVENT + default y + +config SYNO_SATA_SPEED_LIMIT_RECOVERY + bool "Clear sata speed limit after disk plug out" + default y + +config SYNO_SATA_LIBATA_FUA + bool "Enable libata fua support" + default y + +config SYNO_AHCI_INTERNAL_SLOT_MODE + bool "Internal slot may remove unnecessary reg read" + default n + depends on SYNO_OF + +config SYNO_SATA_PWR_CTRL_TEST + tristate "HDD dynamic power control sysfs for testing/verifying" + default n + +config SYNO_AHCI_REG_READ_TEST + tristate "Test AHCI register read" + depends on SYNO_LIBS + default y + +config SYNO_SATA_EH_DEFER_CMD + bool "Defer sending command while ata is processing eh" + depends on SYNO_SATA_DEEPSLEEP + default y + +endmenu #SATA + +menu "DUAL HEAD" + depends on SYNO_DUAL_HEAD + +endmenu #DUAL HEAD + +menu "SAS" + depends on SYNO_SAS + +config SYNO_SAS_DEVICE_PREFIX + string "SAS Disk Name Prefix" + default "sas" + depends on SYNO_PORT_MAPPING_V2 + +config SYNO_SAS_FIX_ENCLOSURE_POWEROFF_WARNON + bool "Avoid WARN ON message when plug off enclosure" + default y + +config SYNO_SAS_SYSFS_BLOCK_DEV_LINK + bool "Add block device symbolic link under sysfs" + default y + +config SYNO_SAS_SPINUP_DELAY + bool "Support SAS disk spinup queue" + default y + +config SYNO_SAS_SPINUP_DELAY_DEBUG + bool "Print out debug message for SAS disk spinup queue" + default n + depends on SYNO_SAS_SPINUP_DELAY + +config SYNO_SAS_SHOW_DISK_PHY_INFO + bool "Show phy info in kernel log when disk hotplug in" + default y + +config SYNO_SAS_HBA_IDX + bool "Indexing Synology SAS HBA" + depends on SYNO_BOOT_ARGUMENTS + default n + +config SYNO_SAS_MAX_HBA_SLOT + int "Maximun number of SAS HBA PCIe slot" + depends on SYNO_SAS_HBA_IDX + default "2" + +config SYNO_SAS_HOST_DISK_LED_CTRL + bool "Set SAS HOST DISK LED" + default y + depends on SCSI_MPT3SAS && SYNO_SAS_HBA_IDX + +config SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF + bool "Make kernel to issue START_STOP to spin down drive" + default y + +config SYNO_SAS_SES_DIAGNOSTIC_PAGE_ENHANCE + bool "Add retry mechanism for diagnostic page 1 & 2 & 10" + depends on SYNO_SAS + default y + +config SYNO_SAS_SATA_EARLY_WAKEUP + bool "Add sas_sata_standby_flag to indicate that start command should be sent when the device in hibernation mode" + depends on SCSI_MPT3SAS + default y + +endmenu #SAS + +endmenu #SCSI + +menu "NVMe" + depends on BLK_DEV_NVME + +config SYNO_NVME_DEVICE_INDEX + bool "Assign an unique index to each NVMe device" + depends on BLK_DEV_NVME + depends on SYNO_BLK_DEV_GENDISK_OPERATIONS + default y + +config SYNO_NVME_DEBUG_FORCE_TIMEOUT + bool "Enable sysfs entry to triger NVMe device timeout" + depends on BLK_DEV_NVME + default y + +config SYNO_NVME_QUIRK_NO_APST + bool "default APST off" + depends on BLK_DEV_NVME + default y + +config SYNO_NVME_EXTEND_IO_TIMEOUT + bool "Extend timeout of NVMe IO command" + depends on BLK_DEV_NVME + default y + +config SYNO_NVME_SW_ACTIVITY + bool "Trigger activity led by software" + depends on BLK_DEV_NVME + default n + +config SYNO_NVME_IDLE_TIME + bool "Export idle time of NVMe devices" + default y + +config SYNO_NVME_BLOCK_INFO + bool "NVMe block info for port mapping V2" + depends on SYNO_PORT_MAPPING_V2 + default y + +config SYNO_NVME_WAIT_DISK_READY + bool "Wait for NVMe device ready when boot up" + default y + depends on BLK_DEV_NVME && SYNO_BLK_DEV_WAIT_DISK_READY + +config SYNO_NVME_SAMSUNG_QDEPTH + bool "adjust samsung 970 EVO qdepth" + depends on SYNO_PURLEY && BLK_DEV_NVME + default n + +config SYNO_NVME_CRIT_WARN_MEDIA_SET_RO + bool "Set NVMe block disk to read-only if the device reports RO" + depends on BLK_DEV_NVME + default y + +endmenu #NVMe + +menu "Network" + +config SYNO_NET_BOND_ALB_INFO + bool "Show bonding alb info in procfs" + default y + +config SYNO_NET_LINK_DOWN_STATUS + bool "Set NIC speed unknown for link down interface" + default y + +endmenu #Network + +menu "USB" + +config SYNO_USB_DEVICE_PREFIX + string "USB device prefix for new port mapping" + default "usb" + depends on SYNO_PORT_MAPPING_V2 + +config SYNO_USB_FLASH_BOOT + bool "Boot From USB Flash" + depends on SYNO_PORT_MAPPING_V2 + default y + +config SYNO_USB_FLASH_DEVICE_INDEX + int "USB Boot Flash Device Number" + depends on SYNO_USB_FLASH_BOOT + default "255" + +config SYNO_USB_FLASH_DEVICE_NAME + string "USB Boot Flash Device Name" + depends on SYNO_USB_FLASH_BOOT + default "synoboot" + +config SYNO_INSTALL_FLAG + bool "Avoid Users Mounting USB Boot Flash" + default y + depends on SYNO_USB_FLASH_BOOT + +config SYNO_USB_UAS_ENABLE_CONTROL + bool "USB device use uas driver or usb-storage dirver" + default y + depends on USB_UAS + +config SYNO_USB_VBUS_GPIO_CONTROL + bool "Vbus GPIO control" + depends on SYNO_OF && SYNO_GPIO + default n + +config SYNO_USB_POWER_OFF_TIME + int "USB power off time (ms)" + depends on SYNO_USB_VBUS_GPIO_CONTROL + default 1000 + +config SYNO_USB_SERIAL_FIX + bool "Generate serial number as S/N issue occurs" + default y + +config SYNO_USB_ENABLE_USBFS_ENTRY + bool "Add USB entry to /proc/bus" + default y + +config SYNO_USB_RESET_WAIT + bool "Add extra delay time for USB reset in xhci driver" + default y + +config SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK + bool "Disable USB 2.0 LPM support check" + default n + +config SYNO_USB_XHCI_RESET_DELAY + bool "Add extra delay in xhci_reset" + default y + +config SYNO_USB_FORBID + bool "Apply Syno USB Forbid Mechanism" + select SYNO_SYNOBIOS_EVENT + default n + +config SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK + bool "Avoid long disconnection time after USB device is plugged out" + default n + +config SYNO_USB_SPEED_DOWNGRADE_RECOVERY + bool "Reset the USB device when speed is downgraded on XHCI" + default y + +config SYNO_USB_STOR_EXTRA_DELAY + bool "Add an extra delay time for USB storage" + default y + +config SYNO_USB_CONNECT_DEBOUNCER + bool "Add connect-debouncer during USB reset" + default y + +config SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD + bool "Empty transfer rings with a disconnected USB device" + default y + +config SYNO_USB_POWER_RESET + bool "Support power cycle before USB re-enumeration" + default n + +config SYNO_USB_POWER_ON_TIME + int "USB power on time (ms)" + depends on SYNO_USB_POWER_RESET + default 10 + +config SYNO_USB_CASTRATED_XHC + bool "special treatment for ports of xHC without defferential pairs of USB3" + depends on SYNO_USB_SPEED_DOWNGRADE_RECOVERY + default n + +config SYNO_USB_NUM_CASTRATED_XHC + int "Maximun number of castrated xHC" + depends on SYNO_USB_CASTRATED_XHC + default "5" + +config SYNO_USB_STOR_ENHANCE_DISCONNECTION + bool "Avoid long disconnection time for USB storage" + default n + +config SYNO_USB_DEVICE_QUIRKS + bool "USB device quirks" + default y + +config SYNO_USB_UPS_DISCONNECT_FILTER + bool "Filter abnormal disconnect from UPS via USB" + depends on SYNO_USB_DEVICE_QUIRKS + default y + +config SYNO_USB_SYNCHRONIZE_CACHE_FILTER + bool "Filter the SYNCHRONIZE_CACHE command for some buggy USB storage" + depends on SYNO_USB_DEVICE_QUIRKS + default y + +config SYNO_USB_INTEL_XHC_LPM_DISABLE + bool "Disable USB 3.0 LPM on Intel HCs" + default y + depends on X86_64 + +config SYNO_OOB_USB_DEVICE + bool "OOB USB Device Function" + depends on SYNO_OOB_SERIAL_OVER_LAN && SYNO_PORT_MAPPING_V2 + default n + +config SYNO_SKIP_INTEL_EHCI_CONTROLLER + bool "Disable 8 series/C220 ehci controller" + depends on SYNO_BROADWELL + default n + +config SYNO_USB_COPY + bool "Enable USB Copy" + depends on USB + default n + +config SYNO_USB_EXTERNAL_HUB + bool "Apply Syno USB Features On External USB3.0 Hub" + default n + +config SYNO_USB_EUNIT_CONTROL + bool "For an eunit that has a separated usb control port from data port" + depends on USB_ACM + default n + +endmenu #USB + +menu "Hardware Monitor" + +config SYNO_ADT7490_FEATURES + bool "Enhance features for adt7490 for Synology Inc. NAS product" + depends on SENSORS_ADT7475 + default n + +config SYNO_ADT7490_PECI1_ENABLE + bool "Enable PECI1 for platform with two CPU" + depends on SYNO_ADT7490_FEATURES + default n + +config SYNO_HDDMON + tristate "Syno HDD monitor" + depends on SYNO_SATA_PWR_CTRL_GPIO + select SYNO_INTERNAL_HD_NUM + +config SYNO_SMBUS_HDDMON + tristate "Syno SMBus HDD Monitor" + depends on SYNO_SATA_PWR_CTRL_SMBUS + +config SYNO_HWMON_PMBUS + bool "SYNO PMBus Monitor" + depends on SYNO_OF + +config SYNO_HWMON_AMD_K10TEMP + bool "AMD CPU Temperature Detection" + default n + depends on SENSORS_K10TEMP + +endmenu #Hardware Monitor + +menu "Serial/TTYs" + +config SYNO_TTY_X86_CONSOLE_OUTPUT + bool "Setup X86 Console Port Output" + default y + depends on X86 + +config SYNO_TTY_FIX_TTYS_FUNCTIONS + bool "Fixed console at ttyS0, uP at ttyS1" + depends on SYNO_BOOT_ARGUMENTS + select CONFIG_EARLY_PRINTK + default n + +config SYNO_TTY_SHORT_TIME_STUCK_FIX + bool "Fix console stuck short time when 8250 probe" + depends on SYNO_GEMINILAKE + default n + +config SYNO_TTY_MICROP_CTRL + bool "Operating the uP through ttyS1" + default y + +config SYNO_TTY_MICROP_FUNCTIONS + bool "uP functions implemntation" + depends on SYNO_TTY_MICROP_CTRL + default y + +config SYNO_TTY_AES_COMMAND + bool "uP AES command" + depends on SYNO_TTY_MICROP_CTRL + default y + +config SYNO_TTY_DTS_INFO + bool "Get uart port mapping from device tree" + depends on SYNO_TTY_FIX_TTYS_FUNCTIONS && SYNO_PORT_MAPPING_V2 && SYNO_OF + default y + +config SYNO_OOB_SERIAL_OVER_LAN + bool "Support serial over lan function" + default n + +config SYNO_OOB_LOG_DEVICE_NAME + string "OOB Log Device Path" + depends on SYNO_OOB_SERIAL_OVER_LAN + default "oob_log" + +config SYNO_SERIAL_CONSOLE_FORBID + bool "Apply Syno Serial Console Forbid Mechanism" + select SYNO_SYNOBIOS_EVENT + default n + +endmenu #Serial/TTYs + +menu "MTD" + +config SYNO_MTD_ALLOC + bool "Allocate buffer until upgrade process is done" + default y + depends on MTD && SYNO_SYSTEM_CALL + +config SYNO_MTD_INFO + bool "Capability for modifying partition information and FIS content in flash." + default y + depends on MTD && MTD_REDBOOT_PARTS + +config SYNO_MTD_ACCESS_LOG + bool "add log for mtd device open/close" + default y + depends on MTD + +config SYNO_MTD_ACCESS_LOG_EXCEPT_VENDOR_PART + bool "do not show mtd vendor part access log" + default n + depends on SYNO_MTD_ACCESS_LOG + +config SYNO_MTD_ACCESS_LOG_EXCEPT_REDBOOTCONF_PART + bool "do not show mtd RedBoot Config part access log" + default n + depends on SYNO_MTD_ACCESS_LOG + +config SYNO_MTD_LOCK_UNLOCK + bool "add mtd->lock and mtd->unlock function" + default n + depends on MTD + +config SYNO_MTD_DYNAMIC_ERASESIZE + bool "dynamicly change mtd erasesize by erasing length" + default n + depends on MTD + +endmenu #MTD + +menu "I2C Hardware Bus support" + +config SYNO_I2C_I801_POLL + bool "disable I2C_I801 interrupt features" + default n + +config SYNO_I2C_I801_SUPPORT_RECOVERY + bool "support I2C_I801 recovery function" + default n + +config SYNO_I2C_DW_FORCE_PROBE + bool "force probe I2C_DW driver" + depends on I2C_DESIGNWARE_PLATFORM + default n + +config SYNO_I2C_DW_CLK_FREQ_CUSTOM + bool "customize designware i2c clock frequency" + default n + depends on I2C_DESIGNWARE_PLATFORM && SYNO_HW_VERSION + +endmenu #I2C Hardware Bus support + +menu "LEDs" + +config SYNO_LEDS_TRIGGER + tristate "Synology LED Triggers" + depends on LEDS_TRIGGERS + +config SYNO_LEDS_LP3943_FEATURES + bool "Customized features of LP3943 led dirver for Synology Corp. NAS product" + depends on LEDS_LP3943 && SYNO_LEDS_TRIGGER + default n + +config SYNO_LEDS_LP3943_PROBE + def_bool y + depends on SYNO_LEDS_LP3943_FEATURES + +choice + prompt "LP3943 Probe method" + default SYNO_LEDS_LP3943_PROBE_FIXED_BUS + depends on SYNO_LEDS_LP3943_PROBE + +config SYNO_LEDS_LP3943_PROBE_FIXED_BUS + bool "Use Fixed Bus" + depends on SYNO_LEDS_LP3943_PROBE + +config SYNO_LEDS_LP3943_PROBE_ACPI + bool "Use ACPI devie" + depends on SYNO_LEDS_LP3943_PROBE && ACPI + +config SYNO_LEDS_LP3943_PROBE_OF + bool "Use device tree" + depends on SYNO_LEDS_LP3943_FEATURES && SYNO_I2C_OF_PROBE + +endchoice + +config SYNO_LED_ATMEGA1608 + tristate "ATMEGA1608 led dirver for Synology" + depends on SYNO_LEDS_TRIGGER + +config SYNO_LED_ATMEGA1608_SEG7 + tristate "ATMEGA1608 led seven segment dirver for Synology" + depends on LEDS_TRIGGERS && SYNO_OF + +config SYNO_ATEMGA1608_FEATURES + bool "ATMEGA1608 led dirver for Synology" + depends on SYNO_LED_ATMEGA1608 + +config SYNO_LEDS_TRIGGER_DISK + tristate "Synology Disk LED Trigger" + depends on LEDS_TRIGGERS && SYNO_OF + +endmenu #LEDs + +menu "ALSA" + +endmenu #ALSA + +menu "Virtio" + +endmenu #Virtio + +menu "IOMMU" + +config SYNO_IOMMU_PASSTHROUGH + bool "enable iommu=pt by default" + default y + +config SYNO_IOMMU_AMD_USB_QUIRK + bool "Enforce default iommu domain type to be Translated model for specifice device" + depends on AMD_IOMMU + default y + +endmenu #IOMMU + +menu "RTC" + +config SYNO_RTC_S35390A_ACPI_SUPPORT + bool "S35390A probe via ACPI device" + depends on RTC_DRV_S35390A && ACPI + default n + +config SYNO_RTC_S35390A_FIX_12HOUR_MODE + bool "Use 12-hour mode for synobios" + depends on RTC_DRV_S35390A + default n + +config SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK + bool "Disable NTP update RTC" + default y + +config SYNO_RTC_PT7C4337_SUPPORT + bool "PT7C4337 device porting" + depends on RTC_DRV_DS1307 + default n + +endmenu #RTC + +menu "PCI" + +config SYNO_PCI_MISSING_DEVICE + bool "Check pci nvme device exist" + depends on PCI + default y + +config SYNO_PCI_ASM1806_SUBID_WORKAROUND + bool "Workaround for clearing wrong subsystem ID" + default n + +config SYNO_PCI_OPTIONAL_SLOT + bool "Support optional PCIe slots" + depends on PCI + default n + select MDIO + +config SYNO_PCI_MAX_SLOT + int "Maximum number of PCIe slot" + depends on SYNO_PCI_OPTIONAL_SLOT + default "1" + +config SYNO_PCI_M2DXX_SIGNAL_SETTING + bool "M2 card controller constomize" + depends on SYNO_PCI_OPTIONAL_SLOT && (SYNO_SATA_MV92XX_PORTING || SYNO_SATA_MV9170_PORTING) + default n + +config SYNO_PCI_DOMAIN_PATH + bool "Gen PCI path with domain for Port mapping v2" + depends on PCI && SYNO_PORT_MAPPING_V2 + default y + +config SYNO_PCI_EUNIT_SUPPORT + bool "Supporting i2c bus on pcie switch for eunit" + depends on PCI + default n + +config SYNO_PCI_EUNIT_I2C + bool "Supporting i2c bus on pcie switch for eunit" + depends on PCI && I2C && SYNO_PCI_EUNIT_SUPPORT + default n + +endmenu #PCI + +menu "TRANSCODING" + +endmenu #TRANSCODING + +menu "NTB" + +config SYNO_NTB_ENHANCE_LINK + bool "Enhance the ability for NTB devices" + depends on NTB + default y + +config SYNO_NTB_FIX_CLEANUP_WORK_PANIC + bool "Fix NTB QP cleanup work panic issue" + depends on NTB + default y + +endmenu #NTB + +menu "POWER" + +endmenu #POWER + +menu "Multipath" + +endmenu #Multipath + +menu "GPIO" +config SYNO_GPIO + bool "Employ refactored GPIO-functions" + depends on GPIOLIB + default y + +config SYNO_GPIO_X86_PINCTRL_CALC_BASE + bool "X86 GPIO Pinctrl new formula" + depends on X86_64 && GPIOLIB + default y + +endmenu #GPIO + +menu "SYNO Device Tree" +config SYNO_OF + bool + depends on SYNO_PORT_MAPPING_V2 + select OF + select OF_EARLY_FLATTREE + +endmenu #SYNO Device Tree + +menu "PWM" + +config SYNO_PWM_CONTROL_LED + bool "Using PWM to control led" + depends on SYNO_RTD1619B && PWM_RTK + +endmenu #PWM + +endmenu #Device Drivers diff --git a/synology/synoconfigs/Kconfig.fs b/synology/synoconfigs/Kconfig.fs new file mode 100644 index 000000000000..10e747fb7c03 --- /dev/null +++ b/synology/synoconfigs/Kconfig.fs @@ -0,0 +1,1212 @@ +menu "File Systems" + +menu "Basic" + +config SYNO_FS_STAT + bool "SYNOStat" + default y + depends on SYNO_SYSTEM_CALL + +config SYNO_FS_XATTR + bool "Synology extended attribute namespace" + default y + +config SYNO_FS_ARCHIVE_BIT + bool "Archive bit" + default y + depends on SYNO_FS_XATTR + +config SYNO_FS_ARCHIVE_VERSION + bool "syno archive version" + default y + +config SYNO_FS_WINACL + bool "Synology WinACL" + default y + select SYNO_FS_ARCHIVE_BIT + +config SYNO_FS_RELATIME_PERIOD + bool "Add mount option to set update period of relatime" + default y + +config SYNO_FS_RECVFILE + bool "Support syno_recv_file syscall" + default y + +config SYNO_FS_CASELESS_STAT + bool "Support caseless stat in filesystem " + default y + depends on SYNO_SYSTEM_CALL + +config SYNO_FS_LOCKER + bool "Mechanism to lock/unlock data for WORM purpose" + default y + +config SYNO_FS_CREATE_TIME + bool "syno create time" + default y + +config SYNO_FS_SYNOTIFY + bool "Support Synotify" + default y + depends on FSNOTIFY && SYNO_SYSTEM_CALL + +config SYNO_FS_SYNOBOOT_LOG + bool "Log for mount/unmount synoboot" + default y + +config SYNO_FS_UNMOUNT + bool "syno unmount dump opened file" + default y + +config SYNO_FS_AGGREGATE_RECVFILE + bool "Enable syno_recv_file syscall to use aggregate_write_end()" + default y + depends on SYNO_FS_RECVFILE + +config SYNO_FS_QUOTA_QUERY + bool "Support query quota used and limit in vfs operations" + default y + depends on SYNO_BTRFS_SYNO_QUOTA + +config SYNO_FS_SPACE_USAGE + bool "Support query space usage in vfs operations" + default y + +config SYNO_FS_DEV + bool "SYNO FS dev support" + default y + depends on SWAP && SYNO_FEATURES + +config SYNO_FS_RBD_META + tristate "Syno rbd meta support" + default y + depends on SWAP && SYNO_FEATURES + +config SYNO_FS_ROOT_PRJQUOTA + bool "Project quota restricts root usage" + default y + depends on QUOTA && SYNO_FEATURES + +config SYNO_FS_SHOW_INCOMPAT_SUPP + bool "Show file system's incompatible support flags" + default y + +config SYNO_FS_SHOW_COMPAT_RO_SUPP + bool "Show file system's compatible read-only support flags" + default y + +config SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE + bool "Add generic fiemap for kernel space" + default y + +config SYNO_FS_SPLICE_FSNOTIFY + bool "splice: report related fsnotify events" + default y + +endmenu #Basic + +menu "CIFS" +config SYNO_CIFS_CREATE_TIME + bool "CIFS syno create time" + default y + depends on CIFS && SYNO_FS_STAT && SYNO_FS_CREATE_TIME + +config SYNO_CIFS_REPLACE_NATIVE_OS + bool "Identify Synology CIFS mount" + default y + +config SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8 + bool "Cifs with UTF8 code page" + default y + +config SYNO_CIFS_INIT_NLINK + bool "Initialize fattr with cf_nlink=1 in cifs_dir_info_to_fattr" + default y + +config SYNO_CIFS_MOUNT_CASELESS + bool "Caseless remote mount" + default y + +config SYNO_CIFS_FORCE_UMOUNT + bool "" + default y + +config SYNO_CIFS_COVERITY + bool "fix cifs coverity" + default y + +config SYNO_CIFS_SMB_OPS + bool "add vers=syno for switch SMB1~3 from negotiate" + default y + depends on SYNO_CIFS_REPLACE_NATIVE_OS + +config SYNO_CIFS_RECONNECT + bool "modify cifs reconnect behavior to prevent wait mutex lock cause hung task" + default y + +endmenu #CIFS + +menu "FAT" + +config SYNO_FAT_CREATE_TIME + bool "FAT syno create time" + default y + depends on FAT_FS && SYNO_FS_STAT && SYNO_FS_CREATE_TIME + +config SYNO_FAT_DEFAULT_MNT_FLUSH + bool "Set FAT default mount option 'flush'" + default y + depends on FAT_FS + +config SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE + bool "Skip waiting time when file close" + default y + depends on FAT_FS && SYNO_FAT_DEFAULT_MNT_FLUSH + +endmenu #FAT + +menu "EXT3" + +config SYNO_EXT3_ARCHIVE_BIT + bool "Ext3 syno archive bit" + default y + depends on SYNO_FS_ARCHIVE_BIT && EXT3_FS + +config SYNO_EXT3_ARCHIVE_VERSION + bool "Ext3 syno archive version" + default y + depends on SYNO_FS_ARCHIVE_VERSION && EXT3_FS && SYNO_EXT4_XATTR + +config SYNO_EXT3_CREATE_TIME + bool "Ext3 syno create time" + default y + depends on SYNO_FS_CREATE_TIME && EXT3_FS + +endmenu #EXT3 + +menu "EXT4" + +config SYNO_EXT4_LAZYINIT_INFO + bool "Export lazyinit progress to sysfs" + default y + depends on EXT4_FS + +config SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED + bool "Adjust lazyinit speed dynamically" + default y + depends on EXT4_FS + +config SYNO_EXT4_LAZYINIT_WAIT_MULT + int "Number of lazyinit wait multiplier" + default 2 + depends on EXT4_FS + +config SYNO_EXT4_XATTR + bool "Ext4 syno xattr" + default y + depends on SYNO_FS_XATTR && EXT4_FS + +config SYNO_EXT4_STAT + bool "Ext4 SYNOStat" + default y + depends on SYNO_FS_STAT && EXT4_FS + +config SYNO_EXT4_ARCHIVE_BIT + bool "Ext4 syno archive bit" + default y + depends on SYNO_FS_ARCHIVE_BIT && EXT4_FS + +config SYNO_EXT4_ARCHIVE_VERSION + bool "Ext4 syno archive version" + default y + depends on SYNO_FS_ARCHIVE_VERSION && EXT4_FS && SYNO_EXT4_XATTR + +config SYNO_EXT4_WINACL + bool "Enable Synology WinACL in Ext4" + default y + depends on EXT4_FS && SYNO_FS_WINACL + select SYNO_EXT4_ARCHIVE_BIT + +config SYNO_EXT4_CREATE_TIME + bool "Ext4 syno create time" + default y + depends on SYNO_FS_CREATE_TIME && EXT4_FS + +config SYNO_EXT4_SYMLINK_IOCTL + bool "add ioctl to symbolic link" + default y + depends on EXT4_FS + +config SYNO_EXT4_CASELESS_STAT + bool "Support caseless stat in ext4" + default y + depends on SYNO_FS_CASELESS_STAT && EXT4_FS + +config SYNO_EXT4_ERROR_REPORT + bool "Enable ext4 error report mechanism" + default y + depends on EXT4_FS + +config SYNO_EXT4_INODE_NUM_OVERFLOW_FIX + bool "Fix ext4 inode number overflow problem on large volume (>64TB)" + default y + depends on EXT4_FS && 64BIT + +config SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM + bool "Ext4 set default mount option journal_checksum" + default y + depends on EXT4_FS + +config SYNO_EXT4_UNUSED_HINT + bool "FIHINTUNUSED ioctl to send free space information to underly layers" + default y + depends on EXT4_FS && SYNO_MD_UNUSED_HINT + +config SYNO_EXT4_DISABLE_INODES_COUNT_CHECK + bool "disable mount time check about inodes count" + default y + depends on EXT4_FS + +config SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS + bool "Increase reserved GDT to break the 16TB boundary of online resize" + default y + depends on EXT4_FS + +config SYNO_EXT4_CAPABILITY_FLAGS + bool "synology capability flags" + default y + depends on EXT4_FS + +config SYNO_EXT4_RBD_META + bool "Reserve SynoRBD meta in filesystem" + default y + depends on EXT4_FS && SYNO_FS_RBD_META && SYNO_EXT4_CAPABILITY_FLAGS + +config SYNO_EXT4_SYNOOPT + bool "Synology specific mount options" + default y + depends on EXT4_FS + +config SYNO_EXT4_ROOT_PRJQUOTA + bool "Project quota restricts root usage on EXT4" + default y + depends on QUOTA && SYNO_FEATURES && SYNO_FS_ROOT_PRJQUOTA && SYNO_EXT4_SYNOOPT + +config SYNO_EXT4_SKIP_UNNECESSARY_BARRIER + bool "Skip blk flush with data!=writeback when sync_fs" + default y + depends on EXT4_FS + +config SYNO_EXT4_BH_FLAGS_WARNING + bool "Workaround for incorrect bh flags" + default y + depends on EXT4_FS + +endmenu #EXT4 + +menu "BTRFS" + +config SYNO_BTRFS_XATTR + bool "Btrfs syno xattr" + default y + depends on SYNO_FS_XATTR && BTRFS_FS + +config SYNO_BTRFS_STAT + bool "Btrfs SYNOStat" + default y + depends on SYNO_FS_STAT && BTRFS_FS + +config SYNO_BTRFS_ARCHIVE_BIT + bool "Btrfs syno archive bit" + default y + depends on SYNO_FS_ARCHIVE_BIT && BTRFS_FS && SYNO_BTRFS_XATTR + +config SYNO_BTRFS_ARCHIVE_VERSION + bool "Support syno archive version for btrfs" + default y + depends on SYNO_FS_ARCHIVE_VERSION && SYNO_BTRFS_XATTR && BTRFS_FS + +config SYNO_BTRFS_WINACL + bool "Enable Synology WinACL in Btrfs" + default y + depends on BTRFS_FS && SYNO_FS_WINACL + select SYNO_BTRFS_ARCHIVE_BIT + select SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT + +config SYNO_BTRFS_CREATE_TIME + bool "Add syno create time for btrfs" + default y + depends on SYNO_FS_CREATE_TIME && SYNO_BTRFS_XATTR && BTRFS_FS + +config SYNO_BTRFS_RESIZE_QUERY + bool "Add a dry-run mode in BTRFS_IOC_RESIZE" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_METADATA_RESERVE + bool "reserve metadata chunk with metadata_ratio" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FALLOCATE_MARK_WRITTEN + bool "Mark fallocated area as written rether than prealloc" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_VFS_INO_TO_PATH + bool "Query ino to path in vfs" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_QGROUP_QUERY + bool "Add ioctl for btrfs qgroup query" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT + bool "improve mount time with dealyed orphan cleanup for tree-root" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT + bool "Btrfs mount option expand to 64-bit" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW + bool "No remount as read-write is allowed for compat-ro" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_MERGE_HOLES + bool "file hole can be merged with both previous and next hole items" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME + bool "Support btrfs send subvolume create time" + default y + depends on BTRFS_FS && SYNO_BTRFS_SEND_FLAGS_SUPPORT + +config SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET + bool "Set btrfs read-only subvol ruuid" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_RENAME_READONLY_SUBVOL + bool "Allow btrfs to rename read-only subvolume" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_RECLAIM_SPACE + bool "add support for reclaim space from partial used extents" + default y + depends on BTRFS_FS && SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT + +config SYNO_BTRFS_IOC_SYNC_SYNO + bool "Add a new ioctl BTRFS_IOC_SYNC_SYNO for iscsi" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_CLONE_RANGE_V2 + bool "clone range v2 version" + default y + depends on BTRFS_FS && SYNO_EXPORT_SYMBOL + +config SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2 + bool "default space cache v2" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SEND_SUBVOL_FLAG + bool "add btrfs send subvol flag" + default y + depends on BTRFS_FS && SYNO_BTRFS_SEND_FLAGS_SUPPORT + +config SYNO_BTRFS_SEND_FLAGS_SUPPORT + bool "Support syno btrfs send flags" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SEND_SKIP_FIND_CLONE + bool "add a send flag to skip find_extent_clone process" + default y + depends on BTRFS_FS && SYNO_BTRFS_SEND_FLAGS_SUPPORT + +config SYNO_BTRFS_SEND_FALLBACK_COMPRESSION + bool "add a send flag to convert file compression algorithm from zstd to lzo" + default y + depends on BTRFS_FS && SYNO_BTRFS_SEND_FLAGS_SUPPORT + +config SYNO_BTRFS_SEND_FALLOCATE_SUPPORT + bool "Support fallocate cmd to pre-allocate file extents while sending subvols" + default y + depends on BTRFS_FS && SYNO_BTRFS_SEND_FLAGS_SUPPORT + +config SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE + bool "add btrfs calculate send data size" + default y + depends on BTRFS_FS && SYNO_BTRFS_SEND_FLAGS_SUPPORT + +config SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME + bool "add btrfs send support pause/resume" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_CASELESS_STAT + bool "Add syno caseless stat for btrfs" + default y + depends on SYNO_FS_CASELESS_STAT && BTRFS_FS + +config SYNO_BTRFS_LOCKER + bool "Mechanism to lock/unlock data for WORM purpose" + default y + depends on BTRFS_FS && SYNO_FS_LOCKER && SYNO_BTRFS_FEATURE_TREE + +config SYNO_BTRFS_LOCKER_SNAPSHOT + bool "Mechanism to lock/unlock read-only snapshot" + default y + depends on SYNO_BTRFS_LOCKER + +config SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK + bool "Support subvolume clock for locker" + default y + depends on SYNO_BTRFS_LOCKER + +config SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK + bool "remove tree checker machanism for inode item flags" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK + bool "remove tree checker machanism for pre-write io" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP + bool "Support btrfs cleaner stop deleting snapshot" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SUBVOLUME_HIDE + bool "Support subvolume hide flag" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_BLOCK_GROUP_HINT_TREE + bool "Add a block group hint tree to speedup volume mount." + default y + depends on BTRFS_FS + select SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT + +config SYNO_BTRFS_LOG_TREE_RSV_METADATA + bool "reserve metadata group for log tree" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_CLUSTER_ALLOCATION + bool "Cluster allocation" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE + bool "Add a block group cache tree to speedup volume mount." + default y + depends on BTRFS_FS + select SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT + +config SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA + bool "log tree use single metadata instead of dup" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_COMPR_DEFAULT_SETTING + bool "Apply default setting of syno compression" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_JOURNAL_INFO_BUG + bool "fix btrfs journal_info bug" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE + bool "fix data chunk allocate too much for parallel write" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED + bool "fix fiemap result not corrected" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FREE_SPACE_ANALYZE + bool "A new ioctl to analyze btrfs free space" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FEATURE_METADATA_CACHE + bool "add metadata cache feature with ssd cache" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK + bool "Avoid trim system chunk." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FREE_EXTENT_MAPS + bool "Add a machanisim to drop extent map cache" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE + bool "tune default max inline size" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SCRUB_CANCEL + bool "Let btrfs cancel scrubbing faster" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_COMPR_CTL + bool "Operate compressed files" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT + bool "add sysfs interface about block group count information" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_COMMIT_STATS + bool "Btrfs performance stats about commit transaction." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR + bool "Fix cp --reflink failed between csum/nocsum" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR + bool "Prevent clone files between compress/nocompress share folders" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SKIP_BLOCK_GROUP + bool "add mount option to skip block group" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION + bool "add ioctl to calculate actual disk size of snapshots" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_UNUSED_HINT + bool "FIHINTUNUSED ioctl to send free space information to underly layers" + default y + depends on SYNO_MD_UNUSED_HINT + depends on BTRFS_FS + +config SYNO_BTRFS_SYSFS_FREE_SPACE_TREE + bool "add sysfs interface about free space tree" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_PERF_STATS + bool "Btrfs performance stats" + default y + depends on BTRFS_FS && DEBUG_FS + +config SYNO_BTRFS_FIX_INCREMENTAL_SEND + bool "fix btrfs send incremental send" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FEATURE_SPACE_USAGE + bool "add space usage for different subvolume type" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_DATA_CORRECTION + bool "Report btrfs data checksum failure" + default n + depends on BTRFS_FS && SYNO_DATA_CORRECTION + +config SYNO_BTRFS_SEND_SIGNAL_HANDLE + bool "add signal handling for exiting btrfs send quickly" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SYNO_QUOTA + bool "Syno btrfs quota 2.0" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE + bool "Keep btrfs global reserve more than 256MB if the fs is larger than 10G." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_REFILL_GLOBAL_RSV + bool "Add retry global rsv fill when alloc metadata block except BTRFS_BLOCK_RSV_TEMP" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_DROP_LOG_TREE + bool "add mount option to drop log tree" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_MULTIPLE_WRITEBACK + bool "improve grantley random write performance." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT + bool "fix drop progress inconsistent when drop snapshot error" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG + bool "Add syno_flag to file extent" + default n + depends on BTRFS_FS && SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK + +config SYNO_BTRFS_DEDUPE + bool "Synology btrfs dedupe" + default n + depends on BTRFS_FS && SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG && SYNO_BTRFS_RECLAIM_SPACE && SYNO_BTRFS_SYNO_QUOTA + +config SYNO_BTRFS_COW_ASYNC_THROTTLE + bool "enhance latency for cow with async throttle" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE + bool "Btrfs limit bio size max 64k for latency" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_ORDERED_EXTENT_THROTTLE + bool "avoid OOM with throttle for ordered extent" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_PRIORITY_ORDERED_EXTENT + bool "improve latency with move work to high workqueue for ordered extent" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_UNLOCKED_BUFFER_WRITE + bool "Btrfs: implement unlocked buffered write" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_BALANCE_DRY_RUN + bool "add btrfs balance dry run" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FEATURE_TREE + bool "synology feature tree" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_CAPABILITY_FLAGS + bool "synology capability flags" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_RBD_META + bool "Reserve SynoRBD meta in filesystem" + default y + depends on BTRFS_FS && SYNO_FS_RBD_META && SYNO_BTRFS_FEATURE_TREE && SYNO_BTRFS_CAPABILITY_FLAGS + +config SYNO_BTRFS_ASYNC_METADATA_RECLAIM + bool "improve latency with async metadata reclaim" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_ASYNC_DATA_FLUSH + bool "improve latency with async flush" + default y + depends on BTRFS_FS && SYNO_BTRFS_MULTIPLE_WRITEBACK && SYNO_BTRFS_ASYNC_METADATA_RECLAIM + +config SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE + bool "improve latency with async metadata flush and throttle" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS + bool "use readahead forward always for verify dev extents" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_DELAYED_REF_THROTTLE + bool "Add btrfs delayed ref throttle" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_CLEANER_THROTTLE + bool "Throttle cleaner" + default y + depends on BTRFS_FS && SYNO_BTRFS_DELAYED_REF_THROTTLE + +config SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE + bool "to provide consistent command count for pause" + default y + depends on SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME + +config SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK + bool "fix partial write end deadlock" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_TRIM_ENOSPC + bool "Fix trim will lead to ENOSPC and lose data." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_LIST_HARDLINKS + bool "list hardlinks with inum" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED + bool "Fix bug when qgroup ulist_node atomic alloc failed." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT + bool "Skip clear extent defrag when nocow ordered extent" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG + bool "fix clonerange nbytes wrogn" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_ALLOCATOR + bool "synology btrfs allocator" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT + bool "synology btrfs skip quota reserve when no quota limit" + default y + depends on BTRFS_FS && SYNO_BTRFS_SYNO_QUOTA + +config SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE + bool "Add btrfs non_blocking_punch_hole" + default y + depends on BTRFS_FS && SYNO_BTRFS_DELAYED_REF_THROTTLE + +config SYNO_BTRFS_MOUNT_STATS + bool "Btrfs performance stats about mount." + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_UUID_CHECKING + bool "Fix unnecessary uuid rescan" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE + bool "Fix unnecessary flush with old size is zero when truncate" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION + bool "Limit pre-run delayed-refs for commit transaction" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE + bool "Fiemap improve for large sparse file" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_HIBERNATION_MONITOR + bool "Monitor modified log for hibernation" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW + bool "fix chunk logical overflow" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_STATISTICS + bool "add meta statistics" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_QUOTA_SOFT_LIMIT + bool "add quota soft limit" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE + bool "improve check new dir created with new dir cache" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET + bool "auto disable compress when nocow set" + default y + depends on BTRFS_FS + +config SYNO_BTRFS_QUICK_BALANCE + bool "balance only one block group" + default y + depends on SYNO_BTRFS_ALLOCATOR + +config SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE + bool "search extent item by extent type" + default y + depends on BTRFS_FS + +endmenu #BTRFS + +menu "ECRYPT" + +config SYNO_ECRYPTFS_ARCHIVE_BIT + bool "Ecryptfs archive bit" + default y + depends on SYNO_FS_ARCHIVE_BIT && ECRYPT_FS + +config SYNO_ECRYPTFS_FILENAME_SYSCALL + bool "System calls to get encrypt or decrypt filename" + default y + depends on SYNO_SYSTEM_CALL && ECRYPT_FS + +config SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY + bool "Avoid ecryptfs mount repeatly at the same mount point" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE + bool "Speed up ecryptfs truncate by skipping zeros write" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH + bool "Check ecryptfs symlink target length after encryption" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_FALLOCATE_SUPPORT + bool "Add fallocate for eCryptfs" + default y + depends on ECRYPT_FS && SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE + +config SYNO_ECRYPTFS_FAST_LOOKUP + bool "Fast lookup, read i_size from xattr" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_PASS_BTRFS_IOCTL + bool "Pass syno btrfs ioctl to lower btrfs filesystem" + default y + depends on ECRYPT_FS && BTRFS_FS + +config SYNO_ECRYPTFS_ARCHIVE_VERSION + bool "Ecryptfs archive version" + default y + depends on SYNO_FS_ARCHIVE_VERSION && ECRYPT_FS + +config SYNO_ECRYPTFS_CREATE_TIME + bool "Ecryptfs syno create time" + default y + depends on SYNO_FS_CREATE_TIME && ECRYPT_FS + +config SYNO_ECRYPTFS_STAT + bool "Ecryptfs SYNOStat" + default y + depends on SYNO_FS_STAT && ECRYPT_FS + +config SYNO_ECRYPTFS_LOWER_INIT + bool "Ecryptfs always initial lower file with rw, ignore security check on initialization" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE + bool "Update ecryptfs i_size only when they are different" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING + bool "Ecryptfs skip EDQUOT, ENOSPC warning log" + default y + depends on ECRYPT_FS + +config SYNO_ECRYPTFS_WINACL + bool "Enable syno acl in ecryptfs" + default y + depends on ECRYPT_FS && SYNO_FS_WINACL + +config SYNO_ECRYPTFS_EXPORT + bool "Enable ecryptfs nfs export" + default y + depends on ECRYPT_FS && EXPORTFS + +config SYNO_ECRYPTFS_REDUCE_MEMCPY + bool "Reduce one memcpy on ecryptfs for performance." + default y + depends on ECRYPT_FS && BTRFS_FS && SYNO_FS_AGGREGATE_RECVFILE + +config SYNO_ECRYPTFS_DISABLE_READAHEAD + bool "disable readahead with bdi" + default y + depends on ECRYPT_FS + +endmenu #ECRYPT + +menu "NFS" + +config SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE + bool "Avoid parent mutex hung task when unlink big file" + default y + depends on NFSD + +config SYNO_NFSD_HIDDEN_FILE + bool "Hide system directories" + default y + depends on NFSD + +config SYNO_NFSD_UDP_PACKET + bool "Provide a interface for user to set the udp packet size they want" + default y + depends on NFSD + +config SYNO_NFSD_UDP_MAX_PACKET_SIZE + int "Provide a interface for user to set the udp packet size they want" + default 32768 + depends on SYNO_NFSD_UDP_PACKET + +config SYNO_NFSD_UDP_MIN_PACKET_SIZE + int "Provide a interface for user to set the udp packet size they want" + default 4096 + depends on SYNO_NFSD_UDP_PACKET + +config SYNO_NFSD_UDP_DEF_PACKET_SIZE + int "Provide a interface for user to set the udp packet size they want" + default 8192 + depends on SYNO_NFSD_UDP_PACKET + +config SYNO_NFSD_SQUASH_TO_ADMIN + bool "Grant permission of administrators group to admin user" + default y + depends on NFSD + +config SYNO_NFSD_UNIX_PRI + bool "Provide a interface for user to enable command chmod or not on ACL share" + default y + depends on NFSD && SYNO_FS_WINACL + +config SYNO_NFSD_WINACL + bool "Support WinACL in NFS" + default y + depends on NFSD && SYNO_FS_WINACL + +config SYNO_NFSD_NUMA_SVC_POOL_PERNODE + bool "Enhance NFS performance for numa model" + default y + depends on NFSD && NUMA + +config SYNO_NFSD_LATENCY_REPORT + bool "Add /proc/net/rpc/nfsd_lat to monitor nfsd latency" + default y + depends on NFSD + +config SYNO_NFS_VAAI_SUPPORT + bool "NFS VAAI support" + default y + depends on NFSD + +config SYNO_NFS_VAAI_LAZY_CLONE + bool "NFS VAAI lazy clone support" + default y + depends on BTRFS_FS && SYNO_NFS_VAAI_SUPPORT + +config SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED + bool "Prevent nfsd from finding idle nfsd when all nfsd are busy." + default y + depends on NFSD + +config SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP + bool "Prevent unnecessary initialization of the large arg 'struct nl4_server'." + default y + depends on NFSD + +config SYNO_NFSD_SYNO_FILE_STATS + bool "Add /proc/fs/nfsd/syno_file_stats to spot check file write" + default y + depends on NFSD + +config SYNO_NFSD_CONNECTION_STAT + bool "Mmonitor number of nfsd connection stat" + default y + depends on NFSD && SYNO_NFSD_LATENCY_REPORT + +config SYNO_NFSD_UDC_COLLECTOR + bool "Collect information for UDC" + default y + depends on NFSD && SYNO_NFSD_LATENCY_REPORT + +endmenu #NFS + +menu "HFSPLUS" + +config SYNO_HFSPLUS_CREATE_TIME + bool "HFS+ syno create time" + default y + depends on HFSPLUS_FS && SYNO_FS_STAT && SYNO_FS_CREATE_TIME + +config SYNO_HFSPLUS_CASELESS + bool "HFS+ shows caseless option for netatalk" + default y + depends on HFSPLUS_FS + +config SYNO_HFSPLUS_NFC_WORKAROUND + bool "workaround for reading on-disk NFC filename" + default y + depends on HFSPLUS_FS + +config SYNO_HFSPLUS_EA + bool "HFS+ enable EA support" + default y + depends on HFSPLUS_FS + +config SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT + bool "HFS+ page mapping limit" + default y + depends on HFSPLUS_FS + +config SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE + bool "remove default creator and type" + default y + depends on HFSPLUS_FS && SYNO_HFSPLUS_EA + +endmenu #HFSPLUS + +menu "UDF" + +config SYNO_UDF_CASELESS + bool "UDF use caseless lookup" + default y + depends on UDF_FS + +endmenu #UDF + +menu "FUSE" + +config SYNO_FUSE_STAT + bool "Support synostat and caseless stat by fuse" + default y + depends on FUSE_FS && SYNO_FS_STAT + +config SYNO_FUSE_ARCHIVE_BIT + bool "Support syno archive bit by fuse" + default y + depends on FUSE_FS && SYNO_FS_ARCHIVE_BIT + +config SYNO_FUSE_ARCHIVE_VERSION + bool "Support syno archive verion by fuse" + default y + depends on FUSE_FS && SYNO_FS_ARCHIVE_VERSION + +config SYNO_FUSE_CREATE_TIME + bool "Support syno create time by fuse" + default y + depends on FUSE_FS && SYNO_FS_CREATE_TIME + +endmenu #FUSE + +menu "OverlayFS" + +config SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS + bool "Workaround to allow case-insensitive upper and lower layers" + default y + depends on OVERLAY_FS + +endmenu #OverlayFS + +menu "AUFS" + +config SYNO_AUFS_PATCH + bool "AUFS patches for docker support" + default y + depends on AUFS_FS + +config SYNO_AUFS_NO_AUTOGEN + bool "Disable auto generated files" + default y + depends on AUFS_FS + +endmenu #AUFS + +menu "ConfigFS" + +config SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE +bool "set SIMPLE_ATTR_SIZE as PAGE_SIZE" + default n + depends on CONFIGFS_FS + +endmenu #ConfigFS + +menu "TMPFS" + +config SYNO_TMPFS_CREATE_TIME + bool "Tmpfs syno create time" + default y + depends on TMPFS && SYNO_FS_CREATE_TIME && SYNO_FS_STAT + +config SYNO_TMPFS_ARCHIVE_BIT + bool "Tmpfs syno archive bit" + default y + depends on TMPFS && SYNO_FS_ARCHIVE_BIT + +endmenu #TMPFS + +menu "ceph" + +config SYNO_CEPH_RECVFILE + bool "Support recvfile syscall on ceph" + default y + depends on CEPH_FS && SYNO_FS_RECVFILE + +config SYNO_CEPH_STAT + bool "ceph SYNOStat" + default y + depends on CEPH_FS && SYNO_FS_STAT + +config SYNO_CEPH_CREATE_TIME + bool "Let ceph support syno create time" + default y + depends on CEPH_FS && SYNO_FS_CREATE_TIME + +config SYNO_CEPH_ARCHIVE_BIT + bool "support syno archive bit" + default y + depends on CEPH_FS && SYNO_FS_ARCHIVE_BIT + +config SYNO_CEPH_CASELESS_STAT + bool "support syno caseless stat" + default y + depends on CEPH_FS && SYNO_FS_CASELESS_STAT + +config SYNO_CEPH_WINACL + bool "support syno acl" + default y + depends on CEPH_FS && SYNO_FS_WINACL + +endmenu #ceph + +endmenu #File Systems diff --git a/synology/synoconfigs/Kconfig.misc b/synology/synoconfigs/Kconfig.misc new file mode 100644 index 000000000000..d4b684c97e04 --- /dev/null +++ b/synology/synoconfigs/Kconfig.misc @@ -0,0 +1,163 @@ +menu "MISC Features" + +config SYNO_APPARMOR_PATCH + bool "Apply Synology patch for AppArmor" + default y + depends on SECURITY_APPARMOR + +config SYNO_OOM_DEBUG + bool "Dump modules and occupied memory sizes while OOM" + default y + +config SYNO_ELEVATE_LOG_LEVEL + bool "Elevate log level of kernel log" + default y + +config SYNO_FORCE_CF9_REBOOT + bool "Support CF9 Force reboot" + default n + depends on (X86_64 && !KGDB_KDB) + +config SYNO_OOM_NOTIFICATION + bool "Support oom notification" + default y + +config SYNO_KERNEL_MODULE_REMOVAL_LOGGING + bool "add logging about kernel module removal" + default y + +config SYNO_POWEROFF_INFO_PRINT + bool "Show pma1 and pma2 in poweroff procedure" + default n + +config SYNO_PSTORE + bool "Synology enhancement of Pstore mechanism" + default n + depends on PSTORE + +config SYNO_SPECULATION_DEFAULT_OFF + bool "Set speculation mitigation to default off" + default n + depends on PAGE_TABLE_ISOLATION + +config SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE + bool "fix rtc wake after power failure" + default y + depends on SYNO_X64 + +config SYNO_PLUGIN_INTERFACE + bool "Synology plugin interface for kernel modules" + default y + +config SYNO_UART_TO_SPI_CONSOLE_LOG + tristate "sysfs for trigger uart to spi log out gpio" + default n + depends on SYNO_LIBS && SYNO_OF + +config SYNO_SYSTEM_SHUTDOWN_HOOK + bool "customized functions exectuted before system shutdown/reboot" + default y + +config SYNO_SYNOBIOS_EVENT + bool "send event to user space through synobios" + default y + +config SYNO_KVM_IGNORE_MSRS + bool "skip logging of ignored MSRS" + default y + depends on KVM + +config SYNO_DISABLE_AUDITSYSCALL + bool "disable kernel always do syscall auditing" + default y + depends on AUDIT + +config SYNO_DEV_ALLOC_PAGES + bool "Enable synology dev alloc pages" + default y + +config SYNO_OUT_OF_RESOURCE_LOG + bool "log for out of resource event occurrence" + default y + +config SYNO_RND_ENTROPY_GEN + bool "generate random entropy" + default y + +config SYNO_ACPI_APEI_AER_DBGMSG + bool "Print AER register in APCI APEI log" + default y + depends on ACPI_APEI_PCIEAER + +endmenu #MISC Features + +menu "Cgroup" + +endmenu #Cgroup + +menu "Encryption" +config SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN + bool "Remove x509 date validation constrain" + depends on KEYS + +endmenu #Encryption + +menu "Udev" + +config SYNO_DEPRECATED_UEVENT_ENV + bool "Export deprecate uevent environment to userspace" + default y + +endmenu #Udev + +menu "Bios Log" + +config SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG + bool "Print the MRC postcode if memory training fail happened at last boot up" + depends on X86 + default y + +config SYNO_BIOS_MRC_POSTCODE_CMOS_ADDR + hex "The address of cmos storing failed MRC postcode" + depends on SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG + default 0x48 + +config SYNO_BIOS_ACPI_FPDT + bool "ACPI Firmware Performance Data Table(FPDT)" + depends on X86_64 && ACPI + default y + +endmenu #BIOS LOG + +menu "ceph" + +config SYNO_CEPH_CUSTOMIZED_CRUSH + bool "customized crush rule for synology hyper converged platform" + depends on CEPH_LIB + default y + +config SYNO_CEPH_SKIP_CRC + bool "skip crc32 calculation" + depends on CEPH_LIB + default y + +config SYNO_CEPH_IDENTIFY_POOL_XATTR_IS_ID + bool "identify whether the pool xattr is pool id" + depends on CEPH_LIB + default y + +endmenu #ceph + +menu "Synology Protection" + +config SYNO_RAMDISK_INTEGRITY_CHECK + bool "Confirm the integrity of ramdisk (rd.gz) is correct and prevent to suffer tampering" + default y + depends on X86_64 + +config SYNO_KEXEC_TEST + bool "Test whether the kernel is booted with Kexec" + default y + depends on X86_64 + +endmenu # Synology Protection diff --git a/synology/synoconfigs/Kconfig.network b/synology/synoconfigs/Kconfig.network new file mode 100644 index 000000000000..e3b7770f5db4 --- /dev/null +++ b/synology/synoconfigs/Kconfig.network @@ -0,0 +1,57 @@ +menu "Network" + +config SYNO_SFP_UNSUPPORTED_NOTIFY + bool "SFP+ module unsupported notify" + default y + +config SYNO_SKIP_RXDROP_BY_CORE + bool "Skip RX packets drop is increasing" + default y + +config SYNO_IPV6_RFC_4862 + bool "IPv6 Stateless Address Autoconfiguration" + default y + +config SYNO_BONDING_INIT_STATUS + bool "Initial the bonding status" + default y + +config SYNO_BONDING_FIX_ACTIVE + bool "Fix a bug in active backup bonding mode" + default y + +config SYNO_FIX_8023AD_LINK_STATUS + bool "Fix 802.3ad link status bug" + default y + +config SYNO_IPV6_LINKLOCAL + bool "Assign an interface to IPV6 link local address automatically." + default y + +config SYNO_OVS_MODE_REFINEMENT + bool "Refine Synology Open vSwitch Mode" + default y + +config SYNO_NF_NAT_WORKAROUND + bool "Fix BUG_ON on nf_nat_setup_info" + default y + +config SYNO_NET_ALB_FIX_OVERFLOW + bool "Fix the overflow bug in alb tx balance mechanism" + default y + +config SYNO_NET_ALB_USE_64BIT_LOAD + bool "use 64 bit varialbe to store load of each tx slave/client" + default y + +config SYNO_NET_EMULEX_HIDE_VF + bool "Not to probe emulex vf by real host" + default y + depends on BE2NET + +config SYNO_AMD_XGBE_PORTING + bool "AMD Xgbe driver porting" + default n + depends on AMD_XGBE + +endmenu #Network diff --git a/synology/synoconfigs/Kconfig.platform b/synology/synoconfigs/Kconfig.platform new file mode 100644 index 000000000000..f5670d678117 --- /dev/null +++ b/synology/synoconfigs/Kconfig.platform @@ -0,0 +1,90 @@ +menu "Platform Features" +config SYNO_X64 + bool + default y + depends on X86_64 + +config SYNO_SELECT_PLATFORM + def_bool y +choice + prompt "Synology platform" + +config SYNO_KVMX64 + bool "KVM X64 Virtual machine" + depends on X86_64 + +config SYNO_KVMX64SOFS + bool "KVM X64 Virtual machine with SOFS" + depends on X86_64 + +config SYNO_KVMX64V2 + bool "KVM X64 Virtual machine with port mapping v2" + depends on X86_64 + +config SYNO_BROADWELL + bool "Intel-Broadwell" + depends on X86_64 + +config SYNO_PURLEY + bool "Intel Purley" + depends on X86_64 + +config SYNO_GEMINILAKE + bool "Intel-Geminilake" + depends on X86_64 + +config SYNO_V1000 + bool "AMD Ryzen Embedded V1000" + depends on X86_64 + +config SYNO_V1000SOFS + bool "AMD Ryzen Embedded V1000 with SOFS" + depends on X86_64 + +config SYNO_RTD1619B + bool "realtek rtd1619b" + depends on ARM64 + select SYNO_LSP_RTD1619B + +config SYNO_ICELAKED + bool "INTEL ICELAKE-D" + depends on X86_64 + +config SYNO_EPYC7002 + bool "AMD EPYC Embedded 7002" + depends on X86_64 + +config SYNO_EPYC7002SOFS + bool "AMD EPYC Embedded 7002 with SOFS" + depends on X86_64 + +config SYNO_RYZEN5K + bool "AMD RYZEN Embedded 5000" + depends on X86_64 + +config SYNO_EPYC7003NTB + bool "AMD EPYC Embedded 7003 with NTB" + depends on X86_64 + +endchoice + +config SYNO_SAS + bool "Synology SAS Support" + default y + depends on SYNO_BROADWELL || SYNO_PURLEY || SYNO_RYZEN5K + +config SYNO_AMD_MCE_THRESHOLD_CLEAR + bool "Clear MCE overflow bit" + default y + depends on X86_MCE_AMD + +config SYNO_INTEL_PSTATE_CALC + bool "Compare P-state ratio only" + default y + +config SYNO_LSP_RTD1619B + bool "Apply Realtek rtd1619b LSP" + depends on ARM64 + +endmenu #Platform Features + diff --git a/synology/synoconfigs/back-porting-records b/synology/synoconfigs/back-porting-records new file mode 100644 index 000000000000..e44ea24b6053 --- /dev/null +++ b/synology/synoconfigs/back-porting-records @@ -0,0 +1,7 @@ +BUG ID: #590 - Enable CONFIG_DEBUG_INFO_BTF +Commit Hashes: + 8493877b58b6f35d643da307ee1ae920b3ddd1d8 + +BUG ID: #852 - kthread: Fix PF_KTHREAD vs to_kthread() race +Commit Hashes: + 709c162ddc835613112bdd2db15b7d04e10c9bbf diff --git a/synology/synoconfigs/epyc7002 b/synology/synoconfigs/epyc7002 new file mode 100644 index 000000000000..90d33f3ce2b0 --- /dev/null +++ b/synology/synoconfigs/epyc7002 @@ -0,0 +1,5992 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +CONFIG_X86_INTEL_LPSS=y +CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_IOSF_MBI=y +# CONFIG_IOSF_MBI_DEBUG is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_XXL=y +# CONFIG_PARAVIRT_DEBUG is not set +# CONFIG_PARAVIRT_SPINLOCKS is not set +CONFIG_X86_HV_CALLBACK_VECTOR=y +CONFIG_XEN=y +CONFIG_XEN_PV=y +CONFIG_XEN_PV_SMP=y +CONFIG_XEN_DOM0=y +CONFIG_XEN_PVHVM=y +CONFIG_XEN_PVHVM_SMP=y +CONFIG_XEN_512GB=y +CONFIG_XEN_SAVE_RESTORE=y +# CONFIG_XEN_DEBUG_FS is not set +# CONFIG_XEN_PVH is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=128 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_NUMA_EMU=y +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +CONFIG_X86_PAT=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_ARCH_ENABLE_THP_MIGRATION=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +CONFIG_HALTPOLL_CPUIDLE=y +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_XEN=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +CONFIG_SYNO_EPYC7002=y +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_VIRTIO_SCSI_DEVICE=y +CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT=10 +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +# CONFIG_SYNO_SATA_PWR_CTRL_GPIO is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +# CONFIG_SYNO_SATA_SPINUP_GROUP is not set +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +# CONFIG_SYNO_NVME_WAIT_DISK_READY is not set +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_SMBUS_HDDMON is not set +CONFIG_SYNO_HWMON_PMBUS=y +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +CONFIG_SYNO_I2C_DW_FORCE_PROBE=y +CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LED_ATMEGA1608=m +CONFIG_SYNO_LED_ATMEGA1608_SEG7=m +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +CONFIG_SYNO_IOMMU_AMD_USB_QUIRK=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=4 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +CONFIG_SYNO_PCI_DOMAIN_PATH=y +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +# CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK is not set +# CONFIG_SYNO_KEXEC_TEST is not set +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_MQ_RDMA=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +CONFIG_BALLOON_COMPACTION=y +CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y +# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_VMAP_PFN=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +# CONFIG_READ_ONLY_THP_FOR_FS is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_SMC is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_9P_XEN=m +# CONFIG_NET_9P_RDMA is not set +# CONFIG_NET_9P_DEBUG is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +CONFIG_FAILOVER=m +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_EDR is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_XEN_PCIDEV_FRONTEND=y +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +CONFIG_PCI_HYPERV=m +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set +CONFIG_PCI_HYPERV_INTERFACE=m + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_SYS_HYPERVISOR=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_DRBD=m +# CONFIG_DRBD_FAULT_INJECTION is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_XEN_BLKDEV_FRONTEND=y +# CONFIG_XEN_BLKDEV_BACKEND is not set +CONFIG_VIRTIO_BLK=m +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +CONFIG_NVME_FABRICS=m +# CONFIG_NVME_RDMA is not set +CONFIG_NVME_FC=m +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +CONFIG_XEN_SCSI_FRONTEND=m +CONFIG_HYPERV_STORAGE=m +CONFIG_LIBFC=m +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +CONFIG_SCSI_VIRTIO=m +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +CONFIG_XEN_NETDEV_FRONTEND=y +# CONFIG_XEN_NETDEV_BACKEND is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +CONFIG_HYPERV_NET=m +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=m +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_VIBRA is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_IQS269A is not set +# CONFIG_INPUT_CMA3000 is not set +CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +CONFIG_HYPERV_KEYBOARD=m +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +CONFIG_HVC_DRIVER=y +CONFIG_HVC_IRQ=y +CONFIG_HVC_XEN=y +CONFIG_HVC_XEN_FRONTEND=y +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +CONFIG_VIRTIO_CONSOLE=m +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_DESIGNWARE_BAYTRAIL=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# CONFIG_DRM_XEN is not set +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_BOOT_VESA_SUPPORT=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +CONFIG_FB_VESA=y +CONFIG_FB_EFI=y +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_XEN_FBDEV_FRONTEND=y +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +CONFIG_FB_HYPERV=m +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y +# CONFIG_SND_XEN_FRONTEND is not set + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +CONFIG_HID_HYPERV_MOUSE=m +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_INFINIBAND=m +# CONFIG_INFINIBAND_USER_MAD is not set +# CONFIG_INFINIBAND_USER_ACCESS is not set +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y +CONFIG_INFINIBAND_VIRT_DMA=y +# CONFIG_INFINIBAND_MTHCA is not set +# CONFIG_MLX4_INFINIBAND is not set +# CONFIG_INFINIBAND_OCRDMA is not set +# CONFIG_INFINIBAND_BNXT_RE is not set +# CONFIG_INFINIBAND_RDMAVT is not set +# CONFIG_RDMA_RXE is not set +# CONFIG_RDMA_SIW is not set +# CONFIG_INFINIBAND_IPOIB is not set +# CONFIG_INFINIBAND_SRP is not set +# CONFIG_INFINIBAND_ISER is not set +# CONFIG_INFINIBAND_RTRS_CLIENT is not set +# CONFIG_INFINIBAND_RTRS_SERVER is not set +# CONFIG_INFINIBAND_OPA_VNIC is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_DECODE_MCE=y +CONFIG_EDAC_AMD64=y +# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set +# CONFIG_EDAC_E752X is not set +# CONFIG_EDAC_I82975X is not set +# CONFIG_EDAC_I3000 is not set +# CONFIG_EDAC_I3200 is not set +# CONFIG_EDAC_IE31200 is not set +# CONFIG_EDAC_X38 is not set +# CONFIG_EDAC_I5400 is not set +# CONFIG_EDAC_I7CORE is not set +# CONFIG_EDAC_I5000 is not set +# CONFIG_EDAC_I5100 is not set +# CONFIG_EDAC_I7300 is not set +# CONFIG_EDAC_SBRIDGE is not set +# CONFIG_EDAC_SKX is not set +# CONFIG_EDAC_I10NM is not set +# CONFIG_EDAC_PND2 is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +CONFIG_DW_DMAC_PCI=y +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_UIO_HV_GENERIC=m +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=m +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +# CONFIG_VDPA is not set +CONFIG_VHOST_IOTLB=m +CONFIG_VHOST=m +CONFIG_VHOST_MENU=y +CONFIG_VHOST_NET=m +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_HYPERV=m +CONFIG_HYPERV_TIMER=y +CONFIG_HYPERV_UTILS=m +CONFIG_HYPERV_BALLOON=m +# end of Microsoft Hyper-V guest support + +# +# Xen driver support +# +CONFIG_XEN_BALLOON=y +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XEN_DEV_EVTCHN=y +CONFIG_XEN_BACKEND=y +CONFIG_XENFS=y +CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_SYS_HYPERVISOR=y +CONFIG_XEN_XENBUS_FRONTEND=y +CONFIG_XEN_GNTDEV=m +CONFIG_XEN_GRANT_DEV_ALLOC=m +# CONFIG_XEN_GRANT_DMA_ALLOC is not set +CONFIG_SWIOTLB_XEN=y +CONFIG_XEN_PCIDEV_BACKEND=m +# CONFIG_XEN_PVCALLS_FRONTEND is not set +# CONFIG_XEN_PVCALLS_BACKEND is not set +CONFIG_XEN_PRIVCMD=y +CONFIG_XEN_ACPI_PROCESSOR=m +# CONFIG_XEN_MCE_LOG is not set +CONFIG_XEN_HAVE_PVMMU=y +CONFIG_XEN_EFI=y +CONFIG_XEN_AUTO_XLATE=y +CONFIG_XEN_ACPI=y +CONFIG_XEN_SYMS=y +CONFIG_XEN_HAVE_VPMU=y +# end of Xen driver support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +CONFIG_INTEL_ATOMISP2_PM=m +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y +CONFIG_HYPERV_IOMMU=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set + +# +# Synology +# +CONFIG_SYNO_DM_FLASHCACHE=m +CONFIG_SYNO_SYNOBIOS=m +# end of Synology +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +CONFIG_VIRTIO_FS=m +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_EXFAT_FS=m +CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_EXFAT_VIRTUAL_XATTR=y +CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:exfat:s0" +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_SUNRPC_XPRT_RDMA is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CIFS_SMB_DIRECT is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_INFINIBAND is not set +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y + +# +# Certificates for signature checking +# +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_XARRAY_MULTI=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_LRU_CACHE=m +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_6x10 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_FONT_SUN8x16=y +# CONFIG_FONT_SUN12x22 is not set +CONFIG_FONT_TER16x32=y +# CONFIG_FONT_6x8 is not set +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# CONFIG_HYPERV_TESTING is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/epyc7002sofs b/synology/synoconfigs/epyc7002sofs new file mode 100644 index 000000000000..02ea40fc2262 --- /dev/null +++ b/synology/synoconfigs/epyc7002sofs @@ -0,0 +1,5803 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +CONFIG_X86_AMD_PLATFORM_DEVICE=y +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=24 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_NUMA_EMU=y +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +# CONFIG_KVM_INTEL is not set +CONFIG_KVM_AMD=m +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +CONFIG_SYNO_EPYC7002SOFS=y +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +# CONFIG_SYNO_SATA_PWR_CTRL_GPIO is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +# CONFIG_SYNO_SATA_SPINUP_GROUP is not set +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +# CONFIG_SYNO_NVME_WAIT_DISK_READY is not set +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_SMBUS_HDDMON is not set +CONFIG_SYNO_HWMON_PMBUS=y +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +CONFIG_SYNO_I2C_DW_FORCE_PROBE=y +CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LED_ATMEGA1608=m +CONFIG_SYNO_LED_ATMEGA1608_SEG7=m +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +CONFIG_SYNO_IOMMU_AMD_USB_QUIRK=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=4 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +CONFIG_SYNO_PCI_DOMAIN_PATH=y +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +CONFIG_SYNO_CEPH_RECVFILE=y +CONFIG_SYNO_CEPH_STAT=y +CONFIG_SYNO_CEPH_CREATE_TIME=y +CONFIG_SYNO_CEPH_ARCHIVE_BIT=y +CONFIG_SYNO_CEPH_CASELESS_STAT=y +CONFIG_SYNO_CEPH_WINACL=y +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH=y +CONFIG_SYNO_CEPH_SKIP_CRC=y +CONFIG_SYNO_CEPH_IDENTIFY_POOL_XATTR_IS_ID=y +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_EDR is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_BLK_DEV_RBD=m +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +CONFIG_LIBFC=m +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_DECODE_MCE=y +CONFIG_EDAC_AMD64=y +# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set +# CONFIG_EDAC_E752X is not set +# CONFIG_EDAC_I82975X is not set +# CONFIG_EDAC_I3000 is not set +# CONFIG_EDAC_I3200 is not set +# CONFIG_EDAC_IE31200 is not set +# CONFIG_EDAC_X38 is not set +# CONFIG_EDAC_I5400 is not set +# CONFIG_EDAC_I7CORE is not set +# CONFIG_EDAC_I5000 is not set +# CONFIG_EDAC_I5100 is not set +# CONFIG_EDAC_I7300 is not set +# CONFIG_EDAC_SBRIDGE is not set +# CONFIG_EDAC_SKX is not set +# CONFIG_EDAC_I10NM is not set +# CONFIG_EDAC_PND2 is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +# CONFIG_CEPH_FS_POSIX_ACL is not set +# CONFIG_CEPH_FS_SECURITY_LABEL is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/epyc7003ntb b/synology/synoconfigs/epyc7003ntb new file mode 100644 index 000000000000..3a8a992c0d3f --- /dev/null +++ b/synology/synoconfigs/epyc7003ntb @@ -0,0 +1,5819 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +CONFIG_X86_AMD_PLATFORM_DEVICE=y +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=24 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_NUMA_EMU=y +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +# CONFIG_KVM_INTEL is not set +CONFIG_KVM_AMD=m +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +CONFIG_SYNO_EPYC7003NTB=y +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +# CONFIG_SYNO_SATA_PWR_CTRL_GPIO is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +# CONFIG_SYNO_SATA_SPINUP_GROUP is not set +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +# CONFIG_SYNO_NVME_WAIT_DISK_READY is not set +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_SMBUS_HDDMON is not set +CONFIG_SYNO_HWMON_PMBUS=y +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +CONFIG_SYNO_I2C_DW_FORCE_PROBE=y +CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LED_ATMEGA1608=m +CONFIG_SYNO_LED_ATMEGA1608_SEG7=m +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +CONFIG_SYNO_IOMMU_AMD_USB_QUIRK=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=4 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +CONFIG_SYNO_PCI_DOMAIN_PATH=y +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +CONFIG_SYNO_NTB_ENHANCE_LINK=y +CONFIG_SYNO_NTB_FIX_CLEANUP_WORK_PANIC=y +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_CONTIG_ALLOC=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_AREAS=7 +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_EDR is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +CONFIG_LIBFC=m +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NTB_NETDEV=m +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_DECODE_MCE=y +CONFIG_EDAC_AMD64=y +# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set +# CONFIG_EDAC_E752X is not set +# CONFIG_EDAC_I82975X is not set +# CONFIG_EDAC_I3000 is not set +# CONFIG_EDAC_I3200 is not set +# CONFIG_EDAC_IE31200 is not set +# CONFIG_EDAC_X38 is not set +# CONFIG_EDAC_I5400 is not set +# CONFIG_EDAC_I7CORE is not set +# CONFIG_EDAC_I5000 is not set +# CONFIG_EDAC_I5100 is not set +# CONFIG_EDAC_I7300 is not set +# CONFIG_EDAC_SBRIDGE is not set +# CONFIG_EDAC_SKX is not set +# CONFIG_EDAC_I10NM is not set +# CONFIG_EDAC_PND2 is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_NTB=m +# CONFIG_NTB_MSI is not set +CONFIG_NTB_AMD=m +# CONFIG_NTB_IDT is not set +# CONFIG_NTB_INTEL is not set +# CONFIG_NTB_SWITCHTEC is not set +# CONFIG_NTB_PINGPONG is not set +# CONFIG_NTB_TOOL is not set +# CONFIG_NTB_PERF is not set +CONFIG_NTB_TRANSPORT=m +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +CONFIG_DMA_CMA=y +# CONFIG_DMA_PERNUMA_CMA is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=12 +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/fst-ci-config b/synology/synoconfigs/fst-ci-config new file mode 100644 index 000000000000..f43f51d8b2ce --- /dev/null +++ b/synology/synoconfigs/fst-ci-config @@ -0,0 +1,4721 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=110200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CONSTRUCTORS=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +# CONFIG_UAPI_HEADER_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="FST-CI" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_PREEMPTION=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_PSI is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_EXPERT=y +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RCU=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_TASKS_TRACE_RCU_READ_MB is not set +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +# CONFIG_NUMA_BALANCING is not set +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_WRITEBACK=y +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_CGROUP_PIDS=y +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_HUGETLB is not set +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_SOCK_CGROUP_DATA=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_RD_LZO=y +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_PCSPKR_PLATFORM=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_HAVE_ARCH_USERFAULTFD_WP=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_PRELOAD is not set +CONFIG_USERFAULTFD=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_KCMP=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +# CONFIG_EMBEDDED is not set +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_SLUB_MEMCG_SYSFS_ON=y +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +CONFIG_SLUB_CPU_PARTIAL=y +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_KASAN_SHADOW_OFFSET=0xdffffc0000000000 +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +CONFIG_X86_EXTENDED_PLATFORM=y +# CONFIG_X86_NUMACHIP is not set +# CONFIG_X86_VSMP is not set +# CONFIG_X86_UV is not set +# CONFIG_X86_GOLDFISH is not set +# CONFIG_X86_INTEL_MID is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +CONFIG_IOSF_MBI=y +# CONFIG_IOSF_MBI_DEBUG is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_DEBUG is not set +# CONFIG_PARAVIRT_SPINLOCKS is not set +CONFIG_X86_HV_CALLBACK_VECTOR=y +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +# CONFIG_PROCESSOR_SELECT is not set +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_ZHAOXIN=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=64 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_MC_PRIO=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +# CONFIG_X86_MCE_INJECT is not set +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# end of Performance monitoring + +CONFIG_X86_16BIT=y +CONFIG_X86_ESPFIX64=y +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +CONFIG_MICROCODE=y +CONFIG_MICROCODE_INTEL=y +CONFIG_MICROCODE_AMD=y +# CONFIG_MICROCODE_OLD_INTERFACE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +CONFIG_AMD_NUMA=y +CONFIG_X86_64_ACPI_NUMA=y +# CONFIG_NUMA_EMU is not set +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +CONFIG_X86_CHECK_BIOS_CORRUPTION=y +CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +CONFIG_X86_PAT=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +CONFIG_EFI_STUB=y +CONFIG_EFI_MIXED=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +# CONFIG_KEXEC_FILE is not set +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x1000000 +CONFIG_RELOCATABLE=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_X86_NEED_RELOCS=y +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_DYNAMIC_MEMORY_LAYOUT=y +CONFIG_RANDOMIZE_MEMORY=y +CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0x0 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +# CONFIG_LEGACY_VSYSCALL_EMULATE is not set +CONFIG_LEGACY_VSYSCALL_XONLY=y +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_MODIFY_LDT_SYSCALL=y +CONFIG_HAVE_LIVEPATCH=y +# CONFIG_LIVEPATCH is not set +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +CONFIG_PM_TRACE=y +CONFIG_PM_TRACE_RTC=y +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y +# CONFIG_ACPI_EC_DEBUGFS is not set +CONFIG_ACPI_AC=y +CONFIG_ACPI_BATTERY=y +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_VIDEO=y +CONFIG_ACPI_FAN=y +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_CPPC_LIB=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=y +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +CONFIG_ACPI_BGRT=y +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_STAT is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +CONFIG_X86_INTEL_PSTATE=y +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +CONFIG_HALTPOLL_CPUIDLE=y +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_RUNTIME_MAP=y +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_RESET_ATTACK_MITIGATION is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +# CONFIG_KVM is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +CONFIG_SYNO_KVMX64=y +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7003NTB is not set +# CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR is not set +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +# CONFIG_SYNO_PORT_MAPPING_V2 is not set +# CONFIG_SYNO_SWAP_FLAG is not set +CONFIG_SYNO_DATA_CORRECTION=y +# CONFIG_SYNO_ISCSI_DEVICE is not set +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT=10 +# CONFIG_SYNO_ECC_NOTIFICATION is not set +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +# CONFIG_SYNO_INTERNAL_NETIF_NUM is not set +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +# CONFIG_SYNO_KERNEL_UTC_TIME is not set +# CONFIG_SYNO_SOFTLOCKUP_COUNTER is not set +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_KVMX64_MQ_TIMEOUT=1024 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +# CONFIG_SYNO_HUNG_TASK_ADJUSTMENT is not set +# CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE is not set +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +# CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY is not set +# CONFIG_SYNO_SKIP_RXDROP_BY_CORE is not set +# CONFIG_SYNO_IPV6_RFC_4862 is not set +# CONFIG_SYNO_BONDING_INIT_STATUS is not set +# CONFIG_SYNO_BONDING_FIX_ACTIVE is not set +# CONFIG_SYNO_FIX_8023AD_LINK_STATUS is not set +# CONFIG_SYNO_IPV6_LINKLOCAL is not set +# CONFIG_SYNO_OVS_MODE_REFINEMENT is not set +# CONFIG_SYNO_NF_NAT_WORKAROUND is not set +# CONFIG_SYNO_NET_ALB_FIX_OVERFLOW is not set +# CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD is not set +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +# CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS is not set +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +# CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY is not set +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +# CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC is not set +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +# CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL is not set +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +# CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL is not set +# CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT is not set +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +# CONFIG_SYNO_DISK_HIBERNATION is not set +# CONFIG_SYNO_SCSI_INQUIRY_STANDARD is not set +# CONFIG_SYNO_SCSI_GET_ATA_IDENTITY is not set +# CONFIG_SYNO_SCSI_DISK_SERIAL is not set +# CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT is not set +# CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS is not set +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y + +# +# SATA +# +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +# CONFIG_SYNO_SATA_DEBUG_FLAG is not set +# CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG is not set +# CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION is not set +# CONFIG_SYNO_SATA_PMP_ENHANCE is not set +# CONFIG_SYNO_SATA_DEEPSLEEP is not set +# CONFIG_SYNO_SATA_SIGNAL_CHECK is not set +# CONFIG_SYNO_SATA_SIGNAL_TEST is not set +# CONFIG_SYNO_SATA_MV92XX_PORTING is not set +# CONFIG_SYNO_SATA_MV9170_PORTING is not set +# CONFIG_SYNO_SATA_DISK_LED_CONTROL is not set +# CONFIG_SYNO_AHCI_SWITCH is not set +# CONFIG_SYNO_KVMX64_MAX_MEDIUM_ACCESS_TIMEOUTS is not set +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +# CONFIG_SYNO_SATA_WCACHE_DISABLE is not set +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +# CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA is not set +# CONFIG_SYNO_SATA_HANDLE_EIO_DISKS is not set +# CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH is not set +# CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM is not set +# CONFIG_SYNO_SATA_SSD_DETECT is not set +# CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER is not set +# CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT is not set +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +# CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST is not set +# CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG is not set +# CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA is not set +# CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT is not set +# CONFIG_SYNO_SATA_PRINT_SN is not set +# CONFIG_SYNO_SATA_NCQ_EH_ENHANCE is not set +# CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE is not set +# CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY is not set +# CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE is not set +# CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME is not set +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST is not set +# CONFIG_SYNO_SATA_PORT_THAW is not set +# CONFIG_SYNO_SATA_RECOVER_MECHANISM is not set +# CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY is not set +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_SATA_PWR_CTRL_TEST is not set +# CONFIG_SYNO_AHCI_REG_READ_TEST is not set +# end of SATA +# end of SCSI + +# +# Network +# +# CONFIG_SYNO_NET_BOND_ALB_INFO is not set +# CONFIG_SYNO_NET_LINK_DOWN_STATUS is not set +# end of Network + +# +# USB +# +# CONFIG_SYNO_USB_SERIAL_FIX is not set +# CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY is not set +# CONFIG_SYNO_USB_RESET_WAIT is not set +# CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK is not set +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +# CONFIG_SYNO_USB_FORBID is not set +# CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK is not set +# CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY is not set +# CONFIG_SYNO_USB_STOR_EXTRA_DELAY is not set +# CONFIG_SYNO_USB_CONNECT_DEBOUNCER is not set +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +# CONFIG_SYNO_USB_POWER_RESET is not set +# CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION is not set +# CONFIG_SYNO_USB_DEVICE_QUIRKS is not set +# CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# end of USB + +# +# Hardware Monitor +# +# end of Hardware Monitor + +# +# Serial/TTYs +# +# CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT is not set +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +# CONFIG_SYNO_TTY_MICROP_CTRL is not set +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +# CONFIG_SYNO_SERIAL_CONSOLE_FORBID is not set +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +# CONFIG_SYNO_I2C_I801_POLL is not set +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +# CONFIG_SYNO_LEDS_TRIGGER is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +# CONFIG_SYNO_IOMMU_PASSTHROUGH is not set +# end of IOMMU + +# +# RTC +# +# CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK is not set +# end of RTC + +# +# PCI +# +# CONFIG_SYNO_PCI_MISSING_DEVICE is not set +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +# end of GPIO + +# +# SYNO Device Tree +# +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +# end of FAT + +# +# EXT3 +# +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +# CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR is not set +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +# CONFIG_SYNO_BTRFS_SYNO_QUOTA is not set +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +# CONFIG_SYNO_NFSD_HIDDEN_FILE is not set +# CONFIG_SYNO_NFSD_UDP_PACKET is not set +# CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN is not set +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +# end of HFSPLUS + +# +# UDF +# +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +# CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS is not set +# end of OverlayFS + +# +# AUFS +# +# end of AUFS + +# +# ConfigFS +# +# CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE is not set +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +# CONFIG_SYNO_FORCE_CF9_REBOOT is not set +# CONFIG_SYNO_OOM_NOTIFICATION is not set +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +# CONFIG_SYNO_POWEROFF_INFO_PRINT is not set +# CONFIG_SYNO_SPECULATION_DEFAULT_OFF is not set +# CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE is not set +# CONFIG_SYNO_PLUGIN_INTERFACE is not set +# CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK is not set +# CONFIG_SYNO_SYNOBIOS_EVENT is not set +# CONFIG_SYNO_DISABLE_AUDITSYSCALL is not set +CONFIG_SYNO_DEV_ALLOC_PAGES=y +# CONFIG_SYNO_RND_ENTROPY_GEN is not set +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +# CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN is not set +# end of Encryption + +# +# Udev +# +# CONFIG_SYNO_DEPRECATED_UEVENT_ENV is not set +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +# CONFIG_SYNO_BIOS_ACPI_FPDT is not set +# end of Bios Log + +# +# Synology Protection +# +# CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK is not set +# CONFIG_SYNO_KEXEC_TEST is not set +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_RQ_ALLOC_TIME=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_CGROUP_RWSTAT=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_ZONED is not set +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_DEV_THROTTLING_LOW=y +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLK_CGROUP_IOLATENCY=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=m +CONFIG_BFQ_GROUP_IOSCHED=y +# CONFIG_BFQ_CGROUP_DEBUG is not set +# end of IO Schedulers + +CONFIG_ASN1=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +CONFIG_BALLOON_COMPACTION=y +CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +# CONFIG_ZSMALLOC is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y +CONFIG_ARCH_HAS_PKEYS=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=y +CONFIG_XFRM_ESP=y +# CONFIG_NET_KEY is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +CONFIG_IP_MROUTE_COMMON=y +CONFIG_IP_MROUTE=y +# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +# CONFIG_INET_IPCOMP is not set +CONFIG_INET_TUNNEL=y +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_CDG is not set +# CONFIG_TCP_CONG_BBR is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +CONFIG_NETLABEL=y +# CONFIG_MPTCP is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_ADVANCED is not set + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_LABELS is not set +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_SIP=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m + +# +# Xtables targets +# +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +# end of Core Netfilter Configuration + +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m +CONFIG_NF_REJECT_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_RAW is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +CONFIG_NF_REJECT_IPV6=y +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_IPV6HEADER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +# CONFIG_IP6_NF_RAW is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ 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_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +CONFIG_NET_CLS_CGROUP=y +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_IPT is not set +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_MPLS is not set +# CONFIG_NET_ACT_VLAN is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_GATE is not set +# CONFIG_NET_TC_SKB_EXT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_MPLS is not set +# CONFIG_NET_NSH is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +CONFIG_NET_L3_MASTER_DEV=y +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +CONFIG_CGROUP_NET_CLASSID=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +CONFIG_FAILOVER=y +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +# CONFIG_HOTPLUG_PCI_PCIE is not set +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIE_ECRC is not set +CONFIG_PCIEASPM=y +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +# CONFIG_PCIEASPM_PERFORMANCE is not set +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER is not set +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_DEVRES=y +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +# CONFIG_OF is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +CONFIG_PNP_DEBUG_MESSAGES=y + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION=y +# CONFIG_BLK_DEV_FD is not set +CONFIG_CDROM=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=y +CONFIG_BLK_DEV_RBD=m +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +CONFIG_SCSI_DEBUG=m +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +CONFIG_SCSI_VIRTIO=y +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_ATA_SFF is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID456 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +CONFIG_DM_BIO_PRISON=m +CONFIG_DM_PERSISTENT_DATA=m +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_CRYPT is not set +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +CONFIG_DM_MIRROR=y +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_RAID is not set +CONFIG_DM_ZERO=y +CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_QL is not set +# CONFIG_DM_MULTIPATH_ST is not set +# CONFIG_DM_MULTIPATH_HST is not set +CONFIG_DM_DELAY=m +CONFIG_DM_DUST=m +# CONFIG_DM_INIT is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +CONFIG_DM_LOG_WRITES=m +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +CONFIG_DUMMY=m +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_IPVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=y +# CONFIG_NETCONSOLE_DYNAMIC is not set +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_VETH is not set +CONFIG_VIRTIO_NET=y +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=y +# CONFIG_LED_TRIGGER_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVRES=y +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Host-side USB support is needed for USB Network Adapter support +# +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=y +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_LEDS=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_MOUSE=y +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_SERIAL_WACOM4=m +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_PNP=y +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +CONFIG_SERIAL_8250_MID=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +# CONFIG_N_HDLC is not set +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +CONFIG_HVC_DRIVER=y +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +CONFIG_VIRTIO_CONSOLE=y +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +# CONFIG_DEVKMEM is not set +CONFIG_NVRAM=y +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +CONFIG_HPET=y +# CONFIG_HPET_MMAP is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_ACPI_I2C_OPREGION=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +# CONFIG_PINCTRL is not set +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_POWER_SUPPLY_HWMON=y +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_BATTERY_CW2015 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_RT5033 is not set +# CONFIG_CHARGER_BD99954 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2990 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_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_LM63 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR 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_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +CONFIG_THERMAL_GOV_USER_SPACE=y +# CONFIG_THERMAL_EMULATION is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +CONFIG_X86_PKG_TEMP_THERMAL=m +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_SYSFS is not set + +# +# Watchdog Pretimeout Governors +# + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_EBC_C384_WDT is not set +# CONFIG_F71808E_WDT is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_IE6XX_WDT is not set +# CONFIG_ITCO_WDT is not set +# CONFIG_IT8712F_WDT is not set +# CONFIG_IT87_WDT is not set +# CONFIG_HP_WATCHDOG is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_NV_TCO is not set +# CONFIG_60XX_WDT is not set +# CONFIG_CPU5_WDT is not set +# CONFIG_SMSC_SCH311X_WDT is not set +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_TQMX86_WDT is not set +# CONFIG_VIA_WDT is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C 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_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX14577 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VESA is not set +CONFIG_FB_EFI=y +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# end of Console display driver support + +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y +# end of Graphics support + +# CONFIG_SOUND is not set + +# +# HID support +# +# CONFIG_HID is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_DECODE_MCE=y +# CONFIG_EDAC_AMD64 is not set +# CONFIG_EDAC_E752X is not set +# CONFIG_EDAC_I82975X is not set +# CONFIG_EDAC_I3000 is not set +# CONFIG_EDAC_I3200 is not set +# CONFIG_EDAC_IE31200 is not set +# CONFIG_EDAC_X38 is not set +# CONFIG_EDAC_I5400 is not set +# CONFIG_EDAC_I7CORE is not set +# CONFIG_EDAC_I5000 is not set +# CONFIG_EDAC_I5100 is not set +# CONFIG_EDAC_I7300 is not set +# CONFIG_EDAC_SBRIDGE is not set +# CONFIG_EDAC_SKX is not set +# CONFIG_EDAC_I10NM is not set +# CONFIG_EDAC_PND2 is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_FTRTC010 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_ACPI=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# 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_HSU_DMA=y +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VFIO is not set +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO=y +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +# CONFIG_STAGING is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_THINKPAD_ACPI is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_TURBO_MAX_3 is not set +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 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_CDCE706 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_I8253_LOCK=y +CONFIG_CLKBLD_I8253=y +# end of Clock Source drivers + +CONFIG_MAILBOX=y +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +# CONFIG_AMD_IOMMU is not set +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +# CONFIG_IRQ_REMAP is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +CONFIG_DAX=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT2=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y +CONFIG_BTRFS_DEBUG=y +CONFIG_BTRFS_ASSERT=y +CONFIG_BTRFS_FS_REF_VERIFY=y +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_FS_DAX=y +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_EXPORTFS_BLOCK_OPS=y +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_ALGS=y +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS4_FS=y +CONFIG_AUTOFS_FS=y +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +CONFIG_VIRTIO_FS=m +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +# CONFIG_AUFS_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +CONFIG_ZISOFS=y +# CONFIG_UDF_FS is not set +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_EXFAT_FS=m +CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_VMCORE_DEVICE_DUMP=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_CHILDREN=y +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +CONFIG_EFIVAR_FS=m +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_SWAP is not set +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_PNFS_FILE_LAYOUT=y +CONFIG_PNFS_BLOCK=y +CONFIG_PNFS_FLEXFILE_LAYOUT=y +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="n" +# CONFIG_NFS_V4_1_MIGRATION is not set +CONFIG_NFS_V4_SECURITY_LABEL=y +CONFIG_ROOT_NFS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DISABLE_UDP_SUPPORT=y +CONFIG_NFS_V4_2_READ_PLUS=y +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +CONFIG_NFSD_V4_2_INTER_SSC=y +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_BACKCHANNEL=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +# CONFIG_SUNRPC_DEBUG is not set +CONFIG_CEPH_FS=m +# CONFIG_CEPH_FS_POSIX_ACL is not set +# CONFIG_CEPH_FS_SECURITY_LABEL is not set +# CONFIG_CIFS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITY_WRITABLE_HOOKS=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_INTEL_TXT is not set +CONFIG_LSM_MMAP_MIN_ADDR=65536 +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_FALLBACK=y +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_FORTIFY_SOURCE=y +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0 +CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS=9 +CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE=256 +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=y +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_ENGINE=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=y +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_ESSIV is not set + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=m +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_ZSTD is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_PADLOCK is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +CONFIG_CRYPTO_DEV_VIRTIO=m +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y + +# +# Certificates for signature checking +# +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=m +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DYNAMIC_DEBUG_CORE=y +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +CONFIG_DEBUG_INFO_COMPRESSED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +CONFIG_HEADERS_INSTALL=y +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +CONFIG_UBSAN=y +# CONFIG_UBSAN_TRAP is not set +CONFIG_UBSAN_BOUNDS=y +CONFIG_UBSAN_MISC=y +CONFIG_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN_ALIGNMENT is not set +# CONFIG_TEST_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_NO_SANITY=y +# CONFIG_PAGE_POISONING_ZERO is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_RODATA_TEST is not set +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +CONFIG_SLUB_DEBUG_ON=y +CONFIG_SLUB_STATS=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +CONFIG_KASAN=y +CONFIG_KASAN_GENERIC=y +# CONFIG_KASAN_OUTLINE is not set +CONFIG_KASAN_INLINE=y +CONFIG_KASAN_STACK=1 +CONFIG_KASAN_VMALLOC=y +# CONFIG_TEST_KASAN_MODULE is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set +CONFIG_DEBUG_PREEMPT=y + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_PROVE_LOCKING=y +# CONFIG_PROVE_RAW_LOCK_NESTING is not set +CONFIG_LOCK_STAT=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y +CONFIG_DEBUG_RWSEMS=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_LOCKDEP=y +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_TRACE_IRQFLAGS=y +CONFIG_TRACE_IRQFLAGS_NMI=y +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +CONFIG_PROVE_RCU=y +# CONFIG_PROVE_RCU_LIST is not set +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_TRACE=y +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_STRICT_GRACE_PERIOD is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_LATENCYTOP=y +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_PREEMPTIRQ_TRACEPOINTS=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_HWLAT_TRACER=y +CONFIG_MMIOTRACE=y +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_TRACER_SNAPSHOT is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_SYNTH_EVENTS is not set +# CONFIG_HIST_TRIGGERS is not set +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_MMIOTRACE_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +CONFIG_PROVIDE_OHCI1394_DMA_INIT=y +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +CONFIG_STRICT_DEVMEM=y +# CONFIG_IO_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_EARLY_PRINTK_USB=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +CONFIG_EARLY_PRINTK_DBGP=y +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEBUG_BOOT_PARAMS=y +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_X86_DEBUG_FPU=y +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +CONFIG_FAULT_INJECTION=y +# CONFIG_FAILSLAB is not set +# CONFIG_FAIL_PAGE_ALLOC is not set +# CONFIG_FAULT_INJECTION_USERCOPY is not set +CONFIG_FAIL_MAKE_REQUEST=y +# CONFIG_FAIL_IO_TIMEOUT is not set +# CONFIG_FAIL_FUTEX is not set +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAIL_FUNCTION=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/fst-locker-config b/synology/synoconfigs/fst-locker-config new file mode 100644 index 000000000000..f74414f342cd --- /dev/null +++ b/synology/synoconfigs/fst-locker-config @@ -0,0 +1,3239 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="Ubuntu clang version 15.0.6" +CONFIG_GCC_VERSION=0 +CONFIG_LD_VERSION=238000000 +CONFIG_CC_IS_CLANG=y +CONFIG_CLANG_VERSION=150006 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CONSTRUCTORS=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +# CONFIG_UAPI_HEADER_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="FST-Dev" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ is not set +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_PREEMPTION=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_PSI is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_EXPERT=y +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RCU=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_TASKS_TRACE_RCU_READ_MB is not set +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_WRITEBACK=y +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +# CONFIG_CGROUP_FREEZER is not set +# CONFIG_CGROUP_HUGETLB is not set +# CONFIG_CPUSETS is not set +# CONFIG_CGROUP_DEVICE is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_SOCK_CGROUP_DATA=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_HAVE_ARCH_USERFAULTFD_WP=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_PRELOAD is not set +CONFIG_USERFAULTFD=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_KCMP=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +# CONFIG_EMBEDDED is not set +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_SLUB_MEMCG_SYSFS_ON=y +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +CONFIG_SLUB_CPU_PARTIAL=y +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_KASAN_SHADOW_OFFSET=0xdffffc0000000000 +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +# CONFIG_X86_X2APIC is not set +# CONFIG_X86_MPPARSE is not set +# CONFIG_GOLDFISH is not set +# CONFIG_RETPOLINE is not set +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_DEBUG is not set +# CONFIG_PARAVIRT_SPINLOCKS is not set +CONFIG_X86_HV_CALLBACK_VECTOR=y +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +# CONFIG_PROCESSOR_SELECT is not set +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_ZHAOXIN=y +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=64 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_MC_PRIO=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +# CONFIG_X86_MCE is not set + +# +# Performance monitoring +# +# CONFIG_PERF_EVENTS_INTEL_UNCORE is not set +# CONFIG_PERF_EVENTS_INTEL_RAPL is not set +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# end of Performance monitoring + +CONFIG_X86_16BIT=y +CONFIG_X86_ESPFIX64=y +CONFIG_X86_VSYSCALL_EMULATION=y +# CONFIG_X86_IOPL_IOPERM is not set +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +# CONFIG_MTRR is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +# CONFIG_EFI is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x1000000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_LEGACY_VSYSCALL_EMULATE is not set +CONFIG_LEGACY_VSYSCALL_XONLY=y +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_MODIFY_LDT_SYSCALL=y +CONFIG_HAVE_LIVEPATCH=y +# CONFIG_LIVEPATCH is not set +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +# CONFIG_SUSPEND is not set +# CONFIG_HIBERNATION is not set +# CONFIG_PM is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +# CONFIG_ACPI_SPCR_TABLE is not set +CONFIG_ACPI_LPIT=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_DOCK is not set +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_CPPC_LIB=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +# CONFIG_CPU_FREQ_STAT is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +CONFIG_X86_INTEL_PSTATE=y +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=y +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +# CONFIG_HALTPOLL_CPUIDLE is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +# CONFIG_PCI_MMCONFIG is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_DMA_API is not set +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +# CONFIG_IA32_EMULATION is not set +# CONFIG_X86_X32 is not set +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_DMIID is not set +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_VIRTUALIZATION=y +# CONFIG_KVM is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +# CONFIG_OPROFILE is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +CONFIG_SYNO_KVMX64=y +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +# CONFIG_SYNO_PORT_MAPPING_V2 is not set +# CONFIG_SYNO_SWAP_FLAG is not set +CONFIG_SYNO_DATA_CORRECTION=y +# CONFIG_SYNO_ISCSI_DEVICE is not set +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT=10 +# CONFIG_SYNO_ECC_NOTIFICATION is not set +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +# CONFIG_SYNO_INTERNAL_NETIF_NUM is not set +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +# CONFIG_SYNO_KERNEL_UTC_TIME is not set +# CONFIG_SYNO_SOFTLOCKUP_COUNTER is not set +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_KVMX64_MQ_TIMEOUT=1024 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +# CONFIG_SYNO_HUNG_TASK_ADJUSTMENT is not set +# CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE is not set +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +# CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY is not set +# CONFIG_SYNO_SKIP_RXDROP_BY_CORE is not set +# CONFIG_SYNO_IPV6_RFC_4862 is not set +# CONFIG_SYNO_BONDING_INIT_STATUS is not set +# CONFIG_SYNO_BONDING_FIX_ACTIVE is not set +# CONFIG_SYNO_FIX_8023AD_LINK_STATUS is not set +# CONFIG_SYNO_IPV6_LINKLOCAL is not set +# CONFIG_SYNO_OVS_MODE_REFINEMENT is not set +# CONFIG_SYNO_NF_NAT_WORKAROUND is not set +# CONFIG_SYNO_NET_ALB_FIX_OVERFLOW is not set +# CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD is not set +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +# CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS is not set +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +# CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY is not set +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +# CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC is not set +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +# CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL is not set +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +# CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL is not set +# CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT is not set +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +# CONFIG_SYNO_DISK_HIBERNATION is not set +# CONFIG_SYNO_SCSI_INQUIRY_STANDARD is not set +# CONFIG_SYNO_SCSI_GET_ATA_IDENTITY is not set +# CONFIG_SYNO_SCSI_DISK_SERIAL is not set +# CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT is not set +# CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS is not set +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y + +# +# SATA +# +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +# CONFIG_SYNO_SATA_DEBUG_FLAG is not set +# CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG is not set +# CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION is not set +# CONFIG_SYNO_SATA_DEEPSLEEP is not set +# CONFIG_SYNO_SATA_SIGNAL_CHECK is not set +# CONFIG_SYNO_SATA_SIGNAL_TEST is not set +# CONFIG_SYNO_SATA_MV92XX_PORTING is not set +# CONFIG_SYNO_SATA_MV9170_PORTING is not set +# CONFIG_SYNO_SATA_DISK_LED_CONTROL is not set +# CONFIG_SYNO_KVMX64_MAX_MEDIUM_ACCESS_TIMEOUTS is not set +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +# CONFIG_SYNO_SATA_WCACHE_DISABLE is not set +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +# CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA is not set +# CONFIG_SYNO_SATA_HANDLE_EIO_DISKS is not set +# CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH is not set +# CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM is not set +# CONFIG_SYNO_SATA_SSD_DETECT is not set +# CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER is not set +# CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT is not set +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +# CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST is not set +# CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG is not set +# CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA is not set +# CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT is not set +# CONFIG_SYNO_SATA_PRINT_SN is not set +# CONFIG_SYNO_SATA_NCQ_EH_ENHANCE is not set +# CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE is not set +# CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY is not set +# CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE is not set +# CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME is not set +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST is not set +# CONFIG_SYNO_SATA_PORT_THAW is not set +# CONFIG_SYNO_SATA_RECOVER_MECHANISM is not set +# CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY is not set +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_SATA_PWR_CTRL_TEST is not set +# CONFIG_SYNO_AHCI_REG_READ_TEST is not set +# end of SATA +# end of SCSI + +# +# Network +# +# CONFIG_SYNO_NET_BOND_ALB_INFO is not set +# CONFIG_SYNO_NET_LINK_DOWN_STATUS is not set +# end of Network + +# +# USB +# +# CONFIG_SYNO_USB_SERIAL_FIX is not set +# CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY is not set +# CONFIG_SYNO_USB_RESET_WAIT is not set +# CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK is not set +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +# CONFIG_SYNO_USB_FORBID is not set +# CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK is not set +# CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY is not set +# CONFIG_SYNO_USB_STOR_EXTRA_DELAY is not set +# CONFIG_SYNO_USB_CONNECT_DEBOUNCER is not set +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +# CONFIG_SYNO_USB_POWER_RESET is not set +# CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION is not set +# CONFIG_SYNO_USB_DEVICE_QUIRKS is not set +# CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# end of USB + +# +# Hardware Monitor +# +# end of Hardware Monitor + +# +# Serial/TTYs +# +# CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT is not set +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +# CONFIG_SYNO_TTY_MICROP_CTRL is not set +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +# CONFIG_SYNO_SERIAL_CONSOLE_FORBID is not set +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +# CONFIG_SYNO_I2C_I801_POLL is not set +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +# CONFIG_SYNO_IOMMU_PASSTHROUGH is not set +# end of IOMMU + +# +# RTC +# +# CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK is not set +# end of RTC + +# +# PCI +# +# CONFIG_SYNO_PCI_MISSING_DEVICE is not set +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +# end of GPIO + +# +# SYNO Device Tree +# +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +# end of FAT + +# +# EXT3 +# +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +# CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR is not set +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +# CONFIG_SYNO_BTRFS_SYNO_QUOTA is not set +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +# end of HFSPLUS + +# +# UDF +# +# end of UDF + +# +# FUSE +# +# end of FUSE + +# +# OverlayFS +# +# end of OverlayFS + +# +# AUFS +# +# end of AUFS + +# +# ConfigFS +# +# CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE is not set +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +# CONFIG_SYNO_FORCE_CF9_REBOOT is not set +# CONFIG_SYNO_OOM_NOTIFICATION is not set +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +# CONFIG_SYNO_POWEROFF_INFO_PRINT is not set +# CONFIG_SYNO_SPECULATION_DEFAULT_OFF is not set +# CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE is not set +# CONFIG_SYNO_PLUGIN_INTERFACE is not set +# CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK is not set +# CONFIG_SYNO_SYNOBIOS_EVENT is not set +# CONFIG_SYNO_DISABLE_AUDITSYSCALL is not set +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +# CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN is not set +# end of Encryption + +# +# Udev +# +# CONFIG_SYNO_DEPRECATED_UEVENT_ENV is not set +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +# CONFIG_SYNO_BIOS_ACPI_FPDT is not set +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +# CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK is not set +# CONFIG_SYNO_KEXEC_TEST is not set +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_WBT is not set +# CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CGROUP_IOCOST is not set +# CONFIG_BLK_DEBUG_FS is not set +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y +# end of Partition Types + +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y + +# +# IO Schedulers +# +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_IOSCHED_BFQ is not set +# end of IO Schedulers + +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ELFCORE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +# CONFIG_COMPACTION is not set +CONFIG_PAGE_REPORTING=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +# CONFIG_ZSMALLOC is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y +CONFIG_ARCH_HAS_PKEYS=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_ESP=y +# CONFIG_NET_KEY is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_IP_MROUTE_COMMON=y +CONFIG_IP_MROUTE=y +# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_FOU is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +# CONFIG_IPV6 is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETFILTER is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_MPLS is not set +# CONFIG_NET_NSH is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +CONFIG_FAILOVER=y +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_QUIRKS is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# + +# +# DesignWare PCI Core Support +# +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER is not set +# CONFIG_FW_LOADER_COMPRESS is not set +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_DEVRES=y +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MHI_BUS is not set +# end of Bus devices + +# CONFIG_CONNECTOR is not set +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +# CONFIG_OF is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=y +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_93CX6 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# end of Texas Instruments shared transport line discipline + +# +# Altera FPGA firmware download module (requires I2C) +# +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_HABANA_AI is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# end of SCSI device support + +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_IPVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_VETH is not set +CONFIG_VIRTIO_NET=y +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +# CONFIG_PHYLIB is not set +# CONFIG_MDIO_DEVICE is not set + +# +# PCS device drivers +# +# end of PCS device drivers + +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Host-side USB support is needed for USB Network Adapter support +# +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=y +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_PNP=y +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +CONFIG_SERIAL_8250_MID=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +# CONFIG_N_HDLC is not set +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +CONFIG_HVC_DRIVER=y +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +CONFIG_VIRTIO_CONSOLE=y +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +# CONFIG_DEVKMEM is not set +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +# CONFIG_I2C is not set +# end of I2C support + +# CONFIG_I3C is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +# CONFIG_PINCTRL is not set +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_MADERA is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +# CONFIG_FB is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +# CONFIG_LCD_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# end of Console display driver support +# end of Graphics support + +# CONFIG_SOUND is not set + +# +# HID support +# +# CONFIG_HID is not set + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=y +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=y +# CONFIG_VIRTIO_PCI_LEGACY is not set +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +# CONFIG_VDPA is not set +# CONFIG_VHOST_MENU is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +# CONFIG_STAGING is not set +# CONFIG_X86_PLATFORM_DEVICES is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# end of Clock Source drivers + +CONFIG_MAILBOX=y +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_IOMMU_SUPPORT is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +# CONFIG_NVMEM is not set + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT2=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_BTRFS_FS_CHECK_INTEGRITY=y +CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y +CONFIG_BTRFS_DEBUG=y +CONFIG_BTRFS_ASSERT=y +CONFIG_BTRFS_FS_REF_VERIFY=y +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_EXPORTFS_BLOCK_OPS=y +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_FUSE_FS is not set +# CONFIG_OVERLAY_FS is not set +# CONFIG_AUFS_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +CONFIG_PROC_VMCORE_DEVICE_DUMP=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_CHILDREN=y +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# end of Pseudo filesystems + +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_FALLBACK=y +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_FORTIFY_SOURCE=y +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +# CONFIG_INTEGRITY is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=y +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=y +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_ENGINE=y + +# +# Public-key cryptography +# +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +CONFIG_CRYPTO_GCM=y +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_ESSIV is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=y +CONFIG_CRYPTO_BLAKE2B=y +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +CONFIG_CRYPTO_GHASH=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1 is not set +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_ZSTD is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_PADLOCK is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +CONFIG_CRYPTO_DEV_VIRTIO=y +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set + +# +# Certificates for signature checking +# +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=y +# CONFIG_RAID6_PQ_BENCHMARK is not set +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_BTREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +# CONFIG_IRQ_POLL is not set +# CONFIG_DIMLIB is not set +CONFIG_OID_REGISTRY=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DYNAMIC_DEBUG_CORE=y +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +CONFIG_DEBUG_INFO_COMPRESSED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +CONFIG_GDB_SCRIPTS=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +CONFIG_HEADERS_INSTALL=y +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +CONFIG_UBSAN=y +# CONFIG_UBSAN_TRAP is not set +CONFIG_UBSAN_BOUNDS=y +CONFIG_UBSAN_MISC=y +CONFIG_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN_ALIGNMENT is not set +# CONFIG_TEST_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_POISONING=y +CONFIG_PAGE_POISONING_NO_SANITY=y +# CONFIG_PAGE_POISONING_ZERO is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_RODATA_TEST is not set +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +CONFIG_DEBUG_OBJECTS=y +# CONFIG_DEBUG_OBJECTS_SELFTEST is not set +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_SLUB_STATS=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_KASAN_SW_TAGS=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +CONFIG_KASAN=y +CONFIG_KASAN_GENERIC=y +# CONFIG_KASAN_OUTLINE is not set +CONFIG_KASAN_INLINE=y +# CONFIG_KASAN_STACK_ENABLE is not set +CONFIG_KASAN_STACK=0 +CONFIG_KASAN_VMALLOC=y +# CONFIG_TEST_KASAN_MODULE is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +CONFIG_DEBUG_TIMEKEEPING=y +CONFIG_DEBUG_PREEMPT=y + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_PROVE_LOCKING=y +# CONFIG_PROVE_RAW_LOCK_NESTING is not set +CONFIG_LOCK_STAT=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y +CONFIG_DEBUG_RWSEMS=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_LOCKDEP=y +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_TRACE_IRQFLAGS=y +CONFIG_TRACE_IRQFLAGS_NMI=y +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +CONFIG_PROVE_RCU=y +# CONFIG_PROVE_RCU_LIST is not set +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_TRACE=y +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_STRICT_GRACE_PERIOD is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_PREEMPTIRQ_TRACEPOINTS=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_HWLAT_TRACER=y +CONFIG_MMIOTRACE=y +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_TRACER_SNAPSHOT is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_SYNTH_EVENTS is not set +# CONFIG_HIST_TRIGGERS is not set +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_MMIOTRACE_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +CONFIG_STRICT_DEVMEM=y +# CONFIG_IO_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_EARLY_PRINTK_USB=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +CONFIG_EARLY_PRINTK_DBGP=y +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEBUG_BOOT_PARAMS=y +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_X86_DEBUG_FPU=y +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +CONFIG_FAULT_INJECTION=y +# CONFIG_FAILSLAB is not set +# CONFIG_FAIL_PAGE_ALLOC is not set +# CONFIG_FAULT_INJECTION_USERCOPY is not set +# CONFIG_FAIL_MAKE_REQUEST is not set +# CONFIG_FAIL_IO_TIMEOUT is not set +# CONFIG_FAIL_FUTEX is not set +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAIL_FUNCTION=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +# CONFIG_RUNTIME_TESTING_MENU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/geminilakelk5 b/synology/synoconfigs/geminilakelk5 new file mode 100644 index 000000000000..5b4ea1c25613 --- /dev/null +++ b/synology/synoconfigs/geminilakelk5 @@ -0,0 +1,5925 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_KCMP=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +# CONFIG_X86_MPPARSE is not set +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +CONFIG_IOSF_MBI=m +# CONFIG_IOSF_MBI_DEBUG is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=8 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +# CONFIG_X86_MCE_AMD is not set +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +# CONFIG_ACPI_DOCK is not set +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +CONFIG_KVM_INTEL=m +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +CONFIG_SYNO_GEMINILAKE=y +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_INTEL_PSTATE_CALC=y +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_X86_CORETEMP=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +# CONFIG_SYNO_ECC_NOTIFICATION is not set +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +# CONFIG_SYNO_I2C_OF_PROBE is not set +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +CONFIG_SYNO_HARDLOCKUP_PANIC_ENHANCE=y +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +# CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY is not set +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_PWR_CTRL_GPIO=y +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +CONFIG_SYNO_SATA_SPINUP_GROUP=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST=y +CONFIG_SYNO_SATA_ASM1061_RESET_DELEY=y +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +CONFIG_SYNO_SATA_SIGNAL_ADJUST=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +CONFIG_SYNO_USB_XHCI_RESET_DELAY=y +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD=y +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_HDDMON=m +# CONFIG_SYNO_HWMON_PMBUS is not set +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_SHORT_TIME_STUCK_FIX=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# CONFIG_SYNO_I2C_DW_FORCE_PROBE is not set +# CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS is not set +CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI=y +# CONFIG_SYNO_LED_ATMEGA1608 is not set +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND=y +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG=y +CONFIG_SYNO_BIOS_MRC_POSTCODE_CMOS_ADDR=0x48 +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_VMAP_PFN=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL 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_MEI_HDCP is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +CONFIG_PINCTRL_INTEL=y +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +CONFIG_PINCTRL_GEMINILAKE=y +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +CONFIG_SENSORS_CORETEMP=y +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +CONFIG_THERMAL_GOV_USER_SPACE=y +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +CONFIG_MFD_INTEL_LPSS=y +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +CONFIG_MFD_INTEL_LPSS_PCI=y +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +CONFIG_AGP=y +# CONFIG_AGP_AMD64 is not set +CONFIG_AGP_INTEL=y +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_VIA is not set +CONFIG_INTEL_GTT=y +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +CONFIG_DRM=m +CONFIG_DRM_MIPI_DSI=y +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +CONFIG_DRM_KMS_HELPER=m +CONFIG_DRM_KMS_FB_HELPER=y +# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_DP_CEC is not set + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# end of I2C encoder or helper chips + +# +# ARM devices +# +# CONFIG_DRM_KOMEDA is not set +# end of ARM devices + +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_NOUVEAU is not set +CONFIG_DRM_I915=m +CONFIG_DRM_I915_FORCE_PROBE="" +CONFIG_DRM_I915_CAPTURE_ERROR=y +CONFIG_DRM_I915_COMPRESS_ERROR=y +CONFIG_DRM_I915_USERPTR=y +# CONFIG_DRM_I915_GVT is not set + +# +# drm/i915 Debugging +# +# CONFIG_DRM_I915_WERROR is not set +# CONFIG_DRM_I915_DEBUG is not set +# CONFIG_DRM_I915_DEBUG_MMIO is not set +# CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS is not set +# CONFIG_DRM_I915_SW_FENCE_CHECK_DAG is not set +# CONFIG_DRM_I915_DEBUG_GUC is not set +# CONFIG_DRM_I915_SELFTEST is not set +# CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS is not set +# CONFIG_DRM_I915_DEBUG_VBLANK_EVADE is not set +# CONFIG_DRM_I915_DEBUG_RUNTIME_PM is not set +# end of drm/i915 Debugging + +# +# drm/i915 Profile Guided Optimisation +# +CONFIG_DRM_I915_FENCE_TIMEOUT=10000 +CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 +CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 +CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 +CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 +CONFIG_DRM_I915_STOP_TIMEOUT=100 +CONFIG_DRM_I915_TIMESLICE_DURATION=1 +# end of drm/i915 Profile Guided Optimisation + +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_BOCHS is not set +CONFIG_DRM_PANEL=y + +# +# Display Panels +# +# CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596 is not set +# CONFIG_DRM_PANEL_BOE_HIMAX8279D is not set +# CONFIG_DRM_PANEL_BOE_TV101WUM_NL6 is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_SIMPLE is not set +# CONFIG_DRM_PANEL_ELIDA_KD35T133 is not set +# CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02 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_LEADTEK_LTK050H3146W is not set +# CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT35510 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set +# CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 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_RONBO_RB070D30 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_S6E88A0_AMS452EF01 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_LS043T1LE01 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7703 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX424AKP is not set +# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set +# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DRM_PANEL_TPO_TPG110 is not set +# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set +# CONFIG_DRM_PANEL_VISIONOX_RM69299 is not set +# CONFIG_DRM_PANEL_XINPENG_XPP055C272 is not set +# end of Display Panels + +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_PANEL_BRIDGE=y + +# +# Display Interface Bridges +# +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CHRONTEL_CH7033 is not set +# CONFIG_DRM_DISPLAY_CONNECTOR is not set +# CONFIG_DRM_LONTIUM_LT9611 is not set +# CONFIG_DRM_LVDS_CODEC is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_NWL_MIPI_DSI is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PARADE_PS8640 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIMPLE_BRIDGE is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TOSHIBA_TC358762 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_TOSHIBA_TC358768 is not set +# CONFIG_DRM_TOSHIBA_TC358775 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_TI_TPD12S015 is not set +# CONFIG_DRM_ANALOGIX_ANX6345 is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_CDNS_MHDP8546 is not set +# end of Display Interface Bridges + +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_ILI9486 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_DRM_VBOXVIDEO is not set +# CONFIG_DRM_LEGACY is not set +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=m + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_INTEL is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +CONFIG_HDMI=y + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +CONFIG_SND_PCM_TIMER=y +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y +# CONFIG_HDMI_LPE_AUDIO is not set + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +CONFIG_INTEL_IDMA64=y +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +# CONFIG_AMD_IOMMU is not set +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +# CONFIG_IRQ_REMAP is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/icelaked b/synology/synoconfigs/icelaked new file mode 100644 index 000000000000..fe03b830d673 --- /dev/null +++ b/synology/synoconfigs/icelaked @@ -0,0 +1,5787 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +# CONFIG_X86_X2APIC is not set +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=24 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +# CONFIG_X86_MCE_AMD is not set +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +CONFIG_ACPI_HED=y +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +CONFIG_ACPI_APEI=y +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_PCIEAER=y +# CONFIG_ACPI_APEI_EINJ is not set +# CONFIG_ACPI_APEI_ERST_DEBUG is not set +# CONFIG_ACPI_DPTF is not set +CONFIG_ACPI_EXTLOG=y +CONFIG_ACPI_ADXL=y +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_UEFI_CPER=y +CONFIG_UEFI_CPER_X86=y +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +CONFIG_KVM_INTEL=m +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +CONFIG_SYNO_ICELAKED=y +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_INTEL_PSTATE_CALC=y +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_X86_CORETEMP=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +# CONFIG_SYNO_SATA_PWR_CTRL_GPIO is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +# CONFIG_SYNO_SATA_SPINUP_GROUP is not set +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +CONFIG_SYNO_NVME_WAIT_DISK_READY=y +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +CONFIG_SYNO_USB_XHCI_RESET_DELAY=y +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +CONFIG_SYNO_USB_EXTERNAL_HUB=y +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_SMBUS_HDDMON is not set +CONFIG_SYNO_HWMON_PMBUS=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI is not set +# CONFIG_SYNO_LEDS_LP3943_PROBE_OF is not set +CONFIG_SYNO_LED_ATMEGA1608=m +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +CONFIG_SYNO_RTC_PT7C4337_SUPPORT=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=2 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +CONFIG_SYNO_PCI_DOMAIN_PATH=y +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +CONFIG_SYNO_ACPI_APEI_AER_DBGMSG=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_EDR is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +# CONFIG_PCI_PRI is not set +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +CONFIG_LIBFC=m +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +CONFIG_IGB_DCA=y +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +CONFIG_SERIAL_8250_MID=y +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_PCA9541 is not set +CONFIG_I2C_MUX_PCA954x=y +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +CONFIG_PINCTRL_INTEL=y +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +CONFIG_PINCTRL_CEDARFORK=y +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +CONFIG_SENSORS_CORETEMP=y +CONFIG_SENSORS_IT87=y +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP50XX is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_GHES=y +CONFIG_EDAC_E752X=y +CONFIG_EDAC_I82975X=y +CONFIG_EDAC_I3000=y +CONFIG_EDAC_I3200=y +CONFIG_EDAC_IE31200=y +CONFIG_EDAC_X38=y +CONFIG_EDAC_I5400=y +CONFIG_EDAC_I7CORE=y +CONFIG_EDAC_I5000=y +CONFIG_EDAC_I5100=y +CONFIG_EDAC_I7300=y +CONFIG_EDAC_SBRIDGE=y +CONFIG_EDAC_SKX=y +CONFIG_EDAC_I10NM=y +CONFIG_EDAC_PND2=y +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +CONFIG_INTEL_IOATDMA=m +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# 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_HSU_DMA=y +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE_RAID=y + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +CONFIG_DCA=m +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +# CONFIG_AMD_IOMMU is not set +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/kvmx64lk5 b/synology/synoconfigs/kvmx64lk5 new file mode 100644 index 000000000000..258b5e5f49ed --- /dev/null +++ b/synology/synoconfigs/kvmx64lk5 @@ -0,0 +1,5493 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 8.5.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=80500 +CONFIG_LD_VERSION=230000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +# CONFIG_HIGH_RES_TIMERS is not set +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_DEBUG is not set +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_X86_HV_CALLBACK_VECTOR=y +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=128 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +# CONFIG_RELOCATABLE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +CONFIG_HALTPOLL_CPUIDLE=y +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +# CONFIG_VIRTUALIZATION is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +CONFIG_SYNO_KVMX64=y +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_X86_CORETEMP=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +# CONFIG_SYNO_INTERNAL_HD_NUM is not set +CONFIG_SYNO_VIRTIO_SCSI_DEVICE=y +CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT=10 +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +# CONFIG_SYNO_I2C_OF_PROBE is not set +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_KVMX64_MQ_TIMEOUT=1024 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +# CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL is not set +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +# CONFIG_SYNO_DISK_HIBERNATION is not set +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +# CONFIG_SYNO_SATA_PWR_CTRL is not set +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +# CONFIG_SYNO_SATA_PMP_ENHANCE is not set +# CONFIG_SYNO_SATA_EUNIT_SUPPORT is not set +# CONFIG_SYNO_SATA_DEEPSLEEP is not set +# CONFIG_SYNO_SATA_SIGNAL_CHECK is not set +# CONFIG_SYNO_SATA_SIGNAL_TEST is not set +# CONFIG_SYNO_SATA_MV92XX_PORTING is not set +# CONFIG_SYNO_SATA_MV9170_PORTING is not set +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +# CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_KVMX64_MAX_MEDIUM_ACCESS_TIMEOUTS=y +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +# CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST is not set +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +# CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY is not set +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST is not set +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +# CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY is not set +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +# CONFIG_SYNO_SATA_PWR_CTRL_TEST is not set +# CONFIG_SYNO_AHCI_REG_READ_TEST is not set +# end of SATA +# end of SCSI + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +# CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK is not set +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +# CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK is not set +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +# CONFIG_SYNO_USB_POWER_RESET is not set +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +# CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION is not set +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +# CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE is not set +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_HWMON_PMBUS is not set +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +# CONFIG_SYNO_TTY_MICROP_CTRL is not set +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +# CONFIG_SYNO_I2C_I801_POLL is not set +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +# CONFIG_SYNO_LEDS_TRIGGER is not set +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +# CONFIG_SYNO_IOMMU_PASSTHROUGH is not set +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +# CONFIG_SYNO_PCI_MISSING_DEVICE is not set +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +# CONFIG_BALLOON_COMPACTION is not set +CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +CONFIG_FAILOVER=m +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=m +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +CONFIG_ENCLOSURE_SERVICES=y +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +# CONFIG_NETCONSOLE is not set +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=m +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +CONFIG_IGB_DCA=y +CONFIG_IGBVF=m +# CONFIG_IXGB is not set +CONFIG_IXGBE=m +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_DCA=y +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=m +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +CONFIG_HVC_DRIVER=y +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +CONFIG_VIRTIO_CONSOLE=m +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=y +CONFIG_HW_RANDOM_INTEL=y +CONFIG_HW_RANDOM_AMD=y +# CONFIG_HW_RANDOM_BA431 is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=m +# CONFIG_HW_RANDOM_CCTRNG is not set +# CONFIG_HW_RANDOM_XIPHERA is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=m +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=m +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +# CONFIG_PINCTRL is not set +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +CONFIG_SENSORS_CORETEMP=y +CONFIG_SENSORS_IT87=y +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +CONFIG_INTEL_IOATDMA=m +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# 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_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE_RAID=y + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +CONFIG_DCA=m +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_BALLOON=m +# CONFIG_VIRTIO_INPUT is not set +CONFIG_VIRTIO_MMIO=m +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_AMD_IOMMU is not set +# CONFIG_INTEL_IOMMU is not set +# CONFIG_IRQ_REMAP is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +# CONFIG_9P_FS_SECURITY is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/kvmx64sofs b/synology/synoconfigs/kvmx64sofs new file mode 100644 index 000000000000..05f6444c30d1 --- /dev/null +++ b/synology/synoconfigs/kvmx64sofs @@ -0,0 +1,5516 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +# CONFIG_HIGH_RES_TIMERS is not set +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_DEBUG is not set +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_X86_HV_CALLBACK_VECTOR=y +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=128 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +# CONFIG_RELOCATABLE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +CONFIG_HALTPOLL_CPUIDLE=y +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +# CONFIG_VIRTUALIZATION is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +CONFIG_SYNO_KVMX64SOFS=y +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_X86_CORETEMP=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +# CONFIG_SYNO_INTERNAL_HD_NUM is not set +CONFIG_SYNO_VIRTIO_SCSI_DEVICE=y +CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT=10 +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +# CONFIG_SYNO_I2C_OF_PROBE is not set +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_KVMX64_MQ_TIMEOUT=1024 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +# CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL is not set +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +# CONFIG_SYNO_DISK_HIBERNATION is not set +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +# CONFIG_SYNO_SATA_PWR_CTRL is not set +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +# CONFIG_SYNO_SATA_PMP_ENHANCE is not set +# CONFIG_SYNO_SATA_EUNIT_SUPPORT is not set +# CONFIG_SYNO_SATA_DEEPSLEEP is not set +# CONFIG_SYNO_SATA_SIGNAL_CHECK is not set +# CONFIG_SYNO_SATA_SIGNAL_TEST is not set +# CONFIG_SYNO_SATA_MV92XX_PORTING is not set +# CONFIG_SYNO_SATA_MV9170_PORTING is not set +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +# CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_KVMX64_MAX_MEDIUM_ACCESS_TIMEOUTS=y +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +# CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST is not set +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +# CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY is not set +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST is not set +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +# CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY is not set +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +# CONFIG_SYNO_SATA_PWR_CTRL_TEST is not set +# CONFIG_SYNO_AHCI_REG_READ_TEST is not set +# end of SATA +# end of SCSI + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +# CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK is not set +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +# CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK is not set +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +# CONFIG_SYNO_USB_POWER_RESET is not set +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +# CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION is not set +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +# CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE is not set +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_HWMON_PMBUS is not set +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +# CONFIG_SYNO_TTY_MICROP_CTRL is not set +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +# CONFIG_SYNO_I2C_I801_POLL is not set +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +# CONFIG_SYNO_LEDS_TRIGGER is not set +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +# CONFIG_SYNO_IOMMU_PASSTHROUGH is not set +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +# CONFIG_SYNO_PCI_MISSING_DEVICE is not set +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +CONFIG_SYNO_CEPH_RECVFILE=y +CONFIG_SYNO_CEPH_STAT=y +CONFIG_SYNO_CEPH_CREATE_TIME=y +CONFIG_SYNO_CEPH_ARCHIVE_BIT=y +CONFIG_SYNO_CEPH_CASELESS_STAT=y +CONFIG_SYNO_CEPH_WINACL=y +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH=y +CONFIG_SYNO_CEPH_SKIP_CRC=y +CONFIG_SYNO_CEPH_IDENTIFY_POOL_XATTR_IS_ID=y +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +# CONFIG_BALLOON_COMPACTION is not set +CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set +# CONFIG_CAIF is not set +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +CONFIG_FAILOVER=m +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_RBD=m +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +CONFIG_ENCLOSURE_SERVICES=y +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +# CONFIG_NETCONSOLE is not set +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=m +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +CONFIG_IGB_DCA=y +CONFIG_IGBVF=m +# CONFIG_IXGB is not set +CONFIG_IXGBE=m +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_DCA=y +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=m +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +CONFIG_HVC_DRIVER=y +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +CONFIG_VIRTIO_CONSOLE=m +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=y +CONFIG_HW_RANDOM_INTEL=y +CONFIG_HW_RANDOM_AMD=y +# CONFIG_HW_RANDOM_BA431 is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=m +# CONFIG_HW_RANDOM_CCTRNG is not set +# CONFIG_HW_RANDOM_XIPHERA is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=m +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=m +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +# CONFIG_PINCTRL is not set +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +CONFIG_SENSORS_CORETEMP=y +CONFIG_SENSORS_IT87=y +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +CONFIG_INTEL_IOATDMA=m +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# 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_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE_RAID=y + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +CONFIG_DCA=m +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_BALLOON=m +# CONFIG_VIRTIO_INPUT is not set +CONFIG_VIRTIO_MMIO=m +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_AMD_IOMMU is not set +# CONFIG_INTEL_IOMMU is not set +# CONFIG_IRQ_REMAP is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +# CONFIG_CEPH_FS_POSIX_ACL is not set +# CONFIG_CEPH_FS_SECURITY_LABEL is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +# CONFIG_9P_FS_SECURITY is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/kvmx64v2 b/synology/synoconfigs/kvmx64v2 new file mode 100644 index 000000000000..41d6f4895d92 --- /dev/null +++ b/synology/synoconfigs/kvmx64v2 @@ -0,0 +1,5517 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +# CONFIG_HIGH_RES_TIMERS is not set +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_DEBUG is not set +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_X86_HV_CALLBACK_VECTOR=y +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=128 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +# CONFIG_RELOCATABLE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +CONFIG_HALTPOLL_CPUIDLE=y +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +# CONFIG_VIRTUALIZATION is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +CONFIG_SYNO_KVMX64V2=y +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_X86_CORETEMP=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +# CONFIG_SYNO_INTERNAL_HD_NUM is not set +CONFIG_SYNO_VIRTIO_SCSI_DEVICE=y +CONFIG_SYNO_KVMX64_PCI_SLOT_BOOT=10 +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +# CONFIG_SYNO_I2C_OF_PROBE is not set +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_KVMX64_MQ_TIMEOUT=1024 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +# CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL is not set +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +# CONFIG_SYNO_DISK_HIBERNATION is not set +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +# CONFIG_SYNO_SATA_PWR_CTRL is not set +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +# CONFIG_SYNO_SATA_PMP_ENHANCE is not set +# CONFIG_SYNO_SATA_EUNIT_SUPPORT is not set +# CONFIG_SYNO_SATA_DEEPSLEEP is not set +# CONFIG_SYNO_SATA_SIGNAL_CHECK is not set +# CONFIG_SYNO_SATA_SIGNAL_TEST is not set +# CONFIG_SYNO_SATA_MV92XX_PORTING is not set +# CONFIG_SYNO_SATA_MV9170_PORTING is not set +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +# CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_KVMX64_MAX_MEDIUM_ACCESS_TIMEOUTS=y +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +# CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST is not set +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +# CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY is not set +# CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY is not set +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST is not set +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +# CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY is not set +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +# CONFIG_SYNO_SATA_PWR_CTRL_TEST is not set +# CONFIG_SYNO_AHCI_REG_READ_TEST is not set +# end of SATA +# end of SCSI + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +# CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK is not set +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +# CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK is not set +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +# CONFIG_SYNO_USB_POWER_RESET is not set +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +# CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION is not set +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +# CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE is not set +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_HWMON_PMBUS is not set +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +# CONFIG_SYNO_TTY_MICROP_CTRL is not set +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +# CONFIG_SYNO_I2C_I801_POLL is not set +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +# CONFIG_SYNO_LEDS_TRIGGER is not set +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +# CONFIG_SYNO_IOMMU_PASSTHROUGH is not set +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +# CONFIG_SYNO_PCI_MISSING_DEVICE is not set +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +CONFIG_SYNO_CEPH_RECVFILE=y +CONFIG_SYNO_CEPH_STAT=y +CONFIG_SYNO_CEPH_CREATE_TIME=y +CONFIG_SYNO_CEPH_ARCHIVE_BIT=y +CONFIG_SYNO_CEPH_CASELESS_STAT=y +CONFIG_SYNO_CEPH_WINACL=y +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH=y +CONFIG_SYNO_CEPH_SKIP_CRC=y +CONFIG_SYNO_CEPH_IDENTIFY_POOL_XATTR_IS_ID=y +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +# CONFIG_BALLOON_COMPACTION is not set +CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +# CONFIG_NET_9P_DEBUG is not set +# CONFIG_CAIF is not set +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +CONFIG_FAILOVER=m +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_RBD=m +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +CONFIG_ENCLOSURE_SERVICES=y +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +# CONFIG_NETCONSOLE is not set +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=m +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +CONFIG_IGB_DCA=y +CONFIG_IGBVF=m +# CONFIG_IXGB is not set +CONFIG_IXGBE=m +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_DCA=y +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=m +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +CONFIG_HVC_DRIVER=y +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +CONFIG_VIRTIO_CONSOLE=m +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=y +CONFIG_HW_RANDOM_INTEL=y +CONFIG_HW_RANDOM_AMD=y +# CONFIG_HW_RANDOM_BA431 is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=m +# CONFIG_HW_RANDOM_CCTRNG is not set +# CONFIG_HW_RANDOM_XIPHERA is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=m +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=m +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +# CONFIG_PINCTRL is not set +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +CONFIG_SENSORS_CORETEMP=y +CONFIG_SENSORS_IT87=y +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +CONFIG_INTEL_IOATDMA=m +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# 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_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE_RAID=y + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +CONFIG_DCA=m +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO=m +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_BALLOON=m +# CONFIG_VIRTIO_INPUT is not set +CONFIG_VIRTIO_MMIO=m +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_AMD_IOMMU is not set +# CONFIG_INTEL_IOMMU is not set +# CONFIG_IRQ_REMAP is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +# CONFIG_CEPH_FS_POSIX_ACL is not set +# CONFIG_CEPH_FS_SECURITY_LABEL is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +# CONFIG_9P_FS_SECURITY is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/purleylk5 b/synology/synoconfigs/purleylk5 new file mode 100644 index 000000000000..d50427538e72 --- /dev/null +++ b/synology/synoconfigs/purleylk5 @@ -0,0 +1,5810 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +# CONFIG_X86_X2APIC is not set +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=64 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +# CONFIG_X86_MCE_AMD is not set +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_NUMA_EMU=y +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +CONFIG_ACPI_HED=y +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +CONFIG_ACPI_APEI=y +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_PCIEAER=y +# CONFIG_ACPI_APEI_EINJ is not set +# CONFIG_ACPI_APEI_ERST_DEBUG is not set +# CONFIG_ACPI_DPTF is not set +CONFIG_ACPI_EXTLOG=y +CONFIG_ACPI_ADXL=y +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_UEFI_CPER=y +CONFIG_UEFI_CPER_X86=y +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +CONFIG_KVM_INTEL=m +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +CONFIG_SYNO_PURLEY=y +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_SAS=y +CONFIG_SYNO_INTEL_PSTATE_CALC=y +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_X86_CORETEMP=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_MULTI_CPU_NUM=2 +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +CONFIG_SYNO_HARDLOCKUP_PANIC_ENHANCE=y +CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION=y +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_PWR_CTRL_GPIO=y +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +# CONFIG_SYNO_SATA_PMP_ENHANCE is not set +# CONFIG_SYNO_SATA_EUNIT_SUPPORT is not set +# CONFIG_SYNO_SATA_DEEPSLEEP is not set +# CONFIG_SYNO_SATA_SPINUP_GROUP is not set +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +# CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER is not set +CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY=y +# CONFIG_SYNO_SATA_JMB585_FIX is not set +# CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX is not set +# CONFIG_SYNO_SATA_JMB585_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE is not set +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +# CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN is not set +# CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST is not set +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +CONFIG_SYNO_SATA_SIGNAL_ADJUST=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +# end of SATA + +# +# SAS +# +CONFIG_SYNO_SAS_DEVICE_PREFIX="sas" +CONFIG_SYNO_SAS_FIX_ENCLOSURE_POWEROFF_WARNON=y +CONFIG_SYNO_SAS_SYSFS_BLOCK_DEV_LINK=y +CONFIG_SYNO_SAS_SPINUP_DELAY=y +# CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG is not set +CONFIG_SYNO_SAS_SHOW_DISK_PHY_INFO=y +CONFIG_SYNO_SAS_HBA_IDX=y +CONFIG_SYNO_SAS_MAX_HBA_SLOT=2 +CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL=y +CONFIG_SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF=y +CONFIG_SYNO_SAS_SES_DIAGNOSTIC_PAGE_ENHANCE=y +CONFIG_SYNO_SAS_SATA_EARLY_WAKEUP=y +# end of SAS +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +CONFIG_SYNO_NVME_SW_ACTIVITY=y +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +CONFIG_SYNO_NVME_WAIT_DISK_READY=y +CONFIG_SYNO_NVME_SAMSUNG_QDEPTH=y +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=13 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +CONFIG_SYNO_USB_XHCI_RESET_DELAY=y +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=2 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +# CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION is not set +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +CONFIG_SYNO_ADT7490_PECI1_ENABLE=y +# CONFIG_SYNO_HDDMON is not set +CONFIG_SYNO_HWMON_PMBUS=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI is not set +# CONFIG_SYNO_LEDS_LP3943_PROBE_OF is not set +CONFIG_SYNO_LED_ATMEGA1608=m +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=4 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +CONFIG_SYNO_ACPI_APEI_AER_DBGMSG=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_EDR is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +# CONFIG_PCI_PRI is not set +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +CONFIG_ENCLOSURE_SERVICES=y +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_MPT2SAS_MAX_SGE=128 +CONFIG_SCSI_MPT3SAS_MAX_SGE=128 +CONFIG_SCSI_MPT2SAS=m +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +CONFIG_LIBFC=m +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +# CONFIG_DM_MULTIPATH_HST is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +CONFIG_IGB_DCA=y +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +CONFIG_I2C_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +CONFIG_PINCTRL_INTEL=y +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set +CONFIG_SYNO_PINCTRL_LEWISBURG=y + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +CONFIG_SENSORS_CORETEMP=y +CONFIG_SENSORS_IT87=y +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_GHES=y +CONFIG_EDAC_E752X=y +CONFIG_EDAC_I82975X=y +CONFIG_EDAC_I3000=y +CONFIG_EDAC_I3200=y +CONFIG_EDAC_IE31200=y +CONFIG_EDAC_X38=y +CONFIG_EDAC_I5400=y +CONFIG_EDAC_I7CORE=y +CONFIG_EDAC_I5000=y +CONFIG_EDAC_I5100=y +CONFIG_EDAC_I7300=y +CONFIG_EDAC_SBRIDGE=y +CONFIG_EDAC_SKX=y +CONFIG_EDAC_I10NM=y +CONFIG_EDAC_PND2=y +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +CONFIG_INTEL_IOATDMA=m +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# 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_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE_RAID=y + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +CONFIG_DCA=m +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +# CONFIG_AMD_IOMMU is not set +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/rtd1619b b/synology/synoconfigs/rtd1619b new file mode 100644 index 000000000000..e65b9b66e72b --- /dev/null +++ b/synology/synoconfigs/rtd1619b @@ -0,0 +1,6002 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="aarch64-unknown-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_IRQ_IPI=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_GENERIC_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_HAVE_FUTEX_CMPXCHG=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_KCMP=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_ARM64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_CONT_PTE_SHIFT=4 +CONFIG_ARM64_CONT_PMD_SHIFT=4 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA32=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_SMP=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_PROC_KCORE_TEXT=y + +# +# Platform selection +# +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AGILEX is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BITMAIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SPARX5 is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_KEEMBAY is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_QCOM is not set +CONFIG_ARCH_REALTEK=y +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_S32 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VISCONTI is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQMP is not set +# end of Platform selection + +# +# Kernel Features +# + +# +# ARM errata workarounds via the alternatives framework +# +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +CONFIG_ARM64_ERRATUM_1024718=y +# CONFIG_ARM64_ERRATUM_1418040 is not set +# CONFIG_ARM64_ERRATUM_1165522 is not set +# CONFIG_ARM64_ERRATUM_1319367 is not set +# CONFIG_ARM64_ERRATUM_1530923 is not set +# CONFIG_ARM64_ERRATUM_1286807 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_1542419 is not set +# CONFIG_ARM64_ERRATUM_1508412 is not set +# CONFIG_CAVIUM_ERRATUM_22375 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_TX2_ERRATUM_219 is not set +# CONFIG_FUJITSU_ERRATUM_010001 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# end of ARM errata workarounds via the alternatives framework + +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_16K_PAGES is not set +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_PA_BITS_48=y +CONFIG_ARM64_PA_BITS=48 +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +# CONFIG_NUMA is not set +CONFIG_HOLES_IN_ZONE=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HW_PERF_EVENTS=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_CC_HAVE_SHADOW_CALL_STACK=y +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_KEXEC=y +# CONFIG_KEXEC_FILE is not set +CONFIG_CRASH_DUMP=y +# CONFIG_XEN is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_RODATA_FULL_DEFAULT_ENABLED=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_ARM64_TAGGED_ADDR_ABI=y +CONFIG_COMPAT=y +CONFIG_KUSER_HELPERS=y +CONFIG_ARMV8_DEPRECATED=y +# CONFIG_SWP_EMULATION is not set +# CONFIG_CP15_BARRIER_EMULATION is not set +# CONFIG_SETEND_EMULATION is not set + +# +# ARMv8.1 architectural features +# +CONFIG_ARM64_HW_AFDBM=y +CONFIG_ARM64_PAN=y +CONFIG_AS_HAS_LSE_ATOMICS=y +# CONFIG_ARM64_VHE is not set +# end of ARMv8.1 architectural features + +# +# ARMv8.2 architectural features +# +CONFIG_ARM64_UAO=y +# CONFIG_ARM64_PMEM is not set +CONFIG_ARM64_RAS_EXTN=y +CONFIG_ARM64_CNP=y +# end of ARMv8.2 architectural features + +# +# ARMv8.3 architectural features +# +CONFIG_ARM64_PTR_AUTH=y +CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y +CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y +CONFIG_AS_HAS_PAC=y +CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y +# end of ARMv8.3 architectural features + +# +# ARMv8.4 architectural features +# +# CONFIG_ARM64_AMU_EXTN is not set +CONFIG_AS_HAS_ARMV8_4=y +# CONFIG_ARM64_TLB_RANGE is not set +# end of ARMv8.4 architectural features + +# +# ARMv8.5 architectural features +# +# CONFIG_ARM64_BTI is not set +CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y +# CONFIG_ARM64_E0PD is not set +# CONFIG_ARCH_RANDOM is not set +CONFIG_ARM64_AS_HAS_MTE=y +CONFIG_ARM64_MTE=y +# end of ARMv8.5 architectural features + +CONFIG_ARM64_SVE=y +CONFIG_ARM64_MODULE_PLTS=y +# CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y +# end of Kernel Features + +# +# Boot options +# +CONFIG_CMDLINE="" +# CONFIG_EFI is not set +# end of Boot options + +CONFIG_SYSVIPC_COMPAT=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_CPU_PM=y +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# end of Power management options + +# +# CPU Power Management +# + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set + +# +# ARM CPU Idle Drivers +# +# CONFIG_ARM_CPUIDLE is not set +# CONFIG_ARM_PSCI_CPUIDLE is not set +# end of ARM CPU Idle Drivers +# end of CPU Idle + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +# end of CPU Frequency scaling +# end of CPU Power Management + +# +# Firmware Drivers +# +# CONFIG_ARM_SCMI_PROTOCOL is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SDE_INTERFACE is not set +CONFIG_FIRMWARE_MEMMAP=y +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_PSCI_CHECKER is not set +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y +# CONFIG_ARM_SMCCC_SOC_ID is not set + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_IRQ_BYPASS_MANAGER=m +CONFIG_VIRTUALIZATION=y +# CONFIG_KVM is not set +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA256_ARM64=y +# CONFIG_CRYPTO_SHA512_ARM64 is not set +# CONFIG_CRYPTO_SHA1_ARM64_CE is not set +CONFIG_CRYPTO_SHA2_ARM64_CE=y +# CONFIG_CRYPTO_SHA512_ARM64_CE is not set +# CONFIG_CRYPTO_SHA3_ARM64 is not set +# CONFIG_CRYPTO_SM3_ARM64_CE is not set +# CONFIG_CRYPTO_SM4_ARM64_CE is not set +# CONFIG_CRYPTO_GHASH_ARM64_CE is not set +# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set +CONFIG_CRYPTO_AES_ARM64=y +CONFIG_CRYPTO_AES_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +# CONFIG_CRYPTO_CHACHA20_NEON is not set +# CONFIG_CRYPTO_POLY1305_NEON is not set +# CONFIG_CRYPTO_NHPOLY1305_NEON is not set +CONFIG_CRYPTO_AES_ARM64_BS=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_SET_FS=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_KEEPINITRD=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_ARCH_SUPPORTS_SHADOW_CALL_STACK=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 +CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_COMPILER_H=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_SELECT_PLATFORM=y +CONFIG_SYNO_RTD1619B=y +CONFIG_SYNO_INTEL_PSTATE_CALC=y +CONFIG_SYNO_LSP_RTD1619B=y +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +# CONFIG_SYNO_I2C_OF_PROBE is not set +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +# CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY is not set +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +# CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT is not set +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_PWR_CTRL_GPIO=y +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +CONFIG_SYNO_SATA_SPINUP_GROUP=y +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +# CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER is not set +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST=y +CONFIG_SYNO_SATA_ASM1061_RESET_DELEY=y +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +CONFIG_SYNO_USB_XHCI_RESET_DELAY=y +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD=y +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_COPY=y +CONFIG_SYNO_USB_EXTERNAL_HUB=y +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_HDDMON=m +# CONFIG_SYNO_HWMON_PMBUS is not set +# end of Hardware Monitor + +# +# Serial/TTYs +# +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +CONFIG_SYNO_MTD_ALLOC=y +CONFIG_SYNO_MTD_INFO=y +CONFIG_SYNO_MTD_ACCESS_LOG=y +# CONFIG_SYNO_MTD_ACCESS_LOG_EXCEPT_VENDOR_PART is not set +# CONFIG_SYNO_MTD_ACCESS_LOG_EXCEPT_REDBOOTCONF_PART is not set +CONFIG_SYNO_MTD_LOCK_UNLOCK=y +CONFIG_SYNO_MTD_DYNAMIC_ERASESIZE=y +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# CONFIG_SYNO_I2C_DW_FORCE_PROBE is not set +# CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS=y +# CONFIG_SYNO_LED_ATMEGA1608 is not set +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_LEDS_TRIGGER_DISK=y +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +CONFIG_SYNO_RTC_PT7C4337_SUPPORT=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND=y +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +CONFIG_SYNO_PCI_DOMAIN_PATH=y +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# CONFIG_SYNO_PWM_CONTROL_LED is not set +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_ASN1=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK=y +CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_READ_LOCK=y +CONFIG_ARCH_INLINE_READ_LOCK_BH=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_READ_UNLOCK=y +CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_WRITE_LOCK=y +CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_SPIN_TRYLOCK=y +CONFIG_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_INLINE_SPIN_LOCK=y +CONFIG_INLINE_SPIN_LOCK_BH=y +CONFIG_INLINE_SPIN_LOCK_IRQ=y +CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_INLINE_SPIN_UNLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_READ_LOCK=y +CONFIG_INLINE_READ_LOCK_BH=y +CONFIG_INLINE_READ_LOCK_IRQ=y +CONFIG_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_BH=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_WRITE_LOCK=y +CONFIG_INLINE_WRITE_LOCK_BH=y +CONFIG_INLINE_WRITE_LOCK_IRQ=y +CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_BH=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_STATE=y +CONFIG_ARCH_HAVE_ELF_PROT=y +CONFIG_ARCH_USE_GNU_PROPERTY=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_CONTIG_ALLOC=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +CONFIG_CMA_DEBUGFS=y +CONFIG_CMA_AREAS=7 +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_ARM_AMBA=y +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_MSI_ARCH_FALLBACKS=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_IOV=y +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +CONFIG_PCIE_RTD=y +CONFIG_RTD16XXB_PCIE1_ACP=y +CONFIG_PCIE_RTD_TRANS=y + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCI_MESON is not set +# CONFIG_PCIE_AL is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_IRQ=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +CONFIG_GENERIC_ARCH_TOPOLOGY=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set + +# +# Partition parsers +# +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# end of Partition parsers + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +CONFIG_MTD_PSTORE=y +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# end of RAM/ROM/Flash chip drivers + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set +# end of Mapping drivers for chip access + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +# end of Self-contained MTD device drivers + +# +# NAND +# +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_RAW_NAND is not set +# CONFIG_MTD_SPI_NAND is not set + +# +# ECC engine support +# +# end of ECC engine support +# end of NAND + +# +# LPDDR & LPDDR2 PCM memory drivers +# +# CONFIG_MTD_LPDDR is not set +# end of LPDDR & LPDDR2 PCM memory drivers + +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_SPI_RTK_SFC=y +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_HYPERBUS is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AHCI_RTK=y +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_CRYPT is not set +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +# CONFIG_NETCONSOLE is not set +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +CONFIG_NET_VENDOR_HISILICON=y +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HNS3 is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +CONFIG_R8169SOC=y +CONFIG_RTL_RX_NO_COPY=y +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_IPQ8064 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_ASPEED_VUART=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +CONFIG_DEVMEM=y +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_TCG_TPM is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +CONFIG_I2C_REALTEK=y +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +CONFIG_PINCTRL_RTD=y +CONFIG_PINCTRL_RTD_SELFTEST=y + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +CONFIG_GPIO_RTD=y +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +CONFIG_GPIO_LOGICVC=y +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_PL061 is not set +CONFIG_GPIO_SAMA5D2_PIOBU=y +# CONFIG_GPIO_SIFIVE is not set +CONFIG_GPIO_SYSCON=y +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_BRCMSTB=y +# 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_RESTART is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +CONFIG_POWER_RESET_REGMAP_POWEROFF=y +CONFIG_REBOOT_MODE=y +CONFIG_SYSCON_REBOOT_MODE=y +# CONFIG_NVMEM_REBOOT_MODE is not set +CONFIG_POWER_RESET_RTK=y +CONFIG_RTK_REBOOT_MODE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_POWER_SUPPLY_HWMON=y +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_BATTERY_CW2015 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_LT3651 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_BQ2415X is not set +CONFIG_CHARGER_BQ24190=y +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ2515X is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_BQ25980 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_RT5033 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHARGER_BD99954 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR 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_OCC_P8_I2C is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_PWM_FAN 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +CONFIG_THERMAL_GOV_USER_SPACE=y +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set +CONFIG_RTK_THERMAL=y +CONFIG_RTK_THERMAL_CPU_CORE_COOLING=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_SYSFS is not set + +# +# Watchdog Pretimeout Governors +# +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ARM_SMC_WATCHDOG is not set +CONFIG_RTK_WATCHDOG=y +# CONFIG_RTD119X_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SYSCON=y +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +CONFIG_MFD_APW888X=y +CONFIG_MFD_APW8889_I2C=y +CONFIG_MFD_APW8886_I2C=y +# end of Multifunction device drivers + +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER_HELPER is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FAN53880 is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_ISL6271A 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_MAX77826 is not set +# CONFIG_REGULATOR_MCP16502 is not set +# CONFIG_REGULATOR_MP5416 is not set +# CONFIG_REGULATOR_MP8859 is not set +# CONFIG_REGULATOR_MP886X is not set +# CONFIG_REGULATOR_MPQ7920 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PCA9450 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_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set +# CONFIG_REGULATOR_RT4801 is not set +# CONFIG_REGULATOR_RTMV20 is not set +# CONFIG_REGULATOR_SLG51000 is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set +# CONFIG_REGULATOR_SY8827N 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_VCTRL is not set +CONFIG_REGULATOR_APW888X_CORE=y +CONFIG_REGULATOR_APW8889=y +CONFIG_REGULATOR_APW8886=y +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_DRM=m +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +CONFIG_DRM_KMS_HELPER=m +CONFIG_DRM_KMS_FB_HELPER=y +# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_DP_CEC is not set + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# end of I2C encoder or helper chips + +# +# ARM devices +# +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_KOMEDA is not set +# end of ARM devices + +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_BOCHS is not set +CONFIG_DRM_PANEL=y + +# +# Display Panels +# +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_SIMPLE is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set +# CONFIG_DRM_PANEL_LG_LG4573 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_SAMSUNG_S6E63M0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 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 +# end of Display Panels + +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_PANEL_BRIDGE=y + +# +# Display Interface Bridges +# +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CHRONTEL_CH7033 is not set +# CONFIG_DRM_DISPLAY_CONNECTOR is not set +# CONFIG_DRM_LONTIUM_LT9611 is not set +# CONFIG_DRM_LVDS_CODEC is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_NWL_MIPI_DSI is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PARADE_PS8640 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIMPLE_BRIDGE is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TOSHIBA_TC358762 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_TOSHIBA_TC358768 is not set +# CONFIG_DRM_TOSHIBA_TC358775 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_TI_TPD12S015 is not set +# CONFIG_DRM_ANALOGIX_ANX6345 is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_CDNS_MHDP8546 is not set +# end of Display Interface Bridges + +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_ILI9486 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_DRM_PL111 is not set +# CONFIG_DRM_LIMA is not set +# CONFIG_DRM_PANFROST is not set +# CONFIG_DRM_TIDSS is not set +# CONFIG_DRM_LEGACY is not set +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=m + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +CONFIG_HDMI=y + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +CONFIG_SND_PCM_TIMER=y +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_RTK_HCD_TEST_MODE is not set +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +CONFIG_USB_XHCI_PLATFORM=m +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_RTK is not set +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +CONFIG_USB_DWC3=m +CONFIG_USB_DWC3_HOST=y + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_RTK=m +CONFIG_USB_DWC3_HAPS=m +CONFIG_USB_DWC3_OF_SIMPLE=m +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +CONFIG_USB_PATCH_ON_RTK=y + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ULPI is not set +# CONFIG_RTK_USB_RLE0599_PHY is not set +CONFIG_RTK_USB2PHY=m +CONFIG_RTK_USB3PHY=m +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +CONFIG_LEDS_LP50XX=y +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_SYSCON=y +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_DRV_RTK=y + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_RTD119X is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_QDMA is not set +# CONFIG_HISI_DMA is not set +CONFIG_INTEL_IDMA64=y +# CONFIG_MV_XOR_V2 is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +# CONFIG_VFIO_PLATFORM is not set +# CONFIG_VFIO_MDEV is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +# CONFIG_GOLDFISH is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_CLK_QORIQ is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +CONFIG_COMMON_CLK_REALTEK=y +CONFIG_CLK_PLL_PSAUD=y +CONFIG_CLK_PLL_DIF=y +# CONFIG_COMMON_CLK_RTD1195 is not set +# CONFIG_COMMON_CLK_RTD1295 is not set +# CONFIG_COMMON_CLK_RTD1319 is not set +# CONFIG_COMMON_CLK_RTD1395 is not set +CONFIG_COMMON_CLK_RTD1619=y +CONFIG_COMMON_CLK_RTD1619B=y +CONFIG_CLK_DET=y +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_HISILICON_ERRATUM_161010101=y +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_ARM_MHU is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +# CONFIG_ARM_SMMU is not set +# CONFIG_ARM_SMMU_V3 is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# CONFIG_SOC_BRCMSTB is not set +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# CONFIG_QUICC_ENGINE is not set +# CONFIG_FSL_RCPM is not set +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# +# Realtek SoC drivers +# +# CONFIG_RTD13XX_RTK_CODEC is not set +# CONFIG_RTD16XXB_RTK_CODEC is not set +CONFIG_REALTEK_SOC=y +CONFIG_REALTEK_PM=y +CONFIG_RTK_MCP=y +# CONFIG_RTK_SC_WRAP_FSS is not set +CONFIG_RTK_USB_CTRL_MANAGER=m +CONFIG_REALTEK_CHIP_INFO=y +CONFIG_RTK_FAN=y +# CONFIG_RTK_FSS_SCAN is not set +CONFIG_RTK_VCPU=y +# CONFIG_RTK_VE3_UART is not set +# CONFIG_RTK_WATCHDOG_STATUS is not set +CONFIG_RTK_GPIO_DEFAULT=y +# CONFIG_RTK_VSFC_CTRL is not set +CONFIG_RTK_CPUHP_QOS=y +# CONFIG_RTK_CPUHP_CONTROL is not set +# CONFIG_RTK_CPU_VCLK is not set +CONFIG_RTK_BSV_CTRL=y +CONFIG_REALTEK_RPC=y +# CONFIG_REALTEK_RPC_VE3 is not set +CONFIG_ION_REALTEK=y +CONFIG_ION_SYSTEM_HEAP_REALTEK=y +CONFIG_ION_CARVEOUT_HEAP_REALTEK=y +CONFIG_ION_CHUNK_HEAP_REALTEK=y +CONFIG_ION_CMA_HEAP_REALTEK=y +CONFIG_ION_RTK_DHC_HEAP=y +# CONFIG_ION_RTK_LEGACY_DEVICE is not set +CONFIG_RTK_HSE=y + +# +# Realtek Power Domain +# +CONFIG_PD_REALTEK=y +# CONFIG_PD_RTD1295 is not set +# CONFIG_PD_RTD1395 is not set +# CONFIG_PD_RTD1619 is not set +CONFIG_PD_RTD1619B=y +# end of Realtek Power Domain + +CONFIG_RTK_INFO_PLL=y +CONFIG_RTK_CPU_VOLT_SEL=y +# CONFIG_RTK_BUFLOCK is not set +# end of Realtek SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +CONFIG_EXTCON=y + +# +# Extcon Device Drivers +# +CONFIG_EXTCON_FSA9480=y +CONFIG_EXTCON_GPIO=y +CONFIG_EXTCON_MAX3355=y +CONFIG_EXTCON_PTN5150=y +CONFIG_EXTCON_RT8973A=y +CONFIG_EXTCON_SM5502=y +CONFIG_EXTCON_USB_GPIO=y +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +# CONFIG_PWM_DEBUG is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWM_RTK=y + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_MAX_NR=1 +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_GIC_V3_ITS_PCI=y +# CONFIG_AL_FIC is not set +CONFIG_PARTITION_PERCPU=y +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y +CONFIG_RESET_TI_SYSCON=y +CONFIG_RESET_RTK_M2TMX=y + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_PHY_XGENE is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +CONFIG_PHY_CADENCE_SIERRA=y +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +CONFIG_PHY_OCELOT_SERDES=y +CONFIG_PHY_RTK_SATA=y +CONFIG_PHY_RTD_PCIE=y +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CMN is not set +CONFIG_ARM_PMU=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_SPE_PMU is not set +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y +CONFIG_RTK_EFUSE=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +CONFIG_PM_OPP=y +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +# CONFIG_AUFS_EXPORT is not set +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +CONFIG_PSTORE_ZONE=y +CONFIG_PSTORE_BLK=y +CONFIG_PSTORE_BLK_BLKDEV="oops" +CONFIG_PSTORE_BLK_KMSG_SIZE=32 +CONFIG_PSTORE_BLK_MAX_REASON=2 +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=y +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=y + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_ESSIV is not set + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +# 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_DES=m +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +CONFIG_LINEAR_RANGES=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +# CONFIG_INDIRECT_PIO is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +CONFIG_AUDIT_GENERIC=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +CONFIG_AUDIT_COMPAT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_ARCH_HAS_SETUP_DMA_OPS=y +CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y +CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y +CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y +CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y +CONFIG_SWIOTLB=y +CONFIG_DMA_NONCOHERENT_MMAP=y +CONFIG_DMA_COHERENT_POOL=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_CMA=y +# CONFIG_DMA_PERNUMA_CMA is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_SG_POOL=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_KCSAN_COMPILER=y +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_KASAN_SW_TAGS=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_HAVE_DEBUG_BUGVERBOSE=y + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# arm64 Debugging +# +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_ARM64_RELOC_TEST is not set +# CONFIG_CORESIGHT is not set +# end of arm64 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/rtd1619bmango b/synology/synoconfigs/rtd1619bmango new file mode 100644 index 000000000000..911c52f4a70a --- /dev/null +++ b/synology/synoconfigs/rtd1619bmango @@ -0,0 +1,6001 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="aarch64-unknown-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_IRQ_IPI=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_GENERIC_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_HAVE_FUTEX_CMPXCHG=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_KCMP=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_ARM64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_CONT_PTE_SHIFT=4 +CONFIG_ARM64_CONT_PMD_SHIFT=4 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA32=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_SMP=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_PROC_KCORE_TEXT=y + +# +# Platform selection +# +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AGILEX is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BITMAIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SPARX5 is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_KEEMBAY is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_QCOM is not set +CONFIG_ARCH_REALTEK=y +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_S32 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VISCONTI is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQMP is not set +# end of Platform selection + +# +# Kernel Features +# + +# +# ARM errata workarounds via the alternatives framework +# +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +CONFIG_ARM64_ERRATUM_1024718=y +# CONFIG_ARM64_ERRATUM_1418040 is not set +# CONFIG_ARM64_ERRATUM_1165522 is not set +# CONFIG_ARM64_ERRATUM_1319367 is not set +# CONFIG_ARM64_ERRATUM_1530923 is not set +# CONFIG_ARM64_ERRATUM_1286807 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_1542419 is not set +# CONFIG_ARM64_ERRATUM_1508412 is not set +# CONFIG_CAVIUM_ERRATUM_22375 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_TX2_ERRATUM_219 is not set +# CONFIG_FUJITSU_ERRATUM_010001 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# end of ARM errata workarounds via the alternatives framework + +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_16K_PAGES is not set +# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_VA_BITS_39=y +# CONFIG_ARM64_VA_BITS_48 is not set +CONFIG_ARM64_VA_BITS=39 +CONFIG_ARM64_PA_BITS_48=y +CONFIG_ARM64_PA_BITS=48 +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +# CONFIG_NUMA is not set +CONFIG_HOLES_IN_ZONE=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HW_PERF_EVENTS=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_CC_HAVE_SHADOW_CALL_STACK=y +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_KEXEC=y +# CONFIG_KEXEC_FILE is not set +CONFIG_CRASH_DUMP=y +# CONFIG_XEN is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_RODATA_FULL_DEFAULT_ENABLED=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_ARM64_TAGGED_ADDR_ABI=y +CONFIG_COMPAT=y +CONFIG_KUSER_HELPERS=y +CONFIG_ARMV8_DEPRECATED=y +# CONFIG_SWP_EMULATION is not set +# CONFIG_CP15_BARRIER_EMULATION is not set +# CONFIG_SETEND_EMULATION is not set + +# +# ARMv8.1 architectural features +# +CONFIG_ARM64_HW_AFDBM=y +CONFIG_ARM64_PAN=y +CONFIG_AS_HAS_LSE_ATOMICS=y +# CONFIG_ARM64_VHE is not set +# end of ARMv8.1 architectural features + +# +# ARMv8.2 architectural features +# +CONFIG_ARM64_UAO=y +# CONFIG_ARM64_PMEM is not set +CONFIG_ARM64_RAS_EXTN=y +CONFIG_ARM64_CNP=y +# end of ARMv8.2 architectural features + +# +# ARMv8.3 architectural features +# +CONFIG_ARM64_PTR_AUTH=y +CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y +CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y +CONFIG_AS_HAS_PAC=y +CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y +# end of ARMv8.3 architectural features + +# +# ARMv8.4 architectural features +# +# CONFIG_ARM64_AMU_EXTN is not set +CONFIG_AS_HAS_ARMV8_4=y +# CONFIG_ARM64_TLB_RANGE is not set +# end of ARMv8.4 architectural features + +# +# ARMv8.5 architectural features +# +# CONFIG_ARM64_BTI is not set +CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y +# CONFIG_ARM64_E0PD is not set +# CONFIG_ARCH_RANDOM is not set +CONFIG_ARM64_AS_HAS_MTE=y +CONFIG_ARM64_MTE=y +# end of ARMv8.5 architectural features + +CONFIG_ARM64_SVE=y +CONFIG_ARM64_MODULE_PLTS=y +# CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y +# end of Kernel Features + +# +# Boot options +# +CONFIG_CMDLINE="" +# CONFIG_EFI is not set +# end of Boot options + +CONFIG_SYSVIPC_COMPAT=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_CPU_PM=y +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# end of Power management options + +# +# CPU Power Management +# + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set + +# +# ARM CPU Idle Drivers +# +# CONFIG_ARM_CPUIDLE is not set +# CONFIG_ARM_PSCI_CPUIDLE is not set +# end of ARM CPU Idle Drivers +# end of CPU Idle + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +# end of CPU Frequency scaling +# end of CPU Power Management + +# +# Firmware Drivers +# +# CONFIG_ARM_SCMI_PROTOCOL is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SDE_INTERFACE is not set +CONFIG_FIRMWARE_MEMMAP=y +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_PSCI_CHECKER is not set +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y +# CONFIG_ARM_SMCCC_SOC_ID is not set + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_IRQ_BYPASS_MANAGER=m +CONFIG_VIRTUALIZATION=y +# CONFIG_KVM is not set +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA256_ARM64=y +# CONFIG_CRYPTO_SHA512_ARM64 is not set +# CONFIG_CRYPTO_SHA1_ARM64_CE is not set +CONFIG_CRYPTO_SHA2_ARM64_CE=y +# CONFIG_CRYPTO_SHA512_ARM64_CE is not set +# CONFIG_CRYPTO_SHA3_ARM64 is not set +# CONFIG_CRYPTO_SM3_ARM64_CE is not set +# CONFIG_CRYPTO_SM4_ARM64_CE is not set +# CONFIG_CRYPTO_GHASH_ARM64_CE is not set +# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set +CONFIG_CRYPTO_AES_ARM64=y +CONFIG_CRYPTO_AES_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +# CONFIG_CRYPTO_CHACHA20_NEON is not set +# CONFIG_CRYPTO_POLY1305_NEON is not set +# CONFIG_CRYPTO_NHPOLY1305_NEON is not set +CONFIG_CRYPTO_AES_ARM64_BS=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_SET_FS=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_KRETPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_KEEPINITRD=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_ARCH_SUPPORTS_SHADOW_CALL_STACK=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 +CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_COMPILER_H=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_SELECT_PLATFORM=y +CONFIG_SYNO_RTD1619B=y +CONFIG_SYNO_INTEL_PSTATE_CALC=y +CONFIG_SYNO_LSP_RTD1619B=y +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +# CONFIG_SYNO_I2C_OF_PROBE is not set +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +# CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY is not set +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +# CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY is not set +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +# CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT is not set +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +# CONFIG_SYNO_SATA_PWR_CTRL_SMBUS is not set +CONFIG_SYNO_SATA_PWR_CTRL_GPIO=y +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +CONFIG_SYNO_SATA_SPINUP_GROUP=y +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +# CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER is not set +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +# CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL is not set +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST=y +CONFIG_SYNO_SATA_ASM1061_RESET_DELEY=y +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +# CONFIG_SYNO_MV1475_SGPIO_LED_CTRL is not set +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +# CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE is not set +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +CONFIG_SYNO_USB_XHCI_RESET_DELAY=y +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD=y +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_COPY=y +CONFIG_SYNO_USB_EXTERNAL_HUB=y +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_HDDMON=m +# CONFIG_SYNO_HWMON_PMBUS is not set +# end of Hardware Monitor + +# +# Serial/TTYs +# +# CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS is not set +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +# CONFIG_SYNO_OOB_SERIAL_OVER_LAN is not set +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +CONFIG_SYNO_MTD_ALLOC=y +CONFIG_SYNO_MTD_INFO=y +CONFIG_SYNO_MTD_ACCESS_LOG=y +# CONFIG_SYNO_MTD_ACCESS_LOG_EXCEPT_VENDOR_PART is not set +# CONFIG_SYNO_MTD_ACCESS_LOG_EXCEPT_REDBOOTCONF_PART is not set +CONFIG_SYNO_MTD_LOCK_UNLOCK=y +CONFIG_SYNO_MTD_DYNAMIC_ERASESIZE=y +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +# CONFIG_SYNO_I2C_DW_FORCE_PROBE is not set +# CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM is not set +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS=y +# CONFIG_SYNO_LED_ATMEGA1608 is not set +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_LEDS_TRIGGER_DISK=y +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND=y +# CONFIG_SYNO_PCI_OPTIONAL_SLOT is not set +CONFIG_SYNO_PCI_DOMAIN_PATH=y +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +CONFIG_SYNO_PWM_CONTROL_LED=y +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_ASN1=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK=y +CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_READ_LOCK=y +CONFIG_ARCH_INLINE_READ_LOCK_BH=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_READ_UNLOCK=y +CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_WRITE_LOCK=y +CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_SPIN_TRYLOCK=y +CONFIG_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_INLINE_SPIN_LOCK=y +CONFIG_INLINE_SPIN_LOCK_BH=y +CONFIG_INLINE_SPIN_LOCK_IRQ=y +CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_INLINE_SPIN_UNLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_READ_LOCK=y +CONFIG_INLINE_READ_LOCK_BH=y +CONFIG_INLINE_READ_LOCK_IRQ=y +CONFIG_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_BH=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_WRITE_LOCK=y +CONFIG_INLINE_WRITE_LOCK_BH=y +CONFIG_INLINE_WRITE_LOCK_IRQ=y +CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_BH=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_STATE=y +CONFIG_ARCH_HAVE_ELF_PROT=y +CONFIG_ARCH_USE_GNU_PROPERTY=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_CONTIG_ALLOC=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +CONFIG_CMA_DEBUGFS=y +CONFIG_CMA_AREAS=7 +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_PAGE_POOL is not set +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_ARM_AMBA=y +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_MSI_ARCH_FALLBACKS=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_IOV=y +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +CONFIG_PCIE_RTD=y +CONFIG_RTD16XXB_PCIE1_ACP=y +CONFIG_PCIE_RTD_TRANS=y + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCI_MESON is not set +# CONFIG_PCIE_AL is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_IRQ=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +CONFIG_GENERIC_ARCH_TOPOLOGY=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set + +# +# Partition parsers +# +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# end of Partition parsers + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +CONFIG_MTD_PSTORE=y +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# end of RAM/ROM/Flash chip drivers + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set +# end of Mapping drivers for chip access + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +# end of Self-contained MTD device drivers + +# +# NAND +# +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_RAW_NAND is not set +# CONFIG_MTD_SPI_NAND is not set + +# +# ECC engine support +# +# end of ECC engine support +# end of NAND + +# +# LPDDR & LPDDR2 PCM memory drivers +# +# CONFIG_MTD_LPDDR is not set +# end of LPDDR & LPDDR2 PCM memory drivers + +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_SPI_RTK_SFC=y +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_HYPERBUS is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AHCI_RTK=y +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_CRYPT is not set +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +# CONFIG_NETCONSOLE is not set +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +CONFIG_NET_VENDOR_HISILICON=y +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HNS3 is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +CONFIG_R8169SOC=y +CONFIG_RTL_RX_NO_COPY=y +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_IPQ8064 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_ASPEED_VUART=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +CONFIG_DEVMEM=y +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_TCG_TPM is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +CONFIG_I2C_REALTEK=y +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +CONFIG_PINCTRL_RTD=y +CONFIG_PINCTRL_RTD_SELFTEST=y + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +CONFIG_GPIO_RTD=y +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +CONFIG_GPIO_LOGICVC=y +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_PL061 is not set +CONFIG_GPIO_SAMA5D2_PIOBU=y +# CONFIG_GPIO_SIFIVE is not set +CONFIG_GPIO_SYSCON=y +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_BRCMSTB=y +# 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_RESTART is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +CONFIG_POWER_RESET_REGMAP_POWEROFF=y +CONFIG_REBOOT_MODE=y +CONFIG_SYSCON_REBOOT_MODE=y +# CONFIG_NVMEM_REBOOT_MODE is not set +CONFIG_POWER_RESET_RTK=y +CONFIG_RTK_REBOOT_MODE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_POWER_SUPPLY_HWMON=y +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_BATTERY_CW2015 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_LT3651 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_BQ2415X is not set +CONFIG_CHARGER_BQ24190=y +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ2515X is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_BQ25980 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_RT5033 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHARGER_BD99954 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR 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_OCC_P8_I2C is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_PWM_FAN 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +CONFIG_THERMAL_GOV_USER_SPACE=y +# CONFIG_CPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set +CONFIG_RTK_THERMAL=y +CONFIG_RTK_THERMAL_CPU_CORE_COOLING=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_SYSFS is not set + +# +# Watchdog Pretimeout Governors +# +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ARM_SMC_WATCHDOG is not set +CONFIG_RTK_WATCHDOG=y +# CONFIG_RTD119X_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_MEN_A21_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SYSCON=y +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +CONFIG_MFD_APW888X=y +CONFIG_MFD_APW8889_I2C=y +CONFIG_MFD_APW8886_I2C=y +# end of Multifunction device drivers + +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER_HELPER is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FAN53880 is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_ISL6271A 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_MAX77826 is not set +# CONFIG_REGULATOR_MCP16502 is not set +# CONFIG_REGULATOR_MP5416 is not set +# CONFIG_REGULATOR_MP8859 is not set +# CONFIG_REGULATOR_MP886X is not set +# CONFIG_REGULATOR_MPQ7920 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PCA9450 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_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set +# CONFIG_REGULATOR_RT4801 is not set +# CONFIG_REGULATOR_RTMV20 is not set +# CONFIG_REGULATOR_SLG51000 is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set +# CONFIG_REGULATOR_SY8827N 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_VCTRL is not set +CONFIG_REGULATOR_APW888X_CORE=y +CONFIG_REGULATOR_APW8889=y +CONFIG_REGULATOR_APW8886=y +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_DRM=m +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +CONFIG_DRM_KMS_HELPER=m +CONFIG_DRM_KMS_FB_HELPER=y +# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_DP_CEC is not set + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# end of I2C encoder or helper chips + +# +# ARM devices +# +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_KOMEDA is not set +# end of ARM devices + +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_BOCHS is not set +CONFIG_DRM_PANEL=y + +# +# Display Panels +# +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_SIMPLE is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set +# CONFIG_DRM_PANEL_LG_LG4573 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_SAMSUNG_S6E63M0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 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 +# end of Display Panels + +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_PANEL_BRIDGE=y + +# +# Display Interface Bridges +# +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CHRONTEL_CH7033 is not set +# CONFIG_DRM_DISPLAY_CONNECTOR is not set +# CONFIG_DRM_LONTIUM_LT9611 is not set +# CONFIG_DRM_LVDS_CODEC is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_NWL_MIPI_DSI is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PARADE_PS8640 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIMPLE_BRIDGE is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TOSHIBA_TC358762 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_TOSHIBA_TC358768 is not set +# CONFIG_DRM_TOSHIBA_TC358775 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_TI_TPD12S015 is not set +# CONFIG_DRM_ANALOGIX_ANX6345 is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_CDNS_MHDP8546 is not set +# end of Display Interface Bridges + +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_ILI9486 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_DRM_PL111 is not set +# CONFIG_DRM_LIMA is not set +# CONFIG_DRM_PANFROST is not set +# CONFIG_DRM_TIDSS is not set +# CONFIG_DRM_LEGACY is not set +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=m + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +CONFIG_HDMI=y + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +CONFIG_SND_PCM_TIMER=y +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_RTK_HCD_TEST_MODE is not set +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +CONFIG_USB_XHCI_PLATFORM=m +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_RTK is not set +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +CONFIG_USB_DWC3=m +CONFIG_USB_DWC3_HOST=y + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_RTK=m +CONFIG_USB_DWC3_HAPS=m +CONFIG_USB_DWC3_OF_SIMPLE=m +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +CONFIG_USB_PATCH_ON_RTK=y + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ULPI is not set +# CONFIG_RTK_USB_RLE0599_PHY is not set +CONFIG_RTK_USB2PHY=m +CONFIG_RTK_USB3PHY=m +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +CONFIG_LEDS_LP50XX=y +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_SYSCON=y +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +# CONFIG_RTC_DRV_RTK is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_RTD119X is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_QDMA is not set +# CONFIG_HISI_DMA is not set +CONFIG_INTEL_IDMA64=y +# CONFIG_MV_XOR_V2 is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +# CONFIG_VFIO_PLATFORM is not set +# CONFIG_VFIO_MDEV is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +# CONFIG_GOLDFISH is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_CLK_QORIQ is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +CONFIG_COMMON_CLK_REALTEK=y +CONFIG_CLK_PLL_PSAUD=y +CONFIG_CLK_PLL_DIF=y +# CONFIG_COMMON_CLK_RTD1195 is not set +# CONFIG_COMMON_CLK_RTD1295 is not set +# CONFIG_COMMON_CLK_RTD1319 is not set +# CONFIG_COMMON_CLK_RTD1395 is not set +CONFIG_COMMON_CLK_RTD1619=y +CONFIG_COMMON_CLK_RTD1619B=y +CONFIG_CLK_DET=y +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_HISILICON_ERRATUM_161010101=y +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_ARM_MHU is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +# CONFIG_ARM_SMMU is not set +# CONFIG_ARM_SMMU_V3 is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# CONFIG_SOC_BRCMSTB is not set +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# CONFIG_QUICC_ENGINE is not set +# CONFIG_FSL_RCPM is not set +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# +# Realtek SoC drivers +# +# CONFIG_RTD13XX_RTK_CODEC is not set +# CONFIG_RTD16XXB_RTK_CODEC is not set +CONFIG_REALTEK_SOC=y +CONFIG_REALTEK_PM=y +CONFIG_RTK_MCP=y +# CONFIG_RTK_SC_WRAP_FSS is not set +CONFIG_RTK_USB_CTRL_MANAGER=m +CONFIG_REALTEK_CHIP_INFO=y +CONFIG_RTK_FAN=y +# CONFIG_RTK_FSS_SCAN is not set +CONFIG_RTK_VCPU=y +# CONFIG_RTK_VE3_UART is not set +# CONFIG_RTK_WATCHDOG_STATUS is not set +CONFIG_RTK_GPIO_DEFAULT=y +# CONFIG_RTK_VSFC_CTRL is not set +CONFIG_RTK_CPUHP_QOS=y +# CONFIG_RTK_CPUHP_CONTROL is not set +# CONFIG_RTK_CPU_VCLK is not set +CONFIG_RTK_BSV_CTRL=y +CONFIG_REALTEK_RPC=y +# CONFIG_REALTEK_RPC_VE3 is not set +CONFIG_ION_REALTEK=y +CONFIG_ION_SYSTEM_HEAP_REALTEK=y +CONFIG_ION_CARVEOUT_HEAP_REALTEK=y +CONFIG_ION_CHUNK_HEAP_REALTEK=y +CONFIG_ION_CMA_HEAP_REALTEK=y +CONFIG_ION_RTK_DHC_HEAP=y +# CONFIG_ION_RTK_LEGACY_DEVICE is not set +CONFIG_RTK_HSE=y + +# +# Realtek Power Domain +# +CONFIG_PD_REALTEK=y +# CONFIG_PD_RTD1295 is not set +# CONFIG_PD_RTD1395 is not set +# CONFIG_PD_RTD1619 is not set +CONFIG_PD_RTD1619B=y +# end of Realtek Power Domain + +CONFIG_RTK_INFO_PLL=y +CONFIG_RTK_CPU_VOLT_SEL=y +# CONFIG_RTK_BUFLOCK is not set +# end of Realtek SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +CONFIG_EXTCON=y + +# +# Extcon Device Drivers +# +CONFIG_EXTCON_FSA9480=y +CONFIG_EXTCON_GPIO=y +CONFIG_EXTCON_MAX3355=y +CONFIG_EXTCON_PTN5150=y +CONFIG_EXTCON_RT8973A=y +CONFIG_EXTCON_SM5502=y +CONFIG_EXTCON_USB_GPIO=y +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +# CONFIG_PWM_DEBUG is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWM_RTK=y + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_MAX_NR=1 +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_ARM_GIC_V3_ITS_PCI=y +# CONFIG_AL_FIC is not set +CONFIG_PARTITION_PERCPU=y +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y +CONFIG_RESET_TI_SYSCON=y +CONFIG_RESET_RTK_M2TMX=y + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_PHY_XGENE is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +CONFIG_PHY_CADENCE_SIERRA=y +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +CONFIG_PHY_OCELOT_SERDES=y +CONFIG_PHY_RTK_SATA=y +CONFIG_PHY_RTD_PCIE=y +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CMN is not set +CONFIG_ARM_PMU=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_SPE_PMU is not set +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y +CONFIG_RTK_EFUSE=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +CONFIG_PM_OPP=y +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +# CONFIG_AUFS_EXPORT is not set +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +CONFIG_PSTORE_ZONE=y +CONFIG_PSTORE_BLK=y +CONFIG_PSTORE_BLK_BLKDEV="oops" +CONFIG_PSTORE_BLK_KMSG_SIZE=32 +CONFIG_PSTORE_BLK_MAX_REASON=2 +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=y +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=y + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_ESSIV is not set + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +# 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_DES=m +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +CONFIG_LINEAR_RANGES=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +# CONFIG_INDIRECT_PIO is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +CONFIG_AUDIT_GENERIC=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +CONFIG_AUDIT_COMPAT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_ARCH_HAS_SETUP_DMA_OPS=y +CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y +CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y +CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y +CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y +CONFIG_SWIOTLB=y +CONFIG_DMA_NONCOHERENT_MMAP=y +CONFIG_DMA_COHERENT_POOL=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_CMA=y +# CONFIG_DMA_PERNUMA_CMA is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +# CONFIG_DIMLIB is not set +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_SG_POOL=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_KCSAN_COMPILER=y +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_KASAN_SW_TAGS=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_HAVE_DEBUG_BUGVERBOSE=y + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# arm64 Debugging +# +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_ARM64_RELOC_TEST is not set +# CONFIG_CORESIGHT is not set +# end of arm64 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/ryzen5k b/synology/synoconfigs/ryzen5k new file mode 100644 index 000000000000..8dd11db96113 --- /dev/null +++ b/synology/synoconfigs/ryzen5k @@ -0,0 +1,5815 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +CONFIG_X86_AMD_PLATFORM_DEVICE=y +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=24 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_NUMA_EMU=y +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +# CONFIG_KVM_INTEL is not set +CONFIG_KVM_AMD=m +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +CONFIG_SYNO_RYZEN5K=y +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_SAS=y +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_NET_EMULEX_HIDE_VF=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_NUMA_SETTING_ENHANCE=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +# CONFIG_SYNO_SATA_PWR_CTRL_GPIO is not set +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +# CONFIG_SYNO_SATA_SPINUP_GROUP is not set +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=y +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +# CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL is not set +# CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE is not set +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA + +# +# SAS +# +CONFIG_SYNO_SAS_DEVICE_PREFIX="sas" +CONFIG_SYNO_SAS_FIX_ENCLOSURE_POWEROFF_WARNON=y +CONFIG_SYNO_SAS_SYSFS_BLOCK_DEV_LINK=y +CONFIG_SYNO_SAS_SPINUP_DELAY=y +# CONFIG_SYNO_SAS_SPINUP_DELAY_DEBUG is not set +CONFIG_SYNO_SAS_SHOW_DISK_PHY_INFO=y +CONFIG_SYNO_SAS_HBA_IDX=y +CONFIG_SYNO_SAS_MAX_HBA_SLOT=2 +CONFIG_SYNO_SAS_HOST_DISK_LED_CTRL=y +CONFIG_SYNO_SCSI_DEVICE_SPINDOWN_BEFORE_POWEROFF=y +CONFIG_SYNO_SAS_SES_DIAGNOSTIC_PAGE_ENHANCE=y +CONFIG_SYNO_SAS_SATA_EARLY_WAKEUP=y +# end of SAS +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +# CONFIG_SYNO_NVME_WAIT_DISK_READY is not set +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +# CONFIG_SYNO_SMBUS_HDDMON is not set +CONFIG_SYNO_HWMON_PMBUS=y +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +CONFIG_SYNO_I2C_DW_FORCE_PROBE=y +CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LED_ATMEGA1608=m +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# CONFIG_SYNO_IOMMU_AMD_USB_QUIRK is not set +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +# CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND is not set +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=4 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +CONFIG_SYNO_PCI_DOMAIN_PATH=y +CONFIG_SYNO_PCI_EUNIT_SUPPORT=y +CONFIG_SYNO_PCI_EUNIT_I2C=y +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_NUMA_SVC_POOL_PERNODE=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +# CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG is not set +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_EDR is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +CONFIG_ENCLOSURE_SERVICES=y +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_MPT2SAS_MAX_SGE=128 +CONFIG_SCSI_MPT3SAS_MAX_SGE=128 +CONFIG_SCSI_MPT2SAS=m +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +CONFIG_LIBFC=m +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=y +# CONFIG_SCSI_DH_HP_SW is not set +# CONFIG_SCSI_DH_EMC is not set +# CONFIG_SCSI_DH_ALUA is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +CONFIG_IGB=m +# CONFIG_IGB_HWMON is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=m + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_OF_MDIO=m +CONFIG_MDIO_DEVRES=m +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3943 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_DECODE_MCE=y +CONFIG_EDAC_AMD64=y +# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set +# CONFIG_EDAC_E752X is not set +# CONFIG_EDAC_I82975X is not set +# CONFIG_EDAC_I3000 is not set +# CONFIG_EDAC_I3200 is not set +# CONFIG_EDAC_IE31200 is not set +# CONFIG_EDAC_X38 is not set +# CONFIG_EDAC_I5400 is not set +# CONFIG_EDAC_I7CORE is not set +# CONFIG_EDAC_I5000 is not set +# CONFIG_EDAC_I5100 is not set +# CONFIG_EDAC_I7300 is not set +# CONFIG_EDAC_SBRIDGE is not set +# CONFIG_EDAC_SKX is not set +# CONFIG_EDAC_I10NM is not set +# CONFIG_EDAC_PND2 is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/soit-ci-config b/synology/synoconfigs/soit-ci-config new file mode 120000 index 000000000000..cb89da251ded --- /dev/null +++ b/synology/synoconfigs/soit-ci-config @@ -0,0 +1 @@ +fst-ci-config \ No newline at end of file diff --git a/synology/synoconfigs/v1000lk5 b/synology/synoconfigs/v1000lk5 new file mode 100644 index 000000000000..fff4fbb6f7e2 --- /dev/null +++ b/synology/synoconfigs/v1000lk5 @@ -0,0 +1,5746 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +CONFIG_X86_AMD_PLATFORM_DEVICE=y +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=16 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +# CONFIG_KVM_INTEL is not set +CONFIG_KVM_AMD=m +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +CONFIG_SYNO_V1000=y +# CONFIG_SYNO_V1000SOFS is not set +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_AMD_XGBE_PORTING=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +CONFIG_SYNO_SATA_PWR_CTRL_GPIO=y +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +CONFIG_SYNO_SATA_SPINUP_GROUP=y +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=m +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +CONFIG_SYNO_SATA_ASM116X_CONTROL=y +CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST=y +CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE=m +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +CONFIG_SYNO_SATA_SIGNAL_ADJUST=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +# CONFIG_SYNO_NVME_WAIT_DISK_READY is not set +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +CONFIG_SYNO_HDDMON=m +CONFIG_SYNO_SMBUS_HDDMON=m +CONFIG_SYNO_HWMON_PMBUS=y +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +CONFIG_SYNO_I2C_DW_FORCE_PROBE=y +CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS is not set +CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_OF is not set +CONFIG_SYNO_LED_ATMEGA1608=m +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# CONFIG_SYNO_IOMMU_AMD_USB_QUIRK is not set +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND=y +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=1 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# +# end of NTB + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG=y +CONFIG_SYNO_BTRFS_DEDUPE=y +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG=m +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +CONFIG_NET_VENDOR_AMD=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_PCNET32 is not set +CONFIG_AMD_XGBE=m +CONFIG_AMD_XGBE_HAVE_ECC=y +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=y +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +CONFIG_MARVELL_10G_PHY=m +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_BUS=y +CONFIG_OF_MDIO=y +CONFIG_MDIO_DEVRES=y +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2=y +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/synoconfigs/v1000sofs b/synology/synoconfigs/v1000sofs new file mode 100644 index 000000000000..a21fcc5513d0 --- /dev/null +++ b/synology/synoconfigs/v1000sofs @@ -0,0 +1,5757 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.10.55 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="x86_64-pc-linux-gnu-gcc (GCC) 12.2.0" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120200 +CONFIG_LD_VERSION=238000000 +CONFIG_CLANG_VERSION=0 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_USELIB=y +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +# CONFIG_PSI_DEFAULT_DISABLED is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RUDE_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_KMEM=y +# CONFIG_BLK_CGROUP is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +# CONFIG_CGROUP_BPF is not set +# CONFIG_CGROUP_DEBUG is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +CONFIG_RD_LZMA=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +# CONFIG_KCMP is not set +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +CONFIG_SYSTEM_DATA_VERIFICATION=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +# CONFIG_X86_CPU_RESCTRL is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_INTEL_LPSS is not set +CONFIG_X86_AMD_PLATFORM_DEVICE=y +# CONFIG_IOSF_MBI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +# CONFIG_HYPERVISOR_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_PROCESSOR_SELECT=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +CONFIG_HPET_TIMER=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=16 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_MC_PRIO is not set +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_AMD_POWER=y +# end of Performance monitoring + +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +# CONFIG_I8K is not set +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +# CONFIG_X86_PAT is not set +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_UMIP=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_EFI=y +# CONFIG_EFI_STUB is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +# CONFIG_SUSPEND is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="/dev/md1" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_TINY_POWER_BUTTON is not set +CONFIG_ACPI_VIDEO=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=m +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_BGRT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_NFIT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +# CONFIG_CPUFREQ_DT is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_ISA_BUS is not set +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32 is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_RUNTIME_MAP is not set +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_WERROR=y +# CONFIG_KVM_INTEL is not set +CONFIG_KVM_AMD=m +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_GENERIC_ENTRY=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +# CONFIG_SECCOMP is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_STACKPROTECTOR is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_SYNO_FEATURES=y + +# +# Platform Features +# +CONFIG_SYNO_X64=y +CONFIG_SYNO_SELECT_PLATFORM=y +# CONFIG_SYNO_KVMX64 is not set +# CONFIG_SYNO_KVMX64SOFS is not set +# CONFIG_SYNO_KVMX64V2 is not set +# CONFIG_SYNO_BROADWELL is not set +# CONFIG_SYNO_PURLEY is not set +# CONFIG_SYNO_GEMINILAKE is not set +# CONFIG_SYNO_V1000 is not set +CONFIG_SYNO_V1000SOFS=y +# CONFIG_SYNO_ICELAKED is not set +# CONFIG_SYNO_EPYC7002 is not set +# CONFIG_SYNO_EPYC7002SOFS is not set +# CONFIG_SYNO_RYZEN5K is not set +# CONFIG_SYNO_EPYC7003NTB is not set +CONFIG_SYNO_AMD_MCE_THRESHOLD_CLEAR=y +# CONFIG_SYNO_INTEL_PSTATE_CALC is not set +# end of Platform Features + +# +# System Features +# +CONFIG_SYNO_SYSTEM_CALL=y +CONFIG_SYNO_LIBS=y +CONFIG_SYNO_KWORK_STAT=y +CONFIG_SYNO_EXPORT_SYMBOL=y +# CONFIG_SYNO_X86_CORETEMP is not set +CONFIG_SYNO_PORT_MAPPING_V2=y +CONFIG_SYNO_SWAP_FLAG=y +CONFIG_SYNO_DATA_CORRECTION=y +CONFIG_SYNO_ISCSI_DEVICE=y +CONFIG_SYNO_ISCSI_DEVICE_PREFIX="iscsi" +CONFIG_SYNO_ISCSI_LOOPBACK_DEVICE=y +CONFIG_SYNO_DISPLAY_CPUINFO=y +CONFIG_SYNO_INTERNAL_HD_NUM=y +CONFIG_SYNO_ECC_NOTIFICATION=y +CONFIG_SYNO_LOAD_AVERAGE=y +CONFIG_SYNO_IOSCHED_DEFAULT_BFQ=y +CONFIG_SYNO_I2C_OF_PROBE=y +CONFIG_SYNO_MULTI_KSWAPD=y +CONFIG_SYNO_ADJUST_KSWAPD_NICE=y +# end of System Features + +# +# Boot Arguments +# +CONFIG_SYNO_BOOT_ARGUMENTS=y +CONFIG_SYNO_HW_VERSION=y +CONFIG_SYNO_HW_REVISION=y +CONFIG_SYNO_INTERNAL_NETIF_NUM=y +CONFIG_SYNO_MAC_ADDRESS=y +CONFIG_SYNO_SERIAL=y +# end of Boot Arguments + +# +# Kernel Core Enhancements +# +CONFIG_SYNO_KERNEL_UTC_TIME=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER=y +CONFIG_SYNO_SOFTLOCKUP_COUNTER_MAX=10 +# CONFIG_SYNO_HARDLOCKUP_THRESH_EXTENSION is not set +CONFIG_SYNO_PRINT_BACKTRACE_ON_LOCKUP=y +CONFIG_SYNO_DUMPSTACK_SHOW_FUNC_ADDR=y +CONFIG_SYNO_HUNG_TASK_ADJUSTMENT=y +CONFIG_SYNO_DEFAULT_HUNG_TASK_WARNINGS=300 +CONFIG_SYNO_DEFAULT_HUNG_TASK_RESET_PERIOD=360 +CONFIG_SYNO_ISCSI_DEAD_LOCK_BH_ISSUE=y +CONFIG_SYNO_CFS_CPU_LOAD_IMBALANCE=y +CONFIG_SYNO_BLOCK_SOFTIRQ_ON_STACK=y +# end of Kernel Core Enhancements + +# +# Network +# +CONFIG_SYNO_SFP_UNSUPPORTED_NOTIFY=y +CONFIG_SYNO_SKIP_RXDROP_BY_CORE=y +CONFIG_SYNO_IPV6_RFC_4862=y +CONFIG_SYNO_BONDING_INIT_STATUS=y +CONFIG_SYNO_BONDING_FIX_ACTIVE=y +CONFIG_SYNO_FIX_8023AD_LINK_STATUS=y +CONFIG_SYNO_IPV6_LINKLOCAL=y +CONFIG_SYNO_OVS_MODE_REFINEMENT=y +CONFIG_SYNO_NF_NAT_WORKAROUND=y +CONFIG_SYNO_NET_ALB_FIX_OVERFLOW=y +CONFIG_SYNO_NET_ALB_USE_64BIT_LOAD=y +CONFIG_SYNO_AMD_XGBE_PORTING=y +# end of Network + +# +# Device Drivers +# + +# +# Block Devices +# +CONFIG_SYNO_BLK_DEV_GENDISK_OPERATIONS=y +CONFIG_SYNO_BLK_DEV_WAIT_DISK_READY=y +CONFIG_SYNO_BLK_DEV_SET_DEV_READ_ONLY=y +# end of Block Devices + +# +# MD +# +CONFIG_SYNO_MD_09_SUPERBLOCK_COMPATIBLE=y +CONFIG_SYNO_MD_STATUS_GET=y +CONFIG_SYNO_MD_SYNC_MSG=y +CONFIG_SYNO_MD_FORCE_START_DIRTY_DEGRADED=y +CONFIG_SYNO_MD_DEVICE_HOTPLUG_NOTIFY=y +CONFIG_SYNO_MD_RAID5_FORCE_RCW=y +CONFIG_SYNO_MD_RAID5_DISABLE_STRIPE_GROWTH=y +CONFIG_SYNO_MD_RAID1_SYSFS_INTERFACE=y +CONFIG_SYNO_MD_RAID5_PERF_ENHANCE_BY_DEFERIO=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_HANG=y +CONFIG_SYNO_MD_SYNC_THROTTLE_MECHANISM=y +CONFIG_SYNO_MD_RAID5_ACTIVE_STRIPE_THRESHOLD=y +CONFIG_SYNO_MD_RESTORE_RAID0_LAYOUT_FEATURE=y +CONFIG_SYNO_MD_RAID5_SKIP_COPY_ENHANCE=y +CONFIG_SYNO_MD_FAST_WAKEUP=y +CONFIG_SYNO_MD_SYNC_DEBUG=y +CONFIG_SYNO_MD_FIX_SB_UPDATE_DEADLOCK=y +CONFIG_SYNO_MD_FLUSH_PLUG=y +CONFIG_SYNO_MD_FIX_RAID1_BIOPOOL_CHANGE=y +CONFIG_SYNO_MD_ROOT_SWAP_PARALLEL_RESYNC=y +CONFIG_SYNO_MD_DM_DUMMY_CACHE_NOCLONE_BIO=y +CONFIG_SYNO_MD_RAID_PERF_STAT=y +CONFIG_SYNO_MD_UNUSED_HINT=y +CONFIG_SYNO_MD_FAST_REBUILD=y +CONFIG_SYNO_MD_FAST_SCRUBBING=y +CONFIG_SYNO_MD_EIO_NODEV_HANDLER=y +CONFIG_SYNO_MD_FIX_RESYNC_STATUS=y +CONFIG_SYNO_MD_FORCE_SB_EVENT_INCREASED=y +CONFIG_SYNO_MD_RAID1_ASSIGN_READ_TARGET=y +CONFIG_SYNO_MD_SKIP_RESYNC_WHEN_SB_NOT_CLEAN=y +CONFIG_SYNO_MD_DATA_CORRECTION=y +CONFIG_SYNO_MD_RAID5_FIX_MAX_LATENCY_HIGH=y +CONFIG_SYNO_MD_DM_EXTRA_IOCTL=y +CONFIG_SYNO_MD_DUMMY_READ=y +CONFIG_SYNO_MD_STATUS_DISKERROR=y +CONFIG_SYNO_MD_ALLOW_MD_RUN_WHEN_RESHAPE_POSITION_IS_ZERO=y +CONFIG_SYNO_MD_SYNC_STATUS_REPORT=y +CONFIG_SYNO_MD_SECTOR_STATUS_REPORT=y +CONFIG_SYNO_MD_FIX_RAID5_RESHAPE_READ_FROM_ERROR_LAYOUT=y +CONFIG_SYNO_MD_UPDATE_SB_AT_RESYNC_START=y +CONFIG_SYNO_MD_BAD_SECTOR_AUTO_REMAP=y +CONFIG_SYNO_MD_AUTO_REMAP_REPORT=y +CONFIG_SYNO_MD_RAID_F1=y +CONFIG_SYNO_MD_RAID5_ENABLE_SSD_TRIM=y +CONFIG_SYNO_MD_RAID5_FIX_SH_COUNT_RACE_WITH_SH_BATCH=y +CONFIG_SYNO_MD_RAID1_FIX_ASSEMBLE_CRASHED_HANG=y +CONFIG_SYNO_MD_FULL_STRIPE_MERGE=y +CONFIG_SYNO_MD_RAID10_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID1_FIX_IO_SERIALIZATION=y +CONFIG_SYNO_MD_DEFAULT_ENABLE_IO_SERIALIZATION=y +CONFIG_SYNO_MD_RAID5_FIX_RETRY_ALIGNED_READ=y +CONFIG_SYNO_MD_RAID_FAIL_FAST_ON_WRITE=y +CONFIG_SYNO_MD_DM_CRYPT_QUEUE_LIMIT=y +# end of MD + +# +# Block +# +CONFIG_SYNO_BLOCK_BLKTRACE_FIX=y +CONFIG_SYNO_BLOCK_LATENCY_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_FIX_BIO_SPLIT_ORDER=y +CONFIG_SYNO_BLOCK_SEQIO_MONITOR_TOOL=y +CONFIG_SYNO_BLOCK_BLKTRACE_AFFINITY_FIX=y +CONFIG_SYNO_BLOCK_USE_NOIO_FLAG=y +# end of Block + +# +# SCSI +# +CONFIG_SYNO_SCSI_PROMOTE_INFO_LOG_LEVEL=y +CONFIG_SYNO_SCSI_OVERRIDE_SD_TIMEOUT=y +CONFIG_SYNO_SCSI_DEVICE_IDLE_TIME=y +CONFIG_SYNO_DISK_HIBERNATION=y +CONFIG_SYNO_SCSI_INQUIRY_STANDARD=y +CONFIG_SYNO_SCSI_GET_ATA_IDENTITY=y +CONFIG_SYNO_SCSI_DISK_SERIAL=y +CONFIG_SYNO_SCSI_CUSTOM_SCMD_TIMEOUT=y +CONFIG_SYNO_SCSI_SPINDOWN_DISK_BEFORE_POWERLOSS=y +CONFIG_SYNO_SCSI_DISK_SPINDOWN_PARALLELLY=y +CONFIG_SYNO_SCSI_INCREASE_DISK_MODEL_NAME_LENGTH=y +CONFIG_SYNO_SCSI_DISK_HIBERNATION_DEBUG=y +CONFIG_SYNO_SCSI_DISK_ERROR_REPORT=y + +# +# SATA +# +CONFIG_SYNO_SATA_DEVICE_PREFIX="sata" +CONFIG_SYNO_SATA_PWR_CTRL=y +CONFIG_SYNO_SATA_PWR_CTRL_SMBUS=y +CONFIG_SYNO_SATA_PWR_CTRL_GPIO=y +CONFIG_SYNO_SATA_DEBUG_FLAG=y +CONFIG_SYNO_SATA_ERROR_HANDLING_FLAG=y +CONFIG_SYNO_SATA_DEVICE_INFOLOG_PROMOTION=y +CONFIG_SYNO_SATA_COMMAND_XLAT_HOOK=y +CONFIG_SYNO_SATA_SPECIFIC_QC_FILTER=y +CONFIG_SYNO_SATA_STATUS_FLAG=y +CONFIG_SYNO_SATA_PMP_ENHANCE=y +CONFIG_SYNO_SATA_EUNIT_SUPPORT=y +CONFIG_SYNO_SATA_EUNIT_SIGNAL_ADJUSTMENT=y +CONFIG_SYNO_SATA_EUNIT_HORKAGE=y +CONFIG_SYNO_SATA_EUNIT_FAST_PROBE=y +CONFIG_SYNO_SATA_EUNIT_HOTPLUG_TASK=y +CONFIG_SYNO_SATA_DEEPSLEEP=y +CONFIG_SYNO_SATA_EUNIT_DEEPSLEEP=y +CONFIG_SYNO_SATA_SPINUP_GROUP=y +CONFIG_SYNO_SATA_CONTROLLER_INFO=y +CONFIG_SYNO_SATA_SIGNAL_CHECK=m +CONFIG_SYNO_SATA_SIGNAL_TEST=m +CONFIG_SYNO_SATA_MV92XX_PORTING=y +CONFIG_SYNO_SATA_MV9170_PORTING=y +# CONFIG_SYNO_SATA_MV92XX_GPIO_CTRL is not set +# CONFIG_SYNO_SATA_MV9170_GPIO_CTRL is not set +CONFIG_SYNO_SATA_MV9XXX_SIGNAL_SETTING=y +CONFIG_SYNO_SATA_DISK_LED_CONTROL=y +CONFIG_SYNO_AHCI_SWITCH=y +CONFIG_SYNO_AHCI_GET_HOST_MMIO_ADDRESS=y +CONFIG_SYNO_AHCI_SOFTWARE_ACITIVITY=y +CONFIG_SYNO_AHCI_SW_ACITIVITY_LED_TRIGGER=y +# CONFIG_SYNO_AHCI_GPIO_SOFTWARE_ACITIVITY is not set +CONFIG_SYNO_SATA_JMB585_FIX=y +CONFIG_SYNO_SATA_JMB585_DUBIOUS_IFS_FIX=y +CONFIG_SYNO_SATA_JMB585_AMP_ADJUST=y +CONFIG_SYNO_SATA_JMB585_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_JMB585_FIRMWARE_UPDATE=m +# CONFIG_SYNO_SATA_ASM1061_AMP_ADJUST is not set +# CONFIG_SYNO_SATA_ASM1061_RESET_DELEY is not set +CONFIG_SYNO_SATA_ASM116X_CONTROL=y +CONFIG_SYNO_SATA_ASM116X_AMP_ADJUST=y +CONFIG_SYNO_SATA_ASM116X_GPIO_LED_CTRL=y +CONFIG_SYNO_SATA_ASM116X_FIRMWARE_UPDATE=m +CONFIG_SYNO_SATA_DETECTION_INFO=y +CONFIG_SYNO_SATA_WCACHE_DISABLE=y +CONFIG_SYNO_SATA_DISK_MONITOR_TOOL=y +CONFIG_SYNO_SATA_SAMPLE_SEQ_IO=y +CONFIG_SYNO_SATA_IOCTL_HDIO_GET_DMA=y +CONFIG_SYNO_SATA_HANDLE_EIO_DISKS=y +CONFIG_SYNO_SATA_FIX_LIBATA_NOT_REFLUSH=y +CONFIG_SYNO_SATA_PMP_SAMSUNG_PROBE_TIME_FIX=y +CONFIG_SYNO_SATA_DISABLE_QUEUED_TRIM=y +CONFIG_SYNO_SATA_SSD_DETECT=y +CONFIG_SYNO_SATA_REDUCE_RETRY_TIMER=y +CONFIG_SYNO_SATA_EXTEND_PROBE_CMD_TIMEOUT=y +CONFIG_SYNO_SATA_SKIP_PARALLEL_SCAN=y +CONFIG_SYNO_SATA_DISABLE_TRIM_ZERO_WHITELIST=y +CONFIG_SYNO_SATA_SHOW_MORE_EH_LOG=y +CONFIG_SYNO_SATA_DISABLE_READ_LOG_DMA=y +CONFIG_SYNO_SATA_INTEL_SSD_COMPATIBILITY=y +CONFIG_SYNO_SATA_EXTEND_READ_LOG_TIMEOUT=y +CONFIG_SYNO_SATA_PRINT_SN=y +CONFIG_SYNO_SATA_NCQ_EH_ENHANCE=y +CONFIG_SYNO_SATA_EARLY_NCQ_ANALYZE=y +CONFIG_SYNO_SATA_DISK_NCQ_COMPATIBILITY=y +CONFIG_SYNO_SATA_DISK_WD_TLER_RETRY=y +CONFIG_SYNO_SATA_TRIM_DISCARD_ZEROES_DATA_ALWAYS_TRUE=y +CONFIG_SYNO_SATA_TRIM_PREFER_WRITE_SAME=y +CONFIG_SYNO_MV1475_SGPIO_LED_CTRL=y +# CONFIG_SYNO_SATA_SIGNAL_ADJUST_BY_DTS is not set +CONFIG_SYNO_SATA_SIGNAL_ADJUST=y +CONFIG_SYNO_SATA_PORT_THAW=y +CONFIG_SYNO_SATA_RECOVER_MECHANISM=y +CONFIG_SYNO_SATA_DEEP_RETRY=y +CONFIG_SYNO_SATA_ERROR_REPORT=y +CONFIG_SYNO_SATA_DISK_PRESENT_CHECK=y +CONFIG_SYNO_SATA_DETECT_POWER_SHORT_BREAK=y +CONFIG_SYNO_SATA_SPEED_LIMIT_RECOVERY=y +CONFIG_SYNO_SATA_LIBATA_FUA=y +CONFIG_SYNO_AHCI_INTERNAL_SLOT_MODE=y +CONFIG_SYNO_SATA_PWR_CTRL_TEST=m +CONFIG_SYNO_AHCI_REG_READ_TEST=m +CONFIG_SYNO_SATA_EH_DEFER_CMD=y +# end of SATA +# end of SCSI + +# +# NVMe +# +CONFIG_SYNO_NVME_DEVICE_INDEX=y +CONFIG_SYNO_NVME_DEBUG_FORCE_TIMEOUT=y +CONFIG_SYNO_NVME_QUIRK_NO_APST=y +CONFIG_SYNO_NVME_EXTEND_IO_TIMEOUT=y +# CONFIG_SYNO_NVME_SW_ACTIVITY is not set +CONFIG_SYNO_NVME_IDLE_TIME=y +CONFIG_SYNO_NVME_BLOCK_INFO=y +# CONFIG_SYNO_NVME_WAIT_DISK_READY is not set +CONFIG_SYNO_NVME_CRIT_WARN_MEDIA_SET_RO=y +# end of NVMe + +# +# Network +# +CONFIG_SYNO_NET_BOND_ALB_INFO=y +CONFIG_SYNO_NET_LINK_DOWN_STATUS=y +# end of Network + +# +# USB +# +CONFIG_SYNO_USB_DEVICE_PREFIX="usb" +CONFIG_SYNO_USB_FLASH_BOOT=y +CONFIG_SYNO_USB_FLASH_DEVICE_INDEX=255 +CONFIG_SYNO_USB_FLASH_DEVICE_NAME="synoboot" +CONFIG_SYNO_INSTALL_FLAG=y +CONFIG_SYNO_USB_UAS_ENABLE_CONTROL=y +CONFIG_SYNO_USB_VBUS_GPIO_CONTROL=y +CONFIG_SYNO_USB_POWER_OFF_TIME=500 +CONFIG_SYNO_USB_SERIAL_FIX=y +CONFIG_SYNO_USB_ENABLE_USBFS_ENTRY=y +CONFIG_SYNO_USB_RESET_WAIT=y +CONFIG_SYNO_USB_DISABLE_USB2_HW_LPM_SUPPORT_CHECK=y +# CONFIG_SYNO_USB_XHCI_RESET_DELAY is not set +CONFIG_SYNO_USB_FORBID=y +CONFIG_SYNO_USB_BUGGY_PORT_RESET_BIT_QUIRK=y +CONFIG_SYNO_USB_SPEED_DOWNGRADE_RECOVERY=y +CONFIG_SYNO_USB_STOR_EXTRA_DELAY=y +CONFIG_SYNO_USB_CONNECT_DEBOUNCER=y +# CONFIG_SYNO_USB_EMPTY_UNAVAILABLE_XHCI_TD is not set +CONFIG_SYNO_USB_POWER_RESET=y +CONFIG_SYNO_USB_POWER_ON_TIME=500 +# CONFIG_SYNO_USB_CASTRATED_XHC is not set +CONFIG_SYNO_USB_STOR_ENHANCE_DISCONNECTION=y +CONFIG_SYNO_USB_DEVICE_QUIRKS=y +CONFIG_SYNO_USB_UPS_DISCONNECT_FILTER=y +CONFIG_SYNO_USB_SYNCHRONIZE_CACHE_FILTER=y +CONFIG_SYNO_USB_INTEL_XHC_LPM_DISABLE=y +CONFIG_SYNO_OOB_USB_DEVICE=y +# CONFIG_SYNO_USB_COPY is not set +# CONFIG_SYNO_USB_EXTERNAL_HUB is not set +# CONFIG_SYNO_USB_EUNIT_CONTROL is not set +# end of USB + +# +# Hardware Monitor +# +CONFIG_SYNO_ADT7490_FEATURES=y +# CONFIG_SYNO_ADT7490_PECI1_ENABLE is not set +CONFIG_SYNO_HDDMON=m +CONFIG_SYNO_SMBUS_HDDMON=m +CONFIG_SYNO_HWMON_PMBUS=y +CONFIG_SYNO_HWMON_AMD_K10TEMP=y +# end of Hardware Monitor + +# +# Serial/TTYs +# +CONFIG_SYNO_TTY_X86_CONSOLE_OUTPUT=y +CONFIG_SYNO_TTY_FIX_TTYS_FUNCTIONS=y +CONFIG_SYNO_TTY_MICROP_CTRL=y +CONFIG_SYNO_TTY_MICROP_FUNCTIONS=y +CONFIG_SYNO_TTY_AES_COMMAND=y +CONFIG_SYNO_TTY_DTS_INFO=y +CONFIG_SYNO_OOB_SERIAL_OVER_LAN=y +CONFIG_SYNO_OOB_LOG_DEVICE_NAME="oob_log" +CONFIG_SYNO_SERIAL_CONSOLE_FORBID=y +# end of Serial/TTYs + +# +# MTD +# +# end of MTD + +# +# I2C Hardware Bus support +# +CONFIG_SYNO_I2C_I801_POLL=y +# CONFIG_SYNO_I2C_I801_SUPPORT_RECOVERY is not set +CONFIG_SYNO_I2C_DW_FORCE_PROBE=y +CONFIG_SYNO_I2C_DW_CLK_FREQ_CUSTOM=y +# end of I2C Hardware Bus support + +# +# LEDs +# +CONFIG_SYNO_LEDS_TRIGGER=y +CONFIG_SYNO_LEDS_LP3943_FEATURES=y +CONFIG_SYNO_LEDS_LP3943_PROBE=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_FIXED_BUS is not set +CONFIG_SYNO_LEDS_LP3943_PROBE_ACPI=y +# CONFIG_SYNO_LEDS_LP3943_PROBE_OF is not set +CONFIG_SYNO_LED_ATMEGA1608=m +# CONFIG_SYNO_LED_ATMEGA1608_SEG7 is not set +CONFIG_SYNO_ATEMGA1608_FEATURES=y +# CONFIG_SYNO_LEDS_TRIGGER_DISK is not set +# end of LEDs + +# +# ALSA +# + +# +# Virtio +# + +# +# IOMMU +# +CONFIG_SYNO_IOMMU_PASSTHROUGH=y +# CONFIG_SYNO_IOMMU_AMD_USB_QUIRK is not set +# end of IOMMU + +# +# RTC +# +CONFIG_SYNO_RTC_S35390A_ACPI_SUPPORT=y +CONFIG_SYNO_RTC_S35390A_FIX_12HOUR_MODE=y +CONFIG_SYNO_RTC_DISABLE_NTP_UPDATE_HWCLOCK=y +# end of RTC + +# +# PCI +# +CONFIG_SYNO_PCI_MISSING_DEVICE=y +CONFIG_SYNO_PCI_ASM1806_SUBID_WORKAROUND=y +CONFIG_SYNO_PCI_OPTIONAL_SLOT=y +CONFIG_SYNO_PCI_MAX_SLOT=1 +CONFIG_SYNO_PCI_M2DXX_SIGNAL_SETTING=y +# CONFIG_SYNO_PCI_DOMAIN_PATH is not set +# CONFIG_SYNO_PCI_EUNIT_SUPPORT is not set +# end of PCI + +# +# TRANSCODING +# + +# +# NTB +# + +# +# POWER +# + +# +# Multipath +# + +# +# GPIO +# +CONFIG_SYNO_GPIO=y +CONFIG_SYNO_GPIO_X86_PINCTRL_CALC_BASE=y +# end of GPIO + +# +# SYNO Device Tree +# +CONFIG_SYNO_OF=y +# end of SYNO Device Tree + +# +# PWM +# +# end of PWM +# end of Device Drivers + +# +# File Systems +# + +# +# Basic +# +CONFIG_SYNO_FS_STAT=y +CONFIG_SYNO_FS_XATTR=y +CONFIG_SYNO_FS_ARCHIVE_BIT=y +CONFIG_SYNO_FS_ARCHIVE_VERSION=y +CONFIG_SYNO_FS_WINACL=y +CONFIG_SYNO_FS_RELATIME_PERIOD=y +CONFIG_SYNO_FS_RECVFILE=y +CONFIG_SYNO_FS_CASELESS_STAT=y +CONFIG_SYNO_FS_LOCKER=y +CONFIG_SYNO_FS_CREATE_TIME=y +CONFIG_SYNO_FS_SYNOTIFY=y +CONFIG_SYNO_FS_SYNOBOOT_LOG=y +CONFIG_SYNO_FS_UNMOUNT=y +CONFIG_SYNO_FS_AGGREGATE_RECVFILE=y +CONFIG_SYNO_FS_QUOTA_QUERY=y +CONFIG_SYNO_FS_SPACE_USAGE=y +CONFIG_SYNO_FS_DEV=y +CONFIG_SYNO_FS_RBD_META=y +CONFIG_SYNO_FS_ROOT_PRJQUOTA=y +CONFIG_SYNO_FS_SHOW_INCOMPAT_SUPP=y +CONFIG_SYNO_FS_SHOW_COMPAT_RO_SUPP=y +CONFIG_SYNO_FS_GENERIC_FIEMAP_FOR_KERNEL_SPACE=y +CONFIG_SYNO_FS_SPLICE_FSNOTIFY=y +# end of Basic + +# +# CIFS +# +CONFIG_SYNO_CIFS_CREATE_TIME=y +CONFIG_SYNO_CIFS_REPLACE_NATIVE_OS=y +CONFIG_SYNO_CIFS_TCON_RECONNECT_CODEPAGE_UTF8=y +CONFIG_SYNO_CIFS_INIT_NLINK=y +CONFIG_SYNO_CIFS_MOUNT_CASELESS=y +CONFIG_SYNO_CIFS_FORCE_UMOUNT=y +CONFIG_SYNO_CIFS_COVERITY=y +CONFIG_SYNO_CIFS_SMB_OPS=y +CONFIG_SYNO_CIFS_RECONNECT=y +# end of CIFS + +# +# FAT +# +CONFIG_SYNO_FAT_CREATE_TIME=y +CONFIG_SYNO_FAT_DEFAULT_MNT_FLUSH=y +CONFIG_SYNO_FAT_SKIP_WAITING_TIME_WHEN_CLOSE_FILE=y +# end of FAT + +# +# EXT3 +# +CONFIG_SYNO_EXT3_ARCHIVE_BIT=y +CONFIG_SYNO_EXT3_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT3_CREATE_TIME=y +# end of EXT3 + +# +# EXT4 +# +CONFIG_SYNO_EXT4_LAZYINIT_INFO=y +CONFIG_SYNO_EXT4_LAZYINIT_DYNAMIC_SPEED=y +CONFIG_SYNO_EXT4_LAZYINIT_WAIT_MULT=2 +CONFIG_SYNO_EXT4_XATTR=y +CONFIG_SYNO_EXT4_STAT=y +CONFIG_SYNO_EXT4_ARCHIVE_BIT=y +CONFIG_SYNO_EXT4_ARCHIVE_VERSION=y +CONFIG_SYNO_EXT4_WINACL=y +CONFIG_SYNO_EXT4_CREATE_TIME=y +CONFIG_SYNO_EXT4_SYMLINK_IOCTL=y +CONFIG_SYNO_EXT4_CASELESS_STAT=y +CONFIG_SYNO_EXT4_ERROR_REPORT=y +CONFIG_SYNO_EXT4_INODE_NUM_OVERFLOW_FIX=y +CONFIG_SYNO_EXT4_DEFAULT_MNTOPT_JOURNAL_CKSUM=y +CONFIG_SYNO_EXT4_UNUSED_HINT=y +CONFIG_SYNO_EXT4_DISABLE_INODES_COUNT_CHECK=y +CONFIG_SYNO_EXT4_ALLOW_MORE_RESERVED_GDT_BLOCKS=y +CONFIG_SYNO_EXT4_CAPABILITY_FLAGS=y +CONFIG_SYNO_EXT4_RBD_META=y +CONFIG_SYNO_EXT4_SYNOOPT=y +CONFIG_SYNO_EXT4_ROOT_PRJQUOTA=y +CONFIG_SYNO_EXT4_SKIP_UNNECESSARY_BARRIER=y +CONFIG_SYNO_EXT4_BH_FLAGS_WARNING=y +# end of EXT4 + +# +# BTRFS +# +CONFIG_SYNO_BTRFS_XATTR=y +CONFIG_SYNO_BTRFS_STAT=y +CONFIG_SYNO_BTRFS_ARCHIVE_BIT=y +CONFIG_SYNO_BTRFS_ARCHIVE_VERSION=y +CONFIG_SYNO_BTRFS_WINACL=y +CONFIG_SYNO_BTRFS_CREATE_TIME=y +CONFIG_SYNO_BTRFS_RESIZE_QUERY=y +CONFIG_SYNO_BTRFS_METADATA_RESERVE=y +CONFIG_SYNO_BTRFS_FALLOCATE_MARK_WRITTEN=y +CONFIG_SYNO_BTRFS_VFS_INO_TO_PATH=y +CONFIG_SYNO_BTRFS_QGROUP_QUERY=y +CONFIG_SYNO_BTRFS_DELAYED_ORPHAN_CLEANUP_WHEN_MOUNT=y +CONFIG_SYNO_BTRFS_MOUNT_OPTION_EXPAND_64BIT=y +CONFIG_SYNO_BTRFS_COMPAT_RO_NO_REMOUNT_RW=y +CONFIG_SYNO_BTRFS_MERGE_HOLES=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_CREATE_TIME=y +CONFIG_SYNO_BTRFS_READONLY_SUBVOL_RUUID_SET=y +CONFIG_SYNO_BTRFS_RENAME_READONLY_SUBVOL=y +CONFIG_SYNO_BTRFS_RECLAIM_SPACE=y +CONFIG_SYNO_BTRFS_IOC_SYNC_SYNO=y +CONFIG_SYNO_BTRFS_CLONE_RANGE_V2=y +CONFIG_SYNO_BTRFS_DEFAULT_SAPCE_CACHE_V2=y +CONFIG_SYNO_BTRFS_SEND_SUBVOL_FLAG=y +CONFIG_SYNO_BTRFS_SEND_FLAGS_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_SKIP_FIND_CLONE=y +CONFIG_SYNO_BTRFS_SEND_FALLBACK_COMPRESSION=y +CONFIG_SYNO_BTRFS_SEND_FALLOCATE_SUPPORT=y +CONFIG_SYNO_BTRFS_SEND_CALCULATE_TOTAL_DATA_SIZE=y +CONFIG_SYNO_BTRFS_SEND_SUPPORT_PAUSE_RESUME=y +CONFIG_SYNO_BTRFS_CASELESS_STAT=y +CONFIG_SYNO_BTRFS_LOCKER=y +CONFIG_SYNO_BTRFS_LOCKER_SNAPSHOT=y +CONFIG_SYNO_BTRFS_LOCKER_SUBVOLUME_CLOCK=y +CONFIG_SYNO_BTRFS_REMOVE_FLAG_TREE_CHECK=y +# CONFIG_SYNO_BTRFS_IGNORE_PRE_WRITE_TREE_CHECK is not set +CONFIG_SYNO_BTRFS_ALLOW_SNAPSHOT_DELETE_STOP=y +CONFIG_SYNO_BTRFS_SUBVOLUME_HIDE=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_HINT_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_RSV_METADATA=y +CONFIG_SYNO_BTRFS_CLUSTER_ALLOCATION=y +CONFIG_SYNO_BTRFS_BLOCK_GROUP_CACHE_TREE=y +CONFIG_SYNO_BTRFS_LOG_TREE_USE_SINGLE_METADATA=y +CONFIG_SYNO_BTRFS_COMPR_DEFAULT_SETTING=y +CONFIG_SYNO_BTRFS_FIX_JOURNAL_INFO_BUG=y +CONFIG_SYNO_BTRFS_FIX_DATA_CHUNK_ALLOCATE_TOO_MUCH_FOR_PARALLEL_WRITE=y +CONFIG_SYNO_BTRFS_FIX_FIEMAP_RESULT_NOT_CORRECTED=y +CONFIG_SYNO_BTRFS_FREE_SPACE_ANALYZE=y +CONFIG_SYNO_BTRFS_FEATURE_METADATA_CACHE=y +CONFIG_SYNO_BTRFS_AVOID_TRIM_SYS_CHUNK=y +CONFIG_SYNO_BTRFS_FREE_EXTENT_MAPS=y +CONFIG_SYNO_BTRFS_TUNE_DEFAULT_MAX_INLINE_SIZE=y +CONFIG_SYNO_BTRFS_SCRUB_CANCEL=y +CONFIG_SYNO_BTRFS_COMPR_CTL=y +CONFIG_SYNO_BTRFS_SYSFS_BLOCK_GROUP_CNT=y +CONFIG_SYNO_BTRFS_COMMIT_STATS=y +CONFIG_SYNO_BTRFS_SUPPORT_FULLY_CLONE_BETWEEN_CSUM_AND_NOCSUM_DIR=y +CONFIG_SYNO_BTRFS_DISABLE_CLONE_BETWEEN_COMPR_AND_NOCOMPR_DIR=y +CONFIG_SYNO_BTRFS_SKIP_BLOCK_GROUP=y +CONFIG_SYNO_BTRFS_SNAPSHOT_SIZE_CALCULATION=y +CONFIG_SYNO_BTRFS_UNUSED_HINT=y +CONFIG_SYNO_BTRFS_SYSFS_FREE_SPACE_TREE=y +CONFIG_SYNO_BTRFS_PERF_STATS=y +CONFIG_SYNO_BTRFS_FIX_INCREMENTAL_SEND=y +CONFIG_SYNO_BTRFS_FEATURE_SPACE_USAGE=y +CONFIG_SYNO_BTRFS_DATA_CORRECTION=y +CONFIG_SYNO_BTRFS_SEND_SIGNAL_HANDLE=y +CONFIG_SYNO_BTRFS_SYNO_QUOTA=y +CONFIG_SYNO_BTRFS_GLOBAL_RESERVE_MINIMAL_VALUE=y +CONFIG_SYNO_BTRFS_REFILL_GLOBAL_RSV=y +CONFIG_SYNO_BTRFS_DROP_LOG_TREE=y +CONFIG_SYNO_BTRFS_MULTIPLE_WRITEBACK=y +CONFIG_SYNO_BTRFS_FIX_DROP_PROGRESS_INCONSISTENT=y +# CONFIG_SYNO_BTRFS_FILE_EXTENT_SYNO_FLAG is not set +CONFIG_SYNO_BTRFS_COW_ASYNC_THROTTLE=y +CONFIG_SYNO_BTRFS_LIMIT_WRITE_BIO_SIZE=y +CONFIG_SYNO_BTRFS_ORDERED_EXTENT_THROTTLE=y +CONFIG_SYNO_BTRFS_PRIORITY_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_UNLOCKED_BUFFER_WRITE=y +CONFIG_SYNO_BTRFS_BALANCE_DRY_RUN=y +CONFIG_SYNO_BTRFS_FEATURE_TREE=y +CONFIG_SYNO_BTRFS_CAPABILITY_FLAGS=y +CONFIG_SYNO_BTRFS_RBD_META=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_RECLAIM=y +CONFIG_SYNO_BTRFS_ASYNC_DATA_FLUSH=y +CONFIG_SYNO_BTRFS_ASYNC_METADATA_FLUSH_AND_THROTTLE=y +CONFIG_SYNO_BTRFS_VERIFY_DEV_EXTENTS_WITH_READAHEAD_FORWARD_ALWAYS=y +CONFIG_SYNO_BTRFS_DELAYED_REF_THROTTLE=y +CONFIG_SYNO_BTRFS_CLEANER_THROTTLE=y +CONFIG_SYNO_BTRFS_SEND_DONOT_SKIP_PRECESSING_BACKREFERENCE=y +CONFIG_SYNO_BTRFS_FIX_PARTIAL_WRITE_END_DEADLOCK=y +CONFIG_SYNO_BTRFS_FIX_TRIM_ENOSPC=y +CONFIG_SYNO_BTRFS_LIST_HARDLINKS=y +CONFIG_SYNO_BTRFS_FIX_BUG_WEHN_QGROUP_ATOMIC_ALLOC_FAILED=y +CONFIG_SYNO_BTRFS_SKIP_CLEAR_EXTENT_DEFRAG_WHEN_NOCOW_ORDERED_EXTENT=y +CONFIG_SYNO_BTRFS_FIX_CLONERANGE_NBYTES_WRONG=y +CONFIG_SYNO_BTRFS_ALLOCATOR=y +CONFIG_SYNO_BTRFS_SKIP_RESERVE_WHEN_NO_QUOTA_LIMIT=y +CONFIG_SYNO_BTRFS_NON_BLOCKING_PUNCH_HOLE=y +CONFIG_SYNO_BTRFS_MOUNT_STATS=y +CONFIG_SYNO_BTRFS_FIX_UUID_CHECKING=y +CONFIG_SYNO_BTRFS_FIX_UNNECESSARY_FLUSH_WITH_OLD_SIZE_IS_ZERO_WHEN_TRUNCATE=y +CONFIG_SYNO_BTRFS_LIMIT_PRE_RUN_DELAYED_REFS_FOR_COMMIT_TRANSACTION=y +CONFIG_SYNO_BTRFS_IMPROVE_FIEMAP_FOR_LARGE_SPARSE_FILE=y +CONFIG_SYNO_BTRFS_HIBERNATION_MONITOR=y +CONFIG_SYNO_BTRFS_FIX_CHUNK_LOGICAL_OVERFLOW=y +CONFIG_SYNO_BTRFS_STATISTICS=y +CONFIG_SYNO_BTRFS_QUOTA_SOFT_LIMIT=y +CONFIG_SYNO_BTRFS_SEND_IMPROVE_CHECK_NEW_DIR_CREATED_WITH_NEW_DIR_CACHE=y +CONFIG_SYNO_BTRFS_AUTO_DISABLE_COMPRESS_WHEN_NOCOW_SET=y +CONFIG_SYNO_BTRFS_QUICK_BALANCE=y +CONFIG_SYNO_BTRFS_SEARCH_BY_EXTENT_TYPE=y +# end of BTRFS + +# +# ECRYPT +# +CONFIG_SYNO_ECRYPTFS_ARCHIVE_BIT=y +CONFIG_SYNO_ECRYPTFS_FILENAME_SYSCALL=y +CONFIG_SYNO_ECRYPTFS_AVOID_MOUNT_REPEATLY=y +CONFIG_SYNO_ECRYPTFS_REMOVE_TRUNCATE_WRITE=y +CONFIG_SYNO_ECRYPTFS_CHECK_SYMLINK_LENGTH=y +CONFIG_SYNO_ECRYPTFS_FALLOCATE_SUPPORT=y +CONFIG_SYNO_ECRYPTFS_FAST_LOOKUP=y +CONFIG_SYNO_ECRYPTFS_PASS_BTRFS_IOCTL=y +CONFIG_SYNO_ECRYPTFS_ARCHIVE_VERSION=y +CONFIG_SYNO_ECRYPTFS_CREATE_TIME=y +CONFIG_SYNO_ECRYPTFS_STAT=y +CONFIG_SYNO_ECRYPTFS_LOWER_INIT=y +CONFIG_SYNO_ECRYPTFS_SKIP_EQUAL_ISIZE_UPDATE=y +CONFIG_SYNO_ECRYPTFS_SKIP_EDQUOT_WARNING=y +CONFIG_SYNO_ECRYPTFS_WINACL=y +CONFIG_SYNO_ECRYPTFS_EXPORT=y +CONFIG_SYNO_ECRYPTFS_REDUCE_MEMCPY=y +CONFIG_SYNO_ECRYPTFS_DISABLE_READAHEAD=y +# end of ECRYPT + +# +# NFS +# +CONFIG_SYNO_NFSD_AVOID_HUNG_TASK_WHEN_UNLINK_BIG_FILE=y +CONFIG_SYNO_NFSD_HIDDEN_FILE=y +CONFIG_SYNO_NFSD_UDP_PACKET=y +CONFIG_SYNO_NFSD_UDP_MAX_PACKET_SIZE=32768 +CONFIG_SYNO_NFSD_UDP_MIN_PACKET_SIZE=4096 +CONFIG_SYNO_NFSD_UDP_DEF_PACKET_SIZE=8192 +CONFIG_SYNO_NFSD_SQUASH_TO_ADMIN=y +CONFIG_SYNO_NFSD_UNIX_PRI=y +CONFIG_SYNO_NFSD_WINACL=y +CONFIG_SYNO_NFSD_LATENCY_REPORT=y +CONFIG_SYNO_NFS_VAAI_SUPPORT=y +CONFIG_SYNO_NFS_VAAI_LAZY_CLONE=y +CONFIG_SYNO_NFSD_SKIP_FINDING_IDLE_NFSD_IF_CONGESTED=y +CONFIG_SYNO_NFSD_INIT_NL4_SERVER_BY_NFS_OP=y +CONFIG_SYNO_NFSD_SYNO_FILE_STATS=y +CONFIG_SYNO_NFSD_CONNECTION_STAT=y +CONFIG_SYNO_NFSD_UDC_COLLECTOR=y +# end of NFS + +# +# HFSPLUS +# +CONFIG_SYNO_HFSPLUS_CREATE_TIME=y +CONFIG_SYNO_HFSPLUS_CASELESS=y +CONFIG_SYNO_HFSPLUS_NFC_WORKAROUND=y +CONFIG_SYNO_HFSPLUS_EA=y +CONFIG_SYNO_HFSPLUS_BNODE_READ_PAGE_MAPPING_LIMIT=y +CONFIG_SYNO_HFSPLUS_REMOVE_DEFAULT_CR_TYPE=y +# end of HFSPLUS + +# +# UDF +# +CONFIG_SYNO_UDF_CASELESS=y +# end of UDF + +# +# FUSE +# +CONFIG_SYNO_FUSE_STAT=y +CONFIG_SYNO_FUSE_ARCHIVE_BIT=y +CONFIG_SYNO_FUSE_ARCHIVE_VERSION=y +CONFIG_SYNO_FUSE_CREATE_TIME=y +# end of FUSE + +# +# OverlayFS +# +CONFIG_SYNO_OVERLAYFS_ALLOW_CUSTOMIZED_DENTRY_OPS=y +# end of OverlayFS + +# +# AUFS +# +CONFIG_SYNO_AUFS_PATCH=y +CONFIG_SYNO_AUFS_NO_AUTOGEN=y +# end of AUFS + +# +# ConfigFS +# +CONFIG_SYNO_CONFIGFS_SIMPLE_ATTR_SIZE_AS_PAGE_SIZE=y +# end of ConfigFS + +# +# TMPFS +# +CONFIG_SYNO_TMPFS_CREATE_TIME=y +CONFIG_SYNO_TMPFS_ARCHIVE_BIT=y +# end of TMPFS + +# +# ceph +# +CONFIG_SYNO_CEPH_RECVFILE=y +CONFIG_SYNO_CEPH_STAT=y +CONFIG_SYNO_CEPH_CREATE_TIME=y +CONFIG_SYNO_CEPH_ARCHIVE_BIT=y +CONFIG_SYNO_CEPH_CASELESS_STAT=y +CONFIG_SYNO_CEPH_WINACL=y +# end of ceph +# end of File Systems + +# +# MISC Features +# +CONFIG_SYNO_APPARMOR_PATCH=y +CONFIG_SYNO_OOM_DEBUG=y +CONFIG_SYNO_ELEVATE_LOG_LEVEL=y +CONFIG_SYNO_FORCE_CF9_REBOOT=y +CONFIG_SYNO_OOM_NOTIFICATION=y +CONFIG_SYNO_KERNEL_MODULE_REMOVAL_LOGGING=y +CONFIG_SYNO_POWEROFF_INFO_PRINT=y +CONFIG_SYNO_PSTORE=y +CONFIG_SYNO_SPECULATION_DEFAULT_OFF=y +CONFIG_SYNO_FIX_RTC_WAKE_AFTER_POWER_FAILURE=y +CONFIG_SYNO_PLUGIN_INTERFACE=y +CONFIG_SYNO_UART_TO_SPI_CONSOLE_LOG=m +CONFIG_SYNO_SYSTEM_SHUTDOWN_HOOK=y +CONFIG_SYNO_SYNOBIOS_EVENT=y +CONFIG_SYNO_KVM_IGNORE_MSRS=y +CONFIG_SYNO_DISABLE_AUDITSYSCALL=y +CONFIG_SYNO_DEV_ALLOC_PAGES=y +CONFIG_SYNO_OUT_OF_RESOURCE_LOG=y +CONFIG_SYNO_RND_ENTROPY_GEN=y +# end of MISC Features + +# +# Cgroup +# + +# +# Encryption +# +CONFIG_SYNO_CRYPTO_REMOVE_X509_DATE_VALIDATION_CONSTRAIN=y +# end of Encryption + +# +# Udev +# +CONFIG_SYNO_DEPRECATED_UEVENT_ENV=y +# end of Udev + +# +# Bios Log +# +# CONFIG_SYNO_BIOS_MEMORY_TRAINING_FAILED_LOG is not set +CONFIG_SYNO_BIOS_ACPI_FPDT=y +# end of Bios Log + +# +# ceph +# +CONFIG_SYNO_CEPH_CUSTOMIZED_CRUSH=y +CONFIG_SYNO_CEPH_SKIP_CRC=y +CONFIG_SYNO_CEPH_IDENTIFY_POOL_XATTR_IS_ID=y +# end of ceph + +# +# Synology Protection +# +CONFIG_SYNO_RAMDISK_INTEGRITY_CHECK=y +CONFIG_SYNO_KEXEC_TEST=y +# end of Synology Protection + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULE_SIG_FORMAT=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA1 is not set +# CONFIG_MODULE_SIG_SHA224 is not set +# CONFIG_MODULE_SIG_SHA256 is not set +CONFIG_MODULE_SIG_SHA384=y +# CONFIG_MODULE_SIG_SHA512 is not set +CONFIG_MODULE_SIG_HASH="sha384" +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_WBT_MQ is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_CMA is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +CONFIG_NET_UDP_TUNNEL=m +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +# CONFIG_INET_ESP_OFFLOAD is not set +# CONFIG_INET_ESPINTCP is not set +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_MROUTE=y +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_NETLABEL is not set +# CONFIG_MPTCP is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +# CONFIG_NF_LOG_NETDEV is not set +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=y +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=m +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CT_NETLINK is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +# CONFIG_NETFILTER_XT_CONNMARK is not set +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +# 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_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=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# 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=m +# 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=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# 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_POLICY=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE 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=m +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# 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 +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +# CONFIG_IP_SET_BITMAP_IP is not set +# CONFIG_IP_SET_BITMAP_IPMAC is not set +# CONFIG_IP_SET_BITMAP_PORT is not set +CONFIG_IP_SET_HASH_IP=m +# CONFIG_IP_SET_HASH_IPMARK is not set +CONFIG_IP_SET_HASH_IPPORT=m +# CONFIG_IP_SET_HASH_IPPORTIP is not set +CONFIG_IP_SET_HASH_IPPORTNET=m +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_SET_HASH_MAC is not set +# CONFIG_IP_SET_HASH_NETPORTNET is not set +CONFIG_IP_SET_HASH_NET=m +# CONFIG_IP_SET_HASH_NETNET is not set +# CONFIG_IP_SET_HASH_NETPORT is not set +# CONFIG_IP_SET_HASH_NETIFACE is not set +# CONFIG_IP_SET_LIST_SET is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +# CONFIG_IP_VS_WRR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_SH is not set +# CONFIG_IP_VS_MH is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_NQ is not set + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_NFCT=y + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +CONFIG_NF_LOG_IPV4=m +# CONFIG_NF_REJECT_IPV4 is not set +CONFIG_NF_NAT_PPTP=m +CONFIG_IP_NF_IPTABLES=m +# 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_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_ARPTABLES is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_REJECT_IPV6 is not set +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +# 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_OPTS 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_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_NAT is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +# CONFIG_L2TP_DEBUGFS is not set +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BRIDGE_MRP is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +CONFIG_ATALK=m +# CONFIG_DEV_APPLETALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=m +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +CONFIG_NET_SCH_SFQ=m +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +CONFIG_NET_SCH_NETEM=m +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +# CONFIG_OPENVSWITCH_GRE is not set +# CONFIG_OPENVSWITCH_VXLAN is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=m +# CONFIG_MPLS_ROUTING is not set +CONFIG_NET_NSH=m +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +# CONFIG_CAIF_NETDEV is not set +# CONFIG_CAIF_USB is not set +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +# CONFIG_FAILOVER is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEFAULT is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM_PERFORMANCE=y +CONFIG_PCIE_PME=y +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +# CONFIG_PCI_PF_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_VMD is not set + +# +# DesignWare PCI Core Support +# +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_INTEL_GW is not set +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support + +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + +# +# Cadence PCIe controllers support +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCI_J721E_HOST is not set +# end of Cadence PCIe controllers support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MOXTET is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_MHI_BUS is not set +# end of Bus devices + +CONFIG_CONNECTOR=m +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_OVERLAY is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +# CONFIG_PNP_DEBUG_MESSAGES is not set + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=655360 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_BLK_DEV_RBD=m +# CONFIG_BLK_DEV_RSXX is not set + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +# CONFIG_NVME_HWMON is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVME_TARGET is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +CONFIG_SATA_SIL24=y +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X 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_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC 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 + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +# CONFIG_DM_UNSTRIPED is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_MIRROR is not set +CONFIG_DM_RAID=m +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_UEVENT is not set +CONFIG_DM_FLAKEY=m +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +CONFIG_VXLAN=m +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +# CONFIG_CAIF_DRIVERS is not set + +# +# Distributed Switch Architecture drivers +# +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +CONFIG_NET_VENDOR_AMD=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_PCNET32 is not set +CONFIG_AMD_XGBE=m +CONFIG_AMD_XGBE_HAVE_ECC=y +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_CX_ECAT is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=y +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +CONFIG_MARVELL_10G_PHY=m +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_BUS=y +CONFIG_OF_MDIO=y +CONFIG_MDIO_DEVRES=y +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set + +# +# PCS device drivers +# +# CONFIG_PCS_XPCS is not set +# end of PCS device drivers + +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +# CONFIG_SERIAL_8250_PNP is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_OF_PLATFORM is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +# CONFIG_SERIAL_SPRD is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_ISI is not set +CONFIG_N_HDLC=m +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set +# CONFIG_SERIAL_DEV_BUS is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_NVRAM is not set +# CONFIG_RAW_DRIVER is not set +CONFIG_DEVPORT=y +# CONFIG_HPET is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# end of Character devices + +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE 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_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_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# 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_AMD_MP2=y +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set + +# +# SPI Multiplexer support +# +# CONFIG_SPI_MUX is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_BAYTRAIL is not set +# CONFIG_PINCTRL_CHERRYVIEW is not set +# CONFIG_PINCTRL_LYNXPOINT is not set +# CONFIG_PINCTRL_BROXTON is not set +# CONFIG_PINCTRL_CANNONLAKE is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_DENVERTON is not set +# CONFIG_PINCTRL_EMMITSBURG is not set +# CONFIG_PINCTRL_GEMINILAKE is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_JASPERLAKE is not set +# CONFIG_PINCTRL_LEWISBURG is not set +# CONFIG_PINCTRL_SUNRISEPOINT is not set +# CONFIG_PINCTRL_TIGERLAKE is not set + +# +# Renesas pinctrl drivers +# +# end of Renesas pinctrl drivers + +# CONFIG_PINCTRL_EQUILIBRIUM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SODAVILLE is not set +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +# end of USB GPIO expanders + +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 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_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 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=m +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +CONFIG_SENSORS_K10TEMP=y +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_AMD_ENERGY is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2990 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_MAX1111 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_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 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_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_ADCXX 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_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS 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_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 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_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 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_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +# CONFIG_THERMAL_OF is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_MMIO is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# end of Intel thermal drivers + +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +# CONFIG_SSB_DRIVER_PCICORE is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C 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_GATEWORKS_GSC is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +CONFIG_LPC_ICH=y +# CONFIG_LPC_SCH is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X 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_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 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_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +CONFIG_RC_CORE=m +# CONFIG_RC_MAP is not set +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +# CONFIG_IR_IMON_DECODER is not set +# CONFIG_IR_RCMM_DECODER is not set +# CONFIG_RC_DEVICES is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_DRM is not set + +# +# ARM devices +# +# end of ARM devices + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=m +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=m +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_LED is not set +# end of Backlight & LCD device support + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +# CONFIG_SND_SEQUENCER_OSS is not set +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set + +# +# HD-Audio +# +# end of HD-Audio + +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_USB_HIFACE=m +# CONFIG_SND_BCD2000 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_VARIAX is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y + +# +# HID support +# +CONFIG_HID=m +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HIDRAW is not set +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX 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_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_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON 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_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON 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_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG 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_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM 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_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# end of I2C HID support + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_MON is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +CONFIG_USB_UHCI_HCD=m +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +CONFIG_USBIP_CORE=m +# CONFIG_USBIP_VHCI_HCD is not set +CONFIG_USBIP_HOST=m +CONFIG_USBIP_DEBUG=y +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_SIMPLE 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_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# 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_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_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_LP3943=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 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_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +CONFIG_RTC_DRV_S35390A=y +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 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_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OF=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_DMAC=y +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_SF_PDMA is not set + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +# CONFIG_SYNC_FILE is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_HEAPS is not set +# end of DMABUF options + +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +# CONFIG_UIO_CIF is not set +# CONFIG_UIO_PDRV_GENIRQ is not set +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_UIO_AEC is not set +# CONFIG_UIO_SERCOS3 is not set +# CONFIG_UIO_PCI_GENERIC is not set +# CONFIG_UIO_NETX is not set +# CONFIG_UIO_PRUSS is not set +# CONFIG_UIO_MF624 is not set +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +# CONFIG_VFIO_PCI_VGA is not set +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +# CONFIG_VFIO_MDEV is not set +CONFIG_IRQ_BYPASS_MANAGER=m +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +# CONFIG_COMEDI is not set +# CONFIG_RTS5208 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# end of Android + +# CONFIG_STAGING_BOARD is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_FB_TFT is not set +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_FIELDBUS_DEV is not set +# CONFIG_KPC2000 is not set +# CONFIG_QLGE is not set +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_ACPI_WMI is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_DCDBAS is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_IBM_RTL is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_MENLOW is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_PMC_ATOM=y +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 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_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_CLK_LGM_CGU is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_CLKBLD_I8253=y +# CONFIG_MICROCHIP_PIT64B is not set +# end of Clock Source drivers + +CONFIG_MAILBOX=y +# CONFIG_PLATFORM_MHU is not set +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOASID=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_VME_BUS is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +# CONFIG_AL_FIC is not set +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_USB_LGM_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +# CONFIG_TEE is not set +# CONFIG_UNISYS_VISORBUS is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_MOST is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_PRINT_QUOTA_WARNING is not set +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +# CONFIG_VIRTIO_FS is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +CONFIG_AUFS_EXPORT=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_XATTR=y +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_DIRREN=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +# CONFIG_AUFS_BR_HFSPLUS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +# CONFIG_HFS_FS is not set +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +# CONFIG_NFSD_BLOCKLAYOUT is not set +# CONFIG_NFSD_SCSILAYOUT is not set +# CONFIG_NFSD_FLEXFILELAYOUT is not set +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +# CONFIG_CEPH_FS_POSIX_ACL is not set +# CONFIG_CEPH_FS_SECURITY_LABEL is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +# CONFIG_CIFS_DFS_UPCALL is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# 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_9 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_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN 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_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set +CONFIG_UNICODE=y +# CONFIG_UNICODE_NORMALIZATION_SELFTEST is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +# CONFIG_INTEL_TXT is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +# CONFIG_SECURITY_SELINUX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SKCIPHER=m +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=m +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_BLAKE2B=m +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_MICHAEL_MIC 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_SHA1=y +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AES_NI_INTEL=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=m +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +CONFIG_CRYPTO_ZSTD=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=m +CONFIG_CRYPTO_JITTERENTROPY=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=m +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA256=m +# CONFIG_CRYPTO_HW is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_MODULE_SIG_KEY="synology/certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="synology/certs/trusted_certificates.pem" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +# CONFIG_BTREE is not set +CONFIG_INTERVAL_TREE=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_BTF=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +CONFIG_PAGE_EXTENSION=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_PAGE_OWNER=y +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_ARCH_HAS_DEBUG_WX=y +# CONFIG_DEBUG_WX is not set +CONFIG_GENERIC_PTDUMP=y +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_WQ_WATCHDOG=y +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Debug kernel data structures + +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_TRACER=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_MAP=y +CONFIG_SYNTH_EVENTS=y +CONFIG_HIST_TRIGGERS=y +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_SAMPLES is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage +# end of Kernel hacking diff --git a/synology/systemd/syno-fan-modules-load.service b/synology/systemd/syno-fan-modules-load.service new file mode 100644 index 000000000000..f017b624ead4 --- /dev/null +++ b/synology/systemd/syno-fan-modules-load.service @@ -0,0 +1,14 @@ +[Unit] +Description=Load Fan Modules in Kernel Project +DefaultDependencies=no +Requisite=systemd-modules-load.service +After=systemd-modules-load.service +IgnoreOnIsolate=yes + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/syno/lib/systemd/scripts/syno-fan-modules-load.sh + +[X-Synology] +Author=Storage Platform Team diff --git a/synology/systemd/syno-fan-modules-load.sh b/synology/systemd/syno-fan-modules-load.sh new file mode 100644 index 000000000000..a90a1bd3920c --- /dev/null +++ b/synology/systemd/syno-fan-modules-load.sh @@ -0,0 +1,130 @@ +#!/bin/sh + +SYNOINFO_DEF="/etc.defaults/synoinfo.conf" + +CheckADTDevice() +{ + file=/sys/class/hwmon/ + for f in "$file"* + do + if [ -d "$f/device" ]; then + name="$(cat "$f/device/name")" + if [ "$name" = "adt7490" ];then + return 1 + fi + fi + done + return 0 +} + +SYNOLoadAdt7490() +{ + modprobe i2c-i801 + modprobe adt7475 + for retry_count in $(seq 1 3) + do + if CheckADTDevice; then + echo "Can not detect ADT device, Retry: $retry_count..." + sleep 1 + modprobe --remove i2c-i801 + modprobe --remove adt7475 + sleep 1 + modprobe i2c-i801 + modprobe adt7475 + else + break + fi + done +} + +# shellcheck disable=SC2125 # FIXME +findADTPath() +{ + ret=0 + unset ADTDIRS + file=/sys/class/i2c-dev/i2c-*/device/*-002[c-e] + for f in $file + do + if [ ! -f "$f/name" ]; then + continue + fi + name="$(cat "$f/name")" + if [ "$name" = "adt7490" ];then + ADTDIRS="${ADTDIRS} $f" + ret=1 + fi + done + return ${ret} +} + +# here we assume adt master will always 0x2e, because due to adt7490's spec, only 0x2e address can be fixed +# shellcheck disable=SC2144 # FIXME +# shellcheck disable=SC2125 # FIXME +findADTMaster() +{ + unset ADTMASTER + adtmasters=/sys/class/i2c-dev/i2c-*/device/*-002e + + if [ -f /sys/class/i2c-dev/i2c-*/device/*-002e/name ]; then + device2e="$(cat /sys/class/i2c-dev/i2c-*/device/*-002e/name)" + if [ "$device2e" = "adt7490" ]; then + adtmasters=/sys/class/i2c-dev/i2c-*/device/*-002e + fi + elif [ -f /sys/class/i2c-dev/i2c-*/device/*-002c/name ]; then + device2c="$(cat /sys/class/i2c-dev/i2c-*/device/*-002c/name)" + if [ "$device2c" = "adt7490" ]; then + adtmasters=/sys/class/i2c-dev/i2c-*/device/*-002c + fi + fi + + for f in $adtmasters + do + # use only 1 master + ADTMASTER="$f" + break + done +} + +SoftLink7490fanInput() +{ + adtfanTmpPath="/tmp/ADTFanPath/" + findADTPath + # no adt path found + if [ 1 -ne $? ]; then + return + fi + findADTMaster + if [ -z "${ADTMASTER}" ]; then + return + fi + /bin/mkdir -p "${adtfanTmpPath}" + # soft link master adt7490 + masterfiles=$(ls -d "${ADTMASTER}"/hwmon/hwmon*/*) + for masterfile in ${masterfiles} + do + ln -s "${masterfile}" "${adtfanTmpPath}"/ + done + # assume other fan input comes from 5 + fanCnt=5 + # soft link slave adt7490 + for ADTDIR in ${ADTDIRS} + do + # skip master itself + if [ "${ADTDIR}" = "${ADTMASTER}" ]; then + continue + fi + slaveFans=$(ls "${ADTDIR}"/hwmon/hwmon*/fan*_input) + for slavefan in ${slaveFans} + do + ln -s "${slavefan}" "${adtfanTmpPath}/fan${fanCnt}_input" + fanCnt=$((fanCnt + 1)) + done + done +} + + +SUPPORT_ADT1475=$(get_key_value $SYNOINFO_DEF supportadt7490) +if [ "$SUPPORT_ADT1475" = "yes" ]; then + SYNOLoadAdt7490 + SoftLink7490fanInput +fi diff --git a/synology/systemd/syno-kernel-modules-load.service b/synology/systemd/syno-kernel-modules-load.service new file mode 100644 index 000000000000..e0d8558d4661 --- /dev/null +++ b/synology/systemd/syno-kernel-modules-load.service @@ -0,0 +1,14 @@ +[Unit] +Description=Load Kernel Modules in Kernel Project +DefaultDependencies=no +Requisite=systemd-modules-load.service +After=systemd-modules-load.service +IgnoreOnIsolate=yes + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/syno/lib/systemd/scripts/syno-kernel-modules-load.sh + +[X-Synology] +Author=Storage Platform Team diff --git a/synology/systemd/syno-kernel-modules-load.sh b/synology/systemd/syno-kernel-modules-load.sh new file mode 100644 index 000000000000..802493a6da5d --- /dev/null +++ b/synology/systemd/syno-kernel-modules-load.sh @@ -0,0 +1,138 @@ +#!/bin/sh + +check_feature() # $1: key +{ + [ "$(get_key_value "/etc.defaults/synoinfo.conf" "${1:-}")" = "yes" ] +} + +probe_modules() # $@: module list +{ + for _m in "$@"; do + modprobe "$_m" + done +} + +# load synobios +modprobe synobios system_mode=1 +/bin/mknod /dev/synobios c 201 0 2>/dev/null + +# load usbhid for bromolow +if check_feature "support_dual_head"; then + probe_modules usblp hid usbhid hid-generic +fi + +# load syno_hddmon +if check_feature "HddEnableDynamicPower"; then + probe_modules syno_hddmon +fi + +# load syno_smbus_hddmon +if check_feature "SMBusHddEnable"; then + probe_modules syno_smbus_hddmon +fi + +# load intel aesni +if check_feature "support_aesni_intel"; then + probe_modules ablk_helper gf128mul lrw glue_helper aesni-intel +fi + +# load lp3943 +if check_feature "support_leds_lp3943"; then + probe_modules i2c-i801 leds-lp3943 +fi + +CheckATMEGA1608Device() +{ + file=/sys/bus/i2c/devices/ + for f in "$file"* + do + name="$(cat "$f/name")" + if [ "$name" = "atmega1608" ]; then + if [ ! -d "$f/driver" ]; then + # if any atmega1608 not is probed by driver, return false + return 0 + fi + fi + done + return 1 +} + +# load atemga1608 +if check_feature "support_leds_atmega1608"; then + probe_modules leds-atmega1608 + for retry_count in $(seq 1 3) + do + if CheckATMEGA1608Device; then + echo "Failed to probe Atmega1608 device, Retry: $retry_count..." + sleep 1 + modprobe --remove leds-atmega1608 + sleep 1 + probe_modules leds-atmega1608 + else + break + fi + done +fi + +CheckATMEGA1608SEG7Device() +{ + file=/sys/bus/i2c/devices/ + for f in "$file"* + do + name="$(cat "$f/name")" + if [ "$name" = "atmega1608_seg7" ]; then + if [ ! -d "$f/driver" ]; then + # if any atmega1608_seg7 not is probed by driver, return false + return 0 + fi + fi + done + return 1 +} + +# load atemga1608 seg7 +if check_feature "support_leds_atmega1608_seg7"; then + probe_modules leds-atmega1608-seg7 + for retry_count in $(seq 1 3) + do + if CheckATMEGA1608SEG7Device; then + echo "Failed to probe Atmega1608_seg7 device, Retry: $retry_count..." + sleep 1 + modprobe --remove leds-atmega1608-seg7 + sleep 1 + probe_modules leds-atmega1608-seg7 + else + break + fi + done +fi + +# load IPMI +if check_feature "support_ipmi"; then + probe_modules ipmi_msghandler ipmi_devintf ipmi_si +fi + +# load ACM +if check_feature "support_acm"; then + probe_modules cdc-acm + mknod /dev/ttyACM0 c 166 0 +fi + +# load USB printer +if check_feature "support_printer"; then + probe_modules usblp +fi + +# load usb-storage and uas +if [ -f "/sys/bus/usb/syno_all_usb_uas_enabled" ]; then + if check_feature "support_uasp"; then + echo 1 > /sys/bus/usb/syno_all_usb_uas_enabled + else + echo 0 > /sys/bus/usb/syno_all_usb_uas_enabled + fi +fi + +modprobe usb-storage +if [ -f "/sys/bus/usb/syno_all_usb_uas_enabled" ]; then + modprobe uas +fi diff --git a/tools/include/linux/rbtree.h b/tools/include/linux/rbtree.h index 30dd21f976c3..2680f2edb837 100644 --- a/tools/include/linux/rbtree.h +++ b/tools/include/linux/rbtree.h @@ -152,4 +152,194 @@ static inline void rb_replace_node_cached(struct rb_node *victim, rb_replace_node(victim, new, &root->rb_root); } -#endif /* __TOOLS_LINUX_PERF_RBTREE_H */ +/* + * The below helper functions use 2 operators with 3 different + * calling conventions. The operators are related like: + * + * comp(a->key,b) < 0 := less(a,b) + * comp(a->key,b) > 0 := less(b,a) + * comp(a->key,b) == 0 := !less(a,b) && !less(b,a) + * + * If these operators define a partial order on the elements we make no + * guarantee on which of the elements matching the key is found. See + * rb_find(). + * + * The reason for this is to allow the find() interface without requiring an + * on-stack dummy object, which might not be feasible due to object size. + */ + +/** + * rb_add_cached() - insert @node into the leftmost cached tree @tree + * @node: node to insert + * @tree: leftmost cached tree to insert @node into + * @less: operator defining the (partial) node order + */ +static __always_inline void +rb_add_cached(struct rb_node *node, struct rb_root_cached *tree, + bool (*less)(struct rb_node *, const struct rb_node *)) +{ + struct rb_node **link = &tree->rb_root.rb_node; + struct rb_node *parent = NULL; + bool leftmost = true; + + while (*link) { + parent = *link; + if (less(node, parent)) { + link = &parent->rb_left; + } else { + link = &parent->rb_right; + leftmost = false; + } + } + + rb_link_node(node, parent, link); + rb_insert_color_cached(node, tree, leftmost); +} + +/** + * rb_add() - insert @node into @tree + * @node: node to insert + * @tree: tree to insert @node into + * @less: operator defining the (partial) node order + */ +static __always_inline void +rb_add(struct rb_node *node, struct rb_root *tree, + bool (*less)(struct rb_node *, const struct rb_node *)) +{ + struct rb_node **link = &tree->rb_node; + struct rb_node *parent = NULL; + + while (*link) { + parent = *link; + if (less(node, parent)) + link = &parent->rb_left; + else + link = &parent->rb_right; + } + + rb_link_node(node, parent, link); + rb_insert_color(node, tree); +} + +/** + * rb_find_add() - find equivalent @node in @tree, or add @node + * @node: node to look-for / insert + * @tree: tree to search / modify + * @cmp: operator defining the node order + * + * Returns the rb_node matching @node, or NULL when no match is found and @node + * is inserted. + */ +static __always_inline struct rb_node * +rb_find_add(struct rb_node *node, struct rb_root *tree, + int (*cmp)(struct rb_node *, const struct rb_node *)) +{ + struct rb_node **link = &tree->rb_node; + struct rb_node *parent = NULL; + int c; + + while (*link) { + parent = *link; + c = cmp(node, parent); + + if (c < 0) + link = &parent->rb_left; + else if (c > 0) + link = &parent->rb_right; + else + return parent; + } + + rb_link_node(node, parent, link); + rb_insert_color(node, tree); + return NULL; +} + +/** + * rb_find() - find @key in tree @tree + * @key: key to match + * @tree: tree to search + * @cmp: operator defining the node order + * + * Returns the rb_node matching @key or NULL. + */ +static __always_inline struct rb_node * +rb_find(const void *key, const struct rb_root *tree, + int (*cmp)(const void *key, const struct rb_node *)) +{ + struct rb_node *node = tree->rb_node; + + while (node) { + int c = cmp(key, node); + + if (c < 0) + node = node->rb_left; + else if (c > 0) + node = node->rb_right; + else + return node; + } + + return NULL; +} + +/** + * rb_find_first() - find the first @key in @tree + * @key: key to match + * @tree: tree to search + * @cmp: operator defining node order + * + * Returns the leftmost node matching @key, or NULL. + */ +static __always_inline struct rb_node * +rb_find_first(const void *key, const struct rb_root *tree, + int (*cmp)(const void *key, const struct rb_node *)) +{ + struct rb_node *node = tree->rb_node; + struct rb_node *match = NULL; + + while (node) { + int c = cmp(key, node); + + if (c <= 0) { + if (!c) + match = node; + node = node->rb_left; + } else if (c > 0) { + node = node->rb_right; + } + } + + return match; +} + +/** + * rb_next_match() - find the next @key in @tree + * @key: key to match + * @tree: tree to search + * @cmp: operator defining node order + * + * Returns the next node matching @key, or NULL. + */ +static __always_inline struct rb_node * +rb_next_match(const void *key, struct rb_node *node, + int (*cmp)(const void *key, const struct rb_node *)) +{ + node = rb_next(node); + if (node && cmp(key, node)) + node = NULL; + return node; +} + +/** + * rb_for_each() - iterates a subtree matching @key + * @node: iterator + * @key: key to match + * @tree: tree to search + * @cmp: operator defining node order + */ +#define rb_for_each(node, key, tree, cmp) \ + for ((node) = rb_find_first((key), (tree), (cmp)); \ + (node); (node) = rb_next_match((key), (node), (cmp))) + +#endif /* __TOOLS_LINUX_PERF_RBTREE_H */ diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h index f44eb0a04afd..c9ce6e8000d2 100644 --- a/tools/include/uapi/linux/fs.h +++ b/tools/include/uapi/linux/fs.h @@ -1,3 +1,6 @@ +#ifndef MY_ABC_HERE +#define MY_ABC_HERE +#endif /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _UAPI_LINUX_FS_H #define _UAPI_LINUX_FS_H @@ -184,6 +187,9 @@ struct fsxattr { #define BLKSECDISCARD _IO(0x12,125) #define BLKROTATIONAL _IO(0x12,126) #define BLKZEROOUT _IO(0x12,127) +#ifdef MY_ABC_HERE +#define BLKHINTUNUSED _IO(0x12, 140) +#endif /* MY_ABC_HERE */ /* * A jump here: 130-131 are reserved for zoned block devices * (see uapi/linux/blkzoned.h) @@ -199,6 +205,11 @@ struct fsxattr { #define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) #define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range) +#ifdef MY_ABC_HERE +#define FIHINTUNUSED _IOWR('x', 129, unsigned int) /* search unused space as hints */ +#endif /* MY_ABC_HERE */ + + #define FSLABEL_MAX 256 /* Max chars for the interface; each fs may differ */ #define FS_IOC_GETFLAGS _IOR('f', 1, long) diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h index 794a375dad36..b2aec04fce8f 100644 --- a/tools/lib/subcmd/subcmd-util.h +++ b/tools/lib/subcmd/subcmd-util.h @@ -50,15 +50,8 @@ static NORETURN inline void die(const char *err, ...) static inline void *xrealloc(void *ptr, size_t size) { void *ret = realloc(ptr, size); - if (!ret && !size) - ret = realloc(ptr, 1); - if (!ret) { - ret = realloc(ptr, size); - if (!ret && !size) - ret = realloc(ptr, 1); - if (!ret) - die("Out of memory, realloc failed"); - } + if (!ret) + die("Out of memory, realloc failed"); return ret; } diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index d8421e1d06be..e85988ce04f1 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -43,75 +43,24 @@ static void elf_hash_init(struct hlist_head *table) #define elf_hash_for_each_possible(name, obj, member, key) \ hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member) -static void rb_add(struct rb_root *tree, struct rb_node *node, - int (*cmp)(struct rb_node *, const struct rb_node *)) -{ - struct rb_node **link = &tree->rb_node; - struct rb_node *parent = NULL; - - while (*link) { - parent = *link; - if (cmp(node, parent) < 0) - link = &parent->rb_left; - else - link = &parent->rb_right; - } - - rb_link_node(node, parent, link); - rb_insert_color(node, tree); -} - -static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key, - int (*cmp)(const void *key, const struct rb_node *)) -{ - struct rb_node *node = tree->rb_node; - struct rb_node *match = NULL; - - while (node) { - int c = cmp(key, node); - if (c <= 0) { - if (!c) - match = node; - node = node->rb_left; - } else if (c > 0) { - node = node->rb_right; - } - } - - return match; -} - -static struct rb_node *rb_next_match(struct rb_node *node, const void *key, - int (*cmp)(const void *key, const struct rb_node *)) -{ - node = rb_next(node); - if (node && cmp(key, node)) - node = NULL; - return node; -} - -#define rb_for_each(tree, node, key, cmp) \ - for ((node) = rb_find_first((tree), (key), (cmp)); \ - (node); (node) = rb_next_match((node), (key), (cmp))) - -static int symbol_to_offset(struct rb_node *a, const struct rb_node *b) +static bool symbol_to_offset(struct rb_node *a, const struct rb_node *b) { struct symbol *sa = rb_entry(a, struct symbol, node); struct symbol *sb = rb_entry(b, struct symbol, node); if (sa->offset < sb->offset) - return -1; + return true; if (sa->offset > sb->offset) - return 1; + return false; if (sa->len < sb->len) - return -1; + return true; if (sa->len > sb->len) - return 1; + return false; sa->alias = sb; - return 0; + return false; } static int symbol_by_offset(const void *key, const struct rb_node *node) @@ -165,7 +114,7 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) { struct rb_node *node; - rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { + rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) { struct symbol *s = rb_entry(node, struct symbol, node); if (s->offset == offset && s->type != STT_SECTION) @@ -179,7 +128,7 @@ struct symbol *find_func_by_offset(struct section *sec, unsigned long offset) { struct rb_node *node; - rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { + rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) { struct symbol *s = rb_entry(node, struct symbol, node); if (s->offset == offset && s->type == STT_FUNC) @@ -193,7 +142,7 @@ struct symbol *find_symbol_containing(const struct section *sec, unsigned long o { struct rb_node *node; - rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { + rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) { struct symbol *s = rb_entry(node, struct symbol, node); if (s->type != STT_SECTION) @@ -207,7 +156,7 @@ struct symbol *find_func_containing(struct section *sec, unsigned long offset) { struct rb_node *node; - rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { + rb_for_each(node, &offset, &sec->symbol_tree, symbol_by_offset) { struct symbol *s = rb_entry(node, struct symbol, node); if (s->type == STT_FUNC) @@ -442,7 +391,7 @@ static int read_symbols(struct elf *elf) sym->offset = sym->sym.st_value; sym->len = sym->sym.st_size; - rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset); + rb_add(&sym->node, &sym->sec->symbol_tree, symbol_to_offset); pnode = rb_prev(&sym->node); if (pnode) entry = &rb_entry(pnode, struct symbol, node)->list; diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c index 280227e3ffd7..f4ec01da8da6 100644 --- a/tools/perf/bench/inject-buildid.c +++ b/tools/perf/bench/inject-buildid.c @@ -133,7 +133,7 @@ static u64 dso_map_addr(struct bench_dso *dso) return 0x400000ULL + dso->ino * 8192ULL; } -static u32 synthesize_attr(struct bench_data *data) +static ssize_t synthesize_attr(struct bench_data *data) { union perf_event event; @@ -151,7 +151,7 @@ static u32 synthesize_attr(struct bench_data *data) return writen(data->input_pipe[1], &event, event.header.size); } -static u32 synthesize_fork(struct bench_data *data) +static ssize_t synthesize_fork(struct bench_data *data) { union perf_event event; @@ -169,8 +169,7 @@ static u32 synthesize_fork(struct bench_data *data) return writen(data->input_pipe[1], &event, event.header.size); } -static u32 synthesize_mmap(struct bench_data *data, struct bench_dso *dso, - u64 timestamp) +static ssize_t synthesize_mmap(struct bench_data *data, struct bench_dso *dso, u64 timestamp) { union perf_event event; size_t len = offsetof(struct perf_record_mmap2, filename); @@ -198,23 +197,25 @@ static u32 synthesize_mmap(struct bench_data *data, struct bench_dso *dso, if (len > sizeof(event.mmap2)) { /* write mmap2 event first */ - writen(data->input_pipe[1], &event, len - bench_id_hdr_size); + if (writen(data->input_pipe[1], &event, len - bench_id_hdr_size) < 0) + return -1; /* zero-fill sample id header */ memset(id_hdr_ptr, 0, bench_id_hdr_size); /* put timestamp in the right position */ ts_idx = (bench_id_hdr_size / sizeof(u64)) - 2; id_hdr_ptr[ts_idx] = timestamp; - writen(data->input_pipe[1], id_hdr_ptr, bench_id_hdr_size); - } else { - ts_idx = (len / sizeof(u64)) - 2; - id_hdr_ptr[ts_idx] = timestamp; - writen(data->input_pipe[1], &event, len); + if (writen(data->input_pipe[1], id_hdr_ptr, bench_id_hdr_size) < 0) + return -1; + + return len; } - return len; + + ts_idx = (len / sizeof(u64)) - 2; + id_hdr_ptr[ts_idx] = timestamp; + return writen(data->input_pipe[1], &event, len); } -static u32 synthesize_sample(struct bench_data *data, struct bench_dso *dso, - u64 timestamp) +static ssize_t synthesize_sample(struct bench_data *data, struct bench_dso *dso, u64 timestamp) { union perf_event event; struct perf_sample sample = { @@ -233,7 +234,7 @@ static u32 synthesize_sample(struct bench_data *data, struct bench_dso *dso, return writen(data->input_pipe[1], &event, event.header.size); } -static u32 synthesize_flush(struct bench_data *data) +static ssize_t synthesize_flush(struct bench_data *data) { struct perf_event_header header = { .size = sizeof(header), @@ -348,14 +349,16 @@ static int inject_build_id(struct bench_data *data, u64 *max_rss) int status; unsigned int i, k; struct rusage rusage; - u64 len = 0; /* this makes the child to run */ if (perf_header__write_pipe(data->input_pipe[1]) < 0) return -1; - len += synthesize_attr(data); - len += synthesize_fork(data); + if (synthesize_attr(data) < 0) + return -1; + + if (synthesize_fork(data) < 0) + return -1; for (i = 0; i < nr_mmaps; i++) { int idx = rand() % (nr_dsos - 1); @@ -363,13 +366,18 @@ static int inject_build_id(struct bench_data *data, u64 *max_rss) u64 timestamp = rand() % 1000000; pr_debug2(" [%d] injecting: %s\n", i+1, dso->name); - len += synthesize_mmap(data, dso, timestamp); + if (synthesize_mmap(data, dso, timestamp) < 0) + return -1; - for (k = 0; k < nr_samples; k++) - len += synthesize_sample(data, dso, timestamp + k * 1000); + for (k = 0; k < nr_samples; k++) { + if (synthesize_sample(data, dso, timestamp + k * 1000) < 0) + return -1; + } - if ((i + 1) % 10 == 0) - len += synthesize_flush(data); + if ((i + 1) % 10 == 0) { + if (synthesize_flush(data) < 0) + return -1; + } } /* tihs makes the child to finish */ diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index d3b5f5faf8c1..02e5774cabb6 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -670,7 +670,7 @@ static void create_tasks(struct perf_sched *sched) err = pthread_attr_init(&attr); BUG_ON(err); err = pthread_attr_setstacksize(&attr, - (size_t) max(16 * 1024, PTHREAD_STACK_MIN)); + (size_t) max(16 * 1024, (int)PTHREAD_STACK_MIN)); BUG_ON(err); err = pthread_mutex_lock(&sched->start_work_mutex); BUG_ON(err); diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index b1be8df80611..d418ca5f9039 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -182,7 +182,7 @@ static void anon_allocate_area(void **alloc_area) { *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (*alloc_area == MAP_FAILED) + if (*alloc_area == MAP_FAILED) { fprintf(stderr, "mmap of anonymous memory failed"); *alloc_area = NULL; } diff --git a/tools/virtio/linux/device.h b/tools/virtio/linux/device.h index 4ad7e1df0db5..e69de29bb2d1 100644 --- a/tools/virtio/linux/device.h +++ b/tools/virtio/linux/device.h @@ -1,2 +0,0 @@ -#ifndef LINUX_DEVICE_H -#endif